From d5148ffa600e6a655b458bedc593020e0574f967 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 25 Jul 2007 11:57:42 +0800 Subject: Blackfin arch: use the [CS]SYNC() macros which include anomaly workarounds rather than __builtin_bfin_[cs]sync() Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu --- drivers/serial/bfin_5xx.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c index 66c92bc36f3..1e79ee605d9 100644 --- a/drivers/serial/bfin_5xx.c +++ b/drivers/serial/bfin_5xx.c @@ -173,12 +173,12 @@ void kgdb_put_debug_char(int chr) uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT]; while (!(UART_GET_LSR(uart) & THRE)) { - __builtin_bfin_ssync(); + SSYNC(); } UART_PUT_LCR(uart, UART_GET_LCR(uart)&(~DLAB)); - __builtin_bfin_ssync(); + SSYNC(); UART_PUT_CHAR(uart, (unsigned char)chr); - __builtin_bfin_ssync(); + SSYNC(); } int kgdb_get_debug_char(void) @@ -192,12 +192,12 @@ int kgdb_get_debug_char(void) uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT]; while(!(UART_GET_LSR(uart) & DR)) { - __builtin_bfin_ssync(); + SSYNC(); } UART_PUT_LCR(uart, UART_GET_LCR(uart)&(~DLAB)); - __builtin_bfin_ssync(); + SSYNC(); chr = UART_GET_CHAR(uart); - __builtin_bfin_ssync(); + SSYNC(); return chr; } @@ -1203,7 +1203,7 @@ static int __init bfin_serial_init(void) IRQF_DISABLED, "BFIN_UART_RX", uart); pr_info("Request irq for kgdb uart port\n"); UART_PUT_IER(uart, UART_GET_IER(uart) | ERBFI); - __builtin_bfin_ssync(); + SSYNC(); t.c_cflag = CS8|B57600; t.c_iflag = 0; t.c_oflag = 0; -- cgit v1.2.3-70-g09d2 From 0ae53640b54f2c30e52044f7102ba08915b988a7 Mon Sep 17 00:00:00 2001 From: Robin Getz Date: Tue, 9 Oct 2007 17:24:49 +0800 Subject: Blackfin arch: Initial patch to add earlyprintk support This allows debugging of problems which happen eary in the kernel boot process (after bootargs are parsed, but before serial subsystem is fully initialized) Signed-off-by: Robin Getz Signed-off-by: Bryan Wu --- Documentation/kernel-parameters.txt | 3 +- arch/blackfin/Kconfig | 14 ++++ arch/blackfin/kernel/Makefile | 1 + arch/blackfin/kernel/early_printk.c | 161 ++++++++++++++++++++++++++++++++++++ drivers/serial/bfin_5xx.c | 129 ++++++++++++++++++++++------- include/asm-blackfin/early_printk.h | 28 +++++++ 6 files changed, 307 insertions(+), 29 deletions(-) create mode 100644 arch/blackfin/kernel/early_printk.c create mode 100644 include/asm-blackfin/early_printk.h (limited to 'drivers') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 4d175c75124..a57c1f216b2 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -35,6 +35,7 @@ parameter is applicable: APIC APIC support is enabled. APM Advanced Power Management support is enabled. AX25 Appropriate AX.25 support is enabled. + BLACKFIN Blackfin architecture is enabled. DRM Direct Rendering Management support is enabled. EDD BIOS Enhanced Disk Drive Services (EDD) is enabled EFI EFI Partitioning (GPT) is enabled @@ -550,7 +551,7 @@ and is between 256 and 4096 characters. It is defined in the file dtc3181e= [HW,SCSI] - earlyprintk= [X86-32,X86-64,SH] + earlyprintk= [X86-32,X86-64,SH,BLACKFIN] earlyprintk=vga earlyprintk=serial[,ttySn[,baudrate]] diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig index 26ebb0e8c43..cc789b988f3 100644 --- a/arch/blackfin/Kconfig +++ b/arch/blackfin/Kconfig @@ -1164,6 +1164,20 @@ config DEBUG_BFIN_NO_KERN_HWTRACE Say Y here to disable hardware tracing in some known "jumpy" pieces of code so that the trace buffer will extend further back. +config EARLY_PRINTK + bool "Early printk" + default n + help + This option enables special console drivers which allow the kernel + to print messages very early in the bootup process. + + This is useful for kernel debugging when your machine crashes very + early before the console code is initialized. After enabling this + feature, you must add "earlyprintk=serial,uart0,57600" to the + command line (bootargs). It is safe to say Y here in all cases, as + all of this lives in the init section and is thrown away after the + kernel boots completely. + config DUAL_CORE_TEST_MODULE tristate "Dual Core Test Module" depends on (BF561) diff --git a/arch/blackfin/kernel/Makefile b/arch/blackfin/kernel/Makefile index 243883ec6de..8aeb6066b19 100644 --- a/arch/blackfin/kernel/Makefile +++ b/arch/blackfin/kernel/Makefile @@ -13,3 +13,4 @@ obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_BFIN_DMA_5XX) += bfin_dma_5xx.o obj-$(CONFIG_DUAL_CORE_TEST_MODULE) += dualcore_test.o obj-$(CONFIG_KGDB) += kgdb.o +obj-$(CONFIG_EARLY_PRINTK) += early_printk.o diff --git a/arch/blackfin/kernel/early_printk.c b/arch/blackfin/kernel/early_printk.c new file mode 100644 index 00000000000..9bf61706694 --- /dev/null +++ b/arch/blackfin/kernel/early_printk.c @@ -0,0 +1,161 @@ +/* + * File: arch/blackfin/kernel/early_printk.c + * Based on: arch/x86_64/kernel/early_printk.c + * Author: Robin Getz +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_SERIAL_BFIN +extern struct console *bfin_earlyserial_init(unsigned int port, + unsigned int cflag); +#endif + +static struct console *early_console; + +/* Default console + * Port n == ttyBFn + * cflags == UART output modes + */ +#define DEFAULT_PORT 0 +#define DEFAULT_CFLAG CS8|B57600 + +#ifdef CONFIG_SERIAL_CORE +/* What should get here is "0,57600" */ +static struct console * __init earlyserial_init(char *buf) +{ + int baud, bit; + char parity; + unsigned int serial_port = DEFAULT_PORT; + unsigned int cflag = DEFAULT_CFLAG; + + serial_port = simple_strtoul(buf, &buf, 10); + buf++; + + cflag = 0; + baud = simple_strtoul(buf, &buf, 10); + switch (baud) { + case 1200: + cflag |= B1200; + break; + case 2400: + cflag |= B2400; + break; + case 4800: + cflag |= B4800; + break; + case 9600: + cflag |= B9600; + break; + case 19200: + cflag |= B19200; + break; + case 38400: + cflag |= B38400; + break; + case 115200: + cflag |= B115200; + break; + default: + cflag |= B57600; + } + + parity = buf[0]; + buf++; + switch (parity) { + case 'e': + cflag |= PARENB; + break; + case 'o': + cflag |= PARODD; + break; + } + + bit = simple_strtoul(buf, &buf, 10); + switch (bit) { + case 5: + cflag |= CS5; + break; + case 6: + cflag |= CS5; + break; + case 7: + cflag |= CS5; + break; + default: + cflag |= CS8; + } + +#ifdef CONFIG_SERIAL_BFIN + return bfin_earlyserial_init(serial_port, cflag); +#else + return NULL; +#endif + +} +#endif + +int __init setup_early_printk(char *buf) +{ + + /* Crashing in here would be really bad, so check both the var + and the pointer before we start using it + */ + if (!buf) + return 0; + + if (!*buf) + return 0; + + if (early_console != NULL) + return 0; + +#ifdef CONFIG_SERIAL_BFIN + /* Check for Blackfin Serial */ + if (!strncmp(buf, "serial,uart", 11)) { + buf += 11; + early_console = earlyserial_init(buf); + } +#endif +#ifdef CONFIG_FB + /* TODO: add framebuffer console support */ +#endif + + if (likely(early_console)) { + early_console->flags |= CON_BOOT; + + register_console(early_console); + printk(KERN_INFO "early printk enabled on %s%d\n", + early_console->name, + early_console->index); + } + + return 0; +} + +early_param("earlyprintk", setup_early_printk); diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c index 1e79ee605d9..5039e2675ab 100644 --- a/drivers/serial/bfin_5xx.c +++ b/drivers/serial/bfin_5xx.c @@ -962,30 +962,6 @@ static void __init bfin_serial_init_ports(void) } #ifdef CONFIG_SERIAL_BFIN_CONSOLE -static void bfin_serial_console_putchar(struct uart_port *port, int ch) -{ - struct bfin_serial_port *uart = (struct bfin_serial_port *)port; - while (!(UART_GET_LSR(uart) & THRE)) - barrier(); - UART_PUT_CHAR(uart, ch); - SSYNC(); -} - -/* - * Interrupts are disabled on entering - */ -static void -bfin_serial_console_write(struct console *co, const char *s, unsigned int count) -{ - struct bfin_serial_port *uart = &bfin_serial_ports[co->index]; - int flags = 0; - - spin_lock_irqsave(&uart->port.lock, flags); - uart_console_write(&uart->port, s, count, bfin_serial_console_putchar); - spin_unlock_irqrestore(&uart->port.lock, flags); - -} - /* * If the port was already initialised (eg, by a boot loader), * try to determine the current setup. @@ -1038,19 +1014,25 @@ bfin_serial_console_get_options(struct bfin_serial_port *uart, int *baud, } pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __FUNCTION__, *baud, *parity, *bits); } +#endif + +#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK) +static struct uart_driver bfin_serial_reg; static int __init bfin_serial_console_setup(struct console *co, char *options) { struct bfin_serial_port *uart; +# ifdef CONFIG_SERIAL_BFIN_CONSOLE int baud = 57600; int bits = 8; int parity = 'n'; -#ifdef CONFIG_SERIAL_BFIN_CTSRTS +# ifdef CONFIG_SERIAL_BFIN_CTSRTS int flow = 'r'; -#else +# else int flow = 'n'; -#endif +# endif +# endif /* * Check whether an invalid uart number has been specified, and @@ -1061,15 +1043,45 @@ bfin_serial_console_setup(struct console *co, char *options) co->index = 0; uart = &bfin_serial_ports[co->index]; +# ifdef CONFIG_SERIAL_BFIN_CONSOLE if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); else bfin_serial_console_get_options(uart, &baud, &parity, &bits); return uart_set_options(&uart->port, co, baud, parity, bits, flow); +# else + return 0; +# endif +} +#endif /* defined (CONFIG_SERIAL_BFIN_CONSOLE) || + defined (CONFIG_EARLY_PRINTK) */ + +#ifdef CONFIG_SERIAL_BFIN_CONSOLE +static void bfin_serial_console_putchar(struct uart_port *port, int ch) +{ + struct bfin_serial_port *uart = (struct bfin_serial_port *)port; + while (!(UART_GET_LSR(uart) & THRE)) + barrier(); + UART_PUT_CHAR(uart, ch); + SSYNC(); +} + +/* + * Interrupts are disabled on entering + */ +static void +bfin_serial_console_write(struct console *co, const char *s, unsigned int count) +{ + struct bfin_serial_port *uart = &bfin_serial_ports[co->index]; + int flags = 0; + + spin_lock_irqsave(&uart->port.lock, flags); + uart_console_write(&uart->port, s, count, bfin_serial_console_putchar); + spin_unlock_irqrestore(&uart->port.lock, flags); + } -static struct uart_driver bfin_serial_reg; static struct console bfin_serial_console = { .name = BFIN_SERIAL_NAME, .write = bfin_serial_console_write, @@ -1095,7 +1107,68 @@ console_initcall(bfin_serial_rs_console_init); #define BFIN_SERIAL_CONSOLE &bfin_serial_console #else #define BFIN_SERIAL_CONSOLE NULL +#endif /* CONFIG_SERIAL_BFIN_CONSOLE */ + + +#ifdef CONFIG_EARLY_PRINTK +static __init void early_serial_putc(struct uart_port *port, int ch) +{ + unsigned timeout = 0xffff; + struct bfin_serial_port *uart = (struct bfin_serial_port *)port; + + while ((!(UART_GET_LSR(uart) & THRE)) && --timeout) + cpu_relax(); + UART_PUT_CHAR(uart, ch); +} + +static __init void early_serial_write(struct console *con, const char *s, + unsigned int n) +{ + struct bfin_serial_port *uart = &bfin_serial_ports[con->index]; + unsigned int i; + + for (i = 0; i < n; i++, s++) { + if (*s == '\n') + early_serial_putc(&uart->port, '\r'); + early_serial_putc(&uart->port, *s); + } +} + +static struct __init console bfin_early_serial_console = { + .name = "early_BFuart", + .write = early_serial_write, + .device = uart_console_device, + .flags = CON_PRINTBUFFER, + .setup = bfin_serial_console_setup, + .index = -1, + .data = &bfin_serial_reg, +}; + +struct console __init *bfin_earlyserial_init(unsigned int port, + unsigned int cflag) +{ + struct bfin_serial_port *uart; + struct ktermios t; + + if (port == -1 || port >= nr_ports) + port = 0; + bfin_serial_init_ports(); + bfin_early_serial_console.index = port; +#ifdef CONFIG_KGDB_UART + kgdb_entry_state = 0; + init_kgdb_uart(); #endif + uart = &bfin_serial_ports[port]; + t.c_cflag = cflag; + t.c_iflag = 0; + t.c_oflag = 0; + t.c_lflag = ICANON; + t.c_line = port; + bfin_serial_set_termios(&uart->port, &t, &t); + return &bfin_early_serial_console; +} + +#endif /* CONFIG_SERIAL_BFIN_CONSOLE */ static struct uart_driver bfin_serial_reg = { .owner = THIS_MODULE, diff --git a/include/asm-blackfin/early_printk.h b/include/asm-blackfin/early_printk.h new file mode 100644 index 00000000000..110f1c1f845 --- /dev/null +++ b/include/asm-blackfin/early_printk.h @@ -0,0 +1,28 @@ +/* + * File: include/asm-blackfin/early_printk.h + * Author: Robin Getz Date: Wed, 10 Oct 2007 16:47:58 +0800 Subject: Blackfin arch: update kgdb patch Signed-off-by: Sonic Zhang Signed-off-by: Bryan Wu --- drivers/serial/bfin_5xx.c | 42 +++++++++++++++++++++++++----------------- include/asm-blackfin/kgdb.h | 1 + 2 files changed, 26 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c index 5039e2675ab..3f39e181469 100644 --- a/drivers/serial/bfin_5xx.c +++ b/drivers/serial/bfin_5xx.c @@ -86,10 +86,8 @@ static void bfin_serial_stop_tx(struct uart_port *port) { struct bfin_serial_port *uart = (struct bfin_serial_port *)port; -#ifdef CONFIG_BF54x while (!(UART_GET_LSR(uart) & TEMT)) continue; -#endif #ifdef CONFIG_SERIAL_BFIN_DMA disable_dma(uart->tx_dma_channel); @@ -128,8 +126,8 @@ static void bfin_serial_start_tx(struct uart_port *port) ier = UART_GET_IER(uart); ier |= ETBEI; UART_PUT_IER(uart, ier); - bfin_serial_tx_chars(uart); #endif + bfin_serial_tx_chars(uart); #endif } @@ -139,18 +137,21 @@ static void bfin_serial_start_tx(struct uart_port *port) static void bfin_serial_stop_rx(struct uart_port *port) { struct bfin_serial_port *uart = (struct bfin_serial_port *)port; +#ifdef CONFIG_KGDB_UART + if (uart->port.line != CONFIG_KGDB_UART_PORT) { +#endif #ifdef CONFIG_BF54x UART_CLEAR_IER(uart, ERBFI); #else unsigned short ier; ier = UART_GET_IER(uart); -#ifdef CONFIG_KGDB_UART - if (uart->port.line != CONFIG_KGDB_UART_PORT) -#endif ier &= ~ERBFI; UART_PUT_IER(uart, ier); #endif +#ifdef CONFIG_KGDB_UART + } +#endif } /* @@ -175,8 +176,11 @@ void kgdb_put_debug_char(int chr) while (!(UART_GET_LSR(uart) & THRE)) { SSYNC(); } + +#ifndef CONFIG_BF54x UART_PUT_LCR(uart, UART_GET_LCR(uart)&(~DLAB)); SSYNC(); +#endif UART_PUT_CHAR(uart, (unsigned char)chr); SSYNC(); } @@ -194,8 +198,10 @@ int kgdb_get_debug_char(void) while(!(UART_GET_LSR(uart) & DR)) { SSYNC(); } +#ifndef CONFIG_BF54x UART_PUT_LCR(uart, UART_GET_LCR(uart)&(~DLAB)); SSYNC(); +#endif chr = UART_GET_CHAR(uart); SSYNC(); @@ -697,17 +703,19 @@ static int bfin_serial_startup(struct uart_port *port) uart->rx_dma_timer.expires = jiffies + DMA_RX_FLUSH_JIFFIES; add_timer(&(uart->rx_dma_timer)); #else + if (request_irq(uart->port.irq, bfin_serial_rx_int, IRQF_DISABLED, + "BFIN_UART_RX", uart)) { # ifdef CONFIG_KGDB_UART - if (uart->port.line != CONFIG_KGDB_UART_PORT && request_irq -# else - if (request_irq + if (uart->port.line != CONFIG_KGDB_UART_PORT) { # endif - (uart->port.irq, bfin_serial_rx_int, IRQF_DISABLED, - "BFIN_UART_RX", uart)) { printk(KERN_NOTICE "Unable to attach BlackFin UART RX interrupt\n"); return -EBUSY; +# ifdef CONFIG_KGDB_UART + } +# endif } + if (request_irq (uart->port.irq+1, bfin_serial_tx_int, IRQF_DISABLED, "BFIN_UART_TX", uart)) { @@ -1154,10 +1162,6 @@ struct console __init *bfin_earlyserial_init(unsigned int port, port = 0; bfin_serial_init_ports(); bfin_early_serial_console.index = port; -#ifdef CONFIG_KGDB_UART - kgdb_entry_state = 0; - init_kgdb_uart(); -#endif uart = &bfin_serial_ports[port]; t.c_cflag = cflag; t.c_iflag = 0; @@ -1255,7 +1259,7 @@ static int __init bfin_serial_init(void) int ret; #ifdef CONFIG_KGDB_UART struct bfin_serial_port *uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT]; - struct termios t; + struct ktermios t; #endif pr_info("Serial: Blackfin serial driver\n"); @@ -1272,10 +1276,14 @@ static int __init bfin_serial_init(void) } #ifdef CONFIG_KGDB_UART if (uart->port.cons->index != CONFIG_KGDB_UART_PORT) { - request_irq(uart->port.irq, bfin_serial_int, + request_irq(uart->port.irq, bfin_serial_rx_int, IRQF_DISABLED, "BFIN_UART_RX", uart); pr_info("Request irq for kgdb uart port\n"); +#ifdef CONFIG_BF54x + UART_SET_IER(uart, ERBFI); +#else UART_PUT_IER(uart, UART_GET_IER(uart) | ERBFI); +#endif SSYNC(); t.c_cflag = CS8|B57600; t.c_iflag = 0; diff --git a/include/asm-blackfin/kgdb.h b/include/asm-blackfin/kgdb.h index 532bd905200..0f73847fd6b 100644 --- a/include/asm-blackfin/kgdb.h +++ b/include/asm-blackfin/kgdb.h @@ -179,5 +179,6 @@ enum regnames { #define STATDA1 0x80 extern void kgdb_print(const char *fmt, ...); +extern void init_kgdb_uart(void); #endif -- cgit v1.2.3-70-g09d2 From bbf275f092b1b2a9bc8a504500ec387f9ddff859 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sun, 5 Aug 2007 16:48:08 +0800 Subject: Blackfin serial driver: pending a unique anomaly id, tie the break flood issue to ANOMALY_05000230 pending a unique anomaly id, tie the break flood issue to ANOMALY_05000230 as when that was fixed, the fallout also fixed the break flood Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu --- drivers/serial/bfin_5xx.c | 43 +++++++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c index 3f39e181469..6f475b60986 100644 --- a/drivers/serial/bfin_5xx.c +++ b/drivers/serial/bfin_5xx.c @@ -231,12 +231,10 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart) { struct tty_struct *tty = uart->port.info->tty; unsigned int status, ch, flg; + static int in_break = 0; #ifdef CONFIG_KGDB_UART struct pt_regs *regs = get_irq_regs(); #endif -#ifdef BF533_FAMILY - static int in_break = 0; -#endif status = UART_GET_LSR(uart); ch = UART_GET_CHAR(uart); @@ -262,29 +260,30 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart) } } #endif - -#ifdef BF533_FAMILY - /* The BF533 family of processors have a nice misbehavior where - * they continuously generate characters for a "single" break. - * We have to basically ignore this flood until the "next" valid - * character comes across. All other Blackfin families operate - * properly though. - */ - if (in_break) { - if (ch != 0) { - in_break = 0; - ch = UART_GET_CHAR(uart); - if (bfin_revid() < 5) + + if (ANOMALY_05000230) { + /* The BF533 family of processors have a nice misbehavior where + * they continuously generate characters for a "single" break. + * We have to basically ignore this flood until the "next" valid + * character comes across. All other Blackfin families operate + * properly though. + * Note: While Anomaly 05000230 does not directly address this, + * the changes that went in for it also fixed this issue. + */ + if (in_break) { + if (ch != 0) { + in_break = 0; + ch = UART_GET_CHAR(uart); + if (bfin_revid() < 5) + return; + } else return; - } else - return; + } } -#endif if (status & BI) { -#ifdef BF533_FAMILY - in_break = 1; -#endif + if (ANOMALY_05000230) + in_break = 1; uart->port.icount.brk++; if (uart_handle_break(&uart->port)) goto ignore_char; -- cgit v1.2.3-70-g09d2 From 301d9cb80b4f64ba24d4b141ad3ca58165a29afb Mon Sep 17 00:00:00 2001 From: Ishizaki Kou Date: Thu, 26 Jul 2007 20:06:08 +1000 Subject: [POWERPC] Init markings for hvc_beat Fix warnings about section mismatch. Signed-off-by: Kou Ishizaki Signed-off-by: Paul Mackerras --- drivers/char/hvc_beat.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/char/hvc_beat.c b/drivers/char/hvc_beat.c index 6f019f19be7..e74bb949c28 100644 --- a/drivers/char/hvc_beat.c +++ b/drivers/char/hvc_beat.c @@ -97,7 +97,7 @@ static int hvc_beat_config(char *p) return 0; } -static int hvc_beat_console_init(void) +static int __init hvc_beat_console_init(void) { if (hvc_beat_useit && machine_is_compatible("Beat")) { hvc_instantiate(0, 0, &hvc_beat_get_put_ops); @@ -106,7 +106,7 @@ static int hvc_beat_console_init(void) } /* temp */ -static int hvc_beat_init(void) +static int __init hvc_beat_init(void) { struct hvc_struct *hp; -- cgit v1.2.3-70-g09d2 From 0d279d47612d1b63155a1d9637a6fc5143dad594 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Mon, 30 Jul 2007 15:55:02 +1000 Subject: [POWERPC] Fixes to allow use of Ebony's flash chips through physmap_of This patch contains a handful of small fixes to allow the Ebony's flash to be exposed as MTD devices via the physmap_of driver. Specifically it: - Makes a small addition to the device tree and zImage wrapper to record the correct address for the flash in the device tree based on the board switches as reported via an FPGA register. - Prohibits building the old hard-coded "Ebony" flash map on arch/powerpc kernels, in favour of using physmap_of's device tree based approach. - Enables MTD and physmap_of in the Ebony defconfig. Signed-off-by: David Gibson Signed-off-by: Paul Mackerras --- arch/powerpc/boot/dts/ebony.dts | 1 + arch/powerpc/boot/ebony.c | 39 ++++++ arch/powerpc/configs/ebony_defconfig | 246 +++++++++++++++++------------------ drivers/mtd/maps/Kconfig | 2 +- 4 files changed, 162 insertions(+), 126 deletions(-) (limited to 'drivers') diff --git a/arch/powerpc/boot/dts/ebony.dts b/arch/powerpc/boot/dts/ebony.dts index c5f99613fc7..27a1463b6ab 100644 --- a/arch/powerpc/boot/dts/ebony.dts +++ b/arch/powerpc/boot/dts/ebony.dts @@ -175,6 +175,7 @@ fpga@7,0 { compatible = "Ebony-FPGA"; reg = <7 0 10>; + virtual-reg = ; }; }; diff --git a/arch/powerpc/boot/ebony.c b/arch/powerpc/boot/ebony.c index 75daedafd0a..eaf0b9bb68d 100644 --- a/arch/powerpc/boot/ebony.c +++ b/arch/powerpc/boot/ebony.c @@ -24,6 +24,7 @@ #include "page.h" #include "ops.h" #include "reg.h" +#include "io.h" #include "dcr.h" #include "44x.h" @@ -92,6 +93,43 @@ void ibm440gp_fixup_clocks(unsigned int sysclk, unsigned int ser_clk) dt_fixup_clock("/plb/opb/serial@40000300", uart1); } +#define EBONY_FPGA_PATH "/plb/opb/ebc/fpga" +#define EBONY_FPGA_FLASH_SEL 0x01 +#define EBONY_SMALL_FLASH_PATH "/plb/opb/ebc/small-flash" + +static void ebony_flashsel_fixup(void) +{ + void *devp; + u32 reg[3] = {0x0, 0x0, 0x80000}; + u8 *fpga; + u8 fpga_reg0 = 0x0; + + devp = finddevice(EBONY_FPGA_PATH); + if (!devp) + fatal("Couldn't locate FPGA node %s\n\r", EBONY_FPGA_PATH); + + if (getprop(devp, "virtual-reg", &fpga, sizeof(fpga)) != sizeof(fpga)) + fatal("%s has missing or invalid virtual-reg property\n\r", + EBONY_FPGA_PATH); + + fpga_reg0 = in_8(fpga); + + devp = finddevice(EBONY_SMALL_FLASH_PATH); + if (!devp) + fatal("Couldn't locate small flash node %s\n\r", + EBONY_SMALL_FLASH_PATH); + + if (getprop(devp, "reg", reg, sizeof(reg)) != sizeof(reg)) + fatal("%s has reg property of unexpected size\n\r", + EBONY_SMALL_FLASH_PATH); + + /* Invert address bit 14 (IBM-endian) if FLASH_SEL fpga bit is set */ + if (fpga_reg0 & EBONY_FPGA_FLASH_SEL) + reg[1] ^= 0x80000; + + setprop(devp, "reg", reg, sizeof(reg)); +} + static void ebony_fixups(void) { // FIXME: sysclk should be derived by reading the FPGA registers @@ -101,6 +139,7 @@ static void ebony_fixups(void) ibm44x_fixup_memsize(); dt_fixup_mac_addresses(ebony_mac0, ebony_mac1); ibm4xx_fixup_ebc_ranges("/plb/opb/ebc"); + ebony_flashsel_fixup(); } void ebony_init(void *mac0, void *mac1) diff --git a/arch/powerpc/configs/ebony_defconfig b/arch/powerpc/configs/ebony_defconfig index 5762cddfc14..d8dc7e63aab 100644 --- a/arch/powerpc/configs/ebony_defconfig +++ b/arch/powerpc/configs/ebony_defconfig @@ -1,9 +1,25 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.22-rc6 -# Tue Jun 26 12:38:33 2007 +# Linux kernel version: 2.6.23-rc1-powerpc-ebony-mtd +# Mon Jul 30 15:47:59 2007 # # CONFIG_PPC64 is not set + +# +# Processor support +# +# CONFIG_6xx is not set +# CONFIG_PPC_85xx is not set +# CONFIG_PPC_8xx is not set +# CONFIG_40x is not set +CONFIG_44x=y +# CONFIG_E200 is not set +CONFIG_4xx=y +CONFIG_BOOKE=y +CONFIG_PTE_64BIT=y +CONFIG_PHYS_64BIT=y +# CONFIG_PPC_MM_SLICES is not set +CONFIG_NOT_COHERENT_CACHE=y CONFIG_PPC32=y CONFIG_PPC_MERGE=y CONFIG_MMU=y @@ -14,39 +30,22 @@ CONFIG_ARCH_HAS_ILOG2_U32=y CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_GENERIC_FIND_NEXT_BIT=y +# CONFIG_ARCH_NO_VIRT_TO_BUS is not set CONFIG_PPC=y CONFIG_EARLY_PRINTK=y CONFIG_GENERIC_NVRAM=y CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y CONFIG_ARCH_MAY_HAVE_PC_FDC=y CONFIG_PPC_OF=y +CONFIG_OF=y # CONFIG_PPC_UDBG_16550 is not set # CONFIG_GENERIC_TBSYNC is not set CONFIG_AUDIT_ARCH=y CONFIG_GENERIC_BUG=y # CONFIG_DEFAULT_UIMAGE is not set - -# -# Processor support -# -# CONFIG_CLASSIC32 is not set -# CONFIG_PPC_82xx is not set -# CONFIG_PPC_83xx is not set -# CONFIG_PPC_85xx is not set -# CONFIG_PPC_86xx is not set -# CONFIG_PPC_8xx is not set -# CONFIG_40x is not set -CONFIG_44x=y -# CONFIG_E200 is not set CONFIG_PPC_DCR_NATIVE=y # CONFIG_PPC_DCR_MMIO is not set CONFIG_PPC_DCR=y -CONFIG_4xx=y -CONFIG_BOOKE=y -CONFIG_PTE_64BIT=y -CONFIG_PHYS_64BIT=y -# CONFIG_PPC_MM_SLICES is not set -CONFIG_NOT_COHERENT_CACHE=y CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" # @@ -63,12 +62,11 @@ CONFIG_LOCALVERSION="" CONFIG_LOCALVERSION_AUTO=y CONFIG_SWAP=y CONFIG_SYSVIPC=y -# CONFIG_IPC_NS is not set CONFIG_SYSVIPC_SYSCTL=y CONFIG_POSIX_MQUEUE=y # CONFIG_BSD_PROCESS_ACCT is not set # CONFIG_TASKSTATS is not set -# CONFIG_UTS_NS is not set +# CONFIG_USER_NS is not set # CONFIG_AUDIT is not set # CONFIG_IKCONFIG is not set CONFIG_LOG_BUF_SHIFT=14 @@ -102,24 +100,17 @@ CONFIG_SLAB=y CONFIG_RT_MUTEXES=y # CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=0 - -# -# Loadable module support -# CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_MODULE_FORCE_UNLOAD is not set # CONFIG_MODVERSIONS is not set # CONFIG_MODULE_SRCVERSION_ALL is not set CONFIG_KMOD=y - -# -# Block layer -# CONFIG_BLOCK=y CONFIG_LBD=y # CONFIG_BLK_DEV_IO_TRACE is not set # CONFIG_LSF is not set +# CONFIG_BLK_DEV_BSG is not set # # IO Schedulers @@ -184,6 +175,8 @@ CONFIG_FLAT_NODE_MEM_MAP=y CONFIG_SPLIT_PTLOCK_CPUS=4 CONFIG_RESOURCES_64BIT=y CONFIG_ZONE_DMA_FLAG=1 +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y CONFIG_PROC_DEVICETREE=y # CONFIG_CMDLINE_BOOL is not set CONFIG_SECCOMP=y @@ -196,9 +189,9 @@ CONFIG_ISA_DMA_API=y # CONFIG_ZONE_DMA=y CONFIG_PPC_INDIRECT_PCI=y -# CONFIG_PPC_INDIRECT_PCI_BE is not set CONFIG_PCI=y CONFIG_PCI_DOMAINS=y +CONFIG_PCI_SYSCALL=y # CONFIG_PCIEPORTBUS is not set CONFIG_ARCH_SUPPORTS_MSI=y # CONFIG_PCI_MSI is not set @@ -306,6 +299,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic" # CONFIG_MAC80211 is not set # CONFIG_IEEE80211 is not set # CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set # # Device Drivers @@ -320,27 +314,85 @@ CONFIG_FW_LOADER=y # CONFIG_DEBUG_DRIVER is not set # CONFIG_DEBUG_DEVRES is not set # CONFIG_SYS_HYPERVISOR is not set +CONFIG_CONNECTOR=y +CONFIG_PROC_EVENTS=y +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_CONCAT is not set +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_REDBOOT_PARTS is not set +# CONFIG_MTD_CMDLINE_PARTS is not set # -# Connector - unified userspace <-> kernelspace linker +# User Modules And Translation Layers # -CONFIG_CONNECTOR=y -CONFIG_PROC_EVENTS=y -# CONFIG_MTD is not set +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set # -# Parallel port support +# RAM/ROM/Flash chip drivers # -# CONFIG_PARPORT is not set +CONFIG_MTD_CFI=y +CONFIG_MTD_JEDECPROBE=y +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_CFI_INTELEXT is not set +CONFIG_MTD_CFI_AMDSTD=y +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +CONFIG_MTD_PHYSMAP_OF=y +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set # -# Plug and Play support +# Disk-On-Chip Device Drivers # -# CONFIG_PNPACPI is not set +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set +# CONFIG_MTD_NAND is not set +# CONFIG_MTD_ONENAND is not set # -# Block devices +# UBI - Unsorted block images # +# CONFIG_MTD_UBI is not set +CONFIG_OF_DEVICE=y +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y # CONFIG_BLK_DEV_FD is not set # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_CPQ_CISS_DA is not set @@ -356,14 +408,12 @@ CONFIG_BLK_DEV_RAM_SIZE=35000 CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 # CONFIG_CDROM_PKTCDVD is not set # CONFIG_ATA_OVER_ETH is not set - -# -# Misc devices -# +# CONFIG_XILINX_SYSACE is not set +CONFIG_MISC_DEVICES=y # CONFIG_PHANTOM is not set +# CONFIG_EEPROM_93CX6 is not set # CONFIG_SGI_IOC4 is not set # CONFIG_TIFM_CORE is not set -# CONFIG_BLINK is not set # CONFIG_IDE is not set # @@ -371,12 +421,9 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 # # CONFIG_RAID_ATTRS is not set # CONFIG_SCSI is not set +# CONFIG_SCSI_DMA is not set # CONFIG_SCSI_NETLINK is not set # CONFIG_ATA is not set - -# -# Multi-device support (RAID and LVM) -# # CONFIG_MD is not set # @@ -389,35 +436,17 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 # # CONFIG_FIREWIRE is not set # CONFIG_IEEE1394 is not set - -# -# I2O device support -# # CONFIG_I2O is not set # CONFIG_MACINTOSH_DRIVERS is not set - -# -# Network device support -# CONFIG_NETDEVICES=y +# CONFIG_NETDEVICES_MULTIQUEUE is not set # CONFIG_DUMMY is not set # CONFIG_BONDING is not set +# CONFIG_MACVLAN is not set # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set # CONFIG_ARCNET is not set - -# -# Ethernet (10 or 100Mbit) -# # CONFIG_NET_ETHERNET is not set -CONFIG_IBM_EMAC=y -CONFIG_IBM_EMAC_RXB=128 -CONFIG_IBM_EMAC_TXB=64 -CONFIG_IBM_EMAC_POLL_WEIGHT=32 -CONFIG_IBM_EMAC_RX_COPY_THRESHOLD=256 -CONFIG_IBM_EMAC_RX_SKB_HEADROOM=0 -# CONFIG_IBM_EMAC_DEBUG is not set -CONFIG_IBM_EMAC_ZMII=y CONFIG_NETDEV_1000=y # CONFIG_ACENIC is not set # CONFIG_DL2K is not set @@ -429,7 +458,6 @@ CONFIG_NETDEV_1000=y # CONFIG_SIS190 is not set # CONFIG_SKGE is not set # CONFIG_SKY2 is not set -# CONFIG_SK98LIN is not set # CONFIG_VIA_VELOCITY is not set # CONFIG_TIGON3 is not set # CONFIG_BNX2 is not set @@ -459,15 +487,7 @@ CONFIG_NETDEV_10000=y # CONFIG_NETCONSOLE is not set # CONFIG_NETPOLL is not set # CONFIG_NET_POLL_CONTROLLER is not set - -# -# ISDN subsystem -# # CONFIG_ISDN is not set - -# -# Telephony Support -# # CONFIG_PHONE is not set # @@ -512,10 +532,6 @@ CONFIG_SERIAL_OF_PLATFORM=y CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 - -# -# IPMI -# # CONFIG_IPMI_HANDLER is not set # CONFIG_WATCHDOG is not set # CONFIG_HW_RANDOM is not set @@ -526,10 +542,6 @@ CONFIG_LEGACY_PTY_COUNT=256 # CONFIG_AGP is not set # CONFIG_DRM is not set # CONFIG_RAW_DRIVER is not set - -# -# TPM devices -# # CONFIG_TCG_TPM is not set CONFIG_DEVPORT=y # CONFIG_I2C is not set @@ -539,11 +551,8 @@ CONFIG_DEVPORT=y # # CONFIG_SPI is not set # CONFIG_SPI_MASTER is not set - -# -# Dallas's 1-wire bus -# # CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set # CONFIG_HWMON is not set # @@ -568,6 +577,7 @@ CONFIG_DEVPORT=y # # CONFIG_DISPLAY_SUPPORT is not set # CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set # CONFIG_FB is not set # CONFIG_FB_IBM_GXT4500 is not set @@ -575,10 +585,7 @@ CONFIG_DEVPORT=y # Sound # # CONFIG_SOUND is not set - -# -# USB support -# +CONFIG_USB_SUPPORT=y CONFIG_USB_ARCH_HAS_HCD=y CONFIG_USB_ARCH_HAS_OHCI=y CONFIG_USB_ARCH_HAS_EHCI=y @@ -593,28 +600,9 @@ CONFIG_USB_ARCH_HAS_EHCI=y # # CONFIG_USB_GADGET is not set # CONFIG_MMC is not set - -# -# LED devices -# # CONFIG_NEW_LEDS is not set - -# -# LED drivers -# - -# -# LED Triggers -# - -# -# InfiniBand support -# # CONFIG_INFINIBAND is not set - -# -# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) -# +# CONFIG_EDAC is not set # # Real Time Clock @@ -634,6 +622,11 @@ CONFIG_USB_ARCH_HAS_EHCI=y # DMA Devices # +# +# Userspace I/O +# +# CONFIG_UIO is not set + # # File systems # @@ -694,6 +687,15 @@ CONFIG_RAMFS=y # CONFIG_BEFS_FS is not set # CONFIG_BFS_FS is not set # CONFIG_EFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_SUMMARY is not set +# CONFIG_JFFS2_FS_XATTR is not set +# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set +CONFIG_JFFS2_ZLIB=y +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set CONFIG_CRAMFS=y # CONFIG_VXFS_FS is not set # CONFIG_HPFS_FS is not set @@ -723,7 +725,6 @@ CONFIG_SUNRPC=y # CONFIG_NCP_FS is not set # CONFIG_CODA_FS is not set # CONFIG_AFS_FS is not set -# CONFIG_9P_FS is not set # # Partition Types @@ -750,8 +751,10 @@ CONFIG_BITREVERSE=y # CONFIG_CRC16 is not set # CONFIG_CRC_ITU_T is not set CONFIG_CRC32=y +# CONFIG_CRC7 is not set # CONFIG_LIBCRC32C is not set CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y CONFIG_PLIST=y CONFIG_HAS_IOMEM=y CONFIG_HAS_IOPORT=y @@ -774,6 +777,7 @@ CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_KERNEL=y # CONFIG_DEBUG_SHIRQ is not set CONFIG_DETECT_SOFTLOCKUP=y +CONFIG_SCHED_DEBUG=y # CONFIG_SCHEDSTATS is not set # CONFIG_TIMER_STATS is not set # CONFIG_DEBUG_SLAB is not set @@ -796,7 +800,6 @@ CONFIG_FORCED_INLINING=y # CONFIG_DEBUG_PAGEALLOC is not set # CONFIG_DEBUGGER is not set # CONFIG_BDI_SWITCH is not set -# CONFIG_BOOTX_TEXT is not set # CONFIG_PPC_EARLY_DEBUG is not set # @@ -804,10 +807,6 @@ CONFIG_FORCED_INLINING=y # # CONFIG_KEYS is not set # CONFIG_SECURITY is not set - -# -# Cryptographic options -# CONFIG_CRYPTO=y CONFIG_CRYPTO_ALGAPI=y CONFIG_CRYPTO_BLKCIPHER=y @@ -845,7 +844,4 @@ CONFIG_CRYPTO_DES=y # CONFIG_CRYPTO_CRC32C is not set # CONFIG_CRYPTO_CAMELLIA is not set # CONFIG_CRYPTO_TEST is not set - -# -# Hardware crypto devices -# +CONFIG_CRYPTO_HW=y diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index cc6c7344243..6cd132c7518 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -362,7 +362,7 @@ config MTD_WALNUT config MTD_EBONY tristate "Flash devices mapped on IBM 440GP Ebony" - depends on MTD_JEDECPROBE && EBONY + depends on MTD_JEDECPROBE && EBONY && !PPC_MERGE help This enables access routines for the flash chips on the IBM 440GP Ebony board. If you have one of these boards and would like to -- cgit v1.2.3-70-g09d2 From cc61f957f486871536cc5531e83337fff4fe48f3 Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Wed, 1 Aug 2007 08:10:03 +1000 Subject: [POWERPC] drivers/macintosh/therm_adt746x.c: kmalloc + memset conversion to kzalloc Signed-off-by: Mariusz Kozlowski Signed-off-by: Paul Mackerras --- drivers/macintosh/therm_adt746x.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c index f25685b9b7c..276945d5151 100644 --- a/drivers/macintosh/therm_adt746x.c +++ b/drivers/macintosh/therm_adt746x.c @@ -379,13 +379,10 @@ static int attach_one_thermostat(struct i2c_adapter *adapter, int addr, if (thermostat) return 0; - th = (struct thermostat *) - kmalloc(sizeof(struct thermostat), GFP_KERNEL); - + th = kzalloc(sizeof(struct thermostat), GFP_KERNEL); if (!th) return -ENOMEM; - memset(th, 0, sizeof(*th)); th->clt.addr = addr; th->clt.adapter = adapter; th->clt.driver = &thermostat_driver; -- cgit v1.2.3-70-g09d2 From 7b52b440d37d669ec93297cf589984a110518d43 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Mon, 13 Aug 2007 06:38:34 +1000 Subject: [POWERPC] via-pmu: Fix typo in printk This fixes a typo in a printk message. Signed-off-by: Michael Buesch Acked-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- drivers/macintosh/via-pmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 157080b3b46..5eee480245f 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -410,7 +410,7 @@ static int __init via_pmu_start(void) irq = irq_of_parse_and_map(vias, 0); if (irq == NO_IRQ) { - printk(KERN_ERR "via-pmu: can't map interruptn"); + printk(KERN_ERR "via-pmu: can't map interrupt\n"); return -ENODEV; } if (request_irq(irq, via_pmu_interrupt, 0, "VIA-PMU", (void *)0)) { -- cgit v1.2.3-70-g09d2 From 9c25099db74b384e16345622071552f9f10dd045 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Wed, 15 Aug 2007 16:42:12 +1000 Subject: [POWERPC] Use of_get_property in ipmi code get_property has been renamed to of_get_property. Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- drivers/char/ipmi/ipmi_si_intf.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 96d2f9ee42d..d57083a9e4e 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -2251,19 +2251,19 @@ static int __devinit ipmi_of_probe(struct of_device *dev, return ret; } - regsize = get_property(np, "reg-size", &proplen); + regsize = of_get_property(np, "reg-size", &proplen); if (regsize && proplen != 4) { dev_warn(&dev->dev, PFX "invalid regsize from OF\n"); return -EINVAL; } - regspacing = get_property(np, "reg-spacing", &proplen); + regspacing = of_get_property(np, "reg-spacing", &proplen); if (regspacing && proplen != 4) { dev_warn(&dev->dev, PFX "invalid regspacing from OF\n"); return -EINVAL; } - regshift = get_property(np, "reg-shift", &proplen); + regshift = of_get_property(np, "reg-shift", &proplen); if (regshift && proplen != 4) { dev_warn(&dev->dev, PFX "invalid regshift from OF\n"); return -EINVAL; -- cgit v1.2.3-70-g09d2 From a05afe9146f7611d40a58be34ee8442727a6af1f Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Wed, 15 Aug 2007 16:54:04 +1000 Subject: [POWERPC] Comment out a currently unused function Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- drivers/macintosh/windfarm_smu_sat.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/macintosh/windfarm_smu_sat.c b/drivers/macintosh/windfarm_smu_sat.c index 351982bcec1..f449d775cdf 100644 --- a/drivers/macintosh/windfarm_smu_sat.c +++ b/drivers/macintosh/windfarm_smu_sat.c @@ -380,10 +380,12 @@ static int __init sat_sensors_init(void) return i2c_add_driver(&wf_sat_driver); } +#if 0 /* uncomment when module_exit() below is uncommented */ static void __exit sat_sensors_exit(void) { i2c_del_driver(&wf_sat_driver); } +#endif module_init(sat_sensors_init); /*module_exit(sat_sensors_exit); Uncomment when cleanup is implemented */ -- cgit v1.2.3-70-g09d2 From ed16c20da6f500bc2dfad933078d2987636a7b60 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Fri, 17 Aug 2007 01:47:39 -0500 Subject: [POWERPC] Remove old includes from arch/ppc Remove includes of files that existed in arch/ppc that we dont need in arch/powerpc anymore. The following includes were removed: This also caused platforms/embedded6xx/mpc7448_hpc2.h to no longer be needed and thus removed. Signed-off-by: Kumar Gala --- arch/powerpc/kernel/setup_32.c | 2 -- arch/powerpc/platforms/52xx/lite5200.c | 1 - arch/powerpc/platforms/82xx/m82xx_pci.h | 2 -- arch/powerpc/platforms/82xx/mpc82xx.c | 1 - arch/powerpc/platforms/82xx/mpc82xx_ads.c | 1 - arch/powerpc/platforms/82xx/pq2ads.h | 1 - arch/powerpc/platforms/83xx/mpc832x_mds.c | 1 - arch/powerpc/platforms/83xx/mpc834x_itx.c | 1 - arch/powerpc/platforms/83xx/mpc834x_mds.c | 1 - arch/powerpc/platforms/83xx/mpc836x_mds.c | 1 - arch/powerpc/platforms/85xx/mpc85xx_cds.c | 1 - arch/powerpc/platforms/85xx/mpc85xx_mds.c | 1 - arch/powerpc/platforms/8xx/m8xx_setup.c | 4 ++-- arch/powerpc/platforms/8xx/mpc86xads.h | 1 - arch/powerpc/platforms/8xx/mpc86xads_setup.c | 1 - arch/powerpc/platforms/8xx/mpc885ads.h | 1 - arch/powerpc/platforms/8xx/mpc885ads_setup.c | 1 - arch/powerpc/platforms/chrp/smp.c | 1 - arch/powerpc/platforms/embedded6xx/ls_uart.c | 1 - arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c | 1 - arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.h | 21 --------------------- arch/powerpc/platforms/powermac/bootx_init.c | 1 - drivers/macintosh/adb-iop.c | 1 - 23 files changed, 2 insertions(+), 46 deletions(-) delete mode 100644 arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.h (limited to 'drivers') diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index 7ec6ba56d83..a288a5f2dbc 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c @@ -18,13 +18,11 @@ #include #include -#include #include #include #include #include #include -#include #include #include #include diff --git a/arch/powerpc/platforms/52xx/lite5200.c b/arch/powerpc/platforms/52xx/lite5200.c index 84bd3da43af..ce3f6951828 100644 --- a/arch/powerpc/platforms/52xx/lite5200.c +++ b/arch/powerpc/platforms/52xx/lite5200.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/platforms/82xx/m82xx_pci.h b/arch/powerpc/platforms/82xx/m82xx_pci.h index 9cd8893b5a3..65e38a7ff48 100644 --- a/arch/powerpc/platforms/82xx/m82xx_pci.h +++ b/arch/powerpc/platforms/82xx/m82xx_pci.h @@ -8,8 +8,6 @@ * 2 of the License, or (at your option) any later version. */ -#include - #define SIU_INT_IRQ1 ((uint)0x13 + CPM_IRQ_OFFSET) #ifndef _IO_BASE diff --git a/arch/powerpc/platforms/82xx/mpc82xx.c b/arch/powerpc/platforms/82xx/mpc82xx.c index cc9900d2e5e..c706871aec1 100644 --- a/arch/powerpc/platforms/82xx/mpc82xx.c +++ b/arch/powerpc/platforms/82xx/mpc82xx.c @@ -36,7 +36,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/platforms/82xx/mpc82xx_ads.c b/arch/powerpc/platforms/82xx/mpc82xx_ads.c index 2d1b05b9f8e..c0a0c56ac5b 100644 --- a/arch/powerpc/platforms/82xx/mpc82xx_ads.c +++ b/arch/powerpc/platforms/82xx/mpc82xx_ads.c @@ -37,7 +37,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/platforms/82xx/pq2ads.h b/arch/powerpc/platforms/82xx/pq2ads.h index 5b5cca6c8c8..6f749b76dd8 100644 --- a/arch/powerpc/platforms/82xx/pq2ads.h +++ b/arch/powerpc/platforms/82xx/pq2ads.h @@ -23,7 +23,6 @@ #define __MACH_ADS8260_DEFS #include -#include /* For our show_cpuinfo hooks. */ #define CPUINFO_VENDOR "Freescale Semiconductor" diff --git a/arch/powerpc/platforms/83xx/mpc832x_mds.c b/arch/powerpc/platforms/83xx/mpc832x_mds.c index 2c8e641a739..61e3f1cb0a7 100644 --- a/arch/powerpc/platforms/83xx/mpc832x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc832x_mds.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/platforms/83xx/mpc834x_itx.c b/arch/powerpc/platforms/83xx/mpc834x_itx.c index 47ba5446f63..6d06645e5ba 100644 --- a/arch/powerpc/platforms/83xx/mpc834x_itx.c +++ b/arch/powerpc/platforms/83xx/mpc834x_itx.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/platforms/83xx/mpc834x_mds.c b/arch/powerpc/platforms/83xx/mpc834x_mds.c index 4c9ff9cadfe..f8aba9a488b 100644 --- a/arch/powerpc/platforms/83xx/mpc834x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc834x_mds.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/platforms/83xx/mpc836x_mds.c b/arch/powerpc/platforms/83xx/mpc836x_mds.c index 84b58934aaf..69970b910c1 100644 --- a/arch/powerpc/platforms/83xx/mpc836x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc836x_mds.c @@ -38,7 +38,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c index 6a171e9abf7..04023347238 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c index be25ecd911b..53830c9a88f 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c @@ -38,7 +38,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/platforms/8xx/m8xx_setup.c b/arch/powerpc/platforms/8xx/m8xx_setup.c index 601b389b570..b2b98dd8be6 100644 --- a/arch/powerpc/platforms/8xx/m8xx_setup.c +++ b/arch/powerpc/platforms/8xx/m8xx_setup.c @@ -36,13 +36,11 @@ #include #include -#include #include #include #include #include #include -#include #include #include #include @@ -55,7 +53,9 @@ struct mpc8xx_pcmcia_ops m8xx_pcmcia_ops; #endif void m8xx_calibrate_decr(void); +#ifdef CONFIG_8xx_WDT extern void m8xx_wdt_handler_install(bd_t *bp); +#endif extern int cpm_pic_init(void); extern int cpm_get_irq(void); diff --git a/arch/powerpc/platforms/8xx/mpc86xads.h b/arch/powerpc/platforms/8xx/mpc86xads.h index 59bad2f9ae5..dd10cd20b6a 100644 --- a/arch/powerpc/platforms/8xx/mpc86xads.h +++ b/arch/powerpc/platforms/8xx/mpc86xads.h @@ -15,7 +15,6 @@ #ifndef __ASM_MPC86XADS_H__ #define __ASM_MPC86XADS_H__ -#include #include /* U-Boot maps BCSR to 0xff080000 */ diff --git a/arch/powerpc/platforms/8xx/mpc86xads_setup.c b/arch/powerpc/platforms/8xx/mpc86xads_setup.c index d881647e992..8f64f48698a 100644 --- a/arch/powerpc/platforms/8xx/mpc86xads_setup.c +++ b/arch/powerpc/platforms/8xx/mpc86xads_setup.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/platforms/8xx/mpc885ads.h b/arch/powerpc/platforms/8xx/mpc885ads.h index 7c31aec284c..14db1241706 100644 --- a/arch/powerpc/platforms/8xx/mpc885ads.h +++ b/arch/powerpc/platforms/8xx/mpc885ads.h @@ -15,7 +15,6 @@ #ifndef __ASM_MPC885ADS_H__ #define __ASM_MPC885ADS_H__ -#include #include /* U-Boot maps BCSR to 0xff080000 */ diff --git a/arch/powerpc/platforms/8xx/mpc885ads_setup.c b/arch/powerpc/platforms/8xx/mpc885ads_setup.c index bd5ff7a892e..d3da38586b0 100644 --- a/arch/powerpc/platforms/8xx/mpc885ads_setup.c +++ b/arch/powerpc/platforms/8xx/mpc885ads_setup.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/platforms/chrp/smp.c b/arch/powerpc/platforms/chrp/smp.c index a137d13008b..10a4a4d063b 100644 --- a/arch/powerpc/platforms/chrp/smp.c +++ b/arch/powerpc/platforms/chrp/smp.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/platforms/embedded6xx/ls_uart.c b/arch/powerpc/platforms/embedded6xx/ls_uart.c index d0bee9f19e4..f7a4def5eff 100644 --- a/arch/powerpc/platforms/embedded6xx/ls_uart.c +++ b/arch/powerpc/platforms/embedded6xx/ls_uart.c @@ -5,7 +5,6 @@ #include #include #include -#include #include #include diff --git a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c index 25c29bc9498..96737e5608d 100644 --- a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c +++ b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c @@ -40,7 +40,6 @@ #include #include #include -#include "mpc7448_hpc2.h" #include #include #include diff --git a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.h b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.h deleted file mode 100644 index f7e0e0c7f8d..00000000000 --- a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * mpc7448_hpc2.h - * - * Definitions for Freescale MPC7448_HPC2 platform - * - * Author: Jacob Pan - * jacob.pan@freescale.com - * Maintainer: Roy Zang - * - * 2006 (c) Freescale Semiconductor, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. - */ - -#ifndef __PPC_PLATFORMS_MPC7448_HPC2_H -#define __PPC_PLATFORMS_MPC7448_HPC2_H - -#include - -#endif /* __PPC_PLATFORMS_MPC7448_HPC2_H */ diff --git a/arch/powerpc/platforms/powermac/bootx_init.c b/arch/powerpc/platforms/powermac/bootx_init.c index 9d73d0234c5..cf660916ae0 100644 --- a/arch/powerpc/platforms/powermac/bootx_init.c +++ b/arch/powerpc/platforms/powermac/bootx_init.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include diff --git a/drivers/macintosh/adb-iop.c b/drivers/macintosh/adb-iop.c index 17ef5d3c01b..44469662517 100644 --- a/drivers/macintosh/adb-iop.c +++ b/drivers/macintosh/adb-iop.c @@ -19,7 +19,6 @@ #include #include -#include #include #include #include -- cgit v1.2.3-70-g09d2 From 33d71d26ba982f99b8cb76b86b2e1e0a0964a8ac Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Mon, 20 Aug 2007 08:50:28 -0500 Subject: [POWERPC] Copy over headers from arch/ppc to arch/powerpc that we need To build arch/powerpc without including asm-ppc/ we need these files in asm-powerpc/ Moved some headers under arch/powerpc/platforms if they were only used by platform or driver files and fixed up the source file includes to match the new locations Signed-off-by: Kumar Gala --- arch/powerpc/platforms/chrp/gg2.h | 61 ++ arch/powerpc/platforms/chrp/pci.c | 2 +- arch/powerpc/platforms/chrp/setup.c | 2 +- arch/powerpc/platforms/embedded6xx/linkstation.c | 3 +- arch/powerpc/platforms/embedded6xx/ls_uart.c | 3 +- arch/powerpc/platforms/embedded6xx/mpc10x.h | 180 ++++ drivers/macintosh/ans-lcd.c | 3 +- drivers/macintosh/ans-lcd.h | 11 + include/asm-powerpc/8xx_immap.h | 564 ++++++++++ include/asm-powerpc/commproc.h | 692 ++++++++++++ include/asm-powerpc/cpm2.h | 1248 ++++++++++++++++++++++ include/asm-powerpc/highmem.h | 135 +++ include/asm-powerpc/hydra.h | 102 ++ include/asm-powerpc/immap_cpm2.h | 648 +++++++++++ include/asm-powerpc/kgdb.h | 57 + include/asm-powerpc/mpc52xx_psc.h | 191 ++++ include/asm-ppc/ans-lcd.h | 11 - 17 files changed, 3897 insertions(+), 16 deletions(-) create mode 100644 arch/powerpc/platforms/chrp/gg2.h create mode 100644 arch/powerpc/platforms/embedded6xx/mpc10x.h create mode 100644 drivers/macintosh/ans-lcd.h create mode 100644 include/asm-powerpc/8xx_immap.h create mode 100644 include/asm-powerpc/commproc.h create mode 100644 include/asm-powerpc/cpm2.h create mode 100644 include/asm-powerpc/highmem.h create mode 100644 include/asm-powerpc/hydra.h create mode 100644 include/asm-powerpc/immap_cpm2.h create mode 100644 include/asm-powerpc/kgdb.h create mode 100644 include/asm-powerpc/mpc52xx_psc.h delete mode 100644 include/asm-ppc/ans-lcd.h (limited to 'drivers') diff --git a/arch/powerpc/platforms/chrp/gg2.h b/arch/powerpc/platforms/chrp/gg2.h new file mode 100644 index 00000000000..341ae55b99f --- /dev/null +++ b/arch/powerpc/platforms/chrp/gg2.h @@ -0,0 +1,61 @@ +/* + * include/asm-ppc/gg2.h -- VLSI VAS96011/12 `Golden Gate 2' register definitions + * + * Copyright (C) 1997 Geert Uytterhoeven + * + * This file is based on the following documentation: + * + * The VAS96011/12 Chipset, Data Book, Edition 1.0 + * VLSI Technology, Inc. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#ifndef _ASMPPC_GG2_H +#define _ASMPPC_GG2_H + + /* + * Memory Map (CHRP mode) + */ + +#define GG2_PCI_MEM_BASE 0xc0000000 /* Peripheral memory space */ +#define GG2_ISA_MEM_BASE 0xf7000000 /* Peripheral memory alias */ +#define GG2_ISA_IO_BASE 0xf8000000 /* Peripheral I/O space */ +#define GG2_PCI_CONFIG_BASE 0xfec00000 /* PCI configuration space */ +#define GG2_INT_ACK_SPECIAL 0xfec80000 /* Interrupt acknowledge and */ + /* special PCI cycles */ +#define GG2_ROM_BASE0 0xff000000 /* ROM bank 0 */ +#define GG2_ROM_BASE1 0xff800000 /* ROM bank 1 */ + + + /* + * GG2 specific PCI Registers + */ + +extern void __iomem *gg2_pci_config_base; /* kernel virtual address */ + +#define GG2_PCI_BUSNO 0x40 /* Bus number */ +#define GG2_PCI_SUBBUSNO 0x41 /* Subordinate bus number */ +#define GG2_PCI_DISCCTR 0x42 /* Disconnect counter */ +#define GG2_PCI_PPC_CTRL 0x50 /* PowerPC interface control register */ +#define GG2_PCI_ADDR_MAP 0x5c /* Address map */ +#define GG2_PCI_PCI_CTRL 0x60 /* PCI interface control register */ +#define GG2_PCI_ROM_CTRL 0x70 /* ROM interface control register */ +#define GG2_PCI_ROM_TIME 0x74 /* ROM timing */ +#define GG2_PCI_CC_CTRL 0x80 /* Cache controller control register */ +#define GG2_PCI_DRAM_BANK0 0x90 /* Control register for DRAM bank #0 */ +#define GG2_PCI_DRAM_BANK1 0x94 /* Control register for DRAM bank #1 */ +#define GG2_PCI_DRAM_BANK2 0x98 /* Control register for DRAM bank #2 */ +#define GG2_PCI_DRAM_BANK3 0x9c /* Control register for DRAM bank #3 */ +#define GG2_PCI_DRAM_BANK4 0xa0 /* Control register for DRAM bank #4 */ +#define GG2_PCI_DRAM_BANK5 0xa4 /* Control register for DRAM bank #5 */ +#define GG2_PCI_DRAM_TIME0 0xb0 /* Timing parameters set #0 */ +#define GG2_PCI_DRAM_TIME1 0xb4 /* Timing parameters set #1 */ +#define GG2_PCI_DRAM_CTRL 0xc0 /* DRAM control */ +#define GG2_PCI_ERR_CTRL 0xd0 /* Error control register */ +#define GG2_PCI_ERR_STATUS 0xd4 /* Error status register */ + /* Cleared when read */ + +#endif /* _ASMPPC_GG2_H */ diff --git a/arch/powerpc/platforms/chrp/pci.c b/arch/powerpc/platforms/chrp/pci.c index 974952ed15c..e43465d34d2 100644 --- a/arch/powerpc/platforms/chrp/pci.c +++ b/arch/powerpc/platforms/chrp/pci.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -21,6 +20,7 @@ #include #include "chrp.h" +#include "gg2.h" /* LongTrail */ void __iomem *gg2_pci_config_base; diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c index dde5ef4dde3..96498ad7b94 100644 --- a/arch/powerpc/platforms/chrp/setup.c +++ b/arch/powerpc/platforms/chrp/setup.c @@ -37,7 +37,6 @@ #include #include #include -#include #include #include #include @@ -51,6 +50,7 @@ #include #include "chrp.h" +#include "gg2.h" void rtas_indicator_progress(char *, unsigned short); diff --git a/arch/powerpc/platforms/embedded6xx/linkstation.c b/arch/powerpc/platforms/embedded6xx/linkstation.c index 8c60e0207d0..61ca02c2d64 100644 --- a/arch/powerpc/platforms/embedded6xx/linkstation.c +++ b/arch/powerpc/platforms/embedded6xx/linkstation.c @@ -18,9 +18,10 @@ #include #include #include -#include #include +#include "mpc10x.h" + static struct mtd_partition linkstation_physmap_partitions[] = { { .name = "mtd_firmimg", diff --git a/arch/powerpc/platforms/embedded6xx/ls_uart.c b/arch/powerpc/platforms/embedded6xx/ls_uart.c index f7a4def5eff..0d9f1500a67 100644 --- a/arch/powerpc/platforms/embedded6xx/ls_uart.c +++ b/arch/powerpc/platforms/embedded6xx/ls_uart.c @@ -4,10 +4,11 @@ #include #include #include -#include #include #include +#include "mpc10x.h" + static void __iomem *avr_addr; static unsigned long avr_clock; diff --git a/arch/powerpc/platforms/embedded6xx/mpc10x.h b/arch/powerpc/platforms/embedded6xx/mpc10x.h new file mode 100644 index 00000000000..b30a6a3b5bd --- /dev/null +++ b/arch/powerpc/platforms/embedded6xx/mpc10x.h @@ -0,0 +1,180 @@ +/* + * Common routines for the Motorola SPS MPC106/8240/107 Host bridge/Mem + * ctlr/EPIC/etc. + * + * Author: Mark A. Greer + * mgreer@mvista.com + * + * 2001 (c) MontaVista, Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ +#ifndef __PPC_KERNEL_MPC10X_H +#define __PPC_KERNEL_MPC10X_H + +#include +#include + +/* + * The values here don't completely map everything but should work in most + * cases. + * + * MAP A (PReP Map) + * Processor: 0x80000000 - 0x807fffff -> PCI I/O: 0x00000000 - 0x007fffff + * Processor: 0xc0000000 - 0xdfffffff -> PCI MEM: 0x00000000 - 0x1fffffff + * PCI MEM: 0x80000000 -> Processor System Memory: 0x00000000 + * EUMB mapped to: ioremap_base - 0x00100000 (ioremap_base - 1 MB) + * + * MAP B (CHRP Map) + * Processor: 0xfe000000 - 0xfebfffff -> PCI I/O: 0x00000000 - 0x00bfffff + * Processor: 0x80000000 - 0xbfffffff -> PCI MEM: 0x80000000 - 0xbfffffff + * PCI MEM: 0x00000000 -> Processor System Memory: 0x00000000 + * EUMB mapped to: ioremap_base - 0x00100000 (ioremap_base - 1 MB) + */ + +/* + * Define the vendor/device IDs for the various bridges--should be added to + * + */ +#define MPC10X_BRIDGE_106 ((PCI_DEVICE_ID_MOTOROLA_MPC106 << 16) | \ + PCI_VENDOR_ID_MOTOROLA) +#define MPC10X_BRIDGE_8240 ((0x0003 << 16) | PCI_VENDOR_ID_MOTOROLA) +#define MPC10X_BRIDGE_107 ((0x0004 << 16) | PCI_VENDOR_ID_MOTOROLA) +#define MPC10X_BRIDGE_8245 ((0x0006 << 16) | PCI_VENDOR_ID_MOTOROLA) + +/* Define the type of map to use */ +#define MPC10X_MEM_MAP_A 1 +#define MPC10X_MEM_MAP_B 2 + +/* Map A (PReP Map) Defines */ +#define MPC10X_MAPA_CNFG_ADDR 0x80000cf8 +#define MPC10X_MAPA_CNFG_DATA 0x80000cfc + +#define MPC10X_MAPA_ISA_IO_BASE 0x80000000 +#define MPC10X_MAPA_ISA_MEM_BASE 0xc0000000 +#define MPC10X_MAPA_DRAM_OFFSET 0x80000000 + +#define MPC10X_MAPA_PCI_INTACK_ADDR 0xbffffff0 +#define MPC10X_MAPA_PCI_IO_START 0x00000000 +#define MPC10X_MAPA_PCI_IO_END (0x00800000 - 1) +#define MPC10X_MAPA_PCI_MEM_START 0x00000000 +#define MPC10X_MAPA_PCI_MEM_END (0x20000000 - 1) + +#define MPC10X_MAPA_PCI_MEM_OFFSET (MPC10X_MAPA_ISA_MEM_BASE - \ + MPC10X_MAPA_PCI_MEM_START) + +/* Map B (CHRP Map) Defines */ +#define MPC10X_MAPB_CNFG_ADDR 0xfec00000 +#define MPC10X_MAPB_CNFG_DATA 0xfee00000 + +#define MPC10X_MAPB_ISA_IO_BASE 0xfe000000 +#define MPC10X_MAPB_ISA_MEM_BASE 0x80000000 +#define MPC10X_MAPB_DRAM_OFFSET 0x00000000 + +#define MPC10X_MAPB_PCI_INTACK_ADDR 0xfef00000 +#define MPC10X_MAPB_PCI_IO_START 0x00000000 +#define MPC10X_MAPB_PCI_IO_END (0x00c00000 - 1) +#define MPC10X_MAPB_PCI_MEM_START 0x80000000 +#define MPC10X_MAPB_PCI_MEM_END (0xc0000000 - 1) + +#define MPC10X_MAPB_PCI_MEM_OFFSET (MPC10X_MAPB_ISA_MEM_BASE - \ + MPC10X_MAPB_PCI_MEM_START) + +/* Set hose members to values appropriate for the mem map used */ +#define MPC10X_SETUP_HOSE(hose, map) { \ + (hose)->pci_mem_offset = MPC10X_MAP##map##_PCI_MEM_OFFSET; \ + (hose)->io_space.start = MPC10X_MAP##map##_PCI_IO_START; \ + (hose)->io_space.end = MPC10X_MAP##map##_PCI_IO_END; \ + (hose)->mem_space.start = MPC10X_MAP##map##_PCI_MEM_START; \ + (hose)->mem_space.end = MPC10X_MAP##map##_PCI_MEM_END; \ + (hose)->io_base_virt = (void *)MPC10X_MAP##map##_ISA_IO_BASE; \ +} + + +/* Miscellaneous Configuration register offsets */ +#define MPC10X_CFG_PIR_REG 0x09 +#define MPC10X_CFG_PIR_HOST_BRIDGE 0x00 +#define MPC10X_CFG_PIR_AGENT 0x01 + +#define MPC10X_CFG_EUMBBAR 0x78 + +#define MPC10X_CFG_PICR1_REG 0xa8 +#define MPC10X_CFG_PICR1_ADDR_MAP_MASK 0x00010000 +#define MPC10X_CFG_PICR1_ADDR_MAP_A 0x00010000 +#define MPC10X_CFG_PICR1_ADDR_MAP_B 0x00000000 +#define MPC10X_CFG_PICR1_SPEC_PCI_RD 0x00000004 +#define MPC10X_CFG_PICR1_ST_GATH_EN 0x00000040 + +#define MPC10X_CFG_PICR2_REG 0xac +#define MPC10X_CFG_PICR2_COPYBACK_OPT 0x00000001 + +#define MPC10X_CFG_MAPB_OPTIONS_REG 0xe0 +#define MPC10X_CFG_MAPB_OPTIONS_CFAE 0x80 /* CPU_FD_ALIAS_EN */ +#define MPC10X_CFG_MAPB_OPTIONS_PFAE 0x40 /* PCI_FD_ALIAS_EN */ +#define MPC10X_CFG_MAPB_OPTIONS_DR 0x20 /* DLL_RESET */ +#define MPC10X_CFG_MAPB_OPTIONS_PCICH 0x08 /* PCI_COMPATIBILITY_HOLE */ +#define MPC10X_CFG_MAPB_OPTIONS_PROCCH 0x04 /* PROC_COMPATIBILITY_HOLE */ + +/* Define offsets for the memory controller registers in the config space */ +#define MPC10X_MCTLR_MEM_START_1 0x80 /* Banks 0-3 */ +#define MPC10X_MCTLR_MEM_START_2 0x84 /* Banks 4-7 */ +#define MPC10X_MCTLR_EXT_MEM_START_1 0x88 /* Banks 0-3 */ +#define MPC10X_MCTLR_EXT_MEM_START_2 0x8c /* Banks 4-7 */ + +#define MPC10X_MCTLR_MEM_END_1 0x90 /* Banks 0-3 */ +#define MPC10X_MCTLR_MEM_END_2 0x94 /* Banks 4-7 */ +#define MPC10X_MCTLR_EXT_MEM_END_1 0x98 /* Banks 0-3 */ +#define MPC10X_MCTLR_EXT_MEM_END_2 0x9c /* Banks 4-7 */ + +#define MPC10X_MCTLR_MEM_BANK_ENABLES 0xa0 + +/* Define some offset in the EUMB */ +#define MPC10X_EUMB_SIZE 0x00100000 /* Total EUMB size (1MB) */ + +#define MPC10X_EUMB_MU_OFFSET 0x00000000 /* Msg Unit reg offset */ +#define MPC10X_EUMB_MU_SIZE 0x00001000 /* Msg Unit reg size */ +#define MPC10X_EUMB_DMA_OFFSET 0x00001000 /* DMA Unit reg offset */ +#define MPC10X_EUMB_DMA_SIZE 0x00001000 /* DMA Unit reg size */ +#define MPC10X_EUMB_ATU_OFFSET 0x00002000 /* Addr xlate reg offset */ +#define MPC10X_EUMB_ATU_SIZE 0x00001000 /* Addr xlate reg size */ +#define MPC10X_EUMB_I2C_OFFSET 0x00003000 /* I2C Unit reg offset */ +#define MPC10X_EUMB_I2C_SIZE 0x00001000 /* I2C Unit reg size */ +#define MPC10X_EUMB_DUART_OFFSET 0x00004000 /* DUART Unit reg offset (8245) */ +#define MPC10X_EUMB_DUART_SIZE 0x00001000 /* DUART Unit reg size (8245) */ +#define MPC10X_EUMB_EPIC_OFFSET 0x00040000 /* EPIC offset in EUMB */ +#define MPC10X_EUMB_EPIC_SIZE 0x00030000 /* EPIC size */ +#define MPC10X_EUMB_PM_OFFSET 0x000fe000 /* Performance Monitor reg offset (8245) */ +#define MPC10X_EUMB_PM_SIZE 0x00001000 /* Performance Monitor reg size (8245) */ +#define MPC10X_EUMB_WP_OFFSET 0x000ff000 /* Data path diagnostic, watchpoint reg offset */ +#define MPC10X_EUMB_WP_SIZE 0x00001000 /* Data path diagnostic, watchpoint reg size */ + +/* + * Define some recommended places to put the EUMB regs. + * For both maps, recommend putting the EUMB from 0xeff00000 to 0xefffffff. + */ +extern unsigned long ioremap_base; +#define MPC10X_MAPA_EUMB_BASE (ioremap_base - MPC10X_EUMB_SIZE) +#define MPC10X_MAPB_EUMB_BASE MPC10X_MAPA_EUMB_BASE + +enum ppc_sys_devices { + MPC10X_IIC1, + MPC10X_DMA0, + MPC10X_DMA1, + MPC10X_UART0, + MPC10X_UART1, + NUM_PPC_SYS_DEVS, +}; + +int mpc10x_bridge_init(struct pci_controller *hose, + uint current_map, + uint new_map, + uint phys_eumb_base); +unsigned long mpc10x_get_mem_size(uint mem_map); +int mpc10x_enable_store_gathering(struct pci_controller *hose); +int mpc10x_disable_store_gathering(struct pci_controller *hose); + +/* For MPC107 boards that use the built-in openpic */ +void mpc10x_set_openpic(void); + +#endif /* __PPC_KERNEL_MPC10X_H */ diff --git a/drivers/macintosh/ans-lcd.c b/drivers/macintosh/ans-lcd.c index e54c4d9f636..73c50bc0209 100644 --- a/drivers/macintosh/ans-lcd.c +++ b/drivers/macintosh/ans-lcd.c @@ -14,9 +14,10 @@ #include #include #include -#include #include +#include "ans-lcd.h" + #define ANSLCD_ADDR 0xf301c000 #define ANSLCD_CTRL_IX 0x00 #define ANSLCD_DATA_IX 0x10 diff --git a/drivers/macintosh/ans-lcd.h b/drivers/macintosh/ans-lcd.h new file mode 100644 index 00000000000..d795b9fd2db --- /dev/null +++ b/drivers/macintosh/ans-lcd.h @@ -0,0 +1,11 @@ +#ifndef _PPC_ANS_LCD_H +#define _PPC_ANS_LCD_H + +#define ANSLCD_MINOR 156 + +#define ANSLCD_CLEAR 0x01 +#define ANSLCD_SENDCTRL 0x02 +#define ANSLCD_SETSHORTDELAY 0x03 +#define ANSLCD_SETLONGDELAY 0x04 + +#endif diff --git a/include/asm-powerpc/8xx_immap.h b/include/asm-powerpc/8xx_immap.h new file mode 100644 index 00000000000..1311cefdfd3 --- /dev/null +++ b/include/asm-powerpc/8xx_immap.h @@ -0,0 +1,564 @@ +/* + * MPC8xx Internal Memory Map + * Copyright (c) 1997 Dan Malek (dmalek@jlc.net) + * + * The I/O on the MPC860 is comprised of blocks of special registers + * and the dual port ram for the Communication Processor Module. + * Within this space are functional units such as the SIU, memory + * controller, system timers, and other control functions. It is + * a combination that I found difficult to separate into logical + * functional files.....but anyone else is welcome to try. -- Dan + */ +#ifdef __KERNEL__ +#ifndef __IMMAP_8XX__ +#define __IMMAP_8XX__ + +/* System configuration registers. +*/ +typedef struct sys_conf { + uint sc_siumcr; + uint sc_sypcr; + uint sc_swt; + char res1[2]; + ushort sc_swsr; + uint sc_sipend; + uint sc_simask; + uint sc_siel; + uint sc_sivec; + uint sc_tesr; + char res2[0xc]; + uint sc_sdcr; + char res3[0x4c]; +} sysconf8xx_t; + +/* PCMCIA configuration registers. +*/ +typedef struct pcmcia_conf { + uint pcmc_pbr0; + uint pcmc_por0; + uint pcmc_pbr1; + uint pcmc_por1; + uint pcmc_pbr2; + uint pcmc_por2; + uint pcmc_pbr3; + uint pcmc_por3; + uint pcmc_pbr4; + uint pcmc_por4; + uint pcmc_pbr5; + uint pcmc_por5; + uint pcmc_pbr6; + uint pcmc_por6; + uint pcmc_pbr7; + uint pcmc_por7; + char res1[0x20]; + uint pcmc_pgcra; + uint pcmc_pgcrb; + uint pcmc_pscr; + char res2[4]; + uint pcmc_pipr; + char res3[4]; + uint pcmc_per; + char res4[4]; +} pcmconf8xx_t; + +/* Memory controller registers. +*/ +typedef struct mem_ctlr { + uint memc_br0; + uint memc_or0; + uint memc_br1; + uint memc_or1; + uint memc_br2; + uint memc_or2; + uint memc_br3; + uint memc_or3; + uint memc_br4; + uint memc_or4; + uint memc_br5; + uint memc_or5; + uint memc_br6; + uint memc_or6; + uint memc_br7; + uint memc_or7; + char res1[0x24]; + uint memc_mar; + uint memc_mcr; + char res2[4]; + uint memc_mamr; + uint memc_mbmr; + ushort memc_mstat; + ushort memc_mptpr; + uint memc_mdr; + char res3[0x80]; +} memctl8xx_t; + +/*----------------------------------------------------------------------- + * BR - Memory Controler: Base Register 16-9 + */ +#define BR_BA_MSK 0xffff8000 /* Base Address Mask */ +#define BR_AT_MSK 0x00007000 /* Address Type Mask */ +#define BR_PS_MSK 0x00000c00 /* Port Size Mask */ +#define BR_PS_32 0x00000000 /* 32 bit port size */ +#define BR_PS_16 0x00000800 /* 16 bit port size */ +#define BR_PS_8 0x00000400 /* 8 bit port size */ +#define BR_PARE 0x00000200 /* Parity Enable */ +#define BR_WP 0x00000100 /* Write Protect */ +#define BR_MS_MSK 0x000000c0 /* Machine Select Mask */ +#define BR_MS_GPCM 0x00000000 /* G.P.C.M. Machine Select */ +#define BR_MS_UPMA 0x00000080 /* U.P.M.A Machine Select */ +#define BR_MS_UPMB 0x000000c0 /* U.P.M.B Machine Select */ +#define BR_V 0x00000001 /* Bank Valid */ + +/*----------------------------------------------------------------------- + * OR - Memory Controler: Option Register 16-11 + */ +#define OR_AM_MSK 0xffff8000 /* Address Mask Mask */ +#define OR_ATM_MSK 0x00007000 /* Address Type Mask Mask */ +#define OR_CSNT_SAM 0x00000800 /* Chip Select Negation Time/ Start */ + /* Address Multiplex */ +#define OR_ACS_MSK 0x00000600 /* Address to Chip Select Setup mask */ +#define OR_ACS_DIV1 0x00000000 /* CS is output at the same time */ +#define OR_ACS_DIV4 0x00000400 /* CS is output 1/4 a clock later */ +#define OR_ACS_DIV2 0x00000600 /* CS is output 1/2 a clock later */ +#define OR_G5LA 0x00000400 /* Output #GPL5 on #GPL_A5 */ +#define OR_G5LS 0x00000200 /* Drive #GPL high on falling edge of...*/ +#define OR_BI 0x00000100 /* Burst inhibit */ +#define OR_SCY_MSK 0x000000f0 /* Cycle Lenght in Clocks */ +#define OR_SCY_0_CLK 0x00000000 /* 0 clock cycles wait states */ +#define OR_SCY_1_CLK 0x00000010 /* 1 clock cycles wait states */ +#define OR_SCY_2_CLK 0x00000020 /* 2 clock cycles wait states */ +#define OR_SCY_3_CLK 0x00000030 /* 3 clock cycles wait states */ +#define OR_SCY_4_CLK 0x00000040 /* 4 clock cycles wait states */ +#define OR_SCY_5_CLK 0x00000050 /* 5 clock cycles wait states */ +#define OR_SCY_6_CLK 0x00000060 /* 6 clock cycles wait states */ +#define OR_SCY_7_CLK 0x00000070 /* 7 clock cycles wait states */ +#define OR_SCY_8_CLK 0x00000080 /* 8 clock cycles wait states */ +#define OR_SCY_9_CLK 0x00000090 /* 9 clock cycles wait states */ +#define OR_SCY_10_CLK 0x000000a0 /* 10 clock cycles wait states */ +#define OR_SCY_11_CLK 0x000000b0 /* 11 clock cycles wait states */ +#define OR_SCY_12_CLK 0x000000c0 /* 12 clock cycles wait states */ +#define OR_SCY_13_CLK 0x000000d0 /* 13 clock cycles wait states */ +#define OR_SCY_14_CLK 0x000000e0 /* 14 clock cycles wait states */ +#define OR_SCY_15_CLK 0x000000f0 /* 15 clock cycles wait states */ +#define OR_SETA 0x00000008 /* External Transfer Acknowledge */ +#define OR_TRLX 0x00000004 /* Timing Relaxed */ +#define OR_EHTR 0x00000002 /* Extended Hold Time on Read */ + +/* System Integration Timers. +*/ +typedef struct sys_int_timers { + ushort sit_tbscr; + char res0[0x02]; + uint sit_tbreff0; + uint sit_tbreff1; + char res1[0x14]; + ushort sit_rtcsc; + char res2[0x02]; + uint sit_rtc; + uint sit_rtsec; + uint sit_rtcal; + char res3[0x10]; + ushort sit_piscr; + char res4[2]; + uint sit_pitc; + uint sit_pitr; + char res5[0x34]; +} sit8xx_t; + +#define TBSCR_TBIRQ_MASK ((ushort)0xff00) +#define TBSCR_REFA ((ushort)0x0080) +#define TBSCR_REFB ((ushort)0x0040) +#define TBSCR_REFAE ((ushort)0x0008) +#define TBSCR_REFBE ((ushort)0x0004) +#define TBSCR_TBF ((ushort)0x0002) +#define TBSCR_TBE ((ushort)0x0001) + +#define RTCSC_RTCIRQ_MASK ((ushort)0xff00) +#define RTCSC_SEC ((ushort)0x0080) +#define RTCSC_ALR ((ushort)0x0040) +#define RTCSC_38K ((ushort)0x0010) +#define RTCSC_SIE ((ushort)0x0008) +#define RTCSC_ALE ((ushort)0x0004) +#define RTCSC_RTF ((ushort)0x0002) +#define RTCSC_RTE ((ushort)0x0001) + +#define PISCR_PIRQ_MASK ((ushort)0xff00) +#define PISCR_PS ((ushort)0x0080) +#define PISCR_PIE ((ushort)0x0004) +#define PISCR_PTF ((ushort)0x0002) +#define PISCR_PTE ((ushort)0x0001) + +/* Clocks and Reset. +*/ +typedef struct clk_and_reset { + uint car_sccr; + uint car_plprcr; + uint car_rsr; + char res[0x74]; /* Reserved area */ +} car8xx_t; + +/* System Integration Timers keys. +*/ +typedef struct sitk { + uint sitk_tbscrk; + uint sitk_tbreff0k; + uint sitk_tbreff1k; + uint sitk_tbk; + char res1[0x10]; + uint sitk_rtcsck; + uint sitk_rtck; + uint sitk_rtseck; + uint sitk_rtcalk; + char res2[0x10]; + uint sitk_piscrk; + uint sitk_pitck; + char res3[0x38]; +} sitk8xx_t; + +/* Clocks and reset keys. +*/ +typedef struct cark { + uint cark_sccrk; + uint cark_plprcrk; + uint cark_rsrk; + char res[0x474]; +} cark8xx_t; + +/* The key to unlock registers maintained by keep-alive power. +*/ +#define KAPWR_KEY ((unsigned int)0x55ccaa33) + +/* Video interface. MPC823 Only. +*/ +typedef struct vid823 { + ushort vid_vccr; + ushort res1; + u_char vid_vsr; + u_char res2; + u_char vid_vcmr; + u_char res3; + uint vid_vbcb; + uint res4; + uint vid_vfcr0; + uint vid_vfaa0; + uint vid_vfba0; + uint vid_vfcr1; + uint vid_vfaa1; + uint vid_vfba1; + u_char res5[0x18]; +} vid823_t; + +/* LCD interface. 823 Only. +*/ +typedef struct lcd { + uint lcd_lccr; + uint lcd_lchcr; + uint lcd_lcvcr; + char res1[4]; + uint lcd_lcfaa; + uint lcd_lcfba; + char lcd_lcsr; + char res2[0x7]; +} lcd823_t; + +/* I2C +*/ +typedef struct i2c { + u_char i2c_i2mod; + char res1[3]; + u_char i2c_i2add; + char res2[3]; + u_char i2c_i2brg; + char res3[3]; + u_char i2c_i2com; + char res4[3]; + u_char i2c_i2cer; + char res5[3]; + u_char i2c_i2cmr; + char res6[0x8b]; +} i2c8xx_t; + +/* DMA control/status registers. +*/ +typedef struct sdma_csr { + char res1[4]; + uint sdma_sdar; + u_char sdma_sdsr; + char res3[3]; + u_char sdma_sdmr; + char res4[3]; + u_char sdma_idsr1; + char res5[3]; + u_char sdma_idmr1; + char res6[3]; + u_char sdma_idsr2; + char res7[3]; + u_char sdma_idmr2; + char res8[0x13]; +} sdma8xx_t; + +/* Communication Processor Module Interrupt Controller. +*/ +typedef struct cpm_ic { + ushort cpic_civr; + char res[0xe]; + uint cpic_cicr; + uint cpic_cipr; + uint cpic_cimr; + uint cpic_cisr; +} cpic8xx_t; + +/* Input/Output Port control/status registers. +*/ +typedef struct io_port { + ushort iop_padir; + ushort iop_papar; + ushort iop_paodr; + ushort iop_padat; + char res1[8]; + ushort iop_pcdir; + ushort iop_pcpar; + ushort iop_pcso; + ushort iop_pcdat; + ushort iop_pcint; + char res2[6]; + ushort iop_pddir; + ushort iop_pdpar; + char res3[2]; + ushort iop_pddat; + uint utmode; + char res4[4]; +} iop8xx_t; + +/* Communication Processor Module Timers +*/ +typedef struct cpm_timers { + ushort cpmt_tgcr; + char res1[0xe]; + ushort cpmt_tmr1; + ushort cpmt_tmr2; + ushort cpmt_trr1; + ushort cpmt_trr2; + ushort cpmt_tcr1; + ushort cpmt_tcr2; + ushort cpmt_tcn1; + ushort cpmt_tcn2; + ushort cpmt_tmr3; + ushort cpmt_tmr4; + ushort cpmt_trr3; + ushort cpmt_trr4; + ushort cpmt_tcr3; + ushort cpmt_tcr4; + ushort cpmt_tcn3; + ushort cpmt_tcn4; + ushort cpmt_ter1; + ushort cpmt_ter2; + ushort cpmt_ter3; + ushort cpmt_ter4; + char res2[8]; +} cpmtimer8xx_t; + +/* Finally, the Communication Processor stuff..... +*/ +typedef struct scc { /* Serial communication channels */ + uint scc_gsmrl; + uint scc_gsmrh; + ushort scc_psmr; + char res1[2]; + ushort scc_todr; + ushort scc_dsr; + ushort scc_scce; + char res2[2]; + ushort scc_sccm; + char res3; + u_char scc_sccs; + char res4[8]; +} scc_t; + +typedef struct smc { /* Serial management channels */ + char res1[2]; + ushort smc_smcmr; + char res2[2]; + u_char smc_smce; + char res3[3]; + u_char smc_smcm; + char res4[5]; +} smc_t; + +/* MPC860T Fast Ethernet Controller. It isn't part of the CPM, but + * it fits within the address space. + */ + +typedef struct fec { + uint fec_addr_low; /* lower 32 bits of station address */ + ushort fec_addr_high; /* upper 16 bits of station address */ + ushort res1; /* reserved */ + uint fec_hash_table_high; /* upper 32-bits of hash table */ + uint fec_hash_table_low; /* lower 32-bits of hash table */ + uint fec_r_des_start; /* beginning of Rx descriptor ring */ + uint fec_x_des_start; /* beginning of Tx descriptor ring */ + uint fec_r_buff_size; /* Rx buffer size */ + uint res2[9]; /* reserved */ + uint fec_ecntrl; /* ethernet control register */ + uint fec_ievent; /* interrupt event register */ + uint fec_imask; /* interrupt mask register */ + uint fec_ivec; /* interrupt level and vector status */ + uint fec_r_des_active; /* Rx ring updated flag */ + uint fec_x_des_active; /* Tx ring updated flag */ + uint res3[10]; /* reserved */ + uint fec_mii_data; /* MII data register */ + uint fec_mii_speed; /* MII speed control register */ + uint res4[17]; /* reserved */ + uint fec_r_bound; /* end of RAM (read-only) */ + uint fec_r_fstart; /* Rx FIFO start address */ + uint res5[6]; /* reserved */ + uint fec_x_fstart; /* Tx FIFO start address */ + uint res6[17]; /* reserved */ + uint fec_fun_code; /* fec SDMA function code */ + uint res7[3]; /* reserved */ + uint fec_r_cntrl; /* Rx control register */ + uint fec_r_hash; /* Rx hash register */ + uint res8[14]; /* reserved */ + uint fec_x_cntrl; /* Tx control register */ + uint res9[0x1e]; /* reserved */ +} fec_t; + +/* The FEC and LCD color map share the same address space.... + * I guess we will never see an 823T :-). + */ +union fec_lcd { + fec_t fl_un_fec; + u_char fl_un_cmap[0x200]; +}; + +typedef struct comm_proc { + /* General control and status registers. + */ + ushort cp_cpcr; + u_char res1[2]; + ushort cp_rccr; + u_char res2; + u_char cp_rmds; + u_char res3[4]; + ushort cp_cpmcr1; + ushort cp_cpmcr2; + ushort cp_cpmcr3; + ushort cp_cpmcr4; + u_char res4[2]; + ushort cp_rter; + u_char res5[2]; + ushort cp_rtmr; + u_char res6[0x14]; + + /* Baud rate generators. + */ + uint cp_brgc1; + uint cp_brgc2; + uint cp_brgc3; + uint cp_brgc4; + + /* Serial Communication Channels. + */ + scc_t cp_scc[4]; + + /* Serial Management Channels. + */ + smc_t cp_smc[2]; + + /* Serial Peripheral Interface. + */ + ushort cp_spmode; + u_char res7[4]; + u_char cp_spie; + u_char res8[3]; + u_char cp_spim; + u_char res9[2]; + u_char cp_spcom; + u_char res10[2]; + + /* Parallel Interface Port. + */ + u_char res11[2]; + ushort cp_pipc; + u_char res12[2]; + ushort cp_ptpr; + uint cp_pbdir; + uint cp_pbpar; + u_char res13[2]; + ushort cp_pbodr; + uint cp_pbdat; + + /* Port E - MPC87x/88x only. + */ + uint cp_pedir; + uint cp_pepar; + uint cp_peso; + uint cp_peodr; + uint cp_pedat; + + /* Communications Processor Timing Register - + Contains RMII Timing for the FECs on MPC87x/88x only. + */ + uint cp_cptr; + + /* Serial Interface and Time Slot Assignment. + */ + uint cp_simode; + u_char cp_sigmr; + u_char res15; + u_char cp_sistr; + u_char cp_sicmr; + u_char res16[4]; + uint cp_sicr; + uint cp_sirp; + u_char res17[0xc]; + + /* 256 bytes of MPC823 video controller RAM array. + */ + u_char cp_vcram[0x100]; + u_char cp_siram[0x200]; + + /* The fast ethernet controller is not really part of the CPM, + * but it resides in the address space. + * The LCD color map is also here. + */ + union fec_lcd fl_un; +#define cp_fec fl_un.fl_un_fec +#define lcd_cmap fl_un.fl_un_cmap + char res18[0xE00]; + + /* The DUET family has a second FEC here */ + fec_t cp_fec2; +#define cp_fec1 cp_fec /* consistency macro */ + + /* Dual Ported RAM follows. + * There are many different formats for this memory area + * depending upon the devices used and options chosen. + * Some processors don't have all of it populated. + */ + u_char cp_dpmem[0x1C00]; /* BD / Data / ucode */ + u_char cp_dparam[0x400]; /* Parameter RAM */ +} cpm8xx_t; + +/* Internal memory map. +*/ +typedef struct immap { + sysconf8xx_t im_siu_conf; /* SIU Configuration */ + pcmconf8xx_t im_pcmcia; /* PCMCIA Configuration */ + memctl8xx_t im_memctl; /* Memory Controller */ + sit8xx_t im_sit; /* System integration timers */ + car8xx_t im_clkrst; /* Clocks and reset */ + sitk8xx_t im_sitk; /* Sys int timer keys */ + cark8xx_t im_clkrstk; /* Clocks and reset keys */ + vid823_t im_vid; /* Video (823 only) */ + lcd823_t im_lcd; /* LCD (823 only) */ + i2c8xx_t im_i2c; /* I2C control/status */ + sdma8xx_t im_sdma; /* SDMA control/status */ + cpic8xx_t im_cpic; /* CPM Interrupt Controller */ + iop8xx_t im_ioport; /* IO Port control/status */ + cpmtimer8xx_t im_cpmtimer; /* CPM timers */ + cpm8xx_t im_cpm; /* Communication processor */ +} immap_t; + +#endif /* __IMMAP_8XX__ */ +#endif /* __KERNEL__ */ diff --git a/include/asm-powerpc/commproc.h b/include/asm-powerpc/commproc.h new file mode 100644 index 00000000000..397248705e0 --- /dev/null +++ b/include/asm-powerpc/commproc.h @@ -0,0 +1,692 @@ +/* + * MPC8xx Communication Processor Module. + * Copyright (c) 1997 Dan Malek (dmalek@jlc.net) + * + * This file contains structures and information for the communication + * processor channels. Some CPM control and status is available + * throught the MPC8xx internal memory map. See immap.h for details. + * This file only contains what I need for the moment, not the total + * CPM capabilities. I (or someone else) will add definitions as they + * are needed. -- Dan + * + * On the MBX board, EPPC-Bug loads CPM microcode into the first 512 + * bytes of the DP RAM and relocates the I2C parameter area to the + * IDMA1 space. The remaining DP RAM is available for buffer descriptors + * or other use. + */ +#ifndef __CPM_8XX__ +#define __CPM_8XX__ + +#include +#include + +/* CPM Command register. +*/ +#define CPM_CR_RST ((ushort)0x8000) +#define CPM_CR_OPCODE ((ushort)0x0f00) +#define CPM_CR_CHAN ((ushort)0x00f0) +#define CPM_CR_FLG ((ushort)0x0001) + +/* Some commands (there are more...later) +*/ +#define CPM_CR_INIT_TRX ((ushort)0x0000) +#define CPM_CR_INIT_RX ((ushort)0x0001) +#define CPM_CR_INIT_TX ((ushort)0x0002) +#define CPM_CR_HUNT_MODE ((ushort)0x0003) +#define CPM_CR_STOP_TX ((ushort)0x0004) +#define CPM_CR_GRA_STOP_TX ((ushort)0x0005) +#define CPM_CR_RESTART_TX ((ushort)0x0006) +#define CPM_CR_CLOSE_RX_BD ((ushort)0x0007) +#define CPM_CR_SET_GADDR ((ushort)0x0008) +#define CPM_CR_SET_TIMER CPM_CR_SET_GADDR + +/* Channel numbers. +*/ +#define CPM_CR_CH_SCC1 ((ushort)0x0000) +#define CPM_CR_CH_I2C ((ushort)0x0001) /* I2C and IDMA1 */ +#define CPM_CR_CH_SCC2 ((ushort)0x0004) +#define CPM_CR_CH_SPI ((ushort)0x0005) /* SPI / IDMA2 / Timers */ +#define CPM_CR_CH_TIMER CPM_CR_CH_SPI +#define CPM_CR_CH_SCC3 ((ushort)0x0008) +#define CPM_CR_CH_SMC1 ((ushort)0x0009) /* SMC1 / DSP1 */ +#define CPM_CR_CH_SCC4 ((ushort)0x000c) +#define CPM_CR_CH_SMC2 ((ushort)0x000d) /* SMC2 / DSP2 */ + +#define mk_cr_cmd(CH, CMD) ((CMD << 8) | (CH << 4)) + +/* The dual ported RAM is multi-functional. Some areas can be (and are + * being) used for microcode. There is an area that can only be used + * as data ram for buffer descriptors, which is all we use right now. + * Currently the first 512 and last 256 bytes are used for microcode. + */ +#define CPM_DATAONLY_BASE ((uint)0x0800) +#define CPM_DATAONLY_SIZE ((uint)0x0700) +#define CPM_DP_NOSPACE ((uint)0x7fffffff) + +/* Export the base address of the communication processor registers + * and dual port ram. + */ +extern cpm8xx_t *cpmp; /* Pointer to comm processor */ +extern unsigned long cpm_dpalloc(uint size, uint align); +extern int cpm_dpfree(unsigned long offset); +extern unsigned long cpm_dpalloc_fixed(unsigned long offset, uint size, uint align); +extern void cpm_dpdump(void); +extern void *cpm_dpram_addr(unsigned long offset); +extern uint cpm_dpram_phys(u8* addr); +extern void cpm_setbrg(uint brg, uint rate); + +extern uint m8xx_cpm_hostalloc(uint size); +extern int m8xx_cpm_hostfree(uint start); +extern void m8xx_cpm_hostdump(void); + +extern void cpm_load_patch(volatile immap_t *immr); + +/* Buffer descriptors used by many of the CPM protocols. +*/ +typedef struct cpm_buf_desc { + ushort cbd_sc; /* Status and Control */ + ushort cbd_datlen; /* Data length in buffer */ + uint cbd_bufaddr; /* Buffer address in host memory */ +} cbd_t; + +#define BD_SC_EMPTY ((ushort)0x8000) /* Receive is empty */ +#define BD_SC_READY ((ushort)0x8000) /* Transmit is ready */ +#define BD_SC_WRAP ((ushort)0x2000) /* Last buffer descriptor */ +#define BD_SC_INTRPT ((ushort)0x1000) /* Interrupt on change */ +#define BD_SC_LAST ((ushort)0x0800) /* Last buffer in frame */ +#define BD_SC_TC ((ushort)0x0400) /* Transmit CRC */ +#define BD_SC_CM ((ushort)0x0200) /* Continous mode */ +#define BD_SC_ID ((ushort)0x0100) /* Rec'd too many idles */ +#define BD_SC_P ((ushort)0x0100) /* xmt preamble */ +#define BD_SC_BR ((ushort)0x0020) /* Break received */ +#define BD_SC_FR ((ushort)0x0010) /* Framing error */ +#define BD_SC_PR ((ushort)0x0008) /* Parity error */ +#define BD_SC_NAK ((ushort)0x0004) /* NAK - did not respond */ +#define BD_SC_OV ((ushort)0x0002) /* Overrun */ +#define BD_SC_UN ((ushort)0x0002) /* Underrun */ +#define BD_SC_CD ((ushort)0x0001) /* ?? */ +#define BD_SC_CL ((ushort)0x0001) /* Collision */ + +/* Parameter RAM offsets. +*/ +#define PROFF_SCC1 ((uint)0x0000) +#define PROFF_IIC ((uint)0x0080) +#define PROFF_SCC2 ((uint)0x0100) +#define PROFF_SPI ((uint)0x0180) +#define PROFF_SCC3 ((uint)0x0200) +#define PROFF_SMC1 ((uint)0x0280) +#define PROFF_SCC4 ((uint)0x0300) +#define PROFF_SMC2 ((uint)0x0380) + +/* Define enough so I can at least use the serial port as a UART. + * The MBX uses SMC1 as the host serial port. + */ +typedef struct smc_uart { + ushort smc_rbase; /* Rx Buffer descriptor base address */ + ushort smc_tbase; /* Tx Buffer descriptor base address */ + u_char smc_rfcr; /* Rx function code */ + u_char smc_tfcr; /* Tx function code */ + ushort smc_mrblr; /* Max receive buffer length */ + uint smc_rstate; /* Internal */ + uint smc_idp; /* Internal */ + ushort smc_rbptr; /* Internal */ + ushort smc_ibc; /* Internal */ + uint smc_rxtmp; /* Internal */ + uint smc_tstate; /* Internal */ + uint smc_tdp; /* Internal */ + ushort smc_tbptr; /* Internal */ + ushort smc_tbc; /* Internal */ + uint smc_txtmp; /* Internal */ + ushort smc_maxidl; /* Maximum idle characters */ + ushort smc_tmpidl; /* Temporary idle counter */ + ushort smc_brklen; /* Last received break length */ + ushort smc_brkec; /* rcv'd break condition counter */ + ushort smc_brkcr; /* xmt break count register */ + ushort smc_rmask; /* Temporary bit mask */ + char res1[8]; /* Reserved */ + ushort smc_rpbase; /* Relocation pointer */ +} smc_uart_t; + +/* Function code bits. +*/ +#define SMC_EB ((u_char)0x10) /* Set big endian byte order */ + +/* SMC uart mode register. +*/ +#define SMCMR_REN ((ushort)0x0001) +#define SMCMR_TEN ((ushort)0x0002) +#define SMCMR_DM ((ushort)0x000c) +#define SMCMR_SM_GCI ((ushort)0x0000) +#define SMCMR_SM_UART ((ushort)0x0020) +#define SMCMR_SM_TRANS ((ushort)0x0030) +#define SMCMR_SM_MASK ((ushort)0x0030) +#define SMCMR_PM_EVEN ((ushort)0x0100) /* Even parity, else odd */ +#define SMCMR_REVD SMCMR_PM_EVEN +#define SMCMR_PEN ((ushort)0x0200) /* Parity enable */ +#define SMCMR_BS SMCMR_PEN +#define SMCMR_SL ((ushort)0x0400) /* Two stops, else one */ +#define SMCR_CLEN_MASK ((ushort)0x7800) /* Character length */ +#define smcr_mk_clen(C) (((C) << 11) & SMCR_CLEN_MASK) + +/* SMC2 as Centronics parallel printer. It is half duplex, in that + * it can only receive or transmit. The parameter ram values for + * each direction are either unique or properly overlap, so we can + * include them in one structure. + */ +typedef struct smc_centronics { + ushort scent_rbase; + ushort scent_tbase; + u_char scent_cfcr; + u_char scent_smask; + ushort scent_mrblr; + uint scent_rstate; + uint scent_r_ptr; + ushort scent_rbptr; + ushort scent_r_cnt; + uint scent_rtemp; + uint scent_tstate; + uint scent_t_ptr; + ushort scent_tbptr; + ushort scent_t_cnt; + uint scent_ttemp; + ushort scent_max_sl; + ushort scent_sl_cnt; + ushort scent_character1; + ushort scent_character2; + ushort scent_character3; + ushort scent_character4; + ushort scent_character5; + ushort scent_character6; + ushort scent_character7; + ushort scent_character8; + ushort scent_rccm; + ushort scent_rccr; +} smc_cent_t; + +/* Centronics Status Mask Register. +*/ +#define SMC_CENT_F ((u_char)0x08) +#define SMC_CENT_PE ((u_char)0x04) +#define SMC_CENT_S ((u_char)0x02) + +/* SMC Event and Mask register. +*/ +#define SMCM_BRKE ((unsigned char)0x40) /* When in UART Mode */ +#define SMCM_BRK ((unsigned char)0x10) /* When in UART Mode */ +#define SMCM_TXE ((unsigned char)0x10) /* When in Transparent Mode */ +#define SMCM_BSY ((unsigned char)0x04) +#define SMCM_TX ((unsigned char)0x02) +#define SMCM_RX ((unsigned char)0x01) + +/* Baud rate generators. +*/ +#define CPM_BRG_RST ((uint)0x00020000) +#define CPM_BRG_EN ((uint)0x00010000) +#define CPM_BRG_EXTC_INT ((uint)0x00000000) +#define CPM_BRG_EXTC_CLK2 ((uint)0x00004000) +#define CPM_BRG_EXTC_CLK6 ((uint)0x00008000) +#define CPM_BRG_ATB ((uint)0x00002000) +#define CPM_BRG_CD_MASK ((uint)0x00001ffe) +#define CPM_BRG_DIV16 ((uint)0x00000001) + +/* SI Clock Route Register +*/ +#define SICR_RCLK_SCC1_BRG1 ((uint)0x00000000) +#define SICR_TCLK_SCC1_BRG1 ((uint)0x00000000) +#define SICR_RCLK_SCC2_BRG2 ((uint)0x00000800) +#define SICR_TCLK_SCC2_BRG2 ((uint)0x00000100) +#define SICR_RCLK_SCC3_BRG3 ((uint)0x00100000) +#define SICR_TCLK_SCC3_BRG3 ((uint)0x00020000) +#define SICR_RCLK_SCC4_BRG4 ((uint)0x18000000) +#define SICR_TCLK_SCC4_BRG4 ((uint)0x03000000) + +/* SCCs. +*/ +#define SCC_GSMRH_IRP ((uint)0x00040000) +#define SCC_GSMRH_GDE ((uint)0x00010000) +#define SCC_GSMRH_TCRC_CCITT ((uint)0x00008000) +#define SCC_GSMRH_TCRC_BISYNC ((uint)0x00004000) +#define SCC_GSMRH_TCRC_HDLC ((uint)0x00000000) +#define SCC_GSMRH_REVD ((uint)0x00002000) +#define SCC_GSMRH_TRX ((uint)0x00001000) +#define SCC_GSMRH_TTX ((uint)0x00000800) +#define SCC_GSMRH_CDP ((uint)0x00000400) +#define SCC_GSMRH_CTSP ((uint)0x00000200) +#define SCC_GSMRH_CDS ((uint)0x00000100) +#define SCC_GSMRH_CTSS ((uint)0x00000080) +#define SCC_GSMRH_TFL ((uint)0x00000040) +#define SCC_GSMRH_RFW ((uint)0x00000020) +#define SCC_GSMRH_TXSY ((uint)0x00000010) +#define SCC_GSMRH_SYNL16 ((uint)0x0000000c) +#define SCC_GSMRH_SYNL8 ((uint)0x00000008) +#define SCC_GSMRH_SYNL4 ((uint)0x00000004) +#define SCC_GSMRH_RTSM ((uint)0x00000002) +#define SCC_GSMRH_RSYN ((uint)0x00000001) + +#define SCC_GSMRL_SIR ((uint)0x80000000) /* SCC2 only */ +#define SCC_GSMRL_EDGE_NONE ((uint)0x60000000) +#define SCC_GSMRL_EDGE_NEG ((uint)0x40000000) +#define SCC_GSMRL_EDGE_POS ((uint)0x20000000) +#define SCC_GSMRL_EDGE_BOTH ((uint)0x00000000) +#define SCC_GSMRL_TCI ((uint)0x10000000) +#define SCC_GSMRL_TSNC_3 ((uint)0x0c000000) +#define SCC_GSMRL_TSNC_4 ((uint)0x08000000) +#define SCC_GSMRL_TSNC_14 ((uint)0x04000000) +#define SCC_GSMRL_TSNC_INF ((uint)0x00000000) +#define SCC_GSMRL_RINV ((uint)0x02000000) +#define SCC_GSMRL_TINV ((uint)0x01000000) +#define SCC_GSMRL_TPL_128 ((uint)0x00c00000) +#define SCC_GSMRL_TPL_64 ((uint)0x00a00000) +#define SCC_GSMRL_TPL_48 ((uint)0x00800000) +#define SCC_GSMRL_TPL_32 ((uint)0x00600000) +#define SCC_GSMRL_TPL_16 ((uint)0x00400000) +#define SCC_GSMRL_TPL_8 ((uint)0x00200000) +#define SCC_GSMRL_TPL_NONE ((uint)0x00000000) +#define SCC_GSMRL_TPP_ALL1 ((uint)0x00180000) +#define SCC_GSMRL_TPP_01 ((uint)0x00100000) +#define SCC_GSMRL_TPP_10 ((uint)0x00080000) +#define SCC_GSMRL_TPP_ZEROS ((uint)0x00000000) +#define SCC_GSMRL_TEND ((uint)0x00040000) +#define SCC_GSMRL_TDCR_32 ((uint)0x00030000) +#define SCC_GSMRL_TDCR_16 ((uint)0x00020000) +#define SCC_GSMRL_TDCR_8 ((uint)0x00010000) +#define SCC_GSMRL_TDCR_1 ((uint)0x00000000) +#define SCC_GSMRL_RDCR_32 ((uint)0x0000c000) +#define SCC_GSMRL_RDCR_16 ((uint)0x00008000) +#define SCC_GSMRL_RDCR_8 ((uint)0x00004000) +#define SCC_GSMRL_RDCR_1 ((uint)0x00000000) +#define SCC_GSMRL_RENC_DFMAN ((uint)0x00003000) +#define SCC_GSMRL_RENC_MANCH ((uint)0x00002000) +#define SCC_GSMRL_RENC_FM0 ((uint)0x00001000) +#define SCC_GSMRL_RENC_NRZI ((uint)0x00000800) +#define SCC_GSMRL_RENC_NRZ ((uint)0x00000000) +#define SCC_GSMRL_TENC_DFMAN ((uint)0x00000600) +#define SCC_GSMRL_TENC_MANCH ((uint)0x00000400) +#define SCC_GSMRL_TENC_FM0 ((uint)0x00000200) +#define SCC_GSMRL_TENC_NRZI ((uint)0x00000100) +#define SCC_GSMRL_TENC_NRZ ((uint)0x00000000) +#define SCC_GSMRL_DIAG_LE ((uint)0x000000c0) /* Loop and echo */ +#define SCC_GSMRL_DIAG_ECHO ((uint)0x00000080) +#define SCC_GSMRL_DIAG_LOOP ((uint)0x00000040) +#define SCC_GSMRL_DIAG_NORM ((uint)0x00000000) +#define SCC_GSMRL_ENR ((uint)0x00000020) +#define SCC_GSMRL_ENT ((uint)0x00000010) +#define SCC_GSMRL_MODE_ENET ((uint)0x0000000c) +#define SCC_GSMRL_MODE_QMC ((uint)0x0000000a) +#define SCC_GSMRL_MODE_DDCMP ((uint)0x00000009) +#define SCC_GSMRL_MODE_BISYNC ((uint)0x00000008) +#define SCC_GSMRL_MODE_V14 ((uint)0x00000007) +#define SCC_GSMRL_MODE_AHDLC ((uint)0x00000006) +#define SCC_GSMRL_MODE_PROFIBUS ((uint)0x00000005) +#define SCC_GSMRL_MODE_UART ((uint)0x00000004) +#define SCC_GSMRL_MODE_SS7 ((uint)0x00000003) +#define SCC_GSMRL_MODE_ATALK ((uint)0x00000002) +#define SCC_GSMRL_MODE_HDLC ((uint)0x00000000) + +#define SCC_TODR_TOD ((ushort)0x8000) + +/* SCC Event and Mask register. +*/ +#define SCCM_TXE ((unsigned char)0x10) +#define SCCM_BSY ((unsigned char)0x04) +#define SCCM_TX ((unsigned char)0x02) +#define SCCM_RX ((unsigned char)0x01) + +typedef struct scc_param { + ushort scc_rbase; /* Rx Buffer descriptor base address */ + ushort scc_tbase; /* Tx Buffer descriptor base address */ + u_char scc_rfcr; /* Rx function code */ + u_char scc_tfcr; /* Tx function code */ + ushort scc_mrblr; /* Max receive buffer length */ + uint scc_rstate; /* Internal */ + uint scc_idp; /* Internal */ + ushort scc_rbptr; /* Internal */ + ushort scc_ibc; /* Internal */ + uint scc_rxtmp; /* Internal */ + uint scc_tstate; /* Internal */ + uint scc_tdp; /* Internal */ + ushort scc_tbptr; /* Internal */ + ushort scc_tbc; /* Internal */ + uint scc_txtmp; /* Internal */ + uint scc_rcrc; /* Internal */ + uint scc_tcrc; /* Internal */ +} sccp_t; + +/* Function code bits. +*/ +#define SCC_EB ((u_char)0x10) /* Set big endian byte order */ + +/* CPM Ethernet through SCCx. + */ +typedef struct scc_enet { + sccp_t sen_genscc; + uint sen_cpres; /* Preset CRC */ + uint sen_cmask; /* Constant mask for CRC */ + uint sen_crcec; /* CRC Error counter */ + uint sen_alec; /* alignment error counter */ + uint sen_disfc; /* discard frame counter */ + ushort sen_pads; /* Tx short frame pad character */ + ushort sen_retlim; /* Retry limit threshold */ + ushort sen_retcnt; /* Retry limit counter */ + ushort sen_maxflr; /* maximum frame length register */ + ushort sen_minflr; /* minimum frame length register */ + ushort sen_maxd1; /* maximum DMA1 length */ + ushort sen_maxd2; /* maximum DMA2 length */ + ushort sen_maxd; /* Rx max DMA */ + ushort sen_dmacnt; /* Rx DMA counter */ + ushort sen_maxb; /* Max BD byte count */ + ushort sen_gaddr1; /* Group address filter */ + ushort sen_gaddr2; + ushort sen_gaddr3; + ushort sen_gaddr4; + uint sen_tbuf0data0; /* Save area 0 - current frame */ + uint sen_tbuf0data1; /* Save area 1 - current frame */ + uint sen_tbuf0rba; /* Internal */ + uint sen_tbuf0crc; /* Internal */ + ushort sen_tbuf0bcnt; /* Internal */ + ushort sen_paddrh; /* physical address (MSB) */ + ushort sen_paddrm; + ushort sen_paddrl; /* physical address (LSB) */ + ushort sen_pper; /* persistence */ + ushort sen_rfbdptr; /* Rx first BD pointer */ + ushort sen_tfbdptr; /* Tx first BD pointer */ + ushort sen_tlbdptr; /* Tx last BD pointer */ + uint sen_tbuf1data0; /* Save area 0 - current frame */ + uint sen_tbuf1data1; /* Save area 1 - current frame */ + uint sen_tbuf1rba; /* Internal */ + uint sen_tbuf1crc; /* Internal */ + ushort sen_tbuf1bcnt; /* Internal */ + ushort sen_txlen; /* Tx Frame length counter */ + ushort sen_iaddr1; /* Individual address filter */ + ushort sen_iaddr2; + ushort sen_iaddr3; + ushort sen_iaddr4; + ushort sen_boffcnt; /* Backoff counter */ + + /* NOTE: Some versions of the manual have the following items + * incorrectly documented. Below is the proper order. + */ + ushort sen_taddrh; /* temp address (MSB) */ + ushort sen_taddrm; + ushort sen_taddrl; /* temp address (LSB) */ +} scc_enet_t; + +/* SCC Event register as used by Ethernet. +*/ +#define SCCE_ENET_GRA ((ushort)0x0080) /* Graceful stop complete */ +#define SCCE_ENET_TXE ((ushort)0x0010) /* Transmit Error */ +#define SCCE_ENET_RXF ((ushort)0x0008) /* Full frame received */ +#define SCCE_ENET_BSY ((ushort)0x0004) /* All incoming buffers full */ +#define SCCE_ENET_TXB ((ushort)0x0002) /* A buffer was transmitted */ +#define SCCE_ENET_RXB ((ushort)0x0001) /* A buffer was received */ + +/* SCC Mode Register (PMSR) as used by Ethernet. +*/ +#define SCC_PSMR_HBC ((ushort)0x8000) /* Enable heartbeat */ +#define SCC_PSMR_FC ((ushort)0x4000) /* Force collision */ +#define SCC_PSMR_RSH ((ushort)0x2000) /* Receive short frames */ +#define SCC_PSMR_IAM ((ushort)0x1000) /* Check individual hash */ +#define SCC_PSMR_ENCRC ((ushort)0x0800) /* Ethernet CRC mode */ +#define SCC_PSMR_PRO ((ushort)0x0200) /* Promiscuous mode */ +#define SCC_PSMR_BRO ((ushort)0x0100) /* Catch broadcast pkts */ +#define SCC_PSMR_SBT ((ushort)0x0080) /* Special backoff timer */ +#define SCC_PSMR_LPB ((ushort)0x0040) /* Set Loopback mode */ +#define SCC_PSMR_SIP ((ushort)0x0020) /* Sample Input Pins */ +#define SCC_PSMR_LCW ((ushort)0x0010) /* Late collision window */ +#define SCC_PSMR_NIB22 ((ushort)0x000a) /* Start frame search */ +#define SCC_PSMR_FDE ((ushort)0x0001) /* Full duplex enable */ + +/* Buffer descriptor control/status used by Ethernet receive. +*/ +#define BD_ENET_RX_EMPTY ((ushort)0x8000) +#define BD_ENET_RX_WRAP ((ushort)0x2000) +#define BD_ENET_RX_INTR ((ushort)0x1000) +#define BD_ENET_RX_LAST ((ushort)0x0800) +#define BD_ENET_RX_FIRST ((ushort)0x0400) +#define BD_ENET_RX_MISS ((ushort)0x0100) +#define BD_ENET_RX_LG ((ushort)0x0020) +#define BD_ENET_RX_NO ((ushort)0x0010) +#define BD_ENET_RX_SH ((ushort)0x0008) +#define BD_ENET_RX_CR ((ushort)0x0004) +#define BD_ENET_RX_OV ((ushort)0x0002) +#define BD_ENET_RX_CL ((ushort)0x0001) +#define BD_ENET_RX_BC ((ushort)0x0080) /* DA is Broadcast */ +#define BD_ENET_RX_MC ((ushort)0x0040) /* DA is Multicast */ +#define BD_ENET_RX_STATS ((ushort)0x013f) /* All status bits */ + +/* Buffer descriptor control/status used by Ethernet transmit. +*/ +#define BD_ENET_TX_READY ((ushort)0x8000) +#define BD_ENET_TX_PAD ((ushort)0x4000) +#define BD_ENET_TX_WRAP ((ushort)0x2000) +#define BD_ENET_TX_INTR ((ushort)0x1000) +#define BD_ENET_TX_LAST ((ushort)0x0800) +#define BD_ENET_TX_TC ((ushort)0x0400) +#define BD_ENET_TX_DEF ((ushort)0x0200) +#define BD_ENET_TX_HB ((ushort)0x0100) +#define BD_ENET_TX_LC ((ushort)0x0080) +#define BD_ENET_TX_RL ((ushort)0x0040) +#define BD_ENET_TX_RCMASK ((ushort)0x003c) +#define BD_ENET_TX_UN ((ushort)0x0002) +#define BD_ENET_TX_CSL ((ushort)0x0001) +#define BD_ENET_TX_STATS ((ushort)0x03ff) /* All status bits */ + +/* SCC as UART +*/ +typedef struct scc_uart { + sccp_t scc_genscc; + char res1[8]; /* Reserved */ + ushort scc_maxidl; /* Maximum idle chars */ + ushort scc_idlc; /* temp idle counter */ + ushort scc_brkcr; /* Break count register */ + ushort scc_parec; /* receive parity error counter */ + ushort scc_frmec; /* receive framing error counter */ + ushort scc_nosec; /* receive noise counter */ + ushort scc_brkec; /* receive break condition counter */ + ushort scc_brkln; /* last received break length */ + ushort scc_uaddr1; /* UART address character 1 */ + ushort scc_uaddr2; /* UART address character 2 */ + ushort scc_rtemp; /* Temp storage */ + ushort scc_toseq; /* Transmit out of sequence char */ + ushort scc_char1; /* control character 1 */ + ushort scc_char2; /* control character 2 */ + ushort scc_char3; /* control character 3 */ + ushort scc_char4; /* control character 4 */ + ushort scc_char5; /* control character 5 */ + ushort scc_char6; /* control character 6 */ + ushort scc_char7; /* control character 7 */ + ushort scc_char8; /* control character 8 */ + ushort scc_rccm; /* receive control character mask */ + ushort scc_rccr; /* receive control character register */ + ushort scc_rlbc; /* receive last break character */ +} scc_uart_t; + +/* SCC Event and Mask registers when it is used as a UART. +*/ +#define UART_SCCM_GLR ((ushort)0x1000) +#define UART_SCCM_GLT ((ushort)0x0800) +#define UART_SCCM_AB ((ushort)0x0200) +#define UART_SCCM_IDL ((ushort)0x0100) +#define UART_SCCM_GRA ((ushort)0x0080) +#define UART_SCCM_BRKE ((ushort)0x0040) +#define UART_SCCM_BRKS ((ushort)0x0020) +#define UART_SCCM_CCR ((ushort)0x0008) +#define UART_SCCM_BSY ((ushort)0x0004) +#define UART_SCCM_TX ((ushort)0x0002) +#define UART_SCCM_RX ((ushort)0x0001) + +/* The SCC PMSR when used as a UART. +*/ +#define SCU_PSMR_FLC ((ushort)0x8000) +#define SCU_PSMR_SL ((ushort)0x4000) +#define SCU_PSMR_CL ((ushort)0x3000) +#define SCU_PSMR_UM ((ushort)0x0c00) +#define SCU_PSMR_FRZ ((ushort)0x0200) +#define SCU_PSMR_RZS ((ushort)0x0100) +#define SCU_PSMR_SYN ((ushort)0x0080) +#define SCU_PSMR_DRT ((ushort)0x0040) +#define SCU_PSMR_PEN ((ushort)0x0010) +#define SCU_PSMR_RPM ((ushort)0x000c) +#define SCU_PSMR_REVP ((ushort)0x0008) +#define SCU_PSMR_TPM ((ushort)0x0003) +#define SCU_PSMR_TEVP ((ushort)0x0002) + +/* CPM Transparent mode SCC. + */ +typedef struct scc_trans { + sccp_t st_genscc; + uint st_cpres; /* Preset CRC */ + uint st_cmask; /* Constant mask for CRC */ +} scc_trans_t; + +#define BD_SCC_TX_LAST ((ushort)0x0800) + +/* IIC parameter RAM. +*/ +typedef struct iic { + ushort iic_rbase; /* Rx Buffer descriptor base address */ + ushort iic_tbase; /* Tx Buffer descriptor base address */ + u_char iic_rfcr; /* Rx function code */ + u_char iic_tfcr; /* Tx function code */ + ushort iic_mrblr; /* Max receive buffer length */ + uint iic_rstate; /* Internal */ + uint iic_rdp; /* Internal */ + ushort iic_rbptr; /* Internal */ + ushort iic_rbc; /* Internal */ + uint iic_rxtmp; /* Internal */ + uint iic_tstate; /* Internal */ + uint iic_tdp; /* Internal */ + ushort iic_tbptr; /* Internal */ + ushort iic_tbc; /* Internal */ + uint iic_txtmp; /* Internal */ + char res1[4]; /* Reserved */ + ushort iic_rpbase; /* Relocation pointer */ + char res2[2]; /* Reserved */ +} iic_t; + +#define BD_IIC_START ((ushort)0x0400) + +/* SPI parameter RAM. +*/ +typedef struct spi { + ushort spi_rbase; /* Rx Buffer descriptor base address */ + ushort spi_tbase; /* Tx Buffer descriptor base address */ + u_char spi_rfcr; /* Rx function code */ + u_char spi_tfcr; /* Tx function code */ + ushort spi_mrblr; /* Max receive buffer length */ + uint spi_rstate; /* Internal */ + uint spi_rdp; /* Internal */ + ushort spi_rbptr; /* Internal */ + ushort spi_rbc; /* Internal */ + uint spi_rxtmp; /* Internal */ + uint spi_tstate; /* Internal */ + uint spi_tdp; /* Internal */ + ushort spi_tbptr; /* Internal */ + ushort spi_tbc; /* Internal */ + uint spi_txtmp; /* Internal */ + uint spi_res; + ushort spi_rpbase; /* Relocation pointer */ + ushort spi_res2; +} spi_t; + +/* SPI Mode register. +*/ +#define SPMODE_LOOP ((ushort)0x4000) /* Loopback */ +#define SPMODE_CI ((ushort)0x2000) /* Clock Invert */ +#define SPMODE_CP ((ushort)0x1000) /* Clock Phase */ +#define SPMODE_DIV16 ((ushort)0x0800) /* BRG/16 mode */ +#define SPMODE_REV ((ushort)0x0400) /* Reversed Data */ +#define SPMODE_MSTR ((ushort)0x0200) /* SPI Master */ +#define SPMODE_EN ((ushort)0x0100) /* Enable */ +#define SPMODE_LENMSK ((ushort)0x00f0) /* character length */ +#define SPMODE_LEN4 ((ushort)0x0030) /* 4 bits per char */ +#define SPMODE_LEN8 ((ushort)0x0070) /* 8 bits per char */ +#define SPMODE_LEN16 ((ushort)0x00f0) /* 16 bits per char */ +#define SPMODE_PMMSK ((ushort)0x000f) /* prescale modulus */ + +/* SPIE fields */ +#define SPIE_MME 0x20 +#define SPIE_TXE 0x10 +#define SPIE_BSY 0x04 +#define SPIE_TXB 0x02 +#define SPIE_RXB 0x01 + +/* + * RISC Controller Configuration Register definitons + */ +#define RCCR_TIME 0x8000 /* RISC Timer Enable */ +#define RCCR_TIMEP(t) (((t) & 0x3F)<<8) /* RISC Timer Period */ +#define RCCR_TIME_MASK 0x00FF /* not RISC Timer related bits */ + +/* RISC Timer Parameter RAM offset */ +#define PROFF_RTMR ((uint)0x01B0) + +typedef struct risc_timer_pram { + unsigned short tm_base; /* RISC Timer Table Base Address */ + unsigned short tm_ptr; /* RISC Timer Table Pointer (internal) */ + unsigned short r_tmr; /* RISC Timer Mode Register */ + unsigned short r_tmv; /* RISC Timer Valid Register */ + unsigned long tm_cmd; /* RISC Timer Command Register */ + unsigned long tm_cnt; /* RISC Timer Internal Count */ +} rt_pram_t; + +/* Bits in RISC Timer Command Register */ +#define TM_CMD_VALID 0x80000000 /* Valid - Enables the timer */ +#define TM_CMD_RESTART 0x40000000 /* Restart - for automatic restart */ +#define TM_CMD_PWM 0x20000000 /* Run in Pulse Width Modulation Mode */ +#define TM_CMD_NUM(n) (((n)&0xF)<<16) /* Timer Number */ +#define TM_CMD_PERIOD(p) ((p)&0xFFFF) /* Timer Period */ + +/* CPM interrupts. There are nearly 32 interrupts generated by CPM + * channels or devices. All of these are presented to the PPC core + * as a single interrupt. The CPM interrupt handler dispatches its + * own handlers, in a similar fashion to the PPC core handler. We + * use the table as defined in the manuals (i.e. no special high + * priority and SCC1 == SCCa, etc...). + */ +#define CPMVEC_NR 32 +#define CPMVEC_PIO_PC15 ((ushort)0x1f) +#define CPMVEC_SCC1 ((ushort)0x1e) +#define CPMVEC_SCC2 ((ushort)0x1d) +#define CPMVEC_SCC3 ((ushort)0x1c) +#define CPMVEC_SCC4 ((ushort)0x1b) +#define CPMVEC_PIO_PC14 ((ushort)0x1a) +#define CPMVEC_TIMER1 ((ushort)0x19) +#define CPMVEC_PIO_PC13 ((ushort)0x18) +#define CPMVEC_PIO_PC12 ((ushort)0x17) +#define CPMVEC_SDMA_CB_ERR ((ushort)0x16) +#define CPMVEC_IDMA1 ((ushort)0x15) +#define CPMVEC_IDMA2 ((ushort)0x14) +#define CPMVEC_TIMER2 ((ushort)0x12) +#define CPMVEC_RISCTIMER ((ushort)0x11) +#define CPMVEC_I2C ((ushort)0x10) +#define CPMVEC_PIO_PC11 ((ushort)0x0f) +#define CPMVEC_PIO_PC10 ((ushort)0x0e) +#define CPMVEC_TIMER3 ((ushort)0x0c) +#define CPMVEC_PIO_PC9 ((ushort)0x0b) +#define CPMVEC_PIO_PC8 ((ushort)0x0a) +#define CPMVEC_PIO_PC7 ((ushort)0x09) +#define CPMVEC_TIMER4 ((ushort)0x07) +#define CPMVEC_PIO_PC6 ((ushort)0x06) +#define CPMVEC_SPI ((ushort)0x05) +#define CPMVEC_SMC1 ((ushort)0x04) +#define CPMVEC_SMC2 ((ushort)0x03) +#define CPMVEC_PIO_PC5 ((ushort)0x02) +#define CPMVEC_PIO_PC4 ((ushort)0x01) +#define CPMVEC_ERROR ((ushort)0x00) + +/* CPM interrupt configuration vector. +*/ +#define CICR_SCD_SCC4 ((uint)0x00c00000) /* SCC4 @ SCCd */ +#define CICR_SCC_SCC3 ((uint)0x00200000) /* SCC3 @ SCCc */ +#define CICR_SCB_SCC2 ((uint)0x00040000) /* SCC2 @ SCCb */ +#define CICR_SCA_SCC1 ((uint)0x00000000) /* SCC1 @ SCCa */ +#define CICR_IRL_MASK ((uint)0x0000e000) /* Core interrrupt */ +#define CICR_HP_MASK ((uint)0x00001f00) /* Hi-pri int. */ +#define CICR_IEN ((uint)0x00000080) /* Int. enable */ +#define CICR_SPS ((uint)0x00000001) /* SCC Spread */ + +extern void cpm_install_handler(int vec, void (*handler)(void *), void *dev_id); +extern void cpm_free_handler(int vec); + +#endif /* __CPM_8XX__ */ diff --git a/include/asm-powerpc/cpm2.h b/include/asm-powerpc/cpm2.h new file mode 100644 index 00000000000..12a2860f9a9 --- /dev/null +++ b/include/asm-powerpc/cpm2.h @@ -0,0 +1,1248 @@ +/* + * Communication Processor Module v2. + * + * This file contains structures and information for the communication + * processor channels found in the dual port RAM or parameter RAM. + * All CPM control and status is available through the CPM2 internal + * memory map. See immap_cpm2.h for details. + */ +#ifdef __KERNEL__ +#ifndef __CPM2__ +#define __CPM2__ + +#include + +/* CPM Command register. +*/ +#define CPM_CR_RST ((uint)0x80000000) +#define CPM_CR_PAGE ((uint)0x7c000000) +#define CPM_CR_SBLOCK ((uint)0x03e00000) +#define CPM_CR_FLG ((uint)0x00010000) +#define CPM_CR_MCN ((uint)0x00003fc0) +#define CPM_CR_OPCODE ((uint)0x0000000f) + +/* Device sub-block and page codes. +*/ +#define CPM_CR_SCC1_SBLOCK (0x04) +#define CPM_CR_SCC2_SBLOCK (0x05) +#define CPM_CR_SCC3_SBLOCK (0x06) +#define CPM_CR_SCC4_SBLOCK (0x07) +#define CPM_CR_SMC1_SBLOCK (0x08) +#define CPM_CR_SMC2_SBLOCK (0x09) +#define CPM_CR_SPI_SBLOCK (0x0a) +#define CPM_CR_I2C_SBLOCK (0x0b) +#define CPM_CR_TIMER_SBLOCK (0x0f) +#define CPM_CR_RAND_SBLOCK (0x0e) +#define CPM_CR_FCC1_SBLOCK (0x10) +#define CPM_CR_FCC2_SBLOCK (0x11) +#define CPM_CR_FCC3_SBLOCK (0x12) +#define CPM_CR_IDMA1_SBLOCK (0x14) +#define CPM_CR_IDMA2_SBLOCK (0x15) +#define CPM_CR_IDMA3_SBLOCK (0x16) +#define CPM_CR_IDMA4_SBLOCK (0x17) +#define CPM_CR_MCC1_SBLOCK (0x1c) + +#define CPM_CR_FCC_SBLOCK(x) (x + 0x10) + +#define CPM_CR_SCC1_PAGE (0x00) +#define CPM_CR_SCC2_PAGE (0x01) +#define CPM_CR_SCC3_PAGE (0x02) +#define CPM_CR_SCC4_PAGE (0x03) +#define CPM_CR_SMC1_PAGE (0x07) +#define CPM_CR_SMC2_PAGE (0x08) +#define CPM_CR_SPI_PAGE (0x09) +#define CPM_CR_I2C_PAGE (0x0a) +#define CPM_CR_TIMER_PAGE (0x0a) +#define CPM_CR_RAND_PAGE (0x0a) +#define CPM_CR_FCC1_PAGE (0x04) +#define CPM_CR_FCC2_PAGE (0x05) +#define CPM_CR_FCC3_PAGE (0x06) +#define CPM_CR_IDMA1_PAGE (0x07) +#define CPM_CR_IDMA2_PAGE (0x08) +#define CPM_CR_IDMA3_PAGE (0x09) +#define CPM_CR_IDMA4_PAGE (0x0a) +#define CPM_CR_MCC1_PAGE (0x07) +#define CPM_CR_MCC2_PAGE (0x08) + +#define CPM_CR_FCC_PAGE(x) (x + 0x04) + +/* Some opcodes (there are more...later) +*/ +#define CPM_CR_INIT_TRX ((ushort)0x0000) +#define CPM_CR_INIT_RX ((ushort)0x0001) +#define CPM_CR_INIT_TX ((ushort)0x0002) +#define CPM_CR_HUNT_MODE ((ushort)0x0003) +#define CPM_CR_STOP_TX ((ushort)0x0004) +#define CPM_CR_GRA_STOP_TX ((ushort)0x0005) +#define CPM_CR_RESTART_TX ((ushort)0x0006) +#define CPM_CR_SET_GADDR ((ushort)0x0008) +#define CPM_CR_START_IDMA ((ushort)0x0009) +#define CPM_CR_STOP_IDMA ((ushort)0x000b) + +#define mk_cr_cmd(PG, SBC, MCN, OP) \ + ((PG << 26) | (SBC << 21) | (MCN << 6) | OP) + +/* Dual Port RAM addresses. The first 16K is available for almost + * any CPM use, so we put the BDs there. The first 128 bytes are + * used for SMC1 and SMC2 parameter RAM, so we start allocating + * BDs above that. All of this must change when we start + * downloading RAM microcode. + */ +#define CPM_DATAONLY_BASE ((uint)128) +#define CPM_DP_NOSPACE ((uint)0x7fffffff) +#if defined(CONFIG_8272) || defined(CONFIG_MPC8555) +#define CPM_DATAONLY_SIZE ((uint)(8 * 1024) - CPM_DATAONLY_BASE) +#define CPM_FCC_SPECIAL_BASE ((uint)0x00009000) +#else +#define CPM_DATAONLY_SIZE ((uint)(16 * 1024) - CPM_DATAONLY_BASE) +#define CPM_FCC_SPECIAL_BASE ((uint)0x0000b000) +#endif + +/* The number of pages of host memory we allocate for CPM. This is + * done early in kernel initialization to get physically contiguous + * pages. + */ +#define NUM_CPM_HOST_PAGES 2 + +/* Export the base address of the communication processor registers + * and dual port ram. + */ +extern cpm_cpm2_t *cpmp; /* Pointer to comm processor */ + +extern unsigned long cpm_dpalloc(uint size, uint align); +extern int cpm_dpfree(unsigned long offset); +extern unsigned long cpm_dpalloc_fixed(unsigned long offset, uint size, uint align); +extern void cpm_dpdump(void); +extern void *cpm_dpram_addr(unsigned long offset); +extern void cpm_setbrg(uint brg, uint rate); +extern void cpm2_fastbrg(uint brg, uint rate, int div16); +extern void cpm2_reset(void); + + +/* Buffer descriptors used by many of the CPM protocols. +*/ +typedef struct cpm_buf_desc { + ushort cbd_sc; /* Status and Control */ + ushort cbd_datlen; /* Data length in buffer */ + uint cbd_bufaddr; /* Buffer address in host memory */ +} cbd_t; + +#define BD_SC_EMPTY ((ushort)0x8000) /* Receive is empty */ +#define BD_SC_READY ((ushort)0x8000) /* Transmit is ready */ +#define BD_SC_WRAP ((ushort)0x2000) /* Last buffer descriptor */ +#define BD_SC_INTRPT ((ushort)0x1000) /* Interrupt on change */ +#define BD_SC_LAST ((ushort)0x0800) /* Last buffer in frame */ +#define BD_SC_CM ((ushort)0x0200) /* Continous mode */ +#define BD_SC_ID ((ushort)0x0100) /* Rec'd too many idles */ +#define BD_SC_P ((ushort)0x0100) /* xmt preamble */ +#define BD_SC_BR ((ushort)0x0020) /* Break received */ +#define BD_SC_FR ((ushort)0x0010) /* Framing error */ +#define BD_SC_PR ((ushort)0x0008) /* Parity error */ +#define BD_SC_OV ((ushort)0x0002) /* Overrun */ +#define BD_SC_CD ((ushort)0x0001) /* ?? */ + +/* Function code bits, usually generic to devices. +*/ +#define CPMFCR_GBL ((u_char)0x20) /* Set memory snooping */ +#define CPMFCR_EB ((u_char)0x10) /* Set big endian byte order */ +#define CPMFCR_TC2 ((u_char)0x04) /* Transfer code 2 value */ +#define CPMFCR_DTB ((u_char)0x02) /* Use local bus for data when set */ +#define CPMFCR_BDB ((u_char)0x01) /* Use local bus for BD when set */ + +/* Parameter RAM offsets from the base. +*/ +#define PROFF_SCC1 ((uint)0x8000) +#define PROFF_SCC2 ((uint)0x8100) +#define PROFF_SCC3 ((uint)0x8200) +#define PROFF_SCC4 ((uint)0x8300) +#define PROFF_FCC1 ((uint)0x8400) +#define PROFF_FCC2 ((uint)0x8500) +#define PROFF_FCC3 ((uint)0x8600) +#define PROFF_MCC1 ((uint)0x8700) +#define PROFF_SMC1_BASE ((uint)0x87fc) +#define PROFF_IDMA1_BASE ((uint)0x87fe) +#define PROFF_MCC2 ((uint)0x8800) +#define PROFF_SMC2_BASE ((uint)0x88fc) +#define PROFF_IDMA2_BASE ((uint)0x88fe) +#define PROFF_SPI_BASE ((uint)0x89fc) +#define PROFF_IDMA3_BASE ((uint)0x89fe) +#define PROFF_TIMERS ((uint)0x8ae0) +#define PROFF_REVNUM ((uint)0x8af0) +#define PROFF_RAND ((uint)0x8af8) +#define PROFF_I2C_BASE ((uint)0x8afc) +#define PROFF_IDMA4_BASE ((uint)0x8afe) + +#define PROFF_SCC_SIZE ((uint)0x100) +#define PROFF_FCC_SIZE ((uint)0x100) +#define PROFF_SMC_SIZE ((uint)64) + +/* The SMCs are relocated to any of the first eight DPRAM pages. + * We will fix these at the first locations of DPRAM, until we + * get some microcode patches :-). + * The parameter ram space for the SMCs is fifty-some bytes, and + * they are required to start on a 64 byte boundary. + */ +#define PROFF_SMC1 (0) +#define PROFF_SMC2 (64) + + +/* Define enough so I can at least use the serial port as a UART. + */ +typedef struct smc_uart { + ushort smc_rbase; /* Rx Buffer descriptor base address */ + ushort smc_tbase; /* Tx Buffer descriptor base address */ + u_char smc_rfcr; /* Rx function code */ + u_char smc_tfcr; /* Tx function code */ + ushort smc_mrblr; /* Max receive buffer length */ + uint smc_rstate; /* Internal */ + uint smc_idp; /* Internal */ + ushort smc_rbptr; /* Internal */ + ushort smc_ibc; /* Internal */ + uint smc_rxtmp; /* Internal */ + uint smc_tstate; /* Internal */ + uint smc_tdp; /* Internal */ + ushort smc_tbptr; /* Internal */ + ushort smc_tbc; /* Internal */ + uint smc_txtmp; /* Internal */ + ushort smc_maxidl; /* Maximum idle characters */ + ushort smc_tmpidl; /* Temporary idle counter */ + ushort smc_brklen; /* Last received break length */ + ushort smc_brkec; /* rcv'd break condition counter */ + ushort smc_brkcr; /* xmt break count register */ + ushort smc_rmask; /* Temporary bit mask */ + uint smc_stmp; /* SDMA Temp */ +} smc_uart_t; + +/* SMC uart mode register (Internal memory map). +*/ +#define SMCMR_REN ((ushort)0x0001) +#define SMCMR_TEN ((ushort)0x0002) +#define SMCMR_DM ((ushort)0x000c) +#define SMCMR_SM_GCI ((ushort)0x0000) +#define SMCMR_SM_UART ((ushort)0x0020) +#define SMCMR_SM_TRANS ((ushort)0x0030) +#define SMCMR_SM_MASK ((ushort)0x0030) +#define SMCMR_PM_EVEN ((ushort)0x0100) /* Even parity, else odd */ +#define SMCMR_REVD SMCMR_PM_EVEN +#define SMCMR_PEN ((ushort)0x0200) /* Parity enable */ +#define SMCMR_BS SMCMR_PEN +#define SMCMR_SL ((ushort)0x0400) /* Two stops, else one */ +#define SMCR_CLEN_MASK ((ushort)0x7800) /* Character length */ +#define smcr_mk_clen(C) (((C) << 11) & SMCR_CLEN_MASK) + +/* SMC Event and Mask register. +*/ +#define SMCM_BRKE ((unsigned char)0x40) /* When in UART Mode */ +#define SMCM_BRK ((unsigned char)0x10) /* When in UART Mode */ +#define SMCM_TXE ((unsigned char)0x10) +#define SMCM_BSY ((unsigned char)0x04) +#define SMCM_TX ((unsigned char)0x02) +#define SMCM_RX ((unsigned char)0x01) + +/* Baud rate generators. +*/ +#define CPM_BRG_RST ((uint)0x00020000) +#define CPM_BRG_EN ((uint)0x00010000) +#define CPM_BRG_EXTC_INT ((uint)0x00000000) +#define CPM_BRG_EXTC_CLK3_9 ((uint)0x00004000) +#define CPM_BRG_EXTC_CLK5_15 ((uint)0x00008000) +#define CPM_BRG_ATB ((uint)0x00002000) +#define CPM_BRG_CD_MASK ((uint)0x00001ffe) +#define CPM_BRG_DIV16 ((uint)0x00000001) + +/* SCCs. +*/ +#define SCC_GSMRH_IRP ((uint)0x00040000) +#define SCC_GSMRH_GDE ((uint)0x00010000) +#define SCC_GSMRH_TCRC_CCITT ((uint)0x00008000) +#define SCC_GSMRH_TCRC_BISYNC ((uint)0x00004000) +#define SCC_GSMRH_TCRC_HDLC ((uint)0x00000000) +#define SCC_GSMRH_REVD ((uint)0x00002000) +#define SCC_GSMRH_TRX ((uint)0x00001000) +#define SCC_GSMRH_TTX ((uint)0x00000800) +#define SCC_GSMRH_CDP ((uint)0x00000400) +#define SCC_GSMRH_CTSP ((uint)0x00000200) +#define SCC_GSMRH_CDS ((uint)0x00000100) +#define SCC_GSMRH_CTSS ((uint)0x00000080) +#define SCC_GSMRH_TFL ((uint)0x00000040) +#define SCC_GSMRH_RFW ((uint)0x00000020) +#define SCC_GSMRH_TXSY ((uint)0x00000010) +#define SCC_GSMRH_SYNL16 ((uint)0x0000000c) +#define SCC_GSMRH_SYNL8 ((uint)0x00000008) +#define SCC_GSMRH_SYNL4 ((uint)0x00000004) +#define SCC_GSMRH_RTSM ((uint)0x00000002) +#define SCC_GSMRH_RSYN ((uint)0x00000001) + +#define SCC_GSMRL_SIR ((uint)0x80000000) /* SCC2 only */ +#define SCC_GSMRL_EDGE_NONE ((uint)0x60000000) +#define SCC_GSMRL_EDGE_NEG ((uint)0x40000000) +#define SCC_GSMRL_EDGE_POS ((uint)0x20000000) +#define SCC_GSMRL_EDGE_BOTH ((uint)0x00000000) +#define SCC_GSMRL_TCI ((uint)0x10000000) +#define SCC_GSMRL_TSNC_3 ((uint)0x0c000000) +#define SCC_GSMRL_TSNC_4 ((uint)0x08000000) +#define SCC_GSMRL_TSNC_14 ((uint)0x04000000) +#define SCC_GSMRL_TSNC_INF ((uint)0x00000000) +#define SCC_GSMRL_RINV ((uint)0x02000000) +#define SCC_GSMRL_TINV ((uint)0x01000000) +#define SCC_GSMRL_TPL_128 ((uint)0x00c00000) +#define SCC_GSMRL_TPL_64 ((uint)0x00a00000) +#define SCC_GSMRL_TPL_48 ((uint)0x00800000) +#define SCC_GSMRL_TPL_32 ((uint)0x00600000) +#define SCC_GSMRL_TPL_16 ((uint)0x00400000) +#define SCC_GSMRL_TPL_8 ((uint)0x00200000) +#define SCC_GSMRL_TPL_NONE ((uint)0x00000000) +#define SCC_GSMRL_TPP_ALL1 ((uint)0x00180000) +#define SCC_GSMRL_TPP_01 ((uint)0x00100000) +#define SCC_GSMRL_TPP_10 ((uint)0x00080000) +#define SCC_GSMRL_TPP_ZEROS ((uint)0x00000000) +#define SCC_GSMRL_TEND ((uint)0x00040000) +#define SCC_GSMRL_TDCR_32 ((uint)0x00030000) +#define SCC_GSMRL_TDCR_16 ((uint)0x00020000) +#define SCC_GSMRL_TDCR_8 ((uint)0x00010000) +#define SCC_GSMRL_TDCR_1 ((uint)0x00000000) +#define SCC_GSMRL_RDCR_32 ((uint)0x0000c000) +#define SCC_GSMRL_RDCR_16 ((uint)0x00008000) +#define SCC_GSMRL_RDCR_8 ((uint)0x00004000) +#define SCC_GSMRL_RDCR_1 ((uint)0x00000000) +#define SCC_GSMRL_RENC_DFMAN ((uint)0x00003000) +#define SCC_GSMRL_RENC_MANCH ((uint)0x00002000) +#define SCC_GSMRL_RENC_FM0 ((uint)0x00001000) +#define SCC_GSMRL_RENC_NRZI ((uint)0x00000800) +#define SCC_GSMRL_RENC_NRZ ((uint)0x00000000) +#define SCC_GSMRL_TENC_DFMAN ((uint)0x00000600) +#define SCC_GSMRL_TENC_MANCH ((uint)0x00000400) +#define SCC_GSMRL_TENC_FM0 ((uint)0x00000200) +#define SCC_GSMRL_TENC_NRZI ((uint)0x00000100) +#define SCC_GSMRL_TENC_NRZ ((uint)0x00000000) +#define SCC_GSMRL_DIAG_LE ((uint)0x000000c0) /* Loop and echo */ +#define SCC_GSMRL_DIAG_ECHO ((uint)0x00000080) +#define SCC_GSMRL_DIAG_LOOP ((uint)0x00000040) +#define SCC_GSMRL_DIAG_NORM ((uint)0x00000000) +#define SCC_GSMRL_ENR ((uint)0x00000020) +#define SCC_GSMRL_ENT ((uint)0x00000010) +#define SCC_GSMRL_MODE_ENET ((uint)0x0000000c) +#define SCC_GSMRL_MODE_DDCMP ((uint)0x00000009) +#define SCC_GSMRL_MODE_BISYNC ((uint)0x00000008) +#define SCC_GSMRL_MODE_V14 ((uint)0x00000007) +#define SCC_GSMRL_MODE_AHDLC ((uint)0x00000006) +#define SCC_GSMRL_MODE_PROFIBUS ((uint)0x00000005) +#define SCC_GSMRL_MODE_UART ((uint)0x00000004) +#define SCC_GSMRL_MODE_SS7 ((uint)0x00000003) +#define SCC_GSMRL_MODE_ATALK ((uint)0x00000002) +#define SCC_GSMRL_MODE_HDLC ((uint)0x00000000) + +#define SCC_TODR_TOD ((ushort)0x8000) + +/* SCC Event and Mask register. +*/ +#define SCCM_TXE ((unsigned char)0x10) +#define SCCM_BSY ((unsigned char)0x04) +#define SCCM_TX ((unsigned char)0x02) +#define SCCM_RX ((unsigned char)0x01) + +typedef struct scc_param { + ushort scc_rbase; /* Rx Buffer descriptor base address */ + ushort scc_tbase; /* Tx Buffer descriptor base address */ + u_char scc_rfcr; /* Rx function code */ + u_char scc_tfcr; /* Tx function code */ + ushort scc_mrblr; /* Max receive buffer length */ + uint scc_rstate; /* Internal */ + uint scc_idp; /* Internal */ + ushort scc_rbptr; /* Internal */ + ushort scc_ibc; /* Internal */ + uint scc_rxtmp; /* Internal */ + uint scc_tstate; /* Internal */ + uint scc_tdp; /* Internal */ + ushort scc_tbptr; /* Internal */ + ushort scc_tbc; /* Internal */ + uint scc_txtmp; /* Internal */ + uint scc_rcrc; /* Internal */ + uint scc_tcrc; /* Internal */ +} sccp_t; + +/* CPM Ethernet through SCC1. + */ +typedef struct scc_enet { + sccp_t sen_genscc; + uint sen_cpres; /* Preset CRC */ + uint sen_cmask; /* Constant mask for CRC */ + uint sen_crcec; /* CRC Error counter */ + uint sen_alec; /* alignment error counter */ + uint sen_disfc; /* discard frame counter */ + ushort sen_pads; /* Tx short frame pad character */ + ushort sen_retlim; /* Retry limit threshold */ + ushort sen_retcnt; /* Retry limit counter */ + ushort sen_maxflr; /* maximum frame length register */ + ushort sen_minflr; /* minimum frame length register */ + ushort sen_maxd1; /* maximum DMA1 length */ + ushort sen_maxd2; /* maximum DMA2 length */ + ushort sen_maxd; /* Rx max DMA */ + ushort sen_dmacnt; /* Rx DMA counter */ + ushort sen_maxb; /* Max BD byte count */ + ushort sen_gaddr1; /* Group address filter */ + ushort sen_gaddr2; + ushort sen_gaddr3; + ushort sen_gaddr4; + uint sen_tbuf0data0; /* Save area 0 - current frame */ + uint sen_tbuf0data1; /* Save area 1 - current frame */ + uint sen_tbuf0rba; /* Internal */ + uint sen_tbuf0crc; /* Internal */ + ushort sen_tbuf0bcnt; /* Internal */ + ushort sen_paddrh; /* physical address (MSB) */ + ushort sen_paddrm; + ushort sen_paddrl; /* physical address (LSB) */ + ushort sen_pper; /* persistence */ + ushort sen_rfbdptr; /* Rx first BD pointer */ + ushort sen_tfbdptr; /* Tx first BD pointer */ + ushort sen_tlbdptr; /* Tx last BD pointer */ + uint sen_tbuf1data0; /* Save area 0 - current frame */ + uint sen_tbuf1data1; /* Save area 1 - current frame */ + uint sen_tbuf1rba; /* Internal */ + uint sen_tbuf1crc; /* Internal */ + ushort sen_tbuf1bcnt; /* Internal */ + ushort sen_txlen; /* Tx Frame length counter */ + ushort sen_iaddr1; /* Individual address filter */ + ushort sen_iaddr2; + ushort sen_iaddr3; + ushort sen_iaddr4; + ushort sen_boffcnt; /* Backoff counter */ + + /* NOTE: Some versions of the manual have the following items + * incorrectly documented. Below is the proper order. + */ + ushort sen_taddrh; /* temp address (MSB) */ + ushort sen_taddrm; + ushort sen_taddrl; /* temp address (LSB) */ +} scc_enet_t; + + +/* SCC Event register as used by Ethernet. +*/ +#define SCCE_ENET_GRA ((ushort)0x0080) /* Graceful stop complete */ +#define SCCE_ENET_TXE ((ushort)0x0010) /* Transmit Error */ +#define SCCE_ENET_RXF ((ushort)0x0008) /* Full frame received */ +#define SCCE_ENET_BSY ((ushort)0x0004) /* All incoming buffers full */ +#define SCCE_ENET_TXB ((ushort)0x0002) /* A buffer was transmitted */ +#define SCCE_ENET_RXB ((ushort)0x0001) /* A buffer was received */ + +/* SCC Mode Register (PSMR) as used by Ethernet. +*/ +#define SCC_PSMR_HBC ((ushort)0x8000) /* Enable heartbeat */ +#define SCC_PSMR_FC ((ushort)0x4000) /* Force collision */ +#define SCC_PSMR_RSH ((ushort)0x2000) /* Receive short frames */ +#define SCC_PSMR_IAM ((ushort)0x1000) /* Check individual hash */ +#define SCC_PSMR_ENCRC ((ushort)0x0800) /* Ethernet CRC mode */ +#define SCC_PSMR_PRO ((ushort)0x0200) /* Promiscuous mode */ +#define SCC_PSMR_BRO ((ushort)0x0100) /* Catch broadcast pkts */ +#define SCC_PSMR_SBT ((ushort)0x0080) /* Special backoff timer */ +#define SCC_PSMR_LPB ((ushort)0x0040) /* Set Loopback mode */ +#define SCC_PSMR_SIP ((ushort)0x0020) /* Sample Input Pins */ +#define SCC_PSMR_LCW ((ushort)0x0010) /* Late collision window */ +#define SCC_PSMR_NIB22 ((ushort)0x000a) /* Start frame search */ +#define SCC_PSMR_FDE ((ushort)0x0001) /* Full duplex enable */ + +/* Buffer descriptor control/status used by Ethernet receive. + * Common to SCC and FCC. + */ +#define BD_ENET_RX_EMPTY ((ushort)0x8000) +#define BD_ENET_RX_WRAP ((ushort)0x2000) +#define BD_ENET_RX_INTR ((ushort)0x1000) +#define BD_ENET_RX_LAST ((ushort)0x0800) +#define BD_ENET_RX_FIRST ((ushort)0x0400) +#define BD_ENET_RX_MISS ((ushort)0x0100) +#define BD_ENET_RX_BC ((ushort)0x0080) /* FCC Only */ +#define BD_ENET_RX_MC ((ushort)0x0040) /* FCC Only */ +#define BD_ENET_RX_LG ((ushort)0x0020) +#define BD_ENET_RX_NO ((ushort)0x0010) +#define BD_ENET_RX_SH ((ushort)0x0008) +#define BD_ENET_RX_CR ((ushort)0x0004) +#define BD_ENET_RX_OV ((ushort)0x0002) +#define BD_ENET_RX_CL ((ushort)0x0001) +#define BD_ENET_RX_STATS ((ushort)0x01ff) /* All status bits */ + +/* Buffer descriptor control/status used by Ethernet transmit. + * Common to SCC and FCC. + */ +#define BD_ENET_TX_READY ((ushort)0x8000) +#define BD_ENET_TX_PAD ((ushort)0x4000) +#define BD_ENET_TX_WRAP ((ushort)0x2000) +#define BD_ENET_TX_INTR ((ushort)0x1000) +#define BD_ENET_TX_LAST ((ushort)0x0800) +#define BD_ENET_TX_TC ((ushort)0x0400) +#define BD_ENET_TX_DEF ((ushort)0x0200) +#define BD_ENET_TX_HB ((ushort)0x0100) +#define BD_ENET_TX_LC ((ushort)0x0080) +#define BD_ENET_TX_RL ((ushort)0x0040) +#define BD_ENET_TX_RCMASK ((ushort)0x003c) +#define BD_ENET_TX_UN ((ushort)0x0002) +#define BD_ENET_TX_CSL ((ushort)0x0001) +#define BD_ENET_TX_STATS ((ushort)0x03ff) /* All status bits */ + +/* SCC as UART +*/ +typedef struct scc_uart { + sccp_t scc_genscc; + uint scc_res1; /* Reserved */ + uint scc_res2; /* Reserved */ + ushort scc_maxidl; /* Maximum idle chars */ + ushort scc_idlc; /* temp idle counter */ + ushort scc_brkcr; /* Break count register */ + ushort scc_parec; /* receive parity error counter */ + ushort scc_frmec; /* receive framing error counter */ + ushort scc_nosec; /* receive noise counter */ + ushort scc_brkec; /* receive break condition counter */ + ushort scc_brkln; /* last received break length */ + ushort scc_uaddr1; /* UART address character 1 */ + ushort scc_uaddr2; /* UART address character 2 */ + ushort scc_rtemp; /* Temp storage */ + ushort scc_toseq; /* Transmit out of sequence char */ + ushort scc_char1; /* control character 1 */ + ushort scc_char2; /* control character 2 */ + ushort scc_char3; /* control character 3 */ + ushort scc_char4; /* control character 4 */ + ushort scc_char5; /* control character 5 */ + ushort scc_char6; /* control character 6 */ + ushort scc_char7; /* control character 7 */ + ushort scc_char8; /* control character 8 */ + ushort scc_rccm; /* receive control character mask */ + ushort scc_rccr; /* receive control character register */ + ushort scc_rlbc; /* receive last break character */ +} scc_uart_t; + +/* SCC Event and Mask registers when it is used as a UART. +*/ +#define UART_SCCM_GLR ((ushort)0x1000) +#define UART_SCCM_GLT ((ushort)0x0800) +#define UART_SCCM_AB ((ushort)0x0200) +#define UART_SCCM_IDL ((ushort)0x0100) +#define UART_SCCM_GRA ((ushort)0x0080) +#define UART_SCCM_BRKE ((ushort)0x0040) +#define UART_SCCM_BRKS ((ushort)0x0020) +#define UART_SCCM_CCR ((ushort)0x0008) +#define UART_SCCM_BSY ((ushort)0x0004) +#define UART_SCCM_TX ((ushort)0x0002) +#define UART_SCCM_RX ((ushort)0x0001) + +/* The SCC PSMR when used as a UART. +*/ +#define SCU_PSMR_FLC ((ushort)0x8000) +#define SCU_PSMR_SL ((ushort)0x4000) +#define SCU_PSMR_CL ((ushort)0x3000) +#define SCU_PSMR_UM ((ushort)0x0c00) +#define SCU_PSMR_FRZ ((ushort)0x0200) +#define SCU_PSMR_RZS ((ushort)0x0100) +#define SCU_PSMR_SYN ((ushort)0x0080) +#define SCU_PSMR_DRT ((ushort)0x0040) +#define SCU_PSMR_PEN ((ushort)0x0010) +#define SCU_PSMR_RPM ((ushort)0x000c) +#define SCU_PSMR_REVP ((ushort)0x0008) +#define SCU_PSMR_TPM ((ushort)0x0003) +#define SCU_PSMR_TEVP ((ushort)0x0002) + +/* CPM Transparent mode SCC. + */ +typedef struct scc_trans { + sccp_t st_genscc; + uint st_cpres; /* Preset CRC */ + uint st_cmask; /* Constant mask for CRC */ +} scc_trans_t; + +#define BD_SCC_TX_LAST ((ushort)0x0800) + +/* How about some FCCs..... +*/ +#define FCC_GFMR_DIAG_NORM ((uint)0x00000000) +#define FCC_GFMR_DIAG_LE ((uint)0x40000000) +#define FCC_GFMR_DIAG_AE ((uint)0x80000000) +#define FCC_GFMR_DIAG_ALE ((uint)0xc0000000) +#define FCC_GFMR_TCI ((uint)0x20000000) +#define FCC_GFMR_TRX ((uint)0x10000000) +#define FCC_GFMR_TTX ((uint)0x08000000) +#define FCC_GFMR_TTX ((uint)0x08000000) +#define FCC_GFMR_CDP ((uint)0x04000000) +#define FCC_GFMR_CTSP ((uint)0x02000000) +#define FCC_GFMR_CDS ((uint)0x01000000) +#define FCC_GFMR_CTSS ((uint)0x00800000) +#define FCC_GFMR_SYNL_NONE ((uint)0x00000000) +#define FCC_GFMR_SYNL_AUTO ((uint)0x00004000) +#define FCC_GFMR_SYNL_8 ((uint)0x00008000) +#define FCC_GFMR_SYNL_16 ((uint)0x0000c000) +#define FCC_GFMR_RTSM ((uint)0x00002000) +#define FCC_GFMR_RENC_NRZ ((uint)0x00000000) +#define FCC_GFMR_RENC_NRZI ((uint)0x00000800) +#define FCC_GFMR_REVD ((uint)0x00000400) +#define FCC_GFMR_TENC_NRZ ((uint)0x00000000) +#define FCC_GFMR_TENC_NRZI ((uint)0x00000100) +#define FCC_GFMR_TCRC_16 ((uint)0x00000000) +#define FCC_GFMR_TCRC_32 ((uint)0x00000080) +#define FCC_GFMR_ENR ((uint)0x00000020) +#define FCC_GFMR_ENT ((uint)0x00000010) +#define FCC_GFMR_MODE_ENET ((uint)0x0000000c) +#define FCC_GFMR_MODE_ATM ((uint)0x0000000a) +#define FCC_GFMR_MODE_HDLC ((uint)0x00000000) + +/* Generic FCC parameter ram. +*/ +typedef struct fcc_param { + ushort fcc_riptr; /* Rx Internal temp pointer */ + ushort fcc_tiptr; /* Tx Internal temp pointer */ + ushort fcc_res1; + ushort fcc_mrblr; /* Max receive buffer length, mod 32 bytes */ + uint fcc_rstate; /* Upper byte is Func code, must be set */ + uint fcc_rbase; /* Receive BD base */ + ushort fcc_rbdstat; /* RxBD status */ + ushort fcc_rbdlen; /* RxBD down counter */ + uint fcc_rdptr; /* RxBD internal data pointer */ + uint fcc_tstate; /* Upper byte is Func code, must be set */ + uint fcc_tbase; /* Transmit BD base */ + ushort fcc_tbdstat; /* TxBD status */ + ushort fcc_tbdlen; /* TxBD down counter */ + uint fcc_tdptr; /* TxBD internal data pointer */ + uint fcc_rbptr; /* Rx BD Internal buf pointer */ + uint fcc_tbptr; /* Tx BD Internal buf pointer */ + uint fcc_rcrc; /* Rx temp CRC */ + uint fcc_res2; + uint fcc_tcrc; /* Tx temp CRC */ +} fccp_t; + + +/* Ethernet controller through FCC. +*/ +typedef struct fcc_enet { + fccp_t fen_genfcc; + uint fen_statbuf; /* Internal status buffer */ + uint fen_camptr; /* CAM address */ + uint fen_cmask; /* Constant mask for CRC */ + uint fen_cpres; /* Preset CRC */ + uint fen_crcec; /* CRC Error counter */ + uint fen_alec; /* alignment error counter */ + uint fen_disfc; /* discard frame counter */ + ushort fen_retlim; /* Retry limit */ + ushort fen_retcnt; /* Retry counter */ + ushort fen_pper; /* Persistence */ + ushort fen_boffcnt; /* backoff counter */ + uint fen_gaddrh; /* Group address filter, high 32-bits */ + uint fen_gaddrl; /* Group address filter, low 32-bits */ + ushort fen_tfcstat; /* out of sequence TxBD */ + ushort fen_tfclen; + uint fen_tfcptr; + ushort fen_mflr; /* Maximum frame length (1518) */ + ushort fen_paddrh; /* MAC address */ + ushort fen_paddrm; + ushort fen_paddrl; + ushort fen_ibdcount; /* Internal BD counter */ + ushort fen_ibdstart; /* Internal BD start pointer */ + ushort fen_ibdend; /* Internal BD end pointer */ + ushort fen_txlen; /* Internal Tx frame length counter */ + uint fen_ibdbase[8]; /* Internal use */ + uint fen_iaddrh; /* Individual address filter */ + uint fen_iaddrl; + ushort fen_minflr; /* Minimum frame length (64) */ + ushort fen_taddrh; /* Filter transfer MAC address */ + ushort fen_taddrm; + ushort fen_taddrl; + ushort fen_padptr; /* Pointer to pad byte buffer */ + ushort fen_cftype; /* control frame type */ + ushort fen_cfrange; /* control frame range */ + ushort fen_maxb; /* maximum BD count */ + ushort fen_maxd1; /* Max DMA1 length (1520) */ + ushort fen_maxd2; /* Max DMA2 length (1520) */ + ushort fen_maxd; /* internal max DMA count */ + ushort fen_dmacnt; /* internal DMA counter */ + uint fen_octc; /* Total octect counter */ + uint fen_colc; /* Total collision counter */ + uint fen_broc; /* Total broadcast packet counter */ + uint fen_mulc; /* Total multicast packet count */ + uint fen_uspc; /* Total packets < 64 bytes */ + uint fen_frgc; /* Total packets < 64 bytes with errors */ + uint fen_ospc; /* Total packets > 1518 */ + uint fen_jbrc; /* Total packets > 1518 with errors */ + uint fen_p64c; /* Total packets == 64 bytes */ + uint fen_p65c; /* Total packets 64 < bytes <= 127 */ + uint fen_p128c; /* Total packets 127 < bytes <= 255 */ + uint fen_p256c; /* Total packets 256 < bytes <= 511 */ + uint fen_p512c; /* Total packets 512 < bytes <= 1023 */ + uint fen_p1024c; /* Total packets 1024 < bytes <= 1518 */ + uint fen_cambuf; /* Internal CAM buffer poiner */ + ushort fen_rfthr; /* Received frames threshold */ + ushort fen_rfcnt; /* Received frames count */ +} fcc_enet_t; + +/* FCC Event/Mask register as used by Ethernet. +*/ +#define FCC_ENET_GRA ((ushort)0x0080) /* Graceful stop complete */ +#define FCC_ENET_RXC ((ushort)0x0040) /* Control Frame Received */ +#define FCC_ENET_TXC ((ushort)0x0020) /* Out of seq. Tx sent */ +#define FCC_ENET_TXE ((ushort)0x0010) /* Transmit Error */ +#define FCC_ENET_RXF ((ushort)0x0008) /* Full frame received */ +#define FCC_ENET_BSY ((ushort)0x0004) /* Busy. Rx Frame dropped */ +#define FCC_ENET_TXB ((ushort)0x0002) /* A buffer was transmitted */ +#define FCC_ENET_RXB ((ushort)0x0001) /* A buffer was received */ + +/* FCC Mode Register (FPSMR) as used by Ethernet. +*/ +#define FCC_PSMR_HBC ((uint)0x80000000) /* Enable heartbeat */ +#define FCC_PSMR_FC ((uint)0x40000000) /* Force Collision */ +#define FCC_PSMR_SBT ((uint)0x20000000) /* Stop backoff timer */ +#define FCC_PSMR_LPB ((uint)0x10000000) /* Local protect. 1 = FDX */ +#define FCC_PSMR_LCW ((uint)0x08000000) /* Late collision select */ +#define FCC_PSMR_FDE ((uint)0x04000000) /* Full Duplex Enable */ +#define FCC_PSMR_MON ((uint)0x02000000) /* RMON Enable */ +#define FCC_PSMR_PRO ((uint)0x00400000) /* Promiscuous Enable */ +#define FCC_PSMR_FCE ((uint)0x00200000) /* Flow Control Enable */ +#define FCC_PSMR_RSH ((uint)0x00100000) /* Receive Short Frames */ +#define FCC_PSMR_CAM ((uint)0x00000400) /* CAM enable */ +#define FCC_PSMR_BRO ((uint)0x00000200) /* Broadcast pkt discard */ +#define FCC_PSMR_ENCRC ((uint)0x00000080) /* Use 32-bit CRC */ + +/* IIC parameter RAM. +*/ +typedef struct iic { + ushort iic_rbase; /* Rx Buffer descriptor base address */ + ushort iic_tbase; /* Tx Buffer descriptor base address */ + u_char iic_rfcr; /* Rx function code */ + u_char iic_tfcr; /* Tx function code */ + ushort iic_mrblr; /* Max receive buffer length */ + uint iic_rstate; /* Internal */ + uint iic_rdp; /* Internal */ + ushort iic_rbptr; /* Internal */ + ushort iic_rbc; /* Internal */ + uint iic_rxtmp; /* Internal */ + uint iic_tstate; /* Internal */ + uint iic_tdp; /* Internal */ + ushort iic_tbptr; /* Internal */ + ushort iic_tbc; /* Internal */ + uint iic_txtmp; /* Internal */ +} iic_t; + +/* SPI parameter RAM. +*/ +typedef struct spi { + ushort spi_rbase; /* Rx Buffer descriptor base address */ + ushort spi_tbase; /* Tx Buffer descriptor base address */ + u_char spi_rfcr; /* Rx function code */ + u_char spi_tfcr; /* Tx function code */ + ushort spi_mrblr; /* Max receive buffer length */ + uint spi_rstate; /* Internal */ + uint spi_rdp; /* Internal */ + ushort spi_rbptr; /* Internal */ + ushort spi_rbc; /* Internal */ + uint spi_rxtmp; /* Internal */ + uint spi_tstate; /* Internal */ + uint spi_tdp; /* Internal */ + ushort spi_tbptr; /* Internal */ + ushort spi_tbc; /* Internal */ + uint spi_txtmp; /* Internal */ + uint spi_res; /* Tx temp. */ + uint spi_res1[4]; /* SDMA temp. */ +} spi_t; + +/* SPI Mode register. +*/ +#define SPMODE_LOOP ((ushort)0x4000) /* Loopback */ +#define SPMODE_CI ((ushort)0x2000) /* Clock Invert */ +#define SPMODE_CP ((ushort)0x1000) /* Clock Phase */ +#define SPMODE_DIV16 ((ushort)0x0800) /* BRG/16 mode */ +#define SPMODE_REV ((ushort)0x0400) /* Reversed Data */ +#define SPMODE_MSTR ((ushort)0x0200) /* SPI Master */ +#define SPMODE_EN ((ushort)0x0100) /* Enable */ +#define SPMODE_LENMSK ((ushort)0x00f0) /* character length */ +#define SPMODE_PMMSK ((ushort)0x000f) /* prescale modulus */ + +#define SPMODE_LEN(x) ((((x)-1)&0xF)<<4) +#define SPMODE_PM(x) ((x) &0xF) + +#define SPI_EB ((u_char)0x10) /* big endian byte order */ + +#define BD_IIC_START ((ushort)0x0400) + +/* IDMA parameter RAM +*/ +typedef struct idma { + ushort ibase; /* IDMA buffer descriptor table base address */ + ushort dcm; /* DMA channel mode */ + ushort ibdptr; /* IDMA current buffer descriptor pointer */ + ushort dpr_buf; /* IDMA transfer buffer base address */ + ushort buf_inv; /* internal buffer inventory */ + ushort ss_max; /* steady-state maximum transfer size */ + ushort dpr_in_ptr; /* write pointer inside the internal buffer */ + ushort sts; /* source transfer size */ + ushort dpr_out_ptr; /* read pointer inside the internal buffer */ + ushort seob; /* source end of burst */ + ushort deob; /* destination end of burst */ + ushort dts; /* destination transfer size */ + ushort ret_add; /* return address when working in ERM=1 mode */ + ushort res0; /* reserved */ + uint bd_cnt; /* internal byte count */ + uint s_ptr; /* source internal data pointer */ + uint d_ptr; /* destination internal data pointer */ + uint istate; /* internal state */ + u_char res1[20]; /* pad to 64-byte length */ +} idma_t; + +/* DMA channel mode bit fields +*/ +#define IDMA_DCM_FB ((ushort)0x8000) /* fly-by mode */ +#define IDMA_DCM_LP ((ushort)0x4000) /* low priority */ +#define IDMA_DCM_TC2 ((ushort)0x0400) /* value driven on TC[2] */ +#define IDMA_DCM_DMA_WRAP_MASK ((ushort)0x01c0) /* mask for DMA wrap */ +#define IDMA_DCM_DMA_WRAP_64 ((ushort)0x0000) /* 64-byte DMA xfer buffer */ +#define IDMA_DCM_DMA_WRAP_128 ((ushort)0x0040) /* 128-byte DMA xfer buffer */ +#define IDMA_DCM_DMA_WRAP_256 ((ushort)0x0080) /* 256-byte DMA xfer buffer */ +#define IDMA_DCM_DMA_WRAP_512 ((ushort)0x00c0) /* 512-byte DMA xfer buffer */ +#define IDMA_DCM_DMA_WRAP_1024 ((ushort)0x0100) /* 1024-byte DMA xfer buffer */ +#define IDMA_DCM_DMA_WRAP_2048 ((ushort)0x0140) /* 2048-byte DMA xfer buffer */ +#define IDMA_DCM_SINC ((ushort)0x0020) /* source inc addr */ +#define IDMA_DCM_DINC ((ushort)0x0010) /* destination inc addr */ +#define IDMA_DCM_ERM ((ushort)0x0008) /* external request mode */ +#define IDMA_DCM_DT ((ushort)0x0004) /* DONE treatment */ +#define IDMA_DCM_SD_MASK ((ushort)0x0003) /* mask for SD bit field */ +#define IDMA_DCM_SD_MEM2MEM ((ushort)0x0000) /* memory-to-memory xfer */ +#define IDMA_DCM_SD_PER2MEM ((ushort)0x0002) /* peripheral-to-memory xfer */ +#define IDMA_DCM_SD_MEM2PER ((ushort)0x0001) /* memory-to-peripheral xfer */ + +/* IDMA Buffer Descriptors +*/ +typedef struct idma_bd { + uint flags; + uint len; /* data length */ + uint src; /* source data buffer pointer */ + uint dst; /* destination data buffer pointer */ +} idma_bd_t; + +/* IDMA buffer descriptor flag bit fields +*/ +#define IDMA_BD_V ((uint)0x80000000) /* valid */ +#define IDMA_BD_W ((uint)0x20000000) /* wrap */ +#define IDMA_BD_I ((uint)0x10000000) /* interrupt */ +#define IDMA_BD_L ((uint)0x08000000) /* last */ +#define IDMA_BD_CM ((uint)0x02000000) /* continuous mode */ +#define IDMA_BD_SDN ((uint)0x00400000) /* source done */ +#define IDMA_BD_DDN ((uint)0x00200000) /* destination done */ +#define IDMA_BD_DGBL ((uint)0x00100000) /* destination global */ +#define IDMA_BD_DBO_LE ((uint)0x00040000) /* little-end dest byte order */ +#define IDMA_BD_DBO_BE ((uint)0x00080000) /* big-end dest byte order */ +#define IDMA_BD_DDTB ((uint)0x00010000) /* destination data bus */ +#define IDMA_BD_SGBL ((uint)0x00002000) /* source global */ +#define IDMA_BD_SBO_LE ((uint)0x00000800) /* little-end src byte order */ +#define IDMA_BD_SBO_BE ((uint)0x00001000) /* big-end src byte order */ +#define IDMA_BD_SDTB ((uint)0x00000200) /* source data bus */ + +/* per-channel IDMA registers +*/ +typedef struct im_idma { + u_char idsr; /* IDMAn event status register */ + u_char res0[3]; + u_char idmr; /* IDMAn event mask register */ + u_char res1[3]; +} im_idma_t; + +/* IDMA event register bit fields +*/ +#define IDMA_EVENT_SC ((unsigned char)0x08) /* stop completed */ +#define IDMA_EVENT_OB ((unsigned char)0x04) /* out of buffers */ +#define IDMA_EVENT_EDN ((unsigned char)0x02) /* external DONE asserted */ +#define IDMA_EVENT_BC ((unsigned char)0x01) /* buffer descriptor complete */ + +/* RISC Controller Configuration Register (RCCR) bit fields +*/ +#define RCCR_TIME ((uint)0x80000000) /* timer enable */ +#define RCCR_TIMEP_MASK ((uint)0x3f000000) /* mask for timer period bit field */ +#define RCCR_DR0M ((uint)0x00800000) /* IDMA0 request mode */ +#define RCCR_DR1M ((uint)0x00400000) /* IDMA1 request mode */ +#define RCCR_DR2M ((uint)0x00000080) /* IDMA2 request mode */ +#define RCCR_DR3M ((uint)0x00000040) /* IDMA3 request mode */ +#define RCCR_DR0QP_MASK ((uint)0x00300000) /* mask for IDMA0 req priority */ +#define RCCR_DR0QP_HIGH ((uint)0x00000000) /* IDMA0 has high req priority */ +#define RCCR_DR0QP_MED ((uint)0x00100000) /* IDMA0 has medium req priority */ +#define RCCR_DR0QP_LOW ((uint)0x00200000) /* IDMA0 has low req priority */ +#define RCCR_DR1QP_MASK ((uint)0x00030000) /* mask for IDMA1 req priority */ +#define RCCR_DR1QP_HIGH ((uint)0x00000000) /* IDMA1 has high req priority */ +#define RCCR_DR1QP_MED ((uint)0x00010000) /* IDMA1 has medium req priority */ +#define RCCR_DR1QP_LOW ((uint)0x00020000) /* IDMA1 has low req priority */ +#define RCCR_DR2QP_MASK ((uint)0x00000030) /* mask for IDMA2 req priority */ +#define RCCR_DR2QP_HIGH ((uint)0x00000000) /* IDMA2 has high req priority */ +#define RCCR_DR2QP_MED ((uint)0x00000010) /* IDMA2 has medium req priority */ +#define RCCR_DR2QP_LOW ((uint)0x00000020) /* IDMA2 has low req priority */ +#define RCCR_DR3QP_MASK ((uint)0x00000003) /* mask for IDMA3 req priority */ +#define RCCR_DR3QP_HIGH ((uint)0x00000000) /* IDMA3 has high req priority */ +#define RCCR_DR3QP_MED ((uint)0x00000001) /* IDMA3 has medium req priority */ +#define RCCR_DR3QP_LOW ((uint)0x00000002) /* IDMA3 has low req priority */ +#define RCCR_EIE ((uint)0x00080000) /* external interrupt enable */ +#define RCCR_SCD ((uint)0x00040000) /* scheduler configuration */ +#define RCCR_ERAM_MASK ((uint)0x0000e000) /* mask for enable RAM microcode */ +#define RCCR_ERAM_0KB ((uint)0x00000000) /* use 0KB of dpram for microcode */ +#define RCCR_ERAM_2KB ((uint)0x00002000) /* use 2KB of dpram for microcode */ +#define RCCR_ERAM_4KB ((uint)0x00004000) /* use 4KB of dpram for microcode */ +#define RCCR_ERAM_6KB ((uint)0x00006000) /* use 6KB of dpram for microcode */ +#define RCCR_ERAM_8KB ((uint)0x00008000) /* use 8KB of dpram for microcode */ +#define RCCR_ERAM_10KB ((uint)0x0000a000) /* use 10KB of dpram for microcode */ +#define RCCR_ERAM_12KB ((uint)0x0000c000) /* use 12KB of dpram for microcode */ +#define RCCR_EDM0 ((uint)0x00000800) /* DREQ0 edge detect mode */ +#define RCCR_EDM1 ((uint)0x00000400) /* DREQ1 edge detect mode */ +#define RCCR_EDM2 ((uint)0x00000200) /* DREQ2 edge detect mode */ +#define RCCR_EDM3 ((uint)0x00000100) /* DREQ3 edge detect mode */ +#define RCCR_DEM01 ((uint)0x00000008) /* DONE0/DONE1 edge detect mode */ +#define RCCR_DEM23 ((uint)0x00000004) /* DONE2/DONE3 edge detect mode */ + +/*----------------------------------------------------------------------- + * CMXFCR - CMX FCC Clock Route Register + */ +#define CMXFCR_FC1 0x40000000 /* FCC1 connection */ +#define CMXFCR_RF1CS_MSK 0x38000000 /* Receive FCC1 Clock Source Mask */ +#define CMXFCR_TF1CS_MSK 0x07000000 /* Transmit FCC1 Clock Source Mask */ +#define CMXFCR_FC2 0x00400000 /* FCC2 connection */ +#define CMXFCR_RF2CS_MSK 0x00380000 /* Receive FCC2 Clock Source Mask */ +#define CMXFCR_TF2CS_MSK 0x00070000 /* Transmit FCC2 Clock Source Mask */ +#define CMXFCR_FC3 0x00004000 /* FCC3 connection */ +#define CMXFCR_RF3CS_MSK 0x00003800 /* Receive FCC3 Clock Source Mask */ +#define CMXFCR_TF3CS_MSK 0x00000700 /* Transmit FCC3 Clock Source Mask */ + +#define CMXFCR_RF1CS_BRG5 0x00000000 /* Receive FCC1 Clock Source is BRG5 */ +#define CMXFCR_RF1CS_BRG6 0x08000000 /* Receive FCC1 Clock Source is BRG6 */ +#define CMXFCR_RF1CS_BRG7 0x10000000 /* Receive FCC1 Clock Source is BRG7 */ +#define CMXFCR_RF1CS_BRG8 0x18000000 /* Receive FCC1 Clock Source is BRG8 */ +#define CMXFCR_RF1CS_CLK9 0x20000000 /* Receive FCC1 Clock Source is CLK9 */ +#define CMXFCR_RF1CS_CLK10 0x28000000 /* Receive FCC1 Clock Source is CLK10 */ +#define CMXFCR_RF1CS_CLK11 0x30000000 /* Receive FCC1 Clock Source is CLK11 */ +#define CMXFCR_RF1CS_CLK12 0x38000000 /* Receive FCC1 Clock Source is CLK12 */ + +#define CMXFCR_TF1CS_BRG5 0x00000000 /* Transmit FCC1 Clock Source is BRG5 */ +#define CMXFCR_TF1CS_BRG6 0x01000000 /* Transmit FCC1 Clock Source is BRG6 */ +#define CMXFCR_TF1CS_BRG7 0x02000000 /* Transmit FCC1 Clock Source is BRG7 */ +#define CMXFCR_TF1CS_BRG8 0x03000000 /* Transmit FCC1 Clock Source is BRG8 */ +#define CMXFCR_TF1CS_CLK9 0x04000000 /* Transmit FCC1 Clock Source is CLK9 */ +#define CMXFCR_TF1CS_CLK10 0x05000000 /* Transmit FCC1 Clock Source is CLK10 */ +#define CMXFCR_TF1CS_CLK11 0x06000000 /* Transmit FCC1 Clock Source is CLK11 */ +#define CMXFCR_TF1CS_CLK12 0x07000000 /* Transmit FCC1 Clock Source is CLK12 */ + +#define CMXFCR_RF2CS_BRG5 0x00000000 /* Receive FCC2 Clock Source is BRG5 */ +#define CMXFCR_RF2CS_BRG6 0x00080000 /* Receive FCC2 Clock Source is BRG6 */ +#define CMXFCR_RF2CS_BRG7 0x00100000 /* Receive FCC2 Clock Source is BRG7 */ +#define CMXFCR_RF2CS_BRG8 0x00180000 /* Receive FCC2 Clock Source is BRG8 */ +#define CMXFCR_RF2CS_CLK13 0x00200000 /* Receive FCC2 Clock Source is CLK13 */ +#define CMXFCR_RF2CS_CLK14 0x00280000 /* Receive FCC2 Clock Source is CLK14 */ +#define CMXFCR_RF2CS_CLK15 0x00300000 /* Receive FCC2 Clock Source is CLK15 */ +#define CMXFCR_RF2CS_CLK16 0x00380000 /* Receive FCC2 Clock Source is CLK16 */ + +#define CMXFCR_TF2CS_BRG5 0x00000000 /* Transmit FCC2 Clock Source is BRG5 */ +#define CMXFCR_TF2CS_BRG6 0x00010000 /* Transmit FCC2 Clock Source is BRG6 */ +#define CMXFCR_TF2CS_BRG7 0x00020000 /* Transmit FCC2 Clock Source is BRG7 */ +#define CMXFCR_TF2CS_BRG8 0x00030000 /* Transmit FCC2 Clock Source is BRG8 */ +#define CMXFCR_TF2CS_CLK13 0x00040000 /* Transmit FCC2 Clock Source is CLK13 */ +#define CMXFCR_TF2CS_CLK14 0x00050000 /* Transmit FCC2 Clock Source is CLK14 */ +#define CMXFCR_TF2CS_CLK15 0x00060000 /* Transmit FCC2 Clock Source is CLK15 */ +#define CMXFCR_TF2CS_CLK16 0x00070000 /* Transmit FCC2 Clock Source is CLK16 */ + +#define CMXFCR_RF3CS_BRG5 0x00000000 /* Receive FCC3 Clock Source is BRG5 */ +#define CMXFCR_RF3CS_BRG6 0x00000800 /* Receive FCC3 Clock Source is BRG6 */ +#define CMXFCR_RF3CS_BRG7 0x00001000 /* Receive FCC3 Clock Source is BRG7 */ +#define CMXFCR_RF3CS_BRG8 0x00001800 /* Receive FCC3 Clock Source is BRG8 */ +#define CMXFCR_RF3CS_CLK13 0x00002000 /* Receive FCC3 Clock Source is CLK13 */ +#define CMXFCR_RF3CS_CLK14 0x00002800 /* Receive FCC3 Clock Source is CLK14 */ +#define CMXFCR_RF3CS_CLK15 0x00003000 /* Receive FCC3 Clock Source is CLK15 */ +#define CMXFCR_RF3CS_CLK16 0x00003800 /* Receive FCC3 Clock Source is CLK16 */ + +#define CMXFCR_TF3CS_BRG5 0x00000000 /* Transmit FCC3 Clock Source is BRG5 */ +#define CMXFCR_TF3CS_BRG6 0x00000100 /* Transmit FCC3 Clock Source is BRG6 */ +#define CMXFCR_TF3CS_BRG7 0x00000200 /* Transmit FCC3 Clock Source is BRG7 */ +#define CMXFCR_TF3CS_BRG8 0x00000300 /* Transmit FCC3 Clock Source is BRG8 */ +#define CMXFCR_TF3CS_CLK13 0x00000400 /* Transmit FCC3 Clock Source is CLK13 */ +#define CMXFCR_TF3CS_CLK14 0x00000500 /* Transmit FCC3 Clock Source is CLK14 */ +#define CMXFCR_TF3CS_CLK15 0x00000600 /* Transmit FCC3 Clock Source is CLK15 */ +#define CMXFCR_TF3CS_CLK16 0x00000700 /* Transmit FCC3 Clock Source is CLK16 */ + +/*----------------------------------------------------------------------- + * CMXSCR - CMX SCC Clock Route Register + */ +#define CMXSCR_GR1 0x80000000 /* Grant Support of SCC1 */ +#define CMXSCR_SC1 0x40000000 /* SCC1 connection */ +#define CMXSCR_RS1CS_MSK 0x38000000 /* Receive SCC1 Clock Source Mask */ +#define CMXSCR_TS1CS_MSK 0x07000000 /* Transmit SCC1 Clock Source Mask */ +#define CMXSCR_GR2 0x00800000 /* Grant Support of SCC2 */ +#define CMXSCR_SC2 0x00400000 /* SCC2 connection */ +#define CMXSCR_RS2CS_MSK 0x00380000 /* Receive SCC2 Clock Source Mask */ +#define CMXSCR_TS2CS_MSK 0x00070000 /* Transmit SCC2 Clock Source Mask */ +#define CMXSCR_GR3 0x00008000 /* Grant Support of SCC3 */ +#define CMXSCR_SC3 0x00004000 /* SCC3 connection */ +#define CMXSCR_RS3CS_MSK 0x00003800 /* Receive SCC3 Clock Source Mask */ +#define CMXSCR_TS3CS_MSK 0x00000700 /* Transmit SCC3 Clock Source Mask */ +#define CMXSCR_GR4 0x00000080 /* Grant Support of SCC4 */ +#define CMXSCR_SC4 0x00000040 /* SCC4 connection */ +#define CMXSCR_RS4CS_MSK 0x00000038 /* Receive SCC4 Clock Source Mask */ +#define CMXSCR_TS4CS_MSK 0x00000007 /* Transmit SCC4 Clock Source Mask */ + +#define CMXSCR_RS1CS_BRG1 0x00000000 /* SCC1 Rx Clock Source is BRG1 */ +#define CMXSCR_RS1CS_BRG2 0x08000000 /* SCC1 Rx Clock Source is BRG2 */ +#define CMXSCR_RS1CS_BRG3 0x10000000 /* SCC1 Rx Clock Source is BRG3 */ +#define CMXSCR_RS1CS_BRG4 0x18000000 /* SCC1 Rx Clock Source is BRG4 */ +#define CMXSCR_RS1CS_CLK11 0x20000000 /* SCC1 Rx Clock Source is CLK11 */ +#define CMXSCR_RS1CS_CLK12 0x28000000 /* SCC1 Rx Clock Source is CLK12 */ +#define CMXSCR_RS1CS_CLK3 0x30000000 /* SCC1 Rx Clock Source is CLK3 */ +#define CMXSCR_RS1CS_CLK4 0x38000000 /* SCC1 Rx Clock Source is CLK4 */ + +#define CMXSCR_TS1CS_BRG1 0x00000000 /* SCC1 Tx Clock Source is BRG1 */ +#define CMXSCR_TS1CS_BRG2 0x01000000 /* SCC1 Tx Clock Source is BRG2 */ +#define CMXSCR_TS1CS_BRG3 0x02000000 /* SCC1 Tx Clock Source is BRG3 */ +#define CMXSCR_TS1CS_BRG4 0x03000000 /* SCC1 Tx Clock Source is BRG4 */ +#define CMXSCR_TS1CS_CLK11 0x04000000 /* SCC1 Tx Clock Source is CLK11 */ +#define CMXSCR_TS1CS_CLK12 0x05000000 /* SCC1 Tx Clock Source is CLK12 */ +#define CMXSCR_TS1CS_CLK3 0x06000000 /* SCC1 Tx Clock Source is CLK3 */ +#define CMXSCR_TS1CS_CLK4 0x07000000 /* SCC1 Tx Clock Source is CLK4 */ + +#define CMXSCR_RS2CS_BRG1 0x00000000 /* SCC2 Rx Clock Source is BRG1 */ +#define CMXSCR_RS2CS_BRG2 0x00080000 /* SCC2 Rx Clock Source is BRG2 */ +#define CMXSCR_RS2CS_BRG3 0x00100000 /* SCC2 Rx Clock Source is BRG3 */ +#define CMXSCR_RS2CS_BRG4 0x00180000 /* SCC2 Rx Clock Source is BRG4 */ +#define CMXSCR_RS2CS_CLK11 0x00200000 /* SCC2 Rx Clock Source is CLK11 */ +#define CMXSCR_RS2CS_CLK12 0x00280000 /* SCC2 Rx Clock Source is CLK12 */ +#define CMXSCR_RS2CS_CLK3 0x00300000 /* SCC2 Rx Clock Source is CLK3 */ +#define CMXSCR_RS2CS_CLK4 0x00380000 /* SCC2 Rx Clock Source is CLK4 */ + +#define CMXSCR_TS2CS_BRG1 0x00000000 /* SCC2 Tx Clock Source is BRG1 */ +#define CMXSCR_TS2CS_BRG2 0x00010000 /* SCC2 Tx Clock Source is BRG2 */ +#define CMXSCR_TS2CS_BRG3 0x00020000 /* SCC2 Tx Clock Source is BRG3 */ +#define CMXSCR_TS2CS_BRG4 0x00030000 /* SCC2 Tx Clock Source is BRG4 */ +#define CMXSCR_TS2CS_CLK11 0x00040000 /* SCC2 Tx Clock Source is CLK11 */ +#define CMXSCR_TS2CS_CLK12 0x00050000 /* SCC2 Tx Clock Source is CLK12 */ +#define CMXSCR_TS2CS_CLK3 0x00060000 /* SCC2 Tx Clock Source is CLK3 */ +#define CMXSCR_TS2CS_CLK4 0x00070000 /* SCC2 Tx Clock Source is CLK4 */ + +#define CMXSCR_RS3CS_BRG1 0x00000000 /* SCC3 Rx Clock Source is BRG1 */ +#define CMXSCR_RS3CS_BRG2 0x00000800 /* SCC3 Rx Clock Source is BRG2 */ +#define CMXSCR_RS3CS_BRG3 0x00001000 /* SCC3 Rx Clock Source is BRG3 */ +#define CMXSCR_RS3CS_BRG4 0x00001800 /* SCC3 Rx Clock Source is BRG4 */ +#define CMXSCR_RS3CS_CLK5 0x00002000 /* SCC3 Rx Clock Source is CLK5 */ +#define CMXSCR_RS3CS_CLK6 0x00002800 /* SCC3 Rx Clock Source is CLK6 */ +#define CMXSCR_RS3CS_CLK7 0x00003000 /* SCC3 Rx Clock Source is CLK7 */ +#define CMXSCR_RS3CS_CLK8 0x00003800 /* SCC3 Rx Clock Source is CLK8 */ + +#define CMXSCR_TS3CS_BRG1 0x00000000 /* SCC3 Tx Clock Source is BRG1 */ +#define CMXSCR_TS3CS_BRG2 0x00000100 /* SCC3 Tx Clock Source is BRG2 */ +#define CMXSCR_TS3CS_BRG3 0x00000200 /* SCC3 Tx Clock Source is BRG3 */ +#define CMXSCR_TS3CS_BRG4 0x00000300 /* SCC3 Tx Clock Source is BRG4 */ +#define CMXSCR_TS3CS_CLK5 0x00000400 /* SCC3 Tx Clock Source is CLK5 */ +#define CMXSCR_TS3CS_CLK6 0x00000500 /* SCC3 Tx Clock Source is CLK6 */ +#define CMXSCR_TS3CS_CLK7 0x00000600 /* SCC3 Tx Clock Source is CLK7 */ +#define CMXSCR_TS3CS_CLK8 0x00000700 /* SCC3 Tx Clock Source is CLK8 */ + +#define CMXSCR_RS4CS_BRG1 0x00000000 /* SCC4 Rx Clock Source is BRG1 */ +#define CMXSCR_RS4CS_BRG2 0x00000008 /* SCC4 Rx Clock Source is BRG2 */ +#define CMXSCR_RS4CS_BRG3 0x00000010 /* SCC4 Rx Clock Source is BRG3 */ +#define CMXSCR_RS4CS_BRG4 0x00000018 /* SCC4 Rx Clock Source is BRG4 */ +#define CMXSCR_RS4CS_CLK5 0x00000020 /* SCC4 Rx Clock Source is CLK5 */ +#define CMXSCR_RS4CS_CLK6 0x00000028 /* SCC4 Rx Clock Source is CLK6 */ +#define CMXSCR_RS4CS_CLK7 0x00000030 /* SCC4 Rx Clock Source is CLK7 */ +#define CMXSCR_RS4CS_CLK8 0x00000038 /* SCC4 Rx Clock Source is CLK8 */ + +#define CMXSCR_TS4CS_BRG1 0x00000000 /* SCC4 Tx Clock Source is BRG1 */ +#define CMXSCR_TS4CS_BRG2 0x00000001 /* SCC4 Tx Clock Source is BRG2 */ +#define CMXSCR_TS4CS_BRG3 0x00000002 /* SCC4 Tx Clock Source is BRG3 */ +#define CMXSCR_TS4CS_BRG4 0x00000003 /* SCC4 Tx Clock Source is BRG4 */ +#define CMXSCR_TS4CS_CLK5 0x00000004 /* SCC4 Tx Clock Source is CLK5 */ +#define CMXSCR_TS4CS_CLK6 0x00000005 /* SCC4 Tx Clock Source is CLK6 */ +#define CMXSCR_TS4CS_CLK7 0x00000006 /* SCC4 Tx Clock Source is CLK7 */ +#define CMXSCR_TS4CS_CLK8 0x00000007 /* SCC4 Tx Clock Source is CLK8 */ + +/*----------------------------------------------------------------------- + * SIUMCR - SIU Module Configuration Register 4-31 + */ +#define SIUMCR_BBD 0x80000000 /* Bus Busy Disable */ +#define SIUMCR_ESE 0x40000000 /* External Snoop Enable */ +#define SIUMCR_PBSE 0x20000000 /* Parity Byte Select Enable */ +#define SIUMCR_CDIS 0x10000000 /* Core Disable */ +#define SIUMCR_DPPC00 0x00000000 /* Data Parity Pins Configuration*/ +#define SIUMCR_DPPC01 0x04000000 /* - " - */ +#define SIUMCR_DPPC10 0x08000000 /* - " - */ +#define SIUMCR_DPPC11 0x0c000000 /* - " - */ +#define SIUMCR_L2CPC00 0x00000000 /* L2 Cache Pins Configuration */ +#define SIUMCR_L2CPC01 0x01000000 /* - " - */ +#define SIUMCR_L2CPC10 0x02000000 /* - " - */ +#define SIUMCR_L2CPC11 0x03000000 /* - " - */ +#define SIUMCR_LBPC00 0x00000000 /* Local Bus Pins Configuration */ +#define SIUMCR_LBPC01 0x00400000 /* - " - */ +#define SIUMCR_LBPC10 0x00800000 /* - " - */ +#define SIUMCR_LBPC11 0x00c00000 /* - " - */ +#define SIUMCR_APPC00 0x00000000 /* Address Parity Pins Configuration*/ +#define SIUMCR_APPC01 0x00100000 /* - " - */ +#define SIUMCR_APPC10 0x00200000 /* - " - */ +#define SIUMCR_APPC11 0x00300000 /* - " - */ +#define SIUMCR_CS10PC00 0x00000000 /* CS10 Pin Configuration */ +#define SIUMCR_CS10PC01 0x00040000 /* - " - */ +#define SIUMCR_CS10PC10 0x00080000 /* - " - */ +#define SIUMCR_CS10PC11 0x000c0000 /* - " - */ +#define SIUMCR_BCTLC00 0x00000000 /* Buffer Control Configuration */ +#define SIUMCR_BCTLC01 0x00010000 /* - " - */ +#define SIUMCR_BCTLC10 0x00020000 /* - " - */ +#define SIUMCR_BCTLC11 0x00030000 /* - " - */ +#define SIUMCR_MMR00 0x00000000 /* Mask Masters Requests */ +#define SIUMCR_MMR01 0x00004000 /* - " - */ +#define SIUMCR_MMR10 0x00008000 /* - " - */ +#define SIUMCR_MMR11 0x0000c000 /* - " - */ +#define SIUMCR_LPBSE 0x00002000 /* LocalBus Parity Byte Select Enable*/ + +/*----------------------------------------------------------------------- + * SCCR - System Clock Control Register 9-8 +*/ +#define SCCR_PCI_MODE 0x00000100 /* PCI Mode */ +#define SCCR_PCI_MODCK 0x00000080 /* Value of PCI_MODCK pin */ +#define SCCR_PCIDF_MSK 0x00000078 /* PCI division factor */ +#define SCCR_PCIDF_SHIFT 3 + +#ifndef CPM_IMMR_OFFSET +#define CPM_IMMR_OFFSET 0x101a8 +#endif + +#define FCC_PSMR_RMII ((uint)0x00020000) /* Use RMII interface */ + +/* FCC iop & clock configuration. BSP code is responsible to define Fx_RXCLK & Fx_TXCLK + * in order to use clock-computing stuff below for the FCC x + */ + +/* Automatically generates register configurations */ +#define PC_CLK(x) ((uint)(1<<(x-1))) /* FCC CLK I/O ports */ + +#define CMXFCR_RF1CS(x) ((uint)((x-5)<<27)) /* FCC1 Receive Clock Source */ +#define CMXFCR_TF1CS(x) ((uint)((x-5)<<24)) /* FCC1 Transmit Clock Source */ +#define CMXFCR_RF2CS(x) ((uint)((x-9)<<19)) /* FCC2 Receive Clock Source */ +#define CMXFCR_TF2CS(x) ((uint)((x-9)<<16)) /* FCC2 Transmit Clock Source */ +#define CMXFCR_RF3CS(x) ((uint)((x-9)<<11)) /* FCC3 Receive Clock Source */ +#define CMXFCR_TF3CS(x) ((uint)((x-9)<<8)) /* FCC3 Transmit Clock Source */ + +#define PC_F1RXCLK PC_CLK(F1_RXCLK) +#define PC_F1TXCLK PC_CLK(F1_TXCLK) +#define CMX1_CLK_ROUTE (CMXFCR_RF1CS(F1_RXCLK) | CMXFCR_TF1CS(F1_TXCLK)) +#define CMX1_CLK_MASK ((uint)0xff000000) + +#define PC_F2RXCLK PC_CLK(F2_RXCLK) +#define PC_F2TXCLK PC_CLK(F2_TXCLK) +#define CMX2_CLK_ROUTE (CMXFCR_RF2CS(F2_RXCLK) | CMXFCR_TF2CS(F2_TXCLK)) +#define CMX2_CLK_MASK ((uint)0x00ff0000) + +#define PC_F3RXCLK PC_CLK(F3_RXCLK) +#define PC_F3TXCLK PC_CLK(F3_TXCLK) +#define CMX3_CLK_ROUTE (CMXFCR_RF3CS(F3_RXCLK) | CMXFCR_TF3CS(F3_TXCLK)) +#define CMX3_CLK_MASK ((uint)0x0000ff00) + +#define CPMUX_CLK_MASK (CMX3_CLK_MASK | CMX2_CLK_MASK) +#define CPMUX_CLK_ROUTE (CMX3_CLK_ROUTE | CMX2_CLK_ROUTE) + +#define CLK_TRX (PC_F3TXCLK | PC_F3RXCLK | PC_F2TXCLK | PC_F2RXCLK) + +/* I/O Pin assignment for FCC1. I don't yet know the best way to do this, + * but there is little variation among the choices. + */ +#define PA1_COL 0x00000001U +#define PA1_CRS 0x00000002U +#define PA1_TXER 0x00000004U +#define PA1_TXEN 0x00000008U +#define PA1_RXDV 0x00000010U +#define PA1_RXER 0x00000020U +#define PA1_TXDAT 0x00003c00U +#define PA1_RXDAT 0x0003c000U +#define PA1_PSORA0 (PA1_RXDAT | PA1_TXDAT) +#define PA1_PSORA1 (PA1_COL | PA1_CRS | PA1_TXER | PA1_TXEN | \ + PA1_RXDV | PA1_RXER) +#define PA1_DIRA0 (PA1_RXDAT | PA1_CRS | PA1_COL | PA1_RXER | PA1_RXDV) +#define PA1_DIRA1 (PA1_TXDAT | PA1_TXEN | PA1_TXER) + + +/* I/O Pin assignment for FCC2. I don't yet know the best way to do this, + * but there is little variation among the choices. + */ +#define PB2_TXER 0x00000001U +#define PB2_RXDV 0x00000002U +#define PB2_TXEN 0x00000004U +#define PB2_RXER 0x00000008U +#define PB2_COL 0x00000010U +#define PB2_CRS 0x00000020U +#define PB2_TXDAT 0x000003c0U +#define PB2_RXDAT 0x00003c00U +#define PB2_PSORB0 (PB2_RXDAT | PB2_TXDAT | PB2_CRS | PB2_COL | \ + PB2_RXER | PB2_RXDV | PB2_TXER) +#define PB2_PSORB1 (PB2_TXEN) +#define PB2_DIRB0 (PB2_RXDAT | PB2_CRS | PB2_COL | PB2_RXER | PB2_RXDV) +#define PB2_DIRB1 (PB2_TXDAT | PB2_TXEN | PB2_TXER) + + +/* I/O Pin assignment for FCC3. I don't yet know the best way to do this, + * but there is little variation among the choices. + */ +#define PB3_RXDV 0x00004000U +#define PB3_RXER 0x00008000U +#define PB3_TXER 0x00010000U +#define PB3_TXEN 0x00020000U +#define PB3_COL 0x00040000U +#define PB3_CRS 0x00080000U +#define PB3_TXDAT 0x0f000000U +#define PC3_TXDAT 0x00000010U +#define PB3_RXDAT 0x00f00000U +#define PB3_PSORB0 (PB3_RXDAT | PB3_TXDAT | PB3_CRS | PB3_COL | \ + PB3_RXER | PB3_RXDV | PB3_TXER | PB3_TXEN) +#define PB3_PSORB1 0 +#define PB3_DIRB0 (PB3_RXDAT | PB3_CRS | PB3_COL | PB3_RXER | PB3_RXDV) +#define PB3_DIRB1 (PB3_TXDAT | PB3_TXEN | PB3_TXER) +#define PC3_DIRC1 (PC3_TXDAT) + +/* Handy macro to specify mem for FCCs*/ +#define FCC_MEM_OFFSET(x) (CPM_FCC_SPECIAL_BASE + (x*128)) +#define FCC1_MEM_OFFSET FCC_MEM_OFFSET(0) +#define FCC2_MEM_OFFSET FCC_MEM_OFFSET(1) +#define FCC3_MEM_OFFSET FCC_MEM_OFFSET(2) + +/* Clocks and GRG's */ + +enum cpm_clk_dir { + CPM_CLK_RX, + CPM_CLK_TX, + CPM_CLK_RTX +}; + +enum cpm_clk_target { + CPM_CLK_SCC1, + CPM_CLK_SCC2, + CPM_CLK_SCC3, + CPM_CLK_SCC4, + CPM_CLK_FCC1, + CPM_CLK_FCC2, + CPM_CLK_FCC3 +}; + +enum cpm_clk { + CPM_CLK_NONE = 0, + CPM_BRG1, /* Baud Rate Generator 1 */ + CPM_BRG2, /* Baud Rate Generator 2 */ + CPM_BRG3, /* Baud Rate Generator 3 */ + CPM_BRG4, /* Baud Rate Generator 4 */ + CPM_BRG5, /* Baud Rate Generator 5 */ + CPM_BRG6, /* Baud Rate Generator 6 */ + CPM_BRG7, /* Baud Rate Generator 7 */ + CPM_BRG8, /* Baud Rate Generator 8 */ + CPM_CLK1, /* Clock 1 */ + CPM_CLK2, /* Clock 2 */ + CPM_CLK3, /* Clock 3 */ + CPM_CLK4, /* Clock 4 */ + CPM_CLK5, /* Clock 5 */ + CPM_CLK6, /* Clock 6 */ + CPM_CLK7, /* Clock 7 */ + CPM_CLK8, /* Clock 8 */ + CPM_CLK9, /* Clock 9 */ + CPM_CLK10, /* Clock 10 */ + CPM_CLK11, /* Clock 11 */ + CPM_CLK12, /* Clock 12 */ + CPM_CLK13, /* Clock 13 */ + CPM_CLK14, /* Clock 14 */ + CPM_CLK15, /* Clock 15 */ + CPM_CLK16, /* Clock 16 */ + CPM_CLK17, /* Clock 17 */ + CPM_CLK18, /* Clock 18 */ + CPM_CLK19, /* Clock 19 */ + CPM_CLK20, /* Clock 20 */ + CPM_CLK_DUMMY +}; + +extern int cpm2_clk_setup(enum cpm_clk_target target, int clock, int mode); + +#endif /* __CPM2__ */ +#endif /* __KERNEL__ */ diff --git a/include/asm-powerpc/highmem.h b/include/asm-powerpc/highmem.h new file mode 100644 index 00000000000..f7b21ee302b --- /dev/null +++ b/include/asm-powerpc/highmem.h @@ -0,0 +1,135 @@ +/* + * highmem.h: virtual kernel memory mappings for high memory + * + * PowerPC version, stolen from the i386 version. + * + * Used in CONFIG_HIGHMEM systems for memory pages which + * are not addressable by direct kernel virtual addresses. + * + * Copyright (C) 1999 Gerhard Wichert, Siemens AG + * Gerhard.Wichert@pdb.siemens.de + * + * + * Redesigned the x86 32-bit VM architecture to deal with + * up to 16 Terrabyte physical memory. With current x86 CPUs + * we now support up to 64 Gigabytes physical RAM. + * + * Copyright (C) 1999 Ingo Molnar + */ + +#ifndef _ASM_HIGHMEM_H +#define _ASM_HIGHMEM_H + +#ifdef __KERNEL__ + +#include +#include +#include +#include +#include + +/* undef for production */ +#define HIGHMEM_DEBUG 1 + +extern pte_t *kmap_pte; +extern pgprot_t kmap_prot; +extern pte_t *pkmap_page_table; + +/* + * Right now we initialize only a single pte table. It can be extended + * easily, subsequent pte tables have to be allocated in one physical + * chunk of RAM. + */ +#define PKMAP_BASE CONFIG_HIGHMEM_START +#define LAST_PKMAP (1 << PTE_SHIFT) +#define LAST_PKMAP_MASK (LAST_PKMAP-1) +#define PKMAP_NR(virt) ((virt-PKMAP_BASE) >> PAGE_SHIFT) +#define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT)) + +#define KMAP_FIX_BEGIN (PKMAP_BASE + 0x00400000UL) + +extern void *kmap_high(struct page *page); +extern void kunmap_high(struct page *page); + +static inline void *kmap(struct page *page) +{ + might_sleep(); + if (!PageHighMem(page)) + return page_address(page); + return kmap_high(page); +} + +static inline void kunmap(struct page *page) +{ + BUG_ON(in_interrupt()); + if (!PageHighMem(page)) + return; + kunmap_high(page); +} + +/* + * The use of kmap_atomic/kunmap_atomic is discouraged - kmap/kunmap + * gives a more generic (and caching) interface. But kmap_atomic can + * be used in IRQ contexts, so in some (very limited) cases we need + * it. + */ +static inline void *kmap_atomic(struct page *page, enum km_type type) +{ + unsigned int idx; + unsigned long vaddr; + + /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */ + pagefault_disable(); + if (!PageHighMem(page)) + return page_address(page); + + idx = type + KM_TYPE_NR*smp_processor_id(); + vaddr = KMAP_FIX_BEGIN + idx * PAGE_SIZE; +#ifdef HIGHMEM_DEBUG + BUG_ON(!pte_none(*(kmap_pte+idx))); +#endif + set_pte_at(&init_mm, vaddr, kmap_pte+idx, mk_pte(page, kmap_prot)); + flush_tlb_page(NULL, vaddr); + + return (void*) vaddr; +} + +static inline void kunmap_atomic(void *kvaddr, enum km_type type) +{ +#ifdef HIGHMEM_DEBUG + unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK; + unsigned int idx = type + KM_TYPE_NR*smp_processor_id(); + + if (vaddr < KMAP_FIX_BEGIN) { // FIXME + pagefault_enable(); + return; + } + + BUG_ON(vaddr != KMAP_FIX_BEGIN + idx * PAGE_SIZE); + + /* + * force other mappings to Oops if they'll try to access + * this pte without first remap it + */ + pte_clear(&init_mm, vaddr, kmap_pte+idx); + flush_tlb_page(NULL, vaddr); +#endif + pagefault_enable(); +} + +static inline struct page *kmap_atomic_to_page(void *ptr) +{ + unsigned long idx, vaddr = (unsigned long) ptr; + + if (vaddr < KMAP_FIX_BEGIN) + return virt_to_page(ptr); + + idx = (vaddr - KMAP_FIX_BEGIN) >> PAGE_SHIFT; + return pte_page(kmap_pte[idx]); +} + +#define flush_cache_kmaps() flush_cache_all() + +#endif /* __KERNEL__ */ + +#endif /* _ASM_HIGHMEM_H */ diff --git a/include/asm-powerpc/hydra.h b/include/asm-powerpc/hydra.h new file mode 100644 index 00000000000..1ad4eed07fb --- /dev/null +++ b/include/asm-powerpc/hydra.h @@ -0,0 +1,102 @@ +/* + * include/asm-ppc/hydra.h -- Mac I/O `Hydra' definitions + * + * Copyright (C) 1997 Geert Uytterhoeven + * + * This file is based on the following documentation: + * + * Macintosh Technology in the Common Hardware Reference Platform + * Apple Computer, Inc. + * + * © Copyright 1995 Apple Computer, Inc. All rights reserved. + * + * It's available online from http://chrp.apple.com/MacTech.pdf. + * You can obtain paper copies of this book from computer bookstores or by + * writing Morgan Kaufmann Publishers, Inc., 340 Pine Street, Sixth Floor, San + * Francisco, CA 94104. Reference ISBN 1-55860-393-X. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#ifndef _ASMPPC_HYDRA_H +#define _ASMPPC_HYDRA_H + +#ifdef __KERNEL__ + +struct Hydra { + /* DBDMA Controller Register Space */ + char Pad1[0x30]; + u_int CachePD; + u_int IDs; + u_int Feature_Control; + char Pad2[0x7fc4]; + /* DBDMA Channel Register Space */ + char SCSI_DMA[0x100]; + char Pad3[0x300]; + char SCCA_Tx_DMA[0x100]; + char SCCA_Rx_DMA[0x100]; + char SCCB_Tx_DMA[0x100]; + char SCCB_Rx_DMA[0x100]; + char Pad4[0x7800]; + /* Device Register Space */ + char SCSI[0x1000]; + char ADB[0x1000]; + char SCC_Legacy[0x1000]; + char SCC[0x1000]; + char Pad9[0x2000]; + char VIA[0x2000]; + char Pad10[0x28000]; + char OpenPIC[0x40000]; +}; + +extern volatile struct Hydra __iomem *Hydra; + + + /* + * Feature Control Register + */ + +#define HYDRA_FC_SCC_CELL_EN 0x00000001 /* Enable SCC Clock */ +#define HYDRA_FC_SCSI_CELL_EN 0x00000002 /* Enable SCSI Clock */ +#define HYDRA_FC_SCCA_ENABLE 0x00000004 /* Enable SCC A Lines */ +#define HYDRA_FC_SCCB_ENABLE 0x00000008 /* Enable SCC B Lines */ +#define HYDRA_FC_ARB_BYPASS 0x00000010 /* Bypass Internal Arbiter */ +#define HYDRA_FC_RESET_SCC 0x00000020 /* Reset SCC */ +#define HYDRA_FC_MPIC_ENABLE 0x00000040 /* Enable OpenPIC */ +#define HYDRA_FC_SLOW_SCC_PCLK 0x00000080 /* 1=15.6672, 0=25 MHz */ +#define HYDRA_FC_MPIC_IS_MASTER 0x00000100 /* OpenPIC Master Mode */ + + + /* + * OpenPIC Interrupt Sources + */ + +#define HYDRA_INT_SIO 0 +#define HYDRA_INT_SCSI_DMA 1 +#define HYDRA_INT_SCCA_TX_DMA 2 +#define HYDRA_INT_SCCA_RX_DMA 3 +#define HYDRA_INT_SCCB_TX_DMA 4 +#define HYDRA_INT_SCCB_RX_DMA 5 +#define HYDRA_INT_SCSI 6 +#define HYDRA_INT_SCCA 7 +#define HYDRA_INT_SCCB 8 +#define HYDRA_INT_VIA 9 +#define HYDRA_INT_ADB 10 +#define HYDRA_INT_ADB_NMI 11 +#define HYDRA_INT_EXT1 12 /* PCI IRQW */ +#define HYDRA_INT_EXT2 13 /* PCI IRQX */ +#define HYDRA_INT_EXT3 14 /* PCI IRQY */ +#define HYDRA_INT_EXT4 15 /* PCI IRQZ */ +#define HYDRA_INT_EXT5 16 /* IDE Primay/Secondary */ +#define HYDRA_INT_EXT6 17 /* IDE Secondary */ +#define HYDRA_INT_EXT7 18 /* Power Off Request */ +#define HYDRA_INT_SPARE 19 + +extern int hydra_init(void); +extern void macio_adb_init(void); + +#endif /* __KERNEL__ */ + +#endif /* _ASMPPC_HYDRA_H */ diff --git a/include/asm-powerpc/immap_cpm2.h b/include/asm-powerpc/immap_cpm2.h new file mode 100644 index 00000000000..f316a91c628 --- /dev/null +++ b/include/asm-powerpc/immap_cpm2.h @@ -0,0 +1,648 @@ +/* + * CPM2 Internal Memory Map + * Copyright (c) 1999 Dan Malek (dmalek@jlc.net) + * + * The Internal Memory Map for devices with CPM2 on them. This + * is the superset of all CPM2 devices (8260, 8266, 8280, 8272, + * 8560). + */ +#ifdef __KERNEL__ +#ifndef __IMMAP_CPM2__ +#define __IMMAP_CPM2__ + +/* System configuration registers. +*/ +typedef struct sys_82xx_conf { + u32 sc_siumcr; + u32 sc_sypcr; + u8 res1[6]; + u16 sc_swsr; + u8 res2[20]; + u32 sc_bcr; + u8 sc_ppc_acr; + u8 res3[3]; + u32 sc_ppc_alrh; + u32 sc_ppc_alrl; + u8 sc_lcl_acr; + u8 res4[3]; + u32 sc_lcl_alrh; + u32 sc_lcl_alrl; + u32 sc_tescr1; + u32 sc_tescr2; + u32 sc_ltescr1; + u32 sc_ltescr2; + u32 sc_pdtea; + u8 sc_pdtem; + u8 res5[3]; + u32 sc_ldtea; + u8 sc_ldtem; + u8 res6[163]; +} sysconf_82xx_cpm2_t; + +typedef struct sys_85xx_conf { + u32 sc_cear; + u16 sc_ceer; + u16 sc_cemr; + u8 res1[70]; + u32 sc_smaer; + u8 res2[4]; + u32 sc_smevr; + u32 sc_smctr; + u32 sc_lmaer; + u8 res3[4]; + u32 sc_lmevr; + u32 sc_lmctr; + u8 res4[144]; +} sysconf_85xx_cpm2_t; + +typedef union sys_conf { + sysconf_82xx_cpm2_t siu_82xx; + sysconf_85xx_cpm2_t siu_85xx; +} sysconf_cpm2_t; + + + +/* Memory controller registers. +*/ +typedef struct mem_ctlr { + u32 memc_br0; + u32 memc_or0; + u32 memc_br1; + u32 memc_or1; + u32 memc_br2; + u32 memc_or2; + u32 memc_br3; + u32 memc_or3; + u32 memc_br4; + u32 memc_or4; + u32 memc_br5; + u32 memc_or5; + u32 memc_br6; + u32 memc_or6; + u32 memc_br7; + u32 memc_or7; + u32 memc_br8; + u32 memc_or8; + u32 memc_br9; + u32 memc_or9; + u32 memc_br10; + u32 memc_or10; + u32 memc_br11; + u32 memc_or11; + u8 res1[8]; + u32 memc_mar; + u8 res2[4]; + u32 memc_mamr; + u32 memc_mbmr; + u32 memc_mcmr; + u8 res3[8]; + u16 memc_mptpr; + u8 res4[2]; + u32 memc_mdr; + u8 res5[4]; + u32 memc_psdmr; + u32 memc_lsdmr; + u8 memc_purt; + u8 res6[3]; + u8 memc_psrt; + u8 res7[3]; + u8 memc_lurt; + u8 res8[3]; + u8 memc_lsrt; + u8 res9[3]; + u32 memc_immr; + u32 memc_pcibr0; + u32 memc_pcibr1; + u8 res10[16]; + u32 memc_pcimsk0; + u32 memc_pcimsk1; + u8 res11[52]; +} memctl_cpm2_t; + +/* System Integration Timers. +*/ +typedef struct sys_int_timers { + u8 res1[32]; + u16 sit_tmcntsc; + u8 res2[2]; + u32 sit_tmcnt; + u8 res3[4]; + u32 sit_tmcntal; + u8 res4[16]; + u16 sit_piscr; + u8 res5[2]; + u32 sit_pitc; + u32 sit_pitr; + u8 res6[94]; + u8 res7[390]; +} sit_cpm2_t; + +#define PISCR_PIRQ_MASK ((u16)0xff00) +#define PISCR_PS ((u16)0x0080) +#define PISCR_PIE ((u16)0x0004) +#define PISCR_PTF ((u16)0x0002) +#define PISCR_PTE ((u16)0x0001) + +/* PCI Controller. +*/ +typedef struct pci_ctlr { + u32 pci_omisr; + u32 pci_omimr; + u8 res1[8]; + u32 pci_ifqpr; + u32 pci_ofqpr; + u8 res2[8]; + u32 pci_imr0; + u32 pci_imr1; + u32 pci_omr0; + u32 pci_omr1; + u32 pci_odr; + u8 res3[4]; + u32 pci_idr; + u8 res4[20]; + u32 pci_imisr; + u32 pci_imimr; + u8 res5[24]; + u32 pci_ifhpr; + u8 res6[4]; + u32 pci_iftpr; + u8 res7[4]; + u32 pci_iphpr; + u8 res8[4]; + u32 pci_iptpr; + u8 res9[4]; + u32 pci_ofhpr; + u8 res10[4]; + u32 pci_oftpr; + u8 res11[4]; + u32 pci_ophpr; + u8 res12[4]; + u32 pci_optpr; + u8 res13[8]; + u32 pci_mucr; + u8 res14[8]; + u32 pci_qbar; + u8 res15[12]; + u32 pci_dmamr0; + u32 pci_dmasr0; + u32 pci_dmacdar0; + u8 res16[4]; + u32 pci_dmasar0; + u8 res17[4]; + u32 pci_dmadar0; + u8 res18[4]; + u32 pci_dmabcr0; + u32 pci_dmandar0; + u8 res19[86]; + u32 pci_dmamr1; + u32 pci_dmasr1; + u32 pci_dmacdar1; + u8 res20[4]; + u32 pci_dmasar1; + u8 res21[4]; + u32 pci_dmadar1; + u8 res22[4]; + u32 pci_dmabcr1; + u32 pci_dmandar1; + u8 res23[88]; + u32 pci_dmamr2; + u32 pci_dmasr2; + u32 pci_dmacdar2; + u8 res24[4]; + u32 pci_dmasar2; + u8 res25[4]; + u32 pci_dmadar2; + u8 res26[4]; + u32 pci_dmabcr2; + u32 pci_dmandar2; + u8 res27[88]; + u32 pci_dmamr3; + u32 pci_dmasr3; + u32 pci_dmacdar3; + u8 res28[4]; + u32 pci_dmasar3; + u8 res29[4]; + u32 pci_dmadar3; + u8 res30[4]; + u32 pci_dmabcr3; + u32 pci_dmandar3; + u8 res31[344]; + u32 pci_potar0; + u8 res32[4]; + u32 pci_pobar0; + u8 res33[4]; + u32 pci_pocmr0; + u8 res34[4]; + u32 pci_potar1; + u8 res35[4]; + u32 pci_pobar1; + u8 res36[4]; + u32 pci_pocmr1; + u8 res37[4]; + u32 pci_potar2; + u8 res38[4]; + u32 pci_pobar2; + u8 res39[4]; + u32 pci_pocmr2; + u8 res40[50]; + u32 pci_ptcr; + u32 pci_gpcr; + u32 pci_gcr; + u32 pci_esr; + u32 pci_emr; + u32 pci_ecr; + u32 pci_eacr; + u8 res41[4]; + u32 pci_edcr; + u8 res42[4]; + u32 pci_eccr; + u8 res43[44]; + u32 pci_pitar1; + u8 res44[4]; + u32 pci_pibar1; + u8 res45[4]; + u32 pci_picmr1; + u8 res46[4]; + u32 pci_pitar0; + u8 res47[4]; + u32 pci_pibar0; + u8 res48[4]; + u32 pci_picmr0; + u8 res49[4]; + u32 pci_cfg_addr; + u32 pci_cfg_data; + u32 pci_int_ack; + u8 res50[756]; +} pci_cpm2_t; + +/* Interrupt Controller. +*/ +typedef struct interrupt_controller { + u16 ic_sicr; + u8 res1[2]; + u32 ic_sivec; + u32 ic_sipnrh; + u32 ic_sipnrl; + u32 ic_siprr; + u32 ic_scprrh; + u32 ic_scprrl; + u32 ic_simrh; + u32 ic_simrl; + u32 ic_siexr; + u8 res2[88]; +} intctl_cpm2_t; + +/* Clocks and Reset. +*/ +typedef struct clk_and_reset { + u32 car_sccr; + u8 res1[4]; + u32 car_scmr; + u8 res2[4]; + u32 car_rsr; + u32 car_rmr; + u8 res[104]; +} car_cpm2_t; + +/* Input/Output Port control/status registers. + * Names consistent with processor manual, although they are different + * from the original 8xx names....... + */ +typedef struct io_port { + u32 iop_pdira; + u32 iop_ppara; + u32 iop_psora; + u32 iop_podra; + u32 iop_pdata; + u8 res1[12]; + u32 iop_pdirb; + u32 iop_pparb; + u32 iop_psorb; + u32 iop_podrb; + u32 iop_pdatb; + u8 res2[12]; + u32 iop_pdirc; + u32 iop_pparc; + u32 iop_psorc; + u32 iop_podrc; + u32 iop_pdatc; + u8 res3[12]; + u32 iop_pdird; + u32 iop_ppard; + u32 iop_psord; + u32 iop_podrd; + u32 iop_pdatd; + u8 res4[12]; +} iop_cpm2_t; + +/* Communication Processor Module Timers +*/ +typedef struct cpm_timers { + u8 cpmt_tgcr1; + u8 res1[3]; + u8 cpmt_tgcr2; + u8 res2[11]; + u16 cpmt_tmr1; + u16 cpmt_tmr2; + u16 cpmt_trr1; + u16 cpmt_trr2; + u16 cpmt_tcr1; + u16 cpmt_tcr2; + u16 cpmt_tcn1; + u16 cpmt_tcn2; + u16 cpmt_tmr3; + u16 cpmt_tmr4; + u16 cpmt_trr3; + u16 cpmt_trr4; + u16 cpmt_tcr3; + u16 cpmt_tcr4; + u16 cpmt_tcn3; + u16 cpmt_tcn4; + u16 cpmt_ter1; + u16 cpmt_ter2; + u16 cpmt_ter3; + u16 cpmt_ter4; + u8 res3[584]; +} cpmtimer_cpm2_t; + +/* DMA control/status registers. +*/ +typedef struct sdma_csr { + u8 res0[24]; + u8 sdma_sdsr; + u8 res1[3]; + u8 sdma_sdmr; + u8 res2[3]; + u8 sdma_idsr1; + u8 res3[3]; + u8 sdma_idmr1; + u8 res4[3]; + u8 sdma_idsr2; + u8 res5[3]; + u8 sdma_idmr2; + u8 res6[3]; + u8 sdma_idsr3; + u8 res7[3]; + u8 sdma_idmr3; + u8 res8[3]; + u8 sdma_idsr4; + u8 res9[3]; + u8 sdma_idmr4; + u8 res10[707]; +} sdma_cpm2_t; + +/* Fast controllers +*/ +typedef struct fcc { + u32 fcc_gfmr; + u32 fcc_fpsmr; + u16 fcc_ftodr; + u8 res1[2]; + u16 fcc_fdsr; + u8 res2[2]; + u16 fcc_fcce; + u8 res3[2]; + u16 fcc_fccm; + u8 res4[2]; + u8 fcc_fccs; + u8 res5[3]; + u8 fcc_ftirr_phy[4]; +} fcc_t; + +/* Fast controllers continued + */ +typedef struct fcc_c { + u32 fcc_firper; + u32 fcc_firer; + u32 fcc_firsr_hi; + u32 fcc_firsr_lo; + u8 fcc_gfemr; + u8 res1[15]; +} fcc_c_t; + +/* TC Layer + */ +typedef struct tclayer { + u16 tc_tcmode; + u16 tc_cdsmr; + u16 tc_tcer; + u16 tc_rcc; + u16 tc_tcmr; + u16 tc_fcc; + u16 tc_ccc; + u16 tc_icc; + u16 tc_tcc; + u16 tc_ecc; + u8 res1[12]; +} tclayer_t; + + +/* I2C +*/ +typedef struct i2c { + u8 i2c_i2mod; + u8 res1[3]; + u8 i2c_i2add; + u8 res2[3]; + u8 i2c_i2brg; + u8 res3[3]; + u8 i2c_i2com; + u8 res4[3]; + u8 i2c_i2cer; + u8 res5[3]; + u8 i2c_i2cmr; + u8 res6[331]; +} i2c_cpm2_t; + +typedef struct scc { /* Serial communication channels */ + u32 scc_gsmrl; + u32 scc_gsmrh; + u16 scc_psmr; + u8 res1[2]; + u16 scc_todr; + u16 scc_dsr; + u16 scc_scce; + u8 res2[2]; + u16 scc_sccm; + u8 res3; + u8 scc_sccs; + u8 res4[8]; +} scc_t; + +typedef struct smc { /* Serial management channels */ + u8 res1[2]; + u16 smc_smcmr; + u8 res2[2]; + u8 smc_smce; + u8 res3[3]; + u8 smc_smcm; + u8 res4[5]; +} smc_t; + +/* Serial Peripheral Interface. +*/ +typedef struct spi_ctrl { + u16 spi_spmode; + u8 res1[4]; + u8 spi_spie; + u8 res2[3]; + u8 spi_spim; + u8 res3[2]; + u8 spi_spcom; + u8 res4[82]; +} spictl_cpm2_t; + +/* CPM Mux. +*/ +typedef struct cpmux { + u8 cmx_si1cr; + u8 res1; + u8 cmx_si2cr; + u8 res2; + u32 cmx_fcr; + u32 cmx_scr; + u8 cmx_smr; + u8 res3; + u16 cmx_uar; + u8 res4[16]; +} cpmux_t; + +/* SIRAM control +*/ +typedef struct siram { + u16 si_amr; + u16 si_bmr; + u16 si_cmr; + u16 si_dmr; + u8 si_gmr; + u8 res1; + u8 si_cmdr; + u8 res2; + u8 si_str; + u8 res3; + u16 si_rsr; +} siramctl_t; + +typedef struct mcc { + u16 mcc_mcce; + u8 res1[2]; + u16 mcc_mccm; + u8 res2[2]; + u8 mcc_mccf; + u8 res3[7]; +} mcc_t; + +typedef struct comm_proc { + u32 cp_cpcr; + u32 cp_rccr; + u8 res1[14]; + u16 cp_rter; + u8 res2[2]; + u16 cp_rtmr; + u16 cp_rtscr; + u8 res3[2]; + u32 cp_rtsr; + u8 res4[12]; +} cpm_cpm2_t; + +/* USB Controller. +*/ +typedef struct usb_ctlr { + u8 usb_usmod; + u8 usb_usadr; + u8 usb_uscom; + u8 res1[1]; + u16 usb_usep1; + u16 usb_usep2; + u16 usb_usep3; + u16 usb_usep4; + u8 res2[4]; + u16 usb_usber; + u8 res3[2]; + u16 usb_usbmr; + u8 usb_usbs; + u8 res4[7]; +} usb_cpm2_t; + +/* ...and the whole thing wrapped up.... +*/ + +typedef struct immap { + /* Some references are into the unique and known dpram spaces, + * others are from the generic base. + */ +#define im_dprambase im_dpram1 + u8 im_dpram1[16*1024]; + u8 res1[16*1024]; + u8 im_dpram2[4*1024]; + u8 res2[8*1024]; + u8 im_dpram3[4*1024]; + u8 res3[16*1024]; + + sysconf_cpm2_t im_siu_conf; /* SIU Configuration */ + memctl_cpm2_t im_memctl; /* Memory Controller */ + sit_cpm2_t im_sit; /* System Integration Timers */ + pci_cpm2_t im_pci; /* PCI Controller */ + intctl_cpm2_t im_intctl; /* Interrupt Controller */ + car_cpm2_t im_clkrst; /* Clocks and reset */ + iop_cpm2_t im_ioport; /* IO Port control/status */ + cpmtimer_cpm2_t im_cpmtimer; /* CPM timers */ + sdma_cpm2_t im_sdma; /* SDMA control/status */ + + fcc_t im_fcc[3]; /* Three FCCs */ + u8 res4z[32]; + fcc_c_t im_fcc_c[3]; /* Continued FCCs */ + + u8 res4[32]; + + tclayer_t im_tclayer[8]; /* Eight TCLayers */ + u16 tc_tcgsr; + u16 tc_tcger; + + /* First set of baud rate generators. + */ + u8 res[236]; + u32 im_brgc5; + u32 im_brgc6; + u32 im_brgc7; + u32 im_brgc8; + + u8 res5[608]; + + i2c_cpm2_t im_i2c; /* I2C control/status */ + cpm_cpm2_t im_cpm; /* Communication processor */ + + /* Second set of baud rate generators. + */ + u32 im_brgc1; + u32 im_brgc2; + u32 im_brgc3; + u32 im_brgc4; + + scc_t im_scc[4]; /* Four SCCs */ + smc_t im_smc[2]; /* Couple of SMCs */ + spictl_cpm2_t im_spi; /* A SPI */ + cpmux_t im_cpmux; /* CPM clock route mux */ + siramctl_t im_siramctl1; /* First SI RAM Control */ + mcc_t im_mcc1; /* First MCC */ + siramctl_t im_siramctl2; /* Second SI RAM Control */ + mcc_t im_mcc2; /* Second MCC */ + usb_cpm2_t im_usb; /* USB Controller */ + + u8 res6[1153]; + + u16 im_si1txram[256]; + u8 res7[512]; + u16 im_si1rxram[256]; + u8 res8[512]; + u16 im_si2txram[256]; + u8 res9[512]; + u16 im_si2rxram[256]; + u8 res10[512]; + u8 res11[4096]; +} cpm2_map_t; + +extern cpm2_map_t *cpm2_immr; + +#endif /* __IMMAP_CPM2__ */ +#endif /* __KERNEL__ */ diff --git a/include/asm-powerpc/kgdb.h b/include/asm-powerpc/kgdb.h new file mode 100644 index 00000000000..b617dac8296 --- /dev/null +++ b/include/asm-powerpc/kgdb.h @@ -0,0 +1,57 @@ +/* + * kgdb.h: Defines and declarations for serial line source level + * remote debugging of the Linux kernel using gdb. + * + * PPC Mods (C) 1998 Michael Tesch (tesch@cs.wisc.edu) + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + */ +#ifdef __KERNEL__ +#ifndef _PPC_KGDB_H +#define _PPC_KGDB_H + +#ifndef __ASSEMBLY__ + +/* Things specific to the gen550 backend. */ +struct uart_port; + +extern void gen550_progress(char *, unsigned short); +extern void gen550_kgdb_map_scc(void); +extern void gen550_init(int, struct uart_port *); + +/* Things specific to the pmac backend. */ +extern void zs_kgdb_hook(int tty_num); + +/* To init the kgdb engine. (called by serial hook)*/ +extern void set_debug_traps(void); + +/* To enter the debugger explicitly. */ +extern void breakpoint(void); + +/* For taking exceptions + * these are defined in traps.c + */ +extern int (*debugger)(struct pt_regs *regs); +extern int (*debugger_bpt)(struct pt_regs *regs); +extern int (*debugger_sstep)(struct pt_regs *regs); +extern int (*debugger_iabr_match)(struct pt_regs *regs); +extern int (*debugger_dabr_match)(struct pt_regs *regs); +extern void (*debugger_fault_handler)(struct pt_regs *regs); + +/* What we bring to the party */ +int kgdb_bpt(struct pt_regs *regs); +int kgdb_sstep(struct pt_regs *regs); +void kgdb(struct pt_regs *regs); +int kgdb_iabr_match(struct pt_regs *regs); +int kgdb_dabr_match(struct pt_regs *regs); + +/* + * external low-level support routines (ie macserial.c) + */ +extern void kgdb_interruptible(int); /* control interrupts from serial */ +extern void putDebugChar(char); /* write a single character */ +extern char getDebugChar(void); /* read and return a single char */ + +#endif /* !(__ASSEMBLY__) */ +#endif /* !(_PPC_KGDB_H) */ +#endif /* __KERNEL__ */ diff --git a/include/asm-powerpc/mpc52xx_psc.h b/include/asm-powerpc/mpc52xx_psc.h new file mode 100644 index 00000000000..26690d2b32f --- /dev/null +++ b/include/asm-powerpc/mpc52xx_psc.h @@ -0,0 +1,191 @@ +/* + * include/asm-ppc/mpc52xx_psc.h + * + * Definitions of consts/structs to drive the Freescale MPC52xx OnChip + * PSCs. Theses are shared between multiple drivers since a PSC can be + * UART, AC97, IR, I2S, ... So this header is in asm-ppc. + * + * + * Maintainer : Sylvain Munaut + * + * Based/Extracted from some header of the 2.4 originally written by + * Dale Farnsworth + * + * Copyright (C) 2004 Sylvain Munaut + * Copyright (C) 2003 MontaVista, Software, Inc. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#ifndef __ASM_MPC52xx_PSC_H__ +#define __ASM_MPC52xx_PSC_H__ + +#include + +/* Max number of PSCs */ +#define MPC52xx_PSC_MAXNUM 6 + +/* Programmable Serial Controller (PSC) status register bits */ +#define MPC52xx_PSC_SR_CDE 0x0080 +#define MPC52xx_PSC_SR_RXRDY 0x0100 +#define MPC52xx_PSC_SR_RXFULL 0x0200 +#define MPC52xx_PSC_SR_TXRDY 0x0400 +#define MPC52xx_PSC_SR_TXEMP 0x0800 +#define MPC52xx_PSC_SR_OE 0x1000 +#define MPC52xx_PSC_SR_PE 0x2000 +#define MPC52xx_PSC_SR_FE 0x4000 +#define MPC52xx_PSC_SR_RB 0x8000 + +/* PSC Command values */ +#define MPC52xx_PSC_RX_ENABLE 0x0001 +#define MPC52xx_PSC_RX_DISABLE 0x0002 +#define MPC52xx_PSC_TX_ENABLE 0x0004 +#define MPC52xx_PSC_TX_DISABLE 0x0008 +#define MPC52xx_PSC_SEL_MODE_REG_1 0x0010 +#define MPC52xx_PSC_RST_RX 0x0020 +#define MPC52xx_PSC_RST_TX 0x0030 +#define MPC52xx_PSC_RST_ERR_STAT 0x0040 +#define MPC52xx_PSC_RST_BRK_CHG_INT 0x0050 +#define MPC52xx_PSC_START_BRK 0x0060 +#define MPC52xx_PSC_STOP_BRK 0x0070 + +/* PSC TxRx FIFO status bits */ +#define MPC52xx_PSC_RXTX_FIFO_ERR 0x0040 +#define MPC52xx_PSC_RXTX_FIFO_UF 0x0020 +#define MPC52xx_PSC_RXTX_FIFO_OF 0x0010 +#define MPC52xx_PSC_RXTX_FIFO_FR 0x0008 +#define MPC52xx_PSC_RXTX_FIFO_FULL 0x0004 +#define MPC52xx_PSC_RXTX_FIFO_ALARM 0x0002 +#define MPC52xx_PSC_RXTX_FIFO_EMPTY 0x0001 + +/* PSC interrupt mask bits */ +#define MPC52xx_PSC_IMR_TXRDY 0x0100 +#define MPC52xx_PSC_IMR_RXRDY 0x0200 +#define MPC52xx_PSC_IMR_DB 0x0400 +#define MPC52xx_PSC_IMR_IPC 0x8000 + +/* PSC input port change bit */ +#define MPC52xx_PSC_CTS 0x01 +#define MPC52xx_PSC_DCD 0x02 +#define MPC52xx_PSC_D_CTS 0x10 +#define MPC52xx_PSC_D_DCD 0x20 + +/* PSC mode fields */ +#define MPC52xx_PSC_MODE_5_BITS 0x00 +#define MPC52xx_PSC_MODE_6_BITS 0x01 +#define MPC52xx_PSC_MODE_7_BITS 0x02 +#define MPC52xx_PSC_MODE_8_BITS 0x03 +#define MPC52xx_PSC_MODE_BITS_MASK 0x03 +#define MPC52xx_PSC_MODE_PAREVEN 0x00 +#define MPC52xx_PSC_MODE_PARODD 0x04 +#define MPC52xx_PSC_MODE_PARFORCE 0x08 +#define MPC52xx_PSC_MODE_PARNONE 0x10 +#define MPC52xx_PSC_MODE_ERR 0x20 +#define MPC52xx_PSC_MODE_FFULL 0x40 +#define MPC52xx_PSC_MODE_RXRTS 0x80 + +#define MPC52xx_PSC_MODE_ONE_STOP_5_BITS 0x00 +#define MPC52xx_PSC_MODE_ONE_STOP 0x07 +#define MPC52xx_PSC_MODE_TWO_STOP 0x0f + +#define MPC52xx_PSC_RFNUM_MASK 0x01ff + + +/* Structure of the hardware registers */ +struct mpc52xx_psc { + u8 mode; /* PSC + 0x00 */ + u8 reserved0[3]; + union { /* PSC + 0x04 */ + u16 status; + u16 clock_select; + } sr_csr; +#define mpc52xx_psc_status sr_csr.status +#define mpc52xx_psc_clock_select sr_csr.clock_select + u16 reserved1; + u8 command; /* PSC + 0x08 */ + u8 reserved2[3]; + union { /* PSC + 0x0c */ + u8 buffer_8; + u16 buffer_16; + u32 buffer_32; + } buffer; +#define mpc52xx_psc_buffer_8 buffer.buffer_8 +#define mpc52xx_psc_buffer_16 buffer.buffer_16 +#define mpc52xx_psc_buffer_32 buffer.buffer_32 + union { /* PSC + 0x10 */ + u8 ipcr; + u8 acr; + } ipcr_acr; +#define mpc52xx_psc_ipcr ipcr_acr.ipcr +#define mpc52xx_psc_acr ipcr_acr.acr + u8 reserved3[3]; + union { /* PSC + 0x14 */ + u16 isr; + u16 imr; + } isr_imr; +#define mpc52xx_psc_isr isr_imr.isr +#define mpc52xx_psc_imr isr_imr.imr + u16 reserved4; + u8 ctur; /* PSC + 0x18 */ + u8 reserved5[3]; + u8 ctlr; /* PSC + 0x1c */ + u8 reserved6[3]; + u16 ccr; /* PSC + 0x20 */ + u8 reserved7[14]; + u8 ivr; /* PSC + 0x30 */ + u8 reserved8[3]; + u8 ip; /* PSC + 0x34 */ + u8 reserved9[3]; + u8 op1; /* PSC + 0x38 */ + u8 reserved10[3]; + u8 op0; /* PSC + 0x3c */ + u8 reserved11[3]; + u32 sicr; /* PSC + 0x40 */ + u8 ircr1; /* PSC + 0x44 */ + u8 reserved13[3]; + u8 ircr2; /* PSC + 0x44 */ + u8 reserved14[3]; + u8 irsdr; /* PSC + 0x4c */ + u8 reserved15[3]; + u8 irmdr; /* PSC + 0x50 */ + u8 reserved16[3]; + u8 irfdr; /* PSC + 0x54 */ + u8 reserved17[3]; + u16 rfnum; /* PSC + 0x58 */ + u16 reserved18; + u16 tfnum; /* PSC + 0x5c */ + u16 reserved19; + u32 rfdata; /* PSC + 0x60 */ + u16 rfstat; /* PSC + 0x64 */ + u16 reserved20; + u8 rfcntl; /* PSC + 0x68 */ + u8 reserved21[5]; + u16 rfalarm; /* PSC + 0x6e */ + u16 reserved22; + u16 rfrptr; /* PSC + 0x72 */ + u16 reserved23; + u16 rfwptr; /* PSC + 0x76 */ + u16 reserved24; + u16 rflrfptr; /* PSC + 0x7a */ + u16 reserved25; + u16 rflwfptr; /* PSC + 0x7e */ + u32 tfdata; /* PSC + 0x80 */ + u16 tfstat; /* PSC + 0x84 */ + u16 reserved26; + u8 tfcntl; /* PSC + 0x88 */ + u8 reserved27[5]; + u16 tfalarm; /* PSC + 0x8e */ + u16 reserved28; + u16 tfrptr; /* PSC + 0x92 */ + u16 reserved29; + u16 tfwptr; /* PSC + 0x96 */ + u16 reserved30; + u16 tflrfptr; /* PSC + 0x9a */ + u16 reserved31; + u16 tflwfptr; /* PSC + 0x9e */ +}; + + +#endif /* __ASM_MPC52xx_PSC_H__ */ diff --git a/include/asm-ppc/ans-lcd.h b/include/asm-ppc/ans-lcd.h deleted file mode 100644 index d795b9fd2db..00000000000 --- a/include/asm-ppc/ans-lcd.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef _PPC_ANS_LCD_H -#define _PPC_ANS_LCD_H - -#define ANSLCD_MINOR 156 - -#define ANSLCD_CLEAR 0x01 -#define ANSLCD_SENDCTRL 0x02 -#define ANSLCD_SETSHORTDELAY 0x03 -#define ANSLCD_SETLONGDELAY 0x04 - -#endif -- cgit v1.2.3-70-g09d2 From 2099172d61abda1b793b499bb8edcaac4de2cdae Mon Sep 17 00:00:00 2001 From: David Gibson Date: Fri, 7 Sep 2007 13:23:53 +1000 Subject: [POWERPC] Document and implement an improved flash device binding for powerpc This replaces the binding for flash chips in booting-without-of.txt with an clarified and improved version. It also makes drivers/mtd/maps/physmap_of.c recognize this new binding. Finally it revises the Ebony device tree source to use the new binding as an example. Signed-off-by: David Gibson Acked-by: Segher Boessenkool Signed-off-by: Paul Mackerras --- Documentation/powerpc/booting-without-of.txt | 92 +++++++---- arch/powerpc/boot/dts/ebony.dts | 30 ++-- drivers/mtd/maps/physmap_of.c | 239 +++++++++++++++++++-------- 3 files changed, 251 insertions(+), 110 deletions(-) (limited to 'drivers') diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt index 76733a3962f..20e0e6cb034 100644 --- a/Documentation/powerpc/booting-without-of.txt +++ b/Documentation/powerpc/booting-without-of.txt @@ -50,7 +50,7 @@ Table of Contents g) Freescale SOC SEC Security Engines h) Board Control and Status (BCSR) i) Freescale QUICC Engine module (QE) - j) Flash chip nodes + j) CFI or JEDEC memory-mapped NOR flash k) Global Utilities Block VII - Specifying interrupt information for devices @@ -1757,45 +1757,69 @@ platforms are moved over to use the flattened-device-tree model. }; }; - j) Flash chip nodes + j) CFI or JEDEC memory-mapped NOR flash Flash chips (Memory Technology Devices) are often used for solid state file systems on embedded devices. - Required properties: + - compatible : should contain the specific model of flash chip(s) + used, if known, followed by either "cfi-flash" or "jedec-flash" + - reg : Address range of the flash chip + - bank-width : Width (in bytes) of the flash bank. Equal to the + device width times the number of interleaved chips. + - device-width : (optional) Width of a single flash chip. If + omitted, assumed to be equal to 'bank-width'. + - #address-cells, #size-cells : Must be present if the flash has + sub-nodes representing partitions (see below). In this case + both #address-cells and #size-cells must be equal to 1. + + For JEDEC compatible devices, the following additional properties + are defined: + + - vendor-id : Contains the flash chip's vendor id (1 byte). + - device-id : Contains the flash chip's device id (1 byte). + + In addition to the information on the flash bank itself, the + device tree may optionally contain additional information + describing partitions of the flash address space. This can be + used on platforms which have strong conventions about which + portions of the flash are used for what purposes, but which don't + use an on-flash partition table such as RedBoot. + + Each partition is represented as a sub-node of the flash device. + Each node's name represents the name of the corresponding + partition of the flash device. + + Flash partitions + - reg : The partition's offset and size within the flash bank. + - label : (optional) The label / name for this flash partition. + If omitted, the label is taken from the node name (excluding + the unit address). + - read-only : (optional) This parameter, if present, is a hint to + Linux that this flash partition should only be mounted + read-only. This is usually used for flash partitions + containing early-boot firmware images or data which should not + be clobbered. - - device_type : has to be "rom" - - compatible : Should specify what this flash device is compatible with. - Currently, this is most likely to be "direct-mapped" (which - corresponds to the MTD physmap mapping driver). - - reg : Offset and length of the register set (or memory mapping) for - the device. - - bank-width : Width of the flash data bus in bytes. Required - for the NOR flashes (compatible == "direct-mapped" and others) ONLY. - - Recommended properties : - - - partitions : Several pairs of 32-bit values where the first value is - partition's offset from the start of the device and the second one is - partition size in bytes with LSB used to signify a read only - partition (so, the partition size should always be an even number). - - partition-names : The list of concatenated zero terminated strings - representing the partition names. - - probe-type : The type of probe which should be done for the chip - (JEDEC vs CFI actually). Valid ONLY for NOR flashes. - - Example: + Example: - flash@ff000000 { - device_type = "rom"; - compatible = "direct-mapped"; - probe-type = "CFI"; - reg = ; - bank-width = <4>; - partitions = <00000000 00f80000 - 00f80000 00080001>; - partition-names = "fs\0firmware"; - }; + flash@ff000000 { + compatible = "amd,am29lv128ml", "cfi-flash"; + reg = ; + bank-width = <4>; + device-width = <1>; + #address-cells = <1>; + #size-cells = <1>; + fs@0 { + label = "fs"; + reg = <0 f80000>; + }; + firmware@f80000 { + label ="firmware"; + reg = ; + read-only; + }; + }; k) Global Utilities Block diff --git a/arch/powerpc/boot/dts/ebony.dts b/arch/powerpc/boot/dts/ebony.dts index 37599bda550..bc259972aaa 100644 --- a/arch/powerpc/boot/dts/ebony.dts +++ b/arch/powerpc/boot/dts/ebony.dts @@ -138,13 +138,16 @@ interrupt-parent = <&UIC1>; small-flash@0,80000 { - device_type = "rom"; - compatible = "direct-mapped"; - probe-type = "JEDEC"; + compatible = "jedec-flash"; bank-width = <1>; - partitions = <0 80000>; - partition-names = "OpenBIOS"; reg = <0 80000 80000>; + #address-cells = <1>; + #size-cells = <1>; + partition@0 { + label = "OpenBIOS"; + reg = <0 80000>; + read-only; + }; }; ds1743@1,0 { @@ -154,14 +157,19 @@ }; large-flash@2,0 { - device_type = "rom"; - compatible = "direct-mapped"; - probe-type = "JEDEC"; + compatible = "jedec-flash"; bank-width = <1>; - partitions = <0 380000 - 380000 80000>; - partition-names = "fs", "firmware"; reg = <2 0 400000>; + #address-cells = <1>; + #size-cells = <1>; + partition@0 { + label = "fs"; + reg = <0 380000>; + }; + partition@380000 { + label = "firmware"; + reg = <380000 80000>; + }; }; ir@3,0 { diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c index bbb42c35b69..3df001bfee3 100644 --- a/drivers/mtd/maps/physmap_of.c +++ b/drivers/mtd/maps/physmap_of.c @@ -4,6 +4,9 @@ * Copyright (C) 2006 MontaVista Software Inc. * Author: Vitaly Wool * + * Revised to handle newer style flash binding by: + * Copyright (C) 2007 David Gibson, IBM Corporation. + * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your @@ -30,56 +33,135 @@ struct physmap_flash_info { struct map_info map; struct resource *res; #ifdef CONFIG_MTD_PARTITIONS - int nr_parts; struct mtd_partition *parts; #endif }; -static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", NULL }; -#ifdef CONFIG_MTD_PARTITIONS -static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL }; -#endif - #ifdef CONFIG_MTD_PARTITIONS -static int parse_flash_partitions(struct device_node *node, - struct mtd_partition **parts) +static int parse_obsolete_partitions(struct of_device *dev, + struct physmap_flash_info *info, + struct device_node *dp) { - int i, plen, retval = -ENOMEM; - const u32 *part; - const char *name; + int i, plen, nr_parts; + const struct { + u32 offset, len; + } *part; + const char *names; - part = of_get_property(node, "partitions", &plen); - if (part == NULL) - goto err; + part = of_get_property(dp, "partitions", &plen); + if (!part) + return -ENOENT; - retval = plen / (2 * sizeof(u32)); - *parts = kzalloc(retval * sizeof(struct mtd_partition), GFP_KERNEL); - if (*parts == NULL) { + dev_warn(&dev->dev, "Device tree uses obsolete partition map binding\n"); + + nr_parts = plen / sizeof(part[0]); + + info->parts = kzalloc(nr_parts * sizeof(struct mtd_partition), GFP_KERNEL); + if (!info->parts) { printk(KERN_ERR "Can't allocate the flash partition data!\n"); - goto err; + return -ENOMEM; } - name = of_get_property(node, "partition-names", &plen); + names = of_get_property(dp, "partition-names", &plen); - for (i = 0; i < retval; i++) { - (*parts)[i].offset = *part++; - (*parts)[i].size = *part & ~1; - if (*part++ & 1) /* bit 0 set signifies read only partition */ - (*parts)[i].mask_flags = MTD_WRITEABLE; + for (i = 0; i < nr_parts; i++) { + info->parts[i].offset = part->offset; + info->parts[i].size = part->len & ~1; + if (part->len & 1) /* bit 0 set signifies read only partition */ + info->parts[i].mask_flags = MTD_WRITEABLE; - if (name != NULL && plen > 0) { - int len = strlen(name) + 1; + if (names && (plen > 0)) { + int len = strlen(names) + 1; - (*parts)[i].name = (char *)name; + info->parts[i].name = (char *)names; plen -= len; - name += len; - } else - (*parts)[i].name = "unnamed"; + names += len; + } else { + info->parts[i].name = "unnamed"; + } + + part++; } -err: - return retval; + + return nr_parts; } -#endif + +static int __devinit process_partitions(struct physmap_flash_info *info, + struct of_device *dev) +{ + const char *partname; + static const char *part_probe_types[] + = { "cmdlinepart", "RedBoot", NULL }; + struct device_node *dp = dev->node, *pp; + int nr_parts, i; + + /* First look for RedBoot table or partitions on the command + * line, these take precedence over device tree information */ + nr_parts = parse_mtd_partitions(info->mtd, part_probe_types, + &info->parts, 0); + if (nr_parts > 0) { + add_mtd_partitions(info->mtd, info->parts, nr_parts); + return 0; + } + + /* First count the subnodes */ + nr_parts = 0; + for (pp = dp->child; pp; pp = pp->sibling) + nr_parts++; + + if (nr_parts) { + info->parts = kzalloc(nr_parts * sizeof(struct mtd_partition), + GFP_KERNEL); + if (!info->parts) { + printk(KERN_ERR "Can't allocate the flash partition data!\n"); + return -ENOMEM; + } + + for (pp = dp->child, i = 0 ; pp; pp = pp->sibling, i++) { + const u32 *reg; + int len; + + reg = of_get_property(pp, "reg", &len); + if (!reg || (len != 2*sizeof(u32))) { + dev_err(&dev->dev, "Invalid 'reg' on %s\n", + dp->full_name); + kfree(info->parts); + info->parts = NULL; + return -EINVAL; + } + info->parts[i].offset = reg[0]; + info->parts[i].size = reg[1]; + + partname = of_get_property(pp, "label", &len); + if (!partname) + partname = of_get_property(pp, "name", &len); + info->parts[i].name = (char *)partname; + + if (of_get_property(pp, "read-only", &len)) + info->parts[i].mask_flags = MTD_WRITEABLE; + } + } else { + nr_parts = parse_obsolete_partitions(dev, info, dp); + } + + if (nr_parts < 0) + return nr_parts; + + if (nr_parts > 0) + add_mtd_partitions(info->mtd, info->parts, nr_parts); + else + add_mtd_device(info->mtd); + + return 0; +} +#else /* MTD_PARTITIONS */ +static int __devinit process_partitions(struct physmap_flash_info *info, + struct device_node *dev) +{ + add_mtd_device(info->mtd); + return 0; +} +#endif /* MTD_PARTITIONS */ static int of_physmap_remove(struct of_device *dev) { @@ -92,7 +174,7 @@ static int of_physmap_remove(struct of_device *dev) if (info->mtd != NULL) { #ifdef CONFIG_MTD_PARTITIONS - if (info->nr_parts) { + if (info->parts) { del_mtd_partitions(info->mtd); kfree(info->parts); } else { @@ -115,17 +197,51 @@ static int of_physmap_remove(struct of_device *dev) return 0; } +/* Helper function to handle probing of the obsolete "direct-mapped" + * compatible binding, which has an extra "probe-type" property + * describing the type of flash probe necessary. */ +static struct mtd_info * __devinit obsolete_probe(struct of_device *dev, + struct map_info *map) +{ + struct device_node *dp = dev->node; + const char *of_probe; + struct mtd_info *mtd; + static const char *rom_probe_types[] + = { "cfi_probe", "jedec_probe", "map_rom"}; + int i; + + dev_warn(&dev->dev, "Device tree uses obsolete \"direct-mapped\" " + "flash binding\n"); + + of_probe = of_get_property(dp, "probe-type", NULL); + if (!of_probe) { + for (i = 0; i < ARRAY_SIZE(rom_probe_types); i++) { + mtd = do_map_probe(rom_probe_types[i], map); + if (mtd) + return mtd; + } + return NULL; + } else if (strcmp(of_probe, "CFI") == 0) { + return do_map_probe("cfi_probe", map); + } else if (strcmp(of_probe, "JEDEC") == 0) { + return do_map_probe("jedec_probe", map); + } else { + if (strcmp(of_probe, "ROM") != 0) + dev_dbg(&dev->dev, "obsolete_probe: don't know probe type " + "'%s', mapping as rom\n", of_probe); + return do_map_probe("mtd_rom", map); + } +} + static int __devinit of_physmap_probe(struct of_device *dev, const struct of_device_id *match) { struct device_node *dp = dev->node; struct resource res; struct physmap_flash_info *info; - const char **probe_type; - const char *of_probe; + const char *probe_type = (const char *)match->data; const u32 *width; int err; - if (of_address_to_resource(dp, 0, &res)) { dev_err(&dev->dev, "Can't get the flash mapping!\n"); err = -EINVAL; @@ -174,21 +290,11 @@ static int __devinit of_physmap_probe(struct of_device *dev, const struct of_dev simple_map_init(&info->map); - of_probe = of_get_property(dp, "probe-type", NULL); - if (of_probe == NULL) { - probe_type = rom_probe_types; - for (; info->mtd == NULL && *probe_type != NULL; probe_type++) - info->mtd = do_map_probe(*probe_type, &info->map); - } else if (!strcmp(of_probe, "CFI")) - info->mtd = do_map_probe("cfi_probe", &info->map); - else if (!strcmp(of_probe, "JEDEC")) - info->mtd = do_map_probe("jedec_probe", &info->map); - else { - if (strcmp(of_probe, "ROM")) - dev_dbg(&dev->dev, "map_probe: don't know probe type " - "'%s', mapping as rom\n", of_probe); - info->mtd = do_map_probe("mtd_rom", &info->map); - } + if (probe_type) + info->mtd = do_map_probe(probe_type, &info->map); + else + info->mtd = obsolete_probe(dev, &info->map); + if (info->mtd == NULL) { dev_err(&dev->dev, "map_probe failed\n"); err = -ENXIO; @@ -196,19 +302,7 @@ static int __devinit of_physmap_probe(struct of_device *dev, const struct of_dev } info->mtd->owner = THIS_MODULE; -#ifdef CONFIG_MTD_PARTITIONS - err = parse_mtd_partitions(info->mtd, part_probe_types, &info->parts, 0); - if (err > 0) { - add_mtd_partitions(info->mtd, info->parts, err); - } else if ((err = parse_flash_partitions(dp, &info->parts)) > 0) { - dev_info(&dev->dev, "Using OF partition information\n"); - add_mtd_partitions(info->mtd, info->parts, err); - info->nr_parts = err; - } else -#endif - - add_mtd_device(info->mtd); - return 0; + return process_partitions(info, dev); err_out: of_physmap_remove(dev); @@ -220,6 +314,21 @@ err_out: } static struct of_device_id of_physmap_match[] = { + { + .compatible = "cfi-flash", + .data = (void *)"cfi_probe", + }, + { + /* FIXME: JEDEC chips can't be safely and reliably + * probed, although the mtd code gets it right in + * practice most of the time. We should use the + * vendor and device ids specified by the binding to + * bypass the heuristic probe code, but the mtd layer + * provides, at present, no interface for doing so + * :(. */ + .compatible = "jedec-flash", + .data = (void *)"jedec_probe", + }, { .type = "rom", .compatible = "direct-mapped" -- cgit v1.2.3-70-g09d2 From 89a300e85b646dd08343264f025f4f412d552bfd Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Wed, 22 Aug 2007 21:49:01 -0500 Subject: ucc_geth: kill unused include The ucc_geth_mii code is based on the gianfar_mii code that use to include ocp.h. ucc never need this and it causes issues when we want to kill arch/ppc includes from arch/powerpc. Signed-off-by: Kumar Gala --- drivers/net/ucc_geth_mii.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ucc_geth_mii.c b/drivers/net/ucc_geth_mii.c index 6c257b88ce5..df884f0ad8e 100644 --- a/drivers/net/ucc_geth_mii.c +++ b/drivers/net/ucc_geth_mii.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3-70-g09d2 From af6a9aabc106b70ab03d6665c713bca3dd3cb195 Mon Sep 17 00:00:00 2001 From: John Rigby Date: Wed, 23 May 2007 11:30:55 -0600 Subject: [POWERPC] 52xx: Fix mpc52xx_uart_of_assign to use correct index Use idx as index into mpc52xx_uart_nodes instead of i Signed-off-by: John Rigby Signed-off-by: Kumar Gala --- drivers/serial/mpc52xx_uart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c index 35f8b86cc78..035cca02819 100644 --- a/drivers/serial/mpc52xx_uart.c +++ b/drivers/serial/mpc52xx_uart.c @@ -1051,7 +1051,7 @@ mpc52xx_uart_of_assign(struct device_node *np, int idx) /* If the slot is already occupied, then swap slots */ if (mpc52xx_uart_nodes[idx] && (free_idx != -1)) mpc52xx_uart_nodes[free_idx] = mpc52xx_uart_nodes[idx]; - mpc52xx_uart_nodes[i] = np; + mpc52xx_uart_nodes[idx] = np; } static void -- cgit v1.2.3-70-g09d2 From aa0154290fc05948560ac43afcccf8259e10bcd0 Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Sun, 26 Aug 2007 19:10:59 +1000 Subject: [POWERPC] Fix pmac_zilog debug arg drivers/serial/pmac_zilog.c:1590: warning: format '%d' expects type 'int', but argument 3 has type 'pm_message_t' Signed-off-by: Olaf Hering Signed-off-by: Paul Mackerras --- drivers/serial/pmac_zilog.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c index 0fa9f676176..f793ac21267 100644 --- a/drivers/serial/pmac_zilog.c +++ b/drivers/serial/pmac_zilog.c @@ -1587,7 +1587,7 @@ static int pmz_suspend(struct macio_dev *mdev, pm_message_t pm_state) if (pm_state.event == mdev->ofdev.dev.power.power_state.event) return 0; - pmz_debug("suspend, switching to state %d\n", pm_state); + pmz_debug("suspend, switching to state %d\n", pm_state.event); state = pmz_uart_reg.state + uap->port.line; -- cgit v1.2.3-70-g09d2 From 8d9ae994d8fce807fc90fb8e3b6ac8df1cc7dce6 Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Sat, 15 Sep 2007 04:54:12 +1000 Subject: [POWERPC] Make partitions optional in physmap_of The latest physmap_of driver has a small error where it will fail the probe with: physmap-flash: probe of fff00000.small-flas failed with error -2 if there are no partition subnodes in the device tree and the old style binding is not used. Since partition definitions are optional, the probe should still succeed. Signed-off-by: Josh Boyer Acked-by: David Gibson --- drivers/mtd/maps/physmap_of.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c index 3df001bfee3..096dd47b5d5 100644 --- a/drivers/mtd/maps/physmap_of.c +++ b/drivers/mtd/maps/physmap_of.c @@ -142,6 +142,8 @@ static int __devinit process_partitions(struct physmap_flash_info *info, } } else { nr_parts = parse_obsolete_partitions(dev, info, dp); + if (nr_parts == -ENOENT) + nr_parts = 0; } if (nr_parts < 0) -- cgit v1.2.3-70-g09d2 From c4d5e375470862fd741f93bf0686d7ac2f7fdce4 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 20 Sep 2007 11:22:25 +1000 Subject: [POWERPC] Cleanups for physmap_of.c (v2) This patch includes a whole batch of smallish cleanups for drivers/mtd/physmap_of.c. - A bunch of uneeded #includes are removed - We switch to the modern linux/of.h etc. in place of asm/prom.h - Use some helper macros to avoid some ugly inline #ifdefs - A few lines of unreachable code are removed - A number of indentation / line-wrapping fixes - More consistent use of kernel idioms such as if (!p) instead of if (p == NULL) - Clarify some printk()s and other informative strings. - parse_obsolete_partitions() now returns 0 if no partition information is found, instead of returning -ENOENT which the caller had to handle specially. - (the big one) Despite the name, this driver really has nothing to do with drivers/mtd/physmap.c. The fact that the flash chips must be physically direct mapped is a constrant, but doesn't really say anything about the actual purpose of this driver, which is to instantiate MTD devices based on information from the device tree. Therefore the physmap name is replaced everywhere within the file with "of_flash". The file itself and the Kconfig option is not renamed for now (so that the diff is actually a diff). That can come later. Signed-off-by: David Gibson Signed-off-by: Josh Boyer --- drivers/mtd/maps/physmap_of.c | 224 +++++++++++++++++++----------------------- 1 file changed, 99 insertions(+), 125 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c index 096dd47b5d5..cf75a566442 100644 --- a/drivers/mtd/maps/physmap_of.c +++ b/drivers/mtd/maps/physmap_of.c @@ -1,5 +1,5 @@ /* - * Normal mappings of chips in physical memory for OF devices + * Flash mappings described by the OF (or flattened) device tree * * Copyright (C) 2006 MontaVista Software Inc. * Author: Vitaly Wool @@ -15,20 +15,15 @@ #include #include -#include #include -#include #include #include #include #include -#include -#include -#include -#include -#include +#include +#include -struct physmap_flash_info { +struct of_flash { struct mtd_info *mtd; struct map_info map; struct resource *res; @@ -38,8 +33,10 @@ struct physmap_flash_info { }; #ifdef CONFIG_MTD_PARTITIONS +#define OF_FLASH_PARTS(info) ((info)->parts) + static int parse_obsolete_partitions(struct of_device *dev, - struct physmap_flash_info *info, + struct of_flash *info, struct device_node *dp) { int i, plen, nr_parts; @@ -50,17 +47,15 @@ static int parse_obsolete_partitions(struct of_device *dev, part = of_get_property(dp, "partitions", &plen); if (!part) - return -ENOENT; + return 0; /* No partitions found */ dev_warn(&dev->dev, "Device tree uses obsolete partition map binding\n"); nr_parts = plen / sizeof(part[0]); - info->parts = kzalloc(nr_parts * sizeof(struct mtd_partition), GFP_KERNEL); - if (!info->parts) { - printk(KERN_ERR "Can't allocate the flash partition data!\n"); + info->parts = kzalloc(nr_parts * sizeof(*info->parts), GFP_KERNEL); + if (!info->parts) return -ENOMEM; - } names = of_get_property(dp, "partition-names", &plen); @@ -86,8 +81,8 @@ static int parse_obsolete_partitions(struct of_device *dev, return nr_parts; } -static int __devinit process_partitions(struct physmap_flash_info *info, - struct of_device *dev) +static int __devinit parse_partitions(struct of_flash *info, + struct of_device *dev) { const char *partname; static const char *part_probe_types[] @@ -109,89 +104,68 @@ static int __devinit process_partitions(struct physmap_flash_info *info, for (pp = dp->child; pp; pp = pp->sibling) nr_parts++; - if (nr_parts) { - info->parts = kzalloc(nr_parts * sizeof(struct mtd_partition), - GFP_KERNEL); - if (!info->parts) { - printk(KERN_ERR "Can't allocate the flash partition data!\n"); - return -ENOMEM; - } + if (nr_parts == 0) + return parse_obsolete_partitions(dev, info, dp); + + info->parts = kzalloc(nr_parts * sizeof(*info->parts), + GFP_KERNEL); + if (!info->parts) + return -ENOMEM; - for (pp = dp->child, i = 0 ; pp; pp = pp->sibling, i++) { - const u32 *reg; - int len; - - reg = of_get_property(pp, "reg", &len); - if (!reg || (len != 2*sizeof(u32))) { - dev_err(&dev->dev, "Invalid 'reg' on %s\n", - dp->full_name); - kfree(info->parts); - info->parts = NULL; - return -EINVAL; - } - info->parts[i].offset = reg[0]; - info->parts[i].size = reg[1]; - - partname = of_get_property(pp, "label", &len); - if (!partname) - partname = of_get_property(pp, "name", &len); - info->parts[i].name = (char *)partname; - - if (of_get_property(pp, "read-only", &len)) - info->parts[i].mask_flags = MTD_WRITEABLE; + for (pp = dp->child, i = 0; pp; pp = pp->sibling, i++) { + const u32 *reg; + int len; + + reg = of_get_property(pp, "reg", &len); + if (!reg || (len != 2*sizeof(u32))) { + dev_err(&dev->dev, "Invalid 'reg' on %s\n", + dp->full_name); + kfree(info->parts); + info->parts = NULL; + return -EINVAL; } - } else { - nr_parts = parse_obsolete_partitions(dev, info, dp); - if (nr_parts == -ENOENT) - nr_parts = 0; - } + info->parts[i].offset = reg[0]; + info->parts[i].size = reg[1]; - if (nr_parts < 0) - return nr_parts; + partname = of_get_property(pp, "label", &len); + if (!partname) + partname = of_get_property(pp, "name", &len); + info->parts[i].name = (char *)partname; - if (nr_parts > 0) - add_mtd_partitions(info->mtd, info->parts, nr_parts); - else - add_mtd_device(info->mtd); + if (of_get_property(pp, "read-only", &len)) + info->parts[i].mask_flags = MTD_WRITEABLE; + } - return 0; + return nr_parts; } #else /* MTD_PARTITIONS */ -static int __devinit process_partitions(struct physmap_flash_info *info, - struct device_node *dev) -{ - add_mtd_device(info->mtd); - return 0; -} +#define OF_FLASH_PARTS(info) (0) +#define parse_partitions(info, dev) (0) #endif /* MTD_PARTITIONS */ -static int of_physmap_remove(struct of_device *dev) +static int of_flash_remove(struct of_device *dev) { - struct physmap_flash_info *info; + struct of_flash *info; info = dev_get_drvdata(&dev->dev); - if (info == NULL) + if (!info) return 0; dev_set_drvdata(&dev->dev, NULL); - if (info->mtd != NULL) { -#ifdef CONFIG_MTD_PARTITIONS - if (info->parts) { + if (info->mtd) { + if (OF_FLASH_PARTS(info)) { del_mtd_partitions(info->mtd); - kfree(info->parts); + kfree(OF_FLASH_PARTS(info)); } else { del_mtd_device(info->mtd); } -#else - del_mtd_device(info->mtd); -#endif map_destroy(info->mtd); } - if (info->map.virt != NULL) + if (info->map.virt) iounmap(info->map.virt); - if (info->res != NULL) { + if (info->res) { release_resource(info->res); kfree(info->res); } @@ -229,52 +203,49 @@ static struct mtd_info * __devinit obsolete_probe(struct of_device *dev, return do_map_probe("jedec_probe", map); } else { if (strcmp(of_probe, "ROM") != 0) - dev_dbg(&dev->dev, "obsolete_probe: don't know probe type " - "'%s', mapping as rom\n", of_probe); + dev_warn(&dev->dev, "obsolete_probe: don't know probe " + "type '%s', mapping as rom\n", of_probe); return do_map_probe("mtd_rom", map); } } -static int __devinit of_physmap_probe(struct of_device *dev, const struct of_device_id *match) +static int __devinit of_flash_probe(struct of_device *dev, + const struct of_device_id *match) { struct device_node *dp = dev->node; struct resource res; - struct physmap_flash_info *info; - const char *probe_type = (const char *)match->data; + struct of_flash *info; + const char *probe_type = match->data; const u32 *width; int err; + err = -ENXIO; if (of_address_to_resource(dp, 0, &res)) { - dev_err(&dev->dev, "Can't get the flash mapping!\n"); - err = -EINVAL; + dev_err(&dev->dev, "Can't get IO address from device tree\n"); goto err_out; } - dev_dbg(&dev->dev, "physmap flash device: %.8llx at %.8llx\n", - (unsigned long long)res.end - res.start + 1, - (unsigned long long)res.start); + dev_dbg(&dev->dev, "of_flash device: %.8llx-%.8llx\n", + (unsigned long long)res.start, (unsigned long long)res.end); - info = kzalloc(sizeof(struct physmap_flash_info), GFP_KERNEL); - if (info == NULL) { - err = -ENOMEM; + err = -ENOMEM; + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) goto err_out; - } memset(info, 0, sizeof(*info)); dev_set_drvdata(&dev->dev, info); + err = -EBUSY; info->res = request_mem_region(res.start, res.end - res.start + 1, - dev->dev.bus_id); - if (info->res == NULL) { - dev_err(&dev->dev, "Could not reserve memory region\n"); - err = -ENOMEM; + dev->dev.bus_id); + if (!info->res) goto err_out; - } + err = -ENXIO; width = of_get_property(dp, "bank-width", NULL); - if (width == NULL) { - dev_err(&dev->dev, "Can't get the flash bank width!\n"); - err = -EINVAL; + if (!width) { + dev_err(&dev->dev, "Can't get bank width from device tree\n"); goto err_out; } @@ -283,10 +254,10 @@ static int __devinit of_physmap_probe(struct of_device *dev, const struct of_dev info->map.size = res.end - res.start + 1; info->map.bankwidth = *width; + err = -ENOMEM; info->map.virt = ioremap(info->map.phys, info->map.size); - if (info->map.virt == NULL) { - dev_err(&dev->dev, "Failed to ioremap flash region\n"); - err = EIO; + if (!info->map.virt) { + dev_err(&dev->dev, "Failed to ioremap() flash region\n"); goto err_out; } @@ -297,25 +268,30 @@ static int __devinit of_physmap_probe(struct of_device *dev, const struct of_dev else info->mtd = obsolete_probe(dev, &info->map); - if (info->mtd == NULL) { - dev_err(&dev->dev, "map_probe failed\n"); - err = -ENXIO; + err = -ENXIO; + if (!info->mtd) { + dev_err(&dev->dev, "do_map_probe() failed\n"); goto err_out; } info->mtd->owner = THIS_MODULE; - return process_partitions(info, dev); + err = parse_partitions(info, dev); + if (err < 0) + goto err_out; -err_out: - of_physmap_remove(dev); - return err; + if (err > 0) + add_mtd_partitions(info->mtd, OF_FLASH_PARTS(info), err); + else + add_mtd_device(info->mtd); return 0; - +err_out: + of_flash_remove(dev); + return err; } -static struct of_device_id of_physmap_match[] = { +static struct of_device_id of_flash_match[] = { { .compatible = "cfi-flash", .data = (void *)"cfi_probe", @@ -337,30 +313,28 @@ static struct of_device_id of_physmap_match[] = { }, { }, }; +MODULE_DEVICE_TABLE(of, of_flash_match); -MODULE_DEVICE_TABLE(of, of_physmap_match); - - -static struct of_platform_driver of_physmap_flash_driver = { - .name = "physmap-flash", - .match_table = of_physmap_match, - .probe = of_physmap_probe, - .remove = of_physmap_remove, +static struct of_platform_driver of_flash_driver = { + .name = "of-flash", + .match_table = of_flash_match, + .probe = of_flash_probe, + .remove = of_flash_remove, }; -static int __init of_physmap_init(void) +static int __init of_flash_init(void) { - return of_register_platform_driver(&of_physmap_flash_driver); + return of_register_platform_driver(&of_flash_driver); } -static void __exit of_physmap_exit(void) +static void __exit of_flash_exit(void) { - of_unregister_platform_driver(&of_physmap_flash_driver); + of_unregister_platform_driver(&of_flash_driver); } -module_init(of_physmap_init); -module_exit(of_physmap_exit); +module_init(of_flash_init); +module_exit(of_flash_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Vitaly Wool "); -MODULE_DESCRIPTION("Configurable MTD map driver for OF"); +MODULE_DESCRIPTION("Device tree based MTD map driver"); -- cgit v1.2.3-70-g09d2 From e4533b243e5e0c3a26287a902a1ed0f8f5b1cec0 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Thu, 5 Apr 2007 00:19:43 +1000 Subject: [POWERPC] Optionally use new device number for pmac_zilog This adds the option for the pmac_zilog driver to use the major/minor numbers recently allocated specifically for it (/dev/ttyPZn) instead of the /dev/ttySn numbers. The advantage of doing this is that it allows the pmac_zilog and 8250 drivers to coexist. The disadvantage of doing this is that it is a user-visible ABI change and it will break existing working setups on powermacs, and could be confusing to users. Signed-off-by: David Woodhouse Signed-off-by: Paul Mackerras --- drivers/serial/Kconfig | 25 +++++++++++++++++++++++++ drivers/serial/pmac_zilog.c | 20 +++++++++++++++----- 2 files changed, 40 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 81b52b7cca2..d6ae38e55d0 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -986,6 +986,31 @@ config SERIAL_PMACZILOG PowerMac machines. Say Y or M if you want to be able to these serial ports. +config SERIAL_PMACZILOG_TTYS + bool "Use ttySn device nodes for Zilog z85c30" + depends on SERIAL_PMACZILOG + help + The pmac_zilog driver for the z85C30 chip on many powermacs + historically used the device numbers for /dev/ttySn. The + 8250 serial port driver also uses these numbers, which means + the two drivers being unable to coexist; you could not use + both z85C30 and 8250 type ports at the same time. + + If this option is not selected, the pmac_zilog driver will + use the device numbers allocated for /dev/ttyPZn. This allows + the pmac_zilog and 8250 drivers to co-exist, but may cause + existing userspace setups to break. Programs that need to + access the built-in serial ports on powermacs will need to + be reconfigured to use /dev/ttyPZn instead of /dev/ttySn. + + If you enable this option, any z85c30 ports in the system will + be registered as ttyS0 onwards as in the past, and you will be + unable to use the 8250 module for PCMCIA or other 16C550-style + UARTs. + + Say N unless you need the z85c30 ports on your powermac + to appear as /dev/ttySn. + config SERIAL_PMACZILOG_CONSOLE bool "Console on PowerMac z85c30 serial port" depends on SERIAL_PMACZILOG=y diff --git a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c index f793ac21267..794bd0f50d7 100644 --- a/drivers/serial/pmac_zilog.c +++ b/drivers/serial/pmac_zilog.c @@ -88,6 +88,16 @@ MODULE_LICENSE("GPL"); #define PWRDBG(fmt, arg...) printk(KERN_DEBUG fmt , ## arg) +#ifdef CONFIG_SERIAL_PMACZILOG_TTYS +#define PMACZILOG_MAJOR TTY_MAJOR +#define PMACZILOG_MINOR 64 +#define PMACZILOG_NAME "ttyS" +#else +#define PMACZILOG_MAJOR 204 +#define PMACZILOG_MINOR 192 +#define PMACZILOG_NAME "ttyPZ" +#endif + /* * For the sake of early serial console, we can do a pre-probe @@ -99,9 +109,10 @@ static DEFINE_MUTEX(pmz_irq_mutex); static struct uart_driver pmz_uart_reg = { .owner = THIS_MODULE, - .driver_name = "ttyS", - .dev_name = "ttyS", - .major = TTY_MAJOR, + .driver_name = PMACZILOG_NAME, + .dev_name = PMACZILOG_NAME, + .major = PMACZILOG_MAJOR, + .minor = PMACZILOG_MINOR, }; @@ -1778,7 +1789,7 @@ static void pmz_console_write(struct console *con, const char *s, unsigned int c static int __init pmz_console_setup(struct console *co, char *options); static struct console pmz_console = { - .name = "ttyS", + .name = PMACZILOG_NAME, .write = pmz_console_write, .device = uart_console_device, .setup = pmz_console_setup, @@ -1802,7 +1813,6 @@ static int __init pmz_register(void) pmz_uart_reg.nr = pmz_ports_count; pmz_uart_reg.cons = PMACZILOG_CONSOLE; - pmz_uart_reg.minor = 64; /* * Register this driver with the serial core -- cgit v1.2.3-70-g09d2 From 555ddbb4e2191c8823df2d61525218ac39481385 Mon Sep 17 00:00:00 2001 From: Aristeu Rozanski Date: Tue, 17 Jul 2007 06:53:09 +1000 Subject: [POWERPC] adbhid: Enable KEY_FN key reporting When a Fn key is used in combination with another key in ADB keyboards it will generate a Fn event and then a second event that can be a different key than pressed (Fn + F1 for instance can generate Fn + brightness down if it's configured like that). This enables the reporting of the Fn key to the input system. As Fn is a dead key for most purposes, it's useful to report it so applications can make use of it. One example is apple_mouse (https://jake.ruivo.org/uinputd/trunk/apple_mouse/) that emulates the second and third keys using a combination of keyboard keys and the mouse button. Other applications may use the KEY_FN as a modifier as well. I've been updating and using this patch for months without problems. Signed-off-by: Aristeu Rozanski Acked-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- drivers/macintosh/adbhid.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c index b46817f699f..48d17bf6c92 100644 --- a/drivers/macintosh/adbhid.c +++ b/drivers/macintosh/adbhid.c @@ -70,7 +70,7 @@ static struct notifier_block adbhid_adb_notifier = { #define ADB_KEY_POWER_OLD 0x7e #define ADB_KEY_POWER 0x7f -u8 adb_to_linux_keycodes[128] = { +u16 adb_to_linux_keycodes[128] = { /* 0x00 */ KEY_A, /* 30 */ /* 0x01 */ KEY_S, /* 31 */ /* 0x02 */ KEY_D, /* 32 */ @@ -134,7 +134,7 @@ u8 adb_to_linux_keycodes[128] = { /* 0x3c */ KEY_RIGHT, /* 106 */ /* 0x3d */ KEY_DOWN, /* 108 */ /* 0x3e */ KEY_UP, /* 103 */ - /* 0x3f */ 0, + /* 0x3f */ KEY_FN, /* 0x1d0 */ /* 0x40 */ 0, /* 0x41 */ KEY_KPDOT, /* 83 */ /* 0x42 */ 0, @@ -208,7 +208,7 @@ struct adbhid { int original_handler_id; int current_handler_id; int mouse_kind; - unsigned char *keycode; + u16 *keycode; char name[64]; char phys[32]; int flags; @@ -275,7 +275,7 @@ static void adbhid_input_keycode(int id, int keycode, int repeat) { struct adbhid *ahid = adbhid[id]; - int up_flag; + int up_flag, key; up_flag = (keycode & 0x80); keycode &= 0x7f; @@ -321,8 +321,7 @@ adbhid_input_keycode(int id, int keycode, int repeat) } } else ahid->flags |= FLAG_FN_KEY_PRESSED; - /* Swallow the key press */ - return; + break; case ADB_KEY_DEL: /* Emulate Fn+delete = forward delete */ if (ahid->flags & FLAG_FN_KEY_PRESSED) { @@ -336,9 +335,9 @@ adbhid_input_keycode(int id, int keycode, int repeat) #endif /* CONFIG_PPC_PMAC */ } - if (adbhid[id]->keycode[keycode]) { - input_report_key(adbhid[id]->input, - adbhid[id]->keycode[keycode], !up_flag); + key = adbhid[id]->keycode[keycode]; + if (key) { + input_report_key(adbhid[id]->input, key, !up_flag); input_sync(adbhid[id]->input); } else printk(KERN_INFO "Unhandled ADB key (scancode %#02x) %s.\n", keycode, @@ -757,8 +756,8 @@ adbhid_input_register(int id, int default_id, int original_handler_id, input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP); input_dev->ledbit[0] = BIT(LED_SCROLLL) | BIT(LED_CAPSL) | BIT(LED_NUML); input_dev->event = adbhid_kbd_event; - input_dev->keycodemax = 127; - input_dev->keycodesize = 1; + input_dev->keycodemax = KEY_FN; + input_dev->keycodesize = sizeof(hid->keycode[0]); break; case ADB_MOUSE: -- cgit v1.2.3-70-g09d2 From 4c2a54b09ba35a409afc34bd331a57a994921664 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 19 Sep 2007 14:50:22 +1000 Subject: [POWERPC] Fix platinumfb framebuffer Current kernels have a non-working platinumfb due to some resource management issues. This fixes it. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- drivers/video/platinumfb.c | 48 +++++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c index 8503e733a17..cbe71a5338d 100644 --- a/drivers/video/platinumfb.c +++ b/drivers/video/platinumfb.c @@ -17,6 +17,8 @@ * more details. */ +#undef DEBUG + #include #include #include @@ -535,33 +537,35 @@ static int __devinit platinumfb_probe(struct of_device* odev, volatile __u8 *fbuffer; int bank0, bank1, bank2, bank3, rc; - printk(KERN_INFO "platinumfb: Found Apple Platinum video hardware\n"); + dev_info(&odev->dev, "Found Apple Platinum video hardware\n"); info = framebuffer_alloc(sizeof(*pinfo), &odev->dev); - if (info == NULL) + if (info == NULL) { + dev_err(&odev->dev, "Failed to allocate fbdev !\n"); return -ENOMEM; + } pinfo = info->par; if (of_address_to_resource(dp, 0, &pinfo->rsrc_reg) || of_address_to_resource(dp, 1, &pinfo->rsrc_fb)) { - printk(KERN_ERR "platinumfb: Can't get resources\n"); - framebuffer_release(info); - return -ENXIO; - } - if (!request_mem_region(pinfo->rsrc_reg.start, - pinfo->rsrc_reg.start - - pinfo->rsrc_reg.end + 1, - "platinumfb registers")) { + dev_err(&odev->dev, "Can't get resources\n"); framebuffer_release(info); return -ENXIO; } + dev_dbg(&odev->dev, " registers : 0x%llx...0x%llx\n", + (unsigned long long)pinfo->rsrc_reg.start, + (unsigned long long)pinfo->rsrc_reg.end); + dev_dbg(&odev->dev, " framebuffer: 0x%llx...0x%llx\n", + (unsigned long long)pinfo->rsrc_fb.start, + (unsigned long long)pinfo->rsrc_fb.end); + + /* Do not try to request register space, they overlap with the + * northbridge and that can fail. Only request framebuffer + */ if (!request_mem_region(pinfo->rsrc_fb.start, - pinfo->rsrc_fb.start - - pinfo->rsrc_fb.end + 1, + pinfo->rsrc_fb.end - pinfo->rsrc_fb.start + 1, "platinumfb framebuffer")) { - release_mem_region(pinfo->rsrc_reg.start, - pinfo->rsrc_reg.end - - pinfo->rsrc_reg.start + 1); + printk(KERN_ERR "platinumfb: Can't request framebuffer !\n"); framebuffer_release(info); return -ENXIO; } @@ -600,7 +604,8 @@ static int __devinit platinumfb_probe(struct of_device* odev, bank2 = fbuffer[0x200000] == 0x56; bank3 = fbuffer[0x300000] == 0x78; pinfo->total_vram = (bank0 + bank1 + bank2 + bank3) * 0x100000; - printk(KERN_INFO "platinumfb: Total VRAM = %dMB (%d%d%d%d)\n", (int) (pinfo->total_vram / 1024 / 1024), + printk(KERN_INFO "platinumfb: Total VRAM = %dMB (%d%d%d%d)\n", + (unsigned int) (pinfo->total_vram / 1024 / 1024), bank3, bank2, bank1, bank0); /* @@ -644,16 +649,15 @@ static int __devexit platinumfb_remove(struct of_device* odev) unregister_framebuffer (info); /* Unmap frame buffer and registers */ + iounmap(pinfo->frame_buffer); + iounmap(pinfo->platinum_regs); + iounmap(pinfo->cmap_regs); + release_mem_region(pinfo->rsrc_fb.start, pinfo->rsrc_fb.end - pinfo->rsrc_fb.start + 1); - release_mem_region(pinfo->rsrc_reg.start, - pinfo->rsrc_reg.end - - pinfo->rsrc_reg.start + 1); - iounmap(pinfo->frame_buffer); - iounmap(pinfo->platinum_regs); + release_mem_region(pinfo->cmap_regs_phys, 0x1000); - iounmap(pinfo->cmap_regs); framebuffer_release(info); -- cgit v1.2.3-70-g09d2 From 17b0429dde9ab60f9cee8e07ab28c7dc6cfe6efd Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 22 Jul 2007 22:18:46 +0200 Subject: mmc: remove custom error codes Convert the MMC layer to use standard error codes and not its own, incompatible values. Signed-off-by: Pierre Ossman --- drivers/mmc/card/block.c | 4 ++-- drivers/mmc/core/core.c | 4 ++-- drivers/mmc/core/mmc.c | 36 ++++++++++++++--------------- drivers/mmc/core/mmc_ops.c | 34 +++++++++++++-------------- drivers/mmc/core/sd.c | 56 ++++++++++++++++++++++----------------------- drivers/mmc/core/sd_ops.c | 46 ++++++++++++++++++------------------- drivers/mmc/host/at91_mci.c | 12 ++++------ drivers/mmc/host/au1xmmc.c | 32 +++++++++++++------------- drivers/mmc/host/imxmmc.c | 14 ++++++------ drivers/mmc/host/mmci.c | 12 +++++----- drivers/mmc/host/omap.c | 12 +++++----- drivers/mmc/host/pxamci.c | 12 +++++----- drivers/mmc/host/sdhci.c | 51 +++++++++++++++++++---------------------- drivers/mmc/host/tifm_sd.c | 20 ++++++++-------- drivers/mmc/host/wbsd.c | 41 ++++++++++++++++----------------- include/linux/mmc/core.h | 19 ++++++++++----- 16 files changed, 203 insertions(+), 202 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 93fe2e5dd61..0da341acf32 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -154,7 +154,7 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card) cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, 0); - if ((err != MMC_ERR_NONE) || !(cmd.resp[0] & R1_APP_CMD)) + if (err || !(cmd.resp[0] & R1_APP_CMD)) return (u32)-1; memset(&cmd, 0, sizeof(struct mmc_command)); @@ -192,7 +192,7 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card) mmc_wait_for_req(card->host, &mrq); - if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) + if (cmd.error || data.error) return (u32)-1; blocks = ntohl(blocks); diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index bfd2ae5bd66..63b67296e92 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -598,7 +598,7 @@ void mmc_rescan(struct work_struct *work) mmc_send_if_cond(host, host->ocr_avail); err = mmc_send_app_op_cond(host, 0, &ocr); - if (err == MMC_ERR_NONE) { + if (!err) { if (mmc_attach_sd(host, ocr)) mmc_power_off(host); } else { @@ -607,7 +607,7 @@ void mmc_rescan(struct work_struct *work) * searching for MMC cards. */ err = mmc_send_op_cond(host, 0, &ocr); - if (err == MMC_ERR_NONE) { + if (!err) { if (mmc_attach_mmc(host, ocr)) mmc_power_off(host); } else { diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 21d7f48e1d4..fe483d5af74 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -164,10 +164,10 @@ static int mmc_read_ext_csd(struct mmc_card *card) BUG_ON(!card); - err = MMC_ERR_FAILED; + err = -EIO; if (card->csd.mmca_vsn < CSD_SPEC_VER_4) - return MMC_ERR_NONE; + return 0; /* * As the ext_csd is so large and mostly unused, we don't store the @@ -178,11 +178,11 @@ static int mmc_read_ext_csd(struct mmc_card *card) printk(KERN_ERR "%s: could not allocate a buffer to " "receive the ext_csd. mmc v4 cards will be " "treated as v3.\n", mmc_hostname(card->host)); - return MMC_ERR_FAILED; + return -ENOMEM; } err = mmc_send_ext_csd(card, ext_csd); - if (err != MMC_ERR_NONE) { + if (err) { /* * High capacity cards should have this "magic" size * stored in their CSD. @@ -197,7 +197,7 @@ static int mmc_read_ext_csd(struct mmc_card *card) "EXT_CSD, performance might " "suffer.\n", mmc_hostname(card->host)); - err = MMC_ERR_NONE; + err = 0; } goto out; } @@ -258,14 +258,14 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, /* The extra bit indicates that we support high capacity */ err = mmc_send_op_cond(host, ocr | (1 << 30), NULL); - if (err != MMC_ERR_NONE) + if (err) goto err; /* * Fetch CID from card. */ err = mmc_all_send_cid(host, cid); - if (err != MMC_ERR_NONE) + if (err) goto err; if (oldcard) { @@ -290,7 +290,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, * Set card RCA. */ err = mmc_set_relative_addr(card); - if (err != MMC_ERR_NONE) + if (err) goto free_card; mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); @@ -300,7 +300,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, * Fetch CSD from card. */ err = mmc_send_csd(card, card->raw_csd); - if (err != MMC_ERR_NONE) + if (err) goto free_card; err = mmc_decode_csd(card); @@ -315,7 +315,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, * Select card, as all following commands rely on that. */ err = mmc_select_card(card); - if (err != MMC_ERR_NONE) + if (err) goto free_card; if (!oldcard) { @@ -323,7 +323,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, * Fetch and process extened CSD. */ err = mmc_read_ext_csd(card); - if (err != MMC_ERR_NONE) + if (err) goto free_card; } @@ -334,7 +334,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, (host->caps & MMC_CAP_MMC_HIGHSPEED)) { err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1); - if (err != MMC_ERR_NONE) + if (err) goto free_card; mmc_card_set_highspeed(card); @@ -363,7 +363,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, (host->caps & MMC_CAP_4_BIT_DATA)) { err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_4); - if (err != MMC_ERR_NONE) + if (err) goto free_card; mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4); @@ -372,14 +372,14 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, if (!oldcard) host->card = card; - return MMC_ERR_NONE; + return 0; free_card: if (!oldcard) mmc_remove_card(card); err: - return MMC_ERR_FAILED; + return -EIO; } /* @@ -413,7 +413,7 @@ static void mmc_detect(struct mmc_host *host) mmc_release_host(host); - if (err != MMC_ERR_NONE) { + if (err) { mmc_remove(host); mmc_claim_host(host); @@ -502,7 +502,7 @@ static void mmc_resume(struct mmc_host *host) err = mmc_init_card(host, host->ocr, host->card); mmc_release_host(host); - if (err != MMC_ERR_NONE) { + if (err) { mmc_remove(host); mmc_claim_host(host); @@ -565,7 +565,7 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr) * Detect and init the card. */ err = mmc_init_card(host, host->ocr, NULL); - if (err != MMC_ERR_NONE) + if (err) goto err; mmc_release_host(host); diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 913e75f0084..15cd575effa 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -40,10 +40,10 @@ static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card) } err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES); - if (err != MMC_ERR_NONE) + if (err) return err; - return MMC_ERR_NONE; + return 0; } int mmc_select_card(struct mmc_card *card) @@ -99,13 +99,13 @@ int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) for (i = 100; i; i--) { err = mmc_wait_for_cmd(host, &cmd, 0); - if (err != MMC_ERR_NONE) + if (err) break; if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0) break; - err = MMC_ERR_TIMEOUT; + err = -ETIMEDOUT; mmc_delay(10); } @@ -131,12 +131,12 @@ int mmc_all_send_cid(struct mmc_host *host, u32 *cid) cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR; err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES); - if (err != MMC_ERR_NONE) + if (err) return err; memcpy(cid, cmd.resp, sizeof(u32) * 4); - return MMC_ERR_NONE; + return 0; } int mmc_set_relative_addr(struct mmc_card *card) @@ -154,10 +154,10 @@ int mmc_set_relative_addr(struct mmc_card *card) cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); - if (err != MMC_ERR_NONE) + if (err) return err; - return MMC_ERR_NONE; + return 0; } int mmc_send_csd(struct mmc_card *card, u32 *csd) @@ -176,12 +176,12 @@ int mmc_send_csd(struct mmc_card *card, u32 *csd) cmd.flags = MMC_RSP_R2 | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); - if (err != MMC_ERR_NONE) + if (err) return err; memcpy(csd, cmd.resp, sizeof(u32) * 4); - return MMC_ERR_NONE; + return 0; } int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd) @@ -218,12 +218,12 @@ int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd) mmc_wait_for_req(card->host, &mrq); - if (cmd.error != MMC_ERR_NONE) + if (cmd.error) return cmd.error; - if (data.error != MMC_ERR_NONE) + if (data.error) return data.error; - return MMC_ERR_NONE; + return 0; } int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value) @@ -244,10 +244,10 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value) cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); - if (err != MMC_ERR_NONE) + if (err) return err; - return MMC_ERR_NONE; + return 0; } int mmc_send_status(struct mmc_card *card, u32 *status) @@ -265,12 +265,12 @@ int mmc_send_status(struct mmc_card *card, u32 *status) cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); - if (err != MMC_ERR_NONE) + if (err) return err; if (status) *status = cmd.resp[0]; - return MMC_ERR_NONE; + return 0; } diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 1edc62b1e5c..00895c99d9b 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -193,30 +193,30 @@ static int mmc_read_switch(struct mmc_card *card) u8 *status; if (card->scr.sda_vsn < SCR_SPEC_VER_1) - return MMC_ERR_NONE; + return 0; if (!(card->csd.cmdclass & CCC_SWITCH)) { printk(KERN_WARNING "%s: card lacks mandatory switch " "function, performance might suffer.\n", mmc_hostname(card->host)); - return MMC_ERR_NONE; + return 0; } - err = MMC_ERR_FAILED; + err = -EIO; status = kmalloc(64, GFP_KERNEL); if (!status) { printk(KERN_ERR "%s: could not allocate a buffer for " "switch capabilities.\n", mmc_hostname(card->host)); - return err; + return -ENOMEM; } err = mmc_sd_switch(card, 0, 0, 1, status); - if (err != MMC_ERR_NONE) { + if (err) { printk(KERN_WARNING "%s: problem reading switch " "capabilities, performance might suffer.\n", mmc_hostname(card->host)); - err = MMC_ERR_NONE; + err = 0; goto out; } @@ -238,28 +238,28 @@ static int mmc_switch_hs(struct mmc_card *card) u8 *status; if (card->scr.sda_vsn < SCR_SPEC_VER_1) - return MMC_ERR_NONE; + return 0; if (!(card->csd.cmdclass & CCC_SWITCH)) - return MMC_ERR_NONE; + return 0; if (!(card->host->caps & MMC_CAP_SD_HIGHSPEED)) - return MMC_ERR_NONE; + return 0; if (card->sw_caps.hs_max_dtr == 0) - return MMC_ERR_NONE; + return 0; - err = MMC_ERR_FAILED; + err = -EIO; status = kmalloc(64, GFP_KERNEL); if (!status) { printk(KERN_ERR "%s: could not allocate a buffer for " "switch capabilities.\n", mmc_hostname(card->host)); - return err; + return -ENOMEM; } err = mmc_sd_switch(card, 1, 0, 1, status); - if (err != MMC_ERR_NONE) + if (err) goto out; if ((status[16] & 0xF) != 1) { @@ -309,18 +309,18 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, * block-addressed SDHC cards. */ err = mmc_send_if_cond(host, ocr); - if (err == MMC_ERR_NONE) + if (!err) ocr |= 1 << 30; err = mmc_send_app_op_cond(host, ocr, NULL); - if (err != MMC_ERR_NONE) + if (err) goto err; /* * Fetch CID from card. */ err = mmc_all_send_cid(host, cid); - if (err != MMC_ERR_NONE) + if (err) goto err; if (oldcard) { @@ -344,7 +344,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, * Set card RCA. */ err = mmc_send_relative_addr(host, &card->rca); - if (err != MMC_ERR_NONE) + if (err) goto free_card; mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); @@ -354,7 +354,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, * Fetch CSD from card. */ err = mmc_send_csd(card, card->raw_csd); - if (err != MMC_ERR_NONE) + if (err) goto free_card; err = mmc_decode_csd(card); @@ -368,7 +368,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, * Select card, as all following commands rely on that. */ err = mmc_select_card(card); - if (err != MMC_ERR_NONE) + if (err) goto free_card; if (!oldcard) { @@ -376,7 +376,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, * Fetch SCR from card. */ err = mmc_app_send_scr(card, card->raw_scr); - if (err != MMC_ERR_NONE) + if (err) goto free_card; err = mmc_decode_scr(card); @@ -387,7 +387,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, * Fetch switch information from card. */ err = mmc_read_switch(card); - if (err != MMC_ERR_NONE) + if (err) goto free_card; } @@ -395,7 +395,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, * Attempt to change to high-speed (if supported) */ err = mmc_switch_hs(card); - if (err != MMC_ERR_NONE) + if (err) goto free_card; /* @@ -418,7 +418,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, if ((host->caps & MMC_CAP_4_BIT_DATA) && (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) { err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4); - if (err != MMC_ERR_NONE) + if (err) goto free_card; mmc_set_bus_width(host, MMC_BUS_WIDTH_4); @@ -442,14 +442,14 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, if (!oldcard) host->card = card; - return MMC_ERR_NONE; + return 0; free_card: if (!oldcard) mmc_remove_card(card); err: - return MMC_ERR_FAILED; + return -EIO; } /* @@ -483,7 +483,7 @@ static void mmc_sd_detect(struct mmc_host *host) mmc_release_host(host); - if (err != MMC_ERR_NONE) { + if (err) { mmc_sd_remove(host); mmc_claim_host(host); @@ -574,7 +574,7 @@ static void mmc_sd_resume(struct mmc_host *host) err = mmc_sd_init_card(host, host->ocr, host->card); mmc_release_host(host); - if (err != MMC_ERR_NONE) { + if (err) { mmc_sd_remove(host); mmc_claim_host(host); @@ -644,7 +644,7 @@ int mmc_attach_sd(struct mmc_host *host, u32 ocr) * Detect and init the card. */ err = mmc_sd_init_card(host, host->ocr, NULL); - if (err != MMC_ERR_NONE) + if (err) goto err; mmc_release_host(host); diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c index 342f340ebc2..b4d43bd0fed 100644 --- a/drivers/mmc/core/sd_ops.c +++ b/drivers/mmc/core/sd_ops.c @@ -40,14 +40,14 @@ static int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card) } err = mmc_wait_for_cmd(host, &cmd, 0); - if (err != MMC_ERR_NONE) + if (err) return err; /* Check that card supported application commands */ if (!(cmd.resp[0] & R1_APP_CMD)) - return MMC_ERR_FAILED; + return -EOPNOTSUPP; - return MMC_ERR_NONE; + return 0; } /** @@ -73,7 +73,7 @@ int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card, BUG_ON(!cmd); BUG_ON(retries < 0); - err = MMC_ERR_INVALID; + err = -EIO; /* * We have to resend MMC_APP_CMD for each attempt so @@ -83,7 +83,7 @@ int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card, memset(&mrq, 0, sizeof(struct mmc_request)); err = mmc_app_cmd(host, card); - if (err != MMC_ERR_NONE) + if (err) continue; memset(&mrq, 0, sizeof(struct mmc_request)); @@ -97,7 +97,7 @@ int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card, mmc_wait_for_req(host, &mrq); err = cmd->error; - if (cmd->error == MMC_ERR_NONE) + if (!cmd->error) break; } @@ -127,14 +127,14 @@ int mmc_app_set_bus_width(struct mmc_card *card, int width) cmd.arg = SD_BUS_WIDTH_4; break; default: - return MMC_ERR_INVALID; + return -EINVAL; } err = mmc_wait_for_app_cmd(card->host, card, &cmd, MMC_CMD_RETRIES); - if (err != MMC_ERR_NONE) + if (err) return err; - return MMC_ERR_NONE; + return 0; } int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) @@ -152,13 +152,13 @@ int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) for (i = 100; i; i--) { err = mmc_wait_for_app_cmd(host, NULL, &cmd, MMC_CMD_RETRIES); - if (err != MMC_ERR_NONE) + if (err) break; if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0) break; - err = MMC_ERR_TIMEOUT; + err = -ETIMEDOUT; mmc_delay(10); } @@ -185,13 +185,13 @@ int mmc_send_if_cond(struct mmc_host *host, u32 ocr) cmd.flags = MMC_RSP_R7 | MMC_CMD_BCR; err = mmc_wait_for_cmd(host, &cmd, 0); - if (err != MMC_ERR_NONE) + if (err) return err; if ((cmd.resp[0] & 0xFF) != test_pattern) - return MMC_ERR_FAILED; + return -EIO; - return MMC_ERR_NONE; + return 0; } int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca) @@ -209,12 +209,12 @@ int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca) cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR; err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES); - if (err != MMC_ERR_NONE) + if (err) return err; *rca = cmd.resp[0] >> 16; - return MMC_ERR_NONE; + return 0; } int mmc_app_send_scr(struct mmc_card *card, u32 *scr) @@ -230,7 +230,7 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr) BUG_ON(!scr); err = mmc_app_cmd(card->host, card); - if (err != MMC_ERR_NONE) + if (err) return err; memset(&mrq, 0, sizeof(struct mmc_request)); @@ -256,15 +256,15 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr) mmc_wait_for_req(card->host, &mrq); - if (cmd.error != MMC_ERR_NONE) + if (cmd.error) return cmd.error; - if (data.error != MMC_ERR_NONE) + if (data.error) return data.error; scr[0] = ntohl(scr[0]); scr[1] = ntohl(scr[1]); - return MMC_ERR_NONE; + return 0; } int mmc_sd_switch(struct mmc_card *card, int mode, int group, @@ -306,11 +306,11 @@ int mmc_sd_switch(struct mmc_card *card, int mode, int group, mmc_wait_for_req(card->host, &mrq); - if (cmd.error != MMC_ERR_NONE) + if (cmd.error) return cmd.error; - if (data.error != MMC_ERR_NONE) + if (data.error) return data.error; - return MMC_ERR_NONE; + return 0; } diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c index 955ea60583b..810a433ce53 100644 --- a/drivers/mmc/host/at91_mci.c +++ b/drivers/mmc/host/at91_mci.c @@ -577,24 +577,22 @@ static void at91_mci_completed_command(struct at91mci_host *host) AT91_MCI_RENDE | AT91_MCI_RTOE | AT91_MCI_DCRCE | AT91_MCI_DTOE | AT91_MCI_OVRE | AT91_MCI_UNRE)) { if ((status & AT91_MCI_RCRCE) && !(mmc_resp_type(cmd) & MMC_RSP_CRC)) { - cmd->error = MMC_ERR_NONE; + cmd->error = 0; } else { if (status & (AT91_MCI_RTOE | AT91_MCI_DTOE)) - cmd->error = MMC_ERR_TIMEOUT; + cmd->error = -ETIMEDOUT; else if (status & (AT91_MCI_RCRCE | AT91_MCI_DCRCE)) - cmd->error = MMC_ERR_BADCRC; - else if (status & (AT91_MCI_OVRE | AT91_MCI_UNRE)) - cmd->error = MMC_ERR_FIFO; + cmd->error = -EILSEQ; else - cmd->error = MMC_ERR_FAILED; + cmd->error = -EIO; pr_debug("Error detected and set to %d (cmd = %d, retries = %d)\n", cmd->error, cmd->opcode, cmd->retries); } } else - cmd->error = MMC_ERR_NONE; + cmd->error = 0; at91_mci_process_next(host); } diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c index 34c99d4ea04..49b0367e57c 100644 --- a/drivers/mmc/host/au1xmmc.c +++ b/drivers/mmc/host/au1xmmc.c @@ -208,7 +208,7 @@ static int au1xmmc_send_command(struct au1xmmc_host *host, int wait, default: printk(KERN_INFO "au1xmmc: unhandled response type %02x\n", mmc_resp_type(cmd)); - return MMC_ERR_INVALID; + return -EINVAL; } if (flags & MMC_DATA_READ) { @@ -253,7 +253,7 @@ static int au1xmmc_send_command(struct au1xmmc_host *host, int wait, IRQ_ON(host, SD_CONFIG_CR); } - return MMC_ERR_NONE; + return 0; } static void au1xmmc_data_complete(struct au1xmmc_host *host, u32 status) @@ -278,7 +278,7 @@ static void au1xmmc_data_complete(struct au1xmmc_host *host, u32 status) while((host->flags & HOST_F_XMIT) && (status & SD_STATUS_DB)) status = au_readl(HOST_STATUS(host)); - data->error = MMC_ERR_NONE; + data->error = 0; dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, host->dma.dir); /* Process any errors */ @@ -288,14 +288,14 @@ static void au1xmmc_data_complete(struct au1xmmc_host *host, u32 status) crc |= ((status & 0x07) == 0x02) ? 0 : 1; if (crc) - data->error = MMC_ERR_BADCRC; + data->error = -EILSEQ; /* Clear the CRC bits */ au_writel(SD_STATUS_WC | SD_STATUS_RC, HOST_STATUS(host)); data->bytes_xfered = 0; - if (data->error == MMC_ERR_NONE) { + if (!data->error) { if (host->flags & HOST_F_DMA) { u32 chan = DMA_CHANNEL(host); @@ -475,7 +475,7 @@ static void au1xmmc_cmd_complete(struct au1xmmc_host *host, u32 status) return; cmd = mrq->cmd; - cmd->error = MMC_ERR_NONE; + cmd->error = 0; if (cmd->flags & MMC_RSP_PRESENT) { if (cmd->flags & MMC_RSP_136) { @@ -512,11 +512,11 @@ static void au1xmmc_cmd_complete(struct au1xmmc_host *host, u32 status) /* Figure out errors */ if (status & (SD_STATUS_SC | SD_STATUS_WC | SD_STATUS_RC)) - cmd->error = MMC_ERR_BADCRC; + cmd->error = -EILSEQ; trans = host->flags & (HOST_F_XMIT | HOST_F_RECV); - if (!trans || cmd->error != MMC_ERR_NONE) { + if (!trans || cmd->error) { IRQ_OFF(host, SD_CONFIG_TH | SD_CONFIG_RA|SD_CONFIG_RF); tasklet_schedule(&host->finish_task); @@ -589,7 +589,7 @@ au1xmmc_prepare_data(struct au1xmmc_host *host, struct mmc_data *data) data->sg_len, host->dma.dir); if (host->dma.len == 0) - return MMC_ERR_TIMEOUT; + return -ETIMEDOUT; au_writel(data->blksz - 1, HOST_BLKSIZE(host)); @@ -640,11 +640,11 @@ au1xmmc_prepare_data(struct au1xmmc_host *host, struct mmc_data *data) //IRQ_ON(host, SD_CONFIG_RA|SD_CONFIG_RF); } - return MMC_ERR_NONE; + return 0; dataerr: dma_unmap_sg(mmc_dev(host->mmc),data->sg,data->sg_len,host->dma.dir); - return MMC_ERR_TIMEOUT; + return -ETIMEDOUT; } /* static void au1xmmc_request @@ -656,7 +656,7 @@ static void au1xmmc_request(struct mmc_host* mmc, struct mmc_request* mrq) struct au1xmmc_host *host = mmc_priv(mmc); unsigned int flags = 0; - int ret = MMC_ERR_NONE; + int ret = 0; WARN_ON(irqs_disabled()); WARN_ON(host->status != HOST_S_IDLE); @@ -672,10 +672,10 @@ static void au1xmmc_request(struct mmc_host* mmc, struct mmc_request* mrq) ret = au1xmmc_prepare_data(host, mrq->data); } - if (ret == MMC_ERR_NONE) + if (!ret) ret = au1xmmc_send_command(host, 0, mrq->cmd, flags); - if (ret != MMC_ERR_NONE) { + if (ret) { mrq->cmd->error = ret; au1xmmc_finish_request(host); } @@ -764,10 +764,10 @@ static irqreturn_t au1xmmc_irq(int irq, void *dev_id) if (host->mrq && (status & STATUS_TIMEOUT)) { if (status & SD_STATUS_RAT) - host->mrq->cmd->error = MMC_ERR_TIMEOUT; + host->mrq->cmd->error = -ETIMEDOUT; else if (status & SD_STATUS_DT) - host->mrq->data->error = MMC_ERR_TIMEOUT; + host->mrq->data->error = -ETIMEDOUT; /* In PIO mode, interrupts might still be enabled */ IRQ_OFF(host, SD_CONFIG_NE | SD_CONFIG_TH); diff --git a/drivers/mmc/host/imxmmc.c b/drivers/mmc/host/imxmmc.c index 54bfc9f2559..04458c34281 100644 --- a/drivers/mmc/host/imxmmc.c +++ b/drivers/mmc/host/imxmmc.c @@ -428,11 +428,11 @@ static int imxmci_finish_data(struct imxmci_host *host, unsigned int stat) if ( stat & STATUS_ERR_MASK ) { dev_dbg(mmc_dev(host->mmc), "request failed. status: 0x%08x\n",stat); if(stat & (STATUS_CRC_READ_ERR | STATUS_CRC_WRITE_ERR)) - data->error = MMC_ERR_BADCRC; + data->error = -EILSEQ; else if(stat & STATUS_TIME_OUT_READ) - data->error = MMC_ERR_TIMEOUT; + data->error = -ETIMEDOUT; else - data->error = MMC_ERR_FAILED; + data->error = -EIO; } else { data->bytes_xfered = host->dma_size; } @@ -458,10 +458,10 @@ static int imxmci_cmd_done(struct imxmci_host *host, unsigned int stat) if (stat & STATUS_TIME_OUT_RESP) { dev_dbg(mmc_dev(host->mmc), "CMD TIMEOUT\n"); - cmd->error = MMC_ERR_TIMEOUT; + cmd->error = -ETIMEDOUT; } else if (stat & STATUS_RESP_CRC_ERR && cmd->flags & MMC_RSP_CRC) { dev_dbg(mmc_dev(host->mmc), "cmd crc error\n"); - cmd->error = MMC_ERR_BADCRC; + cmd->error = -EILSEQ; } if(cmd->flags & MMC_RSP_PRESENT) { @@ -482,7 +482,7 @@ static int imxmci_cmd_done(struct imxmci_host *host, unsigned int stat) dev_dbg(mmc_dev(host->mmc), "RESP 0x%08x, 0x%08x, 0x%08x, 0x%08x, error %d\n", cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3], cmd->error); - if (data && (cmd->error == MMC_ERR_NONE) && !(stat & STATUS_ERR_MASK)) { + if (data && !cmd->error && !(stat & STATUS_ERR_MASK)) { if (host->req->data->flags & MMC_DATA_WRITE) { /* Wait for FIFO to be empty before starting DMA write */ @@ -491,7 +491,7 @@ static int imxmci_cmd_done(struct imxmci_host *host, unsigned int stat) if(imxmci_busy_wait_for_status(host, &stat, STATUS_APPL_BUFF_FE, 40, "imxmci_cmd_done DMA WR") < 0) { - cmd->error = MMC_ERR_FIFO; + cmd->error = -EIO; imxmci_finish_data(host, stat); if(host->req) imxmci_finish_request(host, host->req); diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index be730c0a035..d53e9a8bdaa 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -154,11 +154,11 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, } if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) { if (status & MCI_DATACRCFAIL) - data->error = MMC_ERR_BADCRC; + data->error = -EILSEQ; else if (status & MCI_DATATIMEOUT) - data->error = MMC_ERR_TIMEOUT; + data->error = -ETIMEDOUT; else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN)) - data->error = MMC_ERR_FIFO; + data->error = -EIO; status |= MCI_DATAEND; /* @@ -193,12 +193,12 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, cmd->resp[3] = readl(base + MMCIRESPONSE3); if (status & MCI_CMDTIMEOUT) { - cmd->error = MMC_ERR_TIMEOUT; + cmd->error = -ETIMEDOUT; } else if (status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) { - cmd->error = MMC_ERR_BADCRC; + cmd->error = -EILSEQ; } - if (!cmd->data || cmd->error != MMC_ERR_NONE) { + if (!cmd->data || cmd->error) { if (host->data) mmci_stop_data(host); mmci_request_end(host, cmd->mrq); diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index 0cf97edc5f5..60a67dfcda6 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -263,7 +263,7 @@ mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data) enum dma_data_direction dma_data_dir; BUG_ON(host->dma_ch < 0); - if (data->error != MMC_ERR_NONE) + if (data->error) omap_stop_dma(host->dma_ch); /* Release DMA channel lazily */ mod_timer(&host->dma_timer, jiffies + HZ); @@ -368,7 +368,7 @@ mmc_omap_cmd_done(struct mmc_omap_host *host, struct mmc_command *cmd) } } - if (host->data == NULL || cmd->error != MMC_ERR_NONE) { + if (host->data == NULL || cmd->error) { host->mrq = NULL; clk_disable(host->fclk); mmc_request_done(host->mmc, cmd->mrq); @@ -475,14 +475,14 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id) if (status & OMAP_MMC_STAT_DATA_TOUT) { dev_dbg(mmc_dev(host->mmc), "data timeout\n"); if (host->data) { - host->data->error |= MMC_ERR_TIMEOUT; + host->data->error = -ETIMEDOUT; transfer_error = 1; } } if (status & OMAP_MMC_STAT_DATA_CRC) { if (host->data) { - host->data->error |= MMC_ERR_BADCRC; + host->data->error = -EILSEQ; dev_dbg(mmc_dev(host->mmc), "data CRC error, bytes left %d\n", host->total_bytes_left); @@ -504,7 +504,7 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id) dev_err(mmc_dev(host->mmc), "command timeout, CMD %d\n", host->cmd->opcode); - host->cmd->error = MMC_ERR_TIMEOUT; + host->cmd->error = -ETIMEDOUT; end_command = 1; } } @@ -514,7 +514,7 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id) dev_err(mmc_dev(host->mmc), "command CRC error (CMD%d, arg 0x%08x)\n", host->cmd->opcode, host->cmd->arg); - host->cmd->error = MMC_ERR_BADCRC; + host->cmd->error = -EILSEQ; end_command = 1; } else dev_err(mmc_dev(host->mmc), diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index ff960334b33..b89e32d1e9b 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -226,7 +226,7 @@ static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat) } if (stat & STAT_TIME_OUT_RESPONSE) { - cmd->error = MMC_ERR_TIMEOUT; + cmd->error = -ETIMEDOUT; } else if (stat & STAT_RES_CRC_ERR && cmd->flags & MMC_RSP_CRC) { #ifdef CONFIG_PXA27x /* @@ -239,11 +239,11 @@ static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat) pr_debug("ignoring CRC from command %d - *risky*\n", cmd->opcode); } else #endif - cmd->error = MMC_ERR_BADCRC; + cmd->error = -EILSEQ; } pxamci_disable_irq(host, END_CMD_RES); - if (host->data && cmd->error == MMC_ERR_NONE) { + if (host->data && !cmd->error) { pxamci_enable_irq(host, DATA_TRAN_DONE); } else { pxamci_finish_request(host, host->mrq); @@ -264,9 +264,9 @@ static int pxamci_data_done(struct pxamci_host *host, unsigned int stat) host->dma_dir); if (stat & STAT_READ_TIME_OUT) - data->error = MMC_ERR_TIMEOUT; + data->error = -ETIMEDOUT; else if (stat & (STAT_CRC_READ_ERROR|STAT_CRC_WRITE_ERROR)) - data->error = MMC_ERR_BADCRC; + data->error = -EILSEQ; /* * There appears to be a hardware design bug here. There seems to @@ -274,7 +274,7 @@ static int pxamci_data_done(struct pxamci_host *host, unsigned int stat) * This means that if there was an error on any block, we mark all * data blocks as being in error. */ - if (data->error == MMC_ERR_NONE) + if (!data->error) data->bytes_xfered = data->blocks * data->blksz; else data->bytes_xfered = 0; diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 20a7d89e01b..479d6a265dd 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -481,16 +481,16 @@ static void sdhci_finish_data(struct sdhci_host *host) * Controller doesn't count down when in single block mode. */ if (data->blocks == 1) - blocks = (data->error == MMC_ERR_NONE) ? 0 : 1; + blocks = (data->error == 0) ? 0 : 1; else blocks = readw(host->ioaddr + SDHCI_BLOCK_COUNT); data->bytes_xfered = data->blksz * (data->blocks - blocks); - if ((data->error == MMC_ERR_NONE) && blocks) { + if (!data->error && blocks) { printk(KERN_ERR "%s: Controller signalled completion even " "though there were blocks left.\n", mmc_hostname(host->mmc)); - data->error = MMC_ERR_FAILED; + data->error = -EIO; } if (data->stop) { @@ -498,7 +498,7 @@ static void sdhci_finish_data(struct sdhci_host *host) * The controller needs a reset of internal state machines * upon error conditions. */ - if (data->error != MMC_ERR_NONE) { + if (data->error) { sdhci_reset(host, SDHCI_RESET_CMD); sdhci_reset(host, SDHCI_RESET_DATA); } @@ -533,7 +533,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) printk(KERN_ERR "%s: Controller never released " "inhibit bit(s).\n", mmc_hostname(host->mmc)); sdhci_dumpregs(host); - cmd->error = MMC_ERR_FAILED; + cmd->error = -EIO; tasklet_schedule(&host->finish_tasklet); return; } @@ -554,7 +554,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) { printk(KERN_ERR "%s: Unsupported response type!\n", mmc_hostname(host->mmc)); - cmd->error = MMC_ERR_INVALID; + cmd->error = -EINVAL; tasklet_schedule(&host->finish_tasklet); return; } @@ -601,7 +601,7 @@ static void sdhci_finish_command(struct sdhci_host *host) } } - host->cmd->error = MMC_ERR_NONE; + host->cmd->error = 0; if (host->data && host->data_early) sdhci_finish_data(host); @@ -722,7 +722,7 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) host->mrq = mrq; if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) { - host->mrq->cmd->error = MMC_ERR_TIMEOUT; + host->mrq->cmd->error = -ENOMEDIUM; tasklet_schedule(&host->finish_tasklet); } else sdhci_send_command(host, mrq->cmd); @@ -831,7 +831,7 @@ static void sdhci_tasklet_card(unsigned long param) sdhci_reset(host, SDHCI_RESET_CMD); sdhci_reset(host, SDHCI_RESET_DATA); - host->mrq->cmd->error = MMC_ERR_FAILED; + host->mrq->cmd->error = -ENOMEDIUM; tasklet_schedule(&host->finish_tasklet); } } @@ -859,9 +859,9 @@ static void sdhci_tasklet_finish(unsigned long param) * The controller needs a reset of internal state machines * upon error conditions. */ - if ((mrq->cmd->error != MMC_ERR_NONE) || - (mrq->data && ((mrq->data->error != MMC_ERR_NONE) || - (mrq->data->stop && (mrq->data->stop->error != MMC_ERR_NONE))))) { + if (mrq->cmd->error || + (mrq->data && (mrq->data->error || + (mrq->data->stop && mrq->data->stop->error)))) { /* Some controllers need this kick or reset won't work here */ if (host->chip->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET) { @@ -906,13 +906,13 @@ static void sdhci_timeout_timer(unsigned long data) sdhci_dumpregs(host); if (host->data) { - host->data->error = MMC_ERR_TIMEOUT; + host->data->error = -ETIMEDOUT; sdhci_finish_data(host); } else { if (host->cmd) - host->cmd->error = MMC_ERR_TIMEOUT; + host->cmd->error = -ETIMEDOUT; else - host->mrq->cmd->error = MMC_ERR_TIMEOUT; + host->mrq->cmd->error = -ETIMEDOUT; tasklet_schedule(&host->finish_tasklet); } @@ -941,13 +941,12 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask) } if (intmask & SDHCI_INT_TIMEOUT) - host->cmd->error = MMC_ERR_TIMEOUT; - else if (intmask & SDHCI_INT_CRC) - host->cmd->error = MMC_ERR_BADCRC; - else if (intmask & (SDHCI_INT_END_BIT | SDHCI_INT_INDEX)) - host->cmd->error = MMC_ERR_FAILED; + host->cmd->error = -ETIMEDOUT; + else if (intmask & (SDHCI_INT_CRC | SDHCI_INT_END_BIT | + SDHCI_INT_INDEX)) + host->cmd->error = -EILSEQ; - if (host->cmd->error != MMC_ERR_NONE) + if (host->cmd->error) tasklet_schedule(&host->finish_tasklet); else if (intmask & SDHCI_INT_RESPONSE) sdhci_finish_command(host); @@ -974,13 +973,11 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) } if (intmask & SDHCI_INT_DATA_TIMEOUT) - host->data->error = MMC_ERR_TIMEOUT; - else if (intmask & SDHCI_INT_DATA_CRC) - host->data->error = MMC_ERR_BADCRC; - else if (intmask & SDHCI_INT_DATA_END_BIT) - host->data->error = MMC_ERR_FAILED; + host->data->error = -ETIMEDOUT; + else if (intmask & (SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_END_BIT)) + host->data->error = -EILSEQ; - if (host->data->error != MMC_ERR_NONE) + if (host->data->error) sdhci_finish_data(host); else { if (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL)) diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c index 8b736e96844..b4a56e5e513 100644 --- a/drivers/mmc/host/tifm_sd.c +++ b/drivers/mmc/host/tifm_sd.c @@ -404,14 +404,14 @@ static void tifm_sd_check_status(struct tifm_sd *host) struct tifm_dev *sock = host->dev; struct mmc_command *cmd = host->req->cmd; - if (cmd->error != MMC_ERR_NONE) + if (cmd->error) goto finish_request; if (!(host->cmd_flags & CMD_READY)) return; if (cmd->data) { - if (cmd->data->error != MMC_ERR_NONE) { + if (cmd->data->error) { if ((host->cmd_flags & SCMD_ACTIVE) && !(host->cmd_flags & SCMD_READY)) return; @@ -504,7 +504,7 @@ static void tifm_sd_card_event(struct tifm_dev *sock) { struct tifm_sd *host; unsigned int host_status = 0; - int cmd_error = MMC_ERR_NONE; + int cmd_error = 0; struct mmc_command *cmd = NULL; unsigned long flags; @@ -521,15 +521,15 @@ static void tifm_sd_card_event(struct tifm_dev *sock) writel(host_status & TIFM_MMCSD_ERRMASK, sock->addr + SOCK_MMCSD_STATUS); if (host_status & TIFM_MMCSD_CTO) - cmd_error = MMC_ERR_TIMEOUT; + cmd_error = -ETIMEDOUT; else if (host_status & TIFM_MMCSD_CCRC) - cmd_error = MMC_ERR_BADCRC; + cmd_error = -EILSEQ; if (cmd->data) { if (host_status & TIFM_MMCSD_DTO) - cmd->data->error = MMC_ERR_TIMEOUT; + cmd->data->error = -ETIMEDOUT; else if (host_status & TIFM_MMCSD_DCRC) - cmd->data->error = MMC_ERR_BADCRC; + cmd->data->error = -EILSEQ; } writel(TIFM_FIFO_INT_SETALL, @@ -722,7 +722,7 @@ static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq) return; err_out: - mrq->cmd->error = MMC_ERR_TIMEOUT; + mrq->cmd->error = -ETIMEDOUT; mmc_request_done(mmc, mrq); } @@ -1012,9 +1012,9 @@ static void tifm_sd_remove(struct tifm_dev *sock) writel(TIFM_FIFO_INT_SETALL, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR); writel(0, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET); - host->req->cmd->error = MMC_ERR_TIMEOUT; + host->req->cmd->error = -ENOMEDIUM; if (host->req->stop) - host->req->stop->error = MMC_ERR_TIMEOUT; + host->req->stop->error = -ENOMEDIUM; tasklet_schedule(&host->finish_tasklet); } spin_unlock_irqrestore(&sock->lock, flags); diff --git a/drivers/mmc/host/wbsd.c b/drivers/mmc/host/wbsd.c index 9bf2a877113..44968c2279e 100644 --- a/drivers/mmc/host/wbsd.c +++ b/drivers/mmc/host/wbsd.c @@ -317,7 +317,7 @@ static inline void wbsd_get_short_reply(struct wbsd_host *host, * Correct response type? */ if (wbsd_read_index(host, WBSD_IDX_RSPLEN) != WBSD_RSP_SHORT) { - cmd->error = MMC_ERR_INVALID; + cmd->error = -EILSEQ; return; } @@ -337,7 +337,7 @@ static inline void wbsd_get_long_reply(struct wbsd_host *host, * Correct response type? */ if (wbsd_read_index(host, WBSD_IDX_RSPLEN) != WBSD_RSP_LONG) { - cmd->error = MMC_ERR_INVALID; + cmd->error = -EILSEQ; return; } @@ -372,7 +372,7 @@ static void wbsd_send_command(struct wbsd_host *host, struct mmc_command *cmd) for (i = 3; i >= 0; i--) outb((cmd->arg >> (i * 8)) & 0xff, host->base + WBSD_CMDR); - cmd->error = MMC_ERR_NONE; + cmd->error = 0; /* * Wait for the request to complete. @@ -392,13 +392,13 @@ static void wbsd_send_command(struct wbsd_host *host, struct mmc_command *cmd) /* Card removed? */ if (isr & WBSD_INT_CARD) - cmd->error = MMC_ERR_TIMEOUT; + cmd->error = -ENOMEDIUM; /* Timeout? */ else if (isr & WBSD_INT_TIMEOUT) - cmd->error = MMC_ERR_TIMEOUT; + cmd->error = -ETIMEDOUT; /* CRC? */ else if ((cmd->flags & MMC_RSP_CRC) && (isr & WBSD_INT_CRC)) - cmd->error = MMC_ERR_BADCRC; + cmd->error = -EILSEQ; /* All ok */ else { if (cmd->flags & MMC_RSP_136) @@ -585,7 +585,7 @@ static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data) ((blksize >> 4) & 0xF0) | WBSD_DATA_WIDTH); wbsd_write_index(host, WBSD_IDX_PBSLSB, blksize & 0xFF); } else { - data->error = MMC_ERR_INVALID; + data->error = -EINVAL; return; } @@ -607,7 +607,7 @@ static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data) */ BUG_ON(size > 0x10000); if (size > 0x10000) { - data->error = MMC_ERR_INVALID; + data->error = -EINVAL; return; } @@ -669,7 +669,7 @@ static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data) } } - data->error = MMC_ERR_NONE; + data->error = 0; } static void wbsd_finish_data(struct wbsd_host *host, struct mmc_data *data) @@ -724,8 +724,8 @@ static void wbsd_finish_data(struct wbsd_host *host, struct mmc_data *data) "%d bytes left.\n", mmc_hostname(host->mmc), count); - if (data->error == MMC_ERR_NONE) - data->error = MMC_ERR_FAILED; + if (!data->error) + data->error = -EIO; } else { /* * Transfer data from DMA buffer to @@ -735,7 +735,7 @@ static void wbsd_finish_data(struct wbsd_host *host, struct mmc_data *data) wbsd_dma_to_sg(host, data); } - if (data->error != MMC_ERR_NONE) { + if (data->error) { if (data->bytes_xfered) data->bytes_xfered -= data->blksz; } @@ -767,11 +767,10 @@ static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq) host->mrq = mrq; /* - * If there is no card in the slot then - * timeout immediatly. + * Check that there is actually a card in the slot. */ if (!(host->flags & WBSD_FCARD_PRESENT)) { - cmd->error = MMC_ERR_TIMEOUT; + cmd->error = -ENOMEDIUM; goto done; } @@ -807,7 +806,7 @@ static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq) "supported by this controller.\n", mmc_hostname(host->mmc), cmd->opcode); #endif - cmd->error = MMC_ERR_INVALID; + cmd->error = -EINVAL; goto done; }; @@ -819,7 +818,7 @@ static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq) if (cmd->data) { wbsd_prepare_data(host, cmd->data); - if (cmd->data->error != MMC_ERR_NONE) + if (cmd->data->error) goto done; } @@ -830,7 +829,7 @@ static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq) * will be finished after the data has * transfered. */ - if (cmd->data && (cmd->error == MMC_ERR_NONE)) { + if (cmd->data && !cmd->error) { /* * Dirty fix for hardware bug. */ @@ -1033,7 +1032,7 @@ static void wbsd_tasklet_card(unsigned long param) mmc_hostname(host->mmc)); wbsd_reset(host); - host->mrq->cmd->error = MMC_ERR_FAILED; + host->mrq->cmd->error = -ENOMEDIUM; tasklet_schedule(&host->finish_tasklet); } @@ -1097,7 +1096,7 @@ static void wbsd_tasklet_crc(unsigned long param) DBGF("CRC error\n"); - data->error = MMC_ERR_BADCRC; + data->error = -EILSEQ; tasklet_schedule(&host->finish_tasklet); @@ -1121,7 +1120,7 @@ static void wbsd_tasklet_timeout(unsigned long param) DBGF("Timeout\n"); - data->error = MMC_ERR_TIMEOUT; + data->error = -ETIMEDOUT; tasklet_schedule(&host->finish_tasklet); diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index 63a80ea6112..a2b79518f05 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h @@ -54,12 +54,19 @@ struct mmc_command { unsigned int retries; /* max number of retries */ unsigned int error; /* command error */ -#define MMC_ERR_NONE 0 -#define MMC_ERR_TIMEOUT 1 -#define MMC_ERR_BADCRC 2 -#define MMC_ERR_FIFO 3 -#define MMC_ERR_FAILED 4 -#define MMC_ERR_INVALID 5 +/* + * Standard errno values are used for errors, but some have specific + * meaning in the MMC layer: + * + * ETIMEDOUT Card took too long to respond + * EILSEQ Basic format problem with the received or sent data + * (e.g. CRC check failed, incorrect opcode in response + * or bad end bit) + * EINVAL Request cannot be performed because of restrictions + * in hardware and/or the driver + * ENOMEDIUM Host can determine that the slot is empty and is + * actively failing requests + */ struct mmc_data *data; /* data segment associated with cmd */ struct mmc_request *mrq; /* associated request */ -- cgit v1.2.3-70-g09d2 From adf66a0dc5e8be8d4e64f3c2114f9b175558235b Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 22 Jul 2007 23:08:30 +0200 Subject: mmc: improve error code feedback Now that we use "normal" error codes, improve the reporting and response to error codes in the core. Signed-off-by: Pierre Ossman --- drivers/mmc/core/mmc.c | 27 +++++++++++++++++++-------- drivers/mmc/core/sd.c | 22 +++++++++++++++++----- 2 files changed, 36 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index fe483d5af74..258fe73eeaa 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -176,13 +176,19 @@ static int mmc_read_ext_csd(struct mmc_card *card) ext_csd = kmalloc(512, GFP_KERNEL); if (!ext_csd) { printk(KERN_ERR "%s: could not allocate a buffer to " - "receive the ext_csd. mmc v4 cards will be " - "treated as v3.\n", mmc_hostname(card->host)); + "receive the ext_csd.\n", mmc_hostname(card->host)); return -ENOMEM; } err = mmc_send_ext_csd(card, ext_csd); if (err) { + /* + * We all hosts that cannot perform the command + * to fail more gracefully + */ + if (err != -EINVAL) + goto out; + /* * High capacity cards should have this "magic" size * stored in their CSD. @@ -199,6 +205,7 @@ static int mmc_read_ext_csd(struct mmc_card *card) mmc_hostname(card->host)); err = 0; } + goto out; } @@ -269,8 +276,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, goto err; if (oldcard) { - if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0) + if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0) { + err = -ENOENT; goto err; + } card = oldcard; } else { @@ -278,8 +287,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, * Allocate card structure. */ card = mmc_alloc_card(host); - if (IS_ERR(card)) + if (IS_ERR(card)) { + err = PTR_ERR(card); goto err; + } card->type = MMC_TYPE_MMC; card->rca = 1; @@ -304,10 +315,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, goto free_card; err = mmc_decode_csd(card); - if (err < 0) + if (err) goto free_card; err = mmc_decode_cid(card); - if (err < 0) + if (err) goto free_card; } @@ -379,7 +390,7 @@ free_card: mmc_remove_card(card); err: - return -EIO; + return err; } /* @@ -587,6 +598,6 @@ err: printk(KERN_ERR "%s: error %d whilst initialising MMC card\n", mmc_hostname(host), err); - return 0; + return err; } diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 00895c99d9b..0a04a6e86ca 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -213,10 +213,18 @@ static int mmc_read_switch(struct mmc_card *card) err = mmc_sd_switch(card, 0, 0, 1, status); if (err) { + /* + * We all hosts that cannot perform the command + * to fail more gracefully + */ + if (err != -EINVAL) + goto out; + printk(KERN_WARNING "%s: problem reading switch " "capabilities, performance might suffer.\n", mmc_hostname(card->host)); err = 0; + goto out; } @@ -324,8 +332,10 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, goto err; if (oldcard) { - if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0) + if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0) { + err = -ENOENT; goto err; + } card = oldcard; } else { @@ -333,8 +343,10 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, * Allocate card structure. */ card = mmc_alloc_card(host); - if (IS_ERR(card)) + if (IS_ERR(card)) { + err = PTR_ERR(card); goto err; + } card->type = MMC_TYPE_SD; memcpy(card->raw_cid, cid, sizeof(card->raw_cid)); @@ -358,7 +370,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, goto free_card; err = mmc_decode_csd(card); - if (err < 0) + if (err) goto free_card; mmc_decode_cid(card); @@ -449,7 +461,7 @@ free_card: mmc_remove_card(card); err: - return -EIO; + return err; } /* @@ -666,6 +678,6 @@ err: printk(KERN_ERR "%s: error %d whilst initialising SD card\n", mmc_hostname(host), err); - return 0; + return err; } -- cgit v1.2.3-70-g09d2 From d7604d76351f7745d0e62d9f2bbcbb917c9013f3 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 23 Jul 2007 00:34:07 +0200 Subject: mmc: read ext_csd version number Make sure we do not try to parse a structure we do not understand. Signed-off-by: Pierre Ossman --- drivers/mmc/core/mmc.c | 24 +++++++++++++++++------- include/linux/mmc/mmc.h | 1 + 2 files changed, 18 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 258fe73eeaa..cdc38b43b79 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -161,6 +161,7 @@ static int mmc_read_ext_csd(struct mmc_card *card) { int err; u8 *ext_csd; + unsigned int ext_csd_struct; BUG_ON(!card); @@ -209,13 +210,22 @@ static int mmc_read_ext_csd(struct mmc_card *card) goto out; } - card->ext_csd.sectors = - ext_csd[EXT_CSD_SEC_CNT + 0] << 0 | - ext_csd[EXT_CSD_SEC_CNT + 1] << 8 | - ext_csd[EXT_CSD_SEC_CNT + 2] << 16 | - ext_csd[EXT_CSD_SEC_CNT + 3] << 24; - if (card->ext_csd.sectors) - mmc_card_set_blockaddr(card); + ext_csd_struct = ext_csd[EXT_CSD_REV]; + if (ext_csd_struct > 2) { + printk("%s: unrecognised EXT_CSD structure version %d\n", + mmc_hostname(card->host), ext_csd_struct); + return -EINVAL; + } + + if (ext_csd_struct >= 2) { + card->ext_csd.sectors = + ext_csd[EXT_CSD_SEC_CNT + 0] << 0 | + ext_csd[EXT_CSD_SEC_CNT + 1] << 8 | + ext_csd[EXT_CSD_SEC_CNT + 2] << 16 | + ext_csd[EXT_CSD_SEC_CNT + 3] << 24; + if (card->ext_csd.sectors) + mmc_card_set_blockaddr(card); + } switch (ext_csd[EXT_CSD_CARD_TYPE]) { case EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26: diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h index e3ed9b95040..d1d6cbcc151 100644 --- a/include/linux/mmc/mmc.h +++ b/include/linux/mmc/mmc.h @@ -227,6 +227,7 @@ struct _mmc_csd { #define EXT_CSD_BUS_WIDTH 183 /* R/W */ #define EXT_CSD_HS_TIMING 185 /* R/W */ #define EXT_CSD_CARD_TYPE 196 /* RO */ +#define EXT_CSD_REV 192 /* RO */ #define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */ /* -- cgit v1.2.3-70-g09d2 From b146d26a61e0feab2f12a98ae83fd352830899c0 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 24 Jul 2007 19:16:54 +0200 Subject: mmc: mmc_set_data_timeout() parameter write is redundant The write parameter in mmc_set_data_timeout() is redundant as the data structure contains information about the direction of the transfer. Signed-off-by: Pierre Ossman --- drivers/mmc/card/block.c | 4 ++-- drivers/mmc/core/core.c | 8 +++----- drivers/mmc/core/mmc_ops.c | 2 +- drivers/mmc/core/sd_ops.c | 4 ++-- include/linux/mmc/core.h | 2 +- 5 files changed, 9 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 0da341acf32..9abf29f8435 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -229,8 +229,6 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) if (brq.data.blocks > card->host->max_blk_count) brq.data.blocks = card->host->max_blk_count; - mmc_set_data_timeout(&brq.data, card, rq_data_dir(req) != READ); - /* * If the host doesn't support multiple block writes, force * block writes to single block. SD cards are excepted from @@ -261,6 +259,8 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) brq.data.flags |= MMC_DATA_WRITE; } + mmc_set_data_timeout(&brq.data, card); + brq.data.sg = mq->sg; brq.data.sg_len = mmc_queue_map_sg(mq); diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 63b67296e92..51e611f2f33 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -220,13 +220,11 @@ EXPORT_SYMBOL(mmc_wait_for_cmd); * mmc_set_data_timeout - set the timeout for a data command * @data: data phase for command * @card: the MMC card associated with the data transfer - * @write: flag to differentiate reads from writes * * Computes the data timeout parameters according to the * correct algorithm given the card type. */ -void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card, - int write) +void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card) { unsigned int mult; @@ -239,7 +237,7 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card, * Scale up the multiplier (and therefore the timeout) by * the r2w factor for writes. */ - if (write) + if (data->flags & MMC_DATA_WRITE) mult <<= card->csd.r2w_factor; data->timeout_ns = card->csd.tacc_ns * mult; @@ -255,7 +253,7 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card, timeout_us += data->timeout_clks * 1000 / (card->host->ios.clock / 1000); - if (write) + if (data->flags & MMC_DATA_WRITE) limit_us = 250000; else limit_us = 100000; diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 15cd575effa..39567f91a4b 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -214,7 +214,7 @@ int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd) sg_init_one(&sg, ext_csd, 512); - mmc_set_data_timeout(&data, card, 0); + mmc_set_data_timeout(&data, card); mmc_wait_for_req(card->host, &mrq); diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c index b4d43bd0fed..491e0306b1b 100644 --- a/drivers/mmc/core/sd_ops.c +++ b/drivers/mmc/core/sd_ops.c @@ -252,7 +252,7 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr) sg_init_one(&sg, scr, 8); - mmc_set_data_timeout(&data, card, 0); + mmc_set_data_timeout(&data, card); mmc_wait_for_req(card->host, &mrq); @@ -302,7 +302,7 @@ int mmc_sd_switch(struct mmc_card *card, int mode, int group, sg_init_one(&sg, resp, 64); - mmc_set_data_timeout(&data, card, 0); + mmc_set_data_timeout(&data, card); mmc_wait_for_req(card->host, &mrq); diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index a2b79518f05..2a03f8b9cdf 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h @@ -111,7 +111,7 @@ extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int); extern int mmc_wait_for_app_cmd(struct mmc_host *, struct mmc_card *, struct mmc_command *, int); -extern void mmc_set_data_timeout(struct mmc_data *, const struct mmc_card *, int); +extern void mmc_set_data_timeout(struct mmc_data *, const struct mmc_card *); extern void mmc_claim_host(struct mmc_host *host); extern void mmc_release_host(struct mmc_host *host); -- cgit v1.2.3-70-g09d2 From 255d01af9a990fd5166f04ed0cc0b30b7b67e81e Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 24 Jul 2007 20:38:53 +0200 Subject: mmc: remove BYTEBLOCK capability Remove the BYTEBLOCK capability and let the broken hosts fail the requests with -EINVAL instead. Signed-off-by: Pierre Ossman --- drivers/mmc/host/at91_mci.c | 1 - drivers/mmc/host/imxmmc.c | 2 +- drivers/mmc/host/mmci.c | 8 ++++++++ drivers/mmc/host/sdhci.c | 2 +- drivers/mmc/host/tifm_sd.c | 13 ++++++++++--- drivers/mmc/host/wbsd.c | 2 +- include/linux/mmc/host.h | 5 ++--- 7 files changed, 23 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c index 810a433ce53..576d7cb0b3e 100644 --- a/drivers/mmc/host/at91_mci.c +++ b/drivers/mmc/host/at91_mci.c @@ -834,7 +834,6 @@ static int __init at91_mci_probe(struct platform_device *pdev) mmc->f_min = 375000; mmc->f_max = 25000000; mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; - mmc->caps = MMC_CAP_BYTEBLOCK; mmc->max_blk_size = 4095; mmc->max_blk_count = mmc->max_req_size; diff --git a/drivers/mmc/host/imxmmc.c b/drivers/mmc/host/imxmmc.c index 04458c34281..e33c123c702 100644 --- a/drivers/mmc/host/imxmmc.c +++ b/drivers/mmc/host/imxmmc.c @@ -963,7 +963,7 @@ static int imxmci_probe(struct platform_device *pdev) mmc->f_min = 150000; mmc->f_max = CLK_RATE/2; mmc->ocr_avail = MMC_VDD_32_33; - mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_BYTEBLOCK; + mmc->caps = MMC_CAP_4_BIT_DATA; /* MMC core transfer sizes tunable parameters */ mmc->max_hw_segs = 64; diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index d53e9a8bdaa..4a72772f4fe 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -391,6 +391,14 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq) WARN_ON(host->mrq != NULL); + if (mrq->data && (hweight32(mrq->data->blksz) > 1)) { + printk(KERN_ERR "%s: Unsupported block size (%d bytes)\n", + mmc_hostname(mmc), mrq->data->blksz); + mrq->cmd->error = -EINVAL; + mmc_request_done(mmc, mrq); + return; + } + spin_lock_irq(&host->lock); host->mrq = mrq; diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 479d6a265dd..c63edc5c17e 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1309,7 +1309,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) mmc->ops = &sdhci_ops; mmc->f_min = host->max_clk / 256; mmc->f_max = host->max_clk; - mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE | MMC_CAP_BYTEBLOCK; + mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE; if (caps & SDHCI_CAN_DO_HISPD) mmc->caps |= MMC_CAP_SD_HIGHSPEED; diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c index b4a56e5e513..951392d2ce3 100644 --- a/drivers/mmc/host/tifm_sd.c +++ b/drivers/mmc/host/tifm_sd.c @@ -626,14 +626,21 @@ static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq) spin_lock_irqsave(&sock->lock, flags); if (host->eject) { - spin_unlock_irqrestore(&sock->lock, flags); + mrq->cmd->error = -ENOMEDIUM; goto err_out; } if (host->req) { printk(KERN_ERR "%s : unfinished request detected\n", sock->dev.bus_id); - spin_unlock_irqrestore(&sock->lock, flags); + mrq->cmd->error = -ETIMEDOUT; + goto err_out; + } + + if (mrq->data && (hweight32(mrq->data->blksz) > 1)) { + printk(KERN_ERR "%s: Unsupported block size (%d bytes)\n", + sock->dev.bus_id, mrq->data->blksz); + mrq->cmd->error = -EINVAL; goto err_out; } @@ -722,7 +729,7 @@ static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq) return; err_out: - mrq->cmd->error = -ETIMEDOUT; + spin_unlock_irqrestore(&sock->lock, flags); mmc_request_done(mmc, mrq); } diff --git a/drivers/mmc/host/wbsd.c b/drivers/mmc/host/wbsd.c index 44968c2279e..80db11c05f2 100644 --- a/drivers/mmc/host/wbsd.c +++ b/drivers/mmc/host/wbsd.c @@ -1219,7 +1219,7 @@ static int __devinit wbsd_alloc_mmc(struct device *dev) mmc->f_min = 375000; mmc->f_max = 24000000; mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; - mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE | MMC_CAP_BYTEBLOCK; + mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE; spin_lock_init(&host->lock); diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index b1350dfd3e9..8e2642ebf02 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -87,9 +87,8 @@ struct mmc_host { #define MMC_CAP_4_BIT_DATA (1 << 0) /* Can the host do 4 bit transfers */ #define MMC_CAP_MULTIWRITE (1 << 1) /* Can accurately report bytes sent to card on error */ -#define MMC_CAP_BYTEBLOCK (1 << 2) /* Can do non-log2 block sizes */ -#define MMC_CAP_MMC_HIGHSPEED (1 << 3) /* Can do MMC high-speed timing */ -#define MMC_CAP_SD_HIGHSPEED (1 << 4) /* Can do SD high-speed timing */ +#define MMC_CAP_MMC_HIGHSPEED (1 << 2) /* Can do MMC high-speed timing */ +#define MMC_CAP_SD_HIGHSPEED (1 << 3) /* Can do SD high-speed timing */ /* host specific block data */ unsigned int max_seg_size; /* see blk_queue_max_segment_size */ -- cgit v1.2.3-70-g09d2 From be0192aae1aed3fbf172e3f9a22ec75392c1b175 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 24 Jul 2007 21:11:47 +0200 Subject: mmc: remove confusing flag The MMC_DATA_MULTI flag never had a proper definition of what it means, so remove it and let the drivers check the block count in the request. Signed-off-by: Pierre Ossman --- drivers/mmc/card/block.c | 1 - drivers/mmc/host/at91_mci.c | 4 ++-- drivers/mmc/host/au1xmmc.c | 26 ++++++++++++++------------ include/linux/mmc/core.h | 1 - 4 files changed, 16 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 9abf29f8435..ab510689ecd 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -241,7 +241,6 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) brq.data.blocks = 1; if (brq.data.blocks > 1) { - brq.data.flags |= MMC_DATA_MULTI; brq.mrq.stop = &brq.stop; readcmd = MMC_READ_MULTIPLE_BLOCK; writecmd = MMC_WRITE_MULTIPLE_BLOCK; diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c index 576d7cb0b3e..8ec31780234 100644 --- a/drivers/mmc/host/at91_mci.c +++ b/drivers/mmc/host/at91_mci.c @@ -328,7 +328,7 @@ static void at91_mci_handle_transmitted(struct at91mci_host *host) data = cmd->data; if (!data) return; - if (cmd->data->flags & MMC_DATA_MULTI) { + if (cmd->data->blocks > 1) { pr_debug("multiple write : wait for BLKE...\n"); at91_mci_write(host, AT91_MCI_IER, AT91_MCI_BLKE); } else @@ -439,7 +439,7 @@ static void at91_mci_send_command(struct at91mci_host *host, struct mmc_command if (data->flags & MMC_DATA_STREAM) cmdr |= AT91_MCI_TRTYP_STREAM; - if (data->flags & MMC_DATA_MULTI) + if (data->blocks > 1) cmdr |= AT91_MCI_TRTYP_MULTIPLE; } else { diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c index 49b0367e57c..92c4d0dfee4 100644 --- a/drivers/mmc/host/au1xmmc.c +++ b/drivers/mmc/host/au1xmmc.c @@ -186,7 +186,7 @@ static void au1xmmc_tasklet_finish(unsigned long param) } static int au1xmmc_send_command(struct au1xmmc_host *host, int wait, - struct mmc_command *cmd, unsigned int flags) + struct mmc_command *cmd, struct mmc_data *data) { u32 mmccmd = (cmd->opcode << SD_CMD_CI_SHIFT); @@ -211,16 +211,18 @@ static int au1xmmc_send_command(struct au1xmmc_host *host, int wait, return -EINVAL; } - if (flags & MMC_DATA_READ) { - if (flags & MMC_DATA_MULTI) - mmccmd |= SD_CMD_CT_4; - else - mmccmd |= SD_CMD_CT_2; - } else if (flags & MMC_DATA_WRITE) { - if (flags & MMC_DATA_MULTI) - mmccmd |= SD_CMD_CT_3; - else - mmccmd |= SD_CMD_CT_1; + if (data) { + if (flags & MMC_DATA_READ) { + if (data->blocks > 1) + mmccmd |= SD_CMD_CT_4; + else + mmccmd |= SD_CMD_CT_2; + } else if (flags & MMC_DATA_WRITE) { + if (data->blocks > 1) + mmccmd |= SD_CMD_CT_3; + else + mmccmd |= SD_CMD_CT_1; + } } au_writel(cmd->arg, HOST_CMDARG(host)); @@ -673,7 +675,7 @@ static void au1xmmc_request(struct mmc_host* mmc, struct mmc_request* mrq) } if (!ret) - ret = au1xmmc_send_command(host, 0, mrq->cmd, flags); + ret = au1xmmc_send_command(host, 0, mrq->cmd, mrq->data); if (ret) { mrq->cmd->error = ret; diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index 2a03f8b9cdf..29c98ae10af 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h @@ -83,7 +83,6 @@ struct mmc_data { #define MMC_DATA_WRITE (1 << 8) #define MMC_DATA_READ (1 << 9) #define MMC_DATA_STREAM (1 << 10) -#define MMC_DATA_MULTI (1 << 11) unsigned int bytes_xfered; -- cgit v1.2.3-70-g09d2 From 8fdd8521dcc9d89072f3ca5dca444560bcea39c6 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 24 Jul 2007 21:53:43 +0200 Subject: mmc: add missing printk levels Some printk:s were missing an explicit level. Signed-off-by: Pierre Ossman --- drivers/mmc/core/mmc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index cdc38b43b79..ba7a847cfd0 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -212,8 +212,9 @@ static int mmc_read_ext_csd(struct mmc_card *card) ext_csd_struct = ext_csd[EXT_CSD_REV]; if (ext_csd_struct > 2) { - printk("%s: unrecognised EXT_CSD structure version %d\n", - mmc_hostname(card->host), ext_csd_struct); + printk(KERN_ERR "%s: unrecognised EXT_CSD structure " + "version %d\n", mmc_hostname(card->host), + ext_csd_struct); return -EINVAL; } -- cgit v1.2.3-70-g09d2 From 1d4de9edd6c9ad676b20729ab15c04b78e9a50c5 Mon Sep 17 00:00:00 2001 From: Marc Pignat Date: Thu, 9 Aug 2007 13:56:29 +0200 Subject: mmc: at91_mci: disable handling of blocks with size not multiple of 4 bytes This kind of transfer is not supported, so don't advertise it and make it fail early. Signed-off-by: Marc Pignat Signed-off-by: Pierre Ossman --- drivers/mmc/host/at91_mci.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c index 8ec31780234..6ba98a49612 100644 --- a/drivers/mmc/host/at91_mci.c +++ b/drivers/mmc/host/at91_mci.c @@ -428,6 +428,14 @@ static void at91_mci_send_command(struct at91mci_host *host, struct mmc_command } if (data) { + + if ( data->blksz & 0x3 ) { + pr_debug("Unsupported block size\n"); + cmd->error = -EINVAL; + mmc_request_done(host->mmc, host->request); + return; + } + block_length = data->blksz; blocks = data->blocks; -- cgit v1.2.3-70-g09d2 From 5c4e6f1301649d5b29dd0f70e6da83e728ab5ca5 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 21 May 2007 20:23:20 +0200 Subject: mmc: detect SDIO cards Really basic init sequence for SDIO cards. Signed-off-by: Pierre Ossman --- MAINTAINERS | 2 +- drivers/mmc/core/Makefile | 3 +- drivers/mmc/core/bus.c | 8 ++ drivers/mmc/core/core.c | 40 +++++++--- drivers/mmc/core/sdio.c | 176 ++++++++++++++++++++++++++++++++++++++++++++ drivers/mmc/core/sdio_ops.c | 49 ++++++++++++ drivers/mmc/core/sdio_ops.h | 18 +++++ include/linux/mmc/card.h | 2 + include/linux/mmc/core.h | 1 + include/linux/mmc/sdio.h | 19 +++++ 10 files changed, 304 insertions(+), 14 deletions(-) create mode 100644 drivers/mmc/core/sdio.c create mode 100644 drivers/mmc/core/sdio_ops.c create mode 100644 drivers/mmc/core/sdio_ops.h create mode 100644 include/linux/mmc/sdio.h (limited to 'drivers') diff --git a/MAINTAINERS b/MAINTAINERS index 9a91d9e3f1f..c22d34b11f6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2561,7 +2561,7 @@ L: linux-kernel@vger.kernel.org W: http://www.atnf.csiro.au/~rgooch/linux/kernel-patches.html S: Maintained -MULTIMEDIA CARD (MMC) AND SECURE DIGITAL (SD) SUBSYSTEM +MULTIMEDIA CARD (MMC), SECURE DIGITAL (SD) AND SDIO SUBSYSTEM P: Pierre Ossman M: drzeus-mmc@drzeus.cx L: linux-kernel@vger.kernel.org diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile index 3fdd08c7f14..2fa5ebbc170 100644 --- a/drivers/mmc/core/Makefile +++ b/drivers/mmc/core/Makefile @@ -8,5 +8,6 @@ endif obj-$(CONFIG_MMC) += mmc_core.o mmc_core-y := core.o sysfs.o bus.o host.o \ - mmc.o mmc_ops.o sd.o sd_ops.o + mmc.o mmc_ops.o sd.o sd_ops.o \ + sdio.o sdio_ops.o diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 817a79462b3..87a6070522f 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -34,6 +34,8 @@ static ssize_t mmc_type_show(struct device *dev, return sprintf(buf, "MMC\n"); case MMC_TYPE_SD: return sprintf(buf, "SD\n"); + case MMC_TYPE_SDIO: + return sprintf(buf, "SDIO\n"); default: return -EFAULT; } @@ -76,6 +78,9 @@ mmc_bus_uevent(struct device *dev, char **envp, int num_envp, char *buf, case MMC_TYPE_SD: add_env("MMC_TYPE=%s", "SD"); break; + case MMC_TYPE_SDIO: + add_env("MMC_TYPE=%s", "SDIO"); + break; } add_env("MMC_NAME=%s", mmc_card_name(card)); @@ -221,6 +226,9 @@ int mmc_add_card(struct mmc_card *card) if (mmc_card_blockaddr(card)) type = "SDHC"; break; + case MMC_TYPE_SDIO: + type = "SDIO"; + break; default: type = "?"; break; diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 51e611f2f33..092fa906ab8 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -32,9 +32,11 @@ #include "mmc_ops.h" #include "sd_ops.h" +#include "sdio_ops.h" extern int mmc_attach_mmc(struct mmc_host *host, u32 ocr); extern int mmc_attach_sd(struct mmc_host *host, u32 ocr); +extern int mmc_attach_sdio(struct mmc_host *host, u32 ocr); static struct workqueue_struct *workqueue; @@ -595,24 +597,38 @@ void mmc_rescan(struct work_struct *work) mmc_send_if_cond(host, host->ocr_avail); + /* + * First we search for SDIO... + */ + err = mmc_send_io_op_cond(host, 0, &ocr); + if (!err) { + if (mmc_attach_sdio(host, ocr)) + mmc_power_off(host); + return; + } + + /* + * ...then normal SD... + */ err = mmc_send_app_op_cond(host, 0, &ocr); if (!err) { if (mmc_attach_sd(host, ocr)) mmc_power_off(host); - } else { - /* - * If we fail to detect any SD cards then try - * searching for MMC cards. - */ - err = mmc_send_op_cond(host, 0, &ocr); - if (!err) { - if (mmc_attach_mmc(host, ocr)) - mmc_power_off(host); - } else { + return; + } + + /* + * ...and finally MMC. + */ + err = mmc_send_op_cond(host, 0, &ocr); + if (!err) { + if (mmc_attach_mmc(host, ocr)) mmc_power_off(host); - mmc_release_host(host); - } + return; } + + mmc_release_host(host); + mmc_power_off(host); } else { if (host->bus_ops->detect && !host->bus_dead) host->bus_ops->detect(host); diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c new file mode 100644 index 00000000000..ac0dd68df8e --- /dev/null +++ b/drivers/mmc/core/sdio.c @@ -0,0 +1,176 @@ +/* + * linux/drivers/mmc/sdio.c + * + * Copyright 2006-2007 Pierre Ossman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + */ + +#include + +#include +#include + +#include "core.h" +#include "bus.h" +#include "mmc_ops.h" +#include "sd_ops.h" +#include "sdio_ops.h" + +/* + * Host is being removed. Free up the current card. + */ +static void mmc_sdio_remove(struct mmc_host *host) +{ + BUG_ON(!host); + BUG_ON(!host->card); + + mmc_remove_card(host->card); + host->card = NULL; +} + +/* + * Card detection callback from host. + */ +static void mmc_sdio_detect(struct mmc_host *host) +{ + int err; + + BUG_ON(!host); + BUG_ON(!host->card); + + mmc_claim_host(host); + + /* + * Just check if our card has been removed. + */ + err = mmc_select_card(host->card); + + mmc_release_host(host); + + if (err) { + mmc_sdio_remove(host); + + mmc_claim_host(host); + mmc_detach_bus(host); + mmc_release_host(host); + } +} + + +static const struct mmc_bus_ops mmc_sdio_ops = { + .remove = mmc_sdio_remove, + .detect = mmc_sdio_detect, +}; + + +/* + * Starting point for SDIO card init. + */ +int mmc_attach_sdio(struct mmc_host *host, u32 ocr) +{ + int err; + int funcs; + struct mmc_card *card; + + BUG_ON(!host); + BUG_ON(!host->claimed); + + mmc_attach_bus(host, &mmc_sdio_ops); + + /* + * Sanity check the voltages that the card claims to + * support. + */ + if (ocr & 0x7F) { + printk(KERN_WARNING "%s: card claims to support voltages " + "below the defined range. These will be ignored.\n", + mmc_hostname(host)); + ocr &= ~0x7F; + } + + if (ocr & MMC_VDD_165_195) { + printk(KERN_WARNING "%s: SDIO card claims to support the " + "incompletely defined 'low voltage range'. This " + "will be ignored.\n", mmc_hostname(host)); + ocr &= ~MMC_VDD_165_195; + } + + host->ocr = mmc_select_voltage(host, ocr); + + /* + * Can we support the voltage(s) of the card(s)? + */ + if (!host->ocr) { + err = -EINVAL; + goto err; + } + + /* + * Inform the card of the voltage + */ + err = mmc_send_io_op_cond(host, host->ocr, &ocr); + if (err) + goto err; + + /* + * The number of functions on the card is encoded inside + * the ocr. + */ + funcs = (ocr & 0x70000000) >> 28; + + /* + * Allocate card structure. + */ + card = mmc_alloc_card(host); + if (IS_ERR(card)) { + err = PTR_ERR(card); + goto err; + } + + card->type = MMC_TYPE_SDIO; + + /* + * Set card RCA. + */ + err = mmc_send_relative_addr(host, &card->rca); + if (err) + goto free_card; + + mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); + + /* + * Select card, as all following commands rely on that. + */ + err = mmc_select_card(card); + if (err) + goto free_card; + + host->card = card; + + mmc_release_host(host); + + err = mmc_add_card(host->card); + if (err) + goto reclaim_host; + + return 0; + +reclaim_host: + mmc_claim_host(host); +free_card: + mmc_remove_card(card); + host->card = NULL; +err: + mmc_detach_bus(host); + mmc_release_host(host); + + printk(KERN_ERR "%s: error %d whilst initialising SDIO card\n", + mmc_hostname(host), err); + + return err; +} + diff --git a/drivers/mmc/core/sdio_ops.c b/drivers/mmc/core/sdio_ops.c new file mode 100644 index 00000000000..d6f9f9d8517 --- /dev/null +++ b/drivers/mmc/core/sdio_ops.c @@ -0,0 +1,49 @@ +/* + * linux/drivers/mmc/sdio_ops.c + * + * Copyright 2006-2007 Pierre Ossman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + */ + +#include +#include +#include + +#include "core.h" + +int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) +{ + struct mmc_command cmd; + int i, err = 0; + + BUG_ON(!host); + + memset(&cmd, 0, sizeof(struct mmc_command)); + + cmd.opcode = SD_IO_SEND_OP_COND; + cmd.arg = ocr; + cmd.flags = MMC_RSP_R4 | MMC_CMD_BCR; + + for (i = 100; i; i--) { + err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES); + if (err) + break; + + if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0) + break; + + err = -ETIMEDOUT; + + mmc_delay(10); + } + + if (rocr) + *rocr = cmd.resp[0]; + + return err; +} + diff --git a/drivers/mmc/core/sdio_ops.h b/drivers/mmc/core/sdio_ops.h new file mode 100644 index 00000000000..d8c982976f1 --- /dev/null +++ b/drivers/mmc/core/sdio_ops.h @@ -0,0 +1,18 @@ +/* + * linux/drivers/mmc/sdio_ops.c + * + * Copyright 2006-2007 Pierre Ossman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + */ + +#ifndef _MMC_SDIO_OPS_H +#define _MMC_SDIO_OPS_H + +int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr); + +#endif + diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index badf702fcff..43480ebebf9 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -67,6 +67,7 @@ struct mmc_card { unsigned int type; /* card type */ #define MMC_TYPE_MMC 0 /* MMC card */ #define MMC_TYPE_SD 1 /* SD card */ +#define MMC_TYPE_SDIO 2 /* SDIO card */ unsigned int state; /* (our) card state */ #define MMC_STATE_PRESENT (1<<0) /* present in sysfs */ #define MMC_STATE_READONLY (1<<1) /* card is read-only */ @@ -84,6 +85,7 @@ struct mmc_card { #define mmc_card_mmc(c) ((c)->type == MMC_TYPE_MMC) #define mmc_card_sd(c) ((c)->type == MMC_TYPE_SD) +#define mmc_card_sdio(c) ((c)->type == MMC_TYPE_SDIO) #define mmc_card_present(c) ((c)->state & MMC_STATE_PRESENT) #define mmc_card_readonly(c) ((c)->state & MMC_STATE_READONLY) diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index 29c98ae10af..8faa436c557 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h @@ -41,6 +41,7 @@ struct mmc_command { #define MMC_RSP_R1B (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE|MMC_RSP_BUSY) #define MMC_RSP_R2 (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC) #define MMC_RSP_R3 (MMC_RSP_PRESENT) +#define MMC_RSP_R4 (MMC_RSP_PRESENT) #define MMC_RSP_R6 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE) #define MMC_RSP_R7 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE) diff --git a/include/linux/mmc/sdio.h b/include/linux/mmc/sdio.h new file mode 100644 index 00000000000..d1a0b15cdfd --- /dev/null +++ b/include/linux/mmc/sdio.h @@ -0,0 +1,19 @@ +/* + * include/linux/mmc/sdio.h + * + * Copyright 2006-2007 Pierre Ossman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + */ + +#ifndef MMC_SDIO_H +#define MMC_SDIO_H + +/* SDIO commands type argument response */ +#define SD_IO_SEND_OP_COND 5 /* bcr [23:0] OCR R4 */ + +#endif + -- cgit v1.2.3-70-g09d2 From b2bcc798bbb482b2909801280f3c4aff8cbbf5be Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 22 May 2007 20:25:21 +0200 Subject: mmc: implement SDIO IO_RW_DIRECT operation Signed-off-by: Pierre Ossman --- drivers/mmc/core/sdio_ops.c | 37 +++++++++++++++++++++++++++++++++++++ drivers/mmc/core/sdio_ops.h | 2 ++ include/linux/mmc/core.h | 1 + include/linux/mmc/sdio.h | 34 ++++++++++++++++++++++++++++++++++ 4 files changed, 74 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/core/sdio_ops.c b/drivers/mmc/core/sdio_ops.c index d6f9f9d8517..31233f7b55c 100644 --- a/drivers/mmc/core/sdio_ops.c +++ b/drivers/mmc/core/sdio_ops.c @@ -10,6 +10,7 @@ */ #include +#include #include #include @@ -47,3 +48,39 @@ int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) return err; } +int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, + unsigned addr, u8 in, u8* out) +{ + struct mmc_command cmd; + int err; + + BUG_ON(!card); + BUG_ON(fn > 7); + + memset(&cmd, 0, sizeof(struct mmc_command)); + + cmd.opcode = SD_IO_RW_DIRECT; + cmd.arg = write ? 0x80000000 : 0x00000000; + cmd.arg |= fn << 28; + cmd.arg |= (write && out) ? 0x08000000 : 0x00000000; + cmd.arg |= addr << 9; + cmd.arg |= in; + cmd.flags = MMC_RSP_R5 | MMC_CMD_AC; + + err = mmc_wait_for_cmd(card->host, &cmd, 0); + if (err) + return err; + + if (cmd.resp[0] & R5_ERROR) + return -EIO; + if (cmd.resp[0] & R5_FUNCTION_NUMBER) + return -EINVAL; + if (cmd.resp[0] & R5_OUT_OF_RANGE) + return -ERANGE; + + if (out) + *out = cmd.resp[0] & 0xFF; + + return 0; +} + diff --git a/drivers/mmc/core/sdio_ops.h b/drivers/mmc/core/sdio_ops.h index d8c982976f1..f0e9d69e5ce 100644 --- a/drivers/mmc/core/sdio_ops.h +++ b/drivers/mmc/core/sdio_ops.h @@ -13,6 +13,8 @@ #define _MMC_SDIO_OPS_H int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr); +int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, + unsigned addr, u8 in, u8* out); #endif diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index 8faa436c557..43a92736be6 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h @@ -42,6 +42,7 @@ struct mmc_command { #define MMC_RSP_R2 (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC) #define MMC_RSP_R3 (MMC_RSP_PRESENT) #define MMC_RSP_R4 (MMC_RSP_PRESENT) +#define MMC_RSP_R5 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE) #define MMC_RSP_R6 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE) #define MMC_RSP_R7 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE) diff --git a/include/linux/mmc/sdio.h b/include/linux/mmc/sdio.h index d1a0b15cdfd..e5f06de7d52 100644 --- a/include/linux/mmc/sdio.h +++ b/include/linux/mmc/sdio.h @@ -14,6 +14,40 @@ /* SDIO commands type argument response */ #define SD_IO_SEND_OP_COND 5 /* bcr [23:0] OCR R4 */ +#define SD_IO_RW_DIRECT 52 /* ac [31:0] See below R5 */ + +/* + * SD_IO_RW_DIRECT argument format: + * + * [31] R/W flag + * [30:28] Function number + * [27] RAW flag + * [25:9] Register address + * [7:0] Data + */ + +/* + SDIO status in R5 + Type + e : error bit + s : status bit + r : detected and set for the actual command response + x : detected and set during command execution. the host must poll + the card by sending status command in order to read these bits. + Clear condition + a : according to the card state + b : always related to the previous command. Reception of + a valid command will clear it (with a delay of one command) + c : clear by read + */ + +#define R5_COM_CRC_ERROR (1 << 15) /* er, b */ +#define R5_ILLEGAL_COMMAND (1 << 14) /* er, b */ +#define R5_ERROR (1 << 11) /* erx, c */ +#define R5_FUNCTION_NUMBER (1 << 9) /* er, c */ +#define R5_OUT_OF_RANGE (1 << 8) /* er, c */ +#define R5_STATUS(x) (x & 0xCB00) +#define R5_IO_CURRENT_STATE(x) ((x & 0x3000) >> 12) /* s, b */ #endif -- cgit v1.2.3-70-g09d2 From e29a7d73f4277eb92aa64e17017dea33460828ef Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sat, 26 May 2007 13:48:18 +0200 Subject: mmc: basic SDIO device model Add the sdio bus type and basic device handling. Signed-off-by: Pierre Ossman --- drivers/mmc/core/Makefile | 2 +- drivers/mmc/core/core.c | 27 +++++++-- drivers/mmc/core/sdio.c | 72 ++++++++++++++++++++--- drivers/mmc/core/sdio_bus.c | 129 ++++++++++++++++++++++++++++++++++++++++++ drivers/mmc/core/sdio_bus.h | 22 +++++++ include/linux/mmc/card.h | 7 +++ include/linux/mmc/sdio_func.h | 35 ++++++++++++ 7 files changed, 279 insertions(+), 15 deletions(-) create mode 100644 drivers/mmc/core/sdio_bus.c create mode 100644 drivers/mmc/core/sdio_bus.h create mode 100644 include/linux/mmc/sdio_func.h (limited to 'drivers') diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile index 2fa5ebbc170..71ab3d1e1eb 100644 --- a/drivers/mmc/core/Makefile +++ b/drivers/mmc/core/Makefile @@ -9,5 +9,5 @@ endif obj-$(CONFIG_MMC) += mmc_core.o mmc_core-y := core.o sysfs.o bus.o host.o \ mmc.o mmc_ops.o sd.o sd_ops.o \ - sdio.o sdio_ops.o + sdio.o sdio_ops.o sdio_bus.o diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 092fa906ab8..9747455928d 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -29,6 +29,7 @@ #include "core.h" #include "bus.h" #include "host.h" +#include "sdio_bus.h" #include "mmc_ops.h" #include "sd_ops.h" @@ -739,16 +740,32 @@ static int __init mmc_init(void) return -ENOMEM; ret = mmc_register_bus(); - if (ret == 0) { - ret = mmc_register_host_class(); - if (ret) - mmc_unregister_bus(); - } + if (ret) + goto destroy_workqueue; + + ret = mmc_register_host_class(); + if (ret) + goto unregister_bus; + + ret = sdio_register_bus(); + if (ret) + goto unregister_host_class; + + return 0; + +unregister_host_class: + mmc_unregister_host_class(); +unregister_bus: + mmc_unregister_bus(); +destroy_workqueue: + destroy_workqueue(workqueue); + return ret; } static void __exit mmc_exit(void) { + sdio_unregister_bus(); mmc_unregister_host_class(); mmc_unregister_bus(); destroy_workqueue(workqueue); diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index ac0dd68df8e..444328581ce 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -13,21 +13,49 @@ #include #include +#include #include "core.h" #include "bus.h" +#include "sdio_bus.h" #include "mmc_ops.h" #include "sd_ops.h" #include "sdio_ops.h" +static int sdio_init_func(struct mmc_card *card, unsigned int fn) +{ + struct sdio_func *func; + + BUG_ON(fn > SDIO_MAX_FUNCS); + + func = sdio_alloc_func(card); + if (IS_ERR(func)) + return PTR_ERR(func); + + func->num = fn; + + card->sdio_func[fn - 1] = func; + + return 0; +} + /* * Host is being removed. Free up the current card. */ static void mmc_sdio_remove(struct mmc_host *host) { + int i; + BUG_ON(!host); BUG_ON(!host->card); + for (i = 0;i < host->card->sdio_funcs;i++) { + if (host->card->sdio_func[i]) { + sdio_remove_func(host->card->sdio_func[i]); + host->card->sdio_func[i] = NULL; + } + } + mmc_remove_card(host->card); host->card = NULL; } @@ -73,7 +101,7 @@ static const struct mmc_bus_ops mmc_sdio_ops = { int mmc_attach_sdio(struct mmc_host *host, u32 ocr) { int err; - int funcs; + int i, funcs; struct mmc_card *card; BUG_ON(!host); @@ -132,13 +160,16 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr) } card->type = MMC_TYPE_SDIO; + card->sdio_funcs = funcs; + + host->card = card; /* * Set card RCA. */ err = mmc_send_relative_addr(host, &card->rca); if (err) - goto free_card; + goto remove; mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); @@ -147,23 +178,46 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr) */ err = mmc_select_card(card); if (err) - goto free_card; + goto remove; - host->card = card; + /* + * Initialize (but don't add) all present functions. + */ + for (i = 0;i < funcs;i++) { + err = sdio_init_func(host->card, i + 1); + if (err) + goto remove; + } mmc_release_host(host); + /* + * First add the card to the driver model... + */ err = mmc_add_card(host->card); if (err) - goto reclaim_host; + goto remove_added; + + /* + * ...then the SDIO functions. + */ + for (i = 0;i < funcs;i++) { + err = sdio_add_func(host->card->sdio_func[i]); + if (err) + goto remove_added; + } return 0; -reclaim_host: + +remove_added: + /* Remove without lock if the device has been added. */ + mmc_sdio_remove(host); mmc_claim_host(host); -free_card: - mmc_remove_card(card); - host->card = NULL; +remove: + /* And with lock if it hasn't been added. */ + if (host->card) + mmc_sdio_remove(host); err: mmc_detach_bus(host); mmc_release_host(host); diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c new file mode 100644 index 00000000000..59c909e1c7c --- /dev/null +++ b/drivers/mmc/core/sdio_bus.c @@ -0,0 +1,129 @@ +/* + * linux/drivers/mmc/core/sdio_bus.c + * + * Copyright 2007 Pierre Ossman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * SDIO function driver model + */ + +#include +#include + +#include +#include + +#include "sdio_bus.h" + +#define dev_to_sdio_func(d) container_of(d, struct sdio_func, dev) + +/* + * This currently matches any SDIO function to any driver in order + * to help initial development and testing. + */ +static int sdio_bus_match(struct device *dev, struct device_driver *drv) +{ + return 1; +} + +static int +sdio_bus_uevent(struct device *dev, char **envp, int num_envp, char *buf, + int buf_size) +{ + envp[0] = NULL; + + return 0; +} + +static int sdio_bus_probe(struct device *dev) +{ + return -ENODEV; +} + +static int sdio_bus_remove(struct device *dev) +{ + return 0; +} + +static struct bus_type sdio_bus_type = { + .name = "sdio", + .match = sdio_bus_match, + .uevent = sdio_bus_uevent, + .probe = sdio_bus_probe, + .remove = sdio_bus_remove, +}; + +int sdio_register_bus(void) +{ + return bus_register(&sdio_bus_type); +} + +void sdio_unregister_bus(void) +{ + bus_unregister(&sdio_bus_type); +} + +static void sdio_release_func(struct device *dev) +{ + struct sdio_func *func = dev_to_sdio_func(dev); + + kfree(func); +} + +/* + * Allocate and initialise a new SDIO function structure. + */ +struct sdio_func *sdio_alloc_func(struct mmc_card *card) +{ + struct sdio_func *func; + + func = kmalloc(sizeof(struct sdio_func), GFP_KERNEL); + if (!func) + return ERR_PTR(-ENOMEM); + + memset(func, 0, sizeof(struct sdio_func)); + + func->card = card; + + device_initialize(&func->dev); + + func->dev.parent = &card->dev; + func->dev.bus = &sdio_bus_type; + func->dev.release = sdio_release_func; + + return func; +} + +/* + * Register a new SDIO function with the driver model. + */ +int sdio_add_func(struct sdio_func *func) +{ + int ret; + + snprintf(func->dev.bus_id, sizeof(func->dev.bus_id), + "%s:%d", mmc_card_id(func->card), func->num); + + ret = device_add(&func->dev); + if (ret == 0) + sdio_func_set_present(func); + + return ret; +} + +/* + * Unregister a SDIO function with the driver model, and + * (eventually) free it. + */ +void sdio_remove_func(struct sdio_func *func) +{ + if (sdio_func_present(func)) + device_del(&func->dev); + + put_device(&func->dev); +} + diff --git a/drivers/mmc/core/sdio_bus.h b/drivers/mmc/core/sdio_bus.h new file mode 100644 index 00000000000..567a76821ba --- /dev/null +++ b/drivers/mmc/core/sdio_bus.h @@ -0,0 +1,22 @@ +/* + * linux/drivers/mmc/core/sdio_bus.h + * + * Copyright 2007 Pierre Ossman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + */ +#ifndef _MMC_CORE_SDIO_BUS_H +#define _MMC_CORE_SDIO_BUS_H + +struct sdio_func *sdio_alloc_func(struct mmc_card *card); +int sdio_add_func(struct sdio_func *func); +void sdio_remove_func(struct sdio_func *func); + +int sdio_register_bus(void); +void sdio_unregister_bus(void); + +#endif + diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 43480ebebf9..9f5f74482d9 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -56,6 +56,9 @@ struct sd_switch_caps { }; struct mmc_host; +struct sdio_func; + +#define SDIO_MAX_FUNCS 7 /* * MMC device @@ -73,6 +76,7 @@ struct mmc_card { #define MMC_STATE_READONLY (1<<1) /* card is read-only */ #define MMC_STATE_HIGHSPEED (1<<2) /* card is in high speed mode */ #define MMC_STATE_BLOCKADDR (1<<3) /* card uses block-addressing */ + u32 raw_cid[4]; /* raw card CID */ u32 raw_csd[4]; /* raw card CSD */ u32 raw_scr[2]; /* raw card SCR */ @@ -81,6 +85,9 @@ struct mmc_card { struct mmc_ext_csd ext_csd; /* mmc v4 extended card specific */ struct sd_scr scr; /* extra SD information */ struct sd_switch_caps sw_caps; /* switch (CMD6) caps */ + + unsigned int sdio_funcs; /* number of SDIO functions */ + struct sdio_func *sdio_func[SDIO_MAX_FUNCS]; /* SDIO functions (devices) */ }; #define mmc_card_mmc(c) ((c)->type == MMC_TYPE_MMC) diff --git a/include/linux/mmc/sdio_func.h b/include/linux/mmc/sdio_func.h new file mode 100644 index 00000000000..50c78db420e --- /dev/null +++ b/include/linux/mmc/sdio_func.h @@ -0,0 +1,35 @@ +/* + * include/linux/mmc/sdio_func.h + * + * Copyright 2007 Pierre Ossman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + */ + +#ifndef MMC_SDIO_FUNC_H +#define MMC_SDIO_FUNC_H + +struct mmc_card; + +/* + * SDIO function devices + */ +struct sdio_func { + struct mmc_card *card; /* the card this device belongs to */ + struct device dev; /* the device */ + unsigned int num; /* function number */ + unsigned int state; /* function state */ +#define SDIO_STATE_PRESENT (1<<0) /* present in sysfs */ +}; + +#define sdio_func_present(f) ((f)->state & SDIO_STATE_PRESENT) + +#define sdio_func_set_present(f) ((f)->state |= SDIO_STATE_PRESENT) + +#define sdio_func_id(f) ((f)->dev.bus_id) + +#endif + -- cgit v1.2.3-70-g09d2 From f76c85154d320497bf1a939a98d6c432edcbd4a9 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 27 May 2007 12:00:02 +0200 Subject: mmc: add SDIO driver handling Add basic driver handling to the SDIO device model. Signed-off-by: Pierre Ossman --- drivers/mmc/core/sdio_bus.c | 23 +++++++++++++++++++++++ include/linux/mmc/sdio_func.h | 18 ++++++++++++++++++ 2 files changed, 41 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 59c909e1c7c..fa488cea859 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -67,6 +67,29 @@ void sdio_unregister_bus(void) bus_unregister(&sdio_bus_type); } +/** + * sdio_register_driver - register a function driver + * @drv: SDIO function driver + */ +int sdio_register_driver(struct sdio_driver *drv) +{ + drv->drv.name = drv->name; + drv->drv.bus = &sdio_bus_type; + return driver_register(&drv->drv); +} +EXPORT_SYMBOL_GPL(sdio_register_driver); + +/** + * sdio_unregister_driver - unregister a function driver + * @drv: SDIO function driver + */ +void sdio_unregister_driver(struct sdio_driver *drv) +{ + drv->drv.bus = &sdio_bus_type; + driver_unregister(&drv->drv); +} +EXPORT_SYMBOL_GPL(sdio_unregister_driver); + static void sdio_release_func(struct device *dev) { struct sdio_func *func = dev_to_sdio_func(dev); diff --git a/include/linux/mmc/sdio_func.h b/include/linux/mmc/sdio_func.h index 50c78db420e..13a1a9ca4b6 100644 --- a/include/linux/mmc/sdio_func.h +++ b/include/linux/mmc/sdio_func.h @@ -31,5 +31,23 @@ struct sdio_func { #define sdio_func_id(f) ((f)->dev.bus_id) +#define sdio_get_drvdata(f) dev_get_drvdata(&(f)->dev) +#define sdio_set_drvdata(f,d) dev_set_drvdata(&(f)->dev, d) + +/* + * SDIO function device driver + */ +struct sdio_driver { + char *name; + + int (*probe)(struct sdio_func *); + void (*remove)(struct sdio_func *); + + struct device_driver drv; +}; + +extern int sdio_register_driver(struct sdio_driver *); +extern void sdio_unregister_driver(struct sdio_driver *); + #endif -- cgit v1.2.3-70-g09d2 From 46f555f2731a14545a09ec06d27bd18e8e07069f Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 27 May 2007 12:57:15 +0200 Subject: mmc: add basic SDIO I/O operations Add command wrappers that simplify register access from SDIO function drivers. Signed-off-by: Pierre Ossman --- drivers/mmc/core/Makefile | 3 +- drivers/mmc/core/sdio_io.c | 105 ++++++++++++++++++++++++++++++++++++++++++ include/linux/mmc/sdio_func.h | 12 +++++ 3 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 drivers/mmc/core/sdio_io.c (limited to 'drivers') diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile index 71ab3d1e1eb..bf7a0024803 100644 --- a/drivers/mmc/core/Makefile +++ b/drivers/mmc/core/Makefile @@ -9,5 +9,6 @@ endif obj-$(CONFIG_MMC) += mmc_core.o mmc_core-y := core.o sysfs.o bus.o host.o \ mmc.o mmc_ops.o sd.o sd_ops.o \ - sdio.o sdio_ops.o sdio_bus.o + sdio.o sdio_ops.o sdio_bus.o \ + sdio_io.o diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c new file mode 100644 index 00000000000..4ad06e57563 --- /dev/null +++ b/drivers/mmc/core/sdio_io.c @@ -0,0 +1,105 @@ +/* + * linux/drivers/mmc/core/sdio_io.c + * + * Copyright 2007 Pierre Ossman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + */ + +#include +#include +#include + +#include "sdio_ops.h" + +/** + * sdio_claim_host - exclusively claim a bus for a certain SDIO function + * @func: SDIO function that will be accessed + * + * Claim a bus for a set of operations. The SDIO function given + * is used to figure out which bus is relevant. + */ +void sdio_claim_host(struct sdio_func *func) +{ + BUG_ON(!func); + BUG_ON(!func->card); + + mmc_claim_host(func->card->host); +} +EXPORT_SYMBOL_GPL(sdio_claim_host); + +/** + * sdio_release_host - release a bus for a certain SDIO function + * @func: SDIO function that was accessed + * + * Release a bus, allowing others to claim the bus for their + * operations. + */ +void sdio_release_host(struct sdio_func *func) +{ + BUG_ON(!func); + BUG_ON(!func->card); + + mmc_release_host(func->card->host); +} +EXPORT_SYMBOL_GPL(sdio_release_host); + +/** + * sdio_readb - read a single byte from a SDIO function + * @func: SDIO function to access + * @addr: address to read + * @err_ret: optional status value from transfer + * + * Reads a single byte from the address space of a given SDIO + * function. If there is a problem reading the address, 0xff + * is returned and @err_ret will contain the error code. + */ +unsigned char sdio_readb(struct sdio_func *func, unsigned int addr, + int *err_ret) +{ + int ret; + unsigned char val; + + BUG_ON(!func); + + if (err_ret) + *err_ret = 0; + + ret = mmc_io_rw_direct(func->card, 0, func->num, addr, 0, &val); + if (ret) { + if (err_ret) + *err_ret = ret; + return 0xFF; + } + + return val; +} +EXPORT_SYMBOL_GPL(sdio_readb); + +/** + * sdio_writeb - write a single byte to a SDIO function + * @func: SDIO function to access + * @b: byte to write + * @addr: address to write to + * @err_ret: optional status value from transfer + * + * Writes a single byte to the address space of a given SDIO + * function. @err_ret will contain the status of the actual + * transfer. + */ +void sdio_writeb(struct sdio_func *func, unsigned char b, unsigned int addr, + int *err_ret) +{ + int ret; + + BUG_ON(!func); + + ret = mmc_io_rw_direct(func->card, 1, func->num, addr, b, NULL); + if (err_ret) + *err_ret = ret; +} +EXPORT_SYMBOL_GPL(sdio_writeb); + diff --git a/include/linux/mmc/sdio_func.h b/include/linux/mmc/sdio_func.h index 13a1a9ca4b6..5c56df19628 100644 --- a/include/linux/mmc/sdio_func.h +++ b/include/linux/mmc/sdio_func.h @@ -49,5 +49,17 @@ struct sdio_driver { extern int sdio_register_driver(struct sdio_driver *); extern void sdio_unregister_driver(struct sdio_driver *); +/* + * SDIO I/O operations + */ +extern void sdio_claim_host(struct sdio_func *func); +extern void sdio_release_host(struct sdio_func *func); + +extern unsigned char sdio_readb(struct sdio_func *func, + unsigned int addr, int *err_ret); + +extern void sdio_writeb(struct sdio_func *func, unsigned char b, + unsigned int addr, int *err_ret); + #endif -- cgit v1.2.3-70-g09d2 From fa64efa1f2a0672767ad0753a6e4bfa4bcc77b87 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 27 May 2007 14:22:37 +0200 Subject: mmc: enable/disable functions for SDIO Like many other buses, the devices (functions) on the SDIO bus must be enabled before they can be used. Add functions that allow drivers to do so. Signed-off-by: Pierre Ossman --- drivers/mmc/core/sdio_io.c | 93 +++++++++++++++++++++++++++++++++++++++++++ include/linux/mmc/sdio.h | 92 ++++++++++++++++++++++++++++++++++++++++++ include/linux/mmc/sdio_func.h | 3 ++ 3 files changed, 188 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c index 4ad06e57563..eb6c20935ce 100644 --- a/drivers/mmc/core/sdio_io.c +++ b/drivers/mmc/core/sdio_io.c @@ -11,6 +11,7 @@ #include #include +#include #include #include "sdio_ops.h" @@ -47,6 +48,98 @@ void sdio_release_host(struct sdio_func *func) } EXPORT_SYMBOL_GPL(sdio_release_host); +/** + * sdio_enable_func - enables a SDIO function for usage + * @func: SDIO function to enable + * + * Powers up and activates a SDIO function so that register + * access is possible. + */ +int sdio_enable_func(struct sdio_func *func) +{ + int ret; + unsigned char reg; + unsigned long timeout; + + BUG_ON(!func); + BUG_ON(!func->card); + + pr_debug("SDIO: Enabling device %s...\n", sdio_func_id(func)); + + ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IOEx, 0, ®); + if (ret) + goto err; + + reg |= 1 << func->num; + + ret = mmc_io_rw_direct(func->card, 1, 0, SDIO_CCCR_IOEx, reg, NULL); + if (ret) + goto err; + + /* + * FIXME: This should timeout based on information in the CIS, + * but we don't have card to parse that yet. + */ + timeout = jiffies + HZ; + + while (1) { + ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IORx, 0, ®); + if (ret) + goto err; + if (reg & (1 << func->num)) + break; + ret = -ETIME; + if (time_after(jiffies, timeout)) + goto err; + } + + pr_debug("SDIO: Enabled device %s\n", sdio_func_id(func)); + + return 0; + +err: + pr_debug("SDIO: Failed to enable device %s\n", sdio_func_id(func)); + return ret; +} +EXPORT_SYMBOL_GPL(sdio_enable_func); + +/** + * sdio_disable_func - disable a SDIO function + * @func: SDIO function to disable + * + * Powers down and deactivates a SDIO function. Register access + * to this function will fail until the function is reenabled. + */ +int sdio_disable_func(struct sdio_func *func) +{ + int ret; + unsigned char reg; + + BUG_ON(!func); + BUG_ON(!func->card); + + pr_debug("SDIO: Disabling device %s...\n", sdio_func_id(func)); + + ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IOEx, 0, ®); + if (ret) + goto err; + + reg &= ~(1 << func->num); + + ret = mmc_io_rw_direct(func->card, 1, 0, SDIO_CCCR_IOEx, reg, NULL); + if (ret) + goto err; + + pr_debug("SDIO: Disabled device %s\n", sdio_func_id(func)); + + return 0; + +err: + pr_debug("SDIO: Failed to disable device %s\n", sdio_func_id(func)); + return -EIO; +} +EXPORT_SYMBOL_GPL(sdio_disable_func); + /** * sdio_readb - read a single byte from a SDIO function * @func: SDIO function to access diff --git a/include/linux/mmc/sdio.h b/include/linux/mmc/sdio.h index e5f06de7d52..56239f4aab0 100644 --- a/include/linux/mmc/sdio.h +++ b/include/linux/mmc/sdio.h @@ -49,5 +49,97 @@ #define R5_STATUS(x) (x & 0xCB00) #define R5_IO_CURRENT_STATE(x) ((x & 0x3000) >> 12) /* s, b */ +/* + * Card Common Control Registers (CCCR) + */ + +#define SDIO_CCCR_CCCR 0x00 + +#define SDIO_CCCR_REV_1_00 0 /* CCCR/FBR Version 1.00 */ +#define SDIO_CCCR_REV_1_10 1 /* CCCR/FBR Version 1.10 */ +#define SDIO_CCCR_REV_1_20 2 /* CCCR/FBR Version 1.20 */ + +#define SDIO_SDIO_REV_1_00 0 /* SDIO Spec Version 1.00 */ +#define SDIO_SDIO_REV_1_10 1 /* SDIO Spec Version 1.10 */ +#define SDIO_SDIO_REV_1_20 2 /* SDIO Spec Version 1.20 */ +#define SDIO_SDIO_REV_2_00 3 /* SDIO Spec Version 2.00 */ + +#define SDIO_CCCR_SD 0x01 + +#define SDIO_SD_REV_1_01 0 /* SD Physical Spec Version 1.01 */ +#define SDIO_SD_REV_1_10 1 /* SD Physical Spec Version 1.10 */ +#define SDIO_SD_REV_2_00 2 /* SD Physical Spec Version 2.00 */ + +#define SDIO_CCCR_IOEx 0x02 +#define SDIO_CCCR_IORx 0x03 + +#define SDIO_CCCR_IENx 0x04 /* Function/Master Interrupt Enable */ +#define SDIO_CCCR_INTx 0x05 /* Function Interrupt Pending */ + +#define SDIO_CCCR_ABORT 0x06 /* function abort/card reset */ + +#define SDIO_CCCR_IF 0x07 /* bus interface controls */ + +#define SDIO_BUS_WIDTH_1BIT 0x00 +#define SDIO_BUS_WIDTH_4BIT 0x02 + +#define SDIO_BUS_CD_DISABLE 0x80 /* disable pull-up on DAT3 (pin 1) */ + +#define SDIO_CCCR_CAPS 0x08 + +#define SDIO_CCCR_CAP_SDC 0x01 /* can do CMD52 while data transfer */ +#define SDIO_CCCR_CAP_SMB 0x02 /* can do multi-block xfers (CMD53) */ +#define SDIO_CCCR_CAP_SRW 0x04 /* supports read-wait protocol */ +#define SDIO_CCCR_CAP_SBS 0x08 /* supports suspend/resume */ +#define SDIO_CCCR_CAP_S4MI 0x10 /* interrupt during 4-bit CMD53 */ +#define SDIO_CCCR_CAP_E4MI 0x20 /* enable ints during 4-bit CMD53 */ +#define SDIO_CCCR_CAP_LSC 0x40 /* low speed card */ +#define SDIO_CCCR_CAP_4BLS 0x80 /* 4 bit low speed card */ + +#define SDIO_CCCR_CIS 0x09 /* common CIS pointer (3 bytes) */ + +/* Following 4 regs are valid only if SBS is set */ +#define SDIO_CCCR_SUSPEND 0x0c +#define SDIO_CCCR_SELx 0x0d +#define SDIO_CCCR_EXECx 0x0e +#define SDIO_CCCR_READYx 0x0f + +#define SDIO_CCCR_BLKSIZE 0x10 + +#define SDIO_CCCR_POWER 0x12 + +#define SDIO_POWER_SMPC 0x01 /* Supports Master Power Control */ +#define SDIO_POWER_EMPC 0x02 /* Enable Master Power Control */ + +#define SDIO_CCCR_SPEED 0x13 + +#define SDIO_SPEED_SHS 0x01 /* Supports High-Speed mode */ +#define SDIO_SPEED_EHS 0x02 /* Enable High-Speed mode */ + +/* + * Function Basic Registers (FBR) + */ + +#define SDIO_FBR_STD_IF 0x00 + +#define SDIO_FBR_SUPPORTS_CSA 0x40 /* supports Code Storage Area */ +#define SDIO_FBR_ENABLE_CSA 0x80 /* enable Code Storage Area */ + +#define SDIO_FBR_STD_IF_EXT 0x01 + +#define SDIO_FBR_POWER 0x02 + +#define SDIO_FBR_POWER_SPS 0x01 /* Supports Power Selection */ +#define SDIO_FBR_POWER_EPS 0x02 /* Enable (low) Power Selection */ + +#define SDIO_FBR_CIS 0x09 /* CIS pointer (3 bytes) */ + + +#define SDIO_FBR_CSA 0x0C /* CSA pointer (3 bytes) */ + +#define SDIO_FBR_CSA_DATA 0x0F + +#define SDIO_FBR_BLKSIZE 0x10 /* block size (2 bytes) */ + #endif diff --git a/include/linux/mmc/sdio_func.h b/include/linux/mmc/sdio_func.h index 5c56df19628..3365fef5f71 100644 --- a/include/linux/mmc/sdio_func.h +++ b/include/linux/mmc/sdio_func.h @@ -55,6 +55,9 @@ extern void sdio_unregister_driver(struct sdio_driver *); extern void sdio_claim_host(struct sdio_func *func); extern void sdio_release_host(struct sdio_func *func); +extern int sdio_enable_func(struct sdio_func *func); +extern int sdio_disable_func(struct sdio_func *func); + extern unsigned char sdio_readb(struct sdio_func *func, unsigned int addr, int *err_ret); -- cgit v1.2.3-70-g09d2 From 35c66c19088bddb11110c124bad8abd4441a8421 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 11 Jun 2007 20:25:43 +0200 Subject: sdio: read and decode interesting parts of the CCCR Signed-off-by: Pierre Ossman --- drivers/mmc/core/sdio.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/mmc/card.h | 11 +++++++++ 2 files changed, 74 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 444328581ce..7ce3e3104d2 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -13,6 +13,7 @@ #include #include +#include #include #include "core.h" @@ -39,6 +40,61 @@ static int sdio_init_func(struct mmc_card *card, unsigned int fn) return 0; } +static int sdio_read_cccr(struct mmc_card *card) +{ + int ret; + int cccr_vsn; + unsigned char data; + + memset(&card->cccr, 0, sizeof(struct sdio_cccr)); + + ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_CCCR, 0, &data); + if (ret) + goto out; + + cccr_vsn = data & 0x0f; + + if (cccr_vsn > SDIO_CCCR_REV_1_20) { + printk(KERN_ERR "%s: unrecognised CCCR structure version %d\n", + mmc_hostname(card->host), cccr_vsn); + return -EINVAL; + } + + card->cccr.sdio_vsn = (data & 0xf0) >> 4; + + ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_CAPS, 0, &data); + if (ret) + goto out; + + if (data & SDIO_CCCR_CAP_SMB) + card->cccr.multi_block = 1; + if (data & SDIO_CCCR_CAP_LSC) + card->cccr.low_speed = 1; + if (data & SDIO_CCCR_CAP_4BLS) + card->cccr.wide_bus = 1; + + if (cccr_vsn >= SDIO_CCCR_REV_1_10) { + ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_POWER, 0, &data); + if (ret) + goto out; + + if (data & SDIO_POWER_SMPC) + card->cccr.high_power = 1; + } + + if (cccr_vsn >= SDIO_CCCR_REV_1_20) { + ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &data); + if (ret) + goto out; + + if (data & SDIO_SPEED_SHS) + card->cccr.high_speed = 1; + } + +out: + return ret; +} + /* * Host is being removed. Free up the current card. */ @@ -180,6 +236,13 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr) if (err) goto remove; + /* + * Read the common registers. + */ + err = sdio_read_cccr(card); + if (err) + goto remove; + /* * Initialize (but don't add) all present functions. */ diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 9f5f74482d9..520d9d29b3b 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -55,6 +55,16 @@ struct sd_switch_caps { unsigned int hs_max_dtr; }; +struct sdio_cccr { + unsigned int sdio_vsn; + unsigned int sd_vsn; + unsigned int multi_block:1, + low_speed:1, + wide_bus:1, + high_power:1, + high_speed:1; +}; + struct mmc_host; struct sdio_func; @@ -87,6 +97,7 @@ struct mmc_card { struct sd_switch_caps sw_caps; /* switch (CMD6) caps */ unsigned int sdio_funcs; /* number of SDIO functions */ + struct sdio_cccr cccr; /* common card info */ struct sdio_func *sdio_func[SDIO_MAX_FUNCS]; /* SDIO functions (devices) */ }; -- cgit v1.2.3-70-g09d2 From 0597007f1b22bbb5d4234ca09c045f9bb2711270 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 11 Jun 2007 21:01:00 +0200 Subject: sdio: basic parsing of FBR Signed-off-by: Pierre Ossman --- drivers/mmc/core/sdio.c | 38 ++++++++++++++++++++++++++++++++++++++ include/linux/mmc/sdio_func.h | 5 +++++ 2 files changed, 43 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 7ce3e3104d2..be623856f28 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -23,8 +23,34 @@ #include "sd_ops.h" #include "sdio_ops.h" +static int sdio_read_fbr(struct sdio_func *func) +{ + int ret; + unsigned char data; + + ret = mmc_io_rw_direct(func->card, 0, 0, + func->num * 0x100 + SDIO_FBR_STD_IF, 0, &data); + if (ret) + goto out; + + data &= 0x0f; + + if (data == 0x0f) { + ret = mmc_io_rw_direct(func->card, 0, 0, + func->num * 0x100 + SDIO_FBR_STD_IF_EXT, 0, &data); + if (ret) + goto out; + } + + func->class = data; + +out: + return ret; +} + static int sdio_init_func(struct mmc_card *card, unsigned int fn) { + int ret; struct sdio_func *func; BUG_ON(fn > SDIO_MAX_FUNCS); @@ -35,9 +61,21 @@ static int sdio_init_func(struct mmc_card *card, unsigned int fn) func->num = fn; + ret = sdio_read_fbr(func); + if (ret) + goto fail; + card->sdio_func[fn - 1] = func; return 0; + +fail: + /* + * It is okay to remove the function here even though we hold + * the host lock as we haven't registered the device yet. + */ + sdio_remove_func(func); + return ret; } static int sdio_read_cccr(struct mmc_card *card) diff --git a/include/linux/mmc/sdio_func.h b/include/linux/mmc/sdio_func.h index 3365fef5f71..4164809a8e6 100644 --- a/include/linux/mmc/sdio_func.h +++ b/include/linux/mmc/sdio_func.h @@ -21,6 +21,11 @@ struct sdio_func { struct mmc_card *card; /* the card this device belongs to */ struct device dev; /* the device */ unsigned int num; /* function number */ + + unsigned char class; /* standard interface class */ + unsigned short vendor; /* vendor id */ + unsigned short device; /* device id */ + unsigned int state; /* function state */ #define SDIO_STATE_PRESENT (1<<0) /* present in sysfs */ }; -- cgit v1.2.3-70-g09d2 From b726126196d54cbbba0924191e5c4dd5ba747fa2 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Sat, 16 Jun 2007 02:04:16 -0400 Subject: sdio: initial CIS parsing code Signed-off-by: Nicolas Pitre Signed-off-by: Pierre Ossman --- drivers/mmc/core/Makefile | 2 +- drivers/mmc/core/sdio.c | 5 ++ drivers/mmc/core/sdio_cis.c | 119 ++++++++++++++++++++++++++++++++++++++++++++ drivers/mmc/core/sdio_cis.h | 19 +++++++ 4 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 drivers/mmc/core/sdio_cis.c create mode 100644 drivers/mmc/core/sdio_cis.h (limited to 'drivers') diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile index bf7a0024803..05d69fc72c1 100644 --- a/drivers/mmc/core/Makefile +++ b/drivers/mmc/core/Makefile @@ -10,5 +10,5 @@ obj-$(CONFIG_MMC) += mmc_core.o mmc_core-y := core.o sysfs.o bus.o host.o \ mmc.o mmc_ops.o sd.o sd_ops.o \ sdio.o sdio_ops.o sdio_bus.o \ - sdio_io.o + sdio_cis.o sdio_io.o diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index be623856f28..c5baf76146b 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -22,6 +22,7 @@ #include "mmc_ops.h" #include "sd_ops.h" #include "sdio_ops.h" +#include "sdio_cis.h" static int sdio_read_fbr(struct sdio_func *func) { @@ -65,6 +66,10 @@ static int sdio_init_func(struct mmc_card *card, unsigned int fn) if (ret) goto fail; + ret = sdio_read_cis(func); + if (ret) + goto fail; + card->sdio_func[fn - 1] = func; return 0; diff --git a/drivers/mmc/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c new file mode 100644 index 00000000000..114b600cd78 --- /dev/null +++ b/drivers/mmc/core/sdio_cis.c @@ -0,0 +1,119 @@ +/* + * linux/drivers/mmc/core/sdio_cis.c + * + * Author: Nicolas Pitre + * Created: June 11, 2007 + * Copyright: MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + */ + +#include + +#include +#include +#include + +#include "sdio_cis.h" +#include "sdio_ops.h" + +static int cistpl_manfid(struct sdio_func *func, + const unsigned char *buf, + unsigned size) +{ + /* TPLMID_MANF */ + func->vendor = buf[0] | (buf[1] << 8); + + /* TPLMID_CARD */ + func->device = buf[2] | (buf[3] << 8); + + return 0; +} + +struct cis_tpl { + unsigned char code; + unsigned char min_size; + int (*parse)(struct sdio_func *, const unsigned char *buf, unsigned size); +}; + +static const struct cis_tpl cis_tpl_list[] = { + { 0x15, 3, /* cistpl_vers_1 */ }, + { 0x20, 4, cistpl_manfid }, + { 0x21, 2, /* cistpl_funcid */ }, + { 0x22, 0, /* cistpl_funce */ }, +}; + +int sdio_read_cis(struct sdio_func *func) +{ + int ret; + unsigned char *buf; + unsigned i, ptr = 0; + + for (i = 0; i < 3; i++) { + unsigned char x; + ret = mmc_io_rw_direct(func->card, 0, 0, + func->num * 0x100 + SDIO_FBR_CIS + i, 0, &x); + if (ret) + return ret; + ptr |= x << (i * 8); + } + + buf = kmalloc(256, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + do { + unsigned char tpl_code, tpl_link; + const struct cis_tpl *tpl; + + ret = mmc_io_rw_direct(func->card, 0, 0, ptr++, 0, &tpl_code); + if (ret) + break; + + /* 0xff means we're done */ + if (tpl_code == 0xff) + break; + + ret = mmc_io_rw_direct(func->card, 0, 0, ptr++, 0, &tpl_link); + if (ret) + break; + + for (i = 0; i < ARRAY_SIZE(cis_tpl_list); i++) + if (cis_tpl_list[i].code == tpl_code) + break; + if (i >= ARRAY_SIZE(cis_tpl_list)) { + printk(KERN_WARNING + "%s: unknown CIS tuple 0x%02x of length %u\n", + sdio_func_id(func), tpl_code, tpl_link); + ptr += tpl_link; + continue; + } + tpl = cis_tpl_list + i; + + if (tpl_link < tpl->min_size) { + printk(KERN_ERR + "%s: bad CIS tuple 0x%02x (length = %u, expected >= %u\n", + sdio_func_id(func), tpl_code, tpl_link, tpl->min_size); + ret = -EINVAL; + break; + } + + for (i = 0; i < tpl_link; i++) { + ret = mmc_io_rw_direct(func->card, 0, 0, ptr + i, 0, &buf[i]); + if (ret) + break; + } + if (ret) + break; + ptr += tpl_link; + + if (tpl->parse) + ret = tpl->parse(func, buf, tpl_link); + } while (!ret); + + kfree(buf); + return ret; +} diff --git a/drivers/mmc/core/sdio_cis.h b/drivers/mmc/core/sdio_cis.h new file mode 100644 index 00000000000..df21c495d13 --- /dev/null +++ b/drivers/mmc/core/sdio_cis.h @@ -0,0 +1,19 @@ +/* + * linux/drivers/mmc/core/sdio_cis.h + * + * Author: Nicolas Pitre + * Created: June 11, 2007 + * Copyright: MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + */ + +#ifndef _MMC_SDIO_CIS_H +#define _MMC_SDIO_CIS_H + +int sdio_read_cis(struct sdio_func *func); + +#endif -- cgit v1.2.3-70-g09d2 From b1538bcf75e2e11459947ec4d4329ed04fbe2b2c Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Sat, 16 Jun 2007 02:06:47 -0400 Subject: sdio: link unknown CIS tuples to the sdio_func structure This way those tuples that the core cares about are consumed by the core code, and tuples that only function drivers might make sense of are available to drivers. Signed-off-by: Nicolas Pitre Signed-off-by: Pierre Ossman --- drivers/mmc/core/sdio_bus.c | 3 ++ drivers/mmc/core/sdio_cis.c | 83 ++++++++++++++++++++++++++++--------------- drivers/mmc/core/sdio_cis.h | 1 + include/linux/mmc/sdio_func.h | 12 +++++++ 4 files changed, 70 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index fa488cea859..78e0381f55a 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -17,6 +17,7 @@ #include #include +#include "sdio_cis.h" #include "sdio_bus.h" #define dev_to_sdio_func(d) container_of(d, struct sdio_func, dev) @@ -94,6 +95,8 @@ static void sdio_release_func(struct device *dev) { struct sdio_func *func = dev_to_sdio_func(dev); + sdio_free_cis(func); + kfree(func); } diff --git a/drivers/mmc/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c index 114b600cd78..b6c7342572c 100644 --- a/drivers/mmc/core/sdio_cis.c +++ b/drivers/mmc/core/sdio_cis.c @@ -5,6 +5,8 @@ * Created: June 11, 2007 * Copyright: MontaVista Software Inc. * + * Copyright 2007 Pierre Ossman + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at @@ -49,7 +51,7 @@ static const struct cis_tpl cis_tpl_list[] = { int sdio_read_cis(struct sdio_func *func) { int ret; - unsigned char *buf; + struct sdio_func_tuple *this, **prev; unsigned i, ptr = 0; for (i = 0; i < 3; i++) { @@ -61,13 +63,11 @@ int sdio_read_cis(struct sdio_func *func) ptr |= x << (i * 8); } - buf = kmalloc(256, GFP_KERNEL); - if (!buf) - return -ENOMEM; + /* find the list tail */ + for (prev = &func->tuples; *prev; prev = &(*prev)->next); do { unsigned char tpl_code, tpl_link; - const struct cis_tpl *tpl; ret = mmc_io_rw_direct(func->card, 0, 0, ptr++, 0, &tpl_code); if (ret) @@ -81,39 +81,64 @@ int sdio_read_cis(struct sdio_func *func) if (ret) break; - for (i = 0; i < ARRAY_SIZE(cis_tpl_list); i++) - if (cis_tpl_list[i].code == tpl_code) + this = kmalloc(sizeof(*this) + tpl_link, GFP_KERNEL); + if (!this) + return -ENOMEM; + + for (i = 0; i < tpl_link; i++) { + ret = mmc_io_rw_direct(func->card, 0, 0, + ptr + i, 0, &this->data[i]); + if (ret) break; - if (i >= ARRAY_SIZE(cis_tpl_list)) { - printk(KERN_WARNING - "%s: unknown CIS tuple 0x%02x of length %u\n", - sdio_func_id(func), tpl_code, tpl_link); - ptr += tpl_link; - continue; } - tpl = cis_tpl_list + i; - - if (tpl_link < tpl->min_size) { - printk(KERN_ERR - "%s: bad CIS tuple 0x%02x (length = %u, expected >= %u\n", - sdio_func_id(func), tpl_code, tpl_link, tpl->min_size); - ret = -EINVAL; + if (ret) { + kfree(this); break; } - for (i = 0; i < tpl_link; i++) { - ret = mmc_io_rw_direct(func->card, 0, 0, ptr + i, 0, &buf[i]); - if (ret) + for (i = 0; i < ARRAY_SIZE(cis_tpl_list); i++) + if (cis_tpl_list[i].code == tpl_code) break; + if (i >= ARRAY_SIZE(cis_tpl_list)) { + /* this tuple is unknown to the core */ + this->next = NULL; + this->code = tpl_code; + this->size = tpl_link; + *prev = this; + prev = &this->next; + printk(KERN_DEBUG + "%s: queuing CIS tuple 0x%02x length %u\n", + sdio_func_id(func), tpl_code, tpl_link); + } else { + const struct cis_tpl *tpl = cis_tpl_list + i; + if (tpl_link < tpl->min_size) { + printk(KERN_ERR + "%s: bad CIS tuple 0x%02x (length = %u, expected >= %u)\n", + sdio_func_id(func), tpl_code, tpl_link, tpl->min_size); + ret = -EINVAL; + } else if (tpl->parse) + ret = tpl->parse(func, this->data, tpl_link); + kfree(this); } - if (ret) - break; - ptr += tpl_link; - if (tpl->parse) - ret = tpl->parse(func, buf, tpl_link); + ptr += tpl_link; } while (!ret); - kfree(buf); return ret; } + +void sdio_free_cis(struct sdio_func *func) +{ + struct sdio_func_tuple *tuple, *victim; + + tuple = func->tuples; + + while (tuple) { + victim = tuple; + tuple = tuple->next; + kfree(victim); + } + + func->tuples = NULL; +} + diff --git a/drivers/mmc/core/sdio_cis.h b/drivers/mmc/core/sdio_cis.h index df21c495d13..863d3d51637 100644 --- a/drivers/mmc/core/sdio_cis.h +++ b/drivers/mmc/core/sdio_cis.h @@ -15,5 +15,6 @@ #define _MMC_SDIO_CIS_H int sdio_read_cis(struct sdio_func *func); +void sdio_free_cis(struct sdio_func *func); #endif diff --git a/include/linux/mmc/sdio_func.h b/include/linux/mmc/sdio_func.h index 4164809a8e6..269067663c8 100644 --- a/include/linux/mmc/sdio_func.h +++ b/include/linux/mmc/sdio_func.h @@ -14,6 +14,16 @@ struct mmc_card; +/* + * SDIO function CIS tuple (unknown to the core) + */ +struct sdio_func_tuple { + struct sdio_func_tuple *next; + unsigned char code; + unsigned char size; + unsigned char data[0]; +}; + /* * SDIO function devices */ @@ -28,6 +38,8 @@ struct sdio_func { unsigned int state; /* function state */ #define SDIO_STATE_PRESENT (1<<0) /* present in sysfs */ + + struct sdio_func_tuple *tuples; }; #define sdio_func_present(f) ((f)->state & SDIO_STATE_PRESENT) -- cgit v1.2.3-70-g09d2 From 1a632f8cdc33e7f8edca352164f0c96a75d08f08 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 30 Jul 2007 15:15:30 +0200 Subject: sdio: split up common and function CIS parsing Add a more clean separation between global, common CIS information and the function specific one as we need the common information in places where no specific function is specified. Signed-off-by: Pierre Ossman --- drivers/mmc/core/bus.c | 3 + drivers/mmc/core/sdio.c | 9 +- drivers/mmc/core/sdio_bus.c | 2 +- drivers/mmc/core/sdio_cis.c | 198 +++++++++++++++++++++++++++++++++++++----- drivers/mmc/core/sdio_cis.h | 7 +- include/linux/mmc/card.h | 10 +++ include/linux/mmc/sdio_func.h | 2 + 7 files changed, 205 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 87a6070522f..9be11ec05d8 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -19,6 +19,7 @@ #include "sysfs.h" #include "core.h" +#include "sdio_cis.h" #include "bus.h" #define dev_to_mmc_card(d) container_of(d, struct mmc_card, dev) @@ -181,6 +182,8 @@ static void mmc_release_card(struct device *dev) { struct mmc_card *card = dev_to_mmc_card(dev); + sdio_free_common_cis(card); + kfree(card); } diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index c5baf76146b..1fb36a34046 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -66,7 +66,7 @@ static int sdio_init_func(struct mmc_card *card, unsigned int fn) if (ret) goto fail; - ret = sdio_read_cis(func); + ret = sdio_read_func_cis(func); if (ret) goto fail; @@ -286,6 +286,13 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr) if (err) goto remove; + /* + * Read the common CIS tuples. + */ + err = sdio_read_common_cis(card); + if (err) + goto remove; + /* * Initialize (but don't add) all present functions. */ diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 78e0381f55a..461fe4837a9 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -95,7 +95,7 @@ static void sdio_release_func(struct device *dev) { struct sdio_func *func = dev_to_sdio_func(dev); - sdio_free_cis(func); + sdio_free_func_cis(func); kfree(func); } diff --git a/drivers/mmc/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c index b6c7342572c..ec806a1229b 100644 --- a/drivers/mmc/core/sdio_cis.c +++ b/drivers/mmc/core/sdio_cis.c @@ -16,60 +16,152 @@ #include #include +#include #include #include #include "sdio_cis.h" #include "sdio_ops.h" -static int cistpl_manfid(struct sdio_func *func, - const unsigned char *buf, - unsigned size) +static int cistpl_manfid(struct mmc_card *card, struct sdio_func *func, + const unsigned char *buf, unsigned size) { + unsigned int vendor, device; + /* TPLMID_MANF */ - func->vendor = buf[0] | (buf[1] << 8); + vendor = buf[0] | (buf[1] << 8); /* TPLMID_CARD */ - func->device = buf[2] | (buf[3] << 8); + device = buf[2] | (buf[3] << 8); + + if (func) { + func->vendor = vendor; + func->device = device; + } else { + card->cis.vendor = vendor; + card->cis.device = device; + } + + return 0; +} + +static const unsigned char speed_val[16] = + { 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80 }; +static const unsigned int speed_unit[8] = + { 10000, 100000, 1000000, 10000000, 0, 0, 0, 0 }; + +static int cistpl_funce_common(struct mmc_card *card, + const unsigned char *buf, unsigned size) +{ + if (size < 0x04 || buf[0] != 0) + return -EINVAL; + + /* TPLFE_FN0_BLK_SIZE */ + card->cis.blksize = buf[1] | (buf[2] << 8); + + /* TPLFE_MAX_TRAN_SPEED */ + card->cis.max_dtr = speed_val[(buf[3] >> 3) & 15] * + speed_unit[buf[3] & 7]; + + return 0; +} + +static int cistpl_funce_func(struct sdio_func *func, + const unsigned char *buf, unsigned size) +{ + unsigned vsn; + unsigned min_size; + + vsn = func->card->cccr.sdio_vsn; + min_size = (vsn == SDIO_SDIO_REV_1_00) ? 28 : 42; + + if (size < min_size || buf[0] != 1) + return -EINVAL; + + /* TPLFE_MAX_BLK_SIZE */ + func->blksize = buf[12] | (buf[13] << 8); return 0; } +static int cistpl_funce(struct mmc_card *card, struct sdio_func *func, + const unsigned char *buf, unsigned size) +{ + int ret; + + /* + * There should be two versions of the CISTPL_FUNCE tuple, + * one for the common CIS (function 0) and a version used by + * the individual function's CIS (1-7). Yet, the later has a + * different length depending on the SDIO spec version. + */ + if (func) + ret = cistpl_funce_func(func, buf, size); + else + ret = cistpl_funce_common(card, buf, size); + + if (ret) { + printk(KERN_ERR "%s: bad CISTPL_FUNCE size %u " + "type %u\n", mmc_hostname(card->host), size, buf[0]); + return ret; + } + + return 0; +} + +typedef int (tpl_parse_t)(struct mmc_card *, struct sdio_func *, + const unsigned char *, unsigned); + struct cis_tpl { unsigned char code; unsigned char min_size; - int (*parse)(struct sdio_func *, const unsigned char *buf, unsigned size); + tpl_parse_t *parse; }; static const struct cis_tpl cis_tpl_list[] = { { 0x15, 3, /* cistpl_vers_1 */ }, { 0x20, 4, cistpl_manfid }, { 0x21, 2, /* cistpl_funcid */ }, - { 0x22, 0, /* cistpl_funce */ }, + { 0x22, 0, cistpl_funce }, }; -int sdio_read_cis(struct sdio_func *func) +static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func) { int ret; struct sdio_func_tuple *this, **prev; unsigned i, ptr = 0; + /* + * Note that this works for the common CIS (function number 0) as + * well as a function's CIS * since SDIO_CCCR_CIS and SDIO_FBR_CIS + * have the same offset. + */ for (i = 0; i < 3; i++) { - unsigned char x; - ret = mmc_io_rw_direct(func->card, 0, 0, - func->num * 0x100 + SDIO_FBR_CIS + i, 0, &x); + unsigned char x, fn; + + if (func) + fn = func->num; + else + fn = 0; + + ret = mmc_io_rw_direct(card, 0, 0, + fn * 0x100 + SDIO_FBR_CIS + i, 0, &x); if (ret) return ret; ptr |= x << (i * 8); } - /* find the list tail */ - for (prev = &func->tuples; *prev; prev = &(*prev)->next); + if (func) + prev = &func->tuples; + else + prev = &card->tuples; + + BUG_ON(*prev); do { unsigned char tpl_code, tpl_link; - ret = mmc_io_rw_direct(func->card, 0, 0, ptr++, 0, &tpl_code); + ret = mmc_io_rw_direct(card, 0, 0, ptr++, 0, &tpl_code); if (ret) break; @@ -77,7 +169,7 @@ int sdio_read_cis(struct sdio_func *func) if (tpl_code == 0xff) break; - ret = mmc_io_rw_direct(func->card, 0, 0, ptr++, 0, &tpl_link); + ret = mmc_io_rw_direct(card, 0, 0, ptr++, 0, &tpl_link); if (ret) break; @@ -86,7 +178,7 @@ int sdio_read_cis(struct sdio_func *func) return -ENOMEM; for (i = 0; i < tpl_link; i++) { - ret = mmc_io_rw_direct(func->card, 0, 0, + ret = mmc_io_rw_direct(card, 0, 0, ptr + i, 0, &this->data[i]); if (ret) break; @@ -108,30 +200,45 @@ int sdio_read_cis(struct sdio_func *func) prev = &this->next; printk(KERN_DEBUG "%s: queuing CIS tuple 0x%02x length %u\n", - sdio_func_id(func), tpl_code, tpl_link); + mmc_hostname(card->host), tpl_code, tpl_link); } else { const struct cis_tpl *tpl = cis_tpl_list + i; if (tpl_link < tpl->min_size) { printk(KERN_ERR "%s: bad CIS tuple 0x%02x (length = %u, expected >= %u)\n", - sdio_func_id(func), tpl_code, tpl_link, tpl->min_size); + mmc_hostname(card->host), + tpl_code, tpl_link, tpl->min_size); ret = -EINVAL; - } else if (tpl->parse) - ret = tpl->parse(func, this->data, tpl_link); + } else if (tpl->parse) { + ret = tpl->parse(card, func, + this->data, tpl_link); + } kfree(this); } ptr += tpl_link; } while (!ret); + /* + * Link in all unknown tuples found in the common CIS so that + * drivers don't have to go digging in two places. + */ + if (func) + *prev = card->tuples; + return ret; } -void sdio_free_cis(struct sdio_func *func) +int sdio_read_common_cis(struct mmc_card *card) +{ + return sdio_read_cis(card, NULL); +} + +void sdio_free_common_cis(struct mmc_card *card) { struct sdio_func_tuple *tuple, *victim; - tuple = func->tuples; + tuple = card->tuples; while (tuple) { victim = tuple; @@ -139,6 +246,53 @@ void sdio_free_cis(struct sdio_func *func) kfree(victim); } + card->tuples = NULL; +} + +int sdio_read_func_cis(struct sdio_func *func) +{ + int ret; + + ret = sdio_read_cis(func->card, func); + if (ret) + return ret; + + /* + * Since we've linked to tuples in the card structure, + * we must make sure we have a reference to it. + */ + get_device(&func->card->dev); + + /* + * Vendor/device id is optional for function CIS, so + * copy it from the card structure as needed. + */ + if (func->vendor == 0) { + func->vendor = func->card->cis.vendor; + func->device = func->card->cis.device; + } + + return 0; +} + +void sdio_free_func_cis(struct sdio_func *func) +{ + struct sdio_func_tuple *tuple, *victim; + + tuple = func->tuples; + + while (tuple && tuple != func->card->tuples) { + victim = tuple; + tuple = tuple->next; + kfree(victim); + } + func->tuples = NULL; + + /* + * We have now removed the link to the tuples in the + * card structure, so remove the reference. + */ + put_device(&func->card->dev); } diff --git a/drivers/mmc/core/sdio_cis.h b/drivers/mmc/core/sdio_cis.h index 863d3d51637..4d903c2e425 100644 --- a/drivers/mmc/core/sdio_cis.h +++ b/drivers/mmc/core/sdio_cis.h @@ -14,7 +14,10 @@ #ifndef _MMC_SDIO_CIS_H #define _MMC_SDIO_CIS_H -int sdio_read_cis(struct sdio_func *func); -void sdio_free_cis(struct sdio_func *func); +int sdio_read_common_cis(struct mmc_card *card); +void sdio_free_common_cis(struct mmc_card *card); + +int sdio_read_func_cis(struct sdio_func *func); +void sdio_free_func_cis(struct sdio_func *func); #endif diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 520d9d29b3b..a444431e28b 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -65,8 +65,16 @@ struct sdio_cccr { high_speed:1; }; +struct sdio_cis { + unsigned short vendor; + unsigned short device; + unsigned short blksize; + unsigned int max_dtr; +}; + struct mmc_host; struct sdio_func; +struct sdio_func_tuple; #define SDIO_MAX_FUNCS 7 @@ -98,7 +106,9 @@ struct mmc_card { unsigned int sdio_funcs; /* number of SDIO functions */ struct sdio_cccr cccr; /* common card info */ + struct sdio_cis cis; /* common tuple info */ struct sdio_func *sdio_func[SDIO_MAX_FUNCS]; /* SDIO functions (devices) */ + struct sdio_func_tuple *tuples; /* unknown common tuples */ }; #define mmc_card_mmc(c) ((c)->type == MMC_TYPE_MMC) diff --git a/include/linux/mmc/sdio_func.h b/include/linux/mmc/sdio_func.h index 269067663c8..2f2b3c85441 100644 --- a/include/linux/mmc/sdio_func.h +++ b/include/linux/mmc/sdio_func.h @@ -36,6 +36,8 @@ struct sdio_func { unsigned short vendor; /* vendor id */ unsigned short device; /* device id */ + unsigned short blksize; /* maximum block size */ + unsigned int state; /* function state */ #define SDIO_STATE_PRESENT (1<<0) /* present in sysfs */ -- cgit v1.2.3-70-g09d2 From 26074962e8f547b96614dbe248748ba2a1996ca3 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Sat, 16 Jun 2007 02:07:53 -0400 Subject: mmc: initialize mmc subsystem with subsys_initcall() The problem is that the sdio_bus must be registered before any SDIO drivers are registered against it otherwise the kernel sulks. Because the sdio_bus registration happens through module_init (equivalent to device_initcall), then any SDIO drivers linked before the SDIO core code in the kernel will be initialized first. Upcoming SDIO function drivers are likely to be located outside the drivers/mmc directory as it is common practice to group drivers according to their function rather than the bus they use. SDIO drivers are therefore likely to appear at random location in the kernel link. To make sure the sdio_bus is always initialized before any SDIO drivers, let's move the MMC init to the subsys_initcall level. Signed-off-by: Nicolas Pitre Signed-off-by: Pierre Ossman --- drivers/mmc/core/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 9747455928d..b8f27e5ade9 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -771,7 +771,7 @@ static void __exit mmc_exit(void) destroy_workqueue(workqueue); } -module_init(mmc_init); +subsys_initcall(mmc_init); module_exit(mmc_exit); MODULE_LICENSE("GPL"); -- cgit v1.2.3-70-g09d2 From 3b38bea0d976513970f947806b08b9faca418e7a Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sat, 16 Jun 2007 15:54:55 +0200 Subject: sdio: add device id table and matching Signed-off-by: Pierre Ossman --- drivers/mmc/core/sdio_bus.c | 58 ++++++++++++++++++++++++++++++++++++----- include/linux/mmc/sdio_func.h | 30 ++++++++++++++++++++- include/linux/mod_devicetable.h | 11 ++++++++ 3 files changed, 92 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 461fe4837a9..a3a89e973d9 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -21,14 +21,47 @@ #include "sdio_bus.h" #define dev_to_sdio_func(d) container_of(d, struct sdio_func, dev) +#define to_sdio_driver(d) container_of(d, struct sdio_driver, drv) + +static const struct sdio_device_id *sdio_match_one(struct sdio_func *func, + const struct sdio_device_id *id) +{ + if (id->class != (__u8)SDIO_ANY_ID && id->class != func->class) + return NULL; + if (id->vendor != (__u16)SDIO_ANY_ID && id->vendor != func->vendor) + return NULL; + if (id->device != (__u16)SDIO_ANY_ID && id->device != func->device) + return NULL; + return id; +} + +static const struct sdio_device_id *sdio_match_device(struct sdio_func *func, + struct sdio_driver *sdrv) +{ + const struct sdio_device_id *ids; + + ids = sdrv->id_table; + + if (ids) { + while (ids->class || ids->vendor || ids->device) { + if (sdio_match_one(func, ids)) + return ids; + ids++; + } + } + + return NULL; +} -/* - * This currently matches any SDIO function to any driver in order - * to help initial development and testing. - */ static int sdio_bus_match(struct device *dev, struct device_driver *drv) { - return 1; + struct sdio_func *func = dev_to_sdio_func(dev); + struct sdio_driver *sdrv = to_sdio_driver(drv); + + if (sdio_match_device(func, sdrv)) + return 1; + + return 0; } static int @@ -42,11 +75,24 @@ sdio_bus_uevent(struct device *dev, char **envp, int num_envp, char *buf, static int sdio_bus_probe(struct device *dev) { - return -ENODEV; + struct sdio_driver *drv = to_sdio_driver(dev->driver); + struct sdio_func *func = dev_to_sdio_func(dev); + const struct sdio_device_id *id; + + id = sdio_match_device(func, drv); + if (!id) + return -ENODEV; + + return drv->probe(func, id); } static int sdio_bus_remove(struct device *dev) { + struct sdio_driver *drv = to_sdio_driver(dev->driver); + struct sdio_func *func = dev_to_sdio_func(dev); + + drv->remove(func); + return 0; } diff --git a/include/linux/mmc/sdio_func.h b/include/linux/mmc/sdio_func.h index 2f2b3c85441..8106d399c41 100644 --- a/include/linux/mmc/sdio_func.h +++ b/include/linux/mmc/sdio_func.h @@ -12,6 +12,9 @@ #ifndef MMC_SDIO_FUNC_H #define MMC_SDIO_FUNC_H +#include +#include + struct mmc_card; /* @@ -58,13 +61,38 @@ struct sdio_func { */ struct sdio_driver { char *name; + const struct sdio_device_id *id_table; - int (*probe)(struct sdio_func *); + int (*probe)(struct sdio_func *, const struct sdio_device_id *); void (*remove)(struct sdio_func *); struct device_driver drv; }; +/** + * SDIO_DEVICE - macro used to describe a specific SDIO device + * @vend: the 16 bit manufacturer code + * @dev: the 16 bit function id + * + * This macro is used to create a struct sdio_device_id that matches a + * specific device. The class field will be set to SDIO_ANY_ID. + */ +#define SDIO_DEVICE(vend,dev) \ + .class = SDIO_ANY_ID, \ + .vendor = (vend), .device = (dev) + +/** + * SDIO_DEVICE_CLASS - macro used to describe a specific SDIO device class + * @dev_class: the 8 bit standard interface code + * + * This macro is used to create a struct sdio_device_id that matches a + * specific standard SDIO function type. The vendor and device fields will + * be set to SDIO_ANY_ID. + */ +#define SDIO_DEVICE_CLASS(dev_class) \ + .class = (dev_class), \ + .vendor = SDIO_ANY_ID, .device = SDIO_ANY_ID + extern int sdio_register_driver(struct sdio_driver *); extern void sdio_unregister_driver(struct sdio_driver *); diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index 4dc5fa8be78..e47e5951058 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -340,4 +340,15 @@ struct parisc_device_id { #define PA_HVERSION_ANY_ID 0xffff #define PA_SVERSION_ANY_ID 0xffffffff +/* SDIO */ + +#define SDIO_ANY_ID (~0) + +struct sdio_device_id { + __u8 class; /* Standard interface or SDIO_ANY_ID */ + __u16 vendor; /* Vendor or SDIO_ANY_ID */ + __u16 device; /* Device ID or SDIO_ANY_ID */ + kernel_ulong_t driver_data; /* Data private to the driver */ +}; + #endif /* LINUX_MOD_DEVICETABLE_H */ -- cgit v1.2.3-70-g09d2 From 9eb3a94d022e6c233c0b22ec54516d35d2e87eb9 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 17 Jun 2007 11:18:46 +0200 Subject: mmc: whip bus uevent handler into shape Make the mmc bus uevent callback look like all other subsystems. Signed-off-by: Pierre Ossman --- drivers/mmc/core/bus.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 9be11ec05d8..1cc11714916 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -62,31 +62,34 @@ mmc_bus_uevent(struct device *dev, char **envp, int num_envp, char *buf, int buf_size) { struct mmc_card *card = dev_to_mmc_card(dev); - int retval = 0, i = 0, length = 0; - -#define add_env(fmt,val) do { \ - retval = add_uevent_var(envp, num_envp, &i, \ - buf, buf_size, &length, \ - fmt, val); \ - if (retval) \ - return retval; \ -} while (0); + const char *type; + int i = 0, length = 0; switch (card->type) { case MMC_TYPE_MMC: - add_env("MMC_TYPE=%s", "MMC"); + type = "MMC"; break; case MMC_TYPE_SD: - add_env("MMC_TYPE=%s", "SD"); + type = "SD"; break; case MMC_TYPE_SDIO: - add_env("MMC_TYPE=%s", "SDIO"); + type = "SDIO"; break; + default: + type = NULL; } - add_env("MMC_NAME=%s", mmc_card_name(card)); + if (type) { + if (add_uevent_var(envp, num_envp, &i, + buf, buf_size, &length, + "MMC_TYPE=%s", type)) + return -ENOMEM; + } -#undef add_env + if (add_uevent_var(envp, num_envp, &i, + buf, buf_size, &length, + "MMC_NAME=%s", mmc_card_name(card))) + return -ENOMEM; envp[i] = NULL; -- cgit v1.2.3-70-g09d2 From d59b66c7a575cfa8e01f483875d131e42b539bbc Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 17 Jun 2007 11:34:23 +0200 Subject: sdio: add modalias support Signed-off-by: Pierre Ossman --- drivers/mmc/core/sdio_bus.c | 21 ++++++++++++++++++++- scripts/mod/file2alias.c | 20 ++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index a3a89e973d9..c834f515088 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -68,7 +68,26 @@ static int sdio_bus_uevent(struct device *dev, char **envp, int num_envp, char *buf, int buf_size) { - envp[0] = NULL; + struct sdio_func *func = dev_to_sdio_func(dev); + int i = 0, length = 0; + + if (add_uevent_var(envp, num_envp, &i, + buf, buf_size, &length, + "SDIO_CLASS=%02X", func->class)) + return -ENOMEM; + + if (add_uevent_var(envp, num_envp, &i, + buf, buf_size, &length, + "SDIO_ID=%04X:%04X", func->vendor, func->device)) + return -ENOMEM; + + if (add_uevent_var(envp, num_envp, &i, + buf, buf_size, &length, + "MODALIAS=sdio:c%02Xv%04Xd%04X", + func->class, func->vendor, func->device)) + return -ENOMEM; + + envp[i] = NULL; return 0; } diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 8a09021d8c5..1e5d4d69319 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -484,6 +484,22 @@ static int do_parisc_entry(const char *filename, struct parisc_device_id *id, return 1; } +/* Looks like: sdio:cNvNdN. */ +static int do_sdio_entry(const char *filename, + struct sdio_device_id *id, char *alias) +{ + id->class = TO_NATIVE(id->class); + id->vendor = TO_NATIVE(id->vendor); + id->device = TO_NATIVE(id->device); + + strcpy(alias, "sdio:"); + ADD(alias, "c", id->class != (__u8)SDIO_ANY_ID, id->class); + ADD(alias, "v", id->vendor != (__u16)SDIO_ANY_ID, id->vendor); + ADD(alias, "d", id->device != (__u16)SDIO_ANY_ID, id->device); + + return 1; +} + /* Ignore any prefix, eg. v850 prepends _ */ static inline int sym_is(const char *symbol, const char *name) { @@ -599,6 +615,10 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, do_table(symval, sym->st_size, sizeof(struct parisc_device_id), "parisc", do_parisc_entry, mod); + else if (sym_is(symname, "__mod_sdio_device_table")) + do_table(symval, sym->st_size, + sizeof(struct sdio_device_id), "sdio", + do_sdio_entry, mod); } /* Now add out buffered information to the generated C source */ -- cgit v1.2.3-70-g09d2 From bcfe66e21ef78a078bb0de0bab532701996695d3 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 17 Jun 2007 11:42:21 +0200 Subject: sdio: add basic sysfs attributes Signed-off-by: Pierre Ossman --- drivers/mmc/core/sdio_bus.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index c834f515088..129f0719c39 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -23,6 +23,37 @@ #define dev_to_sdio_func(d) container_of(d, struct sdio_func, dev) #define to_sdio_driver(d) container_of(d, struct sdio_driver, drv) +/* show configuration fields */ +#define sdio_config_attr(field, format_string) \ +static ssize_t \ +field##_show(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct sdio_func *func; \ + \ + func = dev_to_sdio_func (dev); \ + return sprintf (buf, format_string, func->field); \ +} + +sdio_config_attr(class, "0x%02x\n"); +sdio_config_attr(vendor, "0x%04x\n"); +sdio_config_attr(device, "0x%04x\n"); + +static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sdio_func *func = dev_to_sdio_func (dev); + + return sprintf(buf, "sdio:c%02Xv%04Xd%04X\n", + func->class, func->vendor, func->device); +} + +struct device_attribute sdio_dev_attrs[] = { + __ATTR_RO(class), + __ATTR_RO(vendor), + __ATTR_RO(device), + __ATTR_RO(modalias), + __ATTR_NULL, +}; + static const struct sdio_device_id *sdio_match_one(struct sdio_func *func, const struct sdio_device_id *id) { @@ -117,6 +148,7 @@ static int sdio_bus_remove(struct device *dev) static struct bus_type sdio_bus_type = { .name = "sdio", + .dev_attrs = sdio_dev_attrs, .match = sdio_bus_match, .uevent = sdio_bus_uevent, .probe = sdio_bus_probe, -- cgit v1.2.3-70-g09d2 From 2342f3323c9a76367a1d7f9a35525ee3cb3911df Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Sat, 30 Jun 2007 16:21:52 +0200 Subject: sdio: allow for mmc_claim_host to be aborted It is sometimes necessary to give up on trying to claim the host lock, especially if that happens in a thread that has to be stopped. While at it, fix the description for mmc_claim_host() which was wrong. Signed-off-by: Nicolas Pitre Signed-off-by: Pierre Ossman --- drivers/mmc/core/core.c | 22 ++++++++++++++++------ include/linux/mmc/core.h | 13 ++++++++++++- 2 files changed, 28 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index b8f27e5ade9..d1e4b0849e3 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -273,15 +273,20 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card) EXPORT_SYMBOL(mmc_set_data_timeout); /** - * mmc_claim_host - exclusively claim a host + * __mmc_claim_host - exclusively claim a host * @host: mmc host to claim + * @abort: whether or not the operation should be aborted * - * Claim a host for a set of operations. + * Claim a host for a set of operations. If @abort is non null and + * dereference a non-zero value then this will return prematurely with + * that non-zero value without acquiring the lock. Returns zero + * with the lock held otherwise. */ -void mmc_claim_host(struct mmc_host *host) +int __mmc_claim_host(struct mmc_host *host, atomic_t *abort) { DECLARE_WAITQUEUE(wait, current); unsigned long flags; + int stop; might_sleep(); @@ -289,19 +294,24 @@ void mmc_claim_host(struct mmc_host *host) spin_lock_irqsave(&host->lock, flags); while (1) { set_current_state(TASK_UNINTERRUPTIBLE); - if (!host->claimed) + stop = abort ? atomic_read(abort) : 0; + if (stop || !host->claimed) break; spin_unlock_irqrestore(&host->lock, flags); schedule(); spin_lock_irqsave(&host->lock, flags); } set_current_state(TASK_RUNNING); - host->claimed = 1; + if (!stop) + host->claimed = 1; + else + wake_up(&host->wq); spin_unlock_irqrestore(&host->lock, flags); remove_wait_queue(&host->wq, &wait); + return stop; } -EXPORT_SYMBOL(mmc_claim_host); +EXPORT_SYMBOL(__mmc_claim_host); /** * mmc_release_host - release a host diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index 43a92736be6..8945da9b54f 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h @@ -114,7 +114,18 @@ extern int mmc_wait_for_app_cmd(struct mmc_host *, struct mmc_card *, extern void mmc_set_data_timeout(struct mmc_data *, const struct mmc_card *); -extern void mmc_claim_host(struct mmc_host *host); +extern int __mmc_claim_host(struct mmc_host *host, atomic_t *abort); extern void mmc_release_host(struct mmc_host *host); +/** + * mmc_claim_host - exclusively claim a host + * @host: mmc host to claim + * + * Claim a host for a set of operations. + */ +static inline void mmc_claim_host(struct mmc_host *host) +{ + __mmc_claim_host(host, NULL); +} + #endif -- cgit v1.2.3-70-g09d2 From d1496c39e500857b8949cdb91af24e0eb8aae4d0 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Sat, 30 Jun 2007 16:29:41 +0200 Subject: sdio: core support for SDIO function interrupt Signed-off-by: Nicolas Pitre Signed-off-by: Pierre Ossman --- drivers/mmc/core/Makefile | 2 +- drivers/mmc/core/sdio_bus.c | 8 ++ drivers/mmc/core/sdio_irq.c | 237 ++++++++++++++++++++++++++++++++++++++++++ include/linux/mmc/host.h | 4 + include/linux/mmc/sdio_func.h | 7 ++ 5 files changed, 257 insertions(+), 1 deletion(-) create mode 100644 drivers/mmc/core/sdio_irq.c (limited to 'drivers') diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile index 05d69fc72c1..4985807257a 100644 --- a/drivers/mmc/core/Makefile +++ b/drivers/mmc/core/Makefile @@ -10,5 +10,5 @@ obj-$(CONFIG_MMC) += mmc_core.o mmc_core-y := core.o sysfs.o bus.o host.o \ mmc.o mmc_ops.o sd.o sd_ops.o \ sdio.o sdio_ops.o sdio_bus.o \ - sdio_cis.o sdio_io.o + sdio_cis.o sdio_io.o sdio_irq.o diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 129f0719c39..24072445491 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -143,6 +143,14 @@ static int sdio_bus_remove(struct device *dev) drv->remove(func); + if (func->irq_handler) { + printk(KERN_WARNING "WARNING: driver %s did not remove " + "its interrupt handler!\n", drv->name); + sdio_claim_host(func); + sdio_release_irq(func); + sdio_release_host(func); + } + return 0; } diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c new file mode 100644 index 00000000000..01922d29241 --- /dev/null +++ b/drivers/mmc/core/sdio_irq.c @@ -0,0 +1,237 @@ +/* + * linux/drivers/mmc/core/sdio_irq.c + * + * Author: Nicolas Pitre + * Created: June 18, 2007 + * Copyright: MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "sdio_ops.h" + +static int process_sdio_pending_irqs(struct mmc_card *card) +{ + int i, ret; + unsigned char pending; + + ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_INTx, 0, &pending); + if (ret) { + printk(KERN_DEBUG "%s: error %d reading SDIO_CCCR_INTx\n", + mmc_card_id(card), ret); + return ret; + } + + for (i = 1; i <= 7; i++) { + if (pending & (1 << i)) { + struct sdio_func *func = card->sdio_func[i - 1]; + if (!func) { + printk(KERN_WARNING "%s: pending IRQ for " + "non-existant function\n", + sdio_func_id(func)); + } else if (func->irq_handler) { + func->irq_handler(func); + } else + printk(KERN_WARNING "%s: pending IRQ with no handler\n", + sdio_func_id(func)); + } + } + + return 0; +} + +static int sdio_irq_thread(void *_host) +{ + struct mmc_host *host = _host; + struct sched_param param = { .sched_priority = 1 }; + unsigned long period; + int ret; + + sched_setscheduler(current, SCHED_FIFO, ¶m); + + /* + * We want to allow for SDIO cards to work even on non SDIO + * aware hosts. One thing that non SDIO host cannot do is + * asynchronous notification of pending SDIO card interrupts + * hence we poll for them in that case. + */ + period = msecs_to_jiffies(10); + + pr_debug("%s: IRQ thread started (poll period = %lu jiffies)\n", + mmc_hostname(host), period); + + do { + /* + * We claim the host here on drivers behalf for a couple + * reasons: + * + * 1) it is already needed to retrieve the CCCR_INTx; + * 2) we want the driver(s) to clear the IRQ condition ASAP; + * 3) we need to control the abort condition locally. + * + * Just like traditional hard IRQ handlers, we expect SDIO + * IRQ handlers to be quick and to the point, so that the + * holding of the host lock does not cover too much work + * that doesn't require that lock to be held. + */ + ret = __mmc_claim_host(host, &host->sdio_irq_thread_abort); + if (ret) + break; + ret = process_sdio_pending_irqs(host->card); + mmc_release_host(host); + + /* + * Give other threads a chance to run in the presence of + * errors. FIXME: determine if due to card removal and + * possibly exit this thread if so. + */ + if (ret) + ssleep(1); + + set_task_state(current, TASK_INTERRUPTIBLE); + if (!kthread_should_stop()) + schedule_timeout(period); + set_task_state(current, TASK_RUNNING); + } while (!kthread_should_stop()); + + pr_debug("%s: IRQ thread exiting with code %d\n", + mmc_hostname(host), ret); + + return ret; +} + +static int sdio_card_irq_get(struct mmc_card *card) +{ + struct mmc_host *host = card->host; + + BUG_ON(!host->claimed); + + if (!host->sdio_irqs++) { + atomic_set(&host->sdio_irq_thread_abort, 0); + host->sdio_irq_thread = + kthread_run(sdio_irq_thread, host, "ksdiorqd"); + if (IS_ERR(host->sdio_irq_thread)) { + int err = PTR_ERR(host->sdio_irq_thread); + host->sdio_irqs--; + return err; + } + } + + return 0; +} + +static int sdio_card_irq_put(struct mmc_card *card) +{ + struct mmc_host *host = card->host; + + BUG_ON(!host->claimed); + BUG_ON(host->sdio_irqs < 1); + + if (!--host->sdio_irqs) { + atomic_set(&host->sdio_irq_thread_abort, 1); + kthread_stop(host->sdio_irq_thread); + } + + return 0; +} + +/** + * sdio_claim_irq - claim the IRQ for a SDIO function + * @func: SDIO function + * @handler: IRQ handler callback + * + * Claim and activate the IRQ for the given SDIO function. The provided + * handler will be called when that IRQ is asserted. The host is always + * claimed already when the handler is called so the handler must not + * call sdio_claim_host() nor sdio_release_host(). + */ +int sdio_claim_irq(struct sdio_func *func, sdio_irq_handler_t *handler) +{ + int ret; + unsigned char reg; + + BUG_ON(!func); + BUG_ON(!func->card); + + pr_debug("SDIO: Enabling IRQ for %s...\n", sdio_func_id(func)); + + if (func->irq_handler) { + pr_debug("SDIO: IRQ for %s already in use.\n", sdio_func_id(func)); + return -EBUSY; + } + + ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IENx, 0, ®); + if (ret) + return ret; + + reg |= 1 << func->num; + + reg |= 1; /* Master interrupt enable */ + + ret = mmc_io_rw_direct(func->card, 1, 0, SDIO_CCCR_IENx, reg, NULL); + if (ret) + return ret; + + func->irq_handler = handler; + ret = sdio_card_irq_get(func->card); + if (ret) + func->irq_handler = NULL; + + return ret; +} +EXPORT_SYMBOL_GPL(sdio_claim_irq); + +/** + * sdio_release_irq - release the IRQ for a SDIO function + * @func: SDIO function + * + * Disable and release the IRQ for the given SDIO function. + */ +int sdio_release_irq(struct sdio_func *func) +{ + int ret; + unsigned char reg; + + BUG_ON(!func); + BUG_ON(!func->card); + + pr_debug("SDIO: Disabling IRQ for %s...\n", sdio_func_id(func)); + + if (func->irq_handler) { + func->irq_handler = NULL; + sdio_card_irq_put(func->card); + } + + ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IENx, 0, ®); + if (ret) + return ret; + + reg &= ~(1 << func->num); + + /* Disable master interrupt with the last function interrupt */ + if (!(reg & 0xFE)) + reg = 0; + + ret = mmc_io_rw_direct(func->card, 1, 0, SDIO_CCCR_IENx, reg, NULL); + if (ret) + return ret; + + return 0; +} +EXPORT_SYMBOL_GPL(sdio_release_irq); + diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 8e2642ebf02..00dc1809494 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -123,6 +123,10 @@ struct mmc_host { unsigned int bus_refs; /* reference counter */ unsigned int bus_dead:1; /* bus has been released */ + unsigned int sdio_irqs; + struct task_struct *sdio_irq_thread; + atomic_t sdio_irq_thread_abort; + unsigned long private[0] ____cacheline_aligned; }; diff --git a/include/linux/mmc/sdio_func.h b/include/linux/mmc/sdio_func.h index 8106d399c41..a8d268c9c27 100644 --- a/include/linux/mmc/sdio_func.h +++ b/include/linux/mmc/sdio_func.h @@ -16,6 +16,9 @@ #include struct mmc_card; +struct sdio_func; + +typedef void (sdio_irq_handler_t)(struct sdio_func *); /* * SDIO function CIS tuple (unknown to the core) @@ -33,6 +36,7 @@ struct sdio_func_tuple { struct sdio_func { struct mmc_card *card; /* the card this device belongs to */ struct device dev; /* the device */ + sdio_irq_handler_t *irq_handler; /* IRQ callback */ unsigned int num; /* function number */ unsigned char class; /* standard interface class */ @@ -105,6 +109,9 @@ extern void sdio_release_host(struct sdio_func *func); extern int sdio_enable_func(struct sdio_func *func); extern int sdio_disable_func(struct sdio_func *func); +extern int sdio_claim_irq(struct sdio_func *func, sdio_irq_handler_t *handler); +extern int sdio_release_irq(struct sdio_func *func); + extern unsigned char sdio_readb(struct sdio_func *func, unsigned int addr, int *err_ret); -- cgit v1.2.3-70-g09d2 From 6e418a9d26ab4fd44b3e07dc1158027cbdf0a919 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Sat, 30 Jun 2007 02:04:21 -0400 Subject: sdio: UART/GPS driver This currently only accepts the GPS class since that's all I have for testing. Tested with a Matsushita GPS and gpsd version 2.34. Signed-off-by: Nicolas Pitre Signed-off-by: Pierre Ossman --- drivers/mmc/card/Kconfig | 7 + drivers/mmc/card/Makefile | 2 + drivers/mmc/card/sdio_uart.c | 1077 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1086 insertions(+) create mode 100644 drivers/mmc/card/sdio_uart.c (limited to 'drivers') diff --git a/drivers/mmc/card/Kconfig b/drivers/mmc/card/Kconfig index a49cb9737cd..aa8a4e46194 100644 --- a/drivers/mmc/card/Kconfig +++ b/drivers/mmc/card/Kconfig @@ -32,3 +32,10 @@ config MMC_BLOCK_BOUNCE If unsure, say Y here. +config SDIO_UART + tristate "SDIO UART/GPS class support" + depends on MMC + help + SDIO function driver for SDIO cards that implements the UART + class, as well as the GPS class which appears like a UART. + diff --git a/drivers/mmc/card/Makefile b/drivers/mmc/card/Makefile index cf8c939867f..fc5a784cfa1 100644 --- a/drivers/mmc/card/Makefile +++ b/drivers/mmc/card/Makefile @@ -9,3 +9,5 @@ endif obj-$(CONFIG_MMC_BLOCK) += mmc_block.o mmc_block-objs := block.o queue.o +obj-$(CONFIG_SDIO_UART) += sdio_uart.o + diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c new file mode 100644 index 00000000000..e4d9e85ff58 --- /dev/null +++ b/drivers/mmc/card/sdio_uart.c @@ -0,0 +1,1077 @@ +/* + * linux/drivers/mmc/card/sdio_uart.c - SDIO UART/GPS driver + * + * Based on drivers/serial/8250.c and drivers/serial/serial_core.c + * by Russell King. + * + * Author: Nicolas Pitre + * Created: June 15, 2007 + * Copyright: MontaVista Software, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + */ + +/* + * Note: Although this driver assumes a 16550A-like UART implementation, + * it is not possible to leverage the common 8250/16550 driver, nor the + * core UART infrastructure, as they assumes direct access to the hardware + * registers, often under a spinlock. This is not possible in the SDIO + * context as SDIO access functions must be able to sleep. + * + * Because we need to lock the SDIO host to ensure an exclusive access to + * the card, we simply rely on that lock to also prevent and serialize + * concurrent access to the same port. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +#define UART_NR 8 /* Number of UARTs this driver can handle */ + + +#define UART_XMIT_SIZE PAGE_SIZE +#define WAKEUP_CHARS 256 + +#define circ_empty(circ) ((circ)->head == (circ)->tail) +#define circ_clear(circ) ((circ)->head = (circ)->tail = 0) + +#define circ_chars_pending(circ) \ + (CIRC_CNT((circ)->head, (circ)->tail, UART_XMIT_SIZE)) + +#define circ_chars_free(circ) \ + (CIRC_SPACE((circ)->head, (circ)->tail, UART_XMIT_SIZE)) + + +struct uart_icount { + __u32 cts; + __u32 dsr; + __u32 rng; + __u32 dcd; + __u32 rx; + __u32 tx; + __u32 frame; + __u32 overrun; + __u32 parity; + __u32 brk; +}; + +struct sdio_uart_port { + struct kref kref; + struct tty_struct *tty; + unsigned int index; + unsigned int opened; + struct mutex open_lock; + struct sdio_func *func; + struct mutex func_lock; + unsigned int regs_offset; + struct circ_buf xmit; + spinlock_t write_lock; + struct uart_icount icount; + unsigned int uartclk; + unsigned int mctrl; + unsigned int read_status_mask; + unsigned int ignore_status_mask; + unsigned char x_char; + unsigned char ier; + unsigned char lcr; +}; + +static struct sdio_uart_port *sdio_uart_table[UART_NR]; +static DEFINE_SPINLOCK(sdio_uart_table_lock); + +static int sdio_uart_add_port(struct sdio_uart_port *port) +{ + int index, ret = -EBUSY; + + kref_init(&port->kref); + mutex_init(&port->open_lock); + mutex_init(&port->func_lock); + spin_lock_init(&port->write_lock); + + spin_lock(&sdio_uart_table_lock); + for (index = 0; index < UART_NR; index++) { + if (!sdio_uart_table[index]) { + port->index = index; + sdio_uart_table[index] = port; + ret = 0; + break; + } + } + spin_unlock(&sdio_uart_table_lock); + + return ret; +} + +static struct sdio_uart_port *sdio_uart_port_get(unsigned index) +{ + struct sdio_uart_port *port; + + if (index >= UART_NR) + return NULL; + + spin_lock(&sdio_uart_table_lock); + port = sdio_uart_table[index]; + if (port) + kref_get(&port->kref); + spin_unlock(&sdio_uart_table_lock); + + return port; +} + +static void sdio_uart_port_destroy(struct kref *kref) +{ + struct sdio_uart_port *port = + container_of(kref, struct sdio_uart_port, kref); + kfree(port); +} + +static void sdio_uart_port_put(struct sdio_uart_port *port) +{ + kref_put(&port->kref, sdio_uart_port_destroy); +} + +static void sdio_uart_port_remove(struct sdio_uart_port *port) +{ + struct sdio_func *func; + + BUG_ON(sdio_uart_table[port->index] != port); + + spin_lock(&sdio_uart_table_lock); + sdio_uart_table[port->index] = NULL; + spin_unlock(&sdio_uart_table_lock); + + /* + * We're killing a port that potentially still is in use by + * the tty layer. Be careful to prevent any further access + * to the SDIO function and arrange for the tty layer to + * give up on that port ASAP. + * Beware: the lock ordering is critical. + */ + mutex_lock(&port->open_lock); + mutex_lock(&port->func_lock); + func = port->func; + sdio_claim_host(func); + port->func = NULL; + mutex_unlock(&port->func_lock); + if (port->opened) + tty_hangup(port->tty); + mutex_unlock(&port->open_lock); + sdio_release_irq(func); + sdio_disable_func(func); + sdio_release_host(func); + + sdio_uart_port_put(port); +} + +static int sdio_uart_claim_func(struct sdio_uart_port *port) +{ + mutex_lock(&port->func_lock); + if (unlikely(!port->func)) { + mutex_unlock(&port->func_lock); + return -ENODEV; + } + sdio_claim_host(port->func); + mutex_unlock(&port->func_lock); + return 0; +} + +static inline void sdio_uart_release_func(struct sdio_uart_port *port) +{ + sdio_release_host(port->func); +} + +static inline unsigned int sdio_in(struct sdio_uart_port *port, int offset) +{ + unsigned char c; + c = sdio_readb(port->func, port->regs_offset + offset, NULL); + return c; +} + +static inline void sdio_out(struct sdio_uart_port *port, int offset, int value) +{ + sdio_writeb(port->func, value, port->regs_offset + offset, NULL); +} + +static unsigned int sdio_uart_get_mctrl(struct sdio_uart_port *port) +{ + unsigned char status; + unsigned int ret; + + status = sdio_in(port, UART_MSR); + + ret = 0; + if (status & UART_MSR_DCD) + ret |= TIOCM_CAR; + if (status & UART_MSR_RI) + ret |= TIOCM_RNG; + if (status & UART_MSR_DSR) + ret |= TIOCM_DSR; + if (status & UART_MSR_CTS) + ret |= TIOCM_CTS; + return ret; +} + +static void sdio_uart_write_mctrl(struct sdio_uart_port *port, unsigned int mctrl) +{ + unsigned char mcr = 0; + + if (mctrl & TIOCM_RTS) + mcr |= UART_MCR_RTS; + if (mctrl & TIOCM_DTR) + mcr |= UART_MCR_DTR; + if (mctrl & TIOCM_OUT1) + mcr |= UART_MCR_OUT1; + if (mctrl & TIOCM_OUT2) + mcr |= UART_MCR_OUT2; + if (mctrl & TIOCM_LOOP) + mcr |= UART_MCR_LOOP; + + sdio_out(port, UART_MCR, mcr); +} + +static inline void sdio_uart_update_mctrl(struct sdio_uart_port *port, + unsigned int set, unsigned int clear) +{ + unsigned int old; + + old = port->mctrl; + port->mctrl = (old & ~clear) | set; + if (old != port->mctrl) + sdio_uart_write_mctrl(port, port->mctrl); +} + +#define sdio_uart_set_mctrl(port, x) sdio_uart_update_mctrl(port, x, 0) +#define sdio_uart_clear_mctrl(port, x) sdio_uart_update_mctrl(port, 0, x) + +static void sdio_uart_change_speed(struct sdio_uart_port *port, + struct ktermios *termios, + struct ktermios *old) +{ + unsigned char cval, fcr = 0; + unsigned int baud, quot; + + switch (termios->c_cflag & CSIZE) { + case CS5: + cval = UART_LCR_WLEN5; + break; + case CS6: + cval = UART_LCR_WLEN6; + break; + case CS7: + cval = UART_LCR_WLEN7; + break; + default: + case CS8: + cval = UART_LCR_WLEN8; + break; + } + + if (termios->c_cflag & CSTOPB) + cval |= UART_LCR_STOP; + if (termios->c_cflag & PARENB) + cval |= UART_LCR_PARITY; + if (!(termios->c_cflag & PARODD)) + cval |= UART_LCR_EPAR; + + for (;;) { + baud = tty_termios_baud_rate(termios); + if (baud == 0) + baud = 9600; /* Special case: B0 rate. */ + if (baud <= port->uartclk) + break; + /* + * Oops, the quotient was zero. Try again with the old + * baud rate if possible, otherwise default to 9600. + */ + termios->c_cflag &= ~CBAUD; + if (old) { + termios->c_cflag |= old->c_cflag & CBAUD; + old = NULL; + } else + termios->c_cflag |= B9600; + } + quot = (2 * port->uartclk + baud) / (2 * baud); + + if (baud < 2400) + fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1; + else + fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10; + + port->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; + if (termios->c_iflag & INPCK) + port->read_status_mask |= UART_LSR_FE | UART_LSR_PE; + if (termios->c_iflag & (BRKINT | PARMRK)) + port->read_status_mask |= UART_LSR_BI; + + /* + * Characters to ignore + */ + port->ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; + if (termios->c_iflag & IGNBRK) { + port->ignore_status_mask |= UART_LSR_BI; + /* + * If we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= UART_LSR_OE; + } + + /* + * ignore all characters if CREAD is not set + */ + if ((termios->c_cflag & CREAD) == 0) + port->ignore_status_mask |= UART_LSR_DR; + + /* + * CTS flow control flag and modem status interrupts + */ + port->ier &= ~UART_IER_MSI; + if ((termios->c_cflag & CRTSCTS) || !(termios->c_cflag & CLOCAL)) + port->ier |= UART_IER_MSI; + + port->lcr = cval; + + sdio_out(port, UART_IER, port->ier); + sdio_out(port, UART_LCR, cval | UART_LCR_DLAB); + sdio_out(port, UART_DLL, quot & 0xff); + sdio_out(port, UART_DLM, quot >> 8); + sdio_out(port, UART_LCR, cval); + sdio_out(port, UART_FCR, fcr); + + sdio_uart_write_mctrl(port, port->mctrl); +} + +static void sdio_uart_start_tx(struct sdio_uart_port *port) +{ + if (!(port->ier & UART_IER_THRI)) { + port->ier |= UART_IER_THRI; + sdio_out(port, UART_IER, port->ier); + } +} + +static void sdio_uart_stop_tx(struct sdio_uart_port *port) +{ + if (port->ier & UART_IER_THRI) { + port->ier &= ~UART_IER_THRI; + sdio_out(port, UART_IER, port->ier); + } +} + +static void sdio_uart_stop_rx(struct sdio_uart_port *port) +{ + port->ier &= ~UART_IER_RLSI; + port->read_status_mask &= ~UART_LSR_DR; + sdio_out(port, UART_IER, port->ier); +} + +static void sdio_uart_receive_chars(struct sdio_uart_port *port, int *status) +{ + struct tty_struct *tty = port->tty; + unsigned int ch, flag; + int max_count = 256; + + do { + ch = sdio_in(port, UART_RX); + flag = TTY_NORMAL; + port->icount.rx++; + + if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE | + UART_LSR_FE | UART_LSR_OE))) { + /* + * For statistics only + */ + if (*status & UART_LSR_BI) { + *status &= ~(UART_LSR_FE | UART_LSR_PE); + port->icount.brk++; + } else if (*status & UART_LSR_PE) + port->icount.parity++; + else if (*status & UART_LSR_FE) + port->icount.frame++; + if (*status & UART_LSR_OE) + port->icount.overrun++; + + /* + * Mask off conditions which should be ignored. + */ + *status &= port->read_status_mask; + if (*status & UART_LSR_BI) { + flag = TTY_BREAK; + } else if (*status & UART_LSR_PE) + flag = TTY_PARITY; + else if (*status & UART_LSR_FE) + flag = TTY_FRAME; + } + + if ((*status & port->ignore_status_mask & ~UART_LSR_OE) == 0) + tty_insert_flip_char(tty, ch, flag); + + /* + * Overrun is special. Since it's reported immediately, + * it doesn't affect the current character. + */ + if (*status & ~port->ignore_status_mask & UART_LSR_OE) + tty_insert_flip_char(tty, 0, TTY_OVERRUN); + + *status = sdio_in(port, UART_LSR); + } while ((*status & UART_LSR_DR) && (max_count-- > 0)); + tty_flip_buffer_push(tty); +} + +static void sdio_uart_transmit_chars(struct sdio_uart_port *port) +{ + struct circ_buf *xmit = &port->xmit; + int count; + + if (port->x_char) { + sdio_out(port, UART_TX, port->x_char); + port->icount.tx++; + port->x_char = 0; + return; + } + if (circ_empty(xmit) || port->tty->stopped || port->tty->hw_stopped) { + sdio_uart_stop_tx(port); + return; + } + + count = 16; + do { + sdio_out(port, UART_TX, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + if (circ_empty(xmit)) + break; + } while (--count > 0); + + if (circ_chars_pending(xmit) < WAKEUP_CHARS) + tty_wakeup(port->tty); + + if (circ_empty(xmit)) + sdio_uart_stop_tx(port); +} + +static void sdio_uart_check_modem_status(struct sdio_uart_port *port) +{ + int status; + + status = sdio_in(port, UART_MSR); + + if ((status & UART_MSR_ANY_DELTA) == 0) + return; + + if (status & UART_MSR_TERI) + port->icount.rng++; + if (status & UART_MSR_DDSR) + port->icount.dsr++; + if (status & UART_MSR_DDCD) + port->icount.dcd++; + if (status & UART_MSR_DCTS) { + port->icount.cts++; + if (port->tty->termios->c_cflag & CRTSCTS) { + int cts = (status & UART_MSR_CTS); + if (port->tty->hw_stopped) { + if (cts) { + port->tty->hw_stopped = 0; + sdio_uart_start_tx(port); + tty_wakeup(port->tty); + } + } else { + if (!cts) { + port->tty->hw_stopped = 1; + sdio_uart_stop_tx(port); + } + } + } + } +} + +/* + * This handles the interrupt from one port. + */ +static void sdio_uart_irq(struct sdio_func *func) +{ + struct sdio_uart_port *port = sdio_get_drvdata(func); + unsigned int iir, lsr; + + iir = sdio_in(port, UART_IIR); + if (iir & UART_IIR_NO_INT) + return; + lsr = sdio_in(port, UART_LSR); + if (lsr & UART_LSR_DR) + sdio_uart_receive_chars(port, &lsr); + sdio_uart_check_modem_status(port); + if (lsr & UART_LSR_THRE) + sdio_uart_transmit_chars(port); +} + +static int sdio_uart_startup(struct sdio_uart_port *port) +{ + unsigned long page; + int ret; + + /* + * Set the TTY IO error marker - we will only clear this + * once we have successfully opened the port. + */ + set_bit(TTY_IO_ERROR, &port->tty->flags); + + /* Initialise and allocate the transmit buffer. */ + page = __get_free_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + port->xmit.buf = (unsigned char *)page; + circ_clear(&port->xmit); + + ret = sdio_uart_claim_func(port); + if (ret) + goto err1; + ret = sdio_enable_func(port->func); + if (ret) + goto err2; + ret = sdio_claim_irq(port->func, sdio_uart_irq); + if (ret) + goto err3; + + /* + * Clear the FIFO buffers and disable them. + * (they will be reenabled in sdio_change_speed()) + */ + sdio_out(port, UART_FCR, UART_FCR_ENABLE_FIFO); + sdio_out(port, UART_FCR, UART_FCR_ENABLE_FIFO | + UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); + sdio_out(port, UART_FCR, 0); + + /* + * Clear the interrupt registers. + */ + (void) sdio_in(port, UART_LSR); + (void) sdio_in(port, UART_RX); + (void) sdio_in(port, UART_IIR); + (void) sdio_in(port, UART_MSR); + + /* + * Now, initialize the UART + */ + sdio_out(port, UART_LCR, UART_LCR_WLEN8); + + port->ier = UART_IER_RLSI | UART_IER_RDI | UART_IER_RTOIE | UART_IER_UUE; + port->mctrl = TIOCM_OUT2; + + sdio_uart_change_speed(port, port->tty->termios, NULL); + + if (port->tty->termios->c_cflag & CBAUD) + sdio_uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR); + + if (port->tty->termios->c_cflag & CRTSCTS) + if (!(sdio_uart_get_mctrl(port) & TIOCM_CTS)) + port->tty->hw_stopped = 1; + + clear_bit(TTY_IO_ERROR, &port->tty->flags); + + /* Kick the IRQ handler once while we're still holding the host lock */ + sdio_uart_irq(port->func); + + sdio_uart_release_func(port); + return 0; + +err3: + sdio_disable_func(port->func); +err2: + sdio_uart_release_func(port); +err1: + free_page((unsigned long)port->xmit.buf); + return ret; +} + +static void sdio_uart_shutdown(struct sdio_uart_port *port) +{ + int ret; + + ret = sdio_uart_claim_func(port); + if (ret) + goto skip; + + sdio_uart_stop_rx(port); + + /* TODO: wait here for TX FIFO to drain */ + + /* Turn off DTR and RTS early. */ + if (port->tty->termios->c_cflag & HUPCL) + sdio_uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); + + /* Disable interrupts from this port */ + sdio_release_irq(port->func); + port->ier = 0; + sdio_out(port, UART_IER, 0); + + sdio_uart_clear_mctrl(port, TIOCM_OUT2); + + /* Disable break condition and FIFOs. */ + port->lcr &= ~UART_LCR_SBC; + sdio_out(port, UART_LCR, port->lcr); + sdio_out(port, UART_FCR, UART_FCR_ENABLE_FIFO | + UART_FCR_CLEAR_RCVR | + UART_FCR_CLEAR_XMIT); + sdio_out(port, UART_FCR, 0); + + sdio_disable_func(port->func); + + sdio_uart_release_func(port); + +skip: + /* Free the transmit buffer page. */ + free_page((unsigned long)port->xmit.buf); +} + +static int sdio_uart_open (struct tty_struct *tty, struct file * filp) +{ + struct sdio_uart_port *port; + int ret; + + port = sdio_uart_port_get(tty->index); + if (!port) + return -ENODEV; + + mutex_lock(&port->open_lock); + + /* + * Make sure not to mess up with a dead port + * which has not been closed yet. + */ + if (tty->driver_data && tty->driver_data != port) { + mutex_unlock(&port->open_lock); + sdio_uart_port_put(port); + return -EBUSY; + } + + if (!port->opened) { + tty->driver_data = port; + port->tty = tty; + ret = sdio_uart_startup(port); + if (ret) { + tty->driver_data = NULL; + port->tty = NULL; + mutex_unlock(&port->open_lock); + sdio_uart_port_put(port); + return ret; + } + } + port->opened++; + mutex_unlock(&port->open_lock); + return 0; +} + +static void sdio_uart_close(struct tty_struct *tty, struct file * filp) +{ + struct sdio_uart_port *port = tty->driver_data; + + if (!port) + return; + + mutex_lock(&port->open_lock); + BUG_ON(!port->opened); + + /* + * This is messy. The tty layer calls us even when open() + * returned an error. Ignore this close request if tty->count + * is larger than port->count. + */ + if (tty->count > port->opened) { + mutex_unlock(&port->open_lock); + return; + } + + if (--port->opened == 0) { + tty->closing = 1; + sdio_uart_shutdown(port); + tty_ldisc_flush(tty); + port->tty = NULL; + tty->driver_data = NULL; + tty->closing = 0; + } + mutex_unlock(&port->open_lock); + sdio_uart_port_put(port); +} + +static int sdio_uart_write(struct tty_struct * tty, const unsigned char *buf, + int count) +{ + struct sdio_uart_port *port = tty->driver_data; + struct circ_buf *circ = &port->xmit; + int c, ret = 0; + + if (!port->func) + return -ENODEV; + + spin_lock(&port->write_lock); + while (1) { + c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE); + if (count < c) + c = count; + if (c <= 0) + break; + memcpy(circ->buf + circ->head, buf, c); + circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1); + buf += c; + count -= c; + ret += c; + } + spin_unlock(&port->write_lock); + + if ( !(port->ier & UART_IER_THRI)) { + int err = sdio_uart_claim_func(port); + if (!err) { + sdio_uart_start_tx(port); + sdio_uart_irq(port->func); + sdio_uart_release_func(port); + } else + ret = err; + } + + return ret; +} + +static int sdio_uart_write_room(struct tty_struct *tty) +{ + struct sdio_uart_port *port = tty->driver_data; + return port ? circ_chars_free(&port->xmit) : 0; +} + +static int sdio_uart_chars_in_buffer(struct tty_struct *tty) +{ + struct sdio_uart_port *port = tty->driver_data; + return port ? circ_chars_pending(&port->xmit) : 0; +} + +static void sdio_uart_send_xchar(struct tty_struct *tty, char ch) +{ + struct sdio_uart_port *port = tty->driver_data; + + port->x_char = ch; + if (ch && !(port->ier & UART_IER_THRI)) { + if (sdio_uart_claim_func(port) != 0) + return; + sdio_uart_start_tx(port); + sdio_uart_irq(port->func); + sdio_uart_release_func(port); + } +} + +static void sdio_uart_throttle(struct tty_struct *tty) +{ + struct sdio_uart_port *port = tty->driver_data; + + if (!I_IXOFF(tty) && !(tty->termios->c_cflag & CRTSCTS)) + return; + + if (sdio_uart_claim_func(port) != 0) + return; + + if (I_IXOFF(tty)) { + port->x_char = STOP_CHAR(tty); + sdio_uart_start_tx(port); + } + + if (tty->termios->c_cflag & CRTSCTS) + sdio_uart_clear_mctrl(port, TIOCM_RTS); + + sdio_uart_irq(port->func); + sdio_uart_release_func(port); +} + +static void sdio_uart_unthrottle(struct tty_struct *tty) +{ + struct sdio_uart_port *port = tty->driver_data; + + if (!I_IXOFF(tty) && !(tty->termios->c_cflag & CRTSCTS)) + return; + + if (sdio_uart_claim_func(port) != 0) + return; + + if (I_IXOFF(tty)) { + if (port->x_char) { + port->x_char = 0; + } else { + port->x_char = START_CHAR(tty); + sdio_uart_start_tx(port); + } + } + + if (tty->termios->c_cflag & CRTSCTS) + sdio_uart_set_mctrl(port, TIOCM_RTS); + + sdio_uart_irq(port->func); + sdio_uart_release_func(port); +} + +static void sdio_uart_set_termios(struct tty_struct *tty, struct ktermios *old_termios) +{ + struct sdio_uart_port *port = tty->driver_data; + unsigned int cflag = tty->termios->c_cflag; + +#define RELEVANT_IFLAG(iflag) ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) + + if ((cflag ^ old_termios->c_cflag) == 0 && + RELEVANT_IFLAG(tty->termios->c_iflag ^ old_termios->c_iflag) == 0) + return; + + if (sdio_uart_claim_func(port) != 0) + return; + + sdio_uart_change_speed(port, tty->termios, old_termios); + + /* Handle transition to B0 status */ + if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD)) + sdio_uart_clear_mctrl(port, TIOCM_RTS | TIOCM_DTR); + + /* Handle transition away from B0 status */ + if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) { + unsigned int mask = TIOCM_DTR; + if (!(cflag & CRTSCTS) || !test_bit(TTY_THROTTLED, &tty->flags)) + mask |= TIOCM_RTS; + sdio_uart_set_mctrl(port, mask); + } + + /* Handle turning off CRTSCTS */ + if ((old_termios->c_cflag & CRTSCTS) && !(cflag & CRTSCTS)) { + tty->hw_stopped = 0; + sdio_uart_start_tx(port); + } + + /* Handle turning on CRTSCTS */ + if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) { + if (!(sdio_uart_get_mctrl(port) & TIOCM_CTS)) { + tty->hw_stopped = 1; + sdio_uart_stop_tx(port); + } + } + + sdio_uart_release_func(port); +} + +static void sdio_uart_break_ctl(struct tty_struct *tty, int break_state) +{ + struct sdio_uart_port *port = tty->driver_data; + + if (sdio_uart_claim_func(port) != 0) + return; + + if (break_state == -1) + port->lcr |= UART_LCR_SBC; + else + port->lcr &= ~UART_LCR_SBC; + sdio_out(port, UART_LCR, port->lcr); + + sdio_uart_release_func(port); +} + +static int sdio_uart_tiocmget(struct tty_struct *tty, struct file *file) +{ + struct sdio_uart_port *port = tty->driver_data; + int result; + + result = sdio_uart_claim_func(port); + if (!result) { + result = port->mctrl | sdio_uart_get_mctrl(port); + sdio_uart_release_func(port); + } + + return result; +} + +static int sdio_uart_tiocmset(struct tty_struct *tty, struct file *file, + unsigned int set, unsigned int clear) +{ + struct sdio_uart_port *port = tty->driver_data; + int result; + + result =sdio_uart_claim_func(port); + if(!result) { + sdio_uart_update_mctrl(port, set, clear); + sdio_uart_release_func(port); + } + + return result; +} + +static const struct tty_operations sdio_uart_ops = { + .open = sdio_uart_open, + .close = sdio_uart_close, + .write = sdio_uart_write, + .write_room = sdio_uart_write_room, + .chars_in_buffer = sdio_uart_chars_in_buffer, + .send_xchar = sdio_uart_send_xchar, + .throttle = sdio_uart_throttle, + .unthrottle = sdio_uart_unthrottle, + .set_termios = sdio_uart_set_termios, + .break_ctl = sdio_uart_break_ctl, + .tiocmget = sdio_uart_tiocmget, + .tiocmset = sdio_uart_tiocmset, +}; + +static struct tty_driver *sdio_uart_tty_driver; + +static int sdio_uart_probe(struct sdio_func *func, + const struct sdio_device_id *id) +{ + struct sdio_uart_port *port; + int ret; + + port = kzalloc(sizeof(struct sdio_uart_port), GFP_KERNEL); + if (!port) + return -ENOMEM; + + if (func->class == SDIO_CLASS_UART) { + printk(KERN_WARNING "%s: need info on UART class basic setup\n", + sdio_func_id(func)); + kfree(port); + return -ENOSYS; + } else if (func->class == SDIO_CLASS_GPS) { + /* + * We need tuple 0x91. It contains SUBTPL_SIOREG + * and SUBTPL_RCVCAPS. + */ + struct sdio_func_tuple *tpl; + for (tpl = func->tuples; tpl; tpl = tpl->next) { + if (tpl->code != 0x91) + continue; + if (tpl->size < 10) + continue; + if (tpl->data[1] == 0) /* SUBTPL_SIOREG */ + break; + } + if (!tpl) { + printk(KERN_WARNING + "%s: can't find tuple 0x91 subtuple 0 (SUBTPL_SIOREG) for GPS class\n", + sdio_func_id(func)); + kfree(port); + return -EINVAL; + } + printk(KERN_DEBUG "%s: Register ID = 0x%02x, Exp ID = 0x%02x\n", + sdio_func_id(func), tpl->data[2], tpl->data[3]); + port->regs_offset = (tpl->data[4] << 0) | + (tpl->data[5] << 8) | + (tpl->data[6] << 16); + printk(KERN_DEBUG "%s: regs offset = 0x%x\n", + sdio_func_id(func), port->regs_offset); + port->uartclk = tpl->data[7] * 115200; + if (port->uartclk == 0) + port->uartclk = 115200; + printk(KERN_DEBUG "%s: clk %d baudcode %u 4800-div %u\n", + sdio_func_id(func), port->uartclk, + tpl->data[7], tpl->data[8] | (tpl->data[9] << 8)); + } else { + kfree(port); + return -EINVAL; + } + + port->func = func; + sdio_set_drvdata(func, port); + + ret = sdio_uart_add_port(port); + if (ret) { + kfree(port); + } else { + struct device *dev; + dev = tty_register_device(sdio_uart_tty_driver, port->index, &func->dev); + if (IS_ERR(dev)) { + sdio_uart_port_remove(port); + ret = PTR_ERR(dev); + } + } + + return ret; +} + +static void sdio_uart_remove(struct sdio_func *func) +{ + struct sdio_uart_port *port = sdio_get_drvdata(func); + + tty_unregister_device(sdio_uart_tty_driver, port->index); + sdio_uart_port_remove(port); +} + +static const struct sdio_device_id sdio_uart_ids[] = { + { SDIO_DEVICE_CLASS(SDIO_CLASS_UART) }, + { SDIO_DEVICE_CLASS(SDIO_CLASS_GPS) }, + { /* end: all zeroes */ }, +}; + +MODULE_DEVICE_TABLE(sdio, sdio_uart_ids); + +static struct sdio_driver sdio_uart_driver = { + .probe = sdio_uart_probe, + .remove = sdio_uart_remove, + .name = "sdio_uart", + .id_table = sdio_uart_ids, +}; + +static int __init sdio_uart_init(void) +{ + int ret; + struct tty_driver *tty_drv; + + sdio_uart_tty_driver = tty_drv = alloc_tty_driver(UART_NR); + if (!tty_drv) + return -ENOMEM; + + tty_drv->owner = THIS_MODULE; + tty_drv->driver_name = "sdio_uart"; + tty_drv->name = "ttySDIO"; + tty_drv->major = 0; /* dynamically allocated */ + tty_drv->minor_start = 0; + tty_drv->type = TTY_DRIVER_TYPE_SERIAL; + tty_drv->subtype = SERIAL_TYPE_NORMAL; + tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; + tty_drv->init_termios = tty_std_termios; + tty_drv->init_termios.c_cflag = B4800 | CS8 | CREAD | HUPCL | CLOCAL; + tty_set_operations(tty_drv, &sdio_uart_ops); + + ret = tty_register_driver(tty_drv); + if (ret) + goto err1; + + ret = sdio_register_driver(&sdio_uart_driver); + if (ret) + goto err2; + + return 0; + +err2: + tty_unregister_driver(tty_drv); +err1: + put_tty_driver(tty_drv); + return ret; +} + +static void __exit sdio_uart_exit(void) +{ + sdio_unregister_driver(&sdio_uart_driver); + tty_unregister_driver(sdio_uart_tty_driver); + put_tty_driver(sdio_uart_tty_driver); +} + +module_init(sdio_uart_init); +module_exit(sdio_uart_exit); + +MODULE_AUTHOR("Nicolas Pitre"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-70-g09d2 From 5ed334a1f8caaae98806d572f78c5802975ea20f Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Wed, 4 Jul 2007 23:40:34 -0400 Subject: sdio: add /proc interface to sdio_uart driver This mimics what the serial_core does. Useful for diagnostics. Signed-off-by: Nicolas Pitre Signed-off-by: Pierre Ossman --- drivers/mmc/card/sdio_uart.c | 62 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c index e4d9e85ff58..190120d1449 100644 --- a/drivers/mmc/card/sdio_uart.c +++ b/drivers/mmc/card/sdio_uart.c @@ -913,6 +913,67 @@ static int sdio_uart_tiocmset(struct tty_struct *tty, struct file *file, return result; } +static int sdio_uart_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int i, len = 0; + off_t begin = 0; + + len += sprintf(page, "serinfo:1.0 driver%s%s revision:%s\n", + "", "", ""); + for (i = 0; i < UART_NR && len < PAGE_SIZE - 96; i++) { + struct sdio_uart_port *port = sdio_uart_port_get(i); + if (port) { + len += sprintf(page+len, "%d: uart:SDIO", i); + if(capable(CAP_SYS_ADMIN)) { + len += sprintf(page + len, " tx:%d rx:%d", + port->icount.tx, port->icount.rx); + if (port->icount.frame) + len += sprintf(page + len, " fe:%d", + port->icount.frame); + if (port->icount.parity) + len += sprintf(page + len, " pe:%d", + port->icount.parity); + if (port->icount.brk) + len += sprintf(page + len, " brk:%d", + port->icount.brk); + if (port->icount.overrun) + len += sprintf(page + len, " oe:%d", + port->icount.overrun); + if (port->icount.cts) + len += sprintf(page + len, " cts:%d", + port->icount.cts); + if (port->icount.dsr) + len += sprintf(page + len, " dsr:%d", + port->icount.dsr); + if (port->icount.rng) + len += sprintf(page + len, " rng:%d", + port->icount.rng); + if (port->icount.dcd) + len += sprintf(page + len, " dcd:%d", + port->icount.dcd); + } + strcat(page, "\n"); + len++; + sdio_uart_port_put(port); + } + + if (len + begin > off + count) + goto done; + if (len + begin < off) { + begin += len; + len = 0; + } + } + *eof = 1; + +done: + if (off >= len + begin) + return 0; + *start = page + (off - begin); + return (count < begin + len - off) ? count : (begin + len - off); +} + static const struct tty_operations sdio_uart_ops = { .open = sdio_uart_open, .close = sdio_uart_close, @@ -926,6 +987,7 @@ static const struct tty_operations sdio_uart_ops = { .break_ctl = sdio_uart_break_ctl, .tiocmget = sdio_uart_tiocmget, .tiocmset = sdio_uart_tiocmset, + .read_proc = sdio_uart_read_proc, }; static struct tty_driver *sdio_uart_tty_driver; -- cgit v1.2.3-70-g09d2 From 112c9db91ee6bf19eca7cbb6854be3127381c229 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 6 Jul 2007 13:35:01 +0200 Subject: sdio: support IO_RW_EXTENDED Support the multi-byte transfer operation, including handlers for common operations like writel()/readl(). Signed-off-by: Pierre Ossman --- drivers/mmc/core/sdio_io.c | 184 ++++++++++++++++++++++++++++++++++++++++++ drivers/mmc/core/sdio_ops.c | 57 +++++++++++++ drivers/mmc/core/sdio_ops.h | 2 + include/linux/mmc/sdio.h | 12 +++ include/linux/mmc/sdio_func.h | 20 +++++ 5 files changed, 275 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c index eb6c20935ce..ecdb77242e9 100644 --- a/drivers/mmc/core/sdio_io.c +++ b/drivers/mmc/core/sdio_io.c @@ -196,3 +196,187 @@ void sdio_writeb(struct sdio_func *func, unsigned char b, unsigned int addr, } EXPORT_SYMBOL_GPL(sdio_writeb); +/** + * sdio_memcpy_fromio - read a chunk of memory from a SDIO function + * @func: SDIO function to access + * @dst: buffer to store the data + * @addr: address to begin reading from + * @count: number of bytes to read + * + * Reads up to 512 bytes from the address space of a given SDIO + * function. Return value indicates if the transfer succeeded or + * not. + */ +int sdio_memcpy_fromio(struct sdio_func *func, void *dst, + unsigned int addr, int count) +{ + return mmc_io_rw_extended(func->card, 0, func->num, addr, 0, dst, + count); +} +EXPORT_SYMBOL_GPL(sdio_memcpy_fromio); + +/** + * sdio_memcpy_toio - write a chunk of memory to a SDIO function + * @func: SDIO function to access + * @addr: address to start writing to + * @src: buffer that contains the data to write + * @count: number of bytes to write + * + * Writes up to 512 bytes to the address space of a given SDIO + * function. Return value indicates if the transfer succeeded or + * not. + */ +int sdio_memcpy_toio(struct sdio_func *func, unsigned int addr, + void *src, int count) +{ + return mmc_io_rw_extended(func->card, 1, func->num, addr, 0, src, + count); +} +EXPORT_SYMBOL_GPL(sdio_memcpy_toio); + +/** + * sdio_readsb - read from a FIFO on a SDIO function + * @func: SDIO function to access + * @dst: buffer to store the data + * @addr: address of (single byte) FIFO + * @count: number of bytes to read + * + * Reads up to 512 bytes from the specified FIFO of a given SDIO + * function. Return value indicates if the transfer succeeded or + * not. + */ +int sdio_readsb(struct sdio_func *func, void *dst, unsigned int addr, + int count) +{ + return mmc_io_rw_extended(func->card, 0, func->num, addr, 1, dst, + count); +} + +EXPORT_SYMBOL_GPL(sdio_readsb); + +/** + * sdio_writesb - write to a FIFO of a SDIO function + * @func: SDIO function to access + * @addr: address of (single byte) FIFO + * @src: buffer that contains the data to write + * @count: number of bytes to write + * + * Writes up to 512 bytes to the specified FIFO of a given SDIO + * function. Return value indicates if the transfer succeeded or + * not. + */ +int sdio_writesb(struct sdio_func *func, unsigned int addr, void *src, + int count) +{ + return mmc_io_rw_extended(func->card, 1, func->num, addr, 1, src, + count); +} +EXPORT_SYMBOL_GPL(sdio_writesb); + +/** + * sdio_readw - read a 16 bit integer from a SDIO function + * @func: SDIO function to access + * @addr: address to read + * @err_ret: optional status value from transfer + * + * Reads a 16 bit integer from the address space of a given SDIO + * function. If there is a problem reading the address, 0xffff + * is returned and @err_ret will contain the error code. + */ +unsigned short sdio_readw(struct sdio_func *func, unsigned int addr, + int *err_ret) +{ + int ret; + + if (err_ret) + *err_ret = 0; + + ret = sdio_memcpy_fromio(func, func->tmpbuf, addr, 2); + if (ret) { + if (err_ret) + *err_ret = ret; + return 0xFFFF; + } + + return le16_to_cpu(*(u16*)func->tmpbuf); +} +EXPORT_SYMBOL_GPL(sdio_readw); + +/** + * sdio_writew - write a 16 bit integer to a SDIO function + * @func: SDIO function to access + * @b: integer to write + * @addr: address to write to + * @err_ret: optional status value from transfer + * + * Writes a 16 bit integer to the address space of a given SDIO + * function. @err_ret will contain the status of the actual + * transfer. + */ +void sdio_writew(struct sdio_func *func, unsigned short b, unsigned int addr, + int *err_ret) +{ + int ret; + + *(u16*)func->tmpbuf = cpu_to_le16(b); + + ret = sdio_memcpy_toio(func, addr, func->tmpbuf, 2); + if (err_ret) + *err_ret = ret; +} +EXPORT_SYMBOL_GPL(sdio_writew); + +/** + * sdio_readl - read a 32 bit integer from a SDIO function + * @func: SDIO function to access + * @addr: address to read + * @err_ret: optional status value from transfer + * + * Reads a 32 bit integer from the address space of a given SDIO + * function. If there is a problem reading the address, + * 0xffffffff is returned and @err_ret will contain the error + * code. + */ +unsigned long sdio_readl(struct sdio_func *func, unsigned int addr, + int *err_ret) +{ + int ret; + + if (err_ret) + *err_ret = 0; + + ret = sdio_memcpy_fromio(func, func->tmpbuf, addr, 4); + if (ret) { + if (err_ret) + *err_ret = ret; + return 0xFFFFFFFF; + } + + return le32_to_cpu(*(u32*)func->tmpbuf); +} +EXPORT_SYMBOL_GPL(sdio_readl); + +/** + * sdio_writel - write a 32 bit integer to a SDIO function + * @func: SDIO function to access + * @b: integer to write + * @addr: address to write to + * @err_ret: optional status value from transfer + * + * Writes a 32 bit integer to the address space of a given SDIO + * function. @err_ret will contain the status of the actual + * transfer. + */ +void sdio_writel(struct sdio_func *func, unsigned long b, unsigned int addr, + int *err_ret) +{ + int ret; + + *(u32*)func->tmpbuf = cpu_to_le32(b); + + ret = sdio_memcpy_toio(func, addr, func->tmpbuf, 4); + if (err_ret) + *err_ret = ret; +} +EXPORT_SYMBOL_GPL(sdio_writel); + diff --git a/drivers/mmc/core/sdio_ops.c b/drivers/mmc/core/sdio_ops.c index 31233f7b55c..4f2c7713947 100644 --- a/drivers/mmc/core/sdio_ops.c +++ b/drivers/mmc/core/sdio_ops.c @@ -9,6 +9,9 @@ * your option) any later version. */ +#include +#include + #include #include #include @@ -84,3 +87,57 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, return 0; } +int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, + unsigned addr, int bang, u8 *buf, unsigned size) +{ + struct mmc_request mrq; + struct mmc_command cmd; + struct mmc_data data; + struct scatterlist sg; + + BUG_ON(!card); + BUG_ON(fn > 7); + BUG_ON(size > 512); + + memset(&mrq, 0, sizeof(struct mmc_request)); + memset(&cmd, 0, sizeof(struct mmc_command)); + memset(&data, 0, sizeof(struct mmc_data)); + + mrq.cmd = &cmd; + mrq.data = &data; + + cmd.opcode = SD_IO_RW_EXTENDED; + cmd.arg = write ? 0x80000000 : 0x00000000; + cmd.arg |= fn << 28; + cmd.arg |= bang ? 0x00000000 : 0x04000000; + cmd.arg |= addr << 9; + cmd.arg |= (size == 512) ? 0 : size; + cmd.flags = MMC_RSP_R5 | MMC_CMD_ADTC; + + data.blksz = size; + data.blocks = 1; + data.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ; + data.sg = &sg; + data.sg_len = 1; + + sg_init_one(&sg, buf, size); + + mmc_set_data_timeout(&data, card); + + mmc_wait_for_req(card->host, &mrq); + + if (cmd.error) + return cmd.error; + if (data.error) + return data.error; + + if (cmd.resp[0] & R5_ERROR) + return -EIO; + if (cmd.resp[0] & R5_FUNCTION_NUMBER) + return -EINVAL; + if (cmd.resp[0] & R5_OUT_OF_RANGE) + return -ERANGE; + + return 0; +} + diff --git a/drivers/mmc/core/sdio_ops.h b/drivers/mmc/core/sdio_ops.h index f0e9d69e5ce..1d42e4f366a 100644 --- a/drivers/mmc/core/sdio_ops.h +++ b/drivers/mmc/core/sdio_ops.h @@ -15,6 +15,8 @@ int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr); int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, unsigned addr, u8 in, u8* out); +int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, + unsigned addr, int bang, u8 *data, unsigned size); #endif diff --git a/include/linux/mmc/sdio.h b/include/linux/mmc/sdio.h index 56239f4aab0..9b1ec76cac3 100644 --- a/include/linux/mmc/sdio.h +++ b/include/linux/mmc/sdio.h @@ -15,6 +15,7 @@ /* SDIO commands type argument response */ #define SD_IO_SEND_OP_COND 5 /* bcr [23:0] OCR R4 */ #define SD_IO_RW_DIRECT 52 /* ac [31:0] See below R5 */ +#define SD_IO_RW_EXTENDED 53 /* adtc [31:0] See below R5 */ /* * SD_IO_RW_DIRECT argument format: @@ -26,6 +27,17 @@ * [7:0] Data */ +/* + * SD_IO_RW_EXTENDED argument format: + * + * [31] R/W flag + * [30:28] Function number + * [27] Block mode + * [26] Increment address + * [25:9] Register address + * [8:0] Byte/block count + */ + /* SDIO status in R5 Type diff --git a/include/linux/mmc/sdio_func.h b/include/linux/mmc/sdio_func.h index a8d268c9c27..af813fffc4a 100644 --- a/include/linux/mmc/sdio_func.h +++ b/include/linux/mmc/sdio_func.h @@ -48,6 +48,8 @@ struct sdio_func { unsigned int state; /* function state */ #define SDIO_STATE_PRESENT (1<<0) /* present in sysfs */ + u8 tmpbuf[4]; /* DMA:able scratch buffer */ + struct sdio_func_tuple *tuples; }; @@ -114,9 +116,27 @@ extern int sdio_release_irq(struct sdio_func *func); extern unsigned char sdio_readb(struct sdio_func *func, unsigned int addr, int *err_ret); +extern unsigned short sdio_readw(struct sdio_func *func, + unsigned int addr, int *err_ret); +extern unsigned long sdio_readl(struct sdio_func *func, + unsigned int addr, int *err_ret); + +extern int sdio_memcpy_fromio(struct sdio_func *func, void *dst, + unsigned int addr, int count); +extern int sdio_readsb(struct sdio_func *func, void *dst, + unsigned int addr, int count); extern void sdio_writeb(struct sdio_func *func, unsigned char b, unsigned int addr, int *err_ret); +extern void sdio_writew(struct sdio_func *func, unsigned short b, + unsigned int addr, int *err_ret); +extern void sdio_writel(struct sdio_func *func, unsigned long b, + unsigned int addr, int *err_ret); + +extern int sdio_memcpy_toio(struct sdio_func *func, unsigned int addr, + void *src, int count); +extern int sdio_writesb(struct sdio_func *func, unsigned int addr, + void *src, int count); #endif -- cgit v1.2.3-70-g09d2 From 17b759aff916b4d02721e75ce5ed82b1903e5bd6 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Tue, 24 Jul 2007 02:09:39 -0400 Subject: sdio: add interface for host side SDIO interrupt reporting Signed-off-by: Nicolas Pitre Signed-off-by: Pierre Ossman --- drivers/mmc/core/host.c | 3 +++ drivers/mmc/core/sdio_irq.c | 8 +++++++- include/linux/mmc/host.h | 8 ++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 2c7ce8f43a9..37b761891d6 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -100,6 +100,9 @@ int mmc_add_host(struct mmc_host *host) { int err; + WARN_ON((host->caps & MMC_CAP_SDIO_IRQ) && + !host->ops->enable_sdio_irq); + if (!idr_pre_get(&mmc_host_idr, GFP_KERNEL)) return -ENOMEM; diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c index 01922d29241..01daee934d1 100644 --- a/drivers/mmc/core/sdio_irq.c +++ b/drivers/mmc/core/sdio_irq.c @@ -70,7 +70,8 @@ static int sdio_irq_thread(void *_host) * asynchronous notification of pending SDIO card interrupts * hence we poll for them in that case. */ - period = msecs_to_jiffies(10); + period = (host->caps & MMC_CAP_SDIO_IRQ) ? + MAX_SCHEDULE_TIMEOUT : msecs_to_jiffies(10); pr_debug("%s: IRQ thread started (poll period = %lu jiffies)\n", mmc_hostname(host), period); @@ -104,11 +105,16 @@ static int sdio_irq_thread(void *_host) ssleep(1); set_task_state(current, TASK_INTERRUPTIBLE); + if (host->caps & MMC_CAP_SDIO_IRQ) + host->ops->enable_sdio_irq(host, 1); if (!kthread_should_stop()) schedule_timeout(period); set_task_state(current, TASK_RUNNING); } while (!kthread_should_stop()); + if (host->caps & MMC_CAP_SDIO_IRQ) + host->ops->enable_sdio_irq(host, 0); + pr_debug("%s: IRQ thread exiting with code %d\n", mmc_hostname(host), ret); diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 00dc1809494..3fd197962f7 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -51,6 +51,7 @@ struct mmc_host_ops { void (*request)(struct mmc_host *host, struct mmc_request *req); void (*set_ios)(struct mmc_host *host, struct mmc_ios *ios); int (*get_ro)(struct mmc_host *host); + void (*enable_sdio_irq)(struct mmc_host *host, int enable); }; struct mmc_card; @@ -89,6 +90,7 @@ struct mmc_host { #define MMC_CAP_MULTIWRITE (1 << 1) /* Can accurately report bytes sent to card on error */ #define MMC_CAP_MMC_HIGHSPEED (1 << 2) /* Can do MMC high-speed timing */ #define MMC_CAP_SD_HIGHSPEED (1 << 3) /* Can do SD high-speed timing */ +#define MMC_CAP_SDIO_IRQ (1 << 4) /* Can signal pending SDIO IRQs */ /* host specific block data */ unsigned int max_seg_size; /* see blk_queue_max_segment_size */ @@ -150,5 +152,11 @@ extern int mmc_resume_host(struct mmc_host *); extern void mmc_detect_change(struct mmc_host *, unsigned long delay); extern void mmc_request_done(struct mmc_host *, struct mmc_request *); +static inline void mmc_signal_sdio_irq(struct mmc_host *host) +{ + host->ops->enable_sdio_irq(host, 0); + wake_up_process(host->sdio_irq_thread); +} + #endif -- cgit v1.2.3-70-g09d2 From 22bfc979d38f57d5b10d141990175d8fc47f6775 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sun, 29 Jul 2007 16:58:09 +0200 Subject: make struct sdio_dev_attrs[] static On Wed, Jul 25, 2007 at 04:03:04AM -0700, Andrew Morton wrote: >... > Changes since 2.6.22-rc6-mm1: >... > git-mmc.patch >... > git trees >... sdio_dev_attrs[] can become static. Signed-off-by: Adrian Bunk Signed-off-by: Pierre Ossman --- drivers/mmc/core/sdio_bus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 24072445491..d229020db4a 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -46,7 +46,7 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, func->class, func->vendor, func->device); } -struct device_attribute sdio_dev_attrs[] = { +static struct device_attribute sdio_dev_attrs[] = { __ATTR_RO(class), __ATTR_RO(vendor), __ATTR_RO(device), -- cgit v1.2.3-70-g09d2 From 6db5020e7386ddf17378f91eb8c445433e5b07cd Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 30 Jul 2007 17:15:07 +0200 Subject: sdio: change clock speed Change clock speed to the highest supported by the card. Signed-off-by: Pierre Ossman --- drivers/mmc/core/sdio.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 1fb36a34046..62df8e17758 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -293,6 +293,12 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr) if (err) goto remove; + /* + * No support for high-speed yet, so just set + * the card's maximum speed. + */ + mmc_set_clock(host, card->cis.max_dtr); + /* * Initialize (but don't add) all present functions. */ -- cgit v1.2.3-70-g09d2 From 4ff6471c028a9885e8f09a000d87694f81190ab9 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 30 Jul 2007 18:23:53 +0200 Subject: sdio: enable wide bus mode Enable 4-bit data bus mode, according to host and card capabilities. Signed-off-by: Pierre Ossman --- drivers/mmc/core/sdio.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 62df8e17758..48c465a8e34 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -138,6 +138,32 @@ out: return ret; } +static int sdio_enable_wide(struct mmc_card *card) +{ + int ret; + u8 ctrl; + + if (!(card->host->caps & MMC_CAP_4_BIT_DATA)) + return 0; + + if (card->cccr.low_speed && !card->cccr.wide_bus) + return 0; + + ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_IF, 0, &ctrl); + if (ret) + return ret; + + ctrl |= SDIO_BUS_WIDTH_4BIT; + + ret = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_IF, ctrl, NULL); + if (ret) + return ret; + + mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4); + + return 0; +} + /* * Host is being removed. Free up the current card. */ @@ -299,6 +325,13 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr) */ mmc_set_clock(host, card->cis.max_dtr); + /* + * Switch to wider bus (if supported). + */ + err = sdio_enable_wide(card); + if (err) + goto remove; + /* * Initialize (but don't add) all present functions. */ -- cgit v1.2.3-70-g09d2 From ce252edd869ba1fee6a9a6f83e20f349d4c4d669 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 7 Aug 2007 14:06:18 +0200 Subject: mmc: fix incorrect divisor in debug output Signed-off-by: Pierre Ossman --- drivers/mmc/core/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index d1e4b0849e3..07c03cb677b 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -121,7 +121,7 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) "tsac %d ms nsac %d\n", mmc_hostname(host), mrq->data->blksz, mrq->data->blocks, mrq->data->flags, - mrq->data->timeout_ns / 10000000, + mrq->data->timeout_ns / 1000000, mrq->data->timeout_clks); } -- cgit v1.2.3-70-g09d2 From e6f918bf39773d712ab5b457bff54ade3bda0cb1 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 7 Aug 2007 14:11:55 +0200 Subject: mmc: fix sdio timeout calculation SDIO doesn't have a CSD so it uses different timeout values than SD memory. Signed-off-by: Pierre Ossman --- drivers/mmc/core/core.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 07c03cb677b..9d29bed820a 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -231,6 +231,15 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card) { unsigned int mult; + /* + * SDIO cards only define an upper 1 s limit on access. + */ + if (mmc_card_sdio(card)) { + data->timeout_ns = 1000000000; + data->timeout_clks = 0; + return; + } + /* * SD cards use a 100 multiplier rather than 10 */ -- cgit v1.2.3-70-g09d2 From 7616ee95f27a04fd5a6434e9ef4a82cec4b2807c Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Wed, 8 Aug 2007 14:23:05 +0100 Subject: sdio: add SDIO_FBR_BASE(f) macro Signed-off-by: David Vrabel Signed-off-by: Pierre Ossman --- drivers/mmc/core/sdio.c | 4 ++-- drivers/mmc/core/sdio_cis.c | 2 +- include/linux/mmc/sdio.h | 2 ++ 3 files changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 48c465a8e34..58cf36e4467 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -30,7 +30,7 @@ static int sdio_read_fbr(struct sdio_func *func) unsigned char data; ret = mmc_io_rw_direct(func->card, 0, 0, - func->num * 0x100 + SDIO_FBR_STD_IF, 0, &data); + SDIO_FBR_BASE(func->num) + SDIO_FBR_STD_IF, 0, &data); if (ret) goto out; @@ -38,7 +38,7 @@ static int sdio_read_fbr(struct sdio_func *func) if (data == 0x0f) { ret = mmc_io_rw_direct(func->card, 0, 0, - func->num * 0x100 + SDIO_FBR_STD_IF_EXT, 0, &data); + SDIO_FBR_BASE(func->num) + SDIO_FBR_STD_IF_EXT, 0, &data); if (ret) goto out; } diff --git a/drivers/mmc/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c index ec806a1229b..d050c40cf04 100644 --- a/drivers/mmc/core/sdio_cis.c +++ b/drivers/mmc/core/sdio_cis.c @@ -145,7 +145,7 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func) fn = 0; ret = mmc_io_rw_direct(card, 0, 0, - fn * 0x100 + SDIO_FBR_CIS + i, 0, &x); + SDIO_FBR_BASE(fn) + SDIO_FBR_CIS + i, 0, &x); if (ret) return ret; ptr |= x << (i * 8); diff --git a/include/linux/mmc/sdio.h b/include/linux/mmc/sdio.h index 9b1ec76cac3..47ba464f517 100644 --- a/include/linux/mmc/sdio.h +++ b/include/linux/mmc/sdio.h @@ -132,6 +132,8 @@ * Function Basic Registers (FBR) */ +#define SDIO_FBR_BASE(f) ((f) * 0x100) /* base of function f's FBRs */ + #define SDIO_FBR_STD_IF 0x00 #define SDIO_FBR_SUPPORTS_CSA 0x40 /* supports Code Storage Area */ -- cgit v1.2.3-70-g09d2 From 9a08f82b3cc522f727ace580a2aaee5402435bc8 Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Wed, 8 Aug 2007 14:23:48 +0100 Subject: sdio: set the functions' block size Before a driver is probed, set the function's block size to the default so the driver is sure the block size is something sensible and it needn't explicitly set it. The default block size is the largest that's supported by both the card and the host, with a maximum of 512 to ensure aribitrarily sized transfer use the optimal (least) number of commands. See http://lkml.org/lkml/2007/8/7/150 for reasons for the block size choice. Signed-off-by: David Vrabel Signed-off-by: Pierre Ossman --- drivers/mmc/core/sdio_bus.c | 9 ++++++++ drivers/mmc/core/sdio_cis.c | 2 +- drivers/mmc/core/sdio_io.c | 49 +++++++++++++++++++++++++++++++++++++++++++ include/linux/mmc/sdio_func.h | 5 ++++- 4 files changed, 63 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index d229020db4a..fcb13fb0daa 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -128,11 +128,20 @@ static int sdio_bus_probe(struct device *dev) struct sdio_driver *drv = to_sdio_driver(dev->driver); struct sdio_func *func = dev_to_sdio_func(dev); const struct sdio_device_id *id; + int ret; id = sdio_match_device(func, drv); if (!id) return -ENODEV; + /* Set the default block size so the driver is sure it's something + * sensible. */ + sdio_claim_host(func); + ret = sdio_set_block_size(func, 0); + sdio_release_host(func); + if (ret) + return ret; + return drv->probe(func, id); } diff --git a/drivers/mmc/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c index d050c40cf04..1d03f12bbb3 100644 --- a/drivers/mmc/core/sdio_cis.c +++ b/drivers/mmc/core/sdio_cis.c @@ -79,7 +79,7 @@ static int cistpl_funce_func(struct sdio_func *func, return -EINVAL; /* TPLFE_MAX_BLK_SIZE */ - func->blksize = buf[12] | (buf[13] << 8); + func->max_blksize = buf[12] | (buf[13] << 8); return 0; } diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c index ecdb77242e9..c2bad1195e3 100644 --- a/drivers/mmc/core/sdio_io.c +++ b/drivers/mmc/core/sdio_io.c @@ -140,6 +140,55 @@ err: } EXPORT_SYMBOL_GPL(sdio_disable_func); +/** + * sdio_set_block_size - set the block size of an SDIO function + * @func: SDIO function to change + * @blksz: new block size or 0 to use the default. + * + * The default block size is the largest supported by both the function + * and the host, with a maximum of 512 to ensure that arbitrarily sized + * data transfer use the optimal (least) number of commands. + * + * A driver may call this to override the default block size set by the + * core. This can be used to set a block size greater than the maximum + * that reported by the card; it is the driver's responsibility to ensure + * it uses a value that the card supports. + * + * Returns 0 on success, -EINVAL if the host does not support the + * requested block size, or -EIO (etc.) if one of the resultant FBR block + * size register writes failed. + * + */ +int sdio_set_block_size(struct sdio_func *func, unsigned blksz) +{ + int ret; + + if (blksz > func->card->host->max_blk_size) + return -EINVAL; + + if (blksz == 0) { + blksz = min(min( + func->max_blksize, + func->card->host->max_blk_size), + 512u); + } + + ret = mmc_io_rw_direct(func->card, 1, 0, + SDIO_FBR_BASE(func->num) + SDIO_FBR_BLKSIZE, + blksz & 0xff, NULL); + if (ret) + return ret; + ret = mmc_io_rw_direct(func->card, 1, 0, + SDIO_FBR_BASE(func->num) + SDIO_FBR_BLKSIZE + 1, + (blksz >> 8) & 0xff, NULL); + if (ret) + return ret; + func->cur_blksize = blksz; + return 0; +} + +EXPORT_SYMBOL_GPL(sdio_set_block_size); + /** * sdio_readb - read a single byte from a SDIO function * @func: SDIO function to access diff --git a/include/linux/mmc/sdio_func.h b/include/linux/mmc/sdio_func.h index af813fffc4a..f05757984e8 100644 --- a/include/linux/mmc/sdio_func.h +++ b/include/linux/mmc/sdio_func.h @@ -43,7 +43,8 @@ struct sdio_func { unsigned short vendor; /* vendor id */ unsigned short device; /* device id */ - unsigned short blksize; /* maximum block size */ + unsigned max_blksize; /* maximum block size */ + unsigned cur_blksize; /* current block size */ unsigned int state; /* function state */ #define SDIO_STATE_PRESENT (1<<0) /* present in sysfs */ @@ -111,6 +112,8 @@ extern void sdio_release_host(struct sdio_func *func); extern int sdio_enable_func(struct sdio_func *func); extern int sdio_disable_func(struct sdio_func *func); +extern int sdio_set_block_size(struct sdio_func *func, unsigned blksz); + extern int sdio_claim_irq(struct sdio_func *func, sdio_irq_handler_t *handler); extern int sdio_release_irq(struct sdio_func *func); -- cgit v1.2.3-70-g09d2 From eb6594689226663968ef0a9fd71ec5e1e4e04f9c Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Wed, 8 Aug 2007 14:24:21 +0100 Subject: sdio: extend sdio_readsb() and friends to handle any length of buffer Extend sdio_readsb(), sdio_writesb(), sdio_memcpy_fromio(), and sdio_memcpy_toio() to handle any length of buffer by splitting the transfer into several IO_RW_EXTENDED commands. Typically, a transfer would be split into a single block mode transfer followed by a byte mode transfer for the remainder but we also handle lack of block mode support and the block size being greater than 512 (the maximum byte mode transfer size). host->max_seg_size <= host->max_req_size so there's no need to check both when determining the maximum data size for a single command. Signed-off-by: David Vrabel Signed-off-by: Pierre Ossman --- drivers/mmc/core/sdio_io.c | 93 +++++++++++++++++++++++++++++++++++---------- drivers/mmc/core/sdio_ops.c | 19 +++++---- drivers/mmc/core/sdio_ops.h | 2 +- 3 files changed, 86 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c index c2bad1195e3..34b085d4024 100644 --- a/drivers/mmc/core/sdio_io.c +++ b/drivers/mmc/core/sdio_io.c @@ -189,6 +189,67 @@ int sdio_set_block_size(struct sdio_func *func, unsigned blksz) EXPORT_SYMBOL_GPL(sdio_set_block_size); +/* Split an arbitrarily sized data transfer into several + * IO_RW_EXTENDED commands. */ +static int sdio_io_rw_ext_helper(struct sdio_func *func, int write, + unsigned addr, int incr_addr, u8 *buf, unsigned size) +{ + unsigned remainder = size; + unsigned max_blocks; + int ret; + + /* Do the bulk of the transfer using block mode (if supported). */ + if (func->card->cccr.multi_block) { + /* Blocks per command is limited by host count, host transfer + * size (we only use a single sg entry) and the maximum for + * IO_RW_EXTENDED of 511 blocks. */ + max_blocks = min(min( + func->card->host->max_blk_count, + func->card->host->max_seg_size / func->cur_blksize), + 511u); + + while (remainder > func->cur_blksize) { + unsigned blocks; + + blocks = remainder / func->cur_blksize; + if (blocks > max_blocks) + blocks = max_blocks; + size = blocks * func->cur_blksize; + + ret = mmc_io_rw_extended(func->card, write, + func->num, addr, incr_addr, buf, + blocks, func->cur_blksize); + if (ret) + return ret; + + remainder -= size; + buf += size; + if (incr_addr) + addr += size; + } + } + + /* Write the remainder using byte mode. */ + while (remainder > 0) { + size = remainder; + if (size > func->cur_blksize) + size = func->cur_blksize; + if (size > 512) + size = 512; /* maximum size for byte mode */ + + ret = mmc_io_rw_extended(func->card, write, func->num, addr, + incr_addr, buf, 1, size); + if (ret) + return ret; + + remainder -= size; + buf += size; + if (incr_addr) + addr += size; + } + return 0; +} + /** * sdio_readb - read a single byte from a SDIO function * @func: SDIO function to access @@ -252,15 +313,13 @@ EXPORT_SYMBOL_GPL(sdio_writeb); * @addr: address to begin reading from * @count: number of bytes to read * - * Reads up to 512 bytes from the address space of a given SDIO - * function. Return value indicates if the transfer succeeded or - * not. + * Reads from the address space of a given SDIO function. Return + * value indicates if the transfer succeeded or not. */ int sdio_memcpy_fromio(struct sdio_func *func, void *dst, unsigned int addr, int count) { - return mmc_io_rw_extended(func->card, 0, func->num, addr, 0, dst, - count); + return sdio_io_rw_ext_helper(func, 0, addr, 1, dst, count); } EXPORT_SYMBOL_GPL(sdio_memcpy_fromio); @@ -271,15 +330,13 @@ EXPORT_SYMBOL_GPL(sdio_memcpy_fromio); * @src: buffer that contains the data to write * @count: number of bytes to write * - * Writes up to 512 bytes to the address space of a given SDIO - * function. Return value indicates if the transfer succeeded or - * not. + * Writes to the address space of a given SDIO function. Return + * value indicates if the transfer succeeded or not. */ int sdio_memcpy_toio(struct sdio_func *func, unsigned int addr, void *src, int count) { - return mmc_io_rw_extended(func->card, 1, func->num, addr, 0, src, - count); + return sdio_io_rw_ext_helper(func, 1, addr, 1, src, count); } EXPORT_SYMBOL_GPL(sdio_memcpy_toio); @@ -290,15 +347,13 @@ EXPORT_SYMBOL_GPL(sdio_memcpy_toio); * @addr: address of (single byte) FIFO * @count: number of bytes to read * - * Reads up to 512 bytes from the specified FIFO of a given SDIO - * function. Return value indicates if the transfer succeeded or - * not. + * Reads from the specified FIFO of a given SDIO function. Return + * value indicates if the transfer succeeded or not. */ int sdio_readsb(struct sdio_func *func, void *dst, unsigned int addr, int count) { - return mmc_io_rw_extended(func->card, 0, func->num, addr, 1, dst, - count); + return sdio_io_rw_ext_helper(func, 0, addr, 0, dst, count); } EXPORT_SYMBOL_GPL(sdio_readsb); @@ -310,15 +365,13 @@ EXPORT_SYMBOL_GPL(sdio_readsb); * @src: buffer that contains the data to write * @count: number of bytes to write * - * Writes up to 512 bytes to the specified FIFO of a given SDIO - * function. Return value indicates if the transfer succeeded or - * not. + * Writes to the specified FIFO of a given SDIO function. Return + * value indicates if the transfer succeeded or not. */ int sdio_writesb(struct sdio_func *func, unsigned int addr, void *src, int count) { - return mmc_io_rw_extended(func->card, 1, func->num, addr, 1, src, - count); + return sdio_io_rw_ext_helper(func, 1, addr, 0, src, count); } EXPORT_SYMBOL_GPL(sdio_writesb); diff --git a/drivers/mmc/core/sdio_ops.c b/drivers/mmc/core/sdio_ops.c index 4f2c7713947..98e20532452 100644 --- a/drivers/mmc/core/sdio_ops.c +++ b/drivers/mmc/core/sdio_ops.c @@ -88,7 +88,7 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, } int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, - unsigned addr, int bang, u8 *buf, unsigned size) + unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz) { struct mmc_request mrq; struct mmc_command cmd; @@ -97,7 +97,9 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, BUG_ON(!card); BUG_ON(fn > 7); - BUG_ON(size > 512); + BUG_ON(blocks == 1 && blksz > 512); + WARN_ON(blocks == 0); + WARN_ON(blksz == 0); memset(&mrq, 0, sizeof(struct mmc_request)); memset(&cmd, 0, sizeof(struct mmc_command)); @@ -109,18 +111,21 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, cmd.opcode = SD_IO_RW_EXTENDED; cmd.arg = write ? 0x80000000 : 0x00000000; cmd.arg |= fn << 28; - cmd.arg |= bang ? 0x00000000 : 0x04000000; + cmd.arg |= incr_addr ? 0x04000000 : 0x00000000; cmd.arg |= addr << 9; - cmd.arg |= (size == 512) ? 0 : size; + if (blocks == 1 && blksz <= 512) + cmd.arg |= (blksz == 512) ? 0 : blksz; /* byte mode */ + else + cmd.arg |= 0x08000000 | blocks; /* block mode */ cmd.flags = MMC_RSP_R5 | MMC_CMD_ADTC; - data.blksz = size; - data.blocks = 1; + data.blksz = blksz; + data.blocks = blocks; data.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ; data.sg = &sg; data.sg_len = 1; - sg_init_one(&sg, buf, size); + sg_init_one(&sg, buf, blksz * blocks); mmc_set_data_timeout(&data, card); diff --git a/drivers/mmc/core/sdio_ops.h b/drivers/mmc/core/sdio_ops.h index 1d42e4f366a..e2e74b0d17d 100644 --- a/drivers/mmc/core/sdio_ops.h +++ b/drivers/mmc/core/sdio_ops.h @@ -16,7 +16,7 @@ int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr); int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, unsigned addr, u8 in, u8* out); int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, - unsigned addr, int bang, u8 *data, unsigned size); + unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz); #endif -- cgit v1.2.3-70-g09d2 From 9f2fcf99394b34769e3243a7f42a0ba8d21fc774 Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Wed, 1 Aug 2007 00:05:24 +0200 Subject: sdio: kmalloc + memset conversion to kzalloc Signed-off-by: Mariusz Kozlowski Signed-off-by: Pierre Ossman --- drivers/mmc/core/sdio_bus.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index fcb13fb0daa..683d9174010 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -221,12 +221,10 @@ struct sdio_func *sdio_alloc_func(struct mmc_card *card) { struct sdio_func *func; - func = kmalloc(sizeof(struct sdio_func), GFP_KERNEL); + func = kzalloc(sizeof(struct sdio_func), GFP_KERNEL); if (!func) return ERR_PTR(-ENOMEM); - memset(func, 0, sizeof(struct sdio_func)); - func->card = card; device_initialize(&func->dev); -- cgit v1.2.3-70-g09d2 From d84075c8aed771d47d7ac6e96b098559da361c25 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 9 Aug 2007 13:23:56 +0200 Subject: mmc: replace BUG_ON with WARN_ON Replace all cases of BUG_ON with WARN_ON where there is a chance (with varying degrees of slim) that the kernel can continue without incidence. Signed-off-by: Pierre Ossman --- drivers/mmc/core/core.c | 12 ++++++------ drivers/mmc/core/mmc.c | 4 ++-- drivers/mmc/core/sd.c | 6 ++---- drivers/mmc/core/sdio.c | 2 +- drivers/mmc/core/sdio_irq.c | 4 ++-- 5 files changed, 13 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 9d29bed820a..3bebd3b55dc 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -202,7 +202,7 @@ int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries { struct mmc_request mrq; - BUG_ON(!host->claimed); + WARN_ON(!host->claimed); memset(&mrq, 0, sizeof(struct mmc_request)); @@ -333,7 +333,7 @@ void mmc_release_host(struct mmc_host *host) { unsigned long flags; - BUG_ON(!host->claimed); + WARN_ON(!host->claimed); spin_lock_irqsave(&host->lock, flags); host->claimed = 0; @@ -531,7 +531,7 @@ void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops) BUG_ON(!host); BUG_ON(!ops); - BUG_ON(!host->claimed); + WARN_ON(!host->claimed); spin_lock_irqsave(&host->lock, flags); @@ -555,8 +555,8 @@ void mmc_detach_bus(struct mmc_host *host) BUG_ON(!host); - BUG_ON(!host->claimed); - BUG_ON(!host->bus_ops); + WARN_ON(!host->claimed); + WARN_ON(!host->bus_ops); spin_lock_irqsave(&host->lock, flags); @@ -584,7 +584,7 @@ void mmc_detect_change(struct mmc_host *host, unsigned long delay) #ifdef CONFIG_MMC_DEBUG unsigned long flags; spin_lock_irqsave(&host->lock, flags); - BUG_ON(host->removed); + WARN_ON(host->removed); spin_unlock_irqrestore(&host->lock, flags); #endif diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index ba7a847cfd0..6ba458951d2 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -264,7 +264,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, unsigned int max_dtr; BUG_ON(!host); - BUG_ON(!host->claimed); + WARN_ON(!host->claimed); /* * Since we're changing the OCR value, we seem to @@ -558,7 +558,7 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr) int err; BUG_ON(!host); - BUG_ON(!host->claimed); + WARN_ON(!host->claimed); mmc_attach_bus(host, &mmc_ops); diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 0a04a6e86ca..c86588fdaae 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -166,8 +166,6 @@ static int mmc_decode_scr(struct mmc_card *card) unsigned int scr_struct; u32 resp[4]; - BUG_ON(!mmc_card_sd(card)); - resp[3] = card->raw_scr[1]; resp[2] = card->raw_scr[0]; @@ -300,7 +298,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, unsigned int max_dtr; BUG_ON(!host); - BUG_ON(!host->claimed); + WARN_ON(!host->claimed); /* * Since we're changing the OCR value, we seem to @@ -620,7 +618,7 @@ int mmc_attach_sd(struct mmc_host *host, u32 ocr) int err; BUG_ON(!host); - BUG_ON(!host->claimed); + WARN_ON(!host->claimed); mmc_attach_bus(host, &mmc_sd_ops); diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 58cf36e4467..2f3fb994c38 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -230,7 +230,7 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr) struct mmc_card *card; BUG_ON(!host); - BUG_ON(!host->claimed); + WARN_ON(!host->claimed); mmc_attach_bus(host, &mmc_sdio_ops); diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c index 01daee934d1..8843a4c2fe9 100644 --- a/drivers/mmc/core/sdio_irq.c +++ b/drivers/mmc/core/sdio_irq.c @@ -125,7 +125,7 @@ static int sdio_card_irq_get(struct mmc_card *card) { struct mmc_host *host = card->host; - BUG_ON(!host->claimed); + WARN_ON(!host->claimed); if (!host->sdio_irqs++) { atomic_set(&host->sdio_irq_thread_abort, 0); @@ -145,7 +145,7 @@ static int sdio_card_irq_put(struct mmc_card *card) { struct mmc_host *host = card->host; - BUG_ON(!host->claimed); + WARN_ON(!host->claimed); BUG_ON(host->sdio_irqs < 1); if (!--host->sdio_irqs) { -- cgit v1.2.3-70-g09d2 From 7806cdb40fd562e5dcc07321579b62a5dc7cd95c Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Fri, 10 Aug 2007 13:29:46 +0100 Subject: sdio: add sdio_f0_readb() and sdio_f0_writeb() Add sdio_f0_readb() and sdio_f0_writeb() functions to reading and writing function 0 registers. Writes outside the vendor specific CCCR registers (0xF0 - 0xFF) are not permitted. Signed-off-by: David Vrabel Signed-off-by: Pierre Ossman --- drivers/mmc/core/sdio_io.c | 64 +++++++++++++++++++++++++++++++++++++++++++ include/linux/mmc/sdio_func.h | 5 ++++ 2 files changed, 69 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c index 34b085d4024..625b92ce9ce 100644 --- a/drivers/mmc/core/sdio_io.c +++ b/drivers/mmc/core/sdio_io.c @@ -482,3 +482,67 @@ void sdio_writel(struct sdio_func *func, unsigned long b, unsigned int addr, } EXPORT_SYMBOL_GPL(sdio_writel); +/** + * sdio_f0_readb - read a single byte from SDIO function 0 + * @func: an SDIO function of the card + * @addr: address to read + * @err_ret: optional status value from transfer + * + * Reads a single byte from the address space of SDIO function 0. + * If there is a problem reading the address, 0xff is returned + * and @err_ret will contain the error code. + */ +unsigned char sdio_f0_readb(struct sdio_func *func, unsigned int addr, + int *err_ret) +{ + int ret; + unsigned char val; + + BUG_ON(!func); + + if (err_ret) + *err_ret = 0; + + ret = mmc_io_rw_direct(func->card, 0, 0, addr, 0, &val); + if (ret) { + if (err_ret) + *err_ret = ret; + return 0xFF; + } + + return val; +} +EXPORT_SYMBOL_GPL(sdio_f0_readb); + +/** + * sdio_f0_writeb - write a single byte to SDIO function 0 + * @func: an SDIO function of the card + * @b: byte to write + * @addr: address to write to + * @err_ret: optional status value from transfer + * + * Writes a single byte to the address space of SDIO function 0. + * @err_ret will contain the status of the actual transfer. + * + * Only writes to the vendor specific CCCR registers (0xF0 - + * 0xFF) are permiited; @err_ret will be set to -EINVAL for * + * writes outside this range. + */ +void sdio_f0_writeb(struct sdio_func *func, unsigned char b, unsigned int addr, + int *err_ret) +{ + int ret; + + BUG_ON(!func); + + if (addr < 0xF0 || addr > 0xFF) { + if (err_ret) + *err_ret = -EINVAL; + return; + } + + ret = mmc_io_rw_direct(func->card, 1, 0, addr, b, NULL); + if (err_ret) + *err_ret = ret; +} +EXPORT_SYMBOL_GPL(sdio_f0_writeb); diff --git a/include/linux/mmc/sdio_func.h b/include/linux/mmc/sdio_func.h index f05757984e8..da6a96c3977 100644 --- a/include/linux/mmc/sdio_func.h +++ b/include/linux/mmc/sdio_func.h @@ -141,5 +141,10 @@ extern int sdio_memcpy_toio(struct sdio_func *func, unsigned int addr, extern int sdio_writesb(struct sdio_func *func, unsigned int addr, void *src, int count); +extern unsigned char sdio_f0_readb(struct sdio_func *func, + unsigned int addr, int *err_ret); +extern void sdio_f0_writeb(struct sdio_func *func, unsigned char b, + unsigned int addr, int *err_ret); + #endif -- cgit v1.2.3-70-g09d2 From 2ba30eedec37e2f65babf4ea54233f98afbe0871 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Wed, 15 Aug 2007 13:27:29 -0400 Subject: sdio: add default c_ispeed/c_ospeed values to sdio_uart driver Note that the default baudrate is 4800 instead of 9600 as a convenience because that's what GPS devices want which is still the main use for this driver. Signed-off-by: Nicolas Pitre Signed-off-by: Pierre Ossman --- drivers/mmc/card/sdio_uart.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c index 190120d1449..606100212af 100644 --- a/drivers/mmc/card/sdio_uart.c +++ b/drivers/mmc/card/sdio_uart.c @@ -1106,6 +1106,8 @@ static int __init sdio_uart_init(void) tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; tty_drv->init_termios = tty_std_termios; tty_drv->init_termios.c_cflag = B4800 | CS8 | CREAD | HUPCL | CLOCAL; + tty_drv->init_termios.c_ispeed = 4800; + tty_drv->init_termios.c_ospeed = 4800; tty_set_operations(tty_drv, &sdio_uart_ops); ret = tty_register_driver(tty_drv); -- cgit v1.2.3-70-g09d2 From 15b82b46de358a574c2a6a6dea4c8076bef7ac43 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Mon, 20 Aug 2007 17:17:37 -0400 Subject: sdio: fix recursion issues between sdio-uart driver and tty layer In a few places, sdio_uart_irq() is called directly instead of waiting for the actual interrupt to be raised and the SDIO IRQ thread scheduled in order to reduce latency. However, some interaction with the tty core may end up calling us back (serial echo, flow control, etc.) creating two issues: - the host lock gets claimed twice from the same thread causing a deadlock; - the same direct calls to sdio_uart_irq() may be performed causing unexpected reentrancy into the IRQ handler. This patch handles both of those issues. Signed-off-by: Nicolas Pitre Signed-off-by: Pierre Ossman --- drivers/mmc/card/sdio_uart.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c index 606100212af..d552de68311 100644 --- a/drivers/mmc/card/sdio_uart.c +++ b/drivers/mmc/card/sdio_uart.c @@ -79,6 +79,7 @@ struct sdio_uart_port { struct mutex open_lock; struct sdio_func *func; struct mutex func_lock; + struct task_struct *in_sdio_uart_irq; unsigned int regs_offset; struct circ_buf xmit; spinlock_t write_lock; @@ -186,14 +187,16 @@ static int sdio_uart_claim_func(struct sdio_uart_port *port) mutex_unlock(&port->func_lock); return -ENODEV; } - sdio_claim_host(port->func); + if (likely(port->in_sdio_uart_irq != current)) + sdio_claim_host(port->func); mutex_unlock(&port->func_lock); return 0; } static inline void sdio_uart_release_func(struct sdio_uart_port *port) { - sdio_release_host(port->func); + if (likely(port->in_sdio_uart_irq != current)) + sdio_release_host(port->func); } static inline unsigned int sdio_in(struct sdio_uart_port *port, int offset) @@ -511,15 +514,29 @@ static void sdio_uart_irq(struct sdio_func *func) struct sdio_uart_port *port = sdio_get_drvdata(func); unsigned int iir, lsr; + /* + * In a few places sdio_uart_irq() is called directly instead of + * waiting for the actual interrupt to be raised and the SDIO IRQ + * thread scheduled in order to reduce latency. However, some + * interaction with the tty core may end up calling us back + * (serial echo, flow control, etc.) through those same places + * causing undesirable effects. Let's stop the recursion here. + */ + if (unlikely(port->in_sdio_uart_irq == current)) + return; + iir = sdio_in(port, UART_IIR); if (iir & UART_IIR_NO_INT) return; + + port->in_sdio_uart_irq = current; lsr = sdio_in(port, UART_LSR); if (lsr & UART_LSR_DR) sdio_uart_receive_chars(port, &lsr); sdio_uart_check_modem_status(port); if (lsr & UART_LSR_THRE) sdio_uart_transmit_chars(port); + port->in_sdio_uart_irq = NULL; } static int sdio_uart_startup(struct sdio_uart_port *port) -- cgit v1.2.3-70-g09d2 From f75979b77fb20b01522d8fab96dfc76cc9f42420 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 4 Sep 2007 07:59:18 +0200 Subject: sdhci: sdio interrupt support Add support for relaying the sdio interrupt signal from the card. Signed-off-by: Pierre Ossman --- drivers/mmc/host/sdhci.c | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index c63edc5c17e..228ce42371d 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -800,10 +800,35 @@ static int sdhci_get_ro(struct mmc_host *mmc) return !(present & SDHCI_WRITE_PROTECT); } +static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable) +{ + struct sdhci_host *host; + unsigned long flags; + u32 ier; + + host = mmc_priv(mmc); + + spin_lock_irqsave(&host->lock, flags); + + ier = readl(host->ioaddr + SDHCI_INT_ENABLE); + + ier &= ~SDHCI_INT_CARD_INT; + if (enable) + ier |= SDHCI_INT_CARD_INT; + + writel(ier, host->ioaddr + SDHCI_INT_ENABLE); + writel(ier, host->ioaddr + SDHCI_SIGNAL_ENABLE); + + mmiowb(); + + spin_unlock_irqrestore(&host->lock, flags); +} + static const struct mmc_host_ops sdhci_ops = { .request = sdhci_request, .set_ios = sdhci_set_ios, .get_ro = sdhci_get_ro, + .enable_sdio_irq = sdhci_enable_sdio_irq, }; /*****************************************************************************\ @@ -1012,6 +1037,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) irqreturn_t result; struct sdhci_host* host = dev_id; u32 intmask; + int cardint = 0; spin_lock(&host->lock); @@ -1056,6 +1082,11 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) intmask &= ~SDHCI_INT_BUS_POWER; + if (intmask & SDHCI_INT_CARD_INT) + cardint = 1; + + intmask &= ~SDHCI_INT_CARD_INT; + if (intmask) { printk(KERN_ERR "%s: Unexpected interrupt 0x%08x.\n", mmc_hostname(host->mmc), intmask); @@ -1070,6 +1101,12 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) out: spin_unlock(&host->lock); + /* + * We have to delay this as it calls back into the driver. + */ + if (cardint) + mmc_signal_sdio_irq(host->mmc); + return result; } @@ -1309,7 +1346,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) mmc->ops = &sdhci_ops; mmc->f_min = host->max_clk / 256; mmc->f_max = host->max_clk; - mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE; + mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE | MMC_CAP_SDIO_IRQ; if (caps & SDHCI_CAN_DO_HISPD) mmc->caps |= MMC_CAP_SD_HIGHSPEED; -- cgit v1.2.3-70-g09d2 From f9996aee36921e8f1d499de1b2ea380855cf6d97 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 19 Sep 2007 18:38:50 +0200 Subject: mmc: increase power up delay Increase delay for power up in order to support some slower boards. Also add some comments about why the delays are there. Signed-off-by: Pierre Ossman --- drivers/mmc/core/core.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 3bebd3b55dc..bffcaf8df35 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -460,12 +460,20 @@ static void mmc_power_up(struct mmc_host *host) host->ios.timing = MMC_TIMING_LEGACY; mmc_set_ios(host); - mmc_delay(1); + /* + * This delay should be sufficient to allow the power supply + * to reach the minimum voltage. + */ + mmc_delay(2); host->ios.clock = host->f_min; host->ios.power_mode = MMC_POWER_ON; mmc_set_ios(host); + /* + * This delay must be at least 74 clock sizes, or 1 ms, or the + * time required to reach a stable voltage. + */ mmc_delay(2); } -- cgit v1.2.3-70-g09d2 From 759bdc7af450404382e937c76722ae8736daef92 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 19 Sep 2007 18:42:16 +0200 Subject: sdio: store vendor strings Store vendor strings found in CISTPL_VERS_1 so that function drivers can access them. Signed-off-by: Pierre Ossman --- drivers/mmc/core/bus.c | 3 +++ drivers/mmc/core/sdio_bus.c | 3 +++ drivers/mmc/core/sdio_cis.c | 50 ++++++++++++++++++++++++++++++++++++++++++- include/linux/mmc/card.h | 2 ++ include/linux/mmc/sdio_func.h | 3 +++ 5 files changed, 60 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 1cc11714916..733ac95331c 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -187,6 +187,9 @@ static void mmc_release_card(struct device *dev) sdio_free_common_cis(card); + if (card->info) + kfree(card->info); + kfree(card); } diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 683d9174010..0713a8c71e5 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -211,6 +211,9 @@ static void sdio_release_func(struct device *dev) sdio_free_func_cis(func); + if (func->info) + kfree(func->info); + kfree(func); } diff --git a/drivers/mmc/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c index 1d03f12bbb3..d5e51b1c7b3 100644 --- a/drivers/mmc/core/sdio_cis.c +++ b/drivers/mmc/core/sdio_cis.c @@ -23,6 +23,54 @@ #include "sdio_cis.h" #include "sdio_ops.h" +static int cistpl_vers_1(struct mmc_card *card, struct sdio_func *func, + const unsigned char *buf, unsigned size) +{ + unsigned i, nr_strings; + char **buffer, *string; + + buf += 2; + size -= 2; + + nr_strings = 0; + for (i = 0; i < size; i++) { + if (buf[i] == 0xff) + break; + if (buf[i] == 0) + nr_strings++; + } + + if (buf[i-1] != '\0') { + printk(KERN_WARNING "SDIO: ignoring broken CISTPL_VERS_1\n"); + return 0; + } + + size = i; + + buffer = kzalloc(sizeof(char*) * nr_strings + size, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + string = (char*)(buffer + nr_strings); + + for (i = 0; i < nr_strings; i++) { + buffer[i] = string; + strcpy(string, buf); + string += strlen(string) + 1; + buf += strlen(buf) + 1; + } + + if (func) { + func->num_info = nr_strings; + func->info = (const char**)buffer; + } else { + card->num_info = nr_strings; + card->info = (const char**)buffer; + } + + return 0; +} + static int cistpl_manfid(struct mmc_card *card, struct sdio_func *func, const unsigned char *buf, unsigned size) { @@ -119,7 +167,7 @@ struct cis_tpl { }; static const struct cis_tpl cis_tpl_list[] = { - { 0x15, 3, /* cistpl_vers_1 */ }, + { 0x15, 3, cistpl_vers_1 }, { 0x20, 4, cistpl_manfid }, { 0x21, 2, /* cistpl_funcid */ }, { 0x22, 0, cistpl_funce }, diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index a444431e28b..0d508ac17d6 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -108,6 +108,8 @@ struct mmc_card { struct sdio_cccr cccr; /* common card info */ struct sdio_cis cis; /* common tuple info */ struct sdio_func *sdio_func[SDIO_MAX_FUNCS]; /* SDIO functions (devices) */ + unsigned num_info; /* number of info strings */ + const char **info; /* info strings */ struct sdio_func_tuple *tuples; /* unknown common tuples */ }; diff --git a/include/linux/mmc/sdio_func.h b/include/linux/mmc/sdio_func.h index da6a96c3977..b050f4d7b41 100644 --- a/include/linux/mmc/sdio_func.h +++ b/include/linux/mmc/sdio_func.h @@ -51,6 +51,9 @@ struct sdio_func { u8 tmpbuf[4]; /* DMA:able scratch buffer */ + unsigned num_info; /* number of info strings */ + const char **info; /* info strings */ + struct sdio_func_tuple *tuples; }; -- cgit v1.2.3-70-g09d2 From 7213d175e3b6f6db60f843b72e88857a350e146a Mon Sep 17 00:00:00 2001 From: David Brownell Date: Wed, 8 Aug 2007 09:10:23 -0700 Subject: MMC/SD card driver learns SPI Teaching the MMC/SD block card driver about SPI. - Provide the SPI response type flags with each request issued. - Understand that multiblock SPI writes don't use STOP_TRANSMISSION. - Correct check for APP_CMD failure. Signed-off-by: David Brownell Signed-off-by: Pierre Ossman --- drivers/mmc/card/block.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index ab510689ecd..e38d5a3b2a8 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -151,17 +151,19 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card) cmd.opcode = MMC_APP_CMD; cmd.arg = card->rca << 16; - cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, 0); - if (err || !(cmd.resp[0] & R1_APP_CMD)) + if (err) + return (u32)-1; + if (!mmc_host_is_spi(card->host) && !(cmd.resp[0] & R1_APP_CMD)) return (u32)-1; memset(&cmd, 0, sizeof(struct mmc_command)); cmd.opcode = SD_APP_SEND_NUM_WR_BLKS; cmd.arg = 0; - cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; memset(&data, 0, sizeof(struct mmc_data)); @@ -220,11 +222,11 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) brq.cmd.arg = req->sector; if (!mmc_card_blockaddr(card)) brq.cmd.arg <<= 9; - brq.cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + brq.cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; brq.data.blksz = 1 << md->block_bits; brq.stop.opcode = MMC_STOP_TRANSMISSION; brq.stop.arg = 0; - brq.stop.flags = MMC_RSP_R1B | MMC_CMD_AC; + brq.stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; brq.data.blocks = req->nr_sectors >> (md->block_bits - 9); if (brq.data.blocks > card->host->max_blk_count) brq.data.blocks = card->host->max_blk_count; @@ -241,7 +243,12 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) brq.data.blocks = 1; if (brq.data.blocks > 1) { - brq.mrq.stop = &brq.stop; + /* SPI multiblock writes terminate using a special + * token, not a STOP_TRANSMISSION request. + */ + if (!mmc_host_is_spi(card->host) + || rq_data_dir(req) == READ) + brq.mrq.stop = &brq.stop; readcmd = MMC_READ_MULTIPLE_BLOCK; writecmd = MMC_WRITE_MULTIPLE_BLOCK; } else { @@ -301,7 +308,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) goto cmd_err; } - if (rq_data_dir(req) != READ) { + if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) { do { int err; @@ -509,7 +516,7 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card) mmc_claim_host(card->host); cmd.opcode = MMC_SET_BLOCKLEN; cmd.arg = 1 << md->block_bits; - cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, 5); mmc_release_host(card->host); -- cgit v1.2.3-70-g09d2 From af51715079e7fb6b290e1881d63d815dc4de5011 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Wed, 8 Aug 2007 09:11:32 -0700 Subject: MMC core learns about SPI Teach the MMC/SD/SDIO core about using SPI mode. - Use mmc_host_is_spi() so enumeration works through SPI signaling and protocols, not just the native versions. - Provide the SPI response type flags with each request issued, including requests from the new lock/unlock code. - Understand that cmd->resp[0] and mmc_get_status() results for SPI return different values than for "native" MMC/SD protocol; this affects resetting, checking card lock status, and some others. - Understand that some commands act a bit differently ... notably: * OP_COND command doesn't return the OCR * APP_CMD status doesn't have an R1_APP_CMD analogue Those changes required some new and updated primitives: - Provide utilities to access two SPI-only requests, and one request that wasn't previously needed: * mmc_spi_read_ocr() ... SPI only * mmc_spi_set_crc() ... SPI only (override by module parm) * mmc_send_cid() ... for use without broadcast mode - Updated internal routines: * Previous mmc_send_csd() modified into mmc_send_cxd_native(); it uses native "R2" responses, which include 16 bytes of data. * Previous mmc_send_ext_csd() becomes new mmc_send_cxd_data() helper for command-and-data access * Bugfix to that mmc_send_cxd_data() code: dma-to-stack is unsafe/nonportable, so kmalloc a bounce buffer instead. - Modified mmc_send_ext_csd() now uses mmc_send_cxd_data() helper - Modified mmc_send_csd(), and new mmc_spi_send_cid(), routines use those helper routines based on whether they're native or SPI The newest categories of cards supported by the MMC stack aren't expected to work yet with SPI: MMC or SD cards with over 4GB data, and SDIO. All those cards support SPI mode, so eventually they should work too. Signed-off-by: David Brownell Signed-off-by: Pierre Ossman --- drivers/mmc/core/bus.c | 24 +++++-- drivers/mmc/core/core.c | 28 ++++++-- drivers/mmc/core/core.h | 2 + drivers/mmc/core/mmc.c | 50 +++++++++---- drivers/mmc/core/mmc_ops.c | 166 +++++++++++++++++++++++++++++++++++--------- drivers/mmc/core/mmc_ops.h | 3 + drivers/mmc/core/sd.c | 48 ++++++++++--- drivers/mmc/core/sd_ops.c | 59 ++++++++++++---- drivers/mmc/core/sdio.c | 29 +++++--- drivers/mmc/core/sdio_ops.c | 66 +++++++++++++----- 10 files changed, 372 insertions(+), 103 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 733ac95331c..8d6f6014870 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -243,10 +243,17 @@ int mmc_add_card(struct mmc_card *card) break; } - printk(KERN_INFO "%s: new %s%s card at address %04x\n", - mmc_hostname(card->host), - mmc_card_highspeed(card) ? "high speed " : "", - type, card->rca); + if (mmc_host_is_spi(card->host)) { + printk(KERN_INFO "%s: new %s%s card on SPI\n", + mmc_hostname(card->host), + mmc_card_highspeed(card) ? "high speed " : "", + type); + } else { + printk(KERN_INFO "%s: new %s%s card at address %04x\n", + mmc_hostname(card->host), + mmc_card_highspeed(card) ? "high speed " : "", + type, card->rca); + } card->dev.uevent_suppress = 1; @@ -278,8 +285,13 @@ int mmc_add_card(struct mmc_card *card) void mmc_remove_card(struct mmc_card *card) { if (mmc_card_present(card)) { - printk(KERN_INFO "%s: card %04x removed\n", - mmc_hostname(card->host), card->rca); + if (mmc_host_is_spi(card->host)) { + printk(KERN_INFO "%s: SPI card removed\n", + mmc_hostname(card->host)); + } else { + printk(KERN_INFO "%s: card %04x removed\n", + mmc_hostname(card->host), card->rca); + } if (card->host->bus_ops->sysfs_remove) card->host->bus_ops->sysfs_remove(card->host, card); diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index bffcaf8df35..bad39442f8f 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -41,6 +41,14 @@ extern int mmc_attach_sdio(struct mmc_host *host, u32 ocr); static struct workqueue_struct *workqueue; +/* + * Enabling software CRCs on the data blocks can be a significant (30%) + * performance cost, and for other reasons may not always be desired. + * So we allow it it to be disabled. + */ +int use_spi_crc = 1; +module_param(use_spi_crc, bool, 0); + /* * Internal function. Schedule delayed work in the MMC work queue. */ @@ -71,6 +79,11 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) struct mmc_command *cmd = mrq->cmd; int err = cmd->error; + if (err && cmd->retries && mmc_host_is_spi(host)) { + if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND) + cmd->retries = 0; + } + if (err && cmd->retries) { pr_debug("%s: req failed (CMD%u): %d, retrying...\n", mmc_hostname(host), cmd->opcode, err); @@ -453,8 +466,13 @@ static void mmc_power_up(struct mmc_host *host) int bit = fls(host->ocr_avail) - 1; host->ios.vdd = bit; - host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; - host->ios.chip_select = MMC_CS_DONTCARE; + if (mmc_host_is_spi(host)) { + host->ios.chip_select = MMC_CS_HIGH; + host->ios.bus_mode = MMC_BUSMODE_PUSHPULL; + } else { + host->ios.chip_select = MMC_CS_DONTCARE; + host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; + } host->ios.power_mode = MMC_POWER_UP; host->ios.bus_width = MMC_BUS_WIDTH_1; host->ios.timing = MMC_TIMING_LEGACY; @@ -481,8 +499,10 @@ static void mmc_power_off(struct mmc_host *host) { host->ios.clock = 0; host->ios.vdd = 0; - host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; - host->ios.chip_select = MMC_CS_DONTCARE; + if (!mmc_host_is_spi(host)) { + host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; + host->ios.chip_select = MMC_CS_DONTCARE; + } host->ios.power_mode = MMC_POWER_OFF; host->ios.bus_width = MMC_BUS_WIDTH_1; host->ios.timing = MMC_TIMING_LEGACY; diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index bb2774af9ea..39daf2fb5dc 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h @@ -48,5 +48,7 @@ void mmc_rescan(struct work_struct *work); void mmc_start_host(struct mmc_host *host); void mmc_stop_host(struct mmc_host *host); +extern int use_spi_crc; + #endif diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 6ba458951d2..65fe28860f5 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -165,8 +165,6 @@ static int mmc_read_ext_csd(struct mmc_card *card) BUG_ON(!card); - err = -EIO; - if (card->csd.mmca_vsn < CSD_SPEC_VER_4) return 0; @@ -279,10 +277,22 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, if (err) goto err; + /* + * For SPI, enable CRC as appropriate. + */ + if (mmc_host_is_spi(host)) { + err = mmc_spi_set_crc(host, use_spi_crc); + if (err) + goto err; + } + /* * Fetch CID from card. */ - err = mmc_all_send_cid(host, cid); + if (mmc_host_is_spi(host)) + err = mmc_send_cid(host, cid); + else + err = mmc_all_send_cid(host, cid); if (err) goto err; @@ -309,13 +319,15 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, } /* - * Set card RCA. + * For native busses: set card RCA and quit open drain mode. */ - err = mmc_set_relative_addr(card); - if (err) - goto free_card; + if (!mmc_host_is_spi(host)) { + err = mmc_set_relative_addr(card); + if (err) + goto free_card; - mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); + mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); + } if (!oldcard) { /* @@ -336,13 +348,15 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, /* * Select card, as all following commands rely on that. */ - err = mmc_select_card(card); - if (err) - goto free_card; + if (!mmc_host_is_spi(host)) { + err = mmc_select_card(card); + if (err) + goto free_card; + } if (!oldcard) { /* - * Fetch and process extened CSD. + * Fetch and process extended CSD. */ err = mmc_read_ext_csd(card); if (err) @@ -502,7 +516,8 @@ static void mmc_suspend(struct mmc_host *host) BUG_ON(!host->card); mmc_claim_host(host); - mmc_deselect_cards(host); + if (!mmc_host_is_spi(host)) + mmc_deselect_cards(host); host->card->state &= ~MMC_STATE_HIGHSPEED; mmc_release_host(host); } @@ -562,6 +577,15 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr) mmc_attach_bus(host, &mmc_ops); + /* + * We need to get OCR a different way for SPI. + */ + if (mmc_host_is_spi(host)) { + err = mmc_spi_read_ocr(host, 1, &ocr); + if (err) + goto err; + } + /* * Sanity check the voltages that the card claims to * support. diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 39567f91a4b..bf4bc6adcfe 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -63,23 +63,36 @@ int mmc_go_idle(struct mmc_host *host) int err; struct mmc_command cmd; - mmc_set_chip_select(host, MMC_CS_HIGH); - - mmc_delay(1); + /* + * Non-SPI hosts need to prevent chipselect going active during + * GO_IDLE; that would put chips into SPI mode. Remind them of + * that in case of hardware that won't pull up DAT3/nCS otherwise. + * + * SPI hosts ignore ios.chip_select; it's managed according to + * rules that must accomodate non-MMC slaves which this layer + * won't even know about. + */ + if (!mmc_host_is_spi(host)) { + mmc_set_chip_select(host, MMC_CS_HIGH); + mmc_delay(1); + } memset(&cmd, 0, sizeof(struct mmc_command)); cmd.opcode = MMC_GO_IDLE_STATE; cmd.arg = 0; - cmd.flags = MMC_RSP_NONE | MMC_CMD_BC; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_NONE | MMC_CMD_BC; err = mmc_wait_for_cmd(host, &cmd, 0); mmc_delay(1); - mmc_set_chip_select(host, MMC_CS_DONTCARE); + if (!mmc_host_is_spi(host)) { + mmc_set_chip_select(host, MMC_CS_DONTCARE); + mmc_delay(1); + } - mmc_delay(1); + host->use_spi_crc = 0; return err; } @@ -94,23 +107,33 @@ int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) memset(&cmd, 0, sizeof(struct mmc_command)); cmd.opcode = MMC_SEND_OP_COND; - cmd.arg = ocr; - cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR; + cmd.arg = mmc_host_is_spi(host) ? 0 : ocr; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR; for (i = 100; i; i--) { err = mmc_wait_for_cmd(host, &cmd, 0); if (err) break; - if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0) + /* if we're just probing, do a single pass */ + if (ocr == 0) break; + /* otherwise wait until reset completes */ + if (mmc_host_is_spi(host)) { + if (!(cmd.resp[0] & R1_SPI_IDLE)) + break; + } else { + if (cmd.resp[0] & MMC_CARD_BUSY) + break; + } + err = -ETIMEDOUT; mmc_delay(10); } - if (rocr) + if (rocr && !mmc_host_is_spi(host)) *rocr = cmd.resp[0]; return err; @@ -160,40 +183,46 @@ int mmc_set_relative_addr(struct mmc_card *card) return 0; } -int mmc_send_csd(struct mmc_card *card, u32 *csd) +static int +mmc_send_cxd_native(struct mmc_host *host, u32 arg, u32 *cxd, int opcode) { int err; struct mmc_command cmd; - BUG_ON(!card); - BUG_ON(!card->host); - BUG_ON(!csd); + BUG_ON(!host); + BUG_ON(!cxd); memset(&cmd, 0, sizeof(struct mmc_command)); - cmd.opcode = MMC_SEND_CSD; - cmd.arg = card->rca << 16; + cmd.opcode = opcode; + cmd.arg = arg; cmd.flags = MMC_RSP_R2 | MMC_CMD_AC; - err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); + err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES); if (err) return err; - memcpy(csd, cmd.resp, sizeof(u32) * 4); + memcpy(cxd, cmd.resp, sizeof(u32) * 4); return 0; } -int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd) +static int +mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host, + u32 opcode, void *buf, unsigned len) { struct mmc_request mrq; struct mmc_command cmd; struct mmc_data data; struct scatterlist sg; + void *data_buf; - BUG_ON(!card); - BUG_ON(!card->host); - BUG_ON(!ext_csd); + /* dma onto stack is unsafe/nonportable, but callers to this + * routine normally provide temporary on-stack buffers ... + */ + data_buf = kmalloc(len, GFP_KERNEL); + if (data_buf == NULL) + return -ENOMEM; memset(&mrq, 0, sizeof(struct mmc_request)); memset(&cmd, 0, sizeof(struct mmc_command)); @@ -202,21 +231,31 @@ int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd) mrq.cmd = &cmd; mrq.data = &data; - cmd.opcode = MMC_SEND_EXT_CSD; + cmd.opcode = opcode; cmd.arg = 0; - cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; - data.blksz = 512; + /* NOTE HACK: the MMC_RSP_SPI_R1 is always correct here, but we + * rely on callers to never use this with "native" calls for reading + * CSD or CID. Native versions of those commands use the R2 type, + * not R1 plus a data block. + */ + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; + + data.blksz = len; data.blocks = 1; data.flags = MMC_DATA_READ; data.sg = &sg; data.sg_len = 1; - sg_init_one(&sg, ext_csd, 512); + sg_init_one(&sg, data_buf, len); - mmc_set_data_timeout(&data, card); + if (card) + mmc_set_data_timeout(&data, card); - mmc_wait_for_req(card->host, &mrq); + mmc_wait_for_req(host, &mrq); + + memcpy(buf, data_buf, len); + kfree(data_buf); if (cmd.error) return cmd.error; @@ -226,6 +265,67 @@ int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd) return 0; } +int mmc_send_csd(struct mmc_card *card, u32 *csd) +{ + if (!mmc_host_is_spi(card->host)) + return mmc_send_cxd_native(card->host, card->rca << 16, + csd, MMC_SEND_CSD); + + return mmc_send_cxd_data(card, card->host, MMC_SEND_CSD, csd, 16); +} + +int mmc_send_cid(struct mmc_host *host, u32 *cid) +{ + if (!mmc_host_is_spi(host)) { + if (!host->card) + return -EINVAL; + return mmc_send_cxd_native(host, host->card->rca << 16, + cid, MMC_SEND_CID); + } + + return mmc_send_cxd_data(NULL, host, MMC_SEND_CID, cid, 16); +} + +int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd) +{ + return mmc_send_cxd_data(card, card->host, MMC_SEND_EXT_CSD, + ext_csd, 512); +} + +int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp) +{ + struct mmc_command cmd; + int err; + + memset(&cmd, 0, sizeof(struct mmc_command)); + + cmd.opcode = MMC_SPI_READ_OCR; + cmd.arg = highcap ? (1 << 30) : 0; + cmd.flags = MMC_RSP_SPI_R3; + + err = mmc_wait_for_cmd(host, &cmd, 0); + + *ocrp = cmd.resp[1]; + return err; +} + +int mmc_spi_set_crc(struct mmc_host *host, int use_crc) +{ + struct mmc_command cmd; + int err; + + memset(&cmd, 0, sizeof(struct mmc_command)); + + cmd.opcode = MMC_SPI_CRC_ON_OFF; + cmd.flags = MMC_RSP_SPI_R1; + cmd.arg = use_crc; + + err = mmc_wait_for_cmd(host, &cmd, 0); + if (!err) + host->use_spi_crc = use_crc; + return err; +} + int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value) { int err; @@ -241,7 +341,7 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value) (index << 16) | (value << 8) | set; - cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; + cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); if (err) @@ -261,13 +361,17 @@ int mmc_send_status(struct mmc_card *card, u32 *status) memset(&cmd, 0, sizeof(struct mmc_command)); cmd.opcode = MMC_SEND_STATUS; - cmd.arg = card->rca << 16; - cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; + if (!mmc_host_is_spi(card->host)) + cmd.arg = card->rca << 16; + cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); if (err) return err; + /* NOTE: callers are required to understand the difference + * between "native" and SPI format status words! + */ if (status) *status = cmd.resp[0]; diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h index 76d09a93c5d..17854bf7cf0 100644 --- a/drivers/mmc/core/mmc_ops.h +++ b/drivers/mmc/core/mmc_ops.h @@ -22,6 +22,9 @@ int mmc_send_csd(struct mmc_card *card, u32 *csd); int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd); int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value); int mmc_send_status(struct mmc_card *card, u32 *status); +int mmc_send_cid(struct mmc_host *host, u32 *cid); +int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp); +int mmc_spi_set_crc(struct mmc_host *host, int use_crc); #endif diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index c86588fdaae..d1c1e0f592f 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -322,10 +322,22 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, if (err) goto err; + /* + * For SPI, enable CRC as appropriate. + */ + if (mmc_host_is_spi(host)) { + err = mmc_spi_set_crc(host, use_spi_crc); + if (err) + goto err; + } + /* * Fetch CID from card. */ - err = mmc_all_send_cid(host, cid); + if (mmc_host_is_spi(host)) + err = mmc_send_cid(host, cid); + else + err = mmc_all_send_cid(host, cid); if (err) goto err; @@ -351,13 +363,15 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, } /* - * Set card RCA. + * For native busses: get card RCA and quit open drain mode. */ - err = mmc_send_relative_addr(host, &card->rca); - if (err) - goto free_card; + if (!mmc_host_is_spi(host)) { + err = mmc_send_relative_addr(host, &card->rca); + if (err) + goto free_card; - mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); + mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); + } if (!oldcard) { /* @@ -377,9 +391,11 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, /* * Select card, as all following commands rely on that. */ - err = mmc_select_card(card); - if (err) - goto free_card; + if (!mmc_host_is_spi(host)) { + err = mmc_select_card(card); + if (err) + goto free_card; + } if (!oldcard) { /* @@ -562,7 +578,8 @@ static void mmc_sd_suspend(struct mmc_host *host) BUG_ON(!host->card); mmc_claim_host(host); - mmc_deselect_cards(host); + if (!mmc_host_is_spi(host)) + mmc_deselect_cards(host); host->card->state &= ~MMC_STATE_HIGHSPEED; mmc_release_host(host); } @@ -622,6 +639,17 @@ int mmc_attach_sd(struct mmc_host *host, u32 ocr) mmc_attach_bus(host, &mmc_sd_ops); + /* + * We need to get OCR a different way for SPI. + */ + if (mmc_host_is_spi(host)) { + mmc_go_idle(host); + + err = mmc_spi_read_ocr(host, 0, &ocr); + if (err) + goto err; + } + /* * Sanity check the voltages that the card claims to * support. diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c index 491e0306b1b..ee4029a24ef 100644 --- a/drivers/mmc/core/sd_ops.c +++ b/drivers/mmc/core/sd_ops.c @@ -33,10 +33,10 @@ static int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card) if (card) { cmd.arg = card->rca << 16; - cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; } else { cmd.arg = 0; - cmd.flags = MMC_RSP_R1 | MMC_CMD_BCR; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_BCR; } err = mmc_wait_for_cmd(host, &cmd, 0); @@ -44,7 +44,7 @@ static int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card) return err; /* Check that card supported application commands */ - if (!(cmd.resp[0] & R1_APP_CMD)) + if (!mmc_host_is_spi(host) && !(cmd.resp[0] & R1_APP_CMD)) return -EOPNOTSUPP; return 0; @@ -83,8 +83,14 @@ int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card, memset(&mrq, 0, sizeof(struct mmc_request)); err = mmc_app_cmd(host, card); - if (err) + if (err) { + /* no point in retrying; no APP commands allowed */ + if (mmc_host_is_spi(host)) { + if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND) + break; + } continue; + } memset(&mrq, 0, sizeof(struct mmc_request)); @@ -99,6 +105,12 @@ int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card, err = cmd->error; if (!cmd->error) break; + + /* no point in retrying illegal APP commands */ + if (mmc_host_is_spi(host)) { + if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND) + break; + } } return err; @@ -147,23 +159,36 @@ int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) memset(&cmd, 0, sizeof(struct mmc_command)); cmd.opcode = SD_APP_OP_COND; - cmd.arg = ocr; - cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR; + if (mmc_host_is_spi(host)) + cmd.arg = ocr & (1 << 30); /* SPI only defines one bit */ + else + cmd.arg = ocr; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR; for (i = 100; i; i--) { err = mmc_wait_for_app_cmd(host, NULL, &cmd, MMC_CMD_RETRIES); if (err) break; - if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0) + /* if we're just probing, do a single pass */ + if (ocr == 0) break; + /* otherwise wait until reset completes */ + if (mmc_host_is_spi(host)) { + if (!(cmd.resp[0] & R1_SPI_IDLE)) + break; + } else { + if (cmd.resp[0] & MMC_CARD_BUSY) + break; + } + err = -ETIMEDOUT; mmc_delay(10); } - if (rocr) + if (rocr && !mmc_host_is_spi(host)) *rocr = cmd.resp[0]; return err; @@ -174,6 +199,7 @@ int mmc_send_if_cond(struct mmc_host *host, u32 ocr) struct mmc_command cmd; int err; static const u8 test_pattern = 0xAA; + u8 result_pattern; /* * To support SD 2.0 cards, we must always invoke SD_SEND_IF_COND @@ -182,13 +208,18 @@ int mmc_send_if_cond(struct mmc_host *host, u32 ocr) */ cmd.opcode = SD_SEND_IF_COND; cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern; - cmd.flags = MMC_RSP_R7 | MMC_CMD_BCR; + cmd.flags = MMC_RSP_SPI_R7 | MMC_RSP_R7 | MMC_CMD_BCR; err = mmc_wait_for_cmd(host, &cmd, 0); if (err) return err; - if ((cmd.resp[0] & 0xFF) != test_pattern) + if (mmc_host_is_spi(host)) + result_pattern = cmd.resp[1] & 0xFF; + else + result_pattern = cmd.resp[0] & 0xFF; + + if (result_pattern != test_pattern) return -EIO; return 0; @@ -229,6 +260,8 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr) BUG_ON(!card->host); BUG_ON(!scr); + /* NOTE: caller guarantees scr is heap-allocated */ + err = mmc_app_cmd(card->host, card); if (err) return err; @@ -242,7 +275,7 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr) cmd.opcode = SD_APP_SEND_SCR; cmd.arg = 0; - cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; data.blksz = 8; data.blocks = 1; @@ -278,6 +311,8 @@ int mmc_sd_switch(struct mmc_card *card, int mode, int group, BUG_ON(!card); BUG_ON(!card->host); + /* NOTE: caller guarantees resp is heap-allocated */ + mode = !!mode; value &= 0xF; @@ -292,7 +327,7 @@ int mmc_sd_switch(struct mmc_card *card, int mode, int group, cmd.arg = mode << 31 | 0x00FFFFFF; cmd.arg &= ~(0xF << (group * 4)); cmd.arg |= value << (group * 4); - cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; data.blksz = 64; data.blocks = 1; diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 2f3fb994c38..87a50f456ef 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -269,6 +269,15 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr) if (err) goto err; + /* + * For SPI, enable CRC as appropriate. + */ + if (mmc_host_is_spi(host)) { + err = mmc_spi_set_crc(host, use_spi_crc); + if (err) + goto err; + } + /* * The number of functions on the card is encoded inside * the ocr. @@ -290,20 +299,24 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr) host->card = card; /* - * Set card RCA. + * For native busses: set card RCA and quit open drain mode. */ - err = mmc_send_relative_addr(host, &card->rca); - if (err) - goto remove; + if (!mmc_host_is_spi(host)) { + err = mmc_send_relative_addr(host, &card->rca); + if (err) + goto remove; - mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); + mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); + } /* * Select card, as all following commands rely on that. */ - err = mmc_select_card(card); - if (err) - goto remove; + if (!mmc_host_is_spi(host)) { + err = mmc_select_card(card); + if (err) + goto remove; + } /* * Read the common registers. diff --git a/drivers/mmc/core/sdio_ops.c b/drivers/mmc/core/sdio_ops.c index 98e20532452..4d289b27503 100644 --- a/drivers/mmc/core/sdio_ops.c +++ b/drivers/mmc/core/sdio_ops.c @@ -30,23 +30,39 @@ int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) cmd.opcode = SD_IO_SEND_OP_COND; cmd.arg = ocr; - cmd.flags = MMC_RSP_R4 | MMC_CMD_BCR; + cmd.flags = MMC_RSP_SPI_R4 | MMC_RSP_R4 | MMC_CMD_BCR; for (i = 100; i; i--) { err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES); if (err) break; - if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0) + /* if we're just probing, do a single pass */ + if (ocr == 0) break; + /* otherwise wait until reset completes */ + if (mmc_host_is_spi(host)) { + /* + * Both R1_SPI_IDLE and MMC_CARD_BUSY indicate + * an initialized card under SPI, but some cards + * (Marvell's) only behave when looking at this + * one. + */ + if (cmd.resp[1] & MMC_CARD_BUSY) + break; + } else { + if (cmd.resp[0] & MMC_CARD_BUSY) + break; + } + err = -ETIMEDOUT; mmc_delay(10); } if (rocr) - *rocr = cmd.resp[0]; + *rocr = cmd.resp[mmc_host_is_spi(host) ? 1 : 0]; return err; } @@ -68,21 +84,29 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, cmd.arg |= (write && out) ? 0x08000000 : 0x00000000; cmd.arg |= addr << 9; cmd.arg |= in; - cmd.flags = MMC_RSP_R5 | MMC_CMD_AC; + cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, 0); if (err) return err; - if (cmd.resp[0] & R5_ERROR) - return -EIO; - if (cmd.resp[0] & R5_FUNCTION_NUMBER) - return -EINVAL; - if (cmd.resp[0] & R5_OUT_OF_RANGE) - return -ERANGE; + if (mmc_host_is_spi(card->host)) { + /* host driver already reported errors */ + } else { + if (cmd.resp[0] & R5_ERROR) + return -EIO; + if (cmd.resp[0] & R5_FUNCTION_NUMBER) + return -EINVAL; + if (cmd.resp[0] & R5_OUT_OF_RANGE) + return -ERANGE; + } - if (out) - *out = cmd.resp[0] & 0xFF; + if (out) { + if (mmc_host_is_spi(card->host)) + *out = (cmd.resp[0] >> 8) & 0xFF; + else + *out = cmd.resp[0] & 0xFF; + } return 0; } @@ -117,7 +141,7 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, cmd.arg |= (blksz == 512) ? 0 : blksz; /* byte mode */ else cmd.arg |= 0x08000000 | blocks; /* block mode */ - cmd.flags = MMC_RSP_R5 | MMC_CMD_ADTC; + cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC; data.blksz = blksz; data.blocks = blocks; @@ -136,12 +160,16 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, if (data.error) return data.error; - if (cmd.resp[0] & R5_ERROR) - return -EIO; - if (cmd.resp[0] & R5_FUNCTION_NUMBER) - return -EINVAL; - if (cmd.resp[0] & R5_OUT_OF_RANGE) - return -ERANGE; + if (mmc_host_is_spi(card->host)) { + /* host driver already reported errors */ + } else { + if (cmd.resp[0] & R5_ERROR) + return -EIO; + if (cmd.resp[0] & R5_FUNCTION_NUMBER) + return -EINVAL; + if (cmd.resp[0] & R5_OUT_OF_RANGE) + return -ERANGE; + } return 0; } -- cgit v1.2.3-70-g09d2 From 15a0580ced081a0f7dc2deea8a4812bdc5e9a109 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Wed, 8 Aug 2007 09:12:54 -0700 Subject: mmc_spi host driver This is the latest version of the MMC-over-SPI support. It works on 2.6.23-rc2 plus git-mmc (from rc1-mm2), along with the preceding patches which teach the rest of the MMC stack about SPI. The main issue of note is that sometimes cards need to be power cycled to recover after certain faults. Also, it may sometimes be necessary to disable CRCs. ("modprobe mmc_core use_spi_crc=n") Signed-off-by: David Brownell Cc: mikael.starvik@axis.com, Cc: Hans-Peter Nilsson Cc: Jan Nikitenko Cc: Mike Lavender Signed-off-by: Pierre Ossman --- MAINTAINERS | 6 + drivers/mmc/host/Kconfig | 13 + drivers/mmc/host/Makefile | 1 + drivers/mmc/host/mmc_spi.c | 1408 +++++++++++++++++++++++++++++++++++++++++++ include/linux/spi/mmc_spi.h | 33 + 5 files changed, 1461 insertions(+) create mode 100644 drivers/mmc/host/mmc_spi.c create mode 100644 include/linux/spi/mmc_spi.h (limited to 'drivers') diff --git a/MAINTAINERS b/MAINTAINERS index c22d34b11f6..0df29ce05e5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2567,6 +2567,12 @@ M: drzeus-mmc@drzeus.cx L: linux-kernel@vger.kernel.org S: Maintained +MULTIMEDIA CARD (MMC) ETC. OVER SPI +P: David Brownell +M: dbrownell@users.sourceforge.net +L: linux-kernel@vger.kernel.org +S: Odd fixes + MULTISOUND SOUND DRIVER P: Andrew Veliath M: andrewtv@usa.net diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index e23082fe88d..68fb052afd3 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -100,3 +100,16 @@ config MMC_TIFM_SD To compile this driver as a module, choose M here: the module will be called tifm_sd. +config MMC_SPI + tristate "MMC/SD over SPI (EXPERIMENTAL)" + depends on MMC && SPI_MASTER && !HIGHMEM && EXPERIMENTAL + select CRC7 + select CRC_ITU_T + help + Some systems accss MMC/SD cards using a SPI controller instead of + using a "native" MMC/SD controller. This has a disadvantage of + being relatively high overhead, but a compensating advantage of + working on many systems without dedicated MMC/SD controllers. + + If unsure, or if your system has no SPI master driver, say N. + diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index 6685f64345b..8dc82ce647b 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -15,4 +15,5 @@ obj-$(CONFIG_MMC_AU1X) += au1xmmc.o obj-$(CONFIG_MMC_OMAP) += omap.o obj-$(CONFIG_MMC_AT91) += at91_mci.o obj-$(CONFIG_MMC_TIFM_SD) += tifm_sd.o +obj-$(CONFIG_MMC_SPI) += mmc_spi.o diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c new file mode 100644 index 00000000000..f30327bba6f --- /dev/null +++ b/drivers/mmc/host/mmc_spi.c @@ -0,0 +1,1408 @@ +/* + * mmc_spi.c - Access SD/MMC cards through SPI master controllers + * + * (C) Copyright 2005, Intec Automation, + * Mike Lavender (mike@steroidmicros) + * (C) Copyright 2006-2007, David Brownell + * (C) Copyright 2007, Axis Communications, + * Hans-Peter Nilsson (hp@axis.com) + * (C) Copyright 2007, ATRON electronic GmbH, + * Jan Nikitenko + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include +#include +#include + +#include +#include /* for R1_SPI_* bit values */ + +#include +#include + +#include + + +/* NOTES: + * + * - For now, we won't try to interoperate with a real mmc/sd/sdio + * controller, although some of them do have hardware support for + * SPI protocol. The main reason for such configs would be mmc-ish + * cards like DataFlash, which don't support that "native" protocol. + * + * We don't have a "DataFlash/MMC/SD/SDIO card slot" abstraction to + * switch between driver stacks, and in any case if "native" mode + * is available, it will be faster and hence preferable. + * + * - MMC depends on a different chipselect management policy than the + * SPI interface currently supports for shared bus segments: it needs + * to issue multiple spi_message requests with the chipselect active, + * using the results of one message to decide the next one to issue. + * + * Pending updates to the programming interface, this driver expects + * that it not share the bus with other drivers (precluding conflicts). + * + * - We tell the controller to keep the chipselect active from the + * beginning of an mmc_host_ops.request until the end. So beware + * of SPI controller drivers that mis-handle the cs_change flag! + * + * However, many cards seem OK with chipselect flapping up/down + * during that time ... at least on unshared bus segments. + */ + + +/* + * Local protocol constants, internal to data block protocols. + */ + +/* Response tokens used to ack each block written: */ +#define SPI_MMC_RESPONSE_CODE(x) ((x) & 0x1f) +#define SPI_RESPONSE_ACCEPTED ((2 << 1)|1) +#define SPI_RESPONSE_CRC_ERR ((5 << 1)|1) +#define SPI_RESPONSE_WRITE_ERR ((6 << 1)|1) + +/* Read and write blocks start with these tokens and end with crc; + * on error, read tokens act like a subset of R2_SPI_* values. + */ +#define SPI_TOKEN_SINGLE 0xfe /* single block r/w, multiblock read */ +#define SPI_TOKEN_MULTI_WRITE 0xfc /* multiblock write */ +#define SPI_TOKEN_STOP_TRAN 0xfd /* terminate multiblock write */ + +#define MMC_SPI_BLOCKSIZE 512 + + +/* These fixed timeouts come from the latest SD specs, which say to ignore + * the CSD values. The R1B value is for card erase (e.g. the "I forgot the + * card's password" scenario); it's mostly applied to STOP_TRANSMISSION after + * reads which takes nowhere near that long. Older cards may be able to use + * shorter timeouts ... but why bother? + */ +#define readblock_timeout ktime_set(0, 100 * 1000 * 1000) +#define writeblock_timeout ktime_set(0, 250 * 1000 * 1000) +#define r1b_timeout ktime_set(3, 0) + + +/****************************************************************************/ + +/* + * Local Data Structures + */ + +/* "scratch" is per-{command,block} data exchanged with the card */ +struct scratch { + u8 status[29]; + u8 data_token; + __be16 crc_val; +}; + +struct mmc_spi_host { + struct mmc_host *mmc; + struct spi_device *spi; + + unsigned char power_mode; + u16 powerup_msecs; + + struct mmc_spi_platform_data *pdata; + + /* for bulk data transfers */ + struct spi_transfer token, t, crc, early_status; + struct spi_message m; + + /* for status readback */ + struct spi_transfer status; + struct spi_message readback; + + /* underlying DMA-aware controller, or null */ + struct device *dma_dev; + + /* buffer used for commands and for message "overhead" */ + struct scratch *data; + dma_addr_t data_dma; + + /* Specs say to write ones most of the time, even when the card + * has no need to read its input data; and many cards won't care. + * This is our source of those ones. + */ + void *ones; + dma_addr_t ones_dma; +}; + + +/****************************************************************************/ + +/* + * MMC-over-SPI protocol glue, used by the MMC stack interface + */ + +static inline int mmc_cs_off(struct mmc_spi_host *host) +{ + /* chipselect will always be inactive after setup() */ + return spi_setup(host->spi); +} + +static int +mmc_spi_readbytes(struct mmc_spi_host *host, unsigned len) +{ + int status; + + if (len > sizeof(*host->data)) { + WARN_ON(1); + return -EIO; + } + + host->status.len = len; + + if (host->dma_dev) + dma_sync_single_for_device(host->dma_dev, + host->data_dma, sizeof(*host->data), + DMA_FROM_DEVICE); + + status = spi_sync(host->spi, &host->readback); + if (status == 0) + status = host->readback.status; + + if (host->dma_dev) + dma_sync_single_for_cpu(host->dma_dev, + host->data_dma, sizeof(*host->data), + DMA_FROM_DEVICE); + + return status; +} + +static int +mmc_spi_skip(struct mmc_spi_host *host, ktime_t timeout, unsigned n, u8 byte) +{ + u8 *cp = host->data->status; + + timeout = ktime_add(timeout, ktime_get()); + + while (1) { + int status; + unsigned i; + + status = mmc_spi_readbytes(host, n); + if (status < 0) + return status; + + for (i = 0; i < n; i++) { + if (cp[i] != byte) + return cp[i]; + } + + /* REVISIT investigate msleep() to avoid busy-wait I/O + * in at least some cases. + */ + if (ktime_to_ns(ktime_sub(ktime_get(), timeout)) > 0) + break; + } + return -ETIMEDOUT; +} + +static inline int +mmc_spi_wait_unbusy(struct mmc_spi_host *host, ktime_t timeout) +{ + return mmc_spi_skip(host, timeout, sizeof(host->data->status), 0); +} + +static int mmc_spi_readtoken(struct mmc_spi_host *host) +{ + return mmc_spi_skip(host, readblock_timeout, 1, 0xff); +} + + +/* + * Note that for SPI, cmd->resp[0] is not the same data as "native" protocol + * hosts return! The low byte holds R1_SPI bits. The next byte may hold + * R2_SPI bits ... for SEND_STATUS, or after data read errors. + * + * cmd->resp[1] holds any four-byte response, for R3 (READ_OCR) and on + * newer cards R7 (IF_COND). + */ + +static char *maptype(struct mmc_command *cmd) +{ + switch (mmc_spi_resp_type(cmd)) { + case MMC_RSP_SPI_R1: return "R1"; + case MMC_RSP_SPI_R1B: return "R1B"; + case MMC_RSP_SPI_R2: return "R2/R5"; + case MMC_RSP_SPI_R3: return "R3/R4/R7"; + default: return "?"; + } +} + +/* return zero, else negative errno after setting cmd->error */ +static int mmc_spi_response_get(struct mmc_spi_host *host, + struct mmc_command *cmd, int cs_on) +{ + u8 *cp = host->data->status; + u8 *end = cp + host->t.len; + int value = 0; + char tag[32]; + + snprintf(tag, sizeof(tag), " ... CMD%d response SPI_%s", + cmd->opcode, maptype(cmd)); + + /* Except for data block reads, the whole response will already + * be stored in the scratch buffer. It's somewhere after the + * command and the first byte we read after it. We ignore that + * first byte. After STOP_TRANSMISSION command it may include + * two data bits, but otherwise it's all ones. + */ + cp += 8; + while (cp < end && *cp == 0xff) + cp++; + + /* Data block reads (R1 response types) may need more data... */ + if (cp == end) { + unsigned i; + + cp = host->data->status; + + /* Card sends N(CR) (== 1..8) bytes of all-ones then one + * status byte ... and we already scanned 2 bytes. + * + * REVISIT block read paths use nasty byte-at-a-time I/O + * so it can always DMA directly into the target buffer. + * It'd probably be better to memcpy() the first chunk and + * avoid extra i/o calls... + */ + for (i = 2; i < 9; i++) { + value = mmc_spi_readbytes(host, 1); + if (value < 0) + goto done; + if (*cp != 0xff) + goto checkstatus; + } + value = -ETIMEDOUT; + goto done; + } + +checkstatus: + if (*cp & 0x80) { + dev_dbg(&host->spi->dev, "%s: INVALID RESPONSE, %02x\n", + tag, *cp); + value = -EBADR; + goto done; + } + + cmd->resp[0] = *cp++; + cmd->error = 0; + + /* Status byte: the entire seven-bit R1 response. */ + if (cmd->resp[0] != 0) { + if ((R1_SPI_PARAMETER | R1_SPI_ADDRESS + | R1_SPI_ILLEGAL_COMMAND) + & cmd->resp[0]) + value = -EINVAL; + else if (R1_SPI_COM_CRC & cmd->resp[0]) + value = -EILSEQ; + else if ((R1_SPI_ERASE_SEQ | R1_SPI_ERASE_RESET) + & cmd->resp[0]) + value = -EIO; + /* else R1_SPI_IDLE, "it's resetting" */ + } + + switch (mmc_spi_resp_type(cmd)) { + + /* SPI R1B == R1 + busy; STOP_TRANSMISSION (for multiblock reads) + * and less-common stuff like various erase operations. + */ + case MMC_RSP_SPI_R1B: + /* maybe we read all the busy tokens already */ + while (cp < end && *cp == 0) + cp++; + if (cp == end) + mmc_spi_wait_unbusy(host, r1b_timeout); + break; + + /* SPI R2 == R1 + second status byte; SEND_STATUS + * SPI R5 == R1 + data byte; IO_RW_DIRECT + */ + case MMC_RSP_SPI_R2: + cmd->resp[0] |= *cp << 8; + break; + + /* SPI R3, R4, or R7 == R1 + 4 bytes */ + case MMC_RSP_SPI_R3: + cmd->resp[1] = be32_to_cpu(get_unaligned((u32 *)cp)); + break; + + /* SPI R1 == just one status byte */ + case MMC_RSP_SPI_R1: + break; + + default: + dev_dbg(&host->spi->dev, "bad response type %04x\n", + mmc_spi_resp_type(cmd)); + if (value >= 0) + value = -EINVAL; + goto done; + } + + if (value < 0) + dev_dbg(&host->spi->dev, "%s: resp %04x %08x\n", + tag, cmd->resp[0], cmd->resp[1]); + + /* disable chipselect on errors and some success cases */ + if (value >= 0 && cs_on) + return value; +done: + if (value < 0) + cmd->error = value; + mmc_cs_off(host); + return value; +} + +/* Issue command and read its response. + * Returns zero on success, negative for error. + * + * On error, caller must cope with mmc core retry mechanism. That + * means immediate low-level resubmit, which affects the bus lock... + */ +static int +mmc_spi_command_send(struct mmc_spi_host *host, + struct mmc_request *mrq, + struct mmc_command *cmd, int cs_on) +{ + struct scratch *data = host->data; + u8 *cp = data->status; + u32 arg = cmd->arg; + int status; + struct spi_transfer *t; + + /* We can handle most commands (except block reads) in one full + * duplex I/O operation before either starting the next transfer + * (data block or command) or else deselecting the card. + * + * First, write 7 bytes: + * - an all-ones byte to ensure the card is ready + * - opcode byte (plus start and transmission bits) + * - four bytes of big-endian argument + * - crc7 (plus end bit) ... always computed, it's cheap + * + * We init the whole buffer to all-ones, which is what we need + * to write while we're reading (later) response data. + */ + memset(cp++, 0xff, sizeof(data->status)); + + *cp++ = 0x40 | cmd->opcode; + *cp++ = (u8)(arg >> 24); + *cp++ = (u8)(arg >> 16); + *cp++ = (u8)(arg >> 8); + *cp++ = (u8)arg; + *cp++ = (crc7(0, &data->status[1], 5) << 1) | 0x01; + + /* Then, read up to 13 bytes (while writing all-ones): + * - N(CR) (== 1..8) bytes of all-ones + * - status byte (for all response types) + * - the rest of the response, either: + * + nothing, for R1 or R1B responses + * + second status byte, for R2 responses + * + four data bytes, for R3 and R7 responses + * + * Finally, read some more bytes ... in the nice cases we know in + * advance how many, and reading 1 more is always OK: + * - N(EC) (== 0..N) bytes of all-ones, before deselect/finish + * - N(RC) (== 1..N) bytes of all-ones, before next command + * - N(WR) (== 1..N) bytes of all-ones, before data write + * + * So in those cases one full duplex I/O of at most 21 bytes will + * handle the whole command, leaving the card ready to receive a + * data block or new command. We do that whenever we can, shaving + * CPU and IRQ costs (especially when using DMA or FIFOs). + * + * There are two other cases, where it's not generally practical + * to rely on a single I/O: + * + * - R1B responses need at least N(EC) bytes of all-zeroes. + * + * In this case we can *try* to fit it into one I/O, then + * maybe read more data later. + * + * - Data block reads are more troublesome, since a variable + * number of padding bytes precede the token and data. + * + N(CX) (== 0..8) bytes of all-ones, before CSD or CID + * + N(AC) (== 1..many) bytes of all-ones + * + * In this case we currently only have minimal speedups here: + * when N(CR) == 1 we can avoid I/O in response_get(). + */ + if (cs_on && (mrq->data->flags & MMC_DATA_READ)) { + cp += 2; /* min(N(CR)) + status */ + /* R1 */ + } else { + cp += 10; /* max(N(CR)) + status + min(N(RC),N(WR)) */ + if (cmd->flags & MMC_RSP_SPI_S2) /* R2/R5 */ + cp++; + else if (cmd->flags & MMC_RSP_SPI_B4) /* R3/R4/R7 */ + cp += 4; + else if (cmd->flags & MMC_RSP_BUSY) /* R1B */ + cp = data->status + sizeof(data->status); + /* else: R1 (most commands) */ + } + + dev_dbg(&host->spi->dev, " mmc_spi: CMD%d, resp %s\n", + cmd->opcode, maptype(cmd)); + + /* send command, leaving chipselect active */ + spi_message_init(&host->m); + + t = &host->t; + memset(t, 0, sizeof(*t)); + t->tx_buf = t->rx_buf = data->status; + t->tx_dma = t->rx_dma = host->data_dma; + t->len = cp - data->status; + t->cs_change = 1; + spi_message_add_tail(t, &host->m); + + if (host->dma_dev) { + host->m.is_dma_mapped = 1; + dma_sync_single_for_device(host->dma_dev, + host->data_dma, sizeof(*host->data), + DMA_BIDIRECTIONAL); + } + status = spi_sync(host->spi, &host->m); + if (status == 0) + status = host->m.status; + + if (host->dma_dev) + dma_sync_single_for_cpu(host->dma_dev, + host->data_dma, sizeof(*host->data), + DMA_BIDIRECTIONAL); + if (status < 0) { + dev_dbg(&host->spi->dev, " ... write returned %d\n", status); + cmd->error = status; + return status; + } + + /* after no-data commands and STOP_TRANSMISSION, chipselect off */ + return mmc_spi_response_get(host, cmd, cs_on); +} + +/* Build data message with up to four separate transfers. For TX, we + * start by writing the data token. And in most cases, we finish with + * a status transfer. + * + * We always provide TX data for data and CRC. The MMC/SD protocol + * requires us to write ones; but Linux defaults to writing zeroes; + * so we explicitly initialize it to all ones on RX paths. + * + * We also handle DMA mapping, so the underlying SPI controller does + * not need to (re)do it for each message. + */ +static void +mmc_spi_setup_data_message( + struct mmc_spi_host *host, + int multiple, + enum dma_data_direction direction) +{ + struct spi_transfer *t; + struct scratch *scratch = host->data; + dma_addr_t dma = host->data_dma; + + spi_message_init(&host->m); + if (dma) + host->m.is_dma_mapped = 1; + + /* for reads, readblock() skips 0xff bytes before finding + * the token; for writes, this transfer issues that token. + */ + if (direction == DMA_TO_DEVICE) { + t = &host->token; + memset(t, 0, sizeof(*t)); + t->len = 1; + if (multiple) + scratch->data_token = SPI_TOKEN_MULTI_WRITE; + else + scratch->data_token = SPI_TOKEN_SINGLE; + t->tx_buf = &scratch->data_token; + if (dma) + t->tx_dma = dma + offsetof(struct scratch, data_token); + spi_message_add_tail(t, &host->m); + } + + /* Body of transfer is buffer, then CRC ... + * either TX-only, or RX with TX-ones. + */ + t = &host->t; + memset(t, 0, sizeof(*t)); + t->tx_buf = host->ones; + t->tx_dma = host->ones_dma; + /* length and actual buffer info are written later */ + spi_message_add_tail(t, &host->m); + + t = &host->crc; + memset(t, 0, sizeof(*t)); + t->len = 2; + if (direction == DMA_TO_DEVICE) { + /* the actual CRC may get written later */ + t->tx_buf = &scratch->crc_val; + if (dma) + t->tx_dma = dma + offsetof(struct scratch, crc_val); + } else { + t->tx_buf = host->ones; + t->tx_dma = host->ones_dma; + t->rx_buf = &scratch->crc_val; + if (dma) + t->rx_dma = dma + offsetof(struct scratch, crc_val); + } + spi_message_add_tail(t, &host->m); + + /* + * A single block read is followed by N(EC) [0+] all-ones bytes + * before deselect ... don't bother. + * + * Multiblock reads are followed by N(AC) [1+] all-ones bytes before + * the next block is read, or a STOP_TRANSMISSION is issued. We'll + * collect that single byte, so readblock() doesn't need to. + * + * For a write, the one-byte data response follows immediately, then + * come zero or more busy bytes, then N(WR) [1+] all-ones bytes. + * Then single block reads may deselect, and multiblock ones issue + * the next token (next data block, or STOP_TRAN). We can try to + * minimize I/O ops by using a single read to collect end-of-busy. + */ + if (multiple || direction == DMA_TO_DEVICE) { + t = &host->early_status; + memset(t, 0, sizeof(*t)); + t->len = (direction == DMA_TO_DEVICE) + ? sizeof(scratch->status) + : 1; + t->tx_buf = host->ones; + t->tx_dma = host->ones_dma; + t->rx_buf = scratch->status; + if (dma) + t->rx_dma = dma + offsetof(struct scratch, status); + t->cs_change = 1; + spi_message_add_tail(t, &host->m); + } +} + +/* + * Write one block: + * - caller handled preceding N(WR) [1+] all-ones bytes + * - data block + * + token + * + data bytes + * + crc16 + * - an all-ones byte ... card writes a data-response byte + * - followed by N(EC) [0+] all-ones bytes, card writes zero/'busy' + * + * Return negative errno, else success. + */ +static int +mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t) +{ + struct spi_device *spi = host->spi; + int status, i; + struct scratch *scratch = host->data; + + if (host->mmc->use_spi_crc) + scratch->crc_val = cpu_to_be16( + crc_itu_t(0, t->tx_buf, t->len)); + if (host->dma_dev) + dma_sync_single_for_device(host->dma_dev, + host->data_dma, sizeof(*scratch), + DMA_BIDIRECTIONAL); + + status = spi_sync(spi, &host->m); + if (status == 0) + status = host->m.status; + + if (status != 0) { + dev_dbg(&spi->dev, "write error (%d)\n", status); + return status; + } + + if (host->dma_dev) + dma_sync_single_for_cpu(host->dma_dev, + host->data_dma, sizeof(*scratch), + DMA_BIDIRECTIONAL); + + /* + * Get the transmission data-response reply. It must follow + * immediately after the data block we transferred. This reply + * doesn't necessarily tell whether the write operation succeeded; + * it just says if the transmission was ok and whether *earlier* + * writes succeeded; see the standard. + */ + switch (SPI_MMC_RESPONSE_CODE(scratch->status[0])) { + case SPI_RESPONSE_ACCEPTED: + status = 0; + break; + case SPI_RESPONSE_CRC_ERR: + /* host shall then issue MMC_STOP_TRANSMISSION */ + status = -EILSEQ; + break; + case SPI_RESPONSE_WRITE_ERR: + /* host shall then issue MMC_STOP_TRANSMISSION, + * and should MMC_SEND_STATUS to sort it out + */ + status = -EIO; + break; + default: + status = -EPROTO; + break; + } + if (status != 0) { + dev_dbg(&spi->dev, "write error %02x (%d)\n", + scratch->status[0], status); + return status; + } + + t->tx_buf += t->len; + if (host->dma_dev) + t->tx_dma += t->len; + + /* Return when not busy. If we didn't collect that status yet, + * we'll need some more I/O. + */ + for (i = 1; i < sizeof(scratch->status); i++) { + if (scratch->status[i] != 0) + return 0; + } + return mmc_spi_wait_unbusy(host, writeblock_timeout); +} + +/* + * Read one block: + * - skip leading all-ones bytes ... either + * + N(AC) [1..f(clock,CSD)] usually, else + * + N(CX) [0..8] when reading CSD or CID + * - data block + * + token ... if error token, no data or crc + * + data bytes + * + crc16 + * + * After single block reads, we're done; N(EC) [0+] all-ones bytes follow + * before dropping chipselect. + * + * For multiblock reads, caller either reads the next block or issues a + * STOP_TRANSMISSION command. + */ +static int +mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t) +{ + struct spi_device *spi = host->spi; + int status; + struct scratch *scratch = host->data; + + /* At least one SD card sends an all-zeroes byte when N(CX) + * applies, before the all-ones bytes ... just cope with that. + */ + status = mmc_spi_readbytes(host, 1); + if (status < 0) + return status; + status = scratch->status[0]; + if (status == 0xff || status == 0) + status = mmc_spi_readtoken(host); + + if (status == SPI_TOKEN_SINGLE) { + if (host->dma_dev) { + dma_sync_single_for_device(host->dma_dev, + host->data_dma, sizeof(*scratch), + DMA_BIDIRECTIONAL); + dma_sync_single_for_device(host->dma_dev, + t->rx_dma, t->len, + DMA_FROM_DEVICE); + } + + status = spi_sync(spi, &host->m); + if (status == 0) + status = host->m.status; + + if (host->dma_dev) { + dma_sync_single_for_cpu(host->dma_dev, + host->data_dma, sizeof(*scratch), + DMA_BIDIRECTIONAL); + dma_sync_single_for_cpu(host->dma_dev, + t->rx_dma, t->len, + DMA_FROM_DEVICE); + } + + } else { + dev_dbg(&spi->dev, "read error %02x (%d)\n", status, status); + + /* we've read extra garbage, timed out, etc */ + if (status < 0) + return status; + + /* low four bits are an R2 subset, fifth seems to be + * vendor specific ... map them all to generic error.. + */ + return -EIO; + } + + if (host->mmc->use_spi_crc) { + u16 crc = crc_itu_t(0, t->rx_buf, t->len); + + be16_to_cpus(&scratch->crc_val); + if (scratch->crc_val != crc) { + dev_dbg(&spi->dev, "read - crc error: crc_val=0x%04x, " + "computed=0x%04x len=%d\n", + scratch->crc_val, crc, t->len); + return -EILSEQ; + } + } + + t->rx_buf += t->len; + if (host->dma_dev) + t->rx_dma += t->len; + + return 0; +} + +/* + * An MMC/SD data stage includes one or more blocks, optional CRCs, + * and inline handshaking. That handhaking makes it unlike most + * other SPI protocol stacks. + */ +static void +mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd, + struct mmc_data *data, u32 blk_size) +{ + struct spi_device *spi = host->spi; + struct device *dma_dev = host->dma_dev; + struct spi_transfer *t; + enum dma_data_direction direction; + struct scatterlist *sg; + unsigned n_sg; + int multiple = (data->blocks > 1); + + if (data->flags & MMC_DATA_READ) + direction = DMA_FROM_DEVICE; + else + direction = DMA_TO_DEVICE; + mmc_spi_setup_data_message(host, multiple, direction); + t = &host->t; + + /* Handle scatterlist segments one at a time, with synch for + * each 512-byte block + */ + for (sg = data->sg, n_sg = data->sg_len; n_sg; n_sg--, sg++) { + int status = 0; + dma_addr_t dma_addr = 0; + void *kmap_addr; + unsigned length = sg->length; + enum dma_data_direction dir = direction; + + /* set up dma mapping for controller drivers that might + * use DMA ... though they may fall back to PIO + */ + if (dma_dev) { + /* never invalidate whole *shared* pages ... */ + if ((sg->offset != 0 || length != PAGE_SIZE) + && dir == DMA_FROM_DEVICE) + dir = DMA_BIDIRECTIONAL; + + dma_addr = dma_map_page(dma_dev, sg->page, 0, + PAGE_SIZE, dir); + if (direction == DMA_TO_DEVICE) + t->tx_dma = dma_addr + sg->offset; + else + t->rx_dma = dma_addr + sg->offset; + } + + /* allow pio too; we don't allow highmem */ + kmap_addr = kmap(sg->page); + if (direction == DMA_TO_DEVICE) + t->tx_buf = kmap_addr + sg->offset; + else + t->rx_buf = kmap_addr + sg->offset; + + /* transfer each block, and update request status */ + while (length) { + t->len = min(length, blk_size); + + dev_dbg(&host->spi->dev, + " mmc_spi: %s block, %d bytes\n", + (direction == DMA_TO_DEVICE) + ? "write" + : "read", + t->len); + + if (direction == DMA_TO_DEVICE) + status = mmc_spi_writeblock(host, t); + else + status = mmc_spi_readblock(host, t); + if (status < 0) + break; + + data->bytes_xfered += t->len; + length -= t->len; + + if (!multiple) + break; + } + + /* discard mappings */ + if (direction == DMA_FROM_DEVICE) + flush_kernel_dcache_page(sg->page); + kunmap(sg->page); + if (dma_dev) + dma_unmap_page(dma_dev, dma_addr, PAGE_SIZE, dir); + + if (status < 0) { + data->error = status; + dev_dbg(&spi->dev, "%s status %d\n", + (direction == DMA_TO_DEVICE) + ? "write" : "read", + status); + break; + } + } + + /* NOTE some docs describe an MMC-only SET_BLOCK_COUNT (CMD23) that + * can be issued before multiblock writes. Unlike its more widely + * documented analogue for SD cards (SET_WR_BLK_ERASE_COUNT, ACMD23), + * that can affect the STOP_TRAN logic. Complete (and current) + * MMC specs should sort that out before Linux starts using CMD23. + */ + if (direction == DMA_TO_DEVICE && multiple) { + struct scratch *scratch = host->data; + int tmp; + const unsigned statlen = sizeof(scratch->status); + + dev_dbg(&spi->dev, " mmc_spi: STOP_TRAN\n"); + + /* Tweak the per-block message we set up earlier by morphing + * it to hold single buffer with the token followed by some + * all-ones bytes ... skip N(BR) (0..1), scan the rest for + * "not busy any longer" status, and leave chip selected. + */ + INIT_LIST_HEAD(&host->m.transfers); + list_add(&host->early_status.transfer_list, + &host->m.transfers); + + memset(scratch->status, 0xff, statlen); + scratch->status[0] = SPI_TOKEN_STOP_TRAN; + + host->early_status.tx_buf = host->early_status.rx_buf; + host->early_status.tx_dma = host->early_status.rx_dma; + host->early_status.len = statlen; + + if (host->dma_dev) + dma_sync_single_for_device(host->dma_dev, + host->data_dma, sizeof(*scratch), + DMA_BIDIRECTIONAL); + + tmp = spi_sync(spi, &host->m); + if (tmp == 0) + tmp = host->m.status; + + if (host->dma_dev) + dma_sync_single_for_cpu(host->dma_dev, + host->data_dma, sizeof(*scratch), + DMA_BIDIRECTIONAL); + + if (tmp < 0) { + if (!data->error) + data->error = tmp; + return; + } + + /* Ideally we collected "not busy" status with one I/O, + * avoiding wasteful byte-at-a-time scanning... but more + * I/O is often needed. + */ + for (tmp = 2; tmp < statlen; tmp++) { + if (scratch->status[tmp] != 0) + return; + } + tmp = mmc_spi_wait_unbusy(host, writeblock_timeout); + if (tmp < 0 && !data->error) + data->error = tmp; + } +} + +/****************************************************************************/ + +/* + * MMC driver implementation -- the interface to the MMC stack + */ + +static void mmc_spi_request(struct mmc_host *mmc, struct mmc_request *mrq) +{ + struct mmc_spi_host *host = mmc_priv(mmc); + int status = -EINVAL; + +#ifdef DEBUG + /* MMC core and layered drivers *MUST* issue SPI-aware commands */ + { + struct mmc_command *cmd; + int invalid = 0; + + cmd = mrq->cmd; + if (!mmc_spi_resp_type(cmd)) { + dev_dbg(&host->spi->dev, "bogus command\n"); + cmd->error = -EINVAL; + invalid = 1; + } + + cmd = mrq->stop; + if (cmd && !mmc_spi_resp_type(cmd)) { + dev_dbg(&host->spi->dev, "bogus STOP command\n"); + cmd->error = -EINVAL; + invalid = 1; + } + + if (invalid) { + dump_stack(); + mmc_request_done(host->mmc, mrq); + return; + } + } +#endif + + /* issue command; then optionally data and stop */ + status = mmc_spi_command_send(host, mrq, mrq->cmd, mrq->data != NULL); + if (status == 0 && mrq->data) { + mmc_spi_data_do(host, mrq->cmd, mrq->data, mrq->data->blksz); + if (mrq->stop) + status = mmc_spi_command_send(host, mrq, mrq->stop, 0); + else + mmc_cs_off(host); + } + + mmc_request_done(host->mmc, mrq); +} + +/* See Section 6.4.1, in SD "Simplified Physical Layer Specification 2.0" + * + * NOTE that here we can't know that the card has just been powered up; + * not all MMC/SD sockets support power switching. + * + * FIXME when the card is still in SPI mode, e.g. from a previous kernel, + * this doesn't seem to do the right thing at all... + */ +static void mmc_spi_initsequence(struct mmc_spi_host *host) +{ + /* Try to be very sure any previous command has completed; + * wait till not-busy, skip debris from any old commands. + */ + mmc_spi_wait_unbusy(host, r1b_timeout); + mmc_spi_readbytes(host, 10); + + /* + * Do a burst with chipselect active-high. We need to do this to + * meet the requirement of 74 clock cycles with both chipselect + * and CMD (MOSI) high before CMD0 ... after the card has been + * powered up to Vdd(min), and so is ready to take commands. + * + * Some cards are particularly needy of this (e.g. Viking "SD256") + * while most others don't seem to care. + * + * Note that this is one of the places MMC/SD plays games with the + * SPI protocol. Another is that when chipselect is released while + * the card returns BUSY status, the clock must issue several cycles + * with chipselect high before the card will stop driving its output. + */ + host->spi->mode |= SPI_CS_HIGH; + if (spi_setup(host->spi) != 0) { + /* Just warn; most cards work without it. */ + dev_warn(&host->spi->dev, + "can't change chip-select polarity\n"); + host->spi->mode &= ~SPI_CS_HIGH; + } else { + mmc_spi_readbytes(host, 18); + + host->spi->mode &= ~SPI_CS_HIGH; + if (spi_setup(host->spi) != 0) { + /* Wot, we can't get the same setup we had before? */ + dev_err(&host->spi->dev, + "can't restore chip-select polarity\n"); + } + } +} + +static char *mmc_powerstring(u8 power_mode) +{ + switch (power_mode) { + case MMC_POWER_OFF: return "off"; + case MMC_POWER_UP: return "up"; + case MMC_POWER_ON: return "on"; + } + return "?"; +} + +static void mmc_spi_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct mmc_spi_host *host = mmc_priv(mmc); + + if (host->power_mode != ios->power_mode) { + int canpower; + + canpower = host->pdata && host->pdata->setpower; + + dev_dbg(&host->spi->dev, "mmc_spi: power %s (%d)%s\n", + mmc_powerstring(ios->power_mode), + ios->vdd, + canpower ? ", can switch" : ""); + + /* switch power on/off if possible, accounting for + * max 250msec powerup time if needed. + */ + if (canpower) { + switch (ios->power_mode) { + case MMC_POWER_OFF: + case MMC_POWER_UP: + host->pdata->setpower(&host->spi->dev, + ios->vdd); + if (ios->power_mode == MMC_POWER_UP) + msleep(host->powerup_msecs); + } + } + + /* See 6.4.1 in the simplified SD card physical spec 2.0 */ + if (ios->power_mode == MMC_POWER_ON) + mmc_spi_initsequence(host); + + /* If powering down, ground all card inputs to avoid power + * delivery from data lines! On a shared SPI bus, this + * will probably be temporary; 6.4.2 of the simplified SD + * spec says this must last at least 1msec. + * + * - Clock low means CPOL 0, e.g. mode 0 + * - MOSI low comes from writing zero + * - Chipselect is usually active low... + */ + if (canpower && ios->power_mode == MMC_POWER_OFF) { + int mres; + + host->spi->mode &= ~(SPI_CPOL|SPI_CPHA); + mres = spi_setup(host->spi); + if (mres < 0) + dev_dbg(&host->spi->dev, + "switch to SPI mode 0 failed\n"); + + if (spi_w8r8(host->spi, 0x00) < 0) + dev_dbg(&host->spi->dev, + "put spi signals to low failed\n"); + + /* + * Now clock should be low due to spi mode 0; + * MOSI should be low because of written 0x00; + * chipselect should be low (it is active low) + * power supply is off, so now MMC is off too! + * + * FIXME no, chipselect can be high since the + * device is inactive and SPI_CS_HIGH is clear... + */ + msleep(10); + if (mres == 0) { + host->spi->mode |= (SPI_CPOL|SPI_CPHA); + mres = spi_setup(host->spi); + if (mres < 0) + dev_dbg(&host->spi->dev, + "switch back to SPI mode 3" + " failed\n"); + } + } + + host->power_mode = ios->power_mode; + } + + if (host->spi->max_speed_hz != ios->clock && ios->clock != 0) { + int status; + + host->spi->max_speed_hz = ios->clock; + status = spi_setup(host->spi); + dev_dbg(&host->spi->dev, + "mmc_spi: clock to %d Hz, %d\n", + host->spi->max_speed_hz, status); + } +} + +static int mmc_spi_get_ro(struct mmc_host *mmc) +{ + struct mmc_spi_host *host = mmc_priv(mmc); + + if (host->pdata && host->pdata->get_ro) + return host->pdata->get_ro(mmc->parent); + /* board doesn't support read only detection; assume writeable */ + return 0; +} + + +static const struct mmc_host_ops mmc_spi_ops = { + .request = mmc_spi_request, + .set_ios = mmc_spi_set_ios, + .get_ro = mmc_spi_get_ro, +}; + + +/****************************************************************************/ + +/* + * SPI driver implementation + */ + +static irqreturn_t +mmc_spi_detect_irq(int irq, void *mmc) +{ + struct mmc_spi_host *host = mmc_priv(mmc); + u16 delay_msec = max(host->pdata->detect_delay, (u16)100); + + mmc_detect_change(mmc, msecs_to_jiffies(delay_msec)); + return IRQ_HANDLED; +} + +static int mmc_spi_probe(struct spi_device *spi) +{ + void *ones; + struct mmc_host *mmc; + struct mmc_spi_host *host; + int status; + + /* MMC and SD specs only seem to care that sampling is on the + * rising edge ... meaning SPI modes 0 or 3. So either SPI mode + * should be legit. We'll use mode 0 since it seems to be a + * bit less troublesome on some hardware ... unclear why. + */ + spi->mode = SPI_MODE_0; + spi->bits_per_word = 8; + + status = spi_setup(spi); + if (status < 0) { + dev_dbg(&spi->dev, "needs SPI mode %02x, %d KHz; %d\n", + spi->mode, spi->max_speed_hz / 1000, + status); + return status; + } + + /* We can use the bus safely iff nobody else will interfere with + * us. That is, either we have the experimental exclusive access + * primitives ... or else there's nobody to share it with. + */ + if (spi->master->num_chipselect > 1) { + struct device *parent = spi->dev.parent; + + /* If there are multiple devices on this bus, we + * can't proceed. + */ + spin_lock(&parent->klist_children.k_lock); + if (parent->klist_children.k_list.next + != parent->klist_children.k_list.prev) + status = -EMLINK; + else + status = 0; + spin_unlock(&parent->klist_children.k_lock); + if (status < 0) { + dev_err(&spi->dev, "can't share SPI bus\n"); + return status; + } + + /* REVISIT we can't guarantee another device won't + * be added later. It's uncommon though ... for now, + * work as if this is safe. + */ + dev_warn(&spi->dev, "ASSUMING unshared SPI bus!\n"); + } + + /* We need a supply of ones to transmit. This is the only time + * the CPU touches these, so cache coherency isn't a concern. + * + * NOTE if many systems use more than one MMC-over-SPI connector + * it'd save some memory to share this. That's evidently rare. + */ + status = -ENOMEM; + ones = kmalloc(MMC_SPI_BLOCKSIZE, GFP_KERNEL); + if (!ones) + goto nomem; + memset(ones, 0xff, MMC_SPI_BLOCKSIZE); + + mmc = mmc_alloc_host(sizeof(*host), &spi->dev); + if (!mmc) + goto nomem; + + mmc->ops = &mmc_spi_ops; + mmc->max_blk_size = MMC_SPI_BLOCKSIZE; + + /* As long as we keep track of the number of successfully + * transmitted blocks, we're good for multiwrite. + */ + mmc->caps = MMC_CAP_SPI | MMC_CAP_MULTIWRITE; + + /* SPI doesn't need the lowspeed device identification thing for + * MMC or SD cards, since it never comes up in open drain mode. + * That's good; some SPI masters can't handle very low speeds! + * + * However, low speed SDIO cards need not handle over 400 KHz; + * that's the only reason not to use a few MHz for f_min (until + * the upper layer reads the target frequency from the CSD). + */ + mmc->f_min = 400000; + mmc->f_max = spi->max_speed_hz; + + host = mmc_priv(mmc); + host->mmc = mmc; + host->spi = spi; + + host->ones = ones; + + /* Platform data is used to hook up things like card sensing + * and power switching gpios. + */ + host->pdata = spi->dev.platform_data; + if (host->pdata) + mmc->ocr_avail = host->pdata->ocr_mask; + if (!mmc->ocr_avail) { + dev_warn(&spi->dev, "ASSUMING 3.2-3.4 V slot power\n"); + mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34; + } + if (host->pdata && host->pdata->setpower) { + host->powerup_msecs = host->pdata->powerup_msecs; + if (!host->powerup_msecs || host->powerup_msecs > 250) + host->powerup_msecs = 250; + } + + dev_set_drvdata(&spi->dev, mmc); + + /* preallocate dma buffers */ + host->data = kmalloc(sizeof(*host->data), GFP_KERNEL); + if (!host->data) + goto fail_nobuf1; + + if (spi->master->cdev.dev->dma_mask) { + struct device *dev = spi->master->cdev.dev; + + host->dma_dev = dev; + host->ones_dma = dma_map_single(dev, ones, + MMC_SPI_BLOCKSIZE, DMA_TO_DEVICE); + host->data_dma = dma_map_single(dev, host->data, + sizeof(*host->data), DMA_BIDIRECTIONAL); + + /* REVISIT in theory those map operations can fail... */ + + dma_sync_single_for_cpu(host->dma_dev, + host->data_dma, sizeof(*host->data), + DMA_BIDIRECTIONAL); + } + + /* setup message for status/busy readback */ + spi_message_init(&host->readback); + host->readback.is_dma_mapped = (host->dma_dev != NULL); + + spi_message_add_tail(&host->status, &host->readback); + host->status.tx_buf = host->ones; + host->status.tx_dma = host->ones_dma; + host->status.rx_buf = &host->data->status; + host->status.rx_dma = host->data_dma + offsetof(struct scratch, status); + host->status.cs_change = 1; + + /* register card detect irq */ + if (host->pdata && host->pdata->init) { + status = host->pdata->init(&spi->dev, mmc_spi_detect_irq, mmc); + if (status != 0) + goto fail_glue_init; + } + + status = mmc_add_host(mmc); + if (status != 0) + goto fail_add_host; + + dev_info(&spi->dev, "SD/MMC host %s%s%s%s\n", + mmc->class_dev.bus_id, + host->dma_dev ? "" : ", no DMA", + (host->pdata && host->pdata->get_ro) + ? "" : ", no WP", + (host->pdata && host->pdata->setpower) + ? "" : ", no poweroff"); + return 0; + +fail_add_host: + mmc_remove_host (mmc); +fail_glue_init: + if (host->dma_dev) + dma_unmap_single(host->dma_dev, host->data_dma, + sizeof(*host->data), DMA_BIDIRECTIONAL); + kfree(host->data); + +fail_nobuf1: + mmc_free_host(mmc); + dev_set_drvdata(&spi->dev, NULL); + +nomem: + kfree(ones); + return status; +} + + +static int __devexit mmc_spi_remove(struct spi_device *spi) +{ + struct mmc_host *mmc = dev_get_drvdata(&spi->dev); + struct mmc_spi_host *host; + + if (mmc) { + host = mmc_priv(mmc); + + /* prevent new mmc_detect_change() calls */ + if (host->pdata && host->pdata->exit) + host->pdata->exit(&spi->dev, mmc); + + mmc_remove_host(mmc); + + if (host->dma_dev) { + dma_unmap_single(host->dma_dev, host->ones_dma, + MMC_SPI_BLOCKSIZE, DMA_TO_DEVICE); + dma_unmap_single(host->dma_dev, host->data_dma, + sizeof(*host->data), DMA_BIDIRECTIONAL); + } + + kfree(host->data); + kfree(host->ones); + + spi->max_speed_hz = mmc->f_max; + mmc_free_host(mmc); + dev_set_drvdata(&spi->dev, NULL); + } + return 0; +} + + +static struct spi_driver mmc_spi_driver = { + .driver = { + .name = "mmc_spi", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = mmc_spi_probe, + .remove = __devexit_p(mmc_spi_remove), +}; + + +static int __init mmc_spi_init(void) +{ + return spi_register_driver(&mmc_spi_driver); +} +module_init(mmc_spi_init); + + +static void __exit mmc_spi_exit(void) +{ + spi_unregister_driver(&mmc_spi_driver); +} +module_exit(mmc_spi_exit); + + +MODULE_AUTHOR("Mike Lavender, David Brownell, " + "Hans-Peter Nilsson, Jan Nikitenko"); +MODULE_DESCRIPTION("SPI SD/MMC host driver"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/spi/mmc_spi.h b/include/linux/spi/mmc_spi.h new file mode 100644 index 00000000000..e9bbe3ebd72 --- /dev/null +++ b/include/linux/spi/mmc_spi.h @@ -0,0 +1,33 @@ +#ifndef __LINUX_SPI_MMC_SPI_H +#define __LINUX_SPI_MMC_SPI_H + +struct device; +struct mmc_host; + +/* Put this in platform_data of a device being used to manage an MMC/SD + * card slot. (Modeled after PXA mmc glue; see that for usage examples.) + * + * REVISIT This is not a spi-specific notion. Any card slot should be + * able to handle it. If the MMC core doesn't adopt this kind of notion, + * switch the "struct device *" parameters over to "struct spi_device *". + */ +struct mmc_spi_platform_data { + /* driver activation and (optional) card detect irq hookup */ + int (*init)(struct device *, + irqreturn_t (*)(int, void *), + void *); + void (*exit)(struct device *, void *); + + /* sense switch on sd cards */ + int (*get_ro)(struct device *); + + /* how long to debounce card detect, in msecs */ + u16 detect_delay; + + /* power management */ + u16 powerup_msecs; /* delay of up to 250 msec */ + u32 ocr_mask; /* available voltages */ + void (*setpower)(struct device *, unsigned int maskval); +}; + +#endif /* __LINUX_SPI_MMC_SPI_H */ -- cgit v1.2.3-70-g09d2 From af8350c756cb48a738474738f7bf8c0e572fa057 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 24 Sep 2007 07:15:48 +0200 Subject: mmc: add led trigger Add a led trigger for each host controller that indicates if there is a request active on the controller. Signed-off-by: Pierre Ossman --- drivers/mmc/core/core.c | 5 +++++ drivers/mmc/core/host.c | 5 +++++ include/linux/mmc/host.h | 6 ++++++ 3 files changed, 16 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index bad39442f8f..09435e0ec68 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -92,6 +93,8 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) cmd->error = 0; host->ops->request(host, mrq); } else { + led_trigger_event(host->led, LED_OFF); + pr_debug("%s: req done (CMD%u): %d: %08x %08x %08x %08x\n", mmc_hostname(host), cmd->opcode, err, cmd->resp[0], cmd->resp[1], @@ -146,6 +149,8 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) WARN_ON(!host->claimed); + led_trigger_event(host->led, LED_FULL); + mrq->cmd->error = 0; mrq->cmd->mrq = mrq; if (mrq->data) { diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 37b761891d6..64fbc9759a3 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -15,6 +15,7 @@ #include #include #include +#include #include @@ -115,6 +116,8 @@ int mmc_add_host(struct mmc_host *host) snprintf(host->class_dev.bus_id, BUS_ID_SIZE, "mmc%d", host->index); + led_trigger_register_simple(host->class_dev.bus_id, &host->led); + err = device_add(&host->class_dev); if (err) return err; @@ -140,6 +143,8 @@ void mmc_remove_host(struct mmc_host *host) device_del(&host->class_dev); + led_trigger_unregister(host->led); + spin_lock(&mmc_host_lock); idr_remove(&mmc_host_idr, host->index); spin_unlock(&mmc_host_lock); diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 76eef94782f..125eee1407f 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -10,6 +10,8 @@ #ifndef LINUX_MMC_HOST_H #define LINUX_MMC_HOST_H +#include + #include struct mmc_ios { @@ -133,6 +135,10 @@ struct mmc_host { struct task_struct *sdio_irq_thread; atomic_t sdio_irq_thread_abort; +#ifdef CONFIG_LEDS_TRIGGERS + struct led_trigger *led; /* activity led */ +#endif + unsigned long private[0] ____cacheline_aligned; }; -- cgit v1.2.3-70-g09d2 From faf39ede5e6325d3e91b6e4e0017d27fbecb6022 Mon Sep 17 00:00:00 2001 From: Pavel Pisa Date: Sun, 23 Sep 2007 22:59:01 +0200 Subject: arm: i.MX/MX1 SDHC implements SD cards read-only switch read-back The patch enables to define MMC host get_ro() method through platform data. Signed-off-by: Pavel Pisa Signed-off-by: Pierre Ossman --- arch/arm/mach-imx/mx1ads.c | 2 +- drivers/mmc/host/imxmmc.c | 16 ++++++++++++++-- include/asm-arm/arch-imx/mmc.h | 5 ++++- 3 files changed, 19 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/arch/arm/mach-imx/mx1ads.c b/arch/arm/mach-imx/mx1ads.c index da893c80d47..a9778c1587a 100644 --- a/arch/arm/mach-imx/mx1ads.c +++ b/arch/arm/mach-imx/mx1ads.c @@ -116,7 +116,7 @@ static struct platform_device *devices[] __initdata = { }; #ifdef CONFIG_MMC_IMX -static int mx1ads_mmc_card_present(void) +static int mx1ads_mmc_card_present(struct device *dev) { /* MMC/SD Card Detect is PB 20 on MX1ADS V1.0.7 */ return (SSR(1) & (1 << 20) ? 0 : 1); diff --git a/drivers/mmc/host/imxmmc.c b/drivers/mmc/host/imxmmc.c index e33c123c702..6ebc41e7592 100644 --- a/drivers/mmc/host/imxmmc.c +++ b/drivers/mmc/host/imxmmc.c @@ -884,9 +884,21 @@ static void imxmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) } } +static int imxmci_get_ro(struct mmc_host *mmc) +{ + struct imxmci_host *host = mmc_priv(mmc); + + if (host->pdata && host->pdata->get_ro) + return host->pdata->get_ro(mmc_dev(mmc)); + /* Host doesn't support read only detection so assume writeable */ + return 0; +} + + static const struct mmc_host_ops imxmci_ops = { .request = imxmci_request, .set_ios = imxmci_set_ios, + .get_ro = imxmci_get_ro, }; static struct resource *platform_device_resource(struct platform_device *dev, unsigned int mask, int nr) @@ -913,7 +925,7 @@ static void imxmci_check_status(unsigned long data) { struct imxmci_host *host = (struct imxmci_host *)data; - if( host->pdata->card_present() != host->present ) { + if( host->pdata->card_present(mmc_dev(host->mmc)) != host->present ) { host->present ^= 1; dev_info(mmc_dev(host->mmc), "card %s\n", host->present ? "inserted" : "removed"); @@ -1022,7 +1034,7 @@ static int imxmci_probe(struct platform_device *pdev) if (ret) goto out; - host->present = host->pdata->card_present(); + host->present = host->pdata->card_present(mmc_dev(mmc)); init_timer(&host->timer); host->timer.data = (unsigned long)host; host->timer.function = imxmci_check_status; diff --git a/include/asm-arm/arch-imx/mmc.h b/include/asm-arm/arch-imx/mmc.h index 84c726934ac..4712f354dcc 100644 --- a/include/asm-arm/arch-imx/mmc.h +++ b/include/asm-arm/arch-imx/mmc.h @@ -3,8 +3,11 @@ #include +struct device; + struct imxmmc_platform_data { - int (*card_present)(void); + int (*card_present)(struct device *); + int (*get_ro)(struct device *); }; extern void imx_set_mmc_info(struct imxmmc_platform_data *info); -- cgit v1.2.3-70-g09d2 From 81ab570f65395f09962f4bca0d89403f8911c071 Mon Sep 17 00:00:00 2001 From: Bridge Wu Date: Tue, 25 Sep 2007 18:59:07 +0200 Subject: mmc: pxamci: better pending IRQ determination Pending interrupts should be determined from both I_REG and I_MASK registers. Signed-off-by: Bridge Wu Signed-off-by: Nicolas Pitre Signed-off-by: Pierre Ossman --- drivers/mmc/host/pxamci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index b89e32d1e9b..03d16288115 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -298,7 +298,7 @@ static irqreturn_t pxamci_irq(int irq, void *devid) unsigned int ireg; int handled = 0; - ireg = readl(host->base + MMC_I_REG); + ireg = readl(host->base + MMC_I_REG) & ~readl(host->base + MMC_I_MASK); if (ireg) { unsigned stat = readl(host->base + MMC_STAT); -- cgit v1.2.3-70-g09d2 From fe2dc44eac1223a0e92859242f58fd2a58a6f8fa Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Mon, 24 Sep 2007 15:47:18 -0400 Subject: mmc: pxamci: set proper block capabilities according to PXA flavor From PXA27x, it is possible to do 2048-byte block transfers. Signed-off-by: Nicolas Pitre Signed-off-by: Pierre Ossman --- drivers/mmc/host/pxamci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index 03d16288115..67acc6a0089 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -444,9 +444,9 @@ static int pxamci_probe(struct platform_device *pdev) mmc->max_seg_size = PAGE_SIZE; /* - * Block length register is 10 bits. + * Block length register is only 10 bits before PXA27x. */ - mmc->max_blk_size = 1023; + mmc->max_blk_size = (cpu_is_pxa21x() || cpu_is_pxa25x()) ? 1023 : 2048; /* * Block count register is 16 bits. -- cgit v1.2.3-70-g09d2 From df456f479aa6fdc812df51627c6f2c21d8a1aed8 Mon Sep 17 00:00:00 2001 From: Bridge Wu Date: Tue, 25 Sep 2007 19:09:19 +0200 Subject: mmc: pxamci: set proper buswidth capabilities according to PXA flavor From PXA27x, it is possible to do 4-bit data transfers. Signed-off-by: Bridge Wu Signed-off-by: Nicolas Pitre Signed-off-by: Pierre Ossman --- drivers/mmc/host/pxamci.c | 10 +++++++++- drivers/mmc/host/pxamci.h | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index 67acc6a0089..6549f546df5 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -284,7 +284,7 @@ static int pxamci_data_done(struct pxamci_host *host, unsigned int stat) host->data = NULL; if (host->mrq->stop) { pxamci_stop_clock(host); - pxamci_start_cmd(host, host->mrq->stop, 0); + pxamci_start_cmd(host, host->mrq->stop, host->cmdat); } else { pxamci_finish_request(host, host->mrq); } @@ -382,6 +382,11 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) host->cmdat |= CMDAT_INIT; } + if (ios->bus_width == MMC_BUS_WIDTH_4) + host->cmdat |= CMDAT_SD_4DAT; + else + host->cmdat &= ~CMDAT_SD_4DAT; + pr_debug("PXAMCI: clkrt = %x cmdat = %x\n", host->clkrt, host->cmdat); } @@ -460,6 +465,9 @@ static int pxamci_probe(struct platform_device *pdev) mmc->ocr_avail = host->pdata ? host->pdata->ocr_mask : MMC_VDD_32_33|MMC_VDD_33_34; + mmc->caps = 0; + if (!cpu_is_pxa21x() && !cpu_is_pxa25x()) + mmc->caps |= MMC_CAP_4_BIT_DATA; host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL); if (!host->sg_cpu) { diff --git a/drivers/mmc/host/pxamci.h b/drivers/mmc/host/pxamci.h index df17c281278..5655be823a0 100644 --- a/drivers/mmc/host/pxamci.h +++ b/drivers/mmc/host/pxamci.h @@ -25,6 +25,7 @@ #define SPI_EN (1 << 0) #define MMC_CMDAT 0x0010 +#define CMDAT_SD_4DAT (1 << 8) #define CMDAT_DMAEN (1 << 7) #define CMDAT_INIT (1 << 6) #define CMDAT_BUSY (1 << 5) -- cgit v1.2.3-70-g09d2 From 5d3ad4e8a12e538eead0a37d22b1ba6aec0f2127 Mon Sep 17 00:00:00 2001 From: Bridge Wu Date: Tue, 25 Sep 2007 19:11:00 +0200 Subject: mmc: pxamci: add SDIO card interrupt reporting capability Again, only available from PXA27x. Signed-off-by: Bridge Wu Signed-off-by: Nicolas Pitre Signed-off-by: Pierre Ossman --- drivers/mmc/host/pxamci.c | 28 +++++++++++++++++++++++----- drivers/mmc/host/pxamci.h | 1 + 2 files changed, 24 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index 6549f546df5..91e25683b39 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -309,6 +309,10 @@ static irqreturn_t pxamci_irq(int irq, void *devid) handled |= pxamci_cmd_done(host, stat); if (ireg & DATA_TRAN_DONE) handled |= pxamci_data_done(host, stat); + if (ireg & SDIO_INT) { + mmc_signal_sdio_irq(host->mmc); + handled = 1; + } } return IRQ_RETVAL(handled); @@ -391,10 +395,21 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) host->clkrt, host->cmdat); } +static void pxamci_enable_sdio_irq(struct mmc_host *host, int enable) +{ + struct pxamci_host *pxa_host = mmc_priv(host); + + if (enable) + pxamci_enable_irq(pxa_host, SDIO_INT); + else + pxamci_disable_irq(pxa_host, SDIO_INT); +} + static const struct mmc_host_ops pxamci_ops = { - .request = pxamci_request, - .get_ro = pxamci_get_ro, - .set_ios = pxamci_set_ios, + .request = pxamci_request, + .get_ro = pxamci_get_ro, + .set_ios = pxamci_set_ios, + .enable_sdio_irq = pxamci_enable_sdio_irq, }; static void pxamci_dma_irq(int dma, void *devid) @@ -466,8 +481,11 @@ static int pxamci_probe(struct platform_device *pdev) host->pdata->ocr_mask : MMC_VDD_32_33|MMC_VDD_33_34; mmc->caps = 0; - if (!cpu_is_pxa21x() && !cpu_is_pxa25x()) - mmc->caps |= MMC_CAP_4_BIT_DATA; + host->cmdat = 0; + if (!cpu_is_pxa21x() && !cpu_is_pxa25x()) { + mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ; + host->cmdat |= CMDAT_SDIO_INT_EN; + } host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL); if (!host->sg_cpu) { diff --git a/drivers/mmc/host/pxamci.h b/drivers/mmc/host/pxamci.h index 5655be823a0..3153e779d46 100644 --- a/drivers/mmc/host/pxamci.h +++ b/drivers/mmc/host/pxamci.h @@ -25,6 +25,7 @@ #define SPI_EN (1 << 0) #define MMC_CMDAT 0x0010 +#define CMDAT_SDIO_INT_EN (1 << 11) #define CMDAT_SD_4DAT (1 << 8) #define CMDAT_DMAEN (1 << 7) #define CMDAT_INIT (1 << 6) -- cgit v1.2.3-70-g09d2 From 6f4285d13300f1c8cd675a41ab390cea06173cd1 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 27 Sep 2007 10:48:29 +0200 Subject: sdio: adaptive interrupt polling The interrupt polling frequency is a compromise between power usage and interrupt latency. Unfortunately, it affects throughput rather severely for devices which require an interrupt for every chunk of data. By making the polling frequency adaptive, we get better throughput with those devices without sacficing too much power. Polling will quickly increase when there is an actual interrupt, and slowly fall back to the idle frequency when the interrupts stop coming. Signed-off-by: Pierre Ossman --- drivers/mmc/core/sdio_irq.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c index 8843a4c2fe9..f78ffeefed5 100644 --- a/drivers/mmc/core/sdio_irq.c +++ b/drivers/mmc/core/sdio_irq.c @@ -27,7 +27,7 @@ static int process_sdio_pending_irqs(struct mmc_card *card) { - int i, ret; + int i, ret, count; unsigned char pending; ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_INTx, 0, &pending); @@ -37,6 +37,7 @@ static int process_sdio_pending_irqs(struct mmc_card *card) return ret; } + count = 0; for (i = 1; i <= 7; i++) { if (pending & (1 << i)) { struct sdio_func *func = card->sdio_func[i - 1]; @@ -46,20 +47,21 @@ static int process_sdio_pending_irqs(struct mmc_card *card) sdio_func_id(func)); } else if (func->irq_handler) { func->irq_handler(func); + count++; } else printk(KERN_WARNING "%s: pending IRQ with no handler\n", sdio_func_id(func)); } } - return 0; + return count; } static int sdio_irq_thread(void *_host) { struct mmc_host *host = _host; struct sched_param param = { .sched_priority = 1 }; - unsigned long period; + unsigned long period, idle_period; int ret; sched_setscheduler(current, SCHED_FIFO, ¶m); @@ -70,8 +72,9 @@ static int sdio_irq_thread(void *_host) * asynchronous notification of pending SDIO card interrupts * hence we poll for them in that case. */ + idle_period = msecs_to_jiffies(10); period = (host->caps & MMC_CAP_SDIO_IRQ) ? - MAX_SCHEDULE_TIMEOUT : msecs_to_jiffies(10); + MAX_SCHEDULE_TIMEOUT : idle_period; pr_debug("%s: IRQ thread started (poll period = %lu jiffies)\n", mmc_hostname(host), period); @@ -101,9 +104,24 @@ static int sdio_irq_thread(void *_host) * errors. FIXME: determine if due to card removal and * possibly exit this thread if so. */ - if (ret) + if (ret < 0) ssleep(1); + /* + * Adaptive polling frequency based on the assumption + * that an interrupt will be closely followed by more. + * This has a substantial benefit for network devices. + */ + if (!(host->caps & MMC_CAP_SDIO_IRQ)) { + if (ret > 0) + period /= 2; + else { + period++; + if (period > idle_period) + period = idle_period; + } + } + set_task_state(current, TASK_INTERRUPTIBLE); if (host->caps & MMC_CAP_SDIO_IRQ) host->ops->enable_sdio_irq(host, 1); -- cgit v1.2.3-70-g09d2 From a4e32b5f0ac60e6bca7c6896f47e1c624ae45df1 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Tue, 2 Oct 2007 13:30:05 -0700 Subject: [POWERPC] Sky Cpu and Nexus: code style improvement Remove useless spaces and adds some empty lines to make code more readable. Also marker for printk is added. Signed-off-by: Cyrill Gorcunov Cc: Benjamin Herrenschmidt Cc: Kumar Gala Cc: Brian Waite Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- drivers/misc/hdpuftrs/hdpu_cpustate.c | 38 ++++++++++++++++------------------- drivers/misc/hdpuftrs/hdpu_nexus.c | 24 +++++++++++++--------- 2 files changed, 31 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/hdpuftrs/hdpu_cpustate.c b/drivers/misc/hdpuftrs/hdpu_cpustate.c index 276ba3c5143..1874b0740f2 100644 --- a/drivers/misc/hdpuftrs/hdpu_cpustate.c +++ b/drivers/misc/hdpuftrs/hdpu_cpustate.c @@ -169,22 +169,21 @@ static struct platform_driver hdpu_cpustate_driver = { * The various file operations we support. */ static const struct file_operations cpustate_fops = { - owner:THIS_MODULE, - open:cpustate_open, - release:cpustate_release, - read:cpustate_read, - write:cpustate_write, - fasync:NULL, - poll:NULL, - ioctl:NULL, - llseek:no_llseek, - + owner: THIS_MODULE, + open: cpustate_open, + release: cpustate_release, + read: cpustate_read, + write: cpustate_write, + fasync: NULL, + poll: NULL, + ioctl: NULL, + llseek: no_llseek, }; static struct miscdevice cpustate_dev = { MISC_DYNAMIC_MINOR, "sky_cpustate", - &cpustate_fops + &cpustate_fops, }; static int hdpu_cpustate_probe(struct platform_device *pdev) @@ -199,18 +198,18 @@ static int hdpu_cpustate_probe(struct platform_device *pdev) ret = misc_register(&cpustate_dev); if (ret) { - printk(KERN_WARNING "sky_cpustate: Unable to register misc " - "device.\n"); + printk(KERN_WARNING "sky_cpustate: " + "Unable to register misc device.\n"); cpustate.set_addr = NULL; cpustate.clr_addr = NULL; return ret; } proc_de = create_proc_read_entry("sky_cpustate", 0, 0, - cpustate_read_proc, NULL); + cpustate_read_proc, NULL); if (proc_de == NULL) - printk(KERN_WARNING "sky_cpustate: Unable to create proc " - "dir entry\n"); + printk(KERN_WARNING "sky_cpustate: " + "Unable to create proc dir entry\n"); printk(KERN_INFO "Sky CPU State Driver v" SKY_CPUSTATE_VERSION "\n"); return 0; @@ -218,21 +217,18 @@ static int hdpu_cpustate_probe(struct platform_device *pdev) static int hdpu_cpustate_remove(struct platform_device *pdev) { - cpustate.set_addr = NULL; cpustate.clr_addr = NULL; remove_proc_entry("sky_cpustate", NULL); misc_deregister(&cpustate_dev); - return 0; + return 0; } static int __init cpustate_init(void) { - int rc; - rc = platform_driver_register(&hdpu_cpustate_driver); - return rc; + return platform_driver_register(&hdpu_cpustate_driver); } static void __exit cpustate_exit(void) diff --git a/drivers/misc/hdpuftrs/hdpu_nexus.c b/drivers/misc/hdpuftrs/hdpu_nexus.c index 60c8b26f067..fd3f3c22115 100644 --- a/drivers/misc/hdpuftrs/hdpu_nexus.c +++ b/drivers/misc/hdpuftrs/hdpu_nexus.c @@ -40,40 +40,43 @@ static struct platform_driver hdpu_nexus_driver = { int hdpu_slot_id_read(char *buffer, char **buffer_location, off_t offset, int buffer_length, int *zero, void *ptr) { - if (offset > 0) return 0; + return sprintf(buffer, "%d\n", slot_id); } int hdpu_chassis_id_read(char *buffer, char **buffer_location, off_t offset, int buffer_length, int *zero, void *ptr) { - if (offset > 0) return 0; + return sprintf(buffer, "%d\n", chassis_id); } static int hdpu_nexus_probe(struct platform_device *pdev) { struct resource *res; + int *nexus_id_addr; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - int *nexus_id_addr; - nexus_id_addr = - ioremap(res->start, (unsigned long)(res->end - res->start)); + nexus_id_addr = ioremap(res->start, + (unsigned long)(res->end - res->start)); if (nexus_id_addr) { slot_id = (*nexus_id_addr >> 8) & 0x1f; chassis_id = *nexus_id_addr & 0xff; iounmap(nexus_id_addr); - } else - printk("Could not map slot id\n"); + } else { + printk(KERN_ERR "Could not map slot id\n"); + } + hdpu_slot_id = create_proc_entry("sky_slot_id", 0666, &proc_root); hdpu_slot_id->read_proc = hdpu_slot_id_read; hdpu_chassis_id = create_proc_entry("sky_chassis_id", 0666, &proc_root); hdpu_chassis_id->read_proc = hdpu_chassis_id_read; + return 0; } @@ -81,18 +84,19 @@ static int hdpu_nexus_remove(struct platform_device *pdev) { slot_id = -1; chassis_id = -1; + remove_proc_entry("sky_slot_id", &proc_root); remove_proc_entry("sky_chassis_id", &proc_root); + hdpu_slot_id = 0; hdpu_chassis_id = 0; + return 0; } static int __init nexus_init(void) { - int rc; - rc = platform_driver_register(&hdpu_nexus_driver); - return rc; + return platform_driver_register(&hdpu_nexus_driver); } static void __exit nexus_exit(void) -- cgit v1.2.3-70-g09d2 From d2ceb47a7cbcc50b45832c6b24c47515838d169a Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Tue, 2 Oct 2007 13:30:06 -0700 Subject: [POWERPC] Sky Cpu and Nexus: include io.h Add #include directive to properly declare ioremap() and writel(). Signed-off-by: Cyrill Gorcunov Cc: Benjamin Herrenschmidt Cc: Kumar Gala Cc: Brian Waite Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- drivers/misc/hdpuftrs/hdpu_cpustate.c | 1 + drivers/misc/hdpuftrs/hdpu_nexus.c | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/misc/hdpuftrs/hdpu_cpustate.c b/drivers/misc/hdpuftrs/hdpu_cpustate.c index 1874b0740f2..b5c6f21dcb6 100644 --- a/drivers/misc/hdpuftrs/hdpu_cpustate.c +++ b/drivers/misc/hdpuftrs/hdpu_cpustate.c @@ -22,6 +22,7 @@ #include #include #include +#include #define SKY_CPUSTATE_VERSION "1.1" diff --git a/drivers/misc/hdpuftrs/hdpu_nexus.c b/drivers/misc/hdpuftrs/hdpu_nexus.c index fd3f3c22115..fda9998f45c 100644 --- a/drivers/misc/hdpuftrs/hdpu_nexus.c +++ b/drivers/misc/hdpuftrs/hdpu_nexus.c @@ -20,6 +20,7 @@ #include #include +#include static int hdpu_nexus_probe(struct platform_device *pdev); static int hdpu_nexus_remove(struct platform_device *pdev); -- cgit v1.2.3-70-g09d2 From 7472fd36a87e84c2819066543224285a6ab79ffc Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Tue, 2 Oct 2007 13:30:06 -0700 Subject: [POWERPC] Sky Cpu and Nexus: check for platform_get_resource retcode Add adds checking for platform_get_resource() return code to prevent possible NULL pointer usage. Signed-off-by: Cyrill Gorcunov Cc: Benjamin Herrenschmidt Cc: Kumar Gala Cc: Brian Waite Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- drivers/misc/hdpuftrs/hdpu_cpustate.c | 5 +++++ drivers/misc/hdpuftrs/hdpu_nexus.c | 7 ++++++- 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/misc/hdpuftrs/hdpu_cpustate.c b/drivers/misc/hdpuftrs/hdpu_cpustate.c index b5c6f21dcb6..b16742c7c69 100644 --- a/drivers/misc/hdpuftrs/hdpu_cpustate.c +++ b/drivers/misc/hdpuftrs/hdpu_cpustate.c @@ -194,6 +194,11 @@ static int hdpu_cpustate_probe(struct platform_device *pdev) int ret; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + printk(KERN_ERR "sky_cpustate: " + "Invalid memory resource.\n"); + return -EINVAL; + } cpustate.set_addr = (unsigned long *)res->start; cpustate.clr_addr = (unsigned long *)res->end - 1; diff --git a/drivers/misc/hdpuftrs/hdpu_nexus.c b/drivers/misc/hdpuftrs/hdpu_nexus.c index fda9998f45c..01bc9179603 100644 --- a/drivers/misc/hdpuftrs/hdpu_nexus.c +++ b/drivers/misc/hdpuftrs/hdpu_nexus.c @@ -62,6 +62,11 @@ static int hdpu_nexus_probe(struct platform_device *pdev) int *nexus_id_addr; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + printk(KERN_ERR "sky_nexus: " + "Invalid memory resource.\n"); + return -EINVAL; + } nexus_id_addr = ioremap(res->start, (unsigned long)(res->end - res->start)); if (nexus_id_addr) { @@ -69,7 +74,7 @@ static int hdpu_nexus_probe(struct platform_device *pdev) chassis_id = *nexus_id_addr & 0xff; iounmap(nexus_id_addr); } else { - printk(KERN_ERR "Could not map slot id\n"); + printk(KERN_ERR "sky_nexus: Could not map slot id\n"); } hdpu_slot_id = create_proc_entry("sky_slot_id", 0666, &proc_root); -- cgit v1.2.3-70-g09d2 From 5f725fe92cc2e75892b237e863d5f695fb634bb2 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Tue, 2 Oct 2007 13:30:07 -0700 Subject: [POWERPC] Sky Cpu and Nexus: check for create_proc_entry ret code Adds checking of create_proc_entry call to prevent possible NULL pointer usage. Signed-off-by: Cyrill Gorcunov Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: Kumar Gala Cc: Brian Waite Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- drivers/misc/hdpuftrs/hdpu_nexus.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/hdpuftrs/hdpu_nexus.c b/drivers/misc/hdpuftrs/hdpu_nexus.c index 01bc9179603..cc818532c7e 100644 --- a/drivers/misc/hdpuftrs/hdpu_nexus.c +++ b/drivers/misc/hdpuftrs/hdpu_nexus.c @@ -78,10 +78,20 @@ static int hdpu_nexus_probe(struct platform_device *pdev) } hdpu_slot_id = create_proc_entry("sky_slot_id", 0666, &proc_root); - hdpu_slot_id->read_proc = hdpu_slot_id_read; + if (!hdpu_slot_id) { + printk(KERN_WARNING "sky_nexus: " + "Unable to create proc dir entry: sky_slot_id\n"); + } else { + hdpu_slot_id->read_proc = hdpu_slot_id_read; + } hdpu_chassis_id = create_proc_entry("sky_chassis_id", 0666, &proc_root); - hdpu_chassis_id->read_proc = hdpu_chassis_id_read; + if (!hdpu_chassis_id) { + printk(KERN_WARNING "sky_nexus: " + "Unable to create proc dir entry: sky_chassis_id\n"); + } else { + hdpu_chassis_id->read_proc = hdpu_chassis_id_read; + } return 0; } -- cgit v1.2.3-70-g09d2 From 8b70da1a094fb781d49a811fd2368907adc92b8d Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Tue, 2 Oct 2007 13:30:08 -0700 Subject: [POWERPC] Sky Cpu: use C99 style for struct init This changes structure item init format to C99, and removes useless structure items init. Signed-off-by: Cyrill Gorcunov Cc: Benjamin Herrenschmidt Cc: Kumar Gala Cc: Brian Waite Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- drivers/misc/hdpuftrs/hdpu_cpustate.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/hdpuftrs/hdpu_cpustate.c b/drivers/misc/hdpuftrs/hdpu_cpustate.c index b16742c7c69..32f65a3e07c 100644 --- a/drivers/misc/hdpuftrs/hdpu_cpustate.c +++ b/drivers/misc/hdpuftrs/hdpu_cpustate.c @@ -170,21 +170,18 @@ static struct platform_driver hdpu_cpustate_driver = { * The various file operations we support. */ static const struct file_operations cpustate_fops = { - owner: THIS_MODULE, - open: cpustate_open, - release: cpustate_release, - read: cpustate_read, - write: cpustate_write, - fasync: NULL, - poll: NULL, - ioctl: NULL, - llseek: no_llseek, + .owner = THIS_MODULE, + .open = cpustate_open, + .release = cpustate_release, + .read = cpustate_read, + .write = cpustate_write, + .llseek = no_llseek, }; static struct miscdevice cpustate_dev = { - MISC_DYNAMIC_MINOR, - "sky_cpustate", - &cpustate_fops, + .minor = MISC_DYNAMIC_MINOR, + .name = "sky_cpustate", + .fops = &cpustate_fops, }; static int hdpu_cpustate_probe(struct platform_device *pdev) -- cgit v1.2.3-70-g09d2 From 3049ea7e04408abf35dc295014cb6f1eabcf9b8c Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Tue, 2 Oct 2007 13:30:09 -0700 Subject: [POWERPC] Sky Cpu and Nexus: use seq_file/single_open on proc interface This patch changes proc interface to be used with single_file/seq_open calls. Signed-off-by: Cyrill Gorcunov Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- drivers/misc/hdpuftrs/hdpu_cpustate.c | 66 +++++++++++++++++++---------------- drivers/misc/hdpuftrs/hdpu_nexus.c | 52 ++++++++++++++++++++------- 2 files changed, 74 insertions(+), 44 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/hdpuftrs/hdpu_cpustate.c b/drivers/misc/hdpuftrs/hdpu_cpustate.c index 32f65a3e07c..aa8ce7abe92 100644 --- a/drivers/misc/hdpuftrs/hdpu_cpustate.c +++ b/drivers/misc/hdpuftrs/hdpu_cpustate.c @@ -19,9 +19,10 @@ #include #include #include +#include #include #include -#include +#include #include #define SKY_CPUSTATE_VERSION "1.1" @@ -29,7 +30,30 @@ static int hdpu_cpustate_probe(struct platform_device *pdev); static int hdpu_cpustate_remove(struct platform_device *pdev); -struct cpustate_t cpustate; +static unsigned char cpustate_get_state(void); +static int cpustate_proc_open(struct inode *inode, struct file *file); +static int cpustate_proc_read(struct seq_file *seq, void *offset); + +static struct cpustate_t cpustate; + +static const struct file_operations proc_cpustate = { + .open = cpustate_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +static int cpustate_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, cpustate_proc_read, NULL); +} + +static int cpustate_proc_read(struct seq_file *seq, void *offset) +{ + seq_printf(seq, "CPU State: %04x\n", cpustate_get_state()); + return 0; +} static int cpustate_get_ref(int excl) { @@ -67,13 +91,13 @@ static int cpustate_free_ref(void) return 0; } -unsigned char cpustate_get_state(void) +static unsigned char cpustate_get_state(void) { return cpustate.cached_val; } -void cpustate_set_state(unsigned char new_state) +static void cpustate_set_state(unsigned char new_state) { unsigned int state = (new_state << 21); @@ -135,29 +159,6 @@ static int cpustate_release(struct inode *inode, struct file *file) return cpustate_free_ref(); } -/* - * Info exported via "/proc/sky_cpustate". - */ -static int cpustate_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - char *p = page; - int len = 0; - - p += sprintf(p, "CPU State: %04x\n", cpustate_get_state()); - len = p - page; - - if (len <= off + count) - *eof = 1; - *start = page + off; - len -= off; - if (len > count) - len = count; - if (len < 0) - len = 0; - return len; -} - static struct platform_driver hdpu_cpustate_driver = { .probe = hdpu_cpustate_probe, .remove = hdpu_cpustate_remove, @@ -208,11 +209,14 @@ static int hdpu_cpustate_probe(struct platform_device *pdev) return ret; } - proc_de = create_proc_read_entry("sky_cpustate", 0, 0, - cpustate_read_proc, NULL); - if (proc_de == NULL) + proc_de = create_proc_entry("sky_cpustate", 0666, &proc_root); + if (!proc_de) { printk(KERN_WARNING "sky_cpustate: " - "Unable to create proc dir entry\n"); + "Unable to create proc entry\n"); + } else { + proc_de->proc_fops = &proc_cpustate; + proc_de->owner = THIS_MODULE; + } printk(KERN_INFO "Sky CPU State Driver v" SKY_CPUSTATE_VERSION "\n"); return 0; diff --git a/drivers/misc/hdpuftrs/hdpu_nexus.c b/drivers/misc/hdpuftrs/hdpu_nexus.c index cc818532c7e..2887b214798 100644 --- a/drivers/misc/hdpuftrs/hdpu_nexus.c +++ b/drivers/misc/hdpuftrs/hdpu_nexus.c @@ -18,18 +18,38 @@ #include #include #include - #include +#include #include static int hdpu_nexus_probe(struct platform_device *pdev); static int hdpu_nexus_remove(struct platform_device *pdev); +static int hdpu_slot_id_open(struct inode *inode, struct file *file); +static int hdpu_slot_id_read(struct seq_file *seq, void *offset); +static int hdpu_chassis_id_open(struct inode *inode, struct file *file); +static int hdpu_chassis_id_read(struct seq_file *seq, void *offset); static struct proc_dir_entry *hdpu_slot_id; static struct proc_dir_entry *hdpu_chassis_id; static int slot_id = -1; static int chassis_id = -1; +static const struct file_operations proc_slot_id = { + .open = hdpu_slot_id_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +static const struct file_operations proc_chassis_id = { + .open = hdpu_chassis_id_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + static struct platform_driver hdpu_nexus_driver = { .probe = hdpu_nexus_probe, .remove = hdpu_nexus_remove, @@ -38,22 +58,26 @@ static struct platform_driver hdpu_nexus_driver = { }, }; -int hdpu_slot_id_read(char *buffer, char **buffer_location, off_t offset, - int buffer_length, int *zero, void *ptr) +static int hdpu_slot_id_open(struct inode *inode, struct file *file) { - if (offset > 0) - return 0; + return single_open(file, hdpu_slot_id_read, NULL); +} - return sprintf(buffer, "%d\n", slot_id); +static int hdpu_slot_id_read(struct seq_file *seq, void *offset) +{ + seq_printf(seq, "%d\n", slot_id); + return 0; } -int hdpu_chassis_id_read(char *buffer, char **buffer_location, off_t offset, - int buffer_length, int *zero, void *ptr) +static int hdpu_chassis_id_open(struct inode *inode, struct file *file) { - if (offset > 0) - return 0; + return single_open(file, hdpu_chassis_id_read, NULL); +} - return sprintf(buffer, "%d\n", chassis_id); +static int hdpu_chassis_id_read(struct seq_file *seq, void *offset) +{ + seq_printf(seq, "%d\n", chassis_id); + return 0; } static int hdpu_nexus_probe(struct platform_device *pdev) @@ -82,7 +106,8 @@ static int hdpu_nexus_probe(struct platform_device *pdev) printk(KERN_WARNING "sky_nexus: " "Unable to create proc dir entry: sky_slot_id\n"); } else { - hdpu_slot_id->read_proc = hdpu_slot_id_read; + hdpu_slot_id->proc_fops = &proc_slot_id; + hdpu_slot_id->owner = THIS_MODULE; } hdpu_chassis_id = create_proc_entry("sky_chassis_id", 0666, &proc_root); @@ -90,7 +115,8 @@ static int hdpu_nexus_probe(struct platform_device *pdev) printk(KERN_WARNING "sky_nexus: " "Unable to create proc dir entry: sky_chassis_id\n"); } else { - hdpu_chassis_id->read_proc = hdpu_chassis_id_read; + hdpu_chassis_id->proc_fops = &proc_chassis_id; + hdpu_chassis_id->owner = THIS_MODULE; } return 0; -- cgit v1.2.3-70-g09d2 From a15da8eff3627b8368db7f5dd260e5643213d918 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 2 Oct 2007 12:15:39 +1000 Subject: [POWERPC] Uartlite: Fix reg io to access documented register size The Uartlite data sheet defines the registers as 32 bit wide. This patch changes the register access to use 32 bit transfers and eliminates the magic +3 offset which is currently required to make the device work. Signed-off-by: Grant Likely Acked-by: John Williams Signed-off-by: Josh Boyer --- arch/ppc/syslib/virtex_devices.c | 2 +- drivers/serial/uartlite.c | 32 ++++++++++++++++---------------- 2 files changed, 17 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/arch/ppc/syslib/virtex_devices.c b/arch/ppc/syslib/virtex_devices.c index ace4ec08de5..270ad3acfb5 100644 --- a/arch/ppc/syslib/virtex_devices.c +++ b/arch/ppc/syslib/virtex_devices.c @@ -28,7 +28,7 @@ .num_resources = 2, \ .resource = (struct resource[]) { \ { \ - .start = XPAR_UARTLITE_##num##_BASEADDR + 3, \ + .start = XPAR_UARTLITE_##num##_BASEADDR, \ .end = XPAR_UARTLITE_##num##_HIGHADDR, \ .flags = IORESOURCE_MEM, \ }, \ diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c index f5051cf1a0c..59b674aa2c0 100644 --- a/drivers/serial/uartlite.c +++ b/drivers/serial/uartlite.c @@ -61,7 +61,7 @@ static int ulite_receive(struct uart_port *port, int stat) /* stats */ if (stat & ULITE_STATUS_RXVALID) { port->icount.rx++; - ch = readb(port->membase + ULITE_RX); + ch = in_be32((void*)port->membase + ULITE_RX); if (stat & ULITE_STATUS_PARITY) port->icount.parity++; @@ -106,7 +106,7 @@ static int ulite_transmit(struct uart_port *port, int stat) return 0; if (port->x_char) { - writeb(port->x_char, port->membase + ULITE_TX); + out_be32((void*)port->membase + ULITE_TX, port->x_char); port->x_char = 0; port->icount.tx++; return 1; @@ -115,7 +115,7 @@ static int ulite_transmit(struct uart_port *port, int stat) if (uart_circ_empty(xmit) || uart_tx_stopped(port)) return 0; - writeb(xmit->buf[xmit->tail], port->membase + ULITE_TX); + out_be32((void*)port->membase + ULITE_TX, xmit->buf[xmit->tail]); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1); port->icount.tx++; @@ -132,7 +132,7 @@ static irqreturn_t ulite_isr(int irq, void *dev_id) int busy; do { - int stat = readb(port->membase + ULITE_STATUS); + int stat = in_be32((void*)port->membase + ULITE_STATUS); busy = ulite_receive(port, stat); busy |= ulite_transmit(port, stat); } while (busy); @@ -148,7 +148,7 @@ static unsigned int ulite_tx_empty(struct uart_port *port) unsigned int ret; spin_lock_irqsave(&port->lock, flags); - ret = readb(port->membase + ULITE_STATUS); + ret = in_be32((void*)port->membase + ULITE_STATUS); spin_unlock_irqrestore(&port->lock, flags); return ret & ULITE_STATUS_TXEMPTY ? TIOCSER_TEMT : 0; @@ -171,7 +171,7 @@ static void ulite_stop_tx(struct uart_port *port) static void ulite_start_tx(struct uart_port *port) { - ulite_transmit(port, readb(port->membase + ULITE_STATUS)); + ulite_transmit(port, in_be32((void*)port->membase + ULITE_STATUS)); } static void ulite_stop_rx(struct uart_port *port) @@ -200,17 +200,17 @@ static int ulite_startup(struct uart_port *port) if (ret) return ret; - writeb(ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX, - port->membase + ULITE_CONTROL); - writeb(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL); + out_be32((void*)port->membase + ULITE_CONTROL, + ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX); + out_be32((void*)port->membase + ULITE_CONTROL, ULITE_CONTROL_IE); return 0; } static void ulite_shutdown(struct uart_port *port) { - writeb(0, port->membase + ULITE_CONTROL); - readb(port->membase + ULITE_CONTROL); /* dummy */ + out_be32((void*)port->membase + ULITE_CONTROL, 0); + in_be32((void*)port->membase + ULITE_CONTROL); /* dummy */ free_irq(port->irq, port); } @@ -314,7 +314,7 @@ static void ulite_console_wait_tx(struct uart_port *port) /* wait up to 10ms for the character(s) to be sent */ for (i = 0; i < 10000; i++) { - if (readb(port->membase + ULITE_STATUS) & ULITE_STATUS_TXEMPTY) + if (in_be32((void*)port->membase + ULITE_STATUS) & ULITE_STATUS_TXEMPTY) break; udelay(1); } @@ -323,7 +323,7 @@ static void ulite_console_wait_tx(struct uart_port *port) static void ulite_console_putchar(struct uart_port *port, int ch) { ulite_console_wait_tx(port); - writeb(ch, port->membase + ULITE_TX); + out_be32((void*)port->membase + ULITE_TX, ch); } static void ulite_console_write(struct console *co, const char *s, @@ -340,8 +340,8 @@ static void ulite_console_write(struct console *co, const char *s, spin_lock_irqsave(&port->lock, flags); /* save and disable interrupt */ - ier = readb(port->membase + ULITE_STATUS) & ULITE_STATUS_IE; - writeb(0, port->membase + ULITE_CONTROL); + ier = in_be32((void*)port->membase + ULITE_STATUS) & ULITE_STATUS_IE; + out_be32((void*)port->membase + ULITE_CONTROL, 0); uart_console_write(port, s, count, ulite_console_putchar); @@ -349,7 +349,7 @@ static void ulite_console_write(struct console *co, const char *s, /* restore interrupt state */ if (ier) - writeb(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL); + out_be32((void*)port->membase + ULITE_CONTROL, ULITE_CONTROL_IE); if (locked) spin_unlock_irqrestore(&port->lock, flags); -- cgit v1.2.3-70-g09d2 From 483c79db95b56a9650bd6f0638e7366eb20ffc01 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 2 Oct 2007 12:15:44 +1000 Subject: [POWERPC] Uartlite: change name of ports to ulite_ports Changed to match naming convention used in the rest of the module Signed-off-by: Grant Likely Signed-off-by: Josh Boyer --- drivers/serial/uartlite.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c index 59b674aa2c0..ae05a67d9db 100644 --- a/drivers/serial/uartlite.c +++ b/drivers/serial/uartlite.c @@ -46,7 +46,7 @@ #define ULITE_CONTROL_IE 0x10 -static struct uart_port ports[ULITE_NR_UARTS]; +static struct uart_port ulite_ports[ULITE_NR_UARTS]; static int ulite_receive(struct uart_port *port, int stat) { @@ -329,7 +329,7 @@ static void ulite_console_putchar(struct uart_port *port, int ch) static void ulite_console_write(struct console *co, const char *s, unsigned int count) { - struct uart_port *port = &ports[co->index]; + struct uart_port *port = &ulite_ports[co->index]; unsigned long flags; unsigned int ier; int locked = 1; @@ -366,7 +366,7 @@ static int __init ulite_console_setup(struct console *co, char *options) if (co->index < 0 || co->index >= ULITE_NR_UARTS) return -EINVAL; - port = &ports[co->index]; + port = &ulite_ports[co->index]; /* not initialized yet? */ if (!port->membase) @@ -420,7 +420,7 @@ static int __devinit ulite_probe(struct platform_device *pdev) if (pdev->id < 0 || pdev->id >= ULITE_NR_UARTS) return -EINVAL; - if (ports[pdev->id].membase) + if (ulite_ports[pdev->id].membase) return -EBUSY; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -431,7 +431,7 @@ static int __devinit ulite_probe(struct platform_device *pdev) if (!res2) return -ENODEV; - port = &ports[pdev->id]; + port = &ulite_ports[pdev->id]; port->fifosize = 16; port->regshift = 2; -- cgit v1.2.3-70-g09d2 From 00775828e66124b4af54fafc393e5e89248802c9 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 2 Oct 2007 12:15:49 +1000 Subject: [POWERPC] Uartlite: Add macro for uartlite device name Changed to make the following OF_platform bus binding patch a wee bit cleaner Signed-off-by: Grant Likely Signed-off-by: Josh Boyer --- drivers/serial/uartlite.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c index ae05a67d9db..10e0da97811 100644 --- a/drivers/serial/uartlite.c +++ b/drivers/serial/uartlite.c @@ -18,6 +18,7 @@ #include #include +#define ULITE_NAME "ttyUL" #define ULITE_MAJOR 204 #define ULITE_MINOR 187 #define ULITE_NR_UARTS 4 @@ -381,7 +382,7 @@ static int __init ulite_console_setup(struct console *co, char *options) static struct uart_driver ulite_uart_driver; static struct console ulite_console = { - .name = "ttyUL", + .name = ULITE_NAME, .write = ulite_console_write, .device = uart_console_device, .setup = ulite_console_setup, @@ -403,7 +404,7 @@ console_initcall(ulite_console_init); static struct uart_driver ulite_uart_driver = { .owner = THIS_MODULE, .driver_name = "uartlite", - .dev_name = "ttyUL", + .dev_name = ULITE_NAME, .major = ULITE_MAJOR, .minor = ULITE_MINOR, .nr = ULITE_NR_UARTS, -- cgit v1.2.3-70-g09d2 From 8fa7b6100693e0b648ffd34564f6f41226502a19 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 2 Oct 2007 12:15:54 +1000 Subject: [POWERPC] Uartlite: Separate the bus binding from the driver proper Separate the bus binding code from the driver structure allocation code in preparation for adding the of_platform_bus bindings needed by arch/powerpc Signed-off-by: Grant Likely Signed-off-by: Josh Boyer --- drivers/serial/uartlite.c | 99 +++++++++++++++++++++++++++++++---------------- 1 file changed, 65 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c index 10e0da97811..c00a627ef89 100644 --- a/drivers/serial/uartlite.c +++ b/drivers/serial/uartlite.c @@ -413,59 +413,90 @@ static struct uart_driver ulite_uart_driver = { #endif }; -static int __devinit ulite_probe(struct platform_device *pdev) +static int __devinit ulite_assign(struct device *dev, int id, u32 base, int irq) { - struct resource *res, *res2; struct uart_port *port; + int rc; - if (pdev->id < 0 || pdev->id >= ULITE_NR_UARTS) + /* if id = -1; then scan for a free id and use that */ + if (id < 0) { + for (id = 0; id < ULITE_NR_UARTS; id++) + if (ulite_ports[id].mapbase == 0) + break; + } + if (id < 0 || id >= ULITE_NR_UARTS) { + dev_err(dev, "%s%i too large\n", ULITE_NAME, id); return -EINVAL; + } - if (ulite_ports[pdev->id].membase) + if (ulite_ports[id].mapbase) { + dev_err(dev, "cannot assign to %s%i; it is already in use\n", + ULITE_NAME, id); return -EBUSY; + } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; + port = &ulite_ports[id]; - res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res2) - return -ENODEV; + spin_lock_init(&port->lock); + port->fifosize = 16; + port->regshift = 2; + port->iotype = UPIO_MEM; + port->iobase = 1; /* mark port in use */ + port->mapbase = base; + port->membase = NULL; + port->ops = &ulite_ops; + port->irq = irq; + port->flags = UPF_BOOT_AUTOCONF; + port->dev = dev; + port->type = PORT_UNKNOWN; + port->line = id; + + dev_set_drvdata(dev, port); + + /* Register the port */ + rc = uart_add_one_port(&ulite_uart_driver, port); + if (rc) { + dev_err(dev, "uart_add_one_port() failed; err=%i\n", rc); + port->mapbase = 0; + dev_set_drvdata(dev, NULL); + return rc; + } - port = &ulite_ports[pdev->id]; + return 0; +} - port->fifosize = 16; - port->regshift = 2; - port->iotype = UPIO_MEM; - port->iobase = 1; /* mark port in use */ - port->mapbase = res->start; - port->membase = NULL; - port->ops = &ulite_ops; - port->irq = res2->start; - port->flags = UPF_BOOT_AUTOCONF; - port->dev = &pdev->dev; - port->type = PORT_UNKNOWN; - port->line = pdev->id; +static int __devinit ulite_release(struct device *dev) +{ + struct uart_port *port = dev_get_drvdata(dev); + int rc = 0; - uart_add_one_port(&ulite_uart_driver, port); - platform_set_drvdata(pdev, port); + if (port) { + rc = uart_remove_one_port(&ulite_uart_driver, port); + dev_set_drvdata(dev, NULL); + port->mapbase = 0; + } - return 0; + return rc; } -static int ulite_remove(struct platform_device *pdev) +static int __devinit ulite_probe(struct platform_device *pdev) { - struct uart_port *port = platform_get_drvdata(pdev); + struct resource *res, *res2; - platform_set_drvdata(pdev, NULL); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; - if (port) - uart_remove_one_port(&ulite_uart_driver, port); + res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res2) + return -ENODEV; - /* mark port as free */ - port->membase = NULL; + return ulite_assign(&pdev->dev, pdev->id, res->start, res2->start); +} - return 0; +static int ulite_remove(struct platform_device *pdev) +{ + return ulite_release(&pdev->dev); } static struct platform_driver ulite_platform_driver = { -- cgit v1.2.3-70-g09d2 From 435706b385d1f5422e44ee86b5dec0a2150eca02 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 2 Oct 2007 12:15:59 +1000 Subject: [POWERPC] Uartlite: Comment block tidy Tidy the comments to split the driver into logical section; the main driver, the console driver, the platform bus binding, and module initialization and teardown. Signed-off-by: Grant Likely Signed-off-by: Josh Boyer --- drivers/serial/uartlite.c | 43 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c index c00a627ef89..ed13b9fac1a 100644 --- a/drivers/serial/uartlite.c +++ b/drivers/serial/uartlite.c @@ -23,9 +23,13 @@ #define ULITE_MINOR 187 #define ULITE_NR_UARTS 4 -/* For register details see datasheet: - http://www.xilinx.com/bvdocs/ipcenter/data_sheet/opb_uartlite.pdf -*/ +/* --------------------------------------------------------------------- + * Register definitions + * + * For register details see datasheet: + * http://www.xilinx.com/bvdocs/ipcenter/data_sheet/opb_uartlite.pdf + */ + #define ULITE_RX 0x00 #define ULITE_TX 0x04 #define ULITE_STATUS 0x08 @@ -49,6 +53,10 @@ static struct uart_port ulite_ports[ULITE_NR_UARTS]; +/* --------------------------------------------------------------------- + * Core UART driver operations + */ + static int ulite_receive(struct uart_port *port, int stat) { struct tty_struct *tty = port->info->tty; @@ -308,6 +316,10 @@ static struct uart_ops ulite_ops = { .verify_port = ulite_verify_port }; +/* --------------------------------------------------------------------- + * Console driver operations + */ + #ifdef CONFIG_SERIAL_UARTLITE_CONSOLE static void ulite_console_wait_tx(struct uart_port *port) { @@ -413,6 +425,19 @@ static struct uart_driver ulite_uart_driver = { #endif }; +/* --------------------------------------------------------------------- + * Port assignment functions (mapping devices to uart_port structures) + */ + +/** ulite_assign: register a uartlite device with the driver + * + * @dev: pointer to device structure + * @id: requested id number. Pass -1 for automatic port assignment + * @base: base address of uartlite registers + * @irq: irq number for uartlite + * + * Returns: 0 on success, <0 otherwise + */ static int __devinit ulite_assign(struct device *dev, int id, u32 base, int irq) { struct uart_port *port; @@ -465,6 +490,10 @@ static int __devinit ulite_assign(struct device *dev, int id, u32 base, int irq) return 0; } +/** ulite_release: register a uartlite device with the driver + * + * @dev: pointer to device structure + */ static int __devinit ulite_release(struct device *dev) { struct uart_port *port = dev_get_drvdata(dev); @@ -479,6 +508,10 @@ static int __devinit ulite_release(struct device *dev) return rc; } +/* --------------------------------------------------------------------- + * Platform bus binding + */ + static int __devinit ulite_probe(struct platform_device *pdev) { struct resource *res, *res2; @@ -508,6 +541,10 @@ static struct platform_driver ulite_platform_driver = { }, }; +/* --------------------------------------------------------------------- + * Module setup/teardown + */ + int __init ulite_init(void) { int ret; -- cgit v1.2.3-70-g09d2 From 852e1ea748e83eba7fdb1cc198f271837b16137b Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 2 Oct 2007 12:16:04 +1000 Subject: [POWERPC] Uartlite: Add of-platform-bus binding Add of_platform bus binding so this driver can be used with arch/powerpc Signed-off-by: Grant Likely Signed-off-by: Josh Boyer --- drivers/serial/uartlite.c | 96 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 92 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c index ed13b9fac1a..0904c2a62fc 100644 --- a/drivers/serial/uartlite.c +++ b/drivers/serial/uartlite.c @@ -1,7 +1,8 @@ /* * uartlite.c: Serial driver for Xilinx uartlite serial controller * - * Peter Korsgaard + * Copyright (C) 2006 Peter Korsgaard + * Copyright (C) 2007 Secret Lab Technologies Ltd. * * This file is licensed under the terms of the GNU General Public License * version 2. This program is licensed "as is" without any warranty of any @@ -17,6 +18,10 @@ #include #include #include +#if defined(CONFIG_OF) +#include +#include +#endif #define ULITE_NAME "ttyUL" #define ULITE_MAJOR 204 @@ -382,8 +387,10 @@ static int __init ulite_console_setup(struct console *co, char *options) port = &ulite_ports[co->index]; /* not initialized yet? */ - if (!port->membase) + if (!port->membase) { + pr_debug("console on ttyUL%i not initialized\n", co->index); return -ENODEV; + } if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); @@ -541,6 +548,72 @@ static struct platform_driver ulite_platform_driver = { }, }; +/* --------------------------------------------------------------------- + * OF bus bindings + */ +#if defined(CONFIG_OF) +static int __devinit +ulite_of_probe(struct of_device *op, const struct of_device_id *match) +{ + struct resource res; + const unsigned int *id; + int irq, rc; + + dev_dbg(&op->dev, "%s(%p, %p)\n", __FUNCTION__, op, match); + + rc = of_address_to_resource(op->node, 0, &res); + if (rc) { + dev_err(&op->dev, "invalide address\n"); + return rc; + } + + irq = irq_of_parse_and_map(op->node, 0); + + id = of_get_property(op->node, "port-number", NULL); + + return ulite_assign(&op->dev, id ? *id : -1, res.start, irq); +} + +static int __devexit ulite_of_remove(struct of_device *op) +{ + return ulite_release(&op->dev); +} + +/* Match table for of_platform binding */ +static struct of_device_id __devinit ulite_of_match[] = { + { .type = "serial", .compatible = "xilinx,uartlite", }, + {}, +}; +MODULE_DEVICE_TABLE(of, ulite_of_match); + +static struct of_platform_driver ulite_of_driver = { + .owner = THIS_MODULE, + .name = "uartlite", + .match_table = ulite_of_match, + .probe = ulite_of_probe, + .remove = __devexit_p(ulite_of_remove), + .driver = { + .name = "uartlite", + }, +}; + +/* Registration helpers to keep the number of #ifdefs to a minimum */ +static inline int __init ulite_of_register(void) +{ + pr_debug("uartlite: calling of_register_platform_driver()\n"); + return of_register_platform_driver(&ulite_of_driver); +} + +static inline void __exit ulite_of_unregister(void) +{ + of_unregister_platform_driver(&ulite_of_driver); +} +#else /* CONFIG_OF */ +/* CONFIG_OF not enabled; do nothing helpers */ +static inline int __init ulite_of_register(void) { return 0; } +static inline void __exit ulite_of_unregister(void) { } +#endif /* CONFIG_OF */ + /* --------------------------------------------------------------------- * Module setup/teardown */ @@ -549,20 +622,35 @@ int __init ulite_init(void) { int ret; + pr_debug("uartlite: calling uart_register_driver()\n"); ret = uart_register_driver(&ulite_uart_driver); if (ret) - return ret; + goto err_uart; + + ret = ulite_of_register(); + if (ret) + goto err_of; + pr_debug("uartlite: calling platform_driver_register()\n"); ret = platform_driver_register(&ulite_platform_driver); if (ret) - uart_unregister_driver(&ulite_uart_driver); + goto err_plat; + + return 0; +err_plat: + ulite_of_unregister(); +err_of: + uart_unregister_driver(&ulite_uart_driver); +err_uart: + printk(KERN_ERR "registering uartlite driver failed: err=%i", ret); return ret; } void __exit ulite_exit(void) { platform_driver_unregister(&ulite_platform_driver); + ulite_of_unregister(); uart_unregister_driver(&ulite_uart_driver); } -- cgit v1.2.3-70-g09d2 From fb4e6e663b404ecdfac2e3f6e643d204488b28e9 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 2 Oct 2007 12:16:09 +1000 Subject: [POWERPC] Uartlite: Let the console be initialized earlier By configuring it earlier we get console output sooner which is helpful for debugging when the kernel crashes before the serial drivers are initialized. Signed-off-by: Grant Likely Signed-off-by: Josh Boyer --- drivers/serial/uartlite.c | 41 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c index 0904c2a62fc..2b8404c8116 100644 --- a/drivers/serial/uartlite.c +++ b/drivers/serial/uartlite.c @@ -373,6 +373,31 @@ static void ulite_console_write(struct console *co, const char *s, spin_unlock_irqrestore(&port->lock, flags); } +#if defined(CONFIG_OF) +static inline void __init ulite_console_of_find_device(int id) +{ + struct device_node *np; + struct resource res; + const unsigned int *of_id; + int rc; + + for_each_compatible_node(np, NULL, "xilinx,uartlite") { + of_id = of_get_property(np, "port-number", NULL); + if ((!of_id) || (*of_id != id)) + continue; + + rc = of_address_to_resource(np, 0, &res); + if (rc) + continue; + + ulite_ports[id].mapbase = res.start; + return; + } +} +#else /* CONFIG_OF */ +static inline void __init ulite_console_of_find_device(int id) { /* do nothing */ } +#endif /* CONFIG_OF */ + static int __init ulite_console_setup(struct console *co, char *options) { struct uart_port *port; @@ -386,10 +411,20 @@ static int __init ulite_console_setup(struct console *co, char *options) port = &ulite_ports[co->index]; + /* Check if it is an OF device */ + if (!port->mapbase) + ulite_console_of_find_device(co->index); + + /* Do we have a device now? */ + if (!port->mapbase) { + pr_debug("console on ttyUL%i not present\n", co->index); + return -ENODEV; + } + /* not initialized yet? */ if (!port->membase) { - pr_debug("console on ttyUL%i not initialized\n", co->index); - return -ENODEV; + if (ulite_request_port(port)) + return -ENODEV; } if (options) @@ -461,7 +496,7 @@ static int __devinit ulite_assign(struct device *dev, int id, u32 base, int irq) return -EINVAL; } - if (ulite_ports[id].mapbase) { + if ((ulite_ports[id].mapbase) && (ulite_ports[id].mapbase != base)) { dev_err(dev, "cannot assign to %s%i; it is already in use\n", ULITE_NAME, id); return -EBUSY; -- cgit v1.2.3-70-g09d2 From dc8afdc7ada82562231cbae867fe6dcdb7b677f5 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Mon, 1 Oct 2007 07:47:00 +1000 Subject: [POWERPC] XilinxFB: Move xilinxfb_platform_data definition to a shared header file XilnixFB can be used by more than just arch/ppc. Move the data structure definition into include/linux/xilinxfb.h so it can be used by microblaze and arch/powerpc Signed-off-by: Grant Likely Signed-off-by: Josh Boyer --- arch/ppc/syslib/virtex_devices.h | 8 +------- drivers/video/xilinxfb.c | 2 +- include/linux/xilinxfb.h | 23 +++++++++++++++++++++++ 3 files changed, 25 insertions(+), 8 deletions(-) create mode 100644 include/linux/xilinxfb.h (limited to 'drivers') diff --git a/arch/ppc/syslib/virtex_devices.h b/arch/ppc/syslib/virtex_devices.h index 9f38d92ae53..6ebd9b4b8f1 100644 --- a/arch/ppc/syslib/virtex_devices.h +++ b/arch/ppc/syslib/virtex_devices.h @@ -12,13 +12,7 @@ #define __ASM_VIRTEX_DEVICES_H__ #include - -/* ML300/403 reference design framebuffer driver platform data struct */ -struct xilinxfb_platform_data { - u32 rotate_screen; - u32 screen_height_mm; - u32 screen_width_mm; -}; +#include void __init virtex_early_serial_map(void); diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index 6ef9733a18d..4bc67ab56af 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c @@ -30,7 +30,7 @@ #include #include -#include +#include #define DRIVER_NAME "xilinxfb" #define DRIVER_DESCRIPTION "Xilinx TFT LCD frame buffer driver" diff --git a/include/linux/xilinxfb.h b/include/linux/xilinxfb.h new file mode 100644 index 00000000000..9ad984d22c3 --- /dev/null +++ b/include/linux/xilinxfb.h @@ -0,0 +1,23 @@ +/* + * Platform device data for Xilinx Framebuffer device + * + * Copyright 2007 Secret Lab Technologies Ltd. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#ifndef __XILINXFB_H__ +#define __XILINXFB_H__ + +#include + +/* ML300/403 reference design framebuffer driver platform data struct */ +struct xilinxfb_platform_data { + u32 rotate_screen; + u32 screen_height_mm; + u32 screen_width_mm; +}; + +#endif /* __XILINXFB_H__ */ -- cgit v1.2.3-70-g09d2 From e077b50c29a7e8be5812d1156934ea837b712ca6 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Wed, 3 Oct 2007 02:47:02 +1000 Subject: [POWERPC] Uartlite: Revert register io access changes Reverts commit a15da8eff3627b8368db7f5dd260e5643213d918 This driver is used by devices other than the xilinx opb-uartlite which depend on bytewise access to the registers. The change to 32 bit access does not work on these devices. Signed-off-by: Grant Likely Acked-by: Peter Korsgaard Signed-off-by: Josh Boyer --- arch/ppc/syslib/virtex_devices.c | 2 +- drivers/serial/uartlite.c | 36 ++++++++++++++++++------------------ 2 files changed, 19 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/arch/ppc/syslib/virtex_devices.c b/arch/ppc/syslib/virtex_devices.c index 270ad3acfb5..ace4ec08de5 100644 --- a/arch/ppc/syslib/virtex_devices.c +++ b/arch/ppc/syslib/virtex_devices.c @@ -28,7 +28,7 @@ .num_resources = 2, \ .resource = (struct resource[]) { \ { \ - .start = XPAR_UARTLITE_##num##_BASEADDR, \ + .start = XPAR_UARTLITE_##num##_BASEADDR + 3, \ .end = XPAR_UARTLITE_##num##_HIGHADDR, \ .flags = IORESOURCE_MEM, \ }, \ diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c index 2b8404c8116..dfef83f1496 100644 --- a/drivers/serial/uartlite.c +++ b/drivers/serial/uartlite.c @@ -75,7 +75,7 @@ static int ulite_receive(struct uart_port *port, int stat) /* stats */ if (stat & ULITE_STATUS_RXVALID) { port->icount.rx++; - ch = in_be32((void*)port->membase + ULITE_RX); + ch = readb(port->membase + ULITE_RX); if (stat & ULITE_STATUS_PARITY) port->icount.parity++; @@ -120,7 +120,7 @@ static int ulite_transmit(struct uart_port *port, int stat) return 0; if (port->x_char) { - out_be32((void*)port->membase + ULITE_TX, port->x_char); + writeb(port->x_char, port->membase + ULITE_TX); port->x_char = 0; port->icount.tx++; return 1; @@ -129,7 +129,7 @@ static int ulite_transmit(struct uart_port *port, int stat) if (uart_circ_empty(xmit) || uart_tx_stopped(port)) return 0; - out_be32((void*)port->membase + ULITE_TX, xmit->buf[xmit->tail]); + writeb(xmit->buf[xmit->tail], port->membase + ULITE_TX); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1); port->icount.tx++; @@ -146,7 +146,7 @@ static irqreturn_t ulite_isr(int irq, void *dev_id) int busy; do { - int stat = in_be32((void*)port->membase + ULITE_STATUS); + int stat = readb(port->membase + ULITE_STATUS); busy = ulite_receive(port, stat); busy |= ulite_transmit(port, stat); } while (busy); @@ -162,7 +162,7 @@ static unsigned int ulite_tx_empty(struct uart_port *port) unsigned int ret; spin_lock_irqsave(&port->lock, flags); - ret = in_be32((void*)port->membase + ULITE_STATUS); + ret = readb(port->membase + ULITE_STATUS); spin_unlock_irqrestore(&port->lock, flags); return ret & ULITE_STATUS_TXEMPTY ? TIOCSER_TEMT : 0; @@ -185,7 +185,7 @@ static void ulite_stop_tx(struct uart_port *port) static void ulite_start_tx(struct uart_port *port) { - ulite_transmit(port, in_be32((void*)port->membase + ULITE_STATUS)); + ulite_transmit(port, readb(port->membase + ULITE_STATUS)); } static void ulite_stop_rx(struct uart_port *port) @@ -214,17 +214,17 @@ static int ulite_startup(struct uart_port *port) if (ret) return ret; - out_be32((void*)port->membase + ULITE_CONTROL, - ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX); - out_be32((void*)port->membase + ULITE_CONTROL, ULITE_CONTROL_IE); + writeb(ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX, + port->membase + ULITE_CONTROL); + writeb(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL); return 0; } static void ulite_shutdown(struct uart_port *port) { - out_be32((void*)port->membase + ULITE_CONTROL, 0); - in_be32((void*)port->membase + ULITE_CONTROL); /* dummy */ + writeb(0, port->membase + ULITE_CONTROL); + readb(port->membase + ULITE_CONTROL); /* dummy */ free_irq(port->irq, port); } @@ -332,7 +332,7 @@ static void ulite_console_wait_tx(struct uart_port *port) /* wait up to 10ms for the character(s) to be sent */ for (i = 0; i < 10000; i++) { - if (in_be32((void*)port->membase + ULITE_STATUS) & ULITE_STATUS_TXEMPTY) + if (readb(port->membase + ULITE_STATUS) & ULITE_STATUS_TXEMPTY) break; udelay(1); } @@ -341,7 +341,7 @@ static void ulite_console_wait_tx(struct uart_port *port) static void ulite_console_putchar(struct uart_port *port, int ch) { ulite_console_wait_tx(port); - out_be32((void*)port->membase + ULITE_TX, ch); + writeb(ch, port->membase + ULITE_TX); } static void ulite_console_write(struct console *co, const char *s, @@ -358,8 +358,8 @@ static void ulite_console_write(struct console *co, const char *s, spin_lock_irqsave(&port->lock, flags); /* save and disable interrupt */ - ier = in_be32((void*)port->membase + ULITE_STATUS) & ULITE_STATUS_IE; - out_be32((void*)port->membase + ULITE_CONTROL, 0); + ier = readb(port->membase + ULITE_STATUS) & ULITE_STATUS_IE; + writeb(0, port->membase + ULITE_CONTROL); uart_console_write(port, s, count, ulite_console_putchar); @@ -367,7 +367,7 @@ static void ulite_console_write(struct console *co, const char *s, /* restore interrupt state */ if (ier) - out_be32((void*)port->membase + ULITE_CONTROL, ULITE_CONTROL_IE); + writeb(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL); if (locked) spin_unlock_irqrestore(&port->lock, flags); @@ -598,7 +598,7 @@ ulite_of_probe(struct of_device *op, const struct of_device_id *match) rc = of_address_to_resource(op->node, 0, &res); if (rc) { - dev_err(&op->dev, "invalide address\n"); + dev_err(&op->dev, "invalid address\n"); return rc; } @@ -606,7 +606,7 @@ ulite_of_probe(struct of_device *op, const struct of_device_id *match) id = of_get_property(op->node, "port-number", NULL); - return ulite_assign(&op->dev, id ? *id : -1, res.start, irq); + return ulite_assign(&op->dev, id ? *id : -1, res.start+3, irq); } static int __devexit ulite_of_remove(struct of_device *op) -- cgit v1.2.3-70-g09d2 From 5ae70296c85f96a9969891d9de3410ebdf210b71 Mon Sep 17 00:00:00 2001 From: Philip Langdale Date: Sat, 15 Sep 2007 12:54:08 -0700 Subject: mmc: Disabler for Ricoh MMC controller Thanks to Matt Domsch and Rezwanul Kabir at Dell, we know how to disable the MMC controller on the multi-function Ricoh R5C832. The MMC controller needs to be disabled or it will steal MMC cards from the SD controller where they would otherwise be supported by the Linux SDHCI driver. Signed-off-by: Philipl Langdale Signed-off-by: Pierre Ossman --- drivers/mmc/host/Kconfig | 17 +++++ drivers/mmc/host/Makefile | 1 + drivers/mmc/host/ricoh_mmc.c | 151 +++++++++++++++++++++++++++++++++++++++++++ include/linux/pci_ids.h | 2 + 4 files changed, 171 insertions(+) create mode 100644 drivers/mmc/host/ricoh_mmc.c (limited to 'drivers') diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 68fb052afd3..5fef6783c71 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -35,6 +35,23 @@ config MMC_SDHCI If unsure, say N. +config MMC_RICOH_MMC + tristate "Ricoh MMC Controller Disabler (EXPERIMENTAL)" + depends on PCI && EXPERIMENTAL && MMC_SDHCI + help + This selects the disabler for the Ricoh MMC Controller. This + proprietary controller is unnecessary because the SDHCI driver + supports MMC cards on the SD controller, but if it is not + disabled, it will steal the MMC cards away - rendering them + useless. It is safe to select this driver even if you don't + have a Ricoh based card reader. + + + To compile this driver as a module, choose M here: + the module will be called ricoh_mmc. + + If unsure, say Y. + config MMC_OMAP tristate "TI OMAP Multimedia Card Interface support" depends on ARCH_OMAP diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index 8dc82ce647b..3877c87e6da 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_MMC_ARMMMCI) += mmci.o obj-$(CONFIG_MMC_PXA) += pxamci.o obj-$(CONFIG_MMC_IMX) += imxmmc.o obj-$(CONFIG_MMC_SDHCI) += sdhci.o +obj-$(CONFIG_MMC_RICOH_MMC) += ricoh_mmc.o obj-$(CONFIG_MMC_WBSD) += wbsd.o obj-$(CONFIG_MMC_AU1X) += au1xmmc.o obj-$(CONFIG_MMC_OMAP) += omap.o diff --git a/drivers/mmc/host/ricoh_mmc.c b/drivers/mmc/host/ricoh_mmc.c new file mode 100644 index 00000000000..1e8704533bc --- /dev/null +++ b/drivers/mmc/host/ricoh_mmc.c @@ -0,0 +1,151 @@ +/* + * ricoh_mmc.c - Dummy driver to disable the Rioch MMC controller. + * + * Copyright (C) 2007 Philip Langdale, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + */ + +/* + * This is a conceptually ridiculous driver, but it is required by the way + * the Ricoh multi-function R5C832 works. This chip implements firewire + * and four different memory card controllers. Two of those controllers are + * an SDHCI controller and a proprietary MMC controller. The linux SDHCI + * driver supports MMC cards but the chip detects MMC cards in hardware + * and directs them to the MMC controller - so the SDHCI driver never sees + * them. To get around this, we must disable the useless MMC controller. + * At that point, the SDHCI controller will start seeing them. As a bonus, + * a detection event occurs immediately, even if the MMC card is already + * in the reader. + * + * The relevant registers live on the firewire function, so this is unavoidably + * ugly. Such is life. + */ + +#include + +#define DRIVER_NAME "ricoh-mmc" + +static const struct pci_device_id pci_ids[] __devinitdata = { + { + .vendor = PCI_VENDOR_ID_RICOH, + .device = PCI_DEVICE_ID_RICOH_R5C843, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { /* end: all zeroes */ }, +}; + +MODULE_DEVICE_TABLE(pci, pci_ids); + +static int __devinit ricoh_mmc_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + u8 rev; + + struct pci_dev *fw_dev = NULL; + + BUG_ON(pdev == NULL); + BUG_ON(ent == NULL); + + pci_read_config_byte(pdev, PCI_CLASS_REVISION, &rev); + + printk(KERN_INFO DRIVER_NAME + ": Ricoh MMC controller found at %s [%04x:%04x] (rev %x)\n", + pci_name(pdev), (int)pdev->vendor, (int)pdev->device, + (int)rev); + + while ((fw_dev = pci_get_device(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5C832, fw_dev))) { + if (PCI_SLOT(pdev->devfn) == PCI_SLOT(fw_dev->devfn) && + pdev->bus == fw_dev->bus) { + u8 write_enable; + u8 disable; + + pci_read_config_byte(fw_dev, 0xCB, &disable); + if (disable & 0x02) { + printk(KERN_INFO DRIVER_NAME + ": Controller already disabled. Nothing to do.\n"); + return -ENODEV; + } + + pci_read_config_byte(fw_dev, 0xCA, &write_enable); + pci_write_config_byte(fw_dev, 0xCA, 0x57); + pci_write_config_byte(fw_dev, 0xCB, disable | 0x02); + pci_write_config_byte(fw_dev, 0xCA, write_enable); + + pci_set_drvdata(pdev, fw_dev); + + printk(KERN_INFO DRIVER_NAME + ": Controller is now disabled.\n"); + + break; + } + } + + if (pci_get_drvdata(pdev) == NULL) { + printk(KERN_WARNING DRIVER_NAME + ": Main firewire function not found. Cannot disable controller.\n"); + return -ENODEV; + } + + return 0; +} + +static void __devexit ricoh_mmc_remove(struct pci_dev *pdev) +{ + u8 write_enable; + u8 disable; + struct pci_dev *fw_dev = NULL; + + fw_dev = pci_get_drvdata(pdev); + BUG_ON(fw_dev == NULL); + + pci_read_config_byte(fw_dev, 0xCA, &write_enable); + pci_read_config_byte(fw_dev, 0xCB, &disable); + pci_write_config_byte(fw_dev, 0xCA, 0x57); + pci_write_config_byte(fw_dev, 0xCB, disable & ~0x02); + pci_write_config_byte(fw_dev, 0xCA, write_enable); + + printk(KERN_INFO DRIVER_NAME + ": Controller is now re-enabled.\n"); + + pci_set_drvdata(pdev, NULL); +} + +static struct pci_driver ricoh_mmc_driver = { + .name = DRIVER_NAME, + .id_table = pci_ids, + .probe = ricoh_mmc_probe, + .remove = __devexit_p(ricoh_mmc_remove), +}; + +/*****************************************************************************\ + * * + * Driver init/exit * + * * +\*****************************************************************************/ + +static int __init ricoh_mmc_drv_init(void) +{ + printk(KERN_INFO DRIVER_NAME + ": Ricoh MMC Controller disabling driver\n"); + printk(KERN_INFO DRIVER_NAME ": Copyright(c) Philip Langdale\n"); + + return pci_register_driver(&ricoh_mmc_driver); +} + +static void __exit ricoh_mmc_drv_exit(void) +{ + pci_unregister_driver(&ricoh_mmc_driver); +} + +module_init(ricoh_mmc_drv_init); +module_exit(ricoh_mmc_drv_exit); + +MODULE_AUTHOR("Philip Langdale "); +MODULE_DESCRIPTION("Ricoh MMC Controller disabling driver"); +MODULE_LICENSE("GPL"); + diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 55f307ffbf9..c8636bb3e3a 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1471,6 +1471,8 @@ #define PCI_DEVICE_ID_RICOH_RL5C476 0x0476 #define PCI_DEVICE_ID_RICOH_RL5C478 0x0478 #define PCI_DEVICE_ID_RICOH_R5C822 0x0822 +#define PCI_DEVICE_ID_RICOH_R5C832 0x0832 +#define PCI_DEVICE_ID_RICOH_R5C843 0x0843 #define PCI_VENDOR_ID_DLINK 0x1186 #define PCI_DEVICE_ID_DLINK_DGE510T 0x4c00 -- cgit v1.2.3-70-g09d2 From 2df3b71b2746469b5b344cf7da5facecd4110cc9 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Sat, 29 Sep 2007 10:46:20 -0400 Subject: sdhci: fix a typo Signed-off-by: Nicolas Pitre Signed-off-by: Pierre Ossman --- drivers/mmc/host/sdhci.c | 2 +- drivers/mmc/host/sdhci.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 228ce42371d..317578d6853 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -132,7 +132,7 @@ static void sdhci_dumpregs(struct sdhci_host *host) readb(host->ioaddr + SDHCI_POWER_CONTROL), readb(host->ioaddr + SDHCI_BLOCK_GAP_CONTROL)); printk(KERN_DEBUG DRIVER_NAME ": Wake-up: 0x%08x | Clock: 0x%08x\n", - readb(host->ioaddr + SDHCI_WALK_UP_CONTROL), + readb(host->ioaddr + SDHCI_WAKE_UP_CONTROL), readw(host->ioaddr + SDHCI_CLOCK_CONTROL)); printk(KERN_DEBUG DRIVER_NAME ": Timeout: 0x%08x | Int stat: 0x%08x\n", readb(host->ioaddr + SDHCI_TIMEOUT_CONTROL), diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index e28987d6d2e..05195ea900f 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -81,7 +81,7 @@ #define SDHCI_BLOCK_GAP_CONTROL 0x2A -#define SDHCI_WALK_UP_CONTROL 0x2B +#define SDHCI_WAKE_UP_CONTROL 0x2B #define SDHCI_CLOCK_CONTROL 0x2C #define SDHCI_DIVIDER_SHIFT 8 -- cgit v1.2.3-70-g09d2 From 56e71efe44eb06ae1761f43cca70a5f3cc54c0fb Mon Sep 17 00:00:00 2001 From: Feng Tang Date: Sat, 29 Sep 2007 14:15:05 +0800 Subject: sdhci: remove DMA capability check from controller's PCI Class reg Many host controllers don't fully follow the PCI spec to claim whether they support DMA in PCI class register. Leave the driver to judge it from the Capability register, quirks and module parameter Signed-off-by: Feng Tang Signed-off-by: Pierre Ossman --- drivers/mmc/host/sdhci.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 317578d6853..866528c4ac1 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1299,13 +1299,18 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) host->flags |= SDHCI_USE_DMA; } else if (chip->quirks & SDHCI_QUIRK_FORCE_DMA) host->flags |= SDHCI_USE_DMA; - else if ((pdev->class & 0x0000FF) != PCI_SDHCI_IFDMA) - DBG("Controller doesn't have DMA interface\n"); else if (!(caps & SDHCI_CAN_DO_DMA)) DBG("Controller doesn't have DMA capability\n"); else host->flags |= SDHCI_USE_DMA; + if (((pdev->class & 0x0000FF) != PCI_SDHCI_IFDMA) && + (host->flags & SDHCI_USE_DMA)) { + printk(KERN_WARNING "%s: Will use DMA " + "mode even though HW doesn't fully " + "claim to support it.\n", host->slot_descr); + } + if (host->flags & SDHCI_USE_DMA) { if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) { printk(KERN_WARNING "%s: No suitable DMA available. " -- cgit v1.2.3-70-g09d2 From 7c168e3db7d900008ee304574057e0dc1a8505af Mon Sep 17 00:00:00 2001 From: Feng Tang Date: Sun, 30 Sep 2007 12:44:18 +0200 Subject: sdhci: add SDHCI_QUIRK_BROKEN_DMA quirk Some controllers like ENE712 can't work properly with DMA mode, add this quirk to force these kinds of HW work with PIO mode Signed-off-by: Feng Tang Signed-off-by: Pierre Ossman --- drivers/mmc/host/sdhci.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 866528c4ac1..2b4a86c55a9 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -35,6 +35,7 @@ static unsigned int debug_quirks = 0; #define SDHCI_QUIRK_NO_CARD_NO_RESET (1<<2) #define SDHCI_QUIRK_SINGLE_POWER_WRITE (1<<3) #define SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS (1<<4) +#define SDHCI_QUIRK_BROKEN_DMA (1<<5) static const struct pci_device_id pci_ids[] __devinitdata = { { @@ -68,7 +69,8 @@ static const struct pci_device_id pci_ids[] __devinitdata = { .device = PCI_DEVICE_ID_ENE_CB712_SD, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, - .driver_data = SDHCI_QUIRK_SINGLE_POWER_WRITE, + .driver_data = SDHCI_QUIRK_SINGLE_POWER_WRITE | + SDHCI_QUIRK_BROKEN_DMA, }, { @@ -76,7 +78,8 @@ static const struct pci_device_id pci_ids[] __devinitdata = { .device = PCI_DEVICE_ID_ENE_CB712_SD_2, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, - .driver_data = SDHCI_QUIRK_SINGLE_POWER_WRITE, + .driver_data = SDHCI_QUIRK_SINGLE_POWER_WRITE | + SDHCI_QUIRK_BROKEN_DMA, }, { @@ -1304,6 +1307,12 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) else host->flags |= SDHCI_USE_DMA; + if ((chip->quirks & SDHCI_QUIRK_BROKEN_DMA) && + (host->flags & SDHCI_USE_DMA)) { + DBG("Disabling DMA as it is marked broken"); + host->flags &= ~SDHCI_USE_DMA; + } + if (((pdev->class & 0x0000FF) != PCI_SDHCI_IFDMA) && (host->flags & SDHCI_USE_DMA)) { printk(KERN_WARNING "%s: Will use DMA " -- cgit v1.2.3-70-g09d2 From d6f8deecefc133cac044f6029bdb349a1cb8753a Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 30 Sep 2007 12:47:05 +0200 Subject: sdhci: remove old dma module params The forcedma and nodma module parameters can be replaced with the quirks parameter, so remove the redundancy. Signed-off-by: Pierre Ossman --- drivers/mmc/host/sdhci.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 2b4a86c55a9..b397121b947 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -25,8 +25,6 @@ #define DBG(f, x...) \ pr_debug(DRIVER_NAME " [%s()]: " f, __func__,## x) -static unsigned int debug_nodma = 0; -static unsigned int debug_forcedma = 0; static unsigned int debug_quirks = 0; #define SDHCI_QUIRK_CLOCK_BEFORE_RESET (1<<0) @@ -1295,12 +1293,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) caps = readl(host->ioaddr + SDHCI_CAPABILITIES); - if (debug_nodma) - DBG("DMA forced off\n"); - else if (debug_forcedma) { - DBG("DMA forced on\n"); - host->flags |= SDHCI_USE_DMA; - } else if (chip->quirks & SDHCI_QUIRK_FORCE_DMA) + if (chip->quirks & SDHCI_QUIRK_FORCE_DMA) host->flags |= SDHCI_USE_DMA; else if (!(caps & SDHCI_CAN_DO_DMA)) DBG("Controller doesn't have DMA capability\n"); @@ -1613,14 +1606,10 @@ static void __exit sdhci_drv_exit(void) module_init(sdhci_drv_init); module_exit(sdhci_drv_exit); -module_param(debug_nodma, uint, 0444); -module_param(debug_forcedma, uint, 0444); module_param(debug_quirks, uint, 0444); MODULE_AUTHOR("Pierre Ossman "); MODULE_DESCRIPTION("Secure Digital Host Controller Interface driver"); MODULE_LICENSE("GPL"); -MODULE_PARM_DESC(debug_nodma, "Forcefully disable DMA transfers. (default 0)"); -MODULE_PARM_DESC(debug_forcedma, "Forcefully enable DMA transfers. (default 0)"); MODULE_PARM_DESC(debug_quirks, "Force certain quirks."); -- cgit v1.2.3-70-g09d2 From 7ae870368d198affa249ed3382a8a288167ce885 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Tue, 17 Jul 2007 17:59:06 -0500 Subject: [POWERPC] cpm_uart: Be an of_platform device when CONFIG_PPC_CPM_NEW_BINDING is set. The existing OF glue code was crufty and broken. Rather than fix it, it has been removed, and the serial driver now talks to the device tree directly. The non-CONFIG_PPC_CPM_NEW_BINDING code can go away once CPM platforms are dropped from arch/ppc (which will hopefully be soon), and existing arch/powerpc boards that I wasn't able to test on for this patchset get converted (which should be even sooner). Signed-off-by: Scott Wood Signed-off-by: Kumar Gala --- drivers/serial/cpm_uart/cpm_uart.h | 6 +- drivers/serial/cpm_uart/cpm_uart_core.c | 241 +++++++++++++++++++++++++++++--- drivers/serial/cpm_uart/cpm_uart_cpm1.c | 16 ++- drivers/serial/cpm_uart/cpm_uart_cpm1.h | 2 + drivers/serial/cpm_uart/cpm_uart_cpm2.c | 18 ++- drivers/serial/cpm_uart/cpm_uart_cpm2.h | 2 + 6 files changed, 260 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/cpm_uart/cpm_uart.h b/drivers/serial/cpm_uart/cpm_uart.h index a8f894c7819..4e1987adc23 100644 --- a/drivers/serial/cpm_uart/cpm_uart.h +++ b/drivers/serial/cpm_uart/cpm_uart.h @@ -80,14 +80,18 @@ struct uart_cpm_port { int is_portb; /* wait on close if needed */ int wait_closing; + /* value to combine with opcode to form cpm command */ + u32 command; }; +#ifndef CONFIG_PPC_CPM_NEW_BINDING extern int cpm_uart_port_map[UART_NR]; +#endif extern int cpm_uart_nr; extern struct uart_cpm_port cpm_uart_ports[UART_NR]; /* these are located in their respective files */ -void cpm_line_cr_cmd(int line, int cmd); +void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd); int cpm_uart_init_portdesc(void); int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con); void cpm_uart_freebuf(struct uart_cpm_port *pinfo); diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c index cefde58dbad..8564ba2f3ec 100644 --- a/drivers/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/serial/cpm_uart/cpm_uart_core.c @@ -10,7 +10,7 @@ * Maintainer: Kumar Gala (galak@kernel.crashing.org) (CPM2) * Pantelis Antoniou (panto@intracom.gr) (CPM1) * - * Copyright (C) 2004 Freescale Semiconductor, Inc. + * Copyright (C) 2004, 2007 Freescale Semiconductor, Inc. * (C) 2004 Intracom, S.A. * (C) 2005-2006 MontaVista Software, Inc. * Vitaly Bordug @@ -47,6 +47,11 @@ #include #include #include +#include + +#ifdef CONFIG_PPC_CPM_NEW_BINDING +#include +#endif #if defined(CONFIG_SERIAL_CPM_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) #define SUPPORT_SYSRQ @@ -57,12 +62,6 @@ #include "cpm_uart.h" -/***********************************************************************/ - -/* Track which ports are configured as uarts */ -int cpm_uart_port_map[UART_NR]; -/* How many ports did we config as uarts */ -int cpm_uart_nr = 0; /**************************************************************/ @@ -73,6 +72,11 @@ static void cpm_uart_initbd(struct uart_cpm_port *pinfo); /**************************************************************/ +#ifndef CONFIG_PPC_CPM_NEW_BINDING +/* Track which ports are configured as uarts */ +int cpm_uart_port_map[UART_NR]; +/* How many ports did we config as uarts */ +int cpm_uart_nr; /* Place-holder for board-specific stuff */ struct platform_device* __attribute__ ((weak)) __init @@ -119,6 +123,7 @@ static int cpm_uart_id2nr(int id) /* not found or invalid argument */ return -1; } +#endif /* * Check, if transmit buffers are processed @@ -232,15 +237,14 @@ static void cpm_uart_enable_ms(struct uart_port *port) static void cpm_uart_break_ctl(struct uart_port *port, int break_state) { struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; - int line = pinfo - cpm_uart_ports; pr_debug("CPM uart[%d]:break ctrl, break_state: %d\n", port->line, break_state); if (break_state) - cpm_line_cr_cmd(line, CPM_CR_STOP_TX); + cpm_line_cr_cmd(pinfo, CPM_CR_STOP_TX); else - cpm_line_cr_cmd(line, CPM_CR_RESTART_TX); + cpm_line_cr_cmd(pinfo, CPM_CR_RESTART_TX); } /* @@ -407,7 +411,6 @@ static int cpm_uart_startup(struct uart_port *port) { int retval; struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; - int line = pinfo - cpm_uart_ports; pr_debug("CPM uart[%d]:startup\n", port->line); @@ -426,7 +429,7 @@ static int cpm_uart_startup(struct uart_port *port) } if (!(pinfo->flags & FLAG_CONSOLE)) - cpm_line_cr_cmd(line,CPM_CR_INIT_TRX); + cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX); return 0; } @@ -442,7 +445,6 @@ inline void cpm_uart_wait_until_send(struct uart_cpm_port *pinfo) static void cpm_uart_shutdown(struct uart_port *port) { struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; - int line = pinfo - cpm_uart_ports; pr_debug("CPM uart[%d]:shutdown\n", port->line); @@ -473,9 +475,9 @@ static void cpm_uart_shutdown(struct uart_port *port) /* Shut them really down and reinit buffer descriptors */ if (IS_SMC(pinfo)) - cpm_line_cr_cmd(line, CPM_CR_STOP_TX); + cpm_line_cr_cmd(pinfo, CPM_CR_STOP_TX); else - cpm_line_cr_cmd(line, CPM_CR_GRA_STOP_TX); + cpm_line_cr_cmd(pinfo, CPM_CR_GRA_STOP_TX); cpm_uart_initbd(pinfo); } @@ -595,7 +597,6 @@ static void cpm_uart_set_termios(struct uart_port *port, cpm_set_brg(pinfo->brg - 1, baud); spin_unlock_irqrestore(&port->lock, flags); - } static const char *cpm_uart_type(struct uart_port *port) @@ -742,7 +743,6 @@ static void cpm_uart_initbd(struct uart_cpm_port *pinfo) static void cpm_uart_init_scc(struct uart_cpm_port *pinfo) { - int line = pinfo - cpm_uart_ports; volatile scc_t *scp; volatile scc_uart_t *sup; @@ -783,7 +783,7 @@ static void cpm_uart_init_scc(struct uart_cpm_port *pinfo) /* Send the CPM an initialize command. */ - cpm_line_cr_cmd(line, CPM_CR_INIT_TRX); + cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX); /* Set UART mode, 8 bit, no parity, one stop. * Enable receive and transmit. @@ -803,7 +803,6 @@ static void cpm_uart_init_scc(struct uart_cpm_port *pinfo) static void cpm_uart_init_smc(struct uart_cpm_port *pinfo) { - int line = pinfo - cpm_uart_ports; volatile smc_t *sp; volatile smc_uart_t *up; @@ -840,7 +839,7 @@ static void cpm_uart_init_smc(struct uart_cpm_port *pinfo) up->smc_brkec = 0; up->smc_brkcr = 1; - cpm_line_cr_cmd(line, CPM_CR_INIT_TRX); + cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX); /* Set UART mode, 8 bit, no parity, one stop. * Enable receive and transmit. @@ -929,6 +928,85 @@ static struct uart_ops cpm_uart_pops = { .verify_port = cpm_uart_verify_port, }; +#ifdef CONFIG_PPC_CPM_NEW_BINDING +struct uart_cpm_port cpm_uart_ports[UART_NR]; + +int cpm_uart_init_port(struct device_node *np, struct uart_cpm_port *pinfo) +{ + const u32 *data; + void __iomem *mem, __iomem *pram; + int len; + int ret; + + data = of_get_property(np, "fsl,cpm-brg", &len); + if (!data || len != 4) { + printk(KERN_ERR "CPM UART %s has no/invalid " + "fsl,cpm-brg property.\n", np->name); + return -EINVAL; + } + pinfo->brg = *data; + + data = of_get_property(np, "fsl,cpm-command", &len); + if (!data || len != 4) { + printk(KERN_ERR "CPM UART %s has no/invalid " + "fsl,cpm-command property.\n", np->name); + return -EINVAL; + } + pinfo->command = *data; + + mem = of_iomap(np, 0); + if (!mem) + return -ENOMEM; + + pram = of_iomap(np, 1); + if (!pram) { + ret = -ENOMEM; + goto out_mem; + } + + if (of_device_is_compatible(np, "fsl,cpm1-scc-uart") || + of_device_is_compatible(np, "fsl,cpm2-scc-uart")) { + pinfo->sccp = mem; + pinfo->sccup = pram; + } else if (of_device_is_compatible(np, "fsl,cpm1-smc-uart") || + of_device_is_compatible(np, "fsl,cpm2-smc-uart")) { + pinfo->flags |= FLAG_SMC; + pinfo->smcp = mem; + pinfo->smcup = pram; + } else { + ret = -ENODEV; + goto out_pram; + } + + pinfo->tx_nrfifos = TX_NUM_FIFO; + pinfo->tx_fifosize = TX_BUF_SIZE; + pinfo->rx_nrfifos = RX_NUM_FIFO; + pinfo->rx_fifosize = RX_BUF_SIZE; + + pinfo->port.uartclk = ppc_proc_freq; + pinfo->port.mapbase = (unsigned long)mem; + pinfo->port.type = PORT_CPM; + pinfo->port.ops = &cpm_uart_pops, + pinfo->port.iotype = UPIO_MEM; + spin_lock_init(&pinfo->port.lock); + + pinfo->port.irq = of_irq_to_resource(np, 0, NULL); + if (pinfo->port.irq == NO_IRQ) { + ret = -EINVAL; + goto out_pram; + } + + return cpm_uart_request_port(&pinfo->port); + +out_pram: + iounmap(pram); +out_mem: + iounmap(mem); + return ret; +} + +#else + struct uart_cpm_port cpm_uart_ports[UART_NR] = { [UART_SMC1] = { .port = { @@ -1072,6 +1150,7 @@ int cpm_uart_drv_get_platform_data(struct platform_device *pdev, int is_con) return 0; } +#endif #ifdef CONFIG_SERIAL_CPM_CONSOLE /* @@ -1083,8 +1162,12 @@ int cpm_uart_drv_get_platform_data(struct platform_device *pdev, int is_con) static void cpm_uart_console_write(struct console *co, const char *s, u_int count) { +#ifdef CONFIG_PPC_CPM_NEW_BINDING + struct uart_cpm_port *pinfo = &cpm_uart_ports[co->index]; +#else struct uart_cpm_port *pinfo = &cpm_uart_ports[cpm_uart_port_map[co->index]]; +#endif unsigned int i; volatile cbd_t *bdp, *bdbase; volatile unsigned char *cp; @@ -1155,13 +1238,47 @@ static void cpm_uart_console_write(struct console *co, const char *s, static int __init cpm_uart_console_setup(struct console *co, char *options) { - struct uart_port *port; - struct uart_cpm_port *pinfo; int baud = 38400; int bits = 8; int parity = 'n'; int flow = 'n'; int ret; + struct uart_cpm_port *pinfo; + struct uart_port *port; + +#ifdef CONFIG_PPC_CPM_NEW_BINDING + struct device_node *np = NULL; + int i = 0; + + if (co->index >= UART_NR) { + printk(KERN_ERR "cpm_uart: console index %d too high\n", + co->index); + return -ENODEV; + } + + do { + np = of_find_node_by_type(np, "serial"); + if (!np) + return -ENODEV; + + if (!of_device_is_compatible(np, "fsl,cpm1-smc-uart") && + !of_device_is_compatible(np, "fsl,cpm1-scc-uart") && + !of_device_is_compatible(np, "fsl,cpm2-smc-uart") && + !of_device_is_compatible(np, "fsl,cpm2-scc-uart")) + i--; + } while (i++ != co->index); + + pinfo = &cpm_uart_ports[co->index]; + + pinfo->flags |= FLAG_CONSOLE; + port = &pinfo->port; + + ret = cpm_uart_init_port(np, pinfo); + of_node_put(np); + if (ret) + return ret; + +#else struct fs_uart_platform_info *pdata; struct platform_device* pdev = early_uart_get_pdev(co->index); @@ -1188,6 +1305,7 @@ static int __init cpm_uart_console_setup(struct console *co, char *options) } pinfo->flags |= FLAG_CONSOLE; +#endif if (options) { uart_parse_options(options, &baud, &parity, &bits, &flow); @@ -1196,6 +1314,10 @@ static int __init cpm_uart_console_setup(struct console *co, char *options) baud = 9600; } +#ifdef CONFIG_PPC_EARLY_DEBUG_CPM + udbg_putc = NULL; +#endif + if (IS_SMC(pinfo)) { pinfo->smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX); pinfo->smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); @@ -1252,7 +1374,81 @@ static struct uart_driver cpm_reg = { .major = SERIAL_CPM_MAJOR, .minor = SERIAL_CPM_MINOR, .cons = CPM_UART_CONSOLE, + .nr = UART_NR, +}; + +#ifdef CONFIG_PPC_CPM_NEW_BINDING +static int probe_index; + +static int __devinit cpm_uart_probe(struct of_device *ofdev, + const struct of_device_id *match) +{ + int index = probe_index++; + struct uart_cpm_port *pinfo = &cpm_uart_ports[index]; + int ret; + + pinfo->port.line = index; + + if (index >= UART_NR) + return -ENODEV; + + dev_set_drvdata(&ofdev->dev, pinfo); + + ret = cpm_uart_init_port(ofdev->node, pinfo); + if (ret) + return ret; + + return uart_add_one_port(&cpm_reg, &pinfo->port); +} + +static int __devexit cpm_uart_remove(struct of_device *ofdev) +{ + struct uart_cpm_port *pinfo = dev_get_drvdata(&ofdev->dev); + return uart_remove_one_port(&cpm_reg, &pinfo->port); +} + +static struct of_device_id cpm_uart_match[] = { + { + .compatible = "fsl,cpm1-smc-uart", + }, + { + .compatible = "fsl,cpm1-scc-uart", + }, + { + .compatible = "fsl,cpm2-smc-uart", + }, + { + .compatible = "fsl,cpm2-scc-uart", + }, + {} }; + +static struct of_platform_driver cpm_uart_driver = { + .name = "cpm_uart", + .match_table = cpm_uart_match, + .probe = cpm_uart_probe, + .remove = cpm_uart_remove, + }; + +static int __init cpm_uart_init(void) +{ + int ret = uart_register_driver(&cpm_reg); + if (ret) + return ret; + + ret = of_register_platform_driver(&cpm_uart_driver); + if (ret) + uart_unregister_driver(&cpm_reg); + + return ret; +} + +static void __exit cpm_uart_exit(void) +{ + of_unregister_platform_driver(&cpm_uart_driver); + uart_unregister_driver(&cpm_reg); +} +#else static int cpm_uart_drv_probe(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); @@ -1380,6 +1576,7 @@ static void __exit cpm_uart_exit(void) driver_unregister(&cpm_smc_uart_driver); uart_unregister_driver(&cpm_reg); } +#endif module_init(cpm_uart_init); module_exit(cpm_uart_exit); diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.c b/drivers/serial/cpm_uart/cpm_uart_cpm1.c index 8c6324ed020..4647f55e19f 100644 --- a/drivers/serial/cpm_uart/cpm_uart_cpm1.c +++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.c @@ -49,9 +49,20 @@ /**************************************************************/ -void cpm_line_cr_cmd(int line, int cmd) +#ifdef CONFIG_PPC_CPM_NEW_BINDING +void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd) +{ + u16 __iomem *cpcr = &cpmp->cp_cpcr; + + out_be16(cpcr, port->command | (cmd << 8) | CPM_CR_FLG); + while (in_be16(cpcr) & CPM_CR_FLG) + ; +} +#else +void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd) { ushort val; + int line = port - cpm_uart_ports; volatile cpm8xx_t *cp = cpmp; switch (line) { @@ -114,6 +125,7 @@ void scc4_lineif(struct uart_cpm_port *pinfo) /* XXX SCC4: insert port configuration here */ pinfo->brg = 4; } +#endif /* * Allocate DP-Ram and memory buffers. We need to allocate a transmit and @@ -184,6 +196,7 @@ void cpm_uart_freebuf(struct uart_cpm_port *pinfo) cpm_dpfree(pinfo->dp_addr); } +#ifndef CONFIG_PPC_CPM_NEW_BINDING /* Setup any dynamic params in the uart desc */ int cpm_uart_init_portdesc(void) { @@ -279,3 +292,4 @@ int cpm_uart_init_portdesc(void) #endif return 0; } +#endif diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.h b/drivers/serial/cpm_uart/cpm_uart_cpm1.h index 2a6477834c3..69f523a442e 100644 --- a/drivers/serial/cpm_uart/cpm_uart_cpm1.h +++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.h @@ -13,12 +13,14 @@ #include /* defines for IRQs */ +#ifndef CONFIG_PPC_CPM_NEW_BINDING #define SMC1_IRQ (CPM_IRQ_OFFSET + CPMVEC_SMC1) #define SMC2_IRQ (CPM_IRQ_OFFSET + CPMVEC_SMC2) #define SCC1_IRQ (CPM_IRQ_OFFSET + CPMVEC_SCC1) #define SCC2_IRQ (CPM_IRQ_OFFSET + CPMVEC_SCC2) #define SCC3_IRQ (CPM_IRQ_OFFSET + CPMVEC_SCC3) #define SCC4_IRQ (CPM_IRQ_OFFSET + CPMVEC_SCC4) +#endif static inline void cpm_set_brg(int brg, int baud) { diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/serial/cpm_uart/cpm_uart_cpm2.c index 7b61d805ebe..7ebce263ad4 100644 --- a/drivers/serial/cpm_uart/cpm_uart_cpm2.c +++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.c @@ -49,9 +49,22 @@ /**************************************************************/ -void cpm_line_cr_cmd(int line, int cmd) +#ifdef CONFIG_PPC_CPM_NEW_BINDING +void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd) +{ + cpm_cpm2_t __iomem *cp = cpm2_map(im_cpm); + + out_be32(&cp->cp_cpcr, port->command | cmd | CPM_CR_FLG); + while (in_be32(&cp->cp_cpcr) & CPM_CR_FLG) + ; + + cpm2_unmap(cp); +} +#else +void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd) { ulong val; + int line = port - cpm_uart_ports; volatile cpm_cpm2_t *cp = cpm2_map(im_cpm); @@ -211,6 +224,7 @@ void scc4_lineif(struct uart_cpm_port *pinfo) cpm2_unmap(cpmux); cpm2_unmap(io); } +#endif /* * Allocate DP-Ram and memory buffers. We need to allocate a transmit and @@ -281,6 +295,7 @@ void cpm_uart_freebuf(struct uart_cpm_port *pinfo) cpm_dpfree(pinfo->dp_addr); } +#ifndef CONFIG_PPC_CPM_NEW_BINDING /* Setup any dynamic params in the uart desc */ int cpm_uart_init_portdesc(void) { @@ -386,3 +401,4 @@ int cpm_uart_init_portdesc(void) return 0; } +#endif diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.h b/drivers/serial/cpm_uart/cpm_uart_cpm2.h index 1b3219f56c8..e7717ece083 100644 --- a/drivers/serial/cpm_uart/cpm_uart_cpm2.h +++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.h @@ -13,12 +13,14 @@ #include /* defines for IRQs */ +#ifndef CONFIG_PPC_CPM_NEW_BINDING #define SMC1_IRQ SIU_INT_SMC1 #define SMC2_IRQ SIU_INT_SMC2 #define SCC1_IRQ SIU_INT_SCC1 #define SCC2_IRQ SIU_INT_SCC2 #define SCC3_IRQ SIU_INT_SCC3 #define SCC4_IRQ SIU_INT_SCC4 +#endif static inline void cpm_set_brg(int brg, int baud) { -- cgit v1.2.3-70-g09d2 From c1dcfd9d199043ff0e8805484a736ad36d9dd04a Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Tue, 24 Jul 2007 15:53:07 -0500 Subject: [POWERPC] cpm_uart: sparse fixes Mostly a bunch of direct access to in/out conversions, plus a few cast removals, __iomem annotations, and miscellaneous cleanup. Signed-off-by: Scott Wood Signed-off-by: Kumar Gala --- drivers/serial/cpm_uart/cpm_uart.h | 42 ++--- drivers/serial/cpm_uart/cpm_uart_core.c | 299 ++++++++++++++++---------------- drivers/serial/cpm_uart/cpm_uart_cpm1.c | 2 +- drivers/serial/cpm_uart/cpm_uart_cpm1.h | 14 +- drivers/serial/cpm_uart/cpm_uart_cpm2.c | 4 +- drivers/serial/cpm_uart/cpm_uart_cpm2.h | 14 +- 6 files changed, 192 insertions(+), 183 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/cpm_uart/cpm_uart.h b/drivers/serial/cpm_uart/cpm_uart.h index 4e1987adc23..32b9737759c 100644 --- a/drivers/serial/cpm_uart/cpm_uart.h +++ b/drivers/serial/cpm_uart/cpm_uart.h @@ -56,21 +56,21 @@ struct uart_cpm_port { u16 rx_fifosize; u16 tx_nrfifos; u16 tx_fifosize; - smc_t *smcp; - smc_uart_t *smcup; - scc_t *sccp; - scc_uart_t *sccup; - volatile cbd_t *rx_bd_base; - volatile cbd_t *rx_cur; - volatile cbd_t *tx_bd_base; - volatile cbd_t *tx_cur; + smc_t __iomem *smcp; + smc_uart_t __iomem *smcup; + scc_t __iomem *sccp; + scc_uart_t __iomem *sccup; + cbd_t __iomem *rx_bd_base; + cbd_t __iomem *rx_cur; + cbd_t __iomem *tx_bd_base; + cbd_t __iomem *tx_cur; unsigned char *tx_buf; unsigned char *rx_buf; u32 flags; void (*set_lineif)(struct uart_cpm_port *); u8 brg; uint dp_addr; - void *mem_addr; + void *mem_addr; dma_addr_t dma_addr; u32 mem_size; /* helpers */ @@ -106,34 +106,36 @@ void scc4_lineif(struct uart_cpm_port *pinfo); /* virtual to phys transtalion */ -static inline unsigned long cpu2cpm_addr(void* addr, struct uart_cpm_port *pinfo) +static inline unsigned long cpu2cpm_addr(void *addr, + struct uart_cpm_port *pinfo) { int offset; u32 val = (u32)addr; + u32 mem = (u32)pinfo->mem_addr; /* sane check */ - if (likely((val >= (u32)pinfo->mem_addr)) && - (val<((u32)pinfo->mem_addr + pinfo->mem_size))) { - offset = val - (u32)pinfo->mem_addr; - return pinfo->dma_addr+offset; + if (likely(val >= mem && val < mem + pinfo->mem_size)) { + offset = val - mem; + return pinfo->dma_addr + offset; } /* something nasty happened */ BUG(); return 0; } -static inline void *cpm2cpu_addr(unsigned long addr, struct uart_cpm_port *pinfo) +static inline void *cpm2cpu_addr(unsigned long addr, + struct uart_cpm_port *pinfo) { int offset; u32 val = addr; + u32 dma = (u32)pinfo->dma_addr; /* sane check */ - if (likely((val >= pinfo->dma_addr) && - (val<(pinfo->dma_addr + pinfo->mem_size)))) { - offset = val - (u32)pinfo->dma_addr; - return (void*)(pinfo->mem_addr+offset); + if (likely(val >= dma && val < dma + pinfo->mem_size)) { + offset = val - dma; + return pinfo->mem_addr + offset; } /* something nasty happened */ BUG(); - return 0; + return NULL; } diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c index 8564ba2f3ec..afaf195b6e0 100644 --- a/drivers/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/serial/cpm_uart/cpm_uart_core.c @@ -131,14 +131,14 @@ static int cpm_uart_id2nr(int id) static unsigned int cpm_uart_tx_empty(struct uart_port *port) { struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; - volatile cbd_t *bdp = pinfo->tx_bd_base; + cbd_t __iomem *bdp = pinfo->tx_bd_base; int ret = 0; while (1) { - if (bdp->cbd_sc & BD_SC_READY) + if (in_be16(&bdp->cbd_sc) & BD_SC_READY) break; - if (bdp->cbd_sc & BD_SC_WRAP) { + if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP) { ret = TIOCSER_TEMT; break; } @@ -167,15 +167,15 @@ static unsigned int cpm_uart_get_mctrl(struct uart_port *port) static void cpm_uart_stop_tx(struct uart_port *port) { struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; - volatile smc_t *smcp = pinfo->smcp; - volatile scc_t *sccp = pinfo->sccp; + smc_t __iomem *smcp = pinfo->smcp; + scc_t __iomem *sccp = pinfo->sccp; pr_debug("CPM uart[%d]:stop tx\n", port->line); if (IS_SMC(pinfo)) - smcp->smc_smcm &= ~SMCM_TX; + clrbits8(&smcp->smc_smcm, SMCM_TX); else - sccp->scc_sccm &= ~UART_SCCM_TX; + clrbits16(&sccp->scc_sccm, UART_SCCM_TX); } /* @@ -184,24 +184,24 @@ static void cpm_uart_stop_tx(struct uart_port *port) static void cpm_uart_start_tx(struct uart_port *port) { struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; - volatile smc_t *smcp = pinfo->smcp; - volatile scc_t *sccp = pinfo->sccp; + smc_t __iomem *smcp = pinfo->smcp; + scc_t __iomem *sccp = pinfo->sccp; pr_debug("CPM uart[%d]:start tx\n", port->line); if (IS_SMC(pinfo)) { - if (smcp->smc_smcm & SMCM_TX) + if (in_8(&smcp->smc_smcm) & SMCM_TX) return; } else { - if (sccp->scc_sccm & UART_SCCM_TX) + if (in_be16(&sccp->scc_sccm) & UART_SCCM_TX) return; } if (cpm_uart_tx_pump(port) != 0) { if (IS_SMC(pinfo)) { - smcp->smc_smcm |= SMCM_TX; + setbits8(&smcp->smc_smcm, SMCM_TX); } else { - sccp->scc_sccm |= UART_SCCM_TX; + setbits16(&sccp->scc_sccm, UART_SCCM_TX); } } } @@ -212,15 +212,15 @@ static void cpm_uart_start_tx(struct uart_port *port) static void cpm_uart_stop_rx(struct uart_port *port) { struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; - volatile smc_t *smcp = pinfo->smcp; - volatile scc_t *sccp = pinfo->sccp; + smc_t __iomem *smcp = pinfo->smcp; + scc_t __iomem *sccp = pinfo->sccp; pr_debug("CPM uart[%d]:stop rx\n", port->line); if (IS_SMC(pinfo)) - smcp->smc_smcm &= ~SMCM_RX; + clrbits8(&smcp->smc_smcm, SMCM_RX); else - sccp->scc_sccm &= ~UART_SCCM_RX; + clrbits16(&sccp->scc_sccm, UART_SCCM_RX); } /* @@ -263,10 +263,11 @@ static void cpm_uart_int_tx(struct uart_port *port) static void cpm_uart_int_rx(struct uart_port *port) { int i; - unsigned char ch, *cp; + unsigned char ch; + u8 *cp; struct tty_struct *tty = port->info->tty; struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; - volatile cbd_t *bdp; + cbd_t __iomem *bdp; u16 status; unsigned int flg; @@ -278,13 +279,13 @@ static void cpm_uart_int_rx(struct uart_port *port) bdp = pinfo->rx_cur; for (;;) { /* get status */ - status = bdp->cbd_sc; + status = in_be16(&bdp->cbd_sc); /* If this one is empty, return happy */ if (status & BD_SC_EMPTY) break; /* get number of characters, and check spce in flip-buffer */ - i = bdp->cbd_datlen; + i = in_be16(&bdp->cbd_datlen); /* If we have not enough room in tty flip buffer, then we try * later, which will be the next rx-interrupt or a timeout @@ -295,7 +296,7 @@ static void cpm_uart_int_rx(struct uart_port *port) } /* get pointer */ - cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo); + cp = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo); /* loop through the buffer */ while (i-- > 0) { @@ -315,10 +316,11 @@ static void cpm_uart_int_rx(struct uart_port *port) } /* End while (i--) */ /* This BD is ready to be used again. Clear status. get next */ - bdp->cbd_sc &= ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV | BD_SC_ID); - bdp->cbd_sc |= BD_SC_EMPTY; + clrbits16(&bdp->cbd_sc, BD_SC_BR | BD_SC_FR | BD_SC_PR | + BD_SC_OV | BD_SC_ID); + setbits16(&bdp->cbd_sc, BD_SC_EMPTY); - if (bdp->cbd_sc & BD_SC_WRAP) + if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP) bdp = pinfo->rx_bd_base; else bdp++; @@ -326,7 +328,7 @@ static void cpm_uart_int_rx(struct uart_port *port) } /* End for (;;) */ /* Write back buffer pointer */ - pinfo->rx_cur = (volatile cbd_t *) bdp; + pinfo->rx_cur = bdp; /* activate BH processing */ tty_flip_buffer_push(tty); @@ -380,14 +382,14 @@ static irqreturn_t cpm_uart_int(int irq, void *data) u8 events; struct uart_port *port = (struct uart_port *)data; struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; - volatile smc_t *smcp = pinfo->smcp; - volatile scc_t *sccp = pinfo->sccp; + smc_t __iomem *smcp = pinfo->smcp; + scc_t __iomem *sccp = pinfo->sccp; pr_debug("CPM uart[%d]:IRQ\n", port->line); if (IS_SMC(pinfo)) { - events = smcp->smc_smce; - smcp->smc_smce = events; + events = in_8(&smcp->smc_smce); + out_8(&smcp->smc_smce, events); if (events & SMCM_BRKE) uart_handle_break(port); if (events & SMCM_RX) @@ -395,8 +397,8 @@ static irqreturn_t cpm_uart_int(int irq, void *data) if (events & SMCM_TX) cpm_uart_int_tx(port); } else { - events = sccp->scc_scce; - sccp->scc_scce = events; + events = in_be16(&sccp->scc_scce); + out_be16(&sccp->scc_scce, events); if (events & UART_SCCM_BRKE) uart_handle_break(port); if (events & UART_SCCM_RX) @@ -421,11 +423,11 @@ static int cpm_uart_startup(struct uart_port *port) /* Startup rx-int */ if (IS_SMC(pinfo)) { - pinfo->smcp->smc_smcm |= SMCM_RX; - pinfo->smcp->smc_smcmr |= (SMCMR_REN | SMCMR_TEN); + setbits8(&pinfo->smcp->smc_smcm, SMCM_RX); + setbits16(&pinfo->smcp->smc_smcmr, (SMCMR_REN | SMCMR_TEN)); } else { - pinfo->sccp->scc_sccm |= UART_SCCM_RX; - pinfo->sccp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); + setbits16(&pinfo->sccp->scc_sccm, UART_SCCM_RX); + setbits32(&pinfo->sccp->scc_gsmrl, (SCC_GSMRL_ENR | SCC_GSMRL_ENT)); } if (!(pinfo->flags & FLAG_CONSOLE)) @@ -464,13 +466,13 @@ static void cpm_uart_shutdown(struct uart_port *port) /* Stop uarts */ if (IS_SMC(pinfo)) { - volatile smc_t *smcp = pinfo->smcp; - smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); - smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX); + smc_t __iomem *smcp = pinfo->smcp; + clrbits16(&smcp->smc_smcmr, SMCMR_REN | SMCMR_TEN); + clrbits8(&smcp->smc_smcm, SMCM_RX | SMCM_TX); } else { - volatile scc_t *sccp = pinfo->sccp; - sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); - sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX); + scc_t __iomem *sccp = pinfo->sccp; + clrbits32(&sccp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); + clrbits16(&sccp->scc_sccm, UART_SCCM_TX | UART_SCCM_RX); } /* Shut them really down and reinit buffer descriptors */ @@ -492,8 +494,8 @@ static void cpm_uart_set_termios(struct uart_port *port, u16 cval, scval, prev_mode; int bits, sbits; struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; - volatile smc_t *smcp = pinfo->smcp; - volatile scc_t *sccp = pinfo->sccp; + smc_t __iomem *smcp = pinfo->smcp; + scc_t __iomem *sccp = pinfo->sccp; pr_debug("CPM uart[%d]:set_termios\n", port->line); @@ -588,11 +590,11 @@ static void cpm_uart_set_termios(struct uart_port *port, * enables, because we want to put them back if they were * present. */ - prev_mode = smcp->smc_smcmr; - smcp->smc_smcmr = smcr_mk_clen(bits) | cval | SMCMR_SM_UART; - smcp->smc_smcmr |= (prev_mode & (SMCMR_REN | SMCMR_TEN)); + prev_mode = in_be16(&smcp->smc_smcmr); + out_be16(&smcp->smc_smcmr, smcr_mk_clen(bits) | cval | SMCMR_SM_UART); + setbits16(&smcp->smc_smcmr, (prev_mode & (SMCMR_REN | SMCMR_TEN))); } else { - sccp->scc_psmr = (sbits << 12) | scval; + out_be16(&sccp->scc_psmr, (sbits << 12) | scval); } cpm_set_brg(pinfo->brg - 1, baud); @@ -630,8 +632,8 @@ static int cpm_uart_verify_port(struct uart_port *port, */ static int cpm_uart_tx_pump(struct uart_port *port) { - volatile cbd_t *bdp; - unsigned char *p; + cbd_t __iomem *bdp; + u8 *p; int count; struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; struct circ_buf *xmit = &port->info->xmit; @@ -641,13 +643,14 @@ static int cpm_uart_tx_pump(struct uart_port *port) /* Pick next descriptor and fill from buffer */ bdp = pinfo->tx_cur; - p = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo); + p = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo); *p++ = port->x_char; - bdp->cbd_datlen = 1; - bdp->cbd_sc |= BD_SC_READY; + + out_be16(&bdp->cbd_datlen, 1); + setbits16(&bdp->cbd_sc, BD_SC_READY); /* Get next BD. */ - if (bdp->cbd_sc & BD_SC_WRAP) + if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP) bdp = pinfo->tx_bd_base; else bdp++; @@ -666,9 +669,10 @@ static int cpm_uart_tx_pump(struct uart_port *port) /* Pick next descriptor and fill from buffer */ bdp = pinfo->tx_cur; - while (!(bdp->cbd_sc & BD_SC_READY) && (xmit->tail != xmit->head)) { + while (!(in_be16(&bdp->cbd_sc) & BD_SC_READY) && + xmit->tail != xmit->head) { count = 0; - p = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo); + p = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo); while (count < pinfo->tx_fifosize) { *p++ = xmit->buf[xmit->tail]; xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); @@ -677,11 +681,10 @@ static int cpm_uart_tx_pump(struct uart_port *port) if (xmit->head == xmit->tail) break; } - bdp->cbd_datlen = count; - bdp->cbd_sc |= BD_SC_READY; - eieio(); + out_be16(&bdp->cbd_datlen, count); + setbits16(&bdp->cbd_sc, BD_SC_READY); /* Get next BD. */ - if (bdp->cbd_sc & BD_SC_WRAP) + if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP) bdp = pinfo->tx_bd_base; else bdp++; @@ -706,7 +709,7 @@ static void cpm_uart_initbd(struct uart_cpm_port *pinfo) { int i; u8 *mem_addr; - volatile cbd_t *bdp; + cbd_t __iomem *bdp; pr_debug("CPM uart[%d]:initbd\n", pinfo->port.line); @@ -717,13 +720,13 @@ static void cpm_uart_initbd(struct uart_cpm_port *pinfo) mem_addr = pinfo->mem_addr; bdp = pinfo->rx_cur = pinfo->rx_bd_base; for (i = 0; i < (pinfo->rx_nrfifos - 1); i++, bdp++) { - bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr, pinfo); - bdp->cbd_sc = BD_SC_EMPTY | BD_SC_INTRPT; + out_be32(&bdp->cbd_bufaddr, cpu2cpm_addr(mem_addr, pinfo)); + out_be16(&bdp->cbd_sc, BD_SC_EMPTY | BD_SC_INTRPT); mem_addr += pinfo->rx_fifosize; } - bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr, pinfo); - bdp->cbd_sc = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT; + out_be32(&bdp->cbd_bufaddr, cpu2cpm_addr(mem_addr, pinfo)); + out_be16(&bdp->cbd_sc, BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT); /* Set the physical address of the host memory * buffers in the buffer descriptors, and the @@ -732,19 +735,19 @@ static void cpm_uart_initbd(struct uart_cpm_port *pinfo) mem_addr = pinfo->mem_addr + L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize); bdp = pinfo->tx_cur = pinfo->tx_bd_base; for (i = 0; i < (pinfo->tx_nrfifos - 1); i++, bdp++) { - bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr, pinfo); - bdp->cbd_sc = BD_SC_INTRPT; + out_be32(&bdp->cbd_bufaddr, cpu2cpm_addr(mem_addr, pinfo)); + out_be16(&bdp->cbd_sc, BD_SC_INTRPT); mem_addr += pinfo->tx_fifosize; } - bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr, pinfo); - bdp->cbd_sc = BD_SC_WRAP | BD_SC_INTRPT; + out_be32(&bdp->cbd_bufaddr, cpu2cpm_addr(mem_addr, pinfo)); + out_be16(&bdp->cbd_sc, BD_SC_WRAP | BD_SC_INTRPT); } static void cpm_uart_init_scc(struct uart_cpm_port *pinfo) { - volatile scc_t *scp; - volatile scc_uart_t *sup; + scc_t __iomem *scp; + scc_uart_t __iomem *sup; pr_debug("CPM uart[%d]:init_scc\n", pinfo->port.line); @@ -752,8 +755,10 @@ static void cpm_uart_init_scc(struct uart_cpm_port *pinfo) sup = pinfo->sccup; /* Store address */ - pinfo->sccup->scc_genscc.scc_rbase = (unsigned char *)pinfo->rx_bd_base - DPRAM_BASE; - pinfo->sccup->scc_genscc.scc_tbase = (unsigned char *)pinfo->tx_bd_base - DPRAM_BASE; + out_be16(&pinfo->sccup->scc_genscc.scc_rbase, + (u8 __iomem *)pinfo->rx_bd_base - DPRAM_BASE); + out_be16(&pinfo->sccup->scc_genscc.scc_tbase, + (u8 __iomem *)pinfo->tx_bd_base - DPRAM_BASE); /* Set up the uart parameters in the * parameter ram. @@ -761,25 +766,25 @@ static void cpm_uart_init_scc(struct uart_cpm_port *pinfo) cpm_set_scc_fcr(sup); - sup->scc_genscc.scc_mrblr = pinfo->rx_fifosize; - sup->scc_maxidl = pinfo->rx_fifosize; - sup->scc_brkcr = 1; - sup->scc_parec = 0; - sup->scc_frmec = 0; - sup->scc_nosec = 0; - sup->scc_brkec = 0; - sup->scc_uaddr1 = 0; - sup->scc_uaddr2 = 0; - sup->scc_toseq = 0; - sup->scc_char1 = 0x8000; - sup->scc_char2 = 0x8000; - sup->scc_char3 = 0x8000; - sup->scc_char4 = 0x8000; - sup->scc_char5 = 0x8000; - sup->scc_char6 = 0x8000; - sup->scc_char7 = 0x8000; - sup->scc_char8 = 0x8000; - sup->scc_rccm = 0xc0ff; + out_be16(&sup->scc_genscc.scc_mrblr, pinfo->rx_fifosize); + out_be16(&sup->scc_maxidl, pinfo->rx_fifosize); + out_be16(&sup->scc_brkcr, 1); + out_be16(&sup->scc_parec, 0); + out_be16(&sup->scc_frmec, 0); + out_be16(&sup->scc_nosec, 0); + out_be16(&sup->scc_brkec, 0); + out_be16(&sup->scc_uaddr1, 0); + out_be16(&sup->scc_uaddr2, 0); + out_be16(&sup->scc_toseq, 0); + out_be16(&sup->scc_char1, 0x8000); + out_be16(&sup->scc_char2, 0x8000); + out_be16(&sup->scc_char3, 0x8000); + out_be16(&sup->scc_char4, 0x8000); + out_be16(&sup->scc_char5, 0x8000); + out_be16(&sup->scc_char6, 0x8000); + out_be16(&sup->scc_char7, 0x8000); + out_be16(&sup->scc_char8, 0x8000); + out_be16(&sup->scc_rccm, 0xc0ff); /* Send the CPM an initialize command. */ @@ -788,23 +793,23 @@ static void cpm_uart_init_scc(struct uart_cpm_port *pinfo) /* Set UART mode, 8 bit, no parity, one stop. * Enable receive and transmit. */ - scp->scc_gsmrh = 0; - scp->scc_gsmrl = - (SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16); + out_be32(&scp->scc_gsmrh, 0); + out_be32(&scp->scc_gsmrl, + SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16); /* Enable rx interrupts and clear all pending events. */ - scp->scc_sccm = 0; - scp->scc_scce = 0xffff; - scp->scc_dsr = 0x7e7e; - scp->scc_psmr = 0x3000; + out_be16(&scp->scc_sccm, 0); + out_be16(&scp->scc_scce, 0xffff); + out_be16(&scp->scc_dsr, 0x7e7e); + out_be16(&scp->scc_psmr, 0x3000); - scp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); + setbits32(&scp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); } static void cpm_uart_init_smc(struct uart_cpm_port *pinfo) { - volatile smc_t *sp; - volatile smc_uart_t *up; + smc_t __iomem *sp; + smc_uart_t __iomem *up; pr_debug("CPM uart[%d]:init_smc\n", pinfo->port.line); @@ -812,19 +817,21 @@ static void cpm_uart_init_smc(struct uart_cpm_port *pinfo) up = pinfo->smcup; /* Store address */ - pinfo->smcup->smc_rbase = (u_char *)pinfo->rx_bd_base - DPRAM_BASE; - pinfo->smcup->smc_tbase = (u_char *)pinfo->tx_bd_base - DPRAM_BASE; + out_be16(&pinfo->smcup->smc_rbase, + (u8 __iomem *)pinfo->rx_bd_base - DPRAM_BASE); + out_be16(&pinfo->smcup->smc_tbase, + (u8 __iomem *)pinfo->tx_bd_base - DPRAM_BASE); /* * In case SMC1 is being relocated... */ #if defined (CONFIG_I2C_SPI_SMC1_UCODE_PATCH) - up->smc_rbptr = pinfo->smcup->smc_rbase; - up->smc_tbptr = pinfo->smcup->smc_tbase; - up->smc_rstate = 0; - up->smc_tstate = 0; - up->smc_brkcr = 1; /* number of break chars */ - up->smc_brkec = 0; + out_be16(&up->smc_rbptr, in_be16(&pinfo->smcup->smc_rbase)); + out_be16(&up->smc_tbptr, in_be16(&pinfo->smcup->smc_tbase)); + out_be32(&up->smc_rstate, 0); + out_be32(&up->smc_tstate, 0); + out_be16(&up->smc_brkcr, 1); /* number of break chars */ + out_be16(&up->smc_brkec, 0); #endif /* Set up the uart parameters in the @@ -833,24 +840,24 @@ static void cpm_uart_init_smc(struct uart_cpm_port *pinfo) cpm_set_smc_fcr(up); /* Using idle charater time requires some additional tuning. */ - up->smc_mrblr = pinfo->rx_fifosize; - up->smc_maxidl = pinfo->rx_fifosize; - up->smc_brklen = 0; - up->smc_brkec = 0; - up->smc_brkcr = 1; + out_be16(&up->smc_mrblr, pinfo->rx_fifosize); + out_be16(&up->smc_maxidl, pinfo->rx_fifosize); + out_be16(&up->smc_brklen, 0); + out_be16(&up->smc_brkec, 0); + out_be16(&up->smc_brkcr, 1); cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX); /* Set UART mode, 8 bit, no parity, one stop. * Enable receive and transmit. */ - sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART; + out_be16(&sp->smc_smcmr, smcr_mk_clen(9) | SMCMR_SM_UART); /* Enable only rx interrupts clear all pending events. */ - sp->smc_smcm = 0; - sp->smc_smce = 0xff; + out_8(&sp->smc_smcm, 0); + out_8(&sp->smc_smce, 0xff); - sp->smc_smcmr |= (SMCMR_REN | SMCMR_TEN); + setbits16(&sp->smc_smcmr, SMCMR_REN | SMCMR_TEN); } /* @@ -868,11 +875,11 @@ static int cpm_uart_request_port(struct uart_port *port) return 0; if (IS_SMC(pinfo)) { - pinfo->smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX); - pinfo->smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); + clrbits8(&pinfo->smcp->smc_smcm, SMCM_RX | SMCM_TX); + clrbits16(&pinfo->smcp->smc_smcmr, SMCMR_REN | SMCMR_TEN); } else { - pinfo->sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX); - pinfo->sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); + clrbits16(&pinfo->sccp->scc_sccm, UART_SCCM_TX | UART_SCCM_RX); + clrbits32(&pinfo->sccp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); } ret = cpm_uart_allocbuf(pinfo, 0); @@ -931,10 +938,11 @@ static struct uart_ops cpm_uart_pops = { #ifdef CONFIG_PPC_CPM_NEW_BINDING struct uart_cpm_port cpm_uart_ports[UART_NR]; -int cpm_uart_init_port(struct device_node *np, struct uart_cpm_port *pinfo) +static int cpm_uart_init_port(struct device_node *np, + struct uart_cpm_port *pinfo) { const u32 *data; - void __iomem *mem, __iomem *pram; + void __iomem *mem, *pram; int len; int ret; @@ -1169,8 +1177,8 @@ static void cpm_uart_console_write(struct console *co, const char *s, &cpm_uart_ports[cpm_uart_port_map[co->index]]; #endif unsigned int i; - volatile cbd_t *bdp, *bdbase; - volatile unsigned char *cp; + cbd_t __iomem *bdp, *bdbase; + unsigned char *cp; /* Get the address of the host memory buffer. */ @@ -1188,37 +1196,36 @@ static void cpm_uart_console_write(struct console *co, const char *s, * Ready indicates output is ready, and xmt is doing * that, not that it is ready for us to send. */ - while ((bdp->cbd_sc & BD_SC_READY) != 0) + while ((in_be16(&bdp->cbd_sc) & BD_SC_READY) != 0) ; /* Send the character out. * If the buffer address is in the CPM DPRAM, don't * convert it. */ - cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo); - + cp = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo); *cp = *s; - bdp->cbd_datlen = 1; - bdp->cbd_sc |= BD_SC_READY; + out_be16(&bdp->cbd_datlen, 1); + setbits16(&bdp->cbd_sc, BD_SC_READY); - if (bdp->cbd_sc & BD_SC_WRAP) + if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP) bdp = bdbase; else bdp++; /* if a LF, also do CR... */ if (*s == 10) { - while ((bdp->cbd_sc & BD_SC_READY) != 0) + while ((in_be16(&bdp->cbd_sc) & BD_SC_READY) != 0) ; - cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo); - + cp = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo); *cp = 13; - bdp->cbd_datlen = 1; - bdp->cbd_sc |= BD_SC_READY; - if (bdp->cbd_sc & BD_SC_WRAP) + out_be16(&bdp->cbd_datlen, 1); + setbits16(&bdp->cbd_sc, BD_SC_READY); + + if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP) bdp = bdbase; else bdp++; @@ -1229,10 +1236,10 @@ static void cpm_uart_console_write(struct console *co, const char *s, * Finally, Wait for transmitter & holding register to empty * and restore the IER */ - while ((bdp->cbd_sc & BD_SC_READY) != 0) + while ((in_be16(&bdp->cbd_sc) & BD_SC_READY) != 0) ; - pinfo->tx_cur = (volatile cbd_t *) bdp; + pinfo->tx_cur = bdp; } @@ -1319,11 +1326,11 @@ static int __init cpm_uart_console_setup(struct console *co, char *options) #endif if (IS_SMC(pinfo)) { - pinfo->smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX); - pinfo->smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); + clrbits8(&pinfo->smcp->smc_smcm, SMCM_RX | SMCM_TX); + clrbits16(&pinfo->smcp->smc_smcmr, SMCMR_REN | SMCMR_TEN); } else { - pinfo->sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX); - pinfo->sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); + clrbits16(&pinfo->sccp->scc_sccm, UART_SCCM_TX | UART_SCCM_RX); + clrbits32(&pinfo->sccp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); } ret = cpm_uart_allocbuf(pinfo, 1); @@ -1354,7 +1361,7 @@ static struct console cpm_scc_uart_console = { .data = &cpm_reg, }; -int __init cpm_uart_console_init(void) +static int __init cpm_uart_console_init(void) { register_console(&cpm_scc_uart_console); return 0; diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.c b/drivers/serial/cpm_uart/cpm_uart_cpm1.c index 4647f55e19f..52fb044bb79 100644 --- a/drivers/serial/cpm_uart/cpm_uart_cpm1.c +++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.c @@ -179,7 +179,7 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con) pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize); - pinfo->rx_bd_base = (volatile cbd_t *)dp_mem; + pinfo->rx_bd_base = (cbd_t __iomem __force *)dp_mem; pinfo->tx_bd_base = pinfo->rx_bd_base + pinfo->rx_nrfifos; return 0; diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.h b/drivers/serial/cpm_uart/cpm_uart_cpm1.h index 69f523a442e..9b5465fb0bb 100644 --- a/drivers/serial/cpm_uart/cpm_uart_cpm1.h +++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.h @@ -27,18 +27,18 @@ static inline void cpm_set_brg(int brg, int baud) cpm_setbrg(brg, baud); } -static inline void cpm_set_scc_fcr(volatile scc_uart_t * sup) +static inline void cpm_set_scc_fcr(scc_uart_t __iomem * sup) { - sup->scc_genscc.scc_rfcr = SMC_EB; - sup->scc_genscc.scc_tfcr = SMC_EB; + out_8(&sup->scc_genscc.scc_rfcr, SMC_EB); + out_8(&sup->scc_genscc.scc_tfcr, SMC_EB); } -static inline void cpm_set_smc_fcr(volatile smc_uart_t * up) +static inline void cpm_set_smc_fcr(smc_uart_t __iomem * up) { - up->smc_rfcr = SMC_EB; - up->smc_tfcr = SMC_EB; + out_8(&up->smc_rfcr, SMC_EB); + out_8(&up->smc_tfcr, SMC_EB); } -#define DPRAM_BASE ((unsigned char *)cpm_dpram_addr(0)) +#define DPRAM_BASE ((u8 __iomem __force *)cpm_dpram_addr(0)) #endif diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/serial/cpm_uart/cpm_uart_cpm2.c index 7ebce263ad4..5bd4508ce3c 100644 --- a/drivers/serial/cpm_uart/cpm_uart_cpm2.c +++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.c @@ -278,7 +278,7 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con) pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize); - pinfo->rx_bd_base = (volatile cbd_t *)dp_mem; + pinfo->rx_bd_base = (cbd_t __iomem __force *)dp_mem; pinfo->tx_bd_base = pinfo->rx_bd_base + pinfo->rx_nrfifos; return 0; @@ -289,7 +289,7 @@ void cpm_uart_freebuf(struct uart_cpm_port *pinfo) dma_free_coherent(NULL, L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize) + L1_CACHE_ALIGN(pinfo->tx_nrfifos * - pinfo->tx_fifosize), pinfo->mem_addr, + pinfo->tx_fifosize), (void __force *)pinfo->mem_addr, pinfo->dma_addr); cpm_dpfree(pinfo->dp_addr); diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.h b/drivers/serial/cpm_uart/cpm_uart_cpm2.h index e7717ece083..40006a7dce4 100644 --- a/drivers/serial/cpm_uart/cpm_uart_cpm2.h +++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.h @@ -27,18 +27,18 @@ static inline void cpm_set_brg(int brg, int baud) cpm_setbrg(brg, baud); } -static inline void cpm_set_scc_fcr(volatile scc_uart_t * sup) +static inline void cpm_set_scc_fcr(scc_uart_t __iomem *sup) { - sup->scc_genscc.scc_rfcr = CPMFCR_GBL | CPMFCR_EB; - sup->scc_genscc.scc_tfcr = CPMFCR_GBL | CPMFCR_EB; + out_8(&sup->scc_genscc.scc_rfcr, CPMFCR_GBL | CPMFCR_EB); + out_8(&sup->scc_genscc.scc_tfcr, CPMFCR_GBL | CPMFCR_EB); } -static inline void cpm_set_smc_fcr(volatile smc_uart_t * up) +static inline void cpm_set_smc_fcr(smc_uart_t __iomem *up) { - up->smc_rfcr = CPMFCR_GBL | CPMFCR_EB; - up->smc_tfcr = CPMFCR_GBL | CPMFCR_EB; + out_8(&up->smc_rfcr, CPMFCR_GBL | CPMFCR_EB); + out_8(&up->smc_tfcr, CPMFCR_GBL | CPMFCR_EB); } -#define DPRAM_BASE ((unsigned char *)cpm_dpram_addr(0)) +#define DPRAM_BASE ((u8 __iomem __force *)cpm_dpram_addr(0)) #endif -- cgit v1.2.3-70-g09d2 From d948a29ea7a9514f588dafb61d5a6da68131c3ba Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Tue, 17 Jul 2007 18:09:33 -0500 Subject: [POWERPC] cpm_uart: Issue STOP_TX command before initializing console. This prevents some bootloader/bootwrapper characters from being lost. Signed-off-by: Scott Wood Signed-off-by: Kumar Gala --- drivers/serial/cpm_uart/cpm_uart_core.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c index afaf195b6e0..b5e4478de0e 100644 --- a/drivers/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/serial/cpm_uart/cpm_uart_core.c @@ -1325,6 +1325,8 @@ static int __init cpm_uart_console_setup(struct console *co, char *options) udbg_putc = NULL; #endif + cpm_line_cr_cmd(pinfo, CPM_CR_STOP_TX); + if (IS_SMC(pinfo)) { clrbits8(&pinfo->smcp->smc_smcm, SMCM_RX | SMCM_TX); clrbits16(&pinfo->smcp->smc_smcmr, SMCMR_REN | SMCMR_TEN); @@ -1346,6 +1348,7 @@ static int __init cpm_uart_console_setup(struct console *co, char *options) cpm_uart_init_scc(pinfo); uart_set_options(port, co, baud, parity, bits, flow); + cpm_line_cr_cmd(pinfo, CPM_CR_RESTART_TX); return 0; } -- cgit v1.2.3-70-g09d2 From 15f8c604a79c4840ed76eecf3af5d88b7c1dee9e Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Fri, 28 Sep 2007 14:06:16 -0500 Subject: [POWERPC] cpm: Describe multi-user ram in its own device node. The way the current CPM binding describes available multi-user (a.k.a. dual-ported) RAM doesn't work well when there are multiple free regions, and it doesn't work at all if the region doesn't begin at the start of the muram area (as the hardware needs to be programmed with offsets into this area). The latter situation can happen with SMC UARTs on CPM2, as its parameter RAM is relocatable, u-boot puts it at zero, and the kernel doesn't support moving it. It is now described with a muram node, similar to QE. The current CPM binding is sufficiently recent (i.e. never appeared in an official release) that compatibility with existing device trees is not an issue. The code supporting the new binding is shared between cpm1 and cpm2, rather than remain separated. QE should be able to use this code as well, once minor fixes are made to its device trees. Signed-off-by: Scott Wood Signed-off-by: Kumar Gala --- Documentation/powerpc/booting-without-of.txt | 40 ++++++- arch/powerpc/Kconfig.debug | 6 +- arch/powerpc/boot/cpm-serial.c | 44 ++++++-- arch/powerpc/boot/dts/ep88xc.dts | 13 ++- arch/powerpc/boot/dts/mpc8272ads.dts | 11 ++ arch/powerpc/boot/dts/mpc885ads.dts | 13 ++- arch/powerpc/boot/dts/pq2fads.dts | 13 ++- arch/powerpc/sysdev/commproc.c | 11 +- arch/powerpc/sysdev/cpm2_common.c | 35 ++---- arch/powerpc/sysdev/cpm_common.c | 159 +++++++++++++++++++++++++++ drivers/serial/cpm_uart/cpm_uart_cpm2.c | 4 +- include/asm-powerpc/commproc.h | 12 ++ include/asm-powerpc/cpm.h | 14 +++ include/asm-powerpc/cpm2.h | 10 ++ 14 files changed, 337 insertions(+), 48 deletions(-) create mode 100644 include/asm-powerpc/cpm.h (limited to 'drivers') diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt index c36dcd2fbdc..ce5d67f5cb5 100644 --- a/Documentation/powerpc/booting-without-of.txt +++ b/Documentation/powerpc/booting-without-of.txt @@ -1861,9 +1861,7 @@ platforms are moved over to use the flattened-device-tree model. Properties: - compatible : "fsl,cpm1", "fsl,cpm2", or "fsl,qe". - - reg : The first resource is a 48-byte region beginning with - CPCR. The second is the available general-purpose - DPRAM. + - reg : A 48-byte region beginning with CPCR. Example: cpm@119c0 { @@ -1871,7 +1869,7 @@ platforms are moved over to use the flattened-device-tree model. #size-cells = <1>; #interrupt-cells = <2>; compatible = "fsl,mpc8272-cpm", "fsl,cpm2"; - reg = <119c0 30 0 2000>; + reg = <119c0 30>; } ii) Properties common to mulitple CPM/QE devices @@ -2017,6 +2015,40 @@ platforms are moved over to use the flattened-device-tree model. fsl,cpm-command = <2e600000>; }; + viii) Multi-User RAM (MURAM) + + The multi-user/dual-ported RAM is expressed as a bus under the CPM node. + + Ranges must be set up subject to the following restrictions: + + - Children's reg nodes must be offsets from the start of all muram, even + if the user-data area does not begin at zero. + - If multiple range entries are used, the difference between the parent + address and the child address must be the same in all, so that a single + mapping can cover them all while maintaining the ability to determine + CPM-side offsets with pointer subtraction. It is recommended that + multiple range entries not be used. + - A child address of zero must be translatable, even if no reg resources + contain it. + + A child "data" node must exist, compatible with "fsl,cpm-muram-data", to + indicate the portion of muram that is usable by the OS for arbitrary + purposes. The data node may have an arbitrary number of reg resources, + all of which contribute to the allocatable muram pool. + + Example, based on mpc8272: + + muram@0 { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0 10000>; + + data@0 { + compatible = "fsl,cpm-muram-data"; + reg = <0 2000 9800 800>; + }; + }; + m) Chipselect/Local Bus Properties: diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug index f4e5d22312a..464f9b4b316 100644 --- a/arch/powerpc/Kconfig.debug +++ b/arch/powerpc/Kconfig.debug @@ -245,9 +245,9 @@ config PPC_EARLY_DEBUG_44x_PHYSHIGH config PPC_EARLY_DEBUG_CPM_ADDR hex "CPM UART early debug transmit descriptor address" depends on PPC_EARLY_DEBUG_CPM - default "0xfa202808" if PPC_EP88XC - default "0xf0000808" if CPM2 - default "0xff002808" if CPM1 + default "0xfa202008" if PPC_EP88XC + default "0xf0000008" if CPM2 + default "0xff002008" if CPM1 help This specifies the address of the transmit descriptor used for early debug output. Because it is needed before diff --git a/arch/powerpc/boot/cpm-serial.c b/arch/powerpc/boot/cpm-serial.c index fcb8b5e956b..28296facb2a 100644 --- a/arch/powerpc/boot/cpm-serial.c +++ b/arch/powerpc/boot/cpm-serial.c @@ -56,7 +56,8 @@ static struct cpm_smc *smc; static struct cpm_scc *scc; struct cpm_bd *tbdf, *rbdf; static u32 cpm_cmd; -static u8 *dpram_start; +static u8 *muram_start; +static u32 muram_offset; static void (*do_cmd)(int op); static void (*enable_port)(void); @@ -114,13 +115,12 @@ static void scc_enable_port(void) static int cpm_serial_open(void) { - int dpaddr = 0x800; disable_port(); out_8(¶m->rfcr, 0x10); out_8(¶m->tfcr, 0x10); - rbdf = (struct cpm_bd *)(dpram_start + dpaddr); + rbdf = (struct cpm_bd *)muram_start; rbdf->addr = (u8 *)(rbdf + 2); rbdf->sc = 0xa000; rbdf->len = 1; @@ -131,8 +131,8 @@ static int cpm_serial_open(void) tbdf->len = 1; sync(); - out_be16(¶m->rbase, dpaddr); - out_be16(¶m->tbase, dpaddr + sizeof(struct cpm_bd)); + out_be16(¶m->rbase, muram_offset); + out_be16(¶m->tbase, muram_offset + sizeof(struct cpm_bd)); do_cmd(CPM_CMD_INIT_RX_TX); @@ -178,7 +178,7 @@ int cpm_console_init(void *devp, struct serial_console_data *scdp) void *reg_virt[2]; int is_smc = 0, is_cpm2 = 0, n; unsigned long reg_phys; - void *parent; + void *parent, *muram; if (dt_is_compatible(devp, "fsl,cpm1-smc-uart")) { is_smc = 1; @@ -229,16 +229,36 @@ int cpm_console_init(void *devp, struct serial_console_data *scdp) n = getprop(parent, "virtual-reg", reg_virt, sizeof(reg_virt)); if (n < (int)sizeof(reg_virt)) { - for (n = 0; n < 2; n++) { - if (!dt_xlate_reg(parent, n, ®_phys, NULL)) - return -1; + if (!dt_xlate_reg(parent, 0, ®_phys, NULL)) + return -1; - reg_virt[n] = (void *)reg_phys; - } + reg_virt[0] = (void *)reg_phys; } cpcr = reg_virt[0]; - dpram_start = reg_virt[1]; + + muram = finddevice("/soc/cpm/muram/data"); + if (!muram) + return -1; + + /* For bootwrapper-compatible device trees, we assume that the first + * entry has at least 18 bytes, and that #address-cells/#data-cells + * is one for both parent and child. + */ + + n = getprop(muram, "virtual-reg", reg_virt, sizeof(reg_virt)); + if (n < (int)sizeof(reg_virt)) { + if (!dt_xlate_reg(muram, 0, ®_phys, NULL)) + return -1; + + reg_virt[0] = (void *)reg_phys; + } + + muram_start = reg_virt[0]; + + n = getprop(muram, "reg", &muram_offset, 4); + if (n < 4) + return -1; scdp->open = cpm_serial_open; scdp->putc = cpm_serial_putc; diff --git a/arch/powerpc/boot/dts/ep88xc.dts b/arch/powerpc/boot/dts/ep88xc.dts index 0406fc50b2a..02705f29979 100644 --- a/arch/powerpc/boot/dts/ep88xc.dts +++ b/arch/powerpc/boot/dts/ep88xc.dts @@ -142,9 +142,20 @@ command-proc = <9c0>; interrupts = <0>; // cpm error interrupt interrupt-parent = <&CPM_PIC>; - reg = <9c0 40 2000 1c00>; + reg = <9c0 40>; ranges; + muram@2000 { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 2000 2000>; + + data@0 { + compatible = "fsl,cpm-muram-data"; + reg = <0 1c00>; + }; + }; + brg@9f0 { compatible = "fsl,mpc885-brg", "fsl,cpm1-brg", diff --git a/arch/powerpc/boot/dts/mpc8272ads.dts b/arch/powerpc/boot/dts/mpc8272ads.dts index 3fe991d4cb0..188179df084 100644 --- a/arch/powerpc/boot/dts/mpc8272ads.dts +++ b/arch/powerpc/boot/dts/mpc8272ads.dts @@ -124,6 +124,17 @@ reg = <119c0 30 0 2000>; ranges; + muram@0 { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0 10000>; + + data@0 { + compatible = "fsl,cpm-muram-data"; + reg = <0 2000 9800 800>; + }; + }; + brg@119f0 { compatible = "fsl,mpc8272-brg", "fsl,cpm2-brg", diff --git a/arch/powerpc/boot/dts/mpc885ads.dts b/arch/powerpc/boot/dts/mpc885ads.dts index cbcd16f74c4..8848e637293 100644 --- a/arch/powerpc/boot/dts/mpc885ads.dts +++ b/arch/powerpc/boot/dts/mpc885ads.dts @@ -148,9 +148,20 @@ command-proc = <9c0>; interrupts = <0>; // cpm error interrupt interrupt-parent = <&CPM_PIC>; - reg = <9c0 40 2000 1c00>; + reg = <9c0 40>; ranges; + muram@2000 { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 2000 2000>; + + data@0 { + compatible = "fsl,cpm-muram-data"; + reg = <0 1c00>; + }; + }; + brg@9f0 { compatible = "fsl,mpc885-brg", "fsl,cpm1-brg", diff --git a/arch/powerpc/boot/dts/pq2fads.dts b/arch/powerpc/boot/dts/pq2fads.dts index 54e8bd1ae22..2d564921897 100644 --- a/arch/powerpc/boot/dts/pq2fads.dts +++ b/arch/powerpc/boot/dts/pq2fads.dts @@ -119,9 +119,20 @@ #size-cells = <1>; #interrupt-cells = <2>; compatible = "fsl,mpc8280-cpm", "fsl,cpm2"; - reg = <119c0 30 0 2000>; + reg = <119c0 30>; ranges; + muram@0 { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0 10000>; + + data@0 { + compatible = "fsl,cpm-muram-data"; + reg = <0 2000 9800 800>; + }; + }; + brg@119f0 { compatible = "fsl,mpc8280-brg", "fsl,cpm2-brg", diff --git a/arch/powerpc/sysdev/commproc.c b/arch/powerpc/sysdev/commproc.c index 428eb8c151b..f6a63780bbd 100644 --- a/arch/powerpc/sysdev/commproc.c +++ b/arch/powerpc/sysdev/commproc.c @@ -39,12 +39,15 @@ #include #include #include +#include #include #define CPM_MAP_SIZE (0x4000) +#ifndef CONFIG_PPC_CPM_NEW_BINDING static void m8xx_cpm_dpinit(void); +#endif static uint host_buffer; /* One page of host buffer */ static uint host_end; /* end + 1 */ cpm8xx_t __iomem *cpmp; /* Pointer to comm processor space */ @@ -193,7 +196,7 @@ end: return sirq; } -void cpm_reset(void) +void __init cpm_reset(void) { sysconf8xx_t __iomem *siu_conf; @@ -229,8 +232,12 @@ void cpm_reset(void) out_be32(&siu_conf->sc_sdcr, 1); immr_unmap(siu_conf); +#ifdef CONFIG_PPC_CPM_NEW_BINDING + cpm_muram_init(); +#else /* Reclaim the DP memory for our use. */ m8xx_cpm_dpinit(); +#endif } /* We used to do this earlier, but have to postpone as long as possible @@ -296,6 +303,7 @@ cpm_setbrg(uint brg, uint rate) CPM_BRG_EN | CPM_BRG_DIV16); } +#ifndef CONFIG_PPC_CPM_NEW_BINDING /* * dpalloc / dpfree bits. */ @@ -397,6 +405,7 @@ uint cpm_dpram_phys(u8 *addr) return (dpram_pbase + (uint)(addr - dpram_vbase)); } EXPORT_SYMBOL(cpm_dpram_phys); +#endif /* !CONFIG_PPC_CPM_NEW_BINDING */ struct cpm_ioport16 { __be16 dir, par, sor, dat, intr; diff --git a/arch/powerpc/sysdev/cpm2_common.c b/arch/powerpc/sysdev/cpm2_common.c index fc4c9956538..859362fecb7 100644 --- a/arch/powerpc/sysdev/cpm2_common.c +++ b/arch/powerpc/sysdev/cpm2_common.c @@ -46,7 +46,10 @@ #include +#ifndef CONFIG_PPC_CPM_NEW_BINDING static void cpm2_dpinit(void); +#endif + cpm_cpm2_t __iomem *cpmp; /* Pointer to comm processor space */ /* We allocate this here because it is used almost exclusively for @@ -69,7 +72,11 @@ cpm2_reset(void) /* Reclaim the DP memory for our use. */ +#ifdef CONFIG_PPC_CPM_NEW_BINDING + cpm_muram_init(); +#else cpm2_dpinit(); +#endif /* Tell everyone where the comm processor resides. */ @@ -316,6 +323,7 @@ int cpm2_smc_clk_setup(enum cpm_clk_target target, int clock) return ret; } +#ifndef CONFIG_PPC_CPM_NEW_BINDING /* * dpalloc / dpfree bits. */ @@ -328,28 +336,6 @@ static u8 __iomem *im_dprambase; static void cpm2_dpinit(void) { - struct resource r; - -#ifdef CONFIG_PPC_CPM_NEW_BINDING - struct device_node *np; - - np = of_find_compatible_node(NULL, NULL, "fsl,cpm2"); - if (!np) - panic("Cannot find CPM2 node"); - - if (of_address_to_resource(np, 1, &r)) - panic("Cannot get CPM2 resource 1"); - - of_node_put(np); -#else - r.start = CPM_MAP_ADDR; - r.end = r.start + CPM_DATAONLY_BASE + CPM_DATAONLY_SIZE - 1; -#endif - - im_dprambase = ioremap(r.start, r.end - r.start + 1); - if (!im_dprambase) - panic("Cannot map DPRAM"); - spin_lock_init(&cpm_dpmem_lock); /* initialize the info header */ @@ -358,13 +344,15 @@ static void cpm2_dpinit(void) sizeof(cpm_boot_dpmem_rh_block[0]), cpm_boot_dpmem_rh_block); + im_dprambase = cpm2_immr; + /* Attach the usable dpmem area */ /* XXX: This is actually crap. CPM_DATAONLY_BASE and * CPM_DATAONLY_SIZE is only a subset of the available dpram. It * varies with the processor and the microcode patches activated. * But the following should be at least safe. */ - rh_attach_region(&cpm_dpmem_info, 0, r.end - r.start + 1); + rh_attach_region(&cpm_dpmem_info, CPM_DATAONLY_BASE, CPM_DATAONLY_SIZE); } /* This function returns an index into the DPRAM area. @@ -422,6 +410,7 @@ void *cpm_dpram_addr(unsigned long offset) return (void *)(im_dprambase + offset); } EXPORT_SYMBOL(cpm_dpram_addr); +#endif /* !CONFIG_PPC_CPM_NEW_BINDING */ struct cpm2_ioports { u32 dir, par, sor, odr, dat; diff --git a/arch/powerpc/sysdev/cpm_common.c b/arch/powerpc/sysdev/cpm_common.c index 9daa6ac6767..66c8ad4cfce 100644 --- a/arch/powerpc/sysdev/cpm_common.c +++ b/arch/powerpc/sysdev/cpm_common.c @@ -5,15 +5,27 @@ * * Copyright 2007 Freescale Semiconductor, Inc. * + * Some parts derived from commproc.c/cpm2_common.c, which is: + * Copyright (c) 1997 Dan error_act (dmalek@jlc.net) + * Copyright (c) 1999-2001 Dan Malek + * Copyright (c) 2000 MontaVista Software, Inc (source@mvista.com) + * 2006 (c) MontaVista Software, Inc. + * Vitaly Bordug + * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. */ #include +#include + #include #include #include +#include +#include + #include #ifdef CONFIG_PPC_EARLY_DEBUG_CPM @@ -41,6 +53,153 @@ void __init udbg_init_cpm(void) setbat(1, 0xf0000000, 0xf0000000, 1024*1024, _PAGE_IO); #endif udbg_putc = udbg_putc_cpm; + udbg_putc('X'); } } #endif + +#ifdef CONFIG_PPC_CPM_NEW_BINDING +static spinlock_t cpm_muram_lock; +static rh_block_t cpm_boot_muram_rh_block[16]; +static rh_info_t cpm_muram_info; +static u8 __iomem *muram_vbase; +static phys_addr_t muram_pbase; + +/* Max address size we deal with */ +#define OF_MAX_ADDR_CELLS 4 + +int __init cpm_muram_init(void) +{ + struct device_node *np; + struct resource r; + u32 zero[OF_MAX_ADDR_CELLS] = {}; + resource_size_t max = 0; + int i = 0; + int ret = 0; + + printk("cpm_muram_init\n"); + + spin_lock_init(&cpm_muram_lock); + /* initialize the info header */ + rh_init(&cpm_muram_info, 1, + sizeof(cpm_boot_muram_rh_block) / + sizeof(cpm_boot_muram_rh_block[0]), + cpm_boot_muram_rh_block); + + np = of_find_compatible_node(NULL, NULL, "fsl,cpm-muram-data"); + if (!np) { + printk(KERN_ERR "Cannot find CPM muram data node"); + ret = -ENODEV; + goto out; + } + + muram_pbase = of_translate_address(np, zero); + if (muram_pbase == (phys_addr_t)OF_BAD_ADDR) { + printk(KERN_ERR "Cannot translate zero through CPM muram node"); + ret = -ENODEV; + goto out; + } + + while (of_address_to_resource(np, i++, &r) == 0) { + if (r.end > max) + max = r.end; + + rh_attach_region(&cpm_muram_info, r.start - muram_pbase, + r.end - r.start + 1); + } + + muram_vbase = ioremap(muram_pbase, max - muram_pbase + 1); + if (!muram_vbase) { + printk(KERN_ERR "Cannot map CPM muram"); + ret = -ENOMEM; + } + +out: + of_node_put(np); + return ret; +} + +/** + * cpm_muram_alloc - allocate the requested size worth of multi-user ram + * @size: number of bytes to allocate + * @align: requested alignment, in bytes + * + * This function returns an offset into the muram area. + * Use cpm_dpram_addr() to get the virtual address of the area. + * Use cpm_muram_free() to free the allocation. + */ +unsigned long cpm_muram_alloc(unsigned long size, unsigned long align) +{ + unsigned long start; + unsigned long flags; + + spin_lock_irqsave(&cpm_muram_lock, flags); + cpm_muram_info.alignment = align; + start = rh_alloc(&cpm_muram_info, size, "commproc"); + spin_unlock_irqrestore(&cpm_muram_lock, flags); + + return start; +} +EXPORT_SYMBOL(cpm_muram_alloc); + +/** + * cpm_muram_free - free a chunk of multi-user ram + * @offset: The beginning of the chunk as returned by cpm_muram_alloc(). + */ +int cpm_muram_free(unsigned long offset) +{ + int ret; + unsigned long flags; + + spin_lock_irqsave(&cpm_muram_lock, flags); + ret = rh_free(&cpm_muram_info, offset); + spin_unlock_irqrestore(&cpm_muram_lock, flags); + + return ret; +} +EXPORT_SYMBOL(cpm_muram_free); + +/** + * cpm_muram_alloc_fixed - reserve a specific region of multi-user ram + * @offset: the offset into the muram area to reserve + * @size: the number of bytes to reserve + * + * This function returns "start" on success, -ENOMEM on failure. + * Use cpm_dpram_addr() to get the virtual address of the area. + * Use cpm_muram_free() to free the allocation. + */ +unsigned long cpm_muram_alloc_fixed(unsigned long offset, unsigned long size) +{ + unsigned long start; + unsigned long flags; + + spin_lock_irqsave(&cpm_muram_lock, flags); + cpm_muram_info.alignment = 1; + start = rh_alloc_fixed(&cpm_muram_info, offset, size, "commproc"); + spin_unlock_irqrestore(&cpm_muram_lock, flags); + + return start; +} +EXPORT_SYMBOL(cpm_muram_alloc_fixed); + +/** + * cpm_muram_addr - turn a muram offset into a virtual address + * @offset: muram offset to convert + */ +void __iomem *cpm_muram_addr(unsigned long offset) +{ + return muram_vbase + offset; +} +EXPORT_SYMBOL(cpm_muram_addr); + +/** + * cpm_muram_phys - turn a muram virtual address into a DMA address + * @offset: virtual address from cpm_muram_addr() to convert + */ +dma_addr_t cpm_muram_dma(void __iomem *addr) +{ + return muram_pbase + ((u8 __iomem *)addr - muram_vbase); +} +EXPORT_SYMBOL(cpm_muram_dma); + +#endif /* CONFIG_PPC_CPM_NEW_BINDING */ diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/serial/cpm_uart/cpm_uart_cpm2.c index 5bd4508ce3c..882dbc17d59 100644 --- a/drivers/serial/cpm_uart/cpm_uart_cpm2.c +++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.c @@ -235,7 +235,7 @@ void scc4_lineif(struct uart_cpm_port *pinfo) int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con) { int dpmemsz, memsz; - u8 *dp_mem; + u8 __iomem *dp_mem; unsigned long dp_offset; u8 *mem_addr; dma_addr_t dma_addr = 0; @@ -278,7 +278,7 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con) pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize); - pinfo->rx_bd_base = (cbd_t __iomem __force *)dp_mem; + pinfo->rx_bd_base = (cbd_t __iomem *)dp_mem; pinfo->tx_bd_base = pinfo->rx_bd_base + pinfo->rx_nrfifos; return 0; diff --git a/include/asm-powerpc/commproc.h b/include/asm-powerpc/commproc.h index 5dec32404fa..0307c84a5c1 100644 --- a/include/asm-powerpc/commproc.h +++ b/include/asm-powerpc/commproc.h @@ -19,6 +19,7 @@ #include #include +#include /* CPM Command register. */ @@ -54,6 +55,7 @@ #define mk_cr_cmd(CH, CMD) ((CMD << 8) | (CH << 4)) +#ifndef CONFIG_PPC_CPM_NEW_BINDING /* The dual ported RAM is multi-functional. Some areas can be (and are * being) used for microcode. There is an area that can only be used * as data ram for buffer descriptors, which is all we use right now. @@ -62,17 +64,27 @@ #define CPM_DATAONLY_BASE ((uint)0x0800) #define CPM_DATAONLY_SIZE ((uint)0x0700) #define CPM_DP_NOSPACE ((uint)0x7fffffff) +#endif /* Export the base address of the communication processor registers * and dual port ram. */ extern cpm8xx_t __iomem *cpmp; /* Pointer to comm processor */ + +#ifdef CONFIG_PPC_CPM_NEW_BINDING +#define cpm_dpalloc cpm_muram_alloc +#define cpm_dpfree cpm_muram_free +#define cpm_dpram_addr cpm_muram_addr +#define cpm_dpram_phys cpm_muram_dma +#else extern unsigned long cpm_dpalloc(uint size, uint align); extern int cpm_dpfree(unsigned long offset); extern unsigned long cpm_dpalloc_fixed(unsigned long offset, uint size, uint align); extern void cpm_dpdump(void); extern void *cpm_dpram_addr(unsigned long offset); extern uint cpm_dpram_phys(u8* addr); +#endif + extern void cpm_setbrg(uint brg, uint rate); extern uint m8xx_cpm_hostalloc(uint size); diff --git a/include/asm-powerpc/cpm.h b/include/asm-powerpc/cpm.h new file mode 100644 index 00000000000..48df9f330e7 --- /dev/null +++ b/include/asm-powerpc/cpm.h @@ -0,0 +1,14 @@ +#ifndef __CPM_H +#define __CPM_H + +#include +#include + +int cpm_muram_init(void); +unsigned long cpm_muram_alloc(unsigned long size, unsigned long align); +int cpm_muram_free(unsigned long offset); +unsigned long cpm_muram_alloc_fixed(unsigned long offset, unsigned long size); +void __iomem *cpm_muram_addr(unsigned long offset); +dma_addr_t cpm_muram_dma(void __iomem *addr); + +#endif diff --git a/include/asm-powerpc/cpm2.h b/include/asm-powerpc/cpm2.h index d7b57ac5589..e698b1d09dc 100644 --- a/include/asm-powerpc/cpm2.h +++ b/include/asm-powerpc/cpm2.h @@ -11,6 +11,7 @@ #define __CPM2__ #include +#include /* CPM Command register. */ @@ -82,6 +83,7 @@ #define mk_cr_cmd(PG, SBC, MCN, OP) \ ((PG << 26) | (SBC << 21) | (MCN << 6) | OP) +#ifndef CONFIG_PPC_CPM_NEW_BINDING /* Dual Port RAM addresses. The first 16K is available for almost * any CPM use, so we put the BDs there. The first 128 bytes are * used for SMC1 and SMC2 parameter RAM, so we start allocating @@ -97,6 +99,7 @@ #define CPM_DATAONLY_SIZE ((uint)(16 * 1024) - CPM_DATAONLY_BASE) #define CPM_FCC_SPECIAL_BASE ((uint)0x0000b000) #endif +#endif /* The number of pages of host memory we allocate for CPM. This is * done early in kernel initialization to get physically contiguous @@ -109,11 +112,18 @@ */ extern cpm_cpm2_t __iomem *cpmp; /* Pointer to comm processor */ +#ifdef CONFIG_PPC_CPM_NEW_BINDING +#define cpm_dpalloc cpm_muram_alloc +#define cpm_dpfree cpm_muram_free +#define cpm_dpram_addr cpm_muram_addr +#else extern unsigned long cpm_dpalloc(uint size, uint align); extern int cpm_dpfree(unsigned long offset); extern unsigned long cpm_dpalloc_fixed(unsigned long offset, uint size, uint align); extern void cpm_dpdump(void); extern void *cpm_dpram_addr(unsigned long offset); +#endif + extern void cpm_setbrg(uint brg, uint rate); extern void cpm2_fastbrg(uint brg, uint rate, int div16); extern void cpm2_reset(void); -- cgit v1.2.3-70-g09d2 From 8122c6cea033e8034e99d3b10a4e3f377ce23994 Mon Sep 17 00:00:00 2001 From: Thomas Renninger Date: Tue, 2 Oct 2007 13:28:09 -0700 Subject: [CPUFREQ] move policy's governor initialisation out of low-level drivers into cpufreq core Signed-off-by: Thomas Renninger Signed-off-by: Venkatesh Pallipadi Cc: Russell King Cc: Bryan Wu Cc: Andi Kleen Cc: "Luck, Tony" Cc: Paul Mackerras Cc: Benjamin Herrenschmidt Cc: Paul Mundt Cc: "David S. Miller" Signed-off-by: Andrew Morton Signed-off-by: Dave Jones --- arch/arm/mach-imx/cpufreq.c | 1 - arch/arm/mach-sa1100/cpu-sa1110.c | 1 - arch/arm/plat-omap/cpu-omap.c | 1 - arch/blackfin/mach-bf533/cpu.c | 2 -- arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c | 1 - arch/i386/kernel/cpu/cpufreq/cpufreq-nforce2.c | 1 - arch/i386/kernel/cpu/cpufreq/e_powersaver.c | 1 - arch/i386/kernel/cpu/cpufreq/elanfreq.c | 1 - arch/i386/kernel/cpu/cpufreq/gx-suspmod.c | 1 - arch/i386/kernel/cpu/cpufreq/longhaul.c | 1 - arch/i386/kernel/cpu/cpufreq/p4-clockmod.c | 1 - arch/i386/kernel/cpu/cpufreq/powernow-k6.c | 1 - arch/i386/kernel/cpu/cpufreq/powernow-k7.c | 2 -- arch/i386/kernel/cpu/cpufreq/powernow-k8.c | 1 - arch/i386/kernel/cpu/cpufreq/sc520_freq.c | 1 - arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c | 1 - arch/i386/kernel/cpu/cpufreq/speedstep-ich.c | 1 - arch/i386/kernel/cpu/cpufreq/speedstep-smi.c | 1 - arch/ia64/kernel/cpufreq/acpi-cpufreq.c | 2 -- arch/powerpc/platforms/cell/cbe_cpufreq.c | 2 -- arch/powerpc/platforms/pasemi/cpufreq.c | 2 -- arch/powerpc/platforms/powermac/cpufreq_32.c | 1 - arch/powerpc/platforms/powermac/cpufreq_64.c | 1 - arch/sh/kernel/cpufreq.c | 1 - arch/sparc64/kernel/us2e_cpufreq.c | 1 - drivers/cpufreq/cpufreq.c | 2 ++ 26 files changed, 2 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/arch/arm/mach-imx/cpufreq.c b/arch/arm/mach-imx/cpufreq.c index 467d899fbe7..e548ba74a4d 100644 --- a/arch/arm/mach-imx/cpufreq.c +++ b/arch/arm/mach-imx/cpufreq.c @@ -269,7 +269,6 @@ static int __init imx_cpufreq_driver_init(struct cpufreq_policy *policy) return -EINVAL; policy->cur = policy->min = policy->max = imx_get_speed(0); - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->cpuinfo.min_freq = 8000; policy->cpuinfo.max_freq = 200000; /* Manual states, that PLL stabilizes in two CLK32 periods */ diff --git a/arch/arm/mach-sa1100/cpu-sa1110.c b/arch/arm/mach-sa1100/cpu-sa1110.c index 78f4c134604..36b47ff5af1 100644 --- a/arch/arm/mach-sa1100/cpu-sa1110.c +++ b/arch/arm/mach-sa1100/cpu-sa1110.c @@ -331,7 +331,6 @@ static int __init sa1110_cpu_init(struct cpufreq_policy *policy) if (policy->cpu != 0) return -EINVAL; policy->cur = policy->min = policy->max = sa11x0_getspeed(0); - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->cpuinfo.min_freq = 59000; policy->cpuinfo.max_freq = 287000; policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; diff --git a/arch/arm/plat-omap/cpu-omap.c b/arch/arm/plat-omap/cpu-omap.c index a0c71dca237..c0d63b0c61c 100644 --- a/arch/arm/plat-omap/cpu-omap.c +++ b/arch/arm/plat-omap/cpu-omap.c @@ -108,7 +108,6 @@ static int __init omap_cpu_init(struct cpufreq_policy *policy) if (policy->cpu != 0) return -EINVAL; policy->cur = policy->min = policy->max = omap_getspeed(0); - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->cpuinfo.min_freq = clk_round_rate(mpu_clk, 0) / 1000; policy->cpuinfo.max_freq = clk_round_rate(mpu_clk, VERY_HI_RATE) / 1000; policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; diff --git a/arch/blackfin/mach-bf533/cpu.c b/arch/blackfin/mach-bf533/cpu.c index 6fd9cfd0a31..b7a0e0fbd9a 100644 --- a/arch/blackfin/mach-bf533/cpu.c +++ b/arch/blackfin/mach-bf533/cpu.c @@ -118,8 +118,6 @@ static int __init __bf533_cpu_init(struct cpufreq_policy *policy) if (policy->cpu != 0) return -EINVAL; - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; - policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; /*Now ,only support one cpu */ policy->cur = bf533_getfreq(0); diff --git a/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c index 705e13a3078..42115b609f6 100644 --- a/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c +++ b/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c @@ -646,7 +646,6 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) policy->cpuinfo.transition_latency = perf->states[i].transition_latency * 1000; } - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; data->max_freq = perf->states[0].core_frequency * 1000; /* table init */ diff --git a/arch/i386/kernel/cpu/cpufreq/cpufreq-nforce2.c b/arch/i386/kernel/cpu/cpufreq/cpufreq-nforce2.c index 66acd503991..32f0bda3fc9 100644 --- a/arch/i386/kernel/cpu/cpufreq/cpufreq-nforce2.c +++ b/arch/i386/kernel/cpu/cpufreq/cpufreq-nforce2.c @@ -363,7 +363,6 @@ static int nforce2_cpu_init(struct cpufreq_policy *policy) policy->cur = nforce2_get(policy->cpu); policy->min = policy->cpuinfo.min_freq; policy->max = policy->cpuinfo.max_freq; - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; return 0; } diff --git a/arch/i386/kernel/cpu/cpufreq/e_powersaver.c b/arch/i386/kernel/cpu/cpufreq/e_powersaver.c index f43d98e11cc..c11baaf9f2b 100644 --- a/arch/i386/kernel/cpu/cpufreq/e_powersaver.c +++ b/arch/i386/kernel/cpu/cpufreq/e_powersaver.c @@ -253,7 +253,6 @@ static int eps_cpu_init(struct cpufreq_policy *policy) f_table[k].frequency = CPUFREQ_TABLE_END; } - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->cpuinfo.transition_latency = 140000; /* 844mV -> 700mV in ns */ policy->cur = fsb * current_multiplier; diff --git a/arch/i386/kernel/cpu/cpufreq/elanfreq.c b/arch/i386/kernel/cpu/cpufreq/elanfreq.c index f317276afa7..1e7ae7dafcf 100644 --- a/arch/i386/kernel/cpu/cpufreq/elanfreq.c +++ b/arch/i386/kernel/cpu/cpufreq/elanfreq.c @@ -219,7 +219,6 @@ static int elanfreq_cpu_init(struct cpufreq_policy *policy) } /* cpuinfo and default policy values */ - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; policy->cur = elanfreq_get_cpu_frequency(0); diff --git a/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c b/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c index 461dabc4e49..ed2bda127c4 100644 --- a/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c +++ b/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c @@ -420,7 +420,6 @@ static int cpufreq_gx_cpu_init(struct cpufreq_policy *policy) policy->min = maxfreq / POLICY_MIN_DIV; policy->max = maxfreq; policy->cur = curfreq; - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->cpuinfo.min_freq = maxfreq / max_duration; policy->cpuinfo.max_freq = maxfreq; policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; diff --git a/arch/i386/kernel/cpu/cpufreq/longhaul.c b/arch/i386/kernel/cpu/cpufreq/longhaul.c index 58816facc43..a2fbfd912a0 100644 --- a/arch/i386/kernel/cpu/cpufreq/longhaul.c +++ b/arch/i386/kernel/cpu/cpufreq/longhaul.c @@ -877,7 +877,6 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy) if ((longhaul_version != TYPE_LONGHAUL_V1) && (scale_voltage != 0)) longhaul_setup_voltagescaling(); - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->cpuinfo.transition_latency = 200000; /* nsec */ policy->cur = calc_speed(longhaul_get_cpu_mult()); diff --git a/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c b/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c index 4c76b511e19..8eb414b906d 100644 --- a/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c +++ b/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c @@ -229,7 +229,6 @@ static int cpufreq_p4_cpu_init(struct cpufreq_policy *policy) cpufreq_frequency_table_get_attr(p4clockmod_table, policy->cpu); /* cpuinfo and default policy values */ - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->cpuinfo.transition_latency = 1000000; /* assumed */ policy->cur = stock_freq; diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k6.c b/arch/i386/kernel/cpu/cpufreq/powernow-k6.c index f89524051e4..6d028533931 100644 --- a/arch/i386/kernel/cpu/cpufreq/powernow-k6.c +++ b/arch/i386/kernel/cpu/cpufreq/powernow-k6.c @@ -160,7 +160,6 @@ static int powernow_k6_cpu_init(struct cpufreq_policy *policy) } /* cpuinfo and default policy values */ - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; policy->cur = busfreq * max_multiplier; diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k7.c b/arch/i386/kernel/cpu/cpufreq/powernow-k7.c index ca3e1d34188..7decd6a50ff 100644 --- a/arch/i386/kernel/cpu/cpufreq/powernow-k7.c +++ b/arch/i386/kernel/cpu/cpufreq/powernow-k7.c @@ -637,8 +637,6 @@ static int __init powernow_cpu_init (struct cpufreq_policy *policy) printk (KERN_INFO PFX "Minimum speed %d MHz. Maximum speed %d MHz.\n", minimum_speed/1000, maximum_speed/1000); - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; - policy->cpuinfo.transition_latency = cpufreq_scale(2000000UL, fsb, latency); policy->cur = powernow_get(0); diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c index 372df6e67e8..f2a65a9609f 100644 --- a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c +++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c @@ -1208,7 +1208,6 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol) /* run on any CPU again */ set_cpus_allowed(current, oldmask); - pol->governor = CPUFREQ_DEFAULT_GOVERNOR; if (cpu_family == CPU_HW_PSTATE) pol->cpus = cpumask_of_cpu(pol->cpu); else diff --git a/arch/i386/kernel/cpu/cpufreq/sc520_freq.c b/arch/i386/kernel/cpu/cpufreq/sc520_freq.c index b8fb4b521c6..d9f3e90a7ae 100644 --- a/arch/i386/kernel/cpu/cpufreq/sc520_freq.c +++ b/arch/i386/kernel/cpu/cpufreq/sc520_freq.c @@ -111,7 +111,6 @@ static int sc520_freq_cpu_init(struct cpufreq_policy *policy) return -ENODEV; /* cpuinfo and default policy values */ - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->cpuinfo.transition_latency = 1000000; /* 1ms */ policy->cur = sc520_freq_get_cpu_frequency(0); diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c index 6c5dc2c85ae..811d4743854 100644 --- a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c +++ b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c @@ -393,7 +393,6 @@ static int centrino_cpu_init(struct cpufreq_policy *policy) freq = get_cur_freq(policy->cpu); - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->cpuinfo.transition_latency = 10000; /* 10uS transition latency */ policy->cur = freq; diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-ich.c b/arch/i386/kernel/cpu/cpufreq/speedstep-ich.c index a5b2346faf1..36685e8f7be 100644 --- a/arch/i386/kernel/cpu/cpufreq/speedstep-ich.c +++ b/arch/i386/kernel/cpu/cpufreq/speedstep-ich.c @@ -348,7 +348,6 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy) (speed / 1000)); /* cpuinfo and default policy values */ - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->cur = speed; result = cpufreq_frequency_table_cpuinfo(policy, speedstep_freqs); diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c b/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c index e1c509aa305..f2b5a621d27 100644 --- a/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c +++ b/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c @@ -290,7 +290,6 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy) (speed / 1000)); /* cpuinfo and default policy values */ - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; policy->cur = speed; diff --git a/arch/ia64/kernel/cpufreq/acpi-cpufreq.c b/arch/ia64/kernel/cpufreq/acpi-cpufreq.c index 8c6ec707084..b8498ea6206 100644 --- a/arch/ia64/kernel/cpufreq/acpi-cpufreq.c +++ b/arch/ia64/kernel/cpufreq/acpi-cpufreq.c @@ -321,8 +321,6 @@ acpi_cpufreq_cpu_init ( data->acpi_data.states[i].transition_latency * 1000; } } - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; - policy->cur = processor_get_freq(data, policy->cpu); /* table init */ diff --git a/arch/powerpc/platforms/cell/cbe_cpufreq.c b/arch/powerpc/platforms/cell/cbe_cpufreq.c index 0b6e8ee85ab..c50ad22bf73 100644 --- a/arch/powerpc/platforms/cell/cbe_cpufreq.c +++ b/arch/powerpc/platforms/cell/cbe_cpufreq.c @@ -107,8 +107,6 @@ static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy) pr_debug("%d: %d\n", i, cbe_freqs[i].frequency); } - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; - /* if DEBUG is enabled set_pmode() measures the latency * of a transition */ policy->cpuinfo.transition_latency = 25000; diff --git a/arch/powerpc/platforms/pasemi/cpufreq.c b/arch/powerpc/platforms/pasemi/cpufreq.c index 3ae083851b0..1cfb8b0c8fe 100644 --- a/arch/powerpc/platforms/pasemi/cpufreq.c +++ b/arch/powerpc/platforms/pasemi/cpufreq.c @@ -195,8 +195,6 @@ static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy) pr_debug("%d: %d\n", i, pas_freqs[i].frequency); } - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; - policy->cpuinfo.transition_latency = get_gizmo_latency(); cur_astate = get_cur_astate(policy->cpu); diff --git a/arch/powerpc/platforms/powermac/cpufreq_32.c b/arch/powerpc/platforms/powermac/cpufreq_32.c index 1fe35dab0e9..c04abcc28a7 100644 --- a/arch/powerpc/platforms/powermac/cpufreq_32.c +++ b/arch/powerpc/platforms/powermac/cpufreq_32.c @@ -410,7 +410,6 @@ static int pmac_cpufreq_cpu_init(struct cpufreq_policy *policy) if (policy->cpu != 0) return -ENODEV; - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; policy->cur = cur_freq; diff --git a/arch/powerpc/platforms/powermac/cpufreq_64.c b/arch/powerpc/platforms/powermac/cpufreq_64.c index 00f50298c34..4dfb4bc242b 100644 --- a/arch/powerpc/platforms/powermac/cpufreq_64.c +++ b/arch/powerpc/platforms/powermac/cpufreq_64.c @@ -357,7 +357,6 @@ static unsigned int g5_cpufreq_get_speed(unsigned int cpu) static int g5_cpufreq_cpu_init(struct cpufreq_policy *policy) { - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; policy->cur = g5_cpu_freqs[g5_query_freq()].frequency; /* secondary CPUs are tied to the primary one by the diff --git a/arch/sh/kernel/cpufreq.c b/arch/sh/kernel/cpufreq.c index e61890217c5..71d1c427b90 100644 --- a/arch/sh/kernel/cpufreq.c +++ b/arch/sh/kernel/cpufreq.c @@ -93,7 +93,6 @@ static int sh_cpufreq_cpu_init(struct cpufreq_policy *policy) policy->cpuinfo.max_freq = (clk_round_rate(cpuclk, ~0UL) + 500) / 1000; policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->cur = sh_cpufreq_get(policy->cpu); policy->min = policy->cpuinfo.min_freq; policy->max = policy->cpuinfo.max_freq; diff --git a/arch/sparc64/kernel/us2e_cpufreq.c b/arch/sparc64/kernel/us2e_cpufreq.c index 1f83fe6a82d..791c15138f3 100644 --- a/arch/sparc64/kernel/us2e_cpufreq.c +++ b/arch/sparc64/kernel/us2e_cpufreq.c @@ -326,7 +326,6 @@ static int __init us2e_freq_cpu_init(struct cpufreq_policy *policy) table[2].index = 5; table[3].frequency = CPUFREQ_TABLE_END; - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->cpuinfo.transition_latency = 0; policy->cur = clock_tick; diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 2f6a73c01b7..9528bd57736 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -763,6 +763,8 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) init_completion(&policy->kobj_unregister); INIT_WORK(&policy->update, handle_update); + /* Set governor before ->init, so that driver could check it */ + policy->governor = CPUFREQ_DEFAULT_GOVERNOR; /* call driver. From then on the cpufreq must be able * to accept all calls to ->verify and ->setpolicy for this CPU */ -- cgit v1.2.3-70-g09d2 From 1c2562459faedc35927546cfa5273ec6c2884cce Mon Sep 17 00:00:00 2001 From: Thomas Renninger Date: Tue, 2 Oct 2007 13:28:12 -0700 Subject: [CPUFREQ] allow ondemand and conservative cpufreq governors to be used as default Depending on the transition latency of the HW for cpufreq switches, the ondemand or conservative governor cannot be used with certain cpufreq drivers. Still the ondemand should be the default governor on a wide range of systems. This patch allows this and lets the governor fallback to the performance governor at cpufreq driver load time, if the driver does not support fast enough frequency switching. Main benefit is that on e.g. installation or other systems without userspace support a working dynamic cpufreq support can be achieved on most systems by simply loading the cpufreq driver. This is especially essential for recent x86(_64) laptop hardware which may rely on working dynamic cpufreq OS support. Signed-off-by: Thomas Renninger Signed-off-by: Venkatesh Pallipadi Cc: Russell King Cc: Bryan Wu Cc: Andi Kleen Cc: "Luck, Tony" Cc: Paul Mackerras Cc: Benjamin Herrenschmidt Cc: Paul Mundt Cc: "David S. Miller" Signed-off-by: Andrew Morton Signed-off-by: Dave Jones --- drivers/cpufreq/Kconfig | 27 +++++++++++++++++++++++---- drivers/cpufreq/cpufreq.c | 12 ++++++++++++ drivers/cpufreq/cpufreq_conservative.c | 19 +++++++++---------- drivers/cpufreq/cpufreq_ondemand.c | 22 +++++++++------------- include/linux/cpufreq.h | 20 +++++++++++++++++--- 5 files changed, 70 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index 993fa7b8925..721f86f4f00 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -56,10 +56,6 @@ config CPU_FREQ_STAT_DETAILS If in doubt, say N. -# Note that it is not currently possible to set the other governors (such as ondemand) -# as the default, since if they fail to initialise, cpufreq will be -# left in an undefined state. - choice prompt "Default CPUFreq governor" default CPU_FREQ_DEFAULT_GOV_USERSPACE if CPU_FREQ_SA1100 || CPU_FREQ_SA1110 @@ -85,6 +81,29 @@ config CPU_FREQ_DEFAULT_GOV_USERSPACE program shall be able to set the CPU dynamically without having to enable the userspace governor manually. +config CPU_FREQ_DEFAULT_GOV_ONDEMAND + bool "ondemand" + select CPU_FREQ_GOV_ONDEMAND + select CPU_FREQ_GOV_PERFORMANCE + help + Use the CPUFreq governor 'ondemand' as default. This allows + you to get a full dynamic frequency capable system by simply + loading your cpufreq low-level hardware driver. + Be aware that not all cpufreq drivers support the ondemand + governor. If unsure have a look at the help section of the + driver. Fallback governor will be the performance governor. + +config CPU_FREQ_DEFAULT_GOV_CONSERVATIVE + bool "conservative" + select CPU_FREQ_GOV_CONSERVATIVE + select CPU_FREQ_GOV_PERFORMANCE + help + Use the CPUFreq governor 'conservative' as default. This allows + you to get a full dynamic frequency capable system by simply + loading your cpufreq low-level hardware driver. + Be aware that not all cpufreq drivers support the conservative + governor. If unsure have a look at the help section of the + driver. Fallback governor will be the performance governor. endchoice config CPU_FREQ_GOV_PERFORMANCE diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 9528bd57736..418522f88f7 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1484,6 +1484,18 @@ static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event) { int ret; + struct cpufreq_governor *gov = CPUFREQ_PERFORMANCE_GOVERNOR; + + if (policy->governor->max_transition_latency && + policy->cpuinfo.transition_latency > + policy->governor->max_transition_latency) { + printk(KERN_WARNING "%s governor failed, too long" + " transition latency of HW, fallback" + " to %s governor\n", + policy->governor->name, + gov->name); + policy->governor = gov; + } if (!try_module_get(policy->governor->owner)) return -EINVAL; diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index 26f440ccc3f..4bd33ce8a6f 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c @@ -58,7 +58,7 @@ static unsigned int def_sampling_rate; #define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER (1000) #define DEF_SAMPLING_DOWN_FACTOR (1) #define MAX_SAMPLING_DOWN_FACTOR (10) -#define TRANSITION_LATENCY_LIMIT (10 * 1000) +#define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000) static void do_dbs_timer(struct work_struct *work); @@ -466,9 +466,6 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy, (!policy->cur)) return -EINVAL; - if (policy->cpuinfo.transition_latency > - (TRANSITION_LATENCY_LIMIT * 1000)) - return -EINVAL; if (this_dbs_info->enable) /* Already enabled */ break; @@ -551,15 +548,17 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy, return 0; } -static struct cpufreq_governor cpufreq_gov_dbs = { - .name = "conservative", - .governor = cpufreq_governor_dbs, - .owner = THIS_MODULE, +struct cpufreq_governor cpufreq_gov_conservative = { + .name = "conservative", + .governor = cpufreq_governor_dbs, + .max_transition_latency = TRANSITION_LATENCY_LIMIT, + .owner = THIS_MODULE, }; +EXPORT_SYMBOL(cpufreq_gov_conservative); static int __init cpufreq_gov_dbs_init(void) { - return cpufreq_register_governor(&cpufreq_gov_dbs); + return cpufreq_register_governor(&cpufreq_gov_conservative); } static void __exit cpufreq_gov_dbs_exit(void) @@ -567,7 +566,7 @@ static void __exit cpufreq_gov_dbs_exit(void) /* Make sure that the scheduled work is indeed not running */ flush_scheduled_work(); - cpufreq_unregister_governor(&cpufreq_gov_dbs); + cpufreq_unregister_governor(&cpufreq_gov_conservative); } diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index e794527e492..369f4459515 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -47,7 +47,7 @@ static unsigned int def_sampling_rate; (def_sampling_rate / MIN_SAMPLING_RATE_RATIO) #define MAX_SAMPLING_RATE (500 * def_sampling_rate) #define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER (1000) -#define TRANSITION_LATENCY_LIMIT (10 * 1000) +#define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000) static void do_dbs_timer(struct work_struct *work); @@ -508,12 +508,6 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy, if ((!cpu_online(cpu)) || (!policy->cur)) return -EINVAL; - if (policy->cpuinfo.transition_latency > - (TRANSITION_LATENCY_LIMIT * 1000)) { - printk(KERN_WARNING "ondemand governor failed to load " - "due to too long transition latency\n"); - return -EINVAL; - } if (this_dbs_info->enable) /* Already enabled */ break; @@ -585,11 +579,13 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy, return 0; } -static struct cpufreq_governor cpufreq_gov_dbs = { - .name = "ondemand", - .governor = cpufreq_governor_dbs, - .owner = THIS_MODULE, +struct cpufreq_governor cpufreq_gov_ondemand = { + .name = "ondemand", + .governor = cpufreq_governor_dbs, + .max_transition_latency = TRANSITION_LATENCY_LIMIT, + .owner = THIS_MODULE, }; +EXPORT_SYMBOL(cpufreq_gov_ondemand); static int __init cpufreq_gov_dbs_init(void) { @@ -598,12 +594,12 @@ static int __init cpufreq_gov_dbs_init(void) printk(KERN_ERR "Creation of kondemand failed\n"); return -EFAULT; } - return cpufreq_register_governor(&cpufreq_gov_dbs); + return cpufreq_register_governor(&cpufreq_gov_ondemand); } static void __exit cpufreq_gov_dbs_exit(void) { - cpufreq_unregister_governor(&cpufreq_gov_dbs); + cpufreq_unregister_governor(&cpufreq_gov_ondemand); destroy_workqueue(kondemand_wq); } diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 3ec6e7ff5fb..9e5f5d0c87f 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -155,6 +155,9 @@ struct cpufreq_governor { char name[CPUFREQ_NAME_LEN]; int (*governor) (struct cpufreq_policy *policy, unsigned int event); + unsigned int max_transition_latency; /* HW must be able to switch to + next freq faster than this value in nano secs or we + will fallback to performance governor */ struct list_head governor_list; struct module *owner; }; @@ -279,12 +282,23 @@ static inline unsigned int cpufreq_quick_get(unsigned int cpu) *********************************************************************/ -#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE +/* + Performance governor is fallback governor if any other gov failed to + auto load due latency restrictions +*/ extern struct cpufreq_governor cpufreq_gov_performance; -#define CPUFREQ_DEFAULT_GOVERNOR &cpufreq_gov_performance +#define CPUFREQ_PERFORMANCE_GOVERNOR (&cpufreq_gov_performance) +#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE +#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_performance) #elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE) extern struct cpufreq_governor cpufreq_gov_userspace; -#define CPUFREQ_DEFAULT_GOVERNOR &cpufreq_gov_userspace +#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_userspace) +#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND) +extern struct cpufreq_governor cpufreq_gov_ondemand; +#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_ondemand) +#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE) +extern struct cpufreq_governor cpufreq_gov_conservative; +#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_conservative) #endif -- cgit v1.2.3-70-g09d2 From 6afde10c3f58cc3ac593f5b4505b8b1cf719f5d6 Mon Sep 17 00:00:00 2001 From: Thomas Renninger Date: Tue, 2 Oct 2007 13:28:13 -0700 Subject: [CPUFREQ] Only check for transition latency on problematic governors (kconfig fix) Cc: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Dave Jones --- drivers/cpufreq/cpufreq.c | 27 ++++++++++++++++++++------- include/linux/cpufreq.h | 3 ++- 2 files changed, 22 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 418522f88f7..65ac5851122 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1484,17 +1484,30 @@ static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event) { int ret; - struct cpufreq_governor *gov = CPUFREQ_PERFORMANCE_GOVERNOR; + + /* Only must be defined when default governor is known to have latency + restrictions, like e.g. conservative or ondemand. + That this is the case is already ensured in Kconfig + */ +#ifdef CONFIG_CPU_FREQ_GOV_PERFORMANCE + struct cpufreq_governor *gov = &cpufreq_gov_performance; +#else + struct cpufreq_governor *gov = NULL; +#endif if (policy->governor->max_transition_latency && policy->cpuinfo.transition_latency > policy->governor->max_transition_latency) { - printk(KERN_WARNING "%s governor failed, too long" - " transition latency of HW, fallback" - " to %s governor\n", - policy->governor->name, - gov->name); - policy->governor = gov; + if (!gov) + return -EINVAL; + else { + printk(KERN_WARNING "%s governor failed, too long" + " transition latency of HW, fallback" + " to %s governor\n", + policy->governor->name, + gov->name); + policy->governor = gov; + } } if (!try_module_get(policy->governor->owner)) diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 9e5f5d0c87f..450a841b589 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -286,8 +286,9 @@ static inline unsigned int cpufreq_quick_get(unsigned int cpu) Performance governor is fallback governor if any other gov failed to auto load due latency restrictions */ +#ifdef CONFIG_CPU_FREQ_GOV_PERFORMANCE extern struct cpufreq_governor cpufreq_gov_performance; -#define CPUFREQ_PERFORMANCE_GOVERNOR (&cpufreq_gov_performance) +#endif #ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE #define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_performance) #elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE) -- cgit v1.2.3-70-g09d2 From dd184a01b8ece6bac2f7a63de99a4a4d29552746 Mon Sep 17 00:00:00 2001 From: Satyam Sharma Date: Tue, 2 Oct 2007 13:28:14 -0700 Subject: [CPUFREQ] mark hotplug notifier callback as __cpuinit The notifier_block is already __cpuinitdata, thereby allowing us to safely mark the callback function as __cpuinit also, thereby saving space when HOTPLUG_CPU=n. Signed-off-by: Satyam Sharma Signed-off-by: Andrew Morton Signed-off-by: Dave Jones --- drivers/cpufreq/cpufreq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 65ac5851122..e027052a660 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1730,7 +1730,7 @@ int cpufreq_update_policy(unsigned int cpu) } EXPORT_SYMBOL(cpufreq_update_policy); -static int cpufreq_cpu_callback(struct notifier_block *nfb, +static int __cpuinit cpufreq_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) { unsigned int cpu = (unsigned long)hcpu; -- cgit v1.2.3-70-g09d2 From 55395ae72b6e5ae614d28df74158c47454652583 Mon Sep 17 00:00:00 2001 From: Satyam Sharma Date: Tue, 2 Oct 2007 13:28:15 -0700 Subject: [CPUFREQ] cpufreq_stats: misc cpuinit section annotations * Stop referencing the callback directly from the __init and __exit functions of this driver, and instead explicitly call cpufreq_update_policy() et al. This enables the callback function to be marked as __cpuinit (and the notifier_block __cpuinitdata), thereby saving space when HOTPLUG_CPU=n. This also enables us to use other tricks to replace __cpuinit{data} in future. * cpufreq_stats_free_table() is only called from __cpuinit or __exit marked functions, making it an ideal candidate for __cpuexit. * Fix missing space in the module description Signed-off-by: Satyam Sharma Signed-off-by: Andrew Morton Signed-off-by: Dave Jones --- drivers/cpufreq/cpufreq_stats.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 917b9bab9cc..8a45d0f93e2 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -164,8 +164,7 @@ freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq) return -1; } -static void -cpufreq_stats_free_table (unsigned int cpu) +static void __cpuexit cpufreq_stats_free_table(unsigned int cpu) { struct cpufreq_stats *stat = cpufreq_stats_table[cpu]; struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); @@ -305,8 +304,9 @@ cpufreq_stat_notifier_trans (struct notifier_block *nb, unsigned long val, return 0; } -static int cpufreq_stat_cpu_callback(struct notifier_block *nfb, - unsigned long action, void *hcpu) +static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb, + unsigned long action, + void *hcpu) { unsigned int cpu = (unsigned long)hcpu; @@ -323,7 +323,7 @@ static int cpufreq_stat_cpu_callback(struct notifier_block *nfb, return NOTIFY_OK; } -static struct notifier_block cpufreq_stat_cpu_notifier = +static struct notifier_block cpufreq_stat_cpu_notifier __cpuinitdata = { .notifier_call = cpufreq_stat_cpu_callback, }; @@ -356,8 +356,7 @@ __init cpufreq_stats_init(void) register_hotcpu_notifier(&cpufreq_stat_cpu_notifier); for_each_online_cpu(cpu) { - cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier, - CPU_ONLINE, (void *)(long)cpu); + cpufreq_update_policy(cpu); } return 0; } @@ -372,13 +371,12 @@ __exit cpufreq_stats_exit(void) CPUFREQ_TRANSITION_NOTIFIER); unregister_hotcpu_notifier(&cpufreq_stat_cpu_notifier); for_each_online_cpu(cpu) { - cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier, - CPU_DEAD, (void *)(long)cpu); + cpufreq_stats_free_table(cpu); } } MODULE_AUTHOR ("Zou Nan hai "); -MODULE_DESCRIPTION ("'cpufreq_stats' - A driver to export cpufreq stats" +MODULE_DESCRIPTION ("'cpufreq_stats' - A driver to export cpufreq stats " "through sysfs filesystem"); MODULE_LICENSE ("GPL"); -- cgit v1.2.3-70-g09d2 From 3e01e4bcdd56209e70c39293e0c4c355d09364b8 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Wed, 3 Oct 2007 15:32:10 -0400 Subject: sdio: fix IRQ diagnostic message If func is actually null we won't get much from sdio_func_id(func). Signed-off-by: Nicolas Pitre Signed-off-by: Pierre Ossman --- drivers/mmc/core/sdio_irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c index f78ffeefed5..e7865059e12 100644 --- a/drivers/mmc/core/sdio_irq.c +++ b/drivers/mmc/core/sdio_irq.c @@ -44,7 +44,7 @@ static int process_sdio_pending_irqs(struct mmc_card *card) if (!func) { printk(KERN_WARNING "%s: pending IRQ for " "non-existant function\n", - sdio_func_id(func)); + mmc_card_id(card)); } else if (func->irq_handler) { func->irq_handler(func); count++; -- cgit v1.2.3-70-g09d2 From 599473cf15a3fae78cbc3192cfb38ca04d5abc72 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Wed, 3 Oct 2007 15:32:57 -0400 Subject: sdio: make the IRQ thread more resilient in the presence of bad states Currently we print a message about some bad states wrt function IRQ handlers but return 0 from process_sdio_pending_irqs() nevertheless. This can lead to an infinite loop as nothing might have cleared the condition for the pending card interrupt from the host controller by the time host->ops->enable_sdio_irq(host, 1) is called. Signed-off-by: Nicolas Pitre Signed-off-by: Pierre Ossman --- drivers/mmc/core/sdio_irq.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c index e7865059e12..3bd3021f5e8 100644 --- a/drivers/mmc/core/sdio_irq.c +++ b/drivers/mmc/core/sdio_irq.c @@ -45,16 +45,22 @@ static int process_sdio_pending_irqs(struct mmc_card *card) printk(KERN_WARNING "%s: pending IRQ for " "non-existant function\n", mmc_card_id(card)); + ret = -EINVAL; } else if (func->irq_handler) { func->irq_handler(func); count++; - } else + } else { printk(KERN_WARNING "%s: pending IRQ with no handler\n", sdio_func_id(func)); + ret = -EINVAL; + } } } - return count; + if (count) + return count; + + return ret; } static int sdio_irq_thread(void *_host) -- cgit v1.2.3-70-g09d2 From 6b0b594bb81f86dbc7b0829ee5102abaab242913 Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Wed, 3 Oct 2007 11:34:59 -0500 Subject: [POWERPC] qe: miscellaneous code improvements and fixes to the QE library This patch makes numerous miscellaneous code improvements to the QE library. 1. Remove struct ucc_common and merge ucc_init_guemr() into ucc_set_type() (every caller of ucc_init_guemr() also calls ucc_set_type()). Modify all callers of ucc_set_type() accordingly. 2. Remove the unused enum ucc_pram_initial_offset. 3. Refactor qe_setbrg(), also implement work-around for errata QE_General4. 4. Several printk() calls were missing the terminating \n. 5. Add __iomem where needed, and change u16 to __be16 and u32 to __be32 where appropriate. 6. In ucc_slow_init() the RBASE and TBASE registers in the PRAM were programmed with the wrong value. 7. Add the protocol type to struct us_info and updated ucc_slow_init() to use it, instead of always programming QE_CR_PROTOCOL_UNSPECIFIED. 8. Rename ucc_slow_restart_x() to ucc_slow_restart_tx() 9. Add several macros in qe.h (mostly for slow UCC support, but also to standardize some naming convention) and remove several unused macros. 10. Update ucc_geth.c to use the new macros. 11. Add ucc_slow_info.protocol to specify which QE_CR_PROTOCOL_xxx protcol to use when initializing the UCC in ucc_slow_init(). 12. Rename ucc_slow_pram.rfcr to rbmr and ucc_slow_pram.tfcr to tbmr, since these are the real names of the registers. 13. Use the setbits, clrbits, and clrsetbits where appropriate. 14. Refactor ucc_set_qe_mux_rxtx(). 15. Remove all instances of 'volatile'. 16. Simplify get_cmxucr_reg(); 17. Replace qe_mux.cmxucrX with qe_mux.cmxucr[]. 18. Updated struct ucc_geth because struct ucc_fast is not padded any more. Signed-off-by: Timur Tabi Signed-off-by: Kumar Gala --- arch/powerpc/sysdev/qe_lib/qe.c | 36 +++-- arch/powerpc/sysdev/qe_lib/qe_ic.c | 2 - arch/powerpc/sysdev/qe_lib/qe_io.c | 35 ++--- arch/powerpc/sysdev/qe_lib/ucc.c | 270 +++++++++++++++------------------- arch/powerpc/sysdev/qe_lib/ucc_fast.c | 127 ++++++++-------- arch/powerpc/sysdev/qe_lib/ucc_slow.c | 48 +++--- drivers/net/ucc_geth.c | 2 +- drivers/net/ucc_geth.h | 1 + include/asm-powerpc/immap_qe.h | 30 ++-- include/asm-powerpc/qe.h | 243 ++++++++++++++++++++---------- include/asm-powerpc/ucc.h | 40 ++--- include/asm-powerpc/ucc_slow.h | 9 +- 12 files changed, 431 insertions(+), 412 deletions(-) (limited to 'drivers') diff --git a/arch/powerpc/sysdev/qe_lib/qe.c b/arch/powerpc/sysdev/qe_lib/qe.c index 90f87408b5d..3d57d3835b0 100644 --- a/arch/powerpc/sysdev/qe_lib/qe.c +++ b/arch/powerpc/sysdev/qe_lib/qe.c @@ -141,7 +141,7 @@ EXPORT_SYMBOL(qe_issue_cmd); * 16 BRGs, which can be connected to the QE channels or output * as clocks. The BRGs are in two different block of internal * memory mapped space. - * The baud rate clock is the system clock divided by something. + * The BRG clock is the QE clock divided by 2. * It was set up long ago during the initial boot phase and is * is given to us. * Baud rate clocks are zero-based in the driver code (as that maps @@ -165,28 +165,38 @@ unsigned int get_brg_clk(void) return brg_clk; } -/* This function is used by UARTS, or anything else that uses a 16x - * oversampled clock. +/* Program the BRG to the given sampling rate and multiplier + * + * @brg: the BRG, 1-16 + * @rate: the desired sampling rate + * @multiplier: corresponds to the value programmed in GUMR_L[RDCR] or + * GUMR_L[TDCR]. E.g., if this BRG is the RX clock, and GUMR_L[RDCR]=01, + * then 'multiplier' should be 8. + * + * Also note that the value programmed into the BRGC register must be even. */ -void qe_setbrg(u32 brg, u32 rate) +void qe_setbrg(unsigned int brg, unsigned int rate, unsigned int multiplier) { - volatile u32 *bp; u32 divisor, tempval; - int div16 = 0; + u32 div16 = 0; - bp = &qe_immr->brg.brgc[brg]; + divisor = get_brg_clk() / (rate * multiplier); - divisor = (get_brg_clk() / rate); if (divisor > QE_BRGC_DIVISOR_MAX + 1) { - div16 = 1; + div16 = QE_BRGC_DIV16; divisor /= 16; } - tempval = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | QE_BRGC_ENABLE; - if (div16) - tempval |= QE_BRGC_DIV16; + /* Errata QE_General4, which affects some MPC832x and MPC836x SOCs, says + that the BRG divisor must be even if you're not using divide-by-16 + mode. */ + if (!div16 && (divisor & 1)) + divisor++; + + tempval = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | + QE_BRGC_ENABLE | div16; - out_be32(bp, tempval); + out_be32(&qe_immr->brg.brgc[brg - 1], tempval); } /* Initialize SNUMs (thread serial numbers) according to diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.c b/arch/powerpc/sysdev/qe_lib/qe_ic.c index 55e6f394af8..9a2d1edd050 100644 --- a/arch/powerpc/sysdev/qe_lib/qe_ic.c +++ b/arch/powerpc/sysdev/qe_lib/qe_ic.c @@ -405,8 +405,6 @@ void __init qe_ic_init(struct device_node *node, unsigned int flags) set_irq_data(qe_ic->virq_high, qe_ic); set_irq_chained_handler(qe_ic->virq_high, qe_ic_cascade_high); } - - printk("QEIC (%d IRQ sources) at %p\n", NR_QE_IC_INTS, qe_ic->regs); } void qe_ic_set_highest_priority(unsigned int virq, int high) diff --git a/arch/powerpc/sysdev/qe_lib/qe_io.c b/arch/powerpc/sysdev/qe_lib/qe_io.c index e32b45bf9ff..a114cb0c572 100644 --- a/arch/powerpc/sysdev/qe_lib/qe_io.c +++ b/arch/powerpc/sysdev/qe_lib/qe_io.c @@ -195,29 +195,22 @@ EXPORT_SYMBOL(par_io_of_config); #ifdef DEBUG static void dump_par_io(void) { - int i; + unsigned int i; - printk(KERN_INFO "PAR IO registars:\n"); - printk(KERN_INFO "Base address: 0x%08x\n", (u32) par_io); + printk(KERN_INFO "%s: par_io=%p\n", __FUNCTION__, par_io); for (i = 0; i < num_par_io_ports; i++) { - printk(KERN_INFO "cpodr[%d] : addr - 0x%08x, val - 0x%08x\n", - i, (u32) & par_io[i].cpodr, - in_be32(&par_io[i].cpodr)); - printk(KERN_INFO "cpdata[%d]: addr - 0x%08x, val - 0x%08x\n", - i, (u32) & par_io[i].cpdata, - in_be32(&par_io[i].cpdata)); - printk(KERN_INFO "cpdir1[%d]: addr - 0x%08x, val - 0x%08x\n", - i, (u32) & par_io[i].cpdir1, - in_be32(&par_io[i].cpdir1)); - printk(KERN_INFO "cpdir2[%d]: addr - 0x%08x, val - 0x%08x\n", - i, (u32) & par_io[i].cpdir2, - in_be32(&par_io[i].cpdir2)); - printk(KERN_INFO "cppar1[%d]: addr - 0x%08x, val - 0x%08x\n", - i, (u32) & par_io[i].cppar1, - in_be32(&par_io[i].cppar1)); - printk(KERN_INFO "cppar2[%d]: addr - 0x%08x, val - 0x%08x\n", - i, (u32) & par_io[i].cppar2, - in_be32(&par_io[i].cppar2)); + printk(KERN_INFO " cpodr[%u]=%08x\n", i, + in_be32(&par_io[i].cpodr)); + printk(KERN_INFO " cpdata[%u]=%08x\n", i, + in_be32(&par_io[i].cpdata)); + printk(KERN_INFO " cpdir1[%u]=%08x\n", i, + in_be32(&par_io[i].cpdir1)); + printk(KERN_INFO " cpdir2[%u]=%08x\n", i, + in_be32(&par_io[i].cpdir2)); + printk(KERN_INFO " cppar1[%u]=%08x\n", i, + in_be32(&par_io[i].cppar1)); + printk(KERN_INFO " cppar2[%u]=%08x\n", i, + in_be32(&par_io[i].cppar2)); } } diff --git a/arch/powerpc/sysdev/qe_lib/ucc.c b/arch/powerpc/sysdev/qe_lib/ucc.c index f970e5415ac..0e348d9af8a 100644 --- a/arch/powerpc/sysdev/qe_lib/ucc.c +++ b/arch/powerpc/sysdev/qe_lib/ucc.c @@ -28,228 +28,188 @@ static DEFINE_SPINLOCK(ucc_lock); -int ucc_set_qe_mux_mii_mng(int ucc_num) +int ucc_set_qe_mux_mii_mng(unsigned int ucc_num) { unsigned long flags; + if (ucc_num > UCC_MAX_NUM - 1) + return -EINVAL; + spin_lock_irqsave(&ucc_lock, flags); - out_be32(&qe_immr->qmx.cmxgcr, - ((in_be32(&qe_immr->qmx.cmxgcr) & - ~QE_CMXGCR_MII_ENET_MNG) | - (ucc_num << QE_CMXGCR_MII_ENET_MNG_SHIFT))); + clrsetbits_be32(&qe_immr->qmx.cmxgcr, QE_CMXGCR_MII_ENET_MNG, + ucc_num << QE_CMXGCR_MII_ENET_MNG_SHIFT); spin_unlock_irqrestore(&ucc_lock, flags); return 0; } EXPORT_SYMBOL(ucc_set_qe_mux_mii_mng); -int ucc_set_type(int ucc_num, struct ucc_common *regs, - enum ucc_speed_type speed) -{ - u8 guemr = 0; - - /* check if the UCC number is in range. */ - if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0)) - return -EINVAL; - - guemr = regs->guemr; - guemr &= ~(UCC_GUEMR_MODE_MASK_RX | UCC_GUEMR_MODE_MASK_TX); - switch (speed) { - case UCC_SPEED_TYPE_SLOW: - guemr |= (UCC_GUEMR_MODE_SLOW_RX | UCC_GUEMR_MODE_SLOW_TX); - break; - case UCC_SPEED_TYPE_FAST: - guemr |= (UCC_GUEMR_MODE_FAST_RX | UCC_GUEMR_MODE_FAST_TX); - break; - default: - return -EINVAL; - } - regs->guemr = guemr; - - return 0; -} - -int ucc_init_guemr(struct ucc_common *regs) +/* Configure the UCC to either Slow or Fast. + * + * A given UCC can be figured to support either "slow" devices (e.g. UART) + * or "fast" devices (e.g. Ethernet). + * + * 'ucc_num' is the UCC number, from 0 - 7. + * + * This function also sets the UCC_GUEMR_SET_RESERVED3 bit because that bit + * must always be set to 1. + */ +int ucc_set_type(unsigned int ucc_num, enum ucc_speed_type speed) { - u8 guemr = 0; - - if (!regs) - return -EINVAL; - - /* Set bit 3 (which is reserved in the GUEMR register) to 1 */ - guemr = UCC_GUEMR_SET_RESERVED3; - - regs->guemr = guemr; - - return 0; -} + u8 __iomem *guemr; -static void get_cmxucr_reg(int ucc_num, volatile u32 ** p_cmxucr, u8 * reg_num, - u8 * shift) -{ + /* The GUEMR register is at the same location for both slow and fast + devices, so we just use uccX.slow.guemr. */ switch (ucc_num) { - case 0: *p_cmxucr = &(qe_immr->qmx.cmxucr1); - *reg_num = 1; - *shift = 16; + case 0: guemr = &qe_immr->ucc1.slow.guemr; break; - case 2: *p_cmxucr = &(qe_immr->qmx.cmxucr1); - *reg_num = 1; - *shift = 0; + case 1: guemr = &qe_immr->ucc2.slow.guemr; break; - case 4: *p_cmxucr = &(qe_immr->qmx.cmxucr2); - *reg_num = 2; - *shift = 16; + case 2: guemr = &qe_immr->ucc3.slow.guemr; break; - case 6: *p_cmxucr = &(qe_immr->qmx.cmxucr2); - *reg_num = 2; - *shift = 0; + case 3: guemr = &qe_immr->ucc4.slow.guemr; break; - case 1: *p_cmxucr = &(qe_immr->qmx.cmxucr3); - *reg_num = 3; - *shift = 16; + case 4: guemr = &qe_immr->ucc5.slow.guemr; break; - case 3: *p_cmxucr = &(qe_immr->qmx.cmxucr3); - *reg_num = 3; - *shift = 0; + case 5: guemr = &qe_immr->ucc6.slow.guemr; break; - case 5: *p_cmxucr = &(qe_immr->qmx.cmxucr4); - *reg_num = 4; - *shift = 16; + case 6: guemr = &qe_immr->ucc7.slow.guemr; break; - case 7: *p_cmxucr = &(qe_immr->qmx.cmxucr4); - *reg_num = 4; - *shift = 0; + case 7: guemr = &qe_immr->ucc8.slow.guemr; break; default: - break; + return -EINVAL; } + + clrsetbits_8(guemr, UCC_GUEMR_MODE_MASK, + UCC_GUEMR_SET_RESERVED3 | speed); + + return 0; +} + +static void get_cmxucr_reg(unsigned int ucc_num, __be32 **cmxucr, + unsigned int *reg_num, unsigned int *shift) +{ + unsigned int cmx = ((ucc_num & 1) << 1) + (ucc_num > 3); + + *reg_num = cmx + 1; + *cmxucr = &qe_immr->qmx.cmxucr[cmx]; + *shift = 16 - 8 * (ucc_num & 2); } -int ucc_mux_set_grant_tsa_bkpt(int ucc_num, int set, u32 mask) +int ucc_mux_set_grant_tsa_bkpt(unsigned int ucc_num, int set, u32 mask) { - volatile u32 *p_cmxucr; - u8 reg_num; - u8 shift; + __be32 *cmxucr; + unsigned int reg_num; + unsigned int shift; /* check if the UCC number is in range. */ - if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0)) + if (ucc_num > UCC_MAX_NUM - 1) return -EINVAL; - get_cmxucr_reg(ucc_num, &p_cmxucr, ®_num, &shift); + get_cmxucr_reg(ucc_num, &cmxucr, ®_num, &shift); if (set) - out_be32(p_cmxucr, in_be32(p_cmxucr) | (mask << shift)); + setbits32(cmxucr, mask << shift); else - out_be32(p_cmxucr, in_be32(p_cmxucr) & ~(mask << shift)); + clrbits32(cmxucr, mask << shift); return 0; } -int ucc_set_qe_mux_rxtx(int ucc_num, enum qe_clock clock, enum comm_dir mode) +int ucc_set_qe_mux_rxtx(unsigned int ucc_num, enum qe_clock clock, + enum comm_dir mode) { - volatile u32 *p_cmxucr; - u8 reg_num; - u8 shift; - u32 clock_bits; - u32 clock_mask; - int source = -1; + __be32 *cmxucr; + unsigned int reg_num; + unsigned int shift; + u32 clock_bits = 0; /* check if the UCC number is in range. */ - if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0)) + if (ucc_num > UCC_MAX_NUM - 1) return -EINVAL; - if (!((mode == COMM_DIR_RX) || (mode == COMM_DIR_TX))) { - printk(KERN_ERR - "ucc_set_qe_mux_rxtx: bad comm mode type passed."); + /* The communications direction must be RX or TX */ + if (!((mode == COMM_DIR_RX) || (mode == COMM_DIR_TX))) return -EINVAL; - } - get_cmxucr_reg(ucc_num, &p_cmxucr, ®_num, &shift); + get_cmxucr_reg(ucc_num, &cmxucr, ®_num, &shift); switch (reg_num) { case 1: switch (clock) { - case QE_BRG1: source = 1; break; - case QE_BRG2: source = 2; break; - case QE_BRG7: source = 3; break; - case QE_BRG8: source = 4; break; - case QE_CLK9: source = 5; break; - case QE_CLK10: source = 6; break; - case QE_CLK11: source = 7; break; - case QE_CLK12: source = 8; break; - case QE_CLK15: source = 9; break; - case QE_CLK16: source = 10; break; - default: source = -1; break; + case QE_BRG1: clock_bits = 1; break; + case QE_BRG2: clock_bits = 2; break; + case QE_BRG7: clock_bits = 3; break; + case QE_BRG8: clock_bits = 4; break; + case QE_CLK9: clock_bits = 5; break; + case QE_CLK10: clock_bits = 6; break; + case QE_CLK11: clock_bits = 7; break; + case QE_CLK12: clock_bits = 8; break; + case QE_CLK15: clock_bits = 9; break; + case QE_CLK16: clock_bits = 10; break; + default: break; } break; case 2: switch (clock) { - case QE_BRG5: source = 1; break; - case QE_BRG6: source = 2; break; - case QE_BRG7: source = 3; break; - case QE_BRG8: source = 4; break; - case QE_CLK13: source = 5; break; - case QE_CLK14: source = 6; break; - case QE_CLK19: source = 7; break; - case QE_CLK20: source = 8; break; - case QE_CLK15: source = 9; break; - case QE_CLK16: source = 10; break; - default: source = -1; break; + case QE_BRG5: clock_bits = 1; break; + case QE_BRG6: clock_bits = 2; break; + case QE_BRG7: clock_bits = 3; break; + case QE_BRG8: clock_bits = 4; break; + case QE_CLK13: clock_bits = 5; break; + case QE_CLK14: clock_bits = 6; break; + case QE_CLK19: clock_bits = 7; break; + case QE_CLK20: clock_bits = 8; break; + case QE_CLK15: clock_bits = 9; break; + case QE_CLK16: clock_bits = 10; break; + default: break; } break; case 3: switch (clock) { - case QE_BRG9: source = 1; break; - case QE_BRG10: source = 2; break; - case QE_BRG15: source = 3; break; - case QE_BRG16: source = 4; break; - case QE_CLK3: source = 5; break; - case QE_CLK4: source = 6; break; - case QE_CLK17: source = 7; break; - case QE_CLK18: source = 8; break; - case QE_CLK7: source = 9; break; - case QE_CLK8: source = 10; break; - case QE_CLK16: source = 11; break; - default: source = -1; break; + case QE_BRG9: clock_bits = 1; break; + case QE_BRG10: clock_bits = 2; break; + case QE_BRG15: clock_bits = 3; break; + case QE_BRG16: clock_bits = 4; break; + case QE_CLK3: clock_bits = 5; break; + case QE_CLK4: clock_bits = 6; break; + case QE_CLK17: clock_bits = 7; break; + case QE_CLK18: clock_bits = 8; break; + case QE_CLK7: clock_bits = 9; break; + case QE_CLK8: clock_bits = 10; break; + case QE_CLK16: clock_bits = 11; break; + default: break; } break; case 4: switch (clock) { - case QE_BRG13: source = 1; break; - case QE_BRG14: source = 2; break; - case QE_BRG15: source = 3; break; - case QE_BRG16: source = 4; break; - case QE_CLK5: source = 5; break; - case QE_CLK6: source = 6; break; - case QE_CLK21: source = 7; break; - case QE_CLK22: source = 8; break; - case QE_CLK7: source = 9; break; - case QE_CLK8: source = 10; break; - case QE_CLK16: source = 11; break; - default: source = -1; break; + case QE_BRG13: clock_bits = 1; break; + case QE_BRG14: clock_bits = 2; break; + case QE_BRG15: clock_bits = 3; break; + case QE_BRG16: clock_bits = 4; break; + case QE_CLK5: clock_bits = 5; break; + case QE_CLK6: clock_bits = 6; break; + case QE_CLK21: clock_bits = 7; break; + case QE_CLK22: clock_bits = 8; break; + case QE_CLK7: clock_bits = 9; break; + case QE_CLK8: clock_bits = 10; break; + case QE_CLK16: clock_bits = 11; break; + default: break; } break; - default: - source = -1; - break; + default: break; } - if (source == -1) { - printk(KERN_ERR - "ucc_set_qe_mux_rxtx: Bad combination of clock and UCC."); + /* Check for invalid combination of clock and UCC number */ + if (!clock_bits) return -ENOENT; - } - clock_bits = (u32) source; - clock_mask = QE_CMXUCR_TX_CLK_SRC_MASK; - if (mode == COMM_DIR_RX) { - clock_bits <<= 4; /* Rx field is 4 bits to left of Tx field */ - clock_mask <<= 4; /* Rx field is 4 bits to left of Tx field */ - } - clock_bits <<= shift; - clock_mask <<= shift; + if (mode == COMM_DIR_RX) + shift += 4; - out_be32(p_cmxucr, (in_be32(p_cmxucr) & ~clock_mask) | clock_bits); + clrsetbits_be32(cmxucr, QE_CMXUCR_TX_CLK_SRC_MASK << shift, + clock_bits << shift); return 0; } diff --git a/arch/powerpc/sysdev/qe_lib/ucc_fast.c b/arch/powerpc/sysdev/qe_lib/ucc_fast.c index 3df202e8d33..3223acbc39e 100644 --- a/arch/powerpc/sysdev/qe_lib/ucc_fast.c +++ b/arch/powerpc/sysdev/qe_lib/ucc_fast.c @@ -30,46 +30,45 @@ void ucc_fast_dump_regs(struct ucc_fast_private * uccf) { - printk(KERN_INFO "UCC%d Fast registers:", uccf->uf_info->ucc_num); - printk(KERN_INFO "Base address: 0x%08x", (u32) uccf->uf_regs); - - printk(KERN_INFO "gumr : addr - 0x%08x, val - 0x%08x", - (u32) & uccf->uf_regs->gumr, in_be32(&uccf->uf_regs->gumr)); - printk(KERN_INFO "upsmr : addr - 0x%08x, val - 0x%08x", - (u32) & uccf->uf_regs->upsmr, in_be32(&uccf->uf_regs->upsmr)); - printk(KERN_INFO "utodr : addr - 0x%08x, val - 0x%04x", - (u32) & uccf->uf_regs->utodr, in_be16(&uccf->uf_regs->utodr)); - printk(KERN_INFO "udsr : addr - 0x%08x, val - 0x%04x", - (u32) & uccf->uf_regs->udsr, in_be16(&uccf->uf_regs->udsr)); - printk(KERN_INFO "ucce : addr - 0x%08x, val - 0x%08x", - (u32) & uccf->uf_regs->ucce, in_be32(&uccf->uf_regs->ucce)); - printk(KERN_INFO "uccm : addr - 0x%08x, val - 0x%08x", - (u32) & uccf->uf_regs->uccm, in_be32(&uccf->uf_regs->uccm)); - printk(KERN_INFO "uccs : addr - 0x%08x, val - 0x%02x", - (u32) & uccf->uf_regs->uccs, uccf->uf_regs->uccs); - printk(KERN_INFO "urfb : addr - 0x%08x, val - 0x%08x", - (u32) & uccf->uf_regs->urfb, in_be32(&uccf->uf_regs->urfb)); - printk(KERN_INFO "urfs : addr - 0x%08x, val - 0x%04x", - (u32) & uccf->uf_regs->urfs, in_be16(&uccf->uf_regs->urfs)); - printk(KERN_INFO "urfet : addr - 0x%08x, val - 0x%04x", - (u32) & uccf->uf_regs->urfet, in_be16(&uccf->uf_regs->urfet)); - printk(KERN_INFO "urfset: addr - 0x%08x, val - 0x%04x", - (u32) & uccf->uf_regs->urfset, - in_be16(&uccf->uf_regs->urfset)); - printk(KERN_INFO "utfb : addr - 0x%08x, val - 0x%08x", - (u32) & uccf->uf_regs->utfb, in_be32(&uccf->uf_regs->utfb)); - printk(KERN_INFO "utfs : addr - 0x%08x, val - 0x%04x", - (u32) & uccf->uf_regs->utfs, in_be16(&uccf->uf_regs->utfs)); - printk(KERN_INFO "utfet : addr - 0x%08x, val - 0x%04x", - (u32) & uccf->uf_regs->utfet, in_be16(&uccf->uf_regs->utfet)); - printk(KERN_INFO "utftt : addr - 0x%08x, val - 0x%04x", - (u32) & uccf->uf_regs->utftt, in_be16(&uccf->uf_regs->utftt)); - printk(KERN_INFO "utpt : addr - 0x%08x, val - 0x%04x", - (u32) & uccf->uf_regs->utpt, in_be16(&uccf->uf_regs->utpt)); - printk(KERN_INFO "urtry : addr - 0x%08x, val - 0x%08x", - (u32) & uccf->uf_regs->urtry, in_be32(&uccf->uf_regs->urtry)); - printk(KERN_INFO "guemr : addr - 0x%08x, val - 0x%02x", - (u32) & uccf->uf_regs->guemr, uccf->uf_regs->guemr); + printk(KERN_INFO "UCC%u Fast registers:\n", uccf->uf_info->ucc_num); + printk(KERN_INFO "Base address: 0x%p\n", uccf->uf_regs); + + printk(KERN_INFO "gumr : addr=0x%p, val=0x%08x\n", + &uccf->uf_regs->gumr, in_be32(&uccf->uf_regs->gumr)); + printk(KERN_INFO "upsmr : addr=0x%p, val=0x%08x\n", + &uccf->uf_regs->upsmr, in_be32(&uccf->uf_regs->upsmr)); + printk(KERN_INFO "utodr : addr=0x%p, val=0x%04x\n", + &uccf->uf_regs->utodr, in_be16(&uccf->uf_regs->utodr)); + printk(KERN_INFO "udsr : addr=0x%p, val=0x%04x\n", + &uccf->uf_regs->udsr, in_be16(&uccf->uf_regs->udsr)); + printk(KERN_INFO "ucce : addr=0x%p, val=0x%08x\n", + &uccf->uf_regs->ucce, in_be32(&uccf->uf_regs->ucce)); + printk(KERN_INFO "uccm : addr=0x%p, val=0x%08x\n", + &uccf->uf_regs->uccm, in_be32(&uccf->uf_regs->uccm)); + printk(KERN_INFO "uccs : addr=0x%p, val=0x%02x\n", + &uccf->uf_regs->uccs, uccf->uf_regs->uccs); + printk(KERN_INFO "urfb : addr=0x%p, val=0x%08x\n", + &uccf->uf_regs->urfb, in_be32(&uccf->uf_regs->urfb)); + printk(KERN_INFO "urfs : addr=0x%p, val=0x%04x\n", + &uccf->uf_regs->urfs, in_be16(&uccf->uf_regs->urfs)); + printk(KERN_INFO "urfet : addr=0x%p, val=0x%04x\n", + &uccf->uf_regs->urfet, in_be16(&uccf->uf_regs->urfet)); + printk(KERN_INFO "urfset: addr=0x%p, val=0x%04x\n", + &uccf->uf_regs->urfset, in_be16(&uccf->uf_regs->urfset)); + printk(KERN_INFO "utfb : addr=0x%p, val=0x%08x\n", + &uccf->uf_regs->utfb, in_be32(&uccf->uf_regs->utfb)); + printk(KERN_INFO "utfs : addr=0x%p, val=0x%04x\n", + &uccf->uf_regs->utfs, in_be16(&uccf->uf_regs->utfs)); + printk(KERN_INFO "utfet : addr=0x%p, val=0x%04x\n", + &uccf->uf_regs->utfet, in_be16(&uccf->uf_regs->utfet)); + printk(KERN_INFO "utftt : addr=0x%p, val=0x%04x\n", + &uccf->uf_regs->utftt, in_be16(&uccf->uf_regs->utftt)); + printk(KERN_INFO "utpt : addr=0x%p, val=0x%04x\n", + &uccf->uf_regs->utpt, in_be16(&uccf->uf_regs->utpt)); + printk(KERN_INFO "urtry : addr=0x%p, val=0x%08x\n", + &uccf->uf_regs->urtry, in_be32(&uccf->uf_regs->urtry)); + printk(KERN_INFO "guemr : addr=0x%p, val=0x%02x\n", + &uccf->uf_regs->guemr, uccf->uf_regs->guemr); } EXPORT_SYMBOL(ucc_fast_dump_regs); @@ -149,55 +148,57 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc /* check if the UCC port number is in range. */ if ((uf_info->ucc_num < 0) || (uf_info->ucc_num > UCC_MAX_NUM - 1)) { - printk(KERN_ERR "%s: illegal UCC number", __FUNCTION__); + printk(KERN_ERR "%s: illegal UCC number\n", __FUNCTION__); return -EINVAL; } /* Check that 'max_rx_buf_length' is properly aligned (4). */ if (uf_info->max_rx_buf_length & (UCC_FAST_MRBLR_ALIGNMENT - 1)) { - printk(KERN_ERR "%s: max_rx_buf_length not aligned", __FUNCTION__); + printk(KERN_ERR "%s: max_rx_buf_length not aligned\n", + __FUNCTION__); return -EINVAL; } /* Validate Virtual Fifo register values */ if (uf_info->urfs < UCC_FAST_URFS_MIN_VAL) { - printk(KERN_ERR "%s: urfs is too small", __FUNCTION__); + printk(KERN_ERR "%s: urfs is too small\n", __FUNCTION__); return -EINVAL; } if (uf_info->urfs & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) { - printk(KERN_ERR "%s: urfs is not aligned", __FUNCTION__); + printk(KERN_ERR "%s: urfs is not aligned\n", __FUNCTION__); return -EINVAL; } if (uf_info->urfet & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) { - printk(KERN_ERR "%s: urfet is not aligned.", __FUNCTION__); + printk(KERN_ERR "%s: urfet is not aligned.\n", __FUNCTION__); return -EINVAL; } if (uf_info->urfset & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) { - printk(KERN_ERR "%s: urfset is not aligned", __FUNCTION__); + printk(KERN_ERR "%s: urfset is not aligned\n", __FUNCTION__); return -EINVAL; } if (uf_info->utfs & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) { - printk(KERN_ERR "%s: utfs is not aligned", __FUNCTION__); + printk(KERN_ERR "%s: utfs is not aligned\n", __FUNCTION__); return -EINVAL; } if (uf_info->utfet & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) { - printk(KERN_ERR "%s: utfet is not aligned", __FUNCTION__); + printk(KERN_ERR "%s: utfet is not aligned\n", __FUNCTION__); return -EINVAL; } if (uf_info->utftt & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) { - printk(KERN_ERR "%s: utftt is not aligned", __FUNCTION__); + printk(KERN_ERR "%s: utftt is not aligned\n", __FUNCTION__); return -EINVAL; } uccf = kzalloc(sizeof(struct ucc_fast_private), GFP_KERNEL); if (!uccf) { - printk(KERN_ERR "%s: Cannot allocate private data", __FUNCTION__); + printk(KERN_ERR "%s: Cannot allocate private data\n", + __FUNCTION__); return -ENOMEM; } @@ -206,7 +207,7 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc /* Set the PHY base address */ uccf->uf_regs = ioremap(uf_info->regs, sizeof(struct ucc_fast)); if (uccf->uf_regs == NULL) { - printk(KERN_ERR "%s: Cannot map UCC registers", __FUNCTION__); + printk(KERN_ERR "%s: Cannot map UCC registers\n", __FUNCTION__); return -ENOMEM; } @@ -226,18 +227,10 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc uccf->rx_discarded = 0; #endif /* STATISTICS */ - /* Init Guemr register */ - if ((ret = ucc_init_guemr((struct ucc_common *) (uf_regs)))) { - printk(KERN_ERR "%s: cannot init GUEMR", __FUNCTION__); - ucc_fast_free(uccf); - return ret; - } - /* Set UCC to fast type */ - if ((ret = ucc_set_type(uf_info->ucc_num, - (struct ucc_common *) (uf_regs), - UCC_SPEED_TYPE_FAST))) { - printk(KERN_ERR "%s: cannot set UCC type", __FUNCTION__); + ret = ucc_set_type(uf_info->ucc_num, UCC_SPEED_TYPE_FAST); + if (ret) { + printk(KERN_ERR "%s: cannot set UCC type\n", __FUNCTION__); ucc_fast_free(uccf); return ret; } @@ -276,7 +269,8 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc uccf->ucc_fast_tx_virtual_fifo_base_offset = qe_muram_alloc(uf_info->utfs, UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT); if (IS_ERR_VALUE(uccf->ucc_fast_tx_virtual_fifo_base_offset)) { - printk(KERN_ERR "%s: cannot allocate MURAM for TX FIFO", __FUNCTION__); + printk(KERN_ERR "%s: cannot allocate MURAM for TX FIFO\n", + __FUNCTION__); uccf->ucc_fast_tx_virtual_fifo_base_offset = 0; ucc_fast_free(uccf); return -ENOMEM; @@ -288,7 +282,8 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc UCC_FAST_RECEIVE_VIRTUAL_FIFO_SIZE_FUDGE_FACTOR, UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT); if (IS_ERR_VALUE(uccf->ucc_fast_rx_virtual_fifo_base_offset)) { - printk(KERN_ERR "%s: cannot allocate MURAM for RX FIFO", __FUNCTION__); + printk(KERN_ERR "%s: cannot allocate MURAM for RX FIFO\n", + __FUNCTION__); uccf->ucc_fast_rx_virtual_fifo_base_offset = 0; ucc_fast_free(uccf); return -ENOMEM; @@ -318,7 +313,7 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc if ((uf_info->rx_clock != QE_CLK_NONE) && ucc_set_qe_mux_rxtx(uf_info->ucc_num, uf_info->rx_clock, COMM_DIR_RX)) { - printk(KERN_ERR "%s: illegal value for RX clock", + printk(KERN_ERR "%s: illegal value for RX clock\n", __FUNCTION__); ucc_fast_free(uccf); return -EINVAL; @@ -327,7 +322,7 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc if ((uf_info->tx_clock != QE_CLK_NONE) && ucc_set_qe_mux_rxtx(uf_info->ucc_num, uf_info->tx_clock, COMM_DIR_TX)) { - printk(KERN_ERR "%s: illegal value for TX clock", + printk(KERN_ERR "%s: illegal value for TX clock\n", __FUNCTION__); ucc_fast_free(uccf); return -EINVAL; diff --git a/arch/powerpc/sysdev/qe_lib/ucc_slow.c b/arch/powerpc/sysdev/qe_lib/ucc_slow.c index 1f65c26ce63..0174b3aeef8 100644 --- a/arch/powerpc/sysdev/qe_lib/ucc_slow.c +++ b/arch/powerpc/sysdev/qe_lib/ucc_slow.c @@ -115,11 +115,15 @@ void ucc_slow_disable(struct ucc_slow_private * uccs, enum comm_dir mode) out_be32(&us_regs->gumr_l, gumr_l); } +/* Initialize the UCC for Slow operations + * + * The caller should initialize the following us_info + */ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** uccs_ret) { struct ucc_slow_private *uccs; u32 i; - struct ucc_slow *us_regs; + struct ucc_slow __iomem *us_regs; u32 gumr; struct qe_bd *bd; u32 id; @@ -131,7 +135,7 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc /* check if the UCC port number is in range. */ if ((us_info->ucc_num < 0) || (us_info->ucc_num > UCC_MAX_NUM - 1)) { - printk(KERN_ERR "%s: illegal UCC number", __FUNCTION__); + printk(KERN_ERR "%s: illegal UCC number\n", __FUNCTION__); return -EINVAL; } @@ -143,13 +147,14 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc */ if ((!us_info->rfw) && (us_info->max_rx_buf_length & (UCC_SLOW_MRBLR_ALIGNMENT - 1))) { - printk(KERN_ERR "max_rx_buf_length not aligned."); + printk(KERN_ERR "max_rx_buf_length not aligned.\n"); return -EINVAL; } uccs = kzalloc(sizeof(struct ucc_slow_private), GFP_KERNEL); if (!uccs) { - printk(KERN_ERR "%s: Cannot allocate private data", __FUNCTION__); + printk(KERN_ERR "%s: Cannot allocate private data\n", + __FUNCTION__); return -ENOMEM; } @@ -158,7 +163,7 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc /* Set the PHY base address */ uccs->us_regs = ioremap(us_info->regs, sizeof(struct ucc_slow)); if (uccs->us_regs == NULL) { - printk(KERN_ERR "%s: Cannot map UCC registers", __FUNCTION__); + printk(KERN_ERR "%s: Cannot map UCC registers\n", __FUNCTION__); return -ENOMEM; } @@ -182,22 +187,14 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc return -ENOMEM; } id = ucc_slow_get_qe_cr_subblock(us_info->ucc_num); - qe_issue_cmd(QE_ASSIGN_PAGE_TO_DEVICE, id, QE_CR_PROTOCOL_UNSPECIFIED, + qe_issue_cmd(QE_ASSIGN_PAGE_TO_DEVICE, id, us_info->protocol, uccs->us_pram_offset); uccs->us_pram = qe_muram_addr(uccs->us_pram_offset); - /* Init Guemr register */ - if ((ret = ucc_init_guemr((struct ucc_common *) us_regs))) { - printk(KERN_ERR "%s: cannot init GUEMR", __FUNCTION__); - ucc_slow_free(uccs); - return ret; - } - /* Set UCC to slow type */ - if ((ret = ucc_set_type(us_info->ucc_num, - (struct ucc_common *) us_regs, - UCC_SPEED_TYPE_SLOW))) { + ret = ucc_set_type(us_info->ucc_num, UCC_SPEED_TYPE_SLOW); + if (ret) { printk(KERN_ERR "%s: cannot set UCC type", __FUNCTION__); ucc_slow_free(uccs); return ret; @@ -212,7 +209,8 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc qe_muram_alloc(us_info->rx_bd_ring_len * sizeof(struct qe_bd), QE_ALIGNMENT_OF_BD); if (IS_ERR_VALUE(uccs->rx_base_offset)) { - printk(KERN_ERR "%s: cannot allocate RX BDs", __FUNCTION__); + printk(KERN_ERR "%s: cannot allocate %u RX BDs\n", __FUNCTION__, + us_info->rx_bd_ring_len); uccs->rx_base_offset = 0; ucc_slow_free(uccs); return -ENOMEM; @@ -292,12 +290,12 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc /* if the data is in cachable memory, the 'global' */ /* in the function code should be set. */ - uccs->us_pram->tfcr = uccs->us_pram->rfcr = - us_info->data_mem_part | QE_BMR_BYTE_ORDER_BO_MOT; + uccs->us_pram->tbmr = UCC_BMR_BO_BE; + uccs->us_pram->rbmr = UCC_BMR_BO_BE; /* rbase, tbase are offsets from MURAM base */ - out_be16(&uccs->us_pram->rbase, uccs->us_pram_offset); - out_be16(&uccs->us_pram->tbase, uccs->us_pram_offset); + out_be16(&uccs->us_pram->rbase, uccs->rx_base_offset); + out_be16(&uccs->us_pram->tbase, uccs->tx_base_offset); /* Mux clocking */ /* Grant Support */ @@ -311,7 +309,7 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc /* Rx clock routing */ if (ucc_set_qe_mux_rxtx(us_info->ucc_num, us_info->rx_clock, COMM_DIR_RX)) { - printk(KERN_ERR "%s: illegal value for RX clock", + printk(KERN_ERR "%s: illegal value for RX clock\n", __FUNCTION__); ucc_slow_free(uccs); return -EINVAL; @@ -319,7 +317,7 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc /* Tx clock routing */ if (ucc_set_qe_mux_rxtx(us_info->ucc_num, us_info->tx_clock, COMM_DIR_TX)) { - printk(KERN_ERR "%s: illegal value for TX clock", + printk(KERN_ERR "%s: illegal value for TX clock\n", __FUNCTION__); ucc_slow_free(uccs); return -EINVAL; @@ -343,8 +341,8 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc command = QE_INIT_TX; else command = QE_INIT_RX; /* We know at least one is TRUE */ - id = ucc_slow_get_qe_cr_subblock(us_info->ucc_num); - qe_issue_cmd(command, id, QE_CR_PROTOCOL_UNSPECIFIED, 0); + + qe_issue_cmd(command, id, us_info->protocol, 0); *uccs_ret = uccs; return 0; diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 9a38dfe45f8..7dedc960960 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -2919,7 +2919,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) test = in_be16(&ugeth->p_tx_glbl_pram->temoder); /* Function code register value to be used later */ - function_code = QE_BMR_BYTE_ORDER_BO_MOT | UCC_FAST_FUNCTION_CODE_GBL; + function_code = UCC_BMR_BO_BE | UCC_BMR_GBL; /* Required for QE */ /* function code register */ diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h index bb4dac8c0c6..1aa69023cde 100644 --- a/drivers/net/ucc_geth.h +++ b/drivers/net/ucc_geth.h @@ -44,6 +44,7 @@ struct ucc_geth { struct ucc_fast uccf; + u8 res0[0x100 - sizeof(struct ucc_fast)]; u32 maccfg1; /* mac configuration reg. 1 */ u32 maccfg2; /* mac configuration reg. 2 */ diff --git a/include/asm-powerpc/immap_qe.h b/include/asm-powerpc/immap_qe.h index 02548f74ccb..aba9806b31c 100644 --- a/include/asm-powerpc/immap_qe.h +++ b/include/asm-powerpc/immap_qe.h @@ -97,10 +97,7 @@ struct qe_mux { __be32 cmxsi1cr_l; /* CMX SI1 clock route low register */ __be32 cmxsi1cr_h; /* CMX SI1 clock route high register */ __be32 cmxsi1syr; /* CMX SI1 SYNC route register */ - __be32 cmxucr1; /* CMX UCC1, UCC3 clock route register */ - __be32 cmxucr2; /* CMX UCC5, UCC7 clock route register */ - __be32 cmxucr3; /* CMX UCC2, UCC4 clock route register */ - __be32 cmxucr4; /* CMX UCC6, UCC8 clock route register */ + __be32 cmxucr[4]; /* CMX UCCx clock route registers */ __be32 cmxupcr; /* CMX UPC clock route register */ u8 res0[0x1C]; } __attribute__ ((packed)); @@ -261,7 +258,6 @@ struct ucc_slow { __be16 utpt; u8 res4[0x52]; u8 guemr; /* UCC general extended mode register */ - u8 res5[0x200 - 0x091]; } __attribute__ ((packed)); /* QE UCC Fast */ @@ -294,21 +290,13 @@ struct ucc_fast { __be32 urtry; /* UCC retry counter register */ u8 res8[0x4C]; u8 guemr; /* UCC general extended mode register */ - u8 res9[0x100 - 0x091]; -} __attribute__ ((packed)); - -/* QE UCC */ -struct ucc_common { - u8 res1[0x90]; - u8 guemr; - u8 res2[0x200 - 0x091]; } __attribute__ ((packed)); struct ucc { union { struct ucc_slow slow; struct ucc_fast fast; - struct ucc_common common; + u8 res[0x200]; /* UCC blocks are 512 bytes each */ }; } __attribute__ ((packed)); @@ -407,7 +395,7 @@ struct dbg { /* RISC Special Registers (Trap and Breakpoint) */ struct rsp { - u8 fixme[0x100]; + u32 reg[0x40]; /* 64 32-bit registers */ } __attribute__ ((packed)); struct qe_immap { @@ -436,11 +424,13 @@ struct qe_immap { u8 res13[0x600]; struct upc upc2; /* MultiPHY UTOPIA POS Ctrlr 2*/ struct sdma sdma; /* SDMA */ - struct dbg dbg; /* Debug Space */ - struct rsp rsp[0x2]; /* RISC Special Registers + struct dbg dbg; /* 0x104080 - 0x1040FF + Debug Space */ + struct rsp rsp[0x2]; /* 0x104100 - 0x1042FF + RISC Special Registers (Trap and Breakpoint) */ - u8 res14[0x300]; - u8 res15[0x3A00]; + u8 res14[0x300]; /* 0x104300 - 0x1045FF */ + u8 res15[0x3A00]; /* 0x104600 - 0x107FFF */ u8 res16[0x8000]; /* 0x108000 - 0x110000 */ u8 muram[0xC000]; /* 0x110000 - 0x11C000 Multi-user RAM */ @@ -451,7 +441,7 @@ struct qe_immap { extern struct qe_immap *qe_immr; extern phys_addr_t get_qe_base(void); -static inline unsigned long immrbar_virt_to_phys(volatile void * address) +static inline unsigned long immrbar_virt_to_phys(void *address) { if ( ((u32)address >= (u32)qe_immr) && ((u32)address < ((u32)qe_immr + QE_IMMAP_SIZE)) ) diff --git a/include/asm-powerpc/qe.h b/include/asm-powerpc/qe.h index ad23c580631..0dabe46a29d 100644 --- a/include/asm-powerpc/qe.h +++ b/include/asm-powerpc/qe.h @@ -38,7 +38,7 @@ extern int par_io_data_set(u8 port, u8 pin, u8 val); /* QE internal API */ int qe_issue_cmd(u32 cmd, u32 device, u8 mcn_protocol, u32 cmd_input); -void qe_setbrg(u32 brg, u32 rate); +void qe_setbrg(unsigned int brg, unsigned int rate, unsigned int multiplier); int qe_get_snum(void); void qe_put_snum(u8 snum); unsigned long qe_muram_alloc(int size, int align); @@ -49,14 +49,28 @@ void *qe_muram_addr(unsigned long offset); /* Buffer descriptors */ struct qe_bd { - u16 status; - u16 length; - u32 buf; + __be16 status; + __be16 length; + __be32 buf; } __attribute__ ((packed)); #define BD_STATUS_MASK 0xffff0000 #define BD_LENGTH_MASK 0x0000ffff +#define BD_SC_EMPTY 0x8000 /* Receive is empty */ +#define BD_SC_READY 0x8000 /* Transmit is ready */ +#define BD_SC_WRAP 0x2000 /* Last buffer descriptor */ +#define BD_SC_INTRPT 0x1000 /* Interrupt on change */ +#define BD_SC_LAST 0x0800 /* Last buffer in frame */ +#define BD_SC_CM 0x0200 /* Continous mode */ +#define BD_SC_ID 0x0100 /* Rec'd too many idles */ +#define BD_SC_P 0x0100 /* xmt preamble */ +#define BD_SC_BR 0x0020 /* Break received */ +#define BD_SC_FR 0x0010 /* Framing error */ +#define BD_SC_PR 0x0008 /* Parity error */ +#define BD_SC_OV 0x0002 /* Overrun */ +#define BD_SC_CD 0x0001 /* ?? */ + /* Alignment */ #define QE_INTR_TABLE_ALIGN 16 /* ??? */ #define QE_ALIGNMENT_OF_BD 8 @@ -269,15 +283,12 @@ enum qe_clock { /* QE CECR Protocol - For non-MCC, specifies mode for QE CECR command */ #define QE_CR_PROTOCOL_UNSPECIFIED 0x00 /* For all other protocols */ #define QE_CR_PROTOCOL_HDLC_TRANSPARENT 0x00 +#define QE_CR_PROTOCOL_QMC 0x02 +#define QE_CR_PROTOCOL_UART 0x04 #define QE_CR_PROTOCOL_ATM_POS 0x0A #define QE_CR_PROTOCOL_ETHERNET 0x0C #define QE_CR_PROTOCOL_L2_SWITCH 0x0D -/* BMR byte order */ -#define QE_BMR_BYTE_ORDER_BO_PPC 0x08 /* powerpc little endian */ -#define QE_BMR_BYTE_ORDER_BO_MOT 0x10 /* motorola big endian */ -#define QE_BMR_BYTE_ORDER_BO_MAX 0x18 - /* BRG configuration register */ #define QE_BRGC_ENABLE 0x00010000 #define QE_BRGC_DIVISOR_SHIFT 1 @@ -324,41 +335,41 @@ enum qe_clock { #define UPGCR_ADDR 0x10000000 /* Master MPHY Addr multiplexing */ #define UPGCR_DIAG 0x01000000 /* Diagnostic mode */ -/* UCC */ +/* UCC GUEMR register */ #define UCC_GUEMR_MODE_MASK_RX 0x02 -#define UCC_GUEMR_MODE_MASK_TX 0x01 #define UCC_GUEMR_MODE_FAST_RX 0x02 -#define UCC_GUEMR_MODE_FAST_TX 0x01 #define UCC_GUEMR_MODE_SLOW_RX 0x00 +#define UCC_GUEMR_MODE_MASK_TX 0x01 +#define UCC_GUEMR_MODE_FAST_TX 0x01 #define UCC_GUEMR_MODE_SLOW_TX 0x00 +#define UCC_GUEMR_MODE_MASK (UCC_GUEMR_MODE_MASK_RX | UCC_GUEMR_MODE_MASK_TX) #define UCC_GUEMR_SET_RESERVED3 0x10 /* Bit 3 in the guemr is reserved but must be set 1 */ /* structure representing UCC SLOW parameter RAM */ struct ucc_slow_pram { - u16 rbase; /* RX BD base address */ - u16 tbase; /* TX BD base address */ - u8 rfcr; /* Rx function code */ - u8 tfcr; /* Tx function code */ - u16 mrblr; /* Rx buffer length */ - u32 rstate; /* Rx internal state */ - u32 rptr; /* Rx internal data pointer */ - u16 rbptr; /* rb BD Pointer */ - u16 rcount; /* Rx internal byte count */ - u32 rtemp; /* Rx temp */ - u32 tstate; /* Tx internal state */ - u32 tptr; /* Tx internal data pointer */ - u16 tbptr; /* Tx BD pointer */ - u16 tcount; /* Tx byte count */ - u32 ttemp; /* Tx temp */ - u32 rcrc; /* temp receive CRC */ - u32 tcrc; /* temp transmit CRC */ + __be16 rbase; /* RX BD base address */ + __be16 tbase; /* TX BD base address */ + u8 rbmr; /* RX bus mode register (same as CPM's RFCR) */ + u8 tbmr; /* TX bus mode register (same as CPM's TFCR) */ + __be16 mrblr; /* Rx buffer length */ + __be32 rstate; /* Rx internal state */ + __be32 rptr; /* Rx internal data pointer */ + __be16 rbptr; /* rb BD Pointer */ + __be16 rcount; /* Rx internal byte count */ + __be32 rtemp; /* Rx temp */ + __be32 tstate; /* Tx internal state */ + __be32 tptr; /* Tx internal data pointer */ + __be16 tbptr; /* Tx BD pointer */ + __be16 tcount; /* Tx byte count */ + __be32 ttemp; /* Tx temp */ + __be32 rcrc; /* temp receive CRC */ + __be32 tcrc; /* temp transmit CRC */ } __attribute__ ((packed)); /* General UCC SLOW Mode Register (GUMRH & GUMRL) */ -#define UCC_SLOW_GUMR_H_CRC16 0x00004000 -#define UCC_SLOW_GUMR_H_CRC16CCITT 0x00000000 -#define UCC_SLOW_GUMR_H_CRC32CCITT 0x00008000 +#define UCC_SLOW_GUMR_H_SAM_QMC 0x00000000 +#define UCC_SLOW_GUMR_H_SAM_SATM 0x00008000 #define UCC_SLOW_GUMR_H_REVD 0x00002000 #define UCC_SLOW_GUMR_H_TRX 0x00001000 #define UCC_SLOW_GUMR_H_TTX 0x00000800 @@ -378,9 +389,33 @@ struct ucc_slow_pram { #define UCC_SLOW_GUMR_L_TCI 0x10000000 #define UCC_SLOW_GUMR_L_RINV 0x02000000 #define UCC_SLOW_GUMR_L_TINV 0x01000000 -#define UCC_SLOW_GUMR_L_TEND 0x00020000 +#define UCC_SLOW_GUMR_L_TEND 0x00040000 +#define UCC_SLOW_GUMR_L_TDCR_MASK 0x00030000 +#define UCC_SLOW_GUMR_L_TDCR_32 0x00030000 +#define UCC_SLOW_GUMR_L_TDCR_16 0x00020000 +#define UCC_SLOW_GUMR_L_TDCR_8 0x00010000 +#define UCC_SLOW_GUMR_L_TDCR_1 0x00000000 +#define UCC_SLOW_GUMR_L_RDCR_MASK 0x0000c000 +#define UCC_SLOW_GUMR_L_RDCR_32 0x0000c000 +#define UCC_SLOW_GUMR_L_RDCR_16 0x00008000 +#define UCC_SLOW_GUMR_L_RDCR_8 0x00004000 +#define UCC_SLOW_GUMR_L_RDCR_1 0x00000000 +#define UCC_SLOW_GUMR_L_RENC_NRZI 0x00000800 +#define UCC_SLOW_GUMR_L_RENC_NRZ 0x00000000 +#define UCC_SLOW_GUMR_L_TENC_NRZI 0x00000100 +#define UCC_SLOW_GUMR_L_TENC_NRZ 0x00000000 +#define UCC_SLOW_GUMR_L_DIAG_MASK 0x000000c0 +#define UCC_SLOW_GUMR_L_DIAG_LE 0x000000c0 +#define UCC_SLOW_GUMR_L_DIAG_ECHO 0x00000080 +#define UCC_SLOW_GUMR_L_DIAG_LOOP 0x00000040 +#define UCC_SLOW_GUMR_L_DIAG_NORM 0x00000000 #define UCC_SLOW_GUMR_L_ENR 0x00000020 #define UCC_SLOW_GUMR_L_ENT 0x00000010 +#define UCC_SLOW_GUMR_L_MODE_MASK 0x0000000F +#define UCC_SLOW_GUMR_L_MODE_BISYNC 0x00000008 +#define UCC_SLOW_GUMR_L_MODE_AHDLC 0x00000006 +#define UCC_SLOW_GUMR_L_MODE_UART 0x00000004 +#define UCC_SLOW_GUMR_L_MODE_QMC 0x00000002 /* General UCC FAST Mode Register */ #define UCC_FAST_GUMR_TCI 0x20000000 @@ -397,53 +432,111 @@ struct ucc_slow_pram { #define UCC_FAST_GUMR_ENR 0x00000020 #define UCC_FAST_GUMR_ENT 0x00000010 -/* Slow UCC Event Register (UCCE) */ -#define UCC_SLOW_UCCE_GLR 0x1000 -#define UCC_SLOW_UCCE_GLT 0x0800 -#define UCC_SLOW_UCCE_DCC 0x0400 -#define UCC_SLOW_UCCE_FLG 0x0200 -#define UCC_SLOW_UCCE_AB 0x0200 -#define UCC_SLOW_UCCE_IDLE 0x0100 -#define UCC_SLOW_UCCE_GRA 0x0080 -#define UCC_SLOW_UCCE_TXE 0x0010 -#define UCC_SLOW_UCCE_RXF 0x0008 -#define UCC_SLOW_UCCE_CCR 0x0008 -#define UCC_SLOW_UCCE_RCH 0x0008 -#define UCC_SLOW_UCCE_BSY 0x0004 -#define UCC_SLOW_UCCE_TXB 0x0002 -#define UCC_SLOW_UCCE_TX 0x0002 -#define UCC_SLOW_UCCE_RX 0x0001 -#define UCC_SLOW_UCCE_GOV 0x0001 -#define UCC_SLOW_UCCE_GUN 0x0002 -#define UCC_SLOW_UCCE_GINT 0x0004 -#define UCC_SLOW_UCCE_IQOV 0x0008 - -#define UCC_SLOW_UCCE_HDLC_SET (UCC_SLOW_UCCE_TXE | UCC_SLOW_UCCE_BSY | \ - UCC_SLOW_UCCE_GRA | UCC_SLOW_UCCE_TXB | UCC_SLOW_UCCE_RXF | \ - UCC_SLOW_UCCE_DCC | UCC_SLOW_UCCE_GLT | UCC_SLOW_UCCE_GLR) -#define UCC_SLOW_UCCE_ENET_SET (UCC_SLOW_UCCE_TXE | UCC_SLOW_UCCE_BSY | \ - UCC_SLOW_UCCE_GRA | UCC_SLOW_UCCE_TXB | UCC_SLOW_UCCE_RXF) -#define UCC_SLOW_UCCE_TRANS_SET (UCC_SLOW_UCCE_TXE | UCC_SLOW_UCCE_BSY | \ - UCC_SLOW_UCCE_GRA | UCC_SLOW_UCCE_TX | UCC_SLOW_UCCE_RX | \ - UCC_SLOW_UCCE_DCC | UCC_SLOW_UCCE_GLT | UCC_SLOW_UCCE_GLR) -#define UCC_SLOW_UCCE_UART_SET (UCC_SLOW_UCCE_BSY | UCC_SLOW_UCCE_GRA | \ - UCC_SLOW_UCCE_TXB | UCC_SLOW_UCCE_TX | UCC_SLOW_UCCE_RX | \ - UCC_SLOW_UCCE_GLT | UCC_SLOW_UCCE_GLR) -#define UCC_SLOW_UCCE_QMC_SET (UCC_SLOW_UCCE_IQOV | UCC_SLOW_UCCE_GINT | \ - UCC_SLOW_UCCE_GUN | UCC_SLOW_UCCE_GOV) - -#define UCC_SLOW_UCCE_OTHER (UCC_SLOW_UCCE_TXE | UCC_SLOW_UCCE_BSY | \ - UCC_SLOW_UCCE_GRA | UCC_SLOW_UCCE_DCC | UCC_SLOW_UCCE_GLT | \ - UCC_SLOW_UCCE_GLR) - -#define UCC_SLOW_INTR_TX UCC_SLOW_UCCE_TXB -#define UCC_SLOW_INTR_RX (UCC_SLOW_UCCE_RXF | UCC_SLOW_UCCE_RX) -#define UCC_SLOW_INTR (UCC_SLOW_INTR_TX | UCC_SLOW_INTR_RX) +/* UART Slow UCC Event Register (UCCE) */ +#define UCC_UART_UCCE_AB 0x0200 +#define UCC_UART_UCCE_IDLE 0x0100 +#define UCC_UART_UCCE_GRA 0x0080 +#define UCC_UART_UCCE_BRKE 0x0040 +#define UCC_UART_UCCE_BRKS 0x0020 +#define UCC_UART_UCCE_CCR 0x0008 +#define UCC_UART_UCCE_BSY 0x0004 +#define UCC_UART_UCCE_TX 0x0002 +#define UCC_UART_UCCE_RX 0x0001 + +/* HDLC Slow UCC Event Register (UCCE) */ +#define UCC_HDLC_UCCE_GLR 0x1000 +#define UCC_HDLC_UCCE_GLT 0x0800 +#define UCC_HDLC_UCCE_IDLE 0x0100 +#define UCC_HDLC_UCCE_BRKE 0x0040 +#define UCC_HDLC_UCCE_BRKS 0x0020 +#define UCC_HDLC_UCCE_TXE 0x0010 +#define UCC_HDLC_UCCE_RXF 0x0008 +#define UCC_HDLC_UCCE_BSY 0x0004 +#define UCC_HDLC_UCCE_TXB 0x0002 +#define UCC_HDLC_UCCE_RXB 0x0001 + +/* BISYNC Slow UCC Event Register (UCCE) */ +#define UCC_BISYNC_UCCE_GRA 0x0080 +#define UCC_BISYNC_UCCE_TXE 0x0010 +#define UCC_BISYNC_UCCE_RCH 0x0008 +#define UCC_BISYNC_UCCE_BSY 0x0004 +#define UCC_BISYNC_UCCE_TXB 0x0002 +#define UCC_BISYNC_UCCE_RXB 0x0001 + +/* Gigabit Ethernet Fast UCC Event Register (UCCE) */ +#define UCC_GETH_UCCE_MPD 0x80000000 +#define UCC_GETH_UCCE_SCAR 0x40000000 +#define UCC_GETH_UCCE_GRA 0x20000000 +#define UCC_GETH_UCCE_CBPR 0x10000000 +#define UCC_GETH_UCCE_BSY 0x08000000 +#define UCC_GETH_UCCE_RXC 0x04000000 +#define UCC_GETH_UCCE_TXC 0x02000000 +#define UCC_GETH_UCCE_TXE 0x01000000 +#define UCC_GETH_UCCE_TXB7 0x00800000 +#define UCC_GETH_UCCE_TXB6 0x00400000 +#define UCC_GETH_UCCE_TXB5 0x00200000 +#define UCC_GETH_UCCE_TXB4 0x00100000 +#define UCC_GETH_UCCE_TXB3 0x00080000 +#define UCC_GETH_UCCE_TXB2 0x00040000 +#define UCC_GETH_UCCE_TXB1 0x00020000 +#define UCC_GETH_UCCE_TXB0 0x00010000 +#define UCC_GETH_UCCE_RXB7 0x00008000 +#define UCC_GETH_UCCE_RXB6 0x00004000 +#define UCC_GETH_UCCE_RXB5 0x00002000 +#define UCC_GETH_UCCE_RXB4 0x00001000 +#define UCC_GETH_UCCE_RXB3 0x00000800 +#define UCC_GETH_UCCE_RXB2 0x00000400 +#define UCC_GETH_UCCE_RXB1 0x00000200 +#define UCC_GETH_UCCE_RXB0 0x00000100 +#define UCC_GETH_UCCE_RXF7 0x00000080 +#define UCC_GETH_UCCE_RXF6 0x00000040 +#define UCC_GETH_UCCE_RXF5 0x00000020 +#define UCC_GETH_UCCE_RXF4 0x00000010 +#define UCC_GETH_UCCE_RXF3 0x00000008 +#define UCC_GETH_UCCE_RXF2 0x00000004 +#define UCC_GETH_UCCE_RXF1 0x00000002 +#define UCC_GETH_UCCE_RXF0 0x00000001 + +/* UPSMR, when used as a UART */ +#define UCC_UART_UPSMR_FLC 0x8000 +#define UCC_UART_UPSMR_SL 0x4000 +#define UCC_UART_UPSMR_CL_MASK 0x3000 +#define UCC_UART_UPSMR_CL_8 0x3000 +#define UCC_UART_UPSMR_CL_7 0x2000 +#define UCC_UART_UPSMR_CL_6 0x1000 +#define UCC_UART_UPSMR_CL_5 0x0000 +#define UCC_UART_UPSMR_UM_MASK 0x0c00 +#define UCC_UART_UPSMR_UM_NORMAL 0x0000 +#define UCC_UART_UPSMR_UM_MAN_MULTI 0x0400 +#define UCC_UART_UPSMR_UM_AUTO_MULTI 0x0c00 +#define UCC_UART_UPSMR_FRZ 0x0200 +#define UCC_UART_UPSMR_RZS 0x0100 +#define UCC_UART_UPSMR_SYN 0x0080 +#define UCC_UART_UPSMR_DRT 0x0040 +#define UCC_UART_UPSMR_PEN 0x0010 +#define UCC_UART_UPSMR_RPM_MASK 0x000c +#define UCC_UART_UPSMR_RPM_ODD 0x0000 +#define UCC_UART_UPSMR_RPM_LOW 0x0004 +#define UCC_UART_UPSMR_RPM_EVEN 0x0008 +#define UCC_UART_UPSMR_RPM_HIGH 0x000C +#define UCC_UART_UPSMR_TPM_MASK 0x0003 +#define UCC_UART_UPSMR_TPM_ODD 0x0000 +#define UCC_UART_UPSMR_TPM_LOW 0x0001 +#define UCC_UART_UPSMR_TPM_EVEN 0x0002 +#define UCC_UART_UPSMR_TPM_HIGH 0x0003 /* UCC Transmit On Demand Register (UTODR) */ #define UCC_SLOW_TOD 0x8000 #define UCC_FAST_TOD 0x8000 +/* UCC Bus Mode Register masks */ +/* Not to be confused with the Bundle Mode Register */ +#define UCC_BMR_GBL 0x20 +#define UCC_BMR_BO_BE 0x10 +#define UCC_BMR_CETM 0x04 +#define UCC_BMR_DTB 0x02 +#define UCC_BMR_BDB 0x01 + /* Function code masks */ #define FC_GBL 0x20 #define FC_DTB_LCL 0x02 diff --git a/include/asm-powerpc/ucc.h b/include/asm-powerpc/ucc.h index afe3076bdc0..46b09ba6bea 100644 --- a/include/asm-powerpc/ucc.h +++ b/include/asm-powerpc/ucc.h @@ -25,58 +25,38 @@ /* Slow or fast type for UCCs. */ enum ucc_speed_type { - UCC_SPEED_TYPE_FAST, UCC_SPEED_TYPE_SLOW -}; - -/* Initial UCCs Parameter RAM address relative to: MEM_MAP_BASE (IMMR). -*/ -enum ucc_pram_initial_offset { - UCC_PRAM_OFFSET_UCC1 = 0x8400, - UCC_PRAM_OFFSET_UCC2 = 0x8500, - UCC_PRAM_OFFSET_UCC3 = 0x8600, - UCC_PRAM_OFFSET_UCC4 = 0x9000, - UCC_PRAM_OFFSET_UCC5 = 0x8000, - UCC_PRAM_OFFSET_UCC6 = 0x8100, - UCC_PRAM_OFFSET_UCC7 = 0x8200, - UCC_PRAM_OFFSET_UCC8 = 0x8300 + UCC_SPEED_TYPE_FAST = UCC_GUEMR_MODE_FAST_RX | UCC_GUEMR_MODE_FAST_TX, + UCC_SPEED_TYPE_SLOW = UCC_GUEMR_MODE_SLOW_RX | UCC_GUEMR_MODE_SLOW_TX }; /* ucc_set_type * Sets UCC to slow or fast mode. * * ucc_num - (In) number of UCC (0-7). - * regs - (In) pointer to registers base for the UCC. * speed - (In) slow or fast mode for UCC. */ -int ucc_set_type(int ucc_num, struct ucc_common *regs, - enum ucc_speed_type speed); - -/* ucc_init_guemr - * Init the Guemr register. - * - * regs - (In) pointer to registers base for the UCC. - */ -int ucc_init_guemr(struct ucc_common *regs); +int ucc_set_type(unsigned int ucc_num, enum ucc_speed_type speed); -int ucc_set_qe_mux_mii_mng(int ucc_num); +int ucc_set_qe_mux_mii_mng(unsigned int ucc_num); -int ucc_set_qe_mux_rxtx(int ucc_num, enum qe_clock clock, enum comm_dir mode); +int ucc_set_qe_mux_rxtx(unsigned int ucc_num, enum qe_clock clock, + enum comm_dir mode); -int ucc_mux_set_grant_tsa_bkpt(int ucc_num, int set, u32 mask); +int ucc_mux_set_grant_tsa_bkpt(unsigned int ucc_num, int set, u32 mask); /* QE MUX clock routing for UCC */ -static inline int ucc_set_qe_mux_grant(int ucc_num, int set) +static inline int ucc_set_qe_mux_grant(unsigned int ucc_num, int set) { return ucc_mux_set_grant_tsa_bkpt(ucc_num, set, QE_CMXUCR_GRANT); } -static inline int ucc_set_qe_mux_tsa(int ucc_num, int set) +static inline int ucc_set_qe_mux_tsa(unsigned int ucc_num, int set) { return ucc_mux_set_grant_tsa_bkpt(ucc_num, set, QE_CMXUCR_TSA); } -static inline int ucc_set_qe_mux_bkpt(int ucc_num, int set) +static inline int ucc_set_qe_mux_bkpt(unsigned int ucc_num, int set) { return ucc_mux_set_grant_tsa_bkpt(ucc_num, set, QE_CMXUCR_BKPT); } diff --git a/include/asm-powerpc/ucc_slow.h b/include/asm-powerpc/ucc_slow.h index fdaac9d762b..0980e6ad335 100644 --- a/include/asm-powerpc/ucc_slow.h +++ b/include/asm-powerpc/ucc_slow.h @@ -148,9 +148,10 @@ enum ucc_slow_diag_mode { struct ucc_slow_info { int ucc_num; + int protocol; /* QE_CR_PROTOCOL_xxx */ enum qe_clock rx_clock; enum qe_clock tx_clock; - u32 regs; + phys_addr_t regs; int irq; u16 uccm_mask; int data_mem_part; @@ -186,7 +187,7 @@ struct ucc_slow_info { struct ucc_slow_private { struct ucc_slow_info *us_info; - struct ucc_slow *us_regs; /* a pointer to memory map of UCC regs */ + struct ucc_slow __iomem *us_regs; /* Ptr to memory map of UCC regs */ struct ucc_slow_pram *us_pram; /* a pointer to the parameter RAM */ u32 us_pram_offset; int enabled_tx; /* Whether channel is enabled for Tx (ENT) */ @@ -277,12 +278,12 @@ void ucc_slow_graceful_stop_tx(struct ucc_slow_private * uccs); */ void ucc_slow_stop_tx(struct ucc_slow_private * uccs); -/* ucc_slow_restart_x +/* ucc_slow_restart_tx * Restarts transmitting on a specified slow UCC. * * uccs - (In) pointer to the slow UCC structure. */ -void ucc_slow_restart_x(struct ucc_slow_private * uccs); +void ucc_slow_restart_tx(struct ucc_slow_private *uccs); u32 ucc_slow_get_qe_cr_subblock(int uccs_num); -- cgit v1.2.3-70-g09d2 From 258de4badd5b7b5d168307638f755bd4df16c18e Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 4 Oct 2007 10:48:36 -0600 Subject: [POWERPC] XilinxFB: add banner output to probe routine when DEBUG is defined Debug support: when DEBUG is defined, output relevant details to the log about the framebuffer registration. Signed-off-by: Grant Likely Acked-by: Andrei Konovalov --- drivers/video/xilinxfb.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index 4bc67ab56af..1a5f1e429c4 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c @@ -287,6 +287,11 @@ xilinxfb_drv_probe(struct device *dev) goto failed4; } + /* Put a banner in the log (for DEBUG) */ + dev_dbg(dev, "regs: phys=%x, virt=%p\n", + drvdata->regs_phys, drvdata->regs); + dev_dbg(dev, "fb: phys=%p, virt=%p, size=%x\n", + (void*)drvdata->fb_phys, drvdata->fb_virt, FB_SIZE); return 0; /* success */ failed4: -- cgit v1.2.3-70-g09d2 From 3cb3ec2c26473d8123a468abfaca1e926344b1c2 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 4 Oct 2007 10:48:36 -0600 Subject: [POWERPC] XilinxFB: Replace calls to printk with dev_dbg, dev_err, etc. The dev_dbg, dev_err, etc functions provide more context that plain vanilla printk which is useful for debugging. Where appropriate, change printk calls to the appropriate dev_*() call. Signed-off-by: Grant Likely Acked-by: Andrei Konovalov --- drivers/video/xilinxfb.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index 1a5f1e429c4..e63cbd1acfd 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c @@ -18,6 +18,7 @@ * Geert Uytterhoeven. */ +#include #include #include #include @@ -214,7 +215,7 @@ xilinxfb_drv_probe(struct device *dev) drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL); if (!drvdata) { - printk(KERN_ERR "Couldn't allocate device private record\n"); + dev_err(dev, "Couldn't allocate device private record\n"); return -ENOMEM; } dev_set_drvdata(dev, drvdata); @@ -222,14 +223,13 @@ xilinxfb_drv_probe(struct device *dev) /* Map the control registers in */ regs_res = platform_get_resource(pdev, IORESOURCE_IO, 0); if (!regs_res || (regs_res->end - regs_res->start + 1 < 8)) { - printk(KERN_ERR "Couldn't get registers resource\n"); + dev_err(dev, "Couldn't get registers resource\n"); retval = -EFAULT; goto failed1; } if (!request_mem_region(regs_res->start, 8, DRIVER_NAME)) { - printk(KERN_ERR - "Couldn't lock memory region at 0x%08X\n", + dev_err(dev, "Couldn't lock memory region at 0x%08X\n", regs_res->start); retval = -EBUSY; goto failed1; @@ -241,7 +241,7 @@ xilinxfb_drv_probe(struct device *dev) drvdata->fb_virt = dma_alloc_coherent(dev, PAGE_ALIGN(FB_SIZE), &drvdata->fb_phys, GFP_KERNEL); if (!drvdata->fb_virt) { - printk(KERN_ERR "Could not allocate frame buffer memory\n"); + dev_err(dev, "Could not allocate frame buffer memory\n"); retval = -ENOMEM; goto failed2; } @@ -267,7 +267,7 @@ xilinxfb_drv_probe(struct device *dev) drvdata->info.pseudo_palette = drvdata->pseudo_palette; if (fb_alloc_cmap(&drvdata->info.cmap, PALETTE_ENTRIES_NO, 0) < 0) { - printk(KERN_ERR "Fail to allocate colormap (%d entries)\n", + dev_err(dev, "Fail to allocate colormap (%d entries)\n", PALETTE_ENTRIES_NO); retval = -EFAULT; goto failed3; @@ -282,7 +282,7 @@ xilinxfb_drv_probe(struct device *dev) /* Register new frame buffer */ if (register_framebuffer(&drvdata->info) < 0) { - printk(KERN_ERR "Could not register frame buffer\n"); + dev_err(dev, "Could not register frame buffer\n"); retval = -EINVAL; goto failed4; } -- cgit v1.2.3-70-g09d2 From 3fb99ce4e2748dafe3f10dba2932f0d13f577623 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 4 Oct 2007 10:48:37 -0600 Subject: [POWERPC] XilinxFB: rename failout labels to reflect failure Labels and gotos are used in xilinxfb_assign to unwind allocations on device registration failures. Rename the labels to reflect the error which occured. This change is being made to make it easier to add new failout paths (which occurs in a subsuquent patch) and to make reviewing the failout path easier. Signed-off-by: Grant Likely Acked-by: Andrei Konovalov --- drivers/video/xilinxfb.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index e63cbd1acfd..9aa754a2521 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c @@ -225,14 +225,14 @@ xilinxfb_drv_probe(struct device *dev) if (!regs_res || (regs_res->end - regs_res->start + 1 < 8)) { dev_err(dev, "Couldn't get registers resource\n"); retval = -EFAULT; - goto failed1; + goto err_region; } if (!request_mem_region(regs_res->start, 8, DRIVER_NAME)) { dev_err(dev, "Couldn't lock memory region at 0x%08X\n", regs_res->start); retval = -EBUSY; - goto failed1; + goto err_region; } drvdata->regs = (u32 __iomem*) ioremap(regs_res->start, 8); drvdata->regs_phys = regs_res->start; @@ -243,7 +243,7 @@ xilinxfb_drv_probe(struct device *dev) if (!drvdata->fb_virt) { dev_err(dev, "Could not allocate frame buffer memory\n"); retval = -ENOMEM; - goto failed2; + goto err_fbmem; } /* Clear (turn to black) the framebuffer */ @@ -270,7 +270,7 @@ xilinxfb_drv_probe(struct device *dev) dev_err(dev, "Fail to allocate colormap (%d entries)\n", PALETTE_ENTRIES_NO); retval = -EFAULT; - goto failed3; + goto err_cmap; } drvdata->info.flags = FBINFO_DEFAULT; @@ -284,7 +284,7 @@ xilinxfb_drv_probe(struct device *dev) if (register_framebuffer(&drvdata->info) < 0) { dev_err(dev, "Could not register frame buffer\n"); retval = -EINVAL; - goto failed4; + goto err_regfb; } /* Put a banner in the log (for DEBUG) */ @@ -294,10 +294,10 @@ xilinxfb_drv_probe(struct device *dev) (void*)drvdata->fb_phys, drvdata->fb_virt, FB_SIZE); return 0; /* success */ -failed4: +err_regfb: fb_dealloc_cmap(&drvdata->info.cmap); -failed3: +err_cmap: dma_free_coherent(dev, PAGE_ALIGN(FB_SIZE), drvdata->fb_virt, drvdata->fb_phys); @@ -305,10 +305,10 @@ failed3: xilinx_fb_out_be32(drvdata, REG_CTRL, 0); iounmap(drvdata->regs); -failed2: +err_fbmem: release_mem_region(regs_res->start, 8); -failed1: +err_region: kfree(drvdata); dev_set_drvdata(dev, NULL); -- cgit v1.2.3-70-g09d2 From 264776224d3bb0cd80bc0ec11a769e05a58f8c6b Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 4 Oct 2007 10:48:37 -0600 Subject: [POWERPC] XilinxFB: Split device setup from bus binding Split the device setup code away from the platform bus binding. This is in preparation for adding the of_platform bus binding to this driver and most of the setup code is common between the two busses. Signed-off-by: Grant Likely Acked-by: Andrei Konovalov --- drivers/video/xilinxfb.c | 133 ++++++++++++++++++++++++++++------------------- 1 file changed, 80 insertions(+), 53 deletions(-) (limited to 'drivers') diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index 9aa754a2521..12d91279996 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c @@ -196,23 +196,17 @@ static struct fb_ops xilinxfb_ops = .fb_imageblit = cfb_imageblit, }; -/* === The device driver === */ +/* --------------------------------------------------------------------- + * Bus independent setup/teardown + */ -static int -xilinxfb_drv_probe(struct device *dev) +static int xilinxfb_assign(struct device *dev, unsigned long physaddr, + int width_mm, int height_mm, int rotate) { - struct platform_device *pdev; - struct xilinxfb_platform_data *pdata; struct xilinxfb_drvdata *drvdata; - struct resource *regs_res; - int retval; - - if (!dev) - return -EINVAL; - - pdev = to_platform_device(dev); - pdata = pdev->dev.platform_data; + int rc; + /* Allocate the driver data region */ drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL); if (!drvdata) { dev_err(dev, "Couldn't allocate device private record\n"); @@ -221,40 +215,39 @@ xilinxfb_drv_probe(struct device *dev) dev_set_drvdata(dev, drvdata); /* Map the control registers in */ - regs_res = platform_get_resource(pdev, IORESOURCE_IO, 0); - if (!regs_res || (regs_res->end - regs_res->start + 1 < 8)) { - dev_err(dev, "Couldn't get registers resource\n"); - retval = -EFAULT; + if (!request_mem_region(physaddr, 8, DRIVER_NAME)) { + dev_err(dev, "Couldn't lock memory region at 0x%08lX\n", + physaddr); + rc = -ENODEV; goto err_region; } - - if (!request_mem_region(regs_res->start, 8, DRIVER_NAME)) { - dev_err(dev, "Couldn't lock memory region at 0x%08X\n", - regs_res->start); - retval = -EBUSY; - goto err_region; + drvdata->regs_phys = physaddr; + drvdata->regs = ioremap(physaddr, 8); + if (!drvdata->regs) { + dev_err(dev, "Couldn't lock memory region at 0x%08lX\n", + physaddr); + rc = -ENODEV; + goto err_map; } - drvdata->regs = (u32 __iomem*) ioremap(regs_res->start, 8); - drvdata->regs_phys = regs_res->start; /* Allocate the framebuffer memory */ drvdata->fb_virt = dma_alloc_coherent(dev, PAGE_ALIGN(FB_SIZE), &drvdata->fb_phys, GFP_KERNEL); if (!drvdata->fb_virt) { dev_err(dev, "Could not allocate frame buffer memory\n"); - retval = -ENOMEM; + rc = -ENOMEM; goto err_fbmem; } /* Clear (turn to black) the framebuffer */ - memset_io((void *) drvdata->fb_virt, 0, FB_SIZE); + memset_io(drvdata->fb_virt, 0, FB_SIZE); /* Tell the hardware where the frame buffer is */ xilinx_fb_out_be32(drvdata, REG_FB_ADDR, drvdata->fb_phys); /* Turn on the display */ drvdata->reg_ctrl_default = REG_CTRL_ENABLE; - if (pdata && pdata->rotate_screen) + if (rotate) drvdata->reg_ctrl_default |= REG_CTRL_ROTATE; xilinx_fb_out_be32(drvdata, REG_CTRL, drvdata->reg_ctrl_default); @@ -265,31 +258,29 @@ xilinxfb_drv_probe(struct device *dev) drvdata->info.fix = xilinx_fb_fix; drvdata->info.fix.smem_start = drvdata->fb_phys; drvdata->info.pseudo_palette = drvdata->pseudo_palette; + drvdata->info.flags = FBINFO_DEFAULT; + drvdata->info.var = xilinx_fb_var; + + xilinx_fb_var.height = height_mm; + xilinx_fb_var.width = width_mm; - if (fb_alloc_cmap(&drvdata->info.cmap, PALETTE_ENTRIES_NO, 0) < 0) { + /* Allocate a colour map */ + rc = fb_alloc_cmap(&drvdata->info.cmap, PALETTE_ENTRIES_NO, 0); + if (rc) { dev_err(dev, "Fail to allocate colormap (%d entries)\n", PALETTE_ENTRIES_NO); - retval = -EFAULT; goto err_cmap; } - drvdata->info.flags = FBINFO_DEFAULT; - if (pdata) { - xilinx_fb_var.height = pdata->screen_height_mm; - xilinx_fb_var.width = pdata->screen_width_mm; - } - drvdata->info.var = xilinx_fb_var; - /* Register new frame buffer */ - if (register_framebuffer(&drvdata->info) < 0) { + rc = register_framebuffer(&drvdata->info); + if (rc) { dev_err(dev, "Could not register frame buffer\n"); - retval = -EINVAL; goto err_regfb; } /* Put a banner in the log (for DEBUG) */ - dev_dbg(dev, "regs: phys=%x, virt=%p\n", - drvdata->regs_phys, drvdata->regs); + dev_dbg(dev, "regs: phys=%lx, virt=%p\n", physaddr, drvdata->regs); dev_dbg(dev, "fb: phys=%p, virt=%p, size=%x\n", (void*)drvdata->fb_phys, drvdata->fb_virt, FB_SIZE); return 0; /* success */ @@ -300,30 +291,25 @@ err_regfb: err_cmap: dma_free_coherent(dev, PAGE_ALIGN(FB_SIZE), drvdata->fb_virt, drvdata->fb_phys); - /* Turn off the display */ xilinx_fb_out_be32(drvdata, REG_CTRL, 0); - iounmap(drvdata->regs); err_fbmem: - release_mem_region(regs_res->start, 8); + iounmap(drvdata->regs); + +err_map: + release_mem_region(physaddr, 8); err_region: kfree(drvdata); dev_set_drvdata(dev, NULL); - return retval; + return rc; } -static int -xilinxfb_drv_remove(struct device *dev) +static int xilinxfb_release(struct device *dev) { - struct xilinxfb_drvdata *drvdata; - - if (!dev) - return -ENODEV; - - drvdata = (struct xilinxfb_drvdata *) dev_get_drvdata(dev); + struct xilinxfb_drvdata *drvdata = dev_get_drvdata(dev); #if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO) xilinx_fb_blank(VESA_POWERDOWN, &drvdata->info); @@ -348,6 +334,47 @@ xilinxfb_drv_remove(struct device *dev) return 0; } +/* --------------------------------------------------------------------- + * Platform bus binding + */ + +static int +xilinxfb_drv_probe(struct device *dev) +{ + struct platform_device *pdev; + struct xilinxfb_platform_data *pdata; + struct resource *res; + int width_mm; + int height_mm; + int rotate; + + pdev = to_platform_device(dev); + pdata = pdev->dev.platform_data; + if (!pdata) { + dev_err(dev, "Missing pdata structure\n"); + return -ENODEV; + } + + /* Find the registers address */ + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!res) { + dev_err(dev, "Couldn't get registers resource\n"); + return -ENODEV; + } + + height_mm = pdata->screen_height_mm; + width_mm = pdata->screen_width_mm; + rotate = pdata->rotate_screen ? 1 : 0; + + return xilinxfb_assign(dev, res->start, width_mm, height_mm, rotate); +} + +static int +xilinxfb_drv_remove(struct device *dev) +{ + return xilinxfb_release(dev); +} + static struct device_driver xilinxfb_driver = { .name = DRIVER_NAME, -- cgit v1.2.3-70-g09d2 From 47473e31585032e5c048eeec50e0f9165890230a Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 4 Oct 2007 10:48:37 -0600 Subject: [POWERPC] XilinxFB: cleanup platform_bus binding to use platform bus API. Change the platform bus binding to make use of the established platform_bus API. Signed-off-by: Grant Likely Acked-by: Andrei Konovalov --- drivers/video/xilinxfb.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index 12d91279996..e482bb51963 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c @@ -339,26 +339,24 @@ static int xilinxfb_release(struct device *dev) */ static int -xilinxfb_drv_probe(struct device *dev) +xilinxfb_platform_probe(struct platform_device *pdev) { - struct platform_device *pdev; struct xilinxfb_platform_data *pdata; struct resource *res; int width_mm; int height_mm; int rotate; - pdev = to_platform_device(dev); pdata = pdev->dev.platform_data; if (!pdata) { - dev_err(dev, "Missing pdata structure\n"); + dev_err(&pdev->dev, "Missing pdata structure\n"); return -ENODEV; } /* Find the registers address */ res = platform_get_resource(pdev, IORESOURCE_IO, 0); if (!res) { - dev_err(dev, "Couldn't get registers resource\n"); + dev_err(&pdev->dev, "Couldn't get registers resource\n"); return -ENODEV; } @@ -366,22 +364,24 @@ xilinxfb_drv_probe(struct device *dev) width_mm = pdata->screen_width_mm; rotate = pdata->rotate_screen ? 1 : 0; - return xilinxfb_assign(dev, res->start, width_mm, height_mm, rotate); + return xilinxfb_assign(&pdev->dev, res->start, width_mm, height_mm, + rotate); } static int -xilinxfb_drv_remove(struct device *dev) +xilinxfb_platform_remove(struct platform_device *pdev) { - return xilinxfb_release(dev); + return xilinxfb_release(&pdev->dev); } -static struct device_driver xilinxfb_driver = { - .name = DRIVER_NAME, - .bus = &platform_bus_type, - - .probe = xilinxfb_drv_probe, - .remove = xilinxfb_drv_remove +static struct platform_driver xilinxfb_platform_driver = { + .probe = xilinxfb_platform_probe, + .remove = xilinxfb_platform_remove, + .driver = { + .owner = THIS_MODULE, + .name = DRIVER_NAME, + }, }; static int __init @@ -391,13 +391,13 @@ xilinxfb_init(void) * No kernel boot options used, * so we just need to register the driver */ - return driver_register(&xilinxfb_driver); + return platform_driver_register(&xilinxfb_platform_driver); } static void __exit xilinxfb_cleanup(void) { - driver_unregister(&xilinxfb_driver); + platform_driver_unregister(&xilinxfb_platform_driver); } module_init(xilinxfb_init); -- cgit v1.2.3-70-g09d2 From 31e8d4603ecaeb02424c9669e252ab835354a36e Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 4 Oct 2007 10:48:37 -0600 Subject: [POWERPC] XilinxFB: add of_platform bus binding Adds the of_platform bus binding to the xilinxfb driver. Needed to use framebuffer devices described in the OF device tree (used by arch/powerpc). Signed-off-by: Grant Likely Acked-by: Andrei Konovalov --- drivers/video/xilinxfb.c | 107 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 98 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index e482bb51963..dbb23a9fef7 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c @@ -6,9 +6,12 @@ * Author: MontaVista Software, Inc. * source@mvista.com * - * 2002-2007 (c) MontaVista Software, Inc. This file is licensed under the - * terms of the GNU General Public License version 2. This program is licensed - * "as is" without any warranty of any kind, whether express or implied. + * 2002-2007 (c) MontaVista Software, Inc. + * 2007 (c) Secret Lab Technologies, Ltd. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. */ /* @@ -29,7 +32,10 @@ #include #include #include - +#if defined(CONFIG_OF) +#include +#include +#endif #include #include @@ -384,20 +390,103 @@ static struct platform_driver xilinxfb_platform_driver = { }, }; +/* --------------------------------------------------------------------- + * OF bus binding + */ + +#if defined(CONFIG_OF) +static int __devinit +xilinxfb_of_probe(struct of_device *op, const struct of_device_id *match) +{ + struct resource res; + const u32 *prop; + int width = 0, height = 0, rotate = 0; + int size, rc; + + dev_dbg(&op->dev, "xilinxfb_of_probe(%p, %p)\n", op, match); + + rc = of_address_to_resource(op->node, 0, &res); + if (rc) { + dev_err(&op->dev, "invalid address\n"); + return rc; + } + + prop = of_get_property(op->node, "display-number", &size); + if ((prop) && (size >= sizeof(u32)*2)) { + width = prop[0]; + height = prop[1]; + } + + if (of_find_property(op->node, "rotate-display", NULL)) + rotate = 1; + + return xilinxfb_assign(&op->dev, res.start, width, height, rotate); +} + +static int __devexit xilinxfb_of_remove(struct of_device *op) +{ + return xilinxfb_release(&op->dev); +} + +/* Match table for of_platform binding */ +static struct of_device_id __devinit xilinxfb_of_match[] = { + { .compatible = "xilinx,ml300-fb", }, + {}, +}; +MODULE_DEVICE_TABLE(of, xilinxfb_of_match); + +static struct of_platform_driver xilinxfb_of_driver = { + .owner = THIS_MODULE, + .name = DRIVER_NAME, + .match_table = xilinxfb_of_match, + .probe = xilinxfb_of_probe, + .remove = __devexit_p(xilinxfb_of_remove), + .driver = { + .name = DRIVER_NAME, + }, +}; + +/* Registration helpers to keep the number of #ifdefs to a minimum */ +static inline int __init xilinxfb_of_register(void) +{ + pr_debug("xilinxfb: calling of_register_platform_driver()\n"); + return of_register_platform_driver(&xilinxfb_of_driver); +} + +static inline void __exit xilinxfb_of_unregister(void) +{ + of_unregister_platform_driver(&xilinxfb_of_driver); +} +#else /* CONFIG_OF */ +/* CONFIG_OF not enabled; do nothing helpers */ +static inline int __init xilinxfb_of_register(void) { return 0; } +static inline void __exit xilinxfb_of_unregister(void) { } +#endif /* CONFIG_OF */ + +/* --------------------------------------------------------------------- + * Module setup and teardown + */ + static int __init xilinxfb_init(void) { - /* - * No kernel boot options used, - * so we just need to register the driver - */ - return platform_driver_register(&xilinxfb_platform_driver); + int rc; + rc = xilinxfb_of_register(); + if (rc) + return rc; + + rc = platform_driver_register(&xilinxfb_platform_driver); + if (rc) + xilinxfb_of_unregister(); + + return rc; } static void __exit xilinxfb_cleanup(void) { platform_driver_unregister(&xilinxfb_platform_driver); + xilinxfb_of_unregister(); } module_init(xilinxfb_init); -- cgit v1.2.3-70-g09d2 From e3cec00366e9d60ff65c6f6f8fffdfcadea01056 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 4 Oct 2007 15:44:52 -0600 Subject: [POWERPC] XilinxFB: Make missing pdata structure non-fatal Missing pdata structure is not a fatal error. The device can still be initialized without it. Signed-off-by: Grant Likely --- drivers/video/xilinxfb.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index dbb23a9fef7..e6e12be845a 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c @@ -349,15 +349,9 @@ xilinxfb_platform_probe(struct platform_device *pdev) { struct xilinxfb_platform_data *pdata; struct resource *res; - int width_mm; - int height_mm; - int rotate; - - pdata = pdev->dev.platform_data; - if (!pdata) { - dev_err(&pdev->dev, "Missing pdata structure\n"); - return -ENODEV; - } + int width_mm = 0; + int height_mm = 0; + int rotate = 0; /* Find the registers address */ res = platform_get_resource(pdev, IORESOURCE_IO, 0); @@ -366,9 +360,13 @@ xilinxfb_platform_probe(struct platform_device *pdev) return -ENODEV; } - height_mm = pdata->screen_height_mm; - width_mm = pdata->screen_width_mm; - rotate = pdata->rotate_screen ? 1 : 0; + /* If a pdata structure is provided, then extract the parameters */ + pdata = pdev->dev.platform_data; + if (pdata) { + height_mm = pdata->screen_height_mm; + width_mm = pdata->screen_width_mm; + rotate = pdata->rotate_screen ? 1 : 0; + } return xilinxfb_assign(&pdev->dev, res->start, width_mm, height_mm, rotate); -- cgit v1.2.3-70-g09d2 From 1855256c497ecfefc730df6032243f26855ce52c Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 3 Oct 2007 15:15:40 -0400 Subject: drivers/firmware: const-ify DMI API and internals Three main sets of changes: 1) dmi_get_system_info() return value should have been marked const, since callers should not be changing that data. 2) const-ify DMI internals, since DMI firmware tables should, whenever possible, be marked const to ensure we never ever write to that data area. 3) const-ify DMI API, to enable marking tables const where possible in low-level drivers. And if we're really lucky, this might enable some additional optimizations on the part of the compiler. The bulk of the changes are #2 and #3, which are interrelated. #1 could have been a separate patch, but it was so small compared to the others, it was easier to roll it into this changeset. Signed-off-by: Jeff Garzik --- arch/i386/kernel/acpi/boot.c | 8 ++-- arch/i386/kernel/acpi/sleep.c | 2 +- arch/i386/kernel/apm.c | 18 ++++----- arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c | 4 +- arch/i386/kernel/reboot.c | 2 +- arch/i386/kernel/tsc.c | 2 +- arch/i386/mach-generic/bigsmp.c | 4 +- arch/i386/pci/common.c | 4 +- arch/i386/pci/irq.c | 4 +- drivers/acpi/osl.c | 2 +- drivers/acpi/processor_idle.c | 2 +- drivers/acpi/sleep/main.c | 2 +- drivers/acpi/thermal.c | 8 ++-- drivers/ata/ata_piix.c | 4 +- drivers/ata/pata_ali.c | 2 +- drivers/ata/pata_cs5530.c | 2 +- drivers/ata/pata_via.c | 2 +- drivers/char/i8k.c | 4 +- drivers/char/ipmi/ipmi_si_intf.c | 9 +++-- drivers/firmware/dmi_scan.c | 57 ++++++++++++++++------------- drivers/hwmon/abituguru.c | 2 +- drivers/hwmon/applesmc.c | 2 +- drivers/hwmon/hdaps.c | 4 +- drivers/ide/pci/alim15x3.c | 2 +- drivers/ide/pci/via82cxxx.c | 2 +- drivers/input/misc/wistron_btns.c | 2 +- drivers/input/mouse/lifebook.c | 6 +-- drivers/input/mouse/synaptics.c | 2 +- drivers/misc/msi-laptop.c | 2 +- drivers/misc/sony-laptop.c | 4 +- drivers/misc/thinkpad_acpi.c | 2 +- drivers/pnp/pnpbios/core.c | 2 +- drivers/usb/host/uhci-hcd.c | 2 +- drivers/video/imacfb.c | 2 +- include/linux/dmi.h | 22 +++++------ 35 files changed, 103 insertions(+), 97 deletions(-) (limited to 'drivers') diff --git a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c index cacdd883bf2..afd2afe9102 100644 --- a/arch/i386/kernel/acpi/boot.c +++ b/arch/i386/kernel/acpi/boot.c @@ -907,7 +907,7 @@ static void __init acpi_process_madt(void) #ifdef __i386__ -static int __init disable_acpi_irq(struct dmi_system_id *d) +static int __init disable_acpi_irq(const struct dmi_system_id *d) { if (!acpi_force) { printk(KERN_NOTICE "%s detected: force use of acpi=noirq\n", @@ -917,7 +917,7 @@ static int __init disable_acpi_irq(struct dmi_system_id *d) return 0; } -static int __init disable_acpi_pci(struct dmi_system_id *d) +static int __init disable_acpi_pci(const struct dmi_system_id *d) { if (!acpi_force) { printk(KERN_NOTICE "%s detected: force use of pci=noacpi\n", @@ -927,7 +927,7 @@ static int __init disable_acpi_pci(struct dmi_system_id *d) return 0; } -static int __init dmi_disable_acpi(struct dmi_system_id *d) +static int __init dmi_disable_acpi(const struct dmi_system_id *d) { if (!acpi_force) { printk(KERN_NOTICE "%s detected: acpi off\n", d->ident); @@ -942,7 +942,7 @@ static int __init dmi_disable_acpi(struct dmi_system_id *d) /* * Limit ACPI to CPU enumeration for HT */ -static int __init force_acpi_ht(struct dmi_system_id *d) +static int __init force_acpi_ht(const struct dmi_system_id *d) { if (!acpi_force) { printk(KERN_NOTICE "%s detected: force use of acpi=ht\n", diff --git a/arch/i386/kernel/acpi/sleep.c b/arch/i386/kernel/acpi/sleep.c index c42b5ab49de..10699489cfe 100644 --- a/arch/i386/kernel/acpi/sleep.c +++ b/arch/i386/kernel/acpi/sleep.c @@ -84,7 +84,7 @@ __setup("acpi_sleep=", acpi_sleep_setup); /* Ouch, we want to delete this. We already have better version in userspace, in s2ram from suspend.sf.net project */ -static __init int reset_videomode_after_s3(struct dmi_system_id *d) +static __init int reset_videomode_after_s3(const struct dmi_system_id *d) { acpi_realmode_flags |= 2; return 0; diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c index f02a8aca826..32f2365c26e 100644 --- a/arch/i386/kernel/apm.c +++ b/arch/i386/kernel/apm.c @@ -1869,7 +1869,7 @@ static struct miscdevice apm_device = { /* Simple "print if true" callback */ -static int __init print_if_true(struct dmi_system_id *d) +static int __init print_if_true(const struct dmi_system_id *d) { printk("%s\n", d->ident); return 0; @@ -1879,14 +1879,14 @@ static int __init print_if_true(struct dmi_system_id *d) * Some Bioses enable the PS/2 mouse (touchpad) at resume, even if it was * disabled before the suspend. Linux used to get terribly confused by that. */ -static int __init broken_ps2_resume(struct dmi_system_id *d) +static int __init broken_ps2_resume(const struct dmi_system_id *d) { printk(KERN_INFO "%s machine detected. Mousepad Resume Bug workaround hopefully not needed.\n", d->ident); return 0; } /* Some bioses have a broken protected mode poweroff and need to use realmode */ -static int __init set_realmode_power_off(struct dmi_system_id *d) +static int __init set_realmode_power_off(const struct dmi_system_id *d) { if (apm_info.realmode_power_off == 0) { apm_info.realmode_power_off = 1; @@ -1896,7 +1896,7 @@ static int __init set_realmode_power_off(struct dmi_system_id *d) } /* Some laptops require interrupts to be enabled during APM calls */ -static int __init set_apm_ints(struct dmi_system_id *d) +static int __init set_apm_ints(const struct dmi_system_id *d) { if (apm_info.allow_ints == 0) { apm_info.allow_ints = 1; @@ -1906,7 +1906,7 @@ static int __init set_apm_ints(struct dmi_system_id *d) } /* Some APM bioses corrupt memory or just plain do not work */ -static int __init apm_is_horked(struct dmi_system_id *d) +static int __init apm_is_horked(const struct dmi_system_id *d) { if (apm_info.disabled == 0) { apm_info.disabled = 1; @@ -1915,7 +1915,7 @@ static int __init apm_is_horked(struct dmi_system_id *d) return 0; } -static int __init apm_is_horked_d850md(struct dmi_system_id *d) +static int __init apm_is_horked_d850md(const struct dmi_system_id *d) { if (apm_info.disabled == 0) { apm_info.disabled = 1; @@ -1927,7 +1927,7 @@ static int __init apm_is_horked_d850md(struct dmi_system_id *d) } /* Some APM bioses hang on APM idle calls */ -static int __init apm_likes_to_melt(struct dmi_system_id *d) +static int __init apm_likes_to_melt(const struct dmi_system_id *d) { if (apm_info.forbid_idle == 0) { apm_info.forbid_idle = 1; @@ -1951,7 +1951,7 @@ static int __init apm_likes_to_melt(struct dmi_system_id *d) * Phoenix A04 08/24/2000 is known bad (Dell Inspiron 5000e) * Phoenix A07 09/29/2000 is known good (Dell Inspiron 5000) */ -static int __init broken_apm_power(struct dmi_system_id *d) +static int __init broken_apm_power(const struct dmi_system_id *d) { apm_info.get_power_status_broken = 1; printk(KERN_WARNING "BIOS strings suggest APM bugs, disabling power status reporting.\n"); @@ -1962,7 +1962,7 @@ static int __init broken_apm_power(struct dmi_system_id *d) * This bios swaps the APM minute reporting bytes over (Many sony laptops * have this problem). */ -static int __init swab_apm_power_in_minutes(struct dmi_system_id *d) +static int __init swab_apm_power_in_minutes(const struct dmi_system_id *d) { apm_info.get_power_status_swabinminutes = 1; printk(KERN_WARNING "BIOS strings suggest APM reports battery life in minutes and wrong byte order.\n"); diff --git a/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c index 705e13a3078..b6434a7ef8b 100644 --- a/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c +++ b/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c @@ -533,13 +533,13 @@ static int __init acpi_cpufreq_early_init(void) */ static int bios_with_sw_any_bug; -static int sw_any_bug_found(struct dmi_system_id *d) +static int sw_any_bug_found(const struct dmi_system_id *d) { bios_with_sw_any_bug = 1; return 0; } -static struct dmi_system_id sw_any_bug_dmi_table[] = { +static const struct dmi_system_id sw_any_bug_dmi_table[] = { { .callback = sw_any_bug_found, .ident = "Supermicro Server X6DLP", diff --git a/arch/i386/kernel/reboot.c b/arch/i386/kernel/reboot.c index 0d796248866..b37ed226830 100644 --- a/arch/i386/kernel/reboot.c +++ b/arch/i386/kernel/reboot.c @@ -79,7 +79,7 @@ __setup("reboot=", reboot_setup); /* * Some machines require the "reboot=b" commandline option, this quirk makes that automatic. */ -static int __init set_bios_reboot(struct dmi_system_id *d) +static int __init set_bios_reboot(const struct dmi_system_id *d) { if (!reboot_thru_bios) { reboot_thru_bios = 1; diff --git a/arch/i386/kernel/tsc.c b/arch/i386/kernel/tsc.c index a39280b4dd3..3ed0ae8c918 100644 --- a/arch/i386/kernel/tsc.c +++ b/arch/i386/kernel/tsc.c @@ -305,7 +305,7 @@ void mark_tsc_unstable(char *reason) } EXPORT_SYMBOL_GPL(mark_tsc_unstable); -static int __init dmi_mark_tsc_unstable(struct dmi_system_id *d) +static int __init dmi_mark_tsc_unstable(const struct dmi_system_id *d) { printk(KERN_NOTICE "%s detected: marking TSC unstable.\n", d->ident); diff --git a/arch/i386/mach-generic/bigsmp.c b/arch/i386/mach-generic/bigsmp.c index 58a477baec3..292a225edab 100644 --- a/arch/i386/mach-generic/bigsmp.c +++ b/arch/i386/mach-generic/bigsmp.c @@ -21,7 +21,7 @@ static int dmi_bigsmp; /* can be set by dmi scanners */ -static int hp_ht_bigsmp(struct dmi_system_id *d) +static int hp_ht_bigsmp(const struct dmi_system_id *d) { #ifdef CONFIG_X86_GENERICARCH printk(KERN_NOTICE "%s detected: force use of apic=bigsmp\n", d->ident); @@ -31,7 +31,7 @@ static int hp_ht_bigsmp(struct dmi_system_id *d) } -static struct dmi_system_id bigsmp_dmi_table[] = { +static const struct dmi_system_id bigsmp_dmi_table[] = { { hp_ht_bigsmp, "HP ProLiant DL760 G2", { DMI_MATCH(DMI_BIOS_VENDOR, "HP"), DMI_MATCH(DMI_BIOS_VERSION, "P44-"), diff --git a/arch/i386/pci/common.c b/arch/i386/pci/common.c index ebc6f3c6634..07d5223442b 100644 --- a/arch/i386/pci/common.c +++ b/arch/i386/pci/common.c @@ -123,7 +123,7 @@ void __devinit pcibios_fixup_bus(struct pci_bus *b) * on the kernel command line (which was parsed earlier). */ -static int __devinit set_bf_sort(struct dmi_system_id *d) +static int __devinit set_bf_sort(const struct dmi_system_id *d) { if (pci_bf_sort == pci_bf_sort_default) { pci_bf_sort = pci_dmi_bf; @@ -136,7 +136,7 @@ static int __devinit set_bf_sort(struct dmi_system_id *d) * Enable renumbering of PCI bus# ranges to reach all PCI busses (Cardbus) */ #ifdef __i386__ -static int __devinit assign_all_busses(struct dmi_system_id *d) +static int __devinit assign_all_busses(const struct dmi_system_id *d) { pci_probe |= PCI_ASSIGN_ALL_BUSSES; printk(KERN_INFO "%s detected: enabling PCI bus# renumbering" diff --git a/arch/i386/pci/irq.c b/arch/i386/pci/irq.c index 8434f2323b8..d98c6b096f8 100644 --- a/arch/i386/pci/irq.c +++ b/arch/i386/pci/irq.c @@ -1010,7 +1010,7 @@ static void __init pcibios_fixup_irqs(void) * Work around broken HP Pavilion Notebooks which assign USB to * IRQ 9 even though it is actually wired to IRQ 11 */ -static int __init fix_broken_hp_bios_irq9(struct dmi_system_id *d) +static int __init fix_broken_hp_bios_irq9(const struct dmi_system_id *d) { if (!broken_hp_bios_irq9) { broken_hp_bios_irq9 = 1; @@ -1023,7 +1023,7 @@ static int __init fix_broken_hp_bios_irq9(struct dmi_system_id *d) * Work around broken Acer TravelMate 360 Notebooks which assign * Cardbus to IRQ 11 even though it is actually wired to IRQ 10 */ -static int __init fix_acer_tm360_irqrouting(struct dmi_system_id *d) +static int __init fix_acer_tm360_irqrouting(const struct dmi_system_id *d) { if (!acer_tm360_irqrouting) { acer_tm360_irqrouting = 1; diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 12c09fafce9..352cf81af58 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -1214,7 +1214,7 @@ acpi_os_validate_address ( } #ifdef CONFIG_DMI -static int dmi_osi_linux(struct dmi_system_id *d) +static int dmi_osi_linux(const struct dmi_system_id *d) { printk(KERN_NOTICE "%s detected: enabling _OSI(Linux)\n", d->ident); enable_osi_linux(1); diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index f18261368e7..1e8287b4f40 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -92,7 +92,7 @@ module_param(bm_history, uint, 0644); * * To skip this limit, boot/load with a large max_cstate limit. */ -static int set_max_cstate(struct dmi_system_id *id) +static int set_max_cstate(const struct dmi_system_id *id) { if (max_cstate > ACPI_PROCESSOR_MAX_POWER) return 0; diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c index 2cbb9aabd00..5055acf2163 100644 --- a/drivers/acpi/sleep/main.c +++ b/drivers/acpi/sleep/main.c @@ -215,7 +215,7 @@ static struct pm_ops acpi_pm_ops = { * Toshiba fails to preserve interrupts over S1, reinitialization * of 8259 is needed after S1 resume. */ -static int __init init_ints_after_s1(struct dmi_system_id *d) +static int __init init_ints_after_s1(const struct dmi_system_id *d) { printk(KERN_WARNING "%s with broken S1 detected.\n", d->ident); init_8259A_after_S1 = 1; diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index bc6d5866ef9..ad898e10c1a 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -1360,7 +1360,7 @@ static int acpi_thermal_resume(struct acpi_device *device) } #ifdef CONFIG_DMI -static int thermal_act(struct dmi_system_id *d) { +static int thermal_act(const struct dmi_system_id *d) { if (act == 0) { printk(KERN_NOTICE "ACPI: %s detected: " @@ -1369,14 +1369,14 @@ static int thermal_act(struct dmi_system_id *d) { } return 0; } -static int thermal_nocrt(struct dmi_system_id *d) { +static int thermal_nocrt(const struct dmi_system_id *d) { printk(KERN_NOTICE "ACPI: %s detected: " "disabling all critical thermal trip point actions.\n", d->ident); nocrt = 1; return 0; } -static int thermal_tzp(struct dmi_system_id *d) { +static int thermal_tzp(const struct dmi_system_id *d) { if (tzp == 0) { printk(KERN_NOTICE "ACPI: %s detected: " @@ -1385,7 +1385,7 @@ static int thermal_tzp(struct dmi_system_id *d) { } return 0; } -static int thermal_psv(struct dmi_system_id *d) { +static int thermal_psv(const struct dmi_system_id *d) { if (psv == 0) { printk(KERN_NOTICE "ACPI: %s detected: " diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 6996eb5b750..92c2d5082be 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -919,7 +919,7 @@ static void ich_set_dmamode (struct ata_port *ap, struct ata_device *adev) #ifdef CONFIG_PM static int piix_broken_suspend(void) { - static struct dmi_system_id sysids[] = { + static const struct dmi_system_id sysids[] = { { .ident = "TECRA M3", .matches = { @@ -1183,7 +1183,7 @@ static void __devinit piix_init_sata_map(struct pci_dev *pdev, static void piix_iocfg_bit18_quirk(struct pci_dev *pdev) { - static struct dmi_system_id sysids[] = { + static const struct dmi_system_id sysids[] = { { /* Clevo M570U sets IOCFG bit 18 if the cdrom * isn't used to boot the system which diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c index 71bdc3b3189..32a10c99c06 100644 --- a/drivers/ata/pata_ali.c +++ b/drivers/ata/pata_ali.c @@ -40,7 +40,7 @@ * Cable special cases */ -static struct dmi_system_id cable_dmi_table[] = { +static const struct dmi_system_id cable_dmi_table[] = { { .ident = "HP Pavilion N5430", .matches = { diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c index c6066aa43ec..eaaea848b64 100644 --- a/drivers/ata/pata_cs5530.c +++ b/drivers/ata/pata_cs5530.c @@ -214,7 +214,7 @@ static struct ata_port_operations cs5530_port_ops = { .port_start = ata_port_start, }; -static struct dmi_system_id palmax_dmi_table[] = { +static const struct dmi_system_id palmax_dmi_table[] = { { .ident = "Palmax PD1100", .matches = { diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index 636c4f1a0b2..f143db4559e 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -129,7 +129,7 @@ static const struct via_isa_bridge { * Cable special cases */ -static struct dmi_system_id cable_dmi_table[] = { +static const struct dmi_system_id cable_dmi_table[] = { { .ident = "Acer Ferrari 3400", .matches = { diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c index 0289705967d..cd406416eff 100644 --- a/drivers/char/i8k.c +++ b/drivers/char/i8k.c @@ -98,9 +98,9 @@ struct smm_regs { unsigned int edi __attribute__ ((packed)); }; -static inline char *i8k_get_dmi_data(int field) +static inline const char *i8k_get_dmi_data(int field) { - char *dmi_data = dmi_get_system_info(field); + const char *dmi_data = dmi_get_system_info(field); return dmi_data && *dmi_data ? dmi_data : "?"; } diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index dd441ff4af5..7901d5f218e 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -1965,10 +1965,10 @@ struct dmi_ipmi_data u8 slave_addr; }; -static int __devinit decode_dmi(struct dmi_header *dm, +static int __devinit decode_dmi(const struct dmi_header *dm, struct dmi_ipmi_data *dmi) { - u8 *data = (u8 *)dm; + const u8 *data = (const u8 *)dm; unsigned long base_addr; u8 reg_spacing; u8 len = dm->length; @@ -2091,13 +2091,14 @@ static __devinit void try_init_dmi(struct dmi_ipmi_data *ipmi_data) static void __devinit dmi_find_bmc(void) { - struct dmi_device *dev = NULL; + const struct dmi_device *dev = NULL; struct dmi_ipmi_data data; int rv; while ((dev = dmi_find_device(DMI_DEV_TYPE_IPMI, NULL, dev))) { memset(&data, 0, sizeof(data)); - rv = decode_dmi((struct dmi_header *) dev->device_data, &data); + rv = decode_dmi((const struct dmi_header *) dev->device_data, + &data); if (!rv) try_init_dmi(&data); } diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index f7318b3b51f..0cdadea7a40 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -8,9 +8,9 @@ #include #include -static char * __init dmi_string(struct dmi_header *dm, u8 s) +static char * __init dmi_string(const struct dmi_header *dm, u8 s) { - u8 *bp = ((u8 *) dm) + dm->length; + const u8 *bp = ((u8 *) dm) + dm->length; char *str = ""; if (s) { @@ -37,7 +37,7 @@ static char * __init dmi_string(struct dmi_header *dm, u8 s) * pointing to completely the wrong place for example */ static int __init dmi_table(u32 base, int len, int num, - void (*decode)(struct dmi_header *)) + void (*decode)(const struct dmi_header *)) { u8 *buf, *data; int i = 0; @@ -53,7 +53,8 @@ static int __init dmi_table(u32 base, int len, int num, * OR we run off the end of the table (also happens) */ while ((i < num) && (data - buf + sizeof(struct dmi_header)) <= len) { - struct dmi_header *dm = (struct dmi_header *)data; + const struct dmi_header *dm = (const struct dmi_header *)data; + /* * We want to know the total length (formated area and strings) * before decoding to make sure we won't run off the table in @@ -71,7 +72,7 @@ static int __init dmi_table(u32 base, int len, int num, return 0; } -static int __init dmi_checksum(u8 *buf) +static int __init dmi_checksum(const u8 *buf) { u8 sum = 0; int a; @@ -89,9 +90,10 @@ int dmi_available; /* * Save a DMI string */ -static void __init dmi_save_ident(struct dmi_header *dm, int slot, int string) +static void __init dmi_save_ident(const struct dmi_header *dm, int slot, int string) { - char *p, *d = (char*) dm; + const char *d = (const char*) dm; + char *p; if (dmi_ident[slot]) return; @@ -103,9 +105,9 @@ static void __init dmi_save_ident(struct dmi_header *dm, int slot, int string) dmi_ident[slot] = p; } -static void __init dmi_save_uuid(struct dmi_header *dm, int slot, int index) +static void __init dmi_save_uuid(const struct dmi_header *dm, int slot, int index) { - u8 *d = (u8*) dm + index; + const u8 *d = (u8*) dm + index; char *s; int is_ff = 1, is_00 = 1, i; @@ -132,9 +134,9 @@ static void __init dmi_save_uuid(struct dmi_header *dm, int slot, int index) dmi_ident[slot] = s; } -static void __init dmi_save_type(struct dmi_header *dm, int slot, int index) +static void __init dmi_save_type(const struct dmi_header *dm, int slot, int index) { - u8 *d = (u8*) dm + index; + const u8 *d = (u8*) dm + index; char *s; if (dmi_ident[slot]) @@ -148,13 +150,13 @@ static void __init dmi_save_type(struct dmi_header *dm, int slot, int index) dmi_ident[slot] = s; } -static void __init dmi_save_devices(struct dmi_header *dm) +static void __init dmi_save_devices(const struct dmi_header *dm) { int i, count = (dm->length - sizeof(struct dmi_header)) / 2; struct dmi_device *dev; for (i = 0; i < count; i++) { - char *d = (char *)(dm + 1) + (i * 2); + const char *d = (char *)(dm + 1) + (i * 2); /* Skip disabled device */ if ((*d & 0x80) == 0) @@ -173,7 +175,7 @@ static void __init dmi_save_devices(struct dmi_header *dm) } } -static void __init dmi_save_oem_strings_devices(struct dmi_header *dm) +static void __init dmi_save_oem_strings_devices(const struct dmi_header *dm) { int i, count = *(u8 *)(dm + 1); struct dmi_device *dev; @@ -194,7 +196,7 @@ static void __init dmi_save_oem_strings_devices(struct dmi_header *dm) } } -static void __init dmi_save_ipmi_device(struct dmi_header *dm) +static void __init dmi_save_ipmi_device(const struct dmi_header *dm) { struct dmi_device *dev; void * data; @@ -225,7 +227,7 @@ static void __init dmi_save_ipmi_device(struct dmi_header *dm) * and machine entries. For 2.5 we should pull the smbus controller info * out of here. */ -static void __init dmi_decode(struct dmi_header *dm) +static void __init dmi_decode(const struct dmi_header *dm) { switch(dm->type) { case 0: /* BIOS Information */ @@ -265,9 +267,10 @@ static void __init dmi_decode(struct dmi_header *dm) } } -static int __init dmi_present(char __iomem *p) +static int __init dmi_present(const char __iomem *p) { u8 buf[15]; + memcpy_fromio(buf, p, 15); if ((memcmp(buf, "_DMI_", 5) == 0) && dmi_checksum(buf)) { u16 num = (buf[13] << 8) | buf[12]; @@ -348,10 +351,10 @@ void __init dmi_scan_machine(void) * returns non zero or we hit the end. Callback function is called for * each successful match. Returns the number of matches. */ -int dmi_check_system(struct dmi_system_id *list) +int dmi_check_system(const struct dmi_system_id *list) { int i, count = 0; - struct dmi_system_id *d = list; + const struct dmi_system_id *d = list; while (d->ident) { for (i = 0; i < ARRAY_SIZE(d->matches); i++) { @@ -380,7 +383,7 @@ EXPORT_SYMBOL(dmi_check_system); * Returns one DMI data value, can be used to perform * complex DMI data checks. */ -char *dmi_get_system_info(int field) +const char *dmi_get_system_info(int field) { return dmi_ident[field]; } @@ -391,7 +394,7 @@ EXPORT_SYMBOL(dmi_get_system_info); * dmi_name_in_vendors - Check if string is anywhere in the DMI vendor information. * @str: Case sensitive Name */ -int dmi_name_in_vendors(char *str) +int dmi_name_in_vendors(const char *str) { static int fields[] = { DMI_BIOS_VENDOR, DMI_BIOS_VERSION, DMI_SYS_VENDOR, DMI_PRODUCT_NAME, DMI_PRODUCT_VERSION, DMI_BOARD_VENDOR, @@ -418,13 +421,15 @@ EXPORT_SYMBOL(dmi_name_in_vendors); * A new search is initiated by passing %NULL as the @from argument. * If @from is not %NULL, searches continue from next device. */ -struct dmi_device * dmi_find_device(int type, const char *name, - struct dmi_device *from) +const struct dmi_device * dmi_find_device(int type, const char *name, + const struct dmi_device *from) { - struct list_head *d, *head = from ? &from->list : &dmi_devices; + const struct list_head *head = from ? &from->list : &dmi_devices; + struct list_head *d; for(d = head->next; d != &dmi_devices; d = d->next) { - struct dmi_device *dev = list_entry(d, struct dmi_device, list); + const struct dmi_device *dev = + list_entry(d, struct dmi_device, list); if (((type == DMI_DEV_TYPE_ANY) || (dev->type == type)) && ((name == NULL) || (strcmp(dev->name, name) == 0))) @@ -444,7 +449,7 @@ EXPORT_SYMBOL(dmi_find_device); int dmi_get_year(int field) { int year; - char *s = dmi_get_system_info(field); + const char *s = dmi_get_system_info(field); if (!s) return -1; diff --git a/drivers/hwmon/abituguru.c b/drivers/hwmon/abituguru.c index d575ee958de..2317f4bb9c9 100644 --- a/drivers/hwmon/abituguru.c +++ b/drivers/hwmon/abituguru.c @@ -1449,7 +1449,7 @@ static int __init abituguru_init(void) struct resource res = { .flags = IORESOURCE_IO }; #ifdef CONFIG_DMI - char *board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR); + const char *board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR); /* safety check, refuse to load on non Abit motherboards */ if (!force && (!board_vendor || diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c index 941729a131f..56213b7f818 100644 --- a/drivers/hwmon/applesmc.c +++ b/drivers/hwmon/applesmc.c @@ -1071,7 +1071,7 @@ static const struct attribute_group temperature_attributes_group = /* * applesmc_dmi_match - found a match. return one, short-circuiting the hunt. */ -static int applesmc_dmi_match(struct dmi_system_id *id) +static int applesmc_dmi_match(const struct dmi_system_id *id) { int i = 0; struct dmi_match_data* dmi_data = id->driver_data; diff --git a/drivers/hwmon/hdaps.c b/drivers/hwmon/hdaps.c index e0cf5e6fe5b..a7c6d407572 100644 --- a/drivers/hwmon/hdaps.c +++ b/drivers/hwmon/hdaps.c @@ -480,14 +480,14 @@ static struct attribute_group hdaps_attribute_group = { /* Module stuff */ /* hdaps_dmi_match - found a match. return one, short-circuiting the hunt. */ -static int __init hdaps_dmi_match(struct dmi_system_id *id) +static int __init hdaps_dmi_match(const struct dmi_system_id *id) { printk(KERN_INFO "hdaps: %s detected.\n", id->ident); return 1; } /* hdaps_dmi_match_invert - found an inverted match. */ -static int __init hdaps_dmi_match_invert(struct dmi_system_id *id) +static int __init hdaps_dmi_match_invert(const struct dmi_system_id *id) { hdaps_invert = 1; printk(KERN_INFO "hdaps: inverting axis readings.\n"); diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c index 11ecb618007..20ebe3b7049 100644 --- a/drivers/ide/pci/alim15x3.c +++ b/drivers/ide/pci/alim15x3.c @@ -588,7 +588,7 @@ out: * Cable special cases */ -static struct dmi_system_id cable_dmi_table[] = { +static const struct dmi_system_id cable_dmi_table[] = { { .ident = "HP Pavilion N5430", .matches = { diff --git a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c index a7be7795e6a..c10203a3215 100644 --- a/drivers/ide/pci/via82cxxx.c +++ b/drivers/ide/pci/via82cxxx.c @@ -419,7 +419,7 @@ static unsigned int __devinit init_chipset_via82cxxx(struct pci_dev *dev, const * Cable special cases */ -static struct dmi_system_id cable_dmi_table[] = { +static const struct dmi_system_id cable_dmi_table[] = { { .ident = "Acer Ferrari 3400", .matches = { diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c index 60121f10f8d..b438d998625 100644 --- a/drivers/input/misc/wistron_btns.c +++ b/drivers/input/misc/wistron_btns.c @@ -247,7 +247,7 @@ static int have_wifi; static int have_bluetooth; static int have_leds; -static int __init dmi_matched(struct dmi_system_id *dmi) +static int __init dmi_matched(const struct dmi_system_id *dmi) { const struct key_entry *key; diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c index 91109b49fde..608674d0be8 100644 --- a/drivers/input/mouse/lifebook.c +++ b/drivers/input/mouse/lifebook.c @@ -27,7 +27,7 @@ struct lifebook_data { static const char *desired_serio_phys; -static int lifebook_set_serio_phys(struct dmi_system_id *d) +static int lifebook_set_serio_phys(const struct dmi_system_id *d) { desired_serio_phys = d->driver_data; return 0; @@ -35,13 +35,13 @@ static int lifebook_set_serio_phys(struct dmi_system_id *d) static unsigned char lifebook_use_6byte_proto; -static int lifebook_set_6byte_proto(struct dmi_system_id *d) +static int lifebook_set_6byte_proto(const struct dmi_system_id *d) { lifebook_use_6byte_proto = 1; return 0; } -static struct dmi_system_id lifebook_dmi_table[] = { +static const struct dmi_system_id lifebook_dmi_table[] = { { .ident = "FLORA-ie 55mi", .matches = { diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 666ad3a53fd..d349c4a5e3e 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -602,7 +602,7 @@ static int synaptics_reconnect(struct psmouse *psmouse) #if defined(__i386__) #include -static struct dmi_system_id toshiba_dmi_table[] = { +static const struct dmi_system_id toshiba_dmi_table[] = { { .ident = "Toshiba Satellite", .matches = { diff --git a/drivers/misc/msi-laptop.c b/drivers/misc/msi-laptop.c index 349be934db7..83679c76292 100644 --- a/drivers/misc/msi-laptop.c +++ b/drivers/misc/msi-laptop.c @@ -283,7 +283,7 @@ static struct platform_device *msipf_device; /* Initialization */ -static int dmi_check_cb(struct dmi_system_id *id) +static int dmi_check_cb(const struct dmi_system_id *id) { printk("msi-laptop: Identified laptop model '%s'.\n", id->ident); return 0; diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c index d38ddce592c..e73a71f04bb 100644 --- a/drivers/misc/sony-laptop.c +++ b/drivers/misc/sony-laptop.c @@ -807,7 +807,7 @@ static struct sony_nc_event *sony_nc_events; /* Vaio C* --maybe also FE*, N* and AR* ?-- special init sequence * for Fn keys */ -static int sony_nc_C_enable(struct dmi_system_id *id) +static int sony_nc_C_enable(const struct dmi_system_id *id) { int result = 0; @@ -845,7 +845,7 @@ static struct sony_nc_event sony_C_events[] = { }; /* SNC-only model map */ -static struct dmi_system_id sony_nc_ids[] = { +static const struct dmi_system_id sony_nc_ids[] = { { .ident = "Sony Vaio FE Series", .callback = sony_nc_C_enable, diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 0222bbaf7b7..6c0b2f0a51a 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -4448,7 +4448,7 @@ static void ibm_exit(struct ibm_struct *ibm) static void __init get_thinkpad_model_data(struct thinkpad_id_data *tp) { - struct dmi_device *dev = NULL; + const struct dmi_device *dev = NULL; char ec_fw_string[18]; if (!tp) diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c index 0691f473e9d..4e9fd37cff3 100644 --- a/drivers/pnp/pnpbios/core.c +++ b/drivers/pnp/pnpbios/core.c @@ -500,7 +500,7 @@ static int __init pnpbios_probe_system(void) return 0; } -static int __init exploding_pnp_bios(struct dmi_system_id *d) +static int __init exploding_pnp_bios(const struct dmi_system_id *d) { printk(KERN_WARNING "%s detected. Disabling PnPBIOS\n", d->ident); return 0; diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 805e5fc5f5d..4db17f75f4f 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -237,7 +237,7 @@ static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci) static int remote_wakeup_is_broken(struct uhci_hcd *uhci) { int port; - char *sys_info; + const char *sys_info; static char bad_Asus_board[] = "A7V8X"; /* One of Asus's motherboards has a bug which causes it to diff --git a/drivers/video/imacfb.c b/drivers/video/imacfb.c index 18ea4a54910..6455fd2a39f 100644 --- a/drivers/video/imacfb.c +++ b/drivers/video/imacfb.c @@ -58,7 +58,7 @@ static int model = M_UNKNOWN; static int manual_height; static int manual_width; -static int set_system(struct dmi_system_id *id) +static int set_system(const struct dmi_system_id *id) { printk(KERN_INFO "imacfb: %s detected - set system to %ld\n", id->ident, (long)id->driver_data); diff --git a/include/linux/dmi.h b/include/linux/dmi.h index b8ac7b01c45..00fc7a9c35e 100644 --- a/include/linux/dmi.h +++ b/include/linux/dmi.h @@ -54,7 +54,7 @@ struct dmi_strmatch { }; struct dmi_system_id { - int (*callback)(struct dmi_system_id *); + int (*callback)(const struct dmi_system_id *); const char *ident; struct dmi_strmatch matches[4]; void *driver_data; @@ -71,22 +71,22 @@ struct dmi_device { #ifdef CONFIG_DMI -extern int dmi_check_system(struct dmi_system_id *list); -extern char * dmi_get_system_info(int field); -extern struct dmi_device * dmi_find_device(int type, const char *name, - struct dmi_device *from); +extern int dmi_check_system(const struct dmi_system_id *list); +extern const char * dmi_get_system_info(int field); +extern const struct dmi_device * dmi_find_device(int type, const char *name, + const struct dmi_device *from); extern void dmi_scan_machine(void); extern int dmi_get_year(int field); -extern int dmi_name_in_vendors(char *str); +extern int dmi_name_in_vendors(const char *str); #else -static inline int dmi_check_system(struct dmi_system_id *list) { return 0; } -static inline char * dmi_get_system_info(int field) { return NULL; } -static inline struct dmi_device * dmi_find_device(int type, const char *name, - struct dmi_device *from) { return NULL; } +static inline int dmi_check_system(const struct dmi_system_id *list) { return 0; } +static inline const char * dmi_get_system_info(int field) { return NULL; } +static inline const struct dmi_device * dmi_find_device(int type, const char *name, + const struct dmi_device *from) { return NULL; } static inline int dmi_get_year(int year) { return 0; } -static inline int dmi_name_in_vendors(char *s) { return 0; } +static inline int dmi_name_in_vendors(const char *s) { return 0; } #endif -- cgit v1.2.3-70-g09d2 From 9b5d0f1e6dd6b4a67d0851a1c5a4bcf9b0c2f258 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 18 Jul 2007 17:59:15 -0300 Subject: V4L/DVB (5862): V4L: Add internal ioctl-like interface. This patch adds an internal ioctl-like interface which can be used in situations where a single Video4Linux device is implemented by multiple device drivers. One master device controls one or more slave devices. The slaves provide Video4Linux ioctl-like interface for the use of the master. Only a handful of ioctls are implemented at the moment. More can (and should) be added as more functionality is required. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Makefile | 3 +- drivers/media/video/v4l2-int-device.c | 154 +++++++++++++++++++++++++ include/media/v4l2-int-device.h | 210 ++++++++++++++++++++++++++++++++++ 3 files changed, 366 insertions(+), 1 deletion(-) create mode 100644 drivers/media/video/v4l2-int-device.c create mode 100644 include/media/v4l2-int-device.h (limited to 'drivers') diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 10b4d446901..d35306daac2 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -11,7 +11,8 @@ tuner-$(CONFIG_TUNER_TEA5761) += tea5761.o msp3400-objs := msp3400-driver.o msp3400-kthreads.o -obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o compat_ioctl32.o +obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o compat_ioctl32.o \ + v4l2-int-device.o ifeq ($(CONFIG_VIDEO_V4L1_COMPAT),y) obj-$(CONFIG_VIDEO_DEV) += v4l1-compat.o diff --git a/drivers/media/video/v4l2-int-device.c b/drivers/media/video/v4l2-int-device.c new file mode 100644 index 00000000000..7885d9b38c9 --- /dev/null +++ b/drivers/media/video/v4l2-int-device.c @@ -0,0 +1,154 @@ +/* + * drivers/media/video/v4l2-int-device.c + * + * V4L2 internal ioctl interface. + * + * Copyright (C) 2007 Nokia Corporation. + * + * Contact: Sakari Ailus + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include +#include +#include +#include + +#include + +static DEFINE_MUTEX(mutex); +static LIST_HEAD(int_list); + +static void v4l2_int_device_try_attach_all(void) +{ + struct list_head *head_master; + + list_for_each(head_master, &int_list) { + struct list_head *head_slave; + struct v4l2_int_device *m = + list_entry(head_master, struct v4l2_int_device, head); + + if (m->type != v4l2_int_type_master) + continue; + + list_for_each(head_slave, &int_list) { + struct v4l2_int_device *s = + list_entry(head_slave, + struct v4l2_int_device, head); + + if (s->type != v4l2_int_type_slave) + continue; + + /* Slave is connected? */ + if (s->u.slave->master) + continue; + + /* Slave wants to attach to master? */ + if (s->u.slave->attach_to[0] != 0 + && strncmp(m->name, s->u.slave->attach_to, + V4L2NAMESIZE)) + continue; + + if (!try_module_get(m->module)) + continue; + + if (m->u.master->attach(m, s)) { + module_put(m->module); + continue; + } + + s->u.slave->master = m; + } + } +} + +static int ioctl_sort_cmp(const void *a, const void *b) +{ + const struct v4l2_int_ioctl_desc *d1 = a, *d2 = b; + + if (d1->num > d2->num) + return 1; + + if (d1->num < d2->num) + return -1; + + return 0; +} + +int v4l2_int_device_register(struct v4l2_int_device *d) +{ + if (d->type == v4l2_int_type_slave) + sort(d->u.slave->ioctls, d->u.slave->num_ioctls, + sizeof(struct v4l2_int_ioctl_desc), + &ioctl_sort_cmp, NULL); + mutex_lock(&mutex); + list_add(&d->head, &int_list); + v4l2_int_device_try_attach_all(); + mutex_unlock(&mutex); + + return 0; +} + +void v4l2_int_device_unregister(struct v4l2_int_device *d) +{ + mutex_lock(&mutex); + list_del(&d->head); + if (d->type == v4l2_int_type_slave + && d->u.slave->master != NULL) { + d->u.slave->master->u.master->detach(d); + module_put(d->u.slave->master->module); + d->u.slave->master = NULL; + } + mutex_unlock(&mutex); +} + +static int no_such_ioctl(struct v4l2_int_device *d) +{ + return -EINVAL; +} + +/* Adapted from search_extable in extable.c. */ +static v4l2_int_ioctl_func *find_ioctl(struct v4l2_int_slave *slave, int cmd) +{ + const struct v4l2_int_ioctl_desc *first = slave->ioctls; + const struct v4l2_int_ioctl_desc *last = + first + slave->num_ioctls - 1; + + while (first <= last) { + const struct v4l2_int_ioctl_desc *mid; + + mid = (last - first) / 2 + first; + + if (mid->num < cmd) + first = mid + 1; + else if (mid->num > cmd) + last = mid - 1; + else + return mid->func; + } + + return &no_such_ioctl; +} + +int v4l2_int_ioctl_0(struct v4l2_int_device *d, int cmd) +{ + return ((v4l2_int_ioctl_func_0 *)find_ioctl(d->u.slave, cmd))(d); +} + +int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg) +{ + return ((v4l2_int_ioctl_func_1 *)find_ioctl(d->u.slave, cmd))(d, arg); +} diff --git a/include/media/v4l2-int-device.h b/include/media/v4l2-int-device.h new file mode 100644 index 00000000000..2b6fc1122f6 --- /dev/null +++ b/include/media/v4l2-int-device.h @@ -0,0 +1,210 @@ +/* + * include/media/v4l2-int-device.h + * + * V4L2 internal ioctl interface. + * + * Copyright (C) 2007 Nokia Corporation. + * + * Contact: Sakari Ailus + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifndef V4L2_INT_DEVICE_H +#define V4L2_INT_DEVICE_H + +#include +#include + +#define V4L2NAMESIZE 32 + +enum v4l2_int_type { + v4l2_int_type_master = 1, + v4l2_int_type_slave +}; + +enum v4l2_int_ioctl_num { + /* + * + * "Proper" V4L ioctls, as in struct video_device. + * + */ + vidioc_int_enum_fmt_cap_num = 1, + vidioc_int_g_fmt_cap_num, + vidioc_int_s_fmt_cap_num, + vidioc_int_try_fmt_cap_num, + vidioc_int_queryctrl_num, + vidioc_int_g_ctrl_num, + vidioc_int_s_ctrl_num, + vidioc_int_g_parm_num, + vidioc_int_s_parm_num, + + /* + * + * Strictly internal ioctls. + * + */ + /* Initialise the device when slave attaches to the master. */ + vidioc_int_dev_init_num = 1000, + /* Delinitialise the device at slave detach. */ + vidioc_int_dev_exit_num, + /* Set device power state: 0 is off, non-zero is on. */ + vidioc_int_s_power_num, + /* Get parallel interface clock speed for current settings. */ + vidioc_int_g_ext_clk_num, + /* + * Tell what the parallel interface clock speed actually is. + */ + vidioc_int_s_ext_clk_num, + /* Does the slave need to be reset after VIDIOC_DQBUF? */ + vidioc_int_g_needs_reset_num, + + /* + * + * VIDIOC_INT_* ioctls. + * + */ + /* VIDIOC_INT_RESET */ + vidioc_int_reset_num, + /* VIDIOC_INT_INIT */ + vidioc_int_init_num, + /* VIDIOC_INT_G_CHIP_IDENT */ + vidioc_int_g_chip_ident_num, + + /* + * + * Start of private ioctls. + * + */ + vidioc_int_priv_start_num = 2000, +}; + +struct v4l2_int_device; + +struct v4l2_int_master { + int (*attach)(struct v4l2_int_device *master, + struct v4l2_int_device *slave); + void (*detach)(struct v4l2_int_device *master); +}; + +typedef int (v4l2_int_ioctl_func)(struct v4l2_int_device *); +typedef int (v4l2_int_ioctl_func_0)(struct v4l2_int_device *); +typedef int (v4l2_int_ioctl_func_1)(struct v4l2_int_device *, void *); + +struct v4l2_int_ioctl_desc { + int num; + v4l2_int_ioctl_func *func; +}; + +struct v4l2_int_slave { + /* Don't touch master. */ + struct v4l2_int_device *master; + + char attach_to[V4L2NAMESIZE]; + + int num_ioctls; + struct v4l2_int_ioctl_desc *ioctls; +}; + +struct v4l2_int_device { + /* Don't touch head. */ + struct list_head head; + + struct module *module; + + char name[V4L2NAMESIZE]; + + enum v4l2_int_type type; + union { + struct v4l2_int_master *master; + struct v4l2_int_slave *slave; + } u; + + void *priv; +}; + +int v4l2_int_device_register(struct v4l2_int_device *d); +void v4l2_int_device_unregister(struct v4l2_int_device *d); + +int v4l2_int_ioctl_0(struct v4l2_int_device *d, int cmd); +int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg); + +/* + * + * IOCTL wrapper functions for better type checking. + * + */ + +#define V4L2_INT_WRAPPER_0(name) \ + static inline int vidioc_int_##name(struct v4l2_int_device *d) \ + { \ + return v4l2_int_ioctl_0(d, vidioc_int_##name##_num); \ + } \ + \ + static inline struct v4l2_int_ioctl_desc \ + vidioc_int_##name##_cb(int (*func) \ + (struct v4l2_int_device *)) \ + { \ + struct v4l2_int_ioctl_desc desc; \ + \ + desc.num = vidioc_int_##name##_num; \ + desc.func = (v4l2_int_ioctl_func *)func; \ + \ + return desc; \ + } + +#define V4L2_INT_WRAPPER_1(name, arg_type, asterisk) \ + static inline int vidioc_int_##name(struct v4l2_int_device *d, \ + arg_type asterisk arg) \ + { \ + return v4l2_int_ioctl_1(d, vidioc_int_##name##_num, \ + (void *)arg); \ + } \ + \ + static inline struct v4l2_int_ioctl_desc \ + vidioc_int_##name##_cb(int (*func) \ + (struct v4l2_int_device *, \ + arg_type asterisk)) \ + { \ + struct v4l2_int_ioctl_desc desc; \ + \ + desc.num = vidioc_int_##name##_num; \ + desc.func = (v4l2_int_ioctl_func *)func; \ + \ + return desc; \ + } + +V4L2_INT_WRAPPER_1(enum_fmt_cap, struct v4l2_fmtdesc, *); +V4L2_INT_WRAPPER_1(g_fmt_cap, struct v4l2_format, *); +V4L2_INT_WRAPPER_1(s_fmt_cap, struct v4l2_format, *); +V4L2_INT_WRAPPER_1(try_fmt_cap, struct v4l2_format, *); +V4L2_INT_WRAPPER_1(queryctrl, struct v4l2_queryctrl, *); +V4L2_INT_WRAPPER_1(g_ctrl, struct v4l2_control, *); +V4L2_INT_WRAPPER_1(s_ctrl, struct v4l2_control, *); +V4L2_INT_WRAPPER_1(g_parm, struct v4l2_streamparm, *); +V4L2_INT_WRAPPER_1(s_parm, struct v4l2_streamparm, *); + +V4L2_INT_WRAPPER_0(dev_init); +V4L2_INT_WRAPPER_0(dev_exit); +V4L2_INT_WRAPPER_1(s_power, int, ); +V4L2_INT_WRAPPER_1(s_ext_clk, u32, ); +V4L2_INT_WRAPPER_1(g_ext_clk, u32, *); +V4L2_INT_WRAPPER_1(g_needs_reset, void, *); + +V4L2_INT_WRAPPER_0(reset); +V4L2_INT_WRAPPER_0(init); +V4L2_INT_WRAPPER_1(g_chip_ident, int, *); + +#endif -- cgit v1.2.3-70-g09d2 From a5e90862114124d79e1a3f34641b00fec51d1806 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 18 Jul 2007 18:04:17 -0300 Subject: V4L/DVB (5863): TCM825x: Add driver. Add a driver for Toshiba TCM825x VGA camera sensor. This sensor is used e.g. in Nokia N800 internet tablet. This driver uses the new V4L2 internal ioctl interface. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 7 + drivers/media/video/Makefile | 2 + drivers/media/video/tcm825x.c | 942 ++++++++++++++++++++++++++++++++++++++++++ drivers/media/video/tcm825x.h | 195 +++++++++ 4 files changed, 1146 insertions(+) create mode 100644 drivers/media/video/tcm825x.c create mode 100644 drivers/media/video/tcm825x.h (limited to 'drivers') diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index e204e7b4028..675c8574403 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -197,6 +197,13 @@ config VIDEO_OV7670 OV7670 VGA camera. It currently only works with the M88ALP01 controller. +config VIDEO_TCM825X + tristate "TCM825x camera sensor support" + depends on I2C && VIDEO_V4L2 + ---help--- + This is a driver for the Toshiba TCM825x VGA camera sensor. + It is used for example in Nokia N800. + config VIDEO_SAA7110 tristate "Philips SAA7110 video decoder" depends on VIDEO_V4L1 && I2C diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index d35306daac2..8f7205b558f 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -98,6 +98,8 @@ obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o obj-$(CONFIG_VIDEO_OV7670) += ov7670.o +obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o + obj-$(CONFIG_USB_DABUSB) += dabusb.o obj-$(CONFIG_USB_OV511) += ov511.o obj-$(CONFIG_USB_SE401) += se401.o diff --git a/drivers/media/video/tcm825x.c b/drivers/media/video/tcm825x.c new file mode 100644 index 00000000000..4b973b099e5 --- /dev/null +++ b/drivers/media/video/tcm825x.c @@ -0,0 +1,942 @@ +/* + * drivers/media/video/tcm825x.c + * + * TCM825X camera sensor driver. + * + * Copyright (C) 2007 Nokia Corporation. + * + * Contact: Sakari Ailus + * + * Based on code from David Cohen + * + * This driver was based on ov9640 sensor driver from MontaVista + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include +#include + +#include "tcm825x.h" + +/* + * The sensor has two fps modes: the lower one just gives half the fps + * at the same xclk than the high one. + */ +#define MAX_FPS 30 +#define MIN_FPS 8 +#define MAX_HALF_FPS (MAX_FPS / 2) +#define HIGH_FPS_MODE_LOWER_LIMIT 14 +#define DEFAULT_FPS MAX_HALF_FPS + +struct tcm825x_sensor { + const struct tcm825x_platform_data *platform_data; + struct v4l2_int_device *v4l2_int_device; + struct i2c_client *i2c_client; + struct v4l2_pix_format pix; + struct v4l2_fract timeperframe; +}; + +/* list of image formats supported by TCM825X sensor */ +const static struct v4l2_fmtdesc tcm825x_formats[] = { + { + .description = "YUYV (YUV 4:2:2), packed", + .pixelformat = V4L2_PIX_FMT_UYVY, + }, { + /* Note: V4L2 defines RGB565 as: + * + * Byte 0 Byte 1 + * g2 g1 g0 r4 r3 r2 r1 r0 b4 b3 b2 b1 b0 g5 g4 g3 + * + * We interpret RGB565 as: + * + * Byte 0 Byte 1 + * g2 g1 g0 b4 b3 b2 b1 b0 r4 r3 r2 r1 r0 g5 g4 g3 + */ + .description = "RGB565, le", + .pixelformat = V4L2_PIX_FMT_RGB565, + }, +}; + +#define TCM825X_NUM_CAPTURE_FORMATS ARRAY_SIZE(tcm825x_formats) + +/* + * TCM825X register configuration for all combinations of pixel format and + * image size + */ +const static struct tcm825x_reg subqcif = { 0x20, TCM825X_PICSIZ }; +const static struct tcm825x_reg qcif = { 0x18, TCM825X_PICSIZ }; +const static struct tcm825x_reg cif = { 0x14, TCM825X_PICSIZ }; +const static struct tcm825x_reg qqvga = { 0x0c, TCM825X_PICSIZ }; +const static struct tcm825x_reg qvga = { 0x04, TCM825X_PICSIZ }; +const static struct tcm825x_reg vga = { 0x00, TCM825X_PICSIZ }; + +const static struct tcm825x_reg yuv422 = { 0x00, TCM825X_PICFMT }; +const static struct tcm825x_reg rgb565 = { 0x02, TCM825X_PICFMT }; + +/* Our own specific controls */ +#define V4L2_CID_ALC V4L2_CID_PRIVATE_BASE +#define V4L2_CID_H_EDGE_EN V4L2_CID_PRIVATE_BASE + 1 +#define V4L2_CID_V_EDGE_EN V4L2_CID_PRIVATE_BASE + 2 +#define V4L2_CID_LENS V4L2_CID_PRIVATE_BASE + 3 +#define V4L2_CID_MAX_EXPOSURE_TIME V4L2_CID_PRIVATE_BASE + 4 +#define V4L2_CID_LAST_PRIV V4L2_CID_MAX_EXPOSURE_TIME + +/* Video controls */ +static struct vcontrol { + struct v4l2_queryctrl qc; + u16 reg; + u16 start_bit; +} video_control[] = { + { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain", + .minimum = 0, + .maximum = 63, + .step = 1, + }, + .reg = TCM825X_AG, + .start_bit = 0, + }, + { + { + .id = V4L2_CID_RED_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Red Balance", + .minimum = 0, + .maximum = 255, + .step = 1, + }, + .reg = TCM825X_MRG, + .start_bit = 0, + }, + { + { + .id = V4L2_CID_BLUE_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Blue Balance", + .minimum = 0, + .maximum = 255, + .step = 1, + }, + .reg = TCM825X_MBG, + .start_bit = 0, + }, + { + { + .id = V4L2_CID_AUTO_WHITE_BALANCE, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Auto White Balance", + .minimum = 0, + .maximum = 1, + .step = 0, + }, + .reg = TCM825X_AWBSW, + .start_bit = 7, + }, + { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure Time", + .minimum = 0, + .maximum = 0x1fff, + .step = 1, + }, + .reg = TCM825X_ESRSPD_U, + .start_bit = 0, + }, + { + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Mirror Image", + .minimum = 0, + .maximum = 1, + .step = 0, + }, + .reg = TCM825X_H_INV, + .start_bit = 6, + }, + { + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Vertical Flip", + .minimum = 0, + .maximum = 1, + .step = 0, + }, + .reg = TCM825X_V_INV, + .start_bit = 7, + }, + /* Private controls */ + { + { + .id = V4L2_CID_ALC, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Auto Luminance Control", + .minimum = 0, + .maximum = 1, + .step = 0, + }, + .reg = TCM825X_ALCSW, + .start_bit = 7, + }, + { + { + .id = V4L2_CID_H_EDGE_EN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Horizontal Edge Enhancement", + .minimum = 0, + .maximum = 0xff, + .step = 1, + }, + .reg = TCM825X_HDTG, + .start_bit = 0, + }, + { + { + .id = V4L2_CID_V_EDGE_EN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Vertical Edge Enhancement", + .minimum = 0, + .maximum = 0xff, + .step = 1, + }, + .reg = TCM825X_VDTG, + .start_bit = 0, + }, + { + { + .id = V4L2_CID_LENS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Lens Shading Compensation", + .minimum = 0, + .maximum = 0x3f, + .step = 1, + }, + .reg = TCM825X_LENS, + .start_bit = 0, + }, + { + { + .id = V4L2_CID_MAX_EXPOSURE_TIME, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Maximum Exposure Time", + .minimum = 0, + .maximum = 0x3, + .step = 1, + }, + .reg = TCM825X_ESRLIM, + .start_bit = 5, + }, +}; + + +const static struct tcm825x_reg *tcm825x_siz_reg[NUM_IMAGE_SIZES] = +{ &subqcif, &qqvga, &qcif, &qvga, &cif, &vga }; + +const static struct tcm825x_reg *tcm825x_fmt_reg[NUM_PIXEL_FORMATS] = +{ &yuv422, &rgb565 }; + +/* + * Read a value from a register in an TCM825X sensor device. The value is + * returned in 'val'. + * Returns zero if successful, or non-zero otherwise. + */ +static int tcm825x_read_reg(struct i2c_client *client, int reg) +{ + int err; + struct i2c_msg msg[2]; + u8 reg_buf, data_buf = 0; + + if (!client->adapter) + return -ENODEV; + + msg[0].addr = client->addr; + msg[0].flags = 0; + msg[0].len = 1; + msg[0].buf = ®_buf; + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = 1; + msg[1].buf = &data_buf; + + reg_buf = reg; + + err = i2c_transfer(client->adapter, msg, 2); + if (err < 0) + return err; + return data_buf; +} + +/* + * Write a value to a register in an TCM825X sensor device. + * Returns zero if successful, or non-zero otherwise. + */ +static int tcm825x_write_reg(struct i2c_client *client, u8 reg, u8 val) +{ + int err; + struct i2c_msg msg[1]; + unsigned char data[2]; + + if (!client->adapter) + return -ENODEV; + + msg->addr = client->addr; + msg->flags = 0; + msg->len = 2; + msg->buf = data; + data[0] = reg; + data[1] = val; + err = i2c_transfer(client->adapter, msg, 1); + if (err >= 0) + return 0; + return err; +} + +static int __tcm825x_write_reg_mask(struct i2c_client *client, + u8 reg, u8 val, u8 mask) +{ + int rc; + + /* need to do read - modify - write */ + rc = tcm825x_read_reg(client, reg); + if (rc < 0) + return rc; + + rc &= (~mask); /* Clear the masked bits */ + val &= mask; /* Enforce mask on value */ + val |= rc; + + /* write the new value to the register */ + rc = tcm825x_write_reg(client, reg, val); + if (rc) + return rc; + + return 0; +} + +#define tcm825x_write_reg_mask(client, regmask, val) \ + __tcm825x_write_reg_mask(client, TCM825X_ADDR((regmask)), val, \ + TCM825X_MASK((regmask))) + + +/* + * Initialize a list of TCM825X registers. + * The list of registers is terminated by the pair of values + * { TCM825X_REG_TERM, TCM825X_VAL_TERM }. + * Returns zero if successful, or non-zero otherwise. + */ +static int tcm825x_write_default_regs(struct i2c_client *client, + const struct tcm825x_reg *reglist) +{ + int err; + const struct tcm825x_reg *next = reglist; + + while (!((next->reg == TCM825X_REG_TERM) + && (next->val == TCM825X_VAL_TERM))) { + err = tcm825x_write_reg(client, next->reg, next->val); + if (err) { + dev_err(&client->dev, "register writing failed\n"); + return err; + } + next++; + } + + return 0; +} + +static struct vcontrol *find_vctrl(int id) +{ + int i; + + if (id < V4L2_CID_BASE) + return NULL; + + for (i = 0; i < ARRAY_SIZE(video_control); i++) + if (video_control[i].qc.id == id) + return &video_control[i]; + + return NULL; +} + +/* + * Find the best match for a requested image capture size. The best match + * is chosen as the nearest match that has the same number or fewer pixels + * as the requested size, or the smallest image size if the requested size + * has fewer pixels than the smallest image. + */ +static enum image_size tcm825x_find_size(struct v4l2_int_device *s, + unsigned int width, + unsigned int height) +{ + enum image_size isize; + unsigned long pixels = width * height; + struct tcm825x_sensor *sensor = s->priv; + + for (isize = subQCIF; isize < VGA; isize++) { + if (tcm825x_sizes[isize + 1].height + * tcm825x_sizes[isize + 1].width > pixels) { + dev_dbg(&sensor->i2c_client->dev, "size %d\n", isize); + + return isize; + } + } + + dev_dbg(&sensor->i2c_client->dev, "format default VGA\n"); + + return VGA; +} + +/* + * Configure the TCM825X for current image size, pixel format, and + * frame period. fper is the frame period (in seconds) expressed as a + * fraction. Returns zero if successful, or non-zero otherwise. The + * actual frame period is returned in fper. + */ +static int tcm825x_configure(struct v4l2_int_device *s) +{ + struct tcm825x_sensor *sensor = s->priv; + struct v4l2_pix_format *pix = &sensor->pix; + enum image_size isize = tcm825x_find_size(s, pix->width, pix->height); + struct v4l2_fract *fper = &sensor->timeperframe; + enum pixel_format pfmt; + int err; + u32 tgt_fps; + u8 val; + + /* common register initialization */ + err = tcm825x_write_default_regs( + sensor->i2c_client, sensor->platform_data->default_regs()); + if (err) + return err; + + /* configure image size */ + val = tcm825x_siz_reg[isize]->val; + dev_dbg(&sensor->i2c_client->dev, + "configuring image size %d\n", isize); + err = tcm825x_write_reg_mask(sensor->i2c_client, + tcm825x_siz_reg[isize]->reg, val); + if (err) + return err; + + /* configure pixel format */ + switch (pix->pixelformat) { + default: + case V4L2_PIX_FMT_RGB565: + pfmt = RGB565; + break; + case V4L2_PIX_FMT_UYVY: + pfmt = YUV422; + break; + } + + dev_dbg(&sensor->i2c_client->dev, + "configuring pixel format %d\n", pfmt); + val = tcm825x_fmt_reg[pfmt]->val; + + err = tcm825x_write_reg_mask(sensor->i2c_client, + tcm825x_fmt_reg[pfmt]->reg, val); + if (err) + return err; + + /* + * For frame rate < 15, the FPS reg (addr 0x02, bit 7) must be + * set. Frame rate will be halved from the normal. + */ + tgt_fps = fper->denominator / fper->numerator; + if (tgt_fps <= HIGH_FPS_MODE_LOWER_LIMIT) { + val = tcm825x_read_reg(sensor->i2c_client, 0x02); + val |= 0x80; + tcm825x_write_reg(sensor->i2c_client, 0x02, val); + } + + return 0; +} + +/* + * Given the image capture format in pix, the nominal frame period in + * timeperframe, calculate the required xclk frequency. + * + * TCM825X input frequency characteristics are: + * Minimum 11.9 MHz, Typical 24.57 MHz and maximum 25/27 MHz + */ +#define XCLK_MIN 11900000 +#define XCLK_MAX 25000000 + +static int ioctl_g_ext_clk(struct v4l2_int_device *s, u32 *xclk) +{ + struct tcm825x_sensor *sensor = s->priv; + struct v4l2_fract *timeperframe = &sensor->timeperframe; + u32 tgt_xclk; /* target xclk */ + u32 tgt_fps; /* target frames per secound */ + + tgt_fps = timeperframe->denominator / timeperframe->numerator; + + tgt_xclk = (tgt_fps <= HIGH_FPS_MODE_LOWER_LIMIT) ? + (2457 * tgt_fps) / MAX_HALF_FPS : + (2457 * tgt_fps) / MAX_FPS; + tgt_xclk *= 10000; + + tgt_xclk = min(tgt_xclk, (u32)XCLK_MAX); + tgt_xclk = max(tgt_xclk, (u32)XCLK_MIN); + + *xclk = tgt_xclk; + + return 0; +} + +static int ioctl_s_ext_clk(struct v4l2_int_device *s, u32 xclk) +{ + if (xclk > XCLK_MAX || xclk < XCLK_MIN) + return -EINVAL; + + return 0; +} + +static int ioctl_queryctrl(struct v4l2_int_device *s, + struct v4l2_queryctrl *qc) +{ + struct vcontrol *control; + + control = find_vctrl(qc->id); + + if (control == NULL) + return -EINVAL; + + *qc = control->qc; + + return 0; +} + +static int ioctl_g_ctrl(struct v4l2_int_device *s, + struct v4l2_control *vc) +{ + struct tcm825x_sensor *sensor = s->priv; + struct i2c_client *client = sensor->i2c_client; + int val, r; + struct vcontrol *lvc; + + /* exposure time is special, spread accross 2 registers */ + if (vc->id == V4L2_CID_EXPOSURE) { + int val_lower, val_upper; + + val_upper = tcm825x_read_reg(client, + TCM825X_ADDR(TCM825X_ESRSPD_U)); + if (val_upper < 0) + return val_upper; + val_lower = tcm825x_read_reg(client, + TCM825X_ADDR(TCM825X_ESRSPD_L)); + if (val_lower < 0) + return val_lower; + + vc->value = ((val_upper & 0x1f) << 8) | (val_lower); + return 0; + } + + lvc = find_vctrl(vc->id); + if (lvc == NULL) + return -EINVAL; + + r = tcm825x_read_reg(client, TCM825X_ADDR(lvc->reg)); + if (r < 0) + return r; + val = r & TCM825X_MASK(lvc->reg); + val >>= lvc->start_bit; + + if (val < 0) + return val; + + vc->value = val; + return 0; +} + +static int ioctl_s_ctrl(struct v4l2_int_device *s, + struct v4l2_control *vc) +{ + struct tcm825x_sensor *sensor = s->priv; + struct i2c_client *client = sensor->i2c_client; + struct vcontrol *lvc; + int val = vc->value; + + /* exposure time is special, spread accross 2 registers */ + if (vc->id == V4L2_CID_EXPOSURE) { + int val_lower, val_upper; + val_lower = val & TCM825X_MASK(TCM825X_ESRSPD_L); + val_upper = (val >> 8) & TCM825X_MASK(TCM825X_ESRSPD_U); + + if (tcm825x_write_reg_mask(client, + TCM825X_ESRSPD_U, val_upper)) + return -EIO; + + if (tcm825x_write_reg_mask(client, + TCM825X_ESRSPD_L, val_lower)) + return -EIO; + + return 0; + } + + lvc = find_vctrl(vc->id); + if (lvc == NULL) + return -EINVAL; + + val = val << lvc->start_bit; + if (tcm825x_write_reg_mask(client, lvc->reg, val)) + return -EIO; + + return 0; +} + +static int ioctl_enum_fmt_cap(struct v4l2_int_device *s, + struct v4l2_fmtdesc *fmt) +{ + int index = fmt->index; + + switch (fmt->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + if (index >= TCM825X_NUM_CAPTURE_FORMATS) + return -EINVAL; + break; + + default: + return -EINVAL; + } + + fmt->flags = tcm825x_formats[index].flags; + strlcpy(fmt->description, tcm825x_formats[index].description, + sizeof(fmt->description)); + fmt->pixelformat = tcm825x_formats[index].pixelformat; + + return 0; +} + +static int ioctl_try_fmt_cap(struct v4l2_int_device *s, + struct v4l2_format *f) +{ + struct tcm825x_sensor *sensor = s->priv; + enum image_size isize; + int ifmt; + struct v4l2_pix_format *pix = &f->fmt.pix; + + isize = tcm825x_find_size(s, pix->width, pix->height); + dev_dbg(&sensor->i2c_client->dev, "isize = %d num_capture = %d\n", + isize, TCM825X_NUM_CAPTURE_FORMATS); + + pix->width = tcm825x_sizes[isize].width; + pix->height = tcm825x_sizes[isize].height; + + for (ifmt = 0; ifmt < TCM825X_NUM_CAPTURE_FORMATS; ifmt++) + if (pix->pixelformat == tcm825x_formats[ifmt].pixelformat) + break; + + if (ifmt == TCM825X_NUM_CAPTURE_FORMATS) + ifmt = 0; /* Default = YUV 4:2:2 */ + + pix->pixelformat = tcm825x_formats[ifmt].pixelformat; + pix->field = V4L2_FIELD_NONE; + pix->bytesperline = pix->width * TCM825X_BYTES_PER_PIXEL; + pix->sizeimage = pix->bytesperline * pix->height; + pix->priv = 0; + dev_dbg(&sensor->i2c_client->dev, "format = 0x%08x\n", + pix->pixelformat); + + switch (pix->pixelformat) { + case V4L2_PIX_FMT_UYVY: + default: + pix->colorspace = V4L2_COLORSPACE_JPEG; + break; + case V4L2_PIX_FMT_RGB565: + pix->colorspace = V4L2_COLORSPACE_SRGB; + break; + } + + return 0; +} + +static int ioctl_s_fmt_cap(struct v4l2_int_device *s, + struct v4l2_format *f) +{ + struct tcm825x_sensor *sensor = s->priv; + struct v4l2_pix_format *pix = &f->fmt.pix; + int rval; + + rval = ioctl_try_fmt_cap(s, f); + if (rval) + return rval; + + rval = tcm825x_configure(s); + + sensor->pix = *pix; + + return rval; +} + +static int ioctl_g_fmt_cap(struct v4l2_int_device *s, + struct v4l2_format *f) +{ + struct tcm825x_sensor *sensor = s->priv; + + f->fmt.pix = sensor->pix; + + return 0; +} + +static int ioctl_g_parm(struct v4l2_int_device *s, + struct v4l2_streamparm *a) +{ + struct tcm825x_sensor *sensor = s->priv; + struct v4l2_captureparm *cparm = &a->parm.capture; + + if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + memset(a, 0, sizeof(*a)); + a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + cparm->capability = V4L2_CAP_TIMEPERFRAME; + cparm->timeperframe = sensor->timeperframe; + + return 0; +} + +static int ioctl_s_parm(struct v4l2_int_device *s, + struct v4l2_streamparm *a) +{ + struct tcm825x_sensor *sensor = s->priv; + struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe; + u32 tgt_fps; /* target frames per secound */ + int rval; + + if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + if ((timeperframe->numerator == 0) + || (timeperframe->denominator == 0)) { + timeperframe->denominator = DEFAULT_FPS; + timeperframe->numerator = 1; + } + + tgt_fps = timeperframe->denominator / timeperframe->numerator; + + if (tgt_fps > MAX_FPS) { + timeperframe->denominator = MAX_FPS; + timeperframe->numerator = 1; + } else if (tgt_fps < MIN_FPS) { + timeperframe->denominator = MIN_FPS; + timeperframe->numerator = 1; + } + + sensor->timeperframe = *timeperframe; + + rval = tcm825x_configure(s); + + return rval; +} + +static int ioctl_s_power(struct v4l2_int_device *s, int on) +{ + struct tcm825x_sensor *sensor = s->priv; + + return sensor->platform_data->power_set(on); +} + +static int ioctl_g_needs_reset(struct v4l2_int_device *s, void *buf) +{ + struct tcm825x_sensor *sensor = s->priv; + + return sensor->platform_data->needs_reset(s, buf, &sensor->pix); +} + +static int ioctl_reset(struct v4l2_int_device *s) +{ + return -EBUSY; +} + +static int ioctl_init(struct v4l2_int_device *s) +{ + return tcm825x_configure(s); +} + +static int ioctl_dev_exit(struct v4l2_int_device *s) +{ + return 0; +} + +static int ioctl_dev_init(struct v4l2_int_device *s) +{ + struct tcm825x_sensor *sensor = s->priv; + int r; + + r = tcm825x_read_reg(sensor->i2c_client, 0x01); + if (r < 0) + return r; + if (r == 0) { + dev_err(&sensor->i2c_client->dev, "device not detected\n"); + return -EIO; + } + return 0; +} + +#define NUM_IOCTLS 17 + +static struct v4l2_int_ioctl_desc tcm825x_ioctl_desc[NUM_IOCTLS] = { + { vidioc_int_dev_init_num, + (v4l2_int_ioctl_func *)&ioctl_dev_init }, + { vidioc_int_dev_exit_num, + (v4l2_int_ioctl_func *)&ioctl_dev_exit }, + { vidioc_int_s_power_num, + (v4l2_int_ioctl_func *)&ioctl_s_power }, + { vidioc_int_g_ext_clk_num, + (v4l2_int_ioctl_func *)&ioctl_g_ext_clk }, + { vidioc_int_s_ext_clk_num, + (v4l2_int_ioctl_func *)&ioctl_s_ext_clk }, + { vidioc_int_g_needs_reset_num, + (v4l2_int_ioctl_func *)&ioctl_g_needs_reset }, + { vidioc_int_reset_num, + (v4l2_int_ioctl_func *)&ioctl_reset }, + { vidioc_int_init_num, + (v4l2_int_ioctl_func *)&ioctl_init }, + { vidioc_int_enum_fmt_cap_num, + (v4l2_int_ioctl_func *)&ioctl_enum_fmt_cap }, + { vidioc_int_try_fmt_cap_num, + (v4l2_int_ioctl_func *)&ioctl_try_fmt_cap }, + { vidioc_int_g_fmt_cap_num, + (v4l2_int_ioctl_func *)&ioctl_g_fmt_cap }, + { vidioc_int_s_fmt_cap_num, + (v4l2_int_ioctl_func *)&ioctl_s_fmt_cap }, + { vidioc_int_g_parm_num, + (v4l2_int_ioctl_func *)&ioctl_g_parm }, + { vidioc_int_s_parm_num, + (v4l2_int_ioctl_func *)&ioctl_s_parm }, + { vidioc_int_queryctrl_num, + (v4l2_int_ioctl_func *)&ioctl_queryctrl }, + { vidioc_int_g_ctrl_num, + (v4l2_int_ioctl_func *)&ioctl_g_ctrl }, + { vidioc_int_s_ctrl_num, + (v4l2_int_ioctl_func *)&ioctl_s_ctrl }, +}; + +static struct v4l2_int_slave tcm825x_slave = { + .ioctls = tcm825x_ioctl_desc, + .num_ioctls = ARRAY_SIZE(tcm825x_ioctl_desc), +}; + +static struct tcm825x_sensor tcm825x; + +static struct v4l2_int_device tcm825x_int_device = { + .module = THIS_MODULE, + .name = TCM825X_NAME, + .priv = &tcm825x, + .type = v4l2_int_type_slave, + .u = { + .slave = &tcm825x_slave, + }, +}; + +static int tcm825x_probe(struct i2c_client *client) +{ + struct tcm825x_sensor *sensor = &tcm825x; + int rval; + + if (i2c_get_clientdata(client)) + return -EBUSY; + + sensor->platform_data = client->dev.platform_data; + + if (sensor->platform_data == NULL + && !sensor->platform_data->is_okay()) + return -ENODEV; + + sensor->v4l2_int_device = &tcm825x_int_device; + + sensor->i2c_client = client; + i2c_set_clientdata(client, sensor); + + /* Make the default capture format QVGA RGB565 */ + sensor->pix.width = tcm825x_sizes[QVGA].width; + sensor->pix.height = tcm825x_sizes[QVGA].height; + sensor->pix.pixelformat = V4L2_PIX_FMT_RGB565; + + rval = v4l2_int_device_register(sensor->v4l2_int_device); + if (rval) + i2c_set_clientdata(client, NULL); + + return rval; +} + +static int __exit tcm825x_remove(struct i2c_client *client) +{ + struct tcm825x_sensor *sensor = i2c_get_clientdata(client); + + if (!client->adapter) + return -ENODEV; /* our client isn't attached */ + + v4l2_int_device_unregister(sensor->v4l2_int_device); + i2c_set_clientdata(client, NULL); + + return 0; +} + +static struct i2c_driver tcm825x_i2c_driver = { + .driver = { + .name = TCM825X_NAME, + }, + .probe = &tcm825x_probe, + .remove = __exit_p(&tcm825x_remove), +}; + +static struct tcm825x_sensor tcm825x = { + .timeperframe = { + .numerator = 1, + .denominator = DEFAULT_FPS, + }, +}; + +static int __init tcm825x_init(void) +{ + int rval; + int i = 0; + + /* Just an experiment --- don't use *_cb functions yet. */ + tcm825x_ioctl_desc[i++] = vidioc_int_dev_init_cb(&ioctl_dev_init); + BUG_ON(i >= NUM_IOCTLS); + + rval = i2c_add_driver(&tcm825x_i2c_driver); + if (rval) + printk(KERN_INFO "%s: failed registering " TCM825X_NAME "\n", + __FUNCTION__); + + return rval; +} + +static void __exit tcm825x_exit(void) +{ + i2c_del_driver(&tcm825x_i2c_driver); +} + +/* + * FIXME: Menelaus isn't ready (?) at module_init stage, so use + * late_initcall for now. + */ +late_initcall(tcm825x_init); +module_exit(tcm825x_exit); + +MODULE_AUTHOR("Sakari Ailus "); +MODULE_DESCRIPTION("TCM825x camera sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/tcm825x.h b/drivers/media/video/tcm825x.h new file mode 100644 index 00000000000..d6471ec40bc --- /dev/null +++ b/drivers/media/video/tcm825x.h @@ -0,0 +1,195 @@ +/* + * drivers/media/video/tcm825x.h + * + * Register definitions for the TCM825X CameraChip. + * + * Author: David Cohen (david.cohen@indt.org.br) + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + * + * This file was based on ov9640.h from MontaVista + */ + +#ifndef TCM825X_H +#define TCM825X_H + +#include + +#include + +#define TCM825X_NAME "tcm825x" + +#define TCM825X_MASK(x) x & 0x00ff +#define TCM825X_ADDR(x) (x & 0xff00) >> 8 + +/* The TCM825X I2C sensor chip has a fixed slave address of 0x3d. */ +#define TCM825X_I2C_ADDR 0x3d + +/* + * define register offsets for the TCM825X sensor chip + * OFFSET(8 bits) + MASK(8 bits) + * MASK bit 4 and 3 are used when the register uses more than one address + */ +#define TCM825X_FPS 0x0280 +#define TCM825X_ACF 0x0240 +#define TCM825X_DOUTBUF 0x020C +#define TCM825X_DCLKP 0x0202 +#define TCM825X_ACFDET 0x0201 +#define TCM825X_DOUTSW 0x0380 +#define TCM825X_DATAHZ 0x0340 +#define TCM825X_PICSIZ 0x033c +#define TCM825X_PICFMT 0x0302 +#define TCM825X_V_INV 0x0480 +#define TCM825X_H_INV 0x0440 +#define TCM825X_ESRLSW 0x0430 +#define TCM825X_V_LENGTH 0x040F +#define TCM825X_ALCSW 0x0580 +#define TCM825X_ESRLIM 0x0560 +#define TCM825X_ESRSPD_U 0x051F +#define TCM825X_ESRSPD_L 0x06FF +#define TCM825X_AG 0x07FF +#define TCM825X_ESRSPD2 0x06FF +#define TCM825X_ALCMODE 0x0830 +#define TCM825X_ALCH 0x080F +#define TCM825X_ALCL 0x09FF +#define TCM825X_AWBSW 0x0A80 +#define TCM825X_MRG 0x0BFF +#define TCM825X_MBG 0x0CFF +#define TCM825X_GAMSW 0x0D80 +#define TCM825X_HDTG 0x0EFF +#define TCM825X_VDTG 0x0FFF +#define TCM825X_HDTCORE 0x10F0 +#define TCM825X_VDTCORE 0x100F +#define TCM825X_CONT 0x11FF +#define TCM825X_BRIGHT 0x12FF +#define TCM825X_VHUE 0x137F +#define TCM825X_UHUE 0x147F +#define TCM825X_VGAIN 0x153F +#define TCM825X_UGAIN 0x163F +#define TCM825X_UVCORE 0x170F +#define TCM825X_SATU 0x187F +#define TCM825X_MHMODE 0x1980 +#define TCM825X_MHLPFSEL 0x1940 +#define TCM825X_YMODE 0x1930 +#define TCM825X_MIXHG 0x1907 +#define TCM825X_LENS 0x1A3F +#define TCM825X_AGLIM 0x1BE0 +#define TCM825X_LENSRPOL 0x1B10 +#define TCM825X_LENSRGAIN 0x1B0F +#define TCM825X_ES100S 0x1CFF +#define TCM825X_ES120S 0x1DFF +#define TCM825X_DMASK 0x1EC0 +#define TCM825X_CODESW 0x1E20 +#define TCM825X_CODESEL 0x1E10 +#define TCM825X_TESPIC 0x1E04 +#define TCM825X_PICSEL 0x1E03 +#define TCM825X_HNUM 0x20FF +#define TCM825X_VOUTPH 0x287F +#define TCM825X_ESROUT 0x327F +#define TCM825X_ESROUT2 0x33FF +#define TCM825X_AGOUT 0x34FF +#define TCM825X_DGOUT 0x353F +#define TCM825X_AGSLOW1 0x39C0 +#define TCM825X_FLLSMODE 0x3930 +#define TCM825X_FLLSLIM 0x390F +#define TCM825X_DETSEL 0x3AF0 +#define TCM825X_ACDETNC 0x3A0F +#define TCM825X_AGSLOW2 0x3BC0 +#define TCM825X_DG 0x3B3F +#define TCM825X_REJHLEV 0x3CFF +#define TCM825X_ALCLOCK 0x3D80 +#define TCM825X_FPSLNKSW 0x3D40 +#define TCM825X_ALCSPD 0x3D30 +#define TCM825X_REJH 0x3D03 +#define TCM825X_SHESRSW 0x3E80 +#define TCM825X_ESLIMSEL 0x3E40 +#define TCM825X_SHESRSPD 0x3E30 +#define TCM825X_ELSTEP 0x3E0C +#define TCM825X_ELSTART 0x3E03 +#define TCM825X_AGMIN 0x3FFF +#define TCM825X_PREGRG 0x423F +#define TCM825X_PREGBG 0x433F +#define TCM825X_PRERG 0x443F +#define TCM825X_PREBG 0x453F +#define TCM825X_MSKBR 0x477F +#define TCM825X_MSKGR 0x487F +#define TCM825X_MSKRB 0x497F +#define TCM825X_MSKGB 0x4A7F +#define TCM825X_MSKRG 0x4B7F +#define TCM825X_MSKBG 0x4C7F +#define TCM825X_HDTCSW 0x4D80 +#define TCM825X_VDTCSW 0x4D40 +#define TCM825X_DTCYL 0x4D3F +#define TCM825X_HDTPSW 0x4E80 +#define TCM825X_VDTPSW 0x4E40 +#define TCM825X_DTCGAIN 0x4E3F +#define TCM825X_DTLLIMSW 0x4F10 +#define TCM825X_DTLYLIM 0x4F0F +#define TCM825X_YLCUTLMSK 0x5080 +#define TCM825X_YLCUTL 0x503F +#define TCM825X_YLCUTHMSK 0x5180 +#define TCM825X_YLCUTH 0x513F +#define TCM825X_UVSKNC 0x527F +#define TCM825X_UVLJ 0x537F +#define TCM825X_WBGMIN 0x54FF +#define TCM825X_WBGMAX 0x55FF +#define TCM825X_WBSPDUP 0x5603 +#define TCM825X_ALLAREA 0x5820 +#define TCM825X_WBLOCK 0x5810 +#define TCM825X_WB2SP 0x580F +#define TCM825X_KIZUSW 0x5920 +#define TCM825X_PBRSW 0x5910 +#define TCM825X_ABCSW 0x5903 +#define TCM825X_PBDLV 0x5AFF +#define TCM825X_PBC1LV 0x5BFF + +#define TCM825X_NUM_REGS (TCM825X_ADDR(TCM825X_PBC1LV) + 1) + +#define TCM825X_BYTES_PER_PIXEL 2 + +#define TCM825X_REG_TERM 0xff /* terminating list entry for reg */ +#define TCM825X_VAL_TERM 0xff /* terminating list entry for val */ + +/* define a structure for tcm825x register initialization values */ +struct tcm825x_reg { + u8 val; + u16 reg; +}; + +enum image_size { subQCIF = 0, QQVGA, QCIF, QVGA, CIF, VGA }; +enum pixel_format { YUV422 = 0, RGB565 }; +#define NUM_IMAGE_SIZES 6 +#define NUM_PIXEL_FORMATS 2 + +struct capture_size { + unsigned long width; + unsigned long height; +}; + +struct tcm825x_platform_data { + /* Is the sensor usable? Doesn't yet mean it's there, but you + * can try! */ + int (*is_okay)(void); + /* Set power state, zero is off, non-zero is on. */ + int (*power_set)(int power); + /* Default registers written after power-on or reset. */ + const struct tcm825x_reg *(*default_regs)(void); + int (*needs_reset)(struct v4l2_int_device *s, void *buf, + struct v4l2_pix_format *fmt); +}; + +/* Array of image sizes supported by TCM825X. These must be ordered from + * smallest image size to largest. + */ +const static struct capture_size tcm825x_sizes[] = { + { 128, 96 }, /* subQCIF */ + { 160, 120 }, /* QQVGA */ + { 176, 144 }, /* QCIF */ + { 320, 240 }, /* QVGA */ + { 352, 288 }, /* CIF */ + { 640, 480 }, /* VGA */ +}; + +#endif /* ifndef TCM825X_H */ -- cgit v1.2.3-70-g09d2 From baa05e4b454fa7d87f9a41a4bbc1f749c113ff3a Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 20 Jul 2007 06:26:34 -0300 Subject: V4L/DVB (5881): ivtv: init channel for NTSC_M_JP standard. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index d73d433a4ff..622af634104 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -1154,8 +1154,13 @@ static int __devinit ivtv_probe(struct pci_dev *dev, vf.tuner = 0; vf.type = V4L2_TUNER_ANALOG_TV; vf.frequency = 6400; /* the tuner 'baseline' frequency */ - if (itv->std & V4L2_STD_NTSC_M) { - /* Why on earth? */ + + /* Set initial frequency. For PAL/SECAM broadcasts no + 'default' channel exists AFAIK. */ + if (itv->std == V4L2_STD_NTSC_M_JP) { + vf.frequency = 1460; /* ch. 1 91250*16/1000 */ + } + else if (itv->std & V4L2_STD_NTSC_M) { vf.frequency = 1076; /* ch. 4 67250*16/1000 */ } -- cgit v1.2.3-70-g09d2 From 63116febb9233743279a05be510ab8524f5f6242 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 20 Jul 2007 13:12:51 -0300 Subject: V4L/DVB (5883): V4L: Fix a compile warning on non-32-bit machines. Fix a compile warning on non-32-bit machines in v4l2-int-device.h. Add internal ioctl interface fallback function for ioctls with one argument. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-int-device.c | 28 +++++++++++++++++++--------- include/media/v4l2-int-device.h | 2 +- 2 files changed, 20 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/v4l2-int-device.c b/drivers/media/video/v4l2-int-device.c index 7885d9b38c9..aa2a8156338 100644 --- a/drivers/media/video/v4l2-int-device.c +++ b/drivers/media/video/v4l2-int-device.c @@ -115,13 +115,9 @@ void v4l2_int_device_unregister(struct v4l2_int_device *d) mutex_unlock(&mutex); } -static int no_such_ioctl(struct v4l2_int_device *d) -{ - return -EINVAL; -} - /* Adapted from search_extable in extable.c. */ -static v4l2_int_ioctl_func *find_ioctl(struct v4l2_int_slave *slave, int cmd) +static v4l2_int_ioctl_func *find_ioctl(struct v4l2_int_slave *slave, int cmd, + v4l2_int_ioctl_func *no_such_ioctl) { const struct v4l2_int_ioctl_desc *first = slave->ioctls; const struct v4l2_int_ioctl_desc *last = @@ -140,15 +136,29 @@ static v4l2_int_ioctl_func *find_ioctl(struct v4l2_int_slave *slave, int cmd) return mid->func; } - return &no_such_ioctl; + return no_such_ioctl; +} + +static int no_such_ioctl_0(struct v4l2_int_device *d) +{ + return -EINVAL; } int v4l2_int_ioctl_0(struct v4l2_int_device *d, int cmd) { - return ((v4l2_int_ioctl_func_0 *)find_ioctl(d->u.slave, cmd))(d); + return ((v4l2_int_ioctl_func_0 *) + find_ioctl(d->u.slave, cmd, + (v4l2_int_ioctl_func *)&no_such_ioctl_0))(d); +} + +static int no_such_ioctl_1(struct v4l2_int_device *d, void *arg) +{ + return -EINVAL; } int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg) { - return ((v4l2_int_ioctl_func_1 *)find_ioctl(d->u.slave, cmd))(d, arg); + return ((v4l2_int_ioctl_func_1 *) + find_ioctl(d->u.slave, cmd, + (v4l2_int_ioctl_func *)&no_such_ioctl_1))(d, arg); } diff --git a/include/media/v4l2-int-device.h b/include/media/v4l2-int-device.h index 2b6fc1122f6..deb28ce6685 100644 --- a/include/media/v4l2-int-device.h +++ b/include/media/v4l2-int-device.h @@ -170,7 +170,7 @@ int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg); arg_type asterisk arg) \ { \ return v4l2_int_ioctl_1(d, vidioc_int_##name##_num, \ - (void *)arg); \ + (void *)(unsigned long)arg); \ } \ \ static inline struct v4l2_int_ioctl_desc \ -- cgit v1.2.3-70-g09d2 From 18b548ca580838a2cc5813a941e6dab28660bb22 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 17 Jul 2007 18:29:41 -0300 Subject: V4L/DVB (5884): zr36067: clean up debug function Debugging cleanups to the zr36067 driver: * Use module_param_named() to declare the debug parameter, so we can use a single global variable to handle the debug level. This makes the driver a bit smaller (by 648 bytes on x86_64), thanks to one less level of indirection on every use. * Change the debug parameter sysfs permissions, so that the debug level can be adjusted at runtime, as is done in many other media/video drivers. * The debug level is between 0 and 5, not 0 and 4. * Move the zr_debug export and dprintk macro definition to a header file so that we don't have to define them in each source file. * Simplify a duplicate test on zr_debug. Note that zr_debug was subsequently renamed to debug_zr36067 to avoid possible conflicts with other Zoran device drivers, on a suggestion by Trent Piepho. Signed-off-by: Jean Delvare Signed-off-by: Trent Piepho Acked-by: Ronald S. Bultje Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/zoran_card.c | 19 ++++++------------- drivers/media/video/zoran_card.h | 8 ++++++++ drivers/media/video/zoran_device.c | 17 +++++------------ drivers/media/video/zoran_driver.c | 20 +++++--------------- drivers/media/video/zoran_procfs.c | 9 +-------- 5 files changed, 25 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/zoran_card.c b/drivers/media/video/zoran_card.c index 73162a3a61d..8e12ff80550 100644 --- a/drivers/media/video/zoran_card.c +++ b/drivers/media/video/zoran_card.c @@ -145,10 +145,9 @@ module_param(pass_through, int, 0); MODULE_PARM_DESC(pass_through, "Pass TV signal through to TV-out when idling"); -static int debug = 1; -int *zr_debug = &debug; -module_param(debug, int, 0); -MODULE_PARM_DESC(debug, "Debug level (0-4)"); +int zr36067_debug = 1; +module_param_named(debug, zr36067_debug, int, 0644); +MODULE_PARM_DESC(debug, "Debug level (0-5)"); MODULE_DESCRIPTION("Zoran-36057/36067 JPEG codec driver"); MODULE_AUTHOR("Serguei Miridonov"); @@ -161,12 +160,6 @@ static struct pci_device_id zr36067_pci_tbl[] = { }; MODULE_DEVICE_TABLE(pci, zr36067_pci_tbl); -#define dprintk(num, format, args...) \ - do { \ - if (*zr_debug >= num) \ - printk(format, ##args); \ - } while (0) - int zoran_num; /* number of Buzs in use */ struct zoran zoran[BUZ_MAX]; @@ -1075,7 +1068,7 @@ test_interrupts (struct zoran *zr) if (timeout) { dprintk(1, ": time spent: %d\n", 1 * HZ - timeout); } - if (*zr_debug > 1) + if (zr36067_debug > 1) print_interrupts(zr); btwrite(icr, ZR36057_ICR); } @@ -1158,7 +1151,7 @@ zr36057_init (struct zoran *zr) goto exit_unregister; zoran_init_hardware(zr); - if (*zr_debug > 2) + if (zr36067_debug > 2) detect_guest_activity(zr); test_interrupts(zr); if (!pass_through) { @@ -1620,7 +1613,7 @@ init_dc10_cards (void) } /* random nonsense */ - dprintk(5, KERN_DEBUG "Jotti is een held!\n"); + dprintk(6, KERN_DEBUG "Jotti is een held!\n"); /* some mainboards might not do PCI-PCI data transfer well */ if (pci_pci_problems & (PCIPCI_FAIL|PCIAGP_FAIL|PCIPCI_ALIMAGIK)) { diff --git a/drivers/media/video/zoran_card.h b/drivers/media/video/zoran_card.h index ad997c30bee..8444ca0a5f3 100644 --- a/drivers/media/video/zoran_card.h +++ b/drivers/media/video/zoran_card.h @@ -30,6 +30,14 @@ #ifndef __ZORAN_CARD_H__ #define __ZORAN_CARD_H__ +extern int zr36067_debug; + +#define dprintk(num, format, args...) \ + do { \ + if (zr36067_debug >= num) \ + printk(format, ##args); \ + } while (0) + /* Anybody who uses more than four? */ #define BUZ_MAX 4 extern int zoran_num; diff --git a/drivers/media/video/zoran_device.c b/drivers/media/video/zoran_device.c index ba2f4ed2948..dc1ec20fb26 100644 --- a/drivers/media/video/zoran_device.c +++ b/drivers/media/video/zoran_device.c @@ -52,6 +52,7 @@ #include "videocodec.h" #include "zoran.h" #include "zoran_device.h" +#include "zoran_card.h" #define IRQ_MASK ( ZR36057_ISR_GIRQ0 | \ ZR36057_ISR_GIRQ1 | \ @@ -59,14 +60,6 @@ extern const struct zoran_format zoran_formats[]; -extern int *zr_debug; - -#define dprintk(num, format, args...) \ - do { \ - if (*zr_debug >= num) \ - printk(format, ##args); \ - } while (0) - static int lml33dpath = 0; /* 1 will use digital path in capture * mode instead of analog. It can be * used for picture adjustments using @@ -174,7 +167,7 @@ post_office_read (struct zoran *zr, static void dump_guests (struct zoran *zr) { - if (*zr_debug > 2) { + if (zr36067_debug > 2) { int i, guest[8]; for (i = 1; i < 8; i++) { // Don't read jpeg codec here @@ -1271,7 +1264,7 @@ error_handler (struct zoran *zr, zr->num_errors++; /* Report error */ - if (*zr_debug > 1 && zr->num_errors <= 8) { + if (zr36067_debug > 1 && zr->num_errors <= 8) { long frame; frame = zr->jpg_pend[zr->jpg_dma_tail & BUZ_MASK_FRAME]; @@ -1531,7 +1524,7 @@ zoran_irq (int irq, if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS || zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) { - if (*zr_debug > 1 && + if (zr36067_debug > 1 && (!zr->frame_num || zr->JPEG_error)) { printk(KERN_INFO "%s: first frame ready: state=0x%08x odd_even=%d field_per_buff=%d delay=%d\n", @@ -1568,7 +1561,7 @@ zoran_irq (int irq, zr->JPEG_missed; } - if (*zr_debug > 2 && zr->frame_num < 6) { + if (zr36067_debug > 2 && zr->frame_num < 6) { int i; printk("%s: seq=%ld stat_com:", ZR_DEVNAME(zr), zr->jpg_seq_num); diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c index 72a037b75d6..377bb2d11ff 100644 --- a/drivers/media/video/zoran_driver.c +++ b/drivers/media/video/zoran_driver.c @@ -200,14 +200,6 @@ const struct zoran_format zoran_formats[] = { // RJ: Test only - want to test BUZ_USE_HIMEM even when CONFIG_BIGPHYS_AREA is defined -extern int *zr_debug; - -#define dprintk(num, format, args...) \ - do { \ - if (*zr_debug >= num) \ - printk(format, ##args); \ - } while (0) - extern int v4l_nbufs; extern int v4l_bufsize; extern int jpg_nbufs; @@ -1106,12 +1098,10 @@ jpg_sync (struct file *file, frame = zr->jpg_pend[zr->jpg_que_tail & BUZ_MASK_FRAME]; /* buffer should now be in BUZ_STATE_DONE */ - if (*zr_debug > 0) - if (zr->jpg_buffers.buffer[frame].state != BUZ_STATE_DONE) - dprintk(2, - KERN_ERR - "%s: jpg_sync() - internal state error\n", - ZR_DEVNAME(zr)); + if (zr->jpg_buffers.buffer[frame].state != BUZ_STATE_DONE) + dprintk(2, + KERN_ERR "%s: jpg_sync() - internal state error\n", + ZR_DEVNAME(zr)); *bs = zr->jpg_buffers.buffer[frame].bs; bs->frame = frame; @@ -1389,7 +1379,7 @@ zoran_close (struct inode *inode, /* disable interrupts */ btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR); - if (*zr_debug > 1) + if (zr36067_debug > 1) print_interrupts(zr); /* Overlay off */ diff --git a/drivers/media/video/zoran_procfs.c b/drivers/media/video/zoran_procfs.c index 446ae8d5c3d..328ed6e7ac6 100644 --- a/drivers/media/video/zoran_procfs.c +++ b/drivers/media/video/zoran_procfs.c @@ -48,14 +48,7 @@ #include "videocodec.h" #include "zoran.h" #include "zoran_procfs.h" - -extern int *zr_debug; - -#define dprintk(num, format, args...) \ - do { \ - if (*zr_debug >= num) \ - printk(format, ##args); \ - } while (0) +#include "zoran_card.h" #ifdef CONFIG_PROC_FS struct procfs_params_zr36067 { -- cgit v1.2.3-70-g09d2 From 60e3cac47a442fae74d3429f706350229623bcce Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Tue, 17 Jul 2007 18:29:42 -0300 Subject: V4L/DVB (5885): zr36067: Fix problems with module parameters Add permissions to all the module parameters so they can be queried and set (when possible) via sysfs. Add description for the vidmem parameter. Change the video_nr parameter to an array, so that the video number can be specified when a user has more than one card. The driver would try to give all cards the same number otherwise, which will fail for all cards after the first. The default_input option would only allow values of 0 or 1, contrary to the description. Allow values up to the number of inputs defined for the card. Add description of lock_norm's different behavior for 1 and >1. Signed-off-by: Trent Piepho Acked-by: Ronald S. Bultje Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/zoran_card.c | 45 +++++++++++++++++++++++--------------- drivers/media/video/zoran_device.c | 2 +- drivers/media/video/zoran_driver.c | 4 ++-- 3 files changed, 30 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/zoran_card.c b/drivers/media/video/zoran_card.c index 8e12ff80550..48da36a15fc 100644 --- a/drivers/media/video/zoran_card.c +++ b/drivers/media/video/zoran_card.c @@ -64,15 +64,15 @@ extern const struct zoran_format zoran_formats[]; static int card[BUZ_MAX] = { -1, -1, -1, -1 }; -module_param_array(card, int, NULL, 0); +module_param_array(card, int, NULL, 0444); MODULE_PARM_DESC(card, "The type of card"); static int encoder[BUZ_MAX] = { -1, -1, -1, -1 }; -module_param_array(encoder, int, NULL, 0); +module_param_array(encoder, int, NULL, 0444); MODULE_PARM_DESC(encoder, "i2c TV encoder"); static int decoder[BUZ_MAX] = { -1, -1, -1, -1 }; -module_param_array(decoder, int, NULL, 0); +module_param_array(decoder, int, NULL, 0444); MODULE_PARM_DESC(decoder, "i2c TV decoder"); /* @@ -84,29 +84,31 @@ MODULE_PARM_DESC(decoder, "i2c TV decoder"); */ static unsigned long vidmem = 0; /* Video memory base address */ -module_param(vidmem, ulong, 0); +module_param(vidmem, ulong, 0444); +MODULE_PARM_DESC(vidmem, "Default video memory base address"); /* Default input and video norm at startup of the driver. */ -static int default_input = 0; /* 0=Composite, 1=S-Video */ -module_param(default_input, int, 0); +static unsigned int default_input = 0; /* 0=Composite, 1=S-Video */ +module_param(default_input, uint, 0444); MODULE_PARM_DESC(default_input, "Default input (0=Composite, 1=S-Video, 2=Internal)"); static int default_mux = 1; /* 6 Eyes input selection */ -module_param(default_mux, int, 0); +module_param(default_mux, int, 0644); MODULE_PARM_DESC(default_mux, "Default 6 Eyes mux setting (Input selection)"); static int default_norm = 0; /* 0=PAL, 1=NTSC 2=SECAM */ -module_param(default_norm, int, 0); +module_param(default_norm, int, 0444); MODULE_PARM_DESC(default_norm, "Default norm (0=PAL, 1=NTSC, 2=SECAM)"); -static int video_nr = -1; /* /dev/videoN, -1 for autodetect */ -module_param(video_nr, int, 0); -MODULE_PARM_DESC(video_nr, "video device number"); +/* /dev/videoN, -1 for autodetect */ +static int video_nr[BUZ_MAX] = {-1, -1, -1, -1}; +module_param_array(video_nr, int, NULL, 0444); +MODULE_PARM_DESC(video_nr, "video device number (-1=Auto)"); /* Number and size of grab buffers for Video 4 Linux @@ -127,21 +129,21 @@ MODULE_PARM_DESC(video_nr, "video device number"); int v4l_nbufs = 2; int v4l_bufsize = 128; /* Everybody should be able to work with this setting */ -module_param(v4l_nbufs, int, 0); +module_param(v4l_nbufs, int, 0644); MODULE_PARM_DESC(v4l_nbufs, "Maximum number of V4L buffers to use"); -module_param(v4l_bufsize, int, 0); +module_param(v4l_bufsize, int, 0644); MODULE_PARM_DESC(v4l_bufsize, "Maximum size per V4L buffer (in kB)"); int jpg_nbufs = 32; int jpg_bufsize = 512; /* max size for 100% quality full-PAL frame */ -module_param(jpg_nbufs, int, 0); +module_param(jpg_nbufs, int, 0644); MODULE_PARM_DESC(jpg_nbufs, "Maximum number of JPG buffers to use"); -module_param(jpg_bufsize, int, 0); +module_param(jpg_bufsize, int, 0644); MODULE_PARM_DESC(jpg_bufsize, "Maximum size per JPG buffer (in kB)"); int pass_through = 0; /* 1=Pass through TV signal when device is not used */ /* 0=Show color bar when device is not used (LML33: only if lml33dpath=1) */ -module_param(pass_through, int, 0); +module_param(pass_through, int, 0644); MODULE_PARM_DESC(pass_through, "Pass TV signal through to TV-out when idling"); @@ -1114,7 +1116,14 @@ zr36057_init (struct zoran *zr) zr->timing = zr->card.tvn[zr->norm]; } - zr->input = default_input = (default_input ? 1 : 0); + if (default_input > zr->card.inputs-1) { + dprintk(1, + KERN_WARNING + "%s: default_input value %d out of range (0-%d)\n", + ZR_DEVNAME(zr), default_input, zr->card.inputs-1); + default_input = 0; + } + zr->input = default_input; /* Should the following be reset at every open ? */ zr->hue = 32768; @@ -1146,7 +1155,7 @@ zr36057_init (struct zoran *zr) */ memcpy(zr->video_dev, &zoran_template, sizeof(zoran_template)); strcpy(zr->video_dev->name, ZR_DEVNAME(zr)); - err = video_register_device(zr->video_dev, VFL_TYPE_GRABBER, video_nr); + err = video_register_device(zr->video_dev, VFL_TYPE_GRABBER, video_nr[zr->id]); if (err < 0) goto exit_unregister; diff --git a/drivers/media/video/zoran_device.c b/drivers/media/video/zoran_device.c index dc1ec20fb26..68c7c505587 100644 --- a/drivers/media/video/zoran_device.c +++ b/drivers/media/video/zoran_device.c @@ -69,7 +69,7 @@ static int lml33dpath = 0; /* 1 will use digital path in capture * load on Bt819 input, there will be * some image imperfections */ -module_param(lml33dpath, bool, 0); +module_param(lml33dpath, bool, 0644); MODULE_PARM_DESC(lml33dpath, "Use digital path capture mode (on LML33 cards)"); diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c index 377bb2d11ff..4dbe2d449b5 100644 --- a/drivers/media/video/zoran_driver.c +++ b/drivers/media/video/zoran_driver.c @@ -207,8 +207,8 @@ extern int jpg_bufsize; extern int pass_through; static int lock_norm = 0; /* 1=Don't change TV standard (norm) */ -module_param(lock_norm, int, 0); -MODULE_PARM_DESC(lock_norm, "Users can't change norm"); +module_param(lock_norm, int, 0644); +MODULE_PARM_DESC(lock_norm, "Prevent norm changes (1 = ignore, >1 = fail)"); #ifdef CONFIG_VIDEO_V4L2 /* small helper function for calculating buffersizes for v4l2 -- cgit v1.2.3-70-g09d2 From d3c35acf2455fe354bdd00085511bef6bd6d52f1 Mon Sep 17 00:00:00 2001 From: Rasmus Rohde Date: Sat, 21 Jul 2007 15:37:35 -0300 Subject: V4L/DVB (5897): dtt200u: add support for the Miglia TVMini USB DVB-T adapter add code for autodetection and firmware download to the Miglia TVMini USB DVB-T adapter. After firmware download, the device re-registers using the WT220U_ZL0353_WARM usb id. Signed-off-by: Rasmus Rohde Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dtt200u.c | 28 +++++++++++++++++++++++++--- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 1 + 2 files changed, 26 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dtt200u.c b/drivers/media/dvb/dvb-usb/dtt200u.c index 7dbe1432101..d86cf9bee91 100644 --- a/drivers/media/dvb/dvb-usb/dtt200u.c +++ b/drivers/media/dvb/dvb-usb/dtt200u.c @@ -1,5 +1,5 @@ /* DVB USB library compliant Linux driver for the WideView/ Yakumo/ Hama/ - * Typhoon/ Yuan DVB-T USB2.0 receiver. + * Typhoon/ Yuan/ Miglia DVB-T USB2.0 receiver. * * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) * @@ -96,6 +96,7 @@ static struct dvb_usb_device_properties dtt200u_properties; static struct dvb_usb_device_properties wt220u_fc_properties; static struct dvb_usb_device_properties wt220u_properties; static struct dvb_usb_device_properties wt220u_zl0353_properties; +static struct dvb_usb_device_properties wt220u_miglia_properties; static int dtt200u_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) @@ -103,7 +104,8 @@ static int dtt200u_usb_probe(struct usb_interface *intf, if (dvb_usb_device_init(intf,&dtt200u_properties,THIS_MODULE,NULL) == 0 || dvb_usb_device_init(intf,&wt220u_properties,THIS_MODULE,NULL) == 0 || dvb_usb_device_init(intf,&wt220u_fc_properties,THIS_MODULE,NULL) == 0 || - dvb_usb_device_init(intf,&wt220u_zl0353_properties,THIS_MODULE,NULL) == 0) + dvb_usb_device_init(intf,&wt220u_zl0353_properties,THIS_MODULE,NULL) == 0 || + dvb_usb_device_init(intf,&wt220u_miglia_properties,THIS_MODULE,NULL) == 0) return 0; return -ENODEV; @@ -119,6 +121,7 @@ static struct usb_device_id dtt200u_usb_table [] = { { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_FC_COLD) }, { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_FC_WARM) }, { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZAP250_COLD) }, + { USB_DEVICE(USB_VID_MIGLIA, USB_PID_WT220U_ZAP250_COLD) }, { 0 }, }; MODULE_DEVICE_TABLE(usb, dtt200u_usb_table); @@ -303,6 +306,25 @@ static struct dvb_usb_device_properties wt220u_zl0353_properties = { } }; +static struct dvb_usb_device_properties wt220u_miglia_properties = { + .usb_ctrl = CYPRESS_FX2, + .firmware = "dvb-usb-wt220u-miglia-01.fw", + + .num_adapters = 1, + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 1, + .devices = { + { .name = "WideView WT-220U PenType Receiver (Miglia)", + .cold_ids = { &dtt200u_usb_table[9], NULL }, + /* This device turns into WT220U_ZL0353_WARM when fw + has been uploaded */ + .warm_ids = { NULL }, + }, + { NULL }, + } +}; + /* usb specific object needed to register this driver with the usb subsystem */ static struct usb_driver dtt200u_usb_driver = { .name = "dvb_usb_dtt200u", @@ -333,6 +355,6 @@ module_init(dtt200u_usb_module_init); module_exit(dtt200u_usb_module_exit); MODULE_AUTHOR("Patrick Boettcher "); -MODULE_DESCRIPTION("Driver for the WideView/Yakumo/Hama/Typhoon/Club3D DVB-T USB2.0 devices"); +MODULE_DESCRIPTION("Driver for the WideView/Yakumo/Hama/Typhoon/Club3D/Miglia DVB-T USB2.0 devices"); MODULE_VERSION("1.0"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 4dfab02a8a0..78ea3b566ff 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -34,6 +34,7 @@ #define USB_VID_LEADTEK 0x0413 #define USB_VID_LITEON 0x04ca #define USB_VID_MEDION 0x1660 +#define USB_VID_MIGLIA 0x18f3 #define USB_VID_MSI 0x0db0 #define USB_VID_OPERA1 0x695c #define USB_VID_PINNACLE 0x2304 -- cgit v1.2.3-70-g09d2 From 32db775452818656d5fd8fd8b0f54425f5cfc177 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 20 Jul 2007 09:29:43 -0300 Subject: V4L/DVB (5902): Add ivtv-fb framebuffer driver. Add the ivtv-fb framebuffer driver for cx23415 devices (currently only the Hauppauge PVR-350 cards). This makes it possible to use the On-Screen Display functionality of these cards, either for menus during MPEG playback, or as a console or X display. Signed-off-by: Kevin Thayer Signed-off-by: Chris Kennedy Signed-off-by: Hans Verkuil Signed-off-by: John P Harvey Signed-off-by: Ian Armstrong Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/Kconfig | 16 + drivers/media/video/ivtv/Makefile | 1 + drivers/media/video/ivtv/ivtv-driver.c | 15 +- drivers/media/video/ivtv/ivtv-driver.h | 26 +- drivers/media/video/ivtv/ivtv-fb.c | 1215 ++++++++++++++++++++++++++++++++ include/media/ivtv-fb.h | 35 + 6 files changed, 1283 insertions(+), 25 deletions(-) create mode 100644 drivers/media/video/ivtv/ivtv-fb.c create mode 100644 include/media/ivtv-fb.h (limited to 'drivers') diff --git a/drivers/media/video/ivtv/Kconfig b/drivers/media/video/ivtv/Kconfig index e43beb2c9cb..399f231abb9 100644 --- a/drivers/media/video/ivtv/Kconfig +++ b/drivers/media/video/ivtv/Kconfig @@ -25,3 +25,19 @@ config VIDEO_IVTV To compile this driver as a module, choose M here: the module will be called ivtv. + +config VIDEO_IVTV_FB + tristate "Conexant cx23415 framebuffer support" + depends on VIDEO_IVTV && FB && EXPERIMENTAL + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + ---help--- + This is a framebuffer driver for the Conexant cx23415 MPEG + encoder/decoder. + + This is used in the Hauppauge PVR-350 card. There is a driver + homepage at . + + To compile this driver as a module, choose M here: the + module will be called ivtv-fb. diff --git a/drivers/media/video/ivtv/Makefile b/drivers/media/video/ivtv/Makefile index 7e95148fbf4..90e2d127056 100644 --- a/drivers/media/video/ivtv/Makefile +++ b/drivers/media/video/ivtv/Makefile @@ -5,3 +5,4 @@ ivtv-objs := ivtv-audio.o ivtv-cards.o ivtv-controls.o \ ivtv-vbi.o ivtv-video.o ivtv-yuv.o obj-$(CONFIG_VIDEO_IVTV) += ivtv.o +obj-$(CONFIG_VIDEO_IVTV_FB) += ivtv-fb.o diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 622af634104..81cbaf7dd51 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -95,8 +95,14 @@ const u32 yuv_offset[4] = { /* Parameter declarations */ static int cardtype[IVTV_MAX_CARDS]; -static int tuner[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; -static int radio[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; +static int tuner[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 }; +static int radio[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 }; static int cardtype_c = 1; static int tuner_c = 1; @@ -1242,8 +1248,10 @@ static int __devinit ivtv_probe(struct pci_dev *dev, retval = -ENODEV; IVTV_ERR("Error %d on initialization\n", retval); + spin_lock(&ivtv_cards_lock); kfree(ivtv_cards[ivtv_cards_active]); ivtv_cards[ivtv_cards_active] = NULL; + spin_unlock(&ivtv_cards_lock); return retval; } @@ -1346,6 +1354,7 @@ static void module_cleanup(void) pci_unregister_driver(&ivtv_pci_driver); + spin_lock(&ivtv_cards_lock); for (i = 0; i < ivtv_cards_active; i++) { if (ivtv_cards[i] == NULL) continue; @@ -1354,6 +1363,7 @@ static void module_cleanup(void) } kfree(ivtv_cards[i]); } + spin_unlock(&ivtv_cards_lock); } /* Note: These symbols are exported because they are used by the ivtv-fb @@ -1361,6 +1371,7 @@ static void module_cleanup(void) EXPORT_SYMBOL(ivtv_set_irq_mask); EXPORT_SYMBOL(ivtv_cards_active); EXPORT_SYMBOL(ivtv_cards); +EXPORT_SYMBOL(ivtv_cards_lock); EXPORT_SYMBOL(ivtv_api); EXPORT_SYMBOL(ivtv_vapi); EXPORT_SYMBOL(ivtv_vapi_result); diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 8abb34a3581..8fe9d9c7a18 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -89,11 +89,9 @@ extern const u32 yuv_offset[4]; -/* Maximum ivtv driver instances. - Based on 6 PVR500s each with two PVR15s... - TODO: make this dynamic. I believe it is only a global in order to support - ivtv-fb. There must be a better way to do that. */ -#define IVTV_MAX_CARDS 12 +/* Maximum ivtv driver instances. Some people have a huge number of + capture cards, so set this to a high value. */ +#define IVTV_MAX_CARDS 32 /* Supported cards */ #define IVTV_CARD_PVR_250 0 /* WinTV PVR 250 */ @@ -303,28 +301,10 @@ extern const u32 yuv_offset[4]; #define IVTV_DEBUG_HI_DEC(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_DEC, "dec", fmt , ## args) #define IVTV_DEBUG_HI_YUV(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_YUV, "yuv", fmt , ## args) -#define IVTV_FB_DEBUG(x, type, fmt, args...) \ - do { \ - if ((x) & ivtv_debug) \ - printk(KERN_INFO "ivtv%d-fb " type ": " fmt, itv->num , ## args); \ - } while (0) -#define IVTV_FB_DEBUG_WARN(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_WARN, "warning", fmt , ## args) -#define IVTV_FB_DEBUG_INFO(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_INFO, "info", fmt , ## args) -#define IVTV_FB_DEBUG_API(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_API, "api", fmt , ## args) -#define IVTV_FB_DEBUG_DMA(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_DMA, "dma", fmt , ## args) -#define IVTV_FB_DEBUG_IOCTL(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_IOCTL, "ioctl", fmt , ## args) -#define IVTV_FB_DEBUG_I2C(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_I2C, "i2c", fmt , ## args) -#define IVTV_FB_DEBUG_IRQ(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_IRQ, "irq", fmt , ## args) -#define IVTV_FB_DEBUG_DEC(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_DEC, "dec", fmt , ## args) -#define IVTV_FB_DEBUG_YUV(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_YUV, "yuv", fmt , ## args) - /* Standard kernel messages */ #define IVTV_ERR(fmt, args...) printk(KERN_ERR "ivtv%d: " fmt, itv->num , ## args) #define IVTV_WARN(fmt, args...) printk(KERN_WARNING "ivtv%d: " fmt, itv->num , ## args) #define IVTV_INFO(fmt, args...) printk(KERN_INFO "ivtv%d: " fmt, itv->num , ## args) -#define IVTV_FB_ERR(fmt, args...) printk(KERN_ERR "ivtv%d-fb: " fmt, itv->num , ## args) -#define IVTV_FB_WARN(fmt, args...) printk(KERN_WARNING "ivtv%d-fb: " fmt, itv->num , ## args) -#define IVTV_FB_INFO(fmt, args...) printk(KERN_INFO "ivtv%d-fb: " fmt, itv->num , ## args) /* Values for IVTV_API_DEC_PLAYBACK_SPEED mpeg_frame_type_mask parameter: */ #define MPEG_FRAME_TYPE_IFRAME 1 diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c new file mode 100644 index 00000000000..8e9bd75fc2b --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-fb.c @@ -0,0 +1,1215 @@ +/* + On Screen Display cx23415 Framebuffer driver + + This module presents the cx23415 OSD (onscreen display) framebuffer memory + as a standard Linux /dev/fb style framebuffer device. The framebuffer has + support for 8,16 & 32 bpp packed pixel formats with alpha channel. In 16bpp + mode, there is a choice of a three color depths (12, 15 or 16 bits), but no + local alpha. The colorspace is selectable between rgb & yuv. + Depending on the TV standard configured in the ivtv module at load time, + the initial resolution is either 640x400 (NTSC) or 640x480 (PAL) at 8bpp. + Video timings are locked to ensure a vertical refresh rate of 50Hz (PAL) + or 59.94 (NTSC) + + Copyright (c) 2003 Matt T. Yourst + + Derived from drivers/video/vesafb.c + Portions (c) 1998 Gerd Knorr + + 2.6 kernel port: + Copyright (C) 2004 Matthias Badaire + + Copyright (C) 2004 Chris Kennedy + + Copyright (C) 2006 Ian Armstrong + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef CONFIG_MTRR +#include +#endif + +#include "ivtv-driver.h" +#include "ivtv-queue.h" +#include "ivtv-udma.h" +#include "ivtv-irq.h" +#include "ivtv-fileops.h" +#include "ivtv-mailbox.h" +#include "ivtv-cards.h" +#include + +/* card parameters */ +static int ivtv_fb_card_id = -1; +static int ivtv_fb_debug = 0; +static int osd_laced; +static int osd_compat; +static int osd_depth; +static int osd_upper; +static int osd_left; +static int osd_yres; +static int osd_xres; + +module_param(ivtv_fb_card_id, int, 0444); +module_param_named(debug,ivtv_fb_debug, int, 0644); +module_param(osd_laced, bool, 0444); +module_param(osd_compat, bool, 0444); +module_param(osd_depth, int, 0444); +module_param(osd_upper, int, 0444); +module_param(osd_left, int, 0444); +module_param(osd_yres, int, 0444); +module_param(osd_xres, int, 0444); + +MODULE_PARM_DESC(ivtv_fb_card_id, + "Only use framebuffer of the specified ivtv card (0-31)\n" + "\t\t\tdefault -1: initialize all available framebuffers"); + +MODULE_PARM_DESC(debug, + "Debug level (bitmask). Default: errors only\n" + "\t\t\t(debug = 3 gives full debugging)"); + +MODULE_PARM_DESC(osd_compat, + "Compatibility mode - Display size is locked (use for old X drivers)\n" + "\t\t\t0=off\n" + "\t\t\t1=on\n" + "\t\t\tdefault off"); + +/* Why upper, left, xres, yres, depth, laced ? To match terminology used + by fbset. + Why start at 1 for left & upper coordinate ? Because X doesn't allow 0 */ + +MODULE_PARM_DESC(osd_laced, + "Interlaced mode\n" + "\t\t\t0=off\n" + "\t\t\t1=on\n" + "\t\t\tdefault off"); + +MODULE_PARM_DESC(osd_depth, + "Bits per pixel - 8,16,32\n" + "\t\t\tdefault 8"); + +MODULE_PARM_DESC(osd_upper, + "Vertical start position\n" + "\t\t\tdefault 0 (Centered)"); + +MODULE_PARM_DESC(osd_left, + "Horizontal start position\n" + "\t\t\tdefault 0 (Centered)"); + +MODULE_PARM_DESC(osd_yres, + "Display height\n" + "\t\t\tdefault 480 (PAL)\n" + "\t\t\t 400 (NTSC)"); + +MODULE_PARM_DESC(osd_xres, + "Display width\n" + "\t\t\tdefault 640"); + +MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil, John Harvey, Ian Armstrong"); +MODULE_LICENSE("GPL"); + +/* --------------------------------------------------------------------- */ + +#define IVTV_FB_DBGFLG_WARN (1 << 0) +#define IVTV_FB_DBGFLG_INFO (1 << 1) + +#define IVTV_FB_DEBUG(x, type, fmt, args...) \ + do { \ + if ((x) & ivtv_fb_debug) \ + printk(KERN_INFO "ivtv-fb%d " type ": " fmt, itv->num , ## args); \ + } while (0) +#define IVTV_FB_DEBUG_WARN(fmt, args...) IVTV_FB_DEBUG(IVTV_FB_DBGFLG_WARN, "warning", fmt , ## args) +#define IVTV_FB_DEBUG_INFO(fmt, args...) IVTV_FB_DEBUG(IVTV_FB_DBGFLG_INFO, "info", fmt , ## args) + +/* Standard kernel messages */ +#define IVTV_FB_ERR(fmt, args...) printk(KERN_ERR "ivtv-fb%d: " fmt, itv->num , ## args) +#define IVTV_FB_WARN(fmt, args...) printk(KERN_WARNING "ivtv-fb%d: " fmt, itv->num , ## args) +#define IVTV_FB_INFO(fmt, args...) printk(KERN_INFO "ivtv-fb%d: " fmt, itv->num , ## args) + +/* --------------------------------------------------------------------- */ + +#define IVTV_OSD_MAX_WIDTH 720 +#define IVTV_OSD_MAX_HEIGHT 576 + +#define IVTV_OSD_BPP_8 0x00 +#define IVTV_OSD_BPP_16_444 0x03 +#define IVTV_OSD_BPP_16_555 0x02 +#define IVTV_OSD_BPP_16_565 0x01 +#define IVTV_OSD_BPP_32 0x04 + +struct osd_info { + /* Timing info for modes */ + u32 pixclock; + u32 hlimit; + u32 vlimit; + + /* Physical base address */ + unsigned long video_pbase; + /* Relative base address (relative to start of decoder memory) */ + u32 video_rbase; + /* Mapped base address */ + volatile char __iomem *video_vbase; + /* Buffer size */ + u32 video_buffer_size; + +#ifdef CONFIG_MTRR + /* video_base rounded down as required by hardware MTRRs */ + unsigned long fb_start_aligned_physaddr; + /* video_base rounded up as required by hardware MTRRs */ + unsigned long fb_end_aligned_physaddr; +#endif + + /* Store the buffer offset */ + int set_osd_coords_x; + int set_osd_coords_y; + + /* Current dimensions (NOT VISIBLE SIZE!) */ + int display_width; + int display_height; + int display_byte_stride; + + /* Current bits per pixel */ + int bits_per_pixel; + int bytes_per_pixel; + + /* Frame buffer stuff */ + struct fb_info ivtvfb_info; + struct fb_var_screeninfo ivtvfb_defined; + struct fb_fix_screeninfo ivtvfb_fix; +}; + +struct ivtv_osd_coords { + unsigned long offset; + unsigned long max_offset; + int pixel_stride; + int lines; + int x; + int y; +}; + +/* --------------------------------------------------------------------- */ + +/* ivtv API calls for framebuffer related support */ + +static int ivtv_fb_get_framebuffer(struct ivtv *itv, u32 *fbbase, + u32 *fblength) +{ + u32 data[CX2341X_MBOX_MAX_DATA]; + int rc; + + rc = ivtv_vapi_result(itv, data, CX2341X_OSD_GET_FRAMEBUFFER, 0); + *fbbase = data[0]; + *fblength = data[1]; + return rc; +} + +static int ivtv_fb_get_osd_coords(struct ivtv *itv, + struct ivtv_osd_coords *osd) +{ + u32 data[CX2341X_MBOX_MAX_DATA]; + + ivtv_vapi_result(itv, data, CX2341X_OSD_GET_OSD_COORDS, 0); + + osd->offset = data[0] - itv->osd_info->video_rbase; + osd->max_offset = itv->osd_info->display_width * itv->osd_info->display_height * 4; + osd->pixel_stride = data[1]; + osd->lines = data[2]; + osd->x = data[3]; + osd->y = data[4]; + return 0; +} + +static int ivtv_fb_set_osd_coords(struct ivtv *itv, const struct ivtv_osd_coords *osd) +{ + itv->osd_info->display_width = osd->pixel_stride; + itv->osd_info->display_byte_stride = osd->pixel_stride * itv->osd_info->bytes_per_pixel; + itv->osd_info->set_osd_coords_x += osd->x; + itv->osd_info->set_osd_coords_y = osd->y; + + return ivtv_vapi(itv, CX2341X_OSD_SET_OSD_COORDS, 5, + osd->offset + itv->osd_info->video_rbase, + osd->pixel_stride, + osd->lines, osd->x, osd->y); +} + +static int ivtv_fb_set_display_window(struct ivtv *itv, struct v4l2_rect *ivtv_window) +{ + + int osd_height_limit = itv->is_50hz ? 576 : 480; + + /* Only fail if resolution too high, otherwise fudge the start coords. */ + if ((ivtv_window->height > osd_height_limit) || (ivtv_window->width > IVTV_OSD_MAX_WIDTH)) + return -EINVAL; + + /* Ensure we don't exceed display limits */ + if (ivtv_window->top + ivtv_window->height > osd_height_limit) { + IVTV_FB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid height setting (%d,%d)\n", + ivtv_window->top, ivtv_window->height); + ivtv_window->top = osd_height_limit - ivtv_window->height; + } + + if (ivtv_window->left + ivtv_window->width > IVTV_OSD_MAX_WIDTH) { + IVTV_FB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid width setting (%d,%d)\n", + ivtv_window->left, ivtv_window->width); + ivtv_window->left = IVTV_OSD_MAX_WIDTH - ivtv_window->width; + } + + /* Set the OSD origin */ + write_reg((ivtv_window->top << 16) | ivtv_window->left, 0x02a04); + + /* How much to display */ + write_reg(((ivtv_window->top+ivtv_window->height) << 16) | (ivtv_window->left+ivtv_window->width), 0x02a08); + + /* Pass this info back the yuv handler */ + itv->yuv_info.osd_vis_w = ivtv_window->width; + itv->yuv_info.osd_vis_h = ivtv_window->height; + itv->yuv_info.osd_x_offset = ivtv_window->left; + itv->yuv_info.osd_y_offset = ivtv_window->top; + + return 0; +} + +static int ivtv_fb_prep_dec_dma_to_device(struct ivtv *itv, + unsigned long ivtv_dest_addr, void __user *userbuf, + int size_in_bytes) +{ + DEFINE_WAIT(wait); + int ret = 0; + int got_sig = 0; + + mutex_lock(&itv->udma.lock); + /* Map User DMA */ + if (ivtv_udma_setup(itv, ivtv_dest_addr, userbuf, size_in_bytes) <= 0) { + mutex_unlock(&itv->udma.lock); + IVTV_FB_WARN("ivtvfb_prep_dec_dma_to_device, " + "Error with get_user_pages: %d bytes, %d pages returned\n", + size_in_bytes, itv->udma.page_count); + + /* get_user_pages must have failed completely */ + return -EIO; + } + + IVTV_FB_DEBUG_INFO("ivtvfb_prep_dec_dma_to_device, %d bytes, %d pages\n", + size_in_bytes, itv->udma.page_count); + + ivtv_udma_prepare(itv); + prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE); + /* if no UDMA is pending and no UDMA is in progress, then the DMA + is finished */ + while (itv->i_flags & (IVTV_F_I_UDMA_PENDING | IVTV_F_I_UDMA)) { + /* don't interrupt if the DMA is in progress but break off + a still pending DMA. */ + got_sig = signal_pending(current); + if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags)) + break; + got_sig = 0; + schedule(); + } + finish_wait(&itv->dma_waitq, &wait); + + /* Unmap Last DMA Xfer */ + ivtv_udma_unmap(itv); + mutex_unlock(&itv->udma.lock); + if (got_sig) { + IVTV_DEBUG_INFO("User stopped OSD\n"); + return -EINTR; + } + + return ret; +} + +static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source, unsigned long dest_offset, int count) +{ + DEFINE_WAIT(wait); + + /* Nothing to do */ + if (count == 0) { + IVTV_FB_DEBUG_WARN("ivtv_fb_prep_frame: Nothing to do. count = 0\n"); + return -EINVAL; + } + + /* Check Total FB Size */ + if ((dest_offset + count) > itv->osd_info->video_buffer_size) { + IVTV_FB_WARN( + "ivtv_fb_prep_frame: Overflowing the framebuffer %ld, " + "only %d available\n", + (dest_offset + count), itv->osd_info->video_buffer_size); + return -E2BIG; + } + + /* Not fatal, but will have undesirable results */ + if ((unsigned long)source & 3) + IVTV_FB_WARN ("ivtv_fb_prep_frame: Source address not 32 bit aligned (0x%08lx)\n",(unsigned long)source); + + if (dest_offset & 3) + IVTV_FB_WARN ("ivtv_fb_prep_frame: Dest offset not 32 bit aligned (%ld)\n",dest_offset); + + if (count & 3) + IVTV_FB_WARN ("ivtv_fb_prep_frame: Count not a multiple of 4 (%d)\n",count); + + /* Check Source */ + if (!access_ok(VERIFY_READ, source + dest_offset, count)) { + IVTV_FB_WARN( + "Invalid userspace pointer!!! 0x%08lx\n", + (unsigned long)source); + + IVTV_FB_DEBUG_WARN( + "access_ok() failed for offset 0x%08lx source 0x%08lx count %d\n", + dest_offset, (unsigned long)source, + count); + return -EINVAL; + } + + /* OSD Address to send DMA to */ + dest_offset += IVTV_DEC_MEM_START + itv->osd_info->video_rbase; + + /* Fill Buffers */ + return ivtv_fb_prep_dec_dma_to_device(itv, dest_offset, source, count); +} + +static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) +{ + DEFINE_WAIT(wait); + struct ivtv *itv = (struct ivtv *)info->par; + int rc=0; + + switch (cmd) { + + case FBIOGET_VBLANK: { + struct fb_vblank vblank; + u32 trace; + + vblank.flags = FB_VBLANK_HAVE_COUNT |FB_VBLANK_HAVE_VCOUNT | + FB_VBLANK_HAVE_VSYNC; + trace = read_reg (0x028c0) >> 16; + if (itv->is_50hz && trace > 312) trace -= 312; + else if (itv->is_60hz && trace > 262) trace -= 262; + if (trace == 1) vblank.flags |= FB_VBLANK_VSYNCING; + vblank.count = itv->lastVsyncFrame; + vblank.vcount = trace; + vblank.hcount = 0; + if (copy_to_user((void __user *)arg, &vblank, sizeof(vblank))) + return -EFAULT; + return 0; + } + + case FBIO_WAITFORVSYNC: { + prepare_to_wait(&itv->vsync_waitq, &wait, TASK_INTERRUPTIBLE); + if (!schedule_timeout(HZ/20)) rc = -ETIMEDOUT; + finish_wait (&itv->vsync_waitq, &wait); + return rc; + } + + case IVTVFB_IOCTL_PREP_FRAME: { + struct ivtvfb_ioctl_dma_host_to_ivtv_args args; + + IVTV_FB_DEBUG_INFO("IVTVFB_IOCTL_PREP_FRAME\n"); + if (copy_from_user(&args, (void __user *)arg, sizeof(args))) + return -EFAULT; + + return ivtv_fb_prep_frame(itv, cmd, args.source, args.dest_offset, args.count); + } + + default: + IVTV_FB_ERR("Unknown IOCTL %d\n",cmd); + return -EINVAL; + } + return 0; +} + +/* Framebuffer device handling */ + +static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var) +{ + + struct ivtv_osd_coords ivtv_osd; + struct v4l2_rect ivtv_window; + + IVTV_FB_DEBUG_INFO("ivtvfb_set_var\n"); + + /* Select color space */ + if (var->nonstd) /* YUV */ + write_reg (read_reg(0x02a00) | 0x0002000,0x02a00); + else /* RGB */ + write_reg (read_reg(0x02a00) & ~0x0002000,0x02a00); + + /* Set the color mode + Although rare, occasionally things go wrong. The extra mode + change seems to help... */ + + switch (var->bits_per_pixel) { + case 8: + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0); + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_8); + break; + case 32: + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0); + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_32); + break; + case 16: + switch (var->green.length) { + case 4: + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0); + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_16_444); + break; + case 5: + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0); + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_16_555); + break; + case 6: + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0); + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_16_565); + break; + default: + IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n"); + } + break; + default: + IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n"); + } + + itv->osd_info->bits_per_pixel = var->bits_per_pixel; + itv->osd_info->bytes_per_pixel = var->bits_per_pixel / 8; + + /* Set the flicker filter */ + switch (var->vmode & FB_VMODE_MASK) { + case FB_VMODE_NONINTERLACED: /* Filter on */ + ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 1); + break; + case FB_VMODE_INTERLACED: /* Filter off */ + ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 0); + break; + default: + IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid video mode\n"); + } + + /* Read the current osd info */ + ivtv_fb_get_osd_coords(itv, &ivtv_osd); + + /* Now set the OSD to the size we want */ + ivtv_osd.pixel_stride = var->xres_virtual; + ivtv_osd.lines = var->yres_virtual; + ivtv_osd.x = 0; + ivtv_osd.y = 0; + ivtv_fb_set_osd_coords(itv, &ivtv_osd); + + /* Can't seem to find the right API combo for this. + Use another function which does what we need through direct register access. */ + ivtv_window.width = var->xres; + ivtv_window.height = var->yres; + + /* Minimum margin cannot be 0, as X won't allow such a mode */ + if (!var->upper_margin) var->upper_margin ++; + if (!var->left_margin) var->left_margin ++; + ivtv_window.top = var->upper_margin - 1; + ivtv_window.left = var->left_margin - 1; + + ivtv_fb_set_display_window(itv, &ivtv_window); + + /* Force update of yuv registers */ + itv->yuv_info.yuv_forced_update = 1; + + IVTV_FB_INFO("=== Display mode change ===\n"); + IVTV_FB_INFO("Display size %dx%d (%dx%d Virtual) @ %dbpp\n", + var->xres, + var->yres, + var->xres_virtual, + var->yres_virtual, + var->bits_per_pixel); + + IVTV_FB_INFO("Display position %d,%d\n", + var->left_margin, + var->upper_margin); + + if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) { + IVTV_FB_INFO("Display filter : on\n"); + } + else { + IVTV_FB_INFO("Display filter : off\n"); + } + + if (var->nonstd) { + IVTV_FB_INFO("Color space : YUV\n"); + } + else { + IVTV_FB_INFO("Color space : RGB\n"); + } + + return 0; +} + +static int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix) +{ + IVTV_FB_DEBUG_INFO ("ivtvfb_get_fix\n"); + memset(fix, 0, sizeof(struct fb_fix_screeninfo)); + strcpy(fix->id, "cx23415 TV out"); + fix->smem_start = itv->osd_info->video_pbase; + fix->smem_len = itv->osd_info->video_buffer_size; + fix->type = FB_TYPE_PACKED_PIXELS; + fix->visual = (itv->osd_info->bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; + fix->xpanstep = 1; + fix->ypanstep = 1; + fix->ywrapstep = 0; + fix->line_length = itv->osd_info->display_byte_stride; + fix->accel = FB_ACCEL_NONE; + return 0; +} + +/* Check the requested display mode, returning -EINVAL if we can't + handle it. */ + +static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) +{ + int osd_height_limit = itv->is_50hz ? 576 : 480; + + IVTV_FB_DEBUG_INFO ("ivtvfb_check_var\n"); + + /* Check the bits per pixel */ + if (osd_compat) { + if (var->bits_per_pixel != 32) { + IVTV_FB_DEBUG_WARN ("Invalid colour mode: %d\n",var->bits_per_pixel); + return -EINVAL; + } + } + + if (var->bits_per_pixel == 8 || var->bits_per_pixel == 32) { + var->transp.offset = 24; + var->transp.length = 8; + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + } + else if (var->bits_per_pixel == 16) { + /* To find out the true mode, check green length */ + switch (var->green.length) { + case 4: + var->transp.offset = 0; + var->transp.length = 0; + var->red.offset = 8; + var->red.length = 4; + var->green.offset = 4; + var->green.length = 4; + var->blue.offset = 0; + var->blue.length = 4; + break; + case 5: + var->transp.offset = 0; + var->transp.length = 0; + var->red.offset = 10; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 5; + var->blue.offset = 0; + var->blue.length = 5; + break; + default: + var->transp.offset = 0; + var->transp.length = 0; + var->red.offset = 11; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.offset = 0; + var->blue.length = 5; + break; + } + } + else { + IVTV_FB_DEBUG_WARN ("Invalid colour mode: %d\n",var->bits_per_pixel); + return -EINVAL; + } + + /* Check the resolution */ + if (osd_compat) { + if (var->xres != itv->osd_info->ivtvfb_defined.xres || var->yres != itv->osd_info->ivtvfb_defined.yres || + var->xres_virtual != itv->osd_info->ivtvfb_defined.xres_virtual || var->yres_virtual != + itv->osd_info->ivtvfb_defined.yres_virtual) { + IVTV_FB_DEBUG_WARN ("Invalid resolution: %d x %d (%d x %d Virtual)\n", + var->xres,var->yres, var->xres_virtual,var->yres_virtual); + return -EINVAL; + } + } + else { + if (var->xres > IVTV_OSD_MAX_WIDTH || var->yres > osd_height_limit ) { + IVTV_FB_DEBUG_WARN ("Invalid resolution: %d x %d\n", + var->xres,var->yres); + return -EINVAL; + } + + /* Max horizontal size is 1023 @ 32bpp, 2046 & 16bpp, 4092 @ 8bpp */ + if (var->xres_virtual > 4095 / (var->bits_per_pixel / 8) || + var->xres_virtual * var->yres_virtual * (var->bits_per_pixel/8) > itv->osd_info->video_buffer_size || + var->xres_virtual < var->xres || + var->yres_virtual < var->yres) { + IVTV_FB_DEBUG_WARN ("Invalid virtual resolution: %d x %d\n", + var->xres_virtual, var->yres_virtual); + return -EINVAL; + } + } + + /* Some extra checks if in 8 bit mode */ + if (var->bits_per_pixel == 8) { + /* Width must be a multiple of 4 */ + if (var->xres & 3) { + IVTV_FB_DEBUG_WARN ("Invalid resolution for 8bpp: %d\n", var->xres); + return -EINVAL; + } + if (var->xres_virtual & 3) { + IVTV_FB_DEBUG_WARN ("Invalid virtual resolution for 8bpp: %d)\n", var->xres_virtual); + return -EINVAL; + } + } + else if (var->bits_per_pixel == 16) { + /* Width must be a multiple of 2 */ + if (var->xres & 1) { + IVTV_FB_DEBUG_WARN ("Invalid resolution for 16bpp: %d\n", var->xres); + return -EINVAL; + } + if (var->xres_virtual & 1) { + IVTV_FB_DEBUG_WARN ("Invalid virtual resolution for 16bpp: %d)\n", var->xres_virtual); + return -EINVAL; + } + } + + /* Now check the offsets */ + if (var->xoffset >= var->xres_virtual || var->yoffset >= var->yres_virtual) { + IVTV_FB_DEBUG_WARN ("Invalid offset: %d (%d) %d (%d)\n",var->xoffset,var->xres_virtual, + var->yoffset,var->yres_virtual); + return -EINVAL; + } + + /* Check pixel format */ + if (var->nonstd > 1) { + IVTV_FB_DEBUG_WARN ("Invalid nonstd % d\n",var->nonstd); + return -EINVAL; + } + + /* Check video mode */ + if (((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) && + ((var->vmode & FB_VMODE_MASK) != FB_VMODE_INTERLACED)) { + IVTV_FB_DEBUG_WARN ("Invalid video mode: %d\n",var->vmode & FB_VMODE_MASK); + return -EINVAL; + } + + /* Check the left & upper margins + If the margins are too large, just center the screen + (enforcing margins causes too many problems) */ + + if (var->left_margin + var->xres > IVTV_OSD_MAX_WIDTH + 1) { + var->left_margin = 1 + ((IVTV_OSD_MAX_WIDTH - var->xres) / 2); + } + if (var->upper_margin + var->yres > (itv->is_50hz ? 577 : 481)) { + var->upper_margin = 1 + (((itv->is_50hz ? 576 : 480) - var->yres) / 2); + } + + /* Maintain overall 'size' for a constant refresh rate */ + var->right_margin = itv->osd_info->hlimit - var->left_margin - var->xres; + var->lower_margin = itv->osd_info->vlimit - var->upper_margin - var->yres; + + /* Fixed sync times */ + var->hsync_len = 24; + var->vsync_len = 2; + + /* Non-interlaced / interlaced mode is used to switch the OSD filter + on or off. Adjust the clock timings to maintain a constant + vertical refresh rate. */ + var->pixclock = itv->osd_info->pixclock; + if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) + var->pixclock /= 2; + + IVTV_FB_DEBUG_INFO ("ivtvfb_check_var - Parameters validated\n"); + + IVTV_FB_INFO("=== Validated display mode ===\n"); + IVTV_FB_INFO("Display size %dx%d (%dx%d Virtual) @ %dbpp\n", + var->xres, + var->yres, + var->xres_virtual, + var->yres_virtual, + var->bits_per_pixel); + + IVTV_FB_INFO("Display position %d,%d\n", + var->left_margin, + var->upper_margin); + + if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) { + IVTV_FB_INFO("Display filter : on\n"); + } + else { + IVTV_FB_INFO("Display filter : off\n"); + } + + if (var->nonstd) { + IVTV_FB_INFO("Color space : YUV\n"); + } + else { + IVTV_FB_INFO("Color space : RGB\n"); + } + return 0; +} + +static int ivtvfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct ivtv *itv = (struct ivtv *) info->par; + IVTV_FB_DEBUG_INFO ("ivtvfb_check_var\n"); + return _ivtvfb_check_var (var,itv); +} + +static int ivtvfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) +{ + u32 osd_pan_index; + struct ivtv *itv = (struct ivtv *) info->par; + + osd_pan_index = (var->xoffset + (var->yoffset * var->xres_virtual))*var->bits_per_pixel/8; + write_reg (osd_pan_index,0x02A0C); + + /* Pass this info back the yuv handler */ + itv->yuv_info.osd_x_pan = var->xoffset; + itv->yuv_info.osd_y_pan = var->yoffset; + /* Force update of yuv registers */ + itv->yuv_info.yuv_forced_update = 1; + return 0; +} + +static int ivtvfb_set_par(struct fb_info *info) +{ + int rc = 0; + struct ivtv *itv = (struct ivtv *) info->par; + + IVTV_FB_DEBUG_INFO ("ivtvfb_set_par\n"); + + rc = ivtvfb_set_var(itv, &info->var); + ivtvfb_pan_display(&info->var, info); + ivtvfb_get_fix (itv, &info->fix); + return rc; +} + +static int ivtvfb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + u32 color, *palette; + struct ivtv *itv = (struct ivtv *) info->par; + + if (regno >= info->cmap.len) + return -EINVAL; + + color = ((transp & 0xFF00) << 16) |((red & 0xFF00) << 8) | (green & 0xFF00) | ((blue & 0xFF00) >> 8); + if (info->var.bits_per_pixel <= 8) { + write_reg(regno, 0x02a30); + write_reg(color, 0x02a34); + } + else { + if (regno >= 16) + return -EINVAL; + + palette = info->pseudo_palette; + if (info->var.bits_per_pixel == 16) { + switch (info->var.green.length) { + case 4: + color = ((red & 0xf000) >> 4) | + ((green & 0xf000) >> 8) | + ((blue & 0xf000) >> 12); + break; + case 5: + color = ((red & 0xf800) >> 1) | + ((green & 0xf800) >> 6) | + ((blue & 0xf800) >> 11); + break; + case 6: + color = (red & 0xf800 ) | + ((green & 0xfc00) >> 5) | + ((blue & 0xf800) >> 11); + break; + } + } + palette[regno] = color; + } + + return 0; +} + +/* We don't really support blanking. All this does is enable or + disable the OSD. */ +static int ivtvfb_blank(int blank_mode, struct fb_info *info) +{ + struct ivtv *itv = (struct ivtv *)info->par; + + IVTV_FB_DEBUG_INFO ("Set blanking mode : %d\n",blank_mode); + switch (blank_mode) { + case FB_BLANK_UNBLANK: + ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 1); + break; + case FB_BLANK_NORMAL: + case FB_BLANK_HSYNC_SUSPEND: + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_POWERDOWN: + ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0); + break; + } + return 0; +} + +static struct fb_ops ivtvfb_ops = { + .owner = THIS_MODULE, + .fb_check_var = ivtvfb_check_var, + .fb_set_par = ivtvfb_set_par, + .fb_setcolreg = ivtvfb_setcolreg, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = NULL, + .fb_ioctl = ivtvfb_ioctl, + .fb_pan_display = ivtvfb_pan_display, + .fb_blank = ivtvfb_blank, +}; + +/* Initialization */ + + +/* Setup our initial video mode */ +static int ivtvfb_init_vidmode(struct ivtv *itv) +{ + int max_height; + struct v4l2_rect start_window; + + /* Set base references for mode calcs. */ + if (itv->is_50hz) { + itv->osd_info->pixclock = 84316; + itv->osd_info->hlimit = 776; + itv->osd_info->vlimit = 591; + } + else { + itv->osd_info->pixclock = 83926; + itv->osd_info->hlimit = 776; + itv->osd_info->vlimit = 495; + } + + /* Color mode */ + + if (osd_compat) osd_depth = 32; + if (osd_depth != 8 && osd_depth != 16 && osd_depth != 32) osd_depth = 8; + itv->osd_info->bits_per_pixel = osd_depth; + itv->osd_info->bytes_per_pixel = itv->osd_info->bits_per_pixel / 8; + + /* Horizontal size & position */ + + if (osd_xres > 720) osd_xres = 720; + + /* Must be a multiple of 4 for 8bpp & 2 for 16bpp */ + if (osd_depth == 8) + osd_xres &= ~3; + else if (osd_depth == 16) + osd_xres &= ~1; + + if (osd_xres) + start_window.width = osd_xres; + else + start_window.width = osd_compat ? 720: 640; + + /* Check horizontal start (osd_left). */ + if (osd_left && osd_left + start_window.width > 721) { + IVTV_FB_ERR ("Invalid osd_left - assuming default\n"); + osd_left = 0; + } + + /* Hardware coords start at 0, user coords start at 1. */ + osd_left --; + + start_window.left = + osd_left >= 0 ? osd_left : ((IVTV_OSD_MAX_WIDTH - start_window.width) / 2); + + itv->osd_info->display_byte_stride = + start_window.width * itv->osd_info->bytes_per_pixel; + + /* Vertical size & position */ + + max_height = itv->is_50hz ? 576 : 480; + + if ( osd_yres > max_height) osd_yres = max_height; + + if (osd_yres) + start_window.height = osd_yres; + else { + if (itv->is_50hz) + start_window.height = osd_compat ? max_height : 480; + else + start_window.height = osd_compat ? max_height : 400; + } + + /* Check vertical start (osd_upper). */ + if (osd_upper + start_window.height > max_height + 1) { + IVTV_FB_ERR ("Invalid osd_upper - assuming default\n"); + osd_upper = 0; + } + + /* Hardware coords start at 0, user coords start at 1. */ + osd_upper --; + + start_window.top = osd_upper >= 0 ? osd_upper : ((max_height - start_window.height) / 2); + + itv->osd_info->display_width = start_window.width; + itv->osd_info->display_height = start_window.height; + + /* Generate a valid fb_var_screeninfo */ + + itv->osd_info->ivtvfb_defined.xres = itv->osd_info->display_width; + itv->osd_info->ivtvfb_defined.yres = itv->osd_info->display_height; + itv->osd_info->ivtvfb_defined.xres_virtual = itv->osd_info->display_width; + itv->osd_info->ivtvfb_defined.yres_virtual = itv->osd_info->display_height; + itv->osd_info->ivtvfb_defined.bits_per_pixel = itv->osd_info->bits_per_pixel; + itv->osd_info->ivtvfb_defined.vmode = (osd_laced ? FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED); + itv->osd_info->ivtvfb_defined.left_margin = start_window.left + 1; + itv->osd_info->ivtvfb_defined.upper_margin = start_window.top + 1; + itv->osd_info->ivtvfb_defined.accel_flags = FB_ACCEL_NONE; + itv->osd_info->ivtvfb_defined.nonstd = 0; + + /* We've filled in the most data, let the usual mode check + routine fill in the rest. */ + _ivtvfb_check_var (&itv->osd_info->ivtvfb_defined,itv); + + /* Generate valid fb_fix_screeninfo */ + + ivtvfb_get_fix(itv,&itv->osd_info->ivtvfb_fix); + + /* Generate valid fb_info */ + + itv->osd_info->ivtvfb_info.node = -1; + itv->osd_info->ivtvfb_info.flags = FBINFO_FLAG_DEFAULT; + itv->osd_info->ivtvfb_info.fbops = &ivtvfb_ops; + itv->osd_info->ivtvfb_info.par = itv; + itv->osd_info->ivtvfb_info.var = itv->osd_info->ivtvfb_defined; + itv->osd_info->ivtvfb_info.fix = itv->osd_info->ivtvfb_fix; + itv->osd_info->ivtvfb_info.screen_base = (u8 __iomem *)itv->osd_info->video_vbase; + itv->osd_info->ivtvfb_info.fbops = &ivtvfb_ops; + + /* Supply some monitor specs. Bogus values will do for now */ + itv->osd_info->ivtvfb_info.monspecs.hfmin = 8000; + itv->osd_info->ivtvfb_info.monspecs.hfmax = 70000; + itv->osd_info->ivtvfb_info.monspecs.vfmin = 10; + itv->osd_info->ivtvfb_info.monspecs.vfmax = 100; + + /* Allocate color map */ + if (fb_alloc_cmap(&itv->osd_info->ivtvfb_info.cmap, 256, 1)) { + IVTV_FB_ERR ("abort, unable to alloc cmap\n"); + return -ENOMEM; + } + + /* Allocate the pseudo palette */ + itv->osd_info->ivtvfb_info.pseudo_palette = kmalloc(sizeof (u32) * 16, GFP_KERNEL); + + if (!itv->osd_info->ivtvfb_info.pseudo_palette) { + IVTV_FB_ERR ("abort, unable to alloc pseudo pallete\n"); + return -ENOMEM; + } + + return 0; +} + +/* Find OSD buffer base & size. Add to mtrr. Zero osd buffer. */ + +static int ivtvfb_init_io(struct ivtv *itv) +{ + ivtv_fb_get_framebuffer(itv, &itv->osd_info->video_rbase, &itv->osd_info->video_buffer_size); + + /* The osd buffer size depends on the number of video buffers allocated + on the PVR350 itself. For now we'll hardcode the smallest osd buffer + size to prevent any overlap. */ + itv->osd_info->video_buffer_size = 1704960; + + itv->osd_info->video_pbase = itv->base_addr + IVTV_DECODER_OFFSET + itv->osd_info->video_rbase; + itv->osd_info->video_vbase = itv->dec_mem + itv->osd_info->video_rbase; + + if (!itv->osd_info->video_vbase) { + IVTV_FB_ERR("abort, video memory 0x%x @ 0x%lx isn't mapped!\n", + itv->osd_info->video_buffer_size, itv->osd_info->video_pbase); + return -EIO; + } + + IVTV_FB_INFO("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n", + itv->osd_info->video_pbase, itv->osd_info->video_vbase, + itv->osd_info->video_buffer_size / 1024); + +#ifdef CONFIG_MTRR + { + /* Find the largest power of two that maps the whole buffer */ + int size_shift = 31; + + while (!(itv->osd_info->video_buffer_size & (1 << size_shift))) { + size_shift--; + } + size_shift++; + itv->osd_info->fb_start_aligned_physaddr = itv->osd_info->video_pbase & ~((1 << size_shift) - 1); + itv->osd_info->fb_end_aligned_physaddr = itv->osd_info->video_pbase + itv->osd_info->video_buffer_size; + itv->osd_info->fb_end_aligned_physaddr += (1 << size_shift) - 1; + itv->osd_info->fb_end_aligned_physaddr &= ~((1 << size_shift) - 1); + if (mtrr_add(itv->osd_info->fb_start_aligned_physaddr, + itv->osd_info->fb_end_aligned_physaddr - itv->osd_info->fb_start_aligned_physaddr, + MTRR_TYPE_WRCOMB, 1) < 0) { + IVTV_FB_ERR("warning: mtrr_add() failed to add write combining region 0x%08x-0x%08x\n", + (unsigned int)itv->osd_info->fb_start_aligned_physaddr, + (unsigned int)itv->osd_info->fb_end_aligned_physaddr); + } + } +#endif /* CONFIG_MTRR */ + + /* Blank the entire osd. */ + memset_io(itv->osd_info->video_vbase, 0, itv->osd_info->video_buffer_size); + + return 0; +} + +/* Release any memory we've grabbed & remove mtrr entry */ +static void ivtvfb_release_buffers (struct ivtv *itv) +{ + /* Release cmap */ + if (itv->osd_info->ivtvfb_info.cmap.len); + fb_dealloc_cmap(&itv->osd_info->ivtvfb_info.cmap); + + /* Release pseudo palette */ + if (itv->osd_info->ivtvfb_info.pseudo_palette) + kfree(itv->osd_info->ivtvfb_info.pseudo_palette); + +#ifdef CONFIG_MTRR + mtrr_del(-1, itv->osd_info->fb_start_aligned_physaddr, + (itv->osd_info->fb_end_aligned_physaddr - itv->osd_info->fb_start_aligned_physaddr)); +#endif /* CONFIG_MTRR */ + + kfree(itv->osd_info); + itv->osd_info = NULL; +} + +/* Initialize the specified card */ + +static int ivtvfb_init_card (struct ivtv *itv) +{ + int rc; + + if (itv->osd_info) { + IVTV_FB_ERR("Card %d already initialised\n", ivtv_fb_card_id); + return -EBUSY; + } + + itv->osd_info = kzalloc(sizeof(struct osd_info), GFP_ATOMIC); + if (itv->osd_info == 0) { + IVTV_FB_ERR("Failed to allocate memory for osd_info\n"); + return -ENOMEM; + } + + /* Find & setup the OSD buffer */ + if ((rc = ivtvfb_init_io (itv))) + return rc; + + /* Set the startup video mode information */ + if ((rc = ivtvfb_init_vidmode (itv))) { + ivtvfb_release_buffers(itv); + return rc; + } + + /* Register the framebuffer */ + if (register_framebuffer(&itv->osd_info->ivtvfb_info) < 0) { + ivtvfb_release_buffers(itv); + return -EINVAL; + } + + itv->osd_video_pbase = itv->osd_info->video_pbase; + + /* Set the card to the requested mode */ + ivtvfb_set_par(&itv->osd_info->ivtvfb_info); + + /* Set color 0 to black */ + write_reg(0, 0x02a30); + write_reg(0, 0x02a34); + + /* Enable the osd */ + ivtvfb_blank(FB_BLANK_UNBLANK, &itv->osd_info->ivtvfb_info); + + /* Note if we're running in compatibility mode */ + if (osd_compat) + IVTV_FB_INFO("Running in compatibility mode. Display resize & mode change disabled\n"); + + /* Allocate DMA */ + ivtv_udma_alloc(itv); + return 0; + +} + +static int __init ivtvfb_init(void) +{ + struct ivtv *itv; + int i, registered = 0; + + if (ivtv_fb_card_id < -1 || ivtv_fb_card_id >= IVTV_MAX_CARDS) { + printk(KERN_ERR "ivtv-fb: ivtv_fb_card_id parameter is out of range (valid range: -1 - %d)\n", + IVTV_MAX_CARDS - 1); + return -EINVAL; + } + + /* Locate & initialise all cards supporting an OSD. */ + for (i = 0; i < ivtv_cards_active; i++) { + if (ivtv_fb_card_id != -1 && i != ivtv_fb_card_id) + continue; + itv = ivtv_cards[i]; + if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) { + if (ivtvfb_init_card(itv) == 0) { + IVTV_FB_INFO("Framebuffer registered on ivtv card id %d\n", i); + registered++; + } + } + } + if (!registered) { + printk(KERN_ERR "ivtv-fb: no cards found"); + return -ENODEV; + } + return 0; +} + +static void ivtvfb_cleanup(void) +{ + struct ivtv *itv; + int i; + + printk(KERN_INFO "ivtv-fb: Unloading framebuffer module\n"); + + for (i = 0; i < ivtv_cards_active; i++) { + itv = ivtv_cards[i]; + if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) && itv->osd_info) { + IVTV_FB_DEBUG_INFO("Unregister framebuffer %d\n", i); + ivtvfb_blank(FB_BLANK_POWERDOWN, &itv->osd_info->ivtvfb_info); + unregister_framebuffer(&itv->osd_info->ivtvfb_info); + ivtvfb_release_buffers(itv); + itv->osd_video_pbase = 0; + } + } +} + +module_init(ivtvfb_init); +module_exit(ivtvfb_cleanup); diff --git a/include/media/ivtv-fb.h b/include/media/ivtv-fb.h new file mode 100644 index 00000000000..902b2f3d3cb --- /dev/null +++ b/include/media/ivtv-fb.h @@ -0,0 +1,35 @@ +/* + On Screen Display cx23415 Framebuffer driver + + Copyright (C) 2006 Ian Armstrong + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _LINUX_IVTV_FB_H +#define _LINUX_IVTV_FB_H + +/* Framebuffer external API */ + +struct ivtvfb_ioctl_dma_host_to_ivtv_args { + void __user *source; + unsigned long dest_offset; + int count; +}; + +/* Framebuffer ioctls should use the range 1 - 28 */ +#define IVTVFB_IOCTL_PREP_FRAME _IOW('@', 3, struct ivtvfb_ioctl_dma_host_to_ivtv_args) + +#endif -- cgit v1.2.3-70-g09d2 From be383bd312c4defab8bd4bde8c06fea5bfe0996b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 20 Jul 2007 10:16:03 -0300 Subject: V4L/DVB (5904): ivtv-fb: cleanups Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-fb.c | 439 +++++++++++++++++-------------------- 1 file changed, 204 insertions(+), 235 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c index 8e9bd75fc2b..01cd65328e8 100644 --- a/drivers/media/video/ivtv/ivtv-fb.c +++ b/drivers/media/video/ivtv/ivtv-fb.c @@ -3,7 +3,7 @@ This module presents the cx23415 OSD (onscreen display) framebuffer memory as a standard Linux /dev/fb style framebuffer device. The framebuffer has - support for 8,16 & 32 bpp packed pixel formats with alpha channel. In 16bpp + support for 8, 16 & 32 bpp packed pixel formats with alpha channel. In 16bpp mode, there is a choice of a three color depths (12, 15 or 16 bits), but no local alpha. The colorspace is selectable between rgb & yuv. Depending on the TV standard configured in the ivtv module at load time, @@ -111,7 +111,7 @@ MODULE_PARM_DESC(osd_laced, "\t\t\tdefault off"); MODULE_PARM_DESC(osd_depth, - "Bits per pixel - 8,16,32\n" + "Bits per pixel - 8, 16, 32\n" "\t\t\tdefault 8"); MODULE_PARM_DESC(osd_upper, @@ -232,12 +232,13 @@ static int ivtv_fb_get_framebuffer(struct ivtv *itv, u32 *fbbase, static int ivtv_fb_get_osd_coords(struct ivtv *itv, struct ivtv_osd_coords *osd) { + struct osd_info *oi = itv->osd_info; u32 data[CX2341X_MBOX_MAX_DATA]; ivtv_vapi_result(itv, data, CX2341X_OSD_GET_OSD_COORDS, 0); - osd->offset = data[0] - itv->osd_info->video_rbase; - osd->max_offset = itv->osd_info->display_width * itv->osd_info->display_height * 4; + osd->offset = data[0] - oi->video_rbase; + osd->max_offset = oi->display_width * oi->display_height * 4; osd->pixel_stride = data[1]; osd->lines = data[2]; osd->x = data[3]; @@ -247,20 +248,21 @@ static int ivtv_fb_get_osd_coords(struct ivtv *itv, static int ivtv_fb_set_osd_coords(struct ivtv *itv, const struct ivtv_osd_coords *osd) { - itv->osd_info->display_width = osd->pixel_stride; - itv->osd_info->display_byte_stride = osd->pixel_stride * itv->osd_info->bytes_per_pixel; - itv->osd_info->set_osd_coords_x += osd->x; - itv->osd_info->set_osd_coords_y = osd->y; + struct osd_info *oi = itv->osd_info; + + oi->display_width = osd->pixel_stride; + oi->display_byte_stride = osd->pixel_stride * oi->bytes_per_pixel; + oi->set_osd_coords_x += osd->x; + oi->set_osd_coords_y = osd->y; return ivtv_vapi(itv, CX2341X_OSD_SET_OSD_COORDS, 5, - osd->offset + itv->osd_info->video_rbase, + osd->offset + oi->video_rbase, osd->pixel_stride, osd->lines, osd->x, osd->y); } static int ivtv_fb_set_display_window(struct ivtv *itv, struct v4l2_rect *ivtv_window) { - int osd_height_limit = itv->is_50hz ? 576 : 480; /* Only fail if resolution too high, otherwise fudge the start coords. */ @@ -269,13 +271,13 @@ static int ivtv_fb_set_display_window(struct ivtv *itv, struct v4l2_rect *ivtv_w /* Ensure we don't exceed display limits */ if (ivtv_window->top + ivtv_window->height > osd_height_limit) { - IVTV_FB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid height setting (%d,%d)\n", + IVTV_FB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid height setting (%d, %d)\n", ivtv_window->top, ivtv_window->height); ivtv_window->top = osd_height_limit - ivtv_window->height; } if (ivtv_window->left + ivtv_window->width > IVTV_OSD_MAX_WIDTH) { - IVTV_FB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid width setting (%d,%d)\n", + IVTV_FB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid width setting (%d, %d)\n", ivtv_window->left, ivtv_window->width); ivtv_window->left = IVTV_OSD_MAX_WIDTH - ivtv_window->width; } @@ -344,7 +346,8 @@ static int ivtv_fb_prep_dec_dma_to_device(struct ivtv *itv, return ret; } -static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source, unsigned long dest_offset, int count) +static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source, + unsigned long dest_offset, int count) { DEFINE_WAIT(wait); @@ -356,31 +359,28 @@ static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source, un /* Check Total FB Size */ if ((dest_offset + count) > itv->osd_info->video_buffer_size) { - IVTV_FB_WARN( - "ivtv_fb_prep_frame: Overflowing the framebuffer %ld, " - "only %d available\n", - (dest_offset + count), itv->osd_info->video_buffer_size); + IVTV_FB_WARN("ivtv_fb_prep_frame: Overflowing the framebuffer %ld, only %d available\n", + dest_offset + count, itv->osd_info->video_buffer_size); return -E2BIG; } /* Not fatal, but will have undesirable results */ if ((unsigned long)source & 3) - IVTV_FB_WARN ("ivtv_fb_prep_frame: Source address not 32 bit aligned (0x%08lx)\n",(unsigned long)source); + IVTV_FB_WARN("ivtv_fb_prep_frame: Source address not 32 bit aligned (0x%08lx)\n", + (unsigned long)source); if (dest_offset & 3) - IVTV_FB_WARN ("ivtv_fb_prep_frame: Dest offset not 32 bit aligned (%ld)\n",dest_offset); + IVTV_FB_WARN("ivtv_fb_prep_frame: Dest offset not 32 bit aligned (%ld)\n", dest_offset); if (count & 3) - IVTV_FB_WARN ("ivtv_fb_prep_frame: Count not a multiple of 4 (%d)\n",count); + IVTV_FB_WARN("ivtv_fb_prep_frame: Count not a multiple of 4 (%d)\n", count); /* Check Source */ if (!access_ok(VERIFY_READ, source + dest_offset, count)) { - IVTV_FB_WARN( - "Invalid userspace pointer!!! 0x%08lx\n", + IVTV_FB_WARN("Invalid userspace pointer 0x%08lx\n", (unsigned long)source); - IVTV_FB_DEBUG_WARN( - "access_ok() failed for offset 0x%08lx source 0x%08lx count %d\n", + IVTV_FB_DEBUG_WARN("access_ok() failed for offset 0x%08lx source 0x%08lx count %d\n", dest_offset, (unsigned long)source, count); return -EINVAL; @@ -397,17 +397,16 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar { DEFINE_WAIT(wait); struct ivtv *itv = (struct ivtv *)info->par; - int rc=0; + int rc = 0; switch (cmd) { - case FBIOGET_VBLANK: { struct fb_vblank vblank; u32 trace; vblank.flags = FB_VBLANK_HAVE_COUNT |FB_VBLANK_HAVE_VCOUNT | FB_VBLANK_HAVE_VSYNC; - trace = read_reg (0x028c0) >> 16; + trace = read_reg(0x028c0) >> 16; if (itv->is_50hz && trace > 312) trace -= 312; else if (itv->is_60hz && trace > 262) trace -= 262; if (trace == 1) vblank.flags |= FB_VBLANK_VSYNCING; @@ -419,12 +418,11 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar return 0; } - case FBIO_WAITFORVSYNC: { + case FBIO_WAITFORVSYNC: prepare_to_wait(&itv->vsync_waitq, &wait, TASK_INTERRUPTIBLE); if (!schedule_timeout(HZ/20)) rc = -ETIMEDOUT; - finish_wait (&itv->vsync_waitq, &wait); + finish_wait(&itv->vsync_waitq, &wait); return rc; - } case IVTVFB_IOCTL_PREP_FRAME: { struct ivtvfb_ioctl_dma_host_to_ivtv_args args; @@ -437,7 +435,7 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar } default: - IVTV_FB_ERR("Unknown IOCTL %d\n",cmd); + IVTV_FB_ERR("Unknown IOCTL %d\n", cmd); return -EINVAL; } return 0; @@ -447,7 +445,6 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var) { - struct ivtv_osd_coords ivtv_osd; struct v4l2_rect ivtv_window; @@ -455,9 +452,9 @@ static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var) /* Select color space */ if (var->nonstd) /* YUV */ - write_reg (read_reg(0x02a00) | 0x0002000,0x02a00); + write_reg(read_reg(0x02a00) | 0x0002000, 0x02a00); else /* RGB */ - write_reg (read_reg(0x02a00) & ~0x0002000,0x02a00); + write_reg(read_reg(0x02a00) & ~0x0002000, 0x02a00); /* Set the color mode Although rare, occasionally things go wrong. The extra mode @@ -525,8 +522,8 @@ static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var) ivtv_window.height = var->yres; /* Minimum margin cannot be 0, as X won't allow such a mode */ - if (!var->upper_margin) var->upper_margin ++; - if (!var->left_margin) var->left_margin ++; + if (!var->upper_margin) var->upper_margin++; + if (!var->left_margin) var->left_margin++; ivtv_window.top = var->upper_margin - 1; ivtv_window.left = var->left_margin - 1; @@ -535,48 +532,36 @@ static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var) /* Force update of yuv registers */ itv->yuv_info.yuv_forced_update = 1; - IVTV_FB_INFO("=== Display mode change ===\n"); - IVTV_FB_INFO("Display size %dx%d (%dx%d Virtual) @ %dbpp\n", - var->xres, - var->yres, - var->xres_virtual, - var->yres_virtual, - var->bits_per_pixel); - - IVTV_FB_INFO("Display position %d,%d\n", - var->left_margin, - var->upper_margin); + IVTV_FB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n", + var->xres, var->yres, + var->xres_virtual, var->yres_virtual, + var->bits_per_pixel); - if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) { - IVTV_FB_INFO("Display filter : on\n"); - } - else { - IVTV_FB_INFO("Display filter : off\n"); - } + IVTV_FB_DEBUG_INFO("Display position: %d, %d\n", + var->left_margin, var->upper_margin); - if (var->nonstd) { - IVTV_FB_INFO("Color space : YUV\n"); - } - else { - IVTV_FB_INFO("Color space : RGB\n"); - } + IVTV_FB_DEBUG_INFO("Display filter: %s\n", + (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off"); + IVTV_FB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB"); return 0; } static int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix) { - IVTV_FB_DEBUG_INFO ("ivtvfb_get_fix\n"); + struct osd_info *oi = itv->osd_info; + + IVTV_FB_DEBUG_INFO("ivtvfb_get_fix\n"); memset(fix, 0, sizeof(struct fb_fix_screeninfo)); strcpy(fix->id, "cx23415 TV out"); - fix->smem_start = itv->osd_info->video_pbase; - fix->smem_len = itv->osd_info->video_buffer_size; + fix->smem_start = oi->video_pbase; + fix->smem_len = oi->video_buffer_size; fix->type = FB_TYPE_PACKED_PIXELS; - fix->visual = (itv->osd_info->bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; + fix->visual = (oi->bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; fix->xpanstep = 1; fix->ypanstep = 1; fix->ywrapstep = 0; - fix->line_length = itv->osd_info->display_byte_stride; + fix->line_length = oi->display_byte_stride; fix->accel = FB_ACCEL_NONE; return 0; } @@ -586,14 +571,15 @@ static int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix) static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) { + struct osd_info *oi = itv->osd_info; int osd_height_limit = itv->is_50hz ? 576 : 480; - IVTV_FB_DEBUG_INFO ("ivtvfb_check_var\n"); + IVTV_FB_DEBUG_INFO("ivtvfb_check_var\n"); /* Check the bits per pixel */ if (osd_compat) { if (var->bits_per_pixel != 32) { - IVTV_FB_DEBUG_WARN ("Invalid colour mode: %d\n",var->bits_per_pixel); + IVTV_FB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel); return -EINVAL; } } @@ -609,11 +595,12 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) var->blue.length = 8; } else if (var->bits_per_pixel == 16) { + var->transp.offset = 0; + var->transp.length = 0; + /* To find out the true mode, check green length */ switch (var->green.length) { case 4: - var->transp.offset = 0; - var->transp.length = 0; var->red.offset = 8; var->red.length = 4; var->green.offset = 4; @@ -622,8 +609,6 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) var->blue.length = 4; break; case 5: - var->transp.offset = 0; - var->transp.length = 0; var->red.offset = 10; var->red.length = 5; var->green.offset = 5; @@ -632,8 +617,6 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) var->blue.length = 5; break; default: - var->transp.offset = 0; - var->transp.length = 0; var->red.offset = 11; var->red.length = 5; var->green.offset = 5; @@ -644,33 +627,34 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) } } else { - IVTV_FB_DEBUG_WARN ("Invalid colour mode: %d\n",var->bits_per_pixel); + IVTV_FB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel); return -EINVAL; } /* Check the resolution */ if (osd_compat) { - if (var->xres != itv->osd_info->ivtvfb_defined.xres || var->yres != itv->osd_info->ivtvfb_defined.yres || - var->xres_virtual != itv->osd_info->ivtvfb_defined.xres_virtual || var->yres_virtual != - itv->osd_info->ivtvfb_defined.yres_virtual) { - IVTV_FB_DEBUG_WARN ("Invalid resolution: %d x %d (%d x %d Virtual)\n", - var->xres,var->yres, var->xres_virtual,var->yres_virtual); + if (var->xres != oi->ivtvfb_defined.xres || + var->yres != oi->ivtvfb_defined.yres || + var->xres_virtual != oi->ivtvfb_defined.xres_virtual || + var->yres_virtual != oi->ivtvfb_defined.yres_virtual) { + IVTV_FB_DEBUG_WARN("Invalid resolution: %dx%d (virtual %dx%d)\n", + var->xres, var->yres, var->xres_virtual, var->yres_virtual); return -EINVAL; } } else { - if (var->xres > IVTV_OSD_MAX_WIDTH || var->yres > osd_height_limit ) { - IVTV_FB_DEBUG_WARN ("Invalid resolution: %d x %d\n", - var->xres,var->yres); + if (var->xres > IVTV_OSD_MAX_WIDTH || var->yres > osd_height_limit) { + IVTV_FB_DEBUG_WARN("Invalid resolution: %dx%d\n", + var->xres, var->yres); return -EINVAL; } /* Max horizontal size is 1023 @ 32bpp, 2046 & 16bpp, 4092 @ 8bpp */ if (var->xres_virtual > 4095 / (var->bits_per_pixel / 8) || - var->xres_virtual * var->yres_virtual * (var->bits_per_pixel/8) > itv->osd_info->video_buffer_size || + var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8) > oi->video_buffer_size || var->xres_virtual < var->xres || var->yres_virtual < var->yres) { - IVTV_FB_DEBUG_WARN ("Invalid virtual resolution: %d x %d\n", + IVTV_FB_DEBUG_WARN("Invalid virtual resolution: %dx%d\n", var->xres_virtual, var->yres_virtual); return -EINVAL; } @@ -680,43 +664,43 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) if (var->bits_per_pixel == 8) { /* Width must be a multiple of 4 */ if (var->xres & 3) { - IVTV_FB_DEBUG_WARN ("Invalid resolution for 8bpp: %d\n", var->xres); + IVTV_FB_DEBUG_WARN("Invalid resolution for 8bpp: %d\n", var->xres); return -EINVAL; } if (var->xres_virtual & 3) { - IVTV_FB_DEBUG_WARN ("Invalid virtual resolution for 8bpp: %d)\n", var->xres_virtual); + IVTV_FB_DEBUG_WARN("Invalid virtual resolution for 8bpp: %d)\n", var->xres_virtual); return -EINVAL; } } else if (var->bits_per_pixel == 16) { /* Width must be a multiple of 2 */ if (var->xres & 1) { - IVTV_FB_DEBUG_WARN ("Invalid resolution for 16bpp: %d\n", var->xres); + IVTV_FB_DEBUG_WARN("Invalid resolution for 16bpp: %d\n", var->xres); return -EINVAL; } if (var->xres_virtual & 1) { - IVTV_FB_DEBUG_WARN ("Invalid virtual resolution for 16bpp: %d)\n", var->xres_virtual); + IVTV_FB_DEBUG_WARN("Invalid virtual resolution for 16bpp: %d)\n", var->xres_virtual); return -EINVAL; } } /* Now check the offsets */ if (var->xoffset >= var->xres_virtual || var->yoffset >= var->yres_virtual) { - IVTV_FB_DEBUG_WARN ("Invalid offset: %d (%d) %d (%d)\n",var->xoffset,var->xres_virtual, - var->yoffset,var->yres_virtual); + IVTV_FB_DEBUG_WARN("Invalid offset: %d (%d) %d (%d)\n", + var->xoffset, var->xres_virtual, var->yoffset, var->yres_virtual); return -EINVAL; } /* Check pixel format */ if (var->nonstd > 1) { - IVTV_FB_DEBUG_WARN ("Invalid nonstd % d\n",var->nonstd); + IVTV_FB_DEBUG_WARN("Invalid nonstd % d\n", var->nonstd); return -EINVAL; } /* Check video mode */ if (((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) && ((var->vmode & FB_VMODE_MASK) != FB_VMODE_INTERLACED)) { - IVTV_FB_DEBUG_WARN ("Invalid video mode: %d\n",var->vmode & FB_VMODE_MASK); + IVTV_FB_DEBUG_WARN("Invalid video mode: %d\n", var->vmode & FB_VMODE_MASK); return -EINVAL; } @@ -732,8 +716,8 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) } /* Maintain overall 'size' for a constant refresh rate */ - var->right_margin = itv->osd_info->hlimit - var->left_margin - var->xres; - var->lower_margin = itv->osd_info->vlimit - var->upper_margin - var->yres; + var->right_margin = oi->hlimit - var->left_margin - var->xres; + var->lower_margin = oi->vlimit - var->upper_margin - var->yres; /* Fixed sync times */ var->hsync_len = 24; @@ -742,45 +726,29 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) /* Non-interlaced / interlaced mode is used to switch the OSD filter on or off. Adjust the clock timings to maintain a constant vertical refresh rate. */ - var->pixclock = itv->osd_info->pixclock; + var->pixclock = oi->pixclock; if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) var->pixclock /= 2; - IVTV_FB_DEBUG_INFO ("ivtvfb_check_var - Parameters validated\n"); - - IVTV_FB_INFO("=== Validated display mode ===\n"); - IVTV_FB_INFO("Display size %dx%d (%dx%d Virtual) @ %dbpp\n", - var->xres, - var->yres, - var->xres_virtual, - var->yres_virtual, + IVTV_FB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n", + var->xres, var->yres, + var->xres_virtual, var->yres_virtual, var->bits_per_pixel); - IVTV_FB_INFO("Display position %d,%d\n", - var->left_margin, - var->upper_margin); + IVTV_FB_DEBUG_INFO("Display position: %d, %d\n", + var->left_margin, var->upper_margin); - if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) { - IVTV_FB_INFO("Display filter : on\n"); - } - else { - IVTV_FB_INFO("Display filter : off\n"); - } - - if (var->nonstd) { - IVTV_FB_INFO("Color space : YUV\n"); - } - else { - IVTV_FB_INFO("Color space : RGB\n"); - } + IVTV_FB_DEBUG_INFO("Display filter: %s\n", + (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off"); + IVTV_FB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB"); return 0; } static int ivtvfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { struct ivtv *itv = (struct ivtv *) info->par; - IVTV_FB_DEBUG_INFO ("ivtvfb_check_var\n"); - return _ivtvfb_check_var (var,itv); + IVTV_FB_DEBUG_INFO("ivtvfb_check_var\n"); + return _ivtvfb_check_var(var, itv); } static int ivtvfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) @@ -789,7 +757,7 @@ static int ivtvfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *inf struct ivtv *itv = (struct ivtv *) info->par; osd_pan_index = (var->xoffset + (var->yoffset * var->xres_virtual))*var->bits_per_pixel/8; - write_reg (osd_pan_index,0x02A0C); + write_reg(osd_pan_index, 0x02A0C); /* Pass this info back the yuv handler */ itv->yuv_info.osd_x_pan = var->xoffset; @@ -804,11 +772,11 @@ static int ivtvfb_set_par(struct fb_info *info) int rc = 0; struct ivtv *itv = (struct ivtv *) info->par; - IVTV_FB_DEBUG_INFO ("ivtvfb_set_par\n"); + IVTV_FB_DEBUG_INFO("ivtvfb_set_par\n"); rc = ivtvfb_set_var(itv, &info->var); ivtvfb_pan_display(&info->var, info); - ivtvfb_get_fix (itv, &info->fix); + ivtvfb_get_fix(itv, &info->fix); return rc; } @@ -817,7 +785,7 @@ static int ivtvfb_setcolreg(unsigned regno, unsigned red, unsigned green, struct fb_info *info) { u32 color, *palette; - struct ivtv *itv = (struct ivtv *) info->par; + struct ivtv *itv = (struct ivtv *)info->par; if (regno >= info->cmap.len) return -EINVAL; @@ -826,34 +794,32 @@ static int ivtvfb_setcolreg(unsigned regno, unsigned red, unsigned green, if (info->var.bits_per_pixel <= 8) { write_reg(regno, 0x02a30); write_reg(color, 0x02a34); + return 0; } - else { - if (regno >= 16) - return -EINVAL; + if (regno >= 16) + return -EINVAL; - palette = info->pseudo_palette; - if (info->var.bits_per_pixel == 16) { - switch (info->var.green.length) { - case 4: - color = ((red & 0xf000) >> 4) | - ((green & 0xf000) >> 8) | - ((blue & 0xf000) >> 12); - break; - case 5: - color = ((red & 0xf800) >> 1) | - ((green & 0xf800) >> 6) | - ((blue & 0xf800) >> 11); - break; - case 6: - color = (red & 0xf800 ) | - ((green & 0xfc00) >> 5) | - ((blue & 0xf800) >> 11); - break; - } + palette = info->pseudo_palette; + if (info->var.bits_per_pixel == 16) { + switch (info->var.green.length) { + case 4: + color = ((red & 0xf000) >> 4) | + ((green & 0xf000) >> 8) | + ((blue & 0xf000) >> 12); + break; + case 5: + color = ((red & 0xf800) >> 1) | + ((green & 0xf800) >> 6) | + ((blue & 0xf800) >> 11); + break; + case 6: + color = (red & 0xf800 ) | + ((green & 0xfc00) >> 5) | + ((blue & 0xf800) >> 11); + break; } - palette[regno] = color; } - + palette[regno] = color; return 0; } @@ -863,7 +829,7 @@ static int ivtvfb_blank(int blank_mode, struct fb_info *info) { struct ivtv *itv = (struct ivtv *)info->par; - IVTV_FB_DEBUG_INFO ("Set blanking mode : %d\n",blank_mode); + IVTV_FB_DEBUG_INFO("Set blanking mode : %d\n", blank_mode); switch (blank_mode) { case FB_BLANK_UNBLANK: ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 1); @@ -898,27 +864,28 @@ static struct fb_ops ivtvfb_ops = { /* Setup our initial video mode */ static int ivtvfb_init_vidmode(struct ivtv *itv) { - int max_height; + struct osd_info *oi = itv->osd_info; struct v4l2_rect start_window; + int max_height; /* Set base references for mode calcs. */ if (itv->is_50hz) { - itv->osd_info->pixclock = 84316; - itv->osd_info->hlimit = 776; - itv->osd_info->vlimit = 591; + oi->pixclock = 84316; + oi->hlimit = 776; + oi->vlimit = 591; } else { - itv->osd_info->pixclock = 83926; - itv->osd_info->hlimit = 776; - itv->osd_info->vlimit = 495; + oi->pixclock = 83926; + oi->hlimit = 776; + oi->vlimit = 495; } /* Color mode */ if (osd_compat) osd_depth = 32; if (osd_depth != 8 && osd_depth != 16 && osd_depth != 32) osd_depth = 8; - itv->osd_info->bits_per_pixel = osd_depth; - itv->osd_info->bytes_per_pixel = itv->osd_info->bits_per_pixel / 8; + oi->bits_per_pixel = osd_depth; + oi->bytes_per_pixel = oi->bits_per_pixel / 8; /* Horizontal size & position */ @@ -937,97 +904,93 @@ static int ivtvfb_init_vidmode(struct ivtv *itv) /* Check horizontal start (osd_left). */ if (osd_left && osd_left + start_window.width > 721) { - IVTV_FB_ERR ("Invalid osd_left - assuming default\n"); + IVTV_FB_ERR("Invalid osd_left - assuming default\n"); osd_left = 0; } /* Hardware coords start at 0, user coords start at 1. */ - osd_left --; + osd_left--; - start_window.left = - osd_left >= 0 ? osd_left : ((IVTV_OSD_MAX_WIDTH - start_window.width) / 2); + start_window.left = osd_left >= 0 ? osd_left : ((IVTV_OSD_MAX_WIDTH - start_window.width) / 2); - itv->osd_info->display_byte_stride = - start_window.width * itv->osd_info->bytes_per_pixel; + oi->display_byte_stride = + start_window.width * oi->bytes_per_pixel; /* Vertical size & position */ max_height = itv->is_50hz ? 576 : 480; - if ( osd_yres > max_height) osd_yres = max_height; + if (osd_yres > max_height) + osd_yres = max_height; if (osd_yres) start_window.height = osd_yres; - else { - if (itv->is_50hz) - start_window.height = osd_compat ? max_height : 480; - else - start_window.height = osd_compat ? max_height : 400; - } + else + start_window.height = osd_compat ? max_height : (itv->is_50hz ? 480 : 400); /* Check vertical start (osd_upper). */ if (osd_upper + start_window.height > max_height + 1) { - IVTV_FB_ERR ("Invalid osd_upper - assuming default\n"); + IVTV_FB_ERR("Invalid osd_upper - assuming default\n"); osd_upper = 0; } /* Hardware coords start at 0, user coords start at 1. */ - osd_upper --; + osd_upper--; start_window.top = osd_upper >= 0 ? osd_upper : ((max_height - start_window.height) / 2); - itv->osd_info->display_width = start_window.width; - itv->osd_info->display_height = start_window.height; + oi->display_width = start_window.width; + oi->display_height = start_window.height; /* Generate a valid fb_var_screeninfo */ - itv->osd_info->ivtvfb_defined.xres = itv->osd_info->display_width; - itv->osd_info->ivtvfb_defined.yres = itv->osd_info->display_height; - itv->osd_info->ivtvfb_defined.xres_virtual = itv->osd_info->display_width; - itv->osd_info->ivtvfb_defined.yres_virtual = itv->osd_info->display_height; - itv->osd_info->ivtvfb_defined.bits_per_pixel = itv->osd_info->bits_per_pixel; - itv->osd_info->ivtvfb_defined.vmode = (osd_laced ? FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED); - itv->osd_info->ivtvfb_defined.left_margin = start_window.left + 1; - itv->osd_info->ivtvfb_defined.upper_margin = start_window.top + 1; - itv->osd_info->ivtvfb_defined.accel_flags = FB_ACCEL_NONE; - itv->osd_info->ivtvfb_defined.nonstd = 0; + oi->ivtvfb_defined.xres = oi->display_width; + oi->ivtvfb_defined.yres = oi->display_height; + oi->ivtvfb_defined.xres_virtual = oi->display_width; + oi->ivtvfb_defined.yres_virtual = oi->display_height; + oi->ivtvfb_defined.bits_per_pixel = oi->bits_per_pixel; + oi->ivtvfb_defined.vmode = (osd_laced ? FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED); + oi->ivtvfb_defined.left_margin = start_window.left + 1; + oi->ivtvfb_defined.upper_margin = start_window.top + 1; + oi->ivtvfb_defined.accel_flags = FB_ACCEL_NONE; + oi->ivtvfb_defined.nonstd = 0; /* We've filled in the most data, let the usual mode check routine fill in the rest. */ - _ivtvfb_check_var (&itv->osd_info->ivtvfb_defined,itv); + _ivtvfb_check_var(&oi->ivtvfb_defined, itv); /* Generate valid fb_fix_screeninfo */ - ivtvfb_get_fix(itv,&itv->osd_info->ivtvfb_fix); + ivtvfb_get_fix(itv, &oi->ivtvfb_fix); /* Generate valid fb_info */ - itv->osd_info->ivtvfb_info.node = -1; - itv->osd_info->ivtvfb_info.flags = FBINFO_FLAG_DEFAULT; - itv->osd_info->ivtvfb_info.fbops = &ivtvfb_ops; - itv->osd_info->ivtvfb_info.par = itv; - itv->osd_info->ivtvfb_info.var = itv->osd_info->ivtvfb_defined; - itv->osd_info->ivtvfb_info.fix = itv->osd_info->ivtvfb_fix; - itv->osd_info->ivtvfb_info.screen_base = (u8 __iomem *)itv->osd_info->video_vbase; - itv->osd_info->ivtvfb_info.fbops = &ivtvfb_ops; + oi->ivtvfb_info.node = -1; + oi->ivtvfb_info.flags = FBINFO_FLAG_DEFAULT; + oi->ivtvfb_info.fbops = &ivtvfb_ops; + oi->ivtvfb_info.par = itv; + oi->ivtvfb_info.var = oi->ivtvfb_defined; + oi->ivtvfb_info.fix = oi->ivtvfb_fix; + oi->ivtvfb_info.screen_base = (u8 __iomem *)oi->video_vbase; + oi->ivtvfb_info.fbops = &ivtvfb_ops; /* Supply some monitor specs. Bogus values will do for now */ - itv->osd_info->ivtvfb_info.monspecs.hfmin = 8000; - itv->osd_info->ivtvfb_info.monspecs.hfmax = 70000; - itv->osd_info->ivtvfb_info.monspecs.vfmin = 10; - itv->osd_info->ivtvfb_info.monspecs.vfmax = 100; + oi->ivtvfb_info.monspecs.hfmin = 8000; + oi->ivtvfb_info.monspecs.hfmax = 70000; + oi->ivtvfb_info.monspecs.vfmin = 10; + oi->ivtvfb_info.monspecs.vfmax = 100; /* Allocate color map */ - if (fb_alloc_cmap(&itv->osd_info->ivtvfb_info.cmap, 256, 1)) { - IVTV_FB_ERR ("abort, unable to alloc cmap\n"); + if (fb_alloc_cmap(&oi->ivtvfb_info.cmap, 256, 1)) { + IVTV_FB_ERR("abort, unable to alloc cmap\n"); return -ENOMEM; } /* Allocate the pseudo palette */ - itv->osd_info->ivtvfb_info.pseudo_palette = kmalloc(sizeof (u32) * 16, GFP_KERNEL); + oi->ivtvfb_info.pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL); - if (!itv->osd_info->ivtvfb_info.pseudo_palette) { - IVTV_FB_ERR ("abort, unable to alloc pseudo pallete\n"); + if (!oi->ivtvfb_info.pseudo_palette) { + IVTV_FB_ERR("abort, unable to alloc pseudo pallete\n"); return -ENOMEM; } @@ -1038,51 +1001,53 @@ static int ivtvfb_init_vidmode(struct ivtv *itv) static int ivtvfb_init_io(struct ivtv *itv) { - ivtv_fb_get_framebuffer(itv, &itv->osd_info->video_rbase, &itv->osd_info->video_buffer_size); + struct osd_info *oi = itv->osd_info; + + ivtv_fb_get_framebuffer(itv, &oi->video_rbase, &oi->video_buffer_size); /* The osd buffer size depends on the number of video buffers allocated on the PVR350 itself. For now we'll hardcode the smallest osd buffer size to prevent any overlap. */ - itv->osd_info->video_buffer_size = 1704960; + oi->video_buffer_size = 1704960; - itv->osd_info->video_pbase = itv->base_addr + IVTV_DECODER_OFFSET + itv->osd_info->video_rbase; - itv->osd_info->video_vbase = itv->dec_mem + itv->osd_info->video_rbase; + oi->video_pbase = itv->base_addr + IVTV_DECODER_OFFSET + oi->video_rbase; + oi->video_vbase = itv->dec_mem + oi->video_rbase; - if (!itv->osd_info->video_vbase) { + if (!oi->video_vbase) { IVTV_FB_ERR("abort, video memory 0x%x @ 0x%lx isn't mapped!\n", - itv->osd_info->video_buffer_size, itv->osd_info->video_pbase); + oi->video_buffer_size, oi->video_pbase); return -EIO; } IVTV_FB_INFO("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n", - itv->osd_info->video_pbase, itv->osd_info->video_vbase, - itv->osd_info->video_buffer_size / 1024); + oi->video_pbase, oi->video_vbase, + oi->video_buffer_size / 1024); #ifdef CONFIG_MTRR { /* Find the largest power of two that maps the whole buffer */ int size_shift = 31; - while (!(itv->osd_info->video_buffer_size & (1 << size_shift))) { + while (!(oi->video_buffer_size & (1 << size_shift))) { size_shift--; } size_shift++; - itv->osd_info->fb_start_aligned_physaddr = itv->osd_info->video_pbase & ~((1 << size_shift) - 1); - itv->osd_info->fb_end_aligned_physaddr = itv->osd_info->video_pbase + itv->osd_info->video_buffer_size; - itv->osd_info->fb_end_aligned_physaddr += (1 << size_shift) - 1; - itv->osd_info->fb_end_aligned_physaddr &= ~((1 << size_shift) - 1); - if (mtrr_add(itv->osd_info->fb_start_aligned_physaddr, - itv->osd_info->fb_end_aligned_physaddr - itv->osd_info->fb_start_aligned_physaddr, + oi->fb_start_aligned_physaddr = oi->video_pbase & ~((1 << size_shift) - 1); + oi->fb_end_aligned_physaddr = oi->video_pbase + oi->video_buffer_size; + oi->fb_end_aligned_physaddr += (1 << size_shift) - 1; + oi->fb_end_aligned_physaddr &= ~((1 << size_shift) - 1); + if (mtrr_add(oi->fb_start_aligned_physaddr, + oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr, MTRR_TYPE_WRCOMB, 1) < 0) { - IVTV_FB_ERR("warning: mtrr_add() failed to add write combining region 0x%08x-0x%08x\n", - (unsigned int)itv->osd_info->fb_start_aligned_physaddr, - (unsigned int)itv->osd_info->fb_end_aligned_physaddr); + IVTV_FB_WARN("cannot use mttr\n"); + oi->fb_start_aligned_physaddr = 0; + oi->fb_end_aligned_physaddr = 0; } } -#endif /* CONFIG_MTRR */ +#endif /* Blank the entire osd. */ - memset_io(itv->osd_info->video_vbase, 0, itv->osd_info->video_buffer_size); + memset_io(oi->video_vbase, 0, oi->video_buffer_size); return 0; } @@ -1090,26 +1055,30 @@ static int ivtvfb_init_io(struct ivtv *itv) /* Release any memory we've grabbed & remove mtrr entry */ static void ivtvfb_release_buffers (struct ivtv *itv) { + struct osd_info *oi = itv->osd_info; + /* Release cmap */ - if (itv->osd_info->ivtvfb_info.cmap.len); - fb_dealloc_cmap(&itv->osd_info->ivtvfb_info.cmap); + if (oi->ivtvfb_info.cmap.len); + fb_dealloc_cmap(&oi->ivtvfb_info.cmap); /* Release pseudo palette */ - if (itv->osd_info->ivtvfb_info.pseudo_palette) - kfree(itv->osd_info->ivtvfb_info.pseudo_palette); + if (oi->ivtvfb_info.pseudo_palette) + kfree(oi->ivtvfb_info.pseudo_palette); #ifdef CONFIG_MTRR - mtrr_del(-1, itv->osd_info->fb_start_aligned_physaddr, - (itv->osd_info->fb_end_aligned_physaddr - itv->osd_info->fb_start_aligned_physaddr)); -#endif /* CONFIG_MTRR */ + if (oi->fb_end_aligned_physaddr) { + mtrr_del(-1, oi->fb_start_aligned_physaddr, + oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr); + } +#endif - kfree(itv->osd_info); + kfree(oi); itv->osd_info = NULL; } /* Initialize the specified card */ -static int ivtvfb_init_card (struct ivtv *itv) +static int ivtvfb_init_card(struct ivtv *itv) { int rc; @@ -1125,11 +1094,11 @@ static int ivtvfb_init_card (struct ivtv *itv) } /* Find & setup the OSD buffer */ - if ((rc = ivtvfb_init_io (itv))) + if ((rc = ivtvfb_init_io(itv))) return rc; /* Set the startup video mode information */ - if ((rc = ivtvfb_init_vidmode (itv))) { + if ((rc = ivtvfb_init_vidmode(itv))) { ivtvfb_release_buffers(itv); return rc; } -- cgit v1.2.3-70-g09d2 From d715e766ddf4786a06abe6a841e956ad8a875963 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 20 Jul 2007 10:30:32 -0300 Subject: V4L/DVB (5905): ivtv-fb: Use proper ioctl value Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-fb.c | 6 +++--- include/media/ivtv-fb.h | 5 ++--- 2 files changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c index 01cd65328e8..55265bd5c25 100644 --- a/drivers/media/video/ivtv/ivtv-fb.c +++ b/drivers/media/video/ivtv/ivtv-fb.c @@ -424,10 +424,10 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar finish_wait(&itv->vsync_waitq, &wait); return rc; - case IVTVFB_IOCTL_PREP_FRAME: { - struct ivtvfb_ioctl_dma_host_to_ivtv_args args; + case IVTVFB_IOC_DMA_FRAME: { + struct ivtvfb_dma_frame args; - IVTV_FB_DEBUG_INFO("IVTVFB_IOCTL_PREP_FRAME\n"); + IVTV_FB_DEBUG_INFO("IVTVFB_IOC_DMA_FRAME\n"); if (copy_from_user(&args, (void __user *)arg, sizeof(args))) return -EFAULT; diff --git a/include/media/ivtv-fb.h b/include/media/ivtv-fb.h index 902b2f3d3cb..3b746f5e3c9 100644 --- a/include/media/ivtv-fb.h +++ b/include/media/ivtv-fb.h @@ -23,13 +23,12 @@ /* Framebuffer external API */ -struct ivtvfb_ioctl_dma_host_to_ivtv_args { +struct ivtvfb_dma_frame { void __user *source; unsigned long dest_offset; int count; }; -/* Framebuffer ioctls should use the range 1 - 28 */ -#define IVTVFB_IOCTL_PREP_FRAME _IOW('@', 3, struct ivtvfb_ioctl_dma_host_to_ivtv_args) +#define IVTVFB_IOC_DMA_FRAME _IOW ('V', BASE_VIDIOC_PRIVATE+0, struct ivtvfb_dma_frame) #endif -- cgit v1.2.3-70-g09d2 From 84149a0f70a73385ee7fbb77024544cbed4fe16d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 20 Jul 2007 18:17:18 -0300 Subject: V4L/DVB (5906): ivtv-fb: replace HZ with msecs_to_jiffies Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-fb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c index 55265bd5c25..6f5da57299a 100644 --- a/drivers/media/video/ivtv/ivtv-fb.c +++ b/drivers/media/video/ivtv/ivtv-fb.c @@ -420,7 +420,7 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar case FBIO_WAITFORVSYNC: prepare_to_wait(&itv->vsync_waitq, &wait, TASK_INTERRUPTIBLE); - if (!schedule_timeout(HZ/20)) rc = -ETIMEDOUT; + if (!schedule_timeout(msecs_to_jiffies(50))) rc = -ETIMEDOUT; finish_wait(&itv->vsync_waitq, &wait); return rc; -- cgit v1.2.3-70-g09d2 From aaf9fa21b684509973dd593e30423fc0a6a5e7a3 Mon Sep 17 00:00:00 2001 From: Ian Armstrong Date: Sat, 21 Jul 2007 16:43:36 -0300 Subject: V4L/DVB (5908): ivtv-fb: cleanups, prevent fw calls in some cases Signed-off-by: Ian Armstrong Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-fb.c | 48 +++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c index 6f5da57299a..56ce5c08bbb 100644 --- a/drivers/media/video/ivtv/ivtv-fb.c +++ b/drivers/media/video/ivtv/ivtv-fb.c @@ -185,6 +185,9 @@ struct osd_info { unsigned long fb_end_aligned_physaddr; #endif + /* Current osd mode */ + int osd_mode; + /* Store the buffer offset */ int set_osd_coords_x; int set_osd_coords_y; @@ -350,6 +353,7 @@ static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source, unsigned long dest_offset, int count) { DEFINE_WAIT(wait); + struct osd_info *oi = itv->osd_info; /* Nothing to do */ if (count == 0) { @@ -358,9 +362,9 @@ static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source, } /* Check Total FB Size */ - if ((dest_offset + count) > itv->osd_info->video_buffer_size) { + if ((dest_offset + count) > oi->video_buffer_size) { IVTV_FB_WARN("ivtv_fb_prep_frame: Overflowing the framebuffer %ld, only %d available\n", - dest_offset + count, itv->osd_info->video_buffer_size); + dest_offset + count, oi->video_buffer_size); return -E2BIG; } @@ -387,7 +391,7 @@ static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source, } /* OSD Address to send DMA to */ - dest_offset += IVTV_DEC_MEM_START + itv->osd_info->video_rbase; + dest_offset += IVTV_DEC_MEM_START + oi->video_rbase; /* Fill Buffers */ return ivtv_fb_prep_dec_dma_to_device(itv, dest_offset, source, count); @@ -445,8 +449,10 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var) { + struct osd_info *oi = itv->osd_info; struct ivtv_osd_coords ivtv_osd; struct v4l2_rect ivtv_window; + int osd_mode = -1; IVTV_FB_DEBUG_INFO("ivtvfb_set_var\n"); @@ -456,32 +462,24 @@ static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var) else /* RGB */ write_reg(read_reg(0x02a00) & ~0x0002000, 0x02a00); - /* Set the color mode - Although rare, occasionally things go wrong. The extra mode - change seems to help... */ - + /* Set the color mode */ switch (var->bits_per_pixel) { case 8: - ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0); - ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_8); + osd_mode = IVTV_OSD_BPP_8; break; case 32: - ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0); - ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_32); + osd_mode = IVTV_OSD_BPP_32; break; case 16: switch (var->green.length) { case 4: - ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0); - ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_16_444); + osd_mode = IVTV_OSD_BPP_16_444; break; case 5: - ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0); - ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_16_555); + osd_mode = IVTV_OSD_BPP_16_555; break; case 6: - ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0); - ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_16_565); + osd_mode = IVTV_OSD_BPP_16_565; break; default: IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n"); @@ -491,8 +489,17 @@ static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var) IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n"); } - itv->osd_info->bits_per_pixel = var->bits_per_pixel; - itv->osd_info->bytes_per_pixel = var->bits_per_pixel / 8; + /* Change osd mode if needed. + Although rare, things can go wrong. The extra mode + change seems to help... */ + if (osd_mode != -1 && osd_mode != oi->osd_mode) { + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0); + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, osd_mode); + oi->osd_mode = osd_mode; + } + + oi->bits_per_pixel = var->bits_per_pixel; + oi->bytes_per_pixel = var->bits_per_pixel / 8; /* Set the flicker filter */ switch (var->vmode & FB_VMODE_MASK) { @@ -887,6 +894,9 @@ static int ivtvfb_init_vidmode(struct ivtv *itv) oi->bits_per_pixel = osd_depth; oi->bytes_per_pixel = oi->bits_per_pixel / 8; + /* Invalidate current osd mode to force a mode switch later */ + oi->osd_mode = -1; + /* Horizontal size & position */ if (osd_xres > 720) osd_xres = 720; -- cgit v1.2.3-70-g09d2 From f38a7982ad4c38dc592f7f0ac8ee155a2df19fb5 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 22 Jul 2007 08:39:43 -0300 Subject: V4L/DVB (5909): ivtv: update version to 1.1 to mark ivtv-fb support Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-version.h b/drivers/media/video/ivtv/ivtv-version.h index 85530a3cd36..122d5610596 100644 --- a/drivers/media/video/ivtv/ivtv-version.h +++ b/drivers/media/video/ivtv/ivtv-version.h @@ -19,7 +19,7 @@ #define IVTV_DRIVER_NAME "ivtv" #define IVTV_DRIVER_VERSION_MAJOR 1 -#define IVTV_DRIVER_VERSION_MINOR 0 +#define IVTV_DRIVER_VERSION_MINOR 1 #define IVTV_DRIVER_VERSION_PATCHLEVEL 0 #define IVTV_VERSION __stringify(IVTV_DRIVER_VERSION_MAJOR) "." __stringify(IVTV_DRIVER_VERSION_MINOR) "." __stringify(IVTV_DRIVER_VERSION_PATCHLEVEL) -- cgit v1.2.3-70-g09d2 From c6f95d16e0da4d909afc787a3a3dfc504be12177 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 22 Jul 2007 15:44:41 -0300 Subject: V4L/DVB (5910): ivtv-fb: improve debug message Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-fb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c index 56ce5c08bbb..b8ad249a0b1 100644 --- a/drivers/media/video/ivtv/ivtv-fb.c +++ b/drivers/media/video/ivtv/ivtv-fb.c @@ -439,7 +439,7 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar } default: - IVTV_FB_ERR("Unknown IOCTL %d\n", cmd); + IVTV_FB_DEBUG_INFO("Unknown ioctl %08x\n", cmd); return -EINVAL; } return 0; -- cgit v1.2.3-70-g09d2 From 915366da0c591f60cb670d89b5ff376f2ef9d8fe Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Mon, 23 Jul 2007 11:33:26 -0300 Subject: V4L/DVB (5912): Clean up duplicate includes in drivers/media/ This patch cleans up duplicate includes in drivers/media/ Signed-off-by: Jesper Juhl Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/arv.c | 1 - drivers/media/video/cx88/cx88-mpeg.c | 1 - drivers/media/video/cx88/cx88-video.c | 1 - 3 files changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/arv.c b/drivers/media/video/arv.c index 649f52f9ad2..2666d3b7663 100644 --- a/drivers/media/video/arv.c +++ b/drivers/media/video/arv.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index da7a6b591a6..c34158d9dcc 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include "cx88.h" diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index 06b233a7b20..41b5cb63fd2 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -36,7 +36,6 @@ #include #include #include -#include #include #include "cx88.h" -- cgit v1.2.3-70-g09d2 From 54d75ebaa02809f24a16624e32706af3bf97588e Mon Sep 17 00:00:00 2001 From: Olivier DANET Date: Wed, 25 Jul 2007 14:42:54 -0300 Subject: V4L/DVB (5914): Add initial support for Dual-DVB-T stick Add initial support for Dual-DVB-T stick based on DiB7700 and MT2266 - Microtune MT2266 driver. - Preliminary support for these dual tuner devices : - Pinnacle Dual DVB-T diversity - Terratec Cinergy DT USB XS diversity - Hauppauge Nova TD USB Signed-off-by: Olivier DANET Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/Kconfig | 1 + drivers/media/dvb/dvb-usb/dib0700.h | 4 +- drivers/media/dvb/dvb-usb/dib0700_core.c | 2 +- drivers/media/dvb/dvb-usb/dib0700_devices.c | 262 +++++++++++++++++++++++++ drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 5 +- drivers/media/dvb/frontends/Kconfig | 7 + drivers/media/dvb/frontends/Makefile | 1 + drivers/media/dvb/frontends/dib7000p.c | 5 + drivers/media/dvb/frontends/dib7000p.h | 2 +- drivers/media/dvb/frontends/mt2266.c | 288 ++++++++++++++++++++++++++++ drivers/media/dvb/frontends/mt2266.h | 37 ++++ 11 files changed, 609 insertions(+), 5 deletions(-) create mode 100644 drivers/media/dvb/frontends/mt2266.c create mode 100644 drivers/media/dvb/frontends/mt2266.h (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 40e41f2f5af..dec03ee32e1 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -74,6 +74,7 @@ config DVB_USB_DIB0700 select DVB_DIB7000M select DVB_DIB3000MC select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE + select DVB_TUNER_MT2266 if !DVB_FE_CUSTOMISE help Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The USB bridge is also present in devices having the DiB7700 DVB-T-USB diff --git a/drivers/media/dvb/dvb-usb/dib0700.h b/drivers/media/dvb/dvb-usb/dib0700.h index cda3adea24f..74ae6c24087 100644 --- a/drivers/media/dvb/dvb-usb/dib0700.h +++ b/drivers/media/dvb/dvb-usb/dib0700.h @@ -35,12 +35,13 @@ extern int dvb_usb_dib0700_debug; struct dib0700_state { u8 channel_state; u16 mt2060_if1[2]; - + u8 rc_toggle; u8 is_dib7000pc; }; extern int dib0700_set_gpio(struct dvb_usb_device *, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val); extern int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3); +extern int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen); extern int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw); extern int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff); extern struct i2c_algorithm dib0700_i2c_algo; @@ -50,5 +51,4 @@ extern int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device extern int dib0700_device_count; extern struct dvb_usb_device_properties dib0700_devices[]; extern struct usb_device_id dib0700_usb_id_table[]; - #endif diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c index dddf164f269..8a1ea114deb 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_core.c +++ b/drivers/media/dvb/dvb-usb/dib0700_core.c @@ -32,7 +32,7 @@ static int dib0700_ctrl_wr(struct dvb_usb_device *d, u8 *tx, u8 txlen) } /* expecting tx buffer: request data[0] ... data[n] (n <= 4) */ -static int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen) +int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen) { u16 index, value; int status; diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 2208757d901..122d9d4b4ba 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -12,6 +12,7 @@ #include "dib7000m.h" #include "dib7000p.h" #include "mt2060.h" +#include "mt2266.h" static int force_lna_activation; module_param(force_lna_activation, int, 0644); @@ -96,6 +97,228 @@ static int bristol_tuner_attach(struct dvb_usb_adapter *adap) st->mt2060_if1[adap->id]) == NULL ? -ENODEV : 0; } +/* STK7700D: Pinnacle Dual DVB-T Diversity */ + +static struct dibx000_agc_config stk7700d_7000p_mt2266_agc_config = { + BAND_UHF/* | BAND_VHF*/, + 0xE64, // setup + 2372, // inv_gain + 21, // time_stabiliz + + 0, // alpha_level + 118, // thlock + + 0, // wbd_inv + 0, // wbd_ref + 0, // wbd_sel + 0, // wbd_alpha + + 65535, // agc1_max + 0, // agc1_min + 65535, // agc2_max + 23592, // agc2_min + 0, // agc1_pt1 + 128, // agc1_pt2 + 128, // agc1_pt3 + 128, // agc1_slope1 + 0, // agc1_slope2 + 128, // agc2_pt1 + 253, // agc2_pt2 + 81, // agc2_slope1 + 0, // agc2_slope2 + + 17, // alpha_mant + 27, // alpha_exp + + 23, // beta_mant + 51, // beta_exp + + 0, // perform_agc_softsplit : 1 en vrai! +}; + +static struct dibx000_bandwidth_config stk7700d_mt2266_pll_config = { + 60000, 30000, // internal, sampling + 1, 8, 3, 1, 0, // pll_cfg: prediv, ratio, range, reset, bypass + 0, 0, 1, 1, 2, // misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc, modulo + (3 << 14) | (1 << 12) | (524 << 0), // sad_cfg: refsel, sel, freq_15k + 0, // ifreq + 20452225, // timf +}; + +static struct dib7000p_config stk7700d_dib7000p_mt2266_config[] = { + { .output_mpeg2_in_188_bytes = 1, + .hostbus_diversity = 1, + .tuner_is_baseband = 1, + + .agc = &stk7700d_7000p_mt2266_agc_config, + .bw = &stk7700d_mt2266_pll_config, + + .gpio_dir = DIB7000M_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000M_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000M_GPIO_DEFAULT_PWM_POS, + }, + { .output_mpeg2_in_188_bytes = 1, + .hostbus_diversity = 1, + .tuner_is_baseband = 1, + + .agc = &stk7700d_7000p_mt2266_agc_config, + .bw = &stk7700d_mt2266_pll_config, + + .gpio_dir = DIB7000M_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000M_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000M_GPIO_DEFAULT_PWM_POS, + } +}; + +static struct mt2266_config stk7700d_mt2266_config[2] = { + { .i2c_address = 0x60 + }, + { .i2c_address = 0x60 + } +}; + +static int stk7700d_frontend_attach(struct dvb_usb_adapter *adap) +{ + if (adap->id == 0) { + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + dib7000p_i2c_enumeration(&adap->dev->i2c_adap,2,18,stk7700d_dib7000p_mt2266_config); + } + + adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,0x80+(adap->id << 1), + &stk7700d_dib7000p_mt2266_config[adap->id]); + + return adap->fe == NULL ? -ENODEV : 0; +} + +static int stk7700d_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct i2c_adapter *tun_i2c; + tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); + return dvb_attach(mt2266_attach, adap->fe, tun_i2c, + &stk7700d_mt2266_config[adap->id]) == NULL ? -ENODEV : 0;; +} + +#define DEFAULT_RC_INTERVAL 150 + +static u8 rc_request[] = { REQUEST_POLL_RC, 0 }; + +int stk7700d_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +{ + u8 key[4]; + int i; + struct dvb_usb_rc_key *keymap = d->props.rc_key_map; + struct dib0700_state *st = d->priv; + *event = 0; + *state = REMOTE_NO_KEY_PRESSED; + i=dib0700_ctrl_rd(d,rc_request,2,key,4); + if (i<=0) { + err("stk7700d:RC Query Failed\n"); + return 0; + } + if (key[0]==0 && key[1]==0 && key[2]==0 && key[3]==0) return 0; + if (key[1]!=st->rc_toggle) { + for (i=0;iprops.rc_key_map_size; i++) { + if (keymap[i].custom == key[2] && keymap[i].data == key[3]) { + *event = keymap[i].event; + *state = REMOTE_KEY_PRESSED; + st->rc_toggle=key[1]; + return 0; + } + } + err("stk7700d:Unknown remote controller key : %2X %2X\n",(int)key[2],(int)key[3]); + } + return 0; +} + +#define KEY_MAP_SIZE (25+48) + +struct dvb_usb_rc_key stk7700d_rc_keys[] = { + /* Key codes for the tiny Pinnacle remote*/ + { 0x07, 0x00, KEY_MUTE }, + { 0x07, 0x01, KEY_MENU }, // Pinnacle logo + { 0x07, 0x39, KEY_POWER }, + { 0x07, 0x03, KEY_VOLUMEUP }, + { 0x07, 0x09, KEY_VOLUMEDOWN }, + { 0x07, 0x06, KEY_CHANNELUP }, + { 0x07, 0x0c, KEY_CHANNELDOWN }, + { 0x07, 0x0f, KEY_1 }, + { 0x07, 0x15, KEY_2 }, + { 0x07, 0x10, KEY_3 }, + { 0x07, 0x18, KEY_4 }, + { 0x07, 0x1b, KEY_5 }, + { 0x07, 0x1e, KEY_6 }, + { 0x07, 0x11, KEY_7 }, + { 0x07, 0x21, KEY_8 }, + { 0x07, 0x12, KEY_9 }, + { 0x07, 0x27, KEY_0 }, + { 0x07, 0x24, KEY_SCREEN }, // 'Square' key + { 0x07, 0x2a, KEY_TEXT }, // 'T' key + { 0x07, 0x2d, KEY_REWIND }, + { 0x07, 0x30, KEY_PLAY }, + { 0x07, 0x33, KEY_FASTFORWARD }, + { 0x07, 0x36, KEY_RECORD }, + { 0x07, 0x3c, KEY_STOP }, + { 0x07, 0x3f, KEY_CANCEL }, // '?' key + /* Key codes for the Terratec Cinergy DT XS Diversity, similar to cinergyT2.c */ + { 0xeb, 0x01, KEY_POWER }, + { 0xeb, 0x02, KEY_1 }, + { 0xeb, 0x03, KEY_2 }, + { 0xeb, 0x04, KEY_3 }, + { 0xeb, 0x05, KEY_4 }, + { 0xeb, 0x06, KEY_5 }, + { 0xeb, 0x07, KEY_6 }, + { 0xeb, 0x08, KEY_7 }, + { 0xeb, 0x09, KEY_8 }, + { 0xeb, 0x0a, KEY_9 }, + { 0xeb, 0x0b, KEY_VIDEO }, + { 0xeb, 0x0c, KEY_0 }, + { 0xeb, 0x0d, KEY_REFRESH }, + { 0xeb, 0x0f, KEY_EPG }, + { 0xeb, 0x10, KEY_UP }, + { 0xeb, 0x11, KEY_LEFT }, + { 0xeb, 0x12, KEY_OK }, + { 0xeb, 0x13, KEY_RIGHT }, + { 0xeb, 0x14, KEY_DOWN }, + { 0xeb, 0x16, KEY_INFO }, + { 0xeb, 0x17, KEY_RED }, + { 0xeb, 0x18, KEY_GREEN }, + { 0xeb, 0x19, KEY_YELLOW }, + { 0xeb, 0x1a, KEY_BLUE }, + { 0xeb, 0x1b, KEY_CHANNELUP }, + { 0xeb, 0x1c, KEY_VOLUMEUP }, + { 0xeb, 0x1d, KEY_MUTE }, + { 0xeb, 0x1e, KEY_VOLUMEDOWN }, + { 0xeb, 0x1f, KEY_CHANNELDOWN }, + { 0xeb, 0x40, KEY_PAUSE }, + { 0xeb, 0x41, KEY_HOME }, + { 0xeb, 0x42, KEY_MENU }, /* DVD Menu */ + { 0xeb, 0x43, KEY_SUBTITLE }, + { 0xeb, 0x44, KEY_TEXT }, /* Teletext */ + { 0xeb, 0x45, KEY_DELETE }, + { 0xeb, 0x46, KEY_TV }, + { 0xeb, 0x47, KEY_DVD }, + { 0xeb, 0x48, KEY_STOP }, + { 0xeb, 0x49, KEY_VIDEO }, + { 0xeb, 0x4a, KEY_AUDIO }, /* Music */ + { 0xeb, 0x4b, KEY_SCREEN }, /* Pic */ + { 0xeb, 0x4c, KEY_PLAY }, + { 0xeb, 0x4d, KEY_BACK }, + { 0xeb, 0x4e, KEY_REWIND }, + { 0xeb, 0x4f, KEY_FASTFORWARD }, + { 0xeb, 0x54, KEY_PREVIOUS }, + { 0xeb, 0x58, KEY_RECORD }, + { 0xeb, 0x5c, KEY_NEXT } + }; + /* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */ static struct dibx000_agc_config stk7700p_7000m_mt2060_agc_config = { BAND_UHF | BAND_VHF, // band_caps @@ -280,6 +503,9 @@ struct usb_device_id dib0700_usb_id_table[] = { { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_STK7700P) }, { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_2) }, { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_2) }, + { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV2000E) }, + { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY) }, + { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); @@ -372,6 +598,42 @@ struct dvb_usb_device_properties dib0700_devices[] = { { NULL }, }, } + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 2, + .adapter = { + { + .frontend_attach = stk7700d_frontend_attach, + .tuner_attach = stk7700d_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + }, { + .frontend_attach = stk7700d_frontend_attach, + .tuner_attach = stk7700d_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x03), + } + }, + + .num_device_descs = 3, + .devices = { + { "Pinnacle PCTV 2000e", + { &dib0700_usb_id_table[11], NULL }, + { NULL }, + }, + { "Terratec Cinergy DT XS Diversity", + { &dib0700_usb_id_table[12], NULL }, + { NULL }, + }, + { "Haupauge Nova-TD Stick", + { &dib0700_usb_id_table[13], NULL }, + { NULL }, + }, + }, + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_key_map = stk7700d_rc_keys, + .rc_key_map_size = KEY_MAP_SIZE, + .rc_query = stk7700d_rc_query } }; diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 78ea3b566ff..2e38be3aa45 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -12,7 +12,7 @@ /* Vendor IDs */ #define USB_VID_ADSTECH 0x06e1 #define USB_VID_AFATECH 0x15a4 -#define USB_VID_ALCOR_MICRO 0x058f +#define USB_VID_ALCOR_MICRO 0x058f #define USB_VID_ALINK 0x05e3 #define USB_VID_ANCHOR 0x0547 #define USB_VID_ANUBIS_ELECTRONIC 0x10fd @@ -116,8 +116,11 @@ #define USB_PID_HAUPPAUGE_NOVA_T_500_2 0x9950 #define USB_PID_HAUPPAUGE_NOVA_T_STICK 0x7050 #define USB_PID_HAUPPAUGE_NOVA_T_STICK_2 0x7060 +#define USB_PID_HAUPPAUGE_NOVA_TD_STICK 0x9580 #define USB_PID_AVERMEDIA_VOLAR 0xa807 #define USB_PID_AVERMEDIA_VOLAR_2 0xb808 +#define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a +#define USB_PID_PINNACLE_PCTV2000E 0x022c #define USB_PID_NEBULA_DIGITV 0x0201 #define USB_PID_DVICO_BLUEBIRD_LGDT 0xd820 #define USB_PID_DVICO_BLUEBIRD_LG064F_COLD 0xd500 diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index ff448761dce..ba70ad0c3f0 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -322,6 +322,13 @@ config DVB_TUNER_MT2060 help A driver for the silicon IF tuner MT2060 from Microtune. +config DVB_TUNER_MT2266 + tristate "Microtune MT2266 silicon tuner" + depends on I2C + default m if DVB_FE_CUSTOMISE + help + A driver for the silicon baseband tuner MT2266 from Microtune. + comment "Miscellaneous devices" depends on DVB_CORE diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 156b062e02c..217265ca284 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -40,5 +40,6 @@ obj-$(CONFIG_DVB_TDA10086) += tda10086.o obj-$(CONFIG_DVB_TDA826X) += tda826x.o obj-$(CONFIG_DVB_TDA827X) += tda827x.o obj-$(CONFIG_DVB_TUNER_MT2060) += mt2060.o +obj-$(CONFIG_DVB_TUNER_MT2266) += mt2266.o obj-$(CONFIG_DVB_TUNER_QT1010) += qt1010.o obj-$(CONFIG_DVB_TUA6100) += tua6100.o diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c index aece458cfe1..c24189fcbc8 100644 --- a/drivers/media/dvb/frontends/dib7000p.c +++ b/drivers/media/dvb/frontends/dib7000p.c @@ -112,6 +112,11 @@ static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode) break; } + if (state->cfg.hostbus_diversity) { + ret |= dib7000p_write_word(state, 204, 1); // Diversity ? + ret |= dib7000p_write_word(state, 205, 0); // Diversity ? + } + if (state->cfg.output_mpeg2_in_188_bytes) smo_mode |= (1 << 5) ; diff --git a/drivers/media/dvb/frontends/dib7000p.h b/drivers/media/dvb/frontends/dib7000p.h index 79465cf1ace..94829c1ed05 100644 --- a/drivers/media/dvb/frontends/dib7000p.h +++ b/drivers/media/dvb/frontends/dib7000p.h @@ -35,7 +35,7 @@ struct dib7000p_config { extern struct dvb_frontend * dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg); extern struct i2c_adapter * dib7000p_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int); extern int dib7000pc_detection(struct i2c_adapter *i2c_adap); - +extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[]); /* TODO extern INT dib7000p_set_gpio(struct dibDemod *demod, UCHAR num, UCHAR dir, UCHAR val); extern INT dib7000p_enable_vbg_voltage(struct dibDemod *demod); diff --git a/drivers/media/dvb/frontends/mt2266.c b/drivers/media/dvb/frontends/mt2266.c new file mode 100644 index 00000000000..145135778bc --- /dev/null +++ b/drivers/media/dvb/frontends/mt2266.c @@ -0,0 +1,288 @@ +/* + * Driver for Microtune MT2266 "Direct conversion low power broadband tuner" + * + * Copyright (c) 2007 Olivier DANET + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "mt2266.h" + +#define I2C_ADDRESS 0x60 + +#define REG_PART_REV 0 +#define REG_TUNE 1 +#define REG_BAND 6 +#define REG_BANDWIDTH 8 +#define REG_LOCK 0x12 + +#define PART_REV 0x85 + +struct mt2266_priv { + struct mt2266_config *cfg; + struct i2c_adapter *i2c; + + u32 frequency; + u32 bandwidth; +}; + +/* Here, frequencies are expressed in kiloHertz to avoid 32 bits overflows */ + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); + +#define dprintk(args...) do { if (debug) {printk(KERN_DEBUG "MT2266: " args); printk("\n"); }} while (0) + +// Reads a single register +static int mt2266_readreg(struct mt2266_priv *priv, u8 reg, u8 *val) +{ + struct i2c_msg msg[2] = { + { .addr = priv->cfg->i2c_address, .flags = 0, .buf = ®, .len = 1 }, + { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, .buf = val, .len = 1 }, + }; + if (i2c_transfer(priv->i2c, msg, 2) != 2) { + printk(KERN_WARNING "MT2266 I2C read failed\n"); + return -EREMOTEIO; + } + return 0; +} + +// Writes a single register +static int mt2266_writereg(struct mt2266_priv *priv, u8 reg, u8 val) +{ + u8 buf[2] = { reg, val }; + struct i2c_msg msg = { + .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 2 + }; + if (i2c_transfer(priv->i2c, &msg, 1) != 1) { + printk(KERN_WARNING "MT2266 I2C write failed\n"); + return -EREMOTEIO; + } + return 0; +} + +// Writes a set of consecutive registers +static int mt2266_writeregs(struct mt2266_priv *priv,u8 *buf, u8 len) +{ + struct i2c_msg msg = { + .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = len + }; + if (i2c_transfer(priv->i2c, &msg, 1) != 1) { + printk(KERN_WARNING "MT2266 I2C write failed (len=%i)\n",(int)len); + return -EREMOTEIO; + } + return 0; +} + +// Initialisation sequences +static u8 mt2266_init1[] = { + REG_TUNE, + 0x00, 0x00, 0x28, 0x00, 0x52, 0x99, 0x3f }; + +static u8 mt2266_init2[] = { + 0x17, 0x6d, 0x71, 0x61, 0xc0, 0xbf, 0xff, 0xdc, 0x00, 0x0a, + 0xd4, 0x03, 0x64, 0x64, 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x7f, 0x5e, 0x3f, 0xff, 0xff, 0xff, 0x00, 0x77, 0x0f, 0x2d }; + +static u8 mt2266_init_8mhz[] = { + REG_BANDWIDTH, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 }; + +static u8 mt2266_init_7mhz[] = { + REG_BANDWIDTH, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32 }; + +static u8 mt2266_init_6mhz[] = { + REG_BANDWIDTH, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7 }; + +#define FREF 30000 // Quartz oscillator 30 MHz + +static int mt2266_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + struct mt2266_priv *priv; + int ret=0; + u32 freq; + u32 tune; + u8 lnaband; + u8 b[10]; + int i; + + priv = fe->tuner_priv; + + mt2266_writereg(priv,0x17,0x6d); + mt2266_writereg(priv,0x1c,0xff); + + freq = params->frequency / 1000; // Hz -> kHz + priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; + priv->frequency = freq * 1000; + tune=2 * freq * (8192/16) / (FREF/16); + + if (freq <= 495000) lnaband = 0xEE; else + if (freq <= 525000) lnaband = 0xDD; else + if (freq <= 550000) lnaband = 0xCC; else + if (freq <= 580000) lnaband = 0xBB; else + if (freq <= 605000) lnaband = 0xAA; else + if (freq <= 630000) lnaband = 0x99; else + if (freq <= 655000) lnaband = 0x88; else + if (freq <= 685000) lnaband = 0x77; else + if (freq <= 710000) lnaband = 0x66; else + if (freq <= 735000) lnaband = 0x55; else + if (freq <= 765000) lnaband = 0x44; else + if (freq <= 802000) lnaband = 0x33; else + if (freq <= 840000) lnaband = 0x22; else lnaband = 0x11; + + msleep(100); + mt2266_writeregs(priv,(params->u.ofdm.bandwidth==BANDWIDTH_6_MHZ)?mt2266_init_6mhz: + (params->u.ofdm.bandwidth==BANDWIDTH_7_MHZ)?mt2266_init_7mhz: + mt2266_init_8mhz,sizeof(mt2266_init_8mhz)); + + b[0] = REG_TUNE; + b[1] = (tune >> 8) & 0x1F; + b[2] = tune & 0xFF; + b[3] = tune >> 13; + mt2266_writeregs(priv,b,4); + + dprintk("set_parms: tune=%d band=%d\n",(int)tune,(int)lnaband); + dprintk("set_parms: [1..3]: %2x %2x %2x",(int)b[1],(int)b[2],(int)b[3]); + + b[0] = 0x05; + b[1] = 0x62; + b[2] = lnaband; + mt2266_writeregs(priv,b,3); + + //Waits for pll lock or timeout + i = 0; + do { + mt2266_readreg(priv,REG_LOCK,b); + if ((b[0] & 0x40)==0x40) + break; + msleep(10); + i++; + } while (i<10); + dprintk("Lock when i=%i\n",(int)i); + return ret; +} + +static void mt2266_calibrate(struct mt2266_priv *priv) +{ + mt2266_writereg(priv,0x11,0x03); + mt2266_writereg(priv,0x11,0x01); + + mt2266_writeregs(priv,mt2266_init1,sizeof(mt2266_init1)); + mt2266_writeregs(priv,mt2266_init2,sizeof(mt2266_init2)); + + mt2266_writereg(priv,0x33,0x5e); + mt2266_writereg(priv,0x10,0x10); + mt2266_writereg(priv,0x10,0x00); + + mt2266_writeregs(priv,mt2266_init_8mhz,sizeof(mt2266_init_8mhz)); + + msleep(25); + mt2266_writereg(priv,0x17,0x6d); + mt2266_writereg(priv,0x1c,0x00); + msleep(75); + mt2266_writereg(priv,0x17,0x6d); + mt2266_writereg(priv,0x1c,0xff); +} + +static int mt2266_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct mt2266_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; +} + +static int mt2266_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct mt2266_priv *priv = fe->tuner_priv; + *bandwidth = priv->bandwidth; + return 0; +} + +static int mt2266_init(struct dvb_frontend *fe) +{ + struct mt2266_priv *priv = fe->tuner_priv; + mt2266_writereg(priv,0x17,0x6d); + mt2266_writereg(priv,0x1c,0xff); + return 0; +} + +static int mt2266_sleep(struct dvb_frontend *fe) +{ + struct mt2266_priv *priv = fe->tuner_priv; + mt2266_writereg(priv,0x17,0x6d); + mt2266_writereg(priv,0x1c,0x00); + return 0; +} + +static int mt2266_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +static const struct dvb_tuner_ops mt2266_tuner_ops = { + .info = { + .name = "Microtune MT2266", + .frequency_min = 470000000, + .frequency_max = 860000000, + .frequency_step = 50000, + }, + .release = mt2266_release, + .init = mt2266_init, + .sleep = mt2266_sleep, + .set_params = mt2266_set_params, + .get_frequency = mt2266_get_frequency, + .get_bandwidth = mt2266_get_bandwidth +}; + +struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg) +{ + struct mt2266_priv *priv = NULL; + u8 id = 0; + + priv = kzalloc(sizeof(struct mt2266_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + priv->cfg = cfg; + priv->i2c = i2c; + + if (mt2266_readreg(priv,0,&id) != 0) { + kfree(priv); + return NULL; + } + if (id != PART_REV) { + kfree(priv); + return NULL; + } + printk(KERN_INFO "MT2266: successfully identified\n"); + memcpy(&fe->ops.tuner_ops, &mt2266_tuner_ops, sizeof(struct dvb_tuner_ops)); + + fe->tuner_priv = priv; + mt2266_calibrate(priv); + return fe; +} +EXPORT_SYMBOL(mt2266_attach); + +MODULE_AUTHOR("Olivier DANET"); +MODULE_DESCRIPTION("Microtune MT2266 silicon tuner driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/mt2266.h b/drivers/media/dvb/frontends/mt2266.h new file mode 100644 index 00000000000..f31dd613ad3 --- /dev/null +++ b/drivers/media/dvb/frontends/mt2266.h @@ -0,0 +1,37 @@ +/* + * Driver for Microtune MT2266 "Direct conversion low power broadband tuner" + * + * Copyright (c) 2007 Olivier DANET + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef MT2266_H +#define MT2266_H + +struct dvb_frontend; +struct i2c_adapter; + +struct mt2266_config { + u8 i2c_address; +}; + +#if defined(CONFIG_DVB_TUNER_MT2266) || (defined(CONFIG_DVB_TUNER_MT2266_MODULE) && defined(MODULE)) +extern struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg); +#else +static inline struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + return NULL; +} +#endif // CONFIG_DVB_TUNER_MT2266 + +#endif -- cgit v1.2.3-70-g09d2 From 7bb293849489b6cc5d6919b8c7f94cb273303e1f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 22 Jul 2007 09:42:09 -0300 Subject: V4L/DVB (5919): ivtv: remove dead code Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-streams.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index 51df3f85503..405e2e3fcb4 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -314,15 +314,6 @@ static void ivtv_vbi_setup(struct ivtv *itv) int lines; int i; - /* If Embed then streamtype must be Program */ - /* TODO: should we really do this? */ - if (0 && !raw && itv->vbi.insert_mpeg) { - itv->params.stream_type = 0; - - /* assign stream type */ - ivtv_vapi(itv, CX2341X_ENC_SET_STREAM_TYPE, 1, itv->params.stream_type); - } - /* Reset VBI */ ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, 0xffff , 0, 0, 0, 0); -- cgit v1.2.3-70-g09d2 From fa8a7529ba8c3c2f87dec78ad32c388695f4c1b7 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 22 Jul 2007 12:13:08 -0300 Subject: V4L/DVB (5921): ivtv: add missing composite input line for ivtv_pci_pg600v2 Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-cards.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-cards.c b/drivers/media/video/ivtv/ivtv-cards.c index 8eab0208388..baab14b40e8 100644 --- a/drivers/media/video/ivtv/ivtv-cards.c +++ b/drivers/media/video/ivtv/ivtv-cards.c @@ -845,6 +845,7 @@ static const struct ivtv_card ivtv_card_pg600v2 = { { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, { IVTV_CARD_INPUT_SVIDEO1, 1, CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 }, + { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 }, }, .audio_inputs = { { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, -- cgit v1.2.3-70-g09d2 From c976bc82339437e840f7dbf0b8c89c09d3fcd75e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 22 Jul 2007 12:52:40 -0300 Subject: V4L/DVB (5922): ivtv, cx25840: postpone fw load until first use The firmware is now loaded when the driver is actually used for the first time. This allows the driver to be compiled in-kernel instead of as a module. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Makefile | 3 +- drivers/media/video/cx25840/cx25840-core.c | 21 +++- drivers/media/video/cx25840/cx25840-core.h | 1 + drivers/media/video/ivtv/ivtv-driver.c | 193 ++++++++++++++--------------- drivers/media/video/ivtv/ivtv-driver.h | 5 + drivers/media/video/ivtv/ivtv-fileops.c | 9 ++ 6 files changed, 129 insertions(+), 103 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 8f7205b558f..c5286bfba44 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -64,7 +64,6 @@ obj-$(CONFIG_VIDEO_CPIA_USB) += cpia_usb.o obj-$(CONFIG_VIDEO_MEYE) += meye.o obj-$(CONFIG_VIDEO_SAA7134) += saa7134/ obj-$(CONFIG_VIDEO_CX88) += cx88/ -obj-$(CONFIG_VIDEO_IVTV) += ivtv/ obj-$(CONFIG_VIDEO_EM28XX) += em28xx/ obj-$(CONFIG_VIDEO_USBVISION) += usbvision/ obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o @@ -117,6 +116,8 @@ obj-$(CONFIG_USB_KONICAWC) += usbvideo/ obj-$(CONFIG_USB_VICAM) += usbvideo/ obj-$(CONFIG_USB_QUICKCAM_MESSENGER) += usbvideo/ +obj-$(CONFIG_VIDEO_IVTV) += ivtv/ + obj-$(CONFIG_VIDEO_VIVI) += vivi.o EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 67bda9f9a44..9c12bd39cfb 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -625,6 +625,22 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, struct v4l2_tuner *vt = arg; struct v4l2_routing *route = arg; + /* ignore these commands */ + switch (cmd) { + case TUNER_SET_TYPE_ADDR: + return 0; + } + + if (!state->is_initialized) { + v4l_dbg(1, cx25840_debug, client, "cmd %08x triggered fw load\n", cmd); + /* initialize on first use */ + state->is_initialized = 1; + if (state->is_cx25836) + cx25836_initialize(client); + else + cx25840_initialize(client, 1); + } + switch (cmd) { #ifdef CONFIG_VIDEO_ADV_DEBUG /* ioctls to allow direct access to the @@ -906,11 +922,6 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address, i2c_attach_client(client); - if (state->is_cx25836) - cx25836_initialize(client); - else - cx25840_initialize(client, 1); - return 0; } diff --git a/drivers/media/video/cx25840/cx25840-core.h b/drivers/media/video/cx25840/cx25840-core.h index f4b56d2fd6b..8c1fbd9b87c 100644 --- a/drivers/media/video/cx25840/cx25840-core.h +++ b/drivers/media/video/cx25840/cx25840-core.h @@ -46,6 +46,7 @@ struct cx25840_state { u32 id; u32 rev; int is_cx25836; + int is_initialized; }; /* ----------------------------------------------------------------------- */ diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 81cbaf7dd51..00bdcc2e8f5 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -814,7 +814,6 @@ static void ivtv_request_module(struct ivtv *itv, const char *name) static void ivtv_load_and_init_modules(struct ivtv *itv) { - struct v4l2_control ctrl; u32 hw = itv->card->hw_all; int i; @@ -896,11 +895,6 @@ static void ivtv_load_and_init_modules(struct ivtv *itv) } if (hw & IVTV_HW_CX25840) { - /* CX25840_CID_ENABLE_PVR150_WORKAROUND */ - ctrl.id = V4L2_CID_PRIVATE_BASE; - ctrl.value = itv->pvr150_workaround; - itv->video_dec_func(itv, VIDIOC_S_CTRL, &ctrl); - itv->vbi.raw_decoder_line_size = 1444; itv->vbi.raw_decoder_sav_odd_field = 0x20; itv->vbi.raw_decoder_sav_even_field = 0x60; @@ -946,12 +940,9 @@ static int __devinit ivtv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) { int retval = 0; - int video_input; int yuv_buf_size; int vbi_buf_size; - int fw_retry_count = 3; struct ivtv *itv; - struct v4l2_frequency vf; spin_lock(&ivtv_cards_lock); @@ -1038,22 +1029,6 @@ static int __devinit ivtv_probe(struct pci_dev *dev, goto free_io; } - while (--fw_retry_count > 0) { - /* load firmware */ - if (ivtv_firmware_init(itv) == 0) - break; - if (fw_retry_count > 1) - IVTV_WARN("Retry loading firmware\n"); - } - if (fw_retry_count == 0) { - IVTV_ERR("Error initializing firmware\n"); - goto free_i2c; - } - - /* Try and get firmware versions */ - IVTV_DEBUG_INFO("Getting firmware version..\n"); - ivtv_firmware_versions(itv); - /* Check yuv output filter table */ if (itv->has_cx23415) ivtv_yuv_filter_check(itv); @@ -1157,44 +1132,16 @@ static int __devinit ivtv_probe(struct pci_dev *dev, ivtv_call_i2c_clients(itv, TUNER_SET_TYPE_ADDR, &setup); } - vf.tuner = 0; - vf.type = V4L2_TUNER_ANALOG_TV; - vf.frequency = 6400; /* the tuner 'baseline' frequency */ - - /* Set initial frequency. For PAL/SECAM broadcasts no - 'default' channel exists AFAIK. */ - if (itv->std == V4L2_STD_NTSC_M_JP) { - vf.frequency = 1460; /* ch. 1 91250*16/1000 */ - } - else if (itv->std & V4L2_STD_NTSC_M) { - vf.frequency = 1076; /* ch. 4 67250*16/1000 */ - } - /* The tuner is fixed to the standard. The other inputs (e.g. S-Video) are not. */ itv->tuner_std = itv->std; - video_input = itv->active_input; - itv->active_input++; /* Force update of input */ - ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_INPUT, &video_input); - - /* Let the VIDIOC_S_STD ioctl do all the work, keeps the code - in one place. */ - itv->std++; /* Force full standard initialization */ - itv->std_out = itv->std; - ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_FREQUENCY, &vf); - retval = ivtv_streams_setup(itv); if (retval) { IVTV_ERR("Error %d setting up streams\n", retval); goto free_i2c; } - if (itv->card->v4l2_capabilities & V4L2_CAP_VIDEO_OUTPUT) { - ivtv_init_mpeg_decoder(itv); - } - ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_STD, &itv->tuner_std); - IVTV_DEBUG_IRQ("Masking interrupts\n"); /* clear interrupt mask, effectively disabling interrupts */ ivtv_set_irq_mask(itv, 0xffffffff); @@ -1206,26 +1153,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev, IVTV_ERR("Failed to register irq %d\n", retval); goto free_streams; } - - /* On a cx23416 this seems to be able to enable DMA to the chip? */ - if (!itv->has_cx23415) - write_reg_sync(0x03, IVTV_REG_DMACONTROL); - - /* Default interrupts enabled. For the PVR350 this includes the - decoder VSYNC interrupt, which is always on. It is not only used - during decoding but also by the OSD. - Some old PVR250 cards had a cx23415, so testing for that is too - general. Instead test if the card has video output capability. */ - if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) - ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT | IVTV_IRQ_DEC_VSYNC); - else - ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT); - - if (itv->has_cx23415) - ivtv_set_osd_alpha(itv); - IVTV_INFO("Initialized card #%d: %s\n", itv->num, itv->card_name); - return 0; free_irq: @@ -1255,55 +1183,126 @@ static int __devinit ivtv_probe(struct pci_dev *dev, return retval; } +int ivtv_init_on_first_open(struct ivtv *itv) +{ + struct v4l2_frequency vf; + int fw_retry_count = 3; + int video_input; + + while (--fw_retry_count > 0) { + /* load firmware */ + if (ivtv_firmware_init(itv) == 0) + break; + if (fw_retry_count > 1) + IVTV_WARN("Retry loading firmware\n"); + } + if (fw_retry_count == 0) { + IVTV_ERR("Error initializing firmware\n"); + return -1; + } + + /* Try and get firmware versions */ + IVTV_DEBUG_INFO("Getting firmware version..\n"); + ivtv_firmware_versions(itv); + + if (itv->card->hw_all & IVTV_HW_CX25840) { + struct v4l2_control ctrl; + + /* CX25840_CID_ENABLE_PVR150_WORKAROUND */ + ctrl.id = V4L2_CID_PRIVATE_BASE; + ctrl.value = itv->pvr150_workaround; + itv->video_dec_func(itv, VIDIOC_S_CTRL, &ctrl); + } + + vf.tuner = 0; + vf.type = V4L2_TUNER_ANALOG_TV; + vf.frequency = 6400; /* the tuner 'baseline' frequency */ + + /* Set initial frequency. For PAL/SECAM broadcasts no + 'default' channel exists AFAIK. */ + if (itv->std == V4L2_STD_NTSC_M_JP) { + vf.frequency = 1460; /* ch. 1 91250*16/1000 */ + } + else if (itv->std & V4L2_STD_NTSC_M) { + vf.frequency = 1076; /* ch. 4 67250*16/1000 */ + } + + video_input = itv->active_input; + itv->active_input++; /* Force update of input */ + ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_INPUT, &video_input); + + /* Let the VIDIOC_S_STD ioctl do all the work, keeps the code + in one place. */ + itv->std++; /* Force full standard initialization */ + itv->std_out = itv->std; + ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_FREQUENCY, &vf); + + if (itv->card->v4l2_capabilities & V4L2_CAP_VIDEO_OUTPUT) { + ivtv_init_mpeg_decoder(itv); + } + ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_STD, &itv->tuner_std); + + /* On a cx23416 this seems to be able to enable DMA to the chip? */ + if (!itv->has_cx23415) + write_reg_sync(0x03, IVTV_REG_DMACONTROL); + + /* Default interrupts enabled. For the PVR350 this includes the + decoder VSYNC interrupt, which is always on. It is not only used + during decoding but also by the OSD. + Some old PVR250 cards had a cx23415, so testing for that is too + general. Instead test if the card has video output capability. */ + if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { + ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT | IVTV_IRQ_DEC_VSYNC); + ivtv_set_osd_alpha(itv); + } + else + ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT); + return 0; +} + static void ivtv_remove(struct pci_dev *pci_dev) { struct ivtv *itv = pci_get_drvdata(pci_dev); IVTV_DEBUG_INFO("Removing Card #%d\n", itv->num); - /* Stop all captures */ - IVTV_DEBUG_INFO("Stopping all streams\n"); - if (atomic_read(&itv->capturing) > 0) - ivtv_stop_all_captures(itv); - - /* Stop all decoding */ - IVTV_DEBUG_INFO("Stopping decoding\n"); - if (atomic_read(&itv->decoding) > 0) { - int type; - - if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) - type = IVTV_DEC_STREAM_TYPE_YUV; - else - type = IVTV_DEC_STREAM_TYPE_MPG; - ivtv_stop_v4l2_decode_stream(&itv->streams[type], - VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0); + if (test_bit(IVTV_F_I_INITED, &itv->i_flags)) { + /* Stop all captures */ + IVTV_DEBUG_INFO("Stopping all streams\n"); + if (atomic_read(&itv->capturing) > 0) + ivtv_stop_all_captures(itv); + + /* Stop all decoding */ + IVTV_DEBUG_INFO("Stopping decoding\n"); + if (atomic_read(&itv->decoding) > 0) { + int type; + + if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) + type = IVTV_DEC_STREAM_TYPE_YUV; + else + type = IVTV_DEC_STREAM_TYPE_MPG; + ivtv_stop_v4l2_decode_stream(&itv->streams[type], + VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0); + } + ivtv_halt_firmware(itv); } /* Interrupts */ - IVTV_DEBUG_INFO("Disabling interrupts\n"); ivtv_set_irq_mask(itv, 0xffffffff); del_timer_sync(&itv->dma_timer); /* Stop all Work Queues */ - IVTV_DEBUG_INFO("Stop Work Queues\n"); flush_workqueue(itv->irq_work_queues); destroy_workqueue(itv->irq_work_queues); - IVTV_DEBUG_INFO("Stopping Firmware\n"); - ivtv_halt_firmware(itv); - - IVTV_DEBUG_INFO("Unregistering v4l devices\n"); ivtv_streams_cleanup(itv); - IVTV_DEBUG_INFO("Freeing dma resources\n"); ivtv_udma_free(itv); exit_ivtv_i2c(itv); - IVTV_DEBUG_INFO(" Releasing irq\n"); free_irq(itv->dev->irq, (void *)itv); ivtv_iounmap(itv); - IVTV_DEBUG_INFO(" Releasing mem\n"); release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE); release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); if (itv->has_cx23415) diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 8fe9d9c7a18..6e53a1f04f7 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -398,6 +398,8 @@ struct ivtv_mailbox_data { #define IVTV_F_I_WORK_HANDLER_PIO 18 /* there is work to be done for PIO */ #define IVTV_F_I_PIO 19 /* PIO in progress */ #define IVTV_F_I_DEC_PAUSED 20 /* the decoder is paused */ +#define IVTV_F_I_INITED 21 /* set after first open */ +#define IVTV_F_I_FAILED 22 /* set if first open failed */ /* Event notifications */ #define IVTV_F_I_EV_DEC_STOPPED 28 /* decoder stopped event */ @@ -838,6 +840,9 @@ int ivtv_waitq(wait_queue_head_t *waitq); struct tveeprom; /* forward reference */ void ivtv_read_eeprom(struct ivtv *itv, struct tveeprom *tv); +/* First-open initialization: load firmware, init cx25840, etc. */ +int ivtv_init_on_first_open(struct ivtv *itv); + /* This is a PCI post thing, where if the pci register is not read, then the write doesn't always take effect right away. By reading back the register any pending PCI writes will be performed (in order), and so diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index 66ea3cbc369..49886084164 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -850,6 +850,15 @@ int ivtv_v4l2_open(struct inode *inode, struct file *filp) return -ENXIO; } + if (!test_and_set_bit(IVTV_F_I_INITED, &itv->i_flags)) + if (ivtv_init_on_first_open(itv)) + set_bit(IVTV_F_I_FAILED, &itv->i_flags); + + if (test_bit(IVTV_F_I_FAILED, &itv->i_flags)) { + printk(KERN_WARNING "ivtv: failed to initialize on minor %d\n", minor); + return -ENXIO; + } + if (y == IVTV_DEC_STREAM_TYPE_MPG && test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_YUV].s_flags)) return -EBUSY; -- cgit v1.2.3-70-g09d2 From 6e5eb59102aa6007d3ea2b382a1d3ca4112c272a Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 25 Jul 2007 12:55:52 -0300 Subject: V4L/DVB (5924): ivtv-fb: initializing the fb should trigger ivtv firmware load ivtv-fb: initializing the framebuffer should trigger ivtv firmware load Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.c | 12 ++++++++++-- drivers/media/video/ivtv/ivtv-fb.c | 5 +++++ drivers/media/video/ivtv/ivtv-fileops.c | 10 +++------- 3 files changed, 18 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 00bdcc2e8f5..55ed0305fd6 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -1189,6 +1189,12 @@ int ivtv_init_on_first_open(struct ivtv *itv) int fw_retry_count = 3; int video_input; + if (test_bit(IVTV_F_I_FAILED, &itv->i_flags)) + return -ENXIO; + + if (test_and_set_bit(IVTV_F_I_INITED, &itv->i_flags)) + return 0; + while (--fw_retry_count > 0) { /* load firmware */ if (ivtv_firmware_init(itv) == 0) @@ -1196,9 +1202,10 @@ int ivtv_init_on_first_open(struct ivtv *itv) if (fw_retry_count > 1) IVTV_WARN("Retry loading firmware\n"); } + if (fw_retry_count == 0) { - IVTV_ERR("Error initializing firmware\n"); - return -1; + set_bit(IVTV_F_I_FAILED, &itv->i_flags); + return -ENXIO; } /* Try and get firmware versions */ @@ -1381,6 +1388,7 @@ EXPORT_SYMBOL(ivtv_udma_setup); EXPORT_SYMBOL(ivtv_udma_unmap); EXPORT_SYMBOL(ivtv_udma_alloc); EXPORT_SYMBOL(ivtv_udma_prepare); +EXPORT_SYMBOL(ivtv_init_on_first_open); module_init(module_start); module_exit(module_cleanup); diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c index b8ad249a0b1..00765da8a6a 100644 --- a/drivers/media/video/ivtv/ivtv-fb.c +++ b/drivers/media/video/ivtv/ivtv-fb.c @@ -1013,6 +1013,11 @@ static int ivtvfb_init_io(struct ivtv *itv) { struct osd_info *oi = itv->osd_info; + if (ivtv_init_on_first_open(itv)) { + IVTV_FB_ERR("Failed to initialize ivtv\n"); + return -ENXIO; + } + ivtv_fb_get_framebuffer(itv, &oi->video_rbase, &oi->video_buffer_size); /* The osd buffer size depends on the number of video buffers allocated diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index 49886084164..fedddecf661 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -846,16 +846,12 @@ int ivtv_v4l2_open(struct inode *inode, struct file *filp) if (itv == NULL) { /* Couldn't find a device registered on that minor, shouldn't happen! */ - printk(KERN_WARNING "ivtv: No ivtv device found on minor %d\n", minor); + IVTV_WARN("No ivtv device found on minor %d\n", minor); return -ENXIO; } - if (!test_and_set_bit(IVTV_F_I_INITED, &itv->i_flags)) - if (ivtv_init_on_first_open(itv)) - set_bit(IVTV_F_I_FAILED, &itv->i_flags); - - if (test_bit(IVTV_F_I_FAILED, &itv->i_flags)) { - printk(KERN_WARNING "ivtv: failed to initialize on minor %d\n", minor); + if (ivtv_init_on_first_open(itv)) { + IVTV_ERR("Failed to initialize on minor %d\n", minor); return -ENXIO; } -- cgit v1.2.3-70-g09d2 From 469ba047c08669f364c2616967e8494b1f3ef21c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 20 Jul 2007 06:51:58 -0300 Subject: V4L/DVB (5927): ivtv: set correct crystal frequency of the GVMVPRX cards Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 55ed0305fd6..cf52111a2dc 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -57,6 +57,7 @@ #include "ivtv-yuv.h" #include +#include #include /* var to keep track of the number of array elements in use */ @@ -893,6 +894,15 @@ static void ivtv_load_and_init_modules(struct ivtv *itv) else if ((hw & IVTV_HW_UPD64031A) == 0) itv->card = ivtv_get_card(IVTV_CARD_CX23416GYC_NOGR); } + else if (itv->card->type == IVTV_CARD_GV_MVPRX || + itv->card->type == IVTV_CARD_GV_MVPRX2E) { + struct v4l2_crystal_freq crystal_freq; + + /* The crystal frequency of GVMVPRX is 24.576MHz */ + crystal_freq.freq = SAA7115_FREQ_24_576_MHZ; + crystal_freq.flags = SAA7115_FREQ_FL_UCGC; + itv->video_dec_func(itv, VIDIOC_INT_S_CRYSTAL_FREQ, &crystal_freq); + } if (hw & IVTV_HW_CX25840) { itv->vbi.raw_decoder_line_size = 1444; -- cgit v1.2.3-70-g09d2 From b4c85248afcc5265ce8c36b9c15e40e6a92b5ae7 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 20 Jul 2007 06:53:23 -0300 Subject: V4L/DVB (5928): tuner: fix TOP values for the Panasonic VP27 tuner. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-types.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/tuner-types.c b/drivers/media/video/tuner-types.c index 417f642b435..53a99b39387 100644 --- a/drivers/media/video/tuner-types.c +++ b/drivers/media/video/tuner-types.c @@ -670,6 +670,9 @@ static struct tuner_params tuner_panasonic_vp27_params[] = { .count = ARRAY_SIZE(tuner_panasonic_vp27_ntsc_ranges), .has_tda9887 = 1, .intercarrier_mode = 1, + .default_top_low = -3, + .default_top_mid = -3, + .default_top_high = -3, }, }; -- cgit v1.2.3-70-g09d2 From ac247433fe205acf460f05de64a30ee71ea307f2 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 27 Jul 2007 06:56:50 -0300 Subject: V4L/DVB (5929): Add vp27smpx driver This device is internal to the Panasonic VP27S tuner and is used to set the mono/stereo/bilingual setting of the tuner. It is used by two Japanese cx23416-based cards. Signed-off-by: Takahiro Adachi Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 9 ++ drivers/media/video/Makefile | 1 + drivers/media/video/ivtv/Kconfig | 1 + drivers/media/video/ivtv/ivtv-cards.c | 4 +- drivers/media/video/ivtv/ivtv-cards.h | 3 +- drivers/media/video/ivtv/ivtv-driver.c | 4 + drivers/media/video/ivtv/ivtv-i2c.c | 2 + drivers/media/video/vp27smpx.c | 211 +++++++++++++++++++++++++++++++++ include/linux/i2c-id.h | 1 + include/media/v4l2-chip-ident.h | 3 + 10 files changed, 236 insertions(+), 3 deletions(-) create mode 100644 drivers/media/video/vp27smpx.c (limited to 'drivers') diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 675c8574403..0e1d2ccc4e8 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -148,6 +148,15 @@ config VIDEO_WM8739 To compile this driver as a module, choose M here: the module will be called wm8739. +config VIDEO_VP27SMPX + tristate "Panasonic VP27s internal MPX" + depends on VIDEO_V4L2 && I2C && EXPERIMENTAL + ---help--- + Support for the internal MPX of the Panasonic VP27s tuner. + + To compile this driver as a module, choose M here: the + module will be called vp27smpx. + comment "Video decoders" config VIDEO_BT819 diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index c5286bfba44..113e525f6da 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -73,6 +73,7 @@ obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o obj-$(CONFIG_VIDEO_WM8775) += wm8775.o obj-$(CONFIG_VIDEO_WM8739) += wm8739.o +obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip/ obj-$(CONFIG_VIDEO_CPIA2) += cpia2/ obj-$(CONFIG_VIDEO_MXB) += mxb.o diff --git a/drivers/media/video/ivtv/Kconfig b/drivers/media/video/ivtv/Kconfig index 399f231abb9..5efacb33211 100644 --- a/drivers/media/video/ivtv/Kconfig +++ b/drivers/media/video/ivtv/Kconfig @@ -14,6 +14,7 @@ config VIDEO_IVTV select VIDEO_CS53L32A select VIDEO_WM8775 select VIDEO_WM8739 + select VIDEO_VP27SMPX select VIDEO_UPD64031A select VIDEO_UPD64083 ---help--- diff --git a/drivers/media/video/ivtv/ivtv-cards.c b/drivers/media/video/ivtv/ivtv-cards.c index baab14b40e8..e51d7cc35b1 100644 --- a/drivers/media/video/ivtv/ivtv-cards.c +++ b/drivers/media/video/ivtv/ivtv-cards.c @@ -616,7 +616,7 @@ static const struct ivtv_card ivtv_card_gv_mvprx = { .hw_video = IVTV_HW_SAA7115 | IVTV_HW_UPD64031A | IVTV_HW_UPD6408X, .hw_audio = IVTV_HW_GPIO, .hw_audio_ctrl = IVTV_HW_WM8739, - .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_TVAUDIO | + .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_VP27SMPX | IVTV_HW_TUNER | IVTV_HW_WM8739 | IVTV_HW_UPD64031A | IVTV_HW_UPD6408X, .video_inputs = { @@ -654,7 +654,7 @@ static const struct ivtv_card ivtv_card_gv_mvprx2e = { .hw_audio = IVTV_HW_GPIO, .hw_audio_ctrl = IVTV_HW_WM8739, .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_TUNER | - IVTV_HW_TVAUDIO | IVTV_HW_WM8739, + IVTV_HW_VP27SMPX | IVTV_HW_WM8739, .video_inputs = { { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 }, { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, diff --git a/drivers/media/video/ivtv/ivtv-cards.h b/drivers/media/video/ivtv/ivtv-cards.h index 91e9e90c14a..3191920f4c6 100644 --- a/drivers/media/video/ivtv/ivtv-cards.h +++ b/drivers/media/video/ivtv/ivtv-cards.h @@ -33,7 +33,8 @@ #define IVTV_HW_UPD6408X (1 << 11) #define IVTV_HW_SAA717X (1 << 12) #define IVTV_HW_WM8739 (1 << 13) -#define IVTV_HW_GPIO (1 << 14) +#define IVTV_HW_VP27SMPX (1 << 14) +#define IVTV_HW_GPIO (1 << 15) #define IVTV_HW_SAA711X (IVTV_HW_SAA7115 | IVTV_HW_SAA7114) diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index cf52111a2dc..f8ef267e56b 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -853,6 +853,10 @@ static void ivtv_load_and_init_modules(struct ivtv *itv) #ifndef CONFIG_VIDEO_MSP3400 if (hw & IVTV_HW_MSP34XX) ivtv_request_module(itv, "msp3400"); +#endif +#ifndef CONFIG_VIDEO_VP27SMPX + if (hw & IVTV_HW_VP27SMPX) + ivtv_request_module(itv, "vp27smpx"); #endif if (hw & IVTV_HW_TVAUDIO) ivtv_request_module(itv, "tvaudio"); diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c index b3557435456..5e12ebc2a9d 100644 --- a/drivers/media/video/ivtv/ivtv-i2c.c +++ b/drivers/media/video/ivtv/ivtv-i2c.c @@ -109,6 +109,7 @@ static const u8 hw_driverids[] = { I2C_DRIVERID_UPD64083, I2C_DRIVERID_SAA717X, I2C_DRIVERID_WM8739, + I2C_DRIVERID_VP27SMPX, 0 /* IVTV_HW_GPIO dummy driver ID */ }; @@ -128,6 +129,7 @@ static const char * const hw_drivernames[] = { "upd64083", "saa717x", "wm8739", + "vp27smpx", "gpio", }; diff --git a/drivers/media/video/vp27smpx.c b/drivers/media/video/vp27smpx.c new file mode 100644 index 00000000000..9aa526bd2c8 --- /dev/null +++ b/drivers/media/video/vp27smpx.c @@ -0,0 +1,211 @@ +/* + * vp27smpx - driver version 0.0.1 + * + * Copyright (C) 2007 Hans Verkuil + * + * Special thanks to Kazz for the i2c data. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_DESCRIPTION("vp27smpx driver"); +MODULE_AUTHOR("Hans Verkuil"); +MODULE_LICENSE("GPL"); + +static unsigned short normal_i2c[] = { 0xb6 >> 1, I2C_CLIENT_END }; + + +I2C_CLIENT_INSMOD; + +/* ----------------------------------------------------------------------- */ + +struct vp27smpx_state { + int radio; + u32 audmode; +}; + +static void vp27smpx_set_audmode(struct i2c_client *client, u32 audmode) +{ + struct vp27smpx_state *state = i2c_get_clientdata(client); + u8 data[3] = { 0x00, 0x00, 0x04 }; + + switch (audmode) { + case V4L2_TUNER_MODE_MONO: + case V4L2_TUNER_MODE_LANG1: + break; + case V4L2_TUNER_MODE_STEREO: + case V4L2_TUNER_MODE_LANG1_LANG2: + data[1] = 0x01; + break; + case V4L2_TUNER_MODE_LANG2: + data[1] = 0x02; + break; + } + + if (i2c_master_send(client, data, sizeof(data)) != sizeof(data)) { + v4l_err(client, "%s: I/O error setting audmode\n", client->name); + } + else { + state->audmode = audmode; + } +} + +static int vp27smpx_command(struct i2c_client *client, unsigned int cmd, + void *arg) +{ + struct vp27smpx_state *state = i2c_get_clientdata(client); + struct v4l2_tuner *vt = arg; + + switch (cmd) { + case AUDC_SET_RADIO: + state->radio = 1; + break; + + case VIDIOC_S_STD: + state->radio = 0; + break; + + case VIDIOC_S_TUNER: + if (!state->radio) + vp27smpx_set_audmode(client, vt->audmode); + break; + + case VIDIOC_G_TUNER: + if (state->radio) + break; + vt->audmode = state->audmode; + vt->capability = V4L2_TUNER_CAP_STEREO | + V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2; + vt->rxsubchans = V4L2_TUNER_SUB_MONO; + break; + + case VIDIOC_G_CHIP_IDENT: + return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_VP27SMPX, 0); + + case VIDIOC_LOG_STATUS: + v4l_info(client, "Audio Mode: %u%s\n", state->audmode, + state->radio ? " (Radio)" : ""); + break; + + default: + return -EINVAL; + } + return 0; +} + +/* ----------------------------------------------------------------------- */ + +/* i2c implementation */ + +/* + * Generic i2c probe + * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' + */ + +static struct i2c_driver i2c_driver; + +static int vp27smpx_attach(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *client; + struct vp27smpx_state *state; + + /* Check if the adapter supports the needed features */ + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return 0; + + client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (client == 0) + return -ENOMEM; + + client->addr = address; + client->adapter = adapter; + client->driver = &i2c_driver; + snprintf(client->name, sizeof(client->name) - 1, "vp27smpx"); + + v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name); + + state = kzalloc(sizeof(struct vp27smpx_state), GFP_KERNEL); + if (state == NULL) { + kfree(client); + return -ENOMEM; + } + state->audmode = V4L2_TUNER_MODE_STEREO; + i2c_set_clientdata(client, state); + + /* initialize vp27smpx */ + vp27smpx_set_audmode(client, state->audmode); + i2c_attach_client(client); + + return 0; +} + +static int vp27smpx_probe(struct i2c_adapter *adapter) +{ + if (adapter->class & I2C_CLASS_TV_ANALOG) + return i2c_probe(adapter, &addr_data, vp27smpx_attach); + return 0; +} + +static int vp27smpx_detach(struct i2c_client *client) +{ + struct vp27smpx_state *state = i2c_get_clientdata(client); + int err; + + err = i2c_detach_client(client); + if (err) { + return err; + } + kfree(state); + kfree(client); + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +/* i2c implementation */ +static struct i2c_driver i2c_driver = { + .driver = { + .name = "vp27smpx", + }, + .id = I2C_DRIVERID_VP27SMPX, + .attach_adapter = vp27smpx_probe, + .detach_client = vp27smpx_detach, + .command = vp27smpx_command, +}; + + +static int __init vp27smpx_init_module(void) +{ + return i2c_add_driver(&i2c_driver); +} + +static void __exit vp27smpx_cleanup_module(void) +{ + i2c_del_driver(&i2c_driver); +} + +module_init(vp27smpx_init_module); +module_exit(vp27smpx_cleanup_module); diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h index b6901486571..4891e03ad23 100644 --- a/include/linux/i2c-id.h +++ b/include/linux/i2c-id.h @@ -119,6 +119,7 @@ #define I2C_DRIVERID_WM8750 90 /* Wolfson WM8750 audio codec */ #define I2C_DRIVERID_WM8753 91 /* Wolfson WM8753 audio codec */ #define I2C_DRIVERID_LM4857 92 /* LM4857 Audio Amplifier */ +#define I2C_DRIVERID_VP27SMPX 93 /* Panasonic VP27s tuner internal MPX */ #define I2C_DRIVERID_I2CDEV 900 #define I2C_DRIVERID_ARP 902 /* SMBus ARP Client */ diff --git a/include/media/v4l2-chip-ident.h b/include/media/v4l2-chip-ident.h index 09d16c4f00f..8ae42c41dd0 100644 --- a/include/media/v4l2-chip-ident.h +++ b/include/media/v4l2-chip-ident.h @@ -65,6 +65,9 @@ enum { V4L2_IDENT_CX23415 = 415, V4L2_IDENT_CX23416 = 416, + /* module vp27smpx: just ident 2700 */ + V4L2_IDENT_VP27SMPX = 2700, + /* module wm8739: just ident 8739 */ V4L2_IDENT_WM8739 = 8739, -- cgit v1.2.3-70-g09d2 From 36c15f8ee41fbc3d8eaf88bba95be3d50268d5d2 Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Mon, 23 Jul 2007 13:59:55 -0300 Subject: V4L/DVB (5934): dvb-ttpci/saa7146: Replace saa7146_i2c_transfer by generic i2c_transfer Convert av7110_v4l.c to use i2c_transfer() instead of saa7146_i2c_transfer(). Make saa7146_i2c_transfer() static. Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/saa7146_core.c | 1 - drivers/media/common/saa7146_i2c.c | 2 +- drivers/media/dvb/ttpci/av7110_v4l.c | 6 ++++-- include/media/saa7146.h | 1 - 4 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c index ba6701e9767..12cda9eebd1 100644 --- a/drivers/media/common/saa7146_core.c +++ b/drivers/media/common/saa7146_core.c @@ -548,7 +548,6 @@ EXPORT_SYMBOL_GPL(saa7146_wait_for_debi_done); EXPORT_SYMBOL_GPL(saa7146_setgpio); -EXPORT_SYMBOL_GPL(saa7146_i2c_transfer); EXPORT_SYMBOL_GPL(saa7146_i2c_adapter_prepare); EXPORT_SYMBOL_GPL(saa7146_debug); diff --git a/drivers/media/common/saa7146_i2c.c b/drivers/media/common/saa7146_i2c.c index 8c85efc2652..f823286341e 100644 --- a/drivers/media/common/saa7146_i2c.c +++ b/drivers/media/common/saa7146_i2c.c @@ -277,7 +277,7 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d return 0; } -int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *msgs, int num, int retries) +static int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *msgs, int num, int retries) { int i = 0, count = 0; u32* buffer = dev->d_i2c.cpu_addr; diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c index 87afaebc070..76cca003252 100644 --- a/drivers/media/dvb/ttpci/av7110_v4l.c +++ b/drivers/media/dvb/ttpci/av7110_v4l.c @@ -129,23 +129,25 @@ static struct v4l2_input inputs[4] = { static int ves1820_writereg(struct saa7146_dev *dev, u8 addr, u8 reg, u8 data) { + struct av7110 *av7110 = dev->ext_priv; u8 buf[] = { 0x00, reg, data }; struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = 3 }; dprintk(4, "dev: %p\n", dev); - if (1 != saa7146_i2c_transfer(dev, &msg, 1, 1)) + if (1 != i2c_transfer(&av7110->i2c_adap, &msg, 1)) return -1; return 0; } static int tuner_write(struct saa7146_dev *dev, u8 addr, u8 data [4]) { + struct av7110 *av7110 = dev->ext_priv; struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = data, .len = 4 }; dprintk(4, "dev: %p\n", dev); - if (1 != saa7146_i2c_transfer(dev, &msg, 1, 1)) + if (1 != i2c_transfer(&av7110->i2c_adap, &msg, 1)) return -1; return 0; } diff --git a/include/media/saa7146.h b/include/media/saa7146.h index 67703249b24..cd3ff2c29d5 100644 --- a/include/media/saa7146.h +++ b/include/media/saa7146.h @@ -146,7 +146,6 @@ struct saa7146_dev /* from saa7146_i2c.c */ int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c_adapter, u32 bitrate); -int saa7146_i2c_transfer(struct saa7146_dev *saa, const struct i2c_msg *msgs, int num, int retries); /* from saa7146_core.c */ extern struct list_head saa7146_devices; -- cgit v1.2.3-70-g09d2 From 1fab46f0decd226fcbae73b23d7f8ed478416fbb Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Mon, 23 Jul 2007 21:00:36 -0300 Subject: V4L/DVB (5935): dvb_frontend: Range check of frequency and symbol rate Add range check of frequency and symbol rate to the FE_SET_FRONTEND ioctl. This will also avoid a divide-by zero exception in the stv0297 driver, if symbol rate is set to 0. Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 46 +++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index b6c7f6610ec..384b5b8959c 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -697,6 +697,47 @@ static int dvb_frontend_start(struct dvb_frontend *fe) return 0; } +static int dvb_frontend_check_parameters(struct dvb_frontend *fe, + struct dvb_frontend_parameters *parms) +{ + /* range check: frequency */ + if ((fe->ops.info.frequency_min && + parms->frequency < fe->ops.info.frequency_min) || + (fe->ops.info.frequency_max && + parms->frequency > fe->ops.info.frequency_max)) { + printk(KERN_WARNING "DVB: frontend %u frequency %u out of range (%u..%u)\n", + fe->dvb->num, parms->frequency, + fe->ops.info.frequency_min, fe->ops.info.frequency_max); + return -EINVAL; + } + + /* range check: symbol rate */ + if (fe->ops.info.type == FE_QPSK) { + if ((fe->ops.info.symbol_rate_min && + parms->u.qpsk.symbol_rate < fe->ops.info.symbol_rate_min) || + (fe->ops.info.symbol_rate_max && + parms->u.qpsk.symbol_rate > fe->ops.info.symbol_rate_max)) { + printk(KERN_WARNING "DVB: frontend %u symbol rate %u out of range (%u..%u)\n", + fe->dvb->num, parms->u.qpsk.symbol_rate, + fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max); + return -EINVAL; + } + + } else if (fe->ops.info.type == FE_QAM) { + if ((fe->ops.info.symbol_rate_min && + parms->u.qam.symbol_rate < fe->ops.info.symbol_rate_min) || + (fe->ops.info.symbol_rate_max && + parms->u.qam.symbol_rate > fe->ops.info.symbol_rate_max)) { + printk(KERN_WARNING "DVB: frontend %u symbol rate %u out of range (%u..%u)\n", + fe->dvb->num, parms->u.qam.symbol_rate, + fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max); + return -EINVAL; + } + } + + return 0; +} + static int dvb_frontend_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *parg) { @@ -883,6 +924,11 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, case FE_SET_FRONTEND: { struct dvb_frontend_tune_settings fetunesettings; + if (dvb_frontend_check_parameters(fe, parg) < 0) { + err = -EINVAL; + break; + } + memcpy (&fepriv->parameters, parg, sizeof (struct dvb_frontend_parameters)); -- cgit v1.2.3-70-g09d2 From 92b3c1ec128695e606fc435d0b68902105d585bb Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Mon, 23 Jul 2007 21:14:10 -0300 Subject: V4L/DVB (5936): tda10023: Remove range check of symbol rate Remove incorrect range check of symbol rate, spotted by the coverity checker and reported by Adrian Bunk. These range checks are performed by dvb_core now. Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda10023.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/tda10023.c b/drivers/media/dvb/frontends/tda10023.c index 4bb06f97938..a00cf0f54ef 100644 --- a/drivers/media/dvb/frontends/tda10023.c +++ b/drivers/media/dvb/frontends/tda10023.c @@ -215,12 +215,6 @@ static int tda10023_set_symbolrate (struct tda10023_state* state, u32 sr) s16 SFIL=0; u16 NDEC = 0; - if (sr > (SYSCLK/(2*4))) - sr=SYSCLK/(2*4); - - if (sr<870000) - sr=870000; - if (sr < (u32)(SYSCLK/98.40)) { NDEC=3; SFIL=1; -- cgit v1.2.3-70-g09d2 From 261efd12fc291e6b3b42011201bfd011484ad90b Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 30 Jul 2007 11:43:55 -0300 Subject: V4L/DVB (5940): Export v4l2_int_device_{, un}register This patch fixes the following build error: <-- snip --> ... MODPOST 2135 modules make[2]: *** [__modpost] Error 1 <-- snip --> Signed-off-by: Adrian Bunk Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-int-device.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/v4l2-int-device.c b/drivers/media/video/v4l2-int-device.c index aa2a8156338..a643730fa3b 100644 --- a/drivers/media/video/v4l2-int-device.c +++ b/drivers/media/video/v4l2-int-device.c @@ -101,6 +101,7 @@ int v4l2_int_device_register(struct v4l2_int_device *d) return 0; } +EXPORT_SYMBOL_GPL(v4l2_int_device_register); void v4l2_int_device_unregister(struct v4l2_int_device *d) { @@ -114,6 +115,7 @@ void v4l2_int_device_unregister(struct v4l2_int_device *d) } mutex_unlock(&mutex); } +EXPORT_SYMBOL_GPL(v4l2_int_device_unregister); /* Adapted from search_extable in extable.c. */ static v4l2_int_ioctl_func *find_ioctl(struct v4l2_int_slave *slave, int cmd, -- cgit v1.2.3-70-g09d2 From af520a3478b59476ed61eddee73948807398e358 Mon Sep 17 00:00:00 2001 From: Andi Drebes Date: Mon, 30 Jul 2007 11:48:10 -0300 Subject: V4L/DVB (5941): Ttpci/budget-av.c: ARRAY_SIZE() This patch replaces an array size calculation done using sizeof with an invocation of the ARRAY_SIZE macro. Tested by compilation on an i386 box using "allyesconfig". Diffed against Linus' git-tree. Signed-off-by: Andi Drebes Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ttpci/budget-av.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c index 0aee7a13a07..3439c9864f6 100644 --- a/drivers/media/dvb/ttpci/budget-av.c +++ b/drivers/media/dvb/ttpci/budget-av.c @@ -1232,7 +1232,7 @@ static struct saa7146_ext_vv vv_data = { .capabilities = 0, // perhaps later: V4L2_CAP_VBI_CAPTURE, but that need tweaking with the saa7113 .flags = 0, .stds = &standard[0], - .num_stds = sizeof(standard) / sizeof(struct saa7146_standard), + .num_stds = ARRAY_SIZE(standard), .ioctls = &ioctls[0], .ioctl = av_ioctl, }; -- cgit v1.2.3-70-g09d2 From 667c7bc0aff18288186f1223784b57f77be7d81b Mon Sep 17 00:00:00 2001 From: Andi Drebes Date: Mon, 30 Jul 2007 11:49:51 -0300 Subject: V4L/DVB (5942): Usb/vp7045.c: ARRAY_SIZE() This patch replaces an array size calculation done using sizeof with an invocation of the ARRAY_SIZE macro. Tested by compilation on an i386 box using "allyesconfig". Diffed against Linus' git-tree. Signed-off-by: Andi Drebes Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/vp7045.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c index 69a46b3607a..5bbd2d5192f 100644 --- a/drivers/media/dvb/dvb-usb/vp7045.c +++ b/drivers/media/dvb/dvb-usb/vp7045.c @@ -159,7 +159,7 @@ static int vp7045_rc_query(struct dvb_usb_device *d, u32 *event, int *state) return 0; } - for (i = 0; i < sizeof(vp7045_rc_keys)/sizeof(struct dvb_usb_rc_key); i++) + for (i = 0; i < ARRAY_SIZE(vp7045_rc_keys); i++) if (vp7045_rc_keys[i].data == key) { *state = REMOTE_KEY_PRESSED; *event = vp7045_rc_keys[i].event; -- cgit v1.2.3-70-g09d2 From 03b7612336560c6799852acaaaeac70e1f00e483 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Mon, 30 Jul 2007 14:58:10 -0300 Subject: V4L/DVB (5946): Use mutex instead of semaphore in the DVB frontend tuning interface The DVB frontend tuning interface uses a semaphore as mutex. Use the mutex API instead of the (binary) semaphore. Signed-off-by: Matthias Kaehlcke Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 10 +++++----- drivers/media/dvb/dvb-core/dvb_frontend.h | 3 ++- 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 384b5b8959c..afe797b75de 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -138,7 +138,7 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status) dprintk ("%s\n", __FUNCTION__); - if (down_interruptible (&events->sem)) + if (mutex_lock_interruptible (&events->mtx)) return; wp = (events->eventw + 1) % MAX_EVENT; @@ -159,7 +159,7 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status) events->eventw = wp; - up (&events->sem); + mutex_unlock(&events->mtx); e->status = status; @@ -197,7 +197,7 @@ static int dvb_frontend_get_event(struct dvb_frontend *fe, return ret; } - if (down_interruptible (&events->sem)) + if (mutex_lock_interruptible (&events->mtx)) return -ERESTARTSYS; memcpy (event, &events->events[events->eventr], @@ -205,7 +205,7 @@ static int dvb_frontend_get_event(struct dvb_frontend *fe, events->eventr = (events->eventr + 1) % MAX_EVENT; - up (&events->sem); + mutex_unlock(&events->mtx); return 0; } @@ -1126,7 +1126,7 @@ int dvb_register_frontend(struct dvb_adapter* dvb, init_MUTEX (&fepriv->sem); init_waitqueue_head (&fepriv->wait_queue); init_waitqueue_head (&fepriv->events.wait_queue); - init_MUTEX (&fepriv->events.sem); + mutex_init(&fepriv->events.mtx); fe->dvb = dvb; fepriv->inversion = INVERSION_OFF; diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index a770a87b9a9..f95de63d0e2 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -35,6 +35,7 @@ #include #include #include +#include #include @@ -142,7 +143,7 @@ struct dvb_fe_events { int eventr; int overflow; wait_queue_head_t wait_queue; - struct semaphore sem; + struct mutex mtx; }; struct dvb_frontend { -- cgit v1.2.3-70-g09d2 From f47623a04dab402fb2c18fe516a174bc02005629 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Sat, 28 Jul 2007 19:17:39 -0300 Subject: V4L/DVB (5947): Adding support for the MT2131 tuner. This adds support for the Microtune MT2131 tuner. 8VSB mode has been tested but QAM support will likely require more register work. Hauppauge have not announced any QAM devices using the MT2131 so QAM remains undone. For legal reasons, Microtune allowed us to write a GPL driver providing we did not document in significant detail any of the registers. This explains the lack of comments or defined on register names. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/Kconfig | 7 + drivers/media/dvb/frontends/Makefile | 1 + drivers/media/dvb/frontends/mt2131.c | 308 ++++++++++++++++++++++++++++++ drivers/media/dvb/frontends/mt2131.h | 49 +++++ drivers/media/dvb/frontends/mt2131_priv.h | 44 +++++ 5 files changed, 409 insertions(+) create mode 100644 drivers/media/dvb/frontends/mt2131.c create mode 100644 drivers/media/dvb/frontends/mt2131.h create mode 100644 drivers/media/dvb/frontends/mt2131_priv.h (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index ba70ad0c3f0..c3c8af771f8 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -329,6 +329,13 @@ config DVB_TUNER_MT2266 help A driver for the silicon baseband tuner MT2266 from Microtune. +config DVB_TUNER_MT2131 + tristate "Microtune MT2131 silicon tuner" + depends on I2C + default m if DVB_FE_CUSTOMISE + help + A driver for the silicon baseband tuner MT2131 from Microtune. + comment "Miscellaneous devices" depends on DVB_CORE diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 217265ca284..a8cfa03b273 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -43,3 +43,4 @@ obj-$(CONFIG_DVB_TUNER_MT2060) += mt2060.o obj-$(CONFIG_DVB_TUNER_MT2266) += mt2266.o obj-$(CONFIG_DVB_TUNER_QT1010) += qt1010.o obj-$(CONFIG_DVB_TUA6100) += tua6100.o +obj-$(CONFIG_DVB_TUNER_MT2131) += mt2131.o diff --git a/drivers/media/dvb/frontends/mt2131.c b/drivers/media/dvb/frontends/mt2131.c new file mode 100644 index 00000000000..4fe1e62c9f0 --- /dev/null +++ b/drivers/media/dvb/frontends/mt2131.c @@ -0,0 +1,308 @@ +/* + * Driver for Microtune MT2131 "QAM/8VSB single chip tuner" + * + * Copyright (c) 2006 Steven Toth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" + +#include "mt2131.h" +#include "mt2131_priv.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); + +#define dprintk(level,fmt, arg...) if (debug >= level) \ + printk(KERN_INFO "%s: " fmt, "mt2131", ## arg) + +static u8 mt2131_config1[] = { + 0x01, + 0x50, 0x00, 0x50, 0x80, 0x00, 0x49, 0xfa, 0x88, + 0x08, 0x77, 0x41, 0x04, 0x00, 0x00, 0x00, 0x32, + 0x7f, 0xda, 0x4c, 0x00, 0x10, 0xaa, 0x78, 0x80, + 0xff, 0x68, 0xa0, 0xff, 0xdd, 0x00, 0x00 +}; + +static u8 mt2131_config2[] = { + 0x10, + 0x7f, 0xc8, 0x0a, 0x5f, 0x00, 0x04 +}; + +static int mt2131_readreg(struct mt2131_priv *priv, u8 reg, u8 *val) +{ + struct i2c_msg msg[2] = { + { .addr = priv->cfg->i2c_address, .flags = 0, .buf = ®, .len = 1 }, + { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, .buf = val, .len = 1 }, + }; + + if (i2c_transfer(priv->i2c, msg, 2) != 2) { + printk(KERN_WARNING "mt2131 I2C read failed\n"); + return -EREMOTEIO; + } + return 0; +} + +static int mt2131_writereg(struct mt2131_priv *priv, u8 reg, u8 val) +{ + u8 buf[2] = { reg, val }; + struct i2c_msg msg = { .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 2 }; + + if (i2c_transfer(priv->i2c, &msg, 1) != 1) { + printk(KERN_WARNING "mt2131 I2C write failed\n"); + return -EREMOTEIO; + } + return 0; +} + +static int mt2131_writeregs(struct mt2131_priv *priv,u8 *buf, u8 len) +{ + struct i2c_msg msg = { .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = len }; + + if (i2c_transfer(priv->i2c, &msg, 1) != 1) { + printk(KERN_WARNING "mt2131 I2C write failed (len=%i)\n",(int)len); + return -EREMOTEIO; + } + return 0; +} + +static int mt2131_set_gpo(struct dvb_frontend *fe, u8 val) +{ + struct mt2131_priv *priv = fe->tuner_priv; + u8 v; + + mt2131_readreg(priv, 0x07, &v); + mt2131_writereg(priv, 0x07, (v & 0xfe) | (val & 0x01)); + + return 0; +} + +static int mt2131_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + struct mt2131_priv *priv; + int ret=0, i; + u32 freq; + u8 if_band_center; + u32 f_lo1,f_lo2; + u32 div1,num1,div2,num2; + u8 b[8]; + u8 lockval = 0; + + priv = fe->tuner_priv; + if (fe->ops.info.type == FE_OFDM) + priv->bandwidth = params->u.ofdm.bandwidth; + else + priv->bandwidth = 0; + + freq = params->frequency / 1000; // Hz -> kHz + dprintk(1, "%s() freq=%d\n", __FUNCTION__, freq); + + f_lo1 = freq + MT2131_IF1 * 1000; + f_lo1 = (f_lo1 / 250) * 250; + f_lo2 = f_lo1 - freq - MT2131_IF2; + + priv->frequency = (f_lo1 - f_lo2 - MT2131_IF2) * 1000, + + /* Frequency LO1 = 16MHz * (DIV1 + NUM1/8192 ) */ + num1 = f_lo1 * 64 / (MT2131_FREF / 128); + div1 = num1 / 8192; + num1 &= 0x1fff; + + /* Frequency LO2 = 16MHz * (DIV2 + NUM2/8192 ) */ + num2 = f_lo2 * 64 / (MT2131_FREF / 128); + div2 = num2 / 8192; + num2 &= 0x1fff; + + if (freq <= 82500) if_band_center = 0x00; else + if (freq <= 137500) if_band_center = 0x01; else + if (freq <= 192500) if_band_center = 0x02; else + if (freq <= 247500) if_band_center = 0x03; else + if (freq <= 302500) if_band_center = 0x04; else + if (freq <= 357500) if_band_center = 0x05; else + if (freq <= 412500) if_band_center = 0x06; else + if (freq <= 467500) if_band_center = 0x07; else + if (freq <= 522500) if_band_center = 0x08; else + if (freq <= 577500) if_band_center = 0x09; else + if (freq <= 632500) if_band_center = 0x0A; else + if (freq <= 687500) if_band_center = 0x0B; else + if (freq <= 742500) if_band_center = 0x0C; else + if (freq <= 797500) if_band_center = 0x0D; else + if (freq <= 852500) if_band_center = 0x0E; else + if (freq <= 907500) if_band_center = 0x0F; else + if (freq <= 962500) if_band_center = 0x10; else + if (freq <= 1017500) if_band_center = 0x11; else + if (freq <= 1072500) if_band_center = 0x12; else if_band_center = 0x13; + + b[0] = 1; + b[1] = (num1 >> 5) & 0xFF; + b[2] = (num1 & 0x1F); + b[3] = div1; + b[4] = (num2 >> 5) & 0xFF; + b[5] = num2 & 0x1F; + b[6] = div2; + + dprintk(1, "IF1: %dMHz IF2: %dMHz\n", MT2131_IF1, MT2131_IF2); + dprintk(1, "PLL freq=%dkHz band=%d\n", (int)freq, (int)if_band_center); + dprintk(1, "PLL f_lo1=%dkHz f_lo2=%dkHz\n", (int)f_lo1, (int)f_lo2); + dprintk(1, "PLL div1=%d num1=%d div2=%d num2=%d\n", + (int)div1, (int)num1, (int)div2, (int)num2); + dprintk(1, "PLL [1..6]: %2x %2x %2x %2x %2x %2x\n", + (int)b[1], (int)b[2], (int)b[3], (int)b[4], (int)b[5], + (int)b[6]); + + ret = mt2131_writeregs(priv,b,7); + if (ret < 0) + return ret; + + mt2131_writereg(priv, 0x0b, if_band_center); + + /* Wait for lock */ + i = 0; + do { + mt2131_readreg(priv, 0x08, &lockval); + if ((lockval & 0x88) == 0x88) + break; + msleep(4); + i++; + } while (i < 10); + + return ret; +} + +static int mt2131_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct mt2131_priv *priv = fe->tuner_priv; + dprintk(1, "%s()\n", __FUNCTION__); + *frequency = priv->frequency; + return 0; +} + +static int mt2131_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct mt2131_priv *priv = fe->tuner_priv; + dprintk(1, "%s()\n", __FUNCTION__); + *bandwidth = priv->bandwidth; + return 0; +} + +static int mt2131_get_status(struct dvb_frontend *fe, u32 *status) +{ + struct mt2131_priv *priv = fe->tuner_priv; + u8 lock_status = 0; + u8 afc_status = 0; + + *status = 0; + + mt2131_readreg(priv, 0x08, &lock_status); + if ((lock_status & 0x88) == 0x88) + *status = TUNER_STATUS_LOCKED; + + mt2131_readreg(priv, 0x09, &afc_status); + dprintk(1, "%s() - LO Status = 0x%x, AFC Status = 0x%x\n", + __FUNCTION__, lock_status, afc_status); + + return 0; +} + +static int mt2131_init(struct dvb_frontend *fe) +{ + struct mt2131_priv *priv = fe->tuner_priv; + int ret; + dprintk(1, "%s()\n", __FUNCTION__); + + if ((ret = mt2131_writeregs(priv, mt2131_config1, sizeof(mt2131_config1))) < 0) + return ret; + + mt2131_writereg(priv, 0x0b, 0x09); + mt2131_writereg(priv, 0x15, 0x47); + mt2131_writereg(priv, 0x07, 0xf2); + mt2131_writereg(priv, 0x0b, 0x01); + + if ((ret = mt2131_writeregs(priv, mt2131_config2, sizeof(mt2131_config2))) < 0) + return ret; + + return ret; +} + +static int mt2131_release(struct dvb_frontend *fe) +{ + dprintk(1, "%s()\n", __FUNCTION__); + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +static const struct dvb_tuner_ops mt2131_tuner_ops = { + .info = { + .name = "Microtune MT2131", + .frequency_min = 48000000, + .frequency_max = 860000000, + .frequency_step = 50000, + }, + + .release = mt2131_release, + .init = mt2131_init, + + .set_params = mt2131_set_params, + .get_frequency = mt2131_get_frequency, + .get_bandwidth = mt2131_get_bandwidth, + .get_status = mt2131_get_status +}; + +struct dvb_frontend * mt2131_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2131_config *cfg, u16 if1) +{ + struct mt2131_priv *priv = NULL; + u8 id = 0; + + dprintk(1, "%s()\n", __FUNCTION__); + + priv = kzalloc(sizeof(struct mt2131_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + priv->cfg = cfg; + priv->bandwidth = 6000000; /* 6MHz */ + priv->i2c = i2c; + + if (mt2131_readreg(priv, 0, &id) != 0) { + kfree(priv); + return NULL; + } + if ( (id != 0x3E) && (id != 0x3F) ) { + printk(KERN_ERR "MT2131: Device not found at addr 0x%02x\n", cfg->i2c_address); + kfree(priv); + return NULL; + } + + printk(KERN_INFO "MT2131: successfully identified at address 0x%02x\n", cfg->i2c_address); + memcpy(&fe->ops.tuner_ops, &mt2131_tuner_ops, sizeof(struct dvb_tuner_ops)); + + fe->tuner_priv = priv; + return fe; +} +EXPORT_SYMBOL(mt2131_attach); + +MODULE_AUTHOR("Steven Toth"); +MODULE_DESCRIPTION("Microtune MT2131 silicon tuner driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/mt2131.h b/drivers/media/dvb/frontends/mt2131.h new file mode 100644 index 00000000000..5d1f281d87b --- /dev/null +++ b/drivers/media/dvb/frontends/mt2131.h @@ -0,0 +1,49 @@ +/* + * Driver for Microtune MT2131 "QAM/8VSB single chip tuner" + * + * Copyright (c) 2006 Steven Toth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __MT2131_H__ +#define __MT2131_H__ + +struct dvb_frontend; +struct i2c_adapter; + +struct mt2131_config { + u8 i2c_address; + u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */ +}; + +#if defined(CONFIG_DVB_TUNER_MT2131) || defined(CONFIG_DVB_TUNER_MT2131_MODULE) +extern struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct mt2131_config *cfg, + u16 if1); +#else +static inline struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct mt2131_config *cfg, + u16 if1) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + return NULL; +} +#endif // CONFIG_DVB_TUNER_MT2131 + +#endif // __MT2131_H__ diff --git a/drivers/media/dvb/frontends/mt2131_priv.h b/drivers/media/dvb/frontends/mt2131_priv.h new file mode 100644 index 00000000000..fe6333b49c9 --- /dev/null +++ b/drivers/media/dvb/frontends/mt2131_priv.h @@ -0,0 +1,44 @@ +/* + * Driver for Microtune MT2131 "QAM/8VSB single chip tuner" + * + * Copyright (c) 2006 Steven Toth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef MT2131_PRIV_H +#define MT2131_PRIV_H + +/* Regs */ +#define MT2131_PWR 0x07 +#define MT2131_UPC_1 0x0b +#define MT2131_AGC_RL 0x10 +#define MT2131_MISC_2 0x15 + +/* frequency values in KHz */ +#define MT2131_IF1 1220 +#define MT2131_IF2 44000 +#define MT2131_FREF 16000 + +struct mt2131_priv { + struct mt2131_config *cfg; + struct i2c_adapter *i2c; + + u32 frequency; + u32 bandwidth; +}; + +#endif -- cgit v1.2.3-70-g09d2 From 89885558ada9e076b48f4b6887e252e13e7eaf74 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Sat, 28 Jul 2007 19:34:52 -0300 Subject: V4L/DVB (5948): Adding support for the S5H1409/CX24227 8VSB/QAM demodulator. This patch adds support for the Samsung S5H1409 demodulator, also known as the Conexant CX24227 demodulator. 8VSB mode has been tested and QAM has been implemented based on the spec, although it's untested. The S5H1409 / CX24227 appears on various Hauppauge boards. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/Kconfig | 8 + drivers/media/dvb/frontends/Makefile | 1 + drivers/media/dvb/frontends/s5h1409.c | 715 ++++++++++++++++++++++++++++++++++ drivers/media/dvb/frontends/s5h1409.h | 68 ++++ 4 files changed, 792 insertions(+) create mode 100644 drivers/media/dvb/frontends/s5h1409.c create mode 100644 drivers/media/dvb/frontends/s5h1409.h (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index c3c8af771f8..faf9fe3c9cc 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -283,6 +283,14 @@ config DVB_LGDT330X An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want to support this frontend. +config DVB_S5H1409 + tristate "Samsung S5H1409 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want + to support this frontend. + comment "Tuners/PLL support" depends on DVB_CORE diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index a8cfa03b273..c46b9d8e931 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -44,3 +44,4 @@ obj-$(CONFIG_DVB_TUNER_MT2266) += mt2266.o obj-$(CONFIG_DVB_TUNER_QT1010) += qt1010.o obj-$(CONFIG_DVB_TUA6100) += tua6100.o obj-$(CONFIG_DVB_TUNER_MT2131) += mt2131.o +obj-$(CONFIG_DVB_S5H1409) += s5h1409.o diff --git a/drivers/media/dvb/frontends/s5h1409.c b/drivers/media/dvb/frontends/s5h1409.c new file mode 100644 index 00000000000..4b77390f5d4 --- /dev/null +++ b/drivers/media/dvb/frontends/s5h1409.c @@ -0,0 +1,715 @@ +/* + Samsung S5H1409 VSB/QAM demodulator driver + + Copyright (C) 2006 Steven Toth + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include +#include +#include +#include +#include "dvb_frontend.h" +#include "dvb-pll.h" +#include "s5h1409.h" + +struct s5h1409_state { + + struct i2c_adapter* i2c; + + /* configuration settings */ + const struct s5h1409_config* config; + + struct dvb_frontend frontend; + + /* previous uncorrected block counter */ + fe_modulation_t current_modulation; + + u32 current_frequency; +}; + +static int debug = 0; +#define dprintk if (debug) printk + +/* Register values to initialise the demod, this will set VSB by default */ +static struct init_tab { + u8 reg; + u16 data; +} init_tab[] = { + { 0x00, 0x0071, }, + { 0x01, 0x3213, }, + { 0x09, 0x0025, }, + { 0x1c, 0x001d, }, + { 0x1f, 0x002d, }, + { 0x20, 0x001d, }, + { 0x22, 0x0022, }, + { 0x23, 0x0020, }, + { 0x29, 0x110f, }, + { 0x2a, 0x10b4, }, + { 0x2b, 0x10ae, }, + { 0x2c, 0x0031, }, + { 0x31, 0x010d, }, + { 0x32, 0x0100, }, + { 0x44, 0x0510, }, + { 0x54, 0x0104, }, + { 0x58, 0x2222, }, + { 0x59, 0x1162, }, + { 0x5a, 0x3211, }, + { 0x5d, 0x0370, }, + { 0x5e, 0x0296, }, + { 0x61, 0x0010, }, + { 0x63, 0x4a00, }, + { 0x65, 0x0800, }, + { 0x71, 0x0003, }, + { 0x72, 0x0470, }, + { 0x81, 0x0002, }, + { 0x82, 0x0600, }, + { 0x86, 0x0002, }, + { 0x8a, 0x2c38, }, + { 0x8b, 0x2a37, }, + { 0x92, 0x302f, }, + { 0x93, 0x3332, }, + { 0x96, 0x000c, }, + { 0x99, 0x0101, }, + { 0x9c, 0x2e37, }, + { 0x9d, 0x2c37, }, + { 0x9e, 0x2c37, }, + { 0xab, 0x0100, }, + { 0xac, 0x1003, }, + { 0xad, 0x103f, }, + { 0xe2, 0x0100, }, + { 0x28, 0x1010, }, + { 0xb1, 0x000e, }, +}; + +/* VSB SNR lookup table */ +static struct vsb_snr_tab { + u16 val; + u16 data; +} vsb_snr_tab[] = { + { 1023, 770, }, + { 923, 300, }, + { 918, 295, }, + { 915, 290, }, + { 911, 285, }, + { 906, 280, }, + { 901, 275, }, + { 896, 270, }, + { 891, 265, }, + { 885, 260, }, + { 879, 255, }, + { 873, 250, }, + { 864, 245, }, + { 858, 240, }, + { 850, 235, }, + { 841, 230, }, + { 832, 225, }, + { 823, 220, }, + { 812, 215, }, + { 802, 210, }, + { 788, 205, }, + { 778, 200, }, + { 767, 195, }, + { 753, 190, }, + { 740, 185, }, + { 725, 180, }, + { 707, 175, }, + { 689, 170, }, + { 671, 165, }, + { 656, 160, }, + { 637, 155, }, + { 616, 150, }, + { 542, 145, }, + { 519, 140, }, + { 507, 135, }, + { 497, 130, }, + { 492, 125, }, + { 474, 120, }, + { 300, 111, }, + { 0, 0, }, +}; + +/* QAM64 SNR lookup table */ +static struct qam64_snr_tab { + u16 val; + u16 data; +} qam64_snr_tab[] = { + { 12, 300, }, + { 15, 290, }, + { 18, 280, }, + { 22, 270, }, + { 23, 268, }, + { 24, 266, }, + { 25, 264, }, + { 27, 262, }, + { 28, 260, }, + { 29, 258, }, + { 30, 256, }, + { 32, 254, }, + { 33, 252, }, + { 34, 250, }, + { 35, 249, }, + { 36, 248, }, + { 37, 247, }, + { 38, 246, }, + { 39, 245, }, + { 40, 244, }, + { 41, 243, }, + { 42, 241, }, + { 43, 240, }, + { 44, 239, }, + { 45, 238, }, + { 46, 237, }, + { 47, 236, }, + { 48, 235, }, + { 49, 234, }, + { 50, 233, }, + { 51, 232, }, + { 52, 231, }, + { 53, 230, }, + { 55, 229, }, + { 56, 228, }, + { 57, 227, }, + { 58, 226, }, + { 59, 225, }, + { 60, 224, }, + { 62, 223, }, + { 63, 222, }, + { 65, 221, }, + { 66, 220, }, + { 68, 219, }, + { 69, 218, }, + { 70, 217, }, + { 72, 216, }, + { 73, 215, }, + { 75, 214, }, + { 76, 213, }, + { 78, 212, }, + { 80, 211, }, + { 81, 210, }, + { 83, 209, }, + { 84, 208, }, + { 85, 207, }, + { 87, 206, }, + { 89, 205, }, + { 91, 204, }, + { 93, 203, }, + { 95, 202, }, + { 96, 201, }, + { 104, 200, }, +}; + +/* QAM256 SNR lookup table */ +static struct qam256_snr_tab { + u16 val; + u16 data; +} qam256_snr_tab[] = { + { 12, 400, }, + { 13, 390, }, + { 15, 380, }, + { 17, 360, }, + { 19, 350, }, + { 22, 348, }, + { 23, 346, }, + { 24, 344, }, + { 25, 342, }, + { 26, 340, }, + { 27, 336, }, + { 28, 334, }, + { 29, 332, }, + { 30, 330, }, + { 31, 328, }, + { 32, 326, }, + { 33, 325, }, + { 34, 322, }, + { 35, 320, }, + { 37, 318, }, + { 39, 316, }, + { 40, 314, }, + { 41, 312, }, + { 42, 310, }, + { 43, 308, }, + { 46, 306, }, + { 47, 304, }, + { 49, 302, }, + { 51, 300, }, + { 53, 298, }, + { 54, 297, }, + { 55, 296, }, + { 56, 295, }, + { 57, 294, }, + { 59, 293, }, + { 60, 292, }, + { 61, 291, }, + { 63, 290, }, + { 64, 289, }, + { 65, 288, }, + { 66, 287, }, + { 68, 286, }, + { 69, 285, }, + { 71, 284, }, + { 72, 283, }, + { 74, 282, }, + { 75, 281, }, + { 76, 280, }, + { 77, 279, }, + { 78, 278, }, + { 81, 277, }, + { 83, 276, }, + { 84, 275, }, + { 86, 274, }, + { 87, 273, }, + { 89, 272, }, + { 90, 271, }, + { 92, 270, }, + { 93, 269, }, + { 95, 268, }, + { 96, 267, }, + { 98, 266, }, + { 100, 265, }, + { 102, 264, }, + { 104, 263, }, + { 105, 262, }, + { 106, 261, }, + { 110, 260, }, +}; + +/* 8 bit registers, 16 bit values */ +static int s5h1409_writereg(struct s5h1409_state* state, u8 reg, u16 data) +{ + int ret; + u8 buf [] = { reg, data >> 8, data & 0xff }; + + struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 3 }; + + ret = i2c_transfer(state->i2c, &msg, 1); + + if (ret != 1) + printk("%s: writereg error (reg == 0x%02x, val == 0x%04x, ret == %i)\n", + __FUNCTION__, reg, data, ret); + + return (ret != 1) ? -1 : 0; +} + +static u16 s5h1409_readreg(struct s5h1409_state* state, u8 reg) +{ + int ret; + u8 b0 [] = { reg }; + u8 b1 [] = { 0, 0 }; + + struct i2c_msg msg [] = { + { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 2 } }; + + ret = i2c_transfer(state->i2c, msg, 2); + + if (ret != 2) + printk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret) + ; + return (b1[0] << 8) | b1[1]; +} + +static int s5h1409_softreset(struct dvb_frontend* fe) +{ + struct s5h1409_state* state = fe->demodulator_priv; + + dprintk("%s()\n", __FUNCTION__); + + s5h1409_writereg(state, 0xf5, 0); + s5h1409_writereg(state, 0xf5, 1); + return 0; +} + +static int s5h1409_set_if_freq(struct dvb_frontend* fe, int KHz) +{ + struct s5h1409_state* state = fe->demodulator_priv; + int ret = 0; + + dprintk("%s(%d KHz)\n", __FUNCTION__, KHz); + + if( (KHz == 44000) || (KHz == 5380) ) + { + s5h1409_writereg(state, 0x87, 0x01be); + s5h1409_writereg(state, 0x88, 0x0436); + s5h1409_writereg(state, 0x89, 0x054d); + } else { + printk("%s() Invalid arg = %d KHz\n", __FUNCTION__, KHz); + ret = -1; + } + + return ret; +} + +static int s5h1409_set_spectralinversion(struct dvb_frontend* fe, int inverted) +{ + struct s5h1409_state* state = fe->demodulator_priv; + + dprintk("%s()\n", __FUNCTION__); + + if(inverted == 1) + return s5h1409_writereg(state, 0x1b, 0x1101); /* Inverted */ + else + return s5h1409_writereg(state, 0x1b, 0x0110); /* Normal */ +} + +static int s5h1409_enable_modulation(struct dvb_frontend* fe, fe_modulation_t m) +{ + struct s5h1409_state* state = fe->demodulator_priv; + + dprintk("%s(0x%08x)\n", __FUNCTION__, m); + + switch(m) { + case VSB_8: + dprintk("%s() VSB_8\n", __FUNCTION__); + s5h1409_writereg(state, 0xf4, 0); + break; + case QAM_64: + dprintk("%s() QAM_64\n", __FUNCTION__); + s5h1409_writereg(state, 0xf4, 1); + s5h1409_writereg(state, 0x85, 0x100); + break; + case QAM_256: + dprintk("%s() QAM_256\n", __FUNCTION__); + s5h1409_writereg(state, 0xf4, 1); + s5h1409_writereg(state, 0x85, 0x101); + break; + default: + dprintk("%s() Invalid modulation\n", __FUNCTION__); + return -EINVAL; + } + + state->current_modulation = m; + s5h1409_softreset(fe); + + return 0; +} + +static int s5h1409_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) +{ + struct s5h1409_state* state = fe->demodulator_priv; + + dprintk("%s(%d)\n", __FUNCTION__, enable); + + if (enable) + return s5h1409_writereg(state, 0xf3, 1); + else + return s5h1409_writereg(state, 0xf3, 0); +} + +static int s5h1409_set_gpio(struct dvb_frontend* fe, int enable) +{ + struct s5h1409_state* state = fe->demodulator_priv; + + dprintk("%s(%d)\n", __FUNCTION__, enable); + + if (enable) + return s5h1409_writereg(state, 0xe3, 0x1100); + else + return s5h1409_writereg(state, 0xe3, 0); +} + +static int s5h1409_sleep(struct dvb_frontend* fe, int enable) +{ + struct s5h1409_state* state = fe->demodulator_priv; + + dprintk("%s(%d)\n", __FUNCTION__, enable); + + return s5h1409_writereg(state, 0xf2, enable); +} + +static int s5h1409_register_reset(struct dvb_frontend* fe) +{ + struct s5h1409_state* state = fe->demodulator_priv; + + dprintk("%s()\n", __FUNCTION__); + + return s5h1409_writereg(state, 0xfa, 0); +} + +/* Talk to the demod, set the FEC, GUARD, QAM settings etc */ +static int s5h1409_set_frontend (struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct s5h1409_state* state = fe->demodulator_priv; + + dprintk("%s(frequency=%d)\n", __FUNCTION__, p->frequency); + + s5h1409_softreset(fe); + + state->current_frequency = p->frequency; + + s5h1409_enable_modulation(fe, p->u.vsb.modulation); + + if (fe->ops.tuner_ops.set_params) { + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); + fe->ops.tuner_ops.set_params(fe, p); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + } + + return 0; +} + +/* Reset the demod hardware and reset all of the configuration registers + to a default state. */ +static int s5h1409_init (struct dvb_frontend* fe) +{ + int i; + + struct s5h1409_state* state = fe->demodulator_priv; + dprintk("%s()\n", __FUNCTION__); + + s5h1409_sleep(fe, 0); + s5h1409_register_reset(fe); + + for (i=0; icurrent_modulation = VSB_8; + + if (state->config->output_mode == S5H1409_SERIAL_OUTPUT) + s5h1409_writereg(state, 0xab, 0x100); /* Serial */ + else + s5h1409_writereg(state, 0xab, 0x0); /* Parallel */ + + s5h1409_set_spectralinversion(fe, state->config->inversion); + s5h1409_set_if_freq(fe, state->config->if_freq); + s5h1409_set_gpio(fe, state->config->gpio); + s5h1409_softreset(fe); + + /* Note: Leaving the I2C gate open here. */ + s5h1409_i2c_gate_ctrl(fe, 1); + + return 0; +} + +static int s5h1409_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + struct s5h1409_state* state = fe->demodulator_priv; + u16 reg; + u32 tuner_status = 0; + + *status = 0; + + /* Get the demodulator status */ + reg = s5h1409_readreg(state, 0xf1); + if(reg & 0x1000) + *status |= FE_HAS_VITERBI; + if(reg & 0x8000) + *status |= FE_HAS_LOCK | FE_HAS_SYNC; + + switch(state->config->status_mode) { + case S5H1409_DEMODLOCKING: + if (*status & FE_HAS_VITERBI) + *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; + break; + case S5H1409_TUNERLOCKING: + /* Get the tuner status */ + if (fe->ops.tuner_ops.get_status) { + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); + + fe->ops.tuner_ops.get_status(fe, &tuner_status); + + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + } + if (tuner_status) + *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; + break; + } + + dprintk("%s() status 0x%08x\n", __FUNCTION__, *status); + + return 0; +} + +static int s5h1409_qam256_lookup_snr(struct dvb_frontend* fe, u16* snr, u16 v) +{ + int i, ret = -EINVAL; + dprintk("%s()\n", __FUNCTION__); + + for (i=0; i vsb_snr_tab[i].val) { + *snr = vsb_snr_tab[i].data; + ret = 0; + break; + } + } + dprintk("%s() snr=%d\n", __FUNCTION__, *snr); + return ret; +} + +static int s5h1409_read_snr(struct dvb_frontend* fe, u16* snr) +{ + struct s5h1409_state* state = fe->demodulator_priv; + u16 reg; + dprintk("%s()\n", __FUNCTION__); + + reg = s5h1409_readreg(state, 0xf1) & 0x1ff; + + switch(state->current_modulation) { + case QAM_64: + return s5h1409_qam64_lookup_snr(fe, snr, reg); + case QAM_256: + return s5h1409_qam256_lookup_snr(fe, snr, reg); + case VSB_8: + return s5h1409_vsb_lookup_snr(fe, snr, reg); + default: + break; + } + + return -EINVAL; +} + +static int s5h1409_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength) +{ + return s5h1409_read_snr(fe, signal_strength); +} + +static int s5h1409_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +{ + struct s5h1409_state* state = fe->demodulator_priv; + + *ucblocks = s5h1409_readreg(state, 0xb5); + + return 0; +} + +static int s5h1409_read_ber(struct dvb_frontend* fe, u32* ber) +{ + return s5h1409_read_ucblocks(fe, ber); +} + +static int s5h1409_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct s5h1409_state* state = fe->demodulator_priv; + + p->frequency = state->current_frequency; + p->u.vsb.modulation = state->current_modulation; + + return 0; +} + +static int s5h1409_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) +{ + tune->min_delay_ms = 1000; + return 0; +} + +static void s5h1409_release(struct dvb_frontend* fe) +{ + struct s5h1409_state* state = fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops s5h1409_ops; + +struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config, + struct i2c_adapter* i2c) +{ + struct s5h1409_state* state = NULL; + + /* allocate memory for the internal state */ + state = kmalloc(sizeof(struct s5h1409_state), GFP_KERNEL); + if (state == NULL) + goto error; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + state->current_modulation = 0; + + /* check if the demod exists */ + if (s5h1409_readreg(state, 0x04) != 0x0066) + goto error; + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &s5h1409_ops, sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + + /* Note: Leaving the I2C gate open here. */ + s5h1409_writereg(state, 0xf3, 1); + + return &state->frontend; + +error: + kfree(state); + return NULL; +} + +static struct dvb_frontend_ops s5h1409_ops = { + + .info = { + .name = "Samsung S5H1409 QAM/8VSB Frontend", + .type = FE_ATSC, + .frequency_min = 54000000, + .frequency_max = 858000000, + .frequency_stepsize = 62500, + .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB + }, + + .init = s5h1409_init, + .i2c_gate_ctrl = s5h1409_i2c_gate_ctrl, + .set_frontend = s5h1409_set_frontend, + .get_frontend = s5h1409_get_frontend, + .get_tune_settings = s5h1409_get_tune_settings, + .read_status = s5h1409_read_status, + .read_ber = s5h1409_read_ber, + .read_signal_strength = s5h1409_read_signal_strength, + .read_snr = s5h1409_read_snr, + .read_ucblocks = s5h1409_read_ucblocks, + .release = s5h1409_release, +}; + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Enable verbose debug messages"); + +MODULE_DESCRIPTION("Samsung S5H1409 QAM-B/ATSC Demodulator driver"); +MODULE_AUTHOR("Steven Toth"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(s5h1409_attach); diff --git a/drivers/media/dvb/frontends/s5h1409.h b/drivers/media/dvb/frontends/s5h1409.h new file mode 100644 index 00000000000..6e9b9f24b60 --- /dev/null +++ b/drivers/media/dvb/frontends/s5h1409.h @@ -0,0 +1,68 @@ +/* + Samsung S5H1409 VSB/QAM demodulator driver + + Copyright (C) 2006 Steven Toth + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef S5H1409_H +#define S5H1409_H + +#include + +struct s5h1409_config +{ + /* the demodulator's i2c address */ + u8 demod_address; + + /* serial/parallel output */ +#define S5H1409_PARALLEL_OUTPUT 0 +#define S5H1409_SERIAL_OUTPUT 1 + u8 output_mode; + + /* GPIO Setting */ +#define S5H1409_GPIO_OFF 0 +#define S5H1409_GPIO_ON 1 + u8 gpio; + + /* IF Freq in KHz */ + u16 if_freq; + + /* Spectral Inversion */ +#define S5H1409_INVERSION_OFF 0 +#define S5H1409_INVERSION_ON 1 + u8 inversion; + + /* Return lock status based on tuner lock, or demod lock */ +#define S5H1409_TUNERLOCKING 0 +#define S5H1409_DEMODLOCKING 1 + u8 status_mode; +}; + +#if defined(CONFIG_DVB_S5H1409) || defined(CONFIG_DVB_S5H1409_MODULE) +extern struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config, + struct i2c_adapter* i2c); +#else +static inline struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config, + struct i2c_adapter* i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + return NULL; +} +#endif // CONFIG_DVB_S5H1409 + +#endif // S5H1409_H -- cgit v1.2.3-70-g09d2 From a45c92756ed60bc89528701ac512e954acd23b9e Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Wed, 21 Mar 2007 12:03:23 -0300 Subject: V4L/DVB (5949): s5h1409: use ARRAY_SIZE macro when appropriate Use ARRAY_SIZE macro already defined in kernel.h Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/s5h1409.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/s5h1409.c b/drivers/media/dvb/frontends/s5h1409.c index 4b77390f5d4..25cf78142d9 100644 --- a/drivers/media/dvb/frontends/s5h1409.c +++ b/drivers/media/dvb/frontends/s5h1409.c @@ -476,7 +476,7 @@ static int s5h1409_init (struct dvb_frontend* fe) s5h1409_sleep(fe, 0); s5h1409_register_reset(fe); - for (i=0; i vsb_snr_tab[i].val) { *snr = vsb_snr_tab[i].data; ret = 0; -- cgit v1.2.3-70-g09d2 From 3873dd041465799cfdeb642531c0ade4fb6614e5 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 28 Jul 2007 20:02:55 -0300 Subject: V4L/DVB (5950): whitespace cleanup for mt2131 and s5h1409 - trivial whitespace cleanups - add "c-basic-offset: 8" to enforce tabbing style in emacs Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/mt2131.c | 46 ++++++++++++++++++++--------- drivers/media/dvb/frontends/mt2131.h | 9 ++++-- drivers/media/dvb/frontends/mt2131_priv.h | 11 +++++-- drivers/media/dvb/frontends/s5h1409.c | 48 ++++++++++++++++++++----------- drivers/media/dvb/frontends/s5h1409.h | 15 ++++++---- 5 files changed, 88 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/mt2131.c b/drivers/media/dvb/frontends/mt2131.c index 4fe1e62c9f0..375dfa16681 100644 --- a/drivers/media/dvb/frontends/mt2131.c +++ b/drivers/media/dvb/frontends/mt2131.c @@ -53,8 +53,10 @@ static u8 mt2131_config2[] = { static int mt2131_readreg(struct mt2131_priv *priv, u8 reg, u8 *val) { struct i2c_msg msg[2] = { - { .addr = priv->cfg->i2c_address, .flags = 0, .buf = ®, .len = 1 }, - { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, .buf = val, .len = 1 }, + { .addr = priv->cfg->i2c_address, .flags = 0, + .buf = ®, .len = 1 }, + { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, + .buf = val, .len = 1 }, }; if (i2c_transfer(priv->i2c, msg, 2) != 2) { @@ -67,7 +69,8 @@ static int mt2131_readreg(struct mt2131_priv *priv, u8 reg, u8 *val) static int mt2131_writereg(struct mt2131_priv *priv, u8 reg, u8 val) { u8 buf[2] = { reg, val }; - struct i2c_msg msg = { .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 2 }; + struct i2c_msg msg = { .addr = priv->cfg->i2c_address, .flags = 0, + .buf = buf, .len = 2 }; if (i2c_transfer(priv->i2c, &msg, 1) != 1) { printk(KERN_WARNING "mt2131 I2C write failed\n"); @@ -78,10 +81,12 @@ static int mt2131_writereg(struct mt2131_priv *priv, u8 reg, u8 val) static int mt2131_writeregs(struct mt2131_priv *priv,u8 *buf, u8 len) { - struct i2c_msg msg = { .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = len }; + struct i2c_msg msg = { .addr = priv->cfg->i2c_address, + .flags = 0, .buf = buf, .len = len }; if (i2c_transfer(priv->i2c, &msg, 1) != 1) { - printk(KERN_WARNING "mt2131 I2C write failed (len=%i)\n",(int)len); + printk(KERN_WARNING "mt2131 I2C write failed (len=%i)\n", + (int)len); return -EREMOTEIO; } return 0; @@ -98,14 +103,15 @@ static int mt2131_set_gpo(struct dvb_frontend *fe, u8 val) return 0; } -static int mt2131_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +static int mt2131_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) { struct mt2131_priv *priv; int ret=0, i; u32 freq; u8 if_band_center; - u32 f_lo1,f_lo2; - u32 div1,num1,div2,num2; + u32 f_lo1, f_lo2; + u32 div1, num1, div2, num2; u8 b[8]; u8 lockval = 0; @@ -231,7 +237,8 @@ static int mt2131_init(struct dvb_frontend *fe) int ret; dprintk(1, "%s()\n", __FUNCTION__); - if ((ret = mt2131_writeregs(priv, mt2131_config1, sizeof(mt2131_config1))) < 0) + if ((ret = mt2131_writeregs(priv, mt2131_config1, + sizeof(mt2131_config1))) < 0) return ret; mt2131_writereg(priv, 0x0b, 0x09); @@ -239,7 +246,8 @@ static int mt2131_init(struct dvb_frontend *fe) mt2131_writereg(priv, 0x07, 0xf2); mt2131_writereg(priv, 0x0b, 0x01); - if ((ret = mt2131_writeregs(priv, mt2131_config2, sizeof(mt2131_config2))) < 0) + if ((ret = mt2131_writeregs(priv, mt2131_config2, + sizeof(mt2131_config2))) < 0) return ret; return ret; @@ -270,7 +278,9 @@ static const struct dvb_tuner_ops mt2131_tuner_ops = { .get_status = mt2131_get_status }; -struct dvb_frontend * mt2131_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2131_config *cfg, u16 if1) +struct dvb_frontend * mt2131_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct mt2131_config *cfg, u16 if1) { struct mt2131_priv *priv = NULL; u8 id = 0; @@ -290,13 +300,16 @@ struct dvb_frontend * mt2131_attach(struct dvb_frontend *fe, struct i2c_adapter return NULL; } if ( (id != 0x3E) && (id != 0x3F) ) { - printk(KERN_ERR "MT2131: Device not found at addr 0x%02x\n", cfg->i2c_address); + printk(KERN_ERR "MT2131: Device not found at addr 0x%02x\n", + cfg->i2c_address); kfree(priv); return NULL; } - printk(KERN_INFO "MT2131: successfully identified at address 0x%02x\n", cfg->i2c_address); - memcpy(&fe->ops.tuner_ops, &mt2131_tuner_ops, sizeof(struct dvb_tuner_ops)); + printk(KERN_INFO "MT2131: successfully identified at address 0x%02x\n", + cfg->i2c_address); + memcpy(&fe->ops.tuner_ops, &mt2131_tuner_ops, + sizeof(struct dvb_tuner_ops)); fe->tuner_priv = priv; return fe; @@ -306,3 +319,8 @@ EXPORT_SYMBOL(mt2131_attach); MODULE_AUTHOR("Steven Toth"); MODULE_DESCRIPTION("Microtune MT2131 silicon tuner driver"); MODULE_LICENSE("GPL"); + +/* + * Local variables: + * c-basic-offset: 8 + */ diff --git a/drivers/media/dvb/frontends/mt2131.h b/drivers/media/dvb/frontends/mt2131.h index 5d1f281d87b..608f1f66c9e 100644 --- a/drivers/media/dvb/frontends/mt2131.h +++ b/drivers/media/dvb/frontends/mt2131.h @@ -44,6 +44,11 @@ static inline struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe, printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); return NULL; } -#endif // CONFIG_DVB_TUNER_MT2131 +#endif /* CONFIG_DVB_TUNER_MT2131 */ -#endif // __MT2131_H__ +#endif /* __MT2131_H__ */ + +/* + * Local variables: + * c-basic-offset: 8 + */ diff --git a/drivers/media/dvb/frontends/mt2131_priv.h b/drivers/media/dvb/frontends/mt2131_priv.h index fe6333b49c9..e930759c2c0 100644 --- a/drivers/media/dvb/frontends/mt2131_priv.h +++ b/drivers/media/dvb/frontends/mt2131_priv.h @@ -19,8 +19,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#ifndef MT2131_PRIV_H -#define MT2131_PRIV_H +#ifndef __MT2131_PRIV_H__ +#define __MT2131_PRIV_H__ /* Regs */ #define MT2131_PWR 0x07 @@ -41,4 +41,9 @@ struct mt2131_priv { u32 bandwidth; }; -#endif +#endif /* __MT2131_PRIV_H__ */ + +/* + * Local variables: + * c-basic-offset: 8 + */ diff --git a/drivers/media/dvb/frontends/s5h1409.c b/drivers/media/dvb/frontends/s5h1409.c index 25cf78142d9..30e8a705fad 100644 --- a/drivers/media/dvb/frontends/s5h1409.c +++ b/drivers/media/dvb/frontends/s5h1409.c @@ -296,13 +296,14 @@ static int s5h1409_writereg(struct s5h1409_state* state, u8 reg, u16 data) int ret; u8 buf [] = { reg, data >> 8, data & 0xff }; - struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 3 }; + struct i2c_msg msg = { .addr = state->config->demod_address, + .flags = 0, .buf = buf, .len = 3 }; ret = i2c_transfer(state->i2c, &msg, 1); if (ret != 1) - printk("%s: writereg error (reg == 0x%02x, val == 0x%04x, ret == %i)\n", - __FUNCTION__, reg, data, ret); + printk("%s: writereg error (reg == 0x%02x, val == 0x%04x, " + "ret == %i)\n", __FUNCTION__, reg, data, ret); return (ret != 1) ? -1 : 0; } @@ -314,14 +315,15 @@ static u16 s5h1409_readreg(struct s5h1409_state* state, u8 reg) u8 b1 [] = { 0, 0 }; struct i2c_msg msg [] = { - { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, - { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 2 } }; + { .addr = state->config->demod_address, .flags = 0, + .buf = b0, .len = 1 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, + .buf = b1, .len = 2 } }; ret = i2c_transfer(state->i2c, msg, 2); if (ret != 2) - printk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret) - ; + printk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret); return (b1[0] << 8) | b1[1]; } @@ -343,8 +345,7 @@ static int s5h1409_set_if_freq(struct dvb_frontend* fe, int KHz) dprintk("%s(%d KHz)\n", __FUNCTION__, KHz); - if( (KHz == 44000) || (KHz == 5380) ) - { + if( (KHz == 44000) || (KHz == 5380) ) { s5h1409_writereg(state, 0x87, 0x01be); s5h1409_writereg(state, 0x88, 0x0436); s5h1409_writereg(state, 0x89, 0x054d); @@ -368,7 +369,8 @@ static int s5h1409_set_spectralinversion(struct dvb_frontend* fe, int inverted) return s5h1409_writereg(state, 0x1b, 0x0110); /* Normal */ } -static int s5h1409_enable_modulation(struct dvb_frontend* fe, fe_modulation_t m) +static int s5h1409_enable_modulation(struct dvb_frontend* fe, + fe_modulation_t m) { struct s5h1409_state* state = fe->demodulator_priv; @@ -443,7 +445,8 @@ static int s5h1409_register_reset(struct dvb_frontend* fe) } /* Talk to the demod, set the FEC, GUARD, QAM settings etc */ -static int s5h1409_set_frontend (struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int s5h1409_set_frontend (struct dvb_frontend* fe, + struct dvb_frontend_parameters *p) { struct s5h1409_state* state = fe->demodulator_priv; @@ -521,11 +524,13 @@ static int s5h1409_read_status(struct dvb_frontend* fe, fe_status_t* status) case S5H1409_TUNERLOCKING: /* Get the tuner status */ if (fe->ops.tuner_ops.get_status) { - if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); fe->ops.tuner_ops.get_status(fe, &tuner_status); - if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); } if (tuner_status) *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; @@ -605,7 +610,8 @@ static int s5h1409_read_snr(struct dvb_frontend* fe, u16* snr) return -EINVAL; } -static int s5h1409_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength) +static int s5h1409_read_signal_strength(struct dvb_frontend* fe, + u16* signal_strength) { return s5h1409_read_snr(fe, signal_strength); } @@ -624,7 +630,8 @@ static int s5h1409_read_ber(struct dvb_frontend* fe, u32* ber) return s5h1409_read_ucblocks(fe, ber); } -static int s5h1409_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int s5h1409_get_frontend(struct dvb_frontend* fe, + struct dvb_frontend_parameters *p) { struct s5h1409_state* state = fe->demodulator_priv; @@ -634,7 +641,8 @@ static int s5h1409_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par return 0; } -static int s5h1409_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) +static int s5h1409_get_tune_settings(struct dvb_frontend* fe, + struct dvb_frontend_tune_settings *tune) { tune->min_delay_ms = 1000; return 0; @@ -668,7 +676,8 @@ struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config, goto error; /* create dvb_frontend */ - memcpy(&state->frontend.ops, &s5h1409_ops, sizeof(struct dvb_frontend_ops)); + memcpy(&state->frontend.ops, &s5h1409_ops, + sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; /* Note: Leaving the I2C gate open here. */ @@ -713,3 +722,8 @@ MODULE_AUTHOR("Steven Toth"); MODULE_LICENSE("GPL"); EXPORT_SYMBOL(s5h1409_attach); + +/* + * Local variables: + * c-basic-offset: 8 + */ diff --git a/drivers/media/dvb/frontends/s5h1409.h b/drivers/media/dvb/frontends/s5h1409.h index 6e9b9f24b60..bccfd8a6fbd 100644 --- a/drivers/media/dvb/frontends/s5h1409.h +++ b/drivers/media/dvb/frontends/s5h1409.h @@ -19,8 +19,8 @@ */ -#ifndef S5H1409_H -#define S5H1409_H +#ifndef __S5H1409_H__ +#define __S5H1409_H__ #include @@ -58,11 +58,16 @@ extern struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config, struct i2c_adapter* i2c); #else static inline struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config, - struct i2c_adapter* i2c) + struct i2c_adapter* i2c) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); return NULL; } -#endif // CONFIG_DVB_S5H1409 +#endif /* CONFIG_DVB_S5H1409 */ -#endif // S5H1409_H +#endif /* __S5H1409_H__ */ + +/* + * Local variables: + * c-basic-offset: 8 + */ -- cgit v1.2.3-70-g09d2 From b2a657603e7285bf05b86ad198111b5403c57b41 Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Tue, 31 Jul 2007 16:35:32 -0300 Subject: V4L/DVB (5953): msp3400-driver.c: kmalloc + memset conversion to kzalloc Signed-off-by: Mariusz Kozlowski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/msp3400-driver.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c index 11cfcf18ec3..e9d400e19a5 100644 --- a/drivers/media/video/msp3400-driver.c +++ b/drivers/media/video/msp3400-driver.c @@ -813,8 +813,9 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) int msp_rom; client = kzalloc(sizeof(*client), GFP_KERNEL); - if (client == NULL) + if (!client) return -ENOMEM; + client->addr = address; client->adapter = adapter; client->driver = &i2c_driver; @@ -826,14 +827,14 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) return 0; } - state = kmalloc(sizeof(*state), GFP_KERNEL); - if (state == NULL) { + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) { kfree(client); return -ENOMEM; } + i2c_set_clientdata(client, state); - memset(state, 0, sizeof(*state)); state->v4l2_std = V4L2_STD_NTSC; state->audmode = V4L2_TUNER_MODE_STEREO; state->volume = 58880; /* 0db gain */ -- cgit v1.2.3-70-g09d2 From b6884a17fc70e979ef34e4b5560988b522bb50a0 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Fri, 27 Jul 2007 10:08:51 -0300 Subject: V4L/DVB (5954): Sync with DiBcom Driver Release 2.1.3 + some improvements This changesets syncs the OpenSource driver for DiBcom demodulators with version 2.1.3 of DiBcom reference driver. There were some improvements since the last release for linux-dvb, e.g.: - stepped AGC startup - less space for initialization - diversity synchronization Furthermore this changeset contains the following things: - latest AGC settings for MT2266-based devices (namely Nova-TD and other) will improve the sensitivity - support for STK7700D reference design in dib0700-devices - remove some line-breaks when debugging is enabled - getting rid of layer between frontend_parameters and ofdm_channel used in dib*-drivers Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 148 +++-- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 1 + drivers/media/dvb/frontends/dib3000mc.c | 170 ++++-- drivers/media/dvb/frontends/dib7000m.c | 723 ++++++++++++++-------- drivers/media/dvb/frontends/dib7000p.c | 860 ++++++++++++++++++--------- drivers/media/dvb/frontends/dib7000p.h | 7 +- drivers/media/dvb/frontends/dibx000_common.h | 57 +- drivers/media/dvb/frontends/mt2266.c | 4 +- 8 files changed, 1277 insertions(+), 693 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 122d9d4b4ba..04b66f6e659 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -4,7 +4,7 @@ * under the terms of the GNU General Public License as published by the Free * Software Foundation, version 2. * - * Copyright (C) 2005-6 DiBcom, SA + * Copyright (C) 2005-7 DiBcom, SA */ #include "dib0700.h" @@ -99,41 +99,87 @@ static int bristol_tuner_attach(struct dvb_usb_adapter *adap) /* STK7700D: Pinnacle Dual DVB-T Diversity */ -static struct dibx000_agc_config stk7700d_7000p_mt2266_agc_config = { - BAND_UHF/* | BAND_VHF*/, - 0xE64, // setup - 2372, // inv_gain - 21, // time_stabiliz - - 0, // alpha_level - 118, // thlock - - 0, // wbd_inv - 0, // wbd_ref - 0, // wbd_sel - 0, // wbd_alpha - - 65535, // agc1_max - 0, // agc1_min - 65535, // agc2_max - 23592, // agc2_min - 0, // agc1_pt1 - 128, // agc1_pt2 - 128, // agc1_pt3 - 128, // agc1_slope1 - 0, // agc1_slope2 - 128, // agc2_pt1 - 253, // agc2_pt2 - 81, // agc2_slope1 - 0, // agc2_slope2 - - 17, // alpha_mant - 27, // alpha_exp - - 23, // beta_mant - 51, // beta_exp - - 0, // perform_agc_softsplit : 1 en vrai! +/* MT226x */ +static struct dibx000_agc_config stk7700d_7000p_mt2266_agc_config[2] = { + { + BAND_UHF, // band_caps + + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=1, P_agc_inv_pwm2=1, + * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ + (0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), // setup + + 1130, // inv_gain + 21, // time_stabiliz + + 0, // alpha_level + 118, // thlock + + 0, // wbd_inv + 3530, // wbd_ref + 1, // wbd_sel + 0, // wbd_alpha + + 65535, // agc1_max + 33770, // agc1_min + 65535, // agc2_max + 23592, // agc2_min + + 0, // agc1_pt1 + 62, // agc1_pt2 + 255, // agc1_pt3 + 64, // agc1_slope1 + 64, // agc1_slope2 + 132, // agc2_pt1 + 192, // agc2_pt2 + 80, // agc2_slope1 + 80, // agc2_slope2 + + 17, // alpha_mant + 27, // alpha_exp + 23, // beta_mant + 51, // beta_exp + + 1, // perform_agc_softsplit + }, { + BAND_VHF | BAND_LBAND, // band_caps + + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=1, P_agc_inv_pwm2=1, + * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ + (0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), // setup + + 2372, // inv_gain + 21, // time_stabiliz + + 0, // alpha_level + 118, // thlock + + 0, // wbd_inv + 3530, // wbd_ref + 1, // wbd_sel + 0, // wbd_alpha + + 65535, // agc1_max + 0, // agc1_min + 65535, // agc2_max + 23592, // agc2_min + + 0, // agc1_pt1 + 128, // agc1_pt2 + 128, // agc1_pt3 + 128, // agc1_slope1 + 0, // agc1_slope2 + 128, // agc2_pt1 + 253, // agc2_pt2 + 81, // agc2_slope1 + 0, // agc2_slope2 + + 17, // alpha_mant + 27, // alpha_exp + 23, // beta_mant + 51, // beta_exp + + 1, // perform_agc_softsplit + } }; static struct dibx000_bandwidth_config stk7700d_mt2266_pll_config = { @@ -150,23 +196,25 @@ static struct dib7000p_config stk7700d_dib7000p_mt2266_config[] = { .hostbus_diversity = 1, .tuner_is_baseband = 1, - .agc = &stk7700d_7000p_mt2266_agc_config, + .agc_config_count = 2, + .agc = stk7700d_7000p_mt2266_agc_config, .bw = &stk7700d_mt2266_pll_config, - .gpio_dir = DIB7000M_GPIO_DEFAULT_DIRECTIONS, - .gpio_val = DIB7000M_GPIO_DEFAULT_VALUES, - .gpio_pwm_pos = DIB7000M_GPIO_DEFAULT_PWM_POS, + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, }, { .output_mpeg2_in_188_bytes = 1, .hostbus_diversity = 1, .tuner_is_baseband = 1, - .agc = &stk7700d_7000p_mt2266_agc_config, + .agc_config_count = 2, + .agc = stk7700d_7000p_mt2266_agc_config, .bw = &stk7700d_mt2266_pll_config, - .gpio_dir = DIB7000M_GPIO_DEFAULT_DIRECTIONS, - .gpio_val = DIB7000M_GPIO_DEFAULT_VALUES, - .gpio_pwm_pos = DIB7000M_GPIO_DEFAULT_PWM_POS, + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, } }; @@ -211,7 +259,7 @@ static int stk7700d_tuner_attach(struct dvb_usb_adapter *adap) static u8 rc_request[] = { REQUEST_POLL_RC, 0 }; -int stk7700d_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +static int stk7700d_rc_query(struct dvb_usb_device *d, u32 *event, int *state) { u8 key[4]; int i; @@ -241,7 +289,7 @@ int stk7700d_rc_query(struct dvb_usb_device *d, u32 *event, int *state) #define KEY_MAP_SIZE (25+48) -struct dvb_usb_rc_key stk7700d_rc_keys[] = { +static struct dvb_usb_rc_key stk7700d_rc_keys[] = { /* Key codes for the tiny Pinnacle remote*/ { 0x07, 0x00, KEY_MUTE }, { 0x07, 0x01, KEY_MENU }, // Pinnacle logo @@ -436,6 +484,7 @@ static struct dib7000m_config stk7700p_dib7000m_config = { static struct dib7000p_config stk7700p_dib7000p_config = { .output_mpeg2_in_188_bytes = 1, + .agc_config_count = 1, .agc = &stk7700p_7000p_mt2060_agc_config, .bw = &stk7700p_pll_config, @@ -506,6 +555,7 @@ struct usb_device_id dib0700_usb_id_table[] = { { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV2000E) }, { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY) }, { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700D) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); @@ -615,7 +665,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { } }, - .num_device_descs = 3, + .num_device_descs = 4, .devices = { { "Pinnacle PCTV 2000e", { &dib0700_usb_id_table[11], NULL }, @@ -629,6 +679,10 @@ struct dvb_usb_device_properties dib0700_devices[] = { { &dib0700_usb_id_table[13], NULL }, { NULL }, }, + { "DiBcom STK7700D", + { &dib0700_usb_id_table[14], NULL }, + { NULL }, + }, }, .rc_interval = DEFAULT_RC_INTERVAL, .rc_key_map = stk7700d_rc_keys, diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 2e38be3aa45..5657ad8beaa 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -67,6 +67,7 @@ #define USB_PID_DIBCOM_MOD3001_WARM 0x0bc7 #define USB_PID_DIBCOM_STK7700P 0x1e14 #define USB_PID_DIBCOM_STK7700P_PC 0x1e78 +#define USB_PID_DIBCOM_STK7700D 0x1ef0 #define USB_PID_DIBCOM_ANCHOR_2135_COLD 0x2131 #define USB_PID_DPOSH_M9206_COLD 0x9206 #define USB_PID_DPOSH_M9206_WARM 0xa090 diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c index 054d7e6d966..cbbe2c2f05d 100644 --- a/drivers/media/dvb/frontends/dib3000mc.c +++ b/drivers/media/dvb/frontends/dib3000mc.c @@ -1,7 +1,7 @@ /* * Driver for DiBcom DiB3000MC/P-demodulator. * - * Copyright (C) 2004-6 DiBcom (http://www.dibcom.fr/) + * Copyright (C) 2004-7 DiBcom (http://www.dibcom.fr/) * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) * * This code is partially based on the previous dib3000mc.c . @@ -26,7 +26,7 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); -#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB3000MC/P:"); printk(args); } } while (0) +#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB3000MC/P:"); printk(args); printk("\n"); } } while (0) struct dib3000mc_state { struct dvb_frontend demod; @@ -71,7 +71,6 @@ static int dib3000mc_write_word(struct dib3000mc_state *state, u16 reg, u16 val) return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0; } - static int dib3000mc_identify(struct dib3000mc_state *state) { u16 value; @@ -92,7 +91,7 @@ static int dib3000mc_identify(struct dib3000mc_state *state) return 0; } -static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u8 bw, u8 update_offset) +static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u32 bw, u8 update_offset) { u32 timf; @@ -103,7 +102,7 @@ static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u8 bw, } else timf = state->timf; - timf *= (BW_INDEX_TO_KHZ(bw) / 1000); + timf *= (bw / 1000); if (update_offset) { s16 tim_offs = dib3000mc_read_word(state, 416); @@ -111,17 +110,17 @@ static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u8 bw, if (tim_offs & 0x2000) tim_offs -= 0x4000; - if (nfft == 0) + if (nfft == TRANSMISSION_MODE_2K) tim_offs *= 4; timf += tim_offs; - state->timf = timf / (BW_INDEX_TO_KHZ(bw) / 1000); + state->timf = timf / (bw / 1000); } dprintk("timf: %d\n", timf); - dib3000mc_write_word(state, 23, timf >> 16); - dib3000mc_write_word(state, 24, timf & 0xffff); + dib3000mc_write_word(state, 23, (u16) (timf >> 16)); + dib3000mc_write_word(state, 24, (u16) (timf ) & 0xffff); return 0; } @@ -209,31 +208,30 @@ static int dib3000mc_set_output_mode(struct dib3000mc_state *state, int mode) return ret; } -static int dib3000mc_set_bandwidth(struct dvb_frontend *demod, u8 bw) +static int dib3000mc_set_bandwidth(struct dib3000mc_state *state, u32 bw) { - struct dib3000mc_state *state = demod->demodulator_priv; u16 bw_cfg[6] = { 0 }; u16 imp_bw_cfg[3] = { 0 }; u16 reg; /* settings here are for 27.7MHz */ switch (bw) { - case BANDWIDTH_8_MHZ: + case 8000: bw_cfg[0] = 0x0019; bw_cfg[1] = 0x5c30; bw_cfg[2] = 0x0054; bw_cfg[3] = 0x88a0; bw_cfg[4] = 0x01a6; bw_cfg[5] = 0xab20; imp_bw_cfg[0] = 0x04db; imp_bw_cfg[1] = 0x00db; imp_bw_cfg[2] = 0x00b7; break; - case BANDWIDTH_7_MHZ: + case 7000: bw_cfg[0] = 0x001c; bw_cfg[1] = 0xfba5; bw_cfg[2] = 0x0060; bw_cfg[3] = 0x9c25; bw_cfg[4] = 0x01e3; bw_cfg[5] = 0x0cb7; imp_bw_cfg[0] = 0x04c0; imp_bw_cfg[1] = 0x00c0; imp_bw_cfg[2] = 0x00a0; break; - case BANDWIDTH_6_MHZ: + case 6000: bw_cfg[0] = 0x0021; bw_cfg[1] = 0xd040; bw_cfg[2] = 0x0070; bw_cfg[3] = 0xb62b; bw_cfg[4] = 0x0233; bw_cfg[5] = 0x8ed5; imp_bw_cfg[0] = 0x04a5; imp_bw_cfg[1] = 0x00a5; imp_bw_cfg[2] = 0x0089; break; - case 255 /* BANDWIDTH_5_MHZ */: + case 5000: bw_cfg[0] = 0x0028; bw_cfg[1] = 0x9380; bw_cfg[2] = 0x0087; bw_cfg[3] = 0x4100; bw_cfg[4] = 0x02a4; bw_cfg[5] = 0x4500; imp_bw_cfg[0] = 0x0489; imp_bw_cfg[1] = 0x0089; imp_bw_cfg[2] = 0x0072; break; @@ -257,7 +255,7 @@ static int dib3000mc_set_bandwidth(struct dvb_frontend *demod, u8 bw) dib3000mc_write_word(state, reg, imp_bw_cfg[reg - 55]); // Timing configuration - dib3000mc_set_timing(state, 0, bw, 0); + dib3000mc_set_timing(state, TRANSMISSION_MODE_2K, bw, 0); return 0; } @@ -276,7 +274,7 @@ static void dib3000mc_set_impulse_noise(struct dib3000mc_state *state, u8 mode, for (i = 58; i < 87; i++) dib3000mc_write_word(state, i, impulse_noise_val[i-58]); - if (nfft == 1) { + if (nfft == TRANSMISSION_MODE_8K) { dib3000mc_write_word(state, 58, 0x3b); dib3000mc_write_word(state, 84, 0x00); dib3000mc_write_word(state, 85, 0x8200); @@ -376,7 +374,7 @@ static int dib3000mc_init(struct dvb_frontend *demod) // P_search_maxtrial=1 dib3000mc_write_word(state, 5, 1); - dib3000mc_set_bandwidth(&state->demod, BANDWIDTH_8_MHZ); + dib3000mc_set_bandwidth(state, 8000); // div_lock_mask dib3000mc_write_word(state, 4, 0x814); @@ -397,7 +395,7 @@ static int dib3000mc_init(struct dvb_frontend *demod) dib3000mc_write_word(state, 180, 0x2FF0); // Impulse noise configuration - dib3000mc_set_impulse_noise(state, 0, 1); + dib3000mc_set_impulse_noise(state, 0, TRANSMISSION_MODE_8K); // output mode set-up dib3000mc_set_output_mode(state, OUTMODE_HIGH_Z); @@ -423,13 +421,13 @@ static void dib3000mc_set_adp_cfg(struct dib3000mc_state *state, s16 qam) { u16 cfg[4] = { 0 },reg; switch (qam) { - case 0: + case QPSK: cfg[0] = 0x099a; cfg[1] = 0x7fae; cfg[2] = 0x0333; cfg[3] = 0x7ff0; break; - case 1: + case QAM_16: cfg[0] = 0x023d; cfg[1] = 0x7fdf; cfg[2] = 0x00a4; cfg[3] = 0x7ff0; break; - case 2: + case QAM_64: cfg[0] = 0x0148; cfg[1] = 0x7ff0; cfg[2] = 0x00a4; cfg[3] = 0x7ff8; break; } @@ -437,11 +435,11 @@ static void dib3000mc_set_adp_cfg(struct dib3000mc_state *state, s16 qam) dib3000mc_write_word(state, reg, cfg[reg - 129]); } -static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dibx000_ofdm_channel *chan, u16 seq) +static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dvb_frontend_parameters *ch, u16 seq) { - u16 tmp; - - dib3000mc_set_timing(state, chan->nfft, chan->Bw, 0); + u16 value; + dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); + dib3000mc_set_timing(state, ch->u.ofdm.transmission_mode, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth), 0); // if (boost) // dib3000mc_write_word(state, 100, (11 << 6) + 6); @@ -455,7 +453,7 @@ static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dibx dib3000mc_write_word(state, 26, 0x6680); dib3000mc_write_word(state, 29, 0x1273); dib3000mc_write_word(state, 33, 5); - dib3000mc_set_adp_cfg(state, 1); + dib3000mc_set_adp_cfg(state, QAM_16); dib3000mc_write_word(state, 133, 15564); dib3000mc_write_word(state, 12 , 0x0); @@ -470,52 +468,98 @@ static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dibx dib3000mc_write_word(state, 97,0); dib3000mc_write_word(state, 98,0); - dib3000mc_set_impulse_noise(state, 0, chan->nfft); - - tmp = ((chan->nfft & 0x1) << 7) | (chan->guard << 5) | (chan->nqam << 3) | chan->vit_alpha; - dib3000mc_write_word(state, 0, tmp); + dib3000mc_set_impulse_noise(state, 0, ch->u.ofdm.transmission_mode); + value = 0; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: value |= (0 << 7); break; + default: + case TRANSMISSION_MODE_8K: value |= (1 << 7); break; + } + switch (ch->u.ofdm.guard_interval) { + case GUARD_INTERVAL_1_32: value |= (0 << 5); break; + case GUARD_INTERVAL_1_16: value |= (1 << 5); break; + case GUARD_INTERVAL_1_4: value |= (3 << 5); break; + default: + case GUARD_INTERVAL_1_8: value |= (2 << 5); break; + } + switch (ch->u.ofdm.constellation) { + case QPSK: value |= (0 << 3); break; + case QAM_16: value |= (1 << 3); break; + default: + case QAM_64: value |= (2 << 3); break; + } + switch (HIERARCHY_1) { + case HIERARCHY_2: value |= 2; break; + case HIERARCHY_4: value |= 4; break; + default: + case HIERARCHY_1: value |= 1; break; + } + dib3000mc_write_word(state, 0, value); dib3000mc_write_word(state, 5, (1 << 8) | ((seq & 0xf) << 4)); - tmp = (chan->vit_hrch << 4) | (chan->vit_select_hp); - if (!chan->vit_hrch || (chan->vit_hrch && chan->vit_select_hp)) - tmp |= chan->vit_code_rate_hp << 1; - else - tmp |= chan->vit_code_rate_lp << 1; - dib3000mc_write_word(state, 181, tmp); + value = 0; + if (ch->u.ofdm.hierarchy_information == 1) + value |= (1 << 4); + if (1 == 1) + value |= 1; + switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) { + case FEC_2_3: value |= (2 << 1); break; + case FEC_3_4: value |= (3 << 1); break; + case FEC_5_6: value |= (5 << 1); break; + case FEC_7_8: value |= (7 << 1); break; + default: + case FEC_1_2: value |= (1 << 1); break; + } + dib3000mc_write_word(state, 181, value); - // diversity synchro delay - tmp = dib3000mc_read_word(state, 180) & 0x000f; - tmp |= ((chan->nfft == 0) ? 64 : 256) * ((1 << (chan->guard)) * 3 / 2) << 4; // add 50% SFN margin - dib3000mc_write_word(state, 180, tmp); + // diversity synchro delay add 50% SFN margin + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_8K: value = 256; break; + case TRANSMISSION_MODE_2K: + default: value = 64; break; + } + switch (ch->u.ofdm.guard_interval) { + case GUARD_INTERVAL_1_16: value *= 2; break; + case GUARD_INTERVAL_1_8: value *= 4; break; + case GUARD_INTERVAL_1_4: value *= 8; break; + default: + case GUARD_INTERVAL_1_32: value *= 1; break; + } + value <<= 4; + value |= dib3000mc_read_word(state, 180) & 0x000f; + dib3000mc_write_word(state, 180, value); // restart demod - tmp = dib3000mc_read_word(state, 0); - dib3000mc_write_word(state, 0, tmp | (1 << 9)); - dib3000mc_write_word(state, 0, tmp); + value = dib3000mc_read_word(state, 0); + dib3000mc_write_word(state, 0, value | (1 << 9)); + dib3000mc_write_word(state, 0, value); msleep(30); - dib3000mc_set_impulse_noise(state, state->cfg->impulse_noise_mode, chan->nfft); + dib3000mc_set_impulse_noise(state, state->cfg->impulse_noise_mode, ch->u.ofdm.transmission_mode); } -static int dib3000mc_autosearch_start(struct dvb_frontend *demod, struct dibx000_ofdm_channel *chan) +static int dib3000mc_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *chan) { struct dib3000mc_state *state = demod->demodulator_priv; u16 reg; // u32 val; - struct dibx000_ofdm_channel fchan; + struct dvb_frontend_parameters schan; - INIT_OFDM_CHANNEL(&fchan); - fchan = *chan; + schan = *chan; + /* TODO what is that ? */ /* a channel for autosearch */ - fchan.nfft = 1; fchan.guard = 0; fchan.nqam = 2; - fchan.vit_alpha = 1; fchan.vit_code_rate_hp = 2; fchan.vit_code_rate_lp = 2; - fchan.vit_hrch = 0; fchan.vit_select_hp = 1; + schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; + schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32; + schan.u.ofdm.constellation = QAM_64; + schan.u.ofdm.code_rate_HP = FEC_2_3; + schan.u.ofdm.code_rate_LP = FEC_2_3; + schan.u.ofdm.hierarchy_information = 0; - dib3000mc_set_channel_cfg(state, &fchan, 11); + dib3000mc_set_channel_cfg(state, &schan, 11); reg = dib3000mc_read_word(state, 0); dib3000mc_write_word(state, 0, reg | (1 << 8)); @@ -539,7 +583,7 @@ static int dib3000mc_autosearch_is_irq(struct dvb_frontend *demod) return 0; // still pending } -static int dib3000mc_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch) +static int dib3000mc_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) { struct dib3000mc_state *state = demod->demodulator_priv; @@ -549,9 +593,8 @@ static int dib3000mc_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channe // activates isi dib3000mc_write_word(state, 29, 0x1073); - dib3000mc_set_adp_cfg(state, (u8)ch->nqam); - - if (ch->nfft == 1) { + dib3000mc_set_adp_cfg(state, (uint8_t)ch->u.ofdm.constellation); + if (ch->u.ofdm.transmission_mode == TRANSMISSION_MODE_8K) { dib3000mc_write_word(state, 26, 38528); dib3000mc_write_word(state, 33, 8); } else { @@ -560,7 +603,7 @@ static int dib3000mc_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channe } if (dib3000mc_read_word(state, 509) & 0x80) - dib3000mc_set_timing(state, ch->nfft, ch->Bw, 1); + dib3000mc_set_timing(state, ch->u.ofdm.transmission_mode, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth), 1); return 0; } @@ -632,13 +675,9 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep) { struct dib3000mc_state *state = fe->demodulator_priv; - struct dibx000_ofdm_channel ch; - - INIT_OFDM_CHANNEL(&ch); - FEP2DIB(fep,&ch); state->current_bandwidth = fep->u.ofdm.bandwidth; - dib3000mc_set_bandwidth(fe, fep->u.ofdm.bandwidth); + dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth)); if (fe->ops.tuner_ops.set_params) { fe->ops.tuner_ops.set_params(fe, fep); @@ -651,7 +690,7 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe, fep->u.ofdm.code_rate_HP == FEC_AUTO) { int i = 100, found; - dib3000mc_autosearch_start(fe, &ch); + dib3000mc_autosearch_start(fe, fep); do { msleep(1); found = dib3000mc_autosearch_is_irq(fe); @@ -662,13 +701,12 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe, return 0; // no channel found dib3000mc_get_frontend(fe, fep); - FEP2DIB(fep,&ch); } /* make this a config parameter */ dib3000mc_set_output_mode(state, OUTMODE_MPEG2_FIFO); - return dib3000mc_tune(fe, &ch); + return dib3000mc_tune(fe, fep); } static int dib3000mc_read_status(struct dvb_frontend *fe, fe_status_t *stat) diff --git a/drivers/media/dvb/frontends/dib7000m.c b/drivers/media/dvb/frontends/dib7000m.c index f64546c6aeb..608156a691d 100644 --- a/drivers/media/dvb/frontends/dib7000m.c +++ b/drivers/media/dvb/frontends/dib7000m.c @@ -2,7 +2,7 @@ * Linux-DVB Driver for DiBcom's DiB7000M and * first generation DiB7000P-demodulator-family. * - * Copyright (C) 2005-6 DiBcom (http://www.dibcom.fr/) + * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -19,7 +19,7 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); -#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000M:"); printk(args); } } while (0) +#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000M: "); printk(args); printk("\n"); } } while (0) struct dib7000m_state { struct dvb_frontend demod; @@ -39,8 +39,16 @@ struct dib7000m_state { fe_bandwidth_t current_bandwidth; struct dibx000_agc_config *current_agc; u32 timf; + u32 timf_default; + u32 internal_clk; + + uint8_t div_force_off : 1; + uint8_t div_state : 1; + uint16_t div_sync_wait; u16 revision; + + u8 agc_state; }; enum dib7000m_power_mode { @@ -63,7 +71,7 @@ static u16 dib7000m_read_word(struct dib7000m_state *state, u16 reg) }; if (i2c_transfer(state->i2c_adap, msg, 2) != 2) - dprintk("i2c read error on %d\n",reg); + dprintk("i2c read error on %d",reg); return (rb[0] << 8) | rb[1]; } @@ -79,6 +87,25 @@ static int dib7000m_write_word(struct dib7000m_state *state, u16 reg, u16 val) }; return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0; } +static void dib7000m_write_tab(struct dib7000m_state *state, u16 *buf) +{ + u16 l = 0, r, *n; + n = buf; + l = *n++; + while (l) { + r = *n++; + + if (state->reg_offs && (r >= 112 && r <= 331)) // compensate for 7000MC + r++; + + do { + dib7000m_write_word(state, r, *n++); + r++; + } while (--l); + l = *n++; + } +} + static int dib7000m_set_output_mode(struct dib7000m_state *state, int mode) { int ret = 0; @@ -89,8 +116,7 @@ static int dib7000m_set_output_mode(struct dib7000m_state *state, int mode) fifo_threshold = 1792; smo_mode = (dib7000m_read_word(state, 294 + state->reg_offs) & 0x0010) | (1 << 1); - dprintk("-I- Setting output mode for demod %p to %d\n", - &state->demod, mode); + dprintk( "setting output mode for demod %p to %d", &state->demod, mode); switch (mode) { case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock @@ -117,7 +143,7 @@ static int dib7000m_set_output_mode(struct dib7000m_state *state, int mode) outreg = 0; break; default: - dprintk("Unhandled output_mode passed to be set for demod %p\n",&state->demod); + dprintk( "Unhandled output_mode passed to be set for demod %p",&state->demod); break; } @@ -129,13 +155,20 @@ static int dib7000m_set_output_mode(struct dib7000m_state *state, int mode) ret |= dib7000m_write_word(state, 1795, outreg); ret |= dib7000m_write_word(state, 1805, sram); + if (state->revision == 0x4003) { + u16 clk_cfg1 = dib7000m_read_word(state, 909) & 0xfffd; + if (mode == OUTMODE_DIVERSITY) + clk_cfg1 |= (1 << 1); // P_O_CLK_en + dib7000m_write_word(state, 909, clk_cfg1); + } return ret; } -static int dib7000m_set_power_mode(struct dib7000m_state *state, enum dib7000m_power_mode mode) +static void dib7000m_set_power_mode(struct dib7000m_state *state, enum dib7000m_power_mode mode) { /* by default everything is going to be powered off */ u16 reg_903 = 0xffff, reg_904 = 0xffff, reg_905 = 0xffff, reg_906 = 0x3fff; + u8 offset = 0; /* now, depending on the requested mode, we power on */ switch (mode) { @@ -170,16 +203,17 @@ static int dib7000m_set_power_mode(struct dib7000m_state *state, enum dib7000m_p if (!state->cfg.mobile_mode) reg_904 |= (1 << 7) | (1 << 6) | (1 << 4) | (1 << 2) | (1 << 1); - /* P_sdio_select_clk = 0 on MC */ + /* P_sdio_select_clk = 0 on MC and after*/ if (state->revision != 0x4000) reg_906 <<= 1; - dib7000m_write_word(state, 903, reg_903); - dib7000m_write_word(state, 904, reg_904); - dib7000m_write_word(state, 905, reg_905); - dib7000m_write_word(state, 906, reg_906); + if (state->revision == 0x4003) + offset = 1; - return 0; + dib7000m_write_word(state, 903 + offset, reg_903); + dib7000m_write_word(state, 904 + offset, reg_904); + dib7000m_write_word(state, 905 + offset, reg_905); + dib7000m_write_word(state, 906 + offset, reg_906); } static int dib7000m_set_adc_state(struct dib7000m_state *state, enum dibx000_adc_states no) @@ -230,34 +264,55 @@ static int dib7000m_set_adc_state(struct dib7000m_state *state, enum dibx000_adc break; } -// dprintk("-D- 913: %x, 914: %x\n", reg_913, reg_914); - +// dprintk( "913: %x, 914: %x", reg_913, reg_914); ret |= dib7000m_write_word(state, 913, reg_913); ret |= dib7000m_write_word(state, 914, reg_914); return ret; } -static int dib7000m_set_bandwidth(struct dvb_frontend *demod, u8 bw_idx) +static int dib7000m_set_bandwidth(struct dib7000m_state *state, u32 bw) { - struct dib7000m_state *state = demod->demodulator_priv; u32 timf; // store the current bandwidth for later use - state->current_bandwidth = bw_idx; + state->current_bandwidth = bw; if (state->timf == 0) { - dprintk("-D- Using default timf\n"); - timf = state->cfg.bw->timf; + dprintk( "using default timf"); + timf = state->timf_default; } else { - dprintk("-D- Using updated timf\n"); + dprintk( "using updated timf"); timf = state->timf; } - timf = timf * (BW_INDEX_TO_KHZ(bw_idx) / 100) / 80; + timf = timf * (bw / 50) / 160; - dib7000m_write_word(state, 23, (timf >> 16) & 0xffff); - dib7000m_write_word(state, 24, (timf ) & 0xffff); + dib7000m_write_word(state, 23, (u16) ((timf >> 16) & 0xffff)); + dib7000m_write_word(state, 24, (u16) ((timf ) & 0xffff)); + + return 0; +} + +static int dib7000m_set_diversity_in(struct dvb_frontend *demod, int onoff) +{ + struct dib7000m_state *state = demod->demodulator_priv; + + if (state->div_force_off) { + dprintk( "diversity combination deactivated - forced by COFDM parameters"); + onoff = 0; + } + state->div_state = (uint8_t)onoff; + + if (onoff) { + dib7000m_write_word(state, 263 + state->reg_offs, 6); + dib7000m_write_word(state, 264 + state->reg_offs, 6); + dib7000m_write_word(state, 266 + state->reg_offs, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0)); + } else { + dib7000m_write_word(state, 263 + state->reg_offs, 1); + dib7000m_write_word(state, 264 + state->reg_offs, 0); + dib7000m_write_word(state, 266 + state->reg_offs, 0); + } return 0; } @@ -266,7 +321,7 @@ static int dib7000m_sad_calib(struct dib7000m_state *state) { /* internal */ -// dib7000m_write_word(state, 928, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is written in set_bandwidth +// dib7000m_write_word(state, 928, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writting in set_bandwidth dib7000m_write_word(state, 929, (0 << 1) | (0 << 0)); dib7000m_write_word(state, 930, 776); // 0.625*3.3 / 4096 @@ -281,10 +336,10 @@ static int dib7000m_sad_calib(struct dib7000m_state *state) static void dib7000m_reset_pll_common(struct dib7000m_state *state, const struct dibx000_bandwidth_config *bw) { - dib7000m_write_word(state, 18, ((bw->internal*1000) >> 16) & 0xffff); - dib7000m_write_word(state, 19, (bw->internal*1000) & 0xffff); - dib7000m_write_word(state, 21, (bw->ifreq >> 16) & 0xffff); - dib7000m_write_word(state, 22, bw->ifreq & 0xffff); + dib7000m_write_word(state, 18, (u16) (((bw->internal*1000) >> 16) & 0xffff)); + dib7000m_write_word(state, 19, (u16) ( (bw->internal*1000) & 0xffff)); + dib7000m_write_word(state, 21, (u16) ( (bw->ifreq >> 16) & 0xffff)); + dib7000m_write_word(state, 22, (u16) ( bw->ifreq & 0xffff)); dib7000m_write_word(state, 928, bw->sad_cfg); } @@ -325,15 +380,19 @@ static void dib7000m_reset_pll(struct dib7000m_state *state) static void dib7000mc_reset_pll(struct dib7000m_state *state) { const struct dibx000_bandwidth_config *bw = state->cfg.bw; + u16 clk_cfg1; // clk_cfg0 dib7000m_write_word(state, 907, (bw->pll_prediv << 8) | (bw->pll_ratio << 0)); // clk_cfg1 //dib7000m_write_word(state, 908, (1 << 14) | (3 << 12) |(0 << 11) | - dib7000m_write_word(state, 908, (0 << 14) | (3 << 12) |(0 << 11) | + clk_cfg1 = (0 << 14) | (3 << 12) |(0 << 11) | (bw->IO_CLK_en_core << 10) | (bw->bypclk_div << 5) | (bw->enable_refdiv << 4) | - (bw->pll_bypass << 3) | (bw->pll_range << 1) | (bw->pll_reset << 0)); + (1 << 3) | (bw->pll_range << 1) | (bw->pll_reset << 0); + dib7000m_write_word(state, 908, clk_cfg1); + clk_cfg1 = (clk_cfg1 & 0xfff7) | (bw->pll_bypass << 3); + dib7000m_write_word(state, 908, clk_cfg1); // smpl_cfg dib7000m_write_word(state, 910, (1 << 12) | (2 << 10) | (bw->modulo << 8) | (bw->ADClkSrc << 7)); @@ -344,9 +403,6 @@ static void dib7000mc_reset_pll(struct dib7000m_state *state) static int dib7000m_reset_gpio(struct dib7000m_state *st) { /* reset the GPIOs */ - dprintk("-D- gpio dir: %x: gpio val: %x, gpio pwm pos: %x\n", - st->cfg.gpio_dir, st->cfg.gpio_val,st->cfg.gpio_pwm_pos); - dib7000m_write_word(st, 773, st->cfg.gpio_dir); dib7000m_write_word(st, 774, st->cfg.gpio_val); @@ -358,6 +414,107 @@ static int dib7000m_reset_gpio(struct dib7000m_state *st) return 0; } +static u16 dib7000m_defaults_common[] = + +{ + // auto search configuration + 3, 2, + 0x0004, + 0x1000, + 0x0814, + + 12, 6, + 0x001b, + 0x7740, + 0x005b, + 0x8d80, + 0x01c9, + 0xc380, + 0x0000, + 0x0080, + 0x0000, + 0x0090, + 0x0001, + 0xd4c0, + + 1, 26, + 0x6680, // P_corm_thres Lock algorithms configuration + + 1, 170, + 0x0410, // P_palf_alpha_regul, P_palf_filter_freeze, P_palf_filter_on + + 8, 173, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + + 1, 182, + 8192, // P_fft_nb_to_cut + + 2, 195, + 0x0ccd, // P_pha3_thres + 0, // P_cti_use_cpe, P_cti_use_prog + + 1, 205, + 0x200f, // P_cspu_regul, P_cspu_win_cut + + 5, 214, + 0x023d, // P_adp_regul_cnt + 0x00a4, // P_adp_noise_cnt + 0x00a4, // P_adp_regul_ext + 0x7ff0, // P_adp_noise_ext + 0x3ccc, // P_adp_fil + + 1, 226, + 0, // P_2d_byp_ti_num + + 1, 255, + 0x800, // P_equal_thres_wgn + + 1, 263, + 0x0001, + + 1, 281, + 0x0010, // P_fec_* + + 1, 294, + 0x0062, // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard + + 0 +}; + +static u16 dib7000m_defaults[] = + +{ + /* set ADC level to -16 */ + 11, 76, + (1 << 13) - 825 - 117, + (1 << 13) - 837 - 117, + (1 << 13) - 811 - 117, + (1 << 13) - 766 - 117, + (1 << 13) - 737 - 117, + (1 << 13) - 693 - 117, + (1 << 13) - 648 - 117, + (1 << 13) - 619 - 117, + (1 << 13) - 575 - 117, + (1 << 13) - 531 - 117, + (1 << 13) - 501 - 117, + + // Tuner IO bank: max drive (14mA) + 1, 912, + 0x2c8a, + + 1, 1817, + 1, + + 0, +}; + static int dib7000m_demod_reset(struct dib7000m_state *state) { dib7000m_set_power_mode(state, DIB7000M_POWER_ALL); @@ -382,22 +539,47 @@ static int dib7000m_demod_reset(struct dib7000m_state *state) dib7000mc_reset_pll(state); if (dib7000m_reset_gpio(state) != 0) - dprintk("-E- GPIO reset was not successful.\n"); + dprintk( "GPIO reset was not successful."); if (dib7000m_set_output_mode(state, OUTMODE_HIGH_Z) != 0) - dprintk("-E- OUTPUT_MODE could not be resetted.\n"); + dprintk( "OUTPUT_MODE could not be reset."); /* unforce divstr regardless whether i2c enumeration was done or not */ dib7000m_write_word(state, 1794, dib7000m_read_word(state, 1794) & ~(1 << 1) ); - dib7000m_set_bandwidth(&state->demod, BANDWIDTH_8_MHZ); + dib7000m_set_bandwidth(state, 8000); dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_ON); dib7000m_sad_calib(state); dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_OFF); + if (state->cfg.dvbt_mode) + dib7000m_write_word(state, 1796, 0x0); // select DVB-T output + + if (state->cfg.mobile_mode) + dib7000m_write_word(state, 261 + state->reg_offs, 2); + else + dib7000m_write_word(state, 224 + state->reg_offs, 1); + + // P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ... + if(state->cfg.tuner_is_baseband) + dib7000m_write_word(state, 36, 0x0755); + else + dib7000m_write_word(state, 36, 0x1f55); + + // P_divclksel=3 P_divbitsel=1 + if (state->revision == 0x4000) + dib7000m_write_word(state, 909, (3 << 10) | (1 << 6)); + else + dib7000m_write_word(state, 909, (3 << 4) | 1); + + dib7000m_write_tab(state, dib7000m_defaults_common); + dib7000m_write_tab(state, dib7000m_defaults); + dib7000m_set_power_mode(state, DIB7000M_POWER_INTERFACE_ONLY); + state->internal_clk = state->cfg.bw->internal; + return 0; } @@ -427,7 +609,7 @@ static int dib7000m_agc_soft_split(struct dib7000m_state *state) (agc - state->current_agc->split.min_thres) / (state->current_agc->split.max_thres - state->current_agc->split.min_thres); - dprintk("AGC split_offset: %d\n",split_offset); + dprintk( "AGC split_offset: %d",split_offset); // P_agc_force_split and P_agc_split_offset return dib7000m_write_word(state, 103, (dib7000m_read_word(state, 103) & 0xff00) | split_offset); @@ -435,35 +617,26 @@ static int dib7000m_agc_soft_split(struct dib7000m_state *state) static int dib7000m_update_lna(struct dib7000m_state *state) { - int i; u16 dyn_gain; - // when there is no LNA to program return immediatly - if (state->cfg.update_lna == NULL) - return 0; - - msleep(60); - for (i = 0; i < 20; i++) { + if (state->cfg.update_lna) { // read dyn_gain here (because it is demod-dependent and not tuner) dyn_gain = dib7000m_read_word(state, 390); - dprintk("agc global: %d\n", dyn_gain); - if (state->cfg.update_lna(&state->demod,dyn_gain)) { // LNA has changed dib7000m_restart_agc(state); - msleep(60); - } else - break; + return 1; + } } return 0; } -static void dib7000m_set_agc_config(struct dib7000m_state *state, u8 band) +static int dib7000m_set_agc_config(struct dib7000m_state *state, u8 band) { struct dibx000_agc_config *agc = NULL; int i; - if (state->current_band == band) - return; + if (state->current_band == band && state->current_agc != NULL) + return 0; state->current_band = band; for (i = 0; i < state->cfg.agc_config_count; i++) @@ -473,8 +646,8 @@ static void dib7000m_set_agc_config(struct dib7000m_state *state, u8 band) } if (agc == NULL) { - dprintk("-E- No valid AGC configuration found for band 0x%02x\n",band); - return; + dprintk( "no valid AGC configuration found for band 0x%02x",band); + return -EINVAL; } state->current_agc = agc; @@ -489,7 +662,7 @@ static void dib7000m_set_agc_config(struct dib7000m_state *state, u8 band) dib7000m_write_word(state, 98, (agc->alpha_mant << 5) | agc->alpha_exp); dib7000m_write_word(state, 99, (agc->beta_mant << 6) | agc->beta_exp); - dprintk("-D- WBD: ref: %d, sel: %d, active: %d, alpha: %d\n", + dprintk( "WBD: ref: %d, sel: %d, active: %d, alpha: %d", state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel); /* AGC continued */ @@ -510,7 +683,7 @@ static void dib7000m_set_agc_config(struct dib7000m_state *state, u8 band) if (state->revision > 0x4000) { // settings for the MC dib7000m_write_word(state, 71, agc->agc1_pt3); -// dprintk("-D- 929: %x %d %d\n", +// dprintk( "929: %x %d %d", // (dib7000m_read_word(state, 929) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2), agc->wbd_inv, agc->wbd_sel); dib7000m_write_word(state, 929, (dib7000m_read_word(state, 929) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2)); } else { @@ -519,33 +692,160 @@ static void dib7000m_set_agc_config(struct dib7000m_state *state, u8 band) for (i = 0; i < 9; i++) dib7000m_write_word(state, 88 + i, b[i]); } + return 0; } -static void dib7000m_update_timf_freq(struct dib7000m_state *state) +static void dib7000m_update_timf(struct dib7000m_state *state) { u32 timf = (dib7000m_read_word(state, 436) << 16) | dib7000m_read_word(state, 437); - state->timf = timf * 80 / (BW_INDEX_TO_KHZ(state->current_bandwidth) / 100); + state->timf = timf * 160 / (state->current_bandwidth / 50); dib7000m_write_word(state, 23, (u16) (timf >> 16)); dib7000m_write_word(state, 24, (u16) (timf & 0xffff)); - dprintk("-D- Updated timf_frequency: %d (default: %d)\n",state->timf, state->cfg.bw->timf); + dprintk( "updated timf_frequency: %d (default: %d)",state->timf, state->timf_default); } -static void dib7000m_set_channel(struct dib7000m_state *state, struct dibx000_ofdm_channel *ch, u8 seq) +static int dib7000m_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) +{ + struct dib7000m_state *state = demod->demodulator_priv; + u16 cfg_72 = dib7000m_read_word(state, 72); + int ret = -1; + u8 *agc_state = &state->agc_state; + u8 agc_split; + + switch (state->agc_state) { + case 0: + // set power-up level: interf+analog+AGC + dib7000m_set_power_mode(state, DIB7000M_POWER_INTERF_ANALOG_AGC); + dib7000m_set_adc_state(state, DIBX000_ADC_ON); + + if (dib7000m_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency/1000)) != 0) + return -1; + + ret = 7; /* ADC power up */ + (*agc_state)++; + break; + + case 1: + /* AGC initialization */ + if (state->cfg.agc_control) + state->cfg.agc_control(&state->demod, 1); + + dib7000m_write_word(state, 75, 32768); + if (!state->current_agc->perform_agc_softsplit) { + /* we are using the wbd - so slow AGC startup */ + dib7000m_write_word(state, 103, 1 << 8); /* force 0 split on WBD and restart AGC */ + (*agc_state)++; + ret = 5; + } else { + /* default AGC startup */ + (*agc_state) = 4; + /* wait AGC rough lock time */ + ret = 7; + } + + dib7000m_restart_agc(state); + break; + + case 2: /* fast split search path after 5sec */ + dib7000m_write_word(state, 72, cfg_72 | (1 << 4)); /* freeze AGC loop */ + dib7000m_write_word(state, 103, 2 << 9); /* fast split search 0.25kHz */ + (*agc_state)++; + ret = 14; + break; + + case 3: /* split search ended */ + agc_split = (uint8_t)dib7000m_read_word(state, 392); /* store the split value for the next time */ + dib7000m_write_word(state, 75, dib7000m_read_word(state, 390)); /* set AGC gain start value */ + + dib7000m_write_word(state, 72, cfg_72 & ~(1 << 4)); /* std AGC loop */ + dib7000m_write_word(state, 103, (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */ + + dib7000m_restart_agc(state); + + dprintk( "SPLIT %p: %hd", demod, agc_split); + + (*agc_state)++; + ret = 5; + break; + + case 4: /* LNA startup */ + /* wait AGC accurate lock time */ + ret = 7; + + if (dib7000m_update_lna(state)) + // wait only AGC rough lock time + ret = 5; + else + (*agc_state)++; + break; + + case 5: + dib7000m_agc_soft_split(state); + + if (state->cfg.agc_control) + state->cfg.agc_control(&state->demod, 0); + + (*agc_state)++; + break; + + default: + break; + } + return ret; +} + +static void dib7000m_set_channel(struct dib7000m_state *state, struct dvb_frontend_parameters *ch, u8 seq) { u16 value, est[4]; - dib7000m_set_agc_config(state, BAND_OF_FREQUENCY(ch->RF_kHz)); + dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); /* nfft, guard, qam, alpha */ - dib7000m_write_word(state, 0, (ch->nfft << 7) | (ch->guard << 5) | (ch->nqam << 3) | (ch->vit_alpha)); + value = 0; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: value |= (0 << 7); break; + case /* 4K MODE */ 255: value |= (2 << 7); break; + default: + case TRANSMISSION_MODE_8K: value |= (1 << 7); break; + } + switch (ch->u.ofdm.guard_interval) { + case GUARD_INTERVAL_1_32: value |= (0 << 5); break; + case GUARD_INTERVAL_1_16: value |= (1 << 5); break; + case GUARD_INTERVAL_1_4: value |= (3 << 5); break; + default: + case GUARD_INTERVAL_1_8: value |= (2 << 5); break; + } + switch (ch->u.ofdm.constellation) { + case QPSK: value |= (0 << 3); break; + case QAM_16: value |= (1 << 3); break; + default: + case QAM_64: value |= (2 << 3); break; + } + switch (HIERARCHY_1) { + case HIERARCHY_2: value |= 2; break; + case HIERARCHY_4: value |= 4; break; + default: + case HIERARCHY_1: value |= 1; break; + } + dib7000m_write_word(state, 0, value); dib7000m_write_word(state, 5, (seq << 4)); - /* P_dintl_native, P_dintlv_inv, P_vit_hrch, P_vit_code_rate, P_vit_select_hp */ - value = (ch->intlv_native << 6) | (ch->vit_hrch << 4) | (ch->vit_select_hp & 0x1); - if (ch->vit_hrch == 0 || ch->vit_select_hp == 1) - value |= (ch->vit_code_rate_hp << 1); - else - value |= (ch->vit_code_rate_lp << 1); + /* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */ + value = 0; + if (1 != 0) + value |= (1 << 6); + if (ch->u.ofdm.hierarchy_information == 1) + value |= (1 << 4); + if (1 == 1) + value |= 1; + switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) { + case FEC_2_3: value |= (2 << 1); break; + case FEC_3_4: value |= (3 << 1); break; + case FEC_5_6: value |= (5 << 1); break; + case FEC_7_8: value |= (7 << 1); break; + default: + case FEC_1_2: value |= (1 << 1); break; + } dib7000m_write_word(state, 267 + state->reg_offs, value); /* offset loop parameters */ @@ -563,32 +863,38 @@ static void dib7000m_set_channel(struct dib7000m_state *state, struct dibx000_of dib7000m_write_word(state, 33, (0 << 4) | 0x5); /* P_dvsy_sync_wait */ - switch (ch->nfft) { - case 1: value = 256; break; - case 2: value = 128; break; - case 0: + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_8K: value = 256; break; + case /* 4K MODE */ 255: value = 128; break; + case TRANSMISSION_MODE_2K: default: value = 64; break; } - value *= ((1 << (ch->guard)) * 3 / 2); // add 50% SFN margin - value <<= 4; + switch (ch->u.ofdm.guard_interval) { + case GUARD_INTERVAL_1_16: value *= 2; break; + case GUARD_INTERVAL_1_8: value *= 4; break; + case GUARD_INTERVAL_1_4: value *= 8; break; + default: + case GUARD_INTERVAL_1_32: value *= 1; break; + } + state->div_sync_wait = (value * 3) / 2 + 32; // add 50% SFN margin + compensate for one DVSY-fifo TODO /* deactive the possibility of diversity reception if extended interleave - not for 7000MC */ /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */ - if (ch->intlv_native || state->revision > 0x4000) - value |= (1 << 2) | (2 << 0); + if (1 == 1 || state->revision > 0x4000) + state->div_force_off = 0; else - value |= 0; - dib7000m_write_word(state, 266 + state->reg_offs, value); + state->div_force_off = 1; + dib7000m_set_diversity_in(&state->demod, state->div_state); /* channel estimation fine configuration */ - switch (ch->nqam) { - case 2: + switch (ch->u.ofdm.constellation) { + case QAM_64: est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */ est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */ est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */ est[3] = 0xfff8; /* P_adp_noise_ext -0.001 */ break; - case 1: + case QAM_16: est[0] = 0x023d; /* P_adp_regul_cnt 0.07 */ est[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */ est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */ @@ -604,70 +910,48 @@ static void dib7000m_set_channel(struct dib7000m_state *state, struct dibx000_of for (value = 0; value < 4; value++) dib7000m_write_word(state, 214 + value + state->reg_offs, est[value]); - // set power-up level: interf+analog+AGC - dib7000m_set_power_mode(state, DIB7000M_POWER_INTERF_ANALOG_AGC); - dib7000m_set_adc_state(state, DIBX000_ADC_ON); - - msleep(7); - - //AGC initialization - if (state->cfg.agc_control) - state->cfg.agc_control(&state->demod, 1); - - dib7000m_restart_agc(state); - - // wait AGC rough lock time - msleep(5); - - dib7000m_update_lna(state); - dib7000m_agc_soft_split(state); - - // wait AGC accurate lock time - msleep(7); - - if (state->cfg.agc_control) - state->cfg.agc_control(&state->demod, 0); - // set power-up level: autosearch dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD); } -static int dib7000m_autosearch_start(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch) +static int dib7000m_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) { struct dib7000m_state *state = demod->demodulator_priv; - struct dibx000_ofdm_channel auto_ch; + struct dvb_frontend_parameters schan; int ret = 0; - u32 value; - - INIT_OFDM_CHANNEL(&auto_ch); - auto_ch.RF_kHz = ch->RF_kHz; - auto_ch.Bw = ch->Bw; - auto_ch.nqam = 2; - auto_ch.guard = 0; - auto_ch.nfft = 1; - auto_ch.vit_alpha = 1; - auto_ch.vit_select_hp = 1; - auto_ch.vit_code_rate_hp = 2; - auto_ch.vit_code_rate_lp = 3; - auto_ch.vit_hrch = 0; - auto_ch.intlv_native = 1; - - dib7000m_set_channel(state, &auto_ch, 7); + u32 value, factor; + + schan = *ch; + + schan.u.ofdm.constellation = QAM_64; + schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32; + schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; + schan.u.ofdm.code_rate_HP = FEC_2_3; + schan.u.ofdm.code_rate_LP = FEC_3_4; + schan.u.ofdm.hierarchy_information = 0; + + dib7000m_set_channel(state, &schan, 7); + + factor = BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth); + if (factor >= 5000) + factor = 1; + else + factor = 6; // always use the setting for 8MHz here lock_time for 7,6 MHz are longer - value = 30 * state->cfg.bw->internal; + value = 30 * state->internal_clk * factor; ret |= dib7000m_write_word(state, 6, (u16) ((value >> 16) & 0xffff)); // lock0 wait time ret |= dib7000m_write_word(state, 7, (u16) (value & 0xffff)); // lock0 wait time - value = 100 * state->cfg.bw->internal; + value = 100 * state->internal_clk * factor; ret |= dib7000m_write_word(state, 8, (u16) ((value >> 16) & 0xffff)); // lock1 wait time ret |= dib7000m_write_word(state, 9, (u16) (value & 0xffff)); // lock1 wait time - value = 500 * state->cfg.bw->internal; + value = 500 * state->internal_clk * factor; ret |= dib7000m_write_word(state, 10, (u16) ((value >> 16) & 0xffff)); // lock2 wait time ret |= dib7000m_write_word(state, 11, (u16) (value & 0xffff)); // lock2 wait time // start search value = dib7000m_read_word(state, 0); - ret |= dib7000m_write_word(state, 0, value | (1 << 9)); + ret |= dib7000m_write_word(state, 0, (u16) (value | (1 << 9))); /* clear n_irq_pending */ if (state->revision == 0x4000) @@ -685,12 +969,12 @@ static int dib7000m_autosearch_irq(struct dib7000m_state *state, u16 reg) u16 irq_pending = dib7000m_read_word(state, reg); if (irq_pending & 0x1) { // failed - dprintk("#\n"); + dprintk( "autosearch failed"); return 1; } if (irq_pending & 0x2) { // succeeded - dprintk("!\n"); + dprintk( "autosearch succeeded"); return 2; } return 0; // still pending @@ -705,7 +989,7 @@ static int dib7000m_autosearch_is_irq(struct dvb_frontend *demod) return dib7000m_autosearch_irq(state, 537); } -static int dib7000m_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch) +static int dib7000m_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) { struct dib7000m_state *state = demod->demodulator_priv; int ret = 0; @@ -722,182 +1006,103 @@ static int dib7000m_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel ret |= dib7000m_write_word(state, 898, 0x0000); msleep(45); - ret |= dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD); + dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD); /* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */ ret |= dib7000m_write_word(state, 29, (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3)); - // never achieved a lock with that bandwidth so far - wait for timfreq to update + // never achieved a lock before - wait for timfreq to update if (state->timf == 0) msleep(200); //dump_reg(state); /* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */ value = (6 << 8) | 0x80; - switch (ch->nfft) { - case 0: value |= (7 << 12); break; - case 1: value |= (9 << 12); break; - case 2: value |= (8 << 12); break; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: value |= (7 << 12); break; + case /* 4K MODE */ 255: value |= (8 << 12); break; + default: + case TRANSMISSION_MODE_8K: value |= (9 << 12); break; } ret |= dib7000m_write_word(state, 26, value); /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */ value = (0 << 4); - switch (ch->nfft) { - case 0: value |= 0x6; break; - case 1: value |= 0x8; break; - case 2: value |= 0x7; break; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: value |= 0x6; break; + case /* 4K MODE */ 255: value |= 0x7; break; + default: + case TRANSMISSION_MODE_8K: value |= 0x8; break; } ret |= dib7000m_write_word(state, 32, value); /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */ value = (0 << 4); - switch (ch->nfft) { - case 0: value |= 0x6; break; - case 1: value |= 0x8; break; - case 2: value |= 0x7; break; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: value |= 0x6; break; + case /* 4K MODE */ 255: value |= 0x7; break; + default: + case TRANSMISSION_MODE_8K: value |= 0x8; break; } ret |= dib7000m_write_word(state, 33, value); - // we achieved a lock - it's time to update the osc freq + // we achieved a lock - it's time to update the timf freq if ((dib7000m_read_word(state, 535) >> 6) & 0x1) - dib7000m_update_timf_freq(state); + dib7000m_update_timf(state); + dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); return ret; } -static int dib7000m_init(struct dvb_frontend *demod) +static int dib7000m_wakeup(struct dvb_frontend *demod) { struct dib7000m_state *state = demod->demodulator_priv; - int ret = 0; - u8 o = state->reg_offs; dib7000m_set_power_mode(state, DIB7000M_POWER_ALL); if (dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0) - dprintk("-E- could not start Slow ADC\n"); - - if (state->cfg.dvbt_mode) - dib7000m_write_word(state, 1796, 0x0); // select DVB-T output - - if (state->cfg.mobile_mode) - ret |= dib7000m_write_word(state, 261 + o, 2); - else - ret |= dib7000m_write_word(state, 224 + o, 1); - - ret |= dib7000m_write_word(state, 173 + o, 0); - ret |= dib7000m_write_word(state, 174 + o, 0); - ret |= dib7000m_write_word(state, 175 + o, 0); - ret |= dib7000m_write_word(state, 176 + o, 0); - ret |= dib7000m_write_word(state, 177 + o, 0); - ret |= dib7000m_write_word(state, 178 + o, 0); - ret |= dib7000m_write_word(state, 179 + o, 0); - ret |= dib7000m_write_word(state, 180 + o, 0); - - // P_corm_thres Lock algorithms configuration - ret |= dib7000m_write_word(state, 26, 0x6680); - - // P_palf_alpha_regul, P_palf_filter_freeze, P_palf_filter_on - ret |= dib7000m_write_word(state, 170 + o, 0x0410); - // P_fft_nb_to_cut - ret |= dib7000m_write_word(state, 182 + o, 8192); - // P_pha3_thres - ret |= dib7000m_write_word(state, 195 + o, 0x0ccd); - // P_cti_use_cpe, P_cti_use_prog - ret |= dib7000m_write_word(state, 196 + o, 0); - // P_cspu_regul, P_cspu_win_cut - ret |= dib7000m_write_word(state, 205 + o, 0x200f); - // P_adp_regul_cnt - ret |= dib7000m_write_word(state, 214 + o, 0x023d); - // P_adp_noise_cnt - ret |= dib7000m_write_word(state, 215 + o, 0x00a4); - // P_adp_regul_ext - ret |= dib7000m_write_word(state, 216 + o, 0x00a4); - // P_adp_noise_ext - ret |= dib7000m_write_word(state, 217 + o, 0x7ff0); - // P_adp_fil - ret |= dib7000m_write_word(state, 218 + o, 0x3ccc); - - // P_2d_byp_ti_num - ret |= dib7000m_write_word(state, 226 + o, 0); - - // P_fec_* - ret |= dib7000m_write_word(state, 281 + o, 0x0010); - // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard - ret |= dib7000m_write_word(state, 294 + o,0x0062); + dprintk( "could not start Slow ADC"); - // P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ... - if(state->cfg.tuner_is_baseband) - ret |= dib7000m_write_word(state, 36, 0x0755); - else - ret |= dib7000m_write_word(state, 36, 0x1f55); - - // auto search configuration - ret |= dib7000m_write_word(state, 2, 0x0004); - ret |= dib7000m_write_word(state, 3, 0x1000); - ret |= dib7000m_write_word(state, 4, 0x0814); - ret |= dib7000m_write_word(state, 6, 0x001b); - ret |= dib7000m_write_word(state, 7, 0x7740); - ret |= dib7000m_write_word(state, 8, 0x005b); - ret |= dib7000m_write_word(state, 9, 0x8d80); - ret |= dib7000m_write_word(state, 10, 0x01c9); - ret |= dib7000m_write_word(state, 11, 0xc380); - ret |= dib7000m_write_word(state, 12, 0x0000); - ret |= dib7000m_write_word(state, 13, 0x0080); - ret |= dib7000m_write_word(state, 14, 0x0000); - ret |= dib7000m_write_word(state, 15, 0x0090); - ret |= dib7000m_write_word(state, 16, 0x0001); - ret |= dib7000m_write_word(state, 17, 0xd4c0); - ret |= dib7000m_write_word(state, 263 + o,0x0001); - - // P_divclksel=3 P_divbitsel=1 - if (state->revision == 0x4000) - dib7000m_write_word(state, 909, (3 << 10) | (1 << 6)); - else - dib7000m_write_word(state, 909, (3 << 4) | 1); - - // Tuner IO bank: max drive (14mA) - ret |= dib7000m_write_word(state, 912 ,0x2c8a); - - ret |= dib7000m_write_word(state, 1817, 1); - - return ret; + return 0; } static int dib7000m_sleep(struct dvb_frontend *demod) { struct dib7000m_state *st = demod->demodulator_priv; dib7000m_set_output_mode(st, OUTMODE_HIGH_Z); - return dib7000m_set_power_mode(st, DIB7000M_POWER_INTERFACE_ONLY) | - dib7000m_set_adc_state(st, DIBX000_SLOW_ADC_OFF) | + dib7000m_set_power_mode(st, DIB7000M_POWER_INTERFACE_ONLY); + return dib7000m_set_adc_state(st, DIBX000_SLOW_ADC_OFF) | dib7000m_set_adc_state(st, DIBX000_ADC_OFF); } static int dib7000m_identify(struct dib7000m_state *state) { u16 value; + if ((value = dib7000m_read_word(state, 896)) != 0x01b3) { - dprintk("-E- DiB7000M: wrong Vendor ID (read=0x%x)\n",value); + dprintk( "wrong Vendor ID (0x%x)",value); return -EREMOTEIO; } state->revision = dib7000m_read_word(state, 897); if (state->revision != 0x4000 && state->revision != 0x4001 && - state->revision != 0x4002) { - dprintk("-E- DiB7000M: wrong Device ID (%x)\n",value); + state->revision != 0x4002 && + state->revision != 0x4003) { + dprintk( "wrong Device ID (0x%x)",value); return -EREMOTEIO; } /* protect this driver to be used with 7000PC */ if (state->revision == 0x4000 && dib7000m_read_word(state, 769) == 0x4000) { - dprintk("-E- DiB7000M: this driver does not work with DiB7000PC\n"); + dprintk( "this driver does not work with DiB7000PC"); return -EREMOTEIO; } switch (state->revision) { - case 0x4000: dprintk("-I- found DiB7000MA/PA/MB/PB\n"); break; - case 0x4001: state->reg_offs = 1; dprintk("-I- found DiB7000HC\n"); break; - case 0x4002: state->reg_offs = 1; dprintk("-I- found DiB7000MC\n"); break; + case 0x4000: dprintk( "found DiB7000MA/PA/MB/PB"); break; + case 0x4001: state->reg_offs = 1; dprintk( "found DiB7000HC"); break; + case 0x4002: state->reg_offs = 1; dprintk( "found DiB7000MC"); break; + case 0x4003: state->reg_offs = 1; dprintk( "found DiB9000"); break; } return 0; @@ -966,41 +1171,45 @@ static int dib7000m_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep) { struct dib7000m_state *state = fe->demodulator_priv; - struct dibx000_ofdm_channel ch; - - INIT_OFDM_CHANNEL(&ch); - FEP2DIB(fep,&ch); + int time; state->current_bandwidth = fep->u.ofdm.bandwidth; - dib7000m_set_bandwidth(fe, fep->u.ofdm.bandwidth); + dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth)); if (fe->ops.tuner_ops.set_params) fe->ops.tuner_ops.set_params(fe, fep); + /* start up the AGC */ + state->agc_state = 0; + do { + time = dib7000m_agc_startup(fe, fep); + if (time != -1) + msleep(time); + } while (time != -1); + if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO || fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO || fep->u.ofdm.constellation == QAM_AUTO || fep->u.ofdm.code_rate_HP == FEC_AUTO) { int i = 800, found; - dib7000m_autosearch_start(fe, &ch); + dib7000m_autosearch_start(fe, fep); do { msleep(1); found = dib7000m_autosearch_is_irq(fe); } while (found == 0 && i--); - dprintk("autosearch returns: %d\n",found); + dprintk("autosearch returns: %d",found); if (found == 0 || found == 1) return 0; // no channel found dib7000m_get_frontend(fe, fep); - FEP2DIB(fep, &ch); } /* make this a config parameter */ dib7000m_set_output_mode(state, OUTMODE_MPEG2_FIFO); - return dib7000m_tune(fe, &ch); + return dib7000m_tune(fe, fep); } static int dib7000m_read_status(struct dvb_frontend *fe, fe_status_t *stat) @@ -1087,7 +1296,7 @@ int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defau if (dib7000m_identify(&st) != 0) { st.i2c_addr = default_addr; if (dib7000m_identify(&st) != 0) { - dprintk("DiB7000M #%d: not identified\n", k); + dprintk("DiB7000M #%d: not identified", k); return -EIO; } } @@ -1100,7 +1309,7 @@ int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defau /* set new i2c address and force divstart */ dib7000m_write_word(&st, 1794, (new_addr << 2) | 0x2); - dprintk("IC %d initialized (to i2c_address 0x%x)\n", k, new_addr); + dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr); } for (k = 0; k < no_of_demods; k++) { @@ -1172,7 +1381,7 @@ static struct dvb_frontend_ops dib7000m_ops = { .release = dib7000m_release, - .init = dib7000m_init, + .init = dib7000m_wakeup, .sleep = dib7000m_sleep, .set_frontend = dib7000m_set_frontend, diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c index c24189fcbc8..156c53ab56d 100644 --- a/drivers/media/dvb/frontends/dib7000p.c +++ b/drivers/media/dvb/frontends/dib7000p.c @@ -1,7 +1,7 @@ /* * Linux-DVB Driver for DiBcom's second generation DiB7000P (PC). * - * Copyright (C) 2005-6 DiBcom (http://www.dibcom.fr/) + * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -18,7 +18,7 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); -#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000P:"); printk(args); } } while (0) +#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000P: "); printk(args); printk("\n"); } } while (0) struct dib7000p_state { struct dvb_frontend demod; @@ -36,12 +36,19 @@ struct dib7000p_state { struct dibx000_agc_config *current_agc; u32 timf; + uint8_t div_force_off : 1; + uint8_t div_state : 1; + uint16_t div_sync_wait; + + u8 agc_state; + u16 gpio_dir; u16 gpio_val; }; enum dib7000p_power_mode { DIB7000P_POWER_ALL = 0, + DIB7000P_POWER_ANALOG_ADC, DIB7000P_POWER_INTERFACE_ONLY, }; @@ -55,7 +62,7 @@ static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg) }; if (i2c_transfer(state->i2c_adap, msg, 2) != 2) - dprintk("i2c read error on %d\n",reg); + dprintk("i2c read error on %d",reg); return (rb[0] << 8) | rb[1]; } @@ -71,6 +78,22 @@ static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val) }; return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0; } +static void dib7000p_write_tab(struct dib7000p_state *state, u16 *buf) +{ + u16 l = 0, r, *n; + n = buf; + l = *n++; + while (l) { + r = *n++; + + do { + dib7000p_write_word(state, r, *n++); + r++; + } while (--l); + l = *n++; + } +} + static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode) { int ret = 0; @@ -80,7 +103,7 @@ static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode) fifo_threshold = 1792; smo_mode = (dib7000p_read_word(state, 235) & 0x0010) | (1 << 1); - dprintk("-I- Setting output mode for demod %p to %d\n", + dprintk( "setting output mode for demod %p to %d", &state->demod, mode); switch (mode) { @@ -104,19 +127,17 @@ static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode) fifo_threshold = 512; outreg = (1 << 10) | (5 << 6); break; + case OUTMODE_ANALOG_ADC: + outreg = (1 << 10) | (3 << 6); + break; case OUTMODE_HIGH_Z: // disable outreg = 0; break; default: - dprintk("Unhandled output_mode passed to be set for demod %p\n",&state->demod); + dprintk( "Unhandled output_mode passed to be set for demod %p",&state->demod); break; } - if (state->cfg.hostbus_diversity) { - ret |= dib7000p_write_word(state, 204, 1); // Diversity ? - ret |= dib7000p_write_word(state, 205, 0); // Diversity ? - } - if (state->cfg.output_mpeg2_in_188_bytes) smo_mode |= (1 << 5) ; @@ -127,6 +148,30 @@ static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode) return ret; } +static int dib7000p_set_diversity_in(struct dvb_frontend *demod, int onoff) +{ + struct dib7000p_state *state = demod->demodulator_priv; + + if (state->div_force_off) { + dprintk( "diversity combination deactivated - forced by COFDM parameters"); + onoff = 0; + } + state->div_state = (uint8_t)onoff; + + if (onoff) { + dib7000p_write_word(state, 204, 6); + dib7000p_write_word(state, 205, 16); + /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */ + dib7000p_write_word(state, 207, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0)); + } else { + dib7000p_write_word(state, 204, 1); + dib7000p_write_word(state, 205, 0); + dib7000p_write_word(state, 207, 0); + } + + return 0; +} + static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_power_mode mode) { /* by default everything is powered off */ @@ -139,10 +184,21 @@ static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_p case DIB7000P_POWER_ALL: reg_774 = 0x0000; reg_775 = 0x0000; reg_776 = 0x0; reg_899 = 0x0; reg_1280 &= 0x01ff; break; + + case DIB7000P_POWER_ANALOG_ADC: + /* dem, cfg, iqc, sad, agc */ + reg_774 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10) | (1 << 9)); + /* nud */ + reg_776 &= ~((1 << 0)); + /* Dout */ + reg_1280 &= ~((1 << 11)); + /* fall through wanted to enable the interfaces */ + /* just leave power on the control-interfaces: GPIO and (I2C or SDIO) */ case DIB7000P_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C */ reg_1280 &= ~((1 << 14) | (1 << 13) | (1 << 12) | (1 << 10)); break; + /* TODO following stuff is just converted from the dib7000-driver - check when is used what */ } @@ -193,34 +249,31 @@ static void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_ad break; } -// dprintk("908: %x, 909: %x\n", reg_908, reg_909); +// dprintk( "908: %x, 909: %x\n", reg_908, reg_909); dib7000p_write_word(state, 908, reg_908); dib7000p_write_word(state, 909, reg_909); } -static int dib7000p_set_bandwidth(struct dvb_frontend *demod, u8 BW_Idx) +static int dib7000p_set_bandwidth(struct dib7000p_state *state, u32 bw) { - struct dib7000p_state *state = demod->demodulator_priv; u32 timf; // store the current bandwidth for later use - state->current_bandwidth = BW_Idx; + state->current_bandwidth = bw; if (state->timf == 0) { - dprintk("-D- Using default timf\n"); + dprintk( "using default timf"); timf = state->cfg.bw->timf; } else { - dprintk("-D- Using updated timf\n"); + dprintk( "using updated timf"); timf = state->timf; } - timf = timf * (BW_INDEX_TO_KHZ(BW_Idx) / 100) / 80; + timf = timf * (bw / 50) / 160; - dprintk("timf: %d\n",timf); - - dib7000p_write_word(state, 23, (timf >> 16) & 0xffff); - dib7000p_write_word(state, 24, (timf ) & 0xffff); + dib7000p_write_word(state, 23, (u16) ((timf >> 16) & 0xffff)); + dib7000p_write_word(state, 24, (u16) ((timf ) & 0xffff)); return 0; } @@ -228,7 +281,7 @@ static int dib7000p_set_bandwidth(struct dvb_frontend *demod, u8 BW_Idx) static int dib7000p_sad_calib(struct dib7000p_state *state) { /* internal */ -// dib7000p_write_word(state, 72, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is written in set_bandwidth +// dib7000p_write_word(state, 72, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writting in set_bandwidth dib7000p_write_word(state, 73, (0 << 1) | (0 << 0)); dib7000p_write_word(state, 74, 776); // 0.625*3.3 / 4096 @@ -244,15 +297,24 @@ static int dib7000p_sad_calib(struct dib7000p_state *state) static void dib7000p_reset_pll(struct dib7000p_state *state) { struct dibx000_bandwidth_config *bw = &state->cfg.bw[0]; + u16 clk_cfg0; + + /* force PLL bypass */ + clk_cfg0 = (1 << 15) | ((bw->pll_ratio & 0x3f) << 9) | + (bw->modulo << 7) | (bw->ADClkSrc << 6) | (bw->IO_CLK_en_core << 5) | + (bw->bypclk_div << 2) | (bw->enable_refdiv << 1) | (0 << 0); + dib7000p_write_word(state, 900, clk_cfg0); + + /* P_pll_cfg */ dib7000p_write_word(state, 903, (bw->pll_prediv << 5) | (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset); - dib7000p_write_word(state, 900, ((bw->pll_ratio & 0x3f) << 9) | (bw->pll_bypass << 15) | (bw->modulo << 7) | (bw->ADClkSrc << 6) | - (bw->IO_CLK_en_core << 5) | (bw->bypclk_div << 2) | (bw->enable_refdiv << 1) | (0 << 0)); + clk_cfg0 = (bw->pll_bypass << 15) | (clk_cfg0 & 0x7fff); + dib7000p_write_word(state, 900, clk_cfg0); - dib7000p_write_word(state, 18, ((bw->internal*1000) >> 16) & 0xffff); - dib7000p_write_word(state, 19, (bw->internal*1000 ) & 0xffff); - dib7000p_write_word(state, 21, (bw->ifreq >> 16) & 0xffff); - dib7000p_write_word(state, 22, (bw->ifreq ) & 0xffff); + dib7000p_write_word(state, 18, (u16) (((bw->internal*1000) >> 16) & 0xffff)); + dib7000p_write_word(state, 19, (u16) ( (bw->internal*1000 ) & 0xffff)); + dib7000p_write_word(state, 21, (u16) ( (bw->ifreq >> 16) & 0xffff)); + dib7000p_write_word(state, 22, (u16) ( (bw->ifreq ) & 0xffff)); dib7000p_write_word(state, 72, bw->sad_cfg); } @@ -260,7 +322,7 @@ static void dib7000p_reset_pll(struct dib7000p_state *state) static int dib7000p_reset_gpio(struct dib7000p_state *st) { /* reset the GPIOs */ - dprintk("-D- gpio dir: %x: gpio val: %x, gpio pwm pos: %x\n",st->gpio_dir, st->gpio_val,st->cfg.gpio_pwm_pos); + dprintk( "gpio dir: %x: val: %x, pwm_pos: %x",st->gpio_dir, st->gpio_val,st->cfg.gpio_pwm_pos); dib7000p_write_word(st, 1029, st->gpio_dir); dib7000p_write_word(st, 1030, st->gpio_val); @@ -273,6 +335,98 @@ static int dib7000p_reset_gpio(struct dib7000p_state *st) return 0; } +static u16 dib7000p_defaults[] = + +{ + // auto search configuration + 3, 2, + 0x0004, + 0x1000, + 0x0814, /* Equal Lock */ + + 12, 6, + 0x001b, + 0x7740, + 0x005b, + 0x8d80, + 0x01c9, + 0xc380, + 0x0000, + 0x0080, + 0x0000, + 0x0090, + 0x0001, + 0xd4c0, + + 1, 26, + 0x6680, // P_timf_alpha=6, P_corm_alpha=6, P_corm_thres=128 default: 6,4,26 + + /* set ADC level to -16 */ + 11, 79, + (1 << 13) - 825 - 117, + (1 << 13) - 837 - 117, + (1 << 13) - 811 - 117, + (1 << 13) - 766 - 117, + (1 << 13) - 737 - 117, + (1 << 13) - 693 - 117, + (1 << 13) - 648 - 117, + (1 << 13) - 619 - 117, + (1 << 13) - 575 - 117, + (1 << 13) - 531 - 117, + (1 << 13) - 501 - 117, + + 1, 142, + 0x0410, // P_palf_filter_on=1, P_palf_filter_freeze=0, P_palf_alpha_regul=16 + + /* disable power smoothing */ + 8, 145, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + + 1, 154, + 1 << 13, // P_fft_freq_dir=1, P_fft_nb_to_cut=0 + + 1, 168, + 0x0ccd, // P_pha3_thres, default 0x3000 + +// 1, 169, +// 0x0010, // P_cti_use_cpe=0, P_cti_use_prog=0, P_cti_win_len=16, default: 0x0010 + + 1, 183, + 0x200f, // P_cspu_regul=512, P_cspu_win_cut=15, default: 0x2005 + + 5, 187, + 0x023d, // P_adp_regul_cnt=573, default: 410 + 0x00a4, // P_adp_noise_cnt= + 0x00a4, // P_adp_regul_ext + 0x7ff0, // P_adp_noise_ext + 0x3ccc, // P_adp_fil + + 1, 198, + 0x800, // P_equal_thres_wgn + + 1, 222, + 0x0010, // P_fec_ber_rs_len=2 + + 1, 235, + 0x0062, // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard + + 2, 901, + 0x0006, // P_clk_cfg1 + (3 << 10) | (1 << 6), // P_divclksel=3 P_divbitsel=1 + + 1, 905, + 0x2c8e, // Tuner IO bank: max drive (14mA) + divout pads max drive + + 0, +}; + static int dib7000p_demod_reset(struct dib7000p_state *state) { dib7000p_set_power_mode(state, DIB7000P_POWER_ALL); @@ -297,111 +451,307 @@ static int dib7000p_demod_reset(struct dib7000p_state *state) dib7000p_reset_pll(state); if (dib7000p_reset_gpio(state) != 0) - dprintk("-E- GPIO reset was not successful.\n"); + dprintk( "GPIO reset was not successful."); if (dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) != 0) - dprintk("-E- OUTPUT_MODE could not be resetted.\n"); + dprintk( "OUTPUT_MODE could not be reset."); /* unforce divstr regardless whether i2c enumeration was done or not */ dib7000p_write_word(state, 1285, dib7000p_read_word(state, 1285) & ~(1 << 1) ); + dib7000p_set_bandwidth(state, 8000); + + dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON); + dib7000p_sad_calib(state); + dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_OFF); + + // P_iqc_alpha_pha, P_iqc_alpha_amp_dcc_alpha, ... + if(state->cfg.tuner_is_baseband) + dib7000p_write_word(state, 36,0x0755); + else + dib7000p_write_word(state, 36,0x1f55); + + dib7000p_write_tab(state, dib7000p_defaults); + dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY); + return 0; } +static void dib7000p_pll_clk_cfg(struct dib7000p_state *state) +{ + u16 tmp = 0; + tmp = dib7000p_read_word(state, 903); + dib7000p_write_word(state, 903, (tmp | 0x1)); //pwr-up pll + tmp = dib7000p_read_word(state, 900); + dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6)); //use High freq clock +} + static void dib7000p_restart_agc(struct dib7000p_state *state) { // P_restart_iqc & P_restart_agc - dib7000p_write_word(state, 770, 0x0c00); + dib7000p_write_word(state, 770, (1 << 11) | (1 << 9)); dib7000p_write_word(state, 770, 0x0000); } -static void dib7000p_update_lna(struct dib7000p_state *state) +static int dib7000p_update_lna(struct dib7000p_state *state) { - int i; u16 dyn_gain; // when there is no LNA to program return immediatly - if (state->cfg.update_lna == NULL) - return; - - for (i = 0; i < 5; i++) { + if (state->cfg.update_lna) { // read dyn_gain here (because it is demod-dependent and not tuner) dyn_gain = dib7000p_read_word(state, 394); - if (state->cfg.update_lna(&state->demod,dyn_gain)) { // LNA has changed dib7000p_restart_agc(state); - msleep(5); - } else + return 1; + } + } + + return 0; +} + +static int dib7000p_set_agc_config(struct dib7000p_state *state, u8 band) +{ + struct dibx000_agc_config *agc = NULL; + int i; + if (state->current_band == band && state->current_agc != NULL) + return 0; + state->current_band = band; + + for (i = 0; i < state->cfg.agc_config_count; i++) + if (state->cfg.agc[i].band_caps & band) { + agc = &state->cfg.agc[i]; break; + } + + if (agc == NULL) { + dprintk( "no valid AGC configuration found for band 0x%02x",band); + return -EINVAL; } + + state->current_agc = agc; + + /* AGC */ + dib7000p_write_word(state, 75 , agc->setup ); + dib7000p_write_word(state, 76 , agc->inv_gain ); + dib7000p_write_word(state, 77 , agc->time_stabiliz ); + dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock); + + // Demod AGC loop configuration + dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp); + dib7000p_write_word(state, 102, (agc->beta_mant << 6) | agc->beta_exp); + + /* AGC continued */ + dprintk( "WBD: ref: %d, sel: %d, active: %d, alpha: %d", + state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel); + + if (state->wbd_ref != 0) + dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | state->wbd_ref); + else + dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | agc->wbd_ref); + + dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8)); + + dib7000p_write_word(state, 107, agc->agc1_max); + dib7000p_write_word(state, 108, agc->agc1_min); + dib7000p_write_word(state, 109, agc->agc2_max); + dib7000p_write_word(state, 110, agc->agc2_min); + dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2); + dib7000p_write_word(state, 112, agc->agc1_pt3); + dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2); + dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2); + dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2); + return 0; } -static void dib7000p_pll_clk_cfg(struct dib7000p_state *state) +static int dib7000p_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) { - u16 tmp = 0; - tmp = dib7000p_read_word(state, 903); - dib7000p_write_word(state, 903, (tmp | 0x1)); //pwr-up pll - tmp = dib7000p_read_word(state, 900); - dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6)); //use High freq clock + struct dib7000p_state *state = demod->demodulator_priv; + int ret = -1; + u8 *agc_state = &state->agc_state; + u8 agc_split; + + switch (state->agc_state) { + case 0: + // set power-up level: interf+analog+AGC + dib7000p_set_power_mode(state, DIB7000P_POWER_ALL); + dib7000p_set_adc_state(state, DIBX000_ADC_ON); + dib7000p_pll_clk_cfg(state); + + if (dib7000p_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency/1000)) != 0) + return -1; + + ret = 7; + (*agc_state)++; + break; + + case 1: + // AGC initialization + if (state->cfg.agc_control) + state->cfg.agc_control(&state->demod, 1); + + dib7000p_write_word(state, 78, 32768); + if (!state->current_agc->perform_agc_softsplit) { + /* we are using the wbd - so slow AGC startup */ + /* force 0 split on WBD and restart AGC */ + dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | (1 << 8)); + (*agc_state)++; + ret = 5; + } else { + /* default AGC startup */ + (*agc_state) = 4; + /* wait AGC rough lock time */ + ret = 7; + } + + dib7000p_restart_agc(state); + break; + + case 2: /* fast split search path after 5sec */ + dib7000p_write_word(state, 75, state->current_agc->setup | (1 << 4)); /* freeze AGC loop */ + dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (2 << 9) | (0 << 8)); /* fast split search 0.25kHz */ + (*agc_state)++; + ret = 14; + break; + + case 3: /* split search ended */ + agc_split = (uint8_t)dib7000p_read_word(state, 396); /* store the split value for the next time */ + dib7000p_write_word(state, 78, dib7000p_read_word(state, 394)); /* set AGC gain start value */ + + dib7000p_write_word(state, 75, state->current_agc->setup); /* std AGC loop */ + dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */ + + dib7000p_restart_agc(state); + + dprintk( "SPLIT %p: %hd", demod, agc_split); + + (*agc_state)++; + ret = 5; + break; + + case 4: /* LNA startup */ + // wait AGC accurate lock time + ret = 7; + + if (dib7000p_update_lna(state)) + // wait only AGC rough lock time + ret = 5; + else // nothing was done, go to the next state + (*agc_state)++; + break; + + case 5: + if (state->cfg.agc_control) + state->cfg.agc_control(&state->demod, 0); + (*agc_state)++; + break; + default: + break; + } + return ret; } -static void dib7000p_update_timf_freq(struct dib7000p_state *state) +static void dib7000p_update_timf(struct dib7000p_state *state) { u32 timf = (dib7000p_read_word(state, 427) << 16) | dib7000p_read_word(state, 428); - state->timf = timf * 80 / (BW_INDEX_TO_KHZ(state->current_bandwidth) / 100); + state->timf = timf * 160 / (state->current_bandwidth / 50); dib7000p_write_word(state, 23, (u16) (timf >> 16)); dib7000p_write_word(state, 24, (u16) (timf & 0xffff)); - dprintk("-D- Updated timf_frequency: %d (default: %d)\n",state->timf, state->cfg.bw->timf); + dprintk( "updated timf_frequency: %d (default: %d)",state->timf, state->cfg.bw->timf); + } -static void dib7000p_set_channel(struct dib7000p_state *state, struct dibx000_ofdm_channel *ch, u8 seq) +static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_frontend_parameters *ch, u8 seq) { - u16 tmp, est[4]; // reg_26, reg_32, reg_33, reg_187, reg_188, reg_189, reg_190, reg_207, reg_208; + u16 value, est[4]; + + dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); /* nfft, guard, qam, alpha */ - dib7000p_write_word(state, 0, (ch->nfft << 7) | (ch->guard << 5) | (ch->nqam << 3) | (ch->vit_alpha)); + value = 0; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: value |= (0 << 7); break; + case /* 4K MODE */ 255: value |= (2 << 7); break; + default: + case TRANSMISSION_MODE_8K: value |= (1 << 7); break; + } + switch (ch->u.ofdm.guard_interval) { + case GUARD_INTERVAL_1_32: value |= (0 << 5); break; + case GUARD_INTERVAL_1_16: value |= (1 << 5); break; + case GUARD_INTERVAL_1_4: value |= (3 << 5); break; + default: + case GUARD_INTERVAL_1_8: value |= (2 << 5); break; + } + switch (ch->u.ofdm.constellation) { + case QPSK: value |= (0 << 3); break; + case QAM_16: value |= (1 << 3); break; + default: + case QAM_64: value |= (2 << 3); break; + } + switch (HIERARCHY_1) { + case HIERARCHY_2: value |= 2; break; + case HIERARCHY_4: value |= 4; break; + default: + case HIERARCHY_1: value |= 1; break; + } + dib7000p_write_word(state, 0, value); dib7000p_write_word(state, 5, (seq << 4) | 1); /* do not force tps, search list 0 */ - /* P_dintl_native, P_dintlv_inv, P_vit_hrch, P_vit_code_rate, P_vit_select_hp */ - tmp = (ch->intlv_native << 6) | (ch->vit_hrch << 4) | (ch->vit_select_hp & 0x1); - if (ch->vit_hrch == 0 || ch->vit_select_hp == 1) - tmp |= (ch->vit_code_rate_hp << 1); - else - tmp |= (ch->vit_code_rate_lp << 1); - dib7000p_write_word(state, 208, tmp); + /* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */ + value = 0; + if (1 != 0) + value |= (1 << 6); + if (ch->u.ofdm.hierarchy_information == 1) + value |= (1 << 4); + if (1 == 1) + value |= 1; + switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) { + case FEC_2_3: value |= (2 << 1); break; + case FEC_3_4: value |= (3 << 1); break; + case FEC_5_6: value |= (5 << 1); break; + case FEC_7_8: value |= (7 << 1); break; + default: + case FEC_1_2: value |= (1 << 1); break; + } + dib7000p_write_word(state, 208, value); + + /* offset loop parameters */ + dib7000p_write_word(state, 26, 0x6680); // timf(6xxx) + dib7000p_write_word(state, 29, 0x1273); // isi inh1273 on1073 + dib7000p_write_word(state, 32, 0x0003); // pha_off_max(xxx3) + dib7000p_write_word(state, 33, 0x0005); // sfreq(xxx5) /* P_dvsy_sync_wait */ - switch (ch->nfft) { - case 1: tmp = 256; break; - case 2: tmp = 128; break; - case 0: - default: tmp = 64; break; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_8K: value = 256; break; + case /* 4K MODE */ 255: value = 128; break; + case TRANSMISSION_MODE_2K: + default: value = 64; break; } - tmp *= ((1 << (ch->guard)) * 3 / 2); // add 50% SFN margin - tmp <<= 4; - - /* deactive the possibility of diversity reception if extended interleave */ - /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */ - if (ch->intlv_native || ch->nfft == 1) - tmp |= (1 << 2) | (2 << 0); - dib7000p_write_word(state, 207, tmp); + switch (ch->u.ofdm.guard_interval) { + case GUARD_INTERVAL_1_16: value *= 2; break; + case GUARD_INTERVAL_1_8: value *= 4; break; + case GUARD_INTERVAL_1_4: value *= 8; break; + default: + case GUARD_INTERVAL_1_32: value *= 1; break; + } + state->div_sync_wait = (value * 3) / 2 + 32; // add 50% SFN margin + compensate for one DVSY-fifo TODO - dib7000p_write_word(state, 26, 0x6680); // timf(6xxx) - dib7000p_write_word(state, 29, 0x1273); // isi inh1273 on1073 - dib7000p_write_word(state, 32, 0x0003); // pha_off_max(xxx3) - dib7000p_write_word(state, 33, 0x0005); // sfreq(xxx5) + /* deactive the possibility of diversity reception if extended interleaver */ + state->div_force_off = !1 && ch->u.ofdm.transmission_mode != TRANSMISSION_MODE_8K; + dib7000p_set_diversity_in(&state->demod, state->div_state); /* channel estimation fine configuration */ - switch (ch->nqam) { - case 2: + switch (ch->u.ofdm.constellation) { + case QAM_64: est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */ est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */ est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */ est[3] = 0xfff8; /* P_adp_noise_ext -0.001 */ break; - case 1: + case QAM_16: est[0] = 0x023d; /* P_adp_regul_cnt 0.07 */ est[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */ est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */ @@ -414,66 +764,45 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dibx000_of est[3] = 0xfff8; /* P_adp_noise_ext -0.002 */ break; } - for (tmp = 0; tmp < 4; tmp++) - dib7000p_write_word(state, 187 + tmp, est[tmp]); - - // set power-up level: interf+analog+AGC - dib7000p_set_power_mode(state, DIB7000P_POWER_ALL); - dib7000p_set_adc_state(state, DIBX000_ADC_ON); - dib7000p_pll_clk_cfg(state); - msleep(7); - - // AGC initialization - if (state->cfg.agc_control) - state->cfg.agc_control(&state->demod, 1); - - dib7000p_restart_agc(state); - - // wait AGC rough lock time - msleep(5); - - dib7000p_update_lna(state); - - // wait AGC accurate lock time - msleep(7); - if (state->cfg.agc_control) - state->cfg.agc_control(&state->demod, 0); + for (value = 0; value < 4; value++) + dib7000p_write_word(state, 187 + value, est[value]); } -static int dib7000p_autosearch_start(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch) +static int dib7000p_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) { struct dib7000p_state *state = demod->demodulator_priv; - struct dibx000_ofdm_channel auto_ch; - u32 value; - - INIT_OFDM_CHANNEL(&auto_ch); - auto_ch.RF_kHz = ch->RF_kHz; - auto_ch.Bw = ch->Bw; - auto_ch.nqam = 2; - auto_ch.guard = 0; - auto_ch.nfft = 1; - auto_ch.vit_alpha = 1; - auto_ch.vit_select_hp = 1; - auto_ch.vit_code_rate_hp = 2; - auto_ch.vit_code_rate_lp = 3; - auto_ch.vit_hrch = 0; - auto_ch.intlv_native = 1; - - dib7000p_set_channel(state, &auto_ch, 7); + struct dvb_frontend_parameters schan; + u32 value, factor; + + schan = *ch; + schan.u.ofdm.constellation = QAM_64; + schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32; + schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; + schan.u.ofdm.code_rate_HP = FEC_2_3; + schan.u.ofdm.code_rate_LP = FEC_3_4; + schan.u.ofdm.hierarchy_information = 0; + + dib7000p_set_channel(state, &schan, 7); + + factor = BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth); + if (factor >= 5000) + factor = 1; + else + factor = 6; // always use the setting for 8MHz here lock_time for 7,6 MHz are longer - value = 30 * state->cfg.bw->internal; + value = 30 * state->cfg.bw->internal * factor; dib7000p_write_word(state, 6, (u16) ((value >> 16) & 0xffff)); // lock0 wait time dib7000p_write_word(state, 7, (u16) (value & 0xffff)); // lock0 wait time - value = 100 * state->cfg.bw->internal; + value = 100 * state->cfg.bw->internal * factor; dib7000p_write_word(state, 8, (u16) ((value >> 16) & 0xffff)); // lock1 wait time dib7000p_write_word(state, 9, (u16) (value & 0xffff)); // lock1 wait time - value = 500 * state->cfg.bw->internal; + value = 500 * state->cfg.bw->internal * factor; dib7000p_write_word(state, 10, (u16) ((value >> 16) & 0xffff)); // lock2 wait time dib7000p_write_word(state, 11, (u16) (value & 0xffff)); // lock2 wait time value = dib7000p_read_word(state, 0); - dib7000p_write_word(state, 0, (1 << 9) | value); + dib7000p_write_word(state, 0, (u16) ((1 << 9) | value)); dib7000p_read_word(state, 1284); dib7000p_write_word(state, 0, (u16) value); @@ -494,7 +823,95 @@ static int dib7000p_autosearch_is_irq(struct dvb_frontend *demod) return 0; // still pending } -static int dib7000p_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch) +static void dib7000p_spur_protect(struct dib7000p_state *state, u32 rf_khz, u32 bw) +{ + static s16 notch[]={16143, 14402, 12238, 9713, 6902, 3888, 759, -2392}; + static u8 sine [] ={0, 2, 3, 5, 6, 8, 9, 11, 13, 14, 16, 17, 19, 20, 22, + 24, 25, 27, 28, 30, 31, 33, 34, 36, 38, 39, 41, 42, 44, 45, 47, 48, 50, 51, + 53, 55, 56, 58, 59, 61, 62, 64, 65, 67, 68, 70, 71, 73, 74, 76, 77, 79, 80, + 82, 83, 85, 86, 88, 89, 91, 92, 94, 95, 97, 98, 99, 101, 102, 104, 105, + 107, 108, 109, 111, 112, 114, 115, 117, 118, 119, 121, 122, 123, 125, 126, + 128, 129, 130, 132, 133, 134, 136, 137, 138, 140, 141, 142, 144, 145, 146, + 147, 149, 150, 151, 152, 154, 155, 156, 157, 159, 160, 161, 162, 164, 165, + 166, 167, 168, 170, 171, 172, 173, 174, 175, 177, 178, 179, 180, 181, 182, + 183, 184, 185, 186, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + 199, 200, 201, 202, 203, 204, 205, 206, 207, 207, 208, 209, 210, 211, 212, + 213, 214, 215, 215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 224, + 225, 226, 227, 227, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 235, + 235, 236, 237, 237, 238, 238, 239, 239, 240, 241, 241, 242, 242, 243, 243, + 244, 244, 245, 245, 245, 246, 246, 247, 247, 248, 248, 248, 249, 249, 249, + 250, 250, 250, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 254, + 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255}; + + u32 xtal = state->cfg.bw->xtal_hz / 1000; + int f_rel = ( (rf_khz + xtal/2) / xtal) * xtal - rf_khz; + int k; + int coef_re[8],coef_im[8]; + int bw_khz = bw; + u32 pha; + + dprintk( "relative position of the Spur: %dk (RF: %dk, XTAL: %dk)", f_rel, rf_khz, xtal); + + + if (f_rel < -bw_khz/2 || f_rel > bw_khz/2) + return; + + bw_khz /= 100; + + dib7000p_write_word(state, 142 ,0x0610); + + for (k = 0; k < 8; k++) { + pha = ((f_rel * (k+1) * 112 * 80/bw_khz) /1000) & 0x3ff; + + if (pha==0) { + coef_re[k] = 256; + coef_im[k] = 0; + } else if(pha < 256) { + coef_re[k] = sine[256-(pha&0xff)]; + coef_im[k] = sine[pha&0xff]; + } else if (pha == 256) { + coef_re[k] = 0; + coef_im[k] = 256; + } else if (pha < 512) { + coef_re[k] = -sine[pha&0xff]; + coef_im[k] = sine[256 - (pha&0xff)]; + } else if (pha == 512) { + coef_re[k] = -256; + coef_im[k] = 0; + } else if (pha < 768) { + coef_re[k] = -sine[256-(pha&0xff)]; + coef_im[k] = -sine[pha&0xff]; + } else if (pha == 768) { + coef_re[k] = 0; + coef_im[k] = -256; + } else { + coef_re[k] = sine[pha&0xff]; + coef_im[k] = -sine[256 - (pha&0xff)]; + } + + coef_re[k] *= notch[k]; + coef_re[k] += (1<<14); + if (coef_re[k] >= (1<<24)) + coef_re[k] = (1<<24) - 1; + coef_re[k] /= (1<<15); + + coef_im[k] *= notch[k]; + coef_im[k] += (1<<14); + if (coef_im[k] >= (1<<24)) + coef_im[k] = (1<<24)-1; + coef_im[k] /= (1<<15); + + dprintk( "PALF COEF: %d re: %d im: %d", k, coef_re[k], coef_im[k]); + + dib7000p_write_word(state, 143, (0 << 14) | (k << 10) | (coef_re[k] & 0x3ff)); + dib7000p_write_word(state, 144, coef_im[k] & 0x3ff); + dib7000p_write_word(state, 143, (1 << 14) | (k << 10) | (coef_re[k] & 0x3ff)); + } + dib7000p_write_word(state,143 ,0); +} + +static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) { struct dib7000p_state *state = demod->demodulator_priv; u16 tmp = 0; @@ -520,28 +937,31 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel /* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */ tmp = (6 << 8) | 0x80; - switch (ch->nfft) { - case 0: tmp |= (7 << 12); break; - case 1: tmp |= (9 << 12); break; - case 2: tmp |= (8 << 12); break; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: tmp |= (7 << 12); break; + case /* 4K MODE */ 255: tmp |= (8 << 12); break; + default: + case TRANSMISSION_MODE_8K: tmp |= (9 << 12); break; } dib7000p_write_word(state, 26, tmp); /* timf_a(6xxx) */ /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */ tmp = (0 << 4); - switch (ch->nfft) { - case 0: tmp |= 0x6; break; - case 1: tmp |= 0x8; break; - case 2: tmp |= 0x7; break; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: tmp |= 0x6; break; + case /* 4K MODE */ 255: tmp |= 0x7; break; + default: + case TRANSMISSION_MODE_8K: tmp |= 0x8; break; } dib7000p_write_word(state, 32, tmp); /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */ tmp = (0 << 4); - switch (ch->nfft) { - case 0: tmp |= 0x6; break; - case 1: tmp |= 0x8; break; - case 2: tmp |= 0x7; break; + switch (ch->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: tmp |= 0x6; break; + case /* 4K MODE */ 255: tmp |= 0x7; break; + default: + case TRANSMISSION_MODE_8K: tmp |= 0x8; break; } dib7000p_write_word(state, 33, tmp); @@ -557,131 +977,21 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel // we achieved a lock - it's time to update the osc freq if ((tmp >> 6) & 0x1) - dib7000p_update_timf_freq(state); + dib7000p_update_timf(state); + + if (state->cfg.spur_protect) + dib7000p_spur_protect(state, ch->frequency/1000, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); + dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); return 0; } -static int dib7000p_init(struct dvb_frontend *demod) +static int dib7000p_wakeup(struct dvb_frontend *demod) { - struct dibx000_agc_config *agc; struct dib7000p_state *state = demod->demodulator_priv; - int ret = 0; - - // Demodulator default configuration - agc = state->cfg.agc; - dib7000p_set_power_mode(state, DIB7000P_POWER_ALL); dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON); - - /* AGC */ - ret |= dib7000p_write_word(state, 75 , agc->setup ); - ret |= dib7000p_write_word(state, 76 , agc->inv_gain ); - ret |= dib7000p_write_word(state, 77 , agc->time_stabiliz ); - ret |= dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock); - - // Demod AGC loop configuration - ret |= dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp); - ret |= dib7000p_write_word(state, 102, (agc->beta_mant << 6) | agc->beta_exp); - - /* AGC continued */ - dprintk("-D- WBD: ref: %d, sel: %d, active: %d, alpha: %d\n", - state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel); - - if (state->wbd_ref != 0) - ret |= dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | state->wbd_ref); - else - ret |= dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | agc->wbd_ref); - - ret |= dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8) ); - - ret |= dib7000p_write_word(state, 107, agc->agc1_max); - ret |= dib7000p_write_word(state, 108, agc->agc1_min); - ret |= dib7000p_write_word(state, 109, agc->agc2_max); - ret |= dib7000p_write_word(state, 110, agc->agc2_min); - ret |= dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2 ); - ret |= dib7000p_write_word(state, 112, agc->agc1_pt3); - ret |= dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2); - ret |= dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2); - ret |= dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2); - - /* disable power smoothing */ - ret |= dib7000p_write_word(state, 145, 0); - ret |= dib7000p_write_word(state, 146, 0); - ret |= dib7000p_write_word(state, 147, 0); - ret |= dib7000p_write_word(state, 148, 0); - ret |= dib7000p_write_word(state, 149, 0); - ret |= dib7000p_write_word(state, 150, 0); - ret |= dib7000p_write_word(state, 151, 0); - ret |= dib7000p_write_word(state, 152, 0); - - // P_timf_alpha=6, P_corm_alpha=6, P_corm_thres=128 default: 6,4,26 - ret |= dib7000p_write_word(state, 26 ,0x6680); - - // P_palf_filter_on=1, P_palf_filter_freeze=0, P_palf_alpha_regul=16 - ret |= dib7000p_write_word(state, 142,0x0410); - // P_fft_freq_dir=1, P_fft_nb_to_cut=0 - ret |= dib7000p_write_word(state, 154,1 << 13); - // P_pha3_thres, default 0x3000 - ret |= dib7000p_write_word(state, 168,0x0ccd); - // P_cti_use_cpe=0, P_cti_use_prog=0, P_cti_win_len=16, default: 0x0010 - //ret |= dib7000p_write_word(state, 169,0x0010); - // P_cspu_regul=512, P_cspu_win_cut=15, default: 0x2005 - ret |= dib7000p_write_word(state, 183,0x200f); - // P_adp_regul_cnt=573, default: 410 - ret |= dib7000p_write_word(state, 187,0x023d); - // P_adp_noise_cnt= - ret |= dib7000p_write_word(state, 188,0x00a4); - // P_adp_regul_ext - ret |= dib7000p_write_word(state, 189,0x00a4); - // P_adp_noise_ext - ret |= dib7000p_write_word(state, 190,0x7ff0); - // P_adp_fil - ret |= dib7000p_write_word(state, 191,0x3ccc); - - ret |= dib7000p_write_word(state, 222,0x0010); - // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard - ret |= dib7000p_write_word(state, 235,0x0062); - - // P_iqc_alpha_pha, P_iqc_alpha_amp_dcc_alpha, ... - if(state->cfg.tuner_is_baseband) - ret |= dib7000p_write_word(state, 36,0x0755); - else - ret |= dib7000p_write_word(state, 36,0x1f55); - - // auto search configuration - ret |= dib7000p_write_word(state, 2 ,0x0004); - ret |= dib7000p_write_word(state, 3 ,0x1000); - - /* Equal Lock */ - ret |= dib7000p_write_word(state, 4 ,0x0814); - - ret |= dib7000p_write_word(state, 6 ,0x001b); - ret |= dib7000p_write_word(state, 7 ,0x7740); - ret |= dib7000p_write_word(state, 8 ,0x005b); - ret |= dib7000p_write_word(state, 9 ,0x8d80); - ret |= dib7000p_write_word(state, 10 ,0x01c9); - ret |= dib7000p_write_word(state, 11 ,0xc380); - ret |= dib7000p_write_word(state, 12 ,0x0000); - ret |= dib7000p_write_word(state, 13 ,0x0080); - ret |= dib7000p_write_word(state, 14 ,0x0000); - ret |= dib7000p_write_word(state, 15 ,0x0090); - ret |= dib7000p_write_word(state, 16 ,0x0001); - ret |= dib7000p_write_word(state, 17 ,0xd4c0); - - // P_clk_cfg1 - ret |= dib7000p_write_word(state, 901, 0x0006); - - // P_divclksel=3 P_divbitsel=1 - ret |= dib7000p_write_word(state, 902, (3 << 10) | (1 << 6)); - - // Tuner IO bank: max drive (14mA) + divout pads max drive - ret |= dib7000p_write_word(state, 905, 0x2c8e); - - ret |= dib7000p_set_bandwidth(&state->demod, BANDWIDTH_8_MHZ); - dib7000p_sad_calib(state); - - return ret; + return 0; } static int dib7000p_sleep(struct dvb_frontend *demod) @@ -693,16 +1003,16 @@ static int dib7000p_sleep(struct dvb_frontend *demod) static int dib7000p_identify(struct dib7000p_state *st) { u16 value; - dprintk("-I- DiB7000PC: checking demod on I2C address: %d (%x)\n", + dprintk( "checking demod on I2C address: %d (%x)", st->i2c_addr, st->i2c_addr); if ((value = dib7000p_read_word(st, 768)) != 0x01b3) { - dprintk("-E- DiB7000PC: wrong Vendor ID (read=0x%x)\n",value); + dprintk( "wrong Vendor ID (read=0x%x)",value); return -EREMOTEIO; } if ((value = dib7000p_read_word(st, 769)) != 0x4000) { - dprintk("-E- DiB7000PC: wrong Device ID (%x)\n",value); + dprintk( "wrong Device ID (%x)",value); return -EREMOTEIO; } @@ -772,41 +1082,45 @@ static int dib7000p_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep) { struct dib7000p_state *state = fe->demodulator_priv; - struct dibx000_ofdm_channel ch; - - INIT_OFDM_CHANNEL(&ch); - FEP2DIB(fep,&ch); + int time; state->current_bandwidth = fep->u.ofdm.bandwidth; - dib7000p_set_bandwidth(fe, fep->u.ofdm.bandwidth); + dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth)); if (fe->ops.tuner_ops.set_params) fe->ops.tuner_ops.set_params(fe, fep); + /* start up the AGC */ + state->agc_state = 0; + do { + time = dib7000p_agc_startup(fe, fep); + if (time != -1) + msleep(time); + } while (time != -1); + if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO || fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO || fep->u.ofdm.constellation == QAM_AUTO || fep->u.ofdm.code_rate_HP == FEC_AUTO) { int i = 800, found; - dib7000p_autosearch_start(fe, &ch); + dib7000p_autosearch_start(fe, fep); do { msleep(1); found = dib7000p_autosearch_is_irq(fe); } while (found == 0 && i--); - dprintk("autosearch returns: %d\n",found); + dprintk("autosearch returns: %d",found); if (found == 0 || found == 1) return 0; // no channel found dib7000p_get_frontend(fe, fep); - FEP2DIB(fep, &ch); } /* make this a config parameter */ dib7000p_set_output_mode(state, OUTMODE_MPEG2_FIFO); - return dib7000p_tune(fe, &ch); + return dib7000p_tune(fe, fep); } static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t *stat) @@ -884,7 +1198,7 @@ int dib7000pc_detection(struct i2c_adapter *i2c_adap) if (i2c_transfer(i2c_adap, msg, 2) == 2) if (rx[0] == 0x01 && rx[1] == 0xb3) { - dprintk("-D- DiB7000PC detected\n"); + dprintk("-D- DiB7000PC detected"); return 1; } @@ -892,11 +1206,11 @@ int dib7000pc_detection(struct i2c_adapter *i2c_adap) if (i2c_transfer(i2c_adap, msg, 2) == 2) if (rx[0] == 0x01 && rx[1] == 0xb3) { - dprintk("-D- DiB7000PC detected\n"); + dprintk("-D- DiB7000PC detected"); return 1; } - dprintk("-D- DiB7000PC not detected\n"); + dprintk("-D- DiB7000PC not detected"); return 0; } EXPORT_SYMBOL(dib7000pc_detection); @@ -934,7 +1248,7 @@ int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defau /* set new i2c address and force divstart */ dib7000p_write_word(&st, 1285, (new_addr << 2) | 0x2); - dprintk("IC %d initialized (to i2c_address 0x%x)\n", k, new_addr); + dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr); } for (k = 0; k < no_of_demods; k++) { @@ -1005,7 +1319,7 @@ static struct dvb_frontend_ops dib7000p_ops = { .release = dib7000p_release, - .init = dib7000p_init, + .init = dib7000p_wakeup, .sleep = dib7000p_sleep, .set_frontend = dib7000p_set_frontend, diff --git a/drivers/media/dvb/frontends/dib7000p.h b/drivers/media/dvb/frontends/dib7000p.h index 94829c1ed05..e7769e7cd92 100644 --- a/drivers/media/dvb/frontends/dib7000p.h +++ b/drivers/media/dvb/frontends/dib7000p.h @@ -9,6 +9,7 @@ struct dib7000p_config { u8 tuner_is_baseband; int (*update_lna) (struct dvb_frontend *, u16 agc_global); + u8 agc_config_count; struct dibx000_agc_config *agc; struct dibx000_bandwidth_config *bw; @@ -27,15 +28,19 @@ struct dib7000p_config { u8 quartz_direct; + u8 spur_protect; + int (*agc_control) (struct dvb_frontend *, u8 before); }; #define DEFAULT_DIB7000P_I2C_ADDRESS 18 extern struct dvb_frontend * dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg); +extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[]); + extern struct i2c_adapter * dib7000p_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int); extern int dib7000pc_detection(struct i2c_adapter *i2c_adap); -extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[]); + /* TODO extern INT dib7000p_set_gpio(struct dibDemod *demod, UCHAR num, UCHAR dir, UCHAR val); extern INT dib7000p_enable_vbg_voltage(struct dibDemod *demod); diff --git a/drivers/media/dvb/frontends/dibx000_common.h b/drivers/media/dvb/frontends/dibx000_common.h index a1df604366c..5e17275afd2 100644 --- a/drivers/media/dvb/frontends/dibx000_common.h +++ b/drivers/media/dvb/frontends/dibx000_common.h @@ -111,6 +111,8 @@ struct dibx000_bandwidth_config { u32 ifreq; u32 timf; + + u32 xtal_hz; }; enum dibx000_adc_states { @@ -122,56 +124,17 @@ enum dibx000_adc_states { DIBX000_VBG_DISABLE, }; -#define BW_INDEX_TO_KHZ(v) ( (v) == BANDWIDTH_8_MHZ ? 8000 : \ +#define BANDWIDTH_TO_KHZ(v) ( (v) == BANDWIDTH_8_MHZ ? 8000 : \ (v) == BANDWIDTH_7_MHZ ? 7000 : \ (v) == BANDWIDTH_6_MHZ ? 6000 : 8000 ) /* Chip output mode. */ -#define OUTMODE_HIGH_Z 0 -#define OUTMODE_MPEG2_PAR_GATED_CLK 1 -#define OUTMODE_MPEG2_PAR_CONT_CLK 2 -#define OUTMODE_MPEG2_SERIAL 7 -#define OUTMODE_DIVERSITY 4 -#define OUTMODE_MPEG2_FIFO 5 - -/* I hope I can get rid of the following kludge in the near future */ -struct dibx000_ofdm_channel { - u32 RF_kHz; - u8 Bw; - s16 nfft; - s16 guard; - s16 nqam; - s16 vit_hrch; - s16 vit_select_hp; - s16 vit_alpha; - s16 vit_code_rate_hp; - s16 vit_code_rate_lp; - u8 intlv_native; -}; - -#define FEP2DIB(fep,ch) \ - (ch)->RF_kHz = (fep)->frequency / 1000; \ - (ch)->Bw = (fep)->u.ofdm.bandwidth; \ - (ch)->nfft = (fep)->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ? -1 : (fep)->u.ofdm.transmission_mode; \ - (ch)->guard = (fep)->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO ? -1 : (fep)->u.ofdm.guard_interval; \ - (ch)->nqam = (fep)->u.ofdm.constellation == QAM_AUTO ? -1 : (fep)->u.ofdm.constellation == QAM_64 ? 2 : (fep)->u.ofdm.constellation; \ - (ch)->vit_hrch = 0; /* linux-dvb is not prepared for HIERARCHICAL TRANSMISSION */ \ - (ch)->vit_select_hp = 1; \ - (ch)->vit_alpha = 1; \ - (ch)->vit_code_rate_hp = (fep)->u.ofdm.code_rate_HP == FEC_AUTO ? -1 : (fep)->u.ofdm.code_rate_HP; \ - (ch)->vit_code_rate_lp = (fep)->u.ofdm.code_rate_LP == FEC_AUTO ? -1 : (fep)->u.ofdm.code_rate_LP; \ - (ch)->intlv_native = 1; - -#define INIT_OFDM_CHANNEL(ch) do {\ - (ch)->Bw = 0; \ - (ch)->nfft = -1; \ - (ch)->guard = -1; \ - (ch)->nqam = -1; \ - (ch)->vit_hrch = -1; \ - (ch)->vit_select_hp = -1; \ - (ch)->vit_alpha = -1; \ - (ch)->vit_code_rate_hp = -1; \ - (ch)->vit_code_rate_lp = -1; \ -} while (0) +#define OUTMODE_HIGH_Z 0 +#define OUTMODE_MPEG2_PAR_GATED_CLK 1 +#define OUTMODE_MPEG2_PAR_CONT_CLK 2 +#define OUTMODE_MPEG2_SERIAL 7 +#define OUTMODE_DIVERSITY 4 +#define OUTMODE_MPEG2_FIFO 5 +#define OUTMODE_ANALOG_ADC 6 #endif diff --git a/drivers/media/dvb/frontends/mt2266.c b/drivers/media/dvb/frontends/mt2266.c index 145135778bc..33b388e8f7b 100644 --- a/drivers/media/dvb/frontends/mt2266.c +++ b/drivers/media/dvb/frontends/mt2266.c @@ -159,7 +159,7 @@ static int mt2266_set_params(struct dvb_frontend *fe, struct dvb_frontend_parame b[3] = tune >> 13; mt2266_writeregs(priv,b,4); - dprintk("set_parms: tune=%d band=%d\n",(int)tune,(int)lnaband); + dprintk("set_parms: tune=%d band=%d",(int)tune,(int)lnaband); dprintk("set_parms: [1..3]: %2x %2x %2x",(int)b[1],(int)b[2],(int)b[3]); b[0] = 0x05; @@ -176,7 +176,7 @@ static int mt2266_set_params(struct dvb_frontend *fe, struct dvb_frontend_parame msleep(10); i++; } while (i<10); - dprintk("Lock when i=%i\n",(int)i); + dprintk("Lock when i=%i",(int)i); return ret; } -- cgit v1.2.3-70-g09d2 From 01373a5c97ced83d4cb520f7e56c80454a198bfb Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Mon, 30 Jul 2007 12:49:04 -0300 Subject: V4L/DVB (5955): Add support for DiB7070-based devices This changeset adds support for DiB7070P-based devices by adding the dib0070-driver and putting the appropriate layouts into dib0700_devices.c It also includes a new firmware for the dib0700 which is necessary to make the DiB7070-boards work and it also should fix the i2c-problems on some boards. Signed-off-by: Jean-Philippe Sibers Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/Kconfig | 1 + drivers/media/dvb/dvb-usb/dib0700_devices.c | 295 +++++++++++++- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 10 +- drivers/media/dvb/frontends/Kconfig | 9 + drivers/media/dvb/frontends/Makefile | 1 + drivers/media/dvb/frontends/dib0070.c | 580 ++++++++++++++++++++++++++++ drivers/media/dvb/frontends/dib0070.h | 44 +++ drivers/media/dvb/frontends/dib3000mc.c | 2 +- drivers/media/dvb/frontends/dib7000m.c | 12 +- drivers/media/dvb/frontends/dib7000p.c | 44 ++- drivers/media/dvb/frontends/dib7000p.h | 9 +- 11 files changed, 974 insertions(+), 33 deletions(-) create mode 100644 drivers/media/dvb/frontends/dib0070.c create mode 100644 drivers/media/dvb/frontends/dib0070.h (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index dec03ee32e1..d73934dd4c5 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -75,6 +75,7 @@ config DVB_USB_DIB0700 select DVB_DIB3000MC select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE select DVB_TUNER_MT2266 if !DVB_FE_CUSTOMISE + select DVB_TUNER_DIB0070 help Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The USB bridge is also present in devices having the DiB7700 DVB-T-USB diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 04b66f6e659..558ab3bd688 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -13,13 +13,18 @@ #include "dib7000p.h" #include "mt2060.h" #include "mt2266.h" +#include "dib0070.h" static int force_lna_activation; module_param(force_lna_activation, int, 0644); MODULE_PARM_DESC(force_lna_activation, "force the activation of Low-Noise-Amplifyer(s) (LNA), " "if applicable for the device (default: 0=automatic/off)."); -/* Hauppauge Nova-T 500 +struct dib0700_adapter_state { + int (*set_param_save) (struct dvb_frontend *, struct dvb_frontend_parameters *); +}; + +/* Hauppauge Nova-T 500 (aka Bristol) * has a LNA on GPIO0 which is enabled by setting 1 */ static struct mt2060_config bristol_mt2060_config[2] = { { @@ -97,7 +102,7 @@ static int bristol_tuner_attach(struct dvb_usb_adapter *adap) st->mt2060_if1[adap->id]) == NULL ? -ENODEV : 0; } -/* STK7700D: Pinnacle Dual DVB-T Diversity */ +/* STK7700D: Pinnacle/Terratec/Hauppauge Dual DVB-T Diversity */ /* MT226x */ static struct dibx000_agc_config stk7700d_7000p_mt2266_agc_config[2] = { @@ -539,31 +544,243 @@ static int stk7700p_tuner_attach(struct dvb_usb_adapter *adap) st->mt2060_if1[0]) == NULL ? -ENODEV : 0; } +/* DIB7070 generic */ +static struct dibx000_agc_config dib7070_agc_config = { + BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND, + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, + * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */ + (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), // setup + + 600, // inv_gain + 10, // time_stabiliz + + 0, // alpha_level + 118, // thlock + + 0, // wbd_inv + 3530, // wbd_ref + 1, // wbd_sel + 5, // wbd_alpha + + 65535, // agc1_max + 0, // agc1_min + + 65535, // agc2_max + 0, // agc2_min + + 0, // agc1_pt1 + 40, // agc1_pt2 + 183, // agc1_pt3 + 206, // agc1_slope1 + 255, // agc1_slope2 + 72, // agc2_pt1 + 152, // agc2_pt2 + 88, // agc2_slope1 + 90, // agc2_slope2 + + 17, // alpha_mant + 27, // alpha_exp + 23, // beta_mant + 51, // beta_exp + + 0, // perform_agc_softsplit +}; + +static int dib7070_tuner_reset(struct dvb_frontend *fe, int onoff) +{ + return dib7000p_set_gpio(fe, 8, 0, !onoff); +} + +static int dib7070_tuner_sleep(struct dvb_frontend *fe, int onoff) +{ + return dib7000p_set_gpio(fe, 9, 0, onoff); +} + +static struct dib0070_config dib7070p_dib0070_config[2] = { + { + .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, + .reset = dib7070_tuner_reset, + .sleep = dib7070_tuner_sleep, + .clock_khz = 12000, + .clock_pad_drive = 4 + }, { + .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, + .reset = dib7070_tuner_reset, + .sleep = dib7070_tuner_sleep, + .clock_khz = 12000, + + } +}; + +static int dib7070_set_param_override(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) +{ + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dib0700_adapter_state *state = adap->priv; + + u16 offset; + u8 band = BAND_OF_FREQUENCY(fep->frequency/1000); + switch (band) { + case BAND_VHF: offset = 950; break; + case BAND_UHF: + default: offset = 550; break; + } + deb_info("WBD for DiB7000P: %d\n", offset + dib0070_wbd_offset(fe)); + dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe)); + return state->set_param_save(fe, fep); +} + +static int dib7070p_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *st = adap->priv; + struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); + + if (adap->id == 0) { + if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, &dib7070p_dib0070_config[0]) == NULL) + return -ENODEV; + } else { + if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, &dib7070p_dib0070_config[1]) == NULL) + return -ENODEV; + } + + st->set_param_save = adap->fe->ops.tuner_ops.set_params; + adap->fe->ops.tuner_ops.set_params = dib7070_set_param_override; + return 0; +} + +static struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = { + 60000, 15000, // internal, sampling + 1, 20, 3, 1, 0, // pll_cfg: prediv, ratio, range, reset, bypass + 0, 0, 1, 1, 2, // misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc, modulo + (3 << 14) | (1 << 12) | (524 << 0), // sad_cfg: refsel, sel, freq_15k + (0 << 25) | 0, // ifreq = 0.000000 MHz + 20452225, // timf + 12000000, // xtal_hz +}; + +static struct dib7000p_config dib7070p_dib7000p_config = { + .output_mpeg2_in_188_bytes = 1, + + .agc_config_count = 1, + .agc = &dib7070_agc_config, + .bw = &dib7070_bw_config_12_mhz, + + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, + + .hostbus_diversity = 1, +}; + +/* STK7070P */ +static int stk7070p_frontend_attach(struct dvb_usb_adapter *adap) +{ + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + + dib0700_ctrl_clock(adap->dev, 72, 1); + + msleep(10); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + + dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, &dib7070p_dib7000p_config); + + adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &dib7070p_dib7000p_config); + return adap->fe == NULL ? -ENODEV : 0; +} + +/* STK7070PD */ +static struct dib7000p_config stk7070pd_dib7000p_config[2] = { + { + .output_mpeg2_in_188_bytes = 1, + + .agc_config_count = 1, + .agc = &dib7070_agc_config, + .bw = &dib7070_bw_config_12_mhz, + + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, + + .hostbus_diversity = 1, + }, { + .output_mpeg2_in_188_bytes = 1, + + .agc_config_count = 1, + .agc = &dib7070_agc_config, + .bw = &dib7070_bw_config_12_mhz, + + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, + + .hostbus_diversity = 1, + } +}; + +static int stk7070pd_frontend_attach0(struct dvb_usb_adapter *adap) +{ + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + + dib0700_ctrl_clock(adap->dev, 72, 1); + + msleep(10); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + + dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 2, 18, stk7070pd_dib7000p_config); + + adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &stk7070pd_dib7000p_config[0]); + return adap->fe == NULL ? -ENODEV : 0; +} + +static int stk7070pd_frontend_attach1(struct dvb_usb_adapter *adap) +{ + adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x82, &stk7070pd_dib7000p_config[1]); + return adap->fe == NULL ? -ENODEV : 0; +} + +/* DVB-USB and USB stuff follows */ struct usb_device_id dib0700_usb_id_table[] = { - { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P) }, +/* 0 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P) }, { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P_PC) }, { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500) }, { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_2) }, { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK) }, - { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR) }, +/* 5 */ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR) }, { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_VIDEOMATE_U500) }, { USB_DEVICE(USB_VID_UNIWILL, USB_PID_UNIWILL_STK7700P) }, { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_STK7700P) }, { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_2) }, - { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_2) }, +/* 10 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_2) }, { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV2000E) }, { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY) }, { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK) }, { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700D) }, - { } /* Terminating entry */ +/* 15 */{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7070P) }, + { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV_DVB_T_FLASH) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7070PD) }, + { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T) }, + { 0 } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); #define DIB0700_DEFAULT_DEVICE_PROPERTIES \ .caps = DVB_USB_IS_AN_I2C_ADAPTER, \ .usb_ctrl = DEVICE_SPECIFIC, \ - .firmware = "dvb-usb-dib0700-01.fw", \ + .firmware = "dvb-usb-dib0700-03-pre1.fw", \ .download_firmware = dib0700_download_firmware, \ .no_reconnect = 1, \ .size_of_priv = sizeof(struct dib0700_state), \ @@ -675,11 +892,11 @@ struct dvb_usb_device_properties dib0700_devices[] = { { &dib0700_usb_id_table[12], NULL }, { NULL }, }, - { "Haupauge Nova-TD Stick", + { "Haupauge Nova-TD Stick/Elgato Eye-TV Diversity", { &dib0700_usb_id_table[13], NULL }, { NULL }, }, - { "DiBcom STK7700D", + { "DiBcom STK7700D reference design", { &dib0700_usb_id_table[14], NULL }, { NULL }, }, @@ -688,7 +905,65 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_key_map = stk7700d_rc_keys, .rc_key_map_size = KEY_MAP_SIZE, .rc_query = stk7700d_rc_query - } + + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 1, + .adapter = { + { + .frontend_attach = stk7070p_frontend_attach, + .tuner_attach = dib7070p_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + + .size_of_priv = sizeof(struct dib0700_adapter_state), + }, + }, + + .num_device_descs = 2, + .devices = { + { "DiBcom STK7070P reference design", + { &dib0700_usb_id_table[15], NULL }, + { NULL }, + }, + { "Pinnacle PCTV DVB-T Flash Stick", + { &dib0700_usb_id_table[16], NULL }, + { NULL }, + }, + } + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 2, + .adapter = { + { + .frontend_attach = stk7070pd_frontend_attach0, + .tuner_attach = dib7070p_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + + .size_of_priv = sizeof(struct dib0700_adapter_state), + }, { + .frontend_attach = stk7070pd_frontend_attach1, + .tuner_attach = dib7070p_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x03), + + .size_of_priv = sizeof(struct dib0700_adapter_state), + } + }, + + .num_device_descs = 2, + .devices = { + { "DiBcom STK7070PD reference design", + { &dib0700_usb_id_table[17], NULL }, + { NULL }, + }, + { "Pinnacle PCTV Dual DVB-T Diversity Stick", + { &dib0700_usb_id_table[18], NULL }, + { NULL }, + }, + } + }, }; int dib0700_device_count = ARRAY_SIZE(dib0700_devices); diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 5657ad8beaa..dae605bbd0f 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -68,6 +68,8 @@ #define USB_PID_DIBCOM_STK7700P 0x1e14 #define USB_PID_DIBCOM_STK7700P_PC 0x1e78 #define USB_PID_DIBCOM_STK7700D 0x1ef0 +#define USB_PID_DIBCOM_STK7070P 0x1ebc +#define USB_PID_DIBCOM_STK7070PD 0x1ebe #define USB_PID_DIBCOM_ANCHOR_2135_COLD 0x2131 #define USB_PID_DPOSH_M9206_COLD 0x9206 #define USB_PID_DPOSH_M9206_WARM 0xa090 @@ -122,6 +124,11 @@ #define USB_PID_AVERMEDIA_VOLAR_2 0xb808 #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a #define USB_PID_PINNACLE_PCTV2000E 0x022c +#define USB_PID_PINNACLE_PCTV_DVB_T_FLASH 0x0228 +#define USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T 0x0229 +#define USB_PID_PCTV_200E 0x020e +#define USB_PID_PCTV_400E 0x020f +#define USB_PID_PCTV_450E 0x0222 #define USB_PID_NEBULA_DIGITV 0x0201 #define USB_PID_DVICO_BLUEBIRD_LGDT 0xd820 #define USB_PID_DVICO_BLUEBIRD_LG064F_COLD 0xd500 @@ -141,9 +148,6 @@ #define USB_PID_MSI_MEGASKY580_55801 0x5581 #define USB_PID_KYE_DVB_T_COLD 0x701e #define USB_PID_KYE_DVB_T_WARM 0x701f -#define USB_PID_PCTV_200E 0x020e -#define USB_PID_PCTV_400E 0x020f -#define USB_PID_PCTV_450E 0x0222 #define USB_PID_LITEON_DVB_T_COLD 0xf000 #define USB_PID_LITEON_DVB_T_WARM 0xf001 #define USB_PID_DIGIVOX_MINI_SL_COLD 0xe360 diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index faf9fe3c9cc..53e77553964 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -344,6 +344,15 @@ config DVB_TUNER_MT2131 help A driver for the silicon baseband tuner MT2131 from Microtune. +config DVB_TUNER_DIB0070 + tristate "DiBcom DiB0070 silicon base-band tuner" + depends on I2C + default m if DVB_FE_CUSTOMISE + help + A driver for the silicon baseband tuner DiB0070 from DiBcom. + This device is only used inside a SiP called togther with a + demodulator for now. + comment "Miscellaneous devices" depends on DVB_CORE diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index c46b9d8e931..4b8ad1f132a 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -41,6 +41,7 @@ obj-$(CONFIG_DVB_TDA826X) += tda826x.o obj-$(CONFIG_DVB_TDA827X) += tda827x.o obj-$(CONFIG_DVB_TUNER_MT2060) += mt2060.o obj-$(CONFIG_DVB_TUNER_MT2266) += mt2266.o +obj-$(CONFIG_DVB_TUNER_DIB0070) += dib0070.o obj-$(CONFIG_DVB_TUNER_QT1010) += qt1010.o obj-$(CONFIG_DVB_TUA6100) += tua6100.o obj-$(CONFIG_DVB_TUNER_MT2131) += mt2131.o diff --git a/drivers/media/dvb/frontends/dib0070.c b/drivers/media/dvb/frontends/dib0070.c new file mode 100644 index 00000000000..481eaa68415 --- /dev/null +++ b/drivers/media/dvb/frontends/dib0070.c @@ -0,0 +1,580 @@ +/* + * Linux-DVB Driver for DiBcom's DiB0070 base-band RF Tuner. + * + * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + */ +#include +#include + +#include "dvb_frontend.h" + +#include "dib0070.h" +#include "dibx000_common.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); + +#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB0070: "); printk(args); printk("\n"); } } while (0) + +#define DIB0070_P1D 0x00 +#define DIB0070_P1F 0x01 +#define DIB0070_P1G 0x03 +#define DIB0070S_P1A 0x02 + +struct dib0070_state { + struct i2c_adapter *i2c; + struct dvb_frontend *fe; + const struct dib0070_config *cfg; + u16 wbd_ff_offset; + u8 revision; +}; + +static uint16_t dib0070_read_reg(struct dib0070_state *state, u8 reg) +{ + u8 b[2]; + struct i2c_msg msg[2] = { + { .addr = state->cfg->i2c_address, .flags = 0, .buf = ®, .len = 1 }, + { .addr = state->cfg->i2c_address, .flags = I2C_M_RD, .buf = b, .len = 2 }, + }; + if (i2c_transfer(state->i2c, msg, 2) != 2) { + printk(KERN_WARNING "DiB0070 I2C read failed\n"); + return 0; + } + return (b[0] << 8) | b[1]; +} + +static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val) +{ + u8 b[3] = { reg, val >> 8, val & 0xff }; + struct i2c_msg msg = { .addr = state->cfg->i2c_address, .flags = 0, .buf = b, .len = 3 }; + if (i2c_transfer(state->i2c, &msg, 1) != 1) { + printk(KERN_WARNING "DiB0070 I2C write failed\n"); + return -EREMOTEIO; + } + return 0; +} + +#define HARD_RESET(state) do { if (state->cfg->reset) { state->cfg->reset(state->fe,1); msleep(10); state->cfg->reset(state->fe,0); msleep(10); } } while (0) + +static int dib0070_set_bandwidth(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch) +{ + struct dib0070_state *st = fe->tuner_priv; + u16 tmp = 0; + tmp = dib0070_read_reg(st, 0x02) & 0x3fff; + + switch(BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)) { + case 8000: + tmp |= (0 << 14); + break; + case 7000: + tmp |= (1 << 14); + break; + case 6000: + tmp |= (2 << 14); + break; + case 5000: + default: + tmp |= (3 << 14); + break; + } + dib0070_write_reg(st, 0x02, tmp); + return 0; +} + +static void dib0070_captrim(struct dib0070_state *st, u16 LO4) +{ + int8_t captrim, fcaptrim, step_sign, step; + u16 adc, adc_diff = 3000; + + + + dib0070_write_reg(st, 0x0f, 0xed10); + dib0070_write_reg(st, 0x17, 0x0034); + + dib0070_write_reg(st, 0x18, 0x0032); + msleep(2); + + step = captrim = fcaptrim = 64; + + do { + step /= 2; + dib0070_write_reg(st, 0x14, LO4 | captrim); + msleep(1); + adc = dib0070_read_reg(st, 0x19); + + dprintk( "CAPTRIM=%hd; ADC = %hd (ADC) & %dmV", captrim, adc, (u32) adc*(u32)1800/(u32)1024); + + if (adc >= 400) { + adc -= 400; + step_sign = -1; + } else { + adc = 400 - adc; + step_sign = 1; + } + + if (adc < adc_diff) { + dprintk( "CAPTRIM=%hd is closer to target (%hd/%hd)", captrim, adc, adc_diff); + adc_diff = adc; + fcaptrim = captrim; + + + + } + captrim += (step_sign * step); + } while (step >= 1); + + dib0070_write_reg(st, 0x14, LO4 | fcaptrim); + dib0070_write_reg(st, 0x18, 0x07ff); +} + +#define LPF 100 // define for the loop filter 100kHz by default 16-07-06 +#define LO4_SET_VCO_HFDIV(l, v, h) l |= ((v) << 11) | ((h) << 7) +#define LO4_SET_SD(l, s) l |= ((s) << 14) | ((s) << 12) +#define LO4_SET_CTRIM(l, c) l |= (c) << 10 +static int dib0070_tune_digital(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch) +{ + struct dib0070_state *st = fe->tuner_priv; + u32 freq = ch->frequency/1000 + (BAND_OF_FREQUENCY(ch->frequency/1000) == BAND_VHF ? st->cfg->freq_offset_khz_vhf : st->cfg->freq_offset_khz_uhf); + + u8 band = BAND_OF_FREQUENCY(freq), c; + + /*******************VCO***********************************/ + u16 lo4 = 0; + + u8 REFDIV, PRESC = 2; + u32 FBDiv, Rest, FREF, VCOF_kHz; + u16 Num, Den; + /*******************FrontEnd******************************/ + u16 value = 0; + + dprintk( "Tuning for Band: %hd (%d kHz)", band, freq); + + + dib0070_write_reg(st, 0x17, 0x30); + + dib0070_set_bandwidth(fe, ch); /* c is used as HF */ + switch (st->revision) { + case DIB0070S_P1A: + switch (band) { + case BAND_LBAND: + LO4_SET_VCO_HFDIV(lo4, 1, 1); + c = 2; + break; + case BAND_SBAND: + LO4_SET_VCO_HFDIV(lo4, 0, 0); + LO4_SET_CTRIM(lo4, 1);; + c = 1; + break; + case BAND_UHF: + default: + if (freq < 570000) { + LO4_SET_VCO_HFDIV(lo4, 1, 3); + PRESC = 6; c = 6; + } else if (freq < 680000) { + LO4_SET_VCO_HFDIV(lo4, 0, 2); + c = 4; + } else { + LO4_SET_VCO_HFDIV(lo4, 1, 2); + c = 4; + } + break; + } break; + + case DIB0070_P1G: + case DIB0070_P1F: + default: + switch (band) { + case BAND_FM: + LO4_SET_VCO_HFDIV(lo4, 0, 7); + c = 24; + break; + case BAND_LBAND: + LO4_SET_VCO_HFDIV(lo4, 1, 0); + c = 2; + break; + case BAND_VHF: + if (freq < 180000) { + LO4_SET_VCO_HFDIV(lo4, 0, 3); + c = 16; + } else if (freq < 190000) { + LO4_SET_VCO_HFDIV(lo4, 1, 3); + c = 16; + } else { + LO4_SET_VCO_HFDIV(lo4, 0, 6); + c = 12; + } + break; + + case BAND_UHF: + default: + if (freq < 570000) { + LO4_SET_VCO_HFDIV(lo4, 1, 5); + c = 6; + } else if (freq < 700000) { + LO4_SET_VCO_HFDIV(lo4, 0, 1); + c = 4; + } else { + LO4_SET_VCO_HFDIV(lo4, 1, 1); + c = 4; + } + break; + } + break; + } + + dprintk( "HFDIV code: %hd", (lo4 >> 7) & 0xf); + dprintk( "VCO = %hd", (lo4 >> 11) & 0x3); + + + VCOF_kHz = (c * freq) * 2; + dprintk( "VCOF in kHz: %d ((%hd*%d) << 1))",VCOF_kHz, c, freq); + + switch (band) { + case BAND_VHF: + REFDIV = (u8) ((st->cfg->clock_khz + 9999) / 10000); + break; + case BAND_FM: + REFDIV = (u8) ((st->cfg->clock_khz) / 1000); + break; + default: + REFDIV = (u8) ( st->cfg->clock_khz / 10000); + break; + } + FREF = st->cfg->clock_khz / REFDIV; + + dprintk( "REFDIV: %hd, FREF: %d", REFDIV, FREF); + + + + switch (st->revision) { + case DIB0070S_P1A: + FBDiv = (VCOF_kHz / PRESC / FREF); + Rest = (VCOF_kHz / PRESC) - FBDiv * FREF; + break; + + case DIB0070_P1G: + case DIB0070_P1F: + default: + FBDiv = (freq / (FREF / 2)); + Rest = 2 * freq - FBDiv * FREF; + break; + } + + + if (Rest < LPF) Rest = 0; + else if (Rest < 2 * LPF) Rest = 2 * LPF; + else if (Rest > (FREF - LPF)) { Rest = 0 ; FBDiv += 1; } + else if (Rest > (FREF - 2 * LPF)) Rest = FREF - 2 * LPF; + Rest = (Rest * 6528) / (FREF / 10); + dprintk( "FBDIV: %d, Rest: %d", FBDiv, Rest); + + Num = 0; + Den = 1; + + if (Rest > 0) { + LO4_SET_SD(lo4, 1); + Den = 255; + Num = (u16)Rest; + } + dprintk( "Num: %hd, Den: %hd, SD: %hd",Num, Den, (lo4 >> 12) & 0x1); + + + + dib0070_write_reg(st, 0x11, (u16)FBDiv); + + + dib0070_write_reg(st, 0x12, (Den << 8) | REFDIV); + + + dib0070_write_reg(st, 0x13, Num); + + + value = 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001; + + switch (band) { + case BAND_UHF: value |= 0x4000 | 0x0800; break; + case BAND_LBAND: value |= 0x2000 | 0x0400; break; + default: value |= 0x8000 | 0x1000; break; + } + dib0070_write_reg(st, 0x20, value); + + dib0070_captrim(st, lo4); + if (st->revision == DIB0070S_P1A) { + if (band == BAND_SBAND) + dib0070_write_reg(st, 0x15, 0x16e2); + else + dib0070_write_reg(st, 0x15, 0x56e5); + } + + + + switch (band) { + case BAND_UHF: value = 0x7c82; break; + case BAND_LBAND: value = 0x7c84; break; + default: value = 0x7c81; break; + } + dib0070_write_reg(st, 0x0f, value); + dib0070_write_reg(st, 0x06, 0x3fff); + + /* Front End */ + /* c == TUNE, value = SWITCH */ + c = 0; + value = 0; + switch (band) { + case BAND_FM: + c = 0; value = 1; + break; + + case BAND_VHF: + if (freq <= 180000) c = 0; + else if (freq <= 188200) c = 1; + else if (freq <= 196400) c = 2; + else c = 3; + value = 1; + break; + + case BAND_LBAND: + if (freq <= 1500000) c = 0; + else if (freq <= 1600000) c = 1; + else c = 3; + break; + + case BAND_SBAND: + c = 7; + dib0070_write_reg(st, 0x1d,0xFFFF); + break; + + case BAND_UHF: + default: + if (st->cfg->flip_chip) { + if (freq <= 550000) c = 0; + else if (freq <= 590000) c = 1; + else if (freq <= 666000) c = 3; + else c = 5; + } else { + if (freq <= 550000) c = 2; + else if (freq <= 650000) c = 3; + else if (freq <= 750000) c = 5; + else if (freq <= 850000) c = 6; + else c = 7; + } + value = 2; + break; + } + + /* default: LNA_MATCH=7, BIAS=3 */ + dib0070_write_reg(st, 0x07, (value << 11) | (7 << 8) | (c << 3) | (3 << 0)); + dib0070_write_reg(st, 0x08, (c << 10) | (3 << 7) | (127)); + dib0070_write_reg(st, 0x0d, 0x0d80); + + + dib0070_write_reg(st, 0x18, 0x07ff); + dib0070_write_reg(st, 0x17, 0x0033); + + return 0; +} + +static int dib0070_wakeup(struct dvb_frontend *fe) +{ + struct dib0070_state *st = fe->tuner_priv; + if (st->cfg->sleep) + st->cfg->sleep(fe, 0); + return 0; +} + +static int dib0070_sleep(struct dvb_frontend *fe) +{ + struct dib0070_state *st = fe->tuner_priv; + if (st->cfg->sleep) + st->cfg->sleep(fe, 1); + return 0; +} + +static u16 dib0070_p1f_defaults[] = + +{ + 7, 0x02, + 0x0008, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0002, + 0x0100, + + 3, 0x0d, + 0x0d80, + 0x0001, + 0x0000, + + 4, 0x11, + 0x0000, + 0x0103, + 0x0000, + 0x0000, + + 3, 0x16, + 0x0004 | 0x0040, + 0x0030, + 0x07ff, + + 6, 0x1b, + 0x4112, + 0xff00, + 0xc07f, + 0x0000, + 0x0180, + 0x4000 | 0x0800 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001, + + 0, +}; + +static void dib0070_wbd_calibration(struct dib0070_state *state) +{ + u16 wbd_offs; + dib0070_write_reg(state, 0x0f, 0x6d81); + dib0070_write_reg(state, 0x20, 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001); + msleep(9); + wbd_offs = dib0070_read_reg(state, 0x19); + dib0070_write_reg(state, 0x20, 0); + state->wbd_ff_offset = ((wbd_offs * 8 * 18 / 33 + 1) / 2); + dprintk( "WBDStart = %d (Vargen) - FF = %hd", (u32) wbd_offs * 1800/1024, state->wbd_ff_offset); +} + +u16 dib0070_wbd_offset(struct dvb_frontend *fe) +{ + struct dib0070_state *st = fe->tuner_priv; + return st->wbd_ff_offset; +} + +EXPORT_SYMBOL(dib0070_wbd_offset); +static int dib0070_set_ctrl_lo5(struct dvb_frontend *fe, u8 vco_bias_trim, u8 hf_div_trim, u8 cp_current, u8 third_order_filt) +{ + struct dib0070_state *state = fe->tuner_priv; + u16 lo5 = (third_order_filt << 14) | (0 << 13) | (1 << 12) | (3 << 9) | (cp_current << 6) | (hf_div_trim << 3) | (vco_bias_trim << 0); + dprintk( "CTRL_LO5: 0x%x", lo5); + return dib0070_write_reg(state, 0x15, lo5); +} + +#define pgm_read_word(w) (*w) +static int dib0070_reset(struct dib0070_state *state) +{ + u16 l, r, *n; + + HARD_RESET(state); + + +#ifndef FORCE_SBAND_TUNER + if ((dib0070_read_reg(state, 0x22) >> 9) & 0x1) + state->revision = (dib0070_read_reg(state, 0x1f) >> 8) & 0xff; + else +#endif + state->revision = DIB0070S_P1A; + + /* P1F or not */ + dprintk( "Revision: %x", state->revision); + + if (state->revision == DIB0070_P1D) { + dprintk( "Error: this driver is not to be used meant for P1D or earlier"); + return -EINVAL; + } + + n = (u16 *) dib0070_p1f_defaults; + l = pgm_read_word(n++); + while (l) { + r = pgm_read_word(n++); + do { + dib0070_write_reg(state, (u8)r, pgm_read_word(n++)); + r++; + } while (--l); + l = pgm_read_word(n++); + } + + if (state->cfg->force_crystal_mode != 0) + r = state->cfg->force_crystal_mode; + else if (state->cfg->clock_khz >= 24000) + r = 1; + else + r = 2; + + r |= state->cfg->osc_buffer_state << 3; + + dib0070_write_reg(state, 0x10, r); + dib0070_write_reg(state, 0x1f, (1 << 8) | ((state->cfg->clock_pad_drive & 0xf) << 4)); + + if (state->cfg->invert_iq) { + r = dib0070_read_reg(state, 0x02) & 0xffdf; + dib0070_write_reg(state, 0x02, r | (1 << 5)); + } + + + if (state->revision == DIB0070S_P1A) + dib0070_set_ctrl_lo5(state->fe, 4, 7, 3, 1); + else + dib0070_set_ctrl_lo5(state->fe, 4, 4, 2, 0); + + dib0070_write_reg(state, 0x01, (54 << 9) | 0xc8); + return 0; +} + + +static int dib0070_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +static struct dvb_tuner_ops dib0070_ops = { + .info = { + .name = "DiBcom DiB0070", + .frequency_min = 45000000, + .frequency_max = 860000000, + .frequency_step = 1000, + }, + .release = dib0070_release, + + .init = dib0070_wakeup, + .sleep = dib0070_sleep, + .set_params = dib0070_tune_digital, +// .get_frequency = dib0070_get_frequency, +// .get_bandwidth = dib0070_get_bandwidth +}; + +struct dvb_frontend * dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg) +{ + struct dib0070_state *state = kzalloc(sizeof(struct dib0070_state), GFP_KERNEL); + if (state == NULL) + return NULL; + + state->cfg = cfg; + state->i2c = i2c; + state->fe = fe; + fe->tuner_priv = state; + + if (dib0070_reset(state) != 0) + goto free_mem; + + dib0070_wbd_calibration(state); + + printk(KERN_INFO "DiB0070: successfully identified\n"); + memcpy(&fe->ops.tuner_ops, &dib0070_ops, sizeof(struct dvb_tuner_ops)); + + fe->tuner_priv = state; + return fe; + +free_mem: + kfree(state); + fe->tuner_priv = NULL; + return NULL; +} +EXPORT_SYMBOL(dib0070_attach); + +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_DESCRIPTION("Driver for the DiBcom 0070 base-band RF Tuner"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/dib0070.h b/drivers/media/dvb/frontends/dib0070.h new file mode 100644 index 00000000000..786e37d3388 --- /dev/null +++ b/drivers/media/dvb/frontends/dib0070.h @@ -0,0 +1,44 @@ +/* + * Linux-DVB Driver for DiBcom's DiB0070 base-band RF Tuner. + * + * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + */ +#ifndef DIB0070_H +#define DIB0070_H + +struct dvb_frontend; +struct i2c_adapter; + +#define DEFAULT_DIB0070_I2C_ADDRESS 0x60 + +struct dib0070_config { + u8 i2c_address; + + /* tuner pins controlled externally */ + int (*reset) (struct dvb_frontend *, int); + int (*sleep) (struct dvb_frontend *, int); + + /* offset in kHz */ + int freq_offset_khz_uhf; + int freq_offset_khz_vhf; + + u8 osc_buffer_state; /* 0= normal, 1= tri-state */ + u32 clock_khz; + u8 clock_pad_drive; /* (Drive + 1) * 2mA */ + + u8 invert_iq; /* invert Q - in case I or Q is inverted on the board */ + + u8 force_crystal_mode; /* if == 0 -> decision is made in the driver default: <24 -> 2, >=24 -> 1 */ + + u8 flip_chip; +}; + +extern struct dvb_frontend * dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg); +extern void dib0070_ctrl_agc_filter(struct dvb_frontend *, uint8_t open); +extern u16 dib0070_wbd_offset(struct dvb_frontend *); + +#endif diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c index cbbe2c2f05d..38d2322cbaf 100644 --- a/drivers/media/dvb/frontends/dib3000mc.c +++ b/drivers/media/dvb/frontends/dib3000mc.c @@ -593,7 +593,7 @@ static int dib3000mc_tune(struct dvb_frontend *demod, struct dvb_frontend_parame // activates isi dib3000mc_write_word(state, 29, 0x1073); - dib3000mc_set_adp_cfg(state, (uint8_t)ch->u.ofdm.constellation); + dib3000mc_set_adp_cfg(state, (u8)ch->u.ofdm.constellation); if (ch->u.ofdm.transmission_mode == TRANSMISSION_MODE_8K) { dib3000mc_write_word(state, 26, 38528); dib3000mc_write_word(state, 33, 8); diff --git a/drivers/media/dvb/frontends/dib7000m.c b/drivers/media/dvb/frontends/dib7000m.c index 608156a691d..0ad9f3eb20a 100644 --- a/drivers/media/dvb/frontends/dib7000m.c +++ b/drivers/media/dvb/frontends/dib7000m.c @@ -42,9 +42,9 @@ struct dib7000m_state { u32 timf_default; u32 internal_clk; - uint8_t div_force_off : 1; - uint8_t div_state : 1; - uint16_t div_sync_wait; + u8 div_force_off : 1; + u8 div_state : 1; + u16 div_sync_wait; u16 revision; @@ -302,7 +302,7 @@ static int dib7000m_set_diversity_in(struct dvb_frontend *demod, int onoff) dprintk( "diversity combination deactivated - forced by COFDM parameters"); onoff = 0; } - state->div_state = (uint8_t)onoff; + state->div_state = (u8)onoff; if (onoff) { dib7000m_write_word(state, 263 + state->reg_offs, 6); @@ -620,7 +620,7 @@ static int dib7000m_update_lna(struct dib7000m_state *state) u16 dyn_gain; if (state->cfg.update_lna) { - // read dyn_gain here (because it is demod-dependent and not tuner) + // read dyn_gain here (because it is demod-dependent and not fe) dyn_gain = dib7000m_read_word(state, 390); if (state->cfg.update_lna(&state->demod,dyn_gain)) { // LNA has changed @@ -754,7 +754,7 @@ static int dib7000m_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_ break; case 3: /* split search ended */ - agc_split = (uint8_t)dib7000m_read_word(state, 392); /* store the split value for the next time */ + agc_split = (u8)dib7000m_read_word(state, 392); /* store the split value for the next time */ dib7000m_write_word(state, 75, dib7000m_read_word(state, 390)); /* set AGC gain start value */ dib7000m_write_word(state, 72, cfg_72 & ~(1 << 4)); /* std AGC loop */ diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c index 156c53ab56d..1175ab9a453 100644 --- a/drivers/media/dvb/frontends/dib7000p.c +++ b/drivers/media/dvb/frontends/dib7000p.c @@ -36,9 +36,9 @@ struct dib7000p_state { struct dibx000_agc_config *current_agc; u32 timf; - uint8_t div_force_off : 1; - uint8_t div_state : 1; - uint16_t div_sync_wait; + u8 div_force_off : 1; + u8 div_state : 1; + u16 div_sync_wait; u8 agc_state; @@ -156,7 +156,7 @@ static int dib7000p_set_diversity_in(struct dvb_frontend *demod, int onoff) dprintk( "diversity combination deactivated - forced by COFDM parameters"); onoff = 0; } - state->div_state = (uint8_t)onoff; + state->div_state = (u8)onoff; if (onoff) { dib7000p_write_word(state, 204, 6); @@ -294,6 +294,16 @@ static int dib7000p_sad_calib(struct dib7000p_state *state) return 0; } +int dib7000p_set_wbd_ref(struct dvb_frontend *demod, u16 value) +{ + struct dib7000p_state *state = demod->demodulator_priv; + if (value > 4095) + value = 4095; + state->wbd_ref = value; + return dib7000p_write_word(state, 105, (dib7000p_read_word(state, 105) & 0xf000) | value); +} + +EXPORT_SYMBOL(dib7000p_set_wbd_ref); static void dib7000p_reset_pll(struct dib7000p_state *state) { struct dibx000_bandwidth_config *bw = &state->cfg.bw[0]; @@ -335,6 +345,28 @@ static int dib7000p_reset_gpio(struct dib7000p_state *st) return 0; } +static int dib7000p_cfg_gpio(struct dib7000p_state *st, u8 num, u8 dir, u8 val) +{ + st->gpio_dir = dib7000p_read_word(st, 1029); + st->gpio_dir &= ~(1 << num); /* reset the direction bit */ + st->gpio_dir |= (dir & 0x1) << num; /* set the new direction */ + dib7000p_write_word(st, 1029, st->gpio_dir); + + st->gpio_val = dib7000p_read_word(st, 1030); + st->gpio_val &= ~(1 << num); /* reset the direction bit */ + st->gpio_val |= (val & 0x01) << num; /* set the new value */ + dib7000p_write_word(st, 1030, st->gpio_val); + + return 0; +} + +int dib7000p_set_gpio(struct dvb_frontend *demod, u8 num, u8 dir, u8 val) +{ + struct dib7000p_state *state = demod->demodulator_priv; + return dib7000p_cfg_gpio(state, num, dir, val); +} + +EXPORT_SYMBOL(dib7000p_set_gpio); static u16 dib7000p_defaults[] = { @@ -501,7 +533,7 @@ static int dib7000p_update_lna(struct dib7000p_state *state) // when there is no LNA to program return immediatly if (state->cfg.update_lna) { - // read dyn_gain here (because it is demod-dependent and not tuner) + // read dyn_gain here (because it is demod-dependent and not fe) dyn_gain = dib7000p_read_word(state, 394); if (state->cfg.update_lna(&state->demod,dyn_gain)) { // LNA has changed dib7000p_restart_agc(state); @@ -617,7 +649,7 @@ static int dib7000p_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_ break; case 3: /* split search ended */ - agc_split = (uint8_t)dib7000p_read_word(state, 396); /* store the split value for the next time */ + agc_split = (u8)dib7000p_read_word(state, 396); /* store the split value for the next time */ dib7000p_write_word(state, 78, dib7000p_read_word(state, 394)); /* set AGC gain start value */ dib7000p_write_word(state, 75, state->current_agc->setup); /* std AGC loop */ diff --git a/drivers/media/dvb/frontends/dib7000p.h b/drivers/media/dvb/frontends/dib7000p.h index e7769e7cd92..eefcac8b524 100644 --- a/drivers/media/dvb/frontends/dib7000p.h +++ b/drivers/media/dvb/frontends/dib7000p.h @@ -40,12 +40,7 @@ extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u extern struct i2c_adapter * dib7000p_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int); extern int dib7000pc_detection(struct i2c_adapter *i2c_adap); - -/* TODO -extern INT dib7000p_set_gpio(struct dibDemod *demod, UCHAR num, UCHAR dir, UCHAR val); -extern INT dib7000p_enable_vbg_voltage(struct dibDemod *demod); -extern void dib7000p_set_hostbus_diversity(struct dibDemod *demod, UCHAR onoff); -extern USHORT dib7000p_get_current_agc_global(struct dibDemod *demod); -*/ +extern int dib7000p_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val); +extern int dib7000p_set_wbd_ref(struct dvb_frontend *, u16 value); #endif -- cgit v1.2.3-70-g09d2 From 82f3d5594240adcd8d6764cf31dffc473a6cc1d0 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 30 Jul 2007 13:50:28 -0300 Subject: V4L/DVB (5956): Add remote control support for the Hauppauge Nova-T 500 This patch adds remote control support for the Hauppauge Nova-T 500 using the same keys as for STK7700PD. Signed-off-by: Janne Grunau Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 558ab3bd688..994e5b8d44a 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -264,7 +264,7 @@ static int stk7700d_tuner_attach(struct dvb_usb_adapter *adap) static u8 rc_request[] = { REQUEST_POLL_RC, 0 }; -static int stk7700d_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state) { u8 key[4]; int i; @@ -274,7 +274,7 @@ static int stk7700d_rc_query(struct dvb_usb_device *d, u32 *event, int *state) *state = REMOTE_NO_KEY_PRESSED; i=dib0700_ctrl_rd(d,rc_request,2,key,4); if (i<=0) { - err("stk7700d:RC Query Failed\n"); + err("RC Query Failed\n"); return 0; } if (key[0]==0 && key[1]==0 && key[2]==0 && key[3]==0) return 0; @@ -287,14 +287,12 @@ static int stk7700d_rc_query(struct dvb_usb_device *d, u32 *event, int *state) return 0; } } - err("stk7700d:Unknown remote controller key : %2X %2X\n",(int)key[2],(int)key[3]); + err("Unknown remote controller key : %2X %2X\n",(int)key[2],(int)key[3]); } return 0; } -#define KEY_MAP_SIZE (25+48) - -static struct dvb_usb_rc_key stk7700d_rc_keys[] = { +static struct dvb_usb_rc_key dib0700_rc_keys[] = { /* Key codes for the tiny Pinnacle remote*/ { 0x07, 0x00, KEY_MUTE }, { 0x07, 0x01, KEY_MENU }, // Pinnacle logo @@ -370,7 +368,7 @@ static struct dvb_usb_rc_key stk7700d_rc_keys[] = { { 0xeb, 0x54, KEY_PREVIOUS }, { 0xeb, 0x58, KEY_RECORD }, { 0xeb, 0x5c, KEY_NEXT } - }; +}; /* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */ static struct dibx000_agc_config stk7700p_7000m_mt2060_agc_config = { @@ -864,7 +862,12 @@ struct dvb_usb_device_properties dib0700_devices[] = { { &dib0700_usb_id_table[2], &dib0700_usb_id_table[3], NULL }, { NULL }, }, - } + }, + + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_key_map = dib0700_rc_keys, + .rc_key_map_size = sizeof(dib0700_rc_keys), + .rc_query = dib0700_rc_query }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, .num_adapters = 2, @@ -901,10 +904,11 @@ struct dvb_usb_device_properties dib0700_devices[] = { { NULL }, }, }, + .rc_interval = DEFAULT_RC_INTERVAL, - .rc_key_map = stk7700d_rc_keys, - .rc_key_map_size = KEY_MAP_SIZE, - .rc_query = stk7700d_rc_query + .rc_key_map = dib0700_rc_keys, + .rc_key_map_size = sizeof(dib0700_rc_keys), + .rc_query = dib0700_rc_query }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, -- cgit v1.2.3-70-g09d2 From 7161f27f2e61b44352a9dcf3927813380d5e710b Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Mon, 30 Jul 2007 13:54:55 -0300 Subject: V4L/DVB (5957): Add remote keymap for the Hauppauge Nova-TD Stick Copied from drivers/media/dvb/dvb-usb/nova-t-usb2.c Signed-off-by: Janne Grunau Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 51 +++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 994e5b8d44a..fb1a9bf7e59 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -346,7 +346,7 @@ static struct dvb_usb_rc_key dib0700_rc_keys[] = { { 0xeb, 0x1a, KEY_BLUE }, { 0xeb, 0x1b, KEY_CHANNELUP }, { 0xeb, 0x1c, KEY_VOLUMEUP }, - { 0xeb, 0x1d, KEY_MUTE }, + { 0xeb, 0x1d, KEY_MUTE }, { 0xeb, 0x1e, KEY_VOLUMEDOWN }, { 0xeb, 0x1f, KEY_CHANNELDOWN }, { 0xeb, 0x40, KEY_PAUSE }, @@ -367,7 +367,54 @@ static struct dvb_usb_rc_key dib0700_rc_keys[] = { { 0xeb, 0x4f, KEY_FASTFORWARD }, { 0xeb, 0x54, KEY_PREVIOUS }, { 0xeb, 0x58, KEY_RECORD }, - { 0xeb, 0x5c, KEY_NEXT } + { 0xeb, 0x5c, KEY_NEXT }, + + /* Key codes for the Haupauge WinTV Nova-TD, copied from nova-t-usb2.c (Nova-T USB2) */ + { 0x1e, 0x00, KEY_0 }, + { 0x1e, 0x01, KEY_1 }, + { 0x1e, 0x02, KEY_2 }, + { 0x1e, 0x03, KEY_3 }, + { 0x1e, 0x04, KEY_4 }, + { 0x1e, 0x05, KEY_5 }, + { 0x1e, 0x06, KEY_6 }, + { 0x1e, 0x07, KEY_7 }, + { 0x1e, 0x08, KEY_8 }, + { 0x1e, 0x09, KEY_9 }, + { 0x1e, 0x0a, KEY_KPASTERISK }, + { 0x1e, 0x0b, KEY_RED }, + { 0x1e, 0x0c, KEY_RADIO }, + { 0x1e, 0x0d, KEY_MENU }, + { 0x1e, 0x0e, KEY_GRAVE }, /* # */ + { 0x1e, 0x0f, KEY_MUTE }, + { 0x1e, 0x10, KEY_VOLUMEUP }, + { 0x1e, 0x11, KEY_VOLUMEDOWN }, + { 0x1e, 0x12, KEY_CHANNEL }, + { 0x1e, 0x14, KEY_UP }, + { 0x1e, 0x15, KEY_DOWN }, + { 0x1e, 0x16, KEY_LEFT }, + { 0x1e, 0x17, KEY_RIGHT }, + { 0x1e, 0x18, KEY_VIDEO }, + { 0x1e, 0x19, KEY_AUDIO }, + { 0x1e, 0x1a, KEY_MEDIA }, + { 0x1e, 0x1b, KEY_EPG }, + { 0x1e, 0x1c, KEY_TV }, + { 0x1e, 0x1e, KEY_NEXT }, + { 0x1e, 0x1f, KEY_BACK }, + { 0x1e, 0x20, KEY_CHANNELUP }, + { 0x1e, 0x21, KEY_CHANNELDOWN }, + { 0x1e, 0x24, KEY_LAST }, /* Skip backwards */ + { 0x1e, 0x25, KEY_OK }, + { 0x1e, 0x29, KEY_BLUE}, + { 0x1e, 0x2e, KEY_GREEN }, + { 0x1e, 0x30, KEY_PAUSE }, + { 0x1e, 0x32, KEY_REWIND }, + { 0x1e, 0x34, KEY_FASTFORWARD }, + { 0x1e, 0x35, KEY_PLAY }, + { 0x1e, 0x36, KEY_STOP }, + { 0x1e, 0x37, KEY_RECORD }, + { 0x1e, 0x38, KEY_YELLOW }, + { 0x1e, 0x3b, KEY_GOTO }, + { 0x1e, 0x3d, KEY_POWER }, }; /* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */ -- cgit v1.2.3-70-g09d2 From 1f8ca4b37355cc56a4d25d5698a894ec46964f83 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Mon, 30 Jul 2007 14:24:37 -0300 Subject: V4L/DVB (5958): Add support Compro VideoMate 500 with DiB7000PC Add support Compro VideoMate 500 with DiB7000PC. Another design of Compro uses the DiB7000PC and it has new USB ids. Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 3 ++- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index fb1a9bf7e59..b0ae5b73129 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -818,6 +818,7 @@ struct usb_device_id dib0700_usb_id_table[] = { { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV_DVB_T_FLASH) }, { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7070PD) }, { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T) }, + { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_VIDEOMATE_U500_PC) }, { 0 } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); @@ -874,7 +875,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { { NULL }, }, { "Compro Videomate U500", - { &dib0700_usb_id_table[6], NULL }, + { &dib0700_usb_id_table[6], &dib0700_usb_id_table[19] }, { NULL }, }, { "Uniwill STK7700P based (Hama and others)", diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index dae605bbd0f..a16be605c63 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -59,6 +59,7 @@ #define USB_PID_COMPRO_DVBU2000_UNK_COLD 0x010c #define USB_PID_COMPRO_DVBU2000_UNK_WARM 0x010d #define USB_PID_COMPRO_VIDEOMATE_U500 0x1e78 +#define USB_PID_COMPRO_VIDEOMATE_U500_PC 0x1e80 #define USB_PID_DIBCOM_HOOK_DEFAULT 0x0064 #define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM 0x0065 #define USB_PID_DIBCOM_MOD3000_COLD 0x0bb8 -- cgit v1.2.3-70-g09d2 From 8779737b8e01b95fe6f1e33dc90ea621281c7b67 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Mon, 30 Jul 2007 17:02:17 -0300 Subject: V4L/DVB (5959): Fix for size of remote keys in DiB0700 Fix for size of remote control keys in DiB0700. Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index b0ae5b73129..a2b2830f978 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -914,7 +914,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_interval = DEFAULT_RC_INTERVAL, .rc_key_map = dib0700_rc_keys, - .rc_key_map_size = sizeof(dib0700_rc_keys), + .rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys), .rc_query = dib0700_rc_query }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -955,7 +955,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_interval = DEFAULT_RC_INTERVAL, .rc_key_map = dib0700_rc_keys, - .rc_key_map_size = sizeof(dib0700_rc_keys), + .rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys), .rc_query = dib0700_rc_query }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, -- cgit v1.2.3-70-g09d2 From 8f6956c7f9fa72c502bde47df4122bd32d0b86d5 Mon Sep 17 00:00:00 2001 From: Matt Doran Date: Tue, 31 Jul 2007 07:09:30 -0300 Subject: V4L/DVB (5960): Add module parameter to enable SFN workaround In some areas in the world the broadcasters are not using the same cellid for each transmitter in a SFN. The DiBcom has problems with that setup. The module parameter buggy_sfn_workaround makes it re-usable. Signed-off-by: Matt Doran Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/dib3000mc.c | 22 +++++++++++++++++----- drivers/media/dvb/frontends/dib7000p.c | 21 +++++++++++++++++++-- 2 files changed, 36 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c index 38d2322cbaf..f0096de2279 100644 --- a/drivers/media/dvb/frontends/dib3000mc.c +++ b/drivers/media/dvb/frontends/dib3000mc.c @@ -13,10 +13,6 @@ #include #include -//#include -//#include -//#include -//#include #include "dvb_frontend.h" @@ -26,6 +22,10 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); +static int buggy_sfn_workaround; +module_param(buggy_sfn_workaround, int, 0644); +MODULE_PARM_DESC(debug, "Enable work-around for buggy SFNs (default: 0)"); + #define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB3000MC/P:"); printk(args); printk("\n"); } } while (0) struct dib3000mc_state { @@ -42,6 +42,8 @@ struct dib3000mc_state { fe_bandwidth_t current_bandwidth; u16 dev_id; + + u8 sfn_workaround_active :1; }; static u16 dib3000mc_read_word(struct dib3000mc_state *state, u16 reg) @@ -591,7 +593,14 @@ static int dib3000mc_tune(struct dvb_frontend *demod, struct dvb_frontend_parame dib3000mc_set_channel_cfg(state, ch, 0); // activates isi - dib3000mc_write_word(state, 29, 0x1073); + if (state->sfn_workaround_active) { + dprintk("SFN workaround is active\n"); + dib3000mc_write_word(state, 29, 0x1273); + dib3000mc_write_word(state, 108, 0x4000); // P_pha3_force_pha_shift + } else { + dib3000mc_write_word(state, 29, 0x1073); + dib3000mc_write_word(state, 108, 0x0000); // P_pha3_force_pha_shift + } dib3000mc_set_adp_cfg(state, (u8)ch->u.ofdm.constellation); if (ch->u.ofdm.transmission_mode == TRANSMISSION_MODE_8K) { @@ -679,6 +688,9 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe, state->current_bandwidth = fep->u.ofdm.bandwidth; dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth)); + /* maybe the parameter has been changed */ + state->sfn_workaround_active = buggy_sfn_workaround; + if (fe->ops.tuner_ops.set_params) { fe->ops.tuner_ops.set_params(fe, fep); msleep(100); diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c index 1175ab9a453..aa7dc450332 100644 --- a/drivers/media/dvb/frontends/dib7000p.c +++ b/drivers/media/dvb/frontends/dib7000p.c @@ -18,6 +18,10 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); +static int buggy_sfn_workaround; +module_param(buggy_sfn_workaround, int, 0644); +MODULE_PARM_DESC(debug, "Enable work-around for buggy SFNs (default: 0)"); + #define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000P: "); printk(args); printk("\n"); } } while (0) struct dib7000p_state { @@ -44,6 +48,8 @@ struct dib7000p_state { u16 gpio_dir; u16 gpio_val; + + u8 sfn_workaround_active :1; }; enum dib7000p_power_mode { @@ -751,8 +757,8 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_fronte /* offset loop parameters */ dib7000p_write_word(state, 26, 0x6680); // timf(6xxx) - dib7000p_write_word(state, 29, 0x1273); // isi inh1273 on1073 dib7000p_write_word(state, 32, 0x0003); // pha_off_max(xxx3) + dib7000p_write_word(state, 29, 0x1273); // isi dib7000p_write_word(state, 33, 0x0005); // sfreq(xxx5) /* P_dvsy_sync_wait */ @@ -959,7 +965,15 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet msleep(45); /* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */ - dib7000p_write_word(state, 29, (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3)); + tmp = (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3); + if (state->sfn_workaround_active) { + dprintk( "SFN workaround is active"); + tmp |= (1 << 9); + dib7000p_write_word(state, 166, 0x4000); // P_pha3_force_pha_shift + } else { + dib7000p_write_word(state, 166, 0x0000); // P_pha3_force_pha_shift + } + dib7000p_write_word(state, 29, tmp); // never achieved a lock with that bandwidth so far - wait for osc-freq to update if (state->timf == 0) @@ -1119,6 +1133,9 @@ static int dib7000p_set_frontend(struct dvb_frontend* fe, state->current_bandwidth = fep->u.ofdm.bandwidth; dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth)); + /* maybe the parameter has been changed */ + state->sfn_workaround_active = buggy_sfn_workaround; + if (fe->ops.tuner_ops.set_params) fe->ops.tuner_ops.set_params(fe, fep); -- cgit v1.2.3-70-g09d2 From 3db78e59500a45e05cbe271c8e1ba5a2b7ce0ef8 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Tue, 31 Jul 2007 08:19:28 -0300 Subject: V4L/DVB (5961): Fix support for DiB7000M-devices Forgot to initialize the timf_default field. Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 1 + drivers/media/dvb/frontends/dib7000m.c | 2 ++ 2 files changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index a2b2830f978..a70fe75bcb2 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -515,6 +515,7 @@ static struct dibx000_bandwidth_config stk7700p_pll_config = { (3 << 14) | (1 << 12) | (524 << 0), // sad_cfg: refsel, sel, freq_15k 60258167, // ifreq 20452225, // timf + 30000000, // xtal }; static struct dib7000m_config stk7700p_dib7000m_config = { diff --git a/drivers/media/dvb/frontends/dib7000m.c b/drivers/media/dvb/frontends/dib7000m.c index 0ad9f3eb20a..fb18441a8c5 100644 --- a/drivers/media/dvb/frontends/dib7000m.c +++ b/drivers/media/dvb/frontends/dib7000m.c @@ -1344,6 +1344,8 @@ struct dvb_frontend * dib7000m_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, demod->demodulator_priv = st; memcpy(&st->demod.ops, &dib7000m_ops, sizeof(struct dvb_frontend_ops)); + st->timf_default = cfg->bw->timf; + if (dib7000m_identify(st) != 0) goto error; -- cgit v1.2.3-70-g09d2 From 034d65ed209f8525b1989dc3e6beca92fad57a7d Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Tue, 31 Jul 2007 08:48:40 -0300 Subject: V4L/DVB (5962): Fix line-break in err output line-breaks in dib0700-remote-query function fixed. Signed-off-by: Janne Grunau Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index a70fe75bcb2..0eca0fc7532 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -274,7 +274,7 @@ static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state) *state = REMOTE_NO_KEY_PRESSED; i=dib0700_ctrl_rd(d,rc_request,2,key,4); if (i<=0) { - err("RC Query Failed\n"); + err("RC Query Failed"); return 0; } if (key[0]==0 && key[1]==0 && key[2]==0 && key[3]==0) return 0; @@ -287,7 +287,7 @@ static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state) return 0; } } - err("Unknown remote controller key : %2X %2X\n",(int)key[2],(int)key[3]); + err("Unknown remote controller key : %2X %2X",(int)key[2],(int)key[3]); } return 0; } -- cgit v1.2.3-70-g09d2 From 8d99996b0942ff566c62602d83ac2c13521bbe40 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Tue, 31 Jul 2007 10:36:06 -0300 Subject: V4L/DVB (5963): Module parameter description for SFN workaround Thanks to Matt Doran I found that there the module parameter description was not OK. Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/dib3000mc.c | 2 +- drivers/media/dvb/frontends/dib7000p.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c index f0096de2279..edae0be063f 100644 --- a/drivers/media/dvb/frontends/dib3000mc.c +++ b/drivers/media/dvb/frontends/dib3000mc.c @@ -24,7 +24,7 @@ MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); static int buggy_sfn_workaround; module_param(buggy_sfn_workaround, int, 0644); -MODULE_PARM_DESC(debug, "Enable work-around for buggy SFNs (default: 0)"); +MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (default: 0)"); #define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB3000MC/P:"); printk(args); printk("\n"); } } while (0) diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c index aa7dc450332..f45bcfc51cf 100644 --- a/drivers/media/dvb/frontends/dib7000p.c +++ b/drivers/media/dvb/frontends/dib7000p.c @@ -20,7 +20,7 @@ MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); static int buggy_sfn_workaround; module_param(buggy_sfn_workaround, int, 0644); -MODULE_PARM_DESC(debug, "Enable work-around for buggy SFNs (default: 0)"); +MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (default: 0)"); #define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000P: "); printk(args); printk("\n"); } } while (0) -- cgit v1.2.3-70-g09d2 From 89f4267d6fa96cb3db053d5183558c94ad5f46e5 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Tue, 31 Jul 2007 19:45:13 -0300 Subject: V4L/DVB (5964): Fixed remote control for dib0700 with new firmware The new firmware returns the data of the REQUEST_POLL_RC request in reversed order. The default is RC5, but it can be adjusted using a module parameter. Signed-off-by: Janne Grunau Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700.h | 1 + drivers/media/dvb/dvb-usb/dib0700_core.c | 21 ++++++++++++++++++++- drivers/media/dvb/dvb-usb/dib0700_devices.c | 10 +++++----- 3 files changed, 26 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dib0700.h b/drivers/media/dvb/dvb-usb/dib0700.h index 74ae6c24087..4a903ea9589 100644 --- a/drivers/media/dvb/dvb-usb/dib0700.h +++ b/drivers/media/dvb/dvb-usb/dib0700.h @@ -30,6 +30,7 @@ extern int dvb_usb_dib0700_debug; // 1 Byte: 4MSB(1 = enable streaming, 0 = disable streaming) 4LSB(Video Mode: 0 = MPEG2 188Bytes, 1 = Analog) // 2 Byte: MPEG2 mode: 4MSB(1 = Master Mode, 0 = Slave Mode) 4LSB(Channel 1 = bit0, Channel 2 = bit1) // 2 Byte: Analog mode: 4MSB(0 = 625 lines, 1 = 525 lines) 4LSB( " " ) +#define REQUEST_SET_RC 0x11 #define REQUEST_GET_VERSION 0x15 struct dib0700_state { diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c index 8a1ea114deb..3ea294eb96b 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_core.c +++ b/drivers/media/dvb/dvb-usb/dib0700_core.c @@ -13,6 +13,10 @@ int dvb_usb_dib0700_debug; module_param_named(debug,dvb_usb_dib0700_debug, int, 0644); MODULE_PARM_DESC(debug, "set debugging level (1=info,2=fw,4=fwdata,8=data (or-able))." DVB_USB_DEBUG_STATUS); +static int dvb_usb_dib0700_ir_proto = 1; +module_param(dvb_usb_dib0700_ir_proto, int, 0644); +MODULE_PARM_DESC(dvb_usb_dib0700_ir_proto, "set ir protocol (0=NEC, 1=RC5 (default), 2=RC6)."); + /* expecting rx buffer: request data[0] data[1] ... data[2] */ static int dib0700_ctrl_wr(struct dvb_usb_device *d, u8 *tx, u8 txlen) { @@ -260,14 +264,29 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) return dib0700_ctrl_wr(adap->dev, b, 4); } +static int dib0700_rc_setup(struct dvb_usb_device *d) +{ + u8 rc_setup[3] = {REQUEST_SET_RC, dvb_usb_dib0700_ir_proto, 0}; + int i = dib0700_ctrl_wr(d, rc_setup, 3); + if (i<0) { + err("ir protocol setup failed"); + return -1; + } + return 0; +} + static int dib0700_probe(struct usb_interface *intf, const struct usb_device_id *id) { int i; + struct dvb_usb_device *dev; for (i = 0; i < dib0700_device_count; i++) - if (dvb_usb_device_init(intf, &dib0700_devices[i], THIS_MODULE, NULL) == 0) + if (dvb_usb_device_init(intf, &dib0700_devices[i], THIS_MODULE, &dev) == 0) + { + dib0700_rc_setup(dev); return 0; + } return -ENODEV; } diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 0eca0fc7532..4a3c5467d7e 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -275,19 +275,19 @@ static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state) i=dib0700_ctrl_rd(d,rc_request,2,key,4); if (i<=0) { err("RC Query Failed"); - return 0; + return -1; } if (key[0]==0 && key[1]==0 && key[2]==0 && key[3]==0) return 0; - if (key[1]!=st->rc_toggle) { + if (key[3-1]!=st->rc_toggle) { for (i=0;iprops.rc_key_map_size; i++) { - if (keymap[i].custom == key[2] && keymap[i].data == key[3]) { + if (keymap[i].custom == key[3-2] && keymap[i].data == key[3-3]) { *event = keymap[i].event; *state = REMOTE_KEY_PRESSED; - st->rc_toggle=key[1]; + st->rc_toggle=key[3-1]; return 0; } } - err("Unknown remote controller key : %2X %2X",(int)key[2],(int)key[3]); + err("Unknown remote controller key : %2X %2X",(int)key[3-2],(int)key[3-3]); } return 0; } -- cgit v1.2.3-70-g09d2 From 813ce47cee33964ff710d2c91063548773cb4cd5 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Wed, 1 Aug 2007 10:13:36 -0300 Subject: V4L/DVB (5965): Frontend_ioctl(): fix check-after-use The Coverity checker spotted that we have already oops'ed if "fe" was NULL. Since "fe" being NULL seems impossible at this point this patch removes the NULL check. Signed-off-by: Adrian Bunk Acked-by: Manu Abraham Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index afe797b75de..fd9bac5eb25 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -748,7 +748,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, dprintk ("%s\n", __FUNCTION__); - if (!fe || fepriv->exit) + if (fepriv->exit) return -ENODEV; if ((file->f_flags & O_ACCMODE) == O_RDONLY && -- cgit v1.2.3-70-g09d2 From b4b38bd63c07c8927b43c6c378eca1db10fdaf2e Mon Sep 17 00:00:00 2001 From: Ian Armstrong Date: Fri, 3 Aug 2007 09:44:13 -0300 Subject: V4L/DVB (5970): ivtv: prevent vertical overflow of yuv output When the video standard is changed, there's no guarantee the framebuffer dimensions are still legal. The yuv output code uses these dimensions to calculate the size & position for the video overlay. If the framebuffer dimensions are now illegal, the output may exceed the vertical limit of the display, causing distortion. This patch adds an additional check to ensure the output doesn't exceed the limits for the current video standard, cropping if required. Signed-off-by: Ian Armstrong Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-yuv.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c index bcea09542e5..70ddf4060d3 100644 --- a/drivers/media/video/ivtv/ivtv-yuv.c +++ b/drivers/media/video/ivtv/ivtv-yuv.c @@ -898,8 +898,21 @@ static void ivtv_yuv_init (struct ivtv *itv) itv->yuv_info.decode_height = 480; /* If no visible size set, assume full size */ - if (!itv->yuv_info.osd_vis_w) itv->yuv_info.osd_vis_w = 720 - itv->yuv_info.osd_x_offset; - if (!itv->yuv_info.osd_vis_h) itv->yuv_info.osd_vis_h = itv->yuv_info.decode_height - itv->yuv_info.osd_y_offset; + if (!itv->yuv_info.osd_vis_w) + itv->yuv_info.osd_vis_w = 720 - itv->yuv_info.osd_x_offset; + + if (!itv->yuv_info.osd_vis_h) { + itv->yuv_info.osd_vis_h = itv->yuv_info.decode_height - itv->yuv_info.osd_y_offset; + } else { + /* If output video standard has changed, requested height may + not be legal */ + if (itv->yuv_info.osd_vis_h + itv->yuv_info.osd_y_offset > itv->yuv_info.decode_height) { + IVTV_DEBUG_WARN("Clipping yuv output - fb size (%d) exceeds video standard limit (%d)\n", + itv->yuv_info.osd_vis_h + itv->yuv_info.osd_y_offset, + itv->yuv_info.decode_height); + itv->yuv_info.osd_vis_h = itv->yuv_info.decode_height - itv->yuv_info.osd_y_offset; + } + } /* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */ itv->yuv_info.blanking_ptr = kzalloc(720*16,GFP_KERNEL); -- cgit v1.2.3-70-g09d2 From 68a341a53ab5a3c5b7dad4b226124414c62c124d Mon Sep 17 00:00:00 2001 From: Ian Armstrong Date: Fri, 3 Aug 2007 09:51:58 -0300 Subject: V4L/DVB (5971): ivtv-fb: framebuffer timings no longer locked on module load Framebuffer timings are currently locked to the video format in use when the module is loaded. If the video format is then changed, the timings returned by the framebuffer will be for the original format. This patch ensures that the timings returned reflect the current video format. Signed-off-by: Ian Armstrong Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-fb.c | 43 +++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c index 00765da8a6a..d2cc0317274 100644 --- a/drivers/media/video/ivtv/ivtv-fb.c +++ b/drivers/media/video/ivtv/ivtv-fb.c @@ -164,11 +164,6 @@ MODULE_LICENSE("GPL"); #define IVTV_OSD_BPP_32 0x04 struct osd_info { - /* Timing info for modes */ - u32 pixclock; - u32 hlimit; - u32 vlimit; - /* Physical base address */ unsigned long video_pbase; /* Relative base address (relative to start of decoder memory) */ @@ -579,10 +574,25 @@ static int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix) static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) { struct osd_info *oi = itv->osd_info; - int osd_height_limit = itv->is_50hz ? 576 : 480; + int osd_height_limit; + u32 pixclock, hlimit, vlimit; IVTV_FB_DEBUG_INFO("ivtvfb_check_var\n"); + /* Set base references for mode calcs. */ + if (itv->is_50hz) { + pixclock = 84316; + hlimit = 776; + vlimit = 591; + osd_height_limit = 576; + } + else { + pixclock = 83926; + hlimit = 776; + vlimit = 495; + osd_height_limit = 480; + } + /* Check the bits per pixel */ if (osd_compat) { if (var->bits_per_pixel != 32) { @@ -723,8 +733,8 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) } /* Maintain overall 'size' for a constant refresh rate */ - var->right_margin = oi->hlimit - var->left_margin - var->xres; - var->lower_margin = oi->vlimit - var->upper_margin - var->yres; + var->right_margin = hlimit - var->left_margin - var->xres; + var->lower_margin = vlimit - var->upper_margin - var->yres; /* Fixed sync times */ var->hsync_len = 24; @@ -733,9 +743,10 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) /* Non-interlaced / interlaced mode is used to switch the OSD filter on or off. Adjust the clock timings to maintain a constant vertical refresh rate. */ - var->pixclock = oi->pixclock; if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) - var->pixclock /= 2; + var->pixclock = pixclock / 2; + else + var->pixclock = pixclock; IVTV_FB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n", var->xres, var->yres, @@ -875,18 +886,6 @@ static int ivtvfb_init_vidmode(struct ivtv *itv) struct v4l2_rect start_window; int max_height; - /* Set base references for mode calcs. */ - if (itv->is_50hz) { - oi->pixclock = 84316; - oi->hlimit = 776; - oi->vlimit = 591; - } - else { - oi->pixclock = 83926; - oi->hlimit = 776; - oi->vlimit = 495; - } - /* Color mode */ if (osd_compat) osd_depth = 32; -- cgit v1.2.3-70-g09d2 From 943e8910db31e36d945f2bf7d4c273ca5fa01f6e Mon Sep 17 00:00:00 2001 From: Ian Armstrong Date: Fri, 3 Aug 2007 09:58:29 -0300 Subject: V4L/DVB (5972): ivtv: prevent yuv register updates from being missed The yuv output code always compares the new frame position & size with those of the previous frame. If they are different, a flag is set to request the yuv output registers be updated when the new frame is displayed. If the incoming frames are delivered too fast, exhausting the buffers, the most recent frame already buffered will be discarded. Unfortunately, any update request will also be discarded. If the new frame matches the size & position of the now discarded frame, the yuv registers are not flagged for update & will remain in their old state. This patch preserves the register update flag in the event that a frame is dropped. Signed-off-by: Ian Armstrong Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-yuv.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c index 70ddf4060d3..5c94d3282c8 100644 --- a/drivers/media/video/ivtv/ivtv-yuv.c +++ b/drivers/media/video/ivtv/ivtv-yuv.c @@ -940,6 +940,7 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args) int rc = 0; int got_sig = 0; int frame, next_fill_frame, last_fill_frame; + int register_update = 0; IVTV_DEBUG_INFO("yuv_prep_frame\n"); @@ -953,6 +954,7 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args) /* Buffers are full - Overwrite the last frame */ next_fill_frame = frame; frame = (frame - 1) & 3; + register_update = itv->yuv_info.new_frame_info[frame].update; } /* Take a snapshot of the yuv coordinate information */ @@ -991,6 +993,8 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args) /* IVTV_DEBUG_YUV ("Requesting register update for frame %d\n",frame); */ } + itv->yuv_info.new_frame_info[frame].update |= register_update; + /* DMA the frame */ mutex_lock(&itv->udma.lock); -- cgit v1.2.3-70-g09d2 From bfd7beacff2b5c811badb587a74c3dfbf7f98721 Mon Sep 17 00:00:00 2001 From: Ian Armstrong Date: Fri, 3 Aug 2007 10:01:39 -0300 Subject: V4L/DVB (5973): ivtv: attach yuv field order to each frame In the current driver, the field order is global. As soon as it's changed it takes immediate effect. This is a problem when the video changes order mid stream. Although it mostly works okay, the video may judder / flicker. This patch attaches the field order to the frame, so that any buffered frames will not be displayed until the correct field. In the event that the field order is changed mid stream, the driver will ensure that the previous frame is displayed for a minimum of 3 fields. These are the two original fields the frame should have occupied, plus the one extra since the new frame still has to wait for the correct field. Signed-off-by: Ian Armstrong Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.h | 7 ++++++- drivers/media/video/ivtv/ivtv-irq.c | 22 ++++++++++++++-------- drivers/media/video/ivtv/ivtv-yuv.c | 12 +++++++++++- 3 files changed, 31 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 6e53a1f04f7..6c7c9a57a1a 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -531,6 +531,7 @@ struct yuv_frame_info u32 tru_w; u32 tru_h; u32 offset_y; + int lace_mode; }; #define IVTV_YUV_MODE_INTERLACED 0x00 @@ -603,7 +604,6 @@ struct yuv_playback_info int decode_height; int frame_interlaced; - int frame_interlaced_last; int lace_mode; int lace_threshold; @@ -614,6 +614,11 @@ struct yuv_playback_info u32 yuv_forced_update; int update_frame; + + int sync_field[4]; /* Field to sync on */ + int field_delay[4]; /* Flag to extend duration of previous frame */ + u8 fields_lapsed; /* Counter used when delaying a frame */ + struct yuv_frame_info new_frame_info[4]; struct yuv_frame_info old_frame_info; struct yuv_frame_info old_frame_info_args; diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c index fcd6e7f5f12..88c6f4ff5c6 100644 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ b/drivers/media/video/ivtv/ivtv-irq.c @@ -698,17 +698,21 @@ static void ivtv_irq_vsync(struct ivtv *itv) if (0) IVTV_DEBUG_IRQ("DEC VSYNC\n"); - if (((frame ^ itv->yuv_info.lace_sync_field) == 0 && ((itv->lastVsyncFrame & 1) ^ itv->yuv_info.lace_sync_field)) || + if (((frame ^ itv->yuv_info.sync_field[last_dma_frame]) == 0 && + ((itv->lastVsyncFrame & 1) ^ itv->yuv_info.sync_field[last_dma_frame])) || (frame != (itv->lastVsyncFrame & 1) && !itv->yuv_info.frame_interlaced)) { int next_dma_frame = last_dma_frame; - if (next_dma_frame >= 0 && next_dma_frame != atomic_read(&itv->yuv_info.next_fill_frame)) { - write_reg(yuv_offset[next_dma_frame] >> 4, 0x82c); - write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830); - write_reg(yuv_offset[next_dma_frame] >> 4, 0x834); - write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838); - next_dma_frame = (next_dma_frame + 1) & 0x3; - atomic_set(&itv->yuv_info.next_dma_frame, next_dma_frame); + if (!(itv->yuv_info.frame_interlaced && itv->yuv_info.field_delay[next_dma_frame] && itv->yuv_info.fields_lapsed < 1)) { + if (next_dma_frame >= 0 && next_dma_frame != atomic_read(&itv->yuv_info.next_fill_frame)) { + write_reg(yuv_offset[next_dma_frame] >> 4, 0x82c); + write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830); + write_reg(yuv_offset[next_dma_frame] >> 4, 0x834); + write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838); + next_dma_frame = (next_dma_frame + 1) & 0x3; + atomic_set(&itv->yuv_info.next_dma_frame, next_dma_frame); + itv->yuv_info.fields_lapsed = -1; + } } } if (frame != (itv->lastVsyncFrame & 1)) { @@ -749,6 +753,8 @@ static void ivtv_irq_vsync(struct ivtv *itv) set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags); } } + + itv->yuv_info.fields_lapsed ++; } } diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c index 5c94d3282c8..fa8c76f3d35 100644 --- a/drivers/media/video/ivtv/ivtv-yuv.c +++ b/drivers/media/video/ivtv/ivtv-yuv.c @@ -612,7 +612,6 @@ static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *wi itv->yuv_info.v_filter_2 = v_filter_2; } - itv->yuv_info.frame_interlaced_last = itv->yuv_info.frame_interlaced; } /* Modify the supplied coordinate information to fit the visible osd area */ @@ -799,6 +798,7 @@ static u32 ivtv_yuv_window_setup (struct ivtv *itv, struct yuv_frame_info *windo (itv->yuv_info.old_frame_info.src_y != window->src_y) || (itv->yuv_info.old_frame_info.pan_y != window->pan_y) || (itv->yuv_info.old_frame_info.vis_h != window->vis_h) || + (itv->yuv_info.old_frame_info.lace_mode != window->lace_mode) || (itv->yuv_info.old_frame_info.interlaced_y != window->interlaced_y) || (itv->yuv_info.old_frame_info.interlaced_uv != window->interlaced_uv)) { yuv_update |= IVTV_YUV_UPDATE_VERTICAL; @@ -970,6 +970,9 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args) itv->yuv_info.new_frame_info[frame].tru_w = args->src_width; itv->yuv_info.new_frame_info[frame].tru_h = args->src_height; + /* Snapshot field order */ + itv->yuv_info.sync_field[frame] = itv->yuv_info.lace_sync_field; + /* Are we going to offset the Y plane */ if (args->src.height + args->src.top < 512-16) itv->yuv_info.new_frame_info[frame].offset_y = 1; @@ -985,6 +988,7 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args) itv->yuv_info.new_frame_info[frame].update = 0; itv->yuv_info.new_frame_info[frame].interlaced_y = 0; itv->yuv_info.new_frame_info[frame].interlaced_uv = 0; + itv->yuv_info.new_frame_info[frame].lace_mode = itv->yuv_info.lace_mode; if (memcmp (&itv->yuv_info.old_frame_info_args, &itv->yuv_info.new_frame_info[frame], sizeof (itv->yuv_info.new_frame_info[frame]))) { @@ -995,6 +999,12 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args) itv->yuv_info.new_frame_info[frame].update |= register_update; + /* Should this frame be delayed ? */ + if (itv->yuv_info.sync_field[frame] != itv->yuv_info.sync_field[(frame - 1) & 3]) + itv->yuv_info.field_delay[frame] = 1; + else + itv->yuv_info.field_delay[frame] = 0; + /* DMA the frame */ mutex_lock(&itv->udma.lock); -- cgit v1.2.3-70-g09d2 From 19dc74b7c5f02ada19840a85582f42f4dddcdb3e Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Tue, 31 Jul 2007 23:06:50 -0300 Subject: V4L/DVB (5975): cx88: Wrong values used for HD-3000 radio mode After some tedious work with a logic probe and a magnifying glass, I've determined that GPIO 7 is used to switch between the DTT7612's Sound 4.5 MHz IF output on pin 12 and the FM 10.7MHz If output on pin 11. GPIO 2 is used to switch the card's analog sound output from from the analog input connector to the CX23883's audio DACs. So, in radio mode GPIO2 = 1 and GPIO7 = 0. Add some comments about how the HD-3000's GPIOs are connected. Delete the vmux setting for the radio, as vmux doesn't apply to radio mode. Also delete the lines setting unused gpio words to zero; it's not necessary as 0 is the default value for uninitialized fields. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-cards.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index 6a136ddbccf..1fc71a78b92 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -575,35 +575,34 @@ struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, + /* GPIO[2] = audio source for analog audio out connector + * 0 = analog audio input connector + * 1 = CX88 audio DACs + * + * GPIO[7] = input to CX88's audio/chroma ADC + * 0 = FM 10.7 MHz IF + * 1 = Sound 4.5 MHz IF + * + * GPIO[1,5,6] = Oren 51132 pins 27,35,28 respectively + * + * GPIO[16] = Remote control input + */ .input = {{ .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x00008484, - .gpio1 = 0x00000000, - .gpio2 = 0x00000000, - .gpio3 = 0x00000000, },{ .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x00008400, - .gpio1 = 0x00000000, - .gpio2 = 0x00000000, - .gpio3 = 0x00000000, },{ .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x00008400, - .gpio1 = 0x00000000, - .gpio2 = 0x00000000, - .gpio3 = 0x00000000, }}, .radio = { .type = CX88_RADIO, - .vmux = 2, - .gpio0 = 0x00008400, - .gpio1 = 0x00000000, - .gpio2 = 0x00000000, - .gpio3 = 0x00000000, + .gpio0 = 0x00008404, }, .mpeg = CX88_MPEG_DVB, }, -- cgit v1.2.3-70-g09d2 From b97762ba18b57c7057b58ed4f7140a19d0166b01 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Tue, 31 Jul 2007 18:51:30 -0300 Subject: V4L/DVB (5976): mt2131 s5h1409: correct frontend selection logic If a card driver is compiled into the kernel and mt2131 or s5h1409 are compiled as modules, the kernel won't link. A compiled in driver can't use a module, so in this case the mt2131 or s5h1409 are effectively disabled w.r.t the compiled in driver and the stub attach function should be used. Signed-off-by: Trent Piepho Acked-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/mt2131.h | 2 +- drivers/media/dvb/frontends/s5h1409.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/mt2131.h b/drivers/media/dvb/frontends/mt2131.h index 608f1f66c9e..1e4ffe7dc8c 100644 --- a/drivers/media/dvb/frontends/mt2131.h +++ b/drivers/media/dvb/frontends/mt2131.h @@ -30,7 +30,7 @@ struct mt2131_config { u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */ }; -#if defined(CONFIG_DVB_TUNER_MT2131) || defined(CONFIG_DVB_TUNER_MT2131_MODULE) +#if defined(CONFIG_DVB_TUNER_MT2131) || (defined(CONFIG_DVB_TUNER_MT2131_MODULE) && defined(MODULE)) extern struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2131_config *cfg, diff --git a/drivers/media/dvb/frontends/s5h1409.h b/drivers/media/dvb/frontends/s5h1409.h index bccfd8a6fbd..20f9af1af44 100644 --- a/drivers/media/dvb/frontends/s5h1409.h +++ b/drivers/media/dvb/frontends/s5h1409.h @@ -53,7 +53,7 @@ struct s5h1409_config u8 status_mode; }; -#if defined(CONFIG_DVB_S5H1409) || defined(CONFIG_DVB_S5H1409_MODULE) +#if defined(CONFIG_DVB_S5H1409) || (defined(CONFIG_DVB_S5H1409_MODULE) && defined(MODULE)) extern struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config, struct i2c_adapter* i2c); #else -- cgit v1.2.3-70-g09d2 From a75d204860b5051ebd5635278c097bafb4ea53f9 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Wed, 1 Aug 2007 00:13:28 -0300 Subject: V4L/DVB (5977): cx8800: Add register debug functions to radio device too Add the advanced debug functions to the radio videodev template. One could already use them from the video and vbi devices. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-video.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index 41b5cb63fd2..58ec76be436 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -1716,6 +1716,10 @@ static struct video_device cx8800_radio_template = .vidioc_s_ctrl = vidioc_s_ctrl, .vidioc_g_frequency = vidioc_g_frequency, .vidioc_s_frequency = vidioc_s_frequency, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = vidioc_g_register, + .vidioc_s_register = vidioc_s_register, +#endif }; /* ----------------------------------------------------------- */ -- cgit v1.2.3-70-g09d2 From 5e082f1521598a91c9194b2356b157cade9b6e87 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Fri, 3 Aug 2007 18:32:38 -0300 Subject: V4L/DVB (5978): tuner: Better tuner radio support Add radio support for the Thomson DTT7612 tuner. This tuner uses a different 1st intermediate frequency than the other radio tuners supported (a lot of NTSC radio tuners probably need this change too). Add a new tuner-simple parameter, radio_if. It selects the 1st IF used for radio reception. The radio frequency setting code in tuner-simple now uses this field, instead of a special case select() block for each tuner with radio support. The tuner parameters for tuners that used a 33.3 MHz RIF now set radio_if to 1 in tuner-types.c. The Thomson DTT7612 gets radio_if = 2, also add has_tda9887 = 1 and fm_gain_normal = 1. Add some defines for tda9887 bits that control IF setting in radio mode. Add a new tda9887 config option, TDA9887_RIF_41_3, that selects a 41.3 MHz radio IF. Fix the way tda9887 radio options work. The driver was modifying the default radio mode config templates based on the TDA9887_XXXX flags. This means that _all_ tuners would get the same settings. If you had a one tuner than used TDA9887_GAIN_NORMAL and one that didn't, both would get the setting. Now the tda9987 driver just checks if tuner mode is radio and then applies the config settings directly to the data being sent, just like how all the TV mode settings already work. The PLL setting math is made a little more accurate. And a grammar error in a printk is fixed. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tda9887.c | 19 ++++++++++--- drivers/media/video/tuner-simple.c | 55 +++++++++++++++++++++++++------------- drivers/media/video/tuner-types.c | 5 ++++ include/media/tuner-types.h | 4 +++ include/media/tuner.h | 1 + 5 files changed, 62 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index a8f773274fe..aa311e4f1f6 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -97,6 +97,8 @@ struct tvnorm { #define cAudioIF_6_5 0x03 // bit e0:1 +#define cVideoIFMask 0x1c // bit e2:4 +/* Video IF selection in TV Mode (bit B3=0) */ #define cVideoIF_58_75 0x00 // bit e2:4 #define cVideoIF_45_75 0x04 // bit e2:4 #define cVideoIF_38_90 0x08 // bit e2:4 @@ -106,6 +108,13 @@ struct tvnorm { #define cRadioIF_45_75 0x18 // bit e2:4 #define cRadioIF_38_90 0x1C // bit e2:4 +/* IF1 selection in Radio Mode (bit B3=1) */ +#define cRadioIF_33_30 0x00 // bit e2,4 (also 0x10,0x14) +#define cRadioIF_41_30 0x04 // bit e2,4 + +/* Output of AFC pin in radio mode when bit E7=1 */ +#define cRadioAGC_SIF 0x00 // bit e3 +#define cRadioAGC_FM 0x08 // bit e3 #define cTunerGainNormal 0x00 // bit e5 #define cTunerGainLow 0x20 // bit e5 @@ -487,9 +496,13 @@ static int tda9887_set_config(struct tuner *t, char *buf) if (t->tda9887_config & TDA9887_GATING_18) buf[3] &= ~cGating_36; - if (t->tda9887_config & TDA9887_GAIN_NORMAL) { - radio_stereo.e &= ~cTunerGainLow; - radio_mono.e &= ~cTunerGainLow; + if (t->mode == V4L2_TUNER_RADIO) { + if (t->tda9887_config & TDA9887_RIF_41_3) { + buf[3] &= ~cVideoIFMask; + buf[3] |= cRadioIF_41_30; + } + if (t->tda9887_config & TDA9887_GAIN_NORMAL) + buf[3] &= ~cTunerGainLow; } return 0; diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index 2d57e8bc0db..10a7d36a264 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -402,53 +402,68 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq) u8 buffer[4]; u16 div; int rc, j; - enum param_type desired_type = TUNER_PARAM_TYPE_RADIO; struct tuner_params *params; tun = &tuners[t->type]; - for (j = 0; j < tun->count-1; j++) { - if (desired_type != tun->params[j].type) - continue; + for (j = tun->count-1; j > 0; j--) + if (tun->params[j].type == TUNER_PARAM_TYPE_RADIO) + break; + /* default params (j=0) will be used if desired type wasn't found */ + params = &tun->params[j]; + + /* Select Radio 1st IF used */ + switch (params->radio_if) { + case 0: /* 10.7 MHz */ + freq += (unsigned int)(10.7*16000); break; + case 1: /* 33.3 MHz */ + freq += (unsigned int)(33.3*16000); + break; + case 2: /* 41.3 MHz */ + freq += (unsigned int)(41.3*16000); + break; + default: + tuner_warn("Unsupported radio_if value %d\n", params->radio_if); + return; } - /* use default tuner_params if desired_type not available */ - if (desired_type != tun->params[j].type) - j = 0; - - div = (20 * freq / 16000) + (int)(20*10.7); /* IF 10.7 MHz */ - params = &tun->params[j]; - buffer[2] = (params->ranges[0].config & ~TUNER_RATIO_MASK) | TUNER_RATIO_SELECT_50; /* 50 kHz step */ + /* Bandswitch byte */ switch (t->type) { case TUNER_TENA_9533_DI: case TUNER_YMEC_TVF_5533MF: - tuner_dbg ("This tuner doesn't have FM. Most cards has a TEA5767 for FM\n"); + tuner_dbg ("This tuner doesn't have FM. Most cards have a TEA5767 for FM\n"); return; case TUNER_PHILIPS_FM1216ME_MK3: case TUNER_PHILIPS_FM1236_MK3: case TUNER_PHILIPS_FMD1216ME_MK3: case TUNER_LG_NTSC_TAPE: + case TUNER_PHILIPS_FM1256_IH3: buffer[3] = 0x19; break; case TUNER_TNF_5335MF: buffer[3] = 0x11; break; - case TUNER_PHILIPS_FM1256_IH3: - div = (20 * freq) / 16000 + (int)(33.3 * 20); /* IF 33.3 MHz */ - buffer[3] = 0x19; - break; case TUNER_LG_PAL_FM: buffer[3] = 0xa5; break; - case TUNER_MICROTUNE_4049FM5: - div = (20 * freq) / 16000 + (int)(33.3 * 20); /* IF 33.3 MHz */ - buffer[3] = 0xa4; + case TUNER_THOMSON_DTT761X: + buffer[3] = 0x39; break; + case TUNER_MICROTUNE_4049FM5: default: buffer[3] = 0xa4; break; } + + buffer[2] = (params->ranges[0].config & ~TUNER_RATIO_MASK) | + TUNER_RATIO_SELECT_50; /* 50 kHz step */ + + /* Convert from 1/16 kHz V4L steps to 1/20 MHz (=50 kHz) PLL steps + freq * (1 Mhz / 16000 V4L steps) * (20 PLL steps / 1 MHz) = + freq * (1/800) */ + div = (freq + 400) / 800; + if (params->cb_first_if_lower_freq && div < t->last_div) { buffer[0] = buffer[2]; buffer[1] = buffer[3]; @@ -475,6 +490,8 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq) config &= ~TDA9887_PORT1_ACTIVE;*/ if (params->fm_gain_normal) config |= TDA9887_GAIN_NORMAL; + if (params->radio_if == 2) + config |= TDA9887_RIF_41_3; i2c_clients_command(c->adapter, TDA9887_SET_CONFIG, &config); } if (4 != (rc = i2c_master_send(c,buffer,4))) diff --git a/drivers/media/video/tuner-types.c b/drivers/media/video/tuner-types.c index 53a99b39387..c6a7934bd5a 100644 --- a/drivers/media/video/tuner-types.c +++ b/drivers/media/video/tuner-types.c @@ -652,6 +652,7 @@ static struct tuner_params tuner_microtune_4049_fm5_params[] = { .port1_invert_for_secam_lc = 1, .default_pll_gating_18 = 1, .fm_gain_normal=1, + .radio_if = 1, /* 33.3 MHz */ }, }; @@ -733,6 +734,7 @@ static struct tuner_params tuner_philips_fm1256_ih3_params[] = { .type = TUNER_PARAM_TYPE_PAL, .ranges = tuner_fm1236_mk3_ntsc_ranges, .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges), + .radio_if = 1, /* 33.3 MHz */ }, }; @@ -859,6 +861,9 @@ static struct tuner_params tuner_thomson_dtt761x_params[] = { .type = TUNER_PARAM_TYPE_NTSC, .ranges = tuner_thomson_dtt761x_ntsc_ranges, .count = ARRAY_SIZE(tuner_thomson_dtt761x_ntsc_ranges), + .has_tda9887 = 1, + .fm_gain_normal = 1, + .radio_if = 2, /* 41.3 MHz */ }, }; diff --git a/include/media/tuner-types.h b/include/media/tuner-types.h index e5ad3fcfe98..b201371416a 100644 --- a/include/media/tuner-types.h +++ b/include/media/tuner-types.h @@ -79,6 +79,10 @@ struct tuner_params { /* Select 18% (or according to datasheet 0%) L standard PLL gating, vs the driver default of 36%. */ unsigned int default_pll_gating_18:1; + /* IF to use in radio mode. Tuners with a separate radio IF filter + seem to use 10.7, while those without use 33.3 for PAL/SECAM tuners + and 41.3 for NTSC tuners. 0 = 10.7, 1 = 33.3, 2 = 41.3 */ + unsigned int radio_if:2; /* Default tda9887 TOP value in dB for the low band. Default is 0. Range: -16:+15 */ signed int default_top_low:5; diff --git a/include/media/tuner.h b/include/media/tuner.h index 160381c72e4..c03dceb9260 100644 --- a/include/media/tuner.h +++ b/include/media/tuner.h @@ -146,6 +146,7 @@ extern int tuner_debug; #define TDA9887_AUTOMUTE (1<<18) #define TDA9887_GATING_18 (1<<19) #define TDA9887_GAIN_NORMAL (1<<20) +#define TDA9887_RIF_41_3 (1<<21) /* radio IF1 41.3 vs 33.3 */ #ifdef __KERNEL__ -- cgit v1.2.3-70-g09d2 From 4f76b672c4f9ceb9e7e0aa6224293da0ae7430da Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Mon, 6 Aug 2007 13:59:19 -0300 Subject: V4L/DVB (5980): tda8083: fix frequency and symbolrate info The TDA8083 supports a symbol rate from 12..30 MSym/s. The Grundig 29504-451 tuner uses the TDA8060 down-converter, which has a frequency range from 920..2200MHz. Thanks-to: Lars Buerding Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda8083.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/tda8083.c b/drivers/media/dvb/frontends/tda8083.c index 67415c9db6f..0f041e87378 100644 --- a/drivers/media/dvb/frontends/tda8083.c +++ b/drivers/media/dvb/frontends/tda8083.c @@ -443,12 +443,12 @@ static struct dvb_frontend_ops tda8083_ops = { .info = { .name = "Philips TDA8083 DVB-S", .type = FE_QPSK, - .frequency_min = 950000, /* FIXME: guessed! */ - .frequency_max = 1400000, /* FIXME: guessed! */ + .frequency_min = 920000, /* TDA8060 */ + .frequency_max = 2200000, /* TDA8060 */ .frequency_stepsize = 125, /* kHz for QPSK frontends */ /* .frequency_tolerance = ???,*/ - .symbol_rate_min = 1000000, /* FIXME: guessed! */ - .symbol_rate_max = 45000000, /* FIXME: guessed! */ + .symbol_rate_min = 12000000, + .symbol_rate_max = 30000000, /* .symbol_rate_tolerance = ???,*/ .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | -- cgit v1.2.3-70-g09d2 From 5e76a1cb2ce0918ff2429fcfa2d5655dbd273c54 Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Mon, 6 Aug 2007 18:05:27 -0300 Subject: V4L/DVB (5981): Zoran_driver.c: fix memset in ioctl Looks like memset() is zeroing wrong nr of bytes. Signed-off-by: Mariusz Kozlowski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/zoran_driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c index 4dbe2d449b5..d831ca16d9e 100644 --- a/drivers/media/video/zoran_driver.c +++ b/drivers/media/video/zoran_driver.c @@ -3196,7 +3196,7 @@ zoran_do_ioctl (struct inode *inode, "%s: VIDIOC_QUERYBUF - index=%d, type=%d\n", ZR_DEVNAME(zr), buf->index, buf->type); - memset(buf, 0, sizeof(buf)); + memset(buf, 0, sizeof(*buf)); buf->type = type; buf->index = index; -- cgit v1.2.3-70-g09d2 From 473c653fff8dc6a63cad279a8e83395ead12119d Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Mon, 6 Aug 2007 18:05:35 -0300 Subject: V4L/DVB (5982): Dev.c: memset fix Looks like memset() is zeroing wrong nr of bytes. Signed-off-by: Mariusz Kozlowski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videodev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c index b876aca69c7..0334b9aaf12 100644 --- a/drivers/media/video/videodev.c +++ b/drivers/media/video/videodev.c @@ -448,7 +448,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, if (cmd == VIDIOCGMBUF) { struct video_mbuf *p=arg; - memset(p,0,sizeof(p)); + memset(p, 0, sizeof(*p)); if (!vfd->vidiocgmbuf) return ret; -- cgit v1.2.3-70-g09d2 From 8509a29ec6050a03d88f2da59fc2e361f6c16534 Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Mon, 6 Aug 2007 18:05:45 -0300 Subject: V4L/DVB (5983): Arv.c: fix memset in ioctl Looks like memset() is zeroing wrong nr of bytes. Signed-off-by: Mariusz Kozlowski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/arv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/arv.c b/drivers/media/video/arv.c index 2666d3b7663..19e9929ffa0 100644 --- a/drivers/media/video/arv.c +++ b/drivers/media/video/arv.c @@ -441,7 +441,7 @@ static int ar_do_ioctl(struct inode *inode, struct file *file, { struct video_window *w = arg; DEBUG(1, "VIDIOCGWIN:\n"); - memset(w, 0, sizeof(w)); + memset(w, 0, sizeof(*w)); w->width = ar->width; w->height = ar->height; return 0; -- cgit v1.2.3-70-g09d2 From a18255bef2a62632ed442fdb90b091193cbabca5 Mon Sep 17 00:00:00 2001 From: Hartmut Birr Date: Thu, 9 Aug 2007 00:01:51 -0300 Subject: V4L/DVB (5985): Fix the min/max frequencies of some DVB-C frontends The min frequencies of the DVB-C frontends are wrong. In Europe, the center frequency of the lowest channel is 50.5MHz and not 51MHz. All known cards with the stv0297/tda0002x/ves1820 frontend are able to tune to this frequency. I've changed the range to the lowest channel - 1/2 bandwidth and the highest channel + 1/2 bandwidth. For the design of the dvb driver, the frequency ranges must be part of the tuner and not of the frontend itself. The same frontend may be used for different tuners. The attached patch does only fix the ranges and not the design. Signed-off-by: Hartmut Birr Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/stv0297.c | 4 ++-- drivers/media/dvb/frontends/tda10021.c | 4 ++-- drivers/media/dvb/frontends/tda10023.c | 4 ++-- drivers/media/dvb/frontends/ves1820.c | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/stv0297.c b/drivers/media/dvb/frontends/stv0297.c index 9a343972ff5..17e5cb561cd 100644 --- a/drivers/media/dvb/frontends/stv0297.c +++ b/drivers/media/dvb/frontends/stv0297.c @@ -680,8 +680,8 @@ static struct dvb_frontend_ops stv0297_ops = { .info = { .name = "ST STV0297 DVB-C", .type = FE_QAM, - .frequency_min = 64000000, - .frequency_max = 1300000000, + .frequency_min = 47000000, + .frequency_max = 862000000, .frequency_stepsize = 62500, .symbol_rate_min = 870000, .symbol_rate_max = 11700000, diff --git a/drivers/media/dvb/frontends/tda10021.c b/drivers/media/dvb/frontends/tda10021.c index e725f612a6b..4cd9e82c466 100644 --- a/drivers/media/dvb/frontends/tda10021.c +++ b/drivers/media/dvb/frontends/tda10021.c @@ -439,8 +439,8 @@ static struct dvb_frontend_ops tda10021_ops = { .name = "Philips TDA10021 DVB-C", .type = FE_QAM, .frequency_stepsize = 62500, - .frequency_min = 51000000, - .frequency_max = 858000000, + .frequency_min = 47000000, + .frequency_max = 862000000, .symbol_rate_min = (XIN/2)/64, /* SACLK/64 == (XIN/2)/64 */ .symbol_rate_max = (XIN/2)/4, /* SACLK/4 */ #if 0 diff --git a/drivers/media/dvb/frontends/tda10023.c b/drivers/media/dvb/frontends/tda10023.c index a00cf0f54ef..364bc01971a 100644 --- a/drivers/media/dvb/frontends/tda10023.c +++ b/drivers/media/dvb/frontends/tda10023.c @@ -500,8 +500,8 @@ static struct dvb_frontend_ops tda10023_ops = { .name = "Philips TDA10023 DVB-C", .type = FE_QAM, .frequency_stepsize = 62500, - .frequency_min = 51000000, - .frequency_max = 858000000, + .frequency_min = 47000000, + .frequency_max = 862000000, .symbol_rate_min = (SYSCLK/2)/64, /* SACLK/64 == (SYSCLK/2)/64 */ .symbol_rate_max = (SYSCLK/2)/4, /* SACLK/4 */ .caps = 0x400 | //FE_CAN_QAM_4 diff --git a/drivers/media/dvb/frontends/ves1820.c b/drivers/media/dvb/frontends/ves1820.c index 9b57576bfeb..066b73b7569 100644 --- a/drivers/media/dvb/frontends/ves1820.c +++ b/drivers/media/dvb/frontends/ves1820.c @@ -410,8 +410,8 @@ static struct dvb_frontend_ops ves1820_ops = { .name = "VLSI VES1820 DVB-C", .type = FE_QAM, .frequency_stepsize = 62500, - .frequency_min = 51000000, - .frequency_max = 858000000, + .frequency_min = 47000000, + .frequency_max = 862000000, .caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | -- cgit v1.2.3-70-g09d2 From c471b331dda9fdfaf67832998d0b2c848777ab4a Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Thu, 9 Aug 2007 01:03:42 -0300 Subject: V4L/DVB (5986): dvb_frontend: Fixed GET_INFO ioctl and check of frequency limits The calculation of frequency limits ignored tuner-specific frequency limits. Range checks and GET_INFO ioctl updated accordingly. Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index fd9bac5eb25..1a1b2405b0f 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -697,17 +697,35 @@ static int dvb_frontend_start(struct dvb_frontend *fe) return 0; } +static void dvb_frontend_get_frequeny_limits(struct dvb_frontend *fe, + u32 *freq_min, u32 *freq_max) +{ + *freq_min = max(fe->ops.info.frequency_min, fe->ops.tuner_ops.info.frequency_min); + + if (fe->ops.info.frequency_max == 0) + *freq_max = fe->ops.tuner_ops.info.frequency_max; + else if (fe->ops.tuner_ops.info.frequency_max == 0) + *freq_max = fe->ops.info.frequency_max; + else + *freq_max = min(fe->ops.info.frequency_max, fe->ops.tuner_ops.info.frequency_max); + + if (*freq_min == 0 || *freq_max == 0) + printk(KERN_WARNING "DVB: frontend %u frequency limits undefined - fix the driver\n", + fe->dvb->num); +} + static int dvb_frontend_check_parameters(struct dvb_frontend *fe, struct dvb_frontend_parameters *parms) { + u32 freq_min; + u32 freq_max; + /* range check: frequency */ - if ((fe->ops.info.frequency_min && - parms->frequency < fe->ops.info.frequency_min) || - (fe->ops.info.frequency_max && - parms->frequency > fe->ops.info.frequency_max)) { + dvb_frontend_get_frequeny_limits(fe, &freq_min, &freq_max); + if ((freq_min && parms->frequency < freq_min) || + (freq_max && parms->frequency > freq_max)) { printk(KERN_WARNING "DVB: frontend %u frequency %u out of range (%u..%u)\n", - fe->dvb->num, parms->frequency, - fe->ops.info.frequency_min, fe->ops.info.frequency_max); + fe->dvb->num, parms->frequency, freq_min, freq_max); return -EINVAL; } @@ -763,6 +781,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, case FE_GET_INFO: { struct dvb_frontend_info* info = parg; memcpy(info, &fe->ops.info, sizeof(struct dvb_frontend_info)); + dvb_frontend_get_frequeny_limits(fe, &info->frequency_min, &info->frequency_max); /* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't * do it, it is done for it. */ -- cgit v1.2.3-70-g09d2 From 276e49a01a7e6c4a7bfb78618cf2f5befbf9f5de Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Thu, 9 Aug 2007 02:41:16 -0300 Subject: V4L/DVB (5987): saa7146: clean-up irq processing Interrupt processing fixed: First handle interrupt, then acknowledge it. Otherwise the same interrupt might occur twice. Cleaned-up i2c interrupt handler and i2c error messages. Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/saa7146_core.c | 31 +++++++++++++------------------ drivers/media/common/saa7146_i2c.c | 21 ++++++++++++++++----- 2 files changed, 29 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c index 12cda9eebd1..1c962a2b44d 100644 --- a/drivers/media/common/saa7146_core.c +++ b/drivers/media/common/saa7146_core.c @@ -248,10 +248,11 @@ int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt static irqreturn_t interrupt_hw(int irq, void *dev_id) { struct saa7146_dev *dev = dev_id; - u32 isr = 0; + u32 isr; + u32 ack_isr; /* read out the interrupt status register */ - isr = saa7146_read(dev, ISR); + ack_isr = isr = saa7146_read(dev, ISR); /* is this our interrupt? */ if ( 0 == isr ) { @@ -259,8 +260,6 @@ static irqreturn_t interrupt_hw(int irq, void *dev_id) return IRQ_NONE; } - saa7146_write(dev, ISR, isr); - if( 0 != (dev->ext)) { if( 0 != (dev->ext->irq_mask & isr )) { if( 0 != dev->ext->irq_func ) { @@ -283,21 +282,16 @@ static irqreturn_t interrupt_hw(int irq, void *dev_id) isr &= ~MASK_28; } if (0 != (isr & (MASK_16|MASK_17))) { - u32 status = saa7146_read(dev, I2C_STATUS); - if( (0x3 == (status & 0x3)) || (0 == (status & 0x1)) ) { - SAA7146_IER_DISABLE(dev, MASK_16|MASK_17); - /* only wake up if we expect something */ - if( 0 != dev->i2c_op ) { - u32 psr = (saa7146_read(dev, PSR) >> 16) & 0x2; - u32 ssr = (saa7146_read(dev, SSR) >> 17) & 0x1f; - DEB_I2C(("irq: i2c, status: 0x%08x, psr:0x%02x, ssr:0x%02x).\n",status,psr,ssr)); - dev->i2c_op = 0; - wake_up(&dev->i2c_wq); - } else { - DEB_I2C(("unexpected irq: i2c, status: 0x%08x, isr %#x\n",status, isr)); - } + SAA7146_IER_DISABLE(dev, MASK_16|MASK_17); + /* only wake up if we expect something */ + if (0 != dev->i2c_op) { + dev->i2c_op = 0; + wake_up(&dev->i2c_wq); } else { - DEB_I2C(("unhandled irq: i2c, status: 0x%08x, isr %#x\n",status, isr)); + u32 psr = saa7146_read(dev, PSR); + u32 ssr = saa7146_read(dev, SSR); + printk(KERN_WARNING "%s: unexpected i2c irq: isr %08x psr %08x ssr %08x\n", + dev->name, isr, psr, ssr); } isr &= ~(MASK_16|MASK_17); } @@ -306,6 +300,7 @@ static irqreturn_t interrupt_hw(int irq, void *dev_id) ERR(("disabling interrupt source(s)!\n")); SAA7146_IER_DISABLE(dev,isr); } + saa7146_write(dev, ISR, ack_isr); return IRQ_HANDLED; } diff --git a/drivers/media/common/saa7146_i2c.c b/drivers/media/common/saa7146_i2c.c index f823286341e..7e7689afae6 100644 --- a/drivers/media/common/saa7146_i2c.c +++ b/drivers/media/common/saa7146_i2c.c @@ -202,7 +202,8 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d /* a signal arrived */ return -ERESTARTSYS; - printk(KERN_WARNING "saa7146_i2c_writeout: timed out waiting for end of xfer\n"); + printk(KERN_WARNING "%s %s [irq]: timed out waiting for end of xfer\n", + dev->name, __FUNCTION__); return -EIO; } status = saa7146_read(dev, I2C_STATUS); @@ -219,7 +220,8 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d break; } if (time_after(jiffies,timeout)) { - printk(KERN_WARNING "saa7146_i2c_writeout: timed out waiting for MC2\n"); + printk(KERN_WARNING "%s %s: timed out waiting for MC2\n", + dev->name, __FUNCTION__); return -EIO; } } @@ -235,7 +237,8 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d /* this is normal when probing the bus * (no answer from nonexisistant device...) */ - DEB_I2C(("saa7146_i2c_writeout: timed out waiting for end of xfer\n")); + printk(KERN_WARNING "%s %s [poll]: timed out waiting for end of xfer\n", + dev->name, __FUNCTION__); return -EIO; } if (++trial < 50 && short_delay) @@ -246,8 +249,16 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d } /* give a detailed status report */ - if ( 0 != (status & SAA7146_I2C_ERR)) { - + if ( 0 != (status & (SAA7146_I2C_SPERR | SAA7146_I2C_APERR | + SAA7146_I2C_DTERR | SAA7146_I2C_DRERR | + SAA7146_I2C_AL | SAA7146_I2C_ERR | + SAA7146_I2C_BUSY)) ) { + + if ( 0 == (status & SAA7146_I2C_ERR) || + 0 == (status & SAA7146_I2C_BUSY) ) { + /* it may take some time until ERR goes high - ignore */ + DEB_I2C(("unexpected i2c status %04x\n", status)); + } if( 0 != (status & SAA7146_I2C_SPERR) ) { DEB_I2C(("error due to invalid start/stop condition.\n")); } -- cgit v1.2.3-70-g09d2 From 4ebcb48da1eace49ef5f2d83a91984085c6d702d Mon Sep 17 00:00:00 2001 From: Simon Arlott Date: Thu, 9 Aug 2007 11:29:33 -0300 Subject: V4L/DVB (5988): Fix OOP on videobuf-dvb when hibernating Since videobuf_waiton is called with intr=1, it can return -EINTR and therefore err may be non-zero. This happens when the system goes into the standby state. Without the BUG() occurring, there's no problem with standby mode while DVB is being used. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/video-buf-dvb.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/video-buf-dvb.c b/drivers/media/video/video-buf-dvb.c index e617925ba31..d2af82dc8fa 100644 --- a/drivers/media/video/video-buf-dvb.c +++ b/drivers/media/video/video-buf-dvb.c @@ -56,7 +56,6 @@ static int videobuf_dvb_thread(void *data) struct videobuf_buffer, stream); list_del(&buf->stream); err = videobuf_waiton(buf,0,1); - BUG_ON(0 != err); /* no more feeds left or stop_feed() asked us to quit */ if (0 == dvb->nfeeds) -- cgit v1.2.3-70-g09d2 From 7963fa48dafd07a8c6b6007fb038095553ad6a0f Mon Sep 17 00:00:00 2001 From: Steven Walter Date: Thu, 9 Aug 2007 11:36:35 -0300 Subject: V4L/DVB (5989): V4L: Add additional ioctls to compat_ioctl32 With the addition of these ioctls, I'm able to watch TV with a 32-bit version of tvtime on x86_64. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/compat_ioctl32.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/compat_ioctl32.c b/drivers/media/video/compat_ioctl32.c index f065ad12cc6..cefd1381e8d 100644 --- a/drivers/media/video/compat_ioctl32.c +++ b/drivers/media/video/compat_ioctl32.c @@ -848,6 +848,8 @@ long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) case VIDIOCSFREQ32: case VIDIOCGAUDIO: case VIDIOCSAUDIO: + case VIDIOCGVBIFMT: + case VIDIOCSVBIFMT: #endif case VIDIOC_QUERYCAP: case VIDIOC_ENUM_FMT: @@ -874,7 +876,10 @@ long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) case VIDIOC_ENUMINPUT: case VIDIOC_ENUMINPUT32: case VIDIOC_G_CTRL: + case VIDIOC_S_CTRL: case VIDIOC_S_CTRL32: + case VIDIOC_S_FREQUENCY: + case VIDIOC_G_FREQUENCY: case VIDIOC_QUERYCTRL: case VIDIOC_G_INPUT32: case VIDIOC_S_INPUT32: -- cgit v1.2.3-70-g09d2 From 1597f1f676d2c425028b6a20f21a987f489dbdd2 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Thu, 9 Aug 2007 12:02:30 -0300 Subject: V4L/DVB (5990): cinergyt2_suspend: don't forget to unlock cinergyt2->wq_sem Restore unlock of cinergyt2->wq_sem, was deleted by accident. Signed-off-by: Oleg Nesterov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/cinergyT2/cinergyT2.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c index 28929b618e2..b910fa0baa0 100644 --- a/drivers/media/dvb/cinergyT2/cinergyT2.c +++ b/drivers/media/dvb/cinergyT2/cinergyT2.c @@ -1008,6 +1008,8 @@ static int cinergyt2_suspend (struct usb_interface *intf, pm_message_t state) cinergyt2_sleep(cinergyt2, 1); mutex_unlock(&cinergyt2->sem); + mutex_unlock(&cinergyt2->wq_sem); + return 0; } -- cgit v1.2.3-70-g09d2 From 94104aa2a88ac2433f7cbde3dbec629263724271 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 4 Aug 2007 04:56:00 -0300 Subject: V4L/DVB (5992): ivtv: show card name as well in the LOG_STATUS output. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-ioctl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index dfe0aedc60f..85e6a34d5e9 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -1209,6 +1209,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void int i; IVTV_INFO("================= START STATUS CARD #%d =================\n", itv->num); + IVTV_INFO("Version: %s Card: %s\n", IVTV_VERSION, itv->card_name); if (itv->hw_flags & IVTV_HW_TVEEPROM) { struct tveeprom tv; @@ -1242,7 +1243,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void IVTV_INFO("Tuner: %s\n", test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? "Radio" : "TV"); cx2341x_log_status(&itv->params, itv->name); - IVTV_INFO("Version: %s Status flags: 0x%08lx\n", IVTV_VERSION, itv->i_flags); + IVTV_INFO("Status flags: 0x%08lx\n", itv->i_flags); for (i = 0; i < IVTV_MAX_STREAMS; i++) { struct ivtv_stream *s = &itv->streams[i]; -- cgit v1.2.3-70-g09d2 From 89fc4eb924fc8da769083e1680e24c182589d789 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 4 Aug 2007 05:00:07 -0300 Subject: V4L/DVB (5993): cx25840: resetting also requires reloading the firmware Resetting without reloading the firmware is not enough. Sometimes the firmware is 'stuck' and needs to be reloaded. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx25840/cx25840-core.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 9c12bd39cfb..9f99007d389 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -179,7 +179,7 @@ static void cx25836_initialize(struct i2c_client *client) cx25840_and_or(client, 0x15b, ~0x1e, 0x10); } -static void cx25840_initialize(struct i2c_client *client, int loadfw) +static void cx25840_initialize(struct i2c_client *client) { struct cx25840_state *state = i2c_get_clientdata(client); @@ -197,8 +197,7 @@ static void cx25840_initialize(struct i2c_client *client, int loadfw) cx25840_write(client, 0x13c, 0x01); cx25840_write(client, 0x13c, 0x00); /* 5. */ - if (loadfw) - cx25840_loadfw(client); + cx25840_loadfw(client); /* 6. */ cx25840_write(client, 0x115, 0x8c); cx25840_write(client, 0x116, 0x07); @@ -638,7 +637,7 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, if (state->is_cx25836) cx25836_initialize(client); else - cx25840_initialize(client, 1); + cx25840_initialize(client); } switch (cmd) { @@ -841,7 +840,7 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, if (state->is_cx25836) cx25836_initialize(client); else - cx25840_initialize(client, 0); + cx25840_initialize(client); break; case VIDIOC_G_CHIP_IDENT: -- cgit v1.2.3-70-g09d2 From 2cc720957a743ef59f9925ecfef5f71f08387d8b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 4 Aug 2007 05:06:23 -0300 Subject: V4L/DVB (5994): ivtv: make VIDIOC_INT_RESET support smarter. Add support to optionally reset the IR and/or the video digitizer. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-ioctl.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index 85e6a34d5e9..cee6c558c69 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -681,9 +681,17 @@ static int ivtv_debug_ioctls(struct file *filp, unsigned int cmd, void *arg) break; } - case VIDIOC_INT_RESET: - ivtv_reset_ir_gpio(itv); + case VIDIOC_INT_RESET: { + u32 val = *(u32 *)arg; + + if ((val == 0 && itv->options.newi2c) || (val & 0x01)) { + ivtv_reset_ir_gpio(itv); + } + if (val & 0x02) { + itv->video_dec_func(itv, cmd, 0); + } break; + } default: return -EINVAL; -- cgit v1.2.3-70-g09d2 From 372978055dd564d97ca1b4099c99296eaff1fe19 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 11 Sep 2007 11:59:15 -0300 Subject: V4L/DVB (5995): ivtv: add AverMedia M116 - Split Club3D card from Yuan PG600-2, GotView PCI DVD Lite (different composite input) - Add AVerTV MCE 116 Plus (M116) card - Allow Xceive cards to be used without Xceive support Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-cards.c | 81 ++++++++++++++++++++++++++++------ drivers/media/video/ivtv/ivtv-driver.c | 27 +++++------- drivers/media/video/ivtv/ivtv-driver.h | 14 +++--- drivers/media/video/ivtv/ivtv-gpio.c | 24 ---------- drivers/media/video/ivtv/ivtv-gpio.h | 2 +- 5 files changed, 86 insertions(+), 62 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-cards.c b/drivers/media/video/ivtv/ivtv-cards.c index e51d7cc35b1..b6a8be622d3 100644 --- a/drivers/media/video/ivtv/ivtv-cards.c +++ b/drivers/media/video/ivtv/ivtv-cards.c @@ -823,9 +823,7 @@ static const struct ivtv_card ivtv_card_dctmvtvp1 = { /* ------------------------------------------------------------------------- */ -#ifdef HAVE_XC3028 - -/* Yuan PG600-2/GotView PCI DVD Lite/Club3D ZAP-TV1x01 cards */ +/* Yuan PG600-2/GotView PCI DVD Lite cards */ static const struct ivtv_card_pci_info ivtv_pci_pg600v2[] = { { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN3, 0x0600 }, @@ -835,30 +833,87 @@ static const struct ivtv_card_pci_info ivtv_pci_pg600v2[] = { static const struct ivtv_card ivtv_card_pg600v2 = { .type = IVTV_CARD_PG600V2, - .name = "Yuan PG600-2, GotView PCI DVD Lite, Club3D ZAP-TV1x01", + .name = "Yuan PG600-2, GotView PCI DVD Lite", .v4l2_capabilities = IVTV_CAP_ENCODER, .hw_video = IVTV_HW_CX25840, .hw_audio = IVTV_HW_CX25840, .hw_audio_ctrl = IVTV_HW_CX25840, .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER, .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, - { IVTV_CARD_INPUT_SVIDEO1, 1, + { IVTV_CARD_INPUT_SVIDEO1, 0, CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 }, - { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 }, + { IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE1 }, }, .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL }, }, - .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, .tuners = { { .std = V4L2_STD_ALL, .tuner = TUNER_XCEIVE_XC3028 }, }, - .gpio_init = { .direction = 0x1000, .initial_value = 0x1000 }, /* tuner reset */ .pci_list = ivtv_pci_pg600v2, }; -#endif + +/* ------------------------------------------------------------------------- */ + +/* Club3D ZAP-TV1x01 cards */ + +static const struct ivtv_card_pci_info ivtv_pci_club3d[] = { + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN3, 0x0600 }, + { 0, 0, 0 } +}; + +static const struct ivtv_card ivtv_card_club3d = { + .type = IVTV_CARD_CLUB3D, + .name = "Club3D ZAP-TV1x01", + .v4l2_capabilities = IVTV_CAP_ENCODER, + .hw_video = IVTV_HW_CX25840, + .hw_audio = IVTV_HW_CX25840, + .hw_audio_ctrl = IVTV_HW_CX25840, + .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER, + .video_inputs = { + { IVTV_CARD_INPUT_SVIDEO1, 0, + CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 }, + { IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE3 }, + }, + .audio_inputs = { + { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL }, + }, + .tuners = { + { .std = V4L2_STD_ALL, .tuner = TUNER_XCEIVE_XC3028 }, + }, + .pci_list = ivtv_pci_club3d, +}; + +/* ------------------------------------------------------------------------- */ + +/* AVerTV MCE 116 Plus (M116) card */ + +static const struct ivtv_card_pci_info ivtv_pci_avertv_mce116[] = { + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc439 }, + { 0, 0, 0 } +}; + +static const struct ivtv_card ivtv_card_avertv_mce116 = { + .type = IVTV_CARD_AVERTV_MCE116, + .name = "AVerTV MCE 116 Plus", + .v4l2_capabilities = IVTV_CAP_ENCODER, + .hw_video = IVTV_HW_CX25840, + .hw_audio = IVTV_HW_CX25840, + .hw_audio_ctrl = IVTV_HW_CX25840, + .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER | IVTV_HW_WM8739, + .video_inputs = { + { IVTV_CARD_INPUT_SVIDEO1, 0, CX25840_SVIDEO3 }, + { IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE1 }, + }, + .audio_inputs = { + { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, 1 }, + }, + .gpio_init = { .direction = 0xe000, .initial_value = 0x4000 }, /* enable line-in */ + .tuners = { + { .std = V4L2_STD_ALL, .tuner = TUNER_XCEIVE_XC3028 }, + }, + .pci_list = ivtv_pci_avertv_mce116, +}; static const struct ivtv_card *ivtv_card_list[] = { &ivtv_card_pvr250, @@ -879,9 +934,9 @@ static const struct ivtv_card *ivtv_card_list[] = { &ivtv_card_gotview_pci_dvd2, &ivtv_card_yuan_mpc622, &ivtv_card_dctmvtvp1, -#ifdef HAVE_XC3028 &ivtv_card_pg600v2, -#endif + &ivtv_card_club3d, + &ivtv_card_avertv_mce116, /* Variations of standard cards but with the same PCI IDs. These cards must come last in this list. */ diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index f8ef267e56b..198e443e8a5 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -177,9 +177,9 @@ MODULE_PARM_DESC(cardtype, "\t\t\t16 = GOTVIEW PCI DVD2 Deluxe\n" "\t\t\t17 = Yuan MPC622\n" "\t\t\t18 = Digital Cowboy DCT-MTVP1\n" -#ifdef HAVE_XC3028 - "\t\t\t19 = Yuan PG600V2/GotView PCI DVD Lite/Club3D ZAP-TV1x01\n" -#endif + "\t\t\t19 = Yuan PG600V2/GotView PCI DVD Lite\n" + "\t\t\t20 = Club3D ZAP-TV1x01\n" + "\t\t\t21 = AverTV MCE 116 Plus\n" "\t\t\t 0 = Autodetect (default)\n" "\t\t\t-1 = Ignore this card\n\t\t"); MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60"); @@ -821,11 +821,13 @@ static void ivtv_load_and_init_modules(struct ivtv *itv) /* load modules */ #ifndef CONFIG_VIDEO_TUNER if (hw & IVTV_HW_TUNER) { - ivtv_request_module(itv, "tuner"); -#ifdef HAVE_XC3028 - if (itv->options.tuner == TUNER_XCEIVE_XC3028) - ivtv_request_module(itv, "xc3028-tuner"); -#endif + if (itv->options.tuner == TUNER_XCEIVE_XC3028) { + IVTV_INFO("Xceive tuner not yet supported, only composite and S-Video inputs will be available\n"); + itv->tunerid = 1; + } + else { + ivtv_request_module(itv, "tuner"); + } } #endif #ifndef CONFIG_VIDEO_CX25840 @@ -1130,19 +1132,12 @@ static int __devinit ivtv_probe(struct pci_dev *dev, if (itv->options.radio > 0) itv->v4l2_cap |= V4L2_CAP_RADIO; - if (itv->options.tuner > -1) { + if (itv->options.tuner > -1 && itv->tunerid == 0) { struct tuner_setup setup; setup.addr = ADDR_UNSET; setup.type = itv->options.tuner; setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */ -#ifdef HAVE_XC3028 - setup.initmode = V4L2_TUNER_ANALOG_TV; - if (itv->options.tuner == TUNER_XCEIVE_XC3028) { - setup.gpio_write = ivtv_reset_tuner_gpio; - setup.gpio_priv = itv; - } -#endif ivtv_call_i2c_clients(itv, TUNER_SET_TYPE_ADDR, &setup); } diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 6c7c9a57a1a..4a7b23b9f22 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -63,10 +63,9 @@ #include #include -/* #define HAVE_XC3028 1 */ - #include + #define IVTV_ENCODER_OFFSET 0x00000000 #define IVTV_ENCODER_SIZE 0x00800000 /* Last half isn't needed 0x01000000 */ @@ -114,12 +113,10 @@ extern const u32 yuv_offset[4]; #define IVTV_CARD_GOTVIEW_PCI_DVD2 15 /* GotView PCI DVD2 */ #define IVTV_CARD_YUAN_MPC622 16 /* Yuan MPC622 miniPCI */ #define IVTV_CARD_DCTMTVP1 17 /* DIGITAL COWBOY DCT-MTVP1 */ -#ifdef HAVE_XC3028 -#define IVTV_CARD_PG600V2 18 /* Yuan PG600V2/GotView PCI DVD Lite/Club3D ZAP-TV1x01 */ -#define IVTV_CARD_LAST 18 -#else -#define IVTV_CARD_LAST 17 -#endif +#define IVTV_CARD_PG600V2 18 /* Yuan PG600V2/GotView PCI DVD Lite */ +#define IVTV_CARD_CLUB3D 19 /* Club3D ZAP-TV1x01 */ +#define IVTV_CARD_AVERTV_MCE116 20 /* AVerTV MCE 116 Plus */ +#define IVTV_CARD_LAST 20 /* Variants of existing cards but with the same PCI IDs. The driver detects these based on other device information. @@ -705,6 +702,7 @@ struct ivtv { u8 nof_audio_inputs; /* number of audio inputs */ u32 v4l2_cap; /* V4L2 capabilities of card */ u32 hw_flags; /* Hardware description of the board */ + int tunerid; /* Userspace tuner ID for experimental Xceive tuner support */ /* controlling Video decoder function */ int (*video_dec_func)(struct ivtv *, unsigned int, void *); diff --git a/drivers/media/video/ivtv/ivtv-gpio.c b/drivers/media/video/ivtv/ivtv-gpio.c index 6a5a7aa6697..132fb5f7136 100644 --- a/drivers/media/video/ivtv/ivtv-gpio.c +++ b/drivers/media/video/ivtv/ivtv-gpio.c @@ -122,30 +122,6 @@ void ivtv_reset_ir_gpio(struct ivtv *itv) write_reg(curdir, IVTV_REG_GPIO_DIR); } -#ifdef HAVE_XC3028 -int ivtv_reset_tuner_gpio(enum v4l2_tuner_type mode, void *priv, int ptr) -{ - int curdir, curout; - struct ivtv *itv = (struct ivtv *) priv; - - if (itv->card->type != IVTV_CARD_PG600V2 || itv->options.tuner != TUNER_XCEIVE_XC3028) - return -EINVAL; - IVTV_INFO("Resetting tuner\n"); - curout = read_reg(IVTV_REG_GPIO_OUT); - curdir = read_reg(IVTV_REG_GPIO_DIR); - curdir |= (1 << 12); /* GPIO bit 12 */ - - curout &= ~(1 << 12); - write_reg(curout, IVTV_REG_GPIO_OUT); - schedule_timeout_interruptible(msecs_to_jiffies(1)); - - curout |= (1 << 12); - write_reg(curout, IVTV_REG_GPIO_OUT); - schedule_timeout_interruptible(msecs_to_jiffies(1)); - - return 0; -} -#endif void ivtv_gpio_init(struct ivtv *itv) { diff --git a/drivers/media/video/ivtv/ivtv-gpio.h b/drivers/media/video/ivtv/ivtv-gpio.h index c301d2a3934..b31c679bbd8 100644 --- a/drivers/media/video/ivtv/ivtv-gpio.h +++ b/drivers/media/video/ivtv/ivtv-gpio.h @@ -21,5 +21,5 @@ /* GPIO stuff */ void ivtv_gpio_init(struct ivtv *itv); void ivtv_reset_ir_gpio(struct ivtv *itv); -int ivtv_reset_tuner_gpio(enum v4l2_tuner_type mode, void *priv, int ptr); +int ivtv_reset_tuner_gpio(void *dev, int cmd, int value); int ivtv_gpio(struct ivtv *itv, unsigned int command, void *arg); -- cgit v1.2.3-70-g09d2 From 87410dab1238623e082e9a78a62f1bbeb6c475e3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 5 Aug 2007 08:00:36 -0300 Subject: V4L/DVB (5997): cx25840: fix audio mute handling and reporting Audio muting for the tuner input was implemented by stopping the audio microcontroller and restarting it on unmute. However, it appears that this method can actually crash the audio firmware. It's rare and seems to happen with NTSC only. It has been reimplemented by setting to volume to 0. In addition, the reporting of the mute state has been improved as well: it used to be impossible to detect whether the audio was muted by the user or if it was muted due to the microcontroller trying to detect the audio standard. This is now clearly stated. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx25840/cx25840-audio.c | 53 +++++++++++++++++------------ drivers/media/video/cx25840/cx25840-core.c | 6 ++-- drivers/media/video/cx25840/cx25840-core.h | 1 + 3 files changed, 37 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx25840/cx25840-audio.c b/drivers/media/video/cx25840/cx25840-audio.c index f897c1ebd5f..f93b5160bb4 100644 --- a/drivers/media/video/cx25840/cx25840-audio.c +++ b/drivers/media/video/cx25840/cx25840-audio.c @@ -194,19 +194,34 @@ void cx25840_audio_set_path(struct i2c_client *client) static int get_volume(struct i2c_client *client) { + struct cx25840_state *state = i2c_get_clientdata(client); + int vol; + + if (state->unmute_volume >= 0) + return state->unmute_volume; + /* Volume runs +18dB to -96dB in 1/2dB steps * change to fit the msp3400 -114dB to +12dB range */ /* check PATH1_VOLUME */ - int vol = 228 - cx25840_read(client, 0x8d4); + vol = 228 - cx25840_read(client, 0x8d4); vol = (vol / 2) + 23; return vol << 9; } static void set_volume(struct i2c_client *client, int volume) { - /* First convert the volume to msp3400 values (0-127) */ - int vol = volume >> 9; + struct cx25840_state *state = i2c_get_clientdata(client); + int vol; + + if (state->unmute_volume >= 0) { + state->unmute_volume = volume; + return; + } + + /* Convert the volume to msp3400 values (0-127) */ + vol = volume >> 9; + /* now scale it up to cx25840 values * -114dB to -96dB maps to 0 * this should be 19, but in my testing that was 4dB too loud */ @@ -284,30 +299,26 @@ static void set_balance(struct i2c_client *client, int balance) static int get_mute(struct i2c_client *client) { - /* check SRC1_MUTE_EN */ - return cx25840_read(client, 0x8d3) & 0x2 ? 1 : 0; + struct cx25840_state *state = i2c_get_clientdata(client); + + return state->unmute_volume >= 0; } static void set_mute(struct i2c_client *client, int mute) { struct cx25840_state *state = i2c_get_clientdata(client); - if (state->aud_input != CX25840_AUDIO_SERIAL) { - /* Must turn off microcontroller in order to mute sound. - * Not sure if this is the best method, but it does work. - * If the microcontroller is running, then it will undo any - * changes to the mute register. */ - if (mute) { - /* disable microcontroller */ - cx25840_and_or(client, 0x803, ~0x10, 0x00); - cx25840_write(client, 0x8d3, 0x1f); - } else { - /* enable microcontroller */ - cx25840_and_or(client, 0x803, ~0x10, 0x10); - } - } else { - /* SRC1_MUTE_EN */ - cx25840_and_or(client, 0x8d3, ~0x2, mute ? 0x02 : 0x00); + if (mute && state->unmute_volume == -1) { + int vol = get_volume(client); + + set_volume(client, 0); + state->unmute_volume = vol; + } + else if (!mute && state->unmute_volume != -1) { + int vol = state->unmute_volume; + + state->unmute_volume = -1; + set_volume(client, vol); } } diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 9f99007d389..65ad7943dd9 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -915,6 +915,7 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address, state->audclk_freq = 48000; state->pvr150_workaround = 0; state->audmode = V4L2_TUNER_MODE_LANG1; + state->unmute_volume = -1; state->vbi_line_offset = 8; state->id = id; state->rev = device_id; @@ -1066,9 +1067,10 @@ static void log_audio_status(struct i2c_client *client) } v4l_info(client, "Detected audio standard: %s\n", p); v4l_info(client, "Audio muted: %s\n", - (mute_ctl & 0x2) ? "yes" : "no"); + (state->unmute_volume >= 0) ? "yes" : "no"); v4l_info(client, "Audio microcontroller: %s\n", - (download_ctl & 0x10) ? "running" : "stopped"); + (download_ctl & 0x10) ? + ((mute_ctl & 0x2) ? "detecting" : "running") : "stopped"); switch (audio_config >> 4) { case 0x00: p = "undefined"; break; diff --git a/drivers/media/video/cx25840/cx25840-core.h b/drivers/media/video/cx25840/cx25840-core.h index 8c1fbd9b87c..86e2edfc494 100644 --- a/drivers/media/video/cx25840/cx25840-core.h +++ b/drivers/media/video/cx25840/cx25840-core.h @@ -42,6 +42,7 @@ struct cx25840_state { enum cx25840_audio_input aud_input; u32 audclk_freq; int audmode; + int unmute_volume; /* -1 if not muted */ int vbi_line_offset; u32 id; u32 rev; -- cgit v1.2.3-70-g09d2 From 9085009683dd46d95105eda14efa8bda403b459f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 5 Aug 2007 08:02:45 -0300 Subject: V4L/DVB (5998): ivtv: no need to mute the audio input When changing channels the audio has to be muted. This is done by calling CX2341X_ENC_MUTE_AUDIO and by muted the audio input. The latter is not necessary and is now removed. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-fileops.c | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index fedddecf661..9e867b5229d 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -924,21 +924,13 @@ int ivtv_v4l2_open(struct inode *inode, struct file *filp) void ivtv_mute(struct ivtv *itv) { - struct v4l2_control ctrl = { V4L2_CID_AUDIO_MUTE, 1 }; - - /* Mute sound to avoid pop */ - ivtv_control_ioctls(itv, VIDIOC_S_CTRL, &ctrl); - if (atomic_read(&itv->capturing)) ivtv_vapi(itv, CX2341X_ENC_MUTE_AUDIO, 1, 1); - IVTV_DEBUG_INFO("Mute\n"); } void ivtv_unmute(struct ivtv *itv) { - struct v4l2_control ctrl = { V4L2_CID_AUDIO_MUTE, 0 }; - /* initialize or refresh input */ if (atomic_read(&itv->capturing) == 0) ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0); @@ -949,8 +941,5 @@ void ivtv_unmute(struct ivtv *itv) ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12); ivtv_vapi(itv, CX2341X_ENC_MUTE_AUDIO, 1, 0); } - - /* Unmute */ - ivtv_control_ioctls(itv, VIDIOC_S_CTRL, &ctrl); IVTV_DEBUG_INFO("Unmute\n"); } -- cgit v1.2.3-70-g09d2 From 39c4ad6ab364354bf76cdcc0081fa5c4422db907 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 5 Aug 2007 14:24:17 -0300 Subject: V4L/DVB (5999): cx25840: add radio support. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx25840/cx25840-core.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 65ad7943dd9..8f9c32613b4 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -251,7 +251,11 @@ static void input_change(struct i2c_client *client) cx25840_and_or(client, 0x401, ~0x60, 0); cx25840_and_or(client, 0x401, ~0x60, 0x60); - if (std & V4L2_STD_525_60) { + if (state->radio) { + cx25840_write(client, 0x808, 0xf9); + cx25840_write(client, 0x80b, 0x00); + } + else if (std & V4L2_STD_525_60) { /* Certain Hauppauge PVR150 models have a hardware bug that causes audio to drop out. For these models the audio standard must be set explicitly. -- cgit v1.2.3-70-g09d2 From 6af5a0394ae9ce7ac8eea233a8c430d743a377c3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 7 Aug 2007 07:19:33 -0300 Subject: V4L/DVB (6002): ivtv: remove unused struct field. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.h | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 4a7b23b9f22..0a1c16ad10b 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -651,7 +651,6 @@ struct vbi_info { struct v4l2_format in; /* convenience pointer to sliced struct in vbi_in union */ struct v4l2_sliced_vbi_format *sliced_in; - u32 service_set_in; int insert_mpeg; /* Buffer for the maximum of 2 * 18 * packet_size sliced VBI lines. -- cgit v1.2.3-70-g09d2 From be848fe39a656fd57429263f5ac8c656ccdff362 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 9 Aug 2007 17:13:22 -0300 Subject: V4L/DVB (6003): vp27smpx: correctly attribute the origin of the driver Correctly attribute the origin of the driver to Kazuhiko Kawakami. It took some time to get the S-O-B line from the original tvaudio patch author, but here it is. Signed-off-by: Kazuhiko Kawakami Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vp27smpx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/vp27smpx.c b/drivers/media/video/vp27smpx.c index 9aa526bd2c8..8a81fcd13ae 100644 --- a/drivers/media/video/vp27smpx.c +++ b/drivers/media/video/vp27smpx.c @@ -3,7 +3,7 @@ * * Copyright (C) 2007 Hans Verkuil * - * Special thanks to Kazz for the i2c data. + * Based on a tvaudio patch from Kazuhiko Kawakami * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by -- cgit v1.2.3-70-g09d2 From afa76b392e10d37c9e717198b5c2686de26c629d Mon Sep 17 00:00:00 2001 From: Rolf Eike Beer Date: Mon, 13 Aug 2007 08:08:21 -0300 Subject: V4L/DVB (6005): Initialize filp->private_data only once in em28xx_v4l2_open Some lines later filp->private_data is initialized to dev again. Since there are some checks that might fail in the mean time keep the later version. Signed-off-by: Rolf Eike Beer Signed-off-by: Andrew Morton Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-video.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 40307f3f6fe..e4fba906833 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -268,8 +268,6 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) if (NULL == dev) return -ENODEV; - filp->private_data=dev; - em28xx_videodbg("open minor=%d type=%s users=%d\n", minor,v4l2_type_names[dev->type],dev->users); -- cgit v1.2.3-70-g09d2 From 6b1dde90de7f612805fbe8212a39264d7b868efc Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 11 Aug 2007 15:42:12 -0300 Subject: V4L/DVB (6006): tuner: move last_div to tuner-simple private data tuner-simple is the only sub-driver that uses last_div, so we can free up two bytes of memory for all other tuners, by moving this into tuner-simple's private data area. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-driver.h | 1 - drivers/media/video/tuner-simple.c | 29 +++++++++++++++++++++++++---- 2 files changed, 25 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index 0334a912507..fa51b7cec69 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -49,7 +49,6 @@ struct tuner { unsigned int tv_freq; /* keep track of the current settings */ unsigned int radio_freq; - u16 last_div; unsigned int audmode; v4l2_std_id std; diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index 10a7d36a264..572f22423b9 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -82,6 +82,10 @@ MODULE_PARM_DESC(offset,"Allows to specify an offset for tuner"); #define TUNER_PLL_LOCKED 0x40 #define TUNER_STEREO_MK3 0x04 +struct tuner_simple_priv { + u16 last_div; +}; + /* ---------------------------------------------------------------------- */ static int tuner_getstatus(struct i2c_client *c) @@ -126,6 +130,7 @@ static int tuner_stereo(struct i2c_client *c) static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) { struct tuner *t = i2c_get_clientdata(c); + struct tuner_simple_priv *priv = t->priv; u8 config, cb, tuneraddr; u16 div; struct tunertype *tun; @@ -291,7 +296,7 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) break; } - if (params->cb_first_if_lower_freq && div < t->last_div) { + if (params->cb_first_if_lower_freq && div < priv->last_div) { buffer[0] = config; buffer[1] = cb; buffer[2] = (div>>8) & 0x7f; @@ -302,7 +307,7 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) buffer[2] = config; buffer[3] = cb; } - t->last_div = div; + priv->last_div = div; if (params->has_tda9887) { int config = 0; int is_secam_l = (t->std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)) && @@ -399,6 +404,7 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq) { struct tunertype *tun; struct tuner *t = i2c_get_clientdata(c); + struct tuner_simple_priv *priv = t->priv; u8 buffer[4]; u16 div; int rc, j; @@ -464,7 +470,7 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq) freq * (1/800) */ div = (freq + 400) / 800; - if (params->cb_first_if_lower_freq && div < t->last_div) { + if (params->cb_first_if_lower_freq && div < priv->last_div) { buffer[0] = buffer[2]; buffer[1] = buffer[3]; buffer[2] = (div>>8) & 0x7f; @@ -476,7 +482,7 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq) tuner_dbg("radio 0x%02x 0x%02x 0x%02x 0x%02x\n", buffer[0],buffer[1],buffer[2],buffer[3]); - t->last_div = div; + priv->last_div = div; if (params->has_tda9887) { int config = 0; @@ -498,16 +504,31 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq) tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc); } +static void tuner_release(struct i2c_client *c) +{ + struct tuner *t = i2c_get_clientdata(c); + + kfree(t->priv); + t->priv = NULL; +} + static struct tuner_operations simple_tuner_ops = { .set_tv_freq = default_set_tv_freq, .set_radio_freq = default_set_radio_freq, .has_signal = tuner_signal, .is_stereo = tuner_stereo, + .release = tuner_release, }; int default_tuner_init(struct i2c_client *c) { struct tuner *t = i2c_get_clientdata(c); + struct tuner_simple_priv *priv = NULL; + + priv = kzalloc(sizeof(struct tuner_simple_priv), GFP_KERNEL); + if (priv == NULL) + return -ENOMEM; + t->priv = priv; tuner_info("type set to %d (%s)\n", t->type, tuners[t->type].name); -- cgit v1.2.3-70-g09d2 From fbd8af07063f7379e71654013e7915315cd869f8 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Wed, 15 Aug 2007 10:43:08 -0300 Subject: V4L/DVB (6009): Bt8xx: "extern inline" -> "static inline" "extern inline" will have different semantics with gcc 4.3. Signed-off-by: Adrian Bunk Signed-off-by: Manu Abraham Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/bt8xx/bt878.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/bt8xx/bt878.h b/drivers/media/dvb/bt8xx/bt878.h index f685bc12960..1c8e3366000 100644 --- a/drivers/media/dvb/bt8xx/bt878.h +++ b/drivers/media/dvb/bt8xx/bt878.h @@ -149,7 +149,7 @@ void bt878_start(struct bt878 *bt, u32 controlreg, u32 op_sync_orin, void bt878_stop(struct bt878 *bt); #if defined(__powerpc__) /* big-endian */ -extern __inline__ void io_st_le32(volatile unsigned __iomem *addr, unsigned val) +static inline void io_st_le32(volatile unsigned __iomem *addr, unsigned val) { __asm__ __volatile__("stwbrx %1,0,%2":"=m"(*addr):"r"(val), "r"(addr)); -- cgit v1.2.3-70-g09d2 From e9f668dd12d3ed293af0d466bcaa393b78a7d0ee Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Wed, 15 Aug 2007 10:43:19 -0300 Subject: V4L/DVB (6010): Use inline functions instead of inline asm for powerpc Change io_st_le32() to use inline functions rather than direct inline assembly code. Signed-off-by: Kumar Gala Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/bt8xx/bt878.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/bt8xx/bt878.h b/drivers/media/dvb/bt8xx/bt878.h index 1c8e3366000..d593bc14562 100644 --- a/drivers/media/dvb/bt8xx/bt878.h +++ b/drivers/media/dvb/bt8xx/bt878.h @@ -151,9 +151,8 @@ void bt878_stop(struct bt878 *bt); #if defined(__powerpc__) /* big-endian */ static inline void io_st_le32(volatile unsigned __iomem *addr, unsigned val) { - __asm__ __volatile__("stwbrx %1,0,%2":"=m"(*addr):"r"(val), - "r"(addr)); - __asm__ __volatile__("eieio":::"memory"); + st_le32(addr, val); + eieio(); } #define bmtwrite(dat,adr) io_st_le32((adr),(dat)) -- cgit v1.2.3-70-g09d2 From acb09af4e333dc92cdd32ae75ee7e5f3d7aaf60b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 29 Jul 2007 22:56:11 -0300 Subject: V4L/DVB (6014): vivi: use videobuf_read_stream() videobuf_read_stream is more efficient than videobuf_read_one Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vivi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index f6d3a9460cc..c10169e3575 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -1123,7 +1123,7 @@ vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos) if (fh->type==V4L2_BUF_TYPE_VIDEO_CAPTURE) { if (res_locked(fh->dev)) return -EBUSY; - return videobuf_read_one(&fh->vb_vidq, data, count, ppos, + return videobuf_read_stream(&fh->vb_vidq, data, count, ppos, 0, file->f_flags & O_NONBLOCK); } return 0; -- cgit v1.2.3-70-g09d2 From 5f553388b06532b495681f5d6c8e8fbff64ea86a Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Wed, 15 Aug 2007 14:00:09 -0300 Subject: V4L/DVB (6015): DVB: convert struct class_device to struct device The currently used "struct class_device" will be removed from the kernel. Here is a trivial patch that converts DVB to use struct device. Signed-off-by: Kay Sievers Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvbdev.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c index 9ef0c00605e..0f18ce8a939 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.c +++ b/drivers/media/dvb/dvb-core/dvbdev.c @@ -200,7 +200,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, { struct dvb_device *dvbdev; struct file_operations *dvbdevfops; - struct class_device *clsdev; + struct device *clsdev; int id; mutex_lock(&dvbdev_register_lock); @@ -242,10 +242,9 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, mutex_unlock(&dvbdev_register_lock); - clsdev = class_device_create(dvb_class, NULL, MKDEV(DVB_MAJOR, - nums2minor(adap->num, type, id)), - adap->device, "dvb%d.%s%d", adap->num, - dnames[type], id); + clsdev = device_create(dvb_class, adap->device, + MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)), + "dvb%d.%s%d", adap->num, dnames[type], id); if (IS_ERR(clsdev)) { printk(KERN_ERR "%s: failed to create device dvb%d.%s%d (%ld)\n", __FUNCTION__, adap->num, dnames[type], id, PTR_ERR(clsdev)); @@ -266,8 +265,8 @@ void dvb_unregister_device(struct dvb_device *dvbdev) if (!dvbdev) return; - class_device_destroy(dvb_class, MKDEV(DVB_MAJOR, nums2minor(dvbdev->adapter->num, - dvbdev->type, dvbdev->id))); + device_destroy(dvb_class, MKDEV(DVB_MAJOR, nums2minor(dvbdev->adapter->num, + dvbdev->type, dvbdev->id))); list_del (&dvbdev->list_head); kfree (dvbdev->fops); -- cgit v1.2.3-70-g09d2 From c252b0511596f76a32c7c64bcc6cc60b3bc1ec3a Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Mon, 13 Aug 2007 12:21:57 -0300 Subject: V4L/DVB (6019): cx88: Make card database more memory efficient The vmux setting is only two bits, but was taking up a whole 32 in the input description struct. By changing it to a two-bit bitfield, it can fit in what was padding space before and drop the input size by 4 bytes, from 28 to 24. This drops the board description struct, which has 9 inputs, from 280 to 244 bytes. Total driver size decreases by 2108 bytes. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index 809126866a3..78486f90327 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -226,8 +226,8 @@ enum cx88_itype { struct cx88_input { enum cx88_itype type; - unsigned int vmux; u32 gpio0, gpio1, gpio2, gpio3; + unsigned int vmux:2; unsigned int extadc:1; }; -- cgit v1.2.3-70-g09d2 From b09a79f5848f2143a8ffc724910743027d5a70e0 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Mon, 13 Aug 2007 12:21:58 -0300 Subject: V4L/DVB (6020): cx88: Fix use of uninitialized variable An error message for PCI resource allocation failure used the board type before it was set. Just get rid of the error message, as get_ressources() [sic] already prints one. Format that error message better, and add the pci function and subsystem information to better associate the error with what caused it. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-core.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index f31ec96924b..055264b9cd6 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -1077,8 +1077,11 @@ static int get_ressources(struct cx88_core *core, struct pci_dev *pci) pci_resource_len(pci,0), core->name)) return 0; - printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx\n", - core->name,(unsigned long long)pci_resource_start(pci,0)); + printk(KERN_ERR + "%s/%d: Can't get MMIO memory @ 0x%llx, subsystem: %04x:%04x\n", + core->name, PCI_FUNC(pci->devfn), + (unsigned long long)pci_resource_start(pci, 0), + pci->subsystem_vendor, pci->subsystem_device); return -EBUSY; } @@ -1115,12 +1118,6 @@ struct cx88_core* cx88_core_get(struct pci_dev *pci) core->nr = cx88_devcount++; sprintf(core->name,"cx88[%d]",core->nr); if (0 != get_ressources(core,pci)) { - printk(KERN_ERR "CORE %s No more PCI ressources for " - "subsystem: %04x:%04x, board: %s\n", - core->name,pci->subsystem_vendor, - pci->subsystem_device, - cx88_boards[core->board].name); - cx88_devcount--; goto fail_free; } -- cgit v1.2.3-70-g09d2 From 6a59d64c5cc302e0139ddb1f5e57afceecb14368 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Wed, 15 Aug 2007 14:41:57 -0300 Subject: V4L/DVB (6021): cx88: Copy board information into card state The cx88 driver state stored the ID of the board type in core->board. Every time the driver need to get some information about the board configuration, it uses the board number as an index into board configuration array. This patch changes it so that the board number is in core->boardnr, and core->board is a copy of the board configuration information. This allows access to board information without the extra indirection. e.g. cx88_boards[core->board].mpeg becomes core->board.mpeg. This has a number of advantages: - The code is simpler to write. - It compiles to be smaller and faster, without needing the extra array lookup to get at the board information. - The cx88_boards array no longer needs to be exported to all cx88 modules. - The boards array can be made const - It should be possible to avoid keeping the (large) cx88_boards array around after the module is loaded. - If module parameters or eeprom info override some board configuration setting, it's not necessary to modify the boards array, which would affect all boards of the same type. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-blackbird.c | 18 ++++----- drivers/media/video/cx88/cx88-cards.c | 27 ++++++------- drivers/media/video/cx88/cx88-core.c | 45 ++++++++++----------- drivers/media/video/cx88/cx88-dvb.c | 10 ++--- drivers/media/video/cx88/cx88-i2c.c | 24 ++++++------ drivers/media/video/cx88/cx88-input.c | 11 +++--- drivers/media/video/cx88/cx88-mpeg.c | 22 +++++------ drivers/media/video/cx88/cx88-tvaudio.c | 4 +- drivers/media/video/cx88/cx88-video.c | 63 ++++++++++++++---------------- drivers/media/video/cx88/cx88-vp3054-i2c.c | 4 +- drivers/media/video/cx88/cx88.h | 13 ++---- 11 files changed, 112 insertions(+), 129 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index f2fcdb92ecc..74e3eb94575 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -734,14 +734,14 @@ static int vidioc_querycap (struct file *file, void *priv, struct cx88_core *core = dev->core; strcpy(cap->driver, "cx88_blackbird"); - strlcpy(cap->card, cx88_boards[core->board].name,sizeof(cap->card)); + strlcpy(cap->card, core->board.name, sizeof(cap->card)); sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); cap->version = CX88_VERSION_CODE; cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; - if (UNSET != core->tuner_type) + if (UNSET != core->board.tuner_type) cap->capabilities |= V4L2_CAP_TUNER; return 0; } @@ -990,7 +990,7 @@ static int vidioc_g_frequency (struct file *file, void *priv, struct cx8802_fh *fh = priv; struct cx88_core *core = fh->dev->core; - if (unlikely(UNSET == core->tuner_type)) + if (unlikely(UNSET == core->board.tuner_type)) return -EINVAL; f->type = V4L2_TUNER_ANALOG_TV; @@ -1028,7 +1028,7 @@ static int vidioc_g_tuner (struct file *file, void *priv, struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core; u32 reg; - if (unlikely(UNSET == core->tuner_type)) + if (unlikely(UNSET == core->board.tuner_type)) return -EINVAL; if (0 != t->index) return -EINVAL; @@ -1049,7 +1049,7 @@ static int vidioc_s_tuner (struct file *file, void *priv, { struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core; - if (UNSET == core->tuner_type) + if (UNSET == core->board.tuner_type) return -EINVAL; if (0 != t->index) return -EINVAL; @@ -1246,7 +1246,7 @@ static int cx8802_blackbird_advise_acquire(struct cx8802_driver *drv) struct cx88_core *core = drv->core; int err = 0; - switch (core->board) { + switch (core->boardnr) { case CX88_BOARD_HAUPPAUGE_HVR1300: /* By default, core setup will leave the cx22702 out of reset, on the bus. * We left the hardware on power up with the cx22702 active. @@ -1268,7 +1268,7 @@ static int cx8802_blackbird_advise_release(struct cx8802_driver *drv) struct cx88_core *core = drv->core; int err = 0; - switch (core->board) { + switch (core->boardnr) { case CX88_BOARD_HAUPPAUGE_HVR1300: /* Exit leaving the cx23416 on the bus */ break; @@ -1316,13 +1316,13 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv) dprintk( 1, "%s\n", __FUNCTION__); dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n", - core->board, + core->boardnr, core->name, core->pci_bus, core->pci_slot); err = -ENODEV; - if (!(cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD)) + if (!(core->board.mpeg & CX88_MPEG_BLACKBIRD)) goto fail_core; dev->width = 720; diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index 1fc71a78b92..8be90ad4e91 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -30,7 +30,7 @@ /* ------------------------------------------------------------------ */ /* board config info */ -struct cx88_board cx88_boards[] = { +const struct cx88_board cx88_boards[] = { [CX88_BOARD_UNKNOWN] = { .name = "UNKNOWN/GENERIC", .tuner_type = UNSET, @@ -1687,12 +1687,12 @@ static void leadtek_eeprom(struct cx88_core *core, u8 *eeprom_data) return; } - core->has_radio = 1; - core->tuner_type = (eeprom_data[6] == 0x13) ? 43 : 38; + core->board.tuner_type = (eeprom_data[6] == 0x13) ? + TUNER_PHILIPS_FM1236_MK3 : TUNER_PHILIPS_FM1216ME_MK3; printk(KERN_INFO "%s: Leadtek Winfast 2000XP Expert config: " "tuner=%d, eeprom[0]=0x%02x\n", - core->name, core->tuner_type, eeprom_data[0]); + core->name, core->board.tuner_type, eeprom_data[0]); } static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data) @@ -1700,9 +1700,9 @@ static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data) struct tveeprom tv; tveeprom_hauppauge_analog(&core->i2c_client, &tv, eeprom_data); - core->tuner_type = tv.tuner_type; + core->board.tuner_type = tv.tuner_type; core->tuner_formats = tv.tuner_formats; - core->has_radio = tv.has_radio; + core->board.radio.type = tv.has_radio ? CX88_RADIO : 0; /* Make sure we support the board model */ switch (tv.model) @@ -1792,8 +1792,9 @@ static void gdi_eeprom(struct cx88_core *core, u8 *eeprom_data) name ? name : "unknown"); if (NULL == name) return; - core->tuner_type = gdi_tuner[eeprom_data[0x0d]].id; - core->has_radio = gdi_tuner[eeprom_data[0x0d]].fm; + core->board.tuner_type = gdi_tuner[eeprom_data[0x0d]].id; + core->board.radio.type = gdi_tuner[eeprom_data[0x0d]].fm ? + CX88_RADIO : 0; } /* ----------------------------------------------------------------------- */ @@ -1860,7 +1861,7 @@ void cx88_card_list(struct cx88_core *core, struct pci_dev *pci) void cx88_card_setup_pre_i2c(struct cx88_core *core) { - switch (core->board) { + switch (core->boardnr) { case CX88_BOARD_HAUPPAUGE_HVR1300: /* Bring the 702 demod up before i2c scanning/attach or devices are hidden */ /* We leave here with the 702 on the bus */ @@ -1883,7 +1884,7 @@ void cx88_card_setup(struct cx88_core *core) tveeprom_read(&core->i2c_client,eeprom,sizeof(eeprom)); } - switch (core->board) { + switch (core->boardnr) { case CX88_BOARD_HAUPPAUGE: case CX88_BOARD_HAUPPAUGE_ROSLYN: if (0 == core->i2c_rc) @@ -1927,7 +1928,7 @@ void cx88_card_setup(struct cx88_core *core) msleep(1); cx_set(MO_GP0_IO, 0x00000101); if (0 == core->i2c_rc && - core->board == CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID) + core->boardnr == CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID) dvico_fusionhdtv_hybrid_init(core); break; case CX88_BOARD_KWORLD_DVB_T: @@ -1965,14 +1966,10 @@ void cx88_card_setup(struct cx88_core *core) } break; } - if (cx88_boards[core->board].radio.type == CX88_RADIO) - core->has_radio = 1; } /* ------------------------------------------------------------------ */ -EXPORT_SYMBOL(cx88_boards); - /* * Local variables: * c-basic-offset: 8 diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index 055264b9cd6..ece788bd3d5 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -738,7 +738,7 @@ int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int heig value |= (1 << 15); value |= (1 << 16); } - if (INPUT(core->input)->type == CX88_VMUX_SVIDEO) + if (INPUT(core->input).type == CX88_VMUX_SVIDEO) value |= (1 << 13) | (1 << 5); if (V4L2_FIELD_INTERLACED == field) value |= (1 << 3); // VINT (interlaced vertical scaling) @@ -833,7 +833,7 @@ static int set_tvaudio(struct cx88_core *core) { v4l2_std_id norm = core->tvnorm; - if (CX88_VMUX_TELEVISION != INPUT(core->input)->type) + if (CX88_VMUX_TELEVISION != INPUT(core->input).type) return 0; if (V4L2_STD_PAL_BG & norm) { @@ -1067,7 +1067,7 @@ struct video_device *cx88_vdev_init(struct cx88_core *core, vfd->dev = &pci->dev; vfd->release = video_device_release; snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", - core->name, type, cx88_boards[core->board].name); + core->name, type, core->board.name); return vfd; } @@ -1130,39 +1130,34 @@ struct cx88_core* cx88_core_get(struct pci_dev *pci) core->bmmio = (u8 __iomem *)core->lmmio; /* board config */ - core->board = UNSET; + core->boardnr = UNSET; if (card[core->nr] < cx88_bcount) - core->board = card[core->nr]; - for (i = 0; UNSET == core->board && i < cx88_idcount; i++) + core->boardnr = card[core->nr]; + for (i = 0; UNSET == core->boardnr && i < cx88_idcount; i++) if (pci->subsystem_vendor == cx88_subids[i].subvendor && pci->subsystem_device == cx88_subids[i].subdevice) - core->board = cx88_subids[i].card; - if (UNSET == core->board) { - core->board = CX88_BOARD_UNKNOWN; + core->boardnr = cx88_subids[i].card; + if (UNSET == core->boardnr) { + core->boardnr = CX88_BOARD_UNKNOWN; cx88_card_list(core,pci); } + + memcpy(&core->board, &cx88_boards[core->boardnr], sizeof(core->board)); + printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", core->name,pci->subsystem_vendor, - pci->subsystem_device,cx88_boards[core->board].name, - core->board, card[core->nr] == core->board ? + pci->subsystem_device, core->board.name, + core->boardnr, card[core->nr] == core->boardnr ? "insmod option" : "autodetected"); - core->tuner_type = tuner[core->nr]; - core->radio_type = radio[core->nr]; - if (UNSET == core->tuner_type) - core->tuner_type = cx88_boards[core->board].tuner_type; - if (UNSET == core->radio_type) - core->radio_type = cx88_boards[core->board].radio_type; - if (!core->tuner_addr) - core->tuner_addr = cx88_boards[core->board].tuner_addr; - if (!core->radio_addr) - core->radio_addr = cx88_boards[core->board].radio_addr; + if (tuner[core->nr] != UNSET) + core->board.tuner_type = tuner[core->nr]; + if (radio[core->nr] != UNSET) + core->board.radio_type = radio[core->nr]; printk(KERN_INFO "TV tuner %d at 0x%02x, Radio tuner %d at 0x%02x\n", - core->tuner_type, core->tuner_addr<<1, - core->radio_type, core->radio_addr<<1); - - core->tda9887_conf = cx88_boards[core->board].tda9887_conf; + core->board.tuner_type, core->board.tuner_addr<<1, + core->board.radio_type, core->board.radio_addr<<1); /* init hardware */ cx88_reset(core); diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index 1773b40467d..d98b9072101 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -378,7 +378,7 @@ static int dvb_register(struct cx8802_dev *dev) dev->ts_gen_cntrl = 0x0c; /* init frontend */ - switch (dev->core->board) { + switch (dev->core->boardnr) { case CX88_BOARD_HAUPPAUGE_DVB_T1: dev->dvb.frontend = dvb_attach(cx22702_attach, &connexant_refboard_config, @@ -653,7 +653,7 @@ static int cx8802_dvb_advise_acquire(struct cx8802_driver *drv) int err = 0; dprintk( 1, "%s\n", __FUNCTION__); - switch (core->board) { + switch (core->boardnr) { case CX88_BOARD_HAUPPAUGE_HVR1300: /* We arrive here with either the cx23416 or the cx22702 * on the bus. Take the bus from the cx23416 and enable the @@ -676,7 +676,7 @@ static int cx8802_dvb_advise_release(struct cx8802_driver *drv) int err = 0; dprintk( 1, "%s\n", __FUNCTION__); - switch (core->board) { + switch (core->boardnr) { case CX88_BOARD_HAUPPAUGE_HVR1300: /* Do Nothing, leave the cx22702 on the bus. */ break; @@ -694,13 +694,13 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv) dprintk( 1, "%s\n", __FUNCTION__); dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n", - core->board, + core->boardnr, core->name, core->pci_bus, core->pci_slot); err = -ENODEV; - if (!(cx88_boards[core->board].mpeg & CX88_MPEG_DVB)) + if (!(core->board.mpeg & CX88_MPEG_DVB)) goto fail_core; /* If vp3054 isn't enabled, a stub will just return 0 */ diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c index 78bbcfab967..6b42dea860f 100644 --- a/drivers/media/video/cx88/cx88-i2c.c +++ b/drivers/media/video/cx88/cx88-i2c.c @@ -108,28 +108,28 @@ static int attach_inform(struct i2c_client *client) if (!client->driver->command) return 0; - if (core->radio_type != UNSET) { - if ((core->radio_addr==ADDR_UNSET)||(core->radio_addr==client->addr)) { + if (core->board.radio_type != UNSET) { + if ((core->board.radio_addr==ADDR_UNSET)||(core->board.radio_addr==client->addr)) { tun_setup.mode_mask = T_RADIO; - tun_setup.type = core->radio_type; - tun_setup.addr = core->radio_addr; + tun_setup.type = core->board.radio_type; + tun_setup.addr = core->board.radio_addr; client->driver->command (client, TUNER_SET_TYPE_ADDR, &tun_setup); } } - if (core->tuner_type != UNSET) { - if ((core->tuner_addr==ADDR_UNSET)||(core->tuner_addr==client->addr)) { + if (core->board.tuner_type != UNSET) { + if ((core->board.tuner_addr==ADDR_UNSET)||(core->board.tuner_addr==client->addr)) { tun_setup.mode_mask = T_ANALOG_TV; - tun_setup.type = core->tuner_type; - tun_setup.addr = core->tuner_addr; + tun_setup.type = core->board.tuner_type; + tun_setup.addr = core->board.tuner_addr; client->driver->command (client,TUNER_SET_TYPE_ADDR, &tun_setup); } } - if (core->tda9887_conf) - client->driver->command(client, TDA9887_SET_CONFIG, &core->tda9887_conf); + if (core->board.tda9887_conf) + client->driver->command(client, TDA9887_SET_CONFIG, &core->board.tda9887_conf); return 0; } @@ -204,9 +204,9 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci) memcpy(&core->i2c_algo, &cx8800_i2c_algo_template, sizeof(core->i2c_algo)); - if (core->tuner_type != TUNER_ABSENT) + if (core->board.tuner_type != TUNER_ABSENT) core->i2c_adap.class |= I2C_CLASS_TV_ANALOG; - if (cx88_boards[core->board].mpeg & CX88_MPEG_DVB) + if (core->board.mpeg & CX88_MPEG_DVB) core->i2c_adap.class |= I2C_CLASS_TV_DIGITAL; core->i2c_adap.dev.parent = &pci->dev; diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index f5d4a565346..120f56857f0 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -74,7 +74,7 @@ static void cx88_ir_handle_key(struct cx88_IR *ir) /* read gpio value */ gpio = cx_read(ir->gpio_addr); - switch (core->board) { + switch (core->boardnr) { case CX88_BOARD_NPGTECH_REALTV_TOP10FM: /* This board apparently uses a combination of 2 GPIO to represent the keys. Additionally, the second GPIO @@ -113,7 +113,7 @@ static void cx88_ir_handle_key(struct cx88_IR *ir) (gpio & ir->mask_keydown) ? " down" : "", (gpio & ir->mask_keyup) ? " up" : ""); - if (ir->core->board == CX88_BOARD_NORWOOD_MICRO) { + if (ir->core->boardnr == CX88_BOARD_NORWOOD_MICRO) { u32 gpio_key = cx_read(MO_GP0_IO); data = (data << 4) | ((gpio_key & 0xf0) >> 4); @@ -204,7 +204,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) ir->input = input_dev; /* detect & configure */ - switch (core->board) { + switch (core->boardnr) { case CX88_BOARD_DNTV_LIVE_DVB_T: case CX88_BOARD_KWORLD_DVB_T: case CX88_BOARD_KWORLD_DVB_T_CX22702: @@ -314,8 +314,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) } /* init input device */ - snprintf(ir->name, sizeof(ir->name), "cx88 IR (%s)", - cx88_boards[core->board].name); + snprintf(ir->name, sizeof(ir->name), "cx88 IR (%s)", core->board.name); snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(pci)); ir_input_init(input_dev, &ir->ir, ir_type, ir_codes); @@ -406,7 +405,7 @@ void cx88_ir_irq(struct cx88_core *core) ir_dump_samples(ir->samples, ir->scount); /* decode it */ - switch (core->board) { + switch (core->boardnr) { case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1: case CX88_BOARD_DNTV_LIVE_DVB_T_PRO: ircode = ir_decode_pulsedistance(ir->samples, ir->scount, 1, 4); diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index c34158d9dcc..1df245ace2d 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -55,9 +55,9 @@ static void request_module_async(struct work_struct *work) { struct cx8802_dev *dev=container_of(work, struct cx8802_dev, request_module_wk); - if (cx88_boards[dev->core->board].mpeg & CX88_MPEG_DVB) + if (dev->core->board.mpeg & CX88_MPEG_DVB) request_module("cx88-dvb"); - if (cx88_boards[dev->core->board].mpeg & CX88_MPEG_BLACKBIRD) + if (dev->core->board.mpeg & CX88_MPEG_BLACKBIRD) request_module("cx88-blackbird"); } @@ -95,7 +95,7 @@ static int cx8802_start_dma(struct cx8802_dev *dev, dprintk( 1, "core->active_type_id = 0x%08x\n", core->active_type_id); if ( (core->active_type_id == CX88_MPEG_DVB) && - (cx88_boards[core->board].mpeg & CX88_MPEG_DVB) ) { + (core->board.mpeg & CX88_MPEG_DVB) ) { dprintk( 1, "cx8802_start_dma doing .dvb\n"); /* negedge driven & software reset */ @@ -103,7 +103,7 @@ static int cx8802_start_dma(struct cx8802_dev *dev, udelay(100); cx_write(MO_PINMUX_IO, 0x00); cx_write(TS_HW_SOP_CNTRL,0x47<<16|188<<4|0x01); - switch (core->board) { + switch (core->boardnr) { case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q: case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T: case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD: @@ -124,7 +124,7 @@ static int cx8802_start_dma(struct cx8802_dev *dev, cx_write(TS_GEN_CNTRL, dev->ts_gen_cntrl); udelay(100); } else if ( (core->active_type_id == CX88_MPEG_BLACKBIRD) && - (cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD) ) { + (core->board.mpeg & CX88_MPEG_BLACKBIRD) ) { dprintk( 1, "cx8802_start_dma doing .blackbird\n"); cx_write(MO_PINMUX_IO, 0x88); /* enable MPEG parallel IO */ @@ -138,7 +138,7 @@ static int cx8802_start_dma(struct cx8802_dev *dev, udelay(100); } else { printk( "%s() Failed. Unsupported value in .mpeg (0x%08x)\n", __FUNCTION__, - cx88_boards[core->board].mpeg ); + core->board.mpeg ); return -EINVAL; } @@ -689,8 +689,8 @@ int cx8802_register_driver(struct cx8802_driver *drv) printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d]\n", h->core->name,h->pci->subsystem_vendor, - h->pci->subsystem_device,cx88_boards[h->core->board].name, - h->core->board); + h->pci->subsystem_device,h->core->board.name, + h->core->boardnr); /* Bring up a new struct for each driver instance */ driver = kzalloc(sizeof(*drv),GFP_KERNEL); @@ -741,8 +741,8 @@ int cx8802_unregister_driver(struct cx8802_driver *drv) printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d]\n", h->core->name,h->pci->subsystem_vendor, - h->pci->subsystem_device,cx88_boards[h->core->board].name, - h->core->board); + h->pci->subsystem_device,h->core->board.name, + h->core->boardnr); list_for_each_safe(list2, q, &h->drvlist.devlist) { d = list_entry(list2, struct cx8802_driver, devlist); @@ -782,7 +782,7 @@ static int __devinit cx8802_probe(struct pci_dev *pci_dev, printk("%s/2: cx2388x 8802 Driver Manager\n", core->name); err = -ENODEV; - if (!cx88_boards[core->board].mpeg) + if (!core->board.mpeg) goto fail_core; err = -ENOMEM; diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c index 1cc2d286a1c..99e120483ec 100644 --- a/drivers/media/video/cx88/cx88-tvaudio.c +++ b/drivers/media/video/cx88/cx88-tvaudio.c @@ -140,7 +140,7 @@ static void set_audio_finish(struct cx88_core *core, u32 ctl) cx_write(AUD_RATE_THRES_DMD, 0x000000C0); cx88_start_audio_dma(core); - if (cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD) { + if (core->board.mpeg & CX88_MPEG_BLACKBIRD) { cx_write(AUD_I2SINPUTCNTL, 4); cx_write(AUD_BAUDRATE, 1); /* 'pass-thru mode': this enables the i2s output to the mpeg encoder */ @@ -149,7 +149,7 @@ static void set_audio_finish(struct cx88_core *core, u32 ctl) cx_write(AUD_I2SCNTL, 0); /* cx_write(AUD_APB_IN_RATE_ADJ, 0); */ } - if ((always_analog) || (!(cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD))) { + if ((always_analog) || (!(core->board.mpeg & CX88_MPEG_BLACKBIRD))) { ctl |= EN_DAC_ENABLE; cx_write(AUD_CTL, ctl); } diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index 58ec76be436..b0dd4313a84 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -368,17 +368,17 @@ int cx88_video_mux(struct cx88_core *core, unsigned int input) /* struct cx88_core *core = dev->core; */ dprintk(1,"video_mux: %d [vmux=%d,gpio=0x%x,0x%x,0x%x,0x%x]\n", - input, INPUT(input)->vmux, - INPUT(input)->gpio0,INPUT(input)->gpio1, - INPUT(input)->gpio2,INPUT(input)->gpio3); + input, INPUT(input).vmux, + INPUT(input).gpio0,INPUT(input).gpio1, + INPUT(input).gpio2,INPUT(input).gpio3); core->input = input; - cx_andor(MO_INPUT_FORMAT, 0x03 << 14, INPUT(input)->vmux << 14); - cx_write(MO_GP3_IO, INPUT(input)->gpio3); - cx_write(MO_GP0_IO, INPUT(input)->gpio0); - cx_write(MO_GP1_IO, INPUT(input)->gpio1); - cx_write(MO_GP2_IO, INPUT(input)->gpio2); + cx_andor(MO_INPUT_FORMAT, 0x03 << 14, INPUT(input).vmux << 14); + cx_write(MO_GP3_IO, INPUT(input).gpio3); + cx_write(MO_GP0_IO, INPUT(input).gpio0); + cx_write(MO_GP1_IO, INPUT(input).gpio1); + cx_write(MO_GP2_IO, INPUT(input).gpio2); - switch (INPUT(input)->type) { + switch (INPUT(input).type) { case CX88_VMUX_SVIDEO: cx_set(MO_AFECFG_IO, 0x00000001); cx_set(MO_INPUT_FORMAT, 0x00010010); @@ -393,9 +393,9 @@ int cx88_video_mux(struct cx88_core *core, unsigned int input) break; } - if (cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD) { + if (core->board.mpeg & CX88_MPEG_BLACKBIRD) { /* sets sound input from external adc */ - if (INPUT(input)->extadc) + if (INPUT(input).extadc) cx_set(AUD_CTL, EN_I2SIN_ENABLE); else cx_clear(AUD_CTL, EN_I2SIN_ENABLE); @@ -767,12 +767,11 @@ static int video_open(struct inode *inode, struct file *file) fh); if (fh->radio) { - int board = core->board; dprintk(1,"video_open: setting radio device\n"); - cx_write(MO_GP3_IO, cx88_boards[board].radio.gpio3); - cx_write(MO_GP0_IO, cx88_boards[board].radio.gpio0); - cx_write(MO_GP1_IO, cx88_boards[board].radio.gpio1); - cx_write(MO_GP2_IO, cx88_boards[board].radio.gpio2); + cx_write(MO_GP3_IO, core->board.radio.gpio3); + cx_write(MO_GP0_IO, core->board.radio.gpio0); + cx_write(MO_GP1_IO, core->board.radio.gpio1); + cx_write(MO_GP2_IO, core->board.radio.gpio2); core->tvaudio = WW_FM; cx88_set_tvaudio(core); cx88_set_stereo(core,V4L2_TUNER_MODE_STEREO,1); @@ -1078,8 +1077,7 @@ static int vidioc_querycap (struct file *file, void *priv, struct cx88_core *core = dev->core; strcpy(cap->driver, "cx8800"); - strlcpy(cap->card, cx88_boards[core->board].name, - sizeof(cap->card)); + strlcpy(cap->card, core->board.name, sizeof(cap->card)); sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); cap->version = CX88_VERSION_CODE; cap->capabilities = @@ -1087,7 +1085,7 @@ static int vidioc_querycap (struct file *file, void *priv, V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | V4L2_CAP_VBI_CAPTURE; - if (UNSET != core->tuner_type) + if (UNSET != core->board.tuner_type) cap->capabilities |= V4L2_CAP_TUNER; return 0; } @@ -1221,14 +1219,14 @@ int cx88_enum_input (struct cx88_core *core,struct v4l2_input *i) n = i->index; if (n >= 4) return -EINVAL; - if (0 == INPUT(n)->type) + if (0 == INPUT(n).type) return -EINVAL; memset(i,0,sizeof(*i)); i->index = n; i->type = V4L2_INPUT_TYPE_CAMERA; - strcpy(i->name,iname[INPUT(n)->type]); - if ((CX88_VMUX_TELEVISION == INPUT(n)->type) || - (CX88_VMUX_CABLE == INPUT(n)->type)) + strcpy(i->name,iname[INPUT(n).type]); + if ((CX88_VMUX_TELEVISION == INPUT(n).type) || + (CX88_VMUX_CABLE == INPUT(n).type)) i->type = V4L2_INPUT_TYPE_TUNER; i->std = CX88_NORMS; return 0; @@ -1297,7 +1295,7 @@ static int vidioc_g_tuner (struct file *file, void *priv, struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; u32 reg; - if (unlikely(UNSET == core->tuner_type)) + if (unlikely(UNSET == core->board.tuner_type)) return -EINVAL; if (0 != t->index) return -EINVAL; @@ -1318,7 +1316,7 @@ static int vidioc_s_tuner (struct file *file, void *priv, { struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; - if (UNSET == core->tuner_type) + if (UNSET == core->board.tuner_type) return -EINVAL; if (0 != t->index) return -EINVAL; @@ -1333,7 +1331,7 @@ static int vidioc_g_frequency (struct file *file, void *priv, struct cx8800_fh *fh = priv; struct cx88_core *core = fh->dev->core; - if (unlikely(UNSET == core->tuner_type)) + if (unlikely(UNSET == core->board.tuner_type)) return -EINVAL; /* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */ @@ -1348,7 +1346,7 @@ static int vidioc_g_frequency (struct file *file, void *priv, int cx88_set_freq (struct cx88_core *core, struct v4l2_frequency *f) { - if (unlikely(UNSET == core->tuner_type)) + if (unlikely(UNSET == core->board.tuner_type)) return -EINVAL; if (unlikely(f->tuner != 0)) return -EINVAL; @@ -1419,8 +1417,7 @@ static int radio_querycap (struct file *file, void *priv, struct cx88_core *core = dev->core; strcpy(cap->driver, "cx8800"); - strlcpy(cap->card, cx88_boards[core->board].name, - sizeof(cap->card)); + strlcpy(cap->card, core->board.name, sizeof(cap->card)); sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci)); cap->version = CX88_VERSION_CODE; cap->capabilities = V4L2_CAP_TUNER; @@ -1828,10 +1825,10 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, cx_set(MO_PCI_INTMSK, core->pci_irqmask); /* load and configure helper modules */ - if (TUNER_ABSENT != core->tuner_type) + if (TUNER_ABSENT != core->board.tuner_type) request_module("tuner"); - if (cx88_boards[ core->board ].audio_chip == AUDIO_CHIP_WM8775) + if (core->board.audio_chip == AUDIO_CHIP_WM8775) request_module("wm8775"); /* register v4l devices */ @@ -1858,7 +1855,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, printk(KERN_INFO "%s/0: registered device vbi%d\n", core->name,dev->vbi_dev->minor & 0x1f); - if (core->has_radio) { + if (core->board.radio.type == CX88_RADIO) { dev->radio_dev = cx88_vdev_init(core,dev->pci, &cx8800_radio_template,"radio"); err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO, @@ -1884,7 +1881,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, mutex_unlock(&core->lock); /* start tvaudio thread */ - if (core->tuner_type != TUNER_ABSENT) { + if (core->board.tuner_type != TUNER_ABSENT) { core->kthread = kthread_run(cx88_audio_thread, core, "cx88 tvaudio"); if (IS_ERR(core->kthread)) { err = PTR_ERR(core->kthread); diff --git a/drivers/media/video/cx88/cx88-vp3054-i2c.c b/drivers/media/video/cx88/cx88-vp3054-i2c.c index cd0877636a3..f76ca9e2eeb 100644 --- a/drivers/media/video/cx88/cx88-vp3054-i2c.c +++ b/drivers/media/video/cx88/cx88-vp3054-i2c.c @@ -111,7 +111,7 @@ int vp3054_i2c_probe(struct cx8802_dev *dev) struct vp3054_i2c_state *vp3054_i2c; int rc; - if (core->board != CX88_BOARD_DNTV_LIVE_DVB_T_PRO) + if (core->boardnr != CX88_BOARD_DNTV_LIVE_DVB_T_PRO) return 0; dev->card_priv = kzalloc(sizeof(*vp3054_i2c), GFP_KERNEL); @@ -152,7 +152,7 @@ void vp3054_i2c_remove(struct cx8802_dev *dev) struct vp3054_i2c_state *vp3054_i2c = dev->card_priv; if (vp3054_i2c == NULL || - dev->core->board != CX88_BOARD_DNTV_LIVE_DVB_T_PRO) + dev->core->boardnr != CX88_BOARD_DNTV_LIVE_DVB_T_PRO) return; i2c_del_adapter(&vp3054_i2c->adap); diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index 78486f90327..3636ec26de5 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -250,7 +250,7 @@ struct cx88_subid { u32 card; }; -#define INPUT(nr) (&cx88_boards[core->board].input[nr]) +#define INPUT(nr) (core->board.input[nr]) /* ----------------------------------------------------------- */ /* device / file handle status */ @@ -304,13 +304,8 @@ struct cx88_core { u32 i2c_state, i2c_rc; /* config info -- analog */ - unsigned int board; - unsigned int tuner_type; - unsigned int radio_type; - unsigned char tuner_addr; - unsigned char radio_addr; - unsigned int tda9887_conf; - unsigned int has_radio; + unsigned int boardnr; + struct cx88_board board; /* Supported V4L _STD_ tuner formats */ unsigned int tuner_formats; @@ -585,7 +580,7 @@ extern void cx88_call_i2c_clients(struct cx88_core *core, /* ----------------------------------------------------------- */ /* cx88-cards.c */ -extern struct cx88_board cx88_boards[]; +extern const struct cx88_board cx88_boards[]; extern const unsigned int cx88_bcount; extern struct cx88_subid cx88_subids[]; -- cgit v1.2.3-70-g09d2 From bbc83597dfe3093b161014e6ebb351279eabaa7c Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Wed, 15 Aug 2007 14:41:58 -0300 Subject: V4L/DVB (6022): cx88: Move card core creation from cx88-core.c to cx88-cards.c A lot of code in cx88-cards.c was only used by cx88-core.c when the core state is first allocated and initialized. Moving that task to cx88-cards makes the driver simpler and the files more self contained. - Module parameters tuner, radio, card, and latency move to cx88-cards.c - cx88_boards is made static - cx88_subids is made static and const - cx88_bcount is eliminated - cx88_idcount is eliminated - cx88_card_list() is made static - cx88_card_setup_pre_i2c() is made static - cx88_card_setup() is made static - cx88_pci_quirks() is moved from cx88-core to cx88-cards The function argument "char *name" is made const too - get_ressources() is moved from cx88-core to cx88-cards, and renamed to cx88_get_resources() - The code to allocate and initialize the core state struct and the chip is moved out of cx88-core.c:cx88_get_core() and into a new function in cx88-cards.c, cx88_core_create(). This makes both functions simpler. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-cards.c | 168 ++++++++++++++++++++++++++++++++-- drivers/media/video/cx88/cx88-core.c | 163 ++------------------------------- drivers/media/video/cx88/cx88.h | 12 +-- 3 files changed, 172 insertions(+), 171 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index 8be90ad4e91..6204a453c11 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -27,10 +27,26 @@ #include "cx88.h" +static unsigned int tuner[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; +static unsigned int radio[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; +static unsigned int card[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; + +module_param_array(tuner, int, NULL, 0444); +module_param_array(radio, int, NULL, 0444); +module_param_array(card, int, NULL, 0444); + +MODULE_PARM_DESC(tuner,"tuner type"); +MODULE_PARM_DESC(radio,"radio tuner type"); +MODULE_PARM_DESC(card,"card type"); + +static unsigned int latency = UNSET; +module_param(latency,int,0444); +MODULE_PARM_DESC(latency,"pci latency timer"); + /* ------------------------------------------------------------------ */ /* board config info */ -const struct cx88_board cx88_boards[] = { +static const struct cx88_board cx88_boards[] = { [CX88_BOARD_UNKNOWN] = { .name = "UNKNOWN/GENERIC", .tuner_type = UNSET, @@ -1355,12 +1371,11 @@ const struct cx88_board cx88_boards[] = { }}, }, }; -const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards); /* ------------------------------------------------------------------ */ /* PCI subsystem IDs */ -struct cx88_subid cx88_subids[] = { +static const struct cx88_subid cx88_subids[] = { { .subvendor = 0x0070, .subdevice = 0x3400, @@ -1666,7 +1681,6 @@ struct cx88_subid cx88_subids[] = { .card = CX88_BOARD_ADSTECH_PTV_390, }, }; -const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids); /* ----------------------------------------------------------------------- */ /* some leadtek specific stuff */ @@ -1833,7 +1847,7 @@ static void dvico_fusionhdtv_hybrid_init(struct cx88_core *core) /* ----------------------------------------------------------------------- */ -void cx88_card_list(struct cx88_core *core, struct pci_dev *pci) +static void cx88_card_list(struct cx88_core *core, struct pci_dev *pci) { int i; @@ -1854,12 +1868,12 @@ void cx88_card_list(struct cx88_core *core, struct pci_dev *pci) } printk("%s: Here is a list of valid choices for the card= insmod option:\n", core->name); - for (i = 0; i < cx88_bcount; i++) + for (i = 0; i < ARRAY_SIZE(cx88_boards); i++) printk("%s: card=%d -> %s\n", core->name, i, cx88_boards[i].name); } -void cx88_card_setup_pre_i2c(struct cx88_core *core) +static void cx88_card_setup_pre_i2c(struct cx88_core *core) { switch (core->boardnr) { case CX88_BOARD_HAUPPAUGE_HVR1300: @@ -1875,7 +1889,7 @@ void cx88_card_setup_pre_i2c(struct cx88_core *core) } } -void cx88_card_setup(struct cx88_core *core) +static void cx88_card_setup(struct cx88_core *core) { static u8 eeprom[256]; @@ -1970,6 +1984,144 @@ void cx88_card_setup(struct cx88_core *core) /* ------------------------------------------------------------------ */ +static int cx88_pci_quirks(const char *name, struct pci_dev *pci) +{ + unsigned int lat = UNSET; + u8 ctrl = 0; + u8 value; + + /* check pci quirks */ + if (pci_pci_problems & PCIPCI_TRITON) { + printk(KERN_INFO "%s: quirk: PCIPCI_TRITON -- set TBFX\n", + name); + ctrl |= CX88X_EN_TBFX; + } + if (pci_pci_problems & PCIPCI_NATOMA) { + printk(KERN_INFO "%s: quirk: PCIPCI_NATOMA -- set TBFX\n", + name); + ctrl |= CX88X_EN_TBFX; + } + if (pci_pci_problems & PCIPCI_VIAETBF) { + printk(KERN_INFO "%s: quirk: PCIPCI_VIAETBF -- set TBFX\n", + name); + ctrl |= CX88X_EN_TBFX; + } + if (pci_pci_problems & PCIPCI_VSFX) { + printk(KERN_INFO "%s: quirk: PCIPCI_VSFX -- set VSFX\n", + name); + ctrl |= CX88X_EN_VSFX; + } +#ifdef PCIPCI_ALIMAGIK + if (pci_pci_problems & PCIPCI_ALIMAGIK) { + printk(KERN_INFO "%s: quirk: PCIPCI_ALIMAGIK -- latency fixup\n", + name); + lat = 0x0A; + } +#endif + + /* check insmod options */ + if (UNSET != latency) + lat = latency; + + /* apply stuff */ + if (ctrl) { + pci_read_config_byte(pci, CX88X_DEVCTRL, &value); + value |= ctrl; + pci_write_config_byte(pci, CX88X_DEVCTRL, value); + } + if (UNSET != lat) { + printk(KERN_INFO "%s: setting pci latency timer to %d\n", + name, latency); + pci_write_config_byte(pci, PCI_LATENCY_TIMER, latency); + } + return 0; +} + +int cx88_get_resources(const struct cx88_core *core, struct pci_dev *pci) +{ + if (request_mem_region(pci_resource_start(pci,0), + pci_resource_len(pci,0), + core->name)) + return 0; + printk(KERN_ERR + "%s/%d: Can't get MMIO memory @ 0x%llx, subsystem: %04x:%04x\n", + core->name, PCI_FUNC(pci->devfn), + (unsigned long long)pci_resource_start(pci, 0), + pci->subsystem_vendor, pci->subsystem_device); + return -EBUSY; +} + +/* Allocate and initialize the cx88 core struct. One should hold the + * devlist mutex before calling this. */ +struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr) +{ + struct cx88_core *core; + int i; + + core = kzalloc(sizeof(*core), GFP_KERNEL); + + atomic_inc(&core->refcount); + core->pci_bus = pci->bus->number; + core->pci_slot = PCI_SLOT(pci->devfn); + core->pci_irqmask = 0x00fc00; + mutex_init(&core->lock); + + core->nr = nr; + sprintf(core->name, "cx88[%d]", core->nr); + if (0 != cx88_get_resources(core, pci)) { + kfree(core); + return NULL; + } + + /* PCI stuff */ + cx88_pci_quirks(core->name, pci); + core->lmmio = ioremap(pci_resource_start(pci, 0), + pci_resource_len(pci, 0)); + core->bmmio = (u8 __iomem *)core->lmmio; + + /* board config */ + core->boardnr = UNSET; + if (card[core->nr] < ARRAY_SIZE(cx88_boards)) + core->boardnr = card[core->nr]; + for (i = 0; UNSET == core->boardnr && i < ARRAY_SIZE(cx88_subids); i++) + if (pci->subsystem_vendor == cx88_subids[i].subvendor && + pci->subsystem_device == cx88_subids[i].subdevice) + core->boardnr = cx88_subids[i].card; + if (UNSET == core->boardnr) { + core->boardnr = CX88_BOARD_UNKNOWN; + cx88_card_list(core, pci); + } + + memcpy(&core->board, &cx88_boards[core->boardnr], sizeof(core->board)); + + printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", + core->name,pci->subsystem_vendor, + pci->subsystem_device, core->board.name, + core->boardnr, card[core->nr] == core->boardnr ? + "insmod option" : "autodetected"); + + if (tuner[core->nr] != UNSET) + core->board.tuner_type = tuner[core->nr]; + if (radio[core->nr] != UNSET) + core->board.radio_type = radio[core->nr]; + + printk(KERN_INFO "TV tuner %d at 0x%02x, Radio tuner %d at 0x%02x\n", + core->board.tuner_type, core->board.tuner_addr<<1, + core->board.radio_type, core->board.radio_addr<<1); + + /* init hardware */ + cx88_reset(core); + cx88_card_setup_pre_i2c(core); + cx88_i2c_init(core, pci); + cx88_call_i2c_clients (core, TUNER_SET_STANDBY, NULL); + cx88_card_setup(core); + cx88_ir_init(core, pci); + + return core; +} + +/* ------------------------------------------------------------------ */ + /* * Local variables: * c-basic-offset: 8 diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index ece788bd3d5..0765e9db533 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -52,22 +52,6 @@ static unsigned int core_debug = 0; module_param(core_debug,int,0644); MODULE_PARM_DESC(core_debug,"enable debug messages [core]"); -static unsigned int latency = UNSET; -module_param(latency,int,0444); -MODULE_PARM_DESC(latency,"pci latency timer"); - -static unsigned int tuner[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; -static unsigned int radio[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; -static unsigned int card[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; - -module_param_array(tuner, int, NULL, 0444); -module_param_array(radio, int, NULL, 0444); -module_param_array(card, int, NULL, 0444); - -MODULE_PARM_DESC(tuner,"tuner type"); -MODULE_PARM_DESC(radio,"radio tuner type"); -MODULE_PARM_DESC(card,"card type"); - static unsigned int nicam = 0; module_param(nicam,int,0644); MODULE_PARM_DESC(nicam,"tv audio is nicam"); @@ -997,61 +981,6 @@ int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm) /* ------------------------------------------------------------------ */ -static int cx88_pci_quirks(char *name, struct pci_dev *pci) -{ - unsigned int lat = UNSET; - u8 ctrl = 0; - u8 value; - - /* check pci quirks */ - if (pci_pci_problems & PCIPCI_TRITON) { - printk(KERN_INFO "%s: quirk: PCIPCI_TRITON -- set TBFX\n", - name); - ctrl |= CX88X_EN_TBFX; - } - if (pci_pci_problems & PCIPCI_NATOMA) { - printk(KERN_INFO "%s: quirk: PCIPCI_NATOMA -- set TBFX\n", - name); - ctrl |= CX88X_EN_TBFX; - } - if (pci_pci_problems & PCIPCI_VIAETBF) { - printk(KERN_INFO "%s: quirk: PCIPCI_VIAETBF -- set TBFX\n", - name); - ctrl |= CX88X_EN_TBFX; - } - if (pci_pci_problems & PCIPCI_VSFX) { - printk(KERN_INFO "%s: quirk: PCIPCI_VSFX -- set VSFX\n", - name); - ctrl |= CX88X_EN_VSFX; - } -#ifdef PCIPCI_ALIMAGIK - if (pci_pci_problems & PCIPCI_ALIMAGIK) { - printk(KERN_INFO "%s: quirk: PCIPCI_ALIMAGIK -- latency fixup\n", - name); - lat = 0x0A; - } -#endif - - /* check insmod options */ - if (UNSET != latency) - lat = latency; - - /* apply stuff */ - if (ctrl) { - pci_read_config_byte(pci, CX88X_DEVCTRL, &value); - value |= ctrl; - pci_write_config_byte(pci, CX88X_DEVCTRL, value); - } - if (UNSET != lat) { - printk(KERN_INFO "%s: setting pci latency timer to %d\n", - name, latency); - pci_write_config_byte(pci, PCI_LATENCY_TIMER, latency); - } - return 0; -} - -/* ------------------------------------------------------------------ */ - struct video_device *cx88_vdev_init(struct cx88_core *core, struct pci_dev *pci, struct video_device *template, @@ -1071,25 +1000,10 @@ struct video_device *cx88_vdev_init(struct cx88_core *core, return vfd; } -static int get_ressources(struct cx88_core *core, struct pci_dev *pci) -{ - if (request_mem_region(pci_resource_start(pci,0), - pci_resource_len(pci,0), - core->name)) - return 0; - printk(KERN_ERR - "%s/%d: Can't get MMIO memory @ 0x%llx, subsystem: %04x:%04x\n", - core->name, PCI_FUNC(pci->devfn), - (unsigned long long)pci_resource_start(pci, 0), - pci->subsystem_vendor, pci->subsystem_device); - return -EBUSY; -} - struct cx88_core* cx88_core_get(struct pci_dev *pci) { struct cx88_core *core; struct list_head *item; - int i; mutex_lock(&devlist); list_for_each(item,&cx88_devlist) { @@ -1099,82 +1013,23 @@ struct cx88_core* cx88_core_get(struct pci_dev *pci) if (PCI_SLOT(pci->devfn) != core->pci_slot) continue; - if (0 != get_ressources(core,pci)) - goto fail_unlock; + if (0 != cx88_get_resources(core, pci)) { + mutex_unlock(&devlist); + return NULL; + } atomic_inc(&core->refcount); mutex_unlock(&devlist); return core; } - core = kzalloc(sizeof(*core),GFP_KERNEL); - if (NULL == core) - goto fail_unlock; - - atomic_inc(&core->refcount); - core->pci_bus = pci->bus->number; - core->pci_slot = PCI_SLOT(pci->devfn); - core->pci_irqmask = 0x00fc00; - mutex_init(&core->lock); - - core->nr = cx88_devcount++; - sprintf(core->name,"cx88[%d]",core->nr); - if (0 != get_ressources(core,pci)) { - cx88_devcount--; - goto fail_free; - } - list_add_tail(&core->devlist,&cx88_devlist); - - /* PCI stuff */ - cx88_pci_quirks(core->name, pci); - core->lmmio = ioremap(pci_resource_start(pci,0), - pci_resource_len(pci,0)); - core->bmmio = (u8 __iomem *)core->lmmio; - - /* board config */ - core->boardnr = UNSET; - if (card[core->nr] < cx88_bcount) - core->boardnr = card[core->nr]; - for (i = 0; UNSET == core->boardnr && i < cx88_idcount; i++) - if (pci->subsystem_vendor == cx88_subids[i].subvendor && - pci->subsystem_device == cx88_subids[i].subdevice) - core->boardnr = cx88_subids[i].card; - if (UNSET == core->boardnr) { - core->boardnr = CX88_BOARD_UNKNOWN; - cx88_card_list(core,pci); - } - memcpy(&core->board, &cx88_boards[core->boardnr], sizeof(core->board)); - - printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", - core->name,pci->subsystem_vendor, - pci->subsystem_device, core->board.name, - core->boardnr, card[core->nr] == core->boardnr ? - "insmod option" : "autodetected"); - - if (tuner[core->nr] != UNSET) - core->board.tuner_type = tuner[core->nr]; - if (radio[core->nr] != UNSET) - core->board.radio_type = radio[core->nr]; - - printk(KERN_INFO "TV tuner %d at 0x%02x, Radio tuner %d at 0x%02x\n", - core->board.tuner_type, core->board.tuner_addr<<1, - core->board.radio_type, core->board.radio_addr<<1); - - /* init hardware */ - cx88_reset(core); - cx88_card_setup_pre_i2c(core); - cx88_i2c_init(core,pci); - cx88_call_i2c_clients (core, TUNER_SET_STANDBY, NULL); - cx88_card_setup(core); - cx88_ir_init(core,pci); + core = cx88_core_create(pci, cx88_devcount); + if (NULL != core) { + cx88_devcount++; + list_add_tail(&core->devlist, &cx88_devlist); + } mutex_unlock(&devlist); return core; - -fail_free: - kfree(core); -fail_unlock: - mutex_unlock(&devlist); - return NULL; } void cx88_core_put(struct cx88_core *core, struct pci_dev *pci) diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index 3636ec26de5..80e49f986fb 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -580,15 +580,9 @@ extern void cx88_call_i2c_clients(struct cx88_core *core, /* ----------------------------------------------------------- */ /* cx88-cards.c */ -extern const struct cx88_board cx88_boards[]; -extern const unsigned int cx88_bcount; - -extern struct cx88_subid cx88_subids[]; -extern const unsigned int cx88_idcount; - -extern void cx88_card_list(struct cx88_core *core, struct pci_dev *pci); -extern void cx88_card_setup(struct cx88_core *core); -extern void cx88_card_setup_pre_i2c(struct cx88_core *core); +extern int cx88_get_resources(const struct cx88_core *core, + struct pci_dev *pci); +extern struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr); /* ----------------------------------------------------------- */ /* cx88-tvaudio.c */ -- cgit v1.2.3-70-g09d2 From 5772f81326904f2bfbb2bf2f365b3fb36ee3b7d8 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Wed, 15 Aug 2007 14:41:59 -0300 Subject: V4L/DVB (6023): cx88: Clean up some ugly and inconsistent printk()s Get rid of the "CORE" prefix from cx88 printks. It was only used a few times, and it makes it look like they're coming from the kernel core or something. Fix the message, "TV tuner 60 at 0x1fe, Radio tuner -1 at 0x1fe", by adding a "cx88[0]" prefix to be consistent, and to keep people who grep their dmesg output for cx88 from missing it. Get rid of the addresses, which are always wrong. The addresses are always set to -1, but because it's an unsigned 8-bit value, the left shift converts it to the nonsense address 0x1fe. In the cx8802 driver, some cut and pasted code prefixed lines with "CORE cx88[0]:", which has been changed to "cx88[0]/2:" like the other printks from the cx8802 driver. Also fix some ugly printks in the cx8802 driver that used __FUNCTION__ for KERN_INFO and KERN_ERR messages. The changed printks in cx88-mpeg.c also needed lots of whitespace and 80-column fixes. A bunch of misc changes in cx88-dvb.c and cx88-video.c to add message levels or a consistent "cx88[?]/2" or "cx88[?]/0" prefix. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-cards.c | 7 +++--- drivers/media/video/cx88/cx88-dvb.c | 13 ++++++----- drivers/media/video/cx88/cx88-mpeg.c | 42 +++++++++++++++++++++-------------- drivers/media/video/cx88/cx88-video.c | 30 ++++++++++++------------- 4 files changed, 49 insertions(+), 43 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index 6204a453c11..e73e8c96d5b 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -2094,7 +2094,7 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr) memcpy(&core->board, &cx88_boards[core->boardnr], sizeof(core->board)); - printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", + printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", core->name,pci->subsystem_vendor, pci->subsystem_device, core->board.name, core->boardnr, card[core->nr] == core->boardnr ? @@ -2105,9 +2105,8 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr) if (radio[core->nr] != UNSET) core->board.radio_type = radio[core->nr]; - printk(KERN_INFO "TV tuner %d at 0x%02x, Radio tuner %d at 0x%02x\n", - core->board.tuner_type, core->board.tuner_addr<<1, - core->board.radio_type, core->board.radio_addr<<1); + printk(KERN_INFO "%s: TV tuner type %d, Radio tuner type %d\n", + core->name, core->board.tuner_type, core->board.radio_type); /* init hardware */ cx88_reset(core); diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index d98b9072101..00d0e43785a 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -482,7 +482,7 @@ static int dvb_register(struct cx8802_dev *dev) &dev->core->i2c_adap, DVB_PLL_FMD1216ME); } #else - printk("%s: built without vp3054 support\n", dev->core->name); + printk(KERN_ERR "%s/2: built without vp3054 support\n", dev->core->name); #endif break; case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID: @@ -625,12 +625,12 @@ static int dvb_register(struct cx8802_dev *dev) } break; default: - printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n", + printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n", dev->core->name); break; } if (NULL == dev->dvb.frontend) { - printk("%s: frontend initialization failed\n",dev->core->name); + printk(KERN_ERR "%s/2: frontend initialization failed\n", dev->core->name); return -1; } @@ -709,7 +709,7 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv) goto fail_core; /* dvb stuff */ - printk("%s/2: cx2388x based dvb card\n", core->name); + printk(KERN_INFO "%s/2: cx2388x based DVB/ATSC card\n", core->name); videobuf_queue_init(&dev->dvb.dvbq, &dvb_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, @@ -718,7 +718,8 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv) dev); err = dvb_register(dev); if (err != 0) - printk("%s dvb_register failed err = %d\n", __FUNCTION__, err); + printk(KERN_ERR "%s/2: dvb_register failed (err = %d)\n", + core->name, err); fail_core: return err; @@ -747,7 +748,7 @@ static struct cx8802_driver cx8802_dvb_driver = { static int dvb_init(void) { - printk(KERN_INFO "cx2388x dvb driver version %d.%d.%d loaded\n", + printk(KERN_INFO "cx88/2: cx2388x dvb driver version %d.%d.%d loaded\n", (CX88_VERSION_CODE >> 16) & 0xff, (CX88_VERSION_CODE >> 8) & 0xff, CX88_VERSION_CODE & 0xff); diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index 1df245ace2d..5da47e251e6 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -675,22 +675,24 @@ int cx8802_register_driver(struct cx8802_driver *drv) struct list_head *list; int err = 0, i = 0; - printk(KERN_INFO "%s() ->registering driver type=%s access=%s\n", __FUNCTION__ , - drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird", - drv->hw_access == CX8802_DRVCTL_SHARED ? "shared" : "exclusive"); + printk(KERN_INFO + "cx88/2: registering cx8802 driver, type: %s access: %s\n", + drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird", + drv->hw_access == CX8802_DRVCTL_SHARED ? "shared" : "exclusive"); if ((err = cx8802_check_driver(drv)) != 0) { - printk(KERN_INFO "%s() cx8802_driver is invalid\n", __FUNCTION__ ); + printk(KERN_ERR "cx88/2: cx8802_driver is invalid\n"); return err; } list_for_each(list,&cx8802_devlist) { h = list_entry(list, struct cx8802_dev, devlist); - printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d]\n", - h->core->name,h->pci->subsystem_vendor, - h->pci->subsystem_device,h->core->board.name, - h->core->boardnr); + printk(KERN_INFO + "%s/2: subsystem: %04x:%04x, board: %s [card=%d]\n", + h->core->name, h->pci->subsystem_vendor, + h->pci->subsystem_device, h->core->board.name, + h->core->boardnr); /* Bring up a new struct for each driver instance */ driver = kzalloc(sizeof(*drv),GFP_KERNEL); @@ -712,7 +714,9 @@ int cx8802_register_driver(struct cx8802_driver *drv) list_add_tail(&driver->devlist,&h->drvlist.devlist); mutex_unlock(&drv->core->lock); } else { - printk(KERN_ERR "%s() ->probe failed err = %d\n", __FUNCTION__, err); + printk(KERN_ERR + "%s/2: cx8802 probe failed, err = %d\n", + h->core->name, err); } } @@ -732,17 +736,20 @@ int cx8802_unregister_driver(struct cx8802_driver *drv) struct list_head *list2, *q; int err = 0, i = 0; - printk(KERN_INFO "%s() ->unregistering driver type=%s\n", __FUNCTION__ , - drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird"); + printk(KERN_INFO + "cx88/2: unregistering cx8802 driver, type: %s access: %s\n", + drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird", + drv->hw_access == CX8802_DRVCTL_SHARED ? "shared" : "exclusive"); list_for_each(list,&cx8802_devlist) { i++; h = list_entry(list, struct cx8802_dev, devlist); - printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d]\n", - h->core->name,h->pci->subsystem_vendor, - h->pci->subsystem_device,h->core->board.name, - h->core->boardnr); + printk(KERN_INFO + "%s/2: subsystem: %04x:%04x, board: %s [card=%d]\n", + h->core->name, h->pci->subsystem_vendor, + h->pci->subsystem_device, h->core->board.name, + h->core->boardnr); list_for_each_safe(list2, q, &h->drvlist.devlist) { d = list_entry(list2, struct cx8802_driver, devlist); @@ -757,7 +764,8 @@ int cx8802_unregister_driver(struct cx8802_driver *drv) list_del(list2); mutex_unlock(&drv->core->lock); } else - printk(KERN_ERR "%s() ->remove failed err = %d\n", __FUNCTION__, err); + printk(KERN_ERR "%s/2: cx8802 driver remove " + "failed (%d)\n", h->core->name, err); } @@ -865,7 +873,7 @@ static struct pci_driver cx8802_pci_driver = { static int cx8802_init(void) { - printk(KERN_INFO "cx2388x cx88-mpeg Driver Manager version %d.%d.%d loaded\n", + printk(KERN_INFO "cx88/2: cx2388x MPEG-TS Driver Manager version %d.%d.%d loaded\n", (CX88_VERSION_CODE >> 16) & 0xff, (CX88_VERSION_CODE >> 8) & 0xff, CX88_VERSION_CODE & 0xff); diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index b0dd4313a84..e158ea2454a 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -1818,7 +1818,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, err = request_irq(pci_dev->irq, cx8800_irq, IRQF_SHARED | IRQF_DISABLED, core->name, dev); if (err < 0) { - printk(KERN_ERR "%s: can't get IRQ %d\n", + printk(KERN_ERR "%s/0: can't get IRQ %d\n", core->name,pci_dev->irq); goto fail_core; } @@ -1837,7 +1837,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER, video_nr[core->nr]); if (err < 0) { - printk(KERN_INFO "%s: can't register video device\n", + printk(KERN_ERR "%s/0: can't register video device\n", core->name); goto fail_unreg; } @@ -1848,7 +1848,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI, vbi_nr[core->nr]); if (err < 0) { - printk(KERN_INFO "%s/0: can't register vbi device\n", + printk(KERN_ERR "%s/0: can't register vbi device\n", core->name); goto fail_unreg; } @@ -1861,7 +1861,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO, radio_nr[core->nr]); if (err < 0) { - printk(KERN_INFO "%s/0: can't register radio device\n", + printk(KERN_ERR "%s/0: can't register radio device\n", core->name); goto fail_unreg; } @@ -1885,8 +1885,8 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, core->kthread = kthread_run(cx88_audio_thread, core, "cx88 tvaudio"); if (IS_ERR(core->kthread)) { err = PTR_ERR(core->kthread); - printk(KERN_ERR "Failed to create cx88 audio thread, err=%d\n", - err); + printk(KERN_ERR "%s/0: failed to create cx88 audio thread, err=%d\n", + core->name, err); } } return 0; @@ -1937,12 +1937,12 @@ static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state) /* stop video+vbi capture */ spin_lock(&dev->slock); if (!list_empty(&dev->vidq.active)) { - printk("%s: suspend video\n", core->name); + printk("%s/0: suspend video\n", core->name); stop_video_dma(dev); del_timer(&dev->vidq.timeout); } if (!list_empty(&dev->vbiq.active)) { - printk("%s: suspend vbi\n", core->name); + printk("%s/0: suspend vbi\n", core->name); cx8800_stop_vbi_dma(dev); del_timer(&dev->vbiq.timeout); } @@ -1968,8 +1968,8 @@ static int cx8800_resume(struct pci_dev *pci_dev) if (dev->state.disabled) { err=pci_enable_device(pci_dev); if (err) { - printk(KERN_ERR "%s: can't enable device\n", - core->name); + printk(KERN_ERR "%s/0: can't enable device\n", + core->name); return err; } @@ -1977,9 +1977,7 @@ static int cx8800_resume(struct pci_dev *pci_dev) } err= pci_set_power_state(pci_dev, PCI_D0); if (err) { - printk(KERN_ERR "%s: can't enable device\n", - core->name); - + printk(KERN_ERR "%s/0: can't set power state\n", core->name); pci_disable_device(pci_dev); dev->state.disabled = 1; @@ -1993,11 +1991,11 @@ static int cx8800_resume(struct pci_dev *pci_dev) /* restart video+vbi capture */ spin_lock(&dev->slock); if (!list_empty(&dev->vidq.active)) { - printk("%s: resume video\n", core->name); + printk("%s/0: resume video\n", core->name); restart_video_queue(dev,&dev->vidq); } if (!list_empty(&dev->vbiq.active)) { - printk("%s: resume vbi\n", core->name); + printk("%s/0: resume vbi\n", core->name); cx8800_restart_vbi_queue(dev,&dev->vbiq); } spin_unlock(&dev->slock); @@ -2033,7 +2031,7 @@ static struct pci_driver cx8800_pci_driver = { static int cx8800_init(void) { - printk(KERN_INFO "cx2388x v4l2 driver version %d.%d.%d loaded\n", + printk(KERN_INFO "cx88/0: cx2388x v4l2 driver version %d.%d.%d loaded\n", (CX88_VERSION_CODE >> 16) & 0xff, (CX88_VERSION_CODE >> 8) & 0xff, CX88_VERSION_CODE & 0xff); -- cgit v1.2.3-70-g09d2 From 89d969a39da8e9ee5db1c1fb49f55f4206a445ac Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Thu, 16 Aug 2007 10:03:18 -0300 Subject: V4L/DVB (6025): Net_ule(): fix check-after-use The Coverity checker spotted that we'd have already oops'ed if "dev" was NULL. Signed-off-by: Adrian Bunk Signed-off-by: Manu Abraham Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_net.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c index bdd797071cb..b9c78d03a7f 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ b/drivers/media/dvb/dvb-core/dvb_net.c @@ -357,11 +357,6 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) static unsigned char *ule_where = ule_hist, ule_dump = 0; #endif - if (dev == NULL) { - printk( KERN_ERR "NO netdev struct!\n" ); - return; - } - /* For all TS cells in current buffer. * Appearently, we are called for every single TS cell. */ -- cgit v1.2.3-70-g09d2 From 82e67246cd2a860637ee9d27776ad48d32734f6c Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Fri, 17 Aug 2007 17:49:41 -0300 Subject: V4L/DVB (6031): Fix for bug 7819: fixed hotplugging for dvbnet The first part of dvb_net_close() is just a cut&paste from dvb_generic_release(), so maybe it would be better to just call dvb_generic_release() instead? Signed-off-by: Trent Piepho Acked-by: Markus Rechberger Acked-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_net.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c index b9c78d03a7f..13e2998a404 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ b/drivers/media/dvb/dvb-core/dvb_net.c @@ -1441,18 +1441,9 @@ static int dvb_net_close(struct inode *inode, struct file *file) struct dvb_device *dvbdev = file->private_data; struct dvb_net *dvbnet = dvbdev->priv; - if (!dvbdev) - return -ENODEV; + dvb_generic_release(inode, file); - if ((file->f_flags & O_ACCMODE) == O_RDONLY) { - dvbdev->readers++; - } else { - dvbdev->writers++; - } - - dvbdev->users++; - - if(dvbdev->users == 1 && dvbnet->exit==1) { + if(dvbdev->users == 1 && dvbnet->exit == 1) { fops_put(file->f_op); file->f_op = NULL; wake_up(&dvbdev->wait_queue); -- cgit v1.2.3-70-g09d2 From fa40b2237ab6ed239967f76432438080232b88fe Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Fri, 17 Aug 2007 05:50:22 -0300 Subject: V4L/DVB (6034): cx88: Add parameter to control radio deemphasis time constant FM radio transmission use a preemphasis/deemphasis scheme to reduce high-frequency noise. The cx88 audio decoder is supposedly set to no deemphasis by the current driver. However, the "no deemphasis" setting doesn't work. On my chip, cx23883, it produces the same result as the 75 us time constant. Maybe the default settings on the cx23881 are for 50 us? Since the deemphasis time constant varies by country, allow setting it via a module parameter. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-tvaudio.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c index 99e120483ec..9aee8c51ee2 100644 --- a/drivers/media/video/cx88/cx88-tvaudio.c +++ b/drivers/media/video/cx88/cx88-tvaudio.c @@ -62,6 +62,10 @@ static unsigned int always_analog = 0; module_param(always_analog,int,0644); MODULE_PARM_DESC(always_analog,"force analog audio out"); +static unsigned int radio_deemphasis = 0; +module_param(radio_deemphasis,int,0644); +MODULE_PARM_DESC(radio_deemphasis, "Radio deemphasis time constant, " + "0=None, 1=50us (elsewhere), 2=75us (USA)"); #define dprintk(fmt, arg...) if (audio_debug) \ printk(KERN_DEBUG "%s/0: " fmt, core->name , ## arg) @@ -678,6 +682,10 @@ static void set_audio_standard_FM(struct cx88_core *core, }; /* It is enough to leave default values? */ + /* No, it's not! The deemphasis registers are reset to the 75us + * values by default. Analyzing the spectrum of the decoded audio + * reveals that "no deemphasis" is the same as 75 us, while the 50 us + * setting results in less deemphasis. */ static const struct rlist fm_no_deemph[] = { {AUD_POLYPH80SCALEFAC, 0x0003}, @@ -688,6 +696,7 @@ static void set_audio_standard_FM(struct cx88_core *core, set_audio_start(core, SEL_FMRADIO); switch (deemph) { + default: case FM_NO_DEEMPH: set_audio_registers(core, fm_no_deemph); break; @@ -757,7 +766,7 @@ void cx88_set_tvaudio(struct cx88_core *core) set_audio_standard_EIAJ(core); break; case WW_FM: - set_audio_standard_FM(core, FM_NO_DEEMPH); + set_audio_standard_FM(core, radio_deemphasis); break; case WW_NONE: default: -- cgit v1.2.3-70-g09d2 From 458b634cd86968032171a4d6db5c89a772ff0348 Mon Sep 17 00:00:00 2001 From: Alan Nisota Date: Sat, 18 Aug 2007 17:52:35 -0300 Subject: V4L/DVB (6037): Updated GenPix USB driver There are now 4 different versions of the GENPIX USB adapter. The newest 'Skywalker' models are fully self-contained, and need no additional hardware to be used. A very reliable DVB-S card even without using any of the alternate modulatations (which this kernel module does not currently support) The following patch adds support for all 4 versions of the genpix adapter (www.genpix-electronics.com). Signed-off-by: Alan Nisota alannisota@gmail.com Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 7 ++- drivers/media/dvb/dvb-usb/gp8psk-fe.c | 84 +++++++++++++++++------------ drivers/media/dvb/dvb-usb/gp8psk.c | 93 +++++++++++++++++++++++++-------- drivers/media/dvb/dvb-usb/gp8psk.h | 32 +++++++++--- 4 files changed, 152 insertions(+), 64 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index a16be605c63..43bfe50a222 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -158,8 +158,11 @@ #define USB_PID_WINFAST_DTV_DONGLE_COLD 0x6025 #define USB_PID_WINFAST_DTV_DONGLE_WARM 0x6026 #define USB_PID_WINFAST_DTV_DONGLE_STK7700P 0x6f00 -#define USB_PID_GENPIX_8PSK_COLD 0x0200 -#define USB_PID_GENPIX_8PSK_WARM 0x0201 +#define USB_PID_GENPIX_8PSK_REV_1_COLD 0x0200 +#define USB_PID_GENPIX_8PSK_REV_1_WARM 0x0201 +#define USB_PID_GENPIX_8PSK_REV_2 0x0202 +#define USB_PID_GENPIX_SKYWALKER_1 0x0203 +#define USB_PID_GENPIX_SKYWALKER_CW3K 0x0204 #define USB_PID_SIGMATEK_DVB_110 0x6610 #define USB_PID_MSI_DIGI_VOX_MINI_II 0x1513 #define USB_PID_OPERA1_COLD 0x2830 diff --git a/drivers/media/dvb/dvb-usb/gp8psk-fe.c b/drivers/media/dvb/dvb-usb/gp8psk-fe.c index 6ccbdc9cd77..e37142d9271 100644 --- a/drivers/media/dvb/dvb-usb/gp8psk-fe.c +++ b/drivers/media/dvb/dvb-usb/gp8psk-fe.c @@ -1,7 +1,8 @@ /* DVB USB compliant Linux driver for the - * - GENPIX 8pks/qpsk USB2.0 DVB-S module + * - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module * - * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com) + * Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com) + * Copyright (C) 2006,2007 Genpix Electronics (genpix@genpix-electronics.com) * * Thanks to GENPIX for the sample code used to implement this module. * @@ -17,27 +18,39 @@ struct gp8psk_fe_state { struct dvb_frontend fe; - struct dvb_usb_device *d; - + u8 lock; u16 snr; - - unsigned long next_snr_check; + unsigned long next_status_check; + unsigned long status_check_interval; }; +static int gp8psk_fe_update_status(struct gp8psk_fe_state *st) +{ + u8 buf[6]; + if (time_after(jiffies,st->next_status_check)) { + gp8psk_usb_in_op(st->d, GET_SIGNAL_LOCK, 0,0,&st->lock,1); + gp8psk_usb_in_op(st->d, GET_SIGNAL_STRENGTH, 0,0,buf,6); + st->snr = (buf[1]) << 8 | buf[0]; + st->next_status_check = jiffies + (st->status_check_interval*HZ)/1000; + } + return 0; +} + static int gp8psk_fe_read_status(struct dvb_frontend* fe, fe_status_t *status) { struct gp8psk_fe_state *st = fe->demodulator_priv; - u8 lock; + gp8psk_fe_update_status(st); - if (gp8psk_usb_in_op(st->d, GET_SIGNAL_LOCK, 0, 0, &lock,1)) - return -EINVAL; - - if (lock) + if (st->lock) *status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_SIGNAL | FE_HAS_CARRIER; else *status = 0; + if (*status & FE_HAS_LOCK) + st->status_check_interval = 1000; + else + st->status_check_interval = 100; return 0; } @@ -60,33 +73,29 @@ static int gp8psk_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc) static int gp8psk_fe_read_snr(struct dvb_frontend* fe, u16 *snr) { struct gp8psk_fe_state *st = fe->demodulator_priv; - u8 buf[2]; - - if (time_after(jiffies,st->next_snr_check)) { - gp8psk_usb_in_op(st->d,GET_SIGNAL_STRENGTH,0,0,buf,2); - *snr = (int)(buf[1]) << 8 | buf[0]; - /* snr is reported in dBu*256 */ - /* snr / 38.4 ~= 100% strength */ - /* snr * 17 returns 100% strength as 65535 */ - if (*snr <= 3855) - *snr = (*snr<<4) + *snr; // snr * 17 - else - *snr = 65535; - st->next_snr_check = jiffies + (10*HZ)/1000; - } else { - *snr = st->snr; - } + gp8psk_fe_update_status(st); + /* snr is reported in dBu*256 */ + *snr = st->snr; return 0; } static int gp8psk_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength) { - return gp8psk_fe_read_snr(fe, strength); + struct gp8psk_fe_state *st = fe->demodulator_priv; + gp8psk_fe_update_status(st); + /* snr is reported in dBu*256 */ + /* snr / 38.4 ~= 100% strength */ + /* snr * 17 returns 100% strength as 65535 */ + if (st->snr > 0xf00) + *strength = 0xffff; + else + *strength = (st->snr << 4) + st->snr; /* snr*17 */ + return 0; } static int gp8psk_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) { - tune->min_delay_ms = 800; + tune->min_delay_ms = 200; return 0; } @@ -124,7 +133,9 @@ static int gp8psk_fe_set_frontend(struct dvb_frontend* fe, gp8psk_usb_out_op(state->d,TUNE_8PSK,0,0,cmd,10); - state->next_snr_check = jiffies; + state->lock = 0; + state->next_status_check = jiffies; + state->status_check_interval = 200; return 0; } @@ -190,6 +201,12 @@ static int gp8psk_fe_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t volt return 0; } +static int gp8psk_fe_enable_high_lnb_voltage(struct dvb_frontend* fe, long onoff) +{ + struct gp8psk_fe_state* state = fe->demodulator_priv; + return gp8psk_usb_out_op(state->d, USE_EXTRA_VOLT, onoff, 0,NULL,0); +} + static int gp8psk_fe_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long sw_cmd) { struct gp8psk_fe_state* state = fe->demodulator_priv; @@ -235,10 +252,10 @@ success: static struct dvb_frontend_ops gp8psk_fe_ops = { .info = { - .name = "Genpix 8psk-USB DVB-S", + .name = "Genpix 8psk-to-USB2 DVB-S", .type = FE_QPSK, - .frequency_min = 950000, - .frequency_max = 2150000, + .frequency_min = 800000, + .frequency_max = 2250000, .frequency_stepsize = 100, .symbol_rate_min = 1000000, .symbol_rate_max = 45000000, @@ -269,4 +286,5 @@ static struct dvb_frontend_ops gp8psk_fe_ops = { .set_tone = gp8psk_fe_set_tone, .set_voltage = gp8psk_fe_set_voltage, .dishnetwork_send_legacy_command = gp8psk_fe_send_legacy_dish_cmd, + .enable_high_lnb_voltage = gp8psk_fe_enable_high_lnb_voltage }; diff --git a/drivers/media/dvb/dvb-usb/gp8psk.c b/drivers/media/dvb/dvb-usb/gp8psk.c index 518d67fca5e..92147ee3e14 100644 --- a/drivers/media/dvb/dvb-usb/gp8psk.c +++ b/drivers/media/dvb/dvb-usb/gp8psk.c @@ -1,7 +1,8 @@ /* DVB USB compliant Linux driver for the - * - GENPIX 8pks/qpsk USB2.0 DVB-S module + * - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module * - * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com) + * Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com) + * Copyright (C) 2006,2007 Genpix Electronics (genpix@genpix-electronics.com) * * Thanks to GENPIX for the sample code used to implement this module. * @@ -40,7 +41,7 @@ int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 } if (ret < 0 || ret != blen) { - warn("usb in operation failed."); + warn("usb in %d operation failed.", req); ret = -EIO; } else ret = 0; @@ -97,10 +98,10 @@ static int gp8psk_load_bcm4500fw(struct dvb_usb_device *d) if (gp8psk_usb_out_op(d, LOAD_BCM4500,1,0,NULL, 0)) goto out_rel_fw; - info("downloaidng bcm4500 firmware from file '%s'",bcm4500_firmware); + info("downloading bcm4500 firmware from file '%s'",bcm4500_firmware); ptr = fw->data; - buf = kmalloc(512, GFP_KERNEL | GFP_DMA); + buf = kmalloc(64, GFP_KERNEL | GFP_DMA); while (ptr[0] != 0xff) { u16 buflen = ptr[0] + 4; @@ -129,25 +130,34 @@ out_rel_fw: static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff) { u8 status, buf; + int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct); + if (onoff) { gp8psk_usb_in_op(d, GET_8PSK_CONFIG,0,0,&status,1); - if (! (status & 0x01)) /* started */ + if (! (status & bm8pskStarted)) { /* started */ + if(gp_product_id == USB_PID_GENPIX_SKYWALKER_CW3K) + gp8psk_usb_out_op(d, CW3K_INIT, 1, 0, NULL, 0); if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1)) return -EINVAL; + } - if (! (status & 0x02)) /* BCM4500 firmware loaded */ - if(gp8psk_load_bcm4500fw(d)) - return EINVAL; + if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM) + if (! (status & bm8pskFW_Loaded)) /* BCM4500 firmware loaded */ + if(gp8psk_load_bcm4500fw(d)) + return EINVAL; - if (! (status & 0x04)) /* LNB Power */ + if (! (status & bmIntersilOn)) /* LNB Power */ if (gp8psk_usb_in_op(d, START_INTERSIL, 1, 0, &buf, 1)) return EINVAL; - /* Set DVB mode */ - if(gp8psk_usb_out_op(d, SET_DVB_MODE, 1, 0, NULL, 0)) - return -EINVAL; - gp8psk_usb_in_op(d, GET_8PSK_CONFIG,0,0,&status,1); + /* Set DVB mode to 1 */ + if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM) + if (gp8psk_usb_out_op(d, SET_DVB_MODE, 1, 0, NULL, 0)) + return EINVAL; + /* Abort possible TS (if previous tune crashed) */ + if (gp8psk_usb_out_op(d, ARM_TRANSFER, 0, 0, NULL, 0)) + return EINVAL; } else { /* Turn off LNB power */ if (gp8psk_usb_in_op(d, START_INTERSIL, 0, 0, &buf, 1)) @@ -155,11 +165,28 @@ static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff) /* Turn off 8psk power */ if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1)) return -EINVAL; - + if(gp_product_id == USB_PID_GENPIX_SKYWALKER_CW3K) + gp8psk_usb_out_op(d, CW3K_INIT, 0, 0, NULL, 0); } return 0; } +int gp8psk_bcm4500_reload(struct dvb_usb_device *d) +{ + u8 buf; + int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct); + /* Turn off 8psk power */ + if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1)) + return -EINVAL; + /* Turn On 8psk power */ + if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1)) + return -EINVAL; + /* load BCM4500 firmware */ + if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM) + if (gp8psk_load_bcm4500fw(d)) + return EINVAL; + return 0; +} static int gp8psk_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) { @@ -177,12 +204,22 @@ static struct dvb_usb_device_properties gp8psk_properties; static int gp8psk_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) { - return dvb_usb_device_init(intf,&gp8psk_properties,THIS_MODULE,NULL); + int ret; + struct usb_device *udev = interface_to_usbdev(intf); + ret = dvb_usb_device_init(intf,&gp8psk_properties,THIS_MODULE,NULL); + if (ret == 0) { + info("found Genpix USB device pID = %x (hex)", + le16_to_cpu(udev->descriptor.idProduct)); + } + return ret; } static struct usb_device_id gp8psk_usb_table [] = { - { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_COLD) }, - { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_WARM) }, + { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_COLD) }, + { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_WARM) }, + { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_2) }, + { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_1) }, + { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_CW3K) }, { 0 }, }; MODULE_DEVICE_TABLE(usb, gp8psk_usb_table); @@ -213,12 +250,24 @@ static struct dvb_usb_device_properties gp8psk_properties = { .generic_bulk_ctrl_endpoint = 0x01, - .num_device_descs = 1, + .num_device_descs = 4, .devices = { - { .name = "Genpix 8PSK-USB DVB-S USB2.0 receiver", + { .name = "Genpix 8PSK-to-USB2 Rev.1 DVB-S receiver", .cold_ids = { &gp8psk_usb_table[0], NULL }, .warm_ids = { &gp8psk_usb_table[1], NULL }, }, + { .name = "Genpix 8PSK-to-USB2 Rev.2 DVB-S receiver", + .cold_ids = { NULL }, + .warm_ids = { &gp8psk_usb_table[2], NULL }, + }, + { .name = "Genpix SkyWalker-1 DVB-S receiver", + .cold_ids = { NULL }, + .warm_ids = { &gp8psk_usb_table[3], NULL }, + }, + { .name = "Genpix SkyWalker-CW3K DVB-S receiver", + .cold_ids = { NULL }, + .warm_ids = { &gp8psk_usb_table[4], NULL }, + }, { NULL }, } }; @@ -253,6 +302,6 @@ module_init(gp8psk_usb_module_init); module_exit(gp8psk_usb_module_exit); MODULE_AUTHOR("Alan Nisota "); -MODULE_DESCRIPTION("Driver for Genpix 8psk-USB DVB-S USB2.0"); -MODULE_VERSION("1.0"); +MODULE_DESCRIPTION("Driver for Genpix 8psk-to-USB2 DVB-S"); +MODULE_VERSION("1.1"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/gp8psk.h b/drivers/media/dvb/dvb-usb/gp8psk.h index 3eba7061011..e83a57506cf 100644 --- a/drivers/media/dvb/dvb-usb/gp8psk.h +++ b/drivers/media/dvb/dvb-usb/gp8psk.h @@ -1,7 +1,8 @@ /* DVB USB compliant Linux driver for the - * - GENPIX 8pks/qpsk USB2.0 DVB-S module + * - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module * * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com) + * Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com) * * Thanks to GENPIX for the sample code used to implement this module. * @@ -30,21 +31,37 @@ extern int dvb_usb_gp8psk_debug; #define TH_COMMAND_IN 0xC0 #define TH_COMMAND_OUT 0xC1 -/* command bytes */ -#define GET_8PSK_CONFIG 0x80 +/* gp8psk commands */ + +#define GET_8PSK_CONFIG 0x80 /* in */ #define SET_8PSK_CONFIG 0x81 +#define I2C_WRITE 0x83 +#define I2C_READ 0x84 #define ARM_TRANSFER 0x85 #define TUNE_8PSK 0x86 -#define GET_SIGNAL_STRENGTH 0x87 +#define GET_SIGNAL_STRENGTH 0x87 /* in */ #define LOAD_BCM4500 0x88 -#define BOOT_8PSK 0x89 -#define START_INTERSIL 0x8A +#define BOOT_8PSK 0x89 /* in */ +#define START_INTERSIL 0x8A /* in */ #define SET_LNB_VOLTAGE 0x8B #define SET_22KHZ_TONE 0x8C #define SEND_DISEQC_COMMAND 0x8D #define SET_DVB_MODE 0x8E #define SET_DN_SWITCH 0x8F -#define GET_SIGNAL_LOCK 0x90 +#define GET_SIGNAL_LOCK 0x90 /* in */ +#define GET_SERIAL_NUMBER 0x93 /* in */ +#define USE_EXTRA_VOLT 0x94 +#define CW3K_INIT 0x9d + +/* PSK_configuration bits */ +#define bm8pskStarted 0x01 +#define bm8pskFW_Loaded 0x02 +#define bmIntersilOn 0x04 +#define bmDVBmode 0x08 +#define bm22kHz 0x10 +#define bmSEL18V 0x20 +#define bmDCtuned 0x40 +#define bmArmed 0x80 /* Satellite modulation modes */ #define ADV_MOD_DVB_QPSK 0 /* DVB-S QPSK */ @@ -75,5 +92,6 @@ extern struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d); extern int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen); extern int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen); +extern int gp8psk_bcm4500_reload(struct dvb_usb_device *d); #endif -- cgit v1.2.3-70-g09d2 From e927b3fa595117c9f4c6dfa241fe7c3a3c596f17 Mon Sep 17 00:00:00 2001 From: Michael Mauch Date: Sat, 18 Aug 2007 18:02:31 -0300 Subject: V4L/DVB (6038): Trivial: repair mixed parm descs in dvb-usb-init.c Repair modinfo parameter descriptions for force_pid_filter_usage and disable_rc_polling. Signed-off-by: Michael Mauch Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb-usb-init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-init.c b/drivers/media/dvb/dvb-usb/dvb-usb-init.c index ffdde83d1e7..cdd717c3fe4 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-init.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-init.c @@ -24,7 +24,7 @@ MODULE_PARM_DESC(disable_rc_polling, "disable remote control polling (default: 0 static int dvb_usb_force_pid_filter_usage; module_param_named(force_pid_filter_usage, dvb_usb_force_pid_filter_usage, int, 0444); -MODULE_PARM_DESC(disable_rc_polling, "force all dvb-usb-devices to use a PID filter, if any (default: 0)."); +MODULE_PARM_DESC(force_pid_filter_usage, "force all dvb-usb-devices to use a PID filter, if any (default: 0)."); static int dvb_usb_adapter_init(struct dvb_usb_device *d) { -- cgit v1.2.3-70-g09d2 From faebb914399ecf8ecfd0e24b96ac90d7381f7e07 Mon Sep 17 00:00:00 2001 From: Darren Salt Date: Sat, 18 Aug 2007 18:04:00 -0300 Subject: V4L/DVB (6039): Typo fix in Nova-TD description Typo fix in Nova-TD description Signed-off-by: Darren Salt Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 4a3c5467d7e..0227e7fac3c 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -944,7 +944,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { { &dib0700_usb_id_table[12], NULL }, { NULL }, }, - { "Haupauge Nova-TD Stick/Elgato Eye-TV Diversity", + { "Hauppauge Nova-TD Stick/Elgato Eye-TV Diversity", { &dib0700_usb_id_table[13], NULL }, { NULL }, }, -- cgit v1.2.3-70-g09d2 From b1139e353c7fc636bfe413f3296ba0284eb60c2e Mon Sep 17 00:00:00 2001 From: Darren Salt Date: Sat, 18 Aug 2007 18:05:31 -0300 Subject: V4L/DVB (6040): Add IR support for Nova-T Stick Working with Nova-T Stick (70001) with remote control model A415. Untested with other dib0700m/dib0700p devices. Signed-off-by: Darren Salt Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 0227e7fac3c..063fb5095bd 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -887,7 +887,12 @@ struct dvb_usb_device_properties dib0700_devices[] = { { &dib0700_usb_id_table[8], NULL }, { NULL }, } - } + }, + + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_key_map = dib0700_rc_keys, + .rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys), + .rc_query = dib0700_rc_query }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, .num_adapters = 2, -- cgit v1.2.3-70-g09d2 From 33bc4dea0ece371ccadbac8bf90fd0b8e2803f06 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 18 Aug 2007 11:36:09 -0300 Subject: V4L/DVB (6043): ivtv: fix incorrect round-robin implementation Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-irq.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c index 88c6f4ff5c6..a97d55fd227 100644 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ b/drivers/media/video/ivtv/ivtv-irq.c @@ -859,8 +859,9 @@ irqreturn_t ivtv_irq_handler(int irq, void *dev_id) } if ((combo & IVTV_IRQ_DMA) && !test_bit(IVTV_F_I_DMA, &itv->i_flags)) { + itv->irq_rr_idx++; for (i = 0; i < IVTV_MAX_STREAMS; i++) { - int idx = (i + itv->irq_rr_idx++) % IVTV_MAX_STREAMS; + int idx = (i + itv->irq_rr_idx) % IVTV_MAX_STREAMS; struct ivtv_stream *s = &itv->streams[idx]; if (!test_and_clear_bit(IVTV_F_S_DMA_PENDING, &s->s_flags)) @@ -877,8 +878,9 @@ irqreturn_t ivtv_irq_handler(int irq, void *dev_id) } if ((combo & IVTV_IRQ_DMA) && !test_bit(IVTV_F_I_PIO, &itv->i_flags)) { + itv->irq_rr_idx++; for (i = 0; i < IVTV_MAX_STREAMS; i++) { - int idx = (i + itv->irq_rr_idx++) % IVTV_MAX_STREAMS; + int idx = (i + itv->irq_rr_idx) % IVTV_MAX_STREAMS; struct ivtv_stream *s = &itv->streams[idx]; if (!test_and_clear_bit(IVTV_F_S_PIO_PENDING, &s->s_flags)) -- cgit v1.2.3-70-g09d2 From da80be21362376443c6ee9918dfff408e83e0c39 Mon Sep 17 00:00:00 2001 From: Kazuhiko Kawakami Date: Sat, 18 Aug 2007 11:39:28 -0300 Subject: V4L/DVB (6044): vp27smpx: clarify history of this source. Signed-off-by: Kazuhiko Kawakami Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vp27smpx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/vp27smpx.c b/drivers/media/video/vp27smpx.c index 8a81fcd13ae..63002e0ac76 100644 --- a/drivers/media/video/vp27smpx.c +++ b/drivers/media/video/vp27smpx.c @@ -3,7 +3,8 @@ * * Copyright (C) 2007 Hans Verkuil * - * Based on a tvaudio patch from Kazuhiko Kawakami + * Based on a tvaudio patch from Takahiro Adachi + * and Kazuhiko Kawakami * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by -- cgit v1.2.3-70-g09d2 From 3562c43be8cfd6e300508d7c33acebf3369eacd3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 18 Aug 2007 11:46:05 -0300 Subject: V4L/DVB (6045): ivtv: fix handling of INITIALIZE_INPUT fw call The CX2341X_ENC_INITIALIZE_INPUT firmware call requires careful handling, otherwise the computer can freeze or the top-third of the screen can start flickering. This patch ensures that CX2341X_ENC_INITIALIZE_INPUT is called at the right time and in the right way. In addition the stop capture handling was improved so that the last pending DMA transfer is also processed. Otherwise this would be the first data that arrived when a new capture was started which is not what you want. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-fileops.c | 19 +++++++++++-------- drivers/media/video/ivtv/ivtv-ioctl.c | 3 +++ drivers/media/video/ivtv/ivtv-streams.c | 28 +++++----------------------- 3 files changed, 19 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index 9e867b5229d..908e640c274 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -892,12 +892,20 @@ int ivtv_v4l2_open(struct inode *inode, struct file *filp) return -EBUSY; } + if (!test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) { + if (atomic_read(&itv->capturing) > 0) { + /* switching to radio while capture is + in progress is not polite */ + kfree(item); + return -EBUSY; + } + } + /* Mark that the radio is being used. */ + set_bit(IVTV_F_I_RADIO_USER, &itv->i_flags); /* We have the radio */ ivtv_mute(itv); /* Switch tuner to radio */ ivtv_call_i2c_clients(itv, AUDC_SET_RADIO, NULL); - /* Mark that the radio is being used. */ - set_bit(IVTV_F_I_RADIO_USER, &itv->i_flags); /* Select the correct audio input (i.e. radio tuner) */ ivtv_audio_set_io(itv); if (itv->hw_flags & IVTV_HW_SAA711X) @@ -931,13 +939,8 @@ void ivtv_mute(struct ivtv *itv) void ivtv_unmute(struct ivtv *itv) { - /* initialize or refresh input */ - if (atomic_read(&itv->capturing) == 0) - ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0); - - ivtv_msleep_timeout(100, 0); - if (atomic_read(&itv->capturing)) { + ivtv_msleep_timeout(100, 0); ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12); ivtv_vapi(itv, CX2341X_ENC_MUTE_AUDIO, 1, 0); } diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index cee6c558c69..734f2d2ffa6 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -906,6 +906,9 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void IVTV_DEBUG_INFO("Input unchanged\n"); break; } + if (atomic_read(&itv->capturing) > 0) { + return -EBUSY; + } IVTV_DEBUG_INFO("Changing input from %d to %d\n", itv->active_input, inp); diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index 405e2e3fcb4..0582b9d57c5 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -554,9 +554,10 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) clear_bit(IVTV_F_I_EOS, &itv->i_flags); /* Initialize Digitizer for Capture */ + itv->video_dec_func(itv, VIDIOC_STREAMOFF, 0); + ivtv_msleep_timeout(300, 1); ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0); - - ivtv_msleep_timeout(100, 0); + itv->video_dec_func(itv, VIDIOC_STREAMON, 0); } /* begin_capture */ @@ -713,7 +714,6 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) int cap_type; unsigned long then; int stopmode; - u32 data[CX2341X_MBOX_MAX_DATA]; if (s->v4l2dev == NULL) return -EINVAL; @@ -793,27 +793,9 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) } then = jiffies; - /* Make sure DMA is complete */ - add_wait_queue(&s->waitq, &wait); - do { - /* check if DMA is pending */ - if ((s->type == IVTV_ENC_STREAM_TYPE_MPG) && /* MPG Only */ - (read_reg(IVTV_REG_DMASTATUS) & 0x02)) { - /* Check for last DMA */ - ivtv_vapi_result(itv, data, CX2341X_ENC_GET_SEQ_END, 2, 0, 0); - - if (data[0] == 1) { - IVTV_DEBUG_DMA("%s: Last DMA of size 0x%08x\n", s->name, data[1]); - break; - } - } else if (read_reg(IVTV_REG_DMASTATUS) & 0x02) { - break; - } - } while (!ivtv_msleep_timeout(10, 1) && - then + msecs_to_jiffies(2000) > jiffies); - set_current_state(TASK_RUNNING); - remove_wait_queue(&s->waitq, &wait); + /* Handle any pending interrupts */ + ivtv_msleep_timeout(100, 1); } atomic_dec(&itv->capturing); -- cgit v1.2.3-70-g09d2 From f4071b85ea0ca3bd06f63c330562b4cfdffa8473 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 28 Jul 2007 12:07:12 -0300 Subject: V4L/DVB (6046): ivtv: always steal full frames if out of buffers. When there are no more free buffers, then buffers are stolen from the predma queue. Buffers should be stolen from the head of that queue (which is where the most recently added buffers are) and all buffers belonging to a frame should be stolen. Otherwise 'half-frames' would remain in the queue, which leads to ugly playback and complete sync failure for YUV buffers. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.h | 9 ++++-- drivers/media/video/ivtv/ivtv-fileops.c | 3 +- drivers/media/video/ivtv/ivtv-irq.c | 5 ++- drivers/media/video/ivtv/ivtv-queue.c | 54 +++++++++++++++++++-------------- 4 files changed, 45 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 0a1c16ad10b..f5de2fd01b1 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -356,7 +356,7 @@ struct ivtv_mailbox_data { }; /* per-buffer bit flags */ -#define IVTV_F_B_NEED_BUF_SWAP 0 /* this buffer should be byte swapped */ +#define IVTV_F_B_NEED_BUF_SWAP (1 << 0) /* this buffer should be byte swapped */ /* per-stream, s_flags */ #define IVTV_F_S_DMA_PENDING 0 /* this stream has pending DMA */ @@ -437,7 +437,8 @@ struct ivtv_dma_page_info { struct ivtv_buffer { struct list_head list; dma_addr_t dma_handle; - unsigned long b_flags; + unsigned short b_flags; + unsigned short dma_xfer_cnt; char *buf; u32 bytesused; @@ -487,6 +488,10 @@ struct ivtv_stream { struct ivtv_queue q_dma; /* waiting for DMA */ struct ivtv_queue q_predma; /* waiting for DMA */ + /* DMA xfer counter, buffers belonging to the same DMA + xfer will have the same dma_xfer_cnt. */ + u16 dma_xfer_cnt; + /* Base Dev SG Array for cx23415/6 */ struct ivtv_SG_element *SGarray; struct ivtv_SG_element *PIOarray; diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index 908e640c274..076b0089a2b 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -247,8 +247,9 @@ static struct ivtv_buffer *ivtv_get_buffer(struct ivtv_stream *s, int non_block, /* do we have new data? */ buf = ivtv_dequeue(s, &s->q_full); if (buf) { - if (!test_and_clear_bit(IVTV_F_B_NEED_BUF_SWAP, &buf->b_flags)) + if ((buf->b_flags & IVTV_F_B_NEED_BUF_SWAP) == 0) return buf; + buf->b_flags &= ~IVTV_F_B_NEED_BUF_SWAP; if (s->type == IVTV_ENC_STREAM_TYPE_MPG) /* byteswap MPG data */ ivtv_buf_swap(buf); diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c index a97d55fd227..8644f3dda31 100644 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ b/drivers/media/video/ivtv/ivtv-irq.c @@ -214,6 +214,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA s->SGarray[idx].src = cpu_to_le32(offset); s->SGarray[idx].size = cpu_to_le32(s->buf_size); buf->bytesused = (size < s->buf_size) ? size : s->buf_size; + buf->dma_xfer_cnt = s->dma_xfer_cnt; s->q_predma.bytesused += buf->bytesused; size -= buf->bytesused; @@ -286,7 +287,7 @@ static void dma_post(struct ivtv_stream *s) /* flag byteswap ABCD -> DCBA for MPG & VBI data outside irq */ if (s->type == IVTV_ENC_STREAM_TYPE_MPG || s->type == IVTV_ENC_STREAM_TYPE_VBI) - set_bit(IVTV_F_B_NEED_BUF_SWAP, &buf->b_flags); + buf->b_flags |= IVTV_F_B_NEED_BUF_SWAP; } if (buf) buf->bytesused += s->dma_last_offset; @@ -396,12 +397,14 @@ static void ivtv_dma_enc_start(struct ivtv_stream *s) } itv->vbi.dma_offset = s_vbi->dma_offset; s_vbi->SG_length = 0; + s_vbi->dma_xfer_cnt++; set_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags); IVTV_DEBUG_HI_DMA("include DMA for %s\n", s->name); } /* Mark last buffer size for Interrupt flag */ s->SGarray[s->SG_length - 1].size |= cpu_to_le32(0x80000000); + s->dma_xfer_cnt++; if (s->type == IVTV_ENC_STREAM_TYPE_VBI) set_bit(IVTV_F_I_ENC_VBI, &itv->i_flags); diff --git a/drivers/media/video/ivtv/ivtv-queue.c b/drivers/media/video/ivtv/ivtv-queue.c index a04f9387f63..bff75aeee0a 100644 --- a/drivers/media/video/ivtv/ivtv-queue.c +++ b/drivers/media/video/ivtv/ivtv-queue.c @@ -60,6 +60,7 @@ void ivtv_enqueue(struct ivtv_stream *s, struct ivtv_buffer *buf, struct ivtv_qu buf->bytesused = 0; buf->readpos = 0; buf->b_flags = 0; + buf->dma_xfer_cnt = 0; } spin_lock_irqsave(&s->qlock, flags); list_add_tail(&buf->list, &q->list); @@ -87,7 +88,7 @@ struct ivtv_buffer *ivtv_dequeue(struct ivtv_stream *s, struct ivtv_queue *q) } static void ivtv_queue_move_buf(struct ivtv_stream *s, struct ivtv_queue *from, - struct ivtv_queue *to, int clear, int full) + struct ivtv_queue *to, int clear) { struct ivtv_buffer *buf = list_entry(from->list.next, struct ivtv_buffer, list); @@ -97,13 +98,7 @@ static void ivtv_queue_move_buf(struct ivtv_stream *s, struct ivtv_queue *from, from->bytesused -= buf->bytesused - buf->readpos; /* special handling for q_free */ if (clear) - buf->bytesused = buf->readpos = buf->b_flags = 0; - else if (full) { - /* special handling for stolen buffers, assume - all bytes are used. */ - buf->bytesused = s->buf_size; - buf->readpos = buf->b_flags = 0; - } + buf->bytesused = buf->readpos = buf->b_flags = buf->dma_xfer_cnt = 0; to->buffers++; to->length += s->buf_size; to->bytesused += buf->bytesused - buf->readpos; @@ -112,7 +107,7 @@ static void ivtv_queue_move_buf(struct ivtv_stream *s, struct ivtv_queue *from, /* Move 'needed_bytes' worth of buffers from queue 'from' into queue 'to'. If 'needed_bytes' == 0, then move all buffers from 'from' into 'to'. If 'steal' != NULL, then buffers may also taken from that queue if - needed. + needed, but only if 'from' is the free queue. The buffer is automatically cleared if it goes to the free queue. It is also cleared if buffers need to be taken from the 'steal' queue and @@ -133,7 +128,7 @@ int ivtv_queue_move(struct ivtv_stream *s, struct ivtv_queue *from, struct ivtv_ int rc = 0; int from_free = from == &s->q_free; int to_free = to == &s->q_free; - int bytes_available; + int bytes_available, bytes_steal; spin_lock_irqsave(&s->qlock, flags); if (needed_bytes == 0) { @@ -142,32 +137,47 @@ int ivtv_queue_move(struct ivtv_stream *s, struct ivtv_queue *from, struct ivtv_ } bytes_available = from_free ? from->length : from->bytesused; - bytes_available += steal ? steal->length : 0; + bytes_steal = (from_free && steal) ? steal->length : 0; - if (bytes_available < needed_bytes) { + if (bytes_available + bytes_steal < needed_bytes) { spin_unlock_irqrestore(&s->qlock, flags); return -ENOMEM; } + while (bytes_available < needed_bytes) { + struct ivtv_buffer *buf = list_entry(steal->list.prev, struct ivtv_buffer, list); + u16 dma_xfer_cnt = buf->dma_xfer_cnt; + + /* move buffers from the tail of the 'steal' queue to the tail of the + 'from' queue. Always copy all the buffers with the same dma_xfer_cnt + value, this ensures that you do not end up with partial frame data + if one frame is stored in multiple buffers. */ + while (dma_xfer_cnt == buf->dma_xfer_cnt) { + list_move_tail(steal->list.prev, &from->list); + rc++; + steal->buffers--; + steal->length -= s->buf_size; + steal->bytesused -= buf->bytesused - buf->readpos; + buf->bytesused = buf->readpos = buf->b_flags = buf->dma_xfer_cnt = 0; + from->buffers++; + from->length += s->buf_size; + bytes_available += s->buf_size; + if (list_empty(&steal->list)) + break; + buf = list_entry(steal->list.prev, struct ivtv_buffer, list); + } + } if (from_free) { u32 old_length = to->length; while (to->length - old_length < needed_bytes) { - if (list_empty(&from->list)) - from = steal; - if (from == steal) - rc++; /* keep track of 'stolen' buffers */ - ivtv_queue_move_buf(s, from, to, 1, 0); + ivtv_queue_move_buf(s, from, to, 1); } } else { u32 old_bytesused = to->bytesused; while (to->bytesused - old_bytesused < needed_bytes) { - if (list_empty(&from->list)) - from = steal; - if (from == steal) - rc++; /* keep track of 'stolen' buffers */ - ivtv_queue_move_buf(s, from, to, to_free, rc); + ivtv_queue_move_buf(s, from, to, to_free); } } spin_unlock_irqrestore(&s->qlock, flags); -- cgit v1.2.3-70-g09d2 From 37093b1ea600d84fbf7252baf12eedec85ae40f1 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 28 Jul 2007 19:45:50 -0300 Subject: V4L/DVB (6047): ivtv: Fix scatter/gather DMA timeouts It turns out that the cx23415/6 DMA engine cannot do scatter/gather DMA reliably. Every so often depending on the phase of the moon and your hardware configuration the cx2341x DMA engine simply chokes on it and you have to reboot to get it working again. This change replaced the scatter/gather DMA by single transfers at a time, where the driver is now responsible for DMA-ing each buffer. UDMA is still done using scatter/gather DMA, that will be fixed soon. Many thanks to Mark Bryars for discovering the link between scatter/gather and the DMA timeouts. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.h | 22 +-- drivers/media/video/ivtv/ivtv-irq.c | 234 +++++++++++++++++++------------- drivers/media/video/ivtv/ivtv-queue.c | 63 +++++---- drivers/media/video/ivtv/ivtv-queue.h | 8 +- drivers/media/video/ivtv/ivtv-streams.c | 2 +- 5 files changed, 196 insertions(+), 133 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index f5de2fd01b1..e80f9f65a90 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -382,7 +382,6 @@ struct ivtv_mailbox_data { #define IVTV_F_I_RADIO_USER 5 /* The radio tuner is selected */ #define IVTV_F_I_DIG_RST 6 /* Reset digitizer */ #define IVTV_F_I_DEC_YUV 7 /* YUV instead of MPG is being decoded */ -#define IVTV_F_I_ENC_VBI 8 /* VBI DMA */ #define IVTV_F_I_UPDATE_CC 9 /* CC should be updated */ #define IVTV_F_I_UPDATE_WSS 10 /* WSS should be updated */ #define IVTV_F_I_UPDATE_VPS 11 /* VPS should be updated */ @@ -405,7 +404,7 @@ struct ivtv_mailbox_data { #define IVTV_F_I_EV_VSYNC_ENABLED 31 /* VSYNC event enabled */ /* Scatter-Gather array element, used in DMA transfers */ -struct ivtv_SG_element { +struct ivtv_sg_element { u32 src; u32 dst; u32 size; @@ -417,7 +416,7 @@ struct ivtv_user_dma { struct page *map[IVTV_DMA_SG_OSD_ENT]; /* Base Dev SG Array for cx23415/6 */ - struct ivtv_SG_element SGarray[IVTV_DMA_SG_OSD_ENT]; + struct ivtv_sg_element SGarray[IVTV_DMA_SG_OSD_ENT]; dma_addr_t SG_handle; int SG_length; @@ -468,6 +467,10 @@ struct ivtv_stream { int dma; /* can be PCI_DMA_TODEVICE, PCI_DMA_FROMDEVICE or PCI_DMA_NONE */ + u32 pending_offset; + u32 pending_backup; + u64 pending_pts; + u32 dma_offset; u32 dma_backup; u64 dma_pts; @@ -493,10 +496,13 @@ struct ivtv_stream { u16 dma_xfer_cnt; /* Base Dev SG Array for cx23415/6 */ - struct ivtv_SG_element *SGarray; - struct ivtv_SG_element *PIOarray; - dma_addr_t SG_handle; - int SG_length; + struct ivtv_sg_element *sg_pending; + struct ivtv_sg_element *sg_processing; + struct ivtv_sg_element *sg_dma; + dma_addr_t sg_handle; + int sg_pending_size; + int sg_processing_size; + int sg_processed; /* SG List of Buffers */ struct scatterlist *SGlist; @@ -637,7 +643,6 @@ struct vbi_info { u32 enc_start, enc_size; int fpi; u32 frame; - u32 dma_offset; u8 cc_data_odd[256]; u8 cc_data_even[256]; int cc_pos; @@ -724,6 +729,7 @@ struct ivtv { int cur_pio_stream; /* index of stream doing PIO */ u32 dma_data_req_offset; u32 dma_data_req_size; + int dma_retries; int output_mode; /* NONE, MPG, YUV, UDMA YUV, passthrough */ spinlock_t lock; /* lock access to this struct */ int search_pack_header; diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c index 8644f3dda31..9695e535616 100644 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ b/drivers/media/video/ivtv/ivtv-irq.c @@ -60,18 +60,18 @@ static void ivtv_pio_work_handler(struct ivtv *itv) buf = list_entry(s->q_dma.list.next, struct ivtv_buffer, list); list_for_each(p, &s->q_dma.list) { struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list); - u32 size = s->PIOarray[i].size & 0x3ffff; + u32 size = s->sg_processing[i].size & 0x3ffff; /* Copy the data from the card to the buffer */ if (s->type == IVTV_DEC_STREAM_TYPE_VBI) { - memcpy_fromio(buf->buf, itv->dec_mem + s->PIOarray[i].src - IVTV_DECODER_OFFSET, size); + memcpy_fromio(buf->buf, itv->dec_mem + s->sg_processing[i].src - IVTV_DECODER_OFFSET, size); } else { - memcpy_fromio(buf->buf, itv->enc_mem + s->PIOarray[i].src, size); + memcpy_fromio(buf->buf, itv->enc_mem + s->sg_processing[i].src, size); } - if (s->PIOarray[i].size & 0x80000000) - break; i++; + if (i == s->sg_processing_size) + break; } write_reg(IVTV_IRQ_ENC_PIO_COMPLETE, 0x44); } @@ -105,7 +105,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA u32 offset, size; u32 UVoffset = 0, UVsize = 0; int skip_bufs = s->q_predma.buffers; - int idx = s->SG_length; + int idx = s->sg_pending_size; int rc; /* sanity checks */ @@ -123,7 +123,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA case IVTV_ENC_STREAM_TYPE_MPG: offset = data[1]; size = data[2]; - s->dma_pts = 0; + s->pending_pts = 0; break; case IVTV_ENC_STREAM_TYPE_YUV: @@ -131,13 +131,13 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA size = data[2]; UVoffset = data[3]; UVsize = data[4]; - s->dma_pts = ((u64) data[5] << 32) | data[6]; + s->pending_pts = ((u64) data[5] << 32) | data[6]; break; case IVTV_ENC_STREAM_TYPE_PCM: offset = data[1] + 12; size = data[2] - 12; - s->dma_pts = read_dec(offset - 8) | + s->pending_pts = read_dec(offset - 8) | ((u64)(read_dec(offset - 12)) << 32); if (itv->has_cx23415) offset += IVTV_DECODER_OFFSET; @@ -150,13 +150,13 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA IVTV_DEBUG_INFO("VBI offset == 0\n"); return -1; } - s->dma_pts = read_enc(offset - 4) | ((u64)read_enc(offset - 8) << 32); + s->pending_pts = read_enc(offset - 4) | ((u64)read_enc(offset - 8) << 32); break; case IVTV_DEC_STREAM_TYPE_VBI: size = read_dec(itv->vbi.dec_start + 4) + 8; offset = read_dec(itv->vbi.dec_start) + itv->vbi.dec_start; - s->dma_pts = 0; + s->pending_pts = 0; offset += IVTV_DECODER_OFFSET; break; default: @@ -165,17 +165,17 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA } /* if this is the start of the DMA then fill in the magic cookie */ - if (s->SG_length == 0) { + if (s->sg_pending_size == 0) { if (itv->has_cx23415 && (s->type == IVTV_ENC_STREAM_TYPE_PCM || s->type == IVTV_DEC_STREAM_TYPE_VBI)) { - s->dma_backup = read_dec(offset - IVTV_DECODER_OFFSET); + s->pending_backup = read_dec(offset - IVTV_DECODER_OFFSET); write_dec_sync(cpu_to_le32(DMA_MAGIC_COOKIE), offset - IVTV_DECODER_OFFSET); } else { - s->dma_backup = read_enc(offset); + s->pending_backup = read_enc(offset); write_enc_sync(cpu_to_le32(DMA_MAGIC_COOKIE), offset); } - s->dma_offset = offset; + s->pending_offset = offset; } bytes_needed = size; @@ -202,7 +202,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA } s->buffers_stolen = rc; - /* got the buffers, now fill in SGarray (DMA) */ + /* got the buffers, now fill in sg_pending */ buf = list_entry(s->q_predma.list.next, struct ivtv_buffer, list); memset(buf->buf, 0, 128); list_for_each(p, &s->q_predma.list) { @@ -210,9 +210,9 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA if (skip_bufs-- > 0) continue; - s->SGarray[idx].dst = cpu_to_le32(buf->dma_handle); - s->SGarray[idx].src = cpu_to_le32(offset); - s->SGarray[idx].size = cpu_to_le32(s->buf_size); + s->sg_pending[idx].dst = buf->dma_handle; + s->sg_pending[idx].src = offset; + s->sg_pending[idx].size = s->buf_size; buf->bytesused = (size < s->buf_size) ? size : s->buf_size; buf->dma_xfer_cnt = s->dma_xfer_cnt; @@ -230,7 +230,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA } idx++; } - s->SG_length = idx; + s->sg_pending_size = idx; return 0; } @@ -332,9 +332,9 @@ void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock) offset = uv_offset; y_done = 1; } - s->SGarray[idx].src = cpu_to_le32(buf->dma_handle); - s->SGarray[idx].dst = cpu_to_le32(offset); - s->SGarray[idx].size = cpu_to_le32(buf->bytesused); + s->sg_pending[idx].src = buf->dma_handle; + s->sg_pending[idx].dst = offset; + s->sg_pending[idx].size = buf->bytesused; offset += buf->bytesused; bytes_written += buf->bytesused; @@ -343,10 +343,7 @@ void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock) ivtv_buf_sync_for_device(s, buf); idx++; } - s->SG_length = idx; - - /* Mark last buffer size for Interrupt flag */ - s->SGarray[s->SG_length - 1].size |= cpu_to_le32(0x80000000); + s->sg_pending_size = idx; /* Sync Hardware SG List of buffers */ ivtv_stream_sync_for_device(s); @@ -362,6 +359,34 @@ void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock) spin_unlock_irqrestore(&itv->dma_reg_lock, flags); } +static void ivtv_dma_enc_start_xfer(struct ivtv_stream *s) +{ + struct ivtv *itv = s->itv; + + s->sg_dma->src = cpu_to_le32(s->sg_processing[s->sg_processed].src); + s->sg_dma->dst = cpu_to_le32(s->sg_processing[s->sg_processed].dst); + s->sg_dma->size = cpu_to_le32(s->sg_processing[s->sg_processed].size | 0x80000000); + s->sg_processed++; + /* Sync Hardware SG List of buffers */ + ivtv_stream_sync_for_device(s); + write_reg(s->sg_handle, IVTV_REG_ENCDMAADDR); + write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x02, IVTV_REG_DMAXFER); +} + +static void ivtv_dma_dec_start_xfer(struct ivtv_stream *s) +{ + struct ivtv *itv = s->itv; + + s->sg_dma->src = cpu_to_le32(s->sg_processing[s->sg_processed].src); + s->sg_dma->dst = cpu_to_le32(s->sg_processing[s->sg_processed].dst); + s->sg_dma->size = cpu_to_le32(s->sg_processing[s->sg_processed].size | 0x80000000); + s->sg_processed++; + /* Sync Hardware SG List of buffers */ + ivtv_stream_sync_for_device(s); + write_reg(s->sg_handle, IVTV_REG_DECDMAADDR); + write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER); +} + /* start the encoder DMA */ static void ivtv_dma_enc_start(struct ivtv_stream *s) { @@ -375,8 +400,7 @@ static void ivtv_dma_enc_start(struct ivtv_stream *s) ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused); if (ivtv_use_dma(s)) - s->SGarray[s->SG_length - 1].size = - cpu_to_le32(le32_to_cpu(s->SGarray[s->SG_length - 1].size) + 256); + s->sg_pending[s->sg_pending_size - 1].size += 256; /* If this is an MPEG stream, and VBI data is also pending, then append the VBI DMA to the MPEG DMA and transfer both sets of data at once. @@ -387,45 +411,39 @@ static void ivtv_dma_enc_start(struct ivtv_stream *s) sure we only use the MPEG DMA to transfer the VBI DMA if both are in use. This way no conflicts occur. */ clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags); - if (s->type == IVTV_ENC_STREAM_TYPE_MPG && s_vbi->SG_length && - s->SG_length + s_vbi->SG_length <= s->buffers) { + if (s->type == IVTV_ENC_STREAM_TYPE_MPG && s_vbi->sg_pending_size && + s->sg_pending_size + s_vbi->sg_pending_size <= s->buffers) { ivtv_queue_move(s_vbi, &s_vbi->q_predma, NULL, &s_vbi->q_dma, s_vbi->q_predma.bytesused); if (ivtv_use_dma(s_vbi)) - s_vbi->SGarray[s_vbi->SG_length - 1].size = cpu_to_le32(le32_to_cpu(s_vbi->SGarray[s->SG_length - 1].size) + 256); - for (i = 0; i < s_vbi->SG_length; i++) { - s->SGarray[s->SG_length++] = s_vbi->SGarray[i]; + s_vbi->sg_pending[s_vbi->sg_pending_size - 1].size += 256; + for (i = 0; i < s_vbi->sg_pending_size; i++) { + s->sg_pending[s->sg_pending_size++] = s_vbi->sg_pending[i]; } - itv->vbi.dma_offset = s_vbi->dma_offset; - s_vbi->SG_length = 0; + s_vbi->dma_offset = s_vbi->pending_offset; + s_vbi->sg_pending_size = 0; s_vbi->dma_xfer_cnt++; set_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags); IVTV_DEBUG_HI_DMA("include DMA for %s\n", s->name); } - /* Mark last buffer size for Interrupt flag */ - s->SGarray[s->SG_length - 1].size |= cpu_to_le32(0x80000000); s->dma_xfer_cnt++; - - if (s->type == IVTV_ENC_STREAM_TYPE_VBI) - set_bit(IVTV_F_I_ENC_VBI, &itv->i_flags); - else - clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags); + memcpy(s->sg_processing, s->sg_pending, sizeof(struct ivtv_sg_element) * s->sg_pending_size); + s->sg_processing_size = s->sg_pending_size; + s->sg_pending_size = 0; + s->sg_processed = 0; + s->dma_offset = s->pending_offset; + s->dma_backup = s->pending_backup; + s->dma_pts = s->pending_pts; if (ivtv_use_pio(s)) { - for (i = 0; i < s->SG_length; i++) { - s->PIOarray[i].src = le32_to_cpu(s->SGarray[i].src); - s->PIOarray[i].size = le32_to_cpu(s->SGarray[i].size); - } set_bit(IVTV_F_I_WORK_HANDLER_PIO, &itv->i_flags); set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags); set_bit(IVTV_F_I_PIO, &itv->i_flags); itv->cur_pio_stream = s->type; } else { - /* Sync Hardware SG List of buffers */ - ivtv_stream_sync_for_device(s); - write_reg(s->SG_handle, IVTV_REG_ENCDMAADDR); - write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x02, IVTV_REG_DMAXFER); + itv->dma_retries = 0; + ivtv_dma_enc_start_xfer(s); set_bit(IVTV_F_I_DMA, &itv->i_flags); itv->cur_dma_stream = s->type; itv->dma_timer.expires = jiffies + msecs_to_jiffies(100); @@ -439,10 +457,15 @@ static void ivtv_dma_dec_start(struct ivtv_stream *s) if (s->q_predma.bytesused) ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused); + s->dma_xfer_cnt++; + memcpy(s->sg_processing, s->sg_pending, sizeof(struct ivtv_sg_element) * s->sg_pending_size); + s->sg_processing_size = s->sg_pending_size; + s->sg_pending_size = 0; + s->sg_processed = 0; + IVTV_DEBUG_HI_DMA("start DMA for %s\n", s->name); - /* put SG Handle into register 0x0c */ - write_reg(s->SG_handle, IVTV_REG_DECDMAADDR); - write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER); + itv->dma_retries = 0; + ivtv_dma_dec_start_xfer(s); set_bit(IVTV_F_I_DMA, &itv->i_flags); itv->cur_dma_stream = s->type; itv->dma_timer.expires = jiffies + msecs_to_jiffies(100); @@ -453,27 +476,42 @@ static void ivtv_irq_dma_read(struct ivtv *itv) { struct ivtv_stream *s = NULL; struct ivtv_buffer *buf; - int hw_stream_type; + int hw_stream_type = 0; IVTV_DEBUG_HI_IRQ("DEC DMA READ\n"); - del_timer(&itv->dma_timer); - if (read_reg(IVTV_REG_DMASTATUS) & 0x14) { - IVTV_DEBUG_WARN("DEC DMA ERROR %x\n", read_reg(IVTV_REG_DMASTATUS)); - write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); + if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags) && itv->cur_dma_stream < 0) { + del_timer(&itv->dma_timer); + return; } + if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags)) { - if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) { - s = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV]; - hw_stream_type = 2; + s = &itv->streams[itv->cur_dma_stream]; + ivtv_stream_sync_for_cpu(s); + + if (read_reg(IVTV_REG_DMASTATUS) & 0x14) { + IVTV_DEBUG_WARN("DEC DMA ERROR %x (xfer %d of %d, retry %d)\n", + read_reg(IVTV_REG_DMASTATUS), + s->sg_processed, s->sg_processing_size, itv->dma_retries); + write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); + if (itv->dma_retries == 3) { + itv->dma_retries = 0; + } + else { + /* Retry, starting with the first xfer segment. + Just retrying the current segment is not sufficient. */ + s->sg_processed = 0; + itv->dma_retries++; + } } - else { - s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG]; - hw_stream_type = 0; + if (s->sg_processed < s->sg_processing_size) { + /* DMA next buffer */ + ivtv_dma_dec_start_xfer(s); + return; } + if (s->type == IVTV_DEC_STREAM_TYPE_YUV) + hw_stream_type = 2; IVTV_DEBUG_HI_DMA("DEC DATA READ %s: %d\n", s->name, s->q_dma.bytesused); - ivtv_stream_sync_for_cpu(s); - /* For some reason must kick the firmware, like PIO mode, I think this tells the firmware we are done and the size of the xfer so it can calculate what we need next. @@ -490,6 +528,7 @@ static void ivtv_irq_dma_read(struct ivtv *itv) } wake_up(&s->waitq); } + del_timer(&itv->dma_timer); clear_bit(IVTV_F_I_UDMA, &itv->i_flags); clear_bit(IVTV_F_I_DMA, &itv->i_flags); itv->cur_dma_stream = -1; @@ -501,33 +540,44 @@ static void ivtv_irq_enc_dma_complete(struct ivtv *itv) u32 data[CX2341X_MBOX_MAX_DATA]; struct ivtv_stream *s; - del_timer(&itv->dma_timer); ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, data); - IVTV_DEBUG_HI_IRQ("ENC DMA COMPLETE %x %d\n", data[0], data[1]); - if (test_and_clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags)) - data[1] = 3; - else if (data[1] > 2) + IVTV_DEBUG_HI_IRQ("ENC DMA COMPLETE %x %d (%d)\n", data[0], data[1], itv->cur_dma_stream); + if (itv->cur_dma_stream < 0) { + del_timer(&itv->dma_timer); return; - s = &itv->streams[ivtv_stream_map[data[1]]]; + } + s = &itv->streams[itv->cur_dma_stream]; + ivtv_stream_sync_for_cpu(s); + if (data[0] & 0x18) { - IVTV_DEBUG_WARN("ENC DMA ERROR %x\n", data[0]); + IVTV_DEBUG_WARN("ENC DMA ERROR %x (offset %08x, xfer %d of %d, retry %d)\n", data[0], + s->dma_offset, s->sg_processed, s->sg_processing_size, itv->dma_retries); write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); - ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, data[1]); + if (itv->dma_retries == 3) { + itv->dma_retries = 0; + } + else { + /* Retry, starting with the first xfer segment. + Just retrying the current segment is not sufficient. */ + s->sg_processed = 0; + itv->dma_retries++; + } } - s->SG_length = 0; + if (s->sg_processed < s->sg_processing_size) { + /* DMA next buffer */ + ivtv_dma_enc_start_xfer(s); + return; + } + del_timer(&itv->dma_timer); clear_bit(IVTV_F_I_DMA, &itv->i_flags); itv->cur_dma_stream = -1; dma_post(s); - ivtv_stream_sync_for_cpu(s); if (test_and_clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags)) { - u32 tmp; - s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; - tmp = s->dma_offset; - s->dma_offset = itv->vbi.dma_offset; dma_post(s); - s->dma_offset = tmp; } + s->sg_processing_size = 0; + s->sg_processed = 0; wake_up(&itv->dma_waitq); } @@ -541,8 +591,7 @@ static void ivtv_irq_enc_pio_complete(struct ivtv *itv) } s = &itv->streams[itv->cur_pio_stream]; IVTV_DEBUG_HI_IRQ("ENC PIO COMPLETE %s\n", s->name); - s->SG_length = 0; - clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags); + s->sg_pending_size = 0; clear_bit(IVTV_F_I_PIO, &itv->i_flags); itv->cur_pio_stream = -1; dma_post(s); @@ -554,13 +603,8 @@ static void ivtv_irq_enc_pio_complete(struct ivtv *itv) ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, 2); clear_bit(IVTV_F_I_PIO, &itv->i_flags); if (test_and_clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags)) { - u32 tmp; - s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; - tmp = s->dma_offset; - s->dma_offset = itv->vbi.dma_offset; dma_post(s); - s->dma_offset = tmp; } wake_up(&itv->dma_waitq); } @@ -572,19 +616,23 @@ static void ivtv_irq_dma_err(struct ivtv *itv) del_timer(&itv->dma_timer); ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, data); IVTV_DEBUG_WARN("DMA ERROR %08x %08x %08x %d\n", data[0], data[1], - read_reg(IVTV_REG_DMASTATUS), itv->cur_dma_stream); + read_reg(IVTV_REG_DMASTATUS), itv->cur_dma_stream); + write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags) && itv->cur_dma_stream >= 0 && itv->cur_dma_stream < IVTV_MAX_STREAMS) { struct ivtv_stream *s = &itv->streams[itv->cur_dma_stream]; /* retry */ - write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) ivtv_dma_dec_start(s); else ivtv_dma_enc_start(s); return; } + if (test_bit(IVTV_F_I_UDMA, &itv->i_flags)) { + ivtv_udma_start(itv); + return; + } clear_bit(IVTV_F_I_UDMA, &itv->i_flags); clear_bit(IVTV_F_I_DMA, &itv->i_flags); itv->cur_dma_stream = -1; @@ -628,14 +676,14 @@ static void ivtv_irq_enc_vbi_cap(struct ivtv *itv) DMA the data. Since at most four VBI DMA buffers are available, we just drop the old requests when there are already three requests queued. */ - if (s->SG_length > 2) { + if (s->sg_pending_size > 2) { struct list_head *p; list_for_each(p, &s->q_predma.list) { struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list); ivtv_buf_sync_for_cpu(s, buf); } ivtv_queue_move(s, &s->q_predma, NULL, &s->q_free, 0); - s->SG_length = 0; + s->sg_pending_size = 0; } /* if we can append the data, and the MPEG stream isn't capturing, then start a DMA request for just the VBI data. */ diff --git a/drivers/media/video/ivtv/ivtv-queue.c b/drivers/media/video/ivtv/ivtv-queue.c index bff75aeee0a..d9a1478ca1f 100644 --- a/drivers/media/video/ivtv/ivtv-queue.c +++ b/drivers/media/video/ivtv/ivtv-queue.c @@ -195,7 +195,7 @@ void ivtv_flush_queues(struct ivtv_stream *s) int ivtv_stream_alloc(struct ivtv_stream *s) { struct ivtv *itv = s->itv; - int SGsize = sizeof(struct ivtv_SG_element) * s->buffers; + int SGsize = sizeof(struct ivtv_sg_element) * s->buffers; int i; if (s->buffers == 0) @@ -205,27 +205,33 @@ int ivtv_stream_alloc(struct ivtv_stream *s) s->dma != PCI_DMA_NONE ? "DMA " : "", s->name, s->buffers, s->buf_size, s->buffers * s->buf_size / 1024); - if (ivtv_might_use_pio(s)) { - s->PIOarray = (struct ivtv_SG_element *)kzalloc(SGsize, GFP_KERNEL); - if (s->PIOarray == NULL) { - IVTV_ERR("Could not allocate PIOarray for %s stream\n", s->name); - return -ENOMEM; - } + s->sg_pending = (struct ivtv_sg_element *)kzalloc(SGsize, GFP_KERNEL); + if (s->sg_pending == NULL) { + IVTV_ERR("Could not allocate sg_pending for %s stream\n", s->name); + return -ENOMEM; } + s->sg_pending_size = 0; - /* Allocate DMA SG Arrays */ - s->SGarray = (struct ivtv_SG_element *)kzalloc(SGsize, GFP_KERNEL); - if (s->SGarray == NULL) { - IVTV_ERR("Could not allocate SGarray for %s stream\n", s->name); - if (ivtv_might_use_pio(s)) { - kfree(s->PIOarray); - s->PIOarray = NULL; - } + s->sg_processing = (struct ivtv_sg_element *)kzalloc(SGsize, GFP_KERNEL); + if (s->sg_processing == NULL) { + IVTV_ERR("Could not allocate sg_processing for %s stream\n", s->name); + kfree(s->sg_pending); + s->sg_pending = NULL; + return -ENOMEM; + } + s->sg_processing_size = 0; + + s->sg_dma = (struct ivtv_sg_element *)kzalloc(sizeof(struct ivtv_sg_element), GFP_KERNEL); + if (s->sg_dma == NULL) { + IVTV_ERR("Could not allocate sg_dma for %s stream\n", s->name); + kfree(s->sg_pending); + s->sg_pending = NULL; + kfree(s->sg_processing); + s->sg_processing = NULL; return -ENOMEM; } - s->SG_length = 0; if (ivtv_might_use_dma(s)) { - s->SG_handle = pci_map_single(itv->dev, s->SGarray, SGsize, s->dma); + s->sg_handle = pci_map_single(itv->dev, s->sg_dma, sizeof(struct ivtv_sg_element), s->dma); ivtv_stream_sync_for_cpu(s); } @@ -272,16 +278,19 @@ void ivtv_stream_free(struct ivtv_stream *s) } /* Free SG Array/Lists */ - if (s->SGarray != NULL) { - if (s->SG_handle != IVTV_DMA_UNMAPPED) { - pci_unmap_single(s->itv->dev, s->SG_handle, - sizeof(struct ivtv_SG_element) * s->buffers, PCI_DMA_TODEVICE); - s->SG_handle = IVTV_DMA_UNMAPPED; + if (s->sg_dma != NULL) { + if (s->sg_handle != IVTV_DMA_UNMAPPED) { + pci_unmap_single(s->itv->dev, s->sg_handle, + sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE); + s->sg_handle = IVTV_DMA_UNMAPPED; } - kfree(s->SGarray); - kfree(s->PIOarray); - s->PIOarray = NULL; - s->SGarray = NULL; - s->SG_length = 0; + kfree(s->sg_pending); + kfree(s->sg_processing); + kfree(s->sg_dma); + s->sg_pending = NULL; + s->sg_processing = NULL; + s->sg_dma = NULL; + s->sg_pending_size = 0; + s->sg_processing_size = 0; } } diff --git a/drivers/media/video/ivtv/ivtv-queue.h b/drivers/media/video/ivtv/ivtv-queue.h index 2ed8d548255..14a9f7fe50a 100644 --- a/drivers/media/video/ivtv/ivtv-queue.h +++ b/drivers/media/video/ivtv/ivtv-queue.h @@ -79,13 +79,13 @@ void ivtv_stream_free(struct ivtv_stream *s); static inline void ivtv_stream_sync_for_cpu(struct ivtv_stream *s) { if (ivtv_use_dma(s)) - pci_dma_sync_single_for_cpu(s->itv->dev, s->SG_handle, - sizeof(struct ivtv_SG_element) * s->buffers, PCI_DMA_TODEVICE); + pci_dma_sync_single_for_cpu(s->itv->dev, s->sg_handle, + sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE); } static inline void ivtv_stream_sync_for_device(struct ivtv_stream *s) { if (ivtv_use_dma(s)) - pci_dma_sync_single_for_device(s->itv->dev, s->SG_handle, - sizeof(struct ivtv_SG_element) * s->buffers, PCI_DMA_TODEVICE); + pci_dma_sync_single_for_device(s->itv->dev, s->sg_handle, + sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE); } diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index 0582b9d57c5..d1cc366c2a3 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -154,7 +154,7 @@ static void ivtv_stream_init(struct ivtv *itv, int type) spin_lock_init(&s->qlock); init_waitqueue_head(&s->waitq); s->id = -1; - s->SG_handle = IVTV_DMA_UNMAPPED; + s->sg_handle = IVTV_DMA_UNMAPPED; ivtv_queue_init(&s->q_free); ivtv_queue_init(&s->q_full); ivtv_queue_init(&s->q_dma); -- cgit v1.2.3-70-g09d2 From de870b52be9d52c3dad76c9ea7399cb94abcaa1a Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 29 Jul 2007 15:22:05 -0300 Subject: V4L/DVB (6048): ivtv: fix stop stream locking Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-streams.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index d1cc366c2a3..4272fbc0bc8 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -751,6 +751,9 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) stopmode = 1; } + /* ensure these actions are done only once */ + mutex_lock(&itv->serialize_lock); + /* end_capture */ /* when: 0 = end of GOP 1 = NOW!, type: 0 = mpeg, subtype: 3 = video+audio */ ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, stopmode, cap_type, s->subtype); @@ -803,9 +806,6 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) /* Clear capture and no-read bits */ clear_bit(IVTV_F_S_STREAMING, &s->s_flags); - /* ensure these global cleanup actions are done only once */ - mutex_lock(&itv->serialize_lock); - if (s->type == IVTV_ENC_STREAM_TYPE_VBI) ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VBI_CAP); -- cgit v1.2.3-70-g09d2 From 51a99c0428cc6d3a442eef1c9046099c9383d72b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 18 Aug 2007 15:16:00 -0300 Subject: V4L/DVB (6049): ivtv: fix VBI reinsertion decoding - Invalid VBI packets should result in an empty VBI frame, not in an zero-sized frame that causes the reader to incorrectly return a 0 (EOF) value. - PIO completion should not reset the sg_pending_size field. - The DMA offset detection code should be ignored for PIO transfers: it somehow messes up the data on the card and is not needed anyway for PIO. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-irq.c | 5 ++--- drivers/media/video/ivtv/ivtv-vbi.c | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c index 9695e535616..7272f1a71dd 100644 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ b/drivers/media/video/ivtv/ivtv-irq.c @@ -165,7 +165,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA } /* if this is the start of the DMA then fill in the magic cookie */ - if (s->sg_pending_size == 0) { + if (s->sg_pending_size == 0 && ivtv_use_dma(s)) { if (itv->has_cx23415 && (s->type == IVTV_ENC_STREAM_TYPE_PCM || s->type == IVTV_DEC_STREAM_TYPE_VBI)) { s->pending_backup = read_dec(offset - IVTV_DECODER_OFFSET); @@ -252,7 +252,7 @@ static void dma_post(struct ivtv_stream *s) /* Sync Buffer */ ivtv_buf_sync_for_cpu(s, buf); - if (x == 0) { + if (x == 0 && ivtv_use_dma(s)) { offset = s->dma_last_offset; if (u32buf[offset / 4] != DMA_MAGIC_COOKIE) { @@ -591,7 +591,6 @@ static void ivtv_irq_enc_pio_complete(struct ivtv *itv) } s = &itv->streams[itv->cur_pio_stream]; IVTV_DEBUG_HI_IRQ("ENC PIO COMPLETE %s\n", s->name); - s->sg_pending_size = 0; clear_bit(IVTV_F_I_PIO, &itv->i_flags); itv->cur_pio_stream = -1; dma_post(s); diff --git a/drivers/media/video/ivtv/ivtv-vbi.c b/drivers/media/video/ivtv/ivtv-vbi.c index a7282a91bd9..a58c833c2b0 100644 --- a/drivers/media/video/ivtv/ivtv-vbi.c +++ b/drivers/media/video/ivtv/ivtv-vbi.c @@ -163,8 +163,8 @@ static int ivtv_convert_ivtv_vbi(struct ivtv *itv, u8 *p) linemask[1] = 0xf; p += 4; } else { - /* unknown VBI data stream */ - return 0; + /* unknown VBI data, convert to empty VBI frame */ + linemask[0] = linemask[1] = 0; } for (i = 0; i < 36; i++) { int err = 0; -- cgit v1.2.3-70-g09d2 From e17a06badaedba89fad989eed409661c89a22e04 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 18 Aug 2007 15:48:42 -0300 Subject: V4L/DVB (6050): ivtv: retry/timer improvements - Give up frame after three retries. - When the last capture/decode ends, make sure to delete the dma_timer. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-irq.c | 4 ++++ drivers/media/video/ivtv/ivtv-streams.c | 2 ++ 2 files changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c index 7272f1a71dd..d68853fd60a 100644 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ b/drivers/media/video/ivtv/ivtv-irq.c @@ -494,7 +494,9 @@ static void ivtv_irq_dma_read(struct ivtv *itv) s->sg_processed, s->sg_processing_size, itv->dma_retries); write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); if (itv->dma_retries == 3) { + /* Too many retries, give up on this frame */ itv->dma_retries = 0; + s->sg_processed = s->sg_processing_size; } else { /* Retry, starting with the first xfer segment. @@ -554,7 +556,9 @@ static void ivtv_irq_enc_dma_complete(struct ivtv *itv) s->dma_offset, s->sg_processed, s->sg_processing_size, itv->dma_retries); write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); if (itv->dma_retries == 3) { + /* Too many retries, give up on this frame */ itv->dma_retries = 0; + s->sg_processed = s->sg_processing_size; } else { /* Retry, starting with the first xfer segment. diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index 4272fbc0bc8..2e632014c90 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -816,6 +816,7 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) /* Set the following Interrupt mask bits for capture */ ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE); + del_timer(&itv->dma_timer); /* event notification (off) */ if (test_and_clear_bit(IVTV_F_I_DIG_RST, &itv->i_flags)) { @@ -873,6 +874,7 @@ int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts) ivtv_vapi(itv, CX2341X_DEC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_DEC_AUD_MODE_CHG, -1); ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_DECODE); + del_timer(&itv->dma_timer); clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags); clear_bit(IVTV_F_S_STREAMING, &s->s_flags); -- cgit v1.2.3-70-g09d2 From 8267761881d6bb91c168ba4d629b778cf106c485 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 7 Aug 2007 07:16:07 -0300 Subject: V4L/DVB (6051): cx25840: make proper use of SOFT_RESET Whenever the 0x80b register is used the microcontroller should be reset. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx25840/cx25840-audio.c | 22 ++++++++++------------ drivers/media/video/cx25840/cx25840-core.c | 7 ++----- 2 files changed, 12 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx25840/cx25840-audio.c b/drivers/media/video/cx25840/cx25840-audio.c index f93b5160bb4..3d46a776df3 100644 --- a/drivers/media/video/cx25840/cx25840-audio.c +++ b/drivers/media/video/cx25840/cx25840-audio.c @@ -157,13 +157,12 @@ void cx25840_audio_set_path(struct i2c_client *client) { struct cx25840_state *state = i2c_get_clientdata(client); + /* assert soft reset */ + cx25840_and_or(client, 0x810, ~0x1, 0x01); + /* stop microcontroller */ cx25840_and_or(client, 0x803, ~0x10, 0); - /* assert soft reset */ - if (!state->is_cx25836) - cx25840_and_or(client, 0x810, ~0x1, 0x01); - /* Mute everything to prevent the PFFT! */ cx25840_write(client, 0x8d3, 0x1f); @@ -181,15 +180,14 @@ void cx25840_audio_set_path(struct i2c_client *client) set_audclk_freq(client, state->audclk_freq); - /* deassert soft reset */ - if (!state->is_cx25836) - cx25840_and_or(client, 0x810, ~0x1, 0x00); - if (state->aud_input != CX25840_AUDIO_SERIAL) { /* When the microcontroller detects the * audio format, it will unmute the lines */ cx25840_and_or(client, 0x803, ~0x10, 0x10); } + + /* deassert soft reset */ + cx25840_and_or(client, 0x810, ~0x1, 0x00); } static int get_volume(struct i2c_client *client) @@ -330,18 +328,18 @@ int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg) switch (cmd) { case VIDIOC_INT_AUDIO_CLOCK_FREQ: + if (!state->is_cx25836) + cx25840_and_or(client, 0x810, ~0x1, 1); if (state->aud_input != CX25840_AUDIO_SERIAL) { cx25840_and_or(client, 0x803, ~0x10, 0); cx25840_write(client, 0x8d3, 0x1f); } - if (!state->is_cx25836) - cx25840_and_or(client, 0x810, ~0x1, 1); retval = set_audclk_freq(client, *(u32 *)arg); - if (!state->is_cx25836) - cx25840_and_or(client, 0x810, ~0x1, 0); if (state->aud_input != CX25840_AUDIO_SERIAL) { cx25840_and_or(client, 0x803, ~0x10, 0x10); } + if (!state->is_cx25836) + cx25840_and_or(client, 0x810, ~0x1, 0); return retval; case VIDIOC_G_CTRL: diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 8f9c32613b4..ae90d1c3d12 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -250,6 +250,7 @@ static void input_change(struct i2c_client *client) } cx25840_and_or(client, 0x401, ~0x60, 0); cx25840_and_or(client, 0x401, ~0x60, 0x60); + cx25840_and_or(client, 0x810, ~0x01, 1); if (state->radio) { cx25840_write(client, 0x808, 0xf9); @@ -284,11 +285,7 @@ static void input_change(struct i2c_client *client) cx25840_write(client, 0x80b, 0x10); } - if (cx25840_read(client, 0x803) & 0x10) { - /* restart audio decoder microcontroller */ - cx25840_and_or(client, 0x803, ~0x10, 0x00); - cx25840_and_or(client, 0x803, ~0x10, 0x10); - } + cx25840_and_or(client, 0x810, ~0x01, 0); } static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input, -- cgit v1.2.3-70-g09d2 From 2ce55b606b29c6ab0c8583772f6807b49cc89372 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 19 Aug 2007 05:09:37 -0300 Subject: V4L/DVB (6053): ivtv: setup TV output standard on init to prevent flicker The TV output standard was set only on first use, which meant that the saa7127 was set to NTSC until then, leading to flickering on PAL systems. Since the saa7127 has no firmware it is OK to initialize it immediately. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 198e443e8a5..8086c62e754 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -1145,6 +1145,10 @@ static int __devinit ivtv_probe(struct pci_dev *dev, are not. */ itv->tuner_std = itv->std; + if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { + ivtv_call_i2c_clients(itv, VIDIOC_INT_S_STD_OUTPUT, &itv->std); + } + retval = ivtv_streams_setup(itv); if (retval) { IVTV_ERR("Error %d setting up streams\n", retval); -- cgit v1.2.3-70-g09d2 From 313e91e824c0c595dec3740c0c87f55eea6bdb3f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 19 Aug 2007 05:32:33 -0300 Subject: V4L/DVB (6054): ivtv: specify some stream sizes in kB instead of MB Some streams (PCM, VBI decoding) do not need that much memory, so specify the allocated memory in kB instead of MB to limit memory usage. E.g. 1 MB is overkill for the VBI decoding stream, 64 kB is enough. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.c | 18 +++++++++--------- drivers/media/video/ivtv/ivtv-driver.h | 8 +++++--- drivers/media/video/ivtv/ivtv-streams.c | 14 +++++++------- 3 files changed, 21 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 8086c62e754..3591518ed35 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -208,7 +208,7 @@ MODULE_PARM_DESC(enc_vbi_buffers, "Encoder VBI Buffers (in MB)\n" "\t\t\tDefault: " __stringify(IVTV_DEFAULT_ENC_VBI_BUFFERS)); MODULE_PARM_DESC(enc_pcm_buffers, - "Encoder PCM buffers (in MB)\n" + "Encoder PCM buffers (in kB)\n" "\t\t\tDefault: " __stringify(IVTV_DEFAULT_ENC_PCM_BUFFERS)); MODULE_PARM_DESC(dec_mpg_buffers, "Decoder MPG buffers (in MB)\n" @@ -217,7 +217,7 @@ MODULE_PARM_DESC(dec_yuv_buffers, "Decoder YUV buffers (in MB)\n" "\t\t\tDefault: " __stringify(IVTV_DEFAULT_DEC_YUV_BUFFERS)); MODULE_PARM_DESC(dec_vbi_buffers, - "Decoder VBI buffers (in MB)\n" + "Decoder VBI buffers (in kB)\n" "\t\t\tDefault: " __stringify(IVTV_DEFAULT_DEC_VBI_BUFFERS)); MODULE_PARM_DESC(newi2c, "Use new I2C implementation\n" @@ -547,13 +547,13 @@ static void ivtv_process_options(struct ivtv *itv) const char *chipname; int i, j; - itv->options.megabytes[IVTV_ENC_STREAM_TYPE_MPG] = enc_mpg_buffers; - itv->options.megabytes[IVTV_ENC_STREAM_TYPE_YUV] = enc_yuv_buffers; - itv->options.megabytes[IVTV_ENC_STREAM_TYPE_VBI] = enc_vbi_buffers; - itv->options.megabytes[IVTV_ENC_STREAM_TYPE_PCM] = enc_pcm_buffers; - itv->options.megabytes[IVTV_DEC_STREAM_TYPE_MPG] = dec_mpg_buffers; - itv->options.megabytes[IVTV_DEC_STREAM_TYPE_YUV] = dec_yuv_buffers; - itv->options.megabytes[IVTV_DEC_STREAM_TYPE_VBI] = dec_vbi_buffers; + itv->options.kilobytes[IVTV_ENC_STREAM_TYPE_MPG] = enc_mpg_buffers * 1024; + itv->options.kilobytes[IVTV_ENC_STREAM_TYPE_YUV] = enc_yuv_buffers * 1024; + itv->options.kilobytes[IVTV_ENC_STREAM_TYPE_VBI] = enc_vbi_buffers * 1024; + itv->options.kilobytes[IVTV_ENC_STREAM_TYPE_PCM] = enc_pcm_buffers; + itv->options.kilobytes[IVTV_DEC_STREAM_TYPE_MPG] = dec_mpg_buffers * 1024; + itv->options.kilobytes[IVTV_DEC_STREAM_TYPE_YUV] = dec_yuv_buffers * 1024; + itv->options.kilobytes[IVTV_DEC_STREAM_TYPE_VBI] = dec_vbi_buffers; itv->options.cardtype = cardtype[itv->num]; itv->options.tuner = tuner[itv->num]; itv->options.radio = radio[itv->num]; diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index e80f9f65a90..783fb4449b0 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -186,10 +186,12 @@ extern const u32 yuv_offset[4]; #define IVTV_DEFAULT_ENC_MPG_BUFFERS 4 #define IVTV_DEFAULT_ENC_YUV_BUFFERS 2 #define IVTV_DEFAULT_ENC_VBI_BUFFERS 1 -#define IVTV_DEFAULT_ENC_PCM_BUFFERS 1 +/* Exception: size in kB for this stream (MB is overkill) */ +#define IVTV_DEFAULT_ENC_PCM_BUFFERS 320 #define IVTV_DEFAULT_DEC_MPG_BUFFERS 1 #define IVTV_DEFAULT_DEC_YUV_BUFFERS 1 -#define IVTV_DEFAULT_DEC_VBI_BUFFERS 1 +/* Exception: size in kB for this stream (MB is way overkill) */ +#define IVTV_DEFAULT_DEC_VBI_BUFFERS 64 /* ======================================================================== */ /* ========================== END USER SETTABLE DMA VARIABLES ============= */ @@ -321,7 +323,7 @@ extern int ivtv_debug; struct ivtv_options { - int megabytes[IVTV_MAX_STREAMS]; /* Size in megabytes of each stream */ + int kilobytes[IVTV_MAX_STREAMS]; /* Size in kilobytes of each stream */ int cardtype; /* force card type on load */ int tuner; /* set tuner on load */ int radio; /* enable/disable radio */ diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index 2e632014c90..fab5c51b151 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -150,7 +150,7 @@ static void ivtv_stream_init(struct ivtv *itv, int type) s->dma = ivtv_stream_info[type].dma; s->buf_size = itv->stream_buf_size[type]; if (s->buf_size) - s->buffers = itv->options.megabytes[type] * 1024 * 1024 / s->buf_size; + s->buffers = (itv->options.kilobytes[type] * 1024 + s->buf_size - 1) / s->buf_size; spin_lock_init(&s->qlock); init_waitqueue_head(&s->waitq); s->id = -1; @@ -192,7 +192,7 @@ static int ivtv_reg_dev(struct ivtv *itv, int type) /* User explicitly selected 0 buffers for these streams, so don't create them. */ if (minor >= 0 && ivtv_stream_info[type].dma != PCI_DMA_NONE && - itv->options.megabytes[type] == 0) { + itv->options.kilobytes[type] == 0) { IVTV_INFO("Disabled %s device\n", ivtv_stream_info[type].name); return 0; } @@ -238,18 +238,18 @@ static int ivtv_reg_dev(struct ivtv *itv, int type) switch (vfl_type) { case VFL_TYPE_GRABBER: - IVTV_INFO("Registered device video%d for %s (%d MB)\n", - s->v4l2dev->minor, s->name, itv->options.megabytes[type]); + IVTV_INFO("Registered device video%d for %s (%d kB)\n", + s->v4l2dev->minor, s->name, itv->options.kilobytes[type]); break; case VFL_TYPE_RADIO: IVTV_INFO("Registered device radio%d for %s\n", s->v4l2dev->minor - MINOR_VFL_TYPE_RADIO_MIN, s->name); break; case VFL_TYPE_VBI: - if (itv->options.megabytes[type]) - IVTV_INFO("Registered device vbi%d for %s (%d MB)\n", + if (itv->options.kilobytes[type]) + IVTV_INFO("Registered device vbi%d for %s (%d kB)\n", s->v4l2dev->minor - MINOR_VFL_TYPE_VBI_MIN, - s->name, itv->options.megabytes[type]); + s->name, itv->options.kilobytes[type]); else IVTV_INFO("Registered device vbi%d for %s\n", s->v4l2dev->minor - MINOR_VFL_TYPE_VBI_MIN, s->name); -- cgit v1.2.3-70-g09d2 From 1aa32c2ffd146dddd76babf842e998502f1b993a Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 19 Aug 2007 06:08:58 -0300 Subject: V4L/DVB (6055): ivtv: improve debug messages - add FILE debug flag for open/close/read/write/poll. - show cmd for encoder/decoder command ioctl. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.c | 18 ++++++++--- drivers/media/video/ivtv/ivtv-driver.h | 55 +++++++++++++++++---------------- drivers/media/video/ivtv/ivtv-fileops.c | 18 ++++++----- drivers/media/video/ivtv/ivtv-ioctl.c | 9 ++++-- drivers/media/video/ivtv/ivtv-mailbox.c | 6 ++-- 5 files changed, 64 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 3591518ed35..93ddea49f0e 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -186,8 +186,18 @@ MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60"); MODULE_PARM_DESC(secam, "Set SECAM standard: B, G, H, D, K, L, LC"); MODULE_PARM_DESC(ntsc, "Set NTSC standard: M, J, K"); MODULE_PARM_DESC(debug, - "Debug level (bitmask). Default: errors only\n" - "\t\t\t(debug = 1023 gives full debugging)"); + "Debug level (bitmask). Default: 0\n" + "\t\t\t 1/0x0001: warning\n" + "\t\t\t 2/0x0002: info\n" + "\t\t\t 4/0x0004: mailbox\n" + "\t\t\t 8/0x0008: ioctl\n" + "\t\t\t 16/0x0010: file\n" + "\t\t\t 32/0x0020: dma\n" + "\t\t\t 64/0x0040: irq\n" + "\t\t\t 128/0x0080: decoder\n" + "\t\t\t 256/0x0100: yuv\n" + "\t\t\t 512/0x0200: i2c\n" + "\t\t\t1024/0x0400: high volume\n"); MODULE_PARM_DESC(ivtv_pci_latency, "Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n" "\t\t\tDefault: Yes"); @@ -1354,9 +1364,9 @@ static int module_start(void) return -1; } - if (ivtv_debug < 0 || ivtv_debug > 1023) { + if (ivtv_debug < 0 || ivtv_debug > 2047) { ivtv_debug = 0; - printk(KERN_INFO "ivtv: Debug value must be >= 0 and <= 1023\n"); + printk(KERN_INFO "ivtv: Debug value must be >= 0 and <= 2047\n"); } if (pci_register_driver(&ivtv_pci_driver)) { diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 783fb4449b0..93a008409f4 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -256,17 +256,18 @@ extern const u32 yuv_offset[4]; /* debugging */ -#define IVTV_DBGFLG_WARN (1 << 0) -#define IVTV_DBGFLG_INFO (1 << 1) -#define IVTV_DBGFLG_API (1 << 2) -#define IVTV_DBGFLG_DMA (1 << 3) -#define IVTV_DBGFLG_IOCTL (1 << 4) -#define IVTV_DBGFLG_I2C (1 << 5) -#define IVTV_DBGFLG_IRQ (1 << 6) -#define IVTV_DBGFLG_DEC (1 << 7) -#define IVTV_DBGFLG_YUV (1 << 8) +#define IVTV_DBGFLG_WARN (1 << 0) +#define IVTV_DBGFLG_INFO (1 << 1) +#define IVTV_DBGFLG_MB (1 << 2) +#define IVTV_DBGFLG_IOCTL (1 << 3) +#define IVTV_DBGFLG_FILE (1 << 4) +#define IVTV_DBGFLG_DMA (1 << 5) +#define IVTV_DBGFLG_IRQ (1 << 6) +#define IVTV_DBGFLG_DEC (1 << 7) +#define IVTV_DBGFLG_YUV (1 << 8) +#define IVTV_DBGFLG_I2C (1 << 9) /* Flag to turn on high volume debugging */ -#define IVTV_DBGFLG_HIGHVOL (1 << 9) +#define IVTV_DBGFLG_HIGHVOL (1 << 10) /* NOTE: extra space before comma in 'itv->num , ## args' is required for gcc-2.95, otherwise it won't compile. */ @@ -275,30 +276,32 @@ extern const u32 yuv_offset[4]; if ((x) & ivtv_debug) \ printk(KERN_INFO "ivtv%d " type ": " fmt, itv->num , ## args); \ } while (0) -#define IVTV_DEBUG_WARN(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_WARN, "warning", fmt , ## args) -#define IVTV_DEBUG_INFO(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_INFO, "info",fmt , ## args) -#define IVTV_DEBUG_API(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_API, "api", fmt , ## args) -#define IVTV_DEBUG_DMA(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_DMA, "dma", fmt , ## args) +#define IVTV_DEBUG_WARN(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_WARN, "warn", fmt , ## args) +#define IVTV_DEBUG_INFO(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_INFO, "info", fmt , ## args) +#define IVTV_DEBUG_MB(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_MB, "mb", fmt , ## args) +#define IVTV_DEBUG_DMA(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_DMA, "dma", fmt , ## args) #define IVTV_DEBUG_IOCTL(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_IOCTL, "ioctl", fmt , ## args) -#define IVTV_DEBUG_I2C(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_I2C, "i2c", fmt , ## args) -#define IVTV_DEBUG_IRQ(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_IRQ, "irq", fmt , ## args) -#define IVTV_DEBUG_DEC(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_DEC, "dec", fmt , ## args) -#define IVTV_DEBUG_YUV(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_YUV, "yuv", fmt , ## args) +#define IVTV_DEBUG_FILE(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_FILE, "file", fmt , ## args) +#define IVTV_DEBUG_I2C(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_I2C, "i2c", fmt , ## args) +#define IVTV_DEBUG_IRQ(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_IRQ, "irq", fmt , ## args) +#define IVTV_DEBUG_DEC(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_DEC, "dec", fmt , ## args) +#define IVTV_DEBUG_YUV(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_YUV, "yuv", fmt , ## args) #define IVTV_DEBUG_HIGH_VOL(x, type, fmt, args...) \ do { \ if (((x) & ivtv_debug) && (ivtv_debug & IVTV_DBGFLG_HIGHVOL)) \ printk(KERN_INFO "ivtv%d " type ": " fmt, itv->num , ## args); \ } while (0) -#define IVTV_DEBUG_HI_WARN(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_WARN, "warning", fmt , ## args) -#define IVTV_DEBUG_HI_INFO(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_INFO, "info",fmt , ## args) -#define IVTV_DEBUG_HI_API(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_API, "api", fmt , ## args) -#define IVTV_DEBUG_HI_DMA(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_DMA, "dma", fmt , ## args) +#define IVTV_DEBUG_HI_WARN(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_WARN, "warn", fmt , ## args) +#define IVTV_DEBUG_HI_INFO(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_INFO, "info", fmt , ## args) +#define IVTV_DEBUG_HI_MB(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_MB, "mb", fmt , ## args) +#define IVTV_DEBUG_HI_DMA(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_DMA, "dma", fmt , ## args) #define IVTV_DEBUG_HI_IOCTL(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_IOCTL, "ioctl", fmt , ## args) -#define IVTV_DEBUG_HI_I2C(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_I2C, "i2c", fmt , ## args) -#define IVTV_DEBUG_HI_IRQ(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_IRQ, "irq", fmt , ## args) -#define IVTV_DEBUG_HI_DEC(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_DEC, "dec", fmt , ## args) -#define IVTV_DEBUG_HI_YUV(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_YUV, "yuv", fmt , ## args) +#define IVTV_DEBUG_HI_FILE(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_FILE, "file", fmt , ## args) +#define IVTV_DEBUG_HI_I2C(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_I2C, "i2c", fmt , ## args) +#define IVTV_DEBUG_HI_IRQ(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_IRQ, "irq", fmt , ## args) +#define IVTV_DEBUG_HI_DEC(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_DEC, "dec", fmt , ## args) +#define IVTV_DEBUG_HI_YUV(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_YUV, "yuv", fmt , ## args) /* Standard kernel messages */ #define IVTV_ERR(fmt, args...) printk(KERN_ERR "ivtv%d: " fmt, itv->num , ## args) diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index 076b0089a2b..846e9bfa41f 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -409,7 +409,7 @@ static ssize_t ivtv_read_pos(struct ivtv_stream *s, char __user *ubuf, size_t co ssize_t rc = count ? ivtv_read(s, ubuf, count, non_block) : 0; struct ivtv *itv = s->itv; - IVTV_DEBUG_HI_INFO("read %zd from %s, got %zd\n", count, s->name, rc); + IVTV_DEBUG_HI_FILE("read %zd from %s, got %zd\n", count, s->name, rc); if (rc > 0) pos += rc; return rc; @@ -500,7 +500,7 @@ ssize_t ivtv_v4l2_read(struct file * filp, char __user *buf, size_t count, loff_ struct ivtv_stream *s = &itv->streams[id->type]; int rc; - IVTV_DEBUG_HI_IOCTL("read %zd bytes from %s\n", count, s->name); + IVTV_DEBUG_HI_FILE("read %zd bytes from %s\n", count, s->name); rc = ivtv_start_capture(id); if (rc) @@ -538,7 +538,7 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c int rc; DEFINE_WAIT(wait); - IVTV_DEBUG_HI_IOCTL("write %zd bytes to %s\n", count, s->name); + IVTV_DEBUG_HI_FILE("write %zd bytes to %s\n", count, s->name); if (s->type != IVTV_DEC_STREAM_TYPE_MPG && s->type != IVTV_DEC_STREAM_TYPE_YUV && @@ -646,7 +646,7 @@ retry: to transfer the rest. */ if (count && !(filp->f_flags & O_NONBLOCK)) goto retry; - IVTV_DEBUG_HI_INFO("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused); + IVTV_DEBUG_HI_FILE("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused); return bytes_written; } @@ -658,6 +658,7 @@ unsigned int ivtv_v4l2_dec_poll(struct file *filp, poll_table *wait) int res = 0; /* add stream's waitq to the poll list */ + IVTV_DEBUG_HI_FILE("Decoder poll\n"); poll_wait(filp, &s->waitq, wait); set_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags); @@ -687,9 +688,11 @@ unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait) s->name, rc); return POLLERR; } + IVTV_DEBUG_FILE("Encoder poll started capture\n"); } /* add stream's waitq to the poll list */ + IVTV_DEBUG_HI_FILE("Encoder poll\n"); poll_wait(filp, &s->waitq, wait); if (eof || s->q_full.length) @@ -702,7 +705,7 @@ void ivtv_stop_capture(struct ivtv_open_id *id, int gop_end) struct ivtv *itv = id->itv; struct ivtv_stream *s = &itv->streams[id->type]; - IVTV_DEBUG_IOCTL("close() of %s\n", s->name); + IVTV_DEBUG_FILE("close() of %s\n", s->name); /* 'Unclaim' this stream */ @@ -740,7 +743,7 @@ static void ivtv_stop_decoding(struct ivtv_open_id *id, int flags, u64 pts) struct ivtv *itv = id->itv; struct ivtv_stream *s = &itv->streams[id->type]; - IVTV_DEBUG_IOCTL("close() of %s\n", s->name); + IVTV_DEBUG_FILE("close() of %s\n", s->name); /* Stop decoding */ if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { @@ -772,7 +775,7 @@ int ivtv_v4l2_close(struct inode *inode, struct file *filp) struct ivtv *itv = id->itv; struct ivtv_stream *s = &itv->streams[id->type]; - IVTV_DEBUG_IOCTL("close() of %s\n", s->name); + IVTV_DEBUG_FILE("close %s\n", s->name); v4l2_prio_close(&itv->prio, &id->prio); @@ -855,6 +858,7 @@ int ivtv_v4l2_open(struct inode *inode, struct file *filp) IVTV_ERR("Failed to initialize on minor %d\n", minor); return -ENXIO; } + IVTV_DEBUG_FILE("open %s\n", s->name); if (y == IVTV_DEC_STREAM_TYPE_MPG && test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_YUV].s_flags)) diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index 734f2d2ffa6..2c0f2724133 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -1138,12 +1138,14 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void memset(&enc->raw, 0, sizeof(enc->raw)); switch (enc->cmd) { case V4L2_ENC_CMD_START: + IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_START\n"); enc->flags = 0; if (try) return 0; return ivtv_start_capture(id); case V4L2_ENC_CMD_STOP: + IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n"); enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END; if (try) return 0; @@ -1151,6 +1153,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void return 0; case V4L2_ENC_CMD_PAUSE: + IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n"); enc->flags = 0; if (try) return 0; @@ -1163,6 +1166,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void break; case V4L2_ENC_CMD_RESUME: + IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n"); enc->flags = 0; if (try) return 0; @@ -1174,6 +1178,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void ivtv_unmute(itv); break; default: + IVTV_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd); return -EINVAL; } break; @@ -1408,9 +1413,9 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg) int try = (cmd == VIDEO_TRY_COMMAND); if (try) - IVTV_DEBUG_IOCTL("VIDEO_TRY_COMMAND\n"); + IVTV_DEBUG_IOCTL("VIDEO_TRY_COMMAND %d\n", vc->cmd); else - IVTV_DEBUG_IOCTL("VIDEO_COMMAND\n"); + IVTV_DEBUG_IOCTL("VIDEO_COMMAND %d\n", vc->cmd); return ivtv_video_command(itv, id, vc, try); } diff --git a/drivers/media/video/ivtv/ivtv-mailbox.c b/drivers/media/video/ivtv/ivtv-mailbox.c index 5e3b679202a..b05436da713 100644 --- a/drivers/media/video/ivtv/ivtv-mailbox.c +++ b/drivers/media/video/ivtv/ivtv-mailbox.c @@ -225,15 +225,15 @@ static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[]) } if (args < 0 || args > CX2341X_MBOX_MAX_DATA || cmd < 0 || cmd > 255 || api_info[cmd].name == NULL) { - IVTV_ERR("Invalid API call: cmd = 0x%02x, args = %d\n", cmd, args); + IVTV_ERR("Invalid MB call: cmd = 0x%02x, args = %d\n", cmd, args); return -EINVAL; } if (api_info[cmd].flags & API_HIGH_VOL) { - IVTV_DEBUG_HI_API("API Call: %s\n", api_info[cmd].name); + IVTV_DEBUG_HI_MB("MB Call: %s\n", api_info[cmd].name); } else { - IVTV_DEBUG_API("API Call: %s\n", api_info[cmd].name); + IVTV_DEBUG_MB("MB Call: %s\n", api_info[cmd].name); } /* clear possibly uninitialized part of data array */ -- cgit v1.2.3-70-g09d2 From baa4072d84e7a2e9954121c826d7bb8f1fb66b38 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 19 Aug 2007 07:10:55 -0300 Subject: V4L/DVB (6056): ivtv: move serialization to the fileops level Serialization is now done on the open/close/ioctl level and also when the read/write/poll start an encoder/decoder stream. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-fileops.c | 95 +++++++++++++++++++-------------- drivers/media/video/ivtv/ivtv-ioctl.c | 26 ++++++--- drivers/media/video/ivtv/ivtv-streams.c | 11 ---- 3 files changed, 76 insertions(+), 56 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index 846e9bfa41f..1f3c8d0310f 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -502,7 +502,9 @@ ssize_t ivtv_v4l2_read(struct file * filp, char __user *buf, size_t count, loff_ IVTV_DEBUG_HI_FILE("read %zd bytes from %s\n", count, s->name); + mutex_lock(&itv->serialize_lock); rc = ivtv_start_capture(id); + mutex_unlock(&itv->serialize_lock); if (rc) return rc; return ivtv_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK); @@ -613,7 +615,9 @@ retry: } /* Start decoder (returns 0 if already started) */ + mutex_lock(&itv->serialize_lock); rc = ivtv_start_decoding(id, itv->speed); + mutex_unlock(&itv->serialize_lock); if (rc) { IVTV_DEBUG_WARN("Failed start decode stream %s\n", s->name); @@ -681,8 +685,11 @@ unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait) /* Start a capture if there is none */ if (!eof && !test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { - int rc = ivtv_start_capture(id); + int rc; + mutex_lock(&itv->serialize_lock); + rc = ivtv_start_capture(id); + mutex_unlock(&itv->serialize_lock); if (rc) { IVTV_DEBUG_INFO("Could not start capture for %s (%d)\n", s->name, rc); @@ -788,6 +795,7 @@ int ivtv_v4l2_close(struct inode *inode, struct file *filp) /* 'Unclaim' this stream */ /* Stop radio */ + mutex_lock(&itv->serialize_lock); if (id->type == IVTV_ENC_STREAM_TYPE_RAD) { /* Closing radio device, return to TV mode */ ivtv_mute(itv); @@ -822,53 +830,26 @@ int ivtv_v4l2_close(struct inode *inode, struct file *filp) ivtv_stop_capture(id, 0); } kfree(id); + mutex_unlock(&itv->serialize_lock); return 0; } -int ivtv_v4l2_open(struct inode *inode, struct file *filp) +static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp) { - int x, y = 0; + struct ivtv *itv = s->itv; struct ivtv_open_id *item; - struct ivtv *itv = NULL; - struct ivtv_stream *s = NULL; - int minor = iminor(inode); - /* Find which card this open was on */ - spin_lock(&ivtv_cards_lock); - for (x = 0; itv == NULL && x < ivtv_cards_active; x++) { - /* find out which stream this open was on */ - for (y = 0; y < IVTV_MAX_STREAMS; y++) { - s = &ivtv_cards[x]->streams[y]; - if (s->v4l2dev && s->v4l2dev->minor == minor) { - itv = ivtv_cards[x]; - break; - } - } - } - spin_unlock(&ivtv_cards_lock); - - if (itv == NULL) { - /* Couldn't find a device registered - on that minor, shouldn't happen! */ - IVTV_WARN("No ivtv device found on minor %d\n", minor); - return -ENXIO; - } - - if (ivtv_init_on_first_open(itv)) { - IVTV_ERR("Failed to initialize on minor %d\n", minor); - return -ENXIO; - } IVTV_DEBUG_FILE("open %s\n", s->name); - if (y == IVTV_DEC_STREAM_TYPE_MPG && + if (s->type == IVTV_DEC_STREAM_TYPE_MPG && test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_YUV].s_flags)) return -EBUSY; - if (y == IVTV_DEC_STREAM_TYPE_YUV && + if (s->type == IVTV_DEC_STREAM_TYPE_YUV && test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_MPG].s_flags)) return -EBUSY; - if (y == IVTV_DEC_STREAM_TYPE_YUV) { + if (s->type == IVTV_DEC_STREAM_TYPE_YUV) { if (read_reg(0x82c) == 0) { IVTV_ERR("Tried to open YUV output device but need to send data to mpeg decoder before it can be used\n"); /* return -ENODEV; */ @@ -883,7 +864,7 @@ int ivtv_v4l2_open(struct inode *inode, struct file *filp) return -ENOMEM; } item->itv = itv; - item->type = y; + item->type = s->type; v4l2_prio_open(&itv->prio, &item->prio); item->open_id = itv->open_id++; @@ -925,14 +906,50 @@ int ivtv_v4l2_open(struct inode *inode, struct file *filp) } /* YUV or MPG Decoding Mode? */ - if (y == IVTV_DEC_STREAM_TYPE_MPG) + if (s->type == IVTV_DEC_STREAM_TYPE_MPG) clear_bit(IVTV_F_I_DEC_YUV, &itv->i_flags); - else if (y == IVTV_DEC_STREAM_TYPE_YUV) - { + else if (s->type == IVTV_DEC_STREAM_TYPE_YUV) set_bit(IVTV_F_I_DEC_YUV, &itv->i_flags); + return 0; +} + +int ivtv_v4l2_open(struct inode *inode, struct file *filp) +{ + int res, x, y = 0; + struct ivtv *itv = NULL; + struct ivtv_stream *s = NULL; + int minor = iminor(inode); + + /* Find which card this open was on */ + spin_lock(&ivtv_cards_lock); + for (x = 0; itv == NULL && x < ivtv_cards_active; x++) { + /* find out which stream this open was on */ + for (y = 0; y < IVTV_MAX_STREAMS; y++) { + s = &ivtv_cards[x]->streams[y]; + if (s->v4l2dev && s->v4l2dev->minor == minor) { + itv = ivtv_cards[x]; + break; + } + } } + spin_unlock(&ivtv_cards_lock); - return 0; + if (itv == NULL) { + /* Couldn't find a device registered + on that minor, shouldn't happen! */ + IVTV_WARN("No ivtv device found on minor %d\n", minor); + return -ENXIO; + } + + mutex_lock(&itv->serialize_lock); + if (ivtv_init_on_first_open(itv)) { + IVTV_ERR("Failed to initialize on minor %d\n", minor); + mutex_unlock(&itv->serialize_lock); + return -ENXIO; + } + res = ivtv_serialized_open(s, filp); + mutex_unlock(&itv->serialize_lock); + return res; } void ivtv_mute(struct ivtv *itv) diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index 2c0f2724133..2061d82653f 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -1446,11 +1446,15 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg) return 0; if (nonblocking) return -EAGAIN; - /* wait for event */ + /* Wait for event. Note that serialize_lock is locked, + so to allow other processes to access the driver while + we are waiting unlock first and later lock again. */ + mutex_unlock(&itv->serialize_lock); prepare_to_wait(&itv->event_waitq, &wait, TASK_INTERRUPTIBLE); if ((itv->i_flags & (IVTV_F_I_EV_DEC_STOPPED|IVTV_F_I_EV_VSYNC)) == 0) schedule(); finish_wait(&itv->event_waitq, &wait); + mutex_lock(&itv->serialize_lock); if (signal_pending(current)) { /* return if a signal was received */ IVTV_DEBUG_INFO("User stopped wait for event\n"); @@ -1580,12 +1584,9 @@ static int ivtv_v4l2_do_ioctl(struct inode *inode, struct file *filp, return 0; } -int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) +static int ivtv_serialized_ioctl(struct ivtv *itv, struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) { - struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data; - struct ivtv *itv = id->itv; - /* Filter dvb ioctls that cannot be handled by video_usercopy */ switch (cmd) { case VIDEO_SELECT_SOURCE: @@ -1620,3 +1621,16 @@ int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, } return video_usercopy(inode, filp, cmd, arg, ivtv_v4l2_do_ioctl); } + +int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data; + struct ivtv *itv = id->itv; + int res; + + mutex_lock(&itv->serialize_lock); + res = ivtv_serialized_ioctl(itv, inode, filp, cmd, arg); + mutex_unlock(&itv->serialize_lock); + return res; +} diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index fab5c51b151..65fa247e33c 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -437,9 +437,6 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) if (s->v4l2dev == NULL) return -EINVAL; - /* Big serialization lock to ensure no two streams are started - simultaneously: that can give all sorts of weird results. */ - mutex_lock(&itv->serialize_lock); IVTV_DEBUG_INFO("Start encoder stream %s\n", s->name); switch (s->type) { @@ -481,7 +478,6 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) 0, sizeof(itv->vbi.sliced_mpeg_size)); break; default: - mutex_unlock(&itv->serialize_lock); return -EINVAL; } s->subtype = subtype; @@ -564,7 +560,6 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) if (ivtv_vapi(itv, CX2341X_ENC_START_CAPTURE, 2, captype, subtype)) { IVTV_DEBUG_WARN( "Error starting capture!\n"); - mutex_unlock(&itv->serialize_lock); return -EINVAL; } @@ -580,7 +575,6 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) /* you're live! sit back and await interrupts :) */ atomic_inc(&itv->capturing); - mutex_unlock(&itv->serialize_lock); return 0; } @@ -751,9 +745,6 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) stopmode = 1; } - /* ensure these actions are done only once */ - mutex_lock(&itv->serialize_lock); - /* end_capture */ /* when: 0 = end of GOP 1 = NOW!, type: 0 = mpeg, subtype: 3 = video+audio */ ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, stopmode, cap_type, s->subtype); @@ -810,7 +801,6 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VBI_CAP); if (atomic_read(&itv->capturing) > 0) { - mutex_unlock(&itv->serialize_lock); return 0; } @@ -827,7 +817,6 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) } wake_up(&s->waitq); - mutex_unlock(&itv->serialize_lock); return 0; } -- cgit v1.2.3-70-g09d2 From 3869c6a088c2eb165abe476c3372c6a3653649b3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 19 Aug 2007 07:11:44 -0300 Subject: V4L/DVB (6057): ivtv-fb: remove unused header includes Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-fb.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c index d2cc0317274..008076543ac 100644 --- a/drivers/media/video/ivtv/ivtv-fb.c +++ b/drivers/media/video/ivtv/ivtv-fb.c @@ -57,12 +57,8 @@ #endif #include "ivtv-driver.h" -#include "ivtv-queue.h" #include "ivtv-udma.h" -#include "ivtv-irq.h" -#include "ivtv-fileops.h" #include "ivtv-mailbox.h" -#include "ivtv-cards.h" #include /* card parameters */ -- cgit v1.2.3-70-g09d2 From 0989fd2c88a11aa5014b2b348ed51872d14d536d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 19 Aug 2007 12:25:39 -0300 Subject: V4L/DVB (6058): ivtv: add support for highmem udma When trying to DMA userspace buffers to the cx23415 you need to check whether the page is in highmem. If this is the case, then bounce buffers have to be used to allow DMA. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.h | 2 ++ drivers/media/video/ivtv/ivtv-udma.c | 45 ++++++++++++++++++++++++++++------ drivers/media/video/ivtv/ivtv-yuv.c | 9 ++++++- 3 files changed, 47 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 93a008409f4..784098d4bf0 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -419,6 +419,8 @@ struct ivtv_user_dma { struct mutex lock; int page_count; struct page *map[IVTV_DMA_SG_OSD_ENT]; + /* Needed when dealing with highmem userspace buffers */ + struct page *bouncemap[IVTV_DMA_SG_OSD_ENT]; /* Base Dev SG Array for cx23415/6 */ struct ivtv_sg_element SGarray[IVTV_DMA_SG_OSD_ENT]; diff --git a/drivers/media/video/ivtv/ivtv-udma.c b/drivers/media/video/ivtv/ivtv-udma.c index bd642e1aafc..5592abbe14e 100644 --- a/drivers/media/video/ivtv/ivtv-udma.c +++ b/drivers/media/video/ivtv/ivtv-udma.c @@ -38,23 +38,38 @@ void ivtv_udma_get_page_info(struct ivtv_dma_page_info *dma_page, unsigned long int ivtv_udma_fill_sg_list (struct ivtv_user_dma *dma, struct ivtv_dma_page_info *dma_page, int map_offset) { int i, offset; + unsigned long flags; offset = dma_page->offset; /* Fill SG Array with new values */ for (i = 0; i < dma_page->page_count; i++) { - if (i == dma_page->page_count - 1) { - dma->SGlist[map_offset].length = dma_page->tail; + unsigned int len = (i == dma_page->page_count - 1) ? + dma_page->tail : PAGE_SIZE - offset; + + dma->SGlist[map_offset].length = len; + dma->SGlist[map_offset].offset = offset; + if (PageHighMem(dma->map[map_offset])) { + void *src; + + if (dma->bouncemap[map_offset] == NULL) + dma->bouncemap[map_offset] = alloc_page(GFP_KERNEL); + if (dma->bouncemap[map_offset] == NULL) + return -ENOMEM; + local_irq_save(flags); + src = kmap_atomic(dma->map[map_offset], KM_BOUNCE_READ) + offset; + memcpy(page_address(dma->bouncemap[map_offset]) + offset, src, len); + kunmap_atomic(src, KM_BOUNCE_READ); + local_irq_restore(flags); + dma->SGlist[map_offset].page = dma->bouncemap[map_offset]; } else { - dma->SGlist[map_offset].length = PAGE_SIZE - offset; + dma->SGlist[map_offset].page = dma->map[map_offset]; } - dma->SGlist[map_offset].offset = offset; - dma->SGlist[map_offset].page = dma->map[map_offset]; offset = 0; map_offset++; } - return map_offset; + return 0; } void ivtv_udma_fill_sg_array (struct ivtv_user_dma *dma, u32 buffer_offset, u32 buffer_offset_2, u32 split) { @@ -89,7 +104,7 @@ int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr, { struct ivtv_dma_page_info user_dma; struct ivtv_user_dma *dma = &itv->udma; - int err; + int i, err; IVTV_DEBUG_DMA("ivtv_udma_setup, dst: 0x%08x\n", (unsigned int)ivtv_dest_addr); @@ -123,7 +138,14 @@ int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr, dma->page_count = user_dma.page_count; /* Fill SG List with new values */ - ivtv_udma_fill_sg_list(dma, &user_dma, 0); + err = ivtv_udma_fill_sg_list(dma, &user_dma, 0); + if (err) { + for (i = 0; i < dma->page_count; i++) { + put_page(dma->map[i]); + } + dma->page_count = 0; + return err; + } /* Map SG List */ dma->SG_length = pci_map_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE); @@ -166,6 +188,8 @@ void ivtv_udma_unmap(struct ivtv *itv) void ivtv_udma_free(struct ivtv *itv) { + int i; + /* Unmap SG Array */ if (itv->udma.SG_handle) { pci_unmap_single(itv->dev, itv->udma.SG_handle, @@ -176,6 +200,11 @@ void ivtv_udma_free(struct ivtv *itv) if (itv->udma.SG_length) { pci_unmap_sg(itv->dev, itv->udma.SGlist, itv->udma.page_count, PCI_DMA_TODEVICE); } + + for (i = 0; i < IVTV_DMA_SG_OSD_ENT; i++) { + if (itv->udma.bouncemap[i]) + __free_page(itv->udma.bouncemap[i]); + } } void ivtv_udma_start(struct ivtv *itv) diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c index fa8c76f3d35..2ae7556f5e6 100644 --- a/drivers/media/video/ivtv/ivtv-yuv.c +++ b/drivers/media/video/ivtv/ivtv-yuv.c @@ -83,7 +83,14 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, } /* Fill & map SG List */ - ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0)); + if (ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0))) { + IVTV_DEBUG_WARN("could not allocate bounce buffers for highmem userspace buffers\n"); + for (i = 0; i < dma->page_count; i++) { + put_page(dma->map[i]); + } + dma->page_count = 0; + return -ENOMEM; + } dma->SG_length = pci_map_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE); /* Fill SG Array with new values */ -- cgit v1.2.3-70-g09d2 From 25e3f8f40ecf61b87a4b6476ea6d00cb5b74628c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 19 Aug 2007 15:03:05 -0300 Subject: V4L/DVB (6059): ivtv: log stereo/bilingual audio modes Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-ioctl.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index 2061d82653f..de866d450ec 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -1235,7 +1235,8 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void ivtv_get_input(itv, itv->active_input, &vidin); ivtv_get_audio_input(itv, itv->audio_input, &audin); IVTV_INFO("Video Input: %s\n", vidin.name); - IVTV_INFO("Audio Input: %s\n", audin.name); + IVTV_INFO("Audio Input: %s%s\n", audin.name, + (itv->dualwatch_stereo_mode & ~0x300) == 0x200 ? " (Bilingual)" : ""); if (has_output) { struct v4l2_output vidout; struct v4l2_audioout audout; @@ -1247,11 +1248,20 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void "YUV Frames", "Passthrough", }; + static const char * const audio_modes[] = { + "Stereo", + "Left", + "Right", + "Mono", + "Swapped" + }; ivtv_get_output(itv, itv->active_output, &vidout); ivtv_get_audio_output(itv, 0, &audout); IVTV_INFO("Video Output: %s\n", vidout.name); - IVTV_INFO("Audio Output: %s\n", audout.name); + IVTV_INFO("Audio Output: %s (Stereo/Bilingual: %s/%s)\n", audout.name, + audio_modes[itv->audio_stereo_mode], + audio_modes[itv->audio_bilingual_mode]); if (mode < 0 || mode > OUT_PASSTHROUGH) mode = OUT_NONE; IVTV_INFO("Output Mode: %s\n", output_modes[mode]); -- cgit v1.2.3-70-g09d2 From 8beb058f1ecde7bc0554d18ce1baa18b5dfb02d3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 19 Aug 2007 17:56:41 -0300 Subject: V4L/DVB (6060): ivtv: fix IVTV_IOC_DMA_FRAME bug introduced by highmem bugfix The return value of ivtv_udma_fill_sg_list() was changed by the highmem bugfix, but that return value was still used in ivtv-yuv.c. Revert to the old return value, but in addition return -1 in case of a memory allocation error. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-udma.c | 12 +++++++----- drivers/media/video/ivtv/ivtv-yuv.c | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-udma.c b/drivers/media/video/ivtv/ivtv-udma.c index 5592abbe14e..7e503adacea 100644 --- a/drivers/media/video/ivtv/ivtv-udma.c +++ b/drivers/media/video/ivtv/ivtv-udma.c @@ -40,6 +40,9 @@ int ivtv_udma_fill_sg_list (struct ivtv_user_dma *dma, struct ivtv_dma_page_info int i, offset; unsigned long flags; + if (map_offset < 0) + return map_offset; + offset = dma_page->offset; /* Fill SG Array with new values */ @@ -55,7 +58,7 @@ int ivtv_udma_fill_sg_list (struct ivtv_user_dma *dma, struct ivtv_dma_page_info if (dma->bouncemap[map_offset] == NULL) dma->bouncemap[map_offset] = alloc_page(GFP_KERNEL); if (dma->bouncemap[map_offset] == NULL) - return -ENOMEM; + return -1; local_irq_save(flags); src = kmap_atomic(dma->map[map_offset], KM_BOUNCE_READ) + offset; memcpy(page_address(dma->bouncemap[map_offset]) + offset, src, len); @@ -69,7 +72,7 @@ int ivtv_udma_fill_sg_list (struct ivtv_user_dma *dma, struct ivtv_dma_page_info offset = 0; map_offset++; } - return 0; + return map_offset; } void ivtv_udma_fill_sg_array (struct ivtv_user_dma *dma, u32 buffer_offset, u32 buffer_offset_2, u32 split) { @@ -138,13 +141,12 @@ int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr, dma->page_count = user_dma.page_count; /* Fill SG List with new values */ - err = ivtv_udma_fill_sg_list(dma, &user_dma, 0); - if (err) { + if (ivtv_udma_fill_sg_list(dma, &user_dma, 0) < 0) { for (i = 0; i < dma->page_count; i++) { put_page(dma->map[i]); } dma->page_count = 0; - return err; + return -ENOMEM; } /* Map SG List */ diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c index 2ae7556f5e6..1922c1da20d 100644 --- a/drivers/media/video/ivtv/ivtv-yuv.c +++ b/drivers/media/video/ivtv/ivtv-yuv.c @@ -83,7 +83,7 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, } /* Fill & map SG List */ - if (ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0))) { + if (ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0)) < 0) { IVTV_DEBUG_WARN("could not allocate bounce buffers for highmem userspace buffers\n"); for (i = 0; i < dma->page_count; i++) { put_page(dma->map[i]); -- cgit v1.2.3-70-g09d2 From 7c03a4488bf6d28078488c70c82357d4286cacc5 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 19 Aug 2007 18:59:42 -0300 Subject: V4L/DVB (6061): ivtv: add VIDIOC_OVERLAY Add VIDIOC_OVERLAY to enable/disable the OSD. Also add the OSD state to the log status report. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-ioctl.c | 45 ++++++++++++++++++++++++++++----- drivers/media/video/ivtv/ivtv-streams.c | 6 ++--- 2 files changed, 42 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index de866d450ec..ed5707660e0 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -1217,9 +1217,19 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void break; } + case VIDIOC_OVERLAY: { + int *on = arg; + + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) + return -EINVAL; + ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, *on != 0); + break; + } + case VIDIOC_LOG_STATUS: { int has_output = itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT; + u32 data[CX2341X_MBOX_MAX_DATA]; struct v4l2_input vidin; struct v4l2_audio audin; int i; @@ -1234,8 +1244,8 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void ivtv_call_i2c_clients(itv, VIDIOC_LOG_STATUS, NULL); ivtv_get_input(itv, itv->active_input, &vidin); ivtv_get_audio_input(itv, itv->audio_input, &audin); - IVTV_INFO("Video Input: %s\n", vidin.name); - IVTV_INFO("Audio Input: %s%s\n", audin.name, + IVTV_INFO("Video Input: %s\n", vidin.name); + IVTV_INFO("Audio Input: %s%s\n", audin.name, (itv->dualwatch_stereo_mode & ~0x300) == 0x200 ? " (Bilingual)" : ""); if (has_output) { struct v4l2_output vidout; @@ -1255,6 +1265,22 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void "Mono", "Swapped" }; + static const char * const alpha_mode[] = { + "None", + "Global", + "Local", + "Global and Local" + }; + static const char * const pixel_format[] = { + "Indexed", + "RGB 5:6:5", + "ARGB 1:5:5:5", + "ARGB 1:4:4:4", + "ARGB 8:8:8:8", + "5", + "6", + "7", + }; ivtv_get_output(itv, itv->active_output, &vidout); ivtv_get_audio_output(itv, 0, &audout); @@ -1264,12 +1290,17 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void audio_modes[itv->audio_bilingual_mode]); if (mode < 0 || mode > OUT_PASSTHROUGH) mode = OUT_NONE; - IVTV_INFO("Output Mode: %s\n", output_modes[mode]); + IVTV_INFO("Output Mode: %s\n", output_modes[mode]); + ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0); + IVTV_INFO("Overlay: %s, Alpha: %s, Pixel Format: %s\n", + data[0] & 1 ? "On" : "Off", + alpha_mode[(data[0] >> 1) & 0x3], + pixel_format[(data[0] >> 3) & 0x7]); } - IVTV_INFO("Tuner: %s\n", + IVTV_INFO("Tuner: %s\n", test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? "Radio" : "TV"); cx2341x_log_status(&itv->params, itv->name); - IVTV_INFO("Status flags: 0x%08lx\n", itv->i_flags); + IVTV_INFO("Status flags: 0x%08lx\n", itv->i_flags); for (i = 0; i < IVTV_MAX_STREAMS; i++) { struct ivtv_stream *s = &itv->streams[i]; @@ -1279,7 +1310,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void (s->buffers - s->q_free.buffers) * 100 / s->buffers, (s->buffers * s->buf_size) / 1024, s->buffers); } - IVTV_INFO("Read MPEG/VBI: %lld/%lld bytes\n", (long long)itv->mpg_data_received, (long long)itv->vbi_data_inserted); + IVTV_INFO("Read MPG/VBI: %lld/%lld bytes\n", (long long)itv->mpg_data_received, (long long)itv->vbi_data_inserted); IVTV_INFO("================== END STATUS CARD #%d ==================\n", itv->num); break; } @@ -1501,6 +1532,7 @@ static int ivtv_v4l2_do_ioctl(struct inode *inode, struct file *filp, case VIDIOC_S_AUDOUT: case VIDIOC_S_EXT_CTRLS: case VIDIOC_S_FBUF: + case VIDIOC_OVERLAY: ret = v4l2_prio_check(&itv->prio, &id->prio); if (ret) return ret; @@ -1554,6 +1586,7 @@ static int ivtv_v4l2_do_ioctl(struct inode *inode, struct file *filp, case VIDIOC_TRY_ENCODER_CMD: case VIDIOC_G_FBUF: case VIDIOC_S_FBUF: + case VIDIOC_OVERLAY: if (ivtv_debug & IVTV_DBGFLG_IOCTL) { printk(KERN_INFO "ivtv%d ioctl: ", itv->num); v4l_printk_ioctl(cmd); diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index 65fa247e33c..ebf925c549f 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -75,7 +75,7 @@ static struct { struct file_operations *fops; } ivtv_stream_info[] = { { /* IVTV_ENC_STREAM_TYPE_MPG */ - "encoder MPEG", + "encoder MPG", VFL_TYPE_GRABBER, 0, PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, &ivtv_v4l2_enc_fops @@ -93,7 +93,7 @@ static struct { &ivtv_v4l2_enc_fops }, { /* IVTV_ENC_STREAM_TYPE_PCM */ - "encoder PCM audio", + "encoder PCM", VFL_TYPE_GRABBER, IVTV_V4L2_ENC_PCM_OFFSET, PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_PRIVATE, &ivtv_v4l2_enc_fops @@ -105,7 +105,7 @@ static struct { &ivtv_v4l2_enc_fops }, { /* IVTV_DEC_STREAM_TYPE_MPG */ - "decoder MPEG", + "decoder MPG", VFL_TYPE_GRABBER, IVTV_V4L2_DEC_MPG_OFFSET, PCI_DMA_TODEVICE, 0, V4L2_BUF_TYPE_VIDEO_OUTPUT, &ivtv_v4l2_dec_fops -- cgit v1.2.3-70-g09d2 From 8ddac9ee4b6f08d7cacf79202ab882eefc55b0c0 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Sat, 18 Aug 2007 06:57:55 -0300 Subject: V4L/DVB (6064): cx88: Add symbolic names for the PCI interrupt bits Used for the PCI_INTMSK and PCI_INT_STAT registers. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-alsa.c | 16 +++++++++------- drivers/media/video/cx88/cx88-cards.c | 4 +++- drivers/media/video/cx88/cx88-core.c | 2 +- drivers/media/video/cx88/cx88-input.c | 4 ++-- drivers/media/video/cx88/cx88-mpeg.c | 9 +++++---- drivers/media/video/cx88/cx88-reg.h | 22 ++++++++++++++++++++++ drivers/media/video/cx88/cx88-vbi.c | 4 ++-- drivers/media/video/cx88/cx88-video.c | 9 +++++---- 8 files changed, 49 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index 2d666b56020..a529c0a87d1 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -149,9 +149,11 @@ static int _cx88_start_audio_dma(snd_cx88_card_t *chip) /* reset counter */ cx_write(MO_AUDD_GPCNTRL,GP_COUNT_CONTROL_RESET); - dprintk(1,"Enabling IRQ, setting mask from 0x%x to 0x%x\n",chip->core->pci_irqmask,(chip->core->pci_irqmask | 0x02)); + dprintk(1, "Enabling IRQ, setting mask from 0x%x to 0x%x\n", + chip->core->pci_irqmask, + chip->core->pci_irqmask | PCI_INT_AUDINT); /* enable irqs */ - cx_set(MO_PCI_INTMSK, chip->core->pci_irqmask | 0x02); + cx_set(MO_PCI_INTMSK, chip->core->pci_irqmask | PCI_INT_AUDINT); /* Enables corresponding bits at AUD_INT_STAT */ @@ -184,7 +186,7 @@ static int _cx88_stop_audio_dma(snd_cx88_card_t *chip) cx_clear(MO_AUD_DMACNTRL, 0x11); /* disable irqs */ - cx_clear(MO_PCI_INTMSK, 0x02); + cx_clear(MO_PCI_INTMSK, PCI_INT_AUDINT); cx_clear(MO_AUD_INTMSK, (1<<16)| (1<<12)| @@ -273,7 +275,8 @@ static irqreturn_t cx8801_irq(int irq, void *dev_id) int loop, handled = 0; for (loop = 0; loop < MAX_IRQ_LOOP; loop++) { - status = cx_read(MO_PCI_INTSTAT) & (core->pci_irqmask | 0x02); + status = cx_read(MO_PCI_INTSTAT) & + (core->pci_irqmask | PCI_INT_AUDINT); if (0 == status) goto out; dprintk( 3, "cx8801_irq\n" ); @@ -282,8 +285,7 @@ static irqreturn_t cx8801_irq(int irq, void *dev_id) handled = 1; cx_write(MO_PCI_INTSTAT, status); - if (status & 0x02) - { + if (status & PCI_INT_AUDINT) { dprintk( 2, " ALSA IRQ handling\n" ); cx8801_aud_irq(chip); } @@ -293,7 +295,7 @@ static irqreturn_t cx8801_irq(int irq, void *dev_id) dprintk( 0, "clearing mask\n" ); dprintk(1,"%s/0: irq loop -- clearing mask\n", core->name); - cx_clear(MO_PCI_INTMSK,0x02); + cx_clear(MO_PCI_INTMSK, PCI_INT_AUDINT); } out: diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index e73e8c96d5b..a4eb6a87a76 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -2063,7 +2063,9 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr) atomic_inc(&core->refcount); core->pci_bus = pci->bus->number; core->pci_slot = PCI_SLOT(pci->devfn); - core->pci_irqmask = 0x00fc00; + core->pci_irqmask = PCI_INT_RISC_RD_BERRINT | PCI_INT_RISC_WR_BERRINT | + PCI_INT_BRDG_BERRINT | PCI_INT_SRC_DMA_BERRINT | + PCI_INT_DST_DMA_BERRINT | PCI_INT_IPB_DMA_BERRINT; mutex_init(&core->lock); core->nr = nr; diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index 0765e9db533..970926b97ee 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -498,7 +498,7 @@ int cx88_core_irq(struct cx88_core *core, u32 status) { int handled = 0; - if (status & (1<<18)) { + if (status & PCI_INT_IR_SMPINT) { cx88_ir_irq(core); handled++; } diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index 120f56857f0..c78a95ef758 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -167,7 +167,7 @@ static void cx88_ir_start(struct cx88_core *core, struct cx88_IR *ir) schedule_work(&ir->work); } if (ir->sampling) { - core->pci_irqmask |= (1 << 18); /* IR_SMP_INT */ + core->pci_irqmask |= PCI_INT_IR_SMPINT; cx_write(MO_DDS_IO, 0xa80a80); /* 4 kHz sample rate */ cx_write(MO_DDSCFG_IO, 0x5); /* enable */ } @@ -177,7 +177,7 @@ static void cx88_ir_stop(struct cx88_core *core, struct cx88_IR *ir) { if (ir->sampling) { cx_write(MO_DDSCFG_IO, 0x0); - core->pci_irqmask &= ~(1 << 18); + core->pci_irqmask &= ~PCI_INT_IR_SMPINT; } if (ir->polling) { diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index 5da47e251e6..d46114685ed 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -148,7 +148,7 @@ static int cx8802_start_dma(struct cx8802_dev *dev, /* enable irqs */ dprintk( 1, "setting the interrupt mask\n" ); - cx_set(MO_PCI_INTMSK, core->pci_irqmask | 0x04); + cx_set(MO_PCI_INTMSK, core->pci_irqmask | PCI_INT_TSINT); cx_set(MO_TS_INTMSK, 0x1f0011); /* start dma */ @@ -166,7 +166,7 @@ static int cx8802_stop_dma(struct cx8802_dev *dev) cx_clear(MO_TS_DMACNTRL, 0x11); /* disable irqs */ - cx_clear(MO_PCI_INTMSK, 0x000004); + cx_clear(MO_PCI_INTMSK, PCI_INT_TSINT); cx_clear(MO_TS_INTMSK, 0x1f0011); /* Reset the controller */ @@ -413,7 +413,8 @@ static irqreturn_t cx8802_irq(int irq, void *dev_id) int loop, handled = 0; for (loop = 0; loop < MAX_IRQ_LOOP; loop++) { - status = cx_read(MO_PCI_INTSTAT) & (core->pci_irqmask | 0x04); + status = cx_read(MO_PCI_INTSTAT) & + (core->pci_irqmask | PCI_INT_TSINT); if (0 == status) goto out; dprintk( 1, "cx8802_irq\n" ); @@ -424,7 +425,7 @@ static irqreturn_t cx8802_irq(int irq, void *dev_id) if (status & core->pci_irqmask) cx88_core_irq(core,status); - if (status & 0x04) + if (status & PCI_INT_TSINT) cx8802_mpeg_irq(dev); }; if (MAX_IRQ_LOOP == loop) { diff --git a/drivers/media/video/cx88/cx88-reg.h b/drivers/media/video/cx88/cx88-reg.h index d3bf5b17b1d..2b1d102cd22 100644 --- a/drivers/media/video/cx88/cx88-reg.h +++ b/drivers/media/video/cx88/cx88-reg.h @@ -582,6 +582,28 @@ /* ---------------------------------------------------------------------- */ /* various constants */ +// DMA +/* Interrupt mask/status */ +#define PCI_INT_VIDINT (1 << 0) +#define PCI_INT_AUDINT (1 << 1) +#define PCI_INT_TSINT (1 << 2) +#define PCI_INT_VIPINT (1 << 3) +#define PCI_INT_HSTINT (1 << 4) +#define PCI_INT_TM1INT (1 << 5) +#define PCI_INT_SRCDMAINT (1 << 6) +#define PCI_INT_DSTDMAINT (1 << 7) +#define PCI_INT_RISC_RD_BERRINT (1 << 10) +#define PCI_INT_RISC_WR_BERRINT (1 << 11) +#define PCI_INT_BRDG_BERRINT (1 << 12) +#define PCI_INT_SRC_DMA_BERRINT (1 << 13) +#define PCI_INT_DST_DMA_BERRINT (1 << 14) +#define PCI_INT_IPB_DMA_BERRINT (1 << 15) +#define PCI_INT_I2CDONE (1 << 16) +#define PCI_INT_I2CRACK (1 << 17) +#define PCI_INT_IR_SMPINT (1 << 18) +#define PCI_INT_GPIO_INT0 (1 << 19) +#define PCI_INT_GPIO_INT1 (1 << 20) + #define SEL_BTSC 0x01 #define SEL_EIAJ 0x02 #define SEL_A2 0x04 diff --git a/drivers/media/video/cx88/cx88-vbi.c b/drivers/media/video/cx88/cx88-vbi.c index 86c1cf8334b..16c0d36bb6b 100644 --- a/drivers/media/video/cx88/cx88-vbi.c +++ b/drivers/media/video/cx88/cx88-vbi.c @@ -67,7 +67,7 @@ static int cx8800_start_vbi_dma(struct cx8800_dev *dev, q->count = 1; /* enable irqs */ - cx_set(MO_PCI_INTMSK, core->pci_irqmask | 0x01); + cx_set(MO_PCI_INTMSK, core->pci_irqmask | PCI_INT_VIDINT); cx_set(MO_VID_INTMSK, 0x0f0088); /* enable capture */ @@ -91,7 +91,7 @@ int cx8800_stop_vbi_dma(struct cx8800_dev *dev) cx_clear(VID_CAPTURE_CONTROL,0x18); /* disable irqs */ - cx_clear(MO_PCI_INTMSK, 0x000001); + cx_clear(MO_PCI_INTMSK, PCI_INT_VIDINT); cx_clear(MO_VID_INTMSK, 0x0f0088); return 0; } diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index e158ea2454a..e96c688cba9 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -423,7 +423,7 @@ static int start_video_dma(struct cx8800_dev *dev, q->count = 1; /* enable irqs */ - cx_set(MO_PCI_INTMSK, core->pci_irqmask | 0x01); + cx_set(MO_PCI_INTMSK, core->pci_irqmask | PCI_INT_VIDINT); /* Enables corresponding bits at PCI_INT_STAT: bits 0 to 4: video, audio, transport stream, VIP, Host @@ -456,7 +456,7 @@ static int stop_video_dma(struct cx8800_dev *dev) cx_clear(VID_CAPTURE_CONTROL,0x06); /* disable irqs */ - cx_clear(MO_PCI_INTMSK, 0x000001); + cx_clear(MO_PCI_INTMSK, PCI_INT_VIDINT); cx_clear(MO_VID_INTMSK, 0x0f0011); return 0; } @@ -1604,7 +1604,8 @@ static irqreturn_t cx8800_irq(int irq, void *dev_id) int loop, handled = 0; for (loop = 0; loop < 10; loop++) { - status = cx_read(MO_PCI_INTSTAT) & (core->pci_irqmask | 0x01); + status = cx_read(MO_PCI_INTSTAT) & + (core->pci_irqmask | PCI_INT_VIDINT); if (0 == status) goto out; cx_write(MO_PCI_INTSTAT, status); @@ -1612,7 +1613,7 @@ static irqreturn_t cx8800_irq(int irq, void *dev_id) if (status & core->pci_irqmask) cx88_core_irq(core,status); - if (status & 0x01) + if (status & PCI_INT_VIDINT) cx8800_vid_irq(dev); }; if (10 == loop) { -- cgit v1.2.3-70-g09d2 From 5ba862b77e2d7f9e6e2cb133c43be32ac612aea5 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Sat, 18 Aug 2007 07:02:26 -0300 Subject: V4L/DVB (6065): cx88-alsa: Call core irq handler when needed When an irq handled by the cx88 core driver (currently IR and errors) occurs and the cx88-alsa irq handler is the first called, it will claim to have handled the irq but it doesn't call cx88_core_irq() to handle it. The means loading cx88-alsa can disable the IR remote. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-alsa.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index a529c0a87d1..76a8c01208c 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -285,6 +285,8 @@ static irqreturn_t cx8801_irq(int irq, void *dev_id) handled = 1; cx_write(MO_PCI_INTSTAT, status); + if (status & core->pci_irqmask) + cx88_core_irq(core, status); if (status & PCI_INT_AUDINT) { dprintk( 2, " ALSA IRQ handling\n" ); cx8801_aud_irq(chip); -- cgit v1.2.3-70-g09d2 From 59fd8f8d8ee9f7539758419965381bcccfa6f798 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Sat, 18 Aug 2007 22:09:42 -0300 Subject: V4L/DVB (6066): cx88-alsa: Change order of interrupt enabling, fix spurious IRQs Currently the driver turns on audio interrupts, then sets the audio interrupt mask to select which interrupts to get. One could received unwanted interrupts since the mask is set _after_ interrupts have already been turned on. Change the order of the operations, and clear any audio interrupt status bits that are already set for good measure. Before changing the SRAM FIFO parameters, make sure the FIFO isn't being used. This shouldn't happen with just the ALSA driver, as it should never try to turn on FIFO/RISC/DMA while they are already on. However, the V4L driver needs to turn the audio FIFO on for analog audio output to work (undocumented cx88 bug). The FIFO parameters are in an inconsistent state while they are updated, and this results in many FIFO sync error IRQs if the FIFO is in use while it's in this inconsistent state. Also create and use a bunch of symbolic constants for audio interrupt mask bits. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-alsa.c | 42 +++++++++++++++++------------------- drivers/media/video/cx88/cx88-reg.h | 13 +++++++++++ 2 files changed, 33 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index 76a8c01208c..ecb9a74ae03 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -136,12 +136,11 @@ static int _cx88_start_audio_dma(snd_cx88_card_t *chip) struct cx88_core *core=chip->core; struct sram_channel *audio_ch = &cx88_sram_channels[SRAM_CH25]; - - dprintk(1, "Starting audio DMA for %i bytes/line and %i (%i) lines at address %08x\n",buf->bpl, chip->num_periods, audio_ch->fifo_size / buf->bpl, audio_ch->fifo_start); + /* Make sure RISC/FIFO are off before changing FIFO/RISC settings */ + cx_clear(MO_AUD_DMACNTRL, 0x11); /* setup fifo + format - out channel */ - cx88_sram_channel_setup(chip->core, &cx88_sram_channels[SRAM_CH25], - buf->bpl, buf->risc.dma); + cx88_sram_channel_setup(chip->core, audio_ch, buf->bpl, buf->risc.dma); /* sets bpl size */ cx_write(MO_AUDD_LNGTH, buf->bpl); @@ -149,27 +148,30 @@ static int _cx88_start_audio_dma(snd_cx88_card_t *chip) /* reset counter */ cx_write(MO_AUDD_GPCNTRL,GP_COUNT_CONTROL_RESET); + dprintk(1, "Start audio DMA, %d B/line, %d lines/FIFO, %d lines/irq, " + "%d B/irq\n", buf->bpl, cx_read(audio_ch->cmds_start + 8)>>1, + chip->num_periods, buf->bpl * chip->num_periods); + dprintk(1, "Enabling IRQ, setting mask from 0x%x to 0x%x\n", chip->core->pci_irqmask, chip->core->pci_irqmask | PCI_INT_AUDINT); - /* enable irqs */ - cx_set(MO_PCI_INTMSK, chip->core->pci_irqmask | PCI_INT_AUDINT); - /* Enables corresponding bits at AUD_INT_STAT */ - cx_write(MO_AUD_INTMSK, - (1<<16)| - (1<<12)| - (1<<4)| - (1<<0) - ); + cx_write(MO_AUD_INTMSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC | + AUD_INT_DN_RISCI2 | AUD_INT_DN_RISCI1); + + /* Clean any pending interrupt bits already set */ + cx_write(MO_AUD_INTSTAT, ~0); + + /* enable audio irqs */ + cx_set(MO_PCI_INTMSK, chip->core->pci_irqmask | PCI_INT_AUDINT); /* start dma */ cx_set(MO_DEV_CNTRL2, (1<<5)); /* Enables Risc Processor */ cx_set(MO_AUD_DMACNTRL, 0x11); /* audio downstream FIFO and RISC enable */ if (debug) - cx88_sram_channel_dump(chip->core, &cx88_sram_channels[SRAM_CH25]); + cx88_sram_channel_dump(chip->core, audio_ch); return 0; } @@ -187,12 +189,8 @@ static int _cx88_stop_audio_dma(snd_cx88_card_t *chip) /* disable irqs */ cx_clear(MO_PCI_INTMSK, PCI_INT_AUDINT); - cx_clear(MO_AUD_INTMSK, - (1<<16)| - (1<<12)| - (1<<4)| - (1<<0) - ); + cx_clear(MO_AUD_INTMSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC | + AUD_INT_DN_RISCI2 | AUD_INT_DN_RISCI1); if (debug) cx88_sram_channel_dump(chip->core, &cx88_sram_channels[SRAM_CH25]); @@ -239,14 +237,14 @@ static void cx8801_aud_irq(snd_cx88_card_t *chip) cx88_aud_irqs, ARRAY_SIZE(cx88_aud_irqs), status, mask); /* risc op code error */ - if (status & (1 << 16)) { + if (status & AUD_INT_OPC_ERR) { printk(KERN_WARNING "%s/0: audio risc op code error\n",core->name); cx_clear(MO_AUD_DMACNTRL, 0x11); cx88_sram_channel_dump(core, &cx88_sram_channels[SRAM_CH25]); } /* risc1 downstream */ - if (status & 0x01) { + if (status & AUD_INT_DN_RISCI1) { spin_lock(&chip->reg_lock); count = cx_read(MO_AUDD_GPCNT); spin_unlock(&chip->reg_lock); diff --git a/drivers/media/video/cx88/cx88-reg.h b/drivers/media/video/cx88/cx88-reg.h index 2b1d102cd22..2ec52d1cdea 100644 --- a/drivers/media/video/cx88/cx88-reg.h +++ b/drivers/media/video/cx88/cx88-reg.h @@ -612,6 +612,19 @@ #define SEL_FMRADIO 0x20 // AUD_CTL +#define AUD_INT_DN_RISCI1 (1 << 0) +#define AUD_INT_UP_RISCI1 (1 << 1) +#define AUD_INT_RDS_DN_RISCI1 (1 << 2) +#define AUD_INT_DN_RISCI2 (1 << 4) /* yes, 3 is skipped */ +#define AUD_INT_UP_RISCI2 (1 << 5) +#define AUD_INT_RDS_DN_RISCI2 (1 << 6) +#define AUD_INT_DN_SYNC (1 << 12) +#define AUD_INT_UP_SYNC (1 << 13) +#define AUD_INT_RDS_DN_SYNC (1 << 14) +#define AUD_INT_OPC_ERR (1 << 16) +#define AUD_INT_BER_IRQ (1 << 20) +#define AUD_INT_MCHG_IRQ (1 << 21) + #define EN_BTSC_FORCE_MONO 0 #define EN_BTSC_FORCE_STEREO 1 #define EN_BTSC_FORCE_SAP 2 -- cgit v1.2.3-70-g09d2 From 5a5b3b5d4fe3acdd9fb73162023422a9ee0e56f3 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Sat, 18 Aug 2007 21:01:40 -0300 Subject: V4L/DVB (6067): cx88-alsa: Hardware doesn't support mono audio channels_min should be 2, not 1. The hardware only supports stereo. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-alsa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index ecb9a74ae03..3e293da0f70 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -335,7 +335,7 @@ static struct snd_pcm_hardware snd_cx88_digital_hw = { .rates = SNDRV_PCM_RATE_48000, .rate_min = 48000, .rate_max = 48000, - .channels_min = 1, + .channels_min = 2, .channels_max = 2, .buffer_bytes_max = (2*2048), .period_bytes_min = 2048, -- cgit v1.2.3-70-g09d2 From 19453bc18848e842a9743fcc40707e6fb19ae92b Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Sat, 18 Aug 2007 22:54:49 -0300 Subject: V4L/DVB (6068): cx88-alsa: Use pci_dev->revision The revision is part of the pci_dev struct, so there is no need to read it in. Stop storing the revision and latency in the chip struct, since they're never used after being printed out when the driver loads. linux/pci.h wasn't included. It was getting picked up something else, probably cx88.h, but this file uses struct pci_dev so it should include pci.h. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-alsa.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index 3e293da0f70..8d19d33c8b3 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -60,7 +61,6 @@ struct cx88_audio_dev { /* pci i/o */ struct pci_dev *pci; - unsigned char pci_rev,pci_lat; /* audio controls */ int irq; @@ -667,6 +667,7 @@ static int __devinit snd_cx88_create(struct snd_card *card, snd_cx88_card_t *chip; struct cx88_core *core; int err; + unsigned char pci_lat; *rchip = NULL; @@ -711,13 +712,12 @@ static int __devinit snd_cx88_create(struct snd_card *card, } /* print pci info */ - pci_read_config_byte(pci, PCI_CLASS_REVISION, &chip->pci_rev); - pci_read_config_byte(pci, PCI_LATENCY_TIMER, &chip->pci_lat); + pci_read_config_byte(pci, PCI_LATENCY_TIMER, &pci_lat); dprintk(1,"ALSA %s/%i: found at %s, rev: %d, irq: %d, " "latency: %d, mmio: 0x%llx\n", core->name, devno, - pci_name(pci), chip->pci_rev, pci->irq, - chip->pci_lat,(unsigned long long)pci_resource_start(pci,0)); + pci_name(pci), pci->revision, pci->irq, + pci_lat, (unsigned long long)pci_resource_start(pci,0)); chip->irq = pci->irq; synchronize_irq(chip->irq); -- cgit v1.2.3-70-g09d2 From 261f5081a4dbcd148be0a0e744fb454a4f688441 Mon Sep 17 00:00:00 2001 From: Edgar Simo Date: Mon, 20 Aug 2007 14:06:00 -0300 Subject: V4L/DVB (6071): saa7134-dvb: add missing newline This is a simple whitespace cleanup. Signed-off-by: Edgar Simo Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-dvb.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index 1f6bd330071..a0ce67ecb01 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -567,6 +567,7 @@ static void configure_tda827x_fe(struct saa7134_dev *dev, struct tda1004x_config } /* ------------------------------------------------------------------ */ + static struct tda1004x_config tda827x_lifeview_config = { .demod_address = 0x08, .invert = 1, @@ -746,6 +747,7 @@ static struct tda1004x_config asus_p7131_hybrid_lna_config = { .antenna_switch= 2, .request_firmware = philips_tda1004x_request_firmware }; + static struct tda1004x_config kworld_dvb_t_210_config = { .demod_address = 0x08, .invert = 1, @@ -760,6 +762,7 @@ static struct tda1004x_config kworld_dvb_t_210_config = { .antenna_switch= 1, .request_firmware = philips_tda1004x_request_firmware }; + /* ------------------------------------------------------------------ * special case: this card uses saa713x GPIO22 for the mode switch */ -- cgit v1.2.3-70-g09d2 From d90d9f5a0ae9eb80bb3a33472074a114af7e548d Mon Sep 17 00:00:00 2001 From: Edgar Simo Date: Mon, 20 Aug 2007 14:14:50 -0300 Subject: V4L/DVB (6072): saa7134: add DVB-T support for Avermedia Super 007 Add DVB-T support for Avermedia Super 007 Analog television is untested. The device lacks input adapters for radio, svideo & composite -- seems to be a DVB-T ONLY device. Signed-off-by: Edgar Simo Acked-by: Hermann Pitton Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.saa7134 | 1 + drivers/media/video/saa7134/saa7134-cards.c | 23 +++++++++++++++++++++++ drivers/media/video/saa7134/saa7134-dvb.c | 18 ++++++++++++++++++ drivers/media/video/saa7134/saa7134.h | 1 + 4 files changed, 43 insertions(+) (limited to 'drivers') diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134 index 3f8aeab50a1..831b4da48b8 100644 --- a/Documentation/video4linux/CARDLIST.saa7134 +++ b/Documentation/video4linux/CARDLIST.saa7134 @@ -115,3 +115,4 @@ 114 -> KWorld DVB-T 210 [17de:7250] 115 -> Sabrent PCMCIA TV-PCB05 [0919:2003] 116 -> 10MOONS TM300 TV Card [1131:2304] +117 -> Avermedia Super 007 [1461:f01d] diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 25ec1681081..5c3174a62e5 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -3534,6 +3534,22 @@ struct saa7134_board saa7134_boards[] = { .gpio = 0x3000, }, }, + [SAA7134_BOARD_AVERMEDIA_SUPER_007] = { + .name = "Avermedia Super 007", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_TDA8290, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tuner_config = 0, + .mpeg = SAA7134_MPEG_DVB, + .inputs = {{ + .name = name_tv, /* FIXME: analog tv untested */ + .vmux = 1, + .amux = TV, + .tv = 1, + }}, + }, }; const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards); @@ -4256,6 +4272,12 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = PCI_VENDOR_ID_PHILIPS, .subdevice = 0x2304, .driver_data = SAA7134_BOARD_10MOONSTVMASTER3, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x1461, /* Avermedia Technologies Inc */ + .subdevice = 0xf01d, /* AVerTV DVB-T Super 007 */ + .driver_data = SAA7134_BOARD_AVERMEDIA_SUPER_007, },{ /* --- boards without eeprom + subsystem ID --- */ .vendor = PCI_VENDOR_ID_PHILIPS, @@ -4564,6 +4586,7 @@ int saa7134_board_init2(struct saa7134_dev *dev) break; case SAA7134_BOARD_PHILIPS_TIGER: case SAA7134_BOARD_PHILIPS_TIGER_S: + case SAA7134_BOARD_AVERMEDIA_SUPER_007: { u8 data[] = { 0x3c, 0x33, 0x60}; struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index a0ce67ecb01..bbab252cbee 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -763,6 +763,21 @@ static struct tda1004x_config kworld_dvb_t_210_config = { .request_firmware = philips_tda1004x_request_firmware }; +static struct tda1004x_config avermedia_super_007_config = { + .demod_address = 0x08, + .invert = 1, + .invert_oclk = 0, + .xtal_freq = TDA10046_XTAL_16M, + .agc_config = TDA10046_AGC_TDA827X, + .gpio_config = TDA10046_GP01_I, + .if_freq = TDA10046_FREQ_045, + .i2c_gate = 0x4b, + .tuner_address = 0x60, + .tuner_config = 0, + .antenna_switch= 1, + .request_firmware = philips_tda1004x_request_firmware +}; + /* ------------------------------------------------------------------ * special case: this card uses saa713x GPIO22 for the mode switch */ @@ -1025,6 +1040,9 @@ static int dvb_init(struct saa7134_dev *dev) case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA: configure_tda827x_fe(dev, &asus_p7131_hybrid_lna_config); break; + case SAA7134_BOARD_AVERMEDIA_SUPER_007: + configure_tda827x_fe(dev, &avermedia_super_007_config); + break; default: wprintk("Huh? unknown DVB card?\n"); break; diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 346255468da..fd12942b3a1 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -239,6 +239,7 @@ struct saa7134_format { #define SAA7134_BOARD_KWORLD_DVBT_210 114 #define SAA7134_BOARD_SABRENT_TV_PCB05 115 #define SAA7134_BOARD_10MOONSTVMASTER3 116 +#define SAA7134_BOARD_AVERMEDIA_SUPER_007 117 #define SAA7134_MAXBOARDS 8 #define SAA7134_INPUT_MAX 8 -- cgit v1.2.3-70-g09d2 From c996899d0bc2414c7ff4682500344eb912d5ee1d Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 20 Aug 2007 21:04:44 -0300 Subject: V4L/DVB (6074): tuner: fix ifdef tags to match actual file name The file, tuner-driver.h was originally named tuner-hw.h, but we decided to rename it. At the time, I had forgotten to change the #ifdef __TUNER_HW_H__ to #ifdef __TUNER_DRIVER_H__ . This patch corrects that. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-driver.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index fa51b7cec69..145045561a5 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -19,8 +19,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#ifndef __TUNER_HW_H__ -#define __TUNER_HW_H__ +#ifndef __TUNER_DRIVER_H__ +#define __TUNER_DRIVER_H__ #include #include @@ -95,7 +95,7 @@ extern int tea5767_tuner_init(struct i2c_client *c); printk(KERN_DEBUG "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \ i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0) -#endif /* __TUNER_HW_H__ */ +#endif /* __TUNER_DRIVER_H__ */ /* * Overrides for Emacs so that we follow Linus's tabbing style. -- cgit v1.2.3-70-g09d2 From ffbb807c1362a2b64b473c0e093c496a4c7de4bb Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 21 Aug 2007 01:14:12 -0300 Subject: V4L/DVB (6075): tuner: kernel headers go above subsystem headers Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mt20xx.c | 2 +- drivers/media/video/tda8290.c | 2 +- drivers/media/video/tda9887.c | 3 +-- drivers/media/video/tea5761.c | 2 +- drivers/media/video/tea5767.c | 2 +- drivers/media/video/tuner-core.c | 3 +-- drivers/media/video/tuner-simple.c | 1 + 7 files changed, 7 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/mt20xx.c b/drivers/media/video/mt20xx.c index 7549114aaac..210a84d8b97 100644 --- a/drivers/media/video/mt20xx.c +++ b/drivers/media/video/mt20xx.c @@ -5,8 +5,8 @@ */ #include #include -#include #include +#include #include "tuner-driver.h" /* ---------------------------------------------------------------------- */ diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index 59cff5a3c59..760d22f65da 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -19,8 +19,8 @@ */ #include -#include #include +#include #include "tuner-driver.h" /* ---------------------------------------------------------------------- */ diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index aa311e4f1f6..e8597c10aa4 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -3,12 +3,11 @@ #include #include #include -#include #include #include #include #include - +#include #include #include #include "tuner-driver.h" diff --git a/drivers/media/video/tea5761.c b/drivers/media/video/tea5761.c index ae105c2cd0a..43bdc374927 100644 --- a/drivers/media/video/tea5761.c +++ b/drivers/media/video/tea5761.c @@ -8,8 +8,8 @@ */ #include -#include #include +#include #include #include "tuner-driver.h" diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c index 4985d47a508..4c9c4e01331 100644 --- a/drivers/media/video/tea5767.c +++ b/drivers/media/video/tea5767.c @@ -11,8 +11,8 @@ */ #include -#include #include +#include #include "tuner-driver.h" #define PREFIX "TEA5767 " diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index e646465464a..5f378265d8c 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -15,9 +15,8 @@ #include #include #include -#include #include - +#include #include #include #include "tuner-driver.h" diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index 572f22423b9..f1ee60a4aa7 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -5,6 +5,7 @@ */ #include #include +#include #include #include #include -- cgit v1.2.3-70-g09d2 From 5634f2ec809818983f58880e381ee929187e4ddf Mon Sep 17 00:00:00 2001 From: Michal Piotrowski Date: Tue, 21 Aug 2007 12:34:36 -0300 Subject: V4L/DVB (6076): Coding style fix drivers/media/video/zr36060.c Signed-off-by: Michal Piotrowski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/zr36060.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/zr36060.c b/drivers/media/video/zr36060.c index 97c8f9b9dc1..1ef14fef08e 100644 --- a/drivers/media/video/zr36060.c +++ b/drivers/media/video/zr36060.c @@ -38,14 +38,14 @@ #include */ /* I/O commands, error codes */ -#include +#include //#include /* headerfile of this module */ -#include"zr36060.h" +#include "zr36060.h" /* codec io API */ -#include"videocodec.h" +#include "videocodec.h" /* it doesn't make sense to have more than 20 or so, just to prevent some unwanted loops */ -- cgit v1.2.3-70-g09d2 From b9758dfe0a2065f6fe3a484cc26886960aa847c1 Mon Sep 17 00:00:00 2001 From: Michal Piotrowski Date: Tue, 21 Aug 2007 12:34:48 -0300 Subject: V4L/DVB (6077): Coding style fix drivers/media/video/zr36050.c Signed-off-by: Michal Piotrowski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/zr36050.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/zr36050.c b/drivers/media/video/zr36050.c index a6bbd125631..9f622e00c47 100644 --- a/drivers/media/video/zr36050.c +++ b/drivers/media/video/zr36050.c @@ -38,14 +38,14 @@ #include */ /* I/O commands, error codes */ -#include +#include //#include /* headerfile of this module */ -#include"zr36050.h" +#include "zr36050.h" /* codec io API */ -#include"videocodec.h" +#include "videocodec.h" /* it doesn't make sense to have more than 20 or so, just to prevent some unwanted loops */ -- cgit v1.2.3-70-g09d2 From f518b43c452fb2dbe98ee211abfc63cf421927ab Mon Sep 17 00:00:00 2001 From: Michal Piotrowski Date: Tue, 21 Aug 2007 12:36:51 -0300 Subject: V4L/DVB (6078): Coding style fix drivers/media/video/zr36016.c Signed-off-by: Michal Piotrowski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/zr36016.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/zr36016.c b/drivers/media/video/zr36016.c index 62f77584fb8..dd084555da8 100644 --- a/drivers/media/video/zr36016.c +++ b/drivers/media/video/zr36016.c @@ -38,11 +38,11 @@ #include */ /* I/O commands, error codes */ -#include +#include //#include /* v4l API */ -#include +#include /* headerfile of this module */ #include"zr36016.h" -- cgit v1.2.3-70-g09d2 From 9c12224a607a4b22ab86784e3394b52810b9507c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 21 Aug 2007 12:38:39 -0300 Subject: V4L/DVB (6079): Cleanup: remove linux/moduleparam.h from drivers/media files Since at least kernel 2.6.12-rc2, module.h includes moduleparm.h. This patch removes all occurences of moduleparm.h from drivers/media files. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/ir-functions.c | 1 - drivers/media/common/ir-keymaps.c | 1 - drivers/media/dvb/bt8xx/bt878.c | 1 - drivers/media/dvb/bt8xx/dvb-bt8xx.c | 1 - drivers/media/dvb/dvb-core/dmxdev.c | 1 - drivers/media/dvb/dvb-core/dvb_ca_en50221.c | 1 - drivers/media/dvb/dvb-core/dvb_frontend.c | 1 - drivers/media/dvb/dvb-core/dvbdev.c | 1 - drivers/media/dvb/frontends/bcm3510.c | 1 - drivers/media/dvb/frontends/cx22700.c | 1 - drivers/media/dvb/frontends/cx24110.c | 1 - drivers/media/dvb/frontends/cx24123.c | 1 - drivers/media/dvb/frontends/dib3000mb.c | 1 - drivers/media/dvb/frontends/dvb_dummy_fe.c | 1 - drivers/media/dvb/frontends/isl6421.c | 1 - drivers/media/dvb/frontends/l64781.c | 1 - drivers/media/dvb/frontends/lgdt330x.c | 1 - drivers/media/dvb/frontends/lnbp21.c | 1 - drivers/media/dvb/frontends/mt2060.c | 1 - drivers/media/dvb/frontends/mt2131.c | 1 - drivers/media/dvb/frontends/mt2266.c | 1 - drivers/media/dvb/frontends/mt312.c | 1 - drivers/media/dvb/frontends/mt352.c | 1 - drivers/media/dvb/frontends/nxt200x.c | 1 - drivers/media/dvb/frontends/or51132.c | 1 - drivers/media/dvb/frontends/or51211.c | 1 - drivers/media/dvb/frontends/sp8870.c | 1 - drivers/media/dvb/frontends/sp887x.c | 1 - drivers/media/dvb/frontends/stv0299.c | 1 - drivers/media/dvb/frontends/tda1004x.c | 1 - drivers/media/dvb/frontends/tda10086.c | 1 - drivers/media/dvb/frontends/tda8083.c | 1 - drivers/media/dvb/frontends/zl10353.c | 1 - drivers/media/dvb/ttpci/av7110.c | 1 - drivers/media/dvb/ttpci/av7110_ir.c | 1 - drivers/media/dvb/ttpci/budget-core.c | 1 - drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c | 1 - drivers/media/dvb/ttusb-dec/ttusb_dec.c | 1 - drivers/media/video/bt8xx/bttv-cards.c | 1 - drivers/media/video/bt8xx/bttv-driver.c | 1 - drivers/media/video/bt8xx/bttv-i2c.c | 1 - drivers/media/video/bt8xx/bttv-input.c | 1 - drivers/media/video/bt8xx/bttv-vbi.c | 1 - drivers/media/video/btcx-risc.c | 1 - drivers/media/video/cafe_ccic.c | 1 - drivers/media/video/cpia.c | 1 - drivers/media/video/cpia2/cpia2_v4l.c | 1 - drivers/media/video/cx2341x.c | 1 - drivers/media/video/cx88/cx88-blackbird.c | 1 - drivers/media/video/cx88/cx88-core.c | 1 - drivers/media/video/cx88/cx88-i2c.c | 1 - drivers/media/video/cx88/cx88-input.c | 1 - drivers/media/video/cx88/cx88-mpeg.c | 1 - drivers/media/video/cx88/cx88-tvaudio.c | 1 - drivers/media/video/cx88/cx88-vbi.c | 1 - drivers/media/video/cx88/cx88-video.c | 1 - drivers/media/video/cx88/cx88-vp3054-i2c.c | 1 - drivers/media/video/em28xx/em28xx-core.c | 1 - drivers/media/video/em28xx/em28xx-input.c | 1 - drivers/media/video/et61x251/et61x251_core.c | 1 - drivers/media/video/ir-kbd-i2c.c | 1 - drivers/media/video/ivtv/ivtv-driver.h | 1 - drivers/media/video/mt20xx.c | 1 - drivers/media/video/ov7670.c | 1 - drivers/media/video/ovcamchip/ovcamchip_core.c | 1 - drivers/media/video/pvrusb2/pvrusb2-main.c | 1 - drivers/media/video/pwc/pwc-if.c | 1 - drivers/media/video/saa7134/saa7134-alsa.c | 1 - drivers/media/video/saa7134/saa7134-core.c | 1 - drivers/media/video/saa7134/saa7134-empress.c | 1 - drivers/media/video/saa7134/saa7134-i2c.c | 1 - drivers/media/video/saa7134/saa7134-input.c | 1 - drivers/media/video/saa7134/saa7134-oss.c | 1 - drivers/media/video/saa7134/saa7134-ts.c | 1 - drivers/media/video/saa7134/saa7134-tvaudio.c | 1 - drivers/media/video/saa7134/saa7134-vbi.c | 1 - drivers/media/video/saa7134/saa7134-video.c | 1 - drivers/media/video/sn9c102/sn9c102_core.c | 1 - drivers/media/video/tda9887.c | 1 - drivers/media/video/tuner-core.c | 1 - drivers/media/video/tuner-simple.c | 1 - drivers/media/video/tvaudio.c | 1 - drivers/media/video/tveeprom.c | 1 - drivers/media/video/tvmixer.c | 1 - drivers/media/video/usbvision/usbvision-core.c | 1 - drivers/media/video/usbvision/usbvision-video.c | 1 - drivers/media/video/v4l1-compat.c | 1 - drivers/media/video/video-buf.c | 1 - drivers/media/video/vino.c | 1 - drivers/media/video/w9968cf.c | 1 - drivers/media/video/zc0301/zc0301_core.c | 1 - 91 files changed, 91 deletions(-) (limited to 'drivers') diff --git a/drivers/media/common/ir-functions.c b/drivers/media/common/ir-functions.c index a3292e955aa..e7c3ab951a4 100644 --- a/drivers/media/common/ir-functions.c +++ b/drivers/media/common/ir-functions.c @@ -21,7 +21,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c index cbd1184b521..137f68bee39 100644 --- a/drivers/media/common/ir-keymaps.c +++ b/drivers/media/common/ir-keymaps.c @@ -20,7 +20,6 @@ */ #include -#include #include #include diff --git a/drivers/media/dvb/bt8xx/bt878.c b/drivers/media/dvb/bt8xx/bt878.c index df72b4b8ee1..eca602d9b3d 100644 --- a/drivers/media/dvb/bt8xx/bt878.c +++ b/drivers/media/dvb/bt8xx/bt878.c @@ -28,7 +28,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c index 67613eb6fa3..dedd30a8356 100644 --- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c +++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c @@ -21,7 +21,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c index 5394de2e4ce..f94bc31e3b3 100644 --- a/drivers/media/dvb/dvb-core/dmxdev.c +++ b/drivers/media/dvb/dvb-core/dmxdev.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c index 4fadddb264d..b0bf21958ed 100644 --- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 1a1b2405b0f..880d499cd36 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c index 0f18ce8a939..6b7954daeb4 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.c +++ b/drivers/media/dvb/dvb-core/dvbdev.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/bcm3510.c b/drivers/media/dvb/frontends/bcm3510.c index baeb311de89..a913f49c062 100644 --- a/drivers/media/dvb/frontends/bcm3510.c +++ b/drivers/media/dvb/frontends/bcm3510.c @@ -33,7 +33,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/cx22700.c b/drivers/media/dvb/frontends/cx22700.c index 13ad1bfae66..11a4968f18c 100644 --- a/drivers/media/dvb/frontends/cx22700.c +++ b/drivers/media/dvb/frontends/cx22700.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include "dvb_frontend.h" diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c index 10fc0c8316d..b03d8283c37 100644 --- a/drivers/media/dvb/frontends/cx24110.c +++ b/drivers/media/dvb/frontends/cx24110.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include "dvb_frontend.h" diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c index 0834c0677fe..d74fdbd6336 100644 --- a/drivers/media/dvb/frontends/cx24123.c +++ b/drivers/media/dvb/frontends/cx24123.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include "dvb_frontend.h" diff --git a/drivers/media/dvb/frontends/dib3000mb.c b/drivers/media/dvb/frontends/dib3000mb.c index b6adea5ffeb..136b9d2164d 100644 --- a/drivers/media/dvb/frontends/dib3000mb.c +++ b/drivers/media/dvb/frontends/dib3000mb.c @@ -23,7 +23,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/dvb_dummy_fe.c b/drivers/media/dvb/frontends/dvb_dummy_fe.c index 6271b1e7f6a..fed09dfb2b7 100644 --- a/drivers/media/dvb/frontends/dvb_dummy_fe.c +++ b/drivers/media/dvb/frontends/dvb_dummy_fe.c @@ -20,7 +20,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/isl6421.c b/drivers/media/dvb/frontends/isl6421.c index c967148a594..684c8ec166c 100644 --- a/drivers/media/dvb/frontends/isl6421.c +++ b/drivers/media/dvb/frontends/isl6421.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include diff --git a/drivers/media/dvb/frontends/l64781.c b/drivers/media/dvb/frontends/l64781.c index 1aeacb1c4af..443d9045d4c 100644 --- a/drivers/media/dvb/frontends/l64781.c +++ b/drivers/media/dvb/frontends/l64781.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include "dvb_frontend.h" diff --git a/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb/frontends/lgdt330x.c index e25286e2d43..bdc9fa88b86 100644 --- a/drivers/media/dvb/frontends/lgdt330x.c +++ b/drivers/media/dvb/frontends/lgdt330x.c @@ -35,7 +35,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/lnbp21.c b/drivers/media/dvb/frontends/lnbp21.c index 2d2f58c2622..76f935d9755 100644 --- a/drivers/media/dvb/frontends/lnbp21.c +++ b/drivers/media/dvb/frontends/lnbp21.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include diff --git a/drivers/media/dvb/frontends/mt2060.c b/drivers/media/dvb/frontends/mt2060.c index 450fad8d9b6..1305b0e63ce 100644 --- a/drivers/media/dvb/frontends/mt2060.c +++ b/drivers/media/dvb/frontends/mt2060.c @@ -22,7 +22,6 @@ /* In that file, frequencies are expressed in kiloHertz to avoid 32 bits overflows */ #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/mt2131.c b/drivers/media/dvb/frontends/mt2131.c index 375dfa16681..6bcc4ccc991 100644 --- a/drivers/media/dvb/frontends/mt2131.c +++ b/drivers/media/dvb/frontends/mt2131.c @@ -20,7 +20,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/mt2266.c b/drivers/media/dvb/frontends/mt2266.c index 33b388e8f7b..03fe8265745 100644 --- a/drivers/media/dvb/frontends/mt2266.c +++ b/drivers/media/dvb/frontends/mt2266.c @@ -15,7 +15,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/mt312.c b/drivers/media/dvb/frontends/mt312.c index 1ef82182564..0606b9a5b61 100644 --- a/drivers/media/dvb/frontends/mt312.c +++ b/drivers/media/dvb/frontends/mt312.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include diff --git a/drivers/media/dvb/frontends/mt352.c b/drivers/media/dvb/frontends/mt352.c index 87e31ca7e10..5dd9b731f6f 100644 --- a/drivers/media/dvb/frontends/mt352.c +++ b/drivers/media/dvb/frontends/mt352.c @@ -32,7 +32,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/nxt200x.c b/drivers/media/dvb/frontends/nxt200x.c index ddc84899cf8..fcf964fe1d6 100644 --- a/drivers/media/dvb/frontends/nxt200x.c +++ b/drivers/media/dvb/frontends/nxt200x.c @@ -44,7 +44,6 @@ #include #include #include -#include #include #include diff --git a/drivers/media/dvb/frontends/or51132.c b/drivers/media/dvb/frontends/or51132.c index 3cc8b444b8f..b314a1f2dee 100644 --- a/drivers/media/dvb/frontends/or51132.c +++ b/drivers/media/dvb/frontends/or51132.c @@ -36,7 +36,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/or51211.c b/drivers/media/dvb/frontends/or51211.c index f46d5a46683..f02bd944595 100644 --- a/drivers/media/dvb/frontends/or51211.c +++ b/drivers/media/dvb/frontends/or51211.c @@ -32,7 +32,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/sp8870.c b/drivers/media/dvb/frontends/sp8870.c index d98fd5c2e13..da876f7bfe3 100644 --- a/drivers/media/dvb/frontends/sp8870.c +++ b/drivers/media/dvb/frontends/sp8870.c @@ -29,7 +29,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/sp887x.c b/drivers/media/dvb/frontends/sp887x.c index 5c2f8f4e0ae..1aa2539f509 100644 --- a/drivers/media/dvb/frontends/sp887x.c +++ b/drivers/media/dvb/frontends/sp887x.c @@ -12,7 +12,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c index 6c607302c1b..035dd7ba651 100644 --- a/drivers/media/dvb/frontends/stv0299.c +++ b/drivers/media/dvb/frontends/stv0299.c @@ -45,7 +45,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c index 33a84372c9e..8415a8a5247 100644 --- a/drivers/media/dvb/frontends/tda1004x.c +++ b/drivers/media/dvb/frontends/tda1004x.c @@ -31,7 +31,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/tda10086.c b/drivers/media/dvb/frontends/tda10086.c index 0f2d4b41556..9a8ddc537f8 100644 --- a/drivers/media/dvb/frontends/tda10086.c +++ b/drivers/media/dvb/frontends/tda10086.c @@ -22,7 +22,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/tda8083.c b/drivers/media/dvb/frontends/tda8083.c index 0f041e87378..011b74f798a 100644 --- a/drivers/media/dvb/frontends/tda8083.c +++ b/drivers/media/dvb/frontends/tda8083.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/dvb/frontends/zl10353.c b/drivers/media/dvb/frontends/zl10353.c index 245f9b7dddf..a97a7fd2c89 100644 --- a/drivers/media/dvb/frontends/zl10353.c +++ b/drivers/media/dvb/frontends/zl10353.c @@ -21,7 +21,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index 8178832d14a..aecfdeb8ec4 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -40,7 +40,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/dvb/ttpci/av7110_ir.c b/drivers/media/dvb/ttpci/av7110_ir.c index 6322800ee12..e8f553719bc 100644 --- a/drivers/media/dvb/ttpci/av7110_ir.c +++ b/drivers/media/dvb/ttpci/av7110_ir.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/dvb/ttpci/budget-core.c b/drivers/media/dvb/ttpci/budget-core.c index b611f2b1f8b..0252081f013 100644 --- a/drivers/media/dvb/ttpci/budget-core.c +++ b/drivers/media/dvb/ttpci/budget-core.c @@ -34,7 +34,6 @@ * the project's page is at http://www.linuxtv.org/dvb/ */ -#include #include "budget.h" #include "ttpci-eeprom.h" diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c index b60cdc93d6d..288e79f2cb0 100644 --- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c +++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c index 78c98b08997..5e691fd7990 100644 --- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c +++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c @@ -22,7 +22,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c index f6715007d40..1f4f2625395 100644 --- a/drivers/media/video/bt8xx/bttv-cards.c +++ b/drivers/media/video/bt8xx/bttv-cards.c @@ -27,7 +27,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index cb555f2c40f..0711c950784 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -30,7 +30,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/video/bt8xx/bttv-i2c.c b/drivers/media/video/bt8xx/bttv-i2c.c index 0dfa49b6641..844f1762c45 100644 --- a/drivers/media/video/bt8xx/bttv-i2c.c +++ b/drivers/media/video/bt8xx/bttv-i2c.c @@ -28,7 +28,6 @@ */ #include -#include #include #include diff --git a/drivers/media/video/bt8xx/bttv-input.c b/drivers/media/video/bt8xx/bttv-input.c index 4201552bc3c..e7c521b8444 100644 --- a/drivers/media/video/bt8xx/bttv-input.c +++ b/drivers/media/video/bt8xx/bttv-input.c @@ -19,7 +19,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/video/bt8xx/bttv-vbi.c b/drivers/media/video/bt8xx/bttv-vbi.c index 93e35de5a18..007485aa4f0 100644 --- a/drivers/media/video/bt8xx/bttv-vbi.c +++ b/drivers/media/video/bt8xx/bttv-vbi.c @@ -24,7 +24,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/video/btcx-risc.c b/drivers/media/video/btcx-risc.c index b4aca724927..ce0840ccd59 100644 --- a/drivers/media/video/btcx-risc.c +++ b/drivers/media/video/btcx-risc.c @@ -23,7 +23,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c index ef5361824f8..0fae0e000f1 100644 --- a/drivers/media/video/cafe_ccic.c +++ b/drivers/media/video/cafe_ccic.c @@ -14,7 +14,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/video/cpia.c b/drivers/media/video/cpia.c index 78c9699eafb..a1d02e5ce0f 100644 --- a/drivers/media/video/cpia.c +++ b/drivers/media/video/cpia.c @@ -28,7 +28,6 @@ #include -#include #include #include #include diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c index 92778cd1d73..e3aaba1e0e0 100644 --- a/drivers/media/video/cpia2/cpia2_v4l.c +++ b/drivers/media/video/cpia2/cpia2_v4l.c @@ -37,7 +37,6 @@ #include #include #include -#include #include "cpia2.h" #include "cpia2dev.h" diff --git a/drivers/media/video/cx2341x.c b/drivers/media/video/cx2341x.c index d73c86aeeaa..904bba0dbc4 100644 --- a/drivers/media/video/cx2341x.c +++ b/drivers/media/video/cx2341x.c @@ -20,7 +20,6 @@ #include -#include #include #include #include diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index 74e3eb94575..206af419aea 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -27,7 +27,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index 970926b97ee..cea3212d28b 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c index 6b42dea860f..6ae21750b2c 100644 --- a/drivers/media/video/cx88/cx88-i2c.c +++ b/drivers/media/video/cx88/cx88-i2c.c @@ -28,7 +28,6 @@ */ #include -#include #include #include diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index c78a95ef758..78adf4d1cf6 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -27,7 +27,6 @@ #include #include #include -#include #include "cx88.h" #include diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index d46114685ed..6ece35b5fc8 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -23,7 +23,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c index 9aee8c51ee2..82364fb0702 100644 --- a/drivers/media/video/cx88/cx88-tvaudio.c +++ b/drivers/media/video/cx88/cx88-tvaudio.c @@ -36,7 +36,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/video/cx88/cx88-vbi.c b/drivers/media/video/cx88/cx88-vbi.c index 16c0d36bb6b..72c1d19fa79 100644 --- a/drivers/media/video/cx88/cx88-vbi.c +++ b/drivers/media/video/cx88/cx88-vbi.c @@ -2,7 +2,6 @@ */ #include #include -#include #include #include diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index e96c688cba9..a16fc157a67 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/cx88/cx88-vp3054-i2c.c b/drivers/media/video/cx88/cx88-vp3054-i2c.c index f76ca9e2eeb..77c37889232 100644 --- a/drivers/media/video/cx88/cx88-vp3054-i2c.c +++ b/drivers/media/video/cx88/cx88-vp3054-i2c.c @@ -23,7 +23,6 @@ */ #include -#include #include #include diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c index 255a47dfb84..d3282ec62c5 100644 --- a/drivers/media/video/em28xx/em28xx-core.c +++ b/drivers/media/video/em28xx/em28xx-core.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c index 55d45b0032c..e3894b68c4e 100644 --- a/drivers/media/video/em28xx/em28xx-input.c +++ b/drivers/media/video/em28xx/em28xx-input.c @@ -22,7 +22,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c index 585bd1fe076..31062a981e3 100644 --- a/drivers/media/video/et61x251/et61x251_core.c +++ b/drivers/media/video/et61x251/et61x251_core.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index 2d709e06467..b3939a0bada 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c @@ -28,7 +28,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 784098d4bf0..03d31860851 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -38,7 +38,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/video/mt20xx.c b/drivers/media/video/mt20xx.c index 210a84d8b97..bd495c12d29 100644 --- a/drivers/media/video/mt20xx.c +++ b/drivers/media/video/mt20xx.c @@ -5,7 +5,6 @@ */ #include #include -#include #include #include "tuner-driver.h" diff --git a/drivers/media/video/ov7670.c b/drivers/media/video/ov7670.c index c4c5bd67f79..2bc6bdc9c1f 100644 --- a/drivers/media/video/ov7670.c +++ b/drivers/media/video/ov7670.c @@ -12,7 +12,6 @@ */ #include #include -#include #include #include #include diff --git a/drivers/media/video/ovcamchip/ovcamchip_core.c b/drivers/media/video/ovcamchip/ovcamchip_core.c index 3fe9fa04cd8..8063e33f1c8 100644 --- a/drivers/media/video/ovcamchip/ovcamchip_core.c +++ b/drivers/media/video/ovcamchip/ovcamchip_core.c @@ -13,7 +13,6 @@ #include #include -#include #include #include #include "ovcamchip_priv.h" diff --git a/drivers/media/video/pvrusb2/pvrusb2-main.c b/drivers/media/video/pvrusb2/pvrusb2-main.c index 9ea41c6699b..1ea0939096a 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-main.c +++ b/drivers/media/video/pvrusb2/pvrusb2-main.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index 931b274bffc..d3ac70a0d9c 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c @@ -64,7 +64,6 @@ #include #include #include -#include #include "pwc.h" #include "pwc-kiara.h" diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c index 3c0fc9027ad..eb5e77dd0d1 100644 --- a/drivers/media/video/saa7134/saa7134-alsa.c +++ b/drivers/media/video/saa7134/saa7134-alsa.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index 25f84701a8e..80108ddf483 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c index fc260ec8fdc..7ed4eaf05e1 100644 --- a/drivers/media/video/saa7134/saa7134-empress.c +++ b/drivers/media/video/saa7134/saa7134-empress.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c index 1cb8c709ca9..cc87f5855a2 100644 --- a/drivers/media/video/saa7134/saa7134-i2c.c +++ b/drivers/media/video/saa7134/saa7134-i2c.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index 1b6dfd801cc..80d2644f765 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -19,7 +19,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c index 72444f039e3..1a737b64736 100644 --- a/drivers/media/video/saa7134/saa7134-oss.c +++ b/drivers/media/video/saa7134/saa7134-oss.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/saa7134/saa7134-ts.c b/drivers/media/video/saa7134/saa7134-ts.c index 60a90a2617a..7780b2cce80 100644 --- a/drivers/media/video/saa7134/saa7134-ts.c +++ b/drivers/media/video/saa7134/saa7134-ts.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c index 18b4817b4aa..43501b5dc05 100644 --- a/drivers/media/video/saa7134/saa7134-tvaudio.c +++ b/drivers/media/video/saa7134/saa7134-tvaudio.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/saa7134/saa7134-vbi.c b/drivers/media/video/saa7134/saa7134-vbi.c index f38366a470f..0044079f5da 100644 --- a/drivers/media/video/saa7134/saa7134-vbi.c +++ b/drivers/media/video/saa7134/saa7134-vbi.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 9985ded2095..9c317ed6b21 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c index 36d8a455e0e..e0accf1b871 100644 --- a/drivers/media/video/sn9c102/sn9c102_core.c +++ b/drivers/media/video/sn9c102/sn9c102_core.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index e8597c10aa4..d162bc67d44 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -1,5 +1,4 @@ #include -#include #include #include #include diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 5f378265d8c..baeae28f283 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -5,7 +5,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index f1ee60a4aa7..572f22423b9 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -5,7 +5,6 @@ */ #include #include -#include #include #include #include diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c index cffb011590e..a19cdcc17ef 100644 --- a/drivers/media/video/tvaudio.c +++ b/drivers/media/video/tvaudio.c @@ -15,7 +15,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c index fdc3def437b..4b2c4034f5b 100644 --- a/drivers/media/video/tveeprom.c +++ b/drivers/media/video/tveeprom.c @@ -30,7 +30,6 @@ #include -#include #include #include #include diff --git a/drivers/media/video/tvmixer.c b/drivers/media/video/tvmixer.c index 3ae5a9cd2e2..544a4ae7d2e 100644 --- a/drivers/media/video/tvmixer.c +++ b/drivers/media/video/tvmixer.c @@ -2,7 +2,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c index 5b1e346df20..c7d5f9ed22d 100644 --- a/drivers/media/video/usbvision/usbvision-core.c +++ b/drivers/media/video/usbvision/usbvision-core.c @@ -45,7 +45,6 @@ #include #include -#include #include #ifdef CONFIG_KMOD diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c index 0cb006f2943..2f9b2b9e3b0 100644 --- a/drivers/media/video/usbvision/usbvision-video.c +++ b/drivers/media/video/usbvision/usbvision-video.c @@ -68,7 +68,6 @@ #include #include -#include #include #ifdef CONFIG_KMOD diff --git a/drivers/media/video/v4l1-compat.c b/drivers/media/video/v4l1-compat.c index ede8543818b..9eac65f34bf 100644 --- a/drivers/media/video/v4l1-compat.c +++ b/drivers/media/video/v4l1-compat.c @@ -19,7 +19,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/video/video-buf.c b/drivers/media/video/video-buf.c index a32dfbe0585..f6f31e1773d 100644 --- a/drivers/media/video/video-buf.c +++ b/drivers/media/video/video-buf.c @@ -24,7 +24,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c index a0c1647a2ba..9a03dc82c6c 100644 --- a/drivers/media/video/vino.c +++ b/drivers/media/video/vino.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include diff --git a/drivers/media/video/w9968cf.c b/drivers/media/video/w9968cf.c index 8f31613b990..77599f228b6 100644 --- a/drivers/media/video/w9968cf.c +++ b/drivers/media/video/w9968cf.c @@ -42,7 +42,6 @@ #include #include #include -#include #include "w9968cf.h" #include "w9968cf_decoder.h" diff --git a/drivers/media/video/zc0301/zc0301_core.c b/drivers/media/video/zc0301/zc0301_core.c index 703b741e46d..35138c594be 100644 --- a/drivers/media/video/zc0301/zc0301_core.c +++ b/drivers/media/video/zc0301/zc0301_core.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3-70-g09d2 From aeb292d1342c649ac0b35ae9205b761fd14adb57 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 23 Aug 2007 15:45:41 -0300 Subject: V4L/DVB (6081): ivtv: Fix static structure initialization Convert the initialization of ivtv_i2c_algo_template to C99-style. Otherwise a future change to struct i2c_algo_bit_data would break this code. Also declared that structure const - it's a template after all. Signed-off-by: Jean Delvare Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-i2c.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c index 5e12ebc2a9d..085dc3938da 100644 --- a/drivers/media/video/ivtv/ivtv-i2c.c +++ b/drivers/media/video/ivtv/ivtv-i2c.c @@ -536,14 +536,13 @@ static struct i2c_adapter ivtv_i2c_adap_template = { #endif }; -static struct i2c_algo_bit_data ivtv_i2c_algo_template = { - NULL, /* ?? */ - ivtv_setsda_old, /* setsda function */ - ivtv_setscl_old, /* " */ - ivtv_getsda_old, /* " */ - ivtv_getscl_old, /* " */ - 10, /* udelay */ - 200 /* timeout */ +static const struct i2c_algo_bit_data ivtv_i2c_algo_template = { + .setsda = ivtv_setsda_old, + .setscl = ivtv_setscl_old, + .getsda = ivtv_getsda_old, + .getscl = ivtv_getscl_old, + .udelay = 10, + .timeout = 200, }; static struct i2c_client ivtv_i2c_client_template = { -- cgit v1.2.3-70-g09d2 From 16cf1d0c5d7b8970aca2ca426166833642ce0544 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Tue, 21 Aug 2007 08:19:16 -0300 Subject: V4L/DVB (6082): cx88: Improve risc instruction printing in sram channel dump When the risc instrunctions from the CMDS were printed, instruction arguments weren't taken into account. This changes output like: cx88[0]: risc0: 0x1d010400 [ write sol eol irq1 cnt0 count=1024 ] cx88[0]: risc1: 0x0cac2800 [ INVALID sol eol 23 21 19 18 13 count=2048 ] cx88[0]: risc2: 0x1d010400 [ write sol eol irq1 cnt0 count=1024 ] cx88[0]: risc3: 0x0cac2c00 [ INVALID sol eol 23 21 19 18 13 count=3072 ] cx88[0]: risc0: 0x1d010400 [ write sol eol irq1 cnt0 count=1024 ] cx88[0]: risc1: 0x0cac2800 [ arg #1 ] cx88[0]: risc2: 0x1d010400 [ write sol eol irq1 cnt0 count=1024 ] cx88[0]: risc3: 0x0cac2c00 [ arg #1 ] Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-core.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index cea3212d28b..ce7f1f0ae05 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -434,10 +434,13 @@ void cx88_sram_channel_dump(struct cx88_core *core, printk("%s: cmds: %-12s: 0x%08x\n", core->name,name[i], cx_read(ch->cmds_start + 4*i)); - for (i = 0; i < 4; i++) { + for (n = 1, i = 0; i < 4; i++) { risc = cx_read(ch->cmds_start + 4 * (i+11)); printk("%s: risc%d: ", core->name, i); - cx88_risc_decode(risc); + if (--n) + printk("0x%08x [ arg #%d ]\n", risc, n); + else + n = cx88_risc_decode(risc); } for (i = 0; i < 16; i += n) { risc = cx_read(ch->ctrl_start + 4 * i); -- cgit v1.2.3-70-g09d2 From 05b2723387cb4086535e935ee07cca19086308fc Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Fri, 24 Aug 2007 01:06:34 -0300 Subject: V4L/DVB (6083): cx88-alsa: Rework buffer handling Rework the way the DMA buffer is handled and IRQs are generated. ALSA uses a ring-buffer of multiple periods. Each period is supposed to corrispond to one IRQ. The existing driver was generating one interrupt per ring-buffer, as opposed to per period. This meant that as soon as the IRQ was generated, the hardware was already starting to re-write the beginning of the buffer. Since the DMA happens on a per-line basis, there was only a narrow window to copy the data out before the buffer was overwritten. The cx88 core RISC program generator is modified so that it can set the IRQ and counter flags to count every X lines of DMA transfer. This way we can generate an interrupt every period instead of every full ring-buffer. Right now only period of one line are supported, but it should be possible to support longer periods. Note that a WRITE instruction generates an IRQ when it starts, not when the transfer is finished. Thus to generate an IRQ when line X is done, one must set the IRQ flag on the instruction that starts line X+1, not the one that ends line X. Change the line size so that there are four lines in the SRAM FIFO. If there are not four lines, the analog output from the cx88's internal DACs is full of clicks and pops. Try to handle FIFO sync errors. Sometimes the chip generates many of these errors before audio data starts. Up to 50 sync errors will be ignored and the counter reset. Have the IRQ handler save the RISC counter to the chip struct, and then have the pointer callback use this to calculate the pointer position. We could read the counter from the pointer callback, but sometimes the sync errors on start up cause the counter to go crazy. ALSA sees this and thinks there has been an overrun. The IRQ hander can avoid saving the counter position on sync errors. The chip "opened" flag wasn't necessary. ALSA won't try to open the same substream multiple times. Probably this code was cut&pasted from the bt87x driver, which has multiple sub-streams for one chip. Do error checking for the videobuf mapping functions. snd_card_cx88_runtime_free() is useless and can be deleted. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-alsa.c | 168 +++++++++++++++-------------------- drivers/media/video/cx88/cx88-core.c | 22 +++-- drivers/media/video/cx88/cx88-mpeg.c | 2 +- drivers/media/video/cx88/cx88.h | 2 +- 4 files changed, 89 insertions(+), 105 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index 8d19d33c8b3..33dd4cb5e87 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -3,6 +3,7 @@ * Support for audio capture * PCI function #1 of the cx2388x. * + * (c) 2007 Trent Piepho * (c) 2005,2006 Ricardo Cerqueira * (c) 2005 Mauro Carvalho Chehab * Based on a dummy cx88 module by Gerd Knorr @@ -47,7 +48,6 @@ #define dprintk_core(level,fmt, arg...) if (debug >= level) \ printk(KERN_DEBUG "%s/1: " fmt, chip->core->name , ## arg) - /**************************************************************************** Data type declarations - Can be moded to a header file later ****************************************************************************/ @@ -58,6 +58,7 @@ struct cx88_audio_dev { struct cx88_core *core; struct cx88_dmaqueue q; + u64 starttime; /* pci i/o */ struct pci_dev *pci; @@ -68,24 +69,20 @@ struct cx88_audio_dev { struct snd_card *card; spinlock_t reg_lock; + atomic_t count; unsigned int dma_size; unsigned int period_size; unsigned int num_periods; - struct videobuf_dmabuf dma_risc; + struct videobuf_dmabuf dma_risc; int mixer_volume[MIXER_ADDR_LAST+1][2]; int capture_source[MIXER_ADDR_LAST+1][2]; - long int read_count; - long int read_offset; - - struct cx88_buffer *buf; - - long opened; - struct snd_pcm_substream *substream; + struct cx88_buffer *buf; + struct snd_pcm_substream *substream; }; typedef struct cx88_audio_dev snd_cx88_card_t; @@ -146,16 +143,13 @@ static int _cx88_start_audio_dma(snd_cx88_card_t *chip) cx_write(MO_AUDD_LNGTH, buf->bpl); /* reset counter */ - cx_write(MO_AUDD_GPCNTRL,GP_COUNT_CONTROL_RESET); + cx_write(MO_AUDD_GPCNTRL, GP_COUNT_CONTROL_RESET); + atomic_set(&chip->count, 0); - dprintk(1, "Start audio DMA, %d B/line, %d lines/FIFO, %d lines/irq, " - "%d B/irq\n", buf->bpl, cx_read(audio_ch->cmds_start + 8)>>1, + dprintk(1, "Start audio DMA, %d B/line, %d lines/FIFO, %d periods, %d " + "byte buffer\n", buf->bpl, cx_read(audio_ch->cmds_start + 8)>>1, chip->num_periods, buf->bpl * chip->num_periods); - dprintk(1, "Enabling IRQ, setting mask from 0x%x to 0x%x\n", - chip->core->pci_irqmask, - chip->core->pci_irqmask | PCI_INT_AUDINT); - /* Enables corresponding bits at AUD_INT_STAT */ cx_write(MO_AUD_INTMSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC | AUD_INT_DN_RISCI2 | AUD_INT_DN_RISCI1); @@ -198,7 +192,7 @@ static int _cx88_stop_audio_dma(snd_cx88_card_t *chip) return 0; } -#define MAX_IRQ_LOOP 10 +#define MAX_IRQ_LOOP 50 /* * BOARD Specific: IRQ dma bits @@ -223,14 +217,11 @@ static void cx8801_aud_irq(snd_cx88_card_t *chip) { struct cx88_core *core = chip->core; u32 status, mask; - u32 count; status = cx_read(MO_AUD_INTSTAT); mask = cx_read(MO_AUD_INTMSK); - if (0 == (status & mask)) { - spin_unlock(&chip->reg_lock); + if (0 == (status & mask)) return; - } cx_write(MO_AUD_INTSTAT, status); if (debug > 1 || (status & mask & ~0xff)) cx88_print_irqbits(core->name, "irq aud", @@ -238,27 +229,20 @@ static void cx8801_aud_irq(snd_cx88_card_t *chip) status, mask); /* risc op code error */ if (status & AUD_INT_OPC_ERR) { - printk(KERN_WARNING "%s/0: audio risc op code error\n",core->name); + printk(KERN_WARNING "%s/1: Audio risc op code error\n",core->name); cx_clear(MO_AUD_DMACNTRL, 0x11); cx88_sram_channel_dump(core, &cx88_sram_channels[SRAM_CH25]); } - + if (status & AUD_INT_DN_SYNC) { + dprintk(1, "Downstream sync error\n"); + cx_write(MO_AUDD_GPCNTRL, GP_COUNT_CONTROL_RESET); + return; + } /* risc1 downstream */ if (status & AUD_INT_DN_RISCI1) { - spin_lock(&chip->reg_lock); - count = cx_read(MO_AUDD_GPCNT); - spin_unlock(&chip->reg_lock); - if (chip->read_count == 0) - chip->read_count += chip->dma_size; - } - - if (chip->read_count >= chip->period_size) { - dprintk(2, "Elapsing period\n"); + atomic_set(&chip->count, cx_read(MO_AUDD_GPCNT)); snd_pcm_period_elapsed(chip->substream); } - - dprintk(3,"Leaving audio IRQ handler...\n"); - /* FIXME: Any other status should deserve a special handling? */ } @@ -277,23 +261,20 @@ static irqreturn_t cx8801_irq(int irq, void *dev_id) (core->pci_irqmask | PCI_INT_AUDINT); if (0 == status) goto out; - dprintk( 3, "cx8801_irq\n" ); - dprintk( 3, " loop: %d/%d\n", loop, MAX_IRQ_LOOP ); - dprintk( 3, " status: %d\n", status ); + dprintk(3, "cx8801_irq loop %d/%d, status %x\n", + loop, MAX_IRQ_LOOP, status); handled = 1; cx_write(MO_PCI_INTSTAT, status); if (status & core->pci_irqmask) cx88_core_irq(core, status); - if (status & PCI_INT_AUDINT) { - dprintk( 2, " ALSA IRQ handling\n" ); + if (status & PCI_INT_AUDINT) cx8801_aud_irq(chip); - } - }; + } if (MAX_IRQ_LOOP == loop) { - dprintk( 0, "clearing mask\n" ); - dprintk(1,"%s/0: irq loop -- clearing mask\n", + printk(KERN_ERR + "%s/1: IRQ loop detected, disabling interrupts\n", core->name); cx_clear(MO_PCI_INTMSK, PCI_INT_AUDINT); } @@ -315,7 +296,7 @@ static int dsp_buffer_free(snd_cx88_card_t *chip) chip->dma_size = 0; - return 0; + return 0; } /**************************************************************************** @@ -325,6 +306,7 @@ static int dsp_buffer_free(snd_cx88_card_t *chip) /* * Digital hardware definition */ +#define DEFAULT_FIFO_SIZE 4096 static struct snd_pcm_hardware snd_cx88_digital_hw = { .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | @@ -337,19 +319,15 @@ static struct snd_pcm_hardware snd_cx88_digital_hw = { .rate_max = 48000, .channels_min = 2, .channels_max = 2, - .buffer_bytes_max = (2*2048), - .period_bytes_min = 2048, - .period_bytes_max = 2048, - .periods_min = 2, - .periods_max = 2, + /* Analog audio output will be full of clicks and pops if there + are not exactly four lines in the SRAM FIFO buffer. */ + .period_bytes_min = DEFAULT_FIFO_SIZE/4, + .period_bytes_max = DEFAULT_FIFO_SIZE/4, + .periods_min = 1, + .periods_max = 1024, + .buffer_bytes_max = (1024*1024), }; -/* - * audio pcm capture runtime free - */ -static void snd_card_cx88_runtime_free(struct snd_pcm_runtime *runtime) -{ -} /* * audio pcm capture open callback */ @@ -359,26 +337,24 @@ static int snd_cx88_pcm_open(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; int err; - if (test_and_set_bit(0, &chip->opened)) - return -EBUSY; - - err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIODS); if (err < 0) goto _error; chip->substream = substream; - chip->read_count = 0; - chip->read_offset = 0; - - runtime->private_free = snd_card_cx88_runtime_free; runtime->hw = snd_cx88_digital_hw; + if (cx88_sram_channels[SRAM_CH25].fifo_size != DEFAULT_FIFO_SIZE) { + unsigned int bpl = cx88_sram_channels[SRAM_CH25].fifo_size / 4; + bpl &= ~7; /* must be multiple of 8 */ + runtime->hw.period_bytes_min = bpl; + runtime->hw.period_bytes_max = bpl; + } + return 0; _error: dprintk(1,"Error opening PCM!\n"); - clear_bit(0, &chip->opened); - smp_mb__after_clear_bit(); return err; } @@ -387,11 +363,6 @@ _error: */ static int snd_cx88_close(struct snd_pcm_substream *substream) { - snd_cx88_card_t *chip = snd_pcm_substream_chip(substream); - - clear_bit(0, &chip->opened); - smp_mb__after_clear_bit(); - return 0; } @@ -403,54 +374,61 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream, { snd_cx88_card_t *chip = snd_pcm_substream_chip(substream); struct cx88_buffer *buf; + int ret; if (substream->runtime->dma_area) { dsp_buffer_free(chip); substream->runtime->dma_area = NULL; } - chip->period_size = params_period_bytes(hw_params); chip->num_periods = params_periods(hw_params); chip->dma_size = chip->period_size * params_periods(hw_params); BUG_ON(!chip->dma_size); + BUG_ON(chip->num_periods & (chip->num_periods-1)); - dprintk(1,"Setting buffer\n"); - - buf = kzalloc(sizeof(*buf),GFP_KERNEL); + buf = kzalloc(sizeof(*buf), GFP_KERNEL); if (NULL == buf) return -ENOMEM; buf->vb.memory = V4L2_MEMORY_MMAP; + buf->vb.field = V4L2_FIELD_NONE; buf->vb.width = chip->period_size; + buf->bpl = chip->period_size; buf->vb.height = chip->num_periods; buf->vb.size = chip->dma_size; - buf->vb.field = V4L2_FIELD_NONE; videobuf_dma_init(&buf->vb.dma); - videobuf_dma_init_kernel(&buf->vb.dma,PCI_DMA_FROMDEVICE, + ret = videobuf_dma_init_kernel(&buf->vb.dma, PCI_DMA_FROMDEVICE, (PAGE_ALIGN(buf->vb.size) >> PAGE_SHIFT)); + if (ret < 0) + goto error; - videobuf_pci_dma_map(chip->pci,&buf->vb.dma); - + ret = videobuf_pci_dma_map(chip->pci,&buf->vb.dma); + if (ret < 0) + goto error; - cx88_risc_databuffer(chip->pci, &buf->risc, - buf->vb.dma.sglist, - buf->vb.width, buf->vb.height); + ret = cx88_risc_databuffer(chip->pci, &buf->risc, buf->vb.dma.sglist, + buf->vb.width, buf->vb.height, 1); + if (ret < 0) + goto error; - buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); + /* Loop back to start of program */ + buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP|RISC_IRQ1|RISC_CNT_INC); buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma); buf->vb.state = STATE_PREPARED; - buf->bpl = chip->period_size; chip->buf = buf; chip->dma_risc = buf->vb.dma; - dprintk(1,"Buffer ready at %u\n",chip->dma_risc.nr_pages); substream->runtime->dma_area = chip->dma_risc.vmalloc; return 0; + +error: + kfree(buf); + return ret; } /* @@ -477,7 +455,6 @@ static int snd_cx88_prepare(struct snd_pcm_substream *substream) return 0; } - /* * trigger callback */ @@ -486,6 +463,7 @@ static int snd_cx88_card_trigger(struct snd_pcm_substream *substream, int cmd) snd_cx88_card_t *chip = snd_pcm_substream_chip(substream); int err; + /* Local interrupts are already disabled by ALSA */ spin_lock(&chip->reg_lock); switch (cmd) { @@ -512,17 +490,14 @@ static snd_pcm_uframes_t snd_cx88_pointer(struct snd_pcm_substream *substream) { snd_cx88_card_t *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; + u16 count; - if (chip->read_count) { - chip->read_count -= snd_pcm_lib_period_bytes(substream); - chip->read_offset += snd_pcm_lib_period_bytes(substream); - if (chip->read_offset == chip->dma_size) - chip->read_offset = 0; - } - - dprintk(2, "Pointer time, will return %li, read %li\n",chip->read_offset,chip->read_count); - return bytes_to_frames(runtime, chip->read_offset); + count = atomic_read(&chip->count); +// dprintk(2, "%s - count %d (+%u), period %d, frame %lu\n", __FUNCTION__, +// count, new, count & (runtime->periods-1), +// runtime->period_size * (count & (runtime->periods-1))); + return runtime->period_size * (count & (runtime->periods-1)); } /* @@ -592,10 +567,13 @@ static int snd_cx88_capture_volume_put(struct snd_kcontrol *kcontrol, int v; u32 old_control; + /* Do we really know this will always be called with IRQs on? */ spin_lock_irq(&chip->reg_lock); + old_control = 0x3f - (cx_read(AUD_VOL_CTL) & 0x3f); v = 0x3f - (value->value.integer.value[0] & 0x3f); cx_andor(AUD_VOL_CTL, 0x3f, v); + spin_unlock_irq(&chip->reg_lock); return v != old_control; diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index ce7f1f0ae05..41f7f374c18 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -68,13 +68,15 @@ static DEFINE_MUTEX(devlist); #define NO_SYNC_LINE (-1U) +/* @lpi: lines per IRQ, or 0 to not generate irqs. Note: IRQ to be + generated _after_ lpi lines are transferred. */ static u32* cx88_risc_field(u32 *rp, struct scatterlist *sglist, unsigned int offset, u32 sync_line, unsigned int bpl, unsigned int padding, - unsigned int lines) + unsigned int lines, unsigned int lpi) { struct scatterlist *sg; - unsigned int line,todo; + unsigned int line,todo,sol; /* sync instruction */ if (sync_line != NO_SYNC_LINE) @@ -87,15 +89,19 @@ static u32* cx88_risc_field(u32 *rp, struct scatterlist *sglist, offset -= sg_dma_len(sg); sg++; } + if (lpi && line>0 && !(line % lpi)) + sol = RISC_SOL | RISC_IRQ1 | RISC_CNT_INC; + else + sol = RISC_SOL; if (bpl <= sg_dma_len(sg)-offset) { /* fits into current chunk */ - *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|RISC_EOL|bpl); + *(rp++)=cpu_to_le32(RISC_WRITE|sol|RISC_EOL|bpl); *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset); offset+=bpl; } else { /* scanline needs to be split */ todo = bpl; - *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL| + *(rp++)=cpu_to_le32(RISC_WRITE|sol| (sg_dma_len(sg)-offset)); *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset); todo -= (sg_dma_len(sg)-offset); @@ -146,10 +152,10 @@ int cx88_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, rp = risc->cpu; if (UNSET != top_offset) rp = cx88_risc_field(rp, sglist, top_offset, 0, - bpl, padding, lines); + bpl, padding, lines, 0); if (UNSET != bottom_offset) rp = cx88_risc_field(rp, sglist, bottom_offset, 0x200, - bpl, padding, lines); + bpl, padding, lines, 0); /* save pointer to jmp instruction address */ risc->jmp = rp; @@ -159,7 +165,7 @@ int cx88_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, int cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc, struct scatterlist *sglist, unsigned int bpl, - unsigned int lines) + unsigned int lines, unsigned int lpi) { u32 instructions; u32 *rp; @@ -176,7 +182,7 @@ int cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc, /* write risc instructions */ rp = risc->cpu; - rp = cx88_risc_field(rp, sglist, 0, NO_SYNC_LINE, bpl, 0, lines); + rp = cx88_risc_field(rp, sglist, 0, NO_SYNC_LINE, bpl, 0, lines, lpi); /* save pointer to jmp instruction address */ risc->jmp = rp; diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index 6ece35b5fc8..4e6a84f15d1 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -253,7 +253,7 @@ int cx8802_buf_prepare(struct videobuf_queue *q, struct cx8802_dev *dev, goto fail; cx88_risc_databuffer(dev->pci, &buf->risc, buf->vb.dma.sglist, - buf->vb.width, buf->vb.height); + buf->vb.width, buf->vb.height, 0); } buf->vb.state = STATE_PREPARED; return 0; diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index 80e49f986fb..e436a37b440 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -519,7 +519,7 @@ cx88_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, extern int cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc, struct scatterlist *sglist, unsigned int bpl, - unsigned int lines); + unsigned int lines, unsigned int lpi); extern int cx88_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, u32 reg, u32 mask, u32 value); -- cgit v1.2.3-70-g09d2 From ffb7394d51cf6f60a3753a5cc40613fc9d5c5c96 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Fri, 24 Aug 2007 01:06:35 -0300 Subject: V4L/DVB (6084): cx88-alsa: Eliminate snd_cx88_cards The driver kepts a static global array of snd_card pointers for each card probed, which was never used. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-alsa.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index 33dd4cb5e87..ac317fb856e 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -95,7 +95,6 @@ typedef struct cx88_audio_dev snd_cx88_card_t; static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1}; -static struct snd_card *snd_cx88_cards[SNDRV_CARDS]; module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "Enable cx88x soundcard. default enabled."); @@ -759,8 +758,6 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci, snd_card_free(card); return (err); } - snd_cx88_cards[devno] = card; - pci_set_drvdata(pci,card); devno++; -- cgit v1.2.3-70-g09d2 From f6210c9160dff82ceaaf5e59cf5f8fcd6bdefa38 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Fri, 24 Aug 2007 01:06:36 -0300 Subject: V4L/DVB (6085): cx88-alsa: Fix mmap support The driver has long claimed to support mmap, but it didn't work at all. Some of the dma buffer parameters weren't set, and since video_buf uses vmalloc to allocate the buffer, a page callback is needed too. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-alsa.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index ac317fb856e..85d632224f3 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -423,6 +424,8 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream, chip->dma_risc = buf->vb.dma; substream->runtime->dma_area = chip->dma_risc.vmalloc; + substream->runtime->dma_bytes = chip->dma_size; + substream->runtime->dma_addr = 0; return 0; error: @@ -499,6 +502,16 @@ static snd_pcm_uframes_t snd_cx88_pointer(struct snd_pcm_substream *substream) return runtime->period_size * (count & (runtime->periods-1)); } +/* + * page callback (needed for mmap) + */ +static struct page *snd_cx88_page(struct snd_pcm_substream *substream, + unsigned long offset) +{ + void *pageptr = substream->runtime->dma_area + offset; + return vmalloc_to_page(pageptr); +} + /* * operators */ @@ -511,6 +524,7 @@ static struct snd_pcm_ops snd_cx88_pcm_ops = { .prepare = snd_cx88_prepare, .trigger = snd_cx88_card_trigger, .pointer = snd_cx88_pointer, + .page = snd_cx88_page, }; /* -- cgit v1.2.3-70-g09d2 From ad8ff0f10b489562012e433acdac92498fe8bdc9 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 20 Aug 2007 16:01:58 -0300 Subject: V4L/DVB (6086): ivtv: fix output mode processing: UDMA_YUV wasn't cleared - Always clear when stopping the decoder - Clear if the filehandle that is being close was used for UDMA_YUV output. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.h | 1 + drivers/media/video/ivtv/ivtv-fileops.c | 7 ++----- drivers/media/video/ivtv/ivtv-ioctl.c | 2 ++ 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 03d31860851..3ed4703956d 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -517,6 +517,7 @@ struct ivtv_stream { struct ivtv_open_id { u32 open_id; int type; + int yuv_frames; enum v4l2_priority prio; struct ivtv *itv; }; diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index 1f3c8d0310f..62ee41c5220 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -757,6 +757,7 @@ static void ivtv_stop_decoding(struct ivtv_open_id *id, int flags, u64 pts) IVTV_DEBUG_INFO("close stopping decode\n"); ivtv_stop_v4l2_decode_stream(s, flags, pts); + itv->output_mode = OUT_NONE; } clear_bit(IVTV_F_S_APPL_IO, &s->s_flags); clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); @@ -764,11 +765,7 @@ static void ivtv_stop_decoding(struct ivtv_open_id *id, int flags, u64 pts) /* Restore registers we've changed & clean up any mess we've made */ ivtv_yuv_close(itv); } - if (s->type == IVTV_DEC_STREAM_TYPE_YUV && itv->output_mode == OUT_YUV) - itv->output_mode = OUT_NONE; - else if (s->type == IVTV_DEC_STREAM_TYPE_YUV && itv->output_mode == OUT_UDMA_YUV) - itv->output_mode = OUT_NONE; - else if (s->type == IVTV_DEC_STREAM_TYPE_MPG && itv->output_mode == OUT_MPG) + if (itv->output_mode == OUT_UDMA_YUV && id->yuv_frames) itv->output_mode = OUT_NONE; itv->speed = 0; diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index ed5707660e0..2bb1e324785 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -1346,6 +1346,8 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg) ivtv_release_stream(s); return -EBUSY; } + /* Mark that this file handle started the UDMA_YUV mode */ + id->yuv_frames = 1; if (args->y_source == NULL) return 0; return ivtv_yuv_prep_frame(itv, args); -- cgit v1.2.3-70-g09d2 From ea115d54bc963eb2eb0dc223795f3bd6c689ff99 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 20 Aug 2007 16:26:40 -0300 Subject: V4L/DVB (6087): ivtv: prevent changing VBI format while capture is in progress Changing the VBI format requires a CX2341X_ENC_INITIALIZE_INPUT firmware call. This can only be done if no capture is in progress. So return -EBUSY if the encoder is busy. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-ioctl.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index 2bb1e324785..0dde82f67e2 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -584,9 +584,7 @@ static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype, /* set raw VBI format */ if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) { - if (set_fmt && streamtype == IVTV_ENC_STREAM_TYPE_VBI && - itv->vbi.sliced_in->service_set && - atomic_read(&itv->capturing) > 0) { + if (set_fmt && atomic_read(&itv->capturing) > 0) { return -EBUSY; } if (set_fmt) { @@ -624,7 +622,7 @@ static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype, return 0; if (set == 0) return -EINVAL; - if (atomic_read(&itv->capturing) > 0 && itv->vbi.sliced_in->service_set == 0) { + if (atomic_read(&itv->capturing) > 0) { return -EBUSY; } itv->video_dec_func(itv, VIDIOC_S_FMT, fmt); -- cgit v1.2.3-70-g09d2 From 01f1e44fe8455b6c6c557a62119b8622fb99f5f2 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 21 Aug 2007 18:32:42 -0300 Subject: V4L/DVB (6088): cx2341x: some controls can't be changed while the device is busy The driver should now pass the 'busy' state of the device to the cx2341x module whenever controls are set or tried. -EBUSY will be returned if the device is busy and the user attempts to modify certain 'dangerous' controls. It concerns controls that change the audio or video compression mode and bitrates. The cx88-blackbird and pvrusb2 drivers currently always pass '0' (not busy) to the cx2341x, effectively keeping the old behavior for now. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx2341x.c | 18 +++++++++++++++--- drivers/media/video/cx88/cx88-blackbird.c | 6 +++--- drivers/media/video/ivtv/ivtv-controls.c | 6 +++--- drivers/media/video/pvrusb2/pvrusb2-hdw.c | 6 +++--- drivers/media/video/v4l2-common.c | 1 + include/media/cx2341x.h | 2 +- 6 files changed, 26 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx2341x.c b/drivers/media/video/cx2341x.c index 904bba0dbc4..62304255dca 100644 --- a/drivers/media/video/cx2341x.c +++ b/drivers/media/video/cx2341x.c @@ -190,17 +190,21 @@ static int cx2341x_get_ctrl(struct cx2341x_mpeg_params *params, /* Map the control ID to the correct field in the cx2341x_mpeg_params struct. Return -EINVAL if the ID is unknown, else return 0. */ -static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, +static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, int busy, struct v4l2_ext_control *ctrl) { switch (ctrl->id) { case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: + if (busy) + return -EBUSY; params->audio_sampling_freq = ctrl->value; break; case V4L2_CID_MPEG_AUDIO_ENCODING: params->audio_encoding = ctrl->value; break; case V4L2_CID_MPEG_AUDIO_L2_BITRATE: + if (busy) + return -EBUSY; params->audio_l2_bitrate = ctrl->value; break; case V4L2_CID_MPEG_AUDIO_MODE: @@ -245,6 +249,8 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, params->video_gop_closure = ctrl->value; break; case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: + if (busy) + return -EBUSY; /* MPEG-1 only allows CBR */ if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1 && ctrl->value != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) @@ -252,9 +258,13 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, params->video_bitrate_mode = ctrl->value; break; case V4L2_CID_MPEG_VIDEO_BITRATE: + if (busy) + return -EBUSY; params->video_bitrate = ctrl->value; break; case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: + if (busy) + return -EBUSY; params->video_bitrate_peak = ctrl->value; break; case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: @@ -267,6 +277,8 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, params->video_mute_yuv = ctrl->value; break; case V4L2_CID_MPEG_STREAM_TYPE: + if (busy) + return -EBUSY; params->stream_type = ctrl->value; params->video_encoding = (params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_SS || @@ -631,7 +643,7 @@ static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params) (params->audio_crc << 14); } -int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, +int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, int busy, struct v4l2_ext_controls *ctrls, unsigned int cmd) { int err = 0; @@ -663,7 +675,7 @@ int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, err = v4l2_ctrl_check(ctrl, &qctrl, menu_items); if (err) break; - err = cx2341x_set_ctrl(params, ctrl); + err = cx2341x_set_ctrl(params, busy, ctrl); if (err) break; } diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index 206af419aea..47007380a98 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -876,7 +876,7 @@ static int vidioc_g_ext_ctrls (struct file *file, void *priv, if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) return -EINVAL; - return cx2341x_ext_ctrls(&dev->params, f, VIDIOC_G_EXT_CTRLS); + return cx2341x_ext_ctrls(&dev->params, 0, f, VIDIOC_G_EXT_CTRLS); } static int vidioc_s_ext_ctrls (struct file *file, void *priv, @@ -889,7 +889,7 @@ static int vidioc_s_ext_ctrls (struct file *file, void *priv, if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) return -EINVAL; p = dev->params; - err = cx2341x_ext_ctrls(&p, f, VIDIOC_S_EXT_CTRLS); + err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_S_EXT_CTRLS); if (!err) { err = cx2341x_update(dev, blackbird_mbox_func, &dev->params, &p); dev->params = p; @@ -907,7 +907,7 @@ static int vidioc_try_ext_ctrls (struct file *file, void *priv, if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) return -EINVAL; p = dev->params; - err = cx2341x_ext_ctrls(&p, f, VIDIOC_TRY_EXT_CTRLS); + err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS); return err; } diff --git a/drivers/media/video/ivtv/ivtv-controls.c b/drivers/media/video/ivtv/ivtv-controls.c index 7a876c3e5b1..0005ea46f20 100644 --- a/drivers/media/video/ivtv/ivtv-controls.c +++ b/drivers/media/video/ivtv/ivtv-controls.c @@ -232,7 +232,7 @@ int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg) IVTV_DEBUG_IOCTL("VIDIOC_S_EXT_CTRLS\n"); if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) { struct cx2341x_mpeg_params p = itv->params; - int err = cx2341x_ext_ctrls(&p, arg, cmd); + int err = cx2341x_ext_ctrls(&p, atomic_read(&itv->capturing), arg, cmd); if (err) return err; @@ -282,7 +282,7 @@ int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg) } IVTV_DEBUG_IOCTL("VIDIOC_G_EXT_CTRLS\n"); if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) - return cx2341x_ext_ctrls(&itv->params, arg, cmd); + return cx2341x_ext_ctrls(&itv->params, 0, arg, cmd); return -EINVAL; } @@ -292,7 +292,7 @@ int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg) IVTV_DEBUG_IOCTL("VIDIOC_TRY_EXT_CTRLS\n"); if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) - return cx2341x_ext_ctrls(&itv->params, arg, cmd); + return cx2341x_ext_ctrls(&itv->params, atomic_read(&itv->capturing), arg, cmd); return -EINVAL; } diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 1311891e7ee..2d5be5cfbcc 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -492,7 +492,7 @@ static int ctrl_cx2341x_get(struct pvr2_ctrl *cptr,int *vp) cs.controls = &c1; cs.count = 1; c1.id = cptr->info->v4l_id; - ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state,&cs, + ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state, 0, &cs, VIDIOC_G_EXT_CTRLS); if (ret) return ret; *vp = c1.value; @@ -510,7 +510,7 @@ static int ctrl_cx2341x_set(struct pvr2_ctrl *cptr,int m,int v) cs.count = 1; c1.id = cptr->info->v4l_id; c1.value = v; - ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state,&cs, + ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state, 0, &cs, VIDIOC_S_EXT_CTRLS); if (ret) return ret; cptr->hdw->enc_stale = !0; @@ -2478,7 +2478,7 @@ static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw) cs.count = 1; c1.id = V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ; c1.value = hdw->srate_val; - cx2341x_ext_ctrls(&hdw->enc_ctl_state,&cs,VIDIOC_S_EXT_CTRLS); + cx2341x_ext_ctrls(&hdw->enc_ctl_state, 0, &cs,VIDIOC_S_EXT_CTRLS); } /* Scan i2c core at this point - before we clear all the dirty diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index d2915d3530e..0689a041d77 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c @@ -716,6 +716,7 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste case V4L2_CID_AUDIO_MUTE: case V4L2_CID_AUDIO_LOUDNESS: case V4L2_CID_MPEG_AUDIO_MUTE: + case V4L2_CID_MPEG_VIDEO_MUTE: case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: case V4L2_CID_MPEG_VIDEO_PULLDOWN: qctrl->type = V4L2_CTRL_TYPE_BOOLEAN; diff --git a/include/media/cx2341x.h b/include/media/cx2341x.h index 38c12fed753..af8071d7620 100644 --- a/include/media/cx2341x.h +++ b/include/media/cx2341x.h @@ -91,7 +91,7 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func, int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl *qctrl); const char **cx2341x_ctrl_get_menu(u32 id); -int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, +int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, int busy, struct v4l2_ext_controls *ctrls, unsigned int cmd); void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p); void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix); -- cgit v1.2.3-70-g09d2 From d2a35fb172845fe75c40a3ee9c95656c7c115e48 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 22 Aug 2007 08:43:34 -0300 Subject: V4L/DVB (6089): ivtv: log in status if framebuffer uses YUV instead of RGB Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-ioctl.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index 0dde82f67e2..bb59634419c 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -1270,7 +1270,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void "Global and Local" }; static const char * const pixel_format[] = { - "Indexed", + "RGB Indexed", "RGB 5:6:5", "ARGB 1:5:5:5", "ARGB 1:4:4:4", @@ -1278,6 +1278,14 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void "5", "6", "7", + "YUV Indexed", + "YUV 5:6:5", + "AYUV 1:5:5:5", + "AYUV 1:4:4:4", + "AYUV 8:8:8:8", + "13", + "14", + "15", }; ivtv_get_output(itv, itv->active_output, &vidout); @@ -1290,10 +1298,11 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void mode = OUT_NONE; IVTV_INFO("Output Mode: %s\n", output_modes[mode]); ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0); + data[0] |= (read_reg(0x2a00) >> 7) & 0x40; IVTV_INFO("Overlay: %s, Alpha: %s, Pixel Format: %s\n", data[0] & 1 ? "On" : "Off", alpha_mode[(data[0] >> 1) & 0x3], - pixel_format[(data[0] >> 3) & 0x7]); + pixel_format[(data[0] >> 3) & 0xf]); } IVTV_INFO("Tuner: %s\n", test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? "Radio" : "TV"); -- cgit v1.2.3-70-g09d2 From 459a52fab2c42cd5fadfd51fdcfc6dea8107fabf Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 22 Aug 2007 08:58:47 -0300 Subject: V4L/DVB (6090): ivtv-fb: correct transparency bit reporting Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-fb.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c index 008076543ac..7618cd47a35 100644 --- a/drivers/media/video/ivtv/ivtv-fb.c +++ b/drivers/media/video/ivtv/ivtv-fb.c @@ -608,9 +608,6 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) var->blue.length = 8; } else if (var->bits_per_pixel == 16) { - var->transp.offset = 0; - var->transp.length = 0; - /* To find out the true mode, check green length */ switch (var->green.length) { case 4: @@ -620,6 +617,8 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) var->green.length = 4; var->blue.offset = 0; var->blue.length = 4; + var->transp.offset = 12; + var->transp.length = 1; break; case 5: var->red.offset = 10; @@ -628,6 +627,8 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) var->green.length = 5; var->blue.offset = 0; var->blue.length = 5; + var->transp.offset = 15; + var->transp.length = 1; break; default: var->red.offset = 11; @@ -636,6 +637,8 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) var->green.length = 6; var->blue.offset = 0; var->blue.length = 5; + var->transp.offset = 0; + var->transp.length = 0; break; } } -- cgit v1.2.3-70-g09d2 From 612570f2c4794bbf4e5bfa8648b61fbfc9cd8501 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 23 Aug 2007 05:42:59 -0300 Subject: V4L/DVB (6091): ivtv: header cleanup - add guards - remove unused header includes - move card-specific stuff from ivtv-driver.h to ivtv-cards.h - move YUV-specific stuff from ivtv-driver.h to ivtv-yuv.h Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-audio.c | 3 -- drivers/media/video/ivtv/ivtv-audio.h | 5 +++ drivers/media/video/ivtv/ivtv-cards.h | 64 +++++++++++++++++++++++++++ drivers/media/video/ivtv/ivtv-controls.h | 5 +++ drivers/media/video/ivtv/ivtv-driver.c | 7 --- drivers/media/video/ivtv/ivtv-driver.h | 74 +------------------------------- drivers/media/video/ivtv/ivtv-fileops.c | 1 - drivers/media/video/ivtv/ivtv-fileops.h | 5 +++ drivers/media/video/ivtv/ivtv-firmware.h | 5 +++ drivers/media/video/ivtv/ivtv-gpio.h | 5 +++ drivers/media/video/ivtv/ivtv-i2c.h | 5 +++ drivers/media/video/ivtv/ivtv-ioctl.h | 5 +++ drivers/media/video/ivtv/ivtv-irq.c | 3 -- drivers/media/video/ivtv/ivtv-irq.h | 5 +++ drivers/media/video/ivtv/ivtv-mailbox.h | 5 +++ drivers/media/video/ivtv/ivtv-queue.c | 2 - drivers/media/video/ivtv/ivtv-queue.h | 5 +++ drivers/media/video/ivtv/ivtv-streams.c | 8 +--- drivers/media/video/ivtv/ivtv-streams.h | 5 +++ drivers/media/video/ivtv/ivtv-udma.c | 1 - drivers/media/video/ivtv/ivtv-udma.h | 5 +++ drivers/media/video/ivtv/ivtv-vbi.h | 5 +++ drivers/media/video/ivtv/ivtv-version.h | 5 +++ drivers/media/video/ivtv/ivtv-video.h | 5 +++ drivers/media/video/ivtv/ivtv-yuv.c | 9 +++- drivers/media/video/ivtv/ivtv-yuv.h | 18 ++++++++ 26 files changed, 167 insertions(+), 98 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-audio.c b/drivers/media/video/ivtv/ivtv-audio.c index d702b8b539a..6cb65d69c98 100644 --- a/drivers/media/video/ivtv/ivtv-audio.c +++ b/drivers/media/video/ivtv/ivtv-audio.c @@ -19,13 +19,10 @@ */ #include "ivtv-driver.h" -#include "ivtv-mailbox.h" #include "ivtv-i2c.h" -#include "ivtv-gpio.h" #include "ivtv-cards.h" #include "ivtv-audio.h" #include -#include /* Selects the audio input and output according to the current settings. */ diff --git a/drivers/media/video/ivtv/ivtv-audio.h b/drivers/media/video/ivtv/ivtv-audio.h index 9c42846d812..ebb90cc8f86 100644 --- a/drivers/media/video/ivtv/ivtv-audio.h +++ b/drivers/media/video/ivtv/ivtv-audio.h @@ -18,6 +18,11 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_AUDIO_H +#define IVTV_AUDIO_H + int ivtv_audio_set_io(struct ivtv *itv); void ivtv_audio_set_route(struct ivtv *itv, struct v4l2_routing *route); void ivtv_audio_set_audio_clock_freq(struct ivtv *itv, u8 freq); + +#endif diff --git a/drivers/media/video/ivtv/ivtv-cards.h b/drivers/media/video/ivtv/ivtv-cards.h index 3191920f4c6..ff46e5ae865 100644 --- a/drivers/media/video/ivtv/ivtv-cards.h +++ b/drivers/media/video/ivtv/ivtv-cards.h @@ -18,6 +18,68 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_CARDS_H +#define IVTV_CARDS_H + +/* Supported cards */ +#define IVTV_CARD_PVR_250 0 /* WinTV PVR 250 */ +#define IVTV_CARD_PVR_350 1 /* encoder, decoder, tv-out */ +#define IVTV_CARD_PVR_150 2 /* WinTV PVR 150 and PVR 500 (really just two + PVR150s on one PCI board) */ +#define IVTV_CARD_M179 3 /* AVerMedia M179 (encoder only) */ +#define IVTV_CARD_MPG600 4 /* Kuroutoshikou ITVC16-STVLP/YUAN MPG600, encoder only */ +#define IVTV_CARD_MPG160 5 /* Kuroutoshikou ITVC15-STVLP/YUAN MPG160 + cx23415 based, but does not have tv-out */ +#define IVTV_CARD_PG600 6 /* YUAN PG600/DIAMONDMM PVR-550 based on the CX Falcon 2 */ +#define IVTV_CARD_AVC2410 7 /* Adaptec AVC-2410 */ +#define IVTV_CARD_AVC2010 8 /* Adaptec AVD-2010 (No Tuner) */ +#define IVTV_CARD_TG5000TV 9 /* NAGASE TRANSGEAR 5000TV, encoder only */ +#define IVTV_CARD_VA2000MAX_SNT6 10 /* VA2000MAX-STN6 */ +#define IVTV_CARD_CX23416GYC 11 /* Kuroutoshikou CX23416GYC-STVLP (Yuan MPG600GR OEM) */ +#define IVTV_CARD_GV_MVPRX 12 /* I/O Data GV-MVP/RX, RX2, RX2W */ +#define IVTV_CARD_GV_MVPRX2E 13 /* I/O Data GV-MVP/RX2E */ +#define IVTV_CARD_GOTVIEW_PCI_DVD 14 /* GotView PCI DVD */ +#define IVTV_CARD_GOTVIEW_PCI_DVD2 15 /* GotView PCI DVD2 */ +#define IVTV_CARD_YUAN_MPC622 16 /* Yuan MPC622 miniPCI */ +#define IVTV_CARD_DCTMTVP1 17 /* DIGITAL COWBOY DCT-MTVP1 */ +#define IVTV_CARD_PG600V2 18 /* Yuan PG600V2/GotView PCI DVD Lite */ +#define IVTV_CARD_CLUB3D 19 /* Club3D ZAP-TV1x01 */ +#define IVTV_CARD_AVERTV_MCE116 20 /* AVerTV MCE 116 Plus */ +#define IVTV_CARD_LAST 20 + +/* Variants of existing cards but with the same PCI IDs. The driver + detects these based on other device information. + These cards must always come last. + New cards must be inserted above, and the indices of the cards below + must be adjusted accordingly. */ + +/* PVR-350 V1 (uses saa7114) */ +#define IVTV_CARD_PVR_350_V1 (IVTV_CARD_LAST+1) +/* 2 variants of Kuroutoshikou CX23416GYC-STVLP (Yuan MPG600GR OEM) */ +#define IVTV_CARD_CX23416GYC_NOGR (IVTV_CARD_LAST+2) +#define IVTV_CARD_CX23416GYC_NOGRYCS (IVTV_CARD_LAST+3) + +/* system vendor and device IDs */ +#define PCI_VENDOR_ID_ICOMP 0x4444 +#define PCI_DEVICE_ID_IVTV15 0x0803 +#define PCI_DEVICE_ID_IVTV16 0x0016 + +/* subsystem vendor ID */ +#define IVTV_PCI_ID_HAUPPAUGE 0x0070 +#define IVTV_PCI_ID_HAUPPAUGE_ALT1 0x0270 +#define IVTV_PCI_ID_HAUPPAUGE_ALT2 0x4070 +#define IVTV_PCI_ID_ADAPTEC 0x9005 +#define IVTV_PCI_ID_AVERMEDIA 0x1461 +#define IVTV_PCI_ID_YUAN1 0x12ab +#define IVTV_PCI_ID_YUAN2 0xff01 +#define IVTV_PCI_ID_YUAN3 0xffab +#define IVTV_PCI_ID_YUAN4 0xfbab +#define IVTV_PCI_ID_DIAMONDMM 0xff92 +#define IVTV_PCI_ID_IODATA 0x10fc +#define IVTV_PCI_ID_MELCO 0x1154 +#define IVTV_PCI_ID_GOTVIEW1 0xffac +#define IVTV_PCI_ID_GOTVIEW2 0xffad + /* hardware flags */ #define IVTV_HW_CX25840 (1 << 0) #define IVTV_HW_SAA7115 (1 << 1) @@ -206,3 +268,5 @@ int ivtv_get_output(struct ivtv *itv, u16 index, struct v4l2_output *output); int ivtv_get_audio_input(struct ivtv *itv, u16 index, struct v4l2_audio *input); int ivtv_get_audio_output(struct ivtv *itv, u16 index, struct v4l2_audioout *output); const struct ivtv_card *ivtv_get_card(u16 index); + +#endif diff --git a/drivers/media/video/ivtv/ivtv-controls.h b/drivers/media/video/ivtv/ivtv-controls.h index 5a11149725a..bb8a6a5ed2b 100644 --- a/drivers/media/video/ivtv/ivtv-controls.h +++ b/drivers/media/video/ivtv/ivtv-controls.h @@ -18,4 +18,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_CONTROLS_H +#define IVTV_CONTROLS_H + int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg); + +#endif diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 93ddea49f0e..2ed9894672f 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -87,13 +87,6 @@ static struct pci_device_id ivtv_pci_tbl[] __devinitdata = { MODULE_DEVICE_TABLE(pci,ivtv_pci_tbl); -const u32 yuv_offset[4] = { - IVTV_YUV_BUFFER_OFFSET, - IVTV_YUV_BUFFER_OFFSET_1, - IVTV_YUV_BUFFER_OFFSET_2, - IVTV_YUV_BUFFER_OFFSET_3 -}; - /* Parameter declarations */ static int cardtype[IVTV_MAX_CARDS]; static int tuner[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 3ed4703956d..f7849f852e9 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -74,61 +74,10 @@ #define IVTV_REG_OFFSET 0x02000000 #define IVTV_REG_SIZE 0x00010000 -/* Buffers on hardware offsets */ -#define IVTV_YUV_BUFFER_OFFSET 0x001a8600 /* First YUV Buffer */ -#define IVTV_YUV_BUFFER_OFFSET_1 0x00240400 /* Second YUV Buffer */ -#define IVTV_YUV_BUFFER_OFFSET_2 0x002d8200 /* Third YUV Buffer */ -#define IVTV_YUV_BUFFER_OFFSET_3 0x00370000 /* Fourth YUV Buffer */ -#define IVTV_YUV_BUFFER_UV_OFFSET 0x65400 /* Offset to UV Buffer */ - -/* Offset to filter table in firmware */ -#define IVTV_YUV_HORIZONTAL_FILTER_OFFSET 0x025d8 -#define IVTV_YUV_VERTICAL_FILTER_OFFSET 0x03358 - -extern const u32 yuv_offset[4]; - /* Maximum ivtv driver instances. Some people have a huge number of capture cards, so set this to a high value. */ #define IVTV_MAX_CARDS 32 -/* Supported cards */ -#define IVTV_CARD_PVR_250 0 /* WinTV PVR 250 */ -#define IVTV_CARD_PVR_350 1 /* encoder, decoder, tv-out */ -#define IVTV_CARD_PVR_150 2 /* WinTV PVR 150 and PVR 500 (really just two - PVR150s on one PCI board) */ -#define IVTV_CARD_M179 3 /* AVerMedia M179 (encoder only) */ -#define IVTV_CARD_MPG600 4 /* Kuroutoshikou ITVC16-STVLP/YUAN MPG600, encoder only */ -#define IVTV_CARD_MPG160 5 /* Kuroutoshikou ITVC15-STVLP/YUAN MPG160 - cx23415 based, but does not have tv-out */ -#define IVTV_CARD_PG600 6 /* YUAN PG600/DIAMONDMM PVR-550 based on the CX Falcon 2 */ -#define IVTV_CARD_AVC2410 7 /* Adaptec AVC-2410 */ -#define IVTV_CARD_AVC2010 8 /* Adaptec AVD-2010 (No Tuner) */ -#define IVTV_CARD_TG5000TV 9 /* NAGASE TRANSGEAR 5000TV, encoder only */ -#define IVTV_CARD_VA2000MAX_SNT6 10 /* VA2000MAX-STN6 */ -#define IVTV_CARD_CX23416GYC 11 /* Kuroutoshikou CX23416GYC-STVLP (Yuan MPG600GR OEM) */ -#define IVTV_CARD_GV_MVPRX 12 /* I/O Data GV-MVP/RX, RX2, RX2W */ -#define IVTV_CARD_GV_MVPRX2E 13 /* I/O Data GV-MVP/RX2E */ -#define IVTV_CARD_GOTVIEW_PCI_DVD 14 /* GotView PCI DVD */ -#define IVTV_CARD_GOTVIEW_PCI_DVD2 15 /* GotView PCI DVD2 */ -#define IVTV_CARD_YUAN_MPC622 16 /* Yuan MPC622 miniPCI */ -#define IVTV_CARD_DCTMTVP1 17 /* DIGITAL COWBOY DCT-MTVP1 */ -#define IVTV_CARD_PG600V2 18 /* Yuan PG600V2/GotView PCI DVD Lite */ -#define IVTV_CARD_CLUB3D 19 /* Club3D ZAP-TV1x01 */ -#define IVTV_CARD_AVERTV_MCE116 20 /* AVerTV MCE 116 Plus */ -#define IVTV_CARD_LAST 20 - -/* Variants of existing cards but with the same PCI IDs. The driver - detects these based on other device information. - These cards must always come last. - New cards must be inserted above, and the indices of the cards below - must be adjusted accordingly. */ - -/* PVR-350 V1 (uses saa7114) */ -#define IVTV_CARD_PVR_350_V1 (IVTV_CARD_LAST+1) -/* 2 variants of Kuroutoshikou CX23416GYC-STVLP (Yuan MPG600GR OEM) */ -#define IVTV_CARD_CX23416GYC_NOGR (IVTV_CARD_LAST+2) -#define IVTV_CARD_CX23416GYC_NOGRYCS (IVTV_CARD_LAST+3) - #define IVTV_ENC_STREAM_TYPE_MPG 0 #define IVTV_ENC_STREAM_TYPE_YUV 1 #define IVTV_ENC_STREAM_TYPE_VBI 2 @@ -150,27 +99,6 @@ extern const u32 yuv_offset[4]; #define IVTV_ENC_MEM_START 0x00000000 #define IVTV_DEC_MEM_START 0x01000000 -/* system vendor and device IDs */ -#define PCI_VENDOR_ID_ICOMP 0x4444 -#define PCI_DEVICE_ID_IVTV15 0x0803 -#define PCI_DEVICE_ID_IVTV16 0x0016 - -/* subsystem vendor ID */ -#define IVTV_PCI_ID_HAUPPAUGE 0x0070 -#define IVTV_PCI_ID_HAUPPAUGE_ALT1 0x0270 -#define IVTV_PCI_ID_HAUPPAUGE_ALT2 0x4070 -#define IVTV_PCI_ID_ADAPTEC 0x9005 -#define IVTV_PCI_ID_AVERMEDIA 0x1461 -#define IVTV_PCI_ID_YUAN1 0x12ab -#define IVTV_PCI_ID_YUAN2 0xff01 -#define IVTV_PCI_ID_YUAN3 0xffab -#define IVTV_PCI_ID_YUAN4 0xfbab -#define IVTV_PCI_ID_DIAMONDMM 0xff92 -#define IVTV_PCI_ID_IODATA 0x10fc -#define IVTV_PCI_ID_MELCO 0x1154 -#define IVTV_PCI_ID_GOTVIEW1 0xffac -#define IVTV_PCI_ID_GOTVIEW2 0xffad - /* Decoder Buffer hardware size on Chip */ #define IVTV_DEC_MAX_BUF 0x00100000 /* max bytes in decoder buffer */ #define IVTV_DEC_MIN_BUF 0x00010000 /* min bytes in dec buffer */ @@ -890,4 +818,4 @@ int ivtv_init_on_first_open(struct ivtv *itv); #define write_dec_sync(val, addr) \ do { write_dec(val, addr); read_dec(addr); } while (0) -#endif /* IVTV_DRIVER_H */ +#endif diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index 62ee41c5220..6449f5831e6 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -30,7 +30,6 @@ #include "ivtv-audio.h" #include "ivtv-streams.h" #include "ivtv-yuv.h" -#include "ivtv-controls.h" #include "ivtv-ioctl.h" #include "ivtv-cards.h" #include diff --git a/drivers/media/video/ivtv/ivtv-fileops.h b/drivers/media/video/ivtv/ivtv-fileops.h index 74a1745fabb..2c8d5186c9c 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.h +++ b/drivers/media/video/ivtv/ivtv-fileops.h @@ -18,6 +18,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_FILEOPS_H +#define IVTV_FILEOPS_H + /* Testing/Debugging */ int ivtv_v4l2_open(struct inode *inode, struct file *filp); ssize_t ivtv_v4l2_read(struct file *filp, char __user *buf, size_t count, @@ -42,3 +45,5 @@ int ivtv_claim_stream(struct ivtv_open_id *id, int type); /* Release a previously claimed stream. */ void ivtv_release_stream(struct ivtv_stream *s); + +#endif diff --git a/drivers/media/video/ivtv/ivtv-firmware.h b/drivers/media/video/ivtv/ivtv-firmware.h index 8b2ffe65890..041ba94e65b 100644 --- a/drivers/media/video/ivtv/ivtv-firmware.h +++ b/drivers/media/video/ivtv/ivtv-firmware.h @@ -19,7 +19,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_FIRMWARE_H +#define IVTV_FIRMWARE_H + int ivtv_firmware_init(struct ivtv *itv); void ivtv_firmware_versions(struct ivtv *itv); void ivtv_halt_firmware(struct ivtv *itv); void ivtv_init_mpeg_decoder(struct ivtv *itv); + +#endif diff --git a/drivers/media/video/ivtv/ivtv-gpio.h b/drivers/media/video/ivtv/ivtv-gpio.h index b31c679bbd8..964a265d91a 100644 --- a/drivers/media/video/ivtv/ivtv-gpio.h +++ b/drivers/media/video/ivtv/ivtv-gpio.h @@ -18,8 +18,13 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_GPIO_H +#define IVTV_GPIO_H + /* GPIO stuff */ void ivtv_gpio_init(struct ivtv *itv); void ivtv_reset_ir_gpio(struct ivtv *itv); int ivtv_reset_tuner_gpio(void *dev, int cmd, int value); int ivtv_gpio(struct ivtv *itv, unsigned int command, void *arg); + +#endif diff --git a/drivers/media/video/ivtv/ivtv-i2c.h b/drivers/media/video/ivtv/ivtv-i2c.h index 5d210adb5c5..677c3292855 100644 --- a/drivers/media/video/ivtv/ivtv-i2c.h +++ b/drivers/media/video/ivtv/ivtv-i2c.h @@ -18,6 +18,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_I2C_H +#define IVTV_I2C_H + int ivtv_cx25840(struct ivtv *itv, unsigned int cmd, void *arg); int ivtv_saa7115(struct ivtv *itv, unsigned int cmd, void *arg); int ivtv_saa7127(struct ivtv *itv, unsigned int cmd, void *arg); @@ -34,3 +37,5 @@ void ivtv_call_i2c_clients(struct ivtv *itv, unsigned int cmd, void *arg); /* init + register i2c algo-bit adapter */ int __devinit init_ivtv_i2c(struct ivtv *itv); void __devexit exit_ivtv_i2c(struct ivtv *itv); + +#endif diff --git a/drivers/media/video/ivtv/ivtv-ioctl.h b/drivers/media/video/ivtv/ivtv-ioctl.h index cbccf7a9f65..a03351b6853 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.h +++ b/drivers/media/video/ivtv/ivtv-ioctl.h @@ -18,6 +18,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_IOCTL_H +#define IVTV_IOCTL_H + u16 service2vbi(int type); void expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal); u16 get_service_set(struct v4l2_sliced_vbi_format *fmt); @@ -26,3 +29,5 @@ int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void *arg); void ivtv_set_osd_alpha(struct ivtv *itv); int ivtv_set_speed(struct ivtv *itv, int speed); + +#endif diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c index d68853fd60a..b6a94a1ad19 100644 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ b/drivers/media/video/ivtv/ivtv-irq.c @@ -19,12 +19,9 @@ */ #include "ivtv-driver.h" -#include "ivtv-firmware.h" -#include "ivtv-fileops.h" #include "ivtv-queue.h" #include "ivtv-udma.h" #include "ivtv-irq.h" -#include "ivtv-ioctl.h" #include "ivtv-mailbox.h" #include "ivtv-vbi.h" #include "ivtv-yuv.h" diff --git a/drivers/media/video/ivtv/ivtv-irq.h b/drivers/media/video/ivtv/ivtv-irq.h index a43348a3030..e180bd34898 100644 --- a/drivers/media/video/ivtv/ivtv-irq.h +++ b/drivers/media/video/ivtv/ivtv-irq.h @@ -19,8 +19,13 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_IRQ_H +#define IVTV_IRQ_H + irqreturn_t ivtv_irq_handler(int irq, void *dev_id); void ivtv_irq_work_handler(struct work_struct *work); void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock); void ivtv_unfinished_dma(unsigned long arg); + +#endif diff --git a/drivers/media/video/ivtv/ivtv-mailbox.h b/drivers/media/video/ivtv/ivtv-mailbox.h index 79b8aec1437..90c871b8e23 100644 --- a/drivers/media/video/ivtv/ivtv-mailbox.h +++ b/drivers/media/video/ivtv/ivtv-mailbox.h @@ -18,8 +18,13 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_MAILBOX_H +#define IVTV_MAILBOX_H + void ivtv_api_get_data(struct ivtv_mailbox_data *mbox, int mb, u32 data[]); int ivtv_api(struct ivtv *itv, int cmd, int args, u32 data[]); int ivtv_vapi_result(struct ivtv *itv, u32 data[CX2341X_MBOX_MAX_DATA], int cmd, int args, ...); int ivtv_vapi(struct ivtv *itv, int cmd, int args, ...); int ivtv_api_func(void *priv, int cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]); + +#endif diff --git a/drivers/media/video/ivtv/ivtv-queue.c b/drivers/media/video/ivtv/ivtv-queue.c index d9a1478ca1f..437f134796e 100644 --- a/drivers/media/video/ivtv/ivtv-queue.c +++ b/drivers/media/video/ivtv/ivtv-queue.c @@ -20,9 +20,7 @@ */ #include "ivtv-driver.h" -#include "ivtv-streams.h" #include "ivtv-queue.h" -#include "ivtv-mailbox.h" int ivtv_buf_copy_from_user(struct ivtv_stream *s, struct ivtv_buffer *buf, const char __user *src, int copybytes) { diff --git a/drivers/media/video/ivtv/ivtv-queue.h b/drivers/media/video/ivtv/ivtv-queue.h index 14a9f7fe50a..7cfc0c9ab05 100644 --- a/drivers/media/video/ivtv/ivtv-queue.h +++ b/drivers/media/video/ivtv/ivtv-queue.h @@ -19,6 +19,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_QUEUE_H +#define IVTV_QUEUE_H + #define IVTV_DMA_UNMAPPED ((u32) -1) #define SLICED_VBI_PIO 1 @@ -89,3 +92,5 @@ static inline void ivtv_stream_sync_for_device(struct ivtv_stream *s) pci_dma_sync_single_for_device(s->itv->dev, s->sg_handle, sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE); } + +#endif diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index ebf925c549f..fae151a31e8 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -35,16 +35,12 @@ #include "ivtv-driver.h" #include "ivtv-fileops.h" -#include "ivtv-i2c.h" #include "ivtv-queue.h" #include "ivtv-mailbox.h" -#include "ivtv-audio.h" -#include "ivtv-video.h" -#include "ivtv-vbi.h" #include "ivtv-ioctl.h" -#include "ivtv-irq.h" -#include "ivtv-streams.h" +#include "ivtv-yuv.h" #include "ivtv-cards.h" +#include "ivtv-streams.h" static struct file_operations ivtv_v4l2_enc_fops = { .owner = THIS_MODULE, diff --git a/drivers/media/video/ivtv/ivtv-streams.h b/drivers/media/video/ivtv/ivtv-streams.h index 8597b75384a..8f5f5b1c7c8 100644 --- a/drivers/media/video/ivtv/ivtv-streams.h +++ b/drivers/media/video/ivtv/ivtv-streams.h @@ -18,6 +18,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_STREAMS_H +#define IVTV_STREAMS_H + int ivtv_streams_setup(struct ivtv *itv); void ivtv_streams_cleanup(struct ivtv *itv); @@ -29,3 +32,5 @@ int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts); void ivtv_stop_all_captures(struct ivtv *itv); int ivtv_passthrough_mode(struct ivtv *itv, int enable); + +#endif diff --git a/drivers/media/video/ivtv/ivtv-udma.c b/drivers/media/video/ivtv/ivtv-udma.c index 7e503adacea..c4626d1cdf4 100644 --- a/drivers/media/video/ivtv/ivtv-udma.c +++ b/drivers/media/video/ivtv/ivtv-udma.c @@ -21,7 +21,6 @@ */ #include "ivtv-driver.h" -#include "ivtv-streams.h" #include "ivtv-udma.h" void ivtv_udma_get_page_info(struct ivtv_dma_page_info *dma_page, unsigned long first, unsigned long size) diff --git a/drivers/media/video/ivtv/ivtv-udma.h b/drivers/media/video/ivtv/ivtv-udma.h index e131bccedec..df727e23be0 100644 --- a/drivers/media/video/ivtv/ivtv-udma.h +++ b/drivers/media/video/ivtv/ivtv-udma.h @@ -18,6 +18,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_UDMA_H +#define IVTV_UDMA_H + /* User DMA functions */ void ivtv_udma_get_page_info(struct ivtv_dma_page_info *dma_page, unsigned long first, unsigned long size); int ivtv_udma_fill_sg_list(struct ivtv_user_dma *dma, struct ivtv_dma_page_info *dma_page, int map_offset); @@ -41,3 +44,5 @@ static inline void ivtv_udma_sync_for_cpu(struct ivtv *itv) pci_dma_sync_single_for_cpu((struct pci_dev *)itv->dev, itv->udma.SG_handle, sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE); } + +#endif diff --git a/drivers/media/video/ivtv/ivtv-vbi.h b/drivers/media/video/ivtv/ivtv-vbi.h index ec211b49702..d5740493a69 100644 --- a/drivers/media/video/ivtv/ivtv-vbi.h +++ b/drivers/media/video/ivtv/ivtv-vbi.h @@ -17,6 +17,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_VBI_H +#define IVTV_VBI_H + ssize_t ivtv_write_vbi(struct ivtv *itv, const char __user *ubuf, size_t count); void ivtv_process_vbi_data(struct ivtv *itv, struct ivtv_buffer *buf, u64 pts_stamp, int streamtype); @@ -24,3 +27,5 @@ int ivtv_used_line(struct ivtv *itv, int line, int field); void ivtv_disable_vbi(struct ivtv *itv); void ivtv_set_vbi(unsigned long arg); void ivtv_vbi_work_handler(struct ivtv *itv); + +#endif diff --git a/drivers/media/video/ivtv/ivtv-version.h b/drivers/media/video/ivtv/ivtv-version.h index 122d5610596..d050de2a722 100644 --- a/drivers/media/video/ivtv/ivtv-version.h +++ b/drivers/media/video/ivtv/ivtv-version.h @@ -17,6 +17,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_VERSION_H +#define IVTV_VERSION_H + #define IVTV_DRIVER_NAME "ivtv" #define IVTV_DRIVER_VERSION_MAJOR 1 #define IVTV_DRIVER_VERSION_MINOR 1 @@ -24,3 +27,5 @@ #define IVTV_VERSION __stringify(IVTV_DRIVER_VERSION_MAJOR) "." __stringify(IVTV_DRIVER_VERSION_MINOR) "." __stringify(IVTV_DRIVER_VERSION_PATCHLEVEL) #define IVTV_DRIVER_VERSION KERNEL_VERSION(IVTV_DRIVER_VERSION_MAJOR,IVTV_DRIVER_VERSION_MINOR,IVTV_DRIVER_VERSION_PATCHLEVEL) + +#endif diff --git a/drivers/media/video/ivtv/ivtv-video.h b/drivers/media/video/ivtv/ivtv-video.h index c8ade5d3c41..498e9b61c22 100644 --- a/drivers/media/video/ivtv/ivtv-video.h +++ b/drivers/media/video/ivtv/ivtv-video.h @@ -17,8 +17,13 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_VIDEO_H +#define IVTV_VIDEO_H + void ivtv_set_wss(struct ivtv *itv, int enabled, int mode); void ivtv_set_cc(struct ivtv *itv, int mode, u8 cc1, u8 cc2, u8 cc3, u8 cc4); void ivtv_set_vps(struct ivtv *itv, int enabled, u8 vps1, u8 vps2, u8 vps3, u8 vps4, u8 vps5); void ivtv_video_set_io(struct ivtv *itv); + +#endif diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c index 1922c1da20d..bb2cbb206c1 100644 --- a/drivers/media/video/ivtv/ivtv-yuv.c +++ b/drivers/media/video/ivtv/ivtv-yuv.c @@ -19,11 +19,16 @@ */ #include "ivtv-driver.h" -#include "ivtv-queue.h" #include "ivtv-udma.h" -#include "ivtv-irq.h" #include "ivtv-yuv.h" +const u32 yuv_offset[4] = { + IVTV_YUV_BUFFER_OFFSET, + IVTV_YUV_BUFFER_OFFSET_1, + IVTV_YUV_BUFFER_OFFSET_2, + IVTV_YUV_BUFFER_OFFSET_3 +}; + static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, struct ivtv_dma_frame *args) { diff --git a/drivers/media/video/ivtv/ivtv-yuv.h b/drivers/media/video/ivtv/ivtv-yuv.h index 88972d3f77c..0824048ce3a 100644 --- a/drivers/media/video/ivtv/ivtv-yuv.h +++ b/drivers/media/video/ivtv/ivtv-yuv.h @@ -18,7 +18,25 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef IVTV_YUV_H +#define IVTV_YUV_H + +/* Buffers on hardware offsets */ +#define IVTV_YUV_BUFFER_OFFSET 0x001a8600 /* First YUV Buffer */ +#define IVTV_YUV_BUFFER_OFFSET_1 0x00240400 /* Second YUV Buffer */ +#define IVTV_YUV_BUFFER_OFFSET_2 0x002d8200 /* Third YUV Buffer */ +#define IVTV_YUV_BUFFER_OFFSET_3 0x00370000 /* Fourth YUV Buffer */ +#define IVTV_YUV_BUFFER_UV_OFFSET 0x65400 /* Offset to UV Buffer */ + +/* Offset to filter table in firmware */ +#define IVTV_YUV_HORIZONTAL_FILTER_OFFSET 0x025d8 +#define IVTV_YUV_VERTICAL_FILTER_OFFSET 0x03358 + +extern const u32 yuv_offset[4]; + int ivtv_yuv_filter_check(struct ivtv *itv); int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args); void ivtv_yuv_close(struct ivtv *itv); void ivtv_yuv_work_handler (struct ivtv *itv); + +#endif -- cgit v1.2.3-70-g09d2 From 33c0fcad2160bc211272295e862c6f708118d006 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 23 Aug 2007 06:32:46 -0300 Subject: V4L/DVB (6092): ivtv: more cleanups, merged ivtv-audio.c and ivtv-video.c into ivtv-routing.c Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/Makefile | 4 +- drivers/media/video/ivtv/ivtv-audio.c | 71 ---------------- drivers/media/video/ivtv/ivtv-audio.h | 28 ------ drivers/media/video/ivtv/ivtv-controls.c | 10 ++- drivers/media/video/ivtv/ivtv-driver.c | 14 ++- drivers/media/video/ivtv/ivtv-driver.h | 113 ++++-------------------- drivers/media/video/ivtv/ivtv-fb.c | 2 +- drivers/media/video/ivtv/ivtv-fileops.c | 2 +- drivers/media/video/ivtv/ivtv-ioctl.c | 5 +- drivers/media/video/ivtv/ivtv-irq.h | 22 +++++ drivers/media/video/ivtv/ivtv-mailbox.h | 3 + drivers/media/video/ivtv/ivtv-routing.c | 116 +++++++++++++++++++++++++ drivers/media/video/ivtv/ivtv-routing.h | 27 ++++++ drivers/media/video/ivtv/ivtv-streams.c | 16 +++- drivers/media/video/ivtv/ivtv-vbi.c | 64 +++++++++++++- drivers/media/video/ivtv/ivtv-video.c | 142 ------------------------------- drivers/media/video/ivtv/ivtv-video.h | 29 ------- drivers/media/video/ivtv/ivtv-yuv.c | 4 +- drivers/media/video/ivtv/ivtv-yuv.h | 3 + 19 files changed, 290 insertions(+), 385 deletions(-) delete mode 100644 drivers/media/video/ivtv/ivtv-audio.c delete mode 100644 drivers/media/video/ivtv/ivtv-audio.h create mode 100644 drivers/media/video/ivtv/ivtv-routing.c create mode 100644 drivers/media/video/ivtv/ivtv-routing.h delete mode 100644 drivers/media/video/ivtv/ivtv-video.c delete mode 100644 drivers/media/video/ivtv/ivtv-video.h (limited to 'drivers') diff --git a/drivers/media/video/ivtv/Makefile b/drivers/media/video/ivtv/Makefile index 90e2d127056..6998781e2b1 100644 --- a/drivers/media/video/ivtv/Makefile +++ b/drivers/media/video/ivtv/Makefile @@ -1,8 +1,8 @@ -ivtv-objs := ivtv-audio.o ivtv-cards.o ivtv-controls.o \ +ivtv-objs := ivtv-routing.o ivtv-cards.o ivtv-controls.o \ ivtv-driver.o ivtv-fileops.o ivtv-firmware.o \ ivtv-gpio.o ivtv-i2c.o ivtv-ioctl.o ivtv-irq.o \ ivtv-mailbox.o ivtv-queue.o ivtv-streams.o ivtv-udma.o \ - ivtv-vbi.o ivtv-video.o ivtv-yuv.o + ivtv-vbi.o ivtv-yuv.o obj-$(CONFIG_VIDEO_IVTV) += ivtv.o obj-$(CONFIG_VIDEO_IVTV_FB) += ivtv-fb.o diff --git a/drivers/media/video/ivtv/ivtv-audio.c b/drivers/media/video/ivtv/ivtv-audio.c deleted file mode 100644 index 6cb65d69c98..00000000000 --- a/drivers/media/video/ivtv/ivtv-audio.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - Audio-related ivtv functions. - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2005-2007 Hans Verkuil - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "ivtv-driver.h" -#include "ivtv-i2c.h" -#include "ivtv-cards.h" -#include "ivtv-audio.h" -#include - -/* Selects the audio input and output according to the current - settings. */ -int ivtv_audio_set_io(struct ivtv *itv) -{ - struct v4l2_routing route; - u32 audio_input; - int mux_input; - - /* Determine which input to use */ - if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) { - audio_input = itv->card->radio_input.audio_input; - mux_input = itv->card->radio_input.muxer_input; - } else { - audio_input = itv->card->audio_inputs[itv->audio_input].audio_input; - mux_input = itv->card->audio_inputs[itv->audio_input].muxer_input; - } - - /* handle muxer chips */ - route.input = mux_input; - route.output = 0; - ivtv_i2c_hw(itv, itv->card->hw_muxer, VIDIOC_INT_S_AUDIO_ROUTING, &route); - - route.input = audio_input; - if (itv->card->hw_audio & IVTV_HW_MSP34XX) { - route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1); - } - return ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, &route); -} - -void ivtv_audio_set_route(struct ivtv *itv, struct v4l2_routing *route) -{ - ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, route); -} - -void ivtv_audio_set_audio_clock_freq(struct ivtv *itv, u8 freq) -{ - static u32 freqs[3] = { 44100, 48000, 32000 }; - - /* The audio clock of the digitizer must match the codec sample - rate otherwise you get some very strange effects. */ - if (freq > 2) - return; - ivtv_call_i2c_clients(itv, VIDIOC_INT_AUDIO_CLOCK_FREQ, &freqs[freq]); -} - diff --git a/drivers/media/video/ivtv/ivtv-audio.h b/drivers/media/video/ivtv/ivtv-audio.h deleted file mode 100644 index ebb90cc8f86..00000000000 --- a/drivers/media/video/ivtv/ivtv-audio.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - Audio-related ivtv functions. - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2005-2007 Hans Verkuil - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef IVTV_AUDIO_H -#define IVTV_AUDIO_H - -int ivtv_audio_set_io(struct ivtv *itv); -void ivtv_audio_set_route(struct ivtv *itv, struct v4l2_routing *route); -void ivtv_audio_set_audio_clock_freq(struct ivtv *itv, u8 freq); - -#endif diff --git a/drivers/media/video/ivtv/ivtv-controls.c b/drivers/media/video/ivtv/ivtv-controls.c index 0005ea46f20..8c02fa66159 100644 --- a/drivers/media/video/ivtv/ivtv-controls.c +++ b/drivers/media/video/ivtv/ivtv-controls.c @@ -21,7 +21,7 @@ #include "ivtv-driver.h" #include "ivtv-cards.h" #include "ivtv-ioctl.h" -#include "ivtv-audio.h" +#include "ivtv-routing.h" #include "ivtv-i2c.h" #include "ivtv-mailbox.h" #include "ivtv-controls.h" @@ -231,8 +231,10 @@ int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg) } IVTV_DEBUG_IOCTL("VIDIOC_S_EXT_CTRLS\n"); if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) { + static u32 freqs[3] = { 44100, 48000, 32000 }; struct cx2341x_mpeg_params p = itv->params; int err = cx2341x_ext_ctrls(&p, atomic_read(&itv->capturing), arg, cmd); + unsigned idx; if (err) return err; @@ -254,7 +256,11 @@ int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg) } itv->params = p; itv->dualwatch_stereo_mode = p.audio_properties & 0x0300; - ivtv_audio_set_audio_clock_freq(itv, p.audio_properties & 0x03); + idx = p.audio_properties & 0x03; + /* The audio clock of the digitizer must match the codec sample + rate otherwise you get some very strange effects. */ + if (idx < sizeof(freqs)) + ivtv_call_i2c_clients(itv, VIDIOC_INT_AUDIO_CLOCK_FREQ, &freqs[idx]); return err; } return -EINVAL; diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 2ed9894672f..6a74e509c87 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -52,7 +52,7 @@ #include "ivtv-ioctl.h" #include "ivtv-cards.h" #include "ivtv-vbi.h" -#include "ivtv-audio.h" +#include "ivtv-routing.h" #include "ivtv-gpio.h" #include "ivtv-yuv.h" @@ -106,6 +106,18 @@ static char secam[] = "--"; static char ntsc[] = "-"; /* Buffers */ + +/* DMA Buffers, Default size in MB allocated */ +#define IVTV_DEFAULT_ENC_MPG_BUFFERS 4 +#define IVTV_DEFAULT_ENC_YUV_BUFFERS 2 +#define IVTV_DEFAULT_ENC_VBI_BUFFERS 1 +/* Exception: size in kB for this stream (MB is overkill) */ +#define IVTV_DEFAULT_ENC_PCM_BUFFERS 320 +#define IVTV_DEFAULT_DEC_MPG_BUFFERS 1 +#define IVTV_DEFAULT_DEC_YUV_BUFFERS 1 +/* Exception: size in kB for this stream (MB is way overkill) */ +#define IVTV_DEFAULT_DEC_VBI_BUFFERS 64 + static int enc_mpg_buffers = IVTV_DEFAULT_ENC_MPG_BUFFERS; static int enc_yuv_buffers = IVTV_DEFAULT_ENC_YUV_BUFFERS; static int enc_vbi_buffers = IVTV_DEFAULT_ENC_VBI_BUFFERS; diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index f7849f852e9..b9dfdab6636 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -65,12 +65,11 @@ #include +/* Memory layout */ #define IVTV_ENCODER_OFFSET 0x00000000 -#define IVTV_ENCODER_SIZE 0x00800000 /* Last half isn't needed 0x01000000 */ - +#define IVTV_ENCODER_SIZE 0x00800000 /* Total size is 0x01000000, but only first half is used */ #define IVTV_DECODER_OFFSET 0x01000000 -#define IVTV_DECODER_SIZE 0x00800000 /* Last half isn't needed 0x01000000 */ - +#define IVTV_DECODER_SIZE 0x00800000 /* Total size is 0x01000000, but only first half is used */ #define IVTV_REG_OFFSET 0x02000000 #define IVTV_REG_SIZE 0x00010000 @@ -89,51 +88,8 @@ #define IVTV_DEC_STREAM_TYPE_YUV 8 #define IVTV_MAX_STREAMS 9 -#define IVTV_V4L2_DEC_MPG_OFFSET 16 /* offset from 0 to register decoder mpg v4l2 minors on */ -#define IVTV_V4L2_ENC_PCM_OFFSET 24 /* offset from 0 to register pcm v4l2 minors on */ -#define IVTV_V4L2_ENC_YUV_OFFSET 32 /* offset from 0 to register yuv v4l2 minors on */ -#define IVTV_V4L2_DEC_YUV_OFFSET 48 /* offset from 0 to register decoder yuv v4l2 minors on */ -#define IVTV_V4L2_DEC_VBI_OFFSET 8 /* offset from 0 to register decoder vbi input v4l2 minors on */ -#define IVTV_V4L2_DEC_VOUT_OFFSET 16 /* offset from 0 to register vbi output v4l2 minors on */ - -#define IVTV_ENC_MEM_START 0x00000000 -#define IVTV_DEC_MEM_START 0x01000000 - -/* Decoder Buffer hardware size on Chip */ -#define IVTV_DEC_MAX_BUF 0x00100000 /* max bytes in decoder buffer */ -#define IVTV_DEC_MIN_BUF 0x00010000 /* min bytes in dec buffer */ - -/* ======================================================================== */ -/* ========================== START USER SETTABLE DMA VARIABLES =========== */ -/* ======================================================================== */ - #define IVTV_DMA_SG_OSD_ENT (2883584/PAGE_SIZE) /* sg entities */ -/* DMA Buffers, Default size in MB allocated */ -#define IVTV_DEFAULT_ENC_MPG_BUFFERS 4 -#define IVTV_DEFAULT_ENC_YUV_BUFFERS 2 -#define IVTV_DEFAULT_ENC_VBI_BUFFERS 1 -/* Exception: size in kB for this stream (MB is overkill) */ -#define IVTV_DEFAULT_ENC_PCM_BUFFERS 320 -#define IVTV_DEFAULT_DEC_MPG_BUFFERS 1 -#define IVTV_DEFAULT_DEC_YUV_BUFFERS 1 -/* Exception: size in kB for this stream (MB is way overkill) */ -#define IVTV_DEFAULT_DEC_VBI_BUFFERS 64 - -/* ======================================================================== */ -/* ========================== END USER SETTABLE DMA VARIABLES ============= */ -/* ======================================================================== */ - -/* Decoder Status Register */ -#define IVTV_DMA_ERR_LIST 0x00000010 -#define IVTV_DMA_ERR_WRITE 0x00000008 -#define IVTV_DMA_ERR_READ 0x00000004 -#define IVTV_DMA_SUCCESS_WRITE 0x00000002 -#define IVTV_DMA_SUCCESS_READ 0x00000001 -#define IVTV_DMA_READ_ERR (IVTV_DMA_ERR_LIST | IVTV_DMA_ERR_READ) -#define IVTV_DMA_WRITE_ERR (IVTV_DMA_ERR_LIST | IVTV_DMA_ERR_WRITE) -#define IVTV_DMA_ERR (IVTV_DMA_ERR_LIST | IVTV_DMA_ERR_WRITE | IVTV_DMA_ERR_READ) - /* DMA Registers */ #define IVTV_REG_DMAXFER (0x0000) #define IVTV_REG_DMASTATUS (0x0004) @@ -156,32 +112,11 @@ #define IVTV_REG_VPU (0x9058) #define IVTV_REG_APU (0xA064) -#define IVTV_IRQ_ENC_START_CAP (0x1 << 31) -#define IVTV_IRQ_ENC_EOS (0x1 << 30) -#define IVTV_IRQ_ENC_VBI_CAP (0x1 << 29) -#define IVTV_IRQ_ENC_VIM_RST (0x1 << 28) -#define IVTV_IRQ_ENC_DMA_COMPLETE (0x1 << 27) -#define IVTV_IRQ_ENC_PIO_COMPLETE (0x1 << 25) -#define IVTV_IRQ_DEC_AUD_MODE_CHG (0x1 << 24) -#define IVTV_IRQ_DEC_DATA_REQ (0x1 << 22) -#define IVTV_IRQ_DEC_DMA_COMPLETE (0x1 << 20) -#define IVTV_IRQ_DEC_VBI_RE_INSERT (0x1 << 19) -#define IVTV_IRQ_DMA_ERR (0x1 << 18) -#define IVTV_IRQ_DMA_WRITE (0x1 << 17) -#define IVTV_IRQ_DMA_READ (0x1 << 16) -#define IVTV_IRQ_DEC_VSYNC (0x1 << 10) - -/* IRQ Masks */ -#define IVTV_IRQ_MASK_INIT (IVTV_IRQ_DMA_ERR|IVTV_IRQ_ENC_DMA_COMPLETE|\ - IVTV_IRQ_DMA_READ|IVTV_IRQ_ENC_PIO_COMPLETE) - -#define IVTV_IRQ_MASK_CAPTURE (IVTV_IRQ_ENC_START_CAP | IVTV_IRQ_ENC_EOS) -#define IVTV_IRQ_MASK_DECODE (IVTV_IRQ_DEC_DATA_REQ|IVTV_IRQ_DEC_AUD_MODE_CHG) - /* i2c stuff */ #define I2C_CLIENTS_MAX 16 /* debugging */ +extern int ivtv_debug; #define IVTV_DBGFLG_WARN (1 << 0) #define IVTV_DBGFLG_INFO (1 << 1) @@ -235,11 +170,6 @@ #define IVTV_WARN(fmt, args...) printk(KERN_WARNING "ivtv%d: " fmt, itv->num , ## args) #define IVTV_INFO(fmt, args...) printk(KERN_INFO "ivtv%d: " fmt, itv->num , ## args) -/* Values for IVTV_API_DEC_PLAYBACK_SPEED mpeg_frame_type_mask parameter: */ -#define MPEG_FRAME_TYPE_IFRAME 1 -#define MPEG_FRAME_TYPE_IFRAME_PFRAME 3 -#define MPEG_FRAME_TYPE_ALL 7 - /* output modes (cx23415 only) */ #define OUT_NONE 0 #define OUT_MPG 1 @@ -249,9 +179,6 @@ #define IVTV_MAX_PGM_INDEX (400) -extern int ivtv_debug; - - struct ivtv_options { int kilobytes[IVTV_MAX_STREAMS]; /* Size in kilobytes of each stream */ int cardtype; /* force card type on load */ @@ -260,11 +187,6 @@ struct ivtv_options { int newi2c; /* New I2C algorithm */ }; -#define IVTV_MBOX_DMA_START 6 -#define IVTV_MBOX_DMA_END 8 -#define IVTV_MBOX_DMA 9 -#define IVTV_MBOX_FIELD_DISPLAYED 8 - /* ivtv-specific mailbox template */ struct ivtv_mailbox { u32 flags; @@ -450,31 +372,28 @@ struct ivtv_open_id { struct ivtv *itv; }; -#define IVTV_YUV_UPDATE_HORIZONTAL 0x01 -#define IVTV_YUV_UPDATE_VERTICAL 0x02 - struct yuv_frame_info { u32 update; - int src_x; - int src_y; - unsigned int src_w; - unsigned int src_h; - int dst_x; - int dst_y; - unsigned int dst_w; - unsigned int dst_h; - int pan_x; - int pan_y; + s32 src_x; + s32 src_y; + u32 src_w; + u32 src_h; + s32 dst_x; + s32 dst_y; + u32 dst_w; + u32 dst_h; + s32 pan_x; + s32 pan_y; u32 vis_w; u32 vis_h; u32 interlaced_y; u32 interlaced_uv; - int tru_x; + s32 tru_x; u32 tru_w; u32 tru_h; u32 offset_y; - int lace_mode; + s32 lace_mode; }; #define IVTV_YUV_MODE_INTERLACED 0x00 diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c index 7618cd47a35..2c521d1bb05 100644 --- a/drivers/media/video/ivtv/ivtv-fb.c +++ b/drivers/media/video/ivtv/ivtv-fb.c @@ -382,7 +382,7 @@ static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source, } /* OSD Address to send DMA to */ - dest_offset += IVTV_DEC_MEM_START + oi->video_rbase; + dest_offset += IVTV_DECODER_OFFSET + oi->video_rbase; /* Fill Buffers */ return ivtv_fb_prep_dec_dma_to_device(itv, dest_offset, source, count); diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index 6449f5831e6..170bef61aa6 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -27,7 +27,7 @@ #include "ivtv-irq.h" #include "ivtv-vbi.h" #include "ivtv-mailbox.h" -#include "ivtv-audio.h" +#include "ivtv-routing.h" #include "ivtv-streams.h" #include "ivtv-yuv.h" #include "ivtv-ioctl.h" diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index bb59634419c..f4f56a6e1f8 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -25,8 +25,7 @@ #include "ivtv-queue.h" #include "ivtv-fileops.h" #include "ivtv-vbi.h" -#include "ivtv-audio.h" -#include "ivtv-video.h" +#include "ivtv-routing.h" #include "ivtv-streams.h" #include "ivtv-yuv.h" #include "ivtv-ioctl.h" @@ -675,7 +674,7 @@ static int ivtv_debug_ioctls(struct file *filp, unsigned int cmd, void *arg) case VIDIOC_INT_S_AUDIO_ROUTING: { struct v4l2_routing *route = arg; - ivtv_audio_set_route(itv, route); + ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, route); break; } diff --git a/drivers/media/video/ivtv/ivtv-irq.h b/drivers/media/video/ivtv/ivtv-irq.h index e180bd34898..f879a5822e7 100644 --- a/drivers/media/video/ivtv/ivtv-irq.h +++ b/drivers/media/video/ivtv/ivtv-irq.h @@ -22,6 +22,28 @@ #ifndef IVTV_IRQ_H #define IVTV_IRQ_H +#define IVTV_IRQ_ENC_START_CAP (0x1 << 31) +#define IVTV_IRQ_ENC_EOS (0x1 << 30) +#define IVTV_IRQ_ENC_VBI_CAP (0x1 << 29) +#define IVTV_IRQ_ENC_VIM_RST (0x1 << 28) +#define IVTV_IRQ_ENC_DMA_COMPLETE (0x1 << 27) +#define IVTV_IRQ_ENC_PIO_COMPLETE (0x1 << 25) +#define IVTV_IRQ_DEC_AUD_MODE_CHG (0x1 << 24) +#define IVTV_IRQ_DEC_DATA_REQ (0x1 << 22) +#define IVTV_IRQ_DEC_DMA_COMPLETE (0x1 << 20) +#define IVTV_IRQ_DEC_VBI_RE_INSERT (0x1 << 19) +#define IVTV_IRQ_DMA_ERR (0x1 << 18) +#define IVTV_IRQ_DMA_WRITE (0x1 << 17) +#define IVTV_IRQ_DMA_READ (0x1 << 16) +#define IVTV_IRQ_DEC_VSYNC (0x1 << 10) + +/* IRQ Masks */ +#define IVTV_IRQ_MASK_INIT (IVTV_IRQ_DMA_ERR|IVTV_IRQ_ENC_DMA_COMPLETE|\ + IVTV_IRQ_DMA_READ|IVTV_IRQ_ENC_PIO_COMPLETE) + +#define IVTV_IRQ_MASK_CAPTURE (IVTV_IRQ_ENC_START_CAP | IVTV_IRQ_ENC_EOS) +#define IVTV_IRQ_MASK_DECODE (IVTV_IRQ_DEC_DATA_REQ|IVTV_IRQ_DEC_AUD_MODE_CHG) + irqreturn_t ivtv_irq_handler(int irq, void *dev_id); void ivtv_irq_work_handler(struct work_struct *work); diff --git a/drivers/media/video/ivtv/ivtv-mailbox.h b/drivers/media/video/ivtv/ivtv-mailbox.h index 90c871b8e23..71a54eef8fc 100644 --- a/drivers/media/video/ivtv/ivtv-mailbox.h +++ b/drivers/media/video/ivtv/ivtv-mailbox.h @@ -21,6 +21,9 @@ #ifndef IVTV_MAILBOX_H #define IVTV_MAILBOX_H +#define IVTV_MBOX_DMA_END 8 +#define IVTV_MBOX_DMA 9 + void ivtv_api_get_data(struct ivtv_mailbox_data *mbox, int mb, u32 data[]); int ivtv_api(struct ivtv *itv, int cmd, int args, u32 data[]); int ivtv_vapi_result(struct ivtv *itv, u32 data[CX2341X_MBOX_MAX_DATA], int cmd, int args, ...); diff --git a/drivers/media/video/ivtv/ivtv-routing.c b/drivers/media/video/ivtv/ivtv-routing.c new file mode 100644 index 00000000000..398bd33033e --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-routing.c @@ -0,0 +1,116 @@ +/* + Audio/video-routing-related ivtv functions. + Copyright (C) 2003-2004 Kevin Thayer + Copyright (C) 2005-2007 Hans Verkuil + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ivtv-driver.h" +#include "ivtv-i2c.h" +#include "ivtv-cards.h" +#include "ivtv-gpio.h" +#include "ivtv-routing.h" + +#include +#include +#include + +/* Selects the audio input and output according to the current + settings. */ +void ivtv_audio_set_io(struct ivtv *itv) +{ + struct v4l2_routing route; + u32 audio_input; + int mux_input; + + /* Determine which input to use */ + if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) { + audio_input = itv->card->radio_input.audio_input; + mux_input = itv->card->radio_input.muxer_input; + } else { + audio_input = itv->card->audio_inputs[itv->audio_input].audio_input; + mux_input = itv->card->audio_inputs[itv->audio_input].muxer_input; + } + + /* handle muxer chips */ + route.input = mux_input; + route.output = 0; + ivtv_i2c_hw(itv, itv->card->hw_muxer, VIDIOC_INT_S_AUDIO_ROUTING, &route); + + route.input = audio_input; + if (itv->card->hw_audio & IVTV_HW_MSP34XX) { + route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1); + } + ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, &route); +} + +/* Selects the video input and output according to the current + settings. */ +void ivtv_video_set_io(struct ivtv *itv) +{ + struct v4l2_routing route; + int inp = itv->active_input; + u32 type; + + route.input = itv->card->video_inputs[inp].video_input; + route.output = 0; + itv->video_dec_func(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route); + + type = itv->card->video_inputs[inp].video_type; + + if (type == IVTV_CARD_INPUT_VID_TUNER) { + route.input = 0; /* Tuner */ + } else if (type < IVTV_CARD_INPUT_COMPOSITE1) { + route.input = 2; /* S-Video */ + } else { + route.input = 1; /* Composite */ + } + + if (itv->card->hw_video & IVTV_HW_GPIO) + ivtv_gpio(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route); + + if (itv->card->hw_video & IVTV_HW_UPD64031A) { + if (type == IVTV_CARD_INPUT_VID_TUNER || + type >= IVTV_CARD_INPUT_COMPOSITE1) { + /* Composite: GR on, connect to 3DYCS */ + route.input = UPD64031A_GR_ON | UPD64031A_3DYCS_COMPOSITE; + } else { + /* S-Video: GR bypassed, turn it off */ + route.input = UPD64031A_GR_OFF | UPD64031A_3DYCS_DISABLE; + } + route.input |= itv->card->gr_config; + + ivtv_upd64031a(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route); + } + + if (itv->card->hw_video & IVTV_HW_UPD6408X) { + route.input = UPD64083_YCS_MODE; + if (type > IVTV_CARD_INPUT_VID_TUNER && + type < IVTV_CARD_INPUT_COMPOSITE1) { + /* S-Video uses YCNR mode and internal Y-ADC, the upd64031a + is not used. */ + route.input |= UPD64083_YCNR_MODE; + } + else if (itv->card->hw_video & IVTV_HW_UPD64031A) { + /* Use upd64031a output for tuner and composite(CX23416GYC only) inputs */ + if ((type == IVTV_CARD_INPUT_VID_TUNER)|| + (itv->card->type == IVTV_CARD_CX23416GYC)) { + route.input |= UPD64083_EXT_Y_ADC; + } + } + ivtv_upd64083(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route); + } +} diff --git a/drivers/media/video/ivtv/ivtv-routing.h b/drivers/media/video/ivtv/ivtv-routing.h new file mode 100644 index 00000000000..c72a9731ca0 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-routing.h @@ -0,0 +1,27 @@ +/* + Audio/video-routing-related ivtv functions. + Copyright (C) 2003-2004 Kevin Thayer + Copyright (C) 2005-2007 Hans Verkuil + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef IVTV_ROUTING_H +#define IVTV_ROUTING_H + +void ivtv_audio_set_io(struct ivtv *itv); +void ivtv_video_set_io(struct ivtv *itv); + +#endif diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index fae151a31e8..3939a804f04 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -38,6 +38,7 @@ #include "ivtv-queue.h" #include "ivtv-mailbox.h" #include "ivtv-ioctl.h" +#include "ivtv-irq.h" #include "ivtv-yuv.h" #include "ivtv-cards.h" #include "ivtv-streams.h" @@ -62,6 +63,13 @@ static struct file_operations ivtv_v4l2_dec_fops = { .poll = ivtv_v4l2_dec_poll, }; +#define IVTV_V4L2_DEC_MPG_OFFSET 16 /* offset from 0 to register decoder mpg v4l2 minors on */ +#define IVTV_V4L2_ENC_PCM_OFFSET 24 /* offset from 0 to register pcm v4l2 minors on */ +#define IVTV_V4L2_ENC_YUV_OFFSET 32 /* offset from 0 to register yuv v4l2 minors on */ +#define IVTV_V4L2_DEC_YUV_OFFSET 48 /* offset from 0 to register decoder yuv v4l2 minors on */ +#define IVTV_V4L2_DEC_VBI_OFFSET 8 /* offset from 0 to register decoder vbi input v4l2 minors on */ +#define IVTV_V4L2_DEC_VOUT_OFFSET 16 /* offset from 0 to register vbi output v4l2 minors on */ + static struct { const char *name; int vfl_type; @@ -658,10 +666,10 @@ int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset) clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); /* Zero out decoder counters */ - writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_FIELD_DISPLAYED].data[0]); - writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_FIELD_DISPLAYED].data[1]); - writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_FIELD_DISPLAYED].data[2]); - writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_FIELD_DISPLAYED].data[3]); + writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA_END].data[0]); + writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA_END].data[1]); + writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA_END].data[2]); + writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA_END].data[3]); writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[0]); writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[1]); writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[2]); diff --git a/drivers/media/video/ivtv/ivtv-vbi.c b/drivers/media/video/ivtv/ivtv-vbi.c index a58c833c2b0..5d8a40f3d2b 100644 --- a/drivers/media/video/ivtv/ivtv-vbi.c +++ b/drivers/media/video/ivtv/ivtv-vbi.c @@ -18,10 +18,70 @@ */ #include "ivtv-driver.h" -#include "ivtv-video.h" -#include "ivtv-vbi.h" +#include "ivtv-i2c.h" #include "ivtv-ioctl.h" #include "ivtv-queue.h" +#include "ivtv-vbi.h" + +static void ivtv_set_vps(struct ivtv *itv, int enabled, u8 vps1, u8 vps2, u8 vps3, + u8 vps4, u8 vps5) +{ + struct v4l2_sliced_vbi_data data; + + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) + return; + data.id = V4L2_SLICED_VPS; + data.field = 0; + data.line = enabled ? 16 : 0; + data.data[4] = vps1; + data.data[10] = vps2; + data.data[11] = vps3; + data.data[12] = vps4; + data.data[13] = vps5; + ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data); +} + +static void ivtv_set_cc(struct ivtv *itv, int mode, u8 cc1, u8 cc2, u8 cc3, u8 cc4) +{ + struct v4l2_sliced_vbi_data data; + + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) + return; + data.id = V4L2_SLICED_CAPTION_525; + data.field = 0; + data.line = (mode & 1) ? 21 : 0; + data.data[0] = cc1; + data.data[1] = cc2; + ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data); + data.field = 1; + data.line = (mode & 2) ? 21 : 0; + data.data[0] = cc3; + data.data[1] = cc4; + ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data); +} + +static void ivtv_set_wss(struct ivtv *itv, int enabled, int mode) +{ + struct v4l2_sliced_vbi_data data; + + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) + return; + /* When using a 50 Hz system, always turn on the + wide screen signal with 4x3 ratio as the default. + Turning this signal on and off can confuse certain + TVs. As far as I can tell there is no reason not to + transmit this signal. */ + if ((itv->std & V4L2_STD_625_50) && !enabled) { + enabled = 1; + mode = 0x08; /* 4x3 full format */ + } + data.id = V4L2_SLICED_WSS_625; + data.field = 0; + data.line = enabled ? 23 : 0; + data.data[0] = mode & 0xff; + data.data[1] = (mode >> 8) & 0xff; + ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data); +} static int odd_parity(u8 c) { diff --git a/drivers/media/video/ivtv/ivtv-video.c b/drivers/media/video/ivtv/ivtv-video.c deleted file mode 100644 index 5858b197d51..00000000000 --- a/drivers/media/video/ivtv/ivtv-video.c +++ /dev/null @@ -1,142 +0,0 @@ -/* - saa7127 interface functions - Copyright (C) 2004-2007 Hans Verkuil - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "ivtv-driver.h" -#include "ivtv-video.h" -#include "ivtv-i2c.h" -#include "ivtv-gpio.h" -#include "ivtv-cards.h" -#include -#include - -void ivtv_set_vps(struct ivtv *itv, int enabled, u8 vps1, u8 vps2, u8 vps3, - u8 vps4, u8 vps5) -{ - struct v4l2_sliced_vbi_data data; - - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return; - data.id = V4L2_SLICED_VPS; - data.field = 0; - data.line = enabled ? 16 : 0; - data.data[4] = vps1; - data.data[10] = vps2; - data.data[11] = vps3; - data.data[12] = vps4; - data.data[13] = vps5; - ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data); -} - -void ivtv_set_cc(struct ivtv *itv, int mode, u8 cc1, u8 cc2, u8 cc3, u8 cc4) -{ - struct v4l2_sliced_vbi_data data; - - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return; - data.id = V4L2_SLICED_CAPTION_525; - data.field = 0; - data.line = (mode & 1) ? 21 : 0; - data.data[0] = cc1; - data.data[1] = cc2; - ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data); - data.field = 1; - data.line = (mode & 2) ? 21 : 0; - data.data[0] = cc3; - data.data[1] = cc4; - ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data); -} - -void ivtv_set_wss(struct ivtv *itv, int enabled, int mode) -{ - struct v4l2_sliced_vbi_data data; - - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) - return; - /* When using a 50 Hz system, always turn on the - wide screen signal with 4x3 ratio as the default. - Turning this signal on and off can confuse certain - TVs. As far as I can tell there is no reason not to - transmit this signal. */ - if ((itv->std & V4L2_STD_625_50) && !enabled) { - enabled = 1; - mode = 0x08; /* 4x3 full format */ - } - data.id = V4L2_SLICED_WSS_625; - data.field = 0; - data.line = enabled ? 23 : 0; - data.data[0] = mode & 0xff; - data.data[1] = (mode >> 8) & 0xff; - ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data); -} - -void ivtv_video_set_io(struct ivtv *itv) -{ - struct v4l2_routing route; - int inp = itv->active_input; - u32 type; - - route.input = itv->card->video_inputs[inp].video_input; - route.output = 0; - itv->video_dec_func(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route); - - type = itv->card->video_inputs[inp].video_type; - - if (type == IVTV_CARD_INPUT_VID_TUNER) { - route.input = 0; /* Tuner */ - } else if (type < IVTV_CARD_INPUT_COMPOSITE1) { - route.input = 2; /* S-Video */ - } else { - route.input = 1; /* Composite */ - } - - if (itv->card->hw_video & IVTV_HW_GPIO) - ivtv_gpio(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route); - - if (itv->card->hw_video & IVTV_HW_UPD64031A) { - if (type == IVTV_CARD_INPUT_VID_TUNER || - type >= IVTV_CARD_INPUT_COMPOSITE1) { - /* Composite: GR on, connect to 3DYCS */ - route.input = UPD64031A_GR_ON | UPD64031A_3DYCS_COMPOSITE; - } else { - /* S-Video: GR bypassed, turn it off */ - route.input = UPD64031A_GR_OFF | UPD64031A_3DYCS_DISABLE; - } - route.input |= itv->card->gr_config; - - ivtv_upd64031a(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route); - } - - if (itv->card->hw_video & IVTV_HW_UPD6408X) { - route.input = UPD64083_YCS_MODE; - if (type > IVTV_CARD_INPUT_VID_TUNER && - type < IVTV_CARD_INPUT_COMPOSITE1) { - /* S-Video uses YCNR mode and internal Y-ADC, the upd64031a - is not used. */ - route.input |= UPD64083_YCNR_MODE; - } - else if (itv->card->hw_video & IVTV_HW_UPD64031A) { - /* Use upd64031a output for tuner and composite(CX23416GYC only) inputs */ - if ((type == IVTV_CARD_INPUT_VID_TUNER)|| - (itv->card->type == IVTV_CARD_CX23416GYC)) { - route.input |= UPD64083_EXT_Y_ADC; - } - } - ivtv_upd64083(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route); - } -} diff --git a/drivers/media/video/ivtv/ivtv-video.h b/drivers/media/video/ivtv/ivtv-video.h deleted file mode 100644 index 498e9b61c22..00000000000 --- a/drivers/media/video/ivtv/ivtv-video.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - saa7127 interface functions - Copyright (C) 2004-2007 Hans Verkuil - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef IVTV_VIDEO_H -#define IVTV_VIDEO_H - -void ivtv_set_wss(struct ivtv *itv, int enabled, int mode); -void ivtv_set_cc(struct ivtv *itv, int mode, u8 cc1, u8 cc2, u8 cc3, u8 cc4); -void ivtv_set_vps(struct ivtv *itv, int enabled, u8 vps1, u8 vps2, u8 vps3, - u8 vps4, u8 vps5); -void ivtv_video_set_io(struct ivtv *itv); - -#endif diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c index bb2cbb206c1..e2288f224ab 100644 --- a/drivers/media/video/ivtv/ivtv-yuv.c +++ b/drivers/media/video/ivtv/ivtv-yuv.c @@ -42,7 +42,7 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, int y_decode_height, uv_decode_height, y_size; int frame = atomic_read(&itv->yuv_info.next_fill_frame); - y_buffer_offset = IVTV_DEC_MEM_START + yuv_offset[frame]; + y_buffer_offset = IVTV_DECODER_OFFSET + yuv_offset[frame]; uv_buffer_offset = y_buffer_offset + IVTV_YUV_BUFFER_UV_OFFSET; y_decode_height = uv_decode_height = args->src.height + args->src.top; @@ -106,7 +106,7 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, if (itv->yuv_info.blanking_dmaptr) { dma->SGarray[dma->SG_length].size = cpu_to_le32(720*16); dma->SGarray[dma->SG_length].src = cpu_to_le32(itv->yuv_info.blanking_dmaptr); - dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DEC_MEM_START + yuv_offset[frame]); + dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DECODER_OFFSET + yuv_offset[frame]); dma->SG_length++; } } diff --git a/drivers/media/video/ivtv/ivtv-yuv.h b/drivers/media/video/ivtv/ivtv-yuv.h index 0824048ce3a..f7215eeca01 100644 --- a/drivers/media/video/ivtv/ivtv-yuv.h +++ b/drivers/media/video/ivtv/ivtv-yuv.h @@ -32,6 +32,9 @@ #define IVTV_YUV_HORIZONTAL_FILTER_OFFSET 0x025d8 #define IVTV_YUV_VERTICAL_FILTER_OFFSET 0x03358 +#define IVTV_YUV_UPDATE_HORIZONTAL 0x01 +#define IVTV_YUV_UPDATE_VERTICAL 0x02 + extern const u32 yuv_offset[4]; int ivtv_yuv_filter_check(struct ivtv *itv); -- cgit v1.2.3-70-g09d2 From fd8b281a2809d2bd9119df1fbd717ab2371297cd Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 23 Aug 2007 10:13:15 -0300 Subject: V4L/DVB (6093): ivtv: reorganized and cleanup ivtv struct Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.c | 15 +- drivers/media/video/ivtv/ivtv-driver.h | 243 ++++++++++++++++---------------- drivers/media/video/ivtv/ivtv-fb.c | 2 +- drivers/media/video/ivtv/ivtv-ioctl.c | 10 +- drivers/media/video/ivtv/ivtv-irq.c | 12 +- drivers/media/video/ivtv/ivtv-streams.c | 19 ++- 6 files changed, 152 insertions(+), 149 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 6a74e509c87..855697c1c96 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -667,7 +667,7 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv) cx2341x_fill_defaults(&itv->params); itv->params.port = CX2341X_PORT_MEMORY; itv->params.capabilities = CX2341X_CAP_HAS_SLICED_VBI; - init_waitqueue_head(&itv->cap_w); + init_waitqueue_head(&itv->eos_waitq); init_waitqueue_head(&itv->event_waitq); init_waitqueue_head(&itv->vsync_waitq); init_waitqueue_head(&itv->dma_waitq); @@ -713,14 +713,6 @@ static void __devinit ivtv_init_struct2(struct ivtv *itv) break; itv->nof_audio_inputs = i; - /* 0x00EF = saa7114(239) 0x00F0 = saa7115(240) 0x0106 = micro */ - if (itv->card->hw_all & (IVTV_HW_SAA7115 | IVTV_HW_SAA717X)) - itv->digitizer = 0xF1; - else if (itv->card->hw_all & IVTV_HW_SAA7114) - itv->digitizer = 0xEF; - else /* cx25840 */ - itv->digitizer = 0x140; - if (itv->card->hw_all & IVTV_HW_CX25840) { itv->vbi.sliced_size = 288; /* multiple of 16, real size = 284 */ } else { @@ -749,6 +741,7 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev, const struct pci_device_id *pci_id) { u16 cmd; + u8 card_rev; unsigned char pci_latency; IVTV_DEBUG_INFO("Enabling pci device\n"); @@ -795,7 +788,7 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev, } IVTV_DEBUG_INFO("Bus Mastering Enabled.\n"); - pci_read_config_byte(dev, PCI_CLASS_REVISION, &itv->card_rev); + pci_read_config_byte(dev, PCI_CLASS_REVISION, &card_rev); pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency); if (pci_latency < 64 && ivtv_pci_latency) { @@ -812,7 +805,7 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev, IVTV_DEBUG_INFO("%d (rev %d) at %02x:%02x.%x, " "irq: %d, latency: %d, memory: 0x%lx\n", - itv->dev->device, itv->card_rev, dev->bus->number, + itv->dev->device, card_rev, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), itv->dev->irq, pci_latency, (unsigned long)itv->base_addr); diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index b9dfdab6636..2c27515d873 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -550,133 +550,134 @@ struct ivtv_card; /* Struct to hold info about ivtv cards */ struct ivtv { - int num; /* board number, -1 during init! */ - char name[8]; /* board name for printk and interrupts (e.g. 'ivtv0') */ - struct pci_dev *dev; /* PCI device */ + /* General fixed card data */ + int num; /* board number, -1 during init! */ + char name[8]; /* board name for printk and interrupts (e.g. 'ivtv0') */ + struct pci_dev *dev; /* PCI device */ const struct ivtv_card *card; /* card information */ - const char *card_name; /* full name of the card */ - u8 has_cx23415; /* 1 if it is a cx23415 based card, 0 for cx23416 */ - u8 is_50hz; - u8 is_60hz; - u8 is_out_50hz; - u8 is_out_60hz; - u8 pvr150_workaround; /* 1 if the cx25840 needs to workaround a PVR150 bug */ - u8 nof_inputs; /* number of video inputs */ - u8 nof_audio_inputs; /* number of audio inputs */ - u32 v4l2_cap; /* V4L2 capabilities of card */ - u32 hw_flags; /* Hardware description of the board */ - int tunerid; /* Userspace tuner ID for experimental Xceive tuner support */ - - /* controlling Video decoder function */ + const char *card_name; /* full name of the card */ + u8 has_cx23415; /* 1 if it is a cx23415 based card, 0 for cx23416 */ + u8 pvr150_workaround; /* 1 if the cx25840 needs to workaround a PVR150 bug */ + u8 nof_inputs; /* number of video inputs */ + u8 nof_audio_inputs; /* number of audio inputs */ + u32 v4l2_cap; /* V4L2 capabilities of card */ + u32 hw_flags; /* hardware description of the board */ + int tunerid; /* userspace tuner ID for experimental Xceive tuner support */ + v4l2_std_id tuner_std; /* the norm of the card's tuner (fixed) */ + /* controlling video decoder function */ int (*video_dec_func)(struct ivtv *, unsigned int, void *); + u32 base_addr; /* PCI resource base address */ + volatile void __iomem *enc_mem; /* pointer to mapped encoder memory */ + volatile void __iomem *dec_mem; /* pointer to mapped decoder memory */ + volatile void __iomem *reg_mem; /* pointer to mapped registers */ + struct ivtv_options options; /* user options */ + + + /* High-level state info */ + unsigned long i_flags; /* global ivtv flags */ + u8 is_50hz; /* 1 if the current capture standard is 50 Hz */ + u8 is_60hz /* 1 if the current capture standard is 60 Hz */; + u8 is_out_50hz /* 1 if the current TV output standard is 50 Hz */; + u8 is_out_60hz /* 1 if the current TV output standard is 60 Hz */; + int output_mode; /* decoder output mode: NONE, MPG, YUV, UDMA YUV, passthrough */ + u32 audio_input; /* current audio input */ + u32 active_input; /* current video input */ + u32 active_output; /* current video output */ + v4l2_std_id std; /* current capture TV standard */ + v4l2_std_id std_out; /* current TV output standard */ + u8 audio_stereo_mode; /* decoder setting how to handle stereo MPEG audio */ + u8 audio_bilingual_mode; /* decoder setting how to handle bilingual MPEG audio */ + struct cx2341x_mpeg_params params; /* current encoder parameters */ + + + /* Locking */ + spinlock_t lock; /* lock access to this struct */ + /* mutex used to serialize open/close/start/stop/ioctl operations */ + struct mutex serialize_lock; + + + /* Streams */ + int stream_buf_size[IVTV_MAX_STREAMS]; /* stream buffer size */ + struct ivtv_stream streams[IVTV_MAX_STREAMS]; /* stream data */ + atomic_t capturing; /* count number of active capture streams */ + atomic_t decoding; /* count number of active decoding streams */ + + + /* Interrupts & DMA */ + u32 irqmask; /* active interrupts */ + u32 irq_rr_idx; /* round-robin stream index */ + struct workqueue_struct *irq_work_queues; /* workqueue for PIO/YUV/VBI actions */ + struct work_struct irq_work_queue; /* work entry */ + spinlock_t dma_reg_lock; /* lock access to DMA engine registers */ + int cur_dma_stream; /* index of current stream doing DMA (-1 if none) */ + int cur_pio_stream; /* index of current stream doing PIO (-1 if none) */ + u32 dma_data_req_offset; /* store offset in decoder memory of current DMA request */ + u32 dma_data_req_size; /* store size of current DMA request */ + int dma_retries; /* current DMA retry attempt */ + struct ivtv_user_dma udma; /* user based DMA for OSD */ + struct timer_list dma_timer; /* timer used to catch unfinished DMAs */ + u32 last_vsync_frame; /* last seen vsync field */ + wait_queue_head_t dma_waitq; /* wake up when the current DMA is finished */ + wait_queue_head_t eos_waitq; /* wake up when EOS arrives */ + wait_queue_head_t event_waitq; /* wake up when the next decoder event arrives */ + wait_queue_head_t vsync_waitq; /* wake up when the next decoder vsync arrives */ + + + /* Mailbox */ + struct ivtv_mailbox_data enc_mbox; /* encoder mailboxes */ + struct ivtv_mailbox_data dec_mbox; /* decoder mailboxes */ + struct ivtv_api_cache api_cache[256]; /* cached API commands */ + + + /* I2C */ + struct i2c_adapter i2c_adap; + struct i2c_algo_bit_data i2c_algo; + struct i2c_client i2c_client; + struct i2c_client *i2c_clients[I2C_CLIENTS_MAX];/* pointers to all I2C clients */ + int i2c_state; /* i2c bit state */ + struct mutex i2c_bus_lock; /* lock i2c bus */ + + + /* Program Index information */ + u32 pgm_info_offset; /* start of pgm info in encoder memory */ + u32 pgm_info_num; /* number of elements in the pgm cyclic buffer in encoder memory */ + u32 pgm_info_write_idx; /* last index written by the card that was transferred to pgm_info[] */ + u32 pgm_info_read_idx; /* last index in pgm_info read by the application */ + struct v4l2_enc_idx_entry pgm_info[IVTV_MAX_PGM_INDEX]; /* filled from the pgm cyclic buffer on the card */ + + + /* Miscellaneous */ + u32 open_id; /* incremented each time an open occurs, is >= 1 */ + struct v4l2_prio_state prio; /* priority state */ + int search_pack_header; /* 1 if ivtv_copy_buf_to_user() is scanning for a pack header (0xba) */ + int speed; /* current playback speed setting */ + u8 speed_mute_audio; /* 1 if audio should be muted when fast forward */ + u64 mpg_data_received; /* number of bytes received from the MPEG stream */ + u64 vbi_data_inserted; /* number of VBI bytes inserted into the MPEG stream */ + u32 last_dec_timing[3]; /* cache last retrieved pts/scr/frame values */ + unsigned long dualwatch_jiffies;/* jiffies value of the previous dualwatch check */ + u16 dualwatch_stereo_mode; /* current detected dualwatch stereo mode */ + + + /* VBI state info */ + struct vbi_info vbi; /* VBI-specific data */ + + + /* YUV playback */ + struct yuv_playback_info yuv_info; /* YUV playback data */ - struct ivtv_options options; /* User options */ - int stream_buf_size[IVTV_MAX_STREAMS]; /* Stream buffer size */ - struct ivtv_stream streams[IVTV_MAX_STREAMS]; /* Stream data */ - int speed; - u8 speed_mute_audio; - unsigned long i_flags; /* global ivtv flags */ - atomic_t capturing; /* count number of active capture streams */ - atomic_t decoding; /* count number of active decoding streams */ - u32 irq_rr_idx; /* Round-robin stream index */ - int cur_dma_stream; /* index of stream doing DMA */ - int cur_pio_stream; /* index of stream doing PIO */ - u32 dma_data_req_offset; - u32 dma_data_req_size; - int dma_retries; - int output_mode; /* NONE, MPG, YUV, UDMA YUV, passthrough */ - spinlock_t lock; /* lock access to this struct */ - int search_pack_header; - - spinlock_t dma_reg_lock; /* lock access to DMA engine registers */ - struct mutex serialize_lock; /* lock used to serialize starting streams */ - - /* User based DMA for OSD */ - struct ivtv_user_dma udma; - - int open_id; /* incremented each time an open occurs, used as unique ID. - starts at 1, so 0 can be used as uninitialized value - in the stream->id. */ - - u32 base_addr; - u32 irqmask; - - struct v4l2_prio_state prio; - struct workqueue_struct *irq_work_queues; - struct work_struct irq_work_queue; - struct timer_list dma_timer; /* Timer used to catch unfinished DMAs */ - - struct vbi_info vbi; - - struct ivtv_mailbox_data enc_mbox; - struct ivtv_mailbox_data dec_mbox; - struct ivtv_api_cache api_cache[256]; /* Cached API Commands */ - - u8 card_rev; - volatile void __iomem *enc_mem, *dec_mem, *reg_mem; - - u32 pgm_info_offset; - u32 pgm_info_num; - u32 pgm_info_write_idx; - u32 pgm_info_read_idx; - struct v4l2_enc_idx_entry pgm_info[IVTV_MAX_PGM_INDEX]; - - u64 mpg_data_received; - u64 vbi_data_inserted; - - wait_queue_head_t cap_w; - /* when the next decoder event arrives this queue is woken up */ - wait_queue_head_t event_waitq; - /* when the next decoder vsync arrives this queue is woken up */ - wait_queue_head_t vsync_waitq; - /* when the current DMA is finished this queue is woken up */ - wait_queue_head_t dma_waitq; /* OSD support */ unsigned long osd_video_pbase; - int osd_global_alpha_state; /* 0=off : 1=on */ - int osd_local_alpha_state; /* 0=off : 1=on */ - int osd_color_key_state; /* 0=off : 1=on */ - u8 osd_global_alpha; /* Current global alpha */ - u32 osd_color_key; /* Current color key */ - u32 osd_pixelformat; /* Current pixel format */ - struct v4l2_rect osd_rect; /* Current OSD position and size */ - struct v4l2_rect main_rect; /* Current Main window position and size */ - - u32 last_dec_timing[3]; /* Store last retrieved pts/scr/frame values */ - - /* i2c */ - struct i2c_adapter i2c_adap; - struct i2c_algo_bit_data i2c_algo; - struct i2c_client i2c_client; - struct mutex i2c_bus_lock; - int i2c_state; - struct i2c_client *i2c_clients[I2C_CLIENTS_MAX]; - - /* v4l2 and User settings */ - - /* codec settings */ - struct cx2341x_mpeg_params params; - u32 audio_input; - u32 active_input; - u32 active_output; - v4l2_std_id std; - v4l2_std_id std_out; - v4l2_std_id tuner_std; /* The norm of the tuner (fixed) */ - u8 audio_stereo_mode; - u8 audio_bilingual_mode; - - /* dualwatch */ - unsigned long dualwatch_jiffies; - u16 dualwatch_stereo_mode; - - /* Digitizer type */ - int digitizer; /* 0x00EF = saa7114 0x00FO = saa7115 0x0106 = mic */ - - u32 lastVsyncFrame; - - struct yuv_playback_info yuv_info; - struct osd_info *osd_info; + int osd_global_alpha_state; /* 1 = global alpha is on */ + int osd_local_alpha_state; /* 1 = local alpha is on */ + int osd_chroma_key_state; /* 1 = chroma-keying is on */ + u8 osd_global_alpha; /* current global alpha */ + u32 osd_chroma_key; /* current chroma key */ + u32 osd_pixelformat; /* current pixel format */ + struct v4l2_rect osd_rect; /* current OSD position and size */ + struct v4l2_rect main_rect; /* current Main window position and size */ + struct osd_info *osd_info; /* ivtv-fb private OSD info */ }; /* Globals */ diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c index 2c521d1bb05..f5ed2cf1cd8 100644 --- a/drivers/media/video/ivtv/ivtv-fb.c +++ b/drivers/media/video/ivtv/ivtv-fb.c @@ -405,7 +405,7 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar if (itv->is_50hz && trace > 312) trace -= 312; else if (itv->is_60hz && trace > 262) trace -= 262; if (trace == 1) vblank.flags |= FB_VBLANK_VSYNCING; - vblank.count = itv->lastVsyncFrame; + vblank.count = itv->last_vsync_frame; vblank.vcount = trace; vblank.hcount = 0; if (copy_to_user((void __user *)arg, &vblank, sizeof(vblank))) diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index f4f56a6e1f8..01215a1c4b8 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -163,7 +163,7 @@ void ivtv_set_osd_alpha(struct ivtv *itv) { ivtv_vapi(itv, CX2341X_OSD_SET_GLOBAL_ALPHA, 3, itv->osd_global_alpha_state, itv->osd_global_alpha, !itv->osd_local_alpha_state); - ivtv_vapi(itv, CX2341X_OSD_SET_CHROMA_KEY, 2, itv->osd_color_key_state, itv->osd_color_key); + ivtv_vapi(itv, CX2341X_OSD_SET_CHROMA_KEY, 2, itv->osd_chroma_key_state, itv->osd_chroma_key); } int ivtv_set_speed(struct ivtv *itv, int speed) @@ -426,7 +426,7 @@ static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fm case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) return -EINVAL; - fmt->fmt.win.chromakey = itv->osd_color_key; + fmt->fmt.win.chromakey = itv->osd_chroma_key; fmt->fmt.win.global_alpha = itv->osd_global_alpha; break; @@ -546,7 +546,7 @@ static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype, if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) return -EINVAL; if (set_fmt) { - itv->osd_color_key = fmt->fmt.win.chromakey; + itv->osd_chroma_key = fmt->fmt.win.chromakey; itv->osd_global_alpha = fmt->fmt.win.global_alpha; ivtv_set_osd_alpha(itv); } @@ -1197,7 +1197,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void fb->flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA; if (itv->osd_local_alpha_state) fb->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA; - if (itv->osd_color_key_state) + if (itv->osd_chroma_key_state) fb->flags |= V4L2_FBUF_FLAG_CHROMAKEY; break; } @@ -1209,7 +1209,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void return -EINVAL; itv->osd_global_alpha_state = (fb->flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) != 0; itv->osd_local_alpha_state = (fb->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA) != 0; - itv->osd_color_key_state = (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0; + itv->osd_chroma_key_state = (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0; ivtv_set_osd_alpha(itv); break; } diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c index b6a94a1ad19..4ec3df58e24 100644 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ b/drivers/media/video/ivtv/ivtv-irq.c @@ -750,8 +750,8 @@ static void ivtv_irq_vsync(struct ivtv *itv) if (0) IVTV_DEBUG_IRQ("DEC VSYNC\n"); if (((frame ^ itv->yuv_info.sync_field[last_dma_frame]) == 0 && - ((itv->lastVsyncFrame & 1) ^ itv->yuv_info.sync_field[last_dma_frame])) || - (frame != (itv->lastVsyncFrame & 1) && !itv->yuv_info.frame_interlaced)) { + ((itv->last_vsync_frame & 1) ^ itv->yuv_info.sync_field[last_dma_frame])) || + (frame != (itv->last_vsync_frame & 1) && !itv->yuv_info.frame_interlaced)) { int next_dma_frame = last_dma_frame; if (!(itv->yuv_info.frame_interlaced && itv->yuv_info.field_delay[next_dma_frame] && itv->yuv_info.fields_lapsed < 1)) { @@ -766,10 +766,10 @@ static void ivtv_irq_vsync(struct ivtv *itv) } } } - if (frame != (itv->lastVsyncFrame & 1)) { + if (frame != (itv->last_vsync_frame & 1)) { struct ivtv_stream *s = ivtv_get_output_stream(itv); - itv->lastVsyncFrame += 1; + itv->last_vsync_frame += 1; if (frame == 0) { clear_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags); clear_bit(IVTV_F_I_EV_VSYNC_FIELD, &itv->i_flags); @@ -834,7 +834,7 @@ irqreturn_t ivtv_irq_handler(int irq, void *dev_id) */ if (~itv->irqmask & IVTV_IRQ_DEC_VSYNC) { /* vsync is enabled, see if we're in a new field */ - if ((itv->lastVsyncFrame & 1) != (read_reg(0x28c0) & 1)) { + if ((itv->last_vsync_frame & 1) != (read_reg(0x28c0) & 1)) { /* New field, looks like we missed it */ IVTV_DEBUG_YUV("VSync interrupt missed %d\n",read_reg(0x28c0)>>16); vsync_force = 1; @@ -888,7 +888,7 @@ irqreturn_t ivtv_irq_handler(int irq, void *dev_id) if (combo & IVTV_IRQ_ENC_EOS) { IVTV_DEBUG_IRQ("ENC EOS\n"); set_bit(IVTV_F_I_EOS, &itv->i_flags); - wake_up(&itv->cap_w); + wake_up(&itv->eos_waitq); } if (combo & IVTV_IRQ_DEC_DATA_REQ) { diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index 3939a804f04..e05af62a8cd 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -404,8 +404,8 @@ static void ivtv_vbi_setup(struct ivtv *itv) if (!itv->vbi.fpi) itv->vbi.fpi = 1; - IVTV_DEBUG_INFO("Setup VBI start 0x%08x frames %d fpi %d lines 0x%08x\n", - itv->vbi.enc_start, data[1], itv->vbi.fpi, itv->digitizer); + IVTV_DEBUG_INFO("Setup VBI start 0x%08x frames %d fpi %d\n", + itv->vbi.enc_start, data[1], itv->vbi.fpi); /* select VBI lines. Note that the sliced argument seems to have no effect. */ @@ -494,6 +494,8 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); if (atomic_read(&itv->capturing) == 0) { + int digitizer; + /* Always use frame based mode. Experiments have demonstrated that byte stream based mode results in dropped frames and corruption. Not often, but occasionally. Many thanks go to Leonard Orb who spent a lot of @@ -519,7 +521,14 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) ivtv_vapi(itv, CX2341X_ENC_SET_PLACEHOLDER, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - ivtv_vapi(itv, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, itv->digitizer, itv->digitizer); + if (itv->card->hw_all & (IVTV_HW_SAA7115 | IVTV_HW_SAA717X)) + digitizer = 0xF1; + else if (itv->card->hw_all & IVTV_HW_SAA7114) + digitizer = 0xEF; + else /* cx25840 */ + digitizer = 0x140; + + ivtv_vapi(itv, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, digitizer, digitizer); /* Setup VBI */ if (itv->v4l2_cap & V4L2_CAP_VBI_CAPTURE) { @@ -761,7 +770,7 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) unsigned long duration; then = jiffies; - add_wait_queue(&itv->cap_w, &wait); + add_wait_queue(&itv->eos_waitq, &wait); set_current_state(TASK_INTERRUPTIBLE); @@ -787,7 +796,7 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) IVTV_DEBUG_INFO("%s: EOS took %lu ms to occur.\n", s->name, duration); } set_current_state(TASK_RUNNING); - remove_wait_queue(&itv->cap_w, &wait); + remove_wait_queue(&itv->eos_waitq, &wait); } then = jiffies; -- cgit v1.2.3-70-g09d2 From a158f3559334c6314c7876390caffe88c9fdb64d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 23 Aug 2007 11:31:57 -0300 Subject: V4L/DVB (6094): ivtv: more ivtv-driver.h cleanups Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.h | 66 +++++++++++++++++----------------- drivers/media/video/ivtv/ivtv-fb.c | 2 +- drivers/media/video/ivtv/ivtv-irq.c | 10 +++--- 3 files changed, 38 insertions(+), 40 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 2c27515d873..332d16415eb 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -180,11 +180,11 @@ extern int ivtv_debug; #define IVTV_MAX_PGM_INDEX (400) struct ivtv_options { - int kilobytes[IVTV_MAX_STREAMS]; /* Size in kilobytes of each stream */ - int cardtype; /* force card type on load */ - int tuner; /* set tuner on load */ - int radio; /* enable/disable radio */ - int newi2c; /* New I2C algorithm */ + int kilobytes[IVTV_MAX_STREAMS]; /* size in kilobytes of each stream */ + int cardtype; /* force card type on load */ + int tuner; /* set tuner on load */ + int radio; /* enable/disable radio */ + int newi2c; /* new I2C algorithm */ }; /* ivtv-specific mailbox template */ @@ -231,10 +231,10 @@ struct ivtv_mailbox_data { #define IVTV_F_I_DMA 0 /* DMA in progress */ #define IVTV_F_I_UDMA 1 /* UDMA in progress */ #define IVTV_F_I_UDMA_PENDING 2 /* UDMA pending */ -#define IVTV_F_I_SPEED_CHANGE 3 /* A speed change is in progress */ -#define IVTV_F_I_EOS 4 /* End of encoder stream reached */ -#define IVTV_F_I_RADIO_USER 5 /* The radio tuner is selected */ -#define IVTV_F_I_DIG_RST 6 /* Reset digitizer */ +#define IVTV_F_I_SPEED_CHANGE 3 /* a speed change is in progress */ +#define IVTV_F_I_EOS 4 /* end of encoder stream reached */ +#define IVTV_F_I_RADIO_USER 5 /* the radio tuner is selected */ +#define IVTV_F_I_DIG_RST 6 /* reset digitizer */ #define IVTV_F_I_DEC_YUV 7 /* YUV instead of MPG is being decoded */ #define IVTV_F_I_UPDATE_CC 9 /* CC should be updated */ #define IVTV_F_I_UPDATE_WSS 10 /* WSS should be updated */ @@ -242,7 +242,7 @@ struct ivtv_mailbox_data { #define IVTV_F_I_DECODING_YUV 12 /* this stream is YUV frame decoding */ #define IVTV_F_I_ENC_PAUSED 13 /* the encoder is paused */ #define IVTV_F_I_VALID_DEC_TIMINGS 14 /* last_dec_timing is valid */ -#define IVTV_F_I_HAVE_WORK 15 /* Used in the interrupt handler: there is work to be done */ +#define IVTV_F_I_HAVE_WORK 15 /* used in the interrupt handler: there is work to be done */ #define IVTV_F_I_WORK_HANDLER_VBI 16 /* there is work to be done for VBI */ #define IVTV_F_I_WORK_HANDLER_YUV 17 /* there is work to be done for YUV */ #define IVTV_F_I_WORK_HANDLER_PIO 18 /* there is work to be done for PIO */ @@ -295,19 +295,18 @@ struct ivtv_buffer { unsigned short b_flags; unsigned short dma_xfer_cnt; char *buf; - u32 bytesused; u32 readpos; }; struct ivtv_queue { - struct list_head list; - u32 buffers; - u32 length; - u32 bytesused; + struct list_head list; /* the list of buffers in this queue */ + u32 buffers; /* number of buffers in this queue */ + u32 length; /* total number of bytes of available buffer space */ + u32 bytesused; /* total number of bytes used in this queue */ }; -struct ivtv; /* forward reference */ +struct ivtv; /* forward reference */ struct ivtv_stream { /* These first four fields are always set, even if the stream @@ -318,11 +317,9 @@ struct ivtv_stream { int type; /* stream type */ u32 id; - spinlock_t qlock; /* locks access to the queues */ - unsigned long s_flags; /* status flags, see above */ - int dma; /* can be PCI_DMA_TODEVICE, - PCI_DMA_FROMDEVICE or - PCI_DMA_NONE */ + spinlock_t qlock; /* locks access to the queues */ + unsigned long s_flags; /* status flags, see above */ + int dma; /* can be PCI_DMA_TODEVICE, PCI_DMA_FROMDEVICE or PCI_DMA_NONE */ u32 pending_offset; u32 pending_backup; u64 pending_pts; @@ -365,10 +362,10 @@ struct ivtv_stream { }; struct ivtv_open_id { - u32 open_id; - int type; - int yuv_frames; - enum v4l2_priority prio; + u32 open_id; /* unique ID for this file descriptor */ + int type; /* stream type */ + int yuv_frames; /* 1: started OUT_UDMA_YUV output mode */ + enum v4l2_priority prio; /* priority */ struct ivtv *itv; }; @@ -493,6 +490,14 @@ struct yuv_playback_info /* VBI data */ struct vbi_info { + /* VBI general fixed card data */ + u32 raw_decoder_line_size; /* raw VBI line size from digitizer */ + u8 raw_decoder_sav_odd_field; /* raw VBI Start Active Video digitizer code of odd field */ + u8 raw_decoder_sav_even_field; /* raw VBI Start Active Video digitizer code of even field */ + u32 sliced_decoder_line_size; /* sliced VBI line size from digitizer */ + u8 sliced_decoder_sav_odd_field; /* sliced VBI Start Active Video digitizer code of odd field */ + u8 sliced_decoder_sav_even_field; /* sliced VBI Start Active Video digitizer code of even field */ + u32 dec_start; u32 enc_start, enc_size; int fpi; @@ -506,12 +511,6 @@ struct vbi_info { int wss; u8 wss_found; u8 wss_no_update; - u32 raw_decoder_line_size; - u8 raw_decoder_sav_odd_field; - u8 raw_decoder_sav_even_field; - u32 sliced_decoder_line_size; - u8 sliced_decoder_sav_odd_field; - u8 sliced_decoder_sav_even_field; struct v4l2_format in; /* convenience pointer to sliced struct in vbi_in union */ struct v4l2_sliced_vbi_format *sliced_in; @@ -592,8 +591,7 @@ struct ivtv { /* Locking */ spinlock_t lock; /* lock access to this struct */ - /* mutex used to serialize open/close/start/stop/ioctl operations */ - struct mutex serialize_lock; + struct mutex serialize_lock; /* mutex used to serialize open/close/start/stop/ioctl operations */ /* Streams */ @@ -616,7 +614,7 @@ struct ivtv { int dma_retries; /* current DMA retry attempt */ struct ivtv_user_dma udma; /* user based DMA for OSD */ struct timer_list dma_timer; /* timer used to catch unfinished DMAs */ - u32 last_vsync_frame; /* last seen vsync field */ + u32 last_vsync_field; /* last seen vsync field */ wait_queue_head_t dma_waitq; /* wake up when the current DMA is finished */ wait_queue_head_t eos_waitq; /* wake up when EOS arrives */ wait_queue_head_t event_waitq; /* wake up when the next decoder event arrives */ diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c index f5ed2cf1cd8..e80564aed63 100644 --- a/drivers/media/video/ivtv/ivtv-fb.c +++ b/drivers/media/video/ivtv/ivtv-fb.c @@ -405,7 +405,7 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar if (itv->is_50hz && trace > 312) trace -= 312; else if (itv->is_60hz && trace > 262) trace -= 262; if (trace == 1) vblank.flags |= FB_VBLANK_VSYNCING; - vblank.count = itv->last_vsync_frame; + vblank.count = itv->last_vsync_field; vblank.vcount = trace; vblank.hcount = 0; if (copy_to_user((void __user *)arg, &vblank, sizeof(vblank))) diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c index 4ec3df58e24..66d0da22389 100644 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ b/drivers/media/video/ivtv/ivtv-irq.c @@ -750,8 +750,8 @@ static void ivtv_irq_vsync(struct ivtv *itv) if (0) IVTV_DEBUG_IRQ("DEC VSYNC\n"); if (((frame ^ itv->yuv_info.sync_field[last_dma_frame]) == 0 && - ((itv->last_vsync_frame & 1) ^ itv->yuv_info.sync_field[last_dma_frame])) || - (frame != (itv->last_vsync_frame & 1) && !itv->yuv_info.frame_interlaced)) { + ((itv->last_vsync_field & 1) ^ itv->yuv_info.sync_field[last_dma_frame])) || + (frame != (itv->last_vsync_field & 1) && !itv->yuv_info.frame_interlaced)) { int next_dma_frame = last_dma_frame; if (!(itv->yuv_info.frame_interlaced && itv->yuv_info.field_delay[next_dma_frame] && itv->yuv_info.fields_lapsed < 1)) { @@ -766,10 +766,10 @@ static void ivtv_irq_vsync(struct ivtv *itv) } } } - if (frame != (itv->last_vsync_frame & 1)) { + if (frame != (itv->last_vsync_field & 1)) { struct ivtv_stream *s = ivtv_get_output_stream(itv); - itv->last_vsync_frame += 1; + itv->last_vsync_field += 1; if (frame == 0) { clear_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags); clear_bit(IVTV_F_I_EV_VSYNC_FIELD, &itv->i_flags); @@ -834,7 +834,7 @@ irqreturn_t ivtv_irq_handler(int irq, void *dev_id) */ if (~itv->irqmask & IVTV_IRQ_DEC_VSYNC) { /* vsync is enabled, see if we're in a new field */ - if ((itv->last_vsync_frame & 1) != (read_reg(0x28c0) & 1)) { + if ((itv->last_vsync_field & 1) != (read_reg(0x28c0) & 1)) { /* New field, looks like we missed it */ IVTV_DEBUG_YUV("VSync interrupt missed %d\n",read_reg(0x28c0)>>16); vsync_force = 1; -- cgit v1.2.3-70-g09d2 From 559e196a56a5d518181efc1d2fefe0892f4689b4 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 23 Aug 2007 17:51:07 -0300 Subject: V4L/DVB (6096): ivtv: fix V4L2_ENC_CMD_STOP_AT_GOP_END support Support for V4L2_ENC_CMD_STOP_AT_GOP_END was broken. While the driver correctly waited for the card to capture until the GOP was complete, afterwards the driver buffers were just flushed instead of waiting for the application to read all the pending data. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-fileops.c | 37 +++++++++++++++++++++------------ drivers/media/video/ivtv/ivtv-streams.c | 8 ++----- 2 files changed, 26 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index 170bef61aa6..5b5d6666fa1 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -258,19 +258,19 @@ static struct ivtv_buffer *ivtv_get_buffer(struct ivtv_stream *s, int non_block, } return buf; } - /* return if file was opened with O_NONBLOCK */ - if (non_block) { - *err = -EAGAIN; - return NULL; - } /* return if end of stream */ if (s->type != IVTV_DEC_STREAM_TYPE_VBI && !test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { - clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); IVTV_DEBUG_INFO("EOS %s\n", s->name); return NULL; } + /* return if file was opened with O_NONBLOCK */ + if (non_block) { + *err = -EAGAIN; + return NULL; + } + /* wait for more data to arrive */ prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE); /* New buffers might have become available before we were added to the waitqueue */ @@ -378,10 +378,20 @@ static ssize_t ivtv_read(struct ivtv_stream *s, char __user *ubuf, size_t tot_co int rc; buf = ivtv_get_buffer(s, non_block, &rc); - if (buf == NULL && rc == -EAGAIN && tot_written) - break; - if (buf == NULL) + /* if there is no data available... */ + if (buf == NULL) { + /* if we got data, then return that regardless */ + if (tot_written) + break; + /* EOS condition */ + if (rc == 0) { + clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); + clear_bit(IVTV_F_S_APPL_IO, &s->s_flags); + ivtv_release_stream(s); + } + /* set errno */ return rc; + } rc = ivtv_copy_buf_to_user(s, buf, ubuf + tot_written, tot_count - tot_written); if (buf != &itv->vbi.sliced_mpeg_buf) { ivtv_enqueue(s, buf, (buf->readpos == buf->bytesused) ? &s->q_free : &s->q_io); @@ -738,10 +748,11 @@ void ivtv_stop_capture(struct ivtv_open_id *id, int gop_end) ivtv_stop_v4l2_encode_stream(s, gop_end); } } - clear_bit(IVTV_F_S_APPL_IO, &s->s_flags); - clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); - - ivtv_release_stream(s); + if (!gop_end) { + clear_bit(IVTV_F_S_APPL_IO, &s->s_flags); + clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); + ivtv_release_stream(s); + } } static void ivtv_stop_decoding(struct ivtv_open_id *id, int flags, u64 pts) diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index e05af62a8cd..a3296224f82 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -719,7 +719,6 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) struct ivtv *itv = s->itv; DECLARE_WAITQUEUE(wait, current); int cap_type; - unsigned long then; int stopmode; if (s->v4l2dev == NULL) @@ -762,14 +761,12 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) /* when: 0 = end of GOP 1 = NOW!, type: 0 = mpeg, subtype: 3 = video+audio */ ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, stopmode, cap_type, s->subtype); - then = jiffies; - if (!test_bit(IVTV_F_S_PASSTHROUGH, &s->s_flags)) { if (s->type == IVTV_ENC_STREAM_TYPE_MPG && gop_end) { /* only run these if we're shutting down the last cap */ unsigned long duration; + unsigned long then = jiffies; - then = jiffies; add_wait_queue(&itv->eos_waitq, &wait); set_current_state(TASK_INTERRUPTIBLE); @@ -797,10 +794,9 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) } set_current_state(TASK_RUNNING); remove_wait_queue(&itv->eos_waitq, &wait); + set_bit(IVTV_F_S_STREAMOFF, &s->s_flags); } - then = jiffies; - /* Handle any pending interrupts */ ivtv_msleep_timeout(100, 1); } -- cgit v1.2.3-70-g09d2 From 2d4d5f11ecf6df6974579c70461866932f0bd722 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 23 Aug 2007 21:15:24 -0300 Subject: V4L/DVB (6097): ivtv: set correct pixel format and alpha properties ivtv: set correct pixel format and alpha properties in VIDIOC_G_FBUF Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.h | 1 - drivers/media/video/ivtv/ivtv-ioctl.c | 66 ++++++++++++++++++++++++++-------- 2 files changed, 52 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 332d16415eb..41f753c125d 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -672,7 +672,6 @@ struct ivtv { int osd_chroma_key_state; /* 1 = chroma-keying is on */ u8 osd_global_alpha; /* current global alpha */ u32 osd_chroma_key; /* current chroma key */ - u32 osd_pixelformat; /* current pixel format */ struct v4l2_rect osd_rect; /* current OSD position and size */ struct v4l2_rect main_rect; /* current Main window position and size */ struct osd_info *osd_info; /* ivtv-fb private OSD info */ diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index 01215a1c4b8..6d24c6b9a45 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -699,6 +699,7 @@ static int ivtv_debug_ioctls(struct file *filp, unsigned int cmd, void *arg) int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void *arg) { struct ivtv_open_id *id = NULL; + u32 data[CX2341X_MBOX_MAX_DATA]; if (filp) id = (struct ivtv_open_id *)filp->private_data; @@ -1183,22 +1184,59 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void case VIDIOC_G_FBUF: { struct v4l2_framebuffer *fb = arg; + int pixfmt; + static u32 pixel_format[16] = { + V4L2_PIX_FMT_RGB332, /* Really RGB Indexed */ + V4L2_PIX_FMT_RGB565, + V4L2_PIX_FMT_RGB555, + V4L2_PIX_FMT_RGB444, + V4L2_PIX_FMT_RGB32, + 0, + 0, + 0, + /* Really YUV variants */ + V4L2_PIX_FMT_RGB332, /* Really YUV Indexed */ + V4L2_PIX_FMT_RGB565, + V4L2_PIX_FMT_RGB555, + V4L2_PIX_FMT_RGB444, + V4L2_PIX_FMT_RGB32, + 0, + 0, + 0, + }; memset(fb, 0, sizeof(*fb)); if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) return -EINVAL; fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY | V4L2_FBUF_CAP_CHROMAKEY | - V4L2_FBUF_CAP_LOCAL_ALPHA | V4L2_FBUF_CAP_GLOBAL_ALPHA; - fb->fmt.pixelformat = itv->osd_pixelformat; + V4L2_FBUF_CAP_GLOBAL_ALPHA; + ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0); + data[0] |= (read_reg(0x2a00) >> 7) & 0x40; + pixfmt = (data[0] >> 3) & 0xf; + fb->fmt.pixelformat = pixel_format[pixfmt]; fb->fmt.width = itv->osd_rect.width; fb->fmt.height = itv->osd_rect.height; fb->base = (void *)itv->osd_video_pbase; - if (itv->osd_global_alpha_state) - fb->flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA; - if (itv->osd_local_alpha_state) - fb->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA; if (itv->osd_chroma_key_state) fb->flags |= V4L2_FBUF_FLAG_CHROMAKEY; + if (itv->osd_global_alpha_state) + fb->flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA; + pixfmt &= 7; + /* no local alpha for RGB565 or unknown formats */ + if (pixfmt == 1 || pixfmt > 4) + break; + /* 16-bit formats have inverted local alpha */ + if (pixfmt == 2 || pixfmt == 3) + fb->capability |= V4L2_FBUF_CAP_LOCAL_INV_ALPHA; + else + fb->capability |= V4L2_FBUF_CAP_LOCAL_ALPHA; + if (itv->osd_local_alpha_state) { + /* 16-bit formats have inverted local alpha */ + if (pixfmt == 2 || pixfmt == 3) + fb->flags |= V4L2_FBUF_FLAG_LOCAL_INV_ALPHA; + else + fb->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA; + } break; } @@ -1208,7 +1246,8 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) return -EINVAL; itv->osd_global_alpha_state = (fb->flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) != 0; - itv->osd_local_alpha_state = (fb->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA) != 0; + itv->osd_local_alpha_state = + (fb->flags & (V4L2_FBUF_FLAG_LOCAL_ALPHA|V4L2_FBUF_FLAG_LOCAL_INV_ALPHA)) != 0; itv->osd_chroma_key_state = (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0; ivtv_set_osd_alpha(itv); break; @@ -1226,7 +1265,6 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void case VIDIOC_LOG_STATUS: { int has_output = itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT; - u32 data[CX2341X_MBOX_MAX_DATA]; struct v4l2_input vidin; struct v4l2_audio audin; int i; @@ -1248,28 +1286,28 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void struct v4l2_output vidout; struct v4l2_audioout audout; int mode = itv->output_mode; - static const char * const output_modes[] = { + static const char * const output_modes[5] = { "None", "MPEG Streaming", "YUV Streaming", "YUV Frames", "Passthrough", }; - static const char * const audio_modes[] = { + static const char * const audio_modes[5] = { "Stereo", "Left", "Right", "Mono", "Swapped" }; - static const char * const alpha_mode[] = { + static const char * const alpha_mode[4] = { "None", "Global", "Local", "Global and Local" }; - static const char * const pixel_format[] = { - "RGB Indexed", + static const char * const pixel_format[16] = { + "ARGB Indexed", "RGB 5:6:5", "ARGB 1:5:5:5", "ARGB 1:4:4:4", @@ -1277,7 +1315,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void "5", "6", "7", - "YUV Indexed", + "AYUV Indexed", "YUV 5:6:5", "AYUV 1:5:5:5", "AYUV 1:4:4:4", -- cgit v1.2.3-70-g09d2 From 6327e952cd3ef5e5a49c84f794dbba72ff3c0e9c Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Fri, 24 Aug 2007 05:28:54 -0300 Subject: V4L/DVB (6098): ivtv: kzalloc() returns void pointer, no need to cast Since kzalloc() returns a void pointer, we don't need to cast the return value in drivers/media/video/ivtv/ivtv-queue.c Signed-off-by: Jesper Juhl Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-queue.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-queue.c b/drivers/media/video/ivtv/ivtv-queue.c index 437f134796e..39a21671324 100644 --- a/drivers/media/video/ivtv/ivtv-queue.c +++ b/drivers/media/video/ivtv/ivtv-queue.c @@ -203,14 +203,14 @@ int ivtv_stream_alloc(struct ivtv_stream *s) s->dma != PCI_DMA_NONE ? "DMA " : "", s->name, s->buffers, s->buf_size, s->buffers * s->buf_size / 1024); - s->sg_pending = (struct ivtv_sg_element *)kzalloc(SGsize, GFP_KERNEL); + s->sg_pending = kzalloc(SGsize, GFP_KERNEL); if (s->sg_pending == NULL) { IVTV_ERR("Could not allocate sg_pending for %s stream\n", s->name); return -ENOMEM; } s->sg_pending_size = 0; - s->sg_processing = (struct ivtv_sg_element *)kzalloc(SGsize, GFP_KERNEL); + s->sg_processing = kzalloc(SGsize, GFP_KERNEL); if (s->sg_processing == NULL) { IVTV_ERR("Could not allocate sg_processing for %s stream\n", s->name); kfree(s->sg_pending); @@ -219,7 +219,7 @@ int ivtv_stream_alloc(struct ivtv_stream *s) } s->sg_processing_size = 0; - s->sg_dma = (struct ivtv_sg_element *)kzalloc(sizeof(struct ivtv_sg_element), GFP_KERNEL); + s->sg_dma = kzalloc(sizeof(struct ivtv_sg_element), GFP_KERNEL); if (s->sg_dma == NULL) { IVTV_ERR("Could not allocate sg_dma for %s stream\n", s->name); kfree(s->sg_pending); -- cgit v1.2.3-70-g09d2 From 71be258bd9bf41ca3060021f2ed50ad8c672a01e Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Thu, 23 Aug 2007 22:33:28 -0300 Subject: V4L/DVB (6100): dvb_net: whitespace cleanup Clean whitespace brain-damage caused by previous patch, "Fix a warning at dvb_net" Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_net.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c index 13e2998a404..2117377c141 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ b/drivers/media/dvb/dvb-core/dvb_net.c @@ -795,8 +795,8 @@ static int dvb_net_ts_callback(const u8 *buffer1, size_t buffer1_len, } -static void dvb_net_sec(struct net_device *dev, const u8 *pkt, int -pkt_len) +static void dvb_net_sec(struct net_device *dev, + const u8 *pkt, int pkt_len) { u8 *eth; struct sk_buff *skb; -- cgit v1.2.3-70-g09d2 From d9bf2c037754f1493323829048d6210602712a43 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Sat, 25 Aug 2007 11:23:54 -0300 Subject: V4L/DVB (6102): dvb: remove some unneeded vmalloc() return value casts from av7110 vmalloc() returns void * - no need to cast it. Signed-off-by: Jesper Juhl Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ttpci/av7110.c | 2 +- drivers/media/dvb/ttpci/av7110_ir.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index aecfdeb8ec4..8b8144f77a7 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -1542,7 +1542,7 @@ static int get_firmware(struct av7110* av7110) } /* check if the firmware is available */ - av7110->bin_fw = (unsigned char *) vmalloc(fw->size); + av7110->bin_fw = vmalloc(fw->size); if (NULL == av7110->bin_fw) { dprintk(1, "out of memory\n"); release_firmware(fw); diff --git a/drivers/media/dvb/ttpci/av7110_ir.c b/drivers/media/dvb/ttpci/av7110_ir.c index e8f553719bc..5d19c402dad 100644 --- a/drivers/media/dvb/ttpci/av7110_ir.c +++ b/drivers/media/dvb/ttpci/av7110_ir.c @@ -279,7 +279,7 @@ static int av7110_ir_write_proc(struct file *file, const char __user *buffer, if (count < size) return -EINVAL; - page = (char *) vmalloc(size); + page = vmalloc(size); if (!page) return -ENOMEM; -- cgit v1.2.3-70-g09d2 From 0c12c1bfc432477e38ba76f680be4b3f55112a8e Mon Sep 17 00:00:00 2001 From: Marco Schluessler Date: Sat, 25 Aug 2007 11:36:39 -0300 Subject: V4L/DVB (6103): dvb_ca_en50221: return correct error code value return correct error code value Signed-off-by: Marco Schluessler Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_ca_en50221.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c index b0bf21958ed..3f747955791 100644 --- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c @@ -1569,7 +1569,7 @@ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file) { struct dvb_device *dvbdev = file->private_data; struct dvb_ca_private *ca = dvbdev->priv; - int err = 0; + int err; dprintk("%s\n", __FUNCTION__); @@ -1581,7 +1581,7 @@ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file) module_put(ca->pub->owner); - return 0; + return err; } -- cgit v1.2.3-70-g09d2 From 226835d7e0a1136bce2a0b923e0832ab47450a30 Mon Sep 17 00:00:00 2001 From: Marco Schluessler Date: Sat, 25 Aug 2007 11:46:07 -0300 Subject: V4L/DVB (6104): dvb_ca_en50221: decrement module use count on error decrement module use count on error Signed-off-by: Marco Schluessler Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_ca_en50221.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c index 3f747955791..5c7bcb8393d 100644 --- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c @@ -1535,8 +1535,10 @@ static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file) return -EIO; err = dvb_generic_open(inode, file); - if (err < 0) + if (err < 0) { + module_put(ca->pub->owner); return err; + } for (i = 0; i < ca->slot_count; i++) { -- cgit v1.2.3-70-g09d2 From 48136e1e93195b56dc3d9b0730917241b3365633 Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Sat, 25 Aug 2007 12:00:23 -0300 Subject: V4L/DVB (6105): dvb_frontend: ts_bus_ctrl() handling fixed ts_bus_ctrl() should only be called by - the first open - the last release call. Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 38 ++++++++++++++++++------------- 1 file changed, 22 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 880d499cd36..07c0db2abfb 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -1056,18 +1056,15 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) dprintk ("%s\n", __FUNCTION__); - if ((ret = dvb_generic_open (inode, file)) < 0) - return ret; - - if (fe->ops.ts_bus_ctrl) { - if ((ret = fe->ops.ts_bus_ctrl (fe, 1)) < 0) { - dvb_generic_release (inode, file); + if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl) { + if ((ret = fe->ops.ts_bus_ctrl(fe, 1)) < 0) return ret; - } } - if ((file->f_flags & O_ACCMODE) != O_RDONLY) { + if ((ret = dvb_generic_open (inode, file)) < 0) + goto err1; + if ((file->f_flags & O_ACCMODE) != O_RDONLY) { /* normal tune mode when opened R/W */ fepriv->tune_mode_flags &= ~FE_TUNE_MODE_ONESHOT; fepriv->tone = -1; @@ -1075,13 +1072,20 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) ret = dvb_frontend_start (fe); if (ret) - dvb_generic_release (inode, file); + goto err2; /* empty event queue */ fepriv->events.eventr = fepriv->events.eventw = 0; } return ret; + +err2: + dvb_generic_release(inode, file); +err1: + if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl) + fe->ops.ts_bus_ctrl(fe, 0); + return ret; } static int dvb_frontend_release(struct inode *inode, struct file *file) @@ -1096,16 +1100,18 @@ static int dvb_frontend_release(struct inode *inode, struct file *file) if ((file->f_flags & O_ACCMODE) != O_RDONLY) fepriv->release_jiffies = jiffies; - if (fe->ops.ts_bus_ctrl) - fe->ops.ts_bus_ctrl (fe, 0); - ret = dvb_generic_release (inode, file); - if (dvbdev->users==-1 && fepriv->exit==1) { - fops_put(file->f_op); - file->f_op = NULL; - wake_up(&dvbdev->wait_queue); + if (dvbdev->users == -1) { + if (fepriv->exit == 1) { + fops_put(file->f_op); + file->f_op = NULL; + wake_up(&dvbdev->wait_queue); + } + if (fe->ops.ts_bus_ctrl) + fe->ops.ts_bus_ctrl(fe, 0); } + return ret; } -- cgit v1.2.3-70-g09d2 From 849be2cdf11eef830ec2a3f916c8e7d1e51bc9fb Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Sat, 25 Aug 2007 12:22:16 -0300 Subject: V4L/DVB (6106): dvb_frontend: Default for dvb_shutdown_timeout set to 0 Default for dvb_shutdown_timeout set to 0. dvb_shutdown_timeout > 0 is used for debugging only. Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 07c0db2abfb..32017f62a82 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -42,7 +42,7 @@ #include "dvbdev.h" static int dvb_frontend_debug; -static int dvb_shutdown_timeout = 5; +static int dvb_shutdown_timeout; static int dvb_force_auto_inversion; static int dvb_override_tune_delay; static int dvb_powerdown_on_sleep = 1; -- cgit v1.2.3-70-g09d2 From 608f62d6ffbc21067e8b9a09f887a5d6cbfe7617 Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Sat, 25 Aug 2007 13:17:53 -0300 Subject: V4L/DVB (6107): dvb_frontend: clean-up shutdown handling Now dvb_powerdown_on_sleep controls whether - whether LNB power is turned off - whether the tuner/frontend enters sleep mode Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 32017f62a82..b203640ef1c 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -573,10 +573,9 @@ restart: dvb_frontend_swzigzag(fe); } - if (dvb_shutdown_timeout) { - if (dvb_powerdown_on_sleep) - if (fe->ops.set_voltage) - fe->ops.set_voltage(fe, SEC_VOLTAGE_OFF); + if (dvb_powerdown_on_sleep) { + if (fe->ops.set_voltage) + fe->ops.set_voltage(fe, SEC_VOLTAGE_OFF); if (fe->ops.tuner_ops.sleep) { fe->ops.tuner_ops.sleep(fe); if (fe->ops.i2c_gate_ctrl) -- cgit v1.2.3-70-g09d2 From 3eaeef57423b5f9571e7524373ec079f583b2113 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 25 Aug 2007 15:19:18 -0300 Subject: V4L/DVB (6109): ivtv: use new videodev2.h pixel formats Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-ioctl.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index 6d24c6b9a45..206eee7542d 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -1186,7 +1186,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void struct v4l2_framebuffer *fb = arg; int pixfmt; static u32 pixel_format[16] = { - V4L2_PIX_FMT_RGB332, /* Really RGB Indexed */ + V4L2_PIX_FMT_PAL8, /* Uses a 256-entry RGB colormap */ V4L2_PIX_FMT_RGB565, V4L2_PIX_FMT_RGB555, V4L2_PIX_FMT_RGB444, @@ -1194,12 +1194,11 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void 0, 0, 0, - /* Really YUV variants */ - V4L2_PIX_FMT_RGB332, /* Really YUV Indexed */ - V4L2_PIX_FMT_RGB565, - V4L2_PIX_FMT_RGB555, - V4L2_PIX_FMT_RGB444, - V4L2_PIX_FMT_RGB32, + V4L2_PIX_FMT_PAL8, /* Uses a 256-entry YUV colormap */ + V4L2_PIX_FMT_YUV565, + V4L2_PIX_FMT_YUV555, + V4L2_PIX_FMT_YUV444, + V4L2_PIX_FMT_YUV32, 0, 0, 0, -- cgit v1.2.3-70-g09d2 From f58db9590fc56fe519d6919abae7a70ec17b4d0e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 27 Aug 2007 12:05:18 -0300 Subject: V4L/DVB (6111): Fix a warning when compiling on x86_64 tcm825x.c: In function 'ioctl_try_fmt_cap': tcm825x.c:639: warning: format '%d' expects type 'int', but argument 4 has type 'long unsigned int' Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tcm825x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/tcm825x.c b/drivers/media/video/tcm825x.c index 4b973b099e5..3a139f288a9 100644 --- a/drivers/media/video/tcm825x.c +++ b/drivers/media/video/tcm825x.c @@ -635,8 +635,8 @@ static int ioctl_try_fmt_cap(struct v4l2_int_device *s, struct v4l2_pix_format *pix = &f->fmt.pix; isize = tcm825x_find_size(s, pix->width, pix->height); - dev_dbg(&sensor->i2c_client->dev, "isize = %d num_capture = %d\n", - isize, TCM825X_NUM_CAPTURE_FORMATS); + dev_dbg(&sensor->i2c_client->dev, "isize = %d num_capture = %lu\n", + isize, (unsigned long)TCM825X_NUM_CAPTURE_FORMATS); pix->width = tcm825x_sizes[isize].width; pix->height = tcm825x_sizes[isize].height; -- cgit v1.2.3-70-g09d2 From 21340ae03a61bded62acb582264660e61c0636b9 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 26 Aug 2007 10:53:16 -0300 Subject: V4L/DVB (6112): cx25840: use a workqueue to load the firmware Loading the firmware using the i2c bit-banging code blocks the kernel. Move the firmware load code into a workqueue so that it plays well with other processes. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx25840/cx25840-core.c | 45 ++++++++++++++++++++++++------ drivers/media/video/cx25840/cx25840-core.h | 4 ++- 2 files changed, 39 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index ae90d1c3d12..d6f8b3b6af4 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -179,9 +179,18 @@ static void cx25836_initialize(struct i2c_client *client) cx25840_and_or(client, 0x15b, ~0x1e, 0x10); } +static void cx25840_work_handler(struct work_struct *work) +{ + struct cx25840_state *state = container_of(work, struct cx25840_state, fw_work); + cx25840_loadfw(state->c); + wake_up(&state->fw_wait); +} + static void cx25840_initialize(struct i2c_client *client) { + DEFINE_WAIT(wait); struct cx25840_state *state = i2c_get_clientdata(client); + struct workqueue_struct *q; /* datasheet startup in numbered steps, refer to page 3-77 */ /* 2. */ @@ -197,7 +206,19 @@ static void cx25840_initialize(struct i2c_client *client) cx25840_write(client, 0x13c, 0x01); cx25840_write(client, 0x13c, 0x00); /* 5. */ - cx25840_loadfw(client); + /* Do the firmware load in a work handler to prevent. + Otherwise the kernel is blocked waiting for the + bit-banging i2c interface to finish uploading the + firmware. */ + INIT_WORK(&state->fw_work, cx25840_work_handler); + init_waitqueue_head(&state->fw_wait); + q = create_singlethread_workqueue("cx25840_fw"); + prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE); + queue_work(q, &state->fw_work); + schedule(); + finish_wait(&state->fw_wait, &wait); + destroy_workqueue(q); + /* 6. */ cx25840_write(client, 0x115, 0x8c); cx25840_write(client, 0x116, 0x07); @@ -872,17 +893,16 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address, if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) return 0; - state = kzalloc(sizeof(struct cx25840_state), GFP_KERNEL); - if (state == 0) + client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (client == 0) return -ENOMEM; - client = &state->c; client->addr = address; client->adapter = adapter; client->driver = &i2c_driver_cx25840; snprintf(client->name, sizeof(client->name) - 1, "cx25840"); - v4l_dbg(1, cx25840_debug, client, "detecting cx25840 client on address 0x%x\n", address << 1); + v4l_dbg(1, cx25840_debug, client, "detecting cx25840 client on address 0x%x\n", client->addr << 1); device_id = cx25840_read(client, 0x101) << 8; device_id |= cx25840_read(client, 0x100); @@ -891,26 +911,32 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address, * 0x83 for the cx2583x and 0x84 for the cx2584x */ if ((device_id & 0xff00) == 0x8300) { id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6; - state->is_cx25836 = 1; } else if ((device_id & 0xff00) == 0x8400) { id = V4L2_IDENT_CX25840 + ((device_id >> 4) & 0xf); - state->is_cx25836 = 0; } else { v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n"); - kfree(state); + kfree(client); return 0; } + state = kzalloc(sizeof(struct cx25840_state), GFP_KERNEL); + if (state == NULL) { + kfree(client); + return -ENOMEM; + } + /* Note: revision '(device_id & 0x0f) == 2' was never built. The marking skips from 0x1 == 22 to 0x3 == 23. */ v4l_info(client, "cx25%3x-2%x found @ 0x%x (%s)\n", (device_id & 0xfff0) >> 4, (device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1 : (device_id & 0x0f), - address << 1, adapter->name); + client->addr << 1, client->adapter->name); i2c_set_clientdata(client, state); + state->c = client; + state->is_cx25836 = ((device_id & 0xff00) == 0x8300); state->vid_input = CX25840_COMPOSITE7; state->aud_input = CX25840_AUDIO8; state->audclk_freq = 48000; @@ -944,6 +970,7 @@ static int cx25840_detach_client(struct i2c_client *client) } kfree(state); + kfree(client); return 0; } diff --git a/drivers/media/video/cx25840/cx25840-core.h b/drivers/media/video/cx25840/cx25840-core.h index 86e2edfc494..ea669b1f084 100644 --- a/drivers/media/video/cx25840/cx25840-core.h +++ b/drivers/media/video/cx25840/cx25840-core.h @@ -35,7 +35,7 @@ extern int cx25840_debug; #define CX25840_CID_ENABLE_PVR150_WORKAROUND (V4L2_CID_PRIVATE_BASE+0) struct cx25840_state { - struct i2c_client c; + struct i2c_client *c; int pvr150_workaround; int radio; enum cx25840_video_input vid_input; @@ -48,6 +48,8 @@ struct cx25840_state { u32 rev; int is_cx25836; int is_initialized; + wait_queue_head_t fw_wait; /* wake up when the fw load is finished */ + struct work_struct fw_work; /* work entry for fw load */ }; /* ----------------------------------------------------------------------- */ -- cgit v1.2.3-70-g09d2 From 49ebf14e249734a5f64d5bdd9aaa2ddf4bcedc51 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 26 Aug 2007 10:54:14 -0300 Subject: V4L/DVB (6113): ivtv: udelay for the i2c bus was set too high An udelay of 5 is sufficient for standard speed i2c busses, 10 make it too slow. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c index 085dc3938da..285fca676a6 100644 --- a/drivers/media/video/ivtv/ivtv-i2c.c +++ b/drivers/media/video/ivtv/ivtv-i2c.c @@ -541,7 +541,7 @@ static const struct i2c_algo_bit_data ivtv_i2c_algo_template = { .setscl = ivtv_setscl_old, .getsda = ivtv_getsda_old, .getscl = ivtv_getscl_old, - .udelay = 10, + .udelay = 5, .timeout = 200, }; -- cgit v1.2.3-70-g09d2 From 26e9d599561e9a964bd4d7c2be0029db8aaff852 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 25 Aug 2007 05:41:52 -0300 Subject: V4L/DVB (6115): ivtv/ivtv-fb: improve locking to avoid initialization problems ivtv/ivtv-fb: improve locking to prevent ivtv/ivtv-fb initialization problems Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.c | 4 ++++ drivers/media/video/ivtv/ivtv-fb.c | 3 +++ 2 files changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 855697c1c96..2a5e0facca7 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -1003,6 +1003,8 @@ static int __devinit ivtv_probe(struct pci_dev *dev, IVTV_DEBUG_INFO("base addr: 0x%08x\n", itv->base_addr); + mutex_lock(&itv->serialize_lock); + /* PCI Device Setup */ if ((retval = ivtv_setup_pci(itv, dev, pci_id)) != 0) { if (retval == -EIO) @@ -1174,6 +1176,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev, IVTV_ERR("Failed to register irq %d\n", retval); goto free_streams; } + mutex_unlock(&itv->serialize_lock); IVTV_INFO("Initialized card #%d: %s\n", itv->num, itv->card_name); return 0; @@ -1192,6 +1195,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev, release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE); free_workqueue: destroy_workqueue(itv->irq_work_queues); + mutex_unlock(&itv->serialize_lock); err: if (retval == 0) retval = -ENODEV; diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c index e80564aed63..ffe6478682a 100644 --- a/drivers/media/video/ivtv/ivtv-fb.c +++ b/drivers/media/video/ivtv/ivtv-fb.c @@ -1011,10 +1011,13 @@ static int ivtvfb_init_io(struct ivtv *itv) { struct osd_info *oi = itv->osd_info; + mutex_lock(&itv->serialize_lock); if (ivtv_init_on_first_open(itv)) { + mutex_unlock(&itv->serialize_lock); IVTV_FB_ERR("Failed to initialize ivtv\n"); return -ENXIO; } + mutex_unlock(&itv->serialize_lock); ivtv_fb_get_framebuffer(itv, &oi->video_rbase, &oi->video_buffer_size); -- cgit v1.2.3-70-g09d2 From 2f3a98931f51be6093df7c6cc2633bf238778b7d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 25 Aug 2007 14:11:23 -0300 Subject: V4L/DVB (6116): ivtv: VBI cleanups and fixes Besides some VBI cleanups this patch also fixes a subtle problem with the VBI re-insertion stream where the PIO work handler wasn't called quickly enough, resulting in occasional corrupt data. Furthermore the CC output didn't disable CC correctly and at the right time, causing duplicates to be sent. An saa7127 fix for VPS output was also added: the wrong data was sent. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.h | 26 ++-- drivers/media/video/ivtv/ivtv-fileops.c | 11 +- drivers/media/video/ivtv/ivtv-irq.c | 10 +- drivers/media/video/ivtv/ivtv-vbi.c | 239 ++++++++++---------------------- drivers/media/video/ivtv/ivtv-vbi.h | 4 +- drivers/media/video/saa7127.c | 10 +- 6 files changed, 113 insertions(+), 187 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 41f753c125d..748ef66bd94 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -489,6 +489,15 @@ struct yuv_playback_info #define IVTV_VBI_FRAMES 32 /* VBI data */ +struct vbi_cc { + u8 odd[2]; /* two-byte payload of odd field */ + u8 even[2]; /* two-byte payload of even field */; +}; + +struct vbi_vps { + u8 data[5]; /* five-byte VPS payload */ +}; + struct vbi_info { /* VBI general fixed card data */ u32 raw_decoder_line_size; /* raw VBI line size from digitizer */ @@ -502,15 +511,14 @@ struct vbi_info { u32 enc_start, enc_size; int fpi; u32 frame; - u8 cc_data_odd[256]; - u8 cc_data_even[256]; - int cc_pos; - u8 cc_no_update; - u8 vps[5]; - u8 vps_found; - int wss; - u8 wss_found; - u8 wss_no_update; + struct vbi_cc cc_payload[256]; /* Sliced VBI CC payload array. It is an array to + prevent dropping CC data if they couldn't be + processed fast enough. */ + int cc_payload_idx; /* Index in cc_payload */ + u8 cc_missing_cnt; /* Counts number of frames without CC for passthrough mode */ + int wss_payload; /* Sliced VBI WSS payload */ + u8 wss_missing_cnt; /* Counts number of frames without WSS for passthrough mode */ + struct vbi_vps vps_payload; /* Sliced VBI VPS payload */ struct v4l2_format in; /* convenience pointer to sliced struct in vbi_in union */ struct v4l2_sliced_vbi_format *sliced_in; diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index 5b5d6666fa1..da50fa4a72a 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -563,8 +563,11 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c /* This stream does not need to start any decoding */ if (s->type == IVTV_DEC_STREAM_TYPE_VOUT) { + int elems = count / sizeof(struct v4l2_sliced_vbi_data); + set_bit(IVTV_F_S_APPL_IO, &s->s_flags); - return ivtv_write_vbi(itv, user_buf, count); + ivtv_write_vbi(itv, (const struct v4l2_sliced_vbi_data *)user_buf, elems); + return elems * sizeof(struct v4l2_sliced_vbi_data); } mode = s->type == IVTV_DEC_STREAM_TYPE_MPG ? OUT_MPG : OUT_YUV; @@ -828,10 +831,10 @@ int ivtv_v4l2_close(struct inode *inode, struct file *filp) ivtv_stop_decoding(id, VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0); /* If all output streams are closed, and if the user doesn't have - IVTV_DEC_STREAM_TYPE_VOUT open, then disable VBI on TV-out. */ + IVTV_DEC_STREAM_TYPE_VOUT open, then disable CC on TV-out. */ if (itv->output_mode == OUT_NONE && !test_bit(IVTV_F_S_APPL_IO, &s_vout->s_flags)) { - /* disable VBI on TV-out */ - ivtv_disable_vbi(itv); + /* disable CC on TV-out */ + ivtv_disable_cc(itv); } } else { ivtv_stop_capture(id, 0); diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c index 66d0da22389..bf7d99c6ffa 100644 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ b/drivers/media/video/ivtv/ivtv-irq.c @@ -786,7 +786,10 @@ static void ivtv_irq_vsync(struct ivtv *itv) wake_up(&s->waitq); /* Send VBI to saa7127 */ - if (frame) { + if (frame && (itv->output_mode == OUT_PASSTHROUGH || + test_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags) || + test_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags) || + test_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags))) { set_bit(IVTV_F_I_WORK_HANDLER_VBI, &itv->i_flags); set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags); } @@ -809,7 +812,7 @@ static void ivtv_irq_vsync(struct ivtv *itv) } } -#define IVTV_IRQ_DMA (IVTV_IRQ_DMA_READ | IVTV_IRQ_ENC_DMA_COMPLETE | IVTV_IRQ_DMA_ERR | IVTV_IRQ_ENC_START_CAP | IVTV_IRQ_ENC_VBI_CAP | IVTV_IRQ_DEC_DATA_REQ) +#define IVTV_IRQ_DMA (IVTV_IRQ_DMA_READ | IVTV_IRQ_ENC_DMA_COMPLETE | IVTV_IRQ_DMA_ERR | IVTV_IRQ_ENC_START_CAP | IVTV_IRQ_ENC_VBI_CAP | IVTV_IRQ_DEC_DATA_REQ | IVTV_IRQ_DEC_VBI_RE_INSERT) irqreturn_t ivtv_irq_handler(int irq, void *dev_id) { @@ -942,8 +945,9 @@ irqreturn_t ivtv_irq_handler(int irq, void *dev_id) } } - if (test_and_clear_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags)) + if (test_and_clear_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags)) { queue_work(itv->irq_work_queues, &itv->irq_work_queue); + } spin_unlock(&itv->dma_reg_lock); diff --git a/drivers/media/video/ivtv/ivtv-vbi.c b/drivers/media/video/ivtv/ivtv-vbi.c index 5d8a40f3d2b..c151bcf5519 100644 --- a/drivers/media/video/ivtv/ivtv-vbi.c +++ b/drivers/media/video/ivtv/ivtv-vbi.c @@ -23,8 +23,7 @@ #include "ivtv-queue.h" #include "ivtv-vbi.h" -static void ivtv_set_vps(struct ivtv *itv, int enabled, u8 vps1, u8 vps2, u8 vps3, - u8 vps4, u8 vps5) +static void ivtv_set_vps(struct ivtv *itv, int enabled) { struct v4l2_sliced_vbi_data data; @@ -33,15 +32,15 @@ static void ivtv_set_vps(struct ivtv *itv, int enabled, u8 vps1, u8 vps2, u8 vps data.id = V4L2_SLICED_VPS; data.field = 0; data.line = enabled ? 16 : 0; - data.data[4] = vps1; - data.data[10] = vps2; - data.data[11] = vps3; - data.data[12] = vps4; - data.data[13] = vps5; + data.data[2] = itv->vbi.vps_payload.data[0]; + data.data[8] = itv->vbi.vps_payload.data[1]; + data.data[9] = itv->vbi.vps_payload.data[2]; + data.data[10] = itv->vbi.vps_payload.data[3]; + data.data[11] = itv->vbi.vps_payload.data[4]; ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data); } -static void ivtv_set_cc(struct ivtv *itv, int mode, u8 cc1, u8 cc2, u8 cc3, u8 cc4) +static void ivtv_set_cc(struct ivtv *itv, int mode, const struct vbi_cc *cc) { struct v4l2_sliced_vbi_data data; @@ -50,13 +49,13 @@ static void ivtv_set_cc(struct ivtv *itv, int mode, u8 cc1, u8 cc2, u8 cc3, u8 c data.id = V4L2_SLICED_CAPTION_525; data.field = 0; data.line = (mode & 1) ? 21 : 0; - data.data[0] = cc1; - data.data[1] = cc2; + data.data[0] = cc->odd[0]; + data.data[1] = cc->odd[1]; ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data); data.field = 1; data.line = (mode & 2) ? 21 : 0; - data.data[0] = cc3; - data.data[1] = cc4; + data.data[0] = cc->even[0]; + data.data[1] = cc->even[1]; ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data); } @@ -92,62 +91,50 @@ static int odd_parity(u8 c) return c & 1; } -static void passthrough_vbi_data(struct ivtv *itv, int cnt) +void ivtv_write_vbi(struct ivtv *itv, const struct v4l2_sliced_vbi_data *sliced, size_t cnt) { - int wss = 0; - u8 cc[4] = { 0x80, 0x80, 0x80, 0x80 }; - u8 vps[13]; + struct vbi_info *vi = &itv->vbi; + struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } }; int found_cc = 0; - int found_wss = 0; - int found_vps = 0; - int cc_pos = itv->vbi.cc_pos; - int i; + size_t i; for (i = 0; i < cnt; i++) { - struct v4l2_sliced_vbi_data *d = itv->vbi.sliced_dec_data + i; + const struct v4l2_sliced_vbi_data *d = sliced + i; if (d->id == V4L2_SLICED_CAPTION_525 && d->line == 21) { - found_cc = 1; if (d->field) { - cc[2] = d->data[0]; - cc[3] = d->data[1]; + cc.even[0] = d->data[0]; + cc.even[1] = d->data[1]; } else { - cc[0] = d->data[0]; - cc[1] = d->data[1]; + cc.odd[0] = d->data[0]; + cc.odd[1] = d->data[1]; } + found_cc = 1; } else if (d->id == V4L2_SLICED_VPS && d->line == 16 && d->field == 0) { - memcpy(vps, d->data, sizeof(vps)); - found_vps = 1; + struct vbi_vps vps; + + vps.data[0] = d->data[2]; + vps.data[1] = d->data[8]; + vps.data[2] = d->data[9]; + vps.data[3] = d->data[10]; + vps.data[4] = d->data[11]; + if (memcmp(&vps, &vi->vps_payload, sizeof(vps))) { + vi->vps_payload = vps; + set_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags); + } } else if (d->id == V4L2_SLICED_WSS_625 && d->line == 23 && d->field == 0) { - wss = d->data[0] | d->data[1] << 8; - found_wss = 1; - } - } + int wss = d->data[0] | d->data[1] << 8; - if (itv->vbi.wss_found != found_wss || itv->vbi.wss != wss) { - itv->vbi.wss = wss; - itv->vbi.wss_found = found_wss; - set_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags); - } - - if (found_vps || itv->vbi.vps_found) { - itv->vbi.vps[0] = vps[2]; - itv->vbi.vps[1] = vps[8]; - itv->vbi.vps[2] = vps[9]; - itv->vbi.vps[3] = vps[10]; - itv->vbi.vps[4] = vps[11]; - itv->vbi.vps_found = found_vps; - set_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags); + if (vi->wss_payload != wss) { + vi->wss_payload = wss; + set_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags); + } + } } - - if (found_cc && cc_pos < sizeof(itv->vbi.cc_data_even)) { - itv->vbi.cc_data_odd[cc_pos] = cc[0]; - itv->vbi.cc_data_odd[cc_pos + 1] = cc[1]; - itv->vbi.cc_data_even[cc_pos] = cc[2]; - itv->vbi.cc_data_even[cc_pos + 1] = cc[3]; - itv->vbi.cc_pos = cc_pos + 2; + if (found_cc && vi->cc_payload_idx < sizeof(vi->cc_payload)) { + vi->cc_payload[vi->cc_payload_idx++] = cc; set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags); } } @@ -271,69 +258,6 @@ static int ivtv_convert_ivtv_vbi(struct ivtv *itv, u8 *p) return line * sizeof(itv->vbi.sliced_dec_data[0]); } -ssize_t ivtv_write_vbi(struct ivtv *itv, const char __user *ubuf, size_t count) -{ - /* Should be a __user pointer, but sparse doesn't parse this bit correctly. */ - const struct v4l2_sliced_vbi_data *p = (const struct v4l2_sliced_vbi_data *)ubuf; - u8 cc[4] = { 0x80, 0x80, 0x80, 0x80 }; - int found_cc = 0; - int cc_pos = itv->vbi.cc_pos; - - while (count >= sizeof(struct v4l2_sliced_vbi_data)) { - switch (p->id) { - case V4L2_SLICED_CAPTION_525: - if (p->line == 21) { - found_cc = 1; - if (p->field) { - cc[2] = p->data[0]; - cc[3] = p->data[1]; - } else { - cc[0] = p->data[0]; - cc[1] = p->data[1]; - } - } - break; - - case V4L2_SLICED_VPS: - if (p->line == 16 && p->field == 0) { - itv->vbi.vps[0] = p->data[2]; - itv->vbi.vps[1] = p->data[8]; - itv->vbi.vps[2] = p->data[9]; - itv->vbi.vps[3] = p->data[10]; - itv->vbi.vps[4] = p->data[11]; - itv->vbi.vps_found = 1; - set_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags); - } - break; - - case V4L2_SLICED_WSS_625: - if (p->line == 23 && p->field == 0) { - /* No lock needed for WSS */ - itv->vbi.wss = p->data[0] | (p->data[1] << 8); - itv->vbi.wss_found = 1; - set_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags); - } - break; - - default: - break; - } - count -= sizeof(*p); - p++; - } - - if (found_cc && cc_pos < sizeof(itv->vbi.cc_data_even)) { - itv->vbi.cc_data_odd[cc_pos] = cc[0]; - itv->vbi.cc_data_odd[cc_pos + 1] = cc[1]; - itv->vbi.cc_data_even[cc_pos] = cc[2]; - itv->vbi.cc_data_even[cc_pos + 1] = cc[3]; - itv->vbi.cc_pos = cc_pos + 2; - set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags); - } - - return (const char __user *)p - ubuf; -} - /* Compress raw VBI format, removes leading SAV codes and surplus space after the field. Returns new compressed size. */ @@ -482,108 +406,95 @@ void ivtv_process_vbi_data(struct ivtv *itv, struct ivtv_buffer *buf, memcpy(buf->buf, itv->vbi.sliced_dec_data, cnt); buf->bytesused = cnt; - passthrough_vbi_data(itv, cnt / sizeof(itv->vbi.sliced_dec_data[0])); + ivtv_write_vbi(itv, itv->vbi.sliced_dec_data, + cnt / sizeof(itv->vbi.sliced_dec_data[0])); return; } } -void ivtv_disable_vbi(struct ivtv *itv) +void ivtv_disable_cc(struct ivtv *itv) { - clear_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags); - clear_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags); + struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } }; + clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags); - ivtv_set_wss(itv, 0, 0); - ivtv_set_cc(itv, 0, 0, 0, 0, 0); - ivtv_set_vps(itv, 0, 0, 0, 0, 0, 0); - itv->vbi.vps_found = itv->vbi.wss_found = 0; - itv->vbi.wss = 0; - itv->vbi.cc_pos = 0; + ivtv_set_cc(itv, 0, &cc); + itv->vbi.cc_payload_idx = 0; } void ivtv_vbi_work_handler(struct ivtv *itv) { + struct vbi_info *vi = &itv->vbi; struct v4l2_sliced_vbi_data data; + struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } }; /* Lock */ if (itv->output_mode == OUT_PASSTHROUGH) { - /* Note: currently only the saa7115 is used in a PVR350, - so these commands are for now saa7115 specific. */ if (itv->is_50hz) { data.id = V4L2_SLICED_WSS_625; data.field = 0; if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) { ivtv_set_wss(itv, 1, data.data[0] & 0xf); - itv->vbi.wss_no_update = 0; - } else if (itv->vbi.wss_no_update == 4) { + vi->wss_missing_cnt = 0; + } else if (vi->wss_missing_cnt == 4) { ivtv_set_wss(itv, 1, 0x8); /* 4x3 full format */ } else { - itv->vbi.wss_no_update++; + vi->wss_missing_cnt++; } } else { - u8 c1 = 0, c2 = 0, c3 = 0, c4 = 0; int mode = 0; data.id = V4L2_SLICED_CAPTION_525; data.field = 0; if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) { mode |= 1; - c1 = data.data[0]; - c2 = data.data[1]; + cc.odd[0] = data.data[0]; + cc.odd[1] = data.data[1]; } data.field = 1; if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) { mode |= 2; - c3 = data.data[0]; - c4 = data.data[1]; + cc.even[0] = data.data[0]; + cc.even[1] = data.data[1]; } if (mode) { - itv->vbi.cc_no_update = 0; - ivtv_set_cc(itv, mode, c1, c2, c3, c4); - } else if (itv->vbi.cc_no_update == 4) { - ivtv_set_cc(itv, 0, 0, 0, 0, 0); + vi->cc_missing_cnt = 0; + ivtv_set_cc(itv, mode, &cc); + } else if (vi->cc_missing_cnt == 4) { + ivtv_set_cc(itv, 0, &cc); } else { - itv->vbi.cc_no_update++; + vi->cc_missing_cnt++; } } return; } if (test_and_clear_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags)) { - /* Lock */ - ivtv_set_wss(itv, itv->vbi.wss_found, itv->vbi.wss & 0xf); + ivtv_set_wss(itv, 1, vi->wss_payload & 0xf); } - if (test_and_clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags)) { - if (itv->vbi.cc_pos == 0) { - ivtv_set_cc(itv, 3, 0x80, 0x80, 0x80, 0x80); + if (test_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags)) { + if (vi->cc_payload_idx == 0) { + clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags); + ivtv_set_cc(itv, 3, &cc); } - while (itv->vbi.cc_pos) { - u8 cc_odd0 = itv->vbi.cc_data_odd[0]; - u8 cc_odd1 = itv->vbi.cc_data_odd[1]; - u8 cc_even0 = itv->vbi.cc_data_even[0]; - u8 cc_even1 = itv->vbi.cc_data_even[1]; - - memcpy(itv->vbi.cc_data_odd, itv->vbi.cc_data_odd + 2, sizeof(itv->vbi.cc_data_odd) - 2); - memcpy(itv->vbi.cc_data_even, itv->vbi.cc_data_even + 2, sizeof(itv->vbi.cc_data_even) - 2); - itv->vbi.cc_pos -= 2; - if (itv->vbi.cc_pos && cc_odd0 == 0x80 && cc_odd1 == 0x80) + while (vi->cc_payload_idx) { + cc = vi->cc_payload[0]; + + memcpy(vi->cc_payload, vi->cc_payload + 1, + sizeof(vi->cc_payload) - sizeof(vi->cc_payload[0])); + vi->cc_payload_idx--; + if (vi->cc_payload_idx && cc.odd[0] == 0x80 && cc.odd[1] == 0x80) continue; - /* Send to Saa7127 */ - ivtv_set_cc(itv, 3, cc_odd0, cc_odd1, cc_even0, cc_even1); - if (itv->vbi.cc_pos == 0) - set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags); + ivtv_set_cc(itv, 3, &cc); break; } } if (test_and_clear_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags)) { - /* Lock */ - ivtv_set_vps(itv, itv->vbi.vps_found, - itv->vbi.vps[0], itv->vbi.vps[1], - itv->vbi.vps[2], itv->vbi.vps[3], itv->vbi.vps[4]); + ivtv_set_vps(itv, 1); } } diff --git a/drivers/media/video/ivtv/ivtv-vbi.h b/drivers/media/video/ivtv/ivtv-vbi.h index d5740493a69..970567b9194 100644 --- a/drivers/media/video/ivtv/ivtv-vbi.h +++ b/drivers/media/video/ivtv/ivtv-vbi.h @@ -20,11 +20,11 @@ #ifndef IVTV_VBI_H #define IVTV_VBI_H -ssize_t ivtv_write_vbi(struct ivtv *itv, const char __user *ubuf, size_t count); +void ivtv_write_vbi(struct ivtv *itv, const struct v4l2_sliced_vbi_data *sliced, size_t count); void ivtv_process_vbi_data(struct ivtv *itv, struct ivtv_buffer *buf, u64 pts_stamp, int streamtype); int ivtv_used_line(struct ivtv *itv, int line, int field); -void ivtv_disable_vbi(struct ivtv *itv); +void ivtv_disable_cc(struct ivtv *itv); void ivtv_set_vbi(unsigned long arg); void ivtv_vbi_work_handler(struct ivtv *itv); diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c index 9f986930490..e35ef321ec7 100644 --- a/drivers/media/video/saa7127.c +++ b/drivers/media/video/saa7127.c @@ -332,11 +332,11 @@ static int saa7127_set_vps(struct i2c_client *client, struct v4l2_sliced_vbi_dat if (!enable) return 0; - state->vps_data[0] = data->data[4]; - state->vps_data[1] = data->data[10]; - state->vps_data[2] = data->data[11]; - state->vps_data[3] = data->data[12]; - state->vps_data[4] = data->data[13]; + state->vps_data[0] = data->data[2]; + state->vps_data[1] = data->data[8]; + state->vps_data[2] = data->data[9]; + state->vps_data[3] = data->data[10]; + state->vps_data[4] = data->data[11]; v4l_dbg(1, debug, client, "Set VPS data %02x %02x %02x %02x %02x\n", state->vps_data[0], state->vps_data[1], state->vps_data[2], state->vps_data[3], -- cgit v1.2.3-70-g09d2 From effa0b08633122cc63d2b7f098434d359d5767ef Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 25 Aug 2007 15:09:52 -0300 Subject: V4L/DVB (6117): ivtv: finish VBI related cleanup Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.h | 67 ++++++++++++++++++++------------- drivers/media/video/ivtv/ivtv-streams.c | 10 ----- 2 files changed, 40 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 748ef66bd94..5400ccef4df 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -499,7 +499,8 @@ struct vbi_vps { }; struct vbi_info { - /* VBI general fixed card data */ + /* VBI general data, does not change during streaming */ + u32 raw_decoder_line_size; /* raw VBI line size from digitizer */ u8 raw_decoder_sav_odd_field; /* raw VBI Start Active Video digitizer code of odd field */ u8 raw_decoder_sav_even_field; /* raw VBI Start Active Video digitizer code of even field */ @@ -507,27 +508,42 @@ struct vbi_info { u8 sliced_decoder_sav_odd_field; /* sliced VBI Start Active Video digitizer code of odd field */ u8 sliced_decoder_sav_even_field; /* sliced VBI Start Active Video digitizer code of even field */ - u32 dec_start; - u32 enc_start, enc_size; - int fpi; - u32 frame; - struct vbi_cc cc_payload[256]; /* Sliced VBI CC payload array. It is an array to + u32 start[2]; /* start of first VBI line in the odd/even fields */ + u32 count; /* number of VBI lines per field */ + u32 raw_size; /* size of raw VBI line from the digitizer */ + u32 sliced_size; /* size of sliced VBI line from the digitizer */ + + u32 dec_start; /* start in decoder memory of VBI re-insertion buffers */ + u32 enc_start; /* start in encoder memory of VBI capture buffers */ + u32 enc_size; /* size of VBI capture area */ + int fpi; /* number of VBI frames per interrupt */ + + struct v4l2_format in; /* current VBI capture format */ + struct v4l2_sliced_vbi_format *sliced_in; /* convenience pointer to sliced struct in vbi.in union */ + int insert_mpeg; /* if non-zero, then embed VBI data in MPEG stream */ + + /* Raw VBI compatibility hack */ + + u32 frame; /* frame counter hack needed for backwards compatibility + of old VBI software */ + + /* Sliced VBI output data */ + + struct vbi_cc cc_payload[256]; /* sliced VBI CC payload array: it is an array to prevent dropping CC data if they couldn't be - processed fast enough. */ - int cc_payload_idx; /* Index in cc_payload */ - u8 cc_missing_cnt; /* Counts number of frames without CC for passthrough mode */ - int wss_payload; /* Sliced VBI WSS payload */ - u8 wss_missing_cnt; /* Counts number of frames without WSS for passthrough mode */ - struct vbi_vps vps_payload; /* Sliced VBI VPS payload */ - struct v4l2_format in; - /* convenience pointer to sliced struct in vbi_in union */ - struct v4l2_sliced_vbi_format *sliced_in; - int insert_mpeg; - - /* Buffer for the maximum of 2 * 18 * packet_size sliced VBI lines. - One for /dev/vbi0 and one for /dev/vbi8 */ - struct v4l2_sliced_vbi_data sliced_data[36]; - struct v4l2_sliced_vbi_data sliced_dec_data[36]; + processed fast enough */ + int cc_payload_idx; /* index in cc_payload */ + u8 cc_missing_cnt; /* counts number of frames without CC for passthrough mode */ + int wss_payload; /* sliced VBI WSS payload */ + u8 wss_missing_cnt; /* counts number of frames without WSS for passthrough mode */ + struct vbi_vps vps_payload; /* sliced VBI VPS payload */ + + /* Sliced VBI capture data */ + + struct v4l2_sliced_vbi_data sliced_data[36]; /* sliced VBI storage for VBI encoder stream */ + struct v4l2_sliced_vbi_data sliced_dec_data[36];/* sliced VBI storage for VBI decoder stream */ + + /* VBI Embedding data */ /* Buffer for VBI data inserted into MPEG stream. The first byte is a dummy byte that's never used. @@ -544,12 +560,9 @@ struct vbi_info { This pointer array will allocate 2049 bytes to store each VBI frame. */ u8 *sliced_mpeg_data[IVTV_VBI_FRAMES]; u32 sliced_mpeg_size[IVTV_VBI_FRAMES]; - struct ivtv_buffer sliced_mpeg_buf; - u32 inserted_frame; - - u32 start[2], count; - u32 raw_size; - u32 sliced_size; + struct ivtv_buffer sliced_mpeg_buf; /* temporary buffer holding data from sliced_mpeg_data */ + u32 inserted_frame; /* index in sliced_mpeg_size of next sliced data + to be inserted in the MPEG stream */ }; /* forward declaration of struct defined in ivtv-cards.h */ diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index a3296224f82..fd135985e70 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -321,16 +321,6 @@ static void ivtv_vbi_setup(struct ivtv *itv) /* Reset VBI */ ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, 0xffff , 0, 0, 0, 0); - if (itv->is_60hz) { - itv->vbi.count = 12; - itv->vbi.start[0] = 10; - itv->vbi.start[1] = 273; - } else { /* PAL/SECAM */ - itv->vbi.count = 18; - itv->vbi.start[0] = 6; - itv->vbi.start[1] = 318; - } - /* setup VBI registers */ itv->video_dec_func(itv, VIDIOC_S_FMT, &itv->vbi.in); -- cgit v1.2.3-70-g09d2 From 66cfaeff95d20d1377b4fa3d2c6aa7c29d832941 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 26 Aug 2007 05:45:48 -0300 Subject: V4L/DVB (6118): ivtv-fb: add missing FBIO_WAITFORVSYNC ioctl define Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-fb.c | 3 +-- include/media/ivtv-fb.h | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c index ffe6478682a..d2b1f5d5c8b 100644 --- a/drivers/media/video/ivtv/ivtv-fb.c +++ b/drivers/media/video/ivtv/ivtv-fb.c @@ -47,7 +47,7 @@ #include #include #include -#include +#include #include #include @@ -59,7 +59,6 @@ #include "ivtv-driver.h" #include "ivtv-udma.h" #include "ivtv-mailbox.h" -#include /* card parameters */ static int ivtv_fb_card_id = -1; diff --git a/include/media/ivtv-fb.h b/include/media/ivtv-fb.h index 3b746f5e3c9..d3a797b1728 100644 --- a/include/media/ivtv-fb.h +++ b/include/media/ivtv-fb.h @@ -29,6 +29,7 @@ struct ivtvfb_dma_frame { int count; }; -#define IVTVFB_IOC_DMA_FRAME _IOW ('V', BASE_VIDIOC_PRIVATE+0, struct ivtvfb_dma_frame) +#define IVTVFB_IOC_DMA_FRAME _IOW ('V', BASE_VIDIOC_PRIVATE+0, struct ivtvfb_dma_frame) +#define FBIO_WAITFORVSYNC _IOW('F', 0x20, u_int32_t) #endif -- cgit v1.2.3-70-g09d2 From 0f45b8c57e40cca1778b0b75daab65ca139e5bb9 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 26 Aug 2007 06:04:10 -0300 Subject: V4L/DVB (6119): ivtvfb: renamed ivtv-fb to ivtvfb, move header to include/linux The convention for framebuffer devices is to call them xxxfb, not xxx-fb. Conform to this. Also move the ivtvfb.h header to include/linux: it is a public header. The FBIO_WAITFORVSYNC ioctl is now also defined in the ivtvfb.h header, no more need to include matroxfb.h for just this ioctl. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/Kconfig | 2 +- drivers/media/video/ivtv/Makefile | 2 +- drivers/media/video/ivtv/ivtv-fb.c | 1199 ------------------------------------ drivers/media/video/ivtv/ivtvfb.c | 1190 +++++++++++++++++++++++++++++++++++ include/linux/ivtvfb.h | 42 ++ include/media/ivtv-fb.h | 35 -- 6 files changed, 1234 insertions(+), 1236 deletions(-) delete mode 100644 drivers/media/video/ivtv/ivtv-fb.c create mode 100644 drivers/media/video/ivtv/ivtvfb.c create mode 100644 include/linux/ivtvfb.h delete mode 100644 include/media/ivtv-fb.h (limited to 'drivers') diff --git a/drivers/media/video/ivtv/Kconfig b/drivers/media/video/ivtv/Kconfig index 5efacb33211..7f20c166d59 100644 --- a/drivers/media/video/ivtv/Kconfig +++ b/drivers/media/video/ivtv/Kconfig @@ -27,7 +27,7 @@ config VIDEO_IVTV To compile this driver as a module, choose M here: the module will be called ivtv. -config VIDEO_IVTV_FB +config VIDEO_FB_IVTV tristate "Conexant cx23415 framebuffer support" depends on VIDEO_IVTV && FB && EXPERIMENTAL select FB_CFB_FILLRECT diff --git a/drivers/media/video/ivtv/Makefile b/drivers/media/video/ivtv/Makefile index 6998781e2b1..e8eefd96d89 100644 --- a/drivers/media/video/ivtv/Makefile +++ b/drivers/media/video/ivtv/Makefile @@ -5,4 +5,4 @@ ivtv-objs := ivtv-routing.o ivtv-cards.o ivtv-controls.o \ ivtv-vbi.o ivtv-yuv.o obj-$(CONFIG_VIDEO_IVTV) += ivtv.o -obj-$(CONFIG_VIDEO_IVTV_FB) += ivtv-fb.o +obj-$(CONFIG_VIDEO_FB_IVTV) += ivtvfb.o diff --git a/drivers/media/video/ivtv/ivtv-fb.c b/drivers/media/video/ivtv/ivtv-fb.c deleted file mode 100644 index d2b1f5d5c8b..00000000000 --- a/drivers/media/video/ivtv/ivtv-fb.c +++ /dev/null @@ -1,1199 +0,0 @@ -/* - On Screen Display cx23415 Framebuffer driver - - This module presents the cx23415 OSD (onscreen display) framebuffer memory - as a standard Linux /dev/fb style framebuffer device. The framebuffer has - support for 8, 16 & 32 bpp packed pixel formats with alpha channel. In 16bpp - mode, there is a choice of a three color depths (12, 15 or 16 bits), but no - local alpha. The colorspace is selectable between rgb & yuv. - Depending on the TV standard configured in the ivtv module at load time, - the initial resolution is either 640x400 (NTSC) or 640x480 (PAL) at 8bpp. - Video timings are locked to ensure a vertical refresh rate of 50Hz (PAL) - or 59.94 (NTSC) - - Copyright (c) 2003 Matt T. Yourst - - Derived from drivers/video/vesafb.c - Portions (c) 1998 Gerd Knorr - - 2.6 kernel port: - Copyright (C) 2004 Matthias Badaire - - Copyright (C) 2004 Chris Kennedy - - Copyright (C) 2006 Ian Armstrong - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#ifdef CONFIG_MTRR -#include -#endif - -#include "ivtv-driver.h" -#include "ivtv-udma.h" -#include "ivtv-mailbox.h" - -/* card parameters */ -static int ivtv_fb_card_id = -1; -static int ivtv_fb_debug = 0; -static int osd_laced; -static int osd_compat; -static int osd_depth; -static int osd_upper; -static int osd_left; -static int osd_yres; -static int osd_xres; - -module_param(ivtv_fb_card_id, int, 0444); -module_param_named(debug,ivtv_fb_debug, int, 0644); -module_param(osd_laced, bool, 0444); -module_param(osd_compat, bool, 0444); -module_param(osd_depth, int, 0444); -module_param(osd_upper, int, 0444); -module_param(osd_left, int, 0444); -module_param(osd_yres, int, 0444); -module_param(osd_xres, int, 0444); - -MODULE_PARM_DESC(ivtv_fb_card_id, - "Only use framebuffer of the specified ivtv card (0-31)\n" - "\t\t\tdefault -1: initialize all available framebuffers"); - -MODULE_PARM_DESC(debug, - "Debug level (bitmask). Default: errors only\n" - "\t\t\t(debug = 3 gives full debugging)"); - -MODULE_PARM_DESC(osd_compat, - "Compatibility mode - Display size is locked (use for old X drivers)\n" - "\t\t\t0=off\n" - "\t\t\t1=on\n" - "\t\t\tdefault off"); - -/* Why upper, left, xres, yres, depth, laced ? To match terminology used - by fbset. - Why start at 1 for left & upper coordinate ? Because X doesn't allow 0 */ - -MODULE_PARM_DESC(osd_laced, - "Interlaced mode\n" - "\t\t\t0=off\n" - "\t\t\t1=on\n" - "\t\t\tdefault off"); - -MODULE_PARM_DESC(osd_depth, - "Bits per pixel - 8, 16, 32\n" - "\t\t\tdefault 8"); - -MODULE_PARM_DESC(osd_upper, - "Vertical start position\n" - "\t\t\tdefault 0 (Centered)"); - -MODULE_PARM_DESC(osd_left, - "Horizontal start position\n" - "\t\t\tdefault 0 (Centered)"); - -MODULE_PARM_DESC(osd_yres, - "Display height\n" - "\t\t\tdefault 480 (PAL)\n" - "\t\t\t 400 (NTSC)"); - -MODULE_PARM_DESC(osd_xres, - "Display width\n" - "\t\t\tdefault 640"); - -MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil, John Harvey, Ian Armstrong"); -MODULE_LICENSE("GPL"); - -/* --------------------------------------------------------------------- */ - -#define IVTV_FB_DBGFLG_WARN (1 << 0) -#define IVTV_FB_DBGFLG_INFO (1 << 1) - -#define IVTV_FB_DEBUG(x, type, fmt, args...) \ - do { \ - if ((x) & ivtv_fb_debug) \ - printk(KERN_INFO "ivtv-fb%d " type ": " fmt, itv->num , ## args); \ - } while (0) -#define IVTV_FB_DEBUG_WARN(fmt, args...) IVTV_FB_DEBUG(IVTV_FB_DBGFLG_WARN, "warning", fmt , ## args) -#define IVTV_FB_DEBUG_INFO(fmt, args...) IVTV_FB_DEBUG(IVTV_FB_DBGFLG_INFO, "info", fmt , ## args) - -/* Standard kernel messages */ -#define IVTV_FB_ERR(fmt, args...) printk(KERN_ERR "ivtv-fb%d: " fmt, itv->num , ## args) -#define IVTV_FB_WARN(fmt, args...) printk(KERN_WARNING "ivtv-fb%d: " fmt, itv->num , ## args) -#define IVTV_FB_INFO(fmt, args...) printk(KERN_INFO "ivtv-fb%d: " fmt, itv->num , ## args) - -/* --------------------------------------------------------------------- */ - -#define IVTV_OSD_MAX_WIDTH 720 -#define IVTV_OSD_MAX_HEIGHT 576 - -#define IVTV_OSD_BPP_8 0x00 -#define IVTV_OSD_BPP_16_444 0x03 -#define IVTV_OSD_BPP_16_555 0x02 -#define IVTV_OSD_BPP_16_565 0x01 -#define IVTV_OSD_BPP_32 0x04 - -struct osd_info { - /* Physical base address */ - unsigned long video_pbase; - /* Relative base address (relative to start of decoder memory) */ - u32 video_rbase; - /* Mapped base address */ - volatile char __iomem *video_vbase; - /* Buffer size */ - u32 video_buffer_size; - -#ifdef CONFIG_MTRR - /* video_base rounded down as required by hardware MTRRs */ - unsigned long fb_start_aligned_physaddr; - /* video_base rounded up as required by hardware MTRRs */ - unsigned long fb_end_aligned_physaddr; -#endif - - /* Current osd mode */ - int osd_mode; - - /* Store the buffer offset */ - int set_osd_coords_x; - int set_osd_coords_y; - - /* Current dimensions (NOT VISIBLE SIZE!) */ - int display_width; - int display_height; - int display_byte_stride; - - /* Current bits per pixel */ - int bits_per_pixel; - int bytes_per_pixel; - - /* Frame buffer stuff */ - struct fb_info ivtvfb_info; - struct fb_var_screeninfo ivtvfb_defined; - struct fb_fix_screeninfo ivtvfb_fix; -}; - -struct ivtv_osd_coords { - unsigned long offset; - unsigned long max_offset; - int pixel_stride; - int lines; - int x; - int y; -}; - -/* --------------------------------------------------------------------- */ - -/* ivtv API calls for framebuffer related support */ - -static int ivtv_fb_get_framebuffer(struct ivtv *itv, u32 *fbbase, - u32 *fblength) -{ - u32 data[CX2341X_MBOX_MAX_DATA]; - int rc; - - rc = ivtv_vapi_result(itv, data, CX2341X_OSD_GET_FRAMEBUFFER, 0); - *fbbase = data[0]; - *fblength = data[1]; - return rc; -} - -static int ivtv_fb_get_osd_coords(struct ivtv *itv, - struct ivtv_osd_coords *osd) -{ - struct osd_info *oi = itv->osd_info; - u32 data[CX2341X_MBOX_MAX_DATA]; - - ivtv_vapi_result(itv, data, CX2341X_OSD_GET_OSD_COORDS, 0); - - osd->offset = data[0] - oi->video_rbase; - osd->max_offset = oi->display_width * oi->display_height * 4; - osd->pixel_stride = data[1]; - osd->lines = data[2]; - osd->x = data[3]; - osd->y = data[4]; - return 0; -} - -static int ivtv_fb_set_osd_coords(struct ivtv *itv, const struct ivtv_osd_coords *osd) -{ - struct osd_info *oi = itv->osd_info; - - oi->display_width = osd->pixel_stride; - oi->display_byte_stride = osd->pixel_stride * oi->bytes_per_pixel; - oi->set_osd_coords_x += osd->x; - oi->set_osd_coords_y = osd->y; - - return ivtv_vapi(itv, CX2341X_OSD_SET_OSD_COORDS, 5, - osd->offset + oi->video_rbase, - osd->pixel_stride, - osd->lines, osd->x, osd->y); -} - -static int ivtv_fb_set_display_window(struct ivtv *itv, struct v4l2_rect *ivtv_window) -{ - int osd_height_limit = itv->is_50hz ? 576 : 480; - - /* Only fail if resolution too high, otherwise fudge the start coords. */ - if ((ivtv_window->height > osd_height_limit) || (ivtv_window->width > IVTV_OSD_MAX_WIDTH)) - return -EINVAL; - - /* Ensure we don't exceed display limits */ - if (ivtv_window->top + ivtv_window->height > osd_height_limit) { - IVTV_FB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid height setting (%d, %d)\n", - ivtv_window->top, ivtv_window->height); - ivtv_window->top = osd_height_limit - ivtv_window->height; - } - - if (ivtv_window->left + ivtv_window->width > IVTV_OSD_MAX_WIDTH) { - IVTV_FB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid width setting (%d, %d)\n", - ivtv_window->left, ivtv_window->width); - ivtv_window->left = IVTV_OSD_MAX_WIDTH - ivtv_window->width; - } - - /* Set the OSD origin */ - write_reg((ivtv_window->top << 16) | ivtv_window->left, 0x02a04); - - /* How much to display */ - write_reg(((ivtv_window->top+ivtv_window->height) << 16) | (ivtv_window->left+ivtv_window->width), 0x02a08); - - /* Pass this info back the yuv handler */ - itv->yuv_info.osd_vis_w = ivtv_window->width; - itv->yuv_info.osd_vis_h = ivtv_window->height; - itv->yuv_info.osd_x_offset = ivtv_window->left; - itv->yuv_info.osd_y_offset = ivtv_window->top; - - return 0; -} - -static int ivtv_fb_prep_dec_dma_to_device(struct ivtv *itv, - unsigned long ivtv_dest_addr, void __user *userbuf, - int size_in_bytes) -{ - DEFINE_WAIT(wait); - int ret = 0; - int got_sig = 0; - - mutex_lock(&itv->udma.lock); - /* Map User DMA */ - if (ivtv_udma_setup(itv, ivtv_dest_addr, userbuf, size_in_bytes) <= 0) { - mutex_unlock(&itv->udma.lock); - IVTV_FB_WARN("ivtvfb_prep_dec_dma_to_device, " - "Error with get_user_pages: %d bytes, %d pages returned\n", - size_in_bytes, itv->udma.page_count); - - /* get_user_pages must have failed completely */ - return -EIO; - } - - IVTV_FB_DEBUG_INFO("ivtvfb_prep_dec_dma_to_device, %d bytes, %d pages\n", - size_in_bytes, itv->udma.page_count); - - ivtv_udma_prepare(itv); - prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE); - /* if no UDMA is pending and no UDMA is in progress, then the DMA - is finished */ - while (itv->i_flags & (IVTV_F_I_UDMA_PENDING | IVTV_F_I_UDMA)) { - /* don't interrupt if the DMA is in progress but break off - a still pending DMA. */ - got_sig = signal_pending(current); - if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags)) - break; - got_sig = 0; - schedule(); - } - finish_wait(&itv->dma_waitq, &wait); - - /* Unmap Last DMA Xfer */ - ivtv_udma_unmap(itv); - mutex_unlock(&itv->udma.lock); - if (got_sig) { - IVTV_DEBUG_INFO("User stopped OSD\n"); - return -EINTR; - } - - return ret; -} - -static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source, - unsigned long dest_offset, int count) -{ - DEFINE_WAIT(wait); - struct osd_info *oi = itv->osd_info; - - /* Nothing to do */ - if (count == 0) { - IVTV_FB_DEBUG_WARN("ivtv_fb_prep_frame: Nothing to do. count = 0\n"); - return -EINVAL; - } - - /* Check Total FB Size */ - if ((dest_offset + count) > oi->video_buffer_size) { - IVTV_FB_WARN("ivtv_fb_prep_frame: Overflowing the framebuffer %ld, only %d available\n", - dest_offset + count, oi->video_buffer_size); - return -E2BIG; - } - - /* Not fatal, but will have undesirable results */ - if ((unsigned long)source & 3) - IVTV_FB_WARN("ivtv_fb_prep_frame: Source address not 32 bit aligned (0x%08lx)\n", - (unsigned long)source); - - if (dest_offset & 3) - IVTV_FB_WARN("ivtv_fb_prep_frame: Dest offset not 32 bit aligned (%ld)\n", dest_offset); - - if (count & 3) - IVTV_FB_WARN("ivtv_fb_prep_frame: Count not a multiple of 4 (%d)\n", count); - - /* Check Source */ - if (!access_ok(VERIFY_READ, source + dest_offset, count)) { - IVTV_FB_WARN("Invalid userspace pointer 0x%08lx\n", - (unsigned long)source); - - IVTV_FB_DEBUG_WARN("access_ok() failed for offset 0x%08lx source 0x%08lx count %d\n", - dest_offset, (unsigned long)source, - count); - return -EINVAL; - } - - /* OSD Address to send DMA to */ - dest_offset += IVTV_DECODER_OFFSET + oi->video_rbase; - - /* Fill Buffers */ - return ivtv_fb_prep_dec_dma_to_device(itv, dest_offset, source, count); -} - -static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) -{ - DEFINE_WAIT(wait); - struct ivtv *itv = (struct ivtv *)info->par; - int rc = 0; - - switch (cmd) { - case FBIOGET_VBLANK: { - struct fb_vblank vblank; - u32 trace; - - vblank.flags = FB_VBLANK_HAVE_COUNT |FB_VBLANK_HAVE_VCOUNT | - FB_VBLANK_HAVE_VSYNC; - trace = read_reg(0x028c0) >> 16; - if (itv->is_50hz && trace > 312) trace -= 312; - else if (itv->is_60hz && trace > 262) trace -= 262; - if (trace == 1) vblank.flags |= FB_VBLANK_VSYNCING; - vblank.count = itv->last_vsync_field; - vblank.vcount = trace; - vblank.hcount = 0; - if (copy_to_user((void __user *)arg, &vblank, sizeof(vblank))) - return -EFAULT; - return 0; - } - - case FBIO_WAITFORVSYNC: - prepare_to_wait(&itv->vsync_waitq, &wait, TASK_INTERRUPTIBLE); - if (!schedule_timeout(msecs_to_jiffies(50))) rc = -ETIMEDOUT; - finish_wait(&itv->vsync_waitq, &wait); - return rc; - - case IVTVFB_IOC_DMA_FRAME: { - struct ivtvfb_dma_frame args; - - IVTV_FB_DEBUG_INFO("IVTVFB_IOC_DMA_FRAME\n"); - if (copy_from_user(&args, (void __user *)arg, sizeof(args))) - return -EFAULT; - - return ivtv_fb_prep_frame(itv, cmd, args.source, args.dest_offset, args.count); - } - - default: - IVTV_FB_DEBUG_INFO("Unknown ioctl %08x\n", cmd); - return -EINVAL; - } - return 0; -} - -/* Framebuffer device handling */ - -static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var) -{ - struct osd_info *oi = itv->osd_info; - struct ivtv_osd_coords ivtv_osd; - struct v4l2_rect ivtv_window; - int osd_mode = -1; - - IVTV_FB_DEBUG_INFO("ivtvfb_set_var\n"); - - /* Select color space */ - if (var->nonstd) /* YUV */ - write_reg(read_reg(0x02a00) | 0x0002000, 0x02a00); - else /* RGB */ - write_reg(read_reg(0x02a00) & ~0x0002000, 0x02a00); - - /* Set the color mode */ - switch (var->bits_per_pixel) { - case 8: - osd_mode = IVTV_OSD_BPP_8; - break; - case 32: - osd_mode = IVTV_OSD_BPP_32; - break; - case 16: - switch (var->green.length) { - case 4: - osd_mode = IVTV_OSD_BPP_16_444; - break; - case 5: - osd_mode = IVTV_OSD_BPP_16_555; - break; - case 6: - osd_mode = IVTV_OSD_BPP_16_565; - break; - default: - IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n"); - } - break; - default: - IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n"); - } - - /* Change osd mode if needed. - Although rare, things can go wrong. The extra mode - change seems to help... */ - if (osd_mode != -1 && osd_mode != oi->osd_mode) { - ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0); - ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, osd_mode); - oi->osd_mode = osd_mode; - } - - oi->bits_per_pixel = var->bits_per_pixel; - oi->bytes_per_pixel = var->bits_per_pixel / 8; - - /* Set the flicker filter */ - switch (var->vmode & FB_VMODE_MASK) { - case FB_VMODE_NONINTERLACED: /* Filter on */ - ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 1); - break; - case FB_VMODE_INTERLACED: /* Filter off */ - ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 0); - break; - default: - IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid video mode\n"); - } - - /* Read the current osd info */ - ivtv_fb_get_osd_coords(itv, &ivtv_osd); - - /* Now set the OSD to the size we want */ - ivtv_osd.pixel_stride = var->xres_virtual; - ivtv_osd.lines = var->yres_virtual; - ivtv_osd.x = 0; - ivtv_osd.y = 0; - ivtv_fb_set_osd_coords(itv, &ivtv_osd); - - /* Can't seem to find the right API combo for this. - Use another function which does what we need through direct register access. */ - ivtv_window.width = var->xres; - ivtv_window.height = var->yres; - - /* Minimum margin cannot be 0, as X won't allow such a mode */ - if (!var->upper_margin) var->upper_margin++; - if (!var->left_margin) var->left_margin++; - ivtv_window.top = var->upper_margin - 1; - ivtv_window.left = var->left_margin - 1; - - ivtv_fb_set_display_window(itv, &ivtv_window); - - /* Force update of yuv registers */ - itv->yuv_info.yuv_forced_update = 1; - - IVTV_FB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n", - var->xres, var->yres, - var->xres_virtual, var->yres_virtual, - var->bits_per_pixel); - - IVTV_FB_DEBUG_INFO("Display position: %d, %d\n", - var->left_margin, var->upper_margin); - - IVTV_FB_DEBUG_INFO("Display filter: %s\n", - (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off"); - IVTV_FB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB"); - - return 0; -} - -static int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix) -{ - struct osd_info *oi = itv->osd_info; - - IVTV_FB_DEBUG_INFO("ivtvfb_get_fix\n"); - memset(fix, 0, sizeof(struct fb_fix_screeninfo)); - strcpy(fix->id, "cx23415 TV out"); - fix->smem_start = oi->video_pbase; - fix->smem_len = oi->video_buffer_size; - fix->type = FB_TYPE_PACKED_PIXELS; - fix->visual = (oi->bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; - fix->xpanstep = 1; - fix->ypanstep = 1; - fix->ywrapstep = 0; - fix->line_length = oi->display_byte_stride; - fix->accel = FB_ACCEL_NONE; - return 0; -} - -/* Check the requested display mode, returning -EINVAL if we can't - handle it. */ - -static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) -{ - struct osd_info *oi = itv->osd_info; - int osd_height_limit; - u32 pixclock, hlimit, vlimit; - - IVTV_FB_DEBUG_INFO("ivtvfb_check_var\n"); - - /* Set base references for mode calcs. */ - if (itv->is_50hz) { - pixclock = 84316; - hlimit = 776; - vlimit = 591; - osd_height_limit = 576; - } - else { - pixclock = 83926; - hlimit = 776; - vlimit = 495; - osd_height_limit = 480; - } - - /* Check the bits per pixel */ - if (osd_compat) { - if (var->bits_per_pixel != 32) { - IVTV_FB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel); - return -EINVAL; - } - } - - if (var->bits_per_pixel == 8 || var->bits_per_pixel == 32) { - var->transp.offset = 24; - var->transp.length = 8; - var->red.offset = 16; - var->red.length = 8; - var->green.offset = 8; - var->green.length = 8; - var->blue.offset = 0; - var->blue.length = 8; - } - else if (var->bits_per_pixel == 16) { - /* To find out the true mode, check green length */ - switch (var->green.length) { - case 4: - var->red.offset = 8; - var->red.length = 4; - var->green.offset = 4; - var->green.length = 4; - var->blue.offset = 0; - var->blue.length = 4; - var->transp.offset = 12; - var->transp.length = 1; - break; - case 5: - var->red.offset = 10; - var->red.length = 5; - var->green.offset = 5; - var->green.length = 5; - var->blue.offset = 0; - var->blue.length = 5; - var->transp.offset = 15; - var->transp.length = 1; - break; - default: - var->red.offset = 11; - var->red.length = 5; - var->green.offset = 5; - var->green.length = 6; - var->blue.offset = 0; - var->blue.length = 5; - var->transp.offset = 0; - var->transp.length = 0; - break; - } - } - else { - IVTV_FB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel); - return -EINVAL; - } - - /* Check the resolution */ - if (osd_compat) { - if (var->xres != oi->ivtvfb_defined.xres || - var->yres != oi->ivtvfb_defined.yres || - var->xres_virtual != oi->ivtvfb_defined.xres_virtual || - var->yres_virtual != oi->ivtvfb_defined.yres_virtual) { - IVTV_FB_DEBUG_WARN("Invalid resolution: %dx%d (virtual %dx%d)\n", - var->xres, var->yres, var->xres_virtual, var->yres_virtual); - return -EINVAL; - } - } - else { - if (var->xres > IVTV_OSD_MAX_WIDTH || var->yres > osd_height_limit) { - IVTV_FB_DEBUG_WARN("Invalid resolution: %dx%d\n", - var->xres, var->yres); - return -EINVAL; - } - - /* Max horizontal size is 1023 @ 32bpp, 2046 & 16bpp, 4092 @ 8bpp */ - if (var->xres_virtual > 4095 / (var->bits_per_pixel / 8) || - var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8) > oi->video_buffer_size || - var->xres_virtual < var->xres || - var->yres_virtual < var->yres) { - IVTV_FB_DEBUG_WARN("Invalid virtual resolution: %dx%d\n", - var->xres_virtual, var->yres_virtual); - return -EINVAL; - } - } - - /* Some extra checks if in 8 bit mode */ - if (var->bits_per_pixel == 8) { - /* Width must be a multiple of 4 */ - if (var->xres & 3) { - IVTV_FB_DEBUG_WARN("Invalid resolution for 8bpp: %d\n", var->xres); - return -EINVAL; - } - if (var->xres_virtual & 3) { - IVTV_FB_DEBUG_WARN("Invalid virtual resolution for 8bpp: %d)\n", var->xres_virtual); - return -EINVAL; - } - } - else if (var->bits_per_pixel == 16) { - /* Width must be a multiple of 2 */ - if (var->xres & 1) { - IVTV_FB_DEBUG_WARN("Invalid resolution for 16bpp: %d\n", var->xres); - return -EINVAL; - } - if (var->xres_virtual & 1) { - IVTV_FB_DEBUG_WARN("Invalid virtual resolution for 16bpp: %d)\n", var->xres_virtual); - return -EINVAL; - } - } - - /* Now check the offsets */ - if (var->xoffset >= var->xres_virtual || var->yoffset >= var->yres_virtual) { - IVTV_FB_DEBUG_WARN("Invalid offset: %d (%d) %d (%d)\n", - var->xoffset, var->xres_virtual, var->yoffset, var->yres_virtual); - return -EINVAL; - } - - /* Check pixel format */ - if (var->nonstd > 1) { - IVTV_FB_DEBUG_WARN("Invalid nonstd % d\n", var->nonstd); - return -EINVAL; - } - - /* Check video mode */ - if (((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) && - ((var->vmode & FB_VMODE_MASK) != FB_VMODE_INTERLACED)) { - IVTV_FB_DEBUG_WARN("Invalid video mode: %d\n", var->vmode & FB_VMODE_MASK); - return -EINVAL; - } - - /* Check the left & upper margins - If the margins are too large, just center the screen - (enforcing margins causes too many problems) */ - - if (var->left_margin + var->xres > IVTV_OSD_MAX_WIDTH + 1) { - var->left_margin = 1 + ((IVTV_OSD_MAX_WIDTH - var->xres) / 2); - } - if (var->upper_margin + var->yres > (itv->is_50hz ? 577 : 481)) { - var->upper_margin = 1 + (((itv->is_50hz ? 576 : 480) - var->yres) / 2); - } - - /* Maintain overall 'size' for a constant refresh rate */ - var->right_margin = hlimit - var->left_margin - var->xres; - var->lower_margin = vlimit - var->upper_margin - var->yres; - - /* Fixed sync times */ - var->hsync_len = 24; - var->vsync_len = 2; - - /* Non-interlaced / interlaced mode is used to switch the OSD filter - on or off. Adjust the clock timings to maintain a constant - vertical refresh rate. */ - if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) - var->pixclock = pixclock / 2; - else - var->pixclock = pixclock; - - IVTV_FB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n", - var->xres, var->yres, - var->xres_virtual, var->yres_virtual, - var->bits_per_pixel); - - IVTV_FB_DEBUG_INFO("Display position: %d, %d\n", - var->left_margin, var->upper_margin); - - IVTV_FB_DEBUG_INFO("Display filter: %s\n", - (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off"); - IVTV_FB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB"); - return 0; -} - -static int ivtvfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) -{ - struct ivtv *itv = (struct ivtv *) info->par; - IVTV_FB_DEBUG_INFO("ivtvfb_check_var\n"); - return _ivtvfb_check_var(var, itv); -} - -static int ivtvfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) -{ - u32 osd_pan_index; - struct ivtv *itv = (struct ivtv *) info->par; - - osd_pan_index = (var->xoffset + (var->yoffset * var->xres_virtual))*var->bits_per_pixel/8; - write_reg(osd_pan_index, 0x02A0C); - - /* Pass this info back the yuv handler */ - itv->yuv_info.osd_x_pan = var->xoffset; - itv->yuv_info.osd_y_pan = var->yoffset; - /* Force update of yuv registers */ - itv->yuv_info.yuv_forced_update = 1; - return 0; -} - -static int ivtvfb_set_par(struct fb_info *info) -{ - int rc = 0; - struct ivtv *itv = (struct ivtv *) info->par; - - IVTV_FB_DEBUG_INFO("ivtvfb_set_par\n"); - - rc = ivtvfb_set_var(itv, &info->var); - ivtvfb_pan_display(&info->var, info); - ivtvfb_get_fix(itv, &info->fix); - return rc; -} - -static int ivtvfb_setcolreg(unsigned regno, unsigned red, unsigned green, - unsigned blue, unsigned transp, - struct fb_info *info) -{ - u32 color, *palette; - struct ivtv *itv = (struct ivtv *)info->par; - - if (regno >= info->cmap.len) - return -EINVAL; - - color = ((transp & 0xFF00) << 16) |((red & 0xFF00) << 8) | (green & 0xFF00) | ((blue & 0xFF00) >> 8); - if (info->var.bits_per_pixel <= 8) { - write_reg(regno, 0x02a30); - write_reg(color, 0x02a34); - return 0; - } - if (regno >= 16) - return -EINVAL; - - palette = info->pseudo_palette; - if (info->var.bits_per_pixel == 16) { - switch (info->var.green.length) { - case 4: - color = ((red & 0xf000) >> 4) | - ((green & 0xf000) >> 8) | - ((blue & 0xf000) >> 12); - break; - case 5: - color = ((red & 0xf800) >> 1) | - ((green & 0xf800) >> 6) | - ((blue & 0xf800) >> 11); - break; - case 6: - color = (red & 0xf800 ) | - ((green & 0xfc00) >> 5) | - ((blue & 0xf800) >> 11); - break; - } - } - palette[regno] = color; - return 0; -} - -/* We don't really support blanking. All this does is enable or - disable the OSD. */ -static int ivtvfb_blank(int blank_mode, struct fb_info *info) -{ - struct ivtv *itv = (struct ivtv *)info->par; - - IVTV_FB_DEBUG_INFO("Set blanking mode : %d\n", blank_mode); - switch (blank_mode) { - case FB_BLANK_UNBLANK: - ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 1); - break; - case FB_BLANK_NORMAL: - case FB_BLANK_HSYNC_SUSPEND: - case FB_BLANK_VSYNC_SUSPEND: - case FB_BLANK_POWERDOWN: - ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0); - break; - } - return 0; -} - -static struct fb_ops ivtvfb_ops = { - .owner = THIS_MODULE, - .fb_check_var = ivtvfb_check_var, - .fb_set_par = ivtvfb_set_par, - .fb_setcolreg = ivtvfb_setcolreg, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, - .fb_cursor = NULL, - .fb_ioctl = ivtvfb_ioctl, - .fb_pan_display = ivtvfb_pan_display, - .fb_blank = ivtvfb_blank, -}; - -/* Initialization */ - - -/* Setup our initial video mode */ -static int ivtvfb_init_vidmode(struct ivtv *itv) -{ - struct osd_info *oi = itv->osd_info; - struct v4l2_rect start_window; - int max_height; - - /* Color mode */ - - if (osd_compat) osd_depth = 32; - if (osd_depth != 8 && osd_depth != 16 && osd_depth != 32) osd_depth = 8; - oi->bits_per_pixel = osd_depth; - oi->bytes_per_pixel = oi->bits_per_pixel / 8; - - /* Invalidate current osd mode to force a mode switch later */ - oi->osd_mode = -1; - - /* Horizontal size & position */ - - if (osd_xres > 720) osd_xres = 720; - - /* Must be a multiple of 4 for 8bpp & 2 for 16bpp */ - if (osd_depth == 8) - osd_xres &= ~3; - else if (osd_depth == 16) - osd_xres &= ~1; - - if (osd_xres) - start_window.width = osd_xres; - else - start_window.width = osd_compat ? 720: 640; - - /* Check horizontal start (osd_left). */ - if (osd_left && osd_left + start_window.width > 721) { - IVTV_FB_ERR("Invalid osd_left - assuming default\n"); - osd_left = 0; - } - - /* Hardware coords start at 0, user coords start at 1. */ - osd_left--; - - start_window.left = osd_left >= 0 ? osd_left : ((IVTV_OSD_MAX_WIDTH - start_window.width) / 2); - - oi->display_byte_stride = - start_window.width * oi->bytes_per_pixel; - - /* Vertical size & position */ - - max_height = itv->is_50hz ? 576 : 480; - - if (osd_yres > max_height) - osd_yres = max_height; - - if (osd_yres) - start_window.height = osd_yres; - else - start_window.height = osd_compat ? max_height : (itv->is_50hz ? 480 : 400); - - /* Check vertical start (osd_upper). */ - if (osd_upper + start_window.height > max_height + 1) { - IVTV_FB_ERR("Invalid osd_upper - assuming default\n"); - osd_upper = 0; - } - - /* Hardware coords start at 0, user coords start at 1. */ - osd_upper--; - - start_window.top = osd_upper >= 0 ? osd_upper : ((max_height - start_window.height) / 2); - - oi->display_width = start_window.width; - oi->display_height = start_window.height; - - /* Generate a valid fb_var_screeninfo */ - - oi->ivtvfb_defined.xres = oi->display_width; - oi->ivtvfb_defined.yres = oi->display_height; - oi->ivtvfb_defined.xres_virtual = oi->display_width; - oi->ivtvfb_defined.yres_virtual = oi->display_height; - oi->ivtvfb_defined.bits_per_pixel = oi->bits_per_pixel; - oi->ivtvfb_defined.vmode = (osd_laced ? FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED); - oi->ivtvfb_defined.left_margin = start_window.left + 1; - oi->ivtvfb_defined.upper_margin = start_window.top + 1; - oi->ivtvfb_defined.accel_flags = FB_ACCEL_NONE; - oi->ivtvfb_defined.nonstd = 0; - - /* We've filled in the most data, let the usual mode check - routine fill in the rest. */ - _ivtvfb_check_var(&oi->ivtvfb_defined, itv); - - /* Generate valid fb_fix_screeninfo */ - - ivtvfb_get_fix(itv, &oi->ivtvfb_fix); - - /* Generate valid fb_info */ - - oi->ivtvfb_info.node = -1; - oi->ivtvfb_info.flags = FBINFO_FLAG_DEFAULT; - oi->ivtvfb_info.fbops = &ivtvfb_ops; - oi->ivtvfb_info.par = itv; - oi->ivtvfb_info.var = oi->ivtvfb_defined; - oi->ivtvfb_info.fix = oi->ivtvfb_fix; - oi->ivtvfb_info.screen_base = (u8 __iomem *)oi->video_vbase; - oi->ivtvfb_info.fbops = &ivtvfb_ops; - - /* Supply some monitor specs. Bogus values will do for now */ - oi->ivtvfb_info.monspecs.hfmin = 8000; - oi->ivtvfb_info.monspecs.hfmax = 70000; - oi->ivtvfb_info.monspecs.vfmin = 10; - oi->ivtvfb_info.monspecs.vfmax = 100; - - /* Allocate color map */ - if (fb_alloc_cmap(&oi->ivtvfb_info.cmap, 256, 1)) { - IVTV_FB_ERR("abort, unable to alloc cmap\n"); - return -ENOMEM; - } - - /* Allocate the pseudo palette */ - oi->ivtvfb_info.pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL); - - if (!oi->ivtvfb_info.pseudo_palette) { - IVTV_FB_ERR("abort, unable to alloc pseudo pallete\n"); - return -ENOMEM; - } - - return 0; -} - -/* Find OSD buffer base & size. Add to mtrr. Zero osd buffer. */ - -static int ivtvfb_init_io(struct ivtv *itv) -{ - struct osd_info *oi = itv->osd_info; - - mutex_lock(&itv->serialize_lock); - if (ivtv_init_on_first_open(itv)) { - mutex_unlock(&itv->serialize_lock); - IVTV_FB_ERR("Failed to initialize ivtv\n"); - return -ENXIO; - } - mutex_unlock(&itv->serialize_lock); - - ivtv_fb_get_framebuffer(itv, &oi->video_rbase, &oi->video_buffer_size); - - /* The osd buffer size depends on the number of video buffers allocated - on the PVR350 itself. For now we'll hardcode the smallest osd buffer - size to prevent any overlap. */ - oi->video_buffer_size = 1704960; - - oi->video_pbase = itv->base_addr + IVTV_DECODER_OFFSET + oi->video_rbase; - oi->video_vbase = itv->dec_mem + oi->video_rbase; - - if (!oi->video_vbase) { - IVTV_FB_ERR("abort, video memory 0x%x @ 0x%lx isn't mapped!\n", - oi->video_buffer_size, oi->video_pbase); - return -EIO; - } - - IVTV_FB_INFO("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n", - oi->video_pbase, oi->video_vbase, - oi->video_buffer_size / 1024); - -#ifdef CONFIG_MTRR - { - /* Find the largest power of two that maps the whole buffer */ - int size_shift = 31; - - while (!(oi->video_buffer_size & (1 << size_shift))) { - size_shift--; - } - size_shift++; - oi->fb_start_aligned_physaddr = oi->video_pbase & ~((1 << size_shift) - 1); - oi->fb_end_aligned_physaddr = oi->video_pbase + oi->video_buffer_size; - oi->fb_end_aligned_physaddr += (1 << size_shift) - 1; - oi->fb_end_aligned_physaddr &= ~((1 << size_shift) - 1); - if (mtrr_add(oi->fb_start_aligned_physaddr, - oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr, - MTRR_TYPE_WRCOMB, 1) < 0) { - IVTV_FB_WARN("cannot use mttr\n"); - oi->fb_start_aligned_physaddr = 0; - oi->fb_end_aligned_physaddr = 0; - } - } -#endif - - /* Blank the entire osd. */ - memset_io(oi->video_vbase, 0, oi->video_buffer_size); - - return 0; -} - -/* Release any memory we've grabbed & remove mtrr entry */ -static void ivtvfb_release_buffers (struct ivtv *itv) -{ - struct osd_info *oi = itv->osd_info; - - /* Release cmap */ - if (oi->ivtvfb_info.cmap.len); - fb_dealloc_cmap(&oi->ivtvfb_info.cmap); - - /* Release pseudo palette */ - if (oi->ivtvfb_info.pseudo_palette) - kfree(oi->ivtvfb_info.pseudo_palette); - -#ifdef CONFIG_MTRR - if (oi->fb_end_aligned_physaddr) { - mtrr_del(-1, oi->fb_start_aligned_physaddr, - oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr); - } -#endif - - kfree(oi); - itv->osd_info = NULL; -} - -/* Initialize the specified card */ - -static int ivtvfb_init_card(struct ivtv *itv) -{ - int rc; - - if (itv->osd_info) { - IVTV_FB_ERR("Card %d already initialised\n", ivtv_fb_card_id); - return -EBUSY; - } - - itv->osd_info = kzalloc(sizeof(struct osd_info), GFP_ATOMIC); - if (itv->osd_info == 0) { - IVTV_FB_ERR("Failed to allocate memory for osd_info\n"); - return -ENOMEM; - } - - /* Find & setup the OSD buffer */ - if ((rc = ivtvfb_init_io(itv))) - return rc; - - /* Set the startup video mode information */ - if ((rc = ivtvfb_init_vidmode(itv))) { - ivtvfb_release_buffers(itv); - return rc; - } - - /* Register the framebuffer */ - if (register_framebuffer(&itv->osd_info->ivtvfb_info) < 0) { - ivtvfb_release_buffers(itv); - return -EINVAL; - } - - itv->osd_video_pbase = itv->osd_info->video_pbase; - - /* Set the card to the requested mode */ - ivtvfb_set_par(&itv->osd_info->ivtvfb_info); - - /* Set color 0 to black */ - write_reg(0, 0x02a30); - write_reg(0, 0x02a34); - - /* Enable the osd */ - ivtvfb_blank(FB_BLANK_UNBLANK, &itv->osd_info->ivtvfb_info); - - /* Note if we're running in compatibility mode */ - if (osd_compat) - IVTV_FB_INFO("Running in compatibility mode. Display resize & mode change disabled\n"); - - /* Allocate DMA */ - ivtv_udma_alloc(itv); - return 0; - -} - -static int __init ivtvfb_init(void) -{ - struct ivtv *itv; - int i, registered = 0; - - if (ivtv_fb_card_id < -1 || ivtv_fb_card_id >= IVTV_MAX_CARDS) { - printk(KERN_ERR "ivtv-fb: ivtv_fb_card_id parameter is out of range (valid range: -1 - %d)\n", - IVTV_MAX_CARDS - 1); - return -EINVAL; - } - - /* Locate & initialise all cards supporting an OSD. */ - for (i = 0; i < ivtv_cards_active; i++) { - if (ivtv_fb_card_id != -1 && i != ivtv_fb_card_id) - continue; - itv = ivtv_cards[i]; - if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) { - if (ivtvfb_init_card(itv) == 0) { - IVTV_FB_INFO("Framebuffer registered on ivtv card id %d\n", i); - registered++; - } - } - } - if (!registered) { - printk(KERN_ERR "ivtv-fb: no cards found"); - return -ENODEV; - } - return 0; -} - -static void ivtvfb_cleanup(void) -{ - struct ivtv *itv; - int i; - - printk(KERN_INFO "ivtv-fb: Unloading framebuffer module\n"); - - for (i = 0; i < ivtv_cards_active; i++) { - itv = ivtv_cards[i]; - if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) && itv->osd_info) { - IVTV_FB_DEBUG_INFO("Unregister framebuffer %d\n", i); - ivtvfb_blank(FB_BLANK_POWERDOWN, &itv->osd_info->ivtvfb_info); - unregister_framebuffer(&itv->osd_info->ivtvfb_info); - ivtvfb_release_buffers(itv); - itv->osd_video_pbase = 0; - } - } -} - -module_init(ivtvfb_init); -module_exit(ivtvfb_cleanup); diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c new file mode 100644 index 00000000000..ff721c08847 --- /dev/null +++ b/drivers/media/video/ivtv/ivtvfb.c @@ -0,0 +1,1190 @@ +/* + On Screen Display cx23415 Framebuffer driver + + This module presents the cx23415 OSD (onscreen display) framebuffer memory + as a standard Linux /dev/fb style framebuffer device. The framebuffer has + support for 8, 16 & 32 bpp packed pixel formats with alpha channel. In 16bpp + mode, there is a choice of a three color depths (12, 15 or 16 bits), but no + local alpha. The colorspace is selectable between rgb & yuv. + Depending on the TV standard configured in the ivtv module at load time, + the initial resolution is either 640x400 (NTSC) or 640x480 (PAL) at 8bpp. + Video timings are locked to ensure a vertical refresh rate of 50Hz (PAL) + or 59.94 (NTSC) + + Copyright (c) 2003 Matt T. Yourst + + Derived from drivers/video/vesafb.c + Portions (c) 1998 Gerd Knorr + + 2.6 kernel port: + Copyright (C) 2004 Matthias Badaire + + Copyright (C) 2004 Chris Kennedy + + Copyright (C) 2006 Ian Armstrong + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include + +#ifdef CONFIG_MTRR +#include +#endif + +#include "ivtv-driver.h" +#include "ivtv-udma.h" +#include "ivtv-mailbox.h" + +/* card parameters */ +static int ivtv_fb_card_id = -1; +static int ivtv_fb_debug = 0; +static int osd_laced; +static int osd_compat; +static int osd_depth; +static int osd_upper; +static int osd_left; +static int osd_yres; +static int osd_xres; + +module_param(ivtv_fb_card_id, int, 0444); +module_param_named(debug,ivtv_fb_debug, int, 0644); +module_param(osd_laced, bool, 0444); +module_param(osd_compat, bool, 0444); +module_param(osd_depth, int, 0444); +module_param(osd_upper, int, 0444); +module_param(osd_left, int, 0444); +module_param(osd_yres, int, 0444); +module_param(osd_xres, int, 0444); + +MODULE_PARM_DESC(ivtv_fb_card_id, + "Only use framebuffer of the specified ivtv card (0-31)\n" + "\t\t\tdefault -1: initialize all available framebuffers"); + +MODULE_PARM_DESC(debug, + "Debug level (bitmask). Default: errors only\n" + "\t\t\t(debug = 3 gives full debugging)"); + +MODULE_PARM_DESC(osd_compat, + "Compatibility mode - Display size is locked (use for old X drivers)\n" + "\t\t\t0=off\n" + "\t\t\t1=on\n" + "\t\t\tdefault off"); + +/* Why upper, left, xres, yres, depth, laced ? To match terminology used + by fbset. + Why start at 1 for left & upper coordinate ? Because X doesn't allow 0 */ + +MODULE_PARM_DESC(osd_laced, + "Interlaced mode\n" + "\t\t\t0=off\n" + "\t\t\t1=on\n" + "\t\t\tdefault off"); + +MODULE_PARM_DESC(osd_depth, + "Bits per pixel - 8, 16, 32\n" + "\t\t\tdefault 8"); + +MODULE_PARM_DESC(osd_upper, + "Vertical start position\n" + "\t\t\tdefault 0 (Centered)"); + +MODULE_PARM_DESC(osd_left, + "Horizontal start position\n" + "\t\t\tdefault 0 (Centered)"); + +MODULE_PARM_DESC(osd_yres, + "Display height\n" + "\t\t\tdefault 480 (PAL)\n" + "\t\t\t 400 (NTSC)"); + +MODULE_PARM_DESC(osd_xres, + "Display width\n" + "\t\t\tdefault 640"); + +MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil, John Harvey, Ian Armstrong"); +MODULE_LICENSE("GPL"); + +/* --------------------------------------------------------------------- */ + +#define IVTV_FB_DBGFLG_WARN (1 << 0) +#define IVTV_FB_DBGFLG_INFO (1 << 1) + +#define IVTV_FB_DEBUG(x, type, fmt, args...) \ + do { \ + if ((x) & ivtv_fb_debug) \ + printk(KERN_INFO "ivtv-fb%d " type ": " fmt, itv->num , ## args); \ + } while (0) +#define IVTV_FB_DEBUG_WARN(fmt, args...) IVTV_FB_DEBUG(IVTV_FB_DBGFLG_WARN, "warning", fmt , ## args) +#define IVTV_FB_DEBUG_INFO(fmt, args...) IVTV_FB_DEBUG(IVTV_FB_DBGFLG_INFO, "info", fmt , ## args) + +/* Standard kernel messages */ +#define IVTV_FB_ERR(fmt, args...) printk(KERN_ERR "ivtv-fb%d: " fmt, itv->num , ## args) +#define IVTV_FB_WARN(fmt, args...) printk(KERN_WARNING "ivtv-fb%d: " fmt, itv->num , ## args) +#define IVTV_FB_INFO(fmt, args...) printk(KERN_INFO "ivtv-fb%d: " fmt, itv->num , ## args) + +/* --------------------------------------------------------------------- */ + +#define IVTV_OSD_MAX_WIDTH 720 +#define IVTV_OSD_MAX_HEIGHT 576 + +#define IVTV_OSD_BPP_8 0x00 +#define IVTV_OSD_BPP_16_444 0x03 +#define IVTV_OSD_BPP_16_555 0x02 +#define IVTV_OSD_BPP_16_565 0x01 +#define IVTV_OSD_BPP_32 0x04 + +struct osd_info { + /* Physical base address */ + unsigned long video_pbase; + /* Relative base address (relative to start of decoder memory) */ + u32 video_rbase; + /* Mapped base address */ + volatile char __iomem *video_vbase; + /* Buffer size */ + u32 video_buffer_size; + +#ifdef CONFIG_MTRR + /* video_base rounded down as required by hardware MTRRs */ + unsigned long fb_start_aligned_physaddr; + /* video_base rounded up as required by hardware MTRRs */ + unsigned long fb_end_aligned_physaddr; +#endif + + /* Current osd mode */ + int osd_mode; + + /* Store the buffer offset */ + int set_osd_coords_x; + int set_osd_coords_y; + + /* Current dimensions (NOT VISIBLE SIZE!) */ + int display_width; + int display_height; + int display_byte_stride; + + /* Current bits per pixel */ + int bits_per_pixel; + int bytes_per_pixel; + + /* Frame buffer stuff */ + struct fb_info ivtvfb_info; + struct fb_var_screeninfo ivtvfb_defined; + struct fb_fix_screeninfo ivtvfb_fix; +}; + +struct ivtv_osd_coords { + unsigned long offset; + unsigned long max_offset; + int pixel_stride; + int lines; + int x; + int y; +}; + +/* --------------------------------------------------------------------- */ + +/* ivtv API calls for framebuffer related support */ + +static int ivtv_fb_get_framebuffer(struct ivtv *itv, u32 *fbbase, + u32 *fblength) +{ + u32 data[CX2341X_MBOX_MAX_DATA]; + int rc; + + rc = ivtv_vapi_result(itv, data, CX2341X_OSD_GET_FRAMEBUFFER, 0); + *fbbase = data[0]; + *fblength = data[1]; + return rc; +} + +static int ivtv_fb_get_osd_coords(struct ivtv *itv, + struct ivtv_osd_coords *osd) +{ + struct osd_info *oi = itv->osd_info; + u32 data[CX2341X_MBOX_MAX_DATA]; + + ivtv_vapi_result(itv, data, CX2341X_OSD_GET_OSD_COORDS, 0); + + osd->offset = data[0] - oi->video_rbase; + osd->max_offset = oi->display_width * oi->display_height * 4; + osd->pixel_stride = data[1]; + osd->lines = data[2]; + osd->x = data[3]; + osd->y = data[4]; + return 0; +} + +static int ivtv_fb_set_osd_coords(struct ivtv *itv, const struct ivtv_osd_coords *osd) +{ + struct osd_info *oi = itv->osd_info; + + oi->display_width = osd->pixel_stride; + oi->display_byte_stride = osd->pixel_stride * oi->bytes_per_pixel; + oi->set_osd_coords_x += osd->x; + oi->set_osd_coords_y = osd->y; + + return ivtv_vapi(itv, CX2341X_OSD_SET_OSD_COORDS, 5, + osd->offset + oi->video_rbase, + osd->pixel_stride, + osd->lines, osd->x, osd->y); +} + +static int ivtv_fb_set_display_window(struct ivtv *itv, struct v4l2_rect *ivtv_window) +{ + int osd_height_limit = itv->is_50hz ? 576 : 480; + + /* Only fail if resolution too high, otherwise fudge the start coords. */ + if ((ivtv_window->height > osd_height_limit) || (ivtv_window->width > IVTV_OSD_MAX_WIDTH)) + return -EINVAL; + + /* Ensure we don't exceed display limits */ + if (ivtv_window->top + ivtv_window->height > osd_height_limit) { + IVTV_FB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid height setting (%d, %d)\n", + ivtv_window->top, ivtv_window->height); + ivtv_window->top = osd_height_limit - ivtv_window->height; + } + + if (ivtv_window->left + ivtv_window->width > IVTV_OSD_MAX_WIDTH) { + IVTV_FB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid width setting (%d, %d)\n", + ivtv_window->left, ivtv_window->width); + ivtv_window->left = IVTV_OSD_MAX_WIDTH - ivtv_window->width; + } + + /* Set the OSD origin */ + write_reg((ivtv_window->top << 16) | ivtv_window->left, 0x02a04); + + /* How much to display */ + write_reg(((ivtv_window->top+ivtv_window->height) << 16) | (ivtv_window->left+ivtv_window->width), 0x02a08); + + /* Pass this info back the yuv handler */ + itv->yuv_info.osd_vis_w = ivtv_window->width; + itv->yuv_info.osd_vis_h = ivtv_window->height; + itv->yuv_info.osd_x_offset = ivtv_window->left; + itv->yuv_info.osd_y_offset = ivtv_window->top; + + return 0; +} + +static int ivtv_fb_prep_dec_dma_to_device(struct ivtv *itv, + unsigned long ivtv_dest_addr, void __user *userbuf, + int size_in_bytes) +{ + DEFINE_WAIT(wait); + int ret = 0; + int got_sig = 0; + + mutex_lock(&itv->udma.lock); + /* Map User DMA */ + if (ivtv_udma_setup(itv, ivtv_dest_addr, userbuf, size_in_bytes) <= 0) { + mutex_unlock(&itv->udma.lock); + IVTV_FB_WARN("ivtvfb_prep_dec_dma_to_device, " + "Error with get_user_pages: %d bytes, %d pages returned\n", + size_in_bytes, itv->udma.page_count); + + /* get_user_pages must have failed completely */ + return -EIO; + } + + IVTV_FB_DEBUG_INFO("ivtvfb_prep_dec_dma_to_device, %d bytes, %d pages\n", + size_in_bytes, itv->udma.page_count); + + ivtv_udma_prepare(itv); + prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE); + /* if no UDMA is pending and no UDMA is in progress, then the DMA + is finished */ + while (itv->i_flags & (IVTV_F_I_UDMA_PENDING | IVTV_F_I_UDMA)) { + /* don't interrupt if the DMA is in progress but break off + a still pending DMA. */ + got_sig = signal_pending(current); + if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags)) + break; + got_sig = 0; + schedule(); + } + finish_wait(&itv->dma_waitq, &wait); + + /* Unmap Last DMA Xfer */ + ivtv_udma_unmap(itv); + mutex_unlock(&itv->udma.lock); + if (got_sig) { + IVTV_DEBUG_INFO("User stopped OSD\n"); + return -EINTR; + } + + return ret; +} + +static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source, + unsigned long dest_offset, int count) +{ + DEFINE_WAIT(wait); + struct osd_info *oi = itv->osd_info; + + /* Nothing to do */ + if (count == 0) { + IVTV_FB_DEBUG_WARN("ivtv_fb_prep_frame: Nothing to do. count = 0\n"); + return -EINVAL; + } + + /* Check Total FB Size */ + if ((dest_offset + count) > oi->video_buffer_size) { + IVTV_FB_WARN("ivtv_fb_prep_frame: Overflowing the framebuffer %ld, only %d available\n", + dest_offset + count, oi->video_buffer_size); + return -E2BIG; + } + + /* Not fatal, but will have undesirable results */ + if ((unsigned long)source & 3) + IVTV_FB_WARN("ivtv_fb_prep_frame: Source address not 32 bit aligned (0x%08lx)\n", + (unsigned long)source); + + if (dest_offset & 3) + IVTV_FB_WARN("ivtv_fb_prep_frame: Dest offset not 32 bit aligned (%ld)\n", dest_offset); + + if (count & 3) + IVTV_FB_WARN("ivtv_fb_prep_frame: Count not a multiple of 4 (%d)\n", count); + + /* Check Source */ + if (!access_ok(VERIFY_READ, source + dest_offset, count)) { + IVTV_FB_WARN("Invalid userspace pointer 0x%08lx\n", + (unsigned long)source); + + IVTV_FB_DEBUG_WARN("access_ok() failed for offset 0x%08lx source 0x%08lx count %d\n", + dest_offset, (unsigned long)source, + count); + return -EINVAL; + } + + /* OSD Address to send DMA to */ + dest_offset += IVTV_DECODER_OFFSET + oi->video_rbase; + + /* Fill Buffers */ + return ivtv_fb_prep_dec_dma_to_device(itv, dest_offset, source, count); +} + +static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) +{ + DEFINE_WAIT(wait); + struct ivtv *itv = (struct ivtv *)info->par; + int rc = 0; + + switch (cmd) { + case FBIOGET_VBLANK: { + struct fb_vblank vblank; + u32 trace; + + vblank.flags = FB_VBLANK_HAVE_COUNT |FB_VBLANK_HAVE_VCOUNT | + FB_VBLANK_HAVE_VSYNC; + trace = read_reg(0x028c0) >> 16; + if (itv->is_50hz && trace > 312) trace -= 312; + else if (itv->is_60hz && trace > 262) trace -= 262; + if (trace == 1) vblank.flags |= FB_VBLANK_VSYNCING; + vblank.count = itv->last_vsync_field; + vblank.vcount = trace; + vblank.hcount = 0; + if (copy_to_user((void __user *)arg, &vblank, sizeof(vblank))) + return -EFAULT; + return 0; + } + + case FBIO_WAITFORVSYNC: + prepare_to_wait(&itv->vsync_waitq, &wait, TASK_INTERRUPTIBLE); + if (!schedule_timeout(msecs_to_jiffies(50))) rc = -ETIMEDOUT; + finish_wait(&itv->vsync_waitq, &wait); + return rc; + + case IVTVFB_IOC_DMA_FRAME: { + struct ivtvfb_dma_frame args; + + IVTV_FB_DEBUG_INFO("IVTVFB_IOC_DMA_FRAME\n"); + if (copy_from_user(&args, (void __user *)arg, sizeof(args))) + return -EFAULT; + + return ivtv_fb_prep_frame(itv, cmd, args.source, args.dest_offset, args.count); + } + + default: + IVTV_FB_DEBUG_INFO("Unknown ioctl %08x\n", cmd); + return -EINVAL; + } + return 0; +} + +/* Framebuffer device handling */ + +static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var) +{ + struct osd_info *oi = itv->osd_info; + struct ivtv_osd_coords ivtv_osd; + struct v4l2_rect ivtv_window; + int osd_mode = -1; + + IVTV_FB_DEBUG_INFO("ivtvfb_set_var\n"); + + /* Select color space */ + if (var->nonstd) /* YUV */ + write_reg(read_reg(0x02a00) | 0x0002000, 0x02a00); + else /* RGB */ + write_reg(read_reg(0x02a00) & ~0x0002000, 0x02a00); + + /* Set the color mode */ + switch (var->bits_per_pixel) { + case 8: + osd_mode = IVTV_OSD_BPP_8; + break; + case 32: + osd_mode = IVTV_OSD_BPP_32; + break; + case 16: + switch (var->green.length) { + case 4: + osd_mode = IVTV_OSD_BPP_16_444; + break; + case 5: + osd_mode = IVTV_OSD_BPP_16_555; + break; + case 6: + osd_mode = IVTV_OSD_BPP_16_565; + break; + default: + IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n"); + } + break; + default: + IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n"); + } + + /* Change osd mode if needed. + Although rare, things can go wrong. The extra mode + change seems to help... */ + if (osd_mode != -1 && osd_mode != oi->osd_mode) { + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0); + ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, osd_mode); + oi->osd_mode = osd_mode; + } + + oi->bits_per_pixel = var->bits_per_pixel; + oi->bytes_per_pixel = var->bits_per_pixel / 8; + + /* Set the flicker filter */ + switch (var->vmode & FB_VMODE_MASK) { + case FB_VMODE_NONINTERLACED: /* Filter on */ + ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 1); + break; + case FB_VMODE_INTERLACED: /* Filter off */ + ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 0); + break; + default: + IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid video mode\n"); + } + + /* Read the current osd info */ + ivtv_fb_get_osd_coords(itv, &ivtv_osd); + + /* Now set the OSD to the size we want */ + ivtv_osd.pixel_stride = var->xres_virtual; + ivtv_osd.lines = var->yres_virtual; + ivtv_osd.x = 0; + ivtv_osd.y = 0; + ivtv_fb_set_osd_coords(itv, &ivtv_osd); + + /* Can't seem to find the right API combo for this. + Use another function which does what we need through direct register access. */ + ivtv_window.width = var->xres; + ivtv_window.height = var->yres; + + /* Minimum margin cannot be 0, as X won't allow such a mode */ + if (!var->upper_margin) var->upper_margin++; + if (!var->left_margin) var->left_margin++; + ivtv_window.top = var->upper_margin - 1; + ivtv_window.left = var->left_margin - 1; + + ivtv_fb_set_display_window(itv, &ivtv_window); + + /* Force update of yuv registers */ + itv->yuv_info.yuv_forced_update = 1; + + IVTV_FB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n", + var->xres, var->yres, + var->xres_virtual, var->yres_virtual, + var->bits_per_pixel); + + IVTV_FB_DEBUG_INFO("Display position: %d, %d\n", + var->left_margin, var->upper_margin); + + IVTV_FB_DEBUG_INFO("Display filter: %s\n", + (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off"); + IVTV_FB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB"); + + return 0; +} + +static int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix) +{ + struct osd_info *oi = itv->osd_info; + + IVTV_FB_DEBUG_INFO("ivtvfb_get_fix\n"); + memset(fix, 0, sizeof(struct fb_fix_screeninfo)); + strcpy(fix->id, "cx23415 TV out"); + fix->smem_start = oi->video_pbase; + fix->smem_len = oi->video_buffer_size; + fix->type = FB_TYPE_PACKED_PIXELS; + fix->visual = (oi->bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; + fix->xpanstep = 1; + fix->ypanstep = 1; + fix->ywrapstep = 0; + fix->line_length = oi->display_byte_stride; + fix->accel = FB_ACCEL_NONE; + return 0; +} + +/* Check the requested display mode, returning -EINVAL if we can't + handle it. */ + +static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) +{ + struct osd_info *oi = itv->osd_info; + int osd_height_limit; + u32 pixclock, hlimit, vlimit; + + IVTV_FB_DEBUG_INFO("ivtvfb_check_var\n"); + + /* Set base references for mode calcs. */ + if (itv->is_50hz) { + pixclock = 84316; + hlimit = 776; + vlimit = 591; + osd_height_limit = 576; + } + else { + pixclock = 83926; + hlimit = 776; + vlimit = 495; + osd_height_limit = 480; + } + + /* Check the bits per pixel */ + if (osd_compat) { + if (var->bits_per_pixel != 32) { + IVTV_FB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel); + return -EINVAL; + } + } + + if (var->bits_per_pixel == 8 || var->bits_per_pixel == 32) { + var->transp.offset = 24; + var->transp.length = 8; + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + } + else if (var->bits_per_pixel == 16) { + /* To find out the true mode, check green length */ + switch (var->green.length) { + case 4: + var->red.offset = 8; + var->red.length = 4; + var->green.offset = 4; + var->green.length = 4; + var->blue.offset = 0; + var->blue.length = 4; + var->transp.offset = 12; + var->transp.length = 1; + break; + case 5: + var->red.offset = 10; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 5; + var->blue.offset = 0; + var->blue.length = 5; + var->transp.offset = 15; + var->transp.length = 1; + break; + default: + var->red.offset = 11; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.offset = 0; + var->blue.length = 5; + var->transp.offset = 0; + var->transp.length = 0; + break; + } + } + else { + IVTV_FB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel); + return -EINVAL; + } + + /* Check the resolution */ + if (osd_compat) { + if (var->xres != oi->ivtvfb_defined.xres || + var->yres != oi->ivtvfb_defined.yres || + var->xres_virtual != oi->ivtvfb_defined.xres_virtual || + var->yres_virtual != oi->ivtvfb_defined.yres_virtual) { + IVTV_FB_DEBUG_WARN("Invalid resolution: %dx%d (virtual %dx%d)\n", + var->xres, var->yres, var->xres_virtual, var->yres_virtual); + return -EINVAL; + } + } + else { + if (var->xres > IVTV_OSD_MAX_WIDTH || var->yres > osd_height_limit) { + IVTV_FB_DEBUG_WARN("Invalid resolution: %dx%d\n", + var->xres, var->yres); + return -EINVAL; + } + + /* Max horizontal size is 1023 @ 32bpp, 2046 & 16bpp, 4092 @ 8bpp */ + if (var->xres_virtual > 4095 / (var->bits_per_pixel / 8) || + var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8) > oi->video_buffer_size || + var->xres_virtual < var->xres || + var->yres_virtual < var->yres) { + IVTV_FB_DEBUG_WARN("Invalid virtual resolution: %dx%d\n", + var->xres_virtual, var->yres_virtual); + return -EINVAL; + } + } + + /* Some extra checks if in 8 bit mode */ + if (var->bits_per_pixel == 8) { + /* Width must be a multiple of 4 */ + if (var->xres & 3) { + IVTV_FB_DEBUG_WARN("Invalid resolution for 8bpp: %d\n", var->xres); + return -EINVAL; + } + if (var->xres_virtual & 3) { + IVTV_FB_DEBUG_WARN("Invalid virtual resolution for 8bpp: %d)\n", var->xres_virtual); + return -EINVAL; + } + } + else if (var->bits_per_pixel == 16) { + /* Width must be a multiple of 2 */ + if (var->xres & 1) { + IVTV_FB_DEBUG_WARN("Invalid resolution for 16bpp: %d\n", var->xres); + return -EINVAL; + } + if (var->xres_virtual & 1) { + IVTV_FB_DEBUG_WARN("Invalid virtual resolution for 16bpp: %d)\n", var->xres_virtual); + return -EINVAL; + } + } + + /* Now check the offsets */ + if (var->xoffset >= var->xres_virtual || var->yoffset >= var->yres_virtual) { + IVTV_FB_DEBUG_WARN("Invalid offset: %d (%d) %d (%d)\n", + var->xoffset, var->xres_virtual, var->yoffset, var->yres_virtual); + return -EINVAL; + } + + /* Check pixel format */ + if (var->nonstd > 1) { + IVTV_FB_DEBUG_WARN("Invalid nonstd % d\n", var->nonstd); + return -EINVAL; + } + + /* Check video mode */ + if (((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) && + ((var->vmode & FB_VMODE_MASK) != FB_VMODE_INTERLACED)) { + IVTV_FB_DEBUG_WARN("Invalid video mode: %d\n", var->vmode & FB_VMODE_MASK); + return -EINVAL; + } + + /* Check the left & upper margins + If the margins are too large, just center the screen + (enforcing margins causes too many problems) */ + + if (var->left_margin + var->xres > IVTV_OSD_MAX_WIDTH + 1) { + var->left_margin = 1 + ((IVTV_OSD_MAX_WIDTH - var->xres) / 2); + } + if (var->upper_margin + var->yres > (itv->is_50hz ? 577 : 481)) { + var->upper_margin = 1 + (((itv->is_50hz ? 576 : 480) - var->yres) / 2); + } + + /* Maintain overall 'size' for a constant refresh rate */ + var->right_margin = hlimit - var->left_margin - var->xres; + var->lower_margin = vlimit - var->upper_margin - var->yres; + + /* Fixed sync times */ + var->hsync_len = 24; + var->vsync_len = 2; + + /* Non-interlaced / interlaced mode is used to switch the OSD filter + on or off. Adjust the clock timings to maintain a constant + vertical refresh rate. */ + if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) + var->pixclock = pixclock / 2; + else + var->pixclock = pixclock; + + IVTV_FB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n", + var->xres, var->yres, + var->xres_virtual, var->yres_virtual, + var->bits_per_pixel); + + IVTV_FB_DEBUG_INFO("Display position: %d, %d\n", + var->left_margin, var->upper_margin); + + IVTV_FB_DEBUG_INFO("Display filter: %s\n", + (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off"); + IVTV_FB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB"); + return 0; +} + +static int ivtvfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct ivtv *itv = (struct ivtv *) info->par; + IVTV_FB_DEBUG_INFO("ivtvfb_check_var\n"); + return _ivtvfb_check_var(var, itv); +} + +static int ivtvfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) +{ + u32 osd_pan_index; + struct ivtv *itv = (struct ivtv *) info->par; + + osd_pan_index = (var->xoffset + (var->yoffset * var->xres_virtual))*var->bits_per_pixel/8; + write_reg(osd_pan_index, 0x02A0C); + + /* Pass this info back the yuv handler */ + itv->yuv_info.osd_x_pan = var->xoffset; + itv->yuv_info.osd_y_pan = var->yoffset; + /* Force update of yuv registers */ + itv->yuv_info.yuv_forced_update = 1; + return 0; +} + +static int ivtvfb_set_par(struct fb_info *info) +{ + int rc = 0; + struct ivtv *itv = (struct ivtv *) info->par; + + IVTV_FB_DEBUG_INFO("ivtvfb_set_par\n"); + + rc = ivtvfb_set_var(itv, &info->var); + ivtvfb_pan_display(&info->var, info); + ivtvfb_get_fix(itv, &info->fix); + return rc; +} + +static int ivtvfb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + u32 color, *palette; + struct ivtv *itv = (struct ivtv *)info->par; + + if (regno >= info->cmap.len) + return -EINVAL; + + color = ((transp & 0xFF00) << 16) |((red & 0xFF00) << 8) | (green & 0xFF00) | ((blue & 0xFF00) >> 8); + if (info->var.bits_per_pixel <= 8) { + write_reg(regno, 0x02a30); + write_reg(color, 0x02a34); + return 0; + } + if (regno >= 16) + return -EINVAL; + + palette = info->pseudo_palette; + if (info->var.bits_per_pixel == 16) { + switch (info->var.green.length) { + case 4: + color = ((red & 0xf000) >> 4) | + ((green & 0xf000) >> 8) | + ((blue & 0xf000) >> 12); + break; + case 5: + color = ((red & 0xf800) >> 1) | + ((green & 0xf800) >> 6) | + ((blue & 0xf800) >> 11); + break; + case 6: + color = (red & 0xf800 ) | + ((green & 0xfc00) >> 5) | + ((blue & 0xf800) >> 11); + break; + } + } + palette[regno] = color; + return 0; +} + +/* We don't really support blanking. All this does is enable or + disable the OSD. */ +static int ivtvfb_blank(int blank_mode, struct fb_info *info) +{ + struct ivtv *itv = (struct ivtv *)info->par; + + IVTV_FB_DEBUG_INFO("Set blanking mode : %d\n", blank_mode); + switch (blank_mode) { + case FB_BLANK_UNBLANK: + ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 1); + break; + case FB_BLANK_NORMAL: + case FB_BLANK_HSYNC_SUSPEND: + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_POWERDOWN: + ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0); + break; + } + return 0; +} + +static struct fb_ops ivtvfb_ops = { + .owner = THIS_MODULE, + .fb_check_var = ivtvfb_check_var, + .fb_set_par = ivtvfb_set_par, + .fb_setcolreg = ivtvfb_setcolreg, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = NULL, + .fb_ioctl = ivtvfb_ioctl, + .fb_pan_display = ivtvfb_pan_display, + .fb_blank = ivtvfb_blank, +}; + +/* Initialization */ + + +/* Setup our initial video mode */ +static int ivtvfb_init_vidmode(struct ivtv *itv) +{ + struct osd_info *oi = itv->osd_info; + struct v4l2_rect start_window; + int max_height; + + /* Color mode */ + + if (osd_compat) osd_depth = 32; + if (osd_depth != 8 && osd_depth != 16 && osd_depth != 32) osd_depth = 8; + oi->bits_per_pixel = osd_depth; + oi->bytes_per_pixel = oi->bits_per_pixel / 8; + + /* Invalidate current osd mode to force a mode switch later */ + oi->osd_mode = -1; + + /* Horizontal size & position */ + + if (osd_xres > 720) osd_xres = 720; + + /* Must be a multiple of 4 for 8bpp & 2 for 16bpp */ + if (osd_depth == 8) + osd_xres &= ~3; + else if (osd_depth == 16) + osd_xres &= ~1; + + if (osd_xres) + start_window.width = osd_xres; + else + start_window.width = osd_compat ? 720: 640; + + /* Check horizontal start (osd_left). */ + if (osd_left && osd_left + start_window.width > 721) { + IVTV_FB_ERR("Invalid osd_left - assuming default\n"); + osd_left = 0; + } + + /* Hardware coords start at 0, user coords start at 1. */ + osd_left--; + + start_window.left = osd_left >= 0 ? osd_left : ((IVTV_OSD_MAX_WIDTH - start_window.width) / 2); + + oi->display_byte_stride = + start_window.width * oi->bytes_per_pixel; + + /* Vertical size & position */ + + max_height = itv->is_50hz ? 576 : 480; + + if (osd_yres > max_height) + osd_yres = max_height; + + if (osd_yres) + start_window.height = osd_yres; + else + start_window.height = osd_compat ? max_height : (itv->is_50hz ? 480 : 400); + + /* Check vertical start (osd_upper). */ + if (osd_upper + start_window.height > max_height + 1) { + IVTV_FB_ERR("Invalid osd_upper - assuming default\n"); + osd_upper = 0; + } + + /* Hardware coords start at 0, user coords start at 1. */ + osd_upper--; + + start_window.top = osd_upper >= 0 ? osd_upper : ((max_height - start_window.height) / 2); + + oi->display_width = start_window.width; + oi->display_height = start_window.height; + + /* Generate a valid fb_var_screeninfo */ + + oi->ivtvfb_defined.xres = oi->display_width; + oi->ivtvfb_defined.yres = oi->display_height; + oi->ivtvfb_defined.xres_virtual = oi->display_width; + oi->ivtvfb_defined.yres_virtual = oi->display_height; + oi->ivtvfb_defined.bits_per_pixel = oi->bits_per_pixel; + oi->ivtvfb_defined.vmode = (osd_laced ? FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED); + oi->ivtvfb_defined.left_margin = start_window.left + 1; + oi->ivtvfb_defined.upper_margin = start_window.top + 1; + oi->ivtvfb_defined.accel_flags = FB_ACCEL_NONE; + oi->ivtvfb_defined.nonstd = 0; + + /* We've filled in the most data, let the usual mode check + routine fill in the rest. */ + _ivtvfb_check_var(&oi->ivtvfb_defined, itv); + + /* Generate valid fb_fix_screeninfo */ + + ivtvfb_get_fix(itv, &oi->ivtvfb_fix); + + /* Generate valid fb_info */ + + oi->ivtvfb_info.node = -1; + oi->ivtvfb_info.flags = FBINFO_FLAG_DEFAULT; + oi->ivtvfb_info.fbops = &ivtvfb_ops; + oi->ivtvfb_info.par = itv; + oi->ivtvfb_info.var = oi->ivtvfb_defined; + oi->ivtvfb_info.fix = oi->ivtvfb_fix; + oi->ivtvfb_info.screen_base = (u8 __iomem *)oi->video_vbase; + oi->ivtvfb_info.fbops = &ivtvfb_ops; + + /* Supply some monitor specs. Bogus values will do for now */ + oi->ivtvfb_info.monspecs.hfmin = 8000; + oi->ivtvfb_info.monspecs.hfmax = 70000; + oi->ivtvfb_info.monspecs.vfmin = 10; + oi->ivtvfb_info.monspecs.vfmax = 100; + + /* Allocate color map */ + if (fb_alloc_cmap(&oi->ivtvfb_info.cmap, 256, 1)) { + IVTV_FB_ERR("abort, unable to alloc cmap\n"); + return -ENOMEM; + } + + /* Allocate the pseudo palette */ + oi->ivtvfb_info.pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL); + + if (!oi->ivtvfb_info.pseudo_palette) { + IVTV_FB_ERR("abort, unable to alloc pseudo pallete\n"); + return -ENOMEM; + } + + return 0; +} + +/* Find OSD buffer base & size. Add to mtrr. Zero osd buffer. */ + +static int ivtvfb_init_io(struct ivtv *itv) +{ + struct osd_info *oi = itv->osd_info; + + mutex_lock(&itv->serialize_lock); + if (ivtv_init_on_first_open(itv)) { + mutex_unlock(&itv->serialize_lock); + IVTV_FB_ERR("Failed to initialize ivtv\n"); + return -ENXIO; + } + mutex_unlock(&itv->serialize_lock); + + ivtv_fb_get_framebuffer(itv, &oi->video_rbase, &oi->video_buffer_size); + + /* The osd buffer size depends on the number of video buffers allocated + on the PVR350 itself. For now we'll hardcode the smallest osd buffer + size to prevent any overlap. */ + oi->video_buffer_size = 1704960; + + oi->video_pbase = itv->base_addr + IVTV_DECODER_OFFSET + oi->video_rbase; + oi->video_vbase = itv->dec_mem + oi->video_rbase; + + if (!oi->video_vbase) { + IVTV_FB_ERR("abort, video memory 0x%x @ 0x%lx isn't mapped!\n", + oi->video_buffer_size, oi->video_pbase); + return -EIO; + } + + IVTV_FB_INFO("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n", + oi->video_pbase, oi->video_vbase, + oi->video_buffer_size / 1024); + +#ifdef CONFIG_MTRR + { + /* Find the largest power of two that maps the whole buffer */ + int size_shift = 31; + + while (!(oi->video_buffer_size & (1 << size_shift))) { + size_shift--; + } + size_shift++; + oi->fb_start_aligned_physaddr = oi->video_pbase & ~((1 << size_shift) - 1); + oi->fb_end_aligned_physaddr = oi->video_pbase + oi->video_buffer_size; + oi->fb_end_aligned_physaddr += (1 << size_shift) - 1; + oi->fb_end_aligned_physaddr &= ~((1 << size_shift) - 1); + if (mtrr_add(oi->fb_start_aligned_physaddr, + oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr, + MTRR_TYPE_WRCOMB, 1) < 0) { + IVTV_FB_WARN("cannot use mttr\n"); + oi->fb_start_aligned_physaddr = 0; + oi->fb_end_aligned_physaddr = 0; + } + } +#endif + + /* Blank the entire osd. */ + memset_io(oi->video_vbase, 0, oi->video_buffer_size); + + return 0; +} + +/* Release any memory we've grabbed & remove mtrr entry */ +static void ivtvfb_release_buffers (struct ivtv *itv) +{ + struct osd_info *oi = itv->osd_info; + + /* Release cmap */ + if (oi->ivtvfb_info.cmap.len); + fb_dealloc_cmap(&oi->ivtvfb_info.cmap); + + /* Release pseudo palette */ + if (oi->ivtvfb_info.pseudo_palette) + kfree(oi->ivtvfb_info.pseudo_palette); + +#ifdef CONFIG_MTRR + if (oi->fb_end_aligned_physaddr) { + mtrr_del(-1, oi->fb_start_aligned_physaddr, + oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr); + } +#endif + + kfree(oi); + itv->osd_info = NULL; +} + +/* Initialize the specified card */ + +static int ivtvfb_init_card(struct ivtv *itv) +{ + int rc; + + if (itv->osd_info) { + IVTV_FB_ERR("Card %d already initialised\n", ivtv_fb_card_id); + return -EBUSY; + } + + itv->osd_info = kzalloc(sizeof(struct osd_info), GFP_ATOMIC); + if (itv->osd_info == 0) { + IVTV_FB_ERR("Failed to allocate memory for osd_info\n"); + return -ENOMEM; + } + + /* Find & setup the OSD buffer */ + if ((rc = ivtvfb_init_io(itv))) + return rc; + + /* Set the startup video mode information */ + if ((rc = ivtvfb_init_vidmode(itv))) { + ivtvfb_release_buffers(itv); + return rc; + } + + /* Register the framebuffer */ + if (register_framebuffer(&itv->osd_info->ivtvfb_info) < 0) { + ivtvfb_release_buffers(itv); + return -EINVAL; + } + + itv->osd_video_pbase = itv->osd_info->video_pbase; + + /* Set the card to the requested mode */ + ivtvfb_set_par(&itv->osd_info->ivtvfb_info); + + /* Set color 0 to black */ + write_reg(0, 0x02a30); + write_reg(0, 0x02a34); + + /* Enable the osd */ + ivtvfb_blank(FB_BLANK_UNBLANK, &itv->osd_info->ivtvfb_info); + + /* Note if we're running in compatibility mode */ + if (osd_compat) + IVTV_FB_INFO("Running in compatibility mode. Display resize & mode change disabled\n"); + + /* Allocate DMA */ + ivtv_udma_alloc(itv); + return 0; + +} + +static int __init ivtvfb_init(void) +{ + struct ivtv *itv; + int i, registered = 0; + + if (ivtv_fb_card_id < -1 || ivtv_fb_card_id >= IVTV_MAX_CARDS) { + printk(KERN_ERR "ivtv-fb: ivtv_fb_card_id parameter is out of range (valid range: -1 - %d)\n", + IVTV_MAX_CARDS - 1); + return -EINVAL; + } + + /* Locate & initialise all cards supporting an OSD. */ + for (i = 0; i < ivtv_cards_active; i++) { + if (ivtv_fb_card_id != -1 && i != ivtv_fb_card_id) + continue; + itv = ivtv_cards[i]; + if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) { + if (ivtvfb_init_card(itv) == 0) { + IVTV_FB_INFO("Framebuffer registered on ivtv card id %d\n", i); + registered++; + } + } + } + if (!registered) { + printk(KERN_ERR "ivtv-fb: no cards found"); + return -ENODEV; + } + return 0; +} + +static void ivtvfb_cleanup(void) +{ + struct ivtv *itv; + int i; + + printk(KERN_INFO "ivtv-fb: Unloading framebuffer module\n"); + + for (i = 0; i < ivtv_cards_active; i++) { + itv = ivtv_cards[i]; + if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) && itv->osd_info) { + IVTV_FB_DEBUG_INFO("Unregister framebuffer %d\n", i); + ivtvfb_blank(FB_BLANK_POWERDOWN, &itv->osd_info->ivtvfb_info); + unregister_framebuffer(&itv->osd_info->ivtvfb_info); + ivtvfb_release_buffers(itv); + itv->osd_video_pbase = 0; + } + } +} + +module_init(ivtvfb_init); +module_exit(ivtvfb_cleanup); diff --git a/include/linux/ivtvfb.h b/include/linux/ivtvfb.h new file mode 100644 index 00000000000..e980ba62ddc --- /dev/null +++ b/include/linux/ivtvfb.h @@ -0,0 +1,42 @@ +/* + On Screen Display cx23415 Framebuffer driver + + Copyright (C) 2006, 2007 Ian Armstrong + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __LINUX_IVTVFB_H__ +#define __LINUX_IVTVFB_H__ + +#ifdef __KERNEL__ +#include /* need __user */ +#else +#define __user +#endif +#include + +/* Framebuffer external API */ + +struct ivtvfb_dma_frame { + void __user *source; + unsigned long dest_offset; + int count; +}; + +#define IVTVFB_IOC_DMA_FRAME _IOW('V', BASE_VIDIOC_PRIVATE+0, struct ivtvfb_dma_frame) +#define FBIO_WAITFORVSYNC _IOW('F', 0x20, u_int32_t) + +#endif diff --git a/include/media/ivtv-fb.h b/include/media/ivtv-fb.h deleted file mode 100644 index d3a797b1728..00000000000 --- a/include/media/ivtv-fb.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - On Screen Display cx23415 Framebuffer driver - - Copyright (C) 2006 Ian Armstrong - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _LINUX_IVTV_FB_H -#define _LINUX_IVTV_FB_H - -/* Framebuffer external API */ - -struct ivtvfb_dma_frame { - void __user *source; - unsigned long dest_offset; - int count; -}; - -#define IVTVFB_IOC_DMA_FRAME _IOW ('V', BASE_VIDIOC_PRIVATE+0, struct ivtvfb_dma_frame) -#define FBIO_WAITFORVSYNC _IOW('F', 0x20, u_int32_t) - -#endif -- cgit v1.2.3-70-g09d2 From 7b3a0d49e3e929b810ade38926342faca53e867d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 26 Aug 2007 06:11:07 -0300 Subject: V4L/DVB (6120): ivtvfb: rename some missed ivtv-fb references to ivtvfb Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/Kconfig | 2 +- drivers/media/video/ivtv/ivtv-driver.c | 2 +- drivers/media/video/ivtv/ivtv-driver.h | 2 +- drivers/media/video/ivtv/ivtvfb.c | 14 +++++++------- 4 files changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/Kconfig b/drivers/media/video/ivtv/Kconfig index 7f20c166d59..854cc9c30ca 100644 --- a/drivers/media/video/ivtv/Kconfig +++ b/drivers/media/video/ivtv/Kconfig @@ -41,4 +41,4 @@ config VIDEO_FB_IVTV homepage at . To compile this driver as a module, choose M here: the - module will be called ivtv-fb. + module will be called ivtvfb. diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 2a5e0facca7..511a6625241 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -1397,7 +1397,7 @@ static void module_cleanup(void) spin_unlock(&ivtv_cards_lock); } -/* Note: These symbols are exported because they are used by the ivtv-fb +/* Note: These symbols are exported because they are used by the ivtvfb framebuffer module and an infrared module for the IR-blaster. */ EXPORT_SYMBOL(ivtv_set_irq_mask); EXPORT_SYMBOL(ivtv_cards_active); diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 5400ccef4df..32dfc7a859f 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -695,7 +695,7 @@ struct ivtv { u32 osd_chroma_key; /* current chroma key */ struct v4l2_rect osd_rect; /* current OSD position and size */ struct v4l2_rect main_rect; /* current Main window position and size */ - struct osd_info *osd_info; /* ivtv-fb private OSD info */ + struct osd_info *osd_info; /* ivtvfb private OSD info */ }; /* Globals */ diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c index ff721c08847..c8ca7cbbe38 100644 --- a/drivers/media/video/ivtv/ivtvfb.c +++ b/drivers/media/video/ivtv/ivtvfb.c @@ -128,15 +128,15 @@ MODULE_LICENSE("GPL"); #define IVTV_FB_DEBUG(x, type, fmt, args...) \ do { \ if ((x) & ivtv_fb_debug) \ - printk(KERN_INFO "ivtv-fb%d " type ": " fmt, itv->num , ## args); \ + printk(KERN_INFO "ivtvfb%d " type ": " fmt, itv->num , ## args); \ } while (0) #define IVTV_FB_DEBUG_WARN(fmt, args...) IVTV_FB_DEBUG(IVTV_FB_DBGFLG_WARN, "warning", fmt , ## args) #define IVTV_FB_DEBUG_INFO(fmt, args...) IVTV_FB_DEBUG(IVTV_FB_DBGFLG_INFO, "info", fmt , ## args) /* Standard kernel messages */ -#define IVTV_FB_ERR(fmt, args...) printk(KERN_ERR "ivtv-fb%d: " fmt, itv->num , ## args) -#define IVTV_FB_WARN(fmt, args...) printk(KERN_WARNING "ivtv-fb%d: " fmt, itv->num , ## args) -#define IVTV_FB_INFO(fmt, args...) printk(KERN_INFO "ivtv-fb%d: " fmt, itv->num , ## args) +#define IVTV_FB_ERR(fmt, args...) printk(KERN_ERR "ivtvfb%d: " fmt, itv->num , ## args) +#define IVTV_FB_WARN(fmt, args...) printk(KERN_WARNING "ivtvfb%d: " fmt, itv->num , ## args) +#define IVTV_FB_INFO(fmt, args...) printk(KERN_INFO "ivtvfb%d: " fmt, itv->num , ## args) /* --------------------------------------------------------------------- */ @@ -1143,7 +1143,7 @@ static int __init ivtvfb_init(void) int i, registered = 0; if (ivtv_fb_card_id < -1 || ivtv_fb_card_id >= IVTV_MAX_CARDS) { - printk(KERN_ERR "ivtv-fb: ivtv_fb_card_id parameter is out of range (valid range: -1 - %d)\n", + printk(KERN_ERR "ivtvfb: ivtv_fb_card_id parameter is out of range (valid range: -1 - %d)\n", IVTV_MAX_CARDS - 1); return -EINVAL; } @@ -1161,7 +1161,7 @@ static int __init ivtvfb_init(void) } } if (!registered) { - printk(KERN_ERR "ivtv-fb: no cards found"); + printk(KERN_ERR "ivtvfb: no cards found"); return -ENODEV; } return 0; @@ -1172,7 +1172,7 @@ static void ivtvfb_cleanup(void) struct ivtv *itv; int i; - printk(KERN_INFO "ivtv-fb: Unloading framebuffer module\n"); + printk(KERN_INFO "ivtvfb: Unloading framebuffer module\n"); for (i = 0; i < ivtv_cards_active; i++) { itv = ivtv_cards[i]; -- cgit v1.2.3-70-g09d2 From 641ed49db6ecf6c539a5eab50a7540542377add1 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 28 Aug 2007 03:24:31 -0300 Subject: V4L/DVB (6121): ivtvfb: replace ivtv_fb prefix to ivtvfb ivtvfb: replace ivtv_fb prefix to ivtvfb, change warning to info message Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtvfb.c | 168 +++++++++++++++++++------------------- 1 file changed, 84 insertions(+), 84 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c index c8ca7cbbe38..73e46f94b45 100644 --- a/drivers/media/video/ivtv/ivtvfb.c +++ b/drivers/media/video/ivtv/ivtvfb.c @@ -52,8 +52,8 @@ #include "ivtv-mailbox.h" /* card parameters */ -static int ivtv_fb_card_id = -1; -static int ivtv_fb_debug = 0; +static int ivtvfb_card_id = -1; +static int ivtvfb_debug = 0; static int osd_laced; static int osd_compat; static int osd_depth; @@ -62,8 +62,8 @@ static int osd_left; static int osd_yres; static int osd_xres; -module_param(ivtv_fb_card_id, int, 0444); -module_param_named(debug,ivtv_fb_debug, int, 0644); +module_param(ivtvfb_card_id, int, 0444); +module_param_named(debug,ivtvfb_debug, int, 0644); module_param(osd_laced, bool, 0444); module_param(osd_compat, bool, 0444); module_param(osd_depth, int, 0444); @@ -72,7 +72,7 @@ module_param(osd_left, int, 0444); module_param(osd_yres, int, 0444); module_param(osd_xres, int, 0444); -MODULE_PARM_DESC(ivtv_fb_card_id, +MODULE_PARM_DESC(ivtvfb_card_id, "Only use framebuffer of the specified ivtv card (0-31)\n" "\t\t\tdefault -1: initialize all available framebuffers"); @@ -122,21 +122,21 @@ MODULE_LICENSE("GPL"); /* --------------------------------------------------------------------- */ -#define IVTV_FB_DBGFLG_WARN (1 << 0) -#define IVTV_FB_DBGFLG_INFO (1 << 1) +#define IVTVFB_DBGFLG_WARN (1 << 0) +#define IVTVFB_DBGFLG_INFO (1 << 1) -#define IVTV_FB_DEBUG(x, type, fmt, args...) \ +#define IVTVFB_DEBUG(x, type, fmt, args...) \ do { \ - if ((x) & ivtv_fb_debug) \ + if ((x) & ivtvfb_debug) \ printk(KERN_INFO "ivtvfb%d " type ": " fmt, itv->num , ## args); \ } while (0) -#define IVTV_FB_DEBUG_WARN(fmt, args...) IVTV_FB_DEBUG(IVTV_FB_DBGFLG_WARN, "warning", fmt , ## args) -#define IVTV_FB_DEBUG_INFO(fmt, args...) IVTV_FB_DEBUG(IVTV_FB_DBGFLG_INFO, "info", fmt , ## args) +#define IVTVFB_DEBUG_WARN(fmt, args...) IVTVFB_DEBUG(IVTVFB_DBGFLG_WARN, "warning", fmt , ## args) +#define IVTVFB_DEBUG_INFO(fmt, args...) IVTVFB_DEBUG(IVTVFB_DBGFLG_INFO, "info", fmt , ## args) /* Standard kernel messages */ -#define IVTV_FB_ERR(fmt, args...) printk(KERN_ERR "ivtvfb%d: " fmt, itv->num , ## args) -#define IVTV_FB_WARN(fmt, args...) printk(KERN_WARNING "ivtvfb%d: " fmt, itv->num , ## args) -#define IVTV_FB_INFO(fmt, args...) printk(KERN_INFO "ivtvfb%d: " fmt, itv->num , ## args) +#define IVTVFB_ERR(fmt, args...) printk(KERN_ERR "ivtvfb%d: " fmt, itv->num , ## args) +#define IVTVFB_WARN(fmt, args...) printk(KERN_WARNING "ivtvfb%d: " fmt, itv->num , ## args) +#define IVTVFB_INFO(fmt, args...) printk(KERN_INFO "ivtvfb%d: " fmt, itv->num , ## args) /* --------------------------------------------------------------------- */ @@ -201,7 +201,7 @@ struct ivtv_osd_coords { /* ivtv API calls for framebuffer related support */ -static int ivtv_fb_get_framebuffer(struct ivtv *itv, u32 *fbbase, +static int ivtvfb_get_framebuffer(struct ivtv *itv, u32 *fbbase, u32 *fblength) { u32 data[CX2341X_MBOX_MAX_DATA]; @@ -213,7 +213,7 @@ static int ivtv_fb_get_framebuffer(struct ivtv *itv, u32 *fbbase, return rc; } -static int ivtv_fb_get_osd_coords(struct ivtv *itv, +static int ivtvfb_get_osd_coords(struct ivtv *itv, struct ivtv_osd_coords *osd) { struct osd_info *oi = itv->osd_info; @@ -230,7 +230,7 @@ static int ivtv_fb_get_osd_coords(struct ivtv *itv, return 0; } -static int ivtv_fb_set_osd_coords(struct ivtv *itv, const struct ivtv_osd_coords *osd) +static int ivtvfb_set_osd_coords(struct ivtv *itv, const struct ivtv_osd_coords *osd) { struct osd_info *oi = itv->osd_info; @@ -245,7 +245,7 @@ static int ivtv_fb_set_osd_coords(struct ivtv *itv, const struct ivtv_osd_coords osd->lines, osd->x, osd->y); } -static int ivtv_fb_set_display_window(struct ivtv *itv, struct v4l2_rect *ivtv_window) +static int ivtvfb_set_display_window(struct ivtv *itv, struct v4l2_rect *ivtv_window) { int osd_height_limit = itv->is_50hz ? 576 : 480; @@ -255,13 +255,13 @@ static int ivtv_fb_set_display_window(struct ivtv *itv, struct v4l2_rect *ivtv_w /* Ensure we don't exceed display limits */ if (ivtv_window->top + ivtv_window->height > osd_height_limit) { - IVTV_FB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid height setting (%d, %d)\n", + IVTVFB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid height setting (%d, %d)\n", ivtv_window->top, ivtv_window->height); ivtv_window->top = osd_height_limit - ivtv_window->height; } if (ivtv_window->left + ivtv_window->width > IVTV_OSD_MAX_WIDTH) { - IVTV_FB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid width setting (%d, %d)\n", + IVTVFB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid width setting (%d, %d)\n", ivtv_window->left, ivtv_window->width); ivtv_window->left = IVTV_OSD_MAX_WIDTH - ivtv_window->width; } @@ -281,7 +281,7 @@ static int ivtv_fb_set_display_window(struct ivtv *itv, struct v4l2_rect *ivtv_w return 0; } -static int ivtv_fb_prep_dec_dma_to_device(struct ivtv *itv, +static int ivtvfb_prep_dec_dma_to_device(struct ivtv *itv, unsigned long ivtv_dest_addr, void __user *userbuf, int size_in_bytes) { @@ -293,7 +293,7 @@ static int ivtv_fb_prep_dec_dma_to_device(struct ivtv *itv, /* Map User DMA */ if (ivtv_udma_setup(itv, ivtv_dest_addr, userbuf, size_in_bytes) <= 0) { mutex_unlock(&itv->udma.lock); - IVTV_FB_WARN("ivtvfb_prep_dec_dma_to_device, " + IVTVFB_WARN("ivtvfb_prep_dec_dma_to_device, " "Error with get_user_pages: %d bytes, %d pages returned\n", size_in_bytes, itv->udma.page_count); @@ -301,7 +301,7 @@ static int ivtv_fb_prep_dec_dma_to_device(struct ivtv *itv, return -EIO; } - IVTV_FB_DEBUG_INFO("ivtvfb_prep_dec_dma_to_device, %d bytes, %d pages\n", + IVTVFB_DEBUG_INFO("ivtvfb_prep_dec_dma_to_device, %d bytes, %d pages\n", size_in_bytes, itv->udma.page_count); ivtv_udma_prepare(itv); @@ -330,7 +330,7 @@ static int ivtv_fb_prep_dec_dma_to_device(struct ivtv *itv, return ret; } -static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source, +static int ivtvfb_prep_frame(struct ivtv *itv, int cmd, void __user *source, unsigned long dest_offset, int count) { DEFINE_WAIT(wait); @@ -338,34 +338,34 @@ static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source, /* Nothing to do */ if (count == 0) { - IVTV_FB_DEBUG_WARN("ivtv_fb_prep_frame: Nothing to do. count = 0\n"); + IVTVFB_DEBUG_WARN("ivtvfb_prep_frame: Nothing to do. count = 0\n"); return -EINVAL; } /* Check Total FB Size */ if ((dest_offset + count) > oi->video_buffer_size) { - IVTV_FB_WARN("ivtv_fb_prep_frame: Overflowing the framebuffer %ld, only %d available\n", + IVTVFB_WARN("ivtvfb_prep_frame: Overflowing the framebuffer %ld, only %d available\n", dest_offset + count, oi->video_buffer_size); return -E2BIG; } /* Not fatal, but will have undesirable results */ if ((unsigned long)source & 3) - IVTV_FB_WARN("ivtv_fb_prep_frame: Source address not 32 bit aligned (0x%08lx)\n", + IVTVFB_WARN("ivtvfb_prep_frame: Source address not 32 bit aligned (0x%08lx)\n", (unsigned long)source); if (dest_offset & 3) - IVTV_FB_WARN("ivtv_fb_prep_frame: Dest offset not 32 bit aligned (%ld)\n", dest_offset); + IVTVFB_WARN("ivtvfb_prep_frame: Dest offset not 32 bit aligned (%ld)\n", dest_offset); if (count & 3) - IVTV_FB_WARN("ivtv_fb_prep_frame: Count not a multiple of 4 (%d)\n", count); + IVTVFB_WARN("ivtvfb_prep_frame: Count not a multiple of 4 (%d)\n", count); /* Check Source */ if (!access_ok(VERIFY_READ, source + dest_offset, count)) { - IVTV_FB_WARN("Invalid userspace pointer 0x%08lx\n", + IVTVFB_WARN("Invalid userspace pointer 0x%08lx\n", (unsigned long)source); - IVTV_FB_DEBUG_WARN("access_ok() failed for offset 0x%08lx source 0x%08lx count %d\n", + IVTVFB_DEBUG_WARN("access_ok() failed for offset 0x%08lx source 0x%08lx count %d\n", dest_offset, (unsigned long)source, count); return -EINVAL; @@ -375,7 +375,7 @@ static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source, dest_offset += IVTV_DECODER_OFFSET + oi->video_rbase; /* Fill Buffers */ - return ivtv_fb_prep_dec_dma_to_device(itv, dest_offset, source, count); + return ivtvfb_prep_dec_dma_to_device(itv, dest_offset, source, count); } static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) @@ -412,15 +412,15 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar case IVTVFB_IOC_DMA_FRAME: { struct ivtvfb_dma_frame args; - IVTV_FB_DEBUG_INFO("IVTVFB_IOC_DMA_FRAME\n"); + IVTVFB_DEBUG_INFO("IVTVFB_IOC_DMA_FRAME\n"); if (copy_from_user(&args, (void __user *)arg, sizeof(args))) return -EFAULT; - return ivtv_fb_prep_frame(itv, cmd, args.source, args.dest_offset, args.count); + return ivtvfb_prep_frame(itv, cmd, args.source, args.dest_offset, args.count); } default: - IVTV_FB_DEBUG_INFO("Unknown ioctl %08x\n", cmd); + IVTVFB_DEBUG_INFO("Unknown ioctl %08x\n", cmd); return -EINVAL; } return 0; @@ -435,7 +435,7 @@ static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var) struct v4l2_rect ivtv_window; int osd_mode = -1; - IVTV_FB_DEBUG_INFO("ivtvfb_set_var\n"); + IVTVFB_DEBUG_INFO("ivtvfb_set_var\n"); /* Select color space */ if (var->nonstd) /* YUV */ @@ -463,11 +463,11 @@ static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var) osd_mode = IVTV_OSD_BPP_16_565; break; default: - IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n"); + IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n"); } break; default: - IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n"); + IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n"); } /* Change osd mode if needed. @@ -491,18 +491,18 @@ static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var) ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 0); break; default: - IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid video mode\n"); + IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid video mode\n"); } /* Read the current osd info */ - ivtv_fb_get_osd_coords(itv, &ivtv_osd); + ivtvfb_get_osd_coords(itv, &ivtv_osd); /* Now set the OSD to the size we want */ ivtv_osd.pixel_stride = var->xres_virtual; ivtv_osd.lines = var->yres_virtual; ivtv_osd.x = 0; ivtv_osd.y = 0; - ivtv_fb_set_osd_coords(itv, &ivtv_osd); + ivtvfb_set_osd_coords(itv, &ivtv_osd); /* Can't seem to find the right API combo for this. Use another function which does what we need through direct register access. */ @@ -515,22 +515,22 @@ static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var) ivtv_window.top = var->upper_margin - 1; ivtv_window.left = var->left_margin - 1; - ivtv_fb_set_display_window(itv, &ivtv_window); + ivtvfb_set_display_window(itv, &ivtv_window); /* Force update of yuv registers */ itv->yuv_info.yuv_forced_update = 1; - IVTV_FB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n", + IVTVFB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n", var->xres, var->yres, var->xres_virtual, var->yres_virtual, var->bits_per_pixel); - IVTV_FB_DEBUG_INFO("Display position: %d, %d\n", + IVTVFB_DEBUG_INFO("Display position: %d, %d\n", var->left_margin, var->upper_margin); - IVTV_FB_DEBUG_INFO("Display filter: %s\n", + IVTVFB_DEBUG_INFO("Display filter: %s\n", (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off"); - IVTV_FB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB"); + IVTVFB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB"); return 0; } @@ -539,7 +539,7 @@ static int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix) { struct osd_info *oi = itv->osd_info; - IVTV_FB_DEBUG_INFO("ivtvfb_get_fix\n"); + IVTVFB_DEBUG_INFO("ivtvfb_get_fix\n"); memset(fix, 0, sizeof(struct fb_fix_screeninfo)); strcpy(fix->id, "cx23415 TV out"); fix->smem_start = oi->video_pbase; @@ -563,7 +563,7 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) int osd_height_limit; u32 pixclock, hlimit, vlimit; - IVTV_FB_DEBUG_INFO("ivtvfb_check_var\n"); + IVTVFB_DEBUG_INFO("ivtvfb_check_var\n"); /* Set base references for mode calcs. */ if (itv->is_50hz) { @@ -582,7 +582,7 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) /* Check the bits per pixel */ if (osd_compat) { if (var->bits_per_pixel != 32) { - IVTV_FB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel); + IVTVFB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel); return -EINVAL; } } @@ -633,7 +633,7 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) } } else { - IVTV_FB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel); + IVTVFB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel); return -EINVAL; } @@ -643,14 +643,14 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) var->yres != oi->ivtvfb_defined.yres || var->xres_virtual != oi->ivtvfb_defined.xres_virtual || var->yres_virtual != oi->ivtvfb_defined.yres_virtual) { - IVTV_FB_DEBUG_WARN("Invalid resolution: %dx%d (virtual %dx%d)\n", + IVTVFB_DEBUG_WARN("Invalid resolution: %dx%d (virtual %dx%d)\n", var->xres, var->yres, var->xres_virtual, var->yres_virtual); return -EINVAL; } } else { if (var->xres > IVTV_OSD_MAX_WIDTH || var->yres > osd_height_limit) { - IVTV_FB_DEBUG_WARN("Invalid resolution: %dx%d\n", + IVTVFB_DEBUG_WARN("Invalid resolution: %dx%d\n", var->xres, var->yres); return -EINVAL; } @@ -660,7 +660,7 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8) > oi->video_buffer_size || var->xres_virtual < var->xres || var->yres_virtual < var->yres) { - IVTV_FB_DEBUG_WARN("Invalid virtual resolution: %dx%d\n", + IVTVFB_DEBUG_WARN("Invalid virtual resolution: %dx%d\n", var->xres_virtual, var->yres_virtual); return -EINVAL; } @@ -670,43 +670,43 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) if (var->bits_per_pixel == 8) { /* Width must be a multiple of 4 */ if (var->xres & 3) { - IVTV_FB_DEBUG_WARN("Invalid resolution for 8bpp: %d\n", var->xres); + IVTVFB_DEBUG_WARN("Invalid resolution for 8bpp: %d\n", var->xres); return -EINVAL; } if (var->xres_virtual & 3) { - IVTV_FB_DEBUG_WARN("Invalid virtual resolution for 8bpp: %d)\n", var->xres_virtual); + IVTVFB_DEBUG_WARN("Invalid virtual resolution for 8bpp: %d)\n", var->xres_virtual); return -EINVAL; } } else if (var->bits_per_pixel == 16) { /* Width must be a multiple of 2 */ if (var->xres & 1) { - IVTV_FB_DEBUG_WARN("Invalid resolution for 16bpp: %d\n", var->xres); + IVTVFB_DEBUG_WARN("Invalid resolution for 16bpp: %d\n", var->xres); return -EINVAL; } if (var->xres_virtual & 1) { - IVTV_FB_DEBUG_WARN("Invalid virtual resolution for 16bpp: %d)\n", var->xres_virtual); + IVTVFB_DEBUG_WARN("Invalid virtual resolution for 16bpp: %d)\n", var->xres_virtual); return -EINVAL; } } /* Now check the offsets */ if (var->xoffset >= var->xres_virtual || var->yoffset >= var->yres_virtual) { - IVTV_FB_DEBUG_WARN("Invalid offset: %d (%d) %d (%d)\n", + IVTVFB_DEBUG_WARN("Invalid offset: %d (%d) %d (%d)\n", var->xoffset, var->xres_virtual, var->yoffset, var->yres_virtual); return -EINVAL; } /* Check pixel format */ if (var->nonstd > 1) { - IVTV_FB_DEBUG_WARN("Invalid nonstd % d\n", var->nonstd); + IVTVFB_DEBUG_WARN("Invalid nonstd % d\n", var->nonstd); return -EINVAL; } /* Check video mode */ if (((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) && ((var->vmode & FB_VMODE_MASK) != FB_VMODE_INTERLACED)) { - IVTV_FB_DEBUG_WARN("Invalid video mode: %d\n", var->vmode & FB_VMODE_MASK); + IVTVFB_DEBUG_WARN("Invalid video mode: %d\n", var->vmode & FB_VMODE_MASK); return -EINVAL; } @@ -737,24 +737,24 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv) else var->pixclock = pixclock; - IVTV_FB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n", + IVTVFB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n", var->xres, var->yres, var->xres_virtual, var->yres_virtual, var->bits_per_pixel); - IVTV_FB_DEBUG_INFO("Display position: %d, %d\n", + IVTVFB_DEBUG_INFO("Display position: %d, %d\n", var->left_margin, var->upper_margin); - IVTV_FB_DEBUG_INFO("Display filter: %s\n", + IVTVFB_DEBUG_INFO("Display filter: %s\n", (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off"); - IVTV_FB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB"); + IVTVFB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB"); return 0; } static int ivtvfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { struct ivtv *itv = (struct ivtv *) info->par; - IVTV_FB_DEBUG_INFO("ivtvfb_check_var\n"); + IVTVFB_DEBUG_INFO("ivtvfb_check_var\n"); return _ivtvfb_check_var(var, itv); } @@ -779,7 +779,7 @@ static int ivtvfb_set_par(struct fb_info *info) int rc = 0; struct ivtv *itv = (struct ivtv *) info->par; - IVTV_FB_DEBUG_INFO("ivtvfb_set_par\n"); + IVTVFB_DEBUG_INFO("ivtvfb_set_par\n"); rc = ivtvfb_set_var(itv, &info->var); ivtvfb_pan_display(&info->var, info); @@ -836,7 +836,7 @@ static int ivtvfb_blank(int blank_mode, struct fb_info *info) { struct ivtv *itv = (struct ivtv *)info->par; - IVTV_FB_DEBUG_INFO("Set blanking mode : %d\n", blank_mode); + IVTVFB_DEBUG_INFO("Set blanking mode : %d\n", blank_mode); switch (blank_mode) { case FB_BLANK_UNBLANK: ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 1); @@ -902,7 +902,7 @@ static int ivtvfb_init_vidmode(struct ivtv *itv) /* Check horizontal start (osd_left). */ if (osd_left && osd_left + start_window.width > 721) { - IVTV_FB_ERR("Invalid osd_left - assuming default\n"); + IVTVFB_ERR("Invalid osd_left - assuming default\n"); osd_left = 0; } @@ -928,7 +928,7 @@ static int ivtvfb_init_vidmode(struct ivtv *itv) /* Check vertical start (osd_upper). */ if (osd_upper + start_window.height > max_height + 1) { - IVTV_FB_ERR("Invalid osd_upper - assuming default\n"); + IVTVFB_ERR("Invalid osd_upper - assuming default\n"); osd_upper = 0; } @@ -980,7 +980,7 @@ static int ivtvfb_init_vidmode(struct ivtv *itv) /* Allocate color map */ if (fb_alloc_cmap(&oi->ivtvfb_info.cmap, 256, 1)) { - IVTV_FB_ERR("abort, unable to alloc cmap\n"); + IVTVFB_ERR("abort, unable to alloc cmap\n"); return -ENOMEM; } @@ -988,7 +988,7 @@ static int ivtvfb_init_vidmode(struct ivtv *itv) oi->ivtvfb_info.pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL); if (!oi->ivtvfb_info.pseudo_palette) { - IVTV_FB_ERR("abort, unable to alloc pseudo pallete\n"); + IVTVFB_ERR("abort, unable to alloc pseudo pallete\n"); return -ENOMEM; } @@ -1004,12 +1004,12 @@ static int ivtvfb_init_io(struct ivtv *itv) mutex_lock(&itv->serialize_lock); if (ivtv_init_on_first_open(itv)) { mutex_unlock(&itv->serialize_lock); - IVTV_FB_ERR("Failed to initialize ivtv\n"); + IVTVFB_ERR("Failed to initialize ivtv\n"); return -ENXIO; } mutex_unlock(&itv->serialize_lock); - ivtv_fb_get_framebuffer(itv, &oi->video_rbase, &oi->video_buffer_size); + ivtvfb_get_framebuffer(itv, &oi->video_rbase, &oi->video_buffer_size); /* The osd buffer size depends on the number of video buffers allocated on the PVR350 itself. For now we'll hardcode the smallest osd buffer @@ -1020,12 +1020,12 @@ static int ivtvfb_init_io(struct ivtv *itv) oi->video_vbase = itv->dec_mem + oi->video_rbase; if (!oi->video_vbase) { - IVTV_FB_ERR("abort, video memory 0x%x @ 0x%lx isn't mapped!\n", + IVTVFB_ERR("abort, video memory 0x%x @ 0x%lx isn't mapped!\n", oi->video_buffer_size, oi->video_pbase); return -EIO; } - IVTV_FB_INFO("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n", + IVTVFB_INFO("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n", oi->video_pbase, oi->video_vbase, oi->video_buffer_size / 1024); @@ -1045,7 +1045,7 @@ static int ivtvfb_init_io(struct ivtv *itv) if (mtrr_add(oi->fb_start_aligned_physaddr, oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr, MTRR_TYPE_WRCOMB, 1) < 0) { - IVTV_FB_WARN("cannot use mttr\n"); + IVTVFB_INFO("disabled mttr\n"); oi->fb_start_aligned_physaddr = 0; oi->fb_end_aligned_physaddr = 0; } @@ -1089,13 +1089,13 @@ static int ivtvfb_init_card(struct ivtv *itv) int rc; if (itv->osd_info) { - IVTV_FB_ERR("Card %d already initialised\n", ivtv_fb_card_id); + IVTVFB_ERR("Card %d already initialised\n", ivtvfb_card_id); return -EBUSY; } itv->osd_info = kzalloc(sizeof(struct osd_info), GFP_ATOMIC); if (itv->osd_info == 0) { - IVTV_FB_ERR("Failed to allocate memory for osd_info\n"); + IVTVFB_ERR("Failed to allocate memory for osd_info\n"); return -ENOMEM; } @@ -1129,7 +1129,7 @@ static int ivtvfb_init_card(struct ivtv *itv) /* Note if we're running in compatibility mode */ if (osd_compat) - IVTV_FB_INFO("Running in compatibility mode. Display resize & mode change disabled\n"); + IVTVFB_INFO("Running in compatibility mode. Display resize & mode change disabled\n"); /* Allocate DMA */ ivtv_udma_alloc(itv); @@ -1142,20 +1142,20 @@ static int __init ivtvfb_init(void) struct ivtv *itv; int i, registered = 0; - if (ivtv_fb_card_id < -1 || ivtv_fb_card_id >= IVTV_MAX_CARDS) { - printk(KERN_ERR "ivtvfb: ivtv_fb_card_id parameter is out of range (valid range: -1 - %d)\n", + if (ivtvfb_card_id < -1 || ivtvfb_card_id >= IVTV_MAX_CARDS) { + printk(KERN_ERR "ivtvfb: ivtvfb_card_id parameter is out of range (valid range: -1 - %d)\n", IVTV_MAX_CARDS - 1); return -EINVAL; } /* Locate & initialise all cards supporting an OSD. */ for (i = 0; i < ivtv_cards_active; i++) { - if (ivtv_fb_card_id != -1 && i != ivtv_fb_card_id) + if (ivtvfb_card_id != -1 && i != ivtvfb_card_id) continue; itv = ivtv_cards[i]; if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) { if (ivtvfb_init_card(itv) == 0) { - IVTV_FB_INFO("Framebuffer registered on ivtv card id %d\n", i); + IVTVFB_INFO("Framebuffer registered on ivtv card id %d\n", i); registered++; } } @@ -1177,7 +1177,7 @@ static void ivtvfb_cleanup(void) for (i = 0; i < ivtv_cards_active; i++) { itv = ivtv_cards[i]; if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) && itv->osd_info) { - IVTV_FB_DEBUG_INFO("Unregister framebuffer %d\n", i); + IVTVFB_DEBUG_INFO("Unregister framebuffer %d\n", i); ivtvfb_blank(FB_BLANK_POWERDOWN, &itv->osd_info->ivtvfb_info); unregister_framebuffer(&itv->osd_info->ivtvfb_info); ivtvfb_release_buffers(itv); -- cgit v1.2.3-70-g09d2 From 136280322d894e6ec07187f2427b00c3d64ad066 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 28 Aug 2007 03:28:04 -0300 Subject: V4L/DVB (6122): ivtvfb: fix an obvious bug in ivtvfb_release_buffers() Signed-off-by: Adrian Bunk Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtvfb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c index 73e46f94b45..9684048fe56 100644 --- a/drivers/media/video/ivtv/ivtvfb.c +++ b/drivers/media/video/ivtv/ivtvfb.c @@ -1064,8 +1064,8 @@ static void ivtvfb_release_buffers (struct ivtv *itv) struct osd_info *oi = itv->osd_info; /* Release cmap */ - if (oi->ivtvfb_info.cmap.len); - fb_dealloc_cmap(&oi->ivtvfb_info.cmap); + if (oi->ivtvfb_info.cmap.len) + fb_dealloc_cmap(&oi->ivtvfb_info.cmap); /* Release pseudo palette */ if (oi->ivtvfb_info.pseudo_palette) -- cgit v1.2.3-70-g09d2 From 51b39dfa5477fdb2459e3c46f855f01b8b03102d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 26 Aug 2007 06:13:04 -0300 Subject: V4L/DVB (6123): ivtv: move ivtv.h public header to include/linux Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.h | 2 +- include/linux/ivtv.h | 72 ++++++++++++++++++++++++++++++++++ include/media/ivtv.h | 65 ------------------------------ 3 files changed, 73 insertions(+), 66 deletions(-) create mode 100644 include/linux/ivtv.h delete mode 100644 include/media/ivtv.h (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 32dfc7a859f..3bda1df63cb 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -62,7 +62,7 @@ #include #include -#include +#include /* Memory layout */ diff --git a/include/linux/ivtv.h b/include/linux/ivtv.h new file mode 100644 index 00000000000..794b8daa937 --- /dev/null +++ b/include/linux/ivtv.h @@ -0,0 +1,72 @@ +/* + Public ivtv API header + Copyright (C) 2003-2004 Kevin Thayer + Copyright (C) 2004-2007 Hans Verkuil + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __LINUX_IVTV_H__ +#define __LINUX_IVTV_H__ + +#ifdef __KERNEL__ +#include /* need __user */ +#else +#define __user +#endif +#include + +/* ivtv knows several distinct output modes: MPEG streaming, + YUV streaming, YUV updates through user DMA and the passthrough + mode. + + In order to clearly tell the driver that we are in user DMA + YUV mode you need to call IVTV_IOC_DMA_FRAME with y_source == NULL + first (althrough if you don't then the first time + DMA_FRAME is called the mode switch is done automatically). + + When you close the file handle the user DMA mode is exited again. + + While in one mode, you cannot use another mode (EBUSY is returned). + + All this means that if you want to change the YUV interlacing + for the user DMA YUV mode you first need to do call IVTV_IOC_DMA_FRAME + with y_source == NULL before you can set the correct format using + VIDIOC_S_FMT. + + Eventually all this should be replaced with a proper V4L2 API, + but for now we have to do it this way. */ + +struct ivtv_dma_frame { + enum v4l2_buf_type type; /* V4L2_BUF_TYPE_VIDEO_OUTPUT */ + __u32 pixelformat; /* 0 == same as destination */ + void __user *y_source; /* if NULL and type == V4L2_BUF_TYPE_VIDEO_OUTPUT, + then just switch to user DMA YUV output mode */ + void __user *uv_source; /* Unused for RGB pixelformats */ + struct v4l2_rect src; + struct v4l2_rect dst; + __u32 src_width; + __u32 src_height; +}; + +#define IVTV_IOC_DMA_FRAME _IOW ('V', BASE_VIDIOC_PRIVATE+0, struct ivtv_dma_frame) + +/* These are the VBI types as they appear in the embedded VBI private packets. */ +#define IVTV_SLICED_TYPE_TELETEXT_B (1) +#define IVTV_SLICED_TYPE_CAPTION_525 (4) +#define IVTV_SLICED_TYPE_WSS_625 (5) +#define IVTV_SLICED_TYPE_VPS (7) + +#endif /* _LINUX_IVTV_H */ diff --git a/include/media/ivtv.h b/include/media/ivtv.h deleted file mode 100644 index 412b48ea8ed..00000000000 --- a/include/media/ivtv.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - Public ivtv API header - Copyright (C) 2003-2004 Kevin Thayer - Copyright (C) 2004-2007 Hans Verkuil - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _LINUX_IVTV_H -#define _LINUX_IVTV_H - -/* ivtv knows several distinct output modes: MPEG streaming, - YUV streaming, YUV updates through user DMA and the passthrough - mode. - - In order to clearly tell the driver that we are in user DMA - YUV mode you need to call IVTV_IOC_DMA_FRAME with y_source == NULL - first (althrough if you don't then the first time - DMA_FRAME is called the mode switch is done automatically). - - When you close the file handle the user DMA mode is exited again. - - While in one mode, you cannot use another mode (EBUSY is returned). - - All this means that if you want to change the YUV interlacing - for the user DMA YUV mode you first need to do call IVTV_IOC_DMA_FRAME - with y_source == NULL before you can set the correct format using - VIDIOC_S_FMT. - - Eventually all this should be replaced with a proper V4L2 API, - but for now we have to do it this way. */ - -struct ivtv_dma_frame { - enum v4l2_buf_type type; /* V4L2_BUF_TYPE_VIDEO_OUTPUT */ - __u32 pixelformat; /* 0 == same as destination */ - void __user *y_source; /* if NULL and type == V4L2_BUF_TYPE_VIDEO_OUTPUT, - then just switch to user DMA YUV output mode */ - void __user *uv_source; /* Unused for RGB pixelformats */ - struct v4l2_rect src; - struct v4l2_rect dst; - __u32 src_width; - __u32 src_height; -}; - -#define IVTV_IOC_DMA_FRAME _IOW ('V', BASE_VIDIOC_PRIVATE+0, struct ivtv_dma_frame) - -/* These are the VBI types as they appear in the embedded VBI private packets. */ -#define IVTV_SLICED_TYPE_TELETEXT_B (1) -#define IVTV_SLICED_TYPE_CAPTION_525 (4) -#define IVTV_SLICED_TYPE_WSS_625 (5) -#define IVTV_SLICED_TYPE_VPS (7) - -#endif /* _LINUX_IVTV_H */ -- cgit v1.2.3-70-g09d2 From 38051450b378ef2cb51dff76a6b8299f59129172 Mon Sep 17 00:00:00 2001 From: Tyler Trafford Date: Tue, 28 Aug 2007 17:56:47 -0300 Subject: V4L/DVB (6124): cx25840: add a few 10 microsecond delays There were a couple of places in the cx25840 initialization where the datasheet called for a 10 microsecond delay, which we ignored because of the 10 usec I2C delay. Put them in anyway now that the I2C delay was decreased to 5 usec. Signed-off-by: Tyler Trafford Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx25840/cx25840-core.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index d6f8b3b6af4..90f7859bb48 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -133,7 +133,9 @@ static void init_dll1(struct i2c_client *client) cx25840_write(client, 0x159, 0x23); cx25840_write(client, 0x15a, 0x87); cx25840_write(client, 0x15b, 0x06); + udelay(10); cx25840_write(client, 0x159, 0xe1); + udelay(10); cx25840_write(client, 0x15a, 0x86); cx25840_write(client, 0x159, 0xe0); cx25840_write(client, 0x159, 0xe1); @@ -147,6 +149,7 @@ static void init_dll2(struct i2c_client *client) cx25840_write(client, 0x15d, 0xe3); cx25840_write(client, 0x15e, 0x86); cx25840_write(client, 0x15f, 0x06); + udelay(10); cx25840_write(client, 0x15d, 0xe1); cx25840_write(client, 0x15d, 0xe0); cx25840_write(client, 0x15d, 0xe1); @@ -165,9 +168,7 @@ static void cx25836_initialize(struct i2c_client *client) /* 3c. */ cx25840_and_or(client, 0x159, ~0x02, 0x02); /* 3d. */ - /* There should be a 10-us delay here, but since the - i2c bus already has a 10-us delay we don't need to do - anything */ + udelay(10); /* 3e. */ cx25840_and_or(client, 0x159, ~0x02, 0x00); /* 3f. */ -- cgit v1.2.3-70-g09d2 From b930e1d851c3ffbf82127bd0e4d72ffe94d4b7f2 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 27 Aug 2007 18:16:54 -0300 Subject: V4L/DVB (6125): whitespace cleanup: replace leading spaces with tabs There were many instances of 7-space indents spread throughout the v4l-dvb tree. This patch replaces the 7-space indents with tabs. The whitespace cleaner script doesn't catch these, because it assumes that all indents are 8-space. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/cinergyT2/cinergyT2.c | 6 +-- drivers/media/dvb/ttpci/av7110_hw.c | 28 ++++++------ drivers/media/radio/radio-terratec.c | 2 +- drivers/media/video/bt8xx/bttv-cards.c | 22 +++++----- drivers/media/video/cx88/cx88-blackbird.c | 4 +- drivers/media/video/cx88/cx88-mpeg.c | 70 +++++++++++++++--------------- drivers/media/video/cx88/cx88-tvaudio.c | 6 +-- drivers/media/video/msp3400-driver.c | 10 ++--- drivers/media/video/planb.c | 30 ++++++------- drivers/media/video/pwc/pwc-ctrl.c | 2 +- drivers/media/video/pwc/pwc-if.c | 4 +- drivers/media/video/saa7134/saa7134-alsa.c | 2 +- 12 files changed, 93 insertions(+), 93 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c index b910fa0baa0..5a12b567955 100644 --- a/drivers/media/dvb/cinergyT2/cinergyT2.c +++ b/drivers/media/dvb/cinergyT2/cinergyT2.c @@ -548,19 +548,19 @@ static unsigned int cinergyt2_poll (struct file *file, struct poll_table_struct { struct dvb_device *dvbdev = file->private_data; struct cinergyt2 *cinergyt2 = dvbdev->priv; - unsigned int mask = 0; + unsigned int mask = 0; if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem)) return -ERESTARTSYS; poll_wait(file, &cinergyt2->poll_wq, wait); - if (cinergyt2->pending_fe_events != 0) + if (cinergyt2->pending_fe_events != 0) mask |= (POLLIN | POLLRDNORM | POLLPRI); mutex_unlock(&cinergyt2->sem); - return mask; + return mask; } diff --git a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/dvb/ttpci/av7110_hw.c index 515e8232e02..a468aa2e485 100644 --- a/drivers/media/dvb/ttpci/av7110_hw.c +++ b/drivers/media/dvb/ttpci/av7110_hw.c @@ -978,24 +978,24 @@ static int OSDSetColor(struct av7110 *av7110, u8 color, u8 r, u8 g, u8 b, u8 ble static int OSDSetPalette(struct av7110 *av7110, u32 __user * colors, u8 first, u8 last) { - int i; - int length = last - first + 1; + int i; + int length = last - first + 1; - if (length * 4 > DATA_BUFF3_SIZE) - return -EINVAL; + if (length * 4 > DATA_BUFF3_SIZE) + return -EINVAL; - for (i = 0; i < length; i++) { - u32 color, blend, yuv; + for (i = 0; i < length; i++) { + u32 color, blend, yuv; - if (get_user(color, colors + i)) - return -EFAULT; - blend = (color & 0xF0000000) >> 4; - yuv = blend ? RGB2YUV(color & 0xFF, (color >> 8) & 0xFF, + if (get_user(color, colors + i)) + return -EFAULT; + blend = (color & 0xF0000000) >> 4; + yuv = blend ? RGB2YUV(color & 0xFF, (color >> 8) & 0xFF, (color >> 16) & 0xFF) | blend : 0; - yuv = ((yuv & 0xFFFF0000) >> 16) | ((yuv & 0x0000FFFF) << 16); - wdebi(av7110, DEBINOSWAP, DATA_BUFF3_BASE + i * 4, yuv, 4); - } - return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Palette, 4, + yuv = ((yuv & 0xFFFF0000) >> 16) | ((yuv & 0x0000FFFF) << 16); + wdebi(av7110, DEBINOSWAP, DATA_BUFF3_BASE + i * 4, yuv, 4); + } + return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Palette, 4, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]], first, last); diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c index 7e1911c3d54..535ffe8c810 100644 --- a/drivers/media/radio/radio-terratec.c +++ b/drivers/media/radio/radio-terratec.c @@ -173,7 +173,7 @@ static int tt_setfreq(struct tt_device *dev, unsigned long freq1) i--; p--; temp = temp/2; - } + } spin_lock(&lock); diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c index 1f4f2625395..900d18e1406 100644 --- a/drivers/media/video/bt8xx/bttv-cards.c +++ b/drivers/media/video/bt8xx/bttv-cards.c @@ -3275,15 +3275,15 @@ static void eagle_muxsel(struct bttv *btv, unsigned int input) btaor((2)<<5, ~(3<<5), BT848_IFORM); gpio_bits(3,bttv_tvcards[btv->c.type].muxsel[input&7]); - /* composite */ - /* set chroma ADC to sleep */ - btor(BT848_ADC_C_SLEEP, BT848_ADC); - /* set to composite video */ - btand(~BT848_CONTROL_COMP, BT848_E_CONTROL); - btand(~BT848_CONTROL_COMP, BT848_O_CONTROL); - - /* switch sync drive off */ - gpio_bits(LM1882_SYNC_DRIVE,LM1882_SYNC_DRIVE); + /* composite */ + /* set chroma ADC to sleep */ + btor(BT848_ADC_C_SLEEP, BT848_ADC); + /* set to composite video */ + btand(~BT848_CONTROL_COMP, BT848_E_CONTROL); + btand(~BT848_CONTROL_COMP, BT848_O_CONTROL); + + /* switch sync drive off */ + gpio_bits(LM1882_SYNC_DRIVE,LM1882_SYNC_DRIVE); } static void gvc1100_muxsel(struct bttv *btv, unsigned int input) @@ -3452,7 +3452,7 @@ void __devinit bttv_init_card2(struct bttv *btv) printk("bttv%d: radio detected by subsystem id (CPH05x)\n",btv->c.nr); } break; - case BTTV_BOARD_STB2: + case BTTV_BOARD_STB2: if (btv->cardid == 0x3060121a) { /* Fix up entry for 3DFX VoodooTV 100, which is an OEM STB card variant. */ @@ -3783,7 +3783,7 @@ static void __devinit osprey_eeprom(struct bttv *btv, const u8 ee[256]) for (i = 12; i < 21; i++) serial *= 10, serial += ee[i] - '0'; } - } else { + } else { unsigned short type; for (i = 4*16; i < 8*16; i += 16) { diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index 47007380a98..fcaf4f51293 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -1077,7 +1077,7 @@ static int mpeg_open(struct inode *inode, struct file *file) struct cx8802_driver *drv = NULL; int err; - dev = cx8802_get_device(inode); + dev = cx8802_get_device(inode); dprintk( 1, "%s\n", __FUNCTION__); @@ -1234,7 +1234,7 @@ static struct video_device cx8802_mpeg_template = .vidioc_s_tuner = vidioc_s_tuner, .vidioc_s_std = vidioc_s_std, .tvnorms = CX88_NORMS, - .current_norm = V4L2_STD_NTSC_M, + .current_norm = V4L2_STD_NTSC_M, }; /* ------------------------------------------------------------------ */ diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index 4e6a84f15d1..d302793fcfb 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -179,43 +179,43 @@ static int cx8802_restart_queue(struct cx8802_dev *dev, struct cx88_buffer *buf; struct list_head *item; - dprintk( 1, "cx8802_restart_queue\n" ); + dprintk( 1, "cx8802_restart_queue\n" ); if (list_empty(&q->active)) { - struct cx88_buffer *prev; - prev = NULL; - - dprintk(1, "cx8802_restart_queue: queue is empty\n" ); - - for (;;) { - if (list_empty(&q->queued)) - return 0; - buf = list_entry(q->queued.next, struct cx88_buffer, vb.queue); - if (NULL == prev) { - list_del(&buf->vb.queue); - list_add_tail(&buf->vb.queue,&q->active); - cx8802_start_dma(dev, q, buf); - buf->vb.state = STATE_ACTIVE; - buf->count = q->count++; - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); - dprintk(1,"[%p/%d] restart_queue - first active\n", - buf,buf->vb.i); - - } else if (prev->vb.width == buf->vb.width && - prev->vb.height == buf->vb.height && - prev->fmt == buf->fmt) { - list_del(&buf->vb.queue); - list_add_tail(&buf->vb.queue,&q->active); - buf->vb.state = STATE_ACTIVE; - buf->count = q->count++; - prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - dprintk(1,"[%p/%d] restart_queue - move to active\n", - buf,buf->vb.i); - } else { - return 0; - } - prev = buf; - } + struct cx88_buffer *prev; + prev = NULL; + + dprintk(1, "cx8802_restart_queue: queue is empty\n" ); + + for (;;) { + if (list_empty(&q->queued)) + return 0; + buf = list_entry(q->queued.next, struct cx88_buffer, vb.queue); + if (NULL == prev) { + list_del(&buf->vb.queue); + list_add_tail(&buf->vb.queue,&q->active); + cx8802_start_dma(dev, q, buf); + buf->vb.state = STATE_ACTIVE; + buf->count = q->count++; + mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + dprintk(1,"[%p/%d] restart_queue - first active\n", + buf,buf->vb.i); + + } else if (prev->vb.width == buf->vb.width && + prev->vb.height == buf->vb.height && + prev->fmt == buf->fmt) { + list_del(&buf->vb.queue); + list_add_tail(&buf->vb.queue,&q->active); + buf->vb.state = STATE_ACTIVE; + buf->count = q->count++; + prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); + dprintk(1,"[%p/%d] restart_queue - move to active\n", + buf,buf->vb.i); + } else { + return 0; + } + prev = buf; + } return 0; } diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c index 82364fb0702..76e5c78d8ae 100644 --- a/drivers/media/video/cx88/cx88-tvaudio.c +++ b/drivers/media/video/cx88/cx88-tvaudio.c @@ -798,9 +798,9 @@ void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t) core->astat = reg; /* TODO - Reading from AUD_STATUS is not enough - for auto-detecting sap/dual-fm/nicam. - Add some code here later. + Reading from AUD_STATUS is not enough + for auto-detecting sap/dual-fm/nicam. + Add some code here later. */ return; diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c index e9d400e19a5..c0c87e06259 100644 --- a/drivers/media/video/msp3400-driver.c +++ b/drivers/media/video/msp3400-driver.c @@ -244,17 +244,17 @@ int msp_write_dsp(struct i2c_client *client, int addr, int val) * ----------------------------------------------------------------------- */ static int scarts[3][9] = { - /* MASK IN1 IN2 IN3 IN4 IN1_DA IN2_DA MONO MUTE */ + /* MASK IN1 IN2 IN3 IN4 IN1_DA IN2_DA MONO MUTE */ /* SCART DSP Input select */ - { 0x0320, 0x0000, 0x0200, 0x0300, 0x0020, -1, -1, 0x0100, 0x0320 }, + { 0x0320, 0x0000, 0x0200, 0x0300, 0x0020, -1, -1, 0x0100, 0x0320 }, /* SCART1 Output select */ - { 0x0c40, 0x0440, 0x0400, 0x0000, 0x0840, 0x0c00, 0x0040, 0x0800, 0x0c40 }, + { 0x0c40, 0x0440, 0x0400, 0x0000, 0x0840, 0x0c00, 0x0040, 0x0800, 0x0c40 }, /* SCART2 Output select */ - { 0x3080, 0x1000, 0x1080, 0x2080, 0x3080, 0x0000, 0x0080, 0x2000, 0x3000 }, + { 0x3080, 0x1000, 0x1080, 0x2080, 0x3080, 0x0000, 0x0080, 0x2000, 0x3000 }, }; static char *scart_names[] = { - "in1", "in2", "in3", "in4", "in1 da", "in2 da", "mono", "mute" + "in1", "in2", "in3", "in4", "in1 da", "in2 da", "mono", "mute" }; void msp_set_scart(struct i2c_client *client, int in, int out) diff --git a/drivers/media/video/planb.c b/drivers/media/video/planb.c index 4ab1af74a97..0ef73d9d584 100644 --- a/drivers/media/video/planb.c +++ b/drivers/media/video/planb.c @@ -844,21 +844,21 @@ cmd_tab_mask_end: /*********************************/ static int palette2fmt[] = { - 0, - PLANB_GRAY, - 0, - 0, - 0, - PLANB_COLOUR32, - PLANB_COLOUR15, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, + 0, + PLANB_GRAY, + 0, + 0, + 0, + PLANB_COLOUR32, + PLANB_COLOUR15, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, }; #define PLANB_PALETTE_MAX 15 diff --git a/drivers/media/video/pwc/pwc-ctrl.c b/drivers/media/video/pwc/pwc-ctrl.c index 338ced7188f..ea53316d211 100644 --- a/drivers/media/video/pwc/pwc-ctrl.c +++ b/drivers/media/video/pwc/pwc-ctrl.c @@ -1648,7 +1648,7 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg) ARG_OUT(cmd) break; } - /* + /* case VIDIOCPWCGVIDTABLE: { ARG_DEF(struct pwc_table_init_buffer, table); diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index d3ac70a0d9c..1088ebf5744 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c @@ -126,9 +126,9 @@ static struct usb_driver pwc_driver = { static int default_size = PSZ_QCIF; static int default_fps = 10; static int default_fbufs = 3; /* Default number of frame buffers */ - int pwc_mbufs = 2; /* Default number of mmap() buffers */ + int pwc_mbufs = 2; /* Default number of mmap() buffers */ #ifdef CONFIG_USB_PWC_DEBUG - int pwc_trace = PWC_DEBUG_LEVEL; + int pwc_trace = PWC_DEBUG_LEVEL; #endif static int power_save = 0; static int led_on = 100, led_off = 0; /* defaults to LED that is on while in use */ diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c index eb5e77dd0d1..c6f7279669c 100644 --- a/drivers/media/video/saa7134/saa7134-alsa.c +++ b/drivers/media/video/saa7134/saa7134-alsa.c @@ -312,7 +312,7 @@ static int dsp_buffer_free(struct saa7134_dev *dev) dev->dmasound.blksize = 0; dev->dmasound.bufsize = 0; - return 0; + return 0; } -- cgit v1.2.3-70-g09d2 From 293197cd0f34eb6bfb5492a63a878575b69e9df4 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 28 Aug 2007 17:20:42 -0300 Subject: V4L/DVB (6126): tuner: add warning for obsolete i2c address range 0x64 thru 0x6f The tuner module has a rather aggressive range of possible i2c addresses. As per the specs available, it appears as if there are no 4-byte tuners that actually use i2c addresses in the range 0x64 thru 0x6f, yet, tuner-core claims the address range 0x60 thru 0x6f. Allowing tuner.ko to probe these addresses can cause potential damage to certain IR receivers, RTC chips or any other IC's that might otherwise reside on the i2c bus using one of these addresses. The plan is to remove these i2c addresses from the i2c address range of the tuner module. If any devices are discovered that actually do have tuners at one of these addresses, the newer i2c probing methods will be used to handle those cases. In order to collect this information and avoid any potential regressions, the following warning has been added upon successful detection of a tuner using an i2c address in the range 0x64 thru 0x6f: ====================== WARNING! ====================== Support for tuners in i2c address range 0x64 thru 0x6f will soon be dropped. This message indicates that your hardware has a {tuner name} tuner at i2c address {addr}. To ensure continued support for your device, please send a copy of this message, along with full dmesg output to v4l-dvb-maintainer@linuxtv.org Please use subject line: "obsolete tuner i2c address." ====================== WARNING! ====================== Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-core.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index baeae28f283..f505f43bb12 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -145,6 +145,27 @@ static void set_freq(struct i2c_client *c, unsigned long freq) } } +static void tuner_i2c_address_check(struct tuner *t) +{ + if ((t->type == UNSET || t->type == TUNER_ABSENT) || + ((t->i2c.addr < 0x64) || (t->i2c.addr > 0x6f))) + return; + + tuner_warn("====================== WARNING! ======================\n"); + tuner_warn("Support for tuners in i2c address range 0x64 thru 0x6f\n"); + tuner_warn("will soon be dropped. This message indicates that your\n"); + tuner_warn("hardware has a %s tuner at i2c address 0x%02x.\n", + t->i2c.name, t->i2c.addr); + tuner_warn("To ensure continued support for your device, please\n"); + tuner_warn("send a copy of this message, along with full dmesg\n"); + tuner_warn("output to v4l-dvb-maintainer@linuxtv.org\n"); + tuner_warn("Please use subject line: \"obsolete tuner i2c address.\"\n"); + tuner_warn("driver: %s, addr: 0x%02x, type: %d (%s)\n", + t->i2c.adapter->name, t->i2c.addr, t->type, + tuners[t->type].name); + tuner_warn("====================== WARNING! ======================\n"); +} + static void set_type(struct i2c_client *c, unsigned int type, unsigned int new_mode_mask, unsigned int new_config, int (*tuner_callback) (void *dev, int command,int arg)) @@ -244,6 +265,7 @@ static void set_type(struct i2c_client *c, unsigned int type, tuner_dbg("%s %s I2C addr 0x%02x with type %d used for 0x%02x\n", c->adapter->name, c->driver->driver.name, c->addr << 1, type, t->mode_mask); + tuner_i2c_address_check(t); } /* -- cgit v1.2.3-70-g09d2 From db8a695658cda21eacfa2a5e3b15e8964bfb93ef Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 21 Aug 2007 01:24:42 -0300 Subject: V4L/DVB (6127): tuner: kill i2c_client interface to tuner sub-drivers To ease the conversion of the analog tuner sub-drivers into dvb_frontend style tuner modules, we must remove the i2c_client interface. dvb_frontend style tuner modules use i2c_transfer directly on the i2c_adapter. This change only alters the interface between tuner.ko and the tuner sub-drivers. The v4l2 / i2c_client interface to tuner.ko remains intact. This patch adds inline functions tuner_i2c_xfer_send, and tuner_i2c_xfer_recv, to replace i2c_master_send and i2c_master_recv inside the tuner sub-drivers. Signed-off-by: Michael Krufky Acked-by: Hans Verkuil Acked-by: Mike Isely Acked-by: Steven Toth Acked-by: Patrick Boettcher Acked-by: Jarod Wilson Acked-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mt20xx.c | 138 ++++++++++----------- drivers/media/video/tda8290.c | 247 +++++++++++++++++++------------------ drivers/media/video/tda9887.c | 39 +++--- drivers/media/video/tea5761.c | 55 ++++++--- drivers/media/video/tea5767.c | 61 +++++---- drivers/media/video/tuner-core.c | 55 ++++----- drivers/media/video/tuner-driver.h | 37 +++--- drivers/media/video/tuner-i2c.h | 70 +++++++++++ drivers/media/video/tuner-simple.c | 57 +++++---- 9 files changed, 430 insertions(+), 329 deletions(-) create mode 100644 drivers/media/video/tuner-i2c.h (limited to 'drivers') diff --git a/drivers/media/video/mt20xx.c b/drivers/media/video/mt20xx.c index bd495c12d29..41bc91817a1 100644 --- a/drivers/media/video/mt20xx.c +++ b/drivers/media/video/mt20xx.c @@ -37,23 +37,22 @@ static char *microtune_part[] = { }; struct microtune_priv { + struct tuner_i2c_props i2c_props; + unsigned int xogc; unsigned int radio_if2; }; -static void microtune_release(struct i2c_client *c) +static void microtune_release(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(c); - kfree(t->priv); t->priv = NULL; } // IsSpurInBand()? -static int mt2032_spurcheck(struct i2c_client *c, +static int mt2032_spurcheck(struct tuner *t, int f1, int f2, int spectrum_from,int spectrum_to) { - struct tuner *t = i2c_get_clientdata(c); int n1=1,n2,f; f1=f1/1000; //scale to kHz to avoid 32bit overflows @@ -81,7 +80,7 @@ static int mt2032_spurcheck(struct i2c_client *c, return 1; } -static int mt2032_compute_freq(struct i2c_client *c, +static int mt2032_compute_freq(struct tuner *t, unsigned int rfin, unsigned int if1, unsigned int if2, unsigned int spectrum_from, @@ -90,7 +89,6 @@ static int mt2032_compute_freq(struct i2c_client *c, int *ret_sel, unsigned int xogc) //all in Hz { - struct tuner *t = i2c_get_clientdata(c); unsigned int fref,lo1,lo1n,lo1a,s,sel,lo1freq, desired_lo1, desired_lo2,lo2,lo2n,lo2a,lo2num,lo2freq; @@ -140,7 +138,7 @@ static int mt2032_compute_freq(struct i2c_client *c, return(-1); } - mt2032_spurcheck(c, lo1freq, desired_lo2, spectrum_from, spectrum_to); + mt2032_spurcheck(t, lo1freq, desired_lo2, spectrum_from, spectrum_to); // should recalculate lo1 (one step up/down) // set up MT2032 register map for transfer over i2c @@ -164,16 +162,16 @@ static int mt2032_compute_freq(struct i2c_client *c, return 0; } -static int mt2032_check_lo_lock(struct i2c_client *c) +static int mt2032_check_lo_lock(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(c); + struct microtune_priv *priv = t->priv; int try,lock=0; unsigned char buf[2]; for(try=0;try<10;try++) { buf[0]=0x0e; - i2c_master_send(c,buf,1); - i2c_master_recv(c,buf,1); + tuner_i2c_xfer_send(&priv->i2c_props,buf,1); + tuner_i2c_xfer_recv(&priv->i2c_props,buf,1); tuner_dbg("mt2032 Reg.E=0x%02x\n",buf[0]); lock=buf[0] &0x06; @@ -186,15 +184,15 @@ static int mt2032_check_lo_lock(struct i2c_client *c) return lock; } -static int mt2032_optimize_vco(struct i2c_client *c,int sel,int lock) +static int mt2032_optimize_vco(struct tuner *t,int sel,int lock) { - struct tuner *t = i2c_get_clientdata(c); + struct microtune_priv *priv = t->priv; unsigned char buf[2]; int tad1; buf[0]=0x0f; - i2c_master_send(c,buf,1); - i2c_master_recv(c,buf,1); + tuner_i2c_xfer_send(&priv->i2c_props,buf,1); + tuner_i2c_xfer_recv(&priv->i2c_props,buf,1); tuner_dbg("mt2032 Reg.F=0x%02x\n",buf[0]); tad1=buf[0]&0x07; @@ -217,58 +215,57 @@ static int mt2032_optimize_vco(struct i2c_client *c,int sel,int lock) buf[0]=0x0f; buf[1]=sel; - i2c_master_send(c,buf,2); - lock=mt2032_check_lo_lock(c); + tuner_i2c_xfer_send(&priv->i2c_props,buf,2); + lock=mt2032_check_lo_lock(t); return lock; } -static void mt2032_set_if_freq(struct i2c_client *c, unsigned int rfin, +static void mt2032_set_if_freq(struct tuner *t, unsigned int rfin, unsigned int if1, unsigned int if2, unsigned int from, unsigned int to) { unsigned char buf[21]; int lint_try,ret,sel,lock=0; - struct tuner *t = i2c_get_clientdata(c); struct microtune_priv *priv = t->priv; tuner_dbg("mt2032_set_if_freq rfin=%d if1=%d if2=%d from=%d to=%d\n", rfin,if1,if2,from,to); buf[0]=0; - ret=i2c_master_send(c,buf,1); - i2c_master_recv(c,buf,21); + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,1); + tuner_i2c_xfer_recv(&priv->i2c_props,buf,21); buf[0]=0; - ret=mt2032_compute_freq(c,rfin,if1,if2,from,to,&buf[1],&sel,priv->xogc); + ret=mt2032_compute_freq(t,rfin,if1,if2,from,to,&buf[1],&sel,priv->xogc); if (ret<0) return; // send only the relevant registers per Rev. 1.2 buf[0]=0; - ret=i2c_master_send(c,buf,4); + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,4); buf[5]=5; - ret=i2c_master_send(c,buf+5,4); + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+5,4); buf[11]=11; - ret=i2c_master_send(c,buf+11,3); + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+11,3); if(ret!=3) tuner_warn("i2c i/o error: rc == %d (should be 3)\n",ret); // wait for PLLs to lock (per manual), retry LINT if not. for(lint_try=0; lint_try<2; lint_try++) { - lock=mt2032_check_lo_lock(c); + lock=mt2032_check_lo_lock(t); if(optimize_vco) - lock=mt2032_optimize_vco(c,sel,lock); + lock=mt2032_optimize_vco(t,sel,lock); if(lock==6) break; tuner_dbg("mt2032: re-init PLLs by LINT\n"); buf[0]=7; buf[1]=0x80 +8+priv->xogc; // set LINT to re-init PLLs - i2c_master_send(c,buf,2); + tuner_i2c_xfer_send(&priv->i2c_props,buf,2); mdelay(10); buf[1]=8+priv->xogc; - i2c_master_send(c,buf,2); + tuner_i2c_xfer_send(&priv->i2c_props,buf,2); } if (lock!=6) @@ -276,15 +273,14 @@ static void mt2032_set_if_freq(struct i2c_client *c, unsigned int rfin, buf[0]=2; buf[1]=0x20; // LOGC for optimal phase noise - ret=i2c_master_send(c,buf,2); + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); if (ret!=2) tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret); } -static void mt2032_set_tv_freq(struct i2c_client *c, unsigned int freq) +static void mt2032_set_tv_freq(struct tuner *t, unsigned int freq) { - struct tuner *t = i2c_get_clientdata(c); int if2,from,to; // signal bandwidth and picture carrier @@ -300,18 +296,17 @@ static void mt2032_set_tv_freq(struct i2c_client *c, unsigned int freq) if2 = 38900*1000; } - mt2032_set_if_freq(c, freq*62500 /* freq*1000*1000/16 */, + mt2032_set_if_freq(t, freq*62500 /* freq*1000*1000/16 */, 1090*1000*1000, if2, from, to); } -static void mt2032_set_radio_freq(struct i2c_client *c, unsigned int freq) +static void mt2032_set_radio_freq(struct tuner *t, unsigned int freq) { - struct tuner *t = i2c_get_clientdata(c); struct microtune_priv *priv = t->priv; int if2 = priv->radio_if2; // per Manual for FM tuning: first if center freq. 1085 MHz - mt2032_set_if_freq(c, freq * 1000 / 16, + mt2032_set_if_freq(t, freq * 1000 / 16, 1085*1000*1000,if2,if2,if2); } @@ -322,9 +317,8 @@ static struct tuner_operations mt2032_tuner_ops = { }; // Initalization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001 -static int mt2032_init(struct i2c_client *c) +static int mt2032_init(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(c); struct microtune_priv *priv = t->priv; unsigned char buf[21]; int ret,xogc,xok=0; @@ -334,7 +328,7 @@ static int mt2032_init(struct i2c_client *c) buf[2]=0xff; buf[3]=0x0f; buf[4]=0x1f; - ret=i2c_master_send(c,buf+1,4); + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+1,4); buf[5]=6; // Index register 6 buf[6]=0xe4; @@ -342,11 +336,11 @@ static int mt2032_init(struct i2c_client *c) buf[8]=0xc3; buf[9]=0x4e; buf[10]=0xec; - ret=i2c_master_send(c,buf+5,6); + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+5,6); buf[12]=13; // Index register 13 buf[13]=0x32; - ret=i2c_master_send(c,buf+12,2); + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+12,2); // Adjust XOGC (register 7), wait for XOK xogc=7; @@ -354,8 +348,8 @@ static int mt2032_init(struct i2c_client *c) tuner_dbg("mt2032: xogc = 0x%02x\n",xogc&0x07); mdelay(10); buf[0]=0x0e; - i2c_master_send(c,buf,1); - i2c_master_recv(c,buf,1); + tuner_i2c_xfer_send(&priv->i2c_props,buf,1); + tuner_i2c_xfer_recv(&priv->i2c_props,buf,1); xok=buf[0]&0x01; tuner_dbg("mt2032: xok = 0x%02x\n",xok); if (xok == 1) break; @@ -368,7 +362,7 @@ static int mt2032_init(struct i2c_client *c) } buf[0]=0x07; buf[1]=0x88 + xogc; - ret=i2c_master_send(c,buf,2); + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); if (ret!=2) tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret); } while (xok != 1 ); @@ -379,21 +373,21 @@ static int mt2032_init(struct i2c_client *c) return(1); } -static void mt2050_set_antenna(struct i2c_client *c, unsigned char antenna) +static void mt2050_set_antenna(struct tuner *t, unsigned char antenna) { - struct tuner *t = i2c_get_clientdata(c); + struct microtune_priv *priv = t->priv; unsigned char buf[2]; int ret; buf[0] = 6; buf[1] = antenna ? 0x11 : 0x10; - ret=i2c_master_send(c,buf,2); + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); tuner_dbg("mt2050: enabled antenna connector %d\n", antenna); } -static void mt2050_set_if_freq(struct i2c_client *c,unsigned int freq, unsigned int if2) +static void mt2050_set_if_freq(struct tuner *t,unsigned int freq, unsigned int if2) { - struct tuner *t = i2c_get_clientdata(c); + struct microtune_priv *priv = t->priv; unsigned int if1=1218*1000*1000; unsigned int f_lo1,f_lo2,lo1,lo2,f_lo1_modulo,f_lo2_modulo,num1,num2,div1a,div1b,div2a,div2b; int ret; @@ -449,14 +443,13 @@ static void mt2050_set_if_freq(struct i2c_client *c,unsigned int freq, unsigned printk("\n"); } - ret=i2c_master_send(c,buf,6); + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,6); if (ret!=6) tuner_warn("i2c i/o error: rc == %d (should be 6)\n",ret); } -static void mt2050_set_tv_freq(struct i2c_client *c, unsigned int freq) +static void mt2050_set_tv_freq(struct tuner *t, unsigned int freq) { - struct tuner *t = i2c_get_clientdata(c); unsigned int if2; if (t->std & V4L2_STD_525_60) { @@ -470,18 +463,17 @@ static void mt2050_set_tv_freq(struct i2c_client *c, unsigned int freq) // DVB (pinnacle 300i) if2 = 36150*1000; } - mt2050_set_if_freq(c, freq*62500, if2); - mt2050_set_antenna(c, tv_antenna); + mt2050_set_if_freq(t, freq*62500, if2); + mt2050_set_antenna(t, tv_antenna); } -static void mt2050_set_radio_freq(struct i2c_client *c, unsigned int freq) +static void mt2050_set_radio_freq(struct tuner *t, unsigned int freq) { - struct tuner *t = i2c_get_clientdata(c); struct microtune_priv *priv = t->priv; int if2 = priv->radio_if2; - mt2050_set_if_freq(c, freq * 1000 / 16, if2); - mt2050_set_antenna(c, radio_antenna); + mt2050_set_if_freq(t, freq * 1000 / 16, if2); + mt2050_set_antenna(t, radio_antenna); } static struct tuner_operations mt2050_tuner_ops = { @@ -490,23 +482,23 @@ static struct tuner_operations mt2050_tuner_ops = { .release = microtune_release, }; -static int mt2050_init(struct i2c_client *c) +static int mt2050_init(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(c); + struct microtune_priv *priv = t->priv; unsigned char buf[2]; int ret; buf[0]=6; buf[1]=0x10; - ret=i2c_master_send(c,buf,2); // power + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); // power buf[0]=0x0f; buf[1]=0x0f; - ret=i2c_master_send(c,buf,2); // m1lo + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); // m1lo buf[0]=0x0d; - ret=i2c_master_send(c,buf,1); - i2c_master_recv(c,buf,1); + ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,1); + tuner_i2c_xfer_recv(&priv->i2c_props,buf,1); tuner_dbg("mt2050: sro is %x\n",buf[0]); @@ -515,10 +507,9 @@ static int mt2050_init(struct i2c_client *c) return 0; } -int microtune_init(struct i2c_client *c) +int microtune_init(struct tuner *t) { struct microtune_priv *priv = NULL; - struct tuner *t = i2c_get_clientdata(c); char *name; unsigned char buf[21]; int company_code; @@ -528,6 +519,9 @@ int microtune_init(struct i2c_client *c) return -ENOMEM; t->priv = priv; + priv->i2c_props.addr = t->i2c.addr; + priv->i2c_props.adap = t->i2c.adapter; + priv->radio_if2 = 10700 * 1000; /* 10.7MHz - FM radio */ memset(buf,0,sizeof(buf)); @@ -541,8 +535,8 @@ int microtune_init(struct i2c_client *c) } name = "unknown"; - i2c_master_send(c,buf,1); - i2c_master_recv(c,buf,21); + tuner_i2c_xfer_send(&priv->i2c_props,buf,1); + tuner_i2c_xfer_recv(&priv->i2c_props,buf,21); if (tuner_debug) { int i; tuner_dbg("MT20xx hexdump:"); @@ -562,10 +556,10 @@ int microtune_init(struct i2c_client *c) name = microtune_part[buf[0x13]]; switch (buf[0x13]) { case MT2032: - mt2032_init(c); + mt2032_init(t); break; case MT2050: - mt2050_init(c); + mt2050_init(t); break; default: tuner_info("microtune %s found, not (yet?) supported, sorry :-/\n", @@ -573,7 +567,7 @@ int microtune_init(struct i2c_client *c) return 0; } - strlcpy(c->name, name, sizeof(c->name)); + strlcpy(t->i2c.name, name, sizeof(t->i2c.name)); tuner_info("microtune %s found, OK\n",name); return 0; } diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index 760d22f65da..beb4a7e1d28 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -26,6 +26,8 @@ /* ---------------------------------------------------------------------- */ struct tda8290_priv { + struct tuner_i2c_props i2c_props; + unsigned char tda8290_easy_mode; unsigned char tda827x_lpsel; unsigned char tda827x_addr; @@ -79,13 +81,12 @@ static struct tda827x_data tda827x_analog[] = { { .lomax = 0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0} /* End */ }; -static void tda827x_tune(struct i2c_client *c, u16 ifc, unsigned int freq) +static void tda827x_tune(struct tuner *t, u16 ifc, unsigned int freq) { unsigned char tuner_reg[8]; unsigned char reg2[2]; u32 N; int i; - struct tuner *t = i2c_get_clientdata(c); struct tda8290_priv *priv = t->priv; struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags = 0}; @@ -114,54 +115,53 @@ static void tda827x_tune(struct i2c_client *c, u16 ifc, unsigned int freq) msg.buf = tuner_reg; msg.len = 8; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); msg.buf= reg2; msg.len = 2; reg2[0] = 0x80; reg2[1] = 0; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); reg2[0] = 0x60; reg2[1] = 0xbf; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); reg2[0] = 0x30; reg2[1] = tuner_reg[4] + 0x80; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); msleep(1); reg2[0] = 0x30; reg2[1] = tuner_reg[4] + 4; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); msleep(1); reg2[0] = 0x30; reg2[1] = tuner_reg[4]; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); msleep(550); reg2[0] = 0x30; reg2[1] = (tuner_reg[4] & 0xfc) + tda827x_analog[i].cp ; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); reg2[0] = 0x60; reg2[1] = 0x3f; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); reg2[0] = 0x80; reg2[1] = 0x08; // Vsync en - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); } -static void tda827x_agcf(struct i2c_client *c) +static void tda827x_agcf(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(c); struct tda8290_priv *priv = t->priv; unsigned char data[] = {0x80, 0x0c}; struct i2c_msg msg = {.addr = priv->tda827x_addr, .buf = data, .flags = 0, .len = 2}; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); } /* ---------------------------------------------------------------------- */ @@ -204,12 +204,12 @@ static struct tda827xa_data tda827xa_analog[] = { { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} /* End */ }; -static void tda827xa_lna_gain(struct i2c_client *c, int high) +static void tda827xa_lna_gain(struct tuner *t, int high) { - struct tuner *t = i2c_get_clientdata(c); + struct tda8290_priv *priv = t->priv; unsigned char buf[] = {0x22, 0x01}; int arg; - struct i2c_msg msg = {.addr = c->addr, .flags = 0, .buf = buf, .len = sizeof(buf)}; + struct i2c_msg msg = {.addr = priv->i2c_props.addr, .flags = 0, .buf = buf, .len = sizeof(buf)}; if (t->config) { if (high) tuner_dbg("setting LNA to high gain\n"); @@ -227,29 +227,28 @@ static void tda827xa_lna_gain(struct i2c_client *c, int high) else arg = 0; if (t->tuner_callback) - t->tuner_callback(c->adapter->algo_data, 1, arg); + t->tuner_callback(priv->i2c_props.adap->algo_data, 1, arg); buf[1] = high ? 0 : 1; if (t->config == 2) buf[1] = high ? 1 : 0; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); break; case 3: /* switch with GPIO of saa713x */ if (t->tuner_callback) - t->tuner_callback(c->adapter->algo_data, 0, high); + t->tuner_callback(priv->i2c_props.adap->algo_data, 0, high); break; } } -static void tda827xa_tune(struct i2c_client *c, u16 ifc, unsigned int freq) +static void tda827xa_tune(struct tuner *t, u16 ifc, unsigned int freq) { unsigned char tuner_reg[11]; u32 N; int i; - struct tuner *t = i2c_get_clientdata(c); struct tda8290_priv *priv = t->priv; struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags = 0, .buf = tuner_reg}; - tda827xa_lna_gain( c, 1); + tda827xa_lna_gain(t, 1); msleep(10); if (t->mode == V4L2_TUNER_RADIO) @@ -278,7 +277,7 @@ static void tda827xa_tune(struct i2c_client *c, u16 ifc, unsigned int freq) tuner_reg[9] = 0x20; tuner_reg[10] = 0x00; msg.len = 11; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); tuner_reg[0] = 0x90; tuner_reg[1] = 0xff; @@ -286,81 +285,81 @@ static void tda827xa_tune(struct i2c_client *c, u16 ifc, unsigned int freq) tuner_reg[3] = 0; tuner_reg[4] = 0x99 + (priv->tda827x_lpsel << 1); msg.len = 5; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); tuner_reg[0] = 0xa0; tuner_reg[1] = 0xc0; msg.len = 2; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); tuner_reg[0] = 0x30; tuner_reg[1] = 0x10 + tda827xa_analog[i].scr; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); msg.flags = I2C_M_RD; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); msg.flags = 0; tuner_reg[1] >>= 4; tuner_dbg("AGC2 gain is: %d\n", tuner_reg[1]); if (tuner_reg[1] < 1) - tda827xa_lna_gain( c, 0); + tda827xa_lna_gain(t, 0); msleep(100); tuner_reg[0] = 0x60; tuner_reg[1] = 0x3c; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); msleep(163); tuner_reg[0] = 0x50; tuner_reg[1] = 0x8f + (tda827xa_analog[i].gc3 << 4); - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); tuner_reg[0] = 0x80; tuner_reg[1] = 0x28; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); tuner_reg[0] = 0xb0; tuner_reg[1] = 0x01; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); tuner_reg[0] = 0xc0; tuner_reg[1] = 0x19 + (priv->tda827x_lpsel << 1); - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); } -static void tda827xa_agcf(struct i2c_client *c) +static void tda827xa_agcf(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(c); struct tda8290_priv *priv = t->priv; unsigned char data[] = {0x80, 0x2c}; struct i2c_msg msg = {.addr = priv->tda827x_addr, .buf = data, .flags = 0, .len = 2}; - i2c_transfer(c->adapter, &msg, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); } /*---------------------------------------------------------------------*/ -static void tda8290_i2c_bridge(struct i2c_client *c, int close) +static void tda8290_i2c_bridge(struct tuner *t, int close) { + struct tda8290_priv *priv = t->priv; + unsigned char enable[2] = { 0x21, 0xC0 }; unsigned char disable[2] = { 0x21, 0x00 }; unsigned char *msg; if(close) { msg = enable; - i2c_master_send(c, msg, 2); + tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); /* let the bridge stabilize */ msleep(20); } else { msg = disable; - i2c_master_send(c, msg, 2); + tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); } } /*---------------------------------------------------------------------*/ -static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq) +static int tda8290_tune(struct tuner *t, u16 ifc, unsigned int freq) { - struct tuner *t = i2c_get_clientdata(c); struct tda8290_priv *priv = t->priv; unsigned char soft_reset[] = { 0x00, 0x00 }; unsigned char easy_mode[] = { 0x01, priv->tda8290_easy_mode }; @@ -385,34 +384,34 @@ static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq) int i; tuner_dbg("tda827xa config is 0x%02x\n", t->config); - i2c_master_send(c, easy_mode, 2); - i2c_master_send(c, agc_out_on, 2); - i2c_master_send(c, soft_reset, 2); + tuner_i2c_xfer_send(&priv->i2c_props, easy_mode, 2); + tuner_i2c_xfer_send(&priv->i2c_props, agc_out_on, 2); + tuner_i2c_xfer_send(&priv->i2c_props, soft_reset, 2); msleep(1); expert_mode[1] = priv->tda8290_easy_mode + 0x80; - i2c_master_send(c, expert_mode, 2); - i2c_master_send(c, gainset_off, 2); - i2c_master_send(c, if_agc_spd, 2); + tuner_i2c_xfer_send(&priv->i2c_props, expert_mode, 2); + tuner_i2c_xfer_send(&priv->i2c_props, gainset_off, 2); + tuner_i2c_xfer_send(&priv->i2c_props, if_agc_spd, 2); if (priv->tda8290_easy_mode & 0x60) - i2c_master_send(c, adc_head_9, 2); + tuner_i2c_xfer_send(&priv->i2c_props, adc_head_9, 2); else - i2c_master_send(c, adc_head_6, 2); - i2c_master_send(c, pll_bw_nom, 2); + tuner_i2c_xfer_send(&priv->i2c_props, adc_head_6, 2); + tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_nom, 2); - tda8290_i2c_bridge(c, 1); + tda8290_i2c_bridge(t, 1); if (priv->tda827x_ver != 0) - tda827xa_tune(c, ifc, freq); + tda827xa_tune(t, ifc, freq); else - tda827x_tune(c, ifc, freq); + tda827x_tune(t, ifc, freq); for (i = 0; i < 3; i++) { - i2c_master_send(c, &addr_pll_stat, 1); - i2c_master_recv(c, &pll_stat, 1); + tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1); if (pll_stat & 0x80) { - i2c_master_send(c, &addr_adc_sat, 1); - i2c_master_recv(c, &adc_sat, 1); - i2c_master_send(c, &addr_agc_stat, 1); - i2c_master_recv(c, &agc_stat, 1); + tuner_i2c_xfer_send(&priv->i2c_props, &addr_adc_sat, 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &adc_sat, 1); + tuner_i2c_xfer_send(&priv->i2c_props, &addr_agc_stat, 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &agc_stat, 1); tuner_dbg("tda8290 is locked, AGC: %d\n", agc_stat); break; } else { @@ -424,28 +423,28 @@ static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq) if ((agc_stat > 115) || (!(pll_stat & 0x80) && (adc_sat < 20))) { tuner_dbg("adjust gain, step 1. Agc: %d, ADC stat: %d, lock: %d\n", agc_stat, adc_sat, pll_stat & 0x80); - i2c_master_send(c, gainset_2, 2); + tuner_i2c_xfer_send(&priv->i2c_props, gainset_2, 2); msleep(100); - i2c_master_send(c, &addr_agc_stat, 1); - i2c_master_recv(c, &agc_stat, 1); - i2c_master_send(c, &addr_pll_stat, 1); - i2c_master_recv(c, &pll_stat, 1); + tuner_i2c_xfer_send(&priv->i2c_props, &addr_agc_stat, 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &agc_stat, 1); + tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1); if ((agc_stat > 115) || !(pll_stat & 0x80)) { tuner_dbg("adjust gain, step 2. Agc: %d, lock: %d\n", agc_stat, pll_stat & 0x80); if (priv->tda827x_ver != 0) - tda827xa_agcf(c); + tda827xa_agcf(t); else - tda827x_agcf(c); + tda827x_agcf(t); msleep(100); - i2c_master_send(c, &addr_agc_stat, 1); - i2c_master_recv(c, &agc_stat, 1); - i2c_master_send(c, &addr_pll_stat, 1); - i2c_master_recv(c, &pll_stat, 1); + tuner_i2c_xfer_send(&priv->i2c_props, &addr_agc_stat, 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &agc_stat, 1); + tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1); if((agc_stat > 115) || !(pll_stat & 0x80)) { tuner_dbg("adjust gain, step 3. Agc: %d\n", agc_stat); - i2c_master_send(c, adc_head_12, 2); - i2c_master_send(c, pll_bw_low, 2); + tuner_i2c_xfer_send(&priv->i2c_props, adc_head_12, 2); + tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_low, 2); msleep(100); } } @@ -453,20 +452,20 @@ static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq) /* l/ l' deadlock? */ if(priv->tda8290_easy_mode & 0x60) { - i2c_master_send(c, &addr_adc_sat, 1); - i2c_master_recv(c, &adc_sat, 1); - i2c_master_send(c, &addr_pll_stat, 1); - i2c_master_recv(c, &pll_stat, 1); + tuner_i2c_xfer_send(&priv->i2c_props, &addr_adc_sat, 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &adc_sat, 1); + tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1); if ((adc_sat > 20) || !(pll_stat & 0x80)) { tuner_dbg("trying to resolve SECAM L deadlock\n"); - i2c_master_send(c, agc_rst_on, 2); + tuner_i2c_xfer_send(&priv->i2c_props, agc_rst_on, 2); msleep(40); - i2c_master_send(c, agc_rst_off, 2); + tuner_i2c_xfer_send(&priv->i2c_props, agc_rst_off, 2); } } - tda8290_i2c_bridge(c, 0); - i2c_master_send(c, if_agc_set, 2); + tda8290_i2c_bridge(t, 0); + tuner_i2c_xfer_send(&priv->i2c_props, if_agc_set, 2); return 0; } @@ -515,69 +514,69 @@ static void set_audio(struct tuner *t) tuner_dbg("setting tda8290 to system %s\n", mode); } -static void set_tv_freq(struct i2c_client *c, unsigned int freq) +static void set_tv_freq(struct tuner *t, unsigned int freq) { - struct tuner *t = i2c_get_clientdata(c); struct tda8290_priv *priv = t->priv; set_audio(t); - tda8290_tune(c, priv->sgIF, freq); + tda8290_tune(t, priv->sgIF, freq); } -static void set_radio_freq(struct i2c_client *c, unsigned int freq) +static void set_radio_freq(struct tuner *t, unsigned int freq) { /* if frequency is 5.5 MHz */ - tda8290_tune(c, 88, freq); + tda8290_tune(t, 88, freq); } -static int has_signal(struct i2c_client *c) +static int has_signal(struct tuner *t) { + struct tda8290_priv *priv = t->priv; + unsigned char i2c_get_afc[1] = { 0x1B }; unsigned char afc = 0; - i2c_master_send(c, i2c_get_afc, ARRAY_SIZE(i2c_get_afc)); - i2c_master_recv(c, &afc, 1); + tuner_i2c_xfer_send(&priv->i2c_props, i2c_get_afc, ARRAY_SIZE(i2c_get_afc)); + tuner_i2c_xfer_recv(&priv->i2c_props, &afc, 1); return (afc & 0x80)? 65535:0; } /*---------------------------------------------------------------------*/ -static void standby(struct i2c_client *c) +static void standby(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(c); struct tda8290_priv *priv = t->priv; unsigned char cb1[] = { 0x30, 0xD0 }; unsigned char tda8290_standby[] = { 0x00, 0x02 }; unsigned char tda8290_agc_tri[] = { 0x02, 0x20 }; struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, .buf=cb1, .len = 2}; - tda8290_i2c_bridge(c, 1); + tda8290_i2c_bridge(t, 1); if (priv->tda827x_ver != 0) cb1[1] = 0x90; - i2c_transfer(c->adapter, &msg, 1); - tda8290_i2c_bridge(c, 0); - i2c_master_send(c, tda8290_agc_tri, 2); - i2c_master_send(c, tda8290_standby, 2); + i2c_transfer(priv->i2c_props.adap, &msg, 1); + tda8290_i2c_bridge(t, 0); + tuner_i2c_xfer_send(&priv->i2c_props, tda8290_agc_tri, 2); + tuner_i2c_xfer_send(&priv->i2c_props, tda8290_standby, 2); } -static void tda8290_init_if(struct i2c_client *c) +static void tda8290_init_if(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(c); + struct tda8290_priv *priv = t->priv; + unsigned char set_VS[] = { 0x30, 0x6F }; unsigned char set_GP00_CF[] = { 0x20, 0x01 }; unsigned char set_GP01_CF[] = { 0x20, 0x0B }; if ((t->config == 1) || (t->config == 2)) - i2c_master_send(c, set_GP00_CF, 2); + tuner_i2c_xfer_send(&priv->i2c_props, set_GP00_CF, 2); else - i2c_master_send(c, set_GP01_CF, 2); - i2c_master_send(c, set_VS, 2); + tuner_i2c_xfer_send(&priv->i2c_props, set_GP01_CF, 2); + tuner_i2c_xfer_send(&priv->i2c_props, set_VS, 2); } -static void tda8290_init_tuner(struct i2c_client *c) +static void tda8290_init_tuner(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(c); struct tda8290_priv *priv = t->priv; unsigned char tda8275_init[] = { 0x00, 0x00, 0x00, 0x40, 0xdC, 0x04, 0xAf, 0x3F, 0x2A, 0x04, 0xFF, 0x00, 0x00, 0x40 }; @@ -588,17 +587,15 @@ static void tda8290_init_tuner(struct i2c_client *c) if (priv->tda827x_ver != 0) msg.buf = tda8275a_init; - tda8290_i2c_bridge(c, 1); - i2c_transfer(c->adapter, &msg, 1); - tda8290_i2c_bridge(c, 0); + tda8290_i2c_bridge(t, 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); + tda8290_i2c_bridge(t, 0); } /*---------------------------------------------------------------------*/ -static void tda8290_release(struct i2c_client *c) +static void tda8290_release(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(c); - kfree(t->priv); t->priv = NULL; } @@ -611,10 +608,9 @@ static struct tuner_operations tda8290_tuner_ops = { .release = tda8290_release, }; -int tda8290_init(struct i2c_client *c) +int tda8290_init(struct tuner *t) { struct tda8290_priv *priv = NULL; - struct tuner *t = i2c_get_clientdata(c); u8 data; int i, ret, tuners_found; u32 tuner_addrs; @@ -625,13 +621,16 @@ int tda8290_init(struct i2c_client *c) return -ENOMEM; t->priv = priv; - tda8290_i2c_bridge(c, 1); + priv->i2c_props.addr = t->i2c.addr; + priv->i2c_props.adap = t->i2c.adapter; + + tda8290_i2c_bridge(t, 1); /* probe for tuner chip */ tuners_found = 0; tuner_addrs = 0; for (i=0x60; i<= 0x63; i++) { msg.addr = i; - ret = i2c_transfer(c->adapter, &msg, 1); + ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); if (ret == 1) { tuners_found++; tuner_addrs = (tuner_addrs << 8) + i; @@ -641,11 +640,11 @@ int tda8290_init(struct i2c_client *c) behind the bridge and we choose the highest address that doesn't give a response now */ - tda8290_i2c_bridge(c, 0); + tda8290_i2c_bridge(t, 0); if(tuners_found > 1) for (i = 0; i < tuners_found; i++) { msg.addr = tuner_addrs & 0xff; - ret = i2c_transfer(c->adapter, &msg, 1); + ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); if(ret == 1) tuner_addrs = tuner_addrs >> 8; else @@ -662,31 +661,33 @@ int tda8290_init(struct i2c_client *c) priv->tda827x_addr = tuner_addrs; msg.addr = tuner_addrs; - tda8290_i2c_bridge(c, 1); - ret = i2c_transfer(c->adapter, &msg, 1); + tda8290_i2c_bridge(t, 1); + ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); if( ret != 1) tuner_warn ("TDA827x access failed!\n"); if ((data & 0x3c) == 0) { - strlcpy(c->name, "tda8290+75", sizeof(c->name)); + strlcpy(t->i2c.name, "tda8290+75", sizeof(t->i2c.name)); priv->tda827x_ver = 0; } else { - strlcpy(c->name, "tda8290+75a", sizeof(c->name)); + strlcpy(t->i2c.name, "tda8290+75a", sizeof(t->i2c.name)); priv->tda827x_ver = 2; } - tuner_info("type set to %s\n", c->name); + tuner_info("type set to %s\n", t->i2c.name); memcpy(&t->ops, &tda8290_tuner_ops, sizeof(struct tuner_operations)); priv->tda827x_lpsel = 0; t->mode = V4L2_TUNER_ANALOG_TV; - tda8290_init_tuner(c); - tda8290_init_if(c); + tda8290_init_tuner(t); + tda8290_init_if(t); return 0; } -int tda8290_probe(struct i2c_client *c) +int tda8290_probe(struct tuner *t) { + struct i2c_client *c = &t->i2c; + unsigned char soft_reset[] = { 0x00, 0x00 }; unsigned char easy_mode_b[] = { 0x01, 0x02 }; unsigned char easy_mode_g[] = { 0x01, 0x04 }; diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index d162bc67d44..be5387f11af 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -29,6 +29,8 @@ i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0) struct tda9887_priv { + struct tuner_i2c_props i2c_props; + unsigned char data[4]; }; @@ -510,19 +512,19 @@ static int tda9887_set_config(struct tuner *t, char *buf) static int tda9887_status(struct tuner *t) { + struct tda9887_priv *priv = t->priv; unsigned char buf[1]; int rc; memset(buf,0,sizeof(buf)); - if (1 != (rc = i2c_master_recv(&t->i2c,buf,1))) + if (1 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props,buf,1))) tda9887_info("i2c i/o error: rc == %d (should be 1)\n",rc); dump_read_message(t, buf); return 0; } -static void tda9887_configure(struct i2c_client *client) +static void tda9887_configure(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(client); struct tda9887_priv *priv = t->priv; int rc; @@ -557,7 +559,7 @@ static void tda9887_configure(struct i2c_client *client) if (tuner_debug > 1) dump_write_message(t, priv->data); - if (4 != (rc = i2c_master_send(&t->i2c,priv->data,4))) + if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,priv->data,4))) tda9887_info("i2c i/o error: rc == %d (should be 4)\n",rc); if (tuner_debug > 2) { @@ -568,16 +570,15 @@ static void tda9887_configure(struct i2c_client *client) /* ---------------------------------------------------------------------- */ -static void tda9887_tuner_status(struct i2c_client *client) +static void tda9887_tuner_status(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(client); struct tda9887_priv *priv = t->priv; tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", priv->data[1], priv->data[2], priv->data[3]); } -static int tda9887_get_afc(struct i2c_client *client) +static int tda9887_get_afc(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(client); + struct tda9887_priv *priv = t->priv; static int AFC_BITS_2_kHz[] = { -12500, -37500, -62500, -97500, -112500, -137500, -162500, -187500, @@ -587,26 +588,24 @@ static int tda9887_get_afc(struct i2c_client *client) int afc=0; __u8 reg = 0; - if (1 == i2c_master_recv(&t->i2c,®,1)) + if (1 == tuner_i2c_xfer_recv(&priv->i2c_props,®,1)) afc = AFC_BITS_2_kHz[(reg>>1)&0x0f]; return afc; } -static void tda9887_standby(struct i2c_client *client) +static void tda9887_standby(struct tuner *t) { - tda9887_configure(client); + tda9887_configure(t); } -static void tda9887_set_freq(struct i2c_client *client, unsigned int freq) +static void tda9887_set_freq(struct tuner *t, unsigned int freq) { - tda9887_configure(client); + tda9887_configure(t); } -static void tda9887_release(struct i2c_client *c) +static void tda9887_release(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(c); - kfree(t->priv); t->priv = NULL; } @@ -620,17 +619,19 @@ static struct tuner_operations tda9887_tuner_ops = { .release = tda9887_release, }; -int tda9887_tuner_init(struct i2c_client *c) +int tda9887_tuner_init(struct tuner *t) { struct tda9887_priv *priv = NULL; - struct tuner *t = i2c_get_clientdata(c); priv = kzalloc(sizeof(struct tda9887_priv), GFP_KERNEL); if (priv == NULL) return -ENOMEM; t->priv = priv; - strlcpy(c->name, "tda9887", sizeof(c->name)); + priv->i2c_props.addr = t->i2c.addr; + priv->i2c_props.adap = t->i2c.adapter; + + strlcpy(t->i2c.name, "tda9887", sizeof(t->i2c.name)); tda9887_info("tda988[5/6/7] found @ 0x%x (%s)\n", t->i2c.addr, t->i2c.driver->driver.name); diff --git a/drivers/media/video/tea5761.c b/drivers/media/video/tea5761.c index 43bdc374927..9965ba48cff 100644 --- a/drivers/media/video/tea5761.c +++ b/drivers/media/video/tea5761.c @@ -18,6 +18,10 @@ /* from tuner-core.c */ extern int tuner_debug; +struct tea5761_priv { + struct tuner_i2c_props i2c_props; +}; + /*****************************************************************************/ /*************************** @@ -114,10 +118,8 @@ extern int tuner_debug; /*****************************************************************************/ -static void set_tv_freq(struct i2c_client *c, unsigned int freq) +static void set_tv_freq(struct tuner *t, unsigned int freq) { - struct tuner *t = i2c_get_clientdata(c); - tuner_warn("This tuner doesn't support TV freq.\n"); } @@ -135,9 +137,9 @@ static void tea5761_status_dump(unsigned char *buffer) } /* Freq should be specifyed at 62.5 Hz */ -static void set_radio_freq(struct i2c_client *c, unsigned int frq) +static void set_radio_freq(struct tuner *t, unsigned int frq) { - struct tuner *t = i2c_get_clientdata(c); + struct tea5761_priv *priv = t->priv; unsigned char buffer[7] = {0, 0, 0, 0, 0, 0, 0 }; unsigned div; int rc; @@ -167,31 +169,31 @@ static void set_radio_freq(struct i2c_client *c, unsigned int frq) if (tuner_debug) tea5761_status_dump(buffer); - if (7 != (rc = i2c_master_send(c, buffer, 7))) + if (7 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 7))) tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); } -static int tea5761_signal(struct i2c_client *c) +static int tea5761_signal(struct tuner *t) { unsigned char buffer[16]; int rc; - struct tuner *t = i2c_get_clientdata(c); + struct tea5761_priv *priv = t->priv; memset(buffer, 0, sizeof(buffer)); - if (16 != (rc = i2c_master_recv(c, buffer, 16))) + if (16 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 16))) tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); return ((buffer[9] & TEA5761_TUNCHECK_LEV_MASK) << (13 - 4)); } -static int tea5761_stereo(struct i2c_client *c) +static int tea5761_stereo(struct tuner *t) { unsigned char buffer[16]; int rc; - struct tuner *t = i2c_get_clientdata(c); + struct tea5761_priv *priv = t->priv; memset(buffer, 0, sizeof(buffer)); - if (16 != (rc = i2c_master_recv(c, buffer, 16))) + if (16 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 16))) tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); rc = buffer[9] & TEA5761_TUNCHECK_STEREO; @@ -201,13 +203,13 @@ static int tea5761_stereo(struct i2c_client *c) return (rc ? V4L2_TUNER_SUB_STEREO : 0); } -int tea5761_autodetection(struct i2c_client *c) +int tea5761_autodetection(struct tuner *t) { unsigned char buffer[16]; int rc; - struct tuner *t = i2c_get_clientdata(c); + struct tuner_i2c_props i2c = { .adap = t->i2c.adapter, .addr = t->i2c.addr }; - if (16 != (rc = i2c_master_recv(c, buffer, 16))) { + if (16 != (rc = tuner_i2c_xfer_recv(&i2c, buffer, 16))) { tuner_warn("it is not a TEA5761. Received %i chars.\n", rc); return EINVAL; } @@ -220,22 +222,37 @@ int tea5761_autodetection(struct i2c_client *c) return 0; } +static void tea5761_release(struct tuner *t) +{ + kfree(t->priv); + t->priv = NULL; +} + static struct tuner_operations tea5761_tuner_ops = { .set_tv_freq = set_tv_freq, .set_radio_freq = set_radio_freq, .has_signal = tea5761_signal, .is_stereo = tea5761_stereo, + .release = tea5761_release, }; -int tea5761_tuner_init(struct i2c_client *c) +int tea5761_tuner_init(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(c); + struct tea5761_priv *priv = NULL; - if (tea5761_autodetection(c) == EINVAL) + if (tea5761_autodetection(t) == EINVAL) return EINVAL; + priv = kzalloc(sizeof(struct tea5761_priv), GFP_KERNEL); + if (priv == NULL) + return -ENOMEM; + t->priv = priv; + + priv->i2c_props.addr = t->i2c.addr; + priv->i2c_props.adap = t->i2c.adapter; + tuner_info("type set to %d (%s)\n", t->type, "Philips TEA5761HN FM Radio"); - strlcpy(c->name, "tea5761", sizeof(c->name)); + strlcpy(t->i2c.name, "tea5761", sizeof(t->i2c.name)); memcpy(&t->ops, &tea5761_tuner_ops, sizeof(struct tuner_operations)); diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c index 4c9c4e01331..5a08ec2f99f 100644 --- a/drivers/media/video/tea5767.c +++ b/drivers/media/video/tea5767.c @@ -20,6 +20,10 @@ /* from tuner-core.c */ extern int tuner_debug; +struct tea5767_priv { + struct tuner_i2c_props i2c_props; +}; + /*****************************************************************************/ /****************************** @@ -129,10 +133,8 @@ enum tea5767_xtal_freq { /*****************************************************************************/ -static void set_tv_freq(struct i2c_client *c, unsigned int freq) +static void set_tv_freq(struct tuner *t, unsigned int freq) { - struct tuner *t = i2c_get_clientdata(c); - tuner_warn("This tuner doesn't support TV freq.\n"); } @@ -190,9 +192,9 @@ static void tea5767_status_dump(unsigned char *buffer) } /* Freq should be specifyed at 62.5 Hz */ -static void set_radio_freq(struct i2c_client *c, unsigned int frq) +static void set_radio_freq(struct tuner *t, unsigned int frq) { - struct tuner *t = i2c_get_clientdata(c); + struct tea5767_priv *priv = t->priv; unsigned char buffer[5]; unsigned div; int rc; @@ -246,38 +248,38 @@ static void set_radio_freq(struct i2c_client *c, unsigned int frq) buffer[0] = (div >> 8) & 0x3f; buffer[1] = div & 0xff; - if (5 != (rc = i2c_master_send(c, buffer, 5))) + if (5 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 5))) tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); if (tuner_debug) { - if (5 != (rc = i2c_master_recv(c, buffer, 5))) + if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); else tea5767_status_dump(buffer); } } -static int tea5767_signal(struct i2c_client *c) +static int tea5767_signal(struct tuner *t) { unsigned char buffer[5]; int rc; - struct tuner *t = i2c_get_clientdata(c); + struct tea5767_priv *priv = t->priv; memset(buffer, 0, sizeof(buffer)); - if (5 != (rc = i2c_master_recv(c, buffer, 5))) + if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); return ((buffer[3] & TEA5767_ADC_LEVEL_MASK) << 8); } -static int tea5767_stereo(struct i2c_client *c) +static int tea5767_stereo(struct tuner *t) { unsigned char buffer[5]; int rc; - struct tuner *t = i2c_get_clientdata(c); + struct tea5767_priv *priv = t->priv; memset(buffer, 0, sizeof(buffer)); - if (5 != (rc = i2c_master_recv(c, buffer, 5))) + if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); rc = buffer[2] & TEA5767_STEREO_MASK; @@ -287,10 +289,10 @@ static int tea5767_stereo(struct i2c_client *c) return ((buffer[2] & TEA5767_STEREO_MASK) ? V4L2_TUNER_SUB_STEREO : 0); } -static void tea5767_standby(struct i2c_client *c) +static void tea5767_standby(struct tuner *t) { unsigned char buffer[5]; - struct tuner *t = i2c_get_clientdata(c); + struct tea5767_priv *priv = t->priv; unsigned div, rc; div = (87500 * 4 + 700 + 225 + 25) / 50; /* Set frequency to 87.5 MHz */ @@ -301,17 +303,17 @@ static void tea5767_standby(struct i2c_client *c) TEA5767_ST_NOISE_CTL | TEA5767_JAPAN_BAND | TEA5767_STDBY; buffer[4] = 0; - if (5 != (rc = i2c_master_send(c, buffer, 5))) + if (5 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 5))) tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); } -int tea5767_autodetection(struct i2c_client *c) +int tea5767_autodetection(struct tuner *t) { + struct tuner_i2c_props i2c = { .adap = t->i2c.adapter, .addr = t->i2c.addr }; unsigned char buffer[7] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; int rc; - struct tuner *t = i2c_get_clientdata(c); - if ((rc = i2c_master_recv(c, buffer, 7))< 5) { + if ((rc = tuner_i2c_xfer_send(&i2c, buffer, 7))< 5) { tuner_warn("It is not a TEA5767. Received %i bytes.\n", rc); return EINVAL; } @@ -343,20 +345,35 @@ int tea5767_autodetection(struct i2c_client *c) return 0; } +static void tea5767_release(struct tuner *t) +{ + kfree(t->priv); + t->priv = NULL; +} + static struct tuner_operations tea5767_tuner_ops = { .set_tv_freq = set_tv_freq, .set_radio_freq = set_radio_freq, .has_signal = tea5767_signal, .is_stereo = tea5767_stereo, .standby = tea5767_standby, + .release = tea5767_release, }; -int tea5767_tuner_init(struct i2c_client *c) +int tea5767_tuner_init(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(c); + struct tea5767_priv *priv = NULL; + + priv = kzalloc(sizeof(struct tea5767_priv), GFP_KERNEL); + if (priv == NULL) + return -ENOMEM; + t->priv = priv; + + priv->i2c_props.addr = t->i2c.addr; + priv->i2c_props.adap = t->i2c.adapter; tuner_info("type set to %d (%s)\n", t->type, "Philips TEA5767HN FM Radio"); - strlcpy(c->name, "tea5767", sizeof(c->name)); + strlcpy(t->i2c.name, "tea5767", sizeof(t->i2c.name)); memcpy(&t->ops, &tea5767_tuner_ops, sizeof(struct tuner_operations)); diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index f505f43bb12..0363eae800e 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -94,7 +94,7 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq) else freq = tv_range[1] * 16; } - t->ops.set_tv_freq(c, freq); + t->ops.set_tv_freq(t, freq); } static void set_radio_freq(struct i2c_client *c, unsigned int freq) @@ -121,7 +121,7 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq) freq = radio_range[1] * 16000; } - t->ops.set_radio_freq(c, freq); + t->ops.set_radio_freq(t, freq); } static void set_freq(struct i2c_client *c, unsigned long freq) @@ -199,7 +199,7 @@ static void set_type(struct i2c_client *c, unsigned int type, /* discard private data, in case set_type() was previously called */ if (t->ops.release) - t->ops.release(c); + t->ops.release(t); else { kfree(t->priv); t->priv = NULL; @@ -207,13 +207,13 @@ static void set_type(struct i2c_client *c, unsigned int type, switch (t->type) { case TUNER_MT2032: - microtune_init(c); + microtune_init(t); break; case TUNER_PHILIPS_TDA8290: - tda8290_init(c); + tda8290_init(t); break; case TUNER_TEA5767: - if (tea5767_tuner_init(c) == EINVAL) { + if (tea5767_tuner_init(t) == EINVAL) { t->type = TUNER_ABSENT; t->mode_mask = T_UNINITIALIZED; return; @@ -222,7 +222,7 @@ static void set_type(struct i2c_client *c, unsigned int type, break; #ifdef CONFIG_TUNER_TEA5761 case TUNER_TEA5761: - if (tea5761_tuner_init(c) == EINVAL) { + if (tea5761_tuner_init(t) == EINVAL) { t->type = TUNER_ABSENT; t->mode_mask = T_UNINITIALIZED; return; @@ -240,7 +240,7 @@ static void set_type(struct i2c_client *c, unsigned int type, buffer[2] = 0x86; buffer[3] = 0x54; i2c_master_send(c, buffer, 4); - default_tuner_init(c); + default_tuner_init(t); break; case TUNER_PHILIPS_TD1316: buffer[0] = 0x0b; @@ -248,13 +248,13 @@ static void set_type(struct i2c_client *c, unsigned int type, buffer[2] = 0x86; buffer[3] = 0xa4; i2c_master_send(c,buffer,4); - default_tuner_init(c); + default_tuner_init(t); break; case TUNER_TDA9887: - tda9887_tuner_init(c); + tda9887_tuner_init(t); break; default: - default_tuner_init(c); + default_tuner_init(t); break; } @@ -426,9 +426,8 @@ static int tuner_fixup_std(struct tuner *t) return 0; } -static void tuner_status(struct i2c_client *client) +static void tuner_status(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(client); unsigned long freq, freq_fraction; const char *p; @@ -451,10 +450,10 @@ static void tuner_status(struct i2c_client *client) if (t->mode != V4L2_TUNER_RADIO) return; if (t->ops.has_signal) { - tuner_info("Signal strength: %d\n", t->ops.has_signal(client)); + tuner_info("Signal strength: %d\n", t->ops.has_signal(t)); } if (t->ops.is_stereo) { - tuner_info("Stereo: %s\n", t->ops.is_stereo(client) ? "yes" : "no"); + tuner_info("Stereo: %s\n", t->ops.is_stereo(t) ? "yes" : "no"); } } @@ -503,7 +502,7 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) switch (addr) { #ifdef CONFIG_TUNER_TEA5761 case 0x10: - if (tea5761_autodetection(&t->i2c) != EINVAL) { + if (tea5761_autodetection(t) != EINVAL) { t->type = TUNER_TEA5761; t->mode_mask = T_RADIO; t->mode = T_STANDBY; @@ -520,7 +519,7 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) case 0x4b: /* If chip is not tda8290, don't register. since it can be tda9887*/ - if (tda8290_probe(&t->i2c) == 0) { + if (tda8290_probe(t) == 0) { tuner_dbg("chip at addr %x is a tda8290\n", addr); } else { /* Default is being tda9887 */ @@ -531,7 +530,7 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) } break; case 0x60: - if (tea5767_autodetection(&t->i2c) != EINVAL) { + if (tea5767_autodetection(t) != EINVAL) { t->type = TUNER_TEA5767; t->mode_mask = T_RADIO; t->mode = T_STANDBY; @@ -588,7 +587,7 @@ static int tuner_detach(struct i2c_client *client) } if (t->ops.release) - t->ops.release(client); + t->ops.release(t); else { kfree(t->priv); } @@ -613,7 +612,7 @@ static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, if (check_mode(t, cmd) == EINVAL) { t->mode = T_STANDBY; if (t->ops.standby) - t->ops.standby (client); + t->ops.standby(t); return EINVAL; } return 0; @@ -662,7 +661,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) return 0; t->mode = T_STANDBY; if (t->ops.standby) - t->ops.standby (client); + t->ops.standby(t); break; #ifdef CONFIG_VIDEO_V4L1 case VIDIOCSAUDIO: @@ -722,9 +721,9 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) if (V4L2_TUNER_RADIO == t->mode) { if (t->ops.has_signal) - vt->signal = t->ops.has_signal(client); + vt->signal = t->ops.has_signal(t); if (t->ops.is_stereo) { - if (t->ops.is_stereo(client)) + if (t->ops.is_stereo(t)) vt->flags |= VIDEO_TUNER_STEREO_ON; else @@ -753,7 +752,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) return 0; if (V4L2_TUNER_RADIO == t->mode && t->ops.is_stereo) - va->mode = t->ops.is_stereo(client) + va->mode = t->ops.is_stereo(t) ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO; return 0; } @@ -819,7 +818,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) tuner->type = t->mode; if (t->ops.get_afc) - tuner->afc=t->ops.get_afc(client); + tuner->afc=t->ops.get_afc(t); if (t->mode == V4L2_TUNER_ANALOG_TV) tuner->capability |= V4L2_TUNER_CAP_NORM; if (t->mode != V4L2_TUNER_RADIO) { @@ -830,12 +829,12 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) /* radio mode */ if (t->ops.has_signal) - tuner->signal = t->ops.has_signal(client); + tuner->signal = t->ops.has_signal(t); tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; if (t->ops.is_stereo) { - tuner->rxsubchans = t->ops.is_stereo(client) ? + tuner->rxsubchans = t->ops.is_stereo(t) ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; } @@ -864,7 +863,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) } case VIDIOC_LOG_STATUS: if (t->ops.tuner_status) - t->ops.tuner_status(client); + t->ops.tuner_status(t); break; } diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index 145045561a5..3cd1d446f2f 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -24,18 +24,21 @@ #include #include +#include "tuner-i2c.h" extern unsigned const int tuner_count; +struct tuner; + struct tuner_operations { - void (*set_tv_freq)(struct i2c_client *c, unsigned int freq); - void (*set_radio_freq)(struct i2c_client *c, unsigned int freq); - int (*has_signal)(struct i2c_client *c); - int (*is_stereo)(struct i2c_client *c); - int (*get_afc)(struct i2c_client *c); - void (*tuner_status)(struct i2c_client *c); - void (*standby)(struct i2c_client *c); - void (*release)(struct i2c_client *c); + void (*set_tv_freq)(struct tuner *t, unsigned int freq); + void (*set_radio_freq)(struct tuner *t, unsigned int freq); + int (*has_signal)(struct tuner *t); + int (*is_stereo)(struct tuner *t); + int (*get_afc)(struct tuner *t); + void (*tuner_status)(struct tuner *t); + void (*standby)(struct tuner *t); + void (*release)(struct tuner *t); }; struct tuner { @@ -66,20 +69,20 @@ struct tuner { /* ------------------------------------------------------------------------ */ -extern int default_tuner_init(struct i2c_client *c); +extern int default_tuner_init(struct tuner *t); -extern int tda9887_tuner_init(struct i2c_client *c); +extern int tda9887_tuner_init(struct tuner *t); -extern int microtune_init(struct i2c_client *c); +extern int microtune_init(struct tuner *t); -extern int tda8290_init(struct i2c_client *c); -extern int tda8290_probe(struct i2c_client *c); +extern int tda8290_init(struct tuner *t); +extern int tda8290_probe(struct tuner *t); -extern int tea5761_tuner_init(struct i2c_client *c); -extern int tea5761_autodetection(struct i2c_client *c); +extern int tea5761_tuner_init(struct tuner *t); +extern int tea5761_autodetection(struct tuner *t); -extern int tea5767_autodetection(struct i2c_client *c); -extern int tea5767_tuner_init(struct i2c_client *c); +extern int tea5767_autodetection(struct tuner *t); +extern int tea5767_tuner_init(struct tuner *t); /* ------------------------------------------------------------------------ */ diff --git a/drivers/media/video/tuner-i2c.h b/drivers/media/video/tuner-i2c.h new file mode 100644 index 00000000000..159019ec337 --- /dev/null +++ b/drivers/media/video/tuner-i2c.h @@ -0,0 +1,70 @@ +/* + tuner-i2c.h - i2c interface for different tuners + + Copyright (C) 2007 Michael Krufky (mkrufky@linuxtv.org) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __TUNER_I2C_H__ +#define __TUNER_I2C_H__ + +#include + +struct tuner_i2c_props { + u8 addr; + struct i2c_adapter *adap; +}; + +static inline int tuner_i2c_xfer_send(struct tuner_i2c_props *props, char *buf, int len) +{ + struct i2c_msg msg = { .addr = props->addr, .flags = 0, + .buf = buf, .len = len }; + int ret = i2c_transfer(props->adap, &msg, 1); + + return (ret == 1) ? len : ret; +} + +static inline int tuner_i2c_xfer_recv(struct tuner_i2c_props *props, char *buf, int len) +{ + struct i2c_msg msg = { .addr = props->addr, .flags = I2C_M_RD, + .buf = buf, .len = len }; + int ret = i2c_transfer(props->adap, &msg, 1); + + return (ret == 1) ? len : ret; +} + +#ifndef __TUNER_DRIVER_H__ +#define tuner_warn(fmt, arg...) do {\ + printk(KERN_WARNING PREFIX "%d-%04x: " fmt, \ + i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr , ##arg); } while (0) +#define tuner_info(fmt, arg...) do {\ + printk(KERN_INFO PREFIX "%d-%04x: " fmt, \ + i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr , ##arg); } while (0) +#define tuner_dbg(fmt, arg...) do {\ + if ((debug)) \ + printk(KERN_DEBUG PREFIX "%d-%04x: " fmt, \ + i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr , ##arg); } while (0) +#endif /* __TUNER_DRIVER_H__ */ + +#endif /* __TUNER_I2C_H__ */ + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index 572f22423b9..eca2ff249a3 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -84,31 +84,32 @@ MODULE_PARM_DESC(offset,"Allows to specify an offset for tuner"); struct tuner_simple_priv { u16 last_div; + struct tuner_i2c_props i2c_props; }; /* ---------------------------------------------------------------------- */ -static int tuner_getstatus(struct i2c_client *c) +static int tuner_getstatus(struct tuner *t) { + struct tuner_simple_priv *priv = t->priv; unsigned char byte; - if (1 != i2c_master_recv(c,&byte,1)) + if (1 != tuner_i2c_xfer_recv(&priv->i2c_props,&byte,1)) return 0; return byte; } -static int tuner_signal(struct i2c_client *c) +static int tuner_signal(struct tuner *t) { - return (tuner_getstatus(c) & TUNER_SIGNAL) << 13; + return (tuner_getstatus(t) & TUNER_SIGNAL) << 13; } -static int tuner_stereo(struct i2c_client *c) +static int tuner_stereo(struct tuner *t) { int stereo, status; - struct tuner *t = i2c_get_clientdata(c); - status = tuner_getstatus (c); + status = tuner_getstatus(t); switch (t->type) { case TUNER_PHILIPS_FM1216ME_MK3: @@ -127,9 +128,8 @@ static int tuner_stereo(struct i2c_client *c) /* ---------------------------------------------------------------------- */ -static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) +static void default_set_tv_freq(struct tuner *t, unsigned int freq) { - struct tuner *t = i2c_get_clientdata(c); struct tuner_simple_priv *priv = t->priv; u8 config, cb, tuneraddr; u16 div; @@ -285,13 +285,13 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) buffer[1] = 0x04; } /* set to the correct mode (analog or digital) */ - tuneraddr = c->addr; - c->addr = 0x0a; - if (2 != (rc = i2c_master_send(c,&buffer[0],2))) + tuneraddr = priv->i2c_props.addr; + priv->i2c_props.addr = 0x0a; + if (2 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,&buffer[0],2))) tuner_warn("i2c i/o error: rc == %d (should be 2)\n",rc); - if (2 != (rc = i2c_master_send(c,&buffer[2],2))) + if (2 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,&buffer[2],2))) tuner_warn("i2c i/o error: rc == %d (should be 2)\n",rc); - c->addr = tuneraddr; + priv->i2c_props.addr = tuneraddr; /* FIXME: input */ break; } @@ -345,12 +345,12 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) } if (params->default_pll_gating_18) config |= TDA9887_GATING_18; - i2c_clients_command(c->adapter, TDA9887_SET_CONFIG, &config); + i2c_clients_command(priv->i2c_props.adap, TDA9887_SET_CONFIG, &config); } tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n", buffer[0],buffer[1],buffer[2],buffer[3]); - if (4 != (rc = i2c_master_send(c,buffer,4))) + if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,4))) tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc); switch (t->type) { @@ -362,7 +362,7 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) buffer[1] = 0x20; tuner_dbg("tv 0x%02x 0x%02x\n",buffer[0],buffer[1]); - if (2 != (rc = i2c_master_send(c,buffer,2))) + if (2 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,2))) tuner_warn("i2c i/o error: rc == %d (should be 2)\n",rc); break; case TUNER_MICROTUNE_4042FI5: @@ -375,7 +375,7 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) for (;;) { if (time_after(jiffies,timeout)) return; - if (1 != (rc = i2c_master_recv(c,&status_byte,1))) { + if (1 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props,&status_byte,1))) { tuner_warn("i2c i/o read error: rc == %d (should be 1)\n",rc); break; } @@ -393,17 +393,16 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n", buffer[0],buffer[1],buffer[2],buffer[3]); - if (4 != (rc = i2c_master_send(c,buffer,4))) + if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,4))) tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc); break; } } } -static void default_set_radio_freq(struct i2c_client *c, unsigned int freq) +static void default_set_radio_freq(struct tuner *t, unsigned int freq) { struct tunertype *tun; - struct tuner *t = i2c_get_clientdata(c); struct tuner_simple_priv *priv = t->priv; u8 buffer[4]; u16 div; @@ -498,16 +497,14 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq) config |= TDA9887_GAIN_NORMAL; if (params->radio_if == 2) config |= TDA9887_RIF_41_3; - i2c_clients_command(c->adapter, TDA9887_SET_CONFIG, &config); + i2c_clients_command(priv->i2c_props.adap, TDA9887_SET_CONFIG, &config); } - if (4 != (rc = i2c_master_send(c,buffer,4))) + if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,4))) tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc); } -static void tuner_release(struct i2c_client *c) +static void tuner_release(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(c); - kfree(t->priv); t->priv = NULL; } @@ -520,9 +517,8 @@ static struct tuner_operations simple_tuner_ops = { .release = tuner_release, }; -int default_tuner_init(struct i2c_client *c) +int default_tuner_init(struct tuner *t) { - struct tuner *t = i2c_get_clientdata(c); struct tuner_simple_priv *priv = NULL; priv = kzalloc(sizeof(struct tuner_simple_priv), GFP_KERNEL); @@ -530,9 +526,12 @@ int default_tuner_init(struct i2c_client *c) return -ENOMEM; t->priv = priv; + priv->i2c_props.addr = t->i2c.addr; + priv->i2c_props.adap = t->i2c.adapter; + tuner_info("type set to %d (%s)\n", t->type, tuners[t->type].name); - strlcpy(c->name, tuners[t->type].name, sizeof(c->name)); + strlcpy(t->i2c.name, tuners[t->type].name, sizeof(t->i2c.name)); memcpy(&t->ops, &simple_tuner_ops, sizeof(struct tuner_operations)); -- cgit v1.2.3-70-g09d2 From e18f9444bda60a67e6feef00c354f8de0cdaeba7 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 21 Aug 2007 01:25:48 -0300 Subject: V4L/DVB (6128): hybrid tuner refactoring core changes, phase 1 Prepare tuner-core for conversion of tuner sub-drivers into dvb_frontend modules Signed-off-by: Michael Krufky Acked-by: Hans Verkuil Acked-by: Mike Isely Acked-by: Steven Toth Acked-by: Patrick Boettcher Acked-by: Jarod Wilson Acked-by: Oliver Endriss Acked-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.h | 9 +++ drivers/media/video/tuner-core.c | 129 +++++++++++++++++++++++++----- drivers/media/video/tuner-driver.h | 3 + 3 files changed, 123 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index f95de63d0e2..ffb83b0f68c 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -62,6 +62,13 @@ struct dvb_tuner_info { u32 bandwidth_step; }; +struct analog_parameters { + unsigned int frequency; + unsigned int mode; + unsigned int audmode; + u64 std; +}; + struct dvb_tuner_ops { struct dvb_tuner_info info; @@ -72,6 +79,7 @@ struct dvb_tuner_ops { /** This is for simple PLLs - set all parameters in one go. */ int (*set_params)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p); + int (*set_analog_params)(struct dvb_frontend *fe, struct analog_parameters *p); /** This is support for demods like the mt352 - fills out the supplied buffer with what to write. */ int (*calc_regs)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p, u8 *buf, int buf_len); @@ -80,6 +88,7 @@ struct dvb_tuner_ops { int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth); #define TUNER_STATUS_LOCKED 1 +#define TUNER_STATUS_STEREO 2 int (*get_status)(struct dvb_frontend *fe, u32 *status); /** These are provided seperately from set_params in order to facilitate silicon diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 0363eae800e..183bbb9ba6a 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -70,6 +70,40 @@ static struct i2c_client client_template; /* ---------------------------------------------------------------------- */ +static void fe_set_freq(struct tuner *t, unsigned int freq) +{ + struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; + + struct analog_parameters params = { + .frequency = freq, + .mode = t->mode, + .audmode = t->audmode, + .std = t->std + }; + + if (NULL == fe_tuner_ops->set_analog_params) { + tuner_warn("Tuner frontend module has no way to set freq\n"); + return; + } + fe_tuner_ops->set_analog_params(&t->fe, ¶ms); +} + +static void fe_release(struct tuner *t) +{ + struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; + + if (fe_tuner_ops->release) + fe_tuner_ops->release(&t->fe); +} + +static void fe_standby(struct tuner *t) +{ + struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; + + if (fe_tuner_ops->sleep) + fe_tuner_ops->sleep(&t->fe); +} + /* Set tuner frequency, freq in Units of 62.5kHz = 1/16MHz */ static void set_tv_freq(struct i2c_client *c, unsigned int freq) { @@ -171,6 +205,7 @@ static void set_type(struct i2c_client *c, unsigned int type, int (*tuner_callback) (void *dev, int command,int arg)) { struct tuner *t = i2c_get_clientdata(c); + struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; unsigned char buffer[4]; if (type == UNSET || type == TUNER_ABSENT) { @@ -258,6 +293,17 @@ static void set_type(struct i2c_client *c, unsigned int type, break; } + if (fe_tuner_ops->set_analog_params) { + strlcpy(t->i2c.name, fe_tuner_ops->info.name, sizeof(t->i2c.name)); + + t->ops.set_tv_freq = fe_set_freq; + t->ops.set_radio_freq = fe_set_freq; + t->ops.standby = fe_standby; + t->ops.release = fe_release; + } + + tuner_info("type set to %s\n", t->i2c.name); + if (t->mode_mask == T_UNINITIALIZED) t->mode_mask = new_mode_mask; @@ -429,6 +475,7 @@ static int tuner_fixup_std(struct tuner *t) static void tuner_status(struct tuner *t) { unsigned long freq, freq_fraction; + struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; const char *p; switch (t->mode) { @@ -449,6 +496,15 @@ static void tuner_status(struct tuner *t) tuner_info("Standard: 0x%08lx\n", (unsigned long)t->std); if (t->mode != V4L2_TUNER_RADIO) return; + if (fe_tuner_ops->get_status) { + u32 tuner_status; + + fe_tuner_ops->get_status(&t->fe, &tuner_status); + if (tuner_status & TUNER_STATUS_LOCKED) + tuner_info("Tuner is locked.\n"); + if (tuner_status & TUNER_STATUS_STEREO) + tuner_info("Stereo: yes\n"); + } if (t->ops.has_signal) { tuner_info("Signal strength: %d\n", t->ops.has_signal(t)); } @@ -634,6 +690,7 @@ static inline int check_v4l2(struct tuner *t) static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct tuner *t = i2c_get_clientdata(client); + struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; if (tuner_debug>1) v4l_i2c_print_ioctl(&(t->i2c),cmd); @@ -720,15 +777,27 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) return 0; if (V4L2_TUNER_RADIO == t->mode) { - if (t->ops.has_signal) - vt->signal = t->ops.has_signal(t); - if (t->ops.is_stereo) { - if (t->ops.is_stereo(t)) - vt->flags |= - VIDEO_TUNER_STEREO_ON; - else - vt->flags &= - ~VIDEO_TUNER_STEREO_ON; + if (fe_tuner_ops->get_status) { + u32 tuner_status; + + fe_tuner_ops->get_status(&t->fe, &tuner_status); + if (tuner_status & TUNER_STATUS_STEREO) + vt->flags |= VIDEO_TUNER_STEREO_ON; + else + vt->flags &= ~VIDEO_TUNER_STEREO_ON; + vt->signal = tuner_status & TUNER_STATUS_LOCKED + ? 65535 : 0; + } else { + if (t->ops.is_stereo) { + if (t->ops.is_stereo(t)) + vt->flags |= + VIDEO_TUNER_STEREO_ON; + else + vt->flags &= + ~VIDEO_TUNER_STEREO_ON; + } + if (t->ops.has_signal) + vt->signal = t->ops.has_signal(t); } vt->flags |= VIDEO_TUNER_LOW; /* Allow freqs at 62.5 Hz */ @@ -751,9 +820,17 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) if (check_v4l2(t) == EINVAL) return 0; - if (V4L2_TUNER_RADIO == t->mode && t->ops.is_stereo) - va->mode = t->ops.is_stereo(t) - ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO; + if (V4L2_TUNER_RADIO == t->mode) { + if (fe_tuner_ops->get_status) { + u32 tuner_status; + + fe_tuner_ops->get_status(&t->fe, &tuner_status); + va->mode = (tuner_status & TUNER_STATUS_STEREO) + ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO; + } else if (t->ops.is_stereo) + va->mode = t->ops.is_stereo(t) + ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO; + } return 0; } #endif @@ -804,6 +881,15 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) return 0; switch_v4l2(); f->type = t->mode; + if (fe_tuner_ops->get_frequency) { + u32 abs_freq; + + fe_tuner_ops->get_frequency(&t->fe, &abs_freq); + f->frequency = (V4L2_TUNER_RADIO == t->mode) ? + (abs_freq * 2 + 125/2) / 125 : + (abs_freq + 62500/2) / 62500; + break; + } f->frequency = (V4L2_TUNER_RADIO == t->mode) ? t->radio_freq : t->tv_freq; break; @@ -828,16 +914,23 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) } /* radio mode */ - if (t->ops.has_signal) - tuner->signal = t->ops.has_signal(t); - tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; - if (t->ops.is_stereo) { - tuner->rxsubchans = t->ops.is_stereo(t) ? + if (fe_tuner_ops->get_status) { + u32 tuner_status; + + fe_tuner_ops->get_status(&t->fe, &tuner_status); + tuner->rxsubchans = (tuner_status & TUNER_STATUS_STEREO) ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; + tuner->signal = tuner_status & TUNER_STATUS_LOCKED ? 65535 : 0; + } else { + if (t->ops.is_stereo) { + tuner->rxsubchans = t->ops.is_stereo(t) ? + V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; + } + if (t->ops.has_signal) + tuner->signal = t->ops.has_signal(t); } - tuner->capability |= V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; tuner->audmode = t->audmode; diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index 3cd1d446f2f..d4c02b4abe7 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -25,6 +25,7 @@ #include #include #include "tuner-i2c.h" +#include "dvb_frontend.h" extern unsigned const int tuner_count; @@ -58,6 +59,8 @@ struct tuner { int using_v4l2; void *priv; + struct dvb_frontend fe; + /* used by tda9887 */ unsigned int tda9887_config; -- cgit v1.2.3-70-g09d2 From 910bb3e3c5a5d8ed5028846728efc6a375d200eb Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 27 Aug 2007 21:22:20 -0300 Subject: V4L/DVB (6129): tda8290: convert from tuner sub-driver into dvb_frontend module Signed-off-by: Michael Krufky Acked-by: Hans Verkuil Acked-by: Mike Isely Acked-by: Steven Toth Acked-by: Patrick Boettcher Acked-by: Jarod Wilson Acked-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tda8290.c | 367 ++++++++++++++++++++++--------------- drivers/media/video/tda8290.h | 35 ++++ drivers/media/video/tuner-core.c | 16 +- drivers/media/video/tuner-driver.h | 3 - 4 files changed, 270 insertions(+), 151 deletions(-) create mode 100644 drivers/media/video/tda8290.h (limited to 'drivers') diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index beb4a7e1d28..ec731d6fbfb 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -16,12 +16,21 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + This "tda8290" module was split apart from the original "tuner" module. */ #include #include #include -#include "tuner-driver.h" +#include "tuner-i2c.h" +#include "tda8290.h" + +static int debug = 0; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable verbose debug messages"); + +#define PREFIX "tda8290 " /* ---------------------------------------------------------------------- */ @@ -33,6 +42,11 @@ struct tda8290_priv { unsigned char tda827x_addr; unsigned char tda827x_ver; unsigned int sgIF; + + u32 frequency; + + unsigned int *lna_cfg; + int (*tuner_callback) (void *dev, int command,int arg); }; /* ---------------------------------------------------------------------- */ @@ -81,19 +95,21 @@ static struct tda827x_data tda827x_analog[] = { { .lomax = 0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0} /* End */ }; -static void tda827x_tune(struct tuner *t, u16 ifc, unsigned int freq) +static void tda827x_set_analog_params(struct dvb_frontend *fe, + struct analog_parameters *params) { unsigned char tuner_reg[8]; unsigned char reg2[2]; u32 N; int i; - struct tda8290_priv *priv = t->priv; + struct tda8290_priv *priv = fe->tuner_priv; struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags = 0}; + unsigned int freq = params->frequency; - if (t->mode == V4L2_TUNER_RADIO) + if (params->mode == V4L2_TUNER_RADIO) freq = freq / 1000; - N = freq + ifc; + N = freq + priv->sgIF; i = 0; while (tda827x_analog[i].lomax < N) { if(tda827x_analog[i + 1].lomax == 0) @@ -155,9 +171,9 @@ static void tda827x_tune(struct tuner *t, u16 ifc, unsigned int freq) i2c_transfer(priv->i2c_props.adap, &msg, 1); } -static void tda827x_agcf(struct tuner *t) +static void tda827x_agcf(struct dvb_frontend *fe) { - struct tda8290_priv *priv = t->priv; + struct tda8290_priv *priv = fe->tuner_priv; unsigned char data[] = {0x80, 0x0c}; struct i2c_msg msg = {.addr = priv->tda827x_addr, .buf = data, .flags = 0, .len = 2}; @@ -204,57 +220,64 @@ static struct tda827xa_data tda827xa_analog[] = { { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} /* End */ }; -static void tda827xa_lna_gain(struct tuner *t, int high) +static void tda827xa_lna_gain(struct dvb_frontend *fe, int high, + struct analog_parameters *params) { - struct tda8290_priv *priv = t->priv; + struct tda8290_priv *priv = fe->tuner_priv; unsigned char buf[] = {0x22, 0x01}; int arg; struct i2c_msg msg = {.addr = priv->i2c_props.addr, .flags = 0, .buf = buf, .len = sizeof(buf)}; - if (t->config) { + + if ((priv->lna_cfg == NULL) || (priv->tuner_callback == NULL)) + return; + + if (*priv->lna_cfg) { if (high) tuner_dbg("setting LNA to high gain\n"); else tuner_dbg("setting LNA to low gain\n"); } - switch (t->config) { + switch (*priv->lna_cfg) { case 0: /* no LNA */ break; case 1: /* switch is GPIO 0 of tda8290 */ case 2: /* turn Vsync on */ - if (t->std & V4L2_STD_MN) + if (params->std & V4L2_STD_MN) arg = 1; else arg = 0; - if (t->tuner_callback) - t->tuner_callback(priv->i2c_props.adap->algo_data, 1, arg); + if (priv->tuner_callback) + priv->tuner_callback(priv->i2c_props.adap->algo_data, 1, arg); buf[1] = high ? 0 : 1; - if (t->config == 2) + if (*priv->lna_cfg == 2) buf[1] = high ? 1 : 0; i2c_transfer(priv->i2c_props.adap, &msg, 1); break; case 3: /* switch with GPIO of saa713x */ - if (t->tuner_callback) - t->tuner_callback(priv->i2c_props.adap->algo_data, 0, high); + if (priv->tuner_callback) + priv->tuner_callback(priv->i2c_props.adap->algo_data, 0, high); break; } } -static void tda827xa_tune(struct tuner *t, u16 ifc, unsigned int freq) +static void tda827xa_set_analog_params(struct dvb_frontend *fe, + struct analog_parameters *params) { unsigned char tuner_reg[11]; u32 N; int i; - struct tda8290_priv *priv = t->priv; + struct tda8290_priv *priv = fe->tuner_priv; struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags = 0, .buf = tuner_reg}; + unsigned int freq = params->frequency; - tda827xa_lna_gain(t, 1); + tda827xa_lna_gain(fe, 1, params); msleep(10); - if (t->mode == V4L2_TUNER_RADIO) + if (params->mode == V4L2_TUNER_RADIO) freq = freq / 1000; - N = freq + ifc; + N = freq + priv->sgIF; i = 0; while (tda827xa_analog[i].lomax < N) { if(tda827xa_analog[i + 1].lomax == 0) @@ -302,7 +325,7 @@ static void tda827xa_tune(struct tuner *t, u16 ifc, unsigned int freq) tuner_reg[1] >>= 4; tuner_dbg("AGC2 gain is: %d\n", tuner_reg[1]); if (tuner_reg[1] < 1) - tda827xa_lna_gain(t, 0); + tda827xa_lna_gain(fe, 0, params); msleep(100); tuner_reg[0] = 0x60; @@ -327,9 +350,9 @@ static void tda827xa_tune(struct tuner *t, u16 ifc, unsigned int freq) i2c_transfer(priv->i2c_props.adap, &msg, 1); } -static void tda827xa_agcf(struct tuner *t) +static void tda827xa_agcf(struct dvb_frontend *fe) { - struct tda8290_priv *priv = t->priv; + struct tda8290_priv *priv = fe->tuner_priv; unsigned char data[] = {0x80, 0x2c}; struct i2c_msg msg = {.addr = priv->tda827x_addr, .buf = data, .flags = 0, .len = 2}; @@ -338,9 +361,9 @@ static void tda827xa_agcf(struct tuner *t) /*---------------------------------------------------------------------*/ -static void tda8290_i2c_bridge(struct tuner *t, int close) +static void tda8290_i2c_bridge(struct dvb_frontend *fe, int close) { - struct tda8290_priv *priv = t->priv; + struct tda8290_priv *priv = fe->tuner_priv; unsigned char enable[2] = { 0x21, 0xC0 }; unsigned char disable[2] = { 0x21, 0x00 }; @@ -358,9 +381,58 @@ static void tda8290_i2c_bridge(struct tuner *t, int close) /*---------------------------------------------------------------------*/ -static int tda8290_tune(struct tuner *t, u16 ifc, unsigned int freq) +static void set_audio(struct dvb_frontend *fe, + struct analog_parameters *params) { - struct tda8290_priv *priv = t->priv; + struct tda8290_priv *priv = fe->tuner_priv; + char* mode; + + priv->tda827x_lpsel = 0; + if (params->std & V4L2_STD_MN) { + priv->sgIF = 92; + priv->tda8290_easy_mode = 0x01; + priv->tda827x_lpsel = 1; + mode = "MN"; + } else if (params->std & V4L2_STD_B) { + priv->sgIF = 108; + priv->tda8290_easy_mode = 0x02; + mode = "B"; + } else if (params->std & V4L2_STD_GH) { + priv->sgIF = 124; + priv->tda8290_easy_mode = 0x04; + mode = "GH"; + } else if (params->std & V4L2_STD_PAL_I) { + priv->sgIF = 124; + priv->tda8290_easy_mode = 0x08; + mode = "I"; + } else if (params->std & V4L2_STD_DK) { + priv->sgIF = 124; + priv->tda8290_easy_mode = 0x10; + mode = "DK"; + } else if (params->std & V4L2_STD_SECAM_L) { + priv->sgIF = 124; + priv->tda8290_easy_mode = 0x20; + mode = "L"; + } else if (params->std & V4L2_STD_SECAM_LC) { + priv->sgIF = 20; + priv->tda8290_easy_mode = 0x40; + mode = "LC"; + } else { + priv->sgIF = 124; + priv->tda8290_easy_mode = 0x10; + mode = "xx"; + } + + if (params->mode == V4L2_TUNER_RADIO) + priv->sgIF = 88; /* if frequency is 5.5 MHz */ + + tuner_dbg("setting tda8290 to system %s\n", mode); +} + +static int tda8290_set_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct tda8290_priv *priv = fe->tuner_priv; unsigned char soft_reset[] = { 0x00, 0x00 }; unsigned char easy_mode[] = { 0x01, priv->tda8290_easy_mode }; unsigned char expert_mode[] = { 0x01, 0x80 }; @@ -383,7 +455,10 @@ static int tda8290_tune(struct tuner *t, u16 ifc, unsigned int freq) pll_stat; int i; - tuner_dbg("tda827xa config is 0x%02x\n", t->config); + set_audio(fe, params); + + if (priv->lna_cfg) + tuner_dbg("tda827xa config is 0x%02x\n", *priv->lna_cfg); tuner_i2c_xfer_send(&priv->i2c_props, easy_mode, 2); tuner_i2c_xfer_send(&priv->i2c_props, agc_out_on, 2); tuner_i2c_xfer_send(&priv->i2c_props, soft_reset, 2); @@ -399,11 +474,11 @@ static int tda8290_tune(struct tuner *t, u16 ifc, unsigned int freq) tuner_i2c_xfer_send(&priv->i2c_props, adc_head_6, 2); tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_nom, 2); - tda8290_i2c_bridge(t, 1); + tda8290_i2c_bridge(fe, 1); if (priv->tda827x_ver != 0) - tda827xa_tune(t, ifc, freq); + tda827xa_set_analog_params(fe, params); else - tda827x_tune(t, ifc, freq); + tda827x_set_analog_params(fe, params); for (i = 0; i < 3; i++) { tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1); tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1); @@ -433,9 +508,9 @@ static int tda8290_tune(struct tuner *t, u16 ifc, unsigned int freq) tuner_dbg("adjust gain, step 2. Agc: %d, lock: %d\n", agc_stat, pll_stat & 0x80); if (priv->tda827x_ver != 0) - tda827xa_agcf(t); + tda827xa_agcf(fe); else - tda827x_agcf(t); + tda827x_agcf(fe); msleep(100); tuner_i2c_xfer_send(&priv->i2c_props, &addr_agc_stat, 1); tuner_i2c_xfer_recv(&priv->i2c_props, &agc_stat, 1); @@ -464,120 +539,86 @@ static int tda8290_tune(struct tuner *t, u16 ifc, unsigned int freq) } } - tda8290_i2c_bridge(t, 0); + tda8290_i2c_bridge(fe, 0); tuner_i2c_xfer_send(&priv->i2c_props, if_agc_set, 2); + + priv->frequency = (V4L2_TUNER_RADIO == params->mode) ? + params->frequency * 125 / 2 : params->frequency * 62500; + return 0; } /*---------------------------------------------------------------------*/ -static void set_audio(struct tuner *t) +static int tda8290_has_signal(struct dvb_frontend *fe) { - struct tda8290_priv *priv = t->priv; - char* mode; + struct tda8290_priv *priv = fe->tuner_priv; - priv->tda827x_lpsel = 0; - if (t->std & V4L2_STD_MN) { - priv->sgIF = 92; - priv->tda8290_easy_mode = 0x01; - priv->tda827x_lpsel = 1; - mode = "MN"; - } else if (t->std & V4L2_STD_B) { - priv->sgIF = 108; - priv->tda8290_easy_mode = 0x02; - mode = "B"; - } else if (t->std & V4L2_STD_GH) { - priv->sgIF = 124; - priv->tda8290_easy_mode = 0x04; - mode = "GH"; - } else if (t->std & V4L2_STD_PAL_I) { - priv->sgIF = 124; - priv->tda8290_easy_mode = 0x08; - mode = "I"; - } else if (t->std & V4L2_STD_DK) { - priv->sgIF = 124; - priv->tda8290_easy_mode = 0x10; - mode = "DK"; - } else if (t->std & V4L2_STD_SECAM_L) { - priv->sgIF = 124; - priv->tda8290_easy_mode = 0x20; - mode = "L"; - } else if (t->std & V4L2_STD_SECAM_LC) { - priv->sgIF = 20; - priv->tda8290_easy_mode = 0x40; - mode = "LC"; - } else { - priv->sgIF = 124; - priv->tda8290_easy_mode = 0x10; - mode = "xx"; - } - tuner_dbg("setting tda8290 to system %s\n", mode); -} - -static void set_tv_freq(struct tuner *t, unsigned int freq) -{ - struct tda8290_priv *priv = t->priv; + unsigned char i2c_get_afc[1] = { 0x1B }; + unsigned char afc = 0; - set_audio(t); - tda8290_tune(t, priv->sgIF, freq); + tuner_i2c_xfer_send(&priv->i2c_props, i2c_get_afc, ARRAY_SIZE(i2c_get_afc)); + tuner_i2c_xfer_recv(&priv->i2c_props, &afc, 1); + return (afc & 0x80)? 65535:0; } -static void set_radio_freq(struct tuner *t, unsigned int freq) +static int tda8290_get_status(struct dvb_frontend *fe, u32 *status) { - /* if frequency is 5.5 MHz */ - tda8290_tune(t, 88, freq); -} + struct tda8290_priv *priv = fe->tuner_priv; -static int has_signal(struct tuner *t) -{ - struct tda8290_priv *priv = t->priv; + int signal = tda8290_has_signal(fe); + *status = 0; - unsigned char i2c_get_afc[1] = { 0x1B }; - unsigned char afc = 0; + /* for now, report based on afc status */ + if (signal) + *status = TUNER_STATUS_LOCKED; - tuner_i2c_xfer_send(&priv->i2c_props, i2c_get_afc, ARRAY_SIZE(i2c_get_afc)); - tuner_i2c_xfer_recv(&priv->i2c_props, &afc, 1); - return (afc & 0x80)? 65535:0; + tuner_dbg("tda8290: AFC status: %d\n", signal); + + return 0; } /*---------------------------------------------------------------------*/ -static void standby(struct tuner *t) +static int tda8290_standby(struct dvb_frontend *fe) { - struct tda8290_priv *priv = t->priv; + struct tda8290_priv *priv = fe->tuner_priv; unsigned char cb1[] = { 0x30, 0xD0 }; unsigned char tda8290_standby[] = { 0x00, 0x02 }; unsigned char tda8290_agc_tri[] = { 0x02, 0x20 }; struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, .buf=cb1, .len = 2}; - tda8290_i2c_bridge(t, 1); + tda8290_i2c_bridge(fe, 1); if (priv->tda827x_ver != 0) cb1[1] = 0x90; i2c_transfer(priv->i2c_props.adap, &msg, 1); - tda8290_i2c_bridge(t, 0); + tda8290_i2c_bridge(fe, 0); tuner_i2c_xfer_send(&priv->i2c_props, tda8290_agc_tri, 2); tuner_i2c_xfer_send(&priv->i2c_props, tda8290_standby, 2); + + return 0; } -static void tda8290_init_if(struct tuner *t) +static void tda8290_init_if(struct dvb_frontend *fe) { - struct tda8290_priv *priv = t->priv; + struct tda8290_priv *priv = fe->tuner_priv; unsigned char set_VS[] = { 0x30, 0x6F }; unsigned char set_GP00_CF[] = { 0x20, 0x01 }; unsigned char set_GP01_CF[] = { 0x20, 0x0B }; - if ((t->config == 1) || (t->config == 2)) + if ((priv->lna_cfg) && + ((*priv->lna_cfg == 1) || (*priv->lna_cfg == 2))) tuner_i2c_xfer_send(&priv->i2c_props, set_GP00_CF, 2); else tuner_i2c_xfer_send(&priv->i2c_props, set_GP01_CF, 2); tuner_i2c_xfer_send(&priv->i2c_props, set_VS, 2); } -static void tda8290_init_tuner(struct tuner *t) +static void tda8290_init_tuner(struct dvb_frontend *fe) { - struct tda8290_priv *priv = t->priv; + struct tda8290_priv *priv = fe->tuner_priv; unsigned char tda8275_init[] = { 0x00, 0x00, 0x00, 0x40, 0xdC, 0x04, 0xAf, 0x3F, 0x2A, 0x04, 0xFF, 0x00, 0x00, 0x40 }; unsigned char tda8275a_init[] = { 0x00, 0x00, 0x00, 0x00, 0xdC, 0x05, 0x8b, @@ -587,28 +628,40 @@ static void tda8290_init_tuner(struct tuner *t) if (priv->tda827x_ver != 0) msg.buf = tda8275a_init; - tda8290_i2c_bridge(t, 1); + tda8290_i2c_bridge(fe, 1); i2c_transfer(priv->i2c_props.adap, &msg, 1); - tda8290_i2c_bridge(t, 0); + tda8290_i2c_bridge(fe, 0); } /*---------------------------------------------------------------------*/ -static void tda8290_release(struct tuner *t) +static int tda8290_release(struct dvb_frontend *fe) { - kfree(t->priv); - t->priv = NULL; + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + + return 0; } -static struct tuner_operations tda8290_tuner_ops = { - .set_tv_freq = set_tv_freq, - .set_radio_freq = set_radio_freq, - .has_signal = has_signal, - .standby = standby, - .release = tda8290_release, +static int tda8290_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct tda8290_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; +} + +static struct dvb_tuner_ops tda8290_tuner_ops = { + .sleep = tda8290_standby, + .set_analog_params = tda8290_set_params, + .release = tda8290_release, + .get_frequency = tda8290_get_frequency, + .get_status = tda8290_get_status, }; -int tda8290_init(struct tuner *t) +struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr, + struct tda8290_config *cfg) { struct tda8290_priv *priv = NULL; u8 data; @@ -618,13 +671,17 @@ int tda8290_init(struct tuner *t) priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL); if (priv == NULL) - return -ENOMEM; - t->priv = priv; - - priv->i2c_props.addr = t->i2c.addr; - priv->i2c_props.adap = t->i2c.adapter; + return NULL; + fe->tuner_priv = priv; + + priv->i2c_props.addr = i2c_addr; + priv->i2c_props.adap = i2c_adap; + if (cfg) { + priv->lna_cfg = cfg->lna_cfg; + priv->tuner_callback = cfg->tuner_callback; + } - tda8290_i2c_bridge(t, 1); + tda8290_i2c_bridge(fe, 1); /* probe for tuner chip */ tuners_found = 0; tuner_addrs = 0; @@ -640,7 +697,7 @@ int tda8290_init(struct tuner *t) behind the bridge and we choose the highest address that doesn't give a response now */ - tda8290_i2c_bridge(t, 0); + tda8290_i2c_bridge(fe, 0); if(tuners_found > 1) for (i = 0; i < tuners_found; i++) { msg.addr = tuner_addrs & 0xff; @@ -652,41 +709,52 @@ int tda8290_init(struct tuner *t) } if (tuner_addrs == 0) { tuner_addrs = 0x61; - tuner_info ("could not clearly identify tuner address, defaulting to %x\n", + tuner_info("could not clearly identify tuner address, defaulting to %x\n", tuner_addrs); } else { tuner_addrs = tuner_addrs & 0xff; - tuner_info ("setting tuner address to %x\n", tuner_addrs); + tuner_info("setting tuner address to %x\n", tuner_addrs); } priv->tda827x_addr = tuner_addrs; msg.addr = tuner_addrs; - tda8290_i2c_bridge(t, 1); + tda8290_i2c_bridge(fe, 1); ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); if( ret != 1) - tuner_warn ("TDA827x access failed!\n"); + tuner_warn("TDA827x access failed!\n"); + + memcpy(&fe->ops.tuner_ops, &tda8290_tuner_ops, + sizeof(struct dvb_tuner_ops)); + if ((data & 0x3c) == 0) { - strlcpy(t->i2c.name, "tda8290+75", sizeof(t->i2c.name)); + strlcpy(fe->ops.tuner_ops.info.name, "tda8290+75", + sizeof(fe->ops.tuner_ops.info.name)); + fe->ops.tuner_ops.info.frequency_min = 55000000; + fe->ops.tuner_ops.info.frequency_max = 860000000; + fe->ops.tuner_ops.info.frequency_step = 250000; priv->tda827x_ver = 0; } else { - strlcpy(t->i2c.name, "tda8290+75a", sizeof(t->i2c.name)); + strlcpy(fe->ops.tuner_ops.info.name, "tda8290+75a", + sizeof(fe->ops.tuner_ops.info.name)); + fe->ops.tuner_ops.info.frequency_min = 44000000; + fe->ops.tuner_ops.info.frequency_max = 906000000; + fe->ops.tuner_ops.info.frequency_step = 62500; priv->tda827x_ver = 2; } - tuner_info("type set to %s\n", t->i2c.name); - - memcpy(&t->ops, &tda8290_tuner_ops, sizeof(struct tuner_operations)); priv->tda827x_lpsel = 0; - t->mode = V4L2_TUNER_ANALOG_TV; - tda8290_init_tuner(t); - tda8290_init_if(t); - return 0; + tda8290_init_tuner(fe); + tda8290_init_if(fe); + return fe; } -int tda8290_probe(struct tuner *t) +int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr) { - struct i2c_client *c = &t->i2c; + struct tuner_i2c_props i2c_props = { + .adap = i2c_adap, + .addr = i2c_addr + }; unsigned char soft_reset[] = { 0x00, 0x00 }; unsigned char easy_mode_b[] = { 0x01, 0x02 }; @@ -695,23 +763,30 @@ int tda8290_probe(struct tuner *t) unsigned char addr_dto_lsb = 0x07; unsigned char data; - i2c_master_send(c, easy_mode_b, 2); - i2c_master_send(c, soft_reset, 2); - i2c_master_send(c, &addr_dto_lsb, 1); - i2c_master_recv(c, &data, 1); + tuner_i2c_xfer_send(&i2c_props, easy_mode_b, 2); + tuner_i2c_xfer_send(&i2c_props, soft_reset, 2); + tuner_i2c_xfer_send(&i2c_props, &addr_dto_lsb, 1); + tuner_i2c_xfer_recv(&i2c_props, &data, 1); if (data == 0) { - i2c_master_send(c, easy_mode_g, 2); - i2c_master_send(c, soft_reset, 2); - i2c_master_send(c, &addr_dto_lsb, 1); - i2c_master_recv(c, &data, 1); + tuner_i2c_xfer_send(&i2c_props, easy_mode_g, 2); + tuner_i2c_xfer_send(&i2c_props, soft_reset, 2); + tuner_i2c_xfer_send(&i2c_props, &addr_dto_lsb, 1); + tuner_i2c_xfer_recv(&i2c_props, &data, 1); if (data == 0x7b) { return 0; } } - i2c_master_send(c, restore_9886, 3); + tuner_i2c_xfer_send(&i2c_props, restore_9886, 3); return -1; } +EXPORT_SYMBOL_GPL(tda8290_probe); +EXPORT_SYMBOL_GPL(tda8290_attach); + +MODULE_DESCRIPTION("Philips TDA8290 + TDA8275 / TDA8275a tuner driver"); +MODULE_AUTHOR("Gerd Knorr, Hartmut Hackmann"); +MODULE_LICENSE("GPL"); + /* * Overrides for Emacs so that we follow Linus's tabbing style. * --------------------------------------------------------------------------- diff --git a/drivers/media/video/tda8290.h b/drivers/media/video/tda8290.h new file mode 100644 index 00000000000..815ca1c78f8 --- /dev/null +++ b/drivers/media/video/tda8290.h @@ -0,0 +1,35 @@ +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __TDA8290_H__ +#define __TDA8290_H__ + +#include +#include "dvb_frontend.h" + +struct tda8290_config +{ + unsigned int *lna_cfg; + int (*tuner_callback) (void *dev, int command,int arg); +}; + +extern int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr); +extern struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr, + struct tda8290_config *cfg); + +#endif /* __TDA8290_H__ */ diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 183bbb9ba6a..f37fe83b199 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -19,6 +19,7 @@ #include #include #include "tuner-driver.h" +#include "tda8290.h" #define UNSET (-1U) @@ -200,6 +201,15 @@ static void tuner_i2c_address_check(struct tuner *t) tuner_warn("====================== WARNING! ======================\n"); } +static void attach_tda8290(struct tuner *t) +{ + struct tda8290_config cfg = { + .lna_cfg = &t->config, + .tuner_callback = t->tuner_callback + }; + tda8290_attach(&t->fe, t->i2c.adapter, t->i2c.addr, &cfg); +} + static void set_type(struct i2c_client *c, unsigned int type, unsigned int new_mode_mask, unsigned int new_config, int (*tuner_callback) (void *dev, int command,int arg)) @@ -245,8 +255,10 @@ static void set_type(struct i2c_client *c, unsigned int type, microtune_init(t); break; case TUNER_PHILIPS_TDA8290: - tda8290_init(t); + { + attach_tda8290(t); break; + } case TUNER_TEA5767: if (tea5767_tuner_init(t) == EINVAL) { t->type = TUNER_ABSENT; @@ -575,7 +587,7 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) case 0x4b: /* If chip is not tda8290, don't register. since it can be tda9887*/ - if (tda8290_probe(t) == 0) { + if (tda8290_probe(t->i2c.adapter, t->i2c.addr) == 0) { tuner_dbg("chip at addr %x is a tda8290\n", addr); } else { /* Default is being tda9887 */ diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index d4c02b4abe7..05d5f857567 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -78,9 +78,6 @@ extern int tda9887_tuner_init(struct tuner *t); extern int microtune_init(struct tuner *t); -extern int tda8290_init(struct tuner *t); -extern int tda8290_probe(struct tuner *t); - extern int tea5761_tuner_init(struct tuner *t); extern int tea5761_autodetection(struct tuner *t); -- cgit v1.2.3-70-g09d2 From 96c0b7cfa5de1d6be0a6f6d202a6a078f5577d8f Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 27 Aug 2007 21:23:08 -0300 Subject: V4L/DVB (6130): mt20xx: convert from tuner sub-driver into dvb_frontend module Signed-off-by: Michael Krufky Acked-by: Hans Verkuil Acked-by: Mike Isely Acked-by: Steven Toth Acked-by: Patrick Boettcher Acked-by: Jarod Wilson Acked-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mt20xx.c | 246 +++++++++++++++++++++++++------------ drivers/media/video/mt20xx.h | 27 ++++ drivers/media/video/tuner-core.c | 3 +- drivers/media/video/tuner-driver.h | 2 - 4 files changed, 197 insertions(+), 81 deletions(-) create mode 100644 drivers/media/video/mt20xx.h (limited to 'drivers') diff --git a/drivers/media/video/mt20xx.c b/drivers/media/video/mt20xx.c index 41bc91817a1..f49d1f4c40d 100644 --- a/drivers/media/video/mt20xx.c +++ b/drivers/media/video/mt20xx.c @@ -1,12 +1,20 @@ /* - * * i2c tv tuner chip device driver * controls microtune tuners, mt2032 + mt2050 at the moment. + * + * This "mt20xx" module was split apart from the original "tuner" module. */ #include #include #include -#include "tuner-driver.h" +#include "tuner-i2c.h" +#include "mt20xx.h" + +static int debug = 0; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable verbose debug messages"); + +#define PREFIX "mt20xx " /* ---------------------------------------------------------------------- */ @@ -19,9 +27,6 @@ module_param(tv_antenna, int, 0644); static unsigned int radio_antenna = 0; module_param(radio_antenna, int, 0644); -/* from tuner-core.c */ -extern int tuner_debug; - /* ---------------------------------------------------------------------- */ #define MT2032 0x04 @@ -40,19 +45,31 @@ struct microtune_priv { struct tuner_i2c_props i2c_props; unsigned int xogc; - unsigned int radio_if2; + //unsigned int radio_if2; + + u32 frequency; }; -static void microtune_release(struct tuner *t) +static int microtune_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + + return 0; +} + +static int microtune_get_frequency(struct dvb_frontend *fe, u32 *frequency) { - kfree(t->priv); - t->priv = NULL; + struct microtune_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; } // IsSpurInBand()? -static int mt2032_spurcheck(struct tuner *t, +static int mt2032_spurcheck(struct dvb_frontend *fe, int f1, int f2, int spectrum_from,int spectrum_to) { + struct microtune_priv *priv = fe->tuner_priv; int n1=1,n2,f; f1=f1/1000; //scale to kHz to avoid 32bit overflows @@ -80,7 +97,7 @@ static int mt2032_spurcheck(struct tuner *t, return 1; } -static int mt2032_compute_freq(struct tuner *t, +static int mt2032_compute_freq(struct dvb_frontend *fe, unsigned int rfin, unsigned int if1, unsigned int if2, unsigned int spectrum_from, @@ -89,6 +106,7 @@ static int mt2032_compute_freq(struct tuner *t, int *ret_sel, unsigned int xogc) //all in Hz { + struct microtune_priv *priv = fe->tuner_priv; unsigned int fref,lo1,lo1n,lo1a,s,sel,lo1freq, desired_lo1, desired_lo2,lo2,lo2n,lo2a,lo2num,lo2freq; @@ -138,7 +156,7 @@ static int mt2032_compute_freq(struct tuner *t, return(-1); } - mt2032_spurcheck(t, lo1freq, desired_lo2, spectrum_from, spectrum_to); + mt2032_spurcheck(fe, lo1freq, desired_lo2, spectrum_from, spectrum_to); // should recalculate lo1 (one step up/down) // set up MT2032 register map for transfer over i2c @@ -162,9 +180,9 @@ static int mt2032_compute_freq(struct tuner *t, return 0; } -static int mt2032_check_lo_lock(struct tuner *t) +static int mt2032_check_lo_lock(struct dvb_frontend *fe) { - struct microtune_priv *priv = t->priv; + struct microtune_priv *priv = fe->tuner_priv; int try,lock=0; unsigned char buf[2]; @@ -184,9 +202,9 @@ static int mt2032_check_lo_lock(struct tuner *t) return lock; } -static int mt2032_optimize_vco(struct tuner *t,int sel,int lock) +static int mt2032_optimize_vco(struct dvb_frontend *fe,int sel,int lock) { - struct microtune_priv *priv = t->priv; + struct microtune_priv *priv = fe->tuner_priv; unsigned char buf[2]; int tad1; @@ -216,18 +234,18 @@ static int mt2032_optimize_vco(struct tuner *t,int sel,int lock) buf[0]=0x0f; buf[1]=sel; tuner_i2c_xfer_send(&priv->i2c_props,buf,2); - lock=mt2032_check_lo_lock(t); + lock=mt2032_check_lo_lock(fe); return lock; } -static void mt2032_set_if_freq(struct tuner *t, unsigned int rfin, +static void mt2032_set_if_freq(struct dvb_frontend *fe, unsigned int rfin, unsigned int if1, unsigned int if2, unsigned int from, unsigned int to) { unsigned char buf[21]; int lint_try,ret,sel,lock=0; - struct microtune_priv *priv = t->priv; + struct microtune_priv *priv = fe->tuner_priv; tuner_dbg("mt2032_set_if_freq rfin=%d if1=%d if2=%d from=%d to=%d\n", rfin,if1,if2,from,to); @@ -237,7 +255,7 @@ static void mt2032_set_if_freq(struct tuner *t, unsigned int rfin, tuner_i2c_xfer_recv(&priv->i2c_props,buf,21); buf[0]=0; - ret=mt2032_compute_freq(t,rfin,if1,if2,from,to,&buf[1],&sel,priv->xogc); + ret=mt2032_compute_freq(fe,rfin,if1,if2,from,to,&buf[1],&sel,priv->xogc); if (ret<0) return; @@ -253,10 +271,10 @@ static void mt2032_set_if_freq(struct tuner *t, unsigned int rfin, // wait for PLLs to lock (per manual), retry LINT if not. for(lint_try=0; lint_try<2; lint_try++) { - lock=mt2032_check_lo_lock(t); + lock=mt2032_check_lo_lock(fe); if(optimize_vco) - lock=mt2032_optimize_vco(t,sel,lock); + lock=mt2032_optimize_vco(fe,sel,lock); if(lock==6) break; tuner_dbg("mt2032: re-init PLLs by LINT\n"); @@ -279,12 +297,13 @@ static void mt2032_set_if_freq(struct tuner *t, unsigned int rfin, } -static void mt2032_set_tv_freq(struct tuner *t, unsigned int freq) +static int mt2032_set_tv_freq(struct dvb_frontend *fe, + struct analog_parameters *params) { int if2,from,to; // signal bandwidth and picture carrier - if (t->std & V4L2_STD_525_60) { + if (params->std & V4L2_STD_525_60) { // NTSC from = 40750*1000; to = 46750*1000; @@ -296,30 +315,64 @@ static void mt2032_set_tv_freq(struct tuner *t, unsigned int freq) if2 = 38900*1000; } - mt2032_set_if_freq(t, freq*62500 /* freq*1000*1000/16 */, + mt2032_set_if_freq(fe, params->frequency*62500, 1090*1000*1000, if2, from, to); + + return 0; } -static void mt2032_set_radio_freq(struct tuner *t, unsigned int freq) +static int mt2032_set_radio_freq(struct dvb_frontend *fe, + struct analog_parameters *params) { - struct microtune_priv *priv = t->priv; - int if2 = priv->radio_if2; + struct microtune_priv *priv = fe->tuner_priv; + int if2; + + if (params->std & V4L2_STD_525_60) { + tuner_dbg("pinnacle ntsc\n"); + if2 = 41300 * 1000; + } else { + tuner_dbg("pinnacle pal\n"); + if2 = 33300 * 1000; + } // per Manual for FM tuning: first if center freq. 1085 MHz - mt2032_set_if_freq(t, freq * 1000 / 16, - 1085*1000*1000,if2,if2,if2); + mt2032_set_if_freq(fe, params->frequency * 125 / 2, + 1085*1000*1000,if2,if2,if2); + + return 0; } -static struct tuner_operations mt2032_tuner_ops = { - .set_tv_freq = mt2032_set_tv_freq, - .set_radio_freq = mt2032_set_radio_freq, - .release = microtune_release, +static int mt2032_set_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct microtune_priv *priv = fe->tuner_priv; + int ret = -EINVAL; + + switch (params->mode) { + case V4L2_TUNER_RADIO: + ret = mt2032_set_radio_freq(fe, params); + priv->frequency = params->frequency * 125 / 2; + break; + case V4L2_TUNER_ANALOG_TV: + case V4L2_TUNER_DIGITAL_TV: + ret = mt2032_set_tv_freq(fe, params); + priv->frequency = params->frequency * 62500; + break; + } + + return ret; +} + +static struct dvb_tuner_ops mt2032_tuner_ops = { + .set_analog_params = mt2032_set_params, + .release = microtune_release, + .get_frequency = microtune_get_frequency, }; // Initalization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001 -static int mt2032_init(struct tuner *t) +static int mt2032_init(struct dvb_frontend *fe) { - struct microtune_priv *priv = t->priv; + struct microtune_priv *priv = fe->tuner_priv; unsigned char buf[21]; int ret,xogc,xok=0; @@ -368,14 +421,14 @@ static int mt2032_init(struct tuner *t) } while (xok != 1 ); priv->xogc=xogc; - memcpy(&t->ops, &mt2032_tuner_ops, sizeof(struct tuner_operations)); + memcpy(&fe->ops.tuner_ops, &mt2032_tuner_ops, sizeof(struct dvb_tuner_ops)); return(1); } -static void mt2050_set_antenna(struct tuner *t, unsigned char antenna) +static void mt2050_set_antenna(struct dvb_frontend *fe, unsigned char antenna) { - struct microtune_priv *priv = t->priv; + struct microtune_priv *priv = fe->tuner_priv; unsigned char buf[2]; int ret; @@ -385,9 +438,9 @@ static void mt2050_set_antenna(struct tuner *t, unsigned char antenna) tuner_dbg("mt2050: enabled antenna connector %d\n", antenna); } -static void mt2050_set_if_freq(struct tuner *t,unsigned int freq, unsigned int if2) +static void mt2050_set_if_freq(struct dvb_frontend *fe,unsigned int freq, unsigned int if2) { - struct microtune_priv *priv = t->priv; + struct microtune_priv *priv = fe->tuner_priv; unsigned int if1=1218*1000*1000; unsigned int f_lo1,f_lo2,lo1,lo2,f_lo1_modulo,f_lo2_modulo,num1,num2,div1a,div1b,div2a,div2b; int ret; @@ -419,7 +472,7 @@ static void mt2050_set_if_freq(struct tuner *t,unsigned int freq, unsigned int i div2a=(lo2/8)-1; div2b=lo2-(div2a+1)*8; - if (tuner_debug > 1) { + if (debug > 1) { tuner_dbg("lo1 lo2 = %d %d\n", lo1, lo2); tuner_dbg("num1 num2 div1a div1b div2a div2b= %x %x %x %x %x %x\n", num1,num2,div1a,div1b,div2a,div2b); @@ -435,7 +488,7 @@ static void mt2050_set_if_freq(struct tuner *t,unsigned int freq, unsigned int i buf[5]=div2a; if(num2!=0) buf[5]=buf[5]|0x40; - if (tuner_debug > 1) { + if (debug > 1) { int i; tuner_dbg("bufs is: "); for(i=0;i<6;i++) @@ -448,43 +501,78 @@ static void mt2050_set_if_freq(struct tuner *t,unsigned int freq, unsigned int i tuner_warn("i2c i/o error: rc == %d (should be 6)\n",ret); } -static void mt2050_set_tv_freq(struct tuner *t, unsigned int freq) +static int mt2050_set_tv_freq(struct dvb_frontend *fe, + struct analog_parameters *params) { unsigned int if2; - if (t->std & V4L2_STD_525_60) { + if (params->std & V4L2_STD_525_60) { // NTSC if2 = 45750*1000; } else { // PAL if2 = 38900*1000; } - if (V4L2_TUNER_DIGITAL_TV == t->mode) { + if (V4L2_TUNER_DIGITAL_TV == params->mode) { // DVB (pinnacle 300i) if2 = 36150*1000; } - mt2050_set_if_freq(t, freq*62500, if2); - mt2050_set_antenna(t, tv_antenna); + mt2050_set_if_freq(fe, params->frequency*62500, if2); + mt2050_set_antenna(fe, tv_antenna); + + return 0; +} + +static int mt2050_set_radio_freq(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct microtune_priv *priv = fe->tuner_priv; + int if2; + + if (params->std & V4L2_STD_525_60) { + tuner_dbg("pinnacle ntsc\n"); + if2 = 41300 * 1000; + } else { + tuner_dbg("pinnacle pal\n"); + if2 = 33300 * 1000; + } + + mt2050_set_if_freq(fe, params->frequency * 125 / 2, if2); + mt2050_set_antenna(fe, radio_antenna); + + return 0; } -static void mt2050_set_radio_freq(struct tuner *t, unsigned int freq) +static int mt2050_set_params(struct dvb_frontend *fe, + struct analog_parameters *params) { - struct microtune_priv *priv = t->priv; - int if2 = priv->radio_if2; + struct microtune_priv *priv = fe->tuner_priv; + int ret = -EINVAL; - mt2050_set_if_freq(t, freq * 1000 / 16, if2); - mt2050_set_antenna(t, radio_antenna); + switch (params->mode) { + case V4L2_TUNER_RADIO: + ret = mt2050_set_radio_freq(fe, params); + priv->frequency = params->frequency * 125 / 2; + break; + case V4L2_TUNER_ANALOG_TV: + case V4L2_TUNER_DIGITAL_TV: + ret = mt2050_set_tv_freq(fe, params); + priv->frequency = params->frequency * 62500; + break; + } + + return ret; } -static struct tuner_operations mt2050_tuner_ops = { - .set_tv_freq = mt2050_set_tv_freq, - .set_radio_freq = mt2050_set_radio_freq, - .release = microtune_release, +static struct dvb_tuner_ops mt2050_tuner_ops = { + .set_analog_params = mt2050_set_params, + .release = microtune_release, + .get_frequency = microtune_get_frequency, }; -static int mt2050_init(struct tuner *t) +static int mt2050_init(struct dvb_frontend *fe) { - struct microtune_priv *priv = t->priv; + struct microtune_priv *priv = fe->tuner_priv; unsigned char buf[2]; int ret; @@ -502,12 +590,14 @@ static int mt2050_init(struct tuner *t) tuner_dbg("mt2050: sro is %x\n",buf[0]); - memcpy(&t->ops, &mt2050_tuner_ops, sizeof(struct tuner_operations)); + memcpy(&fe->ops.tuner_ops, &mt2050_tuner_ops, sizeof(struct dvb_tuner_ops)); return 0; } -int microtune_init(struct tuner *t) +struct dvb_frontend *microtune_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr) { struct microtune_priv *priv = NULL; char *name; @@ -516,28 +606,21 @@ int microtune_init(struct tuner *t) priv = kzalloc(sizeof(struct microtune_priv), GFP_KERNEL); if (priv == NULL) - return -ENOMEM; - t->priv = priv; + return NULL; + fe->tuner_priv = priv; - priv->i2c_props.addr = t->i2c.addr; - priv->i2c_props.adap = t->i2c.adapter; + priv->i2c_props.addr = i2c_addr; + priv->i2c_props.adap = i2c_adap; - priv->radio_if2 = 10700 * 1000; /* 10.7MHz - FM radio */ + //priv->radio_if2 = 10700 * 1000; /* 10.7MHz - FM radio */ memset(buf,0,sizeof(buf)); - if (t->std & V4L2_STD_525_60) { - tuner_dbg("pinnacle ntsc\n"); - priv->radio_if2 = 41300 * 1000; - } else { - tuner_dbg("pinnacle pal\n"); - priv->radio_if2 = 33300 * 1000; - } name = "unknown"; tuner_i2c_xfer_send(&priv->i2c_props,buf,1); tuner_i2c_xfer_recv(&priv->i2c_props,buf,21); - if (tuner_debug) { + if (debug) { int i; tuner_dbg("MT20xx hexdump:"); for(i=0;i<21;i++) { @@ -556,10 +639,10 @@ int microtune_init(struct tuner *t) name = microtune_part[buf[0x13]]; switch (buf[0x13]) { case MT2032: - mt2032_init(t); + mt2032_init(fe); break; case MT2050: - mt2050_init(t); + mt2050_init(fe); break; default: tuner_info("microtune %s found, not (yet?) supported, sorry :-/\n", @@ -567,11 +650,18 @@ int microtune_init(struct tuner *t) return 0; } - strlcpy(t->i2c.name, name, sizeof(t->i2c.name)); + strlcpy(fe->ops.tuner_ops.info.name, name, + sizeof(fe->ops.tuner_ops.info.name)); tuner_info("microtune %s found, OK\n",name); - return 0; + return fe; } +EXPORT_SYMBOL_GPL(microtune_attach); + +MODULE_DESCRIPTION("Microtune tuner driver"); +MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); +MODULE_LICENSE("GPL"); + /* * Overrides for Emacs so that we follow Linus's tabbing style. * --------------------------------------------------------------------------- diff --git a/drivers/media/video/mt20xx.h b/drivers/media/video/mt20xx.h new file mode 100644 index 00000000000..877dbef891e --- /dev/null +++ b/drivers/media/video/mt20xx.h @@ -0,0 +1,27 @@ +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MT20XX_H__ +#define __MT20XX_H__ + +#include +#include "dvb_frontend.h" + +extern struct dvb_frontend *microtune_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr); + +#endif /* __MT20XX_H__ */ diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index f37fe83b199..f24ec1a18b4 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -19,6 +19,7 @@ #include #include #include "tuner-driver.h" +#include "mt20xx.h" #include "tda8290.h" #define UNSET (-1U) @@ -252,7 +253,7 @@ static void set_type(struct i2c_client *c, unsigned int type, switch (t->type) { case TUNER_MT2032: - microtune_init(t); + microtune_attach(&t->fe, t->i2c.adapter, t->i2c.addr); break; case TUNER_PHILIPS_TDA8290: { diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index 05d5f857567..87d937f2f74 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -76,8 +76,6 @@ extern int default_tuner_init(struct tuner *t); extern int tda9887_tuner_init(struct tuner *t); -extern int microtune_init(struct tuner *t); - extern int tea5761_tuner_init(struct tuner *t); extern int tea5761_autodetection(struct tuner *t); -- cgit v1.2.3-70-g09d2 From 7ab10bf72add23f0badf98ead92f58e34e14d35a Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 27 Aug 2007 21:23:40 -0300 Subject: V4L/DVB (6131): tea5761: convert from tuner sub-driver into dvb_frontend module Signed-off-by: Michael Krufky Acked-by: Hans Verkuil Acked-by: Mike Isely Acked-by: Steven Toth Acked-by: Patrick Boettcher Acked-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tea5761.c | 132 ++++++++++++++++++++++++------------- drivers/media/video/tea5761.h | 28 ++++++++ drivers/media/video/tuner-core.c | 5 +- drivers/media/video/tuner-driver.h | 3 - 4 files changed, 118 insertions(+), 50 deletions(-) create mode 100644 drivers/media/video/tea5761.h (limited to 'drivers') diff --git a/drivers/media/video/tea5761.c b/drivers/media/video/tea5761.c index 9965ba48cff..8cdaf474ffd 100644 --- a/drivers/media/video/tea5761.c +++ b/drivers/media/video/tea5761.c @@ -11,15 +11,19 @@ #include #include #include -#include "tuner-driver.h" +#include "tuner-i2c.h" +#include "tea5761.h" -#define PREFIX "TEA5761 " +static int debug = 0; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable verbose debug messages"); -/* from tuner-core.c */ -extern int tuner_debug; +#define PREFIX "tea5761 " struct tea5761_priv { struct tuner_i2c_props i2c_props; + + u32 frequency; }; /*****************************************************************************/ @@ -118,11 +122,6 @@ struct tea5761_priv { /*****************************************************************************/ -static void set_tv_freq(struct tuner *t, unsigned int freq) -{ - tuner_warn("This tuner doesn't support TV freq.\n"); -} - #define FREQ_OFFSET 0 /* for TEA5767, it is 700 to give the right freq */ static void tea5761_status_dump(unsigned char *buffer) { @@ -137,16 +136,18 @@ static void tea5761_status_dump(unsigned char *buffer) } /* Freq should be specifyed at 62.5 Hz */ -static void set_radio_freq(struct tuner *t, unsigned int frq) +static int set_radio_freq(struct dvb_frontend *fe, + struct analog_parameters *params) { - struct tea5761_priv *priv = t->priv; + struct tea5761_priv *priv = fe->tuner_priv; + unsigned int frq = params->frequency; unsigned char buffer[7] = {0, 0, 0, 0, 0, 0, 0 }; unsigned div; int rc; - tuner_dbg (PREFIX "radio freq counter %d\n", frq); + tuner_dbg("radio freq counter %d\n", frq); - if (t->mode == T_STANDBY) { + if (params->mode == T_STANDBY) { tuner_dbg("TEA5761 set to standby mode\n"); buffer[5] |= TEA5761_TNCTRL_MU; } else { @@ -154,10 +155,9 @@ static void set_radio_freq(struct tuner *t, unsigned int frq) } - if (t->audmode == V4L2_TUNER_MODE_MONO) { + if (params->audmode == V4L2_TUNER_MODE_MONO) { tuner_dbg("TEA5761 set to mono\n"); buffer[5] |= TEA5761_TNCTRL_MST; -; } else { tuner_dbg("TEA5761 set to stereo\n"); } @@ -166,18 +166,22 @@ static void set_radio_freq(struct tuner *t, unsigned int frq) buffer[1] = (div >> 8) & 0x3f; buffer[2] = div & 0xff; - if (tuner_debug) + if (debug) tea5761_status_dump(buffer); if (7 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 7))) tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); + + priv->frequency = frq * 125 / 2; + + return 0; } -static int tea5761_signal(struct tuner *t) +static int tea5761_signal(struct dvb_frontend *fe) { unsigned char buffer[16]; int rc; - struct tea5761_priv *priv = t->priv; + struct tea5761_priv *priv = fe->tuner_priv; memset(buffer, 0, sizeof(buffer)); if (16 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 16))) @@ -186,11 +190,11 @@ static int tea5761_signal(struct tuner *t) return ((buffer[9] & TEA5761_TUNCHECK_LEV_MASK) << (13 - 4)); } -static int tea5761_stereo(struct tuner *t) +static int tea5761_stereo(struct dvb_frontend *fe) { unsigned char buffer[16]; int rc; - struct tea5761_priv *priv = t->priv; + struct tea5761_priv *priv = fe->tuner_priv; memset(buffer, 0, sizeof(buffer)); if (16 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 16))) @@ -203,58 +207,96 @@ static int tea5761_stereo(struct tuner *t) return (rc ? V4L2_TUNER_SUB_STEREO : 0); } -int tea5761_autodetection(struct tuner *t) +static int tea5761_get_status(struct dvb_frontend *fe, u32 *status) +{ + struct tea5761_priv *priv = fe->tuner_priv; + int signal = tea5761_signal(fe); + + *status = 0; + + if (signal) + *status = TUNER_STATUS_LOCKED; + if (tea5761_stereo(fe)) + *status |= TUNER_STATUS_STEREO; + + tuner_dbg("tea5761: Signal strength: %d\n", signal); + + return 0; +} + +int tea5761_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr) { unsigned char buffer[16]; int rc; - struct tuner_i2c_props i2c = { .adap = t->i2c.adapter, .addr = t->i2c.addr }; + struct tuner_i2c_props i2c = { .adap = i2c_adap, .addr = i2c_addr }; if (16 != (rc = tuner_i2c_xfer_recv(&i2c, buffer, 16))) { - tuner_warn("it is not a TEA5761. Received %i chars.\n", rc); + printk(KERN_WARNING "it is not a TEA5761. Received %i chars.\n", rc); return EINVAL; } if (!((buffer[13] != 0x2b) || (buffer[14] != 0x57) || (buffer[15] != 0x061))) { - tuner_warn("Manufacturer ID= 0x%02x, Chip ID = %02x%02x. It is not a TEA5761\n",buffer[13],buffer[14],buffer[15]); + printk(KERN_WARNING "Manufacturer ID= 0x%02x, Chip ID = %02x%02x. It is not a TEA5761\n",buffer[13],buffer[14],buffer[15]); return EINVAL; } - tuner_warn("TEA5761 detected.\n"); + printk(KERN_WARNING "TEA5761 detected.\n"); + return 0; +} + +static int tea5761_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; } -static void tea5761_release(struct tuner *t) +static int tea5761_get_frequency(struct dvb_frontend *fe, u32 *frequency) { - kfree(t->priv); - t->priv = NULL; + struct tea5761_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; } -static struct tuner_operations tea5761_tuner_ops = { - .set_tv_freq = set_tv_freq, - .set_radio_freq = set_radio_freq, - .has_signal = tea5761_signal, - .is_stereo = tea5761_stereo, - .release = tea5761_release, +static struct dvb_tuner_ops tea5761_tuner_ops = { + .info = { + .name = "tea5761", // Philips TEA5761HN FM Radio + }, + .set_analog_params = set_radio_freq, + .release = tea5761_release, + .get_frequency = tea5761_get_frequency, + .get_status = tea5761_get_status, }; -int tea5761_tuner_init(struct tuner *t) +struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr) { struct tea5761_priv *priv = NULL; - if (tea5761_autodetection(t) == EINVAL) - return EINVAL; + if (tea5761_autodetection(i2c_adap, i2c_addr) == EINVAL) + return NULL; priv = kzalloc(sizeof(struct tea5761_priv), GFP_KERNEL); if (priv == NULL) - return -ENOMEM; - t->priv = priv; + return NULL; + fe->tuner_priv = priv; - priv->i2c_props.addr = t->i2c.addr; - priv->i2c_props.adap = t->i2c.adapter; + priv->i2c_props.addr = i2c_addr; + priv->i2c_props.adap = i2c_adap; - tuner_info("type set to %d (%s)\n", t->type, "Philips TEA5761HN FM Radio"); - strlcpy(t->i2c.name, "tea5761", sizeof(t->i2c.name)); + memcpy(&fe->ops.tuner_ops, &tea5761_tuner_ops, + sizeof(struct dvb_tuner_ops)); - memcpy(&t->ops, &tea5761_tuner_ops, sizeof(struct tuner_operations)); + tuner_info("type set to %s\n", "Philips TEA5761HN FM Radio"); - return (0); + return fe; } + + +EXPORT_SYMBOL_GPL(tea5761_attach); +EXPORT_SYMBOL_GPL(tea5761_autodetection); + +MODULE_DESCRIPTION("Philips TEA5761 FM tuner driver"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/tea5761.h b/drivers/media/video/tea5761.h new file mode 100644 index 00000000000..f287c0291bf --- /dev/null +++ b/drivers/media/video/tea5761.h @@ -0,0 +1,28 @@ +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __TEA5761_H__ +#define __TEA5761_H__ + +#include +#include "dvb_frontend.h" + +extern int tea5761_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr); +extern struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr); + +#endif /* __TEA5761_H__ */ diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index f24ec1a18b4..848ee6420c5 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -21,6 +21,7 @@ #include "tuner-driver.h" #include "mt20xx.h" #include "tda8290.h" +#include "tea5761.h" #define UNSET (-1U) @@ -270,7 +271,7 @@ static void set_type(struct i2c_client *c, unsigned int type, break; #ifdef CONFIG_TUNER_TEA5761 case TUNER_TEA5761: - if (tea5761_tuner_init(t) == EINVAL) { + if (tea5761_attach(&t->fe, t->i2c.adapter, t->i2c.addr) == NULL) { t->type = TUNER_ABSENT; t->mode_mask = T_UNINITIALIZED; return; @@ -571,7 +572,7 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) switch (addr) { #ifdef CONFIG_TUNER_TEA5761 case 0x10: - if (tea5761_autodetection(t) != EINVAL) { + if (tea5761_autodetection(t->i2c.adapter, t->i2c.addr) != EINVAL) { t->type = TUNER_TEA5761; t->mode_mask = T_RADIO; t->mode = T_STANDBY; diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index 87d937f2f74..bcb6a61c208 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -76,9 +76,6 @@ extern int default_tuner_init(struct tuner *t); extern int tda9887_tuner_init(struct tuner *t); -extern int tea5761_tuner_init(struct tuner *t); -extern int tea5761_autodetection(struct tuner *t); - extern int tea5767_autodetection(struct tuner *t); extern int tea5767_tuner_init(struct tuner *t); -- cgit v1.2.3-70-g09d2 From 8d0936ed15f509c32e8f81849be3a1cee80e2225 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 27 Aug 2007 21:24:27 -0300 Subject: V4L/DVB (6132): tea5767: convert from tuner sub-driver into dvb_frontend module Signed-off-by: Michael Krufky Acked-by: Hans Verkuil Acked-by: Mike Isely Acked-by: Steven Toth Acked-by: Patrick Boettcher Acked-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tea5767.c | 149 ++++++++++++++++++++++++------------- drivers/media/video/tea5767.h | 29 ++++++++ drivers/media/video/tuner-core.c | 5 +- drivers/media/video/tuner-driver.h | 3 - 4 files changed, 129 insertions(+), 57 deletions(-) create mode 100644 drivers/media/video/tea5767.h (limited to 'drivers') diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c index 5a08ec2f99f..cf908d85319 100644 --- a/drivers/media/video/tea5767.c +++ b/drivers/media/video/tea5767.c @@ -13,15 +13,19 @@ #include #include #include -#include "tuner-driver.h" +#include "tuner-i2c.h" +#include "tea5767.h" -#define PREFIX "TEA5767 " +static int debug = 0; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable verbose debug messages"); -/* from tuner-core.c */ -extern int tuner_debug; +#define PREFIX "tea5767 " struct tea5767_priv { struct tuner_i2c_props i2c_props; + + u32 frequency; }; /*****************************************************************************/ @@ -133,11 +137,6 @@ enum tea5767_xtal_freq { /*****************************************************************************/ -static void set_tv_freq(struct tuner *t, unsigned int freq) -{ - tuner_warn("This tuner doesn't support TV freq.\n"); -} - static void tea5767_status_dump(unsigned char *buffer) { unsigned int div, frq; @@ -192,14 +191,16 @@ static void tea5767_status_dump(unsigned char *buffer) } /* Freq should be specifyed at 62.5 Hz */ -static void set_radio_freq(struct tuner *t, unsigned int frq) +static int set_radio_freq(struct dvb_frontend *fe, + struct analog_parameters *params) { - struct tea5767_priv *priv = t->priv; + struct tea5767_priv *priv = fe->tuner_priv; + unsigned int frq = params->frequency; unsigned char buffer[5]; unsigned div; int rc; - tuner_dbg (PREFIX "radio freq = %d.%03d MHz\n", frq/16000,(frq/16)%1000); + tuner_dbg("radio freq = %d.%03d MHz\n", frq/16000,(frq/16)%1000); /* Rounds freq to next decimal value - for 62.5 KHz step */ /* frq = 20*(frq/16)+radio_frq[frq%16]; */ @@ -209,7 +210,7 @@ static void set_radio_freq(struct tuner *t, unsigned int frq) TEA5767_ST_NOISE_CTL | TEA5767_JAPAN_BAND; buffer[4] = 0; - if (t->audmode == V4L2_TUNER_MODE_MONO) { + if (params->audmode == V4L2_TUNER_MODE_MONO) { tuner_dbg("TEA5767 set to mono\n"); buffer[2] |= TEA5767_MONO; } else { @@ -219,26 +220,26 @@ static void set_radio_freq(struct tuner *t, unsigned int frq) /* Should be replaced */ switch (TEA5767_HIGH_LO_32768) { case TEA5767_HIGH_LO_13MHz: - tuner_dbg ("TEA5767 radio HIGH LO inject xtal @ 13 MHz\n"); + tuner_dbg("radio HIGH LO inject xtal @ 13 MHz\n"); buffer[2] |= TEA5767_HIGH_LO_INJECT; buffer[4] |= TEA5767_PLLREF_ENABLE; div = (frq * (4000 / 16) + 700000 + 225000 + 25000) / 50000; break; case TEA5767_LOW_LO_13MHz: - tuner_dbg ("TEA5767 radio LOW LO inject xtal @ 13 MHz\n"); + tuner_dbg("radio LOW LO inject xtal @ 13 MHz\n"); buffer[4] |= TEA5767_PLLREF_ENABLE; div = (frq * (4000 / 16) - 700000 - 225000 + 25000) / 50000; break; case TEA5767_LOW_LO_32768: - tuner_dbg ("TEA5767 radio LOW LO inject xtal @ 32,768 MHz\n"); + tuner_dbg("radio LOW LO inject xtal @ 32,768 MHz\n"); buffer[3] |= TEA5767_XTAL_32768; /* const 700=4000*175 Khz - to adjust freq to right value */ div = ((frq * (4000 / 16) - 700000 - 225000) + 16384) >> 15; break; case TEA5767_HIGH_LO_32768: default: - tuner_dbg ("TEA5767 radio HIGH LO inject xtal @ 32,768 MHz\n"); + tuner_dbg("radio HIGH LO inject xtal @ 32,768 MHz\n"); buffer[2] |= TEA5767_HIGH_LO_INJECT; buffer[3] |= TEA5767_XTAL_32768; @@ -251,19 +252,23 @@ static void set_radio_freq(struct tuner *t, unsigned int frq) if (5 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 5))) tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); - if (tuner_debug) { + if (debug) { if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); else tea5767_status_dump(buffer); } + + priv->frequency = frq * 125 / 2; + + return 0; } -static int tea5767_signal(struct tuner *t) +static int tea5767_signal(struct dvb_frontend *fe) { unsigned char buffer[5]; int rc; - struct tea5767_priv *priv = t->priv; + struct tea5767_priv *priv = fe->tuner_priv; memset(buffer, 0, sizeof(buffer)); if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) @@ -272,11 +277,11 @@ static int tea5767_signal(struct tuner *t) return ((buffer[3] & TEA5767_ADC_LEVEL_MASK) << 8); } -static int tea5767_stereo(struct tuner *t) +static int tea5767_stereo(struct dvb_frontend *fe) { unsigned char buffer[5]; int rc; - struct tea5767_priv *priv = t->priv; + struct tea5767_priv *priv = fe->tuner_priv; memset(buffer, 0, sizeof(buffer)); if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) @@ -284,15 +289,31 @@ static int tea5767_stereo(struct tuner *t) rc = buffer[2] & TEA5767_STEREO_MASK; - tuner_dbg("TEA5767 radio ST GET = %02x\n", rc); + tuner_dbg("radio ST GET = %02x\n", rc); return ((buffer[2] & TEA5767_STEREO_MASK) ? V4L2_TUNER_SUB_STEREO : 0); } -static void tea5767_standby(struct tuner *t) +static int tea5767_get_status(struct dvb_frontend *fe, u32 *status) +{ + struct tea5767_priv *priv = fe->tuner_priv; + int signal = tea5767_signal(fe); + *status = 0; + + if (signal) + *status = TUNER_STATUS_LOCKED; + if (tea5767_stereo(fe)) + *status |= TUNER_STATUS_STEREO; + + tuner_dbg("tea5767: Signal strength: %d\n", signal); + + return 0; +} + +static int tea5767_standby(struct dvb_frontend *fe) { unsigned char buffer[5]; - struct tea5767_priv *priv = t->priv; + struct tea5767_priv *priv = fe->tuner_priv; unsigned div, rc; div = (87500 * 4 + 700 + 225 + 25) / 50; /* Set frequency to 87.5 MHz */ @@ -305,23 +326,25 @@ static void tea5767_standby(struct tuner *t) if (5 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 5))) tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); + + return 0; } -int tea5767_autodetection(struct tuner *t) +int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr) { - struct tuner_i2c_props i2c = { .adap = t->i2c.adapter, .addr = t->i2c.addr }; + struct tuner_i2c_props i2c = { .adap = i2c_adap, .addr = i2c_addr }; unsigned char buffer[7] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; int rc; - if ((rc = tuner_i2c_xfer_send(&i2c, buffer, 7))< 5) { - tuner_warn("It is not a TEA5767. Received %i bytes.\n", rc); + if ((rc = tuner_i2c_xfer_recv(&i2c, buffer, 7))< 5) { + printk(KERN_WARNING "It is not a TEA5767. Received %i bytes.\n", rc); return EINVAL; } /* If all bytes are the same then it's a TV tuner and not a tea5767 */ if (buffer[0] == buffer[1] && buffer[0] == buffer[2] && buffer[0] == buffer[3] && buffer[0] == buffer[4]) { - tuner_warn("All bytes are equal. It is not a TEA5767\n"); + printk(KERN_WARNING "All bytes are equal. It is not a TEA5767\n"); return EINVAL; } @@ -331,51 +354,73 @@ int tea5767_autodetection(struct tuner *t) * Byte 5: bit 7:0 : == 0 */ if (((buffer[3] & 0x0f) != 0x00) || (buffer[4] != 0x00)) { - tuner_warn("Chip ID is not zero. It is not a TEA5767\n"); + printk(KERN_WARNING "Chip ID is not zero. It is not a TEA5767\n"); return EINVAL; } /* It seems that tea5767 returns 0xff after the 5th byte */ if ((buffer[5] != 0xff) || (buffer[6] != 0xff)) { - tuner_warn("Returned more than 5 bytes. It is not a TEA5767\n"); + printk(KERN_WARNING "Returned more than 5 bytes. It is not a TEA5767\n"); return EINVAL; } - tuner_warn("TEA5767 detected.\n"); + printk(KERN_WARNING "TEA5767 detected.\n"); return 0; } -static void tea5767_release(struct tuner *t) +static int tea5767_release(struct dvb_frontend *fe) { - kfree(t->priv); - t->priv = NULL; + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + + return 0; } -static struct tuner_operations tea5767_tuner_ops = { - .set_tv_freq = set_tv_freq, - .set_radio_freq = set_radio_freq, - .has_signal = tea5767_signal, - .is_stereo = tea5767_stereo, - .standby = tea5767_standby, - .release = tea5767_release, +static int tea5767_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct tea5767_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; +} + +static struct dvb_tuner_ops tea5767_tuner_ops = { + .info = { + .name = "tea5767", // Philips TEA5767HN FM Radio + }, + + .set_analog_params = set_radio_freq, + .sleep = tea5767_standby, + .release = tea5767_release, + .get_frequency = tea5767_get_frequency, + .get_status = tea5767_get_status, }; -int tea5767_tuner_init(struct tuner *t) +struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr) { struct tea5767_priv *priv = NULL; priv = kzalloc(sizeof(struct tea5767_priv), GFP_KERNEL); if (priv == NULL) - return -ENOMEM; - t->priv = priv; + return NULL; + fe->tuner_priv = priv; - priv->i2c_props.addr = t->i2c.addr; - priv->i2c_props.adap = t->i2c.adapter; + priv->i2c_props.addr = i2c_addr; + priv->i2c_props.adap = i2c_adap; - tuner_info("type set to %d (%s)\n", t->type, "Philips TEA5767HN FM Radio"); - strlcpy(t->i2c.name, "tea5767", sizeof(t->i2c.name)); + memcpy(&fe->ops.tuner_ops, &tea5767_tuner_ops, + sizeof(struct dvb_tuner_ops)); - memcpy(&t->ops, &tea5767_tuner_ops, sizeof(struct tuner_operations)); + tuner_info("type set to %s\n", "Philips TEA5767HN FM Radio"); - return (0); + return fe; } + + +EXPORT_SYMBOL_GPL(tea5767_attach); +EXPORT_SYMBOL_GPL(tea5767_autodetection); + +MODULE_DESCRIPTION("Philips TEA5767 FM tuner driver"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/tea5767.h b/drivers/media/video/tea5767.h new file mode 100644 index 00000000000..68e9263badf --- /dev/null +++ b/drivers/media/video/tea5767.h @@ -0,0 +1,29 @@ +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __TEA5767_H__ +#define __TEA5767_H__ + +#include +#include "dvb_frontend.h" + +extern int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr); + +extern struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr); + +#endif /* __TEA5767_H__ */ diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 848ee6420c5..9598a3da85f 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -22,6 +22,7 @@ #include "mt20xx.h" #include "tda8290.h" #include "tea5761.h" +#include "tea5767.h" #define UNSET (-1U) @@ -262,7 +263,7 @@ static void set_type(struct i2c_client *c, unsigned int type, break; } case TUNER_TEA5767: - if (tea5767_tuner_init(t) == EINVAL) { + if (tea5767_attach(&t->fe, t->i2c.adapter, t->i2c.addr) == NULL) { t->type = TUNER_ABSENT; t->mode_mask = T_UNINITIALIZED; return; @@ -600,7 +601,7 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) } break; case 0x60: - if (tea5767_autodetection(t) != EINVAL) { + if (tea5767_autodetection(t->i2c.adapter, t->i2c.addr) != EINVAL) { t->type = TUNER_TEA5767; t->mode_mask = T_RADIO; t->mode = T_STANDBY; diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index bcb6a61c208..664f3467ee4 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -76,9 +76,6 @@ extern int default_tuner_init(struct tuner *t); extern int tda9887_tuner_init(struct tuner *t); -extern int tea5767_autodetection(struct tuner *t); -extern int tea5767_tuner_init(struct tuner *t); - /* ------------------------------------------------------------------------ */ #define tuner_warn(fmt, arg...) do {\ -- cgit v1.2.3-70-g09d2 From 4adad287de82703fd504fdab7aebe760196bb786 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 27 Aug 2007 21:59:08 -0300 Subject: V4L/DVB (6133): tuner-simple: convert from tuner sub-driver into dvb_frontend module Signed-off-by: Michael Krufky Acked-by: Hans Verkuil Acked-by: Mike Isely Acked-by: Steven Toth Acked-by: Patrick Boettcher Acked-by: Jarod Wilson Acked-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-core.c | 17 ++- drivers/media/video/tuner-driver.h | 2 - drivers/media/video/tuner-simple.c | 294 +++++++++++++++++++++++-------------- drivers/media/video/tuner-simple.h | 35 +++++ 4 files changed, 236 insertions(+), 112 deletions(-) create mode 100644 drivers/media/video/tuner-simple.h (limited to 'drivers') diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 9598a3da85f..8ee0be26107 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -17,12 +17,14 @@ #include #include #include +#include #include #include "tuner-driver.h" #include "mt20xx.h" #include "tda8290.h" #include "tea5761.h" #include "tea5767.h" +#include "tuner-simple.h" #define UNSET (-1U) @@ -213,6 +215,15 @@ static void attach_tda8290(struct tuner *t) tda8290_attach(&t->fe, t->i2c.adapter, t->i2c.addr, &cfg); } +static void attach_simple_tuner(struct tuner *t) +{ + struct simple_tuner_config cfg = { + .type = t->type, + .tun = &tuners[t->type] + }; + simple_tuner_attach(&t->fe, t->i2c.adapter, t->i2c.addr, &cfg); +} + static void set_type(struct i2c_client *c, unsigned int type, unsigned int new_mode_mask, unsigned int new_config, int (*tuner_callback) (void *dev, int command,int arg)) @@ -290,7 +301,7 @@ static void set_type(struct i2c_client *c, unsigned int type, buffer[2] = 0x86; buffer[3] = 0x54; i2c_master_send(c, buffer, 4); - default_tuner_init(t); + attach_simple_tuner(t); break; case TUNER_PHILIPS_TD1316: buffer[0] = 0x0b; @@ -298,13 +309,13 @@ static void set_type(struct i2c_client *c, unsigned int type, buffer[2] = 0x86; buffer[3] = 0xa4; i2c_master_send(c,buffer,4); - default_tuner_init(t); + attach_simple_tuner(t); break; case TUNER_TDA9887: tda9887_tuner_init(t); break; default: - default_tuner_init(t); + attach_simple_tuner(t); break; } diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index 664f3467ee4..28a10da76d1 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -72,8 +72,6 @@ struct tuner { /* ------------------------------------------------------------------------ */ -extern int default_tuner_init(struct tuner *t); - extern int tda9887_tuner_init(struct tuner *t); /* ------------------------------------------------------------------------ */ diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index eca2ff249a3..2dbd91c8cb6 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -1,7 +1,8 @@ /* - * * i2c tv tuner chip device driver * controls all those simple 4-control-bytes style tuners. + * + * This "tuner-simple" module was split apart from the original "tuner" module. */ #include #include @@ -9,7 +10,14 @@ #include #include #include -#include "tuner-driver.h" +#include "tuner-i2c.h" +#include "tuner-simple.h" + +static int debug = 0; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable verbose debug messages"); + +#define PREFIX "tuner-simple " static int offset = 0; module_param(offset, int, 0664); @@ -85,13 +93,18 @@ MODULE_PARM_DESC(offset,"Allows to specify an offset for tuner"); struct tuner_simple_priv { u16 last_div; struct tuner_i2c_props i2c_props; + + unsigned int type; + struct tunertype *tun; + + u32 frequency; }; /* ---------------------------------------------------------------------- */ -static int tuner_getstatus(struct tuner *t) +static int tuner_getstatus(struct dvb_frontend *fe) { - struct tuner_simple_priv *priv = t->priv; + struct tuner_simple_priv *priv = fe->tuner_priv; unsigned char byte; if (1 != tuner_i2c_xfer_recv(&priv->i2c_props,&byte,1)) @@ -100,18 +113,20 @@ static int tuner_getstatus(struct tuner *t) return byte; } -static int tuner_signal(struct tuner *t) +static int tuner_signal(struct dvb_frontend *fe) { - return (tuner_getstatus(t) & TUNER_SIGNAL) << 13; + return (tuner_getstatus(fe) & TUNER_SIGNAL) << 13; } -static int tuner_stereo(struct tuner *t) +static int tuner_stereo(struct dvb_frontend *fe) { + struct tuner_simple_priv *priv = fe->tuner_priv; + int stereo, status; - status = tuner_getstatus(t); + status = tuner_getstatus(fe); - switch (t->type) { + switch (priv->type) { case TUNER_PHILIPS_FM1216ME_MK3: case TUNER_PHILIPS_FM1236_MK3: case TUNER_PHILIPS_FM1256_IH3: @@ -126,20 +141,38 @@ static int tuner_stereo(struct tuner *t) } +static int simple_get_status(struct dvb_frontend *fe, u32 *status) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + int signal = tuner_signal(fe); + + *status = 0; + + if (signal) + *status = TUNER_STATUS_LOCKED; + if (tuner_stereo(fe)) + *status |= TUNER_STATUS_STEREO; + + tuner_dbg("tuner-simple: Signal strength: %d\n", signal); + + return 0; +} + /* ---------------------------------------------------------------------- */ -static void default_set_tv_freq(struct tuner *t, unsigned int freq) +static int simple_set_tv_freq(struct dvb_frontend *fe, + struct analog_parameters *params) { - struct tuner_simple_priv *priv = t->priv; + struct tuner_simple_priv *priv = fe->tuner_priv; u8 config, cb, tuneraddr; u16 div; struct tunertype *tun; u8 buffer[4]; int rc, IFPCoff, i, j; enum param_type desired_type; - struct tuner_params *params; + struct tuner_params *t_params; - tun = &tuners[t->type]; + tun = priv->tun; /* IFPCoff = Video Intermediate Frequency - Vif: 940 =16*58.75 NTSC/J (Japan) @@ -153,14 +186,14 @@ static void default_set_tv_freq(struct tuner *t, unsigned int freq) 171.2=16*10.70 FM Radio (at set_radio_freq) */ - if (t->std == V4L2_STD_NTSC_M_JP) { + if (params->std == V4L2_STD_NTSC_M_JP) { IFPCoff = 940; desired_type = TUNER_PARAM_TYPE_NTSC; - } else if ((t->std & V4L2_STD_MN) && - !(t->std & ~V4L2_STD_MN)) { + } else if ((params->std & V4L2_STD_MN) && + !(params->std & ~V4L2_STD_MN)) { IFPCoff = 732; desired_type = TUNER_PARAM_TYPE_NTSC; - } else if (t->std == V4L2_STD_SECAM_LC) { + } else if (params->std == V4L2_STD_SECAM_LC) { IFPCoff = 543; desired_type = TUNER_PARAM_TYPE_SECAM; } else { @@ -173,49 +206,49 @@ static void default_set_tv_freq(struct tuner *t, unsigned int freq) continue; break; } - /* use default tuner_params if desired_type not available */ + /* use default tuner_t_params if desired_type not available */ if (desired_type != tun->params[j].type) { - tuner_dbg("IFPCoff = %d: tuner_params undefined for tuner %d\n", - IFPCoff,t->type); + tuner_dbg("IFPCoff = %d: tuner_t_params undefined for tuner %d\n", + IFPCoff, priv->type); j = 0; } - params = &tun->params[j]; + t_params = &tun->params[j]; - for (i = 0; i < params->count; i++) { - if (freq > params->ranges[i].limit) + for (i = 0; i < t_params->count; i++) { + if (params->frequency > t_params->ranges[i].limit) continue; break; } - if (i == params->count) { + if (i == t_params->count) { tuner_dbg("TV frequency out of range (%d > %d)", - freq, params->ranges[i - 1].limit); - freq = params->ranges[--i].limit; + params->frequency, t_params->ranges[i - 1].limit); + params->frequency = t_params->ranges[--i].limit; } - config = params->ranges[i].config; - cb = params->ranges[i].cb; + config = t_params->ranges[i].config; + cb = t_params->ranges[i].cb; /* i == 0 -> VHF_LO * i == 1 -> VHF_HI * i == 2 -> UHF */ tuner_dbg("tv: param %d, range %d\n",j,i); - div=freq + IFPCoff + offset; + div=params->frequency + IFPCoff + offset; tuner_dbg("Freq= %d.%02d MHz, V_IF=%d.%02d MHz, Offset=%d.%02d MHz, div=%0d\n", - freq / 16, freq % 16 * 100 / 16, + params->frequency / 16, params->frequency % 16 * 100 / 16, IFPCoff / 16, IFPCoff % 16 * 100 / 16, offset / 16, offset % 16 * 100 / 16, div); /* tv norm specific stuff for multi-norm tuners */ - switch (t->type) { + switch (priv->type) { case TUNER_PHILIPS_SECAM: // FI1216MF /* 0x01 -> ??? no change ??? */ /* 0x02 -> PAL BDGHI / SECAM L */ /* 0x04 -> ??? PAL others / SECAM others ??? */ cb &= ~0x03; - if (t->std & V4L2_STD_SECAM_L) //also valid for V4L2_STD_SECAM + if (params->std & V4L2_STD_SECAM_L) //also valid for V4L2_STD_SECAM cb |= PHILIPS_MF_SET_STD_L; - else if (t->std & V4L2_STD_SECAM_LC) + else if (params->std & V4L2_STD_SECAM_LC) cb |= PHILIPS_MF_SET_STD_LC; else /* V4L2_STD_B|V4L2_STD_GH */ cb |= PHILIPS_MF_SET_STD_BG; @@ -224,16 +257,16 @@ static void default_set_tv_freq(struct tuner *t, unsigned int freq) case TUNER_TEMIC_4046FM5: cb &= ~0x0f; - if (t->std & V4L2_STD_PAL_BG) { + if (params->std & V4L2_STD_PAL_BG) { cb |= TEMIC_SET_PAL_BG; - } else if (t->std & V4L2_STD_PAL_I) { + } else if (params->std & V4L2_STD_PAL_I) { cb |= TEMIC_SET_PAL_I; - } else if (t->std & V4L2_STD_PAL_DK) { + } else if (params->std & V4L2_STD_PAL_DK) { cb |= TEMIC_SET_PAL_DK; - } else if (t->std & V4L2_STD_SECAM_L) { + } else if (params->std & V4L2_STD_SECAM_L) { cb |= TEMIC_SET_PAL_L; } @@ -242,13 +275,13 @@ static void default_set_tv_freq(struct tuner *t, unsigned int freq) case TUNER_PHILIPS_FQ1216ME: cb &= ~0x0f; - if (t->std & (V4L2_STD_PAL_BG|V4L2_STD_PAL_DK)) { + if (params->std & (V4L2_STD_PAL_BG|V4L2_STD_PAL_DK)) { cb |= PHILIPS_SET_PAL_BGDK; - } else if (t->std & V4L2_STD_PAL_I) { + } else if (params->std & V4L2_STD_PAL_I) { cb |= PHILIPS_SET_PAL_I; - } else if (t->std & V4L2_STD_SECAM_L) { + } else if (params->std & V4L2_STD_SECAM_L) { cb |= PHILIPS_SET_PAL_L; } @@ -260,7 +293,7 @@ static void default_set_tv_freq(struct tuner *t, unsigned int freq) /* 0x02 -> NTSC antenna input 1 */ /* 0x03 -> NTSC antenna input 2 */ cb &= ~0x03; - if (!(t->std & V4L2_STD_ATSC)) + if (!(params->std & V4L2_STD_ATSC)) cb |= 2; /* FIXME: input */ break; @@ -280,7 +313,7 @@ static void default_set_tv_freq(struct tuner *t, unsigned int freq) buffer[2] = 0x17; buffer[3] = 0x00; cb &= ~0x40; - if (t->std & V4L2_STD_ATSC) { + if (params->std & V4L2_STD_ATSC) { cb |= 0x40; buffer[1] = 0x04; } @@ -296,7 +329,7 @@ static void default_set_tv_freq(struct tuner *t, unsigned int freq) break; } - if (params->cb_first_if_lower_freq && div < priv->last_div) { + if (t_params->cb_first_if_lower_freq && div < priv->last_div) { buffer[0] = config; buffer[1] = cb; buffer[2] = (div>>8) & 0x7f; @@ -308,42 +341,42 @@ static void default_set_tv_freq(struct tuner *t, unsigned int freq) buffer[3] = cb; } priv->last_div = div; - if (params->has_tda9887) { + if (t_params->has_tda9887) { int config = 0; - int is_secam_l = (t->std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)) && - !(t->std & ~(V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)); + int is_secam_l = (params->std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)) && + !(params->std & ~(V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)); - if (t->std == V4L2_STD_SECAM_LC) { - if (params->port1_active ^ params->port1_invert_for_secam_lc) + if (params->std == V4L2_STD_SECAM_LC) { + if (t_params->port1_active ^ t_params->port1_invert_for_secam_lc) config |= TDA9887_PORT1_ACTIVE; - if (params->port2_active ^ params->port2_invert_for_secam_lc) + if (t_params->port2_active ^ t_params->port2_invert_for_secam_lc) config |= TDA9887_PORT2_ACTIVE; } else { - if (params->port1_active) + if (t_params->port1_active) config |= TDA9887_PORT1_ACTIVE; - if (params->port2_active) + if (t_params->port2_active) config |= TDA9887_PORT2_ACTIVE; } - if (params->intercarrier_mode) + if (t_params->intercarrier_mode) config |= TDA9887_INTERCARRIER; if (is_secam_l) { - if (i == 0 && params->default_top_secam_low) - config |= TDA9887_TOP(params->default_top_secam_low); - else if (i == 1 && params->default_top_secam_mid) - config |= TDA9887_TOP(params->default_top_secam_mid); - else if (params->default_top_secam_high) - config |= TDA9887_TOP(params->default_top_secam_high); + if (i == 0 && t_params->default_top_secam_low) + config |= TDA9887_TOP(t_params->default_top_secam_low); + else if (i == 1 && t_params->default_top_secam_mid) + config |= TDA9887_TOP(t_params->default_top_secam_mid); + else if (t_params->default_top_secam_high) + config |= TDA9887_TOP(t_params->default_top_secam_high); } else { - if (i == 0 && params->default_top_low) - config |= TDA9887_TOP(params->default_top_low); - else if (i == 1 && params->default_top_mid) - config |= TDA9887_TOP(params->default_top_mid); - else if (params->default_top_high) - config |= TDA9887_TOP(params->default_top_high); + if (i == 0 && t_params->default_top_low) + config |= TDA9887_TOP(t_params->default_top_low); + else if (i == 1 && t_params->default_top_mid) + config |= TDA9887_TOP(t_params->default_top_mid); + else if (t_params->default_top_high) + config |= TDA9887_TOP(t_params->default_top_high); } - if (params->default_pll_gating_18) + if (t_params->default_pll_gating_18) config |= TDA9887_GATING_18; i2c_clients_command(priv->i2c_props.adap, TDA9887_SET_CONFIG, &config); } @@ -353,7 +386,7 @@ static void default_set_tv_freq(struct tuner *t, unsigned int freq) if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,4))) tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc); - switch (t->type) { + switch (priv->type) { case TUNER_LG_TDVS_H06XF: /* Set the Auxiliary Byte. */ buffer[0] = buffer[2]; @@ -374,7 +407,7 @@ static void default_set_tv_freq(struct tuner *t, unsigned int freq) /* Wait until the PLL locks */ for (;;) { if (time_after(jiffies,timeout)) - return; + return 0; if (1 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props,&status_byte,1))) { tuner_warn("i2c i/o read error: rc == %d (should be 1)\n",rc); break; @@ -398,27 +431,30 @@ static void default_set_tv_freq(struct tuner *t, unsigned int freq) break; } } + return 0; } -static void default_set_radio_freq(struct tuner *t, unsigned int freq) +static int simple_set_radio_freq(struct dvb_frontend *fe, + struct analog_parameters *params) { struct tunertype *tun; - struct tuner_simple_priv *priv = t->priv; + struct tuner_simple_priv *priv = fe->tuner_priv; u8 buffer[4]; u16 div; int rc, j; - struct tuner_params *params; + struct tuner_params *t_params; + unsigned int freq = params->frequency; - tun = &tuners[t->type]; + tun = priv->tun; for (j = tun->count-1; j > 0; j--) if (tun->params[j].type == TUNER_PARAM_TYPE_RADIO) break; - /* default params (j=0) will be used if desired type wasn't found */ - params = &tun->params[j]; + /* default t_params (j=0) will be used if desired type wasn't found */ + t_params = &tun->params[j]; /* Select Radio 1st IF used */ - switch (params->radio_if) { + switch (t_params->radio_if) { case 0: /* 10.7 MHz */ freq += (unsigned int)(10.7*16000); break; @@ -429,16 +465,16 @@ static void default_set_radio_freq(struct tuner *t, unsigned int freq) freq += (unsigned int)(41.3*16000); break; default: - tuner_warn("Unsupported radio_if value %d\n", params->radio_if); - return; + tuner_warn("Unsupported radio_if value %d\n", t_params->radio_if); + return 0; } /* Bandswitch byte */ - switch (t->type) { + switch (priv->type) { case TUNER_TENA_9533_DI: case TUNER_YMEC_TVF_5533MF: - tuner_dbg ("This tuner doesn't have FM. Most cards have a TEA5767 for FM\n"); - return; + tuner_dbg("This tuner doesn't have FM. Most cards have a TEA5767 for FM\n"); + return 0; case TUNER_PHILIPS_FM1216ME_MK3: case TUNER_PHILIPS_FM1236_MK3: case TUNER_PHILIPS_FMD1216ME_MK3: @@ -461,7 +497,7 @@ static void default_set_radio_freq(struct tuner *t, unsigned int freq) break; } - buffer[2] = (params->ranges[0].config & ~TUNER_RATIO_MASK) | + buffer[2] = (t_params->ranges[0].config & ~TUNER_RATIO_MASK) | TUNER_RATIO_SELECT_50; /* 50 kHz step */ /* Convert from 1/16 kHz V4L steps to 1/20 MHz (=50 kHz) PLL steps @@ -469,7 +505,7 @@ static void default_set_radio_freq(struct tuner *t, unsigned int freq) freq * (1/800) */ div = (freq + 400) / 800; - if (params->cb_first_if_lower_freq && div < priv->last_div) { + if (t_params->cb_first_if_lower_freq && div < priv->last_div) { buffer[0] = buffer[2]; buffer[1] = buffer[3]; buffer[2] = (div>>8) & 0x7f; @@ -483,61 +519,105 @@ static void default_set_radio_freq(struct tuner *t, unsigned int freq) buffer[0],buffer[1],buffer[2],buffer[3]); priv->last_div = div; - if (params->has_tda9887) { + if (t_params->has_tda9887) { int config = 0; - if (params->port1_active && !params->port1_fm_high_sensitivity) + if (t_params->port1_active && !t_params->port1_fm_high_sensitivity) config |= TDA9887_PORT1_ACTIVE; - if (params->port2_active && !params->port2_fm_high_sensitivity) + if (t_params->port2_active && !t_params->port2_fm_high_sensitivity) config |= TDA9887_PORT2_ACTIVE; - if (params->intercarrier_mode) + if (t_params->intercarrier_mode) config |= TDA9887_INTERCARRIER; -/* if (params->port1_set_for_fm_mono) +/* if (t_params->port1_set_for_fm_mono) config &= ~TDA9887_PORT1_ACTIVE;*/ - if (params->fm_gain_normal) + if (t_params->fm_gain_normal) config |= TDA9887_GAIN_NORMAL; - if (params->radio_if == 2) + if (t_params->radio_if == 2) config |= TDA9887_RIF_41_3; i2c_clients_command(priv->i2c_props.adap, TDA9887_SET_CONFIG, &config); } if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,4))) tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc); + + return 0; } -static void tuner_release(struct tuner *t) +static int simple_set_params(struct dvb_frontend *fe, + struct analog_parameters *params) { - kfree(t->priv); - t->priv = NULL; + struct tuner_simple_priv *priv = fe->tuner_priv; + int ret = -EINVAL; + + switch (params->mode) { + case V4L2_TUNER_RADIO: + ret = simple_set_radio_freq(fe, params); + priv->frequency = params->frequency * 125 / 2; + break; + case V4L2_TUNER_ANALOG_TV: + case V4L2_TUNER_DIGITAL_TV: + ret = simple_set_tv_freq(fe, params); + priv->frequency = params->frequency * 62500; + break; + } + + return ret; +} + + +static int simple_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + + return 0; +} + +static int simple_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; } -static struct tuner_operations simple_tuner_ops = { - .set_tv_freq = default_set_tv_freq, - .set_radio_freq = default_set_radio_freq, - .has_signal = tuner_signal, - .is_stereo = tuner_stereo, - .release = tuner_release, +static struct dvb_tuner_ops simple_tuner_ops = { + .set_analog_params = simple_set_params, + .release = simple_release, + .get_frequency = simple_get_frequency, + .get_status = simple_get_status, }; -int default_tuner_init(struct tuner *t) +struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c_adap, + u8 i2c_addr, + struct simple_tuner_config *cfg) { struct tuner_simple_priv *priv = NULL; priv = kzalloc(sizeof(struct tuner_simple_priv), GFP_KERNEL); if (priv == NULL) - return -ENOMEM; - t->priv = priv; + return NULL; + fe->tuner_priv = priv; - priv->i2c_props.addr = t->i2c.addr; - priv->i2c_props.adap = t->i2c.adapter; + priv->i2c_props.addr = i2c_addr; + priv->i2c_props.adap = i2c_adap; + priv->type = cfg->type; + priv->tun = cfg->tun; - tuner_info("type set to %d (%s)\n", - t->type, tuners[t->type].name); - strlcpy(t->i2c.name, tuners[t->type].name, sizeof(t->i2c.name)); + memcpy(&fe->ops.tuner_ops, &simple_tuner_ops, sizeof(struct dvb_tuner_ops)); - memcpy(&t->ops, &simple_tuner_ops, sizeof(struct tuner_operations)); + tuner_info("type set to %d (%s)\n", cfg->type, cfg->tun->name); - return 0; + strlcpy(fe->ops.tuner_ops.info.name, cfg->tun->name, sizeof(fe->ops.tuner_ops.info.name)); + + return fe; } + +EXPORT_SYMBOL_GPL(simple_tuner_attach); + +MODULE_DESCRIPTION("Simple 4-control-bytes style tuner driver"); +MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); +MODULE_LICENSE("GPL"); + /* * Overrides for Emacs so that we follow Linus's tabbing style. * --------------------------------------------------------------------------- diff --git a/drivers/media/video/tuner-simple.h b/drivers/media/video/tuner-simple.h new file mode 100644 index 00000000000..75cd45b7145 --- /dev/null +++ b/drivers/media/video/tuner-simple.h @@ -0,0 +1,35 @@ +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __TUNER_SIMPLE_H__ +#define __TUNER_SIMPLE_H__ + +#include +#include "dvb_frontend.h" + +struct simple_tuner_config +{ + /* chip type */ + unsigned int type; + struct tunertype *tun; +}; + +extern struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c_adap, + u8 i2c_addr, + struct simple_tuner_config *cfg); + +#endif /* __TUNER_SIMPLE_H__ */ -- cgit v1.2.3-70-g09d2 From ca805d57cf5ea7482ed3da28653f30621249ee45 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 27 Aug 2007 21:59:35 -0300 Subject: V4L/DVB (6134): tuner: alter build to produce separate modules Break tuner.ko into separate modules. This was a quick change - Tuner sub-drivers are still static-linked to tuner.ko, this will change after using dvb_attach and removing the probing functions. After this change, one can deselect undesired tuner sub-drivers via Kconfig. Signed-off-by: Michael Krufky Acked-by: Hans Verkuil Acked-by: Mike Isely Acked-by: Steven Toth Acked-by: Patrick Boettcher Acked-by: Jarod Wilson Acked-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 56 ++++++++++++++++++++++++++++++++++++++ drivers/media/video/Kconfig | 9 ------ drivers/media/video/Makefile | 12 +++++--- drivers/media/video/mt20xx.h | 10 +++++++ drivers/media/video/tda8290.h | 19 +++++++++++++ drivers/media/video/tea5761.h | 19 +++++++++++++ drivers/media/video/tea5767.h | 18 ++++++++++++ drivers/media/video/tuner-simple.h | 11 ++++++++ 8 files changed, 141 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index d9d033e07e1..3f8cfa873de 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -69,6 +69,62 @@ source "drivers/media/common/Kconfig" config VIDEO_TUNER tristate depends on I2C + select TUNER_MT20XX if !VIDEO_TUNER_CUSTOMIZE + select TUNER_TDA8290 if !VIDEO_TUNER_CUSTOMIZE + select TUNER_TEA5761 if !VIDEO_TUNER_CUSTOMIZE + select TUNER_TEA5767 if !VIDEO_TUNER_CUSTOMIZE + select TUNER_SIMPLE if !VIDEO_TUNER_CUSTOMIZE + +menuconfig VIDEO_TUNER_CUSTOMIZE + bool "Customize analog tuner modules to build" + depends on VIDEO_TUNER + help + This allows the user to deselect tuner drivers unnecessary + for their hardware from the build. Use this option with care + as deselecting tuner drivers which are in fact necessary will + result in V4L devices which cannot be tuned due to lack of + driver support + + If unsure say N. + +if VIDEO_TUNER_CUSTOMIZE + +config TUNER_MT20XX + tristate "Microtune 2032 / 2050 tuners" + depends on I2C + default m if VIDEO_TUNER_CUSTOMIZE + help + Say Y here to include support for the MT2032 / MT2050 tuner. + +config TUNER_TDA8290 + tristate "TDA 8290+8275(a) tuner combo" + depends on I2C + default m if VIDEO_TUNER_CUSTOMIZE + help + Say Y here to include support for Philips TDA8290+8275(a) tuner. + +config TUNER_TEA5761 + tristate "TEA 5761 radio tuner (EXPERIMENTAL)" + depends on I2C && EXPERIMENTAL + default m if VIDEO_TUNER_CUSTOMIZE + help + Say Y here to include support for the Philips TEA5761 radio tuner. + +config TUNER_TEA5767 + tristate "TEA 5767 radio tuner" + depends on I2C + default m if VIDEO_TUNER_CUSTOMIZE + help + Say Y here to include support for the Philips TEA5767 radio tuner. + +config TUNER_SIMPLE + tristate "Simple tuner support" + depends on I2C + default m if VIDEO_TUNER_CUSTOMIZE + help + Say Y here to include support for various simple tuners. + +endif # VIDEO_TUNER_CUSTOMIZE config VIDEO_BUF depends on PCI diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 0e1d2ccc4e8..04756c342cb 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -505,15 +505,6 @@ config TUNER_3036 Say Y here to include support for Philips SAB3036 compatible tuners. If in doubt, say N. -config TUNER_TEA5761 - bool "TEA 5761 radio tuner (EXPERIMENTAL)" - depends on EXPERIMENTAL - depends on I2C - select VIDEO_TUNER - help - Say Y here to include support for Philips TEA5761 radio tuner. - If in doubt, say N. - config VIDEO_VINO tristate "SGI Vino Video For Linux (EXPERIMENTAL)" depends on I2C && SGI_IP22 && EXPERIMENTAL && VIDEO_V4L2 diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 113e525f6da..00699c36ec1 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -4,10 +4,7 @@ zr36067-objs := zoran_procfs.o zoran_device.o \ zoran_driver.o zoran_card.o -tuner-objs := tuner-core.o tuner-types.o tuner-simple.o \ - mt20xx.o tda8290.o tea5767.o tda9887.o - -tuner-$(CONFIG_TUNER_TEA5761) += tea5761.o +tuner-objs := tuner-core.o tuner-types.o tda9887.o msp3400-objs := msp3400-driver.o msp3400-kthreads.o @@ -83,6 +80,13 @@ obj-$(CONFIG_VIDEO_DPC) += dpc7146.o obj-$(CONFIG_TUNER_3036) += tuner-3036.o obj-$(CONFIG_VIDEO_TUNER) += tuner.o + +obj-$(CONFIG_TUNER_SIMPLE) += tuner-simple.o +obj-$(CONFIG_TUNER_MT20XX) += mt20xx.o +obj-$(CONFIG_TUNER_TDA8290) += tda8290.o +obj-$(CONFIG_TUNER_TEA5767) += tea5767.o +obj-$(CONFIG_TUNER_TEA5761) += tea5761.o + obj-$(CONFIG_VIDEO_BUF) += video-buf.o obj-$(CONFIG_VIDEO_BUF_DVB) += video-buf-dvb.o obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o diff --git a/drivers/media/video/mt20xx.h b/drivers/media/video/mt20xx.h index 877dbef891e..5e9c825d2e9 100644 --- a/drivers/media/video/mt20xx.h +++ b/drivers/media/video/mt20xx.h @@ -20,8 +20,18 @@ #include #include "dvb_frontend.h" +#if defined(CONFIG_TUNER_MT20XX) || (defined(CONFIG_TUNER_MT20XX_MODULE) && defined(MODULE)) extern struct dvb_frontend *microtune_attach(struct dvb_frontend *fe, struct i2c_adapter* i2c_adap, u8 i2c_addr); +#else +static inline struct dvb_frontend *microtune_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + return NULL; +} +#endif #endif /* __MT20XX_H__ */ diff --git a/drivers/media/video/tda8290.h b/drivers/media/video/tda8290.h index 815ca1c78f8..107b24b05aa 100644 --- a/drivers/media/video/tda8290.h +++ b/drivers/media/video/tda8290.h @@ -26,10 +26,29 @@ struct tda8290_config int (*tuner_callback) (void *dev, int command,int arg); }; +#if defined(CONFIG_TUNER_TDA8290) || (defined(CONFIG_TUNER_TDA8290_MODULE) && defined(MODULE)) extern int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr); + extern struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe, struct i2c_adapter* i2c_adap, u8 i2c_addr, struct tda8290_config *cfg); +#else +static inline int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr) +{ + printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", + __FUNCTION__); + return -EINVAL; +} + +static inline struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr, + struct tda8290_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + return NULL; +} +#endif #endif /* __TDA8290_H__ */ diff --git a/drivers/media/video/tea5761.h b/drivers/media/video/tea5761.h index f287c0291bf..73a03b42784 100644 --- a/drivers/media/video/tea5761.h +++ b/drivers/media/video/tea5761.h @@ -20,9 +20,28 @@ #include #include "dvb_frontend.h" +#if defined(CONFIG_TUNER_TEA5761) || (defined(CONFIG_TUNER_TEA5761_MODULE) && defined(MODULE)) extern int tea5761_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr); + extern struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe, struct i2c_adapter* i2c_adap, u8 i2c_addr); +#else +static inline int tea5761_autodetection(struct i2c_adapter* i2c_adap, + u8 i2c_addr) +{ + printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", + __FUNCTION__); + return -EINVAL; +} + +static inline struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + return NULL; +} +#endif #endif /* __TEA5761_H__ */ diff --git a/drivers/media/video/tea5767.h b/drivers/media/video/tea5767.h index 68e9263badf..5d78281adcc 100644 --- a/drivers/media/video/tea5767.h +++ b/drivers/media/video/tea5767.h @@ -20,10 +20,28 @@ #include #include "dvb_frontend.h" +#if defined(CONFIG_TUNER_TEA5767) || (defined(CONFIG_TUNER_TEA5767_MODULE) && defined(MODULE)) extern int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr); extern struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe, struct i2c_adapter* i2c_adap, u8 i2c_addr); +#else +static inline int tea5767_autodetection(struct i2c_adapter* i2c_adap, + u8 i2c_addr) +{ + printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", + __FUNCTION__); + return -EINVAL; +} + +static inline struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + return NULL; +} +#endif #endif /* __TEA5767_H__ */ diff --git a/drivers/media/video/tuner-simple.h b/drivers/media/video/tuner-simple.h index 75cd45b7145..9089939a8c0 100644 --- a/drivers/media/video/tuner-simple.h +++ b/drivers/media/video/tuner-simple.h @@ -27,9 +27,20 @@ struct simple_tuner_config struct tunertype *tun; }; +#if defined(CONFIG_TUNER_SIMPLE) || (defined(CONFIG_TUNER_SIMPLE_MODULE) && defined(MODULE)) extern struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c_adap, u8 i2c_addr, struct simple_tuner_config *cfg); +#else +static inline struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c_adap, + u8 i2c_addr, + struct simple_tuner_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + return NULL; +} +#endif #endif /* __TUNER_SIMPLE_H__ */ -- cgit v1.2.3-70-g09d2 From 8fb3b9f7a9e0420150bf6cb8a3c20f45d372cce4 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Thu, 30 Aug 2007 23:00:43 -0300 Subject: V4L/DVB (6136): dvb_frontend: add get_rf_strength function pointer to dvb_tuner_ops Add get_rf_strength function pointer to dvb_tuner_ops, so that rf signal strength can be read directly from the tuner driver by the dvb demodulator driver and / or the analog tuning system. This is an internal api addition -- userspace is not affected. Signed-off-by: Michael Krufky Acked-by: Manu Abraham Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.h | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index ffb83b0f68c..a5262e852c8 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -90,6 +90,7 @@ struct dvb_tuner_ops { #define TUNER_STATUS_LOCKED 1 #define TUNER_STATUS_STEREO 2 int (*get_status)(struct dvb_frontend *fe, u32 *status); + int (*get_rf_strength)(struct dvb_frontend *fe, u16 *strength); /** These are provided seperately from set_params in order to facilitate silicon * tuners which require sophisticated tuning loops, controlling each parameter seperately. */ -- cgit v1.2.3-70-g09d2 From 735f0b9af1748602bb7f3a8009c31cf5f133eec8 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 31 Aug 2007 16:39:39 -0300 Subject: V4L/DVB (6137): tuner-simple: add get_rf_strength and improve status reading efficiency Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-simple.c | 58 +++++++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index 2dbd91c8cb6..7b93d3b1f4c 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -102,7 +102,7 @@ struct tuner_simple_priv { /* ---------------------------------------------------------------------- */ -static int tuner_getstatus(struct dvb_frontend *fe) +static int tuner_read_status(struct dvb_frontend *fe) { struct tuner_simple_priv *priv = fe->tuner_priv; unsigned char byte; @@ -113,47 +113,60 @@ static int tuner_getstatus(struct dvb_frontend *fe) return byte; } -static int tuner_signal(struct dvb_frontend *fe) +static inline int tuner_signal(const int status) { - return (tuner_getstatus(fe) & TUNER_SIGNAL) << 13; + return (status & TUNER_SIGNAL) << 13; } -static int tuner_stereo(struct dvb_frontend *fe) +static inline int tuner_stereo(const int type, const int status) { - struct tuner_simple_priv *priv = fe->tuner_priv; - - int stereo, status; - - status = tuner_getstatus(fe); - - switch (priv->type) { + switch (type) { case TUNER_PHILIPS_FM1216ME_MK3: case TUNER_PHILIPS_FM1236_MK3: case TUNER_PHILIPS_FM1256_IH3: case TUNER_LG_NTSC_TAPE: - stereo = ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3); - break; + return ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3); default: - stereo = status & TUNER_STEREO; + return status & TUNER_STEREO; } +} - return stereo; +static inline int tuner_islocked(const int status) +{ + return (status & TUNER_FL); +} + +static inline int tuner_afcstatus(const int status) +{ + return (status & TUNER_AFC) - 2; } static int simple_get_status(struct dvb_frontend *fe, u32 *status) { struct tuner_simple_priv *priv = fe->tuner_priv; - int signal = tuner_signal(fe); + int tuner_status = tuner_read_status(fe); *status = 0; - if (signal) + if (tuner_islocked(tuner_status)) *status = TUNER_STATUS_LOCKED; - if (tuner_stereo(fe)) + if (tuner_stereo(priv->type, tuner_status)) *status |= TUNER_STATUS_STEREO; - tuner_dbg("tuner-simple: Signal strength: %d\n", signal); + tuner_dbg("AFC Status: %d\n", tuner_afcstatus(tuner_status)); + + return 0; +} + +static int simple_get_rf_strength(struct dvb_frontend *fe, u16 *strength) +{ + struct tuner_simple_priv *priv = fe->tuner_priv; + int signal = tuner_signal(tuner_read_status(fe)); + + *strength = signal; + + tuner_dbg("Signal strength: %d\n", signal); return 0; } @@ -580,9 +593,10 @@ static int simple_get_frequency(struct dvb_frontend *fe, u32 *frequency) static struct dvb_tuner_ops simple_tuner_ops = { .set_analog_params = simple_set_params, - .release = simple_release, - .get_frequency = simple_get_frequency, - .get_status = simple_get_status, + .release = simple_release, + .get_frequency = simple_get_frequency, + .get_status = simple_get_status, + .get_rf_strength = simple_get_rf_strength, }; struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe, -- cgit v1.2.3-70-g09d2 From fd443f7444180c1cd9cbcb816ebf65c8b8e35301 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 31 Aug 2007 16:39:57 -0300 Subject: V4L/DVB (6138): tea5761: add get_rf_strength and improve status reading efficiency Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tea5761.c | 64 +++++++++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/tea5761.c b/drivers/media/video/tea5761.c index 8cdaf474ffd..2150222a386 100644 --- a/drivers/media/video/tea5761.c +++ b/drivers/media/video/tea5761.c @@ -177,49 +177,66 @@ static int set_radio_freq(struct dvb_frontend *fe, return 0; } -static int tea5761_signal(struct dvb_frontend *fe) +static int tea5761_read_status(struct dvb_frontend *fe, char *buffer) { - unsigned char buffer[16]; - int rc; struct tea5761_priv *priv = fe->tuner_priv; + int rc; - memset(buffer, 0, sizeof(buffer)); - if (16 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 16))) - tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); + memset(buffer, 0, 16); + if (16 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 16))) { + tuner_warn("i2c i/o error: rc == %d (should be 16)\n", rc); + return -EREMOTEIO; + } - return ((buffer[9] & TEA5761_TUNCHECK_LEV_MASK) << (13 - 4)); + return 0; } -static int tea5761_stereo(struct dvb_frontend *fe) +static inline int tea5761_signal(struct dvb_frontend *fe, const char *buffer) { - unsigned char buffer[16]; - int rc; struct tea5761_priv *priv = fe->tuner_priv; - memset(buffer, 0, sizeof(buffer)); - if (16 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 16))) - tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); + int signal = ((buffer[9] & TEA5761_TUNCHECK_LEV_MASK) << (13 - 4)); + + tuner_dbg("Signal strength: %d\n", signal); - rc = buffer[9] & TEA5761_TUNCHECK_STEREO; + return signal; +} - tuner_dbg("TEA5761 radio ST GET = %02x\n", rc); +static inline int tea5761_stereo(struct dvb_frontend *fe, const char *buffer) +{ + struct tea5761_priv *priv = fe->tuner_priv; - return (rc ? V4L2_TUNER_SUB_STEREO : 0); + int stereo = buffer[9] & TEA5761_TUNCHECK_STEREO; + + tuner_dbg("Radio ST GET = %02x\n", stereo); + + return (stereo ? V4L2_TUNER_SUB_STEREO : 0); } static int tea5761_get_status(struct dvb_frontend *fe, u32 *status) { - struct tea5761_priv *priv = fe->tuner_priv; - int signal = tea5761_signal(fe); + unsigned char buffer[16]; *status = 0; - if (signal) - *status = TUNER_STATUS_LOCKED; - if (tea5761_stereo(fe)) - *status |= TUNER_STATUS_STEREO; + if (0 == tea5761_read_status(fe, buffer)) { + if (tea5761_signal(fe, buffer)) + *status = TUNER_STATUS_LOCKED; + if (tea5761_stereo(fe, buffer)) + *status |= TUNER_STATUS_STEREO; + } + + return 0; +} + +static int tea5761_get_rf_strength(struct dvb_frontend *fe, u16 *strength) +{ + unsigned char buffer[16]; + + *strength = 0; - tuner_dbg("tea5761: Signal strength: %d\n", signal); + if (0 == tea5761_read_status(fe, buffer)) + *strength = tea5761_signal(fe, buffer); return 0; } @@ -266,6 +283,7 @@ static struct dvb_tuner_ops tea5761_tuner_ops = { .release = tea5761_release, .get_frequency = tea5761_get_frequency, .get_status = tea5761_get_status, + .get_rf_strength = tea5761_get_rf_strength, }; struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe, -- cgit v1.2.3-70-g09d2 From 6b897f2c3982af51134ba83f4b6de71d28d35944 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 31 Aug 2007 16:40:14 -0300 Subject: V4L/DVB (6139): tea5767: add get_rf_strength and improve status reading efficiency Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tea5767.c | 63 ++++++++++++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c index cf908d85319..71df419df7b 100644 --- a/drivers/media/video/tea5767.c +++ b/drivers/media/video/tea5767.c @@ -264,48 +264,66 @@ static int set_radio_freq(struct dvb_frontend *fe, return 0; } -static int tea5767_signal(struct dvb_frontend *fe) +static int tea5767_read_status(struct dvb_frontend *fe, char *buffer) { - unsigned char buffer[5]; - int rc; struct tea5767_priv *priv = fe->tuner_priv; + int rc; - memset(buffer, 0, sizeof(buffer)); - if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) + memset(buffer, 0, 5); + if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) { tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); + return -EREMOTEIO; + } - return ((buffer[3] & TEA5767_ADC_LEVEL_MASK) << 8); + return 0; } -static int tea5767_stereo(struct dvb_frontend *fe) +static inline int tea5767_signal(struct dvb_frontend *fe, const char *buffer) { - unsigned char buffer[5]; - int rc; struct tea5767_priv *priv = fe->tuner_priv; - memset(buffer, 0, sizeof(buffer)); - if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) - tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); + int signal = ((buffer[3] & TEA5767_ADC_LEVEL_MASK) << 8); + + tuner_dbg("Signal strength: %d\n", signal); + + return signal; +} - rc = buffer[2] & TEA5767_STEREO_MASK; +static inline int tea5767_stereo(struct dvb_frontend *fe, const char *buffer) +{ + struct tea5767_priv *priv = fe->tuner_priv; - tuner_dbg("radio ST GET = %02x\n", rc); + int stereo = buffer[2] & TEA5767_STEREO_MASK; - return ((buffer[2] & TEA5767_STEREO_MASK) ? V4L2_TUNER_SUB_STEREO : 0); + tuner_dbg("Radio ST GET = %02x\n", stereo); + + return (stereo ? V4L2_TUNER_SUB_STEREO : 0); } static int tea5767_get_status(struct dvb_frontend *fe, u32 *status) { - struct tea5767_priv *priv = fe->tuner_priv; - int signal = tea5767_signal(fe); + unsigned char buffer[5]; + *status = 0; - if (signal) - *status = TUNER_STATUS_LOCKED; - if (tea5767_stereo(fe)) - *status |= TUNER_STATUS_STEREO; + if (0 == tea5767_read_status(fe, buffer)) { + if (tea5767_signal(fe, buffer)) + *status = TUNER_STATUS_LOCKED; + if (tea5767_stereo(fe, buffer)) + *status |= TUNER_STATUS_STEREO; + } + + return 0; +} + +static int tea5767_get_rf_strength(struct dvb_frontend *fe, u16 *strength) +{ + unsigned char buffer[5]; + + *strength = 0; - tuner_dbg("tea5767: Signal strength: %d\n", signal); + if (0 == tea5767_read_status(fe, buffer)) + *strength = tea5767_signal(fe, buffer); return 0; } @@ -393,6 +411,7 @@ static struct dvb_tuner_ops tea5767_tuner_ops = { .release = tea5767_release, .get_frequency = tea5767_get_frequency, .get_status = tea5767_get_status, + .get_rf_strength = tea5767_get_rf_strength, }; struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe, -- cgit v1.2.3-70-g09d2 From 3782e050f8860fb701d4cb14df16cd4ed9cce2d2 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 31 Aug 2007 17:53:00 -0300 Subject: V4L/DVB (6140): tda8290: add get_rf_strength and improve status reading efficiency Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tda8290.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index ec731d6fbfb..0e5cf459d3e 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -553,27 +553,35 @@ static int tda8290_set_params(struct dvb_frontend *fe, static int tda8290_has_signal(struct dvb_frontend *fe) { struct tda8290_priv *priv = fe->tuner_priv; + int ret; unsigned char i2c_get_afc[1] = { 0x1B }; unsigned char afc = 0; + /* for now, report based on afc status */ tuner_i2c_xfer_send(&priv->i2c_props, i2c_get_afc, ARRAY_SIZE(i2c_get_afc)); tuner_i2c_xfer_recv(&priv->i2c_props, &afc, 1); - return (afc & 0x80)? 65535:0; + + ret = (afc & 0x80) ? 65535 : 0; + + tuner_dbg("AFC status: %d\n", ret); + + return ret; } static int tda8290_get_status(struct dvb_frontend *fe, u32 *status) { - struct tda8290_priv *priv = fe->tuner_priv; - - int signal = tda8290_has_signal(fe); *status = 0; - /* for now, report based on afc status */ - if (signal) + if (tda8290_has_signal(fe)) *status = TUNER_STATUS_LOCKED; - tuner_dbg("tda8290: AFC status: %d\n", signal); + return 0; +} + +static int tda8290_get_rf_strength(struct dvb_frontend *fe, u16 *strength) +{ + *strength = tda8290_has_signal(fe); return 0; } @@ -656,6 +664,7 @@ static struct dvb_tuner_ops tda8290_tuner_ops = { .release = tda8290_release, .get_frequency = tda8290_get_frequency, .get_status = tda8290_get_status, + .get_rf_strength = tda8290_get_rf_strength, }; struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe, -- cgit v1.2.3-70-g09d2 From 1f5ef19779df2c2f75870332b37dd3004c08a515 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 31 Aug 2007 17:38:02 -0300 Subject: V4L/DVB (6141): tuner: use get_rf_strength instead of get_status to determine signal strength Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-core.c | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 8ee0be26107..2f74379f4e4 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -110,6 +110,17 @@ static void fe_standby(struct tuner *t) fe_tuner_ops->sleep(&t->fe); } +static int fe_has_signal(struct tuner *t) +{ + struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; + u16 strength; + + if (fe_tuner_ops->get_rf_strength) + fe_tuner_ops->get_rf_strength(&t->fe, &strength); + + return strength; +} + /* Set tuner frequency, freq in Units of 62.5kHz = 1/16MHz */ static void set_tv_freq(struct i2c_client *c, unsigned int freq) { @@ -326,6 +337,7 @@ static void set_type(struct i2c_client *c, unsigned int type, t->ops.set_radio_freq = fe_set_freq; t->ops.standby = fe_standby; t->ops.release = fe_release; + t->ops.has_signal = fe_has_signal; } tuner_info("type set to %s\n", t->i2c.name); @@ -807,12 +819,10 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) u32 tuner_status; fe_tuner_ops->get_status(&t->fe, &tuner_status); - if (tuner_status & TUNER_STATUS_STEREO) - vt->flags |= VIDEO_TUNER_STEREO_ON; - else - vt->flags &= ~VIDEO_TUNER_STEREO_ON; - vt->signal = tuner_status & TUNER_STATUS_LOCKED - ? 65535 : 0; + if (tuner_status & TUNER_STATUS_STEREO) + vt->flags |= VIDEO_TUNER_STEREO_ON; + else + vt->flags &= ~VIDEO_TUNER_STEREO_ON; } else { if (t->ops.is_stereo) { if (t->ops.is_stereo(t)) @@ -822,9 +832,10 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) vt->flags &= ~VIDEO_TUNER_STEREO_ON; } - if (t->ops.has_signal) - vt->signal = t->ops.has_signal(t); } + if (t->ops.has_signal) + vt->signal = t->ops.has_signal(t); + vt->flags |= VIDEO_TUNER_LOW; /* Allow freqs at 62.5 Hz */ vt->rangelow = radio_range[0] * 16000; @@ -948,15 +959,14 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) fe_tuner_ops->get_status(&t->fe, &tuner_status); tuner->rxsubchans = (tuner_status & TUNER_STATUS_STEREO) ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; - tuner->signal = tuner_status & TUNER_STATUS_LOCKED ? 65535 : 0; } else { if (t->ops.is_stereo) { tuner->rxsubchans = t->ops.is_stereo(t) ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; } - if (t->ops.has_signal) - tuner->signal = t->ops.has_signal(t); } + if (t->ops.has_signal) + tuner->signal = t->ops.has_signal(t); tuner->capability |= V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; tuner->audmode = t->audmode; -- cgit v1.2.3-70-g09d2 From f61b48f7a838bb3d089b12fc9d03fd53c9ef5022 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 1 Sep 2007 02:02:51 -0300 Subject: V4L/DVB (6142): cx25840: fix build warning Fix the following build warning: CC [M] cx25840-core.o cx25840-core.c: In function 'init_dll1': cx25840-core.c:147: warning: implicit declaration of function 'udelay' Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx25840/cx25840-core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 90f7859bb48..15f191e170d 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3-70-g09d2 From d19770e5178a4bc49641711246360c25781d20a4 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Sun, 11 Mar 2007 20:44:05 -0300 Subject: V4L/DVB (6150): Add CX23885/CX23887 PCIe bridge driver This is a new framework to support boards based on the CX23885/7 PCIe bridge. The framework supports digital (no analog yet) Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Makefile | 1 + drivers/media/video/cx23885/Kconfig | 17 + drivers/media/video/cx23885/Makefile | 9 + drivers/media/video/cx23885/cx23885-cards.c | 198 ++++ drivers/media/video/cx23885/cx23885-core.c | 1601 +++++++++++++++++++++++++++ drivers/media/video/cx23885/cx23885-dvb.c | 199 ++++ drivers/media/video/cx23885/cx23885-i2c.c | 375 +++++++ drivers/media/video/cx23885/cx23885-reg.h | 429 +++++++ drivers/media/video/cx23885/cx23885.h | 295 +++++ 9 files changed, 3124 insertions(+) create mode 100644 drivers/media/video/cx23885/Kconfig create mode 100644 drivers/media/video/cx23885/Makefile create mode 100644 drivers/media/video/cx23885/cx23885-cards.c create mode 100644 drivers/media/video/cx23885/cx23885-core.c create mode 100644 drivers/media/video/cx23885/cx23885-dvb.c create mode 100644 drivers/media/video/cx23885/cx23885-i2c.c create mode 100644 drivers/media/video/cx23885/cx23885-reg.h create mode 100644 drivers/media/video/cx23885/cx23885.h (limited to 'drivers') diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 00699c36ec1..9e99d2e1c1b 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -124,5 +124,6 @@ obj-$(CONFIG_USB_QUICKCAM_MESSENGER) += usbvideo/ obj-$(CONFIG_VIDEO_IVTV) += ivtv/ obj-$(CONFIG_VIDEO_VIVI) += vivi.o +obj-$(CONFIG_VIDEO_CX23885) += cx23885/ EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig new file mode 100644 index 00000000000..ea53466dacb --- /dev/null +++ b/drivers/media/video/cx23885/Kconfig @@ -0,0 +1,17 @@ +config VIDEO_CX23885 + tristate "Conexant cx23885 (2388x successor) support" + depends on VIDEO_DEV && PCI && I2C + select I2C_ALGOBIT + select FW_LOADER + select VIDEO_BTCX + select VIDEO_BUF + select VIDEO_TUNER + select VIDEO_TVEEPROM + select VIDEO_IR + ---help--- + This is a video4linux driver for Conexant 23885 based + TV cards. + + To compile this driver as a module, choose M here: the + module will be called cx23885 + diff --git a/drivers/media/video/cx23885/Makefile b/drivers/media/video/cx23885/Makefile new file mode 100644 index 00000000000..665067022d2 --- /dev/null +++ b/drivers/media/video/cx23885/Makefile @@ -0,0 +1,9 @@ +cx23885-objs := cx23885-cards.o cx23885-core.o cx23885-i2c.o cx23885-dvb.o + +obj-$(CONFIG_VIDEO_CX23885) += cx23885.o + +EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core +EXTRA_CFLAGS += -Idrivers/media/dvb/frontends + +EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m) diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c new file mode 100644 index 00000000000..9344fb5d95f --- /dev/null +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -0,0 +1,198 @@ +/* + * Driver for the Conexant CX23885 PCIe bridge + * + * Copyright (c) 2006 Steven Toth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include + +#include "cx23885.h" + +/* ------------------------------------------------------------------ */ +/* board config info */ + +struct cx23885_board cx23885_boards[] = { + [CX23885_BOARD_UNKNOWN] = { + .name = "UNKNOWN/GENERIC", + .bridge = CX23885_BRIDGE_UNDEFINED, + .input = {{ + .type = CX23885_VMUX_COMPOSITE1, + .vmux = 0, + },{ + .type = CX23885_VMUX_COMPOSITE2, + .vmux = 1, + },{ + .type = CX23885_VMUX_COMPOSITE3, + .vmux = 2, + },{ + .type = CX23885_VMUX_COMPOSITE4, + .vmux = 3, + }}, + }, + [CX23885_BOARD_HAUPPAUGE_HVR1800lp] = { + .name = "Hauppauge WinTV-HVR1800lp", + .bridge = CX23885_BRIDGE_885, + .portc = CX23885_MPEG_DVB, + .input = {{ + .type = CX23885_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0xff00, + },{ + .type = CX23885_VMUX_DEBUG, + .vmux = 0, + .gpio0 = 0xff01, + },{ + .type = CX23885_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0xff02, + },{ + .type = CX23885_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0xff02, + }}, + }, + [CX23885_BOARD_HAUPPAUGE_HVR1800] = { + .name = "Hauppauge WinTV-HVR1800", + .bridge = CX23885_BRIDGE_887, + .portc = CX23885_MPEG_DVB, + .input = {{ + .type = CX23885_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0xff00, + },{ + .type = CX23885_VMUX_DEBUG, + .vmux = 0, + .gpio0 = 0xff01, + },{ + .type = CX23885_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0xff02, + },{ + .type = CX23885_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0xff02, + }}, + }, +}; +const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); + +/* ------------------------------------------------------------------ */ +/* PCI subsystem IDs */ + +struct cx23885_subid cx23885_subids[] = { + { + .subvendor = 0x0070, + .subdevice = 0x3400, + .card = CX23885_BOARD_UNKNOWN, + },{ + .subvendor = 0x0070, + .subdevice = 0x7600, + .card = CX23885_BOARD_HAUPPAUGE_HVR1800lp, + },{ + .subvendor = 0x0070, + .subdevice = 0x7800, + .card = CX23885_BOARD_HAUPPAUGE_HVR1800, + },{ + .subvendor = 0x0070, + .subdevice = 0x7801, + .card = CX23885_BOARD_HAUPPAUGE_HVR1800, + }, +}; +const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); + +void cx23885_card_list(struct cx23885_dev *dev) +{ + int i; + + if (0 == dev->pci->subsystem_vendor && + 0 == dev->pci->subsystem_device) { + printk("%s: Your board has no valid PCIe Subsystem ID and thus can't\n" + "%s: be autodetected. Please pass card= insmod option to\n" + "%s: workaround that. Redirect complaints to the vendor of\n" + "%s: the TV card. Best regards,\n" + "%s: -- tux\n", + dev->name, dev->name, dev->name, dev->name, dev->name); + } else { + printk("%s: Your board isn't known (yet) to the driver. You can\n" + "%s: try to pick one of the existing card configs via\n" + "%s: card= insmod option. Updating to the latest\n" + "%s: version might help as well.\n", + dev->name, dev->name, dev->name, dev->name); + } + printk("%s: Here is a list of valid choices for the card= insmod option:\n", + dev->name); + for (i = 0; i < cx23885_bcount; i++) + printk("%s: card=%d -> %s\n", + dev->name, i, cx23885_boards[i].name); +} + +static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) +{ + struct tveeprom tv; + + tveeprom_hauppauge_analog(&dev->i2c_bus[0].i2c_client, &tv, eeprom_data); + + + /* Make sure we support the board model */ + switch (tv.model) + { + case 76601: /* WinTV-HVR1800lp (PCIe, Retail, No IR, Dual channel ATSC and MPEG2 HW Encoder */ + case 77001: /* WinTV-HVR1500 (Express Card, Retail, No IR, ATSC and Basic analog */ + case 78501: /* WinTV-HVR1800 (PCIe, Retail, IR, Dual channel ATSC and MPEG2 HW Encoder */ + case 78521: /* WinTV-HVR1800 (PCIe, Retail, IR, Dual channel ATSC and MPEG2 HW Encoder */ + break; + default: + printk("%s: warning: unknown hauppauge model #%d\n", dev->name, tv.model); + break; + } + + printk(KERN_INFO "%s: hauppauge eeprom: model=%d\n", + dev->name, tv.model); +} + +void cx23885_card_setup(struct cx23885_dev *dev) +{ + static u8 eeprom[256]; + + if (dev->i2c_bus[0].i2c_rc == 0) { + dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1; + tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom, sizeof(eeprom)); + } + + switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1800: + case CX23885_BOARD_HAUPPAUGE_HVR1800lp: + if (dev->i2c_bus[0].i2c_rc == 0) + hauppauge_eeprom(dev, eeprom+0x80); + break; + } +} + +/* ------------------------------------------------------------------ */ + +EXPORT_SYMBOL(cx23885_boards); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off + */ diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c new file mode 100644 index 00000000000..876d396fb7a --- /dev/null +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -0,0 +1,1601 @@ +/* + * Driver for the Conexant CX23885 PCIe bridge + * + * Copyright (c) 2006 Steven Toth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cx23885.h" + +MODULE_DESCRIPTION("Driver for cx23885 based TV cards"); +MODULE_AUTHOR("Steven Toth "); +MODULE_LICENSE("GPL"); + +static unsigned int debug = 0; +module_param(debug,int,0644); +MODULE_PARM_DESC(debug,"enable debug messages"); + +static unsigned int card[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET }; +module_param_array(card, int, NULL, 0444); +MODULE_PARM_DESC(card,"card type"); + +#define dprintk(level,fmt, arg...) if (debug >= level) \ + printk(KERN_DEBUG "%s/0: " fmt, dev->name , ## arg) + +static unsigned int cx23885_devcount; + +static DEFINE_MUTEX(devlist); +static LIST_HEAD(cx23885_devlist); + +#define NO_SYNC_LINE (-1U) + +/* + * CX23885 Assumptions + * 1 line = 16 bytes of CDT + * cmds size = 80 + * cdt size = 16 * linesize + * iqsize = 64 + * maxlines = 6 + * + * Address Space: + * 0x00000000 0x00008fff FIFO clusters + * 0x00010000 0x000104af Channel Management Data Structures + * 0x000104b0 0x000104ff Free + * 0x00010500 0x000108bf 15 channels * iqsize + * 0x000108c0 0x000108ff Free + * 0x00010900 0x00010e9f IQ's + Cluster Descriptor Tables + * 15 channels * (iqsize + (maxlines * linesize)) + * 0x00010ea0 0x00010xxx Free + */ + +struct sram_channel cx23885_sram_channels[] = { + [SRAM_CH01] = { + .name = "test ch1", + .cmds_start = 0x10000, + .ctrl_start = 0x10500, + .cdt = 0x10900, + .fifo_start = 0x3000, + .fifo_size = 0x1000, + .ptr1_reg = DMA1_PTR1, + .ptr2_reg = DMA1_PTR2, + .cnt1_reg = DMA1_CNT1, + .cnt2_reg = DMA1_CNT2, + .jumponly = 1, + }, + [SRAM_CH02] = { + .name = "ch2", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA2_PTR1, + .ptr2_reg = DMA2_PTR2, + .cnt1_reg = DMA2_CNT1, + .cnt2_reg = DMA2_CNT2, + }, + [SRAM_CH03] = { + .name = "ch3", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA3_PTR1, + .ptr2_reg = DMA3_PTR2, + .cnt1_reg = DMA3_CNT1, + .cnt2_reg = DMA3_CNT2, + }, + [SRAM_CH04] = { + .name = "ch4", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA4_PTR1, + .ptr2_reg = DMA4_PTR2, + .cnt1_reg = DMA4_CNT1, + .cnt2_reg = DMA4_CNT2, + }, + [SRAM_CH05] = { + .name = "ch5", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA5_PTR1, + .ptr2_reg = DMA5_PTR2, + .cnt1_reg = DMA5_CNT1, + .cnt2_reg = DMA5_CNT2, + }, + [SRAM_CH06] = { + .name = "TS2 C", + .cmds_start = 0x10140, + .ctrl_start = 0x10680, + .cdt = 0x10480, + .fifo_start = 0x6000, + .fifo_size = 0x1000, + .ptr1_reg = DMA5_PTR1, + .ptr2_reg = DMA5_PTR2, + .cnt1_reg = DMA5_CNT1, + .cnt2_reg = DMA5_CNT2, + }, + [SRAM_CH07] = { + .name = "ch7", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA6_PTR1, + .ptr2_reg = DMA6_PTR2, + .cnt1_reg = DMA6_CNT1, + .cnt2_reg = DMA6_CNT2, + }, + [SRAM_CH08] = { + .name = "ch8", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA7_PTR1, + .ptr2_reg = DMA7_PTR2, + .cnt1_reg = DMA7_CNT1, + .cnt2_reg = DMA7_CNT2, + }, + [SRAM_CH09] = { + .name = "ch9", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA8_PTR1, + .ptr2_reg = DMA8_PTR2, + .cnt1_reg = DMA8_CNT1, + .cnt2_reg = DMA8_CNT2, + }, +}; + +/* FIXME, these allocations will change when + * analog arrives. The be reviewed. + * CX23887 Assumptions + * 1 line = 16 bytes of CDT + * cmds size = 80 + * cdt size = 16 * linesize + * iqsize = 64 + * maxlines = 6 + * + * Address Space: + * 0x00000000 0x00008fff FIFO clusters + * 0x00010000 0x000104af Channel Management Data Structures + * 0x000104b0 0x000104ff Free + * 0x00010500 0x000108bf 15 channels * iqsize + * 0x000108c0 0x000108ff Free + * 0x00010900 0x00010e9f IQ's + Cluster Descriptor Tables + * 15 channels * (iqsize + (maxlines * linesize)) + * 0x00010ea0 0x00010xxx Free + */ + +struct sram_channel cx23887_sram_channels[] = { + [SRAM_CH01] = { + .name = "test ch1", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA1_PTR1, + .ptr2_reg = DMA1_PTR2, + .cnt1_reg = DMA1_CNT1, + .cnt2_reg = DMA1_CNT2, + }, + [SRAM_CH02] = { + .name = "ch2", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA2_PTR1, + .ptr2_reg = DMA2_PTR2, + .cnt1_reg = DMA2_CNT1, + .cnt2_reg = DMA2_CNT2, + }, + [SRAM_CH03] = { + .name = "ch3", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA3_PTR1, + .ptr2_reg = DMA3_PTR2, + .cnt1_reg = DMA3_CNT1, + .cnt2_reg = DMA3_CNT2, + }, + [SRAM_CH04] = { + .name = "ch4", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA4_PTR1, + .ptr2_reg = DMA4_PTR2, + .cnt1_reg = DMA4_CNT1, + .cnt2_reg = DMA4_CNT2, + }, + [SRAM_CH05] = { + .name = "ch5", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA5_PTR1, + .ptr2_reg = DMA5_PTR2, + .cnt1_reg = DMA5_CNT1, + .cnt2_reg = DMA5_CNT2, + }, + [SRAM_CH06] = { + .name = "TS2 C", + .cmds_start = 0x10140, + .ctrl_start = 0x10680, + .cdt = 0x10480, + .fifo_start = 0x6000, + .fifo_size = 0x1000, + .ptr1_reg = DMA5_PTR1, + .ptr2_reg = DMA5_PTR2, + .cnt1_reg = DMA5_CNT1, + .cnt2_reg = DMA5_CNT2, + }, + [SRAM_CH07] = { + .name = "ch7", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA6_PTR1, + .ptr2_reg = DMA6_PTR2, + .cnt1_reg = DMA6_CNT1, + .cnt2_reg = DMA6_CNT2, + }, + [SRAM_CH08] = { + .name = "ch8", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA7_PTR1, + .ptr2_reg = DMA7_PTR2, + .cnt1_reg = DMA7_CNT1, + .cnt2_reg = DMA7_CNT2, + }, + [SRAM_CH09] = { + .name = "ch9", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA8_PTR1, + .ptr2_reg = DMA8_PTR2, + .cnt1_reg = DMA8_CNT1, + .cnt2_reg = DMA8_CNT2, + }, +}; + +static int cx23885_risc_decode(u32 risc) +{ + static char *instr[16] = { + [ RISC_SYNC >> 28 ] = "sync", + [ RISC_WRITE >> 28 ] = "write", + [ RISC_WRITEC >> 28 ] = "writec", + [ RISC_READ >> 28 ] = "read", + [ RISC_READC >> 28 ] = "readc", + [ RISC_JUMP >> 28 ] = "jump", + [ RISC_SKIP >> 28 ] = "skip", + [ RISC_WRITERM >> 28 ] = "writerm", + [ RISC_WRITECM >> 28 ] = "writecm", + [ RISC_WRITECR >> 28 ] = "writecr", + }; + static int incr[16] = { + [ RISC_WRITE >> 28 ] = 3, // 2 + [ RISC_JUMP >> 28 ] = 3, // 2 + [ RISC_SKIP >> 28 ] = 1, + [ RISC_SYNC >> 28 ] = 1, + [ RISC_WRITERM >> 28 ] = 3, + [ RISC_WRITECM >> 28 ] = 3, + [ RISC_WRITECR >> 28 ] = 4, + }; + static char *bits[] = { + "12", "13", "14", "resync", + "cnt0", "cnt1", "18", "19", + "20", "21", "22", "23", + "irq1", "irq2", "eol", "sol", + }; + int i; + + printk("0x%08x [ %s", risc, + instr[risc >> 28] ? instr[risc >> 28] : "INVALID"); + for (i = ARRAY_SIZE(bits)-1; i >= 0; i--) + if (risc & (1 << (i + 12))) + printk(" %s",bits[i]); + printk(" count=%d ]\n", risc & 0xfff); + return incr[risc >> 28] ? incr[risc >> 28] : 1; +} + +void cx23885_wakeup(struct cx23885_tsport *port, + struct cx23885_dmaqueue *q, u32 count) +{ + struct cx23885_dev *dev = port->dev; + struct cx23885_buffer *buf; + int bc; + + for (bc = 0;; bc++) { + if (list_empty(&q->active)) + break; + buf = list_entry(q->active.next, + struct cx23885_buffer, vb.queue); + /* count comes from the hw and is is 16bit wide -- + * this trick handles wrap-arounds correctly for + * up to 32767 buffers in flight... */ + if ((s16) (count - buf->count) < 0) + break; + do_gettimeofday(&buf->vb.ts); + dprintk(2,"[%p/%d] wakeup reg=%d buf=%d\n",buf,buf->vb.i, + count, buf->count); + buf->vb.state = STATE_DONE; + list_del(&buf->vb.queue); + wake_up(&buf->vb.done); + } + if (list_empty(&q->active)) { + del_timer(&q->timeout); + } else { + mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + } + if (bc != 1) + printk("%s: %d buffers handled (should be 1)\n",__FUNCTION__,bc); +} +void cx23885_sram_channel_dump(struct cx23885_dev *dev, + struct sram_channel *ch); + +int cx23885_sram_channel_setup(struct cx23885_dev *dev, + struct sram_channel *ch, + unsigned int bpl, u32 risc) +{ + unsigned int i,lines; + u32 cdt; + + if (ch->cmds_start == 0) + { + dprintk(1, "%s() Erasing channel [%s]\n",__FUNCTION__, ch->name); + cx_write(ch->ptr1_reg, 0); + cx_write(ch->ptr2_reg, 0); + cx_write(ch->cnt2_reg, 0); + cx_write(ch->cnt1_reg, 0); + return 0; + } else { + dprintk(1, "%s() Configuring channel [%s]\n",__FUNCTION__, ch->name); + } + + bpl = (bpl + 7) & ~7; /* alignment */ + cdt = ch->cdt; + lines = ch->fifo_size / bpl; + if (lines > 6) + lines = 6; + BUG_ON(lines < 2); + + cx_write(8+0, cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC) ); + cx_write(8+4, cpu_to_le32(8) ); + cx_write(8+8, cpu_to_le32(0) ); + + /* write CDT */ + for (i = 0; i < lines; i++) { + dprintk(2, "%s() 0x%08x <- 0x%08x\n", __FUNCTION__, cdt + 16*i, ch->fifo_start + bpl*i); + cx_write(cdt + 16*i, ch->fifo_start + bpl*i); + cx_write(cdt + 16*i + 4, 0); + cx_write(cdt + 16*i + 8, 0); + cx_write(cdt + 16*i + 12, 0); + } + + /* write CMDS */ + if (ch->jumponly) + cx_write(ch->cmds_start + 0, 8); + else + cx_write(ch->cmds_start + 0, risc); + cx_write(ch->cmds_start + 4, 0); /* 64 bits 63-32 */ + cx_write(ch->cmds_start + 8, cdt); + cx_write(ch->cmds_start + 12, (lines*16) >> 3); + cx_write(ch->cmds_start + 16, ch->ctrl_start); + if (ch->jumponly) + cx_write(ch->cmds_start + 20, 0x80000000 | (64 >> 2) ); + else + cx_write(ch->cmds_start + 20, 64 >> 2); + for (i = 24; i < 80; i += 4) + cx_write(ch->cmds_start + i, 0); + + /* fill registers */ + cx_write(ch->ptr1_reg, ch->fifo_start); + cx_write(ch->ptr2_reg, cdt); + cx_write(ch->cnt2_reg, (lines*16) >> 3); + cx_write(ch->cnt1_reg, (bpl >> 3) -1); + + dprintk(2,"[bridged %d] sram setup %s: bpl=%d lines=%d\n", + cx23885_boards[dev->board].bridge, + ch->name, + bpl, + lines); + + return 0; +} + +void cx23885_sram_channel_dump(struct cx23885_dev *dev, + struct sram_channel *ch) +{ + static char *name[] = { + "init risc lo", + "init risc hi", + "cdt base", + "cdt size", + "iq base", + "iq size", + "risc pc lo", + "risc pc hi", + "iq wr ptr", + "iq rd ptr", + "cdt current", + "pci target lo", + "pci target hi", + "line / byte", + }; + u32 risc; + unsigned int i,j,n; + + printk("%s: %s - dma channel status dump\n", + dev->name, ch->name); + for (i = 0; i < ARRAY_SIZE(name); i++) + printk("%s: cmds: %-15s: 0x%08x\n", + dev->name, name[i], + cx_read(ch->cmds_start + 4*i)); + + for (i = 0; i < 4; i++) { + risc = cx_read(ch->cmds_start + 4 * (i+14)); + printk("%s: risc%d: ", dev->name, i); + cx23885_risc_decode(risc); + } + for (i = 0; i < (64 >> 2); i += n) { + risc = cx_read(ch->ctrl_start + 4 * i); /* No consideration for bits 63-32 */ + printk("%s: (0x%08x) iq %x: ", dev->name, ch->ctrl_start + 4 * i, i); + n = cx23885_risc_decode(risc); + for (j = 1; j < n; j++) { + risc = cx_read(ch->ctrl_start + 4 * (i+j)); + printk("%s: iq %x: 0x%08x [ arg #%d ]\n", + dev->name, i+j, risc, j); + } + } + + printk("%s: fifo: 0x%08x -> 0x%x\n", + dev->name, ch->fifo_start, ch->fifo_start+ch->fifo_size); + printk("%s: ctrl: 0x%08x -> 0x%x\n", + dev->name, ch->ctrl_start, ch->ctrl_start+6*16); + printk("%s: ptr1_reg: 0x%08x\n", + dev->name, cx_read(ch->ptr1_reg)); + printk("%s: ptr2_reg: 0x%08x\n", + dev->name, cx_read(ch->ptr2_reg)); + printk("%s: cnt1_reg: 0x%08x\n", + dev->name, cx_read(ch->cnt1_reg)); + printk("%s: cnt2_reg: 0x%08x\n", + dev->name, cx_read(ch->cnt2_reg)); +} + +void cx23885_risc_disasm(struct cx23885_tsport *port, struct btcx_riscmem *risc) +{ + struct cx23885_dev *dev = port->dev; + unsigned int i,j,n; + + printk("%s: risc disasm: %p [dma=0x%08lx]\n", + dev->name, risc->cpu, (unsigned long)risc->dma); + for (i = 0; i < (risc->size >> 2); i += n) { + printk("%s: %04d: ", dev->name, i); + n = cx23885_risc_decode(risc->cpu[i]); + for (j = 1; j < n; j++) + printk("%s: %04d: 0x%08x [ arg #%d ]\n", + dev->name, i+j, risc->cpu[i+j], j); + if (risc->cpu[i] == RISC_JUMP) + break; + } +} + +void cx23885_shutdown(struct cx23885_dev *dev) +{ + /* disable RISC controller */ + cx_write(DEV_CNTRL2, 0); + + /* Disable all IR activity */ + cx_write(IR_CNTRL_REG, 0); + + /* Disable Video A/B activity */ + cx_write(VID_A_DMA_CTL, 0); + cx_write(VID_B_DMA_CTL, 0); + cx_write(VID_C_DMA_CTL, 0); + + /* Disable Audio activity */ + cx_write(AUD_INT_DMA_CTL, 0); + cx_write(AUD_EXT_DMA_CTL, 0); + + /* Disable Serial port */ + cx_write(UART_CTL, 0); + + /* Disable Interrupts */ + cx_write(PCI_INT_MSK, 0); + cx_write(VID_A_INT_MSK, 0); + cx_write(VID_B_INT_MSK, 0); + cx_write(VID_C_INT_MSK, 0); + cx_write(AUDIO_INT_INT_MSK, 0); + cx_write(AUDIO_EXT_INT_MSK, 0); + +} + +void cx23885_reset(struct cx23885_dev *dev) +{ + dprintk(1, "%s()\n", __FUNCTION__); + + cx23885_shutdown(dev); + + cx_write(PCI_INT_STAT, 0xffffffff); + cx_write(VID_A_INT_STAT, 0xffffffff); + cx_write(VID_B_INT_STAT, 0xffffffff); + cx_write(VID_C_INT_STAT, 0xffffffff); + cx_write(AUDIO_INT_INT_STAT, 0xffffffff); + cx_write(AUDIO_EXT_INT_STAT, 0xffffffff); + cx_write(CLK_DELAY, cx_read(CLK_DELAY) & 0x80000000); + + mdelay(100); + +#if SRAM + cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH01 ], 188*4, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH02 ], 128, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH03 ], 128, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH04 ], 128, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH05 ], 128, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH06 ], 188*4, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH07 ], 128, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH08 ], 128, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH09 ], 128, 0); + +#else + // FIXME: Put a pointer to the sram_channel table in cx23885_dev + // and stop all this ugly switch/if code + switch(cx23885_boards[dev->board].bridge) { + case CX23885_BRIDGE_885: + cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH01 ], 188*4, 0); + cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH02 ], 128, 0); + cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH03 ], 128, 0); + cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH04 ], 128, 0); + cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH05 ], 128, 0); + cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH06 ], 188*4, 0); + cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH07 ], 128, 0); + cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH08 ], 128, 0); + cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH09 ], 128, 0); + break; + case CX23885_BRIDGE_887: + cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH01 ], 188*4, 0); + cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH02 ], 128, 0); + cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH03 ], 128, 0); + cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH04 ], 128, 0); + cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH05 ], 128, 0); + cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH06 ], 188*4, 0); + cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH07 ], 128, 0); + cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH08 ], 128, 0); + cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH09 ], 128, 0); + break; + default: + printk(KERN_ERR "%s() error, default case", __FUNCTION__ ); + } +#endif + + switch(dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1800: + /* GPIO-0 656_CLK */ + /* GPIO-1 656_D0 */ + /* GPIO-2 8295A Reset */ + /* GPIO-3-10 cx23417 data0-7 */ + /* GPIO-11-14 cx23417 addr0-3 */ + /* GPIO-15-18 cx23417 READY, CS, RD, WR */ + /* GPIO-19 IR_RX */ + dprintk( 1, "%s() Configuring HVR1800 GPIO's\n", __FUNCTION__); + // FIXME: Analog requires the tuner is brought out of reset + break; + } +} + + +static int cx23885_pci_quirks(struct cx23885_dev *dev) +{ + dprintk(1, "%s()\n", __FUNCTION__); + + switch(dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1800lp: + cx_clear(RDR_TLCTL0, 1 << 4); + break; + } + return 0; +} + +static int get_resources(struct cx23885_dev *dev) +{ + if (request_mem_region(pci_resource_start(dev->pci,0), + pci_resource_len(dev->pci,0), + dev->name)) + return 0; + + printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx\n", + dev->name, (unsigned long long)pci_resource_start(dev->pci,0)); + + return -EBUSY; +} + +static void cx23885_timeout(unsigned long data); +int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, + u32 reg, u32 mask, u32 value); + +static int cx23885_ir_init(struct cx23885_dev *dev) +{ + dprintk(1, "%s()\n", __FUNCTION__); + + switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1800: + dprintk(1, "%s() FIXME - Implement IR support\n", __FUNCTION__); + break; + } + + return 0; +} + +static int cx23885_dev_setup(struct cx23885_dev *dev) +{ + int i; + + mutex_init(&dev->lock); + + atomic_inc(&dev->refcount); + + dev->nr = cx23885_devcount++; + dev->pci_bus = dev->pci->bus->number; + dev->pci_slot = PCI_SLOT(dev->pci->devfn); + dev->pci_irqmask = 0x001f00; + + /* External Master 1 Bus */ + dev->i2c_bus[0].nr = 0; + dev->i2c_bus[0].dev = dev; + dev->i2c_bus[0].reg_stat = I2C1_STAT; + dev->i2c_bus[0].reg_ctrl = I2C1_CTRL; + dev->i2c_bus[0].reg_addr = I2C1_ADDR; + dev->i2c_bus[0].reg_rdata = I2C1_RDATA; + dev->i2c_bus[0].reg_wdata = I2C1_WDATA; + dev->i2c_bus[0].i2c_period = (0x9d << 24); /* 100kHz */ + + /* External Master 2 Bus */ + dev->i2c_bus[1].nr = 1; + dev->i2c_bus[1].dev = dev; + dev->i2c_bus[1].reg_stat = I2C2_STAT; + dev->i2c_bus[1].reg_ctrl = I2C2_CTRL; + dev->i2c_bus[1].reg_addr = I2C2_ADDR; + dev->i2c_bus[1].reg_rdata = I2C2_RDATA; + dev->i2c_bus[1].reg_wdata = I2C2_WDATA; + dev->i2c_bus[1].i2c_period = (0x9d << 24); /* 100kHz */ + + /* Internal Master 3 Bus */ + dev->i2c_bus[2].nr = 2; + dev->i2c_bus[2].dev = dev; + dev->i2c_bus[2].reg_stat = I2C3_STAT; + dev->i2c_bus[2].reg_ctrl = I2C3_CTRL; + dev->i2c_bus[2].reg_addr = I2C2_ADDR; + dev->i2c_bus[2].reg_rdata = I2C3_RDATA; + dev->i2c_bus[2].reg_wdata = I2C3_WDATA; + dev->i2c_bus[2].i2c_period = (0x07 << 24); /* 1.95MHz */ + + /* Transport bus init dma queue */ + spin_lock_init(&dev->ts2.slock); + dev->ts2.dev = dev; + dev->ts2.nr = 2; + dev->ts2.sram_chno = SRAM_CH06; + INIT_LIST_HEAD(&dev->ts2.mpegq.active); + INIT_LIST_HEAD(&dev->ts2.mpegq.queued); + dev->ts2.mpegq.timeout.function = cx23885_timeout; + dev->ts2.mpegq.timeout.data = (unsigned long)&dev->ts2; + init_timer(&dev->ts2.mpegq.timeout); + + dev->ts2.reg_gpcnt = VID_C_GPCNT; + dev->ts2.reg_gpcnt_ctl = VID_C_GPCNT_CTL; + dev->ts2.reg_dma_ctl = VID_C_DMA_CTL; + dev->ts2.reg_lngth = VID_C_LNGTH; + dev->ts2.reg_hw_sop_ctrl = VID_C_HW_SOP_CTL; + dev->ts2.reg_gen_ctrl = VID_C_GEN_CTL; + dev->ts2.reg_bd_pkt_status = VID_C_BD_PKT_STATUS; + dev->ts2.reg_sop_status = VID_C_SOP_STATUS; + dev->ts2.reg_fifo_ovfl_stat = VID_C_FIFO_OVFL_STAT; + dev->ts2.reg_vld_misc = VID_C_VLD_MISC; + dev->ts2.reg_ts_clk_en = VID_C_TS_CLK_EN; + dev->ts2.reg_ts_int_msk = VID_C_INT_MSK; + + // FIXME: Make this board specific + dev->ts2.pci_irqmask = 0x04; /* TS Port 2 bit */ + dev->ts2.dma_ctl_val = 0x11; /* Enable RISC controller and Fifo */ + dev->ts2.ts_int_msk_val = 0x1111; /* TS port bits for RISC */ + dev->ts2.gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ + dev->ts2.ts_clk_en_val = 0x1; /* Enable TS_CLK */ + + cx23885_risc_stopper(dev->pci, &dev->ts2.mpegq.stopper, dev->ts2.reg_dma_ctl, dev->ts2.dma_ctl_val, 0x00); + + sprintf(dev->name,"cx23885[%d]", dev->nr); + + if (get_resources(dev) < 0) { + printk(KERN_ERR "CORE %s No more PCIe resources for " + "subsystem: %04x:%04x\n", + dev->name, dev->pci->subsystem_vendor, + dev->pci->subsystem_device); + + cx23885_devcount--; + goto fail_free; + } + + mutex_lock(&devlist); + list_add_tail(&dev->devlist, &cx23885_devlist); + mutex_unlock(&devlist); + + /* PCIe stuff */ + dev->lmmio = ioremap(pci_resource_start(dev->pci,0), + pci_resource_len(dev->pci,0)); + + dev->bmmio = (u8 __iomem *)dev->lmmio; + + cx23885_pci_quirks(dev); + + /* board config */ + dev->board = UNSET; + if (card[dev->nr] < cx23885_bcount) + dev->board = card[dev->nr]; + for (i = 0; UNSET == dev->board && i < cx23885_idcount; i++) + if (dev->pci->subsystem_vendor == cx23885_subids[i].subvendor && + dev->pci->subsystem_device == cx23885_subids[i].subdevice) + dev->board = cx23885_subids[i].card; + if (UNSET == dev->board) { + dev->board = CX23885_BOARD_UNKNOWN; + cx23885_card_list(dev); + } + printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", + dev->name, dev->pci->subsystem_vendor, + dev->pci->subsystem_device, cx23885_boards[dev->board].name, + dev->board, card[dev->nr] == dev->board ? + "insmod option" : "autodetected"); + + /* Configure the hardware internal memory for fifos */ + switch(cx23885_boards[dev->board].bridge) { + case CX23885_BRIDGE_UNDEFINED: + case CX23885_BRIDGE_885: + dev->sram_channels = cx23885_sram_channels; + break; + case CX23885_BRIDGE_887: + dev->sram_channels = cx23887_sram_channels; + break; + default: + printk(KERN_ERR "%s() error, default case", __FUNCTION__ ); + } + + /* init hardware */ + cx23885_reset(dev); + + cx23885_i2c_register(&dev->i2c_bus[0]); + cx23885_i2c_register(&dev->i2c_bus[1]); + cx23885_i2c_register(&dev->i2c_bus[2]); + cx23885_call_i2c_clients (&dev->i2c_bus[0], TUNER_SET_STANDBY, NULL); + + cx23885_card_setup(dev); + cx23885_ir_init(dev); + + if (cx23885_dvb_register(&dev->ts2) < 0) { + printk(KERN_ERR "%s() Failed to register dvb adapters\n", __FUNCTION__); + } + + return 0; + +fail_free: + kfree(dev); + return -ENODEV; +} + +void cx23885_dev_unregister(struct cx23885_dev *dev) +{ + release_mem_region(pci_resource_start(dev->pci,0), + pci_resource_len(dev->pci,0)); + + if (!atomic_dec_and_test(&dev->refcount)) + return; + + cx23885_dvb_unregister(&dev->ts2); + cx23885_i2c_unregister(&dev->i2c_bus[2]); + cx23885_i2c_unregister(&dev->i2c_bus[1]); + cx23885_i2c_unregister(&dev->i2c_bus[0]); + + iounmap(dev->lmmio); +} + +static u32* cx23885_risc_field(u32 *rp, struct scatterlist *sglist, + unsigned int offset, u32 sync_line, + unsigned int bpl, unsigned int padding, + unsigned int lines) +{ + struct scatterlist *sg; + unsigned int line,todo; + + /* sync instruction */ + if (sync_line != NO_SYNC_LINE) + *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); + + /* scan lines */ + sg = sglist; + for (line = 0; line < lines; line++) { + while (offset && offset >= sg_dma_len(sg)) { + offset -= sg_dma_len(sg); + sg++; + } + if (bpl <= sg_dma_len(sg)-offset) { + /* fits into current chunk */ + *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|RISC_EOL|bpl); + *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset); + *(rp++)=cpu_to_le32(0); /* bits 63-32 */ + offset+=bpl; + } else { + /* scanline needs to be split */ + todo = bpl; + *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL| + (sg_dma_len(sg)-offset)); + *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset); + *(rp++)=cpu_to_le32(0); /* bits 63-32 */ + todo -= (sg_dma_len(sg)-offset); + offset = 0; + sg++; + while (todo > sg_dma_len(sg)) { + *(rp++)=cpu_to_le32(RISC_WRITE| + sg_dma_len(sg)); + *(rp++)=cpu_to_le32(sg_dma_address(sg)); + *(rp++)=cpu_to_le32(0); /* bits 63-32 */ + todo -= sg_dma_len(sg); + sg++; + } + *(rp++)=cpu_to_le32(RISC_WRITE|RISC_EOL|todo); + *(rp++)=cpu_to_le32(sg_dma_address(sg)); + *(rp++)=cpu_to_le32(0); /* bits 63-32 */ + offset += todo; + } + offset += padding; + } + + return rp; +} + +int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, + struct scatterlist *sglist, + unsigned int top_offset, unsigned int bottom_offset, + unsigned int bpl, unsigned int padding, unsigned int lines) +{ + u32 instructions,fields; + u32 *rp; + int rc; + + fields = 0; + if (UNSET != top_offset) + fields++; + if (UNSET != bottom_offset) + fields++; + + /* estimate risc mem: worst case is one write per page border + + one write per scan line + syncs + jump (all 2 dwords). Padding + can cause next bpl to start close to a page border. First DMA + region may be smaller than PAGE_SIZE */ + /* write and jump need and extra dword */ + instructions = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + lines); + instructions += 2; + //if ((rc = btcx_riscmem_alloc(pci,risc,instructions*8)) < 0) + if ((rc = btcx_riscmem_alloc(pci,risc,instructions*12)) < 0) + return rc; + + /* write risc instructions */ + rp = risc->cpu; + if (UNSET != top_offset) + rp = cx23885_risc_field(rp, sglist, top_offset, 0, + bpl, padding, lines); + if (UNSET != bottom_offset) + rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x200, + bpl, padding, lines); + + /* save pointer to jmp instruction address */ + risc->jmp = rp; + BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size); + return 0; +} + +int cx23885_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc, + struct scatterlist *sglist, unsigned int bpl, + unsigned int lines) +{ + u32 instructions; + u32 *rp; + int rc; + + /* estimate risc mem: worst case is one write per page border + + one write per scan line + syncs + jump (all 2 dwords). Here + there is no padding and no sync. First DMA region may be smaller + than PAGE_SIZE */ + /* Jump and write need an extra dword */ + instructions = 1 + (bpl * lines) / PAGE_SIZE + lines; + instructions += 1; + + //if ((rc = btcx_riscmem_alloc(pci,risc,instructions*8)) < 0) + if ((rc = btcx_riscmem_alloc(pci,risc,instructions*12)) < 0) + return rc; + + /* write risc instructions */ + rp = risc->cpu; + rp = cx23885_risc_field(rp, sglist, 0, NO_SYNC_LINE, bpl, 0, lines); + + /* save pointer to jmp instruction address */ + risc->jmp = rp; + BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size); + return 0; +} + +int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, + u32 reg, u32 mask, u32 value) +{ + u32 *rp; + int rc; + + if ((rc = btcx_riscmem_alloc(pci, risc, 4*16)) < 0) + return rc; + + /* write risc instructions */ + rp = risc->cpu; + //*(rp++) = cpu_to_le32(RISC_WRITECR | RISC_IRQ2 | RISC_IMM); + *(rp++) = cpu_to_le32(RISC_WRITECR | RISC_IRQ2); + *(rp++) = cpu_to_le32(reg); + *(rp++) = cpu_to_le32(value); + *(rp++) = cpu_to_le32(mask); + *(rp++) = cpu_to_le32(RISC_JUMP); + *(rp++) = cpu_to_le32(risc->dma); + *(rp++) = cpu_to_le32(0); /* bits 63-32 */ + return 0; +} + +void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf) +{ + BUG_ON(in_interrupt()); + videobuf_waiton(&buf->vb,0,0); + videobuf_dma_unmap(q, &buf->vb.dma); + videobuf_dma_free(&buf->vb.dma); + btcx_riscmem_free((struct pci_dev *)q->dev, &buf->risc); + buf->vb.state = STATE_NEEDS_INIT; +} + +static int cx23885_start_dma(struct cx23885_tsport *port, + struct cx23885_dmaqueue *q, + struct cx23885_buffer *buf) +{ + struct cx23885_dev *dev = port->dev; + + dprintk(1, "%s() w: %d, h: %d, f: %d\n", __FUNCTION__, + buf->vb.width, buf->vb.height, buf->vb.field); + +#if SRAM + /* setup fifo + format */ + cx23885_sram_channel_setup(dev, + &dev->sram_channels[ port->sram_chno ], + port->ts_packet_size, buf->risc.dma); + if(debug > 5) + cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ] ); +#else + // FIXME: Put a pointer to the sram_channel table in cx23885_dev + // and stop all this ugly switch/if code + switch(cx23885_boards[dev->board].bridge) { + case CX23885_BRIDGE_885: + cx23885_sram_channel_setup(dev, + &cx23885_sram_channels[ port->sram_chno ], + port->ts_packet_size, buf->risc.dma); + if(debug > 5) + cx23885_sram_channel_dump(dev, &cx23885_sram_channels[ port->sram_chno ] ); + break; + case CX23885_BRIDGE_887: + cx23885_sram_channel_setup(dev, + &cx23887_sram_channels[ port->sram_chno ], + port->ts_packet_size, buf->risc.dma); + if(debug > 5) + cx23885_sram_channel_dump(dev, &cx23887_sram_channels[ port->sram_chno ] ); + break; + default: + printk(KERN_ERR "%s() error, default case", __FUNCTION__ ); + } +#endif + + if(debug > 5) + cx23885_risc_disasm(port, &buf->risc); + + /* write TS length to chip */ + cx_write(port->reg_lngth, buf->vb.width); + + if (!(cx23885_boards[dev->board].portc & CX23885_MPEG_DVB)) { + printk( "%s() Failed. Unsupported value in .portc (0x%08x)\n", __FUNCTION__, + cx23885_boards[dev->board].portc ); + return -EINVAL; + } + + // FIXME: review the need for these two lines + dprintk( 1, "%s() doing .dvb\n", __FUNCTION__); + udelay(100); + + cx_write(port->reg_hw_sop_ctrl, 0x47 << 16 | 188 << 4); + cx_write(port->reg_ts_clk_en, port->ts_clk_en_val); + + // FIXME: review the need for this + cx_write(GPIO2, 0x00); + + switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1800lp: + case CX23885_BOARD_HAUPPAUGE_HVR1800: + cx_write(port->reg_vld_misc, 0x00); + dprintk(1, "%s() Configuring HVR1800/lp/1500 board\n", __FUNCTION__); + break; + default: + // FIXME + printk(KERN_ERR "%s() error, default case", __FUNCTION__ ); + } + + cx_write(port->reg_gen_ctrl, port->gen_ctrl_val); + udelay(100); + + /* reset counter to zero */ + cx_write(port->reg_gpcnt_ctl, 3); + q->count = 1; + + /* A bug in the current 887 implementation, causes an NMI assert during + * starting or stopping interrupts or dma. Avoid the bug for the time being, + * enabling the developer to work on the demod/tuner locking work. + */ + switch(cx23885_boards[dev->board].bridge) { + case CX23885_BRIDGE_885: + /* enable irqs */ + dprintk(1, "%s() enabling TS int's and DMA\n", __FUNCTION__ ); + cx_set(port->reg_ts_int_msk, port->ts_int_msk_val); + cx_set(port->reg_dma_ctl, port->dma_ctl_val); + cx_set(PCI_INT_MSK, dev->pci_irqmask | port->pci_irqmask); + break; + case CX23885_BRIDGE_887: + // FIXME + dprintk(1, "%s() NOT enabling TS int's and DMA, NMI bug\n", __FUNCTION__ ); + break; + default: + // FIXME: generate a sensible switch-default message + printk(KERN_ERR "%s() error, default case", __FUNCTION__ ); + } + + dprintk(1, "%s() Register Dump\n", __FUNCTION__); + dprintk(1, "%s() set port ts_int_msk, now %x\n", __FUNCTION__, cx_read(port->reg_ts_int_msk) ); + dprintk(1, "%s() DEV_CNTRL2 0x%08x\n", __FUNCTION__, cx_read(DEV_CNTRL2) ); + dprintk(1, "%s() PCI_INT_MSK 0x%08x\n", __FUNCTION__, cx_read(PCI_INT_MSK) ); + dprintk(1, "%s() VID_A_INT_MSK 0x%08x\n", __FUNCTION__, cx_read(VID_A_INT_MSK) ); + dprintk(1, "%s() VID_B_INT_MSK 0x%08x\n", __FUNCTION__, cx_read(VID_B_INT_MSK) ); + dprintk(1, "%s() VID_C_INT_MSK 0x%08x\n", __FUNCTION__, cx_read(VID_C_INT_MSK) ); + dprintk(1, "%s() VID_A_DMA_CTL 0x%08x\n", __FUNCTION__, cx_read(VID_A_DMA_CTL) ); + dprintk(1, "%s() VID_B_DMA_CTL 0x%08x\n", __FUNCTION__, cx_read(VID_B_DMA_CTL) ); + dprintk(1, "%s() VID_C_DMA_CTL 0x%08x\n", __FUNCTION__, cx_read(VID_C_DMA_CTL) ); + dprintk(1, "%s() AUD_INT_INT_MSK 0x%08x\n", __FUNCTION__, cx_read(AUDIO_INT_INT_MSK) ); + dprintk(1, "%s() AUD_INT_DMA_CTL 0x%08x\n", __FUNCTION__, cx_read(AUD_INT_DMA_CTL) ); + dprintk(1, "%s() AUD_EXT_INT_MSK 0x%08x\n", __FUNCTION__, cx_read(AUDIO_EXT_INT_MSK) ); + dprintk(1, "%s() AUD_EXT_DMA_CTL 0x%08x\n", __FUNCTION__, cx_read(AUD_EXT_DMA_CTL) ); + + cx_set(DEV_CNTRL2, (1<<5)); /* Enable RISC controller */ + + dprintk(1, "%s() set dev_cntrl2, now %x\n", __FUNCTION__, cx_read(DEV_CNTRL2) ); + dprintk(1, "%s() VID_C_DMA_CTL , now %x\n", __FUNCTION__, cx_read(port->reg_dma_ctl) ); + dprintk(1, "%s() VID_C_DMA_CTL , now %x\n", __FUNCTION__, cx_read(VID_C_DMA_CTL) ); + dprintk(1, "%s() PAD_CTRL %x\n", __FUNCTION__, cx_read(PAD_CTRL) ); + dprintk(1, "%s() GPIO2 %x\n", __FUNCTION__, cx_read(GPIO2) ); + dprintk(1, "%s() VID_C_LN_LNGTH , now %x\n", __FUNCTION__, cx_read(port->reg_lngth) ); + dprintk(1, "%s() VID_C_HW_SOP_CTL, now %x\n", __FUNCTION__, cx_read(port->reg_hw_sop_ctrl) ); + dprintk(1, "%s() VID_C_GEN_CTL , now %x\n", __FUNCTION__, cx_read(port->reg_gen_ctrl) ); + dprintk(1, "%s() VID_C_SOP_STATUS, now %x\n", __FUNCTION__, cx_read(VID_C_SOP_STATUS) ); + dprintk(1, "%s() VID_C_TS_CLK_EN , now %x\n", __FUNCTION__, cx_read(VID_C_TS_CLK_EN) ); + dprintk(1, "%s() VID_C_FIFO_OVLST, now %x\n", __FUNCTION__, cx_read(VID_C_FIFO_OVFL_STAT) ); + dprintk(1, "%s() VID_C_INT_MSTAT , now 0x%08x\n", __FUNCTION__, cx_read(VID_C_INT_MSTAT) ); + return 0; +} + +static int cx23885_stop_dma(struct cx23885_tsport *port) +{ + struct cx23885_dev *dev = port->dev; + dprintk(1, "%s()\n", __FUNCTION__); + + /* Stop interrupts and DMA */ + cx_clear(port->reg_ts_int_msk, port->ts_int_msk_val); + cx_clear(port->reg_dma_ctl, port->dma_ctl_val); + + return 0; +} + +static int cx23885_restart_queue(struct cx23885_tsport *port, + struct cx23885_dmaqueue *q) +{ + struct cx23885_dev *dev = port->dev; + struct cx23885_buffer *buf; + struct list_head *item; + + dprintk(5, "%s()\n", __FUNCTION__); + if (list_empty(&q->active)) + { + struct cx23885_buffer *prev; + prev = NULL; + + dprintk(5, "%s() queue is empty\n", __FUNCTION__); + + for (;;) { + if (list_empty(&q->queued)) + return 0; + buf = list_entry(q->queued.next, struct cx23885_buffer, vb.queue); + if (NULL == prev) { + list_del(&buf->vb.queue); + list_add_tail(&buf->vb.queue,&q->active); + cx23885_start_dma(port, q, buf); + buf->vb.state = STATE_ACTIVE; + buf->count = q->count++; + mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + dprintk(5,"[%p/%d] restart_queue - first active\n", + buf,buf->vb.i); + + } else if (prev->vb.width == buf->vb.width && + prev->vb.height == buf->vb.height && + prev->fmt == buf->fmt) { + list_del(&buf->vb.queue); + list_add_tail(&buf->vb.queue,&q->active); + buf->vb.state = STATE_ACTIVE; + buf->count = q->count++; + prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); + prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */ + dprintk(5,"[%p/%d] restart_queue - move to active\n", + buf,buf->vb.i); + } else { + return 0; + } + prev = buf; + } + return 0; + } + + buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue); + dprintk(2,"restart_queue [%p/%d]: restart dma\n", + buf, buf->vb.i); + cx23885_start_dma(port, q, buf); + list_for_each(item,&q->active) { + buf = list_entry(item, struct cx23885_buffer, vb.queue); + buf->count = q->count++; + } + mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + return 0; +} + +/* ------------------------------------------------------------------ */ + +int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port, + struct cx23885_buffer *buf, enum v4l2_field field) +{ + struct cx23885_dev *dev = port->dev; + int size = port->ts_packet_size * port->ts_packet_count; + int rc; + + dprintk(1, "%s: %p\n", __FUNCTION__, buf); + if (0 != buf->vb.baddr && buf->vb.bsize < size) + return -EINVAL; + + if (STATE_NEEDS_INIT == buf->vb.state) { + buf->vb.width = port->ts_packet_size; + buf->vb.height = port->ts_packet_count; + buf->vb.size = size; + buf->vb.field = field /*V4L2_FIELD_TOP*/; + + if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL))) + goto fail; + cx23885_risc_databuffer(dev->pci, &buf->risc, + buf->vb.dma.sglist, + buf->vb.width, buf->vb.height); + } + buf->vb.state = STATE_PREPARED; + return 0; + + fail: + cx23885_free_buffer(q,buf); + return rc; +} + +void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf) +{ + struct cx23885_buffer *prev; + struct cx23885_dev *dev = port->dev; + struct cx23885_dmaqueue *cx88q = &port->mpegq; + + /* add jump to stopper */ + buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); + buf->risc.jmp[1] = cpu_to_le32(cx88q->stopper.dma); + buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ + + if (list_empty(&cx88q->active)) { + dprintk( 1, "queue is empty - first active\n" ); + list_add_tail(&buf->vb.queue,&cx88q->active); + cx23885_start_dma(port, cx88q, buf); + buf->vb.state = STATE_ACTIVE; + buf->count = cx88q->count++; + mod_timer(&cx88q->timeout, jiffies+BUFFER_TIMEOUT); + dprintk(1,"[%p/%d] %s - first active\n", + buf, buf->vb.i, __FUNCTION__); + + } else { + dprintk( 1, "queue is not empty - append to active\n" ); + prev = list_entry(cx88q->active.prev, struct cx23885_buffer, vb.queue); + list_add_tail(&buf->vb.queue,&cx88q->active); + buf->vb.state = STATE_ACTIVE; + buf->count = cx88q->count++; + prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); + prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */ + dprintk( 1, "[%p/%d] %s - append to active\n", + buf, buf->vb.i, __FUNCTION__); + } +} + +/* ----------------------------------------------------------- */ + +static void do_cancel_buffers(struct cx23885_tsport *port, char *reason, int restart) +{ + struct cx23885_dev *dev = port->dev; + struct cx23885_dmaqueue *q = &port->mpegq; + struct cx23885_buffer *buf; + unsigned long flags; + + spin_lock_irqsave(&port->slock,flags); + while (!list_empty(&q->active)) { + buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue); + list_del(&buf->vb.queue); + buf->vb.state = STATE_ERROR; + wake_up(&buf->vb.done); + dprintk(1,"[%p/%d] %s - dma=0x%08lx\n", + buf, buf->vb.i, reason, (unsigned long)buf->risc.dma); + } + if (restart) + { + dprintk(1, "restarting queue\n" ); + cx23885_restart_queue(port, q); + } + spin_unlock_irqrestore(&port->slock,flags); +} + +void cx23885_cancel_buffers(struct cx23885_tsport *port) +{ + struct cx23885_dev *dev = port->dev; + struct cx23885_dmaqueue *q = &port->mpegq; + + dprintk(1, "%s()\n", __FUNCTION__ ); + del_timer_sync(&q->timeout); + cx23885_stop_dma(port); + do_cancel_buffers(port, "cancel", 0); +} + +static void cx23885_timeout(unsigned long data) +{ + struct cx23885_tsport *port = (struct cx23885_tsport *)data; + struct cx23885_dev *dev = port->dev; + + dprintk(1, "%s()\n",__FUNCTION__); + + if (debug > 5) +#if SRAM + cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ]); +#else + { + // FIXME: Put a pointer to the sram_channel table in cx23885_dev + // and stop all this ugly switch/if code + if(cx23885_boards[dev->board].bridge == CX23885_BRIDGE_885) + cx23885_sram_channel_dump(dev, &cx23885_sram_channels[ port->sram_chno ]); + if(cx23885_boards[dev->board].bridge == CX23885_BRIDGE_887) + cx23885_sram_channel_dump(dev, &cx23887_sram_channels[ port->sram_chno ]); + } +#endif + cx23885_stop_dma(port); + do_cancel_buffers(port, "timeout", 1); +} + +#define PCI_MSK_APB_DMA (1 << 12) +#define PCI_MSK_AL_WR (1 << 11) +#define PCI_MSK_AL_RD (1 << 10) +#define PCI_MSK_RISC_WR (1 << 9) +#define PCI_MSK_RISC_RD (1 << 8) + +#define PCI_MSK_AUD_EXT (1 << 4) +#define PCI_MSK_AUD_INT (1 << 3) +#define PCI_MSK_VID_C (1 << 2) +#define PCI_MSK_VID_B (1 << 1) +#define PCI_MSK_VID_A 1 + +#define VID_C_MSK_BAD_PKT (1 << 20) +#define VID_C_MSK_OPC_ERR (1 << 16) +#define VID_C_MSK_SYNC (1 << 12) +#define VID_C_MSK_OF (1 << 8) +#define VID_C_MSK_RISCI2 (1 << 4) +#define VID_C_MSK_RISCI1 1 + +static irqreturn_t cx23885_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + struct cx23885_dev *dev = dev_id; + struct cx23885_tsport *port = &dev->ts2; + u32 pci_status, pci_mask; + u32 ts2_status, ts2_mask; + int count = 0, handled = 0; + + pci_status = cx_read(PCI_INT_STAT); + pci_mask = cx_read(PCI_INT_MSK); + + ts2_status = cx_read(VID_C_INT_STAT); + ts2_mask = cx_read(VID_C_INT_MSK); + + if ( (pci_status == 0) && (ts2_status == 0) ) + goto out; + + count = cx_read(port->reg_gpcnt); + dprintk(7, "pci_status: 0x%08x pci_mask: 0x%08x\n", pci_status, pci_mask ); + dprintk(7, "ts2_status: 0x%08x ts2_mask: 0x%08x count: 0x%x\n", ts2_status, ts2_mask, count ); + + if ( (pci_status & PCI_MSK_RISC_RD) || + (pci_status & PCI_MSK_RISC_WR) || + (pci_status & PCI_MSK_AL_RD) || + (pci_status & PCI_MSK_AL_WR) || + (pci_status & PCI_MSK_APB_DMA) || + (pci_status & PCI_MSK_VID_C) || + (pci_status & PCI_MSK_VID_B) || + (pci_status & PCI_MSK_VID_A) || + (pci_status & PCI_MSK_AUD_INT) || + (pci_status & PCI_MSK_AUD_EXT) ) + { + + if (pci_status & PCI_MSK_RISC_RD) + dprintk(7, " (PCI_MSK_RISC_RD 0x%08x)\n", PCI_MSK_RISC_RD); + if (pci_status & PCI_MSK_RISC_WR) + dprintk(7, " (PCI_MSK_RISC_WR 0x%08x)\n", PCI_MSK_RISC_WR); + if (pci_status & PCI_MSK_AL_RD) + dprintk(7, " (PCI_MSK_AL_RD 0x%08x)\n", PCI_MSK_AL_RD); + if (pci_status & PCI_MSK_AL_WR) + dprintk(7, " (PCI_MSK_AL_WR 0x%08x)\n", PCI_MSK_AL_WR); + if (pci_status & PCI_MSK_APB_DMA) + dprintk(7, " (PCI_MSK_APB_DMA 0x%08x)\n", PCI_MSK_APB_DMA); + if (pci_status & PCI_MSK_VID_C) + dprintk(7, " (PCI_MSK_VID_C 0x%08x)\n", PCI_MSK_VID_C); + if (pci_status & PCI_MSK_VID_B) + dprintk(7, " (PCI_MSK_VID_B 0x%08x)\n", PCI_MSK_VID_B); + if (pci_status & PCI_MSK_VID_A) + dprintk(7, " (PCI_MSK_VID_A 0x%08x)\n", PCI_MSK_VID_A); + if (pci_status & PCI_MSK_AUD_INT) + dprintk(7, " (PCI_MSK_AUD_INT 0x%08x)\n", PCI_MSK_AUD_INT); + if (pci_status & PCI_MSK_AUD_EXT) + dprintk(7, " (PCI_MSK_AUD_EXT 0x%08x)\n", PCI_MSK_AUD_EXT); + + } + + if ( (ts2_status & VID_C_MSK_OPC_ERR) || + (ts2_status & VID_C_MSK_BAD_PKT) || + (ts2_status & VID_C_MSK_SYNC) || + (ts2_status & VID_C_MSK_OF)) + { + if (ts2_status & VID_C_MSK_OPC_ERR) + dprintk(7, " (VID_C_MSK_OPC_ERR 0x%08x)\n", VID_C_MSK_OPC_ERR); + if (ts2_status & VID_C_MSK_BAD_PKT) + dprintk(7, " (VID_C_MSK_BAD_PKT 0x%08x)\n", VID_C_MSK_BAD_PKT); + if (ts2_status & VID_C_MSK_SYNC) + dprintk(7, " (VID_C_MSK_SYNC 0x%08x)\n", VID_C_MSK_SYNC); + if (ts2_status & VID_C_MSK_OF) + dprintk(7, " (VID_C_MSK_OF 0x%08x)\n", VID_C_MSK_OF); + + printk(KERN_ERR "%s: mpeg risc op code error\n", dev->name); + + cx_clear(port->reg_dma_ctl, port->dma_ctl_val); +#if SRAM + cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ]); +#else + cx23885_sram_channel_dump(dev, &cx23885_sram_channels[ port->sram_chno ]); +#endif + + + } else if (ts2_status & VID_C_MSK_RISCI1) { + + dprintk(7, " (RISCI1 0x%08x)\n", VID_C_MSK_RISCI1); + + spin_lock(&port->slock); + count = cx_read(port->reg_gpcnt); + cx23885_wakeup(port, &port->mpegq, count); + spin_unlock(&port->slock); + + } else if (ts2_status & VID_C_MSK_RISCI2) { + + dprintk(7, " (RISCI2 0x%08x)\n", VID_C_MSK_RISCI2); + + spin_lock(&port->slock); + cx23885_restart_queue(port, &port->mpegq); + spin_unlock(&port->slock); + + } + + cx_write(VID_C_INT_STAT, ts2_status); + cx_write(PCI_INT_STAT, pci_status); + handled = 1; +out: + return IRQ_RETVAL(handled); +} + +static int __devinit cx23885_initdev(struct pci_dev *pci_dev, + const struct pci_device_id *pci_id) +{ + struct cx23885_dev *dev; + int err; + + dev = kzalloc(sizeof(*dev),GFP_KERNEL); + if (NULL == dev) + return -ENOMEM; + + /* pci init */ + dev->pci = pci_dev; + if (pci_enable_device(pci_dev)) { + err = -EIO; + goto fail_free; + } + + if (cx23885_dev_setup(dev) < 0) { + err = -EINVAL; + goto fail_free; + } + + /* print pci info */ + pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev); + pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat); + printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, " + "latency: %d, mmio: 0x%llx\n", dev->name, + pci_name(pci_dev), dev->pci_rev, pci_dev->irq, + dev->pci_lat, (unsigned long long)pci_resource_start(pci_dev,0)); + + pci_set_master(pci_dev); + if (!pci_dma_supported(pci_dev, 0xffffffff)) { + printk("%s/0: Oops: no 32bit PCI DMA ???\n", dev->name); + err = -EIO; + goto fail_irq; + } + + err = request_irq(pci_dev->irq, cx23885_irq + , IRQF_SHARED | IRQF_DISABLED, dev->name, dev); + if (err < 0) { + printk(KERN_ERR "%s: can't get IRQ %d\n", + dev->name, pci_dev->irq); + goto fail_irq; + } + + pci_set_drvdata(pci_dev, dev); + return 0; + +fail_irq: + cx23885_dev_unregister(dev); +fail_free: + kfree(dev); + return err; +} + +static void __devexit cx23885_finidev(struct pci_dev *pci_dev) +{ + struct cx23885_dev *dev = pci_get_drvdata(pci_dev); + + cx23885_shutdown(dev); + + pci_disable_device(pci_dev); + + /* unregister stuff */ + free_irq(pci_dev->irq, dev); + pci_set_drvdata(pci_dev, NULL); + + mutex_lock(&devlist); + list_del(&dev->devlist); + mutex_unlock(&devlist); + + cx23885_dev_unregister(dev); + kfree(dev); +} + +static struct pci_device_id cx23885_pci_tbl[] = { + { + /* CX23885 */ + .vendor = 0x14f1, + .device = 0x8852, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + },{ + /* CX23887 Rev 2 */ + .vendor = 0x14f1, + .device = 0x8880, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + },{ + /* --- end of list --- */ + } +}; +MODULE_DEVICE_TABLE(pci, cx23885_pci_tbl); + +static struct pci_driver cx23885_pci_driver = { + .name = "cx23885", + .id_table = cx23885_pci_tbl, + .probe = cx23885_initdev, + .remove = __devexit_p(cx23885_finidev), + /* TODO */ + .suspend = NULL, + .resume = NULL, +}; + +static int cx23885_init(void) +{ + printk(KERN_INFO "cx23885 driver version %d.%d.%d loaded\n", + (CX88_VERSION_CODE >> 16) & 0xff, + (CX88_VERSION_CODE >> 8) & 0xff, + CX88_VERSION_CODE & 0xff); +#ifdef SNAPSHOT + printk(KERN_INFO "cx23885: snapshot date %04d-%02d-%02d\n", + SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); +#endif + return pci_register_driver(&cx23885_pci_driver); +} + +static void cx23885_fini(void) +{ + pci_unregister_driver(&cx23885_pci_driver); +} + +module_init(cx23885_init); +module_exit(cx23885_fini); + +/* ----------------------------------------------------------- */ +/* + * Local variables: + * c-basic-offset: 8 + * End: + * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off + */ diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c new file mode 100644 index 00000000000..4ff85f75f9f --- /dev/null +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -0,0 +1,199 @@ +/* + * Driver for the Conexant CX23885 PCIe bridge + * + * Copyright (c) 2006 Steven Toth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "cx23885.h" +#include "dvb-pll.h" +#include + +#include "s5h1409.h" +#include "mt2131.h" + +static unsigned int debug = 2; + +#define dprintk(level,fmt, arg...) if (debug >= level) \ + printk(KERN_DEBUG "%s: " fmt, dev->name, ## arg) + +/* ------------------------------------------------------------------ */ + +static int dvb_buf_setup(struct videobuf_queue *q, + unsigned int *count, unsigned int *size) +{ + struct cx23885_tsport *port = q->priv_data; + + port->ts_packet_size = 188 * 4; + port->ts_packet_count = 32; + + *size = port->ts_packet_size * port->ts_packet_count; + *count = 32; + return 0; +} + +static int dvb_buf_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, + enum v4l2_field field) +{ + struct cx23885_tsport *port = q->priv_data; + return cx23885_buf_prepare(q, port, (struct cx23885_buffer*)vb,field); +} + +static void dvb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) +{ + struct cx23885_tsport *port = q->priv_data; + cx23885_buf_queue(port, (struct cx23885_buffer*)vb); +} + +static void dvb_buf_release(struct videobuf_queue *q, struct videobuf_buffer *vb) +{ + cx23885_free_buffer(q, (struct cx23885_buffer*)vb); +} + +static struct videobuf_queue_ops dvb_qops = { + .buf_setup = dvb_buf_setup, + .buf_prepare = dvb_buf_prepare, + .buf_queue = dvb_buf_queue, + .buf_release = dvb_buf_release, +}; + +static struct s5h1409_config hauppauge_hvr1800lp_config = { + .demod_address = 0x32 >> 1, + .output_mode = S5H1409_SERIAL_OUTPUT, + .gpio = S5H1409_GPIO_OFF, + .if_freq = 44000, + .inversion = S5H1409_INVERSION_OFF +}; + +static struct s5h1409_config hauppauge_hvr1800_config = { + .demod_address = 0x32 >> 1, + .output_mode = S5H1409_SERIAL_OUTPUT, + .gpio = S5H1409_GPIO_ON, + .if_freq = 44000, + .inversion = S5H1409_INVERSION_OFF +}; + + +static struct mt2131_config hauppauge_hvr1800lp_rev2_tunerconfig = { + 0x61 +}; + +static struct mt2131_config hauppauge_hvr1800_tunerconfig = { + 0x61 +}; + +static int dvb_register(struct cx23885_tsport *port) +{ + struct cx23885_dev *dev = port->dev; + + /* init struct videobuf_dvb */ + port->dvb.name = dev->name; + + /* init frontend */ + switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1800lp: + port->dvb.frontend = dvb_attach(s5h1409_attach, + &hauppauge_hvr1800lp_config, + &dev->i2c_bus[0].i2c_adap); + if (port->dvb.frontend != NULL) { + dvb_attach(mt2131_attach, + port->dvb.frontend, + &dev->i2c_bus[0].i2c_adap, + &hauppauge_hvr1800lp_rev2_tunerconfig, + 0); + } + break; + case CX23885_BOARD_HAUPPAUGE_HVR1800: + port->dvb.frontend = dvb_attach(s5h1409_attach, + &hauppauge_hvr1800_config, + &dev->i2c_bus[0].i2c_adap); + if (port->dvb.frontend != NULL) { + dvb_attach(mt2131_attach, + port->dvb.frontend, + &dev->i2c_bus[0].i2c_adap, + &hauppauge_hvr1800_tunerconfig, + 0); + } + break; + default: + printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n", + dev->name); + break; + } + if (NULL == port->dvb.frontend) { + printk("%s: frontend initialization failed\n", dev->name); + return -1; + } + + /* Put the analog decoder in standby to keep it quiet */ + cx23885_call_i2c_clients (&dev->i2c_bus[0], TUNER_SET_STANDBY, NULL); + + /* register everything */ + return videobuf_dvb_register(&port->dvb, THIS_MODULE, port, &dev->pci->dev); +} + +int cx23885_dvb_register(struct cx23885_tsport *port) +{ + struct cx23885_dev *dev = port->dev; + int err; + + dprintk( 1, "%s\n", __FUNCTION__); + dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n", + dev->board, + dev->name, + dev->pci_bus, + dev->pci_slot); + + err = -ENODEV; + if (!(cx23885_boards[dev->board].portc & CX23885_MPEG_DVB)) + goto fail_core; + + /* dvb stuff */ + printk("%s: cx23885 based dvb card\n", dev->name); + videobuf_queue_init( + &port->dvb.dvbq, + &dvb_qops, + dev->pci, + &port->slock, + V4L2_BUF_TYPE_VIDEO_CAPTURE, + V4L2_FIELD_TOP, + sizeof(struct cx23885_buffer), + port); + err = dvb_register(port); + if (err != 0) + printk("%s() dvb_register failed err = %d\n", __FUNCTION__, err); + + fail_core: + return err; +} + +int cx23885_dvb_unregister(struct cx23885_tsport *port) +{ + /* dvb */ + if(port->dvb.frontend) + videobuf_dvb_unregister(&port->dvb); + + return 0; +} diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c new file mode 100644 index 00000000000..6f5e207c11a --- /dev/null +++ b/drivers/media/video/cx23885/cx23885-i2c.c @@ -0,0 +1,375 @@ +/* + * Driver for the Conexant CX23885 PCIe bridge + * + * Copyright (c) 2006 Steven Toth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include + +#include "cx23885.h" + +#include + +static unsigned int i2c_debug = 2; +module_param(i2c_debug, int, 0644); +MODULE_PARM_DESC(i2c_debug,"enable debug messages [i2c]"); + +static unsigned int i2c_scan = 0; +module_param(i2c_scan, int, 0444); +MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time"); + +#define dprintk(level,fmt, arg...) if (i2c_debug >= level) \ + printk(KERN_DEBUG "%s: " fmt, dev->name , ## arg) + +#define I2C_WAIT_DELAY 32 +#define I2C_WAIT_RETRY 64 + +#define I2C_EXTEND (1 << 3) +#define I2C_NOSTOP (1 << 4) + +static inline int i2c_slave_did_ack(struct i2c_adapter *i2c_adap) +{ + struct cx23885_i2c *bus = i2c_adap->algo_data; + struct cx23885_dev *dev = bus->dev; + return cx_read(bus->reg_stat) & 0x01; +} + +static inline int i2c_is_busy(struct i2c_adapter *i2c_adap) +{ + struct cx23885_i2c *bus = i2c_adap->algo_data; + struct cx23885_dev *dev = bus->dev; + return cx_read(bus->reg_stat) & 0x02 ? 1 : 0; +} + +static int i2c_wait_done(struct i2c_adapter *i2c_adap) +{ + int count; + + for (count = 0; count < I2C_WAIT_RETRY; count++) { + if (!i2c_is_busy(i2c_adap)) + break; + udelay(I2C_WAIT_DELAY); + } + + if (I2C_WAIT_RETRY == count) + return 0; + + return 1; +} + +static int i2c_sendbytes(struct i2c_adapter *i2c_adap, const struct i2c_msg *msg, int last) +{ + struct cx23885_i2c *bus = i2c_adap->algo_data; + struct cx23885_dev *dev = bus->dev; + u32 wdata, addr, ctrl; + int retval, cnt; + + dprintk(1, "%s()\n", __FUNCTION__); + /* Deal with i2c probe functions with zero payload */ + if (msg->len == 0) { + cx_write(bus->reg_addr, msg->addr << 25); + cx_write(bus->reg_ctrl, bus->i2c_period | (1 << 2)); + if (!i2c_wait_done(i2c_adap)) + return -EIO; + if (!i2c_slave_did_ack(i2c_adap)) + return -EIO; + + dprintk(1, "%s() returns 0\n", __FUNCTION__); + return 0; + } + + + /* dev, reg + first byte */ + addr = (msg->addr << 25) | msg->buf[0]; + wdata = msg->buf[0]; + ctrl = bus->i2c_period | (1 << 12) | (1 << 2); + + if (msg->len > 1) + ctrl |= I2C_NOSTOP | I2C_EXTEND; + + cx_write(bus->reg_addr, addr); + cx_write(bus->reg_wdata, wdata); + cx_write(bus->reg_ctrl, ctrl); + + retval = i2c_wait_done(i2c_adap); + if (retval < 0) + goto err; + if (retval == 0) + goto eio; + if (i2c_debug) { + printk(" addr << 1, msg->buf[0]); + if (!(ctrl & I2C_NOSTOP)) + printk(" >\n"); + } + + for (cnt = 1; cnt < msg->len; cnt++ ) { + /* following bytes */ + wdata = msg->buf[cnt]; + ctrl = bus->i2c_period | (1 << 12) | (1 << 2); + + if (cnt < msg->len-1 || !last) + ctrl |= I2C_NOSTOP | I2C_EXTEND; + + //printk("addr = 0x%08x wdata = 0x%08x ctrl = 0x%08x\n", addr, wdata, ctrl); + cx_write(bus->reg_addr, addr); + cx_write(bus->reg_wdata, wdata); + cx_write(bus->reg_ctrl, ctrl); + + retval = i2c_wait_done(i2c_adap); + if (retval < 0) + goto err; + if (retval == 0) + goto eio; + if (i2c_debug) { + printk(" %02x", msg->buf[cnt]); + if (!(ctrl & I2C_NOSTOP)) + printk(" >\n"); + } + } + return msg->len; + + eio: + retval = -EIO; + err: + printk(" ERR: %d\n",retval); + return retval; +} + +static int i2c_readbytes(struct i2c_adapter *i2c_adap, const struct i2c_msg *msg, int last) +{ + struct cx23885_i2c *bus = i2c_adap->algo_data; + struct cx23885_dev *dev = bus->dev; + u32 ctrl, cnt; + int retval; + + dprintk(1, "%s()\n", __FUNCTION__); + + /* Deal with i2c probe functions with zero payload */ + if (msg->len == 0) { + cx_write(bus->reg_addr, msg->addr << 25); + cx_write(bus->reg_ctrl, bus->i2c_period | (1 << 2) | 1); + if (!i2c_wait_done(i2c_adap)) + return -EIO; + if (!i2c_slave_did_ack(i2c_adap)) + return -EIO; + + + dprintk(1, "%s() returns 0\n", __FUNCTION__); + return 0; + } + + for(cnt = 0; cnt < msg->len; cnt++) { + + ctrl = bus->i2c_period | (1 << 12) | (1 << 2) | 1; + + if (cnt < msg->len-1 || !last) + ctrl |= I2C_NOSTOP | I2C_EXTEND; + + cx_write(bus->reg_addr, msg->addr << 25); + cx_write(bus->reg_ctrl, ctrl); + + retval = i2c_wait_done(i2c_adap); + if (retval < 0) + goto err; + if (retval == 0) + goto eio; + msg->buf[cnt] = cx_read(bus->reg_rdata) & 0xff; + if (i2c_debug) { + if (!(ctrl & I2C_NOSTOP)) + printk(" addr << 1) +1); + printk(" =%02x", msg->buf[cnt]); + if (!(ctrl & I2C_NOSTOP)) + printk(" >\n"); + } + } + return msg->len; + + eio: + retval = -EIO; + err: + printk(" ERR: %d\n",retval); + return retval; +} + +static int i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) +{ + struct cx23885_i2c *bus = i2c_adap->algo_data; + struct cx23885_dev *dev = bus->dev; + int i, retval = 0; + + dprintk(1, "%s(num = %d)\n", __FUNCTION__, num); + + for (i = 0 ; i < num; i++) { + dprintk(1, "%s(num = %d) addr = 0x%02x len = 0x%x\n" + , __FUNCTION__, num, msgs[i].addr, msgs[i].len); + if (msgs[i].flags & I2C_M_RD) { + /* read */ + retval = i2c_readbytes(i2c_adap, &msgs[i], i+1 == num); + if (retval < 0) + goto err; + } else { + /* write */ + retval = i2c_sendbytes(i2c_adap, &msgs[i], i+1 == num); + if (retval < 0) + goto err; + } + } + return num; + + err: + return retval; +} + +static int attach_inform(struct i2c_client *client) +{ + struct cx23885_dev *dev = i2c_get_adapdata(client->adapter); + + dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n", + client->driver->driver.name, client->addr, client->name); + + if (!client->driver->command) + return 0; + + return 0; +} + +static int detach_inform(struct i2c_client *client) +{ + struct cx23885_dev *dev = i2c_get_adapdata(client->adapter); + + dprintk(1, "i2c detach [client=%s]\n", client->name); + + return 0; +} + +void cx23885_call_i2c_clients(struct cx23885_i2c *bus, unsigned int cmd, void *arg) +{ +// struct cx23885_dev *dev = bus->dev; + + if (bus->i2c_rc != 0) + return; + + i2c_clients_command(&bus->i2c_adap, cmd, arg); +} + +static int cx23885_algo_control(struct i2c_adapter *adap, + unsigned int cmd, unsigned long arg) +{ + return 0; +} + +static u32 cx23885_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_SMBUS_EMUL; +} + +static struct i2c_algorithm cx23885_i2c_algo_template = { + .master_xfer = i2c_xfer, + .algo_control = cx23885_algo_control, + .functionality = cx23885_functionality, +}; + +/* ----------------------------------------------------------------------- */ + +static struct i2c_adapter cx23885_i2c_adap_template = { + .name = "cx23885", + .owner = THIS_MODULE, + .id = I2C_HW_B_CX23885, + .algo = &cx23885_i2c_algo_template, +// .class = I2C_CLASS_TV_ANALOG, + .client_register = attach_inform, + .client_unregister = detach_inform, +}; + +static struct i2c_client cx23885_i2c_client_template = { + .name = "cx23885 internal", +}; + +static char *i2c_devs[128] = { + [ 0x32 >> 1 ] = "cx24227", + [ 0x88 >> 1 ] = "cx25837", + [ 0x84 >> 1 ] = "tda8295", + [ 0xa0 >> 1 ] = "eeprom", + [ 0xc0 >> 1 ] = "mt2131/tda8275", + [ 0xc2 >> 1 ] = "mt2131/tda8275", +}; + +static void do_i2c_scan(char *name, struct i2c_client *c) +{ + unsigned char buf; + int i,rc; + + for (i = 0; i < 128; i++) { + c->addr = i; + rc = i2c_master_recv(c,&buf,0); + if (rc < 0) + continue; + printk("%s: i2c scan: found device @ 0x%x [%s]\n", + name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); + } +} + +/* init + register i2c algo-bit adapter */ +int cx23885_i2c_register(struct cx23885_i2c *bus) +{ + struct cx23885_dev *dev = bus->dev; + + dprintk(1, "%s(bus = %d)\n", __FUNCTION__, bus->nr); + + memcpy(&bus->i2c_adap, &cx23885_i2c_adap_template, sizeof(bus->i2c_adap)); + memcpy(&bus->i2c_algo, &cx23885_i2c_algo_template, sizeof(bus->i2c_algo)); + memcpy(&bus->i2c_client, &cx23885_i2c_client_template, sizeof(bus->i2c_client)); + + bus->i2c_adap.dev.parent = &dev->pci->dev; + + strlcpy(bus->i2c_adap.name, bus->dev->name, sizeof(bus->i2c_adap.name)); + bus->i2c_algo.data = bus; + bus->i2c_adap.algo_data = bus; + i2c_add_adapter(&bus->i2c_adap); + + bus->i2c_client.adapter = &bus->i2c_adap; + + if (0 == bus->i2c_rc) { + printk("%s: i2c bus %d registered\n", dev->name, bus->nr); + if (i2c_scan) + do_i2c_scan(dev->name, &bus->i2c_client); + } else + printk("%s: i2c bus %d register FAILED\n", dev->name, bus->nr); + + return bus->i2c_rc; +} + +int cx23885_i2c_unregister(struct cx23885_i2c *bus) +{ + i2c_del_adapter(&bus->i2c_adap); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +EXPORT_SYMBOL(cx23885_call_i2c_clients); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/video/cx23885/cx23885-reg.h b/drivers/media/video/cx23885/cx23885-reg.h new file mode 100644 index 00000000000..5cb692f20d2 --- /dev/null +++ b/drivers/media/video/cx23885/cx23885-reg.h @@ -0,0 +1,429 @@ +/* + * Driver for the Conexant CX23885 PCIe bridge + * + * Copyright (c) 2006 Steven Toth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _CX23885_REG_H_ +#define _CX23885_REG_H_ + + +/* +Address Map +0x00000000 -> 0x00009000 TX SRAM (Fifos) +0x00010000 -> 0x00013c00 RX SRAM CMDS + CDT + +EACH CMDS struct is 0x80 bytes long + +DMAx_PTR1 = 0x03040 address of first cluster +DMAx_PTR2 = 0x10600 address of the CDT +DMAx_CNT1 = cluster size in (bytes >> 4) -1 +DMAx_CNT2 = total cdt size for all entries >> 3 + +Cluster Descriptor entry = 4 DWORDS + DWORD 0 -> ptr to cluster + DWORD 1 Reserved + DWORD 2 Reserved + DWORD 3 Reserved + +Channel manager Data Structure entry = 20 DWORD + 0 IntialProgramCounterLow + 1 IntialProgramCounterHigh + 2 ClusterDescriptorTableBase + 3 ClusterDescriptorTableSize + 4 InstructionQueueBase + 5 InstructionQueueSize +... Reserved + 19 Reserved + + +*/ + +/* Risc Instructions */ +#define RISC_CNT_INC 0x00010000 +#define RISC_CNT_RESET 0x00030000 +#define RISC_IRQ1 0x01000000 +#define RISC_IRQ2 0x02000000 +#define RISC_EOL 0x04000000 +#define RISC_SOL 0x08000000 +#define RISC_WRITE 0x10000000 +#define RISC_SKIP 0x20000000 +#define RISC_JUMP 0x70000000 +#define RISC_SYNC 0x80000000 +#define RISC_RESYNC 0x80008000 +#define RISC_READ 0x90000000 +#define RISC_WRITERM 0xB0000000 +#define RISC_WRITECM 0xC0000000 +#define RISC_WRITECR 0xD0000000 + +//#define RISC_SYNC_ODD 0x80000000 +//#define RISC_SYNC_EVEN 0x80000200 +//#define RISC_RESYNC_ODD 0x80008000 +//#define RISC_RESYNC_EVEN 0x80008200 + +// Do we need these? +#define RISC_WRITEC 0x50000000 +#define RISC_READC 0xA0000000 + +// Is this used? +#define RISC_IMM 0x00000001 + +//#define RISC_CNT_NONE 0x00000000 +//#define RISC_CNT_RSVR 0x00020000 +//#define RISC_JMP_SRP 0x01 + +/* Audio and Video Core */ +#define HOST_REG1 0x00000000 +#define HOST_REG2 0x00000001 +#define HOST_REG3 0x00000002 + +/* Chip Configuration Registers */ +#define CHIP_CTRL 0x00000100 +#define AFE_CTRL 0x00000104 +#define VID_PLL_INT_POST 0x00000108 +#define VID_PLL_FRAC 0x0000010C +#define AUX_PLL_INT_POST 0x00000110 +#define AUX_PLL_FRAC 0x00000114 +#define SYS_PLL_INT_POST 0x00000118 +#define SYS_PLL_FRAC 0x0000011C +#define PIN_CTRL 0x00000120 +#define AUD_IO_CTRL 0x00000124 +#define AUD_LOCK1 0x00000128 +#define AUD_LOCK2 0x0000012C +#define POWER_CTRL 0x00000130 +#define AFE_DIAG_CTRL1 0x00000134 +#define AFE_DIAG_CTRL3 0x0000013C +#define PLL_DIAG_CTRL 0x00000140 +#define AFE_CLK_OUT_CTRL 0x00000144 +#define DLL1_DIAG_CTRL 0x0000015C + +/* GPIO[23:19] Output Enable */ +#define GPIO2_OUT_EN_REG 0x00000160 +/* GPIO[23:19] Data Registers */ +#define GPIO2 0x00000164 + +#define IFADC_CTRL 0x00000180 + +/* Infrared Remote Registers */ +#define IR_CNTRL_REG 0x00000200 +#define IR_TXCLK_REG 0x00000204 +#define IR_RXCLK_REG 0x00000208 +#define IR_CDUTY_REG 0x0000020C +#define IR_STAT_REG 0x00000210 +#define IR_IRQEN_REG 0x00000214 +#define IR_FILTR_REG 0x00000218 +#define IR_FIFO_REG 0x0000023C + +/* Video Decoder Registers */ +#define MODE_CTRL 0x00000400 +#define OUT_CTRL1 0x00000404 +#define OUT_CTRL2 0x00000408 +#define GEN_STAT 0x0000040C +#define INT_STAT_MASK 0x00000410 +#define LUMA_CTRL 0x00000414 +#define HSCALE_CTRL 0x00000418 +#define VSCALE_CTRL 0x0000041C +#define CHROMA_CTRL 0x00000420 +#define VBI_LINE_CTRL1 0x00000424 +#define VBI_LINE_CTRL2 0x00000428 +#define VBI_LINE_CTRL3 0x0000042C +#define VBI_LINE_CTRL4 0x00000430 +#define VBI_LINE_CTRL5 0x00000434 +#define VBI_FC_CFG 0x00000438 +#define VBI_MISC_CFG1 0x0000043C +#define VBI_MISC_CFG2 0x00000440 +#define VBI_PAY1 0x00000444 +#define VBI_PAY2 0x00000448 +#define VBI_CUST1_CFG1 0x0000044C +#define VBI_CUST1_CFG2 0x00000450 +#define VBI_CUST1_CFG3 0x00000454 +#define VBI_CUST2_CFG1 0x00000458 +#define VBI_CUST2_CFG2 0x0000045C +#define VBI_CUST2_CFG3 0x00000460 +#define VBI_CUST3_CFG1 0x00000464 +#define VBI_CUST3_CFG2 0x00000468 +#define VBI_CUST3_CFG3 0x0000046C +#define HORIZ_TIM_CTRL 0x00000470 +#define VERT_TIM_CTRL 0x00000474 +#define SRC_COMB_CFG 0x00000478 +#define CHROMA_VBIOFF_CFG 0x0000047C +#define FIELD_COUNT 0x00000480 +#define MISC_TIM_CTRL 0x00000484 +#define DFE_CTRL1 0x00000488 +#define DFE_CTRL2 0x0000048C +#define DFE_CTRL3 0x00000490 +#define PLL_CTRL 0x00000494 +#define HTL_CTRL 0x00000498 +#define COMB_CTRL 0x0000049C +#define CRUSH_CTRL 0x000004A0 +#define SOFT_RST_CTRL 0x000004A4 +#define CX885_VERSION 0x000004B4 +#define VBI_PASS_CTRL 0x000004BC + +/* Audio Decoder Registers */ +/* 8051 Configuration */ +#define DL_CTL 0x00000800 +#define STD_DET_STATUS 0x00000804 +#define STD_DET_CTL 0x00000808 +#define DW8051_INT 0x0000080C +#define GENERAL_CTL 0x00000810 +#define AAGC_CTL 0x00000814 +#define DEMATRIX_CTL 0x000008CC +#define PATH1_CTL1 0x000008D0 +#define PATH1_VOL_CTL 0x000008D4 +#define PATH1_EQ_CTL 0x000008D8 +#define PATH1_SC_CTL 0x000008DC +#define PATH2_CTL1 0x000008E0 +#define PATH2_VOL_CTL 0x000008E4 +#define PATH2_EQ_CTL 0x000008E8 +#define PATH2_SC_CTL 0x000008EC + +/* Sample Rate Converter */ +#define SRC_CTL 0x000008F0 +#define SRC_LF_COEF 0x000008F4 +#define SRC1_CTL 0x000008F8 +#define SRC2_CTL 0x000008FC +#define SRC3_CTL 0x00000900 +#define SRC4_CTL 0x00000904 +#define SRC5_CTL 0x00000908 +#define SRC6_CTL 0x0000090C +#define BAND_OUT_SEL 0x00000910 +#define I2S_N_CTL 0x00000914 +#define I2S_OUT_CTL 0x00000918 +#define AUTOCONFIG_REG 0x000009C4 + +/* Audio ADC Registers */ +#define DSM_CTRL1 0x00000000 +#define DSM_CTRL2 0x00000001 +#define CHP_EN_CTRL 0x00000002 +#define CHP_CLK_CTRL1 0x00000004 +#define CHP_CLK_CTRL2 0x00000005 +#define BG_REF_CTRL 0x00000006 +#define SD2_SW_CTRL1 0x00000008 +#define SD2_SW_CTRL2 0x00000009 +#define SD2_BIAS_CTRL 0x0000000A +#define AMP_BIAS_CTRL 0x0000000C +#define CH_PWR_CTRL1 0x0000000E +#define CH_PWR_CTRL2 0x0000000F +#define DSM_STATUS1 0x00000010 +#define DSM_STATUS2 0x00000011 +#define DIG_CTL1 0x00000012 +#define DIG_CTL2 0x00000013 +#define I2S_TX_CFG 0x0000001A + +#define DEV_CNTRL2 0x00040000 +#define PCI_INT_MSK 0x00040010 +#define PCI_MSK_APB_DMA (1 << 12) +#define PCI_MSK_AL_WR (1 << 11) +#define PCI_MSK_AL_RD (1 << 10) +#define PCI_MSK_RISC_WR (1 << 9) +#define PCI_MSK_RISC_RD (1 << 8) +#define PCI_MSK_AUD_EXT (1 << 4) +#define PCI_MSK_AUD_INT (1 << 3) +#define PCI_MSK_VID_C (1 << 2) +#define PCI_MSK_VID_B (1 << 1) +#define PCI_MSK_VID_A 1 +#define PCI_INT_STAT 0x00040014 +#define PCI_INT_MSTAT 0x00040018 + +#define VID_A_INT_MSK 0x00040020 +#define VID_A_INT_STAT 0x00040024 +#define VID_A_INT_MSTAT 0x00040028 +#define VID_A_INT_SSTAT 0x0004002C + +#define VID_B_INT_MSK 0x00040030 +#define VID_B_INT_STAT 0x00040034 +#define VID_B_INT_MSTAT 0x00040038 +#define VID_B_INT_SSTAT 0x0004003C + +#define VID_C_INT_MSK 0x00040040 +#define VID_C_MSK_BAD_PKT (1 << 20) +#define VID_C_MSK_OPC_ERR (1 << 16) +#define VID_C_MSK_SYNC (1 << 12) +#define VID_C_MSK_OF (1 << 8) +#define VID_C_MSK_RISCI2 (1 << 4) +#define VID_C_MSK_RISCI1 1 +#define VID_C_INT_STAT 0x00040044 +#define VID_C_INT_MSTAT 0x00040048 +#define VID_C_INT_SSTAT 0x0004004C + +#define AUDIO_INT_INT_MSK 0x00040050 +#define AUDIO_INT_INT_STAT 0x00040054 +#define AUDIO_INT_INT_MSTAT 0x00040058 +#define AUDIO_INT_INT_SSTAT 0x0004005C + +#define AUDIO_EXT_INT_MSK 0x00040060 +#define AUDIO_EXT_INT_STAT 0x00040064 +#define AUDIO_EXT_INT_MSTAT 0x00040068 +#define AUDIO_EXT_INT_SSTAT 0x0004006C + +#define RDR_CFG0 0x00050000 +#define RDR_CFG1 0x00050004 +#define RDR_TLCTL0 0x00050318 + +/* APB DMAC Current Buffer Pointer */ +#define DMA1_PTR1 0x00100000 +#define DMA2_PTR1 0x00100004 +#define DMA3_PTR1 0x00100008 +#define DMA4_PTR1 0x0010000C +#define DMA5_PTR1 0x00100010 +#define DMA6_PTR1 0x00100014 +#define DMA7_PTR1 0x00100018 +#define DMA8_PTR1 0x0010001C + +/* APB DMAC Current Table Pointer */ +#define DMA1_PTR2 0x00100040 +#define DMA2_PTR2 0x00100044 +#define DMA3_PTR2 0x00100048 +#define DMA4_PTR2 0x0010004C +#define DMA5_PTR2 0x00100050 +#define DMA6_PTR2 0x00100054 +#define DMA7_PTR2 0x00100058 +#define DMA8_PTR2 0x0010005C + +/* APB DMAC Buffer Limit */ +#define DMA1_CNT1 0x00100080 +#define DMA2_CNT1 0x00100084 +#define DMA3_CNT1 0x00100088 +#define DMA4_CNT1 0x0010008C +#define DMA5_CNT1 0x00100090 +#define DMA6_CNT1 0x00100094 +#define DMA7_CNT1 0x00100098 +#define DMA8_CNT1 0x0010009C + +/* APB DMAC Table Size */ +#define DMA1_CNT2 0x001000C0 +#define DMA2_CNT2 0x001000C4 +#define DMA3_CNT2 0x001000C8 +#define DMA4_CNT2 0x001000CC +#define DMA5_CNT2 0x001000D0 +#define DMA6_CNT2 0x001000D4 +#define DMA7_CNT2 0x001000D8 +#define DMA8_CNT2 0x001000DC + +/* Timer Counters */ +#define TM_CNT_LDW 0x00110000 +#define TM_CNT_UW 0x00110004 +#define TM_LMT_LDW 0x00110008 +#define TM_LMT_UW 0x0011000C + +/* GPIO */ +#define GP0_IO 0x00110010 +#define GPIO_ISM 0x00110014 +#define SOFT_RESET 0x0011001C + +/* GPIO (417 Microsoftcontroller) RW Data */ +#define MC417_RWD 0x00110020 + +/* GPIO (417 Microsoftcontroller) Output Enable, Low Active */ +#define MC417_OEN 0x00110024 +#define MC417_CTL 0x00110028 +#define CLK_DELAY 0x00110048 +#define PAD_CTRL 0x0011004C + +/* Video A Interface */ +#define VID_A_GPCNT 0x00130020 +#define VBI_A_GPCNT 0x00130024 +#define VID_A_GPCNT_CTL 0x00130030 +#define VBI_A_GPCNT_CTL 0x00130034 +#define VID_A_DMA_CTL 0x00130040 +#define VID_A_VIP_CTRL 0x00130080 +#define VID_A_PIXEL_FRMT 0x00130084 +#define VID_A_VBI_CTRL 0x00130088 + +/* Video B Interface */ +#define VID_B_DMA 0x00130100 +#define VBI_B_DMA 0x00130108 +#define VID_B_GPCNT 0x00130120 +#define VBI_B_GPCNT 0x00130124 +#define VID_B_GPCNT_CTL 0x00130130 +#define VBI_B_GPCNT_CTL 0x00130134 +#define VID_B_DMA_CTL 0x00130140 +#define VID_B_SRC_SEL 0x00130144 +#define VID_B_LNGTH 0x00130150 +#define VID_B_HW_SOP_CTL 0x00130154 +#define VID_B_GEN_CTL 0x00130158 +#define VID_B_BD_PKT_STATUS 0x0013015C +#define VID_B_SOP_STATUS 0x00130160 +#define VID_B_FIFO_OVFL_STAT 0x00130164 +#define VID_B_VLD_MISC 0x00130168 +#define VID_B_TS_CLK_EN 0x0013016C +#define VID_B_VIP_CTRL 0x00130180 +#define VID_B_PIXEL_FRMT 0x00130184 + +/* Video C Interface */ +#define VID_C_GPCNT 0x00130220 +#define VID_C_GPCNT_CTL 0x00130230 +#define VBI_C_GPCNT_CTL 0x00130234 +#define VID_C_DMA_CTL 0x00130240 +#define VID_C_LNGTH 0x00130250 +#define VID_C_HW_SOP_CTL 0x00130254 +#define VID_C_GEN_CTL 0x00130258 +#define VID_C_BD_PKT_STATUS 0x0013025C +#define VID_C_SOP_STATUS 0x00130260 +#define VID_C_FIFO_OVFL_STAT 0x00130264 +#define VID_C_VLD_MISC 0x00130268 +#define VID_C_TS_CLK_EN 0x0013026C + +/* Internal Audio Interface */ +#define AUD_INT_A_GPCNT 0x00140020 +#define AUD_INT_B_GPCNT 0x00140024 +#define AUD_INT_A_GPCNT_CTL 0x00140030 +#define AUD_INT_B_GPCNT_CTL 0x00140034 +#define AUD_INT_DMA_CTL 0x00140040 +#define AUD_INT_A_LNGTH 0x00140050 +#define AUD_INT_B_LNGTH 0x00140054 +#define AUD_INT_A_MODE 0x00140058 +#define AUD_INT_B_MODE 0x0014005C + +/* External Audio Interface */ +#define AUD_EXT_DMA 0x00140100 +#define AUD_EXT_GPCNT 0x00140120 +#define AUD_EXT_GPCNT_CTL 0x00140130 +#define AUD_EXT_DMA_CTL 0x00140140 +#define AUD_EXT_LNGTH 0x00140150 +#define AUD_EXT_A_MODE 0x00140158 + +/* I2C Bus 1 */ +#define I2C1_ADDR 0x00180000 +#define I2C1_WDATA 0x00180004 +#define I2C1_CTRL 0x00180008 +#define I2C1_RDATA 0x0018000C +#define I2C1_STAT 0x00180010 + +/* I2C Bus 2 */ +#define I2C2_ADDR 0x00190000 +#define I2C2_WDATA 0x00190004 +#define I2C2_CTRL 0x00190008 +#define I2C2_RDATA 0x0019000C +#define I2C2_STAT 0x00190010 + +/* I2C Bus 3 */ +#define I2C3_ADDR 0x001A0000 +#define I2C3_WDATA 0x001A0004 +#define I2C3_CTRL 0x001A0008 +#define I2C3_RDATA 0x001A000C +#define I2C3_STAT 0x001A0010 + +/* UART */ +#define UART_CTL 0x001B0000 +#define UART_BRD 0x001B0004 +#define UART_ISR 0x001B000C +#define UART_CNT 0x001B0010 + +#endif /* _CX23885_REG_H_ */ diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h new file mode 100644 index 00000000000..f58ab86bd53 --- /dev/null +++ b/drivers/media/video/cx23885/cx23885.h @@ -0,0 +1,295 @@ +/* + * Driver for the Conexant CX23885 PCIe bridge + * + * Copyright (c) 2006 Steven Toth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "btcx-risc.h" +#include "cx23885-reg.h" + +#include +#include + +#define CX88_VERSION_CODE KERNEL_VERSION(0,0,6) + +#define UNSET (-1U) + +#define CX23885_MAXBOARDS 8 + +#define SRAM 0 + +/* Max number of inputs by card */ +#define MAX_CX23885_INPUT 8 + +//#define SHADOW_MAX 3 + +#define BUFFER_TIMEOUT (HZ) /* 0.5 seconds */ + +#define CX23885_BOARD_NOAUTO UNSET +#define CX23885_BOARD_UNKNOWN 0 +#define CX23885_BOARD_HAUPPAUGE_HVR1800lp 1 +#define CX23885_BOARD_HAUPPAUGE_HVR1800 2 + +enum cx23885_itype { + CX23885_VMUX_COMPOSITE1 = 1, + CX23885_VMUX_COMPOSITE2, + CX23885_VMUX_COMPOSITE3, + CX23885_VMUX_COMPOSITE4, + CX23885_VMUX_SVIDEO, + CX23885_VMUX_TELEVISION, + CX23885_VMUX_CABLE, + CX23885_VMUX_DVB, + CX23885_VMUX_DEBUG, + CX23885_RADIO, +}; + +struct cx23885_fmt { + char *name; + u32 fourcc; /* v4l2 format id */ + int depth; + int flags; + u32 cxformat; +}; + +/* buffer for one video frame */ +struct cx23885_buffer { + /* common v4l buffer stuff -- must be first */ + struct videobuf_buffer vb; + + /* cx23885 specific */ + unsigned int bpl; + struct btcx_riscmem risc; + struct cx23885_fmt *fmt; + u32 count; +}; + +struct cx23885_input { + enum cx23885_itype type; + unsigned int vmux; + u32 gpio0, gpio1, gpio2, gpio3; +}; + +struct cx23885_board { + char *name; + enum { + CX23885_MPEG_UNDEFINED = 0, + CX23885_MPEG_DVB + } portc; + enum { + CX23885_BRIDGE_UNDEFINED = 0, + CX23885_BRIDGE_885 = 885, + CX23885_BRIDGE_887 = 887, + } bridge; + struct cx23885_input input[MAX_CX23885_INPUT]; +}; + +struct cx23885_subid { + u16 subvendor; + u16 subdevice; + u32 card; +}; + +struct cx23885_i2c { + struct cx23885_dev *dev; + + int nr; + + /* i2c i/o */ + struct i2c_adapter i2c_adap; + struct i2c_algo_bit_data i2c_algo; + struct i2c_client i2c_client; + u32 i2c_rc; + + /* 885 registers used for raw addess */ + u32 i2c_period; + u32 reg_ctrl; + u32 reg_stat; + u32 reg_addr; + u32 reg_rdata; + u32 reg_wdata; +}; + +struct cx23885_dmaqueue { + struct list_head active; + struct list_head queued; + struct timer_list timeout; + struct btcx_riscmem stopper; + u32 count; +}; + +struct cx23885_tsport { + struct cx23885_dev *dev; + + int nr; + int sram_chno; + + struct videobuf_dvb dvb; + + /* dma queues */ + struct cx23885_dmaqueue mpegq; + u32 ts_packet_size; + u32 ts_packet_count; + + int width; + int height; + + spinlock_t slock; + + /* registers */ + u32 reg_gpcnt; + u32 reg_gpcnt_ctl; + u32 reg_dma_ctl; + u32 reg_lngth; + u32 reg_hw_sop_ctrl; + u32 reg_gen_ctrl; + u32 reg_bd_pkt_status; + u32 reg_sop_status; + u32 reg_fifo_ovfl_stat; + u32 reg_vld_misc; + u32 reg_ts_clk_en; + u32 reg_ts_int_msk; + + /* Default register vals */ + int pci_irqmask; + u32 dma_ctl_val; + u32 ts_int_msk_val; + u32 gen_ctrl_val; + u32 ts_clk_en_val; +}; + +struct cx23885_dev { + struct list_head devlist; + atomic_t refcount; + + /* pci stuff */ + struct pci_dev *pci; + unsigned char pci_rev, pci_lat; + int pci_bus, pci_slot; + u32 __iomem *lmmio; + u8 __iomem *bmmio; + //u32 shadow[SHADOW_MAX]; + int pci_irqmask; + + /* I2C adapters: Master 1 and 2 (External) and Master 3 (Internal only) */ + struct cx23885_i2c i2c_bus[3]; + + int nr; + struct mutex lock; + + /* board details */ + unsigned int board; + char name[32]; + + struct cx23885_tsport ts2; + + /* sram configuration */ + struct sram_channel *sram_channels; +}; + +#define SRAM_CH01 0 /* Video A */ +#define SRAM_CH02 1 /* VBI A */ +#define SRAM_CH03 2 /* Video B */ +#define SRAM_CH04 3 /* Transport via B */ +#define SRAM_CH05 4 /* VBI B */ +#define SRAM_CH06 5 /* Video C */ +#define SRAM_CH07 6 /* Transport via C */ +#define SRAM_CH08 7 /* Audio Internal A */ +#define SRAM_CH09 8 /* Audio Internal B */ +#define SRAM_CH10 9 /* Audio External */ +#define SRAM_CH11 10 /* COMB_3D_N */ +#define SRAM_CH12 11 /* Comb 3D N1 */ +#define SRAM_CH13 12 /* Comb 3D N2 */ +#define SRAM_CH14 13 /* MOE Vid */ +#define SRAM_CH15 14 /* MOE RSLT */ + +struct sram_channel { + char *name; + u32 cmds_start; + u32 ctrl_start; + u32 cdt; + u32 fifo_start;; + u32 fifo_size; + u32 ptr1_reg; + u32 ptr2_reg; + u32 cnt1_reg; + u32 cnt2_reg; + u32 jumponly; +}; + +/* ----------------------------------------------------------- */ + +#define cx_read(reg) readl(dev->lmmio + ((reg)>>2)) +#define cx_write(reg,value) writel((value), dev->lmmio + ((reg)>>2)) + +#define cx_andor(reg,mask,value) \ + writel((readl(dev->lmmio+((reg)>>2)) & ~(mask)) |\ + ((value) & (mask)), dev->lmmio+((reg)>>2)) + +#define cx_set(reg,bit) cx_andor((reg),(bit),(bit)) +#define cx_clear(reg,bit) cx_andor((reg),(bit),0) + + +extern int cx23885_sram_channel_setup(struct cx23885_dev *dev, + struct sram_channel *ch, + unsigned int bpl, u32 risc); + +/* ----------------------------------------------------------- */ +/* cx23885-cards.c */ + +extern struct cx23885_board cx23885_boards[]; +extern const unsigned int cx23885_bcount; + +extern struct cx23885_subid cx23885_subids[]; +extern const unsigned int cx23885_idcount; + +extern void cx23885_card_list(struct cx23885_dev *dev); +extern void cx23885_card_setup(struct cx23885_dev *dev); +extern void cx23885_card_setup_pre_i2c(struct cx23885_dev *dev); + +extern int cx23885_dvb_register(struct cx23885_tsport *port); +extern int cx23885_dvb_unregister(struct cx23885_tsport *port); + +extern int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port, + struct cx23885_buffer *buf, enum v4l2_field field); + +extern void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf); +extern void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf); + +/* ----------------------------------------------------------- */ +/* cx23885-i2c.c */ +extern int cx23885_i2c_register(struct cx23885_i2c *bus); +extern int cx23885_i2c_unregister(struct cx23885_i2c *bus); +extern void cx23885_call_i2c_clients(struct cx23885_i2c *bus, unsigned int cmd, void *arg); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off + */ -- cgit v1.2.3-70-g09d2 From 2f52cdb20955b024e6b48f4e3d797504c8568a6d Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 11 Mar 2007 20:55:18 -0300 Subject: V4L/DVB (6151): include drivers/media/video/cx23885/Kconfig Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 04756c342cb..5d74925748c 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -668,6 +668,8 @@ config VIDEO_HEXIUM_GEMINI source "drivers/media/video/cx88/Kconfig" +source "drivers/media/video/cx23885/Kconfig" + source "drivers/media/video/ivtv/Kconfig" config VIDEO_M32R_AR -- cgit v1.2.3-70-g09d2 From 03121f05f98cf9bba8f0fe77ef381c17681e1386 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 11 Mar 2007 20:57:52 -0300 Subject: V4L/DVB (6152): cx23885: forward compatibility fixes for recent kernels - fix #include for - fix cx23885_irq declaration for 2.6.19 and later Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 2 +- drivers/media/video/cx23885/cx23885.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 876d396fb7a..4e6e8737e38 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -1361,7 +1361,7 @@ static void cx23885_timeout(unsigned long data) #define VID_C_MSK_RISCI2 (1 << 4) #define VID_C_MSK_RISCI1 1 -static irqreturn_t cx23885_irq(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t cx23885_irq(int irq, void *dev_id) { struct cx23885_dev *dev = dev_id; struct cx23885_tsport *port = &dev->ts2; diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index f58ab86bd53..769a0e7541c 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -28,7 +28,9 @@ #include #include #include +#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE) #include +#endif #include "btcx-risc.h" #include "cx23885-reg.h" -- cgit v1.2.3-70-g09d2 From a2129af5b65e28dc3a10402603aa714e493b2169 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Fri, 16 Mar 2007 11:48:33 -0300 Subject: V4L/DVB (6153): I2C bus 3 register was incorrect I2C bus 3 was being initialised with the incorrect address register. Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 4e6e8737e38..fda0c1631db 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -722,7 +722,7 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) dev->i2c_bus[2].dev = dev; dev->i2c_bus[2].reg_stat = I2C3_STAT; dev->i2c_bus[2].reg_ctrl = I2C3_CTRL; - dev->i2c_bus[2].reg_addr = I2C2_ADDR; + dev->i2c_bus[2].reg_addr = I2C3_ADDR; dev->i2c_bus[2].reg_rdata = I2C3_RDATA; dev->i2c_bus[2].reg_wdata = I2C3_WDATA; dev->i2c_bus[2].i2c_period = (0x07 << 24); /* 1.95MHz */ -- cgit v1.2.3-70-g09d2 From 3bd4065961aa03d030cd58feec03d60479fc4348 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 19 Mar 2007 17:46:03 -0300 Subject: V4L/DVB (6154): NMI hang and corrupt transport packet fixes The sram allocations for the cx23887 differ slightly from the cx23885. This patch modifies the cx23887 specific sram memory map to reflect this. As a result, interrupts and DMA handling have also been enabled in cx23885_start_dma() for 887 specific boards. ATSC streaming is now available on cx23885 and cx23887 bridges. Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index fda0c1631db..5769db47529 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -270,7 +270,7 @@ struct sram_channel cx23887_sram_channels[] = { .name = "TS2 C", .cmds_start = 0x10140, .ctrl_start = 0x10680, - .cdt = 0x10480, + .cdt = 0x108d0, .fifo_start = 0x6000, .fifo_size = 0x1000, .ptr1_reg = DMA5_PTR1, @@ -1095,16 +1095,13 @@ static int cx23885_start_dma(struct cx23885_tsport *port, */ switch(cx23885_boards[dev->board].bridge) { case CX23885_BRIDGE_885: + case CX23885_BRIDGE_887: /* enable irqs */ dprintk(1, "%s() enabling TS int's and DMA\n", __FUNCTION__ ); cx_set(port->reg_ts_int_msk, port->ts_int_msk_val); cx_set(port->reg_dma_ctl, port->dma_ctl_val); cx_set(PCI_INT_MSK, dev->pci_irqmask | port->pci_irqmask); break; - case CX23885_BRIDGE_887: - // FIXME - dprintk(1, "%s() NOT enabling TS int's and DMA, NMI bug\n", __FUNCTION__ ); - break; default: // FIXME: generate a sensible switch-default message printk(KERN_ERR "%s() error, default case", __FUNCTION__ ); -- cgit v1.2.3-70-g09d2 From 3328e4fbf10a2c2513d4de662ab251e0f4cb7c3e Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 19 Mar 2007 18:01:07 -0300 Subject: V4L/DVB (6155): Cleanup/remove code to access the sram memory maps The cx23885 and cx23887 family use two different memory maps which govern how the internal SRAM is configured. This patch streamlines the access to those structures. Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 77 ++---------------------------- drivers/media/video/cx23885/cx23885.h | 2 - 2 files changed, 3 insertions(+), 76 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 5769db47529..b1f75350e83 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -584,7 +584,6 @@ void cx23885_reset(struct cx23885_dev *dev) mdelay(100); -#if SRAM cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH01 ], 188*4, 0); cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH02 ], 128, 0); cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH03 ], 128, 0); @@ -595,37 +594,6 @@ void cx23885_reset(struct cx23885_dev *dev) cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH08 ], 128, 0); cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH09 ], 128, 0); -#else - // FIXME: Put a pointer to the sram_channel table in cx23885_dev - // and stop all this ugly switch/if code - switch(cx23885_boards[dev->board].bridge) { - case CX23885_BRIDGE_885: - cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH01 ], 188*4, 0); - cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH02 ], 128, 0); - cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH03 ], 128, 0); - cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH04 ], 128, 0); - cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH05 ], 128, 0); - cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH06 ], 188*4, 0); - cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH07 ], 128, 0); - cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH08 ], 128, 0); - cx23885_sram_channel_setup(dev, &cx23885_sram_channels[ SRAM_CH09 ], 128, 0); - break; - case CX23885_BRIDGE_887: - cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH01 ], 188*4, 0); - cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH02 ], 128, 0); - cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH03 ], 128, 0); - cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH04 ], 128, 0); - cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH05 ], 128, 0); - cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH06 ], 188*4, 0); - cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH07 ], 128, 0); - cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH08 ], 128, 0); - cx23885_sram_channel_setup(dev, &cx23887_sram_channels[ SRAM_CH09 ], 128, 0); - break; - default: - printk(KERN_ERR "%s() error, default case", __FUNCTION__ ); - } -#endif - switch(dev->board) { case CX23885_BOARD_HAUPPAUGE_HVR1800: /* GPIO-0 656_CLK */ @@ -1019,38 +987,14 @@ static int cx23885_start_dma(struct cx23885_tsport *port, dprintk(1, "%s() w: %d, h: %d, f: %d\n", __FUNCTION__, buf->vb.width, buf->vb.height, buf->vb.field); -#if SRAM /* setup fifo + format */ cx23885_sram_channel_setup(dev, &dev->sram_channels[ port->sram_chno ], port->ts_packet_size, buf->risc.dma); - if(debug > 5) + if(debug > 5) { cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ] ); -#else - // FIXME: Put a pointer to the sram_channel table in cx23885_dev - // and stop all this ugly switch/if code - switch(cx23885_boards[dev->board].bridge) { - case CX23885_BRIDGE_885: - cx23885_sram_channel_setup(dev, - &cx23885_sram_channels[ port->sram_chno ], - port->ts_packet_size, buf->risc.dma); - if(debug > 5) - cx23885_sram_channel_dump(dev, &cx23885_sram_channels[ port->sram_chno ] ); - break; - case CX23885_BRIDGE_887: - cx23885_sram_channel_setup(dev, - &cx23887_sram_channels[ port->sram_chno ], - port->ts_packet_size, buf->risc.dma); - if(debug > 5) - cx23885_sram_channel_dump(dev, &cx23887_sram_channels[ port->sram_chno ] ); - break; - default: - printk(KERN_ERR "%s() error, default case", __FUNCTION__ ); - } -#endif - - if(debug > 5) cx23885_risc_disasm(port, &buf->risc); + } /* write TS length to chip */ cx_write(port->reg_lngth, buf->vb.width); @@ -1323,18 +1267,8 @@ static void cx23885_timeout(unsigned long data) dprintk(1, "%s()\n",__FUNCTION__); if (debug > 5) -#if SRAM cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ]); -#else - { - // FIXME: Put a pointer to the sram_channel table in cx23885_dev - // and stop all this ugly switch/if code - if(cx23885_boards[dev->board].bridge == CX23885_BRIDGE_885) - cx23885_sram_channel_dump(dev, &cx23885_sram_channels[ port->sram_chno ]); - if(cx23885_boards[dev->board].bridge == CX23885_BRIDGE_887) - cx23885_sram_channel_dump(dev, &cx23887_sram_channels[ port->sram_chno ]); - } -#endif + cx23885_stop_dma(port); do_cancel_buffers(port, "timeout", 1); } @@ -1431,12 +1365,7 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) printk(KERN_ERR "%s: mpeg risc op code error\n", dev->name); cx_clear(port->reg_dma_ctl, port->dma_ctl_val); -#if SRAM cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ]); -#else - cx23885_sram_channel_dump(dev, &cx23885_sram_channels[ port->sram_chno ]); -#endif - } else if (ts2_status & VID_C_MSK_RISCI1) { diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 769a0e7541c..04105bcf53f 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -44,8 +44,6 @@ #define CX23885_MAXBOARDS 8 -#define SRAM 0 - /* Max number of inputs by card */ #define MAX_CX23885_INPUT 8 -- cgit v1.2.3-70-g09d2 From 0fc0739ba940c07e97599a7ee04c24faae9808ed Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 19 Mar 2007 18:03:03 -0300 Subject: V4L/DVB (6156): Added the I2C_FUNC_I2C support to the cx23885 i2c algo definition This is required to support the cx258xx family of audio and video decoders. Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c index 6f5e207c11a..dbd048d08dd 100644 --- a/drivers/media/video/cx23885/cx23885-i2c.c +++ b/drivers/media/video/cx23885/cx23885-i2c.c @@ -279,7 +279,7 @@ static int cx23885_algo_control(struct i2c_adapter *adap, static u32 cx23885_functionality(struct i2c_adapter *adap) { - return I2C_FUNC_SMBUS_EMUL; + return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C; } static struct i2c_algorithm cx23885_i2c_algo_template = { -- cgit v1.2.3-70-g09d2 From e133be0f587996f112d7984c03606af418a7ca05 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 19 Mar 2007 19:22:41 -0300 Subject: V4L/DVB (6157): Removed the need to manually define .bridge for each card Moved the field from cx23885_board to cx23885_dev and added code to iautomatically set the bridge type based on the pci device id. Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-cards.c | 3 --- drivers/media/video/cx23885/cx23885-core.c | 24 +++++++++++------------- drivers/media/video/cx23885/cx23885.h | 11 ++++++----- 3 files changed, 17 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index 9344fb5d95f..decf602ab16 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -32,7 +32,6 @@ struct cx23885_board cx23885_boards[] = { [CX23885_BOARD_UNKNOWN] = { .name = "UNKNOWN/GENERIC", - .bridge = CX23885_BRIDGE_UNDEFINED, .input = {{ .type = CX23885_VMUX_COMPOSITE1, .vmux = 0, @@ -49,7 +48,6 @@ struct cx23885_board cx23885_boards[] = { }, [CX23885_BOARD_HAUPPAUGE_HVR1800lp] = { .name = "Hauppauge WinTV-HVR1800lp", - .bridge = CX23885_BRIDGE_885, .portc = CX23885_MPEG_DVB, .input = {{ .type = CX23885_VMUX_TELEVISION, @@ -71,7 +69,6 @@ struct cx23885_board cx23885_boards[] = { }, [CX23885_BOARD_HAUPPAUGE_HVR1800] = { .name = "Hauppauge WinTV-HVR1800", - .bridge = CX23885_BRIDGE_887, .portc = CX23885_MPEG_DVB, .input = {{ .type = CX23885_VMUX_TELEVISION, diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index b1f75350e83..d8e376dee68 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -452,8 +452,8 @@ int cx23885_sram_channel_setup(struct cx23885_dev *dev, cx_write(ch->cnt2_reg, (lines*16) >> 3); cx_write(ch->cnt1_reg, (bpl >> 3) -1); - dprintk(2,"[bridged %d] sram setup %s: bpl=%d lines=%d\n", - cx23885_boards[dev->board].bridge, + dprintk(2,"[bridge %d] sram setup %s: bpl=%d lines=%d\n", + dev->bridge, ch->name, bpl, lines); @@ -770,18 +770,16 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) dev->board, card[dev->nr] == dev->board ? "insmod option" : "autodetected"); - /* Configure the hardware internal memory for fifos */ - switch(cx23885_boards[dev->board].bridge) { - case CX23885_BRIDGE_UNDEFINED: - case CX23885_BRIDGE_885: - dev->sram_channels = cx23885_sram_channels; - break; - case CX23885_BRIDGE_887: + /* Configure the internal memory */ + if(dev->pci->device == 0x8880) { + dev->bridge = CX23885_BRIDGE_887; dev->sram_channels = cx23887_sram_channels; - break; - default: - printk(KERN_ERR "%s() error, default case", __FUNCTION__ ); + } else + if(dev->pci->device == 0x8852) { + dev->bridge = CX23885_BRIDGE_885; + dev->sram_channels = cx23885_sram_channels; } + dprintk(1, "%s() Memory configured for PCIe bridge type %d\n", __FUNCTION__, dev->bridge); /* init hardware */ cx23885_reset(dev); @@ -1037,7 +1035,7 @@ static int cx23885_start_dma(struct cx23885_tsport *port, * starting or stopping interrupts or dma. Avoid the bug for the time being, * enabling the developer to work on the demod/tuner locking work. */ - switch(cx23885_boards[dev->board].bridge) { + switch(dev->bridge) { case CX23885_BRIDGE_885: case CX23885_BRIDGE_887: /* enable irqs */ diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 04105bcf53f..4e1fc68d420 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -101,11 +101,6 @@ struct cx23885_board { CX23885_MPEG_UNDEFINED = 0, CX23885_MPEG_DVB } portc; - enum { - CX23885_BRIDGE_UNDEFINED = 0, - CX23885_BRIDGE_885 = 885, - CX23885_BRIDGE_887 = 887, - } bridge; struct cx23885_input input[MAX_CX23885_INPUT]; }; @@ -210,6 +205,12 @@ struct cx23885_dev { /* sram configuration */ struct sram_channel *sram_channels; + + enum { + CX23885_BRIDGE_UNDEFINED = 0, + CX23885_BRIDGE_885 = 885, + CX23885_BRIDGE_887 = 887, + } bridge; }; #define SRAM_CH01 0 /* Video A */ -- cgit v1.2.3-70-g09d2 From fe475163ff9680495af3b1b5b7633ea7a42e4185 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Tue, 20 Mar 2007 15:27:53 -0300 Subject: V4L/DVB (6158): Fix MT2131 tuner lock status problem The mt2131 tuner reports lock even when the hardware should not lock. This patch allows the s5h1409 demodulator to be configured to query either the tuner driver for status, or the demodulator status when the application requests lock status. This avoids returning false CARRIER and/or SIGNAL lock status. S5H1409 and MT2131 drivers. This is the remainder of the changeset, which only touches cx23885-dvb.c Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-dvb.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index 4ff85f75f9f..188a5a7819c 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -84,7 +84,8 @@ static struct s5h1409_config hauppauge_hvr1800lp_config = { .output_mode = S5H1409_SERIAL_OUTPUT, .gpio = S5H1409_GPIO_OFF, .if_freq = 44000, - .inversion = S5H1409_INVERSION_OFF + .inversion = S5H1409_INVERSION_OFF, + .status_mode = S5H1409_DEMODLOCKING }; static struct s5h1409_config hauppauge_hvr1800_config = { @@ -92,7 +93,8 @@ static struct s5h1409_config hauppauge_hvr1800_config = { .output_mode = S5H1409_SERIAL_OUTPUT, .gpio = S5H1409_GPIO_ON, .if_freq = 44000, - .inversion = S5H1409_INVERSION_OFF + .inversion = S5H1409_INVERSION_OFF, + .status_mode = S5H1409_DEMODLOCKING }; -- cgit v1.2.3-70-g09d2 From 047646bfbbe5ec961d2430514ae29fa0b87ab651 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Tue, 20 Mar 2007 15:33:53 -0300 Subject: V4L/DVB (6159): General code cleanup Removed if 0'd code, removed cx88 references. Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 6 +++--- drivers/media/video/cx23885/cx23885.h | 10 +--------- 2 files changed, 4 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index d8e376dee68..804ba7ff977 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -1498,9 +1498,9 @@ static struct pci_driver cx23885_pci_driver = { static int cx23885_init(void) { printk(KERN_INFO "cx23885 driver version %d.%d.%d loaded\n", - (CX88_VERSION_CODE >> 16) & 0xff, - (CX88_VERSION_CODE >> 8) & 0xff, - CX88_VERSION_CODE & 0xff); + (CX23885_VERSION_CODE >> 16) & 0xff, + (CX23885_VERSION_CODE >> 8) & 0xff, + CX23885_VERSION_CODE & 0xff); #ifdef SNAPSHOT printk(KERN_INFO "cx23885: snapshot date %04d-%02d-%02d\n", SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 4e1fc68d420..b60de21c238 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -38,7 +38,7 @@ #include #include -#define CX88_VERSION_CODE KERNEL_VERSION(0,0,6) +#define CX23885_VERSION_CODE KERNEL_VERSION(0,0,1) #define UNSET (-1U) @@ -69,14 +69,6 @@ enum cx23885_itype { CX23885_RADIO, }; -struct cx23885_fmt { - char *name; - u32 fourcc; /* v4l2 format id */ - int depth; - int flags; - u32 cxformat; -}; - /* buffer for one video frame */ struct cx23885_buffer { /* common v4l buffer stuff -- must be first */ -- cgit v1.2.3-70-g09d2 From 70ebd70573a58a2c0405ef038f1acf74c795eaa5 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 20 Mar 2007 21:32:12 -0300 Subject: V4L/DVB (6161): cx23885-dvb.c doesnt need to include dvb-pll.h The dvb-pll module is not being used by this driver. Remove the unneeded #include. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-dvb.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index 188a5a7819c..79948553901 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -28,7 +28,6 @@ #include #include "cx23885.h" -#include "dvb-pll.h" #include #include "s5h1409.h" -- cgit v1.2.3-70-g09d2 From 44a6481dcd9ec835bbd608b1b2ee47ee62c7e1d8 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 20 Mar 2007 23:00:18 -0300 Subject: V4L/DVB (6162): cx23885: whitespace cleanups Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-cards.c | 3 +- drivers/media/video/cx23885/cx23885-core.c | 275 +++++++++++++++------------- drivers/media/video/cx23885/cx23885-dvb.c | 59 +++--- drivers/media/video/cx23885/cx23885-i2c.c | 40 ++-- drivers/media/video/cx23885/cx23885.h | 17 +- 5 files changed, 211 insertions(+), 183 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index decf602ab16..8bb3fe4a876 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -171,7 +171,8 @@ void cx23885_card_setup(struct cx23885_dev *dev) if (dev->i2c_bus[0].i2c_rc == 0) { dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1; - tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom, sizeof(eeprom)); + tveeprom_read(&dev->i2c_bus[0].i2c_client, + eeprom, sizeof(eeprom)); } switch (dev->board) { diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 804ba7ff977..6f0a8dbc6b3 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -349,15 +349,15 @@ static int cx23885_risc_decode(u32 risc) printk("0x%08x [ %s", risc, instr[risc >> 28] ? instr[risc >> 28] : "INVALID"); - for (i = ARRAY_SIZE(bits)-1; i >= 0; i--) + for (i = ARRAY_SIZE(bits) - 1; i >= 0; i--) if (risc & (1 << (i + 12))) - printk(" %s",bits[i]); + printk(" %s", bits[i]); printk(" count=%d ]\n", risc & 0xfff); return incr[risc >> 28] ? incr[risc >> 28] : 1; } void cx23885_wakeup(struct cx23885_tsport *port, - struct cx23885_dmaqueue *q, u32 count) + struct cx23885_dmaqueue *q, u32 count) { struct cx23885_dev *dev = port->dev; struct cx23885_buffer *buf; @@ -374,7 +374,7 @@ void cx23885_wakeup(struct cx23885_tsport *port, if ((s16) (count - buf->count) < 0) break; do_gettimeofday(&buf->vb.ts); - dprintk(2,"[%p/%d] wakeup reg=%d buf=%d\n",buf,buf->vb.i, + dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i, count, buf->count); buf->vb.state = STATE_DONE; list_del(&buf->vb.queue); @@ -383,31 +383,34 @@ void cx23885_wakeup(struct cx23885_tsport *port, if (list_empty(&q->active)) { del_timer(&q->timeout); } else { - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); } if (bc != 1) - printk("%s: %d buffers handled (should be 1)\n",__FUNCTION__,bc); + printk("%s: %d buffers handled (should be 1)\n", + __FUNCTION__, bc); } void cx23885_sram_channel_dump(struct cx23885_dev *dev, - struct sram_channel *ch); + struct sram_channel *ch); int cx23885_sram_channel_setup(struct cx23885_dev *dev, - struct sram_channel *ch, - unsigned int bpl, u32 risc) + struct sram_channel *ch, + unsigned int bpl, u32 risc) { - unsigned int i,lines; + unsigned int i, lines; u32 cdt; if (ch->cmds_start == 0) { - dprintk(1, "%s() Erasing channel [%s]\n",__FUNCTION__, ch->name); + dprintk(1, "%s() Erasing channel [%s]\n", __FUNCTION__, + ch->name); cx_write(ch->ptr1_reg, 0); cx_write(ch->ptr2_reg, 0); cx_write(ch->cnt2_reg, 0); cx_write(ch->cnt1_reg, 0); return 0; } else { - dprintk(1, "%s() Configuring channel [%s]\n",__FUNCTION__, ch->name); + dprintk(1, "%s() Configuring channel [%s]\n", __FUNCTION__, + ch->name); } bpl = (bpl + 7) & ~7; /* alignment */ @@ -417,13 +420,14 @@ int cx23885_sram_channel_setup(struct cx23885_dev *dev, lines = 6; BUG_ON(lines < 2); - cx_write(8+0, cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC) ); - cx_write(8+4, cpu_to_le32(8) ); - cx_write(8+8, cpu_to_le32(0) ); + cx_write(8 + 0, cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC) ); + cx_write(8 + 4, cpu_to_le32(8) ); + cx_write(8 + 8, cpu_to_le32(0) ); /* write CDT */ for (i = 0; i < lines; i++) { - dprintk(2, "%s() 0x%08x <- 0x%08x\n", __FUNCTION__, cdt + 16*i, ch->fifo_start + bpl*i); + dprintk(2, "%s() 0x%08x <- 0x%08x\n", __FUNCTION__, cdt + 16*i, + ch->fifo_start + bpl*i); cx_write(cdt + 16*i, ch->fifo_start + bpl*i); cx_write(cdt + 16*i + 4, 0); cx_write(cdt + 16*i + 8, 0); @@ -462,7 +466,7 @@ int cx23885_sram_channel_setup(struct cx23885_dev *dev, } void cx23885_sram_channel_dump(struct cx23885_dev *dev, - struct sram_channel *ch) + struct sram_channel *ch) { static char *name[] = { "init risc lo", @@ -481,7 +485,7 @@ void cx23885_sram_channel_dump(struct cx23885_dev *dev, "line / byte", }; u32 risc; - unsigned int i,j,n; + unsigned int i, j, n; printk("%s: %s - dma channel status dump\n", dev->name, ch->name); @@ -491,16 +495,19 @@ void cx23885_sram_channel_dump(struct cx23885_dev *dev, cx_read(ch->cmds_start + 4*i)); for (i = 0; i < 4; i++) { - risc = cx_read(ch->cmds_start + 4 * (i+14)); + risc = cx_read(ch->cmds_start + 4 * (i + 14)); printk("%s: risc%d: ", dev->name, i); cx23885_risc_decode(risc); } for (i = 0; i < (64 >> 2); i += n) { - risc = cx_read(ch->ctrl_start + 4 * i); /* No consideration for bits 63-32 */ - printk("%s: (0x%08x) iq %x: ", dev->name, ch->ctrl_start + 4 * i, i); + risc = cx_read(ch->ctrl_start + 4 * i); + /* No consideration for bits 63-32 */ + + printk("%s: (0x%08x) iq %x: ", dev->name, + ch->ctrl_start + 4 * i, i); n = cx23885_risc_decode(risc); for (j = 1; j < n; j++) { - risc = cx_read(ch->ctrl_start + 4 * (i+j)); + risc = cx_read(ch->ctrl_start + 4 * (i + j)); printk("%s: iq %x: 0x%08x [ arg #%d ]\n", dev->name, i+j, risc, j); } @@ -509,7 +516,7 @@ void cx23885_sram_channel_dump(struct cx23885_dev *dev, printk("%s: fifo: 0x%08x -> 0x%x\n", dev->name, ch->fifo_start, ch->fifo_start+ch->fifo_size); printk("%s: ctrl: 0x%08x -> 0x%x\n", - dev->name, ch->ctrl_start, ch->ctrl_start+6*16); + dev->name, ch->ctrl_start, ch->ctrl_start + 6*16); printk("%s: ptr1_reg: 0x%08x\n", dev->name, cx_read(ch->ptr1_reg)); printk("%s: ptr2_reg: 0x%08x\n", @@ -520,10 +527,11 @@ void cx23885_sram_channel_dump(struct cx23885_dev *dev, dev->name, cx_read(ch->cnt2_reg)); } -void cx23885_risc_disasm(struct cx23885_tsport *port, struct btcx_riscmem *risc) +void cx23885_risc_disasm(struct cx23885_tsport *port, + struct btcx_riscmem *risc) { struct cx23885_dev *dev = port->dev; - unsigned int i,j,n; + unsigned int i, j, n; printk("%s: risc disasm: %p [dma=0x%08lx]\n", dev->name, risc->cpu, (unsigned long)risc->dma); @@ -532,7 +540,7 @@ void cx23885_risc_disasm(struct cx23885_tsport *port, struct btcx_riscmem *risc) n = cx23885_risc_decode(risc->cpu[i]); for (j = 1; j < n; j++) printk("%s: %04d: 0x%08x [ arg #%d ]\n", - dev->name, i+j, risc->cpu[i+j], j); + dev->name, i + j, risc->cpu[i + j], j); if (risc->cpu[i] == RISC_JUMP) break; } @@ -625,8 +633,8 @@ static int cx23885_pci_quirks(struct cx23885_dev *dev) static int get_resources(struct cx23885_dev *dev) { if (request_mem_region(pci_resource_start(dev->pci,0), - pci_resource_len(dev->pci,0), - dev->name)) + pci_resource_len(dev->pci,0), + dev->name)) return 0; printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx\n", @@ -637,7 +645,7 @@ static int get_resources(struct cx23885_dev *dev) static void cx23885_timeout(unsigned long data); int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, - u32 reg, u32 mask, u32 value); + u32 reg, u32 mask, u32 value); static int cx23885_ir_init(struct cx23885_dev *dev) { @@ -726,15 +734,16 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) dev->ts2.gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ dev->ts2.ts_clk_en_val = 0x1; /* Enable TS_CLK */ - cx23885_risc_stopper(dev->pci, &dev->ts2.mpegq.stopper, dev->ts2.reg_dma_ctl, dev->ts2.dma_ctl_val, 0x00); + cx23885_risc_stopper(dev->pci, &dev->ts2.mpegq.stopper, + dev->ts2.reg_dma_ctl, dev->ts2.dma_ctl_val, 0x00); - sprintf(dev->name,"cx23885[%d]", dev->nr); + sprintf(dev->name, "cx23885[%d]", dev->nr); if (get_resources(dev) < 0) { printk(KERN_ERR "CORE %s No more PCIe resources for " - "subsystem: %04x:%04x\n", - dev->name, dev->pci->subsystem_vendor, - dev->pci->subsystem_device); + "subsystem: %04x:%04x\n", + dev->name, dev->pci->subsystem_vendor, + dev->pci->subsystem_device); cx23885_devcount--; goto fail_free; @@ -746,7 +755,7 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) /* PCIe stuff */ dev->lmmio = ioremap(pci_resource_start(dev->pci,0), - pci_resource_len(dev->pci,0)); + pci_resource_len(dev->pci,0)); dev->bmmio = (u8 __iomem *)dev->lmmio; @@ -765,10 +774,10 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) cx23885_card_list(dev); } printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", - dev->name, dev->pci->subsystem_vendor, - dev->pci->subsystem_device, cx23885_boards[dev->board].name, - dev->board, card[dev->nr] == dev->board ? - "insmod option" : "autodetected"); + dev->name, dev->pci->subsystem_vendor, + dev->pci->subsystem_device, cx23885_boards[dev->board].name, + dev->board, card[dev->nr] == dev->board ? + "insmod option" : "autodetected"); /* Configure the internal memory */ if(dev->pci->device == 0x8880) { @@ -779,7 +788,8 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) dev->bridge = CX23885_BRIDGE_885; dev->sram_channels = cx23885_sram_channels; } - dprintk(1, "%s() Memory configured for PCIe bridge type %d\n", __FUNCTION__, dev->bridge); + dprintk(1, "%s() Memory configured for PCIe bridge type %d\n", + __FUNCTION__, dev->bridge); /* init hardware */ cx23885_reset(dev); @@ -793,7 +803,8 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) cx23885_ir_init(dev); if (cx23885_dvb_register(&dev->ts2) < 0) { - printk(KERN_ERR "%s() Failed to register dvb adapters\n", __FUNCTION__); + printk(KERN_ERR "%s() Failed to register dvb adapters\n", + __FUNCTION__); } return 0; @@ -820,12 +831,12 @@ void cx23885_dev_unregister(struct cx23885_dev *dev) } static u32* cx23885_risc_field(u32 *rp, struct scatterlist *sglist, - unsigned int offset, u32 sync_line, - unsigned int bpl, unsigned int padding, - unsigned int lines) + unsigned int offset, u32 sync_line, + unsigned int bpl, unsigned int padding, + unsigned int lines) { struct scatterlist *sg; - unsigned int line,todo; + unsigned int line, todo; /* sync instruction */ if (sync_line != NO_SYNC_LINE) @@ -874,11 +885,11 @@ static u32* cx23885_risc_field(u32 *rp, struct scatterlist *sglist, } int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, - struct scatterlist *sglist, - unsigned int top_offset, unsigned int bottom_offset, - unsigned int bpl, unsigned int padding, unsigned int lines) + struct scatterlist *sglist, unsigned int top_offset, + unsigned int bottom_offset, unsigned int bpl, + unsigned int padding, unsigned int lines) { - u32 instructions,fields; + u32 instructions, fields; u32 *rp; int rc; @@ -903,10 +914,10 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, rp = risc->cpu; if (UNSET != top_offset) rp = cx23885_risc_field(rp, sglist, top_offset, 0, - bpl, padding, lines); + bpl, padding, lines); if (UNSET != bottom_offset) rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x200, - bpl, padding, lines); + bpl, padding, lines); /* save pointer to jmp instruction address */ risc->jmp = rp; @@ -915,8 +926,8 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, } int cx23885_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc, - struct scatterlist *sglist, unsigned int bpl, - unsigned int lines) + struct scatterlist *sglist, unsigned int bpl, + unsigned int lines) { u32 instructions; u32 *rp; @@ -945,7 +956,7 @@ int cx23885_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc, } int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, - u32 reg, u32 mask, u32 value) + u32 reg, u32 mask, u32 value) { u32 *rp; int rc; @@ -969,7 +980,7 @@ int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf) { BUG_ON(in_interrupt()); - videobuf_waiton(&buf->vb,0,0); + videobuf_waiton(&buf->vb, 0, 0); videobuf_dma_unmap(q, &buf->vb.dma); videobuf_dma_free(&buf->vb.dma); btcx_riscmem_free((struct pci_dev *)q->dev, &buf->risc); @@ -977,18 +988,18 @@ void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf) } static int cx23885_start_dma(struct cx23885_tsport *port, - struct cx23885_dmaqueue *q, - struct cx23885_buffer *buf) + struct cx23885_dmaqueue *q, + struct cx23885_buffer *buf) { struct cx23885_dev *dev = port->dev; dprintk(1, "%s() w: %d, h: %d, f: %d\n", __FUNCTION__, - buf->vb.width, buf->vb.height, buf->vb.field); + buf->vb.width, buf->vb.height, buf->vb.field); /* setup fifo + format */ cx23885_sram_channel_setup(dev, - &dev->sram_channels[ port->sram_chno ], - port->ts_packet_size, buf->risc.dma); + &dev->sram_channels[ port->sram_chno ], + port->ts_packet_size, buf->risc.dma); if(debug > 5) { cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ] ); cx23885_risc_disasm(port, &buf->risc); @@ -998,8 +1009,8 @@ static int cx23885_start_dma(struct cx23885_tsport *port, cx_write(port->reg_lngth, buf->vb.width); if (!(cx23885_boards[dev->board].portc & CX23885_MPEG_DVB)) { - printk( "%s() Failed. Unsupported value in .portc (0x%08x)\n", __FUNCTION__, - cx23885_boards[dev->board].portc ); + printk( "%s() Failed. Unsupported value in .portc (0x%08x)\n", + __FUNCTION__, cx23885_boards[dev->board].portc ); return -EINVAL; } @@ -1017,7 +1028,8 @@ static int cx23885_start_dma(struct cx23885_tsport *port, case CX23885_BOARD_HAUPPAUGE_HVR1800lp: case CX23885_BOARD_HAUPPAUGE_HVR1800: cx_write(port->reg_vld_misc, 0x00); - dprintk(1, "%s() Configuring HVR1800/lp/1500 board\n", __FUNCTION__); + dprintk(1, "%s() Configuring HVR1800/lp/1500 board\n", + __FUNCTION__); break; default: // FIXME @@ -1103,53 +1115,54 @@ static int cx23885_restart_queue(struct cx23885_tsport *port, dprintk(5, "%s()\n", __FUNCTION__); if (list_empty(&q->active)) { - struct cx23885_buffer *prev; - prev = NULL; + struct cx23885_buffer *prev; + prev = NULL; dprintk(5, "%s() queue is empty\n", __FUNCTION__); - for (;;) { - if (list_empty(&q->queued)) - return 0; - buf = list_entry(q->queued.next, struct cx23885_buffer, vb.queue); - if (NULL == prev) { - list_del(&buf->vb.queue); - list_add_tail(&buf->vb.queue,&q->active); - cx23885_start_dma(port, q, buf); - buf->vb.state = STATE_ACTIVE; - buf->count = q->count++; - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); - dprintk(5,"[%p/%d] restart_queue - first active\n", - buf,buf->vb.i); - - } else if (prev->vb.width == buf->vb.width && - prev->vb.height == buf->vb.height && - prev->fmt == buf->fmt) { - list_del(&buf->vb.queue); - list_add_tail(&buf->vb.queue,&q->active); - buf->vb.state = STATE_ACTIVE; - buf->count = q->count++; - prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */ - dprintk(5,"[%p/%d] restart_queue - move to active\n", - buf,buf->vb.i); - } else { - return 0; - } - prev = buf; - } + for (;;) { + if (list_empty(&q->queued)) + return 0; + buf = list_entry(q->queued.next, struct cx23885_buffer, + vb.queue); + if (NULL == prev) { + list_del(&buf->vb.queue); + list_add_tail(&buf->vb.queue, &q->active); + cx23885_start_dma(port, q, buf); + buf->vb.state = STATE_ACTIVE; + buf->count = q->count++; + mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + dprintk(5, "[%p/%d] restart_queue - first active\n", + buf, buf->vb.i); + + } else if (prev->vb.width == buf->vb.width && + prev->vb.height == buf->vb.height && + prev->fmt == buf->fmt) { + list_del(&buf->vb.queue); + list_add_tail(&buf->vb.queue, &q->active); + buf->vb.state = STATE_ACTIVE; + buf->count = q->count++; + prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); + prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */ + dprintk(5,"[%p/%d] restart_queue - move to active\n", + buf, buf->vb.i); + } else { + return 0; + } + prev = buf; + } return 0; } buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue); - dprintk(2,"restart_queue [%p/%d]: restart dma\n", + dprintk(2, "restart_queue [%p/%d]: restart dma\n", buf, buf->vb.i); cx23885_start_dma(port, q, buf); - list_for_each(item,&q->active) { + list_for_each(item, &q->active) { buf = list_entry(item, struct cx23885_buffer, vb.queue); buf->count = q->count++; } - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); return 0; } @@ -1172,7 +1185,7 @@ int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port, buf->vb.size = size; buf->vb.field = field /*V4L2_FIELD_TOP*/; - if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL))) + if (0 != (rc = videobuf_iolock(q, &buf->vb, NULL))) goto fail; cx23885_risc_databuffer(dev->pci, &buf->risc, buf->vb.dma.sglist, @@ -1182,7 +1195,7 @@ int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port, return 0; fail: - cx23885_free_buffer(q,buf); + cx23885_free_buffer(q, buf); return rc; } @@ -1199,51 +1212,53 @@ void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf) if (list_empty(&cx88q->active)) { dprintk( 1, "queue is empty - first active\n" ); - list_add_tail(&buf->vb.queue,&cx88q->active); + list_add_tail(&buf->vb.queue, &cx88q->active); cx23885_start_dma(port, cx88q, buf); buf->vb.state = STATE_ACTIVE; buf->count = cx88q->count++; - mod_timer(&cx88q->timeout, jiffies+BUFFER_TIMEOUT); - dprintk(1,"[%p/%d] %s - first active\n", + mod_timer(&cx88q->timeout, jiffies + BUFFER_TIMEOUT); + dprintk(1, "[%p/%d] %s - first active\n", buf, buf->vb.i, __FUNCTION__); } else { dprintk( 1, "queue is not empty - append to active\n" ); - prev = list_entry(cx88q->active.prev, struct cx23885_buffer, vb.queue); - list_add_tail(&buf->vb.queue,&cx88q->active); + prev = list_entry(cx88q->active.prev, struct cx23885_buffer, + vb.queue); + list_add_tail(&buf->vb.queue, &cx88q->active); buf->vb.state = STATE_ACTIVE; buf->count = cx88q->count++; prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */ dprintk( 1, "[%p/%d] %s - append to active\n", - buf, buf->vb.i, __FUNCTION__); + buf, buf->vb.i, __FUNCTION__); } } /* ----------------------------------------------------------- */ -static void do_cancel_buffers(struct cx23885_tsport *port, char *reason, int restart) +static void do_cancel_buffers(struct cx23885_tsport *port, char *reason, + int restart) { struct cx23885_dev *dev = port->dev; struct cx23885_dmaqueue *q = &port->mpegq; struct cx23885_buffer *buf; unsigned long flags; - spin_lock_irqsave(&port->slock,flags); + spin_lock_irqsave(&port->slock, flags); while (!list_empty(&q->active)) { - buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue); + buf = list_entry(q->active.next, struct cx23885_buffer, + vb.queue); list_del(&buf->vb.queue); buf->vb.state = STATE_ERROR; wake_up(&buf->vb.done); - dprintk(1,"[%p/%d] %s - dma=0x%08lx\n", + dprintk(1, "[%p/%d] %s - dma=0x%08lx\n", buf, buf->vb.i, reason, (unsigned long)buf->risc.dma); } - if (restart) - { + if (restart) { dprintk(1, "restarting queue\n" ); cx23885_restart_queue(port, q); } - spin_unlock_irqrestore(&port->slock,flags); + spin_unlock_irqrestore(&port->slock, flags); } void cx23885_cancel_buffers(struct cx23885_tsport *port) @@ -1251,7 +1266,7 @@ void cx23885_cancel_buffers(struct cx23885_tsport *port) struct cx23885_dev *dev = port->dev; struct cx23885_dmaqueue *q = &port->mpegq; - dprintk(1, "%s()\n", __FUNCTION__ ); + dprintk(1, "%s()\n", __FUNCTION__); del_timer_sync(&q->timeout); cx23885_stop_dma(port); do_cancel_buffers(port, "cancel", 0); @@ -1312,15 +1327,15 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) dprintk(7, "ts2_status: 0x%08x ts2_mask: 0x%08x count: 0x%x\n", ts2_status, ts2_mask, count ); if ( (pci_status & PCI_MSK_RISC_RD) || - (pci_status & PCI_MSK_RISC_WR) || - (pci_status & PCI_MSK_AL_RD) || - (pci_status & PCI_MSK_AL_WR) || - (pci_status & PCI_MSK_APB_DMA) || - (pci_status & PCI_MSK_VID_C) || - (pci_status & PCI_MSK_VID_B) || - (pci_status & PCI_MSK_VID_A) || - (pci_status & PCI_MSK_AUD_INT) || - (pci_status & PCI_MSK_AUD_EXT) ) + (pci_status & PCI_MSK_RISC_WR) || + (pci_status & PCI_MSK_AL_RD) || + (pci_status & PCI_MSK_AL_WR) || + (pci_status & PCI_MSK_APB_DMA) || + (pci_status & PCI_MSK_VID_C) || + (pci_status & PCI_MSK_VID_B) || + (pci_status & PCI_MSK_VID_A) || + (pci_status & PCI_MSK_AUD_INT) || + (pci_status & PCI_MSK_AUD_EXT) ) { if (pci_status & PCI_MSK_RISC_RD) @@ -1347,9 +1362,9 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) } if ( (ts2_status & VID_C_MSK_OPC_ERR) || - (ts2_status & VID_C_MSK_BAD_PKT) || - (ts2_status & VID_C_MSK_SYNC) || - (ts2_status & VID_C_MSK_OF)) + (ts2_status & VID_C_MSK_BAD_PKT) || + (ts2_status & VID_C_MSK_SYNC) || + (ts2_status & VID_C_MSK_OF)) { if (ts2_status & VID_C_MSK_OPC_ERR) dprintk(7, " (VID_C_MSK_OPC_ERR 0x%08x)\n", VID_C_MSK_OPC_ERR); @@ -1392,12 +1407,12 @@ out: } static int __devinit cx23885_initdev(struct pci_dev *pci_dev, - const struct pci_device_id *pci_id) + const struct pci_device_id *pci_id) { struct cx23885_dev *dev; int err; - dev = kzalloc(sizeof(*dev),GFP_KERNEL); + dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (NULL == dev) return -ENOMEM; @@ -1428,8 +1443,8 @@ static int __devinit cx23885_initdev(struct pci_dev *pci_dev, goto fail_irq; } - err = request_irq(pci_dev->irq, cx23885_irq - , IRQF_SHARED | IRQF_DISABLED, dev->name, dev); + err = request_irq(pci_dev->irq, cx23885_irq, + IRQF_SHARED | IRQF_DISABLED, dev->name, dev); if (err < 0) { printk(KERN_ERR "%s: can't get IRQ %d\n", dev->name, pci_dev->irq); diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index 79948553901..bd0afc2a044 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -53,11 +53,11 @@ static int dvb_buf_setup(struct videobuf_queue *q, return 0; } -static int dvb_buf_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, - enum v4l2_field field) +static int dvb_buf_prepare(struct videobuf_queue *q, + struct videobuf_buffer *vb, enum v4l2_field field) { struct cx23885_tsport *port = q->priv_data; - return cx23885_buf_prepare(q, port, (struct cx23885_buffer*)vb,field); + return cx23885_buf_prepare(q, port, (struct cx23885_buffer*)vb, field); } static void dvb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) @@ -66,7 +66,8 @@ static void dvb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) cx23885_buf_queue(port, (struct cx23885_buffer*)vb); } -static void dvb_buf_release(struct videobuf_queue *q, struct videobuf_buffer *vb) +static void dvb_buf_release(struct videobuf_queue *q, + struct videobuf_buffer *vb) { cx23885_free_buffer(q, (struct cx23885_buffer*)vb); } @@ -116,26 +117,22 @@ static int dvb_register(struct cx23885_tsport *port) switch (dev->board) { case CX23885_BOARD_HAUPPAUGE_HVR1800lp: port->dvb.frontend = dvb_attach(s5h1409_attach, - &hauppauge_hvr1800lp_config, - &dev->i2c_bus[0].i2c_adap); + &hauppauge_hvr1800lp_config, + &dev->i2c_bus[0].i2c_adap); if (port->dvb.frontend != NULL) { - dvb_attach(mt2131_attach, - port->dvb.frontend, - &dev->i2c_bus[0].i2c_adap, - &hauppauge_hvr1800lp_rev2_tunerconfig, - 0); + dvb_attach(mt2131_attach, port->dvb.frontend, + &dev->i2c_bus[0].i2c_adap, + &hauppauge_hvr1800lp_rev2_tunerconfig, 0); } break; case CX23885_BOARD_HAUPPAUGE_HVR1800: port->dvb.frontend = dvb_attach(s5h1409_attach, - &hauppauge_hvr1800_config, - &dev->i2c_bus[0].i2c_adap); + &hauppauge_hvr1800_config, + &dev->i2c_bus[0].i2c_adap); if (port->dvb.frontend != NULL) { - dvb_attach(mt2131_attach, - port->dvb.frontend, - &dev->i2c_bus[0].i2c_adap, - &hauppauge_hvr1800_tunerconfig, - 0); + dvb_attach(mt2131_attach, port->dvb.frontend, + &dev->i2c_bus[0].i2c_adap, + &hauppauge_hvr1800_tunerconfig, 0); } break; default: @@ -152,7 +149,8 @@ static int dvb_register(struct cx23885_tsport *port) cx23885_call_i2c_clients (&dev->i2c_bus[0], TUNER_SET_STANDBY, NULL); /* register everything */ - return videobuf_dvb_register(&port->dvb, THIS_MODULE, port, &dev->pci->dev); + return videobuf_dvb_register(&port->dvb, THIS_MODULE, port, + &dev->pci->dev); } int cx23885_dvb_register(struct cx23885_tsport *port) @@ -160,8 +158,8 @@ int cx23885_dvb_register(struct cx23885_tsport *port) struct cx23885_dev *dev = port->dev; int err; - dprintk( 1, "%s\n", __FUNCTION__); - dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n", + dprintk(1, "%s\n", __FUNCTION__); + dprintk(1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n", dev->board, dev->name, dev->pci_bus, @@ -173,15 +171,9 @@ int cx23885_dvb_register(struct cx23885_tsport *port) /* dvb stuff */ printk("%s: cx23885 based dvb card\n", dev->name); - videobuf_queue_init( - &port->dvb.dvbq, - &dvb_qops, - dev->pci, - &port->slock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_TOP, - sizeof(struct cx23885_buffer), - port); + videobuf_queue_init(&port->dvb.dvbq, &dvb_qops, dev->pci, &port->slock, + V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_TOP, + sizeof(struct cx23885_buffer), port); err = dvb_register(port); if (err != 0) printk("%s() dvb_register failed err = %d\n", __FUNCTION__, err); @@ -198,3 +190,10 @@ int cx23885_dvb_unregister(struct cx23885_tsport *port) return 0; } + +/* + * Local variables: + * c-basic-offset: 8 + * End: + * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off +*/ diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c index dbd048d08dd..155ab928cd6 100644 --- a/drivers/media/video/cx23885/cx23885-i2c.c +++ b/drivers/media/video/cx23885/cx23885-i2c.c @@ -31,11 +31,11 @@ static unsigned int i2c_debug = 2; module_param(i2c_debug, int, 0644); -MODULE_PARM_DESC(i2c_debug,"enable debug messages [i2c]"); +MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); static unsigned int i2c_scan = 0; module_param(i2c_scan, int, 0444); -MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time"); +MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time"); #define dprintk(level,fmt, arg...) if (i2c_debug >= level) \ printk(KERN_DEBUG "%s: " fmt, dev->name , ## arg) @@ -76,7 +76,8 @@ static int i2c_wait_done(struct i2c_adapter *i2c_adap) return 1; } -static int i2c_sendbytes(struct i2c_adapter *i2c_adap, const struct i2c_msg *msg, int last) +static int i2c_sendbytes(struct i2c_adapter *i2c_adap, + const struct i2c_msg *msg, int last) { struct cx23885_i2c *bus = i2c_adap->algo_data; struct cx23885_dev *dev = bus->dev; @@ -150,11 +151,12 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap, const struct i2c_msg *msg eio: retval = -EIO; err: - printk(" ERR: %d\n",retval); + printk(" ERR: %d\n", retval); return retval; } -static int i2c_readbytes(struct i2c_adapter *i2c_adap, const struct i2c_msg *msg, int last) +static int i2c_readbytes(struct i2c_adapter *i2c_adap, + const struct i2c_msg *msg, int last) { struct cx23885_i2c *bus = i2c_adap->algo_data; struct cx23885_dev *dev = bus->dev; @@ -206,11 +208,12 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap, const struct i2c_msg *msg eio: retval = -EIO; err: - printk(" ERR: %d\n",retval); + printk(" ERR: %d\n", retval); return retval; } -static int i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) +static int i2c_xfer(struct i2c_adapter *i2c_adap, + struct i2c_msg *msgs, int num) { struct cx23885_i2c *bus = i2c_adap->algo_data; struct cx23885_dev *dev = bus->dev; @@ -219,8 +222,8 @@ static int i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) dprintk(1, "%s(num = %d)\n", __FUNCTION__, num); for (i = 0 ; i < num; i++) { - dprintk(1, "%s(num = %d) addr = 0x%02x len = 0x%x\n" - , __FUNCTION__, num, msgs[i].addr, msgs[i].len); + dprintk(1, "%s(num = %d) addr = 0x%02x len = 0x%x\n", + __FUNCTION__, num, msgs[i].addr, msgs[i].len); if (msgs[i].flags & I2C_M_RD) { /* read */ retval = i2c_readbytes(i2c_adap, &msgs[i], i+1 == num); @@ -261,7 +264,8 @@ static int detach_inform(struct i2c_client *client) return 0; } -void cx23885_call_i2c_clients(struct cx23885_i2c *bus, unsigned int cmd, void *arg) +void cx23885_call_i2c_clients(struct cx23885_i2c *bus, + unsigned int cmd, void *arg) { // struct cx23885_dev *dev = bus->dev; @@ -316,11 +320,11 @@ static char *i2c_devs[128] = { static void do_i2c_scan(char *name, struct i2c_client *c) { unsigned char buf; - int i,rc; + int i, rc; for (i = 0; i < 128; i++) { c->addr = i; - rc = i2c_master_recv(c,&buf,0); + rc = i2c_master_recv(c, &buf, 0); if (rc < 0) continue; printk("%s: i2c scan: found device @ 0x%x [%s]\n", @@ -335,13 +339,17 @@ int cx23885_i2c_register(struct cx23885_i2c *bus) dprintk(1, "%s(bus = %d)\n", __FUNCTION__, bus->nr); - memcpy(&bus->i2c_adap, &cx23885_i2c_adap_template, sizeof(bus->i2c_adap)); - memcpy(&bus->i2c_algo, &cx23885_i2c_algo_template, sizeof(bus->i2c_algo)); - memcpy(&bus->i2c_client, &cx23885_i2c_client_template, sizeof(bus->i2c_client)); + memcpy(&bus->i2c_adap, &cx23885_i2c_adap_template, + sizeof(bus->i2c_adap)); + memcpy(&bus->i2c_algo, &cx23885_i2c_algo_template, + sizeof(bus->i2c_algo)); + memcpy(&bus->i2c_client, &cx23885_i2c_client_template, + sizeof(bus->i2c_client)); bus->i2c_adap.dev.parent = &dev->pci->dev; - strlcpy(bus->i2c_adap.name, bus->dev->name, sizeof(bus->i2c_adap.name)); + strlcpy(bus->i2c_adap.name, bus->dev->name, + sizeof(bus->i2c_adap.name)); bus->i2c_algo.data = bus; bus->i2c_adap.algo_data = bus; i2c_add_adapter(&bus->i2c_adap); diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index b60de21c238..4312c3fcc1e 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -183,7 +183,7 @@ struct cx23885_dev { //u32 shadow[SHADOW_MAX]; int pci_irqmask; - /* I2C adapters: Master 1 and 2 (External) and Master 3 (Internal only) */ + /* I2C adapters: Master 1 & 2 (External) & Master 3 (Internal only) */ struct cx23885_i2c i2c_bus[3]; int nr; @@ -268,17 +268,22 @@ extern void cx23885_card_setup_pre_i2c(struct cx23885_dev *dev); extern int cx23885_dvb_register(struct cx23885_tsport *port); extern int cx23885_dvb_unregister(struct cx23885_tsport *port); -extern int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port, - struct cx23885_buffer *buf, enum v4l2_field field); +extern int cx23885_buf_prepare(struct videobuf_queue *q, + struct cx23885_tsport *port, + struct cx23885_buffer *buf, + enum v4l2_field field); -extern void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf); -extern void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf); +extern void cx23885_buf_queue(struct cx23885_tsport *port, + struct cx23885_buffer *buf); +extern void cx23885_free_buffer(struct videobuf_queue *q, + struct cx23885_buffer *buf); /* ----------------------------------------------------------- */ /* cx23885-i2c.c */ extern int cx23885_i2c_register(struct cx23885_i2c *bus); extern int cx23885_i2c_unregister(struct cx23885_i2c *bus); -extern void cx23885_call_i2c_clients(struct cx23885_i2c *bus, unsigned int cmd, void *arg); +extern void cx23885_call_i2c_clients(struct cx23885_i2c *bus, unsigned int cmd, + void *arg); /* * Local variables: -- cgit v1.2.3-70-g09d2 From 60a41d3b61a714d98a36cddbe182cc6ff0794274 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 20 Mar 2007 23:03:52 -0300 Subject: V4L/DVB (6163): cx23885: remove old comments Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 4 ---- drivers/media/video/cx23885/cx23885-i2c.c | 4 +--- drivers/media/video/cx23885/cx23885-reg.h | 11 ++--------- drivers/media/video/cx23885/cx23885.h | 3 --- 4 files changed, 3 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 6f0a8dbc6b3..3e1b62a2d50 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -1043,10 +1043,6 @@ static int cx23885_start_dma(struct cx23885_tsport *port, cx_write(port->reg_gpcnt_ctl, 3); q->count = 1; - /* A bug in the current 887 implementation, causes an NMI assert during - * starting or stopping interrupts or dma. Avoid the bug for the time being, - * enabling the developer to work on the demod/tuner locking work. - */ switch(dev->bridge) { case CX23885_BRIDGE_885: case CX23885_BRIDGE_887: diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c index 155ab928cd6..c40c37f2d13 100644 --- a/drivers/media/video/cx23885/cx23885-i2c.c +++ b/drivers/media/video/cx23885/cx23885-i2c.c @@ -267,12 +267,10 @@ static int detach_inform(struct i2c_client *client) void cx23885_call_i2c_clients(struct cx23885_i2c *bus, unsigned int cmd, void *arg) { -// struct cx23885_dev *dev = bus->dev; - if (bus->i2c_rc != 0) return; - i2c_clients_command(&bus->i2c_adap, cmd, arg); + i2c_clients_command(&bus->i2c_adap, cmd, arg); } static int cx23885_algo_control(struct i2c_adapter *adap, diff --git a/drivers/media/video/cx23885/cx23885-reg.h b/drivers/media/video/cx23885/cx23885-reg.h index 5cb692f20d2..771b22ac215 100644 --- a/drivers/media/video/cx23885/cx23885-reg.h +++ b/drivers/media/video/cx23885/cx23885-reg.h @@ -71,21 +71,14 @@ Channel manager Data Structure entry = 20 DWORD #define RISC_WRITECM 0xC0000000 #define RISC_WRITECR 0xD0000000 -//#define RISC_SYNC_ODD 0x80000000 -//#define RISC_SYNC_EVEN 0x80000200 -//#define RISC_RESYNC_ODD 0x80008000 -//#define RISC_RESYNC_EVEN 0x80008200 -// Do we need these? +/* Do we need these? */ #define RISC_WRITEC 0x50000000 #define RISC_READC 0xA0000000 -// Is this used? +/* Is this used? */ #define RISC_IMM 0x00000001 -//#define RISC_CNT_NONE 0x00000000 -//#define RISC_CNT_RSVR 0x00020000 -//#define RISC_JMP_SRP 0x01 /* Audio and Video Core */ #define HOST_REG1 0x00000000 diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 4312c3fcc1e..929235440e2 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -47,8 +47,6 @@ /* Max number of inputs by card */ #define MAX_CX23885_INPUT 8 -//#define SHADOW_MAX 3 - #define BUFFER_TIMEOUT (HZ) /* 0.5 seconds */ #define CX23885_BOARD_NOAUTO UNSET @@ -180,7 +178,6 @@ struct cx23885_dev { int pci_bus, pci_slot; u32 __iomem *lmmio; u8 __iomem *bmmio; - //u32 shadow[SHADOW_MAX]; int pci_irqmask; /* I2C adapters: Master 1 & 2 (External) & Master 3 (Internal only) */ -- cgit v1.2.3-70-g09d2 From 3c5666aee31decafdca14f6f83d33ec27b27f982 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 20 Mar 2007 23:18:04 -0300 Subject: V4L/DVB (6164): cx23885: turn off i2c_debug by default Turn off i2c_debug by default, to make the driver less verbose. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c index c40c37f2d13..6b49b414aeb 100644 --- a/drivers/media/video/cx23885/cx23885-i2c.c +++ b/drivers/media/video/cx23885/cx23885-i2c.c @@ -29,7 +29,7 @@ #include -static unsigned int i2c_debug = 2; +static unsigned int i2c_debug = 0; module_param(i2c_debug, int, 0644); MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); -- cgit v1.2.3-70-g09d2 From b86b580244511f9b2fb2043d813e9c4c7d294a62 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Thu, 22 Mar 2007 01:01:53 -0300 Subject: V4L/DVB (6165): cx23885: fix Kconfig dependencies Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/Kconfig | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig index ea53466dacb..333dd29d44b 100644 --- a/drivers/media/video/cx23885/Kconfig +++ b/drivers/media/video/cx23885/Kconfig @@ -8,6 +8,9 @@ config VIDEO_CX23885 select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEO_IR + select VIDEO_BUF_DVB + select DVB_TUNER_MT2131 if !DVB_FE_CUSTOMISE + select DVB_S5H1409 if !DVB_FE_CUSTOMISE ---help--- This is a video4linux driver for Conexant 23885 based TV cards. -- cgit v1.2.3-70-g09d2 From 426d523664e01c778f6455e9b3bbd40dda76c66a Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Tue, 14 Aug 2007 23:35:16 -0300 Subject: V4L/DVB (6166): cx23885: Ensure pci_quirks is called after board identification The pci_quirks function was being called too early during initialisation, it needs to be called after the board has been identified. Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 3e1b62a2d50..69167294708 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -759,8 +759,6 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) dev->bmmio = (u8 __iomem *)dev->lmmio; - cx23885_pci_quirks(dev); - /* board config */ dev->board = UNSET; if (card[dev->nr] < cx23885_bcount) @@ -779,6 +777,8 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) dev->board, card[dev->nr] == dev->board ? "insmod option" : "autodetected"); + cx23885_pci_quirks(dev); + /* Configure the internal memory */ if(dev->pci->device == 0x8880) { dev->bridge = CX23885_BRIDGE_887; -- cgit v1.2.3-70-g09d2 From 4823e9ee9f45c78777d040742b5e46336a42c8b3 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Wed, 22 Aug 2007 20:52:21 -0300 Subject: V4L/DVB (6167): cx23885: Changed PCI quirks to after bridge detech Changed the pci_quirks function to detech the bridge type before setting the NMI clear bit, rather than detecting based on unique board id. Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 69167294708..d2bc3e58662 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -622,11 +622,9 @@ static int cx23885_pci_quirks(struct cx23885_dev *dev) { dprintk(1, "%s()\n", __FUNCTION__); - switch(dev->board) { - case CX23885_BOARD_HAUPPAUGE_HVR1800lp: + if(dev->bridge == CX23885_BRIDGE_885) cx_clear(RDR_TLCTL0, 1 << 4); - break; - } + return 0; } @@ -777,8 +775,6 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) dev->board, card[dev->nr] == dev->board ? "insmod option" : "autodetected"); - cx23885_pci_quirks(dev); - /* Configure the internal memory */ if(dev->pci->device == 0x8880) { dev->bridge = CX23885_BRIDGE_887; @@ -791,6 +787,8 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) dprintk(1, "%s() Memory configured for PCIe bridge type %d\n", __FUNCTION__, dev->bridge); + cx23885_pci_quirks(dev); + /* init hardware */ cx23885_reset(dev); -- cgit v1.2.3-70-g09d2 From a77743bc2d29197d48a6f4ae9f8f9e0f0b0ba5d7 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Wed, 22 Aug 2007 21:01:20 -0300 Subject: V4L/DVB (6168): cx23885: Added HVR1250 ATSC support Adding support for the Hauppauge HVR1250 PCIe ATSC board. Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-cards.c | 26 ++++++++++++++++++++++++++ drivers/media/video/cx23885/cx23885-core.c | 7 +++++++ drivers/media/video/cx23885/cx23885-dvb.c | 24 ++++++++++++++++++++++++ drivers/media/video/cx23885/cx23885.h | 1 + 4 files changed, 58 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index 8bb3fe4a876..e6d34fb5b94 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -88,6 +88,27 @@ struct cx23885_board cx23885_boards[] = { .gpio0 = 0xff02, }}, }, + [CX23885_BOARD_HAUPPAUGE_HVR1250] = { + .name = "Hauppauge WinTV-HVR1250", + .portc = CX23885_MPEG_DVB, + .input = {{ + .type = CX23885_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0xff00, + },{ + .type = CX23885_VMUX_DEBUG, + .vmux = 0, + .gpio0 = 0xff01, + },{ + .type = CX23885_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0xff02, + },{ + .type = CX23885_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0xff02, + }}, + }, }; const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); @@ -111,6 +132,10 @@ struct cx23885_subid cx23885_subids[] = { .subvendor = 0x0070, .subdevice = 0x7801, .card = CX23885_BOARD_HAUPPAUGE_HVR1800, + },{ + .subvendor = 0x0070, + .subdevice = 0x7911, + .card = CX23885_BOARD_HAUPPAUGE_HVR1250, }, }; const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); @@ -176,6 +201,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) } switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1250: case CX23885_BOARD_HAUPPAUGE_HVR1800: case CX23885_BOARD_HAUPPAUGE_HVR1800lp: if (dev->i2c_bus[0].i2c_rc == 0) diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index d2bc3e58662..1148d684188 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -603,6 +603,11 @@ void cx23885_reset(struct cx23885_dev *dev) cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH09 ], 128, 0); switch(dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1250: + /* GPIO-0 cx24227 demodulator reset */ + dprintk( 1, "%s() Configuring HVR1250 GPIO's\n", __FUNCTION__); + cx_set(GP0_IO, 0x00010001); /* Bring the part out of reset */ + break; case CX23885_BOARD_HAUPPAUGE_HVR1800: /* GPIO-0 656_CLK */ /* GPIO-1 656_D0 */ @@ -650,6 +655,7 @@ static int cx23885_ir_init(struct cx23885_dev *dev) dprintk(1, "%s()\n", __FUNCTION__); switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1250: case CX23885_BOARD_HAUPPAUGE_HVR1800: dprintk(1, "%s() FIXME - Implement IR support\n", __FUNCTION__); break; @@ -1023,6 +1029,7 @@ static int cx23885_start_dma(struct cx23885_tsport *port, cx_write(GPIO2, 0x00); switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1250: case CX23885_BOARD_HAUPPAUGE_HVR1800lp: case CX23885_BOARD_HAUPPAUGE_HVR1800: cx_write(port->reg_vld_misc, 0x00); diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index bd0afc2a044..63a1dde0d17 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -97,6 +97,16 @@ static struct s5h1409_config hauppauge_hvr1800_config = { .status_mode = S5H1409_DEMODLOCKING }; +static struct s5h1409_config hauppauge_hvr1250_config = { + .demod_address = 0x32 >> 1, + .output_mode = S5H1409_SERIAL_OUTPUT, + .gpio = S5H1409_GPIO_ON, + .if_freq = 44000, + .inversion = S5H1409_INVERSION_OFF, + .status_mode = S5H1409_DEMODLOCKING +}; + + static struct mt2131_config hauppauge_hvr1800lp_rev2_tunerconfig = { 0x61 @@ -106,6 +116,10 @@ static struct mt2131_config hauppauge_hvr1800_tunerconfig = { 0x61 }; +static struct mt2131_config hauppauge_hvr1250_tunerconfig = { + 0x61 +}; + static int dvb_register(struct cx23885_tsport *port) { struct cx23885_dev *dev = port->dev; @@ -115,6 +129,16 @@ static int dvb_register(struct cx23885_tsport *port) /* init frontend */ switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1250: + port->dvb.frontend = dvb_attach(s5h1409_attach, + &hauppauge_hvr1250_config, + &dev->i2c_bus[0].i2c_adap); + if (port->dvb.frontend != NULL) { + dvb_attach(mt2131_attach, port->dvb.frontend, + &dev->i2c_bus[0].i2c_adap, + &hauppauge_hvr1250_tunerconfig, 0); + } + break; case CX23885_BOARD_HAUPPAUGE_HVR1800lp: port->dvb.frontend = dvb_attach(s5h1409_attach, &hauppauge_hvr1800lp_config, diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 929235440e2..300a97980ac 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -53,6 +53,7 @@ #define CX23885_BOARD_UNKNOWN 0 #define CX23885_BOARD_HAUPPAUGE_HVR1800lp 1 #define CX23885_BOARD_HAUPPAUGE_HVR1800 2 +#define CX23885_BOARD_HAUPPAUGE_HVR1250 3 enum cx23885_itype { CX23885_VMUX_COMPOSITE1 = 1, -- cgit v1.2.3-70-g09d2 From f29379c3619d85e0bdc0ee30c8199f7f66866fcf Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Tue, 4 Sep 2007 21:15:46 -0300 Subject: V4L/DVB (6169): Removed unused function mt2131_set_gpo() Unused code is removed. Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/mt2131.c | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/mt2131.c b/drivers/media/dvb/frontends/mt2131.c index 6bcc4ccc991..4b93931de4e 100644 --- a/drivers/media/dvb/frontends/mt2131.c +++ b/drivers/media/dvb/frontends/mt2131.c @@ -91,17 +91,6 @@ static int mt2131_writeregs(struct mt2131_priv *priv,u8 *buf, u8 len) return 0; } -static int mt2131_set_gpo(struct dvb_frontend *fe, u8 val) -{ - struct mt2131_priv *priv = fe->tuner_priv; - u8 v; - - mt2131_readreg(priv, 0x07, &v); - mt2131_writereg(priv, 0x07, (v & 0xfe) | (val & 0x01)); - - return 0; -} - static int mt2131_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) { -- cgit v1.2.3-70-g09d2 From 2e52f215be1b3a0337788c8d3345bdf5e3894e19 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Tue, 4 Sep 2007 21:32:41 -0300 Subject: V4L/DVB (6170): cx23885: General cleanup of old code Removed unused code. Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-cards.c | 1 - drivers/media/video/cx23885/cx23885-core.c | 40 ++--------------------------- drivers/media/video/cx23885/cx23885-dvb.c | 4 +-- drivers/media/video/cx23885/cx23885-i2c.c | 3 +-- drivers/media/video/cx23885/cx23885-reg.h | 9 ------- drivers/media/video/cx23885/cx23885.h | 1 - 6 files changed, 4 insertions(+), 54 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index e6d34fb5b94..09d4376c2e0 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -172,7 +172,6 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) tveeprom_hauppauge_analog(&dev->i2c_bus[0].i2c_client, &tv, eeprom_data); - /* Make sure we support the board model */ switch (tv.model) { diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 1148d684188..7a1c4672041 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -368,11 +368,13 @@ void cx23885_wakeup(struct cx23885_tsport *port, break; buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue); + /* count comes from the hw and is is 16bit wide -- * this trick handles wrap-arounds correctly for * up to 32767 buffers in flight... */ if ((s16) (count - buf->count) < 0) break; + do_gettimeofday(&buf->vb.ts); dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i, count, buf->count); @@ -910,7 +912,6 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, /* write and jump need and extra dword */ instructions = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + lines); instructions += 2; - //if ((rc = btcx_riscmem_alloc(pci,risc,instructions*8)) < 0) if ((rc = btcx_riscmem_alloc(pci,risc,instructions*12)) < 0) return rc; @@ -945,7 +946,6 @@ int cx23885_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc, instructions = 1 + (bpl * lines) / PAGE_SIZE + lines; instructions += 1; - //if ((rc = btcx_riscmem_alloc(pci,risc,instructions*8)) < 0) if ((rc = btcx_riscmem_alloc(pci,risc,instructions*12)) < 0) return rc; @@ -970,7 +970,6 @@ int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, /* write risc instructions */ rp = risc->cpu; - //*(rp++) = cpu_to_le32(RISC_WRITECR | RISC_IRQ2 | RISC_IMM); *(rp++) = cpu_to_le32(RISC_WRITECR | RISC_IRQ2); *(rp++) = cpu_to_le32(reg); *(rp++) = cpu_to_le32(value); @@ -1018,16 +1017,11 @@ static int cx23885_start_dma(struct cx23885_tsport *port, return -EINVAL; } - // FIXME: review the need for these two lines - dprintk( 1, "%s() doing .dvb\n", __FUNCTION__); udelay(100); cx_write(port->reg_hw_sop_ctrl, 0x47 << 16 | 188 << 4); cx_write(port->reg_ts_clk_en, port->ts_clk_en_val); - // FIXME: review the need for this - cx_write(GPIO2, 0x00); - switch (dev->board) { case CX23885_BOARD_HAUPPAUGE_HVR1250: case CX23885_BOARD_HAUPPAUGE_HVR1800lp: @@ -1037,7 +1031,6 @@ static int cx23885_start_dma(struct cx23885_tsport *port, __FUNCTION__); break; default: - // FIXME printk(KERN_ERR "%s() error, default case", __FUNCTION__ ); } @@ -1058,39 +1051,11 @@ static int cx23885_start_dma(struct cx23885_tsport *port, cx_set(PCI_INT_MSK, dev->pci_irqmask | port->pci_irqmask); break; default: - // FIXME: generate a sensible switch-default message printk(KERN_ERR "%s() error, default case", __FUNCTION__ ); } - dprintk(1, "%s() Register Dump\n", __FUNCTION__); - dprintk(1, "%s() set port ts_int_msk, now %x\n", __FUNCTION__, cx_read(port->reg_ts_int_msk) ); - dprintk(1, "%s() DEV_CNTRL2 0x%08x\n", __FUNCTION__, cx_read(DEV_CNTRL2) ); - dprintk(1, "%s() PCI_INT_MSK 0x%08x\n", __FUNCTION__, cx_read(PCI_INT_MSK) ); - dprintk(1, "%s() VID_A_INT_MSK 0x%08x\n", __FUNCTION__, cx_read(VID_A_INT_MSK) ); - dprintk(1, "%s() VID_B_INT_MSK 0x%08x\n", __FUNCTION__, cx_read(VID_B_INT_MSK) ); - dprintk(1, "%s() VID_C_INT_MSK 0x%08x\n", __FUNCTION__, cx_read(VID_C_INT_MSK) ); - dprintk(1, "%s() VID_A_DMA_CTL 0x%08x\n", __FUNCTION__, cx_read(VID_A_DMA_CTL) ); - dprintk(1, "%s() VID_B_DMA_CTL 0x%08x\n", __FUNCTION__, cx_read(VID_B_DMA_CTL) ); - dprintk(1, "%s() VID_C_DMA_CTL 0x%08x\n", __FUNCTION__, cx_read(VID_C_DMA_CTL) ); - dprintk(1, "%s() AUD_INT_INT_MSK 0x%08x\n", __FUNCTION__, cx_read(AUDIO_INT_INT_MSK) ); - dprintk(1, "%s() AUD_INT_DMA_CTL 0x%08x\n", __FUNCTION__, cx_read(AUD_INT_DMA_CTL) ); - dprintk(1, "%s() AUD_EXT_INT_MSK 0x%08x\n", __FUNCTION__, cx_read(AUDIO_EXT_INT_MSK) ); - dprintk(1, "%s() AUD_EXT_DMA_CTL 0x%08x\n", __FUNCTION__, cx_read(AUD_EXT_DMA_CTL) ); - cx_set(DEV_CNTRL2, (1<<5)); /* Enable RISC controller */ - dprintk(1, "%s() set dev_cntrl2, now %x\n", __FUNCTION__, cx_read(DEV_CNTRL2) ); - dprintk(1, "%s() VID_C_DMA_CTL , now %x\n", __FUNCTION__, cx_read(port->reg_dma_ctl) ); - dprintk(1, "%s() VID_C_DMA_CTL , now %x\n", __FUNCTION__, cx_read(VID_C_DMA_CTL) ); - dprintk(1, "%s() PAD_CTRL %x\n", __FUNCTION__, cx_read(PAD_CTRL) ); - dprintk(1, "%s() GPIO2 %x\n", __FUNCTION__, cx_read(GPIO2) ); - dprintk(1, "%s() VID_C_LN_LNGTH , now %x\n", __FUNCTION__, cx_read(port->reg_lngth) ); - dprintk(1, "%s() VID_C_HW_SOP_CTL, now %x\n", __FUNCTION__, cx_read(port->reg_hw_sop_ctrl) ); - dprintk(1, "%s() VID_C_GEN_CTL , now %x\n", __FUNCTION__, cx_read(port->reg_gen_ctrl) ); - dprintk(1, "%s() VID_C_SOP_STATUS, now %x\n", __FUNCTION__, cx_read(VID_C_SOP_STATUS) ); - dprintk(1, "%s() VID_C_TS_CLK_EN , now %x\n", __FUNCTION__, cx_read(VID_C_TS_CLK_EN) ); - dprintk(1, "%s() VID_C_FIFO_OVLST, now %x\n", __FUNCTION__, cx_read(VID_C_FIFO_OVFL_STAT) ); - dprintk(1, "%s() VID_C_INT_MSTAT , now 0x%08x\n", __FUNCTION__, cx_read(VID_C_INT_MSTAT) ); return 0; } @@ -1220,7 +1185,6 @@ void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf) mod_timer(&cx88q->timeout, jiffies + BUFFER_TIMEOUT); dprintk(1, "[%p/%d] %s - first active\n", buf, buf->vb.i, __FUNCTION__); - } else { dprintk( 1, "queue is not empty - append to active\n" ); prev = list_entry(cx88q->active.prev, struct cx23885_buffer, diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index 63a1dde0d17..58ae15a99e9 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -33,7 +33,7 @@ #include "s5h1409.h" #include "mt2131.h" -static unsigned int debug = 2; +static unsigned int debug = 0; #define dprintk(level,fmt, arg...) if (debug >= level) \ printk(KERN_DEBUG "%s: " fmt, dev->name, ## arg) @@ -106,8 +106,6 @@ static struct s5h1409_config hauppauge_hvr1250_config = { .status_mode = S5H1409_DEMODLOCKING }; - - static struct mt2131_config hauppauge_hvr1800lp_rev2_tunerconfig = { 0x61 }; diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c index 6b49b414aeb..5572fbbbb5a 100644 --- a/drivers/media/video/cx23885/cx23885-i2c.c +++ b/drivers/media/video/cx23885/cx23885-i2c.c @@ -130,7 +130,6 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap, if (cnt < msg->len-1 || !last) ctrl |= I2C_NOSTOP | I2C_EXTEND; - //printk("addr = 0x%08x wdata = 0x%08x ctrl = 0x%08x\n", addr, wdata, ctrl); cx_write(bus->reg_addr, addr); cx_write(bus->reg_wdata, wdata); cx_write(bus->reg_ctrl, ctrl); @@ -297,7 +296,6 @@ static struct i2c_adapter cx23885_i2c_adap_template = { .owner = THIS_MODULE, .id = I2C_HW_B_CX23885, .algo = &cx23885_i2c_algo_template, -// .class = I2C_CLASS_TV_ANALOG, .client_register = attach_inform, .client_unregister = detach_inform, }; @@ -348,6 +346,7 @@ int cx23885_i2c_register(struct cx23885_i2c *bus) strlcpy(bus->i2c_adap.name, bus->dev->name, sizeof(bus->i2c_adap.name)); + bus->i2c_algo.data = bus; bus->i2c_adap.algo_data = bus; i2c_add_adapter(&bus->i2c_adap); diff --git a/drivers/media/video/cx23885/cx23885-reg.h b/drivers/media/video/cx23885/cx23885-reg.h index 771b22ac215..6527bd3b4d7 100644 --- a/drivers/media/video/cx23885/cx23885-reg.h +++ b/drivers/media/video/cx23885/cx23885-reg.h @@ -22,7 +22,6 @@ #ifndef _CX23885_REG_H_ #define _CX23885_REG_H_ - /* Address Map 0x00000000 -> 0x00009000 TX SRAM (Fifos) @@ -50,8 +49,6 @@ Channel manager Data Structure entry = 20 DWORD 5 InstructionQueueSize ... Reserved 19 Reserved - - */ /* Risc Instructions */ @@ -70,15 +67,9 @@ Channel manager Data Structure entry = 20 DWORD #define RISC_WRITERM 0xB0000000 #define RISC_WRITECM 0xC0000000 #define RISC_WRITECR 0xD0000000 - - -/* Do we need these? */ #define RISC_WRITEC 0x50000000 #define RISC_READC 0xA0000000 -/* Is this used? */ -#define RISC_IMM 0x00000001 - /* Audio and Video Core */ #define HOST_REG1 0x00000000 diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 300a97980ac..c0f4e433735 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -245,7 +245,6 @@ struct sram_channel { #define cx_set(reg,bit) cx_andor((reg),(bit),(bit)) #define cx_clear(reg,bit) cx_andor((reg),(bit),0) - extern int cx23885_sram_channel_setup(struct cx23885_dev *dev, struct sram_channel *ch, unsigned int bpl, u32 risc); -- cgit v1.2.3-70-g09d2 From 31bae4a62036a1d85aa9ee5864115dad2727336d Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Tue, 4 Sep 2007 21:36:32 -0300 Subject: V4L/DVB (6171): cx23885: Cleaning up defines Moving some defines into the correct header file. Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 19 ------------------- drivers/media/video/cx23885/cx23885-reg.h | 11 ++++++++++- 2 files changed, 10 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 7a1c4672041..fa5f6488b99 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -1251,25 +1251,6 @@ static void cx23885_timeout(unsigned long data) do_cancel_buffers(port, "timeout", 1); } -#define PCI_MSK_APB_DMA (1 << 12) -#define PCI_MSK_AL_WR (1 << 11) -#define PCI_MSK_AL_RD (1 << 10) -#define PCI_MSK_RISC_WR (1 << 9) -#define PCI_MSK_RISC_RD (1 << 8) - -#define PCI_MSK_AUD_EXT (1 << 4) -#define PCI_MSK_AUD_INT (1 << 3) -#define PCI_MSK_VID_C (1 << 2) -#define PCI_MSK_VID_B (1 << 1) -#define PCI_MSK_VID_A 1 - -#define VID_C_MSK_BAD_PKT (1 << 20) -#define VID_C_MSK_OPC_ERR (1 << 16) -#define VID_C_MSK_SYNC (1 << 12) -#define VID_C_MSK_OF (1 << 8) -#define VID_C_MSK_RISCI2 (1 << 4) -#define VID_C_MSK_RISCI1 1 - static irqreturn_t cx23885_irq(int irq, void *dev_id) { struct cx23885_dev *dev = dev_id; diff --git a/drivers/media/video/cx23885/cx23885-reg.h b/drivers/media/video/cx23885/cx23885-reg.h index 6527bd3b4d7..63ab0fb26ac 100644 --- a/drivers/media/video/cx23885/cx23885-reg.h +++ b/drivers/media/video/cx23885/cx23885-reg.h @@ -211,7 +211,7 @@ Channel manager Data Structure entry = 20 DWORD #define I2S_TX_CFG 0x0000001A #define DEV_CNTRL2 0x00040000 -#define PCI_INT_MSK 0x00040010 + #define PCI_MSK_APB_DMA (1 << 12) #define PCI_MSK_AL_WR (1 << 11) #define PCI_MSK_AL_RD (1 << 10) @@ -222,6 +222,8 @@ Channel manager Data Structure entry = 20 DWORD #define PCI_MSK_VID_C (1 << 2) #define PCI_MSK_VID_B (1 << 1) #define PCI_MSK_VID_A 1 +#define PCI_INT_MSK 0x00040010 + #define PCI_INT_STAT 0x00040014 #define PCI_INT_MSTAT 0x00040018 @@ -235,7 +237,14 @@ Channel manager Data Structure entry = 20 DWORD #define VID_B_INT_MSTAT 0x00040038 #define VID_B_INT_SSTAT 0x0004003C +#define VID_C_MSK_BAD_PKT (1 << 20) +#define VID_C_MSK_OPC_ERR (1 << 16) +#define VID_C_MSK_SYNC (1 << 12) +#define VID_C_MSK_OF (1 << 8) +#define VID_C_MSK_RISCI2 (1 << 4) +#define VID_C_MSK_RISCI1 1 #define VID_C_INT_MSK 0x00040040 + #define VID_C_MSK_BAD_PKT (1 << 20) #define VID_C_MSK_OPC_ERR (1 << 16) #define VID_C_MSK_SYNC (1 << 12) -- cgit v1.2.3-70-g09d2 From 86184e06da4b71fc24ae9505ec60ce95c098d0de Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Tue, 4 Sep 2007 21:40:47 -0300 Subject: V4L/DVB (6172): cx23885: Removing duplicate tuner and demod definitions A number of Hauppauge boards share the same tuner and demod configurations. This patch removes duplicate structures. Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-dvb.c | 54 +++---------------------------- 1 file changed, 5 insertions(+), 49 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index 58ae15a99e9..291cc055622 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -79,7 +79,7 @@ static struct videobuf_queue_ops dvb_qops = { .buf_release = dvb_buf_release, }; -static struct s5h1409_config hauppauge_hvr1800lp_config = { +static struct s5h1409_config hauppauge_generic_config = { .demod_address = 0x32 >> 1, .output_mode = S5H1409_SERIAL_OUTPUT, .gpio = S5H1409_GPIO_OFF, @@ -88,33 +88,7 @@ static struct s5h1409_config hauppauge_hvr1800lp_config = { .status_mode = S5H1409_DEMODLOCKING }; -static struct s5h1409_config hauppauge_hvr1800_config = { - .demod_address = 0x32 >> 1, - .output_mode = S5H1409_SERIAL_OUTPUT, - .gpio = S5H1409_GPIO_ON, - .if_freq = 44000, - .inversion = S5H1409_INVERSION_OFF, - .status_mode = S5H1409_DEMODLOCKING -}; - -static struct s5h1409_config hauppauge_hvr1250_config = { - .demod_address = 0x32 >> 1, - .output_mode = S5H1409_SERIAL_OUTPUT, - .gpio = S5H1409_GPIO_ON, - .if_freq = 44000, - .inversion = S5H1409_INVERSION_OFF, - .status_mode = S5H1409_DEMODLOCKING -}; - -static struct mt2131_config hauppauge_hvr1800lp_rev2_tunerconfig = { - 0x61 -}; - -static struct mt2131_config hauppauge_hvr1800_tunerconfig = { - 0x61 -}; - -static struct mt2131_config hauppauge_hvr1250_tunerconfig = { +static struct mt2131_config hauppauge_generic_tunerconfig = { 0x61 }; @@ -128,33 +102,15 @@ static int dvb_register(struct cx23885_tsport *port) /* init frontend */ switch (dev->board) { case CX23885_BOARD_HAUPPAUGE_HVR1250: - port->dvb.frontend = dvb_attach(s5h1409_attach, - &hauppauge_hvr1250_config, - &dev->i2c_bus[0].i2c_adap); - if (port->dvb.frontend != NULL) { - dvb_attach(mt2131_attach, port->dvb.frontend, - &dev->i2c_bus[0].i2c_adap, - &hauppauge_hvr1250_tunerconfig, 0); - } - break; - case CX23885_BOARD_HAUPPAUGE_HVR1800lp: - port->dvb.frontend = dvb_attach(s5h1409_attach, - &hauppauge_hvr1800lp_config, - &dev->i2c_bus[0].i2c_adap); - if (port->dvb.frontend != NULL) { - dvb_attach(mt2131_attach, port->dvb.frontend, - &dev->i2c_bus[0].i2c_adap, - &hauppauge_hvr1800lp_rev2_tunerconfig, 0); - } - break; case CX23885_BOARD_HAUPPAUGE_HVR1800: + case CX23885_BOARD_HAUPPAUGE_HVR1800lp: port->dvb.frontend = dvb_attach(s5h1409_attach, - &hauppauge_hvr1800_config, + &hauppauge_generic_config, &dev->i2c_bus[0].i2c_adap); if (port->dvb.frontend != NULL) { dvb_attach(mt2131_attach, port->dvb.frontend, &dev->i2c_bus[0].i2c_adap, - &hauppauge_hvr1800_tunerconfig, 0); + &hauppauge_generic_tunerconfig, 0); } break; default: -- cgit v1.2.3-70-g09d2 From 2df9a4c2d81ed255c9e027ee5df676a65f4ab578 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Tue, 4 Sep 2007 21:50:49 -0300 Subject: V4L/DVB (6173): cx23885: Minor cleanup and important NMI comment placed in code I wanted to document the NMI assert issue inside the code, even though it's already documented in the patch history. If/when the next cx23887 revision appears, is may need to be enabled on that also. Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index fa5f6488b99..13dc7c8642c 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -331,8 +331,8 @@ static int cx23885_risc_decode(u32 risc) [ RISC_WRITECR >> 28 ] = "writecr", }; static int incr[16] = { - [ RISC_WRITE >> 28 ] = 3, // 2 - [ RISC_JUMP >> 28 ] = 3, // 2 + [ RISC_WRITE >> 28 ] = 3, + [ RISC_JUMP >> 28 ] = 3, [ RISC_SKIP >> 28 ] = 1, [ RISC_SYNC >> 28 ] = 1, [ RISC_WRITERM >> 28 ] = 3, @@ -629,6 +629,10 @@ static int cx23885_pci_quirks(struct cx23885_dev *dev) { dprintk(1, "%s()\n", __FUNCTION__); + /* The cx23885 bridge has a weird bug which causes NMI to be asserted + * when DMA begins if RDR_TLCTL0 bit4 is not cleared. It does not + * occur on the cx23887 bridge. + */ if(dev->bridge == CX23885_BRIDGE_885) cx_clear(RDR_TLCTL0, 1 << 4); -- cgit v1.2.3-70-g09d2 From d54d6980916d5521ad47fa61e5b6ff8733221714 Mon Sep 17 00:00:00 2001 From: Chaogui Zhang Date: Fri, 24 Aug 2007 01:02:32 -0300 Subject: V4L/DVB (6178): add IR remote support for FusionHDTV 5 RT Gold This patch adds support for the built-in IR receiver of the DViCO Fusion HDTV5 RT GOLD PCI card, using FusionHDTV MCE remote controller. Signed-off-by: Chaogui Zhang Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/ir-keymaps.c | 69 +++++++++++++++++++++++++++++++++++++++ drivers/media/video/ir-kbd-i2c.c | 36 +++++++++++++++++++- include/media/ir-common.h | 1 + 3 files changed, 105 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c index 137f68bee39..1879c304ae6 100644 --- a/drivers/media/common/ir-keymaps.c +++ b/drivers/media/common/ir-keymaps.c @@ -1782,3 +1782,72 @@ IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE] = { }; EXPORT_SYMBOL_GPL(ir_codes_tt_1500); + +/* DViCO FUSION HDTV 5 RT GOLD remote */ +IR_KEYTAB_TYPE ir_codes_fusion_gold[IR_KEYTAB_SIZE] = { + + [ 0x0b ] = KEY_1, + [ 0x17 ] = KEY_2, + [ 0x1b ] = KEY_3, + [ 0x07 ] = KEY_4, + [ 0x50 ] = KEY_5, + [ 0x54 ] = KEY_6, + [ 0x48 ] = KEY_7, + [ 0x4c ] = KEY_8, + [ 0x58 ] = KEY_9, + [ 0x03 ] = KEY_0, + + [ 0x5e ] = KEY_OK, + [ 0x51 ] = KEY_UP, + [ 0x53 ] = KEY_DOWN, + [ 0x5b ] = KEY_LEFT, + [ 0x5f ] = KEY_RIGHT, + + [ 0x02 ] = KEY_TV, /* Labeled DTV on remote */ + [ 0x0e ] = KEY_MP3, + [ 0x1a ] = KEY_DVD, + [ 0x1e ] = KEY_RESERVED, /* Labeled CPF on remote */ + [ 0x16 ] = KEY_SETUP, + [ 0x46 ] = KEY_POWER2, /* TV On/Off button on remote */ + [ 0x0a ] = KEY_EPG, /* Labeled Guide on remote */ + + [ 0x49 ] = KEY_BACK, + [ 0x59 ] = KEY_INFO, /* Labeled MORE on remote */ + [ 0x4d ] = KEY_MENU, /* Labeled DVDMENU on remote */ + [ 0x55 ] = KEY_CYCLEWINDOWS, /* Labeled ALT-TAB on remote */ + [ 0x0f ] = KEY_REDO, /* Labeled |<< REPLAY on remote */ + [ 0x12 ] = KEY_END, /* Labeled >>| SKIP on remote */ + [ 0x42 ] = KEY_GREEN, /* Labeled START with a green + * MS windows logo on remote */ + + [ 0x15 ] = KEY_VOLUMEUP, + [ 0x05 ] = KEY_VOLUMEDOWN, + [ 0x11 ] = KEY_CHANNELUP, + [ 0x09 ] = KEY_CHANNELDOWN, + + /* The following are not defined in kernel 2.6 and + * I cannot find suitable substitute key definitions. + + [ 0x52 ] = KEY_PHOTO, + [ 0x5a ] = KEY_LIVE, + [ 0x19 ] = KEY_FOLDER, + + */ + + [ 0x52 ] = KEY_RESERVED, + [ 0x5a ] = KEY_RESERVED, + [ 0x19 ] = KEY_RESERVED, + + [ 0x13 ] = KEY_MODE, /* 4:3 16:9 select */ + [ 0x1f ] = KEY_ZOOM, + + [ 0x43 ] = KEY_REWIND, + [ 0x47 ] = KEY_PLAYPAUSE, + [ 0x4f ] = KEY_FORWARD, + [ 0x57 ] = KEY_MUTE, + [ 0x0d ] = KEY_STOP, + [ 0x01 ] = KEY_RECORD, + [ 0x4e ] = KEY_POWER, +}; + +EXPORT_SYMBOL_GPL(ir_codes_fusion_gold); diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index b3939a0bada..3d5a28c2c92 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c @@ -10,6 +10,8 @@ * Ulrich Mueller * modified for em2820 based USB TV tuners by * Markus Rechberger + * modified for DViCO Fusion HDTV 5 RT GOLD by + * Chaogui Zhang * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -141,6 +143,32 @@ static int get_key_pv951(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) return 1; } +static int get_key_fusion_gold(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) +{ + unsigned char buf[4]; + + /* poll IR chip */ + if (4 != i2c_master_recv(&ir->c,buf,4)) { + dprintk(1,"read error\n"); + return -EIO; + } + + if(buf[0] !=0 || buf[1] !=0 || buf[2] !=0 || buf[3] != 0) + dprintk(2, "ir fusion gold: 0x%2x 0x%2x 0x%2x 0x%2x\n", + buf[0], buf[1], buf[2], buf[3]); + + /* no key pressed or signal from other ir remote */ + if(buf[0] != 0x1 || buf[1] != 0xfe) + return 0; + + *ir_key = buf[2]; + *ir_raw = (buf[2] << 8) | buf[3]; + + return 1; + +} + + static int get_key_knc1(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) { unsigned char b; @@ -363,6 +391,12 @@ static int ir_attach(struct i2c_adapter *adap, int addr, ir_type = IR_TYPE_OTHER; ir_codes = ir_codes_empty; break; + case 0x6b: + name = "FusionGold"; + ir->get_key = get_key_fusion_gold; + ir_type = IR_TYPE_RC5; + ir_codes = ir_codes_fusion_gold; + break; case 0x7a: case 0x47: case 0x71: @@ -474,7 +508,7 @@ static int ir_probe(struct i2c_adapter *adap) static const int probe_bttv[] = { 0x1a, 0x18, 0x4b, 0x64, 0x30, -1}; static const int probe_saa7134[] = { 0x7a, 0x47, 0x71, -1 }; static const int probe_em28XX[] = { 0x30, 0x47, -1 }; - static const int probe_cx88[] = { 0x18, 0x71, -1 }; + static const int probe_cx88[] = { 0x18, 0x6b, 0x71, -1 }; const int *probe = NULL; struct i2c_client c; unsigned char buf; diff --git a/include/media/ir-common.h b/include/media/ir-common.h index 9807a7c1583..dfae84038e2 100644 --- a/include/media/ir-common.h +++ b/include/media/ir-common.h @@ -140,6 +140,7 @@ extern IR_KEYTAB_TYPE ir_codes_budget_ci_old[IR_KEYTAB_SIZE]; extern IR_KEYTAB_TYPE ir_codes_asus_pc39[IR_KEYTAB_SIZE]; extern IR_KEYTAB_TYPE ir_codes_encore_enltv[IR_KEYTAB_SIZE]; extern IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE]; +extern IR_KEYTAB_TYPE ir_codes_fusion_gold[IR_KEYTAB_SIZE]; #endif -- cgit v1.2.3-70-g09d2 From 3c44358c49ee4142d0f868509b5b3b02759fa16a Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 24 Aug 2007 01:07:12 -0300 Subject: V4L/DVB (6179): Clean up FusionHDTV ir code - fixed missing buttons in keymap. - make function names & descriptions more generic, since this same ir receiver and remote is used in many FusionHDTV products. - miscellaneous cleanups. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/ir-keymaps.c | 32 ++++++++++++-------------------- drivers/media/video/ir-kbd-i2c.c | 12 +++++------- include/media/ir-common.h | 2 +- 3 files changed, 18 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c index 1879c304ae6..aefcf28da1c 100644 --- a/drivers/media/common/ir-keymaps.c +++ b/drivers/media/common/ir-keymaps.c @@ -1783,8 +1783,8 @@ IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE] = { EXPORT_SYMBOL_GPL(ir_codes_tt_1500); -/* DViCO FUSION HDTV 5 RT GOLD remote */ -IR_KEYTAB_TYPE ir_codes_fusion_gold[IR_KEYTAB_SIZE] = { +/* DViCO FUSION HDTV MCE remote */ +IR_KEYTAB_TYPE ir_codes_fusionhdtv_mce[IR_KEYTAB_SIZE] = { [ 0x0b ] = KEY_1, [ 0x17 ] = KEY_2, @@ -1806,7 +1806,7 @@ IR_KEYTAB_TYPE ir_codes_fusion_gold[IR_KEYTAB_SIZE] = { [ 0x02 ] = KEY_TV, /* Labeled DTV on remote */ [ 0x0e ] = KEY_MP3, [ 0x1a ] = KEY_DVD, - [ 0x1e ] = KEY_RESERVED, /* Labeled CPF on remote */ + [ 0x1e ] = KEY_FAVORITES, /* Labeled CPF on remote */ [ 0x16 ] = KEY_SETUP, [ 0x46 ] = KEY_POWER2, /* TV On/Off button on remote */ [ 0x0a ] = KEY_EPG, /* Labeled Guide on remote */ @@ -1815,9 +1815,10 @@ IR_KEYTAB_TYPE ir_codes_fusion_gold[IR_KEYTAB_SIZE] = { [ 0x59 ] = KEY_INFO, /* Labeled MORE on remote */ [ 0x4d ] = KEY_MENU, /* Labeled DVDMENU on remote */ [ 0x55 ] = KEY_CYCLEWINDOWS, /* Labeled ALT-TAB on remote */ - [ 0x0f ] = KEY_REDO, /* Labeled |<< REPLAY on remote */ - [ 0x12 ] = KEY_END, /* Labeled >>| SKIP on remote */ - [ 0x42 ] = KEY_GREEN, /* Labeled START with a green + + [ 0x0f ] = KEY_PREVIOUSSONG, /* Labeled |<< REPLAY on remote */ + [ 0x12 ] = KEY_NEXTSONG, /* Labeled >>| SKIP on remote */ + [ 0x42 ] = KEY_ENTER, /* Labeled START with a green * MS windows logo on remote */ [ 0x15 ] = KEY_VOLUMEUP, @@ -1825,29 +1826,20 @@ IR_KEYTAB_TYPE ir_codes_fusion_gold[IR_KEYTAB_SIZE] = { [ 0x11 ] = KEY_CHANNELUP, [ 0x09 ] = KEY_CHANNELDOWN, - /* The following are not defined in kernel 2.6 and - * I cannot find suitable substitute key definitions. - - [ 0x52 ] = KEY_PHOTO, - [ 0x5a ] = KEY_LIVE, - [ 0x19 ] = KEY_FOLDER, - - */ - - [ 0x52 ] = KEY_RESERVED, - [ 0x5a ] = KEY_RESERVED, - [ 0x19 ] = KEY_RESERVED, + [ 0x52 ] = KEY_CAMERA, + [ 0x5a ] = KEY_TUNER, + [ 0x19 ] = KEY_OPEN, [ 0x13 ] = KEY_MODE, /* 4:3 16:9 select */ [ 0x1f ] = KEY_ZOOM, [ 0x43 ] = KEY_REWIND, [ 0x47 ] = KEY_PLAYPAUSE, - [ 0x4f ] = KEY_FORWARD, + [ 0x4f ] = KEY_FASTFORWARD, [ 0x57 ] = KEY_MUTE, [ 0x0d ] = KEY_STOP, [ 0x01 ] = KEY_RECORD, [ 0x4e ] = KEY_POWER, }; -EXPORT_SYMBOL_GPL(ir_codes_fusion_gold); +EXPORT_SYMBOL_GPL(ir_codes_fusionhdtv_mce); diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index 3d5a28c2c92..04f6eb5ea29 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c @@ -143,7 +143,7 @@ static int get_key_pv951(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) return 1; } -static int get_key_fusion_gold(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) +static int get_key_fusionhdtv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) { unsigned char buf[4]; @@ -154,7 +154,7 @@ static int get_key_fusion_gold(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) } if(buf[0] !=0 || buf[1] !=0 || buf[2] !=0 || buf[3] != 0) - dprintk(2, "ir fusion gold: 0x%2x 0x%2x 0x%2x 0x%2x\n", + dprintk(2, "%s: 0x%2x 0x%2x 0x%2x 0x%2x\n", __FUNCTION__, buf[0], buf[1], buf[2], buf[3]); /* no key pressed or signal from other ir remote */ @@ -165,10 +165,8 @@ static int get_key_fusion_gold(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) *ir_raw = (buf[2] << 8) | buf[3]; return 1; - } - static int get_key_knc1(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) { unsigned char b; @@ -392,10 +390,10 @@ static int ir_attach(struct i2c_adapter *adap, int addr, ir_codes = ir_codes_empty; break; case 0x6b: - name = "FusionGold"; - ir->get_key = get_key_fusion_gold; + name = "FusionHDTV"; + ir->get_key = get_key_fusionhdtv; ir_type = IR_TYPE_RC5; - ir_codes = ir_codes_fusion_gold; + ir_codes = ir_codes_fusionhdtv_mce; break; case 0x7a: case 0x47: diff --git a/include/media/ir-common.h b/include/media/ir-common.h index dfae84038e2..7a785fa7721 100644 --- a/include/media/ir-common.h +++ b/include/media/ir-common.h @@ -140,7 +140,7 @@ extern IR_KEYTAB_TYPE ir_codes_budget_ci_old[IR_KEYTAB_SIZE]; extern IR_KEYTAB_TYPE ir_codes_asus_pc39[IR_KEYTAB_SIZE]; extern IR_KEYTAB_TYPE ir_codes_encore_enltv[IR_KEYTAB_SIZE]; extern IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE]; -extern IR_KEYTAB_TYPE ir_codes_fusion_gold[IR_KEYTAB_SIZE]; +extern IR_KEYTAB_TYPE ir_codes_fusionhdtv_mce[IR_KEYTAB_SIZE]; #endif -- cgit v1.2.3-70-g09d2 From a1dec5160d6e536b409761c1914500f4a7cf08c2 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 24 Aug 2007 01:13:07 -0300 Subject: V4L/DVB (6180): tuner: don't probe 0x6b or 0x6f on cx88 boards Ignore 0x6b and 0x6f on cx88 boards. Some FusionHDTV cards have an ir receiver at 0x6b and an RTC at 0x6f which can get corrupted if probed. Signed-off-by: Michael Krufky Acked-by: Jean Delvare Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-core.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 2f74379f4e4..2d4a3e38f27 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -661,6 +661,27 @@ static int tuner_probe(struct i2c_adapter *adap) normal_i2c[1] = I2C_CLIENT_END; } + /* HACK: Ignore 0x6b and 0x6f on cx88 boards. + * FusionHDTV5 RT Gold has an ir receiver at 0x6b + * and an RTC at 0x6f which can get corrupted if probed. + */ + if (adap->id == I2C_HW_B_CX2388x) { + unsigned int i = 0; + + while (i < I2C_CLIENT_MAX_OPTS && ignore[i] != I2C_CLIENT_END) + i += 2; + if (i + 4 < I2C_CLIENT_MAX_OPTS) { + ignore[i+0] = adap->nr; + ignore[i+1] = 0x6b; + ignore[i+2] = adap->nr; + ignore[i+3] = 0x6f; + ignore[i+4] = I2C_CLIENT_END; + } else + printk(KERN_WARNING "tuner: " + "too many options specified " + "in i2c probe ignore list!\n"); + } + default_mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV; if (adap->class & I2C_CLASS_TV_ANALOG) -- cgit v1.2.3-70-g09d2 From 6fcecce7e1a5223be450031fa446323b08d1ec41 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 24 Aug 2007 01:32:31 -0300 Subject: V4L/DVB (6181): cx88: auto-load rtc and ir receiver i2c modules for FusionHDTV5 RT Gold Auto-load ir-kbd-i2c for ir receiver support, and rtc-isl1208 for rtc support for the FusionHDTV5 RT Gold. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-video.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index a16fc157a67..f94a3b41782 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -1831,6 +1831,12 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, if (core->board.audio_chip == AUDIO_CHIP_WM8775) request_module("wm8775"); + switch (core->boardnr) { + case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD: + request_module("ir-kbd-i2c"); + request_module("rtc-isl1208"); + } + /* register v4l devices */ dev->video_dev = cx88_vdev_init(core,dev->pci, &cx8800_video_template,"video"); -- cgit v1.2.3-70-g09d2 From 82896f29d47d945e331873c7295da9e3a47d709d Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Thu, 6 Sep 2007 23:02:23 -0300 Subject: V4L/DVB (6184): cx88-alsa: Make volume control stereo Use the balance control to make the mono volume control stereo. Note that full range isn't supported. The balance control attenuates one channel by 0 to -63 dB, and the volume control provides additional attenuation to both channels by another 0 to -63 dB. So the channel with the most attenuation has a range of 0 to -126 dB, while the other channel only has a range of 0 to -63 dB. ALSA volume controls don't appear to support this concept. I just limited the range to 0 to -63 total. Once you get to -63 dB, you're already at silence, so additional attenuation is pretty much pointless anyway. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-alsa.c | 61 ++++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index 85d632224f3..25de25fb805 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -552,7 +552,7 @@ static int snd_cx88_capture_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *info) { info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - info->count = 1; + info->count = 2; info->value.integer.min = 0; info->value.integer.max = 0x3f; @@ -565,8 +565,12 @@ static int snd_cx88_capture_volume_get(struct snd_kcontrol *kcontrol, { snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); struct cx88_core *core=chip->core; + int vol = 0x3f - (cx_read(AUD_VOL_CTL) & 0x3f), + bal = cx_read(AUD_BAL_CTL); - value->value.integer.value[0] = 0x3f - (cx_read(AUD_VOL_CTL) & 0x3f); + value->value.integer.value[(bal & 0x40) ? 0 : 1] = vol; + vol -= (bal & 0x3f); + value->value.integer.value[(bal & 0x40) ? 1 : 0] = vol < 0 ? 0 : vol; return 0; } @@ -577,19 +581,31 @@ static int snd_cx88_capture_volume_put(struct snd_kcontrol *kcontrol, { snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); struct cx88_core *core=chip->core; - int v; - u32 old_control; - + int v, b; + int changed = 0; + u32 old; + + b = value->value.integer.value[1] - value->value.integer.value[0]; + if (b < 0) { + v = 0x3f - value->value.integer.value[0]; + b = (-b) | 0x40; + } else { + v = 0x3f - value->value.integer.value[1]; + } /* Do we really know this will always be called with IRQs on? */ spin_lock_irq(&chip->reg_lock); - - old_control = 0x3f - (cx_read(AUD_VOL_CTL) & 0x3f); - v = 0x3f - (value->value.integer.value[0] & 0x3f); - cx_andor(AUD_VOL_CTL, 0x3f, v); - + old = cx_read(AUD_VOL_CTL); + if (v != (old & 0x3f)) { + cx_write(AUD_VOL_CTL, (old & ~0x3f) | v); + changed = 1; + } + if (cx_read(AUD_BAL_CTL) != b) { + cx_write(AUD_BAL_CTL, b); + changed = 1; + } spin_unlock_irq(&chip->reg_lock); - return v != old_control; + return changed; } static struct snd_kcontrol_new snd_cx88_capture_volume = { @@ -746,17 +762,12 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci, return (err); err = snd_cx88_pcm(chip, 0, "CX88 Digital"); - - if (err < 0) { - snd_card_free(card); - return (err); - } + if (err < 0) + goto error; err = snd_ctl_add(card, snd_ctl_new1(&snd_cx88_capture_volume, chip)); - if (err < 0) { - snd_card_free(card); - return (err); - } + if (err < 0) + goto error; strcpy (card->driver, "CX88x"); sprintf(card->shortname, "Conexant CX%x", pci->device); @@ -768,14 +779,16 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci, card->driver,devno); err = snd_card_register(card); - if (err < 0) { - snd_card_free(card); - return (err); - } + if (err < 0) + goto error; pci_set_drvdata(pci,card); devno++; return 0; + +error: + snd_card_free(card); + return err; } /* * ALSA destructor -- cgit v1.2.3-70-g09d2 From 415927dcd118ee9e5f24c78976509b9a9c747545 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Thu, 6 Sep 2007 23:02:24 -0300 Subject: V4L/DVB (6186): cx88-alsa: Remove some unused fields in card state struct Not sure why they are there, but they don't do anything now. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-alsa.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index 25de25fb805..f4abed454fd 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -53,13 +53,9 @@ Data type declarations - Can be moded to a header file later ****************************************************************************/ -/* These can be replaced after done */ -#define MIXER_ADDR_LAST MAX_CX88_INPUT - struct cx88_audio_dev { struct cx88_core *core; struct cx88_dmaqueue q; - u64 starttime; /* pci i/o */ struct pci_dev *pci; @@ -78,9 +74,6 @@ struct cx88_audio_dev { struct videobuf_dmabuf dma_risc; - int mixer_volume[MIXER_ADDR_LAST+1][2]; - int capture_source[MIXER_ADDR_LAST+1][2]; - struct cx88_buffer *buf; struct snd_pcm_substream *substream; -- cgit v1.2.3-70-g09d2 From fc959befe0f0e4647bb4e326e3ae55875401888a Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Sat, 8 Sep 2007 19:08:17 -0300 Subject: V4L/DVB (6190): cx23885: GPIO fix for non HVR1800lp boards The HVR1250 and HVR1800 boards need the s5h1409 demod GPIO enabled. Signed-off-by: Steven Toth Reviewed-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-dvb.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index 291cc055622..ffa4c49d691 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -80,6 +80,15 @@ static struct videobuf_queue_ops dvb_qops = { }; static struct s5h1409_config hauppauge_generic_config = { + .demod_address = 0x32 >> 1, + .output_mode = S5H1409_SERIAL_OUTPUT, + .gpio = S5H1409_GPIO_ON, + .if_freq = 44000, + .inversion = S5H1409_INVERSION_OFF, + .status_mode = S5H1409_DEMODLOCKING +}; + +static struct s5h1409_config hauppauge_hvr1800lp_config = { .demod_address = 0x32 >> 1, .output_mode = S5H1409_SERIAL_OUTPUT, .gpio = S5H1409_GPIO_OFF, @@ -103,7 +112,6 @@ static int dvb_register(struct cx23885_tsport *port) switch (dev->board) { case CX23885_BOARD_HAUPPAUGE_HVR1250: case CX23885_BOARD_HAUPPAUGE_HVR1800: - case CX23885_BOARD_HAUPPAUGE_HVR1800lp: port->dvb.frontend = dvb_attach(s5h1409_attach, &hauppauge_generic_config, &dev->i2c_bus[0].i2c_adap); @@ -113,6 +121,16 @@ static int dvb_register(struct cx23885_tsport *port) &hauppauge_generic_tunerconfig, 0); } break; + case CX23885_BOARD_HAUPPAUGE_HVR1800lp: + port->dvb.frontend = dvb_attach(s5h1409_attach, + &hauppauge_hvr1800lp_config, + &dev->i2c_bus[0].i2c_adap); + if (port->dvb.frontend != NULL) { + dvb_attach(mt2131_attach, port->dvb.frontend, + &dev->i2c_bus[0].i2c_adap, + &hauppauge_generic_tunerconfig, 0); + } + break; default: printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n", dev->name); -- cgit v1.2.3-70-g09d2 From bfde287c2f8f0fe4e50e0eb136e4dca6b0ed84dc Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Thu, 6 Sep 2007 15:50:31 -0300 Subject: V4L/DVB (6191): Removed a redundant switch() The switch() statement is no longer required. Signed-off-by: Steven Toth Reviewed-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 13dc7c8642c..f5b73c4b625 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -1025,18 +1025,7 @@ static int cx23885_start_dma(struct cx23885_tsport *port, cx_write(port->reg_hw_sop_ctrl, 0x47 << 16 | 188 << 4); cx_write(port->reg_ts_clk_en, port->ts_clk_en_val); - - switch (dev->board) { - case CX23885_BOARD_HAUPPAUGE_HVR1250: - case CX23885_BOARD_HAUPPAUGE_HVR1800lp: - case CX23885_BOARD_HAUPPAUGE_HVR1800: - cx_write(port->reg_vld_misc, 0x00); - dprintk(1, "%s() Configuring HVR1800/lp/1500 board\n", - __FUNCTION__); - break; - default: - printk(KERN_ERR "%s() error, default case", __FUNCTION__ ); - } + cx_write(port->reg_vld_misc, 0x00); cx_write(port->reg_gen_ctrl, port->gen_ctrl_val); udelay(100); -- cgit v1.2.3-70-g09d2 From 661c7e44c5cc2828c7acb00cb71d985e129e3641 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Thu, 6 Sep 2007 16:07:49 -0300 Subject: V4L/DVB (6192): Ensure start_dma() is capable of starting dma on port VIDB start_dma() would fail to start dma if a device used VIDB (portb). Signed-off-by: Steven Toth Reviewed-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 9 ++++++--- drivers/media/video/cx23885/cx23885.h | 10 ++++++---- 2 files changed, 12 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index f5b73c4b625..907ea4c2ea3 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -1015,9 +1015,12 @@ static int cx23885_start_dma(struct cx23885_tsport *port, /* write TS length to chip */ cx_write(port->reg_lngth, buf->vb.width); - if (!(cx23885_boards[dev->board].portc & CX23885_MPEG_DVB)) { - printk( "%s() Failed. Unsupported value in .portc (0x%08x)\n", - __FUNCTION__, cx23885_boards[dev->board].portc ); + if ( (!(cx23885_boards[dev->board].portb & CX23885_MPEG_DVB)) && + (!(cx23885_boards[dev->board].portc & CX23885_MPEG_DVB)) ) { + printk( "%s() Failed. Unsupported value in .portb/c (0x%08x)/(0x%08x)\n", + __FUNCTION__, + cx23885_boards[dev->board].portb, + cx23885_boards[dev->board].portc ); return -EINVAL; } diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index c0f4e433735..e44698a6bed 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -86,12 +86,14 @@ struct cx23885_input { u32 gpio0, gpio1, gpio2, gpio3; }; +typedef enum { + CX23885_MPEG_UNDEFINED = 0, + CX23885_MPEG_DVB +} port_t; + struct cx23885_board { char *name; - enum { - CX23885_MPEG_UNDEFINED = 0, - CX23885_MPEG_DVB - } portc; + port_t portb, portc; struct cx23885_input input[MAX_CX23885_INPUT]; }; -- cgit v1.2.3-70-g09d2 From ccbe64c664f2e3a86430ef63c974e38ac1cd5b93 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 8 Sep 2007 11:25:37 -0300 Subject: V4L/DVB (6193): cx23885: define Video B Interrupt Status register bit values - define missing register bit values for VID_B - corrected VID/VBI_B_GPCNT_CTL register addresses Signed-off-by: Michael Krufky Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-reg.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/cx23885-reg.h b/drivers/media/video/cx23885/cx23885-reg.h index 63ab0fb26ac..3f1afbeea77 100644 --- a/drivers/media/video/cx23885/cx23885-reg.h +++ b/drivers/media/video/cx23885/cx23885-reg.h @@ -237,6 +237,13 @@ Channel manager Data Structure entry = 20 DWORD #define VID_B_INT_MSTAT 0x00040038 #define VID_B_INT_SSTAT 0x0004003C +#define VID_B_MSK_BAD_PKT (1 << 20) +#define VID_B_MSK_OPC_ERR (1 << 16) +#define VID_B_MSK_SYNC (1 << 12) +#define VID_B_MSK_OF (1 << 8) +#define VID_B_MSK_RISCI2 (1 << 4) +#define VID_B_MSK_RISCI1 1 + #define VID_C_MSK_BAD_PKT (1 << 20) #define VID_C_MSK_OPC_ERR (1 << 16) #define VID_C_MSK_SYNC (1 << 12) @@ -344,8 +351,8 @@ Channel manager Data Structure entry = 20 DWORD #define VBI_B_DMA 0x00130108 #define VID_B_GPCNT 0x00130120 #define VBI_B_GPCNT 0x00130124 -#define VID_B_GPCNT_CTL 0x00130130 -#define VBI_B_GPCNT_CTL 0x00130134 +#define VID_B_GPCNT_CTL 0x00130134 +#define VBI_B_GPCNT_CTL 0x00130138 #define VID_B_DMA_CTL 0x00130140 #define VID_B_SRC_SEL 0x00130144 #define VID_B_LNGTH 0x00130150 -- cgit v1.2.3-70-g09d2 From 6f074abb624aced31339a0f8fac778b344adac4c Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Sat, 8 Sep 2007 14:21:03 -0300 Subject: V4L/DVB (6194): Changes to support interrupts on VIDB Changes to support interrupts on VIDB Signed-off-by: Steven Toth Reviewed-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 59 +++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 907ea4c2ea3..d155f5fb133 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -1252,20 +1252,23 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) struct cx23885_dev *dev = dev_id; struct cx23885_tsport *port = &dev->ts2; u32 pci_status, pci_mask; + u32 ts1_status, ts1_mask; u32 ts2_status, ts2_mask; int count = 0, handled = 0; pci_status = cx_read(PCI_INT_STAT); pci_mask = cx_read(PCI_INT_MSK); - + ts1_status = cx_read(VID_B_INT_STAT); + ts1_mask = cx_read(VID_B_INT_MSK); ts2_status = cx_read(VID_C_INT_STAT); ts2_mask = cx_read(VID_C_INT_MSK); - if ( (pci_status == 0) && (ts2_status == 0) ) + if ( (pci_status == 0) && (ts2_status == 0) && (ts1_status == 0) ) goto out; count = cx_read(port->reg_gpcnt); dprintk(7, "pci_status: 0x%08x pci_mask: 0x%08x\n", pci_status, pci_mask ); + dprintk(7, "ts1_status: 0x%08x ts1_mask: 0x%08x count: 0x%x\n", ts1_status, ts1_mask, count ); dprintk(7, "ts2_status: 0x%08x ts2_mask: 0x%08x count: 0x%x\n", ts2_status, ts2_mask, count ); if ( (pci_status & PCI_MSK_RISC_RD) || @@ -1303,6 +1306,48 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) } + if ( (ts1_status & VID_B_MSK_OPC_ERR) || + (ts1_status & VID_B_MSK_BAD_PKT) || + (ts1_status & VID_B_MSK_SYNC) || + (ts1_status & VID_B_MSK_OF)) + { + if (ts1_status & VID_B_MSK_OPC_ERR) + dprintk(7, " (VID_B_MSK_OPC_ERR 0x%08x)\n", VID_B_MSK_OPC_ERR); + if (ts1_status & VID_B_MSK_BAD_PKT) + dprintk(7, " (VID_B_MSK_BAD_PKT 0x%08x)\n", VID_B_MSK_BAD_PKT); + if (ts1_status & VID_B_MSK_SYNC) + dprintk(7, " (VID_B_MSK_SYNC 0x%08x)\n", VID_B_MSK_SYNC); + if (ts1_status & VID_B_MSK_OF) + dprintk(7, " (VID_B_MSK_OF 0x%08x)\n", VID_B_MSK_OF); + + printk(KERN_ERR "%s: mpeg risc op code error\n", dev->name); + + cx_clear(port->reg_dma_ctl, port->dma_ctl_val); + cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ]); + + } else if (ts1_status & VID_B_MSK_RISCI1) { + + dprintk(7, " (RISCI1 0x%08x)\n", VID_B_MSK_RISCI1); + + spin_lock(&port->slock); + count = cx_read(port->reg_gpcnt); + cx23885_wakeup(port, &port->mpegq, count); + spin_unlock(&port->slock); + + } else if (ts1_status & VID_B_MSK_RISCI2) { + + dprintk(7, " (RISCI2 0x%08x)\n", VID_B_MSK_RISCI2); + + spin_lock(&port->slock); + cx23885_restart_queue(port, &port->mpegq); + spin_unlock(&port->slock); + + } + if (ts1_status) { + cx_write(VID_B_INT_STAT, ts1_status); + handled = 1; + } + if ( (ts2_status & VID_C_MSK_OPC_ERR) || (ts2_status & VID_C_MSK_BAD_PKT) || (ts2_status & VID_C_MSK_SYNC) || @@ -1341,9 +1386,13 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) } - cx_write(VID_C_INT_STAT, ts2_status); - cx_write(PCI_INT_STAT, pci_status); - handled = 1; + if (ts2_status) { + cx_write(VID_C_INT_STAT, ts2_status); + handled = 1; + } + + if (handled) + cx_write(PCI_INT_STAT, pci_status); out: return IRQ_RETVAL(handled); } -- cgit v1.2.3-70-g09d2 From 579f1163cd5b2a3fd96ec5b84b18a071e7da3b6b Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Sat, 8 Sep 2007 15:07:02 -0300 Subject: V4L/DVB (6195): Changes to support MPEG TS on VIDB Changes to support MPEG TS on VIDB Signed-off-by: Steven Toth Reviewed-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 142 ++++++++++++++++------------- drivers/media/video/cx23885/cx23885.h | 7 ++ 2 files changed, 86 insertions(+), 63 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index d155f5fb133..553a72ae163 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -100,12 +100,12 @@ struct sram_channel cx23885_sram_channels[] = { .cnt2_reg = DMA2_CNT2, }, [SRAM_CH03] = { - .name = "ch3", - .cmds_start = 0x0, - .ctrl_start = 0x0, - .cdt = 0x0, - .fifo_start = 0x0, - .fifo_size = 0x0, + .name = "TS1 B", + .cmds_start = 0x100A0, + .ctrl_start = 0x10780, + .cdt = 0x10400, + .fifo_start = 0x5000, + .fifo_size = 0x1000, .ptr1_reg = DMA3_PTR1, .ptr2_reg = DMA3_PTR2, .cnt1_reg = DMA3_CNT1, @@ -596,7 +596,7 @@ void cx23885_reset(struct cx23885_dev *dev) cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH01 ], 188*4, 0); cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH02 ], 128, 0); - cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH03 ], 128, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH03 ], 188*4, 0); cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH04 ], 128, 0); cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH05 ], 128, 0); cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH06 ], 188*4, 0); @@ -679,6 +679,39 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) atomic_inc(&dev->refcount); dev->nr = cx23885_devcount++; + sprintf(dev->name, "cx23885[%d]", dev->nr); + + mutex_lock(&devlist); + list_add_tail(&dev->devlist, &cx23885_devlist); + mutex_unlock(&devlist); + + /* Configure the internal memory */ + if(dev->pci->device == 0x8880) { + dev->bridge = CX23885_BRIDGE_887; + dev->sram_channels = cx23887_sram_channels; + } else + if(dev->pci->device == 0x8852) { + dev->bridge = CX23885_BRIDGE_885; + dev->sram_channels = cx23885_sram_channels; + } else + BUG(); + + dprintk(1, "%s() Memory configured for PCIe bridge type %d\n", + __FUNCTION__, dev->bridge); + + /* board config */ + dev->board = UNSET; + if (card[dev->nr] < cx23885_bcount) + dev->board = card[dev->nr]; + for (i = 0; UNSET == dev->board && i < cx23885_idcount; i++) + if (dev->pci->subsystem_vendor == cx23885_subids[i].subvendor && + dev->pci->subsystem_device == cx23885_subids[i].subdevice) + dev->board = cx23885_subids[i].card; + if (UNSET == dev->board) { + dev->board = CX23885_BOARD_UNKNOWN; + cx23885_card_list(dev); + } + dev->pci_bus = dev->pci->bus->number; dev->pci_slot = PCI_SLOT(dev->pci->devfn); dev->pci_irqmask = 0x001f00; @@ -717,38 +750,13 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) spin_lock_init(&dev->ts2.slock); dev->ts2.dev = dev; dev->ts2.nr = 2; - dev->ts2.sram_chno = SRAM_CH06; + INIT_LIST_HEAD(&dev->ts2.mpegq.active); INIT_LIST_HEAD(&dev->ts2.mpegq.queued); dev->ts2.mpegq.timeout.function = cx23885_timeout; dev->ts2.mpegq.timeout.data = (unsigned long)&dev->ts2; init_timer(&dev->ts2.mpegq.timeout); - dev->ts2.reg_gpcnt = VID_C_GPCNT; - dev->ts2.reg_gpcnt_ctl = VID_C_GPCNT_CTL; - dev->ts2.reg_dma_ctl = VID_C_DMA_CTL; - dev->ts2.reg_lngth = VID_C_LNGTH; - dev->ts2.reg_hw_sop_ctrl = VID_C_HW_SOP_CTL; - dev->ts2.reg_gen_ctrl = VID_C_GEN_CTL; - dev->ts2.reg_bd_pkt_status = VID_C_BD_PKT_STATUS; - dev->ts2.reg_sop_status = VID_C_SOP_STATUS; - dev->ts2.reg_fifo_ovfl_stat = VID_C_FIFO_OVFL_STAT; - dev->ts2.reg_vld_misc = VID_C_VLD_MISC; - dev->ts2.reg_ts_clk_en = VID_C_TS_CLK_EN; - dev->ts2.reg_ts_int_msk = VID_C_INT_MSK; - - // FIXME: Make this board specific - dev->ts2.pci_irqmask = 0x04; /* TS Port 2 bit */ - dev->ts2.dma_ctl_val = 0x11; /* Enable RISC controller and Fifo */ - dev->ts2.ts_int_msk_val = 0x1111; /* TS port bits for RISC */ - dev->ts2.gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ - dev->ts2.ts_clk_en_val = 0x1; /* Enable TS_CLK */ - - cx23885_risc_stopper(dev->pci, &dev->ts2.mpegq.stopper, - dev->ts2.reg_dma_ctl, dev->ts2.dma_ctl_val, 0x00); - - sprintf(dev->name, "cx23885[%d]", dev->nr); - if (get_resources(dev) < 0) { printk(KERN_ERR "CORE %s No more PCIe resources for " "subsystem: %04x:%04x\n", @@ -759,46 +767,18 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) goto fail_free; } - mutex_lock(&devlist); - list_add_tail(&dev->devlist, &cx23885_devlist); - mutex_unlock(&devlist); - /* PCIe stuff */ dev->lmmio = ioremap(pci_resource_start(dev->pci,0), pci_resource_len(dev->pci,0)); dev->bmmio = (u8 __iomem *)dev->lmmio; - /* board config */ - dev->board = UNSET; - if (card[dev->nr] < cx23885_bcount) - dev->board = card[dev->nr]; - for (i = 0; UNSET == dev->board && i < cx23885_idcount; i++) - if (dev->pci->subsystem_vendor == cx23885_subids[i].subvendor && - dev->pci->subsystem_device == cx23885_subids[i].subdevice) - dev->board = cx23885_subids[i].card; - if (UNSET == dev->board) { - dev->board = CX23885_BOARD_UNKNOWN; - cx23885_card_list(dev); - } printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", dev->name, dev->pci->subsystem_vendor, dev->pci->subsystem_device, cx23885_boards[dev->board].name, dev->board, card[dev->nr] == dev->board ? "insmod option" : "autodetected"); - /* Configure the internal memory */ - if(dev->pci->device == 0x8880) { - dev->bridge = CX23885_BRIDGE_887; - dev->sram_channels = cx23887_sram_channels; - } else - if(dev->pci->device == 0x8852) { - dev->bridge = CX23885_BRIDGE_885; - dev->sram_channels = cx23885_sram_channels; - } - dprintk(1, "%s() Memory configured for PCIe bridge type %d\n", - __FUNCTION__, dev->bridge); - cx23885_pci_quirks(dev); /* init hardware */ @@ -812,6 +792,38 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) cx23885_card_setup(dev); cx23885_ir_init(dev); + switch (dev->board) { + default: + dev->ts2.reg_gpcnt = VID_C_GPCNT; + dev->ts2.reg_gpcnt_ctl = VID_C_GPCNT_CTL; + dev->ts2.reg_dma_ctl = VID_C_DMA_CTL; + dev->ts2.reg_lngth = VID_C_LNGTH; + dev->ts2.reg_hw_sop_ctrl = VID_C_HW_SOP_CTL; + dev->ts2.reg_gen_ctrl = VID_C_GEN_CTL; + dev->ts2.reg_bd_pkt_status = VID_C_BD_PKT_STATUS; + dev->ts2.reg_sop_status = VID_C_SOP_STATUS; + dev->ts2.reg_fifo_ovfl_stat = VID_C_FIFO_OVFL_STAT; + dev->ts2.reg_vld_misc = VID_C_VLD_MISC; + dev->ts2.reg_ts_clk_en = VID_C_TS_CLK_EN; + dev->ts2.reg_ts_int_msk = VID_C_INT_MSK; + dev->ts2.reg_src_sel = 0; + + // FIXME: Make this board specific + dev->ts2.pci_irqmask = 0x04; /* TS Port 2 bit */ + dev->ts2.dma_ctl_val = 0x11; /* Enable RISC controller and Fifo */ + dev->ts2.ts_int_msk_val = 0x1111; /* TS port bits for RISC */ + dev->ts2.gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ + dev->ts2.ts_clk_en_val = 0x1; /* Enable TS_CLK */ + dev->ts2.src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; + + // Drive this from cards.c (portb/c) and move it outside of this switch + dev->ts2.sram_chno = SRAM_CH06; + } + + cx23885_risc_stopper(dev->pci, &dev->ts2.mpegq.stopper, + dev->ts2.reg_dma_ctl, dev->ts2.dma_ctl_val, 0x00); + + // FIXME: This should only be called if ts2 is being used, driven by cards.c if (cx23885_dvb_register(&dev->ts2) < 0) { printk(KERN_ERR "%s() Failed to register dvb adapters\n", __FUNCTION__); @@ -1026,13 +1038,17 @@ static int cx23885_start_dma(struct cx23885_tsport *port, udelay(100); + /* If the port supports SRC SELECT, configure it */ + if(port->reg_src_sel) + cx_write(port->reg_src_sel, port->src_sel_val); + cx_write(port->reg_hw_sop_ctrl, 0x47 << 16 | 188 << 4); cx_write(port->reg_ts_clk_en, port->ts_clk_en_val); cx_write(port->reg_vld_misc, 0x00); - cx_write(port->reg_gen_ctrl, port->gen_ctrl_val); udelay(100); + // NOTE: this is 2 (reserved) for portb, does it matter? /* reset counter to zero */ cx_write(port->reg_gpcnt_ctl, 3); q->count = 1; @@ -1047,7 +1063,7 @@ static int cx23885_start_dma(struct cx23885_tsport *port, cx_set(PCI_INT_MSK, dev->pci_irqmask | port->pci_irqmask); break; default: - printk(KERN_ERR "%s() error, default case", __FUNCTION__ ); + BUG(); } cx_set(DEV_CNTRL2, (1<<5)); /* Enable RISC controller */ diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index e44698a6bed..62b44f6d749 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -68,6 +68,11 @@ enum cx23885_itype { CX23885_RADIO, }; +enum cx23885_src_sel_type { + CX23885_SRC_SEL_EXT_656_VIDEO = 0, + CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO +}; + /* buffer for one video frame */ struct cx23885_buffer { /* common v4l buffer stuff -- must be first */ @@ -162,6 +167,7 @@ struct cx23885_tsport { u32 reg_vld_misc; u32 reg_ts_clk_en; u32 reg_ts_int_msk; + u32 reg_src_sel; /* Default register vals */ int pci_irqmask; @@ -169,6 +175,7 @@ struct cx23885_tsport { u32 ts_int_msk_val; u32 gen_ctrl_val; u32 ts_clk_en_val; + u32 src_sel_val; }; struct cx23885_dev { -- cgit v1.2.3-70-g09d2 From 9bc37caadffe8327683980b2323371691fa182e3 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 8 Sep 2007 15:17:13 -0300 Subject: V4L/DVB (6196): cx23885: add support for DViCO FusionHDTV 5 Express This patch adds digital ATSC / QAM support for the DViCO FusionHDTV5 Express. Remote control is supported by ir-kbd-i2c, RTC is supported by rtc-isl1208. Signed-off-by: Michael Krufky Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-cards.c | 8 ++++++++ drivers/media/video/cx23885/cx23885-core.c | 26 ++++++++++++++++++++++++++ drivers/media/video/cx23885/cx23885-dvb.c | 18 ++++++++++++++++++ drivers/media/video/cx23885/cx23885-i2c.c | 6 ++++-- drivers/media/video/cx23885/cx23885.h | 1 + drivers/media/video/ir-kbd-i2c.c | 3 +++ drivers/media/video/tuner-core.c | 3 ++- 7 files changed, 62 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index 09d4376c2e0..cdda11ddf14 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -109,6 +109,10 @@ struct cx23885_board cx23885_boards[] = { .gpio0 = 0xff02, }}, }, + [CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP] = { + .name = "DViCO FusionHDTV5 Express", + .portc = CX23885_MPEG_DVB, + }, }; const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); @@ -136,6 +140,10 @@ struct cx23885_subid cx23885_subids[] = { .subvendor = 0x0070, .subdevice = 0x7911, .card = CX23885_BOARD_HAUPPAUGE_HVR1250, + },{ + .subvendor = 0x18ac, + .subdevice = 0xd500, + .card = CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP, }, }; const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 553a72ae163..bcba1926347 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -793,6 +793,32 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) cx23885_ir_init(dev); switch (dev->board) { + case CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP: + dev->ts2.reg_gpcnt = VID_B_GPCNT; + dev->ts2.reg_gpcnt_ctl = VID_B_GPCNT_CTL; + dev->ts2.reg_dma_ctl = VID_B_DMA_CTL; + dev->ts2.reg_lngth = VID_B_LNGTH; + dev->ts2.reg_hw_sop_ctrl = VID_B_HW_SOP_CTL; + dev->ts2.reg_gen_ctrl = VID_B_GEN_CTL; + dev->ts2.reg_bd_pkt_status = VID_B_BD_PKT_STATUS; + dev->ts2.reg_sop_status = VID_B_SOP_STATUS; + dev->ts2.reg_fifo_ovfl_stat = VID_B_FIFO_OVFL_STAT; + dev->ts2.reg_vld_misc = VID_B_VLD_MISC; + dev->ts2.reg_ts_clk_en = VID_B_TS_CLK_EN; + dev->ts2.reg_ts_int_msk = VID_B_INT_MSK; + dev->ts2.reg_src_sel = VID_B_SRC_SEL; + + // FIXME: Make this board specific + dev->ts2.pci_irqmask = 0x02; /* TS Port 2 bit */ + dev->ts2.dma_ctl_val = 0x11; /* Enable RISC controller and Fifo */ + dev->ts2.ts_int_msk_val = 0x1111; /* TS port bits for RISC */ + dev->ts2.gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ + dev->ts2.ts_clk_en_val = 0x1; /* Enable TS_CLK */ + dev->ts2.src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; + + // Drive this from cards.c (portb/c) and move it outside of this switch + dev->ts2.sram_chno = SRAM_CH03; + break; default: dev->ts2.reg_gpcnt = VID_C_GPCNT; dev->ts2.reg_gpcnt_ctl = VID_C_GPCNT_CTL; diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index ffa4c49d691..0ace919195d 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -32,6 +32,8 @@ #include "s5h1409.h" #include "mt2131.h" +#include "lgdt330x.h" +#include "dvb-pll.h" static unsigned int debug = 0; @@ -101,6 +103,12 @@ static struct mt2131_config hauppauge_generic_tunerconfig = { 0x61 }; +static struct lgdt330x_config fusionhdtv_5_express = { + .demod_address = 0x0e, + .demod_chip = LGDT3303, + .serial_mpeg = 0x40, +}; + static int dvb_register(struct cx23885_tsport *port) { struct cx23885_dev *dev = port->dev; @@ -131,6 +139,16 @@ static int dvb_register(struct cx23885_tsport *port) &hauppauge_generic_tunerconfig, 0); } break; + case CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP: + port->dvb.frontend = dvb_attach(lgdt330x_attach, + &fusionhdtv_5_express, + &dev->i2c_bus[0].i2c_adap); + if (port->dvb.frontend != NULL) { + dvb_attach(dvb_pll_attach, port->dvb.frontend, + 0x61, &dev->i2c_bus[0].i2c_adap, + DVB_PLL_LG_TDVS_H06XF); + } + break; default: printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n", dev->name); diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c index 5572fbbbb5a..b517c8b5a56 100644 --- a/drivers/media/video/cx23885/cx23885-i2c.c +++ b/drivers/media/video/cx23885/cx23885-i2c.c @@ -305,12 +305,14 @@ static struct i2c_client cx23885_i2c_client_template = { }; static char *i2c_devs[128] = { + [ 0x1c >> 1 ] = "lgdt3303", + [ 0x86 >> 1 ] = "tda9887", [ 0x32 >> 1 ] = "cx24227", [ 0x88 >> 1 ] = "cx25837", [ 0x84 >> 1 ] = "tda8295", [ 0xa0 >> 1 ] = "eeprom", - [ 0xc0 >> 1 ] = "mt2131/tda8275", - [ 0xc2 >> 1 ] = "mt2131/tda8275", + [ 0xc0 >> 1 ] = "tuner/mt2131/tda8275", + [ 0xc2 >> 1 ] = "tuner/mt2131/tda8275", }; static void do_i2c_scan(char *name, struct i2c_client *c) diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 62b44f6d749..4933274b1e3 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -54,6 +54,7 @@ #define CX23885_BOARD_HAUPPAUGE_HVR1800lp 1 #define CX23885_BOARD_HAUPPAUGE_HVR1800 2 #define CX23885_BOARD_HAUPPAUGE_HVR1250 3 +#define CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP 4 enum cx23885_itype { CX23885_VMUX_COMPOSITE1 = 1, diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index 04f6eb5ea29..d98dd0d1e37 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c @@ -507,6 +507,7 @@ static int ir_probe(struct i2c_adapter *adap) static const int probe_saa7134[] = { 0x7a, 0x47, 0x71, -1 }; static const int probe_em28XX[] = { 0x30, 0x47, -1 }; static const int probe_cx88[] = { 0x18, 0x6b, 0x71, -1 }; + static const int probe_cx23885[] = { 0x6b, -1 }; const int *probe = NULL; struct i2c_client c; unsigned char buf; @@ -527,6 +528,8 @@ static int ir_probe(struct i2c_adapter *adap) break; case I2C_HW_B_CX2388x: probe = probe_cx88; + case I2C_HW_B_CX23885: + probe = probe_cx23885; break; } if (NULL == probe) diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 2d4a3e38f27..94843086cda 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -665,7 +665,8 @@ static int tuner_probe(struct i2c_adapter *adap) * FusionHDTV5 RT Gold has an ir receiver at 0x6b * and an RTC at 0x6f which can get corrupted if probed. */ - if (adap->id == I2C_HW_B_CX2388x) { + if ((adap->id == I2C_HW_B_CX2388x) || + (adap->id == I2C_HW_B_CX23885)) { unsigned int i = 0; while (i < I2C_CLIENT_MAX_OPTS && ignore[i] != I2C_CLIENT_END) -- cgit v1.2.3-70-g09d2 From a6a3f14035fe94c0925fea62f3d3a7a1ab44c1f1 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Sat, 8 Sep 2007 21:31:56 -0300 Subject: V4L/DVB (6199): cx23885: Changes to allow demodulators on each transport bus cx23885: Changes to allow demodulators on each transport bus. Signed-off-by: Steven Toth Reviewed-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-cards.c | 53 ++++- drivers/media/video/cx23885/cx23885-core.c | 324 ++++++++++++---------------- drivers/media/video/cx23885/cx23885-dvb.c | 4 +- drivers/media/video/cx23885/cx23885-reg.h | 16 +- drivers/media/video/cx23885/cx23885.h | 5 +- 5 files changed, 207 insertions(+), 195 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index cdda11ddf14..b9012acabb2 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -111,7 +111,7 @@ struct cx23885_board cx23885_boards[] = { }, [CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP] = { .name = "DViCO FusionHDTV5 Express", - .portc = CX23885_MPEG_DVB, + .portb = CX23885_MPEG_DVB, }, }; const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); @@ -197,8 +197,43 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) dev->name, tv.model); } +void cx23885_gpio_setup(struct cx23885_dev *dev) +{ + switch(dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1250: + /* GPIO-0 cx24227 demodulator reset */ + cx_set(GP0_IO, 0x00010001); /* Bring the part out of reset */ + break; + case CX23885_BOARD_HAUPPAUGE_HVR1800: + /* GPIO-0 656_CLK */ + /* GPIO-1 656_D0 */ + /* GPIO-2 8295A Reset */ + /* GPIO-3-10 cx23417 data0-7 */ + /* GPIO-11-14 cx23417 addr0-3 */ + /* GPIO-15-18 cx23417 READY, CS, RD, WR */ + /* GPIO-19 IR_RX */ + // FIXME: Analog requires the tuner is brought out of reset + break; + } +} + +int cx23885_ir_init(struct cx23885_dev *dev) +{ + switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1250: + case CX23885_BOARD_HAUPPAUGE_HVR1800: + /* FIXME: Implement me */ + break; + } + + return 0; +} + void cx23885_card_setup(struct cx23885_dev *dev) { + struct cx23885_tsport *ts1 = &dev->ts1; + struct cx23885_tsport *ts2 = &dev->ts2; + static u8 eeprom[256]; if (dev->i2c_bus[0].i2c_rc == 0) { @@ -215,6 +250,22 @@ void cx23885_card_setup(struct cx23885_dev *dev) hauppauge_eeprom(dev, eeprom+0x80); break; } + + switch (dev->board) { + case CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP: + ts1->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ + ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ + ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; + break; + case CX23885_BOARD_HAUPPAUGE_HVR1250: + case CX23885_BOARD_HAUPPAUGE_HVR1800: + case CX23885_BOARD_HAUPPAUGE_HVR1800lp: + default: + ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ + ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ + ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; + } + } /* ------------------------------------------------------------------ */ diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index bcba1926347..51879961e3e 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -604,24 +604,7 @@ void cx23885_reset(struct cx23885_dev *dev) cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH08 ], 128, 0); cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH09 ], 128, 0); - switch(dev->board) { - case CX23885_BOARD_HAUPPAUGE_HVR1250: - /* GPIO-0 cx24227 demodulator reset */ - dprintk( 1, "%s() Configuring HVR1250 GPIO's\n", __FUNCTION__); - cx_set(GP0_IO, 0x00010001); /* Bring the part out of reset */ - break; - case CX23885_BOARD_HAUPPAUGE_HVR1800: - /* GPIO-0 656_CLK */ - /* GPIO-1 656_D0 */ - /* GPIO-2 8295A Reset */ - /* GPIO-3-10 cx23417 data0-7 */ - /* GPIO-11-14 cx23417 addr0-3 */ - /* GPIO-15-18 cx23417 READY, CS, RD, WR */ - /* GPIO-19 IR_RX */ - dprintk( 1, "%s() Configuring HVR1800 GPIO's\n", __FUNCTION__); - // FIXME: Analog requires the tuner is brought out of reset - break; - } + cx23885_gpio_setup(dev); } @@ -656,17 +639,68 @@ static void cx23885_timeout(unsigned long data); int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, u32 reg, u32 mask, u32 value); -static int cx23885_ir_init(struct cx23885_dev *dev) +static int cx23885_init_tsport(struct cx23885_dev *dev, struct cx23885_tsport *port, int portno) { - dprintk(1, "%s()\n", __FUNCTION__); - - switch (dev->board) { - case CX23885_BOARD_HAUPPAUGE_HVR1250: - case CX23885_BOARD_HAUPPAUGE_HVR1800: - dprintk(1, "%s() FIXME - Implement IR support\n", __FUNCTION__); + dprintk(1, "%s(portno=%d)\n", __FUNCTION__, portno); + + /* Transport bus init dma queue - Common settings */ + port->dma_ctl_val = 0x11; /* Enable RISC controller and Fifo */ + port->ts_int_msk_val = 0x1111; /* TS port bits for RISC */ + + spin_lock_init(&port->slock); + port->dev = dev; + port->nr = portno; + + INIT_LIST_HEAD(&port->mpegq.active); + INIT_LIST_HEAD(&port->mpegq.queued); + port->mpegq.timeout.function = cx23885_timeout; + port->mpegq.timeout.data = (unsigned long)port; + init_timer(&port->mpegq.timeout); + + switch(portno) { + case 1: + port->reg_gpcnt = VID_B_GPCNT; + port->reg_gpcnt_ctl = VID_B_GPCNT_CTL; + port->reg_dma_ctl = VID_B_DMA_CTL; + port->reg_lngth = VID_B_LNGTH; + port->reg_hw_sop_ctrl = VID_B_HW_SOP_CTL; + port->reg_gen_ctrl = VID_B_GEN_CTL; + port->reg_bd_pkt_status = VID_B_BD_PKT_STATUS; + port->reg_sop_status = VID_B_SOP_STATUS; + port->reg_fifo_ovfl_stat = VID_B_FIFO_OVFL_STAT; + port->reg_vld_misc = VID_B_VLD_MISC; + port->reg_ts_clk_en = VID_B_TS_CLK_EN; + port->reg_src_sel = VID_B_SRC_SEL; + port->reg_ts_int_msk = VID_B_INT_MSK; + port->reg_ts_int_stat = VID_B_INT_STAT; + port->sram_chno = SRAM_CH03; /* VID_B */ + port->pci_irqmask = 0x02; /* VID_B bit1 */ + break; + case 2: + port->reg_gpcnt = VID_C_GPCNT; + port->reg_gpcnt_ctl = VID_C_GPCNT_CTL; + port->reg_dma_ctl = VID_C_DMA_CTL; + port->reg_lngth = VID_C_LNGTH; + port->reg_hw_sop_ctrl = VID_C_HW_SOP_CTL; + port->reg_gen_ctrl = VID_C_GEN_CTL; + port->reg_bd_pkt_status = VID_C_BD_PKT_STATUS; + port->reg_sop_status = VID_C_SOP_STATUS; + port->reg_fifo_ovfl_stat = VID_C_FIFO_OVFL_STAT; + port->reg_vld_misc = VID_C_VLD_MISC; + port->reg_ts_clk_en = VID_C_TS_CLK_EN; + port->reg_src_sel = 0; + port->reg_ts_int_msk = VID_C_INT_MSK; + port->reg_ts_int_stat = VID_C_INT_STAT; + port->sram_chno = SRAM_CH06; /* VID_C */ + port->pci_irqmask = 0x04; /* VID_C bit2 */ break; + default: + BUG(); } + cx23885_risc_stopper(dev->pci, &port->mpegq.stopper, + port->reg_dma_ctl, port->dma_ctl_val, 0x00); + return 0; } @@ -746,16 +780,11 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) dev->i2c_bus[2].reg_wdata = I2C3_WDATA; dev->i2c_bus[2].i2c_period = (0x07 << 24); /* 1.95MHz */ - /* Transport bus init dma queue */ - spin_lock_init(&dev->ts2.slock); - dev->ts2.dev = dev; - dev->ts2.nr = 2; + if(cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) + cx23885_init_tsport(dev, &dev->ts1, 1); - INIT_LIST_HEAD(&dev->ts2.mpegq.active); - INIT_LIST_HEAD(&dev->ts2.mpegq.queued); - dev->ts2.mpegq.timeout.function = cx23885_timeout; - dev->ts2.mpegq.timeout.data = (unsigned long)&dev->ts2; - init_timer(&dev->ts2.mpegq.timeout); + if(cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) + cx23885_init_tsport(dev, &dev->ts2, 2); if (get_resources(dev) < 0) { printk(KERN_ERR "CORE %s No more PCIe resources for " @@ -788,71 +817,21 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) cx23885_i2c_register(&dev->i2c_bus[1]); cx23885_i2c_register(&dev->i2c_bus[2]); cx23885_call_i2c_clients (&dev->i2c_bus[0], TUNER_SET_STANDBY, NULL); - cx23885_card_setup(dev); cx23885_ir_init(dev); - switch (dev->board) { - case CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP: - dev->ts2.reg_gpcnt = VID_B_GPCNT; - dev->ts2.reg_gpcnt_ctl = VID_B_GPCNT_CTL; - dev->ts2.reg_dma_ctl = VID_B_DMA_CTL; - dev->ts2.reg_lngth = VID_B_LNGTH; - dev->ts2.reg_hw_sop_ctrl = VID_B_HW_SOP_CTL; - dev->ts2.reg_gen_ctrl = VID_B_GEN_CTL; - dev->ts2.reg_bd_pkt_status = VID_B_BD_PKT_STATUS; - dev->ts2.reg_sop_status = VID_B_SOP_STATUS; - dev->ts2.reg_fifo_ovfl_stat = VID_B_FIFO_OVFL_STAT; - dev->ts2.reg_vld_misc = VID_B_VLD_MISC; - dev->ts2.reg_ts_clk_en = VID_B_TS_CLK_EN; - dev->ts2.reg_ts_int_msk = VID_B_INT_MSK; - dev->ts2.reg_src_sel = VID_B_SRC_SEL; - - // FIXME: Make this board specific - dev->ts2.pci_irqmask = 0x02; /* TS Port 2 bit */ - dev->ts2.dma_ctl_val = 0x11; /* Enable RISC controller and Fifo */ - dev->ts2.ts_int_msk_val = 0x1111; /* TS port bits for RISC */ - dev->ts2.gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ - dev->ts2.ts_clk_en_val = 0x1; /* Enable TS_CLK */ - dev->ts2.src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; - - // Drive this from cards.c (portb/c) and move it outside of this switch - dev->ts2.sram_chno = SRAM_CH03; - break; - default: - dev->ts2.reg_gpcnt = VID_C_GPCNT; - dev->ts2.reg_gpcnt_ctl = VID_C_GPCNT_CTL; - dev->ts2.reg_dma_ctl = VID_C_DMA_CTL; - dev->ts2.reg_lngth = VID_C_LNGTH; - dev->ts2.reg_hw_sop_ctrl = VID_C_HW_SOP_CTL; - dev->ts2.reg_gen_ctrl = VID_C_GEN_CTL; - dev->ts2.reg_bd_pkt_status = VID_C_BD_PKT_STATUS; - dev->ts2.reg_sop_status = VID_C_SOP_STATUS; - dev->ts2.reg_fifo_ovfl_stat = VID_C_FIFO_OVFL_STAT; - dev->ts2.reg_vld_misc = VID_C_VLD_MISC; - dev->ts2.reg_ts_clk_en = VID_C_TS_CLK_EN; - dev->ts2.reg_ts_int_msk = VID_C_INT_MSK; - dev->ts2.reg_src_sel = 0; - - // FIXME: Make this board specific - dev->ts2.pci_irqmask = 0x04; /* TS Port 2 bit */ - dev->ts2.dma_ctl_val = 0x11; /* Enable RISC controller and Fifo */ - dev->ts2.ts_int_msk_val = 0x1111; /* TS port bits for RISC */ - dev->ts2.gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ - dev->ts2.ts_clk_en_val = 0x1; /* Enable TS_CLK */ - dev->ts2.src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; - - // Drive this from cards.c (portb/c) and move it outside of this switch - dev->ts2.sram_chno = SRAM_CH06; + if(cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) { + if (cx23885_dvb_register(&dev->ts1) < 0) { + printk(KERN_ERR "%s() Failed to register dvb adapters on VID_B\n", + __FUNCTION__); + } } - cx23885_risc_stopper(dev->pci, &dev->ts2.mpegq.stopper, - dev->ts2.reg_dma_ctl, dev->ts2.dma_ctl_val, 0x00); - - // FIXME: This should only be called if ts2 is being used, driven by cards.c - if (cx23885_dvb_register(&dev->ts2) < 0) { - printk(KERN_ERR "%s() Failed to register dvb adapters\n", - __FUNCTION__); + if(cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) { + if (cx23885_dvb_register(&dev->ts2) < 0) { + printk(KERN_ERR "%s() Failed to register dvb adapters on VID_C\n", + __FUNCTION__); + } } return 0; @@ -870,7 +849,12 @@ void cx23885_dev_unregister(struct cx23885_dev *dev) if (!atomic_dec_and_test(&dev->refcount)) return; - cx23885_dvb_unregister(&dev->ts2); + if(cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) + cx23885_dvb_unregister(&dev->ts1); + + if(cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) + cx23885_dvb_unregister(&dev->ts2); + cx23885_i2c_unregister(&dev->i2c_bus[2]); cx23885_i2c_unregister(&dev->i2c_bus[1]); cx23885_i2c_unregister(&dev->i2c_bus[0]); @@ -1289,14 +1273,66 @@ static void cx23885_timeout(unsigned long data) do_cancel_buffers(port, "timeout", 1); } +static int cx23885_irq_ts(struct cx23885_tsport *port, u32 status) +{ + struct cx23885_dev *dev = port->dev; + int handled = 0; + u32 count; + + if ( (status & VID_BC_MSK_OPC_ERR) || + (status & VID_BC_MSK_BAD_PKT) || + (status & VID_BC_MSK_SYNC) || + (status & VID_BC_MSK_OF)) + { + if (status & VID_BC_MSK_OPC_ERR) + dprintk(7, " (VID_BC_MSK_OPC_ERR 0x%08x)\n", VID_BC_MSK_OPC_ERR); + if (status & VID_BC_MSK_BAD_PKT) + dprintk(7, " (VID_BC_MSK_BAD_PKT 0x%08x)\n", VID_BC_MSK_BAD_PKT); + if (status & VID_BC_MSK_SYNC) + dprintk(7, " (VID_BC_MSK_SYNC 0x%08x)\n", VID_BC_MSK_SYNC); + if (status & VID_BC_MSK_OF) + dprintk(7, " (VID_BC_MSK_OF 0x%08x)\n", VID_BC_MSK_OF); + + printk(KERN_ERR "%s: mpeg risc op code error\n", dev->name); + + cx_clear(port->reg_dma_ctl, port->dma_ctl_val); + cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ]); + + } else if (status & VID_BC_MSK_RISCI1) { + + dprintk(7, " (RISCI1 0x%08x)\n", VID_BC_MSK_RISCI1); + + spin_lock(&port->slock); + count = cx_read(port->reg_gpcnt); + cx23885_wakeup(port, &port->mpegq, count); + spin_unlock(&port->slock); + + } else if (status & VID_BC_MSK_RISCI2) { + + dprintk(7, " (RISCI2 0x%08x)\n", VID_BC_MSK_RISCI2); + + spin_lock(&port->slock); + cx23885_restart_queue(port, &port->mpegq); + spin_unlock(&port->slock); + + } + if (status) { + cx_write(port->reg_ts_int_stat, status); + handled = 1; + } + + return handled; +} + static irqreturn_t cx23885_irq(int irq, void *dev_id) { struct cx23885_dev *dev = dev_id; - struct cx23885_tsport *port = &dev->ts2; + struct cx23885_tsport *ts1 = &dev->ts1; + struct cx23885_tsport *ts2 = &dev->ts2; u32 pci_status, pci_mask; u32 ts1_status, ts1_mask; u32 ts2_status, ts2_mask; - int count = 0, handled = 0; + int ts1_count = 0, ts2_count = 0, handled = 0; pci_status = cx_read(PCI_INT_STAT); pci_mask = cx_read(PCI_INT_MSK); @@ -1308,10 +1344,11 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) if ( (pci_status == 0) && (ts2_status == 0) && (ts1_status == 0) ) goto out; - count = cx_read(port->reg_gpcnt); + ts1_count = cx_read(ts1->reg_gpcnt); + ts2_count = cx_read(ts2->reg_gpcnt); dprintk(7, "pci_status: 0x%08x pci_mask: 0x%08x\n", pci_status, pci_mask ); - dprintk(7, "ts1_status: 0x%08x ts1_mask: 0x%08x count: 0x%x\n", ts1_status, ts1_mask, count ); - dprintk(7, "ts2_status: 0x%08x ts2_mask: 0x%08x count: 0x%x\n", ts2_status, ts2_mask, count ); + dprintk(7, "ts1_status: 0x%08x ts1_mask: 0x%08x count: 0x%x\n", ts1_status, ts1_mask, ts1_count ); + dprintk(7, "ts2_status: 0x%08x ts2_mask: 0x%08x count: 0x%x\n", ts2_status, ts2_mask, ts2_count ); if ( (pci_status & PCI_MSK_RISC_RD) || (pci_status & PCI_MSK_RISC_WR) || @@ -1348,90 +1385,11 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) } - if ( (ts1_status & VID_B_MSK_OPC_ERR) || - (ts1_status & VID_B_MSK_BAD_PKT) || - (ts1_status & VID_B_MSK_SYNC) || - (ts1_status & VID_B_MSK_OF)) - { - if (ts1_status & VID_B_MSK_OPC_ERR) - dprintk(7, " (VID_B_MSK_OPC_ERR 0x%08x)\n", VID_B_MSK_OPC_ERR); - if (ts1_status & VID_B_MSK_BAD_PKT) - dprintk(7, " (VID_B_MSK_BAD_PKT 0x%08x)\n", VID_B_MSK_BAD_PKT); - if (ts1_status & VID_B_MSK_SYNC) - dprintk(7, " (VID_B_MSK_SYNC 0x%08x)\n", VID_B_MSK_SYNC); - if (ts1_status & VID_B_MSK_OF) - dprintk(7, " (VID_B_MSK_OF 0x%08x)\n", VID_B_MSK_OF); + if (ts1_status) + handled += cx23885_irq_ts(ts1, ts1_status); - printk(KERN_ERR "%s: mpeg risc op code error\n", dev->name); - - cx_clear(port->reg_dma_ctl, port->dma_ctl_val); - cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ]); - - } else if (ts1_status & VID_B_MSK_RISCI1) { - - dprintk(7, " (RISCI1 0x%08x)\n", VID_B_MSK_RISCI1); - - spin_lock(&port->slock); - count = cx_read(port->reg_gpcnt); - cx23885_wakeup(port, &port->mpegq, count); - spin_unlock(&port->slock); - - } else if (ts1_status & VID_B_MSK_RISCI2) { - - dprintk(7, " (RISCI2 0x%08x)\n", VID_B_MSK_RISCI2); - - spin_lock(&port->slock); - cx23885_restart_queue(port, &port->mpegq); - spin_unlock(&port->slock); - - } - if (ts1_status) { - cx_write(VID_B_INT_STAT, ts1_status); - handled = 1; - } - - if ( (ts2_status & VID_C_MSK_OPC_ERR) || - (ts2_status & VID_C_MSK_BAD_PKT) || - (ts2_status & VID_C_MSK_SYNC) || - (ts2_status & VID_C_MSK_OF)) - { - if (ts2_status & VID_C_MSK_OPC_ERR) - dprintk(7, " (VID_C_MSK_OPC_ERR 0x%08x)\n", VID_C_MSK_OPC_ERR); - if (ts2_status & VID_C_MSK_BAD_PKT) - dprintk(7, " (VID_C_MSK_BAD_PKT 0x%08x)\n", VID_C_MSK_BAD_PKT); - if (ts2_status & VID_C_MSK_SYNC) - dprintk(7, " (VID_C_MSK_SYNC 0x%08x)\n", VID_C_MSK_SYNC); - if (ts2_status & VID_C_MSK_OF) - dprintk(7, " (VID_C_MSK_OF 0x%08x)\n", VID_C_MSK_OF); - - printk(KERN_ERR "%s: mpeg risc op code error\n", dev->name); - - cx_clear(port->reg_dma_ctl, port->dma_ctl_val); - cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ]); - - } else if (ts2_status & VID_C_MSK_RISCI1) { - - dprintk(7, " (RISCI1 0x%08x)\n", VID_C_MSK_RISCI1); - - spin_lock(&port->slock); - count = cx_read(port->reg_gpcnt); - cx23885_wakeup(port, &port->mpegq, count); - spin_unlock(&port->slock); - - } else if (ts2_status & VID_C_MSK_RISCI2) { - - dprintk(7, " (RISCI2 0x%08x)\n", VID_C_MSK_RISCI2); - - spin_lock(&port->slock); - cx23885_restart_queue(port, &port->mpegq); - spin_unlock(&port->slock); - - } - - if (ts2_status) { - cx_write(VID_C_INT_STAT, ts2_status); - handled = 1; - } + if (ts2_status) + handled += cx23885_irq_ts(ts2, ts2_status); if (handled) cx_write(PCI_INT_STAT, pci_status); diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index 0ace919195d..e0dc1495b8c 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -160,6 +160,7 @@ static int dvb_register(struct cx23885_tsport *port) } /* Put the analog decoder in standby to keep it quiet */ + /* Assumption here: analog decoder is only on i2c bus 0 */ cx23885_call_i2c_clients (&dev->i2c_bus[0], TUNER_SET_STANDBY, NULL); /* register everything */ @@ -180,8 +181,6 @@ int cx23885_dvb_register(struct cx23885_tsport *port) dev->pci_slot); err = -ENODEV; - if (!(cx23885_boards[dev->board].portc & CX23885_MPEG_DVB)) - goto fail_core; /* dvb stuff */ printk("%s: cx23885 based dvb card\n", dev->name); @@ -192,7 +191,6 @@ int cx23885_dvb_register(struct cx23885_tsport *port) if (err != 0) printk("%s() dvb_register failed err = %d\n", __FUNCTION__, err); - fail_core: return err; } diff --git a/drivers/media/video/cx23885/cx23885-reg.h b/drivers/media/video/cx23885/cx23885-reg.h index 3f1afbeea77..162169f9091 100644 --- a/drivers/media/video/cx23885/cx23885-reg.h +++ b/drivers/media/video/cx23885/cx23885-reg.h @@ -250,14 +250,16 @@ Channel manager Data Structure entry = 20 DWORD #define VID_C_MSK_OF (1 << 8) #define VID_C_MSK_RISCI2 (1 << 4) #define VID_C_MSK_RISCI1 1 -#define VID_C_INT_MSK 0x00040040 -#define VID_C_MSK_BAD_PKT (1 << 20) -#define VID_C_MSK_OPC_ERR (1 << 16) -#define VID_C_MSK_SYNC (1 << 12) -#define VID_C_MSK_OF (1 << 8) -#define VID_C_MSK_RISCI2 (1 << 4) -#define VID_C_MSK_RISCI1 1 +/* A superset for testing purposes */ +#define VID_BC_MSK_BAD_PKT (1 << 20) +#define VID_BC_MSK_OPC_ERR (1 << 16) +#define VID_BC_MSK_SYNC (1 << 12) +#define VID_BC_MSK_OF (1 << 8) +#define VID_BC_MSK_RISCI2 (1 << 4) +#define VID_BC_MSK_RISCI1 1 + +#define VID_C_INT_MSK 0x00040040 #define VID_C_INT_STAT 0x00040044 #define VID_C_INT_MSTAT 0x00040048 #define VID_C_INT_SSTAT 0x0004004C diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 4933274b1e3..45c47cd6070 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -168,6 +168,7 @@ struct cx23885_tsport { u32 reg_vld_misc; u32 reg_ts_clk_en; u32 reg_ts_int_msk; + u32 reg_ts_int_stat; u32 reg_src_sel; /* Default register vals */ @@ -201,7 +202,7 @@ struct cx23885_dev { unsigned int board; char name[32]; - struct cx23885_tsport ts2; + struct cx23885_tsport ts1, ts2; /* sram configuration */ struct sram_channel *sram_channels; @@ -269,6 +270,8 @@ extern struct cx23885_subid cx23885_subids[]; extern const unsigned int cx23885_idcount; extern void cx23885_card_list(struct cx23885_dev *dev); +extern int cx23885_ir_init(struct cx23885_dev *dev); +extern void cx23885_gpio_setup(struct cx23885_dev *dev); extern void cx23885_card_setup(struct cx23885_dev *dev); extern void cx23885_card_setup_pre_i2c(struct cx23885_dev *dev); -- cgit v1.2.3-70-g09d2 From f139fa71c03d80c1d1ee60aa4b0a3ec7a14d45f9 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 9 Sep 2007 03:55:34 -0300 Subject: V4L/DVB (6200): cx23885: use a pointer to the required i2c bus in dvb_register function Store a pointer to the required i2c_bus so that we do not put the wrong analog demod into standby. Signed-off-by: Michael Krufky Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-dvb.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index e0dc1495b8c..d952f3a6753 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -112,6 +112,7 @@ static struct lgdt330x_config fusionhdtv_5_express = { static int dvb_register(struct cx23885_tsport *port) { struct cx23885_dev *dev = port->dev; + struct cx23885_i2c *i2c_bus = NULL; /* init struct videobuf_dvb */ port->dvb.name = dev->name; @@ -120,33 +121,35 @@ static int dvb_register(struct cx23885_tsport *port) switch (dev->board) { case CX23885_BOARD_HAUPPAUGE_HVR1250: case CX23885_BOARD_HAUPPAUGE_HVR1800: + i2c_bus = &dev->i2c_bus[0]; port->dvb.frontend = dvb_attach(s5h1409_attach, &hauppauge_generic_config, - &dev->i2c_bus[0].i2c_adap); + &i2c_bus->i2c_adap); if (port->dvb.frontend != NULL) { dvb_attach(mt2131_attach, port->dvb.frontend, - &dev->i2c_bus[0].i2c_adap, + &i2c_bus->i2c_adap, &hauppauge_generic_tunerconfig, 0); } break; case CX23885_BOARD_HAUPPAUGE_HVR1800lp: + i2c_bus = &dev->i2c_bus[0]; port->dvb.frontend = dvb_attach(s5h1409_attach, &hauppauge_hvr1800lp_config, - &dev->i2c_bus[0].i2c_adap); + &i2c_bus->i2c_adap); if (port->dvb.frontend != NULL) { dvb_attach(mt2131_attach, port->dvb.frontend, - &dev->i2c_bus[0].i2c_adap, + &i2c_bus->i2c_adap, &hauppauge_generic_tunerconfig, 0); } break; case CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP: + i2c_bus = &dev->i2c_bus[0]; port->dvb.frontend = dvb_attach(lgdt330x_attach, &fusionhdtv_5_express, - &dev->i2c_bus[0].i2c_adap); + &i2c_bus->i2c_adap); if (port->dvb.frontend != NULL) { - dvb_attach(dvb_pll_attach, port->dvb.frontend, - 0x61, &dev->i2c_bus[0].i2c_adap, - DVB_PLL_LG_TDVS_H06XF); + dvb_attach(dvb_pll_attach, port->dvb.frontend, 0x61, + &i2c_bus->i2c_adap, DVB_PLL_LG_TDVS_H06XF); } break; default: @@ -160,8 +163,7 @@ static int dvb_register(struct cx23885_tsport *port) } /* Put the analog decoder in standby to keep it quiet */ - /* Assumption here: analog decoder is only on i2c bus 0 */ - cx23885_call_i2c_clients (&dev->i2c_bus[0], TUNER_SET_STANDBY, NULL); + cx23885_call_i2c_clients(i2c_bus, TUNER_SET_STANDBY, NULL); /* register everything */ return videobuf_dvb_register(&port->dvb, THIS_MODULE, port, -- cgit v1.2.3-70-g09d2 From 289ea1f03353104c4f288f6c70c5c7e1568ea257 Mon Sep 17 00:00:00 2001 From: Simon Farnsworth Date: Mon, 10 Sep 2007 13:37:26 -0300 Subject: V4L/DVB (6203): Fix SVideo input on KWorld DVB-T 220 boards Fix SVideo input on KWorld DVB-T 220 boards. Without this patch, the luma pin on the SVideo input is treated as a composite in, and the chroma pin is ignored. Also, fix the radio, and provide a second composite input for people who are used to the existing composite on SVideo connector behaviour. Signed-off-by: Simon Farnsworth Reviewed-by: Hermann Pitton Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-cards.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 5c3174a62e5..c4dc9868c48 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -2771,6 +2771,7 @@ struct saa7134_board saa7134_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .mpeg = SAA7134_MPEG_DVB, + .gpiomask = 1 << 21, .inputs = {{ .name = name_tv, .vmux = 1, @@ -2781,13 +2782,18 @@ struct saa7134_board saa7134_boards[] = { .vmux = 3, .amux = LINE1, },{ - .name = name_svideo, + .name = name_comp2, .vmux = 0, .amux = LINE1, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, }}, .radio = { .name = name_radio, - .amux = LINE1, + .amux = TV, + .gpio = 0x0200000, }, }, [SAA7134_BOARD_KWORLD_DVBT_210] = { -- cgit v1.2.3-70-g09d2 From 747f07961e9450058522840129cd7bb994f05fb9 Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sat, 8 Sep 2007 22:10:11 -0300 Subject: V4L/DVB (6205): pvrusb2: Fix oops in error leg cleanup Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-context.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.c b/drivers/media/video/pvrusb2/pvrusb2-context.c index 6bbed88d786..22719ba861a 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-context.c +++ b/drivers/media/video/pvrusb2/pvrusb2-context.c @@ -33,8 +33,10 @@ static void pvr2_context_destroy(struct pvr2_context *mp) { if (mp->hdw) pvr2_hdw_destroy(mp->hdw); pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr_main id=%p",mp); - flush_workqueue(mp->workqueue); - destroy_workqueue(mp->workqueue); + if (mp->workqueue) { + flush_workqueue(mp->workqueue); + destroy_workqueue(mp->workqueue); + } kfree(mp); } -- cgit v1.2.3-70-g09d2 From 401c27ce96382b3bdbc7a9c7e7303fd1b3af9ef0 Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sat, 8 Sep 2007 22:11:46 -0300 Subject: V4L/DVB (6207): pvrusb2: Fix a potential oops in an error leg cleanup Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-hdw.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 2d5be5cfbcc..5d9045268cf 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -2172,6 +2172,7 @@ static void pvr2_hdw_remove_usb_stuff(struct pvr2_hdw *hdw) /* Destroy hardware interaction structure */ void pvr2_hdw_destroy(struct pvr2_hdw *hdw) { + if (!hdw) return; pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_destroy: hdw=%p",hdw); if (hdw->fw_buffer) { kfree(hdw->fw_buffer); -- cgit v1.2.3-70-g09d2 From 4db666cc3d199a8b837174bb0ad00d6b8f6115d6 Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sat, 8 Sep 2007 22:16:27 -0300 Subject: V4L/DVB (6208): pvrusb2: Implement programmatic means to extract prom contents The pvrusb2 driver already has a method for extracting the FX2's program memory back out to a user application; this ability is used to facilitate manual firmware extraction as per the procedure documented on the pvrusb2 web site. This change follows that pattern and implements a corresponding method to grab the binary contents of the PVR USB2 prom (which for PVR USB2 devices can contain information in addition to the usual Hauppauge metadata). Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-debugifc.c | 16 ++- drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h | 1 + drivers/media/video/pvrusb2/pvrusb2-hdw.c | 150 +++++++++++++++++---- drivers/media/video/pvrusb2/pvrusb2-hdw.h | 12 +- 4 files changed, 147 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c index e9da9bb8f8d..6f135f4a249 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c +++ b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c @@ -397,10 +397,22 @@ static int pvr2_debugifc_do1cmd(struct pvr2_hdw *hdw,const char *buf, count -= scnt; buf += scnt; if (!wptr) return -EINVAL; if (debugifc_match_keyword(wptr,wlen,"fetch")) { - pvr2_hdw_cpufw_set_enabled(hdw,!0); + scnt = debugifc_isolate_word(buf,count,&wptr,&wlen); + if (scnt && wptr) { + count -= scnt; buf += scnt; + if (debugifc_match_keyword(wptr,wlen,"prom")) { + pvr2_hdw_cpufw_set_enabled(hdw,!0,!0); + } else if (debugifc_match_keyword(wptr,wlen, + "ram")) { + pvr2_hdw_cpufw_set_enabled(hdw,0,!0); + } else { + return -EINVAL; + } + } + pvr2_hdw_cpufw_set_enabled(hdw,0,!0); return 0; } else if (debugifc_match_keyword(wptr,wlen,"done")) { - pvr2_hdw_cpufw_set_enabled(hdw,0); + pvr2_hdw_cpufw_set_enabled(hdw,0,0); return 0; } else { return -EINVAL; diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h index ce66ab8ff2d..985d9ae7f5e 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h @@ -238,6 +238,7 @@ struct pvr2_hdw { // CPU firmware info (used to help find / save firmware data) char *fw_buffer; unsigned int fw_size; + int fw_cpu_flag; /* True if we are dealing with the CPU */ // Which subsystem pieces have been enabled / configured unsigned long subsys_enabled_mask; diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 5d9045268cf..7172f66a6a2 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -2605,7 +2605,85 @@ void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw) } while (0); LOCK_GIVE(hdw->big_lock); } -void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw, int enable_flag) + +/* Grab EEPROM contents, needed for direct method. */ +#define EEPROM_SIZE 8192 +#define trace_eeprom(...) pvr2_trace(PVR2_TRACE_EEPROM,__VA_ARGS__) +static u8 *pvr2_full_eeprom_fetch(struct pvr2_hdw *hdw) +{ + struct i2c_msg msg[2]; + u8 *eeprom; + u8 iadd[2]; + u8 addr; + u16 eepromSize; + unsigned int offs; + int ret; + int mode16 = 0; + unsigned pcnt,tcnt; + eeprom = kmalloc(EEPROM_SIZE,GFP_KERNEL); + if (!eeprom) { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "Failed to allocate memory" + " required to read eeprom"); + return NULL; + } + + trace_eeprom("Value for eeprom addr from controller was 0x%x", + hdw->eeprom_addr); + addr = hdw->eeprom_addr; + /* Seems that if the high bit is set, then the *real* eeprom + address is shifted right now bit position (noticed this in + newer PVR USB2 hardware) */ + if (addr & 0x80) addr >>= 1; + + /* FX2 documentation states that a 16bit-addressed eeprom is + expected if the I2C address is an odd number (yeah, this is + strange but it's what they do) */ + mode16 = (addr & 1); + eepromSize = (mode16 ? EEPROM_SIZE : 256); + trace_eeprom("Examining %d byte eeprom at location 0x%x" + " using %d bit addressing",eepromSize,addr, + mode16 ? 16 : 8); + + msg[0].addr = addr; + msg[0].flags = 0; + msg[0].len = mode16 ? 2 : 1; + msg[0].buf = iadd; + msg[1].addr = addr; + msg[1].flags = I2C_M_RD; + + /* We have to do the actual eeprom data fetch ourselves, because + (1) we're only fetching part of the eeprom, and (2) if we were + getting the whole thing our I2C driver can't grab it in one + pass - which is what tveeprom is otherwise going to attempt */ + memset(eeprom,0,EEPROM_SIZE); + for (tcnt = 0; tcnt < EEPROM_SIZE; tcnt += pcnt) { + pcnt = 16; + if (pcnt + tcnt > EEPROM_SIZE) pcnt = EEPROM_SIZE-tcnt; + offs = tcnt + (eepromSize - EEPROM_SIZE); + if (mode16) { + iadd[0] = offs >> 8; + iadd[1] = offs; + } else { + iadd[0] = offs; + } + msg[1].len = pcnt; + msg[1].buf = eeprom+tcnt; + if ((ret = i2c_transfer(&hdw->i2c_adap, + msg,ARRAY_SIZE(msg))) != 2) { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "eeprom fetch set offs err=%d",ret); + kfree(eeprom); + return NULL; + } + } + return eeprom; +} + + +void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw, + int prom_flag, + int enable_flag) { int ret; u16 address; @@ -2619,37 +2697,59 @@ void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw, int enable_flag) kfree(hdw->fw_buffer); hdw->fw_buffer = NULL; hdw->fw_size = 0; - /* Now release the CPU. It will disconnect and - reconnect later. */ - pvr2_hdw_cpureset_assert(hdw,0); + if (hdw->fw_cpu_flag) { + /* Now release the CPU. It will disconnect + and reconnect later. */ + pvr2_hdw_cpureset_assert(hdw,0); + } break; } - pvr2_trace(PVR2_TRACE_FIRMWARE, - "Preparing to suck out CPU firmware"); - hdw->fw_size = 0x2000; - hdw->fw_buffer = kzalloc(hdw->fw_size,GFP_KERNEL); - if (!hdw->fw_buffer) { - hdw->fw_size = 0; - break; - } + hdw->fw_cpu_flag = (prom_flag == 0); + if (hdw->fw_cpu_flag) { + pvr2_trace(PVR2_TRACE_FIRMWARE, + "Preparing to suck out CPU firmware"); + hdw->fw_size = 0x2000; + hdw->fw_buffer = kzalloc(hdw->fw_size,GFP_KERNEL); + if (!hdw->fw_buffer) { + hdw->fw_size = 0; + break; + } - /* We have to hold the CPU during firmware upload. */ - pvr2_hdw_cpureset_assert(hdw,1); + /* We have to hold the CPU during firmware upload. */ + pvr2_hdw_cpureset_assert(hdw,1); - /* download the firmware from address 0000-1fff in 2048 - (=0x800) bytes chunk. */ + /* download the firmware from address 0000-1fff in 2048 + (=0x800) bytes chunk. */ - pvr2_trace(PVR2_TRACE_FIRMWARE,"Grabbing CPU firmware"); - pipe = usb_rcvctrlpipe(hdw->usb_dev, 0); - for(address = 0; address < hdw->fw_size; address += 0x800) { - ret = usb_control_msg(hdw->usb_dev,pipe,0xa0,0xc0, - address,0, - hdw->fw_buffer+address,0x800,HZ); - if (ret < 0) break; - } + pvr2_trace(PVR2_TRACE_FIRMWARE, + "Grabbing CPU firmware"); + pipe = usb_rcvctrlpipe(hdw->usb_dev, 0); + for(address = 0; address < hdw->fw_size; + address += 0x800) { + ret = usb_control_msg(hdw->usb_dev,pipe, + 0xa0,0xc0, + address,0, + hdw->fw_buffer+address, + 0x800,HZ); + if (ret < 0) break; + } - pvr2_trace(PVR2_TRACE_FIRMWARE,"Done grabbing CPU firmware"); + pvr2_trace(PVR2_TRACE_FIRMWARE, + "Done grabbing CPU firmware"); + } else { + pvr2_trace(PVR2_TRACE_FIRMWARE, + "Sucking down EEPROM contents"); + hdw->fw_buffer = pvr2_full_eeprom_fetch(hdw); + if (!hdw->fw_buffer) { + pvr2_trace(PVR2_TRACE_FIRMWARE, + "EEPROM content suck failed."); + break; + } + hdw->fw_size = EEPROM_SIZE; + pvr2_trace(PVR2_TRACE_FIRMWARE, + "Done sucking down EEPROM contents"); + } } while (0); LOCK_GIVE(hdw->big_lock); } diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/drivers/media/video/pvrusb2/pvrusb2-hdw.h index 4dba8d00632..e2f9d5e4cb6 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.h +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.h @@ -197,11 +197,13 @@ void pvr2_hdw_subsys_stream_bit_chg(struct pvr2_hdw *hdw, unsigned long pvr2_hdw_subsys_stream_get(struct pvr2_hdw *); -/* Enable / disable retrieval of CPU firmware. This must be enabled before - pvr2_hdw_cpufw_get() will function. Note that doing this may prevent - the device from running (and leaving this mode may imply a device - reset). */ -void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *, int enable_flag); +/* Enable / disable retrieval of CPU firmware or prom contents. This must + be enabled before pvr2_hdw_cpufw_get() will function. Note that doing + this may prevent the device from running (and leaving this mode may + imply a device reset). */ +void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *, + int prom_flag, + int enable_flag); /* Return true if we're in a mode for retrieval CPU firmware */ int pvr2_hdw_cpufw_get_enabled(struct pvr2_hdw *); -- cgit v1.2.3-70-g09d2 From 1d643a372259749ce2029e386ed5760d5d7f8b89 Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sat, 8 Sep 2007 22:18:50 -0300 Subject: V4L/DVB (6209): pvrusb2: Better discriminate among device types This is a bunch of cleanup in various places to improve behavior based on actual device type being driven. While this doesn't actually affect operation with existing devices, it cleans things up so that it will be easier / more deterministic when other devices are added. Ideally we should make stuff like this table-driven, but for now this is just a series of small incremental (read: safe) improvements. Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-hdw.c | 82 ++++++++++++++++++++----------- 1 file changed, 54 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 7172f66a6a2..c8ee379159e 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -1143,6 +1143,13 @@ static int pvr2_upload_firmware1(struct pvr2_hdw *hdw) fw_files_24xxx, ARRAY_SIZE(fw_files_24xxx) }, }; + + if ((hdw->hdw_type >= ARRAY_SIZE(fw_file_defs)) || + (!fw_file_defs[hdw->hdw_type].lst)) { + hdw->fw1_state = FW1_STATE_OK; + return 0; + } + hdw->fw1_state = FW1_STATE_FAILED; // default result trace_firmware("pvr2_upload_firmware1"); @@ -1224,6 +1231,11 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw) CX2341X_FIRM_ENC_FILENAME, }; + if ((hdw->hdw_type != PVR2_HDW_TYPE_29XXX) && + (hdw->hdw_type != PVR2_HDW_TYPE_24XXX)) { + return 0; + } + trace_firmware("pvr2_upload_firmware2"); ret = pvr2_locate_firmware(hdw,&fw_entry,"encoder", @@ -1742,29 +1754,35 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw) unsigned int idx; struct pvr2_ctrl *cptr; int reloadFl = 0; - if (!reloadFl) { - reloadFl = (hdw->usb_intf->cur_altsetting->desc.bNumEndpoints - == 0); - if (reloadFl) { - pvr2_trace(PVR2_TRACE_INIT, - "USB endpoint config looks strange" - "; possibly firmware needs to be loaded"); + if ((hdw->hdw_type == PVR2_HDW_TYPE_29XXX) || + (hdw->hdw_type == PVR2_HDW_TYPE_24XXX)) { + if (!reloadFl) { + reloadFl = + (hdw->usb_intf->cur_altsetting->desc.bNumEndpoints + == 0); + if (reloadFl) { + pvr2_trace(PVR2_TRACE_INIT, + "USB endpoint config looks strange" + "; possibly firmware needs to be" + " loaded"); + } } - } - if (!reloadFl) { - reloadFl = !pvr2_hdw_check_firmware(hdw); - if (reloadFl) { - pvr2_trace(PVR2_TRACE_INIT, - "Check for FX2 firmware failed" - "; possibly firmware needs to be loaded"); + if (!reloadFl) { + reloadFl = !pvr2_hdw_check_firmware(hdw); + if (reloadFl) { + pvr2_trace(PVR2_TRACE_INIT, + "Check for FX2 firmware failed" + "; possibly firmware needs to be" + " loaded"); + } } - } - if (reloadFl) { - if (pvr2_upload_firmware1(hdw) != 0) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Failure uploading firmware1"); + if (reloadFl) { + if (pvr2_upload_firmware1(hdw) != 0) { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "Failure uploading firmware1"); + } + return; } - return; } hdw->fw1_state = FW1_STATE_OK; @@ -1773,17 +1791,25 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw) } if (!pvr2_hdw_dev_ok(hdw)) return; - for (idx = 0; idx < pvr2_client_lists[hdw->hdw_type].cnt; idx++) { - request_module(pvr2_client_lists[hdw->hdw_type].lst[idx]); + if (hdw->hdw_type < ARRAY_SIZE(pvr2_client_lists)) { + for (idx = 0; + idx < pvr2_client_lists[hdw->hdw_type].cnt; + idx++) { + request_module( + pvr2_client_lists[hdw->hdw_type].lst[idx]); + } } - pvr2_hdw_cmd_powerup(hdw); - if (!pvr2_hdw_dev_ok(hdw)) return; + if ((hdw->hdw_type == PVR2_HDW_TYPE_29XXX) || + (hdw->hdw_type == PVR2_HDW_TYPE_24XXX)) { + pvr2_hdw_cmd_powerup(hdw); + if (!pvr2_hdw_dev_ok(hdw)) return; - if (pvr2_upload_firmware2(hdw)){ - pvr2_trace(PVR2_TRACE_ERROR_LEGS,"device unstable!!"); - pvr2_hdw_render_useless(hdw); - return; + if (pvr2_upload_firmware2(hdw)){ + pvr2_trace(PVR2_TRACE_ERROR_LEGS,"device unstable!!"); + pvr2_hdw_render_useless(hdw); + return; + } } // This step MUST happen after the earlier powerup step. -- cgit v1.2.3-70-g09d2 From 9f66d4eac6be2428901ab6e0cbb6747d5b6794ef Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sat, 8 Sep 2007 22:28:51 -0300 Subject: V4L/DVB (6210): pvrusb2: Do a far better job at setting the default initial video standard The v4l tveeprom logic tells us what video standards are supported by the hardware, however it doesn't directly tell us what should be the preferred initial standard. For example "NTSC/NTSC-J" devices are reported by tveeprom as support NTSC-M and PAL-M, and while that might be true, in the vast majority of cases NTSC-M is really what the user is going to want. However the driver previously just arbitrarily picked the "lowest numbered" standard as the initial default, which in that case would have been PAL-M. (And making matters more confusing - this only caused real problems on 24xxx devices because the saa7115 on 29xxx seems to autodetect the right answer anyway.) This change implements an algorithm that uses the set of "supported" standards as a hint to decide on the initial standard. This algorithm ONLY comes into play if the driver isn't specifically told what to do; said another way - the user can always still change the standard via the sysfs interface, via the usual V4L methods, or even specified as a module parameter. The idea here is only to pick a better starting point if the user (or app) doesn't otherwise do something to set the standard; otherwise this change has no real impact. Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-hdw.c | 59 +++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index c8ee379159e..20dc573bc15 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -1694,6 +1694,44 @@ static int pvr2_hdw_check_firmware(struct pvr2_hdw *hdw) return result == 0; } +struct pvr2_std_hack { + v4l2_std_id pat; /* Pattern to match */ + v4l2_std_id msk; /* Which bits we care about */ + v4l2_std_id std; /* What additional standards or default to set */ +}; + +/* This data structure labels specific combinations of standards from + tveeprom that we'll try to recognize. If we recognize one, then assume + a specified default standard to use. This is here because tveeprom only + tells us about available standards not the intended default standard (if + any) for the device in question. We guess the default based on what has + been reported as available. Note that this is only for guessing a + default - which can always be overridden explicitly - and if the user + has otherwise named a default then that default will always be used in + place of this table. */ +const static struct pvr2_std_hack std_eeprom_maps[] = { + { /* PAL(B/G) */ + .pat = V4L2_STD_B|V4L2_STD_GH, + .std = V4L2_STD_PAL_B|V4L2_STD_PAL_B1|V4L2_STD_PAL_G, + }, + { /* NTSC(M) */ + .pat = V4L2_STD_MN, + .std = V4L2_STD_NTSC_M, + }, + { /* PAL(I) */ + .pat = V4L2_STD_PAL_I, + .std = V4L2_STD_PAL_I, + }, + { /* SECAM(L/L') */ + .pat = V4L2_STD_SECAM_L|V4L2_STD_SECAM_LC, + .std = V4L2_STD_SECAM_L|V4L2_STD_SECAM_LC, + }, + { /* PAL(D/D1/K) */ + .pat = V4L2_STD_DK, + .std = V4L2_STD_PAL_D/V4L2_STD_PAL_D1|V4L2_STD_PAL_K, + }, +}; + static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw) { char buf[40]; @@ -1732,6 +1770,27 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw) return; } + { + unsigned int idx; + for (idx = 0; idx < ARRAY_SIZE(std_eeprom_maps); idx++) { + if (std_eeprom_maps[idx].msk ? + ((std_eeprom_maps[idx].pat ^ + hdw->std_mask_eeprom) & + std_eeprom_maps[idx].msk) : + (std_eeprom_maps[idx].pat != + hdw->std_mask_eeprom)) continue; + bcnt = pvr2_std_id_to_str(buf,sizeof(buf), + std_eeprom_maps[idx].std); + pvr2_trace(PVR2_TRACE_INIT, + "Initial video standard guessed as %.*s", + bcnt,buf); + hdw->std_mask_cur = std_eeprom_maps[idx].std; + hdw->std_dirty = !0; + pvr2_hdw_internal_find_stdenum(hdw); + return; + } + } + if (hdw->std_enum_cnt > 1) { // Autoselect the first listed standard hdw->std_enum_cur = 1; -- cgit v1.2.3-70-g09d2 From 56585386e297c54a65feef55810c13b4313bdf1e Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sat, 8 Sep 2007 22:32:12 -0300 Subject: V4L/DVB (6211): pvrusb2: Allocate a debug mask bit for reporting video standard things It's useful to see specific details for how the pvrusb2 driver is figuring out things related to the video standard, independent of other initialization activities. So let's set up a separate debug mask bit for this and turn it on. Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-debug.h | 53 +++++++++++++++-------------- drivers/media/video/pvrusb2/pvrusb2-hdw.c | 10 +++--- drivers/media/video/pvrusb2/pvrusb2-main.c | 1 + drivers/media/video/pvrusb2/pvrusb2-std.c | 8 ++--- 4 files changed, 37 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/pvrusb2/pvrusb2-debug.h b/drivers/media/video/pvrusb2/pvrusb2-debug.h index d95a8588e4f..da6441b88f3 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-debug.h +++ b/drivers/media/video/pvrusb2/pvrusb2-debug.h @@ -26,32 +26,33 @@ extern int pvrusb2_debug; /* These are listed in *rough* order of decreasing usefulness and increasing noise level. */ -#define PVR2_TRACE_INFO (1 << 0) // Normal messages -#define PVR2_TRACE_ERROR_LEGS (1 << 1) // error messages -#define PVR2_TRACE_TOLERANCE (1 << 2) // track tolerance-affected errors -#define PVR2_TRACE_TRAP (1 << 3) // Trap & report misbehavior from app -#define PVR2_TRACE_INIT (1 << 4) // misc initialization steps -#define PVR2_TRACE_START_STOP (1 << 5) // Streaming start / stop -#define PVR2_TRACE_CTL (1 << 6) // commit of control changes -#define PVR2_TRACE_DEBUG (1 << 7) // Temporary debug code -#define PVR2_TRACE_EEPROM (1 << 8) // eeprom parsing / report -#define PVR2_TRACE_STRUCT (1 << 9) // internal struct creation -#define PVR2_TRACE_OPEN_CLOSE (1 << 10) // application open / close -#define PVR2_TRACE_CREG (1 << 11) // Main critical region entry / exit -#define PVR2_TRACE_SYSFS (1 << 12) // Sysfs driven I/O -#define PVR2_TRACE_FIRMWARE (1 << 13) // firmware upload actions -#define PVR2_TRACE_CHIPS (1 << 14) // chip broadcast operation -#define PVR2_TRACE_I2C (1 << 15) // I2C related stuff -#define PVR2_TRACE_I2C_CMD (1 << 16) // Software commands to I2C modules -#define PVR2_TRACE_I2C_CORE (1 << 17) // I2C core debugging -#define PVR2_TRACE_I2C_TRAF (1 << 18) // I2C traffic through the adapter -#define PVR2_TRACE_V4LIOCTL (1 << 19) // v4l ioctl details -#define PVR2_TRACE_ENCODER (1 << 20) // mpeg2 encoder operation -#define PVR2_TRACE_BUF_POOL (1 << 21) // Track buffer pool management -#define PVR2_TRACE_BUF_FLOW (1 << 22) // Track buffer flow in system -#define PVR2_TRACE_DATA_FLOW (1 << 23) // Track data flow -#define PVR2_TRACE_DEBUGIFC (1 << 24) // Debug interface actions -#define PVR2_TRACE_GPIO (1 << 25) // GPIO state bit changes +#define PVR2_TRACE_INFO (1 << 0) /* Normal messages */ +#define PVR2_TRACE_ERROR_LEGS (1 << 1) /* error messages */ +#define PVR2_TRACE_TOLERANCE (1 << 2) /* track tolerance-affected errors */ +#define PVR2_TRACE_TRAP (1 << 3) /* Trap & report app misbehavior */ +#define PVR2_TRACE_STD (1 << 4) /* Log video standard stuff */ +#define PVR2_TRACE_INIT (1 << 5) /* misc initialization steps */ +#define PVR2_TRACE_START_STOP (1 << 6) /* Streaming start / stop */ +#define PVR2_TRACE_CTL (1 << 7) /* commit of control changes */ +#define PVR2_TRACE_DEBUG (1 << 8) /* Temporary debug code */ +#define PVR2_TRACE_EEPROM (1 << 9) /* eeprom parsing / report */ +#define PVR2_TRACE_STRUCT (1 << 10) /* internal struct creation */ +#define PVR2_TRACE_OPEN_CLOSE (1 << 11) /* application open / close */ +#define PVR2_TRACE_CREG (1 << 12) /* Main critical region entry / exit */ +#define PVR2_TRACE_SYSFS (1 << 13) /* Sysfs driven I/O */ +#define PVR2_TRACE_FIRMWARE (1 << 14) /* firmware upload actions */ +#define PVR2_TRACE_CHIPS (1 << 15) /* chip broadcast operation */ +#define PVR2_TRACE_I2C (1 << 16) /* I2C related stuff */ +#define PVR2_TRACE_I2C_CMD (1 << 17) /* Software commands to I2C modules */ +#define PVR2_TRACE_I2C_CORE (1 << 18) /* I2C core debugging */ +#define PVR2_TRACE_I2C_TRAF (1 << 19) /* I2C traffic through the adapter */ +#define PVR2_TRACE_V4LIOCTL (1 << 20) /* v4l ioctl details */ +#define PVR2_TRACE_ENCODER (1 << 21) /* mpeg2 encoder operation */ +#define PVR2_TRACE_BUF_POOL (1 << 22) /* Track buffer pool management */ +#define PVR2_TRACE_BUF_FLOW (1 << 23) /* Track buffer flow in system */ +#define PVR2_TRACE_DATA_FLOW (1 << 24) /* Track data flow */ +#define PVR2_TRACE_DEBUGIFC (1 << 25) /* Debug interface actions */ +#define PVR2_TRACE_GPIO (1 << 26) /* GPIO state bit changes */ #endif /* __PVRUSB2_HDW_INTERNAL_H */ diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 20dc573bc15..eec83d6ae78 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -1741,7 +1741,7 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw) std1 = get_default_standard(hdw); bcnt = pvr2_std_id_to_str(buf,sizeof(buf),hdw->std_mask_eeprom); - pvr2_trace(PVR2_TRACE_INIT, + pvr2_trace(PVR2_TRACE_STD, "Supported video standard(s) reported by eeprom: %.*s", bcnt,buf); @@ -1750,7 +1750,7 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw) std2 = std1 & ~hdw->std_mask_avail; if (std2) { bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std2); - pvr2_trace(PVR2_TRACE_INIT, + pvr2_trace(PVR2_TRACE_STD, "Expanding supported video standards" " to include: %.*s", bcnt,buf); @@ -1761,7 +1761,7 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw) if (std1) { bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std1); - pvr2_trace(PVR2_TRACE_INIT, + pvr2_trace(PVR2_TRACE_STD, "Initial video standard forced to %.*s", bcnt,buf); hdw->std_mask_cur = std1; @@ -1781,7 +1781,7 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw) hdw->std_mask_eeprom)) continue; bcnt = pvr2_std_id_to_str(buf,sizeof(buf), std_eeprom_maps[idx].std); - pvr2_trace(PVR2_TRACE_INIT, + pvr2_trace(PVR2_TRACE_STD, "Initial video standard guessed as %.*s", bcnt,buf); hdw->std_mask_cur = std_eeprom_maps[idx].std; @@ -1796,7 +1796,7 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw) hdw->std_enum_cur = 1; hdw->std_mask_cur = hdw->std_defs[hdw->std_enum_cur-1].id; hdw->std_dirty = !0; - pvr2_trace(PVR2_TRACE_INIT, + pvr2_trace(PVR2_TRACE_STD, "Initial video standard auto-selected to %s", hdw->std_defs[hdw->std_enum_cur-1].name); return; diff --git a/drivers/media/video/pvrusb2/pvrusb2-main.c b/drivers/media/video/pvrusb2/pvrusb2-main.c index 1ea0939096a..ca9e2789c8c 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-main.c +++ b/drivers/media/video/pvrusb2/pvrusb2-main.c @@ -41,6 +41,7 @@ #define DEFAULT_DEBUG_MASK (PVR2_TRACE_ERROR_LEGS| \ PVR2_TRACE_INFO| \ + PVR2_TRACE_STD| \ PVR2_TRACE_TOLERANCE| \ PVR2_TRACE_TRAP| \ 0) diff --git a/drivers/media/video/pvrusb2/pvrusb2-std.c b/drivers/media/video/pvrusb2/pvrusb2-std.c index 81de26ba41d..63e55bb59fc 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-std.c +++ b/drivers/media/video/pvrusb2/pvrusb2-std.c @@ -298,7 +298,7 @@ static int pvr2_std_fill(struct v4l2_standard *std,v4l2_std_id id) std->id = id; bcnt = pvr2_std_id_to_str(std->name,sizeof(std->name)-1,id); std->name[bcnt] = 0; - pvr2_trace(PVR2_TRACE_INIT,"Set up standard idx=%u name=%s", + pvr2_trace(PVR2_TRACE_STD,"Set up standard idx=%u name=%s", std->index,std->name); return !0; } @@ -320,11 +320,11 @@ struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr, v4l2_std_id idmsk,cmsk,fmsk; struct v4l2_standard *stddefs; - if (pvrusb2_debug & PVR2_TRACE_INIT) { + if (pvrusb2_debug & PVR2_TRACE_STD) { char buf[50]; bcnt = pvr2_std_id_to_str(buf,sizeof(buf),id); pvr2_trace( - PVR2_TRACE_INIT,"Mapping standards mask=0x%x (%.*s)", + PVR2_TRACE_STD,"Mapping standards mask=0x%x (%.*s)", (int)id,bcnt,buf); } @@ -355,7 +355,7 @@ struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr, bcnt,buf); } - pvr2_trace(PVR2_TRACE_INIT,"Setting up %u unique standard(s)", + pvr2_trace(PVR2_TRACE_STD,"Setting up %u unique standard(s)", std_cnt); if (!std_cnt) return NULL; // paranoia -- cgit v1.2.3-70-g09d2 From 7fb0dfc853735ccf4e580b0d71510bad96d37c4f Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sat, 8 Sep 2007 23:19:32 -0300 Subject: V4L/DVB (6212): pvrusb2: I2C adapter tweaks from Jean Delvare * I2C adapters aren't expected to handle I2C_M_NOSTART unless they really have to. As the pvrusb2 driver doesn't support it, I take it that it doesn't need it so it shouldn't mention it at all. * I2C_FUNC_SMBUS_EMUL includes I2C_FUNC_SMBUS_BYTE_DATA so listing both is redundant. Signed-off-by: Jean Delvare Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-i2c-core.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c index 6786d3c0c98..7697f391e8b 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c +++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c @@ -389,10 +389,6 @@ static int pvr2_i2c_xfer(struct i2c_adapter *i2c_adap, ret = -EINVAL; goto done; } - if ((msgs[0].flags & I2C_M_NOSTART)) { - trace_i2c("i2c refusing I2C_M_NOSTART"); - goto done; - } if (msgs[0].addr < PVR2_I2C_FUNC_CNT) { funcp = hdw->i2c_func[msgs[0].addr]; } @@ -494,14 +490,12 @@ static int pvr2_i2c_xfer(struct i2c_adapter *i2c_adap, cnt = msgs[idx].len; printk(KERN_INFO "pvrusb2 i2c xfer %u/%u:" - " addr=0x%x len=%d %s%s", + " addr=0x%x len=%d %s", idx+1,num, msgs[idx].addr, cnt, (msgs[idx].flags & I2C_M_RD ? - "read" : "write"), - (msgs[idx].flags & I2C_M_NOSTART ? - " nostart" : "")); + "read" : "write")); if ((ret > 0) || !(msgs[idx].flags & I2C_M_RD)) { if (cnt > 8) cnt = 8; printk(" ["); @@ -534,7 +528,7 @@ static int pvr2_i2c_control(struct i2c_adapter *adapter, static u32 pvr2_i2c_functionality(struct i2c_adapter *adap) { - return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C | I2C_FUNC_SMBUS_BYTE_DATA; + return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C; } static int pvr2_i2c_core_singleton(struct i2c_client *cp, -- cgit v1.2.3-70-g09d2 From 39f46adef8e83653b4716369683c134e1413ad30 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 9 Sep 2007 06:17:44 -0300 Subject: V4L/DVB (6214): usbvision: Don't support I2C_M_REV_DIR_ADDR I2C adapters should only support I2C_M_REV_DIR_ADDR if they really have to (i.e. if they are connected to a broken I2C device which needs this deviation from the standard I2C protocol.) As no media chip driver uses I2C_M_REV_DIR_ADDR, I don't think that the usbvision driver needs to support it. Signed-off-by: Jean Delvare Acked-by: Thierry Merle Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/usbvision/usbvision-i2c.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/usbvision/usbvision-i2c.c b/drivers/media/video/usbvision/usbvision-i2c.c index 025be555194..c66aef63916 100644 --- a/drivers/media/video/usbvision/usbvision-i2c.c +++ b/drivers/media/video/usbvision/usbvision-i2c.c @@ -134,8 +134,6 @@ static inline int usb_find_address(struct i2c_adapter *i2c_adap, addr = (msg->addr << 1); if (flags & I2C_M_RD) addr |= 1; - if (flags & I2C_M_REV_DIR_ADDR) - addr ^= 1; add[0] = addr; if (flags & I2C_M_RD) @@ -192,7 +190,7 @@ static int algo_control(struct i2c_adapter *adapter, unsigned int cmd, unsigned static u32 functionality(struct i2c_adapter *adap) { - return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING; + return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR; } -- cgit v1.2.3-70-g09d2 From 588005e1008f2cea61b7a1ae2a86c531e99b8c9c Mon Sep 17 00:00:00 2001 From: Hans-Jürgen Koch Date: Wed, 12 Sep 2007 16:20:43 -0300 Subject: V4L/DVB (6215): Bugfix for saa6588.c, add forgotten spin_lock_init() There's a serious bug in saa6588.c, it uses a non-initialized spin_lock. Funny thing is that it works fine with bttv, but completly freezes the machine if e.g. saa7134 is loaded. Thanks to Derek Philip for reporting this bug on the rdsd-devel list. This patch adds the missing spin_lock_init(). Signed-off-by: Hans J. Koch Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa6588.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/video/saa6588.c b/drivers/media/video/saa6588.c index 92eabf88a09..72e344a12c7 100644 --- a/drivers/media/video/saa6588.c +++ b/drivers/media/video/saa6588.c @@ -406,6 +406,7 @@ static int saa6588_attach(struct i2c_adapter *adap, int addr, int kind) kfree(s); return -ENOMEM; } + spin_lock_init(&s->lock); s->client = client_template; s->block_count = 0; s->wr_index = 0; -- cgit v1.2.3-70-g09d2 From 098c645e39e10dc580763b5ea4bd4fb390013474 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 30 Aug 2007 09:20:38 -0300 Subject: V4L/DVB (6216): V4L: Int if: add vidioc_int_g_ifparm, other updates vidioc_int_g_ifparm can be used to obtain hardware-specific information about the interface used by the slave. Rearrange v4l2-int-device.h as well. Also remove useless & characters. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-int-device.c | 4 +- include/media/v4l2-int-device.h | 130 ++++++++++++++++++++-------------- 2 files changed, 80 insertions(+), 54 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/v4l2-int-device.c b/drivers/media/video/v4l2-int-device.c index a643730fa3b..7ad8700ebde 100644 --- a/drivers/media/video/v4l2-int-device.c +++ b/drivers/media/video/v4l2-int-device.c @@ -150,7 +150,7 @@ int v4l2_int_ioctl_0(struct v4l2_int_device *d, int cmd) { return ((v4l2_int_ioctl_func_0 *) find_ioctl(d->u.slave, cmd, - (v4l2_int_ioctl_func *)&no_such_ioctl_0))(d); + (v4l2_int_ioctl_func *)no_such_ioctl_0))(d); } static int no_such_ioctl_1(struct v4l2_int_device *d, void *arg) @@ -162,5 +162,5 @@ int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg) { return ((v4l2_int_ioctl_func_1 *) find_ioctl(d->u.slave, cmd, - (v4l2_int_ioctl_func *)&no_such_ioctl_1))(d, arg); + (v4l2_int_ioctl_func *)no_such_ioctl_1))(d, arg); } diff --git a/include/media/v4l2-int-device.h b/include/media/v4l2-int-device.h index deb28ce6685..861978deb3b 100644 --- a/include/media/v4l2-int-device.h +++ b/include/media/v4l2-int-device.h @@ -30,11 +30,84 @@ #define V4L2NAMESIZE 32 +/* + * + * The internal V4L2 device interface core. + * + */ + enum v4l2_int_type { v4l2_int_type_master = 1, v4l2_int_type_slave }; +struct v4l2_int_device; + +struct v4l2_int_master { + int (*attach)(struct v4l2_int_device *master, + struct v4l2_int_device *slave); + void (*detach)(struct v4l2_int_device *master); +}; + +typedef int (v4l2_int_ioctl_func)(struct v4l2_int_device *); +typedef int (v4l2_int_ioctl_func_0)(struct v4l2_int_device *); +typedef int (v4l2_int_ioctl_func_1)(struct v4l2_int_device *, void *); + +struct v4l2_int_ioctl_desc { + int num; + v4l2_int_ioctl_func *func; +}; + +struct v4l2_int_slave { + /* Don't touch master. */ + struct v4l2_int_device *master; + + char attach_to[V4L2NAMESIZE]; + + int num_ioctls; + struct v4l2_int_ioctl_desc *ioctls; +}; + +struct v4l2_int_device { + /* Don't touch head. */ + struct list_head head; + + struct module *module; + + char name[V4L2NAMESIZE]; + + enum v4l2_int_type type; + union { + struct v4l2_int_master *master; + struct v4l2_int_slave *slave; + } u; + + void *priv; +}; + +int v4l2_int_device_register(struct v4l2_int_device *d); +void v4l2_int_device_unregister(struct v4l2_int_device *d); + +int v4l2_int_ioctl_0(struct v4l2_int_device *d, int cmd); +int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg); + +/* + * + * Types and definitions for IOCTL commands. + * + */ + +/* Slave interface type. */ +enum v4l2_if_type { +}; + +struct v4l2_ifparm { + enum v4l2_if_type if_type; + union { + } u; +}; + +/* IOCTL command numbers. */ enum v4l2_int_ioctl_num { /* * @@ -62,10 +135,12 @@ enum v4l2_int_ioctl_num { vidioc_int_dev_exit_num, /* Set device power state: 0 is off, non-zero is on. */ vidioc_int_s_power_num, - /* Get parallel interface clock speed for current settings. */ + /* Get slave interface parameters. */ + vidioc_int_g_ifparm_num, + /* Get external clock speed for current slave settings. */ vidioc_int_g_ext_clk_num, /* - * Tell what the parallel interface clock speed actually is. + * Tell what the generated interface clock speed actually is. */ vidioc_int_s_ext_clk_num, /* Does the slave need to be reset after VIDIOC_DQBUF? */ @@ -91,56 +166,6 @@ enum v4l2_int_ioctl_num { vidioc_int_priv_start_num = 2000, }; -struct v4l2_int_device; - -struct v4l2_int_master { - int (*attach)(struct v4l2_int_device *master, - struct v4l2_int_device *slave); - void (*detach)(struct v4l2_int_device *master); -}; - -typedef int (v4l2_int_ioctl_func)(struct v4l2_int_device *); -typedef int (v4l2_int_ioctl_func_0)(struct v4l2_int_device *); -typedef int (v4l2_int_ioctl_func_1)(struct v4l2_int_device *, void *); - -struct v4l2_int_ioctl_desc { - int num; - v4l2_int_ioctl_func *func; -}; - -struct v4l2_int_slave { - /* Don't touch master. */ - struct v4l2_int_device *master; - - char attach_to[V4L2NAMESIZE]; - - int num_ioctls; - struct v4l2_int_ioctl_desc *ioctls; -}; - -struct v4l2_int_device { - /* Don't touch head. */ - struct list_head head; - - struct module *module; - - char name[V4L2NAMESIZE]; - - enum v4l2_int_type type; - union { - struct v4l2_int_master *master; - struct v4l2_int_slave *slave; - } u; - - void *priv; -}; - -int v4l2_int_device_register(struct v4l2_int_device *d); -void v4l2_int_device_unregister(struct v4l2_int_device *d); - -int v4l2_int_ioctl_0(struct v4l2_int_device *d, int cmd); -int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg); - /* * * IOCTL wrapper functions for better type checking. @@ -199,6 +224,7 @@ V4L2_INT_WRAPPER_1(s_parm, struct v4l2_streamparm, *); V4L2_INT_WRAPPER_0(dev_init); V4L2_INT_WRAPPER_0(dev_exit); V4L2_INT_WRAPPER_1(s_power, int, ); +V4L2_INT_WRAPPER_1(g_ifparm, struct v4l2_ifparm, *); V4L2_INT_WRAPPER_1(s_ext_clk, u32, ); V4L2_INT_WRAPPER_1(g_ext_clk, u32, *); V4L2_INT_WRAPPER_1(g_needs_reset, void, *); -- cgit v1.2.3-70-g09d2 From 61c310dc1e2a34bced25b4fa7609316d6755ccc2 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 30 Aug 2007 09:20:40 -0300 Subject: V4L/DVB (6218): V4L: Int if: Use -ENOIOCTLCMD for nonexistent ioctls Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-int-device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/v4l2-int-device.c b/drivers/media/video/v4l2-int-device.c index 7ad8700ebde..f497c945834 100644 --- a/drivers/media/video/v4l2-int-device.c +++ b/drivers/media/video/v4l2-int-device.c @@ -143,7 +143,7 @@ static v4l2_int_ioctl_func *find_ioctl(struct v4l2_int_slave *slave, int cmd, static int no_such_ioctl_0(struct v4l2_int_device *d) { - return -EINVAL; + return -ENOIOCTLCMD; } int v4l2_int_ioctl_0(struct v4l2_int_device *d, int cmd) @@ -155,7 +155,7 @@ int v4l2_int_ioctl_0(struct v4l2_int_device *d, int cmd) static int no_such_ioctl_1(struct v4l2_int_device *d, void *arg) { - return -EINVAL; + return -ENOIOCTLCMD; } int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg) -- cgit v1.2.3-70-g09d2 From 2060955748dff6280cd211b68c92d9a99d1c78f9 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 30 Aug 2007 09:20:42 -0300 Subject: V4L/DVB (6220): TCM825x: Add support for vidioc_int_g_ifparm call, small cleanups vidioc_int_g_ifparm returns platform-specific information about the interface settings used by the sensor. Support for [gs]_ext_clk has been removed. Fix indentation and remove useless & characters. Remove experiment for typechecking slave callback function arguments. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tcm825x.c | 128 +++++++++++++++++++----------------------- drivers/media/video/tcm825x.h | 4 ++ 2 files changed, 61 insertions(+), 71 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/tcm825x.c b/drivers/media/video/tcm825x.c index 3a139f288a9..41cd6a0b048 100644 --- a/drivers/media/video/tcm825x.c +++ b/drivers/media/video/tcm825x.c @@ -470,46 +470,6 @@ static int tcm825x_configure(struct v4l2_int_device *s) return 0; } -/* - * Given the image capture format in pix, the nominal frame period in - * timeperframe, calculate the required xclk frequency. - * - * TCM825X input frequency characteristics are: - * Minimum 11.9 MHz, Typical 24.57 MHz and maximum 25/27 MHz - */ -#define XCLK_MIN 11900000 -#define XCLK_MAX 25000000 - -static int ioctl_g_ext_clk(struct v4l2_int_device *s, u32 *xclk) -{ - struct tcm825x_sensor *sensor = s->priv; - struct v4l2_fract *timeperframe = &sensor->timeperframe; - u32 tgt_xclk; /* target xclk */ - u32 tgt_fps; /* target frames per secound */ - - tgt_fps = timeperframe->denominator / timeperframe->numerator; - - tgt_xclk = (tgt_fps <= HIGH_FPS_MODE_LOWER_LIMIT) ? - (2457 * tgt_fps) / MAX_HALF_FPS : - (2457 * tgt_fps) / MAX_FPS; - tgt_xclk *= 10000; - - tgt_xclk = min(tgt_xclk, (u32)XCLK_MAX); - tgt_xclk = max(tgt_xclk, (u32)XCLK_MIN); - - *xclk = tgt_xclk; - - return 0; -} - -static int ioctl_s_ext_clk(struct v4l2_int_device *s, u32 xclk) -{ - if (xclk > XCLK_MAX || xclk < XCLK_MIN) - return -EINVAL; - - return 0; -} - static int ioctl_queryctrl(struct v4l2_int_device *s, struct v4l2_queryctrl *qc) { @@ -756,6 +716,41 @@ static int ioctl_s_power(struct v4l2_int_device *s, int on) return sensor->platform_data->power_set(on); } +/* + * Given the image capture format in pix, the nominal frame period in + * timeperframe, calculate the required xclk frequency. + * + * TCM825X input frequency characteristics are: + * Minimum 11.9 MHz, Typical 24.57 MHz and maximum 25/27 MHz + */ + +static int ioctl_g_ifparm(struct v4l2_int_device *s, struct v4l2_ifparm *p) +{ + struct tcm825x_sensor *sensor = s->priv; + struct v4l2_fract *timeperframe = &sensor->timeperframe; + u32 tgt_xclk; /* target xclk */ + u32 tgt_fps; /* target frames per secound */ + int rval; + + rval = sensor->platform_data->ifparm(p); + if (rval) + return rval; + + tgt_fps = timeperframe->denominator / timeperframe->numerator; + + tgt_xclk = (tgt_fps <= HIGH_FPS_MODE_LOWER_LIMIT) ? + (2457 * tgt_fps) / MAX_HALF_FPS : + (2457 * tgt_fps) / MAX_FPS; + tgt_xclk *= 10000; + + tgt_xclk = min(tgt_xclk, (u32)TCM825X_XCLK_MAX); + tgt_xclk = max(tgt_xclk, (u32)TCM825X_XCLK_MIN); + + p->u.bt656.clock_curr = tgt_xclk; + + return 0; +} + static int ioctl_g_needs_reset(struct v4l2_int_device *s, void *buf) { struct tcm825x_sensor *sensor = s->priv; @@ -793,43 +788,39 @@ static int ioctl_dev_init(struct v4l2_int_device *s) return 0; } -#define NUM_IOCTLS 17 - -static struct v4l2_int_ioctl_desc tcm825x_ioctl_desc[NUM_IOCTLS] = { +static struct v4l2_int_ioctl_desc tcm825x_ioctl_desc[] = { { vidioc_int_dev_init_num, - (v4l2_int_ioctl_func *)&ioctl_dev_init }, + (v4l2_int_ioctl_func *)ioctl_dev_init }, { vidioc_int_dev_exit_num, - (v4l2_int_ioctl_func *)&ioctl_dev_exit }, + (v4l2_int_ioctl_func *)ioctl_dev_exit }, { vidioc_int_s_power_num, - (v4l2_int_ioctl_func *)&ioctl_s_power }, - { vidioc_int_g_ext_clk_num, - (v4l2_int_ioctl_func *)&ioctl_g_ext_clk }, - { vidioc_int_s_ext_clk_num, - (v4l2_int_ioctl_func *)&ioctl_s_ext_clk }, + (v4l2_int_ioctl_func *)ioctl_s_power }, + { vidioc_int_g_ifparm_num, + (v4l2_int_ioctl_func *)ioctl_g_ifparm }, { vidioc_int_g_needs_reset_num, - (v4l2_int_ioctl_func *)&ioctl_g_needs_reset }, + (v4l2_int_ioctl_func *)ioctl_g_needs_reset }, { vidioc_int_reset_num, - (v4l2_int_ioctl_func *)&ioctl_reset }, + (v4l2_int_ioctl_func *)ioctl_reset }, { vidioc_int_init_num, - (v4l2_int_ioctl_func *)&ioctl_init }, + (v4l2_int_ioctl_func *)ioctl_init }, { vidioc_int_enum_fmt_cap_num, - (v4l2_int_ioctl_func *)&ioctl_enum_fmt_cap }, + (v4l2_int_ioctl_func *)ioctl_enum_fmt_cap }, { vidioc_int_try_fmt_cap_num, - (v4l2_int_ioctl_func *)&ioctl_try_fmt_cap }, + (v4l2_int_ioctl_func *)ioctl_try_fmt_cap }, { vidioc_int_g_fmt_cap_num, - (v4l2_int_ioctl_func *)&ioctl_g_fmt_cap }, + (v4l2_int_ioctl_func *)ioctl_g_fmt_cap }, { vidioc_int_s_fmt_cap_num, - (v4l2_int_ioctl_func *)&ioctl_s_fmt_cap }, + (v4l2_int_ioctl_func *)ioctl_s_fmt_cap }, { vidioc_int_g_parm_num, - (v4l2_int_ioctl_func *)&ioctl_g_parm }, + (v4l2_int_ioctl_func *)ioctl_g_parm }, { vidioc_int_s_parm_num, - (v4l2_int_ioctl_func *)&ioctl_s_parm }, + (v4l2_int_ioctl_func *)ioctl_s_parm }, { vidioc_int_queryctrl_num, - (v4l2_int_ioctl_func *)&ioctl_queryctrl }, + (v4l2_int_ioctl_func *)ioctl_queryctrl }, { vidioc_int_g_ctrl_num, - (v4l2_int_ioctl_func *)&ioctl_g_ctrl }, + (v4l2_int_ioctl_func *)ioctl_g_ctrl }, { vidioc_int_s_ctrl_num, - (v4l2_int_ioctl_func *)&ioctl_s_ctrl }, + (v4l2_int_ioctl_func *)ioctl_s_ctrl }, }; static struct v4l2_int_slave tcm825x_slave = { @@ -894,16 +885,16 @@ static int __exit tcm825x_remove(struct i2c_client *client) } static struct i2c_driver tcm825x_i2c_driver = { - .driver = { + .driver = { .name = TCM825X_NAME, }, - .probe = &tcm825x_probe, - .remove = __exit_p(&tcm825x_remove), + .probe = tcm825x_probe, + .remove = __exit_p(tcm825x_remove), }; static struct tcm825x_sensor tcm825x = { .timeperframe = { - .numerator = 1, + .numerator = 1, .denominator = DEFAULT_FPS, }, }; @@ -911,11 +902,6 @@ static struct tcm825x_sensor tcm825x = { static int __init tcm825x_init(void) { int rval; - int i = 0; - - /* Just an experiment --- don't use *_cb functions yet. */ - tcm825x_ioctl_desc[i++] = vidioc_int_dev_init_cb(&ioctl_dev_init); - BUG_ON(i >= NUM_IOCTLS); rval = i2c_add_driver(&tcm825x_i2c_driver); if (rval) diff --git a/drivers/media/video/tcm825x.h b/drivers/media/video/tcm825x.h index d6471ec40bc..966765b66b3 100644 --- a/drivers/media/video/tcm825x.h +++ b/drivers/media/video/tcm825x.h @@ -163,6 +163,9 @@ enum pixel_format { YUV422 = 0, RGB565 }; #define NUM_IMAGE_SIZES 6 #define NUM_PIXEL_FORMATS 2 +#define TCM825X_XCLK_MIN 11900000 +#define TCM825X_XCLK_MAX 25000000 + struct capture_size { unsigned long width; unsigned long height; @@ -178,6 +181,7 @@ struct tcm825x_platform_data { const struct tcm825x_reg *(*default_regs)(void); int (*needs_reset)(struct v4l2_int_device *s, void *buf, struct v4l2_pix_format *fmt); + int (*ifparm)(struct v4l2_ifparm *p); }; /* Array of image sizes supported by TCM825X. These must be ordered from -- cgit v1.2.3-70-g09d2 From f64899ca5af69c33a446d355609831fad6f715cd Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Mon, 17 Sep 2007 22:17:12 -0300 Subject: V4L/DVB (6221): budget-ci: select TT keymap for DVB-S TT 1500 DVB-S TT 1500 must use the TT keymap. Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ttpci/budget-ci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c index 873c3ba296f..509349211d4 100644 --- a/drivers/media/dvb/ttpci/budget-ci.c +++ b/drivers/media/dvb/ttpci/budget-ci.c @@ -214,7 +214,6 @@ static int msp430_ir_init(struct budget_ci *budget_ci) case 0x100f: case 0x1011: case 0x1012: - case 0x1017: /* The hauppauge keymap is a superset of these remotes */ ir_input_init(input_dev, &budget_ci->ir.state, IR_TYPE_RC5, ir_codes_hauppauge_new); @@ -225,6 +224,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci) budget_ci->ir.rc5_device = rc5_device; break; case 0x1010: + case 0x1017: /* for the Technotrend 1500 bundled remote */ ir_input_init(input_dev, &budget_ci->ir.state, IR_TYPE_RC5, ir_codes_tt_1500); -- cgit v1.2.3-70-g09d2 From c8e2f07be0ac536c110702ed741c7bc6836e3438 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 15 Sep 2007 18:45:10 -0300 Subject: V4L/DVB (6222): select DVB_PLL if !DVB_FE_CUSTOMISE for FusionHDTV5 Express VIDEO_CX23885 must select DVB_PLL if !DVB_FE_CUSTOMISE for FusionHDTV5 Express Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig index 333dd29d44b..45345fc189e 100644 --- a/drivers/media/video/cx23885/Kconfig +++ b/drivers/media/video/cx23885/Kconfig @@ -11,6 +11,7 @@ config VIDEO_CX23885 select VIDEO_BUF_DVB select DVB_TUNER_MT2131 if !DVB_FE_CUSTOMISE select DVB_S5H1409 if !DVB_FE_CUSTOMISE + select DVB_PLL if !DVB_FE_CUSTOMISE ---help--- This is a video4linux driver for Conexant 23885 based TV cards. -- cgit v1.2.3-70-g09d2 From 0e789d7ffafbfd44f7fb2bdbf1138547d8abc231 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 18 Sep 2007 13:25:45 -0300 Subject: V4L/DVB (6224): VIDEO_CX23885 depends on DVB_CORE Fix the following dependency issue: ERROR: "dvb_dmx_init" [drivers/media/video/video-buf-dvb.ko] undefined! ERROR: "dvb_unregister_adapter" [drivers/media/video/video-buf-dvb.ko] undefined! ERROR: "dvb_register_frontend" [drivers/media/video/video-buf-dvb.ko] undefined! ERROR: "dvb_unregister_frontend" [drivers/media/video/video-buf-dvb.ko] undefined! ERROR: "dvb_net_release" [drivers/media/video/video-buf-dvb.ko] undefined! ERROR: "dvb_frontend_detach" [drivers/media/video/video-buf-dvb.ko] undefined! ERROR: "dvb_dmxdev_release" [drivers/media/video/video-buf-dvb.ko] undefined! ERROR: "dvb_dmx_swfilter" [drivers/media/video/video-buf-dvb.ko] undefined! ERROR: "dvb_net_init" [drivers/media/video/video-buf-dvb.ko] undefined! ERROR: "dvb_dmx_release" [drivers/media/video/video-buf-dvb.ko] undefined! ERROR: "dvb_register_adapter" [drivers/media/video/video-buf-dvb.ko] undefined! ERROR: "dvb_dmxdev_init" [drivers/media/video/video-buf-dvb.ko] undefined! ERROR: "mt2131_attach" [drivers/media/video/cx23885/cx23885.ko] undefined! ERROR: "s5h1409_attach" [drivers/media/video/cx23885/cx23885.ko] undefined! Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig index 45345fc189e..ebfcc7c2a89 100644 --- a/drivers/media/video/cx23885/Kconfig +++ b/drivers/media/video/cx23885/Kconfig @@ -1,6 +1,6 @@ config VIDEO_CX23885 tristate "Conexant cx23885 (2388x successor) support" - depends on VIDEO_DEV && PCI && I2C + depends on DVB_CORE && VIDEO_DEV && PCI && I2C select I2C_ALGOBIT select FW_LOADER select VIDEO_BTCX -- cgit v1.2.3-70-g09d2 From f438d97447d4ccd241db8477f62a0647b9e8220e Mon Sep 17 00:00:00 2001 From: Stas Sergeev Date: Mon, 17 Sep 2007 15:34:09 -0300 Subject: V4L/DVB (6225): AverTV Studio 307 has only one composite input AverTV Studio 307 has only one composite input. Signed-off-by: Stas Sergeev Acked-by: Nickolay V. Shmyrev Signed-off-by: Andrew Morton Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-cards.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index c4dc9868c48..6b6eae82bcf 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -32,6 +32,7 @@ static char name_mute[] = "mute"; static char name_radio[] = "Radio"; static char name_tv[] = "Television"; static char name_tv_mono[] = "TV (mono only)"; +static char name_comp[] = "Composite"; static char name_comp1[] = "Composite1"; static char name_comp2[] = "Composite2"; static char name_comp3[] = "Composite3"; @@ -1535,12 +1536,7 @@ struct saa7134_board saa7134_boards[] = { .tv = 1, .gpio = 0x00, },{ - .name = name_comp1, - .vmux = 0, - .amux = LINE1, - .gpio = 0x02, - },{ - .name = name_comp2, + .name = name_comp, .vmux = 3, .amux = LINE1, .gpio = 0x02, -- cgit v1.2.3-70-g09d2 From 5d7802b2617d785ea0b8631b0605defc19ee6561 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 7 Sep 2007 18:03:58 -0300 Subject: V4L/DVB (6226): dvb-pll: pass fe pointer into dvb_pll_configure() and set() functions The pll-specific set() function will need access to the dvb_pll_priv structure for new functionality. This patch gives access to this structure to the required functions. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/dvb-pll.c | 36 ++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index 11f7d5939bd..59ae4ece65a 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -29,7 +29,8 @@ struct dvb_pll_desc { u32 min; u32 max; u32 iffreq; - void (*set)(u8 *buf, const struct dvb_frontend_parameters *params); + void (*set)(struct dvb_frontend *fe, u8 *buf, + const struct dvb_frontend_parameters *params); u8 *initdata; u8 *sleepdata; int count; @@ -89,7 +90,7 @@ static struct dvb_pll_desc dvb_pll_thomson_dtt7610 = { }, }; -static void thomson_dtt759x_bw(u8 *buf, +static void thomson_dtt759x_bw(struct dvb_frontend *fe, u8 *buf, const struct dvb_frontend_parameters *params) { if (BANDWIDTH_7_MHZ == params->u.ofdm.bandwidth) @@ -210,7 +211,8 @@ static struct dvb_pll_desc dvb_pll_env57h1xd5 = { /* Philips TDA6650/TDA6651 * used in Panasonic ENV77H11D5 */ -static void tda665x_bw(u8 *buf, const struct dvb_frontend_parameters *params) +static void tda665x_bw(struct dvb_frontend *fe, u8 *buf, + const struct dvb_frontend_parameters *params) { if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) buf[3] |= 0x08; @@ -243,7 +245,8 @@ static struct dvb_pll_desc dvb_pll_tda665x = { /* Infineon TUA6034 * used in LG TDTP E102P */ -static void tua6034_bw(u8 *buf, const struct dvb_frontend_parameters *params) +static void tua6034_bw(struct dvb_frontend *fe, u8 *buf, + const struct dvb_frontend_parameters *params) { if (BANDWIDTH_7_MHZ != params->u.ofdm.bandwidth) buf[3] |= 0x08; @@ -283,7 +286,8 @@ static struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf = { /* Philips FMD1216ME * used in Medion Hybrid PCMCIA card and USB Box */ -static void fmd1216me_bw(u8 *buf, const struct dvb_frontend_parameters *params) +static void fmd1216me_bw(struct dvb_frontend *fe, u8 *buf, + const struct dvb_frontend_parameters *params) { if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ && params->frequency >= 158870000) @@ -313,7 +317,8 @@ static struct dvb_pll_desc dvb_pll_fmd1216me = { /* ALPS TDED4 * used in Nebula-Cards and USB boxes */ -static void tded4_bw(u8 *buf, const struct dvb_frontend_parameters *params) +static void tded4_bw(struct dvb_frontend *fe, u8 *buf, + const struct dvb_frontend_parameters *params) { if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) buf[3] |= 0x04; @@ -354,7 +359,8 @@ static struct dvb_pll_desc dvb_pll_tdhu2 = { /* Philips TUV1236D * used in ATI HDTV Wonder */ -static void tuv1236d_rf(u8 *buf, const struct dvb_frontend_parameters *params) +static void tuv1236d_rf(struct dvb_frontend *fe, u8 *buf, + const struct dvb_frontend_parameters *params) { switch (params->u.vsb.modulation) { case QAM_64: @@ -420,7 +426,8 @@ static struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = { /* * Philips TD1316 Tuner. */ -static void td1316_bw(u8 *buf, const struct dvb_frontend_parameters *params) +static void td1316_bw(struct dvb_frontend *fe, u8 *buf, + const struct dvb_frontend_parameters *params) { u8 band; @@ -474,7 +481,8 @@ static struct dvb_pll_desc dvb_pll_thomson_fe6600 = { } }; -static void opera1_bw(u8 *buf, const struct dvb_frontend_parameters *params) +static void opera1_bw(struct dvb_frontend *fe, u8 *buf, + const struct dvb_frontend_parameters *params) { if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) buf[2] |= 0x08; @@ -567,9 +575,11 @@ static int debug = 0; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "enable verbose debug messages"); -static int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf, +static int dvb_pll_configure(struct dvb_frontend *fe, u8 *buf, const struct dvb_frontend_parameters *params) { + struct dvb_pll_priv *priv = fe->tuner_priv; + struct dvb_pll_desc *desc = priv->pll_desc; u32 div; int i; @@ -597,7 +607,7 @@ static int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf, buf[3] = desc->entries[i].cb; if (desc->set) - desc->set(buf, params); + desc->set(fe, buf, params); if (debug) printk("pll: %s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n", @@ -654,7 +664,7 @@ static int dvb_pll_set_params(struct dvb_frontend *fe, if (priv->i2c == NULL) return -EINVAL; - if ((result = dvb_pll_configure(priv->pll_desc, buf, params)) < 0) + if ((result = dvb_pll_configure(fe, buf, params)) < 0) return result; else frequency = result; @@ -682,7 +692,7 @@ static int dvb_pll_calc_regs(struct dvb_frontend *fe, if (buf_len < 5) return -EINVAL; - if ((result = dvb_pll_configure(priv->pll_desc, buf+1, params)) < 0) + if ((result = dvb_pll_configure(fe, buf+1, params)) < 0) return result; else frequency = result; -- cgit v1.2.3-70-g09d2 From a27e5e769e46626052fc18ff63f274ee97142bab Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 7 Sep 2007 18:11:15 -0300 Subject: V4L/DVB (6227): dvb-pll: store instance ID in dvb_pll_priv structure Store an instance ID in the dvb_pll_priv structure, so that module options specific to a given pll may be used by the functions within the driver. When debug is turned on, print a message indicating which pll was attached and it's instance id. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/dvb-pll.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index 59ae4ece65a..5f4762edc40 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -556,6 +556,9 @@ static struct dvb_pll_desc *pll_list[] = { /* ----------------------------------------------------------- */ struct dvb_pll_priv { + /* pll number */ + int nr; + /* i2c details */ int pll_i2c_address; struct i2c_adapter *i2c; @@ -575,6 +578,8 @@ static int debug = 0; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "enable verbose debug messages"); +static unsigned int dvb_pll_devcount; + static int dvb_pll_configure(struct dvb_frontend *fe, u8 *buf, const struct dvb_frontend_parameters *params) { @@ -787,6 +792,7 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, priv->pll_i2c_address = pll_addr; priv->i2c = i2c; priv->pll_desc = desc; + priv->nr = dvb_pll_devcount++; memcpy(&fe->ops.tuner_ops, &dvb_pll_tuner_ops, sizeof(struct dvb_tuner_ops)); @@ -801,6 +807,14 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, fe->ops.tuner_ops.sleep = NULL; fe->tuner_priv = priv; + + if (debug) { + printk("dvb-pll[%d]", priv->nr); + if (i2c != NULL) + printk(" %d-%04x", i2c_adapter_id(i2c), pll_addr); + printk(": id# %d (%s) attached\n", pll_desc_id, desc->name); + } + return fe; } EXPORT_SYMBOL(dvb_pll_attach); -- cgit v1.2.3-70-g09d2 From 05a4611b5d71ad6f968fdeef092c24914570898b Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 7 Sep 2007 18:19:57 -0300 Subject: V4L/DVB (6228): dvb-pll: add module option to specify rf input Add a module option to dvb-pll, called "input" to specify which rf input to use on devices with multiple rf inputs. If the module option is not specified, then the driver will autoselect the rf input, as per previous behavior. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/dvb-pll.c | 82 ++++++++++++++++++++++------------- 1 file changed, 53 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index 5f4762edc40..7b133248b2b 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -24,6 +24,36 @@ #include "dvb-pll.h" +struct dvb_pll_priv { + /* pll number */ + int nr; + + /* i2c details */ + int pll_i2c_address; + struct i2c_adapter *i2c; + + /* the PLL descriptor */ + struct dvb_pll_desc *pll_desc; + + /* cached frequency/bandwidth */ + u32 frequency; + u32 bandwidth; +}; + +#define DVB_PLL_MAX 16 + +static unsigned int dvb_pll_devcount; + +static int debug = 0; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable verbose debug messages"); + +static unsigned int input[DVB_PLL_MAX] = { [ 0 ... (DVB_PLL_MAX-1) ] = 0 }; +module_param_array(input, int, NULL, 0644); +MODULE_PARM_DESC(input,"specify rf input choice, 0 for autoselect (default)"); + +/* ----------------------------------------------------------- */ + struct dvb_pll_desc { char *name; u32 min; @@ -362,14 +392,32 @@ static struct dvb_pll_desc dvb_pll_tdhu2 = { static void tuv1236d_rf(struct dvb_frontend *fe, u8 *buf, const struct dvb_frontend_parameters *params) { - switch (params->u.vsb.modulation) { - case QAM_64: - case QAM_256: + struct dvb_pll_priv *priv = fe->tuner_priv; + unsigned int new_rf = input[priv->nr]; + + if ((new_rf == 0) || (new_rf > 2)) { + switch (params->u.vsb.modulation) { + case QAM_64: + case QAM_256: + new_rf = 1; + break; + case VSB_8: + default: + new_rf = 2; + } + } + + switch (new_rf) { + case 1: buf[3] |= 0x08; break; - case VSB_8: - default: + case 2: buf[3] &= ~0x08; + break; + default: + printk(KERN_WARNING + "%s: unhandled rf input selection: %d", + __FUNCTION__, new_rf); } } @@ -553,33 +601,9 @@ static struct dvb_pll_desc *pll_list[] = { [DVB_PLL_FCV1236D] = &dvb_pll_fcv1236d, }; -/* ----------------------------------------------------------- */ - -struct dvb_pll_priv { - /* pll number */ - int nr; - - /* i2c details */ - int pll_i2c_address; - struct i2c_adapter *i2c; - - /* the PLL descriptor */ - struct dvb_pll_desc *pll_desc; - - /* cached frequency/bandwidth */ - u32 frequency; - u32 bandwidth; -}; - /* ----------------------------------------------------------- */ /* code */ -static int debug = 0; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "enable verbose debug messages"); - -static unsigned int dvb_pll_devcount; - static int dvb_pll_configure(struct dvb_frontend *fe, u8 *buf, const struct dvb_frontend_parameters *params) { -- cgit v1.2.3-70-g09d2 From ff3e7dd5809fb632447f1aa6de6b3ffb755727dd Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 9 Sep 2007 13:00:45 -0300 Subject: V4L/DVB (6229): dvb-pll: increase DVB_PLL_MAX to 64 Increased DVB_PLL_MAX from 16 to a figure that would never be reached in a practical sense. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/dvb-pll.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index 7b133248b2b..0fb4d453ae5 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -40,7 +40,7 @@ struct dvb_pll_priv { u32 bandwidth; }; -#define DVB_PLL_MAX 16 +#define DVB_PLL_MAX 64 static unsigned int dvb_pll_devcount; -- cgit v1.2.3-70-g09d2 From 704e39bf620810734a38b3f9c0e07cede2a76d91 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 7 Sep 2007 18:27:43 -0300 Subject: V4L/DVB (6230): dvb-pll: add module option to force dvb-pll desc id (for debug use only) Add a module option to force the dvb-pll module to use an alternate dvb-pll description without having to recompile the kernel. Having a module option like this is useful in some cases, where the vendor may release an alternate revision of the hardware using a different tuner, but without changing the pci subsystem / usb device ids. This option is intended for debugging purposes _only_. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/dvb-pll.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index 0fb4d453ae5..64007032997 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -52,6 +52,11 @@ static unsigned int input[DVB_PLL_MAX] = { [ 0 ... (DVB_PLL_MAX-1) ] = 0 }; module_param_array(input, int, NULL, 0644); MODULE_PARM_DESC(input,"specify rf input choice, 0 for autoselect (default)"); +static unsigned int id[DVB_PLL_MAX] = + { [ 0 ... (DVB_PLL_MAX-1) ] = DVB_PLL_UNDEFINED }; +module_param_array(id, int, NULL, 0644); +MODULE_PARM_DESC(id, "force pll id to use (DEBUG ONLY)"); + /* ----------------------------------------------------------- */ struct dvb_pll_desc { @@ -794,6 +799,10 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, int ret; struct dvb_pll_desc *desc; + if ((id[dvb_pll_devcount] > DVB_PLL_UNDEFINED) && + (id[dvb_pll_devcount] < ARRAY_SIZE(pll_list))) + pll_desc_id = id[dvb_pll_devcount]; + BUG_ON(pll_desc_id < 1 || pll_desc_id >= ARRAY_SIZE(pll_list)); desc = pll_list[pll_desc_id]; @@ -836,7 +845,10 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, printk("dvb-pll[%d]", priv->nr); if (i2c != NULL) printk(" %d-%04x", i2c_adapter_id(i2c), pll_addr); - printk(": id# %d (%s) attached\n", pll_desc_id, desc->name); + printk(": id# %d (%s) attached, %s\n", pll_desc_id, desc->name, + id[priv->nr] == pll_desc_id ? + "insmod option" : "autodetected"); + } return fe; -- cgit v1.2.3-70-g09d2 From 8528fa414703f5be17092be2d3a2c5389755253a Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 9 Sep 2007 05:08:30 -0300 Subject: V4L/DVB (6231): dvb-pll: always show pll name if forced via insmod option The name of the pll will be shown if forced via insmod option, or if debug is enabled. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/dvb-pll.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index 64007032997..27b2d54b697 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -841,7 +841,7 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, fe->tuner_priv = priv; - if (debug) { + if ((debug) || (id[priv->nr] == pll_desc_id)) { printk("dvb-pll[%d]", priv->nr); if (i2c != NULL) printk(" %d-%04x", i2c_adapter_id(i2c), pll_addr); -- cgit v1.2.3-70-g09d2 From 4562fbeac61468f80a8d05e5ed50660bd97b4859 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 9 Sep 2007 05:16:34 -0300 Subject: V4L/DVB (6232): dvb-pll: report whether input rf will be autoselected or set via insmod option Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/dvb-pll.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index 27b2d54b697..8c8d7342d0b 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -848,7 +848,20 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, printk(": id# %d (%s) attached, %s\n", pll_desc_id, desc->name, id[priv->nr] == pll_desc_id ? "insmod option" : "autodetected"); - + } + if ((debug) || (input[priv->nr] > 0)) { + printk("dvb-pll[%d]", priv->nr); + if (i2c != NULL) + printk(" %d-%04x", i2c_adapter_id(i2c), pll_addr); + printk(": tuner rf input will be "); + switch (input[priv->nr]) { + case 0: + printk("autoselected\n"); + break; + default: + printk("set to input %d (insmod option)\n", + input[priv->nr]); + } } return fe; -- cgit v1.2.3-70-g09d2 From 23869e236846657415654e8f5fbda9faec8d19e4 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Wed, 19 Sep 2007 02:44:18 -0300 Subject: V4L/DVB (6235): cafe_ccic: default to allocating DMA buffers at probe time By default, we allocate DMA buffers when actually reading from the video capture device. On a system with 128MB or 256MB of ram, it's very easy for that memory to quickly become fragmented. We've had users report having 30+MB of memory free, but the cafe_ccic driver is still unable to allocate DMA buffers. Our workaround has been to make use of the 'alloc_bufs_at_load' parameter to allocate DMA buffers during device probing. This patch makes DMA buffer allocation happen during device probe by default, and changes the parameter to 'alloc_bufs_at_read'. The camera hardware is there, if the cafe_ccic driver is enabled/loaded it should do its best to ensure that the camera is actually usable; delaying DMA buffer allocation saves an insignicant amount of memory, and causes the driver to be much less useful. Signed-off-by: Andres Salomon Acked-by: Jonathan Corbet Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cafe_ccic.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c index 0fae0e000f1..ccb37006bb1 100644 --- a/drivers/media/video/cafe_ccic.c +++ b/drivers/media/video/cafe_ccic.c @@ -62,13 +62,13 @@ MODULE_SUPPORTED_DEVICE("Video"); */ #define MAX_DMA_BUFS 3 -static int alloc_bufs_at_load = 0; -module_param(alloc_bufs_at_load, bool, 0444); -MODULE_PARM_DESC(alloc_bufs_at_load, - "Non-zero value causes DMA buffers to be allocated at module " - "load time. This increases the chances of successfully getting " - "those buffers, but at the cost of nailing down the memory from " - "the outset."); +static int alloc_bufs_at_read = 0; +module_param(alloc_bufs_at_read, bool, 0444); +MODULE_PARM_DESC(alloc_bufs_at_read, + "Non-zero value causes DMA buffers to be allocated when the " + "video capture device is read, rather than at module load " + "time. This saves memory, but decreases the chances of " + "successfully getting those buffers."); static int n_dma_bufs = 3; module_param(n_dma_bufs, uint, 0644); @@ -1502,7 +1502,7 @@ static int cafe_v4l_release(struct inode *inode, struct file *filp) } if (cam->users == 0) { cafe_ctlr_power_down(cam); - if (! alloc_bufs_at_load) + if (alloc_bufs_at_read) cafe_free_dma_bufs(cam); } mutex_unlock(&cam->s_mutex); @@ -2161,7 +2161,7 @@ static int cafe_pci_probe(struct pci_dev *pdev, /* * If so requested, try to get our DMA buffers now. */ - if (alloc_bufs_at_load) { + if (!alloc_bufs_at_read) { if (cafe_alloc_dma_bufs(cam, 1)) cam_warn(cam, "Unable to alloc DMA buffers at load" " will try again later."); -- cgit v1.2.3-70-g09d2 From 0b67f5c568c545cb36f88e9f418af2df1cc58589 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Wed, 26 Sep 2007 10:19:01 -0300 Subject: V4L/DVB (6237): Oops in pwc v4l driver The pwc driver is defficient in locking, which can trigger an oops when disconnecting. Signed-off-by: Oliver Neukum CC: Luc Saillard Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pwc/pwc-if.c | 96 ++++++++++++++++++++++++++++++---------- 1 file changed, 72 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index 1088ebf5744..0ff5718bf9b 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c @@ -907,31 +907,49 @@ int pwc_isoc_init(struct pwc_device *pdev) return 0; } -void pwc_isoc_cleanup(struct pwc_device *pdev) +static void pwc_iso_stop(struct pwc_device *pdev) { int i; - PWC_DEBUG_OPEN(">> pwc_isoc_cleanup()\n"); - if (pdev == NULL) - return; - if (pdev->iso_init == 0) - return; - /* Unlinking ISOC buffers one by one */ for (i = 0; i < MAX_ISO_BUFS; i++) { struct urb *urb; urb = pdev->sbuf[i].urb; if (urb != 0) { - if (pdev->iso_init) { - PWC_DEBUG_MEMORY("Unlinking URB %p\n", urb); - usb_kill_urb(urb); - } + PWC_DEBUG_MEMORY("Unlinking URB %p\n", urb); + usb_kill_urb(urb); + } + } +} + +static void pwc_iso_free(struct pwc_device *pdev) +{ + int i; + + /* Freeing ISOC buffers one by one */ + for (i = 0; i < MAX_ISO_BUFS; i++) { + struct urb *urb; + + urb = pdev->sbuf[i].urb; + if (urb != 0) { PWC_DEBUG_MEMORY("Freeing URB\n"); usb_free_urb(urb); pdev->sbuf[i].urb = NULL; } } +} + +void pwc_isoc_cleanup(struct pwc_device *pdev) +{ + PWC_DEBUG_OPEN(">> pwc_isoc_cleanup()\n"); + if (pdev == NULL) + return; + if (pdev->iso_init == 0) + return; + + pwc_iso_stop(pdev); + pwc_iso_free(pdev); /* Stop camera, but only if we are sure the camera is still there (unplug is signalled by EPIPE) @@ -1211,6 +1229,7 @@ static int pwc_video_close(struct inode *inode, struct file *file) PWC_DEBUG_OPEN(">> video_close called(vdev = 0x%p).\n", vdev); + lock_kernel(); pdev = (struct pwc_device *)vdev->priv; if (pdev->vopen == 0) PWC_DEBUG_MODULE("video_close() called on closed device?\n"); @@ -1230,7 +1249,6 @@ static int pwc_video_close(struct inode *inode, struct file *file) pwc_isoc_cleanup(pdev); pwc_free_buffers(pdev); - lock_kernel(); /* Turn off LEDS and power down camera, but only when not unplugged */ if (!pdev->unplugged) { /* Turn LEDs off */ @@ -1276,7 +1294,7 @@ static ssize_t pwc_video_read(struct file *file, char __user *buf, struct pwc_device *pdev; int noblock = file->f_flags & O_NONBLOCK; DECLARE_WAITQUEUE(wait, current); - int bytes_to_read; + int bytes_to_read, rv = 0; void *image_buffer_addr; PWC_DEBUG_READ("pwc_video_read(vdev=0x%p, buf=%p, count=%zd) called.\n", @@ -1286,8 +1304,12 @@ static ssize_t pwc_video_read(struct file *file, char __user *buf, pdev = vdev->priv; if (pdev == NULL) return -EFAULT; - if (pdev->error_status) - return -pdev->error_status; /* Something happened, report what. */ + + mutex_lock(&pdev->modlock); + if (pdev->error_status) { + rv = -pdev->error_status; /* Something happened, report what. */ + goto err_out; + } /* In case we're doing partial reads, we don't have to wait for a frame */ if (pdev->image_read_pos == 0) { @@ -1298,17 +1320,20 @@ static ssize_t pwc_video_read(struct file *file, char __user *buf, if (pdev->error_status) { remove_wait_queue(&pdev->frameq, &wait); set_current_state(TASK_RUNNING); - return -pdev->error_status ; + rv = -pdev->error_status ; + goto err_out; } if (noblock) { remove_wait_queue(&pdev->frameq, &wait); set_current_state(TASK_RUNNING); - return -EWOULDBLOCK; + rv = -EWOULDBLOCK; + goto err_out; } if (signal_pending(current)) { remove_wait_queue(&pdev->frameq, &wait); set_current_state(TASK_RUNNING); - return -ERESTARTSYS; + rv = -ERESTARTSYS; + goto err_out; } schedule(); set_current_state(TASK_INTERRUPTIBLE); @@ -1317,8 +1342,10 @@ static ssize_t pwc_video_read(struct file *file, char __user *buf, set_current_state(TASK_RUNNING); /* Decompress and release frame */ - if (pwc_handle_frame(pdev)) - return -EFAULT; + if (pwc_handle_frame(pdev)) { + rv = -EFAULT; + goto err_out; + } } PWC_DEBUG_READ("Copying data to user space.\n"); @@ -1333,14 +1360,20 @@ static ssize_t pwc_video_read(struct file *file, char __user *buf, image_buffer_addr = pdev->image_data; image_buffer_addr += pdev->images[pdev->fill_image].offset; image_buffer_addr += pdev->image_read_pos; - if (copy_to_user(buf, image_buffer_addr, count)) - return -EFAULT; + if (copy_to_user(buf, image_buffer_addr, count)) { + rv = -EFAULT; + goto err_out; + } pdev->image_read_pos += count; if (pdev->image_read_pos >= bytes_to_read) { /* All data has been read */ pdev->image_read_pos = 0; pwc_next_image(pdev); } + mutex_unlock(&pdev->modlock); return count; +err_out: + mutex_unlock(&pdev->modlock); + return rv; } static unsigned int pwc_video_poll(struct file *file, poll_table *wait) @@ -1366,7 +1399,20 @@ static unsigned int pwc_video_poll(struct file *file, poll_table *wait) static int pwc_video_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - return video_usercopy(inode, file, cmd, arg, pwc_video_do_ioctl); + struct video_device *vdev = file->private_data; + struct pwc_device *pdev; + int r = -ENODEV; + + if (!vdev) + goto out; + pdev = vdev->priv; + + mutex_lock(&pdev->modlock); + if (!pdev->unplugged) + r = video_usercopy(inode, file, cmd, arg, pwc_video_do_ioctl); + mutex_unlock(&pdev->modlock); +out: + return r; } static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma) @@ -1809,7 +1855,10 @@ static void usb_pwc_disconnect(struct usb_interface *intf) wake_up_interruptible(&pdev->frameq); /* Wait until device is closed */ if(pdev->vopen) { + mutex_lock(&pdev->modlock); pdev->unplugged = 1; + mutex_unlock(&pdev->modlock); + pwc_iso_stop(pdev); } else { /* Device is closed, so we can safely unregister it */ PWC_DEBUG_PROBE("Unregistering video device in disconnect().\n"); @@ -1827,7 +1876,6 @@ disconnect_out: unlock_kernel(); } - /* *grunt* We have to do atoi ourselves :-( */ static int pwc_atoi(const char *s) { -- cgit v1.2.3-70-g09d2 From 9e19db5b6dda251b8d76c3a0069e63faca6be3f0 Mon Sep 17 00:00:00 2001 From: Brett Warden Date: Fri, 28 Sep 2007 03:19:04 -0300 Subject: V4L/DVB (6238): bw-qcam: use data_reverse instead of manually poking the control register Fixes use of parport_write_control() to match the newer interface that requires explicit parport_data_reverse() and parport_data_forward() calls. This eliminates the following error message and restores the original intended behavior: parport0 (bw-qcam): use data_reverse for this! Also increases threshold in qc_detect() from 300 to 400, as my camera often results in a count of approx 330. Added a kernel error message to indicate detection failure. Thanks Ray and Randy for your comments, and for pointing out that I needed to reset the port to forward mode! Signed-off-by: Brett T. Warden Acked-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bw-qcam.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c index 7d47cbe6ad2..0edd05ebcc3 100644 --- a/drivers/media/video/bw-qcam.c +++ b/drivers/media/video/bw-qcam.c @@ -104,6 +104,17 @@ static inline void write_lpdata(struct qcam_device *q, int d) static inline void write_lpcontrol(struct qcam_device *q, int d) { + if(0x20 & d) { + /* Set bidirectional mode to reverse (data in) */ + parport_data_reverse(q->pport); + } else { + /* Set bidirectional mode to forward (data out) */ + parport_data_forward(q->pport); + } + + /* Now issue the regular port command, but strip out the + * direction flag */ + d &= ~0x20; parport_write_control(q->pport, d); } @@ -344,10 +355,13 @@ static int qc_detect(struct qcam_device *q) /* Be (even more) liberal in what you accept... */ /* if (count > 30 && count < 200) */ - if (count > 20 && count < 300) + if (count > 20 && count < 400) + { return 1; /* found */ - else + } else { + printk(KERN_ERR "No Quickcam found on port %s\n", q->pport->name); return 0; /* not found */ + } } -- cgit v1.2.3-70-g09d2 From 0173e4696f201c53ab17ee4d9da81d74b5f9eddc Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Thu, 27 Sep 2007 11:37:19 -0300 Subject: V4L/DVB (6241): fix typo in DVB_PLL Kconfig help text s/driver/drives/1 Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index 53e77553964..59b9ed1f1ae 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -299,7 +299,7 @@ config DVB_PLL depends on DVB_CORE && I2C default m if DVB_FE_CUSTOMISE help - This module driver a number of tuners based on PLL chips with a + This module drives a number of tuners based on PLL chips with a common I2C interface. Say Y when you want to support these tuners. config DVB_TDA826X -- cgit v1.2.3-70-g09d2 From 3e7589c50771aa0f6eaa8de799e599c016f4029c Mon Sep 17 00:00:00 2001 From: Pekka Seppanen Date: Sun, 30 Sep 2007 21:49:01 -0300 Subject: V4L/DVB (6243): [PATCH 2/2] GemTek Radio card Details now match with radio-gemtek.c, eg. no more different ports. Included a short note about cards that should be compatible with radio-gemtek module. Signed-off-by: Pekka Seppanen Signed-off-by: Douglas Schilling Landgraf Reviewed-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/Kconfig | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index f8bf9fe37d3..11e962f1a97 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig @@ -111,11 +111,16 @@ config RADIO_AZTECH_PORT jumper sets the card to 0x358. config RADIO_GEMTEK - tristate "GemTek Radio Card support" + tristate "GemTek Radio card (or compatible) support" depends on ISA && VIDEO_V4L2 ---help--- Choose Y here if you have this FM radio card, and then fill in the - port address below. + I/O port address and settings below. The following cards either have + GemTek Radio tuner or are rebranded GemTek Radio cards: + + - Sound Vision 16 Gold with FM Radio + - Typhoon Radio card (some models) + - Hama Radio card In order to control your radio card, you will need to use programs that are compatible with the Video For Linux API. Information on @@ -126,14 +131,25 @@ config RADIO_GEMTEK module will be called radio-gemtek. config RADIO_GEMTEK_PORT - hex "GemTek i/o port (0x20c, 0x30c, 0x24c or 0x34c)" + hex "Fixed I/O port (0x20c, 0x30c, 0x24c, 0x34c, 0c24c or 0x28c)" depends on RADIO_GEMTEK=y default "34c" help Enter either 0x20c, 0x30c, 0x24c or 0x34c here. The card default is 0x34c, if you haven't changed the jumper setting on the card. On Sound Vision 16 Gold PnP with FM Radio (ESS1869+FM Gemtek), the I/O - port is 0x28c. + port is 0x20c, 0x248 or 0x28c. + If automatic I/O port probing is enabled this port will be used only + in case of automatic probing failure, ie. as a fallback. + +config RADIO_GEMTEK_PROBE + bool "Automatic I/O port probing" + depends on RADIO_GEMTEK=y + default y + help + Say Y here to enable automatic probing for GemTek Radio card. The + following ports will be probed: 0x20c, 0x30c, 0x24c, 0x34c, 0x248 and + 0x28c. config RADIO_GEMTEK_PCI tristate "GemTek PCI Radio Card support" -- cgit v1.2.3-70-g09d2 From 4753647e6422341a091e729b9d81a9a5e7fe6179 Mon Sep 17 00:00:00 2001 From: Pekka Seppanen Date: Mon, 1 Oct 2007 00:27:55 -0300 Subject: V4L/DVB (6244): [PATCH 1/2] GemTek Radio card Code cleanup for GemTek Radio card driver. Removed unnecessary / invalid I/O commands and rewrote code for tuning on-board BU2614FS chip. Adds several new module params for power users. Includes automatic device probing. Signed-off-by: Pekka Seppanen Signed-off-by: Douglas Schilling Landgraf Reviewed-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-gemtek.c | 651 ++++++++++++++++++++++++++----------- 1 file changed, 462 insertions(+), 189 deletions(-) (limited to 'drivers') diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c index eab8c80a2e4..f959bb71c46 100644 --- a/drivers/media/radio/radio-gemtek.c +++ b/drivers/media/radio/radio-gemtek.c @@ -26,143 +26,413 @@ #include #include -#include /* for KERNEL_VERSION MACRO */ -#define RADIO_VERSION KERNEL_VERSION(0,0,2) +#include /* for KERNEL_VERSION MACRO */ +#define RADIO_VERSION KERNEL_VERSION(0,0,3) +#define RADIO_BANNER "GemTek Radio card driver: v0.0.3" -static struct v4l2_queryctrl radio_qctrl[] = { - { - .id = V4L2_CID_AUDIO_MUTE, - .name = "Mute", - .minimum = 0, - .maximum = 1, - .default_value = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ - .id = V4L2_CID_AUDIO_VOLUME, - .name = "Volume", - .minimum = 0, - .maximum = 65535, - .step = 65535, - .default_value = 0xff, - .type = V4L2_CTRL_TYPE_INTEGER, - } -}; +/* + * Module info. + */ + +MODULE_AUTHOR("Jonas Munsin, Pekka Seppänen "); +MODULE_DESCRIPTION("A driver for the GemTek Radio card."); +MODULE_LICENSE("GPL"); + +/* + * Module params. + */ #ifndef CONFIG_RADIO_GEMTEK_PORT #define CONFIG_RADIO_GEMTEK_PORT -1 #endif +#ifndef CONFIG_RADIO_GEMTEK_PROBE +#define CONFIG_RADIO_GEMTEK_PROBE 1 +#endif -static int io = CONFIG_RADIO_GEMTEK_PORT; -static int radio_nr = -1; -static spinlock_t lock; +static int io = CONFIG_RADIO_GEMTEK_PORT; +static int probe = CONFIG_RADIO_GEMTEK_PROBE; +static int hardmute; +static int shutdown = 1; +static int keepmuted = 1; +static int initmute = 1; +static int radio_nr = -1; -struct gemtek_device -{ - int port; - unsigned long curfreq; +module_param(io, int, 0444); +MODULE_PARM_DESC(io, "Force I/O port for the GemTek Radio card if automatic" + "probing is disabled or fails. The most common I/O ports are: 0x20c " + "0x30c, 0x24c or 0x34c (0x20c, 0x248 and 0x28c have been reported to " + " work for the combined sound/radiocard)."); + +module_param(probe, bool, 0444); +MODULE_PARM_DESC(probe, "Enable automatic device probing. Note: only the most " + "common I/O ports used by the card are probed."); + +module_param(hardmute, bool, 0644); +MODULE_PARM_DESC(hardmute, "Enable `hard muting' by shutting down PLL, may " + "reduce static noise."); + +module_param(shutdown, bool, 0644); +MODULE_PARM_DESC(shutdown, "Enable shutting down PLL and muting line when " + "module is unloaded."); + +module_param(keepmuted, bool, 0644); +MODULE_PARM_DESC(keepmuted, "Keep card muted even when frequency is changed."); + +module_param(initmute, bool, 0444); +MODULE_PARM_DESC(initmute, "Mute card when module is loaded."); + +module_param(radio_nr, int, 0444); + +/* + * Functions for controlling the card. + */ +#define GEMTEK_LOWFREQ (87*16000) +#define GEMTEK_HIGHFREQ (108*16000) + +#define GEMTEK_CK 0x01 /* Clock signal */ +#define GEMTEK_DA 0x02 /* Serial data */ +#define GEMTEK_CE 0x04 /* Chip enable */ +#define GEMTEK_NS 0x08 /* No signal */ +#define GEMTEK_MT 0x10 /* Line mute */ +#define GEMTEK_STDF_3_125_KHZ 0x01 /* Standard frequency 3.125 kHz */ +#define GEMTEK_PLL_OFF 0x07 /* PLL off */ + +#define BU2614_BUS_SIZE 32 /* BU2614 / BU2614FS bus size */ +#define BU2614_NOPS 8 /* Number of supported operations */ + +#define SHORT_DELAY 5 /* usec */ +#define LONG_DELAY 75 /* usec */ + +struct gemtek_device { + unsigned long lastfreq; int muted; + unsigned long bu2614data[BU2614_NOPS]; }; +enum { + BU2614_VOID, + BU2614_FREQ, /* D0..D15, Frequency data */ + BU2614_PORT, /* P0..P2, Output port control data */ + BU2614_FMES, /* CT, Frequency measurement beginning data */ + BU2614_STDF, /* R0..R2, Standard frequency data */ + BU2614_SWIN, /* S, Switch between FMIN / AMIN */ + BU2614_SWAL, /* PS, Swallow counter division (AMIN only) */ + BU2614_FMUN, /* GT, Frequency measurement time and unlock */ + BU2614_TEST /* TS, Test data is input */ +}; + +struct bu2614_op { + int op; /* Operation */ + int size; /* Data size */ +}; + +static struct gemtek_device gemtek_unit; + +static struct bu2614_op bu2614ops[] = { + {.op = BU2614_FREQ, + .size = 0x10}, + {.op = BU2614_PORT, + .size = 0x03}, + {.op = BU2614_VOID, + .size = 0x04}, + {.op = BU2614_FMES, + .size = 0x01}, + {.op = BU2614_STDF, + .size = 0x03}, + {.op = BU2614_SWIN, + .size = 0x01}, + {.op = BU2614_SWAL, + .size = 0x01}, + {.op = BU2614_VOID, + .size = 0x01}, + {.op = BU2614_FMUN, + .size = 0x01}, + {.op = BU2614_TEST, + .size = 0x01} +}; -/* local things */ +static spinlock_t lock; -/* the correct way to mute the gemtek may be to write the last written - * frequency || 0x10, but just writing 0x10 once seems to do it as well +/* + * Set data which will be sent to BU2614FS. */ -static void gemtek_mute(struct gemtek_device *dev) +static void gemtek_bu2614_set(struct gemtek_device *dev, int op, + unsigned long data) { - if(dev->muted) - return; + int i, q; + + for (i = 0, q = 0; q < ARRAY_SIZE(dev->bu2614data); ++i) { + if (bu2614ops[i].op == op) { + dev->bu2614data[q] = + data & ((1 << bu2614ops[i].size) - 1); + return; + } + + if (bu2614ops[i].op != BU2614_VOID) + ++q; + } +} + +/* + * Transmit settings to BU2614FS over GemTek IC. + */ +static void gemtek_bu2614_transmit(struct gemtek_device *dev) +{ + int i, bit, q, mute; + spin_lock(&lock); - outb(0x10, io); + + mute = dev->muted ? GEMTEK_MT : 0x00; + + outb_p(mute | GEMTEK_DA | GEMTEK_CK, io); + udelay(SHORT_DELAY); + outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, io); + udelay(LONG_DELAY); + + for (i = 0, q = 0; q < ARRAY_SIZE(dev->bu2614data); ++i) { + for (bit = 0; bit < bu2614ops[i].size; ++bit) { + if (bu2614ops[i].op != BU2614_VOID && + dev->bu2614data[q] & (1 << bit)) { + outb_p(mute | GEMTEK_CE | GEMTEK_DA, io); + udelay(SHORT_DELAY); + outb_p(mute | GEMTEK_CE | GEMTEK_DA | + GEMTEK_CK, io); + udelay(SHORT_DELAY); + } else { + outb_p(mute | GEMTEK_CE, io); + udelay(SHORT_DELAY); + outb_p(mute | GEMTEK_CE | GEMTEK_CK, io); + udelay(SHORT_DELAY); + } + } + + if (bu2614ops[i].op != BU2614_VOID) + ++q; + } + + outb_p(mute | GEMTEK_DA | GEMTEK_CK, io); + udelay(SHORT_DELAY); + outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, io); + udelay(LONG_DELAY); + spin_unlock(&lock); - dev->muted = 1; } -static void gemtek_unmute(struct gemtek_device *dev) +/* + * Convert FM-frequency for BU2614FS (3.125 KHz STDF expected). + */ +static inline void gemtek_convfreq(unsigned long *freq) { - if(dev->muted == 0) + (*freq) /= 160; + (*freq) += 1052; /* FMIN, 10.52 MHz */ + (*freq) *= 1565; /* STDF, 1 / 156.5 = 0.00639 */ + (*freq) /= 1000; +} + +/* + * Set FM-frequency. + */ +static void gemtek_setfreq(struct gemtek_device *dev, unsigned long freq) +{ + + if (keepmuted && hardmute && dev->muted) return; - spin_lock(&lock); - outb(0x20, io); - spin_unlock(&lock); + + if (freq < GEMTEK_LOWFREQ) + freq = GEMTEK_LOWFREQ; + else if (freq > GEMTEK_HIGHFREQ) + freq = GEMTEK_HIGHFREQ; + + dev->lastfreq = freq; dev->muted = 0; + + gemtek_bu2614_set(dev, BU2614_PORT, 0); + gemtek_bu2614_set(dev, BU2614_FMES, 0); + gemtek_bu2614_set(dev, BU2614_SWIN, 0); /* FM-mode */ + gemtek_bu2614_set(dev, BU2614_SWAL, 0); + gemtek_bu2614_set(dev, BU2614_FMUN, 1); /* GT bit set */ + gemtek_bu2614_set(dev, BU2614_TEST, 0); + + gemtek_convfreq(&freq); + + gemtek_bu2614_set(dev, BU2614_STDF, GEMTEK_STDF_3_125_KHZ); + gemtek_bu2614_set(dev, BU2614_FREQ, freq); + + gemtek_bu2614_transmit(dev); } -static void zero(void) +/* + * Set mute flag. + */ +static void gemtek_mute(struct gemtek_device *dev) { - outb_p(0x04, io); - udelay(5); - outb_p(0x05, io); - udelay(5); + int i; + dev->muted = 1; + + if (hardmute) { + /* Turn off PLL, disable data output */ + gemtek_bu2614_set(dev, BU2614_PORT, 0); + gemtek_bu2614_set(dev, BU2614_FMES, 0); /* CT bit off */ + gemtek_bu2614_set(dev, BU2614_SWIN, 0); /* FM-mode */ + gemtek_bu2614_set(dev, BU2614_SWAL, 0); + gemtek_bu2614_set(dev, BU2614_FMUN, 0); /* GT bit off */ + gemtek_bu2614_set(dev, BU2614_TEST, 0); + gemtek_bu2614_set(dev, BU2614_STDF, GEMTEK_PLL_OFF); + gemtek_bu2614_set(dev, BU2614_FREQ, 0); + gemtek_bu2614_transmit(dev); + } else { + spin_lock(&lock); + + /* Read bus contents (CE, CK and DA). */ + i = inb_p(io); + /* Write it back with mute flag set. */ + outb_p((i >> 5) | GEMTEK_MT, io); + udelay(SHORT_DELAY); + + spin_unlock(&lock); + } } -static void one(void) +/* + * Unset mute flag. + */ +static void gemtek_unmute(struct gemtek_device *dev) { - outb_p(0x06, io); - udelay(5); - outb_p(0x07, io); - udelay(5); + int i; + dev->muted = 0; + + if (hardmute) { + /* Turn PLL back on. */ + gemtek_setfreq(dev, dev->lastfreq); + } else { + spin_lock(&lock); + + i = inb_p(io); + outb_p(i >> 5, io); + udelay(SHORT_DELAY); + + spin_unlock(&lock); + } } -static int gemtek_setfreq(struct gemtek_device *dev, unsigned long freq) +/* + * Get signal strength (= stereo status). + */ +static inline int gemtek_getsigstr(void) { - int i; + return inb_p(io) & GEMTEK_NS ? 0 : 1; +} -/* freq = 78.25*((float)freq/16000.0 + 10.52); */ +/* + * Check if requested card acts like GemTek Radio card. + */ +static int gemtek_verify(int port) +{ + static int verified = -1; + int i, q; - freq /= 16; - freq += 10520; - freq *= 7825; - freq /= 100000; + if (verified == port) + return 1; spin_lock(&lock); - /* 2 start bits */ - outb_p(0x03, io); - udelay(5); - outb_p(0x07, io); - udelay(5); + q = inb_p(port); /* Read bus contents before probing. */ + /* Try to turn on CE, CK and DA respectively and check if card responds + properly. */ + for (i = 0; i < 3; ++i) { + outb_p(1 << i, port); + udelay(SHORT_DELAY); - /* 28 frequency bits (lsb first) */ - for (i = 0; i < 14; i++) - if (freq & (1 << i)) - one(); - else - zero(); - /* 36 unknown bits */ - for (i = 0; i < 11; i++) - zero(); - one(); - for (i = 0; i < 4; i++) - zero(); - one(); - zero(); - - /* 2 end bits */ - outb_p(0x03, io); - udelay(5); - outb_p(0x07, io); - udelay(5); + if ((inb_p(port) & (~GEMTEK_NS)) != (0x17 | (1 << (i + 5)))) { + spin_unlock(&lock); + return 0; + } + } + outb_p(q >> 5, port); /* Write bus contents back. */ + udelay(SHORT_DELAY); spin_unlock(&lock); + verified = port; - return 0; + return 1; } -static int gemtek_getsigstr(struct gemtek_device *dev) +/* + * Automatic probing for card. + */ +static int gemtek_probe(void) { - spin_lock(&lock); - inb(io); - udelay(5); - spin_unlock(&lock); - if (inb(io) & 8) /* bit set = no signal present */ - return 0; - return 1; /* signal present */ + int ioports[] = { 0x20c, 0x30c, 0x24c, 0x34c, 0x248, 0x28c }; + int i; + + if (!probe) { + printk(KERN_INFO "Automatic device probing disabled.\n"); + return -1; + } + + printk(KERN_INFO "Automatic device probing enabled.\n"); + + for (i = 0; i < ARRAY_SIZE(ioports); ++i) { + printk(KERN_INFO "Trying I/O port 0x%x...\n", ioports[i]); + + if (!request_region(ioports[i], 1, "gemtek-probe")) { + printk(KERN_WARNING "I/O port 0x%x busy!\n", + ioports[i]); + continue; + } + + if (gemtek_verify(ioports[i])) { + printk(KERN_INFO "Card found from I/O port " + "0x%x!\n", ioports[i]); + + release_region(ioports[i], 1); + + io = ioports[i]; + return io; + } + + release_region(ioports[i], 1); + } + + printk(KERN_ERR "Automatic probing failed!\n"); + + return -1; } -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *v) +/* + * Video 4 Linux stuff. + */ + +static struct v4l2_queryctrl radio_qctrl[] = { + { + .id = V4L2_CID_AUDIO_MUTE, + .name = "Mute", + .minimum = 0, + .maximum = 1, + .default_value = 1, + .type = V4L2_CTRL_TYPE_BOOLEAN, + }, { + .id = V4L2_CID_AUDIO_VOLUME, + .name = "Volume", + .minimum = 0, + .maximum = 65535, + .step = 65535, + .default_value = 0xff, + .type = V4L2_CTRL_TYPE_INTEGER, + } +}; + +static struct file_operations gemtek_fops = { + .owner = THIS_MODULE, + .open = video_exclusive_open, + .release = video_exclusive_release, + .ioctl = video_ioctl2, + .compat_ioctl = v4l_compat_ioctl32, + .llseek = no_llseek +}; + +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *v) { strlcpy(v->driver, "radio-gemtek", sizeof(v->driver)); strlcpy(v->card, "GemTek", sizeof(v->card)); @@ -172,28 +442,29 @@ static int vidioc_querycap(struct file *file, void *priv, return 0; } -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) +static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { - struct video_device *dev = video_devdata(file); - struct gemtek_device *rt = dev->priv; - if (v->index > 0) return -EINVAL; strcpy(v->name, "FM"); v->type = V4L2_TUNER_RADIO; - v->rangelow = (87*16000); - v->rangehigh = (108*16000); - v->rxsubchans = V4L2_TUNER_SUB_MONO; - v->capability = V4L2_TUNER_CAP_LOW; - v->audmode = V4L2_TUNER_MODE_MONO; - v->signal = 0xffff*gemtek_getsigstr(rt); + v->rangelow = GEMTEK_LOWFREQ; + v->rangehigh = GEMTEK_HIGHFREQ; + v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; + v->signal = 0xffff * gemtek_getsigstr(); + if (v->signal) { + v->audmode = V4L2_TUNER_MODE_STEREO; + v->rxsubchans = V4L2_TUNER_SUB_STEREO; + } else { + v->audmode = V4L2_TUNER_MODE_MONO; + v->rxsubchans = V4L2_TUNER_SUB_MONO; + } + return 0; } -static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) +static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { if (v->index > 0) return -EINVAL; @@ -201,38 +472,35 @@ static int vidioc_s_tuner(struct file *file, void *priv, } static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + struct v4l2_frequency *f) { struct video_device *dev = video_devdata(file); struct gemtek_device *rt = dev->priv; - rt->curfreq = f->frequency; - /* needs to be called twice in order for getsigstr to work */ - gemtek_setfreq(rt, rt->curfreq); - gemtek_setfreq(rt, rt->curfreq); + gemtek_setfreq(rt, f->frequency); + return 0; } static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + struct v4l2_frequency *f) { struct video_device *dev = video_devdata(file); struct gemtek_device *rt = dev->priv; f->type = V4L2_TUNER_RADIO; - f->frequency = rt->curfreq; + f->frequency = rt->lastfreq; return 0; } static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) + struct v4l2_queryctrl *qc) { int i; - for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { + for (i = 0; i < ARRAY_SIZE(radio_qctrl); ++i) { if (qc->id && qc->id == radio_qctrl[i].id) { - memcpy(qc, &(radio_qctrl[i]), - sizeof(*qc)); + memcpy(qc, &(radio_qctrl[i]), sizeof(*qc)); return 0; } } @@ -240,7 +508,7 @@ static int vidioc_queryctrl(struct file *file, void *priv, } static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) + struct v4l2_control *ctrl) { struct video_device *dev = video_devdata(file); struct gemtek_device *rt = dev->priv; @@ -260,7 +528,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv, } static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) + struct v4l2_control *ctrl) { struct video_device *dev = video_devdata(file); struct gemtek_device *rt = dev->priv; @@ -282,8 +550,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv, return -EINVAL; } -static int vidioc_g_audio (struct file *file, void *priv, - struct v4l2_audio *a) +static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) { if (a->index > 1) return -EINVAL; @@ -306,99 +573,105 @@ static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) return 0; } -static int vidioc_s_audio(struct file *file, void *priv, - struct v4l2_audio *a) +static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a) { if (a->index != 0) return -EINVAL; return 0; } -static struct gemtek_device gemtek_unit; - -static const struct file_operations gemtek_fops = { - .owner = THIS_MODULE, - .open = video_exclusive_open, - .release = video_exclusive_release, - .ioctl = video_ioctl2, - .compat_ioctl = v4l_compat_ioctl32, - .llseek = no_llseek, +static struct video_device gemtek_radio = { + .owner = THIS_MODULE, + .name = "GemTek Radio card", + .type = VID_TYPE_TUNER, + .hardware = VID_HARDWARE_GEMTEK, + .fops = &gemtek_fops, + .vidioc_querycap = vidioc_querycap, + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_audio = vidioc_g_audio, + .vidioc_s_audio = vidioc_s_audio, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl }; -static struct video_device gemtek_radio= -{ - .owner = THIS_MODULE, - .name = "GemTek radio", - .type = VID_TYPE_TUNER, - .fops = &gemtek_fops, - .vidioc_querycap = vidioc_querycap, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, -}; +/* + * Initialization / cleanup related stuff. + */ +/* + * Initilize card. + */ static int __init gemtek_init(void) { - if(io==-1) - { - printk(KERN_ERR "You must set an I/O address with io=0x20c, io=0x30c, io=0x24c or io=0x34c (io=0x020c or io=0x248 for the combined sound/radiocard)\n"); - return -EINVAL; - } + int i; - if (!request_region(io, 4, "gemtek")) - { - printk(KERN_ERR "gemtek: port 0x%x already in use\n", io); - return -EBUSY; - } + printk(KERN_INFO RADIO_BANNER "\n"); - gemtek_radio.priv=&gemtek_unit; + spin_lock_init(&lock); - if(video_register_device(&gemtek_radio, VFL_TYPE_RADIO, radio_nr)==-1) - { - release_region(io, 4); + gemtek_probe(); + if (io) { + if (!request_region(io, 1, "gemtek")) { + printk(KERN_ERR "I/O port 0x%x already in use.\n", io); + return -EBUSY; + } + + if (!gemtek_verify(io)) + printk(KERN_WARNING "Card at I/O port 0x%x does not " + "respond properly, check your " + "configuration.\n", io); + else + printk(KERN_INFO "Using I/O port 0x%x.\n", io); + } else if (probe) { + printk(KERN_ERR "Automatic probing failed and no " + "fixed I/O port defined.\n"); + return -ENODEV; + } else { + printk(KERN_ERR "Automatic probing disabled but no fixed " + "I/O port defined."); return -EINVAL; } - printk(KERN_INFO "GemTek Radio Card driver.\n"); - spin_lock_init(&lock); + gemtek_radio.priv = &gemtek_unit; + + if (video_register_device(&gemtek_radio, VFL_TYPE_RADIO, + radio_nr) == -1) { + release_region(io, 1); + return -EBUSY; + } - /* this is _maybe_ unnecessary */ - outb(0x01, io); + /* Set defaults */ + gemtek_unit.lastfreq = GEMTEK_LOWFREQ; + for (i = 0; i < ARRAY_SIZE(gemtek_unit.bu2614data); ++i) + gemtek_unit.bu2614data[i] = 0; - /* mute card - prevents noisy bootups */ - gemtek_unit.muted = 0; - gemtek_mute(&gemtek_unit); + if (initmute) + gemtek_mute(&gemtek_unit); return 0; } -MODULE_AUTHOR("Jonas Munsin"); -MODULE_DESCRIPTION("A driver for the GemTek Radio Card"); -MODULE_LICENSE("GPL"); - -module_param(io, int, 0); -MODULE_PARM_DESC(io, "I/O address of the GemTek card (0x20c, 0x30c, 0x24c or 0x34c (0x20c or 0x248 have been reported to work for the combined sound/radiocard))."); -module_param(radio_nr, int, 0); - -static void __exit gemtek_cleanup(void) +/* + * Module cleanup + */ +static void __exit gemtek_exit(void) { + if (shutdown) { + hardmute = 1; /* Turn off PLL */ + gemtek_mute(&gemtek_unit); + } else { + printk(KERN_INFO "Module unloaded but card not muted!\n"); + } + video_unregister_device(&gemtek_radio); - release_region(io,4); + release_region(io, 1); } module_init(gemtek_init); -module_exit(gemtek_cleanup); - -/* - Local variables: - compile-command: "gcc -c -DMODVERSIONS -D__KERNEL__ -DMODULE -O6 -Wall -Wstrict-prototypes -I /home/blp/tmp/linux-2.1.111-rtrack/include radio-rtrack2.c" - End: -*/ +module_exit(gemtek_exit); -- cgit v1.2.3-70-g09d2 From 857e594ad5662349d95ad33f987cbf55cc356a90 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Mon, 1 Oct 2007 00:32:25 -0300 Subject: V4L/DVB (6245): GemTek Radio card - frequency calculation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Frequency calculation to use better math. It's still the same IF offset and step size (which are not the same as the datasheet says) as the code was before. It's just more efficient and accurate. Signed-off-by: Trent Piepho Reviewed-by: Pekka Seppänen Signed-off-by: Douglas Schilling Landgraf Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-gemtek.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c index f959bb71c46..0fcd2b09218 100644 --- a/drivers/media/radio/radio-gemtek.c +++ b/drivers/media/radio/radio-gemtek.c @@ -89,6 +89,14 @@ module_param(radio_nr, int, 0444); #define GEMTEK_LOWFREQ (87*16000) #define GEMTEK_HIGHFREQ (108*16000) +/* + * Frequency calculation constants. Intermediate frequency 10.52 MHz (nominal + * value 10.7 MHz), reference divisor 6.39 kHz (nominal 6.25 kHz). + */ +#define FSCALE 8 +#define IF_OFFSET ((unsigned int)(10.52 * 16000 * (1< Date: Mon, 1 Oct 2007 00:38:30 -0300 Subject: V4L/DVB (6246): GemTek Radio card - Control Word MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Redoes the way the control word is stored and set. The existing code was a lot more complicated than it needed to be. Signed-off-by: Trent Piepho Signed-off-by: Douglas Schilling Landgraf Signed-off-by: Mauro Carvalho Chehab Reviewed-by: Pekka Seppänen --- drivers/media/radio/radio-gemtek.c | 124 +++++++++++++------------------------ 1 file changed, 44 insertions(+), 80 deletions(-) (limited to 'drivers') diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c index 0fcd2b09218..0c963db0361 100644 --- a/drivers/media/radio/radio-gemtek.c +++ b/drivers/media/radio/radio-gemtek.c @@ -106,7 +106,6 @@ module_param(radio_nr, int, 0444); #define GEMTEK_PLL_OFF 0x07 /* PLL off */ #define BU2614_BUS_SIZE 32 /* BU2614 / BU2614FS bus size */ -#define BU2614_NOPS 8 /* Number of supported operations */ #define SHORT_DELAY 5 /* usec */ #define LONG_DELAY 75 /* usec */ @@ -114,72 +113,53 @@ module_param(radio_nr, int, 0444); struct gemtek_device { unsigned long lastfreq; int muted; - unsigned long bu2614data[BU2614_NOPS]; + u32 bu2614data; }; -enum { - BU2614_VOID, - BU2614_FREQ, /* D0..D15, Frequency data */ - BU2614_PORT, /* P0..P2, Output port control data */ - BU2614_FMES, /* CT, Frequency measurement beginning data */ - BU2614_STDF, /* R0..R2, Standard frequency data */ - BU2614_SWIN, /* S, Switch between FMIN / AMIN */ - BU2614_SWAL, /* PS, Swallow counter division (AMIN only) */ - BU2614_FMUN, /* GT, Frequency measurement time and unlock */ - BU2614_TEST /* TS, Test data is input */ -}; - -struct bu2614_op { - int op; /* Operation */ - int size; /* Data size */ -}; +#define BU2614_FREQ_BITS 16 /* D0..D15, Frequency data */ +#define BU2614_PORT_BITS 3 /* P0..P2, Output port control data */ +#define BU2614_VOID_BITS 4 /* unused */ +#define BU2614_FMES_BITS 1 /* CT, Frequency measurement beginning data */ +#define BU2614_STDF_BITS 3 /* R0..R2, Standard frequency data */ +#define BU2614_SWIN_BITS 1 /* S, Switch between FMIN / AMIN */ +#define BU2614_SWAL_BITS 1 /* PS, Swallow counter division (AMIN only)*/ +#define BU2614_VOID2_BITS 1 /* unused */ +#define BU2614_FMUN_BITS 1 /* GT, Frequency measurement time & unlock */ +#define BU2614_TEST_BITS 1 /* TS, Test data is input */ + +#define BU2614_FREQ_SHIFT 0 +#define BU2614_PORT_SHIFT (BU2614_FREQ_BITS + BU2614_FREQ_SHIFT) +#define BU2614_VOID_SHIFT (BU2614_PORT_BITS + BU2614_PORT_SHIFT) +#define BU2614_FMES_SHIFT (BU2614_VOID_BITS + BU2614_VOID_SHIFT) +#define BU2614_STDF_SHIFT (BU2614_FMES_BITS + BU2614_FMES_SHIFT) +#define BU2614_SWIN_SHIFT (BU2614_STDF_BITS + BU2614_STDF_SHIFT) +#define BU2614_SWAL_SHIFT (BU2614_SWIN_BITS + BU2614_SWIN_SHIFT) +#define BU2614_VOID2_SHIFT (BU2614_SWAL_BITS + BU2614_SWAL_SHIFT) +#define BU2614_FMUN_SHIFT (BU2614_VOID2_BITS + BU2614_VOID2_SHIFT) +#define BU2614_TEST_SHIFT (BU2614_FMUN_BITS + BU2614_FMUN_SHIFT) + +#define MKMASK(field) (((1<bu2614data); ++i) { - if (bu2614ops[i].op == op) { - dev->bu2614data[q] = - data & ((1 << bu2614ops[i].size) - 1); - return; - } - - if (bu2614ops[i].op != BU2614_VOID) - ++q; - } -} +#define gemtek_bu2614_set(dev, field, data) ((dev)->bu2614data = \ + ((dev)->bu2614data & ~field##_MASK) | ((data) << field##_SHIFT)) /* * Transmit settings to BU2614FS over GemTek IC. @@ -197,25 +177,12 @@ static void gemtek_bu2614_transmit(struct gemtek_device *dev) outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, io); udelay(LONG_DELAY); - for (i = 0, q = 0; q < ARRAY_SIZE(dev->bu2614data); ++i) { - for (bit = 0; bit < bu2614ops[i].size; ++bit) { - if (bu2614ops[i].op != BU2614_VOID && - dev->bu2614data[q] & (1 << bit)) { - outb_p(mute | GEMTEK_CE | GEMTEK_DA, io); - udelay(SHORT_DELAY); - outb_p(mute | GEMTEK_CE | GEMTEK_DA | - GEMTEK_CK, io); - udelay(SHORT_DELAY); - } else { - outb_p(mute | GEMTEK_CE, io); - udelay(SHORT_DELAY); - outb_p(mute | GEMTEK_CE | GEMTEK_CK, io); - udelay(SHORT_DELAY); - } - } - - if (bu2614ops[i].op != BU2614_VOID) - ++q; + for (i = 0, q = dev->bu2614data; i < 32; i++, q >>= 1) { + bit = (q & 1) ? GEMTEK_DA : 0; + outb_p(mute | GEMTEK_CE | bit, io); + udelay(SHORT_DELAY); + outb_p(mute | GEMTEK_CE | bit | GEMTEK_CK, io); + udelay(SHORT_DELAY); } outb_p(mute | GEMTEK_DA | GEMTEK_CK, io); @@ -612,8 +579,6 @@ static struct video_device gemtek_radio = { */ static int __init gemtek_init(void) { - int i; - printk(KERN_INFO RADIO_BANNER "\n"); spin_lock_init(&lock); @@ -651,8 +616,7 @@ static int __init gemtek_init(void) /* Set defaults */ gemtek_unit.lastfreq = GEMTEK_LOWFREQ; - for (i = 0; i < ARRAY_SIZE(gemtek_unit.bu2614data); ++i) - gemtek_unit.bu2614data[i] = 0; + gemtek_unit.bu2614data = 0; if (initmute) gemtek_mute(&gemtek_unit); -- cgit v1.2.3-70-g09d2 From 13595a51c0da8ec212ba6f5df79519dbd74166c0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 1 Oct 2007 08:51:39 -0300 Subject: V4L/DVB (6247): Fix bug #8689: Fixes IR stop/start during suspend/resume IR workqueue should be disabled during suspend. This avoids some troubles, like the one reported on bug #8689: "The Hauppauge HVR 1100 ir-remote control does not work after resume from suspend to ram or disk." This patch disables IR before suspending, re-enabling it after resume. Thanks to Peter Poklop for reporting it and helping with the fix. Signed-off-by: Mauro Carvalho Chehab Reviewed-by: Peter Poklop --- drivers/media/video/cx88/cx88-core.c | 3 +++ drivers/media/video/cx88/cx88-input.c | 4 ++-- drivers/media/video/cx88/cx88-video.c | 6 ++++++ drivers/media/video/cx88/cx88.h | 2 ++ 4 files changed, 13 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index 41f7f374c18..716154828ff 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -1084,6 +1084,9 @@ EXPORT_SYMBOL(cx88_vdev_init); EXPORT_SYMBOL(cx88_core_get); EXPORT_SYMBOL(cx88_core_put); +EXPORT_SYMBOL(cx88_ir_start); +EXPORT_SYMBOL(cx88_ir_stop); + /* * Local variables: * c-basic-offset: 8 diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index 78adf4d1cf6..e52de3968c6 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -158,7 +158,7 @@ static void cx88_ir_work(struct work_struct *work) mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling)); } -static void cx88_ir_start(struct cx88_core *core, struct cx88_IR *ir) +void cx88_ir_start(struct cx88_core *core, struct cx88_IR *ir) { if (ir->polling) { setup_timer(&ir->timer, ir_timer, (unsigned long)ir); @@ -172,7 +172,7 @@ static void cx88_ir_start(struct cx88_core *core, struct cx88_IR *ir) } } -static void cx88_ir_stop(struct cx88_core *core, struct cx88_IR *ir) +void cx88_ir_stop(struct cx88_core *core, struct cx88_IR *ir) { if (ir->sampling) { cx_write(MO_DDSCFG_IO, 0x0); diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index f94a3b41782..705c29b002e 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -1954,6 +1954,8 @@ static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state) } spin_unlock(&dev->slock); + if (core->ir) + cx88_ir_stop(core, core->ir); /* FIXME -- shutdown device */ cx88_shutdown(core); @@ -1993,6 +1995,10 @@ static int cx8800_resume(struct pci_dev *pci_dev) /* FIXME: re-initialize hardware */ cx88_reset(core); + if (core->ir) + cx88_ir_start(core, core->ir); + + cx_set(MO_PCI_INTMSK, core->pci_irqmask); /* restart video+vbi capture */ spin_lock(&dev->slock); diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index e436a37b440..0e4f8e27867 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -614,6 +614,8 @@ struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci); int cx88_ir_fini(struct cx88_core *core); void cx88_ir_irq(struct cx88_core *core); +void cx88_ir_start(struct cx88_core *core, struct cx88_IR *ir); +void cx88_ir_stop(struct cx88_core *core, struct cx88_IR *ir); /* ----------------------------------------------------------- */ /* cx88-mpeg.c */ -- cgit v1.2.3-70-g09d2 From b5457b7bdf284d683880163a4c59fdde2f84325a Mon Sep 17 00:00:00 2001 From: Sascha Sommer Date: Tue, 2 Oct 2007 12:23:39 -0300 Subject: V4L/DVB (6249): Add Typhoon Tv-Tuner PCI to bttv-cards.c Adds an entry for the Typhoon Tv-Tuner PCI to bttv-cards.c Signed-off-by: Sascha Sommer Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.bttv | 1 + drivers/media/video/bt8xx/bttv-cards.c | 17 +++++++++++++++++ drivers/media/video/bt8xx/bttv.h | 2 ++ 3 files changed, 20 insertions(+) (limited to 'drivers') diff --git a/Documentation/video4linux/CARDLIST.bttv b/Documentation/video4linux/CARDLIST.bttv index 177159c5f4c..d97cf7cc608 100644 --- a/Documentation/video4linux/CARDLIST.bttv +++ b/Documentation/video4linux/CARDLIST.bttv @@ -147,3 +147,4 @@ 146 -> SSAI Ultrasound Video Interface [414a:5353] 147 -> VoodooTV 200 (USA) [121a:3000] 148 -> DViCO FusionHDTV 2 [dbc0:d200] +149 -> Typhoon TV-Tuner PCI (50684) diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c index 900d18e1406..dd6a7d68b07 100644 --- a/drivers/media/video/bt8xx/bttv-cards.c +++ b/drivers/media/video/bt8xx/bttv-cards.c @@ -2988,6 +2988,23 @@ struct tvcard bttv_tvcards[] = { .no_tda9875 = 1, .no_tda7432 = 1, }, + /* ---- card 0x95---------------------------------- */ + [BTTV_BOARD_TYPHOON_TVTUNERPCI] = { + .name = "Typhoon TV-Tuner PCI (50684)", + .video_inputs = 3, + .audio_inputs = 1, + .tuner = 0, + .svhs = 2, + .gpiomask = 0x3014f, + .muxsel = { 2, 3, 1, 1 }, + .gpiomux = { 0x20001,0x10001, 0, 0 }, + .gpiomute = 10, + .needs_tvaudio = 1, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_PAL_I, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + }, }; static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards); diff --git a/drivers/media/video/bt8xx/bttv.h b/drivers/media/video/bt8xx/bttv.h index dcc847dc248..19e75d50a10 100644 --- a/drivers/media/video/bt8xx/bttv.h +++ b/drivers/media/video/bt8xx/bttv.h @@ -172,6 +172,8 @@ #define BTTV_BOARD_SSAI_ULTRASOUND 0x92 #define BTTV_BOARD_VOODOOTV_200 0x93 #define BTTV_BOARD_DVICO_FUSIONHDTV_2 0x94 +#define BTTV_BOARD_TYPHOON_TVTUNERPCI 0x95 + /* more card-specific defines */ #define PT2254_L_CHANNEL 0x10 -- cgit v1.2.3-70-g09d2 From 7c596fa964806acb3b5ababb7ec4e1da35b140b3 Mon Sep 17 00:00:00 2001 From: Brett Warden Date: Tue, 2 Oct 2007 17:37:21 -0300 Subject: V4L/DVB (6250): bw-qcam use data_reverse instead of manually poking the control register fix coding-style repairs Signed-off-by: Andrew Morton Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bw-qcam.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c index 0edd05ebcc3..7f7e3d3398d 100644 --- a/drivers/media/video/bw-qcam.c +++ b/drivers/media/video/bw-qcam.c @@ -104,7 +104,7 @@ static inline void write_lpdata(struct qcam_device *q, int d) static inline void write_lpcontrol(struct qcam_device *q, int d) { - if(0x20 & d) { + if (d & 0x20) { /* Set bidirectional mode to reverse (data in) */ parport_data_reverse(q->pport); } else { @@ -355,11 +355,11 @@ static int qc_detect(struct qcam_device *q) /* Be (even more) liberal in what you accept... */ /* if (count > 30 && count < 200) */ - if (count > 20 && count < 400) - { + if (count > 20 && count < 400) { return 1; /* found */ } else { - printk(KERN_ERR "No Quickcam found on port %s\n", q->pport->name); + printk(KERN_ERR "No Quickcam found on port %s\n", + q->pport->name); return 0; /* not found */ } } -- cgit v1.2.3-70-g09d2 From 7a7d9a89d0307b1743d782197e2c5fc5ddf183f3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 23 Aug 2007 16:26:14 -0300 Subject: V4L/DVB (6251): Replace video-buf to a more generic approach video-buf currently does two different tasks: - Manages video buffers with a common code that allows implementing all the V4L2 different modes of buffering; - Controls memory allocations While the first task is generic, the second were written to support PCI DMA Scatter/Gather needs. The original approach can't even work for those video capture hardware that don't support scatter/gather. I did one approach to make it more generic. While the approach worked fine for vivi driver, it were not generic enough to handle USB needs. This patch creates two different modules, one containing the generic video buffer handling (videobuf-core) and another with PCI DMA S/G. After this patch, it would be simpler to write an USB video-buf and a non-SG DMA module. Signed-off-by: Mauro Carvalho Chehab http://thread.gmane.org/gmane.comp.video.video4linux/34978/focus=34981 Reviewed-by: Ricardo Cerqueira --- drivers/media/video/videobuf-core.c | 976 ++++++++++++++++++++++++++++++++++ drivers/media/video/videobuf-dma-sg.c | 772 +++++++++++++++++++++++++++ include/media/videobuf-core.h | 236 ++++++++ include/media/videobuf-dma-sg.h | 142 +++++ 4 files changed, 2126 insertions(+) create mode 100644 drivers/media/video/videobuf-core.c create mode 100644 drivers/media/video/videobuf-dma-sg.c create mode 100644 include/media/videobuf-core.h create mode 100644 include/media/videobuf-dma-sg.h (limited to 'drivers') diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c new file mode 100644 index 00000000000..256501384af --- /dev/null +++ b/drivers/media/video/videobuf-core.c @@ -0,0 +1,976 @@ +/* + * generic helper functions for handling video4linux capture buffers + * + * (c) 2007 Mauro Carvalho Chehab, + * + * Highly based on video-buf written originally by: + * (c) 2001,02 Gerd Knorr + * (c) 2006 Mauro Carvalho Chehab, + * (c) 2006 Ted Walther and John Sokol + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 + */ + +#include +#include +#include +#include +#include + +#include + +#define MAGIC_BUFFER 0x20070728 +#define MAGIC_CHECK(is,should) if (unlikely((is) != (should))) \ + { printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); } + +static int debug = 0; +module_param(debug, int, 0644); + +MODULE_DESCRIPTION("helper module to manage video4linux buffers"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_LICENSE("GPL"); + +#define dprintk(level, fmt, arg...) if (debug >= level) \ + printk(KERN_DEBUG "vbuf: " fmt , ## arg) + +/* --------------------------------------------------------------------- */ + +#define CALL(q, f, arg...) \ + ( (q->int_ops->f)? q->int_ops->f(arg) : 0) + +void* videobuf_alloc(struct videobuf_queue* q) +{ + struct videobuf_buffer *vb; + + BUG_ON (q->msizeint_ops || !q->int_ops->alloc) { + printk(KERN_ERR "No specific ops defined!\n"); + BUG(); + } + + vb = q->int_ops->alloc(q->msize); + + if (NULL != vb) { + init_waitqueue_head(&vb->done); + vb->magic = MAGIC_BUFFER; + } + + return vb; +} + +int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr) +{ + int retval = 0; + DECLARE_WAITQUEUE(wait, current); + + MAGIC_CHECK(vb->magic,MAGIC_BUFFER); + add_wait_queue(&vb->done, &wait); + while (vb->state == STATE_ACTIVE || vb->state == STATE_QUEUED) { + if (non_blocking) { + retval = -EAGAIN; + break; + } + set_current_state(intr ? TASK_INTERRUPTIBLE + : TASK_UNINTERRUPTIBLE); + if (vb->state == STATE_ACTIVE || vb->state == STATE_QUEUED) + schedule(); + set_current_state(TASK_RUNNING); + if (intr && signal_pending(current)) { + dprintk(1,"buffer waiton: -EINTR\n"); + retval = -EINTR; + break; + } + } + remove_wait_queue(&vb->done, &wait); + return retval; +} + +int videobuf_iolock(struct videobuf_queue* q, struct videobuf_buffer *vb, + struct v4l2_framebuffer *fbuf) +{ + MAGIC_CHECK(vb->magic,MAGIC_BUFFER); + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + return CALL(q,iolock,q,vb,fbuf); +} + +/* --------------------------------------------------------------------- */ + + +void videobuf_queue_init(struct videobuf_queue* q, + struct videobuf_queue_ops *ops, + void *dev, + spinlock_t *irqlock, + enum v4l2_buf_type type, + enum v4l2_field field, + unsigned int msize, + void *priv) +{ + memset(q,0,sizeof(*q)); + q->irqlock = irqlock; + q->dev = dev; + q->type = type; + q->field = field; + q->msize = msize; + q->ops = ops; + q->priv_data = priv; + + /* All buffer operations are mandatory */ + BUG_ON (!q->ops->buf_setup); + BUG_ON (!q->ops->buf_prepare); + BUG_ON (!q->ops->buf_queue); + BUG_ON (!q->ops->buf_release); + + mutex_init(&q->lock); + INIT_LIST_HEAD(&q->stream); +} + +int videobuf_queue_is_busy(struct videobuf_queue *q) +{ + int i; + + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + if (q->streaming) { + dprintk(1,"busy: streaming active\n"); + return 1; + } + if (q->reading) { + dprintk(1,"busy: pending read #1\n"); + return 1; + } + if (q->read_buf) { + dprintk(1,"busy: pending read #2\n"); + return 1; + } + for (i = 0; i < VIDEO_MAX_FRAME; i++) { + if (NULL == q->bufs[i]) + continue; + if (CALL(q,is_mmapped,q->bufs[i])) { + dprintk(1,"busy: buffer #%d mapped\n",i); + return 1; + } + if (q->bufs[i]->state == STATE_QUEUED) { + dprintk(1,"busy: buffer #%d queued\n",i); + return 1; + } + if (q->bufs[i]->state == STATE_ACTIVE) { + dprintk(1,"busy: buffer #%d avtive\n",i); + return 1; + } + } + return 0; +} + +void videobuf_queue_cancel(struct videobuf_queue *q) +{ + unsigned long flags=0; + int i; + + /* remove queued buffers from list */ + if (q->irqlock) + spin_lock_irqsave(q->irqlock,flags); + for (i = 0; i < VIDEO_MAX_FRAME; i++) { + if (NULL == q->bufs[i]) + continue; + if (q->bufs[i]->state == STATE_QUEUED) { + list_del(&q->bufs[i]->queue); + q->bufs[i]->state = STATE_ERROR; + } + } + if (q->irqlock) + spin_unlock_irqrestore(q->irqlock,flags); + + /* free all buffers + clear queue */ + for (i = 0; i < VIDEO_MAX_FRAME; i++) { + if (NULL == q->bufs[i]) + continue; + q->ops->buf_release(q,q->bufs[i]); + } + INIT_LIST_HEAD(&q->stream); +} + +/* --------------------------------------------------------------------- */ + +enum v4l2_field videobuf_next_field(struct videobuf_queue *q) +{ + enum v4l2_field field = q->field; + + BUG_ON(V4L2_FIELD_ANY == field); + + if (V4L2_FIELD_ALTERNATE == field) { + if (V4L2_FIELD_TOP == q->last) { + field = V4L2_FIELD_BOTTOM; + q->last = V4L2_FIELD_BOTTOM; + } else { + field = V4L2_FIELD_TOP; + q->last = V4L2_FIELD_TOP; + } + } + return field; +} + +static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b, + struct videobuf_buffer *vb, enum v4l2_buf_type type) +{ + MAGIC_CHECK(vb->magic,MAGIC_BUFFER); + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + b->index = vb->i; + b->type = type; + + b->memory = vb->memory; + switch (b->memory) { + case V4L2_MEMORY_MMAP: + b->m.offset = vb->boff; + b->length = vb->bsize; + break; + case V4L2_MEMORY_USERPTR: + b->m.userptr = vb->baddr; + b->length = vb->bsize; + break; + case V4L2_MEMORY_OVERLAY: + b->m.offset = vb->boff; + break; + } + + b->flags = 0; + if (CALL(q,is_mmapped,vb)) + b->flags |= V4L2_BUF_FLAG_MAPPED; + + switch (vb->state) { + case STATE_PREPARED: + case STATE_QUEUED: + case STATE_ACTIVE: + b->flags |= V4L2_BUF_FLAG_QUEUED; + break; + case STATE_DONE: + case STATE_ERROR: + b->flags |= V4L2_BUF_FLAG_DONE; + break; + case STATE_NEEDS_INIT: + case STATE_IDLE: + /* nothing */ + break; + } + + if (vb->input != UNSET) { + b->flags |= V4L2_BUF_FLAG_INPUT; + b->input = vb->input; + } + + b->field = vb->field; + b->timestamp = vb->ts; + b->bytesused = vb->size; + b->sequence = vb->field_count >> 1; +} + +int videobuf_reqbufs(struct videobuf_queue *q, + struct v4l2_requestbuffers *req) +{ + unsigned int size,count; + int retval; + + if (req->type != q->type) { + dprintk(1,"reqbufs: queue type invalid\n"); + return -EINVAL; + } + if (req->count < 1) { + dprintk(1,"reqbufs: count invalid (%d)\n",req->count); + return -EINVAL; + } + if (req->memory != V4L2_MEMORY_MMAP && + req->memory != V4L2_MEMORY_USERPTR && + req->memory != V4L2_MEMORY_OVERLAY) { + dprintk(1,"reqbufs: memory type invalid\n"); + return -EINVAL; + } + + if (q->streaming) { + dprintk(1,"reqbufs: streaming already exists\n"); + return -EBUSY; + } + if (!list_empty(&q->stream)) { + dprintk(1,"reqbufs: stream running\n"); + return -EBUSY; + } + + mutex_lock(&q->lock); + count = req->count; + if (count > VIDEO_MAX_FRAME) + count = VIDEO_MAX_FRAME; + size = 0; + q->ops->buf_setup(q,&count,&size); + size = PAGE_ALIGN(size); + dprintk(1,"reqbufs: bufs=%d, size=0x%x [%d pages total]\n", + count, size, (count*size)>>PAGE_SHIFT); + + retval = videobuf_mmap_setup(q,count,size,req->memory); + if (retval < 0) { + dprintk(1,"reqbufs: mmap setup returned %d\n",retval); + goto done; + } + + req->count = count; + + done: + mutex_unlock(&q->lock); + return retval; +} + +int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b) +{ + if (unlikely(b->type != q->type)) { + dprintk(1,"querybuf: Wrong type.\n"); + return -EINVAL; + } + if (unlikely(b->index < 0 || b->index >= VIDEO_MAX_FRAME)) { + dprintk(1,"querybuf: index out of range.\n"); + return -EINVAL; + } + if (unlikely(NULL == q->bufs[b->index])) { + dprintk(1,"querybuf: buffer is null.\n"); + return -EINVAL; + } + videobuf_status(q,b,q->bufs[b->index],q->type); + return 0; +} + +int videobuf_qbuf(struct videobuf_queue *q, + struct v4l2_buffer *b) +{ + struct videobuf_buffer *buf; + enum v4l2_field field; + unsigned long flags=0; + int retval; + + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + mutex_lock(&q->lock); + retval = -EBUSY; + if (q->reading) { + dprintk(1,"qbuf: Reading running...\n"); + goto done; + } + retval = -EINVAL; + if (b->type != q->type) { + dprintk(1,"qbuf: Wrong type.\n"); + goto done; + } + if (b->index < 0 || b->index >= VIDEO_MAX_FRAME) { + dprintk(1,"qbuf: index out of range.\n"); + goto done; + } + buf = q->bufs[b->index]; + if (NULL == buf) { + dprintk(1,"qbuf: buffer is null.\n"); + goto done; + } + MAGIC_CHECK(buf->magic,MAGIC_BUFFER); + if (buf->memory != b->memory) { + dprintk(1,"qbuf: memory type is wrong.\n"); + goto done; + } + if (buf->state != STATE_NEEDS_INIT && buf->state != STATE_IDLE) { + dprintk(1,"qbuf: buffer is already queued or active.\n"); + goto done; + } + + if (b->flags & V4L2_BUF_FLAG_INPUT) { + if (b->input >= q->inputs) { + dprintk(1,"qbuf: wrong input.\n"); + goto done; + } + buf->input = b->input; + } else { + buf->input = UNSET; + } + + switch (b->memory) { + case V4L2_MEMORY_MMAP: + if (0 == buf->baddr) { + dprintk(1,"qbuf: mmap requested but buffer addr is zero!\n"); + goto done; + } + break; + case V4L2_MEMORY_USERPTR: + if (b->length < buf->bsize) { + dprintk(1,"qbuf: buffer length is not enough\n"); + goto done; + } + if (STATE_NEEDS_INIT != buf->state && buf->baddr != b->m.userptr) + q->ops->buf_release(q,buf); + buf->baddr = b->m.userptr; + break; + case V4L2_MEMORY_OVERLAY: + buf->boff = b->m.offset; + break; + default: + dprintk(1,"qbuf: wrong memory type\n"); + goto done; + } + + dprintk(1,"qbuf: requesting next field\n"); + field = videobuf_next_field(q); + retval = q->ops->buf_prepare(q,buf,field); + if (0 != retval) { + dprintk(1,"qbuf: buffer_prepare returned %d\n",retval); + goto done; + } + + list_add_tail(&buf->stream,&q->stream); + if (q->streaming) { + if (q->irqlock) + spin_lock_irqsave(q->irqlock,flags); + q->ops->buf_queue(q,buf); + if (q->irqlock) + spin_unlock_irqrestore(q->irqlock,flags); + } + dprintk(1,"qbuf: succeded\n"); + retval = 0; + + done: + mutex_unlock(&q->lock); + return retval; +} + +int videobuf_dqbuf(struct videobuf_queue *q, + struct v4l2_buffer *b, int nonblocking) +{ + struct videobuf_buffer *buf; + int retval; + + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + mutex_lock(&q->lock); + retval = -EBUSY; + if (q->reading) { + dprintk(1,"dqbuf: Reading running...\n"); + goto done; + } + retval = -EINVAL; + if (b->type != q->type) { + dprintk(1,"dqbuf: Wrong type.\n"); + goto done; + } + if (list_empty(&q->stream)) { + dprintk(1,"dqbuf: stream running\n"); + goto done; + } + buf = list_entry(q->stream.next, struct videobuf_buffer, stream); + retval = videobuf_waiton(buf, nonblocking, 1); + if (retval < 0) { + dprintk(1,"dqbuf: waiton returned %d\n",retval); + goto done; + } + switch (buf->state) { + case STATE_ERROR: + dprintk(1,"dqbuf: state is error\n"); + retval = -EIO; + CALL(q,sync,q, buf); + buf->state = STATE_IDLE; + break; + case STATE_DONE: + dprintk(1,"dqbuf: state is done\n"); + CALL(q,sync,q, buf); + buf->state = STATE_IDLE; + break; + default: + dprintk(1,"dqbuf: state invalid\n"); + retval = -EINVAL; + goto done; + } + list_del(&buf->stream); + memset(b,0,sizeof(*b)); + videobuf_status(q,b,buf,q->type); + + done: + mutex_unlock(&q->lock); + return retval; +} + +int videobuf_streamon(struct videobuf_queue *q) +{ + struct videobuf_buffer *buf; + struct list_head *list; + unsigned long flags=0; + int retval; + + mutex_lock(&q->lock); + retval = -EBUSY; + if (q->reading) + goto done; + retval = 0; + if (q->streaming) + goto done; + q->streaming = 1; + if (q->irqlock) + spin_lock_irqsave(q->irqlock,flags); + list_for_each(list,&q->stream) { + buf = list_entry(list, struct videobuf_buffer, stream); + if (buf->state == STATE_PREPARED) + q->ops->buf_queue(q,buf); + } + if (q->irqlock) + spin_unlock_irqrestore(q->irqlock,flags); + + done: + mutex_unlock(&q->lock); + return retval; +} + +int videobuf_streamoff(struct videobuf_queue *q) +{ + int retval = -EINVAL; + + mutex_lock(&q->lock); + if (!q->streaming) + goto done; + videobuf_queue_cancel(q); + q->streaming = 0; + retval = 0; + + done: + mutex_unlock(&q->lock); + return retval; +} + +static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q, + char __user *data, + size_t count, loff_t *ppos) +{ + enum v4l2_field field; + unsigned long flags=0; + int retval; + + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + /* setup stuff */ + q->read_buf = videobuf_alloc(q); + if (NULL == q->read_buf) + return -ENOMEM; + + q->read_buf->memory = V4L2_MEMORY_USERPTR; + q->read_buf->baddr = (unsigned long)data; + q->read_buf->bsize = count; + + field = videobuf_next_field(q); + retval = q->ops->buf_prepare(q,q->read_buf,field); + if (0 != retval) + goto done; + + /* start capture & wait */ + if (q->irqlock) + spin_lock_irqsave(q->irqlock,flags); + q->ops->buf_queue(q,q->read_buf); + if (q->irqlock) + spin_unlock_irqrestore(q->irqlock,flags); + retval = videobuf_waiton(q->read_buf,0,0); + if (0 == retval) { + CALL(q,sync,q,q->read_buf); + if (STATE_ERROR == q->read_buf->state) + retval = -EIO; + else + retval = q->read_buf->size; + } + + done: + /* cleanup */ + q->ops->buf_release(q,q->read_buf); + kfree(q->read_buf); + q->read_buf = NULL; + return retval; +} + +ssize_t videobuf_read_one(struct videobuf_queue *q, + char __user *data, size_t count, loff_t *ppos, + int nonblocking) +{ + enum v4l2_field field; + unsigned long flags=0; + unsigned size, nbufs; + int retval; + + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + mutex_lock(&q->lock); + + nbufs = 1; size = 0; + q->ops->buf_setup(q,&nbufs,&size); + + if (NULL == q->read_buf && + count >= size && + !nonblocking) { + retval = videobuf_read_zerocopy(q,data,count,ppos); + if (retval >= 0 || retval == -EIO) + /* ok, all done */ + goto done; + /* fallback to kernel bounce buffer on failures */ + } + + if (NULL == q->read_buf) { + /* need to capture a new frame */ + retval = -ENOMEM; + q->read_buf = videobuf_alloc(q); + + dprintk(1,"video alloc=0x%p\n", q->read_buf); + if (NULL == q->read_buf) + goto done; + q->read_buf->memory = V4L2_MEMORY_USERPTR; + q->read_buf->bsize = count; /* preferred size */ + field = videobuf_next_field(q); + retval = q->ops->buf_prepare(q,q->read_buf,field); + + if (0 != retval) { + kfree (q->read_buf); + q->read_buf = NULL; + goto done; + } + if (q->irqlock) + spin_lock_irqsave(q->irqlock,flags); + + q->ops->buf_queue(q,q->read_buf); + if (q->irqlock) + spin_unlock_irqrestore(q->irqlock,flags); + q->read_off = 0; + } + + /* wait until capture is done */ + retval = videobuf_waiton(q->read_buf, nonblocking, 1); + if (0 != retval) + goto done; + + CALL(q,sync,q,q->read_buf); + + if (STATE_ERROR == q->read_buf->state) { + /* catch I/O errors */ + q->ops->buf_release(q,q->read_buf); + kfree(q->read_buf); + q->read_buf = NULL; + retval = -EIO; + goto done; + } + + /* Copy to userspace */ + retval=CALL(q,copy_to_user,q,data,count,nonblocking); + if (retval<0) + goto done; + + q->read_off += retval; + if (q->read_off == q->read_buf->size) { + /* all data copied, cleanup */ + q->ops->buf_release(q,q->read_buf); + kfree(q->read_buf); + q->read_buf = NULL; + } + + done: + mutex_unlock(&q->lock); + return retval; +} + +int videobuf_read_start(struct videobuf_queue *q) +{ + enum v4l2_field field; + unsigned long flags=0; + int count = 0, size = 0; + int err, i; + + q->ops->buf_setup(q,&count,&size); + if (count < 2) + count = 2; + if (count > VIDEO_MAX_FRAME) + count = VIDEO_MAX_FRAME; + size = PAGE_ALIGN(size); + + err = videobuf_mmap_setup(q, count, size, V4L2_MEMORY_USERPTR); + if (err) + return err; + + for (i = 0; i < count; i++) { + field = videobuf_next_field(q); + err = q->ops->buf_prepare(q,q->bufs[i],field); + if (err) + return err; + list_add_tail(&q->bufs[i]->stream, &q->stream); + } + if (q->irqlock) + spin_lock_irqsave(q->irqlock,flags); + for (i = 0; i < count; i++) + q->ops->buf_queue(q,q->bufs[i]); + if (q->irqlock) + spin_unlock_irqrestore(q->irqlock,flags); + q->reading = 1; + return 0; +} + +void videobuf_read_stop(struct videobuf_queue *q) +{ + int i; + + videobuf_queue_cancel(q); + videobuf_mmap_free(q); + INIT_LIST_HEAD(&q->stream); + for (i = 0; i < VIDEO_MAX_FRAME; i++) { + if (NULL == q->bufs[i]) + continue; + kfree(q->bufs[i]); + q->bufs[i] = NULL; + } + q->read_buf = NULL; + q->reading = 0; +} + +ssize_t videobuf_read_stream(struct videobuf_queue *q, + char __user *data, size_t count, loff_t *ppos, + int vbihack, int nonblocking) +{ + int rc, retval; + unsigned long flags=0; + + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + dprintk(2,"%s\n",__FUNCTION__); + mutex_lock(&q->lock); + retval = -EBUSY; + if (q->streaming) + goto done; + if (!q->reading) { + retval = videobuf_read_start(q); + if (retval < 0) + goto done; + } + + retval = 0; + while (count > 0) { + /* get / wait for data */ + if (NULL == q->read_buf) { + q->read_buf = list_entry(q->stream.next, + struct videobuf_buffer, + stream); + list_del(&q->read_buf->stream); + q->read_off = 0; + } + rc = videobuf_waiton(q->read_buf, nonblocking, 1); + if (rc < 0) { + if (0 == retval) + retval = rc; + break; + } + + if (q->read_buf->state == STATE_DONE) { + rc = CALL (q,copy_stream, q, data, count, + retval, vbihack, nonblocking); + if (rc < 0) { + retval = rc; + break; + } + retval += rc; + count -= rc; + q->read_off += rc; + } else { + /* some error */ + q->read_off = q->read_buf->size; + if (0 == retval) + retval = -EIO; + } + + /* requeue buffer when done with copying */ + if (q->read_off == q->read_buf->size) { + list_add_tail(&q->read_buf->stream, + &q->stream); + if (q->irqlock) + spin_lock_irqsave(q->irqlock,flags); + q->ops->buf_queue(q,q->read_buf); + if (q->irqlock) + spin_unlock_irqrestore(q->irqlock,flags); + q->read_buf = NULL; + } + if (retval < 0) + break; + } + + done: + mutex_unlock(&q->lock); + return retval; +} + +unsigned int videobuf_poll_stream(struct file *file, + struct videobuf_queue *q, + poll_table *wait) +{ + struct videobuf_buffer *buf = NULL; + unsigned int rc = 0; + + mutex_lock(&q->lock); + if (q->streaming) { + if (!list_empty(&q->stream)) + buf = list_entry(q->stream.next, + struct videobuf_buffer, stream); + } else { + if (!q->reading) + videobuf_read_start(q); + if (!q->reading) { + rc = POLLERR; + } else if (NULL == q->read_buf) { + q->read_buf = list_entry(q->stream.next, + struct videobuf_buffer, + stream); + list_del(&q->read_buf->stream); + q->read_off = 0; + } + buf = q->read_buf; + } + if (!buf) + rc = POLLERR; + + if (0 == rc) { + poll_wait(file, &buf->done, wait); + if (buf->state == STATE_DONE || + buf->state == STATE_ERROR) + rc = POLLIN|POLLRDNORM; + } + mutex_unlock(&q->lock); + return rc; +} + +int videobuf_mmap_setup(struct videobuf_queue *q, + unsigned int bcount, unsigned int bsize, + enum v4l2_memory memory) +{ + unsigned int i; + int err; + + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + err = videobuf_mmap_free(q); + if (0 != err) + return err; + + /* Allocate and initialize buffers */ + for (i = 0; i < bcount; i++) { + q->bufs[i] = videobuf_alloc(q); + + q->bufs[i]->i = i; + q->bufs[i]->input = UNSET; + q->bufs[i]->memory = memory; + q->bufs[i]->bsize = bsize; + switch (memory) { + case V4L2_MEMORY_MMAP: + q->bufs[i]->boff = bsize * i; + break; + case V4L2_MEMORY_USERPTR: + case V4L2_MEMORY_OVERLAY: + /* nothing */ + break; + } + } + + dprintk(1,"mmap setup: %d buffers, %d bytes each\n", + bcount,bsize); + + return 0; +} + +int videobuf_mmap_free(struct videobuf_queue *q) +{ + int i; + int rc; + + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + rc = CALL(q,mmap_free,q); + if (rc<0) + return rc; + + for (i = 0; i < VIDEO_MAX_FRAME; i++) { + if (NULL == q->bufs[i]) + continue; + q->ops->buf_release(q,q->bufs[i]); + kfree(q->bufs[i]); + q->bufs[i] = NULL; + } + + return rc; +} + +int videobuf_mmap_mapper(struct videobuf_queue *q, + struct vm_area_struct *vma) +{ + int retval; + + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + mutex_lock(&q->lock); + retval=CALL(q,mmap_mapper,q,vma); + mutex_unlock(&q->lock); + + return retval; +} + +#ifdef CONFIG_VIDEO_V4L1_COMPAT +int videobuf_cgmbuf(struct videobuf_queue *q, + struct video_mbuf *mbuf, int count) +{ + struct v4l2_requestbuffers req; + int rc,i; + + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + + memset(&req,0,sizeof(req)); + req.type = q->type; + req.count = count; + req.memory = V4L2_MEMORY_MMAP; + rc = videobuf_reqbufs(q,&req); + if (rc < 0) + return rc; + + mbuf->frames = req.count; + mbuf->size = 0; + for (i = 0; i < mbuf->frames; i++) { + mbuf->offsets[i] = q->bufs[i]->boff; + mbuf->size += q->bufs[i]->bsize; + } + + return 0; +} +#endif + +/* --------------------------------------------------------------------- */ + +EXPORT_SYMBOL_GPL(videobuf_waiton); +EXPORT_SYMBOL_GPL(videobuf_iolock); + +EXPORT_SYMBOL_GPL(videobuf_alloc); + +EXPORT_SYMBOL_GPL(videobuf_queue_init); +EXPORT_SYMBOL_GPL(videobuf_queue_cancel); +EXPORT_SYMBOL_GPL(videobuf_queue_is_busy); + +EXPORT_SYMBOL_GPL(videobuf_next_field); +EXPORT_SYMBOL_GPL(videobuf_reqbufs); +EXPORT_SYMBOL_GPL(videobuf_querybuf); +EXPORT_SYMBOL_GPL(videobuf_qbuf); +EXPORT_SYMBOL_GPL(videobuf_dqbuf); +EXPORT_SYMBOL_GPL(videobuf_cgmbuf); +EXPORT_SYMBOL_GPL(videobuf_streamon); +EXPORT_SYMBOL_GPL(videobuf_streamoff); + +EXPORT_SYMBOL_GPL(videobuf_read_start); +EXPORT_SYMBOL_GPL(videobuf_read_stop); +EXPORT_SYMBOL_GPL(videobuf_read_stream); +EXPORT_SYMBOL_GPL(videobuf_read_one); +EXPORT_SYMBOL_GPL(videobuf_poll_stream); + +EXPORT_SYMBOL_GPL(videobuf_mmap_setup); +EXPORT_SYMBOL_GPL(videobuf_mmap_free); +EXPORT_SYMBOL_GPL(videobuf_mmap_mapper); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c new file mode 100644 index 00000000000..3345877c47d --- /dev/null +++ b/drivers/media/video/videobuf-dma-sg.c @@ -0,0 +1,772 @@ +/* + * helper functions for PCI DMA video4linux capture buffers + * + * The functions expect the hardware being able to scatter gatter + * (i.e. the buffers are not linear in physical memory, but fragmented + * into PAGE_SIZE chunks). They also assume the driver does not need + * to touch the video data. + * + * (c) 2007 Mauro Carvalho Chehab, + * + * Highly based on video-buf written originally by: + * (c) 2001,02 Gerd Knorr + * (c) 2006 Mauro Carvalho Chehab, + * (c) 2006 Ted Walther and John Sokol + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#define MAGIC_DMABUF 0x19721112 +#define MAGIC_SG_MEM 0x17890714 + +#define MAGIC_CHECK(is,should) if (unlikely((is) != (should))) \ + { printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); } + +static int debug = 0; +module_param(debug, int, 0644); + +MODULE_DESCRIPTION("helper module to manage video4linux pci dma sg buffers"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_LICENSE("GPL"); + +#define dprintk(level, fmt, arg...) if (debug >= level) \ + printk(KERN_DEBUG "vbuf-sg: " fmt , ## arg) + +/* --------------------------------------------------------------------- */ + +struct scatterlist* +videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages) +{ + struct scatterlist *sglist; + struct page *pg; + int i; + + sglist = kcalloc(nr_pages, sizeof(struct scatterlist), GFP_KERNEL); + if (NULL == sglist) + return NULL; + for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) { + pg = vmalloc_to_page(virt); + if (NULL == pg) + goto err; + BUG_ON(PageHighMem(pg)); + sglist[i].page = pg; + sglist[i].length = PAGE_SIZE; + } + return sglist; + + err: + kfree(sglist); + return NULL; +} + +struct scatterlist* +videobuf_pages_to_sg(struct page **pages, int nr_pages, int offset) +{ + struct scatterlist *sglist; + int i = 0; + + if (NULL == pages[0]) + return NULL; + sglist = kcalloc(nr_pages, sizeof(*sglist), GFP_KERNEL); + if (NULL == sglist) + return NULL; + + if (NULL == pages[0]) + goto nopage; + if (PageHighMem(pages[0])) + /* DMA to highmem pages might not work */ + goto highmem; + sglist[0].page = pages[0]; + sglist[0].offset = offset; + sglist[0].length = PAGE_SIZE - offset; + for (i = 1; i < nr_pages; i++) { + if (NULL == pages[i]) + goto nopage; + if (PageHighMem(pages[i])) + goto highmem; + sglist[i].page = pages[i]; + sglist[i].length = PAGE_SIZE; + } + return sglist; + + nopage: + dprintk(2,"sgl: oops - no page\n"); + kfree(sglist); + return NULL; + + highmem: + dprintk(2,"sgl: oops - highmem page\n"); + kfree(sglist); + return NULL; +} + +/* --------------------------------------------------------------------- */ + +struct videobuf_dmabuf *videobuf_to_dma (struct videobuf_buffer *buf) +{ + struct videbuf_pci_sg_memory *mem=buf->priv; + BUG_ON (!mem); + + MAGIC_CHECK(mem->magic,MAGIC_SG_MEM); + + return &mem->dma; +} + +void videobuf_dma_init(struct videobuf_dmabuf *dma) +{ + memset(dma,0,sizeof(*dma)); + dma->magic = MAGIC_DMABUF; +} + +int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, + unsigned long data, unsigned long size) +{ + unsigned long first,last; + int err, rw = 0; + + dma->direction = direction; + switch (dma->direction) { + case PCI_DMA_FROMDEVICE: rw = READ; break; + case PCI_DMA_TODEVICE: rw = WRITE; break; + default: BUG(); + } + + first = (data & PAGE_MASK) >> PAGE_SHIFT; + last = ((data+size-1) & PAGE_MASK) >> PAGE_SHIFT; + dma->offset = data & ~PAGE_MASK; + dma->nr_pages = last-first+1; + dma->pages = kmalloc(dma->nr_pages * sizeof(struct page*), + GFP_KERNEL); + if (NULL == dma->pages) + return -ENOMEM; + dprintk(1,"init user [0x%lx+0x%lx => %d pages]\n", + data,size,dma->nr_pages); + + dma->varea = (void *) data; + + down_read(¤t->mm->mmap_sem); + err = get_user_pages(current,current->mm, + data & PAGE_MASK, dma->nr_pages, + rw == READ, 1, /* force */ + dma->pages, NULL); + up_read(¤t->mm->mmap_sem); + if (err != dma->nr_pages) { + dma->nr_pages = (err >= 0) ? err : 0; + dprintk(1,"get_user_pages: err=%d [%d]\n",err,dma->nr_pages); + return err < 0 ? err : -EINVAL; + } + return 0; +} + +int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction, + int nr_pages) +{ + dprintk(1,"init kernel [%d pages]\n",nr_pages); + dma->direction = direction; + dma->vmalloc = vmalloc_32(nr_pages << PAGE_SHIFT); + if (NULL == dma->vmalloc) { + dprintk(1,"vmalloc_32(%d pages) failed\n",nr_pages); + return -ENOMEM; + } + dprintk(1,"vmalloc is at addr 0x%08lx, size=%d\n", + (unsigned long)dma->vmalloc, + nr_pages << PAGE_SHIFT); + memset(dma->vmalloc,0,nr_pages << PAGE_SHIFT); + dma->nr_pages = nr_pages; + return 0; +} + +int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction, + dma_addr_t addr, int nr_pages) +{ + dprintk(1,"init overlay [%d pages @ bus 0x%lx]\n", + nr_pages,(unsigned long)addr); + dma->direction = direction; + if (0 == addr) + return -EINVAL; + + dma->bus_addr = addr; + dma->nr_pages = nr_pages; + return 0; +} + +int videobuf_dma_map(struct videobuf_queue* q,struct videobuf_dmabuf *dma) +{ + void *dev=q->dev; + struct videobuf_dma_sg_ops *ops=q->priv_ops; + + MAGIC_CHECK(dma->magic,MAGIC_DMABUF); + BUG_ON(0 == dma->nr_pages); + + if (dma->pages) { + dma->sglist = videobuf_pages_to_sg(dma->pages, dma->nr_pages, + dma->offset); + } + if (dma->vmalloc) { + dma->sglist = videobuf_vmalloc_to_sg + (dma->vmalloc,dma->nr_pages); + } + if (dma->bus_addr) { + dma->sglist = kmalloc(sizeof(struct scatterlist), GFP_KERNEL); + if (NULL != dma->sglist) { + dma->sglen = 1; + sg_dma_address(&dma->sglist[0]) = dma->bus_addr & PAGE_MASK; + dma->sglist[0].offset = dma->bus_addr & ~PAGE_MASK; + sg_dma_len(&dma->sglist[0]) = dma->nr_pages * PAGE_SIZE; + } + } + if (NULL == dma->sglist) { + dprintk(1,"scatterlist is NULL\n"); + return -ENOMEM; + } + if (!dma->bus_addr) { + if (ops && ops->vb_map_sg) { + dma->sglen = ops->vb_map_sg(dev,dma->sglist, + dma->nr_pages, dma->direction); + } + if (0 == dma->sglen) { + printk(KERN_WARNING + "%s: videobuf_map_sg failed\n",__FUNCTION__); + kfree(dma->sglist); + dma->sglist = NULL; + dma->sglen = 0; + return -EIO; + } + } + return 0; +} + +int videobuf_dma_sync(struct videobuf_queue *q,struct videobuf_dmabuf *dma) +{ + void *dev=q->dev; + struct videobuf_dma_sg_ops *ops=q->priv_ops; + + MAGIC_CHECK(dma->magic,MAGIC_DMABUF); + BUG_ON(!dma->sglen); + + if (!dma->bus_addr && ops && ops->vb_dma_sync_sg) + ops->vb_dma_sync_sg(dev,dma->sglist,dma->nr_pages, + dma->direction); + + return 0; +} + +int videobuf_dma_unmap(struct videobuf_queue* q,struct videobuf_dmabuf *dma) +{ + void *dev=q->dev; + struct videobuf_dma_sg_ops *ops=q->priv_ops; + + MAGIC_CHECK(dma->magic,MAGIC_DMABUF); + if (!dma->sglen) + return 0; + + if (!dma->bus_addr && ops && ops->vb_unmap_sg) + ops->vb_unmap_sg(dev,dma->sglist,dma->nr_pages, + dma->direction); + kfree(dma->sglist); + dma->sglist = NULL; + dma->sglen = 0; + return 0; +} + +int videobuf_dma_free(struct videobuf_dmabuf *dma) +{ + MAGIC_CHECK(dma->magic,MAGIC_DMABUF); + BUG_ON(dma->sglen); + + if (dma->pages) { + int i; + for (i=0; i < dma->nr_pages; i++) + page_cache_release(dma->pages[i]); + kfree(dma->pages); + dma->pages = NULL; + } + + vfree(dma->vmalloc); + dma->vmalloc = NULL; + dma->varea = NULL; + + if (dma->bus_addr) { + dma->bus_addr = 0; + } + dma->direction = PCI_DMA_NONE; + return 0; +} + +/* --------------------------------------------------------------------- */ + +int videobuf_pci_dma_map(struct pci_dev *pci,struct videobuf_dmabuf *dma) +{ + struct videobuf_queue q; + struct videobuf_dma_sg_ops qops; + + q.dev=pci; + qops.vb_map_sg=(vb_map_sg_t *)pci_map_sg; + qops.vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; + q.priv_ops = &qops; + + return (videobuf_dma_map(&q,dma)); +} + +int videobuf_pci_dma_unmap(struct pci_dev *pci,struct videobuf_dmabuf *dma) +{ + struct videobuf_queue q; + struct videobuf_dma_sg_ops qops; + + q.dev=pci; + qops.vb_map_sg=(vb_map_sg_t *)pci_map_sg; + qops.vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; + q.priv_ops = &qops; + + return (videobuf_dma_unmap(&q,dma)); +} + +/* --------------------------------------------------------------------- */ + +static void +videobuf_vm_open(struct vm_area_struct *vma) +{ + struct videobuf_mapping *map = vma->vm_private_data; + + dprintk(2,"vm_open %p [count=%d,vma=%08lx-%08lx]\n",map, + map->count,vma->vm_start,vma->vm_end); + map->count++; +} + +static void +videobuf_vm_close(struct vm_area_struct *vma) +{ + struct videobuf_mapping *map = vma->vm_private_data; + struct videobuf_queue *q = map->q; + struct videbuf_pci_sg_memory *mem; + int i; + + dprintk(2,"vm_close %p [count=%d,vma=%08lx-%08lx]\n",map, + map->count,vma->vm_start,vma->vm_end); + + map->count--; + if (0 == map->count) { + dprintk(1,"munmap %p q=%p\n",map,q); + mutex_lock(&q->lock); + for (i = 0; i < VIDEO_MAX_FRAME; i++) { + if (NULL == q->bufs[i]) + continue; + mem=q->bufs[i]->priv; + + if (!mem) + continue; + + MAGIC_CHECK(mem->magic,MAGIC_SG_MEM); + + if (mem->map != map) + continue; + mem->map = NULL; + q->bufs[i]->baddr = 0; + q->ops->buf_release(q,q->bufs[i]); + } + mutex_unlock(&q->lock); + kfree(map); + } + return; +} + +/* + * Get a anonymous page for the mapping. Make sure we can DMA to that + * memory location with 32bit PCI devices (i.e. don't use highmem for + * now ...). Bounce buffers don't work very well for the data rates + * video capture has. + */ +static struct page* +videobuf_vm_nopage(struct vm_area_struct *vma, unsigned long vaddr, + int *type) +{ + struct page *page; + + dprintk(3,"nopage: fault @ %08lx [vma %08lx-%08lx]\n", + vaddr,vma->vm_start,vma->vm_end); + if (vaddr > vma->vm_end) + return NOPAGE_SIGBUS; + page = alloc_page(GFP_USER | __GFP_DMA32); + if (!page) + return NOPAGE_OOM; + clear_user_page(page_address(page), vaddr, page); + if (type) + *type = VM_FAULT_MINOR; + return page; +} + +static struct vm_operations_struct videobuf_vm_ops = +{ + .open = videobuf_vm_open, + .close = videobuf_vm_close, + .nopage = videobuf_vm_nopage, +}; + +/* --------------------------------------------------------------------- + * PCI handlers for the generic methods + */ + +/* Allocated area consists on 3 parts: + struct video_buffer + struct _buffer (cx88_buffer, saa7134_buf, ...) + struct videobuf_pci_sg_memory + */ + +static void *__videobuf_alloc(size_t size) +{ + struct videbuf_pci_sg_memory *mem; + struct videobuf_buffer *vb; + + vb = kzalloc(size+sizeof(*mem),GFP_KERNEL); + + mem = vb->priv = ((char *)vb)+size; + mem->magic=MAGIC_SG_MEM; + + videobuf_dma_init(&mem->dma); + + dprintk(1,"%s: allocated at %p(%ld+%ld) & %p(%ld)\n", + __FUNCTION__,vb,(long)sizeof(*vb),(long)size-sizeof(*vb), + mem,(long)sizeof(*mem)); + + return vb; +} + +static int __videobuf_iolock (struct videobuf_queue* q, + struct videobuf_buffer *vb, + struct v4l2_framebuffer *fbuf) +{ + int err,pages; + dma_addr_t bus; + struct videbuf_pci_sg_memory *mem=vb->priv; + BUG_ON(!mem); + + MAGIC_CHECK(mem->magic,MAGIC_SG_MEM); + + switch (vb->memory) { + case V4L2_MEMORY_MMAP: + case V4L2_MEMORY_USERPTR: + if (0 == vb->baddr) { + /* no userspace addr -- kernel bounce buffer */ + pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT; + err = videobuf_dma_init_kernel( &mem->dma, + PCI_DMA_FROMDEVICE, + pages ); + if (0 != err) + return err; + } else { + /* dma directly to userspace */ + err = videobuf_dma_init_user( &mem->dma, + PCI_DMA_FROMDEVICE, + vb->baddr,vb->bsize ); + if (0 != err) + return err; + } + break; + case V4L2_MEMORY_OVERLAY: + if (NULL == fbuf) + return -EINVAL; + /* FIXME: need sanity checks for vb->boff */ + /* + * Using a double cast to avoid compiler warnings when + * building for PAE. Compiler doesn't like direct casting + * of a 32 bit ptr to 64 bit integer. + */ + bus = (dma_addr_t)(unsigned long)fbuf->base + vb->boff; + pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT; + err = videobuf_dma_init_overlay(&mem->dma,PCI_DMA_FROMDEVICE, + bus, pages); + if (0 != err) + return err; + break; + default: + BUG(); + } + err = videobuf_dma_map(q,&mem->dma); + if (0 != err) + return err; + + return 0; +} + +static int __videobuf_sync(struct videobuf_queue *q, + struct videobuf_buffer *buf) +{ + struct videbuf_pci_sg_memory *mem=buf->priv; + BUG_ON (!mem); + MAGIC_CHECK(mem->magic,MAGIC_SG_MEM); + + return videobuf_dma_sync(q,&mem->dma); +} + +static int __videobuf_mmap_free(struct videobuf_queue *q) +{ + int i; + + for (i = 0; i < VIDEO_MAX_FRAME; i++) { + if (q->bufs[i]) { + struct videbuf_pci_sg_memory *mem=q->bufs[i]->priv; + if (mem && mem->map) + return -EBUSY; + } + } + + return 0; +} + +static int __videobuf_mmap_mapper(struct videobuf_queue *q, + struct vm_area_struct *vma) +{ + struct videbuf_pci_sg_memory *mem; + struct videobuf_mapping *map; + unsigned int first,last,size,i; + int retval; + + retval = -EINVAL; + if (!(vma->vm_flags & VM_WRITE)) { + dprintk(1,"mmap app bug: PROT_WRITE please\n"); + goto done; + } + if (!(vma->vm_flags & VM_SHARED)) { + dprintk(1,"mmap app bug: MAP_SHARED please\n"); + goto done; + } + + /* look for first buffer to map */ + for (first = 0; first < VIDEO_MAX_FRAME; first++) { + if (NULL == q->bufs[first]) + continue; + mem=q->bufs[first]->priv; + BUG_ON (!mem); + MAGIC_CHECK(mem->magic,MAGIC_SG_MEM); + + if (V4L2_MEMORY_MMAP != q->bufs[first]->memory) + continue; + if (q->bufs[first]->boff == (vma->vm_pgoff << PAGE_SHIFT)) + break; + } + if (VIDEO_MAX_FRAME == first) { + dprintk(1,"mmap app bug: offset invalid [offset=0x%lx]\n", + (vma->vm_pgoff << PAGE_SHIFT)); + goto done; + } + + /* look for last buffer to map */ + for (size = 0, last = first; last < VIDEO_MAX_FRAME; last++) { + if (NULL == q->bufs[last]) + continue; + if (V4L2_MEMORY_MMAP != q->bufs[last]->memory) + continue; + mem=q->bufs[last]->priv; + if (mem->map) { + retval = -EBUSY; + goto done; + } + size += q->bufs[last]->bsize; + if (size == (vma->vm_end - vma->vm_start)) + break; + } + if (VIDEO_MAX_FRAME == last) { + dprintk(1,"mmap app bug: size invalid [size=0x%lx]\n", + (vma->vm_end - vma->vm_start)); + goto done; + } + + /* create mapping + update buffer list */ + retval = -ENOMEM; + map = kmalloc(sizeof(struct videobuf_mapping),GFP_KERNEL); + if (NULL == map) + goto done; + for (size = 0, i = first; i <= last; size += q->bufs[i++]->bsize) { + mem=q->bufs[i]->priv; + mem->map = map; + q->bufs[i]->baddr = vma->vm_start + size; + } + map->count = 1; + map->start = vma->vm_start; + map->end = vma->vm_end; + map->q = q; + vma->vm_ops = &videobuf_vm_ops; + vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED; + vma->vm_flags &= ~VM_IO; /* using shared anonymous pages */ + vma->vm_private_data = map; + dprintk(1,"mmap %p: q=%p %08lx-%08lx pgoff %08lx bufs %d-%d\n", + map,q,vma->vm_start,vma->vm_end,vma->vm_pgoff,first,last); + retval = 0; + + done: + return retval; +} + +static int __videobuf_is_mmapped (struct videobuf_buffer *buf) +{ + struct videbuf_pci_sg_memory *mem=buf->priv; + + BUG_ON (!mem); + MAGIC_CHECK(mem->magic,MAGIC_SG_MEM); + + return (mem->map)?1:0; +} + +static int __videobuf_copy_to_user ( struct videobuf_queue *q, + char __user *data, size_t count, + int nonblocking ) +{ + struct videbuf_pci_sg_memory *mem=q->read_buf->priv; + BUG_ON (!mem); + MAGIC_CHECK(mem->magic,MAGIC_SG_MEM); + + /* copy to userspace */ + if (count > q->read_buf->size - q->read_off) + count = q->read_buf->size - q->read_off; + + if (copy_to_user(data, mem->dma.vmalloc+q->read_off, count)) + return -EFAULT; + + return count; +} + +static int __videobuf_copy_stream ( struct videobuf_queue *q, + char __user *data, size_t count, size_t pos, + int vbihack, int nonblocking ) +{ + unsigned int *fc; + struct videbuf_pci_sg_memory *mem=q->read_buf->priv; + BUG_ON (!mem); + MAGIC_CHECK(mem->magic,MAGIC_SG_MEM); + + if (vbihack) { + /* dirty, undocumented hack -- pass the frame counter + * within the last four bytes of each vbi data block. + * We need that one to maintain backward compatibility + * to all vbi decoding software out there ... */ + fc = (unsigned int*)mem->dma.vmalloc; + fc += (q->read_buf->size>>2) -1; + *fc = q->read_buf->field_count >> 1; + dprintk(1,"vbihack: %d\n",*fc); + } + + /* copy stuff using the common method */ + count = __videobuf_copy_to_user (q,data,count,nonblocking); + + if ( (count==-EFAULT) && (0 == pos) ) + return -EFAULT; + + return count; +} + +static struct videobuf_qtype_ops pci_ops = { + .magic = MAGIC_QTYPE_OPS, + + .alloc = __videobuf_alloc, + .iolock = __videobuf_iolock, + .sync = __videobuf_sync, + .mmap_free = __videobuf_mmap_free, + .mmap_mapper = __videobuf_mmap_mapper, + .is_mmapped = __videobuf_is_mmapped, + .copy_to_user = __videobuf_copy_to_user, + .copy_stream = __videobuf_copy_stream, +}; + +void *videobuf_pci_alloc (size_t size) +{ + struct videobuf_queue q; + + /* Required to make generic handler to call __videobuf_alloc */ + q.int_ops=&pci_ops; + + q.msize=size; + + return videobuf_alloc (&q); +} + +void videobuf_queue_pci_init(struct videobuf_queue* q, + struct videobuf_queue_ops *ops, + void *dev, + spinlock_t *irqlock, + enum v4l2_buf_type type, + enum v4l2_field field, + unsigned int msize, + void *priv) +{ + struct videobuf_dma_sg_ops *priv_ops; + + videobuf_queue_init(q, ops, dev, irqlock, type, field, msize, priv); + q->int_ops=&pci_ops; + + /* FIXME: the code bellow should be removed after having a proper + * memory allocation method for vivi and tm6000 + */ + q->priv_ops= kzalloc(sizeof(struct videobuf_dma_sg_ops), GFP_KERNEL); + BUG_ON (!q->priv_ops); + + priv_ops=q->priv_ops; + + /* Sets default methods for handling Scatter Gather mapping */ + priv_ops->vb_map_sg=(vb_map_sg_t *)pci_map_sg; + priv_ops->vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; + priv_ops->vb_dma_sync_sg=(vb_map_sg_t *)pci_dma_sync_sg_for_cpu; +} + +void videobuf_set_pci_ops (struct videobuf_queue* q, + struct videobuf_dma_sg_ops *ops) +{ + kfree (q->priv_ops); + + q->priv_ops=ops; + + if (!ops) + return; + + /* If not specified, defaults to PCI map sg */ + if (!ops->vb_map_sg) + ops->vb_map_sg=(vb_map_sg_t *)pci_map_sg; + + if (!ops->vb_dma_sync_sg) + ops->vb_dma_sync_sg=(vb_map_sg_t *)pci_dma_sync_sg_for_cpu; + if (!ops->vb_unmap_sg) + ops->vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; +} + + +/* --------------------------------------------------------------------- */ + +EXPORT_SYMBOL_GPL(videobuf_vmalloc_to_sg); + +EXPORT_SYMBOL_GPL(videobuf_to_dma); +EXPORT_SYMBOL_GPL(videobuf_dma_init); +EXPORT_SYMBOL_GPL(videobuf_dma_init_user); +EXPORT_SYMBOL_GPL(videobuf_dma_init_kernel); +EXPORT_SYMBOL_GPL(videobuf_dma_init_overlay); +EXPORT_SYMBOL_GPL(videobuf_dma_map); +EXPORT_SYMBOL_GPL(videobuf_dma_sync); +EXPORT_SYMBOL_GPL(videobuf_dma_unmap); +EXPORT_SYMBOL_GPL(videobuf_dma_free); + +EXPORT_SYMBOL_GPL(videobuf_pci_dma_map); +EXPORT_SYMBOL_GPL(videobuf_pci_dma_unmap); +EXPORT_SYMBOL_GPL(videobuf_pci_alloc); + +EXPORT_SYMBOL_GPL(videobuf_queue_pci_init); +EXPORT_SYMBOL_GPL(videobuf_set_pci_ops); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/include/media/videobuf-core.h b/include/media/videobuf-core.h new file mode 100644 index 00000000000..0ac21ae44f6 --- /dev/null +++ b/include/media/videobuf-core.h @@ -0,0 +1,236 @@ +/* + * generic helper functions for handling video4linux capture buffers + * + * (c) 2007 Mauro Carvalho Chehab, + * + * Highly based on video-buf written originally by: + * (c) 2001,02 Gerd Knorr + * (c) 2006 Mauro Carvalho Chehab, + * (c) 2006 Ted Walther and John Sokol + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 + */ + +#include +#ifdef CONFIG_VIDEO_V4L1_COMPAT +#include +#endif +#include + +#define UNSET (-1U) + + +struct videobuf_buffer; +struct videobuf_queue; + +/* --------------------------------------------------------------------- */ + +/* + * A small set of helper functions to manage video4linux buffers. + * + * struct videobuf_buffer holds the data structures used by the helper + * functions, additionally some commonly used fields for v4l buffers + * (width, height, lists, waitqueue) are in there. That struct should + * be used as first element in the drivers buffer struct. + * + * about the mmap helpers (videobuf_mmap_*): + * + * The mmaper function allows to map any subset of contingous buffers. + * This includes one mmap() call for all buffers (which the original + * video4linux API uses) as well as one mmap() for every single buffer + * (which v4l2 uses). + * + * If there is a valid mapping for a buffer, buffer->baddr/bsize holds + * userspace address + size which can be feeded into the + * videobuf_dma_init_user function listed above. + * + */ + +struct videobuf_mapping { + unsigned int count; + unsigned long start; + unsigned long end; + struct videobuf_queue *q; +}; + +enum videobuf_state { + STATE_NEEDS_INIT = 0, + STATE_PREPARED = 1, + STATE_QUEUED = 2, + STATE_ACTIVE = 3, + STATE_DONE = 4, + STATE_ERROR = 5, + STATE_IDLE = 6, +}; + +struct videobuf_buffer { + unsigned int i; + u32 magic; + + /* info about the buffer */ + unsigned int width; + unsigned int height; + unsigned int bytesperline; /* use only if != 0 */ + unsigned long size; + unsigned int input; + enum v4l2_field field; + enum videobuf_state state; + struct list_head stream; /* QBUF/DQBUF list */ + + /* touched by irq handler */ + struct list_head queue; + wait_queue_head_t done; + unsigned int field_count; + struct timeval ts; + + /* Memory type */ + enum v4l2_memory memory; + + /* buffer size */ + size_t bsize; + + /* buffer offset (mmap + overlay) */ + size_t boff; + + /* buffer addr (userland ptr!) */ + unsigned long baddr; + + /* Private pointer to allow specific methods to store their data */ + int privsize; + void *priv; +}; + +struct videobuf_queue_ops { + int (*buf_setup)(struct videobuf_queue *q, + unsigned int *count, unsigned int *size); + int (*buf_prepare)(struct videobuf_queue *q, + struct videobuf_buffer *vb, + enum v4l2_field field); + void (*buf_queue)(struct videobuf_queue *q, + struct videobuf_buffer *vb); + void (*buf_release)(struct videobuf_queue *q, + struct videobuf_buffer *vb); +}; + +#define MAGIC_QTYPE_OPS 0x12261003 + +/* Helper operations - device type dependent */ +struct videobuf_qtype_ops { + u32 magic; + + void* (*alloc) (size_t size); + int (*iolock) (struct videobuf_queue* q, + struct videobuf_buffer *vb, + struct v4l2_framebuffer *fbuf); + int (*mmap) (struct videobuf_queue *q, + unsigned int *count, + unsigned int *size, + enum v4l2_memory memory); + int (*sync) (struct videobuf_queue* q, + struct videobuf_buffer *buf); + int (*copy_to_user) (struct videobuf_queue *q, + char __user *data, + size_t count, + int nonblocking); + int (*copy_stream) (struct videobuf_queue *q, + char __user *data, + size_t count, + size_t pos, + int vbihack, + int nonblocking); + int (*mmap_free) (struct videobuf_queue *q); + int (*mmap_mapper) (struct videobuf_queue *q, + struct vm_area_struct *vma); + int (*is_mmapped) (struct videobuf_buffer *buf); +}; + +struct videobuf_queue { + struct mutex lock; + spinlock_t *irqlock; + void *dev; /* on pci, points to struct pci_dev */ + + enum v4l2_buf_type type; + unsigned int inputs; /* for V4L2_BUF_FLAG_INPUT */ + unsigned int msize; + enum v4l2_field field; + enum v4l2_field last; /* for field=V4L2_FIELD_ALTERNATE */ + struct videobuf_buffer *bufs[VIDEO_MAX_FRAME]; + struct videobuf_queue_ops *ops; + struct videobuf_qtype_ops *int_ops; + + /* capture via mmap() + ioctl(QBUF/DQBUF) */ + unsigned int streaming; + struct list_head stream; + + /* capture via read() */ + unsigned int reading; + unsigned int read_off; + struct videobuf_buffer *read_buf; + + /* driver private data */ + void *priv_data; + + /*FIXME: should be removed after completing the vb conversion */ + void *priv_ops; +}; + +int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr); +int videobuf_iolock(struct videobuf_queue* q, struct videobuf_buffer *vb, + struct v4l2_framebuffer *fbuf); + +void *videobuf_alloc(struct videobuf_queue* q); + +void videobuf_queue_init(struct videobuf_queue *q, + struct videobuf_queue_ops *ops, + void *dev, + spinlock_t *irqlock, + enum v4l2_buf_type type, + enum v4l2_field field, + unsigned int msize, + void *priv); +int videobuf_queue_is_busy(struct videobuf_queue *q); +void videobuf_queue_cancel(struct videobuf_queue *q); + +enum v4l2_field videobuf_next_field(struct videobuf_queue *q); +int videobuf_reqbufs(struct videobuf_queue *q, + struct v4l2_requestbuffers *req); +int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b); +int videobuf_qbuf(struct videobuf_queue *q, + struct v4l2_buffer *b); +int videobuf_dqbuf(struct videobuf_queue *q, + struct v4l2_buffer *b, int nonblocking); +#ifdef CONFIG_VIDEO_V4L1_COMPAT +int videobuf_cgmbuf(struct videobuf_queue *q, + struct video_mbuf *mbuf, int count); +#endif +int videobuf_streamon(struct videobuf_queue *q); +int videobuf_streamoff(struct videobuf_queue *q); + +int videobuf_read_start(struct videobuf_queue *q); +void videobuf_read_stop(struct videobuf_queue *q); +ssize_t videobuf_read_stream(struct videobuf_queue *q, + char __user *data, size_t count, loff_t *ppos, + int vbihack, int nonblocking); +ssize_t videobuf_read_one(struct videobuf_queue *q, + char __user *data, size_t count, loff_t *ppos, + int nonblocking); +unsigned int videobuf_poll_stream(struct file *file, + struct videobuf_queue *q, + poll_table *wait); + +int videobuf_mmap_setup(struct videobuf_queue *q, + unsigned int bcount, unsigned int bsize, + enum v4l2_memory memory); +int videobuf_mmap_free(struct videobuf_queue *q); +int videobuf_mmap_mapper(struct videobuf_queue *q, + struct vm_area_struct *vma); + +/* --------------------------------------------------------------------- */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/include/media/videobuf-dma-sg.h b/include/media/videobuf-dma-sg.h new file mode 100644 index 00000000000..62a3709905f --- /dev/null +++ b/include/media/videobuf-dma-sg.h @@ -0,0 +1,142 @@ +/* + * helper functions for PCI DMA video4linux capture buffers + * + * The functions expect the hardware being able to scatter gatter + * (i.e. the buffers are not linear in physical memory, but fragmented + * into PAGE_SIZE chunks). They also assume the driver does not need + * to touch the video data. + * + * (c) 2007 Mauro Carvalho Chehab, + * + * Highly based on video-buf written originally by: + * (c) 2001,02 Gerd Knorr + * (c) 2006 Mauro Carvalho Chehab, + * (c) 2006 Ted Walther and John Sokol + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 + */ + +#include + +/* --------------------------------------------------------------------- */ + +/* + * Return a scatterlist for some page-aligned vmalloc()'ed memory + * block (NULL on errors). Memory for the scatterlist is allocated + * using kmalloc. The caller must free the memory. + */ +struct scatterlist* videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages); + +/* + * Return a scatterlist for a an array of userpages (NULL on errors). + * Memory for the scatterlist is allocated using kmalloc. The caller + * must free the memory. + */ +struct scatterlist* videobuf_pages_to_sg(struct page **pages, int nr_pages, + int offset); + +/* --------------------------------------------------------------------- */ + +/* + * A small set of helper functions to manage buffers (both userland + * and kernel) for DMA. + * + * videobuf_dma_init_*() + * creates a buffer. The userland version takes a userspace + * pointer + length. The kernel version just wants the size and + * does memory allocation too using vmalloc_32(). + * + * videobuf_dma_*() + * see Documentation/DMA-mapping.txt, these functions to + * basically the same. The map function does also build a + * scatterlist for the buffer (and unmap frees it ...) + * + * videobuf_dma_free() + * no comment ... + * + */ + +struct videobuf_dmabuf { + u32 magic; + + /* for userland buffer */ + int offset; + struct page **pages; + + /* for kernel buffers */ + void *vmalloc; + + /* Stores the userspace pointer to vmalloc area */ + void *varea; + + /* for overlay buffers (pci-pci dma) */ + dma_addr_t bus_addr; + + /* common */ + struct scatterlist *sglist; + int sglen; + int nr_pages; + int direction; +}; + +struct videbuf_pci_sg_memory +{ + u32 magic; + + /* for mmap'ed buffers */ + struct videobuf_mapping *map; + struct videobuf_dmabuf dma; +}; + +/* FIXME: To be removed soon */ +typedef int (vb_map_sg_t)(void *dev, struct scatterlist *sglist, int nr_pages, + int direction); + +/* FIXME: To be removed soon */ +struct videobuf_dma_sg_ops +{ + vb_map_sg_t *vb_map_sg; + vb_map_sg_t *vb_dma_sync_sg; + vb_map_sg_t *vb_unmap_sg; + +}; + +void videobuf_dma_init(struct videobuf_dmabuf *dma); +int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, + unsigned long data, unsigned long size); +int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction, + int nr_pages); +int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction, + dma_addr_t addr, int nr_pages); +int videobuf_dma_free(struct videobuf_dmabuf *dma); + +int videobuf_dma_map(struct videobuf_queue* q,struct videobuf_dmabuf *dma); +int videobuf_dma_sync(struct videobuf_queue* q,struct videobuf_dmabuf *dma); +int videobuf_dma_unmap(struct videobuf_queue* q,struct videobuf_dmabuf *dma); +struct videobuf_dmabuf *videobuf_to_dma (struct videobuf_buffer *buf); + +void *videobuf_pci_alloc (size_t size); + +void videobuf_queue_pci_init(struct videobuf_queue* q, + struct videobuf_queue_ops *ops, + void *dev, + spinlock_t *irqlock, + enum v4l2_buf_type type, + enum v4l2_field field, + unsigned int msize, + void *priv); + + /*FIXME: these variants are used only on *-alsa code, where videobuf is + * used without queue + */ +int videobuf_pci_dma_map(struct pci_dev *pci,struct videobuf_dmabuf *dma); +int videobuf_pci_dma_unmap(struct pci_dev *pci,struct videobuf_dmabuf *dma); + +/* FIXME: temporary routine for vivi and tm6000, while lacking implementation + * of videobuf-vmalloc + */ +void videobuf_set_pci_ops (struct videobuf_queue* q, + struct videobuf_dma_sg_ops *ops); + -- cgit v1.2.3-70-g09d2 From c1accaa21bdef38ec0f36eaaf7ce3384fff9d0c5 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 23 Aug 2007 16:37:49 -0300 Subject: V4L/DVB (6252): Adapt drivers to use the newer videobuf modules PCI-dependent videobuf_foo methods were renamed as videobuf_pci_foo. Also, videobuf_dmabuf is now part of videobuf-dma-sg private struct. So, to access it, a subroutine call is needed. This patch renames all occurences of those function calls to be consistent with the video-buf split. Signed-off-by: Mauro Carvalho Chehab http://thread.gmane.org/gmane.comp.video.video4linux/34978/focus=34981 Reviewed-by: Ricardo Cerqueira --- Documentation/dvb/faq.txt | 2 +- drivers/media/Kconfig | 6 ++++- drivers/media/common/Kconfig | 2 +- drivers/media/common/saa7146_core.c | 2 +- drivers/media/common/saa7146_fops.c | 5 ++-- drivers/media/common/saa7146_vbi.c | 9 ++++--- drivers/media/common/saa7146_video.c | 9 ++++--- drivers/media/video/Kconfig | 2 +- drivers/media/video/Makefile | 3 ++- drivers/media/video/bt8xx/Kconfig | 2 +- drivers/media/video/bt8xx/bttv-driver.c | 17 +++++++----- drivers/media/video/bt8xx/bttv-risc.c | 35 +++++++++++++----------- drivers/media/video/bt8xx/bttv-vbi.c | 5 ++-- drivers/media/video/bt8xx/bttvp.h | 2 +- drivers/media/video/cafe_ccic.c | 2 +- drivers/media/video/cx88/Kconfig | 2 +- drivers/media/video/cx88/cx88-alsa.c | 24 ++++++++++------- drivers/media/video/cx88/cx88-blackbird.c | 2 +- drivers/media/video/cx88/cx88-core.c | 6 +++-- drivers/media/video/cx88/cx88-dvb.c | 2 +- drivers/media/video/cx88/cx88-mpeg.c | 3 ++- drivers/media/video/cx88/cx88-vbi.c | 3 ++- drivers/media/video/cx88/cx88-video.c | 38 +++++++-------------------- drivers/media/video/cx88/cx88.h | 2 +- drivers/media/video/saa7134/Kconfig | 2 +- drivers/media/video/saa7134/saa7134-core.c | 8 +++--- drivers/media/video/saa7134/saa7134-dvb.c | 2 +- drivers/media/video/saa7134/saa7134-empress.c | 2 +- drivers/media/video/saa7134/saa7134-ts.c | 6 +++-- drivers/media/video/saa7134/saa7134-vbi.c | 6 +++-- drivers/media/video/saa7134/saa7134-video.c | 34 +++++------------------- drivers/media/video/saa7134/saa7134.h | 2 +- drivers/media/video/video-buf-dvb.c | 6 +++-- include/media/saa7146_vv.h | 2 +- 34 files changed, 125 insertions(+), 130 deletions(-) (limited to 'drivers') diff --git a/Documentation/dvb/faq.txt b/Documentation/dvb/faq.txt index dbcedf5833e..2511a335abd 100644 --- a/Documentation/dvb/faq.txt +++ b/Documentation/dvb/faq.txt @@ -150,7 +150,7 @@ Some very frequently asked questions about linuxtv-dvb - saa7146_vv: SAA7146 video and vbi functions. These are only needed for full-featured cards. - - video-buf: capture helper module for the saa7146_vv driver. This + - videobuf-dma-sg: capture helper module for the saa7146_vv driver. This one is responsible to handle capture buffers. - dvb-ttpci: The main driver for AV7110 based, full-featured diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 3f8cfa873de..28ee65c5391 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -126,8 +126,12 @@ config TUNER_SIMPLE endif # VIDEO_TUNER_CUSTOMIZE -config VIDEO_BUF +config VIDEOBUF_GEN + tristate + +config VIDEOBUF_DMA_SG depends on PCI + select VIDEOBUF_GEN tristate config VIDEO_BUF_DVB diff --git a/drivers/media/common/Kconfig b/drivers/media/common/Kconfig index 5c63c8e24ee..c5092ef1082 100644 --- a/drivers/media/common/Kconfig +++ b/drivers/media/common/Kconfig @@ -5,5 +5,5 @@ config VIDEO_SAA7146 config VIDEO_SAA7146_VV tristate depends on VIDEO_DEV - select VIDEO_BUF + select VIDEOBUF_DMA_SG select VIDEO_SAA7146 diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c index 1c962a2b44d..365a22118a0 100644 --- a/drivers/media/common/saa7146_core.c +++ b/drivers/media/common/saa7146_core.c @@ -100,7 +100,7 @@ int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop) * general helper functions ****************************************************************************/ -/* this is videobuf_vmalloc_to_sg() from video-buf.c +/* this is videobuf_vmalloc_to_sg() from videobuf-dma-sg.c make sure virt has been allocated with vmalloc_32(), otherwise the BUG() may be triggered on highmem machines */ static struct scatterlist* vmalloc_to_sg(unsigned char *virt, int nr_pages) diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c index b4770aecc01..67d1b1b1b25 100644 --- a/drivers/media/common/saa7146_fops.c +++ b/drivers/media/common/saa7146_fops.c @@ -53,13 +53,14 @@ void saa7146_res_free(struct saa7146_fh *fh, unsigned int bits) void saa7146_dma_free(struct saa7146_dev *dev,struct videobuf_queue *q, struct saa7146_buf *buf) { + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); DEB_EE(("dev:%p, buf:%p\n",dev,buf)); BUG_ON(in_interrupt()); videobuf_waiton(&buf->vb,0,0); - videobuf_dma_unmap(q, &buf->vb.dma); - videobuf_dma_free(&buf->vb.dma); + videobuf_dma_unmap(q, dma); + videobuf_dma_free(dma); buf->vb.state = STATE_NEEDS_INIT; } diff --git a/drivers/media/common/saa7146_vbi.c b/drivers/media/common/saa7146_vbi.c index 063608462eb..6103484e444 100644 --- a/drivers/media/common/saa7146_vbi.c +++ b/drivers/media/common/saa7146_vbi.c @@ -165,7 +165,7 @@ static void saa7146_set_vbi_capture(struct saa7146_dev *dev, struct saa7146_buf /* we don't wait here for the first field anymore. this is different from the video capture and might cause that the first buffer is only half filled (with only one field). but since this is some sort of streaming data, this is not that negative. - but by doing this, we can use the whole engine from video-buf.c... */ + but by doing this, we can use the whole engine from videobuf-dma-sg.c... */ /* WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | e_wait); @@ -239,6 +239,8 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,e saa7146_dma_free(dev,q,buf); if (STATE_NEEDS_INIT == buf->vb.state) { + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + buf->vb.width = llength; buf->vb.height = lines; buf->vb.size = size; @@ -250,7 +252,8 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,e err = videobuf_iolock(q,&buf->vb, NULL); if (err) goto oops; - err = saa7146_pgtable_build_single(dev->pci, &buf->pt[2], buf->vb.dma.sglist, buf->vb.dma.sglen); + err = saa7146_pgtable_build_single(dev->pci, &buf->pt[2], + dma->sglist, dma->sglen); if (0 != err) return err; } @@ -404,7 +407,7 @@ static int vbi_open(struct saa7146_dev *dev, struct file *file) fh->vbi_fmt.start[1] = 312; fh->vbi_fmt.count[1] = 16; - videobuf_queue_init(&fh->vbi_q, &vbi_qops, + videobuf_queue_pci_init(&fh->vbi_q, &vbi_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VBI_CAPTURE, V4L2_FIELD_SEQ_TB, // FIXME: does this really work? diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c index 664280c78ff..29dbc602a48 100644 --- a/drivers/media/common/saa7146_video.c +++ b/drivers/media/common/saa7146_video.c @@ -594,8 +594,9 @@ static int set_control(struct saa7146_fh *fh, struct v4l2_control *c) static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *buf) { struct pci_dev *pci = dev->pci; - struct scatterlist *list = buf->vb.dma.sglist; - int length = buf->vb.dma.sglen; + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + struct scatterlist *list = dma->sglist; + int length = dma->sglen; struct saa7146_format *sfmt = format_by_fourcc(dev,buf->fmt->pixelformat); DEB_EE(("dev:%p, buf:%p, sg_len:%d\n",dev,buf,length)); @@ -655,7 +656,7 @@ static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *bu /* if we have a user buffer, the first page may not be aligned to a page boundary. */ - pt1->offset = buf->vb.dma.sglist->offset; + pt1->offset = list->offset; pt2->offset = pt1->offset+o1; pt3->offset = pt1->offset+o2; @@ -1411,7 +1412,7 @@ static int video_open(struct saa7146_dev *dev, struct file *file) sfmt = format_by_fourcc(dev,fh->video_fmt.pixelformat); fh->video_fmt.sizeimage = (fh->video_fmt.width * fh->video_fmt.height * sfmt->depth)/8; - videobuf_queue_init(&fh->video_q, &video_qops, + videobuf_queue_pci_init(&fh->video_q, &video_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED, diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 5d74925748c..c4f424422f7 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -364,7 +364,7 @@ endmenu # encoder / decoder chips config VIDEO_VIVI tristate "Virtual Video Driver" depends on VIDEO_V4L2 && !SPARC32 && !SPARC64 && PCI - select VIDEO_BUF + select VIDEOBUF_DMA_SG default n ---help--- Enables a virtual video driver. This device shows a color bar diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 9e99d2e1c1b..cb300241eb8 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -87,7 +87,8 @@ obj-$(CONFIG_TUNER_TDA8290) += tda8290.o obj-$(CONFIG_TUNER_TEA5767) += tea5767.o obj-$(CONFIG_TUNER_TEA5761) += tea5761.o -obj-$(CONFIG_VIDEO_BUF) += video-buf.o +obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o +obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o obj-$(CONFIG_VIDEO_BUF_DVB) += video-buf-dvb.o obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o diff --git a/drivers/media/video/bt8xx/Kconfig b/drivers/media/video/bt8xx/Kconfig index 58eae887a62..2ca162b390a 100644 --- a/drivers/media/video/bt8xx/Kconfig +++ b/drivers/media/video/bt8xx/Kconfig @@ -4,7 +4,7 @@ config VIDEO_BT848 select I2C_ALGOBIT select FW_LOADER select VIDEO_BTCX - select VIDEO_BUF + select VIDEOBUF_DMA_SG select VIDEO_IR select VIDEO_TUNER select VIDEO_TVEEPROM diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index 0711c950784..4ab4e14b5c6 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -2582,7 +2582,7 @@ static int setup_window(struct bttv_fh *fh, struct bttv *btv, if (check_btres(fh, RESOURCE_OVERLAY)) { struct bttv_buffer *new; - new = videobuf_alloc(sizeof(*new)); + new = videobuf_pci_alloc(sizeof(*new)); new->crop = btv->crop[!!fh->do_crop].rect; bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new); retval = bttv_switch_overlay(btv,fh,new); @@ -3048,7 +3048,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, mutex_lock(&fh->cap.lock); if (*on) { fh->ov.tvnorm = btv->tvnorm; - new = videobuf_alloc(sizeof(*new)); + new = videobuf_pci_alloc(sizeof(*new)); new->crop = btv->crop[!!fh->do_crop].rect; bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new); } else { @@ -3141,9 +3141,12 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, retval = -EIO; /* fall through */ case STATE_DONE: - videobuf_dma_sync(&fh->cap,&buf->vb.dma); + { + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + videobuf_dma_sync(&fh->cap,dma); bttv_dma_free(&fh->cap,btv,buf); break; + } default: retval = -EINVAL; break; @@ -3337,7 +3340,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, if (check_btres(fh, RESOURCE_OVERLAY)) { struct bttv_buffer *new; - new = videobuf_alloc(sizeof(*new)); + new = videobuf_pci_alloc(sizeof(*new)); new->crop = btv->crop[!!fh->do_crop].rect; bttv_overlay_risc(btv,&fh->ov,fh->ovfmt,new); retval = bttv_switch_overlay(btv,fh,new); @@ -3696,7 +3699,7 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait) mutex_unlock(&fh->cap.lock); return POLLERR; } - fh->cap.read_buf = videobuf_alloc(fh->cap.msize); + fh->cap.read_buf = videobuf_pci_alloc(fh->cap.msize); if (NULL == fh->cap.read_buf) { mutex_unlock(&fh->cap.lock); return POLLERR; @@ -3763,13 +3766,13 @@ static int bttv_open(struct inode *inode, struct file *file) fh->ov.setup_ok = 0; v4l2_prio_open(&btv->prio,&fh->prio); - videobuf_queue_init(&fh->cap, &bttv_video_qops, + videobuf_queue_pci_init(&fh->cap, &bttv_video_qops, btv->c.pci, &btv->s_lock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED, sizeof(struct bttv_buffer), fh); - videobuf_queue_init(&fh->vbi, &bttv_vbi_qops, + videobuf_queue_pci_init(&fh->vbi, &bttv_vbi_qops, btv->c.pci, &btv->s_lock, V4L2_BUF_TYPE_VBI_CAPTURE, V4L2_FIELD_SEQ_TB, diff --git a/drivers/media/video/bt8xx/bttv-risc.c b/drivers/media/video/bt8xx/bttv-risc.c index e7104d9cb4b..58986f1a5f1 100644 --- a/drivers/media/video/bt8xx/bttv-risc.c +++ b/drivers/media/video/bt8xx/bttv-risc.c @@ -574,10 +574,12 @@ bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc, void bttv_dma_free(struct videobuf_queue *q,struct bttv *btv, struct bttv_buffer *buf) { + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + BUG_ON(in_interrupt()); videobuf_waiton(&buf->vb,0,0); - videobuf_dma_unmap(q, &buf->vb.dma); - videobuf_dma_free(&buf->vb.dma); + videobuf_dma_unmap(q, dma); + videobuf_dma_free(dma); btcx_riscmem_free(btv->c.pci,&buf->bottom); btcx_riscmem_free(btv->c.pci,&buf->top); buf->vb.state = STATE_NEEDS_INIT; @@ -699,6 +701,7 @@ int bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf) { const struct bttv_tvnorm *tvnorm = bttv_tvnorms + buf->tvnorm; + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); dprintk(KERN_DEBUG "bttv%d: buffer field: %s format: %s size: %dx%d\n", @@ -716,25 +719,25 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf) switch (buf->vb.field) { case V4L2_FIELD_TOP: - bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist, + bttv_risc_packed(btv,&buf->top,dma->sglist, /* offset */ 0,bpl, /* padding */ 0,/* skip_lines */ 0, buf->vb.height); break; case V4L2_FIELD_BOTTOM: - bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist, + bttv_risc_packed(btv,&buf->bottom,dma->sglist, 0,bpl,0,0,buf->vb.height); break; case V4L2_FIELD_INTERLACED: - bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist, + bttv_risc_packed(btv,&buf->top,dma->sglist, 0,bpl,bpl,0,buf->vb.height >> 1); - bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist, + bttv_risc_packed(btv,&buf->bottom,dma->sglist, bpl,bpl,bpl,0,buf->vb.height >> 1); break; case V4L2_FIELD_SEQ_TB: - bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist, + bttv_risc_packed(btv,&buf->top,dma->sglist, 0,bpl,0,0,buf->vb.height >> 1); - bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist, + bttv_risc_packed(btv,&buf->bottom,dma->sglist, bpf,bpl,0,0,buf->vb.height >> 1); break; default: @@ -767,7 +770,7 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf) bttv_calc_geo(btv,&buf->geo,buf->vb.width, buf->vb.height,/* both_fields */ 0, tvnorm,&buf->crop); - bttv_risc_planar(btv, &buf->top, buf->vb.dma.sglist, + bttv_risc_planar(btv, &buf->top, dma->sglist, 0,buf->vb.width,0,buf->vb.height, uoffset,voffset,buf->fmt->hshift, buf->fmt->vshift,0); @@ -776,7 +779,7 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf) bttv_calc_geo(btv,&buf->geo,buf->vb.width, buf->vb.height,0, tvnorm,&buf->crop); - bttv_risc_planar(btv, &buf->bottom, buf->vb.dma.sglist, + bttv_risc_planar(btv, &buf->bottom, dma->sglist, 0,buf->vb.width,0,buf->vb.height, uoffset,voffset,buf->fmt->hshift, buf->fmt->vshift,0); @@ -789,14 +792,14 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf) ypadding = buf->vb.width; cpadding = buf->vb.width >> buf->fmt->hshift; bttv_risc_planar(btv,&buf->top, - buf->vb.dma.sglist, + dma->sglist, 0,buf->vb.width,ypadding,lines, uoffset,voffset, buf->fmt->hshift, buf->fmt->vshift, cpadding); bttv_risc_planar(btv,&buf->bottom, - buf->vb.dma.sglist, + dma->sglist, ypadding,buf->vb.width,ypadding,lines, uoffset+cpadding, voffset+cpadding, @@ -812,7 +815,7 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf) ypadding = buf->vb.width; cpadding = buf->vb.width >> buf->fmt->hshift; bttv_risc_planar(btv,&buf->top, - buf->vb.dma.sglist, + dma->sglist, 0,buf->vb.width,0,lines, uoffset >> 1, voffset >> 1, @@ -820,7 +823,7 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf) buf->fmt->vshift, 0); bttv_risc_planar(btv,&buf->bottom, - buf->vb.dma.sglist, + dma->sglist, lines * ypadding,buf->vb.width,0,lines, lines * ypadding + (uoffset >> 1), lines * ypadding + (voffset >> 1), @@ -839,10 +842,10 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf) buf->vb.field = V4L2_FIELD_SEQ_TB; bttv_calc_geo(btv,&buf->geo,tvnorm->swidth,tvnorm->sheight, 1,tvnorm,&buf->crop); - bttv_risc_packed(btv, &buf->top, buf->vb.dma.sglist, + bttv_risc_packed(btv, &buf->top, dma->sglist, /* offset */ 0, RAW_BPL, /* padding */ 0, /* skip_lines */ 0, RAW_LINES); - bttv_risc_packed(btv, &buf->bottom, buf->vb.dma.sglist, + bttv_risc_packed(btv, &buf->bottom, dma->sglist, buf->vb.size/2 , RAW_BPL, 0, 0, RAW_LINES); } diff --git a/drivers/media/video/bt8xx/bttv-vbi.c b/drivers/media/video/bt8xx/bttv-vbi.c index 007485aa4f0..346ce019bdc 100644 --- a/drivers/media/video/bt8xx/bttv-vbi.c +++ b/drivers/media/video/bt8xx/bttv-vbi.c @@ -150,13 +150,14 @@ static int vbi_buffer_prepare(struct videobuf_queue *q, if (redo_dma_risc) { unsigned int bpl, padding, offset; + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); bpl = 2044; /* max. vbipack */ padding = VBI_BPL - bpl; if (fh->vbi_fmt.fmt.count[0] > 0) { rc = bttv_risc_packed(btv, &buf->top, - buf->vb.dma.sglist, + dma->sglist, /* offset */ 0, bpl, padding, skip_lines0, fh->vbi_fmt.fmt.count[0]); @@ -168,7 +169,7 @@ static int vbi_buffer_prepare(struct videobuf_queue *q, offset = fh->vbi_fmt.fmt.count[0] * VBI_BPL; rc = bttv_risc_packed(btv, &buf->bottom, - buf->vb.dma.sglist, + dma->sglist, offset, bpl, padding, skip_lines1, fh->vbi_fmt.fmt.count[1]); diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h index 5b25faca150..0b92c35a843 100644 --- a/drivers/media/video/bt8xx/bttvp.h +++ b/drivers/media/video/bt8xx/bttvp.h @@ -41,7 +41,7 @@ #include #include -#include +#include #include #include #include diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c index ccb37006bb1..b63cab33692 100644 --- a/drivers/media/video/cafe_ccic.c +++ b/drivers/media/video/cafe_ccic.c @@ -1197,7 +1197,7 @@ static int cafe_setup_siobuf(struct cafe_camera *cam, int index) buf->v4lbuf.field = V4L2_FIELD_NONE; buf->v4lbuf.memory = V4L2_MEMORY_MMAP; /* - * Offset: must be 32-bit even on a 64-bit system. video-buf + * Offset: must be 32-bit even on a 64-bit system. videobuf-dma-sg * just uses the length times the index, but the spec warns * against doing just that - vma merging problems. So we * leave a gap between each pair of buffers. diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig index f750a543c96..c68ba74d44e 100644 --- a/drivers/media/video/cx88/Kconfig +++ b/drivers/media/video/cx88/Kconfig @@ -4,7 +4,7 @@ config VIDEO_CX88 select I2C_ALGOBIT select FW_LOADER select VIDEO_BTCX - select VIDEO_BUF + select VIDEOBUF_DMA_SG select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEO_IR diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index f4abed454fd..90c36c5705c 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -72,7 +72,7 @@ struct cx88_audio_dev { unsigned int period_size; unsigned int num_periods; - struct videobuf_dmabuf dma_risc; + struct videobuf_dmabuf *dma_risc; struct cx88_buffer *buf; @@ -282,11 +282,12 @@ static int dsp_buffer_free(snd_cx88_card_t *chip) BUG_ON(!chip->dma_size); dprintk(2,"Freeing buffer\n"); - videobuf_pci_dma_unmap(chip->pci, &chip->dma_risc); - videobuf_dma_free(&chip->dma_risc); + videobuf_pci_dma_unmap(chip->pci, chip->dma_risc); + videobuf_dma_free(chip->dma_risc); btcx_riscmem_free(chip->pci,&chip->buf->risc); kfree(chip->buf); + chip->dma_risc = NULL; chip->dma_size = 0; return 0; @@ -366,6 +367,8 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream, struct snd_pcm_hw_params * hw_params) { snd_cx88_card_t *chip = snd_pcm_substream_chip(substream); + struct videobuf_dmabuf *dma; + struct cx88_buffer *buf; int ret; @@ -381,7 +384,7 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream, BUG_ON(!chip->dma_size); BUG_ON(chip->num_periods & (chip->num_periods-1)); - buf = kzalloc(sizeof(*buf), GFP_KERNEL); + buf = videobuf_pci_alloc(sizeof(*buf)); if (NULL == buf) return -ENOMEM; @@ -392,17 +395,18 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream, buf->vb.height = chip->num_periods; buf->vb.size = chip->dma_size; - videobuf_dma_init(&buf->vb.dma); - ret = videobuf_dma_init_kernel(&buf->vb.dma, PCI_DMA_FROMDEVICE, + dma=videobuf_to_dma(&buf->vb); + videobuf_dma_init(dma); + ret = videobuf_dma_init_kernel(dma, PCI_DMA_FROMDEVICE, (PAGE_ALIGN(buf->vb.size) >> PAGE_SHIFT)); if (ret < 0) goto error; - ret = videobuf_pci_dma_map(chip->pci,&buf->vb.dma); + ret = videobuf_pci_dma_map(chip->pci,dma); if (ret < 0) goto error; - ret = cx88_risc_databuffer(chip->pci, &buf->risc, buf->vb.dma.sglist, + ret = cx88_risc_databuffer(chip->pci, &buf->risc, dma->sglist, buf->vb.width, buf->vb.height, 1); if (ret < 0) goto error; @@ -414,9 +418,9 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream, buf->vb.state = STATE_PREPARED; chip->buf = buf; - chip->dma_risc = buf->vb.dma; + chip->dma_risc = dma; - substream->runtime->dma_area = chip->dma_risc.vmalloc; + substream->runtime->dma_area = chip->dma_risc->vmalloc; substream->runtime->dma_bytes = chip->dma_size; substream->runtime->dma_addr = 0; return 0; diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index fcaf4f51293..6d6f5048d76 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -1111,7 +1111,7 @@ static int mpeg_open(struct inode *inode, struct file *file) file->private_data = fh; fh->dev = dev; - videobuf_queue_init(&fh->mpegq, &blackbird_qops, + videobuf_queue_pci_init(&fh->mpegq, &blackbird_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED, diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index 716154828ff..85609b41f86 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -213,10 +213,12 @@ int cx88_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, void cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf) { + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + BUG_ON(in_interrupt()); videobuf_waiton(&buf->vb,0,0); - videobuf_dma_unmap(q, &buf->vb.dma); - videobuf_dma_free(&buf->vb.dma); + videobuf_dma_unmap(q, dma); + videobuf_dma_free(dma); btcx_riscmem_free((struct pci_dev *)q->dev, &buf->risc); buf->vb.state = STATE_NEEDS_INIT; } diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index 00d0e43785a..d16e5c6d21c 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -710,7 +710,7 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv) /* dvb stuff */ printk(KERN_INFO "%s/2: cx2388x based DVB/ATSC card\n", core->name); - videobuf_queue_init(&dev->dvb.dvbq, &dvb_qops, + videobuf_queue_pci_init(&dev->dvb.dvbq, &dvb_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_TOP, diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index d302793fcfb..a652f294d23 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -237,6 +237,7 @@ int cx8802_buf_prepare(struct videobuf_queue *q, struct cx8802_dev *dev, struct cx88_buffer *buf, enum v4l2_field field) { int size = dev->ts_packet_size * dev->ts_packet_count; + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); int rc; dprintk(1, "%s: %p\n", __FUNCTION__, buf); @@ -252,7 +253,7 @@ int cx8802_buf_prepare(struct videobuf_queue *q, struct cx8802_dev *dev, if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL))) goto fail; cx88_risc_databuffer(dev->pci, &buf->risc, - buf->vb.dma.sglist, + dma->sglist, buf->vb.width, buf->vb.height, 0); } buf->vb.state = STATE_PREPARED; diff --git a/drivers/media/video/cx88/cx88-vbi.c b/drivers/media/video/cx88/cx88-vbi.c index 72c1d19fa79..aa40505c4b3 100644 --- a/drivers/media/video/cx88/cx88-vbi.c +++ b/drivers/media/video/cx88/cx88-vbi.c @@ -172,6 +172,7 @@ vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, return -EINVAL; if (STATE_NEEDS_INIT == buf->vb.state) { + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); buf->vb.width = VBI_LINE_LENGTH; buf->vb.height = VBI_LINE_COUNT; buf->vb.size = size; @@ -180,7 +181,7 @@ vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL))) goto fail; cx88_risc_buffer(dev->pci, &buf->risc, - buf->vb.dma.sglist, + dma->sglist, 0, buf->vb.width * buf->vb.height, buf->vb.width, 0, buf->vb.height); diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index 705c29b002e..1439b726853 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -534,6 +534,7 @@ buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, struct cx8800_dev *dev = fh->dev; struct cx88_core *core = dev->core; struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb); + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); int rc, init_buffer = 0; BUG_ON(NULL == fh->fmt); @@ -566,30 +567,30 @@ buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, switch (buf->vb.field) { case V4L2_FIELD_TOP: cx88_risc_buffer(dev->pci, &buf->risc, - buf->vb.dma.sglist, 0, UNSET, + dma->sglist, 0, UNSET, buf->bpl, 0, buf->vb.height); break; case V4L2_FIELD_BOTTOM: cx88_risc_buffer(dev->pci, &buf->risc, - buf->vb.dma.sglist, UNSET, 0, + dma->sglist, UNSET, 0, buf->bpl, 0, buf->vb.height); break; case V4L2_FIELD_INTERLACED: cx88_risc_buffer(dev->pci, &buf->risc, - buf->vb.dma.sglist, 0, buf->bpl, + dma->sglist, 0, buf->bpl, buf->bpl, buf->bpl, buf->vb.height >> 1); break; case V4L2_FIELD_SEQ_TB: cx88_risc_buffer(dev->pci, &buf->risc, - buf->vb.dma.sglist, + dma->sglist, 0, buf->bpl * (buf->vb.height >> 1), buf->bpl, 0, buf->vb.height >> 1); break; case V4L2_FIELD_SEQ_BT: cx88_risc_buffer(dev->pci, &buf->risc, - buf->vb.dma.sglist, + dma->sglist, buf->bpl * (buf->vb.height >> 1), 0, buf->bpl, 0, buf->vb.height >> 1); @@ -752,13 +753,13 @@ static int video_open(struct inode *inode, struct file *file) fh->height = 240; fh->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); - videobuf_queue_init(&fh->vidq, &cx8800_video_qops, + videobuf_queue_pci_init(&fh->vidq, &cx8800_video_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED, sizeof(struct cx88_buffer), fh); - videobuf_queue_init(&fh->vbiq, &cx8800_vbi_qops, + videobuf_queue_pci_init(&fh->vbiq, &cx8800_vbi_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VBI_CAPTURE, V4L2_FIELD_SEQ_TB, @@ -1104,28 +1105,9 @@ static int vidioc_enum_fmt_cap (struct file *file, void *priv, #ifdef CONFIG_VIDEO_V4L1_COMPAT static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf) { - struct cx8800_fh *fh = priv; - struct videobuf_queue *q; - struct v4l2_requestbuffers req; - unsigned int i; - int err; + struct cx8800_fh *fh = priv; - q = get_queue(fh); - memset(&req,0,sizeof(req)); - req.type = q->type; - req.count = 8; - req.memory = V4L2_MEMORY_MMAP; - err = videobuf_reqbufs(q,&req); - if (err < 0) - return err; - - mbuf->frames = req.count; - mbuf->size = 0; - for (i = 0; i < mbuf->frames; i++) { - mbuf->offsets[i] = q->bufs[i]->boff; - mbuf->size += q->bufs[i]->bsize; - } - return 0; + return videobuf_cgmbuf (get_queue(fh), mbuf, 8); } #endif diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index 0e4f8e27867..875a9abab2a 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include #if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE) diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig index 9f1417a4f7d..82bc4ef414a 100644 --- a/drivers/media/video/saa7134/Kconfig +++ b/drivers/media/video/saa7134/Kconfig @@ -1,7 +1,7 @@ config VIDEO_SAA7134 tristate "Philips SAA7134 support" depends on VIDEO_DEV && PCI && I2C - select VIDEO_BUF + select VIDEOBUF_DMA_SG select VIDEO_IR select VIDEO_TUNER select CRC32 diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index 80108ddf483..a1d986e01a3 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -236,9 +236,10 @@ int saa7134_buffer_startpage(struct saa7134_buf *buf) unsigned long saa7134_buffer_base(struct saa7134_buf *buf) { unsigned long base; + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); base = saa7134_buffer_startpage(buf) * 4096; - base += buf->vb.dma.sglist[0].offset; + base += dma->sglist[0].offset; return base; } @@ -286,11 +287,12 @@ void saa7134_pgtable_free(struct pci_dev *pci, struct saa7134_pgtable *pt) void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf) { + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); BUG_ON(in_interrupt()); videobuf_waiton(&buf->vb,0,0); - videobuf_dma_unmap(q, &buf->vb.dma); - videobuf_dma_free(&buf->vb.dma); + videobuf_dma_unmap(q, dma); + videobuf_dma_free(dma); buf->vb.state = STATE_NEEDS_INIT; } diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index bbab252cbee..38d87332cc5 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -850,7 +850,7 @@ static int dvb_init(struct saa7134_dev *dev) dev->ts.nr_bufs = 32; dev->ts.nr_packets = 32*4; dev->dvb.name = dev->name; - videobuf_queue_init(&dev->dvb.dvbq, &saa7134_ts_qops, + videobuf_queue_pci_init(&dev->dvb.dvbq, &saa7134_ts_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_ALTERNATE, diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c index 7ed4eaf05e1..a16df57af63 100644 --- a/drivers/media/video/saa7134/saa7134-empress.c +++ b/drivers/media/video/saa7134/saa7134-empress.c @@ -400,7 +400,7 @@ static int empress_init(struct saa7134_dev *dev) printk(KERN_INFO "%s: registered device video%d [mpeg]\n", dev->name,dev->empress_dev->minor & 0x1f); - videobuf_queue_init(&dev->empress_tsq, &saa7134_ts_qops, + videobuf_queue_pci_init(&dev->empress_tsq, &saa7134_ts_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_ALTERNATE, diff --git a/drivers/media/video/saa7134/saa7134-ts.c b/drivers/media/video/saa7134/saa7134-ts.c index 7780b2cce80..5b1d1dafb5a 100644 --- a/drivers/media/video/saa7134/saa7134-ts.c +++ b/drivers/media/video/saa7134/saa7134-ts.c @@ -92,6 +92,8 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, } if (STATE_NEEDS_INIT == buf->vb.state) { + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + buf->vb.width = llength; buf->vb.height = lines; buf->vb.size = size; @@ -101,8 +103,8 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, if (err) goto oops; err = saa7134_pgtable_build(dev->pci,buf->pt, - buf->vb.dma.sglist, - buf->vb.dma.sglen, + dma->sglist, + dma->sglen, saa7134_buffer_startpage(buf)); if (err) goto oops; diff --git a/drivers/media/video/saa7134/saa7134-vbi.c b/drivers/media/video/saa7134/saa7134-vbi.c index 0044079f5da..81a2aedeff5 100644 --- a/drivers/media/video/saa7134/saa7134-vbi.c +++ b/drivers/media/video/saa7134/saa7134-vbi.c @@ -137,6 +137,8 @@ static int buffer_prepare(struct videobuf_queue *q, saa7134_dma_free(q,buf); if (STATE_NEEDS_INIT == buf->vb.state) { + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + buf->vb.width = llength; buf->vb.height = lines; buf->vb.size = size; @@ -146,8 +148,8 @@ static int buffer_prepare(struct videobuf_queue *q, if (err) goto oops; err = saa7134_pgtable_build(dev->pci,buf->pt, - buf->vb.dma.sglist, - buf->vb.dma.sglen, + dma->sglist, + dma->sglen, saa7134_buffer_startpage(buf)); if (err) goto oops; diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 9c317ed6b21..cf40a9690a5 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -1037,6 +1037,8 @@ static int buffer_prepare(struct videobuf_queue *q, } if (STATE_NEEDS_INIT == buf->vb.state) { + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + buf->vb.width = fh->width; buf->vb.height = fh->height; buf->vb.size = size; @@ -1048,8 +1050,8 @@ static int buffer_prepare(struct videobuf_queue *q, if (err) goto oops; err = saa7134_pgtable_build(dev->pci,buf->pt, - buf->vb.dma.sglist, - buf->vb.dma.sglen, + dma->sglist, + dma->sglen, saa7134_buffer_startpage(buf)); if (err) goto oops; @@ -1309,13 +1311,13 @@ static int video_open(struct inode *inode, struct file *file) fh->height = 576; v4l2_prio_open(&dev->prio,&fh->prio); - videobuf_queue_init(&fh->cap, &video_qops, + videobuf_queue_pci_init(&fh->cap, &video_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED, sizeof(struct saa7134_buf), fh); - videobuf_queue_init(&fh->vbi, &saa7134_vbi_qops, + videobuf_queue_pci_init(&fh->vbi, &saa7134_vbi_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VBI_CAPTURE, V4L2_FIELD_SEQ_TB, @@ -2137,29 +2139,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file, } #ifdef CONFIG_VIDEO_V4L1_COMPAT case VIDIOCGMBUF: - { - struct video_mbuf *mbuf = arg; - struct videobuf_queue *q; - struct v4l2_requestbuffers req; - unsigned int i; - - q = saa7134_queue(fh); - memset(&req,0,sizeof(req)); - req.type = q->type; - req.count = gbuffers; - req.memory = V4L2_MEMORY_MMAP; - err = videobuf_reqbufs(q,&req); - if (err < 0) - return err; - memset(mbuf,0,sizeof(*mbuf)); - mbuf->frames = req.count; - mbuf->size = 0; - for (i = 0; i < mbuf->frames; i++) { - mbuf->offsets[i] = q->bufs[i]->boff; - mbuf->size += q->bufs[i]->bsize; - } - return 0; - } + return videobuf_cgmbuf(saa7134_queue(fh), arg, gbuffers); #endif case VIDIOC_REQBUFS: return videobuf_reqbufs(saa7134_queue(fh),arg); diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index fd12942b3a1..dae608f9bf3 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -37,7 +37,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/media/video/video-buf-dvb.c b/drivers/media/video/video-buf-dvb.c index d2af82dc8fa..9631ead297e 100644 --- a/drivers/media/video/video-buf-dvb.c +++ b/drivers/media/video/video-buf-dvb.c @@ -22,7 +22,7 @@ #include #include -#include +#include #include /* ------------------------------------------------------------------ */ @@ -45,6 +45,7 @@ static int videobuf_dvb_thread(void *data) struct videobuf_buffer *buf; unsigned long flags; int err; + struct videobuf_dmabuf *dma; dprintk("dvb thread started\n"); set_freezable(); @@ -65,8 +66,9 @@ static int videobuf_dvb_thread(void *data) try_to_freeze(); /* feed buffer data to demux */ + dma=videobuf_to_dma(buf); if (buf->state == STATE_DONE) - dvb_dmx_swfilter(&dvb->demux, buf->dma.vmalloc, + dvb_dmx_swfilter(&dvb->demux, dma->vmalloc, buf->size); /* requeue buffer */ diff --git a/include/media/saa7146_vv.h b/include/media/saa7146_vv.h index cce20ed5cf6..e49f7e15606 100644 --- a/include/media/saa7146_vv.h +++ b/include/media/saa7146_vv.h @@ -4,7 +4,7 @@ #include #include #include -#include +#include #define MAX_SAA7146_CAPTURE_BUFFERS 32 /* arbitrary */ #define BUFFER_TIMEOUT (HZ/2) /* 0.5 seconds */ -- cgit v1.2.3-70-g09d2 From 6bb2790f8a0cf93d3dbed6b6e986441110e6174b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 23 Aug 2007 16:41:14 -0300 Subject: V4L/DVB (6253): Convert vivi to use the newer videobuf-dma-sg module Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vivi.c | 53 +++++++++++++++++----------------------------- 1 file changed, 20 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index c10169e3575..89c40341007 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -33,7 +33,7 @@ #include #endif #include -#include +#include #include #include #include @@ -327,19 +327,21 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf) int wmax = buf->vb.width; struct timeval ts; char *tmpbuf; + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); - if (buf->vb.dma.varea) { + + if (dma->varea) { tmpbuf=kmalloc (wmax*2, GFP_KERNEL); } else { - tmpbuf=buf->vb.dma.vmalloc; + tmpbuf=dma->vmalloc; } for (h=0;hvb.dma.varea) { + if (dma->varea) { gen_line(tmpbuf,0,wmax,hmax,h,dev->timestr); /* FIXME: replacing to __copy_to_user */ - if (copy_to_user(buf->vb.dma.varea+pos,tmpbuf,wmax*2)!=0) + if (copy_to_user(dma->varea+pos,tmpbuf,wmax*2)!=0) dprintk(2,"vivifill copy_to_user failed.\n"); } else { gen_line(tmpbuf,pos,wmax,hmax,h,dev->timestr); @@ -369,7 +371,7 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf) dev->h,dev->m,dev->s,(dev->us+500)/1000); dprintk(2,"vivifill at %s: Buffer 0x%08lx size= %d\n",dev->timestr, - (unsigned long)buf->vb.dma.varea,pos); + (unsigned long)dma->varea,pos); /* Advice that buffer was filled */ buf->vb.state = STATE_DONE; @@ -597,13 +599,19 @@ buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) if (0 == *count) *count = 32; + while (*size * *count > vid_limit * 1024 * 1024) (*count)--; + + dprintk(1,"%s, count=%d, size=%d\n",__FUNCTION__,*count, *size); + return 0; } static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf) { + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + dprintk(1,"%s\n",__FUNCTION__); if (in_interrupt()) @@ -611,8 +619,8 @@ static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf) videobuf_waiton(&buf->vb,0,0); - videobuf_dma_unmap(vq, &buf->vb.dma); - videobuf_dma_free(&buf->vb.dma); + videobuf_dma_unmap(vq, dma); + videobuf_dma_free(dma); buf->vb.state = STATE_NEEDS_INIT; } @@ -626,7 +634,7 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, struct vivi_buffer *buf = container_of(vb,struct vivi_buffer,vb); int rc, init_buffer = 0; -// dprintk(1,"%s, field=%d\n",__FUNCTION__,field); + dprintk(1,"%s, field=%d\n",__FUNCTION__,field); BUG_ON(NULL == fh->fmt); if (fh->width < 48 || fh->width > norm_maxw() || @@ -724,11 +732,6 @@ static struct videobuf_queue_ops vivi_video_qops = { .buf_prepare = buffer_prepare, .buf_queue = buffer_queue, .buf_release = buffer_release, - - /* Non-pci handling routines */ -// .vb_map_sg = vivi_map_sg, -// .vb_dma_sync_sg = vivi_dma_sync_sg, -// .vb_unmap_sg = vivi_unmap_sg, }; /* ------------------------------------------------------------------ @@ -904,25 +907,8 @@ static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p) static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf) { struct vivi_fh *fh=priv; - struct videobuf_queue *q=&fh->vb_vidq; - struct v4l2_requestbuffers req; - unsigned int i; - int ret; - req.type = q->type; - req.count = 8; - req.memory = V4L2_MEMORY_MMAP; - ret = videobuf_reqbufs(q,&req); - if (ret < 0) - return (ret); - - mbuf->frames = req.count; - mbuf->size = 0; - for (i = 0; i < mbuf->frames; i++) { - mbuf->offsets[i] = q->bufs[i]->boff; - mbuf->size += q->bufs[i]->bsize; - } - return (0); + return videobuf_cgmbuf (&fh->vb_vidq, mbuf, 8); } #endif @@ -1106,12 +1092,13 @@ static int vivi_open(struct inode *inode, struct file *file) sprintf(dev->timestr,"%02d:%02d:%02d:%03d", dev->h,dev->m,dev->s,(dev->us+500)/1000); - videobuf_queue_init(&fh->vb_vidq, &vivi_video_qops, + videobuf_queue_pci_init(&fh->vb_vidq, &vivi_video_qops, NULL, NULL, fh->type, V4L2_FIELD_INTERLACED, sizeof(struct vivi_buffer),fh); + return 0; } -- cgit v1.2.3-70-g09d2 From 87b9ad070cf76c0f1e8cf836f7eb86e9ac94e34a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 2 Aug 2007 23:31:33 -0300 Subject: V4L/DVB (6254): Add videobuf-vmalloc Adds a newer videobuf-vmalloc module. This module uses the same videobuf controls, but implements memory allocation based on vmalloc methods. With this method, an USB driver can use video-buf, without needing to request memory from the DMA-safe area. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 4 + drivers/media/video/Kconfig | 2 +- drivers/media/video/Makefile | 1 + drivers/media/video/videobuf-vmalloc.c | 384 +++++++++++++++++++++++++++++++++ include/media/videobuf-vmalloc.h | 44 ++++ 5 files changed, 434 insertions(+), 1 deletion(-) create mode 100644 drivers/media/video/videobuf-vmalloc.c create mode 100644 include/media/videobuf-vmalloc.h (limited to 'drivers') diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 28ee65c5391..fc3ea4c67cc 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -134,6 +134,10 @@ config VIDEOBUF_DMA_SG select VIDEOBUF_GEN tristate +config VIDEOBUF_VMALLOC + select VIDEOBUF_GEN + tristate + config VIDEO_BUF_DVB tristate diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index c4f424422f7..2e571eb9313 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -364,7 +364,7 @@ endmenu # encoder / decoder chips config VIDEO_VIVI tristate "Virtual Video Driver" depends on VIDEO_V4L2 && !SPARC32 && !SPARC64 && PCI - select VIDEOBUF_DMA_SG + select VIDEOBUF_VMALLOC default n ---help--- Enables a virtual video driver. This device shows a color bar diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index cb300241eb8..c8140aec1a1 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -89,6 +89,7 @@ obj-$(CONFIG_TUNER_TEA5761) += tea5761.o obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o +obj-$(CONFIG_VIDEOBUF_VMALLOC) += videobuf-vmalloc.o obj-$(CONFIG_VIDEO_BUF_DVB) += video-buf-dvb.o obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c new file mode 100644 index 00000000000..993d5285e18 --- /dev/null +++ b/drivers/media/video/videobuf-vmalloc.c @@ -0,0 +1,384 @@ +/* + * helper functions for vmalloc video4linux capture buffers + * + * The functions expect the hardware being able to scatter gatter + * (i.e. the buffers are not linear in physical memory, but fragmented + * into PAGE_SIZE chunks). They also assume the driver does not need + * to touch the video data. + * + * (c) 2007 Mauro Carvalho Chehab, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#define MAGIC_DMABUF 0x17760309 +#define MAGIC_VMAL_MEM 0x18221223 + +#define MAGIC_CHECK(is,should) if (unlikely((is) != (should))) \ + { printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); } + +static int debug = 0; +module_param(debug, int, 0644); + +MODULE_DESCRIPTION("helper module to manage video4linux vmalloc buffers"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_LICENSE("GPL"); + +#define dprintk(level, fmt, arg...) if (debug >= level) \ + printk(KERN_DEBUG "vbuf-sg: " fmt , ## arg) + + +/***************************************************************************/ + +static void +videobuf_vm_open(struct vm_area_struct *vma) +{ + struct videobuf_mapping *map = vma->vm_private_data; + + dprintk(2,"vm_open %p [count=%d,vma=%08lx-%08lx]\n",map, + map->count,vma->vm_start,vma->vm_end); + + map->count++; +} + +static void +videobuf_vm_close(struct vm_area_struct *vma) +{ + struct videobuf_mapping *map = vma->vm_private_data; + struct videobuf_queue *q = map->q; + struct videbuf_vmalloc_memory *mem; + int i; + + dprintk(2,"vm_close %p [count=%d,vma=%08lx-%08lx]\n",map, + map->count,vma->vm_start,vma->vm_end); + + map->count--; + if (0 == map->count) { + dprintk(1,"munmap %p q=%p\n",map,q); + mutex_lock(&q->lock); + for (i = 0; i < VIDEO_MAX_FRAME; i++) { + if (NULL == q->bufs[i]) + continue; + mem=q->bufs[i]->priv; + + if (!mem) + continue; + + MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); + + if (mem->map != map) + continue; + mem->map = NULL; + q->bufs[i]->baddr = 0; + q->ops->buf_release(q,q->bufs[i]); + } + mutex_unlock(&q->lock); + kfree(map); + } + return; +} + +static struct vm_operations_struct videobuf_vm_ops = +{ + .open = videobuf_vm_open, + .close = videobuf_vm_close, +}; + +/* --------------------------------------------------------------------- + * vmalloc handlers for the generic methods + */ + +/* Allocated area consists on 3 parts: + struct video_buffer + struct _buffer (cx88_buffer, saa7134_buf, ...) + struct videobuf_pci_sg_memory + */ + +static void *__videobuf_alloc(size_t size) +{ + struct videbuf_vmalloc_memory *mem; + struct videobuf_buffer *vb; + + vb = kzalloc(size+sizeof(*mem),GFP_KERNEL); + + mem = vb->priv = ((char *)vb)+size; + mem->magic=MAGIC_VMAL_MEM; + + dprintk(1,"%s: allocated at %p(%ld+%ld) & %p(%ld)\n", + __FUNCTION__,vb,(long)sizeof(*vb),(long)size-sizeof(*vb), + mem,(long)sizeof(*mem)); + + return vb; +} + +static int __videobuf_iolock (struct videobuf_queue* q, + struct videobuf_buffer *vb, + struct v4l2_framebuffer *fbuf) +{ + int pages; + + struct videbuf_vmalloc_memory *mem=vb->priv; + + + BUG_ON(!mem); + + MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); + + + pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT; + + /* Currently, doesn't support V4L2_MEMORY_OVERLAY */ + if ((vb->memory != V4L2_MEMORY_MMAP) && + (vb->memory != V4L2_MEMORY_USERPTR) ) { + printk(KERN_ERR "Method currently unsupported.\n"); + return -EINVAL; + } + + /* FIXME: should be tested with kernel mmap mem */ + mem->vmalloc=vmalloc_user (PAGE_ALIGN(vb->size)); + if (NULL == mem->vmalloc) { + dprintk(1,"vmalloc (%d pages) failed\n",pages); + return -ENOMEM; + } + + dprintk(1,"vmalloc is at addr 0x%08lx, size=%d\n", + (unsigned long)mem->vmalloc, + pages << PAGE_SHIFT); + + /* It seems that some kernel versions need to do remap *after* + the mmap() call + */ + if (mem->vma) { + int retval=remap_vmalloc_range(mem->vma, mem->vmalloc,0); + kfree(mem->vma); + mem->vma=NULL; + if (retval<0) { + dprintk(1,"mmap app bug: remap_vmalloc_range area %p error %d\n", + mem->vmalloc,retval); + return retval; + } + } + + return 0; +} + +static int __videobuf_sync(struct videobuf_queue *q, + struct videobuf_buffer *buf) +{ + return 0; +} + +static int __videobuf_mmap_free(struct videobuf_queue *q) +{ + unsigned int i; + + for (i = 0; i < VIDEO_MAX_FRAME; i++) { + if (q->bufs[i]) { + struct videbuf_vmalloc_memory *mem=q->bufs[i]->priv; + if (mem && mem->map) + return -EBUSY; + } + } + + return 0; +} + +static int __videobuf_mmap_mapper(struct videobuf_queue *q, + struct vm_area_struct *vma) +{ + struct videbuf_vmalloc_memory *mem; + struct videobuf_mapping *map; + unsigned int first; + int retval; + unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; + + if (! (vma->vm_flags & VM_WRITE) || ! (vma->vm_flags & VM_SHARED)) + return -EINVAL; + + /* look for first buffer to map */ + for (first = 0; first < VIDEO_MAX_FRAME; first++) { + if (NULL == q->bufs[first]) + continue; + + if (V4L2_MEMORY_MMAP != q->bufs[first]->memory) + continue; + if (q->bufs[first]->boff == offset) + break; + } + if (VIDEO_MAX_FRAME == first) { + dprintk(1,"mmap app bug: offset invalid [offset=0x%lx]\n", + (vma->vm_pgoff << PAGE_SHIFT)); + return -EINVAL; + } + mem=q->bufs[first]->priv; + BUG_ON (!mem); + MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); + + /* create mapping + update buffer list */ + map = mem->map = kmalloc(sizeof(struct videobuf_mapping),GFP_KERNEL); + if (NULL == map) + return -ENOMEM; + + map->start = vma->vm_start; + map->end = vma->vm_end; + map->q = q; + + q->bufs[first]->baddr = vma->vm_start; + + vma->vm_ops = &videobuf_vm_ops; + vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED; + vma->vm_private_data = map; + + /* Try to remap memory */ + retval=remap_vmalloc_range(vma, mem->vmalloc,0); + if (retval<0) { + dprintk(1,"mmap: postponing remap_vmalloc_range\n"); + mem->vma=kmalloc(sizeof(*vma),GFP_KERNEL); + if (!mem->vma) { + kfree(map); + mem->map=NULL; + return -ENOMEM; + } + memcpy(mem->vma,vma,sizeof(*vma)); + } + + dprintk(1,"mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n", + map,q,vma->vm_start,vma->vm_end, + (long int) q->bufs[first]->bsize, + vma->vm_pgoff,first); + + videobuf_vm_open(vma); + + return (0); +} + +static int __videobuf_is_mmapped (struct videobuf_buffer *buf) +{ + struct videbuf_vmalloc_memory *mem=buf->priv; + BUG_ON (!mem); + MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); + + return (mem->map)?1:0; +} + +static int __videobuf_copy_to_user ( struct videobuf_queue *q, + char __user *data, size_t count, + int nonblocking ) +{ + struct videbuf_vmalloc_memory *mem=q->read_buf->priv; + BUG_ON (!mem); + MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); + + BUG_ON (!mem->vmalloc); + + /* copy to userspace */ + if (count > q->read_buf->size - q->read_off) + count = q->read_buf->size - q->read_off; + + if (copy_to_user(data, mem->vmalloc+q->read_off, count)) + return -EFAULT; + + return count; +} + +static int __videobuf_copy_stream ( struct videobuf_queue *q, + char __user *data, size_t count, size_t pos, + int vbihack, int nonblocking ) +{ + unsigned int *fc; + struct videbuf_vmalloc_memory *mem=q->read_buf->priv; + BUG_ON (!mem); + MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); + + if (vbihack) { + /* dirty, undocumented hack -- pass the frame counter + * within the last four bytes of each vbi data block. + * We need that one to maintain backward compatibility + * to all vbi decoding software out there ... */ + fc = (unsigned int*)mem->vmalloc; + fc += (q->read_buf->size>>2) -1; + *fc = q->read_buf->field_count >> 1; + dprintk(1,"vbihack: %d\n",*fc); + } + + /* copy stuff using the common method */ + count = __videobuf_copy_to_user (q,data,count,nonblocking); + + if ( (count==-EFAULT) && (0 == pos) ) + return -EFAULT; + + return count; +} + +static struct videobuf_qtype_ops qops = { + .magic = MAGIC_QTYPE_OPS, + + .alloc = __videobuf_alloc, + .iolock = __videobuf_iolock, + .sync = __videobuf_sync, + .mmap_free = __videobuf_mmap_free, + .mmap_mapper = __videobuf_mmap_mapper, + .is_mmapped = __videobuf_is_mmapped, + .copy_to_user = __videobuf_copy_to_user, + .copy_stream = __videobuf_copy_stream, +}; + +void videobuf_queue_vmalloc_init(struct videobuf_queue* q, + struct videobuf_queue_ops *ops, + void *dev, + spinlock_t *irqlock, + enum v4l2_buf_type type, + enum v4l2_field field, + unsigned int msize, + void *priv) +{ + videobuf_queue_init(q, ops, dev, irqlock, type, field, msize, priv); + q->int_ops=&qops; +} + +EXPORT_SYMBOL_GPL(videobuf_queue_vmalloc_init); + +void *videobuf_to_vmalloc (struct videobuf_buffer *buf) +{ + struct videbuf_vmalloc_memory *mem=buf->priv; + BUG_ON (!mem); + MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); + + return mem->vmalloc; +} +EXPORT_SYMBOL_GPL(videobuf_to_vmalloc); + +void videobuf_vmalloc_free (struct videobuf_buffer *buf) +{ + struct videbuf_vmalloc_memory *mem=buf->priv; + BUG_ON (!mem); + + MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); + + vfree(mem->vmalloc); + + return; +} +EXPORT_SYMBOL_GPL(videobuf_vmalloc_free); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/include/media/videobuf-vmalloc.h b/include/media/videobuf-vmalloc.h new file mode 100644 index 00000000000..5fff68df668 --- /dev/null +++ b/include/media/videobuf-vmalloc.h @@ -0,0 +1,44 @@ +/* + * helper functions for vmalloc capture buffers + * + * The functions expect the hardware being able to scatter gatter + * (i.e. the buffers are not linear in physical memory, but fragmented + * into PAGE_SIZE chunks). They also assume the driver does not need + * to touch the video data. + * + * (c) 2007 Mauro Carvalho Chehab, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 + */ + +#include + +/* --------------------------------------------------------------------- */ + +struct videbuf_vmalloc_memory +{ + u32 magic; + + /* for mmap'ed buffers */ + struct videobuf_mapping *map; + + void *vmalloc; + + /* remap_vmalloc_range seems to need to run after mmap() on some cases */ + struct vm_area_struct *vma; +}; + +void videobuf_queue_vmalloc_init(struct videobuf_queue* q, + struct videobuf_queue_ops *ops, + void *dev, + spinlock_t *irqlock, + enum v4l2_buf_type type, + enum v4l2_field field, + unsigned int msize, + void *priv); + +void *videobuf_to_vmalloc (struct videobuf_buffer *buf); + +void videobuf_vmalloc_free (struct videobuf_buffer *buf); -- cgit v1.2.3-70-g09d2 From 5a0377060efcf844f4e359f3ab013de7f1b98da2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 2 Aug 2007 23:31:54 -0300 Subject: V4L/DVB (6255): Convert vivi to use videobuf-vmalloc This patch removes the usage of videobuf-dma-sg from vivi driver, using instead videobuf-vmalloc. This way, vivi will be useful for testing the newer method. Reverting this patch won't hurt vivi, since both methods work fine. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vivi.c | 44 +++++++++++++++----------------------------- 1 file changed, 15 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 89c40341007..c14e2b3e424 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -33,7 +33,7 @@ #include #endif #include -#include +#include #include #include #include @@ -145,7 +145,6 @@ struct vivi_buffer { struct videobuf_buffer vb; struct vivi_fmt *fmt; - }; struct vivi_dmaqueue { @@ -326,29 +325,22 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf) int hmax = buf->vb.height; int wmax = buf->vb.width; struct timeval ts; - char *tmpbuf; - struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); - - - if (dma->varea) { - tmpbuf=kmalloc (wmax*2, GFP_KERNEL); - } else { - tmpbuf=dma->vmalloc; - } + char *tmpbuf = kmalloc(wmax*2,GFP_KERNEL); + void *vbuf=videobuf_to_vmalloc (&buf->vb); + if (!tmpbuf) + return; for (h=0;hvarea) { - gen_line(tmpbuf,0,wmax,hmax,h,dev->timestr); - /* FIXME: replacing to __copy_to_user */ - if (copy_to_user(dma->varea+pos,tmpbuf,wmax*2)!=0) - dprintk(2,"vivifill copy_to_user failed.\n"); - } else { - gen_line(tmpbuf,pos,wmax,hmax,h,dev->timestr); - } + gen_line(tmpbuf,0,wmax,hmax,h,dev->timestr); + /* FIXME: replacing to __copy_to_user */ + if (copy_to_user(vbuf+pos,tmpbuf,wmax*2)!=0) + dprintk(2,"vivifill copy_to_user failed.\n"); pos += wmax*2; } + kfree(tmpbuf); + /* Updates stream time */ dev->us+=jiffies_to_usecs(jiffies-dev->jiffies); @@ -371,7 +363,7 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf) dev->h,dev->m,dev->s,(dev->us+500)/1000); dprintk(2,"vivifill at %s: Buffer 0x%08lx size= %d\n",dev->timestr, - (unsigned long)dma->varea,pos); + (unsigned long)tmpbuf,pos); /* Advice that buffer was filled */ buf->vb.state = STATE_DONE; @@ -610,17 +602,13 @@ buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf) { - struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); - dprintk(1,"%s\n",__FUNCTION__); if (in_interrupt()) BUG(); - videobuf_waiton(&buf->vb,0,0); - videobuf_dma_unmap(vq, dma); - videobuf_dma_free(dma); + videobuf_vmalloc_free(&buf->vb); buf->vb.state = STATE_NEEDS_INIT; } @@ -726,7 +714,6 @@ static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb free_buffer(vq,buf); } - static struct videobuf_queue_ops vivi_video_qops = { .buf_setup = buffer_setup, .buf_prepare = buffer_prepare, @@ -1092,13 +1079,12 @@ static int vivi_open(struct inode *inode, struct file *file) sprintf(dev->timestr,"%02d:%02d:%02d:%03d", dev->h,dev->m,dev->s,(dev->us+500)/1000); - videobuf_queue_pci_init(&fh->vb_vidq, &vivi_video_qops, + videobuf_queue_vmalloc_init(&fh->vb_vidq, &vivi_video_qops, NULL, NULL, fh->type, V4L2_FIELD_INTERLACED, sizeof(struct vivi_buffer),fh); - return 0; } @@ -1192,7 +1178,7 @@ static const struct file_operations vivi_fops = { .read = vivi_read, .poll = vivi_poll, .ioctl = video_ioctl2, /* V4L2 ioctl handler */ - .mmap = vivi_mmap, + .mmap = vivi_mmap, .llseek = no_llseek, }; -- cgit v1.2.3-70-g09d2 From 79618cf41337ccedb9abeee059ce76aac7962739 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 23 Aug 2007 16:31:15 -0300 Subject: V4L/DVB (6256): Remove the obsolete video-buf module Signed-off-by: Mauro Carvalho Chehab http://thread.gmane.org/gmane.comp.video.video4linux/34978/focus=34981 Reviewed-by: Ricardo Cerqueira --- drivers/media/video/video-buf.c | 1424 --------------------------------------- include/media/video-buf.h | 289 -------- 2 files changed, 1713 deletions(-) delete mode 100644 drivers/media/video/video-buf.c delete mode 100644 include/media/video-buf.h (limited to 'drivers') diff --git a/drivers/media/video/video-buf.c b/drivers/media/video/video-buf.c deleted file mode 100644 index f6f31e1773d..00000000000 --- a/drivers/media/video/video-buf.c +++ /dev/null @@ -1,1424 +0,0 @@ -/* - * - * generic helper functions for video4linux capture buffers, to handle - * memory management and PCI DMA. - * Right now, bttv, saa7134, saa7146 and cx88 use it. - * - * The functions expect the hardware being able to scatter gatter - * (i.e. the buffers are not linear in physical memory, but fragmented - * into PAGE_SIZE chunks). They also assume the driver does not need - * to touch the video data. - * - * device specific map/unmap/sync stuff now are mapped as operations - * to allow its usage by USB and virtual devices. - * - * (c) 2001-2004 Gerd Knorr [SUSE Labs] - * (c) 2006 Mauro Carvalho Chehab - * (c) 2006 Ted Walther and John Sokol - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define MAGIC_DMABUF 0x19721112 -#define MAGIC_BUFFER 0x20040302 -#define MAGIC_CHECK(is,should) if (unlikely((is) != (should))) \ - { printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); } - -static int debug = 0; -module_param(debug, int, 0644); - -MODULE_DESCRIPTION("helper module to manage video4linux pci dma buffers"); -MODULE_AUTHOR("Gerd Knorr [SuSE Labs]"); -MODULE_LICENSE("GPL"); - -#define dprintk(level, fmt, arg...) if (debug >= level) \ - printk(KERN_DEBUG "vbuf: " fmt , ## arg) - -struct scatterlist* -videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages) -{ - struct scatterlist *sglist; - struct page *pg; - int i; - - sglist = kcalloc(nr_pages, sizeof(struct scatterlist), GFP_KERNEL); - if (NULL == sglist) - return NULL; - for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) { - pg = vmalloc_to_page(virt); - if (NULL == pg) - goto err; - BUG_ON(PageHighMem(pg)); - sglist[i].page = pg; - sglist[i].length = PAGE_SIZE; - } - return sglist; - - err: - kfree(sglist); - return NULL; -} - -struct scatterlist* -videobuf_pages_to_sg(struct page **pages, int nr_pages, int offset) -{ - struct scatterlist *sglist; - int i = 0; - - if (NULL == pages[0]) - return NULL; - sglist = kcalloc(nr_pages, sizeof(*sglist), GFP_KERNEL); - if (NULL == sglist) - return NULL; - - if (NULL == pages[0]) - goto nopage; - if (PageHighMem(pages[0])) - /* DMA to highmem pages might not work */ - goto highmem; - sglist[0].page = pages[0]; - sglist[0].offset = offset; - sglist[0].length = PAGE_SIZE - offset; - for (i = 1; i < nr_pages; i++) { - if (NULL == pages[i]) - goto nopage; - if (PageHighMem(pages[i])) - goto highmem; - sglist[i].page = pages[i]; - sglist[i].length = PAGE_SIZE; - } - return sglist; - - nopage: - dprintk(2,"sgl: oops - no page\n"); - kfree(sglist); - return NULL; - - highmem: - dprintk(2,"sgl: oops - highmem page\n"); - kfree(sglist); - return NULL; -} - -/* --------------------------------------------------------------------- */ - -void videobuf_dma_init(struct videobuf_dmabuf *dma) -{ - memset(dma,0,sizeof(*dma)); - dma->magic = MAGIC_DMABUF; -} - -int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, - unsigned long data, unsigned long size) -{ - unsigned long first,last; - int err, rw = 0; - - dma->direction = direction; - switch (dma->direction) { - case PCI_DMA_FROMDEVICE: rw = READ; break; - case PCI_DMA_TODEVICE: rw = WRITE; break; - default: BUG(); - } - - first = (data & PAGE_MASK) >> PAGE_SHIFT; - last = ((data+size-1) & PAGE_MASK) >> PAGE_SHIFT; - dma->offset = data & ~PAGE_MASK; - dma->nr_pages = last-first+1; - dma->pages = kmalloc(dma->nr_pages * sizeof(struct page*), - GFP_KERNEL); - if (NULL == dma->pages) - return -ENOMEM; - dprintk(1,"init user [0x%lx+0x%lx => %d pages]\n", - data,size,dma->nr_pages); - - dma->varea = (void *) data; - - down_read(¤t->mm->mmap_sem); - err = get_user_pages(current,current->mm, - data & PAGE_MASK, dma->nr_pages, - rw == READ, 1, /* force */ - dma->pages, NULL); - up_read(¤t->mm->mmap_sem); - if (err != dma->nr_pages) { - dma->nr_pages = (err >= 0) ? err : 0; - dprintk(1,"get_user_pages: err=%d [%d]\n",err,dma->nr_pages); - return err < 0 ? err : -EINVAL; - } - return 0; -} - -int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction, - int nr_pages) -{ - dprintk(1,"init kernel [%d pages]\n",nr_pages); - dma->direction = direction; - dma->vmalloc = vmalloc_32(nr_pages << PAGE_SHIFT); - if (NULL == dma->vmalloc) { - dprintk(1,"vmalloc_32(%d pages) failed\n",nr_pages); - return -ENOMEM; - } - dprintk(1,"vmalloc is at addr 0x%08lx, size=%d\n", - (unsigned long)dma->vmalloc, - nr_pages << PAGE_SHIFT); - memset(dma->vmalloc,0,nr_pages << PAGE_SHIFT); - dma->nr_pages = nr_pages; - return 0; -} - -int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction, - dma_addr_t addr, int nr_pages) -{ - dprintk(1,"init overlay [%d pages @ bus 0x%lx]\n", - nr_pages,(unsigned long)addr); - dma->direction = direction; - if (0 == addr) - return -EINVAL; - - dma->bus_addr = addr; - dma->nr_pages = nr_pages; - return 0; -} - -int videobuf_dma_map(struct videobuf_queue* q,struct videobuf_dmabuf *dma) -{ - void *dev=q->dev; - - MAGIC_CHECK(dma->magic,MAGIC_DMABUF); - BUG_ON(0 == dma->nr_pages); - - if (dma->pages) { - dma->sglist = videobuf_pages_to_sg(dma->pages, dma->nr_pages, - dma->offset); - } - if (dma->vmalloc) { - dma->sglist = videobuf_vmalloc_to_sg - (dma->vmalloc,dma->nr_pages); - } - if (dma->bus_addr) { - dma->sglist = kmalloc(sizeof(struct scatterlist), GFP_KERNEL); - if (NULL != dma->sglist) { - dma->sglen = 1; - sg_dma_address(&dma->sglist[0]) = dma->bus_addr & PAGE_MASK; - dma->sglist[0].offset = dma->bus_addr & ~PAGE_MASK; - sg_dma_len(&dma->sglist[0]) = dma->nr_pages * PAGE_SIZE; - } - } - if (NULL == dma->sglist) { - dprintk(1,"scatterlist is NULL\n"); - return -ENOMEM; - } - if (!dma->bus_addr) { - if (q->ops->vb_map_sg) { - dma->sglen = q->ops->vb_map_sg(dev,dma->sglist, - dma->nr_pages, dma->direction); - } - if (0 == dma->sglen) { - printk(KERN_WARNING - "%s: videobuf_map_sg failed\n",__FUNCTION__); - kfree(dma->sglist); - dma->sglist = NULL; - dma->sglen = 0; - return -EIO; - } - } - return 0; -} - -int videobuf_dma_sync(struct videobuf_queue* q,struct videobuf_dmabuf *dma) -{ - void *dev=q->dev; - - MAGIC_CHECK(dma->magic,MAGIC_DMABUF); - BUG_ON(!dma->sglen); - - if (!dma->bus_addr && q->ops->vb_dma_sync_sg) - q->ops->vb_dma_sync_sg(dev,dma->sglist,dma->nr_pages, - dma->direction); - - return 0; -} - -int videobuf_dma_unmap(struct videobuf_queue* q,struct videobuf_dmabuf *dma) -{ - void *dev=q->dev; - - MAGIC_CHECK(dma->magic,MAGIC_DMABUF); - if (!dma->sglen) - return 0; - - if (!dma->bus_addr && q->ops->vb_unmap_sg) - q->ops->vb_unmap_sg(dev,dma->sglist,dma->nr_pages, - dma->direction); - kfree(dma->sglist); - dma->sglist = NULL; - dma->sglen = 0; - return 0; -} - -int videobuf_dma_free(struct videobuf_dmabuf *dma) -{ - MAGIC_CHECK(dma->magic,MAGIC_DMABUF); - BUG_ON(dma->sglen); - - if (dma->pages) { - int i; - for (i=0; i < dma->nr_pages; i++) - page_cache_release(dma->pages[i]); - kfree(dma->pages); - dma->pages = NULL; - } - - vfree(dma->vmalloc); - dma->vmalloc = NULL; - dma->varea = NULL; - - if (dma->bus_addr) { - dma->bus_addr = 0; - } - dma->direction = PCI_DMA_NONE; - return 0; -} - -/* --------------------------------------------------------------------- */ - -void* videobuf_alloc(unsigned int size) -{ - struct videobuf_buffer *vb; - - vb = kzalloc(size,GFP_KERNEL); - if (NULL != vb) { - videobuf_dma_init(&vb->dma); - init_waitqueue_head(&vb->done); - vb->magic = MAGIC_BUFFER; - } - return vb; -} - -int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr) -{ - int retval = 0; - DECLARE_WAITQUEUE(wait, current); - - MAGIC_CHECK(vb->magic,MAGIC_BUFFER); - add_wait_queue(&vb->done, &wait); - while (vb->state == STATE_ACTIVE || vb->state == STATE_QUEUED) { - if (non_blocking) { - retval = -EAGAIN; - break; - } - set_current_state(intr ? TASK_INTERRUPTIBLE - : TASK_UNINTERRUPTIBLE); - if (vb->state == STATE_ACTIVE || vb->state == STATE_QUEUED) - schedule(); - set_current_state(TASK_RUNNING); - if (intr && signal_pending(current)) { - dprintk(1,"buffer waiton: -EINTR\n"); - retval = -EINTR; - break; - } - } - remove_wait_queue(&vb->done, &wait); - return retval; -} - -int -videobuf_iolock(struct videobuf_queue* q, struct videobuf_buffer *vb, - struct v4l2_framebuffer *fbuf) -{ - int err,pages; - dma_addr_t bus; - - MAGIC_CHECK(vb->magic,MAGIC_BUFFER); - switch (vb->memory) { - case V4L2_MEMORY_MMAP: - case V4L2_MEMORY_USERPTR: - if (0 == vb->baddr) { - /* no userspace addr -- kernel bounce buffer */ - pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT; - err = videobuf_dma_init_kernel(&vb->dma,PCI_DMA_FROMDEVICE, - pages); - if (0 != err) - return err; - } else { - /* dma directly to userspace */ - err = videobuf_dma_init_user(&vb->dma,PCI_DMA_FROMDEVICE, - vb->baddr,vb->bsize); - if (0 != err) - return err; - } - break; - case V4L2_MEMORY_OVERLAY: - if (NULL == fbuf) - return -EINVAL; - /* FIXME: need sanity checks for vb->boff */ - /* - * Using a double cast to avoid compiler warnings when - * building for PAE. Compiler doesn't like direct casting - * of a 32 bit ptr to 64 bit integer. - */ - bus = (dma_addr_t)(unsigned long)fbuf->base + vb->boff; - pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT; - err = videobuf_dma_init_overlay(&vb->dma,PCI_DMA_FROMDEVICE, - bus, pages); - if (0 != err) - return err; - break; - default: - BUG(); - } - err = videobuf_dma_map(q,&vb->dma); - if (0 != err) - return err; - - return 0; -} - -/* --------------------------------------------------------------------- */ - -void videobuf_queue_pci(struct videobuf_queue* q) -{ - /* If not specified, defaults to PCI map sg */ - if (!q->ops->vb_map_sg) - q->ops->vb_map_sg=(vb_map_sg_t *)pci_map_sg; - - if (!q->ops->vb_dma_sync_sg) - q->ops->vb_dma_sync_sg=(vb_map_sg_t *)pci_dma_sync_sg_for_cpu; - if (!q->ops->vb_unmap_sg) - q->ops->vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; -} - -int videobuf_pci_dma_map(struct pci_dev *pci,struct videobuf_dmabuf *dma) -{ - struct videobuf_queue q; - struct videobuf_queue_ops qops; - - q.dev=pci; - qops.vb_map_sg=(vb_map_sg_t *)pci_map_sg; - qops.vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; - q.ops = &qops; - - return (videobuf_dma_map(&q,dma)); -} - -int videobuf_pci_dma_unmap(struct pci_dev *pci,struct videobuf_dmabuf *dma) -{ - struct videobuf_queue q; - struct videobuf_queue_ops qops; - - q.dev=pci; - qops.vb_map_sg=(vb_map_sg_t *)pci_map_sg; - qops.vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; - q.ops = &qops; - - return (videobuf_dma_unmap(&q,dma)); -} - -void videobuf_queue_init(struct videobuf_queue* q, - struct videobuf_queue_ops *ops, - void *dev, - spinlock_t *irqlock, - enum v4l2_buf_type type, - enum v4l2_field field, - unsigned int msize, - void *priv) -{ - memset(q,0,sizeof(*q)); - q->irqlock = irqlock; - q->dev = dev; - q->type = type; - q->field = field; - q->msize = msize; - q->ops = ops; - q->priv_data = priv; - - videobuf_queue_pci(q); - - mutex_init(&q->lock); - INIT_LIST_HEAD(&q->stream); -} - -int -videobuf_queue_is_busy(struct videobuf_queue *q) -{ - int i; - - if (q->streaming) { - dprintk(1,"busy: streaming active\n"); - return 1; - } - if (q->reading) { - dprintk(1,"busy: pending read #1\n"); - return 1; - } - if (q->read_buf) { - dprintk(1,"busy: pending read #2\n"); - return 1; - } - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - if (q->bufs[i]->map) { - dprintk(1,"busy: buffer #%d mapped\n",i); - return 1; - } - if (q->bufs[i]->state == STATE_QUEUED) { - dprintk(1,"busy: buffer #%d queued\n",i); - return 1; - } - if (q->bufs[i]->state == STATE_ACTIVE) { - dprintk(1,"busy: buffer #%d avtive\n",i); - return 1; - } - } - return 0; -} - -void -videobuf_queue_cancel(struct videobuf_queue *q) -{ - unsigned long flags=0; - int i; - - /* remove queued buffers from list */ - if (q->irqlock) - spin_lock_irqsave(q->irqlock,flags); - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - if (q->bufs[i]->state == STATE_QUEUED) { - list_del(&q->bufs[i]->queue); - q->bufs[i]->state = STATE_ERROR; - } - } - if (q->irqlock) - spin_unlock_irqrestore(q->irqlock,flags); - - /* free all buffers + clear queue */ - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - q->ops->buf_release(q,q->bufs[i]); - } - INIT_LIST_HEAD(&q->stream); -} - -/* --------------------------------------------------------------------- */ - -enum v4l2_field -videobuf_next_field(struct videobuf_queue *q) -{ - enum v4l2_field field = q->field; - - BUG_ON(V4L2_FIELD_ANY == field); - - if (V4L2_FIELD_ALTERNATE == field) { - if (V4L2_FIELD_TOP == q->last) { - field = V4L2_FIELD_BOTTOM; - q->last = V4L2_FIELD_BOTTOM; - } else { - field = V4L2_FIELD_TOP; - q->last = V4L2_FIELD_TOP; - } - } - return field; -} - -void -videobuf_status(struct v4l2_buffer *b, struct videobuf_buffer *vb, - enum v4l2_buf_type type) -{ - MAGIC_CHECK(vb->magic,MAGIC_BUFFER); - - b->index = vb->i; - b->type = type; - - b->memory = vb->memory; - switch (b->memory) { - case V4L2_MEMORY_MMAP: - b->m.offset = vb->boff; - b->length = vb->bsize; - break; - case V4L2_MEMORY_USERPTR: - b->m.userptr = vb->baddr; - b->length = vb->bsize; - break; - case V4L2_MEMORY_OVERLAY: - b->m.offset = vb->boff; - break; - } - - b->flags = 0; - if (vb->map) - b->flags |= V4L2_BUF_FLAG_MAPPED; - - switch (vb->state) { - case STATE_PREPARED: - case STATE_QUEUED: - case STATE_ACTIVE: - b->flags |= V4L2_BUF_FLAG_QUEUED; - break; - case STATE_DONE: - case STATE_ERROR: - b->flags |= V4L2_BUF_FLAG_DONE; - break; - case STATE_NEEDS_INIT: - case STATE_IDLE: - /* nothing */ - break; - } - - if (vb->input != UNSET) { - b->flags |= V4L2_BUF_FLAG_INPUT; - b->input = vb->input; - } - - b->field = vb->field; - b->timestamp = vb->ts; - b->bytesused = vb->size; - b->sequence = vb->field_count >> 1; -} - -int -videobuf_reqbufs(struct videobuf_queue *q, - struct v4l2_requestbuffers *req) -{ - unsigned int size,count; - int retval; - - if (req->type != q->type) { - dprintk(1,"reqbufs: queue type invalid\n"); - return -EINVAL; - } - if (req->count < 1) { - dprintk(1,"reqbufs: count invalid (%d)\n",req->count); - return -EINVAL; - } - if (req->memory != V4L2_MEMORY_MMAP && - req->memory != V4L2_MEMORY_USERPTR && - req->memory != V4L2_MEMORY_OVERLAY) { - dprintk(1,"reqbufs: memory type invalid\n"); - return -EINVAL; - } - - if (q->streaming) { - dprintk(1,"reqbufs: streaming already exists\n"); - return -EBUSY; - } - if (!list_empty(&q->stream)) { - dprintk(1,"reqbufs: stream running\n"); - return -EBUSY; - } - - mutex_lock(&q->lock); - count = req->count; - if (count > VIDEO_MAX_FRAME) - count = VIDEO_MAX_FRAME; - size = 0; - q->ops->buf_setup(q,&count,&size); - size = PAGE_ALIGN(size); - dprintk(1,"reqbufs: bufs=%d, size=0x%x [%d pages total]\n", - count, size, (count*size)>>PAGE_SHIFT); - - retval = videobuf_mmap_setup(q,count,size,req->memory); - if (retval < 0) { - dprintk(1,"reqbufs: mmap setup returned %d\n",retval); - goto done; - } - - req->count = count; - - done: - mutex_unlock(&q->lock); - return retval; -} - -int -videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b) -{ - if (unlikely(b->type != q->type)) { - dprintk(1,"querybuf: Wrong type.\n"); - return -EINVAL; - } - if (unlikely(b->index < 0 || b->index >= VIDEO_MAX_FRAME)) { - dprintk(1,"querybuf: index out of range.\n"); - return -EINVAL; - } - if (unlikely(NULL == q->bufs[b->index])) { - dprintk(1,"querybuf: buffer is null.\n"); - return -EINVAL; - } - videobuf_status(b,q->bufs[b->index],q->type); - return 0; -} - -int -videobuf_qbuf(struct videobuf_queue *q, - struct v4l2_buffer *b) -{ - struct videobuf_buffer *buf; - enum v4l2_field field; - unsigned long flags=0; - int retval; - - mutex_lock(&q->lock); - retval = -EBUSY; - if (q->reading) { - dprintk(1,"qbuf: Reading running...\n"); - goto done; - } - retval = -EINVAL; - if (b->type != q->type) { - dprintk(1,"qbuf: Wrong type.\n"); - goto done; - } - if (b->index < 0 || b->index >= VIDEO_MAX_FRAME) { - dprintk(1,"qbuf: index out of range.\n"); - goto done; - } - buf = q->bufs[b->index]; - if (NULL == buf) { - dprintk(1,"qbuf: buffer is null.\n"); - goto done; - } - MAGIC_CHECK(buf->magic,MAGIC_BUFFER); - if (buf->memory != b->memory) { - dprintk(1,"qbuf: memory type is wrong.\n"); - goto done; - } - if (buf->state != STATE_NEEDS_INIT && buf->state != STATE_IDLE) { - dprintk(1,"qbuf: buffer is already queued or active.\n"); - goto done; - } - - if (b->flags & V4L2_BUF_FLAG_INPUT) { - if (b->input >= q->inputs) { - dprintk(1,"qbuf: wrong input.\n"); - goto done; - } - buf->input = b->input; - } else { - buf->input = UNSET; - } - - switch (b->memory) { - case V4L2_MEMORY_MMAP: - if (0 == buf->baddr) { - dprintk(1,"qbuf: mmap requested but buffer addr is zero!\n"); - goto done; - } - break; - case V4L2_MEMORY_USERPTR: - if (b->length < buf->bsize) { - dprintk(1,"qbuf: buffer length is not enough\n"); - goto done; - } - if (STATE_NEEDS_INIT != buf->state && buf->baddr != b->m.userptr) - q->ops->buf_release(q,buf); - buf->baddr = b->m.userptr; - break; - case V4L2_MEMORY_OVERLAY: - buf->boff = b->m.offset; - break; - default: - dprintk(1,"qbuf: wrong memory type\n"); - goto done; - } - - dprintk(1,"qbuf: requesting next field\n"); - field = videobuf_next_field(q); - retval = q->ops->buf_prepare(q,buf,field); - if (0 != retval) { - dprintk(1,"qbuf: buffer_prepare returned %d\n",retval); - goto done; - } - - list_add_tail(&buf->stream,&q->stream); - if (q->streaming) { - if (q->irqlock) - spin_lock_irqsave(q->irqlock,flags); - q->ops->buf_queue(q,buf); - if (q->irqlock) - spin_unlock_irqrestore(q->irqlock,flags); - } - dprintk(1,"qbuf: succeded\n"); - retval = 0; - - done: - mutex_unlock(&q->lock); - return retval; -} - -int -videobuf_dqbuf(struct videobuf_queue *q, - struct v4l2_buffer *b, int nonblocking) -{ - struct videobuf_buffer *buf; - int retval; - - mutex_lock(&q->lock); - retval = -EBUSY; - if (q->reading) { - dprintk(1,"dqbuf: Reading running...\n"); - goto done; - } - retval = -EINVAL; - if (b->type != q->type) { - dprintk(1,"dqbuf: Wrong type.\n"); - goto done; - } - if (list_empty(&q->stream)) { - dprintk(1,"dqbuf: stream running\n"); - goto done; - } - buf = list_entry(q->stream.next, struct videobuf_buffer, stream); - retval = videobuf_waiton(buf, nonblocking, 1); - if (retval < 0) { - dprintk(1,"dqbuf: waiton returned %d\n",retval); - goto done; - } - switch (buf->state) { - case STATE_ERROR: - dprintk(1,"dqbuf: state is error\n"); - retval = -EIO; - videobuf_dma_sync(q,&buf->dma); - buf->state = STATE_IDLE; - break; - case STATE_DONE: - dprintk(1,"dqbuf: state is done\n"); - videobuf_dma_sync(q,&buf->dma); - buf->state = STATE_IDLE; - break; - default: - dprintk(1,"dqbuf: state invalid\n"); - retval = -EINVAL; - goto done; - } - list_del(&buf->stream); - memset(b,0,sizeof(*b)); - videobuf_status(b,buf,q->type); - - done: - mutex_unlock(&q->lock); - return retval; -} - -int videobuf_streamon(struct videobuf_queue *q) -{ - struct videobuf_buffer *buf; - struct list_head *list; - unsigned long flags=0; - int retval; - - mutex_lock(&q->lock); - retval = -EBUSY; - if (q->reading) - goto done; - retval = 0; - if (q->streaming) - goto done; - q->streaming = 1; - if (q->irqlock) - spin_lock_irqsave(q->irqlock,flags); - list_for_each(list,&q->stream) { - buf = list_entry(list, struct videobuf_buffer, stream); - if (buf->state == STATE_PREPARED) - q->ops->buf_queue(q,buf); - } - if (q->irqlock) - spin_unlock_irqrestore(q->irqlock,flags); - - done: - mutex_unlock(&q->lock); - return retval; -} - -int videobuf_streamoff(struct videobuf_queue *q) -{ - int retval = -EINVAL; - - mutex_lock(&q->lock); - if (!q->streaming) - goto done; - videobuf_queue_cancel(q); - q->streaming = 0; - retval = 0; - - done: - mutex_unlock(&q->lock); - return retval; -} - -static ssize_t -videobuf_read_zerocopy(struct videobuf_queue *q, char __user *data, - size_t count, loff_t *ppos) -{ - enum v4l2_field field; - unsigned long flags=0; - int retval; - - /* setup stuff */ - q->read_buf = videobuf_alloc(q->msize); - if (NULL == q->read_buf) - return -ENOMEM; - - q->read_buf->memory = V4L2_MEMORY_USERPTR; - q->read_buf->baddr = (unsigned long)data; - q->read_buf->bsize = count; - field = videobuf_next_field(q); - retval = q->ops->buf_prepare(q,q->read_buf,field); - if (0 != retval) - goto done; - - /* start capture & wait */ - if (q->irqlock) - spin_lock_irqsave(q->irqlock,flags); - q->ops->buf_queue(q,q->read_buf); - if (q->irqlock) - spin_unlock_irqrestore(q->irqlock,flags); - retval = videobuf_waiton(q->read_buf,0,0); - if (0 == retval) { - videobuf_dma_sync(q,&q->read_buf->dma); - if (STATE_ERROR == q->read_buf->state) - retval = -EIO; - else - retval = q->read_buf->size; - } - - done: - /* cleanup */ - q->ops->buf_release(q,q->read_buf); - kfree(q->read_buf); - q->read_buf = NULL; - return retval; -} - -ssize_t videobuf_read_one(struct videobuf_queue *q, - char __user *data, size_t count, loff_t *ppos, - int nonblocking) -{ - enum v4l2_field field; - unsigned long flags=0; - unsigned size, nbufs, bytes; - int retval; - - mutex_lock(&q->lock); - - nbufs = 1; size = 0; - q->ops->buf_setup(q,&nbufs,&size); - if (NULL == q->read_buf && - count >= size && - !nonblocking) { - retval = videobuf_read_zerocopy(q,data,count,ppos); - if (retval >= 0 || retval == -EIO) - /* ok, all done */ - goto done; - /* fallback to kernel bounce buffer on failures */ - } - - if (NULL == q->read_buf) { - /* need to capture a new frame */ - retval = -ENOMEM; - q->read_buf = videobuf_alloc(q->msize); - dprintk(1,"video alloc=0x%p\n", q->read_buf); - if (NULL == q->read_buf) - goto done; - q->read_buf->memory = V4L2_MEMORY_USERPTR; - q->read_buf->bsize = count; /* preferred size */ - field = videobuf_next_field(q); - retval = q->ops->buf_prepare(q,q->read_buf,field); - if (0 != retval) { - kfree (q->read_buf); - q->read_buf = NULL; - goto done; - } - if (q->irqlock) - spin_lock_irqsave(q->irqlock,flags); - q->ops->buf_queue(q,q->read_buf); - if (q->irqlock) - spin_unlock_irqrestore(q->irqlock,flags); - q->read_off = 0; - } - - /* wait until capture is done */ - retval = videobuf_waiton(q->read_buf, nonblocking, 1); - if (0 != retval) - goto done; - videobuf_dma_sync(q,&q->read_buf->dma); - - if (STATE_ERROR == q->read_buf->state) { - /* catch I/O errors */ - q->ops->buf_release(q,q->read_buf); - kfree(q->read_buf); - q->read_buf = NULL; - retval = -EIO; - goto done; - } - - /* copy to userspace */ - bytes = count; - if (bytes > q->read_buf->size - q->read_off) - bytes = q->read_buf->size - q->read_off; - retval = -EFAULT; - if (copy_to_user(data, q->read_buf->dma.vmalloc+q->read_off, bytes)) - goto done; - - retval = bytes; - q->read_off += bytes; - if (q->read_off == q->read_buf->size) { - /* all data copied, cleanup */ - q->ops->buf_release(q,q->read_buf); - kfree(q->read_buf); - q->read_buf = NULL; - } - - done: - mutex_unlock(&q->lock); - return retval; -} - -int videobuf_read_start(struct videobuf_queue *q) -{ - enum v4l2_field field; - unsigned long flags=0; - int count = 0, size = 0; - int err, i; - - q->ops->buf_setup(q,&count,&size); - if (count < 2) - count = 2; - if (count > VIDEO_MAX_FRAME) - count = VIDEO_MAX_FRAME; - size = PAGE_ALIGN(size); - - err = videobuf_mmap_setup(q, count, size, V4L2_MEMORY_USERPTR); - if (err) - return err; - for (i = 0; i < count; i++) { - field = videobuf_next_field(q); - err = q->ops->buf_prepare(q,q->bufs[i],field); - if (err) - return err; - list_add_tail(&q->bufs[i]->stream, &q->stream); - } - if (q->irqlock) - spin_lock_irqsave(q->irqlock,flags); - for (i = 0; i < count; i++) - q->ops->buf_queue(q,q->bufs[i]); - if (q->irqlock) - spin_unlock_irqrestore(q->irqlock,flags); - q->reading = 1; - return 0; -} - -void videobuf_read_stop(struct videobuf_queue *q) -{ - int i; - - videobuf_queue_cancel(q); - videobuf_mmap_free(q); - INIT_LIST_HEAD(&q->stream); - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - kfree(q->bufs[i]); - q->bufs[i] = NULL; - } - q->read_buf = NULL; - q->reading = 0; -} - -ssize_t videobuf_read_stream(struct videobuf_queue *q, - char __user *data, size_t count, loff_t *ppos, - int vbihack, int nonblocking) -{ - unsigned int *fc, bytes; - int err, retval; - unsigned long flags=0; - - dprintk(2,"%s\n",__FUNCTION__); - mutex_lock(&q->lock); - retval = -EBUSY; - if (q->streaming) - goto done; - if (!q->reading) { - retval = videobuf_read_start(q); - if (retval < 0) - goto done; - } - - retval = 0; - while (count > 0) { - /* get / wait for data */ - if (NULL == q->read_buf) { - q->read_buf = list_entry(q->stream.next, - struct videobuf_buffer, - stream); - list_del(&q->read_buf->stream); - q->read_off = 0; - } - err = videobuf_waiton(q->read_buf, nonblocking, 1); - if (err < 0) { - if (0 == retval) - retval = err; - break; - } - - if (q->read_buf->state == STATE_DONE) { - if (vbihack) { - /* dirty, undocumented hack -- pass the frame counter - * within the last four bytes of each vbi data block. - * We need that one to maintain backward compatibility - * to all vbi decoding software out there ... */ - fc = (unsigned int*)q->read_buf->dma.vmalloc; - fc += (q->read_buf->size>>2) -1; - *fc = q->read_buf->field_count >> 1; - dprintk(1,"vbihack: %d\n",*fc); - } - - /* copy stuff */ - bytes = count; - if (bytes > q->read_buf->size - q->read_off) - bytes = q->read_buf->size - q->read_off; - if (copy_to_user(data + retval, - q->read_buf->dma.vmalloc + q->read_off, - bytes)) { - if (0 == retval) - retval = -EFAULT; - break; - } - count -= bytes; - retval += bytes; - q->read_off += bytes; - } else { - /* some error */ - q->read_off = q->read_buf->size; - if (0 == retval) - retval = -EIO; - } - - /* requeue buffer when done with copying */ - if (q->read_off == q->read_buf->size) { - list_add_tail(&q->read_buf->stream, - &q->stream); - if (q->irqlock) - spin_lock_irqsave(q->irqlock,flags); - q->ops->buf_queue(q,q->read_buf); - if (q->irqlock) - spin_unlock_irqrestore(q->irqlock,flags); - q->read_buf = NULL; - } - if (retval < 0) - break; - } - - done: - mutex_unlock(&q->lock); - return retval; -} - -unsigned int videobuf_poll_stream(struct file *file, - struct videobuf_queue *q, - poll_table *wait) -{ - struct videobuf_buffer *buf = NULL; - unsigned int rc = 0; - - mutex_lock(&q->lock); - if (q->streaming) { - if (!list_empty(&q->stream)) - buf = list_entry(q->stream.next, - struct videobuf_buffer, stream); - } else { - if (!q->reading) - videobuf_read_start(q); - if (!q->reading) { - rc = POLLERR; - } else if (NULL == q->read_buf) { - q->read_buf = list_entry(q->stream.next, - struct videobuf_buffer, - stream); - list_del(&q->read_buf->stream); - q->read_off = 0; - } - buf = q->read_buf; - } - if (!buf) - rc = POLLERR; - - if (0 == rc) { - poll_wait(file, &buf->done, wait); - if (buf->state == STATE_DONE || - buf->state == STATE_ERROR) - rc = POLLIN|POLLRDNORM; - } - mutex_unlock(&q->lock); - return rc; -} - -/* --------------------------------------------------------------------- */ - -static void -videobuf_vm_open(struct vm_area_struct *vma) -{ - struct videobuf_mapping *map = vma->vm_private_data; - - dprintk(2,"vm_open %p [count=%d,vma=%08lx-%08lx]\n",map, - map->count,vma->vm_start,vma->vm_end); - map->count++; -} - -static void -videobuf_vm_close(struct vm_area_struct *vma) -{ - struct videobuf_mapping *map = vma->vm_private_data; - struct videobuf_queue *q = map->q; - int i; - - dprintk(2,"vm_close %p [count=%d,vma=%08lx-%08lx]\n",map, - map->count,vma->vm_start,vma->vm_end); - - map->count--; - if (0 == map->count) { - dprintk(1,"munmap %p q=%p\n",map,q); - mutex_lock(&q->lock); - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - if (q->bufs[i]) - ; - if (q->bufs[i]->map != map) - continue; - q->bufs[i]->map = NULL; - q->bufs[i]->baddr = 0; - q->ops->buf_release(q,q->bufs[i]); - } - mutex_unlock(&q->lock); - kfree(map); - } - return; -} - -/* - * Get a anonymous page for the mapping. Make sure we can DMA to that - * memory location with 32bit PCI devices (i.e. don't use highmem for - * now ...). Bounce buffers don't work very well for the data rates - * video capture has. - */ -static struct page* -videobuf_vm_nopage(struct vm_area_struct *vma, unsigned long vaddr, - int *type) -{ - struct page *page; - - dprintk(3,"nopage: fault @ %08lx [vma %08lx-%08lx]\n", - vaddr,vma->vm_start,vma->vm_end); - if (vaddr > vma->vm_end) - return NOPAGE_SIGBUS; - page = alloc_page(GFP_USER | __GFP_DMA32); - if (!page) - return NOPAGE_OOM; - clear_user_page(page_address(page), vaddr, page); - if (type) - *type = VM_FAULT_MINOR; - return page; -} - -static struct vm_operations_struct videobuf_vm_ops = -{ - .open = videobuf_vm_open, - .close = videobuf_vm_close, - .nopage = videobuf_vm_nopage, -}; - -int videobuf_mmap_setup(struct videobuf_queue *q, - unsigned int bcount, unsigned int bsize, - enum v4l2_memory memory) -{ - unsigned int i; - int err; - - err = videobuf_mmap_free(q); - if (0 != err) - return err; - - for (i = 0; i < bcount; i++) { - q->bufs[i] = videobuf_alloc(q->msize); - q->bufs[i]->i = i; - q->bufs[i]->input = UNSET; - q->bufs[i]->memory = memory; - q->bufs[i]->bsize = bsize; - switch (memory) { - case V4L2_MEMORY_MMAP: - q->bufs[i]->boff = bsize * i; - break; - case V4L2_MEMORY_USERPTR: - case V4L2_MEMORY_OVERLAY: - /* nothing */ - break; - } - } - dprintk(1,"mmap setup: %d buffers, %d bytes each\n", - bcount,bsize); - return 0; -} - -int videobuf_mmap_free(struct videobuf_queue *q) -{ - int i; - - for (i = 0; i < VIDEO_MAX_FRAME; i++) - if (q->bufs[i] && q->bufs[i]->map) - return -EBUSY; - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - q->ops->buf_release(q,q->bufs[i]); - kfree(q->bufs[i]); - q->bufs[i] = NULL; - } - return 0; -} - -int videobuf_mmap_mapper(struct videobuf_queue *q, - struct vm_area_struct *vma) -{ - struct videobuf_mapping *map; - unsigned int first,last,size,i; - int retval; - - mutex_lock(&q->lock); - retval = -EINVAL; - if (!(vma->vm_flags & VM_WRITE)) { - dprintk(1,"mmap app bug: PROT_WRITE please\n"); - goto done; - } - if (!(vma->vm_flags & VM_SHARED)) { - dprintk(1,"mmap app bug: MAP_SHARED please\n"); - goto done; - } - - /* look for first buffer to map */ - for (first = 0; first < VIDEO_MAX_FRAME; first++) { - if (NULL == q->bufs[first]) - continue; - if (V4L2_MEMORY_MMAP != q->bufs[first]->memory) - continue; - if (q->bufs[first]->boff == (vma->vm_pgoff << PAGE_SHIFT)) - break; - } - if (VIDEO_MAX_FRAME == first) { - dprintk(1,"mmap app bug: offset invalid [offset=0x%lx]\n", - (vma->vm_pgoff << PAGE_SHIFT)); - goto done; - } - - /* look for last buffer to map */ - for (size = 0, last = first; last < VIDEO_MAX_FRAME; last++) { - if (NULL == q->bufs[last]) - continue; - if (V4L2_MEMORY_MMAP != q->bufs[last]->memory) - continue; - if (q->bufs[last]->map) { - retval = -EBUSY; - goto done; - } - size += q->bufs[last]->bsize; - if (size == (vma->vm_end - vma->vm_start)) - break; - } - if (VIDEO_MAX_FRAME == last) { - dprintk(1,"mmap app bug: size invalid [size=0x%lx]\n", - (vma->vm_end - vma->vm_start)); - goto done; - } - - /* create mapping + update buffer list */ - retval = -ENOMEM; - map = kmalloc(sizeof(struct videobuf_mapping),GFP_KERNEL); - if (NULL == map) - goto done; - for (size = 0, i = first; i <= last; size += q->bufs[i++]->bsize) { - q->bufs[i]->map = map; - q->bufs[i]->baddr = vma->vm_start + size; - } - map->count = 1; - map->start = vma->vm_start; - map->end = vma->vm_end; - map->q = q; - vma->vm_ops = &videobuf_vm_ops; - vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED; - vma->vm_flags &= ~VM_IO; /* using shared anonymous pages */ - vma->vm_private_data = map; - dprintk(1,"mmap %p: q=%p %08lx-%08lx pgoff %08lx bufs %d-%d\n", - map,q,vma->vm_start,vma->vm_end,vma->vm_pgoff,first,last); - retval = 0; - - done: - mutex_unlock(&q->lock); - return retval; -} - -/* --------------------------------------------------------------------- */ - -EXPORT_SYMBOL_GPL(videobuf_vmalloc_to_sg); - -EXPORT_SYMBOL_GPL(videobuf_dma_init); -EXPORT_SYMBOL_GPL(videobuf_dma_init_user); -EXPORT_SYMBOL_GPL(videobuf_dma_init_kernel); -EXPORT_SYMBOL_GPL(videobuf_dma_init_overlay); -EXPORT_SYMBOL_GPL(videobuf_dma_map); -EXPORT_SYMBOL_GPL(videobuf_dma_sync); -EXPORT_SYMBOL_GPL(videobuf_dma_unmap); -EXPORT_SYMBOL_GPL(videobuf_dma_free); - -EXPORT_SYMBOL_GPL(videobuf_pci_dma_map); -EXPORT_SYMBOL_GPL(videobuf_pci_dma_unmap); - -EXPORT_SYMBOL_GPL(videobuf_alloc); -EXPORT_SYMBOL_GPL(videobuf_waiton); -EXPORT_SYMBOL_GPL(videobuf_iolock); - -EXPORT_SYMBOL_GPL(videobuf_queue_init); -EXPORT_SYMBOL_GPL(videobuf_queue_cancel); -EXPORT_SYMBOL_GPL(videobuf_queue_is_busy); - -EXPORT_SYMBOL_GPL(videobuf_next_field); -EXPORT_SYMBOL_GPL(videobuf_status); -EXPORT_SYMBOL_GPL(videobuf_reqbufs); -EXPORT_SYMBOL_GPL(videobuf_querybuf); -EXPORT_SYMBOL_GPL(videobuf_qbuf); -EXPORT_SYMBOL_GPL(videobuf_dqbuf); -EXPORT_SYMBOL_GPL(videobuf_streamon); -EXPORT_SYMBOL_GPL(videobuf_streamoff); - -EXPORT_SYMBOL_GPL(videobuf_read_start); -EXPORT_SYMBOL_GPL(videobuf_read_stop); -EXPORT_SYMBOL_GPL(videobuf_read_stream); -EXPORT_SYMBOL_GPL(videobuf_read_one); -EXPORT_SYMBOL_GPL(videobuf_poll_stream); - -EXPORT_SYMBOL_GPL(videobuf_mmap_setup); -EXPORT_SYMBOL_GPL(videobuf_mmap_free); -EXPORT_SYMBOL_GPL(videobuf_mmap_mapper); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/include/media/video-buf.h b/include/media/video-buf.h deleted file mode 100644 index d6f079476db..00000000000 --- a/include/media/video-buf.h +++ /dev/null @@ -1,289 +0,0 @@ -/* - * - * generic helper functions for video4linux capture buffers, to handle - * memory management and PCI DMA. - * Right now, bttv, saa7134, saa7146 and cx88 use it. - * - * The functions expect the hardware being able to scatter gatter - * (i.e. the buffers are not linear in physical memory, but fragmented - * into PAGE_SIZE chunks). They also assume the driver does not need - * to touch the video data. - * - * device specific map/unmap/sync stuff now are mapped as file operations - * to allow its usage by USB and virtual devices. - * - * (c) 2001,02 Gerd Knorr - * (c) 2006 Mauro Carvalho Chehab, - * (c) 2006 Ted Walther and John Sokol - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include -#include - -#define UNSET (-1U) - -/* --------------------------------------------------------------------- */ - -/* - * Return a scatterlist for some page-aligned vmalloc()'ed memory - * block (NULL on errors). Memory for the scatterlist is allocated - * using kmalloc. The caller must free the memory. - */ -struct scatterlist* videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages); - -/* - * Return a scatterlist for a an array of userpages (NULL on errors). - * Memory for the scatterlist is allocated using kmalloc. The caller - * must free the memory. - */ -struct scatterlist* videobuf_pages_to_sg(struct page **pages, int nr_pages, - int offset); - -struct videobuf_buffer; -struct videobuf_queue; - -/* --------------------------------------------------------------------- */ - -/* - * A small set of helper functions to manage buffers (both userland - * and kernel) for DMA. - * - * videobuf_dma_init_*() - * creates a buffer. The userland version takes a userspace - * pointer + length. The kernel version just wants the size and - * does memory allocation too using vmalloc_32(). - * - * videobuf_dma_*() - * see Documentation/DMA-mapping.txt, these functions to - * basically the same. The map function does also build a - * scatterlist for the buffer (and unmap frees it ...) - * - * videobuf_dma_free() - * no comment ... - * - */ - -struct videobuf_dmabuf { - u32 magic; - - /* for userland buffer */ - int offset; - struct page **pages; - - /* for kernel buffers */ - void *vmalloc; - - /* Stores the userspace pointer to vmalloc area */ - void *varea; - - /* for overlay buffers (pci-pci dma) */ - dma_addr_t bus_addr; - - /* common */ - struct scatterlist *sglist; - int sglen; - int nr_pages; - int direction; -}; - -void videobuf_dma_init(struct videobuf_dmabuf *dma); -int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, - unsigned long data, unsigned long size); -int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction, - int nr_pages); -int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction, - dma_addr_t addr, int nr_pages); -int videobuf_dma_free(struct videobuf_dmabuf *dma); - -int videobuf_dma_map(struct videobuf_queue* q,struct videobuf_dmabuf *dma); -int videobuf_dma_sync(struct videobuf_queue* q,struct videobuf_dmabuf *dma); -int videobuf_dma_unmap(struct videobuf_queue* q,struct videobuf_dmabuf *dma); - - /*FIXME: these variants are used only on *-alsa code, where videobuf is - * used without queue - */ -int videobuf_pci_dma_map(struct pci_dev *pci,struct videobuf_dmabuf *dma); -int videobuf_pci_dma_unmap(struct pci_dev *pci,struct videobuf_dmabuf *dma); - -/* --------------------------------------------------------------------- */ - -/* - * A small set of helper functions to manage video4linux buffers. - * - * struct videobuf_buffer holds the data structures used by the helper - * functions, additionally some commonly used fields for v4l buffers - * (width, height, lists, waitqueue) are in there. That struct should - * be used as first element in the drivers buffer struct. - * - * about the mmap helpers (videobuf_mmap_*): - * - * The mmaper function allows to map any subset of contingous buffers. - * This includes one mmap() call for all buffers (which the original - * video4linux API uses) as well as one mmap() for every single buffer - * (which v4l2 uses). - * - * If there is a valid mapping for a buffer, buffer->baddr/bsize holds - * userspace address + size which can be feeded into the - * videobuf_dma_init_user function listed above. - * - */ - -struct videobuf_mapping { - unsigned int count; - unsigned long start; - unsigned long end; - struct videobuf_queue *q; -}; - -enum videobuf_state { - STATE_NEEDS_INIT = 0, - STATE_PREPARED = 1, - STATE_QUEUED = 2, - STATE_ACTIVE = 3, - STATE_DONE = 4, - STATE_ERROR = 5, - STATE_IDLE = 6, -}; - -struct videobuf_buffer { - unsigned int i; - u32 magic; - - /* info about the buffer */ - unsigned int width; - unsigned int height; - unsigned int bytesperline; /* use only if != 0 */ - unsigned long size; - unsigned int input; - enum v4l2_field field; - enum videobuf_state state; - struct videobuf_dmabuf dma; - struct list_head stream; /* QBUF/DQBUF list */ - - /* for mmap'ed buffers */ - enum v4l2_memory memory; - size_t boff; /* buffer offset (mmap + overlay) */ - size_t bsize; /* buffer size */ - unsigned long baddr; /* buffer addr (userland ptr!) */ - struct videobuf_mapping *map; - - /* touched by irq handler */ - struct list_head queue; - wait_queue_head_t done; - unsigned int field_count; - struct timeval ts; -}; - -typedef int (vb_map_sg_t)(void *dev,struct scatterlist *sglist,int nr_pages, - int direction); - - -struct videobuf_queue_ops { - int (*buf_setup)(struct videobuf_queue *q, - unsigned int *count, unsigned int *size); - int (*buf_prepare)(struct videobuf_queue *q, - struct videobuf_buffer *vb, - enum v4l2_field field); - void (*buf_queue)(struct videobuf_queue *q, - struct videobuf_buffer *vb); - void (*buf_release)(struct videobuf_queue *q, - struct videobuf_buffer *vb); - - /* Helper operations - device dependent. - * If null, videobuf_init defaults all to PCI handling - */ - - vb_map_sg_t *vb_map_sg; - vb_map_sg_t *vb_dma_sync_sg; - vb_map_sg_t *vb_unmap_sg; -}; - -struct videobuf_queue { - struct mutex lock; - spinlock_t *irqlock; - void *dev; /* on pci, points to struct pci_dev */ - - enum v4l2_buf_type type; - unsigned int inputs; /* for V4L2_BUF_FLAG_INPUT */ - unsigned int msize; - enum v4l2_field field; - enum v4l2_field last; /* for field=V4L2_FIELD_ALTERNATE */ - struct videobuf_buffer *bufs[VIDEO_MAX_FRAME]; - struct videobuf_queue_ops *ops; - - /* capture via mmap() + ioctl(QBUF/DQBUF) */ - unsigned int streaming; - struct list_head stream; - - /* capture via read() */ - unsigned int reading; - unsigned int read_off; - struct videobuf_buffer *read_buf; - - /* driver private data */ - void *priv_data; -}; - -void* videobuf_alloc(unsigned int size); -int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr); -int videobuf_iolock(struct videobuf_queue* q, struct videobuf_buffer *vb, - struct v4l2_framebuffer *fbuf); - -/* Maps fops to PCI stuff */ -void videobuf_queue_pci(struct videobuf_queue* q); - -void videobuf_queue_init(struct videobuf_queue *q, - struct videobuf_queue_ops *ops, - void *dev, - spinlock_t *irqlock, - enum v4l2_buf_type type, - enum v4l2_field field, - unsigned int msize, - void *priv); -int videobuf_queue_is_busy(struct videobuf_queue *q); -void videobuf_queue_cancel(struct videobuf_queue *q); - -enum v4l2_field videobuf_next_field(struct videobuf_queue *q); -void videobuf_status(struct v4l2_buffer *b, struct videobuf_buffer *vb, - enum v4l2_buf_type type); -int videobuf_reqbufs(struct videobuf_queue *q, - struct v4l2_requestbuffers *req); -int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b); -int videobuf_qbuf(struct videobuf_queue *q, - struct v4l2_buffer *b); -int videobuf_dqbuf(struct videobuf_queue *q, - struct v4l2_buffer *b, int nonblocking); -int videobuf_streamon(struct videobuf_queue *q); -int videobuf_streamoff(struct videobuf_queue *q); - -int videobuf_read_start(struct videobuf_queue *q); -void videobuf_read_stop(struct videobuf_queue *q); -ssize_t videobuf_read_stream(struct videobuf_queue *q, - char __user *data, size_t count, loff_t *ppos, - int vbihack, int nonblocking); -ssize_t videobuf_read_one(struct videobuf_queue *q, - char __user *data, size_t count, loff_t *ppos, - int nonblocking); -unsigned int videobuf_poll_stream(struct file *file, - struct videobuf_queue *q, - poll_table *wait); - -int videobuf_mmap_setup(struct videobuf_queue *q, - unsigned int bcount, unsigned int bsize, - enum v4l2_memory memory); -int videobuf_mmap_free(struct videobuf_queue *q); -int videobuf_mmap_mapper(struct videobuf_queue *q, - struct vm_area_struct *vma); - -/* --------------------------------------------------------------------- */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ -- cgit v1.2.3-70-g09d2 From 9eb59573d4b86f347e6cd04f47a4c2082009fa58 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Wed, 10 Oct 2007 02:18:27 +0200 Subject: [CPUFREQ] Don't take semaphore in cpufreq_quick_get() I don't see any reason to take an expensive lock in cpufreq_quick_get() Reading policy->cur is a single atomic operation and after the lock is dropped again the state could change any time anyways. So don't take the lock in the first place. This also makes this function interrupt safe which is useful for some code of mine. Signed-off-by: Andi Kleen Cc: "Pallipadi, Venkatesh" Signed-off-by: Dave Jones --- drivers/cpufreq/cpufreq.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index e027052a660..f7b9d6fce12 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1111,12 +1111,7 @@ unsigned int cpufreq_quick_get(unsigned int cpu) unsigned int ret_freq = 0; if (policy) { - if (unlikely(lock_policy_rwsem_read(cpu))) - return ret_freq; - ret_freq = policy->cur; - - unlock_policy_rwsem_read(cpu); cpufreq_cpu_put(policy); } -- cgit v1.2.3-70-g09d2 From e54664c0958acf14ef3a65d1b78f4a54b437cdf7 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Sun, 29 Jul 2007 15:12:26 -0500 Subject: RDMA/cxgb3: Make the iw_cxgb3 module parameters writable Allow changing parameter values without having to reload the module. This is safe because these parameters are only looked at when a new connection is established. Signed-off-by: Steve Wise Signed-off-by: Roland Dreier --- drivers/infiniband/hw/cxgb3/iwch_cm.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c index 1cdfcd43b0b..20ba372dd18 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_cm.c +++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c @@ -63,37 +63,37 @@ static char *states[] = { }; static int ep_timeout_secs = 10; -module_param(ep_timeout_secs, int, 0444); +module_param(ep_timeout_secs, int, 0644); MODULE_PARM_DESC(ep_timeout_secs, "CM Endpoint operation timeout " "in seconds (default=10)"); static int mpa_rev = 1; -module_param(mpa_rev, int, 0444); +module_param(mpa_rev, int, 0644); MODULE_PARM_DESC(mpa_rev, "MPA Revision, 0 supports amso1100, " "1 is spec compliant. (default=1)"); static int markers_enabled = 0; -module_param(markers_enabled, int, 0444); +module_param(markers_enabled, int, 0644); MODULE_PARM_DESC(markers_enabled, "Enable MPA MARKERS (default(0)=disabled)"); static int crc_enabled = 1; -module_param(crc_enabled, int, 0444); +module_param(crc_enabled, int, 0644); MODULE_PARM_DESC(crc_enabled, "Enable MPA CRC (default(1)=enabled)"); static int rcv_win = 256 * 1024; -module_param(rcv_win, int, 0444); +module_param(rcv_win, int, 0644); MODULE_PARM_DESC(rcv_win, "TCP receive window in bytes (default=256)"); static int snd_win = 32 * 1024; -module_param(snd_win, int, 0444); +module_param(snd_win, int, 0644); MODULE_PARM_DESC(snd_win, "TCP send window in bytes (default=32KB)"); static unsigned int nocong = 0; -module_param(nocong, uint, 0444); +module_param(nocong, uint, 0644); MODULE_PARM_DESC(nocong, "Turn off congestion control (default=0)"); static unsigned int cong_flavor = 1; -module_param(cong_flavor, uint, 0444); +module_param(cong_flavor, uint, 0644); MODULE_PARM_DESC(cong_flavor, "TCP Congestion control flavor (default=1)"); static void process_work(struct work_struct *work); -- cgit v1.2.3-70-g09d2 From ce423ef50ee1b6b7db63c748034423aa0afce224 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 9 Oct 2007 19:59:04 -0700 Subject: IPoIB: Make sure no receives are handled when stopping device The current IPoIB code might process receive completions from ipoib_drain_cq() when bringing down the interface. This could cause packets to be passed up the stack without the device's poll method being called. Avoid this by setting the status of any successful completions to IB_WC_WR_FLUSH_ERR. Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/ipoib/ipoib_ib.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index 10944888cff..5a70e287f25 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -558,6 +558,14 @@ void ipoib_drain_cq(struct net_device *dev) do { n = ib_poll_cq(priv->cq, IPOIB_NUM_WC, priv->ibwc); for (i = 0; i < n; ++i) { + /* + * Convert any successful completions to flush + * errors to avoid passing packets up the + * stack after bringing the device down. + */ + if (priv->ibwc[i].status == IB_WC_SUCCESS) + priv->ibwc[i].status = IB_WC_WR_FLUSH_ERR; + if (priv->ibwc[i].wr_id & IPOIB_CM_OP_SRQ) ipoib_cm_handle_rx_wc(dev, priv->ibwc + i); else if (priv->ibwc[i].wr_id & IPOIB_OP_RECV) -- cgit v1.2.3-70-g09d2 From 65d470b3ea52ee1402499d6fcb4632296452e5b1 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 9 Oct 2007 19:59:04 -0700 Subject: IB: find_first_zero_bit() takes unsigned pointer Fix sparse warning drivers/infiniband/core/device.c:142:6: warning: incorrect type in argument 1 (different signedness) drivers/infiniband/core/device.c:142:6: expected unsigned long const *addr drivers/infiniband/core/device.c:142:6: got long *[assigned] inuse by making the local variable inuse unsigned. Does not affect generated code at all. Signed-off-by: Roland Dreier --- drivers/infiniband/core/device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c index 2506c43ba04..5ac5ffee05c 100644 --- a/drivers/infiniband/core/device.c +++ b/drivers/infiniband/core/device.c @@ -120,12 +120,12 @@ static struct ib_device *__ib_device_get_by_name(const char *name) static int alloc_name(char *name) { - long *inuse; + unsigned long *inuse; char buf[IB_DEVICE_NAME_MAX]; struct ib_device *device; int i; - inuse = (long *) get_zeroed_page(GFP_KERNEL); + inuse = (unsigned long *) get_zeroed_page(GFP_KERNEL); if (!inuse) return -ENOMEM; -- cgit v1.2.3-70-g09d2 From 36ce10d3e849c2f9efa3fd647058de398ee276eb Mon Sep 17 00:00:00 2001 From: Dotan Barak Date: Tue, 7 Aug 2007 11:18:52 +0300 Subject: mlx4_core: Use enum value GO_BIT_TIMEOUT_MSECS Rename GO_BIT_TIMEOUT to GO_BIT_TIMEOUT_MSECS for clarity, and actually use it as the go bit timeout (instead of having the define but then ignoring it and using a hard-coded 10 * HZ for the actual timeout). Signed-off-by: Dotan Barak Signed-off-by: Roland Dreier --- drivers/net/mlx4/cmd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/mlx4/cmd.c b/drivers/net/mlx4/cmd.c index a9f31753661..b540820e9c2 100644 --- a/drivers/net/mlx4/cmd.c +++ b/drivers/net/mlx4/cmd.c @@ -95,7 +95,7 @@ enum { }; enum { - GO_BIT_TIMEOUT = 10000 + GO_BIT_TIMEOUT_MSECS = 10000 }; struct mlx4_cmd_context { @@ -155,7 +155,7 @@ static int mlx4_cmd_post(struct mlx4_dev *dev, u64 in_param, u64 out_param, end = jiffies; if (event) - end += HZ * 10; + end += msecs_to_jiffies(GO_BIT_TIMEOUT_MSECS); while (cmd_pending(dev)) { if (time_after_eq(jiffies, end)) -- cgit v1.2.3-70-g09d2 From eaf559bf566f76887533c077d425adce847f06c8 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 9 Oct 2007 19:59:05 -0700 Subject: mlx4_core: Don't free special QPs in QP number bitmap Special QPs are not allocated using the regular QP number bitmap, so when they are destroyed, their QP number should not be freed in the bitmap. Found by Dotan Barak of Mellanox. Signed-off-by: Roland Dreier --- drivers/net/mlx4/qp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/mlx4/qp.c b/drivers/net/mlx4/qp.c index 19b48c71cf7..278414b2d01 100644 --- a/drivers/net/mlx4/qp.c +++ b/drivers/net/mlx4/qp.c @@ -240,7 +240,8 @@ void mlx4_qp_free(struct mlx4_dev *dev, struct mlx4_qp *qp) mlx4_table_put(dev, &qp_table->auxc_table, qp->qpn); mlx4_table_put(dev, &qp_table->qp_table, qp->qpn); - mlx4_bitmap_free(&qp_table->bitmap, qp->qpn); + if (qp->qpn < dev->caps.sqp_start + 8) + mlx4_bitmap_free(&qp_table->bitmap, qp->qpn); } EXPORT_SYMBOL_GPL(mlx4_qp_free); -- cgit v1.2.3-70-g09d2 From 2242fa4f04d670f02efb43ec537d677edc220880 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 9 Oct 2007 19:59:05 -0700 Subject: IB/mlx4: Use __set_data_seg() in mlx4_ib_post_recv() Use a __set_data_seg() helper in mlx4_ib_post_recv() too; in addition to making the code easier to read, this also allows gcc to generate better code -- on x86_64: add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-8 (-8) function old new delta mlx4_ib_post_recv 359 351 -8 Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mlx4/qp.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c index 85c51bdc36f..31a480e5b0d 100644 --- a/drivers/infiniband/hw/mlx4/qp.c +++ b/drivers/infiniband/hw/mlx4/qp.c @@ -1249,6 +1249,13 @@ static void set_data_seg(struct mlx4_wqe_data_seg *dseg, struct ib_sge *sg) dseg->byte_count = cpu_to_be32(sg->length); } +static void __set_data_seg(struct mlx4_wqe_data_seg *dseg, struct ib_sge *sg) +{ + dseg->byte_count = cpu_to_be32(sg->length); + dseg->lkey = cpu_to_be32(sg->lkey); + dseg->addr = cpu_to_be64(sg->addr); +} + int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, struct ib_send_wr **bad_wr) { @@ -1464,11 +1471,8 @@ int mlx4_ib_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *wr, scat = get_recv_wqe(qp, ind); - for (i = 0; i < wr->num_sge; ++i) { - scat[i].byte_count = cpu_to_be32(wr->sg_list[i].length); - scat[i].lkey = cpu_to_be32(wr->sg_list[i].lkey); - scat[i].addr = cpu_to_be64(wr->sg_list[i].addr); - } + for (i = 0; i < wr->num_sge; ++i) + __set_data_seg(scat + i, wr->sg_list + i); if (i < qp->rq.max_gs) { scat[i].byte_count = 0; -- cgit v1.2.3-70-g09d2 From 1fea391039d1c4e876a164099bff475a02a29d96 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 9 Oct 2007 19:59:05 -0700 Subject: IB/ehca: Include from ehca_classes.h ehca_classes.h uses struct mutex, so while seems to be pulled in indirectly by one of the headers it includes, the right thing is to include directly. Signed-off-by: Michael S. Tsirkin Acked-by: Stefan Roscher Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/ehca_classes.h | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h index b5e96030531..0d69f0f001d 100644 --- a/drivers/infiniband/hw/ehca/ehca_classes.h +++ b/drivers/infiniband/hw/ehca/ehca_classes.h @@ -53,6 +53,7 @@ struct ehca_pd; struct ehca_av; #include +#include #include #include -- cgit v1.2.3-70-g09d2 From 8a68bbe31d51cc75d2acf1c9f5ceff91f7662ea4 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Wed, 29 Aug 2007 08:36:22 -0500 Subject: IB/fmr_pool: Clean up some error messages in fmr_pool.c A number of printks in fmr_pool.c dont have newlines, eg: fmr_create failed for FMR 0<5>FS-Cache: Loaded Fix them up. Signed-off-by: Anton Blanchard Signed-off-by: Roland Dreier --- drivers/infiniband/core/fmr_pool.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/fmr_pool.c b/drivers/infiniband/core/fmr_pool.c index a06bcc65a87..d7f64525469 100644 --- a/drivers/infiniband/core/fmr_pool.c +++ b/drivers/infiniband/core/fmr_pool.c @@ -152,7 +152,7 @@ static void ib_fmr_batch_release(struct ib_fmr_pool *pool) #ifdef DEBUG if (fmr->ref_count !=0) { - printk(KERN_WARNING PFX "Unmapping FMR 0x%08x with ref count %d", + printk(KERN_WARNING PFX "Unmapping FMR 0x%08x with ref count %d\n", fmr, fmr->ref_count); } #endif @@ -170,7 +170,7 @@ static void ib_fmr_batch_release(struct ib_fmr_pool *pool) ret = ib_unmap_fmr(&fmr_list); if (ret) - printk(KERN_WARNING PFX "ib_unmap_fmr returned %d", ret); + printk(KERN_WARNING PFX "ib_unmap_fmr returned %d\n", ret); spin_lock_irq(&pool->pool_lock); list_splice(&unmap_list, &pool->free_list); @@ -235,13 +235,13 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd, attr = kmalloc(sizeof *attr, GFP_KERNEL); if (!attr) { - printk(KERN_WARNING PFX "couldn't allocate device attr struct"); + printk(KERN_WARNING PFX "couldn't allocate device attr struct\n"); return ERR_PTR(-ENOMEM); } ret = ib_query_device(device, attr); if (ret) { - printk(KERN_WARNING PFX "couldn't query device: %d", ret); + printk(KERN_WARNING PFX "couldn't query device: %d\n", ret); kfree(attr); return ERR_PTR(ret); } @@ -255,7 +255,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd, pool = kmalloc(sizeof *pool, GFP_KERNEL); if (!pool) { - printk(KERN_WARNING PFX "couldn't allocate pool struct"); + printk(KERN_WARNING PFX "couldn't allocate pool struct\n"); return ERR_PTR(-ENOMEM); } @@ -272,7 +272,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd, kmalloc(IB_FMR_HASH_SIZE * sizeof *pool->cache_bucket, GFP_KERNEL); if (!pool->cache_bucket) { - printk(KERN_WARNING PFX "Failed to allocate cache in pool"); + printk(KERN_WARNING PFX "Failed to allocate cache in pool\n"); ret = -ENOMEM; goto out_free_pool; } @@ -296,7 +296,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd, "ib_fmr(%s)", device->name); if (IS_ERR(pool->thread)) { - printk(KERN_WARNING PFX "couldn't start cleanup thread"); + printk(KERN_WARNING PFX "couldn't start cleanup thread\n"); ret = PTR_ERR(pool->thread); goto out_free_pool; } @@ -314,7 +314,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd, GFP_KERNEL); if (!fmr) { printk(KERN_WARNING PFX "failed to allocate fmr " - "struct for FMR %d", i); + "struct for FMR %d\n", i); goto out_fail; } @@ -326,7 +326,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd, fmr->fmr = ib_alloc_fmr(pd, params->access, &fmr_attr); if (IS_ERR(fmr->fmr)) { printk(KERN_WARNING PFX "fmr_create failed " - "for FMR %d", i); + "for FMR %d\n", i); kfree(fmr); goto out_fail; } @@ -381,7 +381,7 @@ void ib_destroy_fmr_pool(struct ib_fmr_pool *pool) } if (i < pool->pool_size) - printk(KERN_WARNING PFX "pool still has %d regions registered", + printk(KERN_WARNING PFX "pool still has %d regions registered\n", pool->pool_size - i); kfree(pool->cache_bucket); @@ -518,7 +518,7 @@ int ib_fmr_pool_unmap(struct ib_pool_fmr *fmr) #ifdef DEBUG if (fmr->ref_count < 0) - printk(KERN_WARNING PFX "FMR %p has ref count %d < 0", + printk(KERN_WARNING PFX "FMR %p has ref count %d < 0\n", fmr, fmr->ref_count); #endif -- cgit v1.2.3-70-g09d2 From 08fb105540f4649eaa25270ec3ada1d35406afcc Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Tue, 7 Aug 2007 16:08:28 +0300 Subject: mlx4_core: Enable MSI-X by default Recover from MSI-X errors by automatically falling back on regular interrupt, instead of asking the user to do this manually. This makes it possible to enable MSI-X by default, and will make it possible to get rid of the msi_x module option in the future. Signed-off-by: Michael S. Tsirkin Signed-off-by: Roland Dreier --- drivers/net/mlx4/main.c | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c index 4dc9dc19b71..4b126943558 100644 --- a/drivers/net/mlx4/main.c +++ b/drivers/net/mlx4/main.c @@ -61,7 +61,7 @@ MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0"); #ifdef CONFIG_PCI_MSI -static int msi_x; +static int msi_x = 1; module_param(msi_x, int, 0444); MODULE_PARM_DESC(msi_x, "attempt to use MSI-X if nonzero"); @@ -599,13 +599,17 @@ static int __devinit mlx4_setup_hca(struct mlx4_dev *dev) err = mlx4_NOP(dev); if (err) { - mlx4_err(dev, "NOP command failed to generate interrupt " - "(IRQ %d), aborting.\n", - priv->eq_table.eq[MLX4_EQ_ASYNC].irq); - if (dev->flags & MLX4_FLAG_MSI_X) - mlx4_err(dev, "Try again with MSI-X disabled.\n"); - else + if (dev->flags & MLX4_FLAG_MSI_X) { + mlx4_warn(dev, "NOP command failed to generate MSI-X " + "interrupt IRQ %d).\n", + priv->eq_table.eq[MLX4_EQ_ASYNC].irq); + mlx4_warn(dev, "Trying again without MSI-X.\n"); + } else { + mlx4_err(dev, "NOP command failed to generate interrupt " + "(IRQ %d), aborting.\n", + priv->eq_table.eq[MLX4_EQ_ASYNC].irq); mlx4_err(dev, "BIOS or ACPI interrupt routing problem?\n"); + } goto err_cmd_poll; } @@ -803,8 +807,6 @@ static int __devinit mlx4_init_one(struct pci_dev *pdev, goto err_free_dev; } - mlx4_enable_msi_x(dev); - if (mlx4_cmd_init(dev)) { mlx4_err(dev, "Failed to init command interface, aborting.\n"); goto err_free_dev; @@ -814,7 +816,15 @@ static int __devinit mlx4_init_one(struct pci_dev *pdev, if (err) goto err_cmd; + mlx4_enable_msi_x(dev); + err = mlx4_setup_hca(dev); + if (err == -EBUSY && (dev->flags & MLX4_FLAG_MSI_X)) { + dev->flags &= ~MLX4_FLAG_MSI_X; + pci_disable_msix(pdev); + err = mlx4_setup_hca(dev); + } + if (err) goto err_close; @@ -838,15 +848,15 @@ err_cleanup: mlx4_cleanup_uar_table(dev); err_close: + if (dev->flags & MLX4_FLAG_MSI_X) + pci_disable_msix(pdev); + mlx4_close_hca(dev); err_cmd: mlx4_cmd_cleanup(dev); err_free_dev: - if (dev->flags & MLX4_FLAG_MSI_X) - pci_disable_msix(pdev); - kfree(priv); err_release_bar2: -- cgit v1.2.3-70-g09d2 From 017aadc4b505ad3ec2acc4e6ba96d63ae1c997a5 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Tue, 7 Aug 2007 16:10:34 +0300 Subject: IB/mthca: Enable MSI-X by default Recover from MSI-X errors by automatically falling back on regular interrupt, instead of asking the user to do this manually. This makes it possible to enable MSI-X by default, and will make it possible to get rid of the msi_x module option in the future. Signed-off-by: Michael S. Tsirkin Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_main.c | 77 +++++++++++++++++++------------- 1 file changed, 46 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c index 76fed7545c5..04c1520524c 100644 --- a/drivers/infiniband/hw/mthca/mthca_main.c +++ b/drivers/infiniband/hw/mthca/mthca_main.c @@ -61,7 +61,7 @@ MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0"); #ifdef CONFIG_PCI_MSI -static int msi_x = 0; +static int msi_x = 1; module_param(msi_x, int, 0444); MODULE_PARM_DESC(msi_x, "attempt to use MSI-X if nonzero"); @@ -833,14 +833,19 @@ static int mthca_setup_hca(struct mthca_dev *dev) err = mthca_NOP(dev, &status); if (err || status) { - mthca_err(dev, "NOP command failed to generate interrupt (IRQ %d), aborting.\n", - dev->mthca_flags & MTHCA_FLAG_MSI_X ? - dev->eq_table.eq[MTHCA_EQ_CMD].msi_x_vector : - dev->pdev->irq); - if (dev->mthca_flags & (MTHCA_FLAG_MSI | MTHCA_FLAG_MSI_X)) - mthca_err(dev, "Try again with MSI/MSI-X disabled.\n"); - else + if (dev->mthca_flags & (MTHCA_FLAG_MSI | MTHCA_FLAG_MSI_X)) { + mthca_warn(dev, "NOP command failed to generate interrupt " + "(IRQ %d).\n", + dev->mthca_flags & MTHCA_FLAG_MSI_X ? + dev->eq_table.eq[MTHCA_EQ_CMD].msi_x_vector : + dev->pdev->irq); + mthca_warn(dev, "Trying again with MSI/MSI-X disabled.\n"); + } else { + mthca_err(dev, "NOP command failed to generate interrupt " + "(IRQ %d), aborting.\n", + dev->pdev->irq); mthca_err(dev, "BIOS or ACPI interrupt routing problem?\n"); + } goto err_cmd_poll; } @@ -1115,24 +1120,6 @@ static int __mthca_init_one(struct pci_dev *pdev, int hca_type) goto err_free_dev; } - if (msi_x && !mthca_enable_msi_x(mdev)) - mdev->mthca_flags |= MTHCA_FLAG_MSI_X; - else if (msi) { - static int warned; - - if (!warned) { - printk(KERN_WARNING PFX "WARNING: MSI support will be " - "removed from the ib_mthca driver in January 2008.\n"); - printk(KERN_WARNING " If you are using MSI and cannot " - "switch to MSI-X, please tell " - ".\n"); - ++warned; - } - - if (!pci_enable_msi(pdev)) - mdev->mthca_flags |= MTHCA_FLAG_MSI; - } - if (mthca_cmd_init(mdev)) { mthca_err(mdev, "Failed to init command interface, aborting.\n"); goto err_free_dev; @@ -1156,7 +1143,35 @@ static int __mthca_init_one(struct pci_dev *pdev, int hca_type) mthca_warn(mdev, "If you have problems, try updating your HCA FW.\n"); } + if (msi_x && !mthca_enable_msi_x(mdev)) + mdev->mthca_flags |= MTHCA_FLAG_MSI_X; + else if (msi) { + static int warned; + + if (!warned) { + printk(KERN_WARNING PFX "WARNING: MSI support will be " + "removed from the ib_mthca driver in January 2008.\n"); + printk(KERN_WARNING " If you are using MSI and cannot " + "switch to MSI-X, please tell " + ".\n"); + ++warned; + } + + if (!pci_enable_msi(pdev)) + mdev->mthca_flags |= MTHCA_FLAG_MSI; + } + err = mthca_setup_hca(mdev); + if (err == -EBUSY && (mdev->mthca_flags & (MTHCA_FLAG_MSI | MTHCA_FLAG_MSI_X))) { + if (mdev->mthca_flags & MTHCA_FLAG_MSI_X) + pci_disable_msix(pdev); + if (mdev->mthca_flags & MTHCA_FLAG_MSI) + pci_disable_msi(pdev); + mdev->mthca_flags &= ~(MTHCA_FLAG_MSI_X | MTHCA_FLAG_MSI); + + err = mthca_setup_hca(mdev); + } + if (err) goto err_close; @@ -1192,17 +1207,17 @@ err_cleanup: mthca_cleanup_uar_table(mdev); err_close: + if (mdev->mthca_flags & MTHCA_FLAG_MSI_X) + pci_disable_msix(pdev); + if (mdev->mthca_flags & MTHCA_FLAG_MSI) + pci_disable_msi(pdev); + mthca_close_hca(mdev); err_cmd: mthca_cmd_cleanup(mdev); err_free_dev: - if (mdev->mthca_flags & MTHCA_FLAG_MSI_X) - pci_disable_msix(pdev); - if (mdev->mthca_flags & MTHCA_FLAG_MSI) - pci_disable_msi(pdev); - ib_dealloc_device(&mdev->ib_dev); err_free_res: -- cgit v1.2.3-70-g09d2 From b3ac60fc243f2312d27ecded058ef96f52f25fe0 Mon Sep 17 00:00:00 2001 From: Eli Cohen Date: Tue, 9 Oct 2007 19:59:06 -0700 Subject: IPoIB: Fix typo to end statement with ';' instead of ',' Signed-off-by: Eli Cohen Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/ipoib/ipoib_verbs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c index 563aeacf9e1..3c6e45db0ab 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c @@ -185,7 +185,7 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca) goto out_free_cq; init_attr.send_cq = priv->cq; - init_attr.recv_cq = priv->cq, + init_attr.recv_cq = priv->cq; priv->qp = ib_create_qp(priv->pd, &init_attr); if (IS_ERR(priv->qp)) { -- cgit v1.2.3-70-g09d2 From ca6de177acef8f2c7c3901ea583a263364ca7bbb Mon Sep 17 00:00:00 2001 From: Eli Cohen Date: Tue, 21 Aug 2007 18:46:10 +0300 Subject: IPoIB: Fix error path memory leak Clean up properly if ib_query_pkey() or ib_query_gid() fail. Signed-off-by: Eli Cohen Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/ipoib/ipoib_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 894b1dcdf3e..5f948b9a994 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -1083,7 +1083,7 @@ static struct net_device *ipoib_add_port(const char *format, if (result) { printk(KERN_WARNING "%s: ib_query_pkey port %d failed (ret = %d)\n", hca->name, port, result); - goto alloc_mem_failed; + goto device_init_failed; } /* @@ -1099,7 +1099,7 @@ static struct net_device *ipoib_add_port(const char *format, if (result) { printk(KERN_WARNING "%s: ib_query_gid port %d failed (ret = %d)\n", hca->name, port, result); - goto alloc_mem_failed; + goto device_init_failed; } else memcpy(priv->dev->dev_addr + 4, priv->local_gid.raw, sizeof (union ib_gid)); -- cgit v1.2.3-70-g09d2 From d7dc3ccbe4dd1d37950da0138079e61d5be06ca9 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 9 Oct 2007 19:59:06 -0700 Subject: IB/mlx4: Fix up SRQ limit_watermark endianness mlx4_srq_query() returns a big-endian 16-bit value through an int *, which screws up sparse checking. Fix this so that a CPU-endian value is returned. Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mlx4/srq.c | 2 +- drivers/net/mlx4/srq.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx4/srq.c b/drivers/infiniband/hw/mlx4/srq.c index 408748fb528..e7e9a3d0dac 100644 --- a/drivers/infiniband/hw/mlx4/srq.c +++ b/drivers/infiniband/hw/mlx4/srq.c @@ -251,7 +251,7 @@ int mlx4_ib_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *srq_attr) if (ret) return ret; - srq_attr->srq_limit = be16_to_cpu(limit_watermark); + srq_attr->srq_limit = limit_watermark; srq_attr->max_wr = srq->msrq.max - 1; srq_attr->max_sge = srq->msrq.max_gs; diff --git a/drivers/net/mlx4/srq.c b/drivers/net/mlx4/srq.c index b061c86d683..31b255a3291 100644 --- a/drivers/net/mlx4/srq.c +++ b/drivers/net/mlx4/srq.c @@ -227,7 +227,7 @@ int mlx4_srq_query(struct mlx4_dev *dev, struct mlx4_srq *srq, int *limit_waterm err = mlx4_QUERY_SRQ(dev, mailbox, srq->srqn); if (err) goto err_out; - *limit_watermark = srq_context->limit_watermark; + *limit_watermark = be16_to_cpu(srq_context->limit_watermark); err_out: mlx4_free_cmd_mailbox(dev, mailbox); -- cgit v1.2.3-70-g09d2 From 1f794483025bc1e9e8e3321089a7f29ad3cc448f Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Wed, 29 Aug 2007 11:05:35 -0500 Subject: IB/ehca: Make output clearer by removing some debug messages ehca spits out a lot of debugging information. I had to look closely to see the "Port 1 is not active" message within all the debug: eHCA Infiniband Device Driver (Rel.: SVNEHCA_0022) eHCA scaling code enabled ehca D.001.DQDXYCB-P1-C9: PU0006 EHCA_ERR:ehca_define_sqp Port 1 is not active. ehca D.001.DQDXYCB-P1-C9: PU0006 EHCA_ERR:ehca_create_qp ehca_define_sqp() failed rc=ffffffffffffffff ib_mad: Couldn't create ib_mad QP1 ib_mad: Couldn't open ehca0 port 1 ehca D.001.DQDXYCB-P1-C9: PU0006 EHCA_ERR:ehca_alloc_fmr unsupported fmr_attr->page_shift=9 ehca D.001.DQDXYCB-P1-C9: PU0006 EHCA_ERR:ehca_alloc_fmr rc=ffffffffffffffea pd=c000000b4b5b2420 mr_access_flags=7 fmr_attr=c0000005afd37394 fmr_create failed for FMR 0 Remove a few debug statements so that things are clearer: eHCA Infiniband Device Driver (Rel.: SVNEHCA_0022) eHCA scaling code enabled ehca D.001.DQDXYCB-P1-C9: PU0006 EHCA_ERR:ehca_define_sqp Port 1 is not active. ib_mad: Couldn't create ib_mad QP1 ib_mad: Couldn't open ehca0 port 1 ehca D.001.DQDXYCB-P1-C9: PU0006 EHCA_ERR:ehca_alloc_fmr unsupported fmr_attr->page_shift=9 fmr_create failed for FMR 0 Signed-off-by: Anton Blanchard Acked-by: Hoang-Nam Nguyen Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/ehca_mrmw.c | 4 ---- drivers/infiniband/hw/ehca/ehca_qp.c | 2 -- 2 files changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ehca/ehca_mrmw.c b/drivers/infiniband/hw/ehca/ehca_mrmw.c index d97eda3e1da..dc4c84040aa 100644 --- a/drivers/infiniband/hw/ehca/ehca_mrmw.c +++ b/drivers/infiniband/hw/ehca/ehca_mrmw.c @@ -846,10 +846,6 @@ struct ib_fmr *ehca_alloc_fmr(struct ib_pd *pd, alloc_fmr_exit1: ehca_mr_delete(e_fmr); alloc_fmr_exit0: - if (IS_ERR(ib_fmr)) - ehca_err(pd->device, "rc=%lx pd=%p mr_access_flags=%x " - "fmr_attr=%p", PTR_ERR(ib_fmr), pd, - mr_access_flags, fmr_attr); return ib_fmr; } /* end ehca_alloc_fmr() */ diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c index 84d435a5ee1..88f07451fb8 100644 --- a/drivers/infiniband/hw/ehca/ehca_qp.c +++ b/drivers/infiniband/hw/ehca/ehca_qp.c @@ -714,8 +714,6 @@ static struct ehca_qp *internal_create_qp( if (qp_type == IB_QPT_GSI) { h_ret = ehca_define_sqp(shca, my_qp, init_attr); if (h_ret != H_SUCCESS) { - ehca_err(pd->device, "ehca_define_sqp() failed rc=%lx", - h_ret); ret = ehca2ib_return_code(h_ret); goto create_qp_exit4; } -- cgit v1.2.3-70-g09d2 From 339e2640a9f403f7b7acb2ea67f3568b8ac3eebf Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Wed, 29 Aug 2007 12:43:01 -0500 Subject: IB/ehca: Export module parameters in sysfs At the moment the ehca module parameters are not exported in sysfs. Export them with 0444 permissions. Signed-off-by: Anton Blanchard Acked-by: Hoang-Nam Nguyen Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/ehca_main.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c index 99036b65bb8..db041dfb412 100644 --- a/drivers/infiniband/hw/ehca/ehca_main.c +++ b/drivers/infiniband/hw/ehca/ehca_main.c @@ -65,16 +65,16 @@ int ehca_static_rate = -1; int ehca_scaling_code = 0; int ehca_mr_largepage = 0; -module_param_named(open_aqp1, ehca_open_aqp1, int, 0); -module_param_named(debug_level, ehca_debug_level, int, 0); -module_param_named(hw_level, ehca_hw_level, int, 0); -module_param_named(nr_ports, ehca_nr_ports, int, 0); -module_param_named(use_hp_mr, ehca_use_hp_mr, int, 0); -module_param_named(port_act_time, ehca_port_act_time, int, 0); -module_param_named(poll_all_eqs, ehca_poll_all_eqs, int, 0); -module_param_named(static_rate, ehca_static_rate, int, 0); -module_param_named(scaling_code, ehca_scaling_code, int, 0); -module_param_named(mr_largepage, ehca_mr_largepage, int, 0); +module_param_named(open_aqp1, ehca_open_aqp1, int, S_IRUGO); +module_param_named(debug_level, ehca_debug_level, int, S_IRUGO); +module_param_named(hw_level, ehca_hw_level, int, S_IRUGO); +module_param_named(nr_ports, ehca_nr_ports, int, S_IRUGO); +module_param_named(use_hp_mr, ehca_use_hp_mr, int, S_IRUGO); +module_param_named(port_act_time, ehca_port_act_time, int, S_IRUGO); +module_param_named(poll_all_eqs, ehca_poll_all_eqs, int, S_IRUGO); +module_param_named(static_rate, ehca_static_rate, int, S_IRUGO); +module_param_named(scaling_code, ehca_scaling_code, int, S_IRUGO); +module_param_named(mr_largepage, ehca_mr_largepage, int, S_IRUGO); MODULE_PARM_DESC(open_aqp1, "AQP1 on startup (0: no (default), 1: yes)"); -- cgit v1.2.3-70-g09d2 From 3c10c7c929b30e8813d15960cb97f95a0b2ba615 Mon Sep 17 00:00:00 2001 From: Ali Ayoub Date: Sun, 9 Sep 2007 14:55:11 +0300 Subject: IB/sa: Error handling thinko fix ib_create_send_mad() returns an error code pointer on error, not NULL. Signed-off-by: Michael S. Tsirkin Signed-off-by: Roland Dreier --- drivers/infiniband/core/sa_query.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c index d271bd715c1..312c8ff5ae8 100644 --- a/drivers/infiniband/core/sa_query.c +++ b/drivers/infiniband/core/sa_query.c @@ -531,7 +531,7 @@ static int alloc_mad(struct ib_sa_query *query, gfp_t gfp_mask) query->sm_ah->pkey_index, 0, IB_MGMT_SA_HDR, IB_MGMT_SA_DATA, gfp_mask); - if (!query->mad_buf) { + if (IS_ERR(query->mad_buf)) { kref_put(&query->sm_ah->ref, free_sm_ah); return -ENOMEM; } -- cgit v1.2.3-70-g09d2 From a855b1a7423ac83c76638f156d79c854b0feb94d Mon Sep 17 00:00:00 2001 From: Peter Oruba Date: Fri, 10 Aug 2007 13:54:33 -0700 Subject: IB/mthca: Use PCI-X/PCI-Express read control interfaces These driver changes incorporate the proposed PCI-X / PCI-Express read byte count interface. Reading and setting those values doesn't take place "manually", instead wrapping functions are called to allow quirks for some PCI bridges. Signed-off by: Peter Oruba Based on work by Stephen Hemminger Cc: Roland Dreier Cc: Michael S. Tsirkin Signed-off-by: Andrew Morton Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_main.c | 33 ++++++++------------------------ 1 file changed, 8 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c index 04c1520524c..60de6f93869 100644 --- a/drivers/infiniband/hw/mthca/mthca_main.c +++ b/drivers/infiniband/hw/mthca/mthca_main.c @@ -137,40 +137,23 @@ static const char mthca_version[] __devinitdata = static int mthca_tune_pci(struct mthca_dev *mdev) { - int cap; - u16 val; - if (!tune_pci) return 0; /* First try to max out Read Byte Count */ - cap = pci_find_capability(mdev->pdev, PCI_CAP_ID_PCIX); - if (cap) { - if (pci_read_config_word(mdev->pdev, cap + PCI_X_CMD, &val)) { - mthca_err(mdev, "Couldn't read PCI-X command register, " - "aborting.\n"); - return -ENODEV; - } - val = (val & ~PCI_X_CMD_MAX_READ) | (3 << 2); - if (pci_write_config_word(mdev->pdev, cap + PCI_X_CMD, val)) { - mthca_err(mdev, "Couldn't write PCI-X command register, " - "aborting.\n"); + if (pci_find_capability(mdev->pdev, PCI_CAP_ID_PCIX)) { + if (pcix_set_mmrbc(mdev->pdev, pcix_get_max_mmrbc(mdev->pdev))) { + mthca_err(mdev, "Couldn't set PCI-X max read count, " + "aborting.\n"); return -ENODEV; } } else if (!(mdev->mthca_flags & MTHCA_FLAG_PCIE)) mthca_info(mdev, "No PCI-X capability, not setting RBC.\n"); - cap = pci_find_capability(mdev->pdev, PCI_CAP_ID_EXP); - if (cap) { - if (pci_read_config_word(mdev->pdev, cap + PCI_EXP_DEVCTL, &val)) { - mthca_err(mdev, "Couldn't read PCI Express device control " - "register, aborting.\n"); - return -ENODEV; - } - val = (val & ~PCI_EXP_DEVCTL_READRQ) | (5 << 12); - if (pci_write_config_word(mdev->pdev, cap + PCI_EXP_DEVCTL, val)) { - mthca_err(mdev, "Couldn't write PCI Express device control " - "register, aborting.\n"); + if (pci_find_capability(mdev->pdev, PCI_CAP_ID_EXP)) { + if (pcie_set_readrq(mdev->pdev, 4096)) { + mthca_err(mdev, "Couldn't write PCI Express read request, " + "aborting.\n"); return -ENODEV; } } else if (mdev->mthca_flags & MTHCA_FLAG_PCIE) -- cgit v1.2.3-70-g09d2 From 441633b968a5be0ef9be7c37ae24c35eda5b730d Mon Sep 17 00:00:00 2001 From: Stefan Roscher Date: Tue, 11 Sep 2007 15:26:33 +0200 Subject: IB/ehca: Small QP userspace support Signed-off-by: Joachim Fenkes Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/ehca_qp.c | 7 +++---- drivers/infiniband/hw/ehca/ipz_pt_fn.c | 1 + 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c index 88f07451fb8..87b32ab6caf 100644 --- a/drivers/infiniband/hw/ehca/ehca_qp.c +++ b/drivers/infiniband/hw/ehca/ehca_qp.c @@ -273,6 +273,7 @@ static inline void queue2resp(struct ipzu_queue_resp *resp, resp->queue_length = queue->queue_length; resp->pagesize = queue->pagesize; resp->toggle_state = queue->toggle_state; + resp->offset = queue->offset; } /* @@ -598,8 +599,7 @@ static struct ehca_qp *internal_create_qp( parms.squeue.max_sge = max_send_sge; parms.rqueue.max_sge = max_recv_sge; - if (EHCA_BMASK_GET(HCA_CAP_MINI_QP, shca->hca_cap) - && !(context && udata)) { /* no small QP support in userspace ATM */ + if (EHCA_BMASK_GET(HCA_CAP_MINI_QP, shca->hca_cap)) { if (HAS_SQ(my_qp)) ehca_determine_small_queue( &parms.squeue, max_send_sge, is_llqp); @@ -739,8 +739,7 @@ static struct ehca_qp *internal_create_qp( resp.ext_type = my_qp->ext_type; resp.qkey = my_qp->qkey; resp.real_qp_num = my_qp->real_qp_num; - resp.ipz_rqueue.offset = my_qp->ipz_rqueue.offset; - resp.ipz_squeue.offset = my_qp->ipz_squeue.offset; + if (HAS_SQ(my_qp)) queue2resp(&resp.ipz_squeue, &my_qp->ipz_squeue); if (HAS_RQ(my_qp)) diff --git a/drivers/infiniband/hw/ehca/ipz_pt_fn.c b/drivers/infiniband/hw/ehca/ipz_pt_fn.c index 29bd476fbd5..661f8db6270 100644 --- a/drivers/infiniband/hw/ehca/ipz_pt_fn.c +++ b/drivers/infiniband/hw/ehca/ipz_pt_fn.c @@ -158,6 +158,7 @@ static int alloc_small_queue_page(struct ipz_queue *queue, struct ehca_pd *pd) queue->queue_pages[0] = (void *)(page->page | (bit << (order + 9))); queue->small_page = page; + queue->offset = bit << (order + 9); return 1; out: -- cgit v1.2.3-70-g09d2 From 5281a4b8a0c6bac0c070913ec25868faa06a3115 Mon Sep 17 00:00:00 2001 From: Stefan Roscher Date: Tue, 11 Sep 2007 15:29:39 +0200 Subject: IB/ehca: Support more than 4k QPs for userspace and kernelspace Signed-off-by: Joachim Fenkes Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/ehca_cq.c | 7 ++++++- drivers/infiniband/hw/ehca/ehca_main.c | 2 +- drivers/infiniband/hw/ehca/ehca_qp.c | 9 +++++++-- drivers/infiniband/hw/ehca/ehca_uverbs.c | 22 +++++++++++----------- 4 files changed, 25 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ehca/ehca_cq.c b/drivers/infiniband/hw/ehca/ehca_cq.c index 81aff36101b..a6f17e488c7 100644 --- a/drivers/infiniband/hw/ehca/ehca_cq.c +++ b/drivers/infiniband/hw/ehca/ehca_cq.c @@ -166,7 +166,6 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector, write_lock_irqsave(&ehca_cq_idr_lock, flags); ret = idr_get_new(&ehca_cq_idr, my_cq, &my_cq->token); write_unlock_irqrestore(&ehca_cq_idr_lock, flags); - } while (ret == -EAGAIN); if (ret) { @@ -176,6 +175,12 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector, goto create_cq_exit1; } + if (my_cq->token > 0x1FFFFFF) { + cq = ERR_PTR(-ENOMEM); + ehca_err(device, "Invalid number of cq. device=%p", device); + goto create_cq_exit2; + } + /* * CQs maximum depth is 4GB-64, but we need additional 20 as buffer * for receiving errors CQEs. diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c index db041dfb412..99169073917 100644 --- a/drivers/infiniband/hw/ehca/ehca_main.c +++ b/drivers/infiniband/hw/ehca/ehca_main.c @@ -380,7 +380,7 @@ int ehca_init_device(struct ehca_shca *shca) strlcpy(shca->ib_device.name, "ehca%d", IB_DEVICE_NAME_MAX); shca->ib_device.owner = THIS_MODULE; - shca->ib_device.uverbs_abi_ver = 7; + shca->ib_device.uverbs_abi_ver = 8; shca->ib_device.uverbs_cmd_mask = (1ull << IB_USER_VERBS_CMD_GET_CONTEXT) | (1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) | diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c index 87b32ab6caf..bfae1c228b2 100644 --- a/drivers/infiniband/hw/ehca/ehca_qp.c +++ b/drivers/infiniband/hw/ehca/ehca_qp.c @@ -557,7 +557,6 @@ static struct ehca_qp *internal_create_qp( write_lock_irqsave(&ehca_qp_idr_lock, flags); ret = idr_get_new(&ehca_qp_idr, my_qp, &my_qp->token); write_unlock_irqrestore(&ehca_qp_idr_lock, flags); - } while (ret == -EAGAIN); if (ret) { @@ -566,11 +565,17 @@ static struct ehca_qp *internal_create_qp( goto create_qp_exit0; } + if (my_qp->token > 0x1FFFFFF) { + ret = -EINVAL; + ehca_err(pd->device, "Invalid number of qp"); + goto create_qp_exit1; + } + parms.servicetype = ibqptype2servicetype(qp_type); if (parms.servicetype < 0) { ret = -EINVAL; ehca_err(pd->device, "Invalid qp_type=%x", qp_type); - goto create_qp_exit0; + goto create_qp_exit1; } if (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR) diff --git a/drivers/infiniband/hw/ehca/ehca_uverbs.c b/drivers/infiniband/hw/ehca/ehca_uverbs.c index 4bc687fdf53..3340f49f021 100644 --- a/drivers/infiniband/hw/ehca/ehca_uverbs.c +++ b/drivers/infiniband/hw/ehca/ehca_uverbs.c @@ -164,7 +164,7 @@ static int ehca_mmap_cq(struct vm_area_struct *vma, struct ehca_cq *cq, int ret; switch (rsrc_type) { - case 1: /* galpa fw handle */ + case 0: /* galpa fw handle */ ehca_dbg(cq->ib_cq.device, "cq_num=%x fw", cq->cq_number); ret = ehca_mmap_fw(vma, &cq->galpas, &cq->mm_count_galpa); if (unlikely(ret)) { @@ -175,7 +175,7 @@ static int ehca_mmap_cq(struct vm_area_struct *vma, struct ehca_cq *cq, } break; - case 2: /* cq queue_addr */ + case 1: /* cq queue_addr */ ehca_dbg(cq->ib_cq.device, "cq_num=%x queue", cq->cq_number); ret = ehca_mmap_queue(vma, &cq->ipz_queue, &cq->mm_count_queue); if (unlikely(ret)) { @@ -201,7 +201,7 @@ static int ehca_mmap_qp(struct vm_area_struct *vma, struct ehca_qp *qp, int ret; switch (rsrc_type) { - case 1: /* galpa fw handle */ + case 0: /* galpa fw handle */ ehca_dbg(qp->ib_qp.device, "qp_num=%x fw", qp->ib_qp.qp_num); ret = ehca_mmap_fw(vma, &qp->galpas, &qp->mm_count_galpa); if (unlikely(ret)) { @@ -212,7 +212,7 @@ static int ehca_mmap_qp(struct vm_area_struct *vma, struct ehca_qp *qp, } break; - case 2: /* qp rqueue_addr */ + case 1: /* qp rqueue_addr */ ehca_dbg(qp->ib_qp.device, "qp_num=%x rqueue", qp->ib_qp.qp_num); ret = ehca_mmap_queue(vma, &qp->ipz_rqueue, @@ -225,7 +225,7 @@ static int ehca_mmap_qp(struct vm_area_struct *vma, struct ehca_qp *qp, } break; - case 3: /* qp squeue_addr */ + case 2: /* qp squeue_addr */ ehca_dbg(qp->ib_qp.device, "qp_num=%x squeue", qp->ib_qp.qp_num); ret = ehca_mmap_queue(vma, &qp->ipz_squeue, @@ -249,10 +249,10 @@ static int ehca_mmap_qp(struct vm_area_struct *vma, struct ehca_qp *qp, int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) { - u64 fileoffset = vma->vm_pgoff << PAGE_SHIFT; - u32 idr_handle = fileoffset >> 32; - u32 q_type = (fileoffset >> 28) & 0xF; /* CQ, QP,... */ - u32 rsrc_type = (fileoffset >> 24) & 0xF; /* sq,rq,cmnd_window */ + u64 fileoffset = vma->vm_pgoff; + u32 idr_handle = fileoffset & 0x1FFFFFF; + u32 q_type = (fileoffset >> 27) & 0x1; /* CQ, QP,... */ + u32 rsrc_type = (fileoffset >> 25) & 0x3; /* sq,rq,cmnd_window */ u32 cur_pid = current->tgid; u32 ret; struct ehca_cq *cq; @@ -261,7 +261,7 @@ int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) struct ib_uobject *uobject; switch (q_type) { - case 1: /* CQ */ + case 0: /* CQ */ read_lock(&ehca_cq_idr_lock); cq = idr_find(&ehca_cq_idr, idr_handle); read_unlock(&ehca_cq_idr_lock); @@ -289,7 +289,7 @@ int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) } break; - case 2: /* QP */ + case 1: /* QP */ read_lock(&ehca_qp_idr_lock); qp = idr_find(&ehca_qp_idr, idr_handle); read_unlock(&ehca_qp_idr_lock); -- cgit v1.2.3-70-g09d2 From e390d3b52f791fcea26312ba4982cda82052727b Mon Sep 17 00:00:00 2001 From: Hoang-Nam Nguyen Date: Tue, 11 Sep 2007 15:31:06 +0200 Subject: IB/ehca: Use remap_4k_pfn() to map firmware contexts to user space Use Paul's new remap_4k_pfn() function to map our 4K firmware contexts into user space on 64K-page machines without exposing neighboring firmware contexts. Return the context's offset within a 64K page to user space so it can determine the proper virtual address. For details about remap_4k_pfn(), see commit 721151d0 or http://patchwork.ozlabs.org/linuxppc/patch?id=10281 Signed-off-by: Joachim Fenkes Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/ehca_classes.h | 4 +++- drivers/infiniband/hw/ehca/ehca_cq.c | 2 ++ drivers/infiniband/hw/ehca/ehca_qp.c | 2 ++ drivers/infiniband/hw/ehca/ehca_uverbs.c | 6 +++--- 4 files changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h index 0d69f0f001d..0942a173881 100644 --- a/drivers/infiniband/hw/ehca/ehca_classes.h +++ b/drivers/infiniband/hw/ehca/ehca_classes.h @@ -338,6 +338,8 @@ struct ehca_create_cq_resp { u32 cq_number; u32 token; struct ipzu_queue_resp ipz_queue; + u32 fw_handle_ofs; + u32 dummy; }; struct ehca_create_qp_resp { @@ -348,7 +350,7 @@ struct ehca_create_qp_resp { u32 qkey; /* qp_num assigned by ehca: sqp0/1 may have got different numbers */ u32 real_qp_num; - u32 dummy; /* padding for 8 byte alignment */ + u32 fw_handle_ofs; struct ipzu_queue_resp ipz_squeue; struct ipzu_queue_resp ipz_rqueue; }; diff --git a/drivers/infiniband/hw/ehca/ehca_cq.c b/drivers/infiniband/hw/ehca/ehca_cq.c index a6f17e488c7..d68603ddfc2 100644 --- a/drivers/infiniband/hw/ehca/ehca_cq.c +++ b/drivers/infiniband/hw/ehca/ehca_cq.c @@ -281,6 +281,8 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector, resp.ipz_queue.queue_length = ipz_queue->queue_length; resp.ipz_queue.pagesize = ipz_queue->pagesize; resp.ipz_queue.toggle_state = ipz_queue->toggle_state; + resp.fw_handle_ofs = (u32) + (my_cq->galpas.user.fw_handle & (PAGE_SIZE - 1)); if (ib_copy_to_udata(udata, &resp, sizeof(resp))) { ehca_err(device, "Copy to udata failed."); goto create_cq_exit4; diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c index bfae1c228b2..e89fdca7fa1 100644 --- a/drivers/infiniband/hw/ehca/ehca_qp.c +++ b/drivers/infiniband/hw/ehca/ehca_qp.c @@ -749,6 +749,8 @@ static struct ehca_qp *internal_create_qp( queue2resp(&resp.ipz_squeue, &my_qp->ipz_squeue); if (HAS_RQ(my_qp)) queue2resp(&resp.ipz_rqueue, &my_qp->ipz_rqueue); + resp.fw_handle_ofs = (u32) + (my_qp->galpas.user.fw_handle & (PAGE_SIZE - 1)); if (ib_copy_to_udata(udata, &resp, sizeof resp)) { ehca_err(pd->device, "Copy to udata failed"); diff --git a/drivers/infiniband/hw/ehca/ehca_uverbs.c b/drivers/infiniband/hw/ehca/ehca_uverbs.c index 3340f49f021..84a16bcfd53 100644 --- a/drivers/infiniband/hw/ehca/ehca_uverbs.c +++ b/drivers/infiniband/hw/ehca/ehca_uverbs.c @@ -109,7 +109,7 @@ static int ehca_mmap_fw(struct vm_area_struct *vma, struct h_galpas *galpas, u64 vsize, physical; vsize = vma->vm_end - vma->vm_start; - if (vsize != EHCA_PAGESIZE) { + if (vsize < EHCA_PAGESIZE) { ehca_gen_err("invalid vsize=%lx", vma->vm_end - vma->vm_start); return -EINVAL; } @@ -118,8 +118,8 @@ static int ehca_mmap_fw(struct vm_area_struct *vma, struct h_galpas *galpas, vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); ehca_gen_dbg("vsize=%lx physical=%lx", vsize, physical); /* VM_IO | VM_RESERVED are set by remap_pfn_range() */ - ret = remap_pfn_range(vma, vma->vm_start, physical >> PAGE_SHIFT, - vsize, vma->vm_page_prot); + ret = remap_4k_pfn(vma, vma->vm_start, physical >> EHCA_PAGESHIFT, + vma->vm_page_prot); if (unlikely(ret)) { ehca_gen_err("remap_pfn_range() failed ret=%x", ret); return -ENOMEM; -- cgit v1.2.3-70-g09d2 From 2863ad4bddf366790a733cfd71f2f480afdf36fc Mon Sep 17 00:00:00 2001 From: Joachim Fenkes Date: Tue, 11 Sep 2007 15:31:49 +0200 Subject: IB/ehca: Refactor hvcall tracing Change hvcall trace output towards better readability: reg numbers instead of argument numbers, return code as signed decimal instead of unsigned hex. Signed-off-by: Joachim Fenkes Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/hcp_if.c | 57 ++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ehca/hcp_if.c b/drivers/infiniband/hw/ehca/hcp_if.c index 24f454162f2..a762cc7e016 100644 --- a/drivers/infiniband/hw/ehca/hcp_if.c +++ b/drivers/infiniband/hw/ehca/hcp_if.c @@ -84,6 +84,10 @@ #define H_MP_SHUTDOWN EHCA_BMASK_IBM(48, 48) #define H_MP_RESET_QKEY_CTR EHCA_BMASK_IBM(49, 49) +#define HCALL4_REGS_FORMAT "r4=%lx r5=%lx r6=%lx r7=%lx" +#define HCALL7_REGS_FORMAT HCALL4_REGS_FORMAT " r8=%lx r9=%lx r10=%lx" +#define HCALL9_REGS_FORMAT HCALL7_REGS_FORMAT " r11=%lx r12=%lx" + static DEFINE_SPINLOCK(hcall_lock); static u32 get_longbusy_msecs(int longbusy_rc) @@ -118,8 +122,7 @@ static long ehca_plpar_hcall_norets(unsigned long opcode, long ret; int i, sleep_msecs; - ehca_gen_dbg("opcode=%lx arg1=%lx arg2=%lx arg3=%lx arg4=%lx " - "arg5=%lx arg6=%lx arg7=%lx", + ehca_gen_dbg("opcode=%lx " HCALL7_REGS_FORMAT, opcode, arg1, arg2, arg3, arg4, arg5, arg6, arg7); for (i = 0; i < 5; i++) { @@ -133,16 +136,13 @@ static long ehca_plpar_hcall_norets(unsigned long opcode, } if (ret < H_SUCCESS) - ehca_gen_err("opcode=%lx ret=%lx" - " arg1=%lx arg2=%lx arg3=%lx arg4=%lx" - " arg5=%lx arg6=%lx arg7=%lx ", - opcode, ret, - arg1, arg2, arg3, arg4, arg5, - arg6, arg7); - - ehca_gen_dbg("opcode=%lx ret=%lx", opcode, ret); - return ret; + ehca_gen_err("opcode=%lx ret=%li " HCALL7_REGS_FORMAT, + opcode, ret, arg1, arg2, arg3, + arg4, arg5, arg6, arg7); + else + ehca_gen_dbg("opcode=%lx ret=%li", opcode, ret); + return ret; } return H_BUSY; @@ -164,10 +164,8 @@ static long ehca_plpar_hcall9(unsigned long opcode, int i, sleep_msecs, lock_is_set = 0; unsigned long flags = 0; - ehca_gen_dbg("opcode=%lx arg1=%lx arg2=%lx arg3=%lx arg4=%lx " - "arg5=%lx arg6=%lx arg7=%lx arg8=%lx arg9=%lx", - opcode, arg1, arg2, arg3, arg4, arg5, arg6, arg7, - arg8, arg9); + ehca_gen_dbg("INPUT -- opcode=%lx " HCALL9_REGS_FORMAT, opcode, + arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); for (i = 0; i < 5; i++) { if ((opcode == H_ALLOC_RESOURCE) && (arg2 == 5)) { @@ -188,26 +186,19 @@ static long ehca_plpar_hcall9(unsigned long opcode, continue; } - if (ret < H_SUCCESS) - ehca_gen_err("opcode=%lx ret=%lx" - " arg1=%lx arg2=%lx arg3=%lx arg4=%lx" - " arg5=%lx arg6=%lx arg7=%lx arg8=%lx" - " arg9=%lx" - " out1=%lx out2=%lx out3=%lx out4=%lx" - " out5=%lx out6=%lx out7=%lx out8=%lx" - " out9=%lx", - opcode, ret, - arg1, arg2, arg3, arg4, arg5, - arg6, arg7, arg8, arg9, - outs[0], outs[1], outs[2], outs[3], + if (ret < H_SUCCESS) { + ehca_gen_err("INPUT -- opcode=%lx " HCALL9_REGS_FORMAT, + opcode, arg1, arg2, arg3, arg4, arg5, + arg6, arg7, arg8, arg9); + ehca_gen_err("OUTPUT -- ret=%li " HCALL9_REGS_FORMAT, + ret, outs[0], outs[1], outs[2], outs[3], + outs[4], outs[5], outs[6], outs[7], + outs[8]); + } else + ehca_gen_dbg("OUTPUT -- ret=%li " HCALL9_REGS_FORMAT, + ret, outs[0], outs[1], outs[2], outs[3], outs[4], outs[5], outs[6], outs[7], outs[8]); - - ehca_gen_dbg("opcode=%lx ret=%lx out1=%lx out2=%lx out3=%lx " - "out4=%lx out5=%lx out6=%lx out7=%lx out8=%lx " - "out9=%lx", - opcode, ret, outs[0], outs[1], outs[2], outs[3], - outs[4], outs[5], outs[6], outs[7], outs[8]); return ret; } -- cgit v1.2.3-70-g09d2 From e37221928bf685d63ba5319746eafe463d61e330 Mon Sep 17 00:00:00 2001 From: Joachim Fenkes Date: Tue, 11 Sep 2007 15:32:22 +0200 Subject: IB/ehca: Print return codes as signed decimal integers ...because -12 is easier to read than FFFFFFF4. Signed-off-by: Joachim Fenkes Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/ehca_cq.c | 14 +++--- drivers/infiniband/hw/ehca/ehca_hca.c | 2 +- drivers/infiniband/hw/ehca/ehca_main.c | 24 +++++------ drivers/infiniband/hw/ehca/ehca_mcast.c | 4 +- drivers/infiniband/hw/ehca/ehca_mrmw.c | 73 ++++++++++++++++---------------- drivers/infiniband/hw/ehca/ehca_qp.c | 42 +++++++++--------- drivers/infiniband/hw/ehca/ehca_reqs.c | 2 +- drivers/infiniband/hw/ehca/ehca_sqp.c | 2 +- drivers/infiniband/hw/ehca/ehca_uverbs.c | 18 ++++---- drivers/infiniband/hw/ehca/hcp_if.c | 20 ++++----- 10 files changed, 100 insertions(+), 101 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ehca/ehca_cq.c b/drivers/infiniband/hw/ehca/ehca_cq.c index d68603ddfc2..79c25f51c21 100644 --- a/drivers/infiniband/hw/ehca/ehca_cq.c +++ b/drivers/infiniband/hw/ehca/ehca_cq.c @@ -190,7 +190,7 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector, if (h_ret != H_SUCCESS) { ehca_err(device, "hipz_h_alloc_resource_cq() failed " - "h_ret=%lx device=%p", h_ret, device); + "h_ret=%li device=%p", h_ret, device); cq = ERR_PTR(ehca2ib_return_code(h_ret)); goto create_cq_exit2; } @@ -198,7 +198,7 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector, ipz_rc = ipz_queue_ctor(NULL, &my_cq->ipz_queue, param.act_pages, EHCA_PAGESIZE, sizeof(struct ehca_cqe), 0, 0); if (!ipz_rc) { - ehca_err(device, "ipz_queue_ctor() failed ipz_rc=%x device=%p", + ehca_err(device, "ipz_queue_ctor() failed ipz_rc=%i device=%p", ipz_rc, device); cq = ERR_PTR(-EINVAL); goto create_cq_exit3; @@ -226,7 +226,7 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector, if (h_ret < H_SUCCESS) { ehca_err(device, "hipz_h_register_rpage_cq() failed " - "ehca_cq=%p cq_num=%x h_ret=%lx counter=%i " + "ehca_cq=%p cq_num=%x h_ret=%li counter=%i " "act_pages=%i", my_cq, my_cq->cq_number, h_ret, counter, param.act_pages); cq = ERR_PTR(-EINVAL); @@ -238,7 +238,7 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector, if ((h_ret != H_SUCCESS) || vpage) { ehca_err(device, "Registration of pages not " "complete ehca_cq=%p cq_num=%x " - "h_ret=%lx", my_cq, my_cq->cq_number, + "h_ret=%li", my_cq, my_cq->cq_number, h_ret); cq = ERR_PTR(-EAGAIN); goto create_cq_exit4; @@ -246,7 +246,7 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector, } else { if (h_ret != H_PAGE_REGISTERED) { ehca_err(device, "Registration of page failed " - "ehca_cq=%p cq_num=%x h_ret=%lx" + "ehca_cq=%p cq_num=%x h_ret=%li" "counter=%i act_pages=%i", my_cq, my_cq->cq_number, h_ret, counter, param.act_pages); @@ -298,7 +298,7 @@ create_cq_exit3: h_ret = hipz_h_destroy_cq(adapter_handle, my_cq, 1); if (h_ret != H_SUCCESS) ehca_err(device, "hipz_h_destroy_cq() failed ehca_cq=%p " - "cq_num=%x h_ret=%lx", my_cq, my_cq->cq_number, h_ret); + "cq_num=%x h_ret=%li", my_cq, my_cq->cq_number, h_ret); create_cq_exit2: write_lock_irqsave(&ehca_cq_idr_lock, flags); @@ -362,7 +362,7 @@ int ehca_destroy_cq(struct ib_cq *cq) cq_num); } if (h_ret != H_SUCCESS) { - ehca_err(device, "hipz_h_destroy_cq() failed h_ret=%lx " + ehca_err(device, "hipz_h_destroy_cq() failed h_ret=%li " "ehca_cq=%p cq_num=%x", h_ret, my_cq, cq_num); return ehca2ib_return_code(h_ret); } diff --git a/drivers/infiniband/hw/ehca/ehca_hca.c b/drivers/infiniband/hw/ehca/ehca_hca.c index cf22472d941..3436c49eee0 100644 --- a/drivers/infiniband/hw/ehca/ehca_hca.c +++ b/drivers/infiniband/hw/ehca/ehca_hca.c @@ -352,7 +352,7 @@ int ehca_modify_port(struct ib_device *ibdev, hret = hipz_h_modify_port(shca->ipz_hca_handle, port, cap, props->init_type, port_modify_mask); if (hret != H_SUCCESS) { - ehca_err(&shca->ib_device, "Modify port failed hret=%lx", + ehca_err(&shca->ib_device, "Modify port failed h_ret=%li", hret); ret = -EINVAL; } diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c index 99169073917..0e3ffeef45d 100644 --- a/drivers/infiniband/hw/ehca/ehca_main.c +++ b/drivers/infiniband/hw/ehca/ehca_main.c @@ -273,7 +273,7 @@ int ehca_sense_attributes(struct ehca_shca *shca) h_ret = hipz_h_query_hca(shca->ipz_hca_handle, rblock); if (h_ret != H_SUCCESS) { - ehca_gen_err("Cannot query device properties. h_ret=%lx", + ehca_gen_err("Cannot query device properties. h_ret=%li", h_ret); ret = -EPERM; goto sense_attributes1; @@ -332,7 +332,7 @@ int ehca_sense_attributes(struct ehca_shca *shca) port = (struct hipz_query_port *)rblock; h_ret = hipz_h_query_port(shca->ipz_hca_handle, 1, port); if (h_ret != H_SUCCESS) { - ehca_gen_err("Cannot query port properties. h_ret=%lx", + ehca_gen_err("Cannot query port properties. h_ret=%li", h_ret); ret = -EPERM; goto sense_attributes1; @@ -526,13 +526,13 @@ static int ehca_destroy_aqp1(struct ehca_sport *sport) ret = ib_destroy_qp(sport->ibqp_aqp1); if (ret) { - ehca_gen_err("Cannot destroy AQP1 QP. ret=%x", ret); + ehca_gen_err("Cannot destroy AQP1 QP. ret=%i", ret); return ret; } ret = ib_destroy_cq(sport->ibcq_aqp1); if (ret) - ehca_gen_err("Cannot destroy AQP1 CQ. ret=%x", ret); + ehca_gen_err("Cannot destroy AQP1 CQ. ret=%i", ret); return ret; } @@ -728,7 +728,7 @@ static int __devinit ehca_probe(struct ibmebus_dev *dev, ret = ehca_reg_internal_maxmr(shca, shca->pd, &shca->maxmr); if (ret) { - ehca_err(&shca->ib_device, "Cannot create internal MR ret=%x", + ehca_err(&shca->ib_device, "Cannot create internal MR ret=%i", ret); goto probe5; } @@ -736,7 +736,7 @@ static int __devinit ehca_probe(struct ibmebus_dev *dev, ret = ib_register_device(&shca->ib_device); if (ret) { ehca_err(&shca->ib_device, - "ib_register_device() failed ret=%x", ret); + "ib_register_device() failed ret=%i", ret); goto probe6; } @@ -777,7 +777,7 @@ probe8: ret = ehca_destroy_aqp1(&shca->sport[0]); if (ret) ehca_err(&shca->ib_device, - "Cannot destroy AQP1 for port 1. ret=%x", ret); + "Cannot destroy AQP1 for port 1. ret=%i", ret); probe7: ib_unregister_device(&shca->ib_device); @@ -826,7 +826,7 @@ static int __devexit ehca_remove(struct ibmebus_dev *dev) if (ret) ehca_err(&shca->ib_device, "Cannot destroy AQP1 for port %x " - "ret=%x", ret, i); + "ret=%i", ret, i); } } @@ -835,20 +835,20 @@ static int __devexit ehca_remove(struct ibmebus_dev *dev) ret = ehca_dereg_internal_maxmr(shca); if (ret) ehca_err(&shca->ib_device, - "Cannot destroy internal MR. ret=%x", ret); + "Cannot destroy internal MR. ret=%i", ret); ret = ehca_dealloc_pd(&shca->pd->ib_pd); if (ret) ehca_err(&shca->ib_device, - "Cannot destroy internal PD. ret=%x", ret); + "Cannot destroy internal PD. ret=%i", ret); ret = ehca_destroy_eq(shca, &shca->eq); if (ret) - ehca_err(&shca->ib_device, "Cannot destroy EQ. ret=%x", ret); + ehca_err(&shca->ib_device, "Cannot destroy EQ. ret=%i", ret); ret = ehca_destroy_eq(shca, &shca->neq); if (ret) - ehca_err(&shca->ib_device, "Canot destroy NEQ. ret=%x", ret); + ehca_err(&shca->ib_device, "Canot destroy NEQ. ret=%i", ret); ib_dealloc_device(&shca->ib_device); diff --git a/drivers/infiniband/hw/ehca/ehca_mcast.c b/drivers/infiniband/hw/ehca/ehca_mcast.c index 32a870660bf..e3ef0264ccc 100644 --- a/drivers/infiniband/hw/ehca/ehca_mcast.c +++ b/drivers/infiniband/hw/ehca/ehca_mcast.c @@ -88,7 +88,7 @@ int ehca_attach_mcast(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) if (h_ret != H_SUCCESS) ehca_err(ibqp->device, "ehca_qp=%p qp_num=%x hipz_h_attach_mcqp() failed " - "h_ret=%lx", my_qp, ibqp->qp_num, h_ret); + "h_ret=%li", my_qp, ibqp->qp_num, h_ret); return ehca2ib_return_code(h_ret); } @@ -125,7 +125,7 @@ int ehca_detach_mcast(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) if (h_ret != H_SUCCESS) ehca_err(ibqp->device, "ehca_qp=%p qp_num=%x hipz_h_detach_mcqp() failed " - "h_ret=%lx", my_qp, ibqp->qp_num, h_ret); + "h_ret=%li", my_qp, ibqp->qp_num, h_ret); return ehca2ib_return_code(h_ret); } diff --git a/drivers/infiniband/hw/ehca/ehca_mrmw.c b/drivers/infiniband/hw/ehca/ehca_mrmw.c index dc4c84040aa..e925e84c9bc 100644 --- a/drivers/infiniband/hw/ehca/ehca_mrmw.c +++ b/drivers/infiniband/hw/ehca/ehca_mrmw.c @@ -159,7 +159,7 @@ struct ib_mr *ehca_get_dma_mr(struct ib_pd *pd, int mr_access_flags) get_dma_mr_exit0: if (IS_ERR(ib_mr)) - ehca_err(&shca->ib_device, "rc=%lx pd=%p mr_access_flags=%x ", + ehca_err(&shca->ib_device, "h_ret=%li pd=%p mr_access_flags=%x", PTR_ERR(ib_mr), pd, mr_access_flags); return ib_mr; } /* end ehca_get_dma_mr() */ @@ -271,7 +271,7 @@ reg_phys_mr_exit1: ehca_mr_delete(e_mr); reg_phys_mr_exit0: if (IS_ERR(ib_mr)) - ehca_err(pd->device, "rc=%lx pd=%p phys_buf_array=%p " + ehca_err(pd->device, "h_ret=%li pd=%p phys_buf_array=%p " "num_phys_buf=%x mr_access_flags=%x iova_start=%p", PTR_ERR(ib_mr), pd, phys_buf_array, num_phys_buf, mr_access_flags, iova_start); @@ -403,8 +403,7 @@ reg_user_mr_exit1: ehca_mr_delete(e_mr); reg_user_mr_exit0: if (IS_ERR(ib_mr)) - ehca_err(pd->device, "rc=%lx pd=%p mr_access_flags=%x" - " udata=%p", + ehca_err(pd->device, "rc=%li pd=%p mr_access_flags=%x udata=%p", PTR_ERR(ib_mr), pd, mr_access_flags, udata); return ib_mr; } /* end ehca_reg_user_mr() */ @@ -565,7 +564,7 @@ rereg_phys_mr_exit1: spin_unlock_irqrestore(&e_mr->mrlock, sl_flags); rereg_phys_mr_exit0: if (ret) - ehca_err(mr->device, "ret=%x mr=%p mr_rereg_mask=%x pd=%p " + ehca_err(mr->device, "ret=%i mr=%p mr_rereg_mask=%x pd=%p " "phys_buf_array=%p num_phys_buf=%x mr_access_flags=%x " "iova_start=%p", ret, mr, mr_rereg_mask, pd, phys_buf_array, @@ -607,7 +606,7 @@ int ehca_query_mr(struct ib_mr *mr, struct ib_mr_attr *mr_attr) h_ret = hipz_h_query_mr(shca->ipz_hca_handle, e_mr, &hipzout); if (h_ret != H_SUCCESS) { - ehca_err(mr->device, "hipz_mr_query failed, h_ret=%lx mr=%p " + ehca_err(mr->device, "hipz_mr_query failed, h_ret=%li mr=%p " "hca_hndl=%lx mr_hndl=%lx lkey=%x", h_ret, mr, shca->ipz_hca_handle.handle, e_mr->ipz_mr_handle.handle, mr->lkey); @@ -625,7 +624,7 @@ query_mr_exit1: spin_unlock_irqrestore(&e_mr->mrlock, sl_flags); query_mr_exit0: if (ret) - ehca_err(mr->device, "ret=%x mr=%p mr_attr=%p", + ehca_err(mr->device, "ret=%i mr=%p mr_attr=%p", ret, mr, mr_attr); return ret; } /* end ehca_query_mr() */ @@ -667,7 +666,7 @@ int ehca_dereg_mr(struct ib_mr *mr) /* TODO: BUSY: MR still has bound window(s) */ h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_mr); if (h_ret != H_SUCCESS) { - ehca_err(mr->device, "hipz_free_mr failed, h_ret=%lx shca=%p " + ehca_err(mr->device, "hipz_free_mr failed, h_ret=%li shca=%p " "e_mr=%p hca_hndl=%lx mr_hndl=%lx mr->lkey=%x", h_ret, shca, e_mr, shca->ipz_hca_handle.handle, e_mr->ipz_mr_handle.handle, mr->lkey); @@ -683,7 +682,7 @@ int ehca_dereg_mr(struct ib_mr *mr) dereg_mr_exit0: if (ret) - ehca_err(mr->device, "ret=%x mr=%p", ret, mr); + ehca_err(mr->device, "ret=%i mr=%p", ret, mr); return ret; } /* end ehca_dereg_mr() */ @@ -708,7 +707,7 @@ struct ib_mw *ehca_alloc_mw(struct ib_pd *pd) h_ret = hipz_h_alloc_resource_mw(shca->ipz_hca_handle, e_mw, e_pd->fw_pd, &hipzout); if (h_ret != H_SUCCESS) { - ehca_err(pd->device, "hipz_mw_allocate failed, h_ret=%lx " + ehca_err(pd->device, "hipz_mw_allocate failed, h_ret=%li " "shca=%p hca_hndl=%lx mw=%p", h_ret, shca, shca->ipz_hca_handle.handle, e_mw); ib_mw = ERR_PTR(ehca2ib_return_code(h_ret)); @@ -723,7 +722,7 @@ alloc_mw_exit1: ehca_mw_delete(e_mw); alloc_mw_exit0: if (IS_ERR(ib_mw)) - ehca_err(pd->device, "rc=%lx pd=%p", PTR_ERR(ib_mw), pd); + ehca_err(pd->device, "h_ret=%li pd=%p", PTR_ERR(ib_mw), pd); return ib_mw; } /* end ehca_alloc_mw() */ @@ -750,7 +749,7 @@ int ehca_dealloc_mw(struct ib_mw *mw) h_ret = hipz_h_free_resource_mw(shca->ipz_hca_handle, e_mw); if (h_ret != H_SUCCESS) { - ehca_err(mw->device, "hipz_free_mw failed, h_ret=%lx shca=%p " + ehca_err(mw->device, "hipz_free_mw failed, h_ret=%li shca=%p " "mw=%p rkey=%x hca_hndl=%lx mw_hndl=%lx", h_ret, shca, mw, mw->rkey, shca->ipz_hca_handle.handle, e_mw->ipz_mw_handle.handle); @@ -912,7 +911,7 @@ int ehca_map_phys_fmr(struct ib_fmr *fmr, map_phys_fmr_exit0: if (ret) - ehca_err(fmr->device, "ret=%x fmr=%p page_list=%p list_len=%x " + ehca_err(fmr->device, "ret=%i fmr=%p page_list=%p list_len=%x " "iova=%lx", ret, fmr, page_list, list_len, iova); return ret; } /* end ehca_map_phys_fmr() */ @@ -975,7 +974,7 @@ int ehca_unmap_fmr(struct list_head *fmr_list) unmap_fmr_exit0: if (ret) - ehca_gen_err("ret=%x fmr_list=%p num_fmr=%x unmap_fmr_cnt=%x", + ehca_gen_err("ret=%i fmr_list=%p num_fmr=%x unmap_fmr_cnt=%x", ret, fmr_list, num_fmr, unmap_fmr_cnt); return ret; } /* end ehca_unmap_fmr() */ @@ -999,7 +998,7 @@ int ehca_dealloc_fmr(struct ib_fmr *fmr) h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_fmr); if (h_ret != H_SUCCESS) { - ehca_err(fmr->device, "hipz_free_mr failed, h_ret=%lx e_fmr=%p " + ehca_err(fmr->device, "hipz_free_mr failed, h_ret=%li e_fmr=%p " "hca_hndl=%lx fmr_hndl=%lx fmr->lkey=%x", h_ret, e_fmr, shca->ipz_hca_handle.handle, e_fmr->ipz_mr_handle.handle, fmr->lkey); @@ -1012,7 +1011,7 @@ int ehca_dealloc_fmr(struct ib_fmr *fmr) free_fmr_exit0: if (ret) - ehca_err(&shca->ib_device, "ret=%x fmr=%p", ret, fmr); + ehca_err(&shca->ib_device, "ret=%i fmr=%p", ret, fmr); return ret; } /* end ehca_dealloc_fmr() */ @@ -1042,7 +1041,7 @@ int ehca_reg_mr(struct ehca_shca *shca, (u64)iova_start, size, hipz_acl, e_pd->fw_pd, &hipzout); if (h_ret != H_SUCCESS) { - ehca_err(&shca->ib_device, "hipz_alloc_mr failed, h_ret=%lx " + ehca_err(&shca->ib_device, "hipz_alloc_mr failed, h_ret=%li " "hca_hndl=%lx", h_ret, shca->ipz_hca_handle.handle); ret = ehca2ib_return_code(h_ret); goto ehca_reg_mr_exit0; @@ -1068,9 +1067,9 @@ int ehca_reg_mr(struct ehca_shca *shca, ehca_reg_mr_exit1: h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_mr); if (h_ret != H_SUCCESS) { - ehca_err(&shca->ib_device, "h_ret=%lx shca=%p e_mr=%p " + ehca_err(&shca->ib_device, "h_ret=%li shca=%p e_mr=%p " "iova_start=%p size=%lx acl=%x e_pd=%p lkey=%x " - "pginfo=%p num_kpages=%lx num_hwpages=%lx ret=%x", + "pginfo=%p num_kpages=%lx num_hwpages=%lx ret=%i", h_ret, shca, e_mr, iova_start, size, acl, e_pd, hipzout.lkey, pginfo, pginfo->num_kpages, pginfo->num_hwpages, ret); @@ -1079,7 +1078,7 @@ ehca_reg_mr_exit1: } ehca_reg_mr_exit0: if (ret) - ehca_err(&shca->ib_device, "ret=%x shca=%p e_mr=%p " + ehca_err(&shca->ib_device, "ret=%i shca=%p e_mr=%p " "iova_start=%p size=%lx acl=%x e_pd=%p pginfo=%p " "num_kpages=%lx num_hwpages=%lx", ret, shca, e_mr, iova_start, size, acl, e_pd, pginfo, @@ -1123,7 +1122,7 @@ int ehca_reg_mr_rpages(struct ehca_shca *shca, ret = ehca_set_pagebuf(pginfo, rnum, kpage); if (ret) { ehca_err(&shca->ib_device, "ehca_set_pagebuf " - "bad rc, ret=%x rnum=%x kpage=%p", + "bad rc, ret=%i rnum=%x kpage=%p", ret, rnum, kpage); goto ehca_reg_mr_rpages_exit1; } @@ -1151,7 +1150,7 @@ int ehca_reg_mr_rpages(struct ehca_shca *shca, */ if (h_ret != H_SUCCESS) { ehca_err(&shca->ib_device, "last " - "hipz_reg_rpage_mr failed, h_ret=%lx " + "hipz_reg_rpage_mr failed, h_ret=%li " "e_mr=%p i=%x hca_hndl=%lx mr_hndl=%lx" " lkey=%x", h_ret, e_mr, i, shca->ipz_hca_handle.handle, @@ -1163,7 +1162,7 @@ int ehca_reg_mr_rpages(struct ehca_shca *shca, ret = 0; } else if (h_ret != H_PAGE_REGISTERED) { ehca_err(&shca->ib_device, "hipz_reg_rpage_mr failed, " - "h_ret=%lx e_mr=%p i=%x lkey=%x hca_hndl=%lx " + "h_ret=%li e_mr=%p i=%x lkey=%x hca_hndl=%lx " "mr_hndl=%lx", h_ret, e_mr, i, e_mr->ib.ib_mr.lkey, shca->ipz_hca_handle.handle, @@ -1179,7 +1178,7 @@ ehca_reg_mr_rpages_exit1: ehca_free_fw_ctrlblock(kpage); ehca_reg_mr_rpages_exit0: if (ret) - ehca_err(&shca->ib_device, "ret=%x shca=%p e_mr=%p pginfo=%p " + ehca_err(&shca->ib_device, "ret=%i shca=%p e_mr=%p pginfo=%p " "num_kpages=%lx num_hwpages=%lx", ret, shca, e_mr, pginfo, pginfo->num_kpages, pginfo->num_hwpages); return ret; @@ -1240,7 +1239,7 @@ inline int ehca_rereg_mr_rereg1(struct ehca_shca *shca, * (MW bound or MR is shared) */ ehca_warn(&shca->ib_device, "hipz_h_reregister_pmr failed " - "(Rereg1), h_ret=%lx e_mr=%p", h_ret, e_mr); + "(Rereg1), h_ret=%li e_mr=%p", h_ret, e_mr); *pginfo = pginfo_save; ret = -EAGAIN; } else if ((u64 *)hipzout.vaddr != iova_start) { @@ -1269,7 +1268,7 @@ ehca_rereg_mr_rereg1_exit1: ehca_free_fw_ctrlblock(kpage); ehca_rereg_mr_rereg1_exit0: if ( ret && (ret != -EAGAIN) ) - ehca_err(&shca->ib_device, "ret=%x lkey=%x rkey=%x " + ehca_err(&shca->ib_device, "ret=%i lkey=%x rkey=%x " "pginfo=%p num_kpages=%lx num_hwpages=%lx", ret, *lkey, *rkey, pginfo, pginfo->num_kpages, pginfo->num_hwpages); @@ -1330,7 +1329,7 @@ int ehca_rereg_mr(struct ehca_shca *shca, h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_mr); if (h_ret != H_SUCCESS) { ehca_err(&shca->ib_device, "hipz_free_mr failed, " - "h_ret=%lx e_mr=%p hca_hndl=%lx mr_hndl=%lx " + "h_ret=%li e_mr=%p hca_hndl=%lx mr_hndl=%lx " "mr->lkey=%x", h_ret, e_mr, shca->ipz_hca_handle.handle, e_mr->ipz_mr_handle.handle, @@ -1362,7 +1361,7 @@ int ehca_rereg_mr(struct ehca_shca *shca, ehca_rereg_mr_exit0: if (ret) - ehca_err(&shca->ib_device, "ret=%x shca=%p e_mr=%p " + ehca_err(&shca->ib_device, "ret=%i shca=%p e_mr=%p " "iova_start=%p size=%lx acl=%x e_pd=%p pginfo=%p " "num_kpages=%lx lkey=%x rkey=%x rereg_1_hcall=%x " "rereg_3_hcall=%x", ret, shca, e_mr, iova_start, size, @@ -1406,7 +1405,7 @@ int ehca_unmap_one_fmr(struct ehca_shca *shca, * FMRs are not shared and no MW bound to FMRs */ ehca_err(&shca->ib_device, "hipz_reregister_pmr failed " - "(Rereg1), h_ret=%lx e_fmr=%p hca_hndl=%lx " + "(Rereg1), h_ret=%li e_fmr=%p hca_hndl=%lx " "mr_hndl=%lx lkey=%x lkey_out=%x", h_ret, e_fmr, shca->ipz_hca_handle.handle, e_fmr->ipz_mr_handle.handle, @@ -1418,7 +1417,7 @@ int ehca_unmap_one_fmr(struct ehca_shca *shca, h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_fmr); if (h_ret != H_SUCCESS) { ehca_err(&shca->ib_device, "hipz_free_mr failed, " - "h_ret=%lx e_fmr=%p hca_hndl=%lx mr_hndl=%lx " + "h_ret=%li e_fmr=%p hca_hndl=%lx mr_hndl=%lx " "lkey=%x", h_ret, e_fmr, shca->ipz_hca_handle.handle, e_fmr->ipz_mr_handle.handle, @@ -1453,7 +1452,7 @@ int ehca_unmap_one_fmr(struct ehca_shca *shca, ehca_unmap_one_fmr_exit0: if (ret) - ehca_err(&shca->ib_device, "ret=%x tmp_lkey=%x tmp_rkey=%x " + ehca_err(&shca->ib_device, "ret=%i tmp_lkey=%x tmp_rkey=%x " "fmr_max_pages=%x", ret, tmp_lkey, tmp_rkey, e_fmr->fmr_max_pages); return ret; @@ -1482,7 +1481,7 @@ int ehca_reg_smr(struct ehca_shca *shca, (u64)iova_start, hipz_acl, e_pd->fw_pd, &hipzout); if (h_ret != H_SUCCESS) { - ehca_err(&shca->ib_device, "hipz_reg_smr failed, h_ret=%lx " + ehca_err(&shca->ib_device, "hipz_reg_smr failed, h_ret=%li " "shca=%p e_origmr=%p e_newmr=%p iova_start=%p acl=%x " "e_pd=%p hca_hndl=%lx mr_hndl=%lx lkey=%x", h_ret, shca, e_origmr, e_newmr, iova_start, acl, e_pd, @@ -1506,7 +1505,7 @@ int ehca_reg_smr(struct ehca_shca *shca, ehca_reg_smr_exit0: if (ret) - ehca_err(&shca->ib_device, "ret=%x shca=%p e_origmr=%p " + ehca_err(&shca->ib_device, "ret=%i shca=%p e_origmr=%p " "e_newmr=%p iova_start=%p acl=%x e_pd=%p", ret, shca, e_origmr, e_newmr, iova_start, acl, e_pd); return ret; @@ -1581,7 +1580,7 @@ ehca_reg_internal_maxmr_exit1: ehca_mr_delete(e_mr); ehca_reg_internal_maxmr_exit0: if (ret) - ehca_err(&shca->ib_device, "ret=%x shca=%p e_pd=%p e_maxmr=%p", + ehca_err(&shca->ib_device, "ret=%i shca=%p e_pd=%p e_maxmr=%p", ret, shca, e_pd, e_maxmr); return ret; } /* end ehca_reg_internal_maxmr() */ @@ -1608,7 +1607,7 @@ int ehca_reg_maxmr(struct ehca_shca *shca, (u64)iova_start, hipz_acl, e_pd->fw_pd, &hipzout); if (h_ret != H_SUCCESS) { - ehca_err(&shca->ib_device, "hipz_reg_smr failed, h_ret=%lx " + ehca_err(&shca->ib_device, "hipz_reg_smr failed, h_ret=%li " "e_origmr=%p hca_hndl=%lx mr_hndl=%lx lkey=%x", h_ret, e_origmr, shca->ipz_hca_handle.handle, e_origmr->ipz_mr_handle.handle, @@ -1649,7 +1648,7 @@ int ehca_dereg_internal_maxmr(struct ehca_shca *shca) ret = ehca_dereg_mr(&e_maxmr->ib.ib_mr); if (ret) { ehca_err(&shca->ib_device, "dereg internal max-MR failed, " - "ret=%x e_maxmr=%p shca=%p lkey=%x", + "ret=%i e_maxmr=%p shca=%p lkey=%x", ret, e_maxmr, shca, e_maxmr->ib.ib_mr.lkey); shca->maxmr = e_maxmr; goto ehca_dereg_internal_maxmr_exit0; @@ -1659,7 +1658,7 @@ int ehca_dereg_internal_maxmr(struct ehca_shca *shca) ehca_dereg_internal_maxmr_exit0: if (ret) - ehca_err(&shca->ib_device, "ret=%x shca=%p shca->maxmr=%p", + ehca_err(&shca->ib_device, "ret=%i shca=%p shca->maxmr=%p", ret, shca, shca->maxmr); return ret; } /* end ehca_dereg_internal_maxmr() */ diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c index e89fdca7fa1..88d7dd94603 100644 --- a/drivers/infiniband/hw/ehca/ehca_qp.c +++ b/drivers/infiniband/hw/ehca/ehca_qp.c @@ -310,7 +310,7 @@ static inline int init_qp_queue(struct ehca_shca *shca, } if (!ipz_rc) { - ehca_err(ib_dev, "Cannot allocate page for queue. ipz_rc=%x", + ehca_err(ib_dev, "Cannot allocate page for queue. ipz_rc=%i", ipz_rc); return -EBUSY; } @@ -334,7 +334,7 @@ static inline int init_qp_queue(struct ehca_shca *shca, if (cnt == (nr_q_pages - 1)) { /* last page! */ if (h_ret != expected_hret) { ehca_err(ib_dev, "hipz_qp_register_rpage() " - "h_ret= %lx ", h_ret); + "h_ret=%li", h_ret); ret = ehca2ib_return_code(h_ret); goto init_qp_queue1; } @@ -348,7 +348,7 @@ static inline int init_qp_queue(struct ehca_shca *shca, } else { if (h_ret != H_PAGE_REGISTERED) { ehca_err(ib_dev, "hipz_qp_register_rpage() " - "h_ret= %lx ", h_ret); + "h_ret=%li", h_ret); ret = ehca2ib_return_code(h_ret); goto init_qp_queue1; } @@ -617,7 +617,7 @@ static struct ehca_qp *internal_create_qp( h_ret = hipz_h_alloc_resource_qp(shca->ipz_hca_handle, &parms); if (h_ret != H_SUCCESS) { - ehca_err(pd->device, "h_alloc_resource_qp() failed h_ret=%lx", + ehca_err(pd->device, "h_alloc_resource_qp() failed h_ret=%li", h_ret); ret = ehca2ib_return_code(h_ret); goto create_qp_exit1; @@ -671,7 +671,7 @@ static struct ehca_qp *internal_create_qp( &parms.squeue, swqe_size); if (ret) { ehca_err(pd->device, "Couldn't initialize squeue " - "and pages ret=%x", ret); + "and pages ret=%i", ret); goto create_qp_exit2; } } @@ -682,7 +682,7 @@ static struct ehca_qp *internal_create_qp( H_SUCCESS, &parms.rqueue, rwqe_size); if (ret) { ehca_err(pd->device, "Couldn't initialize rqueue " - "and pages ret=%x", ret); + "and pages ret=%i", ret); goto create_qp_exit3; } } @@ -728,7 +728,7 @@ static struct ehca_qp *internal_create_qp( ret = ehca_cq_assign_qp(my_qp->send_cq, my_qp); if (ret) { ehca_err(pd->device, - "Couldn't assign qp to send_cq ret=%x", ret); + "Couldn't assign qp to send_cq ret=%i", ret); goto create_qp_exit4; } } @@ -845,7 +845,7 @@ struct ib_srq *ehca_create_srq(struct ib_pd *pd, mqpcb, my_qp->galpas.kernel); if (hret != H_SUCCESS) { ehca_err(pd->device, "Could not modify SRQ to INIT" - "ehca_qp=%p qp_num=%x hret=%lx", + "ehca_qp=%p qp_num=%x h_ret=%li", my_qp, my_qp->real_qp_num, hret); goto create_srq2; } @@ -859,7 +859,7 @@ struct ib_srq *ehca_create_srq(struct ib_pd *pd, mqpcb, my_qp->galpas.kernel); if (hret != H_SUCCESS) { ehca_err(pd->device, "Could not enable SRQ" - "ehca_qp=%p qp_num=%x hret=%lx", + "ehca_qp=%p qp_num=%x h_ret=%li", my_qp, my_qp->real_qp_num, hret); goto create_srq2; } @@ -873,7 +873,7 @@ struct ib_srq *ehca_create_srq(struct ib_pd *pd, mqpcb, my_qp->galpas.kernel); if (hret != H_SUCCESS) { ehca_err(pd->device, "Could not modify SRQ to RTR" - "ehca_qp=%p qp_num=%x hret=%lx", + "ehca_qp=%p qp_num=%x h_ret=%li", my_qp, my_qp->real_qp_num, hret); goto create_srq2; } @@ -911,7 +911,7 @@ static int prepare_sqe_rts(struct ehca_qp *my_qp, struct ehca_shca *shca, &bad_send_wqe_p, NULL, 2); if (h_ret != H_SUCCESS) { ehca_err(&shca->ib_device, "hipz_h_disable_and_get_wqe() failed" - " ehca_qp=%p qp_num=%x h_ret=%lx", + " ehca_qp=%p qp_num=%x h_ret=%li", my_qp, qp_num, h_ret); return ehca2ib_return_code(h_ret); } @@ -989,7 +989,7 @@ static int internal_modify_qp(struct ib_qp *ibqp, mqpcb, my_qp->galpas.kernel); if (h_ret != H_SUCCESS) { ehca_err(ibqp->device, "hipz_h_query_qp() failed " - "ehca_qp=%p qp_num=%x h_ret=%lx", + "ehca_qp=%p qp_num=%x h_ret=%li", my_qp, ibqp->qp_num, h_ret); ret = ehca2ib_return_code(h_ret); goto modify_qp_exit1; @@ -1025,7 +1025,7 @@ static int internal_modify_qp(struct ib_qp *ibqp, ibqp, &smiqp_attr, smiqp_attr_mask, 1); if (smirc) { ehca_err(ibqp->device, "SMI RESET -> INIT failed. " - "ehca_modify_qp() rc=%x", smirc); + "ehca_modify_qp() rc=%i", smirc); ret = H_PARAMETER; goto modify_qp_exit1; } @@ -1127,7 +1127,7 @@ static int internal_modify_qp(struct ib_qp *ibqp, ret = prepare_sqe_rts(my_qp, shca, &bad_wqe_cnt); if (ret) { ehca_err(ibqp->device, "prepare_sqe_rts() failed " - "ehca_qp=%p qp_num=%x ret=%x", + "ehca_qp=%p qp_num=%x ret=%i", my_qp, ibqp->qp_num, ret); goto modify_qp_exit2; } @@ -1352,7 +1352,7 @@ static int internal_modify_qp(struct ib_qp *ibqp, if (h_ret != H_SUCCESS) { ret = ehca2ib_return_code(h_ret); - ehca_err(ibqp->device, "hipz_h_modify_qp() failed rc=%lx " + ehca_err(ibqp->device, "hipz_h_modify_qp() failed h_ret=%li " "ehca_qp=%p qp_num=%x", h_ret, my_qp, ibqp->qp_num); goto modify_qp_exit2; } @@ -1385,7 +1385,7 @@ static int internal_modify_qp(struct ib_qp *ibqp, ret = ehca2ib_return_code(h_ret); ehca_err(ibqp->device, "ENABLE in context of " "RESET_2_INIT failed! Maybe you didn't get " - "a LID h_ret=%lx ehca_qp=%p qp_num=%x", + "a LID h_ret=%li ehca_qp=%p qp_num=%x", h_ret, my_qp, ibqp->qp_num); goto modify_qp_exit2; } @@ -1473,7 +1473,7 @@ int ehca_query_qp(struct ib_qp *qp, if (h_ret != H_SUCCESS) { ret = ehca2ib_return_code(h_ret); ehca_err(qp->device, "hipz_h_query_qp() failed " - "ehca_qp=%p qp_num=%x h_ret=%lx", + "ehca_qp=%p qp_num=%x h_ret=%li", my_qp, qp->qp_num, h_ret); goto query_qp_exit1; } @@ -1648,7 +1648,7 @@ int ehca_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr, if (h_ret != H_SUCCESS) { ret = ehca2ib_return_code(h_ret); - ehca_err(ibsrq->device, "hipz_h_modify_qp() failed rc=%lx " + ehca_err(ibsrq->device, "hipz_h_modify_qp() failed h_ret=%li " "ehca_qp=%p qp_num=%x", h_ret, my_qp, my_qp->real_qp_num); } @@ -1691,7 +1691,7 @@ int ehca_query_srq(struct ib_srq *srq, struct ib_srq_attr *srq_attr) if (h_ret != H_SUCCESS) { ret = ehca2ib_return_code(h_ret); ehca_err(srq->device, "hipz_h_query_qp() failed " - "ehca_qp=%p qp_num=%x h_ret=%lx", + "ehca_qp=%p qp_num=%x h_ret=%li", my_qp, my_qp->real_qp_num, h_ret); goto query_srq_exit1; } @@ -1741,7 +1741,7 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp, ret = ehca_cq_unassign_qp(my_qp->send_cq, qp_num); if (ret) { ehca_err(dev, "Couldn't unassign qp from " - "send_cq ret=%x qp_num=%x cq_num=%x", ret, + "send_cq ret=%i qp_num=%x cq_num=%x", ret, qp_num, my_qp->send_cq->cq_number); return ret; } @@ -1753,7 +1753,7 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp, h_ret = hipz_h_destroy_qp(shca->ipz_hca_handle, my_qp); if (h_ret != H_SUCCESS) { - ehca_err(dev, "hipz_h_destroy_qp() failed rc=%lx " + ehca_err(dev, "hipz_h_destroy_qp() failed h_ret=%li " "ehca_qp=%p qp_num=%x", h_ret, my_qp, qp_num); return ehca2ib_return_code(h_ret); } diff --git a/drivers/infiniband/hw/ehca/ehca_reqs.c b/drivers/infiniband/hw/ehca/ehca_reqs.c index 94eed70fedf..ea91360835d 100644 --- a/drivers/infiniband/hw/ehca/ehca_reqs.c +++ b/drivers/infiniband/hw/ehca/ehca_reqs.c @@ -526,7 +526,7 @@ poll_cq_one_read_cqe: if (!cqe) { ret = -EAGAIN; ehca_dbg(cq->device, "Completion queue is empty ehca_cq=%p " - "cq_num=%x ret=%x", my_cq, my_cq->cq_number, ret); + "cq_num=%x ret=%i", my_cq, my_cq->cq_number, ret); goto poll_cq_one_exit0; } diff --git a/drivers/infiniband/hw/ehca/ehca_sqp.c b/drivers/infiniband/hw/ehca/ehca_sqp.c index 9f16e9c7939..f0792e5fbd0 100644 --- a/drivers/infiniband/hw/ehca/ehca_sqp.c +++ b/drivers/infiniband/hw/ehca/ehca_sqp.c @@ -82,7 +82,7 @@ u64 ehca_define_sqp(struct ehca_shca *shca, if (ret != H_SUCCESS) { ehca_err(&shca->ib_device, - "Can't define AQP1 for port %x. rc=%lx", + "Can't define AQP1 for port %x. h_ret=%li", port, ret); return ret; } diff --git a/drivers/infiniband/hw/ehca/ehca_uverbs.c b/drivers/infiniband/hw/ehca/ehca_uverbs.c index 84a16bcfd53..5234d6c15c4 100644 --- a/drivers/infiniband/hw/ehca/ehca_uverbs.c +++ b/drivers/infiniband/hw/ehca/ehca_uverbs.c @@ -121,7 +121,7 @@ static int ehca_mmap_fw(struct vm_area_struct *vma, struct h_galpas *galpas, ret = remap_4k_pfn(vma, vma->vm_start, physical >> EHCA_PAGESHIFT, vma->vm_page_prot); if (unlikely(ret)) { - ehca_gen_err("remap_pfn_range() failed ret=%x", ret); + ehca_gen_err("remap_pfn_range() failed ret=%i", ret); return -ENOMEM; } @@ -146,7 +146,7 @@ static int ehca_mmap_queue(struct vm_area_struct *vma, struct ipz_queue *queue, page = virt_to_page(virt_addr); ret = vm_insert_page(vma, start, page); if (unlikely(ret)) { - ehca_gen_err("vm_insert_page() failed rc=%x", ret); + ehca_gen_err("vm_insert_page() failed rc=%i", ret); return ret; } start += PAGE_SIZE; @@ -169,7 +169,7 @@ static int ehca_mmap_cq(struct vm_area_struct *vma, struct ehca_cq *cq, ret = ehca_mmap_fw(vma, &cq->galpas, &cq->mm_count_galpa); if (unlikely(ret)) { ehca_err(cq->ib_cq.device, - "ehca_mmap_fw() failed rc=%x cq_num=%x", + "ehca_mmap_fw() failed rc=%i cq_num=%x", ret, cq->cq_number); return ret; } @@ -180,7 +180,7 @@ static int ehca_mmap_cq(struct vm_area_struct *vma, struct ehca_cq *cq, ret = ehca_mmap_queue(vma, &cq->ipz_queue, &cq->mm_count_queue); if (unlikely(ret)) { ehca_err(cq->ib_cq.device, - "ehca_mmap_queue() failed rc=%x cq_num=%x", + "ehca_mmap_queue() failed rc=%i cq_num=%x", ret, cq->cq_number); return ret; } @@ -206,7 +206,7 @@ static int ehca_mmap_qp(struct vm_area_struct *vma, struct ehca_qp *qp, ret = ehca_mmap_fw(vma, &qp->galpas, &qp->mm_count_galpa); if (unlikely(ret)) { ehca_err(qp->ib_qp.device, - "remap_pfn_range() failed ret=%x qp_num=%x", + "remap_pfn_range() failed ret=%i qp_num=%x", ret, qp->ib_qp.qp_num); return -ENOMEM; } @@ -219,7 +219,7 @@ static int ehca_mmap_qp(struct vm_area_struct *vma, struct ehca_qp *qp, &qp->mm_count_rqueue); if (unlikely(ret)) { ehca_err(qp->ib_qp.device, - "ehca_mmap_queue(rq) failed rc=%x qp_num=%x", + "ehca_mmap_queue(rq) failed rc=%i qp_num=%x", ret, qp->ib_qp.qp_num); return ret; } @@ -232,7 +232,7 @@ static int ehca_mmap_qp(struct vm_area_struct *vma, struct ehca_qp *qp, &qp->mm_count_squeue); if (unlikely(ret)) { ehca_err(qp->ib_qp.device, - "ehca_mmap_queue(sq) failed rc=%x qp_num=%x", + "ehca_mmap_queue(sq) failed rc=%i qp_num=%x", ret, qp->ib_qp.qp_num); return ret; } @@ -283,7 +283,7 @@ int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) ret = ehca_mmap_cq(vma, cq, rsrc_type); if (unlikely(ret)) { ehca_err(cq->ib_cq.device, - "ehca_mmap_cq() failed rc=%x cq_num=%x", + "ehca_mmap_cq() failed rc=%i cq_num=%x", ret, cq->cq_number); return ret; } @@ -313,7 +313,7 @@ int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) ret = ehca_mmap_qp(vma, qp, rsrc_type); if (unlikely(ret)) { ehca_err(qp->ib_qp.device, - "ehca_mmap_qp() failed rc=%x qp_num=%x", + "ehca_mmap_qp() failed rc=%i qp_num=%x", ret, qp->ib_qp.qp_num); return ret; } diff --git a/drivers/infiniband/hw/ehca/hcp_if.c b/drivers/infiniband/hw/ehca/hcp_if.c index a762cc7e016..3d68f6536f9 100644 --- a/drivers/infiniband/hw/ehca/hcp_if.c +++ b/drivers/infiniband/hw/ehca/hcp_if.c @@ -238,7 +238,7 @@ u64 hipz_h_alloc_resource_eq(const struct ipz_adapter_handle adapter_handle, *eq_ist = (u32)outs[5]; if (ret == H_NOT_ENOUGH_RESOURCES) - ehca_gen_err("Not enough resource - ret=%lx ", ret); + ehca_gen_err("Not enough resource - ret=%li ", ret); return ret; } @@ -276,7 +276,7 @@ u64 hipz_h_alloc_resource_cq(const struct ipz_adapter_handle adapter_handle, hcp_galpas_ctor(&cq->galpas, outs[5], outs[6]); if (ret == H_NOT_ENOUGH_RESOURCES) - ehca_gen_err("Not enough resources. ret=%lx", ret); + ehca_gen_err("Not enough resources. ret=%li", ret); return ret; } @@ -351,7 +351,7 @@ u64 hipz_h_alloc_resource_qp(const struct ipz_adapter_handle adapter_handle, hcp_galpas_ctor(&parms->galpas, outs[6], outs[6]); if (ret == H_NOT_ENOUGH_RESOURCES) - ehca_gen_err("Not enough resources. ret=%lx", ret); + ehca_gen_err("Not enough resources. ret=%li", ret); return ret; } @@ -546,7 +546,7 @@ u64 hipz_h_modify_qp(const struct ipz_adapter_handle adapter_handle, 0, 0, 0, 0, 0); if (ret == H_NOT_ENOUGH_RESOURCES) - ehca_gen_err("Insufficient resources ret=%lx", ret); + ehca_gen_err("Insufficient resources ret=%li", ret); return ret; } @@ -582,7 +582,7 @@ u64 hipz_h_destroy_qp(const struct ipz_adapter_handle adapter_handle, qp->ipz_qp_handle.handle, /* r6 */ 0, 0, 0, 0, 0, 0); if (ret == H_HARDWARE) - ehca_gen_err("HCA not operational. ret=%lx", ret); + ehca_gen_err("HCA not operational. ret=%li", ret); ret = ehca_plpar_hcall_norets(H_FREE_RESOURCE, adapter_handle.handle, /* r4 */ @@ -590,7 +590,7 @@ u64 hipz_h_destroy_qp(const struct ipz_adapter_handle adapter_handle, 0, 0, 0, 0, 0); if (ret == H_RESOURCE) - ehca_gen_err("Resource still in use. ret=%lx", ret); + ehca_gen_err("Resource still in use. ret=%li", ret); return ret; } @@ -625,7 +625,7 @@ u64 hipz_h_define_aqp1(const struct ipz_adapter_handle adapter_handle, *bma_qp_nr = (u32)outs[1]; if (ret == H_ALIAS_EXIST) - ehca_gen_err("AQP1 already exists. ret=%lx", ret); + ehca_gen_err("AQP1 already exists. ret=%li", ret); return ret; } @@ -647,7 +647,7 @@ u64 hipz_h_attach_mcqp(const struct ipz_adapter_handle adapter_handle, 0, 0); if (ret == H_NOT_ENOUGH_RESOURCES) - ehca_gen_err("Not enough resources. ret=%lx", ret); + ehca_gen_err("Not enough resources. ret=%li", ret); return ret; } @@ -686,7 +686,7 @@ u64 hipz_h_destroy_cq(const struct ipz_adapter_handle adapter_handle, 0, 0, 0, 0); if (ret == H_RESOURCE) - ehca_gen_err("H_FREE_RESOURCE failed ret=%lx ", ret); + ehca_gen_err("H_FREE_RESOURCE failed ret=%li ", ret); return ret; } @@ -708,7 +708,7 @@ u64 hipz_h_destroy_eq(const struct ipz_adapter_handle adapter_handle, 0, 0, 0, 0, 0); if (ret == H_RESOURCE) - ehca_gen_err("Resource in use. ret=%lx ", ret); + ehca_gen_err("Resource in use. ret=%li ", ret); return ret; } -- cgit v1.2.3-70-g09d2 From 86dce445e01a50339f8f86c466c64a863e5fd18a Mon Sep 17 00:00:00 2001 From: Joachim Fenkes Date: Tue, 11 Sep 2007 15:32:50 +0200 Subject: IB/ehca: ehca_gen_warn() should always print Signed-off-by: Joachim Fenkes Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/ehca_tools.h | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ehca/ehca_tools.h b/drivers/infiniband/hw/ehca/ehca_tools.h index 57c77a715f4..f9b264b4697 100644 --- a/drivers/infiniband/hw/ehca/ehca_tools.h +++ b/drivers/infiniband/hw/ehca/ehca_tools.h @@ -98,15 +98,12 @@ extern int ehca_debug_level; } while (0) #define ehca_gen_warn(format, arg...) \ - do { \ - if (unlikely(ehca_debug_level)) \ - printk(KERN_INFO "PU%04x EHCA_WARN:%s " format "\n", \ - get_paca()->paca_index, __FUNCTION__, ## arg); \ - } while (0) + printk(KERN_INFO "PU%04x EHCA_WARN:%s " format "\n", \ + get_paca()->paca_index, __FUNCTION__, ## arg) #define ehca_gen_err(format, arg...) \ printk(KERN_ERR "PU%04x EHCA_ERR:%s " format "\n", \ - get_paca()->paca_index, __FUNCTION__, ## arg) + get_paca()->paca_index, __FUNCTION__, ## arg) /** * ehca_dmp - printk a memory block, whose length is n*8 bytes. -- cgit v1.2.3-70-g09d2 From b708fba3c2942a175c3cb04a7bb4c89f907b497b Mon Sep 17 00:00:00 2001 From: Joachim Fenkes Date: Tue, 11 Sep 2007 15:33:40 +0200 Subject: IB/ehca: Add check for max #SGE to create_qp() Signed-off-by: Joachim Fenkes Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/ehca_qp.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c index 88d7dd94603..f95403cb523 100644 --- a/drivers/infiniband/hw/ehca/ehca_qp.c +++ b/drivers/infiniband/hw/ehca/ehca_qp.c @@ -513,7 +513,7 @@ static struct ehca_qp *internal_create_qp( } else if (init_attr->cap.max_send_wr > 255) { ehca_err(pd->device, "Invalid Number of " - "ax_send_wr=%x for UD QP_TYPE=%x", + "max_send_wr=%x for UD QP_TYPE=%x", init_attr->cap.max_send_wr, qp_type); return ERR_PTR(-EINVAL); } @@ -524,6 +524,18 @@ static struct ehca_qp *internal_create_qp( return ERR_PTR(-EINVAL); break; } + } else { + int max_sge = (qp_type == IB_QPT_UD || qp_type == IB_QPT_SMI + || qp_type == IB_QPT_GSI) ? 250 : 252; + + if (init_attr->cap.max_send_sge > max_sge + || init_attr->cap.max_recv_sge > max_sge) { + ehca_err(pd->device, "Invalid number of SGEs requested " + "send_sge=%x recv_sge=%x max_sge=%x", + init_attr->cap.max_send_sge, + init_attr->cap.max_recv_sge, max_sge); + return ERR_PTR(-EINVAL); + } } if (pd->uobject && udata) -- cgit v1.2.3-70-g09d2 From e90d0b3daede2bae2e78f8bf88c19182961cd19d Mon Sep 17 00:00:00 2001 From: Joachim Fenkes Date: Tue, 11 Sep 2007 15:34:04 +0200 Subject: IB/ehca: Path migration support Fix some modify_qp() issues related to path migration. Signed-off-by: Joachim Fenkes Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/ehca_irq.c | 4 +- drivers/infiniband/hw/ehca/ehca_qp.c | 90 +++++++++++++++++++++++++---------- 2 files changed, 68 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ehca/ehca_irq.c b/drivers/infiniband/hw/ehca/ehca_irq.c index a925ea52443..70939864fef 100644 --- a/drivers/infiniband/hw/ehca/ehca_irq.c +++ b/drivers/infiniband/hw/ehca/ehca_irq.c @@ -294,8 +294,8 @@ static void parse_identifier(struct ehca_shca *shca, u64 eqe) case 0x11: /* unaffiliated access error */ ehca_err(&shca->ib_device, "Unaffiliated access error."); break; - case 0x12: /* path migrating error */ - ehca_err(&shca->ib_device, "Path migration error."); + case 0x12: /* path migrating */ + ehca_err(&shca->ib_device, "Path migrating."); break; case 0x13: /* interface trace stopped */ ehca_err(&shca->ib_device, "Interface trace stopped."); diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c index f95403cb523..b10c7df669b 100644 --- a/drivers/infiniband/hw/ehca/ehca_qp.c +++ b/drivers/infiniband/hw/ehca/ehca_qp.c @@ -1165,6 +1165,13 @@ static int internal_modify_qp(struct ib_qp *ibqp, } if (attr_mask & IB_QP_PKEY_INDEX) { + if (attr->pkey_index >= 16) { + ret = -EINVAL; + ehca_err(ibqp->device, "Invalid pkey_index=%x. " + "ehca_qp=%p qp_num=%x max_pkey_index=f", + attr->pkey_index, my_qp, ibqp->qp_num); + goto modify_qp_exit2; + } mqpcb->prim_p_key_idx = attr->pkey_index; update_mask |= EHCA_BMASK_SET(MQPCB_MASK_PRIM_P_KEY_IDX, 1); } @@ -1273,50 +1280,78 @@ static int internal_modify_qp(struct ib_qp *ibqp, int ehca_mult = ib_rate_to_mult( shca->sport[my_qp->init_attr.port_num].rate); + if (attr->alt_port_num < 1 + || attr->alt_port_num > shca->num_ports) { + ret = -EINVAL; + ehca_err(ibqp->device, "Invalid alt_port=%x. " + "ehca_qp=%p qp_num=%x num_ports=%x", + attr->alt_port_num, my_qp, ibqp->qp_num, + shca->num_ports); + goto modify_qp_exit2; + } + mqpcb->alt_phys_port = attr->alt_port_num; + + if (attr->alt_pkey_index >= 16) { + ret = -EINVAL; + ehca_err(ibqp->device, "Invalid alt_pkey_index=%x. " + "ehca_qp=%p qp_num=%x max_pkey_index=f", + attr->pkey_index, my_qp, ibqp->qp_num); + goto modify_qp_exit2; + } + mqpcb->alt_p_key_idx = attr->alt_pkey_index; + + mqpcb->timeout_al = attr->alt_timeout; mqpcb->dlid_al = attr->alt_ah_attr.dlid; - update_mask |= EHCA_BMASK_SET(MQPCB_MASK_DLID_AL, 1); mqpcb->source_path_bits_al = attr->alt_ah_attr.src_path_bits; - update_mask |= - EHCA_BMASK_SET(MQPCB_MASK_SOURCE_PATH_BITS_AL, 1); mqpcb->service_level_al = attr->alt_ah_attr.sl; - update_mask |= EHCA_BMASK_SET(MQPCB_MASK_SERVICE_LEVEL_AL, 1); - if (ah_mult < ehca_mult) - mqpcb->max_static_rate = (ah_mult > 0) ? - ((ehca_mult - 1) / ah_mult) : 0; + if (ah_mult > 0 && ah_mult < ehca_mult) + mqpcb->max_static_rate_al = (ehca_mult - 1) / ah_mult; else mqpcb->max_static_rate_al = 0; - update_mask |= EHCA_BMASK_SET(MQPCB_MASK_MAX_STATIC_RATE_AL, 1); + /* OpenIB doesn't support alternate retry counts - copy them */ + mqpcb->retry_count_al = mqpcb->retry_count; + mqpcb->rnr_retry_count_al = mqpcb->rnr_retry_count; + + update_mask |= EHCA_BMASK_SET(MQPCB_MASK_ALT_PHYS_PORT, 1) + | EHCA_BMASK_SET(MQPCB_MASK_ALT_P_KEY_IDX, 1) + | EHCA_BMASK_SET(MQPCB_MASK_TIMEOUT_AL, 1) + | EHCA_BMASK_SET(MQPCB_MASK_DLID_AL, 1) + | EHCA_BMASK_SET(MQPCB_MASK_SOURCE_PATH_BITS_AL, 1) + | EHCA_BMASK_SET(MQPCB_MASK_SERVICE_LEVEL_AL, 1) + | EHCA_BMASK_SET(MQPCB_MASK_MAX_STATIC_RATE_AL, 1) + | EHCA_BMASK_SET(MQPCB_MASK_RETRY_COUNT_AL, 1) + | EHCA_BMASK_SET(MQPCB_MASK_RNR_RETRY_COUNT_AL, 1); + + /* + * Always supply the GRH flag, even if it's zero, to give the + * hypervisor a clear "yes" or "no" instead of a "perhaps" + */ + update_mask |= EHCA_BMASK_SET(MQPCB_MASK_SEND_GRH_FLAG_AL, 1); /* * only if GRH is TRUE we might consider SOURCE_GID_IDX * and DEST_GID otherwise phype will return H_ATTR_PARM!!! */ if (attr->alt_ah_attr.ah_flags == IB_AH_GRH) { - mqpcb->send_grh_flag_al = 1 << 31; - update_mask |= - EHCA_BMASK_SET(MQPCB_MASK_SEND_GRH_FLAG_AL, 1); - mqpcb->source_gid_idx_al = - attr->alt_ah_attr.grh.sgid_index; - update_mask |= - EHCA_BMASK_SET(MQPCB_MASK_SOURCE_GID_IDX_AL, 1); + mqpcb->send_grh_flag_al = 1; for (cnt = 0; cnt < 16; cnt++) mqpcb->dest_gid_al.byte[cnt] = attr->alt_ah_attr.grh.dgid.raw[cnt]; - - update_mask |= - EHCA_BMASK_SET(MQPCB_MASK_DEST_GID_AL, 1); + mqpcb->source_gid_idx_al = + attr->alt_ah_attr.grh.sgid_index; mqpcb->flow_label_al = attr->alt_ah_attr.grh.flow_label; - update_mask |= - EHCA_BMASK_SET(MQPCB_MASK_FLOW_LABEL_AL, 1); mqpcb->hop_limit_al = attr->alt_ah_attr.grh.hop_limit; - update_mask |= - EHCA_BMASK_SET(MQPCB_MASK_HOP_LIMIT_AL, 1); mqpcb->traffic_class_al = attr->alt_ah_attr.grh.traffic_class; + update_mask |= + EHCA_BMASK_SET(MQPCB_MASK_SOURCE_GID_IDX_AL, 1) + | EHCA_BMASK_SET(MQPCB_MASK_DEST_GID_AL, 1) + | EHCA_BMASK_SET(MQPCB_MASK_FLOW_LABEL_AL, 1) + | EHCA_BMASK_SET(MQPCB_MASK_HOP_LIMIT_AL, 1) | EHCA_BMASK_SET(MQPCB_MASK_TRAFFIC_CLASS_AL, 1); } } @@ -1338,7 +1373,14 @@ static int internal_modify_qp(struct ib_qp *ibqp, } if (attr_mask & IB_QP_PATH_MIG_STATE) { - mqpcb->path_migration_state = attr->path_mig_state; + if (attr->path_mig_state != IB_MIG_REARM + && attr->path_mig_state != IB_MIG_MIGRATED) { + ret = -EINVAL; + ehca_err(ibqp->device, "Invalid mig_state=%x", + attr->path_mig_state); + goto modify_qp_exit2; + } + mqpcb->path_migration_state = attr->path_mig_state + 1; update_mask |= EHCA_BMASK_SET(MQPCB_MASK_PATH_MIGRATION_STATE, 1); } @@ -1506,7 +1548,7 @@ int ehca_query_qp(struct ib_qp *qp, qp_attr->qkey = qpcb->qkey; qp_attr->path_mtu = qpcb->path_mtu; - qp_attr->path_mig_state = qpcb->path_migration_state; + qp_attr->path_mig_state = qpcb->path_migration_state - 1; qp_attr->rq_psn = qpcb->receive_psn; qp_attr->sq_psn = qpcb->send_psn; qp_attr->min_rnr_timer = qpcb->min_rnr_nak_timer_field; -- cgit v1.2.3-70-g09d2 From 0b5de96858e516311f2d3ca45073c2afd2eb5d94 Mon Sep 17 00:00:00 2001 From: Joachim Fenkes Date: Tue, 11 Sep 2007 15:34:35 +0200 Subject: IB/ehca: Serialize MR alloc and MR free hvCalls Some firmware levels exhibit a race condition between H_ALLOC_RESOURCE(MR) and H_FREE_RESOURCE(MR). Work around this problem by locking these hvCalls against each other. Signed-off-by: Joachim Fenkes Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/hcp_if.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ehca/hcp_if.c b/drivers/infiniband/hw/ehca/hcp_if.c index 3d68f6536f9..c16a21374bb 100644 --- a/drivers/infiniband/hw/ehca/hcp_if.c +++ b/drivers/infiniband/hw/ehca/hcp_if.c @@ -120,15 +120,28 @@ static long ehca_plpar_hcall_norets(unsigned long opcode, unsigned long arg7) { long ret; - int i, sleep_msecs; + int i, sleep_msecs, do_lock; + unsigned long flags; ehca_gen_dbg("opcode=%lx " HCALL7_REGS_FORMAT, opcode, arg1, arg2, arg3, arg4, arg5, arg6, arg7); + /* lock H_FREE_RESOURCE(MR) against itself and H_ALLOC_RESOURCE(MR) */ + if ((opcode == H_FREE_RESOURCE) && (arg7 == 5)) { + arg7 = 0; /* better not upset firmware */ + do_lock = 1; + } + for (i = 0; i < 5; i++) { + if (do_lock) + spin_lock_irqsave(&hcall_lock, flags); + ret = plpar_hcall_norets(opcode, arg1, arg2, arg3, arg4, arg5, arg6, arg7); + if (do_lock) + spin_unlock_irqrestore(&hcall_lock, flags); + if (H_IS_LONG_BUSY(ret)) { sleep_msecs = get_longbusy_msecs(ret); msleep_interruptible(sleep_msecs); @@ -161,23 +174,24 @@ static long ehca_plpar_hcall9(unsigned long opcode, unsigned long arg9) { long ret; - int i, sleep_msecs, lock_is_set = 0; + int i, sleep_msecs, do_lock; unsigned long flags = 0; ehca_gen_dbg("INPUT -- opcode=%lx " HCALL9_REGS_FORMAT, opcode, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); + /* lock H_ALLOC_RESOURCE(MR) against itself and H_FREE_RESOURCE(MR) */ + do_lock = ((opcode == H_ALLOC_RESOURCE) && (arg2 == 5)); + for (i = 0; i < 5; i++) { - if ((opcode == H_ALLOC_RESOURCE) && (arg2 == 5)) { + if (do_lock) spin_lock_irqsave(&hcall_lock, flags); - lock_is_set = 1; - } ret = plpar_hcall9(opcode, outs, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); - if (lock_is_set) + if (do_lock) spin_unlock_irqrestore(&hcall_lock, flags); if (H_IS_LONG_BUSY(ret)) { @@ -807,7 +821,7 @@ u64 hipz_h_free_resource_mr(const struct ipz_adapter_handle adapter_handle, return ehca_plpar_hcall_norets(H_FREE_RESOURCE, adapter_handle.handle, /* r4 */ mr->ipz_mr_handle.handle, /* r5 */ - 0, 0, 0, 0, 0); + 0, 0, 0, 0, 5); } u64 hipz_h_reregister_pmr(const struct ipz_adapter_handle adapter_handle, -- cgit v1.2.3-70-g09d2 From 5110e4de4995db1c28457b08ed1e291f9b38f2e7 Mon Sep 17 00:00:00 2001 From: Joachim Fenkes Date: Wed, 12 Sep 2007 16:44:11 +0200 Subject: IB/ehca: Replace get_paca()->paca_index by the more portable raw_smp_processor_id() We can use raw_smp_processor_id() here because the processor ID is only used for debug output and therefore our use is preemption-unsafe. Signed-off-by: Joachim Fenkes Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/ehca_tools.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ehca/ehca_tools.h b/drivers/infiniband/hw/ehca/ehca_tools.h index f9b264b4697..4a8346a2bc9 100644 --- a/drivers/infiniband/hw/ehca/ehca_tools.h +++ b/drivers/infiniband/hw/ehca/ehca_tools.h @@ -73,37 +73,37 @@ extern int ehca_debug_level; if (unlikely(ehca_debug_level)) \ dev_printk(KERN_DEBUG, (ib_dev)->dma_device, \ "PU%04x EHCA_DBG:%s " format "\n", \ - get_paca()->paca_index, __FUNCTION__, \ + raw_smp_processor_id(), __FUNCTION__, \ ## arg); \ } while (0) #define ehca_info(ib_dev, format, arg...) \ dev_info((ib_dev)->dma_device, "PU%04x EHCA_INFO:%s " format "\n", \ - get_paca()->paca_index, __FUNCTION__, ## arg) + raw_smp_processor_id(), __FUNCTION__, ## arg) #define ehca_warn(ib_dev, format, arg...) \ dev_warn((ib_dev)->dma_device, "PU%04x EHCA_WARN:%s " format "\n", \ - get_paca()->paca_index, __FUNCTION__, ## arg) + raw_smp_processor_id(), __FUNCTION__, ## arg) #define ehca_err(ib_dev, format, arg...) \ dev_err((ib_dev)->dma_device, "PU%04x EHCA_ERR:%s " format "\n", \ - get_paca()->paca_index, __FUNCTION__, ## arg) + raw_smp_processor_id(), __FUNCTION__, ## arg) /* use this one only if no ib_dev available */ #define ehca_gen_dbg(format, arg...) \ do { \ if (unlikely(ehca_debug_level)) \ printk(KERN_DEBUG "PU%04x EHCA_DBG:%s " format "\n", \ - get_paca()->paca_index, __FUNCTION__, ## arg); \ + raw_smp_processor_id(), __FUNCTION__, ## arg); \ } while (0) #define ehca_gen_warn(format, arg...) \ printk(KERN_INFO "PU%04x EHCA_WARN:%s " format "\n", \ - get_paca()->paca_index, __FUNCTION__, ## arg) + raw_smp_processor_id(), __FUNCTION__, ## arg) #define ehca_gen_err(format, arg...) \ printk(KERN_ERR "PU%04x EHCA_ERR:%s " format "\n", \ - get_paca()->paca_index, __FUNCTION__, ## arg) + raw_smp_processor_id(), __FUNCTION__, ## arg) /** * ehca_dmp - printk a memory block, whose length is n*8 bytes. -- cgit v1.2.3-70-g09d2 From 39089e77741a53874eb8a29e4516bbafcc29298a Mon Sep 17 00:00:00 2001 From: Joachim Fenkes Date: Tue, 11 Sep 2007 15:35:32 +0200 Subject: IB/ehca: Bump version number and change its format Nobody needed the SVNEHCA_ prefix anyway. Signed-off-by: Joachim Fenkes Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/ehca_main.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c index 0e3ffeef45d..403467f66fe 100644 --- a/drivers/infiniband/hw/ehca/ehca_main.c +++ b/drivers/infiniband/hw/ehca/ehca_main.c @@ -49,10 +49,12 @@ #include "ehca_tools.h" #include "hcp_if.h" +#define HCAD_VERSION "0024" + MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Christoph Raisch "); MODULE_DESCRIPTION("IBM eServer HCA InfiniBand Device Driver"); -MODULE_VERSION("SVNEHCA_0023"); +MODULE_VERSION(HCAD_VERSION); int ehca_open_aqp1 = 0; int ehca_debug_level = 0; @@ -909,7 +911,7 @@ int __init ehca_module_init(void) int ret; printk(KERN_INFO "eHCA Infiniband Device Driver " - "(Rel.: SVNEHCA_0023)\n"); + "(Version " HCAD_VERSION ")\n"); ret = ehca_create_comp_pool(); if (ret) { -- cgit v1.2.3-70-g09d2 From 08c283ac262d7ab21c5733ff469ff88985381ca9 Mon Sep 17 00:00:00 2001 From: Hoang-Nam Nguyen Date: Thu, 13 Sep 2007 18:14:58 +0200 Subject: IB/ehca: Fix large page HW cap defines Signed-off-by: Joachim Fenkes Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/ehca_classes.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h index 0942a173881..d6706966a01 100644 --- a/drivers/infiniband/hw/ehca/ehca_classes.h +++ b/drivers/infiniband/hw/ehca/ehca_classes.h @@ -100,10 +100,10 @@ struct ehca_sport { struct ehca_sma_attr saved_attr; }; -#define HCA_CAP_MR_PGSIZE_4K 1 -#define HCA_CAP_MR_PGSIZE_64K 2 -#define HCA_CAP_MR_PGSIZE_1M 4 -#define HCA_CAP_MR_PGSIZE_16M 8 +#define HCA_CAP_MR_PGSIZE_4K 0x80000000 +#define HCA_CAP_MR_PGSIZE_64K 0x40000000 +#define HCA_CAP_MR_PGSIZE_1M 0x20000000 +#define HCA_CAP_MR_PGSIZE_16M 0x10000000 struct ehca_shca { struct ib_device ib_device; -- cgit v1.2.3-70-g09d2 From 81668838c4583b19276b16382e0c61e21ef5adf0 Mon Sep 17 00:00:00 2001 From: Sean Hefty Date: Thu, 2 Aug 2007 12:21:31 -0700 Subject: IPoIB: Specify Traffic Class with path record queries for QoS support To support QoS within and between subnets, modify IPoIB to request specific Traffic Class values with path record queries, using the value associated with the IPoIB broadcast group. Signed-off-by: Sean Hefty [ See some comments I made on this at v1 and v2 of the posts ] Reviewed-by: Or Gerlitz Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/ipoib/ipoib.h | 22 +++++++++++++++++++++- drivers/infiniband/ulp/ipoib/ipoib_main.c | 8 +++++--- drivers/infiniband/ulp/ipoib/ipoib_multicast.c | 22 ---------------------- 3 files changed, 26 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index 285c143115c..fc16bced8e5 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h @@ -113,7 +113,27 @@ struct ipoib_pseudoheader { u8 hwaddr[INFINIBAND_ALEN]; }; -struct ipoib_mcast; +/* Used for all multicast joins (broadcast, IPv4 mcast and IPv6 mcast) */ +struct ipoib_mcast { + struct ib_sa_mcmember_rec mcmember; + struct ib_sa_multicast *mc; + struct ipoib_ah *ah; + + struct rb_node rb_node; + struct list_head list; + + unsigned long created; + unsigned long backoff; + + unsigned long flags; + unsigned char logcount; + + struct list_head neigh_list; + + struct sk_buff_head pkt_queue; + + struct net_device *dev; +}; struct ipoib_rx_buf { struct sk_buff *skb; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 5f948b9a994..900335a36e4 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -468,9 +468,10 @@ static struct ipoib_path *path_rec_create(struct net_device *dev, void *gid) INIT_LIST_HEAD(&path->neigh_list); memcpy(path->pathrec.dgid.raw, gid, sizeof (union ib_gid)); - path->pathrec.sgid = priv->local_gid; - path->pathrec.pkey = cpu_to_be16(priv->pkey); - path->pathrec.numb_path = 1; + path->pathrec.sgid = priv->local_gid; + path->pathrec.pkey = cpu_to_be16(priv->pkey); + path->pathrec.numb_path = 1; + path->pathrec.traffic_class = priv->broadcast->mcmember.traffic_class; return path; } @@ -491,6 +492,7 @@ static int path_rec_start(struct net_device *dev, IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID | IB_SA_PATH_REC_NUMB_PATH | + IB_SA_PATH_REC_TRAFFIC_CLASS | IB_SA_PATH_REC_PKEY, 1000, GFP_ATOMIC, path_rec_completion, diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index aae367057a5..94a57097e2b 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -57,28 +57,6 @@ MODULE_PARM_DESC(mcast_debug_level, static DEFINE_MUTEX(mcast_mutex); -/* Used for all multicast joins (broadcast, IPv4 mcast and IPv6 mcast) */ -struct ipoib_mcast { - struct ib_sa_mcmember_rec mcmember; - struct ib_sa_multicast *mc; - struct ipoib_ah *ah; - - struct rb_node rb_node; - struct list_head list; - - unsigned long created; - unsigned long backoff; - - unsigned long flags; - unsigned char logcount; - - struct list_head neigh_list; - - struct sk_buff_head pkt_queue; - - struct net_device *dev; -}; - struct ipoib_mcast_iter { struct net_device *dev; union ib_gid mgid; -- cgit v1.2.3-70-g09d2 From 733d65fe33b3002a6f2694c0fd8bd760dc13141f Mon Sep 17 00:00:00 2001 From: Sean Hefty Date: Wed, 8 Aug 2007 15:41:28 -0700 Subject: IB/sa: Add new QoS fields to path record The QoS annex defines new fields for path records. Add them to the ib_sa for consumers that want to use them. Signed-off-by: Sean Hefty Reviewed-by: Or Gerlitz Signed-off-by: Roland Dreier --- drivers/infiniband/core/sa_query.c | 10 +++------- include/rdma/ib_sa.h | 11 +++++------ 2 files changed, 8 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c index 312c8ff5ae8..cf474ec2707 100644 --- a/drivers/infiniband/core/sa_query.c +++ b/drivers/infiniband/core/sa_query.c @@ -123,14 +123,10 @@ static u32 tid; .field_name = "sa_path_rec:" #field static const struct ib_field path_rec_table[] = { - { RESERVED, + { PATH_REC_FIELD(service_id), .offset_words = 0, .offset_bits = 0, - .size_bits = 32 }, - { RESERVED, - .offset_words = 1, - .offset_bits = 0, - .size_bits = 32 }, + .size_bits = 64 }, { PATH_REC_FIELD(dgid), .offset_words = 2, .offset_bits = 0, @@ -179,7 +175,7 @@ static const struct ib_field path_rec_table[] = { .offset_words = 12, .offset_bits = 16, .size_bits = 16 }, - { RESERVED, + { PATH_REC_FIELD(qos_class), .offset_words = 13, .offset_bits = 0, .size_bits = 12 }, diff --git a/include/rdma/ib_sa.h b/include/rdma/ib_sa.h index 5e26b2f53f8..942692b0b92 100644 --- a/include/rdma/ib_sa.h +++ b/include/rdma/ib_sa.h @@ -109,8 +109,8 @@ enum ib_sa_selector { * Reserved rows are indicated with comments to help maintainability. */ -/* reserved: 0 */ -/* reserved: 1 */ +#define IB_SA_PATH_REC_SERVICE_ID (IB_SA_COMP_MASK( 0) |\ + IB_SA_COMP_MASK( 1)) #define IB_SA_PATH_REC_DGID IB_SA_COMP_MASK( 2) #define IB_SA_PATH_REC_SGID IB_SA_COMP_MASK( 3) #define IB_SA_PATH_REC_DLID IB_SA_COMP_MASK( 4) @@ -123,7 +123,7 @@ enum ib_sa_selector { #define IB_SA_PATH_REC_REVERSIBLE IB_SA_COMP_MASK(11) #define IB_SA_PATH_REC_NUMB_PATH IB_SA_COMP_MASK(12) #define IB_SA_PATH_REC_PKEY IB_SA_COMP_MASK(13) -/* reserved: 14 */ +#define IB_SA_PATH_REC_QOS_CLASS IB_SA_COMP_MASK(14) #define IB_SA_PATH_REC_SL IB_SA_COMP_MASK(15) #define IB_SA_PATH_REC_MTU_SELECTOR IB_SA_COMP_MASK(16) #define IB_SA_PATH_REC_MTU IB_SA_COMP_MASK(17) @@ -134,8 +134,7 @@ enum ib_sa_selector { #define IB_SA_PATH_REC_PREFERENCE IB_SA_COMP_MASK(22) struct ib_sa_path_rec { - /* reserved */ - /* reserved */ + __be64 service_id; union ib_gid dgid; union ib_gid sgid; __be16 dlid; @@ -148,7 +147,7 @@ struct ib_sa_path_rec { int reversible; u8 numb_path; __be16 pkey; - /* reserved */ + __be16 qos_class; u8 sl; u8 mtu_selector; u8 mtu; -- cgit v1.2.3-70-g09d2 From a81c994d5eef87ed77cb30d8343d6be296528b3f Mon Sep 17 00:00:00 2001 From: Sean Hefty Date: Wed, 8 Aug 2007 15:51:06 -0700 Subject: RDMA/cma: Add ability to specify type of service Provide support to specify a type of service for a communication identifier. A new function call is used when dealing with IPv4 addresses. For IPv6 addresses, the ToS is specified through the traffic class field in the sockaddr_in6 structure. Signed-off-by: Sean Hefty [ The comments Eitan Zahavi and myself have made over the v1 post at were fully addressed. ] Reviewed-by: Or Gerlitz Signed-off-by: Roland Dreier --- drivers/infiniband/core/cma.c | 44 +++++++++++++++++++++++++++++++++---------- include/rdma/rdma_cm.h | 14 ++++++++++++++ 2 files changed, 48 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 9ffb9987450..19c9172f0cd 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -138,6 +138,7 @@ struct rdma_id_private { u32 qkey; u32 qp_num; u8 srq; + u8 tos; }; struct cma_multicast { @@ -1474,6 +1475,15 @@ err: } EXPORT_SYMBOL(rdma_listen); +void rdma_set_service_type(struct rdma_cm_id *id, int tos) +{ + struct rdma_id_private *id_priv; + + id_priv = container_of(id, struct rdma_id_private, id); + id_priv->tos = (u8) tos; +} +EXPORT_SYMBOL(rdma_set_service_type); + static void cma_query_handler(int status, struct ib_sa_path_rec *path_rec, void *context) { @@ -1498,23 +1508,37 @@ static void cma_query_handler(int status, struct ib_sa_path_rec *path_rec, static int cma_query_ib_route(struct rdma_id_private *id_priv, int timeout_ms, struct cma_work *work) { - struct rdma_dev_addr *addr = &id_priv->id.route.addr.dev_addr; + struct rdma_addr *addr = &id_priv->id.route.addr; struct ib_sa_path_rec path_rec; + ib_sa_comp_mask comp_mask; + struct sockaddr_in6 *sin6; memset(&path_rec, 0, sizeof path_rec); - ib_addr_get_sgid(addr, &path_rec.sgid); - ib_addr_get_dgid(addr, &path_rec.dgid); - path_rec.pkey = cpu_to_be16(ib_addr_get_pkey(addr)); + ib_addr_get_sgid(&addr->dev_addr, &path_rec.sgid); + ib_addr_get_dgid(&addr->dev_addr, &path_rec.dgid); + path_rec.pkey = cpu_to_be16(ib_addr_get_pkey(&addr->dev_addr)); path_rec.numb_path = 1; path_rec.reversible = 1; + path_rec.service_id = cma_get_service_id(id_priv->id.ps, &addr->dst_addr); + + comp_mask = IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID | + IB_SA_PATH_REC_PKEY | IB_SA_PATH_REC_NUMB_PATH | + IB_SA_PATH_REC_REVERSIBLE | IB_SA_PATH_REC_SERVICE_ID; + + if (addr->src_addr.sa_family == AF_INET) { + path_rec.qos_class = cpu_to_be16((u16) id_priv->tos); + comp_mask |= IB_SA_PATH_REC_QOS_CLASS; + } else { + sin6 = (struct sockaddr_in6 *) &addr->src_addr; + path_rec.traffic_class = (u8) (be32_to_cpu(sin6->sin6_flowinfo) >> 20); + comp_mask |= IB_SA_PATH_REC_TRAFFIC_CLASS; + } id_priv->query_id = ib_sa_path_rec_get(&sa_client, id_priv->id.device, - id_priv->id.port_num, &path_rec, - IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID | - IB_SA_PATH_REC_PKEY | IB_SA_PATH_REC_NUMB_PATH | - IB_SA_PATH_REC_REVERSIBLE, - timeout_ms, GFP_KERNEL, - cma_query_handler, work, &id_priv->query); + id_priv->id.port_num, &path_rec, + comp_mask, timeout_ms, + GFP_KERNEL, cma_query_handler, + work, &id_priv->query); return (id_priv->query_id < 0) ? id_priv->query_id : 0; } diff --git a/include/rdma/rdma_cm.h b/include/rdma/rdma_cm.h index 2d6a7705eae..010f876f41d 100644 --- a/include/rdma/rdma_cm.h +++ b/include/rdma/rdma_cm.h @@ -314,4 +314,18 @@ int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr, */ void rdma_leave_multicast(struct rdma_cm_id *id, struct sockaddr *addr); +/** + * rdma_set_service_type - Set the type of service associated with a + * connection identifier. + * @id: Communication identifier to associated with service type. + * @tos: Type of service. + * + * The type of service is interpretted as a differentiated service + * field (RFC 2474). The service type should be specified before + * performing route resolution, as existing communication on the + * connection identifier may be unaffected. The type of service + * requested may not be supported by the network to all destinations. + */ +void rdma_set_service_type(struct rdma_cm_id *id, int tos); + #endif /* RDMA_CM_H */ -- cgit v1.2.3-70-g09d2 From 7ce86409adcd2fda652b628173a66e905950ece1 Mon Sep 17 00:00:00 2001 From: Sean Hefty Date: Wed, 8 Aug 2007 15:51:13 -0700 Subject: RDMA/ucma: Allow user space to set service type Export the ability to set the type of service to user space. Model the interface after setsockopt. Signed-off-by: Sean Hefty Signed-off-by: Roland Dreier --- drivers/infiniband/core/ucma.c | 74 +++++++++++++++++++++++++++++++++++++++++- include/rdma/rdma_user_cm.h | 18 ++++++++++ 2 files changed, 91 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index 53b4c94a7eb..90d675ad9ec 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -792,6 +792,78 @@ out: return ret; } +static int ucma_set_option_id(struct ucma_context *ctx, int optname, + void *optval, size_t optlen) +{ + int ret = 0; + + switch (optname) { + case RDMA_OPTION_ID_TOS: + if (optlen != sizeof(u8)) { + ret = -EINVAL; + break; + } + rdma_set_service_type(ctx->cm_id, *((u8 *) optval)); + break; + default: + ret = -ENOSYS; + } + + return ret; +} + +static int ucma_set_option_level(struct ucma_context *ctx, int level, + int optname, void *optval, size_t optlen) +{ + int ret; + + switch (level) { + case RDMA_OPTION_ID: + ret = ucma_set_option_id(ctx, optname, optval, optlen); + break; + default: + ret = -ENOSYS; + } + + return ret; +} + +static ssize_t ucma_set_option(struct ucma_file *file, const char __user *inbuf, + int in_len, int out_len) +{ + struct rdma_ucm_set_option cmd; + struct ucma_context *ctx; + void *optval; + int ret; + + if (copy_from_user(&cmd, inbuf, sizeof(cmd))) + return -EFAULT; + + ctx = ucma_get_ctx(file, cmd.id); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + optval = kmalloc(cmd.optlen, GFP_KERNEL); + if (!optval) { + ret = -ENOMEM; + goto out1; + } + + if (copy_from_user(optval, (void __user *) (unsigned long) cmd.optval, + cmd.optlen)) { + ret = -EFAULT; + goto out2; + } + + ret = ucma_set_option_level(ctx, cmd.level, cmd.optname, optval, + cmd.optlen); +out2: + kfree(optval); +out1: + ucma_put_ctx(ctx); + return ret; +} + static ssize_t ucma_notify(struct ucma_file *file, const char __user *inbuf, int in_len, int out_len) { @@ -936,7 +1008,7 @@ static ssize_t (*ucma_cmd_table[])(struct ucma_file *file, [RDMA_USER_CM_CMD_INIT_QP_ATTR] = ucma_init_qp_attr, [RDMA_USER_CM_CMD_GET_EVENT] = ucma_get_event, [RDMA_USER_CM_CMD_GET_OPTION] = NULL, - [RDMA_USER_CM_CMD_SET_OPTION] = NULL, + [RDMA_USER_CM_CMD_SET_OPTION] = ucma_set_option, [RDMA_USER_CM_CMD_NOTIFY] = ucma_notify, [RDMA_USER_CM_CMD_JOIN_MCAST] = ucma_join_multicast, [RDMA_USER_CM_CMD_LEAVE_MCAST] = ucma_leave_multicast, diff --git a/include/rdma/rdma_user_cm.h b/include/rdma/rdma_user_cm.h index f632b0c007c..9749c1b34d0 100644 --- a/include/rdma/rdma_user_cm.h +++ b/include/rdma/rdma_user_cm.h @@ -212,4 +212,22 @@ struct rdma_ucm_event_resp { } param; }; +/* Option levels */ +enum { + RDMA_OPTION_ID = 0 +}; + +/* Option details */ +enum { + RDMA_OPTION_ID_TOS = 0 +}; + +struct rdma_ucm_set_option { + __u64 optval; + __u32 id; + __u32 level; + __u32 optname; + __u32 optlen; +}; + #endif /* RDMA_USER_CM_H */ -- cgit v1.2.3-70-g09d2 From 247e020ee5e2a7bf46f2d7a3d4490a670a712a40 Mon Sep 17 00:00:00 2001 From: Sean Hefty Date: Wed, 8 Aug 2007 15:51:18 -0700 Subject: IB/srp: Add QoS support through service ID Provide the target service ID when performing a path record query to support optional QoS capability. QoS requires support from the SA. Signed-off-by: Sean Hefty Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/srp/ib_srp.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index f6a05142814..9ccc63886d9 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -285,6 +285,7 @@ static int srp_lookup_path(struct srp_target_port *target) target->srp_host->dev->dev, target->srp_host->port, &target->path, + IB_SA_PATH_REC_SERVICE_ID | IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID | IB_SA_PATH_REC_NUMB_PATH | @@ -1692,6 +1693,7 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target) goto out; } target->service_id = cpu_to_be64(simple_strtoull(p, NULL, 16)); + target->path.service_id = target->service_id; kfree(p); break; -- cgit v1.2.3-70-g09d2 From c8d8beea0383e47c9d65d45f0ca95626ec435fcd Mon Sep 17 00:00:00 2001 From: Joachim Fenkes Date: Thu, 13 Sep 2007 18:15:28 +0200 Subject: IB/umem: Add hugetlb flag to struct ib_umem During ib_umem_get(), determine whether all pages from the memory region are hugetlb pages and report this in the "hugetlb" member. Low-level drivers can use this information if they need it. Signed-off-by: Joachim Fenkes Signed-off-by: Roland Dreier --- drivers/infiniband/core/umem.c | 20 +++++++++++++++++++- include/rdma/ib_umem.h | 1 + 2 files changed, 20 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c index 664d2faa9e7..2f54e29dc7a 100644 --- a/drivers/infiniband/core/umem.c +++ b/drivers/infiniband/core/umem.c @@ -37,6 +37,7 @@ #include #include #include +#include #include "uverbs.h" @@ -75,6 +76,7 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, { struct ib_umem *umem; struct page **page_list; + struct vm_area_struct **vma_list; struct ib_umem_chunk *chunk; unsigned long locked; unsigned long lock_limit; @@ -104,6 +106,9 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, */ umem->writable = !!(access & ~IB_ACCESS_REMOTE_READ); + /* We assume the memory is from hugetlb until proved otherwise */ + umem->hugetlb = 1; + INIT_LIST_HEAD(&umem->chunk_list); page_list = (struct page **) __get_free_page(GFP_KERNEL); @@ -112,6 +117,14 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, return ERR_PTR(-ENOMEM); } + /* + * if we can't alloc the vma_list, it's not so bad; + * just assume the memory is not hugetlb memory + */ + vma_list = (struct vm_area_struct **) __get_free_page(GFP_KERNEL); + if (!vma_list) + umem->hugetlb = 0; + npages = PAGE_ALIGN(size + umem->offset) >> PAGE_SHIFT; down_write(¤t->mm->mmap_sem); @@ -131,7 +144,7 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, ret = get_user_pages(current, current->mm, cur_base, min_t(int, npages, PAGE_SIZE / sizeof (struct page *)), - 1, !umem->writable, page_list, NULL); + 1, !umem->writable, page_list, vma_list); if (ret < 0) goto out; @@ -152,6 +165,9 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, chunk->nents = min_t(int, ret, IB_UMEM_MAX_PAGE_CHUNK); for (i = 0; i < chunk->nents; ++i) { + if (vma_list && + !is_vm_hugetlb_page(vma_list[i + off])) + umem->hugetlb = 0; chunk->page_list[i].page = page_list[i + off]; chunk->page_list[i].offset = 0; chunk->page_list[i].length = PAGE_SIZE; @@ -186,6 +202,8 @@ out: current->mm->locked_vm = locked; up_write(¤t->mm->mmap_sem); + if (vma_list) + free_page((unsigned long) vma_list); free_page((unsigned long) page_list); return ret < 0 ? ERR_PTR(ret) : umem; diff --git a/include/rdma/ib_umem.h b/include/rdma/ib_umem.h index c533d6c7903..22298423cf0 100644 --- a/include/rdma/ib_umem.h +++ b/include/rdma/ib_umem.h @@ -45,6 +45,7 @@ struct ib_umem { int offset; int page_size; int writable; + int hugetlb; struct list_head chunk_list; struct work_struct work; struct mm_struct *mm; -- cgit v1.2.3-70-g09d2 From 3a31c41901b6bd3937ec36e0e4a930849e270df6 Mon Sep 17 00:00:00 2001 From: Joachim Fenkes Date: Thu, 13 Sep 2007 18:16:20 +0200 Subject: IB/ehca: Only use MR large pages for hugetlb regions ...because, on virtualized hardware like System p, we can't be sure that the physical pages behind them are contiguous otherwise. Signed-off-by: Joachim Fenkes Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/ehca_mrmw.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ehca/ehca_mrmw.c b/drivers/infiniband/hw/ehca/ehca_mrmw.c index e925e84c9bc..da88738265e 100644 --- a/drivers/infiniband/hw/ehca/ehca_mrmw.c +++ b/drivers/infiniband/hw/ehca/ehca_mrmw.c @@ -51,6 +51,7 @@ #define NUM_CHUNKS(length, chunk_size) \ (((length) + (chunk_size - 1)) / (chunk_size)) + /* max number of rpages (per hcall register_rpages) */ #define MAX_RPAGES 512 @@ -64,6 +65,11 @@ enum ehca_mr_pgsize { EHCA_MR_PGSIZE16M = 0x1000000L }; +#define EHCA_MR_PGSHIFT4K 12 +#define EHCA_MR_PGSHIFT64K 16 +#define EHCA_MR_PGSHIFT1M 20 +#define EHCA_MR_PGSHIFT16M 24 + static u32 ehca_encode_hwpage_size(u32 pgsize) { u32 idx = 0; @@ -347,17 +353,16 @@ struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, /* select proper hw_pgsize */ if (ehca_mr_largepage && (shca->hca_cap_mr_pgsize & HCA_CAP_MR_PGSIZE_16M)) { - if (length <= EHCA_MR_PGSIZE4K - && PAGE_SIZE == EHCA_MR_PGSIZE4K) - hwpage_size = EHCA_MR_PGSIZE4K; - else if (length <= EHCA_MR_PGSIZE64K) - hwpage_size = EHCA_MR_PGSIZE64K; - else if (length <= EHCA_MR_PGSIZE1M) - hwpage_size = EHCA_MR_PGSIZE1M; - else - hwpage_size = EHCA_MR_PGSIZE16M; + int page_shift = PAGE_SHIFT; + if (e_mr->umem->hugetlb) { + /* determine page_shift, clamp between 4K and 16M */ + page_shift = (fls64(length - 1) + 3) & ~3; + page_shift = min(max(page_shift, EHCA_MR_PGSHIFT4K), + EHCA_MR_PGSHIFT16M); + } + hwpage_size = 1UL << page_shift; } else - hwpage_size = EHCA_MR_PGSIZE4K; + hwpage_size = EHCA_MR_PGSIZE4K; /* ehca1 only supports 4k */ ehca_dbg(pd->device, "hwpage_size=%lx", hwpage_size); reg_user_mr_fallback: -- cgit v1.2.3-70-g09d2 From 935ef2d7a2910ca810fce57511f4d06a0cf00b5e Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Wed, 12 Sep 2007 05:00:25 -0500 Subject: RDMA/cma: Use neigh_event_send() to start neighbour discovery Calling arp_send() to initiate neighbour discovery (ND) doesn't do the full ND protocol. Namely, it doesn't handle retransmitting the arp request if it is dropped. The function neigh_event_send() does all this. Without doing full ND, RDMA address resolution fails in the presence of dropped ARP broadcast packets. Signed-off-by: Steve Wise Acked-by: Sean Hefty Signed-off-by: Roland Dreier --- drivers/infiniband/core/addr.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index c5c33d35f87..5381c80de10 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -161,8 +161,7 @@ static void addr_send_arp(struct sockaddr_in *dst_in) if (ip_route_output_key(&rt, &fl)) return; - arp_send(ARPOP_REQUEST, ETH_P_ARP, rt->rt_gateway, rt->idev->dev, - rt->rt_src, NULL, rt->idev->dev->dev_addr, NULL); + neigh_event_send(rt->u.dst.neighbour, NULL); ip_rt_put(rt); } -- cgit v1.2.3-70-g09d2 From ec2a1344ad348a789b1d9d9b32cccbef33161574 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 9 Oct 2007 19:59:13 -0700 Subject: IB/iser: Remove unnecessary includes is not needed because everyplace it appears, also appears. is not needed because nothing seems to be using device IO anyway. Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/iser/iser_initiator.c | 2 -- drivers/infiniband/ulp/iser/iser_memory.c | 2 -- drivers/infiniband/ulp/iser/iser_verbs.c | 1 - 3 files changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c index 9ea5b9aaba7..a6f2303ed14 100644 --- a/drivers/infiniband/ulp/iser/iser_initiator.c +++ b/drivers/infiniband/ulp/iser/iser_initiator.c @@ -34,8 +34,6 @@ #include #include #include -#include -#include #include #include #include diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c index 36cdf77ae92..e05690e3592 100644 --- a/drivers/infiniband/ulp/iser/iser_memory.c +++ b/drivers/infiniband/ulp/iser/iser_memory.c @@ -36,8 +36,6 @@ #include #include #include -#include -#include #include #include "iscsi_iser.h" diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index d42ec0156ee..654a4dce023 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c @@ -32,7 +32,6 @@ * * $Id: iser_verbs.c 7051 2006-05-10 12:29:11Z ogerlitz $ */ -#include #include #include #include -- cgit v1.2.3-70-g09d2 From ea98054fefa28b646c740baffe83c2962f8228f6 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 9 Oct 2007 19:59:13 -0700 Subject: mlx4_core: Change capability decoding: SRC->XRC The SRC ("scalable RC") transport has been renamed to XRC ("extended RC"), to avoid having an abbreviation that is so easily confused with an abbreviation for "source." Update the HCA capability decoding output to use the new name. Signed-off-by: Roland Dreier --- drivers/net/mlx4/fw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/mlx4/fw.c b/drivers/net/mlx4/fw.c index c45cbe43a0c..6471d33afb7 100644 --- a/drivers/net/mlx4/fw.c +++ b/drivers/net/mlx4/fw.c @@ -76,7 +76,7 @@ static void dump_dev_cap_flags(struct mlx4_dev *dev, u32 flags) [ 0] = "RC transport", [ 1] = "UC transport", [ 2] = "UD transport", - [ 3] = "SRC transport", + [ 3] = "XRC transport", [ 4] = "reliable multicast", [ 5] = "FCoIB support", [ 6] = "SRQ support", -- cgit v1.2.3-70-g09d2 From 9faa559c01311281f26544291322252327b65922 Mon Sep 17 00:00:00 2001 From: Satyam Sharma Date: Thu, 23 Aug 2007 04:58:30 +0530 Subject: IB/ehca: Misc cpuinit section annotations and #ifdef cleanups * Replace {un}register_cpu_notifier with {un}register_hotcpu_notifier thereby losing a couple of #ifdef HOTPLUG_CPU pairs. * Move comp_pool_callback_nb declaration to below that of callback function so that initialization of .notifier_call and .priority can occur at build time itself and not runtime. * Mark the notifier_block (and callback function, and another static function used by it) as __cpuinit{data} for the sake of consistency and remove enclosing #ifdef. (This may increase size for modular build of this module, however, because these are no longer dropped unconditionally now.) Signed-off-by: Satyam Sharma Acked-by: Joachim Fenkes Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/ehca_irq.c | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ehca/ehca_irq.c b/drivers/infiniband/hw/ehca/ehca_irq.c index 70939864fef..3f617b27b95 100644 --- a/drivers/infiniband/hw/ehca/ehca_irq.c +++ b/drivers/infiniband/hw/ehca/ehca_irq.c @@ -69,9 +69,6 @@ static void queue_comp_task(struct ehca_cq *__cq); static struct ehca_comp_pool *pool; -#ifdef CONFIG_HOTPLUG_CPU -static struct notifier_block comp_pool_callback_nb; -#endif static inline void comp_event_callback(struct ehca_cq *cq) { @@ -760,9 +757,7 @@ static void destroy_comp_task(struct ehca_comp_pool *pool, kthread_stop(task); } -#ifdef CONFIG_HOTPLUG_CPU -static void take_over_work(struct ehca_comp_pool *pool, - int cpu) +static void __cpuinit take_over_work(struct ehca_comp_pool *pool, int cpu) { struct ehca_cpu_comp_task *cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu); LIST_HEAD(list); @@ -785,9 +780,9 @@ static void take_over_work(struct ehca_comp_pool *pool, } -static int comp_pool_callback(struct notifier_block *nfb, - unsigned long action, - void *hcpu) +static int __cpuinit comp_pool_callback(struct notifier_block *nfb, + unsigned long action, + void *hcpu) { unsigned int cpu = (unsigned long)hcpu; struct ehca_cpu_comp_task *cct; @@ -833,7 +828,11 @@ static int comp_pool_callback(struct notifier_block *nfb, return NOTIFY_OK; } -#endif + +static struct notifier_block comp_pool_callback_nb __cpuinitdata = { + .notifier_call = comp_pool_callback, + .priority = 0, +}; int ehca_create_comp_pool(void) { @@ -864,11 +863,7 @@ int ehca_create_comp_pool(void) } } -#ifdef CONFIG_HOTPLUG_CPU - comp_pool_callback_nb.notifier_call = comp_pool_callback; - comp_pool_callback_nb.priority = 0; - register_cpu_notifier(&comp_pool_callback_nb); -#endif + register_hotcpu_notifier(&comp_pool_callback_nb); printk(KERN_INFO "eHCA scaling code enabled\n"); @@ -882,9 +877,7 @@ void ehca_destroy_comp_pool(void) if (!ehca_scaling_code) return; -#ifdef CONFIG_HOTPLUG_CPU - unregister_cpu_notifier(&comp_pool_callback_nb); -#endif + unregister_hotcpu_notifier(&comp_pool_callback_nb); for (i = 0; i < NR_CPUS; i++) { if (cpu_online(i)) -- cgit v1.2.3-70-g09d2 From 57cb61d587e990d556385d367589ff61f6c2c0f2 Mon Sep 17 00:00:00 2001 From: Ralph Campbell Date: Thu, 20 Sep 2007 16:33:44 -0700 Subject: IB/core: Fix handling of multicast response failures I was looking at the code for multicast.c and noticed that ib_sa_join_multicast() calls queue_join() which puts the request at the front of the group->pending_list. If this is a second request, it seems like it would interfere with process_join_error() since group->last_join won't point to the member at the head of the pending_list. The sequence would thus be: 1. ib_sa_join_multicast() puts member1 on head of pending_list and starts work thread 2. mcast_work_handler() calls send_join() which sets group->last_join to member1 3. ib_sa_join_multicast() puts member2 on head of pending_list 4. join operation for member1 receives failures response from SA. 5. join_handler() is called with error status 6. process_join_error() fails to process member1 since it doesn't match the first entry in the group->pending_list. The impact is that the failed join request is tossed. The second request is processed, and after it completes, the original request ends up being retried. This change also results in join requests being processed in FIFO order. Signed-off-by: Ralph Campbell Signed-off-by: Sean Hefty Signed-off-by: Roland Dreier --- drivers/infiniband/core/multicast.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/multicast.c b/drivers/infiniband/core/multicast.c index 15b4c4d3606..1bc1fe60528 100644 --- a/drivers/infiniband/core/multicast.c +++ b/drivers/infiniband/core/multicast.c @@ -196,7 +196,7 @@ static void queue_join(struct mcast_member *member) unsigned long flags; spin_lock_irqsave(&group->lock, flags); - list_add(&member->list, &group->pending_list); + list_add_tail(&member->list, &group->pending_list); if (group->state == MCAST_IDLE) { group->state = MCAST_BUSY; atomic_inc(&group->refcount); -- cgit v1.2.3-70-g09d2 From cd9281d873c91a01af0cb96ff0f75e9905e54403 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Tue, 18 Sep 2007 09:14:18 +0200 Subject: IB/mlx4: Display misc device information under /sys/class/infiniband/ display the following device information under /sys/class/infiniband/mlx4_X: board_id, fw_ver, hw_rev, hca_type. This patch makes this information available to userspace utilities such as ibstat and ibv_devinfo. Signed-off-by: Jack Morgenstein Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mlx4/main.c | 45 +++++++++++++++++++++++++++++++++++++++ drivers/net/mlx4/main.c | 4 ++-- drivers/net/mlx4/mlx4.h | 7 ------ include/linux/mlx4/device.h | 6 ++++++ 4 files changed, 53 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index dde8fe9af47..d9fc822a146 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -476,9 +476,48 @@ out: return err; } +static ssize_t show_hca(struct class_device *cdev, char *buf) +{ + struct mlx4_ib_dev *dev = container_of(cdev, struct mlx4_ib_dev, ib_dev.class_dev); + return sprintf(buf, "MT%d\n", dev->dev->pdev->device); +} + +static ssize_t show_fw_ver(struct class_device *cdev, char *buf) +{ + struct mlx4_ib_dev *dev = container_of(cdev, struct mlx4_ib_dev, ib_dev.class_dev); + return sprintf(buf, "%d.%d.%d\n", (int) (dev->dev->caps.fw_ver >> 32), + (int) (dev->dev->caps.fw_ver >> 16) & 0xffff, + (int) dev->dev->caps.fw_ver & 0xffff); +} + +static ssize_t show_rev(struct class_device *cdev, char *buf) +{ + struct mlx4_ib_dev *dev = container_of(cdev, struct mlx4_ib_dev, ib_dev.class_dev); + return sprintf(buf, "%x\n", dev->dev->rev_id); +} + +static ssize_t show_board(struct class_device *cdev, char *buf) +{ + struct mlx4_ib_dev *dev = container_of(cdev, struct mlx4_ib_dev, ib_dev.class_dev); + return sprintf(buf, "%.*s\n", MLX4_BOARD_ID_LEN, dev->dev->board_id); +} + +static CLASS_DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL); +static CLASS_DEVICE_ATTR(fw_ver, S_IRUGO, show_fw_ver, NULL); +static CLASS_DEVICE_ATTR(hca_type, S_IRUGO, show_hca, NULL); +static CLASS_DEVICE_ATTR(board_id, S_IRUGO, show_board, NULL); + +static struct class_device_attribute *mlx4_class_attributes[] = { + &class_device_attr_hw_rev, + &class_device_attr_fw_ver, + &class_device_attr_hca_type, + &class_device_attr_board_id +}; + static void *mlx4_ib_add(struct mlx4_dev *dev) { struct mlx4_ib_dev *ibdev; + int i; ibdev = (struct mlx4_ib_dev *) ib_alloc_device(sizeof *ibdev); if (!ibdev) { @@ -580,6 +619,12 @@ static void *mlx4_ib_add(struct mlx4_dev *dev) if (mlx4_ib_mad_init(ibdev)) goto err_reg; + for (i = 0; i < ARRAY_SIZE(mlx4_class_attributes); ++i) { + if (class_device_create_file(&ibdev->ib_dev.class_dev, + mlx4_class_attributes[i])) + goto err_reg; + } + return ibdev; err_reg: diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c index 4b126943558..9e590e11c1c 100644 --- a/drivers/net/mlx4/main.c +++ b/drivers/net/mlx4/main.c @@ -524,8 +524,8 @@ static int __devinit mlx4_init_hca(struct mlx4_dev *dev) } priv->eq_table.inta_pin = adapter.inta_pin; - priv->rev_id = adapter.revision_id; - memcpy(priv->board_id, adapter.board_id, sizeof priv->board_id); + dev->rev_id = adapter.revision_id; + memcpy(dev->board_id, adapter.board_id, sizeof dev->board_id); return 0; diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h index be304a7c2c9..b9f83976191 100644 --- a/drivers/net/mlx4/mlx4.h +++ b/drivers/net/mlx4/mlx4.h @@ -55,10 +55,6 @@ enum { MLX4_CLR_INT_SIZE = 0x00008 }; -enum { - MLX4_BOARD_ID_LEN = 64 -}; - enum { MLX4_MGM_ENTRY_SIZE = 0x40, MLX4_QP_PER_MGM = 4 * (MLX4_MGM_ENTRY_SIZE / 16 - 2), @@ -277,9 +273,6 @@ struct mlx4_priv { struct mlx4_uar driver_uar; void __iomem *kar; - - u32 rev_id; - char board_id[MLX4_BOARD_ID_LEN]; }; static inline struct mlx4_priv *mlx4_priv(struct mlx4_dev *dev) diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h index cfb78fb2c04..a93520c76fd 100644 --- a/include/linux/mlx4/device.h +++ b/include/linux/mlx4/device.h @@ -48,6 +48,10 @@ enum { MLX4_MAX_PORTS = 2 }; +enum { + MLX4_BOARD_ID_LEN = 64 +}; + enum { MLX4_DEV_CAP_FLAG_RC = 1 << 0, MLX4_DEV_CAP_FLAG_UC = 1 << 1, @@ -272,6 +276,8 @@ struct mlx4_dev { unsigned long flags; struct mlx4_caps caps; struct radix_tree_root qp_table_tree; + u32 rev_id; + char board_id[MLX4_BOARD_ID_LEN]; }; struct mlx4_init_port_param { -- cgit v1.2.3-70-g09d2 From 03f72a51cb1a0ba530e3308e3de84399a75b41ec Mon Sep 17 00:00:00 2001 From: Hoang-Nam Nguyen Date: Fri, 28 Sep 2007 17:16:27 +0200 Subject: IB/ehca: Fix mem leak of firmware ctrlblock in ehca_create_srq() Signed-off-by: Hoang-Nam Nguyen Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/ehca_qp.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c index b10c7df669b..2591651dac9 100644 --- a/drivers/infiniband/hw/ehca/ehca_qp.c +++ b/drivers/infiniband/hw/ehca/ehca_qp.c @@ -890,6 +890,8 @@ struct ib_srq *ehca_create_srq(struct ib_pd *pd, goto create_srq2; } + ehca_free_fw_ctrlblock(mqpcb); + return &my_qp->ib_srq; create_srq2: -- cgit v1.2.3-70-g09d2 From a66072237500f31cec19fa688210150de9c9f957 Mon Sep 17 00:00:00 2001 From: Hoang-Nam Nguyen Date: Fri, 28 Sep 2007 17:18:47 +0200 Subject: IB/ehca: Adjust 64-bit alignment of create QP response for userspace Signed-off-by: Hoang-Nam Nguyen Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/ehca_classes.h | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h index d6706966a01..0f7a55d35ea 100644 --- a/drivers/infiniband/hw/ehca/ehca_classes.h +++ b/drivers/infiniband/hw/ehca/ehca_classes.h @@ -351,6 +351,7 @@ struct ehca_create_qp_resp { /* qp_num assigned by ehca: sqp0/1 may have got different numbers */ u32 real_qp_num; u32 fw_handle_ofs; + u32 dummy; struct ipzu_queue_resp ipz_squeue; struct ipzu_queue_resp ipz_rqueue; }; -- cgit v1.2.3-70-g09d2 From c01759cee91379cc3cb551bfd7c76f1b51f91ca2 Mon Sep 17 00:00:00 2001 From: Joachim Fenkes Date: Fri, 28 Sep 2007 17:20:05 +0200 Subject: IB/ehca: Return srq_attr->max_sge in ehca_query_srq() Totally forgot this. Signed-off-by: Joachim Fenkes Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/ehca_qp.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c index 2591651dac9..e2bd62be11e 100644 --- a/drivers/infiniband/hw/ehca/ehca_qp.c +++ b/drivers/infiniband/hw/ehca/ehca_qp.c @@ -1753,6 +1753,7 @@ int ehca_query_srq(struct ib_srq *srq, struct ib_srq_attr *srq_attr) } srq_attr->max_wr = qpcb->max_nr_outst_recv_wr - 1; + srq_attr->max_sge = qpcb->actual_nr_sges_in_rq_wqe; srq_attr->srq_limit = EHCA_BMASK_GET( MQPCB_CURR_SRQ_LIMIT, qpcb->curr_srq_limit); -- cgit v1.2.3-70-g09d2 From 2be8e3ee8efd6f99ce454115c29d09750915021a Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 9 Oct 2007 19:59:15 -0700 Subject: IB/umad: Add P_Key index support Add support for setting the P_Key index of sent MADs and getting the P_Key index of received MADs. This requires a change to the layout of the ABI structure struct ib_user_mad_hdr, so to avoid breaking compatibility, we default to the old (unchanged) ABI and add a new ioctl IB_USER_MAD_ENABLE_PKEY that allows applications that are aware of the new ABI to opt into using it. We plan on switching to the new ABI by default in a year or so, and this patch adds a warning that is printed when an application uses the old ABI, to push people towards converting to the new ABI. Signed-off-by: Roland Dreier Reviewed-by: Sean Hefty Reviewed-by: Hal Rosenstock --- Documentation/infiniband/user_mad.txt | 14 +++++ drivers/infiniband/core/user_mad.c | 102 ++++++++++++++++++++++++---------- include/rdma/ib_user_mad.h | 48 ++++++++++++++++ 3 files changed, 135 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/Documentation/infiniband/user_mad.txt b/Documentation/infiniband/user_mad.txt index 8ec54b974b6..744687dd195 100644 --- a/Documentation/infiniband/user_mad.txt +++ b/Documentation/infiniband/user_mad.txt @@ -99,6 +99,20 @@ Transaction IDs request/response pairs. The upper 32 bits are reserved for use by the kernel and will be overwritten before a MAD is sent. +P_Key Index Handling + + The old ib_umad interface did not allow setting the P_Key index for + MADs that are sent and did not provide a way for obtaining the P_Key + index of received MADs. A new layout for struct ib_user_mad_hdr + with a pkey_index member has been defined; however, to preserve + binary compatibility with older applications, this new layout will + not be used unless the IB_USER_MAD_ENABLE_PKEY ioctl is called + before a file descriptor is used for anything else. + + In September 2008, the IB_USER_MAD_ABI_VERSION will be incremented + to 6, the new layout of struct ib_user_mad_hdr will be used by + default, and the IB_USER_MAD_ENABLE_PKEY ioctl will be removed. + Setting IsSM Capability Bit To set the IsSM capability bit for a port, simply open the diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c index d97ded25c4f..aee29139368 100644 --- a/drivers/infiniband/core/user_mad.c +++ b/drivers/infiniband/core/user_mad.c @@ -118,6 +118,8 @@ struct ib_umad_file { wait_queue_head_t recv_wait; struct ib_mad_agent *agent[IB_UMAD_MAX_AGENTS]; int agents_dead; + u8 use_pkey_index; + u8 already_used; }; struct ib_umad_packet { @@ -147,6 +149,12 @@ static void ib_umad_release_dev(struct kref *ref) kfree(dev); } +static int hdr_size(struct ib_umad_file *file) +{ + return file->use_pkey_index ? sizeof (struct ib_user_mad_hdr) : + sizeof (struct ib_user_mad_hdr_old); +} + /* caller must hold port->mutex at least for reading */ static struct ib_mad_agent *__get_agent(struct ib_umad_file *file, int id) { @@ -221,13 +229,13 @@ static void recv_handler(struct ib_mad_agent *agent, packet->length = mad_recv_wc->mad_len; packet->recv_wc = mad_recv_wc; - packet->mad.hdr.status = 0; - packet->mad.hdr.length = sizeof (struct ib_user_mad) + - mad_recv_wc->mad_len; - packet->mad.hdr.qpn = cpu_to_be32(mad_recv_wc->wc->src_qp); - packet->mad.hdr.lid = cpu_to_be16(mad_recv_wc->wc->slid); - packet->mad.hdr.sl = mad_recv_wc->wc->sl; - packet->mad.hdr.path_bits = mad_recv_wc->wc->dlid_path_bits; + packet->mad.hdr.status = 0; + packet->mad.hdr.length = hdr_size(file) + mad_recv_wc->mad_len; + packet->mad.hdr.qpn = cpu_to_be32(mad_recv_wc->wc->src_qp); + packet->mad.hdr.lid = cpu_to_be16(mad_recv_wc->wc->slid); + packet->mad.hdr.sl = mad_recv_wc->wc->sl; + packet->mad.hdr.path_bits = mad_recv_wc->wc->dlid_path_bits; + packet->mad.hdr.pkey_index = mad_recv_wc->wc->pkey_index; packet->mad.hdr.grh_present = !!(mad_recv_wc->wc->wc_flags & IB_WC_GRH); if (packet->mad.hdr.grh_present) { struct ib_ah_attr ah_attr; @@ -253,8 +261,8 @@ err1: ib_free_recv_mad(mad_recv_wc); } -static ssize_t copy_recv_mad(char __user *buf, struct ib_umad_packet *packet, - size_t count) +static ssize_t copy_recv_mad(struct ib_umad_file *file, char __user *buf, + struct ib_umad_packet *packet, size_t count) { struct ib_mad_recv_buf *recv_buf; int left, seg_payload, offset, max_seg_payload; @@ -262,15 +270,15 @@ static ssize_t copy_recv_mad(char __user *buf, struct ib_umad_packet *packet, /* We need enough room to copy the first (or only) MAD segment. */ recv_buf = &packet->recv_wc->recv_buf; if ((packet->length <= sizeof (*recv_buf->mad) && - count < sizeof (packet->mad) + packet->length) || + count < hdr_size(file) + packet->length) || (packet->length > sizeof (*recv_buf->mad) && - count < sizeof (packet->mad) + sizeof (*recv_buf->mad))) + count < hdr_size(file) + sizeof (*recv_buf->mad))) return -EINVAL; - if (copy_to_user(buf, &packet->mad, sizeof (packet->mad))) + if (copy_to_user(buf, &packet->mad, hdr_size(file))) return -EFAULT; - buf += sizeof (packet->mad); + buf += hdr_size(file); seg_payload = min_t(int, packet->length, sizeof (*recv_buf->mad)); if (copy_to_user(buf, recv_buf->mad, seg_payload)) return -EFAULT; @@ -280,7 +288,7 @@ static ssize_t copy_recv_mad(char __user *buf, struct ib_umad_packet *packet, * Multipacket RMPP MAD message. Copy remainder of message. * Note that last segment may have a shorter payload. */ - if (count < sizeof (packet->mad) + packet->length) { + if (count < hdr_size(file) + packet->length) { /* * The buffer is too small, return the first RMPP segment, * which includes the RMPP message length. @@ -300,18 +308,23 @@ static ssize_t copy_recv_mad(char __user *buf, struct ib_umad_packet *packet, return -EFAULT; } } - return sizeof (packet->mad) + packet->length; + return hdr_size(file) + packet->length; } -static ssize_t copy_send_mad(char __user *buf, struct ib_umad_packet *packet, - size_t count) +static ssize_t copy_send_mad(struct ib_umad_file *file, char __user *buf, + struct ib_umad_packet *packet, size_t count) { - ssize_t size = sizeof (packet->mad) + packet->length; + ssize_t size = hdr_size(file) + packet->length; if (count < size) return -EINVAL; - if (copy_to_user(buf, &packet->mad, size)) + if (copy_to_user(buf, &packet->mad, hdr_size(file))) + return -EFAULT; + + buf += hdr_size(file); + + if (copy_to_user(buf, packet->mad.data, packet->length)) return -EFAULT; return size; @@ -324,7 +337,7 @@ static ssize_t ib_umad_read(struct file *filp, char __user *buf, struct ib_umad_packet *packet; ssize_t ret; - if (count < sizeof (struct ib_user_mad)) + if (count < hdr_size(file)) return -EINVAL; spin_lock_irq(&file->recv_lock); @@ -348,9 +361,9 @@ static ssize_t ib_umad_read(struct file *filp, char __user *buf, spin_unlock_irq(&file->recv_lock); if (packet->recv_wc) - ret = copy_recv_mad(buf, packet, count); + ret = copy_recv_mad(file, buf, packet, count); else - ret = copy_send_mad(buf, packet, count); + ret = copy_send_mad(file, buf, packet, count); if (ret < 0) { /* Requeue packet */ @@ -442,15 +455,14 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, __be64 *tid; int ret, data_len, hdr_len, copy_offset, rmpp_active; - if (count < sizeof (struct ib_user_mad) + IB_MGMT_RMPP_HDR) + if (count < hdr_size(file) + IB_MGMT_RMPP_HDR) return -EINVAL; packet = kzalloc(sizeof *packet + IB_MGMT_RMPP_HDR, GFP_KERNEL); if (!packet) return -ENOMEM; - if (copy_from_user(&packet->mad, buf, - sizeof (struct ib_user_mad) + IB_MGMT_RMPP_HDR)) { + if (copy_from_user(&packet->mad, buf, hdr_size(file))) { ret = -EFAULT; goto err; } @@ -461,6 +473,13 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, goto err; } + buf += hdr_size(file); + + if (copy_from_user(packet->mad.data, buf, IB_MGMT_RMPP_HDR)) { + ret = -EFAULT; + goto err; + } + down_read(&file->port->mutex); agent = __get_agent(file, packet->mad.hdr.id); @@ -500,11 +519,11 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, IB_MGMT_RMPP_FLAG_ACTIVE; } - data_len = count - sizeof (struct ib_user_mad) - hdr_len; + data_len = count - hdr_size(file) - hdr_len; packet->msg = ib_create_send_mad(agent, be32_to_cpu(packet->mad.hdr.qpn), - 0, rmpp_active, hdr_len, - data_len, GFP_KERNEL); + packet->mad.hdr.pkey_index, rmpp_active, + hdr_len, data_len, GFP_KERNEL); if (IS_ERR(packet->msg)) { ret = PTR_ERR(packet->msg); goto err_ah; @@ -517,7 +536,6 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, /* Copy MAD header. Any RMPP header is already in place. */ memcpy(packet->msg->mad, packet->mad.data, IB_MGMT_MAD_HDR); - buf += sizeof (struct ib_user_mad); if (!rmpp_active) { if (copy_from_user(packet->msg->mad + copy_offset, @@ -646,6 +664,16 @@ found: goto out; } + if (!file->already_used) { + file->already_used = 1; + if (!file->use_pkey_index) { + printk(KERN_WARNING "user_mad: process %s did not enable " + "P_Key index support.\n", current->comm); + printk(KERN_WARNING "user_mad: Documentation/infiniband/user_mad.txt " + "has info on the new ABI.\n"); + } + } + file->agent[agent_id] = agent; ret = 0; @@ -682,6 +710,20 @@ out: return ret; } +static long ib_umad_enable_pkey(struct ib_umad_file *file) +{ + int ret = 0; + + down_write(&file->port->mutex); + if (file->already_used) + ret = -EINVAL; + else + file->use_pkey_index = 1; + up_write(&file->port->mutex); + + return ret; +} + static long ib_umad_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { @@ -690,6 +732,8 @@ static long ib_umad_ioctl(struct file *filp, unsigned int cmd, return ib_umad_reg_agent(filp->private_data, arg); case IB_USER_MAD_UNREGISTER_AGENT: return ib_umad_unreg_agent(filp->private_data, arg); + case IB_USER_MAD_ENABLE_PKEY: + return ib_umad_enable_pkey(filp->private_data); default: return -ENOIOCTLCMD; } diff --git a/include/rdma/ib_user_mad.h b/include/rdma/ib_user_mad.h index d66b15ea82c..2a32043d1ab 100644 --- a/include/rdma/ib_user_mad.h +++ b/include/rdma/ib_user_mad.h @@ -51,8 +51,51 @@ * avoid incompatibility between 32-bit userspace and 64-bit kernels). */ +/** + * ib_user_mad_hdr_old - Old version of MAD packet header without pkey_index + * @id - ID of agent MAD received with/to be sent with + * @status - 0 on successful receive, ETIMEDOUT if no response + * received (transaction ID in data[] will be set to TID of original + * request) (ignored on send) + * @timeout_ms - Milliseconds to wait for response (unset on receive) + * @retries - Number of automatic retries to attempt + * @qpn - Remote QP number received from/to be sent to + * @qkey - Remote Q_Key to be sent with (unset on receive) + * @lid - Remote lid received from/to be sent to + * @sl - Service level received with/to be sent with + * @path_bits - Local path bits received with/to be sent with + * @grh_present - If set, GRH was received/should be sent + * @gid_index - Local GID index to send with (unset on receive) + * @hop_limit - Hop limit in GRH + * @traffic_class - Traffic class in GRH + * @gid - Remote GID in GRH + * @flow_label - Flow label in GRH + */ +struct ib_user_mad_hdr_old { + __u32 id; + __u32 status; + __u32 timeout_ms; + __u32 retries; + __u32 length; + __be32 qpn; + __be32 qkey; + __be16 lid; + __u8 sl; + __u8 path_bits; + __u8 grh_present; + __u8 gid_index; + __u8 hop_limit; + __u8 traffic_class; + __u8 gid[16]; + __be32 flow_label; +}; + /** * ib_user_mad_hdr - MAD packet header + * This layout allows specifying/receiving the P_Key index. To use + * this capability, an application must call the + * IB_USER_MAD_ENABLE_PKEY ioctl on the user MAD file handle before + * any other actions with the file handle. * @id - ID of agent MAD received with/to be sent with * @status - 0 on successful receive, ETIMEDOUT if no response * received (transaction ID in data[] will be set to TID of original @@ -70,6 +113,7 @@ * @traffic_class - Traffic class in GRH * @gid - Remote GID in GRH * @flow_label - Flow label in GRH + * @pkey_index - P_Key index */ struct ib_user_mad_hdr { __u32 id; @@ -88,6 +132,8 @@ struct ib_user_mad_hdr { __u8 traffic_class; __u8 gid[16]; __be32 flow_label; + __u16 pkey_index; + __u8 reserved[6]; }; /** @@ -134,4 +180,6 @@ struct ib_user_mad_reg_req { #define IB_USER_MAD_UNREGISTER_AGENT _IOW(IB_IOCTL_MAGIC, 2, __u32) +#define IB_USER_MAD_ENABLE_PKEY _IO(IB_IOCTL_MAGIC, 3) + #endif /* IB_USER_MAD_H */ -- cgit v1.2.3-70-g09d2 From a394f83bdfec10b09d8cb111e622556b2e6fd0de Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 9 Oct 2007 19:59:15 -0700 Subject: IB/umad: Fix bit ordering and 32-on-64 problems on big endian systems The declaration of struct ib_user_mad_reg_req.method_mask[] exported to userspace was an array of __u32, but the kernel internally treated it as a bitmap made up of longs. This makes a difference for 64-bit big-endian kernels, where numbering the bits in an array of__u32 gives: |31.....0|63....31|95....64|127...96| while numbering the bits in an array of longs gives: |63..............0|127............64| 64-bit userspace can handle this by just treating method_mask[] as an array of longs, but 32-bit userspace is really stuck: the meaning of the bits in method_mask[] depends on whether the kernel is 32-bit or 64-bit, and there's no sane way for userspace to know that. Fix this by updating to make it clear that method_mask[] is an array of longs, and using a compat_ioctl method to convert to an array of 64-bit longs to handle the 32-on-64 problem. This fixes the interface description to match existing behavior (so working binaries continue to work) in almost all situations, and gives consistent semantics in the case of 32-bit userspace that can run on either a 32-bit or 64-bit kernel, so that the same binary can work for both 32-on-32 and 32-on-64 systems. Signed-off-by: Roland Dreier --- drivers/infiniband/core/user_mad.c | 49 +++++++++++++++++++++++++++++++------- include/rdma/ib_user_mad.h | 22 ++++++++++++++++- 2 files changed, 61 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c index aee29139368..b53eac4611d 100644 --- a/drivers/infiniband/core/user_mad.c +++ b/drivers/infiniband/core/user_mad.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -607,7 +608,8 @@ static unsigned int ib_umad_poll(struct file *filp, struct poll_table_struct *wa return mask; } -static int ib_umad_reg_agent(struct ib_umad_file *file, unsigned long arg) +static int ib_umad_reg_agent(struct ib_umad_file *file, void __user *arg, + int compat_method_mask) { struct ib_user_mad_reg_req ureq; struct ib_mad_reg_req req; @@ -622,7 +624,7 @@ static int ib_umad_reg_agent(struct ib_umad_file *file, unsigned long arg) goto out; } - if (copy_from_user(&ureq, (void __user *) arg, sizeof ureq)) { + if (copy_from_user(&ureq, arg, sizeof ureq)) { ret = -EFAULT; goto out; } @@ -643,8 +645,18 @@ found: if (ureq.mgmt_class) { req.mgmt_class = ureq.mgmt_class; req.mgmt_class_version = ureq.mgmt_class_version; - memcpy(req.method_mask, ureq.method_mask, sizeof req.method_mask); - memcpy(req.oui, ureq.oui, sizeof req.oui); + memcpy(req.oui, ureq.oui, sizeof req.oui); + + if (compat_method_mask) { + u32 *umm = (u32 *) ureq.method_mask; + int i; + + for (i = 0; i < BITS_TO_LONGS(IB_MGMT_MAX_METHODS); ++i) + req.method_mask[i] = + umm[i * 2] | ((u64) umm[i * 2 + 1] << 32); + } else + memcpy(req.method_mask, ureq.method_mask, + sizeof req.method_mask); } agent = ib_register_mad_agent(file->port->ib_dev, file->port->port_num, @@ -682,13 +694,13 @@ out: return ret; } -static int ib_umad_unreg_agent(struct ib_umad_file *file, unsigned long arg) +static int ib_umad_unreg_agent(struct ib_umad_file *file, u32 __user *arg) { struct ib_mad_agent *agent = NULL; u32 id; int ret = 0; - if (get_user(id, (u32 __user *) arg)) + if (get_user(id, arg)) return -EFAULT; down_write(&file->port->mutex); @@ -729,9 +741,9 @@ static long ib_umad_ioctl(struct file *filp, unsigned int cmd, { switch (cmd) { case IB_USER_MAD_REGISTER_AGENT: - return ib_umad_reg_agent(filp->private_data, arg); + return ib_umad_reg_agent(filp->private_data, (void __user *) arg, 0); case IB_USER_MAD_UNREGISTER_AGENT: - return ib_umad_unreg_agent(filp->private_data, arg); + return ib_umad_unreg_agent(filp->private_data, (__u32 __user *) arg); case IB_USER_MAD_ENABLE_PKEY: return ib_umad_enable_pkey(filp->private_data); default: @@ -739,6 +751,23 @@ static long ib_umad_ioctl(struct file *filp, unsigned int cmd, } } +#ifdef CONFIG_COMPAT +static long ib_umad_compat_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + switch (cmd) { + case IB_USER_MAD_REGISTER_AGENT: + return ib_umad_reg_agent(filp->private_data, compat_ptr(arg), 1); + case IB_USER_MAD_UNREGISTER_AGENT: + return ib_umad_unreg_agent(filp->private_data, compat_ptr(arg)); + case IB_USER_MAD_ENABLE_PKEY: + return ib_umad_enable_pkey(filp->private_data); + default: + return -ENOIOCTLCMD; + } +} +#endif + static int ib_umad_open(struct inode *inode, struct file *filp) { struct ib_umad_port *port; @@ -826,7 +855,9 @@ static const struct file_operations umad_fops = { .write = ib_umad_write, .poll = ib_umad_poll, .unlocked_ioctl = ib_umad_ioctl, - .compat_ioctl = ib_umad_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = ib_umad_compat_ioctl, +#endif .open = ib_umad_open, .release = ib_umad_close }; diff --git a/include/rdma/ib_user_mad.h b/include/rdma/ib_user_mad.h index 2a32043d1ab..29d2c7205a9 100644 --- a/include/rdma/ib_user_mad.h +++ b/include/rdma/ib_user_mad.h @@ -147,6 +147,26 @@ struct ib_user_mad { __u64 data[0]; }; +/* + * Earlier versions of this interface definition declared the + * method_mask[] member as an array of __u32 but treated it as a + * bitmap made up of longs in the kernel. This ambiguity meant that + * 32-bit big-endian applications that can run on both 32-bit and + * 64-bit kernels had no consistent ABI to rely on, and 64-bit + * big-endian applications that treated method_mask as being made up + * of 32-bit words would have their bitmap misinterpreted. + * + * To clear up this confusion, we change the declaration of + * method_mask[] to use unsigned long and handle the conversion from + * 32-bit userspace to 64-bit kernel for big-endian systems in the + * compat_ioctl method. Unfortunately, to keep the structure layout + * the same, we need the method_mask[] array to be aligned only to 4 + * bytes even when long is 64 bits, which forces us into this ugly + * typedef. + */ +typedef unsigned long __attribute__((aligned(4))) packed_ulong; +#define IB_USER_MAD_LONGS_PER_METHOD_MASK (128 / (8 * sizeof (long))) + /** * ib_user_mad_reg_req - MAD registration request * @id - Set by the kernel; used to identify agent in future requests. @@ -165,7 +185,7 @@ struct ib_user_mad { */ struct ib_user_mad_reg_req { __u32 id; - __u32 method_mask[4]; + packed_ulong method_mask[IB_USER_MAD_LONGS_PER_METHOD_MASK]; __u8 qpn; __u8 mgmt_class; __u8 mgmt_class_version; -- cgit v1.2.3-70-g09d2 From 04d29b0ede242000b24cfc34cc78fbd164c47e1a Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 9 Oct 2007 19:59:15 -0700 Subject: IB/uverbs: Make ib_uverbs_release_event_file() static ib_uverbs_release_event_file() is only used in uverbs_main.c, so make it static to that file. Also move the definition before the first use, so a forward declaration is not needed. Signed-off-by: Roland Dreier --- drivers/infiniband/core/uverbs.h | 1 - drivers/infiniband/core/uverbs_main.c | 16 ++++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h index c33546f9e96..c75eb6c9bd4 100644 --- a/drivers/infiniband/core/uverbs.h +++ b/drivers/infiniband/core/uverbs.h @@ -148,7 +148,6 @@ void idr_remove_uobj(struct idr *idp, struct ib_uobject *uobj); struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file, int is_async, int *fd); -void ib_uverbs_release_event_file(struct kref *ref); struct ib_uverbs_event_file *ib_uverbs_lookup_comp_file(int fd); void ib_uverbs_release_ucq(struct ib_uverbs_file *file, diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 14d7ccd8919..7c2ac390558 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -125,6 +125,14 @@ static void ib_uverbs_release_dev(struct kref *ref) complete(&dev->comp); } +static void ib_uverbs_release_event_file(struct kref *ref) +{ + struct ib_uverbs_event_file *file = + container_of(ref, struct ib_uverbs_event_file, ref); + + kfree(file); +} + void ib_uverbs_release_ucq(struct ib_uverbs_file *file, struct ib_uverbs_event_file *ev_file, struct ib_ucq_object *uobj) @@ -331,14 +339,6 @@ static unsigned int ib_uverbs_event_poll(struct file *filp, return pollflags; } -void ib_uverbs_release_event_file(struct kref *ref) -{ - struct ib_uverbs_event_file *file = - container_of(ref, struct ib_uverbs_event_file, ref); - - kfree(file); -} - static int ib_uverbs_event_fasync(int fd, struct file *filp, int on) { struct ib_uverbs_event_file *file = filp->private_data; -- cgit v1.2.3-70-g09d2 From 5b0bf5e25efea77103b0ac7c8057cd56c778ef41 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Wed, 1 Aug 2007 12:28:20 +0300 Subject: mlx4_core: Support ICM tables in coherent memory Enable having ICM tables in coherent memory, and use coherent memory for the dMPT table. This will allow writing MPT entries for MRs both via the SW2HW_MPT command and also directly by the driver for FMR remapping without needing to flush or worry about cacheline boundaries. Signed-off-by: Jack Morgenstein Signed-off-by: Michael S. Tsirkin Signed-off-by: Roland Dreier --- drivers/net/mlx4/icm.c | 113 +++++++++++++++++++++++++++++++++++++----------- drivers/net/mlx4/icm.h | 7 +-- drivers/net/mlx4/main.c | 40 ++++++++--------- drivers/net/mlx4/mlx4.h | 1 + 4 files changed, 112 insertions(+), 49 deletions(-) (limited to 'drivers') diff --git a/drivers/net/mlx4/icm.c b/drivers/net/mlx4/icm.c index b7a4aa8476f..250e2488757 100644 --- a/drivers/net/mlx4/icm.c +++ b/drivers/net/mlx4/icm.c @@ -34,6 +34,7 @@ #include #include #include +#include #include @@ -50,19 +51,41 @@ enum { MLX4_TABLE_CHUNK_SIZE = 1 << 18 }; -void mlx4_free_icm(struct mlx4_dev *dev, struct mlx4_icm *icm) +static void mlx4_free_icm_pages(struct mlx4_dev *dev, struct mlx4_icm_chunk *chunk) { - struct mlx4_icm_chunk *chunk, *tmp; int i; - list_for_each_entry_safe(chunk, tmp, &icm->chunk_list, list) { - if (chunk->nsg > 0) - pci_unmap_sg(dev->pdev, chunk->mem, chunk->npages, - PCI_DMA_BIDIRECTIONAL); + if (chunk->nsg > 0) + pci_unmap_sg(dev->pdev, chunk->mem, chunk->npages, + PCI_DMA_BIDIRECTIONAL); + + for (i = 0; i < chunk->npages; ++i) + __free_pages(chunk->mem[i].page, + get_order(chunk->mem[i].length)); +} - for (i = 0; i < chunk->npages; ++i) - __free_pages(chunk->mem[i].page, - get_order(chunk->mem[i].length)); +static void mlx4_free_icm_coherent(struct mlx4_dev *dev, struct mlx4_icm_chunk *chunk) +{ + int i; + + for (i = 0; i < chunk->npages; ++i) + dma_free_coherent(&dev->pdev->dev, chunk->mem[i].length, + lowmem_page_address(chunk->mem[i].page), + sg_dma_address(&chunk->mem[i])); +} + +void mlx4_free_icm(struct mlx4_dev *dev, struct mlx4_icm *icm, int coherent) +{ + struct mlx4_icm_chunk *chunk, *tmp; + + if (!icm) + return; + + list_for_each_entry_safe(chunk, tmp, &icm->chunk_list, list) { + if (coherent) + mlx4_free_icm_coherent(dev, chunk); + else + mlx4_free_icm_pages(dev, chunk); kfree(chunk); } @@ -70,16 +93,45 @@ void mlx4_free_icm(struct mlx4_dev *dev, struct mlx4_icm *icm) kfree(icm); } +static int mlx4_alloc_icm_pages(struct scatterlist *mem, int order, gfp_t gfp_mask) +{ + mem->page = alloc_pages(gfp_mask, order); + if (!mem->page) + return -ENOMEM; + + mem->length = PAGE_SIZE << order; + mem->offset = 0; + return 0; +} + +static int mlx4_alloc_icm_coherent(struct device *dev, struct scatterlist *mem, + int order, gfp_t gfp_mask) +{ + void *buf = dma_alloc_coherent(dev, PAGE_SIZE << order, + &sg_dma_address(mem), gfp_mask); + if (!buf) + return -ENOMEM; + + sg_set_buf(mem, buf, PAGE_SIZE << order); + BUG_ON(mem->offset); + sg_dma_len(mem) = PAGE_SIZE << order; + return 0; +} + struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages, - gfp_t gfp_mask) + gfp_t gfp_mask, int coherent) { struct mlx4_icm *icm; struct mlx4_icm_chunk *chunk = NULL; int cur_order; + int ret; + + /* We use sg_set_buf for coherent allocs, which assumes low memory */ + BUG_ON(coherent && (gfp_mask & __GFP_HIGHMEM)); icm = kmalloc(sizeof *icm, gfp_mask & ~(__GFP_HIGHMEM | __GFP_NOWARN)); if (!icm) - return icm; + return NULL; icm->refcount = 0; INIT_LIST_HEAD(&icm->chunk_list); @@ -101,12 +153,20 @@ struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages, while (1 << cur_order > npages) --cur_order; - chunk->mem[chunk->npages].page = alloc_pages(gfp_mask, cur_order); - if (chunk->mem[chunk->npages].page) { - chunk->mem[chunk->npages].length = PAGE_SIZE << cur_order; - chunk->mem[chunk->npages].offset = 0; + if (coherent) + ret = mlx4_alloc_icm_coherent(&dev->pdev->dev, + &chunk->mem[chunk->npages], + cur_order, gfp_mask); + else + ret = mlx4_alloc_icm_pages(&chunk->mem[chunk->npages], + cur_order, gfp_mask); + + if (!ret) { + ++chunk->npages; - if (++chunk->npages == MLX4_ICM_CHUNK_LEN) { + if (coherent) + ++chunk->nsg; + else if (chunk->npages == MLX4_ICM_CHUNK_LEN) { chunk->nsg = pci_map_sg(dev->pdev, chunk->mem, chunk->npages, PCI_DMA_BIDIRECTIONAL); @@ -125,7 +185,7 @@ struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages, } } - if (chunk) { + if (!coherent && chunk) { chunk->nsg = pci_map_sg(dev->pdev, chunk->mem, chunk->npages, PCI_DMA_BIDIRECTIONAL); @@ -137,7 +197,7 @@ struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages, return icm; fail: - mlx4_free_icm(dev, icm); + mlx4_free_icm(dev, icm, coherent); return NULL; } @@ -202,7 +262,7 @@ int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj) table->icm[i] = mlx4_alloc_icm(dev, MLX4_TABLE_CHUNK_SIZE >> PAGE_SHIFT, (table->lowmem ? GFP_KERNEL : GFP_HIGHUSER) | - __GFP_NOWARN); + __GFP_NOWARN, table->coherent); if (!table->icm[i]) { ret = -ENOMEM; goto out; @@ -210,7 +270,7 @@ int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj) if (mlx4_MAP_ICM(dev, table->icm[i], table->virt + (u64) i * MLX4_TABLE_CHUNK_SIZE)) { - mlx4_free_icm(dev, table->icm[i]); + mlx4_free_icm(dev, table->icm[i], table->coherent); table->icm[i] = NULL; ret = -ENOMEM; goto out; @@ -234,7 +294,7 @@ void mlx4_table_put(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj) if (--table->icm[i]->refcount == 0) { mlx4_UNMAP_ICM(dev, table->virt + i * MLX4_TABLE_CHUNK_SIZE, MLX4_TABLE_CHUNK_SIZE / MLX4_ICM_PAGE_SIZE); - mlx4_free_icm(dev, table->icm[i]); + mlx4_free_icm(dev, table->icm[i], table->coherent); table->icm[i] = NULL; } @@ -309,7 +369,7 @@ void mlx4_table_put_range(struct mlx4_dev *dev, struct mlx4_icm_table *table, int mlx4_init_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table, u64 virt, int obj_size, int nobj, int reserved, - int use_lowmem) + int use_lowmem, int use_coherent) { int obj_per_chunk; int num_icm; @@ -327,6 +387,7 @@ int mlx4_init_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table, table->num_obj = nobj; table->obj_size = obj_size; table->lowmem = use_lowmem; + table->coherent = use_coherent; mutex_init(&table->mutex); for (i = 0; i * MLX4_TABLE_CHUNK_SIZE < reserved * obj_size; ++i) { @@ -336,11 +397,11 @@ int mlx4_init_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table, table->icm[i] = mlx4_alloc_icm(dev, chunk_size >> PAGE_SHIFT, (use_lowmem ? GFP_KERNEL : GFP_HIGHUSER) | - __GFP_NOWARN); + __GFP_NOWARN, use_coherent); if (!table->icm[i]) goto err; if (mlx4_MAP_ICM(dev, table->icm[i], virt + i * MLX4_TABLE_CHUNK_SIZE)) { - mlx4_free_icm(dev, table->icm[i]); + mlx4_free_icm(dev, table->icm[i], use_coherent); table->icm[i] = NULL; goto err; } @@ -359,7 +420,7 @@ err: if (table->icm[i]) { mlx4_UNMAP_ICM(dev, virt + i * MLX4_TABLE_CHUNK_SIZE, MLX4_TABLE_CHUNK_SIZE / MLX4_ICM_PAGE_SIZE); - mlx4_free_icm(dev, table->icm[i]); + mlx4_free_icm(dev, table->icm[i], use_coherent); } return -ENOMEM; @@ -373,7 +434,7 @@ void mlx4_cleanup_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table) if (table->icm[i]) { mlx4_UNMAP_ICM(dev, table->virt + i * MLX4_TABLE_CHUNK_SIZE, MLX4_TABLE_CHUNK_SIZE / MLX4_ICM_PAGE_SIZE); - mlx4_free_icm(dev, table->icm[i]); + mlx4_free_icm(dev, table->icm[i], table->coherent); } kfree(table->icm); diff --git a/drivers/net/mlx4/icm.h b/drivers/net/mlx4/icm.h index bea223d879a..a77db6de859 100644 --- a/drivers/net/mlx4/icm.h +++ b/drivers/net/mlx4/icm.h @@ -67,8 +67,9 @@ struct mlx4_icm_iter { struct mlx4_dev; -struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages, gfp_t gfp_mask); -void mlx4_free_icm(struct mlx4_dev *dev, struct mlx4_icm *icm); +struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages, + gfp_t gfp_mask, int coherent); +void mlx4_free_icm(struct mlx4_dev *dev, struct mlx4_icm *icm, int coherent); int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj); void mlx4_table_put(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj); @@ -78,7 +79,7 @@ void mlx4_table_put_range(struct mlx4_dev *dev, struct mlx4_icm_table *table, int start, int end); int mlx4_init_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table, u64 virt, int obj_size, int nobj, int reserved, - int use_lowmem); + int use_lowmem, int use_coherent); void mlx4_cleanup_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table); int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj); void mlx4_table_put(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj); diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c index 9e590e11c1c..07c2847a7cc 100644 --- a/drivers/net/mlx4/main.c +++ b/drivers/net/mlx4/main.c @@ -168,7 +168,7 @@ static int __devinit mlx4_load_fw(struct mlx4_dev *dev) int err; priv->fw.fw_icm = mlx4_alloc_icm(dev, priv->fw.fw_pages, - GFP_HIGHUSER | __GFP_NOWARN); + GFP_HIGHUSER | __GFP_NOWARN, 0); if (!priv->fw.fw_icm) { mlx4_err(dev, "Couldn't allocate FW area, aborting.\n"); return -ENOMEM; @@ -192,7 +192,7 @@ err_unmap_fa: mlx4_UNMAP_FA(dev); err_free: - mlx4_free_icm(dev, priv->fw.fw_icm); + mlx4_free_icm(dev, priv->fw.fw_icm, 0); return err; } @@ -207,7 +207,7 @@ static int __devinit mlx4_init_cmpt_table(struct mlx4_dev *dev, u64 cmpt_base, ((u64) (MLX4_CMPT_TYPE_QP * cmpt_entry_sz) << MLX4_CMPT_SHIFT), cmpt_entry_sz, dev->caps.num_qps, - dev->caps.reserved_qps, 0); + dev->caps.reserved_qps, 0, 0); if (err) goto err; @@ -216,7 +216,7 @@ static int __devinit mlx4_init_cmpt_table(struct mlx4_dev *dev, u64 cmpt_base, ((u64) (MLX4_CMPT_TYPE_SRQ * cmpt_entry_sz) << MLX4_CMPT_SHIFT), cmpt_entry_sz, dev->caps.num_srqs, - dev->caps.reserved_srqs, 0); + dev->caps.reserved_srqs, 0, 0); if (err) goto err_qp; @@ -225,7 +225,7 @@ static int __devinit mlx4_init_cmpt_table(struct mlx4_dev *dev, u64 cmpt_base, ((u64) (MLX4_CMPT_TYPE_CQ * cmpt_entry_sz) << MLX4_CMPT_SHIFT), cmpt_entry_sz, dev->caps.num_cqs, - dev->caps.reserved_cqs, 0); + dev->caps.reserved_cqs, 0, 0); if (err) goto err_srq; @@ -236,7 +236,7 @@ static int __devinit mlx4_init_cmpt_table(struct mlx4_dev *dev, u64 cmpt_base, cmpt_entry_sz, roundup_pow_of_two(MLX4_NUM_EQ + dev->caps.reserved_eqs), - MLX4_NUM_EQ + dev->caps.reserved_eqs, 0); + MLX4_NUM_EQ + dev->caps.reserved_eqs, 0, 0); if (err) goto err_cq; @@ -275,7 +275,7 @@ static int __devinit mlx4_init_icm(struct mlx4_dev *dev, (unsigned long long) aux_pages << 2); priv->fw.aux_icm = mlx4_alloc_icm(dev, aux_pages, - GFP_HIGHUSER | __GFP_NOWARN); + GFP_HIGHUSER | __GFP_NOWARN, 0); if (!priv->fw.aux_icm) { mlx4_err(dev, "Couldn't allocate aux memory, aborting.\n"); return -ENOMEM; @@ -303,7 +303,7 @@ static int __devinit mlx4_init_icm(struct mlx4_dev *dev, init_hca->mtt_base, dev->caps.mtt_entry_sz, dev->caps.num_mtt_segs, - dev->caps.reserved_mtts, 1); + dev->caps.reserved_mtts, 1, 0); if (err) { mlx4_err(dev, "Failed to map MTT context memory, aborting.\n"); goto err_unmap_eq; @@ -313,7 +313,7 @@ static int __devinit mlx4_init_icm(struct mlx4_dev *dev, init_hca->dmpt_base, dev_cap->dmpt_entry_sz, dev->caps.num_mpts, - dev->caps.reserved_mrws, 1); + dev->caps.reserved_mrws, 1, 1); if (err) { mlx4_err(dev, "Failed to map dMPT context memory, aborting.\n"); goto err_unmap_mtt; @@ -323,7 +323,7 @@ static int __devinit mlx4_init_icm(struct mlx4_dev *dev, init_hca->qpc_base, dev_cap->qpc_entry_sz, dev->caps.num_qps, - dev->caps.reserved_qps, 0); + dev->caps.reserved_qps, 0, 0); if (err) { mlx4_err(dev, "Failed to map QP context memory, aborting.\n"); goto err_unmap_dmpt; @@ -333,7 +333,7 @@ static int __devinit mlx4_init_icm(struct mlx4_dev *dev, init_hca->auxc_base, dev_cap->aux_entry_sz, dev->caps.num_qps, - dev->caps.reserved_qps, 0); + dev->caps.reserved_qps, 0, 0); if (err) { mlx4_err(dev, "Failed to map AUXC context memory, aborting.\n"); goto err_unmap_qp; @@ -343,7 +343,7 @@ static int __devinit mlx4_init_icm(struct mlx4_dev *dev, init_hca->altc_base, dev_cap->altc_entry_sz, dev->caps.num_qps, - dev->caps.reserved_qps, 0); + dev->caps.reserved_qps, 0, 0); if (err) { mlx4_err(dev, "Failed to map ALTC context memory, aborting.\n"); goto err_unmap_auxc; @@ -353,7 +353,7 @@ static int __devinit mlx4_init_icm(struct mlx4_dev *dev, init_hca->rdmarc_base, dev_cap->rdmarc_entry_sz << priv->qp_table.rdmarc_shift, dev->caps.num_qps, - dev->caps.reserved_qps, 0); + dev->caps.reserved_qps, 0, 0); if (err) { mlx4_err(dev, "Failed to map RDMARC context memory, aborting\n"); goto err_unmap_altc; @@ -363,7 +363,7 @@ static int __devinit mlx4_init_icm(struct mlx4_dev *dev, init_hca->cqc_base, dev_cap->cqc_entry_sz, dev->caps.num_cqs, - dev->caps.reserved_cqs, 0); + dev->caps.reserved_cqs, 0, 0); if (err) { mlx4_err(dev, "Failed to map CQ context memory, aborting.\n"); goto err_unmap_rdmarc; @@ -373,7 +373,7 @@ static int __devinit mlx4_init_icm(struct mlx4_dev *dev, init_hca->srqc_base, dev_cap->srq_entry_sz, dev->caps.num_srqs, - dev->caps.reserved_srqs, 0); + dev->caps.reserved_srqs, 0, 0); if (err) { mlx4_err(dev, "Failed to map SRQ context memory, aborting.\n"); goto err_unmap_cq; @@ -388,7 +388,7 @@ static int __devinit mlx4_init_icm(struct mlx4_dev *dev, init_hca->mc_base, MLX4_MGM_ENTRY_SIZE, dev->caps.num_mgms + dev->caps.num_amgms, dev->caps.num_mgms + dev->caps.num_amgms, - 0); + 0, 0); if (err) { mlx4_err(dev, "Failed to map MCG context memory, aborting.\n"); goto err_unmap_srq; @@ -433,7 +433,7 @@ err_unmap_aux: mlx4_UNMAP_ICM_AUX(dev); err_free_aux: - mlx4_free_icm(dev, priv->fw.aux_icm); + mlx4_free_icm(dev, priv->fw.aux_icm, 0); return err; } @@ -458,7 +458,7 @@ static void mlx4_free_icms(struct mlx4_dev *dev) mlx4_unmap_eq_icm(dev); mlx4_UNMAP_ICM_AUX(dev); - mlx4_free_icm(dev, priv->fw.aux_icm); + mlx4_free_icm(dev, priv->fw.aux_icm, 0); } static void mlx4_close_hca(struct mlx4_dev *dev) @@ -466,7 +466,7 @@ static void mlx4_close_hca(struct mlx4_dev *dev) mlx4_CLOSE_HCA(dev, 0); mlx4_free_icms(dev); mlx4_UNMAP_FA(dev); - mlx4_free_icm(dev, mlx4_priv(dev)->fw.fw_icm); + mlx4_free_icm(dev, mlx4_priv(dev)->fw.fw_icm, 0); } static int __devinit mlx4_init_hca(struct mlx4_dev *dev) @@ -537,7 +537,7 @@ err_free_icm: err_stop_fw: mlx4_UNMAP_FA(dev); - mlx4_free_icm(dev, priv->fw.fw_icm); + mlx4_free_icm(dev, priv->fw.fw_icm, 0); return err; } diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h index b9f83976191..2bad045b25c 100644 --- a/drivers/net/mlx4/mlx4.h +++ b/drivers/net/mlx4/mlx4.h @@ -129,6 +129,7 @@ struct mlx4_icm_table { int num_obj; int obj_size; int lowmem; + int coherent; struct mutex mutex; struct mlx4_icm **icm; }; -- cgit v1.2.3-70-g09d2 From cf78237d7b0e683d172e40b1e85b26ca49a3cdba Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 9 Oct 2007 19:59:16 -0700 Subject: mlx4_core: Reserve the correct number of MTT segments Taking ilog2(dev->caps.reserved_mtts) to find out the order to pass to the MTT buddy allocator will do the wrong thing if reserved_mtts is ever not a power of 2. Be safe and use fls(dev->caps.reserved_mtts - 1). Signed-off-by: Roland Dreier --- drivers/net/mlx4/mr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/mlx4/mr.c b/drivers/net/mlx4/mr.c index 5b87183e62c..60a6ee27cfd 100644 --- a/drivers/net/mlx4/mr.c +++ b/drivers/net/mlx4/mr.c @@ -444,7 +444,7 @@ int __devinit mlx4_init_mr_table(struct mlx4_dev *dev) goto err_buddy; if (dev->caps.reserved_mtts) { - if (mlx4_alloc_mtt_range(dev, ilog2(dev->caps.reserved_mtts)) == -1) { + if (mlx4_alloc_mtt_range(dev, fls(dev->caps.reserved_mtts - 1)) == -1) { mlx4_warn(dev, "MTT table of order %d is too small.\n", mr_table->mtt_buddy.max_order); err = -ENOMEM; -- cgit v1.2.3-70-g09d2 From 121964ec38d3e17b5ea6183b3c0571df2f4b0eb6 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 9 Oct 2007 19:59:16 -0700 Subject: mlx4_core: Fix meaning of dev->caps.reserved_mtts Everything that uses caps.reserved_mtts expects it to be a count of MTT segments, not MTT entries. So convert the value that the FW gives us to a count of segments. Signed-off-by: Roland Dreier --- drivers/net/mlx4/main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c index 07c2847a7cc..ed7e8d76cde 100644 --- a/drivers/net/mlx4/main.c +++ b/drivers/net/mlx4/main.c @@ -149,7 +149,8 @@ static int __devinit mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev dev->caps.max_cqes = dev_cap->max_cq_sz - 1; dev->caps.reserved_cqs = dev_cap->reserved_cqs; dev->caps.reserved_eqs = dev_cap->reserved_eqs; - dev->caps.reserved_mtts = dev_cap->reserved_mtts; + dev->caps.reserved_mtts = DIV_ROUND_UP(dev_cap->reserved_mtts, + MLX4_MTT_ENTRY_PER_SEG); dev->caps.reserved_mrws = dev_cap->reserved_mrws; dev->caps.reserved_uars = dev_cap->reserved_uars; dev->caps.reserved_pds = dev_cap->reserved_pds; -- cgit v1.2.3-70-g09d2 From d7bb58fb1c0e7264a7261c7d0304121ef9402e94 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Wed, 1 Aug 2007 12:28:53 +0300 Subject: mlx4_core: Write MTTs from CPU instead with of WRITE_MTT FW command Write MTT entries directly to ICM from the driver (eliminating use of WRITE_MTT command). This reduces the number of FW commands needed to register an MR by at least a factor of 2 and speeds up memory registration significantly. This code will also be used to implement FMRs. Signed-off-by: Jack Morgenstein Signed-off-by: Michael S. Tsirkin Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mlx4/mr.c | 7 ++-- drivers/net/mlx4/icm.c | 21 +++++++++--- drivers/net/mlx4/icm.h | 2 +- drivers/net/mlx4/main.c | 11 +++++++ drivers/net/mlx4/mr.c | 73 ++++++++++++++++++++--------------------- 5 files changed, 67 insertions(+), 47 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx4/mr.c b/drivers/infiniband/hw/mlx4/mr.c index 85ae906f1d1..734ec2bd15c 100644 --- a/drivers/infiniband/hw/mlx4/mr.c +++ b/drivers/infiniband/hw/mlx4/mr.c @@ -96,11 +96,10 @@ int mlx4_ib_umem_write_mtt(struct mlx4_ib_dev *dev, struct mlx4_mtt *mtt, pages[i++] = sg_dma_address(&chunk->page_list[j]) + umem->page_size * k; /* - * Be friendly to WRITE_MTT firmware - * command, and pass it chunks of - * appropriate size. + * Be friendly to mlx4_write_mtt() and + * pass it chunks of appropriate size. */ - if (i == PAGE_SIZE / sizeof (u64) - 2) { + if (i == PAGE_SIZE / sizeof (u64)) { err = mlx4_write_mtt(dev->dev, mtt, n, i, pages); if (err) diff --git a/drivers/net/mlx4/icm.c b/drivers/net/mlx4/icm.c index 250e2488757..4b3c109d5ea 100644 --- a/drivers/net/mlx4/icm.c +++ b/drivers/net/mlx4/icm.c @@ -301,9 +301,9 @@ void mlx4_table_put(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj) mutex_unlock(&table->mutex); } -void *mlx4_table_find(struct mlx4_icm_table *table, int obj) +void *mlx4_table_find(struct mlx4_icm_table *table, int obj, dma_addr_t *dma_handle) { - int idx, offset, i; + int idx, offset, dma_offset, i; struct mlx4_icm_chunk *chunk; struct mlx4_icm *icm; struct page *page = NULL; @@ -313,15 +313,26 @@ void *mlx4_table_find(struct mlx4_icm_table *table, int obj) mutex_lock(&table->mutex); - idx = obj & (table->num_obj - 1); - icm = table->icm[idx / (MLX4_TABLE_CHUNK_SIZE / table->obj_size)]; - offset = idx % (MLX4_TABLE_CHUNK_SIZE / table->obj_size); + idx = (obj & (table->num_obj - 1)) * table->obj_size; + icm = table->icm[idx / MLX4_TABLE_CHUNK_SIZE]; + dma_offset = offset = idx % MLX4_TABLE_CHUNK_SIZE; if (!icm) goto out; list_for_each_entry(chunk, &icm->chunk_list, list) { for (i = 0; i < chunk->npages; ++i) { + if (dma_handle && dma_offset >= 0) { + if (sg_dma_len(&chunk->mem[i]) > dma_offset) + *dma_handle = sg_dma_address(&chunk->mem[i]) + + dma_offset; + dma_offset -= sg_dma_len(&chunk->mem[i]); + } + /* + * DMA mapping can merge pages but not split them, + * so if we found the page, dma_handle has already + * been assigned to. + */ if (chunk->mem[i].length > offset) { page = chunk->mem[i].page; goto out; diff --git a/drivers/net/mlx4/icm.h b/drivers/net/mlx4/icm.h index a77db6de859..6c44edf3584 100644 --- a/drivers/net/mlx4/icm.h +++ b/drivers/net/mlx4/icm.h @@ -83,7 +83,7 @@ int mlx4_init_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table, void mlx4_cleanup_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table); int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj); void mlx4_table_put(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj); -void *mlx4_table_find(struct mlx4_icm_table *table, int obj); +void *mlx4_table_find(struct mlx4_icm_table *table, int obj, dma_addr_t *dma_handle); int mlx4_table_get_range(struct mlx4_dev *dev, struct mlx4_icm_table *table, int start, int end); void mlx4_table_put_range(struct mlx4_dev *dev, struct mlx4_icm_table *table, diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c index ed7e8d76cde..478b3ba74ed 100644 --- a/drivers/net/mlx4/main.c +++ b/drivers/net/mlx4/main.c @@ -300,6 +300,17 @@ static int __devinit mlx4_init_icm(struct mlx4_dev *dev, goto err_unmap_cmpt; } + /* + * Reserved MTT entries must be aligned up to a cacheline + * boundary, since the FW will write to them, while the driver + * writes to all other MTT entries. (The variable + * dev->caps.mtt_entry_sz below is really the MTT segment + * size, not the raw entry size) + */ + dev->caps.reserved_mtts = + ALIGN(dev->caps.reserved_mtts * dev->caps.mtt_entry_sz, + dma_get_cache_alignment()) / dev->caps.mtt_entry_sz; + err = mlx4_init_icm_table(dev, &priv->mr_table.mtt_table, init_hca->mtt_base, dev->caps.mtt_entry_sz, diff --git a/drivers/net/mlx4/mr.c b/drivers/net/mlx4/mr.c index 60a6ee27cfd..3cc98c699aa 100644 --- a/drivers/net/mlx4/mr.c +++ b/drivers/net/mlx4/mr.c @@ -349,58 +349,57 @@ err_table: } EXPORT_SYMBOL_GPL(mlx4_mr_enable); -static int mlx4_WRITE_MTT(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, - int num_mtt) +static int mlx4_write_mtt_chunk(struct mlx4_dev *dev, struct mlx4_mtt *mtt, + int start_index, int npages, u64 *page_list) { - return mlx4_cmd(dev, mailbox->dma, num_mtt, 0, MLX4_CMD_WRITE_MTT, - MLX4_CMD_TIME_CLASS_B); + struct mlx4_priv *priv = mlx4_priv(dev); + __be64 *mtts; + dma_addr_t dma_handle; + int i; + int s = start_index * sizeof (u64); + + /* All MTTs must fit in the same page */ + if (start_index / (PAGE_SIZE / sizeof (u64)) != + (start_index + npages - 1) / (PAGE_SIZE / sizeof (u64))) + return -EINVAL; + + if (start_index & (MLX4_MTT_ENTRY_PER_SEG - 1)) + return -EINVAL; + + mtts = mlx4_table_find(&priv->mr_table.mtt_table, mtt->first_seg + + s / dev->caps.mtt_entry_sz, &dma_handle); + if (!mtts) + return -ENOMEM; + + for (i = 0; i < npages; ++i) + mtts[i] = cpu_to_be64(page_list[i] | MLX4_MTT_FLAG_PRESENT); + + dma_sync_single(&dev->pdev->dev, dma_handle, npages * sizeof (u64), DMA_TO_DEVICE); + + return 0; } int mlx4_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt, int start_index, int npages, u64 *page_list) { - struct mlx4_cmd_mailbox *mailbox; - __be64 *mtt_entry; - int i; - int err = 0; + int chunk; + int err; if (mtt->order < 0) return -EINVAL; - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - - mtt_entry = mailbox->buf; - while (npages > 0) { - mtt_entry[0] = cpu_to_be64(mlx4_mtt_addr(dev, mtt) + start_index * 8); - mtt_entry[1] = 0; - - for (i = 0; i < npages && i < MLX4_MAILBOX_SIZE / 8 - 2; ++i) - mtt_entry[i + 2] = cpu_to_be64(page_list[i] | - MLX4_MTT_FLAG_PRESENT); - - /* - * If we have an odd number of entries to write, add - * one more dummy entry for firmware efficiency. - */ - if (i & 1) - mtt_entry[i + 2] = 0; - - err = mlx4_WRITE_MTT(dev, mailbox, (i + 1) & ~1); + chunk = min_t(int, PAGE_SIZE / sizeof(u64), npages); + err = mlx4_write_mtt_chunk(dev, mtt, start_index, chunk, page_list); if (err) - goto out; + return err; - npages -= i; - start_index += i; - page_list += i; + npages -= chunk; + start_index += chunk; + page_list += chunk; } -out: - mlx4_free_cmd_mailbox(dev, mailbox); - - return err; + return 0; } EXPORT_SYMBOL_GPL(mlx4_write_mtt); -- cgit v1.2.3-70-g09d2 From 8ad11fb6b0739e704953e2b0aed453bf7d75d4f6 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Wed, 1 Aug 2007 12:29:05 +0300 Subject: IB/mlx4: Implement FMRs Implement FMRs for mlx4. This is an adaptation of code from mthca. Signed-off-by: Jack Morgenstein Signed-off-by: Michael S. Tsirkin Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mlx4/main.c | 5 ++ drivers/infiniband/hw/mlx4/mlx4_ib.h | 16 ++++ drivers/infiniband/hw/mlx4/mr.c | 93 ++++++++++++++++++++ drivers/net/mlx4/mr.c | 165 +++++++++++++++++++++++++++++++++++ include/linux/mlx4/device.h | 21 +++++ 5 files changed, 300 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index d9fc822a146..d8287d9db41 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -607,6 +607,11 @@ static void *mlx4_ib_add(struct mlx4_dev *dev) ibdev->ib_dev.detach_mcast = mlx4_ib_mcg_detach; ibdev->ib_dev.process_mad = mlx4_ib_process_mad; + ibdev->ib_dev.alloc_fmr = mlx4_ib_fmr_alloc; + ibdev->ib_dev.map_phys_fmr = mlx4_ib_map_phys_fmr; + ibdev->ib_dev.unmap_fmr = mlx4_ib_unmap_fmr; + ibdev->ib_dev.dealloc_fmr = mlx4_ib_fmr_dealloc; + if (init_node_data(ibdev)) goto err_map; diff --git a/drivers/infiniband/hw/mlx4/mlx4_ib.h b/drivers/infiniband/hw/mlx4/mlx4_ib.h index 705ff2fa237..28697653a37 100644 --- a/drivers/infiniband/hw/mlx4/mlx4_ib.h +++ b/drivers/infiniband/hw/mlx4/mlx4_ib.h @@ -93,6 +93,11 @@ struct mlx4_ib_mr { struct ib_umem *umem; }; +struct mlx4_ib_fmr { + struct ib_fmr ibfmr; + struct mlx4_fmr mfmr; +}; + struct mlx4_ib_wq { u64 *wrid; spinlock_t lock; @@ -199,6 +204,10 @@ static inline struct mlx4_ib_mr *to_mmr(struct ib_mr *ibmr) return container_of(ibmr, struct mlx4_ib_mr, ibmr); } +static inline struct mlx4_ib_fmr *to_mfmr(struct ib_fmr *ibfmr) +{ + return container_of(ibfmr, struct mlx4_ib_fmr, ibfmr); +} static inline struct mlx4_ib_qp *to_mqp(struct ib_qp *ibqp) { return container_of(ibqp, struct mlx4_ib_qp, ibqp); @@ -284,6 +293,13 @@ int mlx4_ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num, int mlx4_ib_mad_init(struct mlx4_ib_dev *dev); void mlx4_ib_mad_cleanup(struct mlx4_ib_dev *dev); +struct ib_fmr *mlx4_ib_fmr_alloc(struct ib_pd *pd, int mr_access_flags, + struct ib_fmr_attr *fmr_attr); +int mlx4_ib_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list, int npages, + u64 iova); +int mlx4_ib_unmap_fmr(struct list_head *fmr_list); +int mlx4_ib_fmr_dealloc(struct ib_fmr *fmr); + static inline int mlx4_ib_ah_grh_present(struct mlx4_ib_ah *ah) { return !!(ah->av.g_slid & 0x80); diff --git a/drivers/infiniband/hw/mlx4/mr.c b/drivers/infiniband/hw/mlx4/mr.c index 734ec2bd15c..7dc91a3e712 100644 --- a/drivers/infiniband/hw/mlx4/mr.c +++ b/drivers/infiniband/hw/mlx4/mr.c @@ -181,3 +181,96 @@ int mlx4_ib_dereg_mr(struct ib_mr *ibmr) return 0; } + +struct ib_fmr *mlx4_ib_fmr_alloc(struct ib_pd *pd, int acc, + struct ib_fmr_attr *fmr_attr) +{ + struct mlx4_ib_dev *dev = to_mdev(pd->device); + struct mlx4_ib_fmr *fmr; + int err = -ENOMEM; + + fmr = kmalloc(sizeof *fmr, GFP_KERNEL); + if (!fmr) + return ERR_PTR(-ENOMEM); + + err = mlx4_fmr_alloc(dev->dev, to_mpd(pd)->pdn, convert_access(acc), + fmr_attr->max_pages, fmr_attr->max_maps, + fmr_attr->page_shift, &fmr->mfmr); + if (err) + goto err_free; + + err = mlx4_mr_enable(to_mdev(pd->device)->dev, &fmr->mfmr.mr); + if (err) + goto err_mr; + + fmr->ibfmr.rkey = fmr->ibfmr.lkey = fmr->mfmr.mr.key; + + return &fmr->ibfmr; + +err_mr: + mlx4_mr_free(to_mdev(pd->device)->dev, &fmr->mfmr.mr); + +err_free: + kfree(fmr); + + return ERR_PTR(err); +} + +int mlx4_ib_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list, + int npages, u64 iova) +{ + struct mlx4_ib_fmr *ifmr = to_mfmr(ibfmr); + struct mlx4_ib_dev *dev = to_mdev(ifmr->ibfmr.device); + + return mlx4_map_phys_fmr(dev->dev, &ifmr->mfmr, page_list, npages, iova, + &ifmr->ibfmr.lkey, &ifmr->ibfmr.rkey); +} + +int mlx4_ib_unmap_fmr(struct list_head *fmr_list) +{ + struct ib_fmr *ibfmr; + int err; + struct mlx4_dev *mdev = NULL; + + list_for_each_entry(ibfmr, fmr_list, list) { + if (mdev && to_mdev(ibfmr->device)->dev != mdev) + return -EINVAL; + mdev = to_mdev(ibfmr->device)->dev; + } + + if (!mdev) + return 0; + + list_for_each_entry(ibfmr, fmr_list, list) { + struct mlx4_ib_fmr *ifmr = to_mfmr(ibfmr); + + mlx4_fmr_unmap(mdev, &ifmr->mfmr, &ifmr->ibfmr.lkey, &ifmr->ibfmr.rkey); + } + + /* + * Make sure all MPT status updates are visible before issuing + * SYNC_TPT firmware command. + */ + wmb(); + + err = mlx4_SYNC_TPT(mdev); + if (err) + printk(KERN_WARNING "mlx4_ib: SYNC_TPT error %d when " + "unmapping FMRs\n", err); + + return 0; +} + +int mlx4_ib_fmr_dealloc(struct ib_fmr *ibfmr) +{ + struct mlx4_ib_fmr *ifmr = to_mfmr(ibfmr); + struct mlx4_ib_dev *dev = to_mdev(ibfmr->device); + int err; + + err = mlx4_fmr_free(dev->dev, &ifmr->mfmr); + + if (!err) + kfree(ifmr); + + return err; +} diff --git a/drivers/net/mlx4/mr.c b/drivers/net/mlx4/mr.c index 3cc98c699aa..4bc39e65015 100644 --- a/drivers/net/mlx4/mr.c +++ b/drivers/net/mlx4/mr.c @@ -68,6 +68,9 @@ struct mlx4_mpt_entry { #define MLX4_MTT_FLAG_PRESENT 1 +#define MLX4_MPT_STATUS_SW 0xF0 +#define MLX4_MPT_STATUS_HW 0x00 + static u32 mlx4_buddy_alloc(struct mlx4_buddy *buddy, int order) { int o; @@ -469,3 +472,165 @@ void mlx4_cleanup_mr_table(struct mlx4_dev *dev) mlx4_buddy_cleanup(&mr_table->mtt_buddy); mlx4_bitmap_cleanup(&mr_table->mpt_bitmap); } + +static inline int mlx4_check_fmr(struct mlx4_fmr *fmr, u64 *page_list, + int npages, u64 iova) +{ + int i, page_mask; + + if (npages > fmr->max_pages) + return -EINVAL; + + page_mask = (1 << fmr->page_shift) - 1; + + /* We are getting page lists, so va must be page aligned. */ + if (iova & page_mask) + return -EINVAL; + + /* Trust the user not to pass misaligned data in page_list */ + if (0) + for (i = 0; i < npages; ++i) { + if (page_list[i] & ~page_mask) + return -EINVAL; + } + + if (fmr->maps >= fmr->max_maps) + return -EINVAL; + + return 0; +} + +int mlx4_map_phys_fmr(struct mlx4_dev *dev, struct mlx4_fmr *fmr, u64 *page_list, + int npages, u64 iova, u32 *lkey, u32 *rkey) +{ + u32 key; + int i, err; + + err = mlx4_check_fmr(fmr, page_list, npages, iova); + if (err) + return err; + + ++fmr->maps; + + key = key_to_hw_index(fmr->mr.key); + key += dev->caps.num_mpts; + *lkey = *rkey = fmr->mr.key = hw_index_to_key(key); + + *(u8 *) fmr->mpt = MLX4_MPT_STATUS_SW; + + /* Make sure MPT status is visible before writing MTT entries */ + wmb(); + + for (i = 0; i < npages; ++i) + fmr->mtts[i] = cpu_to_be64(page_list[i] | MLX4_MTT_FLAG_PRESENT); + + dma_sync_single(&dev->pdev->dev, fmr->dma_handle, + npages * sizeof(u64), DMA_TO_DEVICE); + + fmr->mpt->key = cpu_to_be32(key); + fmr->mpt->lkey = cpu_to_be32(key); + fmr->mpt->length = cpu_to_be64(npages * (1ull << fmr->page_shift)); + fmr->mpt->start = cpu_to_be64(iova); + + /* Make MTT entries are visible before setting MPT status */ + wmb(); + + *(u8 *) fmr->mpt = MLX4_MPT_STATUS_HW; + + /* Make sure MPT status is visible before consumer can use FMR */ + wmb(); + + return 0; +} +EXPORT_SYMBOL_GPL(mlx4_map_phys_fmr); + +int mlx4_fmr_alloc(struct mlx4_dev *dev, u32 pd, u32 access, int max_pages, + int max_maps, u8 page_shift, struct mlx4_fmr *fmr) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + u64 mtt_seg; + int err = -ENOMEM; + + if (page_shift < 12 || page_shift >= 32) + return -EINVAL; + + /* All MTTs must fit in the same page */ + if (max_pages * sizeof *fmr->mtts > PAGE_SIZE) + return -EINVAL; + + fmr->page_shift = page_shift; + fmr->max_pages = max_pages; + fmr->max_maps = max_maps; + fmr->maps = 0; + + err = mlx4_mr_alloc(dev, pd, 0, 0, access, max_pages, + page_shift, &fmr->mr); + if (err) + return err; + + mtt_seg = fmr->mr.mtt.first_seg * dev->caps.mtt_entry_sz; + + fmr->mtts = mlx4_table_find(&priv->mr_table.mtt_table, + fmr->mr.mtt.first_seg, + &fmr->dma_handle); + if (!fmr->mtts) { + err = -ENOMEM; + goto err_free; + } + + fmr->mpt = mlx4_table_find(&priv->mr_table.dmpt_table, + key_to_hw_index(fmr->mr.key), NULL); + if (!fmr->mpt) { + err = -ENOMEM; + goto err_free; + } + + return 0; + +err_free: + mlx4_mr_free(dev, &fmr->mr); + return err; +} +EXPORT_SYMBOL_GPL(mlx4_fmr_alloc); + +int mlx4_fmr_enable(struct mlx4_dev *dev, struct mlx4_fmr *fmr) +{ + return mlx4_mr_enable(dev, &fmr->mr); +} +EXPORT_SYMBOL_GPL(mlx4_fmr_enable); + +void mlx4_fmr_unmap(struct mlx4_dev *dev, struct mlx4_fmr *fmr, + u32 *lkey, u32 *rkey) +{ + u32 key; + + if (!fmr->maps) + return; + + key = key_to_hw_index(fmr->mr.key); + key &= dev->caps.num_mpts - 1; + *lkey = *rkey = fmr->mr.key = hw_index_to_key(key); + + fmr->maps = 0; + + *(u8 *) fmr->mpt = MLX4_MPT_STATUS_SW; +} +EXPORT_SYMBOL_GPL(mlx4_fmr_unmap); + +int mlx4_fmr_free(struct mlx4_dev *dev, struct mlx4_fmr *fmr) +{ + if (fmr->maps) + return -EBUSY; + + fmr->mr.enabled = 0; + mlx4_mr_free(dev, &fmr->mr); + + return 0; +} +EXPORT_SYMBOL_GPL(mlx4_fmr_free); + +int mlx4_SYNC_TPT(struct mlx4_dev *dev) +{ + return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_SYNC_TPT, 1000); +} +EXPORT_SYMBOL_GPL(mlx4_SYNC_TPT); diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h index a93520c76fd..222815d91c4 100644 --- a/include/linux/mlx4/device.h +++ b/include/linux/mlx4/device.h @@ -214,6 +214,17 @@ struct mlx4_mr { int enabled; }; +struct mlx4_fmr { + struct mlx4_mr mr; + struct mlx4_mpt_entry *mpt; + __be64 *mtts; + dma_addr_t dma_handle; + int max_pages; + int max_maps; + int maps; + u8 page_shift; +}; + struct mlx4_uar { unsigned long pfn; int index; @@ -337,4 +348,14 @@ int mlx4_CLOSE_PORT(struct mlx4_dev *dev, int port); int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16]); int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16]); +int mlx4_map_phys_fmr(struct mlx4_dev *dev, struct mlx4_fmr *fmr, u64 *page_list, + int npages, u64 iova, u32 *lkey, u32 *rkey); +int mlx4_fmr_alloc(struct mlx4_dev *dev, u32 pd, u32 access, int max_pages, + int max_maps, u8 page_shift, struct mlx4_fmr *fmr); +int mlx4_fmr_enable(struct mlx4_dev *dev, struct mlx4_fmr *fmr); +void mlx4_fmr_unmap(struct mlx4_dev *dev, struct mlx4_fmr *fmr, + u32 *lkey, u32 *rkey); +int mlx4_fmr_free(struct mlx4_dev *dev, struct mlx4_fmr *fmr); +int mlx4_SYNC_TPT(struct mlx4_dev *dev); + #endif /* MLX4_DEVICE_H */ -- cgit v1.2.3-70-g09d2 From e57ac0c297b9e1074dcb6b6ee5cd1d6407a7df14 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Tue, 2 Oct 2007 09:40:13 +0200 Subject: mlx4_core: Increase max number of QPs per multicast group to 56 Increase the number of QPs allowed per multicast group from 8 to 56. This allows for one QP per core on 16-core systems, which are now quite common, and allows some space for future growth. Signed-off-by: Jack Morgenstein Signed-off-by: Roland Dreier --- drivers/net/mlx4/mlx4.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h index 2bad045b25c..53a1cdddfc1 100644 --- a/drivers/net/mlx4/mlx4.h +++ b/drivers/net/mlx4/mlx4.h @@ -56,7 +56,7 @@ enum { }; enum { - MLX4_MGM_ENTRY_SIZE = 0x40, + MLX4_MGM_ENTRY_SIZE = 0x100, MLX4_QP_PER_MGM = 4 * (MLX4_MGM_ENTRY_SIZE / 16 - 2), MLX4_MTT_ENTRY_PER_SEG = 8 }; -- cgit v1.2.3-70-g09d2 From 1a1eb6a646f52dc62e3f9ceac4aab9c27e781186 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 9 Oct 2007 19:59:17 -0700 Subject: IB/mthca: Increase max number of QPs per multicast group to 56 Increase the number of QPs allowed per multicast group from 8 to 56. This allows for one QP per core on 16-core systems, which are now quite common, and allows some space for future growth. This is basically the same patch that Jack Morgenstein just supplied for mlx4. Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_dev.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mthca/mthca_dev.h b/drivers/infiniband/hw/mthca/mthca_dev.h index 9bae3cc6060..15aa32eb78b 100644 --- a/drivers/infiniband/hw/mthca/mthca_dev.h +++ b/drivers/infiniband/hw/mthca/mthca_dev.h @@ -83,7 +83,7 @@ enum { MTHCA_QP_CONTEXT_SIZE = 0x200, MTHCA_RDB_ENTRY_SIZE = 0x20, MTHCA_AV_SIZE = 0x20, - MTHCA_MGM_ENTRY_SIZE = 0x40, + MTHCA_MGM_ENTRY_SIZE = 0x100, /* Arbel FW gives us these, but we need them for Tavor */ MTHCA_MPT_ENTRY_SIZE = 0x40, -- cgit v1.2.3-70-g09d2 From de98b693e9857e183679cd2f49b3c30d2bc57629 Mon Sep 17 00:00:00 2001 From: Sean Hefty Date: Wed, 1 Aug 2007 13:49:53 -0700 Subject: IB/cm: Modify interface to send MRAs in response to duplicate messages The IB CM provides a message received acknowledged (MRA) message that can be sent to indicate that a REQ or REP message has been received, but will require more time to process than the timeout specified by those messages. In many cases, the application may not know how long it will take to respond to a CM message, but the majority of the time, it will usually respond before a retry has been sent. Rather than sending an MRA in response to all messages just to handle the case where a longer timeout is needed, it is more efficient to queue the MRA for sending in case a duplicate message is received. This avoids sending an MRA when it is not needed, but limits the number of times that a REQ or REP will be resent. It also provides for a simpler implementation than generating the MRA based on a timer event. (That is, trying to send the MRA after receiving the first REQ or REP if a response has not been generated, so that it is received at the remote side before a duplicate REQ or REP has been received) Signed-off-by: Sean Hefty Signed-off-by: Roland Dreier --- drivers/infiniband/core/cm.c | 51 ++++++++++++++++++++------------------------ include/rdma/ib_cm.h | 7 ++++-- 2 files changed, 28 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index 4df269f5d9a..2e39236d189 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -2219,6 +2219,9 @@ int ib_send_cm_mra(struct ib_cm_id *cm_id, { struct cm_id_private *cm_id_priv; struct ib_mad_send_buf *msg; + enum ib_cm_state cm_state; + enum ib_cm_lap_state lap_state; + enum cm_msg_response msg_response; void *data; unsigned long flags; int ret; @@ -2235,48 +2238,40 @@ int ib_send_cm_mra(struct ib_cm_id *cm_id, spin_lock_irqsave(&cm_id_priv->lock, flags); switch(cm_id_priv->id.state) { case IB_CM_REQ_RCVD: - ret = cm_alloc_msg(cm_id_priv, &msg); - if (ret) - goto error1; - - cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv, - CM_MSG_RESPONSE_REQ, service_timeout, - private_data, private_data_len); - ret = ib_post_send_mad(msg, NULL); - if (ret) - goto error2; - cm_id->state = IB_CM_MRA_REQ_SENT; + cm_state = IB_CM_MRA_REQ_SENT; + lap_state = cm_id->lap_state; + msg_response = CM_MSG_RESPONSE_REQ; break; case IB_CM_REP_RCVD: - ret = cm_alloc_msg(cm_id_priv, &msg); - if (ret) - goto error1; - - cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv, - CM_MSG_RESPONSE_REP, service_timeout, - private_data, private_data_len); - ret = ib_post_send_mad(msg, NULL); - if (ret) - goto error2; - cm_id->state = IB_CM_MRA_REP_SENT; + cm_state = IB_CM_MRA_REP_SENT; + lap_state = cm_id->lap_state; + msg_response = CM_MSG_RESPONSE_REP; break; case IB_CM_ESTABLISHED: + cm_state = cm_id->state; + lap_state = IB_CM_MRA_LAP_SENT; + msg_response = CM_MSG_RESPONSE_OTHER; + break; + default: + ret = -EINVAL; + goto error1; + } + + if (!(service_timeout & IB_CM_MRA_FLAG_DELAY)) { ret = cm_alloc_msg(cm_id_priv, &msg); if (ret) goto error1; cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv, - CM_MSG_RESPONSE_OTHER, service_timeout, + msg_response, service_timeout, private_data, private_data_len); ret = ib_post_send_mad(msg, NULL); if (ret) goto error2; - cm_id->lap_state = IB_CM_MRA_LAP_SENT; - break; - default: - ret = -EINVAL; - goto error1; } + + cm_id->state = cm_state; + cm_id->lap_state = lap_state; cm_id_priv->service_timeout = service_timeout; cm_set_private_data(cm_id_priv, data, private_data_len); spin_unlock_irqrestore(&cm_id_priv->lock, flags); diff --git a/include/rdma/ib_cm.h b/include/rdma/ib_cm.h index 12243e80c70..a627c8682d2 100644 --- a/include/rdma/ib_cm.h +++ b/include/rdma/ib_cm.h @@ -477,12 +477,15 @@ int ib_send_cm_rej(struct ib_cm_id *cm_id, const void *private_data, u8 private_data_len); +#define IB_CM_MRA_FLAG_DELAY 0x80 /* Send MRA only after a duplicate msg */ + /** * ib_send_cm_mra - Sends a message receipt acknowledgement to a connection * message. * @cm_id: Connection identifier associated with the connection message. - * @service_timeout: The maximum time required for the sender to reply to - * to the connection message. + * @service_timeout: The lower 5-bits specify the maximum time required for + * the sender to reply to to the connection message. The upper 3-bits + * specify additional control flags. * @private_data: Optional user-defined private data sent with the * message receipt acknowledgement. * @private_data_len: Size of the private data buffer, in bytes. -- cgit v1.2.3-70-g09d2 From dcb3f974da827c964cb8d419fbb4350cdc08a559 Mon Sep 17 00:00:00 2001 From: Sean Hefty Date: Wed, 1 Aug 2007 14:47:16 -0700 Subject: RDMA/cma: Queue IB CM MRAs to avoid unnecessary remote retries Automatically queue MRA message to decrease the number of retries sent by the remote side during connection establishment. This also has the effect of increasing the overall connection timeout without using a longer retry time in the case of dropped packets. Signed-off-by: Sean Hefty Signed-off-by: Roland Dreier --- drivers/infiniband/core/cma.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 19c9172f0cd..72539529fa6 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -52,6 +52,7 @@ MODULE_LICENSE("Dual BSD/GPL"); #define CMA_CM_RESPONSE_TIMEOUT 20 #define CMA_MAX_CM_RETRIES 15 +#define CMA_CM_MRA_SETTING (IB_CM_MRA_FLAG_DELAY | 24) static void cma_add_one(struct ib_device *device); static void cma_remove_one(struct ib_device *device); @@ -1090,6 +1091,7 @@ static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event) event.param.ud.private_data_len = IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE - offset; } else { + ib_send_cm_mra(cm_id, CMA_CM_MRA_SETTING, NULL, 0); conn_id = cma_new_conn_id(&listen_id->id, ib_event); cma_set_req_event_data(&event, &ib_event->param.req_rcvd, ib_event->private_data, offset); -- cgit v1.2.3-70-g09d2 From 76d7cc0345a037e8eea426f8abc710abd22946dd Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 9 Oct 2007 19:59:17 -0700 Subject: IB/mthca: Use mmiowb() to avoid firmware commands getting jumbled up Firmware commands are sent to the HCA by writing multiple words to a command register block. Access to this block of registers is serialized with a mutex. However, on large SGI systems, problems were seen with multiple CPUs issuing FW commands at the same time, because the writes to the register block may be reordered within the system interconnect and reach the HCA in a different order than they were issued (even with the mutex). Fix this by adding an mmiowb() before dropping the mutex. Tested-by: Arthur Kepner Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_cmd.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c index acc95892713..6966f943f44 100644 --- a/drivers/infiniband/hw/mthca/mthca_cmd.c +++ b/drivers/infiniband/hw/mthca/mthca_cmd.c @@ -290,6 +290,12 @@ static int mthca_cmd_post(struct mthca_dev *dev, err = mthca_cmd_post_hcr(dev, in_param, out_param, in_modifier, op_modifier, op, token, event); + /* + * Make sure that our HCR writes don't get mixed in with + * writes from another CPU starting a FW command. + */ + mmiowb(); + mutex_unlock(&dev->cmd.hcr_mutex); return err; } -- cgit v1.2.3-70-g09d2 From 2e61c646edfa013203e3428762f8d6a72e10bdea Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 9 Oct 2007 19:59:18 -0700 Subject: mlx4_core: Use mmiowb() to avoid firmware commands getting jumbled up Firmware commands are sent to the HCA by writing multiple words to a command register block. Access to this block of registers is serialized with a mutex. However, on large SGI systems writes to the register block may be reordered within the system interconnect and reach the HCA in a different order than they were issued (even with the mutex). Fix this by adding an mmiowb() before dropping the mutex. This bug was observed with real workloads with the similar FW command code in the mthca driver, and adding the mmiowb() as in commit 66547550 ("IB/mthca: Use mmiowb() to avoid firmware commands getting jumbled up") was confirmed to fix the problems, so we should add the same fix to mlx4. Signed-off-by: Roland Dreier --- drivers/net/mlx4/cmd.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/net/mlx4/cmd.c b/drivers/net/mlx4/cmd.c index b540820e9c2..db49051b97b 100644 --- a/drivers/net/mlx4/cmd.c +++ b/drivers/net/mlx4/cmd.c @@ -184,6 +184,13 @@ static int mlx4_cmd_post(struct mlx4_dev *dev, u64 in_param, u64 out_param, (event ? (1 << HCR_E_BIT) : 0) | (op_modifier << HCR_OPMOD_SHIFT) | op), hcr + 6); + + /* + * Make sure that our HCR writes don't get mixed in with + * writes from another CPU starting a FW command. + */ + mmiowb(); + cmd->toggle = cmd->toggle ^ 1; ret = 0; -- cgit v1.2.3-70-g09d2 From ede6bc04f3a07a9c93f02c92cdc281d254398321 Mon Sep 17 00:00:00 2001 From: Dotan Barak Date: Sun, 7 Oct 2007 09:30:48 +0200 Subject: IPoIB/cm: Clean up initialization of QP attr in ipoib_cm_create_tx_qp() Make the way QP is being created in ipoib_cm_create_tx_qp() consistent with ipoib_cm_create_rx_qp(). Signed-off-by: Dotan Barak Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/ipoib/ipoib_cm.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 08b4676a382..23addb3a6f4 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -810,14 +810,16 @@ static int ipoib_cm_rep_handler(struct ib_cm_id *cm_id, struct ib_cm_event *even static struct ib_qp *ipoib_cm_create_tx_qp(struct net_device *dev, struct ib_cq *cq) { struct ipoib_dev_priv *priv = netdev_priv(dev); - struct ib_qp_init_attr attr = {}; - attr.recv_cq = priv->cq; - attr.srq = priv->cm.srq; - attr.cap.max_send_wr = ipoib_sendq_size; - attr.cap.max_send_sge = 1; - attr.sq_sig_type = IB_SIGNAL_ALL_WR; - attr.qp_type = IB_QPT_RC; - attr.send_cq = cq; + struct ib_qp_init_attr attr = { + .send_cq = cq, + .recv_cq = priv->cq, + .srq = priv->cm.srq, + .cap.max_send_wr = ipoib_sendq_size, + .cap.max_send_sge = 1, + .sq_sig_type = IB_SIGNAL_ALL_WR, + .qp_type = IB_QPT_RC, + }; + return ib_create_qp(priv->pd, &attr); } -- cgit v1.2.3-70-g09d2 From 76dea3bc2644e99cce1d98d0bbd3124314e5b50a Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 9 Oct 2007 19:59:18 -0700 Subject: IB/ehca: Fix clipping of device limits to INT_MAX Doing min_t(int, foo, INT_MAX) doesn't work correctly, because if foo is bigger than INT_MAX, then when treated as a signed integer, it will become negative and hence such an expression is just an elaborate NOP. Fix such cases in ehca to do min_t(unsigned, foo, INT_MAX) instead. This fixes negative reported values for max_cqe, max_pd and max_ah: Before: max_cqe: -64 max_pd: -1 max_ah: -1 After: max_cqe: 2147483647 max_pd: 2147483647 max_ah: 2147483647 Based on a bug report and fix from Anton Blanchard . Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/ehca_hca.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ehca/ehca_hca.c b/drivers/infiniband/hw/ehca/ehca_hca.c index 3436c49eee0..4aa3ffa6a19 100644 --- a/drivers/infiniband/hw/ehca/ehca_hca.c +++ b/drivers/infiniband/hw/ehca/ehca_hca.c @@ -82,17 +82,17 @@ int ehca_query_device(struct ib_device *ibdev, struct ib_device_attr *props) props->vendor_id = rblock->vendor_id >> 8; props->vendor_part_id = rblock->vendor_part_id >> 16; props->hw_ver = rblock->hw_ver; - props->max_qp = min_t(int, rblock->max_qp, INT_MAX); - props->max_qp_wr = min_t(int, rblock->max_wqes_wq, INT_MAX); - props->max_sge = min_t(int, rblock->max_sge, INT_MAX); - props->max_sge_rd = min_t(int, rblock->max_sge_rd, INT_MAX); - props->max_cq = min_t(int, rblock->max_cq, INT_MAX); - props->max_cqe = min_t(int, rblock->max_cqe, INT_MAX); - props->max_mr = min_t(int, rblock->max_mr, INT_MAX); - props->max_mw = min_t(int, rblock->max_mw, INT_MAX); - props->max_pd = min_t(int, rblock->max_pd, INT_MAX); - props->max_ah = min_t(int, rblock->max_ah, INT_MAX); - props->max_fmr = min_t(int, rblock->max_mr, INT_MAX); + props->max_qp = min_t(unsigned, rblock->max_qp, INT_MAX); + props->max_qp_wr = min_t(unsigned, rblock->max_wqes_wq, INT_MAX); + props->max_sge = min_t(unsigned, rblock->max_sge, INT_MAX); + props->max_sge_rd = min_t(unsigned, rblock->max_sge_rd, INT_MAX); + props->max_cq = min_t(unsigned, rblock->max_cq, INT_MAX); + props->max_cqe = min_t(unsigned, rblock->max_cqe, INT_MAX); + props->max_mr = min_t(unsigned, rblock->max_mr, INT_MAX); + props->max_mw = min_t(unsigned, rblock->max_mw, INT_MAX); + props->max_pd = min_t(unsigned, rblock->max_pd, INT_MAX); + props->max_ah = min_t(unsigned, rblock->max_ah, INT_MAX); + props->max_fmr = min_t(unsigned, rblock->max_mr, INT_MAX); if (EHCA_BMASK_GET(HCA_CAP_SRQ, shca->hca_cap)) { props->max_srq = props->max_qp; @@ -104,15 +104,15 @@ int ehca_query_device(struct ib_device *ibdev, struct ib_device_attr *props) props->local_ca_ack_delay = rblock->local_ca_ack_delay; props->max_raw_ipv6_qp - = min_t(int, rblock->max_raw_ipv6_qp, INT_MAX); + = min_t(unsigned, rblock->max_raw_ipv6_qp, INT_MAX); props->max_raw_ethy_qp - = min_t(int, rblock->max_raw_ethy_qp, INT_MAX); + = min_t(unsigned, rblock->max_raw_ethy_qp, INT_MAX); props->max_mcast_grp - = min_t(int, rblock->max_mcast_grp, INT_MAX); + = min_t(unsigned, rblock->max_mcast_grp, INT_MAX); props->max_mcast_qp_attach - = min_t(int, rblock->max_mcast_qp_attach, INT_MAX); + = min_t(unsigned, rblock->max_mcast_qp_attach, INT_MAX); props->max_total_mcast_qp_attach - = min_t(int, rblock->max_total_mcast_qp_attach, INT_MAX); + = min_t(unsigned, rblock->max_total_mcast_qp_attach, INT_MAX); /* translate device capabilities */ props->device_cap_flags = IB_DEVICE_SYS_IMAGE_GUID | -- cgit v1.2.3-70-g09d2 From ba366a23b68029fc8560acf1ad8735eed910f962 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 23 Aug 2007 18:12:08 -0300 Subject: V4L/DVB (6257): Rename video-buf-dvb to videobuf-dvb to be consistent with the other patches Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Makefile | 2 +- drivers/media/video/cx88/cx88.h | 2 +- drivers/media/video/saa7134/saa7134.h | 2 +- drivers/media/video/video-buf-dvb.c | 256 ---------------------------------- drivers/media/video/videobuf-dvb.c | 256 ++++++++++++++++++++++++++++++++++ include/media/video-buf-dvb.h | 37 ----- include/media/videobuf-dvb.h | 37 +++++ 7 files changed, 296 insertions(+), 296 deletions(-) delete mode 100644 drivers/media/video/video-buf-dvb.c create mode 100644 drivers/media/video/videobuf-dvb.c delete mode 100644 include/media/video-buf-dvb.h create mode 100644 include/media/videobuf-dvb.h (limited to 'drivers') diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index c8140aec1a1..b5a064163e0 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -90,7 +90,7 @@ obj-$(CONFIG_TUNER_TEA5761) += tea5761.o obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o obj-$(CONFIG_VIDEOBUF_VMALLOC) += videobuf-vmalloc.o -obj-$(CONFIG_VIDEO_BUF_DVB) += video-buf-dvb.o +obj-$(CONFIG_VIDEOBUF_DVB) += videobuf-dvb.o obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index 875a9abab2a..b3fe2d59cd1 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -32,7 +32,7 @@ #include #include #if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE) -#include +#include #endif #include "btcx-risc.h" diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index dae608f9bf3..cb617c8dbb7 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -42,7 +42,7 @@ #include #include #if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE) -#include +#include #endif #define UNSET (-1U) diff --git a/drivers/media/video/video-buf-dvb.c b/drivers/media/video/video-buf-dvb.c deleted file mode 100644 index 9631ead297e..00000000000 --- a/drivers/media/video/video-buf-dvb.c +++ /dev/null @@ -1,256 +0,0 @@ -/* - * - * some helper function for simple DVB cards which simply DMA the - * complete transport stream and let the computer sort everything else - * (i.e. we are using the software demux, ...). Also uses the - * video-buf to manage DMA buffers. - * - * (c) 2004 Gerd Knorr [SUSE Labs] - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -/* ------------------------------------------------------------------ */ - -MODULE_AUTHOR("Gerd Knorr [SuSE Labs]"); -MODULE_LICENSE("GPL"); - -static unsigned int debug = 0; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug,"enable debug messages"); - -#define dprintk(fmt, arg...) if (debug) \ - printk(KERN_DEBUG "%s/dvb: " fmt, dvb->name , ## arg) - -/* ------------------------------------------------------------------ */ - -static int videobuf_dvb_thread(void *data) -{ - struct videobuf_dvb *dvb = data; - struct videobuf_buffer *buf; - unsigned long flags; - int err; - struct videobuf_dmabuf *dma; - - dprintk("dvb thread started\n"); - set_freezable(); - videobuf_read_start(&dvb->dvbq); - - for (;;) { - /* fetch next buffer */ - buf = list_entry(dvb->dvbq.stream.next, - struct videobuf_buffer, stream); - list_del(&buf->stream); - err = videobuf_waiton(buf,0,1); - - /* no more feeds left or stop_feed() asked us to quit */ - if (0 == dvb->nfeeds) - break; - if (kthread_should_stop()) - break; - try_to_freeze(); - - /* feed buffer data to demux */ - dma=videobuf_to_dma(buf); - if (buf->state == STATE_DONE) - dvb_dmx_swfilter(&dvb->demux, dma->vmalloc, - buf->size); - - /* requeue buffer */ - list_add_tail(&buf->stream,&dvb->dvbq.stream); - spin_lock_irqsave(dvb->dvbq.irqlock,flags); - dvb->dvbq.ops->buf_queue(&dvb->dvbq,buf); - spin_unlock_irqrestore(dvb->dvbq.irqlock,flags); - } - - videobuf_read_stop(&dvb->dvbq); - dprintk("dvb thread stopped\n"); - - /* Hmm, linux becomes *very* unhappy without this ... */ - while (!kthread_should_stop()) { - set_current_state(TASK_INTERRUPTIBLE); - schedule(); - } - return 0; -} - -static int videobuf_dvb_start_feed(struct dvb_demux_feed *feed) -{ - struct dvb_demux *demux = feed->demux; - struct videobuf_dvb *dvb = demux->priv; - int rc; - - if (!demux->dmx.frontend) - return -EINVAL; - - mutex_lock(&dvb->lock); - dvb->nfeeds++; - rc = dvb->nfeeds; - - if (NULL != dvb->thread) - goto out; - dvb->thread = kthread_run(videobuf_dvb_thread, - dvb, "%s dvb", dvb->name); - if (IS_ERR(dvb->thread)) { - rc = PTR_ERR(dvb->thread); - dvb->thread = NULL; - } - -out: - mutex_unlock(&dvb->lock); - return rc; -} - -static int videobuf_dvb_stop_feed(struct dvb_demux_feed *feed) -{ - struct dvb_demux *demux = feed->demux; - struct videobuf_dvb *dvb = demux->priv; - int err = 0; - - mutex_lock(&dvb->lock); - dvb->nfeeds--; - if (0 == dvb->nfeeds && NULL != dvb->thread) { - // FIXME: cx8802_cancel_buffers(dev); - err = kthread_stop(dvb->thread); - dvb->thread = NULL; - } - mutex_unlock(&dvb->lock); - return err; -} - -/* ------------------------------------------------------------------ */ - -int videobuf_dvb_register(struct videobuf_dvb *dvb, - struct module *module, - void *adapter_priv, - struct device *device) -{ - int result; - - mutex_init(&dvb->lock); - - /* register adapter */ - result = dvb_register_adapter(&dvb->adapter, dvb->name, module, device); - if (result < 0) { - printk(KERN_WARNING "%s: dvb_register_adapter failed (errno = %d)\n", - dvb->name, result); - goto fail_adapter; - } - dvb->adapter.priv = adapter_priv; - - /* register frontend */ - result = dvb_register_frontend(&dvb->adapter, dvb->frontend); - if (result < 0) { - printk(KERN_WARNING "%s: dvb_register_frontend failed (errno = %d)\n", - dvb->name, result); - goto fail_frontend; - } - - /* register demux stuff */ - dvb->demux.dmx.capabilities = - DMX_TS_FILTERING | DMX_SECTION_FILTERING | - DMX_MEMORY_BASED_FILTERING; - dvb->demux.priv = dvb; - dvb->demux.filternum = 256; - dvb->demux.feednum = 256; - dvb->demux.start_feed = videobuf_dvb_start_feed; - dvb->demux.stop_feed = videobuf_dvb_stop_feed; - result = dvb_dmx_init(&dvb->demux); - if (result < 0) { - printk(KERN_WARNING "%s: dvb_dmx_init failed (errno = %d)\n", - dvb->name, result); - goto fail_dmx; - } - - dvb->dmxdev.filternum = 256; - dvb->dmxdev.demux = &dvb->demux.dmx; - dvb->dmxdev.capabilities = 0; - result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter); - if (result < 0) { - printk(KERN_WARNING "%s: dvb_dmxdev_init failed (errno = %d)\n", - dvb->name, result); - goto fail_dmxdev; - } - - dvb->fe_hw.source = DMX_FRONTEND_0; - result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw); - if (result < 0) { - printk(KERN_WARNING "%s: add_frontend failed (DMX_FRONTEND_0, errno = %d)\n", - dvb->name, result); - goto fail_fe_hw; - } - - dvb->fe_mem.source = DMX_MEMORY_FE; - result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem); - if (result < 0) { - printk(KERN_WARNING "%s: add_frontend failed (DMX_MEMORY_FE, errno = %d)\n", - dvb->name, result); - goto fail_fe_mem; - } - - result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw); - if (result < 0) { - printk(KERN_WARNING "%s: connect_frontend failed (errno = %d)\n", - dvb->name, result); - goto fail_fe_conn; - } - - /* register network adapter */ - dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx); - return 0; - -fail_fe_conn: - dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); -fail_fe_mem: - dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); -fail_fe_hw: - dvb_dmxdev_release(&dvb->dmxdev); -fail_dmxdev: - dvb_dmx_release(&dvb->demux); -fail_dmx: - dvb_unregister_frontend(dvb->frontend); -fail_frontend: - dvb_frontend_detach(dvb->frontend); - dvb_unregister_adapter(&dvb->adapter); -fail_adapter: - return result; -} - -void videobuf_dvb_unregister(struct videobuf_dvb *dvb) -{ - dvb_net_release(&dvb->net); - dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); - dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); - dvb_dmxdev_release(&dvb->dmxdev); - dvb_dmx_release(&dvb->demux); - dvb_unregister_frontend(dvb->frontend); - dvb_frontend_detach(dvb->frontend); - dvb_unregister_adapter(&dvb->adapter); -} - -EXPORT_SYMBOL(videobuf_dvb_register); -EXPORT_SYMBOL(videobuf_dvb_unregister); - -/* ------------------------------------------------------------------ */ -/* - * Local variables: - * c-basic-offset: 8 - * compile-command: "make DVB=1" - * End: - */ - diff --git a/drivers/media/video/videobuf-dvb.c b/drivers/media/video/videobuf-dvb.c new file mode 100644 index 00000000000..880317e04a0 --- /dev/null +++ b/drivers/media/video/videobuf-dvb.c @@ -0,0 +1,256 @@ +/* + * + * some helper function for simple DVB cards which simply DMA the + * complete transport stream and let the computer sort everything else + * (i.e. we are using the software demux, ...). Also uses the + * video-buf to manage DMA buffers. + * + * (c) 2004 Gerd Knorr [SUSE Labs] + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* ------------------------------------------------------------------ */ + +MODULE_AUTHOR("Gerd Knorr [SuSE Labs]"); +MODULE_LICENSE("GPL"); + +static unsigned int debug = 0; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug,"enable debug messages"); + +#define dprintk(fmt, arg...) if (debug) \ + printk(KERN_DEBUG "%s/dvb: " fmt, dvb->name , ## arg) + +/* ------------------------------------------------------------------ */ + +static int videobuf_dvb_thread(void *data) +{ + struct videobuf_dvb *dvb = data; + struct videobuf_buffer *buf; + unsigned long flags; + int err; + struct videobuf_dmabuf *dma; + + dprintk("dvb thread started\n"); + set_freezable(); + videobuf_read_start(&dvb->dvbq); + + for (;;) { + /* fetch next buffer */ + buf = list_entry(dvb->dvbq.stream.next, + struct videobuf_buffer, stream); + list_del(&buf->stream); + err = videobuf_waiton(buf,0,1); + + /* no more feeds left or stop_feed() asked us to quit */ + if (0 == dvb->nfeeds) + break; + if (kthread_should_stop()) + break; + try_to_freeze(); + + /* feed buffer data to demux */ + dma=videobuf_to_dma(buf); + if (buf->state == STATE_DONE) + dvb_dmx_swfilter(&dvb->demux, dma->vmalloc, + buf->size); + + /* requeue buffer */ + list_add_tail(&buf->stream,&dvb->dvbq.stream); + spin_lock_irqsave(dvb->dvbq.irqlock,flags); + dvb->dvbq.ops->buf_queue(&dvb->dvbq,buf); + spin_unlock_irqrestore(dvb->dvbq.irqlock,flags); + } + + videobuf_read_stop(&dvb->dvbq); + dprintk("dvb thread stopped\n"); + + /* Hmm, linux becomes *very* unhappy without this ... */ + while (!kthread_should_stop()) { + set_current_state(TASK_INTERRUPTIBLE); + schedule(); + } + return 0; +} + +static int videobuf_dvb_start_feed(struct dvb_demux_feed *feed) +{ + struct dvb_demux *demux = feed->demux; + struct videobuf_dvb *dvb = demux->priv; + int rc; + + if (!demux->dmx.frontend) + return -EINVAL; + + mutex_lock(&dvb->lock); + dvb->nfeeds++; + rc = dvb->nfeeds; + + if (NULL != dvb->thread) + goto out; + dvb->thread = kthread_run(videobuf_dvb_thread, + dvb, "%s dvb", dvb->name); + if (IS_ERR(dvb->thread)) { + rc = PTR_ERR(dvb->thread); + dvb->thread = NULL; + } + +out: + mutex_unlock(&dvb->lock); + return rc; +} + +static int videobuf_dvb_stop_feed(struct dvb_demux_feed *feed) +{ + struct dvb_demux *demux = feed->demux; + struct videobuf_dvb *dvb = demux->priv; + int err = 0; + + mutex_lock(&dvb->lock); + dvb->nfeeds--; + if (0 == dvb->nfeeds && NULL != dvb->thread) { + // FIXME: cx8802_cancel_buffers(dev); + err = kthread_stop(dvb->thread); + dvb->thread = NULL; + } + mutex_unlock(&dvb->lock); + return err; +} + +/* ------------------------------------------------------------------ */ + +int videobuf_dvb_register(struct videobuf_dvb *dvb, + struct module *module, + void *adapter_priv, + struct device *device) +{ + int result; + + mutex_init(&dvb->lock); + + /* register adapter */ + result = dvb_register_adapter(&dvb->adapter, dvb->name, module, device); + if (result < 0) { + printk(KERN_WARNING "%s: dvb_register_adapter failed (errno = %d)\n", + dvb->name, result); + goto fail_adapter; + } + dvb->adapter.priv = adapter_priv; + + /* register frontend */ + result = dvb_register_frontend(&dvb->adapter, dvb->frontend); + if (result < 0) { + printk(KERN_WARNING "%s: dvb_register_frontend failed (errno = %d)\n", + dvb->name, result); + goto fail_frontend; + } + + /* register demux stuff */ + dvb->demux.dmx.capabilities = + DMX_TS_FILTERING | DMX_SECTION_FILTERING | + DMX_MEMORY_BASED_FILTERING; + dvb->demux.priv = dvb; + dvb->demux.filternum = 256; + dvb->demux.feednum = 256; + dvb->demux.start_feed = videobuf_dvb_start_feed; + dvb->demux.stop_feed = videobuf_dvb_stop_feed; + result = dvb_dmx_init(&dvb->demux); + if (result < 0) { + printk(KERN_WARNING "%s: dvb_dmx_init failed (errno = %d)\n", + dvb->name, result); + goto fail_dmx; + } + + dvb->dmxdev.filternum = 256; + dvb->dmxdev.demux = &dvb->demux.dmx; + dvb->dmxdev.capabilities = 0; + result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter); + if (result < 0) { + printk(KERN_WARNING "%s: dvb_dmxdev_init failed (errno = %d)\n", + dvb->name, result); + goto fail_dmxdev; + } + + dvb->fe_hw.source = DMX_FRONTEND_0; + result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw); + if (result < 0) { + printk(KERN_WARNING "%s: add_frontend failed (DMX_FRONTEND_0, errno = %d)\n", + dvb->name, result); + goto fail_fe_hw; + } + + dvb->fe_mem.source = DMX_MEMORY_FE; + result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem); + if (result < 0) { + printk(KERN_WARNING "%s: add_frontend failed (DMX_MEMORY_FE, errno = %d)\n", + dvb->name, result); + goto fail_fe_mem; + } + + result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw); + if (result < 0) { + printk(KERN_WARNING "%s: connect_frontend failed (errno = %d)\n", + dvb->name, result); + goto fail_fe_conn; + } + + /* register network adapter */ + dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx); + return 0; + +fail_fe_conn: + dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); +fail_fe_mem: + dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); +fail_fe_hw: + dvb_dmxdev_release(&dvb->dmxdev); +fail_dmxdev: + dvb_dmx_release(&dvb->demux); +fail_dmx: + dvb_unregister_frontend(dvb->frontend); +fail_frontend: + dvb_frontend_detach(dvb->frontend); + dvb_unregister_adapter(&dvb->adapter); +fail_adapter: + return result; +} + +void videobuf_dvb_unregister(struct videobuf_dvb *dvb) +{ + dvb_net_release(&dvb->net); + dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); + dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); + dvb_dmxdev_release(&dvb->dmxdev); + dvb_dmx_release(&dvb->demux); + dvb_unregister_frontend(dvb->frontend); + dvb_frontend_detach(dvb->frontend); + dvb_unregister_adapter(&dvb->adapter); +} + +EXPORT_SYMBOL(videobuf_dvb_register); +EXPORT_SYMBOL(videobuf_dvb_unregister); + +/* ------------------------------------------------------------------ */ +/* + * Local variables: + * c-basic-offset: 8 + * compile-command: "make DVB=1" + * End: + */ + diff --git a/include/media/video-buf-dvb.h b/include/media/video-buf-dvb.h deleted file mode 100644 index 8233cafdeef..00000000000 --- a/include/media/video-buf-dvb.h +++ /dev/null @@ -1,37 +0,0 @@ -#include -#include -#include -#include -#include - -struct videobuf_dvb { - /* filling that the job of the driver */ - char *name; - struct dvb_frontend *frontend; - struct videobuf_queue dvbq; - - /* video-buf-dvb state info */ - struct mutex lock; - struct task_struct *thread; - int nfeeds; - - /* videobuf_dvb_(un)register manges this */ - struct dvb_adapter adapter; - struct dvb_demux demux; - struct dmxdev dmxdev; - struct dmx_frontend fe_hw; - struct dmx_frontend fe_mem; - struct dvb_net net; -}; - -int videobuf_dvb_register(struct videobuf_dvb *dvb, - struct module *module, - void *adapter_priv, - struct device *device); -void videobuf_dvb_unregister(struct videobuf_dvb *dvb); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/include/media/videobuf-dvb.h b/include/media/videobuf-dvb.h new file mode 100644 index 00000000000..8233cafdeef --- /dev/null +++ b/include/media/videobuf-dvb.h @@ -0,0 +1,37 @@ +#include +#include +#include +#include +#include + +struct videobuf_dvb { + /* filling that the job of the driver */ + char *name; + struct dvb_frontend *frontend; + struct videobuf_queue dvbq; + + /* video-buf-dvb state info */ + struct mutex lock; + struct task_struct *thread; + int nfeeds; + + /* videobuf_dvb_(un)register manges this */ + struct dvb_adapter adapter; + struct dvb_demux demux; + struct dmxdev dmxdev; + struct dmx_frontend fe_hw; + struct dmx_frontend fe_mem; + struct dvb_net net; +}; + +int videobuf_dvb_register(struct videobuf_dvb *dvb, + struct module *module, + void *adapter_priv, + struct device *device); +void videobuf_dvb_unregister(struct videobuf_dvb *dvb); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ -- cgit v1.2.3-70-g09d2 From 327a338d4fd018d33e7cacde46c0d82622b4bda8 Mon Sep 17 00:00:00 2001 From: Arthur Jones Date: Thu, 2 Aug 2007 14:46:29 -0700 Subject: IB/ipath: iba6110 rev4 GPIO counters support On iba6110 rev4, support for three more IB counters were added. The LocalLinkIntegrityError counter, the ExcessiveBufferOverrunErrors counter and support for error counting of flow control packets on an invalid VL. These counters trigger GPIO interrupts and the sw keeps track of the counts. Since we also use GPIO interrupts to signal packet reception, we need to turn off the fast interrupts, or we risk losing a GPIO interrupt. Signed-off-by: Arthur Jones Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_iba6110.c | 8 ++++++++ drivers/infiniband/hw/ipath/ipath_intr.c | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ipath/ipath_iba6110.c b/drivers/infiniband/hw/ipath/ipath_iba6110.c index 650745d83fa..e1c5998887e 100644 --- a/drivers/infiniband/hw/ipath/ipath_iba6110.c +++ b/drivers/infiniband/hw/ipath/ipath_iba6110.c @@ -1559,6 +1559,14 @@ static int ipath_ht_early_init(struct ipath_devdata *dd) ipath_dev_err(dd, "Unsupported InfiniPath serial " "number %.16s!\n", dd->ipath_serial); + if (dd->ipath_minrev >= 4) { + /* Rev4+ reports extra errors via internal GPIO pins */ + dd->ipath_flags |= IPATH_GPIO_ERRINTRS; + dd->ipath_gpio_mask |= IPATH_GPIO_ERRINTR_MASK; + ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_mask, + dd->ipath_gpio_mask); + } + return 0; } diff --git a/drivers/infiniband/hw/ipath/ipath_intr.c b/drivers/infiniband/hw/ipath/ipath_intr.c index b29fe7e9b11..11b361408ae 100644 --- a/drivers/infiniband/hw/ipath/ipath_intr.c +++ b/drivers/infiniband/hw/ipath/ipath_intr.c @@ -1085,8 +1085,8 @@ irqreturn_t ipath_intr(int irq, void *data) * GPIO_2 indicates (on some HT4xx boards) that a packet * has arrived for Port 0. Checking for this * is controlled by flag IPATH_GPIO_INTR. - * GPIO_3..5 on IBA6120 Rev2 chips indicate errors - * that we need to count. Checking for this + * GPIO_3..5 on IBA6120 Rev2 and IBA6110 Rev4 chips indicate + * errors that we need to count. Checking for this * is controlled by flag IPATH_GPIO_ERRINTRS. */ u32 gpiostatus; -- cgit v1.2.3-70-g09d2 From 40558dafff257d69248af8b96c7e896f6bc79dfa Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 27 Aug 2007 07:37:34 -0300 Subject: V4L/DVB (6259): Fix vivi poll() method Due to the replace of videobuf_read_one to videobuf_read_stream, poll() method implementation is wrong. This fixes poll() implementation, making read of /dev/video? to work again. With this method, an USB driver can use video-buf, without needing to request memory from the DMA-safe area. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vivi.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index c14e2b3e424..01c97767131 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -1122,9 +1122,8 @@ vivi_poll(struct file *file, struct poll_table_struct *wait) } else { dprintk(1,"poll: read() interface\n"); /* read() capture */ - buf = (struct vivi_buffer*)fh->vb_vidq.read_buf; - if (NULL == buf) - return POLLERR; + return videobuf_poll_stream(file, &fh-> vb_vidq, + wait); } poll_wait(file, &buf->vb.done, wait); if (buf->vb.state == STATE_DONE || -- cgit v1.2.3-70-g09d2 From 28318c72adc14952d05d8037d73cec852247791c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 2 Oct 2007 11:16:16 -0300 Subject: V4L/DVB (6260): Fix Kconfig dependency Thanks to Michael Krufky for pointing this to me. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 2 +- drivers/media/video/cx23885/Kconfig | 4 ++-- drivers/media/video/cx88/Kconfig | 2 +- drivers/media/video/saa7134/Kconfig | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index fc3ea4c67cc..e705265909d 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -138,7 +138,7 @@ config VIDEOBUF_VMALLOC select VIDEOBUF_GEN tristate -config VIDEO_BUF_DVB +config VIDEOBUF_DVB tristate config VIDEO_BTCX diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig index ebfcc7c2a89..af60700da8c 100644 --- a/drivers/media/video/cx23885/Kconfig +++ b/drivers/media/video/cx23885/Kconfig @@ -4,11 +4,11 @@ config VIDEO_CX23885 select I2C_ALGOBIT select FW_LOADER select VIDEO_BTCX - select VIDEO_BUF + select VIDEOBUF select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEO_IR - select VIDEO_BUF_DVB + select VIDEOBUF_DVB select DVB_TUNER_MT2131 if !DVB_FE_CUSTOMISE select DVB_S5H1409 if !DVB_FE_CUSTOMISE select DVB_PLL if !DVB_FE_CUSTOMISE diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig index c68ba74d44e..eeb5224ca10 100644 --- a/drivers/media/video/cx88/Kconfig +++ b/drivers/media/video/cx88/Kconfig @@ -46,7 +46,7 @@ config VIDEO_CX88_BLACKBIRD config VIDEO_CX88_DVB tristate "DVB/ATSC Support for cx2388x based TV cards" depends on VIDEO_CX88 && DVB_CORE - select VIDEO_BUF_DVB + select VIDEOBUF_DVB select DVB_PLL if !DVB_FE_CUSTOMISE select DVB_MT352 if !DVB_FE_CUSTOMISE select DVB_ZL10353 if !DVB_FE_CUSTOMISE diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig index 82bc4ef414a..d6d8d660196 100644 --- a/drivers/media/video/saa7134/Kconfig +++ b/drivers/media/video/saa7134/Kconfig @@ -38,7 +38,7 @@ config VIDEO_SAA7134_OSS config VIDEO_SAA7134_DVB tristate "DVB/ATSC Support for saa7134 based TV cards" depends on VIDEO_SAA7134 && DVB_CORE - select VIDEO_BUF_DVB + select VIDEOBUF_DVB select FW_LOADER select DVB_PLL if !DVB_FE_CUSTOMISE select DVB_MT352 if !DVB_FE_CUSTOMISE -- cgit v1.2.3-70-g09d2 From c520a4970c7e5f18275ef935372e56eabd6d0e44 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 6 Sep 2007 18:55:07 -0300 Subject: V4L/DVB (6261): Cleans mem->vmalloc after vfree Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf-vmalloc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c index 993d5285e18..6ef4f523689 100644 --- a/drivers/media/video/videobuf-vmalloc.c +++ b/drivers/media/video/videobuf-vmalloc.c @@ -372,6 +372,7 @@ void videobuf_vmalloc_free (struct videobuf_buffer *buf) MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); vfree(mem->vmalloc); + mem->vmalloc=NULL; return; } -- cgit v1.2.3-70-g09d2 From e78dcf55520769471c66024b13df7e9e592436f4 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 6 Sep 2007 19:08:24 -0300 Subject: V4L/DVB (6262): An allocation error message were being printed as a debug msg Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf-vmalloc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c index 6ef4f523689..b2abfc9d9a8 100644 --- a/drivers/media/video/videobuf-vmalloc.c +++ b/drivers/media/video/videobuf-vmalloc.c @@ -140,7 +140,6 @@ static int __videobuf_iolock (struct videobuf_queue* q, MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); - pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT; /* Currently, doesn't support V4L2_MEMORY_OVERLAY */ @@ -153,7 +152,7 @@ static int __videobuf_iolock (struct videobuf_queue* q, /* FIXME: should be tested with kernel mmap mem */ mem->vmalloc=vmalloc_user (PAGE_ALIGN(vb->size)); if (NULL == mem->vmalloc) { - dprintk(1,"vmalloc (%d pages) failed\n",pages); + printk(KERN_ERR "vmalloc (%d pages) failed\n",pages); return -ENOMEM; } -- cgit v1.2.3-70-g09d2 From 123f8ef64e3996e06a930756b6b2cdede4b18da0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 6 Sep 2007 20:11:35 -0300 Subject: V4L/DVB (6263): Fix buffer release code Release code should happen before the cleaning of map variable. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf-vmalloc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c index b2abfc9d9a8..fd059cde63f 100644 --- a/drivers/media/video/videobuf-vmalloc.c +++ b/drivers/media/video/videobuf-vmalloc.c @@ -84,9 +84,11 @@ videobuf_vm_close(struct vm_area_struct *vma) if (mem->map != map) continue; + + q->ops->buf_release(q,q->bufs[i]); + mem->map = NULL; q->bufs[i]->baddr = 0; - q->ops->buf_release(q,q->bufs[i]); } mutex_unlock(&q->lock); kfree(map); -- cgit v1.2.3-70-g09d2 From 3bef5e4a1f73898dc8c8433f938d3a8b22f2be22 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 22 Sep 2007 02:01:33 -0300 Subject: V4L/DVB (6264): Make the vertical lines to move While this is not the standard color bar behaviour, having some movement there allows to check if buffers are being properly handled. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vivi.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 01c97767131..650e959aeb7 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -229,9 +229,8 @@ static u8 bars[8][3] = { #define TSTAMP_MAX_Y TSTAMP_MIN_Y+15 #define TSTAMP_MIN_X 64 - static void gen_line(char *basep,int inipos,int wmax, - int hmax, int line, char *timestr) + int hmax, int line, int count, char *timestr) { int w,i,j,pos=inipos,y; char *p,*s; @@ -242,9 +241,10 @@ static void gen_line(char *basep,int inipos,int wmax, /* Generate a standard color bar pattern */ for (w=0;wvb); + /* FIXME: move to dev struct */ + static int mv_count=0; if (!tmpbuf) return; for (h=0;htimestr); + gen_line(tmpbuf,0,wmax,hmax,h,mv_count, + dev->timestr); /* FIXME: replacing to __copy_to_user */ if (copy_to_user(vbuf+pos,tmpbuf,wmax*2)!=0) dprintk(2,"vivifill copy_to_user failed.\n"); pos += wmax*2; } + mv_count++; + kfree(tmpbuf); /* Updates stream time */ -- cgit v1.2.3-70-g09d2 From cd4765efdd816ac14075fc7d5adf489502e75e1e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 25 Sep 2007 11:53:24 -0300 Subject: V4L/DVB (6265): Prevent for calling mmap_free without an allocated buffer Signed-off-by: Mauro Carvalho Chehab http://thread.gmane.org/gmane.comp.video.video4linux/34978/focus=34981 Reviewed-by: Ricardo Cerqueira --- drivers/media/video/videobuf-core.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index 256501384af..eb3b98400c1 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c @@ -880,6 +880,9 @@ int videobuf_mmap_free(struct videobuf_queue *q) int i; int rc; + if (!q) + return 0; + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); rc = CALL(q,mmap_free,q); -- cgit v1.2.3-70-g09d2 From 851c0c96b2212f48fe51afc1589541b5eae3a544 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 27 Sep 2007 18:25:44 -0300 Subject: V4L/DVB (6266): videobuf cleanup: mmap check is common to all videobuf. Make it at core Signed-off-by: Mauro Carvalho Chehab http://thread.gmane.org/gmane.comp.video.video4linux/34978/focus=34981 Reviewed-by: Ricardo Cerqueira --- drivers/media/video/videobuf-core.c | 4 ++-- drivers/media/video/videobuf-dma-sg.c | 24 +++++------------------ drivers/media/video/videobuf-vmalloc.c | 36 ++++++++++------------------------ include/media/videobuf-core.h | 4 +++- include/media/videobuf-dma-sg.h | 1 - include/media/videobuf-vmalloc.h | 3 --- 6 files changed, 20 insertions(+), 52 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index eb3b98400c1..3bd06bb633a 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c @@ -149,7 +149,7 @@ int videobuf_queue_is_busy(struct videobuf_queue *q) for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (NULL == q->bufs[i]) continue; - if (CALL(q,is_mmapped,q->bufs[i])) { + if (q->bufs[i]->map) { dprintk(1,"busy: buffer #%d mapped\n",i); return 1; } @@ -238,7 +238,7 @@ static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b, } b->flags = 0; - if (CALL(q,is_mmapped,vb)) + if (vb->map) b->flags |= V4L2_BUF_FLAG_MAPPED; switch (vb->state) { diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c index 3345877c47d..0939ede831a 100644 --- a/drivers/media/video/videobuf-dma-sg.c +++ b/drivers/media/video/videobuf-dma-sg.c @@ -374,9 +374,9 @@ videobuf_vm_close(struct vm_area_struct *vma) MAGIC_CHECK(mem->magic,MAGIC_SG_MEM); - if (mem->map != map) + if (q->bufs[i]->map != map) continue; - mem->map = NULL; + q->bufs[i]->map = NULL; q->bufs[i]->baddr = 0; q->ops->buf_release(q,q->bufs[i]); } @@ -520,8 +520,7 @@ static int __videobuf_mmap_free(struct videobuf_queue *q) for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (q->bufs[i]) { - struct videbuf_pci_sg_memory *mem=q->bufs[i]->priv; - if (mem && mem->map) + if (q->bufs[i]->map) return -EBUSY; } } @@ -572,8 +571,7 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, continue; if (V4L2_MEMORY_MMAP != q->bufs[last]->memory) continue; - mem=q->bufs[last]->priv; - if (mem->map) { + if (q->bufs[last]->map) { retval = -EBUSY; goto done; } @@ -593,8 +591,7 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, if (NULL == map) goto done; for (size = 0, i = first; i <= last; size += q->bufs[i++]->bsize) { - mem=q->bufs[i]->priv; - mem->map = map; + q->bufs[i]->map = map; q->bufs[i]->baddr = vma->vm_start + size; } map->count = 1; @@ -613,16 +610,6 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, return retval; } -static int __videobuf_is_mmapped (struct videobuf_buffer *buf) -{ - struct videbuf_pci_sg_memory *mem=buf->priv; - - BUG_ON (!mem); - MAGIC_CHECK(mem->magic,MAGIC_SG_MEM); - - return (mem->map)?1:0; -} - static int __videobuf_copy_to_user ( struct videobuf_queue *q, char __user *data, size_t count, int nonblocking ) @@ -678,7 +665,6 @@ static struct videobuf_qtype_ops pci_ops = { .sync = __videobuf_sync, .mmap_free = __videobuf_mmap_free, .mmap_mapper = __videobuf_mmap_mapper, - .is_mmapped = __videobuf_is_mmapped, .copy_to_user = __videobuf_copy_to_user, .copy_stream = __videobuf_copy_stream, }; diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c index fd059cde63f..c9d6ae0d3b4 100644 --- a/drivers/media/video/videobuf-vmalloc.c +++ b/drivers/media/video/videobuf-vmalloc.c @@ -62,7 +62,6 @@ videobuf_vm_close(struct vm_area_struct *vma) { struct videobuf_mapping *map = vma->vm_private_data; struct videobuf_queue *q = map->q; - struct videbuf_vmalloc_memory *mem; int i; dprintk(2,"vm_close %p [count=%d,vma=%08lx-%08lx]\n",map, @@ -75,19 +74,13 @@ videobuf_vm_close(struct vm_area_struct *vma) for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (NULL == q->bufs[i]) continue; - mem=q->bufs[i]->priv; - if (!mem) - continue; - - MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); - - if (mem->map != map) + if (q->bufs[i]->map != map) continue; q->ops->buf_release(q,q->bufs[i]); - mem->map = NULL; + q->bufs[i]->map = NULL; q->bufs[i]->baddr = 0; } mutex_unlock(&q->lock); @@ -191,8 +184,7 @@ static int __videobuf_mmap_free(struct videobuf_queue *q) for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (q->bufs[i]) { - struct videbuf_vmalloc_memory *mem=q->bufs[i]->priv; - if (mem && mem->map) + if (q->bufs[i]->map) return -EBUSY; } } @@ -227,12 +219,9 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, (vma->vm_pgoff << PAGE_SHIFT)); return -EINVAL; } - mem=q->bufs[first]->priv; - BUG_ON (!mem); - MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); /* create mapping + update buffer list */ - map = mem->map = kmalloc(sizeof(struct videobuf_mapping),GFP_KERNEL); + map = q->bufs[first]->map = kmalloc(sizeof(struct videobuf_mapping),GFP_KERNEL); if (NULL == map) return -ENOMEM; @@ -246,14 +235,19 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED; vma->vm_private_data = map; + mem=q->bufs[first]->priv; + BUG_ON (!mem); + MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); + /* Try to remap memory */ retval=remap_vmalloc_range(vma, mem->vmalloc,0); if (retval<0) { dprintk(1,"mmap: postponing remap_vmalloc_range\n"); + mem->vma=kmalloc(sizeof(*vma),GFP_KERNEL); if (!mem->vma) { kfree(map); - mem->map=NULL; + q->bufs[first]->map=NULL; return -ENOMEM; } memcpy(mem->vma,vma,sizeof(*vma)); @@ -269,15 +263,6 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, return (0); } -static int __videobuf_is_mmapped (struct videobuf_buffer *buf) -{ - struct videbuf_vmalloc_memory *mem=buf->priv; - BUG_ON (!mem); - MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); - - return (mem->map)?1:0; -} - static int __videobuf_copy_to_user ( struct videobuf_queue *q, char __user *data, size_t count, int nonblocking ) @@ -335,7 +320,6 @@ static struct videobuf_qtype_ops qops = { .sync = __videobuf_sync, .mmap_free = __videobuf_mmap_free, .mmap_mapper = __videobuf_mmap_mapper, - .is_mmapped = __videobuf_is_mmapped, .copy_to_user = __videobuf_copy_to_user, .copy_stream = __videobuf_copy_stream, }; diff --git a/include/media/videobuf-core.h b/include/media/videobuf-core.h index 0ac21ae44f6..96949e31eaf 100644 --- a/include/media/videobuf-core.h +++ b/include/media/videobuf-core.h @@ -97,6 +97,9 @@ struct videobuf_buffer { /* buffer addr (userland ptr!) */ unsigned long baddr; + /* for mmap'ed buffers */ + struct videobuf_mapping *map; + /* Private pointer to allow specific methods to store their data */ int privsize; void *priv; @@ -143,7 +146,6 @@ struct videobuf_qtype_ops { int (*mmap_free) (struct videobuf_queue *q); int (*mmap_mapper) (struct videobuf_queue *q, struct vm_area_struct *vma); - int (*is_mmapped) (struct videobuf_buffer *buf); }; struct videobuf_queue { diff --git a/include/media/videobuf-dma-sg.h b/include/media/videobuf-dma-sg.h index 62a3709905f..206d9027b39 100644 --- a/include/media/videobuf-dma-sg.h +++ b/include/media/videobuf-dma-sg.h @@ -86,7 +86,6 @@ struct videbuf_pci_sg_memory u32 magic; /* for mmap'ed buffers */ - struct videobuf_mapping *map; struct videobuf_dmabuf dma; }; diff --git a/include/media/videobuf-vmalloc.h b/include/media/videobuf-vmalloc.h index 5fff68df668..26a8958d23d 100644 --- a/include/media/videobuf-vmalloc.h +++ b/include/media/videobuf-vmalloc.h @@ -21,9 +21,6 @@ struct videbuf_vmalloc_memory { u32 magic; - /* for mmap'ed buffers */ - struct videobuf_mapping *map; - void *vmalloc; /* remap_vmalloc_range seems to need to run after mmap() on some cases */ -- cgit v1.2.3-70-g09d2 From 9900132f3437e9373aa030cdb5bd2d5db15566e3 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Thu, 27 Sep 2007 20:34:09 -0300 Subject: V4L/DVB (6268): V4L: Fix a lock inversion in generic videobuf code videobuf_qbuf takes q->lock, and then calls q->ops->buf_prepare which by design in all drivers calls videobuf_iolock which calls videobuf_dma_init_user and this takes current->mm->mmap_sem on the other hand if user calls mumap from other thread, sys_munmap takes current->mm->mmap_sem and videobuf_vm_close takes q->lock Since this can occur only for V4L2_MEMORY_MMAP buffers, take current->mm->mmap_sem in qbuf, before q->lock, and don't take current->mm->mmap_sem videobuf_dma_init_user for those buffers Signed-off-by: Maxim Levitsky http://thread.gmane.org/gmane.comp.video.video4linux/34978/focus=34981 Reviewed-by: Ricardo Cerqueira Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf-core.c | 7 +++++++ drivers/media/video/videobuf-dma-sg.c | 32 +++++++++++++++++++++++++++----- 2 files changed, 34 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index 3bd06bb633a..a27e114cace 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c @@ -349,6 +349,9 @@ int videobuf_qbuf(struct videobuf_queue *q, MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + if (b->memory == V4L2_MEMORY_MMAP) + down_read(¤t->mm->mmap_sem); + mutex_lock(&q->lock); retval = -EBUSY; if (q->reading) { @@ -434,6 +437,10 @@ int videobuf_qbuf(struct videobuf_queue *q, done: mutex_unlock(&q->lock); + + if (b->memory == V4L2_MEMORY_MMAP) + up_read(¤t->mm->mmap_sem); + return retval; } diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c index 0939ede831a..05dd38343fa 100644 --- a/drivers/media/video/videobuf-dma-sg.c +++ b/drivers/media/video/videobuf-dma-sg.c @@ -134,8 +134,8 @@ void videobuf_dma_init(struct videobuf_dmabuf *dma) dma->magic = MAGIC_DMABUF; } -int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, - unsigned long data, unsigned long size) +static int videobuf_dma_init_user_locked(struct videobuf_dmabuf *dma, + int direction, unsigned long data, unsigned long size) { unsigned long first,last; int err, rw = 0; @@ -160,12 +160,12 @@ int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, dma->varea = (void *) data; - down_read(¤t->mm->mmap_sem); + err = get_user_pages(current,current->mm, data & PAGE_MASK, dma->nr_pages, rw == READ, 1, /* force */ dma->pages, NULL); - up_read(¤t->mm->mmap_sem); + if (err != dma->nr_pages) { dma->nr_pages = (err >= 0) ? err : 0; dprintk(1,"get_user_pages: err=%d [%d]\n",err,dma->nr_pages); @@ -174,6 +174,17 @@ int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, return 0; } +int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, + unsigned long data, unsigned long size) +{ + int ret; + down_read(¤t->mm->mmap_sem); + ret = videobuf_dma_init_user_locked(dma, direction, data, size); + up_read(¤t->mm->mmap_sem); + + return ret; +} + int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction, int nr_pages) { @@ -469,13 +480,24 @@ static int __videobuf_iolock (struct videobuf_queue* q, pages ); if (0 != err) return err; - } else { + } else if (vb->memory == V4L2_MEMORY_USERPTR) { /* dma directly to userspace */ err = videobuf_dma_init_user( &mem->dma, PCI_DMA_FROMDEVICE, vb->baddr,vb->bsize ); if (0 != err) return err; + } else { + /* NOTE: HACK: videobuf_iolock on V4L2_MEMORY_MMAP + buffers can only be called from videobuf_qbuf + we take current->mm->mmap_sem there, to prevent + locking inversion, so don't take it here */ + + err = videobuf_dma_init_user_locked(&mem->dma, + PCI_DMA_FROMDEVICE, + vb->baddr, vb->bsize); + if (0 != err) + return err; } break; case V4L2_MEMORY_OVERLAY: -- cgit v1.2.3-70-g09d2 From b4aeb8b8232bd80764997bf38f574f63e118c259 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Thu, 27 Sep 2007 20:34:15 -0300 Subject: V4L/DVB (6269): V4L: Fix a "scheduling while atomic" bug in saa7134 set_tvnorm can sleep in saa7134_i2c_xfer (it will be called through tuner code) but code calls it under spinlock. Fix that Signed-off-by: Maxim Levitsky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-video.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index cf40a9690a5..27c659cd0f3 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -1834,7 +1834,11 @@ static int video_do_ioctl(struct inode *inode, struct file *file, if (res_check(fh, RESOURCE_OVERLAY)) { spin_lock_irqsave(&dev->slock,flags); stop_preview(dev,fh); + spin_unlock_irqrestore(&dev->slock, flags); + set_tvnorm(dev,&tvnorms[i]); + + spin_lock_irqsave(&dev->slock, flags); start_preview(dev,fh); spin_unlock_irqrestore(&dev->slock,flags); } else -- cgit v1.2.3-70-g09d2 From f5a1ac64cc444cf19c8817d61a410b70bbb619d9 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Thu, 27 Sep 2007 20:34:20 -0300 Subject: V4L/DVB (6270): V4L: Honor dev->ctl_invert when setting up the decoder in saa7134 When user sets dev->ctl_invert, driver writes negative values to SAA7134_DEC_LUMA_CONTRAST and SAA7134_DEC_CHROMA_SATURATION, but general code that initializes decorder ignores that Signed-off-by: Maxim Levitsky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-video.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 27c659cd0f3..525b5b77c13 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -584,9 +584,13 @@ static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) saa_writeb(SAA7134_SYNC_CTRL, sync_control); saa_writeb(SAA7134_LUMA_CTRL, luma_control); saa_writeb(SAA7134_DEC_LUMA_BRIGHT, dev->ctl_bright); - saa_writeb(SAA7134_DEC_LUMA_CONTRAST, dev->ctl_contrast); - saa_writeb(SAA7134_DEC_CHROMA_SATURATION, dev->ctl_saturation); + saa_writeb(SAA7134_DEC_LUMA_CONTRAST, + dev->ctl_invert ? -dev->ctl_contrast : dev->ctl_contrast); + + saa_writeb(SAA7134_DEC_CHROMA_SATURATION, + dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation); + saa_writeb(SAA7134_DEC_CHROMA_HUE, dev->ctl_hue); saa_writeb(SAA7134_CHROMA_CTRL1, norm->chroma_ctrl1); saa_writeb(SAA7134_CHROMA_GAIN, norm->chroma_gain); -- cgit v1.2.3-70-g09d2 From cb71201f20e43581857043a1f856fb61ce44bdf8 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Thu, 27 Sep 2007 20:34:25 -0300 Subject: V4L/DVB (6271): V4L: Add basic support for suspend/resume for saa7134 This adds support for suspend/resume for core of saa7134 Should fix bug#7220 Signed-off-by: Maxim Levitsky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-core.c | 175 +++++++++++++++++++++----- drivers/media/video/saa7134/saa7134-ts.c | 23 +++- drivers/media/video/saa7134/saa7134-tvaudio.c | 4 +- drivers/media/video/saa7134/saa7134-video.c | 125 +++++++++--------- drivers/media/video/saa7134/saa7134.h | 12 ++ 5 files changed, 244 insertions(+), 95 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index a1d986e01a3..7f5df32ed0e 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "saa7134-reg.h" #include "saa7134.h" @@ -392,6 +393,38 @@ void saa7134_buffer_timeout(unsigned long data) spin_unlock_irqrestore(&dev->slock,flags); } +/* resends a current buffer in queue after resume */ + +int saa7134_buffer_requeue(struct saa7134_dev *dev, + struct saa7134_dmaqueue *q) +{ + struct saa7134_buf *buf , *next; + unsigned long flags; + + spin_lock_irqsave(&dev->slock, flags); + + buf = q->curr; + next = buf; + + dprintk("buffer_requeue\n"); + + if (!buf) { + spin_unlock_irqrestore(&dev->slock, flags); + return 0; + } + + dprintk("buffer_requeue : resending active buffers \n"); + + if (!list_empty(&q->queue)) + next = list_entry(q->queue.next, struct saa7134_buf, + vb.queue); + + buf->activate(dev, buf, next); + spin_unlock_irqrestore(&dev->slock, flags); + + return 0; +} + /* ------------------------------------------------------------------ */ int saa7134_set_dmabits(struct saa7134_dev *dev) @@ -647,6 +680,39 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id) /* ------------------------------------------------------------------ */ /* early init (no i2c, no irq) */ + +static int saa7134_hw_enable1(struct saa7134_dev *dev) +{ + /* RAM FIFO config */ + saa_writel(SAA7134_FIFO_SIZE, 0x08070503); + saa_writel(SAA7134_THRESHOULD, 0x02020202); + + /* enable audio + video processing */ + saa_writel(SAA7134_MAIN_CTRL, + SAA7134_MAIN_CTRL_VPLLE | + SAA7134_MAIN_CTRL_APLLE | + SAA7134_MAIN_CTRL_EXOSC | + SAA7134_MAIN_CTRL_EVFE1 | + SAA7134_MAIN_CTRL_EVFE2 | + SAA7134_MAIN_CTRL_ESFE | + SAA7134_MAIN_CTRL_EBDAC); + + /* + * Initialize OSS _after_ enabling audio clock PLL and audio processing. + * OSS initialization writes to registers via the audio DSP; these + * writes will fail unless the audio clock has been started. At worst, + * audio will not work. + */ + + /* enable peripheral devices */ + saa_writeb(SAA7134_SPECIAL_MODE, 0x01); + + /* set vertical line numbering start (vbi needs this) */ + saa_writeb(SAA7134_SOURCE_TIMING2, 0x20); + + return 0; +} + static int saa7134_hwinit1(struct saa7134_dev *dev) { dprintk("hwinit1\n"); @@ -663,44 +729,16 @@ static int saa7134_hwinit1(struct saa7134_dev *dev) saa7134_ts_init1(dev); saa7134_input_init1(dev); - /* RAM FIFO config */ - saa_writel(SAA7134_FIFO_SIZE, 0x08070503); - saa_writel(SAA7134_THRESHOULD,0x02020202); - - /* enable audio + video processing */ - saa_writel(SAA7134_MAIN_CTRL, - SAA7134_MAIN_CTRL_VPLLE | - SAA7134_MAIN_CTRL_APLLE | - SAA7134_MAIN_CTRL_EXOSC | - SAA7134_MAIN_CTRL_EVFE1 | - SAA7134_MAIN_CTRL_EVFE2 | - SAA7134_MAIN_CTRL_ESFE | - SAA7134_MAIN_CTRL_EBDAC); - - /* - * Initialize OSS _after_ enabling audio clock PLL and audio processing. - * OSS initialization writes to registers via the audio DSP; these - * writes will fail unless the audio clock has been started. At worst, - * audio will not work. - */ - - /* enable peripheral devices */ - saa_writeb(SAA7134_SPECIAL_MODE, 0x01); - - /* set vertical line numbering start (vbi needs this) */ - saa_writeb(SAA7134_SOURCE_TIMING2, 0x20); + saa7134_hw_enable1(dev); return 0; } /* late init (with i2c + irq) */ -static int saa7134_hwinit2(struct saa7134_dev *dev) +static int saa7134_hw_enable2(struct saa7134_dev *dev) { - unsigned int irq2_mask; - dprintk("hwinit2\n"); - saa7134_video_init2(dev); - saa7134_tvaudio_init2(dev); + unsigned int irq2_mask; /* enable IRQ's */ irq2_mask = @@ -726,6 +764,20 @@ static int saa7134_hwinit2(struct saa7134_dev *dev) return 0; } +static int saa7134_hwinit2(struct saa7134_dev *dev) +{ + + dprintk("hwinit2\n"); + + saa7134_video_init2(dev); + saa7134_tvaudio_init2(dev); + + saa7134_hw_enable2(dev); + + return 0; +} + + /* shutdown */ static int saa7134_hwfini(struct saa7134_dev *dev) { @@ -1118,6 +1170,65 @@ static void __devexit saa7134_finidev(struct pci_dev *pci_dev) kfree(dev); } +static int saa7134_suspend(struct pci_dev *pci_dev , pm_message_t state) +{ + + /* Disable card's IRQs to prevent it from resuming computer */ + + struct saa7134_dev *dev = pci_get_drvdata(pci_dev); + + saa_writel(SAA7134_IRQ1, 0); + saa_writel(SAA7134_IRQ2, 0); + + + pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state)); + pci_save_state(pci_dev); + + return 0; +} + +static int saa7134_resume(struct pci_dev *pci_dev) +{ + + struct saa7134_dev *dev = pci_get_drvdata(pci_dev); + + pci_restore_state(pci_dev); + pci_set_power_state(pci_dev, PCI_D0); + + /* Do things that are done in saa7134_initdev , + except of initializing memory structures.*/ + + saa7134_board_init1(dev); + + if (saa7134_boards[dev->board].video_out) + saa7134_videoport_init(dev); + + if (card_has_mpeg(dev)) + saa7134_ts_init_hw(dev); + + saa7134_hw_enable1(dev); + + saa7134_set_decoder(dev); + + saa7134_i2c_call_clients(dev, VIDIOC_S_STD, &dev->tvnorm->id); + + saa7134_board_init2(dev); + saa7134_hw_enable2(dev); + + dev->force_mute_update = 1; + saa7134_tvaudio_setmute(dev); + dev->force_mute_update = 0; + saa7134_tvaudio_setvolume(dev, dev->ctl_volume); + saa7134_enable_i2s(dev); + + /*recapture unfinished buffer(s)*/ + saa7134_buffer_requeue(dev, &dev->video_q); + saa7134_buffer_requeue(dev, &dev->vbi_q); + saa7134_buffer_requeue(dev, &dev->ts_q); + + return 0; +} + /* ----------------------------------------------------------- */ int saa7134_ts_register(struct saa7134_mpeg_ops *ops) @@ -1159,6 +1270,8 @@ static struct pci_driver saa7134_pci_driver = { .id_table = saa7134_pci_tbl, .probe = saa7134_initdev, .remove = __devexit_p(saa7134_finidev), + .suspend = saa7134_suspend, + .resume = saa7134_resume }; static int saa7134_init(void) diff --git a/drivers/media/video/saa7134/saa7134-ts.c b/drivers/media/video/saa7134/saa7134-ts.c index 5b1d1dafb5a..4b63ad3e846 100644 --- a/drivers/media/video/saa7134/saa7134-ts.c +++ b/drivers/media/video/saa7134/saa7134-ts.c @@ -177,6 +177,22 @@ static unsigned int ts_nr_packets = 64; module_param(ts_nr_packets, int, 0444); MODULE_PARM_DESC(ts_nr_packets,"size of a ts buffers (in ts packets)"); +int saa7134_ts_init_hw(struct saa7134_dev *dev) +{ + /* deactivate TS softreset */ + saa_writeb(SAA7134_TS_SERIAL1, 0x00); + /* TSSOP high active, TSVAL high active, TSLOCK ignored */ + saa_writeb(SAA7134_TS_PARALLEL, 0xec); + saa_writeb(SAA7134_TS_PARALLEL_SERIAL, (TS_PACKET_SIZE-1)); + saa_writeb(SAA7134_TS_DMA0, ((dev->ts.nr_packets-1)&0xff)); + saa_writeb(SAA7134_TS_DMA1, (((dev->ts.nr_packets-1)>>8)&0xff)); + /* TSNOPIT=0, TSCOLAP=0 */ + saa_writeb(SAA7134_TS_DMA2, + ((((dev->ts.nr_packets-1)>>16)&0x3f) | 0x00)); + + return 0; +} + int saa7134_ts_init1(struct saa7134_dev *dev) { /* sanitycheck insmod options */ @@ -200,12 +216,7 @@ int saa7134_ts_init1(struct saa7134_dev *dev) saa7134_pgtable_alloc(dev->pci,&dev->ts.pt_ts); /* init TS hw */ - saa_writeb(SAA7134_TS_SERIAL1, 0x00); /* deactivate TS softreset */ - saa_writeb(SAA7134_TS_PARALLEL, 0xec); /* TSSOP high active, TSVAL high active, TSLOCK ignored */ - saa_writeb(SAA7134_TS_PARALLEL_SERIAL, (TS_PACKET_SIZE-1)); - saa_writeb(SAA7134_TS_DMA0, ((dev->ts.nr_packets-1)&0xff)); - saa_writeb(SAA7134_TS_DMA1, (((dev->ts.nr_packets-1)>>8)&0xff)); - saa_writeb(SAA7134_TS_DMA2, ((((dev->ts.nr_packets-1)>>16)&0x3f) | 0x00)); /* TSNOPIT=0, TSCOLAP=0 */ + saa7134_ts_init_hw(dev); return 0; } diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c index 43501b5dc05..df2dab06387 100644 --- a/drivers/media/video/saa7134/saa7134-tvaudio.c +++ b/drivers/media/video/saa7134/saa7134-tvaudio.c @@ -231,7 +231,7 @@ static void mute_input_7134(struct saa7134_dev *dev) } if (dev->hw_mute == mute && - dev->hw_input == in) { + dev->hw_input == in && !dev->force_mute_update) { dprintk("mute/input: nothing to do [mute=%d,input=%s]\n", mute,in->name); return; @@ -876,7 +876,7 @@ static int tvaudio_thread_ddep(void *data) /* ------------------------------------------------------------------ */ /* common stuff + external entry points */ -static void saa7134_enable_i2s(struct saa7134_dev *dev) +void saa7134_enable_i2s(struct saa7134_dev *dev) { int i2s_format; diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 525b5b77c13..24d579723b5 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -540,22 +540,12 @@ void res_free(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int bits) /* ------------------------------------------------------------------ */ -static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) +void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) { - int luma_control,sync_control,mux; dprintk("set tv norm = %s\n",norm->name); dev->tvnorm = norm; - mux = card_in(dev,dev->ctl_input).vmux; - luma_control = norm->luma_control; - sync_control = norm->sync_control; - - if (mux > 5) - luma_control |= 0x80; /* svideo */ - if (noninterlaced || dev->nosignal) - sync_control |= 0x20; - /* setup cropping */ dev->crop_bounds.left = norm->h_start; dev->crop_defrect.left = norm->h_start; @@ -570,6 +560,40 @@ static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) dev->crop_current = dev->crop_defrect; + saa7134_set_decoder(dev); + + if (card_in(dev, dev->ctl_input).tv) { + if ((card(dev).tuner_type == TUNER_PHILIPS_TDA8290) + && ((card(dev).tuner_config == 1) + || (card(dev).tuner_config == 2))) + saa7134_set_gpio(dev, 22, 5); + saa7134_i2c_call_clients(dev, VIDIOC_S_STD, &norm->id); + } +} + +static void video_mux(struct saa7134_dev *dev, int input) +{ + dprintk("video input = %d [%s]\n", input, card_in(dev, input).name); + dev->ctl_input = input; + set_tvnorm(dev, dev->tvnorm); + saa7134_tvaudio_setinput(dev, &card_in(dev, input)); +} + +void saa7134_set_decoder(struct saa7134_dev *dev) +{ + int luma_control, sync_control, mux; + + struct saa7134_tvnorm *norm = dev->tvnorm; + mux = card_in(dev, dev->ctl_input).vmux; + + luma_control = norm->luma_control; + sync_control = norm->sync_control; + + if (mux > 5) + luma_control |= 0x80; /* svideo */ + if (noninterlaced || dev->nosignal) + sync_control |= 0x20; + /* setup video decoder */ saa_writeb(SAA7134_INCR_DELAY, 0x08); saa_writeb(SAA7134_ANALOG_IN_CTRL1, 0xc0 | mux); @@ -604,23 +628,6 @@ static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) saa_writeb(SAA7134_MISC_VGATE_MSB, norm->vgate_misc); saa_writeb(SAA7134_RAW_DATA_GAIN, 0x40); saa_writeb(SAA7134_RAW_DATA_OFFSET, 0x80); - - /* only tell the tuner if this is a tv input */ - if (card_in(dev,dev->ctl_input).tv) { - if ((card(dev).tuner_type == TUNER_PHILIPS_TDA8290) - && ((card(dev).tuner_config == 1) - || (card(dev).tuner_config == 2))) - saa7134_set_gpio(dev, 22, 5); - saa7134_i2c_call_clients(dev,VIDIOC_S_STD,&norm->id); - } -} - -static void video_mux(struct saa7134_dev *dev, int input) -{ - dprintk("video input = %d [%s]\n",input,card_in(dev,input).name); - dev->ctl_input = input; - set_tvnorm(dev,dev->tvnorm); - saa7134_tvaudio_setinput(dev,&card_in(dev,input)); } static void set_h_prescale(struct saa7134_dev *dev, int task, int prescale) @@ -2399,34 +2406,40 @@ int saa7134_video_init1(struct saa7134_dev *dev) dev->video_q.timeout.data = (unsigned long)(&dev->video_q); dev->video_q.dev = dev; - if (saa7134_boards[dev->board].video_out) { - /* enable video output */ - int vo = saa7134_boards[dev->board].video_out; - int video_reg; - unsigned int vid_port_opts = saa7134_boards[dev->board].vid_port_opts; - saa_writeb(SAA7134_VIDEO_PORT_CTRL0, video_out[vo][0]); - video_reg = video_out[vo][1]; - if (vid_port_opts & SET_T_CODE_POLARITY_NON_INVERTED) - video_reg &= ~VP_T_CODE_P_INVERTED; - saa_writeb(SAA7134_VIDEO_PORT_CTRL1, video_reg); - saa_writeb(SAA7134_VIDEO_PORT_CTRL2, video_out[vo][2]); - saa_writeb(SAA7134_VIDEO_PORT_CTRL3, video_out[vo][3]); - saa_writeb(SAA7134_VIDEO_PORT_CTRL4, video_out[vo][4]); - video_reg = video_out[vo][5]; - if (vid_port_opts & SET_CLOCK_NOT_DELAYED) - video_reg &= ~VP_CLK_CTRL2_DELAYED; - if (vid_port_opts & SET_CLOCK_INVERTED) - video_reg |= VP_CLK_CTRL1_INVERTED; - saa_writeb(SAA7134_VIDEO_PORT_CTRL5, video_reg); - video_reg = video_out[vo][6]; - if (vid_port_opts & SET_VSYNC_OFF) { - video_reg &= ~VP_VS_TYPE_MASK; - video_reg |= VP_VS_TYPE_OFF; - } - saa_writeb(SAA7134_VIDEO_PORT_CTRL6, video_reg); - saa_writeb(SAA7134_VIDEO_PORT_CTRL7, video_out[vo][7]); - saa_writeb(SAA7134_VIDEO_PORT_CTRL8, video_out[vo][8]); - } + if (saa7134_boards[dev->board].video_out) + saa7134_videoport_init(dev); + + return 0; +} + +int saa7134_videoport_init(struct saa7134_dev *dev) +{ + /* enable video output */ + int vo = saa7134_boards[dev->board].video_out; + int video_reg; + unsigned int vid_port_opts = saa7134_boards[dev->board].vid_port_opts; + saa_writeb(SAA7134_VIDEO_PORT_CTRL0, video_out[vo][0]); + video_reg = video_out[vo][1]; + if (vid_port_opts & SET_T_CODE_POLARITY_NON_INVERTED) + video_reg &= ~VP_T_CODE_P_INVERTED; + saa_writeb(SAA7134_VIDEO_PORT_CTRL1, video_reg); + saa_writeb(SAA7134_VIDEO_PORT_CTRL2, video_out[vo][2]); + saa_writeb(SAA7134_VIDEO_PORT_CTRL3, video_out[vo][3]); + saa_writeb(SAA7134_VIDEO_PORT_CTRL4, video_out[vo][4]); + video_reg = video_out[vo][5]; + if (vid_port_opts & SET_CLOCK_NOT_DELAYED) + video_reg &= ~VP_CLK_CTRL2_DELAYED; + if (vid_port_opts & SET_CLOCK_INVERTED) + video_reg |= VP_CLK_CTRL1_INVERTED; + saa_writeb(SAA7134_VIDEO_PORT_CTRL5, video_reg); + video_reg = video_out[vo][6]; + if (vid_port_opts & SET_VSYNC_OFF) { + video_reg &= ~VP_VS_TYPE_MASK; + video_reg |= VP_VS_TYPE_OFF; + } + saa_writeb(SAA7134_VIDEO_PORT_CTRL6, video_reg); + saa_writeb(SAA7134_VIDEO_PORT_CTRL7, video_out[vo][7]); + saa_writeb(SAA7134_VIDEO_PORT_CTRL8, video_out[vo][8]); return 0; } diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index cb617c8dbb7..5b1f2260655 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -522,6 +522,7 @@ struct saa7134_dev { struct saa7134_input *input; struct saa7134_input *hw_input; unsigned int hw_mute; + unsigned int force_mute_update; int last_carrier; int nosignal; @@ -594,6 +595,9 @@ void saa7134_buffer_next(struct saa7134_dev *dev, struct saa7134_dmaqueue *q); void saa7134_buffer_timeout(unsigned long data); void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf); +int saa7134_buffer_requeue(struct saa7134_dev *dev, + struct saa7134_dmaqueue *q); + int saa7134_set_dmabits(struct saa7134_dev *dev); extern int (*saa7134_dmasound_init)(struct saa7134_dev *dev); @@ -626,6 +630,10 @@ void saa7134_i2c_call_clients(struct saa7134_dev *dev, extern struct video_device saa7134_video_template; extern struct video_device saa7134_radio_template; +void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm); +int saa7134_videoport_init(struct saa7134_dev *dev); +void saa7134_set_decoder(struct saa7134_dev *dev); + int saa7134_common_ioctl(struct saa7134_dev *dev, unsigned int cmd, void *arg); @@ -649,6 +657,8 @@ void saa7134_irq_ts_done(struct saa7134_dev *dev, unsigned long status); int saa7134_ts_register(struct saa7134_mpeg_ops *ops); void saa7134_ts_unregister(struct saa7134_mpeg_ops *ops); +int saa7134_ts_init_hw(struct saa7134_dev *dev); + /* ----------------------------------------------------------- */ /* saa7134-vbi.c */ @@ -677,6 +687,8 @@ int saa7134_tvaudio_do_scan(struct saa7134_dev *dev); int saa_dsp_writel(struct saa7134_dev *dev, int reg, u32 value); +void saa7134_enable_i2s(struct saa7134_dev *dev); + /* ----------------------------------------------------------- */ /* saa7134-oss.c */ -- cgit v1.2.3-70-g09d2 From 11f7078c10944437b6cf335cea50ed7da675a8b1 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Thu, 27 Sep 2007 20:44:39 -0300 Subject: V4L/DVB (6272): V4L: properly fix support for capturing interlaced video in saa7134 By "capturing interlaced video" I mean that card ensures that top field is really top and vice versa (I think it takes the filed ID from signal) Properly turn on/off that support depending on signal state Signed-off-by: Maxim Levitsky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-core.c | 8 +++++--- drivers/media/video/saa7134/saa7134-video.c | 16 ++++++++++------ drivers/media/video/saa7134/saa7134.h | 2 +- 3 files changed, 16 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index 7f5df32ed0e..fae0bfe7939 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -594,8 +594,10 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id) print_irqstatus(dev,loop,report,status); - if (report & SAA7134_IRQ_REPORT_RDCAP /* _INTL */) - saa7134_irq_video_intl(dev); + if ((report & SAA7134_IRQ_REPORT_RDCAP) || + (report & SAA7134_IRQ_REPORT_INTL)) + saa7134_irq_video_signalchange(dev); + if ((report & SAA7134_IRQ_REPORT_DONE_RA0) && (status & 0x60) == 0) @@ -1081,7 +1083,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, mutex_unlock(&devlist_lock); /* check for signal */ - saa7134_irq_video_intl(dev); + saa7134_irq_video_signalchange(dev); if (saa7134_dmasound_init && !dev->dmasound.priv_data) { saa7134_dmasound_init(dev); diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 24d579723b5..7c97ac15e66 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -40,7 +40,7 @@ static unsigned int video_debug = 0; static unsigned int gbuffers = 8; -static unsigned int noninterlaced = 1; +static unsigned int noninterlaced = 0; static unsigned int gbufsize = 720*576*4; static unsigned int gbufsize_max = 720*576*4; static char secam[] = "--"; @@ -2454,7 +2454,7 @@ int saa7134_video_init2(struct saa7134_dev *dev) return 0; } -void saa7134_irq_video_intl(struct saa7134_dev *dev) +void saa7134_irq_video_signalchange(struct saa7134_dev *dev) { static const char *st[] = { "(no signal)", "NTSC", "PAL", "SECAM" }; @@ -2466,24 +2466,28 @@ void saa7134_irq_video_intl(struct saa7134_dev *dev) (st1 & 0x40) ? "not locked" : "locked", (st2 & 0x40) ? "no" : "yes", st[st1 & 0x03]); - dev->nosignal = (st1 & 0x40) || (st2 & 0x40); + dev->nosignal = (st1 & 0x40) || (st2 & 0x40) || !(st2 & 0x1); if (dev->nosignal) { /* no video signal -> mute audio */ if (dev->ctl_automute) dev->automute = 1; saa7134_tvaudio_setmute(dev); - saa_setb(SAA7134_SYNC_CTRL, 0x20); } else { /* wake up tvaudio audio carrier scan thread */ saa7134_tvaudio_do_scan(dev); - if (!noninterlaced) - saa_clearb(SAA7134_SYNC_CTRL, 0x20); } + + if ((st2 & 0x80) && !noninterlaced && !dev->nosignal) + saa_clearb(SAA7134_SYNC_CTRL, 0x20); + else + saa_setb(SAA7134_SYNC_CTRL, 0x20); + if (dev->mops && dev->mops->signal_change) dev->mops->signal_change(dev); } + void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status) { enum v4l2_field field; diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 5b1f2260655..745b750cd3f 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -639,7 +639,7 @@ int saa7134_common_ioctl(struct saa7134_dev *dev, int saa7134_video_init1(struct saa7134_dev *dev); int saa7134_video_init2(struct saa7134_dev *dev); -void saa7134_irq_video_intl(struct saa7134_dev *dev); +void saa7134_irq_video_signalchange(struct saa7134_dev *dev); void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status); -- cgit v1.2.3-70-g09d2 From a326ae1126fddd07728e854322e0c657c6b1fbda Mon Sep 17 00:00:00 2001 From: Brandon Philips Date: Thu, 27 Sep 2007 20:54:52 -0300 Subject: V4L/DVB (6273): V4L: vivi.c vidioc_try_fmt_cap() negotiate a valid field If the client provides V4L2_FIELD_ANY vivi should return a valid field :) Signed-off-by: Brandon Philips Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vivi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 650e959aeb7..512128a6f58 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -820,8 +820,7 @@ static int vidioc_try_fmt_cap (struct file *file, void *priv, field = f->fmt.pix.field; if (field == V4L2_FIELD_ANY) { -// field=V4L2_FIELD_INTERLACED; - field=V4L2_FIELD_SEQ_TB; + field=V4L2_FIELD_INTERLACED; } else if (V4L2_FIELD_INTERLACED != field) { dprintk(1,"Field type invalid.\n"); return -EINVAL; -- cgit v1.2.3-70-g09d2 From 85c7c70bc241d506dffc1879158f77f8aac69734 Mon Sep 17 00:00:00 2001 From: Brandon Philips Date: Thu, 27 Sep 2007 20:55:02 -0300 Subject: V4L/DVB (6274): V4L: vivi.c replace logic in vivi_poll with videobuf_poll_stream Since vivi is using videobuf_read_stream() it can use videobuf_poll_stream() now. Signed-off-by: Brandon Philips Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vivi.c | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 512128a6f58..cdef622f6b3 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -1111,29 +1111,14 @@ vivi_poll(struct file *file, struct poll_table_struct *wait) { struct vivi_fh *fh = file->private_data; struct vivi_buffer *buf; + struct videobuf_queue *q = &fh->vb_vidq; dprintk(1,"%s\n",__FUNCTION__); if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type) return POLLERR; - if (res_get(fh->dev,fh)) { - dprintk(1,"poll: mmap interface\n"); - /* streaming capture */ - if (list_empty(&fh->vb_vidq.stream)) - return POLLERR; - buf = list_entry(fh->vb_vidq.stream.next,struct vivi_buffer,vb.stream); - } else { - dprintk(1,"poll: read() interface\n"); - /* read() capture */ - return videobuf_poll_stream(file, &fh-> vb_vidq, - wait); - } - poll_wait(file, &buf->vb.done, wait); - if (buf->vb.state == STATE_DONE || - buf->vb.state == STATE_ERROR) - return POLLIN|POLLRDNORM; - return 0; + return videobuf_poll_stream(file, q, wait); } static int vivi_release(struct inode *inode, struct file *file) -- cgit v1.2.3-70-g09d2 From ba32bd95d431525ad2ffac97cadf9ee40b63939e Mon Sep 17 00:00:00 2001 From: Brandon Philips Date: Thu, 27 Sep 2007 20:55:17 -0300 Subject: V4L/DVB (6275): V4L: vivi.c remove the "resource" locking The "resource" locking in vivi isn't needed since streamon/streamoff/read_stream do mutual exclusion using q->reading/q->streaming. Plus it is sort of broken: a) res_locked() use in vivi_read() is racey. b) res_free() calls mutex_lock twice causing streamoff to break Signed-off-by: Brandon Philips Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vivi.c | 48 ++++------------------------------------------ 1 file changed, 4 insertions(+), 44 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index cdef622f6b3..82755091648 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -170,7 +170,6 @@ struct vivi_dev { int users; /* various device info */ - unsigned int resources; struct video_device vfd; struct vivi_dmaqueue vidq; @@ -726,40 +725,6 @@ static struct videobuf_queue_ops vivi_video_qops = { .buf_release = buffer_release, }; -/* ------------------------------------------------------------------ - IOCTL handling - ------------------------------------------------------------------*/ - - -static int res_get(struct vivi_dev *dev, struct vivi_fh *fh) -{ - /* is it free? */ - mutex_lock(&dev->lock); - if (dev->resources) { - /* no, someone else uses it */ - mutex_unlock(&dev->lock); - return 0; - } - /* it's free, grab it */ - dev->resources =1; - dprintk(1,"res: get\n"); - mutex_unlock(&dev->lock); - return 1; -} - -static int res_locked(struct vivi_dev *dev) -{ - return (dev->resources); -} - -static void res_free(struct vivi_dev *dev, struct vivi_fh *fh) -{ - mutex_lock(&dev->lock); - dev->resources = 0; - dprintk(1,"res: put\n"); - mutex_lock(&dev->lock); -} - /* ------------------------------------------------------------------ IOCTL vidioc handling ------------------------------------------------------------------*/ @@ -913,9 +878,7 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) if (i != fh->type) return -EINVAL; - if (!res_get(dev,fh)) - return -EBUSY; - return (videobuf_streamon(&fh->vb_vidq)); + return videobuf_streamon(&fh->vb_vidq); } static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) @@ -928,10 +891,7 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) if (i != fh->type) return -EINVAL; - videobuf_streamoff(&fh->vb_vidq); - res_free(dev,fh); - - return (0); + return videobuf_streamoff(&fh->vb_vidq); } static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *i) @@ -1096,10 +1056,10 @@ static ssize_t vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos) { struct vivi_fh *fh = file->private_data; + struct vivi_dev *dev = fh->dev; + struct videobuf_queue *q = &fh->vb_vidq; if (fh->type==V4L2_BUF_TYPE_VIDEO_CAPTURE) { - if (res_locked(fh->dev)) - return -EBUSY; return videobuf_read_stream(&fh->vb_vidq, data, count, ppos, 0, file->f_flags & O_NONBLOCK); } -- cgit v1.2.3-70-g09d2 From 00f98d0804c88c29bef81cb98c861f13c9b33f30 Mon Sep 17 00:00:00 2001 From: Brandon Philips Date: Thu, 27 Sep 2007 20:55:28 -0300 Subject: V4L/DVB (6276): V4L: videobuf-core.c lock before streaming check The reading/streaming fields are used for mutual exclusion of the queue and should be protected by the queue lock. Signed-off-by: Brandon Philips Signed-off-by: Mauro Carvalho Chehab http://thread.gmane.org/gmane.comp.video.video4linux/34978/focus=34981 Reviewed-by: Ricardo Cerqueira --- drivers/media/video/videobuf-core.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index a27e114cace..ca67f80184b 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c @@ -289,16 +289,18 @@ int videobuf_reqbufs(struct videobuf_queue *q, return -EINVAL; } + mutex_lock(&q->lock); if (q->streaming) { dprintk(1,"reqbufs: streaming already exists\n"); - return -EBUSY; + retval = -EBUSY; + goto done; } if (!list_empty(&q->stream)) { dprintk(1,"reqbufs: stream running\n"); - return -EBUSY; + retval = -EBUSY; + goto done; } - mutex_lock(&q->lock); count = req->count; if (count > VIDEO_MAX_FRAME) count = VIDEO_MAX_FRAME; -- cgit v1.2.3-70-g09d2 From 14f37aee299bf9a897516f5e33948ee1f014eae1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 27 Sep 2007 21:00:50 -0300 Subject: V4L/DVB (6277): vivi cleanup: remove the unused vars Vivi driver is now simpler. This patch removes the now unused vars. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vivi.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 82755091648..61a6608d6e6 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -871,7 +871,6 @@ static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf) static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) { struct vivi_fh *fh=priv; - struct vivi_dev *dev = fh->dev; if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; @@ -884,7 +883,6 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) { struct vivi_fh *fh=priv; - struct vivi_dev *dev = fh->dev; if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; @@ -1056,8 +1054,6 @@ static ssize_t vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos) { struct vivi_fh *fh = file->private_data; - struct vivi_dev *dev = fh->dev; - struct videobuf_queue *q = &fh->vb_vidq; if (fh->type==V4L2_BUF_TYPE_VIDEO_CAPTURE) { return videobuf_read_stream(&fh->vb_vidq, data, count, ppos, 0, @@ -1070,7 +1066,6 @@ static unsigned int vivi_poll(struct file *file, struct poll_table_struct *wait) { struct vivi_fh *fh = file->private_data; - struct vivi_buffer *buf; struct videobuf_queue *q = &fh->vb_vidq; dprintk(1,"%s\n",__FUNCTION__); -- cgit v1.2.3-70-g09d2 From d00cd2985e0e796621adf0f782af1563d990b0b5 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Tue, 2 Oct 2007 09:03:39 -0300 Subject: V4L/DVB (6278): Buf: fix typo that caused data loss when readng streams from device If videobuf_read_stream reads two or more buffers it was overwriting the first one Signed-off-by: Maxim Levitsky Signed-off-by: Mauro Carvalho Chehab http://thread.gmane.org/gmane.comp.video.video4linux/34978/focus=34981 Reviewed-by: Ricardo Cerqueira --- drivers/media/video/videobuf-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index ca67f80184b..8e4026e6fae 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c @@ -771,7 +771,7 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q, } if (q->read_buf->state == STATE_DONE) { - rc = CALL (q,copy_stream, q, data, count, + rc = CALL (q,copy_stream, q, data + retval, count, retval, vbihack, nonblocking); if (rc < 0) { retval = rc; -- cgit v1.2.3-70-g09d2 From 9320874a3e6aea7044a4a7eedeab13db990424ab Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 3 Oct 2007 11:23:01 -0300 Subject: V4L/DVB (6279): en_50221: convert to kthread API Here's an attempted update to the full kthread API + wake_up_process: Signed-off-by: Andrew Morton CC: Andrew de Quincey Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_ca_en50221.c | 84 ++++++----------------------- 1 file changed, 16 insertions(+), 68 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c index 5c7bcb8393d..084a508a03d 100644 --- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "dvb_ca_en50221.h" #include "dvb_ringbuffer.h" @@ -139,13 +140,7 @@ struct dvb_ca_private { wait_queue_head_t wait_queue; /* PID of the monitoring thread */ - pid_t thread_pid; - - /* Wait queue used when shutting thread down */ - wait_queue_head_t thread_queue; - - /* Flag indicating when thread should exit */ - unsigned int exit:1; + struct task_struct *thread; /* Flag indicating if the CA device is open */ unsigned int open:1; @@ -901,27 +896,9 @@ static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca) ca->wakeup = 1; mb(); - wake_up_interruptible(&ca->thread_queue); + wake_up_process(ca->thread); } -/** - * Used by the CA thread to determine if an early wakeup is necessary - * - * @param ca CA instance. - */ -static int dvb_ca_en50221_thread_should_wakeup(struct dvb_ca_private *ca) -{ - if (ca->wakeup) { - ca->wakeup = 0; - return 1; - } - if (ca->exit) - return 1; - - return 0; -} - - /** * Update the delay used by the thread. * @@ -981,7 +958,6 @@ static void dvb_ca_en50221_thread_update_delay(struct dvb_ca_private *ca) static int dvb_ca_en50221_thread(void *data) { struct dvb_ca_private *ca = data; - char name[15]; int slot; int flags; int status; @@ -990,28 +966,17 @@ static int dvb_ca_en50221_thread(void *data) dprintk("%s\n", __FUNCTION__); - /* setup kernel thread */ - snprintf(name, sizeof(name), "kdvb-ca-%i:%i", ca->dvbdev->adapter->num, ca->dvbdev->id); - - lock_kernel(); - daemonize(name); - sigfillset(¤t->blocked); - unlock_kernel(); - /* choose the correct initial delay */ dvb_ca_en50221_thread_update_delay(ca); /* main loop */ - while (!ca->exit) { + while (!kthread_should_stop()) { /* sleep for a bit */ - if (!ca->wakeup) { - flags = wait_event_interruptible_timeout(ca->thread_queue, - dvb_ca_en50221_thread_should_wakeup(ca), - ca->delay); - if ((flags == -ERESTARTSYS) || ca->exit) { - /* got signal or quitting */ - break; - } + while (!ca->wakeup) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(ca->delay); + if (kthread_should_stop()) + return 0; } ca->wakeup = 0; @@ -1180,10 +1145,6 @@ static int dvb_ca_en50221_thread(void *data) } } - /* completed */ - ca->thread_pid = 0; - mb(); - wake_up_interruptible(&ca->thread_queue); return 0; } @@ -1683,9 +1644,6 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, goto error; } init_waitqueue_head(&ca->wait_queue); - ca->thread_pid = 0; - init_waitqueue_head(&ca->thread_queue); - ca->exit = 0; ca->open = 0; ca->wakeup = 0; ca->next_read_slot = 0; @@ -1711,14 +1669,14 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, mb(); /* create a kthread for monitoring this CA device */ - - ret = kernel_thread(dvb_ca_en50221_thread, ca, 0); - - if (ret < 0) { - printk("dvb_ca_init: failed to start kernel_thread (%d)\n", ret); + ca->thread = kthread_run(dvb_ca_en50221_thread, ca, "kdvb-ca-%i:%i", + ca->dvbdev->adapter->num, ca->dvbdev->id); + if (IS_ERR(ca->thread)) { + ret = PTR_ERR(ca->thread); + printk("dvb_ca_init: failed to start kernel_thread (%d)\n", + ret); goto error; } - ca->thread_pid = ret; return 0; error: @@ -1749,17 +1707,7 @@ void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca) dprintk("%s\n", __FUNCTION__); /* shutdown the thread if there was one */ - if (ca->thread_pid) { - if (kill_proc(ca->thread_pid, 0, 1) == -ESRCH) { - printk("dvb_ca_release adapter %d: thread PID %d already died\n", - ca->dvbdev->adapter->num, ca->thread_pid); - } else { - ca->exit = 1; - mb(); - dvb_ca_en50221_thread_wakeup(ca); - wait_event_interruptible(ca->thread_queue, ca->thread_pid == 0); - } - } + kthread_stop(ca->thread); for (i = 0; i < ca->slot_count; i++) { dvb_ca_en50221_slot_shutdown(ca, i); -- cgit v1.2.3-70-g09d2 From 5a3ebe8755e88cd765f75121665c0d38004f8f37 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Thu, 4 Oct 2007 04:54:11 -0300 Subject: V4L/DVB (6283): videobuf: Remove references to old Kconfig option name CONFIG_VIDEO_BUF_DVB became CONFIG_VIDEOBUF_DVB. But in these cases, it makes more sense to use CONFIG_VIDEO_SAA7134_DVB or CONFIG_VIDEO_CX88_DVB_MODULE depending on the driver. The reference in cx23885.h should just be removed, as the code there needs to be included if DVB is on or off. I do not think you can even compile the cx23885 driver without DVB. It's clearly just leftover from when the file was obvious copied from the cx88 driver (which is not mentioned in the copyright BTW). Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885.h | 2 -- drivers/media/video/cx88/cx88-i2c.c | 2 +- drivers/media/video/cx88/cx88.h | 6 +++--- drivers/media/video/saa7134/saa7134.h | 4 ++-- 4 files changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 45c47cd6070..3d4fae565e3 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -28,9 +28,7 @@ #include #include #include -#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE) #include -#endif #include "btcx-risc.h" #include "cx23885-reg.h" diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c index 6ae21750b2c..c8b1c50625f 100644 --- a/drivers/media/video/cx88/cx88-i2c.c +++ b/drivers/media/video/cx88/cx88-i2c.c @@ -145,7 +145,7 @@ void cx88_call_i2c_clients(struct cx88_core *core, unsigned int cmd, void *arg) if (0 != core->i2c_rc) return; -#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE) +#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE) if ( (core->dvbdev) && (core->dvbdev->dvb.frontend) ) { if (core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl) core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl(core->dvbdev->dvb.frontend, 1); diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index b3fe2d59cd1..42e0a9b8c55 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -31,7 +31,7 @@ #include #include #include -#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE) +#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE) #include #endif @@ -311,7 +311,7 @@ struct cx88_core { unsigned int tuner_formats; /* config info -- dvb */ -#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE) +#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE) int (*prev_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage); #endif @@ -458,7 +458,7 @@ struct cx8802_dev { int width; int height; -#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE) +#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE) /* for dvb only */ struct videobuf_dvb dvb; diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 745b750cd3f..064f3dbe695 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -41,7 +41,7 @@ #include #include #include -#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE) +#if defined(CONFIG_VIDEO_SAA7134_DVB) || defined(CONFIG_VIDEO_SAA7134_DVB_MODULE) #include #endif @@ -538,7 +538,7 @@ struct saa7134_dev { struct work_struct empress_workqueue; int empress_started; -#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE) +#if defined(CONFIG_VIDEO_SAA7134_DVB) || defined(CONFIG_VIDEO_SAA7134_DVB_MODULE) /* SAA7134_MPEG_DVB only */ struct videobuf_dvb dvb; int (*original_demod_sleep)(struct dvb_frontend* fe); -- cgit v1.2.3-70-g09d2 From 409d84f85a8d523ecd108cbe2c0e722682da95ff Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Thu, 4 Oct 2007 05:28:45 -0300 Subject: V4L/DVB (6284): cx23885: Update to new videobuf code cx23885 was still uses the old video-buf includes and code, which would only `work' if one happened to be compiling against a kernel that had the old headers. Even then, it wouldn't actually work, it would just compile without errors. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 10 ++++++---- drivers/media/video/cx23885/cx23885.h | 4 ++-- 2 files changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 51879961e3e..4d0614093ad 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -1008,10 +1008,12 @@ int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf) { + struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); + BUG_ON(in_interrupt()); videobuf_waiton(&buf->vb, 0, 0); - videobuf_dma_unmap(q, &buf->vb.dma); - videobuf_dma_free(&buf->vb.dma); + videobuf_dma_unmap(q, dma); + videobuf_dma_free(dma); btcx_riscmem_free((struct pci_dev *)q->dev, &buf->risc); buf->vb.state = STATE_NEEDS_INIT; } @@ -1176,8 +1178,8 @@ int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port, if (0 != (rc = videobuf_iolock(q, &buf->vb, NULL))) goto fail; cx23885_risc_databuffer(dev->pci, &buf->risc, - buf->vb.dma.sglist, - buf->vb.width, buf->vb.height); + videobuf_to_dma(&buf->vb)->sglist, + buf->vb.width, buf->vb.height); } buf->vb.state = STATE_PREPARED; return 0; diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 3d4fae565e3..dec4dc2fcbb 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -27,8 +27,8 @@ #include #include #include -#include -#include +#include +#include #include "btcx-risc.h" #include "cx23885-reg.h" -- cgit v1.2.3-70-g09d2 From 925343ecdfd3f1dafd1049ddd4944621bbe3422e Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Thu, 23 Aug 2007 21:22:15 -0300 Subject: V4L/DVB (6285): Remove pointless kmalloc() return value cast in Zoran PCI controller driver No need to cast the void pointer returned by kmalloc() in drivers/media/video/zoran_driver.c::v4l_fbuffer_alloc(). Signed-off-by: Jesper Juhl Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/zoran_driver.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c index d831ca16d9e..1c14fa2bd41 100644 --- a/drivers/media/video/zoran_driver.c +++ b/drivers/media/video/zoran_driver.c @@ -339,10 +339,7 @@ v4l_fbuffer_alloc (struct file *file) if (fh->v4l_buffers.buffer_size <= MAX_KMALLOC_MEM) { /* Use kmalloc */ - mem = - (unsigned char *) kmalloc(fh->v4l_buffers. - buffer_size, - GFP_KERNEL); + mem = kmalloc(fh->v4l_buffers.buffer_size, GFP_KERNEL); if (mem == 0) { dprintk(1, KERN_ERR -- cgit v1.2.3-70-g09d2 From 593f18c6e4d04134f240fbad001d878802d8925f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 7 Oct 2007 02:17:09 -0300 Subject: V4L/DVB (6286): Add support for MSI TV @nywhere A/D NB This is a Lifeview hybrid OEM board. Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.saa7134 | 2 +- drivers/media/video/saa7134/saa7134-cards.c | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134 index 831b4da48b8..67f08cc4be7 100644 --- a/Documentation/video4linux/CARDLIST.saa7134 +++ b/Documentation/video4linux/CARDLIST.saa7134 @@ -92,7 +92,7 @@ 91 -> AVerMedia A169 B [1461:7360] 92 -> AVerMedia A169 B1 [1461:6360] 93 -> Medion 7134 Bridge #2 [16be:0005] - 94 -> LifeView FlyDVB-T Hybrid Cardbus [5168:3306,5168:3502] + 94 -> LifeView FlyDVB-T Hybrid Cardbus/MSI TV @nywhere A/D NB [5168:3306,5168:3502,4e42:3502] 95 -> LifeView FlyVIDEO3000 (NTSC) [5169:0138] 96 -> Medion Md8800 Quadro [16be:0007,16be:0008] 97 -> LifeView FlyDVB-S /Acorp TV134DS [5168:0300,4e42:0300] diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 6b6eae82bcf..62420d599d7 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -2898,7 +2898,7 @@ struct saa7134_board saa7134_boards[] = { .radio_addr = ADDR_UNSET, }, [SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS] = { - .name = "LifeView FlyDVB-T Hybrid Cardbus", + .name = "LifeView FlyDVB-T Hybrid Cardbus/MSI TV @nywhere A/D NB", .audio_clock = 0x00200000, .tuner_type = TUNER_PHILIPS_TDA8290, .radio_type = UNSET, @@ -4280,6 +4280,12 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = 0x1461, /* Avermedia Technologies Inc */ .subdevice = 0xf01d, /* AVerTV DVB-T Super 007 */ .driver_data = SAA7134_BOARD_AVERMEDIA_SUPER_007, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x4e42, + .subdevice = 0x3502, + .driver_data = SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS },{ /* --- boards without eeprom + subsystem ID --- */ .vendor = PCI_VENDOR_ID_PHILIPS, -- cgit v1.2.3-70-g09d2 From aecfde539eeac11f269894413abf3b60cf74844f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 8 Oct 2007 09:04:09 -0300 Subject: V4L/DVB (6287): Fix DMA Scatter/Gather constructor cx23885 driver were converted to use the newer videobuf support. Unfortunately, the constructor weren't changed. This causes an oops, since the abstract methods (implemented as callbacks) aren't defined. Signed-off-by: Mauro Carvalho Chehab Reviewed-by: Michael Krufky --- drivers/media/video/cx23885/cx23885-dvb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index d952f3a6753..eda8c05d093 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -186,7 +186,7 @@ int cx23885_dvb_register(struct cx23885_tsport *port) /* dvb stuff */ printk("%s: cx23885 based dvb card\n", dev->name); - videobuf_queue_init(&port->dvb.dvbq, &dvb_qops, dev->pci, &port->slock, + videobuf_queue_pci_init(&port->dvb.dvbq, &dvb_qops, dev->pci, &port->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_TOP, sizeof(struct cx23885_buffer), port); err = dvb_register(port); -- cgit v1.2.3-70-g09d2 From 7568e3ce6710cb2c1bc1564a273e9f222efbc95e Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Mon, 8 Oct 2007 09:20:49 -0300 Subject: V4L/DVB (6289): Remove reference to dead CONFIG_UST and ust.h header Signed-off-by: Robert P. J. Day Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-common.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index 0689a041d77..c3440b280d2 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c @@ -65,11 +65,6 @@ #include #endif -#if defined(CONFIG_UST) || defined(CONFIG_UST_MODULE) -#include -#endif - - #include MODULE_AUTHOR("Bill Dirks, Justin Schoeman, Gerd Knorr"); -- cgit v1.2.3-70-g09d2 From 5ddff43435394c1c2540fcdeed00cb54862c31bf Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 8 Oct 2007 11:43:49 -0300 Subject: V4L/DVB (6290): remove videobuf_set_pci_ops Before the videobuf redesign, a procedure for re-using videobuf without PCI scatter/gather where provided by changing the pci-dependent operations by other operations. With the newer approach, those methods are obsolete and can safelly be removed. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf-dma-sg.c | 62 +++-------------------------------- include/media/videobuf-core.h | 3 -- include/media/videobuf-dma-sg.h | 19 ----------- 3 files changed, 4 insertions(+), 80 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c index 05dd38343fa..a38efe10feb 100644 --- a/drivers/media/video/videobuf-dma-sg.c +++ b/drivers/media/video/videobuf-dma-sg.c @@ -220,7 +220,6 @@ int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction, int videobuf_dma_map(struct videobuf_queue* q,struct videobuf_dmabuf *dma) { void *dev=q->dev; - struct videobuf_dma_sg_ops *ops=q->priv_ops; MAGIC_CHECK(dma->magic,MAGIC_DMABUF); BUG_ON(0 == dma->nr_pages); @@ -247,10 +246,8 @@ int videobuf_dma_map(struct videobuf_queue* q,struct videobuf_dmabuf *dma) return -ENOMEM; } if (!dma->bus_addr) { - if (ops && ops->vb_map_sg) { - dma->sglen = ops->vb_map_sg(dev,dma->sglist, + dma->sglen = pci_map_sg(dev,dma->sglist, dma->nr_pages, dma->direction); - } if (0 == dma->sglen) { printk(KERN_WARNING "%s: videobuf_map_sg failed\n",__FUNCTION__); @@ -266,30 +263,24 @@ int videobuf_dma_map(struct videobuf_queue* q,struct videobuf_dmabuf *dma) int videobuf_dma_sync(struct videobuf_queue *q,struct videobuf_dmabuf *dma) { void *dev=q->dev; - struct videobuf_dma_sg_ops *ops=q->priv_ops; MAGIC_CHECK(dma->magic,MAGIC_DMABUF); BUG_ON(!dma->sglen); - if (!dma->bus_addr && ops && ops->vb_dma_sync_sg) - ops->vb_dma_sync_sg(dev,dma->sglist,dma->nr_pages, - dma->direction); - + pci_dma_sync_sg_for_cpu (dev,dma->sglist,dma->nr_pages,dma->direction); return 0; } int videobuf_dma_unmap(struct videobuf_queue* q,struct videobuf_dmabuf *dma) { void *dev=q->dev; - struct videobuf_dma_sg_ops *ops=q->priv_ops; MAGIC_CHECK(dma->magic,MAGIC_DMABUF); if (!dma->sglen) return 0; - if (!dma->bus_addr && ops && ops->vb_unmap_sg) - ops->vb_unmap_sg(dev,dma->sglist,dma->nr_pages, - dma->direction); + pci_unmap_sg (dev,dma->sglist,dma->nr_pages,dma->direction); + kfree(dma->sglist); dma->sglist = NULL; dma->sglen = 0; @@ -325,12 +316,8 @@ int videobuf_dma_free(struct videobuf_dmabuf *dma) int videobuf_pci_dma_map(struct pci_dev *pci,struct videobuf_dmabuf *dma) { struct videobuf_queue q; - struct videobuf_dma_sg_ops qops; q.dev=pci; - qops.vb_map_sg=(vb_map_sg_t *)pci_map_sg; - qops.vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; - q.priv_ops = &qops; return (videobuf_dma_map(&q,dma)); } @@ -338,12 +325,8 @@ int videobuf_pci_dma_map(struct pci_dev *pci,struct videobuf_dmabuf *dma) int videobuf_pci_dma_unmap(struct pci_dev *pci,struct videobuf_dmabuf *dma) { struct videobuf_queue q; - struct videobuf_dma_sg_ops qops; q.dev=pci; - qops.vb_map_sg=(vb_map_sg_t *)pci_map_sg; - qops.vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; - q.priv_ops = &qops; return (videobuf_dma_unmap(&q,dma)); } @@ -712,46 +695,10 @@ void videobuf_queue_pci_init(struct videobuf_queue* q, unsigned int msize, void *priv) { - struct videobuf_dma_sg_ops *priv_ops; - videobuf_queue_init(q, ops, dev, irqlock, type, field, msize, priv); q->int_ops=&pci_ops; - - /* FIXME: the code bellow should be removed after having a proper - * memory allocation method for vivi and tm6000 - */ - q->priv_ops= kzalloc(sizeof(struct videobuf_dma_sg_ops), GFP_KERNEL); - BUG_ON (!q->priv_ops); - - priv_ops=q->priv_ops; - - /* Sets default methods for handling Scatter Gather mapping */ - priv_ops->vb_map_sg=(vb_map_sg_t *)pci_map_sg; - priv_ops->vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; - priv_ops->vb_dma_sync_sg=(vb_map_sg_t *)pci_dma_sync_sg_for_cpu; } -void videobuf_set_pci_ops (struct videobuf_queue* q, - struct videobuf_dma_sg_ops *ops) -{ - kfree (q->priv_ops); - - q->priv_ops=ops; - - if (!ops) - return; - - /* If not specified, defaults to PCI map sg */ - if (!ops->vb_map_sg) - ops->vb_map_sg=(vb_map_sg_t *)pci_map_sg; - - if (!ops->vb_dma_sync_sg) - ops->vb_dma_sync_sg=(vb_map_sg_t *)pci_dma_sync_sg_for_cpu; - if (!ops->vb_unmap_sg) - ops->vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; -} - - /* --------------------------------------------------------------------- */ EXPORT_SYMBOL_GPL(videobuf_vmalloc_to_sg); @@ -771,7 +718,6 @@ EXPORT_SYMBOL_GPL(videobuf_pci_dma_unmap); EXPORT_SYMBOL_GPL(videobuf_pci_alloc); EXPORT_SYMBOL_GPL(videobuf_queue_pci_init); -EXPORT_SYMBOL_GPL(videobuf_set_pci_ops); /* * Local variables: diff --git a/include/media/videobuf-core.h b/include/media/videobuf-core.h index 96949e31eaf..9bae5a2eda6 100644 --- a/include/media/videobuf-core.h +++ b/include/media/videobuf-core.h @@ -173,9 +173,6 @@ struct videobuf_queue { /* driver private data */ void *priv_data; - - /*FIXME: should be removed after completing the vb conversion */ - void *priv_ops; }; int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr); diff --git a/include/media/videobuf-dma-sg.h b/include/media/videobuf-dma-sg.h index 206d9027b39..38105031db2 100644 --- a/include/media/videobuf-dma-sg.h +++ b/include/media/videobuf-dma-sg.h @@ -89,19 +89,6 @@ struct videbuf_pci_sg_memory struct videobuf_dmabuf dma; }; -/* FIXME: To be removed soon */ -typedef int (vb_map_sg_t)(void *dev, struct scatterlist *sglist, int nr_pages, - int direction); - -/* FIXME: To be removed soon */ -struct videobuf_dma_sg_ops -{ - vb_map_sg_t *vb_map_sg; - vb_map_sg_t *vb_dma_sync_sg; - vb_map_sg_t *vb_unmap_sg; - -}; - void videobuf_dma_init(struct videobuf_dmabuf *dma); int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, unsigned long data, unsigned long size); @@ -133,9 +120,3 @@ void videobuf_queue_pci_init(struct videobuf_queue* q, int videobuf_pci_dma_map(struct pci_dev *pci,struct videobuf_dmabuf *dma); int videobuf_pci_dma_unmap(struct pci_dev *pci,struct videobuf_dmabuf *dma); -/* FIXME: temporary routine for vivi and tm6000, while lacking implementation - * of videobuf-vmalloc - */ -void videobuf_set_pci_ops (struct videobuf_queue* q, - struct videobuf_dma_sg_ops *ops); - -- cgit v1.2.3-70-g09d2 From d5f1b01644b6fd5e9eb480a4762cd6b569cb1246 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 8 Oct 2007 11:48:57 -0300 Subject: V4L/DVB (6291): Fix: avoid oops on some SMP machines This workaround fix a bug that happens on some SMP machines. On those machines, videobuf_iolock is called too soon, before file .mmap handler. This patch calls the scheduler before iolocking, allowing it to properly call the pending mmap. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf-core.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index 8e4026e6fae..aa402abc4b0 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c @@ -94,6 +94,14 @@ int videobuf_iolock(struct videobuf_queue* q, struct videobuf_buffer *vb, MAGIC_CHECK(vb->magic,MAGIC_BUFFER); MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + /* FIXME: This is required to avoid OOPS on some cases, since mmap_mapper() + method should be called before _iolock. + On some cases, the mmap_mapper() is called only after scheduling. + + However, this way is just too dirty! Better to wait for some event. + */ + schedule_timeout(HZ); + return CALL(q,iolock,q,vb,fbuf); } -- cgit v1.2.3-70-g09d2 From d4cae5a50021271b9ef4e5e39e71e177d12fa8cb Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 8 Oct 2007 12:20:02 -0300 Subject: V4L/DVB (6292): videobuf_core init always require callback implementation In the past, videobuf_queue_init were used to initialize PCI DMA videobuffers. This patch renames it, to avoid confusion with the previous kernel API, doing: s/videobuf_queue_init/void videobuf_queue_core_init/ Also, the operations is now part of the function parameter. The function will also add a test if this is defined, otherwise producing BUG. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf-core.c | 23 ++++++++++++++--------- drivers/media/video/videobuf-dma-sg.c | 4 ++-- drivers/media/video/videobuf-vmalloc.c | 4 ++-- include/media/videobuf-core.h | 5 +++-- 4 files changed, 21 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index aa402abc4b0..f5c5ea8b6b0 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c @@ -108,23 +108,25 @@ int videobuf_iolock(struct videobuf_queue* q, struct videobuf_buffer *vb, /* --------------------------------------------------------------------- */ -void videobuf_queue_init(struct videobuf_queue* q, +void videobuf_queue_core_init(struct videobuf_queue* q, struct videobuf_queue_ops *ops, void *dev, spinlock_t *irqlock, enum v4l2_buf_type type, enum v4l2_field field, unsigned int msize, - void *priv) + void *priv, + struct videobuf_qtype_ops *int_ops) { memset(q,0,sizeof(*q)); - q->irqlock = irqlock; - q->dev = dev; - q->type = type; - q->field = field; - q->msize = msize; - q->ops = ops; + q->irqlock = irqlock; + q->dev = dev; + q->type = type; + q->field = field; + q->msize = msize; + q->ops = ops; q->priv_data = priv; + q->int_ops = int_ops; /* All buffer operations are mandatory */ BUG_ON (!q->ops->buf_setup); @@ -132,6 +134,9 @@ void videobuf_queue_init(struct videobuf_queue* q, BUG_ON (!q->ops->buf_queue); BUG_ON (!q->ops->buf_release); + /* Having implementations for abstract methods are mandatory */ + BUG_ON (!q->int_ops); + mutex_init(&q->lock); INIT_LIST_HEAD(&q->stream); } @@ -966,7 +971,7 @@ EXPORT_SYMBOL_GPL(videobuf_iolock); EXPORT_SYMBOL_GPL(videobuf_alloc); -EXPORT_SYMBOL_GPL(videobuf_queue_init); +EXPORT_SYMBOL_GPL(videobuf_queue_core_init); EXPORT_SYMBOL_GPL(videobuf_queue_cancel); EXPORT_SYMBOL_GPL(videobuf_queue_is_busy); diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c index a38efe10feb..8bb7fdd306d 100644 --- a/drivers/media/video/videobuf-dma-sg.c +++ b/drivers/media/video/videobuf-dma-sg.c @@ -695,8 +695,8 @@ void videobuf_queue_pci_init(struct videobuf_queue* q, unsigned int msize, void *priv) { - videobuf_queue_init(q, ops, dev, irqlock, type, field, msize, priv); - q->int_ops=&pci_ops; + videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize, + priv, &pci_ops); } /* --------------------------------------------------------------------- */ diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c index c9d6ae0d3b4..2e3689a12a2 100644 --- a/drivers/media/video/videobuf-vmalloc.c +++ b/drivers/media/video/videobuf-vmalloc.c @@ -333,8 +333,8 @@ void videobuf_queue_vmalloc_init(struct videobuf_queue* q, unsigned int msize, void *priv) { - videobuf_queue_init(q, ops, dev, irqlock, type, field, msize, priv); - q->int_ops=&qops; + videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize, + priv, &qops); } EXPORT_SYMBOL_GPL(videobuf_queue_vmalloc_init); diff --git a/include/media/videobuf-core.h b/include/media/videobuf-core.h index 9bae5a2eda6..9fa09fb800a 100644 --- a/include/media/videobuf-core.h +++ b/include/media/videobuf-core.h @@ -181,14 +181,15 @@ int videobuf_iolock(struct videobuf_queue* q, struct videobuf_buffer *vb, void *videobuf_alloc(struct videobuf_queue* q); -void videobuf_queue_init(struct videobuf_queue *q, +void videobuf_queue_core_init(struct videobuf_queue *q, struct videobuf_queue_ops *ops, void *dev, spinlock_t *irqlock, enum v4l2_buf_type type, enum v4l2_field field, unsigned int msize, - void *priv); + void *priv, + struct videobuf_qtype_ops *int_ops); int videobuf_queue_is_busy(struct videobuf_queue *q); void videobuf_queue_cancel(struct videobuf_queue *q); -- cgit v1.2.3-70-g09d2 From 54bd5b66c87d14e250f108aad1228b905d6882f6 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Mon, 8 Oct 2007 16:26:13 -0300 Subject: V4L/DVB (6293): V4L: convert struct class_device to struct device The currently used "struct class_device" will be removed from the kernel. Here is a patch that converts all users in drivers/media/video/ to struct device. Reviewed-by: Thierry Merle Reviewed-by: Mike Isely Reviewed-by: Luca Risolia Signed-off-by: Kay Sievers Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bt8xx/bttv-driver.c | 11 +- drivers/media/video/et61x251/et61x251_core.c | 58 ++++--- drivers/media/video/ov511.c | 81 +++++---- drivers/media/video/pvrusb2/pvrusb2-sysfs.c | 210 +++++++++++++----------- drivers/media/video/pwc/pwc-if.c | 31 ++-- drivers/media/video/sn9c102/sn9c102_core.c | 112 +++++++------ drivers/media/video/stv680.c | 51 +++--- drivers/media/video/usbvision/usbvision-video.c | 119 +++++++------- drivers/media/video/videodev.c | 40 ++--- include/media/v4l2-dev.h | 14 +- 10 files changed, 387 insertions(+), 340 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index 4ab4e14b5c6..49278537eec 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -154,13 +154,14 @@ MODULE_LICENSE("GPL"); /* ----------------------------------------------------------------------- */ /* sysfs */ -static ssize_t show_card(struct class_device *cd, char *buf) +static ssize_t show_card(struct device *cd, + struct device_attribute *attr, char *buf) { struct video_device *vfd = to_video_device(cd); struct bttv *btv = dev_get_drvdata(vfd->dev); return sprintf(buf, "%d\n", btv ? btv->c.type : UNSET); } -static CLASS_DEVICE_ATTR(card, S_IRUGO, show_card, NULL); +static DEVICE_ATTR(card, S_IRUGO, show_card, NULL); /* ----------------------------------------------------------------------- */ /* dvb auto-load setup */ @@ -4615,9 +4616,9 @@ static int __devinit bttv_register_video(struct bttv *btv) goto err; printk(KERN_INFO "bttv%d: registered device video%d\n", btv->c.nr,btv->video_dev->minor & 0x1f); - if (class_device_create_file(&btv->video_dev->class_dev, - &class_device_attr_card)<0) { - printk(KERN_ERR "bttv%d: class_device_create_file 'card' " + if (device_create_file(&btv->video_dev->class_dev, + &dev_attr_card)<0) { + printk(KERN_ERR "bttv%d: device_create_file 'card' " "failed\n", btv->c.nr); goto err; } diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c index 31062a981e3..d5fef4c01c8 100644 --- a/drivers/media/video/et61x251/et61x251_core.c +++ b/drivers/media/video/et61x251/et61x251_core.c @@ -706,7 +706,8 @@ static u8 et61x251_strtou8(const char* buff, size_t len, ssize_t* count) NOTE 2: buffers are PAGE_SIZE long */ -static ssize_t et61x251_show_reg(struct class_device* cd, char* buf) +static ssize_t et61x251_show_reg(struct device* cd, + struct device_attribute *attr, char* buf) { struct et61x251_device* cam; ssize_t count; @@ -729,7 +730,8 @@ static ssize_t et61x251_show_reg(struct class_device* cd, char* buf) static ssize_t -et61x251_store_reg(struct class_device* cd, const char* buf, size_t len) +et61x251_store_reg(struct device* cd, + struct device_attribute *attr, const char* buf, size_t len) { struct et61x251_device* cam; u8 index; @@ -761,7 +763,8 @@ et61x251_store_reg(struct class_device* cd, const char* buf, size_t len) } -static ssize_t et61x251_show_val(struct class_device* cd, char* buf) +static ssize_t et61x251_show_val(struct device* cd, + struct device_attribute *attr, char* buf) { struct et61x251_device* cam; ssize_t count; @@ -792,7 +795,8 @@ static ssize_t et61x251_show_val(struct class_device* cd, char* buf) static ssize_t -et61x251_store_val(struct class_device* cd, const char* buf, size_t len) +et61x251_store_val(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) { struct et61x251_device* cam; u8 value; @@ -830,7 +834,8 @@ et61x251_store_val(struct class_device* cd, const char* buf, size_t len) } -static ssize_t et61x251_show_i2c_reg(struct class_device* cd, char* buf) +static ssize_t et61x251_show_i2c_reg(struct device* cd, + struct device_attribute *attr, char* buf) { struct et61x251_device* cam; ssize_t count; @@ -855,7 +860,8 @@ static ssize_t et61x251_show_i2c_reg(struct class_device* cd, char* buf) static ssize_t -et61x251_store_i2c_reg(struct class_device* cd, const char* buf, size_t len) +et61x251_store_i2c_reg(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) { struct et61x251_device* cam; u8 index; @@ -887,7 +893,8 @@ et61x251_store_i2c_reg(struct class_device* cd, const char* buf, size_t len) } -static ssize_t et61x251_show_i2c_val(struct class_device* cd, char* buf) +static ssize_t et61x251_show_i2c_val(struct device* cd, + struct device_attribute *attr, char* buf) { struct et61x251_device* cam; ssize_t count; @@ -923,7 +930,8 @@ static ssize_t et61x251_show_i2c_val(struct class_device* cd, char* buf) static ssize_t -et61x251_store_i2c_val(struct class_device* cd, const char* buf, size_t len) +et61x251_store_i2c_val(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) { struct et61x251_device* cam; u8 value; @@ -966,42 +974,40 @@ et61x251_store_i2c_val(struct class_device* cd, const char* buf, size_t len) } -static CLASS_DEVICE_ATTR(reg, S_IRUGO | S_IWUSR, - et61x251_show_reg, et61x251_store_reg); -static CLASS_DEVICE_ATTR(val, S_IRUGO | S_IWUSR, - et61x251_show_val, et61x251_store_val); -static CLASS_DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR, - et61x251_show_i2c_reg, et61x251_store_i2c_reg); -static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR, - et61x251_show_i2c_val, et61x251_store_i2c_val); +static DEVICE_ATTR(reg, S_IRUGO | S_IWUSR, + et61x251_show_reg, et61x251_store_reg); +static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, + et61x251_show_val, et61x251_store_val); +static DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR, + et61x251_show_i2c_reg, et61x251_store_i2c_reg); +static DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR, + et61x251_show_i2c_val, et61x251_store_i2c_val); static int et61x251_create_sysfs(struct et61x251_device* cam) { - struct class_device *classdev = &(cam->v4ldev->class_dev); + struct device *classdev = &(cam->v4ldev->class_dev); int err = 0; - if ((err = class_device_create_file(classdev, &class_device_attr_reg))) + if ((err = device_create_file(classdev, &dev_attr_reg))) goto err_out; - if ((err = class_device_create_file(classdev, &class_device_attr_val))) + if ((err = device_create_file(classdev, &dev_attr_val))) goto err_reg; if (cam->sensor.sysfs_ops) { - if ((err = class_device_create_file(classdev, - &class_device_attr_i2c_reg))) + if ((err = device_create_file(classdev, &dev_attr_i2c_reg))) goto err_val; - if ((err = class_device_create_file(classdev, - &class_device_attr_i2c_val))) + if ((err = device_create_file(classdev, &dev_attr_i2c_val))) goto err_i2c_reg; } err_i2c_reg: if (cam->sensor.sysfs_ops) - class_device_remove_file(classdev, &class_device_attr_i2c_reg); + device_remove_file(classdev, &dev_attr_i2c_reg); err_val: - class_device_remove_file(classdev, &class_device_attr_val); + device_remove_file(classdev, &dev_attr_val); err_reg: - class_device_remove_file(classdev, &class_device_attr_reg); + device_remove_file(classdev, &dev_attr_reg); err_out: return err; } diff --git a/drivers/media/video/ov511.c b/drivers/media/video/ov511.c index e5edff1059a..9eb2562347a 100644 --- a/drivers/media/video/ov511.c +++ b/drivers/media/video/ov511.c @@ -5554,41 +5554,46 @@ error: * sysfs ***************************************************************************/ -static inline struct usb_ov511 *cd_to_ov(struct class_device *cd) +static inline struct usb_ov511 *cd_to_ov(struct device *cd) { struct video_device *vdev = to_video_device(cd); return video_get_drvdata(vdev); } -static ssize_t show_custom_id(struct class_device *cd, char *buf) +static ssize_t show_custom_id(struct device *cd, + struct device_attribute *attr, char *buf) { struct usb_ov511 *ov = cd_to_ov(cd); return sprintf(buf, "%d\n", ov->customid); } -static CLASS_DEVICE_ATTR(custom_id, S_IRUGO, show_custom_id, NULL); +static DEVICE_ATTR(custom_id, S_IRUGO, show_custom_id, NULL); -static ssize_t show_model(struct class_device *cd, char *buf) +static ssize_t show_model(struct device *cd, + struct device_attribute *attr, char *buf) { struct usb_ov511 *ov = cd_to_ov(cd); return sprintf(buf, "%s\n", ov->desc); } -static CLASS_DEVICE_ATTR(model, S_IRUGO, show_model, NULL); +static DEVICE_ATTR(model, S_IRUGO, show_model, NULL); -static ssize_t show_bridge(struct class_device *cd, char *buf) +static ssize_t show_bridge(struct device *cd, + struct device_attribute *attr, char *buf) { struct usb_ov511 *ov = cd_to_ov(cd); return sprintf(buf, "%s\n", symbolic(brglist, ov->bridge)); } -static CLASS_DEVICE_ATTR(bridge, S_IRUGO, show_bridge, NULL); +static DEVICE_ATTR(bridge, S_IRUGO, show_bridge, NULL); -static ssize_t show_sensor(struct class_device *cd, char *buf) +static ssize_t show_sensor(struct device *cd, + struct device_attribute *attr, char *buf) { struct usb_ov511 *ov = cd_to_ov(cd); return sprintf(buf, "%s\n", symbolic(senlist, ov->sensor)); } -static CLASS_DEVICE_ATTR(sensor, S_IRUGO, show_sensor, NULL); +static DEVICE_ATTR(sensor, S_IRUGO, show_sensor, NULL); -static ssize_t show_brightness(struct class_device *cd, char *buf) +static ssize_t show_brightness(struct device *cd, + struct device_attribute *attr, char *buf) { struct usb_ov511 *ov = cd_to_ov(cd); unsigned short x; @@ -5598,9 +5603,10 @@ static ssize_t show_brightness(struct class_device *cd, char *buf) sensor_get_brightness(ov, &x); return sprintf(buf, "%d\n", x >> 8); } -static CLASS_DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL); +static DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL); -static ssize_t show_saturation(struct class_device *cd, char *buf) +static ssize_t show_saturation(struct device *cd, + struct device_attribute *attr, char *buf) { struct usb_ov511 *ov = cd_to_ov(cd); unsigned short x; @@ -5610,9 +5616,10 @@ static ssize_t show_saturation(struct class_device *cd, char *buf) sensor_get_saturation(ov, &x); return sprintf(buf, "%d\n", x >> 8); } -static CLASS_DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL); +static DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL); -static ssize_t show_contrast(struct class_device *cd, char *buf) +static ssize_t show_contrast(struct device *cd, + struct device_attribute *attr, char *buf) { struct usb_ov511 *ov = cd_to_ov(cd); unsigned short x; @@ -5622,9 +5629,10 @@ static ssize_t show_contrast(struct class_device *cd, char *buf) sensor_get_contrast(ov, &x); return sprintf(buf, "%d\n", x >> 8); } -static CLASS_DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL); +static DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL); -static ssize_t show_hue(struct class_device *cd, char *buf) +static ssize_t show_hue(struct device *cd, + struct device_attribute *attr, char *buf) { struct usb_ov511 *ov = cd_to_ov(cd); unsigned short x; @@ -5634,9 +5642,10 @@ static ssize_t show_hue(struct class_device *cd, char *buf) sensor_get_hue(ov, &x); return sprintf(buf, "%d\n", x >> 8); } -static CLASS_DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL); +static DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL); -static ssize_t show_exposure(struct class_device *cd, char *buf) +static ssize_t show_exposure(struct device *cd, + struct device_attribute *attr, char *buf) { struct usb_ov511 *ov = cd_to_ov(cd); unsigned char exp = 0; @@ -5646,49 +5655,49 @@ static ssize_t show_exposure(struct class_device *cd, char *buf) sensor_get_exposure(ov, &exp); return sprintf(buf, "%d\n", exp >> 8); } -static CLASS_DEVICE_ATTR(exposure, S_IRUGO, show_exposure, NULL); +static DEVICE_ATTR(exposure, S_IRUGO, show_exposure, NULL); static int ov_create_sysfs(struct video_device *vdev) { int rc; - rc = video_device_create_file(vdev, &class_device_attr_custom_id); + rc = video_device_create_file(vdev, &dev_attr_custom_id); if (rc) goto err; - rc = video_device_create_file(vdev, &class_device_attr_model); + rc = video_device_create_file(vdev, &dev_attr_model); if (rc) goto err_id; - rc = video_device_create_file(vdev, &class_device_attr_bridge); + rc = video_device_create_file(vdev, &dev_attr_bridge); if (rc) goto err_model; - rc = video_device_create_file(vdev, &class_device_attr_sensor); + rc = video_device_create_file(vdev, &dev_attr_sensor); if (rc) goto err_bridge; - rc = video_device_create_file(vdev, &class_device_attr_brightness); + rc = video_device_create_file(vdev, &dev_attr_brightness); if (rc) goto err_sensor; - rc = video_device_create_file(vdev, &class_device_attr_saturation); + rc = video_device_create_file(vdev, &dev_attr_saturation); if (rc) goto err_bright; - rc = video_device_create_file(vdev, &class_device_attr_contrast); + rc = video_device_create_file(vdev, &dev_attr_contrast); if (rc) goto err_sat; - rc = video_device_create_file(vdev, &class_device_attr_hue); + rc = video_device_create_file(vdev, &dev_attr_hue); if (rc) goto err_contrast; - rc = video_device_create_file(vdev, &class_device_attr_exposure); + rc = video_device_create_file(vdev, &dev_attr_exposure); if (rc) goto err_hue; return 0; err_hue: - video_device_remove_file(vdev, &class_device_attr_hue); + video_device_remove_file(vdev, &dev_attr_hue); err_contrast: - video_device_remove_file(vdev, &class_device_attr_contrast); + video_device_remove_file(vdev, &dev_attr_contrast); err_sat: - video_device_remove_file(vdev, &class_device_attr_saturation); + video_device_remove_file(vdev, &dev_attr_saturation); err_bright: - video_device_remove_file(vdev, &class_device_attr_brightness); + video_device_remove_file(vdev, &dev_attr_brightness); err_sensor: - video_device_remove_file(vdev, &class_device_attr_sensor); + video_device_remove_file(vdev, &dev_attr_sensor); err_bridge: - video_device_remove_file(vdev, &class_device_attr_bridge); + video_device_remove_file(vdev, &dev_attr_bridge); err_model: - video_device_remove_file(vdev, &class_device_attr_model); + video_device_remove_file(vdev, &dev_attr_model); err_id: - video_device_remove_file(vdev, &class_device_attr_custom_id); + video_device_remove_file(vdev, &dev_attr_custom_id); err: return rc; } diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c index 7ab79baa1c8..b20dc4421d5 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c +++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c @@ -33,16 +33,16 @@ struct pvr2_sysfs { struct pvr2_channel channel; - struct class_device *class_dev; + struct device *class_dev; #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC struct pvr2_sysfs_debugifc *debugifc; #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ struct pvr2_sysfs_ctl_item *item_first; struct pvr2_sysfs_ctl_item *item_last; - struct class_device_attribute attr_v4l_minor_number; - struct class_device_attribute attr_v4l_radio_minor_number; - struct class_device_attribute attr_unit_number; - struct class_device_attribute attr_bus_info; + struct device_attribute attr_v4l_minor_number; + struct device_attribute attr_v4l_radio_minor_number; + struct device_attribute attr_unit_number; + struct device_attribute attr_bus_info; int v4l_minor_number_created_ok; int v4l_radio_minor_number_created_ok; int unit_number_created_ok; @@ -51,22 +51,22 @@ struct pvr2_sysfs { #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC struct pvr2_sysfs_debugifc { - struct class_device_attribute attr_debugcmd; - struct class_device_attribute attr_debuginfo; + struct device_attribute attr_debugcmd; + struct device_attribute attr_debuginfo; int debugcmd_created_ok; int debuginfo_created_ok; }; #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ struct pvr2_sysfs_ctl_item { - struct class_device_attribute attr_name; - struct class_device_attribute attr_type; - struct class_device_attribute attr_min; - struct class_device_attribute attr_max; - struct class_device_attribute attr_enum; - struct class_device_attribute attr_bits; - struct class_device_attribute attr_val; - struct class_device_attribute attr_custom; + struct device_attribute attr_name; + struct device_attribute attr_type; + struct device_attribute attr_min; + struct device_attribute attr_max; + struct device_attribute attr_enum; + struct device_attribute attr_bits; + struct device_attribute attr_val; + struct device_attribute attr_custom; struct pvr2_ctrl *cptr; struct pvr2_sysfs *chptr; struct pvr2_sysfs_ctl_item *item_next; @@ -80,13 +80,13 @@ struct pvr2_sysfs_class { struct class class; }; -static ssize_t show_name(int id,struct class_device *class_dev,char *buf) +static ssize_t show_name(int id,struct device *class_dev,char *buf) { struct pvr2_ctrl *cptr; struct pvr2_sysfs *sfp; const char *name; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (!cptr) return -EINVAL; @@ -99,14 +99,14 @@ static ssize_t show_name(int id,struct class_device *class_dev,char *buf) return scnprintf(buf,PAGE_SIZE,"%s\n",name); } -static ssize_t show_type(int id,struct class_device *class_dev,char *buf) +static ssize_t show_type(int id,struct device *class_dev,char *buf) { struct pvr2_ctrl *cptr; struct pvr2_sysfs *sfp; const char *name; enum pvr2_ctl_type tp; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (!cptr) return -EINVAL; @@ -126,13 +126,13 @@ static ssize_t show_type(int id,struct class_device *class_dev,char *buf) return scnprintf(buf,PAGE_SIZE,"%s\n",name); } -static ssize_t show_min(int id,struct class_device *class_dev,char *buf) +static ssize_t show_min(int id,struct device *class_dev,char *buf) { struct pvr2_ctrl *cptr; struct pvr2_sysfs *sfp; long val; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (!cptr) return -EINVAL; @@ -143,13 +143,13 @@ static ssize_t show_min(int id,struct class_device *class_dev,char *buf) return scnprintf(buf,PAGE_SIZE,"%ld\n",val); } -static ssize_t show_max(int id,struct class_device *class_dev,char *buf) +static ssize_t show_max(int id,struct device *class_dev,char *buf) { struct pvr2_ctrl *cptr; struct pvr2_sysfs *sfp; long val; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (!cptr) return -EINVAL; @@ -160,14 +160,14 @@ static ssize_t show_max(int id,struct class_device *class_dev,char *buf) return scnprintf(buf,PAGE_SIZE,"%ld\n",val); } -static ssize_t show_val_norm(int id,struct class_device *class_dev,char *buf) +static ssize_t show_val_norm(int id,struct device *class_dev,char *buf) { struct pvr2_ctrl *cptr; struct pvr2_sysfs *sfp; int val,ret; unsigned int cnt = 0; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (!cptr) return -EINVAL; @@ -184,14 +184,14 @@ static ssize_t show_val_norm(int id,struct class_device *class_dev,char *buf) return cnt+1; } -static ssize_t show_val_custom(int id,struct class_device *class_dev,char *buf) +static ssize_t show_val_custom(int id,struct device *class_dev,char *buf) { struct pvr2_ctrl *cptr; struct pvr2_sysfs *sfp; int val,ret; unsigned int cnt = 0; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (!cptr) return -EINVAL; @@ -208,14 +208,14 @@ static ssize_t show_val_custom(int id,struct class_device *class_dev,char *buf) return cnt+1; } -static ssize_t show_enum(int id,struct class_device *class_dev,char *buf) +static ssize_t show_enum(int id,struct device *class_dev,char *buf) { struct pvr2_ctrl *cptr; struct pvr2_sysfs *sfp; long val; unsigned int bcnt,ccnt,ecnt; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (!cptr) return -EINVAL; @@ -233,14 +233,14 @@ static ssize_t show_enum(int id,struct class_device *class_dev,char *buf) return bcnt; } -static ssize_t show_bits(int id,struct class_device *class_dev,char *buf) +static ssize_t show_bits(int id,struct device *class_dev,char *buf) { struct pvr2_ctrl *cptr; struct pvr2_sysfs *sfp; int valid_bits,msk; unsigned int bcnt,ccnt; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (!cptr) return -EINVAL; @@ -278,23 +278,23 @@ static int store_val_any(int id,int customfl,struct pvr2_sysfs *sfp, return ret; } -static ssize_t store_val_norm(int id,struct class_device *class_dev, +static ssize_t store_val_norm(int id,struct device *class_dev, const char *buf,size_t count) { struct pvr2_sysfs *sfp; int ret; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; ret = store_val_any(id,0,sfp,buf,count); if (!ret) ret = count; return ret; } -static ssize_t store_val_custom(int id,struct class_device *class_dev, +static ssize_t store_val_custom(int id,struct device *class_dev, const char *buf,size_t count) { struct pvr2_sysfs *sfp; int ret; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; ret = store_val_any(id,1,sfp,buf,count); if (!ret) ret = count; return ret; @@ -304,7 +304,7 @@ static ssize_t store_val_custom(int id,struct class_device *class_dev, Mike Isely 30-April-2005 This next batch of horrible preprocessor hackery is needed because the - kernel's class_device_attribute mechanism fails to pass the actual + kernel's device_attribute mechanism fails to pass the actual attribute through to the show / store functions, which means we have no way to package up any attribute-specific parameters, like for example the control id. So we work around this brain-damage by encoding the control @@ -314,11 +314,13 @@ static ssize_t store_val_custom(int id,struct class_device *class_dev, */ #define CREATE_SHOW_INSTANCE(sf_name,ctl_id) \ -static ssize_t sf_name##_##ctl_id(struct class_device *class_dev,char *buf) \ +static ssize_t sf_name##_##ctl_id(struct device *class_dev, \ +struct device_attribute *attr, char *buf) \ { return sf_name(ctl_id,class_dev,buf); } #define CREATE_STORE_INSTANCE(sf_name,ctl_id) \ -static ssize_t sf_name##_##ctl_id(struct class_device *class_dev,const char *buf,size_t count) \ +static ssize_t sf_name##_##ctl_id(struct device *class_dev, \ +struct device_attribute *attr, const char *buf, size_t count) \ { return sf_name(ctl_id,class_dev,buf,count); } #define CREATE_BATCH(ctl_id) \ @@ -395,17 +397,27 @@ CREATE_BATCH(58) CREATE_BATCH(59) struct pvr2_sysfs_func_set { - ssize_t (*show_name)(struct class_device *,char *); - ssize_t (*show_type)(struct class_device *,char *); - ssize_t (*show_min)(struct class_device *,char *); - ssize_t (*show_max)(struct class_device *,char *); - ssize_t (*show_enum)(struct class_device *,char *); - ssize_t (*show_bits)(struct class_device *,char *); - ssize_t (*show_val_norm)(struct class_device *,char *); - ssize_t (*store_val_norm)(struct class_device *, + ssize_t (*show_name)(struct device *, + struct device_attribute *attr, char *); + ssize_t (*show_type)(struct device *, + struct device_attribute *attr, char *); + ssize_t (*show_min)(struct device *, + struct device_attribute *attr, char *); + ssize_t (*show_max)(struct device *, + struct device_attribute *attr, char *); + ssize_t (*show_enum)(struct device *, + struct device_attribute *attr, char *); + ssize_t (*show_bits)(struct device *, + struct device_attribute *attr, char *); + ssize_t (*show_val_norm)(struct device *, + struct device_attribute *attr, char *); + ssize_t (*store_val_norm)(struct device *, + struct device_attribute *attr, const char *,size_t); - ssize_t (*show_val_custom)(struct class_device *,char *); - ssize_t (*store_val_custom)(struct class_device *, + ssize_t (*show_val_custom)(struct device *, + struct device_attribute *attr, char *); + ssize_t (*store_val_custom)(struct device *, + struct device_attribute *attr, const char *,size_t); }; @@ -597,9 +609,9 @@ static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id) } #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC -static ssize_t debuginfo_show(struct class_device *,char *); -static ssize_t debugcmd_show(struct class_device *,char *); -static ssize_t debugcmd_store(struct class_device *,const char *,size_t count); +static ssize_t debuginfo_show(struct device *,char *); +static ssize_t debugcmd_show(struct device *,char *); +static ssize_t debugcmd_store(struct device *,const char *,size_t count); static void pvr2_sysfs_add_debugifc(struct pvr2_sysfs *sfp) { @@ -616,16 +628,16 @@ static void pvr2_sysfs_add_debugifc(struct pvr2_sysfs *sfp) dip->attr_debuginfo.attr.mode = S_IRUGO; dip->attr_debuginfo.show = debuginfo_show; sfp->debugifc = dip; - ret = class_device_create_file(sfp->class_dev,&dip->attr_debugcmd); + ret = device_create_file(sfp->class_dev,&dip->attr_debugcmd); if (ret < 0) { - printk(KERN_WARNING "%s: class_device_create_file error: %d\n", + printk(KERN_WARNING "%s: device_create_file error: %d\n", __FUNCTION__, ret); } else { dip->debugcmd_created_ok = !0; } - ret = class_device_create_file(sfp->class_dev,&dip->attr_debuginfo); + ret = device_create_file(sfp->class_dev,&dip->attr_debuginfo); if (ret < 0) { - printk(KERN_WARNING "%s: class_device_create_file error: %d\n", + printk(KERN_WARNING "%s: device_create_file error: %d\n", __FUNCTION__, ret); } else { dip->debuginfo_created_ok = !0; @@ -637,11 +649,11 @@ static void pvr2_sysfs_tear_down_debugifc(struct pvr2_sysfs *sfp) { if (!sfp->debugifc) return; if (sfp->debugifc->debuginfo_created_ok) { - class_device_remove_file(sfp->class_dev, + device_remove_file(sfp->class_dev, &sfp->debugifc->attr_debuginfo); } if (sfp->debugifc->debugcmd_created_ok) { - class_device_remove_file(sfp->class_dev, + device_remove_file(sfp->class_dev, &sfp->debugifc->attr_debugcmd); } kfree(sfp->debugifc); @@ -683,7 +695,7 @@ static void pvr2_sysfs_class_release(struct class *class) } -static void pvr2_sysfs_release(struct class_device *class_dev) +static void pvr2_sysfs_release(struct device *class_dev) { pvr2_sysfs_trace("Releasing class_dev id=%p",class_dev); kfree(class_dev); @@ -698,32 +710,33 @@ static void class_dev_destroy(struct pvr2_sysfs *sfp) #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ pvr2_sysfs_tear_down_controls(sfp); if (sfp->bus_info_created_ok) { - class_device_remove_file(sfp->class_dev, + device_remove_file(sfp->class_dev, &sfp->attr_bus_info); } if (sfp->v4l_minor_number_created_ok) { - class_device_remove_file(sfp->class_dev, + device_remove_file(sfp->class_dev, &sfp->attr_v4l_minor_number); } if (sfp->v4l_radio_minor_number_created_ok) { - class_device_remove_file(sfp->class_dev, + device_remove_file(sfp->class_dev, &sfp->attr_v4l_radio_minor_number); } if (sfp->unit_number_created_ok) { - class_device_remove_file(sfp->class_dev, + device_remove_file(sfp->class_dev, &sfp->attr_unit_number); } pvr2_sysfs_trace("Destroying class_dev id=%p",sfp->class_dev); - sfp->class_dev->class_data = NULL; - class_device_unregister(sfp->class_dev); + sfp->class_dev->driver_data = NULL; + device_unregister(sfp->class_dev); sfp->class_dev = NULL; } -static ssize_t v4l_minor_number_show(struct class_device *class_dev,char *buf) +static ssize_t v4l_minor_number_show(struct device *class_dev, + struct device_attribute *attr, char *buf) { struct pvr2_sysfs *sfp; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; return scnprintf(buf,PAGE_SIZE,"%d\n", pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw, @@ -731,21 +744,23 @@ static ssize_t v4l_minor_number_show(struct class_device *class_dev,char *buf) } -static ssize_t bus_info_show(struct class_device *class_dev,char *buf) +static ssize_t bus_info_show(struct device *class_dev, + struct device_attribute *attr, char *buf) { struct pvr2_sysfs *sfp; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; return scnprintf(buf,PAGE_SIZE,"%s\n", pvr2_hdw_get_bus_info(sfp->channel.hdw)); } -static ssize_t v4l_radio_minor_number_show(struct class_device *class_dev, +static ssize_t v4l_radio_minor_number_show(struct device *class_dev, + struct device_attribute *attr, char *buf) { struct pvr2_sysfs *sfp; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; return scnprintf(buf,PAGE_SIZE,"%d\n", pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw, @@ -753,10 +768,11 @@ static ssize_t v4l_radio_minor_number_show(struct class_device *class_dev, } -static ssize_t unit_number_show(struct class_device *class_dev,char *buf) +static ssize_t unit_number_show(struct device *class_dev, + struct device_attribute *attr, char *buf) { struct pvr2_sysfs *sfp; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; return scnprintf(buf,PAGE_SIZE,"%d\n", pvr2_hdw_get_unit_number(sfp->channel.hdw)); @@ -767,7 +783,7 @@ static void class_dev_create(struct pvr2_sysfs *sfp, struct pvr2_sysfs_class *class_ptr) { struct usb_device *usb_dev; - struct class_device *class_dev; + struct device *class_dev; int ret; usb_dev = pvr2_hdw_get_dev(sfp->channel.hdw); @@ -779,23 +795,23 @@ static void class_dev_create(struct pvr2_sysfs *sfp, class_dev->class = &class_ptr->class; if (pvr2_hdw_get_sn(sfp->channel.hdw)) { - snprintf(class_dev->class_id,BUS_ID_SIZE,"sn-%lu", + snprintf(class_dev->bus_id, BUS_ID_SIZE, "sn-%lu", pvr2_hdw_get_sn(sfp->channel.hdw)); } else if (pvr2_hdw_get_unit_number(sfp->channel.hdw) >= 0) { - snprintf(class_dev->class_id,BUS_ID_SIZE,"unit-%c", + snprintf(class_dev->bus_id, BUS_ID_SIZE, "unit-%c", pvr2_hdw_get_unit_number(sfp->channel.hdw) + 'a'); } else { kfree(class_dev); return; } - class_dev->dev = &usb_dev->dev; + class_dev->parent = &usb_dev->dev; sfp->class_dev = class_dev; - class_dev->class_data = sfp; - ret = class_device_register(class_dev); + class_dev->driver_data = sfp; + ret = device_register(class_dev); if (ret) { - printk(KERN_ERR "%s: class_device_register failed\n", + printk(KERN_ERR "%s: device_register failed\n", __FUNCTION__); kfree(class_dev); return; @@ -805,10 +821,10 @@ static void class_dev_create(struct pvr2_sysfs *sfp, sfp->attr_v4l_minor_number.attr.mode = S_IRUGO; sfp->attr_v4l_minor_number.show = v4l_minor_number_show; sfp->attr_v4l_minor_number.store = NULL; - ret = class_device_create_file(sfp->class_dev, + ret = device_create_file(sfp->class_dev, &sfp->attr_v4l_minor_number); if (ret < 0) { - printk(KERN_WARNING "%s: class_device_create_file error: %d\n", + printk(KERN_WARNING "%s: device_create_file error: %d\n", __FUNCTION__, ret); } else { sfp->v4l_minor_number_created_ok = !0; @@ -818,10 +834,10 @@ static void class_dev_create(struct pvr2_sysfs *sfp, sfp->attr_v4l_radio_minor_number.attr.mode = S_IRUGO; sfp->attr_v4l_radio_minor_number.show = v4l_radio_minor_number_show; sfp->attr_v4l_radio_minor_number.store = NULL; - ret = class_device_create_file(sfp->class_dev, + ret = device_create_file(sfp->class_dev, &sfp->attr_v4l_radio_minor_number); if (ret < 0) { - printk(KERN_WARNING "%s: class_device_create_file error: %d\n", + printk(KERN_WARNING "%s: device_create_file error: %d\n", __FUNCTION__, ret); } else { sfp->v4l_radio_minor_number_created_ok = !0; @@ -831,9 +847,9 @@ static void class_dev_create(struct pvr2_sysfs *sfp, sfp->attr_unit_number.attr.mode = S_IRUGO; sfp->attr_unit_number.show = unit_number_show; sfp->attr_unit_number.store = NULL; - ret = class_device_create_file(sfp->class_dev,&sfp->attr_unit_number); + ret = device_create_file(sfp->class_dev,&sfp->attr_unit_number); if (ret < 0) { - printk(KERN_WARNING "%s: class_device_create_file error: %d\n", + printk(KERN_WARNING "%s: device_create_file error: %d\n", __FUNCTION__, ret); } else { sfp->unit_number_created_ok = !0; @@ -843,10 +859,10 @@ static void class_dev_create(struct pvr2_sysfs *sfp, sfp->attr_bus_info.attr.mode = S_IRUGO; sfp->attr_bus_info.show = bus_info_show; sfp->attr_bus_info.store = NULL; - ret = class_device_create_file(sfp->class_dev, + ret = device_create_file(sfp->class_dev, &sfp->attr_bus_info); if (ret < 0) { - printk(KERN_WARNING "%s: class_device_create_file error: %d\n", + printk(KERN_WARNING "%s: device_create_file error: %d\n", __FUNCTION__, ret); } else { sfp->bus_info_created_ok = !0; @@ -886,7 +902,7 @@ struct pvr2_sysfs *pvr2_sysfs_create(struct pvr2_context *mp, } -static int pvr2_sysfs_hotplug(struct class_device *cd,char **envp, +static int pvr2_sysfs_hotplug(struct device *cd,char **envp, int numenvp,char *buf,int size) { /* Even though we don't do anything here, we still need this function @@ -902,8 +918,8 @@ struct pvr2_sysfs_class *pvr2_sysfs_class_create(void) pvr2_sysfs_trace("Creating pvr2_sysfs_class id=%p",clp); clp->class.name = "pvrusb2"; clp->class.class_release = pvr2_sysfs_class_release; - clp->class.release = pvr2_sysfs_release; - clp->class.uevent = pvr2_sysfs_hotplug; + clp->class.dev_release = pvr2_sysfs_release; + clp->class.dev_uevent = pvr2_sysfs_hotplug; if (class_register(&clp->class)) { pvr2_sysfs_trace( "Registration failed for pvr2_sysfs_class id=%p",clp); @@ -921,32 +937,32 @@ void pvr2_sysfs_class_destroy(struct pvr2_sysfs_class *clp) #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC -static ssize_t debuginfo_show(struct class_device *class_dev,char *buf) +static ssize_t debuginfo_show(struct device *class_dev,char *buf) { struct pvr2_sysfs *sfp; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; pvr2_hdw_trigger_module_log(sfp->channel.hdw); return pvr2_debugifc_print_info(sfp->channel.hdw,buf,PAGE_SIZE); } -static ssize_t debugcmd_show(struct class_device *class_dev,char *buf) +static ssize_t debugcmd_show(struct device *class_dev,char *buf) { struct pvr2_sysfs *sfp; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; return pvr2_debugifc_print_status(sfp->channel.hdw,buf,PAGE_SIZE); } -static ssize_t debugcmd_store(struct class_device *class_dev, - const char *buf,size_t count) +static ssize_t debugcmd_store(struct device *class_dev, + const char *buf, size_t count) { struct pvr2_sysfs *sfp; int ret; - sfp = (struct pvr2_sysfs *)class_dev->class_data; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; ret = pvr2_debugifc_docmd(sfp->channel.hdw,buf,count); diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index 0ff5718bf9b..0b67d4ec031 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c @@ -996,20 +996,22 @@ int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_f /********* * sysfs *********/ -static struct pwc_device *cd_to_pwc(struct class_device *cd) +static struct pwc_device *cd_to_pwc(struct device *cd) { struct video_device *vdev = to_video_device(cd); return video_get_drvdata(vdev); } -static ssize_t show_pan_tilt(struct class_device *class_dev, char *buf) +static ssize_t show_pan_tilt(struct device *class_dev, + struct device_attribute *attr, char *buf) { struct pwc_device *pdev = cd_to_pwc(class_dev); return sprintf(buf, "%d %d\n", pdev->pan_angle, pdev->tilt_angle); } -static ssize_t store_pan_tilt(struct class_device *class_dev, const char *buf, - size_t count) +static ssize_t store_pan_tilt(struct device *class_dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct pwc_device *pdev = cd_to_pwc(class_dev); int pan, tilt; @@ -1025,10 +1027,11 @@ static ssize_t store_pan_tilt(struct class_device *class_dev, const char *buf, return ret; return strlen(buf); } -static CLASS_DEVICE_ATTR(pan_tilt, S_IRUGO | S_IWUSR, show_pan_tilt, - store_pan_tilt); +static DEVICE_ATTR(pan_tilt, S_IRUGO | S_IWUSR, show_pan_tilt, + store_pan_tilt); -static ssize_t show_snapshot_button_status(struct class_device *class_dev, char *buf) +static ssize_t show_snapshot_button_status(struct device *class_dev, + struct device_attribute *attr, char *buf) { struct pwc_device *pdev = cd_to_pwc(class_dev); int status = pdev->snapshot_button_status; @@ -1036,26 +1039,26 @@ static ssize_t show_snapshot_button_status(struct class_device *class_dev, char return sprintf(buf, "%d\n", status); } -static CLASS_DEVICE_ATTR(button, S_IRUGO | S_IWUSR, show_snapshot_button_status, - NULL); +static DEVICE_ATTR(button, S_IRUGO | S_IWUSR, show_snapshot_button_status, + NULL); static int pwc_create_sysfs_files(struct video_device *vdev) { struct pwc_device *pdev = video_get_drvdata(vdev); int rc; - rc = video_device_create_file(vdev, &class_device_attr_button); + rc = video_device_create_file(vdev, &dev_attr_button); if (rc) goto err; if (pdev->features & FEATURE_MOTOR_PANTILT) { - rc = video_device_create_file(vdev,&class_device_attr_pan_tilt); + rc = video_device_create_file(vdev, &dev_attr_pan_tilt); if (rc) goto err_button; } return 0; err_button: - video_device_remove_file(vdev, &class_device_attr_button); + video_device_remove_file(vdev, &dev_attr_button); err: return rc; } @@ -1064,8 +1067,8 @@ static void pwc_remove_sysfs_files(struct video_device *vdev) { struct pwc_device *pdev = video_get_drvdata(vdev); if (pdev->features & FEATURE_MOTOR_PANTILT) - video_device_remove_file(vdev, &class_device_attr_pan_tilt); - video_device_remove_file(vdev, &class_device_attr_button); + video_device_remove_file(vdev, &dev_attr_pan_tilt); + video_device_remove_file(vdev, &dev_attr_button); } #ifdef CONFIG_USB_PWC_DEBUG diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c index e0accf1b871..6991e06f765 100644 --- a/drivers/media/video/sn9c102/sn9c102_core.c +++ b/drivers/media/video/sn9c102/sn9c102_core.c @@ -1029,7 +1029,8 @@ static u16 sn9c102_strtou16(const char* buff, size_t len, ssize_t* count) NOTE 2: buffers are PAGE_SIZE long */ -static ssize_t sn9c102_show_reg(struct class_device* cd, char* buf) +static ssize_t sn9c102_show_reg(struct device* cd, + struct device_attribute *attr, char* buf) { struct sn9c102_device* cam; ssize_t count; @@ -1053,7 +1054,8 @@ static ssize_t sn9c102_show_reg(struct class_device* cd, char* buf) static ssize_t -sn9c102_store_reg(struct class_device* cd, const char* buf, size_t len) +sn9c102_store_reg(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) { struct sn9c102_device* cam; u16 index; @@ -1086,7 +1088,8 @@ sn9c102_store_reg(struct class_device* cd, const char* buf, size_t len) } -static ssize_t sn9c102_show_val(struct class_device* cd, char* buf) +static ssize_t sn9c102_show_val(struct device* cd, + struct device_attribute *attr, char* buf) { struct sn9c102_device* cam; ssize_t count; @@ -1118,7 +1121,8 @@ static ssize_t sn9c102_show_val(struct class_device* cd, char* buf) static ssize_t -sn9c102_store_val(struct class_device* cd, const char* buf, size_t len) +sn9c102_store_val(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) { struct sn9c102_device* cam; u16 value; @@ -1157,7 +1161,8 @@ sn9c102_store_val(struct class_device* cd, const char* buf, size_t len) } -static ssize_t sn9c102_show_i2c_reg(struct class_device* cd, char* buf) +static ssize_t sn9c102_show_i2c_reg(struct device* cd, + struct device_attribute *attr, char* buf) { struct sn9c102_device* cam; ssize_t count; @@ -1183,7 +1188,8 @@ static ssize_t sn9c102_show_i2c_reg(struct class_device* cd, char* buf) static ssize_t -sn9c102_store_i2c_reg(struct class_device* cd, const char* buf, size_t len) +sn9c102_store_i2c_reg(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) { struct sn9c102_device* cam; u16 index; @@ -1216,7 +1222,8 @@ sn9c102_store_i2c_reg(struct class_device* cd, const char* buf, size_t len) } -static ssize_t sn9c102_show_i2c_val(struct class_device* cd, char* buf) +static ssize_t sn9c102_show_i2c_val(struct device* cd, + struct device_attribute *attr, char* buf) { struct sn9c102_device* cam; ssize_t count; @@ -1253,7 +1260,8 @@ static ssize_t sn9c102_show_i2c_val(struct class_device* cd, char* buf) static ssize_t -sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len) +sn9c102_store_i2c_val(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) { struct sn9c102_device* cam; u16 value; @@ -1298,7 +1306,8 @@ sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len) static ssize_t -sn9c102_store_green(struct class_device* cd, const char* buf, size_t len) +sn9c102_store_green(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) { struct sn9c102_device* cam; enum sn9c102_bridge bridge; @@ -1329,16 +1338,16 @@ sn9c102_store_green(struct class_device* cd, const char* buf, size_t len) case BRIDGE_SN9C102: if (value > 0x0f) return -EINVAL; - if ((res = sn9c102_store_reg(cd, "0x11", 4)) >= 0) - res = sn9c102_store_val(cd, buf, len); + if ((res = sn9c102_store_reg(cd, attr, "0x11", 4)) >= 0) + res = sn9c102_store_val(cd, attr, buf, len); break; case BRIDGE_SN9C103: case BRIDGE_SN9C105: case BRIDGE_SN9C120: if (value > 0x7f) return -EINVAL; - if ((res = sn9c102_store_reg(cd, "0x07", 4)) >= 0) - res = sn9c102_store_val(cd, buf, len); + if ((res = sn9c102_store_reg(cd, attr, "0x07", 4)) >= 0) + res = sn9c102_store_val(cd, attr, buf, len); break; } @@ -1347,7 +1356,8 @@ sn9c102_store_green(struct class_device* cd, const char* buf, size_t len) static ssize_t -sn9c102_store_blue(struct class_device* cd, const char* buf, size_t len) +sn9c102_store_blue(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) { ssize_t res = 0; u16 value; @@ -1357,15 +1367,16 @@ sn9c102_store_blue(struct class_device* cd, const char* buf, size_t len) if (!count || value > 0x7f) return -EINVAL; - if ((res = sn9c102_store_reg(cd, "0x06", 4)) >= 0) - res = sn9c102_store_val(cd, buf, len); + if ((res = sn9c102_store_reg(cd, attr, "0x06", 4)) >= 0) + res = sn9c102_store_val(cd, attr, buf, len); return res; } static ssize_t -sn9c102_store_red(struct class_device* cd, const char* buf, size_t len) +sn9c102_store_red(struct device* cd, struct device_attribute *attr, + const char* buf, size_t len) { ssize_t res = 0; u16 value; @@ -1375,14 +1386,16 @@ sn9c102_store_red(struct class_device* cd, const char* buf, size_t len) if (!count || value > 0x7f) return -EINVAL; - if ((res = sn9c102_store_reg(cd, "0x05", 4)) >= 0) - res = sn9c102_store_val(cd, buf, len); + if ((res = sn9c102_store_reg(cd, attr, "0x05", 4)) >= 0) + res = sn9c102_store_val(cd, attr, buf, len); return res; } -static ssize_t sn9c102_show_frame_header(struct class_device* cd, char* buf) +static ssize_t sn9c102_show_frame_header(struct device* cd, + struct device_attribute *attr, + char* buf) { struct sn9c102_device* cam; ssize_t count; @@ -1401,72 +1414,63 @@ static ssize_t sn9c102_show_frame_header(struct class_device* cd, char* buf) } -static CLASS_DEVICE_ATTR(reg, S_IRUGO | S_IWUSR, - sn9c102_show_reg, sn9c102_store_reg); -static CLASS_DEVICE_ATTR(val, S_IRUGO | S_IWUSR, - sn9c102_show_val, sn9c102_store_val); -static CLASS_DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR, - sn9c102_show_i2c_reg, sn9c102_store_i2c_reg); -static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR, - sn9c102_show_i2c_val, sn9c102_store_i2c_val); -static CLASS_DEVICE_ATTR(green, S_IWUGO, NULL, sn9c102_store_green); -static CLASS_DEVICE_ATTR(blue, S_IWUGO, NULL, sn9c102_store_blue); -static CLASS_DEVICE_ATTR(red, S_IWUGO, NULL, sn9c102_store_red); -static CLASS_DEVICE_ATTR(frame_header, S_IRUGO, - sn9c102_show_frame_header, NULL); +static DEVICE_ATTR(reg, S_IRUGO | S_IWUSR, sn9c102_show_reg, sn9c102_store_reg); +static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, sn9c102_show_val, sn9c102_store_val); +static DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR, + sn9c102_show_i2c_reg, sn9c102_store_i2c_reg); +static DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR, + sn9c102_show_i2c_val, sn9c102_store_i2c_val); +static DEVICE_ATTR(green, S_IWUGO, NULL, sn9c102_store_green); +static DEVICE_ATTR(blue, S_IWUGO, NULL, sn9c102_store_blue); +static DEVICE_ATTR(red, S_IWUGO, NULL, sn9c102_store_red); +static DEVICE_ATTR(frame_header, S_IRUGO, sn9c102_show_frame_header, NULL); static int sn9c102_create_sysfs(struct sn9c102_device* cam) { - struct class_device *classdev = &(cam->v4ldev->class_dev); + struct device *classdev = &(cam->v4ldev->class_dev); int err = 0; - if ((err = class_device_create_file(classdev, &class_device_attr_reg))) + if ((err = device_create_file(classdev, &dev_attr_reg))) goto err_out; - if ((err = class_device_create_file(classdev, &class_device_attr_val))) + if ((err = device_create_file(classdev, &dev_attr_val))) goto err_reg; - if ((err = class_device_create_file(classdev, - &class_device_attr_frame_header))) + if ((err = device_create_file(classdev, &dev_attr_frame_header))) goto err_val; if (cam->sensor.sysfs_ops) { - if ((err = class_device_create_file(classdev, - &class_device_attr_i2c_reg))) + if ((err = device_create_file(classdev, &dev_attr_i2c_reg))) goto err_frame_header; - if ((err = class_device_create_file(classdev, - &class_device_attr_i2c_val))) + if ((err = device_create_file(classdev, &dev_attr_i2c_val))) goto err_i2c_reg; } if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) { - if ((err = class_device_create_file(classdev, - &class_device_attr_green))) + if ((err = device_create_file(classdev, &dev_attr_green))) goto err_i2c_val; } else { - if ((err = class_device_create_file(classdev, - &class_device_attr_blue))) + if ((err = device_create_file(classdev, &dev_attr_blue))) goto err_i2c_val; - if ((err = class_device_create_file(classdev, - &class_device_attr_red))) + if ((err = device_create_file(classdev, &dev_attr_red))) goto err_blue; } return 0; err_blue: - class_device_remove_file(classdev, &class_device_attr_blue); + device_remove_file(classdev, &dev_attr_blue); err_i2c_val: if (cam->sensor.sysfs_ops) - class_device_remove_file(classdev, &class_device_attr_i2c_val); + device_remove_file(classdev, &dev_attr_i2c_val); err_i2c_reg: if (cam->sensor.sysfs_ops) - class_device_remove_file(classdev, &class_device_attr_i2c_reg); + device_remove_file(classdev, &dev_attr_i2c_reg); err_frame_header: - class_device_remove_file(classdev, &class_device_attr_frame_header); + device_remove_file(classdev, &dev_attr_frame_header); err_val: - class_device_remove_file(classdev, &class_device_attr_val); + device_remove_file(classdev, &dev_attr_val); err_reg: - class_device_remove_file(classdev, &class_device_attr_reg); + device_remove_file(classdev, &dev_attr_reg); err_out: return err; } diff --git a/drivers/media/video/stv680.c b/drivers/media/video/stv680.c index 4dc5bc714b9..9e009a7ab86 100644 --- a/drivers/media/video/stv680.c +++ b/drivers/media/video/stv680.c @@ -499,13 +499,14 @@ exit: * sysfs ***************************************************************************/ #define stv680_file(name, variable, field) \ -static ssize_t show_##name(struct class_device *class_dev, char *buf) \ +static ssize_t show_##name(struct device *class_dev, \ + struct device_attribute *attr, char *buf) \ { \ struct video_device *vdev = to_video_device(class_dev); \ struct usb_stv *stv = video_get_drvdata(vdev); \ return sprintf(buf, field, stv->variable); \ } \ -static CLASS_DEVICE_ATTR(name, S_IRUGO, show_##name, NULL); +static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL); stv680_file(model, camera_name, "%s\n"); stv680_file(in_use, user, "%d\n"); @@ -520,53 +521,53 @@ static int stv680_create_sysfs_files(struct video_device *vdev) { int rc; - rc = video_device_create_file(vdev, &class_device_attr_model); + rc = video_device_create_file(vdev, &dev_attr_model); if (rc) goto err; - rc = video_device_create_file(vdev, &class_device_attr_in_use); + rc = video_device_create_file(vdev, &dev_attr_in_use); if (rc) goto err_model; - rc = video_device_create_file(vdev, &class_device_attr_streaming); + rc = video_device_create_file(vdev, &dev_attr_streaming); if (rc) goto err_inuse; - rc = video_device_create_file(vdev, &class_device_attr_palette); + rc = video_device_create_file(vdev, &dev_attr_palette); if (rc) goto err_stream; - rc = video_device_create_file(vdev, &class_device_attr_frames_total); + rc = video_device_create_file(vdev, &dev_attr_frames_total); if (rc) goto err_pal; - rc = video_device_create_file(vdev, &class_device_attr_frames_read); + rc = video_device_create_file(vdev, &dev_attr_frames_read); if (rc) goto err_framtot; - rc = video_device_create_file(vdev, &class_device_attr_packets_dropped); + rc = video_device_create_file(vdev, &dev_attr_packets_dropped); if (rc) goto err_framread; - rc = video_device_create_file(vdev, &class_device_attr_decoding_errors); + rc = video_device_create_file(vdev, &dev_attr_decoding_errors); if (rc) goto err_dropped; return 0; err_dropped: - video_device_remove_file(vdev, &class_device_attr_packets_dropped); + video_device_remove_file(vdev, &dev_attr_packets_dropped); err_framread: - video_device_remove_file(vdev, &class_device_attr_frames_read); + video_device_remove_file(vdev, &dev_attr_frames_read); err_framtot: - video_device_remove_file(vdev, &class_device_attr_frames_total); + video_device_remove_file(vdev, &dev_attr_frames_total); err_pal: - video_device_remove_file(vdev, &class_device_attr_palette); + video_device_remove_file(vdev, &dev_attr_palette); err_stream: - video_device_remove_file(vdev, &class_device_attr_streaming); + video_device_remove_file(vdev, &dev_attr_streaming); err_inuse: - video_device_remove_file(vdev, &class_device_attr_in_use); + video_device_remove_file(vdev, &dev_attr_in_use); err_model: - video_device_remove_file(vdev, &class_device_attr_model); + video_device_remove_file(vdev, &dev_attr_model); err: return rc; } static void stv680_remove_sysfs_files(struct video_device *vdev) { - video_device_remove_file(vdev, &class_device_attr_model); - video_device_remove_file(vdev, &class_device_attr_in_use); - video_device_remove_file(vdev, &class_device_attr_streaming); - video_device_remove_file(vdev, &class_device_attr_palette); - video_device_remove_file(vdev, &class_device_attr_frames_total); - video_device_remove_file(vdev, &class_device_attr_frames_read); - video_device_remove_file(vdev, &class_device_attr_packets_dropped); - video_device_remove_file(vdev, &class_device_attr_decoding_errors); + video_device_remove_file(vdev, &dev_attr_model); + video_device_remove_file(vdev, &dev_attr_in_use); + video_device_remove_file(vdev, &dev_attr_streaming); + video_device_remove_file(vdev, &dev_attr_palette); + video_device_remove_file(vdev, &dev_attr_frames_total); + video_device_remove_file(vdev, &dev_attr_frames_read); + video_device_remove_file(vdev, &dev_attr_packets_dropped); + video_device_remove_file(vdev, &dev_attr_decoding_errors); } /******************************************************************** diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c index 2f9b2b9e3b0..e2f3c01cfa1 100644 --- a/drivers/media/video/usbvision/usbvision-video.c +++ b/drivers/media/video/usbvision/usbvision-video.c @@ -182,20 +182,22 @@ MODULE_ALIAS(DRIVER_ALIAS); #define YES_NO(x) ((x) ? "Yes" : "No") -static inline struct usb_usbvision *cd_to_usbvision(struct class_device *cd) +static inline struct usb_usbvision *cd_to_usbvision(struct device *cd) { struct video_device *vdev = container_of(cd, struct video_device, class_dev); return video_get_drvdata(vdev); } -static ssize_t show_version(struct class_device *cd, char *buf) +static ssize_t show_version(struct device *cd, + struct device_attribute *attr, char *buf) { return sprintf(buf, "%s\n", USBVISION_VERSION_STRING); } -static CLASS_DEVICE_ATTR(version, S_IRUGO, show_version, NULL); +static DEVICE_ATTR(version, S_IRUGO, show_version, NULL); -static ssize_t show_model(struct class_device *cd, char *buf) +static ssize_t show_model(struct device *cd, + struct device_attribute *attr, char *buf) { struct video_device *vdev = container_of(cd, struct video_device, class_dev); @@ -203,9 +205,10 @@ static ssize_t show_model(struct class_device *cd, char *buf) return sprintf(buf, "%s\n", usbvision_device_data[usbvision->DevModel].ModelString); } -static CLASS_DEVICE_ATTR(model, S_IRUGO, show_model, NULL); +static DEVICE_ATTR(model, S_IRUGO, show_model, NULL); -static ssize_t show_hue(struct class_device *cd, char *buf) +static ssize_t show_hue(struct device *cd, + struct device_attribute *attr, char *buf) { struct video_device *vdev = container_of(cd, struct video_device, class_dev); @@ -217,9 +220,10 @@ static ssize_t show_hue(struct class_device *cd, char *buf) call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl); return sprintf(buf, "%d\n", ctrl.value); } -static CLASS_DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL); +static DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL); -static ssize_t show_contrast(struct class_device *cd, char *buf) +static ssize_t show_contrast(struct device *cd, + struct device_attribute *attr, char *buf) { struct video_device *vdev = container_of(cd, struct video_device, class_dev); @@ -231,9 +235,10 @@ static ssize_t show_contrast(struct class_device *cd, char *buf) call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl); return sprintf(buf, "%d\n", ctrl.value); } -static CLASS_DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL); +static DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL); -static ssize_t show_brightness(struct class_device *cd, char *buf) +static ssize_t show_brightness(struct device *cd, + struct device_attribute *attr, char *buf) { struct video_device *vdev = container_of(cd, struct video_device, class_dev); @@ -245,9 +250,10 @@ static ssize_t show_brightness(struct class_device *cd, char *buf) call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl); return sprintf(buf, "%d\n", ctrl.value); } -static CLASS_DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL); +static DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL); -static ssize_t show_saturation(struct class_device *cd, char *buf) +static ssize_t show_saturation(struct device *cd, + struct device_attribute *attr, char *buf) { struct video_device *vdev = container_of(cd, struct video_device, class_dev); @@ -259,9 +265,10 @@ static ssize_t show_saturation(struct class_device *cd, char *buf) call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl); return sprintf(buf, "%d\n", ctrl.value); } -static CLASS_DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL); +static DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL); -static ssize_t show_streaming(struct class_device *cd, char *buf) +static ssize_t show_streaming(struct device *cd, + struct device_attribute *attr, char *buf) { struct video_device *vdev = container_of(cd, struct video_device, class_dev); @@ -269,9 +276,10 @@ static ssize_t show_streaming(struct class_device *cd, char *buf) return sprintf(buf, "%s\n", YES_NO(usbvision->streaming==Stream_On?1:0)); } -static CLASS_DEVICE_ATTR(streaming, S_IRUGO, show_streaming, NULL); +static DEVICE_ATTR(streaming, S_IRUGO, show_streaming, NULL); -static ssize_t show_compression(struct class_device *cd, char *buf) +static ssize_t show_compression(struct device *cd, + struct device_attribute *attr, char *buf) { struct video_device *vdev = container_of(cd, struct video_device, class_dev); @@ -279,16 +287,17 @@ static ssize_t show_compression(struct class_device *cd, char *buf) return sprintf(buf, "%s\n", YES_NO(usbvision->isocMode==ISOC_MODE_COMPRESS)); } -static CLASS_DEVICE_ATTR(compression, S_IRUGO, show_compression, NULL); +static DEVICE_ATTR(compression, S_IRUGO, show_compression, NULL); -static ssize_t show_device_bridge(struct class_device *cd, char *buf) +static ssize_t show_device_bridge(struct device *cd, + struct device_attribute *attr, char *buf) { struct video_device *vdev = container_of(cd, struct video_device, class_dev); struct usb_usbvision *usbvision = video_get_drvdata(vdev); return sprintf(buf, "%d\n", usbvision->bridgeType); } -static CLASS_DEVICE_ATTR(bridge, S_IRUGO, show_device_bridge, NULL); +static DEVICE_ATTR(bridge, S_IRUGO, show_device_bridge, NULL); static void usbvision_create_sysfs(struct video_device *vdev) { @@ -296,40 +305,40 @@ static void usbvision_create_sysfs(struct video_device *vdev) if (!vdev) return; do { - res=class_device_create_file(&vdev->class_dev, - &class_device_attr_version); + res = device_create_file(&vdev->class_dev, + &dev_attr_version); if (res<0) break; - res=class_device_create_file(&vdev->class_dev, - &class_device_attr_model); + res = device_create_file(&vdev->class_dev, + &dev_attr_model); if (res<0) break; - res=class_device_create_file(&vdev->class_dev, - &class_device_attr_hue); + res = device_create_file(&vdev->class_dev, + &dev_attr_hue); if (res<0) break; - res=class_device_create_file(&vdev->class_dev, - &class_device_attr_contrast); + res = device_create_file(&vdev->class_dev, + &dev_attr_contrast); if (res<0) break; - res=class_device_create_file(&vdev->class_dev, - &class_device_attr_brightness); + res = device_create_file(&vdev->class_dev, + &dev_attr_brightness); if (res<0) break; - res=class_device_create_file(&vdev->class_dev, - &class_device_attr_saturation); + res = device_create_file(&vdev->class_dev, + &dev_attr_saturation); if (res<0) break; - res=class_device_create_file(&vdev->class_dev, - &class_device_attr_streaming); + res = device_create_file(&vdev->class_dev, + &dev_attr_streaming); if (res<0) break; - res=class_device_create_file(&vdev->class_dev, - &class_device_attr_compression); + res = device_create_file(&vdev->class_dev, + &dev_attr_compression); if (res<0) break; - res=class_device_create_file(&vdev->class_dev, - &class_device_attr_bridge); + res = device_create_file(&vdev->class_dev, + &dev_attr_bridge); if (res>=0) return; } while (0); @@ -340,24 +349,24 @@ static void usbvision_create_sysfs(struct video_device *vdev) static void usbvision_remove_sysfs(struct video_device *vdev) { if (vdev) { - class_device_remove_file(&vdev->class_dev, - &class_device_attr_version); - class_device_remove_file(&vdev->class_dev, - &class_device_attr_model); - class_device_remove_file(&vdev->class_dev, - &class_device_attr_hue); - class_device_remove_file(&vdev->class_dev, - &class_device_attr_contrast); - class_device_remove_file(&vdev->class_dev, - &class_device_attr_brightness); - class_device_remove_file(&vdev->class_dev, - &class_device_attr_saturation); - class_device_remove_file(&vdev->class_dev, - &class_device_attr_streaming); - class_device_remove_file(&vdev->class_dev, - &class_device_attr_compression); - class_device_remove_file(&vdev->class_dev, - &class_device_attr_bridge); + device_remove_file(&vdev->class_dev, + &dev_attr_version); + device_remove_file(&vdev->class_dev, + &dev_attr_model); + device_remove_file(&vdev->class_dev, + &dev_attr_hue); + device_remove_file(&vdev->class_dev, + &dev_attr_contrast); + device_remove_file(&vdev->class_dev, + &dev_attr_brightness); + device_remove_file(&vdev->class_dev, + &dev_attr_saturation); + device_remove_file(&vdev->class_dev, + &dev_attr_streaming); + device_remove_file(&vdev->class_dev, + &dev_attr_compression); + device_remove_file(&vdev->class_dev, + &dev_attr_bridge); } } diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c index 0334b9aaf12..0fbe8a1a91b 100644 --- a/drivers/media/video/videodev.c +++ b/drivers/media/video/videodev.c @@ -54,15 +54,14 @@ * sysfs stuff */ -static ssize_t show_name(struct class_device *cd, char *buf) +static ssize_t show_name(struct device *cd, + struct device_attribute *attr, char *buf) { struct video_device *vfd = container_of(cd, struct video_device, - class_dev); - return sprintf(buf,"%.*s\n",(int)sizeof(vfd->name),vfd->name); + class_dev); + return sprintf(buf, "%.*s\n", (int)sizeof(vfd->name), vfd->name); } -static CLASS_DEVICE_ATTR(name, S_IRUGO, show_name, NULL); - struct video_device *video_device_alloc(void) { struct video_device *vfd; @@ -76,10 +75,9 @@ void video_device_release(struct video_device *vfd) kfree(vfd); } -static void video_release(struct class_device *cd) +static void video_release(struct device *cd) { - struct video_device *vfd = container_of(cd, struct video_device, - class_dev); + struct video_device *vfd = container_of(cd, struct video_device, class_dev); #if 1 /* needed until all drivers are fixed */ @@ -89,9 +87,15 @@ static void video_release(struct class_device *cd) vfd->release(vfd); } +static struct device_attribute video_device_attrs[] = { + __ATTR(name, S_IRUGO, show_name, NULL), + __ATTR_NULL +}; + static struct class video_class = { .name = VIDEO_NAME, - .release = video_release, + .dev_attrs = video_device_attrs, + .dev_release = video_release, }; /* @@ -1753,22 +1757,16 @@ int video_register_device(struct video_device *vfd, int type, int nr) /* sysfs class */ memset(&vfd->class_dev, 0x00, sizeof(vfd->class_dev)); if (vfd->dev) - vfd->class_dev.dev = vfd->dev; + vfd->class_dev.parent = vfd->dev; vfd->class_dev.class = &video_class; vfd->class_dev.devt = MKDEV(VIDEO_MAJOR, vfd->minor); - sprintf(vfd->class_dev.class_id, "%s%d", name_base, i - base); - ret = class_device_register(&vfd->class_dev); + sprintf(vfd->class_dev.bus_id, "%s%d", name_base, i - base); + ret = device_register(&vfd->class_dev); if (ret < 0) { - printk(KERN_ERR "%s: class_device_register failed\n", + printk(KERN_ERR "%s: device_register failed\n", __FUNCTION__); goto fail_minor; } - ret = class_device_create_file(&vfd->class_dev, &class_device_attr_name); - if (ret < 0) { - printk(KERN_ERR "%s: class_device_create_file 'name' failed\n", - __FUNCTION__); - goto fail_classdev; - } #if 1 /* needed until all drivers are fixed */ @@ -1779,8 +1777,6 @@ int video_register_device(struct video_device *vfd, int type, int nr) #endif return 0; -fail_classdev: - class_device_unregister(&vfd->class_dev); fail_minor: mutex_lock(&videodev_lock); video_device[vfd->minor] = NULL; @@ -1804,7 +1800,7 @@ void video_unregister_device(struct video_device *vfd) panic("videodev: bad unregister"); video_device[vfd->minor]=NULL; - class_device_unregister(&vfd->class_dev); + device_unregister(&vfd->class_dev); mutex_unlock(&videodev_lock); } diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h index 8b79e2cf77f..e75d5e6c4ce 100644 --- a/include/media/v4l2-dev.h +++ b/include/media/v4l2-dev.h @@ -86,8 +86,11 @@ struct video_device /* device ops */ const struct file_operations *fops; + /* sysfs */ + struct device class_dev; /* v4l device */ + struct device *dev; /* device parent */ + /* device info */ - struct device *dev; char name[32]; int type; /* v4l1 */ int type2; /* v4l2 */ @@ -332,7 +335,6 @@ void *priv; /* for videodev.c intenal usage -- please don't touch */ int users; /* video_exclusive_{open|close} ... */ struct mutex lock; /* ... helper function uses these */ - struct class_device class_dev; /* sysfs */ }; /* Class-dev to video-device */ @@ -360,18 +362,18 @@ extern int video_usercopy(struct inode *inode, struct file *file, static inline int __must_check video_device_create_file(struct video_device *vfd, - struct class_device_attribute *attr) + struct device_attribute *attr) { - int ret = class_device_create_file(&vfd->class_dev, attr); + int ret = device_create_file(&vfd->class_dev, attr); if (ret < 0) printk(KERN_WARNING "%s error: %d\n", __FUNCTION__, ret); return ret; } static inline void video_device_remove_file(struct video_device *vfd, - struct class_device_attribute *attr) + struct device_attribute *attr) { - class_device_remove_file(&vfd->class_dev, attr); + device_remove_file(&vfd->class_dev, attr); } #endif /* CONFIG_VIDEO_V4L1_COMPAT */ -- cgit v1.2.3-70-g09d2 From 0ac3a5bbca33840542d98420d9d82e8738299b20 Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Mon, 8 Oct 2007 16:13:02 -0300 Subject: V4L/DVB (6295): saa7134: add autodetection for KWorld ATSC-115 Recognize the KWorld ATSC115 PCI ID as a hardware clone of the ATSC110. Signed-off-by: Eric Sandeen Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.saa7134 | 2 +- drivers/media/video/saa7134/saa7134-cards.c | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134 index 67f08cc4be7..a14545300e4 100644 --- a/Documentation/video4linux/CARDLIST.saa7134 +++ b/Documentation/video4linux/CARDLIST.saa7134 @@ -88,7 +88,7 @@ 87 -> ADS Instant TV Duo Cardbus PTV331 [0331:1421] 88 -> Tevion/KWorld DVB-T 220RF [17de:7201] 89 -> ELSA EX-VISION 700TV [1048:226c] - 90 -> Kworld ATSC110 [17de:7350] + 90 -> Kworld ATSC110/115 [17de:7350,17de:7352] 91 -> AVerMedia A169 B [1461:7360] 92 -> AVerMedia A169 B1 [1461:6360] 93 -> Medion 7134 Bridge #2 [16be:0005] diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 62420d599d7..a4c192fb4e4 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -2822,7 +2822,7 @@ struct saa7134_board saa7134_boards[] = { }, }, [SAA7134_BOARD_KWORLD_ATSC110] = { - .name = "Kworld ATSC110", + .name = "Kworld ATSC110/115", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_TUV1236D, .radio_type = UNSET, @@ -4082,6 +4082,12 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = 0x17de, .subdevice = 0x7350, .driver_data = SAA7134_BOARD_KWORLD_ATSC110, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, /* SAA7135HL */ + .subvendor = 0x17de, + .subdevice = 0x7352, + .driver_data = SAA7134_BOARD_KWORLD_ATSC110, /* ATSC 115 */ },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, -- cgit v1.2.3-70-g09d2 From fa3b877e5c75a2f4d1706c40163dbf176a2fd80d Mon Sep 17 00:00:00 2001 From: Joachim Steiger Date: Mon, 8 Oct 2007 20:08:46 -0300 Subject: V4L/DVB (6296): dib0700: add support for AverMedia DVB-T Express card add Avermedia dvb-t express card 34 (usb2) id Signed-off-by: Joachim Steiger Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 7 ++++++- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 063fb5095bd..e8c4a869453 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -820,6 +820,7 @@ struct usb_device_id dib0700_usb_id_table[] = { { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7070PD) }, { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T) }, { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_VIDEOMATE_U500_PC) }, +/* 20 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_EXPRESS) }, { 0 } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); @@ -861,7 +862,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { }, }, - .num_device_descs = 6, + .num_device_descs = 7, .devices = { { "DiBcom STK7700P reference design", { &dib0700_usb_id_table[0], &dib0700_usb_id_table[1] }, @@ -886,6 +887,10 @@ struct dvb_usb_device_properties dib0700_devices[] = { { "Leadtek Winfast DTV Dongle (STK7700P based)", { &dib0700_usb_id_table[8], NULL }, { NULL }, + }, + { "AVerMedia AVerTV DVB-T Express", + { &dib0700_usb_id_table[20] }, + { NULL }, } }, diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 43bfe50a222..4fa3e895028 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -121,6 +121,7 @@ #define USB_PID_HAUPPAUGE_NOVA_T_STICK 0x7050 #define USB_PID_HAUPPAUGE_NOVA_T_STICK_2 0x7060 #define USB_PID_HAUPPAUGE_NOVA_TD_STICK 0x9580 +#define USB_PID_AVERMEDIA_EXPRESS 0xb568 #define USB_PID_AVERMEDIA_VOLAR 0xa807 #define USB_PID_AVERMEDIA_VOLAR_2 0xb808 #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a -- cgit v1.2.3-70-g09d2 From 21a7ad4a7e86a5da16caf61eb50bc92af4929672 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 8 Oct 2007 17:18:17 -0300 Subject: V4L/DVB (6297): cx23885: remove wrong Kconfig selection of VIDEOBUF fix bad Kconfig dependency of cx23885 module. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/Kconfig | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig index af60700da8c..72004a07b2d 100644 --- a/drivers/media/video/cx23885/Kconfig +++ b/drivers/media/video/cx23885/Kconfig @@ -4,7 +4,6 @@ config VIDEO_CX23885 select I2C_ALGOBIT select FW_LOADER select VIDEO_BTCX - select VIDEOBUF select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEO_IR -- cgit v1.2.3-70-g09d2 From 102abd826a20307c5a0d23f49b8a3b5d98bddf94 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Mon, 8 Oct 2007 18:34:11 -0300 Subject: V4L/DVB (6299): dvb: Add dependencies for VIDEOBUF_DVB It needs to select VIDEOBUF_GEN and VIDEOBUF_DMA_SG, since it uses those modules. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index e705265909d..dd9bd4310c8 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -140,6 +140,8 @@ config VIDEOBUF_VMALLOC config VIDEOBUF_DVB tristate + select VIDEOBUF_GEN + select VIDEOBUF_DMA_SG config VIDEO_BTCX tristate -- cgit v1.2.3-70-g09d2 From bde00cc027879a39f249ffedb048032cb7e484e4 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Mon, 8 Oct 2007 18:36:21 -0300 Subject: V4L/DVB (6300): CodingStyle cleanup Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videodev.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c index 0fbe8a1a91b..8d8e517b344 100644 --- a/drivers/media/video/videodev.c +++ b/drivers/media/video/videodev.c @@ -77,7 +77,8 @@ void video_device_release(struct video_device *vfd) static void video_release(struct device *cd) { - struct video_device *vfd = container_of(cd, struct video_device, class_dev); + struct video_device *vfd = container_of(cd, struct video_device, + class_dev); #if 1 /* needed until all drivers are fixed */ -- cgit v1.2.3-70-g09d2 From c726b65d079cafabc558616badbeead442e2b114 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Mon, 8 Oct 2007 19:05:28 -0300 Subject: V4L/DVB (6301): pvrusb: Update DEBUGIFC sysfs to kernel 2.6.13+ The prototypes for the show and store methods of a device_attribute changed in kernel 2.6.13, but the code in pvrusb2 was never updated. I guess the DEBUGIFC stuff isn't used much.... Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-sysfs.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c index b20dc4421d5..7a78d6b3473 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c +++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c @@ -609,9 +609,12 @@ static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id) } #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC -static ssize_t debuginfo_show(struct device *,char *); -static ssize_t debugcmd_show(struct device *,char *); -static ssize_t debugcmd_store(struct device *,const char *,size_t count); +static ssize_t debuginfo_show(struct device *, struct device_attribute *, + char *); +static ssize_t debugcmd_show(struct device *, struct device_attribute *, + char *); +static ssize_t debugcmd_store(struct device *, struct device_attribute *, + const char *, size_t count); static void pvr2_sysfs_add_debugifc(struct pvr2_sysfs *sfp) { @@ -937,7 +940,8 @@ void pvr2_sysfs_class_destroy(struct pvr2_sysfs_class *clp) #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC -static ssize_t debuginfo_show(struct device *class_dev,char *buf) +static ssize_t debuginfo_show(struct device *class_dev, + struct device_attribute *attr, char *buf) { struct pvr2_sysfs *sfp; sfp = (struct pvr2_sysfs *)class_dev->driver_data; @@ -947,7 +951,8 @@ static ssize_t debuginfo_show(struct device *class_dev,char *buf) } -static ssize_t debugcmd_show(struct device *class_dev,char *buf) +static ssize_t debugcmd_show(struct device *class_dev, + struct device_attribute *attr, char *buf) { struct pvr2_sysfs *sfp; sfp = (struct pvr2_sysfs *)class_dev->driver_data; @@ -957,6 +962,7 @@ static ssize_t debugcmd_show(struct device *class_dev,char *buf) static ssize_t debugcmd_store(struct device *class_dev, + struct device_attribute *attr, const char *buf, size_t count) { struct pvr2_sysfs *sfp; -- cgit v1.2.3-70-g09d2 From 49ee718ef51f4d938f80f67207e1bfa2a38897a4 Mon Sep 17 00:00:00 2001 From: Brandon Philips Date: Fri, 5 Oct 2007 16:26:27 -0300 Subject: V4L/DVB (6305): V4L: videobuf-core.c avoid NULL dereferences in videobuf-core The return value of videobuf_alloc() is unchecked but this function will return NULL on an error. Check for NULL and make videobuf_reqbufs() return the number of successfully allocated buffers. Also, fix saa7146_video.c and bttv-driver.c to use this returned buffer count. Tested against the vivi driver. Not tested against saa7146 or bt8xx devices. Signed-off-by: Brandon Philips Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/saa7146_video.c | 2 ++ drivers/media/video/bt8xx/bttv-driver.c | 2 ++ drivers/media/video/videobuf-core.c | 18 +++++++++++++----- 3 files changed, 17 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c index 29dbc602a48..f245a3b2ef4 100644 --- a/drivers/media/common/saa7146_video.c +++ b/drivers/media/common/saa7146_video.c @@ -1212,6 +1212,8 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int mutex_unlock(&q->lock); return err; } + + gbuffers = err; memset(mbuf,0,sizeof(*mbuf)); mbuf->frames = gbuffers; mbuf->size = gbuffers * gbufsize; diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index 49278537eec..7a332b3efe5 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -3072,6 +3072,8 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, V4L2_MEMORY_MMAP); if (retval < 0) goto fh_unlock_and_return; + + gbuffers = retval; memset(mbuf,0,sizeof(*mbuf)); mbuf->frames = gbuffers; mbuf->size = gbuffers * gbufsize; diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index f5c5ea8b6b0..25a98496e3d 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c @@ -329,7 +329,7 @@ int videobuf_reqbufs(struct videobuf_queue *q, goto done; } - req->count = count; + req->count = retval; done: mutex_unlock(&q->lock); @@ -698,7 +698,7 @@ int videobuf_read_start(struct videobuf_queue *q) { enum v4l2_field field; unsigned long flags=0; - int count = 0, size = 0; + unsigned int count = 0, size = 0; int err, i; q->ops->buf_setup(q,&count,&size); @@ -709,9 +709,11 @@ int videobuf_read_start(struct videobuf_queue *q) size = PAGE_ALIGN(size); err = videobuf_mmap_setup(q, count, size, V4L2_MEMORY_USERPTR); - if (err) + if (err < 0) return err; + count = err; + for (i = 0; i < count; i++) { field = videobuf_next_field(q); err = q->ops->buf_prepare(q,q->bufs[i],field); @@ -876,6 +878,9 @@ int videobuf_mmap_setup(struct videobuf_queue *q, for (i = 0; i < bcount; i++) { q->bufs[i] = videobuf_alloc(q); + if (q->bufs[i] == NULL) + break; + q->bufs[i]->i = i; q->bufs[i]->input = UNSET; q->bufs[i]->memory = memory; @@ -891,10 +896,13 @@ int videobuf_mmap_setup(struct videobuf_queue *q, } } + if (!i) + return -ENOMEM; + dprintk(1,"mmap setup: %d buffers, %d bytes each\n", - bcount,bsize); + i, bsize); - return 0; + return i; } int videobuf_mmap_free(struct videobuf_queue *q) -- cgit v1.2.3-70-g09d2 From acd827d63a568a2cfa26ae8e6093b098c91c631b Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Mon, 8 Oct 2007 12:07:35 -0300 Subject: V4L/DVB (6306): Few clenups for saa7134 resume code *Disable DMA explictly on suspend *Enable DMA on resume, after all buffers were configured *Disable overlay on resume - apps should enable it when X is resumed Signed-off-by: Maxim Levitsky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-core.c | 38 ++++++++++++++------------- drivers/media/video/saa7134/saa7134-tvaudio.c | 2 +- drivers/media/video/saa7134/saa7134.h | 2 +- 3 files changed, 22 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index fae0bfe7939..80f04f252fc 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -398,29 +398,23 @@ void saa7134_buffer_timeout(unsigned long data) int saa7134_buffer_requeue(struct saa7134_dev *dev, struct saa7134_dmaqueue *q) { - struct saa7134_buf *buf , *next; - unsigned long flags; + struct saa7134_buf *buf, *next; - spin_lock_irqsave(&dev->slock, flags); + assert_spin_locked(&dev->slock); buf = q->curr; next = buf; - dprintk("buffer_requeue\n"); - if (!buf) { - spin_unlock_irqrestore(&dev->slock, flags); + if (!buf) return 0; - } dprintk("buffer_requeue : resending active buffers \n"); if (!list_empty(&q->queue)) next = list_entry(q->queue.next, struct saa7134_buf, vb.queue); - buf->activate(dev, buf, next); - spin_unlock_irqrestore(&dev->slock, flags); return 0; } @@ -435,6 +429,9 @@ int saa7134_set_dmabits(struct saa7134_dev *dev) assert_spin_locked(&dev->slock); + if (dev->inresume) + return 0; + /* video capture -- dma 0 + video task A */ if (dev->video_q.curr) { task |= 0x01; @@ -1175,13 +1172,15 @@ static void __devexit saa7134_finidev(struct pci_dev *pci_dev) static int saa7134_suspend(struct pci_dev *pci_dev , pm_message_t state) { - /* Disable card's IRQs to prevent it from resuming computer */ - struct saa7134_dev *dev = pci_get_drvdata(pci_dev); + /* disable overlay - apps should enable it explicitly on resume*/ + dev->ovenable = 0; + + /* Disable interrupts, DMA, and rest of the chip*/ saa_writel(SAA7134_IRQ1, 0); saa_writel(SAA7134_IRQ2, 0); - + saa_writel(SAA7134_MAIN_CTRL, 0); pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state)); pci_save_state(pci_dev); @@ -1193,6 +1192,7 @@ static int saa7134_resume(struct pci_dev *pci_dev) { struct saa7134_dev *dev = pci_get_drvdata(pci_dev); + unsigned int flags; pci_restore_state(pci_dev); pci_set_power_state(pci_dev, PCI_D0); @@ -1200,6 +1200,7 @@ static int saa7134_resume(struct pci_dev *pci_dev) /* Do things that are done in saa7134_initdev , except of initializing memory structures.*/ + dev->inresume = 1; saa7134_board_init1(dev); if (saa7134_boards[dev->board].video_out) @@ -1209,25 +1210,26 @@ static int saa7134_resume(struct pci_dev *pci_dev) saa7134_ts_init_hw(dev); saa7134_hw_enable1(dev); - saa7134_set_decoder(dev); - saa7134_i2c_call_clients(dev, VIDIOC_S_STD, &dev->tvnorm->id); - saa7134_board_init2(dev); saa7134_hw_enable2(dev); - dev->force_mute_update = 1; saa7134_tvaudio_setmute(dev); - dev->force_mute_update = 0; saa7134_tvaudio_setvolume(dev, dev->ctl_volume); saa7134_enable_i2s(dev); - /*recapture unfinished buffer(s)*/ + /*resume unfinished buffer(s)*/ + spin_lock_irqsave(&dev->slock, flags); saa7134_buffer_requeue(dev, &dev->video_q); saa7134_buffer_requeue(dev, &dev->vbi_q); saa7134_buffer_requeue(dev, &dev->ts_q); + /* start DMA now*/ + dev->inresume = 0; + saa7134_set_dmabits(dev); + spin_unlock_irqrestore(&dev->slock, flags); + return 0; } diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c index df2dab06387..1b9e39a5ea4 100644 --- a/drivers/media/video/saa7134/saa7134-tvaudio.c +++ b/drivers/media/video/saa7134/saa7134-tvaudio.c @@ -231,7 +231,7 @@ static void mute_input_7134(struct saa7134_dev *dev) } if (dev->hw_mute == mute && - dev->hw_input == in && !dev->force_mute_update) { + dev->hw_input == in && !dev->inresume) { dprintk("mute/input: nothing to do [mute=%d,input=%s]\n", mute,in->name); return; diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 064f3dbe695..28ec6804bd5 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -522,9 +522,9 @@ struct saa7134_dev { struct saa7134_input *input; struct saa7134_input *hw_input; unsigned int hw_mute; - unsigned int force_mute_update; int last_carrier; int nosignal; + unsigned int inresume; /* SAA7134_MPEG_* */ struct saa7134_ts ts; -- cgit v1.2.3-70-g09d2 From 3abff557d5eed7d6fd03aa11353a1c0f329cac2b Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 9 Oct 2007 22:03:12 -0300 Subject: V4L/DVB (6307): V4L: w9968cf, remove bad usage of ERESTARTSYS w9968cf, remove bad usage of ERESTARTSYS down_read_trylock can't be interrupted and so ERESTARTSYS would reach userspace, which is not permitted. Change it to EAGAIN Signed-off-by: Jiri Slaby Acked-by: Luca Risolia Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/w9968cf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/w9968cf.c b/drivers/media/video/w9968cf.c index 77599f228b6..5a1b5f5a7d4 100644 --- a/drivers/media/video/w9968cf.c +++ b/drivers/media/video/w9968cf.c @@ -2679,7 +2679,7 @@ static int w9968cf_open(struct inode* inode, struct file* filp) /* This the only safe way to prevent race conditions with disconnect */ if (!down_read_trylock(&w9968cf_disconnect)) - return -ERESTARTSYS; + return -EAGAIN; cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); -- cgit v1.2.3-70-g09d2 From c3e2a8e64cb2282a406ff6e63f7bd09eb6f61a1d Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 9 Oct 2007 22:15:27 -0300 Subject: V4L/DVB (6308): V4L: zc0301, remove bad usage of ERESTARTSYS zc0301, remove bad usage of ERESTARTSYS down_read_trylock can't be interrupted and so ERESTARTSYS would reach userspace, which is not permitted. Change it to EAGAIN Signed-off-by: Jiri Slaby Acked-by: Luca Risolia Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/zc0301/zc0301_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/zc0301/zc0301_core.c b/drivers/media/video/zc0301/zc0301_core.c index 35138c594be..08a93c31c0a 100644 --- a/drivers/media/video/zc0301/zc0301_core.c +++ b/drivers/media/video/zc0301/zc0301_core.c @@ -655,7 +655,7 @@ static int zc0301_open(struct inode* inode, struct file* filp) int err = 0; if (!down_read_trylock(&zc0301_dev_lock)) - return -ERESTARTSYS; + return -EAGAIN; cam = video_get_drvdata(video_devdata(filp)); -- cgit v1.2.3-70-g09d2 From 210d6ca3db058cd1d6e6fd235ee3e25d6ac221cd Mon Sep 17 00:00:00 2001 From: Ralph Campbell Date: Tue, 24 Jul 2007 13:55:39 -0700 Subject: IB/ipath: Performance optimization for CPU differences Different processors have different ordering restrictions for write combining. By taking advantage of this, we can eliminate some write barriers when writing to the send buffers. Signed-off-by: Ralph Campbell Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_diag.c | 22 +++++----- drivers/infiniband/hw/ipath/ipath_iba6120.c | 2 + drivers/infiniband/hw/ipath/ipath_kernel.h | 2 + drivers/infiniband/hw/ipath/ipath_verbs.c | 62 +++++++++++++++++------------ 4 files changed, 53 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ipath/ipath_diag.c b/drivers/infiniband/hw/ipath/ipath_diag.c index cf25cdab02f..4137c7770f1 100644 --- a/drivers/infiniband/hw/ipath/ipath_diag.c +++ b/drivers/infiniband/hw/ipath/ipath_diag.c @@ -446,19 +446,21 @@ static ssize_t ipath_diagpkt_write(struct file *fp, dd->ipath_unit, plen - 1, pbufn); if (dp.pbc_wd == 0) - /* Legacy operation, use computed pbc_wd */ dp.pbc_wd = plen; - - /* we have to flush after the PBC for correctness on some cpus - * or WC buffer can be written out of order */ writeq(dp.pbc_wd, piobuf); - ipath_flush_wc(); - /* copy all by the trigger word, then flush, so it's written + /* + * Copy all by the trigger word, then flush, so it's written * to chip before trigger word, then write trigger word, then - * flush again, so packet is sent. */ - __iowrite32_copy(piobuf + 2, tmpbuf, clen - 1); - ipath_flush_wc(); - __raw_writel(tmpbuf[clen - 1], piobuf + clen + 1); + * flush again, so packet is sent. + */ + if (dd->ipath_flags & IPATH_PIO_FLUSH_WC) { + ipath_flush_wc(); + __iowrite32_copy(piobuf + 2, tmpbuf, clen - 1); + ipath_flush_wc(); + __raw_writel(tmpbuf[clen - 1], piobuf + clen + 1); + } else + __iowrite32_copy(piobuf + 2, tmpbuf, clen); + ipath_flush_wc(); ret = sizeof(dp); diff --git a/drivers/infiniband/hw/ipath/ipath_iba6120.c b/drivers/infiniband/hw/ipath/ipath_iba6120.c index 5b6ac9a1a70..a324c6f7aeb 100644 --- a/drivers/infiniband/hw/ipath/ipath_iba6120.c +++ b/drivers/infiniband/hw/ipath/ipath_iba6120.c @@ -1273,6 +1273,8 @@ static void ipath_pe_tidtemplate(struct ipath_devdata *dd) static int ipath_pe_early_init(struct ipath_devdata *dd) { dd->ipath_flags |= IPATH_4BYTE_TID; + if (ipath_unordered_wc()) + dd->ipath_flags |= IPATH_PIO_FLUSH_WC; /* * For openfabrics, we need to be able to handle an IB header of diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h index 7a7966f7e4f..d983f92b9bc 100644 --- a/drivers/infiniband/hw/ipath/ipath_kernel.h +++ b/drivers/infiniband/hw/ipath/ipath_kernel.h @@ -724,6 +724,8 @@ int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv); #define IPATH_LINKACTIVE 0x200 /* link current state is unknown */ #define IPATH_LINKUNK 0x400 + /* Write combining flush needed for PIO */ +#define IPATH_PIO_FLUSH_WC 0x1000 /* no IB cable, or no device on IB cable */ #define IPATH_NOCABLE 0x4000 /* Supports port zero per packet receive interrupts via diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c index 16aa61fd808..559d4a66293 100644 --- a/drivers/infiniband/hw/ipath/ipath_verbs.c +++ b/drivers/infiniband/hw/ipath/ipath_verbs.c @@ -631,7 +631,7 @@ static inline u32 clear_upper_bytes(u32 data, u32 n, u32 off) #endif static void copy_io(u32 __iomem *piobuf, struct ipath_sge_state *ss, - u32 length) + u32 length, unsigned flush_wc) { u32 extra = 0; u32 data = 0; @@ -757,11 +757,14 @@ static void copy_io(u32 __iomem *piobuf, struct ipath_sge_state *ss, } /* Update address before sending packet. */ update_sge(ss, length); - /* must flush early everything before trigger word */ - ipath_flush_wc(); - __raw_writel(last, piobuf); - /* be sure trigger word is written */ - ipath_flush_wc(); + if (flush_wc) { + /* must flush early everything before trigger word */ + ipath_flush_wc(); + __raw_writel(last, piobuf); + /* be sure trigger word is written */ + ipath_flush_wc(); + } else + __raw_writel(last, piobuf); } /** @@ -776,6 +779,7 @@ int ipath_verbs_send(struct ipath_devdata *dd, u32 hdrwords, u32 *hdr, u32 len, struct ipath_sge_state *ss) { u32 __iomem *piobuf; + unsigned flush_wc; u32 plen; int ret; @@ -799,47 +803,55 @@ int ipath_verbs_send(struct ipath_devdata *dd, u32 hdrwords, * or WC buffer can be written out of order. */ writeq(plen, piobuf); - ipath_flush_wc(); piobuf += 2; + + flush_wc = dd->ipath_flags & IPATH_PIO_FLUSH_WC; if (len == 0) { /* * If there is just the header portion, must flush before * writing last word of header for correctness, and after * the last header word (trigger word). */ - __iowrite32_copy(piobuf, hdr, hdrwords - 1); - ipath_flush_wc(); - __raw_writel(hdr[hdrwords - 1], piobuf + hdrwords - 1); - ipath_flush_wc(); - ret = 0; - goto bail; + if (flush_wc) { + ipath_flush_wc(); + __iowrite32_copy(piobuf, hdr, hdrwords - 1); + ipath_flush_wc(); + __raw_writel(hdr[hdrwords - 1], piobuf + hdrwords - 1); + ipath_flush_wc(); + } else + __iowrite32_copy(piobuf, hdr, hdrwords); + goto done; } + if (flush_wc) + ipath_flush_wc(); __iowrite32_copy(piobuf, hdr, hdrwords); piobuf += hdrwords; /* The common case is aligned and contained in one segment. */ if (likely(ss->num_sge == 1 && len <= ss->sge.length && !((unsigned long)ss->sge.vaddr & (sizeof(u32) - 1)))) { - u32 w; + u32 dwords; u32 *addr = (u32 *) ss->sge.vaddr; /* Update address before sending packet. */ update_sge(ss, len); /* Need to round up for the last dword in the packet. */ - w = (len + 3) >> 2; - __iowrite32_copy(piobuf, addr, w - 1); - /* must flush early everything before trigger word */ - ipath_flush_wc(); - __raw_writel(addr[w - 1], piobuf + w - 1); - /* be sure trigger word is written */ - ipath_flush_wc(); - ret = 0; - goto bail; + dwords = (len + 3) >> 2; + if (flush_wc) { + __iowrite32_copy(piobuf, addr, dwords - 1); + /* must flush early everything before trigger word */ + ipath_flush_wc(); + __raw_writel(addr[dwords - 1], piobuf + dwords - 1); + /* be sure trigger word is written */ + ipath_flush_wc(); + } else + __iowrite32_copy(piobuf, addr, dwords); + goto done; } - copy_io(piobuf, ss, len); + copy_io(piobuf, ss, len, flush_wc); +done: ret = 0; - bail: return ret; } -- cgit v1.2.3-70-g09d2 From 4ee97180ac76deb5a715ac45b7d7516e6ee82ae7 Mon Sep 17 00:00:00 2001 From: Ralph Campbell Date: Wed, 25 Jul 2007 11:08:28 -0700 Subject: IB/ipath: Change UD to queue work requests like RC & UC The code to post UD sends tried to process work requests at the time ib_post_send() is called without using a WQE queue. This was fine as long as HW resources were available for sending a packet. This patch changes UD to be handled more like RC and UC and shares more code. Signed-off-by: Ralph Campbell Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_qp.c | 11 +- drivers/infiniband/hw/ipath/ipath_rc.c | 61 +++-- drivers/infiniband/hw/ipath/ipath_ruc.c | 308 +++++++++---------------- drivers/infiniband/hw/ipath/ipath_uc.c | 77 +++---- drivers/infiniband/hw/ipath/ipath_ud.c | 372 ++++++++++-------------------- drivers/infiniband/hw/ipath/ipath_verbs.c | 241 ++++++++++++------- drivers/infiniband/hw/ipath/ipath_verbs.h | 35 ++- 7 files changed, 494 insertions(+), 611 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ipath/ipath_qp.c b/drivers/infiniband/hw/ipath/ipath_qp.c index 1324b35ff1f..a8c4a6b03d7 100644 --- a/drivers/infiniband/hw/ipath/ipath_qp.c +++ b/drivers/infiniband/hw/ipath/ipath_qp.c @@ -338,6 +338,7 @@ static void ipath_reset_qp(struct ipath_qp *qp) qp->s_busy = 0; qp->s_flags &= IPATH_S_SIGNAL_REQ_WR; qp->s_hdrwords = 0; + qp->s_wqe = NULL; qp->s_psn = 0; qp->r_psn = 0; qp->r_msn = 0; @@ -751,6 +752,9 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd, switch (init_attr->qp_type) { case IB_QPT_UC: case IB_QPT_RC: + case IB_QPT_UD: + case IB_QPT_SMI: + case IB_QPT_GSI: sz = sizeof(struct ipath_sge) * init_attr->cap.max_send_sge + sizeof(struct ipath_swqe); @@ -759,10 +763,6 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd, ret = ERR_PTR(-ENOMEM); goto bail; } - /* FALLTHROUGH */ - case IB_QPT_UD: - case IB_QPT_SMI: - case IB_QPT_GSI: sz = sizeof(*qp); if (init_attr->srq) { struct ipath_srq *srq = to_isrq(init_attr->srq); @@ -805,8 +805,7 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd, spin_lock_init(&qp->r_rq.lock); atomic_set(&qp->refcount, 0); init_waitqueue_head(&qp->wait); - tasklet_init(&qp->s_task, ipath_do_ruc_send, - (unsigned long)qp); + tasklet_init(&qp->s_task, ipath_do_send, (unsigned long)qp); INIT_LIST_HEAD(&qp->piowait); INIT_LIST_HEAD(&qp->timerwait); qp->state = IB_QPS_RESET; diff --git a/drivers/infiniband/hw/ipath/ipath_rc.c b/drivers/infiniband/hw/ipath/ipath_rc.c index 46744ea2bab..53259daeb4f 100644 --- a/drivers/infiniband/hw/ipath/ipath_rc.c +++ b/drivers/infiniband/hw/ipath/ipath_rc.c @@ -81,9 +81,8 @@ static void ipath_init_restart(struct ipath_qp *qp, struct ipath_swqe *wqe) * Note that we are in the responder's side of the QP context. * Note the QP s_lock must be held. */ -static int ipath_make_rc_ack(struct ipath_qp *qp, - struct ipath_other_headers *ohdr, - u32 pmtu, u32 *bth0p, u32 *bth2p) +static int ipath_make_rc_ack(struct ipath_ibdev *dev, struct ipath_qp *qp, + struct ipath_other_headers *ohdr, u32 pmtu) { struct ipath_ack_entry *e; u32 hwords; @@ -192,8 +191,7 @@ static int ipath_make_rc_ack(struct ipath_qp *qp, } qp->s_hdrwords = hwords; qp->s_cur_size = len; - *bth0p = bth0 | (1 << 22); /* Set M bit */ - *bth2p = bth2; + ipath_make_ruc_header(dev, qp, ohdr, bth0, bth2); return 1; bail: @@ -203,32 +201,39 @@ bail: /** * ipath_make_rc_req - construct a request packet (SEND, RDMA r/w, ATOMIC) * @qp: a pointer to the QP - * @ohdr: a pointer to the IB header being constructed - * @pmtu: the path MTU - * @bth0p: pointer to the BTH opcode word - * @bth2p: pointer to the BTH PSN word * * Return 1 if constructed; otherwise, return 0. - * Note the QP s_lock must be held and interrupts disabled. */ -int ipath_make_rc_req(struct ipath_qp *qp, - struct ipath_other_headers *ohdr, - u32 pmtu, u32 *bth0p, u32 *bth2p) +int ipath_make_rc_req(struct ipath_qp *qp) { struct ipath_ibdev *dev = to_idev(qp->ibqp.device); + struct ipath_other_headers *ohdr; struct ipath_sge_state *ss; struct ipath_swqe *wqe; u32 hwords; u32 len; u32 bth0; u32 bth2; + u32 pmtu = ib_mtu_enum_to_int(qp->path_mtu); char newreq; + unsigned long flags; + int ret = 0; + + ohdr = &qp->s_hdr.u.oth; + if (qp->remote_ah_attr.ah_flags & IB_AH_GRH) + ohdr = &qp->s_hdr.u.l.oth; + + /* + * The lock is needed to synchronize between the sending tasklet, + * the receive interrupt handler, and timeout resends. + */ + spin_lock_irqsave(&qp->s_lock, flags); /* Sending responses has higher priority over sending requests. */ if ((qp->r_head_ack_queue != qp->s_tail_ack_queue || (qp->s_flags & IPATH_S_ACK_PENDING) || qp->s_ack_state != OP(ACKNOWLEDGE)) && - ipath_make_rc_ack(qp, ohdr, pmtu, bth0p, bth2p)) + ipath_make_rc_ack(dev, qp, ohdr, pmtu)) goto done; if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK) || @@ -560,13 +565,12 @@ int ipath_make_rc_req(struct ipath_qp *qp, qp->s_hdrwords = hwords; qp->s_cur_sge = ss; qp->s_cur_size = len; - *bth0p = bth0 | (qp->s_state << 24); - *bth2p = bth2; + ipath_make_ruc_header(dev, qp, ohdr, bth0 | (qp->s_state << 24), bth2); done: - return 1; - + ret = 1; bail: - return 0; + spin_unlock_irqrestore(&qp->s_lock, flags); + return ret; } /** @@ -627,7 +631,7 @@ static void send_rc_ack(struct ipath_qp *qp) /* * If we can send the ACK, clear the ACK state. */ - if (ipath_verbs_send(dev->dd, hwords, (u32 *) &hdr, 0, NULL) == 0) { + if (ipath_verbs_send(qp, &hdr, hwords, NULL, 0) == 0) { dev->n_unicast_xmit++; goto done; } @@ -757,7 +761,9 @@ void ipath_restart_rc(struct ipath_qp *qp, u32 psn, struct ib_wc *wc) wc->vendor_err = 0; wc->byte_len = 0; wc->qp = &qp->ibqp; + wc->imm_data = 0; wc->src_qp = qp->remote_qpn; + wc->wc_flags = 0; wc->pkey_index = 0; wc->slid = qp->remote_ah_attr.dlid; wc->sl = qp->remote_ah_attr.sl; @@ -1041,7 +1047,9 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode, wc.vendor_err = 0; wc.byte_len = 0; wc.qp = &qp->ibqp; + wc.imm_data = 0; wc.src_qp = qp->remote_qpn; + wc.wc_flags = 0; wc.pkey_index = 0; wc.slid = qp->remote_ah_attr.dlid; wc.sl = qp->remote_ah_attr.sl; @@ -1453,6 +1461,19 @@ static inline int ipath_rc_rcv_error(struct ipath_ibdev *dev, qp->r_ack_psn = qp->r_psn - 1; goto send_ack; } + /* + * Try to send a simple ACK to work around a Mellanox bug + * which doesn't accept a RDMA read response or atomic + * response as an ACK for earlier SENDs or RDMA writes. + */ + if (qp->r_head_ack_queue == qp->s_tail_ack_queue && + !(qp->s_flags & IPATH_S_ACK_PENDING) && + qp->s_ack_state == OP(ACKNOWLEDGE)) { + spin_unlock_irqrestore(&qp->s_lock, flags); + qp->r_nak_state = 0; + qp->r_ack_psn = qp->s_ack_queue[i].psn - 1; + goto send_ack; + } /* * Resend the RDMA read or atomic op which * ACKs this duplicate request. diff --git a/drivers/infiniband/hw/ipath/ipath_ruc.c b/drivers/infiniband/hw/ipath/ipath_ruc.c index c69c2523944..4b6b7ee8e5c 100644 --- a/drivers/infiniband/hw/ipath/ipath_ruc.c +++ b/drivers/infiniband/hw/ipath/ipath_ruc.c @@ -31,6 +31,8 @@ * SOFTWARE. */ +#include + #include "ipath_verbs.h" #include "ipath_kernel.h" @@ -106,27 +108,30 @@ void ipath_insert_rnr_queue(struct ipath_qp *qp) spin_unlock_irqrestore(&dev->pending_lock, flags); } -static int init_sge(struct ipath_qp *qp, struct ipath_rwqe *wqe) +/** + * ipath_init_sge - Validate a RWQE and fill in the SGE state + * @qp: the QP + * + * Return 1 if OK. + */ +int ipath_init_sge(struct ipath_qp *qp, struct ipath_rwqe *wqe, + u32 *lengthp, struct ipath_sge_state *ss) { - int user = to_ipd(qp->ibqp.pd)->user; int i, j, ret; struct ib_wc wc; - qp->r_len = 0; + *lengthp = 0; for (i = j = 0; i < wqe->num_sge; i++) { if (wqe->sg_list[i].length == 0) continue; /* Check LKEY */ - if ((user && wqe->sg_list[i].lkey == 0) || - !ipath_lkey_ok(qp, &qp->r_sg_list[j], &wqe->sg_list[i], - IB_ACCESS_LOCAL_WRITE)) + if (!ipath_lkey_ok(qp, j ? &ss->sg_list[j - 1] : &ss->sge, + &wqe->sg_list[i], IB_ACCESS_LOCAL_WRITE)) goto bad_lkey; - qp->r_len += wqe->sg_list[i].length; + *lengthp += wqe->sg_list[i].length; j++; } - qp->r_sge.sge = qp->r_sg_list[0]; - qp->r_sge.sg_list = qp->r_sg_list + 1; - qp->r_sge.num_sge = j; + ss->num_sge = j; ret = 1; goto bail; @@ -172,6 +177,8 @@ int ipath_get_rwqe(struct ipath_qp *qp, int wr_id_only) u32 tail; int ret; + qp->r_sge.sg_list = qp->r_sg_list; + if (qp->ibqp.srq) { srq = to_isrq(qp->ibqp.srq); handler = srq->ibsrq.event_handler; @@ -199,7 +206,8 @@ int ipath_get_rwqe(struct ipath_qp *qp, int wr_id_only) wqe = get_rwqe_ptr(rq, tail); if (++tail >= rq->size) tail = 0; - } while (!wr_id_only && !init_sge(qp, wqe)); + } while (!wr_id_only && !ipath_init_sge(qp, wqe, &qp->r_len, + &qp->r_sge)); qp->r_wr_id = wqe->wr_id; wq->tail = tail; @@ -239,9 +247,9 @@ bail: /** * ipath_ruc_loopback - handle UC and RC lookback requests - * @sqp: the loopback QP + * @sqp: the sending QP * - * This is called from ipath_do_uc_send() or ipath_do_rc_send() to + * This is called from ipath_do_send() to * forward a WQE addressed to the same HCA. * Note that although we are single threaded due to the tasklet, we still * have to protect against post_send(). We don't have to worry about @@ -450,40 +458,18 @@ again: wc.byte_len = wqe->length; wc.qp = &qp->ibqp; wc.src_qp = qp->remote_qpn; - /* XXX do we know which pkey matched? Only needed for GSI. */ wc.pkey_index = 0; wc.slid = qp->remote_ah_attr.dlid; wc.sl = qp->remote_ah_attr.sl; wc.dlid_path_bits = 0; + wc.port_num = 1; /* Signal completion event if the solicited bit is set. */ ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, wqe->wr.send_flags & IB_SEND_SOLICITED); send_comp: sqp->s_rnr_retry = sqp->s_rnr_retry_cnt; - - if (!(sqp->s_flags & IPATH_S_SIGNAL_REQ_WR) || - (wqe->wr.send_flags & IB_SEND_SIGNALED)) { - wc.wr_id = wqe->wr.wr_id; - wc.status = IB_WC_SUCCESS; - wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode]; - wc.vendor_err = 0; - wc.byte_len = wqe->length; - wc.qp = &sqp->ibqp; - wc.src_qp = 0; - wc.pkey_index = 0; - wc.slid = 0; - wc.sl = 0; - wc.dlid_path_bits = 0; - wc.port_num = 0; - ipath_cq_enter(to_icq(sqp->ibqp.send_cq), &wc, 0); - } - - /* Update s_last now that we are finished with the SWQE */ - spin_lock_irqsave(&sqp->s_lock, flags); - if (++sqp->s_last >= sqp->s_size) - sqp->s_last = 0; - spin_unlock_irqrestore(&sqp->s_lock, flags); + ipath_send_complete(sqp, wqe, IB_WC_SUCCESS); goto again; done: @@ -491,13 +477,11 @@ done: wake_up(&qp->wait); } -static int want_buffer(struct ipath_devdata *dd) +static void want_buffer(struct ipath_devdata *dd) { set_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl); ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl); - - return 0; } /** @@ -507,14 +491,11 @@ static int want_buffer(struct ipath_devdata *dd) * * Called when we run out of PIO buffers. */ -static void ipath_no_bufs_available(struct ipath_qp *qp, struct ipath_ibdev *dev) +static void ipath_no_bufs_available(struct ipath_qp *qp, + struct ipath_ibdev *dev) { unsigned long flags; - spin_lock_irqsave(&dev->pending_lock, flags); - if (list_empty(&qp->piowait)) - list_add_tail(&qp->piowait, &dev->piowait); - spin_unlock_irqrestore(&dev->pending_lock, flags); /* * Note that as soon as want_buffer() is called and * possibly before it returns, ipath_ib_piobufavail() @@ -524,100 +505,13 @@ static void ipath_no_bufs_available(struct ipath_qp *qp, struct ipath_ibdev *dev * We leave the busy flag set so that another post send doesn't * try to put the same QP on the piowait list again. */ + spin_lock_irqsave(&dev->pending_lock, flags); + list_add_tail(&qp->piowait, &dev->piowait); + spin_unlock_irqrestore(&dev->pending_lock, flags); want_buffer(dev->dd); dev->n_piowait++; } -/** - * ipath_post_ruc_send - post RC and UC sends - * @qp: the QP to post on - * @wr: the work request to send - */ -int ipath_post_ruc_send(struct ipath_qp *qp, struct ib_send_wr *wr) -{ - struct ipath_swqe *wqe; - unsigned long flags; - u32 next; - int i, j; - int acc; - int ret; - - /* - * Don't allow RDMA reads or atomic operations on UC or - * undefined operations. - * Make sure buffer is large enough to hold the result for atomics. - */ - if (qp->ibqp.qp_type == IB_QPT_UC) { - if ((unsigned) wr->opcode >= IB_WR_RDMA_READ) { - ret = -EINVAL; - goto bail; - } - } else if ((unsigned) wr->opcode > IB_WR_ATOMIC_FETCH_AND_ADD) { - ret = -EINVAL; - goto bail; - } else if (wr->opcode >= IB_WR_ATOMIC_CMP_AND_SWP && - (wr->num_sge == 0 || - wr->sg_list[0].length < sizeof(u64) || - wr->sg_list[0].addr & (sizeof(u64) - 1))) { - ret = -EINVAL; - goto bail; - } else if (wr->opcode >= IB_WR_RDMA_READ && !qp->s_max_rd_atomic) { - ret = -EINVAL; - goto bail; - } - /* IB spec says that num_sge == 0 is OK. */ - if (wr->num_sge > qp->s_max_sge) { - ret = -ENOMEM; - goto bail; - } - spin_lock_irqsave(&qp->s_lock, flags); - next = qp->s_head + 1; - if (next >= qp->s_size) - next = 0; - if (next == qp->s_last) { - spin_unlock_irqrestore(&qp->s_lock, flags); - ret = -EINVAL; - goto bail; - } - - wqe = get_swqe_ptr(qp, qp->s_head); - wqe->wr = *wr; - wqe->ssn = qp->s_ssn++; - wqe->sg_list[0].mr = NULL; - wqe->sg_list[0].vaddr = NULL; - wqe->sg_list[0].length = 0; - wqe->sg_list[0].sge_length = 0; - wqe->length = 0; - acc = wr->opcode >= IB_WR_RDMA_READ ? IB_ACCESS_LOCAL_WRITE : 0; - for (i = 0, j = 0; i < wr->num_sge; i++) { - if (to_ipd(qp->ibqp.pd)->user && wr->sg_list[i].lkey == 0) { - spin_unlock_irqrestore(&qp->s_lock, flags); - ret = -EINVAL; - goto bail; - } - if (wr->sg_list[i].length == 0) - continue; - if (!ipath_lkey_ok(qp, &wqe->sg_list[j], &wr->sg_list[i], - acc)) { - spin_unlock_irqrestore(&qp->s_lock, flags); - ret = -EINVAL; - goto bail; - } - wqe->length += wr->sg_list[i].length; - j++; - } - wqe->wr.num_sge = j; - qp->s_head = next; - spin_unlock_irqrestore(&qp->s_lock, flags); - - ipath_do_ruc_send((unsigned long) qp); - - ret = 0; - -bail: - return ret; -} - /** * ipath_make_grh - construct a GRH header * @dev: a pointer to the ipath device @@ -648,39 +542,66 @@ u32 ipath_make_grh(struct ipath_ibdev *dev, struct ib_grh *hdr, return sizeof(struct ib_grh) / sizeof(u32); } +void ipath_make_ruc_header(struct ipath_ibdev *dev, struct ipath_qp *qp, + struct ipath_other_headers *ohdr, + u32 bth0, u32 bth2) +{ + u16 lrh0; + u32 nwords; + u32 extra_bytes; + + /* Construct the header. */ + extra_bytes = -qp->s_cur_size & 3; + nwords = (qp->s_cur_size + extra_bytes) >> 2; + lrh0 = IPATH_LRH_BTH; + if (unlikely(qp->remote_ah_attr.ah_flags & IB_AH_GRH)) { + qp->s_hdrwords += ipath_make_grh(dev, &qp->s_hdr.u.l.grh, + &qp->remote_ah_attr.grh, + qp->s_hdrwords, nwords); + lrh0 = IPATH_LRH_GRH; + } + lrh0 |= qp->remote_ah_attr.sl << 4; + qp->s_hdr.lrh[0] = cpu_to_be16(lrh0); + qp->s_hdr.lrh[1] = cpu_to_be16(qp->remote_ah_attr.dlid); + qp->s_hdr.lrh[2] = cpu_to_be16(qp->s_hdrwords + nwords + SIZE_OF_CRC); + qp->s_hdr.lrh[3] = cpu_to_be16(dev->dd->ipath_lid); + bth0 |= ipath_get_pkey(dev->dd, qp->s_pkey_index); + bth0 |= extra_bytes << 20; + ohdr->bth[0] = cpu_to_be32(bth0 | (1 << 22)); + ohdr->bth[1] = cpu_to_be32(qp->remote_qpn); + ohdr->bth[2] = cpu_to_be32(bth2); +} + /** - * ipath_do_ruc_send - perform a send on an RC or UC QP + * ipath_do_send - perform a send on a QP * @data: contains a pointer to the QP * * Process entries in the send work queue until credit or queue is * exhausted. Only allow one CPU to send a packet per QP (tasklet). - * Otherwise, after we drop the QP s_lock, two threads could send - * packets out of order. + * Otherwise, two threads could send packets out of order. */ -void ipath_do_ruc_send(unsigned long data) +void ipath_do_send(unsigned long data) { struct ipath_qp *qp = (struct ipath_qp *)data; struct ipath_ibdev *dev = to_idev(qp->ibqp.device); - unsigned long flags; - u16 lrh0; - u32 nwords; - u32 extra_bytes; - u32 bth0; - u32 bth2; - u32 pmtu = ib_mtu_enum_to_int(qp->path_mtu); - struct ipath_other_headers *ohdr; + int (*make_req)(struct ipath_qp *qp); if (test_and_set_bit(IPATH_S_BUSY, &qp->s_busy)) goto bail; - if (unlikely(qp->remote_ah_attr.dlid == dev->dd->ipath_lid)) { + if ((qp->ibqp.qp_type == IB_QPT_RC || + qp->ibqp.qp_type == IB_QPT_UC) && + qp->remote_ah_attr.dlid == dev->dd->ipath_lid) { ipath_ruc_loopback(qp); goto clear; } - ohdr = &qp->s_hdr.u.oth; - if (qp->remote_ah_attr.ah_flags & IB_AH_GRH) - ohdr = &qp->s_hdr.u.l.oth; + if (qp->ibqp.qp_type == IB_QPT_RC) + make_req = ipath_make_rc_req; + else if (qp->ibqp.qp_type == IB_QPT_UC) + make_req = ipath_make_uc_req; + else + make_req = ipath_make_ud_req; again: /* Check for a constructed packet to be sent. */ @@ -689,9 +610,8 @@ again: * If no PIO bufs are available, return. An interrupt will * call ipath_ib_piobufavail() when one is available. */ - if (ipath_verbs_send(dev->dd, qp->s_hdrwords, - (u32 *) &qp->s_hdr, qp->s_cur_size, - qp->s_cur_sge)) { + if (ipath_verbs_send(qp, &qp->s_hdr, qp->s_hdrwords, + qp->s_cur_sge, qp->s_cur_size)) { ipath_no_bufs_available(qp, dev); goto bail; } @@ -700,54 +620,42 @@ again: qp->s_hdrwords = 0; } - /* - * The lock is needed to synchronize between setting - * qp->s_ack_state, resend timer, and post_send(). - */ - spin_lock_irqsave(&qp->s_lock, flags); - - if (!((qp->ibqp.qp_type == IB_QPT_RC) ? - ipath_make_rc_req(qp, ohdr, pmtu, &bth0, &bth2) : - ipath_make_uc_req(qp, ohdr, pmtu, &bth0, &bth2))) { - /* - * Clear the busy bit before unlocking to avoid races with - * adding new work queue items and then failing to process - * them. - */ - clear_bit(IPATH_S_BUSY, &qp->s_busy); - spin_unlock_irqrestore(&qp->s_lock, flags); - goto bail; - } + if (make_req(qp)) + goto again; +clear: + clear_bit(IPATH_S_BUSY, &qp->s_busy); +bail:; +} - spin_unlock_irqrestore(&qp->s_lock, flags); +void ipath_send_complete(struct ipath_qp *qp, struct ipath_swqe *wqe, + enum ib_wc_status status) +{ + u32 last = qp->s_last; - /* Construct the header. */ - extra_bytes = (4 - qp->s_cur_size) & 3; - nwords = (qp->s_cur_size + extra_bytes) >> 2; - lrh0 = IPATH_LRH_BTH; - if (unlikely(qp->remote_ah_attr.ah_flags & IB_AH_GRH)) { - qp->s_hdrwords += ipath_make_grh(dev, &qp->s_hdr.u.l.grh, - &qp->remote_ah_attr.grh, - qp->s_hdrwords, nwords); - lrh0 = IPATH_LRH_GRH; - } - lrh0 |= qp->remote_ah_attr.sl << 4; - qp->s_hdr.lrh[0] = cpu_to_be16(lrh0); - qp->s_hdr.lrh[1] = cpu_to_be16(qp->remote_ah_attr.dlid); - qp->s_hdr.lrh[2] = cpu_to_be16(qp->s_hdrwords + nwords + - SIZE_OF_CRC); - qp->s_hdr.lrh[3] = cpu_to_be16(dev->dd->ipath_lid); - bth0 |= ipath_get_pkey(dev->dd, qp->s_pkey_index); - bth0 |= extra_bytes << 20; - ohdr->bth[0] = cpu_to_be32(bth0); - ohdr->bth[1] = cpu_to_be32(qp->remote_qpn); - ohdr->bth[2] = cpu_to_be32(bth2); + if (++last == qp->s_size) + last = 0; + qp->s_last = last; - /* Check for more work to do. */ - goto again; + /* See ch. 11.2.4.1 and 10.7.3.1 */ + if (!(qp->s_flags & IPATH_S_SIGNAL_REQ_WR) || + (wqe->wr.send_flags & IB_SEND_SIGNALED) || + status != IB_WC_SUCCESS) { + struct ib_wc wc; -clear: - clear_bit(IPATH_S_BUSY, &qp->s_busy); -bail: - return; + wc.wr_id = wqe->wr.wr_id; + wc.status = status; + wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode]; + wc.vendor_err = 0; + wc.byte_len = wqe->length; + wc.imm_data = 0; + wc.qp = &qp->ibqp; + wc.src_qp = 0; + wc.wc_flags = 0; + wc.pkey_index = 0; + wc.slid = 0; + wc.sl = 0; + wc.dlid_path_bits = 0; + wc.port_num = 0; + ipath_cq_enter(to_icq(qp->ibqp.send_cq), &wc, 0); + } } diff --git a/drivers/infiniband/hw/ipath/ipath_uc.c b/drivers/infiniband/hw/ipath/ipath_uc.c index 8380fbc50d2..767beb903c2 100644 --- a/drivers/infiniband/hw/ipath/ipath_uc.c +++ b/drivers/infiniband/hw/ipath/ipath_uc.c @@ -37,72 +37,40 @@ /* cut down ridiculously long IB macro names */ #define OP(x) IB_OPCODE_UC_##x -static void complete_last_send(struct ipath_qp *qp, struct ipath_swqe *wqe, - struct ib_wc *wc) -{ - if (++qp->s_last == qp->s_size) - qp->s_last = 0; - if (!(qp->s_flags & IPATH_S_SIGNAL_REQ_WR) || - (wqe->wr.send_flags & IB_SEND_SIGNALED)) { - wc->wr_id = wqe->wr.wr_id; - wc->status = IB_WC_SUCCESS; - wc->opcode = ib_ipath_wc_opcode[wqe->wr.opcode]; - wc->vendor_err = 0; - wc->byte_len = wqe->length; - wc->qp = &qp->ibqp; - wc->src_qp = qp->remote_qpn; - wc->pkey_index = 0; - wc->slid = qp->remote_ah_attr.dlid; - wc->sl = qp->remote_ah_attr.sl; - wc->dlid_path_bits = 0; - wc->port_num = 0; - ipath_cq_enter(to_icq(qp->ibqp.send_cq), wc, 0); - } -} - /** * ipath_make_uc_req - construct a request packet (SEND, RDMA write) * @qp: a pointer to the QP - * @ohdr: a pointer to the IB header being constructed - * @pmtu: the path MTU - * @bth0p: pointer to the BTH opcode word - * @bth2p: pointer to the BTH PSN word * * Return 1 if constructed; otherwise, return 0. - * Note the QP s_lock must be held and interrupts disabled. */ -int ipath_make_uc_req(struct ipath_qp *qp, - struct ipath_other_headers *ohdr, - u32 pmtu, u32 *bth0p, u32 *bth2p) +int ipath_make_uc_req(struct ipath_qp *qp) { + struct ipath_other_headers *ohdr; struct ipath_swqe *wqe; u32 hwords; u32 bth0; u32 len; - struct ib_wc wc; + u32 pmtu = ib_mtu_enum_to_int(qp->path_mtu); + int ret = 0; if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK)) goto done; + ohdr = &qp->s_hdr.u.oth; + if (qp->remote_ah_attr.ah_flags & IB_AH_GRH) + ohdr = &qp->s_hdr.u.l.oth; + /* header size in 32-bit words LRH+BTH = (8+12)/4. */ hwords = 5; bth0 = 1 << 22; /* Set M bit */ /* Get the next send request. */ - wqe = get_swqe_ptr(qp, qp->s_last); + wqe = get_swqe_ptr(qp, qp->s_cur); + qp->s_wqe = NULL; switch (qp->s_state) { default: - /* - * Signal the completion of the last send - * (if there is one). - */ - if (qp->s_last != qp->s_tail) { - complete_last_send(qp, wqe, &wc); - wqe = get_swqe_ptr(qp, qp->s_last); - } - /* Check if send work queue is empty. */ - if (qp->s_tail == qp->s_head) + if (qp->s_cur == qp->s_head) goto done; /* * Start a new request. @@ -131,6 +99,9 @@ int ipath_make_uc_req(struct ipath_qp *qp, } if (wqe->wr.send_flags & IB_SEND_SOLICITED) bth0 |= 1 << 23; + qp->s_wqe = wqe; + if (++qp->s_cur >= qp->s_size) + qp->s_cur = 0; break; case IB_WR_RDMA_WRITE: @@ -157,13 +128,14 @@ int ipath_make_uc_req(struct ipath_qp *qp, if (wqe->wr.send_flags & IB_SEND_SOLICITED) bth0 |= 1 << 23; } + qp->s_wqe = wqe; + if (++qp->s_cur >= qp->s_size) + qp->s_cur = 0; break; default: goto done; } - if (++qp->s_tail >= qp->s_size) - qp->s_tail = 0; break; case OP(SEND_FIRST): @@ -185,6 +157,9 @@ int ipath_make_uc_req(struct ipath_qp *qp, } if (wqe->wr.send_flags & IB_SEND_SOLICITED) bth0 |= 1 << 23; + qp->s_wqe = wqe; + if (++qp->s_cur >= qp->s_size) + qp->s_cur = 0; break; case OP(RDMA_WRITE_FIRST): @@ -207,18 +182,22 @@ int ipath_make_uc_req(struct ipath_qp *qp, if (wqe->wr.send_flags & IB_SEND_SOLICITED) bth0 |= 1 << 23; } + qp->s_wqe = wqe; + if (++qp->s_cur >= qp->s_size) + qp->s_cur = 0; break; } qp->s_len -= len; qp->s_hdrwords = hwords; qp->s_cur_sge = &qp->s_sge; qp->s_cur_size = len; - *bth0p = bth0 | (qp->s_state << 24); - *bth2p = qp->s_next_psn++ & IPATH_PSN_MASK; - return 1; + ipath_make_ruc_header(to_idev(qp->ibqp.device), + qp, ohdr, bth0 | (qp->s_state << 24), + qp->s_next_psn++ & IPATH_PSN_MASK); + ret = 1; done: - return 0; + return ret; } /** diff --git a/drivers/infiniband/hw/ipath/ipath_ud.c b/drivers/infiniband/hw/ipath/ipath_ud.c index f9a3338a5fb..34c4a0a5be3 100644 --- a/drivers/infiniband/hw/ipath/ipath_ud.c +++ b/drivers/infiniband/hw/ipath/ipath_ud.c @@ -36,68 +36,17 @@ #include "ipath_verbs.h" #include "ipath_kernel.h" -static int init_sge(struct ipath_qp *qp, struct ipath_rwqe *wqe, - u32 *lengthp, struct ipath_sge_state *ss) -{ - int user = to_ipd(qp->ibqp.pd)->user; - int i, j, ret; - struct ib_wc wc; - - *lengthp = 0; - for (i = j = 0; i < wqe->num_sge; i++) { - if (wqe->sg_list[i].length == 0) - continue; - /* Check LKEY */ - if ((user && wqe->sg_list[i].lkey == 0) || - !ipath_lkey_ok(qp, j ? &ss->sg_list[j - 1] : &ss->sge, - &wqe->sg_list[i], IB_ACCESS_LOCAL_WRITE)) - goto bad_lkey; - *lengthp += wqe->sg_list[i].length; - j++; - } - ss->num_sge = j; - ret = 1; - goto bail; - -bad_lkey: - wc.wr_id = wqe->wr_id; - wc.status = IB_WC_LOC_PROT_ERR; - wc.opcode = IB_WC_RECV; - wc.vendor_err = 0; - wc.byte_len = 0; - wc.imm_data = 0; - wc.qp = &qp->ibqp; - wc.src_qp = 0; - wc.wc_flags = 0; - wc.pkey_index = 0; - wc.slid = 0; - wc.sl = 0; - wc.dlid_path_bits = 0; - wc.port_num = 0; - /* Signal solicited completion event. */ - ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, 1); - ret = 0; -bail: - return ret; -} - /** * ipath_ud_loopback - handle send on loopback QPs - * @sqp: the QP - * @ss: the SGE state - * @length: the length of the data to send - * @wr: the work request - * @wc: the work completion entry + * @sqp: the sending QP + * @swqe: the send work request * - * This is called from ipath_post_ud_send() to forward a WQE addressed + * This is called from ipath_make_ud_req() to forward a WQE addressed * to the same HCA. * Note that the receive interrupt handler may be calling ipath_ud_rcv() * while this is being called. */ -static void ipath_ud_loopback(struct ipath_qp *sqp, - struct ipath_sge_state *ss, - u32 length, struct ib_send_wr *wr, - struct ib_wc *wc) +static void ipath_ud_loopback(struct ipath_qp *sqp, struct ipath_swqe *swqe) { struct ipath_ibdev *dev = to_idev(sqp->ibqp.device); struct ipath_qp *qp; @@ -110,12 +59,18 @@ static void ipath_ud_loopback(struct ipath_qp *sqp, struct ipath_rwq *wq; struct ipath_rwqe *wqe; void (*handler)(struct ib_event *, void *); + struct ib_wc wc; u32 tail; u32 rlen; + u32 length; - qp = ipath_lookup_qpn(&dev->qp_table, wr->wr.ud.remote_qpn); - if (!qp) - return; + qp = ipath_lookup_qpn(&dev->qp_table, swqe->wr.wr.ud.remote_qpn); + if (!qp) { + dev->n_pkt_drops++; + goto send_comp; + } + + rsge.sg_list = NULL; /* * Check that the qkey matches (except for QP0, see 9.6.1.4.1). @@ -123,39 +78,34 @@ static void ipath_ud_loopback(struct ipath_qp *sqp, * qkey from the QP context instead of the WR (see 10.2.5). */ if (unlikely(qp->ibqp.qp_num && - ((int) wr->wr.ud.remote_qkey < 0 - ? qp->qkey : wr->wr.ud.remote_qkey) != qp->qkey)) { + ((int) swqe->wr.wr.ud.remote_qkey < 0 ? + sqp->qkey : swqe->wr.wr.ud.remote_qkey) != qp->qkey)) { /* XXX OK to lose a count once in a while. */ dev->qkey_violations++; dev->n_pkt_drops++; - goto done; + goto drop; } /* * A GRH is expected to preceed the data even if not * present on the wire. */ - wc->byte_len = length + sizeof(struct ib_grh); + length = swqe->length; + wc.byte_len = length + sizeof(struct ib_grh); - if (wr->opcode == IB_WR_SEND_WITH_IMM) { - wc->wc_flags = IB_WC_WITH_IMM; - wc->imm_data = wr->imm_data; + if (swqe->wr.opcode == IB_WR_SEND_WITH_IMM) { + wc.wc_flags = IB_WC_WITH_IMM; + wc.imm_data = swqe->wr.imm_data; } else { - wc->wc_flags = 0; - wc->imm_data = 0; + wc.wc_flags = 0; + wc.imm_data = 0; } - if (wr->num_sge > 1) { - rsge.sg_list = kmalloc((wr->num_sge - 1) * - sizeof(struct ipath_sge), - GFP_ATOMIC); - } else - rsge.sg_list = NULL; - /* - * Get the next work request entry to find where to put the data. - * Note that it is safe to drop the lock after changing rq->tail - * since ipath_post_receive() won't fill the empty slot. + * This would be a lot simpler if we could call ipath_get_rwqe() + * but that uses state that the receive interrupt handler uses + * so we would need to lock out receive interrupts while doing + * local loopback. */ if (qp->ibqp.srq) { srq = to_isrq(qp->ibqp.srq); @@ -167,32 +117,53 @@ static void ipath_ud_loopback(struct ipath_qp *sqp, rq = &qp->r_rq; } + if (rq->max_sge > 1) { + /* + * XXX We could use GFP_KERNEL if ipath_do_send() + * was always called from the tasklet instead of + * from ipath_post_send(). + */ + rsge.sg_list = kmalloc((rq->max_sge - 1) * + sizeof(struct ipath_sge), + GFP_ATOMIC); + if (!rsge.sg_list) { + dev->n_pkt_drops++; + goto drop; + } + } + + /* + * Get the next work request entry to find where to put the data. + * Note that it is safe to drop the lock after changing rq->tail + * since ipath_post_receive() won't fill the empty slot. + */ spin_lock_irqsave(&rq->lock, flags); wq = rq->wq; tail = wq->tail; - while (1) { - if (unlikely(tail == wq->head)) { - spin_unlock_irqrestore(&rq->lock, flags); - dev->n_pkt_drops++; - goto bail_sge; - } - /* Make sure entry is read after head index is read. */ - smp_rmb(); - wqe = get_rwqe_ptr(rq, tail); - if (++tail >= rq->size) - tail = 0; - if (init_sge(qp, wqe, &rlen, &rsge)) - break; - wq->tail = tail; + /* Validate tail before using it since it is user writable. */ + if (tail >= rq->size) + tail = 0; + if (unlikely(tail == wq->head)) { + spin_unlock_irqrestore(&rq->lock, flags); + dev->n_pkt_drops++; + goto drop; + } + wqe = get_rwqe_ptr(rq, tail); + if (!ipath_init_sge(qp, wqe, &rlen, &rsge)) { + spin_unlock_irqrestore(&rq->lock, flags); + dev->n_pkt_drops++; + goto drop; } /* Silently drop packets which are too big. */ - if (wc->byte_len > rlen) { + if (wc.byte_len > rlen) { spin_unlock_irqrestore(&rq->lock, flags); dev->n_pkt_drops++; - goto bail_sge; + goto drop; } + if (++tail >= rq->size) + tail = 0; wq->tail = tail; - wc->wr_id = wqe->wr_id; + wc.wr_id = wqe->wr_id; if (handler) { u32 n; @@ -221,13 +192,13 @@ static void ipath_ud_loopback(struct ipath_qp *sqp, } else spin_unlock_irqrestore(&rq->lock, flags); - ah_attr = &to_iah(wr->wr.ud.ah)->attr; + ah_attr = &to_iah(swqe->wr.wr.ud.ah)->attr; if (ah_attr->ah_flags & IB_AH_GRH) { ipath_copy_sge(&rsge, &ah_attr->grh, sizeof(struct ib_grh)); - wc->wc_flags |= IB_WC_GRH; + wc.wc_flags |= IB_WC_GRH; } else ipath_skip_sge(&rsge, sizeof(struct ib_grh)); - sge = &ss->sge; + sge = swqe->sg_list; while (length) { u32 len = sge->length; @@ -241,8 +212,8 @@ static void ipath_ud_loopback(struct ipath_qp *sqp, sge->length -= len; sge->sge_length -= len; if (sge->sge_length == 0) { - if (--ss->num_sge) - *sge = *ss->sg_list++; + if (--swqe->wr.num_sge) + sge++; } else if (sge->length == 0 && sge->mr != NULL) { if (++sge->n >= IPATH_SEGSZ) { if (++sge->m >= sge->mr->mapsz) @@ -256,123 +227,60 @@ static void ipath_ud_loopback(struct ipath_qp *sqp, } length -= len; } - wc->status = IB_WC_SUCCESS; - wc->opcode = IB_WC_RECV; - wc->vendor_err = 0; - wc->qp = &qp->ibqp; - wc->src_qp = sqp->ibqp.qp_num; + wc.status = IB_WC_SUCCESS; + wc.opcode = IB_WC_RECV; + wc.vendor_err = 0; + wc.qp = &qp->ibqp; + wc.src_qp = sqp->ibqp.qp_num; /* XXX do we know which pkey matched? Only needed for GSI. */ - wc->pkey_index = 0; - wc->slid = dev->dd->ipath_lid | + wc.pkey_index = 0; + wc.slid = dev->dd->ipath_lid | (ah_attr->src_path_bits & ((1 << (dev->mkeyprot_resv_lmc & 7)) - 1)); - wc->sl = ah_attr->sl; - wc->dlid_path_bits = + wc.sl = ah_attr->sl; + wc.dlid_path_bits = ah_attr->dlid & ((1 << (dev->mkeyprot_resv_lmc & 7)) - 1); + wc.port_num = 1; /* Signal completion event if the solicited bit is set. */ - ipath_cq_enter(to_icq(qp->ibqp.recv_cq), wc, - wr->send_flags & IB_SEND_SOLICITED); - -bail_sge: + ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, + swqe->wr.send_flags & IB_SEND_SOLICITED); +drop: kfree(rsge.sg_list); -done: if (atomic_dec_and_test(&qp->refcount)) wake_up(&qp->wait); +send_comp: + ipath_send_complete(sqp, swqe, IB_WC_SUCCESS); } /** - * ipath_post_ud_send - post a UD send on QP + * ipath_make_ud_req - construct a UD request packet * @qp: the QP - * @wr: the work request * - * Note that we actually send the data as it is posted instead of putting - * the request into a ring buffer. If we wanted to use a ring buffer, - * we would need to save a reference to the destination address in the SWQE. + * Return 1 if constructed; otherwise, return 0. */ -int ipath_post_ud_send(struct ipath_qp *qp, struct ib_send_wr *wr) +int ipath_make_ud_req(struct ipath_qp *qp) { struct ipath_ibdev *dev = to_idev(qp->ibqp.device); struct ipath_other_headers *ohdr; struct ib_ah_attr *ah_attr; - struct ipath_sge_state ss; - struct ipath_sge *sg_list; - struct ib_wc wc; - u32 hwords; + struct ipath_swqe *wqe; u32 nwords; - u32 len; u32 extra_bytes; u32 bth0; u16 lrh0; u16 lid; - int i; - int ret; + int ret = 0; - if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK)) { - ret = 0; + if (unlikely(!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK))) goto bail; - } - if (wr->wr.ud.ah->pd != qp->ibqp.pd) { - ret = -EPERM; + if (qp->s_cur == qp->s_head) goto bail; - } - /* IB spec says that num_sge == 0 is OK. */ - if (wr->num_sge > qp->s_max_sge) { - ret = -EINVAL; - goto bail; - } - - if (wr->num_sge > 1) { - sg_list = kmalloc((qp->s_max_sge - 1) * sizeof(*sg_list), - GFP_ATOMIC); - if (!sg_list) { - ret = -ENOMEM; - goto bail; - } - } else - sg_list = NULL; - - /* Check the buffer to send. */ - ss.sg_list = sg_list; - ss.sge.mr = NULL; - ss.sge.vaddr = NULL; - ss.sge.length = 0; - ss.sge.sge_length = 0; - ss.num_sge = 0; - len = 0; - for (i = 0; i < wr->num_sge; i++) { - /* Check LKEY */ - if (to_ipd(qp->ibqp.pd)->user && wr->sg_list[i].lkey == 0) { - ret = -EINVAL; - goto bail; - } - - if (wr->sg_list[i].length == 0) - continue; - if (!ipath_lkey_ok(qp, ss.num_sge ? - sg_list + ss.num_sge - 1 : &ss.sge, - &wr->sg_list[i], 0)) { - ret = -EINVAL; - goto bail; - } - len += wr->sg_list[i].length; - ss.num_sge++; - } - /* Check for invalid packet size. */ - if (len > dev->dd->ipath_ibmtu) { - ret = -EINVAL; - goto bail; - } - extra_bytes = (4 - len) & 3; - nwords = (len + extra_bytes) >> 2; + wqe = get_swqe_ptr(qp, qp->s_cur); /* Construct the header. */ - ah_attr = &to_iah(wr->wr.ud.ah)->attr; - if (ah_attr->dlid == 0) { - ret = -EINVAL; - goto bail; - } + ah_attr = &to_iah(wqe->wr.wr.ud.ah)->attr; if (ah_attr->dlid >= IPATH_MULTICAST_LID_BASE) { if (ah_attr->dlid != IPATH_PERMISSIVE_LID) dev->n_multicast_xmit++; @@ -383,64 +291,53 @@ int ipath_post_ud_send(struct ipath_qp *qp, struct ib_send_wr *wr) lid = ah_attr->dlid & ~((1 << (dev->mkeyprot_resv_lmc & 7)) - 1); if (unlikely(lid == dev->dd->ipath_lid)) { - /* - * Pass in an uninitialized ib_wc to save stack - * space. - */ - ipath_ud_loopback(qp, &ss, len, wr, &wc); + ipath_ud_loopback(qp, wqe); goto done; } } + + extra_bytes = -wqe->length & 3; + nwords = (wqe->length + extra_bytes) >> 2; + + /* header size in 32-bit words LRH+BTH+DETH = (8+12+8)/4. */ + qp->s_hdrwords = 7; + if (wqe->wr.opcode == IB_WR_SEND_WITH_IMM) + qp->s_hdrwords++; + qp->s_cur_size = wqe->length; + qp->s_cur_sge = &qp->s_sge; + qp->s_wqe = wqe; + qp->s_sge.sge = wqe->sg_list[0]; + qp->s_sge.sg_list = wqe->sg_list + 1; + qp->s_sge.num_sge = wqe->wr.num_sge; + if (ah_attr->ah_flags & IB_AH_GRH) { /* Header size in 32-bit words. */ - hwords = 17; + qp->s_hdrwords += ipath_make_grh(dev, &qp->s_hdr.u.l.grh, + &ah_attr->grh, + qp->s_hdrwords, nwords); lrh0 = IPATH_LRH_GRH; ohdr = &qp->s_hdr.u.l.oth; - qp->s_hdr.u.l.grh.version_tclass_flow = - cpu_to_be32((6 << 28) | - (ah_attr->grh.traffic_class << 20) | - ah_attr->grh.flow_label); - qp->s_hdr.u.l.grh.paylen = - cpu_to_be16(((wr->opcode == - IB_WR_SEND_WITH_IMM ? 6 : 5) + - nwords + SIZE_OF_CRC) << 2); - /* next_hdr is defined by C8-7 in ch. 8.4.1 */ - qp->s_hdr.u.l.grh.next_hdr = 0x1B; - qp->s_hdr.u.l.grh.hop_limit = ah_attr->grh.hop_limit; - /* The SGID is 32-bit aligned. */ - qp->s_hdr.u.l.grh.sgid.global.subnet_prefix = - dev->gid_prefix; - qp->s_hdr.u.l.grh.sgid.global.interface_id = - dev->dd->ipath_guid; - qp->s_hdr.u.l.grh.dgid = ah_attr->grh.dgid; /* * Don't worry about sending to locally attached multicast * QPs. It is unspecified by the spec. what happens. */ } else { /* Header size in 32-bit words. */ - hwords = 7; lrh0 = IPATH_LRH_BTH; ohdr = &qp->s_hdr.u.oth; } - if (wr->opcode == IB_WR_SEND_WITH_IMM) { - ohdr->u.ud.imm_data = wr->imm_data; - wc.imm_data = wr->imm_data; - hwords += 1; + if (wqe->wr.opcode == IB_WR_SEND_WITH_IMM) { + ohdr->u.ud.imm_data = wqe->wr.imm_data; bth0 = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE << 24; - } else if (wr->opcode == IB_WR_SEND) { - wc.imm_data = 0; + } else bth0 = IB_OPCODE_UD_SEND_ONLY << 24; - } else { - ret = -EINVAL; - goto bail; - } lrh0 |= ah_attr->sl << 4; if (qp->ibqp.qp_type == IB_QPT_SMI) lrh0 |= 0xF000; /* Set VL (see ch. 13.5.3.1) */ qp->s_hdr.lrh[0] = cpu_to_be16(lrh0); qp->s_hdr.lrh[1] = cpu_to_be16(ah_attr->dlid); /* DEST LID */ - qp->s_hdr.lrh[2] = cpu_to_be16(hwords + nwords + SIZE_OF_CRC); + qp->s_hdr.lrh[2] = cpu_to_be16(qp->s_hdrwords + nwords + + SIZE_OF_CRC); lid = dev->dd->ipath_lid; if (lid) { lid |= ah_attr->src_path_bits & @@ -448,7 +345,7 @@ int ipath_post_ud_send(struct ipath_qp *qp, struct ib_send_wr *wr) qp->s_hdr.lrh[3] = cpu_to_be16(lid); } else qp->s_hdr.lrh[3] = IB_LID_PERMISSIVE; - if (wr->send_flags & IB_SEND_SOLICITED) + if (wqe->wr.send_flags & IB_SEND_SOLICITED) bth0 |= 1 << 23; bth0 |= extra_bytes << 20; bth0 |= qp->ibqp.qp_type == IB_QPT_SMI ? IPATH_DEFAULT_P_KEY : @@ -460,38 +357,20 @@ int ipath_post_ud_send(struct ipath_qp *qp, struct ib_send_wr *wr) ohdr->bth[1] = ah_attr->dlid >= IPATH_MULTICAST_LID_BASE && ah_attr->dlid != IPATH_PERMISSIVE_LID ? __constant_cpu_to_be32(IPATH_MULTICAST_QPN) : - cpu_to_be32(wr->wr.ud.remote_qpn); - /* XXX Could lose a PSN count but not worth locking */ + cpu_to_be32(wqe->wr.wr.ud.remote_qpn); ohdr->bth[2] = cpu_to_be32(qp->s_next_psn++ & IPATH_PSN_MASK); /* * Qkeys with the high order bit set mean use the * qkey from the QP context instead of the WR (see 10.2.5). */ - ohdr->u.ud.deth[0] = cpu_to_be32((int)wr->wr.ud.remote_qkey < 0 ? - qp->qkey : wr->wr.ud.remote_qkey); + ohdr->u.ud.deth[0] = cpu_to_be32((int)wqe->wr.wr.ud.remote_qkey < 0 ? + qp->qkey : wqe->wr.wr.ud.remote_qkey); ohdr->u.ud.deth[1] = cpu_to_be32(qp->ibqp.qp_num); - if (ipath_verbs_send(dev->dd, hwords, (u32 *) &qp->s_hdr, - len, &ss)) - dev->n_no_piobuf++; done: - /* Queue the completion status entry. */ - if (!(qp->s_flags & IPATH_S_SIGNAL_REQ_WR) || - (wr->send_flags & IB_SEND_SIGNALED)) { - wc.wr_id = wr->wr_id; - wc.status = IB_WC_SUCCESS; - wc.vendor_err = 0; - wc.opcode = IB_WC_SEND; - wc.byte_len = len; - wc.qp = &qp->ibqp; - wc.src_qp = 0; - wc.wc_flags = 0; - /* XXX initialize other fields? */ - ipath_cq_enter(to_icq(qp->ibqp.send_cq), &wc, 0); - } - kfree(sg_list); - - ret = 0; + if (++qp->s_cur >= qp->s_size) + qp->s_cur = 0; + ret = 1; bail: return ret; @@ -673,6 +552,7 @@ void ipath_ud_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr, */ wc.dlid_path_bits = dlid >= IPATH_MULTICAST_LID_BASE ? 0 : dlid & ((1 << (dev->mkeyprot_resv_lmc & 7)) - 1); + wc.port_num = 1; /* Signal completion event if the solicited bit is set. */ ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, (ohdr->bth[0] & diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c index 559d4a66293..3cc82b62b3c 100644 --- a/drivers/infiniband/hw/ipath/ipath_verbs.c +++ b/drivers/infiniband/hw/ipath/ipath_verbs.c @@ -230,6 +230,103 @@ void ipath_skip_sge(struct ipath_sge_state *ss, u32 length) } } +/** + * ipath_post_one_send - post one RC, UC, or UD send work request + * @qp: the QP to post on + * @wr: the work request to send + */ +static int ipath_post_one_send(struct ipath_qp *qp, struct ib_send_wr *wr) +{ + struct ipath_swqe *wqe; + u32 next; + int i; + int j; + int acc; + int ret; + unsigned long flags; + + spin_lock_irqsave(&qp->s_lock, flags); + + /* Check that state is OK to post send. */ + if (!(ib_ipath_state_ops[qp->state] & IPATH_POST_SEND_OK)) + goto bail_inval; + + /* IB spec says that num_sge == 0 is OK. */ + if (wr->num_sge > qp->s_max_sge) + goto bail_inval; + + /* + * Don't allow RDMA reads or atomic operations on UC or + * undefined operations. + * Make sure buffer is large enough to hold the result for atomics. + */ + if (qp->ibqp.qp_type == IB_QPT_UC) { + if ((unsigned) wr->opcode >= IB_WR_RDMA_READ) + goto bail_inval; + } else if (qp->ibqp.qp_type == IB_QPT_UD) { + /* Check UD opcode */ + if (wr->opcode != IB_WR_SEND && + wr->opcode != IB_WR_SEND_WITH_IMM) + goto bail_inval; + /* Check UD destination address PD */ + if (qp->ibqp.pd != wr->wr.ud.ah->pd) + goto bail_inval; + } else if ((unsigned) wr->opcode > IB_WR_ATOMIC_FETCH_AND_ADD) + goto bail_inval; + else if (wr->opcode >= IB_WR_ATOMIC_CMP_AND_SWP && + (wr->num_sge == 0 || + wr->sg_list[0].length < sizeof(u64) || + wr->sg_list[0].addr & (sizeof(u64) - 1))) + goto bail_inval; + else if (wr->opcode >= IB_WR_RDMA_READ && !qp->s_max_rd_atomic) + goto bail_inval; + + next = qp->s_head + 1; + if (next >= qp->s_size) + next = 0; + if (next == qp->s_last) + goto bail_inval; + + wqe = get_swqe_ptr(qp, qp->s_head); + wqe->wr = *wr; + wqe->ssn = qp->s_ssn++; + wqe->length = 0; + if (wr->num_sge) { + acc = wr->opcode >= IB_WR_RDMA_READ ? + IB_ACCESS_LOCAL_WRITE : 0; + for (i = 0, j = 0; i < wr->num_sge; i++) { + u32 length = wr->sg_list[i].length; + int ok; + + if (length == 0) + continue; + ok = ipath_lkey_ok(qp, &wqe->sg_list[j], + &wr->sg_list[i], acc); + if (!ok) + goto bail_inval; + wqe->length += length; + j++; + } + wqe->wr.num_sge = j; + } + if (qp->ibqp.qp_type == IB_QPT_UC || + qp->ibqp.qp_type == IB_QPT_RC) { + if (wqe->length > 0x80000000U) + goto bail_inval; + } else if (wqe->length > to_idev(qp->ibqp.device)->dd->ipath_ibmtu) + goto bail_inval; + qp->s_head = next; + + ret = 0; + goto bail; + +bail_inval: + ret = -EINVAL; +bail: + spin_unlock_irqrestore(&qp->s_lock, flags); + return ret; +} + /** * ipath_post_send - post a send on a QP * @ibqp: the QP to post the send on @@ -244,35 +341,17 @@ static int ipath_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, struct ipath_qp *qp = to_iqp(ibqp); int err = 0; - /* Check that state is OK to post send. */ - if (!(ib_ipath_state_ops[qp->state] & IPATH_POST_SEND_OK)) { - *bad_wr = wr; - err = -EINVAL; - goto bail; - } - for (; wr; wr = wr->next) { - switch (qp->ibqp.qp_type) { - case IB_QPT_UC: - case IB_QPT_RC: - err = ipath_post_ruc_send(qp, wr); - break; - - case IB_QPT_SMI: - case IB_QPT_GSI: - case IB_QPT_UD: - err = ipath_post_ud_send(qp, wr); - break; - - default: - err = -EINVAL; - } + err = ipath_post_one_send(qp, wr); if (err) { *bad_wr = wr; - break; + goto bail; } } + /* Try to do the send work in the caller's context. */ + ipath_do_send((unsigned long) qp); + bail: return err; } @@ -641,11 +720,11 @@ static void copy_io(u32 __iomem *piobuf, struct ipath_sge_state *ss, u32 len = ss->sge.length; u32 off; - BUG_ON(len == 0); if (len > length) len = length; if (len > ss->sge.sge_length) len = ss->sge.sge_length; + BUG_ON(len == 0); /* If the source address is not aligned, try to align it. */ off = (unsigned long)ss->sge.vaddr & (sizeof(u32) - 1); if (off) { @@ -767,30 +846,15 @@ static void copy_io(u32 __iomem *piobuf, struct ipath_sge_state *ss, __raw_writel(last, piobuf); } -/** - * ipath_verbs_send - send a packet - * @dd: the infinipath device - * @hdrwords: the number of words in the header - * @hdr: the packet header - * @len: the length of the packet in bytes - * @ss: the SGE to send - */ -int ipath_verbs_send(struct ipath_devdata *dd, u32 hdrwords, - u32 *hdr, u32 len, struct ipath_sge_state *ss) +static int ipath_verbs_send_pio(struct ipath_qp *qp, u32 *hdr, u32 hdrwords, + struct ipath_sge_state *ss, u32 len, + u32 plen, u32 dwords) { + struct ipath_devdata *dd = to_idev(qp->ibqp.device)->dd; u32 __iomem *piobuf; unsigned flush_wc; - u32 plen; int ret; - /* +1 is for the qword padding of pbc */ - plen = hdrwords + ((len + 3) >> 2) + 1; - if (unlikely((plen << 2) > dd->ipath_ibmaxlen)) { - ret = -EINVAL; - goto bail; - } - - /* Get a PIO buffer to use. */ piobuf = ipath_getpiobuf(dd, NULL); if (unlikely(piobuf == NULL)) { ret = -EBUSY; @@ -831,13 +895,10 @@ int ipath_verbs_send(struct ipath_devdata *dd, u32 hdrwords, /* The common case is aligned and contained in one segment. */ if (likely(ss->num_sge == 1 && len <= ss->sge.length && !((unsigned long)ss->sge.vaddr & (sizeof(u32) - 1)))) { - u32 dwords; u32 *addr = (u32 *) ss->sge.vaddr; /* Update address before sending packet. */ update_sge(ss, len); - /* Need to round up for the last dword in the packet. */ - dwords = (len + 3) >> 2; if (flush_wc) { __iowrite32_copy(piobuf, addr, dwords - 1); /* must flush early everything before trigger word */ @@ -851,11 +912,37 @@ int ipath_verbs_send(struct ipath_devdata *dd, u32 hdrwords, } copy_io(piobuf, ss, len, flush_wc); done: + if (qp->s_wqe) + ipath_send_complete(qp, qp->s_wqe, IB_WC_SUCCESS); ret = 0; bail: return ret; } +/** + * ipath_verbs_send - send a packet + * @qp: the QP to send on + * @hdr: the packet header + * @hdrwords: the number of words in the header + * @ss: the SGE to send + * @len: the length of the packet in bytes + */ +int ipath_verbs_send(struct ipath_qp *qp, struct ipath_ib_header *hdr, + u32 hdrwords, struct ipath_sge_state *ss, u32 len) +{ + u32 plen; + int ret; + u32 dwords = (len + 3) >> 2; + + /* +1 is for the qword padding of pbc */ + plen = hdrwords + dwords + 1; + + ret = ipath_verbs_send_pio(qp, (u32 *) hdr, hdrwords, + ss, len, plen, dwords); + + return ret; +} + int ipath_snapshot_counters(struct ipath_devdata *dd, u64 *swords, u64 *rwords, u64 *spkts, u64 *rpkts, u64 *xmit_wait) @@ -864,7 +951,6 @@ int ipath_snapshot_counters(struct ipath_devdata *dd, u64 *swords, if (!(dd->ipath_flags & IPATH_INITTED)) { /* no hardware, freeze, etc. */ - ipath_dbg("unit %u not usable\n", dd->ipath_unit); ret = -EINVAL; goto bail; } @@ -890,48 +976,44 @@ bail: int ipath_get_counters(struct ipath_devdata *dd, struct ipath_verbs_counters *cntrs) { + struct ipath_cregs const *crp = dd->ipath_cregs; int ret; if (!(dd->ipath_flags & IPATH_INITTED)) { /* no hardware, freeze, etc. */ - ipath_dbg("unit %u not usable\n", dd->ipath_unit); ret = -EINVAL; goto bail; } cntrs->symbol_error_counter = - ipath_snap_cntr(dd, dd->ipath_cregs->cr_ibsymbolerrcnt); + ipath_snap_cntr(dd, crp->cr_ibsymbolerrcnt); cntrs->link_error_recovery_counter = - ipath_snap_cntr(dd, dd->ipath_cregs->cr_iblinkerrrecovcnt); + ipath_snap_cntr(dd, crp->cr_iblinkerrrecovcnt); /* * The link downed counter counts when the other side downs the * connection. We add in the number of times we downed the link * due to local link integrity errors to compensate. */ cntrs->link_downed_counter = - ipath_snap_cntr(dd, dd->ipath_cregs->cr_iblinkdowncnt); + ipath_snap_cntr(dd, crp->cr_iblinkdowncnt); cntrs->port_rcv_errors = - ipath_snap_cntr(dd, dd->ipath_cregs->cr_rxdroppktcnt) + - ipath_snap_cntr(dd, dd->ipath_cregs->cr_rcvovflcnt) + - ipath_snap_cntr(dd, dd->ipath_cregs->cr_portovflcnt) + - ipath_snap_cntr(dd, dd->ipath_cregs->cr_err_rlencnt) + - ipath_snap_cntr(dd, dd->ipath_cregs->cr_invalidrlencnt) + - ipath_snap_cntr(dd, dd->ipath_cregs->cr_erricrccnt) + - ipath_snap_cntr(dd, dd->ipath_cregs->cr_errvcrccnt) + - ipath_snap_cntr(dd, dd->ipath_cregs->cr_errlpcrccnt) + - ipath_snap_cntr(dd, dd->ipath_cregs->cr_badformatcnt) + + ipath_snap_cntr(dd, crp->cr_rxdroppktcnt) + + ipath_snap_cntr(dd, crp->cr_rcvovflcnt) + + ipath_snap_cntr(dd, crp->cr_portovflcnt) + + ipath_snap_cntr(dd, crp->cr_err_rlencnt) + + ipath_snap_cntr(dd, crp->cr_invalidrlencnt) + + ipath_snap_cntr(dd, crp->cr_errlinkcnt) + + ipath_snap_cntr(dd, crp->cr_erricrccnt) + + ipath_snap_cntr(dd, crp->cr_errvcrccnt) + + ipath_snap_cntr(dd, crp->cr_errlpcrccnt) + + ipath_snap_cntr(dd, crp->cr_badformatcnt) + dd->ipath_rxfc_unsupvl_errs; cntrs->port_rcv_remphys_errors = - ipath_snap_cntr(dd, dd->ipath_cregs->cr_rcvebpcnt); - cntrs->port_xmit_discards = - ipath_snap_cntr(dd, dd->ipath_cregs->cr_unsupvlcnt); - cntrs->port_xmit_data = - ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordsendcnt); - cntrs->port_rcv_data = - ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordrcvcnt); - cntrs->port_xmit_packets = - ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktsendcnt); - cntrs->port_rcv_packets = - ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktrcvcnt); + ipath_snap_cntr(dd, crp->cr_rcvebpcnt); + cntrs->port_xmit_discards = ipath_snap_cntr(dd, crp->cr_unsupvlcnt); + cntrs->port_xmit_data = ipath_snap_cntr(dd, crp->cr_wordsendcnt); + cntrs->port_rcv_data = ipath_snap_cntr(dd, crp->cr_wordrcvcnt); + cntrs->port_xmit_packets = ipath_snap_cntr(dd, crp->cr_pktsendcnt); + cntrs->port_rcv_packets = ipath_snap_cntr(dd, crp->cr_pktrcvcnt); cntrs->local_link_integrity_errors = (dd->ipath_flags & IPATH_GPIO_ERRINTRS) ? dd->ipath_lli_errs : dd->ipath_lli_errors; @@ -1045,8 +1127,9 @@ static int ipath_query_port(struct ib_device *ibdev, u8 port, struct ib_port_attr *props) { struct ipath_ibdev *dev = to_idev(ibdev); + struct ipath_devdata *dd = dev->dd; enum ib_mtu mtu; - u16 lid = dev->dd->ipath_lid; + u16 lid = dd->ipath_lid; u64 ibcstat; memset(props, 0, sizeof(*props)); @@ -1054,16 +1137,16 @@ static int ipath_query_port(struct ib_device *ibdev, props->lmc = dev->mkeyprot_resv_lmc & 7; props->sm_lid = dev->sm_lid; props->sm_sl = dev->sm_sl; - ibcstat = dev->dd->ipath_lastibcstat; + ibcstat = dd->ipath_lastibcstat; props->state = ((ibcstat >> 4) & 0x3) + 1; /* See phys_state_show() */ props->phys_state = ipath_cvt_physportstate[ - dev->dd->ipath_lastibcstat & 0xf]; + dd->ipath_lastibcstat & 0xf]; props->port_cap_flags = dev->port_cap_flags; props->gid_tbl_len = 1; props->max_msg_sz = 0x80000000; - props->pkey_tbl_len = ipath_get_npkeys(dev->dd); - props->bad_pkey_cntr = ipath_get_cr_errpkey(dev->dd) - + props->pkey_tbl_len = ipath_get_npkeys(dd); + props->bad_pkey_cntr = ipath_get_cr_errpkey(dd) - dev->z_pkey_violations; props->qkey_viol_cntr = dev->qkey_violations; props->active_width = IB_WIDTH_4X; @@ -1073,12 +1156,12 @@ static int ipath_query_port(struct ib_device *ibdev, props->init_type_reply = 0; /* - * Note: the chips support a maximum MTU of 4096, but the driver + * Note: the chip supports a maximum MTU of 4096, but the driver * hasn't implemented this feature yet, so set the maximum value * to 2048. */ props->max_mtu = IB_MTU_2048; - switch (dev->dd->ipath_ibmtu) { + switch (dd->ipath_ibmtu) { case 4096: mtu = IB_MTU_4096; break; @@ -1427,9 +1510,7 @@ static int disable_timer(struct ipath_devdata *dd) { /* Disable GPIO bit 2 interrupt */ if (dd->ipath_flags & IPATH_GPIO_INTR) { - u64 val; /* Disable GPIO bit 2 interrupt */ - val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_gpio_mask); dd->ipath_gpio_mask &= ~((u64) (1 << IPATH_GPIO_PORT0_BIT)); ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_mask, dd->ipath_gpio_mask); diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.h b/drivers/infiniband/hw/ipath/ipath_verbs.h index 1a24c6a4a81..619ad728b07 100644 --- a/drivers/infiniband/hw/ipath/ipath_verbs.h +++ b/drivers/infiniband/hw/ipath/ipath_verbs.h @@ -42,6 +42,8 @@ #include #include +#include "ipath_kernel.h" + #define IPATH_MAX_RDMA_ATOMIC 4 #define QPN_MAX (1 << 24) @@ -59,6 +61,7 @@ */ #define IB_CQ_NONE (IB_CQ_NEXT_COMP + 1) +/* AETH NAK opcode values */ #define IB_RNR_NAK 0x20 #define IB_NAK_PSN_ERROR 0x60 #define IB_NAK_INVALID_REQUEST 0x61 @@ -66,6 +69,7 @@ #define IB_NAK_REMOTE_OPERATIONAL_ERROR 0x63 #define IB_NAK_INVALID_RD_REQUEST 0x64 +/* Flags for checking QP state (see ib_ipath_state_ops[]) */ #define IPATH_POST_SEND_OK 0x01 #define IPATH_POST_RECV_OK 0x02 #define IPATH_PROCESS_RECV_OK 0x04 @@ -239,7 +243,7 @@ struct ipath_mregion { */ struct ipath_sge { struct ipath_mregion *mr; - void *vaddr; /* current pointer into the segment */ + void *vaddr; /* kernel virtual address of segment */ u32 sge_length; /* length of the SGE */ u32 length; /* remaining length of the segment */ u16 m; /* current index: mr->map[m] */ @@ -407,6 +411,7 @@ struct ipath_qp { u32 s_ssn; /* SSN of tail entry */ u32 s_lsn; /* limit sequence number (credit) */ struct ipath_swqe *s_wq; /* send work queue */ + struct ipath_swqe *s_wqe; struct ipath_rq r_rq; /* receive work queue */ struct ipath_sge r_sg_list[0]; /* verified SGEs */ }; @@ -683,8 +688,8 @@ void ipath_sqerror_qp(struct ipath_qp *qp, struct ib_wc *wc); void ipath_get_credit(struct ipath_qp *qp, u32 aeth); -int ipath_verbs_send(struct ipath_devdata *dd, u32 hdrwords, - u32 *hdr, u32 len, struct ipath_sge_state *ss); +int ipath_verbs_send(struct ipath_qp *qp, struct ipath_ib_header *hdr, + u32 hdrwords, struct ipath_sge_state *ss, u32 len); void ipath_cq_enter(struct ipath_cq *cq, struct ib_wc *entry, int sig); @@ -692,8 +697,6 @@ void ipath_copy_sge(struct ipath_sge_state *ss, void *data, u32 length); void ipath_skip_sge(struct ipath_sge_state *ss, u32 length); -int ipath_post_ruc_send(struct ipath_qp *qp, struct ib_send_wr *wr); - void ipath_uc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr, int has_grh, void *data, u32 tlen, struct ipath_qp *qp); @@ -733,6 +736,8 @@ int ipath_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr); int ipath_destroy_srq(struct ib_srq *ibsrq); +void ipath_cq_enter(struct ipath_cq *cq, struct ib_wc *entry, int sig); + int ipath_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry); struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries, int comp_vector, @@ -782,18 +787,28 @@ int ipath_mmap(struct ib_ucontext *context, struct vm_area_struct *vma); void ipath_insert_rnr_queue(struct ipath_qp *qp); +int ipath_init_sge(struct ipath_qp *qp, struct ipath_rwqe *wqe, + u32 *lengthp, struct ipath_sge_state *ss); + int ipath_get_rwqe(struct ipath_qp *qp, int wr_id_only); u32 ipath_make_grh(struct ipath_ibdev *dev, struct ib_grh *hdr, struct ib_global_route *grh, u32 hwords, u32 nwords); -void ipath_do_ruc_send(unsigned long data); +void ipath_make_ruc_header(struct ipath_ibdev *dev, struct ipath_qp *qp, + struct ipath_other_headers *ohdr, + u32 bth0, u32 bth2); + +void ipath_do_send(unsigned long data); + +void ipath_send_complete(struct ipath_qp *qp, struct ipath_swqe *wqe, + enum ib_wc_status status); + +int ipath_make_rc_req(struct ipath_qp *qp); -int ipath_make_rc_req(struct ipath_qp *qp, struct ipath_other_headers *ohdr, - u32 pmtu, u32 *bth0p, u32 *bth2p); +int ipath_make_uc_req(struct ipath_qp *qp); -int ipath_make_uc_req(struct ipath_qp *qp, struct ipath_other_headers *ohdr, - u32 pmtu, u32 *bth0p, u32 *bth2p); +int ipath_make_ud_req(struct ipath_qp *qp); int ipath_register_ib_device(struct ipath_devdata *); -- cgit v1.2.3-70-g09d2 From 9bec3992312b8bb3aee71bd3b57d106a0a649479 Mon Sep 17 00:00:00 2001 From: Dave Olson Date: Fri, 1 Jun 2007 13:01:47 -0700 Subject: IB/ipath: Verify host bus bandwidth to chip will not limit performance There have been a number of issues where host bandwidth via HT or PCIe to the InfiniPath chip has been limited in some fashion (BIOS, configuration, etc.), resulting in user confusion. This check gives a clear warning that something is wrong and needs to be resolved. Signed-off-by: Dave Olson Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_driver.c | 86 ++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c index 6ccba365a24..5248f57fe19 100644 --- a/drivers/infiniband/hw/ipath/ipath_driver.c +++ b/drivers/infiniband/hw/ipath/ipath_driver.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -280,6 +281,89 @@ void __attribute__((weak)) ipath_disable_wc(struct ipath_devdata *dd) { } +/* + * Perform a PIO buffer bandwidth write test, to verify proper system + * configuration. Even when all the setup calls work, occasionally + * BIOS or other issues can prevent write combining from working, or + * can cause other bandwidth problems to the chip. + * + * This test simply writes the same buffer over and over again, and + * measures close to the peak bandwidth to the chip (not testing + * data bandwidth to the wire). On chips that use an address-based + * trigger to send packets to the wire, this is easy. On chips that + * use a count to trigger, we want to make sure that the packet doesn't + * go out on the wire, or trigger flow control checks. + */ +static void ipath_verify_pioperf(struct ipath_devdata *dd) +{ + u32 pbnum, cnt, lcnt; + u32 __iomem *piobuf; + u32 *addr; + u64 msecs, emsecs; + + piobuf = ipath_getpiobuf(dd, &pbnum); + if (!piobuf) { + dev_info(&dd->pcidev->dev, + "No PIObufs for checking perf, skipping\n"); + return; + } + + /* + * Enough to give us a reasonable test, less than piobuf size, and + * likely multiple of store buffer length. + */ + cnt = 1024; + + addr = vmalloc(cnt); + if (!addr) { + dev_info(&dd->pcidev->dev, + "Couldn't get memory for checking PIO perf," + " skipping\n"); + goto done; + } + + preempt_disable(); /* we want reasonably accurate elapsed time */ + msecs = 1 + jiffies_to_msecs(jiffies); + for (lcnt = 0; lcnt < 10000U; lcnt++) { + /* wait until we cross msec boundary */ + if (jiffies_to_msecs(jiffies) >= msecs) + break; + udelay(1); + } + + writeq(0, piobuf); /* length 0, no dwords actually sent */ + ipath_flush_wc(); + + /* + * this is only roughly accurate, since even with preempt we + * still take interrupts that could take a while. Running for + * >= 5 msec seems to get us "close enough" to accurate values + */ + msecs = jiffies_to_msecs(jiffies); + for (emsecs = lcnt = 0; emsecs <= 5UL; lcnt++) { + __iowrite32_copy(piobuf + 64, addr, cnt >> 2); + emsecs = jiffies_to_msecs(jiffies) - msecs; + } + + /* 1 GiB/sec, slightly over IB SDR line rate */ + if (lcnt < (emsecs * 1024U)) + ipath_dev_err(dd, + "Performance problem: bandwidth to PIO buffers is " + "only %u MiB/sec\n", + lcnt / (u32) emsecs); + else + ipath_dbg("PIO buffer bandwidth %u MiB/sec is OK\n", + lcnt / (u32) emsecs); + + preempt_enable(); + + vfree(addr); + +done: + /* disarm piobuf, so it's available again */ + ipath_disarm_piobufs(dd, pbnum, 1); +} + static int __devinit ipath_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -515,6 +599,8 @@ static int __devinit ipath_init_one(struct pci_dev *pdev, ret = 0; } + ipath_verify_pioperf(dd); + ipath_device_create_group(&pdev->dev, dd); ipathfs_add_device(dd); ipath_user_add(dd); -- cgit v1.2.3-70-g09d2 From 1793b4771d258c93ed86a6356c95cac418781fdd Mon Sep 17 00:00:00 2001 From: Ralph Campbell Date: Tue, 7 Aug 2007 18:09:34 -0700 Subject: IB/ipath: Remove unneeded code for ipathfs The ipathfs file system is used to export binary data verses ASCII data such as through /sys. This patch removes some unneeded files since the data is available through other /sys files. Signed-off-by: Ralph Campbell Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_fs.c | 187 --------------------------------- 1 file changed, 187 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ipath/ipath_fs.c b/drivers/infiniband/hw/ipath/ipath_fs.c index 2e689b974e1..262c25db05c 100644 --- a/drivers/infiniband/hw/ipath/ipath_fs.c +++ b/drivers/infiniband/hw/ipath/ipath_fs.c @@ -130,175 +130,6 @@ static const struct file_operations atomic_counters_ops = { .read = atomic_counters_read, }; -static ssize_t atomic_node_info_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - u32 nodeinfo[10]; - struct ipath_devdata *dd; - u64 guid; - - dd = file->f_path.dentry->d_inode->i_private; - - guid = be64_to_cpu(dd->ipath_guid); - - nodeinfo[0] = /* BaseVersion is SMA */ - /* ClassVersion is SMA */ - (1 << 8) /* NodeType */ - | (1 << 0); /* NumPorts */ - nodeinfo[1] = (u32) (guid >> 32); - nodeinfo[2] = (u32) (guid & 0xffffffff); - /* PortGUID == SystemImageGUID for us */ - nodeinfo[3] = nodeinfo[1]; - /* PortGUID == SystemImageGUID for us */ - nodeinfo[4] = nodeinfo[2]; - /* PortGUID == NodeGUID for us */ - nodeinfo[5] = nodeinfo[3]; - /* PortGUID == NodeGUID for us */ - nodeinfo[6] = nodeinfo[4]; - nodeinfo[7] = (4 << 16) /* we support 4 pkeys */ - | (dd->ipath_deviceid << 0); - /* our chip version as 16 bits major, 16 bits minor */ - nodeinfo[8] = dd->ipath_minrev | (dd->ipath_majrev << 16); - nodeinfo[9] = (dd->ipath_unit << 24) | (dd->ipath_vendorid << 0); - - return simple_read_from_buffer(buf, count, ppos, nodeinfo, - sizeof nodeinfo); -} - -static const struct file_operations atomic_node_info_ops = { - .read = atomic_node_info_read, -}; - -static ssize_t atomic_port_info_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - u32 portinfo[13]; - u32 tmp, tmp2; - struct ipath_devdata *dd; - - dd = file->f_path.dentry->d_inode->i_private; - - /* so we only initialize non-zero fields. */ - memset(portinfo, 0, sizeof portinfo); - - /* - * Notimpl yet M_Key (64) - * Notimpl yet GID (64) - */ - - portinfo[4] = (dd->ipath_lid << 16); - - /* - * Notimpl yet SMLID. - * CapabilityMask is 0, we don't support any of these - * DiagCode is 0; we don't store any diag info for now Notimpl yet - * M_KeyLeasePeriod (we don't support M_Key) - */ - - /* LocalPortNum is whichever port number they ask for */ - portinfo[7] = (dd->ipath_unit << 24) - /* LinkWidthEnabled */ - | (2 << 16) - /* LinkWidthSupported (really 2, but not IB valid) */ - | (3 << 8) - /* LinkWidthActive */ - | (2 << 0); - tmp = dd->ipath_lastibcstat & IPATH_IBSTATE_MASK; - tmp2 = 5; - if (tmp == IPATH_IBSTATE_INIT) - tmp = 2; - else if (tmp == IPATH_IBSTATE_ARM) - tmp = 3; - else if (tmp == IPATH_IBSTATE_ACTIVE) - tmp = 4; - else { - tmp = 0; /* down */ - tmp2 = tmp & 0xf; - } - - portinfo[8] = (1 << 28) /* LinkSpeedSupported */ - | (tmp << 24) /* PortState */ - | (tmp2 << 20) /* PortPhysicalState */ - | (2 << 16) - - /* LinkDownDefaultState */ - /* M_KeyProtectBits == 0 */ - /* NotImpl yet LMC == 0 (we can support all values) */ - | (1 << 4) /* LinkSpeedActive */ - | (1 << 0); /* LinkSpeedEnabled */ - switch (dd->ipath_ibmtu) { - case 4096: - tmp = 5; - break; - case 2048: - tmp = 4; - break; - case 1024: - tmp = 3; - break; - case 512: - tmp = 2; - break; - case 256: - tmp = 1; - break; - default: /* oops, something is wrong */ - ipath_dbg("Problem, ipath_ibmtu 0x%x not a valid IB MTU, " - "treat as 2048\n", dd->ipath_ibmtu); - tmp = 4; - break; - } - portinfo[9] = (tmp << 28) - /* NeighborMTU */ - /* Notimpl MasterSMSL */ - | (1 << 20) - - /* VLCap */ - /* Notimpl InitType (actually, an SMA decision) */ - /* VLHighLimit is 0 (only one VL) */ - ; /* VLArbitrationHighCap is 0 (only one VL) */ - /* - * Note: the chips support a maximum MTU of 4096, but the driver - * hasn't implemented this feature yet, so set the maximum - * to 2048. - */ - portinfo[10] = /* VLArbitrationLowCap is 0 (only one VL) */ - /* InitTypeReply is SMA decision */ - (4 << 16) /* MTUCap 2048 */ - | (7 << 13) /* VLStallCount */ - | (0x1f << 8) /* HOQLife */ - | (1 << 4) - - /* OperationalVLs 0 */ - /* PartitionEnforcementInbound */ - /* PartitionEnforcementOutbound not enforced */ - /* FilterRawinbound not enforced */ - ; /* FilterRawOutbound not enforced */ - /* M_KeyViolations are not counted by hardware, SMA can count */ - tmp = ipath_read_creg32(dd, dd->ipath_cregs->cr_errpkey); - /* P_KeyViolations are counted by hardware. */ - portinfo[11] = ((tmp & 0xffff) << 0); - portinfo[12] = - /* Q_KeyViolations are not counted by hardware */ - (1 << 8) - - /* GUIDCap */ - /* SubnetTimeOut handled by SMA */ - /* RespTimeValue handled by SMA */ - ; - /* LocalPhyErrors are programmed to max */ - portinfo[12] |= (0xf << 20) - | (0xf << 16) /* OverRunErrors are programmed to max */ - ; - - return simple_read_from_buffer(buf, count, ppos, portinfo, - sizeof portinfo); -} - -static const struct file_operations atomic_port_info_ops = { - .read = atomic_port_info_read, -}; - static ssize_t flash_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { @@ -427,22 +258,6 @@ static int create_device_files(struct super_block *sb, goto bail; } - ret = create_file("node_info", S_IFREG|S_IRUGO, dir, &tmp, - &atomic_node_info_ops, dd); - if (ret) { - printk(KERN_ERR "create_file(%s/node_info) " - "failed: %d\n", unit, ret); - goto bail; - } - - ret = create_file("port_info", S_IFREG|S_IRUGO, dir, &tmp, - &atomic_port_info_ops, dd); - if (ret) { - printk(KERN_ERR "create_file(%s/port_info) " - "failed: %d\n", unit, ret); - goto bail; - } - ret = create_file("flash", S_IFREG|S_IWUSR|S_IRUGO, dir, &tmp, &flash_ops, dd); if (ret) { @@ -508,8 +323,6 @@ static int remove_device_files(struct super_block *sb, } remove_file(dir, "flash"); - remove_file(dir, "port_info"); - remove_file(dir, "node_info"); remove_file(dir, "atomic_counters"); d_delete(dir); ret = simple_rmdir(root->d_inode, dir); -- cgit v1.2.3-70-g09d2 From 9ef8617af77136e743e5dd4b081a61797888a977 Mon Sep 17 00:00:00 2001 From: Dave Olson Date: Thu, 9 Aug 2007 15:18:48 -0700 Subject: IB/ipath: Correctly describe workaround for TID write chip bug This is a comment change, only, correcting the comment to match the implemented workaround, rather than the original workaround, and clarifying why it's needed. Signed-off-by: Dave Olson Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_iba6120.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ipath/ipath_iba6120.c b/drivers/infiniband/hw/ipath/ipath_iba6120.c index a324c6f7aeb..d43f0b3a43f 100644 --- a/drivers/infiniband/hw/ipath/ipath_iba6120.c +++ b/drivers/infiniband/hw/ipath/ipath_iba6120.c @@ -1143,11 +1143,14 @@ static void ipath_pe_put_tid(struct ipath_devdata *dd, u64 __iomem *tidptr, pa |= 2 << 29; } - /* workaround chip bug 9437 by writing each TID twice - * and holding a spinlock around the writes, so they don't - * intermix with other TID (eager or expected) writes - * Unfortunately, this call can be done from interrupt level - * for the port 0 eager TIDs, so we have to use irqsave + /* + * Workaround chip bug 9437 by writing the scratch register + * before and after the TID, and with an io write barrier. + * We use a spinlock around the writes, so they can't intermix + * with other TID (eager or expected) writes (the chip bug + * is triggered by back to back TID writes). Unfortunately, this + * call can be done from interrupt level for the port 0 eager TIDs, + * so we have to use irqsave locks. */ spin_lock_irqsave(&dd->ipath_tid_lock, flags); ipath_write_kreg(dd, dd->ipath_kregs->kr_scratch, 0xfeeddeaf); -- cgit v1.2.3-70-g09d2 From 55046698faf6357ff7c53593dbfd43a9a3f681a7 Mon Sep 17 00:00:00 2001 From: Ralph Campbell Date: Fri, 17 Aug 2007 11:28:48 -0700 Subject: IB/ipath: UC RDMA WRITE with IMMEDIATE doesn't send the immediate This patch fixes a bug in the receive processing for UC RDMA WRITE with immediate which caused the last packet to be dropped. Signed-off-by: Ralph Campbell Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_uc.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ipath/ipath_uc.c b/drivers/infiniband/hw/ipath/ipath_uc.c index 767beb903c2..2dd8de20d22 100644 --- a/drivers/infiniband/hw/ipath/ipath_uc.c +++ b/drivers/infiniband/hw/ipath/ipath_uc.c @@ -464,6 +464,16 @@ void ipath_uc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr, case OP(RDMA_WRITE_LAST_WITH_IMMEDIATE): rdma_last_imm: + if (header_in_data) { + wc.imm_data = *(__be32 *) data; + data += sizeof(__be32); + } else { + /* Immediate data comes after BTH */ + wc.imm_data = ohdr->u.imm_data; + } + hdrsize += 4; + wc.wc_flags = IB_WC_WITH_IMM; + /* Get the number of bytes the message was padded by. */ pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3; /* Check for invalid length. */ @@ -484,16 +494,7 @@ void ipath_uc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr, dev->n_pkt_drops++; goto done; } - if (header_in_data) { - wc.imm_data = *(__be32 *) data; - data += sizeof(__be32); - } else { - /* Immediate data comes after BTH */ - wc.imm_data = ohdr->u.imm_data; - } - hdrsize += 4; - wc.wc_flags = IB_WC_WITH_IMM; - wc.byte_len = 0; + wc.byte_len = qp->r_len; goto last_imm; case OP(RDMA_WRITE_LAST): -- cgit v1.2.3-70-g09d2 From d29cc6efb9731a415957b8d0ff16e31729ed6837 Mon Sep 17 00:00:00 2001 From: Dave Olson Date: Fri, 17 Aug 2007 14:42:14 -0700 Subject: IB/ipath: Future proof eeprom checksum code (contents reading) In an earlier change, the amount of data read from the flash was mistakenly limited to the size known to the current driver. This causes problems when the length is increased, and written with the new longer version; the checksum would fail because not enough data was read. Always read the full 128 byte length to prevent this. Signed-off-by: Dave Olson Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_eeprom.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ipath/ipath_eeprom.c b/drivers/infiniband/hw/ipath/ipath_eeprom.c index b4503e9c1e9..bcfa3ccb555 100644 --- a/drivers/infiniband/hw/ipath/ipath_eeprom.c +++ b/drivers/infiniband/hw/ipath/ipath_eeprom.c @@ -596,7 +596,11 @@ void ipath_get_eeprom_info(struct ipath_devdata *dd) goto bail; } - len = offsetof(struct ipath_flash, if_future); + /* + * read full flash, not just currently used part, since it may have + * been written with a newer definition + * */ + len = sizeof(struct ipath_flash); buf = vmalloc(len); if (!buf) { ipath_dev_err(dd, "Couldn't allocate memory to read %u " @@ -737,8 +741,10 @@ int ipath_update_eeprom_log(struct ipath_devdata *dd) /* * The quick-check above determined that there is something worthy * of logging, so get current contents and do a more detailed idea. + * read full flash, not just currently used part, since it may have + * been written with a newer definition */ - len = offsetof(struct ipath_flash, if_future); + len = sizeof(struct ipath_flash); buf = vmalloc(len); ret = 1; if (!buf) { -- cgit v1.2.3-70-g09d2 From 036be09ca55ee8512c05742f4f6b88911d012a90 Mon Sep 17 00:00:00 2001 From: Ralph Campbell Date: Mon, 20 Aug 2007 16:52:35 -0700 Subject: IB/ipath: Remove redundant code This patch removes some redundant initialization code. Signed-off-by: Ralph Campbell Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_driver.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c index 5248f57fe19..44784d049b7 100644 --- a/drivers/infiniband/hw/ipath/ipath_driver.c +++ b/drivers/infiniband/hw/ipath/ipath_driver.c @@ -382,8 +382,6 @@ static int __devinit ipath_init_one(struct pci_dev *pdev, ipath_cdbg(VERBOSE, "initializing unit #%u\n", dd->ipath_unit); - read_bars(dd, pdev, &bar0, &bar1); - ret = pci_enable_device(pdev); if (ret) { /* This can happen iff: @@ -529,9 +527,6 @@ static int __devinit ipath_init_one(struct pci_dev *pdev, goto bail_regions; } - dd->ipath_deviceid = ent->device; /* save for later use */ - dd->ipath_vendorid = ent->vendor; - dd->ipath_pcirev = pdev->revision; #if defined(__powerpc__) -- cgit v1.2.3-70-g09d2 From c9cf7db2bca9180f5888eebc23dc607666a9685b Mon Sep 17 00:00:00 2001 From: Ralph Campbell Date: Sat, 25 Aug 2007 16:48:29 -0700 Subject: IB/ipath: Generate flush CQE when QP is in error state Follow the IB spec. (C10-96) for post send which states that a flushed completion event should be generated for work requests posted when a QP is in the error state. Signed-off-by: Ralph Campbell Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_verbs.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c index 3cc82b62b3c..495194bb84a 100644 --- a/drivers/infiniband/hw/ipath/ipath_verbs.c +++ b/drivers/infiniband/hw/ipath/ipath_verbs.c @@ -230,6 +230,18 @@ void ipath_skip_sge(struct ipath_sge_state *ss, u32 length) } } +static void ipath_flush_wqe(struct ipath_qp *qp, struct ib_send_wr *wr) +{ + struct ib_wc wc; + + memset(&wc, 0, sizeof(wc)); + wc.wr_id = wr->wr_id; + wc.status = IB_WC_WR_FLUSH_ERR; + wc.opcode = ib_ipath_wc_opcode[wr->opcode]; + wc.qp = &qp->ibqp; + ipath_cq_enter(to_icq(qp->ibqp.send_cq), &wc, 1); +} + /** * ipath_post_one_send - post one RC, UC, or UD send work request * @qp: the QP to post on @@ -248,8 +260,14 @@ static int ipath_post_one_send(struct ipath_qp *qp, struct ib_send_wr *wr) spin_lock_irqsave(&qp->s_lock, flags); /* Check that state is OK to post send. */ - if (!(ib_ipath_state_ops[qp->state] & IPATH_POST_SEND_OK)) - goto bail_inval; + if (unlikely(!(ib_ipath_state_ops[qp->state] & IPATH_POST_SEND_OK))) { + if (qp->state != IB_QPS_SQE && qp->state != IB_QPS_ERR) + goto bail_inval; + /* C10-96 says generate a flushed completion entry. */ + ipath_flush_wqe(qp, wr); + ret = 0; + goto bail; + } /* IB spec says that num_sge == 0 is OK. */ if (wr->num_sge > qp->s_max_sge) -- cgit v1.2.3-70-g09d2 From d42b01b584b6f55f70c56f6a3dabc26f4982d30d Mon Sep 17 00:00:00 2001 From: Ralph Campbell Date: Sat, 25 Aug 2007 16:45:03 -0700 Subject: IB/ipath: Implement IB_EVENT_QP_LAST_WQE_REACHED This patch implements the IB_EVENT_QP_LAST_WQE_REACHED event which is needed by ib_ipoib to destroy the QP when used in connected mode. Signed-off-by: Ralph Campbell Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_qp.c | 20 +++++++++++++++++--- drivers/infiniband/hw/ipath/ipath_rc.c | 12 +++++++++++- drivers/infiniband/hw/ipath/ipath_verbs.h | 2 +- 3 files changed, 29 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ipath/ipath_qp.c b/drivers/infiniband/hw/ipath/ipath_qp.c index a8c4a6b03d7..6a41fdbc8e5 100644 --- a/drivers/infiniband/hw/ipath/ipath_qp.c +++ b/drivers/infiniband/hw/ipath/ipath_qp.c @@ -377,13 +377,15 @@ static void ipath_reset_qp(struct ipath_qp *qp) * @err: the receive completion error to signal if a RWQE is active * * Flushes both send and receive work queues. + * Returns true if last WQE event should be generated. * The QP s_lock should be held and interrupts disabled. */ -void ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err) +int ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err) { struct ipath_ibdev *dev = to_idev(qp->ibqp.device); struct ib_wc wc; + int ret = 0; ipath_dbg("QP%d/%d in error state\n", qp->ibqp.qp_num, qp->remote_qpn); @@ -454,7 +456,10 @@ void ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err) wq->tail = tail; spin_unlock(&qp->r_rq.lock); - } + } else if (qp->ibqp.event_handler) + ret = 1; + + return ret; } /** @@ -473,6 +478,7 @@ int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, struct ipath_qp *qp = to_iqp(ibqp); enum ib_qp_state cur_state, new_state; unsigned long flags; + int lastwqe = 0; int ret; spin_lock_irqsave(&qp->s_lock, flags); @@ -532,7 +538,7 @@ int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, break; case IB_QPS_ERR: - ipath_error_qp(qp, IB_WC_WR_FLUSH_ERR); + lastwqe = ipath_error_qp(qp, IB_WC_WR_FLUSH_ERR); break; default: @@ -591,6 +597,14 @@ int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, qp->state = new_state; spin_unlock_irqrestore(&qp->s_lock, flags); + if (lastwqe) { + struct ib_event ev; + + ev.device = qp->ibqp.device; + ev.element.qp = &qp->ibqp; + ev.event = IB_EVENT_QP_LAST_WQE_REACHED; + qp->ibqp.event_handler(&ev, qp->ibqp.qp_context); + } ret = 0; goto bail; diff --git a/drivers/infiniband/hw/ipath/ipath_rc.c b/drivers/infiniband/hw/ipath/ipath_rc.c index 53259daeb4f..5c29b2bfea1 100644 --- a/drivers/infiniband/hw/ipath/ipath_rc.c +++ b/drivers/infiniband/hw/ipath/ipath_rc.c @@ -1497,11 +1497,21 @@ send_ack: static void ipath_rc_error(struct ipath_qp *qp, enum ib_wc_status err) { unsigned long flags; + int lastwqe; spin_lock_irqsave(&qp->s_lock, flags); qp->state = IB_QPS_ERR; - ipath_error_qp(qp, err); + lastwqe = ipath_error_qp(qp, err); spin_unlock_irqrestore(&qp->s_lock, flags); + + if (lastwqe) { + struct ib_event ev; + + ev.device = qp->ibqp.device; + ev.element.qp = &qp->ibqp; + ev.event = IB_EVENT_QP_LAST_WQE_REACHED; + qp->ibqp.event_handler(&ev, qp->ibqp.qp_context); + } } static inline void ipath_update_ack_queue(struct ipath_qp *qp, unsigned n) diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.h b/drivers/infiniband/hw/ipath/ipath_verbs.h index 619ad728b07..a1972295bff 100644 --- a/drivers/infiniband/hw/ipath/ipath_verbs.h +++ b/drivers/infiniband/hw/ipath/ipath_verbs.h @@ -672,7 +672,7 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd, int ipath_destroy_qp(struct ib_qp *ibqp); -void ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err); +int ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err); int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask, struct ib_udata *udata); -- cgit v1.2.3-70-g09d2 From 6cff2faaf135b602c914710f3414630c3fc1ee83 Mon Sep 17 00:00:00 2001 From: Ralph Campbell Date: Fri, 7 Sep 2007 16:54:01 -0700 Subject: IB/ipath: Optimize completion queue entry insertion and polling The code to add an entry to the completion queue stored the QPN which is needed for the user level verbs view of the completion queue entry but the kernel struct ib_wc contains a pointer to the QP instead of a QPN. When the kernel polled for a completion queue entry, the QPN was lookup up and the QP pointer recovered. This patch stores the CQE differently based on whether the CQ is a kernel CQ or a user CQ thus avoiding the QPN to QP lookup overhead. Signed-off-by: Ralph Campbell Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_cq.c | 94 ++++++++++++++++--------------- drivers/infiniband/hw/ipath/ipath_verbs.h | 6 +- 2 files changed, 53 insertions(+), 47 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ipath/ipath_cq.c b/drivers/infiniband/hw/ipath/ipath_cq.c index a6f04d27ec5..645ed71fd79 100644 --- a/drivers/infiniband/hw/ipath/ipath_cq.c +++ b/drivers/infiniband/hw/ipath/ipath_cq.c @@ -76,22 +76,25 @@ void ipath_cq_enter(struct ipath_cq *cq, struct ib_wc *entry, int solicited) } return; } - wc->queue[head].wr_id = entry->wr_id; - wc->queue[head].status = entry->status; - wc->queue[head].opcode = entry->opcode; - wc->queue[head].vendor_err = entry->vendor_err; - wc->queue[head].byte_len = entry->byte_len; - wc->queue[head].imm_data = (__u32 __force)entry->imm_data; - wc->queue[head].qp_num = entry->qp->qp_num; - wc->queue[head].src_qp = entry->src_qp; - wc->queue[head].wc_flags = entry->wc_flags; - wc->queue[head].pkey_index = entry->pkey_index; - wc->queue[head].slid = entry->slid; - wc->queue[head].sl = entry->sl; - wc->queue[head].dlid_path_bits = entry->dlid_path_bits; - wc->queue[head].port_num = entry->port_num; - /* Make sure queue entry is written before the head index. */ - smp_wmb(); + if (cq->ip) { + wc->uqueue[head].wr_id = entry->wr_id; + wc->uqueue[head].status = entry->status; + wc->uqueue[head].opcode = entry->opcode; + wc->uqueue[head].vendor_err = entry->vendor_err; + wc->uqueue[head].byte_len = entry->byte_len; + wc->uqueue[head].imm_data = (__u32 __force)entry->imm_data; + wc->uqueue[head].qp_num = entry->qp->qp_num; + wc->uqueue[head].src_qp = entry->src_qp; + wc->uqueue[head].wc_flags = entry->wc_flags; + wc->uqueue[head].pkey_index = entry->pkey_index; + wc->uqueue[head].slid = entry->slid; + wc->uqueue[head].sl = entry->sl; + wc->uqueue[head].dlid_path_bits = entry->dlid_path_bits; + wc->uqueue[head].port_num = entry->port_num; + /* Make sure entry is written before the head index. */ + smp_wmb(); + } else + wc->kqueue[head] = *entry; wc->head = next; if (cq->notify == IB_CQ_NEXT_COMP || @@ -130,6 +133,12 @@ int ipath_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry) int npolled; u32 tail; + /* The kernel can only poll a kernel completion queue */ + if (cq->ip) { + npolled = -EINVAL; + goto bail; + } + spin_lock_irqsave(&cq->lock, flags); wc = cq->queue; @@ -137,31 +146,10 @@ int ipath_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry) if (tail > (u32) cq->ibcq.cqe) tail = (u32) cq->ibcq.cqe; for (npolled = 0; npolled < num_entries; ++npolled, ++entry) { - struct ipath_qp *qp; - if (tail == wc->head) break; - /* Make sure entry is read after head index is read. */ - smp_rmb(); - qp = ipath_lookup_qpn(&to_idev(cq->ibcq.device)->qp_table, - wc->queue[tail].qp_num); - entry->qp = &qp->ibqp; - if (atomic_dec_and_test(&qp->refcount)) - wake_up(&qp->wait); - - entry->wr_id = wc->queue[tail].wr_id; - entry->status = wc->queue[tail].status; - entry->opcode = wc->queue[tail].opcode; - entry->vendor_err = wc->queue[tail].vendor_err; - entry->byte_len = wc->queue[tail].byte_len; - entry->imm_data = wc->queue[tail].imm_data; - entry->src_qp = wc->queue[tail].src_qp; - entry->wc_flags = wc->queue[tail].wc_flags; - entry->pkey_index = wc->queue[tail].pkey_index; - entry->slid = wc->queue[tail].slid; - entry->sl = wc->queue[tail].sl; - entry->dlid_path_bits = wc->queue[tail].dlid_path_bits; - entry->port_num = wc->queue[tail].port_num; + /* The kernel doesn't need a RMB since it has the lock. */ + *entry = wc->kqueue[tail]; if (tail >= cq->ibcq.cqe) tail = 0; else @@ -171,6 +159,7 @@ int ipath_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry) spin_unlock_irqrestore(&cq->lock, flags); +bail: return npolled; } @@ -215,6 +204,7 @@ struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries, int comp_vec struct ipath_cq *cq; struct ipath_cq_wc *wc; struct ib_cq *ret; + u32 sz; if (entries < 1 || entries > ib_ipath_max_cqes) { ret = ERR_PTR(-EINVAL); @@ -235,7 +225,12 @@ struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries, int comp_vec * We need to use vmalloc() in order to support mmap and large * numbers of entries. */ - wc = vmalloc_user(sizeof(*wc) + sizeof(struct ib_wc) * entries); + sz = sizeof(*wc); + if (udata && udata->outlen >= sizeof(__u64)) + sz += sizeof(struct ib_uverbs_wc) * (entries + 1); + else + sz += sizeof(struct ib_wc) * (entries + 1); + wc = vmalloc_user(sz); if (!wc) { ret = ERR_PTR(-ENOMEM); goto bail_cq; @@ -247,9 +242,8 @@ struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries, int comp_vec */ if (udata && udata->outlen >= sizeof(__u64)) { int err; - u32 s = sizeof *wc + sizeof(struct ib_wc) * entries; - cq->ip = ipath_create_mmap_info(dev, s, context, wc); + cq->ip = ipath_create_mmap_info(dev, sz, context, wc); if (!cq->ip) { ret = ERR_PTR(-ENOMEM); goto bail_wc; @@ -380,6 +374,7 @@ int ipath_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata) struct ipath_cq_wc *wc; u32 head, tail, n; int ret; + u32 sz; if (cqe < 1 || cqe > ib_ipath_max_cqes) { ret = -EINVAL; @@ -389,7 +384,12 @@ int ipath_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata) /* * Need to use vmalloc() if we want to support large #s of entries. */ - wc = vmalloc_user(sizeof(*wc) + sizeof(struct ib_wc) * cqe); + sz = sizeof(*wc); + if (udata && udata->outlen >= sizeof(__u64)) + sz += sizeof(struct ib_uverbs_wc) * (cqe + 1); + else + sz += sizeof(struct ib_wc) * (cqe + 1); + wc = vmalloc_user(sz); if (!wc) { ret = -ENOMEM; goto bail; @@ -430,7 +430,10 @@ int ipath_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata) goto bail; } for (n = 0; tail != head; n++) { - wc->queue[n] = old_wc->queue[tail]; + if (cq->ip) + wc->uqueue[n] = old_wc->uqueue[tail]; + else + wc->kqueue[n] = old_wc->kqueue[tail]; if (tail == (u32) cq->ibcq.cqe) tail = 0; else @@ -447,9 +450,8 @@ int ipath_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata) if (cq->ip) { struct ipath_ibdev *dev = to_idev(ibcq->device); struct ipath_mmap_info *ip = cq->ip; - u32 s = sizeof *wc + sizeof(struct ib_wc) * cqe; - ipath_update_mmap_info(dev, ip, s, wc); + ipath_update_mmap_info(dev, ip, sz, wc); spin_lock_irq(&dev->pending_lock); if (list_empty(&ip->pending_mmaps)) list_add(&ip->pending_mmaps, &dev->pending_mmaps); diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.h b/drivers/infiniband/hw/ipath/ipath_verbs.h index a1972295bff..9be9bf91f4f 100644 --- a/drivers/infiniband/hw/ipath/ipath_verbs.h +++ b/drivers/infiniband/hw/ipath/ipath_verbs.h @@ -191,7 +191,11 @@ struct ipath_mmap_info { struct ipath_cq_wc { u32 head; /* index of next entry to fill */ u32 tail; /* index of next ib_poll_cq() entry */ - struct ib_uverbs_wc queue[1]; /* this is actually size ibcq.cqe + 1 */ + union { + /* these are actually size ibcq.cqe + 1 */ + struct ib_uverbs_wc uqueue[0]; + struct ib_wc kqueue[0]; + }; }; /* -- cgit v1.2.3-70-g09d2 From 15cba26f42c13ca30cbb4388f132ac0ddf4df538 Mon Sep 17 00:00:00 2001 From: Ralph Campbell Date: Wed, 12 Sep 2007 15:00:58 -0700 Subject: IB/ipath: Add ability to set the LMC via the sysfs debugging interface This patch adds the ability to set the LMC via a sysfs file as if the SM sent a SubnSet(PortInfo) MAD. It is useful for debugging when no SM is running. Signed-off-by: Ralph Campbell Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_sysfs.c | 40 ++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ipath/ipath_sysfs.c b/drivers/infiniband/hw/ipath/ipath_sysfs.c index 16238cd3a03..e1ad7cfc21f 100644 --- a/drivers/infiniband/hw/ipath/ipath_sysfs.c +++ b/drivers/infiniband/hw/ipath/ipath_sysfs.c @@ -163,6 +163,42 @@ static ssize_t show_boardversion(struct device *dev, return scnprintf(buf, PAGE_SIZE, "%s", dd->ipath_boardversion); } +static ssize_t show_lmc(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ipath_devdata *dd = dev_get_drvdata(dev); + + return scnprintf(buf, PAGE_SIZE, "%u\n", dd->ipath_lmc); +} + +static ssize_t store_lmc(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct ipath_devdata *dd = dev_get_drvdata(dev); + u16 lmc = 0; + int ret; + + ret = ipath_parse_ushort(buf, &lmc); + if (ret < 0) + goto invalid; + + if (lmc > 7) { + ret = -EINVAL; + goto invalid; + } + + ipath_set_lid(dd, dd->ipath_lid, lmc); + + goto bail; +invalid: + ipath_dev_err(dd, "attempt to set invalid LMC %u\n", lmc); +bail: + return ret; +} + static ssize_t show_lid(struct device *dev, struct device_attribute *attr, char *buf) @@ -190,7 +226,7 @@ static ssize_t store_lid(struct device *dev, goto invalid; } - ipath_set_lid(dd, lid, 0); + ipath_set_lid(dd, lid, dd->ipath_lmc); goto bail; invalid: @@ -648,6 +684,7 @@ static struct attribute_group driver_attr_group = { }; static DEVICE_ATTR(guid, S_IWUSR | S_IRUGO, show_guid, store_guid); +static DEVICE_ATTR(lmc, S_IWUSR | S_IRUGO, show_lmc, store_lmc); static DEVICE_ATTR(lid, S_IWUSR | S_IRUGO, show_lid, store_lid); static DEVICE_ATTR(link_state, S_IWUSR, NULL, store_link_state); static DEVICE_ATTR(mlid, S_IWUSR | S_IRUGO, show_mlid, store_mlid); @@ -667,6 +704,7 @@ static DEVICE_ATTR(logged_errors, S_IRUGO, show_logged_errs, NULL); static struct attribute *dev_attributes[] = { &dev_attr_guid.attr, + &dev_attr_lmc.attr, &dev_attr_lid.attr, &dev_attr_link_state.attr, &dev_attr_mlid.attr, -- cgit v1.2.3-70-g09d2 From 542869a17eee2edf389273f40f757aa4e662b3da Mon Sep 17 00:00:00 2001 From: Ralph Campbell Date: Thu, 13 Sep 2007 11:42:52 -0700 Subject: IB/ipath: Remove duplicate copy of LMC The LMC value was being saved by the SMA in two places. This patch cleans it up so only one copy is kept. Signed-off-by: Ralph Campbell Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_mad.c | 39 +++++++++++++++++-------------- drivers/infiniband/hw/ipath/ipath_ud.c | 10 ++++---- drivers/infiniband/hw/ipath/ipath_verbs.c | 4 ++-- drivers/infiniband/hw/ipath/ipath_verbs.h | 2 +- 4 files changed, 29 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ipath/ipath_mad.c b/drivers/infiniband/hw/ipath/ipath_mad.c index d61c0304454..8f152167208 100644 --- a/drivers/infiniband/hw/ipath/ipath_mad.c +++ b/drivers/infiniband/hw/ipath/ipath_mad.c @@ -245,7 +245,7 @@ static int recv_subn_get_portinfo(struct ib_smp *smp, /* Only return the mkey if the protection field allows it. */ if (smp->method == IB_MGMT_METHOD_SET || dev->mkey == smp->mkey || - (dev->mkeyprot_resv_lmc >> 6) == 0) + dev->mkeyprot == 0) pip->mkey = dev->mkey; pip->gid_prefix = dev->gid_prefix; lid = dev->dd->ipath_lid; @@ -264,7 +264,7 @@ static int recv_subn_get_portinfo(struct ib_smp *smp, pip->portphysstate_linkdown = (ipath_cvt_physportstate[ibcstat & 0xf] << 4) | (get_linkdowndefaultstate(dev->dd) ? 1 : 2); - pip->mkeyprot_resv_lmc = dev->mkeyprot_resv_lmc; + pip->mkeyprot_resv_lmc = (dev->mkeyprot << 6) | dev->dd->ipath_lmc; pip->linkspeedactive_enabled = 0x11; /* 2.5Gbps, 2.5Gbps */ switch (dev->dd->ipath_ibmtu) { case 4096: @@ -401,6 +401,7 @@ static int recv_subn_set_portinfo(struct ib_smp *smp, struct ib_port_info *pip = (struct ib_port_info *)smp->data; struct ib_event event; struct ipath_ibdev *dev; + struct ipath_devdata *dd; u32 flags; char clientrereg = 0; u16 lid, smlid; @@ -415,6 +416,7 @@ static int recv_subn_set_portinfo(struct ib_smp *smp, goto err; dev = to_idev(ibdev); + dd = dev->dd; event.device = ibdev; event.element.port_num = port; @@ -423,11 +425,12 @@ static int recv_subn_set_portinfo(struct ib_smp *smp, dev->mkey_lease_period = be16_to_cpu(pip->mkey_lease_period); lid = be16_to_cpu(pip->lid); - if (lid != dev->dd->ipath_lid) { + if (dd->ipath_lid != lid || + dd->ipath_lmc != (pip->mkeyprot_resv_lmc & 7)) { /* Must be a valid unicast LID address. */ if (lid == 0 || lid >= IPATH_MULTICAST_LID_BASE) goto err; - ipath_set_lid(dev->dd, lid, pip->mkeyprot_resv_lmc & 7); + ipath_set_lid(dd, lid, pip->mkeyprot_resv_lmc & 7); event.event = IB_EVENT_LID_CHANGE; ib_dispatch_event(&event); } @@ -461,18 +464,18 @@ static int recv_subn_set_portinfo(struct ib_smp *smp, case 0: /* NOP */ break; case 1: /* SLEEP */ - if (set_linkdowndefaultstate(dev->dd, 1)) + if (set_linkdowndefaultstate(dd, 1)) goto err; break; case 2: /* POLL */ - if (set_linkdowndefaultstate(dev->dd, 0)) + if (set_linkdowndefaultstate(dd, 0)) goto err; break; default: goto err; } - dev->mkeyprot_resv_lmc = pip->mkeyprot_resv_lmc; + dev->mkeyprot = pip->mkeyprot_resv_lmc >> 6; dev->vl_high_limit = pip->vl_high_limit; switch ((pip->neighbormtu_mastersmsl >> 4) & 0xF) { @@ -495,7 +498,7 @@ static int recv_subn_set_portinfo(struct ib_smp *smp, /* XXX We have already partially updated our state! */ goto err; } - ipath_set_mtu(dev->dd, mtu); + ipath_set_mtu(dd, mtu); dev->sm_sl = pip->neighbormtu_mastersmsl & 0xF; @@ -511,16 +514,16 @@ static int recv_subn_set_portinfo(struct ib_smp *smp, * later. */ if (pip->pkey_violations == 0) - dev->z_pkey_violations = ipath_get_cr_errpkey(dev->dd); + dev->z_pkey_violations = ipath_get_cr_errpkey(dd); if (pip->qkey_violations == 0) dev->qkey_violations = 0; ore = pip->localphyerrors_overrunerrors; - if (set_phyerrthreshold(dev->dd, (ore >> 4) & 0xF)) + if (set_phyerrthreshold(dd, (ore >> 4) & 0xF)) goto err; - if (set_overrunthreshold(dev->dd, (ore & 0xF))) + if (set_overrunthreshold(dd, (ore & 0xF))) goto err; dev->subnet_timeout = pip->clientrereg_resv_subnetto & 0x1F; @@ -538,7 +541,7 @@ static int recv_subn_set_portinfo(struct ib_smp *smp, * is down or is being set to down. */ state = pip->linkspeed_portstate & 0xF; - flags = dev->dd->ipath_flags; + flags = dd->ipath_flags; lstate = (pip->portphysstate_linkdown >> 4) & 0xF; if (lstate && !(state == IB_PORT_DOWN || state == IB_PORT_NOP)) goto err; @@ -554,7 +557,7 @@ static int recv_subn_set_portinfo(struct ib_smp *smp, /* FALLTHROUGH */ case IB_PORT_DOWN: if (lstate == 0) - if (get_linkdowndefaultstate(dev->dd)) + if (get_linkdowndefaultstate(dd)) lstate = IPATH_IB_LINKDOWN_SLEEP; else lstate = IPATH_IB_LINKDOWN; @@ -566,7 +569,7 @@ static int recv_subn_set_portinfo(struct ib_smp *smp, lstate = IPATH_IB_LINKDOWN_DISABLE; else goto err; - ipath_set_linkstate(dev->dd, lstate); + ipath_set_linkstate(dd, lstate); if (flags & IPATH_LINKACTIVE) { event.event = IB_EVENT_PORT_ERR; ib_dispatch_event(&event); @@ -575,7 +578,7 @@ static int recv_subn_set_portinfo(struct ib_smp *smp, case IB_PORT_ARMED: if (!(flags & (IPATH_LINKINIT | IPATH_LINKACTIVE))) break; - ipath_set_linkstate(dev->dd, IPATH_IB_LINKARM); + ipath_set_linkstate(dd, IPATH_IB_LINKARM); if (flags & IPATH_LINKACTIVE) { event.event = IB_EVENT_PORT_ERR; ib_dispatch_event(&event); @@ -584,7 +587,7 @@ static int recv_subn_set_portinfo(struct ib_smp *smp, case IB_PORT_ACTIVE: if (!(flags & IPATH_LINKARMED)) break; - ipath_set_linkstate(dev->dd, IPATH_IB_LINKACTIVE); + ipath_set_linkstate(dd, IPATH_IB_LINKACTIVE); event.event = IB_EVENT_PORT_ACTIVE; ib_dispatch_event(&event); break; @@ -1350,7 +1353,7 @@ static int process_subn(struct ib_device *ibdev, int mad_flags, if (dev->mkey_lease_timeout && jiffies >= dev->mkey_lease_timeout) { /* Clear timeout and mkey protection field. */ dev->mkey_lease_timeout = 0; - dev->mkeyprot_resv_lmc &= 0x3F; + dev->mkeyprot = 0; } /* @@ -1361,7 +1364,7 @@ static int process_subn(struct ib_device *ibdev, int mad_flags, dev->mkey != smp->mkey && (smp->method == IB_MGMT_METHOD_SET || (smp->method == IB_MGMT_METHOD_GET && - (dev->mkeyprot_resv_lmc >> 7) != 0))) { + dev->mkeyprot >= 2))) { if (dev->mkey_violations != 0xFFFF) ++dev->mkey_violations; if (dev->mkey_lease_timeout || diff --git a/drivers/infiniband/hw/ipath/ipath_ud.c b/drivers/infiniband/hw/ipath/ipath_ud.c index 34c4a0a5be3..16a2a938b52 100644 --- a/drivers/infiniband/hw/ipath/ipath_ud.c +++ b/drivers/infiniband/hw/ipath/ipath_ud.c @@ -236,10 +236,10 @@ static void ipath_ud_loopback(struct ipath_qp *sqp, struct ipath_swqe *swqe) wc.pkey_index = 0; wc.slid = dev->dd->ipath_lid | (ah_attr->src_path_bits & - ((1 << (dev->mkeyprot_resv_lmc & 7)) - 1)); + ((1 << dev->dd->ipath_lmc) - 1)); wc.sl = ah_attr->sl; wc.dlid_path_bits = - ah_attr->dlid & ((1 << (dev->mkeyprot_resv_lmc & 7)) - 1); + ah_attr->dlid & ((1 << dev->dd->ipath_lmc) - 1); wc.port_num = 1; /* Signal completion event if the solicited bit is set. */ ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, @@ -289,7 +289,7 @@ int ipath_make_ud_req(struct ipath_qp *qp) } else { dev->n_unicast_xmit++; lid = ah_attr->dlid & - ~((1 << (dev->mkeyprot_resv_lmc & 7)) - 1); + ~((1 << dev->dd->ipath_lmc) - 1); if (unlikely(lid == dev->dd->ipath_lid)) { ipath_ud_loopback(qp, wqe); goto done; @@ -341,7 +341,7 @@ int ipath_make_ud_req(struct ipath_qp *qp) lid = dev->dd->ipath_lid; if (lid) { lid |= ah_attr->src_path_bits & - ((1 << (dev->mkeyprot_resv_lmc & 7)) - 1); + ((1 << dev->dd->ipath_lmc) - 1); qp->s_hdr.lrh[3] = cpu_to_be16(lid); } else qp->s_hdr.lrh[3] = IB_LID_PERMISSIVE; @@ -551,7 +551,7 @@ void ipath_ud_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr, * Save the LMC lower bits if the destination LID is a unicast LID. */ wc.dlid_path_bits = dlid >= IPATH_MULTICAST_LID_BASE ? 0 : - dlid & ((1 << (dev->mkeyprot_resv_lmc & 7)) - 1); + dlid & ((1 << dev->dd->ipath_lmc) - 1); wc.port_num = 1; /* Signal completion event if the solicited bit is set. */ ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c index 495194bb84a..13aba3d4054 100644 --- a/drivers/infiniband/hw/ipath/ipath_verbs.c +++ b/drivers/infiniband/hw/ipath/ipath_verbs.c @@ -513,7 +513,7 @@ void ipath_ib_rcv(struct ipath_ibdev *dev, void *rhdr, void *data, /* Check for a valid destination LID (see ch. 7.11.1). */ lid = be16_to_cpu(hdr->lrh[1]); if (lid < IPATH_MULTICAST_LID_BASE) { - lid &= ~((1 << (dev->mkeyprot_resv_lmc & 7)) - 1); + lid &= ~((1 << dev->dd->ipath_lmc) - 1); if (unlikely(lid != dev->dd->ipath_lid)) { dev->rcv_errors++; goto bail; @@ -1152,7 +1152,7 @@ static int ipath_query_port(struct ib_device *ibdev, memset(props, 0, sizeof(*props)); props->lid = lid ? lid : __constant_be16_to_cpu(IB_LID_PERMISSIVE); - props->lmc = dev->mkeyprot_resv_lmc & 7; + props->lmc = dd->ipath_lmc; props->sm_lid = dev->sm_lid; props->sm_sl = dev->sm_sl; ibcstat = dd->ipath_lastibcstat; diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.h b/drivers/infiniband/hw/ipath/ipath_verbs.h index 9be9bf91f4f..6ccb54f104a 100644 --- a/drivers/infiniband/hw/ipath/ipath_verbs.h +++ b/drivers/infiniband/hw/ipath/ipath_verbs.h @@ -501,7 +501,7 @@ struct ipath_ibdev { int ib_unit; /* This is the device number */ u16 sm_lid; /* in host order */ u8 sm_sl; - u8 mkeyprot_resv_lmc; + u8 mkeyprot; /* non-zero when timer is set */ unsigned long mkey_lease_timeout; -- cgit v1.2.3-70-g09d2 From 70c51da2c4f84317bb13a2b564600afdcebd686f Mon Sep 17 00:00:00 2001 From: Arthur Jones Date: Fri, 14 Sep 2007 12:22:49 -0700 Subject: IB/ipath: Use counters in ipath_poll and cleanup interrupts in ipath_close ipath_poll() suffered from a couple subtle bugs. Under the right conditions we could leave recv interrupts enabled on an ipath user context on close, thereby taking potentially unwanted interrupts on the next open -- this is fixed by unconditionally turning off recv interrupts on close. Also, we now use counters rather than set/clear bits which allows us to make sure we catch all interrupts at the cost of changing the semantics slightly (it's now give me all events since the last time I called poll() rather than give me all events since I called _this_ poll routine). We also added some memory barriers which may help ensure we get all notifications in a timely manner. Signed-off-by: Arthur Jones Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_file_ops.c | 67 +++++++++++++++++----------- drivers/infiniband/hw/ipath/ipath_intr.c | 33 +++++--------- drivers/infiniband/hw/ipath/ipath_kernel.h | 8 +++- 3 files changed, 57 insertions(+), 51 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ipath/ipath_file_ops.c b/drivers/infiniband/hw/ipath/ipath_file_ops.c index 33ab0d6b80f..016e7c4e366 100644 --- a/drivers/infiniband/hw/ipath/ipath_file_ops.c +++ b/drivers/infiniband/hw/ipath/ipath_file_ops.c @@ -1341,6 +1341,19 @@ bail: return ret; } +static unsigned ipath_poll_hdrqfull(struct ipath_portdata *pd) +{ + unsigned pollflag = 0; + + if ((pd->poll_type & IPATH_POLL_TYPE_OVERFLOW) && + pd->port_hdrqfull != pd->port_hdrqfull_poll) { + pollflag |= POLLIN | POLLRDNORM; + pd->port_hdrqfull_poll = pd->port_hdrqfull; + } + + return pollflag; +} + static unsigned int ipath_poll_urgent(struct ipath_portdata *pd, struct file *fp, struct poll_table_struct *pt) @@ -1350,22 +1363,20 @@ static unsigned int ipath_poll_urgent(struct ipath_portdata *pd, dd = pd->port_dd; - if (test_bit(IPATH_PORT_WAITING_OVERFLOW, &pd->int_flag)) { - pollflag |= POLLERR; - clear_bit(IPATH_PORT_WAITING_OVERFLOW, &pd->int_flag); - } + /* variable access in ipath_poll_hdrqfull() needs this */ + rmb(); + pollflag = ipath_poll_hdrqfull(pd); - if (test_bit(IPATH_PORT_WAITING_URG, &pd->int_flag)) { + if (pd->port_urgent != pd->port_urgent_poll) { pollflag |= POLLIN | POLLRDNORM; - clear_bit(IPATH_PORT_WAITING_URG, &pd->int_flag); + pd->port_urgent_poll = pd->port_urgent; } if (!pollflag) { + /* this saves a spin_lock/unlock in interrupt handler... */ set_bit(IPATH_PORT_WAITING_URG, &pd->port_flag); - if (pd->poll_type & IPATH_POLL_TYPE_OVERFLOW) - set_bit(IPATH_PORT_WAITING_OVERFLOW, - &pd->port_flag); - + /* flush waiting flag so don't miss an event... */ + wmb(); poll_wait(fp, &pd->port_wait, pt); } @@ -1376,31 +1387,27 @@ static unsigned int ipath_poll_next(struct ipath_portdata *pd, struct file *fp, struct poll_table_struct *pt) { - u32 head, tail; + u32 head; + u32 tail; unsigned pollflag = 0; struct ipath_devdata *dd; dd = pd->port_dd; + /* variable access in ipath_poll_hdrqfull() needs this */ + rmb(); + pollflag = ipath_poll_hdrqfull(pd); + head = ipath_read_ureg32(dd, ur_rcvhdrhead, pd->port_port); tail = *(volatile u64 *)pd->port_rcvhdrtail_kvaddr; - if (test_bit(IPATH_PORT_WAITING_OVERFLOW, &pd->int_flag)) { - pollflag |= POLLERR; - clear_bit(IPATH_PORT_WAITING_OVERFLOW, &pd->int_flag); - } - - if (tail != head || - test_bit(IPATH_PORT_WAITING_RCV, &pd->int_flag)) { + if (head != tail) pollflag |= POLLIN | POLLRDNORM; - clear_bit(IPATH_PORT_WAITING_RCV, &pd->int_flag); - } - - if (!pollflag) { + else { + /* this saves a spin_lock/unlock in interrupt handler */ set_bit(IPATH_PORT_WAITING_RCV, &pd->port_flag); - if (pd->poll_type & IPATH_POLL_TYPE_OVERFLOW) - set_bit(IPATH_PORT_WAITING_OVERFLOW, - &pd->port_flag); + /* flush waiting flag so we don't miss an event */ + wmb(); set_bit(pd->port_port + INFINIPATH_R_INTRAVAIL_SHIFT, &dd->ipath_rcvctrl); @@ -1917,6 +1924,12 @@ static int ipath_do_user_init(struct file *fp, ipath_cdbg(VERBOSE, "Wrote port%d egrhead %x from tail regs\n", pd->port_port, head32); pd->port_tidcursor = 0; /* start at beginning after open */ + + /* initialize poll variables... */ + pd->port_urgent = 0; + pd->port_urgent_poll = 0; + pd->port_hdrqfull_poll = pd->port_hdrqfull; + /* * now enable the port; the tail registers will be written to memory * by the chip as soon as it sees the write to @@ -2039,9 +2052,11 @@ static int ipath_close(struct inode *in, struct file *fp) if (dd->ipath_kregbase) { int i; - /* atomically clear receive enable port. */ + /* atomically clear receive enable port and intr avail. */ clear_bit(INFINIPATH_R_PORTENABLE_SHIFT + port, &dd->ipath_rcvctrl); + clear_bit(pd->port_port + INFINIPATH_R_INTRAVAIL_SHIFT, + &dd->ipath_rcvctrl); ipath_write_kreg( dd, dd->ipath_kregs->kr_rcvctrl, dd->ipath_rcvctrl); /* and read back from chip to be sure that nothing diff --git a/drivers/infiniband/hw/ipath/ipath_intr.c b/drivers/infiniband/hw/ipath/ipath_intr.c index 11b361408ae..61eac8cc0d9 100644 --- a/drivers/infiniband/hw/ipath/ipath_intr.c +++ b/drivers/infiniband/hw/ipath/ipath_intr.c @@ -688,17 +688,9 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs) chkerrpkts = 1; dd->ipath_lastrcvhdrqtails[i] = tl; pd->port_hdrqfull++; - if (test_bit(IPATH_PORT_WAITING_OVERFLOW, - &pd->port_flag)) { - clear_bit( - IPATH_PORT_WAITING_OVERFLOW, - &pd->port_flag); - set_bit( - IPATH_PORT_WAITING_OVERFLOW, - &pd->int_flag); - wake_up_interruptible( - &pd->port_wait); - } + /* flush hdrqfull so that poll() sees it */ + wmb(); + wake_up_interruptible(&pd->port_wait); } } } @@ -960,6 +952,8 @@ static void handle_urcv(struct ipath_devdata *dd, u32 istat) int i; int rcvdint = 0; + /* test_bit below needs this... */ + rmb(); portr = ((istat >> INFINIPATH_I_RCVAVAIL_SHIFT) & dd->ipath_i_rcvavail_mask) | ((istat >> INFINIPATH_I_RCVURG_SHIFT) & @@ -967,22 +961,15 @@ static void handle_urcv(struct ipath_devdata *dd, u32 istat) for (i = 1; i < dd->ipath_cfgports; i++) { struct ipath_portdata *pd = dd->ipath_pd[i]; if (portr & (1 << i) && pd && pd->port_cnt) { - if (test_bit(IPATH_PORT_WAITING_RCV, - &pd->port_flag)) { - clear_bit(IPATH_PORT_WAITING_RCV, - &pd->port_flag); - set_bit(IPATH_PORT_WAITING_RCV, - &pd->int_flag); + if (test_and_clear_bit(IPATH_PORT_WAITING_RCV, + &pd->port_flag)) { clear_bit(i + INFINIPATH_R_INTRAVAIL_SHIFT, &dd->ipath_rcvctrl); wake_up_interruptible(&pd->port_wait); rcvdint = 1; - } else if (test_bit(IPATH_PORT_WAITING_URG, - &pd->port_flag)) { - clear_bit(IPATH_PORT_WAITING_URG, - &pd->port_flag); - set_bit(IPATH_PORT_WAITING_URG, - &pd->int_flag); + } else if (test_and_clear_bit(IPATH_PORT_WAITING_URG, + &pd->port_flag)) { + pd->port_urgent++; wake_up_interruptible(&pd->port_wait); } } diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h index d983f92b9bc..872fb36703d 100644 --- a/drivers/infiniband/hw/ipath/ipath_kernel.h +++ b/drivers/infiniband/hw/ipath/ipath_kernel.h @@ -139,6 +139,12 @@ struct ipath_portdata { u32 port_pionowait; /* total number of rcvhdrqfull errors */ u32 port_hdrqfull; + /* saved total number of rcvhdrqfull errors for poll edge trigger */ + u32 port_hdrqfull_poll; + /* total number of polled urgent packets */ + u32 port_urgent; + /* saved total number of polled urgent packets for poll edge trigger */ + u32 port_urgent_poll; /* pid of process using this port */ pid_t port_pid; /* same size as task_struct .comm[] */ @@ -757,8 +763,6 @@ int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv); #define IPATH_PORT_MASTER_UNINIT 4 /* waiting for an urgent packet to arrive */ #define IPATH_PORT_WAITING_URG 5 - /* waiting for a header overflow */ -#define IPATH_PORT_WAITING_OVERFLOW 6 /* free up any allocated data at closes */ void ipath_free_data(struct ipath_portdata *dd); -- cgit v1.2.3-70-g09d2 From 4bec0b9155d6757847b754e21b55ecafcecef839 Mon Sep 17 00:00:00 2001 From: Arthur Jones Date: Tue, 18 Sep 2007 14:24:23 -0700 Subject: IB/ipath: iba6110 rev4 no longer needs recv header overrun workaround iba6110 rev3 and earlier had a chip bug where the chip could overrun the recv header queue. rev4 fixed this chip bug so userspace no longer needs to workaround it. Now we only set the workaround flag for older chip versions. Signed-off-by: Arthur Jones Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_iba6110.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ipath/ipath_iba6110.c b/drivers/infiniband/hw/ipath/ipath_iba6110.c index e1c5998887e..d4940beb58c 100644 --- a/drivers/infiniband/hw/ipath/ipath_iba6110.c +++ b/drivers/infiniband/hw/ipath/ipath_iba6110.c @@ -1599,8 +1599,10 @@ static int ipath_ht_get_base_info(struct ipath_portdata *pd, void *kbase) { struct ipath_base_info *kinfo = kbase; - kinfo->spi_runtime_flags |= IPATH_RUNTIME_HT | - IPATH_RUNTIME_RCVHDR_COPY; + kinfo->spi_runtime_flags |= IPATH_RUNTIME_HT; + + if (pd->port_dd->ipath_minrev < 4) + kinfo->spi_runtime_flags |= IPATH_RUNTIME_RCVHDR_COPY; return 0; } -- cgit v1.2.3-70-g09d2 From 20bed343142bfaf08765e35aaefa56dc5cc287db Mon Sep 17 00:00:00 2001 From: Arthur Jones Date: Tue, 18 Sep 2007 14:44:45 -0700 Subject: IB/ipath: Indicate a couple of chip bugs to userspace A couple of chip bugs in the iba6110 and in the iba6120 are not in more recent chips. This first bug swaps two of the pioavail register locations. In the second bug, the chip can sometimes forget to dma the pio avail register to memory. We indicate the presence of these bugs with runtime flags and we indicate the presence of the flags by bumping the SWMINOR. Signed-off-by: Arthur Jones Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_common.h | 4 +++- drivers/infiniband/hw/ipath/ipath_iba6110.c | 3 ++- drivers/infiniband/hw/ipath/ipath_iba6120.c | 3 ++- 3 files changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ipath/ipath_common.h b/drivers/infiniband/hw/ipath/ipath_common.h index 6ad822c3593..851df8a75e7 100644 --- a/drivers/infiniband/hw/ipath/ipath_common.h +++ b/drivers/infiniband/hw/ipath/ipath_common.h @@ -189,6 +189,8 @@ typedef enum _ipath_ureg { #define IPATH_RUNTIME_RCVHDR_COPY 0x8 #define IPATH_RUNTIME_MASTER 0x10 /* 0x20 and 0x40 are no longer used, but are reserved for ABI compatibility */ +#define IPATH_RUNTIME_FORCE_PIOAVAIL 0x400 +#define IPATH_RUNTIME_PIO_REGSWAPPED 0x800 /* * This structure is returned by ipath_userinit() immediately after @@ -350,7 +352,7 @@ struct ipath_base_info { * may not be implemented; the user code must deal with this if it * cares, or it must abort after initialization reports the difference. */ -#define IPATH_USER_SWMINOR 5 +#define IPATH_USER_SWMINOR 6 #define IPATH_USER_SWVERSION ((IPATH_USER_SWMAJOR<<16) | IPATH_USER_SWMINOR) diff --git a/drivers/infiniband/hw/ipath/ipath_iba6110.c b/drivers/infiniband/hw/ipath/ipath_iba6110.c index d4940beb58c..df42a1e3b6b 100644 --- a/drivers/infiniband/hw/ipath/ipath_iba6110.c +++ b/drivers/infiniband/hw/ipath/ipath_iba6110.c @@ -1599,7 +1599,8 @@ static int ipath_ht_get_base_info(struct ipath_portdata *pd, void *kbase) { struct ipath_base_info *kinfo = kbase; - kinfo->spi_runtime_flags |= IPATH_RUNTIME_HT; + kinfo->spi_runtime_flags |= IPATH_RUNTIME_HT | + IPATH_RUNTIME_PIO_REGSWAPPED; if (pd->port_dd->ipath_minrev < 4) kinfo->spi_runtime_flags |= IPATH_RUNTIME_RCVHDR_COPY; diff --git a/drivers/infiniband/hw/ipath/ipath_iba6120.c b/drivers/infiniband/hw/ipath/ipath_iba6120.c index d43f0b3a43f..0103d6f4847 100644 --- a/drivers/infiniband/hw/ipath/ipath_iba6120.c +++ b/drivers/infiniband/hw/ipath/ipath_iba6120.c @@ -1348,7 +1348,8 @@ static int ipath_pe_get_base_info(struct ipath_portdata *pd, void *kbase) dd = pd->port_dd; done: - kinfo->spi_runtime_flags |= IPATH_RUNTIME_PCIE; + kinfo->spi_runtime_flags |= IPATH_RUNTIME_PCIE | + IPATH_RUNTIME_FORCE_PIOAVAIL | IPATH_RUNTIME_PIO_REGSWAPPED; return 0; } -- cgit v1.2.3-70-g09d2 From aa7c79abd154ed9aba4c19b861d439ef6af35d3a Mon Sep 17 00:00:00 2001 From: Dave Olson Date: Thu, 16 Aug 2007 18:10:43 -0700 Subject: IB/ipath: Fix QHT7040 serial number check Remove all the OEM and bringup boards, and complain and fail initialization if one is found. QHT7040 with GPIO rework (128ywwuuuu) is OK, older 112ywwuuuu is no longer supported). The check that had been added was failing both the 112 and 128 series. Signed-off-by: Dave Olson Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_iba6110.c | 44 ++++++++++------------------- 1 file changed, 15 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ipath/ipath_iba6110.c b/drivers/infiniband/hw/ipath/ipath_iba6110.c index df42a1e3b6b..ddbebe4bdb2 100644 --- a/drivers/infiniband/hw/ipath/ipath_iba6110.c +++ b/drivers/infiniband/hw/ipath/ipath_iba6110.c @@ -631,56 +631,35 @@ static int ipath_ht_boardname(struct ipath_devdata *dd, char *name, { char *n = NULL; u8 boardrev = dd->ipath_boardrev; - int ret; + int ret = 0; switch (boardrev) { - case 4: /* Ponderosa is one of the bringup boards */ - n = "Ponderosa"; - break; case 5: /* * original production board; two production levels, with * different serial number ranges. See ipath_ht_early_init() for * case where we enable IPATH_GPIO_INTR for later serial # range. + * Original 112* serial number is no longer supported. */ n = "InfiniPath_QHT7040"; break; - case 6: - n = "OEM_Board_3"; - break; case 7: /* small form factor production board */ n = "InfiniPath_QHT7140"; break; - case 8: - n = "LS/X-1"; - break; - case 9: /* Comstock bringup test board */ - n = "Comstock"; - break; - case 10: - n = "OEM_Board_2"; - break; - case 11: - n = "InfiniPath_HT-470"; /* obsoleted */ - break; - case 12: - n = "OEM_Board_4"; - break; default: /* don't know, just print the number */ ipath_dev_err(dd, "Don't yet know about board " "with ID %u\n", boardrev); snprintf(name, namelen, "Unknown_InfiniPath_QHT7xxx_%u", boardrev); + ret = 1; break; } if (n) snprintf(name, namelen, "%s", n); - if (dd->ipath_boardrev != 6 && dd->ipath_boardrev != 7 && - dd->ipath_boardrev != 11) { + if (ret) { ipath_dev_err(dd, "Unsupported InfiniPath board %s!\n", name); - ret = 1; goto bail; } if (dd->ipath_majrev != 3 || (dd->ipath_minrev < 2 || @@ -1554,10 +1533,17 @@ static int ipath_ht_early_init(struct ipath_devdata *dd) * can use GPIO interrupts. They have serial #'s starting * with 128, rather than 112. */ - dd->ipath_flags |= IPATH_GPIO_INTR; - } else - ipath_dev_err(dd, "Unsupported InfiniPath serial " - "number %.16s!\n", dd->ipath_serial); + if (dd->ipath_serial[0] == '1' && + dd->ipath_serial[1] == '2' && + dd->ipath_serial[2] == '8') + dd->ipath_flags |= IPATH_GPIO_INTR; + else { + ipath_dev_err(dd, "Unsupported InfiniPath board " + "(serial number %.16s)!\n", + dd->ipath_serial); + return 1; + } + } if (dd->ipath_minrev >= 4) { /* Rev4+ reports extra errors via internal GPIO pins */ -- cgit v1.2.3-70-g09d2 From 192594d5230f447ef2df8de9d7902ac90d11c118 Mon Sep 17 00:00:00 2001 From: Michael Albaugh Date: Tue, 2 Oct 2007 13:26:45 -0700 Subject: IB/ipath: Maintain active time on all chips There is a count of "active hours" maintained in EEPROM, to aid troubleshooting. The definition of "active" is based on traffic exceeding a threshold in any given 5-second polling interval. As originally written, the check was inadvertently bypassed for chips whose counters were 64-bits wide, and only applied to chips with 32-bit wide counters. This patch moves the test for amount of traffic "out" to a more common location, rather than depending on a side-effect of the software emulation of 64-bit counts on chips whose hardware is only 32-bits wide. Signed-off-by: Michael Albaugh Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_stats.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ipath/ipath_stats.c b/drivers/infiniband/hw/ipath/ipath_stats.c index bae4f56f727..f0271415cd5 100644 --- a/drivers/infiniband/hw/ipath/ipath_stats.c +++ b/drivers/infiniband/hw/ipath/ipath_stats.c @@ -55,7 +55,6 @@ u64 ipath_snap_cntr(struct ipath_devdata *dd, ipath_creg creg) u64 val64; unsigned long t0, t1; u64 ret; - unsigned long flags; t0 = jiffies; /* If fast increment counters are only 32 bits, snapshot them, @@ -92,18 +91,12 @@ u64 ipath_snap_cntr(struct ipath_devdata *dd, ipath_creg creg) if (creg == dd->ipath_cregs->cr_wordsendcnt) { if (val != dd->ipath_lastsword) { dd->ipath_sword += val - dd->ipath_lastsword; - spin_lock_irqsave(&dd->ipath_eep_st_lock, flags); - dd->ipath_traffic_wds += val - dd->ipath_lastsword; - spin_unlock_irqrestore(&dd->ipath_eep_st_lock, flags); dd->ipath_lastsword = val; } val64 = dd->ipath_sword; } else if (creg == dd->ipath_cregs->cr_wordrcvcnt) { if (val != dd->ipath_lastrword) { dd->ipath_rword += val - dd->ipath_lastrword; - spin_lock_irqsave(&dd->ipath_eep_st_lock, flags); - dd->ipath_traffic_wds += val - dd->ipath_lastrword; - spin_unlock_irqrestore(&dd->ipath_eep_st_lock, flags); dd->ipath_lastrword = val; } val64 = dd->ipath_rword; @@ -247,6 +240,7 @@ void ipath_get_faststats(unsigned long opaque) u32 val; static unsigned cnt; unsigned long flags; + u64 traffic_wds; /* * don't access the chip while running diags, or memory diags can @@ -262,12 +256,13 @@ void ipath_get_faststats(unsigned long opaque) * exceeding a threshold, so we need to check the word-counts * even if they are 64-bit. */ - ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordsendcnt); - ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordrcvcnt); + traffic_wds = ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordsendcnt) + + ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordrcvcnt); spin_lock_irqsave(&dd->ipath_eep_st_lock, flags); - if (dd->ipath_traffic_wds >= IPATH_TRAFFIC_ACTIVE_THRESHOLD) + traffic_wds -= dd->ipath_traffic_wds; + dd->ipath_traffic_wds += traffic_wds; + if (traffic_wds >= IPATH_TRAFFIC_ACTIVE_THRESHOLD) atomic_add(5, &dd->ipath_active_time); /* S/B #define */ - dd->ipath_traffic_wds = 0; spin_unlock_irqrestore(&dd->ipath_eep_st_lock, flags); if (dd->ipath_flags & IPATH_32BITCOUNTERS) { -- cgit v1.2.3-70-g09d2 From 6a733cdc71b7aa8107caa57f2a16629aa731242a Mon Sep 17 00:00:00 2001 From: Michael Albaugh Date: Wed, 3 Oct 2007 10:47:38 -0700 Subject: IB/ipath: Better handling of unexpected GPIO interrupts The General Purpose I/O pins can be configured to cause interrupts. At the end of the interrupt code dealing with all known causes, a message is output if any bits remain un-handled. Since this is a "can't happen" scenario, it should only be triggered by bugs elsewhere. It is harmless, and potentially beneficial, to limit the damage by masking any such unexpected interrupts. This patch adds disabling of interrupts from any pins that should not have been allowed to interrupt, in addition to emitting a message. Signed-off-by: Michael Albaugh Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_intr.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ipath/ipath_intr.c b/drivers/infiniband/hw/ipath/ipath_intr.c index 61eac8cc0d9..801a20d06de 100644 --- a/drivers/infiniband/hw/ipath/ipath_intr.c +++ b/drivers/infiniband/hw/ipath/ipath_intr.c @@ -1124,10 +1124,8 @@ irqreturn_t ipath_intr(int irq, void *data) /* * Some unexpected bits remain. If they could have * caused the interrupt, complain and clear. - * MEA: this is almost certainly non-ideal. - * we should look into auto-disable of unexpected - * GPIO interrupts, possibly on a "three strikes" - * basis. + * To avoid repetition of this condition, also clear + * the mask. It is almost certainly due to error. */ const u32 mask = (u32) dd->ipath_gpio_mask; @@ -1135,6 +1133,10 @@ irqreturn_t ipath_intr(int irq, void *data) ipath_dbg("Unexpected GPIO IRQ bits %x\n", gpiostatus & mask); to_clear |= (gpiostatus & mask); + dd->ipath_gpio_mask &= ~(gpiostatus & mask); + ipath_write_kreg(dd, + dd->ipath_kregs->kr_gpio_mask, + dd->ipath_gpio_mask); } } if (to_clear) { -- cgit v1.2.3-70-g09d2 From 49739b3e24a10d819d3167a1c5b319d0b1186245 Mon Sep 17 00:00:00 2001 From: Ralph Campbell Date: Wed, 19 Sep 2007 16:47:31 -0700 Subject: IB/ipath: Fix IB_EVENT_PORT_ERR event The link state event calls were being generated when the SM told the SMA to change link states. This works for IB_EVENT_PORT_ACTIVE but not if the link goes down and stays down. The fix is to generate event calls from the interrupt handler when the HW link state changes. Signed-off-by: Ralph Campbell Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_driver.c | 2 ++ drivers/infiniband/hw/ipath/ipath_intr.c | 17 +++++++++++++++++ drivers/infiniband/hw/ipath/ipath_kernel.h | 2 ++ drivers/infiniband/hw/ipath/ipath_mad.c | 10 ---------- drivers/infiniband/hw/ipath/ipath_verbs.c | 12 ++++++++++-- 5 files changed, 31 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c index 44784d049b7..1f152ded1e3 100644 --- a/drivers/infiniband/hw/ipath/ipath_driver.c +++ b/drivers/infiniband/hw/ipath/ipath_driver.c @@ -2086,6 +2086,8 @@ void ipath_shutdown_device(struct ipath_devdata *dd) INFINIPATH_IBCC_LINKINITCMD_SHIFT); ipath_cancel_sends(dd, 0); + signal_ib_event(dd, IB_EVENT_PORT_ERR); + /* disable IBC */ dd->ipath_control &= ~INFINIPATH_C_LINKENABLE; ipath_write_kreg(dd, dd->ipath_kregs->kr_control, diff --git a/drivers/infiniband/hw/ipath/ipath_intr.c b/drivers/infiniband/hw/ipath/ipath_intr.c index 801a20d06de..6a5dd5cd773 100644 --- a/drivers/infiniband/hw/ipath/ipath_intr.c +++ b/drivers/infiniband/hw/ipath/ipath_intr.c @@ -275,6 +275,16 @@ static char *ib_linkstate(u32 linkstate) return ret; } +void signal_ib_event(struct ipath_devdata *dd, enum ib_event_type ev) +{ + struct ib_event event; + + event.device = &dd->verbs_dev->ibdev; + event.element.port_num = 1; + event.event = ev; + ib_dispatch_event(&event); +} + static void handle_e_ibstatuschanged(struct ipath_devdata *dd, ipath_err_t errs, int noprint) { @@ -373,6 +383,8 @@ static void handle_e_ibstatuschanged(struct ipath_devdata *dd, dd->ipath_ibpollcnt = 0; /* some state other than 2 or 3 */ ipath_stats.sps_iblink++; if (ltstate != INFINIPATH_IBCS_LT_STATE_LINKUP) { + if (dd->ipath_flags & IPATH_LINKACTIVE) + signal_ib_event(dd, IB_EVENT_PORT_ERR); dd->ipath_flags |= IPATH_LINKDOWN; dd->ipath_flags &= ~(IPATH_LINKUNK | IPATH_LINKINIT | IPATH_LINKACTIVE | @@ -405,7 +417,10 @@ static void handle_e_ibstatuschanged(struct ipath_devdata *dd, *dd->ipath_statusp |= IPATH_STATUS_IB_READY | IPATH_STATUS_IB_CONF; dd->ipath_f_setextled(dd, lstate, ltstate); + signal_ib_event(dd, IB_EVENT_PORT_ACTIVE); } else if ((val & IPATH_IBSTATE_MASK) == IPATH_IBSTATE_INIT) { + if (dd->ipath_flags & IPATH_LINKACTIVE) + signal_ib_event(dd, IB_EVENT_PORT_ERR); /* * set INIT and DOWN. Down is checked by most of the other * code, but INIT is useful to know in a few places. @@ -418,6 +433,8 @@ static void handle_e_ibstatuschanged(struct ipath_devdata *dd, | IPATH_STATUS_IB_READY); dd->ipath_f_setextled(dd, lstate, ltstate); } else if ((val & IPATH_IBSTATE_MASK) == IPATH_IBSTATE_ARM) { + if (dd->ipath_flags & IPATH_LINKACTIVE) + signal_ib_event(dd, IB_EVENT_PORT_ERR); dd->ipath_flags |= IPATH_LINKARMED; dd->ipath_flags &= ~(IPATH_LINKUNK | IPATH_LINKDOWN | IPATH_LINKINIT | diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h index 872fb36703d..8786dd7922e 100644 --- a/drivers/infiniband/hw/ipath/ipath_kernel.h +++ b/drivers/infiniband/hw/ipath/ipath_kernel.h @@ -42,6 +42,7 @@ #include #include #include +#include #include "ipath_common.h" #include "ipath_debug.h" @@ -775,6 +776,7 @@ void ipath_get_eeprom_info(struct ipath_devdata *); int ipath_update_eeprom_log(struct ipath_devdata *dd); void ipath_inc_eeprom_err(struct ipath_devdata *dd, u32 eidx, u32 incr); u64 ipath_snap_cntr(struct ipath_devdata *, ipath_creg); +void signal_ib_event(struct ipath_devdata *dd, enum ib_event_type ev); /* * Set LED override, only the two LSBs have "public" meaning, but diff --git a/drivers/infiniband/hw/ipath/ipath_mad.c b/drivers/infiniband/hw/ipath/ipath_mad.c index 8f152167208..0ae3a7c3f86 100644 --- a/drivers/infiniband/hw/ipath/ipath_mad.c +++ b/drivers/infiniband/hw/ipath/ipath_mad.c @@ -570,26 +570,16 @@ static int recv_subn_set_portinfo(struct ib_smp *smp, else goto err; ipath_set_linkstate(dd, lstate); - if (flags & IPATH_LINKACTIVE) { - event.event = IB_EVENT_PORT_ERR; - ib_dispatch_event(&event); - } break; case IB_PORT_ARMED: if (!(flags & (IPATH_LINKINIT | IPATH_LINKACTIVE))) break; ipath_set_linkstate(dd, IPATH_IB_LINKARM); - if (flags & IPATH_LINKACTIVE) { - event.event = IB_EVENT_PORT_ERR; - ib_dispatch_event(&event); - } break; case IB_PORT_ACTIVE: if (!(flags & IPATH_LINKARMED)) break; ipath_set_linkstate(dd, IPATH_IB_LINKACTIVE); - event.event = IB_EVENT_PORT_ACTIVE; - ib_dispatch_event(&event); break; default: /* XXX We have already partially updated our state! */ diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c index 13aba3d4054..74f77e7c2c1 100644 --- a/drivers/infiniband/hw/ipath/ipath_verbs.c +++ b/drivers/infiniband/hw/ipath/ipath_verbs.c @@ -948,6 +948,7 @@ bail: int ipath_verbs_send(struct ipath_qp *qp, struct ipath_ib_header *hdr, u32 hdrwords, struct ipath_sge_state *ss, u32 len) { + struct ipath_devdata *dd = to_idev(qp->ibqp.device)->dd; u32 plen; int ret; u32 dwords = (len + 3) >> 2; @@ -955,8 +956,15 @@ int ipath_verbs_send(struct ipath_qp *qp, struct ipath_ib_header *hdr, /* +1 is for the qword padding of pbc */ plen = hdrwords + dwords + 1; - ret = ipath_verbs_send_pio(qp, (u32 *) hdr, hdrwords, - ss, len, plen, dwords); + /* Drop non-VL15 packets if we are not in the active state */ + if (!(dd->ipath_flags & IPATH_LINKACTIVE) && + qp->ibqp.qp_type != IB_QPT_SMI) { + if (qp->s_wqe) + ipath_send_complete(qp, qp->s_wqe, IB_WC_SUCCESS); + ret = 0; + } else + ret = ipath_verbs_send_pio(qp, (u32 *) hdr, hdrwords, + ss, len, plen, dwords); return ret; } -- cgit v1.2.3-70-g09d2 From bda94e32b39c0e60d43b34a175363601b6f12ca4 Mon Sep 17 00:00:00 2001 From: Ralph Campbell Date: Fri, 5 Oct 2007 16:03:21 -0700 Subject: IB/ipath: Remove redundant link state checks This patch removes some redundant checks when the SMA changes the link state since the same checks are made in the lower level function that sets the state. Signed-off-by: Ralph Campbell Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_mad.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ipath/ipath_mad.c b/drivers/infiniband/hw/ipath/ipath_mad.c index 0ae3a7c3f86..3d1432d1e3f 100644 --- a/drivers/infiniband/hw/ipath/ipath_mad.c +++ b/drivers/infiniband/hw/ipath/ipath_mad.c @@ -402,7 +402,6 @@ static int recv_subn_set_portinfo(struct ib_smp *smp, struct ib_event event; struct ipath_ibdev *dev; struct ipath_devdata *dd; - u32 flags; char clientrereg = 0; u16 lid, smlid; u8 lwe; @@ -541,7 +540,6 @@ static int recv_subn_set_portinfo(struct ib_smp *smp, * is down or is being set to down. */ state = pip->linkspeed_portstate & 0xF; - flags = dd->ipath_flags; lstate = (pip->portphysstate_linkdown >> 4) & 0xF; if (lstate && !(state == IB_PORT_DOWN || state == IB_PORT_NOP)) goto err; @@ -572,13 +570,9 @@ static int recv_subn_set_portinfo(struct ib_smp *smp, ipath_set_linkstate(dd, lstate); break; case IB_PORT_ARMED: - if (!(flags & (IPATH_LINKINIT | IPATH_LINKACTIVE))) - break; ipath_set_linkstate(dd, IPATH_IB_LINKARM); break; case IB_PORT_ACTIVE: - if (!(flags & IPATH_LINKARMED)) - break; ipath_set_linkstate(dd, IPATH_IB_LINKACTIVE); break; default: -- cgit v1.2.3-70-g09d2 From 3ac8c70f74ca67111c570f4ba828cc4b6fc229f4 Mon Sep 17 00:00:00 2001 From: Dave Olson Date: Wed, 3 Oct 2007 12:47:00 -0700 Subject: IB/ipath: Minor fix to ordering of freeing and zeroing of tid pages. Fixed to be the same as everywhere else. copy and then zero the page * in the array first, and then pass the copy to the VM routines. Signed-off-by: Dave Olson Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_file_ops.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ipath/ipath_file_ops.c b/drivers/infiniband/hw/ipath/ipath_file_ops.c index 016e7c4e366..5de3243a47c 100644 --- a/drivers/infiniband/hw/ipath/ipath_file_ops.c +++ b/drivers/infiniband/hw/ipath/ipath_file_ops.c @@ -538,6 +538,9 @@ static int ipath_tid_free(struct ipath_portdata *pd, unsigned subport, continue; cnt++; if (dd->ipath_pageshadow[porttid + tid]) { + struct page *p; + p = dd->ipath_pageshadow[porttid + tid]; + dd->ipath_pageshadow[porttid + tid] = NULL; ipath_cdbg(VERBOSE, "PID %u freeing TID %u\n", pd->port_pid, tid); dd->ipath_f_put_tid(dd, &tidbase[tid], @@ -546,9 +549,7 @@ static int ipath_tid_free(struct ipath_portdata *pd, unsigned subport, pci_unmap_page(dd->pcidev, dd->ipath_physshadow[porttid + tid], PAGE_SIZE, PCI_DMA_FROMDEVICE); - ipath_release_user_pages( - &dd->ipath_pageshadow[porttid + tid], 1); - dd->ipath_pageshadow[porttid + tid] = NULL; + ipath_release_user_pages(&p, 1); ipath_stats.sps_pageunlocks++; } else ipath_dbg("Unused tid %u, ignoring\n", tid); -- cgit v1.2.3-70-g09d2 From 5705f7021748a69d84d6567e68e8851dab551464 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 25 Sep 2007 12:35:59 +0200 Subject: Introduce rq_for_each_segment replacing rq_for_each_bio Every usage of rq_for_each_bio wraps a usage of bio_for_each_segment, so these can be combined into rq_for_each_segment. We define "struct req_iterator" to hold the 'bio' and 'index' that are needed for the double iteration. Signed-off-by: Neil Brown Various compile fixes by me... Signed-off-by: Jens Axboe --- Documentation/block/biodoc.txt | 20 +++++------ block/ll_rw_blk.c | 19 ++++------ drivers/block/floppy.c | 81 ++++++++++++++++++++---------------------- drivers/block/lguest_blk.c | 10 +++--- drivers/block/nbd.c | 22 +++++------- drivers/block/ps3disk.c | 31 ++++++++-------- drivers/block/xen-blkfront.c | 7 ++-- drivers/ide/ide-floppy.c | 16 ++++----- drivers/s390/block/dasd_diag.c | 11 ++---- drivers/s390/block/dasd_eckd.c | 15 ++++---- drivers/s390/block/dasd_fba.c | 15 ++++---- drivers/s390/char/tape_34xx.c | 15 +++----- drivers/s390/char/tape_3590.c | 16 ++++----- include/linux/blkdev.h | 15 +++++++- 14 files changed, 131 insertions(+), 162 deletions(-) (limited to 'drivers') diff --git a/Documentation/block/biodoc.txt b/Documentation/block/biodoc.txt index 8af392fc6ef..dc3f49e3e53 100644 --- a/Documentation/block/biodoc.txt +++ b/Documentation/block/biodoc.txt @@ -477,9 +477,9 @@ With this multipage bio design: the same bi_io_vec array, but with the index and size accordingly modified) - A linked list of bios is used as before for unrelated merges (*) - this avoids reallocs and makes independent completions easier to handle. -- Code that traverses the req list needs to make a distinction between - segments of a request (bio_for_each_segment) and the distinct completion - units/bios (rq_for_each_bio). +- Code that traverses the req list can find all the segments of a bio + by using rq_for_each_segment. This handles the fact that a request + has multiple bios, each of which can have multiple segments. - Drivers which can't process a large bio in one shot can use the bi_idx field to keep track of the next bio_vec entry to process. (e.g a 1MB bio_vec needs to be handled in max 128kB chunks for IDE) @@ -664,14 +664,14 @@ in lvm or md. 3.2.1 Traversing segments and completion units in a request -The macros bio_for_each_segment() and rq_for_each_bio() should be used for -traversing the bios in the request list (drivers should avoid directly -trying to do it themselves). Using these helpers should also make it easier -to cope with block changes in the future. +The macro rq_for_each_segment() should be used for traversing the bios +in the request list (drivers should avoid directly trying to do it +themselves). Using these helpers should also make it easier to cope +with block changes in the future. - rq_for_each_bio(bio, rq) - bio_for_each_segment(bio_vec, bio, i) - /* bio_vec is now current segment */ + struct req_iterator iter; + rq_for_each_segment(bio_vec, rq, iter) + /* bio_vec is now current segment */ I/O completion callbacks are per-bio rather than per-segment, so drivers that traverse bio chains on completion need to keep that in mind. Drivers diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index e35119a72a4..094c0fa5c40 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -1244,8 +1244,7 @@ static void blk_recalc_rq_segments(struct request *rq) int seg_size; int hw_seg_size; int cluster; - struct bio *bio; - int i; + struct req_iterator iter; int high, highprv = 1; struct request_queue *q = rq->q; @@ -1255,8 +1254,7 @@ static void blk_recalc_rq_segments(struct request *rq) cluster = q->queue_flags & (1 << QUEUE_FLAG_CLUSTER); hw_seg_size = seg_size = 0; phys_size = hw_size = nr_phys_segs = nr_hw_segs = 0; - rq_for_each_bio(bio, rq) - bio_for_each_segment(bv, bio, i) { + rq_for_each_segment(bv, rq, iter) { /* * the trick here is making sure that a high page is never * considered part of another segment, since that might @@ -1353,8 +1351,8 @@ int blk_rq_map_sg(struct request_queue *q, struct request *rq, struct scatterlist *sg) { struct bio_vec *bvec, *bvprv; - struct bio *bio; - int nsegs, i, cluster; + struct req_iterator iter; + int nsegs, cluster; nsegs = 0; cluster = q->queue_flags & (1 << QUEUE_FLAG_CLUSTER); @@ -1363,11 +1361,7 @@ int blk_rq_map_sg(struct request_queue *q, struct request *rq, * for each bio in rq */ bvprv = NULL; - rq_for_each_bio(bio, rq) { - /* - * for each segment in bio - */ - bio_for_each_segment(bvec, bio, i) { + rq_for_each_segment(bvec, rq, iter) { int nbytes = bvec->bv_len; if (bvprv && cluster) { @@ -1390,8 +1384,7 @@ new_segment: nsegs++; } bvprv = bvec; - } /* segments in bio */ - } /* bios in rq */ + } /* segments in rq */ return nsegs; } diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 085b7794fb3..f0a86e201b4 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -2437,22 +2437,19 @@ static void rw_interrupt(void) /* Compute maximal contiguous buffer size. */ static int buffer_chain_size(void) { - struct bio *bio; struct bio_vec *bv; - int size, i; + int size; + struct req_iterator iter; char *base; base = bio_data(current_req->bio); size = 0; - rq_for_each_bio(bio, current_req) { - bio_for_each_segment(bv, bio, i) { - if (page_address(bv->bv_page) + bv->bv_offset != - base + size) - break; + rq_for_each_segment(bv, current_req, iter) { + if (page_address(bv->bv_page) + bv->bv_offset != base + size) + break; - size += bv->bv_len; - } + size += bv->bv_len; } return size >> 9; @@ -2479,9 +2476,9 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2) { int remaining; /* number of transferred 512-byte sectors */ struct bio_vec *bv; - struct bio *bio; char *buffer, *dma_buffer; - int size, i; + int size; + struct req_iterator iter; max_sector = transfer_size(ssize, min(max_sector, max_sector_2), @@ -2514,43 +2511,41 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2) size = current_req->current_nr_sectors << 9; - rq_for_each_bio(bio, current_req) { - bio_for_each_segment(bv, bio, i) { - if (!remaining) - break; + rq_for_each_segment(bv, current_req, iter) { + if (!remaining) + break; - size = bv->bv_len; - SUPBOUND(size, remaining); + size = bv->bv_len; + SUPBOUND(size, remaining); - buffer = page_address(bv->bv_page) + bv->bv_offset; + buffer = page_address(bv->bv_page) + bv->bv_offset; #ifdef FLOPPY_SANITY_CHECK - if (dma_buffer + size > - floppy_track_buffer + (max_buffer_sectors << 10) || - dma_buffer < floppy_track_buffer) { - DPRINT("buffer overrun in copy buffer %d\n", - (int)((floppy_track_buffer - - dma_buffer) >> 9)); - printk("fsector_t=%d buffer_min=%d\n", - fsector_t, buffer_min); - printk("current_count_sectors=%ld\n", - current_count_sectors); - if (CT(COMMAND) == FD_READ) - printk("read\n"); - if (CT(COMMAND) == FD_WRITE) - printk("write\n"); - break; - } - if (((unsigned long)buffer) % 512) - DPRINT("%p buffer not aligned\n", buffer); -#endif + if (dma_buffer + size > + floppy_track_buffer + (max_buffer_sectors << 10) || + dma_buffer < floppy_track_buffer) { + DPRINT("buffer overrun in copy buffer %d\n", + (int)((floppy_track_buffer - + dma_buffer) >> 9)); + printk("fsector_t=%d buffer_min=%d\n", + fsector_t, buffer_min); + printk("current_count_sectors=%ld\n", + current_count_sectors); if (CT(COMMAND) == FD_READ) - memcpy(buffer, dma_buffer, size); - else - memcpy(dma_buffer, buffer, size); - - remaining -= size; - dma_buffer += size; + printk("read\n"); + if (CT(COMMAND) == FD_WRITE) + printk("write\n"); + break; } + if (((unsigned long)buffer) % 512) + DPRINT("%p buffer not aligned\n", buffer); +#endif + if (CT(COMMAND) == FD_READ) + memcpy(buffer, dma_buffer, size); + else + memcpy(dma_buffer, buffer, size); + + remaining -= size; + dma_buffer += size; } #ifdef FLOPPY_SANITY_CHECK if (remaining) { diff --git a/drivers/block/lguest_blk.c b/drivers/block/lguest_blk.c index 160cf14431a..1e838ae60a6 100644 --- a/drivers/block/lguest_blk.c +++ b/drivers/block/lguest_blk.c @@ -142,12 +142,11 @@ static irqreturn_t lgb_irq(int irq, void *_bd) * return the total length. */ static unsigned int req_to_dma(struct request *req, struct lguest_dma *dma) { - unsigned int i = 0, idx, len = 0; - struct bio *bio; + unsigned int i = 0, len = 0; + struct req_iterator iter; + struct bio_vec *bvec; - rq_for_each_bio(bio, req) { - struct bio_vec *bvec; - bio_for_each_segment(bvec, bio, idx) { + rq_for_each_segment(bvec, req, iter) { /* We told the block layer not to give us too many. */ BUG_ON(i == LGUEST_MAX_DMA_SECTIONS); /* If we had a zero-length segment, it would look like @@ -160,7 +159,6 @@ static unsigned int req_to_dma(struct request *req, struct lguest_dma *dma) dma->len[i] = bvec->bv_len; len += bvec->bv_len; i++; - } } /* If the array isn't full, we mark the end with a 0 length */ if (i < LGUEST_MAX_DMA_SECTIONS) diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index be92c658f06..228b2ff577a 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -180,7 +180,7 @@ static inline int sock_send_bvec(struct socket *sock, struct bio_vec *bvec, static int nbd_send_req(struct nbd_device *lo, struct request *req) { - int result, i, flags; + int result, flags; struct nbd_request request; unsigned long size = req->nr_sectors << 9; struct socket *sock = lo->sock; @@ -205,16 +205,15 @@ static int nbd_send_req(struct nbd_device *lo, struct request *req) } if (nbd_cmd(req) == NBD_CMD_WRITE) { - struct bio *bio; + struct req_iterator iter; + struct bio_vec *bvec; /* * we are really probing at internals to determine * whether to set MSG_MORE or not... */ - rq_for_each_bio(bio, req) { - struct bio_vec *bvec; - bio_for_each_segment(bvec, bio, i) { + rq_for_each_segment(bvec, req, iter) { flags = 0; - if ((i < (bio->bi_vcnt - 1)) || bio->bi_next) + if (!rq_iter_last(req, iter)) flags = MSG_MORE; dprintk(DBG_TX, "%s: request %p: sending %d bytes data\n", lo->disk->disk_name, req, @@ -226,7 +225,6 @@ static int nbd_send_req(struct nbd_device *lo, struct request *req) result); goto error_out; } - } } } return 0; @@ -321,11 +319,10 @@ static struct request *nbd_read_stat(struct nbd_device *lo) dprintk(DBG_RX, "%s: request %p: got reply\n", lo->disk->disk_name, req); if (nbd_cmd(req) == NBD_CMD_READ) { - int i; - struct bio *bio; - rq_for_each_bio(bio, req) { - struct bio_vec *bvec; - bio_for_each_segment(bvec, bio, i) { + struct req_iterator iter; + struct bio_vec *bvec; + + rq_for_each_segment(bvec, req, iter) { result = sock_recv_bvec(sock, bvec); if (result <= 0) { printk(KERN_ERR "%s: Receive data failed (result %d)\n", @@ -336,7 +333,6 @@ static struct request *nbd_read_stat(struct nbd_device *lo) } dprintk(DBG_RX, "%s: request %p: got %d bytes data\n", lo->disk->disk_name, req, bvec->bv_len); - } } } return req; diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c index aa8b890c80d..8953e7ce001 100644 --- a/drivers/block/ps3disk.c +++ b/drivers/block/ps3disk.c @@ -91,30 +91,30 @@ static void ps3disk_scatter_gather(struct ps3_storage_device *dev, struct request *req, int gather) { unsigned int offset = 0; - struct bio *bio; - sector_t sector; + struct req_iterator iter; struct bio_vec *bvec; - unsigned int i = 0, j; + unsigned int i = 0; size_t size; void *buf; - rq_for_each_bio(bio, req) { - sector = bio->bi_sector; + rq_for_each_segment(bvec, req, iter) { + unsigned long flags; dev_dbg(&dev->sbd.core, "%s:%u: bio %u: %u segs %u sectors from %lu\n", - __func__, __LINE__, i, bio_segments(bio), - bio_sectors(bio), sector); - bio_for_each_segment(bvec, bio, j) { + __func__, __LINE__, i, bio_segments(iter.bio), + bio_sectors(iter.bio), + (unsigned long)iter.bio->bi_sector); + size = bvec->bv_len; - buf = __bio_kmap_atomic(bio, j, KM_IRQ0); + buf = bvec_kmap_irq(bvec, &flags); if (gather) memcpy(dev->bounce_buf+offset, buf, size); else memcpy(buf, dev->bounce_buf+offset, size); offset += size; - flush_kernel_dcache_page(bio_iovec_idx(bio, j)->bv_page); - __bio_kunmap_atomic(bio, KM_IRQ0); - } + flush_kernel_dcache_page(bvec->bv_page); + bvec_kunmap_irq(bvec, &flags); + i++; } } @@ -130,12 +130,13 @@ static int ps3disk_submit_request_sg(struct ps3_storage_device *dev, #ifdef DEBUG unsigned int n = 0; - struct bio *bio; + struct bio_vec *bv; + struct req_iterator iter; - rq_for_each_bio(bio, req) + rq_for_each_segment(bv, req, iter) n++; dev_dbg(&dev->sbd.core, - "%s:%u: %s req has %u bios for %lu sectors %lu hard sectors\n", + "%s:%u: %s req has %u bvecs for %lu sectors %lu hard sectors\n", __func__, __LINE__, op, n, req->nr_sectors, req->hard_nr_sectors); #endif diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 964e51634f2..6af250113c2 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -150,9 +150,8 @@ static int blkif_queue_request(struct request *req) struct blkfront_info *info = req->rq_disk->private_data; unsigned long buffer_mfn; struct blkif_request *ring_req; - struct bio *bio; + struct req_iterator iter; struct bio_vec *bvec; - int idx; unsigned long id; unsigned int fsect, lsect; int ref; @@ -186,8 +185,7 @@ static int blkif_queue_request(struct request *req) ring_req->operation = BLKIF_OP_WRITE_BARRIER; ring_req->nr_segments = 0; - rq_for_each_bio (bio, req) { - bio_for_each_segment (bvec, bio, idx) { + rq_for_each_segment(bvec, req, iter) { BUG_ON(ring_req->nr_segments == BLKIF_MAX_SEGMENTS_PER_REQUEST); buffer_mfn = pfn_to_mfn(page_to_pfn(bvec->bv_page)); @@ -213,7 +211,6 @@ static int blkif_queue_request(struct request *req) .last_sect = lsect }; ring_req->nr_segments++; - } } info->ring.req_prod_pvt++; diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index ae8e1a64b8a..a775450d7a3 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c @@ -606,13 +606,12 @@ static void idefloppy_input_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, uns { struct request *rq = pc->rq; struct bio_vec *bvec; - struct bio *bio; + struct req_iterator iter; unsigned long flags; char *data; - int count, i, done = 0; + int count, done = 0; - rq_for_each_bio(bio, rq) { - bio_for_each_segment(bvec, bio, i) { + rq_for_each_segment(bvec, rq, iter) { if (!bcount) break; @@ -625,7 +624,6 @@ static void idefloppy_input_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, uns bcount -= count; pc->b_count += count; done += count; - } } idefloppy_do_end_request(drive, 1, done >> 9); @@ -639,14 +637,13 @@ static void idefloppy_input_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, uns static void idefloppy_output_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, unsigned int bcount) { struct request *rq = pc->rq; - struct bio *bio; + struct req_iterator iter; struct bio_vec *bvec; unsigned long flags; - int count, i, done = 0; + int count, done = 0; char *data; - rq_for_each_bio(bio, rq) { - bio_for_each_segment(bvec, bio, i) { + rq_for_each_segment(bvec, rq, iter) { if (!bcount) break; @@ -659,7 +656,6 @@ static void idefloppy_output_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, un bcount -= count; pc->b_count += count; done += count; - } } idefloppy_do_end_request(drive, 1, done >> 9); diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index d32c60dbdd8..6bb9676f203 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -472,14 +472,13 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req) struct dasd_ccw_req *cqr; struct dasd_diag_req *dreq; struct dasd_diag_bio *dbio; - struct bio *bio; + struct req_iterator iter; struct bio_vec *bv; char *dst; unsigned int count, datasize; sector_t recid, first_rec, last_rec; unsigned int blksize, off; unsigned char rw_cmd; - int i; if (rq_data_dir(req) == READ) rw_cmd = MDSK_READ_REQ; @@ -493,13 +492,11 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req) last_rec = (req->sector + req->nr_sectors - 1) >> device->s2b_shift; /* Check struct bio and count the number of blocks for the request. */ count = 0; - rq_for_each_bio(bio, req) { - bio_for_each_segment(bv, bio, i) { + rq_for_each_segment(bv, req, iter) { if (bv->bv_len & (blksize - 1)) /* Fba can only do full blocks. */ return ERR_PTR(-EINVAL); count += bv->bv_len >> (device->s2b_shift + 9); - } } /* Paranoia. */ if (count != last_rec - first_rec + 1) @@ -516,8 +513,7 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req) dreq->block_count = count; dbio = dreq->bio; recid = first_rec; - rq_for_each_bio(bio, req) { - bio_for_each_segment(bv, bio, i) { + rq_for_each_segment(bv, req, iter) { dst = page_address(bv->bv_page) + bv->bv_offset; for (off = 0; off < bv->bv_len; off += blksize) { memset(dbio, 0, sizeof (struct dasd_diag_bio)); @@ -528,7 +524,6 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req) dst += blksize; recid++; } - } } cqr->retries = DIAG_MAX_RETRIES; cqr->buildclk = get_clock(); diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index ea63ba7828f..36ba4584987 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -1176,7 +1176,7 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req) struct LO_eckd_data *LO_data; struct dasd_ccw_req *cqr; struct ccw1 *ccw; - struct bio *bio; + struct req_iterator iter; struct bio_vec *bv; char *dst; unsigned int blksize, blk_per_trk, off; @@ -1185,7 +1185,6 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req) sector_t first_trk, last_trk; unsigned int first_offs, last_offs; unsigned char cmd, rcmd; - int i; private = (struct dasd_eckd_private *) device->private; if (rq_data_dir(req) == READ) @@ -1206,8 +1205,7 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req) /* Check struct bio and count the number of blocks for the request. */ count = 0; cidaw = 0; - rq_for_each_bio(bio, req) { - bio_for_each_segment(bv, bio, i) { + rq_for_each_segment(bv, req, iter) { if (bv->bv_len & (blksize - 1)) /* Eckd can only do full blocks. */ return ERR_PTR(-EINVAL); @@ -1217,7 +1215,6 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req) bv->bv_len)) cidaw += bv->bv_len >> (device->s2b_shift + 9); #endif - } } /* Paranoia. */ if (count != last_rec - first_rec + 1) @@ -1257,7 +1254,7 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req) locate_record(ccw++, LO_data++, first_trk, first_offs + 1, last_rec - recid + 1, cmd, device, blksize); } - rq_for_each_bio(bio, req) bio_for_each_segment(bv, bio, i) { + rq_for_each_segment(bv, req, iter) { dst = page_address(bv->bv_page) + bv->bv_offset; if (dasd_page_cache) { char *copy = kmem_cache_alloc(dasd_page_cache, @@ -1328,12 +1325,12 @@ dasd_eckd_free_cp(struct dasd_ccw_req *cqr, struct request *req) { struct dasd_eckd_private *private; struct ccw1 *ccw; - struct bio *bio; + struct req_iterator iter; struct bio_vec *bv; char *dst, *cda; unsigned int blksize, blk_per_trk, off; sector_t recid; - int i, status; + int status; if (!dasd_page_cache) goto out; @@ -1346,7 +1343,7 @@ dasd_eckd_free_cp(struct dasd_ccw_req *cqr, struct request *req) ccw++; if (private->uses_cdl == 0 || recid > 2*blk_per_trk) ccw++; - rq_for_each_bio(bio, req) bio_for_each_segment(bv, bio, i) { + rq_for_each_segment(bv, req, iter) { dst = page_address(bv->bv_page) + bv->bv_offset; for (off = 0; off < bv->bv_len; off += blksize) { /* Skip locate record. */ diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index da16ead8aff..119b8d2d5f1 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c @@ -234,14 +234,13 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req) struct LO_fba_data *LO_data; struct dasd_ccw_req *cqr; struct ccw1 *ccw; - struct bio *bio; + struct req_iterator iter; struct bio_vec *bv; char *dst; int count, cidaw, cplength, datasize; sector_t recid, first_rec, last_rec; unsigned int blksize, off; unsigned char cmd; - int i; private = (struct dasd_fba_private *) device->private; if (rq_data_dir(req) == READ) { @@ -257,8 +256,7 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req) /* Check struct bio and count the number of blocks for the request. */ count = 0; cidaw = 0; - rq_for_each_bio(bio, req) { - bio_for_each_segment(bv, bio, i) { + rq_for_each_segment(bv, req, iter) { if (bv->bv_len & (blksize - 1)) /* Fba can only do full blocks. */ return ERR_PTR(-EINVAL); @@ -268,7 +266,6 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req) bv->bv_len)) cidaw += bv->bv_len / blksize; #endif - } } /* Paranoia. */ if (count != last_rec - first_rec + 1) @@ -304,7 +301,7 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req) locate_record(ccw++, LO_data++, rq_data_dir(req), 0, count); } recid = first_rec; - rq_for_each_bio(bio, req) bio_for_each_segment(bv, bio, i) { + rq_for_each_segment(bv, req, iter) { dst = page_address(bv->bv_page) + bv->bv_offset; if (dasd_page_cache) { char *copy = kmem_cache_alloc(dasd_page_cache, @@ -359,11 +356,11 @@ dasd_fba_free_cp(struct dasd_ccw_req *cqr, struct request *req) { struct dasd_fba_private *private; struct ccw1 *ccw; - struct bio *bio; + struct req_iterator iter; struct bio_vec *bv; char *dst, *cda; unsigned int blksize, off; - int i, status; + int status; if (!dasd_page_cache) goto out; @@ -374,7 +371,7 @@ dasd_fba_free_cp(struct dasd_ccw_req *cqr, struct request *req) ccw++; if (private->rdc_data.mode.bits.data_chain != 0) ccw++; - rq_for_each_bio(bio, req) bio_for_each_segment(bv, bio, i) { + rq_for_each_segment(bv, req, iter) { dst = page_address(bv->bv_page) + bv->bv_offset; for (off = 0; off < bv->bv_len; off += blksize) { /* Skip locate record. */ diff --git a/drivers/s390/char/tape_34xx.c b/drivers/s390/char/tape_34xx.c index 80e7a537e7d..ea3e6a345c8 100644 --- a/drivers/s390/char/tape_34xx.c +++ b/drivers/s390/char/tape_34xx.c @@ -1134,21 +1134,18 @@ tape_34xx_bread(struct tape_device *device, struct request *req) { struct tape_request *request; struct ccw1 *ccw; - int count = 0, i; + int count = 0; unsigned off; char *dst; struct bio_vec *bv; - struct bio *bio; + struct req_iterator iter; struct tape_34xx_block_id * start_block; DBF_EVENT(6, "xBREDid:"); /* Count the number of blocks for the request. */ - rq_for_each_bio(bio, req) { - bio_for_each_segment(bv, bio, i) { - count += bv->bv_len >> (TAPEBLOCK_HSEC_S2B + 9); - } - } + rq_for_each_segment(bv, req, iter) + count += bv->bv_len >> (TAPEBLOCK_HSEC_S2B + 9); /* Allocate the ccw request. */ request = tape_alloc_request(3+count+1, 8); @@ -1175,8 +1172,7 @@ tape_34xx_bread(struct tape_device *device, struct request *req) ccw = tape_ccw_cc(ccw, NOP, 0, NULL); ccw = tape_ccw_cc(ccw, NOP, 0, NULL); - rq_for_each_bio(bio, req) { - bio_for_each_segment(bv, bio, i) { + rq_for_each_segment(bv, req, iter) { dst = kmap(bv->bv_page) + bv->bv_offset; for (off = 0; off < bv->bv_len; off += TAPEBLOCK_HSEC_SIZE) { @@ -1187,7 +1183,6 @@ tape_34xx_bread(struct tape_device *device, struct request *req) ccw++; dst += TAPEBLOCK_HSEC_SIZE; } - } } ccw = tape_ccw_end(ccw, NOP, 0, NULL); diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c index 7e2b2ab4926..b16ad7a7631 100644 --- a/drivers/s390/char/tape_3590.c +++ b/drivers/s390/char/tape_3590.c @@ -623,21 +623,19 @@ tape_3590_bread(struct tape_device *device, struct request *req) { struct tape_request *request; struct ccw1 *ccw; - int count = 0, start_block, i; + int count = 0, start_block; unsigned off; char *dst; struct bio_vec *bv; - struct bio *bio; + struct req_iterator iter; DBF_EVENT(6, "xBREDid:"); start_block = req->sector >> TAPEBLOCK_HSEC_S2B; DBF_EVENT(6, "start_block = %i\n", start_block); - rq_for_each_bio(bio, req) { - bio_for_each_segment(bv, bio, i) { - count += bv->bv_len >> (TAPEBLOCK_HSEC_S2B + 9); - } - } + rq_for_each_segment(bv, req, iter) + count += bv->bv_len >> (TAPEBLOCK_HSEC_S2B + 9); + request = tape_alloc_request(2 + count + 1, 4); if (IS_ERR(request)) return request; @@ -653,8 +651,7 @@ tape_3590_bread(struct tape_device *device, struct request *req) */ ccw = tape_ccw_cc(ccw, NOP, 0, NULL); - rq_for_each_bio(bio, req) { - bio_for_each_segment(bv, bio, i) { + rq_for_each_segment(bv, req, iter) { dst = page_address(bv->bv_page) + bv->bv_offset; for (off = 0; off < bv->bv_len; off += TAPEBLOCK_HSEC_SIZE) { @@ -667,7 +664,6 @@ tape_3590_bread(struct tape_device *device, struct request *req) } if (off > bv->bv_len) BUG(); - } } ccw = tape_ccw_end(ccw, NOP, 0, NULL); DBF_EVENT(6, "xBREDccwg\n"); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index b126c6f68e2..a4b13b8a9d0 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -637,10 +637,23 @@ static inline void blk_queue_bounce(struct request_queue *q, struct bio **bio) } #endif /* CONFIG_MMU */ -#define rq_for_each_bio(_bio, rq) \ +struct req_iterator { + int i; + struct bio *bio; +}; + +/* This should not be used directly - use rq_for_each_segment */ +#define __rq_for_each_bio(_bio, rq) \ if ((rq->bio)) \ for (_bio = (rq)->bio; _bio; _bio = _bio->bi_next) +#define rq_for_each_segment(bvl, _rq, _iter) \ + __rq_for_each_bio(_iter.bio, _rq) \ + bio_for_each_segment(bvl, _iter.bio, _iter.i) + +#define rq_iter_last(rq, _iter) \ + (_iter.bio->bi_next == NULL && _iter.i == _iter.bio->bi_vcnt-1) + extern int blk_register_queue(struct gendisk *disk); extern void blk_unregister_queue(struct gendisk *disk); extern void register_disk(struct gendisk *dev); -- cgit v1.2.3-70-g09d2 From eea9befaccb8d43ce89585d612159761c978f056 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 16 Aug 2007 13:31:26 +0200 Subject: Fix various abuse of bio fields in umem.c umem.c: advances bi_idx and bi_sector to track where it is up to. But it is only ever doing this on one bio, so the updated fields can easily be kept elsewhere (current_*). updates bi_size, but never uses the updated values, so this isn't needed. reuses bi_phys_segments to count how many iovecs have been completely. As the completion happens sequentiually, we can store this information outside the bio too. Signed-off-by: Neil Brown diff .prev/drivers/block/umem.c ./drivers/block/umem.c Signed-off-by: Jens Axboe --- drivers/block/umem.c | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/block/umem.c b/drivers/block/umem.c index 6b7c02d6360..c378e285d70 100644 --- a/drivers/block/umem.c +++ b/drivers/block/umem.c @@ -113,6 +113,8 @@ struct cardinfo { * have been written */ struct bio *bio, *currentbio, **biotail; + int current_idx; + sector_t current_sector; struct request_queue *queue; @@ -121,6 +123,7 @@ struct cardinfo { struct mm_dma_desc *desc; int cnt, headcnt; struct bio *bio, **biotail; + int idx; } mm_pages[2]; #define DESC_PER_PAGE ((PAGE_SIZE*2)/sizeof(struct mm_dma_desc)) @@ -380,12 +383,16 @@ static int add_bio(struct cardinfo *card) dma_addr_t dma_handle; int offset; struct bio *bio; + struct bio_vec *vec; + int idx; int rw; int len; bio = card->currentbio; if (!bio && card->bio) { card->currentbio = card->bio; + card->current_idx = card->bio->bi_idx; + card->current_sector = card->bio->bi_sector; card->bio = card->bio->bi_next; if (card->bio == NULL) card->biotail = &card->bio; @@ -394,15 +401,17 @@ static int add_bio(struct cardinfo *card) } if (!bio) return 0; + idx = card->current_idx; rw = bio_rw(bio); if (card->mm_pages[card->Ready].cnt >= DESC_PER_PAGE) return 0; - len = bio_iovec(bio)->bv_len; - dma_handle = pci_map_page(card->dev, - bio_page(bio), - bio_offset(bio), + vec = bio_iovec_idx(bio, idx); + len = vec->bv_len; + dma_handle = pci_map_page(card->dev, + vec->bv_page, + vec->bv_offset, len, (rw==READ) ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); @@ -410,6 +419,8 @@ static int add_bio(struct cardinfo *card) p = &card->mm_pages[card->Ready]; desc = &p->desc[p->cnt]; p->cnt++; + if (p->bio == NULL) + p->idx = idx; if ((p->biotail) != &bio->bi_next) { *(p->biotail) = bio; p->biotail = &(bio->bi_next); @@ -419,7 +430,7 @@ static int add_bio(struct cardinfo *card) desc->data_dma_handle = dma_handle; desc->pci_addr = cpu_to_le64((u64)desc->data_dma_handle); - desc->local_addr= cpu_to_le64(bio->bi_sector << 9); + desc->local_addr = cpu_to_le64(card->current_sector << 9); desc->transfer_size = cpu_to_le32(len); offset = ( ((char*)&desc->sem_control_bits) - ((char*)p->desc)); desc->sem_addr = cpu_to_le64((u64)(p->page_dma+offset)); @@ -435,10 +446,10 @@ static int add_bio(struct cardinfo *card) desc->control_bits |= cpu_to_le32(DMASCR_TRANSFER_READ); desc->sem_control_bits = desc->control_bits; - bio->bi_sector += (len>>9); - bio->bi_size -= len; - bio->bi_idx++; - if (bio->bi_idx >= bio->bi_vcnt) + card->current_sector += (len >> 9); + idx++; + card->current_idx = idx; + if (idx >= bio->bi_vcnt) card->currentbio = NULL; return 1; @@ -474,10 +485,12 @@ static void process_page(unsigned long data) last=1; } page->headcnt++; - idx = bio->bi_phys_segments; - bio->bi_phys_segments++; - if (bio->bi_phys_segments >= bio->bi_vcnt) + idx = page->idx; + page->idx++; + if (page->idx >= bio->bi_vcnt) { page->bio = bio->bi_next; + page->idx = page->bio->bi_idx; + } pci_unmap_page(card->dev, desc->data_dma_handle, bio_iovec_idx(bio,idx)->bv_len, @@ -547,7 +560,6 @@ static int mm_make_request(struct request_queue *q, struct bio *bio) pr_debug("mm_make_request %llu %u\n", (unsigned long long)bio->bi_sector, bio->bi_size); - bio->bi_phys_segments = bio->bi_idx; /* count of completed segments*/ spin_lock_irq(&card->lock); *card->biotail = bio; bio->bi_next = NULL; -- cgit v1.2.3-70-g09d2 From 3001ca77128273cc5634d79f5306ce2e5a14ec41 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 16 Aug 2007 13:31:27 +0200 Subject: New function blk_req_append_bio ll_back_merge_fn is currently exported to SCSI where is it used, together with blk_rq_bio_prep, in exactly the same way these functions are used in __blk_rq_map_user. So move the common code into a new function (blk_rq_append_bio), and don't export ll_back_merge_fn any longer. Signed-off-by: Neil Brown diff .prev/block/ll_rw_blk.c ./block/ll_rw_blk.c Signed-off-by: Jens Axboe --- block/ll_rw_blk.c | 38 ++++++++++++++++++++++---------------- drivers/scsi/scsi_lib.c | 11 +---------- include/linux/blkdev.h | 4 ++-- 3 files changed, 25 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index 094c0fa5c40..2de9bad1d04 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -1441,7 +1441,8 @@ static inline int ll_new_hw_segment(struct request_queue *q, return 1; } -int ll_back_merge_fn(struct request_queue *q, struct request *req, struct bio *bio) +static int ll_back_merge_fn(struct request_queue *q, struct request *req, + struct bio *bio) { unsigned short max_sectors; int len; @@ -1477,7 +1478,6 @@ int ll_back_merge_fn(struct request_queue *q, struct request *req, struct bio *b return ll_new_hw_segment(q, req, bio); } -EXPORT_SYMBOL(ll_back_merge_fn); static int ll_front_merge_fn(struct request_queue *q, struct request *req, struct bio *bio) @@ -2367,6 +2367,23 @@ static int __blk_rq_unmap_user(struct bio *bio) return ret; } +int blk_rq_append_bio(struct request_queue *q, struct request *rq, + struct bio *bio) +{ + if (!rq->bio) + blk_rq_bio_prep(q, rq, bio); + else if (!ll_back_merge_fn(q, rq, bio)) + return -EINVAL; + else { + rq->biotail->bi_next = bio; + rq->biotail = bio; + + rq->data_len += bio->bi_size; + } + return 0; +} +EXPORT_SYMBOL(blk_rq_append_bio); + static int __blk_rq_map_user(struct request_queue *q, struct request *rq, void __user *ubuf, unsigned int len) { @@ -2398,21 +2415,10 @@ static int __blk_rq_map_user(struct request_queue *q, struct request *rq, */ bio_get(bio); - if (!rq->bio) - blk_rq_bio_prep(q, rq, bio); - else if (!ll_back_merge_fn(q, rq, bio)) { - ret = -EINVAL; - goto unmap_bio; - } else { - rq->biotail->bi_next = bio; - rq->biotail = bio; - - rq->data_len += bio->bi_size; - } - - return bio->bi_size; + ret = blk_rq_append_bio(q, rq, bio); + if (!ret) + return bio->bi_size; -unmap_bio: /* if it was boucned we must call the end io function */ bio_endio(bio, bio->bi_size, 0); __blk_rq_unmap_user(orig_bio); diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index a417a6ff9f9..59b39853029 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -263,16 +263,7 @@ static int scsi_merge_bio(struct request *rq, struct bio *bio) bio->bi_rw |= (1 << BIO_RW); blk_queue_bounce(q, &bio); - if (!rq->bio) - blk_rq_bio_prep(q, rq, bio); - else if (!ll_back_merge_fn(q, rq, bio)) - return -EINVAL; - else { - rq->biotail->bi_next = bio; - rq->biotail = bio; - } - - return 0; + return blk_rq_append_bio(q, rq, bio); } static int scsi_bi_endio(struct bio *bio, unsigned int bytes_done, int error) diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index a4b13b8a9d0..3021a5b1d39 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -675,8 +675,8 @@ extern int sg_scsi_ioctl(struct file *, struct request_queue *, /* * Temporary export, until SCSI gets fixed up. */ -extern int ll_back_merge_fn(struct request_queue *, struct request *, - struct bio *); +extern int blk_rq_append_bio(struct request_queue *q, struct request *rq, + struct bio *bio); /* * A queue has just exitted congestion. Note this in the global counter of -- cgit v1.2.3-70-g09d2 From 66846572bfb4ec62bcba260028cbbcbdb77bd636 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 16 Aug 2007 13:31:28 +0200 Subject: Stop exporting blk_rq_bio_prep blk_rq_bio_prep is exported for use in exactly one place. That place can benefit from using the new blk_rq_append_bio instead. So - change dm-emc to call blk_rq_append_bio - stop exporting blk_rq_bio_prep, and - initialise rq_disk in blk_rq_bio_prep, as dm-emc needs it. Signed-off-by: Neil Brown diff .prev/block/ll_rw_blk.c ./block/ll_rw_blk.c Signed-off-by: Jens Axboe --- block/ll_rw_blk.c | 11 +++++++---- drivers/md/dm-emc.c | 10 +--------- include/linux/blkdev.h | 1 - 3 files changed, 8 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index 2de9bad1d04..eb27b335d23 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -43,6 +43,8 @@ static void init_request_from_bio(struct request *req, struct bio *bio); static int __make_request(struct request_queue *q, struct bio *bio); static struct io_context *current_io_context(gfp_t gfp_flags, int node); static void blk_recalc_rq_segments(struct request *rq); +static void blk_rq_bio_prep(struct request_queue *q, struct request *rq, + struct bio *bio); /* * For the allocated request tables @@ -3665,8 +3667,8 @@ void end_request(struct request *req, int uptodate) EXPORT_SYMBOL(end_request); -void blk_rq_bio_prep(struct request_queue *q, struct request *rq, - struct bio *bio) +static void blk_rq_bio_prep(struct request_queue *q, struct request *rq, + struct bio *bio) { /* first two bits are identical in rq->cmd_flags and bio->bi_rw */ rq->cmd_flags |= (bio->bi_rw & 3); @@ -3680,9 +3682,10 @@ void blk_rq_bio_prep(struct request_queue *q, struct request *rq, rq->data_len = bio->bi_size; rq->bio = rq->biotail = bio; -} -EXPORT_SYMBOL(blk_rq_bio_prep); + if (bio->bi_bdev) + rq->rq_disk = bio->bi_bdev->bd_disk; +} int kblockd_schedule_work(struct work_struct *work) { diff --git a/drivers/md/dm-emc.c b/drivers/md/dm-emc.c index 265c467854d..71cc858b786 100644 --- a/drivers/md/dm-emc.c +++ b/drivers/md/dm-emc.c @@ -109,15 +109,7 @@ static struct request *get_failover_req(struct emc_handler *h, return NULL; } - rq->bio = rq->biotail = bio; - blk_rq_bio_prep(q, rq, bio); - - rq->rq_disk = bdev->bd_contains->bd_disk; - - /* bio backed don't set data */ - rq->buffer = rq->data = NULL; - /* rq data_len used for pc cmd's request_bufflen */ - rq->data_len = bio->bi_size; + blk_rq_append_bio(q, rq, bio); rq->sense = h->sense; memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 3021a5b1d39..492ac946391 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -823,7 +823,6 @@ static inline struct request *blk_map_queue_find_tag(struct blk_queue_tag *bqt, return bqt->tag_index[tag]; } -extern void blk_rq_bio_prep(struct request_queue *, struct request *, struct bio *); extern int blkdev_issue_flush(struct block_device *, sector_t *); #define MAX_PHYS_SEGMENTS 128 -- cgit v1.2.3-70-g09d2 From 6c92e699b56287da582ccb12a64b959b6d6109ba Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Thu, 16 Aug 2007 13:43:12 +0200 Subject: Fixup rq_for_each_segment() indentation Remove one level of nesting where appropriate. Signed-off-by: Jens Axboe --- block/ll_rw_blk.c | 34 ++++++++++++++++----------------- drivers/block/lguest_blk.c | 24 +++++++++++------------ drivers/block/nbd.c | 43 ++++++++++++++++++++---------------------- drivers/block/ps3disk.c | 19 +++++++++---------- drivers/block/xen-blkfront.c | 25 ++++++++++++------------ drivers/ide/ide-floppy.c | 36 +++++++++++++++++------------------ drivers/s390/block/dasd_diag.c | 28 +++++++++++++-------------- drivers/s390/block/dasd_eckd.c | 13 ++++++------- drivers/s390/block/dasd_fba.c | 13 ++++++------- drivers/s390/char/tape_34xx.c | 19 +++++++++---------- drivers/s390/char/tape_3590.c | 23 +++++++++++----------- 11 files changed, 134 insertions(+), 143 deletions(-) (limited to 'drivers') diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index e0608c4ecc2..c6b2a477d33 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -1364,28 +1364,28 @@ int blk_rq_map_sg(struct request_queue *q, struct request *rq, */ bvprv = NULL; rq_for_each_segment(bvec, rq, iter) { - int nbytes = bvec->bv_len; + int nbytes = bvec->bv_len; - if (bvprv && cluster) { - if (sg[nsegs - 1].length + nbytes > q->max_segment_size) - goto new_segment; + if (bvprv && cluster) { + if (sg[nsegs - 1].length + nbytes > q->max_segment_size) + goto new_segment; - if (!BIOVEC_PHYS_MERGEABLE(bvprv, bvec)) - goto new_segment; - if (!BIOVEC_SEG_BOUNDARY(q, bvprv, bvec)) - goto new_segment; + if (!BIOVEC_PHYS_MERGEABLE(bvprv, bvec)) + goto new_segment; + if (!BIOVEC_SEG_BOUNDARY(q, bvprv, bvec)) + goto new_segment; - sg[nsegs - 1].length += nbytes; - } else { + sg[nsegs - 1].length += nbytes; + } else { new_segment: - memset(&sg[nsegs],0,sizeof(struct scatterlist)); - sg[nsegs].page = bvec->bv_page; - sg[nsegs].length = nbytes; - sg[nsegs].offset = bvec->bv_offset; + memset(&sg[nsegs],0,sizeof(struct scatterlist)); + sg[nsegs].page = bvec->bv_page; + sg[nsegs].length = nbytes; + sg[nsegs].offset = bvec->bv_offset; - nsegs++; - } - bvprv = bvec; + nsegs++; + } + bvprv = bvec; } /* segments in rq */ return nsegs; diff --git a/drivers/block/lguest_blk.c b/drivers/block/lguest_blk.c index 1e838ae60a6..fa8e42341b8 100644 --- a/drivers/block/lguest_blk.c +++ b/drivers/block/lguest_blk.c @@ -147,18 +147,18 @@ static unsigned int req_to_dma(struct request *req, struct lguest_dma *dma) struct bio_vec *bvec; rq_for_each_segment(bvec, req, iter) { - /* We told the block layer not to give us too many. */ - BUG_ON(i == LGUEST_MAX_DMA_SECTIONS); - /* If we had a zero-length segment, it would look like - * the end of the data referred to by the "struct - * lguest_dma", so make sure that doesn't happen. */ - BUG_ON(!bvec->bv_len); - /* Convert page & offset to a physical address */ - dma->addr[i] = page_to_phys(bvec->bv_page) - + bvec->bv_offset; - dma->len[i] = bvec->bv_len; - len += bvec->bv_len; - i++; + /* We told the block layer not to give us too many. */ + BUG_ON(i == LGUEST_MAX_DMA_SECTIONS); + /* If we had a zero-length segment, it would look like + * the end of the data referred to by the "struct + * lguest_dma", so make sure that doesn't happen. */ + BUG_ON(!bvec->bv_len); + /* Convert page & offset to a physical address */ + dma->addr[i] = page_to_phys(bvec->bv_page) + + bvec->bv_offset; + dma->len[i] = bvec->bv_len; + len += bvec->bv_len; + i++; } /* If the array isn't full, we mark the end with a 0 length */ if (i < LGUEST_MAX_DMA_SECTIONS) diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 228b2ff577a..be5ec3a9b1f 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -212,19 +212,17 @@ static int nbd_send_req(struct nbd_device *lo, struct request *req) * whether to set MSG_MORE or not... */ rq_for_each_segment(bvec, req, iter) { - flags = 0; - if (!rq_iter_last(req, iter)) - flags = MSG_MORE; - dprintk(DBG_TX, "%s: request %p: sending %d bytes data\n", - lo->disk->disk_name, req, - bvec->bv_len); - result = sock_send_bvec(sock, bvec, flags); - if (result <= 0) { - printk(KERN_ERR "%s: Send data failed (result %d)\n", - lo->disk->disk_name, - result); - goto error_out; - } + flags = 0; + if (!rq_iter_last(req, iter)) + flags = MSG_MORE; + dprintk(DBG_TX, "%s: request %p: sending %d bytes data\n", + lo->disk->disk_name, req, bvec->bv_len); + result = sock_send_bvec(sock, bvec, flags); + if (result <= 0) { + printk(KERN_ERR "%s: Send data failed (result %d)\n", + lo->disk->disk_name, result); + goto error_out; + } } } return 0; @@ -323,16 +321,15 @@ static struct request *nbd_read_stat(struct nbd_device *lo) struct bio_vec *bvec; rq_for_each_segment(bvec, req, iter) { - result = sock_recv_bvec(sock, bvec); - if (result <= 0) { - printk(KERN_ERR "%s: Receive data failed (result %d)\n", - lo->disk->disk_name, - result); - req->errors++; - return req; - } - dprintk(DBG_RX, "%s: request %p: got %d bytes data\n", - lo->disk->disk_name, req, bvec->bv_len); + result = sock_recv_bvec(sock, bvec); + if (result <= 0) { + printk(KERN_ERR "%s: Receive data failed (result %d)\n", + lo->disk->disk_name, result); + req->errors++; + return req; + } + dprintk(DBG_RX, "%s: request %p: got %d bytes data\n", + lo->disk->disk_name, req, bvec->bv_len); } } return req; diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c index 8953e7ce001..06d0552cf49 100644 --- a/drivers/block/ps3disk.c +++ b/drivers/block/ps3disk.c @@ -105,16 +105,15 @@ static void ps3disk_scatter_gather(struct ps3_storage_device *dev, bio_sectors(iter.bio), (unsigned long)iter.bio->bi_sector); - size = bvec->bv_len; - buf = bvec_kmap_irq(bvec, &flags); - if (gather) - memcpy(dev->bounce_buf+offset, buf, size); - else - memcpy(buf, dev->bounce_buf+offset, size); - offset += size; - flush_kernel_dcache_page(bvec->bv_page); - bvec_kunmap_irq(bvec, &flags); - + size = bvec->bv_len; + buf = bvec_kmap_irq(bvec, &flags); + if (gather) + memcpy(dev->bounce_buf+offset, buf, size); + else + memcpy(buf, dev->bounce_buf+offset, size); + offset += size; + flush_kernel_dcache_page(bvec->bv_page); + bvec_kunmap_irq(bvec, &flags); i++; } } diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 6af250113c2..2bdebcb3ff1 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -186,31 +186,30 @@ static int blkif_queue_request(struct request *req) ring_req->nr_segments = 0; rq_for_each_segment(bvec, req, iter) { - BUG_ON(ring_req->nr_segments - == BLKIF_MAX_SEGMENTS_PER_REQUEST); - buffer_mfn = pfn_to_mfn(page_to_pfn(bvec->bv_page)); - fsect = bvec->bv_offset >> 9; - lsect = fsect + (bvec->bv_len >> 9) - 1; - /* install a grant reference. */ - ref = gnttab_claim_grant_reference(&gref_head); - BUG_ON(ref == -ENOSPC); - - gnttab_grant_foreign_access_ref( + BUG_ON(ring_req->nr_segments == BLKIF_MAX_SEGMENTS_PER_REQUEST); + buffer_mfn = pfn_to_mfn(page_to_pfn(bvec->bv_page)); + fsect = bvec->bv_offset >> 9; + lsect = fsect + (bvec->bv_len >> 9) - 1; + /* install a grant reference. */ + ref = gnttab_claim_grant_reference(&gref_head); + BUG_ON(ref == -ENOSPC); + + gnttab_grant_foreign_access_ref( ref, info->xbdev->otherend_id, buffer_mfn, rq_data_dir(req) ); - info->shadow[id].frame[ring_req->nr_segments] = + info->shadow[id].frame[ring_req->nr_segments] = mfn_to_pfn(buffer_mfn); - ring_req->seg[ring_req->nr_segments] = + ring_req->seg[ring_req->nr_segments] = (struct blkif_request_segment) { .gref = ref, .first_sect = fsect, .last_sect = lsect }; - ring_req->nr_segments++; + ring_req->nr_segments++; } info->ring.req_prod_pvt++; diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index a775450d7a3..04a357808f2 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c @@ -612,18 +612,18 @@ static void idefloppy_input_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, uns int count, done = 0; rq_for_each_segment(bvec, rq, iter) { - if (!bcount) - break; + if (!bcount) + break; - count = min(bvec->bv_len, bcount); + count = min(bvec->bv_len, bcount); - data = bvec_kmap_irq(bvec, &flags); - drive->hwif->atapi_input_bytes(drive, data, count); - bvec_kunmap_irq(data, &flags); + data = bvec_kmap_irq(bvec, &flags); + drive->hwif->atapi_input_bytes(drive, data, count); + bvec_kunmap_irq(data, &flags); - bcount -= count; - pc->b_count += count; - done += count; + bcount -= count; + pc->b_count += count; + done += count; } idefloppy_do_end_request(drive, 1, done >> 9); @@ -644,18 +644,18 @@ static void idefloppy_output_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, un char *data; rq_for_each_segment(bvec, rq, iter) { - if (!bcount) - break; + if (!bcount) + break; - count = min(bvec->bv_len, bcount); + count = min(bvec->bv_len, bcount); - data = bvec_kmap_irq(bvec, &flags); - drive->hwif->atapi_output_bytes(drive, data, count); - bvec_kunmap_irq(data, &flags); + data = bvec_kmap_irq(bvec, &flags); + drive->hwif->atapi_output_bytes(drive, data, count); + bvec_kunmap_irq(data, &flags); - bcount -= count; - pc->b_count += count; - done += count; + bcount -= count; + pc->b_count += count; + done += count; } idefloppy_do_end_request(drive, 1, done >> 9); diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index 6bb9676f203..571320ab9e1 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -493,10 +493,10 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req) /* Check struct bio and count the number of blocks for the request. */ count = 0; rq_for_each_segment(bv, req, iter) { - if (bv->bv_len & (blksize - 1)) - /* Fba can only do full blocks. */ - return ERR_PTR(-EINVAL); - count += bv->bv_len >> (device->s2b_shift + 9); + if (bv->bv_len & (blksize - 1)) + /* Fba can only do full blocks. */ + return ERR_PTR(-EINVAL); + count += bv->bv_len >> (device->s2b_shift + 9); } /* Paranoia. */ if (count != last_rec - first_rec + 1) @@ -514,16 +514,16 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req) dbio = dreq->bio; recid = first_rec; rq_for_each_segment(bv, req, iter) { - dst = page_address(bv->bv_page) + bv->bv_offset; - for (off = 0; off < bv->bv_len; off += blksize) { - memset(dbio, 0, sizeof (struct dasd_diag_bio)); - dbio->type = rw_cmd; - dbio->block_number = recid + 1; - dbio->buffer = dst; - dbio++; - dst += blksize; - recid++; - } + dst = page_address(bv->bv_page) + bv->bv_offset; + for (off = 0; off < bv->bv_len; off += blksize) { + memset(dbio, 0, sizeof (struct dasd_diag_bio)); + dbio->type = rw_cmd; + dbio->block_number = recid + 1; + dbio->buffer = dst; + dbio++; + dst += blksize; + recid++; + } } cqr->retries = DIAG_MAX_RETRIES; cqr->buildclk = get_clock(); diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 36ba4584987..44adf8496bd 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -1206,14 +1206,13 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req) count = 0; cidaw = 0; rq_for_each_segment(bv, req, iter) { - if (bv->bv_len & (blksize - 1)) - /* Eckd can only do full blocks. */ - return ERR_PTR(-EINVAL); - count += bv->bv_len >> (device->s2b_shift + 9); + if (bv->bv_len & (blksize - 1)) + /* Eckd can only do full blocks. */ + return ERR_PTR(-EINVAL); + count += bv->bv_len >> (device->s2b_shift + 9); #if defined(CONFIG_64BIT) - if (idal_is_needed (page_address(bv->bv_page), - bv->bv_len)) - cidaw += bv->bv_len >> (device->s2b_shift + 9); + if (idal_is_needed (page_address(bv->bv_page), bv->bv_len)) + cidaw += bv->bv_len >> (device->s2b_shift + 9); #endif } /* Paranoia. */ diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index 119b8d2d5f1..1d95822e0b8 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c @@ -257,14 +257,13 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req) count = 0; cidaw = 0; rq_for_each_segment(bv, req, iter) { - if (bv->bv_len & (blksize - 1)) - /* Fba can only do full blocks. */ - return ERR_PTR(-EINVAL); - count += bv->bv_len >> (device->s2b_shift + 9); + if (bv->bv_len & (blksize - 1)) + /* Fba can only do full blocks. */ + return ERR_PTR(-EINVAL); + count += bv->bv_len >> (device->s2b_shift + 9); #if defined(CONFIG_64BIT) - if (idal_is_needed (page_address(bv->bv_page), - bv->bv_len)) - cidaw += bv->bv_len / blksize; + if (idal_is_needed (page_address(bv->bv_page), bv->bv_len)) + cidaw += bv->bv_len / blksize; #endif } /* Paranoia. */ diff --git a/drivers/s390/char/tape_34xx.c b/drivers/s390/char/tape_34xx.c index ea3e6a345c8..5b47e9cce75 100644 --- a/drivers/s390/char/tape_34xx.c +++ b/drivers/s390/char/tape_34xx.c @@ -1173,16 +1173,15 @@ tape_34xx_bread(struct tape_device *device, struct request *req) ccw = tape_ccw_cc(ccw, NOP, 0, NULL); rq_for_each_segment(bv, req, iter) { - dst = kmap(bv->bv_page) + bv->bv_offset; - for (off = 0; off < bv->bv_len; - off += TAPEBLOCK_HSEC_SIZE) { - ccw->flags = CCW_FLAG_CC; - ccw->cmd_code = READ_FORWARD; - ccw->count = TAPEBLOCK_HSEC_SIZE; - set_normalized_cda(ccw, (void*) __pa(dst)); - ccw++; - dst += TAPEBLOCK_HSEC_SIZE; - } + dst = kmap(bv->bv_page) + bv->bv_offset; + for (off = 0; off < bv->bv_len; off += TAPEBLOCK_HSEC_SIZE) { + ccw->flags = CCW_FLAG_CC; + ccw->cmd_code = READ_FORWARD; + ccw->count = TAPEBLOCK_HSEC_SIZE; + set_normalized_cda(ccw, (void*) __pa(dst)); + ccw++; + dst += TAPEBLOCK_HSEC_SIZE; + } } ccw = tape_ccw_end(ccw, NOP, 0, NULL); diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c index b16ad7a7631..9f244c591ee 100644 --- a/drivers/s390/char/tape_3590.c +++ b/drivers/s390/char/tape_3590.c @@ -652,18 +652,17 @@ tape_3590_bread(struct tape_device *device, struct request *req) ccw = tape_ccw_cc(ccw, NOP, 0, NULL); rq_for_each_segment(bv, req, iter) { - dst = page_address(bv->bv_page) + bv->bv_offset; - for (off = 0; off < bv->bv_len; - off += TAPEBLOCK_HSEC_SIZE) { - ccw->flags = CCW_FLAG_CC; - ccw->cmd_code = READ_FORWARD; - ccw->count = TAPEBLOCK_HSEC_SIZE; - set_normalized_cda(ccw, (void *) __pa(dst)); - ccw++; - dst += TAPEBLOCK_HSEC_SIZE; - } - if (off > bv->bv_len) - BUG(); + dst = page_address(bv->bv_page) + bv->bv_offset; + for (off = 0; off < bv->bv_len; off += TAPEBLOCK_HSEC_SIZE) { + ccw->flags = CCW_FLAG_CC; + ccw->cmd_code = READ_FORWARD; + ccw->count = TAPEBLOCK_HSEC_SIZE; + set_normalized_cda(ccw, (void *) __pa(dst)); + ccw++; + dst += TAPEBLOCK_HSEC_SIZE; + } + if (off > bv->bv_len) + BUG(); } ccw = tape_ccw_end(ccw, NOP, 0, NULL); DBF_EVENT(6, "xBREDccwg\n"); -- cgit v1.2.3-70-g09d2 From 6712ecf8f648118c3363c142196418f89a510b90 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 27 Sep 2007 12:47:43 +0200 Subject: Drop 'size' argument from bio_endio and bi_end_io As bi_end_io is only called once when the reqeust is complete, the 'size' argument is now redundant. Remove it. Now there is no need for bio_endio to subtract the size completed from bi_size. So don't do that either. While we are at it, change bi_end_io to return void. Signed-off-by: Neil Brown Signed-off-by: Jens Axboe --- block/ll_rw_blk.c | 10 ++++----- drivers/block/aoe/aoeblk.c | 4 ++-- drivers/block/aoe/aoecmd.c | 2 +- drivers/block/aoe/aoedev.c | 4 ++-- drivers/block/cciss.c | 2 +- drivers/block/cpqarray.c | 2 +- drivers/block/floppy.c | 6 +----- drivers/block/loop.c | 4 ++-- drivers/block/pktcdvd.c | 25 ++++++----------------- drivers/block/rd.c | 4 ++-- drivers/block/umem.c | 2 +- drivers/md/dm-crypt.c | 21 +++++++------------ drivers/md/dm-emc.c | 5 +---- drivers/md/dm-io.c | 8 +------- drivers/md/dm-mpath.c | 4 ++-- drivers/md/dm-raid1.c | 4 ++-- drivers/md/dm-snap.c | 2 +- drivers/md/dm-zero.c | 2 +- drivers/md/dm.c | 18 +++++++---------- drivers/md/faulty.c | 10 ++++----- drivers/md/linear.c | 4 ++-- drivers/md/md.c | 25 ++++++++--------------- drivers/md/multipath.c | 13 ++++-------- drivers/md/raid0.c | 4 ++-- drivers/md/raid1.c | 30 +++++++-------------------- drivers/md/raid10.c | 31 ++++++++-------------------- drivers/md/raid5.c | 48 +++++++++++++++----------------------------- drivers/s390/block/dcssblk.c | 4 ++-- drivers/s390/block/xpram.c | 6 ++---- drivers/scsi/scsi_lib.c | 10 +++------ fs/bio.c | 35 +++++++------------------------- fs/block_dev.c | 2 +- fs/buffer.c | 6 +----- fs/direct-io.c | 13 ++---------- fs/gfs2/super.c | 4 +--- fs/jfs/jfs_logmgr.c | 5 +---- fs/jfs/jfs_metapage.c | 12 ++--------- fs/mpage.c | 12 ++--------- fs/ocfs2/cluster/heartbeat.c | 4 ---- fs/xfs/linux-2.6/xfs_aops.c | 4 ---- fs/xfs/linux-2.6/xfs_buf.c | 4 ---- include/linux/bio.h | 6 +++--- include/linux/swap.h | 2 +- mm/bounce.c | 25 +++++------------------ mm/page_io.c | 12 ++--------- 45 files changed, 132 insertions(+), 328 deletions(-) (limited to 'drivers') diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index b55ed0df33f..cd9d2c5d91a 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -547,7 +547,7 @@ static void req_bio_endio(struct request *rq, struct bio *bio, bio->bi_size -= nbytes; bio->bi_sector += (nbytes >> 9); if (bio->bi_size == 0) - bio_endio(bio, bio->bi_size, error); + bio_endio(bio, error); } else { /* @@ -2401,7 +2401,7 @@ static int __blk_rq_map_user(struct request_queue *q, struct request *rq, return bio->bi_size; /* if it was boucned we must call the end io function */ - bio_endio(bio, bio->bi_size, 0); + bio_endio(bio, 0); __blk_rq_unmap_user(orig_bio); bio_put(bio); return ret; @@ -2510,7 +2510,7 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq, return PTR_ERR(bio); if (bio->bi_size != len) { - bio_endio(bio, bio->bi_size, 0); + bio_endio(bio, 0); bio_unmap_user(bio); return -EINVAL; } @@ -3040,7 +3040,7 @@ out: return 0; end_io: - bio_endio(bio, nr_sectors << 9, err); + bio_endio(bio, err); return 0; } @@ -3187,7 +3187,7 @@ static inline void __generic_make_request(struct bio *bio) bdevname(bio->bi_bdev, b), (long long) bio->bi_sector); end_io: - bio_endio(bio, bio->bi_size, -EIO); + bio_endio(bio, -EIO); break; } diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c index 007faaf008e..b1d00ef6659 100644 --- a/drivers/block/aoe/aoeblk.c +++ b/drivers/block/aoe/aoeblk.c @@ -138,7 +138,7 @@ aoeblk_make_request(struct request_queue *q, struct bio *bio) buf = mempool_alloc(d->bufpool, GFP_NOIO); if (buf == NULL) { printk(KERN_INFO "aoe: buf allocation failure\n"); - bio_endio(bio, bio->bi_size, -ENOMEM); + bio_endio(bio, -ENOMEM); return 0; } memset(buf, 0, sizeof(*buf)); @@ -159,7 +159,7 @@ aoeblk_make_request(struct request_queue *q, struct bio *bio) d->aoemajor, d->aoeminor); spin_unlock_irqrestore(&d->lock, flags); mempool_free(buf, d->bufpool); - bio_endio(bio, bio->bi_size, -ENXIO); + bio_endio(bio, -ENXIO); return 0; } diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index 01fbdd38e3b..5abae34ad65 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -652,7 +652,7 @@ aoecmd_ata_rsp(struct sk_buff *skb) disk_stat_add(disk, sectors[rw], n_sect); disk_stat_add(disk, io_ticks, duration); n = (buf->flags & BUFFL_FAIL) ? -EIO : 0; - bio_endio(buf->bio, buf->bio->bi_size, n); + bio_endio(buf->bio, n); mempool_free(buf, d->bufpool); } } diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c index 05a97197c91..51f50710e5f 100644 --- a/drivers/block/aoe/aoedev.c +++ b/drivers/block/aoe/aoedev.c @@ -119,7 +119,7 @@ aoedev_downdev(struct aoedev *d) bio = buf->bio; if (--buf->nframesout == 0) { mempool_free(buf, d->bufpool); - bio_endio(bio, bio->bi_size, -EIO); + bio_endio(bio, -EIO); } skb_shinfo(f->skb)->nr_frags = f->skb->data_len = 0; } @@ -130,7 +130,7 @@ aoedev_downdev(struct aoedev *d) list_del(d->bufq.next); bio = buf->bio; mempool_free(buf, d->bufpool); - bio_endio(bio, bio->bi_size, -EIO); + bio_endio(bio, -EIO); } if (d->gd) diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 084358a828e..28d145756f6 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -1194,7 +1194,7 @@ static inline void complete_buffers(struct bio *bio, int status) int nr_sectors = bio_sectors(bio); bio->bi_next = NULL; - bio_endio(bio, nr_sectors << 9, status ? 0 : -EIO); + bio_endio(bio, status ? 0 : -EIO); bio = xbh; } } diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c index eb9799acf65..3853c9a38d6 100644 --- a/drivers/block/cpqarray.c +++ b/drivers/block/cpqarray.c @@ -987,7 +987,7 @@ static inline void complete_buffers(struct bio *bio, int ok) xbh = bio->bi_next; bio->bi_next = NULL; - bio_endio(bio, nr_sectors << 9, ok ? 0 : -EIO); + bio_endio(bio, ok ? 0 : -EIO); bio = xbh; } diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index f0a86e201b4..80483aac4cc 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -3810,14 +3810,10 @@ static int check_floppy_change(struct gendisk *disk) * a disk in the drive, and whether that disk is writable. */ -static int floppy_rb0_complete(struct bio *bio, unsigned int bytes_done, +static void floppy_rb0_complete(struct bio *bio, int err) { - if (bio->bi_size) - return 1; - complete((struct completion *)bio->bi_private); - return 0; } static int __floppy_read_block_0(struct block_device *bdev) diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 9f015fce413..b9233a06934 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -551,7 +551,7 @@ static int loop_make_request(struct request_queue *q, struct bio *old_bio) out: spin_unlock_irq(&lo->lo_lock); - bio_io_error(old_bio, old_bio->bi_size); + bio_io_error(old_bio); return 0; } @@ -580,7 +580,7 @@ static inline void loop_handle_bio(struct loop_device *lo, struct bio *bio) bio_put(bio); } else { int ret = do_bio_filebacked(lo, bio); - bio_endio(bio, bio->bi_size, ret); + bio_endio(bio, ret); } } diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index fadbfd880ba..540bf367698 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -1058,15 +1058,12 @@ static void pkt_make_local_copy(struct packet_data *pkt, struct bio_vec *bvec) } } -static int pkt_end_io_read(struct bio *bio, unsigned int bytes_done, int err) +static void pkt_end_io_read(struct bio *bio, int err) { struct packet_data *pkt = bio->bi_private; struct pktcdvd_device *pd = pkt->pd; BUG_ON(!pd); - if (bio->bi_size) - return 1; - VPRINTK("pkt_end_io_read: bio=%p sec0=%llx sec=%llx err=%d\n", bio, (unsigned long long)pkt->sector, (unsigned long long)bio->bi_sector, err); @@ -1077,19 +1074,14 @@ static int pkt_end_io_read(struct bio *bio, unsigned int bytes_done, int err) wake_up(&pd->wqueue); } pkt_bio_finished(pd); - - return 0; } -static int pkt_end_io_packet_write(struct bio *bio, unsigned int bytes_done, int err) +static void pkt_end_io_packet_write(struct bio *bio, int err) { struct packet_data *pkt = bio->bi_private; struct pktcdvd_device *pd = pkt->pd; BUG_ON(!pd); - if (bio->bi_size) - return 1; - VPRINTK("pkt_end_io_packet_write: id=%d, err=%d\n", pkt->id, err); pd->stats.pkt_ended++; @@ -1098,7 +1090,6 @@ static int pkt_end_io_packet_write(struct bio *bio, unsigned int bytes_done, int atomic_dec(&pkt->io_wait); atomic_inc(&pkt->run_sm); wake_up(&pd->wqueue); - return 0; } /* @@ -1470,7 +1461,7 @@ static void pkt_finish_packet(struct packet_data *pkt, int uptodate) while (bio) { next = bio->bi_next; bio->bi_next = NULL; - bio_endio(bio, bio->bi_size, uptodate ? 0 : -EIO); + bio_endio(bio, uptodate ? 0 : -EIO); bio = next; } pkt->orig_bios = pkt->orig_bios_tail = NULL; @@ -2462,19 +2453,15 @@ static int pkt_close(struct inode *inode, struct file *file) } -static int pkt_end_io_read_cloned(struct bio *bio, unsigned int bytes_done, int err) +static void pkt_end_io_read_cloned(struct bio *bio, int err) { struct packet_stacked_data *psd = bio->bi_private; struct pktcdvd_device *pd = psd->pd; - if (bio->bi_size) - return 1; - bio_put(bio); - bio_endio(psd->bio, psd->bio->bi_size, err); + bio_endio(psd->bio, err); mempool_free(psd, psd_pool); pkt_bio_finished(pd); - return 0; } static int pkt_make_request(struct request_queue *q, struct bio *bio) @@ -2620,7 +2607,7 @@ static int pkt_make_request(struct request_queue *q, struct bio *bio) } return 0; end_io: - bio_io_error(bio, bio->bi_size); + bio_io_error(bio); return 0; } diff --git a/drivers/block/rd.c b/drivers/block/rd.c index 65150b548f3..701ea77f62e 100644 --- a/drivers/block/rd.c +++ b/drivers/block/rd.c @@ -287,10 +287,10 @@ static int rd_make_request(struct request_queue *q, struct bio *bio) if (ret) goto fail; - bio_endio(bio, bio->bi_size, 0); + bio_endio(bio, 0); return 0; fail: - bio_io_error(bio, bio->bi_size); + bio_io_error(bio); return 0; } diff --git a/drivers/block/umem.c b/drivers/block/umem.c index c378e285d70..be7fac86725 100644 --- a/drivers/block/umem.c +++ b/drivers/block/umem.c @@ -545,7 +545,7 @@ static void process_page(unsigned long data) return_bio = bio->bi_next; bio->bi_next = NULL; - bio_endio(bio, bio->bi_size, 0); + bio_endio(bio, 0); } } diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index bdc52d6922b..8216a6f75be 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -489,7 +489,7 @@ static void dec_pending(struct dm_crypt_io *io, int error) if (!atomic_dec_and_test(&io->pending)) return; - bio_endio(io->base_bio, io->base_bio->bi_size, io->error); + bio_endio(io->base_bio, io->error); mempool_free(io, cc->io_pool); } @@ -509,25 +509,19 @@ static void kcryptd_queue_io(struct dm_crypt_io *io) queue_work(_kcryptd_workqueue, &io->work); } -static int crypt_endio(struct bio *clone, unsigned int done, int error) +static void crypt_endio(struct bio *clone, int error) { struct dm_crypt_io *io = clone->bi_private; struct crypt_config *cc = io->target->private; unsigned read_io = bio_data_dir(clone) == READ; /* - * free the processed pages, even if - * it's only a partially completed write + * free the processed pages */ - if (!read_io) - crypt_free_buffer_pages(cc, clone, done); - - /* keep going - not finished yet */ - if (unlikely(clone->bi_size)) - return 1; - - if (!read_io) + if (!read_io) { + crypt_free_buffer_pages(cc, clone, clone->bi_size); goto out; + } if (unlikely(!bio_flagged(clone, BIO_UPTODATE))) { error = -EIO; @@ -537,12 +531,11 @@ static int crypt_endio(struct bio *clone, unsigned int done, int error) bio_put(clone); io->post_process = 1; kcryptd_queue_io(io); - return 0; + return; out: bio_put(clone); dec_pending(io, error); - return error; } static void clone_init(struct dm_crypt_io *io, struct bio *clone) diff --git a/drivers/md/dm-emc.c b/drivers/md/dm-emc.c index 71cc858b786..a2191a4fcf7 100644 --- a/drivers/md/dm-emc.c +++ b/drivers/md/dm-emc.c @@ -38,13 +38,10 @@ static inline void free_bio(struct bio *bio) bio_put(bio); } -static int emc_endio(struct bio *bio, unsigned int bytes_done, int error) +static void emc_endio(struct bio *bio, int error) { struct dm_path *path = bio->bi_private; - if (bio->bi_size) - return 1; - /* We also need to look at the sense keys here whether or not to * switch to the next PG etc. * diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c index f3a77248643..b8e342fe758 100644 --- a/drivers/md/dm-io.c +++ b/drivers/md/dm-io.c @@ -124,15 +124,11 @@ static void dec_count(struct io *io, unsigned int region, int error) } } -static int endio(struct bio *bio, unsigned int done, int error) +static void endio(struct bio *bio, int error) { struct io *io; unsigned region; - /* keep going until we've finished */ - if (bio->bi_size) - return 1; - if (error && bio_data_dir(bio) == READ) zero_fill_bio(bio); @@ -146,8 +142,6 @@ static int endio(struct bio *bio, unsigned int done, int error) bio_put(bio); dec_count(io, region, error); - - return 0; } /*----------------------------------------------------------------- diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index d6ca9d0a6fd..31056abca89 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -390,11 +390,11 @@ static void dispatch_queued_ios(struct multipath *m) r = map_io(m, bio, mpio, 1); if (r < 0) - bio_endio(bio, bio->bi_size, r); + bio_endio(bio, r); else if (r == DM_MAPIO_REMAPPED) generic_make_request(bio); else if (r == DM_MAPIO_REQUEUE) - bio_endio(bio, bio->bi_size, -EIO); + bio_endio(bio, -EIO); bio = next; } diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index 144071e70a9..d09ff15490a 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c @@ -820,7 +820,7 @@ static void write_callback(unsigned long error, void *context) break; } } - bio_endio(bio, bio->bi_size, 0); + bio_endio(bio, 0); } static void do_write(struct mirror_set *ms, struct bio *bio) @@ -900,7 +900,7 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes) */ if (unlikely(ms->log_failure)) while ((bio = bio_list_pop(&sync))) - bio_endio(bio, bio->bi_size, -EIO); + bio_endio(bio, -EIO); else while ((bio = bio_list_pop(&sync))) do_write(ms, bio); diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index 83ddbfe6b8a..98a633f3d6b 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c @@ -636,7 +636,7 @@ static void error_bios(struct bio *bio) while (bio) { n = bio->bi_next; bio->bi_next = NULL; - bio_io_error(bio, bio->bi_size); + bio_io_error(bio); bio = n; } } diff --git a/drivers/md/dm-zero.c b/drivers/md/dm-zero.c index f314d7dc9c2..bdec206c404 100644 --- a/drivers/md/dm-zero.c +++ b/drivers/md/dm-zero.c @@ -43,7 +43,7 @@ static int zero_map(struct dm_target *ti, struct bio *bio, break; } - bio_endio(bio, bio->bi_size, 0); + bio_endio(bio, 0); /* accepted bio, don't make new request */ return DM_MAPIO_SUBMITTED; diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 2120155929a..167765c4774 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -484,23 +484,20 @@ static void dec_pending(struct dm_io *io, int error) blk_add_trace_bio(io->md->queue, io->bio, BLK_TA_COMPLETE); - bio_endio(io->bio, io->bio->bi_size, io->error); + bio_endio(io->bio, io->error); } free_io(io->md, io); } } -static int clone_endio(struct bio *bio, unsigned int done, int error) +static void clone_endio(struct bio *bio, int error) { int r = 0; struct dm_target_io *tio = bio->bi_private; struct mapped_device *md = tio->io->md; dm_endio_fn endio = tio->ti->type->end_io; - if (bio->bi_size) - return 1; - if (!bio_flagged(bio, BIO_UPTODATE) && !error) error = -EIO; @@ -514,7 +511,7 @@ static int clone_endio(struct bio *bio, unsigned int done, int error) error = r; else if (r == DM_ENDIO_INCOMPLETE) /* The target will handle the io */ - return 1; + return; else if (r) { DMWARN("unimplemented target endio return value: %d", r); BUG(); @@ -530,7 +527,6 @@ static int clone_endio(struct bio *bio, unsigned int done, int error) bio_put(bio); free_tio(md, tio); - return r; } static sector_t max_io_len(struct mapped_device *md, @@ -761,7 +757,7 @@ static void __split_bio(struct mapped_device *md, struct bio *bio) ci.map = dm_get_table(md); if (!ci.map) { - bio_io_error(bio, bio->bi_size); + bio_io_error(bio); return; } @@ -803,7 +799,7 @@ static int dm_request(struct request_queue *q, struct bio *bio) * guarantee it is (or can be) handled by the targets correctly. */ if (unlikely(bio_barrier(bio))) { - bio_endio(bio, bio->bi_size, -EOPNOTSUPP); + bio_endio(bio, -EOPNOTSUPP); return 0; } @@ -820,13 +816,13 @@ static int dm_request(struct request_queue *q, struct bio *bio) up_read(&md->io_lock); if (bio_rw(bio) == READA) { - bio_io_error(bio, bio->bi_size); + bio_io_error(bio); return 0; } r = queue_io(md, bio); if (r < 0) { - bio_io_error(bio, bio->bi_size); + bio_io_error(bio); return 0; } else if (r == 0) diff --git a/drivers/md/faulty.c b/drivers/md/faulty.c index cb059cf14c2..cf2ddce3411 100644 --- a/drivers/md/faulty.c +++ b/drivers/md/faulty.c @@ -65,18 +65,16 @@ #include -static int faulty_fail(struct bio *bio, unsigned int bytes_done, int error) +static void faulty_fail(struct bio *bio, int error) { struct bio *b = bio->bi_private; b->bi_size = bio->bi_size; b->bi_sector = bio->bi_sector; - if (bio->bi_size == 0) - bio_put(bio); + bio_put(bio); - clear_bit(BIO_UPTODATE, &b->bi_flags); - return (b->bi_end_io)(b, bytes_done, -EIO); + bio_io_error(b); } typedef struct faulty_conf { @@ -179,7 +177,7 @@ static int make_request(struct request_queue *q, struct bio *bio) /* special case - don't decrement, don't generic_make_request, * just fail immediately */ - bio_endio(bio, bio->bi_size, -EIO); + bio_endio(bio, -EIO); return 0; } diff --git a/drivers/md/linear.c b/drivers/md/linear.c index 17f795c3e0a..550148770bb 100644 --- a/drivers/md/linear.c +++ b/drivers/md/linear.c @@ -338,7 +338,7 @@ static int linear_make_request (struct request_queue *q, struct bio *bio) sector_t block; if (unlikely(bio_barrier(bio))) { - bio_endio(bio, bio->bi_size, -EOPNOTSUPP); + bio_endio(bio, -EOPNOTSUPP); return 0; } @@ -358,7 +358,7 @@ static int linear_make_request (struct request_queue *q, struct bio *bio) bdevname(tmp_dev->rdev->bdev, b), (unsigned long long)tmp_dev->size, (unsigned long long)tmp_dev->offset); - bio_io_error(bio, bio->bi_size); + bio_io_error(bio); return 0; } if (unlikely(bio->bi_sector + (bio->bi_size >> 9) > diff --git a/drivers/md/md.c b/drivers/md/md.c index f883b7e37f3..e8f102ea9b0 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -213,7 +213,7 @@ static DEFINE_SPINLOCK(all_mddevs_lock); static int md_fail_request (struct request_queue *q, struct bio *bio) { - bio_io_error(bio, bio->bi_size); + bio_io_error(bio); return 0; } @@ -384,12 +384,10 @@ static void free_disk_sb(mdk_rdev_t * rdev) } -static int super_written(struct bio *bio, unsigned int bytes_done, int error) +static void super_written(struct bio *bio, int error) { mdk_rdev_t *rdev = bio->bi_private; mddev_t *mddev = rdev->mddev; - if (bio->bi_size) - return 1; if (error || !test_bit(BIO_UPTODATE, &bio->bi_flags)) { printk("md: super_written gets error=%d, uptodate=%d\n", @@ -401,16 +399,13 @@ static int super_written(struct bio *bio, unsigned int bytes_done, int error) if (atomic_dec_and_test(&mddev->pending_writes)) wake_up(&mddev->sb_wait); bio_put(bio); - return 0; } -static int super_written_barrier(struct bio *bio, unsigned int bytes_done, int error) +static void super_written_barrier(struct bio *bio, int error) { struct bio *bio2 = bio->bi_private; mdk_rdev_t *rdev = bio2->bi_private; mddev_t *mddev = rdev->mddev; - if (bio->bi_size) - return 1; if (!test_bit(BIO_UPTODATE, &bio->bi_flags) && error == -EOPNOTSUPP) { @@ -424,11 +419,11 @@ static int super_written_barrier(struct bio *bio, unsigned int bytes_done, int e spin_unlock_irqrestore(&mddev->write_lock, flags); wake_up(&mddev->sb_wait); bio_put(bio); - return 0; + } else { + bio_put(bio2); + bio->bi_private = rdev; + super_written(bio, error); } - bio_put(bio2); - bio->bi_private = rdev; - return super_written(bio, bytes_done, error); } void md_super_write(mddev_t *mddev, mdk_rdev_t *rdev, @@ -489,13 +484,9 @@ void md_super_wait(mddev_t *mddev) finish_wait(&mddev->sb_wait, &wq); } -static int bi_complete(struct bio *bio, unsigned int bytes_done, int error) +static void bi_complete(struct bio *bio, int error) { - if (bio->bi_size) - return 1; - complete((struct completion*)bio->bi_private); - return 0; } int sync_page_io(struct block_device *bdev, sector_t sector, int size, diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index 1e2af43a73b..f2a63f394ad 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -82,21 +82,17 @@ static void multipath_end_bh_io (struct multipath_bh *mp_bh, int err) struct bio *bio = mp_bh->master_bio; multipath_conf_t *conf = mddev_to_conf(mp_bh->mddev); - bio_endio(bio, bio->bi_size, err); + bio_endio(bio, err); mempool_free(mp_bh, conf->pool); } -static int multipath_end_request(struct bio *bio, unsigned int bytes_done, - int error) +static void multipath_end_request(struct bio *bio, int error) { int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct multipath_bh * mp_bh = (struct multipath_bh *)(bio->bi_private); multipath_conf_t *conf = mddev_to_conf(mp_bh->mddev); mdk_rdev_t *rdev = conf->multipaths[mp_bh->path].rdev; - if (bio->bi_size) - return 1; - if (uptodate) multipath_end_bh_io(mp_bh, 0); else if (!bio_rw_ahead(bio)) { @@ -112,7 +108,6 @@ static int multipath_end_request(struct bio *bio, unsigned int bytes_done, } else multipath_end_bh_io(mp_bh, error); rdev_dec_pending(rdev, conf->mddev); - return 0; } static void unplug_slaves(mddev_t *mddev) @@ -155,7 +150,7 @@ static int multipath_make_request (struct request_queue *q, struct bio * bio) const int rw = bio_data_dir(bio); if (unlikely(bio_barrier(bio))) { - bio_endio(bio, bio->bi_size, -EOPNOTSUPP); + bio_endio(bio, -EOPNOTSUPP); return 0; } @@ -169,7 +164,7 @@ static int multipath_make_request (struct request_queue *q, struct bio * bio) mp_bh->path = multipath_map(conf); if (mp_bh->path < 0) { - bio_endio(bio, bio->bi_size, -EIO); + bio_endio(bio, -EIO); mempool_free(mp_bh, conf->pool); return 0; } diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index b8216bc6db4..ef0da2d8495 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -420,7 +420,7 @@ static int raid0_make_request (struct request_queue *q, struct bio *bio) const int rw = bio_data_dir(bio); if (unlikely(bio_barrier(bio))) { - bio_endio(bio, bio->bi_size, -EOPNOTSUPP); + bio_endio(bio, -EOPNOTSUPP); return 0; } @@ -490,7 +490,7 @@ bad_map: " or bigger than %dk %llu %d\n", chunk_size, (unsigned long long)bio->bi_sector, bio->bi_size >> 10); - bio_io_error(bio, bio->bi_size); + bio_io_error(bio); return 0; } diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index f33a729960c..6d03bea6fa5 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -238,7 +238,7 @@ static void raid_end_bio_io(r1bio_t *r1_bio) (unsigned long long) bio->bi_sector + (bio->bi_size >> 9) - 1); - bio_endio(bio, bio->bi_size, + bio_endio(bio, test_bit(R1BIO_Uptodate, &r1_bio->state) ? 0 : -EIO); } free_r1bio(r1_bio); @@ -255,16 +255,13 @@ static inline void update_head_pos(int disk, r1bio_t *r1_bio) r1_bio->sector + (r1_bio->sectors); } -static int raid1_end_read_request(struct bio *bio, unsigned int bytes_done, int error) +static void raid1_end_read_request(struct bio *bio, int error) { int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); r1bio_t * r1_bio = (r1bio_t *)(bio->bi_private); int mirror; conf_t *conf = mddev_to_conf(r1_bio->mddev); - if (bio->bi_size) - return 1; - mirror = r1_bio->read_disk; /* * this branch is our 'one mirror IO has finished' event handler: @@ -301,10 +298,9 @@ static int raid1_end_read_request(struct bio *bio, unsigned int bytes_done, int } rdev_dec_pending(conf->mirrors[mirror].rdev, conf->mddev); - return 0; } -static int raid1_end_write_request(struct bio *bio, unsigned int bytes_done, int error) +static void raid1_end_write_request(struct bio *bio, int error) { int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); r1bio_t * r1_bio = (r1bio_t *)(bio->bi_private); @@ -312,8 +308,6 @@ static int raid1_end_write_request(struct bio *bio, unsigned int bytes_done, int conf_t *conf = mddev_to_conf(r1_bio->mddev); struct bio *to_put = NULL; - if (bio->bi_size) - return 1; for (mirror = 0; mirror < conf->raid_disks; mirror++) if (r1_bio->bios[mirror] == bio) @@ -366,7 +360,7 @@ static int raid1_end_write_request(struct bio *bio, unsigned int bytes_done, int (unsigned long long) mbio->bi_sector, (unsigned long long) mbio->bi_sector + (mbio->bi_size >> 9) - 1); - bio_endio(mbio, mbio->bi_size, 0); + bio_endio(mbio, 0); } } } @@ -400,8 +394,6 @@ static int raid1_end_write_request(struct bio *bio, unsigned int bytes_done, int if (to_put) bio_put(to_put); - - return 0; } @@ -796,7 +788,7 @@ static int make_request(struct request_queue *q, struct bio * bio) if (unlikely(!mddev->barriers_work && bio_barrier(bio))) { if (rw == WRITE) md_write_end(mddev); - bio_endio(bio, bio->bi_size, -EOPNOTSUPP); + bio_endio(bio, -EOPNOTSUPP); return 0; } @@ -1137,14 +1129,11 @@ abort: } -static int end_sync_read(struct bio *bio, unsigned int bytes_done, int error) +static void end_sync_read(struct bio *bio, int error) { r1bio_t * r1_bio = (r1bio_t *)(bio->bi_private); int i; - if (bio->bi_size) - return 1; - for (i=r1_bio->mddev->raid_disks; i--; ) if (r1_bio->bios[i] == bio) break; @@ -1160,10 +1149,9 @@ static int end_sync_read(struct bio *bio, unsigned int bytes_done, int error) if (atomic_dec_and_test(&r1_bio->remaining)) reschedule_retry(r1_bio); - return 0; } -static int end_sync_write(struct bio *bio, unsigned int bytes_done, int error) +static void end_sync_write(struct bio *bio, int error) { int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); r1bio_t * r1_bio = (r1bio_t *)(bio->bi_private); @@ -1172,9 +1160,6 @@ static int end_sync_write(struct bio *bio, unsigned int bytes_done, int error) int i; int mirror=0; - if (bio->bi_size) - return 1; - for (i = 0; i < conf->raid_disks; i++) if (r1_bio->bios[i] == bio) { mirror = i; @@ -1200,7 +1185,6 @@ static int end_sync_write(struct bio *bio, unsigned int bytes_done, int error) md_done_sync(mddev, r1_bio->sectors, uptodate); put_buf(r1_bio); } - return 0; } static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio) diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 4e53792aa52..25a96c42bdb 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -227,7 +227,7 @@ static void raid_end_bio_io(r10bio_t *r10_bio) { struct bio *bio = r10_bio->master_bio; - bio_endio(bio, bio->bi_size, + bio_endio(bio, test_bit(R10BIO_Uptodate, &r10_bio->state) ? 0 : -EIO); free_r10bio(r10_bio); } @@ -243,15 +243,13 @@ static inline void update_head_pos(int slot, r10bio_t *r10_bio) r10_bio->devs[slot].addr + (r10_bio->sectors); } -static int raid10_end_read_request(struct bio *bio, unsigned int bytes_done, int error) +static void raid10_end_read_request(struct bio *bio, int error) { int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); r10bio_t * r10_bio = (r10bio_t *)(bio->bi_private); int slot, dev; conf_t *conf = mddev_to_conf(r10_bio->mddev); - if (bio->bi_size) - return 1; slot = r10_bio->read_slot; dev = r10_bio->devs[slot].devnum; @@ -284,19 +282,15 @@ static int raid10_end_read_request(struct bio *bio, unsigned int bytes_done, int } rdev_dec_pending(conf->mirrors[dev].rdev, conf->mddev); - return 0; } -static int raid10_end_write_request(struct bio *bio, unsigned int bytes_done, int error) +static void raid10_end_write_request(struct bio *bio, int error) { int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); r10bio_t * r10_bio = (r10bio_t *)(bio->bi_private); int slot, dev; conf_t *conf = mddev_to_conf(r10_bio->mddev); - if (bio->bi_size) - return 1; - for (slot = 0; slot < conf->copies; slot++) if (r10_bio->devs[slot].bio == bio) break; @@ -339,7 +333,6 @@ static int raid10_end_write_request(struct bio *bio, unsigned int bytes_done, in } rdev_dec_pending(conf->mirrors[dev].rdev, conf->mddev); - return 0; } @@ -787,7 +780,7 @@ static int make_request(struct request_queue *q, struct bio * bio) unsigned long flags; if (unlikely(bio_barrier(bio))) { - bio_endio(bio, bio->bi_size, -EOPNOTSUPP); + bio_endio(bio, -EOPNOTSUPP); return 0; } @@ -819,7 +812,7 @@ static int make_request(struct request_queue *q, struct bio * bio) " or bigger than %dk %llu %d\n", chunk_sects/2, (unsigned long long)bio->bi_sector, bio->bi_size >> 10); - bio_io_error(bio, bio->bi_size); + bio_io_error(bio); return 0; } @@ -1155,15 +1148,12 @@ abort: } -static int end_sync_read(struct bio *bio, unsigned int bytes_done, int error) +static void end_sync_read(struct bio *bio, int error) { r10bio_t * r10_bio = (r10bio_t *)(bio->bi_private); conf_t *conf = mddev_to_conf(r10_bio->mddev); int i,d; - if (bio->bi_size) - return 1; - for (i=0; icopies; i++) if (r10_bio->devs[i].bio == bio) break; @@ -1192,10 +1182,9 @@ static int end_sync_read(struct bio *bio, unsigned int bytes_done, int error) reschedule_retry(r10_bio); } rdev_dec_pending(conf->mirrors[d].rdev, conf->mddev); - return 0; } -static int end_sync_write(struct bio *bio, unsigned int bytes_done, int error) +static void end_sync_write(struct bio *bio, int error) { int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); r10bio_t * r10_bio = (r10bio_t *)(bio->bi_private); @@ -1203,9 +1192,6 @@ static int end_sync_write(struct bio *bio, unsigned int bytes_done, int error) conf_t *conf = mddev_to_conf(mddev); int i,d; - if (bio->bi_size) - return 1; - for (i = 0; i < conf->copies; i++) if (r10_bio->devs[i].bio == bio) break; @@ -1228,7 +1214,6 @@ static int end_sync_write(struct bio *bio, unsigned int bytes_done, int error) } } rdev_dec_pending(conf->mirrors[d].rdev, mddev); - return 0; } /* @@ -1374,7 +1359,7 @@ static void recovery_request_write(mddev_t *mddev, r10bio_t *r10_bio) if (test_bit(R10BIO_Uptodate, &r10_bio->state)) generic_make_request(wbio); else - bio_endio(wbio, wbio->bi_size, -EIO); + bio_endio(wbio, -EIO); } diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index f96dea975fa..caaca9e178b 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -108,12 +108,11 @@ static void return_io(struct bio *return_bi) { struct bio *bi = return_bi; while (bi) { - int bytes = bi->bi_size; return_bi = bi->bi_next; bi->bi_next = NULL; bi->bi_size = 0; - bi->bi_end_io(bi, bytes, + bi->bi_end_io(bi, test_bit(BIO_UPTODATE, &bi->bi_flags) ? 0 : -EIO); bi = return_bi; @@ -382,10 +381,10 @@ static unsigned long get_stripe_work(struct stripe_head *sh) return pending; } -static int -raid5_end_read_request(struct bio *bi, unsigned int bytes_done, int error); -static int -raid5_end_write_request (struct bio *bi, unsigned int bytes_done, int error); +static void +raid5_end_read_request(struct bio *bi, int error); +static void +raid5_end_write_request(struct bio *bi, int error); static void ops_run_io(struct stripe_head *sh) { @@ -1110,8 +1109,7 @@ static void shrink_stripes(raid5_conf_t *conf) conf->slab_cache = NULL; } -static int raid5_end_read_request(struct bio * bi, unsigned int bytes_done, - int error) +static void raid5_end_read_request(struct bio * bi, int error) { struct stripe_head *sh = bi->bi_private; raid5_conf_t *conf = sh->raid_conf; @@ -1120,8 +1118,6 @@ static int raid5_end_read_request(struct bio * bi, unsigned int bytes_done, char b[BDEVNAME_SIZE]; mdk_rdev_t *rdev; - if (bi->bi_size) - return 1; for (i=0 ; idev[i].req) @@ -1132,7 +1128,7 @@ static int raid5_end_read_request(struct bio * bi, unsigned int bytes_done, uptodate); if (i == disks) { BUG(); - return 0; + return; } if (uptodate) { @@ -1185,20 +1181,15 @@ static int raid5_end_read_request(struct bio * bi, unsigned int bytes_done, clear_bit(R5_LOCKED, &sh->dev[i].flags); set_bit(STRIPE_HANDLE, &sh->state); release_stripe(sh); - return 0; } -static int raid5_end_write_request (struct bio *bi, unsigned int bytes_done, - int error) +static void raid5_end_write_request (struct bio *bi, int error) { struct stripe_head *sh = bi->bi_private; raid5_conf_t *conf = sh->raid_conf; int disks = sh->disks, i; int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags); - if (bi->bi_size) - return 1; - for (i=0 ; idev[i].req) break; @@ -1208,7 +1199,7 @@ static int raid5_end_write_request (struct bio *bi, unsigned int bytes_done, uptodate); if (i == disks) { BUG(); - return 0; + return; } if (!uptodate) @@ -1219,7 +1210,6 @@ static int raid5_end_write_request (struct bio *bi, unsigned int bytes_done, clear_bit(R5_LOCKED, &sh->dev[i].flags); set_bit(STRIPE_HANDLE, &sh->state); release_stripe(sh); - return 0; } @@ -3340,7 +3330,7 @@ static struct bio *remove_bio_from_retry(raid5_conf_t *conf) * first). * If the read failed.. */ -static int raid5_align_endio(struct bio *bi, unsigned int bytes, int error) +static void raid5_align_endio(struct bio *bi, int error) { struct bio* raid_bi = bi->bi_private; mddev_t *mddev; @@ -3348,8 +3338,6 @@ static int raid5_align_endio(struct bio *bi, unsigned int bytes, int error) int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags); mdk_rdev_t *rdev; - if (bi->bi_size) - return 1; bio_put(bi); mddev = raid_bi->bi_bdev->bd_disk->queue->queuedata; @@ -3360,17 +3348,16 @@ static int raid5_align_endio(struct bio *bi, unsigned int bytes, int error) rdev_dec_pending(rdev, conf->mddev); if (!error && uptodate) { - bio_endio(raid_bi, bytes, 0); + bio_endio(raid_bi, 0); if (atomic_dec_and_test(&conf->active_aligned_reads)) wake_up(&conf->wait_for_stripe); - return 0; + return; } pr_debug("raid5_align_endio : io error...handing IO for a retry\n"); add_bio_to_retry(raid_bi, conf); - return 0; } static int bio_fits_rdev(struct bio *bi) @@ -3476,7 +3463,7 @@ static int make_request(struct request_queue *q, struct bio * bi) int remaining; if (unlikely(bio_barrier(bi))) { - bio_endio(bi, bi->bi_size, -EOPNOTSUPP); + bio_endio(bi, -EOPNOTSUPP); return 0; } @@ -3592,12 +3579,11 @@ static int make_request(struct request_queue *q, struct bio * bi) remaining = --bi->bi_phys_segments; spin_unlock_irq(&conf->device_lock); if (remaining == 0) { - int bytes = bi->bi_size; if ( rw == WRITE ) md_write_end(mddev); - bi->bi_size = 0; - bi->bi_end_io(bi, bytes, + + bi->bi_end_io(bi, test_bit(BIO_UPTODATE, &bi->bi_flags) ? 0 : -EIO); } @@ -3875,10 +3861,8 @@ static int retry_aligned_read(raid5_conf_t *conf, struct bio *raid_bio) remaining = --raid_bio->bi_phys_segments; spin_unlock_irq(&conf->device_lock); if (remaining == 0) { - int bytes = raid_bio->bi_size; - raid_bio->bi_size = 0; - raid_bio->bi_end_io(raid_bio, bytes, + raid_bio->bi_end_io(raid_bio, test_bit(BIO_UPTODATE, &raid_bio->bi_flags) ? 0 : -EIO); } diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index 4d8798bacf9..859f870552e 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -674,10 +674,10 @@ dcssblk_make_request(struct request_queue *q, struct bio *bio) } bytes_done += bvec->bv_len; } - bio_endio(bio, bytes_done, 0); + bio_endio(bio, 0); return 0; fail: - bio_io_error(bio, bio->bi_size); + bio_io_error(bio); return 0; } diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c index 354a060e5be..0fbacc8b106 100644 --- a/drivers/s390/block/xpram.c +++ b/drivers/s390/block/xpram.c @@ -230,12 +230,10 @@ static int xpram_make_request(struct request_queue *q, struct bio *bio) } } set_bit(BIO_UPTODATE, &bio->bi_flags); - bytes = bio->bi_size; - bio->bi_size = 0; - bio->bi_end_io(bio, bytes, 0); + bio_end_io(bio, 0); return 0; fail: - bio_io_error(bio, bio->bi_size); + bio_io_error(bio); return 0; } diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 59b39853029..604f4d71793 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -266,13 +266,9 @@ static int scsi_merge_bio(struct request *rq, struct bio *bio) return blk_rq_append_bio(q, rq, bio); } -static int scsi_bi_endio(struct bio *bio, unsigned int bytes_done, int error) +static void scsi_bi_endio(struct bio *bio, int error) { - if (bio->bi_size) - return 1; - bio_put(bio); - return 0; } /** @@ -328,7 +324,7 @@ static int scsi_req_map_sg(struct request *rq, struct scatterlist *sgl, if (bio->bi_vcnt >= nr_vecs) { err = scsi_merge_bio(rq, bio); if (err) { - bio_endio(bio, bio->bi_size, 0); + bio_endio(bio, 0); goto free_bios; } bio = NULL; @@ -350,7 +346,7 @@ free_bios: /* * call endio instead of bio_put incase it was bounced */ - bio_endio(bio, bio->bi_size, 0); + bio_endio(bio, 0); } return err; diff --git a/fs/bio.c b/fs/bio.c index 3adecd64ff6..5f604f269df 100644 --- a/fs/bio.c +++ b/fs/bio.c @@ -798,13 +798,9 @@ void bio_unmap_user(struct bio *bio) bio_put(bio); } -static int bio_map_kern_endio(struct bio *bio, unsigned int bytes_done, int err) +static void bio_map_kern_endio(struct bio *bio, int err) { - if (bio->bi_size) - return 1; - bio_put(bio); - return 0; } @@ -1002,12 +998,10 @@ void bio_check_pages_dirty(struct bio *bio) /** * bio_endio - end I/O on a bio * @bio: bio - * @bytes_done: number of bytes completed * @error: error, if any * * Description: - * bio_endio() will end I/O on @bytes_done number of bytes. This - * must always be the whole (remaining) bio. bio_endio() is the + * bio_endio() will end I/O on the whole bio. bio_endio() is the * preferred way to end I/O on a bio, it takes care of clearing * BIO_UPTODATE on error. @error is 0 on success, and and one of the * established -Exxxx (-EIO, for instance) error values in case @@ -1015,22 +1009,15 @@ void bio_check_pages_dirty(struct bio *bio) * bio unless they own it and thus know that it has an end_io * function. **/ -void bio_endio(struct bio *bio, unsigned int bytes_done, int error) +void bio_endio(struct bio *bio, int error) { if (error) clear_bit(BIO_UPTODATE, &bio->bi_flags); else if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) error = -EIO; - if (unlikely(bytes_done != bio->bi_size)) { - printk("%s: want %u bytes done, only %u left\n", __FUNCTION__, - bytes_done, bio->bi_size); - bytes_done = bio->bi_size; - } - - bio->bi_size = 0; /* expected by some callees - will be removed */ if (bio->bi_end_io) - bio->bi_end_io(bio, bytes_done, error); + bio->bi_end_io(bio, error); } void bio_pair_release(struct bio_pair *bp) @@ -1038,37 +1025,29 @@ void bio_pair_release(struct bio_pair *bp) if (atomic_dec_and_test(&bp->cnt)) { struct bio *master = bp->bio1.bi_private; - bio_endio(master, master->bi_size, bp->error); + bio_endio(master, bp->error); mempool_free(bp, bp->bio2.bi_private); } } -static int bio_pair_end_1(struct bio * bi, unsigned int done, int err) +static void bio_pair_end_1(struct bio *bi, int err) { struct bio_pair *bp = container_of(bi, struct bio_pair, bio1); if (err) bp->error = err; - if (bi->bi_size) - return 1; - bio_pair_release(bp); - return 0; } -static int bio_pair_end_2(struct bio * bi, unsigned int done, int err) +static void bio_pair_end_2(struct bio *bi, int err) { struct bio_pair *bp = container_of(bi, struct bio_pair, bio2); if (err) bp->error = err; - if (bi->bi_size) - return 1; - bio_pair_release(bp); - return 0; } /* diff --git a/fs/block_dev.c b/fs/block_dev.c index 2980eabe577..6339a30879b 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -172,7 +172,7 @@ blkdev_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, } #if 0 -static int blk_end_aio(struct bio *bio, unsigned int bytes_done, int error) +static void blk_end_aio(struct bio *bio, int error) { struct kiocb *iocb = bio->bi_private; atomic_t *bio_count = &iocb->ki_bio_count; diff --git a/fs/buffer.c b/fs/buffer.c index 0e5ec371ce7..75b51dfa5e0 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -2634,13 +2634,10 @@ sector_t generic_block_bmap(struct address_space *mapping, sector_t block, return tmp.b_blocknr; } -static int end_bio_bh_io_sync(struct bio *bio, unsigned int bytes_done, int err) +static void end_bio_bh_io_sync(struct bio *bio, int err) { struct buffer_head *bh = bio->bi_private; - if (bio->bi_size) - return 1; - if (err == -EOPNOTSUPP) { set_bit(BIO_EOPNOTSUPP, &bio->bi_flags); set_bit(BH_Eopnotsupp, &bh->b_state); @@ -2648,7 +2645,6 @@ static int end_bio_bh_io_sync(struct bio *bio, unsigned int bytes_done, int err) bh->b_end_io(bh, test_bit(BIO_UPTODATE, &bio->bi_flags)); bio_put(bio); - return 0; } int submit_bh(int rw, struct buffer_head * bh) diff --git a/fs/direct-io.c b/fs/direct-io.c index 901dc55e9f5..b5928a7b6a5 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -264,15 +264,12 @@ static int dio_bio_complete(struct dio *dio, struct bio *bio); /* * Asynchronous IO callback. */ -static int dio_bio_end_aio(struct bio *bio, unsigned int bytes_done, int error) +static void dio_bio_end_aio(struct bio *bio, int error) { struct dio *dio = bio->bi_private; unsigned long remaining; unsigned long flags; - if (bio->bi_size) - return 1; - /* cleanup the bio */ dio_bio_complete(dio, bio); @@ -287,8 +284,6 @@ static int dio_bio_end_aio(struct bio *bio, unsigned int bytes_done, int error) aio_complete(dio->iocb, ret, 0); kfree(dio); } - - return 0; } /* @@ -298,21 +293,17 @@ static int dio_bio_end_aio(struct bio *bio, unsigned int bytes_done, int error) * During I/O bi_private points at the dio. After I/O, bi_private is used to * implement a singly-linked list of completed BIOs, at dio->bio_list. */ -static int dio_bio_end_io(struct bio *bio, unsigned int bytes_done, int error) +static void dio_bio_end_io(struct bio *bio, int error) { struct dio *dio = bio->bi_private; unsigned long flags; - if (bio->bi_size) - return 1; - spin_lock_irqsave(&dio->bio_lock, flags); bio->bi_private = dio->bio_list; dio->bio_list = bio; if (--dio->refcount == 1 && dio->waiter) wake_up_process(dio->waiter); spin_unlock_irqrestore(&dio->bio_lock, flags); - return 0; } static int diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index f916b9740c7..2473e2a86d1 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -160,11 +160,9 @@ int gfs2_check_sb(struct gfs2_sbd *sdp, struct gfs2_sb_host *sb, int silent) } -static int end_bio_io_page(struct bio *bio, unsigned int bytes_done, int error) +static void end_bio_io_page(struct bio *bio, int error) { struct page *page = bio->bi_private; - if (bio->bi_size) - return 1; if (!error) SetPageUptodate(page); diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c index de3e4a506db..57c3b8ac36b 100644 --- a/fs/jfs/jfs_logmgr.c +++ b/fs/jfs/jfs_logmgr.c @@ -2200,16 +2200,13 @@ static int lbmIOWait(struct lbuf * bp, int flag) * * executed at INTIODONE level */ -static int lbmIODone(struct bio *bio, unsigned int bytes_done, int error) +static void lbmIODone(struct bio *bio, int error) { struct lbuf *bp = bio->bi_private; struct lbuf *nextbp, *tail; struct jfs_log *log; unsigned long flags; - if (bio->bi_size) - return 1; - /* * get back jfs buffer bound to the i/o buffer */ diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c index 62e96be02ac..1332adc0b9f 100644 --- a/fs/jfs/jfs_metapage.c +++ b/fs/jfs/jfs_metapage.c @@ -280,14 +280,10 @@ static void last_read_complete(struct page *page) unlock_page(page); } -static int metapage_read_end_io(struct bio *bio, unsigned int bytes_done, - int err) +static void metapage_read_end_io(struct bio *bio, int err) { struct page *page = bio->bi_private; - if (bio->bi_size) - return 1; - if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) { printk(KERN_ERR "metapage_read_end_io: I/O error\n"); SetPageError(page); @@ -341,16 +337,12 @@ static void last_write_complete(struct page *page) end_page_writeback(page); } -static int metapage_write_end_io(struct bio *bio, unsigned int bytes_done, - int err) +static void metapage_write_end_io(struct bio *bio, int err) { struct page *page = bio->bi_private; BUG_ON(!PagePrivate(page)); - if (bio->bi_size) - return 1; - if (! test_bit(BIO_UPTODATE, &bio->bi_flags)) { printk(KERN_ERR "metapage_write_end_io: I/O error\n"); SetPageError(page); diff --git a/fs/mpage.c b/fs/mpage.c index c1698f2291a..b1c3e589050 100644 --- a/fs/mpage.c +++ b/fs/mpage.c @@ -39,14 +39,11 @@ * status of that page is hard. See end_buffer_async_read() for the details. * There is no point in duplicating all that complexity. */ -static int mpage_end_io_read(struct bio *bio, unsigned int bytes_done, int err) +static void mpage_end_io_read(struct bio *bio, int err) { const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1; - if (bio->bi_size) - return 1; - do { struct page *page = bvec->bv_page; @@ -62,17 +59,13 @@ static int mpage_end_io_read(struct bio *bio, unsigned int bytes_done, int err) unlock_page(page); } while (bvec >= bio->bi_io_vec); bio_put(bio); - return 0; } -static int mpage_end_io_write(struct bio *bio, unsigned int bytes_done, int err) +static void mpage_end_io_write(struct bio *bio, int err) { const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1; - if (bio->bi_size) - return 1; - do { struct page *page = bvec->bv_page; @@ -87,7 +80,6 @@ static int mpage_end_io_write(struct bio *bio, unsigned int bytes_done, int err) end_page_writeback(page); } while (bvec >= bio->bi_io_vec); bio_put(bio); - return 0; } static struct bio *mpage_bio_submit(int rw, struct bio *bio) diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c index 2bd7f788cf3..da2c2b442b4 100644 --- a/fs/ocfs2/cluster/heartbeat.c +++ b/fs/ocfs2/cluster/heartbeat.c @@ -217,7 +217,6 @@ static void o2hb_wait_on_io(struct o2hb_region *reg, } static int o2hb_bio_end_io(struct bio *bio, - unsigned int bytes_done, int error) { struct o2hb_bio_wait_ctxt *wc = bio->bi_private; @@ -227,9 +226,6 @@ static int o2hb_bio_end_io(struct bio *bio, wc->wc_error = error; } - if (bio->bi_size) - return 1; - o2hb_bio_wait_dec(wc, 1); bio_put(bio); return 0; diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c index 5f152f60d74..3f13519436a 100644 --- a/fs/xfs/linux-2.6/xfs_aops.c +++ b/fs/xfs/linux-2.6/xfs_aops.c @@ -326,14 +326,10 @@ xfs_iomap_valid( STATIC int xfs_end_bio( struct bio *bio, - unsigned int bytes_done, int error) { xfs_ioend_t *ioend = bio->bi_private; - if (bio->bi_size) - return 1; - ASSERT(atomic_read(&bio->bi_cnt) >= 1); ioend->io_error = test_bit(BIO_UPTODATE, &bio->bi_flags) ? 0 : error; diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index b0f0e58866d..6a75f4d984a 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c @@ -1106,16 +1106,12 @@ _xfs_buf_ioend( STATIC int xfs_buf_bio_end_io( struct bio *bio, - unsigned int bytes_done, int error) { xfs_buf_t *bp = (xfs_buf_t *)bio->bi_private; unsigned int blocksize = bp->b_target->bt_bsize; struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1; - if (bio->bi_size) - return 1; - if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) bp->b_error = EIO; diff --git a/include/linux/bio.h b/include/linux/bio.h index 1ddef34f43c..089a8bc55dd 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -64,7 +64,7 @@ struct bio_vec { struct bio_set; struct bio; -typedef int (bio_end_io_t) (struct bio *, unsigned int, int); +typedef void (bio_end_io_t) (struct bio *, int); typedef void (bio_destructor_t) (struct bio *); /* @@ -226,7 +226,7 @@ struct bio { #define BIO_SEG_BOUNDARY(q, b1, b2) \ BIOVEC_SEG_BOUNDARY((q), __BVEC_END((b1)), __BVEC_START((b2))) -#define bio_io_error(bio, bytes) bio_endio((bio), (bytes), -EIO) +#define bio_io_error(bio) bio_endio((bio), -EIO) /* * drivers should not use the __ version unless they _really_ want to @@ -286,7 +286,7 @@ extern struct bio *bio_alloc_bioset(gfp_t, int, struct bio_set *); extern void bio_put(struct bio *); extern void bio_free(struct bio *, struct bio_set *); -extern void bio_endio(struct bio *, unsigned int, int); +extern void bio_endio(struct bio *, int); struct request_queue; extern int bio_phys_segments(struct request_queue *, struct bio *); extern int bio_hw_segments(struct request_queue *, struct bio *); diff --git a/include/linux/swap.h b/include/linux/swap.h index 665f85f2a3a..edf681a7fd8 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -221,7 +221,7 @@ extern void swap_unplug_io_fn(struct backing_dev_info *, struct page *); /* linux/mm/page_io.c */ extern int swap_readpage(struct file *, struct page *); extern int swap_writepage(struct page *page, struct writeback_control *wbc); -extern int end_swap_bio_read(struct bio *bio, unsigned int bytes_done, int err); +extern void end_swap_bio_read(struct bio *bio, int err); /* linux/mm/swap_state.c */ extern struct address_space swapper_space; diff --git a/mm/bounce.c b/mm/bounce.c index 179fe38a241..3b549bf31f7 100644 --- a/mm/bounce.c +++ b/mm/bounce.c @@ -140,26 +140,19 @@ static void bounce_end_io(struct bio *bio, mempool_t *pool, int err) mempool_free(bvec->bv_page, pool); } - bio_endio(bio_orig, bio_orig->bi_size, err); + bio_endio(bio_orig, err); bio_put(bio); } -static int bounce_end_io_write(struct bio *bio, unsigned int bytes_done, int err) +static void bounce_end_io_write(struct bio *bio, int err) { - if (bio->bi_size) - return 1; - bounce_end_io(bio, page_pool, err); - return 0; } -static int bounce_end_io_write_isa(struct bio *bio, unsigned int bytes_done, int err) +static void bounce_end_io_write_isa(struct bio *bio, int err) { - if (bio->bi_size) - return 1; bounce_end_io(bio, isa_page_pool, err); - return 0; } static void __bounce_end_io_read(struct bio *bio, mempool_t *pool, int err) @@ -172,22 +165,14 @@ static void __bounce_end_io_read(struct bio *bio, mempool_t *pool, int err) bounce_end_io(bio, pool, err); } -static int bounce_end_io_read(struct bio *bio, unsigned int bytes_done, int err) +static void bounce_end_io_read(struct bio *bio, int err) { - if (bio->bi_size) - return 1; - __bounce_end_io_read(bio, page_pool, err); - return 0; } -static int bounce_end_io_read_isa(struct bio *bio, unsigned int bytes_done, int err) +static void bounce_end_io_read_isa(struct bio *bio, int err) { - if (bio->bi_size) - return 1; - __bounce_end_io_read(bio, isa_page_pool, err); - return 0; } static void __blk_queue_bounce(struct request_queue *q, struct bio **bio_orig, diff --git a/mm/page_io.c b/mm/page_io.c index dbffec0d78c..3b97f685027 100644 --- a/mm/page_io.c +++ b/mm/page_io.c @@ -44,14 +44,11 @@ static struct bio *get_swap_bio(gfp_t gfp_flags, pgoff_t index, return bio; } -static int end_swap_bio_write(struct bio *bio, unsigned int bytes_done, int err) +static void end_swap_bio_write(struct bio *bio, int err) { const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct page *page = bio->bi_io_vec[0].bv_page; - if (bio->bi_size) - return 1; - if (!uptodate) { SetPageError(page); /* @@ -71,17 +68,13 @@ static int end_swap_bio_write(struct bio *bio, unsigned int bytes_done, int err) } end_page_writeback(page); bio_put(bio); - return 0; } -int end_swap_bio_read(struct bio *bio, unsigned int bytes_done, int err) +void end_swap_bio_read(struct bio *bio, int err) { const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct page *page = bio->bi_io_vec[0].bv_page; - if (bio->bi_size) - return 1; - if (!uptodate) { SetPageError(page); ClearPageUptodate(page); @@ -94,7 +87,6 @@ int end_swap_bio_read(struct bio *bio, unsigned int bytes_done, int err) } unlock_page(page); bio_put(bio); - return 0; } /* -- cgit v1.2.3-70-g09d2 From edec49616c7b4ad7ceb3b936a8d95b10652ee677 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Mon, 1 Oct 2007 16:33:52 +0200 Subject: Sysace: Use the established platform bus api SystemACE uses the platform bus binding, but it doesn't use the platform bus API. Move to using the correct API for consistency sake and future proofing against platform bus changes. Signed-off-by: Grant Likely Signed-off-by: Jens Axboe --- drivers/block/xsysace.c | 48 ++++++++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c index 3ede0b63da1..b10447611af 100644 --- a/drivers/block/xsysace.c +++ b/drivers/block/xsysace.c @@ -1060,13 +1060,12 @@ static void __devexit ace_teardown(struct ace_device *ace) * Platform Bus Support */ -static int __devinit ace_probe(struct device *device) +static int __devinit ace_probe(struct platform_device *dev) { - struct platform_device *dev = to_platform_device(device); struct ace_device *ace; int i; - dev_dbg(device, "ace_probe(%p)\n", device); + dev_dbg(&dev->dev, "ace_probe(%p)\n", dev); /* * Allocate the ace device structure @@ -1075,7 +1074,7 @@ static int __devinit ace_probe(struct device *device) if (!ace) goto err_alloc; - ace->dev = device; + ace->dev = &dev->dev; ace->id = dev->id; ace->irq = NO_IRQ; @@ -1089,7 +1088,7 @@ static int __devinit ace_probe(struct device *device) /* FIXME: Should get bus_width from the platform_device struct */ ace->bus_width = 1; - dev_set_drvdata(&dev->dev, ace); + platform_set_drvdata(dev, ace); /* Call the bus-independant setup code */ if (ace_setup(ace) != 0) @@ -1098,7 +1097,7 @@ static int __devinit ace_probe(struct device *device) return 0; err_setup: - dev_set_drvdata(&dev->dev, NULL); + platform_set_drvdata(dev, NULL); kfree(ace); err_alloc: printk(KERN_ERR "xsysace: could not initialize device\n"); @@ -1108,25 +1107,27 @@ static int __devinit ace_probe(struct device *device) /* * Platform bus remove() method */ -static int __devexit ace_remove(struct device *device) +static int __devexit ace_remove(struct platform_device *dev) { - struct ace_device *ace = dev_get_drvdata(device); - - dev_dbg(device, "ace_remove(%p)\n", device); + struct ace_device *ace = platform_get_drvdata(dev); + dev_dbg(&dev->dev, "ace_remove(%p)\n", dev); if (ace) { ace_teardown(ace); + platform_set_drvdata(dev, NULL); kfree(ace); } return 0; } -static struct device_driver ace_driver = { - .name = "xsysace", - .bus = &platform_bus_type, +static struct platform_driver ace_platform_driver = { .probe = ace_probe, .remove = __devexit_p(ace_remove), + .driver = { + .owner = THIS_MODULE, + .name = "xsysace", + }, }; /* --------------------------------------------------------------------- @@ -1134,20 +1135,31 @@ static struct device_driver ace_driver = { */ static int __init ace_init(void) { + int rc; + ace_major = register_blkdev(ace_major, "xsysace"); if (ace_major <= 0) { - printk(KERN_WARNING "xsysace: register_blkdev() failed\n"); - return ace_major; + rc = -ENOMEM; + goto err_blk; } - pr_debug("Registering Xilinx SystemACE driver, major=%i\n", ace_major); - return driver_register(&ace_driver); + if ((rc = platform_driver_register(&ace_platform_driver)) != 0) + goto err_plat; + + pr_info("Xilinx SystemACE device driver, major=%i\n", ace_major); + return 0; + + err_plat: + unregister_blkdev(ace_major, "xsysace"); + err_blk: + printk(KERN_ERR "xsysace: registration failed; err=%i\n", rc); + return rc; } static void __exit ace_exit(void) { pr_debug("Unregistering Xilinx SystemACE driver\n"); - driver_unregister(&ace_driver); + platform_driver_unregister(&ace_platform_driver); unregister_blkdev(ace_major, "xsysace"); } -- cgit v1.2.3-70-g09d2 From 1b455466549f46bab0a75a7a296a9331a38fd6fa Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Mon, 1 Oct 2007 16:33:53 +0200 Subject: Sysace: Move structure allocation from bus binding into common code Split the determination of device registers/irqs/etc from the actual allocation and initialization of the device structure. This cleans up the code a bit in preparation to add an of_platform bus binding Signed-off-by: Grant Likely Signed-off-by: Jens Axboe --- drivers/block/xsysace.c | 99 ++++++++++++++++++++++++++++++------------------- 1 file changed, 61 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c index b10447611af..555939bd2d5 100644 --- a/drivers/block/xsysace.c +++ b/drivers/block/xsysace.c @@ -1033,7 +1033,7 @@ static int __devinit ace_setup(struct ace_device *ace) if (ace->irq != NO_IRQ) free_irq(ace->irq, ace); err_ioremap: - printk(KERN_INFO "xsysace: error initializing device at 0x%lx\n", + dev_info(ace->dev, "xsysace: error initializing device at 0x%lx\n", ace->physaddr); return -ENOMEM; } @@ -1056,68 +1056,91 @@ static void __devexit ace_teardown(struct ace_device *ace) iounmap(ace->baseaddr); } -/* --------------------------------------------------------------------- - * Platform Bus Support - */ - -static int __devinit ace_probe(struct platform_device *dev) +static int __devinit +ace_alloc(struct device *dev, int id, unsigned long physaddr, + int irq, int bus_width) { struct ace_device *ace; - int i; + int rc; + dev_dbg(dev, "ace_alloc(%p)\n", dev); - dev_dbg(&dev->dev, "ace_probe(%p)\n", dev); + if (!physaddr) { + rc = -ENODEV; + goto err_noreg; + } - /* - * Allocate the ace device structure - */ + /* Allocate and initialize the ace device structure */ ace = kzalloc(sizeof(struct ace_device), GFP_KERNEL); - if (!ace) + if (!ace) { + rc = -ENOMEM; goto err_alloc; - - ace->dev = &dev->dev; - ace->id = dev->id; - ace->irq = NO_IRQ; - - for (i = 0; i < dev->num_resources; i++) { - if (dev->resource[i].flags & IORESOURCE_MEM) - ace->physaddr = dev->resource[i].start; - if (dev->resource[i].flags & IORESOURCE_IRQ) - ace->irq = dev->resource[i].start; } - /* FIXME: Should get bus_width from the platform_device struct */ - ace->bus_width = 1; - - platform_set_drvdata(dev, ace); + ace->dev = dev; + ace->id = id; + ace->physaddr = physaddr; + ace->irq = irq; + ace->bus_width = bus_width; - /* Call the bus-independant setup code */ - if (ace_setup(ace) != 0) + /* Call the setup code */ + if ((rc = ace_setup(ace)) != 0) goto err_setup; + dev_set_drvdata(dev, ace); return 0; err_setup: - platform_set_drvdata(dev, NULL); + dev_set_drvdata(dev, NULL); kfree(ace); err_alloc: - printk(KERN_ERR "xsysace: could not initialize device\n"); - return -ENOMEM; + err_noreg: + dev_err(dev, "could not initialize device, err=%i\n", rc); + return rc; } -/* - * Platform bus remove() method - */ -static int __devexit ace_remove(struct platform_device *dev) +static void __devexit ace_free(struct device *dev) { - struct ace_device *ace = platform_get_drvdata(dev); - dev_dbg(&dev->dev, "ace_remove(%p)\n", dev); + struct ace_device *ace = dev_get_drvdata(dev); + dev_dbg(dev, "ace_free(%p)\n", dev); if (ace) { ace_teardown(ace); - platform_set_drvdata(dev, NULL); + dev_set_drvdata(dev, NULL); kfree(ace); } +} + +/* --------------------------------------------------------------------- + * Platform Bus Support + */ + +static int __devinit ace_probe(struct platform_device *dev) +{ + unsigned long physaddr = 0; + int bus_width = 1; /* FIXME: should not be hard coded */ + int id = dev->id; + int irq = NO_IRQ; + int i; + + dev_dbg(&dev->dev, "ace_probe(%p)\n", dev); + + for (i = 0; i < dev->num_resources; i++) { + if (dev->resource[i].flags & IORESOURCE_MEM) + physaddr = dev->resource[i].start; + if (dev->resource[i].flags & IORESOURCE_IRQ) + irq = dev->resource[i].start; + } + + /* Call the bus-independant setup code */ + return ace_alloc(&dev->dev, id, physaddr, irq, bus_width); +} +/* + * Platform bus remove() method + */ +static int __devexit ace_remove(struct platform_device *dev) +{ + ace_free(&dev->dev); return 0; } -- cgit v1.2.3-70-g09d2 From 4a24d8610df542b6599a65b100d438df144574de Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Mon, 1 Oct 2007 16:33:54 +0200 Subject: Sysace: minor rework and cleanup changes Miscellanious rework to the sysace driver; Not critical, but makes the subsequent addition of the of_platform bus binding a wee bit cleaner Signed-off-by: Grant Likely Signed-off-by: Jens Axboe --- drivers/block/xsysace.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c index 555939bd2d5..10bb4e54f68 100644 --- a/drivers/block/xsysace.c +++ b/drivers/block/xsysace.c @@ -158,6 +158,9 @@ MODULE_LICENSE("GPL"); #define ACE_FIFO_SIZE (32) #define ACE_BUF_PER_SECTOR (ACE_SECTOR_SIZE / ACE_FIFO_SIZE) +#define ACE_BUS_WIDTH_8 0 +#define ACE_BUS_WIDTH_16 1 + struct ace_reg_ops; struct ace_device { @@ -931,9 +934,11 @@ static int __devinit ace_setup(struct ace_device *ace) { u16 version; u16 val; - int rc; + dev_dbg(ace->dev, "ace_setup(ace=0x%p)\n", ace); + dev_dbg(ace->dev, "physaddr=0x%lx irq=%i\n", ace->physaddr, ace->irq); + spin_lock_init(&ace->lock); init_completion(&ace->id_completion); @@ -982,7 +987,7 @@ static int __devinit ace_setup(struct ace_device *ace) snprintf(ace->gd->disk_name, 32, "xs%c", ace->id + 'a'); /* set bus width */ - if (ace->bus_width == 1) { + if (ace->bus_width == ACE_BUS_WIDTH_16) { /* 0x0101 should work regardless of endianess */ ace_out_le16(ace, ACE_BUSMODE, 0x0101); @@ -1117,7 +1122,7 @@ static void __devexit ace_free(struct device *dev) static int __devinit ace_probe(struct platform_device *dev) { unsigned long physaddr = 0; - int bus_width = 1; /* FIXME: should not be hard coded */ + int bus_width = ACE_BUS_WIDTH_16; /* FIXME: should not be hard coded */ int id = dev->id; int irq = NO_IRQ; int i; @@ -1166,6 +1171,7 @@ static int __init ace_init(void) goto err_blk; } + pr_debug("xsysace: registering platform binding\n"); if ((rc = platform_driver_register(&ace_platform_driver)) != 0) goto err_plat; -- cgit v1.2.3-70-g09d2 From 32f6fff47df65d25d3dedbd2953508c05225b726 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Mon, 1 Oct 2007 16:33:54 +0200 Subject: Sysace: Move IRQ handler registration to occur after FSM is initialized The FSM needs to be initialized before it is safe to call the ISR Signed-off-by: Grant Likely Signed-off-by: Jens Axboe --- drivers/block/xsysace.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c index 10bb4e54f68..296d5674a3c 100644 --- a/drivers/block/xsysace.c +++ b/drivers/block/xsysace.c @@ -949,15 +949,6 @@ static int __devinit ace_setup(struct ace_device *ace) if (!ace->baseaddr) goto err_ioremap; - if (ace->irq != NO_IRQ) { - rc = request_irq(ace->irq, ace_interrupt, 0, "systemace", ace); - if (rc) { - /* Failure - fall back to polled mode */ - dev_err(ace->dev, "request_irq failed\n"); - ace->irq = NO_IRQ; - } - } - /* * Initialize the state machine tasklet and stall timer */ @@ -1015,6 +1006,16 @@ static int __devinit ace_setup(struct ace_device *ace) val |= ACE_CTRL_DATABUFRDYIRQ | ACE_CTRL_ERRORIRQ; ace_out(ace, ACE_CTRL, val); + /* Now we can hook up the irq handler */ + if (ace->irq != NO_IRQ) { + rc = request_irq(ace->irq, ace_interrupt, 0, "systemace", ace); + if (rc) { + /* Failure - fall back to polled mode */ + dev_err(ace->dev, "request_irq failed\n"); + ace->irq = NO_IRQ; + } + } + /* Print the identification */ dev_info(ace->dev, "Xilinx SystemACE revision %i.%i.%i\n", (version >> 12) & 0xf, (version >> 8) & 0x0f, version & 0xff); @@ -1035,8 +1036,6 @@ static int __devinit ace_setup(struct ace_device *ace) blk_cleanup_queue(ace->queue); err_blk_initq: iounmap(ace->baseaddr); - if (ace->irq != NO_IRQ) - free_irq(ace->irq, ace); err_ioremap: dev_info(ace->dev, "xsysace: error initializing device at 0x%lx\n", ace->physaddr); -- cgit v1.2.3-70-g09d2 From 95e896c35f3c3157159b89682b60281640b5d148 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Mon, 1 Oct 2007 16:33:55 +0200 Subject: Sysace: Add of_platform_bus binding The of_platform bus binding is needed to make the device driver usable under arch/powerpc. Signed-off-by: Grant Likely Signed-off-by: Jens Axboe --- drivers/block/xsysace.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) (limited to 'drivers') diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c index 296d5674a3c..56c4af3c2ed 100644 --- a/drivers/block/xsysace.c +++ b/drivers/block/xsysace.c @@ -91,6 +91,10 @@ #include #include #include +#if defined(CONFIG_OF) +#include +#include +#endif MODULE_AUTHOR("Grant Likely "); MODULE_DESCRIPTION("Xilinx SystemACE device driver"); @@ -1157,6 +1161,85 @@ static struct platform_driver ace_platform_driver = { }, }; +/* --------------------------------------------------------------------- + * OF_Platform Bus Support + */ + +#if defined(CONFIG_OF) +static int __devinit +ace_of_probe(struct of_device *op, const struct of_device_id *match) +{ + struct resource res; + unsigned long physaddr; + const u32 *id; + int irq, bus_width, rc; + + dev_dbg(&op->dev, "ace_of_probe(%p, %p)\n", op, match); + + /* device id */ + id = of_get_property(op->node, "port-number", NULL); + + /* physaddr */ + rc = of_address_to_resource(op->node, 0, &res); + if (rc) { + dev_err(&op->dev, "invalid address\n"); + return rc; + } + physaddr = res.start; + + /* irq */ + irq = irq_of_parse_and_map(op->node, 0); + + /* bus width */ + bus_width = ACE_BUS_WIDTH_16; + if (of_find_property(op->node, "8-bit", NULL)) + bus_width = ACE_BUS_WIDTH_8; + + /* Call the bus-independant setup code */ + return ace_alloc(&op->dev, id ? *id : 0, physaddr, irq, bus_width); +} + +static int __devexit ace_of_remove(struct of_device *op) +{ + ace_free(&op->dev); + return 0; +} + +/* Match table for of_platform binding */ +static struct of_device_id __devinit ace_of_match[] = { + { .compatible = "xilinx,xsysace", }, + {}, +}; +MODULE_DEVICE_TABLE(of, ace_of_match); + +static struct of_platform_driver ace_of_driver = { + .owner = THIS_MODULE, + .name = "xsysace", + .match_table = ace_of_match, + .probe = ace_of_probe, + .remove = __devexit_p(ace_of_remove), + .driver = { + .name = "xsysace", + }, +}; + +/* Registration helpers to keep the number of #ifdefs to a minimum */ +static inline int __init ace_of_register(void) +{ + pr_debug("xsysace: registering OF binding\n"); + return of_register_platform_driver(&ace_of_driver); +} + +static inline void __exit ace_of_unregister(void) +{ + of_unregister_platform_driver(&ace_of_driver); +} +#else /* CONFIG_OF */ +/* CONFIG_OF not enabled; do nothing helpers */ +static inline int __init ace_of_register(void) { return 0; } +static inline void __exit ace_of_unregister(void) { } +#endif /* CONFIG_OF */ + /* --------------------------------------------------------------------- * Module init/exit routines */ @@ -1170,6 +1253,9 @@ static int __init ace_init(void) goto err_blk; } + if ((rc = ace_of_register()) != 0) + goto err_of; + pr_debug("xsysace: registering platform binding\n"); if ((rc = platform_driver_register(&ace_platform_driver)) != 0) goto err_plat; @@ -1178,6 +1264,8 @@ static int __init ace_init(void) return 0; err_plat: + ace_of_unregister(); + err_of: unregister_blkdev(ace_major, "xsysace"); err_blk: printk(KERN_ERR "xsysace: registration failed; err=%i\n", rc); @@ -1188,6 +1276,7 @@ static void __exit ace_exit(void) { pr_debug("Unregistering Xilinx SystemACE driver\n"); platform_driver_unregister(&ace_platform_driver); + ace_of_unregister(); unregister_blkdev(ace_major, "xsysace"); } -- cgit v1.2.3-70-g09d2 From ed155a95a4eb7d8dae61b64ab394314c5195e414 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Mon, 1 Oct 2007 16:33:56 +0200 Subject: Sysace: Labels in C code should not be indented. Remove the indentation on labels Signed-off-by: Grant Likely Signed-off-by: Jens Axboe --- drivers/block/xsysace.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c index 56c4af3c2ed..3ea172b7b7a 100644 --- a/drivers/block/xsysace.c +++ b/drivers/block/xsysace.c @@ -1034,13 +1034,13 @@ static int __devinit ace_setup(struct ace_device *ace) return 0; - err_read: +err_read: put_disk(ace->gd); - err_alloc_disk: +err_alloc_disk: blk_cleanup_queue(ace->queue); - err_blk_initq: +err_blk_initq: iounmap(ace->baseaddr); - err_ioremap: +err_ioremap: dev_info(ace->dev, "xsysace: error initializing device at 0x%lx\n", ace->physaddr); return -ENOMEM; @@ -1097,11 +1097,11 @@ ace_alloc(struct device *dev, int id, unsigned long physaddr, dev_set_drvdata(dev, ace); return 0; - err_setup: +err_setup: dev_set_drvdata(dev, NULL); kfree(ace); - err_alloc: - err_noreg: +err_alloc: +err_noreg: dev_err(dev, "could not initialize device, err=%i\n", rc); return rc; } @@ -1263,11 +1263,11 @@ static int __init ace_init(void) pr_info("Xilinx SystemACE device driver, major=%i\n", ace_major); return 0; - err_plat: +err_plat: ace_of_unregister(); - err_of: +err_of: unregister_blkdev(ace_major, "xsysace"); - err_blk: +err_blk: printk(KERN_ERR "xsysace: registration failed; err=%i\n", rc); return rc; } -- cgit v1.2.3-70-g09d2 From 3084f0c6105a71e43225c36b4d97c1407988a242 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 27 Sep 2007 06:25:06 -0400 Subject: drivers/block/umem: move private include away from include/linux Move include/linux/umem.h to drivers/block, as umem.c is the only user, and its not an exported header. Move the PCI_{VENDOR,DEVICE}_ID_* constants to include/linux/pci_ids.h. Signed-off-by: Jeff Garzik --- drivers/block/umem.c | 2 +- drivers/block/umem.h | 133 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/pci_ids.h | 5 ++ include/linux/umem.h | 138 ------------------------------------------------ 4 files changed, 139 insertions(+), 139 deletions(-) create mode 100644 drivers/block/umem.h delete mode 100644 include/linux/umem.h (limited to 'drivers') diff --git a/drivers/block/umem.c b/drivers/block/umem.c index be7fac86725..33ef7661e1c 100644 --- a/drivers/block/umem.c +++ b/drivers/block/umem.c @@ -52,7 +52,7 @@ #include /* O_ACCMODE */ #include /* HDIO_GETGEO */ -#include +#include "umem.h" #include #include diff --git a/drivers/block/umem.h b/drivers/block/umem.h new file mode 100644 index 00000000000..3a3819afed9 --- /dev/null +++ b/drivers/block/umem.h @@ -0,0 +1,133 @@ + +/* + * This file contains defines for the + * Micro Memory MM5415 + * family PCI Memory Module with Battery Backup. + * + * Copyright Micro Memory INC 2001. All rights reserved. + * Release under the terms of the GNU GENERAL PUBLIC LICENSE version 2. + * See the file COPYING. + */ + +#ifndef _DRIVERS_BLOCK_MM_H +#define _DRIVERS_BLOCK_MM_H + + +#define IRQ_TIMEOUT (1 * HZ) + +/* CSR register definition */ +#define MEMCTRLSTATUS_MAGIC 0x00 +#define MM_MAGIC_VALUE (unsigned char)0x59 + +#define MEMCTRLSTATUS_BATTERY 0x04 +#define BATTERY_1_DISABLED 0x01 +#define BATTERY_1_FAILURE 0x02 +#define BATTERY_2_DISABLED 0x04 +#define BATTERY_2_FAILURE 0x08 + +#define MEMCTRLSTATUS_MEMORY 0x07 +#define MEM_128_MB 0xfe +#define MEM_256_MB 0xfc +#define MEM_512_MB 0xf8 +#define MEM_1_GB 0xf0 +#define MEM_2_GB 0xe0 + +#define MEMCTRLCMD_LEDCTRL 0x08 +#define LED_REMOVE 2 +#define LED_FAULT 4 +#define LED_POWER 6 +#define LED_FLIP 255 +#define LED_OFF 0x00 +#define LED_ON 0x01 +#define LED_FLASH_3_5 0x02 +#define LED_FLASH_7_0 0x03 +#define LED_POWER_ON 0x00 +#define LED_POWER_OFF 0x01 +#define USER_BIT1 0x01 +#define USER_BIT2 0x02 + +#define MEMORY_INITIALIZED USER_BIT1 + +#define MEMCTRLCMD_ERRCTRL 0x0C +#define EDC_NONE_DEFAULT 0x00 +#define EDC_NONE 0x01 +#define EDC_STORE_READ 0x02 +#define EDC_STORE_CORRECT 0x03 + +#define MEMCTRLCMD_ERRCNT 0x0D +#define MEMCTRLCMD_ERRSTATUS 0x0E + +#define ERROR_DATA_LOG 0x20 +#define ERROR_ADDR_LOG 0x28 +#define ERROR_COUNT 0x3D +#define ERROR_SYNDROME 0x3E +#define ERROR_CHECK 0x3F + +#define DMA_PCI_ADDR 0x40 +#define DMA_LOCAL_ADDR 0x48 +#define DMA_TRANSFER_SIZE 0x50 +#define DMA_DESCRIPTOR_ADDR 0x58 +#define DMA_SEMAPHORE_ADDR 0x60 +#define DMA_STATUS_CTRL 0x68 +#define DMASCR_GO 0x00001 +#define DMASCR_TRANSFER_READ 0x00002 +#define DMASCR_CHAIN_EN 0x00004 +#define DMASCR_SEM_EN 0x00010 +#define DMASCR_DMA_COMP_EN 0x00020 +#define DMASCR_CHAIN_COMP_EN 0x00040 +#define DMASCR_ERR_INT_EN 0x00080 +#define DMASCR_PARITY_INT_EN 0x00100 +#define DMASCR_ANY_ERR 0x00800 +#define DMASCR_MBE_ERR 0x01000 +#define DMASCR_PARITY_ERR_REP 0x02000 +#define DMASCR_PARITY_ERR_DET 0x04000 +#define DMASCR_SYSTEM_ERR_SIG 0x08000 +#define DMASCR_TARGET_ABT 0x10000 +#define DMASCR_MASTER_ABT 0x20000 +#define DMASCR_DMA_COMPLETE 0x40000 +#define DMASCR_CHAIN_COMPLETE 0x80000 + +/* +3.SOME PCs HAVE HOST BRIDGES WHICH APPARENTLY DO NOT CORRECTLY HANDLE +READ-LINE (0xE) OR READ-MULTIPLE (0xC) PCI COMMAND CODES DURING DMA +TRANSFERS. IN OTHER SYSTEMS THESE COMMAND CODES WILL CAUSE THE HOST BRIDGE +TO ALLOW LONGER BURSTS DURING DMA READ OPERATIONS. THE UPPER FOUR BITS +(31..28) OF THE DMA CSR HAVE BEEN MADE PROGRAMMABLE, SO THAT EITHER A 0x6, +AN 0xE OR A 0xC CAN BE WRITTEN TO THEM TO SET THE COMMAND CODE USED DURING +DMA READ OPERATIONS. +*/ +#define DMASCR_READ 0x60000000 +#define DMASCR_READLINE 0xE0000000 +#define DMASCR_READMULTI 0xC0000000 + + +#define DMASCR_ERROR_MASK (DMASCR_MASTER_ABT | DMASCR_TARGET_ABT | DMASCR_SYSTEM_ERR_SIG | DMASCR_PARITY_ERR_DET | DMASCR_MBE_ERR | DMASCR_ANY_ERR) +#define DMASCR_HARD_ERROR (DMASCR_MASTER_ABT | DMASCR_TARGET_ABT | DMASCR_SYSTEM_ERR_SIG | DMASCR_PARITY_ERR_DET | DMASCR_MBE_ERR) + +#define WINDOWMAP_WINNUM 0x7B + +#define DMA_READ_FROM_HOST 0 +#define DMA_WRITE_TO_HOST 1 + +struct mm_dma_desc { + __le64 pci_addr; + __le64 local_addr; + __le32 transfer_size; + u32 zero1; + __le64 next_desc_addr; + __le64 sem_addr; + __le32 control_bits; + u32 zero2; + + dma_addr_t data_dma_handle; + + /* Copy of the bits */ + __le64 sem_control_bits; +} __attribute__((aligned(8))); + +/* bits for card->flags */ +#define UM_FLAG_DMA_IN_REGS 1 +#define UM_FLAG_NO_BYTE_STATUS 2 +#define UM_FLAG_NO_BATTREG 4 +#define UM_FLAG_NO_BATT 8 +#endif diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 55f307ffbf9..506b9ae241f 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1736,6 +1736,11 @@ #define PCI_VENDOR_ID_RADISYS 0x1331 +#define PCI_VENDOR_ID_MICRO_MEMORY 0x1332 +#define PCI_DEVICE_ID_MICRO_MEMORY_5415CN 0x5415 +#define PCI_DEVICE_ID_MICRO_MEMORY_5425CN 0x5425 +#define PCI_DEVICE_ID_MICRO_MEMORY_6155 0x6155 + #define PCI_VENDOR_ID_DOMEX 0x134a #define PCI_DEVICE_ID_DOMEX_DMX3191D 0x0001 diff --git a/include/linux/umem.h b/include/linux/umem.h deleted file mode 100644 index f36ebfc32bf..00000000000 --- a/include/linux/umem.h +++ /dev/null @@ -1,138 +0,0 @@ - -/* - * This file contains defines for the - * Micro Memory MM5415 - * family PCI Memory Module with Battery Backup. - * - * Copyright Micro Memory INC 2001. All rights reserved. - * Release under the terms of the GNU GENERAL PUBLIC LICENSE version 2. - * See the file COPYING. - */ - -#ifndef _DRIVERS_BLOCK_MM_H -#define _DRIVERS_BLOCK_MM_H - - -#define IRQ_TIMEOUT (1 * HZ) - -/* CSR register definition */ -#define MEMCTRLSTATUS_MAGIC 0x00 -#define MM_MAGIC_VALUE (unsigned char)0x59 - -#define MEMCTRLSTATUS_BATTERY 0x04 -#define BATTERY_1_DISABLED 0x01 -#define BATTERY_1_FAILURE 0x02 -#define BATTERY_2_DISABLED 0x04 -#define BATTERY_2_FAILURE 0x08 - -#define MEMCTRLSTATUS_MEMORY 0x07 -#define MEM_128_MB 0xfe -#define MEM_256_MB 0xfc -#define MEM_512_MB 0xf8 -#define MEM_1_GB 0xf0 -#define MEM_2_GB 0xe0 - -#define MEMCTRLCMD_LEDCTRL 0x08 -#define LED_REMOVE 2 -#define LED_FAULT 4 -#define LED_POWER 6 -#define LED_FLIP 255 -#define LED_OFF 0x00 -#define LED_ON 0x01 -#define LED_FLASH_3_5 0x02 -#define LED_FLASH_7_0 0x03 -#define LED_POWER_ON 0x00 -#define LED_POWER_OFF 0x01 -#define USER_BIT1 0x01 -#define USER_BIT2 0x02 - -#define MEMORY_INITIALIZED USER_BIT1 - -#define MEMCTRLCMD_ERRCTRL 0x0C -#define EDC_NONE_DEFAULT 0x00 -#define EDC_NONE 0x01 -#define EDC_STORE_READ 0x02 -#define EDC_STORE_CORRECT 0x03 - -#define MEMCTRLCMD_ERRCNT 0x0D -#define MEMCTRLCMD_ERRSTATUS 0x0E - -#define ERROR_DATA_LOG 0x20 -#define ERROR_ADDR_LOG 0x28 -#define ERROR_COUNT 0x3D -#define ERROR_SYNDROME 0x3E -#define ERROR_CHECK 0x3F - -#define DMA_PCI_ADDR 0x40 -#define DMA_LOCAL_ADDR 0x48 -#define DMA_TRANSFER_SIZE 0x50 -#define DMA_DESCRIPTOR_ADDR 0x58 -#define DMA_SEMAPHORE_ADDR 0x60 -#define DMA_STATUS_CTRL 0x68 -#define DMASCR_GO 0x00001 -#define DMASCR_TRANSFER_READ 0x00002 -#define DMASCR_CHAIN_EN 0x00004 -#define DMASCR_SEM_EN 0x00010 -#define DMASCR_DMA_COMP_EN 0x00020 -#define DMASCR_CHAIN_COMP_EN 0x00040 -#define DMASCR_ERR_INT_EN 0x00080 -#define DMASCR_PARITY_INT_EN 0x00100 -#define DMASCR_ANY_ERR 0x00800 -#define DMASCR_MBE_ERR 0x01000 -#define DMASCR_PARITY_ERR_REP 0x02000 -#define DMASCR_PARITY_ERR_DET 0x04000 -#define DMASCR_SYSTEM_ERR_SIG 0x08000 -#define DMASCR_TARGET_ABT 0x10000 -#define DMASCR_MASTER_ABT 0x20000 -#define DMASCR_DMA_COMPLETE 0x40000 -#define DMASCR_CHAIN_COMPLETE 0x80000 - -/* -3.SOME PCs HAVE HOST BRIDGES WHICH APPARENTLY DO NOT CORRECTLY HANDLE -READ-LINE (0xE) OR READ-MULTIPLE (0xC) PCI COMMAND CODES DURING DMA -TRANSFERS. IN OTHER SYSTEMS THESE COMMAND CODES WILL CAUSE THE HOST BRIDGE -TO ALLOW LONGER BURSTS DURING DMA READ OPERATIONS. THE UPPER FOUR BITS -(31..28) OF THE DMA CSR HAVE BEEN MADE PROGRAMMABLE, SO THAT EITHER A 0x6, -AN 0xE OR A 0xC CAN BE WRITTEN TO THEM TO SET THE COMMAND CODE USED DURING -DMA READ OPERATIONS. -*/ -#define DMASCR_READ 0x60000000 -#define DMASCR_READLINE 0xE0000000 -#define DMASCR_READMULTI 0xC0000000 - - -#define DMASCR_ERROR_MASK (DMASCR_MASTER_ABT | DMASCR_TARGET_ABT | DMASCR_SYSTEM_ERR_SIG | DMASCR_PARITY_ERR_DET | DMASCR_MBE_ERR | DMASCR_ANY_ERR) -#define DMASCR_HARD_ERROR (DMASCR_MASTER_ABT | DMASCR_TARGET_ABT | DMASCR_SYSTEM_ERR_SIG | DMASCR_PARITY_ERR_DET | DMASCR_MBE_ERR) - -#define WINDOWMAP_WINNUM 0x7B - -#define DMA_READ_FROM_HOST 0 -#define DMA_WRITE_TO_HOST 1 - -struct mm_dma_desc { - __le64 pci_addr; - __le64 local_addr; - __le32 transfer_size; - u32 zero1; - __le64 next_desc_addr; - __le64 sem_addr; - __le32 control_bits; - u32 zero2; - - dma_addr_t data_dma_handle; - - /* Copy of the bits */ - __le64 sem_control_bits; -} __attribute__((aligned(8))); - -#define PCI_VENDOR_ID_MICRO_MEMORY 0x1332 -#define PCI_DEVICE_ID_MICRO_MEMORY_5415CN 0x5415 -#define PCI_DEVICE_ID_MICRO_MEMORY_5425CN 0x5425 -#define PCI_DEVICE_ID_MICRO_MEMORY_6155 0x6155 - -/* bits for card->flags */ -#define UM_FLAG_DMA_IN_REGS 1 -#define UM_FLAG_NO_BYTE_STATUS 2 -#define UM_FLAG_NO_BATTREG 4 -#define UM_FLAG_NO_BATT 8 -#endif -- cgit v1.2.3-70-g09d2 From 4e0af881afee2b399854b1cdfdbe37e6ab6a09ca Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 27 Sep 2007 06:41:25 -0400 Subject: drivers/block/umem: use dev_printk() dev_printk() gives us a consistent prefix (driver name + PCI bus id), which allows us to eliminate the hand-rolled one. Also allows us to eliminate card->card_number, which was used solely in printk() calls. Signed-off-by: Jeff Garzik --- drivers/block/umem.c | 111 ++++++++++++++++++++++++++++----------------------- 1 file changed, 62 insertions(+), 49 deletions(-) (limited to 'drivers') diff --git a/drivers/block/umem.c b/drivers/block/umem.c index 33ef7661e1c..32060b84c0f 100644 --- a/drivers/block/umem.c +++ b/drivers/block/umem.c @@ -97,7 +97,6 @@ static int major_nr; #include struct cardinfo { - int card_number; struct pci_dev *dev; int irq; @@ -236,7 +235,7 @@ static void dump_regs(struct cardinfo *card) */ static void dump_dmastat(struct cardinfo *card, unsigned int dmastat) { - printk(KERN_DEBUG "MM%d*: DMAstat - ", card->card_number); + dev_printk(KERN_DEBUG, &card->dev->dev, "DMAstat - "); if (dmastat & DMASCR_ANY_ERR) printk("ANY_ERR "); if (dmastat & DMASCR_MBE_ERR) @@ -499,17 +498,17 @@ static void process_page(unsigned long data) if (control & DMASCR_HARD_ERROR) { /* error */ clear_bit(BIO_UPTODATE, &bio->bi_flags); - printk(KERN_WARNING "MM%d: I/O error on sector %d/%d\n", - card->card_number, - le32_to_cpu(desc->local_addr)>>9, - le32_to_cpu(desc->transfer_size)); + dev_printk(KERN_WARNING, &card->dev->dev, + "I/O error on sector %d/%d\n", + le32_to_cpu(desc->local_addr)>>9, + le32_to_cpu(desc->transfer_size)); dump_dmastat(card, control); } else if (test_bit(BIO_RW, &bio->bi_rw) && le32_to_cpu(desc->local_addr)>>9 == card->init_size) { card->init_size += le32_to_cpu(desc->transfer_size)>>9; if (card->init_size>>1 >= card->mm_size) { - printk(KERN_INFO "MM%d: memory now initialised\n", - card->card_number); + dev_printk(KERN_INFO, &card->dev->dev, + "memory now initialised\n"); set_userbit(card, MEMORY_INITIALIZED, 1); } } @@ -618,46 +617,51 @@ HW_TRACE(0x30); dump_dmastat(card, dma_status); if (stat & 0x01) - printk(KERN_ERR "MM%d*: Memory access error detected (err count %d)\n", - card->card_number, count); + dev_printk(KERN_ERR, &card->dev->dev, + "Memory access error detected (err count %d)\n", + count); if (stat & 0x02) - printk(KERN_ERR "MM%d*: Multi-bit EDC error\n", - card->card_number); + dev_printk(KERN_ERR, &card->dev->dev, + "Multi-bit EDC error\n"); - printk(KERN_ERR "MM%d*: Fault Address 0x%02x%08x, Fault Data 0x%08x%08x\n", - card->card_number, addr_log2, addr_log1, data_log2, data_log1); - printk(KERN_ERR "MM%d*: Fault Check 0x%02x, Fault Syndrome 0x%02x\n", - card->card_number, check, syndrome); + dev_printk(KERN_ERR, &card->dev->dev, + "Fault Address 0x%02x%08x, Fault Data 0x%08x%08x\n", + addr_log2, addr_log1, data_log2, data_log1); + dev_printk(KERN_ERR, &card->dev->dev, + "Fault Check 0x%02x, Fault Syndrome 0x%02x\n", + check, syndrome); writeb(0, card->csr_remap + ERROR_COUNT); } if (dma_status & DMASCR_PARITY_ERR_REP) { - printk(KERN_ERR "MM%d*: PARITY ERROR REPORTED\n", card->card_number); + dev_printk(KERN_ERR, &card->dev->dev, + "PARITY ERROR REPORTED\n"); pci_read_config_word(card->dev, PCI_STATUS, &cfg_status); pci_write_config_word(card->dev, PCI_STATUS, cfg_status); } if (dma_status & DMASCR_PARITY_ERR_DET) { - printk(KERN_ERR "MM%d*: PARITY ERROR DETECTED\n", card->card_number); + dev_printk(KERN_ERR, &card->dev->dev, + "PARITY ERROR DETECTED\n"); pci_read_config_word(card->dev, PCI_STATUS, &cfg_status); pci_write_config_word(card->dev, PCI_STATUS, cfg_status); } if (dma_status & DMASCR_SYSTEM_ERR_SIG) { - printk(KERN_ERR "MM%d*: SYSTEM ERROR\n", card->card_number); + dev_printk(KERN_ERR, &card->dev->dev, "SYSTEM ERROR\n"); pci_read_config_word(card->dev, PCI_STATUS, &cfg_status); pci_write_config_word(card->dev, PCI_STATUS, cfg_status); } if (dma_status & DMASCR_TARGET_ABT) { - printk(KERN_ERR "MM%d*: TARGET ABORT\n", card->card_number); + dev_printk(KERN_ERR, &card->dev->dev, "TARGET ABORT\n"); pci_read_config_word(card->dev, PCI_STATUS, &cfg_status); pci_write_config_word(card->dev, PCI_STATUS, cfg_status); } if (dma_status & DMASCR_MASTER_ABT) { - printk(KERN_ERR "MM%d*: MASTER ABORT\n", card->card_number); + dev_printk(KERN_ERR, &card->dev->dev, "MASTER ABORT\n"); pci_read_config_word(card->dev, PCI_STATUS, &cfg_status); pci_write_config_word(card->dev, PCI_STATUS, cfg_status); } @@ -708,20 +712,20 @@ static int check_battery(struct cardinfo *card, int battery, int status) card->battery[battery].last_change = jiffies; if (card->battery[battery].good) { - printk(KERN_ERR "MM%d: Battery %d now good\n", - card->card_number, battery + 1); + dev_printk(KERN_ERR, &card->dev->dev, + "Battery %d now good\n", battery + 1); card->battery[battery].warned = 0; } else - printk(KERN_ERR "MM%d: Battery %d now FAILED\n", - card->card_number, battery + 1); + dev_printk(KERN_ERR, &card->dev->dev, + "Battery %d now FAILED\n", battery + 1); return 1; } else if (!card->battery[battery].good && !card->battery[battery].warned && time_after_eq(jiffies, card->battery[battery].last_change + (HZ * 60 * 60 * 5))) { - printk(KERN_ERR "MM%d: Battery %d still FAILED after 5 hours\n", - card->card_number, battery + 1); + dev_printk(KERN_ERR, &card->dev->dev, + "Battery %d still FAILED after 5 hours\n", battery + 1); card->battery[battery].warned = 1; return 1; @@ -745,8 +749,8 @@ static void check_batteries(struct cardinfo *card) status = readb(card->csr_remap + MEMCTRLSTATUS_BATTERY); if (debug & DEBUG_BATTERY_POLLING) - printk(KERN_DEBUG "MM%d: checking battery status, 1 = %s, 2 = %s\n", - card->card_number, + dev_printk(KERN_DEBUG, &card->dev->dev, + "checking battery status, 1 = %s, 2 = %s\n", (status & BATTERY_1_FAILURE) ? "FAILURE" : "OK", (status & BATTERY_2_FAILURE) ? "FAILURE" : "OK"); @@ -866,6 +870,10 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i unsigned char batt_status; unsigned int saved_bar, data; int magic_number; + static int printed_version; + + if (!printed_version++) + printk(KERN_INFO DRIVER_VERSION " : " DRIVER_DESC "\n"); if (pci_enable_device(dev) < 0) return -ENODEV; @@ -874,21 +882,21 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i pci_set_master(dev); card->dev = dev; - card->card_number = num_cards; card->csr_base = pci_resource_start(dev, 0); card->csr_len = pci_resource_len(dev, 0); - printk(KERN_INFO "Micro Memory(tm) controller #%d found at %02x:%02x (PCI Mem Module (Battery Backup))\n", - card->card_number, dev->bus->number, dev->devfn); + dev_printk(KERN_INFO, &dev->dev, + "Micro Memory(tm) controller found (PCI Mem Module (Battery Backup))\n"); if (pci_set_dma_mask(dev, DMA_64BIT_MASK) && pci_set_dma_mask(dev, DMA_32BIT_MASK)) { - printk(KERN_WARNING "MM%d: NO suitable DMA found\n",num_cards); + dev_printk(KERN_WARNING, &dev->dev, "NO suitable DMA found\n"); return -ENOMEM; } if (!request_mem_region(card->csr_base, card->csr_len, "Micro Memory")) { - printk(KERN_ERR "MM%d: Unable to request memory region\n", card->card_number); + dev_printk(KERN_ERR, &card->dev->dev, + "Unable to request memory region\n"); ret = -ENOMEM; goto failed_req_csr; @@ -896,13 +904,15 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i card->csr_remap = ioremap_nocache(card->csr_base, card->csr_len); if (!card->csr_remap) { - printk(KERN_ERR "MM%d: Unable to remap memory region\n", card->card_number); + dev_printk(KERN_ERR, &card->dev->dev, + "Unable to remap memory region\n"); ret = -ENOMEM; goto failed_remap_csr; } - printk(KERN_INFO "MM%d: CSR 0x%08lx -> 0x%p (0x%lx)\n", card->card_number, + dev_printk(KERN_INFO, &card->dev->dev, + "CSR 0x%08lx -> 0x%p (0x%lx)\n", card->csr_base, card->csr_remap, card->csr_len); switch(card->dev->device) { @@ -927,7 +937,7 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i } if (readb(card->csr_remap + MEMCTRLSTATUS_MAGIC) != magic_number) { - printk(KERN_ERR "MM%d: Magic number invalid\n", card->card_number); + dev_printk(KERN_ERR, &card->dev->dev, "Magic number invalid\n"); ret = -ENOMEM; goto failed_magic; } @@ -940,7 +950,7 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i &card->mm_pages[1].page_dma); if (card->mm_pages[0].desc == NULL || card->mm_pages[1].desc == NULL) { - printk(KERN_ERR "MM%d: alloc failed\n", card->card_number); + dev_printk(KERN_ERR, &card->dev->dev, "alloc failed\n"); goto failed_alloc; } reset_page(&card->mm_pages[0]); @@ -995,11 +1005,12 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i card->battery[0].last_change = card->battery[1].last_change = jiffies; if (card->flags & UM_FLAG_NO_BATT) - printk(KERN_INFO "MM%d: Size %d KB\n", - card->card_number, card->mm_size); + dev_printk(KERN_INFO, &card->dev->dev, + "Size %d KB\n", card->mm_size); else { - printk(KERN_INFO "MM%d: Size %d KB, Battery 1 %s (%s), Battery 2 %s (%s)\n", - card->card_number, card->mm_size, + dev_printk(KERN_INFO, &card->dev->dev, + "Size %d KB, Battery 1 %s (%s), Battery 2 %s (%s)\n", + card->mm_size, (batt_status & BATTERY_1_DISABLED ? "Disabled" : "Enabled"), card->battery[0].good ? "OK" : "FAILURE", (batt_status & BATTERY_2_DISABLED ? "Disabled" : "Enabled"), @@ -1021,14 +1032,16 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i if (request_irq(dev->irq, mm_interrupt, IRQF_SHARED, "pci-umem", card)) { - printk(KERN_ERR "MM%d: Unable to allocate IRQ\n", card->card_number); + dev_printk(KERN_ERR, &card->dev->dev, + "Unable to allocate IRQ\n"); ret = -ENODEV; goto failed_req_irq; } card->irq = dev->irq; - printk(KERN_INFO "MM%d: Window size %d bytes, IRQ %d\n", card->card_number, + dev_printk(KERN_INFO, &card->dev->dev, + "Window size %d bytes, IRQ %d\n", card->win_size, card->irq); spin_lock_init(&card->lock); @@ -1049,10 +1062,12 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i num_cards++; if (!get_userbit(card, MEMORY_INITIALIZED)) { - printk(KERN_INFO "MM%d: memory NOT initialized. Consider over-writing whole device.\n", card->card_number); + dev_printk(KERN_INFO, &card->dev->dev, + "memory NOT initialized. Consider over-writing whole device.\n"); card->init_size = 0; } else { - printk(KERN_INFO "MM%d: memory already initialized\n", card->card_number); + dev_printk(KERN_INFO, &card->dev->dev, + "memory already initialized\n"); card->init_size = card->mm_size; } @@ -1137,8 +1152,6 @@ static int __init mm_init(void) int retval, i; int err; - printk(KERN_INFO DRIVER_VERSION " : " DRIVER_DESC "\n"); - retval = pci_register_driver(&mm_pci_driver); if (retval) return -ENOMEM; @@ -1169,7 +1182,7 @@ static int __init mm_init(void) } init_battery_timer(); - printk("MM: desc_per_page = %ld\n", DESC_PER_PAGE); + printk(KERN_INFO "MM: desc_per_page = %ld\n", DESC_PER_PAGE); /* printk("mm_init: Done. 10-19-01 9:00\n"); */ return 0; -- cgit v1.2.3-70-g09d2 From ee4a7b6874469244ed0e3b8fde20028e0bb52642 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 27 Sep 2007 07:40:33 -0400 Subject: drivers/block/umem: minor cleanups * tab-align DRIVER_*, pci_driver entries * reduced wasted memory by killing unused struct cardinfo members * move free_irq() call above resource unmap, to fix tiny window where irq handler may access recently-unmapped memory * propagate pci_enable_device() return value * use pci_request_regions, pci_release_regions() for resource reservation * call pci_disable_device() in pci_driver::remove() Signed-off-by: Jeff Garzik --- drivers/block/umem.c | 59 ++++++++++++++++++++++++++-------------------------- 1 file changed, 29 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/block/umem.c b/drivers/block/umem.c index 32060b84c0f..97c5dc9436a 100644 --- a/drivers/block/umem.c +++ b/drivers/block/umem.c @@ -67,9 +67,10 @@ * Version Information */ -#define DRIVER_VERSION "v2.3" -#define DRIVER_AUTHOR "San Mehat, Johannes Erdfelt, NeilBrown" -#define DRIVER_DESC "Micro Memory(tm) PCI memory board block driver" +#define DRIVER_NAME "umem" +#define DRIVER_VERSION "v2.3" +#define DRIVER_AUTHOR "San Mehat, Johannes Erdfelt, NeilBrown" +#define DRIVER_DESC "Micro Memory(tm) PCI memory board block driver" static int debug; /* #define HW_TRACE(x) writeb(x,cards[0].csr_remap + MEMCTRLSTATUS_MAGIC) */ @@ -99,12 +100,7 @@ static int major_nr; struct cardinfo { struct pci_dev *dev; - int irq; - - unsigned long csr_base; unsigned char __iomem *csr_remap; - unsigned long csr_len; - unsigned int win_size; /* PCI window size */ unsigned int mm_size; /* size in kbytes */ unsigned int init_size; /* initial segment, in sectors, @@ -869,22 +865,27 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i unsigned char mem_present; unsigned char batt_status; unsigned int saved_bar, data; + unsigned long csr_base; + unsigned long csr_len; int magic_number; static int printed_version; if (!printed_version++) printk(KERN_INFO DRIVER_VERSION " : " DRIVER_DESC "\n"); - if (pci_enable_device(dev) < 0) - return -ENODEV; + ret = pci_enable_device(dev); + if (ret) + return ret; pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF8); pci_set_master(dev); card->dev = dev; - card->csr_base = pci_resource_start(dev, 0); - card->csr_len = pci_resource_len(dev, 0); + csr_base = pci_resource_start(dev, 0); + csr_len = pci_resource_len(dev, 0); + if (!csr_base || !csr_len) + return -ENODEV; dev_printk(KERN_INFO, &dev->dev, "Micro Memory(tm) controller found (PCI Mem Module (Battery Backup))\n"); @@ -894,15 +895,15 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i dev_printk(KERN_WARNING, &dev->dev, "NO suitable DMA found\n"); return -ENOMEM; } - if (!request_mem_region(card->csr_base, card->csr_len, "Micro Memory")) { + + ret = pci_request_regions(dev, DRIVER_NAME); + if (ret) { dev_printk(KERN_ERR, &card->dev->dev, "Unable to request memory region\n"); - ret = -ENOMEM; - goto failed_req_csr; } - card->csr_remap = ioremap_nocache(card->csr_base, card->csr_len); + card->csr_remap = ioremap_nocache(csr_base, csr_len); if (!card->csr_remap) { dev_printk(KERN_ERR, &card->dev->dev, "Unable to remap memory region\n"); @@ -913,7 +914,7 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i dev_printk(KERN_INFO, &card->dev->dev, "CSR 0x%08lx -> 0x%p (0x%lx)\n", - card->csr_base, card->csr_remap, card->csr_len); + csr_base, card->csr_remap, csr_len); switch(card->dev->device) { case 0x5415: @@ -1028,9 +1029,6 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i data = ~data; data += 1; - card->win_size = data; - - if (request_irq(dev->irq, mm_interrupt, IRQF_SHARED, "pci-umem", card)) { dev_printk(KERN_ERR, &card->dev->dev, "Unable to allocate IRQ\n"); @@ -1039,10 +1037,8 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i goto failed_req_irq; } - card->irq = dev->irq; dev_printk(KERN_INFO, &card->dev->dev, - "Window size %d bytes, IRQ %d\n", - card->win_size, card->irq); + "Window size %d bytes, IRQ %d\n", data, dev->irq); spin_lock_init(&card->lock); @@ -1089,7 +1085,7 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i failed_magic: iounmap(card->csr_remap); failed_remap_csr: - release_mem_region(card->csr_base, card->csr_len); + pci_release_regions(dev); failed_req_csr: return ret; @@ -1104,9 +1100,8 @@ static void mm_pci_remove(struct pci_dev *dev) struct cardinfo *card = pci_get_drvdata(dev); tasklet_kill(&card->tasklet); + free_irq(dev->irq, card); iounmap(card->csr_remap); - release_mem_region(card->csr_base, card->csr_len); - free_irq(card->irq, card); if (card->mm_pages[0].desc) pci_free_consistent(card->dev, PAGE_SIZE*2, @@ -1117,6 +1112,9 @@ static void mm_pci_remove(struct pci_dev *dev) card->mm_pages[1].desc, card->mm_pages[1].page_dma); blk_cleanup_queue(card->queue); + + pci_release_regions(dev); + pci_disable_device(dev); } static const struct pci_device_id mm_pci_ids[] = { @@ -1136,11 +1134,12 @@ static const struct pci_device_id mm_pci_ids[] = { MODULE_DEVICE_TABLE(pci, mm_pci_ids); static struct pci_driver mm_pci_driver = { - .name = "umem", - .id_table = mm_pci_ids, - .probe = mm_pci_probe, - .remove = mm_pci_remove, + .name = DRIVER_NAME, + .id_table = mm_pci_ids, + .probe = mm_pci_probe, + .remove = mm_pci_remove, }; + /* ----------------------------------------------------------------------------------- -- mm_init -- cgit v1.2.3-70-g09d2 From 4e953a216265f8646360fa909bdc87ea4bf446b3 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 27 Sep 2007 07:41:50 -0400 Subject: drivers/block/umem: trim trailing whitespace Signed-off-by: Jeff Garzik --- drivers/block/umem.c | 22 +++++++++++----------- drivers/block/umem.h | 14 +++++++------- 2 files changed, 18 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/block/umem.c b/drivers/block/umem.c index 97c5dc9436a..25104176369 100644 --- a/drivers/block/umem.c +++ b/drivers/block/umem.c @@ -293,7 +293,7 @@ static void mm_start_io(struct cardinfo *card) desc->control_bits &= ~cpu_to_le32(DMASCR_CHAIN_EN); desc->sem_control_bits = desc->control_bits; - + if (debug & DEBUG_LED_ON_TRANSFER) set_led(card, LED_REMOVE, LED_ON); @@ -327,7 +327,7 @@ static int add_bio(struct cardinfo *card); static void activate(struct cardinfo *card) { - /* if No page is Active, and Ready is + /* if No page is Active, and Ready is * not empty, then switch Ready page * to active and start IO. * Then add any bh's that are available to Ready @@ -366,7 +366,7 @@ static void mm_unplug_device(struct request_queue *q) spin_unlock_irqrestore(&card->lock, flags); } -/* +/* * If there is room on Ready page, take * one bh off list and add it. * return 1 if there was room, else 0. @@ -467,7 +467,7 @@ static void process_page(unsigned long data) if (card->Active < 0) goto out_unlock; page = &card->mm_pages[card->Active]; - + while (page->headcnt < page->cnt) { struct bio *bio = page->bio; struct mm_dma_desc *desc = &page->desc[page->headcnt]; @@ -477,7 +477,7 @@ static void process_page(unsigned long data) if (!(control & DMASCR_DMA_COMPLETE)) { control = dma_status; - last=1; + last=1; } page->headcnt++; idx = page->idx; @@ -487,7 +487,7 @@ static void process_page(unsigned long data) page->idx = page->bio->bi_idx; } - pci_unmap_page(card->dev, desc->data_dma_handle, + pci_unmap_page(card->dev, desc->data_dma_handle, bio_iovec_idx(bio,idx)->bv_len, (control& DMASCR_TRANSFER_READ) ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); @@ -592,7 +592,7 @@ HW_TRACE(0x30); else writeb((DMASCR_DMA_COMPLETE|DMASCR_CHAIN_COMPLETE) >> 16, card->csr_remap+ DMA_STATUS_CTRL + 2); - + /* log errors and clear interrupt status */ if (dma_status & DMASCR_ANY_ERR) { unsigned int data_log1, data_log2; @@ -668,7 +668,7 @@ HW_TRACE(0x30); HW_TRACE(0x36); - return IRQ_HANDLED; + return IRQ_HANDLED; } /* ----------------------------------------------------------------------------------- @@ -761,7 +761,7 @@ static void check_all_batteries(unsigned long ptr) { int i; - for (i = 0; i < num_cards; i++) + for (i = 0; i < num_cards; i++) if (!(cards[i].flags & UM_FLAG_NO_BATT)) { struct cardinfo *card = &cards[i]; spin_lock_bh(&card->lock); @@ -972,7 +972,7 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i tasklet_init(&card->tasklet, process_page, (unsigned long)card); card->check_batteries = 0; - + mem_present = readb(card->csr_remap + MEMCTRLSTATUS_MEMORY); switch (mem_present) { case MEM_128_MB: @@ -1005,7 +1005,7 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i card->battery[1].good = !(batt_status & BATTERY_2_FAILURE); card->battery[0].last_change = card->battery[1].last_change = jiffies; - if (card->flags & UM_FLAG_NO_BATT) + if (card->flags & UM_FLAG_NO_BATT) dev_printk(KERN_INFO, &card->dev->dev, "Size %d KB\n", card->mm_size); else { diff --git a/drivers/block/umem.h b/drivers/block/umem.h index 3a3819afed9..375c68974c9 100644 --- a/drivers/block/umem.h +++ b/drivers/block/umem.h @@ -87,13 +87,13 @@ #define DMASCR_DMA_COMPLETE 0x40000 #define DMASCR_CHAIN_COMPLETE 0x80000 -/* -3.SOME PCs HAVE HOST BRIDGES WHICH APPARENTLY DO NOT CORRECTLY HANDLE -READ-LINE (0xE) OR READ-MULTIPLE (0xC) PCI COMMAND CODES DURING DMA -TRANSFERS. IN OTHER SYSTEMS THESE COMMAND CODES WILL CAUSE THE HOST BRIDGE -TO ALLOW LONGER BURSTS DURING DMA READ OPERATIONS. THE UPPER FOUR BITS -(31..28) OF THE DMA CSR HAVE BEEN MADE PROGRAMMABLE, SO THAT EITHER A 0x6, -AN 0xE OR A 0xC CAN BE WRITTEN TO THEM TO SET THE COMMAND CODE USED DURING +/* +3.SOME PCs HAVE HOST BRIDGES WHICH APPARENTLY DO NOT CORRECTLY HANDLE +READ-LINE (0xE) OR READ-MULTIPLE (0xC) PCI COMMAND CODES DURING DMA +TRANSFERS. IN OTHER SYSTEMS THESE COMMAND CODES WILL CAUSE THE HOST BRIDGE +TO ALLOW LONGER BURSTS DURING DMA READ OPERATIONS. THE UPPER FOUR BITS +(31..28) OF THE DMA CSR HAVE BEEN MADE PROGRAMMABLE, SO THAT EITHER A 0x6, +AN 0xE OR A 0xC CAN BE WRITTEN TO THEM TO SET THE COMMAND CODE USED DURING DMA READ OPERATIONS. */ #define DMASCR_READ 0x60000000 -- cgit v1.2.3-70-g09d2 From cb3503ca54dc34e8dc3b823a6bd52c0807c102f4 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 27 Sep 2007 07:49:39 -0400 Subject: drivers/block/umem: use DRIVER_NAME where appropriate Signed-off-by: Jeff Garzik --- drivers/block/umem.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/block/umem.c b/drivers/block/umem.c index 25104176369..99806f9ee4c 100644 --- a/drivers/block/umem.c +++ b/drivers/block/umem.c @@ -1029,7 +1029,7 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i data = ~data; data += 1; - if (request_irq(dev->irq, mm_interrupt, IRQF_SHARED, "pci-umem", card)) { + if (request_irq(dev->irq, mm_interrupt, IRQF_SHARED, DRIVER_NAME, card)) { dev_printk(KERN_ERR, &card->dev->dev, "Unable to allocate IRQ\n"); ret = -ENODEV; @@ -1155,7 +1155,7 @@ static int __init mm_init(void) if (retval) return -ENOMEM; - err = major_nr = register_blkdev(0, "umem"); + err = major_nr = register_blkdev(0, DRIVER_NAME); if (err < 0) { pci_unregister_driver(&mm_pci_driver); return -EIO; @@ -1187,7 +1187,7 @@ static int __init mm_init(void) out: pci_unregister_driver(&mm_pci_driver); - unregister_blkdev(major_nr, "umem"); + unregister_blkdev(major_nr, DRIVER_NAME); while (i--) put_disk(mm_gendisk[i]); return -ENOMEM; @@ -1210,7 +1210,7 @@ static void __exit mm_cleanup(void) pci_unregister_driver(&mm_pci_driver); - unregister_blkdev(major_nr, "umem"); + unregister_blkdev(major_nr, DRIVER_NAME); } module_init(mm_init); -- cgit v1.2.3-70-g09d2 From 34e1b83413d91999416443f31c276095f9937aa6 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 4 Oct 2007 08:52:38 +0200 Subject: Sysace: Minor coding convention fixup Put function call and return code test on separate lines. Signed-off-by: Grant Likely Signed-off-by: Jens Axboe --- drivers/block/xsysace.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c index 3ea172b7b7a..3847464f5ea 100644 --- a/drivers/block/xsysace.c +++ b/drivers/block/xsysace.c @@ -1091,7 +1091,8 @@ ace_alloc(struct device *dev, int id, unsigned long physaddr, ace->bus_width = bus_width; /* Call the setup code */ - if ((rc = ace_setup(ace)) != 0) + rc = ace_setup(ace); + if (rc) goto err_setup; dev_set_drvdata(dev, ace); @@ -1253,11 +1254,13 @@ static int __init ace_init(void) goto err_blk; } - if ((rc = ace_of_register()) != 0) + rc = ace_of_register(); + if (rc) goto err_of; pr_debug("xsysace: registering platform binding\n"); - if ((rc = platform_driver_register(&ace_platform_driver)) != 0) + rc = platform_driver_register(&ace_platform_driver); + if (rc) goto err_plat; pr_info("Xilinx SystemACE device driver, major=%i\n", ace_major); -- cgit v1.2.3-70-g09d2 From b5515d86f2efd4dd3516c16c17c1a611a5800b19 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 4 Oct 2007 08:52:39 +0200 Subject: Sysace: sparse fixes Signed-off-by: Grant Likely Signed-off-by: Jens Axboe --- drivers/block/xsysace.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c index 3847464f5ea..5b73471ada7 100644 --- a/drivers/block/xsysace.c +++ b/drivers/block/xsysace.c @@ -195,7 +195,7 @@ struct ace_device { /* Details of hardware device */ unsigned long physaddr; - void *baseaddr; + void __iomem *baseaddr; int irq; int bus_width; /* 0 := 8 bit; 1 := 16 bit */ struct ace_reg_ops *reg_ops; @@ -227,20 +227,20 @@ struct ace_reg_ops { /* 8 Bit bus width */ static u16 ace_in_8(struct ace_device *ace, int reg) { - void *r = ace->baseaddr + reg; + void __iomem *r = ace->baseaddr + reg; return in_8(r) | (in_8(r + 1) << 8); } static void ace_out_8(struct ace_device *ace, int reg, u16 val) { - void *r = ace->baseaddr + reg; + void __iomem *r = ace->baseaddr + reg; out_8(r, val); out_8(r + 1, val >> 8); } static void ace_datain_8(struct ace_device *ace) { - void *r = ace->baseaddr + 0x40; + void __iomem *r = ace->baseaddr + 0x40; u8 *dst = ace->data_ptr; int i = ACE_FIFO_SIZE; while (i--) @@ -250,7 +250,7 @@ static void ace_datain_8(struct ace_device *ace) static void ace_dataout_8(struct ace_device *ace) { - void *r = ace->baseaddr + 0x40; + void __iomem *r = ace->baseaddr + 0x40; u8 *src = ace->data_ptr; int i = ACE_FIFO_SIZE; while (i--) -- cgit v1.2.3-70-g09d2 From d2bbf3da3759d04cd5836955cc59c8ae96092831 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 4 Oct 2007 08:52:40 +0200 Subject: Sysace: Don't enable IRQ until after interrupt handler is registered The previous patch to move the interrupt handler registration moved it below enabling interrupts which could be a problem if the device is on a shared interrupt line. This patch fixes the order. Signed-off-by: Grant Likely Signed-off-by: Jens Axboe --- drivers/block/xsysace.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c index 5b73471ada7..9e7652dcde6 100644 --- a/drivers/block/xsysace.c +++ b/drivers/block/xsysace.c @@ -1005,11 +1005,6 @@ static int __devinit ace_setup(struct ace_device *ace) ace_out(ace, ACE_CTRL, ACE_CTRL_FORCECFGMODE | ACE_CTRL_DATABUFRDYIRQ | ACE_CTRL_ERRORIRQ); - /* Enable interrupts */ - val = ace_in(ace, ACE_CTRL); - val |= ACE_CTRL_DATABUFRDYIRQ | ACE_CTRL_ERRORIRQ; - ace_out(ace, ACE_CTRL, val); - /* Now we can hook up the irq handler */ if (ace->irq != NO_IRQ) { rc = request_irq(ace->irq, ace_interrupt, 0, "systemace", ace); @@ -1020,6 +1015,11 @@ static int __devinit ace_setup(struct ace_device *ace) } } + /* Enable interrupts */ + val = ace_in(ace, ACE_CTRL); + val |= ACE_CTRL_DATABUFRDYIRQ | ACE_CTRL_ERRORIRQ; + ace_out(ace, ACE_CTRL, val); + /* Print the identification */ dev_info(ace->dev, "Xilinx SystemACE revision %i.%i.%i\n", (version >> 12) & 0xf, (version >> 8) & 0x0f, version & 0xff); -- cgit v1.2.3-70-g09d2 From b9a22794f2c186b5722eac94b6735e797d976027 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 4 Oct 2007 10:48:37 -0600 Subject: [POWERPC] XilinxFB: sparse fixes Signed-off-by: Grant Likely --- drivers/video/xilinxfb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index e6e12be845a..dec602c2307 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c @@ -118,7 +118,7 @@ struct xilinxfb_drvdata { u32 regs_phys; /* phys. address of the control registers */ u32 __iomem *regs; /* virt. address of the control registers */ - unsigned char __iomem *fb_virt; /* virt. address of the frame buffer */ + void *fb_virt; /* virt. address of the frame buffer */ dma_addr_t fb_phys; /* phys. address of the frame buffer */ u32 reg_ctrl_default; @@ -246,7 +246,7 @@ static int xilinxfb_assign(struct device *dev, unsigned long physaddr, } /* Clear (turn to black) the framebuffer */ - memset_io(drvdata->fb_virt, 0, FB_SIZE); + memset_io((void __iomem *)drvdata->fb_virt, 0, FB_SIZE); /* Tell the hardware where the frame buffer is */ xilinx_fb_out_be32(drvdata, REG_FB_ADDR, drvdata->fb_phys); @@ -259,7 +259,7 @@ static int xilinxfb_assign(struct device *dev, unsigned long physaddr, /* Fill struct fb_info */ drvdata->info.device = dev; - drvdata->info.screen_base = drvdata->fb_virt; + drvdata->info.screen_base = (void __iomem *)drvdata->fb_virt; drvdata->info.fbops = &xilinxfb_ops; drvdata->info.fix = xilinx_fb_fix; drvdata->info.fix.smem_start = drvdata->fb_phys; -- cgit v1.2.3-70-g09d2 From 7948261942ffdb35e274b8e1a0889601f45d4603 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Wed, 10 Oct 2007 05:37:39 -0300 Subject: V4L/DVB (6311): dvb: Replace list_for_each+list_entry with list_for_each_entry Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_demux.c | 5 +---- drivers/media/dvb/dvb-core/dvbdev.c | 27 ++++++++------------------- 2 files changed, 9 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c index cb6987fce26..7959020f931 100644 --- a/drivers/media/dvb/dvb-core/dvb_demux.c +++ b/drivers/media/dvb/dvb-core/dvb_demux.c @@ -373,13 +373,10 @@ static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed, static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf) { struct dvb_demux_feed *feed; - struct list_head *pos, *head = &demux->feed_list; u16 pid = ts_pid(buf); int dvr_done = 0; - list_for_each(pos, head) { - feed = list_entry(pos, struct dvb_demux_feed, list_head); - + list_for_each_entry(feed, &demux->feed_list, list_head) { if ((feed->pid != pid) && (feed->pid != 0x2000)) continue; diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c index 6b7954daeb4..56231d8edc0 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.c +++ b/drivers/media/dvb/dvb-core/dvbdev.c @@ -58,18 +58,13 @@ static struct class *dvb_class; static struct dvb_device* dvbdev_find_device (int minor) { - struct list_head *entry; + struct dvb_adapter *adap; - list_for_each (entry, &dvb_adapter_list) { - struct list_head *entry0; - struct dvb_adapter *adap; - adap = list_entry (entry, struct dvb_adapter, list_head); - list_for_each (entry0, &adap->device_list) { - struct dvb_device *dev; - dev = list_entry (entry0, struct dvb_device, list_head); + list_for_each_entry(adap, &dvb_adapter_list, list_head) { + struct dvb_device *dev; + list_for_each_entry(dev, &adap->device_list, list_head) if (nums2minor(adap->num, dev->type, dev->id) == minor) return dev; - } } return NULL; @@ -179,13 +174,10 @@ static int dvbdev_get_free_id (struct dvb_adapter *adap, int type) u32 id = 0; while (id < DVB_MAX_IDS) { - struct list_head *entry; - list_for_each (entry, &adap->device_list) { - struct dvb_device *dev; - dev = list_entry (entry, struct dvb_device, list_head); + struct dvb_device *dev; + list_for_each_entry(dev, &adap->device_list, list_head) if (dev->type == type && dev->id == id) goto skip; - } return id; skip: id++; @@ -279,13 +271,10 @@ static int dvbdev_get_free_adapter_num (void) int num = 0; while (num < DVB_MAX_ADAPTERS) { - struct list_head *entry; - list_for_each (entry, &dvb_adapter_list) { - struct dvb_adapter *adap; - adap = list_entry (entry, struct dvb_adapter, list_head); + struct dvb_adapter *adap; + list_for_each_entry(adap, &dvb_adapter_list, list_head) if (adap->num == num) goto skip; - } return num; skip: num++; -- cgit v1.2.3-70-g09d2 From 8bb629e22f2547736c24fe4738673e20cc06d469 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Wed, 10 Oct 2007 05:37:40 -0300 Subject: V4L/DVB (6312): cx88: Replace list_for_each+list_entry with list_for_each_entry Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-core.c | 4 +--- drivers/media/video/cx88/cx88-vbi.c | 5 +---- drivers/media/video/cx88/cx88-video.c | 11 +++-------- 3 files changed, 5 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index 85609b41f86..62e8dd24c5f 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -1013,11 +1013,9 @@ struct video_device *cx88_vdev_init(struct cx88_core *core, struct cx88_core* cx88_core_get(struct pci_dev *pci) { struct cx88_core *core; - struct list_head *item; mutex_lock(&devlist); - list_for_each(item,&cx88_devlist) { - core = list_entry(item, struct cx88_core, devlist); + list_for_each_entry(core, &cx88_devlist, devlist) { if (pci->bus->number != core->pci_bus) continue; if (PCI_SLOT(pci->devfn) != core->pci_slot) diff --git a/drivers/media/video/cx88/cx88-vbi.c b/drivers/media/video/cx88/cx88-vbi.c index aa40505c4b3..babb0855640 100644 --- a/drivers/media/video/cx88/cx88-vbi.c +++ b/drivers/media/video/cx88/cx88-vbi.c @@ -99,7 +99,6 @@ int cx8800_restart_vbi_queue(struct cx8800_dev *dev, struct cx88_dmaqueue *q) { struct cx88_buffer *buf; - struct list_head *item; if (list_empty(&q->active)) return 0; @@ -108,10 +107,8 @@ int cx8800_restart_vbi_queue(struct cx8800_dev *dev, dprintk(2,"restart_queue [%p/%d]: restart dma\n", buf, buf->vb.i); cx8800_start_vbi_dma(dev, q, buf); - list_for_each(item,&q->active) { - buf = list_entry(item, struct cx88_buffer, vb.queue); + list_for_each_entry(buf, &q->active, vb.queue) buf->count = q->count++; - } mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); return 0; } diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index 1439b726853..231ae6c4dd2 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -466,17 +466,14 @@ static int restart_video_queue(struct cx8800_dev *dev, { struct cx88_core *core = dev->core; struct cx88_buffer *buf, *prev; - struct list_head *item; if (!list_empty(&q->active)) { buf = list_entry(q->active.next, struct cx88_buffer, vb.queue); dprintk(2,"restart_queue [%p/%d]: restart dma\n", buf, buf->vb.i); start_video_dma(dev, q, buf); - list_for_each(item,&q->active) { - buf = list_entry(item, struct cx88_buffer, vb.queue); - buf->count = q->count++; - } + list_for_each_entry(buf, &q->active, vb.queue) + buf->count = q->count++; mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); return 0; } @@ -713,12 +710,10 @@ static int video_open(struct inode *inode, struct file *file) struct cx8800_dev *h,*dev = NULL; struct cx88_core *core; struct cx8800_fh *fh; - struct list_head *list; enum v4l2_buf_type type = 0; int radio = 0; - list_for_each(list,&cx8800_devlist) { - h = list_entry(list, struct cx8800_dev, devlist); + list_for_each_entry(h, &cx8800_devlist, devlist) { if (h->video_dev->minor == minor) { dev = h; type = V4L2_BUF_TYPE_VIDEO_CAPTURE; -- cgit v1.2.3-70-g09d2 From 805a43924158e4eb2bffc4cac0aedcfb42a89469 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Wed, 10 Oct 2007 05:37:41 -0300 Subject: V4L/DVB (6313): ivtv: Replace list_for_each+list_entry with list_for_each_entry Also fixed a few cases of cut&paste errors where 'buf' would be set to the first entry in the list prior to be used as the loop iterator. In one case the value of buf was used before it was changed, but the rest were unnecessary. There was one list_for_each+list_entry loop that wasn't changed, since it depending on the loop iterator being left as NULL if the list was empty. Signed-off-by: Trent Piepho CC: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-irq.c | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c index bf7d99c6ffa..fd1688e4757 100644 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ b/drivers/media/video/ivtv/ivtv-irq.c @@ -42,7 +42,6 @@ static void ivtv_pio_work_handler(struct ivtv *itv) { struct ivtv_stream *s = &itv->streams[itv->cur_pio_stream]; struct ivtv_buffer *buf; - struct list_head *p; int i = 0; IVTV_DEBUG_HI_DMA("ivtv_pio_work_handler\n"); @@ -54,9 +53,7 @@ static void ivtv_pio_work_handler(struct ivtv *itv) return; } IVTV_DEBUG_HI_DMA("Process PIO %s\n", s->name); - buf = list_entry(s->q_dma.list.next, struct ivtv_buffer, list); - list_for_each(p, &s->q_dma.list) { - struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list); + list_for_each_entry(buf, &s->q_dma.list, list) { u32 size = s->sg_processing[i].size & 0x3ffff; /* Copy the data from the card to the buffer */ @@ -97,7 +94,6 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA { struct ivtv *itv = s->itv; struct ivtv_buffer *buf; - struct list_head *p; u32 bytes_needed = 0; u32 offset, size; u32 UVoffset = 0, UVsize = 0; @@ -202,9 +198,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA /* got the buffers, now fill in sg_pending */ buf = list_entry(s->q_predma.list.next, struct ivtv_buffer, list); memset(buf->buf, 0, 128); - list_for_each(p, &s->q_predma.list) { - struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list); - + list_for_each_entry(buf, &s->q_predma.list, list) { if (skip_bufs-- > 0) continue; s->sg_pending[idx].dst = buf->dma_handle; @@ -289,9 +283,7 @@ static void dma_post(struct ivtv_stream *s) if (buf) buf->bytesused += s->dma_last_offset; if (buf && s->type == IVTV_DEC_STREAM_TYPE_VBI) { - list_for_each(p, &s->q_dma.list) { - buf = list_entry(p, struct ivtv_buffer, list); - + list_for_each_entry(buf, &s->q_dma.list, list) { /* Parse and Groom VBI Data */ s->q_dma.bytesused -= buf->bytesused; ivtv_process_vbi_data(itv, buf, 0, s->type); @@ -311,7 +303,6 @@ void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock) { struct ivtv *itv = s->itv; struct ivtv_buffer *buf; - struct list_head *p; u32 y_size = itv->params.height * itv->params.width; u32 uv_offset = offset + IVTV_YUV_BUFFER_UV_OFFSET; int y_done = 0; @@ -320,10 +311,7 @@ void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock) int idx = 0; IVTV_DEBUG_HI_DMA("DEC PREPARE DMA %s: %08x %08x\n", s->name, s->q_predma.bytesused, offset); - buf = list_entry(s->q_predma.list.next, struct ivtv_buffer, list); - list_for_each(p, &s->q_predma.list) { - struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list); - + list_for_each_entry(buf, &s->q_predma.list, list) { /* YUV UV Offset from Y Buffer */ if (s->type == IVTV_DEC_STREAM_TYPE_YUV && !y_done && bytes_written >= y_size) { offset = uv_offset; @@ -677,11 +665,9 @@ static void ivtv_irq_enc_vbi_cap(struct ivtv *itv) we just drop the old requests when there are already three requests queued. */ if (s->sg_pending_size > 2) { - struct list_head *p; - list_for_each(p, &s->q_predma.list) { - struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list); + struct ivtv_buffer *buf; + list_for_each_entry(buf, &s->q_predma.list, list) ivtv_buf_sync_for_cpu(s, buf); - } ivtv_queue_move(s, &s->q_predma, NULL, &s->q_free, 0); s->sg_pending_size = 0; } -- cgit v1.2.3-70-g09d2 From 6d28e98906aa9405895f92348543d08da1837ea5 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Wed, 10 Oct 2007 05:37:42 -0300 Subject: V4L/DVB (6314): saa7134: Replace list_for_each+list_entry with list_for_each_entry A couple loops weren't changed because they expected the loop iterator to be left as NULL if the list was empty. Maybe the code should just check for that first, then loop? Adjust some of the loop logic to be simpler. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-core.c | 20 +++---------- drivers/media/video/saa7134/saa7134-empress.c | 15 ++++------ drivers/media/video/saa7134/saa7134-oss.c | 42 ++++++++++----------------- drivers/media/video/saa7134/saa7134-video.c | 22 +++++++------- 4 files changed, 35 insertions(+), 64 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index 80f04f252fc..1a4a24471f2 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -890,7 +890,6 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, const struct pci_device_id *pci_id) { struct saa7134_dev *dev; - struct list_head *item; struct saa7134_mpeg_ops *mops; int err; @@ -1072,10 +1071,8 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, saa7134_devcount++; mutex_lock(&devlist_lock); - list_for_each(item,&mops_list) { - mops = list_entry(item, struct saa7134_mpeg_ops, next); + list_for_each_entry(mops, &mops_list, next) mpeg_ops_attach(mops, dev); - } list_add_tail(&dev->devlist,&saa7134_devlist); mutex_unlock(&devlist_lock); @@ -1109,7 +1106,6 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, static void __devexit saa7134_finidev(struct pci_dev *pci_dev) { struct saa7134_dev *dev = pci_get_drvdata(pci_dev); - struct list_head *item; struct saa7134_mpeg_ops *mops; /* Release DMA sound modules if present */ @@ -1138,10 +1134,8 @@ static void __devexit saa7134_finidev(struct pci_dev *pci_dev) /* unregister */ mutex_lock(&devlist_lock); list_del(&dev->devlist); - list_for_each(item,&mops_list) { - mops = list_entry(item, struct saa7134_mpeg_ops, next); + list_for_each_entry(mops, &mops_list, next) mpeg_ops_detach(mops, dev); - } mutex_unlock(&devlist_lock); saa7134_devcount--; @@ -1237,14 +1231,11 @@ static int saa7134_resume(struct pci_dev *pci_dev) int saa7134_ts_register(struct saa7134_mpeg_ops *ops) { - struct list_head *item; struct saa7134_dev *dev; mutex_lock(&devlist_lock); - list_for_each(item,&saa7134_devlist) { - dev = list_entry(item, struct saa7134_dev, devlist); + list_for_each_entry(dev, &saa7134_devlist, devlist) mpeg_ops_attach(ops, dev); - } list_add_tail(&ops->next,&mops_list); mutex_unlock(&devlist_lock); return 0; @@ -1252,15 +1243,12 @@ int saa7134_ts_register(struct saa7134_mpeg_ops *ops) void saa7134_ts_unregister(struct saa7134_mpeg_ops *ops) { - struct list_head *item; struct saa7134_dev *dev; mutex_lock(&devlist_lock); list_del(&ops->next); - list_for_each(item,&saa7134_devlist) { - dev = list_entry(item, struct saa7134_dev, devlist); + list_for_each_entry(dev, &saa7134_devlist, devlist) mpeg_ops_detach(ops, dev); - } mutex_unlock(&devlist_lock); } diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c index a16df57af63..34ca874dd7f 100644 --- a/drivers/media/video/saa7134/saa7134-empress.c +++ b/drivers/media/video/saa7134/saa7134-empress.c @@ -76,17 +76,14 @@ static int ts_init_encoder(struct saa7134_dev* dev) static int ts_open(struct inode *inode, struct file *file) { int minor = iminor(inode); - struct saa7134_dev *h,*dev = NULL; - struct list_head *list; + struct saa7134_dev *dev; int err; - list_for_each(list,&saa7134_devlist) { - h = list_entry(list, struct saa7134_dev, devlist); - if (h->empress_dev && h->empress_dev->minor == minor) - dev = h; - } - if (NULL == dev) - return -ENODEV; + list_for_each_entry(dev, &saa7134_devlist, devlist) + if (dev->empress_dev && dev->empress_dev->minor == minor) + goto found; + return -ENODEV; + found: dprintk("open minor=%d\n",minor); err = -EBUSY; diff --git a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c index 1a737b64736..aedf04653e0 100644 --- a/drivers/media/video/saa7134/saa7134-oss.c +++ b/drivers/media/video/saa7134/saa7134-oss.c @@ -239,17 +239,14 @@ static int dsp_rec_stop(struct saa7134_dev *dev) static int dsp_open(struct inode *inode, struct file *file) { int minor = iminor(inode); - struct saa7134_dev *h,*dev = NULL; - struct list_head *list; + struct saa7134_dev *dev; int err; - list_for_each(list,&saa7134_devlist) { - h = list_entry(list, struct saa7134_dev, devlist); - if (h->dmasound.minor_dsp == minor) - dev = h; - } - if (NULL == dev) - return -ENODEV; + list_for_each_entry(dev, &saa7134_devlist, devlist) + if (dev->dmasound.minor_dsp == minor) + goto found; + return -ENODEV; + found: mutex_lock(&dev->dmasound.lock); err = -EBUSY; @@ -680,19 +677,14 @@ mixer_level(struct saa7134_dev *dev, enum saa7134_audio_in src, int level) static int mixer_open(struct inode *inode, struct file *file) { int minor = iminor(inode); - struct saa7134_dev *h,*dev = NULL; - struct list_head *list; + struct saa7134_dev *dev; - list_for_each(list,&saa7134_devlist) { - h = list_entry(list, struct saa7134_dev, devlist); - if (h->dmasound.minor_mixer == minor) - dev = h; - } - if (NULL == dev) - return -ENODEV; - - file->private_data = dev; - return 0; + list_for_each_entry(dev, &saa7134_devlist, devlist) + if (dev->dmasound.minor_mixer == minor) { + file->private_data = dev; + return 0; + } + return -ENODEV; } static int mixer_release(struct inode *inode, struct file *file) @@ -1022,18 +1014,14 @@ static int saa7134_oss_init(void) static void saa7134_oss_exit(void) { - struct saa7134_dev *dev = NULL; - struct list_head *list; - - list_for_each(list,&saa7134_devlist) { - dev = list_entry(list, struct saa7134_dev, devlist); + struct saa7134_dev *dev; + list_for_each_entry(dev, &saa7134_devlist, devlist) { /* Device isn't registered by OSS, probably ALSA's */ if (!dev->dmasound.minor_dsp) continue; oss_device_exit(dev); - } saa7134_dmasound_init = NULL; diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 7c97ac15e66..471b92793c1 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -1285,26 +1285,24 @@ static int saa7134_resource(struct saa7134_fh *fh) static int video_open(struct inode *inode, struct file *file) { int minor = iminor(inode); - struct saa7134_dev *h,*dev = NULL; + struct saa7134_dev *dev; struct saa7134_fh *fh; - struct list_head *list; enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; int radio = 0; - list_for_each(list,&saa7134_devlist) { - h = list_entry(list, struct saa7134_dev, devlist); - if (h->video_dev && (h->video_dev->minor == minor)) - dev = h; - if (h->radio_dev && (h->radio_dev->minor == minor)) { + list_for_each_entry(dev, &saa7134_devlist, devlist) { + if (dev->video_dev && (dev->video_dev->minor == minor)) + goto found; + if (dev->radio_dev && (dev->radio_dev->minor == minor)) { radio = 1; - dev = h; + goto found; } - if (h->vbi_dev && (h->vbi_dev->minor == minor)) { + if (dev->vbi_dev && (dev->vbi_dev->minor == minor)) { type = V4L2_BUF_TYPE_VBI_CAPTURE; - dev = h; + goto found; } } - if (NULL == dev) - return -ENODEV; + return -ENODEV; + found: dprintk("open minor=%d radio=%d type=%s\n",minor,radio, v4l2_type_names[type]); -- cgit v1.2.3-70-g09d2 From e77e2c2f2989eefff7e1c0fff9cb72afaedf6796 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Wed, 10 Oct 2007 05:37:42 -0300 Subject: V4L/DVB (6315): pvrusb2: Change list_for_each+list_entry to list_for_each_entry Signed-off-by: Trent Piepho Reviewed-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-hdw.c | 4 +- drivers/media/video/pvrusb2/pvrusb2-i2c-core.c | 51 ++++++++------------------ 2 files changed, 17 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index eec83d6ae78..27b12b4b5c8 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -3458,7 +3458,6 @@ int pvr2_hdw_register_access(struct pvr2_hdw *hdw, int setFl,u64 *val_ptr) { #ifdef CONFIG_VIDEO_ADV_DEBUG - struct list_head *item; struct pvr2_i2c_client *cp; struct v4l2_register req; int stat = 0; @@ -3471,8 +3470,7 @@ int pvr2_hdw_register_access(struct pvr2_hdw *hdw, req.reg = reg_id; if (setFl) req.val = *val_ptr; mutex_lock(&hdw->i2c_list_lock); do { - list_for_each(item,&hdw->i2c_clients) { - cp = list_entry(item,struct pvr2_i2c_client,list); + list_for_each_entry(cp, &hdw->i2c_clients, list) { if (!v4l2_chip_match_i2c_client( cp->client, req.match_type, req.match_chip)) { diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c index 7697f391e8b..898c9d2e4cd 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c +++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c @@ -570,15 +570,13 @@ int pvr2_i2c_client_cmd(struct pvr2_i2c_client *cp,unsigned int cmd,void *arg) int pvr2_i2c_core_cmd(struct pvr2_hdw *hdw,unsigned int cmd,void *arg) { - struct list_head *item,*nc; - struct pvr2_i2c_client *cp; + struct pvr2_i2c_client *cp, *ncp; int stat = -EINVAL; if (!hdw) return stat; mutex_lock(&hdw->i2c_list_lock); - list_for_each_safe(item,nc,&hdw->i2c_clients) { - cp = list_entry(item,struct pvr2_i2c_client,list); + list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients, list) { if (!cp->recv_enable) continue; mutex_unlock(&hdw->i2c_list_lock); stat = pvr2_i2c_client_cmd(cp,cmd,arg); @@ -602,13 +600,11 @@ static int handler_check(struct pvr2_i2c_client *cp) void pvr2_i2c_core_status_poll(struct pvr2_hdw *hdw) { - struct list_head *item; struct pvr2_i2c_client *cp; mutex_lock(&hdw->i2c_list_lock); do { struct v4l2_tuner *vtp = &hdw->tuner_signal_info; memset(vtp,0,sizeof(*vtp)); - list_for_each(item,&hdw->i2c_clients) { - cp = list_entry(item,struct pvr2_i2c_client,list); + list_for_each_entry(cp, &hdw->i2c_clients, list) { if (!cp->detected_flag) continue; if (!cp->status_poll) continue; cp->status_poll(cp); @@ -630,8 +626,7 @@ void pvr2_i2c_core_sync(struct pvr2_hdw *hdw) { unsigned long msk; unsigned int idx; - struct list_head *item,*nc; - struct pvr2_i2c_client *cp; + struct pvr2_i2c_client *cp, *ncp; if (!hdw->i2c_linked) return; if (!(hdw->i2c_pend_types & PVR2_I2C_PEND_ALL)) { @@ -649,9 +644,7 @@ void pvr2_i2c_core_sync(struct pvr2_hdw *hdw) buf = kmalloc(BUFSIZE,GFP_KERNEL); pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_DETECT"); hdw->i2c_pend_types &= ~PVR2_I2C_PEND_DETECT; - list_for_each(item,&hdw->i2c_clients) { - cp = list_entry(item,struct pvr2_i2c_client, - list); + list_for_each_entry(cp, &hdw->i2c_clients, list) { if (!cp->detected_flag) { cp->ctl_mask = 0; pvr2_i2c_probe(hdw,cp); @@ -687,9 +680,7 @@ void pvr2_i2c_core_sync(struct pvr2_hdw *hdw) "i2c: PEND_STALE (0x%lx)", hdw->i2c_stale_mask); hdw->i2c_pend_types &= ~PVR2_I2C_PEND_STALE; - list_for_each(item,&hdw->i2c_clients) { - cp = list_entry(item,struct pvr2_i2c_client, - list); + list_for_each_entry(cp, &hdw->i2c_clients, list) { m2 = hdw->i2c_stale_mask; m2 &= cp->ctl_mask; m2 &= ~cp->pend_mask; @@ -710,9 +701,8 @@ void pvr2_i2c_core_sync(struct pvr2_hdw *hdw) and update each one. */ pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_CLIENT"); hdw->i2c_pend_types &= ~PVR2_I2C_PEND_CLIENT; - list_for_each_safe(item,nc,&hdw->i2c_clients) { - cp = list_entry(item,struct pvr2_i2c_client, - list); + list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients, + list) { if (!cp->handler) continue; if (!cp->handler->func_table->update) continue; pvr2_trace(PVR2_TRACE_I2C_CORE, @@ -744,10 +734,8 @@ void pvr2_i2c_core_sync(struct pvr2_hdw *hdw) for (idx = 0, msk = 1; pm; idx++, msk <<= 1) { if (!(pm & msk)) continue; pm &= ~msk; - list_for_each(item,&hdw->i2c_clients) { - cp = list_entry(item, - struct pvr2_i2c_client, - list); + list_for_each_entry(cp, &hdw->i2c_clients, + list) { if (cp->pend_mask & msk) { cp->pend_mask &= ~msk; cp->recv_enable = !0; @@ -771,7 +759,6 @@ int pvr2_i2c_core_check_stale(struct pvr2_hdw *hdw) unsigned long msk,sm,pm; unsigned int idx; const struct pvr2_i2c_op *opf; - struct list_head *item; struct pvr2_i2c_client *cp; unsigned int pt = 0; @@ -790,11 +777,9 @@ int pvr2_i2c_core_check_stale(struct pvr2_hdw *hdw) } if (sm) pt |= PVR2_I2C_PEND_STALE; - list_for_each(item,&hdw->i2c_clients) { - cp = list_entry(item,struct pvr2_i2c_client,list); - if (!handler_check(cp)) continue; - pt |= PVR2_I2C_PEND_CLIENT; - } + list_for_each_entry(cp, &hdw->i2c_clients, list) + if (handler_check(cp)) + pt |= PVR2_I2C_PEND_CLIENT; if (pt) { mutex_lock(&hdw->i2c_list_lock); do { @@ -882,12 +867,10 @@ unsigned int pvr2_i2c_report(struct pvr2_hdw *hdw, char *buf,unsigned int maxlen) { unsigned int ccnt,bcnt; - struct list_head *item; struct pvr2_i2c_client *cp; ccnt = 0; mutex_lock(&hdw->i2c_list_lock); do { - list_for_each(item,&hdw->i2c_clients) { - cp = list_entry(item,struct pvr2_i2c_client,list); + list_for_each_entry(cp, &hdw->i2c_clients, list) { bcnt = pvr2_i2c_client_describe( cp, (PVR2_I2C_DETAIL_HANDLER| @@ -925,13 +908,11 @@ static int pvr2_i2c_attach_inform(struct i2c_client *client) static int pvr2_i2c_detach_inform(struct i2c_client *client) { struct pvr2_hdw *hdw = (struct pvr2_hdw *)(client->adapter->algo_data); - struct pvr2_i2c_client *cp; - struct list_head *item,*nc; + struct pvr2_i2c_client *cp, *ncp; unsigned long amask = 0; int foundfl = 0; mutex_lock(&hdw->i2c_list_lock); do { - list_for_each_safe(item,nc,&hdw->i2c_clients) { - cp = list_entry(item,struct pvr2_i2c_client,list); + list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients, list) { if (cp->client == client) { trace_i2c("pvr2_i2c_detach" " [client=%s @ 0x%x ctxt=%p]", -- cgit v1.2.3-70-g09d2 From a991f44b79fa49b281eb078eed4a76a42101012a Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Wed, 10 Oct 2007 05:37:43 -0300 Subject: V4L/DVB (6316): Change list_for_each+list_entry to list_for_each_entry The rest of V4L files. There is one list_for_each+list_entry in cpia_pp.c that wasn't changed because it expects the loop iterator to remain NULL if the list is empty. A bug in vivi is fixed; the 'safe' version needs to be used because the loop deletes the list entries. Simplify a second loop in vivi and get rid if an un-used variable in that loop. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bt8xx/bttv-gpio.c | 6 ++---- drivers/media/video/cx23885/cx23885-core.c | 5 +---- drivers/media/video/dpc7146.c | 5 +---- drivers/media/video/em28xx/em28xx-video.c | 4 +--- drivers/media/video/mxb.c | 4 +--- drivers/media/video/tvmixer.c | 5 +---- drivers/media/video/v4l2-int-device.c | 14 +++----------- drivers/media/video/videobuf-core.c | 5 +---- drivers/media/video/vivi.c | 27 +++++++++------------------ 9 files changed, 20 insertions(+), 55 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/bt8xx/bttv-gpio.c b/drivers/media/video/bt8xx/bttv-gpio.c index 84154c26f9c..dce6dae5740 100644 --- a/drivers/media/video/bt8xx/bttv-gpio.c +++ b/drivers/media/video/bt8xx/bttv-gpio.c @@ -106,11 +106,9 @@ int bttv_sub_add_device(struct bttv_core *core, char *name) int bttv_sub_del_devices(struct bttv_core *core) { - struct bttv_sub_device *sub; - struct list_head *item,*save; + struct bttv_sub_device *sub, *save; - list_for_each_safe(item,save,&core->subs) { - sub = list_entry(item,struct bttv_sub_device,list); + list_for_each_entry_safe(sub, save, &core->subs, list) { list_del(&sub->list); device_unregister(&sub->dev); } diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 4d0614093ad..af16505bd2e 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -1100,7 +1100,6 @@ static int cx23885_restart_queue(struct cx23885_tsport *port, { struct cx23885_dev *dev = port->dev; struct cx23885_buffer *buf; - struct list_head *item; dprintk(5, "%s()\n", __FUNCTION__); if (list_empty(&q->active)) @@ -1148,10 +1147,8 @@ static int cx23885_restart_queue(struct cx23885_tsport *port, dprintk(2, "restart_queue [%p/%d]: restart dma\n", buf, buf->vb.i); cx23885_start_dma(port, q, buf); - list_for_each(item, &q->active) { - buf = list_entry(item, struct cx23885_buffer, vb.queue); + list_for_each_entry(buf, &q->active, vb.queue) buf->count = q->count++; - } mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); return 0; } diff --git a/drivers/media/video/dpc7146.c b/drivers/media/video/dpc7146.c index 0fcc935828f..255dae30370 100644 --- a/drivers/media/video/dpc7146.c +++ b/drivers/media/video/dpc7146.c @@ -92,7 +92,6 @@ static int dpc_probe(struct saa7146_dev* dev) { struct dpc* dpc = NULL; struct i2c_client *client; - struct list_head *item; dpc = kzalloc(sizeof(struct dpc), GFP_KERNEL); if( NULL == dpc ) { @@ -116,11 +115,9 @@ static int dpc_probe(struct saa7146_dev* dev) } /* loop through all i2c-devices on the bus and look who is there */ - list_for_each(item,&dpc->i2c_adapter.clients) { - client = list_entry(item, struct i2c_client, list); + list_for_each_entry(client, &dpc->i2c_adapter.clients, list) if( I2C_SAA7111A == client->addr ) dpc->saa7111a = client; - } /* check if all devices are present */ if( 0 == dpc->saa7111a ) { diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index e4fba906833..b8d5327c438 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -252,10 +252,8 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) int minor = iminor(inode); int errCode = 0; struct em28xx *h,*dev = NULL; - struct list_head *list; - list_for_each(list,&em28xx_devlist) { - h = list_entry(list, struct em28xx, devlist); + list_for_each_entry(h, &em28xx_devlist, devlist) { if (h->vdev->minor == minor) { dev = h; dev->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c index 152cc6b3e15..98ad3092a07 100644 --- a/drivers/media/video/mxb.c +++ b/drivers/media/video/mxb.c @@ -153,7 +153,6 @@ static int mxb_probe(struct saa7146_dev* dev) { struct mxb* mxb = NULL; struct i2c_client *client; - struct list_head *item; int result; if ((result = request_module("saa7111")) < 0) { @@ -196,8 +195,7 @@ static int mxb_probe(struct saa7146_dev* dev) } /* loop through all i2c-devices on the bus and look who is there */ - list_for_each(item,&mxb->i2c_adapter.clients) { - client = list_entry(item, struct i2c_client, list); + list_for_each_entry(client, &mxb->i2c_adapter.clients, list) { if( I2C_ADDR_TEA6420_1 == client->addr ) mxb->tea6420_1 = client; if( I2C_ADDR_TEA6420_2 == client->addr ) diff --git a/drivers/media/video/tvmixer.c b/drivers/media/video/tvmixer.c index 544a4ae7d2e..9fa5b702e07 100644 --- a/drivers/media/video/tvmixer.c +++ b/drivers/media/video/tvmixer.c @@ -237,13 +237,10 @@ static const struct file_operations tvmixer_fops = { static int tvmixer_adapters(struct i2c_adapter *adap) { - struct list_head *item; struct i2c_client *client; - list_for_each(item,&adap->clients) { - client = list_entry(item, struct i2c_client, list); + list_for_each_entry(client, &adap->clients, list) tvmixer_clients(client); - } return 0; } diff --git a/drivers/media/video/v4l2-int-device.c b/drivers/media/video/v4l2-int-device.c index f497c945834..8b4ef530a3a 100644 --- a/drivers/media/video/v4l2-int-device.c +++ b/drivers/media/video/v4l2-int-device.c @@ -34,21 +34,13 @@ static LIST_HEAD(int_list); static void v4l2_int_device_try_attach_all(void) { - struct list_head *head_master; - - list_for_each(head_master, &int_list) { - struct list_head *head_slave; - struct v4l2_int_device *m = - list_entry(head_master, struct v4l2_int_device, head); + struct v4l2_int_device *m, *s; + list_for_each_entry(m, &int_list, head) { if (m->type != v4l2_int_type_master) continue; - list_for_each(head_slave, &int_list) { - struct v4l2_int_device *s = - list_entry(head_slave, - struct v4l2_int_device, head); - + list_for_each_entry(s, &int_list, head) { if (s->type != v4l2_int_type_slave) continue; diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index 25a98496e3d..c606332512b 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c @@ -517,7 +517,6 @@ int videobuf_dqbuf(struct videobuf_queue *q, int videobuf_streamon(struct videobuf_queue *q) { struct videobuf_buffer *buf; - struct list_head *list; unsigned long flags=0; int retval; @@ -531,11 +530,9 @@ int videobuf_streamon(struct videobuf_queue *q) q->streaming = 1; if (q->irqlock) spin_lock_irqsave(q->irqlock,flags); - list_for_each(list,&q->stream) { - buf = list_entry(list, struct videobuf_buffer, stream); + list_for_each_entry(buf, &q->stream, stream) if (buf->state == STATE_PREPARED) q->ops->buf_queue(q,buf); - } if (q->irqlock) spin_unlock_irqrestore(q->irqlock,flags); diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 61a6608d6e6..b532aa280a1 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -507,7 +507,6 @@ static void vivi_stop_thread(struct vivi_dmaqueue *dma_q) static int restart_video_queue(struct vivi_dmaqueue *dma_q) { struct vivi_buffer *buf, *prev; - struct list_head *item; dprintk(1,"%s dma_q=0x%08lx\n",__FUNCTION__,(unsigned long)dma_q); @@ -521,9 +520,7 @@ static int restart_video_queue(struct vivi_dmaqueue *dma_q) // vivi_start_thread(dma_q); /* cancel all outstanding capture / vbi requests */ - list_for_each(item,&dma_q->active) { - buf = list_entry(item, struct vivi_buffer, vb.queue); - + list_for_each_entry_safe(buf, prev, &dma_q->active, vb.queue) { list_del(&buf->vb.queue); buf->vb.state = STATE_ERROR; wake_up(&buf->vb.done); @@ -982,31 +979,25 @@ static int vidioc_s_ctrl (struct file *file, void *priv, static int vivi_open(struct inode *inode, struct file *file) { int minor = iminor(inode); - struct vivi_dev *h,*dev = NULL; + struct vivi_dev *dev; struct vivi_fh *fh; - struct list_head *list; - enum v4l2_buf_type type = 0; int i; printk(KERN_DEBUG "vivi: open called (minor=%d)\n",minor); - list_for_each(list,&vivi_devlist) { - h = list_entry(list, struct vivi_dev, vivi_devlist); - if (h->vfd.minor == minor) { - dev = h; - type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - } - } - if (NULL == dev) - return -ENODEV; + list_for_each_entry(dev, &vivi_devlist, vivi_devlist) + if (dev->vfd.minor == minor) + goto found; + return -ENODEV; +found: /* If more than one user, mutex should be added */ dev->users++; - dprintk(1,"open minor=%d type=%s users=%d\n", - minor,v4l2_type_names[type],dev->users); + dprintk(1, "open minor=%d type=%s users=%d\n", minor, + v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users); /* allocate + initialize per filehandle data */ fh = kzalloc(sizeof(*fh),GFP_KERNEL); -- cgit v1.2.3-70-g09d2 From c783837bc69dd0f329a441c1704f5a02d01d1bd5 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Tue, 9 Oct 2007 17:07:58 -0400 Subject: pxamci: support arbitrary block size The PXA has two transmit FIFOes, each32 byte deep. when one FIFO is full and the other one has been transmitted, they are automatically swapped and DMA is triggered for another 32 byte burst. However, when there is less than 32 bytes left to send, the FIFO swap has to be done manually. This is required for some SDIO transfers which are not required to be multiples of 32 bytes. A DMA completion interrupt is set for each descriptor which length isn't a multiple of 32 in order to force the FIFO swap. While at it, the DMA interrupt handler has been made a bit more resilient against errors. Signed-off-by: Nicolas Pitre Signed-off-by: Pierre Ossman --- drivers/mmc/host/pxamci.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index 91e25683b39..657901eecfc 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -142,6 +142,10 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data) host->dma_dir); for (i = 0; i < host->dma_len; i++) { + unsigned int length = sg_dma_len(&data->sg[i]); + host->sg_cpu[i].dcmd = dcmd | length; + if (length & 31 && !(data->flags & MMC_DATA_READ)) + host->sg_cpu[i].dcmd |= DCMD_ENDIRQEN; if (data->flags & MMC_DATA_READ) { host->sg_cpu[i].dsadr = host->res->start + MMC_RXFIFO; host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]); @@ -149,7 +153,6 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data) host->sg_cpu[i].dsadr = sg_dma_address(&data->sg[i]); host->sg_cpu[i].dtadr = host->res->start + MMC_TXFIFO; } - host->sg_cpu[i].dcmd = dcmd | sg_dma_len(&data->sg[i]); host->sg_cpu[i].ddadr = host->sg_dma + (i + 1) * sizeof(struct pxa_dma_desc); } @@ -414,8 +417,18 @@ static const struct mmc_host_ops pxamci_ops = { static void pxamci_dma_irq(int dma, void *devid) { - printk(KERN_ERR "DMA%d: IRQ???\n", dma); - DCSR(dma) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR; + struct pxamci_host *host = devid; + int dcsr = DCSR(dma); + DCSR(dma) = dcsr & ~DCSR_STOPIRQEN; + + if (dcsr & DCSR_ENDINTR) { + writel(BUF_PART_FULL, host->base + MMC_PRTBUF); + } else { + printk(KERN_ERR "%s: DMA error on channel %d (DCSR=%#x)\n", + mmc_hostname(host->mmc), dma, dcsr); + host->data->error = -EIO; + pxamci_data_done(host, 0); + } } static irqreturn_t pxamci_detect_irq(int irq, void *devid) -- cgit v1.2.3-70-g09d2 From 55a98e955caab78a5959933a4a3a0136e2491d6c Mon Sep 17 00:00:00 2001 From: Eli Cohen Date: Wed, 10 Oct 2007 17:55:37 +0200 Subject: IB/mthca: Mark error paths as unlikely() in post_srq_recv functions Signed-off-by: Eli Cohen Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_srq.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mthca/mthca_srq.c b/drivers/infiniband/hw/mthca/mthca_srq.c index 88d219e730a..3f58c11a62b 100644 --- a/drivers/infiniband/hw/mthca/mthca_srq.c +++ b/drivers/infiniband/hw/mthca/mthca_srq.c @@ -509,7 +509,7 @@ int mthca_tavor_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr, for (nreq = 0; wr; wr = wr->next) { ind = srq->first_free; - if (ind < 0) { + if (unlikely(ind < 0)) { mthca_err(dev, "SRQ %06x full\n", srq->srqn); err = -ENOMEM; *bad_wr = wr; @@ -519,7 +519,7 @@ int mthca_tavor_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr, wqe = get_wqe(srq, ind); next_ind = *wqe_to_link(wqe); - if (next_ind < 0) { + if (unlikely(next_ind < 0)) { mthca_err(dev, "SRQ %06x full\n", srq->srqn); err = -ENOMEM; *bad_wr = wr; @@ -623,7 +623,7 @@ int mthca_arbel_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr, for (nreq = 0; wr; ++nreq, wr = wr->next) { ind = srq->first_free; - if (ind < 0) { + if (unlikely(ind < 0)) { mthca_err(dev, "SRQ %06x full\n", srq->srqn); err = -ENOMEM; *bad_wr = wr; @@ -633,7 +633,7 @@ int mthca_arbel_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr, wqe = get_wqe(srq, ind); next_ind = *wqe_to_link(wqe); - if (next_ind < 0) { + if (unlikely(next_ind < 0)) { mthca_err(dev, "SRQ %06x full\n", srq->srqn); err = -ENOMEM; *bad_wr = wr; -- cgit v1.2.3-70-g09d2 From 335a64a5a958002bc238c90de695e120c3c8c120 Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Mon, 8 Oct 2007 10:13:00 +0200 Subject: IPoIB: Allow setting policy to ignore multicast groups The kernel IB stack allows (through the RDMA CM) userspace applications to join and use multicast groups from the IPoIB MGID range. This allows multicast traffic to be handled directly from userspace QPs, without going through the kernel stack, which gives better performance for some applications. However, to fully interoperate with IP multicast, such userspace applications need to participate in IGMP reports and queries, or else routers may not forward the multicast traffic to the system where the application is running. The simplest way to do this is to share the kernel IGMP implementation by using the IP_ADD_MEMBERSHIP option to join multicast groups that are being handled directly in userspace. However, in such cases, the actual multicast traffic should not also be handled by the IPoIB interface, because that would burn resources handling multicast packets that will just be discarded in the kernel. To handle this, this patch adds lookup on the database used for IB multicast group reference counting when IPoIB is joining multicast groups, and if a multicast group is already handled by user space, then the IPoIB kernel driver ignores the group. This is controlled by a per-interface policy flag. When the flag is set, IPoIB will not join and attach its QP to a multicast group which already has an entry in the database; when the flag is cleared, IPoIB will behave as before this change. For each IPoIB interface, the /sys/class/net/$intf/umcast attribute controls the policy flag. The default value is off/0. Signed-off-by: Or Gerlitz Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/ipoib/ipoib.h | 2 ++ drivers/infiniband/ulp/ipoib/ipoib_main.c | 33 ++++++++++++++++++++++++++ drivers/infiniband/ulp/ipoib/ipoib_multicast.c | 9 +++++++ drivers/infiniband/ulp/ipoib/ipoib_vlan.c | 2 ++ 4 files changed, 46 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index fc16bced8e5..a198ce8371d 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h @@ -86,6 +86,7 @@ enum { IPOIB_MCAST_STARTED = 8, IPOIB_FLAG_NETIF_STOPPED = 9, IPOIB_FLAG_ADMIN_CM = 10, + IPOIB_FLAG_UMCAST = 11, IPOIB_MAX_BACKOFF_SECONDS = 16, @@ -384,6 +385,7 @@ static inline void ipoib_put_ah(struct ipoib_ah *ah) int ipoib_open(struct net_device *dev); int ipoib_add_pkey_attr(struct net_device *dev); +int ipoib_add_umcast_attr(struct net_device *dev); void ipoib_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_ah *address, u32 qpn); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 900335a36e4..ff17fe3c765 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -1019,6 +1019,37 @@ static ssize_t show_pkey(struct device *dev, } static DEVICE_ATTR(pkey, S_IRUGO, show_pkey, NULL); +static ssize_t show_umcast(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ipoib_dev_priv *priv = netdev_priv(to_net_dev(dev)); + + return sprintf(buf, "%d\n", test_bit(IPOIB_FLAG_UMCAST, &priv->flags)); +} + +static ssize_t set_umcast(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ipoib_dev_priv *priv = netdev_priv(to_net_dev(dev)); + unsigned long umcast_val = simple_strtoul(buf, NULL, 0); + + if (umcast_val > 0) { + set_bit(IPOIB_FLAG_UMCAST, &priv->flags); + ipoib_warn(priv, "ignoring multicast groups joined directly " + "by userspace\n"); + } else + clear_bit(IPOIB_FLAG_UMCAST, &priv->flags); + + return count; +} +static DEVICE_ATTR(umcast, S_IWUSR | S_IRUGO, show_umcast, set_umcast); + +int ipoib_add_umcast_attr(struct net_device *dev) +{ + return device_create_file(&dev->dev, &dev_attr_umcast); +} + static ssize_t create_child(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -1136,6 +1167,8 @@ static struct net_device *ipoib_add_port(const char *format, goto sysfs_failed; if (ipoib_add_pkey_attr(priv->dev)) goto sysfs_failed; + if (ipoib_add_umcast_attr(priv->dev)) + goto sysfs_failed; if (device_create_file(&priv->dev->dev, &dev_attr_create_child)) goto sysfs_failed; if (device_create_file(&priv->dev->dev, &dev_attr_delete_child)) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index 94a57097e2b..62abfb6f35c 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -761,6 +761,7 @@ void ipoib_mcast_restart_task(struct work_struct *work) struct ipoib_mcast *mcast, *tmcast; LIST_HEAD(remove_list); unsigned long flags; + struct ib_sa_mcmember_rec rec; ipoib_dbg_mcast(priv, "restarting multicast task\n"); @@ -794,6 +795,14 @@ void ipoib_mcast_restart_task(struct work_struct *work) if (!mcast || test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)) { struct ipoib_mcast *nmcast; + /* ignore group which is directly joined by userspace */ + if (test_bit(IPOIB_FLAG_UMCAST, &priv->flags) && + !ib_sa_get_mcmember_rec(priv->ca, priv->port, &mgid, &rec)) { + ipoib_dbg_mcast(priv, "ignoring multicast entry for mgid " + IPOIB_GID_FMT "\n", IPOIB_GID_ARG(mgid)); + continue; + } + /* Not found or send-only group, let's add a new entry */ ipoib_dbg_mcast(priv, "adding multicast entry for mgid " IPOIB_GID_FMT "\n", IPOIB_GID_ARG(mgid)); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c index 6762988439d..293f5b892e3 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c @@ -119,6 +119,8 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey) goto sysfs_failed; if (ipoib_add_pkey_attr(priv->dev)) goto sysfs_failed; + if (ipoib_add_umcast_attr(priv->dev)) + goto sysfs_failed; if (device_create_file(&priv->dev->dev, &dev_attr_parent)) goto sysfs_failed; -- cgit v1.2.3-70-g09d2 From 3d73c2884f45f9a297cbc956cea101405a9703f2 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Wed, 10 Oct 2007 15:43:54 -0700 Subject: mlx4_core: Fix section mismatches Commit ee49bd93 ("mlx4_core: Reset device when internal error is detected") introduced some section mismatch problems when CONFIG_HOTPLUG=n, because the error recovery code tears down and reinitializes the device after everything is loaded, which ends up calling into lots of code marked __devinit and __devexit from regular .text. Fix this by getting rid of these now-incorrect section markers. Signed-off-by: Roland Dreier --- drivers/net/mlx4/cq.c | 2 +- drivers/net/mlx4/eq.c | 13 ++++++------- drivers/net/mlx4/main.c | 38 +++++++++++++++++++++----------------- drivers/net/mlx4/mcg.c | 2 +- drivers/net/mlx4/mr.c | 2 +- drivers/net/mlx4/pd.c | 2 +- drivers/net/mlx4/qp.c | 2 +- drivers/net/mlx4/srq.c | 2 +- 8 files changed, 33 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/net/mlx4/cq.c b/drivers/net/mlx4/cq.c index 39253d0c159..d4441fee3d8 100644 --- a/drivers/net/mlx4/cq.c +++ b/drivers/net/mlx4/cq.c @@ -231,7 +231,7 @@ void mlx4_cq_free(struct mlx4_dev *dev, struct mlx4_cq *cq) } EXPORT_SYMBOL_GPL(mlx4_cq_free); -int __devinit mlx4_init_cq_table(struct mlx4_dev *dev) +int mlx4_init_cq_table(struct mlx4_dev *dev) { struct mlx4_cq_table *cq_table = &mlx4_priv(dev)->cq_table; int err; diff --git a/drivers/net/mlx4/eq.c b/drivers/net/mlx4/eq.c index 2095c843fa1..9c36c203403 100644 --- a/drivers/net/mlx4/eq.c +++ b/drivers/net/mlx4/eq.c @@ -300,8 +300,7 @@ static int mlx4_HW2SW_EQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, MLX4_CMD_TIME_CLASS_A); } -static void __devinit __iomem *mlx4_get_eq_uar(struct mlx4_dev *dev, - struct mlx4_eq *eq) +static void __iomem *mlx4_get_eq_uar(struct mlx4_dev *dev, struct mlx4_eq *eq) { struct mlx4_priv *priv = mlx4_priv(dev); int index; @@ -323,8 +322,8 @@ static void __devinit __iomem *mlx4_get_eq_uar(struct mlx4_dev *dev, return priv->eq_table.uar_map[index] + 0x800 + 8 * (eq->eqn % 4); } -static int __devinit mlx4_create_eq(struct mlx4_dev *dev, int nent, - u8 intr, struct mlx4_eq *eq) +static int mlx4_create_eq(struct mlx4_dev *dev, int nent, + u8 intr, struct mlx4_eq *eq) { struct mlx4_priv *priv = mlx4_priv(dev); struct mlx4_cmd_mailbox *mailbox; @@ -485,7 +484,7 @@ static void mlx4_free_irqs(struct mlx4_dev *dev) free_irq(eq_table->eq[i].irq, eq_table->eq + i); } -static int __devinit mlx4_map_clr_int(struct mlx4_dev *dev) +static int mlx4_map_clr_int(struct mlx4_dev *dev) { struct mlx4_priv *priv = mlx4_priv(dev); @@ -506,7 +505,7 @@ static void mlx4_unmap_clr_int(struct mlx4_dev *dev) iounmap(priv->clr_base); } -int __devinit mlx4_map_eq_icm(struct mlx4_dev *dev, u64 icm_virt) +int mlx4_map_eq_icm(struct mlx4_dev *dev, u64 icm_virt) { struct mlx4_priv *priv = mlx4_priv(dev); int ret; @@ -548,7 +547,7 @@ void mlx4_unmap_eq_icm(struct mlx4_dev *dev) __free_page(priv->eq_table.icm_page); } -int __devinit mlx4_init_eq_table(struct mlx4_dev *dev) +int mlx4_init_eq_table(struct mlx4_dev *dev) { struct mlx4_priv *priv = mlx4_priv(dev); int err; diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c index 478b3ba74ed..e029b8afbd3 100644 --- a/drivers/net/mlx4/main.c +++ b/drivers/net/mlx4/main.c @@ -85,7 +85,7 @@ static struct mlx4_profile default_profile = { .num_mtt = 1 << 20, }; -static int __devinit mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) +static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) { int err; int i; @@ -256,10 +256,8 @@ err: return err; } -static int __devinit mlx4_init_icm(struct mlx4_dev *dev, - struct mlx4_dev_cap *dev_cap, - struct mlx4_init_hca_param *init_hca, - u64 icm_size) +static int mlx4_init_icm(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap, + struct mlx4_init_hca_param *init_hca, u64 icm_size) { struct mlx4_priv *priv = mlx4_priv(dev); u64 aux_pages; @@ -481,7 +479,7 @@ static void mlx4_close_hca(struct mlx4_dev *dev) mlx4_free_icm(dev, mlx4_priv(dev)->fw.fw_icm, 0); } -static int __devinit mlx4_init_hca(struct mlx4_dev *dev) +static int mlx4_init_hca(struct mlx4_dev *dev) { struct mlx4_priv *priv = mlx4_priv(dev); struct mlx4_adapter adapter; @@ -554,7 +552,7 @@ err_stop_fw: return err; } -static int __devinit mlx4_setup_hca(struct mlx4_dev *dev) +static int mlx4_setup_hca(struct mlx4_dev *dev) { struct mlx4_priv *priv = mlx4_priv(dev); int err; @@ -721,19 +719,12 @@ no_msi: priv->eq_table.eq[i].irq = dev->pdev->irq; } -static int __devinit mlx4_init_one(struct pci_dev *pdev, - const struct pci_device_id *id) +static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id) { - static int mlx4_version_printed; struct mlx4_priv *priv; struct mlx4_dev *dev; int err; - if (!mlx4_version_printed) { - printk(KERN_INFO "%s", mlx4_version); - ++mlx4_version_printed; - } - printk(KERN_INFO PFX "Initializing %s\n", pci_name(pdev)); @@ -883,7 +874,20 @@ err_disable_pdev: return err; } -static void __devexit mlx4_remove_one(struct pci_dev *pdev) +static int __devinit mlx4_init_one(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + static int mlx4_version_printed; + + if (!mlx4_version_printed) { + printk(KERN_INFO "%s", mlx4_version); + ++mlx4_version_printed; + } + + return mlx4_init_one(pdev, id); +} + +static void mlx4_remove_one(struct pci_dev *pdev) { struct mlx4_dev *dev = pci_get_drvdata(pdev); struct mlx4_priv *priv = mlx4_priv(dev); @@ -924,7 +928,7 @@ static void __devexit mlx4_remove_one(struct pci_dev *pdev) int mlx4_restart_one(struct pci_dev *pdev) { mlx4_remove_one(pdev); - return mlx4_init_one(pdev, NULL); + return __mlx4_init_one(pdev, NULL); } static struct pci_device_id mlx4_pci_table[] = { diff --git a/drivers/net/mlx4/mcg.c b/drivers/net/mlx4/mcg.c index 672024a0ee7..a99e7729d33 100644 --- a/drivers/net/mlx4/mcg.c +++ b/drivers/net/mlx4/mcg.c @@ -359,7 +359,7 @@ out: } EXPORT_SYMBOL_GPL(mlx4_multicast_detach); -int __devinit mlx4_init_mcg_table(struct mlx4_dev *dev) +int mlx4_init_mcg_table(struct mlx4_dev *dev) { struct mlx4_priv *priv = mlx4_priv(dev); int err; diff --git a/drivers/net/mlx4/mr.c b/drivers/net/mlx4/mr.c index 4bc39e65015..0c05a10bae3 100644 --- a/drivers/net/mlx4/mr.c +++ b/drivers/net/mlx4/mr.c @@ -430,7 +430,7 @@ int mlx4_buf_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt, } EXPORT_SYMBOL_GPL(mlx4_buf_write_mtt); -int __devinit mlx4_init_mr_table(struct mlx4_dev *dev) +int mlx4_init_mr_table(struct mlx4_dev *dev) { struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table; int err; diff --git a/drivers/net/mlx4/pd.c b/drivers/net/mlx4/pd.c index 23dea1ee775..3a93c5f0f7a 100644 --- a/drivers/net/mlx4/pd.c +++ b/drivers/net/mlx4/pd.c @@ -57,7 +57,7 @@ void mlx4_pd_free(struct mlx4_dev *dev, u32 pdn) } EXPORT_SYMBOL_GPL(mlx4_pd_free); -int __devinit mlx4_init_pd_table(struct mlx4_dev *dev) +int mlx4_init_pd_table(struct mlx4_dev *dev) { struct mlx4_priv *priv = mlx4_priv(dev); diff --git a/drivers/net/mlx4/qp.c b/drivers/net/mlx4/qp.c index 278414b2d01..cc4b1be1821 100644 --- a/drivers/net/mlx4/qp.c +++ b/drivers/net/mlx4/qp.c @@ -251,7 +251,7 @@ static int mlx4_CONF_SPECIAL_QP(struct mlx4_dev *dev, u32 base_qpn) MLX4_CMD_TIME_CLASS_B); } -int __devinit mlx4_init_qp_table(struct mlx4_dev *dev) +int mlx4_init_qp_table(struct mlx4_dev *dev) { struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table; int err; diff --git a/drivers/net/mlx4/srq.c b/drivers/net/mlx4/srq.c index 31b255a3291..d23f46d692e 100644 --- a/drivers/net/mlx4/srq.c +++ b/drivers/net/mlx4/srq.c @@ -235,7 +235,7 @@ err_out: } EXPORT_SYMBOL_GPL(mlx4_srq_query); -int __devinit mlx4_init_srq_table(struct mlx4_dev *dev) +int mlx4_init_srq_table(struct mlx4_dev *dev) { struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table; int err; -- cgit v1.2.3-70-g09d2 From 7e9ed18874f0df84b6651f0636e1cfdac43bc610 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Fri, 27 Jul 2007 15:43:24 +0200 Subject: [MAC80211]: improved short preamble handling Similarly to CTS protection, whether short preambles are used for 802.11b transmissions should be a per-subif setting, not device global. For STAs, this patch makes short preamble handling automatic based on the ERP IE. For APs, hostapd still uses the prism ioctls, but the write ioctl has been restricted to AP-only subifs. ieee80211_txrx_data.short_preamble (an unused field) was removed. Unfortunately, some API changes were required for the following functions: - ieee80211_generic_frame_duration - ieee80211_rts_duration - ieee80211_ctstoself_duration - ieee80211_rts_get - ieee80211_ctstoself_get Affected drivers were updated accordingly. Signed-off-by: Daniel Drake Signed-off-by: Jiri Benc Signed-off-by: John W. Linville --- drivers/net/wireless/rtl8187.h | 1 + drivers/net/wireless/rtl8187_dev.c | 4 +++- include/net/mac80211.h | 15 ++++++++++----- net/mac80211/ieee80211_i.h | 7 +++++-- net/mac80211/ieee80211_ioctl.c | 7 +++++-- net/mac80211/ieee80211_sta.c | 16 +++++++++++++++- net/mac80211/tx.c | 31 ++++++++++++++++++------------- net/mac80211/util.c | 37 +++++++++++++++++++++++++++++++------ 8 files changed, 88 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rtl8187.h b/drivers/net/wireless/rtl8187.h index 6124e467b15..7993b3d8720 100644 --- a/drivers/net/wireless/rtl8187.h +++ b/drivers/net/wireless/rtl8187.h @@ -67,6 +67,7 @@ struct rtl8187_priv { struct rtl818x_csr *map; void (*rf_init)(struct ieee80211_hw *); int mode; + int if_id; /* rtl8187 specific */ struct ieee80211_channel channels[14]; diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index e61c6d5ba1a..73f1ebc7eec 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c @@ -96,7 +96,7 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb, if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) { tmp |= RTL8187_TX_FLAG_RTS; hdr->rts_duration = - ieee80211_rts_duration(dev, skb->len, control); + ieee80211_rts_duration(dev, priv->if_id, skb->len, control); } if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) tmp |= RTL8187_TX_FLAG_CTS; @@ -510,6 +510,8 @@ static int rtl8187_config_interface(struct ieee80211_hw *dev, int if_id, struct rtl8187_priv *priv = dev->priv; int i; + priv->if_id = if_id; + for (i = 0; i < ETH_ALEN; i++) rtl818x_iowrite8(priv, &priv->map->BSSID[i], conf->bssid[i]); diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 91cee0f0aa7..3282038a151 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -835,6 +835,7 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, /** * ieee80211_rts_get - RTS frame generation function * @hw: pointer obtained from ieee80211_alloc_hw(). + * @if_id: interface ID from &struct ieee80211_if_init_conf. * @frame: pointer to the frame that is going to be protected by the RTS. * @frame_len: the frame length (in octets). * @frame_txctl: &struct ieee80211_tx_control of the frame. @@ -845,7 +846,7 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, * the next RTS frame from the 802.11 code. The low-level is responsible * for calling this function before and RTS frame is needed. */ -void ieee80211_rts_get(struct ieee80211_hw *hw, +void ieee80211_rts_get(struct ieee80211_hw *hw, int if_id, const void *frame, size_t frame_len, const struct ieee80211_tx_control *frame_txctl, struct ieee80211_rts *rts); @@ -853,6 +854,7 @@ void ieee80211_rts_get(struct ieee80211_hw *hw, /** * ieee80211_rts_duration - Get the duration field for an RTS frame * @hw: pointer obtained from ieee80211_alloc_hw(). + * @if_id: interface ID from &struct ieee80211_if_init_conf. * @frame_len: the length of the frame that is going to be protected by the RTS. * @frame_txctl: &struct ieee80211_tx_control of the frame. * @@ -860,13 +862,14 @@ void ieee80211_rts_get(struct ieee80211_hw *hw, * the duration field, the low-level driver uses this function to receive * the duration field value in little-endian byteorder. */ -__le16 ieee80211_rts_duration(struct ieee80211_hw *hw, +__le16 ieee80211_rts_duration(struct ieee80211_hw *hw, int if_id, size_t frame_len, const struct ieee80211_tx_control *frame_txctl); /** * ieee80211_ctstoself_get - CTS-to-self frame generation function * @hw: pointer obtained from ieee80211_alloc_hw(). + * @if_id: interface ID from &struct ieee80211_if_init_conf. * @frame: pointer to the frame that is going to be protected by the CTS-to-self. * @frame_len: the frame length (in octets). * @frame_txctl: &struct ieee80211_tx_control of the frame. @@ -877,7 +880,7 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, * the next CTS-to-self frame from the 802.11 code. The low-level is responsible * for calling this function before and CTS-to-self frame is needed. */ -void ieee80211_ctstoself_get(struct ieee80211_hw *hw, +void ieee80211_ctstoself_get(struct ieee80211_hw *hw, int if_id, const void *frame, size_t frame_len, const struct ieee80211_tx_control *frame_txctl, struct ieee80211_cts *cts); @@ -885,6 +888,7 @@ void ieee80211_ctstoself_get(struct ieee80211_hw *hw, /** * ieee80211_ctstoself_duration - Get the duration field for a CTS-to-self frame * @hw: pointer obtained from ieee80211_alloc_hw(). + * @if_id: interface ID from &struct ieee80211_if_init_conf. * @frame_len: the length of the frame that is going to be protected by the CTS-to-self. * @frame_txctl: &struct ieee80211_tx_control of the frame. * @@ -892,20 +896,21 @@ void ieee80211_ctstoself_get(struct ieee80211_hw *hw, * the duration field, the low-level driver uses this function to receive * the duration field value in little-endian byteorder. */ -__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, +__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, int if_id, size_t frame_len, const struct ieee80211_tx_control *frame_txctl); /** * ieee80211_generic_frame_duration - Calculate the duration field for a frame * @hw: pointer obtained from ieee80211_alloc_hw(). + * @if_id: interface ID from &struct ieee80211_if_init_conf. * @frame_len: the length of the frame. * @rate: the rate (in 100kbps) at which the frame is going to be transmitted. * * Calculate the duration field of some generic frame, given its * length and transmission rate (in 100kbps). */ -__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, +__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, int if_id, size_t frame_len, int rate); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index e76a5867895..b0af6e9f531 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -127,7 +127,6 @@ struct ieee80211_txrx_data { struct ieee80211_tx_control *control; unsigned int unicast:1; unsigned int ps_buffered:1; - unsigned int short_preamble:1; unsigned int probe_last_frag:1; struct ieee80211_hw_mode *mode; struct ieee80211_rate *rate; @@ -286,6 +285,11 @@ struct ieee80211_sub_if_data { unsigned int promisc:1; unsigned int use_protection:1; /* CTS protect ERP frames */ + /* use short preamble with IEEE 802.11b: this flag is set when the AP + * or beacon generator reports that there are no present stations that + * cannot support short preambles */ + unsigned int short_preamble:1; + struct net_device_stats stats; int drop_unencrypted; int eapol; /* 0 = process EAPOL frames as normal data frames, @@ -447,7 +451,6 @@ struct ieee80211_local { int fragmentation_threshold; int short_retry_limit; /* dot11ShortRetryLimit */ int long_retry_limit; /* dot11LongRetryLimit */ - int short_preamble; /* use short preamble with IEEE 802.11b */ struct crypto_blkcipher *wep_tx_tfm; struct crypto_blkcipher *wep_rx_tfm; diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index e7904db5532..8292431ac48 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c @@ -1061,7 +1061,10 @@ static int ieee80211_ioctl_prism2_param(struct net_device *dev, break; case PRISM2_PARAM_PREAMBLE: - local->short_preamble = value; + if (sdata->type != IEEE80211_IF_TYPE_AP) + ret = -ENOENT; + else + sdata->short_preamble = value; break; case PRISM2_PARAM_STAT_TIME: @@ -1184,7 +1187,7 @@ static int ieee80211_ioctl_get_prism2_param(struct net_device *dev, break; case PRISM2_PARAM_PREAMBLE: - *param = local->short_preamble; + *param = sdata->short_preamble; break; case PRISM2_PARAM_STAT_TIME: diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 8e6548974a9..0f5f8131bd7 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -318,6 +318,7 @@ static void ieee80211_handle_erp_ie(struct net_device *dev, u8 erp_value) struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_if_sta *ifsta = &sdata->u.sta; int use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0; + int preamble_mode = (erp_value & WLAN_ERP_BARKER_PREAMBLE) != 0; if (use_protection != sdata->use_protection) { if (net_ratelimit()) { @@ -329,6 +330,18 @@ static void ieee80211_handle_erp_ie(struct net_device *dev, u8 erp_value) } sdata->use_protection = use_protection; } + + if (!preamble_mode != sdata->short_preamble) { + if (net_ratelimit()) { + printk(KERN_DEBUG "%s: switched to %s barker preamble" + " (BSSID=" MAC_FMT ")\n", + dev->name, + (preamble_mode == WLAN_ERP_PREAMBLE_SHORT) ? + "short" : "long", + MAC_ARG(ifsta->bssid)); + } + sdata->short_preamble = !preamble_mode; + } } @@ -415,6 +428,7 @@ static void ieee80211_set_associated(struct net_device *dev, ieee80211_sta_send_associnfo(dev, ifsta); } else { netif_carrier_off(dev); + sdata->short_preamble = 0; sdata->use_protection = 0; memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); } @@ -2281,7 +2295,7 @@ static int ieee80211_sta_join_ibss(struct net_device *dev, "for IBSS beacon\n", dev->name); break; } - control.tx_rate = (local->short_preamble && + control.tx_rate = (sdata->short_preamble && (rate->flags & IEEE80211_RATE_PREAMBLE2)) ? rate->val2 : rate->val; control.antenna_sel_tx = local->hw.conf.antenna_sel_tx; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 532cf5127b7..36761c7139b 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -173,7 +173,7 @@ static u16 ieee80211_duration(struct ieee80211_txrx_data *tx, int group_addr, * to closest integer */ dur = ieee80211_frame_duration(local, 10, rate, erp, - local->short_preamble); + tx->sdata->short_preamble); if (next_frag_len) { /* Frame is fragmented: duration increases with time needed to @@ -182,7 +182,7 @@ static u16 ieee80211_duration(struct ieee80211_txrx_data *tx, int group_addr, /* next fragment */ dur += ieee80211_frame_duration(local, next_frag_len, txrate->rate, erp, - local->short_preamble); + tx->sdata->short_preamble); } return dur; @@ -627,12 +627,6 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_txrx_data *tx) tx->u.tx.control->rate = tx->u.tx.rate; } tx->u.tx.control->tx_rate = tx->u.tx.rate->val; - if ((tx->u.tx.rate->flags & IEEE80211_RATE_PREAMBLE2) && - tx->local->short_preamble && - (!tx->sta || (tx->sta->flags & WLAN_STA_SHORT_PREAMBLE))) { - tx->u.tx.short_preamble = 1; - tx->u.tx.control->tx_rate = tx->u.tx.rate->val2; - } return TXRX_CONTINUE; } @@ -641,6 +635,7 @@ static ieee80211_txrx_result ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; + u16 fc = le16_to_cpu(hdr->frame_control); u16 dur; struct ieee80211_tx_control *control = tx->u.tx.control; struct ieee80211_hw_mode *mode = tx->u.tx.mode; @@ -677,6 +672,16 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) !(control->flags & IEEE80211_TXCTL_USE_RTS_CTS)) control->flags |= IEEE80211_TXCTL_USE_CTS_PROTECT; + /* Transmit data frames using short preambles if the driver supports + * short preambles at the selected rate and short preambles are + * available on the network at the current point in time. */ + if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) && + (tx->u.tx.rate->flags & IEEE80211_RATE_PREAMBLE2) && + tx->sdata->short_preamble && + (!tx->sta || (tx->sta->flags & WLAN_STA_SHORT_PREAMBLE))) { + tx->u.tx.control->tx_rate = tx->u.tx.rate->val2; + } + /* Setup duration field for the first fragment of the frame. Duration * for remaining fragments will be updated when they are being sent * to low-level driver in ieee80211_tx(). */ @@ -1750,7 +1755,7 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, int if_id, return NULL; } - control->tx_rate = (local->short_preamble && + control->tx_rate = (sdata->short_preamble && (rate->flags & IEEE80211_RATE_PREAMBLE2)) ? rate->val2 : rate->val; control->antenna_sel_tx = local->hw.conf.antenna_sel_tx; @@ -1765,7 +1770,7 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, int if_id, } EXPORT_SYMBOL(ieee80211_beacon_get); -void ieee80211_rts_get(struct ieee80211_hw *hw, +void ieee80211_rts_get(struct ieee80211_hw *hw, int if_id, const void *frame, size_t frame_len, const struct ieee80211_tx_control *frame_txctl, struct ieee80211_rts *rts) @@ -1775,13 +1780,13 @@ void ieee80211_rts_get(struct ieee80211_hw *hw, fctl = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS; rts->frame_control = cpu_to_le16(fctl); - rts->duration = ieee80211_rts_duration(hw, frame_len, frame_txctl); + rts->duration = ieee80211_rts_duration(hw, if_id, frame_len, frame_txctl); memcpy(rts->ra, hdr->addr1, sizeof(rts->ra)); memcpy(rts->ta, hdr->addr2, sizeof(rts->ta)); } EXPORT_SYMBOL(ieee80211_rts_get); -void ieee80211_ctstoself_get(struct ieee80211_hw *hw, +void ieee80211_ctstoself_get(struct ieee80211_hw *hw, int if_id, const void *frame, size_t frame_len, const struct ieee80211_tx_control *frame_txctl, struct ieee80211_cts *cts) @@ -1791,7 +1796,7 @@ void ieee80211_ctstoself_get(struct ieee80211_hw *hw, fctl = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTS; cts->frame_control = cpu_to_le16(fctl); - cts->duration = ieee80211_ctstoself_duration(hw, frame_len, frame_txctl); + cts->duration = ieee80211_ctstoself_duration(hw, if_id, frame_len, frame_txctl); memcpy(cts->ra, hdr->addr1, sizeof(cts->ra)); } EXPORT_SYMBOL(ieee80211_ctstoself_get); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index c4565830947..091ac0d634a 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -314,31 +314,46 @@ int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, } /* Exported duration function for driver use */ -__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, +__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, int if_id, size_t frame_len, int rate) { struct ieee80211_local *local = hw_to_local(hw); + struct net_device *bdev = dev_get_by_index(if_id); + struct ieee80211_sub_if_data *sdata; u16 dur; int erp; + if (unlikely(!bdev)) + return 0; + + sdata = IEEE80211_DEV_TO_SUB_IF(bdev); erp = ieee80211_is_erp_rate(hw->conf.phymode, rate); dur = ieee80211_frame_duration(local, frame_len, rate, - erp, local->short_preamble); + erp, sdata->short_preamble); + dev_put(bdev); return cpu_to_le16(dur); } EXPORT_SYMBOL(ieee80211_generic_frame_duration); -__le16 ieee80211_rts_duration(struct ieee80211_hw *hw, +__le16 ieee80211_rts_duration(struct ieee80211_hw *hw, int if_id, size_t frame_len, const struct ieee80211_tx_control *frame_txctl) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_rate *rate; - int short_preamble = local->short_preamble; + struct net_device *bdev = dev_get_by_index(if_id); + struct ieee80211_sub_if_data *sdata; + int short_preamble; int erp; u16 dur; + if (unlikely(!bdev)) + return 0; + + sdata = IEEE80211_DEV_TO_SUB_IF(bdev); + short_preamble = sdata->short_preamble; + rate = frame_txctl->rts_rate; erp = !!(rate->flags & IEEE80211_RATE_ERP); @@ -352,20 +367,29 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, dur += ieee80211_frame_duration(local, 10, rate->rate, erp, short_preamble); + dev_put(bdev); return cpu_to_le16(dur); } EXPORT_SYMBOL(ieee80211_rts_duration); -__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, +__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, int if_id, size_t frame_len, const struct ieee80211_tx_control *frame_txctl) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_rate *rate; - int short_preamble = local->short_preamble; + struct net_device *bdev = dev_get_by_index(if_id); + struct ieee80211_sub_if_data *sdata; + int short_preamble; int erp; u16 dur; + if (unlikely(!bdev)) + return 0; + + sdata = IEEE80211_DEV_TO_SUB_IF(bdev); + short_preamble = sdata->short_preamble; + rate = frame_txctl->rts_rate; erp = !!(rate->flags & IEEE80211_RATE_ERP); @@ -378,6 +402,7 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, erp, short_preamble); } + dev_put(bdev); return cpu_to_le16(dur); } EXPORT_SYMBOL(ieee80211_ctstoself_duration); -- cgit v1.2.3-70-g09d2 From bea3348eef27e6044b6161fd04c3152215f96411 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 3 Oct 2007 16:41:36 -0700 Subject: [NET]: Make NAPI polling independent of struct net_device objects. Several devices have multiple independant RX queues per net device, and some have a single interrupt doorbell for several queues. In either case, it's easier to support layouts like that if the structure representing the poll is independant from the net device itself. The signature of the ->poll() call back goes from: int foo_poll(struct net_device *dev, int *budget) to int foo_poll(struct napi_struct *napi, int budget) The caller is returned the number of RX packets processed (or the number of "NAPI credits" consumed if you want to get abstract). The callee no longer messes around bumping dev->quota, *budget, etc. because that is all handled in the caller upon return. The napi_struct is to be embedded in the device driver private data structures. Furthermore, it is the driver's responsibility to disable all NAPI instances in it's ->stop() device close handler. Since the napi_struct is privatized into the driver's private data structures, only the driver knows how to get at all of the napi_struct instances it may have per-device. With lots of help and suggestions from Rusty Russell, Roland Dreier, Michael Chan, Jeff Garzik, and Jamal Hadi Salim. Bug fixes from Thomas Graf, Roland Dreier, Peter Zijlstra, Joseph Fannin, Scott Wood, Hans J. Koch, and Michael Chan. [ Ported to current tree and all drivers converted. Integrated Stephen's follow-on kerneldoc additions, and restored poll_list handling to the old style to fix mutual exclusion issues. -DaveM ] Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- Documentation/DocBook/kernel-api.tmpl | 8 +- Documentation/networking/NAPI_HOWTO.txt | 766 ------------------------------ Documentation/networking/netdevices.txt | 12 +- drivers/infiniband/ulp/ipoib/ipoib.h | 4 +- drivers/infiniband/ulp/ipoib/ipoib_ib.c | 43 +- drivers/infiniband/ulp/ipoib/ipoib_main.c | 11 +- drivers/net/8139cp.c | 41 +- drivers/net/8139too.c | 48 +- drivers/net/amd8111e.c | 30 +- drivers/net/amd8111e.h | 2 + drivers/net/arm/ep93xx_eth.c | 72 ++- drivers/net/b44.c | 48 +- drivers/net/b44.h | 2 + drivers/net/bnx2.c | 47 +- drivers/net/bnx2.h | 2 + drivers/net/cassini.c | 40 +- drivers/net/cassini.h | 2 + drivers/net/chelsio/common.h | 1 + drivers/net/chelsio/cxgb2.c | 9 +- drivers/net/chelsio/sge.c | 29 +- drivers/net/chelsio/sge.h | 2 +- drivers/net/cxgb3/adapter.h | 22 +- drivers/net/cxgb3/cxgb3_main.c | 96 ++-- drivers/net/cxgb3/sge.c | 170 +++---- drivers/net/e100.c | 37 +- drivers/net/e1000/e1000.h | 1 + drivers/net/e1000/e1000_main.c | 45 +- drivers/net/ehea/ehea.h | 2 +- drivers/net/ehea/ehea_main.c | 129 ++--- drivers/net/epic100.c | 36 +- drivers/net/fec_8xx/fec_8xx.h | 2 + drivers/net/fec_8xx/fec_main.c | 59 ++- drivers/net/forcedeth.c | 69 +-- drivers/net/fs_enet/fs_enet-main.c | 55 +-- drivers/net/fs_enet/fs_enet.h | 1 + drivers/net/gianfar.c | 47 +- drivers/net/gianfar.h | 3 + drivers/net/ibmveth.c | 117 +++-- drivers/net/ibmveth.h | 1 + drivers/net/ixgb/ixgb.h | 1 + drivers/net/ixgb/ixgb_main.c | 29 +- drivers/net/ixp2000/ixpdev.c | 39 +- drivers/net/ixp2000/ixpdev.h | 2 + drivers/net/macb.c | 40 +- drivers/net/macb.h | 1 + drivers/net/mv643xx_eth.c | 48 +- drivers/net/mv643xx_eth.h | 2 + drivers/net/myri10ge/myri10ge.c | 40 +- drivers/net/natsemi.c | 42 +- drivers/net/netxen/netxen_nic.h | 1 + drivers/net/netxen/netxen_nic_main.c | 39 +- drivers/net/pasemi_mac.c | 36 +- drivers/net/pasemi_mac.h | 1 + drivers/net/pcnet32.c | 82 ++-- drivers/net/ps3_gelic_net.c | 45 +- drivers/net/ps3_gelic_net.h | 1 + drivers/net/qla3xxx.c | 29 +- drivers/net/qla3xxx.h | 2 + drivers/net/r8169.c | 58 ++- drivers/net/s2io.c | 35 +- drivers/net/s2io.h | 3 +- drivers/net/sb1250-mac.c | 47 +- drivers/net/sis190.c | 19 +- drivers/net/skge.c | 44 +- drivers/net/skge.h | 1 + drivers/net/sky2.c | 94 ++-- drivers/net/sky2.h | 1 + drivers/net/spider_net.c | 60 ++- drivers/net/spider_net.h | 2 + drivers/net/starfire.c | 51 +- drivers/net/sungem.c | 52 +- drivers/net/sungem.h | 1 + drivers/net/tc35815.c | 49 +- drivers/net/tg3.c | 61 ++- drivers/net/tg3.h | 1 + drivers/net/tsi108_eth.c | 40 +- drivers/net/tulip/interrupt.c | 54 +-- drivers/net/tulip/tulip.h | 3 +- drivers/net/tulip/tulip_core.c | 11 +- drivers/net/typhoon.c | 47 +- drivers/net/ucc_geth.c | 64 +-- drivers/net/ucc_geth.h | 1 + drivers/net/via-rhine.c | 42 +- drivers/net/xen-netfront.c | 33 +- include/linux/netdevice.h | 361 +++++++++++--- include/linux/netpoll.h | 55 ++- net/core/dev.c | 180 ++++--- net/core/net-sysfs.c | 15 - net/core/netpoll.c | 39 +- net/core/rtnetlink.c | 6 - net/sched/sch_generic.c | 12 + 91 files changed, 1758 insertions(+), 2375 deletions(-) delete mode 100644 Documentation/networking/NAPI_HOWTO.txt (limited to 'drivers') diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl index b886f52a9aa..e5da4f2b7c2 100644 --- a/Documentation/DocBook/kernel-api.tmpl +++ b/Documentation/DocBook/kernel-api.tmpl @@ -240,17 +240,23 @@ X!Ilib/string.c Driver Support !Enet/core/dev.c !Enet/ethernet/eth.c +!Enet/sched/sch_generic.c !Iinclude/linux/etherdevice.h +!Iinclude/linux/netdevice.h + + PHY Support !Edrivers/net/phy/phy.c !Idrivers/net/phy/phy.c !Edrivers/net/phy/phy_device.c !Idrivers/net/phy/phy_device.c !Edrivers/net/phy/mdio_bus.c !Idrivers/net/phy/mdio_bus.c + +--> Synchronous PPP !Edrivers/net/wan/syncppp.c diff --git a/Documentation/networking/NAPI_HOWTO.txt b/Documentation/networking/NAPI_HOWTO.txt deleted file mode 100644 index 7907435a661..00000000000 --- a/Documentation/networking/NAPI_HOWTO.txt +++ /dev/null @@ -1,766 +0,0 @@ -HISTORY: -February 16/2002 -- revision 0.2.1: -COR typo corrected -February 10/2002 -- revision 0.2: -some spell checking ;-> -January 12/2002 -- revision 0.1 -This is still work in progress so may change. -To keep up to date please watch this space. - -Introduction to NAPI -==================== - -NAPI is a proven (www.cyberus.ca/~hadi/usenix-paper.tgz) technique -to improve network performance on Linux. For more details please -read that paper. -NAPI provides a "inherent mitigation" which is bound by system capacity -as can be seen from the following data collected by Robert on Gigabit -ethernet (e1000): - - Psize Ipps Tput Rxint Txint Done Ndone - --------------------------------------------------------------- - 60 890000 409362 17 27622 7 6823 - 128 758150 464364 21 9301 10 7738 - 256 445632 774646 42 15507 21 12906 - 512 232666 994445 241292 19147 241192 1062 - 1024 119061 1000003 872519 19258 872511 0 - 1440 85193 1000003 946576 19505 946569 0 - - -Legend: -"Ipps" stands for input packets per second. -"Tput" == packets out of total 1M that made it out. -"txint" == transmit completion interrupts seen -"Done" == The number of times that the poll() managed to pull all -packets out of the rx ring. Note from this that the lower the -load the more we could clean up the rxring -"Ndone" == is the converse of "Done". Note again, that the higher -the load the more times we couldn't clean up the rxring. - -Observe that: -when the NIC receives 890Kpackets/sec only 17 rx interrupts are generated. -The system cant handle the processing at 1 interrupt/packet at that load level. -At lower rates on the other hand, rx interrupts go up and therefore the -interrupt/packet ratio goes up (as observable from that table). So there is -possibility that under low enough input, you get one poll call for each -input packet caused by a single interrupt each time. And if the system -cant handle interrupt per packet ratio of 1, then it will just have to -chug along .... - - -0) Prerequisites: -================== -A driver MAY continue using the old 2.4 technique for interfacing -to the network stack and not benefit from the NAPI changes. -NAPI additions to the kernel do not break backward compatibility. -NAPI, however, requires the following features to be available: - -A) DMA ring or enough RAM to store packets in software devices. - -B) Ability to turn off interrupts or maybe events that send packets up -the stack. - -NAPI processes packet events in what is known as dev->poll() method. -Typically, only packet receive events are processed in dev->poll(). -The rest of the events MAY be processed by the regular interrupt handler -to reduce processing latency (justified also because there are not that -many of them). -Note, however, NAPI does not enforce that dev->poll() only processes -receive events. -Tests with the tulip driver indicated slightly increased latency if -all of the interrupt handler is moved to dev->poll(). Also MII handling -gets a little trickier. -The example used in this document is to move the receive processing only -to dev->poll(); this is shown with the patch for the tulip driver. -For an example of code that moves all the interrupt driver to -dev->poll() look at the ported e1000 code. - -There are caveats that might force you to go with moving everything to -dev->poll(). Different NICs work differently depending on their status/event -acknowledgement setup. -There are two types of event register ACK mechanisms. - I) what is known as Clear-on-read (COR). - when you read the status/event register, it clears everything! - The natsemi and sunbmac NICs are known to do this. - In this case your only choice is to move all to dev->poll() - - II) Clear-on-write (COW) - i) you clear the status by writing a 1 in the bit-location you want. - These are the majority of the NICs and work the best with NAPI. - Put only receive events in dev->poll(); leave the rest in - the old interrupt handler. - ii) whatever you write in the status register clears every thing ;-> - Cant seem to find any supported by Linux which do this. If - someone knows such a chip email us please. - Move all to dev->poll() - -C) Ability to detect new work correctly. -NAPI works by shutting down event interrupts when there's work and -turning them on when there's none. -New packets might show up in the small window while interrupts were being -re-enabled (refer to appendix 2). A packet might sneak in during the period -we are enabling interrupts. We only get to know about such a packet when the -next new packet arrives and generates an interrupt. -Essentially, there is a small window of opportunity for a race condition -which for clarity we'll refer to as the "rotting packet". - -This is a very important topic and appendix 2 is dedicated for more -discussion. - -Locking rules and environmental guarantees -========================================== - --Guarantee: Only one CPU at any time can call dev->poll(); this is because -only one CPU can pick the initial interrupt and hence the initial -netif_rx_schedule(dev); -- The core layer invokes devices to send packets in a round robin format. -This implies receive is totally lockless because of the guarantee that only -one CPU is executing it. -- contention can only be the result of some other CPU accessing the rx -ring. This happens only in close() and suspend() (when these methods -try to clean the rx ring); -****guarantee: driver authors need not worry about this; synchronization -is taken care for them by the top net layer. --local interrupts are enabled (if you dont move all to dev->poll()). For -example link/MII and txcomplete continue functioning just same old way. -This improves the latency of processing these events. It is also assumed that -the receive interrupt is the largest cause of noise. Note this might not -always be true. -[according to Manfred Spraul, the winbond insists on sending one -txmitcomplete interrupt for each packet (although this can be mitigated)]. -For these broken drivers, move all to dev->poll(). - -For the rest of this text, we'll assume that dev->poll() only -processes receive events. - -new methods introduce by NAPI -============================= - -a) netif_rx_schedule(dev) -Called by an IRQ handler to schedule a poll for device - -b) netif_rx_schedule_prep(dev) -puts the device in a state which allows for it to be added to the -CPU polling list if it is up and running. You can look at this as -the first half of netif_rx_schedule(dev) above; the second half -being c) below. - -c) __netif_rx_schedule(dev) -Add device to the poll list for this CPU; assuming that _prep above -has already been called and returned 1. - -d) netif_rx_reschedule(dev, undo) -Called to reschedule polling for device specifically for some -deficient hardware. Read Appendix 2 for more details. - -e) netif_rx_complete(dev) - -Remove interface from the CPU poll list: it must be in the poll list -on current cpu. This primitive is called by dev->poll(), when -it completes its work. The device cannot be out of poll list at this -call, if it is then clearly it is a BUG(). You'll know ;-> - -All of the above methods are used below, so keep reading for clarity. - -Device driver changes to be made when porting NAPI -================================================== - -Below we describe what kind of changes are required for NAPI to work. - -1) introduction of dev->poll() method -===================================== - -This is the method that is invoked by the network core when it requests -for new packets from the driver. A driver is allowed to send upto -dev->quota packets by the current CPU before yielding to the network -subsystem (so other devices can also get opportunity to send to the stack). - -dev->poll() prototype looks as follows: -int my_poll(struct net_device *dev, int *budget) - -budget is the remaining number of packets the network subsystem on the -current CPU can send up the stack before yielding to other system tasks. -*Each driver is responsible for decrementing budget by the total number of -packets sent. - Total number of packets cannot exceed dev->quota. - -dev->poll() method is invoked by the top layer, the driver just sends if it -can to the stack the packet quantity requested. - -more on dev->poll() below after the interrupt changes are explained. - -2) registering dev->poll() method -=================================== - -dev->poll should be set in the dev->probe() method. -e.g: -dev->open = my_open; -. -. -/* two new additions */ -/* first register my poll method */ -dev->poll = my_poll; -/* next register my weight/quanta; can be overridden in /proc */ -dev->weight = 16; -. -. -dev->stop = my_close; - - - -3) scheduling dev->poll() -============================= -This involves modifying the interrupt handler and the code -path which takes the packet off the NIC and sends them to the -stack. - -it's important at this point to introduce the classical D Becker -interrupt processor: - ------------------- -static irqreturn_t -netdevice_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - - struct net_device *dev = (struct net_device *)dev_instance; - struct my_private *tp = (struct my_private *)dev->priv; - - int work_count = my_work_count; - status = read_interrupt_status_reg(); - if (status == 0) - return IRQ_NONE; /* Shared IRQ: not us */ - if (status == 0xffff) - return IRQ_HANDLED; /* Hot unplug */ - if (status & error) - do_some_error_handling() - - do { - acknowledge_ints_ASAP(); - - if (status & link_interrupt) { - spin_lock(&tp->link_lock); - do_some_link_stat_stuff(); - spin_lock(&tp->link_lock); - } - - if (status & rx_interrupt) { - receive_packets(dev); - } - - if (status & rx_nobufs) { - make_rx_buffs_avail(); - } - - if (status & tx_related) { - spin_lock(&tp->lock); - tx_ring_free(dev); - if (tx_died) - restart_tx(); - spin_unlock(&tp->lock); - } - - status = read_interrupt_status_reg(); - - } while (!(status & error) || more_work_to_be_done); - return IRQ_HANDLED; -} - ----------------------------------------------------------------------- - -We now change this to what is shown below to NAPI-enable it: - ----------------------------------------------------------------------- -static irqreturn_t -netdevice_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct net_device *dev = (struct net_device *)dev_instance; - struct my_private *tp = (struct my_private *)dev->priv; - - status = read_interrupt_status_reg(); - if (status == 0) - return IRQ_NONE; /* Shared IRQ: not us */ - if (status == 0xffff) - return IRQ_HANDLED; /* Hot unplug */ - if (status & error) - do_some_error_handling(); - - do { -/************************ start note *********************************/ - acknowledge_ints_ASAP(); // dont ack rx and rxnobuff here -/************************ end note *********************************/ - - if (status & link_interrupt) { - spin_lock(&tp->link_lock); - do_some_link_stat_stuff(); - spin_unlock(&tp->link_lock); - } -/************************ start note *********************************/ - if (status & rx_interrupt || (status & rx_nobuffs)) { - if (netif_rx_schedule_prep(dev)) { - - /* disable interrupts caused - * by arriving packets */ - disable_rx_and_rxnobuff_ints(); - /* tell system we have work to be done. */ - __netif_rx_schedule(dev); - } else { - printk("driver bug! interrupt while in poll\n"); - /* FIX by disabling interrupts */ - disable_rx_and_rxnobuff_ints(); - } - } -/************************ end note note *********************************/ - - if (status & tx_related) { - spin_lock(&tp->lock); - tx_ring_free(dev); - - if (tx_died) - restart_tx(); - spin_unlock(&tp->lock); - } - - status = read_interrupt_status_reg(); - -/************************ start note *********************************/ - } while (!(status & error) || more_work_to_be_done(status)); -/************************ end note note *********************************/ - return IRQ_HANDLED; -} - ---------------------------------------------------------------------- - - -We note several things from above: - -I) Any interrupt source which is caused by arriving packets is now -turned off when it occurs. Depending on the hardware, there could be -several reasons that arriving packets would cause interrupts; these are the -interrupt sources we wish to avoid. The two common ones are a) a packet -arriving (rxint) b) a packet arriving and finding no DMA buffers available -(rxnobuff) . -This means also acknowledge_ints_ASAP() will not clear the status -register for those two items above; clearing is done in the place where -proper work is done within NAPI; at the poll() and refill_rx_ring() -discussed further below. -netif_rx_schedule_prep() returns 1 if device is in running state and -gets successfully added to the core poll list. If we get a zero value -we can _almost_ assume are already added to the list (instead of not running. -Logic based on the fact that you shouldn't get interrupt if not running) -We rectify this by disabling rx and rxnobuf interrupts. - -II) that receive_packets(dev) and make_rx_buffs_avail() may have disappeared. -These functionalities are still around actually...... - -infact, receive_packets(dev) is very close to my_poll() and -make_rx_buffs_avail() is invoked from my_poll() - -4) converting receive_packets() to dev->poll() -=============================================== - -We need to convert the classical D Becker receive_packets(dev) to my_poll() - -First the typical receive_packets() below: -------------------------------------------------------------------- - -/* this is called by interrupt handler */ -static void receive_packets (struct net_device *dev) -{ - - struct my_private *tp = (struct my_private *)dev->priv; - rx_ring = tp->rx_ring; - cur_rx = tp->cur_rx; - int entry = cur_rx % RX_RING_SIZE; - int received = 0; - int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx; - - while (rx_ring_not_empty) { - u32 rx_status; - unsigned int rx_size; - unsigned int pkt_size; - struct sk_buff *skb; - /* read size+status of next frame from DMA ring buffer */ - /* the number 16 and 4 are just examples */ - rx_status = le32_to_cpu (*(u32 *) (rx_ring + ring_offset)); - rx_size = rx_status >> 16; - pkt_size = rx_size - 4; - - /* process errors */ - if ((rx_size > (MAX_ETH_FRAME_SIZE+4)) || - (!(rx_status & RxStatusOK))) { - netdrv_rx_err (rx_status, dev, tp, ioaddr); - return; - } - - if (--rx_work_limit < 0) - break; - - /* grab a skb */ - skb = dev_alloc_skb (pkt_size + 2); - if (skb) { - . - . - netif_rx (skb); - . - . - } else { /* OOM */ - /*seems very driver specific ... some just pass - whatever is on the ring already. */ - } - - /* move to the next skb on the ring */ - entry = (++tp->cur_rx) % RX_RING_SIZE; - received++ ; - - } - - /* store current ring pointer state */ - tp->cur_rx = cur_rx; - - /* Refill the Rx ring buffers if they are needed */ - refill_rx_ring(); - . - . - -} -------------------------------------------------------------------- -We change it to a new one below; note the additional parameter in -the call. - -------------------------------------------------------------------- - -/* this is called by the network core */ -static int my_poll (struct net_device *dev, int *budget) -{ - - struct my_private *tp = (struct my_private *)dev->priv; - rx_ring = tp->rx_ring; - cur_rx = tp->cur_rx; - int entry = cur_rx % RX_BUF_LEN; - /* maximum packets to send to the stack */ -/************************ note note *********************************/ - int rx_work_limit = dev->quota; - -/************************ end note note *********************************/ - do { // outer beginning loop starts here - - clear_rx_status_register_bit(); - - while (rx_ring_not_empty) { - u32 rx_status; - unsigned int rx_size; - unsigned int pkt_size; - struct sk_buff *skb; - /* read size+status of next frame from DMA ring buffer */ - /* the number 16 and 4 are just examples */ - rx_status = le32_to_cpu (*(u32 *) (rx_ring + ring_offset)); - rx_size = rx_status >> 16; - pkt_size = rx_size - 4; - - /* process errors */ - if ((rx_size > (MAX_ETH_FRAME_SIZE+4)) || - (!(rx_status & RxStatusOK))) { - netdrv_rx_err (rx_status, dev, tp, ioaddr); - return 1; - } - -/************************ note note *********************************/ - if (--rx_work_limit < 0) { /* we got packets, but no quota */ - /* store current ring pointer state */ - tp->cur_rx = cur_rx; - - /* Refill the Rx ring buffers if they are needed */ - refill_rx_ring(dev); - goto not_done; - } -/********************** end note **********************************/ - - /* grab a skb */ - skb = dev_alloc_skb (pkt_size + 2); - if (skb) { - . - . -/************************ note note *********************************/ - netif_receive_skb (skb); -/********************** end note **********************************/ - . - . - } else { /* OOM */ - /*seems very driver specific ... common is just pass - whatever is on the ring already. */ - } - - /* move to the next skb on the ring */ - entry = (++tp->cur_rx) % RX_RING_SIZE; - received++ ; - - } - - /* store current ring pointer state */ - tp->cur_rx = cur_rx; - - /* Refill the Rx ring buffers if they are needed */ - refill_rx_ring(dev); - - /* no packets on ring; but new ones can arrive since we last - checked */ - status = read_interrupt_status_reg(); - if (rx status is not set) { - /* If something arrives in this narrow window, - an interrupt will be generated */ - goto done; - } - /* done! at least that's what it looks like ;-> - if new packets came in after our last check on status bits - they'll be caught by the while check and we go back and clear them - since we havent exceeded our quota */ - } while (rx_status_is_set); - -done: - -/************************ note note *********************************/ - dev->quota -= received; - *budget -= received; - - /* If RX ring is not full we are out of memory. */ - if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) - goto oom; - - /* we are happy/done, no more packets on ring; put us back - to where we can start processing interrupts again */ - netif_rx_complete(dev); - enable_rx_and_rxnobuf_ints(); - - /* The last op happens after poll completion. Which means the following: - * 1. it can race with disabling irqs in irq handler (which are done to - * schedule polls) - * 2. it can race with dis/enabling irqs in other poll threads - * 3. if an irq raised after the beginning of the outer beginning - * loop (marked in the code above), it will be immediately - * triggered here. - * - * Summarizing: the logic may result in some redundant irqs both - * due to races in masking and due to too late acking of already - * processed irqs. The good news: no events are ever lost. - */ - - return 0; /* done */ - -not_done: - if (tp->cur_rx - tp->dirty_rx > RX_RING_SIZE/2 || - tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) - refill_rx_ring(dev); - - if (!received) { - printk("received==0\n"); - received = 1; - } - dev->quota -= received; - *budget -= received; - return 1; /* not_done */ - -oom: - /* Start timer, stop polling, but do not enable rx interrupts. */ - start_poll_timer(dev); - return 0; /* we'll take it from here so tell core "done"*/ - -/************************ End note note *********************************/ -} -------------------------------------------------------------------- - -From above we note that: -0) rx_work_limit = dev->quota -1) refill_rx_ring() is in charge of clearing the bit for rxnobuff when -it does the work. -2) We have a done and not_done state. -3) instead of netif_rx() we call netif_receive_skb() to pass the skb. -4) we have a new way of handling oom condition -5) A new outer for (;;) loop has been added. This serves the purpose of -ensuring that if a new packet has come in, after we are all set and done, -and we have not exceeded our quota that we continue sending packets up. - - ------------------------------------------------------------ -Poll timer code will need to do the following: - -a) - - if (tp->cur_rx - tp->dirty_rx > RX_RING_SIZE/2 || - tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) - refill_rx_ring(dev); - - /* If RX ring is not full we are still out of memory. - Restart the timer again. Else we re-add ourselves - to the master poll list. - */ - - if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) - restart_timer(); - - else netif_rx_schedule(dev); /* we are back on the poll list */ - -5) dev->close() and dev->suspend() issues -========================================== -The driver writer needn't worry about this; the top net layer takes -care of it. - -6) Adding new Stats to /proc -============================= -In order to debug some of the new features, we introduce new stats -that need to be collected. -TODO: Fill this later. - -APPENDIX 1: discussion on using ethernet HW FC -============================================== -Most chips with FC only send a pause packet when they run out of Rx buffers. -Since packets are pulled off the DMA ring by a softirq in NAPI, -if the system is slow in grabbing them and we have a high input -rate (faster than the system's capacity to remove packets), then theoretically -there will only be one rx interrupt for all packets during a given packetstorm. -Under low load, we might have a single interrupt per packet. -FC should be programmed to apply in the case when the system cant pull out -packets fast enough i.e send a pause only when you run out of rx buffers. -Note FC in itself is a good solution but we have found it to not be -much of a commodity feature (both in NICs and switches) and hence falls -under the same category as using NIC based mitigation. Also, experiments -indicate that it's much harder to resolve the resource allocation -issue (aka lazy receiving that NAPI offers) and hence quantify its usefulness -proved harder. In any case, FC works even better with NAPI but is not -necessary. - - -APPENDIX 2: the "rotting packet" race-window avoidance scheme -============================================================= - -There are two types of associations seen here - -1) status/int which honors level triggered IRQ - -If a status bit for receive or rxnobuff is set and the corresponding -interrupt-enable bit is not on, then no interrupts will be generated. However, -as soon as the "interrupt-enable" bit is unmasked, an immediate interrupt is -generated. [assuming the status bit was not turned off]. -Generally the concept of level triggered IRQs in association with a status and -interrupt-enable CSR register set is used to avoid the race. - -If we take the example of the tulip: -"pending work" is indicated by the status bit(CSR5 in tulip). -the corresponding interrupt bit (CSR7 in tulip) might be turned off (but -the CSR5 will continue to be turned on with new packet arrivals even if -we clear it the first time) -Very important is the fact that if we turn on the interrupt bit on when -status is set that an immediate irq is triggered. - -If we cleared the rx ring and proclaimed there was "no more work -to be done" and then went on to do a few other things; then when we enable -interrupts, there is a possibility that a new packet might sneak in during -this phase. It helps to look at the pseudo code for the tulip poll -routine: - --------------------------- - do { - ACK; - while (ring_is_not_empty()) { - work-work-work - if quota is exceeded: exit, no touching irq status/mask - } - /* No packets, but new can arrive while we are doing this*/ - CSR5 := read - if (CSR5 is not set) { - /* If something arrives in this narrow window here, - * where the comments are ;-> irq will be generated */ - unmask irqs; - exit poll; - } - } while (rx_status_is_set); ------------------------- - -CSR5 bit of interest is only the rx status. -If you look at the last if statement: -you just finished grabbing all the packets from the rx ring .. you check if -status bit says there are more packets just in ... it says none; you then -enable rx interrupts again; if a new packet just came in during this check, -we are counting that CSR5 will be set in that small window of opportunity -and that by re-enabling interrupts, we would actually trigger an interrupt -to register the new packet for processing. - -[The above description nay be very verbose, if you have better wording -that will make this more understandable, please suggest it.] - -2) non-capable hardware - -These do not generally respect level triggered IRQs. Normally, -irqs may be lost while being masked and the only way to leave poll is to do -a double check for new input after netif_rx_complete() is invoked -and re-enable polling (after seeing this new input). - -Sample code: - ---------- - . - . -restart_poll: - while (ring_is_not_empty()) { - work-work-work - if quota is exceeded: exit, not touching irq status/mask - } - . - . - . - enable_rx_interrupts() - netif_rx_complete(dev); - if (ring_has_new_packet() && netif_rx_reschedule(dev, received)) { - disable_rx_and_rxnobufs() - goto restart_poll - } while (rx_status_is_set); ---------- - -Basically netif_rx_complete() removes us from the poll list, but because a -new packet which will never be caught due to the possibility of a race -might come in, we attempt to re-add ourselves to the poll list. - - - - -APPENDIX 3: Scheduling issues. -============================== -As seen NAPI moves processing to softirq level. Linux uses the ksoftirqd as the -general solution to schedule softirq's to run before next interrupt and by putting -them under scheduler control. Also this prevents consecutive softirq's from -monopolize the CPU. This also have the effect that the priority of ksoftirq needs -to be considered when running very CPU-intensive applications and networking to -get the proper balance of softirq/user balance. Increasing ksoftirq priority to 0 -(eventually more) is reported cure problems with low network performance at high -CPU load. - -Most used processes in a GIGE router: -USER PID %CPU %MEM SIZE RSS TTY STAT START TIME COMMAND -root 3 0.2 0.0 0 0 ? RWN Aug 15 602:00 (ksoftirqd_CPU0) -root 232 0.0 7.9 41400 40884 ? S Aug 15 74:12 gated - --------------------------------------------------------------------- - -relevant sites: -================== -ftp://robur.slu.se/pub/Linux/net-development/NAPI/ - - --------------------------------------------------------------------- -TODO: Write net-skeleton.c driver. -------------------------------------------------------------- - -Authors: -======== -Alexey Kuznetsov -Jamal Hadi Salim -Robert Olsson - -Acknowledgements: -================ -People who made this document better: - -Lennert Buytenhek -Andrew Morton -Manfred Spraul -Donald Becker -Jeff Garzik diff --git a/Documentation/networking/netdevices.txt b/Documentation/networking/netdevices.txt index 37869295fc7..9f7be9b7785 100644 --- a/Documentation/networking/netdevices.txt +++ b/Documentation/networking/netdevices.txt @@ -95,9 +95,13 @@ dev->set_multicast_list: Synchronization: netif_tx_lock spinlock. Context: BHs disabled -dev->poll: - Synchronization: __LINK_STATE_RX_SCHED bit in dev->state. See - dev_close code and comments in net/core/dev.c for more info. +struct napi_struct synchronization rules +======================================== +napi->poll: + Synchronization: NAPI_STATE_SCHED bit in napi->state. Device + driver's dev->close method will invoke napi_disable() on + all NAPI instances which will do a sleeping poll on the + NAPI_STATE_SCHED napi->state bit, waiting for all pending + NAPI activity to cease. Context: softirq will be called with interrupts disabled by netconsole. - diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index 285c143115c..35f3ca42bd6 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h @@ -228,6 +228,8 @@ struct ipoib_dev_priv { struct net_device *dev; + struct napi_struct napi; + unsigned long flags; struct mutex mcast_mutex; @@ -351,7 +353,7 @@ extern struct workqueue_struct *ipoib_workqueue; /* functions */ -int ipoib_poll(struct net_device *dev, int *budget); +int ipoib_poll(struct napi_struct *napi, int budget); void ipoib_ib_completion(struct ib_cq *cq, void *dev_ptr); struct ipoib_ah *ipoib_create_ah(struct net_device *dev, diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index 10944888cff..481e4b6bd94 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -281,63 +281,58 @@ static void ipoib_ib_handle_tx_wc(struct net_device *dev, struct ib_wc *wc) wc->status, wr_id, wc->vendor_err); } -int ipoib_poll(struct net_device *dev, int *budget) +int ipoib_poll(struct napi_struct *napi, int budget) { - struct ipoib_dev_priv *priv = netdev_priv(dev); - int max = min(*budget, dev->quota); + struct ipoib_dev_priv *priv = container_of(napi, struct ipoib_dev_priv, napi); + struct net_device *dev = priv->dev; int done; int t; - int empty; int n, i; done = 0; - empty = 0; - while (max) { +poll_more: + while (done < budget) { + int max = (budget - done); + t = min(IPOIB_NUM_WC, max); n = ib_poll_cq(priv->cq, t, priv->ibwc); - for (i = 0; i < n; ++i) { + for (i = 0; i < n; i++) { struct ib_wc *wc = priv->ibwc + i; if (wc->wr_id & IPOIB_CM_OP_SRQ) { ++done; - --max; ipoib_cm_handle_rx_wc(dev, wc); } else if (wc->wr_id & IPOIB_OP_RECV) { ++done; - --max; ipoib_ib_handle_rx_wc(dev, wc); } else ipoib_ib_handle_tx_wc(dev, wc); } - if (n != t) { - empty = 1; + if (n != t) break; - } } - dev->quota -= done; - *budget -= done; - - if (empty) { - netif_rx_complete(dev); + if (done < budget) { + netif_rx_complete(dev, napi); if (unlikely(ib_req_notify_cq(priv->cq, IB_CQ_NEXT_COMP | IB_CQ_REPORT_MISSED_EVENTS)) && - netif_rx_reschedule(dev, 0)) - return 1; - - return 0; + netif_rx_reschedule(dev, napi)) + goto poll_more; } - return 1; + return done; } void ipoib_ib_completion(struct ib_cq *cq, void *dev_ptr) { - netif_rx_schedule(dev_ptr); + struct net_device *dev = dev_ptr; + struct ipoib_dev_priv *priv = netdev_priv(dev); + + netif_rx_schedule(dev, &priv->napi); } static inline int post_send(struct ipoib_dev_priv *priv, @@ -577,7 +572,6 @@ int ipoib_ib_dev_stop(struct net_device *dev, int flush) int i; clear_bit(IPOIB_FLAG_INITIALIZED, &priv->flags); - netif_poll_disable(dev); ipoib_cm_dev_stop(dev); @@ -660,7 +654,6 @@ timeout: msleep(1); } - netif_poll_enable(dev); ib_req_notify_cq(priv->cq, IB_CQ_NEXT_COMP); return 0; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 894b1dcdf3e..a59ff07ec3c 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -98,16 +98,20 @@ int ipoib_open(struct net_device *dev) ipoib_dbg(priv, "bringing up interface\n"); + napi_enable(&priv->napi); set_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags); if (ipoib_pkey_dev_delay_open(dev)) return 0; - if (ipoib_ib_dev_open(dev)) + if (ipoib_ib_dev_open(dev)) { + napi_disable(&priv->napi); return -EINVAL; + } if (ipoib_ib_dev_up(dev)) { ipoib_ib_dev_stop(dev, 1); + napi_disable(&priv->napi); return -EINVAL; } @@ -140,6 +144,7 @@ static int ipoib_stop(struct net_device *dev) ipoib_dbg(priv, "stopping interface\n"); clear_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags); + napi_disable(&priv->napi); netif_stop_queue(dev); @@ -948,8 +953,8 @@ static void ipoib_setup(struct net_device *dev) dev->hard_header = ipoib_hard_header; dev->set_multicast_list = ipoib_set_mcast_list; dev->neigh_setup = ipoib_neigh_setup_dev; - dev->poll = ipoib_poll; - dev->weight = 100; + + netif_napi_add(dev, &priv->napi, ipoib_poll, 100); dev->watchdog_timeo = HZ; diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index a79f28c7a10..7f18ca23d9f 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -334,6 +334,8 @@ struct cp_private { spinlock_t lock; u32 msg_enable; + struct napi_struct napi; + struct pci_dev *pdev; u32 rx_config; u16 cpcmd; @@ -501,12 +503,12 @@ static inline unsigned int cp_rx_csum_ok (u32 status) return 0; } -static int cp_rx_poll (struct net_device *dev, int *budget) +static int cp_rx_poll(struct napi_struct *napi, int budget) { - struct cp_private *cp = netdev_priv(dev); - unsigned rx_tail = cp->rx_tail; - unsigned rx_work = dev->quota; - unsigned rx; + struct cp_private *cp = container_of(napi, struct cp_private, napi); + struct net_device *dev = cp->dev; + unsigned int rx_tail = cp->rx_tail; + int rx; rx_status_loop: rx = 0; @@ -588,33 +590,28 @@ rx_next: desc->opts1 = cpu_to_le32(DescOwn | cp->rx_buf_sz); rx_tail = NEXT_RX(rx_tail); - if (!rx_work--) + if (rx >= budget) break; } cp->rx_tail = rx_tail; - dev->quota -= rx; - *budget -= rx; - /* if we did not reach work limit, then we're done with * this round of polling */ - if (rx_work) { + if (rx < budget) { unsigned long flags; if (cpr16(IntrStatus) & cp_rx_intr_mask) goto rx_status_loop; - local_irq_save(flags); + spin_lock_irqsave(&cp->lock, flags); cpw16_f(IntrMask, cp_intr_mask); - __netif_rx_complete(dev); - local_irq_restore(flags); - - return 0; /* done */ + __netif_rx_complete(dev, napi); + spin_unlock_irqrestore(&cp->lock, flags); } - return 1; /* not done */ + return rx; } static irqreturn_t cp_interrupt (int irq, void *dev_instance) @@ -647,9 +644,9 @@ static irqreturn_t cp_interrupt (int irq, void *dev_instance) } if (status & (RxOK | RxErr | RxEmpty | RxFIFOOvr)) - if (netif_rx_schedule_prep(dev)) { + if (netif_rx_schedule_prep(dev, &cp->napi)) { cpw16_f(IntrMask, cp_norx_intr_mask); - __netif_rx_schedule(dev); + __netif_rx_schedule(dev, &cp->napi); } if (status & (TxOK | TxErr | TxEmpty | SWInt)) @@ -1175,6 +1172,8 @@ static int cp_open (struct net_device *dev) if (rc) return rc; + napi_enable(&cp->napi); + cp_init_hw(cp); rc = request_irq(dev->irq, cp_interrupt, IRQF_SHARED, dev->name, dev); @@ -1188,6 +1187,7 @@ static int cp_open (struct net_device *dev) return 0; err_out_hw: + napi_disable(&cp->napi); cp_stop_hw(cp); cp_free_rings(cp); return rc; @@ -1198,6 +1198,8 @@ static int cp_close (struct net_device *dev) struct cp_private *cp = netdev_priv(dev); unsigned long flags; + napi_disable(&cp->napi); + if (netif_msg_ifdown(cp)) printk(KERN_DEBUG "%s: disabling interface\n", dev->name); @@ -1933,11 +1935,10 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) dev->hard_start_xmit = cp_start_xmit; dev->get_stats = cp_get_stats; dev->do_ioctl = cp_ioctl; - dev->poll = cp_rx_poll; #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = cp_poll_controller; #endif - dev->weight = 16; /* arbitrary? from NAPI_HOWTO.txt. */ + netif_napi_add(dev, &cp->napi, cp_rx_poll, 16); #ifdef BROKEN dev->change_mtu = cp_change_mtu; #endif diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index f4e4298d24b..20af6baecfc 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -573,6 +573,8 @@ struct rtl8139_private { int drv_flags; struct pci_dev *pci_dev; u32 msg_enable; + struct napi_struct napi; + struct net_device *dev; struct net_device_stats stats; unsigned char *rx_ring; unsigned int cur_rx; /* Index into the Rx buffer of next Rx pkt. */ @@ -625,10 +627,10 @@ static void rtl8139_tx_timeout (struct net_device *dev); static void rtl8139_init_ring (struct net_device *dev); static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev); -static int rtl8139_poll(struct net_device *dev, int *budget); #ifdef CONFIG_NET_POLL_CONTROLLER static void rtl8139_poll_controller(struct net_device *dev); #endif +static int rtl8139_poll(struct napi_struct *napi, int budget); static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance); static int rtl8139_close (struct net_device *dev); static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd); @@ -963,6 +965,7 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, assert (dev != NULL); tp = netdev_priv(dev); + tp->dev = dev; ioaddr = tp->mmio_addr; assert (ioaddr != NULL); @@ -976,8 +979,7 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, /* The Rtl8139-specific entries in the device structure. */ dev->open = rtl8139_open; dev->hard_start_xmit = rtl8139_start_xmit; - dev->poll = rtl8139_poll; - dev->weight = 64; + netif_napi_add(dev, &tp->napi, rtl8139_poll, 64); dev->stop = rtl8139_close; dev->get_stats = rtl8139_get_stats; dev->set_multicast_list = rtl8139_set_rx_mode; @@ -1332,6 +1334,8 @@ static int rtl8139_open (struct net_device *dev) } + napi_enable(&tp->napi); + tp->mii.full_duplex = tp->mii.force_media; tp->tx_flag = (TX_FIFO_THRESH << 11) & 0x003f0000; @@ -2103,39 +2107,32 @@ static void rtl8139_weird_interrupt (struct net_device *dev, } } -static int rtl8139_poll(struct net_device *dev, int *budget) +static int rtl8139_poll(struct napi_struct *napi, int budget) { - struct rtl8139_private *tp = netdev_priv(dev); + struct rtl8139_private *tp = container_of(napi, struct rtl8139_private, napi); + struct net_device *dev = tp->dev; void __iomem *ioaddr = tp->mmio_addr; - int orig_budget = min(*budget, dev->quota); - int done = 1; + int work_done; spin_lock(&tp->rx_lock); - if (likely(RTL_R16(IntrStatus) & RxAckBits)) { - int work_done; - - work_done = rtl8139_rx(dev, tp, orig_budget); - if (likely(work_done > 0)) { - *budget -= work_done; - dev->quota -= work_done; - done = (work_done < orig_budget); - } - } + work_done = 0; + if (likely(RTL_R16(IntrStatus) & RxAckBits)) + work_done += rtl8139_rx(dev, tp, budget); - if (done) { + if (work_done < budget) { unsigned long flags; /* * Order is important since data can get interrupted * again when we think we are done. */ - local_irq_save(flags); + spin_lock_irqsave(&tp->lock, flags); RTL_W16_F(IntrMask, rtl8139_intr_mask); - __netif_rx_complete(dev); - local_irq_restore(flags); + __netif_rx_complete(dev, napi); + spin_unlock_irqrestore(&tp->lock, flags); } spin_unlock(&tp->rx_lock); - return !done; + return work_done; } /* The interrupt handler does all of the Rx thread work and cleans up @@ -2180,9 +2177,9 @@ static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance) /* Receive packets are processed by poll routine. If not running start it now. */ if (status & RxAckBits){ - if (netif_rx_schedule_prep(dev)) { + if (netif_rx_schedule_prep(dev, &tp->napi)) { RTL_W16_F (IntrMask, rtl8139_norx_intr_mask); - __netif_rx_schedule (dev); + __netif_rx_schedule(dev, &tp->napi); } } @@ -2223,7 +2220,8 @@ static int rtl8139_close (struct net_device *dev) void __iomem *ioaddr = tp->mmio_addr; unsigned long flags; - netif_stop_queue (dev); + netif_stop_queue(dev); + napi_disable(&tp->napi); if (netif_msg_ifdown(tp)) printk(KERN_DEBUG "%s: Shutting down ethercard, status was 0x%4.4x.\n", diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c index a61b2f89fc3..cf06fc067e9 100644 --- a/drivers/net/amd8111e.c +++ b/drivers/net/amd8111e.c @@ -723,9 +723,10 @@ static int amd8111e_tx(struct net_device *dev) #ifdef CONFIG_AMD8111E_NAPI /* This function handles the driver receive operation in polling mode */ -static int amd8111e_rx_poll(struct net_device *dev, int * budget) +static int amd8111e_rx_poll(struct napi_struct *napi, int budget) { - struct amd8111e_priv *lp = netdev_priv(dev); + struct amd8111e_priv *lp = container_of(napi, struct amd8111e_priv, napi); + struct net_device *dev = lp->amd8111e_net_dev; int rx_index = lp->rx_idx & RX_RING_DR_MOD_MASK; void __iomem *mmio = lp->mmio; struct sk_buff *skb,*new_skb; @@ -737,7 +738,7 @@ static int amd8111e_rx_poll(struct net_device *dev, int * budget) #if AMD8111E_VLAN_TAG_USED short vtag; #endif - int rx_pkt_limit = dev->quota; + int rx_pkt_limit = budget; unsigned long flags; do{ @@ -838,21 +839,14 @@ static int amd8111e_rx_poll(struct net_device *dev, int * budget) } while(intr0 & RINT0); /* Receive descriptor is empty now */ - dev->quota -= num_rx_pkt; - *budget -= num_rx_pkt; - spin_lock_irqsave(&lp->lock, flags); - netif_rx_complete(dev); + __netif_rx_complete(dev, napi); writel(VAL0|RINTEN0, mmio + INTEN0); writel(VAL2 | RDMD0, mmio + CMD0); spin_unlock_irqrestore(&lp->lock, flags); - return 0; rx_not_empty: - /* Do not call a netif_rx_complete */ - dev->quota -= num_rx_pkt; - *budget -= num_rx_pkt; - return 1; + return num_rx_pkt; } #else @@ -1287,11 +1281,11 @@ static irqreturn_t amd8111e_interrupt(int irq, void *dev_id) /* Check if Receive Interrupt has occurred. */ #ifdef CONFIG_AMD8111E_NAPI if(intr0 & RINT0){ - if(netif_rx_schedule_prep(dev)){ + if(netif_rx_schedule_prep(dev, &lp->napi)){ /* Disable receive interupts */ writel(RINTEN0, mmio + INTEN0); /* Schedule a polling routine */ - __netif_rx_schedule(dev); + __netif_rx_schedule(dev, &lp->napi); } else if (intren0 & RINTEN0) { printk("************Driver bug! \ @@ -1345,6 +1339,8 @@ static int amd8111e_close(struct net_device * dev) struct amd8111e_priv *lp = netdev_priv(dev); netif_stop_queue(dev); + napi_disable(&lp->napi); + spin_lock_irq(&lp->lock); amd8111e_disable_interrupt(lp); @@ -1375,12 +1371,15 @@ static int amd8111e_open(struct net_device * dev ) dev->name, dev)) return -EAGAIN; + napi_enable(&lp->napi); + spin_lock_irq(&lp->lock); amd8111e_init_hw_default(lp); if(amd8111e_restart(dev)){ spin_unlock_irq(&lp->lock); + napi_disable(&lp->napi); if (dev->irq) free_irq(dev->irq, dev); return -ENOMEM; @@ -2031,8 +2030,7 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev, dev->tx_timeout = amd8111e_tx_timeout; dev->watchdog_timeo = AMD8111E_TX_TIMEOUT; #ifdef CONFIG_AMD8111E_NAPI - dev->poll = amd8111e_rx_poll; - dev->weight = 32; + netif_napi_add(dev, &lp->napi, amd8111e_rx_poll, 32); #endif #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = amd8111e_poll; diff --git a/drivers/net/amd8111e.h b/drivers/net/amd8111e.h index e65080a5994..612e653610e 100644 --- a/drivers/net/amd8111e.h +++ b/drivers/net/amd8111e.h @@ -763,6 +763,8 @@ struct amd8111e_priv{ /* Reg memory mapped address */ void __iomem *mmio; + struct napi_struct napi; + spinlock_t lock; /* Guard lock */ unsigned long rx_idx, tx_idx; /* The next free ring entry */ unsigned long tx_complete_idx; diff --git a/drivers/net/arm/ep93xx_eth.c b/drivers/net/arm/ep93xx_eth.c index f6ece1d43f6..7f016f3d5bf 100644 --- a/drivers/net/arm/ep93xx_eth.c +++ b/drivers/net/arm/ep93xx_eth.c @@ -169,6 +169,9 @@ struct ep93xx_priv spinlock_t tx_pending_lock; unsigned int tx_pending; + struct net_device *dev; + struct napi_struct napi; + struct net_device_stats stats; struct mii_if_info mii; @@ -190,15 +193,11 @@ static struct net_device_stats *ep93xx_get_stats(struct net_device *dev) return &(ep->stats); } -static int ep93xx_rx(struct net_device *dev, int *budget) +static int ep93xx_rx(struct net_device *dev, int processed, int budget) { struct ep93xx_priv *ep = netdev_priv(dev); - int rx_done; - int processed; - rx_done = 0; - processed = 0; - while (*budget > 0) { + while (processed < budget) { int entry; struct ep93xx_rstat *rstat; u32 rstat0; @@ -211,10 +210,8 @@ static int ep93xx_rx(struct net_device *dev, int *budget) rstat0 = rstat->rstat0; rstat1 = rstat->rstat1; - if (!(rstat0 & RSTAT0_RFP) || !(rstat1 & RSTAT1_RFP)) { - rx_done = 1; + if (!(rstat0 & RSTAT0_RFP) || !(rstat1 & RSTAT1_RFP)) break; - } rstat->rstat0 = 0; rstat->rstat1 = 0; @@ -275,8 +272,6 @@ static int ep93xx_rx(struct net_device *dev, int *budget) err: ep->rx_pointer = (entry + 1) & (RX_QUEUE_ENTRIES - 1); processed++; - dev->quota--; - (*budget)--; } if (processed) { @@ -284,7 +279,7 @@ err: wrw(ep, REG_RXSTSENQ, processed); } - return !rx_done; + return processed; } static int ep93xx_have_more_rx(struct ep93xx_priv *ep) @@ -293,36 +288,32 @@ static int ep93xx_have_more_rx(struct ep93xx_priv *ep) return !!((rstat->rstat0 & RSTAT0_RFP) && (rstat->rstat1 & RSTAT1_RFP)); } -static int ep93xx_poll(struct net_device *dev, int *budget) +static int ep93xx_poll(struct napi_struct *napi, int budget) { - struct ep93xx_priv *ep = netdev_priv(dev); - - /* - * @@@ Have to stop polling if device is downed while we - * are polling. - */ + struct ep93xx_priv *ep = container_of(napi, struct ep93xx_priv, napi); + struct net_device *dev = ep->dev; + int rx = 0; poll_some_more: - if (ep93xx_rx(dev, budget)) - return 1; - - netif_rx_complete(dev); - - spin_lock_irq(&ep->rx_lock); - wrl(ep, REG_INTEN, REG_INTEN_TX | REG_INTEN_RX); - if (ep93xx_have_more_rx(ep)) { - wrl(ep, REG_INTEN, REG_INTEN_TX); - wrl(ep, REG_INTSTSP, REG_INTSTS_RX); + rx = ep93xx_rx(dev, rx, budget); + if (rx < budget) { + int more = 0; + + spin_lock_irq(&ep->rx_lock); + __netif_rx_complete(dev, napi); + wrl(ep, REG_INTEN, REG_INTEN_TX | REG_INTEN_RX); + if (ep93xx_have_more_rx(ep)) { + wrl(ep, REG_INTEN, REG_INTEN_TX); + wrl(ep, REG_INTSTSP, REG_INTSTS_RX); + more = 1; + } spin_unlock_irq(&ep->rx_lock); - if (netif_rx_reschedule(dev, 0)) + if (more && netif_rx_reschedule(dev, napi)) goto poll_some_more; - - return 0; } - spin_unlock_irq(&ep->rx_lock); - return 0; + return rx; } static int ep93xx_xmit(struct sk_buff *skb, struct net_device *dev) @@ -426,9 +417,9 @@ static irqreturn_t ep93xx_irq(int irq, void *dev_id) if (status & REG_INTSTS_RX) { spin_lock(&ep->rx_lock); - if (likely(__netif_rx_schedule_prep(dev))) { + if (likely(__netif_rx_schedule_prep(dev, &ep->napi))) { wrl(ep, REG_INTEN, REG_INTEN_TX); - __netif_rx_schedule(dev); + __netif_rx_schedule(dev, &ep->napi); } spin_unlock(&ep->rx_lock); } @@ -648,7 +639,10 @@ static int ep93xx_open(struct net_device *dev) dev->dev_addr[4], dev->dev_addr[5]); } + napi_enable(&ep->napi); + if (ep93xx_start_hw(dev)) { + napi_disable(&ep->napi); ep93xx_free_buffers(ep); return -EIO; } @@ -662,6 +656,7 @@ static int ep93xx_open(struct net_device *dev) err = request_irq(ep->irq, ep93xx_irq, IRQF_SHARED, dev->name, dev); if (err) { + napi_disable(&ep->napi); ep93xx_stop_hw(dev); ep93xx_free_buffers(ep); return err; @@ -678,6 +673,7 @@ static int ep93xx_close(struct net_device *dev) { struct ep93xx_priv *ep = netdev_priv(dev); + napi_disable(&ep->napi); netif_stop_queue(dev); wrl(ep, REG_GIINTMSK, 0); @@ -788,14 +784,12 @@ struct net_device *ep93xx_dev_alloc(struct ep93xx_eth_data *data) dev->get_stats = ep93xx_get_stats; dev->ethtool_ops = &ep93xx_ethtool_ops; - dev->poll = ep93xx_poll; dev->hard_start_xmit = ep93xx_xmit; dev->open = ep93xx_open; dev->stop = ep93xx_close; dev->do_ioctl = ep93xx_ioctl; dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; - dev->weight = 64; return dev; } @@ -847,6 +841,8 @@ static int ep93xx_eth_probe(struct platform_device *pdev) goto err_out; } ep = netdev_priv(dev); + ep->dev = dev; + netif_napi_add(dev, &ep->napi, ep93xx_poll, 64); platform_set_drvdata(pdev, dev); diff --git a/drivers/net/b44.c b/drivers/net/b44.c index 0795df23549..b92b3e25c42 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -848,10 +848,11 @@ static int b44_rx(struct b44 *bp, int budget) return received; } -static int b44_poll(struct net_device *netdev, int *budget) +static int b44_poll(struct napi_struct *napi, int budget) { - struct b44 *bp = netdev_priv(netdev); - int done; + struct b44 *bp = container_of(napi, struct b44, napi); + struct net_device *netdev = bp->dev; + int work_done; spin_lock_irq(&bp->lock); @@ -862,22 +863,9 @@ static int b44_poll(struct net_device *netdev, int *budget) } spin_unlock_irq(&bp->lock); - done = 1; - if (bp->istat & ISTAT_RX) { - int orig_budget = *budget; - int work_done; - - if (orig_budget > netdev->quota) - orig_budget = netdev->quota; - - work_done = b44_rx(bp, orig_budget); - - *budget -= work_done; - netdev->quota -= work_done; - - if (work_done >= orig_budget) - done = 0; - } + work_done = 0; + if (bp->istat & ISTAT_RX) + work_done += b44_rx(bp, budget); if (bp->istat & ISTAT_ERRORS) { unsigned long flags; @@ -888,15 +876,15 @@ static int b44_poll(struct net_device *netdev, int *budget) b44_init_hw(bp, B44_FULL_RESET_SKIP_PHY); netif_wake_queue(bp->dev); spin_unlock_irqrestore(&bp->lock, flags); - done = 1; + work_done = 0; } - if (done) { - netif_rx_complete(netdev); + if (work_done < budget) { + netif_rx_complete(netdev, napi); b44_enable_ints(bp); } - return (done ? 0 : 1); + return work_done; } static irqreturn_t b44_interrupt(int irq, void *dev_id) @@ -924,13 +912,13 @@ static irqreturn_t b44_interrupt(int irq, void *dev_id) goto irq_ack; } - if (netif_rx_schedule_prep(dev)) { + if (netif_rx_schedule_prep(dev, &bp->napi)) { /* NOTE: These writes are posted by the readback of * the ISTAT register below. */ bp->istat = istat; __b44_disable_ints(bp); - __netif_rx_schedule(dev); + __netif_rx_schedule(dev, &bp->napi); } else { printk(KERN_ERR PFX "%s: Error, poll already scheduled\n", dev->name); @@ -1420,6 +1408,8 @@ static int b44_open(struct net_device *dev) if (err) goto out; + napi_enable(&bp->napi); + b44_init_rings(bp); b44_init_hw(bp, B44_FULL_RESET); @@ -1427,6 +1417,7 @@ static int b44_open(struct net_device *dev) err = request_irq(dev->irq, b44_interrupt, IRQF_SHARED, dev->name, dev); if (unlikely(err < 0)) { + napi_disable(&bp->napi); b44_chip_reset(bp); b44_free_rings(bp); b44_free_consistent(bp); @@ -1609,7 +1600,7 @@ static int b44_close(struct net_device *dev) netif_stop_queue(dev); - netif_poll_disable(dev); + napi_disable(&bp->napi); del_timer_sync(&bp->timer); @@ -1626,8 +1617,6 @@ static int b44_close(struct net_device *dev) free_irq(dev->irq, dev); - netif_poll_enable(dev); - if (bp->flags & B44_FLAG_WOL_ENABLE) { b44_init_hw(bp, B44_PARTIAL_RESET); b44_setup_wol(bp); @@ -2194,8 +2183,7 @@ static int __devinit b44_init_one(struct pci_dev *pdev, dev->set_mac_address = b44_set_mac_addr; dev->do_ioctl = b44_ioctl; dev->tx_timeout = b44_tx_timeout; - dev->poll = b44_poll; - dev->weight = 64; + netif_napi_add(dev, &bp->napi, b44_poll, 64); dev->watchdog_timeo = B44_TX_TIMEOUT; #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = b44_poll_controller; diff --git a/drivers/net/b44.h b/drivers/net/b44.h index e537e63f292..63c55a4ab3c 100644 --- a/drivers/net/b44.h +++ b/drivers/net/b44.h @@ -423,6 +423,8 @@ struct b44 { struct ring_info *rx_buffers; struct ring_info *tx_buffers; + struct napi_struct napi; + u32 dma_offset; u32 flags; #define B44_FLAG_B0_ANDLATER 0x00000001 diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 66eed22cbd2..ab028ad0423 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -428,7 +428,7 @@ bnx2_netif_stop(struct bnx2 *bp) { bnx2_disable_int_sync(bp); if (netif_running(bp->dev)) { - netif_poll_disable(bp->dev); + napi_disable(&bp->napi); netif_tx_disable(bp->dev); bp->dev->trans_start = jiffies; /* prevent tx timeout */ } @@ -440,7 +440,7 @@ bnx2_netif_start(struct bnx2 *bp) if (atomic_dec_and_test(&bp->intr_sem)) { if (netif_running(bp->dev)) { netif_wake_queue(bp->dev); - netif_poll_enable(bp->dev); + napi_enable(&bp->napi); bnx2_enable_int(bp); } } @@ -2551,7 +2551,7 @@ bnx2_msi(int irq, void *dev_instance) if (unlikely(atomic_read(&bp->intr_sem) != 0)) return IRQ_HANDLED; - netif_rx_schedule(dev); + netif_rx_schedule(dev, &bp->napi); return IRQ_HANDLED; } @@ -2568,7 +2568,7 @@ bnx2_msi_1shot(int irq, void *dev_instance) if (unlikely(atomic_read(&bp->intr_sem) != 0)) return IRQ_HANDLED; - netif_rx_schedule(dev); + netif_rx_schedule(dev, &bp->napi); return IRQ_HANDLED; } @@ -2604,9 +2604,9 @@ bnx2_interrupt(int irq, void *dev_instance) if (unlikely(atomic_read(&bp->intr_sem) != 0)) return IRQ_HANDLED; - if (netif_rx_schedule_prep(dev)) { + if (netif_rx_schedule_prep(dev, &bp->napi)) { bp->last_status_idx = sblk->status_idx; - __netif_rx_schedule(dev); + __netif_rx_schedule(dev, &bp->napi); } return IRQ_HANDLED; @@ -2632,12 +2632,14 @@ bnx2_has_work(struct bnx2 *bp) } static int -bnx2_poll(struct net_device *dev, int *budget) +bnx2_poll(struct napi_struct *napi, int budget) { - struct bnx2 *bp = netdev_priv(dev); + struct bnx2 *bp = container_of(napi, struct bnx2, napi); + struct net_device *dev = bp->dev; struct status_block *sblk = bp->status_blk; u32 status_attn_bits = sblk->status_attn_bits; u32 status_attn_bits_ack = sblk->status_attn_bits_ack; + int work_done = 0; if ((status_attn_bits & STATUS_ATTN_EVENTS) != (status_attn_bits_ack & STATUS_ATTN_EVENTS)) { @@ -2655,23 +2657,14 @@ bnx2_poll(struct net_device *dev, int *budget) if (bp->status_blk->status_tx_quick_consumer_index0 != bp->hw_tx_cons) bnx2_tx_int(bp); - if (bp->status_blk->status_rx_quick_consumer_index0 != bp->hw_rx_cons) { - int orig_budget = *budget; - int work_done; - - if (orig_budget > dev->quota) - orig_budget = dev->quota; - - work_done = bnx2_rx_int(bp, orig_budget); - *budget -= work_done; - dev->quota -= work_done; - } + if (bp->status_blk->status_rx_quick_consumer_index0 != bp->hw_rx_cons) + work_done = bnx2_rx_int(bp, budget); bp->last_status_idx = bp->status_blk->status_idx; rmb(); if (!bnx2_has_work(bp)) { - netif_rx_complete(dev); + netif_rx_complete(dev, napi); if (likely(bp->flags & USING_MSI_FLAG)) { REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | @@ -2686,10 +2679,9 @@ bnx2_poll(struct net_device *dev, int *budget) REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | bp->last_status_idx); - return 0; } - return 1; + return work_done; } /* Called with rtnl_lock from vlan functions and also netif_tx_lock @@ -5039,6 +5031,8 @@ bnx2_open(struct net_device *dev) if (rc) return rc; + napi_enable(&bp->napi); + if ((bp->flags & MSI_CAP_FLAG) && !disable_msi) { if (pci_enable_msi(bp->pdev) == 0) { bp->flags |= USING_MSI_FLAG; @@ -5049,6 +5043,7 @@ bnx2_open(struct net_device *dev) rc = bnx2_request_irq(bp); if (rc) { + napi_disable(&bp->napi); bnx2_free_mem(bp); return rc; } @@ -5056,6 +5051,7 @@ bnx2_open(struct net_device *dev) rc = bnx2_init_nic(bp); if (rc) { + napi_disable(&bp->napi); bnx2_free_irq(bp); bnx2_free_skbs(bp); bnx2_free_mem(bp); @@ -5088,6 +5084,7 @@ bnx2_open(struct net_device *dev) rc = bnx2_request_irq(bp); if (rc) { + napi_disable(&bp->napi); bnx2_free_skbs(bp); bnx2_free_mem(bp); del_timer_sync(&bp->timer); @@ -5301,7 +5298,8 @@ bnx2_close(struct net_device *dev) while (bp->in_reset_task) msleep(1); - bnx2_netif_stop(bp); + bnx2_disable_int_sync(bp); + napi_disable(&bp->napi); del_timer_sync(&bp->timer); if (bp->flags & NO_WOL_FLAG) reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN; @@ -6858,11 +6856,10 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) #ifdef BCM_VLAN dev->vlan_rx_register = bnx2_vlan_rx_register; #endif - dev->poll = bnx2_poll; dev->ethtool_ops = &bnx2_ethtool_ops; - dev->weight = 64; bp = netdev_priv(dev); + netif_napi_add(dev, &bp->napi, bnx2_poll, 64); #if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER) dev->poll_controller = poll_bnx2; diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h index 102adfe1e92..fbae439db64 100644 --- a/drivers/net/bnx2.h +++ b/drivers/net/bnx2.h @@ -6473,6 +6473,8 @@ struct bnx2 { struct net_device *dev; struct pci_dev *pdev; + struct napi_struct napi; + atomic_t intr_sem; struct status_block *status_blk; diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c index f6e4030c73d..13f14df21e6 100644 --- a/drivers/net/cassini.c +++ b/drivers/net/cassini.c @@ -2485,7 +2485,7 @@ static irqreturn_t cas_interruptN(int irq, void *dev_id) if (status & INTR_RX_DONE_ALT) { /* handle rx separately */ #ifdef USE_NAPI cas_mask_intr(cp); - netif_rx_schedule(dev); + netif_rx_schedule(dev, &cp->napi); #else cas_rx_ringN(cp, ring, 0); #endif @@ -2536,7 +2536,7 @@ static irqreturn_t cas_interrupt1(int irq, void *dev_id) if (status & INTR_RX_DONE_ALT) { /* handle rx separately */ #ifdef USE_NAPI cas_mask_intr(cp); - netif_rx_schedule(dev); + netif_rx_schedule(dev, &cp->napi); #else cas_rx_ringN(cp, 1, 0); #endif @@ -2592,7 +2592,7 @@ static irqreturn_t cas_interrupt(int irq, void *dev_id) if (status & INTR_RX_DONE) { #ifdef USE_NAPI cas_mask_intr(cp); - netif_rx_schedule(dev); + netif_rx_schedule(dev, &cp->napi); #else cas_rx_ringN(cp, 0, 0); #endif @@ -2607,9 +2607,10 @@ static irqreturn_t cas_interrupt(int irq, void *dev_id) #ifdef USE_NAPI -static int cas_poll(struct net_device *dev, int *budget) +static int cas_poll(struct napi_struct *napi, int budget) { - struct cas *cp = netdev_priv(dev); + struct cas *cp = container_of(napi, struct cas, napi); + struct net_device *dev = cp->dev; int i, enable_intr, todo, credits; u32 status = readl(cp->regs + REG_INTR_STATUS); unsigned long flags; @@ -2620,20 +2621,18 @@ static int cas_poll(struct net_device *dev, int *budget) /* NAPI rx packets. we spread the credits across all of the * rxc rings - */ - todo = min(*budget, dev->quota); - - /* to make sure we're fair with the work we loop through each + * + * to make sure we're fair with the work we loop through each * ring N_RX_COMP_RING times with a request of - * todo / N_RX_COMP_RINGS + * budget / N_RX_COMP_RINGS */ enable_intr = 1; credits = 0; for (i = 0; i < N_RX_COMP_RINGS; i++) { int j; for (j = 0; j < N_RX_COMP_RINGS; j++) { - credits += cas_rx_ringN(cp, j, todo / N_RX_COMP_RINGS); - if (credits >= todo) { + credits += cas_rx_ringN(cp, j, budget / N_RX_COMP_RINGS); + if (credits >= budget) { enable_intr = 0; goto rx_comp; } @@ -2641,9 +2640,6 @@ static int cas_poll(struct net_device *dev, int *budget) } rx_comp: - *budget -= credits; - dev->quota -= credits; - /* final rx completion */ spin_lock_irqsave(&cp->lock, flags); if (status) @@ -2674,11 +2670,10 @@ rx_comp: #endif spin_unlock_irqrestore(&cp->lock, flags); if (enable_intr) { - netif_rx_complete(dev); + netif_rx_complete(dev, napi); cas_unmask_intr(cp); - return 0; } - return 1; + return credits; } #endif @@ -4351,6 +4346,9 @@ static int cas_open(struct net_device *dev) goto err_spare; } +#ifdef USE_NAPI + napi_enable(&cp->napi); +#endif /* init hw */ cas_lock_all_save(cp, flags); cas_clean_rings(cp); @@ -4376,6 +4374,9 @@ static int cas_close(struct net_device *dev) unsigned long flags; struct cas *cp = netdev_priv(dev); +#ifdef USE_NAPI + napi_enable(&cp->napi); +#endif /* Make sure we don't get distracted by suspend/resume */ mutex_lock(&cp->pm_mutex); @@ -5062,8 +5063,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev, dev->watchdog_timeo = CAS_TX_TIMEOUT; dev->change_mtu = cas_change_mtu; #ifdef USE_NAPI - dev->poll = cas_poll; - dev->weight = 64; + netif_napi_add(dev, &cp->napi, cas_poll, 64); #endif #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = cas_netpoll; diff --git a/drivers/net/cassini.h b/drivers/net/cassini.h index a970804487c..2f93f83342d 100644 --- a/drivers/net/cassini.h +++ b/drivers/net/cassini.h @@ -4280,6 +4280,8 @@ struct cas { int rx_cur[N_RX_COMP_RINGS], rx_new[N_RX_COMP_RINGS]; int rx_last[N_RX_DESC_RINGS]; + struct napi_struct napi; + /* Set when chip is actually in operational state * (ie. not power managed) */ int hw_running; diff --git a/drivers/net/chelsio/common.h b/drivers/net/chelsio/common.h index 8ba702c8b56..b5de4452cf2 100644 --- a/drivers/net/chelsio/common.h +++ b/drivers/net/chelsio/common.h @@ -278,6 +278,7 @@ struct adapter { struct peespi *espi; struct petp *tp; + struct napi_struct napi; struct port_info port[MAX_NPORTS]; struct delayed_work stats_update_task; struct timer_list stats_update_timer; diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c index 231ce43b97c..593736c7550 100644 --- a/drivers/net/chelsio/cxgb2.c +++ b/drivers/net/chelsio/cxgb2.c @@ -255,8 +255,11 @@ static int cxgb_open(struct net_device *dev) struct adapter *adapter = dev->priv; int other_ports = adapter->open_device_map & PORT_MASK; - if (!adapter->open_device_map && (err = cxgb_up(adapter)) < 0) + napi_enable(&adapter->napi); + if (!adapter->open_device_map && (err = cxgb_up(adapter)) < 0) { + napi_disable(&adapter->napi); return err; + } __set_bit(dev->if_port, &adapter->open_device_map); link_start(&adapter->port[dev->if_port]); @@ -274,6 +277,7 @@ static int cxgb_close(struct net_device *dev) struct cmac *mac = p->mac; netif_stop_queue(dev); + napi_disable(&adapter->napi); mac->ops->disable(mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX); netif_carrier_off(dev); @@ -1113,8 +1117,7 @@ static int __devinit init_one(struct pci_dev *pdev, netdev->poll_controller = t1_netpoll; #endif #ifdef CONFIG_CHELSIO_T1_NAPI - netdev->weight = 64; - netdev->poll = t1_poll; + netif_napi_add(netdev, &adapter->napi, t1_poll, 64); #endif SET_ETHTOOL_OPS(netdev, &t1_ethtool_ops); diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c index e4f874a70fe..ffa7e649a6e 100644 --- a/drivers/net/chelsio/sge.c +++ b/drivers/net/chelsio/sge.c @@ -1620,23 +1620,20 @@ static int process_pure_responses(struct adapter *adapter) * or protection from interrupts as data interrupts are off at this point and * other adapter interrupts do not interfere. */ -int t1_poll(struct net_device *dev, int *budget) +int t1_poll(struct napi_struct *napi, int budget) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = container_of(napi, struct adapter, napi); + struct net_device *dev = adapter->port[0].dev; int work_done; - work_done = process_responses(adapter, min(*budget, dev->quota)); - *budget -= work_done; - dev->quota -= work_done; - - if (unlikely(responses_pending(adapter))) - return 1; - - netif_rx_complete(dev); - writel(adapter->sge->respQ.cidx, adapter->regs + A_SG_SLEEPING); - - return 0; + work_done = process_responses(adapter, budget); + if (likely(!responses_pending(adapter))) { + netif_rx_complete(dev, napi); + writel(adapter->sge->respQ.cidx, + adapter->regs + A_SG_SLEEPING); + } + return work_done; } /* @@ -1653,13 +1650,13 @@ irqreturn_t t1_interrupt(int irq, void *data) writel(F_PL_INTR_SGE_DATA, adapter->regs + A_PL_CAUSE); - if (__netif_rx_schedule_prep(dev)) { + if (napi_schedule_prep(&adapter->napi)) { if (process_pure_responses(adapter)) - __netif_rx_schedule(dev); + __netif_rx_schedule(dev, &adapter->napi); else { /* no data, no NAPI needed */ writel(sge->respQ.cidx, adapter->regs + A_SG_SLEEPING); - netif_poll_enable(dev); /* undo schedule_prep */ + napi_enable(&adapter->napi); /* undo schedule_prep */ } } return IRQ_HANDLED; diff --git a/drivers/net/chelsio/sge.h b/drivers/net/chelsio/sge.h index d132a0ef2a2..713d9c55f24 100644 --- a/drivers/net/chelsio/sge.h +++ b/drivers/net/chelsio/sge.h @@ -77,7 +77,7 @@ int t1_sge_configure(struct sge *, struct sge_params *); int t1_sge_set_coalesce_params(struct sge *, struct sge_params *); void t1_sge_destroy(struct sge *); irqreturn_t t1_interrupt(int irq, void *cookie); -int t1_poll(struct net_device *, int *); +int t1_poll(struct napi_struct *, int); int t1_start_xmit(struct sk_buff *skb, struct net_device *dev); void t1_set_vlan_accel(struct adapter *adapter, int on_off); diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h index 20e887de254..04426170338 100644 --- a/drivers/net/cxgb3/adapter.h +++ b/drivers/net/cxgb3/adapter.h @@ -49,11 +49,13 @@ typedef irqreturn_t(*intr_handler_t) (int, void *); struct vlan_group; - struct adapter; +struct sge_qset; + struct port_info { struct adapter *adapter; struct vlan_group *vlan_grp; + struct sge_qset *qs; const struct port_type_info *port_type; u8 port_id; u8 rx_csum_offload; @@ -173,10 +175,12 @@ enum { /* per port SGE statistics */ }; struct sge_qset { /* an SGE queue set */ + struct adapter *adap; + struct napi_struct napi; struct sge_rspq rspq; struct sge_fl fl[SGE_RXQ_PER_SET]; struct sge_txq txq[SGE_TXQ_PER_SET]; - struct net_device *netdev; /* associated net device */ + struct net_device *netdev; unsigned long txq_stopped; /* which Tx queues are stopped */ struct timer_list tx_reclaim_timer; /* reclaims TX buffers */ unsigned long port_stats[SGE_PSTAT_MAX]; @@ -221,12 +225,6 @@ struct adapter { struct delayed_work adap_check_task; struct work_struct ext_intr_handler_task; - /* - * Dummy netdevices are needed when using multiple receive queues with - * NAPI as each netdevice can service only one queue. - */ - struct net_device *dummy_netdev[SGE_QSETS - 1]; - struct dentry *debugfs_root; struct mutex mdio_lock; @@ -253,12 +251,6 @@ static inline struct port_info *adap2pinfo(struct adapter *adap, int idx) return netdev_priv(adap->port[idx]); } -/* - * We use the spare atalk_ptr to map a net device to its SGE queue set. - * This is a macro so it can be used as l-value. - */ -#define dev2qset(netdev) ((netdev)->atalk_ptr) - #define OFFLOAD_DEVMAP_BIT 15 #define tdev2adap(d) container_of(d, struct adapter, tdev) @@ -284,7 +276,7 @@ int t3_mgmt_tx(struct adapter *adap, struct sk_buff *skb); void t3_update_qset_coalesce(struct sge_qset *qs, const struct qset_params *p); int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, int irq_vec_idx, const struct qset_params *p, - int ntxq, struct net_device *netdev); + int ntxq, struct net_device *dev); int t3_get_desc(const struct sge_qset *qs, unsigned int qnum, unsigned int idx, unsigned char *data); irqreturn_t t3_sge_intr_msix(int irq, void *cookie); diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index 5ab319cfe5d..5db7d4e27ec 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -339,49 +339,17 @@ static void setup_rss(struct adapter *adap) V_RRCPLCPUSIZE(6), cpus, rspq_map); } -/* - * If we have multiple receive queues per port serviced by NAPI we need one - * netdevice per queue as NAPI operates on netdevices. We already have one - * netdevice, namely the one associated with the interface, so we use dummy - * ones for any additional queues. Note that these netdevices exist purely - * so that NAPI has something to work with, they do not represent network - * ports and are not registered. - */ -static int init_dummy_netdevs(struct adapter *adap) +static void init_napi(struct adapter *adap) { - int i, j, dummy_idx = 0; - struct net_device *nd; - - for_each_port(adap, i) { - struct net_device *dev = adap->port[i]; - const struct port_info *pi = netdev_priv(dev); - - for (j = 0; j < pi->nqsets - 1; j++) { - if (!adap->dummy_netdev[dummy_idx]) { - struct port_info *p; - - nd = alloc_netdev(sizeof(*p), "", ether_setup); - if (!nd) - goto free_all; + int i; - p = netdev_priv(nd); - p->adapter = adap; - nd->weight = 64; - set_bit(__LINK_STATE_START, &nd->state); - adap->dummy_netdev[dummy_idx] = nd; - } - strcpy(adap->dummy_netdev[dummy_idx]->name, dev->name); - dummy_idx++; - } - } - return 0; + for (i = 0; i < SGE_QSETS; i++) { + struct sge_qset *qs = &adap->sge.qs[i]; -free_all: - while (--dummy_idx >= 0) { - free_netdev(adap->dummy_netdev[dummy_idx]); - adap->dummy_netdev[dummy_idx] = NULL; + if (qs->adap) + netif_napi_add(qs->netdev, &qs->napi, qs->napi.poll, + 64); } - return -ENOMEM; } /* @@ -392,20 +360,18 @@ free_all: static void quiesce_rx(struct adapter *adap) { int i; - struct net_device *dev; - for_each_port(adap, i) { - dev = adap->port[i]; - while (test_bit(__LINK_STATE_RX_SCHED, &dev->state)) - msleep(1); - } + for (i = 0; i < SGE_QSETS; i++) + if (adap->sge.qs[i].adap) + napi_disable(&adap->sge.qs[i].napi); +} - for (i = 0; i < ARRAY_SIZE(adap->dummy_netdev); i++) { - dev = adap->dummy_netdev[i]; - if (dev) - while (test_bit(__LINK_STATE_RX_SCHED, &dev->state)) - msleep(1); - } +static void enable_all_napi(struct adapter *adap) +{ + int i; + for (i = 0; i < SGE_QSETS; i++) + if (adap->sge.qs[i].adap) + napi_enable(&adap->sge.qs[i].napi); } /** @@ -418,7 +384,7 @@ static void quiesce_rx(struct adapter *adap) */ static int setup_sge_qsets(struct adapter *adap) { - int i, j, err, irq_idx = 0, qset_idx = 0, dummy_dev_idx = 0; + int i, j, err, irq_idx = 0, qset_idx = 0; unsigned int ntxq = SGE_TXQ_PER_SET; if (adap->params.rev > 0 && !(adap->flags & USING_MSI)) @@ -426,15 +392,14 @@ static int setup_sge_qsets(struct adapter *adap) for_each_port(adap, i) { struct net_device *dev = adap->port[i]; - const struct port_info *pi = netdev_priv(dev); + struct port_info *pi = netdev_priv(dev); + pi->qs = &adap->sge.qs[pi->first_qset]; for (j = 0; j < pi->nqsets; ++j, ++qset_idx) { err = t3_sge_alloc_qset(adap, qset_idx, 1, (adap->flags & USING_MSIX) ? qset_idx + 1 : irq_idx, - &adap->params.sge.qset[qset_idx], ntxq, - j == 0 ? dev : - adap-> dummy_netdev[dummy_dev_idx++]); + &adap->params.sge.qset[qset_idx], ntxq, dev); if (err) { t3_free_sge_resources(adap); return err; @@ -845,21 +810,18 @@ static int cxgb_up(struct adapter *adap) goto out; } - err = init_dummy_netdevs(adap); - if (err) - goto out; - err = t3_init_hw(adap, 0); if (err) goto out; t3_write_reg(adap, A_ULPRX_TDDP_PSZ, V_HPZ0(PAGE_SHIFT - 12)); - + err = setup_sge_qsets(adap); if (err) goto out; setup_rss(adap); + init_napi(adap); adap->flags |= FULL_INIT_DONE; } @@ -886,6 +848,7 @@ static int cxgb_up(struct adapter *adap) adap->name, adap))) goto irq_err; + enable_all_napi(adap); t3_sge_start(adap); t3_intr_enable(adap); @@ -1012,8 +975,10 @@ static int cxgb_open(struct net_device *dev) int other_ports = adapter->open_device_map & PORT_MASK; int err; - if (!adapter->open_device_map && (err = cxgb_up(adapter)) < 0) + if (!adapter->open_device_map && (err = cxgb_up(adapter)) < 0) { + quiesce_rx(adapter); return err; + } set_bit(pi->port_id, &adapter->open_device_map); if (is_offload(adapter) && !ofld_disable) { @@ -2524,7 +2489,6 @@ static int __devinit init_one(struct pci_dev *pdev, #ifdef CONFIG_NET_POLL_CONTROLLER netdev->poll_controller = cxgb_netpoll; #endif - netdev->weight = 64; SET_ETHTOOL_OPS(netdev, &cxgb_ethtool_ops); } @@ -2625,12 +2589,6 @@ static void __devexit remove_one(struct pci_dev *pdev) t3_free_sge_resources(adapter); cxgb_disable_msi(adapter); - for (i = 0; i < ARRAY_SIZE(adapter->dummy_netdev); i++) - if (adapter->dummy_netdev[i]) { - free_netdev(adapter->dummy_netdev[i]); - adapter->dummy_netdev[i] = NULL; - } - for_each_port(adapter, i) if (adapter->port[i]) free_netdev(adapter->port[i]); diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c index 58a5f60521e..069c1aca8a6 100644 --- a/drivers/net/cxgb3/sge.c +++ b/drivers/net/cxgb3/sge.c @@ -591,9 +591,6 @@ void t3_free_qset(struct adapter *adapter, struct sge_qset *q) q->rspq.desc, q->rspq.phys_addr); } - if (q->netdev) - q->netdev->atalk_ptr = NULL; - memset(q, 0, sizeof(*q)); } @@ -1074,7 +1071,7 @@ int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev) unsigned int ndesc, pidx, credits, gen, compl; const struct port_info *pi = netdev_priv(dev); struct adapter *adap = pi->adapter; - struct sge_qset *qs = dev2qset(dev); + struct sge_qset *qs = pi->qs; struct sge_txq *q = &qs->txq[TXQ_ETH]; /* @@ -1326,13 +1323,12 @@ static void restart_ctrlq(unsigned long data) struct sk_buff *skb; struct sge_qset *qs = (struct sge_qset *)data; struct sge_txq *q = &qs->txq[TXQ_CTRL]; - const struct port_info *pi = netdev_priv(qs->netdev); - struct adapter *adap = pi->adapter; spin_lock(&q->lock); again:reclaim_completed_tx_imm(q); - while (q->in_use < q->size && (skb = __skb_dequeue(&q->sendq)) != NULL) { + while (q->in_use < q->size && + (skb = __skb_dequeue(&q->sendq)) != NULL) { write_imm(&q->desc[q->pidx], skb, skb->len, q->gen); @@ -1354,7 +1350,7 @@ static void restart_ctrlq(unsigned long data) } spin_unlock(&q->lock); - t3_write_reg(adap, A_SG_KDOORBELL, + t3_write_reg(qs->adap, A_SG_KDOORBELL, F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id)); } @@ -1638,8 +1634,7 @@ static inline void offload_enqueue(struct sge_rspq *q, struct sk_buff *skb) else { struct sge_qset *qs = rspq_to_qset(q); - if (__netif_rx_schedule_prep(qs->netdev)) - __netif_rx_schedule(qs->netdev); + napi_schedule(&qs->napi); q->rx_head = skb; } q->rx_tail = skb; @@ -1675,34 +1670,30 @@ static inline void deliver_partial_bundle(struct t3cdev *tdev, * receive handler. Batches need to be of modest size as we do prefetches * on the packets in each. */ -static int ofld_poll(struct net_device *dev, int *budget) +static int ofld_poll(struct napi_struct *napi, int budget) { - const struct port_info *pi = netdev_priv(dev); - struct adapter *adapter = pi->adapter; - struct sge_qset *qs = dev2qset(dev); + struct sge_qset *qs = container_of(napi, struct sge_qset, napi); struct sge_rspq *q = &qs->rspq; - int work_done, limit = min(*budget, dev->quota), avail = limit; + struct adapter *adapter = qs->adap; + int work_done = 0; - while (avail) { + while (work_done < budget) { struct sk_buff *head, *tail, *skbs[RX_BUNDLE_SIZE]; int ngathered; spin_lock_irq(&q->lock); head = q->rx_head; if (!head) { - work_done = limit - avail; - *budget -= work_done; - dev->quota -= work_done; - __netif_rx_complete(dev); + napi_complete(napi); spin_unlock_irq(&q->lock); - return 0; + return work_done; } tail = q->rx_tail; q->rx_head = q->rx_tail = NULL; spin_unlock_irq(&q->lock); - for (ngathered = 0; avail && head; avail--) { + for (ngathered = 0; work_done < budget && head; work_done++) { prefetch(head->data); skbs[ngathered] = head; head = head->next; @@ -1724,10 +1715,8 @@ static int ofld_poll(struct net_device *dev, int *budget) } deliver_partial_bundle(&adapter->tdev, q, skbs, ngathered); } - work_done = limit - avail; - *budget -= work_done; - dev->quota -= work_done; - return 1; + + return work_done; } /** @@ -2071,50 +2060,47 @@ static inline int is_pure_response(const struct rsp_desc *r) /** * napi_rx_handler - the NAPI handler for Rx processing - * @dev: the net device + * @napi: the napi instance * @budget: how many packets we can process in this round * * Handler for new data events when using NAPI. */ -static int napi_rx_handler(struct net_device *dev, int *budget) +static int napi_rx_handler(struct napi_struct *napi, int budget) { - const struct port_info *pi = netdev_priv(dev); - struct adapter *adap = pi->adapter; - struct sge_qset *qs = dev2qset(dev); - int effective_budget = min(*budget, dev->quota); - - int work_done = process_responses(adap, qs, effective_budget); - *budget -= work_done; - dev->quota -= work_done; + struct sge_qset *qs = container_of(napi, struct sge_qset, napi); + struct adapter *adap = qs->adap; + int work_done = process_responses(adap, qs, budget); - if (work_done >= effective_budget) - return 1; - - netif_rx_complete(dev); + if (likely(work_done < budget)) { + napi_complete(napi); - /* - * Because we don't atomically flush the following write it is - * possible that in very rare cases it can reach the device in a way - * that races with a new response being written plus an error interrupt - * causing the NAPI interrupt handler below to return unhandled status - * to the OS. To protect against this would require flushing the write - * and doing both the write and the flush with interrupts off. Way too - * expensive and unjustifiable given the rarity of the race. - * - * The race cannot happen at all with MSI-X. - */ - t3_write_reg(adap, A_SG_GTS, V_RSPQ(qs->rspq.cntxt_id) | - V_NEWTIMER(qs->rspq.next_holdoff) | - V_NEWINDEX(qs->rspq.cidx)); - return 0; + /* + * Because we don't atomically flush the following + * write it is possible that in very rare cases it can + * reach the device in a way that races with a new + * response being written plus an error interrupt + * causing the NAPI interrupt handler below to return + * unhandled status to the OS. To protect against + * this would require flushing the write and doing + * both the write and the flush with interrupts off. + * Way too expensive and unjustifiable given the + * rarity of the race. + * + * The race cannot happen at all with MSI-X. + */ + t3_write_reg(adap, A_SG_GTS, V_RSPQ(qs->rspq.cntxt_id) | + V_NEWTIMER(qs->rspq.next_holdoff) | + V_NEWINDEX(qs->rspq.cidx)); + } + return work_done; } /* * Returns true if the device is already scheduled for polling. */ -static inline int napi_is_scheduled(struct net_device *dev) +static inline int napi_is_scheduled(struct napi_struct *napi) { - return test_bit(__LINK_STATE_RX_SCHED, &dev->state); + return test_bit(NAPI_STATE_SCHED, &napi->state); } /** @@ -2197,8 +2183,7 @@ static inline int handle_responses(struct adapter *adap, struct sge_rspq *q) V_NEWTIMER(q->holdoff_tmr) | V_NEWINDEX(q->cidx)); return 0; } - if (likely(__netif_rx_schedule_prep(qs->netdev))) - __netif_rx_schedule(qs->netdev); + napi_schedule(&qs->napi); return 1; } @@ -2209,8 +2194,7 @@ static inline int handle_responses(struct adapter *adap, struct sge_rspq *q) irqreturn_t t3_sge_intr_msix(int irq, void *cookie) { struct sge_qset *qs = cookie; - const struct port_info *pi = netdev_priv(qs->netdev); - struct adapter *adap = pi->adapter; + struct adapter *adap = qs->adap; struct sge_rspq *q = &qs->rspq; spin_lock(&q->lock); @@ -2229,13 +2213,11 @@ irqreturn_t t3_sge_intr_msix(int irq, void *cookie) irqreturn_t t3_sge_intr_msix_napi(int irq, void *cookie) { struct sge_qset *qs = cookie; - const struct port_info *pi = netdev_priv(qs->netdev); - struct adapter *adap = pi->adapter; struct sge_rspq *q = &qs->rspq; spin_lock(&q->lock); - if (handle_responses(adap, q) < 0) + if (handle_responses(qs->adap, q) < 0) q->unhandled_irqs++; spin_unlock(&q->lock); return IRQ_HANDLED; @@ -2278,11 +2260,13 @@ static irqreturn_t t3_intr_msi(int irq, void *cookie) return IRQ_HANDLED; } -static int rspq_check_napi(struct net_device *dev, struct sge_rspq *q) +static int rspq_check_napi(struct sge_qset *qs) { - if (!napi_is_scheduled(dev) && is_new_response(&q->desc[q->cidx], q)) { - if (likely(__netif_rx_schedule_prep(dev))) - __netif_rx_schedule(dev); + struct sge_rspq *q = &qs->rspq; + + if (!napi_is_scheduled(&qs->napi) && + is_new_response(&q->desc[q->cidx], q)) { + napi_schedule(&qs->napi); return 1; } return 0; @@ -2303,10 +2287,9 @@ irqreturn_t t3_intr_msi_napi(int irq, void *cookie) spin_lock(&q->lock); - new_packets = rspq_check_napi(adap->sge.qs[0].netdev, q); + new_packets = rspq_check_napi(&adap->sge.qs[0]); if (adap->params.nports == 2) - new_packets += rspq_check_napi(adap->sge.qs[1].netdev, - &adap->sge.qs[1].rspq); + new_packets += rspq_check_napi(&adap->sge.qs[1]); if (!new_packets && t3_slow_intr_handler(adap) == 0) q->unhandled_irqs++; @@ -2409,9 +2392,9 @@ static irqreturn_t t3b_intr(int irq, void *cookie) static irqreturn_t t3b_intr_napi(int irq, void *cookie) { u32 map; - struct net_device *dev; struct adapter *adap = cookie; - struct sge_rspq *q0 = &adap->sge.qs[0].rspq; + struct sge_qset *qs0 = &adap->sge.qs[0]; + struct sge_rspq *q0 = &qs0->rspq; t3_write_reg(adap, A_PL_CLI, 0); map = t3_read_reg(adap, A_SG_DATA_INTR); @@ -2424,18 +2407,11 @@ static irqreturn_t t3b_intr_napi(int irq, void *cookie) if (unlikely(map & F_ERRINTR)) t3_slow_intr_handler(adap); - if (likely(map & 1)) { - dev = adap->sge.qs[0].netdev; - - if (likely(__netif_rx_schedule_prep(dev))) - __netif_rx_schedule(dev); - } - if (map & 2) { - dev = adap->sge.qs[1].netdev; + if (likely(map & 1)) + napi_schedule(&qs0->napi); - if (likely(__netif_rx_schedule_prep(dev))) - __netif_rx_schedule(dev); - } + if (map & 2) + napi_schedule(&adap->sge.qs[1].napi); spin_unlock(&q0->lock); return IRQ_HANDLED; @@ -2514,8 +2490,7 @@ static void sge_timer_cb(unsigned long data) { spinlock_t *lock; struct sge_qset *qs = (struct sge_qset *)data; - const struct port_info *pi = netdev_priv(qs->netdev); - struct adapter *adap = pi->adapter; + struct adapter *adap = qs->adap; if (spin_trylock(&qs->txq[TXQ_ETH].lock)) { reclaim_completed_tx(adap, &qs->txq[TXQ_ETH]); @@ -2526,9 +2501,9 @@ static void sge_timer_cb(unsigned long data) spin_unlock(&qs->txq[TXQ_OFLD].lock); } lock = (adap->flags & USING_MSIX) ? &qs->rspq.lock : - &adap->sge.qs[0].rspq.lock; + &adap->sge.qs[0].rspq.lock; if (spin_trylock_irq(lock)) { - if (!napi_is_scheduled(qs->netdev)) { + if (!napi_is_scheduled(&qs->napi)) { u32 status = t3_read_reg(adap, A_SG_RSPQ_FL_STATUS); if (qs->fl[0].credits < qs->fl[0].size) @@ -2562,12 +2537,9 @@ static void sge_timer_cb(unsigned long data) */ void t3_update_qset_coalesce(struct sge_qset *qs, const struct qset_params *p) { - if (!qs->netdev) - return; - qs->rspq.holdoff_tmr = max(p->coalesce_usecs * 10, 1U);/* can't be 0 */ qs->rspq.polling = p->polling; - qs->netdev->poll = p->polling ? napi_rx_handler : ofld_poll; + qs->napi.poll = p->polling ? napi_rx_handler : ofld_poll; } /** @@ -2587,7 +2559,7 @@ void t3_update_qset_coalesce(struct sge_qset *qs, const struct qset_params *p) */ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, int irq_vec_idx, const struct qset_params *p, - int ntxq, struct net_device *netdev) + int ntxq, struct net_device *dev) { int i, ret = -ENOMEM; struct sge_qset *q = &adapter->sge.qs[id]; @@ -2708,16 +2680,10 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, } spin_unlock(&adapter->sge.reg_lock); - q->netdev = netdev; - t3_update_qset_coalesce(q, p); - /* - * We use atalk_ptr as a backpointer to a qset. In case a device is - * associated with multiple queue sets only the first one sets - * atalk_ptr. - */ - if (netdev->atalk_ptr == NULL) - netdev->atalk_ptr = q; + q->adap = adapter; + q->netdev = dev; + t3_update_qset_coalesce(q, p); refill_fl(adapter, &q->fl[0], q->fl[0].size, GFP_KERNEL); refill_fl(adapter, &q->fl[1], q->fl[1].size, GFP_KERNEL); diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 280313b9b06..e25f5ec2b27 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -539,6 +539,7 @@ struct nic { struct csr __iomem *csr; enum scb_cmd_lo cuc_cmd; unsigned int cbs_avail; + struct napi_struct napi; struct cb *cbs; struct cb *cb_to_use; struct cb *cb_to_send; @@ -1974,35 +1975,31 @@ static irqreturn_t e100_intr(int irq, void *dev_id) if(stat_ack & stat_ack_rnr) nic->ru_running = RU_SUSPENDED; - if(likely(netif_rx_schedule_prep(netdev))) { + if(likely(netif_rx_schedule_prep(netdev, &nic->napi))) { e100_disable_irq(nic); - __netif_rx_schedule(netdev); + __netif_rx_schedule(netdev, &nic->napi); } return IRQ_HANDLED; } -static int e100_poll(struct net_device *netdev, int *budget) +static int e100_poll(struct napi_struct *napi, int budget) { - struct nic *nic = netdev_priv(netdev); - unsigned int work_to_do = min(netdev->quota, *budget); - unsigned int work_done = 0; + struct nic *nic = container_of(napi, struct nic, napi); + struct net_device *netdev = nic->netdev; + int work_done = 0; int tx_cleaned; - e100_rx_clean(nic, &work_done, work_to_do); + e100_rx_clean(nic, &work_done, budget); tx_cleaned = e100_tx_clean(nic); /* If no Rx and Tx cleanup work was done, exit polling mode. */ if((!tx_cleaned && (work_done == 0)) || !netif_running(netdev)) { - netif_rx_complete(netdev); + netif_rx_complete(netdev, napi); e100_enable_irq(nic); - return 0; } - *budget -= work_done; - netdev->quota -= work_done; - - return 1; + return work_done; } #ifdef CONFIG_NET_POLL_CONTROLLER @@ -2071,7 +2068,7 @@ static int e100_up(struct nic *nic) nic->netdev->name, nic->netdev))) goto err_no_irq; netif_wake_queue(nic->netdev); - netif_poll_enable(nic->netdev); + napi_enable(&nic->napi); /* enable ints _after_ enabling poll, preventing a race between * disable ints+schedule */ e100_enable_irq(nic); @@ -2089,7 +2086,7 @@ err_rx_clean_list: static void e100_down(struct nic *nic) { /* wait here for poll to complete */ - netif_poll_disable(nic->netdev); + napi_disable(&nic->napi); netif_stop_queue(nic->netdev); e100_hw_reset(nic); free_irq(nic->pdev->irq, nic->netdev); @@ -2572,14 +2569,13 @@ static int __devinit e100_probe(struct pci_dev *pdev, SET_ETHTOOL_OPS(netdev, &e100_ethtool_ops); netdev->tx_timeout = e100_tx_timeout; netdev->watchdog_timeo = E100_WATCHDOG_PERIOD; - netdev->poll = e100_poll; - netdev->weight = E100_NAPI_WEIGHT; #ifdef CONFIG_NET_POLL_CONTROLLER netdev->poll_controller = e100_netpoll; #endif strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1); nic = netdev_priv(netdev); + netif_napi_add(netdev, &nic->napi, e100_poll, E100_NAPI_WEIGHT); nic->netdev = netdev; nic->pdev = pdev; nic->msg_enable = (1 << debug) - 1; @@ -2733,7 +2729,7 @@ static int e100_suspend(struct pci_dev *pdev, pm_message_t state) struct nic *nic = netdev_priv(netdev); if (netif_running(netdev)) - netif_poll_disable(nic->netdev); + napi_disable(&nic->napi); del_timer_sync(&nic->watchdog); netif_carrier_off(nic->netdev); netif_device_detach(netdev); @@ -2779,7 +2775,7 @@ static void e100_shutdown(struct pci_dev *pdev) struct nic *nic = netdev_priv(netdev); if (netif_running(netdev)) - netif_poll_disable(nic->netdev); + napi_disable(&nic->napi); del_timer_sync(&nic->watchdog); netif_carrier_off(nic->netdev); @@ -2804,12 +2800,13 @@ static void e100_shutdown(struct pci_dev *pdev) static pci_ers_result_t e100_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state) { struct net_device *netdev = pci_get_drvdata(pdev); + struct nic *nic = netdev_priv(netdev); /* Similar to calling e100_down(), but avoids adpater I/O. */ netdev->stop(netdev); /* Detach; put netif into state similar to hotplug unplug. */ - netif_poll_enable(netdev); + napi_enable(&nic->napi); netif_device_detach(netdev); pci_disable_device(pdev); diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index 16a6edfeba4..781ed996848 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -300,6 +300,7 @@ struct e1000_adapter { int cleaned_count); struct e1000_rx_ring *rx_ring; /* One per active queue */ #ifdef CONFIG_E1000_NAPI + struct napi_struct napi; struct net_device *polling_netdev; /* One per active queue */ #endif int num_tx_queues; diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index e7c8951f47f..723568d6e44 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -166,7 +166,7 @@ static irqreturn_t e1000_intr_msi(int irq, void *data); static boolean_t e1000_clean_tx_irq(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring); #ifdef CONFIG_E1000_NAPI -static int e1000_clean(struct net_device *poll_dev, int *budget); +static int e1000_clean(struct napi_struct *napi, int budget); static boolean_t e1000_clean_rx_irq(struct e1000_adapter *adapter, struct e1000_rx_ring *rx_ring, int *work_done, int work_to_do); @@ -545,7 +545,7 @@ int e1000_up(struct e1000_adapter *adapter) clear_bit(__E1000_DOWN, &adapter->flags); #ifdef CONFIG_E1000_NAPI - netif_poll_enable(adapter->netdev); + napi_enable(&adapter->napi); #endif e1000_irq_enable(adapter); @@ -634,7 +634,7 @@ e1000_down(struct e1000_adapter *adapter) set_bit(__E1000_DOWN, &adapter->flags); #ifdef CONFIG_E1000_NAPI - netif_poll_disable(netdev); + napi_disable(&adapter->napi); #endif e1000_irq_disable(adapter); @@ -936,8 +936,7 @@ e1000_probe(struct pci_dev *pdev, netdev->tx_timeout = &e1000_tx_timeout; netdev->watchdog_timeo = 5 * HZ; #ifdef CONFIG_E1000_NAPI - netdev->poll = &e1000_clean; - netdev->weight = 64; + netif_napi_add(netdev, &adapter->napi, e1000_clean, 64); #endif netdev->vlan_rx_register = e1000_vlan_rx_register; netdev->vlan_rx_add_vid = e1000_vlan_rx_add_vid; @@ -1151,9 +1150,6 @@ e1000_probe(struct pci_dev *pdev, /* tell the stack to leave us alone until e1000_open() is called */ netif_carrier_off(netdev); netif_stop_queue(netdev); -#ifdef CONFIG_E1000_NAPI - netif_poll_disable(netdev); -#endif strcpy(netdev->name, "eth%d"); if ((err = register_netdev(netdev))) @@ -1222,12 +1218,13 @@ e1000_remove(struct pci_dev *pdev) * would have already happened in close and is redundant. */ e1000_release_hw_control(adapter); - unregister_netdev(netdev); #ifdef CONFIG_E1000_NAPI for (i = 0; i < adapter->num_rx_queues; i++) dev_put(&adapter->polling_netdev[i]); #endif + unregister_netdev(netdev); + if (!e1000_check_phy_reset_block(&adapter->hw)) e1000_phy_hw_reset(&adapter->hw); @@ -1325,8 +1322,6 @@ e1000_sw_init(struct e1000_adapter *adapter) #ifdef CONFIG_E1000_NAPI for (i = 0; i < adapter->num_rx_queues; i++) { adapter->polling_netdev[i].priv = adapter; - adapter->polling_netdev[i].poll = &e1000_clean; - adapter->polling_netdev[i].weight = 64; dev_hold(&adapter->polling_netdev[i]); set_bit(__LINK_STATE_START, &adapter->polling_netdev[i].state); } @@ -1443,7 +1438,7 @@ e1000_open(struct net_device *netdev) clear_bit(__E1000_DOWN, &adapter->flags); #ifdef CONFIG_E1000_NAPI - netif_poll_enable(netdev); + napi_enable(&adapter->napi); #endif e1000_irq_enable(adapter); @@ -3786,12 +3781,12 @@ e1000_intr_msi(int irq, void *data) } #ifdef CONFIG_E1000_NAPI - if (likely(netif_rx_schedule_prep(netdev))) { + if (likely(netif_rx_schedule_prep(netdev, &adapter->napi))) { adapter->total_tx_bytes = 0; adapter->total_tx_packets = 0; adapter->total_rx_bytes = 0; adapter->total_rx_packets = 0; - __netif_rx_schedule(netdev); + __netif_rx_schedule(netdev, &adapter->napi); } else e1000_irq_enable(adapter); #else @@ -3871,12 +3866,12 @@ e1000_intr(int irq, void *data) E1000_WRITE_REG(hw, IMC, ~0); E1000_WRITE_FLUSH(hw); } - if (likely(netif_rx_schedule_prep(netdev))) { + if (likely(netif_rx_schedule_prep(netdev, &adapter->napi))) { adapter->total_tx_bytes = 0; adapter->total_tx_packets = 0; adapter->total_rx_bytes = 0; adapter->total_rx_packets = 0; - __netif_rx_schedule(netdev); + __netif_rx_schedule(netdev, &adapter->napi); } else /* this really should not happen! if it does it is basically a * bug, but not a hard error, so enable ints and continue */ @@ -3924,10 +3919,10 @@ e1000_intr(int irq, void *data) **/ static int -e1000_clean(struct net_device *poll_dev, int *budget) +e1000_clean(struct napi_struct *napi, int budget) { - struct e1000_adapter *adapter; - int work_to_do = min(*budget, poll_dev->quota); + struct e1000_adapter *adapter = container_of(napi, struct e1000_adapter, napi); + struct net_device *poll_dev = adapter->netdev; int tx_cleaned = 0, work_done = 0; /* Must NOT use netdev_priv macro here. */ @@ -3948,23 +3943,19 @@ e1000_clean(struct net_device *poll_dev, int *budget) } adapter->clean_rx(adapter, &adapter->rx_ring[0], - &work_done, work_to_do); - - *budget -= work_done; - poll_dev->quota -= work_done; + &work_done, budget); /* If no Tx and not enough Rx work done, exit the polling mode */ - if ((!tx_cleaned && (work_done == 0)) || + if ((!tx_cleaned && (work_done < budget)) || !netif_running(poll_dev)) { quit_polling: if (likely(adapter->itr_setting & 3)) e1000_set_itr(adapter); - netif_rx_complete(poll_dev); + netif_rx_complete(poll_dev, napi); e1000_irq_enable(adapter); - return 0; } - return 1; + return work_done; } #endif diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h index 8d58be56f4e..a154681165b 100644 --- a/drivers/net/ehea/ehea.h +++ b/drivers/net/ehea/ehea.h @@ -351,6 +351,7 @@ struct ehea_q_skb_arr { * Port resources */ struct ehea_port_res { + struct napi_struct napi; struct port_stats p_stats; struct ehea_mr send_mr; /* send memory region */ struct ehea_mr recv_mr; /* receive memory region */ @@ -362,7 +363,6 @@ struct ehea_port_res { struct ehea_cq *send_cq; struct ehea_cq *recv_cq; struct ehea_eq *eq; - struct net_device *d_netdev; struct ehea_q_skb_arr rq1_skba; struct ehea_q_skb_arr rq2_skba; struct ehea_q_skb_arr rq3_skba; diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 717b12984d1..5ebd545ab04 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -393,9 +393,9 @@ static int ehea_treat_poll_error(struct ehea_port_res *pr, int rq, return 0; } -static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev, - struct ehea_port_res *pr, - int *budget) +static int ehea_proc_rwqes(struct net_device *dev, + struct ehea_port_res *pr, + int budget) { struct ehea_port *port = pr->port; struct ehea_qp *qp = pr->qp; @@ -408,18 +408,16 @@ static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev, int skb_arr_rq2_len = pr->rq2_skba.len; int skb_arr_rq3_len = pr->rq3_skba.len; int processed, processed_rq1, processed_rq2, processed_rq3; - int wqe_index, last_wqe_index, rq, my_quota, port_reset; + int wqe_index, last_wqe_index, rq, port_reset; processed = processed_rq1 = processed_rq2 = processed_rq3 = 0; last_wqe_index = 0; - my_quota = min(*budget, dev->quota); cqe = ehea_poll_rq1(qp, &wqe_index); - while ((my_quota > 0) && cqe) { + while ((processed < budget) && cqe) { ehea_inc_rq1(qp); processed_rq1++; processed++; - my_quota--; if (netif_msg_rx_status(port)) ehea_dump(cqe, sizeof(*cqe), "CQE"); @@ -434,14 +432,14 @@ static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev, if (netif_msg_rx_err(port)) ehea_error("LL rq1: skb=NULL"); - skb = netdev_alloc_skb(port->netdev, + skb = netdev_alloc_skb(dev, EHEA_L_PKT_SIZE); if (!skb) break; } skb_copy_to_linear_data(skb, ((char*)cqe) + 64, cqe->num_bytes_transfered - 4); - ehea_fill_skb(port->netdev, skb, cqe); + ehea_fill_skb(dev, skb, cqe); } else if (rq == 2) { /* RQ2 */ skb = get_skb_by_index(skb_arr_rq2, skb_arr_rq2_len, cqe); @@ -450,7 +448,7 @@ static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev, ehea_error("rq2: skb=NULL"); break; } - ehea_fill_skb(port->netdev, skb, cqe); + ehea_fill_skb(dev, skb, cqe); processed_rq2++; } else { /* RQ3 */ skb = get_skb_by_index(skb_arr_rq3, @@ -460,7 +458,7 @@ static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev, ehea_error("rq3: skb=NULL"); break; } - ehea_fill_skb(port->netdev, skb, cqe); + ehea_fill_skb(dev, skb, cqe); processed_rq3++; } @@ -471,7 +469,7 @@ static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev, else netif_receive_skb(skb); - port->netdev->last_rx = jiffies; + dev->last_rx = jiffies; } else { pr->p_stats.poll_receive_errors++; port_reset = ehea_treat_poll_error(pr, rq, cqe, @@ -484,14 +482,12 @@ static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev, } pr->rx_packets += processed; - *budget -= processed; ehea_refill_rq1(pr, last_wqe_index, processed_rq1); ehea_refill_rq2(pr, processed_rq2); ehea_refill_rq3(pr, processed_rq3); - cqe = ehea_poll_rq1(qp, &wqe_index); - return cqe; + return processed; } static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota) @@ -554,22 +550,27 @@ static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota) } #define EHEA_NAPI_POLL_NUM_BEFORE_IRQ 16 +#define EHEA_POLL_MAX_CQES 65535 -static int ehea_poll(struct net_device *dev, int *budget) +static int ehea_poll(struct napi_struct *napi, int budget) { - struct ehea_port_res *pr = dev->priv; + struct ehea_port_res *pr = container_of(napi, struct ehea_port_res, napi); + struct net_device *dev = pr->port->netdev; struct ehea_cqe *cqe; struct ehea_cqe *cqe_skb = NULL; int force_irq, wqe_index; - - cqe = ehea_poll_rq1(pr->qp, &wqe_index); - cqe_skb = ehea_poll_cq(pr->send_cq); + int rx = 0; force_irq = (pr->poll_counter > EHEA_NAPI_POLL_NUM_BEFORE_IRQ); + cqe_skb = ehea_proc_cqes(pr, EHEA_POLL_MAX_CQES); + + if (!force_irq) + rx += ehea_proc_rwqes(dev, pr, budget - rx); - if ((!cqe && !cqe_skb) || force_irq) { + while ((rx != budget) || force_irq) { pr->poll_counter = 0; - netif_rx_complete(dev); + force_irq = 0; + netif_rx_complete(dev, napi); ehea_reset_cq_ep(pr->recv_cq); ehea_reset_cq_ep(pr->send_cq); ehea_reset_cq_n1(pr->recv_cq); @@ -578,43 +579,35 @@ static int ehea_poll(struct net_device *dev, int *budget) cqe_skb = ehea_poll_cq(pr->send_cq); if (!cqe && !cqe_skb) - return 0; + return rx; - if (!netif_rx_reschedule(dev, dev->quota)) - return 0; - } - - cqe = ehea_proc_rwqes(dev, pr, budget); - cqe_skb = ehea_proc_cqes(pr, 300); + if (!netif_rx_reschedule(dev, napi)) + return rx; - if (cqe || cqe_skb) - pr->poll_counter++; + cqe_skb = ehea_proc_cqes(pr, EHEA_POLL_MAX_CQES); + rx += ehea_proc_rwqes(dev, pr, budget - rx); + } - return 1; + pr->poll_counter++; + return rx; } #ifdef CONFIG_NET_POLL_CONTROLLER static void ehea_netpoll(struct net_device *dev) { struct ehea_port *port = netdev_priv(dev); + int i; - netif_rx_schedule(port->port_res[0].d_netdev); + for (i = 0; i < port->num_def_qps; i++) + netif_rx_schedule(dev, &port->port_res[i].napi); } #endif -static int ehea_poll_firstqueue(struct net_device *dev, int *budget) -{ - struct ehea_port *port = netdev_priv(dev); - struct net_device *d_dev = port->port_res[0].d_netdev; - - return ehea_poll(d_dev, budget); -} - static irqreturn_t ehea_recv_irq_handler(int irq, void *param) { struct ehea_port_res *pr = param; - netif_rx_schedule(pr->d_netdev); + netif_rx_schedule(pr->port->netdev, &pr->napi); return IRQ_HANDLED; } @@ -1236,14 +1229,7 @@ static int ehea_init_port_res(struct ehea_port *port, struct ehea_port_res *pr, kfree(init_attr); - pr->d_netdev = alloc_netdev(0, "", ether_setup); - if (!pr->d_netdev) - goto out_free; - pr->d_netdev->priv = pr; - pr->d_netdev->weight = 64; - pr->d_netdev->poll = ehea_poll; - set_bit(__LINK_STATE_START, &pr->d_netdev->state); - strcpy(pr->d_netdev->name, port->netdev->name); + netif_napi_add(pr->port->netdev, &pr->napi, ehea_poll, 64); ret = 0; goto out; @@ -1266,8 +1252,6 @@ static int ehea_clean_portres(struct ehea_port *port, struct ehea_port_res *pr) { int ret, i; - free_netdev(pr->d_netdev); - ret = ehea_destroy_qp(pr->qp); if (!ret) { @@ -2248,6 +2232,22 @@ out: return ret; } +static void port_napi_disable(struct ehea_port *port) +{ + int i; + + for (i = 0; i < port->num_def_qps; i++) + napi_disable(&port->port_res[i].napi); +} + +static void port_napi_enable(struct ehea_port *port) +{ + int i; + + for (i = 0; i < port->num_def_qps; i++) + napi_enable(&port->port_res[i].napi); +} + static int ehea_open(struct net_device *dev) { int ret; @@ -2259,8 +2259,10 @@ static int ehea_open(struct net_device *dev) ehea_info("enabling port %s", dev->name); ret = ehea_up(dev); - if (!ret) + if (!ret) { + port_napi_enable(port); netif_start_queue(dev); + } up(&port->port_lock); @@ -2269,7 +2271,7 @@ static int ehea_open(struct net_device *dev) static int ehea_down(struct net_device *dev) { - int ret, i; + int ret; struct ehea_port *port = netdev_priv(dev); if (port->state == EHEA_PORT_DOWN) @@ -2278,10 +2280,7 @@ static int ehea_down(struct net_device *dev) ehea_drop_multicast_list(dev); ehea_free_interrupts(dev); - for (i = 0; i < port->num_def_qps; i++) - while (test_bit(__LINK_STATE_RX_SCHED, - &port->port_res[i].d_netdev->state)) - msleep(1); + port_napi_disable(port); port->state = EHEA_PORT_DOWN; @@ -2319,7 +2318,8 @@ static void ehea_reset_port(struct work_struct *work) port->resets++; down(&port->port_lock); netif_stop_queue(dev); - netif_poll_disable(dev); + + port_napi_disable(port); ehea_down(dev); @@ -2330,7 +2330,8 @@ static void ehea_reset_port(struct work_struct *work) if (netif_msg_timer(port)) ehea_info("Device %s resetted successfully", dev->name); - netif_poll_enable(dev); + port_napi_enable(port); + netif_wake_queue(dev); out: up(&port->port_lock); @@ -2358,7 +2359,9 @@ static void ehea_rereg_mrs(struct work_struct *work) dev->name); down(&port->port_lock); netif_stop_queue(dev); - netif_poll_disable(dev); + + port_napi_disable(port); + ehea_down(dev); up(&port->port_lock); } @@ -2406,7 +2409,7 @@ static void ehea_rereg_mrs(struct work_struct *work) ret = ehea_up(dev); if (!ret) { - netif_poll_enable(dev); + port_napi_enable(port); netif_wake_queue(dev); } @@ -2644,11 +2647,9 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter, memcpy(dev->dev_addr, &port->mac_addr, ETH_ALEN); dev->open = ehea_open; - dev->poll = ehea_poll_firstqueue; #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = ehea_netpoll; #endif - dev->weight = 64; dev->stop = ehea_stop; dev->hard_start_xmit = ehea_start_xmit; dev->get_stats = ehea_get_stats; diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index 119778401e4..f8446e373bd 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -262,6 +262,7 @@ struct epic_private { /* Ring pointers. */ spinlock_t lock; /* Group with Tx control cache line. */ spinlock_t napi_lock; + struct napi_struct napi; unsigned int reschedule_in_poll; unsigned int cur_tx, dirty_tx; @@ -294,7 +295,7 @@ static void epic_tx_timeout(struct net_device *dev); static void epic_init_ring(struct net_device *dev); static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev); static int epic_rx(struct net_device *dev, int budget); -static int epic_poll(struct net_device *dev, int *budget); +static int epic_poll(struct napi_struct *napi, int budget); static irqreturn_t epic_interrupt(int irq, void *dev_instance); static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static const struct ethtool_ops netdev_ethtool_ops; @@ -487,8 +488,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev, dev->ethtool_ops = &netdev_ethtool_ops; dev->watchdog_timeo = TX_TIMEOUT; dev->tx_timeout = &epic_tx_timeout; - dev->poll = epic_poll; - dev->weight = 64; + netif_napi_add(dev, &ep->napi, epic_poll, 64); ret = register_netdev(dev); if (ret < 0) @@ -660,8 +660,11 @@ static int epic_open(struct net_device *dev) /* Soft reset the chip. */ outl(0x4001, ioaddr + GENCTL); - if ((retval = request_irq(dev->irq, &epic_interrupt, IRQF_SHARED, dev->name, dev))) + napi_enable(&ep->napi); + if ((retval = request_irq(dev->irq, &epic_interrupt, IRQF_SHARED, dev->name, dev))) { + napi_disable(&ep->napi); return retval; + } epic_init_ring(dev); @@ -1103,9 +1106,9 @@ static irqreturn_t epic_interrupt(int irq, void *dev_instance) if ((status & EpicNapiEvent) && !ep->reschedule_in_poll) { spin_lock(&ep->napi_lock); - if (netif_rx_schedule_prep(dev)) { + if (netif_rx_schedule_prep(dev, &ep->napi)) { epic_napi_irq_off(dev, ep); - __netif_rx_schedule(dev); + __netif_rx_schedule(dev, &ep->napi); } else ep->reschedule_in_poll++; spin_unlock(&ep->napi_lock); @@ -1257,26 +1260,22 @@ static void epic_rx_err(struct net_device *dev, struct epic_private *ep) outw(RxQueued, ioaddr + COMMAND); } -static int epic_poll(struct net_device *dev, int *budget) +static int epic_poll(struct napi_struct *napi, int budget) { - struct epic_private *ep = dev->priv; - int work_done = 0, orig_budget; + struct epic_private *ep = container_of(napi, struct epic_private, napi); + struct net_device *dev = ep->mii.dev; + int work_done = 0; long ioaddr = dev->base_addr; - orig_budget = (*budget > dev->quota) ? dev->quota : *budget; - rx_action: epic_tx(dev, ep); - work_done += epic_rx(dev, *budget); + work_done += epic_rx(dev, budget); epic_rx_err(dev, ep); - *budget -= work_done; - dev->quota -= work_done; - - if (netif_running(dev) && (work_done < orig_budget)) { + if (netif_running(dev) && (work_done < budget)) { unsigned long flags; int more; @@ -1286,7 +1285,7 @@ rx_action: more = ep->reschedule_in_poll; if (!more) { - __netif_rx_complete(dev); + __netif_rx_complete(dev, napi); outl(EpicNapiEvent, ioaddr + INTSTAT); epic_napi_irq_on(dev, ep); } else @@ -1298,7 +1297,7 @@ rx_action: goto rx_action; } - return (work_done >= orig_budget); + return work_done; } static int epic_close(struct net_device *dev) @@ -1309,6 +1308,7 @@ static int epic_close(struct net_device *dev) int i; netif_stop_queue(dev); + napi_disable(&ep->napi); if (debug > 1) printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n", diff --git a/drivers/net/fec_8xx/fec_8xx.h b/drivers/net/fec_8xx/fec_8xx.h index 5af60b0f920..f3b1c6fbba8 100644 --- a/drivers/net/fec_8xx/fec_8xx.h +++ b/drivers/net/fec_8xx/fec_8xx.h @@ -105,6 +105,8 @@ struct fec; struct fec_enet_private { spinlock_t lock; /* during all ops except TX pckt processing */ spinlock_t tx_lock; /* during fec_start_xmit and fec_tx */ + struct net_device *dev; + struct napi_struct napi; int fecno; struct fec *fecp; const struct fec_platform_info *fpi; diff --git a/drivers/net/fec_8xx/fec_main.c b/drivers/net/fec_8xx/fec_main.c index e5502af5b8e..6348fb93ca9 100644 --- a/drivers/net/fec_8xx/fec_main.c +++ b/drivers/net/fec_8xx/fec_main.c @@ -465,9 +465,9 @@ void fec_stop(struct net_device *dev) } /* common receive function */ -static int fec_enet_rx_common(struct net_device *dev, int *budget) +static int fec_enet_rx_common(struct fec_enet_private *ep, + struct net_device *dev, int budget) { - struct fec_enet_private *fep = netdev_priv(dev); fec_t *fecp = fep->fecp; const struct fec_platform_info *fpi = fep->fpi; cbd_t *bdp; @@ -475,11 +475,8 @@ static int fec_enet_rx_common(struct net_device *dev, int *budget) int received = 0; __u16 pkt_len, sc; int curidx; - int rx_work_limit; if (fpi->use_napi) { - rx_work_limit = min(dev->quota, *budget); - if (!netif_running(dev)) return 0; } @@ -530,11 +527,6 @@ static int fec_enet_rx_common(struct net_device *dev, int *budget) BUG_ON(skbn == NULL); } else { - - /* napi, got packet but no quota */ - if (fpi->use_napi && --rx_work_limit < 0) - break; - skb = fep->rx_skbuff[curidx]; BUG_ON(skb == NULL); @@ -599,25 +591,24 @@ static int fec_enet_rx_common(struct net_device *dev, int *budget) * able to keep up at the expense of system resources. */ FW(fecp, r_des_active, 0x01000000); + + if (received >= budget) + break; + } fep->cur_rx = bdp; if (fpi->use_napi) { - dev->quota -= received; - *budget -= received; - - if (rx_work_limit < 0) - return 1; /* not done */ + if (received < budget) { + netif_rx_complete(dev, &fep->napi); - /* done */ - netif_rx_complete(dev); - - /* enable RX interrupt bits */ - FS(fecp, imask, FEC_ENET_RXF | FEC_ENET_RXB); + /* enable RX interrupt bits */ + FS(fecp, imask, FEC_ENET_RXF | FEC_ENET_RXB); + } } - return 0; + return received; } static void fec_enet_tx(struct net_device *dev) @@ -743,12 +734,12 @@ fec_enet_interrupt(int irq, void *dev_id) if ((int_events & FEC_ENET_RXF) != 0) { if (!fpi->use_napi) - fec_enet_rx_common(dev, NULL); + fec_enet_rx_common(fep, dev, ~0); else { - if (netif_rx_schedule_prep(dev)) { + if (netif_rx_schedule_prep(dev, &fep->napi)) { /* disable rx interrupts */ FC(fecp, imask, FEC_ENET_RXF | FEC_ENET_RXB); - __netif_rx_schedule(dev); + __netif_rx_schedule(dev, &fep->napi); } else { printk(KERN_ERR DRV_MODULE_NAME ": %s driver bug! interrupt while in poll!\n", @@ -893,10 +884,13 @@ static int fec_enet_open(struct net_device *dev) const struct fec_platform_info *fpi = fep->fpi; unsigned long flags; + napi_enable(&fep->napi); + /* Install our interrupt handler. */ if (request_irq(fpi->fec_irq, fec_enet_interrupt, 0, "fec", dev) != 0) { printk(KERN_ERR DRV_MODULE_NAME ": %s Could not allocate FEC IRQ!", dev->name); + napi_disable(&fep->napi); return -EINVAL; } @@ -907,6 +901,7 @@ static int fec_enet_open(struct net_device *dev) printk(KERN_ERR DRV_MODULE_NAME ": %s Could not allocate PHY IRQ!", dev->name); free_irq(fpi->fec_irq, dev); + napi_disable(&fep->napi); return -EINVAL; } @@ -932,6 +927,7 @@ static int fec_enet_close(struct net_device *dev) unsigned long flags; netif_stop_queue(dev); + napi_disable(&fep->napi); netif_carrier_off(dev); if (fpi->use_mdio) @@ -955,9 +951,12 @@ static struct net_device_stats *fec_enet_get_stats(struct net_device *dev) return &fep->stats; } -static int fec_enet_poll(struct net_device *dev, int *budget) +static int fec_enet_poll(struct napi_struct *napi, int budget) { - return fec_enet_rx_common(dev, budget); + struct fec_enet_private *fep = container_of(napi, struct fec_enet_private, napi); + struct net_device *dev = fep->dev; + + return fec_enet_rx_common(fep, dev, budget); } /*************************************************************************/ @@ -1107,6 +1106,7 @@ int fec_8xx_init_one(const struct fec_platform_info *fpi, SET_MODULE_OWNER(dev); fep = netdev_priv(dev); + fep->dev = dev; /* partial reset of FEC */ fec_whack_reset(fecp); @@ -1172,10 +1172,9 @@ int fec_8xx_init_one(const struct fec_platform_info *fpi, dev->get_stats = fec_enet_get_stats; dev->set_multicast_list = fec_set_multicast_list; dev->set_mac_address = fec_set_mac_address; - if (fpi->use_napi) { - dev->poll = fec_enet_poll; - dev->weight = fpi->napi_weight; - } + netif_napi_add(dev, &fec->napi, + fec_enet_poll, fpi->napi_weight); + dev->ethtool_ops = &fec_ethtool_ops; dev->do_ioctl = fec_ioctl; diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 1938d6dfc86..24c1294614f 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -159,6 +159,8 @@ #define dprintk(x...) do { } while (0) #endif +#define TX_WORK_PER_LOOP 64 +#define RX_WORK_PER_LOOP 64 /* * Hardware access: @@ -745,6 +747,9 @@ struct nv_skb_map { struct fe_priv { spinlock_t lock; + struct net_device *dev; + struct napi_struct napi; + /* General data: * Locking: spin_lock(&np->lock); */ struct net_device_stats stats; @@ -1586,9 +1591,10 @@ static int nv_alloc_rx_optimized(struct net_device *dev) static void nv_do_rx_refill(unsigned long data) { struct net_device *dev = (struct net_device *) data; + struct fe_priv *np = netdev_priv(dev); /* Just reschedule NAPI rx processing */ - netif_rx_schedule(dev); + netif_rx_schedule(dev, &np->napi); } #else static void nv_do_rx_refill(unsigned long data) @@ -2997,7 +3003,7 @@ static irqreturn_t nv_nic_irq(int foo, void *data) #ifdef CONFIG_FORCEDETH_NAPI if (events & NVREG_IRQ_RX_ALL) { - netif_rx_schedule(dev); + netif_rx_schedule(dev, &np->napi); /* Disable furthur receive irq's */ spin_lock(&np->lock); @@ -3010,7 +3016,7 @@ static irqreturn_t nv_nic_irq(int foo, void *data) spin_unlock(&np->lock); } #else - if (nv_rx_process(dev, dev->weight)) { + if (nv_rx_process(dev, RX_WORK_PER_LOOP)) { if (unlikely(nv_alloc_rx(dev))) { spin_lock(&np->lock); if (!np->in_shutdown) @@ -3079,8 +3085,6 @@ static irqreturn_t nv_nic_irq(int foo, void *data) return IRQ_RETVAL(i); } -#define TX_WORK_PER_LOOP 64 -#define RX_WORK_PER_LOOP 64 /** * All _optimized functions are used to help increase performance * (reduce CPU and increase throughput). They use descripter version 3, @@ -3114,7 +3118,7 @@ static irqreturn_t nv_nic_irq_optimized(int foo, void *data) #ifdef CONFIG_FORCEDETH_NAPI if (events & NVREG_IRQ_RX_ALL) { - netif_rx_schedule(dev); + netif_rx_schedule(dev, &np->napi); /* Disable furthur receive irq's */ spin_lock(&np->lock); @@ -3127,7 +3131,7 @@ static irqreturn_t nv_nic_irq_optimized(int foo, void *data) spin_unlock(&np->lock); } #else - if (nv_rx_process_optimized(dev, dev->weight)) { + if (nv_rx_process_optimized(dev, RX_WORK_PER_LOOP)) { if (unlikely(nv_alloc_rx_optimized(dev))) { spin_lock(&np->lock); if (!np->in_shutdown) @@ -3245,19 +3249,19 @@ static irqreturn_t nv_nic_irq_tx(int foo, void *data) } #ifdef CONFIG_FORCEDETH_NAPI -static int nv_napi_poll(struct net_device *dev, int *budget) +static int nv_napi_poll(struct napi_struct *napi, int budget) { - int pkts, limit = min(*budget, dev->quota); - struct fe_priv *np = netdev_priv(dev); + struct fe_priv *np = container_of(napi, struct fe_priv, napi); + struct net_device *dev = np->dev; u8 __iomem *base = get_hwbase(dev); unsigned long flags; - int retcode; + int pkts, retcode; if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { - pkts = nv_rx_process(dev, limit); + pkts = nv_rx_process(dev, budget); retcode = nv_alloc_rx(dev); } else { - pkts = nv_rx_process_optimized(dev, limit); + pkts = nv_rx_process_optimized(dev, budget); retcode = nv_alloc_rx_optimized(dev); } @@ -3268,13 +3272,12 @@ static int nv_napi_poll(struct net_device *dev, int *budget) spin_unlock_irqrestore(&np->lock, flags); } - if (pkts < limit) { - /* all done, no more packets present */ - netif_rx_complete(dev); - + if (pkts < budget) { /* re-enable receive interrupts */ spin_lock_irqsave(&np->lock, flags); + __netif_rx_complete(dev, napi); + np->irqmask |= NVREG_IRQ_RX_ALL; if (np->msi_flags & NV_MSI_X_ENABLED) writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask); @@ -3282,13 +3285,8 @@ static int nv_napi_poll(struct net_device *dev, int *budget) writel(np->irqmask, base + NvRegIrqMask); spin_unlock_irqrestore(&np->lock, flags); - return 0; - } else { - /* used up our quantum, so reschedule */ - dev->quota -= pkts; - *budget -= pkts; - return 1; } + return pkts; } #endif @@ -3296,6 +3294,7 @@ static int nv_napi_poll(struct net_device *dev, int *budget) static irqreturn_t nv_nic_irq_rx(int foo, void *data) { struct net_device *dev = (struct net_device *) data; + struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); u32 events; @@ -3303,7 +3302,7 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data) writel(NVREG_IRQ_RX_ALL, base + NvRegMSIXIrqStatus); if (events) { - netif_rx_schedule(dev); + netif_rx_schedule(dev, &np->napi); /* disable receive interrupts on the nic */ writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask); pci_push(base); @@ -3329,7 +3328,7 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data) if (!(events & np->irqmask)) break; - if (nv_rx_process_optimized(dev, dev->weight)) { + if (nv_rx_process_optimized(dev, RX_WORK_PER_LOOP)) { if (unlikely(nv_alloc_rx_optimized(dev))) { spin_lock_irqsave(&np->lock, flags); if (!np->in_shutdown) @@ -4620,7 +4619,9 @@ static void nv_self_test(struct net_device *dev, struct ethtool_test *test, u64 if (test->flags & ETH_TEST_FL_OFFLINE) { if (netif_running(dev)) { netif_stop_queue(dev); - netif_poll_disable(dev); +#ifdef CONFIG_FORCEDETH_NAPI + napi_disable(&np->napi); +#endif netif_tx_lock_bh(dev); spin_lock_irq(&np->lock); nv_disable_hw_interrupts(dev, np->irqmask); @@ -4679,7 +4680,9 @@ static void nv_self_test(struct net_device *dev, struct ethtool_test *test, u64 nv_start_rx(dev); nv_start_tx(dev); netif_start_queue(dev); - netif_poll_enable(dev); +#ifdef CONFIG_FORCEDETH_NAPI + napi_enable(&np->napi); +#endif nv_enable_hw_interrupts(dev, np->irqmask); } } @@ -4911,7 +4914,9 @@ static int nv_open(struct net_device *dev) nv_start_rx(dev); nv_start_tx(dev); netif_start_queue(dev); - netif_poll_enable(dev); +#ifdef CONFIG_FORCEDETH_NAPI + napi_enable(&np->napi); +#endif if (ret) { netif_carrier_on(dev); @@ -4942,7 +4947,9 @@ static int nv_close(struct net_device *dev) spin_lock_irq(&np->lock); np->in_shutdown = 1; spin_unlock_irq(&np->lock); - netif_poll_disable(dev); +#ifdef CONFIG_FORCEDETH_NAPI + napi_disable(&np->napi); +#endif synchronize_irq(dev->irq); del_timer_sync(&np->oom_kick); @@ -4994,6 +5001,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i goto out; np = netdev_priv(dev); + np->dev = dev; np->pci_dev = pci_dev; spin_lock_init(&np->lock); SET_MODULE_OWNER(dev); @@ -5155,9 +5163,8 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = nv_poll_controller; #endif - dev->weight = RX_WORK_PER_LOOP; #ifdef CONFIG_FORCEDETH_NAPI - dev->poll = nv_napi_poll; + netif_napi_add(dev, &np->napi, nv_napi_poll, RX_WORK_PER_LOOP); #endif SET_ETHTOOL_OPS(dev, &ops); dev->tx_timeout = nv_tx_timeout; diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index a4a2a0ea43d..c509cb13222 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -70,18 +70,16 @@ static void fs_set_multicast_list(struct net_device *dev) } /* NAPI receive function */ -static int fs_enet_rx_napi(struct net_device *dev, int *budget) +static int fs_enet_rx_napi(struct napi_struct *napi, int budget) { - struct fs_enet_private *fep = netdev_priv(dev); + struct fs_enet_private *fep = container_of(napi, struct fs_enet_private, napi); + struct net_device *dev = to_net_dev(fep->dev); const struct fs_platform_info *fpi = fep->fpi; cbd_t *bdp; struct sk_buff *skb, *skbn, *skbt; int received = 0; u16 pkt_len, sc; int curidx; - int rx_work_limit = 0; /* pacify gcc */ - - rx_work_limit = min(dev->quota, *budget); if (!netif_running(dev)) return 0; @@ -96,7 +94,6 @@ static int fs_enet_rx_napi(struct net_device *dev, int *budget) (*fep->ops->napi_clear_rx_event)(dev); while (((sc = CBDR_SC(bdp)) & BD_ENET_RX_EMPTY) == 0) { - curidx = bdp - fep->rx_bd_base; /* @@ -136,11 +133,6 @@ static int fs_enet_rx_napi(struct net_device *dev, int *budget) skbn = skb; } else { - - /* napi, got packet but no quota */ - if (--rx_work_limit < 0) - break; - skb = fep->rx_skbuff[curidx]; dma_unmap_single(fep->dev, CBDR_BUFADDR(bdp), @@ -199,22 +191,19 @@ static int fs_enet_rx_napi(struct net_device *dev, int *budget) bdp = fep->rx_bd_base; (*fep->ops->rx_bd_done)(dev); + + if (received >= budget) + break; } fep->cur_rx = bdp; - dev->quota -= received; - *budget -= received; - - if (rx_work_limit < 0) - return 1; /* not done */ - - /* done */ - netif_rx_complete(dev); - - (*fep->ops->napi_enable_rx)(dev); - - return 0; + if (received >= budget) { + /* done */ + netif_rx_complete(dev, napi); + (*fep->ops->napi_enable_rx)(dev); + } + return received; } /* non NAPI receive function */ @@ -470,7 +459,7 @@ fs_enet_interrupt(int irq, void *dev_id) if (!fpi->use_napi) fs_enet_rx_non_napi(dev); else { - napi_ok = netif_rx_schedule_prep(dev); + napi_ok = napi_schedule_prep(&fep->napi); (*fep->ops->napi_disable_rx)(dev); (*fep->ops->clear_int_events)(dev, fep->ev_napi_rx); @@ -478,7 +467,7 @@ fs_enet_interrupt(int irq, void *dev_id) /* NOTE: it is possible for FCCs in NAPI mode */ /* to submit a spurious interrupt while in poll */ if (napi_ok) - __netif_rx_schedule(dev); + __netif_rx_schedule(dev, &fep->napi); } } @@ -799,18 +788,22 @@ static int fs_enet_open(struct net_device *dev) int r; int err; + napi_enable(&fep->napi); + /* Install our interrupt handler. */ r = fs_request_irq(dev, fep->interrupt, "fs_enet-mac", fs_enet_interrupt); if (r != 0) { printk(KERN_ERR DRV_MODULE_NAME ": %s Could not allocate FS_ENET IRQ!", dev->name); + napi_disable(&fep->napi); return -EINVAL; } err = fs_init_phy(dev); - if(err) + if(err) { + napi_disable(&fep->napi); return err; - + } phy_start(fep->phydev); return 0; @@ -823,6 +816,7 @@ static int fs_enet_close(struct net_device *dev) netif_stop_queue(dev); netif_carrier_off(dev); + napi_disable(&fep->napi); phy_stop(fep->phydev); spin_lock_irqsave(&fep->lock, flags); @@ -1047,10 +1041,9 @@ static struct net_device *fs_init_instance(struct device *dev, ndev->stop = fs_enet_close; ndev->get_stats = fs_enet_get_stats; ndev->set_multicast_list = fs_set_multicast_list; - if (fpi->use_napi) { - ndev->poll = fs_enet_rx_napi; - ndev->weight = fpi->napi_weight; - } + netif_napi_add(ndev, &fep->napi, + fs_enet_rx_napi, fpi->napi_weight); + ndev->ethtool_ops = &fs_ethtool_ops; ndev->do_ioctl = fs_ioctl; diff --git a/drivers/net/fs_enet/fs_enet.h b/drivers/net/fs_enet/fs_enet.h index 569be225cd0..46d0606b143 100644 --- a/drivers/net/fs_enet/fs_enet.h +++ b/drivers/net/fs_enet/fs_enet.h @@ -121,6 +121,7 @@ struct fs_enet_mii_bus { }; struct fs_enet_private { + struct napi_struct napi; struct device *dev; /* pointer back to the device (must be initialized first) */ spinlock_t lock; /* during all ops except TX pckt processing */ spinlock_t tx_lock; /* during fs_start_xmit and fs_tx */ diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index f92690555dd..bd2de325bbd 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -134,7 +134,7 @@ static void gfar_configure_serdes(struct net_device *dev); extern int gfar_local_mdio_write(struct gfar_mii *regs, int mii_id, int regnum, u16 value); extern int gfar_local_mdio_read(struct gfar_mii *regs, int mii_id, int regnum); #ifdef CONFIG_GFAR_NAPI -static int gfar_poll(struct net_device *dev, int *budget); +static int gfar_poll(struct napi_struct *napi, int budget); #endif #ifdef CONFIG_NET_POLL_CONTROLLER static void gfar_netpoll(struct net_device *dev); @@ -188,6 +188,7 @@ static int gfar_probe(struct platform_device *pdev) return -ENOMEM; priv = netdev_priv(dev); + priv->dev = dev; /* Set the info in the priv to the current info */ priv->einfo = einfo; @@ -261,10 +262,7 @@ static int gfar_probe(struct platform_device *pdev) dev->hard_start_xmit = gfar_start_xmit; dev->tx_timeout = gfar_timeout; dev->watchdog_timeo = TX_TIMEOUT; -#ifdef CONFIG_GFAR_NAPI - dev->poll = gfar_poll; - dev->weight = GFAR_DEV_WEIGHT; -#endif + netif_napi_add(dev, &priv->napi, gfar_poll, GFAR_DEV_WEIGHT); #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = gfar_netpoll; #endif @@ -939,6 +937,8 @@ static int gfar_enet_open(struct net_device *dev) { int err; + napi_enable(&priv->napi); + /* Initialize a bunch of registers */ init_registers(dev); @@ -946,10 +946,14 @@ static int gfar_enet_open(struct net_device *dev) err = init_phy(dev); - if(err) + if(err) { + napi_disable(&priv->napi); return err; + } err = startup_gfar(dev); + if (err) + napi_disable(&priv->napi); netif_start_queue(dev); @@ -1102,6 +1106,9 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) static int gfar_close(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); + + napi_disable(&priv->napi); + stop_gfar(dev); /* Disconnect from the PHY */ @@ -1318,7 +1325,7 @@ struct sk_buff * gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp) return NULL; alignamount = RXBUF_ALIGNMENT - - (((unsigned) skb->data) & (RXBUF_ALIGNMENT - 1)); + (((unsigned long) skb->data) & (RXBUF_ALIGNMENT - 1)); /* We need the data buffer to be aligned properly. We will reserve * as many bytes as needed to align the data properly @@ -1390,12 +1397,12 @@ irqreturn_t gfar_receive(int irq, void *dev_id) /* support NAPI */ #ifdef CONFIG_GFAR_NAPI - if (netif_rx_schedule_prep(dev)) { + if (netif_rx_schedule_prep(dev, &priv->napi)) { tempval = gfar_read(&priv->regs->imask); tempval &= IMASK_RX_DISABLED; gfar_write(&priv->regs->imask, tempval); - __netif_rx_schedule(dev); + __netif_rx_schedule(dev, &priv->napi); } else { if (netif_msg_rx_err(priv)) printk(KERN_DEBUG "%s: receive called twice (%x)[%x]\n", @@ -1569,23 +1576,16 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit) } #ifdef CONFIG_GFAR_NAPI -static int gfar_poll(struct net_device *dev, int *budget) +static int gfar_poll(struct napi_struct *napi, int budget) { + struct gfar_private *priv = container_of(napi, struct gfar_private, napi); + struct net_device *dev = priv->dev; int howmany; - struct gfar_private *priv = netdev_priv(dev); - int rx_work_limit = *budget; - - if (rx_work_limit > dev->quota) - rx_work_limit = dev->quota; - howmany = gfar_clean_rx_ring(dev, rx_work_limit); + howmany = gfar_clean_rx_ring(dev, budget); - dev->quota -= howmany; - rx_work_limit -= howmany; - *budget -= howmany; - - if (rx_work_limit > 0) { - netif_rx_complete(dev); + if (howmany < budget) { + netif_rx_complete(dev, napi); /* Clear the halt bit in RSTAT */ gfar_write(&priv->regs->rstat, RSTAT_CLEAR_RHALT); @@ -1601,8 +1601,7 @@ static int gfar_poll(struct net_device *dev, int *budget) gfar_write(&priv->regs->rxic, 0); } - /* Return 1 if there's more work to do */ - return (rx_work_limit > 0) ? 0 : 1; + return howmany; } #endif diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h index d8e779c102f..b8714e00482 100644 --- a/drivers/net/gianfar.h +++ b/drivers/net/gianfar.h @@ -691,6 +691,9 @@ struct gfar_private { /* RX Locked fields */ spinlock_t rxlock; + struct net_device *dev; + struct napi_struct napi; + /* skb array and index */ struct sk_buff ** rx_skbuff; u16 skb_currx; diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index acba90f1638..78e28ada1e2 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -83,7 +83,7 @@ static int ibmveth_open(struct net_device *dev); static int ibmveth_close(struct net_device *dev); static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); -static int ibmveth_poll(struct net_device *dev, int *budget); +static int ibmveth_poll(struct napi_struct *napi, int budget); static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *dev); static struct net_device_stats *ibmveth_get_stats(struct net_device *dev); static void ibmveth_set_multicast_list(struct net_device *dev); @@ -480,6 +480,8 @@ static int ibmveth_open(struct net_device *netdev) ibmveth_debug_printk("open starting\n"); + napi_enable(&adapter->napi); + for(i = 0; irx_buff_pool[i].size; @@ -489,6 +491,7 @@ static int ibmveth_open(struct net_device *netdev) if(!adapter->buffer_list_addr || !adapter->filter_list_addr) { ibmveth_error_printk("unable to allocate filter or buffer list pages\n"); ibmveth_cleanup(adapter); + napi_disable(&adapter->napi); return -ENOMEM; } @@ -498,6 +501,7 @@ static int ibmveth_open(struct net_device *netdev) if(!adapter->rx_queue.queue_addr) { ibmveth_error_printk("unable to allocate rx queue pages\n"); ibmveth_cleanup(adapter); + napi_disable(&adapter->napi); return -ENOMEM; } @@ -514,6 +518,7 @@ static int ibmveth_open(struct net_device *netdev) (dma_mapping_error(adapter->rx_queue.queue_dma))) { ibmveth_error_printk("unable to map filter or buffer list pages\n"); ibmveth_cleanup(adapter); + napi_disable(&adapter->napi); return -ENOMEM; } @@ -545,6 +550,7 @@ static int ibmveth_open(struct net_device *netdev) rxq_desc.desc, mac_address); ibmveth_cleanup(adapter); + napi_disable(&adapter->napi); return -ENONET; } @@ -555,6 +561,7 @@ static int ibmveth_open(struct net_device *netdev) ibmveth_error_printk("unable to alloc pool\n"); adapter->rx_buff_pool[i].active = 0; ibmveth_cleanup(adapter); + napi_disable(&adapter->napi); return -ENOMEM ; } } @@ -567,6 +574,7 @@ static int ibmveth_open(struct net_device *netdev) } while (H_IS_LONG_BUSY(rc) || (rc == H_BUSY)); ibmveth_cleanup(adapter); + napi_disable(&adapter->napi); return rc; } @@ -587,6 +595,8 @@ static int ibmveth_close(struct net_device *netdev) ibmveth_debug_printk("close starting\n"); + napi_disable(&adapter->napi); + if (!adapter->pool_config) netif_stop_queue(netdev); @@ -767,80 +777,68 @@ out: spin_lock_irqsave(&adapter->stats_lock, flags); return 0; } -static int ibmveth_poll(struct net_device *netdev, int *budget) +static int ibmveth_poll(struct napi_struct *napi, int budget) { - struct ibmveth_adapter *adapter = netdev->priv; - int max_frames_to_process = netdev->quota; + struct ibmveth_adapter *adapter = container_of(napi, struct ibmveth_adapter, napi); + struct net_device *netdev = adapter->netdev; int frames_processed = 0; - int more_work = 1; unsigned long lpar_rc; restart_poll: do { - struct net_device *netdev = adapter->netdev; - - if(ibmveth_rxq_pending_buffer(adapter)) { - struct sk_buff *skb; + struct sk_buff *skb; - rmb(); + if (!ibmveth_rxq_pending_buffer(adapter)) + break; - if(!ibmveth_rxq_buffer_valid(adapter)) { - wmb(); /* suggested by larson1 */ - adapter->rx_invalid_buffer++; - ibmveth_debug_printk("recycling invalid buffer\n"); - ibmveth_rxq_recycle_buffer(adapter); - } else { - int length = ibmveth_rxq_frame_length(adapter); - int offset = ibmveth_rxq_frame_offset(adapter); - skb = ibmveth_rxq_get_buffer(adapter); + rmb(); + if (!ibmveth_rxq_buffer_valid(adapter)) { + wmb(); /* suggested by larson1 */ + adapter->rx_invalid_buffer++; + ibmveth_debug_printk("recycling invalid buffer\n"); + ibmveth_rxq_recycle_buffer(adapter); + } else { + int length = ibmveth_rxq_frame_length(adapter); + int offset = ibmveth_rxq_frame_offset(adapter); + skb = ibmveth_rxq_get_buffer(adapter); - ibmveth_rxq_harvest_buffer(adapter); + ibmveth_rxq_harvest_buffer(adapter); - skb_reserve(skb, offset); - skb_put(skb, length); - skb->protocol = eth_type_trans(skb, netdev); + skb_reserve(skb, offset); + skb_put(skb, length); + skb->protocol = eth_type_trans(skb, netdev); - netif_receive_skb(skb); /* send it up */ + netif_receive_skb(skb); /* send it up */ - adapter->stats.rx_packets++; - adapter->stats.rx_bytes += length; - frames_processed++; - netdev->last_rx = jiffies; - } - } else { - more_work = 0; + adapter->stats.rx_packets++; + adapter->stats.rx_bytes += length; + frames_processed++; + netdev->last_rx = jiffies; } - } while(more_work && (frames_processed < max_frames_to_process)); + } while (frames_processed < budget); ibmveth_replenish_task(adapter); - if(more_work) { - /* more work to do - return that we are not done yet */ - netdev->quota -= frames_processed; - *budget -= frames_processed; - return 1; - } - - /* we think we are done - reenable interrupts, then check once more to make sure we are done */ - lpar_rc = h_vio_signal(adapter->vdev->unit_address, VIO_IRQ_ENABLE); + if (frames_processed < budget) { + /* We think we are done - reenable interrupts, + * then check once more to make sure we are done. + */ + lpar_rc = h_vio_signal(adapter->vdev->unit_address, + VIO_IRQ_ENABLE); - ibmveth_assert(lpar_rc == H_SUCCESS); + ibmveth_assert(lpar_rc == H_SUCCESS); - netif_rx_complete(netdev); + netif_rx_complete(netdev, napi); - if(ibmveth_rxq_pending_buffer(adapter) && netif_rx_reschedule(netdev, frames_processed)) - { - lpar_rc = h_vio_signal(adapter->vdev->unit_address, VIO_IRQ_DISABLE); - ibmveth_assert(lpar_rc == H_SUCCESS); - more_work = 1; - goto restart_poll; + if (ibmveth_rxq_pending_buffer(adapter) && + netif_rx_reschedule(netdev, napi)) { + lpar_rc = h_vio_signal(adapter->vdev->unit_address, + VIO_IRQ_DISABLE); + goto restart_poll; + } } - netdev->quota -= frames_processed; - *budget -= frames_processed; - - /* we really are done */ - return 0; + return frames_processed; } static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance) @@ -849,10 +847,11 @@ static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance) struct ibmveth_adapter *adapter = netdev->priv; unsigned long lpar_rc; - if(netif_rx_schedule_prep(netdev)) { - lpar_rc = h_vio_signal(adapter->vdev->unit_address, VIO_IRQ_DISABLE); + if (netif_rx_schedule_prep(netdev, &adapter->napi)) { + lpar_rc = h_vio_signal(adapter->vdev->unit_address, + VIO_IRQ_DISABLE); ibmveth_assert(lpar_rc == H_SUCCESS); - __netif_rx_schedule(netdev); + __netif_rx_schedule(netdev, &adapter->napi); } return IRQ_HANDLED; } @@ -1004,6 +1003,8 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ adapter->mcastFilterSize= *mcastFilterSize_p; adapter->pool_config = 0; + netif_napi_add(netdev, &adapter->napi, ibmveth_poll, 16); + /* Some older boxes running PHYP non-natively have an OF that returns a 8-byte local-mac-address field (and the first 2 bytes have to be ignored) while newer boxes' OF return @@ -1020,8 +1021,6 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ netdev->irq = dev->irq; netdev->open = ibmveth_open; - netdev->poll = ibmveth_poll; - netdev->weight = 16; netdev->stop = ibmveth_close; netdev->hard_start_xmit = ibmveth_start_xmit; netdev->get_stats = ibmveth_get_stats; diff --git a/drivers/net/ibmveth.h b/drivers/net/ibmveth.h index 72cc15a6cab..e05694126f8 100644 --- a/drivers/net/ibmveth.h +++ b/drivers/net/ibmveth.h @@ -112,6 +112,7 @@ struct ibmveth_rx_q { struct ibmveth_adapter { struct vio_dev *vdev; struct net_device *netdev; + struct napi_struct napi; struct net_device_stats stats; unsigned int mcastFilterSize; unsigned long mac_addr; diff --git a/drivers/net/ixgb/ixgb.h b/drivers/net/ixgb/ixgb.h index 3569d5b0338..1eee8894c73 100644 --- a/drivers/net/ixgb/ixgb.h +++ b/drivers/net/ixgb/ixgb.h @@ -184,6 +184,7 @@ struct ixgb_adapter { boolean_t rx_csum; /* OS defined structs */ + struct napi_struct napi; struct net_device *netdev; struct pci_dev *pdev; struct net_device_stats net_stats; diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index 991c8833e23..e3f27c67fb2 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -97,7 +97,7 @@ static irqreturn_t ixgb_intr(int irq, void *data); static boolean_t ixgb_clean_tx_irq(struct ixgb_adapter *adapter); #ifdef CONFIG_IXGB_NAPI -static int ixgb_clean(struct net_device *netdev, int *budget); +static int ixgb_clean(struct napi_struct *napi, int budget); static boolean_t ixgb_clean_rx_irq(struct ixgb_adapter *adapter, int *work_done, int work_to_do); #else @@ -288,7 +288,7 @@ ixgb_up(struct ixgb_adapter *adapter) mod_timer(&adapter->watchdog_timer, jiffies); #ifdef CONFIG_IXGB_NAPI - netif_poll_enable(netdev); + napi_enable(&adapter->napi); #endif ixgb_irq_enable(adapter); @@ -309,7 +309,7 @@ ixgb_down(struct ixgb_adapter *adapter, boolean_t kill_watchdog) if(kill_watchdog) del_timer_sync(&adapter->watchdog_timer); #ifdef CONFIG_IXGB_NAPI - netif_poll_disable(netdev); + napi_disable(&adapter->napi); #endif adapter->link_speed = 0; adapter->link_duplex = 0; @@ -421,8 +421,7 @@ ixgb_probe(struct pci_dev *pdev, netdev->tx_timeout = &ixgb_tx_timeout; netdev->watchdog_timeo = 5 * HZ; #ifdef CONFIG_IXGB_NAPI - netdev->poll = &ixgb_clean; - netdev->weight = 64; + netif_napi_add(netdev, &adapter->napi, ixgb_clean, 64); #endif netdev->vlan_rx_register = ixgb_vlan_rx_register; netdev->vlan_rx_add_vid = ixgb_vlan_rx_add_vid; @@ -1746,7 +1745,7 @@ ixgb_intr(int irq, void *data) } #ifdef CONFIG_IXGB_NAPI - if(netif_rx_schedule_prep(netdev)) { + if (netif_rx_schedule_prep(netdev, &adapter->napi)) { /* Disable interrupts and register for poll. The flush of the posted write is intentionally left out. @@ -1754,7 +1753,7 @@ ixgb_intr(int irq, void *data) atomic_inc(&adapter->irq_sem); IXGB_WRITE_REG(&adapter->hw, IMC, ~0); - __netif_rx_schedule(netdev); + __netif_rx_schedule(netdev, &adapter->napi); } #else /* yes, that is actually a & and it is meant to make sure that @@ -1776,27 +1775,23 @@ ixgb_intr(int irq, void *data) **/ static int -ixgb_clean(struct net_device *netdev, int *budget) +ixgb_clean(struct napi_struct *napi, int budget) { - struct ixgb_adapter *adapter = netdev_priv(netdev); - int work_to_do = min(*budget, netdev->quota); + struct ixgb_adapter *adapter = container_of(napi, struct ixgb_adapter, napi); + struct net_device *netdev = adapter->netdev; int tx_cleaned; int work_done = 0; tx_cleaned = ixgb_clean_tx_irq(adapter); - ixgb_clean_rx_irq(adapter, &work_done, work_to_do); - - *budget -= work_done; - netdev->quota -= work_done; + ixgb_clean_rx_irq(adapter, &work_done, budget); /* if no Tx and not enough Rx work done, exit the polling mode */ if((!tx_cleaned && (work_done == 0)) || !netif_running(netdev)) { - netif_rx_complete(netdev); + netif_rx_complete(netdev, napi); ixgb_irq_enable(adapter); - return 0; } - return 1; + return work_done; } #endif diff --git a/drivers/net/ixp2000/ixpdev.c b/drivers/net/ixp2000/ixpdev.c index d9ce1aef148..6c0dd49149d 100644 --- a/drivers/net/ixp2000/ixpdev.c +++ b/drivers/net/ixp2000/ixpdev.c @@ -74,9 +74,9 @@ static int ixpdev_xmit(struct sk_buff *skb, struct net_device *dev) } -static int ixpdev_rx(struct net_device *dev, int *budget) +static int ixpdev_rx(struct net_device *dev, int processed, int budget) { - while (*budget > 0) { + while (processed < budget) { struct ixpdev_rx_desc *desc; struct sk_buff *skb; void *buf; @@ -122,29 +122,34 @@ static int ixpdev_rx(struct net_device *dev, int *budget) err: ixp2000_reg_write(RING_RX_PENDING, _desc); - dev->quota--; - (*budget)--; + processed++; } - return 1; + return processed; } /* dev always points to nds[0]. */ -static int ixpdev_poll(struct net_device *dev, int *budget) +static int ixpdev_poll(struct napi_struct *napi, int budget) { + struct ixpdev_priv *ip = container_of(napi, struct ixpdev_priv, napi); + struct net_device *dev = ip->dev; + int rx; + /* @@@ Have to stop polling when nds[0] is administratively * downed while we are polling. */ + rx = 0; do { ixp2000_reg_write(IXP2000_IRQ_THD_RAW_STATUS_A_0, 0x00ff); - if (ixpdev_rx(dev, budget)) - return 1; + rx = ixpdev_rx(dev, rx, budget); + if (rx >= budget) + break; } while (ixp2000_reg_read(IXP2000_IRQ_THD_RAW_STATUS_A_0) & 0x00ff); - netif_rx_complete(dev); + netif_rx_complete(dev, napi); ixp2000_reg_write(IXP2000_IRQ_THD_ENABLE_SET_A_0, 0x00ff); - return 0; + return rx; } static void ixpdev_tx_complete(void) @@ -199,9 +204,12 @@ static irqreturn_t ixpdev_interrupt(int irq, void *dev_id) * Any of the eight receive units signaled RX? */ if (status & 0x00ff) { + struct net_device *dev = nds[0]; + struct ixpdev_priv *ip = netdev_priv(dev); + ixp2000_reg_wrb(IXP2000_IRQ_THD_ENABLE_CLEAR_A_0, 0x00ff); - if (likely(__netif_rx_schedule_prep(nds[0]))) { - __netif_rx_schedule(nds[0]); + if (likely(napi_schedule_prep(&ip->napi))) { + __netif_rx_schedule(dev, &ip->napi); } else { printk(KERN_CRIT "ixp2000: irq while polling!!\n"); } @@ -232,11 +240,13 @@ static int ixpdev_open(struct net_device *dev) struct ixpdev_priv *ip = netdev_priv(dev); int err; + napi_enable(&ip->napi); if (!nds_open++) { err = request_irq(IRQ_IXP2000_THDA0, ixpdev_interrupt, IRQF_SHARED, "ixp2000_eth", nds); if (err) { nds_open--; + napi_disable(&ip->napi); return err; } @@ -254,6 +264,7 @@ static int ixpdev_close(struct net_device *dev) struct ixpdev_priv *ip = netdev_priv(dev); netif_stop_queue(dev); + napi_disable(&ip->napi); set_port_admin_status(ip->channel, 0); if (!--nds_open) { @@ -274,7 +285,6 @@ struct net_device *ixpdev_alloc(int channel, int sizeof_priv) return NULL; dev->hard_start_xmit = ixpdev_xmit; - dev->poll = ixpdev_poll; dev->open = ixpdev_open; dev->stop = ixpdev_close; #ifdef CONFIG_NET_POLL_CONTROLLER @@ -282,9 +292,10 @@ struct net_device *ixpdev_alloc(int channel, int sizeof_priv) #endif dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; - dev->weight = 64; ip = netdev_priv(dev); + ip->dev = dev; + netif_napi_add(dev, &ip->napi, ixpdev_poll, 64); ip->channel = channel; ip->tx_queue_entries = 0; diff --git a/drivers/net/ixp2000/ixpdev.h b/drivers/net/ixp2000/ixpdev.h index bd686cb6305..391ece62324 100644 --- a/drivers/net/ixp2000/ixpdev.h +++ b/drivers/net/ixp2000/ixpdev.h @@ -14,6 +14,8 @@ struct ixpdev_priv { + struct net_device *dev; + struct napi_struct napi; int channel; int tx_queue_entries; }; diff --git a/drivers/net/macb.c b/drivers/net/macb.c index a4bb0264180..74c3f7a7ae4 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -470,47 +470,41 @@ static int macb_rx(struct macb *bp, int budget) return received; } -static int macb_poll(struct net_device *dev, int *budget) +static int macb_poll(struct napi_struct *napi, int budget) { - struct macb *bp = netdev_priv(dev); - int orig_budget, work_done, retval = 0; + struct macb *bp = container_of(napi, struct macb, napi); + struct net_device *dev = bp->dev; + int work_done; u32 status; status = macb_readl(bp, RSR); macb_writel(bp, RSR, status); + work_done = 0; if (!status) { /* * This may happen if an interrupt was pending before * this function was called last time, and no packets * have been received since. */ - netif_rx_complete(dev); + netif_rx_complete(dev, napi); goto out; } dev_dbg(&bp->pdev->dev, "poll: status = %08lx, budget = %d\n", - (unsigned long)status, *budget); + (unsigned long)status, budget); if (!(status & MACB_BIT(REC))) { dev_warn(&bp->pdev->dev, "No RX buffers complete, status = %02lx\n", (unsigned long)status); - netif_rx_complete(dev); + netif_rx_complete(dev, napi); goto out; } - orig_budget = *budget; - if (orig_budget > dev->quota) - orig_budget = dev->quota; - - work_done = macb_rx(bp, orig_budget); - if (work_done < orig_budget) { - netif_rx_complete(dev); - retval = 0; - } else { - retval = 1; - } + work_done = macb_rx(bp, budget); + if (work_done < budget) + netif_rx_complete(dev, napi); /* * We've done what we can to clean the buffers. Make sure we @@ -521,7 +515,7 @@ out: /* TODO: Handle errors */ - return retval; + return work_done; } static irqreturn_t macb_interrupt(int irq, void *dev_id) @@ -545,7 +539,7 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id) } if (status & MACB_RX_INT_FLAGS) { - if (netif_rx_schedule_prep(dev)) { + if (netif_rx_schedule_prep(dev, &bp->napi)) { /* * There's no point taking any more interrupts * until we have processed the buffers @@ -553,7 +547,7 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id) macb_writel(bp, IDR, MACB_RX_INT_FLAGS); dev_dbg(&bp->pdev->dev, "scheduling RX softirq\n"); - __netif_rx_schedule(dev); + __netif_rx_schedule(dev, &bp->napi); } } @@ -937,6 +931,8 @@ static int macb_open(struct net_device *dev) return err; } + napi_enable(&bp->napi); + macb_init_rings(bp); macb_init_hw(bp); @@ -954,6 +950,7 @@ static int macb_close(struct net_device *dev) unsigned long flags; netif_stop_queue(dev); + napi_disable(&bp->napi); if (bp->phy_dev) phy_stop(bp->phy_dev); @@ -1146,8 +1143,7 @@ static int __devinit macb_probe(struct platform_device *pdev) dev->get_stats = macb_get_stats; dev->set_multicast_list = macb_set_rx_mode; dev->do_ioctl = macb_ioctl; - dev->poll = macb_poll; - dev->weight = 64; + netif_napi_add(dev, &bp->napi, macb_poll, 64); dev->ethtool_ops = &macb_ethtool_ops; dev->base_addr = regs->start; diff --git a/drivers/net/macb.h b/drivers/net/macb.h index 4e3283ebd97..57b85acf0d1 100644 --- a/drivers/net/macb.h +++ b/drivers/net/macb.h @@ -374,6 +374,7 @@ struct macb { struct clk *pclk; struct clk *hclk; struct net_device *dev; + struct napi_struct napi; struct net_device_stats stats; struct macb_stats hw_stats; diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 315335671f0..702eba54916 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -66,7 +66,7 @@ static int mv643xx_eth_change_mtu(struct net_device *, int); static struct net_device_stats *mv643xx_eth_get_stats(struct net_device *); static void eth_port_init_mac_tables(unsigned int eth_port_num); #ifdef MV643XX_NAPI -static int mv643xx_poll(struct net_device *dev, int *budget); +static int mv643xx_poll(struct napi_struct *napi, int budget); #endif static int ethernet_phy_get(unsigned int eth_port_num); static void ethernet_phy_set(unsigned int eth_port_num, int phy_addr); @@ -562,7 +562,7 @@ static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id) /* wait for previous write to complete */ mv_read(MV643XX_ETH_INTERRUPT_MASK_REG(port_num)); - netif_rx_schedule(dev); + netif_rx_schedule(dev, &mp->napi); } #else if (eth_int_cause & ETH_INT_CAUSE_RX) @@ -880,6 +880,10 @@ static int mv643xx_eth_open(struct net_device *dev) mv643xx_eth_rx_refill_descs(dev); /* Fill RX ring with skb's */ +#ifdef MV643XX_NAPI + napi_enable(&mp->napi); +#endif + eth_port_start(dev); /* Interrupt Coalescing */ @@ -982,7 +986,7 @@ static int mv643xx_eth_stop(struct net_device *dev) mv_read(MV643XX_ETH_INTERRUPT_MASK_REG(port_num)); #ifdef MV643XX_NAPI - netif_poll_disable(dev); + napi_disable(&mp->napi); #endif netif_carrier_off(dev); netif_stop_queue(dev); @@ -992,10 +996,6 @@ static int mv643xx_eth_stop(struct net_device *dev) mv643xx_eth_free_tx_rings(dev); mv643xx_eth_free_rx_rings(dev); -#ifdef MV643XX_NAPI - netif_poll_enable(dev); -#endif - free_irq(dev->irq, dev); return 0; @@ -1007,11 +1007,12 @@ static int mv643xx_eth_stop(struct net_device *dev) * * This function is used in case of NAPI */ -static int mv643xx_poll(struct net_device *dev, int *budget) +static int mv643xx_poll(struct napi_struct *napi, int budget) { - struct mv643xx_private *mp = netdev_priv(dev); - int done = 1, orig_budget, work_done; + struct mv643xx_private *mp = container_of(napi, struct mv643xx_private, napi); + struct net_device *dev = mp->dev; unsigned int port_num = mp->port_num; + int work_done; #ifdef MV643XX_TX_FAST_REFILL if (++mp->tx_clean_threshold > 5) { @@ -1020,27 +1021,20 @@ static int mv643xx_poll(struct net_device *dev, int *budget) } #endif + work_done = 0; if ((mv_read(MV643XX_ETH_RX_CURRENT_QUEUE_DESC_PTR_0(port_num))) - != (u32) mp->rx_used_desc_q) { - orig_budget = *budget; - if (orig_budget > dev->quota) - orig_budget = dev->quota; - work_done = mv643xx_eth_receive_queue(dev, orig_budget); - *budget -= work_done; - dev->quota -= work_done; - if (work_done >= orig_budget) - done = 0; - } + != (u32) mp->rx_used_desc_q) + work_done = mv643xx_eth_receive_queue(dev, budget); - if (done) { - netif_rx_complete(dev); + if (work_done < budget) { + netif_rx_complete(dev, napi); mv_write(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num), 0); mv_write(MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num), 0); mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), ETH_INT_UNMASK_ALL); } - return done ? 0 : 1; + return work_done; } #endif @@ -1333,6 +1327,10 @@ static int mv643xx_eth_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dev); mp = netdev_priv(dev); + mp->dev = dev; +#ifdef MV643XX_NAPI + netif_napi_add(dev, &mp->napi, mv643xx_poll, 64); +#endif res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); BUG_ON(!res); @@ -1347,10 +1345,6 @@ static int mv643xx_eth_probe(struct platform_device *pdev) /* No need to Tx Timeout */ dev->tx_timeout = mv643xx_eth_tx_timeout; -#ifdef MV643XX_NAPI - dev->poll = mv643xx_poll; - dev->weight = 64; -#endif #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = mv643xx_netpoll; diff --git a/drivers/net/mv643xx_eth.h b/drivers/net/mv643xx_eth.h index 565b96696ac..be669eb2378 100644 --- a/drivers/net/mv643xx_eth.h +++ b/drivers/net/mv643xx_eth.h @@ -320,6 +320,8 @@ struct mv643xx_private { struct work_struct tx_timeout_task; + struct net_device *dev; + struct napi_struct napi; struct net_device_stats stats; struct mv643xx_mib_counters mib_counters; spinlock_t lock; diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 556962f9612..a30146ea51f 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -163,6 +163,7 @@ struct myri10ge_priv { int small_bytes; int big_bytes; struct net_device *dev; + struct napi_struct napi; struct net_device_stats stats; u8 __iomem *sram; int sram_size; @@ -1100,7 +1101,7 @@ static inline void myri10ge_tx_done(struct myri10ge_priv *mgp, int mcp_index) } } -static inline void myri10ge_clean_rx_done(struct myri10ge_priv *mgp, int *limit) +static inline int myri10ge_clean_rx_done(struct myri10ge_priv *mgp, int budget) { struct myri10ge_rx_done *rx_done = &mgp->rx_done; unsigned long rx_bytes = 0; @@ -1109,10 +1110,11 @@ static inline void myri10ge_clean_rx_done(struct myri10ge_priv *mgp, int *limit) int idx = rx_done->idx; int cnt = rx_done->cnt; + int work_done = 0; u16 length; __wsum checksum; - while (rx_done->entry[idx].length != 0 && *limit != 0) { + while (rx_done->entry[idx].length != 0 && work_done++ < budget) { length = ntohs(rx_done->entry[idx].length); rx_done->entry[idx].length = 0; checksum = csum_unfold(rx_done->entry[idx].checksum); @@ -1128,10 +1130,6 @@ static inline void myri10ge_clean_rx_done(struct myri10ge_priv *mgp, int *limit) rx_bytes += rx_ok * (unsigned long)length; cnt++; idx = cnt & (myri10ge_max_intr_slots - 1); - - /* limit potential for livelock by only handling a - * limited number of frames. */ - (*limit)--; } rx_done->idx = idx; rx_done->cnt = cnt; @@ -1145,6 +1143,7 @@ static inline void myri10ge_clean_rx_done(struct myri10ge_priv *mgp, int *limit) if (mgp->rx_big.fill_cnt - mgp->rx_big.cnt < myri10ge_fill_thresh) myri10ge_alloc_rx_pages(mgp, &mgp->rx_big, mgp->big_bytes, 0); + return work_done; } static inline void myri10ge_check_statblock(struct myri10ge_priv *mgp) @@ -1189,26 +1188,21 @@ static inline void myri10ge_check_statblock(struct myri10ge_priv *mgp) } } -static int myri10ge_poll(struct net_device *netdev, int *budget) +static int myri10ge_poll(struct napi_struct *napi, int budget) { - struct myri10ge_priv *mgp = netdev_priv(netdev); + struct myri10ge_priv *mgp = container_of(napi, struct myri10ge_priv, napi); + struct net_device *netdev = mgp->dev; struct myri10ge_rx_done *rx_done = &mgp->rx_done; - int limit, orig_limit, work_done; + int work_done; /* process as many rx events as NAPI will allow */ - limit = min(*budget, netdev->quota); - orig_limit = limit; - myri10ge_clean_rx_done(mgp, &limit); - work_done = orig_limit - limit; - *budget -= work_done; - netdev->quota -= work_done; + work_done = myri10ge_clean_rx_done(mgp, budget); if (rx_done->entry[rx_done->idx].length == 0 || !netif_running(netdev)) { - netif_rx_complete(netdev); + netif_rx_complete(netdev, napi); put_be32(htonl(3), mgp->irq_claim); - return 0; } - return 1; + return work_done; } static irqreturn_t myri10ge_intr(int irq, void *arg) @@ -1226,7 +1220,7 @@ static irqreturn_t myri10ge_intr(int irq, void *arg) /* low bit indicates receives are present, so schedule * napi poll handler */ if (stats->valid & 1) - netif_rx_schedule(mgp->dev); + netif_rx_schedule(mgp->dev, &mgp->napi); if (!mgp->msi_enabled) { put_be32(0, mgp->irq_deassert); @@ -1853,7 +1847,7 @@ static int myri10ge_open(struct net_device *dev) mgp->link_state = htonl(~0U); mgp->rdma_tags_available = 15; - netif_poll_enable(mgp->dev); /* must happen prior to any irq */ + napi_enable(&mgp->napi); /* must happen prior to any irq */ status = myri10ge_send_cmd(mgp, MXGEFW_CMD_ETHERNET_UP, &cmd, 0); if (status) { @@ -1897,7 +1891,7 @@ static int myri10ge_close(struct net_device *dev) del_timer_sync(&mgp->watchdog_timer); mgp->running = MYRI10GE_ETH_STOPPING; - netif_poll_disable(mgp->dev); + napi_disable(&mgp->napi); netif_carrier_off(dev); netif_stop_queue(dev); old_down_cnt = mgp->down_cnt; @@ -2857,6 +2851,8 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) mgp = netdev_priv(netdev); memset(mgp, 0, sizeof(*mgp)); mgp->dev = netdev; + netif_napi_add(netdev, &mgp->napi, + myri10ge_poll, myri10ge_napi_weight); mgp->pdev = pdev; mgp->csum_flag = MXGEFW_FLAGS_CKSUM; mgp->pause = myri10ge_flow_control; @@ -2981,8 +2977,6 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netdev->features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_TSO; if (dac_enabled) netdev->features |= NETIF_F_HIGHDMA; - netdev->poll = myri10ge_poll; - netdev->weight = myri10ge_napi_weight; /* make sure we can get an irq, and that MSI can be * setup (if available). Also ensure netdev->irq diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index b47a12d684f..43cfa4b3e29 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -560,6 +560,8 @@ struct netdev_private { /* address of a sent-in-place packet/buffer, for later free() */ struct sk_buff *tx_skbuff[TX_RING_SIZE]; dma_addr_t tx_dma[TX_RING_SIZE]; + struct net_device *dev; + struct napi_struct napi; struct net_device_stats stats; /* Media monitoring timer */ struct timer_list timer; @@ -636,7 +638,7 @@ static void init_registers(struct net_device *dev); static int start_tx(struct sk_buff *skb, struct net_device *dev); static irqreturn_t intr_handler(int irq, void *dev_instance); static void netdev_error(struct net_device *dev, int intr_status); -static int natsemi_poll(struct net_device *dev, int *budget); +static int natsemi_poll(struct napi_struct *napi, int budget); static void netdev_rx(struct net_device *dev, int *work_done, int work_to_do); static void netdev_tx_done(struct net_device *dev); static int natsemi_change_mtu(struct net_device *dev, int new_mtu); @@ -861,6 +863,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, dev->irq = irq; np = netdev_priv(dev); + netif_napi_add(dev, &np->napi, natsemi_poll, 64); np->pci_dev = pdev; pci_set_drvdata(pdev, dev); @@ -931,8 +934,6 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, dev->do_ioctl = &netdev_ioctl; dev->tx_timeout = &tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; - dev->poll = natsemi_poll; - dev->weight = 64; #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = &natsemi_poll_controller; @@ -1554,6 +1555,8 @@ static int netdev_open(struct net_device *dev) free_irq(dev->irq, dev); return i; } + napi_enable(&np->napi); + init_ring(dev); spin_lock_irq(&np->lock); init_registers(dev); @@ -2200,10 +2203,10 @@ static irqreturn_t intr_handler(int irq, void *dev_instance) prefetch(&np->rx_skbuff[np->cur_rx % RX_RING_SIZE]); - if (netif_rx_schedule_prep(dev)) { + if (netif_rx_schedule_prep(dev, &np->napi)) { /* Disable interrupts and register for poll */ natsemi_irq_disable(dev); - __netif_rx_schedule(dev); + __netif_rx_schedule(dev, &np->napi); } else printk(KERN_WARNING "%s: Ignoring interrupt, status %#08x, mask %#08x.\n", @@ -2216,12 +2219,11 @@ static irqreturn_t intr_handler(int irq, void *dev_instance) /* This is the NAPI poll routine. As well as the standard RX handling * it also handles all other interrupts that the chip might raise. */ -static int natsemi_poll(struct net_device *dev, int *budget) +static int natsemi_poll(struct napi_struct *napi, int budget) { - struct netdev_private *np = netdev_priv(dev); + struct netdev_private *np = container_of(napi, struct netdev_private, napi); + struct net_device *dev = np->dev; void __iomem * ioaddr = ns_ioaddr(dev); - - int work_to_do = min(*budget, dev->quota); int work_done = 0; do { @@ -2236,7 +2238,7 @@ static int natsemi_poll(struct net_device *dev, int *budget) if (np->intr_status & (IntrRxDone | IntrRxIntr | RxStatusFIFOOver | IntrRxErr | IntrRxOverrun)) { - netdev_rx(dev, &work_done, work_to_do); + netdev_rx(dev, &work_done, budget); } if (np->intr_status & @@ -2250,16 +2252,13 @@ static int natsemi_poll(struct net_device *dev, int *budget) if (np->intr_status & IntrAbnormalSummary) netdev_error(dev, np->intr_status); - *budget -= work_done; - dev->quota -= work_done; - - if (work_done >= work_to_do) - return 1; + if (work_done >= budget) + return work_done; np->intr_status = readl(ioaddr + IntrStatus); } while (np->intr_status); - netif_rx_complete(dev); + netif_rx_complete(dev, napi); /* Reenable interrupts providing nothing is trying to shut * the chip down. */ @@ -2268,7 +2267,7 @@ static int natsemi_poll(struct net_device *dev, int *budget) natsemi_irq_enable(dev); spin_unlock(&np->lock); - return 0; + return work_done; } /* This routine is logically part of the interrupt handler, but separated @@ -3158,6 +3157,8 @@ static int netdev_close(struct net_device *dev) dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx); + napi_disable(&np->napi); + /* * FIXME: what if someone tries to close a device * that is suspended? @@ -3253,7 +3254,7 @@ static void __devexit natsemi_remove1 (struct pci_dev *pdev) * disable_irq() to enforce synchronization. * * natsemi_poll: checks before reenabling interrupts. suspend * sets hands_off, disables interrupts and then waits with - * netif_poll_disable(). + * napi_disable(). * * Interrupts must be disabled, otherwise hands_off can cause irq storms. */ @@ -3279,7 +3280,7 @@ static int natsemi_suspend (struct pci_dev *pdev, pm_message_t state) spin_unlock_irq(&np->lock); enable_irq(dev->irq); - netif_poll_disable(dev); + napi_disable(&np->napi); /* Update the error counts. */ __get_stats(dev); @@ -3320,6 +3321,8 @@ static int natsemi_resume (struct pci_dev *pdev) pci_enable_device(pdev); /* pci_power_on(pdev); */ + napi_enable(&np->napi); + natsemi_reset(dev); init_ring(dev); disable_irq(dev->irq); @@ -3333,7 +3336,6 @@ static int natsemi_resume (struct pci_dev *pdev) mod_timer(&np->timer, jiffies + 1*HZ); } netif_device_attach(dev); - netif_poll_enable(dev); out: rtnl_unlock(); return 0; diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index d4c92cc879d..aaa34939485 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -880,6 +880,7 @@ struct netxen_adapter { struct netxen_adapter *master; struct net_device *netdev; struct pci_dev *pdev; + struct napi_struct napi; struct net_device_stats net_stats; unsigned char mac_addr[ETH_ALEN]; int mtu; diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 3122d010163..a10bbefbdad 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -68,7 +68,7 @@ static void netxen_tx_timeout(struct net_device *netdev); static void netxen_tx_timeout_task(struct work_struct *work); static void netxen_watchdog(unsigned long); static int netxen_handle_int(struct netxen_adapter *, struct net_device *); -static int netxen_nic_poll(struct net_device *dev, int *budget); +static int netxen_nic_poll(struct napi_struct *napi, int budget); #ifdef CONFIG_NET_POLL_CONTROLLER static void netxen_nic_poll_controller(struct net_device *netdev); #endif @@ -402,6 +402,9 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) adapter->netdev = netdev; adapter->pdev = pdev; + netif_napi_add(netdev, &adapter->napi, + netxen_nic_poll, NETXEN_NETDEV_WEIGHT); + /* this will be read from FW later */ adapter->intr_scheme = -1; @@ -422,8 +425,6 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netxen_nic_change_mtu(netdev, netdev->mtu); SET_ETHTOOL_OPS(netdev, &netxen_nic_ethtool_ops); - netdev->poll = netxen_nic_poll; - netdev->weight = NETXEN_NETDEV_WEIGHT; #ifdef CONFIG_NET_POLL_CONTROLLER netdev->poll_controller = netxen_nic_poll_controller; #endif @@ -885,6 +886,8 @@ static int netxen_nic_open(struct net_device *netdev) if (!adapter->driver_mismatch) mod_timer(&adapter->watchdog_timer, jiffies); + napi_enable(&adapter->napi); + netxen_nic_enable_int(adapter); /* Done here again so that even if phantom sw overwrote it, @@ -894,6 +897,7 @@ static int netxen_nic_open(struct net_device *netdev) del_timer_sync(&adapter->watchdog_timer); printk(KERN_ERR "%s: Failed to initialize port %d\n", netxen_nic_driver_name, adapter->portnum); + napi_disable(&adapter->napi); return -EIO; } if (adapter->macaddr_set) @@ -923,6 +927,7 @@ static int netxen_nic_close(struct net_device *netdev) netif_carrier_off(netdev); netif_stop_queue(netdev); + napi_disable(&adapter->napi); netxen_nic_disable_int(adapter); @@ -1243,11 +1248,11 @@ netxen_handle_int(struct netxen_adapter *adapter, struct net_device *netdev) netxen_nic_disable_int(adapter); if (netxen_nic_rx_has_work(adapter) || netxen_nic_tx_has_work(adapter)) { - if (netif_rx_schedule_prep(netdev)) { + if (netif_rx_schedule_prep(netdev, &adapter->napi)) { /* * Interrupts are already disabled. */ - __netif_rx_schedule(netdev); + __netif_rx_schedule(netdev, &adapter->napi); } else { static unsigned int intcount = 0; if ((++intcount & 0xfff) == 0xfff) @@ -1305,14 +1310,13 @@ irqreturn_t netxen_intr(int irq, void *data) return IRQ_HANDLED; } -static int netxen_nic_poll(struct net_device *netdev, int *budget) +static int netxen_nic_poll(struct napi_struct *napi, int budget) { - struct netxen_adapter *adapter = netdev_priv(netdev); - int work_to_do = min(*budget, netdev->quota); + struct netxen_adapter *adapter = container_of(napi, struct netxen_adapter, napi); + struct net_device *netdev = adapter->netdev; int done = 1; int ctx; - int this_work_done; - int work_done = 0; + int work_done; DPRINTK(INFO, "polling for %d descriptors\n", *budget); @@ -1330,16 +1334,11 @@ static int netxen_nic_poll(struct net_device *netdev, int *budget) * packets are on one context, it gets only half of the quota, * and ends up not processing it. */ - this_work_done = netxen_process_rcv_ring(adapter, ctx, - work_to_do / - MAX_RCV_CTX); - work_done += this_work_done; + work_done += netxen_process_rcv_ring(adapter, ctx, + budget / MAX_RCV_CTX); } - netdev->quota -= work_done; - *budget -= work_done; - - if (work_done >= work_to_do && netxen_nic_rx_has_work(adapter) != 0) + if (work_done >= budget && netxen_nic_rx_has_work(adapter) != 0) done = 0; if (netxen_process_cmd_ring((unsigned long)adapter) == 0) @@ -1348,11 +1347,11 @@ static int netxen_nic_poll(struct net_device *netdev, int *budget) DPRINTK(INFO, "new work_done: %d work_to_do: %d\n", work_done, work_to_do); if (done) { - netif_rx_complete(netdev); + netif_rx_complete(netdev, napi); netxen_nic_enable_int(adapter); } - return !done; + return work_done; } #ifdef CONFIG_NET_POLL_CONTROLLER diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 0b3066a6fe4..e63cc335a4b 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -584,7 +584,7 @@ static irqreturn_t pasemi_mac_rx_intr(int irq, void *data) if (*mac->rx_status & PAS_STATUS_TIMER) reg |= PAS_IOB_DMA_RXCH_RESET_TINTC; - netif_rx_schedule(dev); + netif_rx_schedule(dev, &mac->napi); pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_RXCH_RESET(mac->dma_rxch), reg); @@ -808,7 +808,7 @@ static int pasemi_mac_open(struct net_device *dev) dev_warn(&mac->pdev->dev, "phy init failed: %d\n", ret); netif_start_queue(dev); - netif_poll_enable(dev); + napi_enable(&mac->napi); /* Interrupts are a bit different for our DMA controller: While * it's got one a regular PCI device header, the interrupt there @@ -845,7 +845,7 @@ static int pasemi_mac_open(struct net_device *dev) out_rx_int: free_irq(mac->tx_irq, dev); out_tx_int: - netif_poll_disable(dev); + napi_disable(&mac->napi); netif_stop_queue(dev); pasemi_mac_free_tx_resources(dev); out_tx_resources: @@ -869,6 +869,7 @@ static int pasemi_mac_close(struct net_device *dev) } netif_stop_queue(dev); + napi_disable(&mac->napi); /* Clean out any pending buffers */ pasemi_mac_clean_tx(mac); @@ -1047,26 +1048,20 @@ static void pasemi_mac_set_rx_mode(struct net_device *dev) } -static int pasemi_mac_poll(struct net_device *dev, int *budget) +static int pasemi_mac_poll(struct napi_struct *napi, int budget) { - int pkts, limit = min(*budget, dev->quota); - struct pasemi_mac *mac = netdev_priv(dev); - - pkts = pasemi_mac_clean_rx(mac, limit); + struct pasemi_mac *mac = container_of(napi, struct pasemi_mac, napi); + struct net_device *dev = mac->netdev; + int pkts; - dev->quota -= pkts; - *budget -= pkts; - - if (pkts < limit) { + pkts = pasemi_mac_clean_rx(mac, budget); + if (pkts < budget) { /* all done, no more packets present */ - netif_rx_complete(dev); + netif_rx_complete(dev, napi); pasemi_mac_restart_rx_intr(mac); - return 0; - } else { - /* used up our quantum, so reschedule */ - return 1; } + return pkts; } static int __devinit @@ -1099,6 +1094,10 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) mac->netdev = dev; mac->dma_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa007, NULL); + netif_napi_add(dev, &mac->napi, pasemi_mac_poll, 64); + + dev->features = NETIF_F_HW_CSUM; + if (!mac->dma_pdev) { dev_err(&pdev->dev, "Can't find DMA Controller\n"); err = -ENODEV; @@ -1150,9 +1149,6 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) dev->hard_start_xmit = pasemi_mac_start_tx; dev->get_stats = pasemi_mac_get_stats; dev->set_multicast_list = pasemi_mac_set_rx_mode; - dev->weight = 64; - dev->poll = pasemi_mac_poll; - dev->features = NETIF_F_HW_CSUM; /* The dma status structure is located in the I/O bridge, and * is cache coherent. diff --git a/drivers/net/pasemi_mac.h b/drivers/net/pasemi_mac.h index c29ee159c33..85d3b7856e5 100644 --- a/drivers/net/pasemi_mac.h +++ b/drivers/net/pasemi_mac.h @@ -56,6 +56,7 @@ struct pasemi_mac { struct pci_dev *dma_pdev; struct pci_dev *iob_pdev; struct phy_device *phydev; + struct napi_struct napi; struct net_device_stats stats; /* Pointer to the cacheable per-channel status registers */ diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index e6a67531de9..a9973490dba 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -280,6 +280,8 @@ struct pcnet32_private { unsigned int dirty_rx, /* ring entries to be freed. */ dirty_tx; + struct net_device *dev; + struct napi_struct napi; struct net_device_stats stats; char tx_full; char phycount; /* number of phys found */ @@ -440,15 +442,21 @@ static struct pcnet32_access pcnet32_dwio = { static void pcnet32_netif_stop(struct net_device *dev) { + struct pcnet32_private *lp = netdev_priv(dev); dev->trans_start = jiffies; - netif_poll_disable(dev); +#ifdef CONFIG_PCNET32_NAPI + napi_disable(&lp->napi); +#endif netif_tx_disable(dev); } static void pcnet32_netif_start(struct net_device *dev) { + struct pcnet32_private *lp = netdev_priv(dev); netif_wake_queue(dev); - netif_poll_enable(dev); +#ifdef CONFIG_PCNET32_NAPI + napi_enable(&lp->napi); +#endif } /* @@ -816,7 +824,7 @@ static int pcnet32_set_ringparam(struct net_device *dev, if ((1 << i) != lp->rx_ring_size) pcnet32_realloc_rx_ring(dev, lp, i); - dev->weight = lp->rx_ring_size / 2; + lp->napi.weight = lp->rx_ring_size / 2; if (netif_running(dev)) { pcnet32_netif_start(dev); @@ -1255,7 +1263,7 @@ static void pcnet32_rx_entry(struct net_device *dev, return; } -static int pcnet32_rx(struct net_device *dev, int quota) +static int pcnet32_rx(struct net_device *dev, int budget) { struct pcnet32_private *lp = netdev_priv(dev); int entry = lp->cur_rx & lp->rx_mod_mask; @@ -1263,7 +1271,7 @@ static int pcnet32_rx(struct net_device *dev, int quota) int npackets = 0; /* If we own the next entry, it's a new packet. Send it up. */ - while (quota > npackets && (short)le16_to_cpu(rxp->status) >= 0) { + while (npackets < budget && (short)le16_to_cpu(rxp->status) >= 0) { pcnet32_rx_entry(dev, lp, rxp, entry); npackets += 1; /* @@ -1379,15 +1387,16 @@ static int pcnet32_tx(struct net_device *dev) } #ifdef CONFIG_PCNET32_NAPI -static int pcnet32_poll(struct net_device *dev, int *budget) +static int pcnet32_poll(struct napi_struct *napi, int budget) { - struct pcnet32_private *lp = netdev_priv(dev); - int quota = min(dev->quota, *budget); + struct pcnet32_private *lp = container_of(napi, struct pcnet32_private, napi); + struct net_device *dev = lp->dev; unsigned long ioaddr = dev->base_addr; unsigned long flags; + int work_done; u16 val; - quota = pcnet32_rx(dev, quota); + work_done = pcnet32_rx(dev, budget); spin_lock_irqsave(&lp->lock, flags); if (pcnet32_tx(dev)) { @@ -1399,28 +1408,22 @@ static int pcnet32_poll(struct net_device *dev, int *budget) } spin_unlock_irqrestore(&lp->lock, flags); - *budget -= quota; - dev->quota -= quota; - - if (dev->quota == 0) { - return 1; - } - - netif_rx_complete(dev); - - spin_lock_irqsave(&lp->lock, flags); + if (work_done < budget) { + spin_lock_irqsave(&lp->lock, flags); - /* clear interrupt masks */ - val = lp->a.read_csr(ioaddr, CSR3); - val &= 0x00ff; - lp->a.write_csr(ioaddr, CSR3, val); + __netif_rx_complete(dev, napi); - /* Set interrupt enable. */ - lp->a.write_csr(ioaddr, CSR0, CSR0_INTEN); - mmiowb(); - spin_unlock_irqrestore(&lp->lock, flags); + /* clear interrupt masks */ + val = lp->a.read_csr(ioaddr, CSR3); + val &= 0x00ff; + lp->a.write_csr(ioaddr, CSR3, val); - return 0; + /* Set interrupt enable. */ + lp->a.write_csr(ioaddr, CSR0, CSR0_INTEN); + mmiowb(); + spin_unlock_irqrestore(&lp->lock, flags); + } + return work_done; } #endif @@ -1815,6 +1818,8 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) } lp->pci_dev = pdev; + lp->dev = dev; + spin_lock_init(&lp->lock); SET_MODULE_OWNER(dev); @@ -1843,6 +1848,10 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) lp->mii_if.mdio_read = mdio_read; lp->mii_if.mdio_write = mdio_write; +#ifdef CONFIG_PCNET32_NAPI + netif_napi_add(dev, &lp->napi, pcnet32_poll, lp->rx_ring_size / 2); +#endif + if (fdx && !(lp->options & PCNET32_PORT_ASEL) && ((cards_found >= MAX_UNITS) || full_duplex[cards_found])) lp->options |= PCNET32_PORT_FD; @@ -1953,10 +1962,6 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) dev->ethtool_ops = &pcnet32_ethtool_ops; dev->tx_timeout = pcnet32_tx_timeout; dev->watchdog_timeo = (5 * HZ); - dev->weight = lp->rx_ring_size / 2; -#ifdef CONFIG_PCNET32_NAPI - dev->poll = pcnet32_poll; -#endif #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = pcnet32_poll_controller; @@ -2276,6 +2281,10 @@ static int pcnet32_open(struct net_device *dev) goto err_free_ring; } +#ifdef CONFIG_PCNET32_NAPI + napi_enable(&lp->napi); +#endif + /* Re-initialize the PCNET32, and start it when done. */ lp->a.write_csr(ioaddr, 1, (lp->init_dma_addr & 0xffff)); lp->a.write_csr(ioaddr, 2, (lp->init_dma_addr >> 16)); @@ -2599,18 +2608,18 @@ pcnet32_interrupt(int irq, void *dev_id) /* unlike for the lance, there is no restart needed */ } #ifdef CONFIG_PCNET32_NAPI - if (netif_rx_schedule_prep(dev)) { + if (netif_rx_schedule_prep(dev, &lp->napi)) { u16 val; /* set interrupt masks */ val = lp->a.read_csr(ioaddr, CSR3); val |= 0x5f00; lp->a.write_csr(ioaddr, CSR3, val); mmiowb(); - __netif_rx_schedule(dev); + __netif_rx_schedule(dev, &lp->napi); break; } #else - pcnet32_rx(dev, dev->weight); + pcnet32_rx(dev, lp->napi.weight); if (pcnet32_tx(dev)) { /* reset the chip to clear the error condition, then restart */ lp->a.reset(ioaddr); @@ -2645,6 +2654,9 @@ static int pcnet32_close(struct net_device *dev) del_timer_sync(&lp->watchdog_timer); netif_stop_queue(dev); +#ifdef CONFIG_PCNET32_NAPI + napi_disable(&lp->napi); +#endif spin_lock_irqsave(&lp->lock, flags); diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c index e5650391843..92561c0450b 100644 --- a/drivers/net/ps3_gelic_net.c +++ b/drivers/net/ps3_gelic_net.c @@ -556,6 +556,7 @@ static int gelic_net_stop(struct net_device *netdev) { struct gelic_net_card *card = netdev_priv(netdev); + napi_disable(&card->napi); netif_stop_queue(netdev); /* turn off DMA, force end */ @@ -987,32 +988,24 @@ refill: * if the quota is exceeded, but the driver has still packets. * */ -static int gelic_net_poll(struct net_device *netdev, int *budget) +static int gelic_net_poll(struct napi_struct *napi, int budget) { - struct gelic_net_card *card = netdev_priv(netdev); - int packets_to_do, packets_done = 0; - int no_more_packets = 0; - - packets_to_do = min(*budget, netdev->quota); + struct gelic_net_card *card = container_of(napi, struct gelic_net_card, napi); + struct net_device *netdev = card->netdev; + int packets_done = 0; - while (packets_to_do) { - if (gelic_net_decode_one_descr(card)) { - packets_done++; - packets_to_do--; - } else { - /* no more packets for the stack */ - no_more_packets = 1; + while (packets_done < budget) { + if (!gelic_net_decode_one_descr(card)) break; - } + + packets_done++; } - netdev->quota -= packets_done; - *budget -= packets_done; - if (no_more_packets) { - netif_rx_complete(netdev); + + if (packets_done < budget) { + netif_rx_complete(netdev, napi); gelic_net_rx_irq_on(card); - return 0; - } else - return 1; + } + return packets_done; } /** * gelic_net_change_mtu - changes the MTU of an interface @@ -1055,7 +1048,7 @@ static irqreturn_t gelic_net_interrupt(int irq, void *ptr) if (status & GELIC_NET_RXINT) { gelic_net_rx_irq_off(card); - netif_rx_schedule(netdev); + netif_rx_schedule(netdev, &card->napi); } if (status & GELIC_NET_TXINT) { @@ -1159,6 +1152,8 @@ static int gelic_net_open(struct net_device *netdev) if (gelic_net_alloc_rx_skbs(card)) goto alloc_skbs_failed; + napi_enable(&card->napi); + card->tx_dma_progress = 0; card->ghiintmask = GELIC_NET_RXINT | GELIC_NET_TXINT; @@ -1360,9 +1355,6 @@ static void gelic_net_setup_netdev_ops(struct net_device *netdev) /* tx watchdog */ netdev->tx_timeout = &gelic_net_tx_timeout; netdev->watchdog_timeo = GELIC_NET_WATCHDOG_TIMEOUT; - /* NAPI */ - netdev->poll = &gelic_net_poll; - netdev->weight = GELIC_NET_NAPI_WEIGHT; netdev->ethtool_ops = &gelic_net_ethtool_ops; } @@ -1390,6 +1382,9 @@ static int gelic_net_setup_netdev(struct gelic_net_card *card) gelic_net_setup_netdev_ops(netdev); + netif_napi_add(netdev, &card->napi, + gelic_net_poll, GELIC_NET_NAPI_WEIGHT); + netdev->features = NETIF_F_IP_CSUM; status = lv1_net_control(bus_id(card), dev_id(card), diff --git a/drivers/net/ps3_gelic_net.h b/drivers/net/ps3_gelic_net.h index a9c4c4fc254..968560269a3 100644 --- a/drivers/net/ps3_gelic_net.h +++ b/drivers/net/ps3_gelic_net.h @@ -194,6 +194,7 @@ struct gelic_net_descr_chain { struct gelic_net_card { struct net_device *netdev; + struct napi_struct napi; /* * hypervisor requires irq_status should be * 8 bytes aligned, but u64 member is diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c index ea151315050..bf9f8f64ba6 100755 --- a/drivers/net/qla3xxx.c +++ b/drivers/net/qla3xxx.c @@ -2310,10 +2310,10 @@ static int ql_tx_rx_clean(struct ql3_adapter *qdev, return work_done; } -static int ql_poll(struct net_device *ndev, int *budget) +static int ql_poll(struct napi_struct *napi, int budget) { - struct ql3_adapter *qdev = netdev_priv(ndev); - int work_to_do = min(*budget, ndev->quota); + struct ql3_adapter *qdev = container_of(napi, struct ql3_adapter, napi); + struct net_device *ndev = qdev->ndev; int rx_cleaned = 0, tx_cleaned = 0; unsigned long hw_flags; struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers; @@ -2321,16 +2321,13 @@ static int ql_poll(struct net_device *ndev, int *budget) if (!netif_carrier_ok(ndev)) goto quit_polling; - ql_tx_rx_clean(qdev, &tx_cleaned, &rx_cleaned, work_to_do); - *budget -= rx_cleaned; - ndev->quota -= rx_cleaned; + ql_tx_rx_clean(qdev, &tx_cleaned, &rx_cleaned, budget); - if( tx_cleaned + rx_cleaned != work_to_do || + if (tx_cleaned + rx_cleaned != budget || !netif_running(ndev)) { quit_polling: - netif_rx_complete(ndev); - spin_lock_irqsave(&qdev->hw_lock, hw_flags); + __netif_rx_complete(ndev, napi); ql_update_small_bufq_prod_index(qdev); ql_update_lrg_bufq_prod_index(qdev); writel(qdev->rsp_consumer_index, @@ -2338,9 +2335,8 @@ quit_polling: spin_unlock_irqrestore(&qdev->hw_lock, hw_flags); ql_enable_interrupts(qdev); - return 0; } - return 1; + return tx_cleaned + rx_cleaned; } static irqreturn_t ql3xxx_isr(int irq, void *dev_id) @@ -2390,8 +2386,8 @@ static irqreturn_t ql3xxx_isr(int irq, void *dev_id) spin_unlock(&qdev->adapter_lock); } else if (value & ISP_IMR_DISABLE_CMPL_INT) { ql_disable_interrupts(qdev); - if (likely(netif_rx_schedule_prep(ndev))) { - __netif_rx_schedule(ndev); + if (likely(netif_rx_schedule_prep(ndev, &qdev->napi))) { + __netif_rx_schedule(ndev, &qdev->napi); } } else { return IRQ_NONE; @@ -3617,7 +3613,7 @@ static int ql_adapter_down(struct ql3_adapter *qdev, int do_reset) del_timer_sync(&qdev->adapter_timer); - netif_poll_disable(ndev); + napi_disable(&qdev->napi); if (do_reset) { int soft_reset; @@ -3705,7 +3701,7 @@ static int ql_adapter_up(struct ql3_adapter *qdev) mod_timer(&qdev->adapter_timer, jiffies + HZ * 1); - netif_poll_enable(ndev); + napi_enable(&qdev->napi); ql_enable_interrupts(qdev); return 0; @@ -4061,8 +4057,7 @@ static int __devinit ql3xxx_probe(struct pci_dev *pdev, ndev->tx_timeout = ql3xxx_tx_timeout; ndev->watchdog_timeo = 5 * HZ; - ndev->poll = &ql_poll; - ndev->weight = 64; + netif_napi_add(ndev, &qdev->napi, ql_poll, 64); ndev->irq = pdev->irq; diff --git a/drivers/net/qla3xxx.h b/drivers/net/qla3xxx.h index 4a832c46c27..aa2216f0d7b 100755 --- a/drivers/net/qla3xxx.h +++ b/drivers/net/qla3xxx.h @@ -1175,6 +1175,8 @@ struct ql3_adapter { struct pci_dev *pdev; struct net_device *ndev; /* Parent NET device */ + struct napi_struct napi; + /* Hardware information */ u8 chip_rev_id; u8 pci_slot; diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index c76dd29c8e9..3f2306e3f51 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -384,6 +384,7 @@ struct rtl8169_private { void __iomem *mmio_addr; /* memory map physical address */ struct pci_dev *pci_dev; /* Index of PCI device */ struct net_device *dev; + struct napi_struct napi; struct net_device_stats stats; /* statistics of net device */ spinlock_t lock; /* spin lock flag */ u32 msg_enable; @@ -443,13 +444,13 @@ static void rtl_set_rx_mode(struct net_device *dev); static void rtl8169_tx_timeout(struct net_device *dev); static struct net_device_stats *rtl8169_get_stats(struct net_device *dev); static int rtl8169_rx_interrupt(struct net_device *, struct rtl8169_private *, - void __iomem *); + void __iomem *, u32 budget); static int rtl8169_change_mtu(struct net_device *dev, int new_mtu); static void rtl8169_down(struct net_device *dev); static void rtl8169_rx_clear(struct rtl8169_private *tp); #ifdef CONFIG_R8169_NAPI -static int rtl8169_poll(struct net_device *dev, int *budget); +static int rtl8169_poll(struct napi_struct *napi, int budget); #endif static const unsigned int rtl8169_rx_config = @@ -1656,8 +1657,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dev->set_mac_address = rtl_set_mac_address; #ifdef CONFIG_R8169_NAPI - dev->poll = rtl8169_poll; - dev->weight = R8169_NAPI_WEIGHT; + netif_napi_add(dev, &tp->napi, rtl8169_poll, R8169_NAPI_WEIGHT); #endif #ifdef CONFIG_R8169_VLAN @@ -1777,6 +1777,10 @@ static int rtl8169_open(struct net_device *dev) if (retval < 0) goto err_release_ring_2; +#ifdef CONFIG_R8169_NAPI + napi_enable(&tp->napi); +#endif + rtl_hw_start(dev); rtl8169_request_timer(dev); @@ -2082,7 +2086,9 @@ static int rtl8169_change_mtu(struct net_device *dev, int new_mtu) if (ret < 0) goto out; - netif_poll_enable(dev); +#ifdef CONFIG_R8169_NAPI + napi_enable(&tp->napi); +#endif rtl_hw_start(dev); @@ -2274,11 +2280,15 @@ static void rtl8169_wait_for_quiescence(struct net_device *dev) synchronize_irq(dev->irq); /* Wait for any pending NAPI task to complete */ - netif_poll_disable(dev); +#ifdef CONFIG_R8169_NAPI + napi_disable(&tp->napi); +#endif rtl8169_irq_mask_and_ack(ioaddr); - netif_poll_enable(dev); +#ifdef CONFIG_R8169_NAPI + napi_enable(&tp->napi); +#endif } static void rtl8169_reinit_task(struct work_struct *work) @@ -2322,7 +2332,7 @@ static void rtl8169_reset_task(struct work_struct *work) rtl8169_wait_for_quiescence(dev); - rtl8169_rx_interrupt(dev, tp, tp->mmio_addr); + rtl8169_rx_interrupt(dev, tp, tp->mmio_addr, ~(u32)0); rtl8169_tx_clear(tp); if (tp->dirty_rx == tp->cur_rx) { @@ -2636,14 +2646,14 @@ out: static int rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp, - void __iomem *ioaddr) + void __iomem *ioaddr, u32 budget) { unsigned int cur_rx, rx_left; unsigned int delta, count; cur_rx = tp->cur_rx; rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx; - rx_left = rtl8169_rx_quota(rx_left, (u32) dev->quota); + rx_left = rtl8169_rx_quota(rx_left, budget); for (; rx_left > 0; rx_left--, cur_rx++) { unsigned int entry = cur_rx % NUM_RX_DESC; @@ -2792,8 +2802,8 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance) RTL_W16(IntrMask, tp->intr_event & ~tp->napi_event); tp->intr_mask = ~tp->napi_event; - if (likely(netif_rx_schedule_prep(dev))) - __netif_rx_schedule(dev); + if (likely(netif_rx_schedule_prep(dev, &tp->napi))) + __netif_rx_schedule(dev, &tp->napi); else if (netif_msg_intr(tp)) { printk(KERN_INFO "%s: interrupt %04x in poll\n", dev->name, status); @@ -2803,7 +2813,7 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance) #else /* Rx interrupt */ if (status & (RxOK | RxOverflow | RxFIFOOver)) - rtl8169_rx_interrupt(dev, tp, ioaddr); + rtl8169_rx_interrupt(dev, tp, ioaddr, ~(u32)0); /* Tx interrupt */ if (status & (TxOK | TxErr)) @@ -2826,20 +2836,18 @@ out: } #ifdef CONFIG_R8169_NAPI -static int rtl8169_poll(struct net_device *dev, int *budget) +static int rtl8169_poll(struct napi_struct *napi, int budget) { - unsigned int work_done, work_to_do = min(*budget, dev->quota); - struct rtl8169_private *tp = netdev_priv(dev); + struct rtl8169_private *tp = container_of(napi, struct rtl8169_private, napi); + struct net_device *dev = tp->dev; void __iomem *ioaddr = tp->mmio_addr; + int work_done; - work_done = rtl8169_rx_interrupt(dev, tp, ioaddr); + work_done = rtl8169_rx_interrupt(dev, tp, ioaddr, (u32) budget); rtl8169_tx_interrupt(dev, tp, ioaddr); - *budget -= work_done; - dev->quota -= work_done; - - if (work_done < work_to_do) { - netif_rx_complete(dev); + if (work_done < budget) { + netif_rx_complete(dev, napi); tp->intr_mask = 0xffff; /* * 20040426: the barrier is not strictly required but the @@ -2851,7 +2859,7 @@ static int rtl8169_poll(struct net_device *dev, int *budget) RTL_W16(IntrMask, tp->intr_event); } - return (work_done >= work_to_do); + return work_done; } #endif @@ -2880,7 +2888,7 @@ core_down: synchronize_irq(dev->irq); if (!poll_locked) { - netif_poll_disable(dev); + napi_disable(&tp->napi); poll_locked++; } @@ -2918,8 +2926,6 @@ static int rtl8169_close(struct net_device *dev) free_irq(dev->irq, dev); - netif_poll_enable(dev); - pci_free_consistent(pdev, R8169_RX_RING_BYTES, tp->RxDescArray, tp->RxPhyAddr); pci_free_consistent(pdev, R8169_TX_RING_BYTES, tp->TxDescArray, diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 24feb00600e..dd012322cdb 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -2568,7 +2568,7 @@ static void free_rx_buffers(struct s2io_nic *sp) /** * s2io_poll - Rx interrupt handler for NAPI support - * @dev : pointer to the device structure. + * @napi : pointer to the napi structure. * @budget : The number of packets that were budgeted to be processed * during one pass through the 'Poll" function. * Description: @@ -2579,9 +2579,10 @@ static void free_rx_buffers(struct s2io_nic *sp) * 0 on success and 1 if there are No Rx packets to be processed. */ -static int s2io_poll(struct net_device *dev, int *budget) +static int s2io_poll(struct napi_struct *napi, int budget) { - struct s2io_nic *nic = dev->priv; + struct s2io_nic *nic = container_of(napi, struct s2io_nic, napi); + struct net_device *dev = nic->dev; int pkt_cnt = 0, org_pkts_to_process; struct mac_info *mac_control; struct config_param *config; @@ -2592,9 +2593,7 @@ static int s2io_poll(struct net_device *dev, int *budget) mac_control = &nic->mac_control; config = &nic->config; - nic->pkts_to_process = *budget; - if (nic->pkts_to_process > dev->quota) - nic->pkts_to_process = dev->quota; + nic->pkts_to_process = budget; org_pkts_to_process = nic->pkts_to_process; writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int); @@ -2608,12 +2607,8 @@ static int s2io_poll(struct net_device *dev, int *budget) goto no_rx; } } - if (!pkt_cnt) - pkt_cnt = 1; - dev->quota -= pkt_cnt; - *budget -= pkt_cnt; - netif_rx_complete(dev); + netif_rx_complete(dev, napi); for (i = 0; i < config->rx_ring_num; i++) { if (fill_rx_buffers(nic, i) == -ENOMEM) { @@ -2626,12 +2621,9 @@ static int s2io_poll(struct net_device *dev, int *budget) writeq(0x0, &bar0->rx_traffic_mask); readl(&bar0->rx_traffic_mask); atomic_dec(&nic->isr_cnt); - return 0; + return pkt_cnt; no_rx: - dev->quota -= pkt_cnt; - *budget -= pkt_cnt; - for (i = 0; i < config->rx_ring_num; i++) { if (fill_rx_buffers(nic, i) == -ENOMEM) { DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name); @@ -2640,7 +2632,7 @@ no_rx: } } atomic_dec(&nic->isr_cnt); - return 1; + return pkt_cnt; } #ifdef CONFIG_NET_POLL_CONTROLLER @@ -3809,6 +3801,8 @@ static int s2io_open(struct net_device *dev) netif_carrier_off(dev); sp->last_link_state = 0; + napi_enable(&sp->napi); + /* Initialize H/W and enable interrupts */ err = s2io_card_up(sp); if (err) { @@ -3828,6 +3822,7 @@ static int s2io_open(struct net_device *dev) return 0; hw_init_failed: + napi_disable(&sp->napi); if (sp->intr_type == MSI_X) { if (sp->entries) { kfree(sp->entries); @@ -3861,6 +3856,7 @@ static int s2io_close(struct net_device *dev) struct s2io_nic *sp = dev->priv; netif_stop_queue(dev); + napi_disable(&sp->napi); /* Reset card, kill tasklet and free Tx and Rx buffers. */ s2io_card_down(sp); @@ -4232,8 +4228,8 @@ static irqreturn_t s2io_isr(int irq, void *dev_id) if (napi) { if (reason & GEN_INTR_RXTRAFFIC) { - if ( likely ( netif_rx_schedule_prep(dev)) ) { - __netif_rx_schedule(dev); + if (likely (netif_rx_schedule_prep(dev, &sp->napi))) { + __netif_rx_schedule(dev, &sp->napi); writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_mask); } else @@ -7215,8 +7211,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) * will use eth_mac_addr() for dev->set_mac_address * mac address will be set every time dev->open() is called */ - dev->poll = s2io_poll; - dev->weight = 32; + netif_napi_add(dev, &sp->napi, s2io_poll, 32); #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = s2io_netpoll; diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 92983ee7df8..420fefb9918 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -786,6 +786,7 @@ struct s2io_nic { */ int pkts_to_process; struct net_device *dev; + struct napi_struct napi; struct mac_info mac_control; struct config_param config; struct pci_dev *pdev; @@ -1019,7 +1020,7 @@ static void s2io_set_multicast(struct net_device *dev); static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp); static void s2io_link(struct s2io_nic * sp, int link); static void s2io_reset(struct s2io_nic * sp); -static int s2io_poll(struct net_device *dev, int *budget); +static int s2io_poll(struct napi_struct *napi, int budget); static void s2io_init_pci(struct s2io_nic * sp); static int s2io_set_mac_addr(struct net_device *dev, u8 * addr); static void s2io_alarm_handle(unsigned long data); diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index e7fdcf15b5a..53845ebb649 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -238,6 +238,7 @@ struct sbmac_softc { */ struct net_device *sbm_dev; /* pointer to linux device */ + struct napi_struct napi; spinlock_t sbm_lock; /* spin lock */ struct timer_list sbm_timer; /* for monitoring MII */ struct net_device_stats sbm_stats; @@ -320,7 +321,7 @@ static struct net_device_stats *sbmac_get_stats(struct net_device *dev); static void sbmac_set_rx_mode(struct net_device *dev); static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static int sbmac_close(struct net_device *dev); -static int sbmac_poll(struct net_device *poll_dev, int *budget); +static int sbmac_poll(struct napi_struct *napi, int budget); static int sbmac_mii_poll(struct sbmac_softc *s,int noisy); static int sbmac_mii_probe(struct net_device *dev); @@ -2154,20 +2155,13 @@ static irqreturn_t sbmac_intr(int irq,void *dev_instance) * Transmits on channel 0 */ - if (isr & (M_MAC_INT_CHANNEL << S_MAC_TX_CH0)) { + if (isr & (M_MAC_INT_CHANNEL << S_MAC_TX_CH0)) sbdma_tx_process(sc,&(sc->sbm_txdma), 0); -#ifdef CONFIG_NETPOLL_TRAP - if (netpoll_trap()) { - if (test_and_clear_bit(__LINK_STATE_XOFF, &dev->state)) - __netif_schedule(dev); - } -#endif - } if (isr & (M_MAC_INT_CHANNEL << S_MAC_RX_CH0)) { - if (netif_rx_schedule_prep(dev)) { + if (netif_rx_schedule_prep(dev, &sc->napi)) { __raw_writeq(0, sc->sbm_imr); - __netif_rx_schedule(dev); + __netif_rx_schedule(dev, &sc->napi); /* Depend on the exit from poll to reenable intr */ } else { @@ -2470,8 +2464,8 @@ static int sbmac_init(struct net_device *dev, int idx) dev->do_ioctl = sbmac_mii_ioctl; dev->tx_timeout = sbmac_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; - dev->poll = sbmac_poll; - dev->weight = 16; + + netif_napi_add(dev, &sc->napi, sbmac_poll, 16); dev->change_mtu = sb1250_change_mtu; #ifdef CONFIG_NET_POLL_CONTROLLER @@ -2537,6 +2531,8 @@ static int sbmac_open(struct net_device *dev) return -EINVAL; } + napi_enable(&sc->napi); + /* * Configure default speed */ @@ -2850,6 +2846,8 @@ static int sbmac_close(struct net_device *dev) unsigned long flags; int irq; + napi_disable(&sc->napi); + sbmac_set_channel_state(sc,sbmac_state_off); del_timer_sync(&sc->sbm_timer); @@ -2874,26 +2872,17 @@ static int sbmac_close(struct net_device *dev) return 0; } -static int sbmac_poll(struct net_device *dev, int *budget) +static int sbmac_poll(struct napi_struct *napi, int budget) { - int work_to_do; + struct sbmac_softc *sc = container_of(napi, struct sbmac_softc, napi); + struct net_device *dev = sc->sbm_dev; int work_done; - struct sbmac_softc *sc = netdev_priv(dev); - - work_to_do = min(*budget, dev->quota); - work_done = sbdma_rx_process(sc, &(sc->sbm_rxdma), work_to_do, 1); - - if (work_done > work_to_do) - printk(KERN_ERR "%s exceeded work_to_do budget=%d quota=%d work-done=%d\n", - sc->sbm_dev->name, *budget, dev->quota, work_done); + work_done = sbdma_rx_process(sc, &(sc->sbm_rxdma), budget, 1); sbdma_tx_process(sc, &(sc->sbm_txdma), 1); - *budget -= work_done; - dev->quota -= work_done; - - if (work_done < work_to_do) { - netif_rx_complete(dev); + if (work_done < budget) { + netif_rx_complete(dev, napi); #ifdef CONFIG_SBMAC_COALESCE __raw_writeq(((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_TX_CH0) | @@ -2905,7 +2894,7 @@ static int sbmac_poll(struct net_device *dev, int *budget) #endif } - return (work_done >= work_to_do); + return work_done; } #if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR) || defined(SBMAC_ETH3_HWADDR) diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index d470b19c081..038ccfbafdd 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c @@ -47,24 +47,13 @@ #define PHY_ID_ANY 0x1f #define MII_REG_ANY 0x1f -#ifdef CONFIG_SIS190_NAPI -#define NAPI_SUFFIX "-NAPI" -#else -#define NAPI_SUFFIX "" -#endif - -#define DRV_VERSION "1.2" NAPI_SUFFIX +#define DRV_VERSION "1.2" #define DRV_NAME "sis190" #define SIS190_DRIVER_NAME DRV_NAME " Gigabit Ethernet driver " DRV_VERSION #define PFX DRV_NAME ": " -#ifdef CONFIG_SIS190_NAPI -#define sis190_rx_skb netif_receive_skb -#define sis190_rx_quota(count, quota) min(count, quota) -#else #define sis190_rx_skb netif_rx #define sis190_rx_quota(count, quota) count -#endif #define MAC_ADDR_LEN 6 @@ -1115,10 +1104,8 @@ static void sis190_down(struct net_device *dev) synchronize_irq(dev->irq); - if (!poll_locked) { - netif_poll_disable(dev); + if (!poll_locked) poll_locked++; - } synchronize_sched(); @@ -1137,8 +1124,6 @@ static int sis190_close(struct net_device *dev) free_irq(dev->irq, dev); - netif_poll_enable(dev); - pci_free_consistent(pdev, TX_RING_BYTES, tp->TxDescRing, tp->tx_dma); pci_free_consistent(pdev, RX_RING_BYTES, tp->RxDescRing, tp->rx_dma); diff --git a/drivers/net/skge.c b/drivers/net/skge.c index e3d8520209b..0bf46ed4e68 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -2528,7 +2528,7 @@ static int skge_up(struct net_device *dev) skge_write32(hw, B0_IMSK, hw->intr_mask); spin_unlock_irq(&hw->hw_lock); - netif_poll_enable(dev); + napi_enable(&skge->napi); return 0; free_rx_ring: @@ -2558,7 +2558,7 @@ static int skge_down(struct net_device *dev) if (hw->chip_id == CHIP_ID_GENESIS && hw->phy_type == SK_PHY_XMAC) del_timer_sync(&skge->link_timer); - netif_poll_disable(dev); + napi_disable(&skge->napi); netif_carrier_off(dev); spin_lock_irq(&hw->hw_lock); @@ -3044,14 +3044,13 @@ static void skge_tx_done(struct net_device *dev) } } -static int skge_poll(struct net_device *dev, int *budget) +static int skge_poll(struct napi_struct *napi, int to_do) { - struct skge_port *skge = netdev_priv(dev); + struct skge_port *skge = container_of(napi, struct skge_port, napi); + struct net_device *dev = skge->netdev; struct skge_hw *hw = skge->hw; struct skge_ring *ring = &skge->rx_ring; struct skge_element *e; - unsigned long flags; - int to_do = min(dev->quota, *budget); int work_done = 0; skge_tx_done(dev); @@ -3082,20 +3081,16 @@ static int skge_poll(struct net_device *dev, int *budget) wmb(); skge_write8(hw, Q_ADDR(rxqaddr[skge->port], Q_CSR), CSR_START); - *budget -= work_done; - dev->quota -= work_done; - - if (work_done >= to_do) - return 1; /* not done */ - - spin_lock_irqsave(&hw->hw_lock, flags); - __netif_rx_complete(dev); - hw->intr_mask |= napimask[skge->port]; - skge_write32(hw, B0_IMSK, hw->intr_mask); - skge_read32(hw, B0_IMSK); - spin_unlock_irqrestore(&hw->hw_lock, flags); + if (work_done < to_do) { + spin_lock_irq(&hw->hw_lock); + __netif_rx_complete(dev, napi); + hw->intr_mask |= napimask[skge->port]; + skge_write32(hw, B0_IMSK, hw->intr_mask); + skge_read32(hw, B0_IMSK); + spin_unlock_irq(&hw->hw_lock); + } - return 0; + return work_done; } /* Parity errors seem to happen when Genesis is connected to a switch @@ -3252,8 +3247,9 @@ static irqreturn_t skge_intr(int irq, void *dev_id) } if (status & (IS_XA1_F|IS_R1_F)) { + struct skge_port *skge = netdev_priv(hw->dev[0]); hw->intr_mask &= ~(IS_XA1_F|IS_R1_F); - netif_rx_schedule(hw->dev[0]); + netif_rx_schedule(hw->dev[0], &skge->napi); } if (status & IS_PA_TO_TX1) @@ -3271,13 +3267,14 @@ static irqreturn_t skge_intr(int irq, void *dev_id) skge_mac_intr(hw, 0); if (hw->dev[1]) { + struct skge_port *skge = netdev_priv(hw->dev[1]); + if (status & (IS_XA2_F|IS_R2_F)) { hw->intr_mask &= ~(IS_XA2_F|IS_R2_F); - netif_rx_schedule(hw->dev[1]); + netif_rx_schedule(hw->dev[1], &skge->napi); } if (status & IS_PA_TO_RX2) { - struct skge_port *skge = netdev_priv(hw->dev[1]); ++skge->net_stats.rx_over_errors; skge_write16(hw, B3_PA_CTRL, PA_CLR_TO_RX2); } @@ -3569,8 +3566,6 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port, SET_ETHTOOL_OPS(dev, &skge_ethtool_ops); dev->tx_timeout = skge_tx_timeout; dev->watchdog_timeo = TX_WATCHDOG; - dev->poll = skge_poll; - dev->weight = NAPI_WEIGHT; #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = skge_netpoll; #endif @@ -3580,6 +3575,7 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port, dev->features |= NETIF_F_HIGHDMA; skge = netdev_priv(dev); + netif_napi_add(dev, &skge->napi, skge_poll, NAPI_WEIGHT); skge->netdev = dev; skge->hw = hw; skge->msg_enable = netif_msg_init(debug, default_msg); diff --git a/drivers/net/skge.h b/drivers/net/skge.h index edd71468220..dd0fd45c715 100644 --- a/drivers/net/skge.h +++ b/drivers/net/skge.h @@ -2448,6 +2448,7 @@ enum pause_status { struct skge_port { struct skge_hw *hw; struct net_device *netdev; + struct napi_struct napi; int port; u32 msg_enable; diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index ea117fc3d5e..a0d75b0f379 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1130,7 +1130,7 @@ static void sky2_vlan_rx_register(struct net_device *dev, struct vlan_group *grp u16 port = sky2->port; netif_tx_lock_bh(dev); - netif_poll_disable(sky2->hw->dev[0]); + napi_disable(&hw->napi); sky2->vlgrp = grp; if (grp) { @@ -1145,7 +1145,7 @@ static void sky2_vlan_rx_register(struct net_device *dev, struct vlan_group *grp TX_VLAN_TAG_OFF); } - netif_poll_enable(sky2->hw->dev[0]); + napi_enable(&hw->napi); netif_tx_unlock_bh(dev); } #endif @@ -1385,9 +1385,13 @@ static int sky2_up(struct net_device *dev) sky2_prefetch_init(hw, txqaddr[port], sky2->tx_le_map, TX_RING_SIZE - 1); + napi_enable(&hw->napi); + err = sky2_rx_start(sky2); - if (err) + if (err) { + napi_disable(&hw->napi); goto err_out; + } /* Enable interrupts from phy/mac for port */ imask = sky2_read32(hw, B0_IMSK); @@ -1676,6 +1680,8 @@ static int sky2_down(struct net_device *dev) /* Stop more packets from being queued */ netif_stop_queue(dev); + napi_disable(&hw->napi); + /* Disable port IRQ */ imask = sky2_read32(hw, B0_IMSK); imask &= ~portirq_msk[port]; @@ -2016,7 +2022,7 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu) dev->trans_start = jiffies; /* prevent tx timeout */ netif_stop_queue(dev); - netif_poll_disable(hw->dev[0]); + napi_disable(&hw->napi); synchronize_irq(hw->pdev->irq); @@ -2043,12 +2049,16 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu) err = sky2_rx_start(sky2); sky2_write32(hw, B0_IMSK, imask); + /* Unconditionally re-enable NAPI because even if we + * call dev_close() that will do a napi_disable(). + */ + napi_enable(&hw->napi); + if (err) dev_close(dev); else { gma_write16(hw, port, GM_GP_CTRL, ctl); - netif_poll_enable(hw->dev[0]); netif_wake_queue(dev); } @@ -2544,18 +2554,15 @@ static int sky2_rx_hung(struct net_device *dev) static void sky2_watchdog(unsigned long arg) { struct sky2_hw *hw = (struct sky2_hw *) arg; - struct net_device *dev; /* Check for lost IRQ once a second */ if (sky2_read32(hw, B0_ISRC)) { - dev = hw->dev[0]; - if (__netif_rx_schedule_prep(dev)) - __netif_rx_schedule(dev); + napi_schedule(&hw->napi); } else { int i, active = 0; for (i = 0; i < hw->ports; i++) { - dev = hw->dev[i]; + struct net_device *dev = hw->dev[i]; if (!netif_running(dev)) continue; ++active; @@ -2605,11 +2612,11 @@ static void sky2_err_intr(struct sky2_hw *hw, u32 status) sky2_le_error(hw, 1, Q_XA2, TX_RING_SIZE); } -static int sky2_poll(struct net_device *dev0, int *budget) +static int sky2_poll(struct napi_struct *napi, int work_limit) { - struct sky2_hw *hw = ((struct sky2_port *) netdev_priv(dev0))->hw; - int work_done; + struct sky2_hw *hw = container_of(napi, struct sky2_hw, napi); u32 status = sky2_read32(hw, B0_Y2_SP_EISR); + int work_done; if (unlikely(status & Y2_IS_ERROR)) sky2_err_intr(hw, status); @@ -2620,31 +2627,27 @@ static int sky2_poll(struct net_device *dev0, int *budget) if (status & Y2_IS_IRQ_PHY2) sky2_phy_intr(hw, 1); - work_done = sky2_status_intr(hw, min(dev0->quota, *budget)); - *budget -= work_done; - dev0->quota -= work_done; + work_done = sky2_status_intr(hw, work_limit); /* More work? */ - if (hw->st_idx != sky2_read16(hw, STAT_PUT_IDX)) - return 1; + if (hw->st_idx == sky2_read16(hw, STAT_PUT_IDX)) { + /* Bug/Errata workaround? + * Need to kick the TX irq moderation timer. + */ + if (sky2_read8(hw, STAT_TX_TIMER_CTRL) == TIM_START) { + sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_STOP); + sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_START); + } - /* Bug/Errata workaround? - * Need to kick the TX irq moderation timer. - */ - if (sky2_read8(hw, STAT_TX_TIMER_CTRL) == TIM_START) { - sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_STOP); - sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_START); + napi_complete(napi); + sky2_read32(hw, B0_Y2_SP_LISR); } - netif_rx_complete(dev0); - - sky2_read32(hw, B0_Y2_SP_LISR); - return 0; + return work_done; } static irqreturn_t sky2_intr(int irq, void *dev_id) { struct sky2_hw *hw = dev_id; - struct net_device *dev0 = hw->dev[0]; u32 status; /* Reading this mask interrupts as side effect */ @@ -2653,8 +2656,8 @@ static irqreturn_t sky2_intr(int irq, void *dev_id) return IRQ_NONE; prefetch(&hw->st_le[hw->st_idx]); - if (likely(__netif_rx_schedule_prep(dev0))) - __netif_rx_schedule(dev0); + + napi_schedule(&hw->napi); return IRQ_HANDLED; } @@ -2663,10 +2666,8 @@ static irqreturn_t sky2_intr(int irq, void *dev_id) static void sky2_netpoll(struct net_device *dev) { struct sky2_port *sky2 = netdev_priv(dev); - struct net_device *dev0 = sky2->hw->dev[0]; - if (netif_running(dev) && __netif_rx_schedule_prep(dev0)) - __netif_rx_schedule(dev0); + napi_schedule(&sky2->hw->napi); } #endif @@ -2914,8 +2915,6 @@ static void sky2_restart(struct work_struct *work) sky2_write32(hw, B0_IMSK, 0); sky2_read32(hw, B0_IMSK); - netif_poll_disable(hw->dev[0]); - for (i = 0; i < hw->ports; i++) { dev = hw->dev[i]; if (netif_running(dev)) @@ -2924,7 +2923,6 @@ static void sky2_restart(struct work_struct *work) sky2_reset(hw); sky2_write32(hw, B0_IMSK, Y2_IS_BASE); - netif_poll_enable(hw->dev[0]); for (i = 0; i < hw->ports; i++) { dev = hw->dev[i]; @@ -3735,7 +3733,7 @@ static int sky2_debug_show(struct seq_file *seq, void *v) { struct net_device *dev = seq->private; const struct sky2_port *sky2 = netdev_priv(dev); - const struct sky2_hw *hw = sky2->hw; + struct sky2_hw *hw = sky2->hw; unsigned port = sky2->port; unsigned idx, last; int sop; @@ -3748,7 +3746,7 @@ static int sky2_debug_show(struct seq_file *seq, void *v) sky2_read32(hw, B0_IMSK), sky2_read32(hw, B0_Y2_SP_ICR)); - netif_poll_disable(hw->dev[0]); + napi_disable(&hw->napi); last = sky2_read16(hw, STAT_PUT_IDX); if (hw->st_idx == last) @@ -3818,7 +3816,7 @@ static int sky2_debug_show(struct seq_file *seq, void *v) last = sky2_read16(hw, Y2_QADDR(rxqaddr[port], PREF_UNIT_PUT_IDX)), sky2_read16(hw, Y2_QADDR(rxqaddr[port], PREF_UNIT_LAST_IDX))); - netif_poll_enable(hw->dev[0]); + napi_enable(&hw->napi); return 0; } @@ -3943,15 +3941,8 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, SET_ETHTOOL_OPS(dev, &sky2_ethtool_ops); dev->tx_timeout = sky2_tx_timeout; dev->watchdog_timeo = TX_WATCHDOG; - if (port == 0) - dev->poll = sky2_poll; - dev->weight = NAPI_WEIGHT; #ifdef CONFIG_NET_POLL_CONTROLLER - /* Network console (only works on port 0) - * because netpoll makes assumptions about NAPI - */ - if (port == 0) - dev->poll_controller = sky2_netpoll; + dev->poll_controller = sky2_netpoll; #endif sky2 = netdev_priv(dev); @@ -4166,6 +4157,7 @@ static int __devinit sky2_probe(struct pci_dev *pdev, err = -ENOMEM; goto err_out_free_pci; } + netif_napi_add(dev, &hw->napi, sky2_poll, NAPI_WEIGHT); if (!disable_msi && pci_enable_msi(pdev) == 0) { err = sky2_test_msi(hw); @@ -4288,8 +4280,6 @@ static int sky2_suspend(struct pci_dev *pdev, pm_message_t state) if (!hw) return 0; - netif_poll_disable(hw->dev[0]); - for (i = 0; i < hw->ports; i++) { struct net_device *dev = hw->dev[i]; struct sky2_port *sky2 = netdev_priv(dev); @@ -4356,8 +4346,6 @@ static int sky2_resume(struct pci_dev *pdev) } } - netif_poll_enable(hw->dev[0]); - return 0; out: dev_err(&pdev->dev, "resume failed (%d)\n", err); @@ -4374,7 +4362,7 @@ static void sky2_shutdown(struct pci_dev *pdev) if (!hw) return; - netif_poll_disable(hw->dev[0]); + napi_disable(&hw->napi); for (i = 0; i < hw->ports; i++) { struct net_device *dev = hw->dev[i]; diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index 8bc5c54e3ef..f18f8752118 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -2057,6 +2057,7 @@ struct sky2_port { struct sky2_hw { void __iomem *regs; struct pci_dev *pdev; + struct napi_struct napi; struct net_device *dev[2]; unsigned long flags; #define SKY2_HW_USE_MSI 0x00000001 diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 82d837ab4db..6d8f2bb7e0f 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -1278,34 +1278,26 @@ bad_desc: * (using netif_receive_skb). If all/enough packets are up, the driver * reenables interrupts and returns 0. If not, 1 is returned. */ -static int -spider_net_poll(struct net_device *netdev, int *budget) +static int spider_net_poll(struct napi_struct *napi, int budget) { - struct spider_net_card *card = netdev_priv(netdev); - int packets_to_do, packets_done = 0; - int no_more_packets = 0; - - packets_to_do = min(*budget, netdev->quota); - - while (packets_to_do) { - if (spider_net_decode_one_descr(card)) { - packets_done++; - packets_to_do--; - } else { - /* no more packets for the stack */ - no_more_packets = 1; + struct spider_net_card *card = container_of(napi, struct spider_net_card, napi); + struct net_device *netdev = card->netdev; + int packets_done = 0; + + while (packets_done < budget) { + if (!spider_net_decode_one_descr(card)) break; - } + + packets_done++; } if ((packets_done == 0) && (card->num_rx_ints != 0)) { - no_more_packets = spider_net_resync_tail_ptr(card); + if (!spider_net_resync_tail_ptr(card)) + packets_done = budget; spider_net_resync_head_ptr(card); } card->num_rx_ints = 0; - netdev->quota -= packets_done; - *budget -= packets_done; spider_net_refill_rx_chain(card); spider_net_enable_rxdmac(card); @@ -1313,14 +1305,13 @@ spider_net_poll(struct net_device *netdev, int *budget) /* if all packets are in the stack, enable interrupts and return 0 */ /* if not, return 1 */ - if (no_more_packets) { - netif_rx_complete(netdev); + if (packets_done < budget) { + netif_rx_complete(netdev, napi); spider_net_rx_irq_on(card); card->ignore_rx_ramfull = 0; - return 0; } - return 1; + return packets_done; } /** @@ -1560,7 +1551,8 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg) spider_net_refill_rx_chain(card); spider_net_enable_rxdmac(card); card->num_rx_ints ++; - netif_rx_schedule(card->netdev); + netif_rx_schedule(card->netdev, + &card->napi); } show_error = 0; break; @@ -1580,7 +1572,8 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg) spider_net_refill_rx_chain(card); spider_net_enable_rxdmac(card); card->num_rx_ints ++; - netif_rx_schedule(card->netdev); + netif_rx_schedule(card->netdev, + &card->napi); show_error = 0; break; @@ -1594,7 +1587,8 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg) spider_net_refill_rx_chain(card); spider_net_enable_rxdmac(card); card->num_rx_ints ++; - netif_rx_schedule(card->netdev); + netif_rx_schedule(card->netdev, + &card->napi); show_error = 0; break; @@ -1686,11 +1680,11 @@ spider_net_interrupt(int irq, void *ptr) if (status_reg & SPIDER_NET_RXINT ) { spider_net_rx_irq_off(card); - netif_rx_schedule(netdev); + netif_rx_schedule(netdev, &card->napi); card->num_rx_ints ++; } if (status_reg & SPIDER_NET_TXINT) - netif_rx_schedule(netdev); + netif_rx_schedule(netdev, &card->napi); if (status_reg & SPIDER_NET_LINKINT) spider_net_link_reset(netdev); @@ -2034,7 +2028,7 @@ spider_net_open(struct net_device *netdev) netif_start_queue(netdev); netif_carrier_on(netdev); - netif_poll_enable(netdev); + napi_enable(&card->napi); spider_net_enable_interrupts(card); @@ -2204,7 +2198,7 @@ spider_net_stop(struct net_device *netdev) { struct spider_net_card *card = netdev_priv(netdev); - netif_poll_disable(netdev); + napi_disable(&card->napi); netif_carrier_off(netdev); netif_stop_queue(netdev); del_timer_sync(&card->tx_timer); @@ -2304,9 +2298,6 @@ spider_net_setup_netdev_ops(struct net_device *netdev) /* tx watchdog */ netdev->tx_timeout = &spider_net_tx_timeout; netdev->watchdog_timeo = SPIDER_NET_WATCHDOG_TIMEOUT; - /* NAPI */ - netdev->poll = &spider_net_poll; - netdev->weight = SPIDER_NET_NAPI_WEIGHT; /* HW VLAN */ #ifdef CONFIG_NET_POLL_CONTROLLER /* poll controller */ @@ -2351,6 +2342,9 @@ spider_net_setup_netdev(struct spider_net_card *card) card->options.rx_csum = SPIDER_NET_RX_CSUM_DEFAULT; + netif_napi_add(netdev, &card->napi, + spider_net_poll, SPIDER_NET_NAPI_WEIGHT); + spider_net_setup_netdev_ops(netdev); netdev->features = NETIF_F_IP_CSUM | NETIF_F_LLTX; diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h index dbbdb8cee3c..a2fcdebc379 100644 --- a/drivers/net/spider_net.h +++ b/drivers/net/spider_net.h @@ -466,6 +466,8 @@ struct spider_net_card { struct pci_dev *pdev; struct mii_phy phy; + struct napi_struct napi; + int medium; void __iomem *regs; diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index 8b6478663a5..3b9336c3420 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -178,16 +178,13 @@ static int full_duplex[MAX_UNITS] = {0, }; #define skb_num_frags(skb) (skb_shinfo(skb)->nr_frags + 1) #ifdef HAVE_NETDEV_POLL -#define init_poll(dev) \ -do { \ - dev->poll = &netdev_poll; \ - dev->weight = max_interrupt_work; \ -} while (0) -#define netdev_rx(dev, ioaddr) \ +#define init_poll(dev, np) \ + netif_napi_add(dev, &np->napi, netdev_poll, max_interrupt_work) +#define netdev_rx(dev, np, ioaddr) \ do { \ u32 intr_enable; \ - if (netif_rx_schedule_prep(dev)) { \ - __netif_rx_schedule(dev); \ + if (netif_rx_schedule_prep(dev, &np->napi)) { \ + __netif_rx_schedule(dev, &np->napi); \ intr_enable = readl(ioaddr + IntrEnable); \ intr_enable &= ~(IntrRxDone | IntrRxEmpty); \ writel(intr_enable, ioaddr + IntrEnable); \ @@ -204,12 +201,12 @@ do { \ } while (0) #define netdev_receive_skb(skb) netif_receive_skb(skb) #define vlan_netdev_receive_skb(skb, vlgrp, vlid) vlan_hwaccel_receive_skb(skb, vlgrp, vlid) -static int netdev_poll(struct net_device *dev, int *budget); +static int netdev_poll(struct napi_struct *napi, int budget); #else /* not HAVE_NETDEV_POLL */ -#define init_poll(dev) +#define init_poll(dev, np) #define netdev_receive_skb(skb) netif_rx(skb) #define vlan_netdev_receive_skb(skb, vlgrp, vlid) vlan_hwaccel_rx(skb, vlgrp, vlid) -#define netdev_rx(dev, ioaddr) \ +#define netdev_rx(dev, np, ioaddr) \ do { \ int quota = np->dirty_rx + RX_RING_SIZE - np->cur_rx; \ __netdev_rx(dev, "a);\ @@ -599,6 +596,8 @@ struct netdev_private { struct tx_done_desc *tx_done_q; dma_addr_t tx_done_q_dma; unsigned int tx_done; + struct napi_struct napi; + struct net_device *dev; struct net_device_stats stats; struct pci_dev *pci_dev; #ifdef VLAN_SUPPORT @@ -791,6 +790,7 @@ static int __devinit starfire_init_one(struct pci_dev *pdev, dev->irq = irq; np = netdev_priv(dev); + np->dev = dev; np->base = base; spin_lock_init(&np->lock); pci_set_drvdata(pdev, dev); @@ -851,7 +851,7 @@ static int __devinit starfire_init_one(struct pci_dev *pdev, dev->hard_start_xmit = &start_tx; dev->tx_timeout = tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; - init_poll(dev); + init_poll(dev, np); dev->stop = &netdev_close; dev->get_stats = &get_stats; dev->set_multicast_list = &set_rx_mode; @@ -1056,6 +1056,9 @@ static int netdev_open(struct net_device *dev) writel(np->intr_timer_ctrl, ioaddr + IntrTimerCtrl); +#ifdef HAVE_NETDEV_POLL + napi_enable(&np->napi); +#endif netif_start_queue(dev); if (debug > 1) @@ -1330,7 +1333,7 @@ static irqreturn_t intr_handler(int irq, void *dev_instance) handled = 1; if (intr_status & (IntrRxDone | IntrRxEmpty)) - netdev_rx(dev, ioaddr); + netdev_rx(dev, np, ioaddr); /* Scavenge the skbuff list based on the Tx-done queue. There are redundant checks here that may be cleaned up @@ -1531,36 +1534,35 @@ static int __netdev_rx(struct net_device *dev, int *quota) #ifdef HAVE_NETDEV_POLL -static int netdev_poll(struct net_device *dev, int *budget) +static int netdev_poll(struct napi_struct *napi, int budget) { + struct netdev_private *np = container_of(napi, struct netdev_private, napi); + struct net_device *dev = np->dev; u32 intr_status; - struct netdev_private *np = netdev_priv(dev); void __iomem *ioaddr = np->base; - int retcode = 0, quota = dev->quota; + int quota = budget; do { writel(IntrRxDone | IntrRxEmpty, ioaddr + IntrClear); - retcode = __netdev_rx(dev, "a); - *budget -= (dev->quota - quota); - dev->quota = quota; - if (retcode) + if (__netdev_rx(dev, "a)) goto out; intr_status = readl(ioaddr + IntrStatus); } while (intr_status & (IntrRxDone | IntrRxEmpty)); - netif_rx_complete(dev); + netif_rx_complete(dev, napi); intr_status = readl(ioaddr + IntrEnable); intr_status |= IntrRxDone | IntrRxEmpty; writel(intr_status, ioaddr + IntrEnable); out: if (debug > 5) - printk(KERN_DEBUG " exiting netdev_poll(): %d.\n", retcode); + printk(KERN_DEBUG " exiting netdev_poll(): %d.\n", + budget - quota); /* Restart Rx engine if stopped. */ - return retcode; + return budget - quota; } #endif /* HAVE_NETDEV_POLL */ @@ -1904,6 +1906,9 @@ static int netdev_close(struct net_device *dev) int i; netif_stop_queue(dev); +#ifdef HAVE_NETDEV_POLL + napi_disable(&np->napi); +#endif if (debug > 1) { printk(KERN_DEBUG "%s: Shutting down ethercard, Intr status %#8.8x.\n", diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index 43280385503..bf821e96f7b 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -19,7 +19,7 @@ * * gem_change_mtu() and gem_set_multicast() are called with a read_lock() * help by net/core/dev.c, thus they can't schedule. That means they can't - * call netif_poll_disable() neither, thus force gem_poll() to keep a spinlock + * call napi_disable() neither, thus force gem_poll() to keep a spinlock * where it could have been dropped. change_mtu especially would love also to * be able to msleep instead of horrid locked delays when resetting the HW, * but that read_lock() makes it impossible, unless I defer it's action to @@ -878,19 +878,20 @@ static int gem_rx(struct gem *gp, int work_to_do) return work_done; } -static int gem_poll(struct net_device *dev, int *budget) +static int gem_poll(struct napi_struct *napi, int budget) { - struct gem *gp = dev->priv; + struct gem *gp = container_of(napi, struct gem, napi); + struct net_device *dev = gp->dev; unsigned long flags; + int work_done; /* * NAPI locking nightmare: See comment at head of driver */ spin_lock_irqsave(&gp->lock, flags); + work_done = 0; do { - int work_to_do, work_done; - /* Handle anomalies */ if (gp->status & GREG_STAT_ABNORMAL) { if (gem_abnormal_irq(dev, gp, gp->status)) @@ -906,29 +907,25 @@ static int gem_poll(struct net_device *dev, int *budget) /* Run RX thread. We don't use any locking here, * code willing to do bad things - like cleaning the - * rx ring - must call netif_poll_disable(), which + * rx ring - must call napi_disable(), which * schedule_timeout()'s if polling is already disabled. */ - work_to_do = min(*budget, dev->quota); - - work_done = gem_rx(gp, work_to_do); - - *budget -= work_done; - dev->quota -= work_done; + work_done += gem_rx(gp, budget); - if (work_done >= work_to_do) - return 1; + if (work_done >= budget) + return work_done; spin_lock_irqsave(&gp->lock, flags); gp->status = readl(gp->regs + GREG_STAT); } while (gp->status & GREG_STAT_NAPI); - __netif_rx_complete(dev); + __netif_rx_complete(dev, napi); gem_enable_ints(gp); spin_unlock_irqrestore(&gp->lock, flags); - return 0; + + return work_done; } static irqreturn_t gem_interrupt(int irq, void *dev_id) @@ -946,17 +943,17 @@ static irqreturn_t gem_interrupt(int irq, void *dev_id) spin_lock_irqsave(&gp->lock, flags); - if (netif_rx_schedule_prep(dev)) { + if (netif_rx_schedule_prep(dev, &gp->napi)) { u32 gem_status = readl(gp->regs + GREG_STAT); if (gem_status == 0) { - netif_poll_enable(dev); + napi_enable(&gp->napi); spin_unlock_irqrestore(&gp->lock, flags); return IRQ_NONE; } gp->status = gem_status; gem_disable_ints(gp); - __netif_rx_schedule(dev); + __netif_rx_schedule(dev, &gp->napi); } spin_unlock_irqrestore(&gp->lock, flags); @@ -2284,7 +2281,7 @@ static void gem_reset_task(struct work_struct *work) mutex_lock(&gp->pm_mutex); - netif_poll_disable(gp->dev); + napi_disable(&gp->napi); spin_lock_irq(&gp->lock); spin_lock(&gp->tx_lock); @@ -2307,7 +2304,7 @@ static void gem_reset_task(struct work_struct *work) spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); - netif_poll_enable(gp->dev); + napi_enable(&gp->napi); mutex_unlock(&gp->pm_mutex); } @@ -2324,6 +2321,8 @@ static int gem_open(struct net_device *dev) if (!gp->asleep) rc = gem_do_start(dev); gp->opened = (rc == 0); + if (gp->opened) + napi_enable(&gp->napi); mutex_unlock(&gp->pm_mutex); @@ -2334,9 +2333,7 @@ static int gem_close(struct net_device *dev) { struct gem *gp = dev->priv; - /* Note: we don't need to call netif_poll_disable() here because - * our caller (dev_close) already did it for us - */ + napi_disable(&gp->napi); mutex_lock(&gp->pm_mutex); @@ -2358,7 +2355,7 @@ static int gem_suspend(struct pci_dev *pdev, pm_message_t state) mutex_lock(&gp->pm_mutex); - netif_poll_disable(dev); + napi_disable(&gp->napi); printk(KERN_INFO "%s: suspending, WakeOnLan %s\n", dev->name, @@ -2482,7 +2479,7 @@ static int gem_resume(struct pci_dev *pdev) spin_unlock(&gp->tx_lock); spin_unlock_irqrestore(&gp->lock, flags); - netif_poll_enable(dev); + napi_enable(&gp->napi); mutex_unlock(&gp->pm_mutex); @@ -3121,8 +3118,7 @@ static int __devinit gem_init_one(struct pci_dev *pdev, dev->get_stats = gem_get_stats; dev->set_multicast_list = gem_set_multicast; dev->do_ioctl = gem_ioctl; - dev->poll = gem_poll; - dev->weight = 64; + netif_napi_add(dev, &gp->napi, gem_poll, 64); dev->ethtool_ops = &gem_ethtool_ops; dev->tx_timeout = gem_tx_timeout; dev->watchdog_timeo = 5 * HZ; diff --git a/drivers/net/sungem.h b/drivers/net/sungem.h index 58cf87c5751..76d760acc9e 100644 --- a/drivers/net/sungem.h +++ b/drivers/net/sungem.h @@ -993,6 +993,7 @@ struct gem { u32 msg_enable; u32 status; + struct napi_struct napi; struct net_device_stats net_stats; int tx_fifo_sz; diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c index ec41469eee8..b5e0dff6723 100644 --- a/drivers/net/tc35815.c +++ b/drivers/net/tc35815.c @@ -414,6 +414,9 @@ enum tc35815_timer_state { struct tc35815_local { struct pci_dev *pci_dev; + struct net_device *dev; + struct napi_struct napi; + /* statistics */ struct net_device_stats stats; struct { @@ -566,7 +569,7 @@ static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev); static irqreturn_t tc35815_interrupt(int irq, void *dev_id); #ifdef TC35815_NAPI static int tc35815_rx(struct net_device *dev, int limit); -static int tc35815_poll(struct net_device *dev, int *budget); +static int tc35815_poll(struct napi_struct *napi, int budget); #else static void tc35815_rx(struct net_device *dev); #endif @@ -685,6 +688,7 @@ static int __devinit tc35815_init_one (struct pci_dev *pdev, SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); lp = dev->priv; + lp->dev = dev; /* enable device (incl. PCI PM wakeup), and bus-mastering */ rc = pci_enable_device (pdev); @@ -738,8 +742,7 @@ static int __devinit tc35815_init_one (struct pci_dev *pdev, dev->tx_timeout = tc35815_tx_timeout; dev->watchdog_timeo = TC35815_TX_TIMEOUT; #ifdef TC35815_NAPI - dev->poll = tc35815_poll; - dev->weight = NAPI_WEIGHT; + netif_napi_add(dev, &lp->napi, tc35815_poll, NAPI_WEIGHT); #endif #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = tc35815_poll_controller; @@ -748,8 +751,6 @@ static int __devinit tc35815_init_one (struct pci_dev *pdev, dev->irq = pdev->irq; dev->base_addr = (unsigned long) ioaddr; - /* dev->priv/lp zeroed and aligned in alloc_etherdev */ - lp = dev->priv; spin_lock_init(&lp->lock); lp->pci_dev = pdev; lp->boardtype = ent->driver_data; @@ -1237,6 +1238,10 @@ tc35815_open(struct net_device *dev) return -EAGAIN; } +#ifdef TC35815_NAPI + napi_enable(&lp->napi); +#endif + /* Reset the hardware here. Don't forget to set the station address. */ spin_lock_irq(&lp->lock); tc35815_chip_init(dev); @@ -1436,6 +1441,7 @@ static int tc35815_do_interrupt(struct net_device *dev, u32 status) static irqreturn_t tc35815_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; + struct tc35815_local *lp = netdev_priv(dev); struct tc35815_regs __iomem *tr = (struct tc35815_regs __iomem *)dev->base_addr; #ifdef TC35815_NAPI @@ -1444,8 +1450,8 @@ static irqreturn_t tc35815_interrupt(int irq, void *dev_id) if (!(dmactl & DMA_IntMask)) { /* disable interrupts */ tc_writel(dmactl | DMA_IntMask, &tr->DMA_Ctl); - if (netif_rx_schedule_prep(dev)) - __netif_rx_schedule(dev); + if (netif_rx_schedule_prep(dev, &lp->napi)) + __netif_rx_schedule(dev, &lp->napi); else { printk(KERN_ERR "%s: interrupt taken in poll\n", dev->name); @@ -1726,13 +1732,12 @@ tc35815_rx(struct net_device *dev) } #ifdef TC35815_NAPI -static int -tc35815_poll(struct net_device *dev, int *budget) +static int tc35815_poll(struct napi_struct *napi, int budget) { - struct tc35815_local *lp = dev->priv; + struct tc35815_local *lp = container_of(napi, struct tc35815_local, napi); + struct net_device *dev = lp->dev; struct tc35815_regs __iomem *tr = (struct tc35815_regs __iomem *)dev->base_addr; - int limit = min(*budget, dev->quota); int received = 0, handled; u32 status; @@ -1744,23 +1749,19 @@ tc35815_poll(struct net_device *dev, int *budget) handled = tc35815_do_interrupt(dev, status, limit); if (handled >= 0) { received += handled; - limit -= handled; - if (limit <= 0) + if (received >= budget) break; } status = tc_readl(&tr->Int_Src); } while (status); spin_unlock(&lp->lock); - dev->quota -= received; - *budget -= received; - if (limit <= 0) - return 1; - - netif_rx_complete(dev); - /* enable interrupts */ - tc_writel(tc_readl(&tr->DMA_Ctl) & ~DMA_IntMask, &tr->DMA_Ctl); - return 0; + if (received < budget) { + netif_rx_complete(dev, napi); + /* enable interrupts */ + tc_writel(tc_readl(&tr->DMA_Ctl) & ~DMA_IntMask, &tr->DMA_Ctl); + } + return received; } #endif @@ -1949,7 +1950,11 @@ static int tc35815_close(struct net_device *dev) { struct tc35815_local *lp = dev->priv; + netif_stop_queue(dev); +#ifdef TC35815_NAPI + napi_disable(&lp->napi); +#endif /* Flush the Tx and disable Rx here. */ diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 9034a05734e..ef1e3d1173c 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -574,7 +574,7 @@ static void tg3_restart_ints(struct tg3 *tp) static inline void tg3_netif_stop(struct tg3 *tp) { tp->dev->trans_start = jiffies; /* prevent tx timeout */ - netif_poll_disable(tp->dev); + napi_disable(&tp->napi); netif_tx_disable(tp->dev); } @@ -585,7 +585,7 @@ static inline void tg3_netif_start(struct tg3 *tp) * so long as all callers are assured to have free tx slots * (such as after tg3_init_hw) */ - netif_poll_enable(tp->dev); + napi_enable(&tp->napi); tp->hw_status->status |= SD_STATUS_UPDATED; tg3_enable_ints(tp); } @@ -3471,11 +3471,12 @@ next_pkt_nopost: return received; } -static int tg3_poll(struct net_device *netdev, int *budget) +static int tg3_poll(struct napi_struct *napi, int budget) { - struct tg3 *tp = netdev_priv(netdev); + struct tg3 *tp = container_of(napi, struct tg3, napi); + struct net_device *netdev = tp->dev; struct tg3_hw_status *sblk = tp->hw_status; - int done; + int work_done = 0; /* handle link change and other phy events */ if (!(tp->tg3_flags & @@ -3494,7 +3495,7 @@ static int tg3_poll(struct net_device *netdev, int *budget) if (sblk->idx[0].tx_consumer != tp->tx_cons) { tg3_tx(tp); if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING)) { - netif_rx_complete(netdev); + netif_rx_complete(netdev, napi); schedule_work(&tp->reset_task); return 0; } @@ -3502,20 +3503,10 @@ static int tg3_poll(struct net_device *netdev, int *budget) /* run RX thread, within the bounds set by NAPI. * All RX "locking" is done by ensuring outside - * code synchronizes with dev->poll() + * code synchronizes with tg3->napi.poll() */ - if (sblk->idx[0].rx_producer != tp->rx_rcb_ptr) { - int orig_budget = *budget; - int work_done; - - if (orig_budget > netdev->quota) - orig_budget = netdev->quota; - - work_done = tg3_rx(tp, orig_budget); - - *budget -= work_done; - netdev->quota -= work_done; - } + if (sblk->idx[0].rx_producer != tp->rx_rcb_ptr) + work_done = tg3_rx(tp, budget); if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) { tp->last_tag = sblk->status_tag; @@ -3524,13 +3515,12 @@ static int tg3_poll(struct net_device *netdev, int *budget) sblk->status &= ~SD_STATUS_UPDATED; /* if no more work, tell net stack and NIC we're done */ - done = !tg3_has_work(tp); - if (done) { - netif_rx_complete(netdev); + if (!tg3_has_work(tp)) { + netif_rx_complete(netdev, napi); tg3_restart_ints(tp); } - return (done ? 0 : 1); + return work_done; } static void tg3_irq_quiesce(struct tg3 *tp) @@ -3577,7 +3567,7 @@ static irqreturn_t tg3_msi_1shot(int irq, void *dev_id) prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]); if (likely(!tg3_irq_sync(tp))) - netif_rx_schedule(dev); /* schedule NAPI poll */ + netif_rx_schedule(dev, &tp->napi); return IRQ_HANDLED; } @@ -3602,7 +3592,7 @@ static irqreturn_t tg3_msi(int irq, void *dev_id) */ tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001); if (likely(!tg3_irq_sync(tp))) - netif_rx_schedule(dev); /* schedule NAPI poll */ + netif_rx_schedule(dev, &tp->napi); return IRQ_RETVAL(1); } @@ -3644,7 +3634,7 @@ static irqreturn_t tg3_interrupt(int irq, void *dev_id) sblk->status &= ~SD_STATUS_UPDATED; if (likely(tg3_has_work(tp))) { prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]); - netif_rx_schedule(dev); /* schedule NAPI poll */ + netif_rx_schedule(dev, &tp->napi); } else { /* No work, shared interrupt perhaps? re-enable * interrupts, and flush that PCI write @@ -3690,7 +3680,7 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id) tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001); if (tg3_irq_sync(tp)) goto out; - if (netif_rx_schedule_prep(dev)) { + if (netif_rx_schedule_prep(dev, &tp->napi)) { prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]); /* Update last_tag to mark that this status has been * seen. Because interrupt may be shared, we may be @@ -3698,7 +3688,7 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id) * if tg3_poll() is not scheduled. */ tp->last_tag = sblk->status_tag; - __netif_rx_schedule(dev); + __netif_rx_schedule(dev, &tp->napi); } out: return IRQ_RETVAL(handled); @@ -3737,7 +3727,7 @@ static int tg3_restart_hw(struct tg3 *tp, int reset_phy) tg3_full_unlock(tp); del_timer_sync(&tp->timer); tp->irq_sync = 0; - netif_poll_enable(tp->dev); + napi_enable(&tp->napi); dev_close(tp->dev); tg3_full_lock(tp, 0); } @@ -3932,7 +3922,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) len = skb_headlen(skb); /* We are running in BH disabled context with netif_tx_lock - * and TX reclaim runs via tp->poll inside of a software + * and TX reclaim runs via tp->napi.poll inside of a software * interrupt. Furthermore, IRQ processing runs lockless so we have * no IRQ context deadlocks to worry about either. Rejoice! */ @@ -4087,7 +4077,7 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev) len = skb_headlen(skb); /* We are running in BH disabled context with netif_tx_lock - * and TX reclaim runs via tp->poll inside of a software + * and TX reclaim runs via tp->napi.poll inside of a software * interrupt. Furthermore, IRQ processing runs lockless so we have * no IRQ context deadlocks to worry about either. Rejoice! */ @@ -7147,6 +7137,8 @@ static int tg3_open(struct net_device *dev) return err; } + napi_enable(&tp->napi); + tg3_full_lock(tp, 0); err = tg3_init_hw(tp, 1); @@ -7174,6 +7166,7 @@ static int tg3_open(struct net_device *dev) tg3_full_unlock(tp); if (err) { + napi_disable(&tp->napi); free_irq(tp->pdev->irq, dev); if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { pci_disable_msi(tp->pdev); @@ -7199,6 +7192,8 @@ static int tg3_open(struct net_device *dev) tg3_full_unlock(tp); + napi_disable(&tp->napi); + return err; } @@ -7460,6 +7455,7 @@ static int tg3_close(struct net_device *dev) { struct tg3 *tp = netdev_priv(dev); + napi_disable(&tp->napi); cancel_work_sync(&tp->reset_task); netif_stop_queue(dev); @@ -11900,9 +11896,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, dev->set_mac_address = tg3_set_mac_addr; dev->do_ioctl = tg3_ioctl; dev->tx_timeout = tg3_tx_timeout; - dev->poll = tg3_poll; + netif_napi_add(dev, &tp->napi, tg3_poll, 64); dev->ethtool_ops = &tg3_ethtool_ops; - dev->weight = 64; dev->watchdog_timeo = TG3_TX_TIMEOUT; dev->change_mtu = tg3_change_mtu; dev->irq = pdev->irq; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 5c21f49026c..a6a23bbcdfe 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2176,6 +2176,7 @@ struct tg3 { dma_addr_t tx_desc_mapping; /* begin "rx thread" cacheline section */ + struct napi_struct napi; void (*write32_rx_mbox) (struct tg3 *, u32, u32); u32 rx_rcb_ptr; diff --git a/drivers/net/tsi108_eth.c b/drivers/net/tsi108_eth.c index 1aabc91f645..b3069ee34bd 100644 --- a/drivers/net/tsi108_eth.c +++ b/drivers/net/tsi108_eth.c @@ -79,6 +79,9 @@ struct tsi108_prv_data { void __iomem *regs; /* Base of normal regs */ void __iomem *phyregs; /* Base of register bank used for PHY access */ + struct net_device *dev; + struct napi_struct napi; + unsigned int phy; /* Index of PHY for this interface */ unsigned int irq_num; unsigned int id; @@ -837,13 +840,13 @@ static int tsi108_refill_rx(struct net_device *dev, int budget) return done; } -static int tsi108_poll(struct net_device *dev, int *budget) +static int tsi108_poll(struct napi_struct *napi, int budget) { - struct tsi108_prv_data *data = netdev_priv(dev); + struct tsi108_prv_data *data = container_of(napi, struct tsi108_prv_data, napi); + struct net_device *dev = data->dev; u32 estat = TSI_READ(TSI108_EC_RXESTAT); u32 intstat = TSI_READ(TSI108_EC_INTSTAT); - int total_budget = min(*budget, dev->quota); - int num_received = 0, num_filled = 0, budget_used; + int num_received = 0, num_filled = 0; intstat &= TSI108_INT_RXQUEUE0 | TSI108_INT_RXTHRESH | TSI108_INT_RXOVERRUN | TSI108_INT_RXERROR | TSI108_INT_RXWAIT; @@ -852,7 +855,7 @@ static int tsi108_poll(struct net_device *dev, int *budget) TSI_WRITE(TSI108_EC_INTSTAT, intstat); if (data->rxpending || (estat & TSI108_EC_RXESTAT_Q0_DESCINT)) - num_received = tsi108_complete_rx(dev, total_budget); + num_received = tsi108_complete_rx(dev, budget); /* This should normally fill no more slots than the number of * packets received in tsi108_complete_rx(). The exception @@ -867,7 +870,7 @@ static int tsi108_poll(struct net_device *dev, int *budget) */ if (data->rxfree < TSI108_RXRING_LEN) - num_filled = tsi108_refill_rx(dev, total_budget * 2); + num_filled = tsi108_refill_rx(dev, budget * 2); if (intstat & TSI108_INT_RXERROR) { u32 err = TSI_READ(TSI108_EC_RXERR); @@ -890,14 +893,9 @@ static int tsi108_poll(struct net_device *dev, int *budget) spin_unlock_irq(&data->misclock); } - budget_used = max(num_received, num_filled / 2); - - *budget -= budget_used; - dev->quota -= budget_used; - - if (budget_used != total_budget) { + if (num_received < budget) { data->rxpending = 0; - netif_rx_complete(dev); + netif_rx_complete(dev, napi); TSI_WRITE(TSI108_EC_INTMASK, TSI_READ(TSI108_EC_INTMASK) @@ -906,14 +904,11 @@ static int tsi108_poll(struct net_device *dev, int *budget) TSI108_INT_RXOVERRUN | TSI108_INT_RXERROR | TSI108_INT_RXWAIT)); - - /* IRQs are level-triggered, so no need to re-check */ - return 0; } else { data->rxpending = 1; } - return 1; + return num_received; } static void tsi108_rx_int(struct net_device *dev) @@ -931,7 +926,7 @@ static void tsi108_rx_int(struct net_device *dev) * from tsi108_check_rxring(). */ - if (netif_rx_schedule_prep(dev)) { + if (netif_rx_schedule_prep(dev, &data->napi)) { /* Mask, rather than ack, the receive interrupts. The ack * will happen in tsi108_poll(). */ @@ -942,7 +937,7 @@ static void tsi108_rx_int(struct net_device *dev) | TSI108_INT_RXTHRESH | TSI108_INT_RXOVERRUN | TSI108_INT_RXERROR | TSI108_INT_RXWAIT); - __netif_rx_schedule(dev); + __netif_rx_schedule(dev, &data->napi); } else { if (!netif_running(dev)) { /* This can happen if an interrupt occurs while the @@ -1401,6 +1396,8 @@ static int tsi108_open(struct net_device *dev) TSI_WRITE(TSI108_EC_TXQ_PTRLOW, data->txdma); tsi108_init_phy(dev); + napi_enable(&data->napi); + setup_timer(&data->timer, tsi108_timed_checker, (unsigned long)dev); mod_timer(&data->timer, jiffies + 1); @@ -1425,6 +1422,7 @@ static int tsi108_close(struct net_device *dev) struct tsi108_prv_data *data = netdev_priv(dev); netif_stop_queue(dev); + napi_disable(&data->napi); del_timer_sync(&data->timer); @@ -1562,6 +1560,7 @@ tsi108_init_one(struct platform_device *pdev) printk("tsi108_eth%d: probe...\n", pdev->id); data = netdev_priv(dev); + data->dev = dev; pr_debug("tsi108_eth%d:regs:phyresgs:phy:irq_num=0x%x:0x%x:0x%x:0x%x\n", pdev->id, einfo->regs, einfo->phyregs, @@ -1597,9 +1596,8 @@ tsi108_init_one(struct platform_device *pdev) dev->set_mac_address = tsi108_set_mac; dev->set_multicast_list = tsi108_set_rx_mode; dev->get_stats = tsi108_get_stats; - dev->poll = tsi108_poll; + netif_napi_add(dev, &data->napi, tsi108_poll, 64); dev->do_ioctl = tsi108_do_ioctl; - dev->weight = 64; /* 64 is more suitable for GigE interface - klai */ /* Apparently, the Linux networking code won't use scatter-gather * if the hardware doesn't do checksums. However, it's faster diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c index 53efd6694e7..36533144638 100644 --- a/drivers/net/tulip/interrupt.c +++ b/drivers/net/tulip/interrupt.c @@ -103,28 +103,29 @@ int tulip_refill_rx(struct net_device *dev) void oom_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; - netif_rx_schedule(dev); + struct tulip_private *tp = netdev_priv(dev); + netif_rx_schedule(dev, &tp->napi); } -int tulip_poll(struct net_device *dev, int *budget) +int tulip_poll(struct napi_struct *napi, int budget) { - struct tulip_private *tp = netdev_priv(dev); + struct tulip_private *tp = container_of(napi, struct tulip_private, napi); + struct net_device *dev = tp->dev; int entry = tp->cur_rx % RX_RING_SIZE; - int rx_work_limit = *budget; + int work_done = 0; +#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION int received = 0; +#endif if (!netif_running(dev)) goto done; - if (rx_work_limit > dev->quota) - rx_work_limit = dev->quota; - #ifdef CONFIG_TULIP_NAPI_HW_MITIGATION /* that one buffer is needed for mit activation; or might be a bug in the ring buffer code; check later -- JHS*/ - if (rx_work_limit >=RX_RING_SIZE) rx_work_limit--; + if (budget >=RX_RING_SIZE) budget--; #endif if (tulip_debug > 4) @@ -144,14 +145,13 @@ int tulip_poll(struct net_device *dev, int *budget) while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) { s32 status = le32_to_cpu(tp->rx_ring[entry].status); - if (tp->dirty_rx + RX_RING_SIZE == tp->cur_rx) break; if (tulip_debug > 5) printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %8.8x.\n", dev->name, entry, status); - if (--rx_work_limit < 0) + if (work_done++ >= budget) goto not_done; if ((status & 0x38008300) != 0x0300) { @@ -238,7 +238,9 @@ int tulip_poll(struct net_device *dev, int *budget) tp->stats.rx_packets++; tp->stats.rx_bytes += pkt_len; } - received++; +#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION + received++; +#endif entry = (++tp->cur_rx) % RX_RING_SIZE; if (tp->cur_rx - tp->dirty_rx > RX_RING_SIZE/4) @@ -296,17 +298,15 @@ done: #endif /* CONFIG_TULIP_NAPI_HW_MITIGATION */ - dev->quota -= received; - *budget -= received; - tulip_refill_rx(dev); /* If RX ring is not full we are out of memory. */ - if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) goto oom; + if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) + goto oom; /* Remove us from polling list and enable RX intr. */ - netif_rx_complete(dev); + netif_rx_complete(dev, napi); iowrite32(tulip_tbl[tp->chip_id].valid_intrs, tp->base_addr+CSR7); /* The last op happens after poll completion. Which means the following: @@ -320,28 +320,20 @@ done: * processed irqs. But it must not result in losing events. */ - return 0; + return work_done; not_done: - if (!received) { - - received = dev->quota; /* Not to happen */ - } - dev->quota -= received; - *budget -= received; - if (tp->cur_rx - tp->dirty_rx > RX_RING_SIZE/2 || tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) tulip_refill_rx(dev); - if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) goto oom; - - return 1; + if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) + goto oom; + return work_done; oom: /* Executed with RX ints disabled */ - /* Start timer, stop polling, but do not enable rx interrupts. */ mod_timer(&tp->oom_timer, jiffies+1); @@ -350,9 +342,9 @@ done: * before we did netif_rx_complete(). See? We would lose it. */ /* remove ourselves from the polling list */ - netif_rx_complete(dev); + netif_rx_complete(dev, napi); - return 0; + return work_done; } #else /* CONFIG_TULIP_NAPI */ @@ -534,7 +526,7 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance) rxd++; /* Mask RX intrs and add the device to poll list. */ iowrite32(tulip_tbl[tp->chip_id].valid_intrs&~RxPollInt, ioaddr + CSR7); - netif_rx_schedule(dev); + netif_rx_schedule(dev, &tp->napi); if (!(csr5&~(AbnormalIntr|NormalIntr|RxPollInt|TPLnkPass))) break; diff --git a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h index 16f26a8364f..5a4d7270973 100644 --- a/drivers/net/tulip/tulip.h +++ b/drivers/net/tulip/tulip.h @@ -353,6 +353,7 @@ struct tulip_private { int chip_id; int revision; int flags; + struct napi_struct napi; struct net_device_stats stats; struct timer_list timer; /* Media selection timer. */ struct timer_list oom_timer; /* Out of memory timer. */ @@ -429,7 +430,7 @@ extern int tulip_rx_copybreak; irqreturn_t tulip_interrupt(int irq, void *dev_instance); int tulip_refill_rx(struct net_device *dev); #ifdef CONFIG_TULIP_NAPI -int tulip_poll(struct net_device *dev, int *budget); +int tulip_poll(struct napi_struct *napi, int budget); #endif diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index eca984f89bb..7040a59fa3c 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -294,6 +294,10 @@ static void tulip_up(struct net_device *dev) int next_tick = 3*HZ; int i; +#ifdef CONFIG_TULIP_NAPI + napi_enable(&tp->napi); +#endif + /* Wake the chip from sleep/snooze mode. */ tulip_set_power_state (tp, 0, 0); @@ -728,6 +732,10 @@ static void tulip_down (struct net_device *dev) flush_scheduled_work(); +#ifdef CONFIG_TULIP_NAPI + napi_disable(&tp->napi); +#endif + del_timer_sync (&tp->timer); #ifdef CONFIG_TULIP_NAPI del_timer_sync (&tp->oom_timer); @@ -1606,8 +1614,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, dev->tx_timeout = tulip_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; #ifdef CONFIG_TULIP_NAPI - dev->poll = tulip_poll; - dev->weight = 16; + netif_napi_add(dev, &tp->napi, tulip_poll, 16); #endif dev->stop = tulip_close; dev->get_stats = tulip_get_stats; diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index 03587205546..0377b8b64c7 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -284,6 +284,7 @@ struct typhoon { struct basic_ring rxLoRing; struct pci_dev * pdev; struct net_device * dev; + struct napi_struct napi; spinlock_t state_lock; struct vlan_group * vlgrp; struct basic_ring rxHiRing; @@ -1759,12 +1760,12 @@ typhoon_fill_free_ring(struct typhoon *tp) } static int -typhoon_poll(struct net_device *dev, int *total_budget) +typhoon_poll(struct napi_struct *napi, int budget) { - struct typhoon *tp = netdev_priv(dev); + struct typhoon *tp = container_of(napi, struct typhoon, napi); + struct net_device *dev = tp->dev; struct typhoon_indexes *indexes = tp->indexes; - int orig_budget = *total_budget; - int budget, work_done, done; + int work_done; rmb(); if(!tp->awaiting_resp && indexes->respReady != indexes->respCleared) @@ -1773,30 +1774,16 @@ typhoon_poll(struct net_device *dev, int *total_budget) if(le32_to_cpu(indexes->txLoCleared) != tp->txLoRing.lastRead) typhoon_tx_complete(tp, &tp->txLoRing, &indexes->txLoCleared); - if(orig_budget > dev->quota) - orig_budget = dev->quota; - - budget = orig_budget; work_done = 0; - done = 1; if(indexes->rxHiCleared != indexes->rxHiReady) { - work_done = typhoon_rx(tp, &tp->rxHiRing, &indexes->rxHiReady, + work_done += typhoon_rx(tp, &tp->rxHiRing, &indexes->rxHiReady, &indexes->rxHiCleared, budget); - budget -= work_done; } if(indexes->rxLoCleared != indexes->rxLoReady) { work_done += typhoon_rx(tp, &tp->rxLoRing, &indexes->rxLoReady, - &indexes->rxLoCleared, budget); - } - - if(work_done) { - *total_budget -= work_done; - dev->quota -= work_done; - - if(work_done >= orig_budget) - done = 0; + &indexes->rxLoCleared, budget - work_done); } if(le32_to_cpu(indexes->rxBuffCleared) == tp->rxBuffRing.lastWrite) { @@ -1804,14 +1791,14 @@ typhoon_poll(struct net_device *dev, int *total_budget) typhoon_fill_free_ring(tp); } - if(done) { - netif_rx_complete(dev); + if (work_done < budget) { + netif_rx_complete(dev, napi); iowrite32(TYPHOON_INTR_NONE, tp->ioaddr + TYPHOON_REG_INTR_MASK); typhoon_post_pci_writes(tp->ioaddr); } - return (done ? 0 : 1); + return work_done; } static irqreturn_t @@ -1828,10 +1815,10 @@ typhoon_interrupt(int irq, void *dev_instance) iowrite32(intr_status, ioaddr + TYPHOON_REG_INTR_STATUS); - if(netif_rx_schedule_prep(dev)) { + if (netif_rx_schedule_prep(dev, &tp->napi)) { iowrite32(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_MASK); typhoon_post_pci_writes(ioaddr); - __netif_rx_schedule(dev); + __netif_rx_schedule(dev, &tp->napi); } else { printk(KERN_ERR "%s: Error, poll already scheduled\n", dev->name); @@ -2119,9 +2106,13 @@ typhoon_open(struct net_device *dev) if(err < 0) goto out_sleep; + napi_enable(&tp->napi); + err = typhoon_start_runtime(tp); - if(err < 0) + if(err < 0) { + napi_disable(&tp->napi); goto out_irq; + } netif_start_queue(dev); return 0; @@ -2150,6 +2141,7 @@ typhoon_close(struct net_device *dev) struct typhoon *tp = netdev_priv(dev); netif_stop_queue(dev); + napi_disable(&tp->napi); if(typhoon_stop_runtime(tp, WaitSleep) < 0) printk(KERN_ERR "%s: unable to stop runtime\n", dev->name); @@ -2521,8 +2513,7 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dev->stop = typhoon_close; dev->set_multicast_list = typhoon_set_rx_mode; dev->tx_timeout = typhoon_tx_timeout; - dev->poll = typhoon_poll; - dev->weight = 16; + netif_napi_add(dev, &tp->napi, typhoon_poll, 16); dev->watchdog_timeo = TX_TIMEOUT; dev->get_stats = typhoon_get_stats; dev->set_mac_address = typhoon_set_mac_address; diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 9a38dfe45f8..72f617bf252 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -3582,41 +3582,31 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ) } #ifdef CONFIG_UGETH_NAPI -static int ucc_geth_poll(struct net_device *dev, int *budget) +static int ucc_geth_poll(struct napi_struct *napi, int budget) { - struct ucc_geth_private *ugeth = netdev_priv(dev); + struct ucc_geth_private *ugeth = container_of(napi, struct ucc_geth_private, napi); + struct net_device *dev = ugeth->dev; struct ucc_geth_info *ug_info; - struct ucc_fast_private *uccf; - int howmany; - u8 i; - int rx_work_limit; - register u32 uccm; + int howmany, i; ug_info = ugeth->ug_info; - rx_work_limit = *budget; - if (rx_work_limit > dev->quota) - rx_work_limit = dev->quota; - howmany = 0; + for (i = 0; i < ug_info->numQueuesRx; i++) + howmany += ucc_geth_rx(ugeth, i, budget - howmany); - for (i = 0; i < ug_info->numQueuesRx; i++) { - howmany += ucc_geth_rx(ugeth, i, rx_work_limit); - } - - dev->quota -= howmany; - rx_work_limit -= howmany; - *budget -= howmany; + if (howmany < budget) { + struct ucc_fast_private *uccf; + u32 uccm; - if (rx_work_limit > 0) { - netif_rx_complete(dev); + netif_rx_complete(dev, napi); uccf = ugeth->uccf; uccm = in_be32(uccf->p_uccm); uccm |= UCCE_RX_EVENTS; out_be32(uccf->p_uccm, uccm); } - return (rx_work_limit > 0) ? 0 : 1; + return howmany; } #endif /* CONFIG_UGETH_NAPI */ @@ -3651,10 +3641,10 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info) /* check for receive events that require processing */ if (ucce & UCCE_RX_EVENTS) { #ifdef CONFIG_UGETH_NAPI - if (netif_rx_schedule_prep(dev)) { - uccm &= ~UCCE_RX_EVENTS; + if (netif_rx_schedule_prep(dev, &ugeth->napi)) { + uccm &= ~UCCE_RX_EVENTS; out_be32(uccf->p_uccm, uccm); - __netif_rx_schedule(dev); + __netif_rx_schedule(dev, &ugeth->napi); } #else rx_mask = UCCE_RXBF_SINGLE_MASK; @@ -3717,12 +3707,15 @@ static int ucc_geth_open(struct net_device *dev) return err; } +#ifdef CONFIG_UGETH_NAPI + napi_enable(&ugeth->napi); +#endif err = ucc_geth_startup(ugeth); if (err) { if (netif_msg_ifup(ugeth)) ugeth_err("%s: Cannot configure net device, aborting.", dev->name); - return err; + goto out_err; } err = adjust_enet_interface(ugeth); @@ -3730,7 +3723,7 @@ static int ucc_geth_open(struct net_device *dev) if (netif_msg_ifup(ugeth)) ugeth_err("%s: Cannot configure net device, aborting.", dev->name); - return err; + goto out_err; } /* Set MACSTNADDR1, MACSTNADDR2 */ @@ -3748,7 +3741,7 @@ static int ucc_geth_open(struct net_device *dev) if (err) { if (netif_msg_ifup(ugeth)) ugeth_err("%s: Cannot initialize PHY, aborting.", dev->name); - return err; + goto out_err; } phy_start(ugeth->phydev); @@ -3761,7 +3754,7 @@ static int ucc_geth_open(struct net_device *dev) ugeth_err("%s: Cannot get IRQ for net device, aborting.", dev->name); ucc_geth_stop(ugeth); - return err; + goto out_err; } err = ugeth_enable(ugeth, COMM_DIR_RX_AND_TX); @@ -3769,12 +3762,18 @@ static int ucc_geth_open(struct net_device *dev) if (netif_msg_ifup(ugeth)) ugeth_err("%s: Cannot enable net device, aborting.", dev->name); ucc_geth_stop(ugeth); - return err; + goto out_err; } netif_start_queue(dev); return err; + +out_err: +#ifdef CONFIG_UGETH_NAPI + napi_disable(&ugeth->napi); +#endif + return err; } /* Stops the kernel queue, and halts the controller */ @@ -3784,6 +3783,10 @@ static int ucc_geth_close(struct net_device *dev) ugeth_vdbg("%s: IN", __FUNCTION__); +#ifdef CONFIG_UGETH_NAPI + napi_disable(&ugeth->napi); +#endif + ucc_geth_stop(ugeth); phy_disconnect(ugeth->phydev); @@ -3964,8 +3967,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma dev->tx_timeout = ucc_geth_timeout; dev->watchdog_timeo = TX_TIMEOUT; #ifdef CONFIG_UGETH_NAPI - dev->poll = ucc_geth_poll; - dev->weight = UCC_GETH_DEV_WEIGHT; + netif_napi_add(dev, &ugeth->napi, ucc_geth_poll, UCC_GETH_DEV_WEIGHT); #endif /* CONFIG_UGETH_NAPI */ dev->stop = ucc_geth_close; dev->get_stats = ucc_geth_get_stats; diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h index bb4dac8c0c6..0579ba081aa 100644 --- a/drivers/net/ucc_geth.h +++ b/drivers/net/ucc_geth.h @@ -1184,6 +1184,7 @@ struct ucc_geth_private { struct ucc_geth_info *ug_info; struct ucc_fast_private *uccf; struct net_device *dev; + struct napi_struct napi; struct net_device_stats stats; /* linux network statistics */ struct ucc_geth *ug_regs; struct ucc_geth_init_pram *p_init_enet_param_shadow; diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index b56dff26772..7a5899059c4 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -389,6 +389,8 @@ struct rhine_private { struct pci_dev *pdev; long pioaddr; + struct net_device *dev; + struct napi_struct napi; struct net_device_stats stats; spinlock_t lock; @@ -582,28 +584,25 @@ static void rhine_poll(struct net_device *dev) #endif #ifdef CONFIG_VIA_RHINE_NAPI -static int rhine_napipoll(struct net_device *dev, int *budget) +static int rhine_napipoll(struct napi_struct *napi, int budget) { - struct rhine_private *rp = netdev_priv(dev); + struct rhine_private *rp = container_of(napi, struct rhine_private, napi); + struct net_device *dev = rp->dev; void __iomem *ioaddr = rp->base; - int done, limit = min(dev->quota, *budget); + int work_done; - done = rhine_rx(dev, limit); - *budget -= done; - dev->quota -= done; + work_done = rhine_rx(dev, budget); - if (done < limit) { - netif_rx_complete(dev); + if (work_done < budget) { + netif_rx_complete(dev, napi); iowrite16(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow | IntrRxDropped | IntrRxNoBuf | IntrTxAborted | IntrTxDone | IntrTxError | IntrTxUnderrun | IntrPCIErr | IntrStatsMax | IntrLinkChange, ioaddr + IntrEnable); - return 0; } - else - return 1; + return work_done; } #endif @@ -707,6 +706,7 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, SET_NETDEV_DEV(dev, &pdev->dev); rp = netdev_priv(dev); + rp->dev = dev; rp->quirks = quirks; rp->pioaddr = pioaddr; rp->pdev = pdev; @@ -785,8 +785,7 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, dev->poll_controller = rhine_poll; #endif #ifdef CONFIG_VIA_RHINE_NAPI - dev->poll = rhine_napipoll; - dev->weight = 64; + netif_napi_add(dev, &rp->napi, rhine_napipoll, 64); #endif if (rp->quirks & rqRhineI) dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM; @@ -1061,7 +1060,9 @@ static void init_registers(struct net_device *dev) rhine_set_rx_mode(dev); - netif_poll_enable(dev); +#ifdef CONFIG_VIA_RHINE_NAPI + napi_enable(&rp->napi); +#endif /* Enable interrupts by setting the interrupt mask. */ iowrite16(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow | @@ -1196,6 +1197,10 @@ static void rhine_tx_timeout(struct net_device *dev) /* protect against concurrent rx interrupts */ disable_irq(rp->pdev->irq); +#ifdef CONFIG_VIA_RHINE_NAPI + napi_disable(&rp->napi); +#endif + spin_lock(&rp->lock); /* clear all descriptors */ @@ -1324,7 +1329,7 @@ static irqreturn_t rhine_interrupt(int irq, void *dev_instance) IntrPCIErr | IntrStatsMax | IntrLinkChange, ioaddr + IntrEnable); - netif_rx_schedule(dev); + netif_rx_schedule(dev, &rp->napi); #else rhine_rx(dev, RX_RING_SIZE); #endif @@ -1837,7 +1842,9 @@ static int rhine_close(struct net_device *dev) spin_lock_irq(&rp->lock); netif_stop_queue(dev); - netif_poll_disable(dev); +#ifdef CONFIG_VIA_RHINE_NAPI + napi_disable(&rp->napi); +#endif if (debug > 1) printk(KERN_DEBUG "%s: Shutting down ethercard, " @@ -1936,6 +1943,9 @@ static int rhine_suspend(struct pci_dev *pdev, pm_message_t state) if (!netif_running(dev)) return 0; +#ifdef CONFIG_VIA_RHINE_NAPI + napi_disable(&rp->napi); +#endif netif_device_detach(dev); pci_save_state(pdev); diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 4445810335a..70e551c19e3 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -72,6 +72,7 @@ struct netfront_info { struct list_head list; struct net_device *netdev; + struct napi_struct napi; struct net_device_stats stats; struct xen_netif_tx_front_ring tx; @@ -185,7 +186,8 @@ static int xennet_can_sg(struct net_device *dev) static void rx_refill_timeout(unsigned long data) { struct net_device *dev = (struct net_device *)data; - netif_rx_schedule(dev); + struct netfront_info *np = netdev_priv(dev); + netif_rx_schedule(dev, &np->napi); } static int netfront_tx_slot_available(struct netfront_info *np) @@ -342,12 +344,14 @@ static int xennet_open(struct net_device *dev) memset(&np->stats, 0, sizeof(np->stats)); + napi_enable(&np->napi); + spin_lock_bh(&np->rx_lock); if (netif_carrier_ok(dev)) { xennet_alloc_rx_buffers(dev); np->rx.sring->rsp_event = np->rx.rsp_cons + 1; if (RING_HAS_UNCONSUMED_RESPONSES(&np->rx)) - netif_rx_schedule(dev); + netif_rx_schedule(dev, &np->napi); } spin_unlock_bh(&np->rx_lock); @@ -589,6 +593,7 @@ static int xennet_close(struct net_device *dev) { struct netfront_info *np = netdev_priv(dev); netif_stop_queue(np->netdev); + napi_disable(&np->napi); return 0; } @@ -872,15 +877,16 @@ static int handle_incoming_queue(struct net_device *dev, return packets_dropped; } -static int xennet_poll(struct net_device *dev, int *pbudget) +static int xennet_poll(struct napi_struct *napi, int budget) { - struct netfront_info *np = netdev_priv(dev); + struct netfront_info *np = container_of(napi, struct netfront_info, napi); + struct net_device *dev = np->netdev; struct sk_buff *skb; struct netfront_rx_info rinfo; struct xen_netif_rx_response *rx = &rinfo.rx; struct xen_netif_extra_info *extras = rinfo.extras; RING_IDX i, rp; - int work_done, budget, more_to_do = 1; + int work_done; struct sk_buff_head rxq; struct sk_buff_head errq; struct sk_buff_head tmpq; @@ -899,9 +905,6 @@ static int xennet_poll(struct net_device *dev, int *pbudget) skb_queue_head_init(&errq); skb_queue_head_init(&tmpq); - budget = *pbudget; - if (budget > dev->quota) - budget = dev->quota; rp = np->rx.sring->rsp_prod; rmb(); /* Ensure we see queued responses up to 'rp'. */ @@ -1006,22 +1009,21 @@ err: xennet_alloc_rx_buffers(dev); - *pbudget -= work_done; - dev->quota -= work_done; - if (work_done < budget) { + int more_to_do = 0; + local_irq_save(flags); RING_FINAL_CHECK_FOR_RESPONSES(&np->rx, more_to_do); if (!more_to_do) - __netif_rx_complete(dev); + __netif_rx_complete(dev, napi); local_irq_restore(flags); } spin_unlock(&np->rx_lock); - return more_to_do; + return work_done; } static int xennet_change_mtu(struct net_device *dev, int mtu) @@ -1201,10 +1203,9 @@ static struct net_device * __devinit xennet_create_dev(struct xenbus_device *dev netdev->hard_start_xmit = xennet_start_xmit; netdev->stop = xennet_close; netdev->get_stats = xennet_get_stats; - netdev->poll = xennet_poll; + netif_napi_add(netdev, &np->napi, xennet_poll, 64); netdev->uninit = xennet_uninit; netdev->change_mtu = xennet_change_mtu; - netdev->weight = 64; netdev->features = NETIF_F_IP_CSUM; SET_ETHTOOL_OPS(netdev, &xennet_ethtool_ops); @@ -1349,7 +1350,7 @@ static irqreturn_t xennet_interrupt(int irq, void *dev_id) xennet_tx_buf_gc(dev); /* Under tx_lock: protects access to rx shared-ring indexes. */ if (RING_HAS_UNCONSUMED_RESPONSES(&np->rx)) - netif_rx_schedule(dev); + netif_rx_schedule(dev, &np->napi); } spin_unlock_irqrestore(&np->tx_lock, flags); diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index e679b275166..b93575db8cc 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -31,6 +31,7 @@ #ifdef __KERNEL__ #include +#include #include #include #include @@ -38,6 +39,7 @@ #include #include #include +#include struct vlan_group; struct ethtool_ops; @@ -258,7 +260,6 @@ enum netdev_state_t __LINK_STATE_PRESENT, __LINK_STATE_SCHED, __LINK_STATE_NOCARRIER, - __LINK_STATE_RX_SCHED, __LINK_STATE_LINKWATCH_PENDING, __LINK_STATE_DORMANT, __LINK_STATE_QDISC_RUNNING, @@ -277,6 +278,110 @@ struct netdev_boot_setup { extern int __init netdev_boot_setup(char *str); +/* + * Structure for NAPI scheduling similar to tasklet but with weighting + */ +struct napi_struct { + /* The poll_list must only be managed by the entity which + * changes the state of the NAPI_STATE_SCHED bit. This means + * whoever atomically sets that bit can add this napi_struct + * to the per-cpu poll_list, and whoever clears that bit + * can remove from the list right before clearing the bit. + */ + struct list_head poll_list; + + unsigned long state; + int weight; + int (*poll)(struct napi_struct *, int); +#ifdef CONFIG_NETPOLL + spinlock_t poll_lock; + int poll_owner; + struct net_device *dev; + struct list_head dev_list; +#endif +}; + +enum +{ + NAPI_STATE_SCHED, /* Poll is scheduled */ +}; + +extern void FASTCALL(__napi_schedule(struct napi_struct *n)); + +/** + * napi_schedule_prep - check if napi can be scheduled + * @n: napi context + * + * Test if NAPI routine is already running, and if not mark + * it as running. This is used as a condition variable + * insure only one NAPI poll instance runs + */ +static inline int napi_schedule_prep(struct napi_struct *n) +{ + return !test_and_set_bit(NAPI_STATE_SCHED, &n->state); +} + +/** + * napi_schedule - schedule NAPI poll + * @n: napi context + * + * Schedule NAPI poll routine to be called if it is not already + * running. + */ +static inline void napi_schedule(struct napi_struct *n) +{ + if (napi_schedule_prep(n)) + __napi_schedule(n); +} + +/** + * napi_complete - NAPI processing complete + * @n: napi context + * + * Mark NAPI processing as complete. + */ +static inline void __napi_complete(struct napi_struct *n) +{ + BUG_ON(!test_bit(NAPI_STATE_SCHED, &n->state)); + list_del(&n->poll_list); + smp_mb__before_clear_bit(); + clear_bit(NAPI_STATE_SCHED, &n->state); +} + +static inline void napi_complete(struct napi_struct *n) +{ + local_irq_disable(); + __napi_complete(n); + local_irq_enable(); +} + +/** + * napi_disable - prevent NAPI from scheduling + * @n: napi context + * + * Stop NAPI from being scheduled on this context. + * Waits till any outstanding processing completes. + */ +static inline void napi_disable(struct napi_struct *n) +{ + while (test_and_set_bit(NAPI_STATE_SCHED, &n->state)) + msleep_interruptible(1); +} + +/** + * napi_enable - enable NAPI scheduling + * @n: napi context + * + * Resume NAPI from being scheduled on this context. + * Must be paired with napi_disable. + */ +static inline void napi_enable(struct napi_struct *n) +{ + BUG_ON(!test_bit(NAPI_STATE_SCHED, &n->state)); + smp_mb__before_clear_bit(); + clear_bit(NAPI_STATE_SCHED, &n->state); +} + /* * The DEVICE structure. * Actually, this whole structure is a big mistake. It mixes I/O @@ -319,6 +424,9 @@ struct net_device unsigned long state; struct list_head dev_list; +#ifdef CONFIG_NETPOLL + struct list_head napi_list; +#endif /* The device initialization function. Called only once. */ int (*init)(struct net_device *dev); @@ -430,12 +538,6 @@ struct net_device /* * Cache line mostly used on receive path (including eth_type_trans()) */ - struct list_head poll_list ____cacheline_aligned_in_smp; - /* Link to poll list */ - - int (*poll) (struct net_device *dev, int *quota); - int quota; - int weight; unsigned long last_rx; /* Time of last Rx */ /* Interface address info used in eth_type_trans() */ unsigned char dev_addr[MAX_ADDR_LEN]; /* hw address, (before bcast @@ -582,6 +684,12 @@ struct net_device #define NETDEV_ALIGN 32 #define NETDEV_ALIGN_CONST (NETDEV_ALIGN - 1) +/** + * netdev_priv - access network device private data + * @dev: network device + * + * Get network device private data + */ static inline void *netdev_priv(const struct net_device *dev) { return dev->priv; @@ -593,6 +701,23 @@ static inline void *netdev_priv(const struct net_device *dev) */ #define SET_NETDEV_DEV(net, pdev) ((net)->dev.parent = (pdev)) +static inline void netif_napi_add(struct net_device *dev, + struct napi_struct *napi, + int (*poll)(struct napi_struct *, int), + int weight) +{ + INIT_LIST_HEAD(&napi->poll_list); + napi->poll = poll; + napi->weight = weight; +#ifdef CONFIG_NETPOLL + napi->dev = dev; + list_add(&napi->dev_list, &dev->napi_list); + spin_lock_init(&napi->poll_lock); + napi->poll_owner = -1; +#endif + set_bit(NAPI_STATE_SCHED, &napi->state); +} + struct packet_type { __be16 type; /* This is really htons(ether_type). */ struct net_device *dev; /* NULL is wildcarded here */ @@ -678,7 +803,6 @@ static inline int unregister_gifconf(unsigned int family) * Incoming packets are placed on per-cpu queues so that * no locking is needed. */ - struct softnet_data { struct net_device *output_queue; @@ -686,7 +810,7 @@ struct softnet_data struct list_head poll_list; struct sk_buff *completion_queue; - struct net_device backlog_dev; /* Sorry. 8) */ + struct napi_struct backlog; #ifdef CONFIG_NET_DMA struct dma_chan *net_dma; #endif @@ -704,11 +828,24 @@ static inline void netif_schedule(struct net_device *dev) __netif_schedule(dev); } +/** + * netif_start_queue - allow transmit + * @dev: network device + * + * Allow upper layers to call the device hard_start_xmit routine. + */ static inline void netif_start_queue(struct net_device *dev) { clear_bit(__LINK_STATE_XOFF, &dev->state); } +/** + * netif_wake_queue - restart transmit + * @dev: network device + * + * Allow upper layers to call the device hard_start_xmit routine. + * Used for flow control when transmit resources are available. + */ static inline void netif_wake_queue(struct net_device *dev) { #ifdef CONFIG_NETPOLL_TRAP @@ -721,16 +858,35 @@ static inline void netif_wake_queue(struct net_device *dev) __netif_schedule(dev); } +/** + * netif_stop_queue - stop transmitted packets + * @dev: network device + * + * Stop upper layers calling the device hard_start_xmit routine. + * Used for flow control when transmit resources are unavailable. + */ static inline void netif_stop_queue(struct net_device *dev) { set_bit(__LINK_STATE_XOFF, &dev->state); } +/** + * netif_queue_stopped - test if transmit queue is flowblocked + * @dev: network device + * + * Test if transmit queue on device is currently unable to send. + */ static inline int netif_queue_stopped(const struct net_device *dev) { return test_bit(__LINK_STATE_XOFF, &dev->state); } +/** + * netif_running - test if up + * @dev: network device + * + * Test if the device has been brought up. + */ static inline int netif_running(const struct net_device *dev) { return test_bit(__LINK_STATE_START, &dev->state); @@ -742,6 +898,14 @@ static inline int netif_running(const struct net_device *dev) * done at the overall netdevice level. * Also test the device if we're multiqueue. */ + +/** + * netif_start_subqueue - allow sending packets on subqueue + * @dev: network device + * @queue_index: sub queue index + * + * Start individual transmit queue of a device with multiple transmit queues. + */ static inline void netif_start_subqueue(struct net_device *dev, u16 queue_index) { #ifdef CONFIG_NETDEVICES_MULTIQUEUE @@ -749,6 +913,13 @@ static inline void netif_start_subqueue(struct net_device *dev, u16 queue_index) #endif } +/** + * netif_stop_subqueue - stop sending packets on subqueue + * @dev: network device + * @queue_index: sub queue index + * + * Stop individual transmit queue of a device with multiple transmit queues. + */ static inline void netif_stop_subqueue(struct net_device *dev, u16 queue_index) { #ifdef CONFIG_NETDEVICES_MULTIQUEUE @@ -760,6 +931,13 @@ static inline void netif_stop_subqueue(struct net_device *dev, u16 queue_index) #endif } +/** + * netif_subqueue_stopped - test status of subqueue + * @dev: network device + * @queue_index: sub queue index + * + * Check individual transmit queue of a device with multiple transmit queues. + */ static inline int netif_subqueue_stopped(const struct net_device *dev, u16 queue_index) { @@ -771,6 +949,14 @@ static inline int netif_subqueue_stopped(const struct net_device *dev, #endif } + +/** + * netif_wake_subqueue - allow sending packets on subqueue + * @dev: network device + * @queue_index: sub queue index + * + * Resume individual transmit queue of a device with multiple transmit queues. + */ static inline void netif_wake_subqueue(struct net_device *dev, u16 queue_index) { #ifdef CONFIG_NETDEVICES_MULTIQUEUE @@ -784,6 +970,13 @@ static inline void netif_wake_subqueue(struct net_device *dev, u16 queue_index) #endif } +/** + * netif_is_multiqueue - test if device has multiple transmit queues + * @dev: network device + * + * Check if device has multiple transmit queues + * Always falls if NETDEVICE_MULTIQUEUE is not configured + */ static inline int netif_is_multiqueue(const struct net_device *dev) { #ifdef CONFIG_NETDEVICES_MULTIQUEUE @@ -796,20 +989,7 @@ static inline int netif_is_multiqueue(const struct net_device *dev) /* Use this variant when it is known for sure that it * is executing from interrupt context. */ -static inline void dev_kfree_skb_irq(struct sk_buff *skb) -{ - if (atomic_dec_and_test(&skb->users)) { - struct softnet_data *sd; - unsigned long flags; - - local_irq_save(flags); - sd = &__get_cpu_var(softnet_data); - skb->next = sd->completion_queue; - sd->completion_queue = skb; - raise_softirq_irqoff(NET_TX_SOFTIRQ); - local_irq_restore(flags); - } -} +extern void dev_kfree_skb_irq(struct sk_buff *skb); /* Use this variant in places where it could be invoked * either from interrupt or non-interrupt context. @@ -833,18 +1013,28 @@ extern int dev_set_mac_address(struct net_device *, extern int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev); -extern void dev_init(void); - extern int netdev_budget; /* Called by rtnetlink.c:rtnl_unlock() */ extern void netdev_run_todo(void); +/** + * dev_put - release reference to device + * @dev: network device + * + * Hold reference to device to keep it from being freed. + */ static inline void dev_put(struct net_device *dev) { atomic_dec(&dev->refcnt); } +/** + * dev_hold - get reference to device + * @dev: network device + * + * Release reference to device to allow it to be freed. + */ static inline void dev_hold(struct net_device *dev) { atomic_inc(&dev->refcnt); @@ -861,6 +1051,12 @@ static inline void dev_hold(struct net_device *dev) extern void linkwatch_fire_event(struct net_device *dev); +/** + * netif_carrier_ok - test if carrier present + * @dev: network device + * + * Check if carrier is present on device + */ static inline int netif_carrier_ok(const struct net_device *dev) { return !test_bit(__LINK_STATE_NOCARRIER, &dev->state); @@ -872,30 +1068,66 @@ extern void netif_carrier_on(struct net_device *dev); extern void netif_carrier_off(struct net_device *dev); +/** + * netif_dormant_on - mark device as dormant. + * @dev: network device + * + * Mark device as dormant (as per RFC2863). + * + * The dormant state indicates that the relevant interface is not + * actually in a condition to pass packets (i.e., it is not 'up') but is + * in a "pending" state, waiting for some external event. For "on- + * demand" interfaces, this new state identifies the situation where the + * interface is waiting for events to place it in the up state. + * + */ static inline void netif_dormant_on(struct net_device *dev) { if (!test_and_set_bit(__LINK_STATE_DORMANT, &dev->state)) linkwatch_fire_event(dev); } +/** + * netif_dormant_off - set device as not dormant. + * @dev: network device + * + * Device is not in dormant state. + */ static inline void netif_dormant_off(struct net_device *dev) { if (test_and_clear_bit(__LINK_STATE_DORMANT, &dev->state)) linkwatch_fire_event(dev); } +/** + * netif_dormant - test if carrier present + * @dev: network device + * + * Check if carrier is present on device + */ static inline int netif_dormant(const struct net_device *dev) { return test_bit(__LINK_STATE_DORMANT, &dev->state); } +/** + * netif_oper_up - test if device is operational + * @dev: network device + * + * Check if carrier is operational + */ static inline int netif_oper_up(const struct net_device *dev) { return (dev->operstate == IF_OPER_UP || dev->operstate == IF_OPER_UNKNOWN /* backward compat */); } -/* Hot-plugging. */ +/** + * netif_device_present - is device available or removed + * @dev: network device + * + * Check if device has not been removed from system. + */ static inline int netif_device_present(struct net_device *dev) { return test_bit(__LINK_STATE_PRESENT, &dev->state); @@ -955,46 +1187,38 @@ static inline u32 netif_msg_init(int debug_value, int default_msg_enable_bits) return (1 << debug_value) - 1; } -/* Test if receive needs to be scheduled */ -static inline int __netif_rx_schedule_prep(struct net_device *dev) -{ - return !test_and_set_bit(__LINK_STATE_RX_SCHED, &dev->state); -} - /* Test if receive needs to be scheduled but only if up */ -static inline int netif_rx_schedule_prep(struct net_device *dev) +static inline int netif_rx_schedule_prep(struct net_device *dev, + struct napi_struct *napi) { - return netif_running(dev) && __netif_rx_schedule_prep(dev); + return netif_running(dev) && napi_schedule_prep(napi); } /* Add interface to tail of rx poll list. This assumes that _prep has * already been called and returned 1. */ - -extern void __netif_rx_schedule(struct net_device *dev); +static inline void __netif_rx_schedule(struct net_device *dev, + struct napi_struct *napi) +{ + dev_hold(dev); + __napi_schedule(napi); +} /* Try to reschedule poll. Called by irq handler. */ -static inline void netif_rx_schedule(struct net_device *dev) +static inline void netif_rx_schedule(struct net_device *dev, + struct napi_struct *napi) { - if (netif_rx_schedule_prep(dev)) - __netif_rx_schedule(dev); + if (netif_rx_schedule_prep(dev, napi)) + __netif_rx_schedule(dev, napi); } -/* Try to reschedule poll. Called by dev->poll() after netif_rx_complete(). - * Do not inline this? - */ -static inline int netif_rx_reschedule(struct net_device *dev, int undo) +/* Try to reschedule poll. Called by dev->poll() after netif_rx_complete(). */ +static inline int netif_rx_reschedule(struct net_device *dev, + struct napi_struct *napi) { - if (netif_rx_schedule_prep(dev)) { - unsigned long flags; - - dev->quota += undo; - - local_irq_save(flags); - list_add_tail(&dev->poll_list, &__get_cpu_var(softnet_data).poll_list); - __raise_softirq_irqoff(NET_RX_SOFTIRQ); - local_irq_restore(flags); + if (napi_schedule_prep(napi)) { + __netif_rx_schedule(dev, napi); return 1; } return 0; @@ -1003,12 +1227,11 @@ static inline int netif_rx_reschedule(struct net_device *dev, int undo) /* same as netif_rx_complete, except that local_irq_save(flags) * has already been issued */ -static inline void __netif_rx_complete(struct net_device *dev) +static inline void __netif_rx_complete(struct net_device *dev, + struct napi_struct *napi) { - BUG_ON(!test_bit(__LINK_STATE_RX_SCHED, &dev->state)); - list_del(&dev->poll_list); - smp_mb__before_clear_bit(); - clear_bit(__LINK_STATE_RX_SCHED, &dev->state); + __napi_complete(napi); + dev_put(dev); } /* Remove interface from poll list: it must be in the poll list @@ -1016,28 +1239,22 @@ static inline void __netif_rx_complete(struct net_device *dev) * it completes the work. The device cannot be out of poll list at this * moment, it is BUG(). */ -static inline void netif_rx_complete(struct net_device *dev) +static inline void netif_rx_complete(struct net_device *dev, + struct napi_struct *napi) { unsigned long flags; local_irq_save(flags); - __netif_rx_complete(dev); + __netif_rx_complete(dev, napi); local_irq_restore(flags); } -static inline void netif_poll_disable(struct net_device *dev) -{ - while (test_and_set_bit(__LINK_STATE_RX_SCHED, &dev->state)) - /* No hurry. */ - schedule_timeout_interruptible(1); -} - -static inline void netif_poll_enable(struct net_device *dev) -{ - smp_mb__before_clear_bit(); - clear_bit(__LINK_STATE_RX_SCHED, &dev->state); -} - +/** + * netif_tx_lock - grab network device transmit lock + * @dev: network device + * + * Get network device transmit lock + */ static inline void netif_tx_lock(struct net_device *dev) { spin_lock(&dev->_xmit_lock); diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h index 29930b71a9a..08dcc39ec18 100644 --- a/include/linux/netpoll.h +++ b/include/linux/netpoll.h @@ -25,8 +25,6 @@ struct netpoll { struct netpoll_info { atomic_t refcnt; - spinlock_t poll_lock; - int poll_owner; int rx_flags; spinlock_t rx_lock; struct netpoll *rx_np; /* netpoll that registered an rx_hook */ @@ -64,32 +62,61 @@ static inline int netpoll_rx(struct sk_buff *skb) return ret; } -static inline void *netpoll_poll_lock(struct net_device *dev) +static inline int netpoll_receive_skb(struct sk_buff *skb) { + if (!list_empty(&skb->dev->napi_list)) + return netpoll_rx(skb); + return 0; +} + +static inline void *netpoll_poll_lock(struct napi_struct *napi) +{ + struct net_device *dev = napi->dev; + rcu_read_lock(); /* deal with race on ->npinfo */ - if (dev->npinfo) { - spin_lock(&dev->npinfo->poll_lock); - dev->npinfo->poll_owner = smp_processor_id(); - return dev->npinfo; + if (dev && dev->npinfo) { + spin_lock(&napi->poll_lock); + napi->poll_owner = smp_processor_id(); + return napi; } return NULL; } static inline void netpoll_poll_unlock(void *have) { - struct netpoll_info *npi = have; + struct napi_struct *napi = have; - if (npi) { - npi->poll_owner = -1; - spin_unlock(&npi->poll_lock); + if (napi) { + napi->poll_owner = -1; + spin_unlock(&napi->poll_lock); } rcu_read_unlock(); } +static inline void netpoll_netdev_init(struct net_device *dev) +{ + INIT_LIST_HEAD(&dev->napi_list); +} + #else -#define netpoll_rx(a) 0 -#define netpoll_poll_lock(a) NULL -#define netpoll_poll_unlock(a) +static inline int netpoll_rx(struct sk_buff *skb) +{ + return 0; +} +static inline int netpoll_receive_skb(struct sk_buff *skb) +{ + return 0; +} +static inline void *netpoll_poll_lock(struct napi_struct *napi) +{ + return NULL; +} +static inline void netpoll_poll_unlock(void *have) +{ +} +static inline void netpoll_netdev_init(struct net_device *dev) +{ +} #endif #endif diff --git a/net/core/dev.c b/net/core/dev.c index a76021c7120..29cf00c5d86 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -220,7 +220,8 @@ static RAW_NOTIFIER_HEAD(netdev_chain); * Device drivers call our routines to queue packets here. We empty the * queue in the local softnet handler. */ -DEFINE_PER_CPU(struct softnet_data, softnet_data) = { NULL }; + +DEFINE_PER_CPU(struct softnet_data, softnet_data); #ifdef CONFIG_SYSFS extern int netdev_sysfs_init(void); @@ -1018,16 +1019,12 @@ int dev_close(struct net_device *dev) clear_bit(__LINK_STATE_START, &dev->state); /* Synchronize to scheduled poll. We cannot touch poll list, - * it can be even on different cpu. So just clear netif_running(), - * and wait when poll really will happen. Actually, the best place - * for this is inside dev->stop() after device stopped its irq - * engine, but this requires more changes in devices. */ - + * it can be even on different cpu. So just clear netif_running(). + * + * dev->stop() will invoke napi_disable() on all of it's + * napi_struct instances on this device. + */ smp_mb__after_clear_bit(); /* Commit netif_running(). */ - while (test_bit(__LINK_STATE_RX_SCHED, &dev->state)) { - /* No hurry. */ - msleep(1); - } /* * Call the device specific close. This cannot fail. @@ -1233,21 +1230,21 @@ void __netif_schedule(struct net_device *dev) } EXPORT_SYMBOL(__netif_schedule); -void __netif_rx_schedule(struct net_device *dev) +void dev_kfree_skb_irq(struct sk_buff *skb) { - unsigned long flags; + if (atomic_dec_and_test(&skb->users)) { + struct softnet_data *sd; + unsigned long flags; - local_irq_save(flags); - dev_hold(dev); - list_add_tail(&dev->poll_list, &__get_cpu_var(softnet_data).poll_list); - if (dev->quota < 0) - dev->quota += dev->weight; - else - dev->quota = dev->weight; - __raise_softirq_irqoff(NET_RX_SOFTIRQ); - local_irq_restore(flags); + local_irq_save(flags); + sd = &__get_cpu_var(softnet_data); + skb->next = sd->completion_queue; + sd->completion_queue = skb; + raise_softirq_irqoff(NET_TX_SOFTIRQ); + local_irq_restore(flags); + } } -EXPORT_SYMBOL(__netif_rx_schedule); +EXPORT_SYMBOL(dev_kfree_skb_irq); void dev_kfree_skb_any(struct sk_buff *skb) { @@ -1259,7 +1256,12 @@ void dev_kfree_skb_any(struct sk_buff *skb) EXPORT_SYMBOL(dev_kfree_skb_any); -/* Hot-plugging. */ +/** + * netif_device_detach - mark device as removed + * @dev: network device + * + * Mark device as removed from system and therefore no longer available. + */ void netif_device_detach(struct net_device *dev) { if (test_and_clear_bit(__LINK_STATE_PRESENT, &dev->state) && @@ -1269,6 +1271,12 @@ void netif_device_detach(struct net_device *dev) } EXPORT_SYMBOL(netif_device_detach); +/** + * netif_device_attach - mark device as attached + * @dev: network device + * + * Mark device as attached from system and restart if needed. + */ void netif_device_attach(struct net_device *dev) { if (!test_and_set_bit(__LINK_STATE_PRESENT, &dev->state) && @@ -1730,7 +1738,7 @@ enqueue: return NET_RX_SUCCESS; } - netif_rx_schedule(&queue->backlog_dev); + napi_schedule(&queue->backlog); goto enqueue; } @@ -1771,6 +1779,7 @@ static inline struct net_device *skb_bond(struct sk_buff *skb) return dev; } + static void net_tx_action(struct softirq_action *h) { struct softnet_data *sd = &__get_cpu_var(softnet_data); @@ -1927,7 +1936,7 @@ int netif_receive_skb(struct sk_buff *skb) __be16 type; /* if we've gotten here through NAPI, check netpoll */ - if (skb->dev->poll && netpoll_rx(skb)) + if (netpoll_receive_skb(skb)) return NET_RX_DROP; if (!skb->tstamp.tv64) @@ -2017,22 +2026,25 @@ out: return ret; } -static int process_backlog(struct net_device *backlog_dev, int *budget) +static int process_backlog(struct napi_struct *napi, int quota) { int work = 0; - int quota = min(backlog_dev->quota, *budget); struct softnet_data *queue = &__get_cpu_var(softnet_data); unsigned long start_time = jiffies; - backlog_dev->weight = weight_p; - for (;;) { + napi->weight = weight_p; + do { struct sk_buff *skb; struct net_device *dev; local_irq_disable(); skb = __skb_dequeue(&queue->input_pkt_queue); - if (!skb) - goto job_done; + if (!skb) { + __napi_complete(napi); + local_irq_enable(); + break; + } + local_irq_enable(); dev = skb->dev; @@ -2040,67 +2052,86 @@ static int process_backlog(struct net_device *backlog_dev, int *budget) netif_receive_skb(skb); dev_put(dev); + } while (++work < quota && jiffies == start_time); - work++; - - if (work >= quota || jiffies - start_time > 1) - break; - - } - - backlog_dev->quota -= work; - *budget -= work; - return -1; - -job_done: - backlog_dev->quota -= work; - *budget -= work; + return work; +} - list_del(&backlog_dev->poll_list); - smp_mb__before_clear_bit(); - netif_poll_enable(backlog_dev); +/** + * __napi_schedule - schedule for receive + * @napi: entry to schedule + * + * The entry's receive function will be scheduled to run + */ +void fastcall __napi_schedule(struct napi_struct *n) +{ + unsigned long flags; - local_irq_enable(); - return 0; + local_irq_save(flags); + list_add_tail(&n->poll_list, &__get_cpu_var(softnet_data).poll_list); + __raise_softirq_irqoff(NET_RX_SOFTIRQ); + local_irq_restore(flags); } +EXPORT_SYMBOL(__napi_schedule); + static void net_rx_action(struct softirq_action *h) { - struct softnet_data *queue = &__get_cpu_var(softnet_data); + struct list_head *list = &__get_cpu_var(softnet_data).poll_list; unsigned long start_time = jiffies; int budget = netdev_budget; void *have; local_irq_disable(); - while (!list_empty(&queue->poll_list)) { - struct net_device *dev; + while (!list_empty(list)) { + struct napi_struct *n; + int work, weight; - if (budget <= 0 || jiffies - start_time > 1) + /* If softirq window is exhuasted then punt. + * + * Note that this is a slight policy change from the + * previous NAPI code, which would allow up to 2 + * jiffies to pass before breaking out. The test + * used to be "jiffies - start_time > 1". + */ + if (unlikely(budget <= 0 || jiffies != start_time)) goto softnet_break; local_irq_enable(); - dev = list_entry(queue->poll_list.next, - struct net_device, poll_list); - have = netpoll_poll_lock(dev); + /* Even though interrupts have been re-enabled, this + * access is safe because interrupts can only add new + * entries to the tail of this list, and only ->poll() + * calls can remove this head entry from the list. + */ + n = list_entry(list->next, struct napi_struct, poll_list); - if (dev->quota <= 0 || dev->poll(dev, &budget)) { - netpoll_poll_unlock(have); - local_irq_disable(); - list_move_tail(&dev->poll_list, &queue->poll_list); - if (dev->quota < 0) - dev->quota += dev->weight; - else - dev->quota = dev->weight; - } else { - netpoll_poll_unlock(have); - dev_put(dev); - local_irq_disable(); - } + have = netpoll_poll_lock(n); + + weight = n->weight; + + work = n->poll(n, weight); + + WARN_ON_ONCE(work > weight); + + budget -= work; + + local_irq_disable(); + + /* Drivers must not modify the NAPI state if they + * consume the entire weight. In such cases this code + * still "owns" the NAPI instance and therefore can + * move the instance around on the list at-will. + */ + if (unlikely(work == weight)) + list_move_tail(&n->poll_list, list); + + netpoll_poll_unlock(have); } out: local_irq_enable(); + #ifdef CONFIG_NET_DMA /* * There may not be any more sk_buffs coming right now, so push @@ -2115,6 +2146,7 @@ out: } } #endif + return; softnet_break: @@ -3704,6 +3736,7 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name, dev->egress_subqueue_count = queue_count; dev->get_stats = internal_stats; + netpoll_netdev_init(dev); setup(dev); strcpy(dev->name, name); return dev; @@ -4076,10 +4109,9 @@ static int __init net_dev_init(void) skb_queue_head_init(&queue->input_pkt_queue); queue->completion_queue = NULL; INIT_LIST_HEAD(&queue->poll_list); - set_bit(__LINK_STATE_START, &queue->backlog_dev.state); - queue->backlog_dev.weight = weight_p; - queue->backlog_dev.poll = process_backlog; - atomic_set(&queue->backlog_dev.refcnt, 1); + + queue->backlog.poll = process_backlog; + queue->backlog.weight = weight_p; } netdev_dma_register(); diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 5c19b0646d7..79159db6acb 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -216,20 +216,6 @@ static ssize_t store_tx_queue_len(struct device *dev, return netdev_store(dev, attr, buf, len, change_tx_queue_len); } -NETDEVICE_SHOW(weight, fmt_dec); - -static int change_weight(struct net_device *net, unsigned long new_weight) -{ - net->weight = new_weight; - return 0; -} - -static ssize_t store_weight(struct device *dev, struct device_attribute *attr, - const char *buf, size_t len) -{ - return netdev_store(dev, attr, buf, len, change_weight); -} - static struct device_attribute net_class_attributes[] = { __ATTR(addr_len, S_IRUGO, show_addr_len, NULL), __ATTR(iflink, S_IRUGO, show_iflink, NULL), @@ -246,7 +232,6 @@ static struct device_attribute net_class_attributes[] = { __ATTR(flags, S_IRUGO | S_IWUSR, show_flags, store_flags), __ATTR(tx_queue_len, S_IRUGO | S_IWUSR, show_tx_queue_len, store_tx_queue_len), - __ATTR(weight, S_IRUGO | S_IWUSR, show_weight, store_weight), {} }; diff --git a/net/core/netpoll.c b/net/core/netpoll.c index de1b26aa572..abe6e3a4cc4 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -119,19 +119,22 @@ static __sum16 checksum_udp(struct sk_buff *skb, struct udphdr *uh, static void poll_napi(struct netpoll *np) { struct netpoll_info *npinfo = np->dev->npinfo; + struct napi_struct *napi; int budget = 16; - if (test_bit(__LINK_STATE_RX_SCHED, &np->dev->state) && - npinfo->poll_owner != smp_processor_id() && - spin_trylock(&npinfo->poll_lock)) { - npinfo->rx_flags |= NETPOLL_RX_DROP; - atomic_inc(&trapped); + list_for_each_entry(napi, &np->dev->napi_list, dev_list) { + if (test_bit(NAPI_STATE_SCHED, &napi->state) && + napi->poll_owner != smp_processor_id() && + spin_trylock(&napi->poll_lock)) { + npinfo->rx_flags |= NETPOLL_RX_DROP; + atomic_inc(&trapped); - np->dev->poll(np->dev, &budget); + napi->poll(napi, budget); - atomic_dec(&trapped); - npinfo->rx_flags &= ~NETPOLL_RX_DROP; - spin_unlock(&npinfo->poll_lock); + atomic_dec(&trapped); + npinfo->rx_flags &= ~NETPOLL_RX_DROP; + spin_unlock(&napi->poll_lock); + } } } @@ -157,7 +160,7 @@ void netpoll_poll(struct netpoll *np) /* Process pending work on NIC */ np->dev->poll_controller(np->dev); - if (np->dev->poll) + if (!list_empty(&np->dev->napi_list)) poll_napi(np); service_arp_queue(np->dev->npinfo); @@ -233,6 +236,17 @@ repeat: return skb; } +static int netpoll_owner_active(struct net_device *dev) +{ + struct napi_struct *napi; + + list_for_each_entry(napi, &dev->napi_list, dev_list) { + if (napi->poll_owner == smp_processor_id()) + return 1; + } + return 0; +} + static void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb) { int status = NETDEV_TX_BUSY; @@ -246,8 +260,7 @@ static void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb) } /* don't get messages out of order, and no recursion */ - if (skb_queue_len(&npinfo->txq) == 0 && - npinfo->poll_owner != smp_processor_id()) { + if (skb_queue_len(&npinfo->txq) == 0 && !netpoll_owner_active(dev)) { unsigned long flags; local_irq_save(flags); @@ -652,8 +665,6 @@ int netpoll_setup(struct netpoll *np) npinfo->rx_flags = 0; npinfo->rx_np = NULL; - spin_lock_init(&npinfo->poll_lock); - npinfo->poll_owner = -1; spin_lock_init(&npinfo->rx_lock); skb_queue_head_init(&npinfo->arp_tx); diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 4756d5857ab..2b0b6fac6ce 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -634,7 +634,6 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, NLA_PUT_STRING(skb, IFLA_IFNAME, dev->name); NLA_PUT_U32(skb, IFLA_TXQLEN, dev->tx_queue_len); - NLA_PUT_U32(skb, IFLA_WEIGHT, dev->weight); NLA_PUT_U8(skb, IFLA_OPERSTATE, netif_running(dev) ? dev->operstate : IF_OPER_DOWN); NLA_PUT_U8(skb, IFLA_LINKMODE, dev->link_mode); @@ -834,9 +833,6 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, if (tb[IFLA_TXQLEN]) dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]); - if (tb[IFLA_WEIGHT]) - dev->weight = nla_get_u32(tb[IFLA_WEIGHT]); - if (tb[IFLA_OPERSTATE]) set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE])); @@ -1074,8 +1070,6 @@ replay: nla_len(tb[IFLA_BROADCAST])); if (tb[IFLA_TXQLEN]) dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]); - if (tb[IFLA_WEIGHT]) - dev->weight = nla_get_u32(tb[IFLA_WEIGHT]); if (tb[IFLA_OPERSTATE]) set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE])); if (tb[IFLA_LINKMODE]) diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index c81649cf0b9..e970e8e7572 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -256,6 +256,12 @@ static void dev_watchdog_down(struct net_device *dev) netif_tx_unlock_bh(dev); } +/** + * netif_carrier_on - set carrier + * @dev: network device + * + * Device has detected that carrier. + */ void netif_carrier_on(struct net_device *dev) { if (test_and_clear_bit(__LINK_STATE_NOCARRIER, &dev->state)) @@ -264,6 +270,12 @@ void netif_carrier_on(struct net_device *dev) __netdev_watchdog_up(dev); } +/** + * netif_carrier_off - clear carrier + * @dev: network device + * + * Device has detected loss of carrier. + */ void netif_carrier_off(struct net_device *dev) { if (!test_and_set_bit(__LINK_STATE_NOCARRIER, &dev->state)) -- cgit v1.2.3-70-g09d2 From e314dbdc1c0dc6a548ecf0afce28ecfd538ff568 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Tue, 25 Sep 2007 16:14:46 -0700 Subject: [NET]: Virtual ethernet device driver. Veth stands for Virtual ETHernet. It is a simple tunnel driver that works at the link layer and looks like a pair of ethernet devices interconnected with each other. Mainly it allows to communicate between network namespaces but it can be used as is as well. The newlink callback is organized that way to make it easy to create the peer device in the separate namespace when we have them in kernel. This implementation uses another interface - the RTM_NRELINK message introduced by Patric. Bug fixes from Daniel Lezcano. Signed-off-by: Pavel Emelyanov Acked-by: Patrick McHardy Signed-off-by: David S. Miller --- drivers/net/Kconfig | 6 + drivers/net/Makefile | 1 + drivers/net/veth.c | 477 +++++++++++++++++++++++++++++++++++++++++++++++++++ include/net/veth.h | 12 ++ 4 files changed, 496 insertions(+) create mode 100644 drivers/net/veth.c create mode 100644 include/net/veth.h (limited to 'drivers') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index c5519250efd..e0a979184c0 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -135,6 +135,12 @@ config TUN If you don't know what to use this for, you don't need it. +config VETH + tristate "Virtual ethernet device" + ---help--- + The device is an ethernet tunnel. Devices are created in pairs. When + one end receives the packet it appears on its pair and vice versa. + config NET_SB1000 tristate "General Instruments Surfboard 1000" depends on PNP diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 9c928a84584..d6f7302ab72 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -193,6 +193,7 @@ obj-$(CONFIG_MACSONIC) += macsonic.o obj-$(CONFIG_MACMACE) += macmace.o obj-$(CONFIG_MAC89x0) += mac89x0.o obj-$(CONFIG_TUN) += tun.o +obj-$(CONFIG_VETH) += veth.o obj-$(CONFIG_NET_NETX) += netx-eth.o obj-$(CONFIG_DL2K) += dl2k.o obj-$(CONFIG_R8169) += r8169.o diff --git a/drivers/net/veth.c b/drivers/net/veth.c new file mode 100644 index 00000000000..ca1c6893b80 --- /dev/null +++ b/drivers/net/veth.c @@ -0,0 +1,477 @@ +/* + * drivers/net/veth.c + * + * Copyright (C) 2007 OpenVZ http://openvz.org, SWsoft Inc + * + * Author: Pavel Emelianov + * Ethtool interface from: Eric W. Biederman + * + */ + +#include +#include +#include +#include + +#include +#include +#include + +#define DRV_NAME "veth" +#define DRV_VERSION "1.0" + +struct veth_net_stats { + unsigned long rx_packets; + unsigned long tx_packets; + unsigned long rx_bytes; + unsigned long tx_bytes; + unsigned long tx_dropped; +}; + +struct veth_priv { + struct net_device *peer; + struct net_device *dev; + struct list_head list; + struct veth_net_stats *stats; + unsigned ip_summed; +}; + +static LIST_HEAD(veth_list); + +/* + * ethtool interface + */ + +static struct { + const char string[ETH_GSTRING_LEN]; +} ethtool_stats_keys[] = { + { "peer_ifindex" }, +}; + +static int veth_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + cmd->supported = 0; + cmd->advertising = 0; + cmd->speed = SPEED_10000; + cmd->duplex = DUPLEX_FULL; + cmd->port = PORT_TP; + cmd->phy_address = 0; + cmd->transceiver = XCVR_INTERNAL; + cmd->autoneg = AUTONEG_DISABLE; + cmd->maxtxpkt = 0; + cmd->maxrxpkt = 0; + return 0; +} + +static void veth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) +{ + strcpy(info->driver, DRV_NAME); + strcpy(info->version, DRV_VERSION); + strcpy(info->fw_version, "N/A"); +} + +static void veth_get_strings(struct net_device *dev, u32 stringset, u8 *buf) +{ + switch(stringset) { + case ETH_SS_STATS: + memcpy(buf, ðtool_stats_keys, sizeof(ethtool_stats_keys)); + break; + } +} + +static int veth_get_stats_count(struct net_device *dev) +{ + return ARRAY_SIZE(ethtool_stats_keys); +} + +static void veth_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, u64 *data) +{ + struct veth_priv *priv; + + priv = netdev_priv(dev); + data[0] = priv->peer->ifindex; +} + +static u32 veth_get_rx_csum(struct net_device *dev) +{ + struct veth_priv *priv; + + priv = netdev_priv(dev); + return priv->ip_summed == CHECKSUM_UNNECESSARY; +} + +static int veth_set_rx_csum(struct net_device *dev, u32 data) +{ + struct veth_priv *priv; + + priv = netdev_priv(dev); + priv->ip_summed = data ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE; + return 0; +} + +static u32 veth_get_tx_csum(struct net_device *dev) +{ + return (dev->features & NETIF_F_NO_CSUM) != 0; +} + +static int veth_set_tx_csum(struct net_device *dev, u32 data) +{ + if (data) + dev->features |= NETIF_F_NO_CSUM; + else + dev->features &= ~NETIF_F_NO_CSUM; + return 0; +} + +static struct ethtool_ops veth_ethtool_ops = { + .get_settings = veth_get_settings, + .get_drvinfo = veth_get_drvinfo, + .get_link = ethtool_op_get_link, + .get_rx_csum = veth_get_rx_csum, + .set_rx_csum = veth_set_rx_csum, + .get_tx_csum = veth_get_tx_csum, + .set_tx_csum = veth_set_tx_csum, + .get_sg = ethtool_op_get_sg, + .set_sg = ethtool_op_set_sg, + .get_strings = veth_get_strings, + .get_stats_count = veth_get_stats_count, + .get_ethtool_stats = veth_get_ethtool_stats, +}; + +/* + * xmit + */ + +static int veth_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct net_device *rcv = NULL; + struct veth_priv *priv, *rcv_priv; + struct veth_net_stats *stats; + int length, cpu; + + skb_orphan(skb); + + priv = netdev_priv(dev); + rcv = priv->peer; + rcv_priv = netdev_priv(rcv); + + cpu = smp_processor_id(); + stats = per_cpu_ptr(priv->stats, cpu); + + if (!(rcv->flags & IFF_UP)) + goto outf; + + skb->pkt_type = PACKET_HOST; + skb->protocol = eth_type_trans(skb, rcv); + if (dev->features & NETIF_F_NO_CSUM) + skb->ip_summed = rcv_priv->ip_summed; + + dst_release(skb->dst); + skb->dst = NULL; + skb->mark = 0; + secpath_reset(skb); + nf_reset(skb); + + length = skb->len; + + stats->tx_bytes += length; + stats->tx_packets++; + + stats = per_cpu_ptr(rcv_priv->stats, cpu); + stats->rx_bytes += length; + stats->rx_packets++; + + netif_rx(skb); + return 0; + +outf: + kfree_skb(skb); + stats->tx_dropped++; + return 0; +} + +/* + * general routines + */ + +static struct net_device_stats *veth_get_stats(struct net_device *dev) +{ + struct veth_priv *priv; + struct net_device_stats *dev_stats; + int cpu; + struct veth_net_stats *stats; + + priv = netdev_priv(dev); + dev_stats = &dev->stats; + + dev_stats->rx_packets = 0; + dev_stats->tx_packets = 0; + dev_stats->rx_bytes = 0; + dev_stats->tx_bytes = 0; + dev_stats->tx_dropped = 0; + + for_each_online_cpu(cpu) { + stats = per_cpu_ptr(priv->stats, cpu); + + dev_stats->rx_packets += stats->rx_packets; + dev_stats->tx_packets += stats->tx_packets; + dev_stats->rx_bytes += stats->rx_bytes; + dev_stats->tx_bytes += stats->tx_bytes; + dev_stats->tx_dropped += stats->tx_dropped; + } + + return dev_stats; +} + +static int veth_open(struct net_device *dev) +{ + struct veth_priv *priv; + + priv = netdev_priv(dev); + if (priv->peer == NULL) + return -ENOTCONN; + + if (priv->peer->flags & IFF_UP) { + netif_carrier_on(dev); + netif_carrier_on(priv->peer); + } + return 0; +} + +static int veth_close(struct net_device *dev) +{ + struct veth_priv *priv; + + if (netif_carrier_ok(dev)) { + priv = netdev_priv(dev); + netif_carrier_off(dev); + netif_carrier_off(priv->peer); + } + return 0; +} + +static int veth_dev_init(struct net_device *dev) +{ + struct veth_net_stats *stats; + struct veth_priv *priv; + + stats = alloc_percpu(struct veth_net_stats); + if (stats == NULL) + return -ENOMEM; + + priv = netdev_priv(dev); + priv->stats = stats; + return 0; +} + +static void veth_dev_free(struct net_device *dev) +{ + struct veth_priv *priv; + + priv = netdev_priv(dev); + free_percpu(priv->stats); + free_netdev(dev); +} + +static void veth_setup(struct net_device *dev) +{ + ether_setup(dev); + + dev->hard_start_xmit = veth_xmit; + dev->get_stats = veth_get_stats; + dev->open = veth_open; + dev->stop = veth_close; + dev->ethtool_ops = &veth_ethtool_ops; + dev->features |= NETIF_F_LLTX; + dev->init = veth_dev_init; + dev->destructor = veth_dev_free; +} + +/* + * netlink interface + */ + +static int veth_validate(struct nlattr *tb[], struct nlattr *data[]) +{ + if (tb[IFLA_ADDRESS]) { + if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) + return -EINVAL; + if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) + return -EADDRNOTAVAIL; + } + return 0; +} + +static struct rtnl_link_ops veth_link_ops; + +static int veth_newlink(struct net_device *dev, + struct nlattr *tb[], struct nlattr *data[]) +{ + int err; + struct net_device *peer; + struct veth_priv *priv; + char ifname[IFNAMSIZ]; + struct nlattr *peer_tb[IFLA_MAX + 1], **tbp; + + /* + * create and register peer first + * + * struct ifinfomsg is at the head of VETH_INFO_PEER, but we + * skip it since no info from it is useful yet + */ + + if (data != NULL && data[VETH_INFO_PEER] != NULL) { + struct nlattr *nla_peer; + + nla_peer = data[VETH_INFO_PEER]; + err = nla_parse(peer_tb, IFLA_MAX, + nla_data(nla_peer) + sizeof(struct ifinfomsg), + nla_len(nla_peer) - sizeof(struct ifinfomsg), + ifla_policy); + if (err < 0) + return err; + + err = veth_validate(peer_tb, NULL); + if (err < 0) + return err; + + tbp = peer_tb; + } else + tbp = tb; + + if (tbp[IFLA_IFNAME]) + nla_strlcpy(ifname, tbp[IFLA_IFNAME], IFNAMSIZ); + else + snprintf(ifname, IFNAMSIZ, DRV_NAME "%%d"); + + peer = rtnl_create_link(ifname, &veth_link_ops, tbp); + if (IS_ERR(peer)) + return PTR_ERR(peer); + + if (tbp[IFLA_ADDRESS] == NULL) + random_ether_addr(peer->dev_addr); + + err = register_netdevice(peer); + if (err < 0) + goto err_register_peer; + + netif_carrier_off(peer); + + /* + * register dev last + * + * note, that since we've registered new device the dev's name + * should be re-allocated + */ + + if (tb[IFLA_ADDRESS] == NULL) + random_ether_addr(dev->dev_addr); + + if (tb[IFLA_IFNAME]) + nla_strlcpy(dev->name, tb[IFLA_IFNAME], IFNAMSIZ); + else + snprintf(dev->name, IFNAMSIZ, DRV_NAME "%%d"); + + if (strchr(dev->name, '%')) { + err = dev_alloc_name(dev, dev->name); + if (err < 0) + goto err_alloc_name; + } + + err = register_netdevice(dev); + if (err < 0) + goto err_register_dev; + + netif_carrier_off(dev); + + /* + * tie the deviced together + */ + + priv = netdev_priv(dev); + priv->dev = dev; + priv->peer = peer; + list_add(&priv->list, &veth_list); + + priv = netdev_priv(peer); + priv->dev = peer; + priv->peer = dev; + INIT_LIST_HEAD(&priv->list); + return 0; + +err_register_dev: + /* nothing to do */ +err_alloc_name: + unregister_netdevice(peer); + return err; + +err_register_peer: + free_netdev(peer); + return err; +} + +static void veth_dellink(struct net_device *dev) +{ + struct veth_priv *priv; + struct net_device *peer; + + priv = netdev_priv(dev); + peer = priv->peer; + + if (!list_empty(&priv->list)) + list_del(&priv->list); + + priv = netdev_priv(peer); + if (!list_empty(&priv->list)) + list_del(&priv->list); + + unregister_netdevice(dev); + unregister_netdevice(peer); +} + +static const struct nla_policy veth_policy[VETH_INFO_MAX + 1]; + +static struct rtnl_link_ops veth_link_ops = { + .kind = DRV_NAME, + .priv_size = sizeof(struct veth_priv), + .setup = veth_setup, + .validate = veth_validate, + .newlink = veth_newlink, + .dellink = veth_dellink, + .policy = veth_policy, + .maxtype = VETH_INFO_MAX, +}; + +/* + * init/fini + */ + +static __init int veth_init(void) +{ + return rtnl_link_register(&veth_link_ops); +} + +static __exit void veth_exit(void) +{ + struct veth_priv *priv, *next; + + rtnl_lock(); + /* + * cannot trust __rtnl_link_unregister() to unregister all + * devices, as each ->dellink call will remove two devices + * from the list at once. + */ + list_for_each_entry_safe(priv, next, &veth_list, list) + veth_dellink(priv->dev); + + __rtnl_link_unregister(&veth_link_ops); + rtnl_unlock(); +} + +module_init(veth_init); +module_exit(veth_exit); + +MODULE_DESCRIPTION("Virtual Ethernet Tunnel"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS_RTNL_LINK(DRV_NAME); diff --git a/include/net/veth.h b/include/net/veth.h new file mode 100644 index 00000000000..3354c1eb424 --- /dev/null +++ b/include/net/veth.h @@ -0,0 +1,12 @@ +#ifndef __NET_VETH_H_ +#define __NET_VETH_H_ + +enum { + VETH_INFO_UNSPEC, + VETH_INFO_PEER, + + __VETH_INFO_MAX +#define VETH_INFO_MAX (__VETH_INFO_MAX - 1) +}; + +#endif -- cgit v1.2.3-70-g09d2 From d4dc4ec9d84e0578b9bfbe56a11fafdb7cbac771 Mon Sep 17 00:00:00 2001 From: Jan-Bernd Themann Date: Tue, 25 Sep 2007 16:16:34 -0700 Subject: [EHEA]: Use LRO. Signed-off-by: Jan-Bernd Themann Signed-off-by: David S. Miller --- drivers/net/Kconfig | 1 + drivers/net/ehea/ehea.h | 7 ++++ drivers/net/ehea/ehea_ethtool.c | 15 ++++++++ drivers/net/ehea/ehea_main.c | 84 +++++++++++++++++++++++++++++++++++++---- 4 files changed, 100 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index e0a979184c0..61dedfeed62 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2507,6 +2507,7 @@ config CHELSIO_T3 config EHEA tristate "eHEA Ethernet support" depends on IBMEBUS + select INET_LRO ---help--- This driver supports the IBM pSeries eHEA ethernet adapter. diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h index a154681165b..c0cbd949e33 100644 --- a/drivers/net/ehea/ehea.h +++ b/drivers/net/ehea/ehea.h @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -58,6 +59,7 @@ #define EHEA_SMALL_QUEUES #define EHEA_NUM_TX_QP 1 +#define EHEA_LRO_MAX_AGGR 64 #ifdef EHEA_SMALL_QUEUES #define EHEA_MAX_CQE_COUNT 1023 @@ -84,6 +86,8 @@ #define EHEA_RQ2_PKT_SIZE 1522 #define EHEA_L_PKT_SIZE 256 /* low latency */ +#define MAX_LRO_DESCRIPTORS 8 + /* Send completion signaling */ /* Protection Domain Identifier */ @@ -376,6 +380,8 @@ struct ehea_port_res { u64 tx_packets; u64 rx_packets; u32 poll_counter; + struct net_lro_mgr lro_mgr; + struct net_lro_desc lro_desc[MAX_LRO_DESCRIPTORS]; }; @@ -429,6 +435,7 @@ struct ehea_port { u32 msg_enable; u32 sig_comp_iv; u32 state; + u32 lro_max_aggr; u8 phy_link; u8 full_duplex; u8 autoneg; diff --git a/drivers/net/ehea/ehea_ethtool.c b/drivers/net/ehea/ehea_ethtool.c index decec8cfe96..29ef7a98f8b 100644 --- a/drivers/net/ehea/ehea_ethtool.c +++ b/drivers/net/ehea/ehea_ethtool.c @@ -183,6 +183,9 @@ static char ehea_ethtool_stats_keys[][ETH_GSTRING_LEN] = { {"PR5 free_swqes"}, {"PR6 free_swqes"}, {"PR7 free_swqes"}, + {"LRO aggregated"}, + {"LRO flushed"}, + {"LRO no_desc"}, }; static void ehea_get_strings(struct net_device *dev, u32 stringset, u8 *data) @@ -239,6 +242,18 @@ static void ehea_get_ethtool_stats(struct net_device *dev, for (k = 0; k < 8; k++) data[i++] = atomic_read(&port->port_res[k].swqe_avail); + for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++) + tmp |= port->port_res[k].lro_mgr.stats.aggregated; + data[i++] = tmp; + + for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++) + tmp |= port->port_res[k].lro_mgr.stats.flushed; + data[i++] = tmp; + + for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++) + tmp |= port->port_res[k].lro_mgr.stats.no_desc; + data[i++] = tmp; + } const struct ethtool_ops ehea_ethtool_ops = { diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 5ebd545ab04..b8e00391a5e 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -52,6 +52,8 @@ static int rq2_entries = EHEA_DEF_ENTRIES_RQ2; static int rq3_entries = EHEA_DEF_ENTRIES_RQ3; static int sq_entries = EHEA_DEF_ENTRIES_SQ; static int use_mcs = 0; +static int use_lro = 0; +static int lro_max_aggr = EHEA_LRO_MAX_AGGR; static int num_tx_qps = EHEA_NUM_TX_QP; static int prop_carrier_state = 0; @@ -62,6 +64,8 @@ module_param(rq3_entries, int, 0); module_param(sq_entries, int, 0); module_param(prop_carrier_state, int, 0); module_param(use_mcs, int, 0); +module_param(use_lro, int, 0); +module_param(lro_max_aggr, int, 0); module_param(num_tx_qps, int, 0); MODULE_PARM_DESC(num_tx_qps, "Number of TX-QPS"); @@ -82,6 +86,11 @@ MODULE_PARM_DESC(sq_entries, " Number of entries for the Send Queue " __MODULE_STRING(EHEA_DEF_ENTRIES_SQ) ")"); MODULE_PARM_DESC(use_mcs, " 0:NAPI, 1:Multiple receive queues, Default = 0 "); +MODULE_PARM_DESC(lro_max_aggr, " LRO: Max packets to be aggregated. Default = " + __MODULE_STRING(EHEA_LRO_MAX_AGGR)); +MODULE_PARM_DESC(use_lro, " Large Receive Offload, 1: enable, 0: disable, " + "Default = 0"); + static int port_name_cnt = 0; static LIST_HEAD(adapter_list); u64 ehea_driver_flags = 0; @@ -393,6 +402,60 @@ static int ehea_treat_poll_error(struct ehea_port_res *pr, int rq, return 0; } +static int get_skb_hdr(struct sk_buff *skb, void **iphdr, + void **tcph, u64 *hdr_flags, void *priv) +{ + struct ehea_cqe *cqe = priv; + unsigned int ip_len; + struct iphdr *iph; + + /* non tcp/udp packets */ + if (!cqe->header_length) + return -1; + + /* non tcp packet */ + skb_reset_network_header(skb); + iph = ip_hdr(skb); + if (iph->protocol != IPPROTO_TCP) + return -1; + + ip_len = ip_hdrlen(skb); + skb_set_transport_header(skb, ip_len); + *tcph = tcp_hdr(skb); + + /* check if ip header and tcp header are complete */ + if (iph->tot_len < ip_len + tcp_hdrlen(skb)) + return -1; + + *hdr_flags = LRO_IPV4 | LRO_TCP; + *iphdr = iph; + + return 0; +} + +static void ehea_proc_skb(struct ehea_port_res *pr, struct ehea_cqe *cqe, + struct sk_buff *skb) +{ + int vlan_extracted = (cqe->status & EHEA_CQE_VLAN_TAG_XTRACT) + && pr->port->vgrp; + + if (use_lro) { + if (vlan_extracted) + lro_vlan_hwaccel_receive_skb(&pr->lro_mgr, skb, + pr->port->vgrp, + cqe->vlan_tag, + cqe); + else + lro_receive_skb(&pr->lro_mgr, skb, cqe); + } else { + if (vlan_extracted) + vlan_hwaccel_receive_skb(skb, pr->port->vgrp, + cqe->vlan_tag); + else + netif_receive_skb(skb); + } +} + static int ehea_proc_rwqes(struct net_device *dev, struct ehea_port_res *pr, int budget) @@ -462,13 +525,7 @@ static int ehea_proc_rwqes(struct net_device *dev, processed_rq3++; } - if ((cqe->status & EHEA_CQE_VLAN_TAG_XTRACT) - && port->vgrp) - vlan_hwaccel_receive_skb(skb, port->vgrp, - cqe->vlan_tag); - else - netif_receive_skb(skb); - + ehea_proc_skb(pr, cqe, skb); dev->last_rx = jiffies; } else { pr->p_stats.poll_receive_errors++; @@ -480,6 +537,8 @@ static int ehea_proc_rwqes(struct net_device *dev, } cqe = ehea_poll_rq1(qp, &wqe_index); } + if (use_lro) + lro_flush_all(&pr->lro_mgr); pr->rx_packets += processed; @@ -1231,6 +1290,15 @@ static int ehea_init_port_res(struct ehea_port *port, struct ehea_port_res *pr, netif_napi_add(pr->port->netdev, &pr->napi, ehea_poll, 64); + pr->lro_mgr.max_aggr = pr->port->lro_max_aggr; + pr->lro_mgr.max_desc = MAX_LRO_DESCRIPTORS; + pr->lro_mgr.lro_arr = pr->lro_desc; + pr->lro_mgr.get_skb_header = get_skb_hdr; + pr->lro_mgr.features = LRO_F_NAPI | LRO_F_EXTRACT_VLAN_ID; + pr->lro_mgr.dev = port->netdev; + pr->lro_mgr.ip_summed = CHECKSUM_UNNECESSARY; + pr->lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY; + ret = 0; goto out; @@ -2682,6 +2750,8 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter, goto out_dereg_bc; } + port->lro_max_aggr = lro_max_aggr; + ret = ehea_get_jumboframe_status(port, &jumbo); if (ret) ehea_error("failed determining jumbo frame status for %s", -- cgit v1.2.3-70-g09d2 From 1e6e9342d41ff80ced0ad5dfcf084926700cdfc5 Mon Sep 17 00:00:00 2001 From: Andrew Gallatin Date: Mon, 17 Sep 2007 11:37:42 -0700 Subject: [MYRI10GE]: Use LRO. Singed off by: Andrew Gallatin Signed-off-by: David S. Miller --- drivers/net/Kconfig | 1 + drivers/net/myri10ge/myri10ge.c | 109 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 109 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 61dedfeed62..40ff9a5269a 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2583,6 +2583,7 @@ config MYRI10GE depends on PCI select FW_LOADER select CRC32 + select INET_LRO ---help--- This driver supports Myricom Myri-10G Dual Protocol interface in Ethernet mode. If the eeprom on your board is not recent enough, diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index a30146ea51f..48b23c59240 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -48,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -62,6 +63,8 @@ #include #include #include +#include +#include #include #include #include @@ -89,6 +92,8 @@ MODULE_LICENSE("Dual BSD/GPL"); #define MYRI10GE_EEPROM_STRINGS_SIZE 256 #define MYRI10GE_MAX_SEND_DESC_TSO ((65536 / 2048) * 2) +#define MYRI10GE_MAX_LRO_DESCRIPTORS 8 +#define MYRI10GE_LRO_MAX_PKTS 64 #define MYRI10GE_NO_CONFIRM_DATA htonl(0xffffffff) #define MYRI10GE_NO_RESPONSE_RESULT 0xffffffff @@ -151,6 +156,8 @@ struct myri10ge_rx_done { dma_addr_t bus; int cnt; int idx; + struct net_lro_mgr lro_mgr; + struct net_lro_desc lro_desc[MYRI10GE_MAX_LRO_DESCRIPTORS]; }; struct myri10ge_priv { @@ -278,6 +285,14 @@ static int myri10ge_debug = -1; /* defaults above */ module_param(myri10ge_debug, int, 0); MODULE_PARM_DESC(myri10ge_debug, "Debug level (0=none,...,16=all)"); +static int myri10ge_lro = 1; +module_param(myri10ge_lro, int, S_IRUGO); +MODULE_PARM_DESC(myri10ge_lro, "Enable large receive offload\n"); + +static int myri10ge_lro_max_pkts = MYRI10GE_LRO_MAX_PKTS; +module_param(myri10ge_lro_max_pkts, int, S_IRUGO); +MODULE_PARM_DESC(myri10ge_lro, "Number of LRO packets to be aggregated\n"); + static int myri10ge_fill_thresh = 256; module_param(myri10ge_fill_thresh, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(myri10ge_fill_thresh, "Number of empty rx slots allowed\n"); @@ -1021,6 +1036,15 @@ myri10ge_rx_done(struct myri10ge_priv *mgp, struct myri10ge_rx_buf *rx, remainder -= MYRI10GE_ALLOC_SIZE; } + if (mgp->csum_flag && myri10ge_lro) { + rx_frags[0].page_offset += MXGEFW_PAD; + rx_frags[0].size -= MXGEFW_PAD; + len -= MXGEFW_PAD; + lro_receive_frags(&mgp->rx_done.lro_mgr, rx_frags, + len, len, (void *)(unsigned long)csum, csum); + return 1; + } + hlen = MYRI10GE_HLEN > len ? len : MYRI10GE_HLEN; /* allocate an skb to attach the page(s) to. */ @@ -1136,6 +1160,9 @@ static inline int myri10ge_clean_rx_done(struct myri10ge_priv *mgp, int budget) mgp->stats.rx_packets += rx_packets; mgp->stats.rx_bytes += rx_bytes; + if (myri10ge_lro) + lro_flush_all(&rx_done->lro_mgr); + /* restock receive rings if needed */ if (mgp->rx_small.fill_cnt - mgp->rx_small.cnt < myri10ge_fill_thresh) myri10ge_alloc_rx_pages(mgp, &mgp->rx_small, @@ -1373,7 +1400,8 @@ static const char myri10ge_gstrings_stats[][ETH_GSTRING_LEN] = { "dropped_pause", "dropped_bad_phy", "dropped_bad_crc32", "dropped_unicast_filtered", "dropped_multicast_filtered", "dropped_runt", "dropped_overrun", "dropped_no_small_buffer", - "dropped_no_big_buffer" + "dropped_no_big_buffer", "LRO aggregated", "LRO flushed", + "LRO avg aggr", "LRO no_desc" }; #define MYRI10GE_NET_STATS_LEN 21 @@ -1439,6 +1467,14 @@ myri10ge_get_ethtool_stats(struct net_device *netdev, data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_overrun); data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_no_small_buffer); data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_no_big_buffer); + data[i++] = mgp->rx_done.lro_mgr.stats.aggregated; + data[i++] = mgp->rx_done.lro_mgr.stats.flushed; + if (mgp->rx_done.lro_mgr.stats.flushed) + data[i++] = mgp->rx_done.lro_mgr.stats.aggregated / + mgp->rx_done.lro_mgr.stats.flushed; + else + data[i++] = 0; + data[i++] = mgp->rx_done.lro_mgr.stats.no_desc; } static void myri10ge_set_msglevel(struct net_device *netdev, u32 value) @@ -1712,10 +1748,69 @@ static void myri10ge_free_irq(struct myri10ge_priv *mgp) pci_disable_msi(pdev); } +static int +myri10ge_get_frag_header(struct skb_frag_struct *frag, void **mac_hdr, + void **ip_hdr, void **tcpudp_hdr, + u64 * hdr_flags, void *priv) +{ + struct ethhdr *eh; + struct vlan_ethhdr *veh; + struct iphdr *iph; + u8 *va = page_address(frag->page) + frag->page_offset; + unsigned long ll_hlen; + __wsum csum = (__wsum) (unsigned long)priv; + + /* find the mac header, aborting if not IPv4 */ + + eh = (struct ethhdr *)va; + *mac_hdr = eh; + ll_hlen = ETH_HLEN; + if (eh->h_proto != htons(ETH_P_IP)) { + if (eh->h_proto == htons(ETH_P_8021Q)) { + veh = (struct vlan_ethhdr *)va; + if (veh->h_vlan_encapsulated_proto != htons(ETH_P_IP)) + return -1; + + ll_hlen += VLAN_HLEN; + + /* + * HW checksum starts ETH_HLEN bytes into + * frame, so we must subtract off the VLAN + * header's checksum before csum can be used + */ + csum = csum_sub(csum, csum_partial(va + ETH_HLEN, + VLAN_HLEN, 0)); + } else { + return -1; + } + } + *hdr_flags = LRO_IPV4; + + iph = (struct iphdr *)(va + ll_hlen); + *ip_hdr = iph; + if (iph->protocol != IPPROTO_TCP) + return -1; + *hdr_flags |= LRO_TCP; + *tcpudp_hdr = (u8 *) (*ip_hdr) + (iph->ihl << 2); + + /* verify the IP checksum */ + if (unlikely(ip_fast_csum((u8 *) iph, iph->ihl))) + return -1; + + /* verify the checksum */ + if (unlikely(csum_tcpudp_magic(iph->saddr, iph->daddr, + ntohs(iph->tot_len) - (iph->ihl << 2), + IPPROTO_TCP, csum))) + return -1; + + return 0; +} + static int myri10ge_open(struct net_device *dev) { struct myri10ge_priv *mgp; struct myri10ge_cmd cmd; + struct net_lro_mgr *lro_mgr; int status, big_pow2; mgp = netdev_priv(dev); @@ -1847,6 +1942,18 @@ static int myri10ge_open(struct net_device *dev) mgp->link_state = htonl(~0U); mgp->rdma_tags_available = 15; + lro_mgr = &mgp->rx_done.lro_mgr; + lro_mgr->dev = dev; + lro_mgr->features = LRO_F_NAPI; + lro_mgr->ip_summed = CHECKSUM_COMPLETE; + lro_mgr->ip_summed_aggr = CHECKSUM_UNNECESSARY; + lro_mgr->max_desc = MYRI10GE_MAX_LRO_DESCRIPTORS; + lro_mgr->lro_arr = mgp->rx_done.lro_desc; + lro_mgr->get_frag_header = myri10ge_get_frag_header; + lro_mgr->max_aggr = myri10ge_lro_max_pkts; + if (lro_mgr->max_aggr > MAX_SKB_FRAGS) + lro_mgr->max_aggr = MAX_SKB_FRAGS; + napi_enable(&mgp->napi); /* must happen prior to any irq */ status = myri10ge_send_cmd(mgp, MXGEFW_CMD_ETHERNET_UP, &cmd, 0); -- cgit v1.2.3-70-g09d2 From d39badf05b52f99169b22ce324fd31c8b44a0473 Mon Sep 17 00:00:00 2001 From: Satyam Sharma Date: Fri, 10 Aug 2007 15:27:24 -0700 Subject: [NET] netconsole: Cleanups, codingstyle, prettyfication Based upon initial work by Keiichi Kii . (1) Remove unwanted headers. (2) Mark __init and __exit as appropriate. (3) Various trivial codingstyle and prettification stuff. Signed-off-by: Satyam Sharma Signed-off-by: Keiichi Kii Acked-by: Matt Mackall Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/net/netconsole.c | 55 ++++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 69233f6aa05..f1c2a2defd7 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -35,35 +35,32 @@ ****************************************************************/ #include -#include #include #include #include -#include #include #include -#include -#include #include MODULE_AUTHOR("Maintainer: Matt Mackall "); MODULE_DESCRIPTION("Console driver for network interfaces"); MODULE_LICENSE("GPL"); -static char config[256]; -module_param_string(netconsole, config, 256, 0); +#define MAX_PARAM_LENGTH 256 +#define MAX_PRINT_CHUNK 1000 + +static char config[MAX_PARAM_LENGTH]; +module_param_string(netconsole, config, MAX_PARAM_LENGTH, 0); MODULE_PARM_DESC(netconsole, " netconsole=[src-port]@[src-ip]/[dev],[tgt-port]@/[tgt-macaddr]\n"); static struct netpoll np = { - .name = "netconsole", - .dev_name = "eth0", - .local_port = 6665, - .remote_port = 6666, - .remote_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + .name = "netconsole", + .dev_name = "eth0", + .local_port = 6665, + .remote_port = 6666, + .remote_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, }; -static int configured = 0; - -#define MAX_PRINT_CHUNK 1000 +static int configured; static void write_msg(struct console *con, const char *msg, unsigned int len) { @@ -75,7 +72,7 @@ static void write_msg(struct console *con, const char *msg, unsigned int len) local_irq_save(flags); - for(left = len; left; ) { + for (left = len; left;) { frag = min(left, MAX_PRINT_CHUNK); netpoll_send_udp(&np, msg, frag); msg += frag; @@ -86,12 +83,12 @@ static void write_msg(struct console *con, const char *msg, unsigned int len) } static struct console netconsole = { - .name = "netcon", - .flags = CON_ENABLED | CON_PRINTBUFFER, - .write = write_msg + .name = "netcon", + .flags = CON_ENABLED | CON_PRINTBUFFER, + .write = write_msg, }; -static int option_setup(char *opt) +static int __init option_setup(char *opt) { configured = !netpoll_parse_options(&np, opt); return 1; @@ -99,28 +96,30 @@ static int option_setup(char *opt) __setup("netconsole=", option_setup); -static int init_netconsole(void) +static int __init init_netconsole(void) { - int err; + int err = 0; - if(strlen(config)) + if (strnlen(config, MAX_PARAM_LENGTH)) option_setup(config); - if(!configured) { - printk("netconsole: not configured, aborting\n"); - return 0; + if (!configured) { + printk(KERN_INFO "netconsole: not configured, aborting\n"); + goto out; } err = netpoll_setup(&np); if (err) - return err; + goto out; register_console(&netconsole); printk(KERN_INFO "netconsole: network logging started\n"); - return 0; + +out: + return err; } -static void cleanup_netconsole(void) +static void __exit cleanup_netconsole(void) { unregister_console(&netconsole); netpoll_cleanup(&np); -- cgit v1.2.3-70-g09d2 From d133ccbdc30c7f86459519cec1126d6473762b10 Mon Sep 17 00:00:00 2001 From: Satyam Sharma Date: Fri, 10 Aug 2007 15:28:10 -0700 Subject: [NET] netconsole: Remove bogus check Based upon initial work by Keiichi Kii . The (!np.dev) check in write_msg() is bogus (always false), because: np.dev is set by netpoll_setup(), which is called by init_netconsole() before register_console(), so write_msg() cannot be triggered unless netpoll_setup() successfully set np.dev. Also np.dev cannot go away from under us, because netpoll_setup() grabs us reference on it. So let's remove the bogus check. Signed-off-by: Satyam Sharma Acked-by: Keiichi Kii Acked-by: Matt Mackall Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/net/netconsole.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index f1c2a2defd7..2c2aef1ae8e 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -67,9 +67,6 @@ static void write_msg(struct console *con, const char *msg, unsigned int len) int frag, left; unsigned long flags; - if (!np.dev) - return; - local_irq_save(flags); for (left = len; left;) { -- cgit v1.2.3-70-g09d2 From d2b60881e28072109601c373abd1085499ccfef0 Mon Sep 17 00:00:00 2001 From: Satyam Sharma Date: Fri, 10 Aug 2007 15:29:47 -0700 Subject: [NET] netconsole: Simplify boot/module option setup logic Based upon initial work by Keiichi Kii . Presently, boot/module parameters are set up quite differently for the case of built-in netconsole (__setup() -> obsolete_checksetup() -> netpoll_parse_options() -> strlen(config) == 0 in init_netconsole()) vs modular netconsole (module_param_string() -> string copied to the config variable -> strlen(config) != 0 init_netconsole() -> netpoll_parse_options()). This patch makes both of them similar by doing exactly the equivalent of a module_param_string() in option_setup() also -- just copying the param string passed from the kernel command line into "config" variable. So, strlen(config) != 0 in both cases, and netpoll_parse_options() is always called from init_netconsole(), thus making the setup logic for both cases similar. Now, option_setup() is only ever called / used for the built-in case, so we put it inside a #ifndef MODULE, otherwise gcc will complain about option_setup() being "defined but not used". Also, the "configured" variable is redundant with this patch and hence removed. Signed-off-by: Satyam Sharma Signed-off-by: Keiichi Kii Acked-by: Matt Mackall Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/net/netconsole.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 2c2aef1ae8e..e56aa6c9743 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -53,6 +53,15 @@ static char config[MAX_PARAM_LENGTH]; module_param_string(netconsole, config, MAX_PARAM_LENGTH, 0); MODULE_PARM_DESC(netconsole, " netconsole=[src-port]@[src-ip]/[dev],[tgt-port]@/[tgt-macaddr]\n"); +#ifndef MODULE +static int __init option_setup(char *opt) +{ + strlcpy(config, opt, MAX_PARAM_LENGTH); + return 1; +} +__setup("netconsole=", option_setup); +#endif /* MODULE */ + static struct netpoll np = { .name = "netconsole", .dev_name = "eth0", @@ -60,7 +69,6 @@ static struct netpoll np = { .remote_port = 6666, .remote_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, }; -static int configured; static void write_msg(struct console *con, const char *msg, unsigned int len) { @@ -85,26 +93,19 @@ static struct console netconsole = { .write = write_msg, }; -static int __init option_setup(char *opt) -{ - configured = !netpoll_parse_options(&np, opt); - return 1; -} - -__setup("netconsole=", option_setup); - static int __init init_netconsole(void) { int err = 0; - if (strnlen(config, MAX_PARAM_LENGTH)) - option_setup(config); - - if (!configured) { + if (!strnlen(config, MAX_PARAM_LENGTH)) { printk(KERN_INFO "netconsole: not configured, aborting\n"); goto out; } + err = netpoll_parse_options(&np, config); + if (err) + goto out; + err = netpoll_setup(&np); if (err) goto out; -- cgit v1.2.3-70-g09d2 From 0cc120bea1d4ba3893a26c70d271e89f928b8a97 Mon Sep 17 00:00:00 2001 From: Satyam Sharma Date: Fri, 10 Aug 2007 15:30:31 -0700 Subject: [NET] netconsole: Use netif_running() in write_msg() Based upon initial work by Keiichi Kii . Avoid unnecessarily disabling interrupts and calling netpoll_send_udp() if the corresponding local interface is not up. Signed-off-by: Satyam Sharma Acked-by: Keiichi Kii Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/net/netconsole.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index e56aa6c9743..75cb76139dd 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -75,16 +75,16 @@ static void write_msg(struct console *con, const char *msg, unsigned int len) int frag, left; unsigned long flags; - local_irq_save(flags); - - for (left = len; left;) { - frag = min(left, MAX_PRINT_CHUNK); - netpoll_send_udp(&np, msg, frag); - msg += frag; - left -= frag; + if (netif_running(np.dev)) { + local_irq_save(flags); + for (left = len; left;) { + frag = min(left, MAX_PRINT_CHUNK); + netpoll_send_udp(&np, msg, frag); + msg += frag; + left -= frag; + } + local_irq_restore(flags); } - - local_irq_restore(flags); } static struct console netconsole = { -- cgit v1.2.3-70-g09d2 From df180e369cf54a8ef8440667ab1d13d452fc7215 Mon Sep 17 00:00:00 2001 From: Satyam Sharma Date: Fri, 10 Aug 2007 15:32:14 -0700 Subject: [NET] netconsole: Introduce netconsole_target Based upon initial work by Keiichi Kii . Introduce a wrapper structure over netpoll to represent logging targets configured in netconsole. This will get extended with other members in further patches. This is done independent of the (to-be-introduced) NETCONSOLE_DYNAMIC config option so that we're able to drastically cut down on the #ifdef complexity of final netconsole.c. Also, struct netconsole_target would be required for multiple targets support also, and not just dynamic reconfigurability. Signed-off-by: Satyam Sharma Signed-off-by: Keiichi Kii Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/net/netconsole.c | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 75cb76139dd..be15ca6205a 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -62,24 +62,35 @@ static int __init option_setup(char *opt) __setup("netconsole=", option_setup); #endif /* MODULE */ -static struct netpoll np = { - .name = "netconsole", - .dev_name = "eth0", - .local_port = 6665, - .remote_port = 6666, - .remote_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, +/** + * struct netconsole_target - Represents a configured netconsole target. + * @np: The netpoll structure for this target. + */ +struct netconsole_target { + struct netpoll np; +}; + +static struct netconsole_target default_target = { + .np = { + .name = "netconsole", + .dev_name = "eth0", + .local_port = 6665, + .remote_port = 6666, + .remote_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + }, }; static void write_msg(struct console *con, const char *msg, unsigned int len) { int frag, left; unsigned long flags; + struct netconsole_target *nt = &default_target; - if (netif_running(np.dev)) { + if (netif_running(nt->np.dev)) { local_irq_save(flags); for (left = len; left;) { frag = min(left, MAX_PRINT_CHUNK); - netpoll_send_udp(&np, msg, frag); + netpoll_send_udp(&nt->np, msg, frag); msg += frag; left -= frag; } @@ -96,17 +107,18 @@ static struct console netconsole = { static int __init init_netconsole(void) { int err = 0; + struct netconsole_target *nt = &default_target; if (!strnlen(config, MAX_PARAM_LENGTH)) { printk(KERN_INFO "netconsole: not configured, aborting\n"); goto out; } - err = netpoll_parse_options(&np, config); + err = netpoll_parse_options(&nt->np, config); if (err) goto out; - err = netpoll_setup(&np); + err = netpoll_setup(&nt->np); if (err) goto out; @@ -119,8 +131,10 @@ out: static void __exit cleanup_netconsole(void) { + struct netconsole_target *nt = &default_target; + unregister_console(&netconsole); - netpoll_cleanup(&np); + netpoll_cleanup(&nt->np); } module_init(init_netconsole); -- cgit v1.2.3-70-g09d2 From 17951f34b0970b05e29fd93a5b93fa05ec71308b Mon Sep 17 00:00:00 2001 From: Satyam Sharma Date: Fri, 10 Aug 2007 15:33:01 -0700 Subject: [NET] netconsole: Introduce netconsole_netdev_notifier Based upon initial work by Keiichi Kii . To update fields of underlying netpoll structure at runtime on corresponding NETDEV_CHANGEADDR or NETDEV_CHANGENAME notifications. ioctl(SIOCSIFHWADDR or SIOCSIFNAME) could be used to change the hardware/MAC address or name of the local interface that our netpoll is attached to. Whenever this happens, netdev notifier chain is called out with the NETDEV_CHANGEADDR or NETDEV_CHANGENAME event message. We respond to that and update the local_mac or dev_name field of the struct netpoll. This makes sense anyway, but is especially required for dynamic netconsole because the netpoll structure's internal members become user visible files when either sysfs or configfs are used. So this helps us to keep up with the MAC address/name changes and keep values in struct netpoll uptodate. [ Note that ioctl(SIOCSIFADDR) to change IP address of interface at runtime is not handled (to update local_ip of netpoll) on purpose -- some setups may set the local_ip to a private address, not necessary the actual IP address of the sender host, as presently allowed. ] Signed-off-by: Satyam Sharma Signed-off-by: Keiichi Kii Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/net/netconsole.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'drivers') diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index be15ca6205a..55570988250 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -80,6 +80,33 @@ static struct netconsole_target default_target = { }, }; +/* Handle network interface device notifications */ +static int netconsole_netdev_event(struct notifier_block *this, + unsigned long event, + void *ptr) +{ + struct net_device *dev = ptr; + struct netconsole_target *nt = &default_target; + + if (nt->np.dev == dev) { + switch (event) { + case NETDEV_CHANGEADDR: + memcpy(nt->np.local_mac, dev->dev_addr, ETH_ALEN); + break; + + case NETDEV_CHANGENAME: + strlcpy(nt->np.dev_name, dev->name, IFNAMSIZ); + break; + } + } + + return NOTIFY_DONE; +} + +static struct notifier_block netconsole_netdev_notifier = { + .notifier_call = netconsole_netdev_event, +}; + static void write_msg(struct console *con, const char *msg, unsigned int len) { int frag, left; @@ -122,6 +149,10 @@ static int __init init_netconsole(void) if (err) goto out; + err = register_netdevice_notifier(&netconsole_netdev_notifier); + if (err) + goto out; + register_console(&netconsole); printk(KERN_INFO "netconsole: network logging started\n"); @@ -134,6 +165,7 @@ static void __exit cleanup_netconsole(void) struct netconsole_target *nt = &default_target; unregister_console(&netconsole); + unregister_netdevice_notifier(&netconsole_netdev_notifier); netpoll_cleanup(&nt->np); } -- cgit v1.2.3-70-g09d2 From b5427c27173e128dda1541bd9d3b05df79af5882 Mon Sep 17 00:00:00 2001 From: Satyam Sharma Date: Fri, 10 Aug 2007 15:33:40 -0700 Subject: [NET] netconsole: Support multiple logging targets Based upon initial work by Keiichi Kii . This patch introduces support for multiple targets, independent of CONFIG_NETCONSOLE_DYNAMIC -- this is useful even in the default case and (including the infrastructure introduced in previous patches) doesn't really add too many bytes to module text. All the complexity (and size) comes with the dynamic reconfigurability / userspace interface patch, and so it's plausible users may want to keep this enabled but that disabled (say to avoid a dependency on CONFIG_CONFIGFS_FS too). Also update documentation to mention the use of ";" separator to specify multiple logging targets in the boot/module option string. Brief overview: We maintain a target_list (and corresponding lock). Get rid of the static "default_target" and introduce allocation and release functions for our netconsole_target objects (but keeping sure to preserve previous behaviour such as default values). During init_netconsole(), ";" is used as the separator to identify multiple target specifications in the boot/module option string. The target specifications are parsed and netpolls setup. During exit, the target_list is torn down and all items released. Signed-off-by: Satyam Sharma Signed-off-by: Keiichi Kii Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- Documentation/networking/netconsole.txt | 6 ++ drivers/net/netconsole.c | 171 ++++++++++++++++++++++++-------- 2 files changed, 137 insertions(+), 40 deletions(-) (limited to 'drivers') diff --git a/Documentation/networking/netconsole.txt b/Documentation/networking/netconsole.txt index 5962f45815a..1aaa7383e41 100644 --- a/Documentation/networking/netconsole.txt +++ b/Documentation/networking/netconsole.txt @@ -34,6 +34,12 @@ Examples: insmod netconsole netconsole=@/,@10.0.0.2/ +It also supports logging to multiple remote agents by specifying +parameters for the multiple agents separated by semicolons and the +complete string enclosed in "quotes", thusly: + + modprobe netconsole netconsole="@/,@10.0.0.2/;@/eth1,6892@10.0.0.3/" + Built-in netconsole starts immediately after the TCP stack is initialized and attempts to bring up the supplied dev at the supplied address. diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 55570988250..458c4d674a9 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -62,44 +62,93 @@ static int __init option_setup(char *opt) __setup("netconsole=", option_setup); #endif /* MODULE */ +/* Linked list of all configured targets */ +static LIST_HEAD(target_list); + +/* This needs to be a spinlock because write_msg() cannot sleep */ +static DEFINE_SPINLOCK(target_list_lock); + /** * struct netconsole_target - Represents a configured netconsole target. + * @list: Links this target into the target_list. * @np: The netpoll structure for this target. */ struct netconsole_target { + struct list_head list; struct netpoll np; }; -static struct netconsole_target default_target = { - .np = { - .name = "netconsole", - .dev_name = "eth0", - .local_port = 6665, - .remote_port = 6666, - .remote_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, - }, -}; +/* Allocate new target and setup netpoll for it */ +static struct netconsole_target *alloc_target(char *target_config) +{ + int err = -ENOMEM; + struct netconsole_target *nt; + + /* Allocate and initialize with defaults */ + nt = kzalloc(sizeof(*nt), GFP_KERNEL); + if (!nt) { + printk(KERN_ERR "netconsole: failed to allocate memory\n"); + goto fail; + } + + nt->np.name = "netconsole"; + strlcpy(nt->np.dev_name, "eth0", IFNAMSIZ); + nt->np.local_port = 6665; + nt->np.remote_port = 6666; + memset(nt->np.remote_mac, 0xff, ETH_ALEN); + + /* Parse parameters and setup netpoll */ + err = netpoll_parse_options(&nt->np, target_config); + if (err) + goto fail; + + err = netpoll_setup(&nt->np); + if (err) + goto fail; + + return nt; + +fail: + kfree(nt); + return ERR_PTR(err); +} + +/* Cleanup netpoll for given target and free it */ +static void free_target(struct netconsole_target *nt) +{ + netpoll_cleanup(&nt->np); + kfree(nt); +} /* Handle network interface device notifications */ static int netconsole_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) { + unsigned long flags; + struct netconsole_target *nt; struct net_device *dev = ptr; - struct netconsole_target *nt = &default_target; - if (nt->np.dev == dev) { - switch (event) { - case NETDEV_CHANGEADDR: - memcpy(nt->np.local_mac, dev->dev_addr, ETH_ALEN); - break; + if (!(event == NETDEV_CHANGEADDR || event == NETDEV_CHANGENAME)) + goto done; + + spin_lock_irqsave(&target_list_lock, flags); + list_for_each_entry(nt, &target_list, list) { + if (nt->np.dev == dev) { + switch (event) { + case NETDEV_CHANGEADDR: + memcpy(nt->np.local_mac, dev->dev_addr, ETH_ALEN); + break; - case NETDEV_CHANGENAME: - strlcpy(nt->np.dev_name, dev->name, IFNAMSIZ); - break; + case NETDEV_CHANGENAME: + strlcpy(nt->np.dev_name, dev->name, IFNAMSIZ); + break; + } } } + spin_unlock_irqrestore(&target_list_lock, flags); +done: return NOTIFY_DONE; } @@ -111,18 +160,32 @@ static void write_msg(struct console *con, const char *msg, unsigned int len) { int frag, left; unsigned long flags; - struct netconsole_target *nt = &default_target; - - if (netif_running(nt->np.dev)) { - local_irq_save(flags); - for (left = len; left;) { - frag = min(left, MAX_PRINT_CHUNK); - netpoll_send_udp(&nt->np, msg, frag); - msg += frag; - left -= frag; + struct netconsole_target *nt; + const char *tmp; + + /* Avoid taking lock and disabling interrupts unnecessarily */ + if (list_empty(&target_list)) + return; + + spin_lock_irqsave(&target_list_lock, flags); + list_for_each_entry(nt, &target_list, list) { + if (netif_running(nt->np.dev)) { + /* + * We nest this inside the for-each-target loop above + * so that we're able to get as much logging out to + * at least one target if we die inside here, instead + * of unnecessarily keeping all targets in lock-step. + */ + tmp = msg; + for (left = len; left;) { + frag = min(left, MAX_PRINT_CHUNK); + netpoll_send_udp(&nt->np, tmp, frag); + tmp += frag; + left -= frag; + } } - local_irq_restore(flags); } + spin_unlock_irqrestore(&target_list_lock, flags); } static struct console netconsole = { @@ -134,39 +197,67 @@ static struct console netconsole = { static int __init init_netconsole(void) { int err = 0; - struct netconsole_target *nt = &default_target; + struct netconsole_target *nt, *tmp; + unsigned long flags; + char *target_config; + char *input = config; - if (!strnlen(config, MAX_PARAM_LENGTH)) { + if (!strnlen(input, MAX_PARAM_LENGTH)) { printk(KERN_INFO "netconsole: not configured, aborting\n"); goto out; } - err = netpoll_parse_options(&nt->np, config); - if (err) - goto out; - - err = netpoll_setup(&nt->np); - if (err) - goto out; + while ((target_config = strsep(&input, ";"))) { + nt = alloc_target(target_config); + if (IS_ERR(nt)) { + err = PTR_ERR(nt); + goto fail; + } + spin_lock_irqsave(&target_list_lock, flags); + list_add(&nt->list, &target_list); + spin_unlock_irqrestore(&target_list_lock, flags); + } err = register_netdevice_notifier(&netconsole_netdev_notifier); if (err) - goto out; + goto fail; register_console(&netconsole); printk(KERN_INFO "netconsole: network logging started\n"); out: return err; + +fail: + printk(KERN_ERR "netconsole: cleaning up\n"); + + /* + * Remove all targets and destroy them. Skipping the list + * lock is safe here, and netpoll_cleanup() will sleep. + */ + list_for_each_entry_safe(nt, tmp, &target_list, list) { + list_del(&nt->list); + free_target(nt); + } + + return err; } static void __exit cleanup_netconsole(void) { - struct netconsole_target *nt = &default_target; + struct netconsole_target *nt, *tmp; unregister_console(&netconsole); unregister_netdevice_notifier(&netconsole_netdev_notifier); - netpoll_cleanup(&nt->np); + + /* + * Remove all targets and destroy them. Skipping the list + * lock is safe here, and netpoll_cleanup() will sleep. + */ + list_for_each_entry_safe(nt, tmp, &target_list, list) { + list_del(&nt->list); + free_target(nt); + } } module_init(init_netconsole); -- cgit v1.2.3-70-g09d2 From 0bcc1816188e570bde1d56a208996660f2633ae0 Mon Sep 17 00:00:00 2001 From: Satyam Sharma Date: Fri, 10 Aug 2007 15:35:05 -0700 Subject: [NET] netconsole: Support dynamic reconfiguration using configfs Based upon initial work by Keiichi Kii . This patch introduces support for dynamic reconfiguration (adding, removing and/or modifying parameters of netconsole targets at runtime) using a userspace interface exported via configfs. Documentation is also updated accordingly. Issues and brief design overview: (1) Kernel-initiated creation / destruction of kernel objects is not possible with configfs -- the lifetimes of the "config items" is managed exclusively from userspace. But netconsole must support boot/module params too, and these are parsed in kernel and hence netpolls must be setup from the kernel. Joel Becker suggested to separately manage the lifetimes of the two kinds of netconsole_target objects -- those created via configfs mkdir(2) from userspace and those specified from the boot/module option string. This adds complexity and some redundancy here and also means that boot/module param-created targets are not exposed through the configfs namespace (and hence cannot be updated / destroyed dynamically). However, this saves us from locking / refcounting complexities that would need to be introduced in configfs to support kernel-initiated item creation / destroy there. (2) In configfs, item creation takes place in the call chain of the mkdir(2) syscall in the driver subsystem. If we used an ioctl(2) to create / destroy objects from userspace, the special userspace program is able to fill out the structure to be passed into the ioctl and hence specify attributes such as local interface that are required at the time we set up the netpoll. For configfs, this information is not available at the time of mkdir(2). So, we keep all newly-created targets (via configfs) disabled by default. The user is expected to set various attributes appropriately (including the local network interface if required) and then write(2) "1" to the "enabled" attribute. Thus, netpoll_setup() is then called on the set parameters in the context of _this_ write(2) on the "enabled" attribute itself. This design enables the user to reconfigure existing netconsole targets at runtime to be attached to newly-come-up interfaces that may not have existed when netconsole was loaded or when the targets were actually created. All this effectively enables us to get rid of custom ioctls. (3) Ultra-paranoid configfs attribute show() and store() operations, with sanity and input range checking, using only safe string primitives, and compliant with the recommendations in Documentation/filesystems/sysfs.txt. (4) A new function netpoll_print_options() is created in the netpoll API, that just prints out the configured parameters for a netpoll structure. netpoll_parse_options() is modified to use that and it is also exported to be used from netconsole. Signed-off-by: Satyam Sharma Acked-by: Keiichi Kii Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- Documentation/networking/netconsole.txt | 68 ++++ drivers/net/Kconfig | 10 + drivers/net/netconsole.c | 605 ++++++++++++++++++++++++++++++-- include/linux/netpoll.h | 1 + net/core/netpoll.c | 44 ++- 5 files changed, 683 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/Documentation/networking/netconsole.txt b/Documentation/networking/netconsole.txt index 1aaa7383e41..3c2f2b32863 100644 --- a/Documentation/networking/netconsole.txt +++ b/Documentation/networking/netconsole.txt @@ -3,6 +3,10 @@ started by Ingo Molnar , 2001.09.17 2.6 port and netpoll api by Matt Mackall , Sep 9 2003 Please send bug reports to Matt Mackall +and Satyam Sharma + +Introduction: +============= This module logs kernel printk messages over UDP allowing debugging of problem where disk logging fails and serial consoles are impractical. @@ -13,6 +17,9 @@ the specified interface as soon as possible. While this doesn't allow capture of early kernel panics, it does capture most of the boot process. +Sender and receiver configuration: +================================== + It takes a string configuration parameter "netconsole" in the following format: @@ -46,6 +53,67 @@ address. The remote host can run either 'netcat -u -l -p ' or syslogd. +Dynamic reconfiguration: +======================== + +Dynamic reconfigurability is a useful addition to netconsole that enables +remote logging targets to be dynamically added, removed, or have their +parameters reconfigured at runtime from a configfs-based userspace interface. +[ Note that the parameters of netconsole targets that were specified/created +from the boot/module option are not exposed via this interface, and hence +cannot be modified dynamically. ] + +To include this feature, select CONFIG_NETCONSOLE_DYNAMIC when building the +netconsole module (or kernel, if netconsole is built-in). + +Some examples follow (where configfs is mounted at the /sys/kernel/config +mountpoint). + +To add a remote logging target (target names can be arbitrary): + + cd /sys/kernel/config/netconsole/ + mkdir target1 + +Note that newly created targets have default parameter values (as mentioned +above) and are disabled by default -- they must first be enabled by writing +"1" to the "enabled" attribute (usually after setting parameters accordingly) +as described below. + +To remove a target: + + rmdir /sys/kernel/config/netconsole/othertarget/ + +The interface exposes these parameters of a netconsole target to userspace: + + enabled Is this target currently enabled? (read-write) + dev_name Local network interface name (read-write) + local_port Source UDP port to use (read-write) + remote_port Remote agent's UDP port (read-write) + local_ip Source IP address to use (read-write) + remote_ip Remote agent's IP address (read-write) + local_mac Local interface's MAC address (read-only) + remote_mac Remote agent's MAC address (read-write) + +The "enabled" attribute is also used to control whether the parameters of +a target can be updated or not -- you can modify the parameters of only +disabled targets (i.e. if "enabled" is 0). + +To update a target's parameters: + + cat enabled # check if enabled is 1 + echo 0 > enabled # disable the target (if required) + echo eth2 > dev_name # set local interface + echo 10.0.0.4 > remote_ip # update some parameter + echo cb:a9:87:65:43:21 > remote_mac # update more parameters + echo 1 > enabled # enable target again + +You can also update the local interface dynamically. This is especially +useful if you want to use interfaces that have newly come up (and may not +have existed when netconsole was loaded / initialized). + +Miscellaneous notes: +==================== + WARNING: the default target ethernet setting uses the broadcast ethernet address to send packets, which can cause increased load on other systems on the same ethernet segment. diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 40ff9a5269a..10ed28ef356 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -3082,6 +3082,16 @@ config NETCONSOLE If you want to log kernel messages over the network, enable this. See for details. +config NETCONSOLE_DYNAMIC + bool "Dynamic reconfiguration of logging targets (EXPERIMENTAL)" + depends on NETCONSOLE && SYSFS && EXPERIMENTAL + select CONFIGFS_FS + help + This option enables the ability to dynamically reconfigure target + parameters (interface, IP addresses, port numbers, MAC addresses) + at runtime through a userspace interface exported using configfs. + See for details. + config NETPOLL def_bool NETCONSOLE diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 458c4d674a9..69ef1eb03be 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -41,6 +41,8 @@ #include #include #include +#include +#include MODULE_AUTHOR("Maintainer: Matt Mackall "); MODULE_DESCRIPTION("Console driver for network interfaces"); @@ -71,20 +73,100 @@ static DEFINE_SPINLOCK(target_list_lock); /** * struct netconsole_target - Represents a configured netconsole target. * @list: Links this target into the target_list. + * @item: Links us into the configfs subsystem hierarchy. + * @enabled: On / off knob to enable / disable target. + * Visible from userspace (read-write). + * We maintain a strict 1:1 correspondence between this and + * whether the corresponding netpoll is active or inactive. + * Also, other parameters of a target may be modified at + * runtime only when it is disabled (enabled == 0). * @np: The netpoll structure for this target. + * Contains the other userspace visible parameters: + * dev_name (read-write) + * local_port (read-write) + * remote_port (read-write) + * local_ip (read-write) + * remote_ip (read-write) + * local_mac (read-only) + * remote_mac (read-write) */ struct netconsole_target { struct list_head list; +#ifdef CONFIG_NETCONSOLE_DYNAMIC + struct config_item item; +#endif + int enabled; struct netpoll np; }; -/* Allocate new target and setup netpoll for it */ -static struct netconsole_target *alloc_target(char *target_config) +#ifdef CONFIG_NETCONSOLE_DYNAMIC + +static struct configfs_subsystem netconsole_subsys; + +static int __init dynamic_netconsole_init(void) +{ + config_group_init(&netconsole_subsys.su_group); + mutex_init(&netconsole_subsys.su_mutex); + return configfs_register_subsystem(&netconsole_subsys); +} + +static void __exit dynamic_netconsole_exit(void) +{ + configfs_unregister_subsystem(&netconsole_subsys); +} + +/* + * Targets that were created by parsing the boot/module option string + * do not exist in the configfs hierarchy (and have NULL names) and will + * never go away, so make these a no-op for them. + */ +static void netconsole_target_get(struct netconsole_target *nt) +{ + if (config_item_name(&nt->item)) + config_item_get(&nt->item); +} + +static void netconsole_target_put(struct netconsole_target *nt) +{ + if (config_item_name(&nt->item)) + config_item_put(&nt->item); +} + +#else /* !CONFIG_NETCONSOLE_DYNAMIC */ + +static int __init dynamic_netconsole_init(void) +{ + return 0; +} + +static void __exit dynamic_netconsole_exit(void) +{ +} + +/* + * No danger of targets going away from under us when dynamic + * reconfigurability is off. + */ +static void netconsole_target_get(struct netconsole_target *nt) +{ +} + +static void netconsole_target_put(struct netconsole_target *nt) +{ +} + +#endif /* CONFIG_NETCONSOLE_DYNAMIC */ + +/* Allocate new target (from boot/module param) and setup netpoll for it */ +static struct netconsole_target *alloc_param_target(char *target_config) { int err = -ENOMEM; struct netconsole_target *nt; - /* Allocate and initialize with defaults */ + /* + * Allocate and initialize with defaults. + * Note that these targets get their config_item fields zeroed-out. + */ nt = kzalloc(sizeof(*nt), GFP_KERNEL); if (!nt) { printk(KERN_ERR "netconsole: failed to allocate memory\n"); @@ -106,6 +188,8 @@ static struct netconsole_target *alloc_target(char *target_config) if (err) goto fail; + nt->enabled = 1; + return nt; fail: @@ -113,13 +197,469 @@ fail: return ERR_PTR(err); } -/* Cleanup netpoll for given target and free it */ -static void free_target(struct netconsole_target *nt) +/* Cleanup netpoll for given target (from boot/module param) and free it */ +static void free_param_target(struct netconsole_target *nt) { netpoll_cleanup(&nt->np); kfree(nt); } +#ifdef CONFIG_NETCONSOLE_DYNAMIC + +/* + * Our subsystem hierarchy is: + * + * /sys/kernel/config/netconsole/ + * | + * / + * | enabled + * | dev_name + * | local_port + * | remote_port + * | local_ip + * | remote_ip + * | local_mac + * | remote_mac + * | + * /... + */ + +struct netconsole_target_attr { + struct configfs_attribute attr; + ssize_t (*show)(struct netconsole_target *nt, + char *buf); + ssize_t (*store)(struct netconsole_target *nt, + const char *buf, + size_t count); +}; + +static struct netconsole_target *to_target(struct config_item *item) +{ + return item ? + container_of(item, struct netconsole_target, item) : + NULL; +} + +/* + * Wrapper over simple_strtol (base 10) with sanity and range checking. + * We return (signed) long only because we may want to return errors. + * Do not use this to convert numbers that are allowed to be negative. + */ +static long strtol10_check_range(const char *cp, long min, long max) +{ + long ret; + char *p = (char *) cp; + + WARN_ON(min < 0); + WARN_ON(max < min); + + ret = simple_strtol(p, &p, 10); + + if (*p && (*p != '\n')) { + printk(KERN_ERR "netconsole: invalid input\n"); + return -EINVAL; + } + if ((ret < min) || (ret > max)) { + printk(KERN_ERR "netconsole: input %ld must be between " + "%ld and %ld\n", ret, min, max); + return -EINVAL; + } + + return ret; +} + +/* + * Attribute operations for netconsole_target. + */ + +static ssize_t show_enabled(struct netconsole_target *nt, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", nt->enabled); +} + +static ssize_t show_dev_name(struct netconsole_target *nt, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%s\n", nt->np.dev_name); +} + +static ssize_t show_local_port(struct netconsole_target *nt, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", nt->np.local_port); +} + +static ssize_t show_remote_port(struct netconsole_target *nt, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", nt->np.remote_port); +} + +static ssize_t show_local_ip(struct netconsole_target *nt, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d.%d.%d.%d\n", + HIPQUAD(nt->np.local_ip)); +} + +static ssize_t show_remote_ip(struct netconsole_target *nt, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d.%d.%d.%d\n", + HIPQUAD(nt->np.remote_ip)); +} + +static ssize_t show_local_mac(struct netconsole_target *nt, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x\n", + nt->np.local_mac[0], nt->np.local_mac[1], + nt->np.local_mac[2], nt->np.local_mac[3], + nt->np.local_mac[4], nt->np.local_mac[5]); +} + +static ssize_t show_remote_mac(struct netconsole_target *nt, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x\n", + nt->np.remote_mac[0], nt->np.remote_mac[1], + nt->np.remote_mac[2], nt->np.remote_mac[3], + nt->np.remote_mac[4], nt->np.remote_mac[5]); +} + +/* + * This one is special -- targets created through the configfs interface + * are not enabled (and the corresponding netpoll activated) by default. + * The user is expected to set the desired parameters first (which + * would enable him to dynamically add new netpoll targets for new + * network interfaces as and when they come up). + */ +static ssize_t store_enabled(struct netconsole_target *nt, + const char *buf, + size_t count) +{ + int err; + long enabled; + + enabled = strtol10_check_range(buf, 0, 1); + if (enabled < 0) + return enabled; + + if (enabled) { /* 1 */ + + /* + * Skip netpoll_parse_options() -- all the attributes are + * already configured via configfs. Just print them out. + */ + netpoll_print_options(&nt->np); + + err = netpoll_setup(&nt->np); + if (err) + return err; + + printk(KERN_INFO "netconsole: network logging started\n"); + + } else { /* 0 */ + netpoll_cleanup(&nt->np); + } + + nt->enabled = enabled; + + return strnlen(buf, count); +} + +static ssize_t store_dev_name(struct netconsole_target *nt, + const char *buf, + size_t count) +{ + size_t len; + + if (nt->enabled) { + printk(KERN_ERR "netconsole: target (%s) is enabled, " + "disable to update parameters\n", + config_item_name(&nt->item)); + return -EINVAL; + } + + strlcpy(nt->np.dev_name, buf, IFNAMSIZ); + + /* Get rid of possible trailing newline from echo(1) */ + len = strnlen(nt->np.dev_name, IFNAMSIZ); + if (nt->np.dev_name[len - 1] == '\n') + nt->np.dev_name[len - 1] = '\0'; + + return strnlen(buf, count); +} + +static ssize_t store_local_port(struct netconsole_target *nt, + const char *buf, + size_t count) +{ + long local_port; +#define __U16_MAX ((__u16) ~0U) + + if (nt->enabled) { + printk(KERN_ERR "netconsole: target (%s) is enabled, " + "disable to update parameters\n", + config_item_name(&nt->item)); + return -EINVAL; + } + + local_port = strtol10_check_range(buf, 0, __U16_MAX); + if (local_port < 0) + return local_port; + + nt->np.local_port = local_port; + + return strnlen(buf, count); +} + +static ssize_t store_remote_port(struct netconsole_target *nt, + const char *buf, + size_t count) +{ + long remote_port; +#define __U16_MAX ((__u16) ~0U) + + if (nt->enabled) { + printk(KERN_ERR "netconsole: target (%s) is enabled, " + "disable to update parameters\n", + config_item_name(&nt->item)); + return -EINVAL; + } + + remote_port = strtol10_check_range(buf, 0, __U16_MAX); + if (remote_port < 0) + return remote_port; + + nt->np.remote_port = remote_port; + + return strnlen(buf, count); +} + +static ssize_t store_local_ip(struct netconsole_target *nt, + const char *buf, + size_t count) +{ + if (nt->enabled) { + printk(KERN_ERR "netconsole: target (%s) is enabled, " + "disable to update parameters\n", + config_item_name(&nt->item)); + return -EINVAL; + } + + nt->np.local_ip = ntohl(in_aton(buf)); + + return strnlen(buf, count); +} + +static ssize_t store_remote_ip(struct netconsole_target *nt, + const char *buf, + size_t count) +{ + if (nt->enabled) { + printk(KERN_ERR "netconsole: target (%s) is enabled, " + "disable to update parameters\n", + config_item_name(&nt->item)); + return -EINVAL; + } + + nt->np.remote_ip = ntohl(in_aton(buf)); + + return strnlen(buf, count); +} + +static ssize_t store_remote_mac(struct netconsole_target *nt, + const char *buf, + size_t count) +{ + u8 remote_mac[ETH_ALEN]; + char *p = (char *) buf; + int i; + + if (nt->enabled) { + printk(KERN_ERR "netconsole: target (%s) is enabled, " + "disable to update parameters\n", + config_item_name(&nt->item)); + return -EINVAL; + } + + for (i = 0; i < ETH_ALEN - 1; i++) { + remote_mac[i] = simple_strtoul(p, &p, 16); + if (*p != ':') + goto invalid; + p++; + } + remote_mac[ETH_ALEN - 1] = simple_strtoul(p, &p, 16); + if (*p && (*p != '\n')) + goto invalid; + + memcpy(nt->np.remote_mac, remote_mac, ETH_ALEN); + + return strnlen(buf, count); + +invalid: + printk(KERN_ERR "netconsole: invalid input\n"); + return -EINVAL; +} + +/* + * Attribute definitions for netconsole_target. + */ + +#define NETCONSOLE_TARGET_ATTR_RO(_name) \ +static struct netconsole_target_attr netconsole_target_##_name = \ + __CONFIGFS_ATTR(_name, S_IRUGO, show_##_name, NULL) + +#define NETCONSOLE_TARGET_ATTR_RW(_name) \ +static struct netconsole_target_attr netconsole_target_##_name = \ + __CONFIGFS_ATTR(_name, S_IRUGO | S_IWUSR, show_##_name, store_##_name) + +NETCONSOLE_TARGET_ATTR_RW(enabled); +NETCONSOLE_TARGET_ATTR_RW(dev_name); +NETCONSOLE_TARGET_ATTR_RW(local_port); +NETCONSOLE_TARGET_ATTR_RW(remote_port); +NETCONSOLE_TARGET_ATTR_RW(local_ip); +NETCONSOLE_TARGET_ATTR_RW(remote_ip); +NETCONSOLE_TARGET_ATTR_RO(local_mac); +NETCONSOLE_TARGET_ATTR_RW(remote_mac); + +static struct configfs_attribute *netconsole_target_attrs[] = { + &netconsole_target_enabled.attr, + &netconsole_target_dev_name.attr, + &netconsole_target_local_port.attr, + &netconsole_target_remote_port.attr, + &netconsole_target_local_ip.attr, + &netconsole_target_remote_ip.attr, + &netconsole_target_local_mac.attr, + &netconsole_target_remote_mac.attr, + NULL, +}; + +/* + * Item operations and type for netconsole_target. + */ + +static void netconsole_target_release(struct config_item *item) +{ + kfree(to_target(item)); +} + +static ssize_t netconsole_target_attr_show(struct config_item *item, + struct configfs_attribute *attr, + char *buf) +{ + ssize_t ret = -EINVAL; + struct netconsole_target *nt = to_target(item); + struct netconsole_target_attr *na = + container_of(attr, struct netconsole_target_attr, attr); + + if (na->show) + ret = na->show(nt, buf); + + return ret; +} + +static ssize_t netconsole_target_attr_store(struct config_item *item, + struct configfs_attribute *attr, + const char *buf, + size_t count) +{ + ssize_t ret = -EINVAL; + struct netconsole_target *nt = to_target(item); + struct netconsole_target_attr *na = + container_of(attr, struct netconsole_target_attr, attr); + + if (na->store) + ret = na->store(nt, buf, count); + + return ret; +} + +static struct configfs_item_operations netconsole_target_item_ops = { + .release = netconsole_target_release, + .show_attribute = netconsole_target_attr_show, + .store_attribute = netconsole_target_attr_store, +}; + +static struct config_item_type netconsole_target_type = { + .ct_attrs = netconsole_target_attrs, + .ct_item_ops = &netconsole_target_item_ops, + .ct_owner = THIS_MODULE, +}; + +/* + * Group operations and type for netconsole_subsys. + */ + +static struct config_item *make_netconsole_target(struct config_group *group, + const char *name) +{ + unsigned long flags; + struct netconsole_target *nt; + + /* + * Allocate and initialize with defaults. + * Target is disabled at creation (enabled == 0). + */ + nt = kzalloc(sizeof(*nt), GFP_KERNEL); + if (!nt) { + printk(KERN_ERR "netconsole: failed to allocate memory\n"); + return NULL; + } + + nt->np.name = "netconsole"; + strlcpy(nt->np.dev_name, "eth0", IFNAMSIZ); + nt->np.local_port = 6665; + nt->np.remote_port = 6666; + memset(nt->np.remote_mac, 0xff, ETH_ALEN); + + /* Initialize the config_item member */ + config_item_init_type_name(&nt->item, name, &netconsole_target_type); + + /* Adding, but it is disabled */ + spin_lock_irqsave(&target_list_lock, flags); + list_add(&nt->list, &target_list); + spin_unlock_irqrestore(&target_list_lock, flags); + + return &nt->item; +} + +static void drop_netconsole_target(struct config_group *group, + struct config_item *item) +{ + unsigned long flags; + struct netconsole_target *nt = to_target(item); + + spin_lock_irqsave(&target_list_lock, flags); + list_del(&nt->list); + spin_unlock_irqrestore(&target_list_lock, flags); + + /* + * The target may have never been enabled, or was manually disabled + * before being removed so netpoll may have already been cleaned up. + */ + if (nt->enabled) + netpoll_cleanup(&nt->np); + + config_item_put(&nt->item); +} + +static struct configfs_group_operations netconsole_subsys_group_ops = { + .make_item = make_netconsole_target, + .drop_item = drop_netconsole_target, +}; + +static struct config_item_type netconsole_subsys_type = { + .ct_group_ops = &netconsole_subsys_group_ops, + .ct_owner = THIS_MODULE, +}; + +/* The netconsole configfs subsystem */ +static struct configfs_subsystem netconsole_subsys = { + .su_group = { + .cg_item = { + .ci_namebuf = "netconsole", + .ci_type = &netconsole_subsys_type, + }, + }, +}; + +#endif /* CONFIG_NETCONSOLE_DYNAMIC */ + /* Handle network interface device notifications */ static int netconsole_netdev_event(struct notifier_block *this, unsigned long event, @@ -134,6 +674,7 @@ static int netconsole_netdev_event(struct notifier_block *this, spin_lock_irqsave(&target_list_lock, flags); list_for_each_entry(nt, &target_list, list) { + netconsole_target_get(nt); if (nt->np.dev == dev) { switch (event) { case NETDEV_CHANGEADDR: @@ -145,6 +686,7 @@ static int netconsole_netdev_event(struct notifier_block *this, break; } } + netconsole_target_put(nt); } spin_unlock_irqrestore(&target_list_lock, flags); @@ -169,7 +711,8 @@ static void write_msg(struct console *con, const char *msg, unsigned int len) spin_lock_irqsave(&target_list_lock, flags); list_for_each_entry(nt, &target_list, list) { - if (netif_running(nt->np.dev)) { + netconsole_target_get(nt); + if (nt->enabled && netif_running(nt->np.dev)) { /* * We nest this inside the for-each-target loop above * so that we're able to get as much logging out to @@ -184,6 +727,7 @@ static void write_msg(struct console *con, const char *msg, unsigned int len) left -= frag; } } + netconsole_target_put(nt); } spin_unlock_irqrestore(&target_list_lock, flags); } @@ -196,48 +740,52 @@ static struct console netconsole = { static int __init init_netconsole(void) { - int err = 0; + int err; struct netconsole_target *nt, *tmp; unsigned long flags; char *target_config; char *input = config; - if (!strnlen(input, MAX_PARAM_LENGTH)) { - printk(KERN_INFO "netconsole: not configured, aborting\n"); - goto out; - } - - while ((target_config = strsep(&input, ";"))) { - nt = alloc_target(target_config); - if (IS_ERR(nt)) { - err = PTR_ERR(nt); - goto fail; + if (strnlen(input, MAX_PARAM_LENGTH)) { + while ((target_config = strsep(&input, ";"))) { + nt = alloc_param_target(target_config); + if (IS_ERR(nt)) { + err = PTR_ERR(nt); + goto fail; + } + spin_lock_irqsave(&target_list_lock, flags); + list_add(&nt->list, &target_list); + spin_unlock_irqrestore(&target_list_lock, flags); } - spin_lock_irqsave(&target_list_lock, flags); - list_add(&nt->list, &target_list); - spin_unlock_irqrestore(&target_list_lock, flags); } err = register_netdevice_notifier(&netconsole_netdev_notifier); if (err) goto fail; + err = dynamic_netconsole_init(); + if (err) + goto undonotifier; + register_console(&netconsole); printk(KERN_INFO "netconsole: network logging started\n"); -out: return err; +undonotifier: + unregister_netdevice_notifier(&netconsole_netdev_notifier); + fail: printk(KERN_ERR "netconsole: cleaning up\n"); /* - * Remove all targets and destroy them. Skipping the list + * Remove all targets and destroy them (only targets created + * from the boot/module option exist here). Skipping the list * lock is safe here, and netpoll_cleanup() will sleep. */ list_for_each_entry_safe(nt, tmp, &target_list, list) { list_del(&nt->list); - free_target(nt); + free_param_target(nt); } return err; @@ -248,15 +796,20 @@ static void __exit cleanup_netconsole(void) struct netconsole_target *nt, *tmp; unregister_console(&netconsole); + dynamic_netconsole_exit(); unregister_netdevice_notifier(&netconsole_netdev_notifier); /* - * Remove all targets and destroy them. Skipping the list - * lock is safe here, and netpoll_cleanup() will sleep. + * Targets created via configfs pin references on our module + * and would first be rmdir(2)'ed from userspace. We reach + * here only when they are already destroyed, and only those + * created from the boot/module option are left, so remove and + * destroy them. Skipping the list lock is safe here, and + * netpoll_cleanup() will sleep. */ list_for_each_entry_safe(nt, tmp, &target_list, list) { list_del(&nt->list); - free_target(nt); + free_param_target(nt); } } diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h index 08dcc39ec18..20250d963d7 100644 --- a/include/linux/netpoll.h +++ b/include/linux/netpoll.h @@ -35,6 +35,7 @@ struct netpoll_info { void netpoll_poll(struct netpoll *np); void netpoll_send_udp(struct netpoll *np, const char *msg, int len); +void netpoll_print_options(struct netpoll *np); int netpoll_parse_options(struct netpoll *np, char *opt); int netpoll_setup(struct netpoll *np); int netpoll_trap(void); diff --git a/net/core/netpoll.c b/net/core/netpoll.c index abe6e3a4cc4..0952f936b29 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -532,6 +532,29 @@ out: return 0; } +void netpoll_print_options(struct netpoll *np) +{ + printk(KERN_INFO "%s: local port %d\n", + np->name, np->local_port); + printk(KERN_INFO "%s: local IP %d.%d.%d.%d\n", + np->name, HIPQUAD(np->local_ip)); + printk(KERN_INFO "%s: interface %s\n", + np->name, np->dev_name); + printk(KERN_INFO "%s: remote port %d\n", + np->name, np->remote_port); + printk(KERN_INFO "%s: remote IP %d.%d.%d.%d\n", + np->name, HIPQUAD(np->remote_ip)); + printk(KERN_INFO "%s: remote ethernet address " + "%02x:%02x:%02x:%02x:%02x:%02x\n", + np->name, + np->remote_mac[0], + np->remote_mac[1], + np->remote_mac[2], + np->remote_mac[3], + np->remote_mac[4], + np->remote_mac[5]); +} + int netpoll_parse_options(struct netpoll *np, char *opt) { char *cur=opt, *delim; @@ -544,7 +567,6 @@ int netpoll_parse_options(struct netpoll *np, char *opt) cur = delim; } cur++; - printk(KERN_INFO "%s: local port %d\n", np->name, np->local_port); if (*cur != '/') { if ((delim = strchr(cur, '/')) == NULL) @@ -552,9 +574,6 @@ int netpoll_parse_options(struct netpoll *np, char *opt) *delim = 0; np->local_ip = ntohl(in_aton(cur)); cur = delim; - - printk(KERN_INFO "%s: local IP %d.%d.%d.%d\n", - np->name, HIPQUAD(np->local_ip)); } cur++; @@ -568,8 +587,6 @@ int netpoll_parse_options(struct netpoll *np, char *opt) } cur++; - printk(KERN_INFO "%s: interface %s\n", np->name, np->dev_name); - if (*cur != '@') { /* dst port */ if ((delim = strchr(cur, '@')) == NULL) @@ -579,7 +596,6 @@ int netpoll_parse_options(struct netpoll *np, char *opt) cur = delim; } cur++; - printk(KERN_INFO "%s: remote port %d\n", np->name, np->remote_port); /* dst ip */ if ((delim = strchr(cur, '/')) == NULL) @@ -588,9 +604,6 @@ int netpoll_parse_options(struct netpoll *np, char *opt) np->remote_ip = ntohl(in_aton(cur)); cur = delim + 1; - printk(KERN_INFO "%s: remote IP %d.%d.%d.%d\n", - np->name, HIPQUAD(np->remote_ip)); - if (*cur != 0) { /* MAC address */ if ((delim = strchr(cur, ':')) == NULL) @@ -621,15 +634,7 @@ int netpoll_parse_options(struct netpoll *np, char *opt) np->remote_mac[5] = simple_strtol(cur, NULL, 16); } - printk(KERN_INFO "%s: remote ethernet address " - "%02x:%02x:%02x:%02x:%02x:%02x\n", - np->name, - np->remote_mac[0], - np->remote_mac[1], - np->remote_mac[2], - np->remote_mac[3], - np->remote_mac[4], - np->remote_mac[5]); + netpoll_print_options(np); return 0; @@ -831,6 +836,7 @@ void netpoll_set_trap(int trap) EXPORT_SYMBOL(netpoll_set_trap); EXPORT_SYMBOL(netpoll_trap); +EXPORT_SYMBOL(netpoll_print_options); EXPORT_SYMBOL(netpoll_parse_options); EXPORT_SYMBOL(netpoll_setup); EXPORT_SYMBOL(netpoll_cleanup); -- cgit v1.2.3-70-g09d2 From 4a1d7c25cb438f96b700ac26dc5aa0a38a6d86ea Mon Sep 17 00:00:00 2001 From: Alex Villacís Lasso Date: Tue, 28 Aug 2007 15:57:50 -0700 Subject: [IrDA]: Kingsun Dazzle IrDA USB driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This dongle does not follow the usb-irda specification, so it needs its own special driver. Just like the Kingsun/Donshine dongle, it exposes two interrupt endpoints. Reception is performed through direct reads from the input endpoint. Transmission requires splitting the IrDA frames into 8-byte segments, in which the first byte encodes how many of the remaining 7 bytes are used as data. Speed change is made with a control URB just like the one in cypress_m8, and it seems to support up to 115200 bps. On plugin, this dongle reports vendor and device IDs: 0x07d0:0x4100 Signed-off-by: Alex Villacís Lasso Signed-off-by: Samuel Ortiz Signed-off-by: David S. Miller --- drivers/net/irda/Kconfig | 12 + drivers/net/irda/Makefile | 1 + drivers/net/irda/ksdazzle-sir.c | 823 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 836 insertions(+) create mode 100644 drivers/net/irda/ksdazzle-sir.c (limited to 'drivers') diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig index 2098d0af8ff..cfa7b8835d3 100644 --- a/drivers/net/irda/Kconfig +++ b/drivers/net/irda/Kconfig @@ -162,7 +162,19 @@ config EP7211_DONGLE Say Y here if you want to build support for the Cirrus logic EP7211 chipset's infrared module. +config KSDAZZLE_DONGLE + tristate "KingSun Dazzle IrDA-USB dongle (EXPERIMENTAL)" + depends on IRDA && USB && EXPERIMENTAL + help + Say Y or M here if you want to build support for the KingSun Dazzle + IrDA-USB bridge device driver. + + This USB bridge does not conform to the IrDA-USB device class + specification, and therefore needs its own specific driver. This + dongle supports SIR speeds only (9600 through 115200 bps). + To compile it as a module, choose M here: the module will be called + ksdazzle-sir. comment "Old SIR device drivers" diff --git a/drivers/net/irda/Makefile b/drivers/net/irda/Makefile index 2808ef5c7b7..e19da3b919a 100644 --- a/drivers/net/irda/Makefile +++ b/drivers/net/irda/Makefile @@ -47,6 +47,7 @@ obj-$(CONFIG_MA600_DONGLE) += ma600-sir.o obj-$(CONFIG_TOIM3232_DONGLE) += toim3232-sir.o obj-$(CONFIG_EP7211_DONGLE) += ep7211-sir.o obj-$(CONFIG_KINGSUN_DONGLE) += kingsun-sir.o +obj-$(CONFIG_KSDAZZLE_DONGLE) += ksdazzle-sir.o # The SIR helper module sir-dev-objs := sir_dev.o sir_dongle.o diff --git a/drivers/net/irda/ksdazzle-sir.c b/drivers/net/irda/ksdazzle-sir.c new file mode 100644 index 00000000000..12b0e7a15be --- /dev/null +++ b/drivers/net/irda/ksdazzle-sir.c @@ -0,0 +1,823 @@ +/***************************************************************************** +* +* Filename: ksdazzle.c +* Version: 0.1.1 +* Description: Irda KingSun Dazzle USB Dongle +* Status: Experimental +* Author: Alex Villacís Lasso +* +* Based on stir4200, mcs7780, kingsun-sir drivers. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + +/* + * Following is my most current (2007-07-26) understanding of how the Kingsun + * 07D0:4100 dongle (sometimes known as the MA-660) is supposed to work. This + * information was deduced by examining the USB traffic captured with USBSnoopy + * from the WinXP driver. Feel free to update here as more of the dongle is + * known. + * + * General: This dongle exposes one interface with two interrupt endpoints, one + * IN and one OUT. In this regard, it is similar to what the Kingsun/Donshine + * dongle (07c0:4200) exposes. Traffic is raw and needs to be wrapped and + * unwrapped manually as in stir4200, kingsun-sir, and ks959-sir. + * + * Transmission: To transmit an IrDA frame, it is necessary to wrap it, then + * split it into multiple segments of up to 7 bytes each, and transmit each in + * sequence. It seems that sending a single big block (like kingsun-sir does) + * won't work with this dongle. Each segment needs to be prefixed with a value + * equal to (unsigned char)0xF8 + , inside a payload + * of exactly 8 bytes. For example, a segment of 1 byte gets prefixed by 0xF9, + * and one of 7 bytes gets prefixed by 0xFF. The bytes at the end of the + * payload, not considered by the prefix, are ignored (set to 0 by this + * implementation). + * + * Reception: To receive data, the driver must poll the dongle regularly (like + * kingsun-sir.c) with interrupt URBs. If data is available, it will be returned + * in payloads from 0 to 8 bytes long. When concatenated, these payloads form + * a raw IrDA stream that needs to be unwrapped as in stir4200 and kingsun-sir + * + * Speed change: To change the speed of the dongle, the driver prepares a + * control URB with the following as a setup packet: + * bRequestType USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE + * bRequest 0x09 + * wValue 0x0200 + * wIndex 0x0001 + * wLength 0x0008 (length of the payload) + * The payload is a 8-byte record, apparently identical to the one used in + * drivers/usb/serial/cypress_m8.c to change speed: + * __u32 baudSpeed; + * unsigned int dataBits : 2; // 0 - 5 bits 3 - 8 bits + * unsigned int : 1; + * unsigned int stopBits : 1; + * unsigned int parityEnable : 1; + * unsigned int parityType : 1; + * unsigned int : 1; + * unsigned int reset : 1; + * unsigned char reserved[3]; // set to 0 + * + * For now only SIR speeds have been observed with this dongle. Therefore, + * nothing is known on what changes (if any) must be done to frame wrapping / + * unwrapping for higher than SIR speeds. This driver assumes no change is + * necessary and announces support for all the way to 115200 bps. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#define KSDAZZLE_VENDOR_ID 0x07d0 +#define KSDAZZLE_PRODUCT_ID 0x4100 + +/* These are the currently known USB ids */ +static struct usb_device_id dongles[] = { + /* KingSun Co,Ltd IrDA/USB Bridge */ + {USB_DEVICE(KSDAZZLE_VENDOR_ID, KSDAZZLE_PRODUCT_ID)}, + {} +}; + +MODULE_DEVICE_TABLE(usb, dongles); + +#define KINGSUN_MTT 0x07 +#define KINGSUN_REQ_RECV 0x01 +#define KINGSUN_REQ_SEND 0x09 + +#define KINGSUN_SND_FIFO_SIZE 2048 /* Max packet we can send */ + +struct ksdazzle_speedparams { + __le32 baudrate; /* baud rate, little endian */ + __u8 flags; + __u8 reserved[3]; +} __attribute__ ((packed)); + +#define KS_DATA_5_BITS 0x00 +#define KS_DATA_6_BITS 0x01 +#define KS_DATA_7_BITS 0x02 +#define KS_DATA_8_BITS 0x03 + +#define KS_STOP_BITS_1 0x00 +#define KS_STOP_BITS_2 0x08 + +#define KS_PAR_DISABLE 0x00 +#define KS_PAR_EVEN 0x10 +#define KS_PAR_ODD 0x30 +#define KS_RESET 0x80 + +#define KINGSUN_EP_IN 0 +#define KINGSUN_EP_OUT 1 + +struct ksdazzle_cb { + struct usb_device *usbdev; /* init: probe_irda */ + struct net_device *netdev; /* network layer */ + struct irlap_cb *irlap; /* The link layer we are binded to */ + struct net_device_stats stats; /* network statistics */ + struct qos_info qos; + + struct urb *tx_urb; + __u8 *tx_buf_clear; + unsigned int tx_buf_clear_used; + unsigned int tx_buf_clear_sent; + __u8 tx_payload[8]; + + struct urb *rx_urb; + __u8 rx_payload[8]; + iobuff_t rx_unwrap_buff; + + struct usb_ctrlrequest *speed_setuprequest; + struct urb *speed_urb; + struct ksdazzle_speedparams speedparams; + unsigned int new_speed; + + __u8 ep_in; + __u8 ep_out; + + spinlock_t lock; + int receiving; +}; + +/* Callback transmission routine */ +static void ksdazzle_speed_irq(struct urb *urb) +{ + /* unlink, shutdown, unplug, other nasties */ + if (urb->status != 0) { + err("ksdazzle_speed_irq: urb asynchronously failed - %d", + urb->status); + } +} + +/* Send a control request to change speed of the dongle */ +static int ksdazzle_change_speed(struct ksdazzle_cb *kingsun, unsigned speed) +{ + static unsigned int supported_speeds[] = { 2400, 9600, 19200, 38400, + 57600, 115200, 576000, 1152000, 4000000, 0 + }; + int err; + unsigned int i; + + if (kingsun->speed_setuprequest == NULL || kingsun->speed_urb == NULL) + return -ENOMEM; + + /* Check that requested speed is among the supported ones */ + for (i = 0; supported_speeds[i] && supported_speeds[i] != speed; i++) ; + if (supported_speeds[i] == 0) + return -EOPNOTSUPP; + + memset(&(kingsun->speedparams), 0, sizeof(struct ksdazzle_speedparams)); + kingsun->speedparams.baudrate = cpu_to_le32(speed); + kingsun->speedparams.flags = KS_DATA_8_BITS; + + /* speed_setuprequest pre-filled in ksdazzle_probe */ + usb_fill_control_urb(kingsun->speed_urb, kingsun->usbdev, + usb_sndctrlpipe(kingsun->usbdev, 0), + (unsigned char *)kingsun->speed_setuprequest, + &(kingsun->speedparams), + sizeof(struct ksdazzle_speedparams), + ksdazzle_speed_irq, kingsun); + kingsun->speed_urb->status = 0; + err = usb_submit_urb(kingsun->speed_urb, GFP_ATOMIC); + + return err; +} + +/* Submit one fragment of an IrDA frame to the dongle */ +static void ksdazzle_send_irq(struct urb *urb); +static int ksdazzle_submit_tx_fragment(struct ksdazzle_cb *kingsun) +{ + unsigned int wraplen; + int ret; + + /* We can send at most 7 bytes of payload at a time */ + wraplen = 7; + if (wraplen > kingsun->tx_buf_clear_used) + wraplen = kingsun->tx_buf_clear_used; + + /* Prepare payload prefix with used length */ + memset(kingsun->tx_payload, 0, 8); + kingsun->tx_payload[0] = (unsigned char)0xf8 + wraplen; + memcpy(kingsun->tx_payload + 1, kingsun->tx_buf_clear, wraplen); + + usb_fill_int_urb(kingsun->tx_urb, kingsun->usbdev, + usb_sndintpipe(kingsun->usbdev, kingsun->ep_out), + kingsun->tx_payload, 8, ksdazzle_send_irq, kingsun, 1); + kingsun->tx_urb->status = 0; + ret = usb_submit_urb(kingsun->tx_urb, GFP_ATOMIC); + + /* Remember how much data was sent, in order to update at callback */ + kingsun->tx_buf_clear_sent = (ret == 0) ? wraplen : 0; + return ret; +} + +/* Callback transmission routine */ +static void ksdazzle_send_irq(struct urb *urb) +{ + struct ksdazzle_cb *kingsun = urb->context; + struct net_device *netdev = kingsun->netdev; + int ret = 0; + + /* in process of stopping, just drop data */ + if (!netif_running(kingsun->netdev)) { + err("ksdazzle_send_irq: Network not running!"); + return; + } + + /* unlink, shutdown, unplug, other nasties */ + if (urb->status != 0) { + err("ksdazzle_send_irq: urb asynchronously failed - %d", + urb->status); + return; + } + + if (kingsun->tx_buf_clear_used > 0) { + /* Update data remaining to be sent */ + if (kingsun->tx_buf_clear_sent < kingsun->tx_buf_clear_used) { + memmove(kingsun->tx_buf_clear, + kingsun->tx_buf_clear + + kingsun->tx_buf_clear_sent, + kingsun->tx_buf_clear_used - + kingsun->tx_buf_clear_sent); + } + kingsun->tx_buf_clear_used -= kingsun->tx_buf_clear_sent; + kingsun->tx_buf_clear_sent = 0; + + if (kingsun->tx_buf_clear_used > 0) { + /* There is more data to be sent */ + if ((ret = ksdazzle_submit_tx_fragment(kingsun)) != 0) { + err("ksdazzle_send_irq: failed tx_urb submit: %d", ret); + switch (ret) { + case -ENODEV: + case -EPIPE: + break; + default: + kingsun->stats.tx_errors++; + netif_start_queue(netdev); + } + } + } else { + /* All data sent, send next speed && wake network queue */ + if (kingsun->new_speed != -1 && + cpu_to_le32(kingsun->new_speed) != + kingsun->speedparams.baudrate) + ksdazzle_change_speed(kingsun, + kingsun->new_speed); + + netif_wake_queue(netdev); + } + } +} + +/* + * Called from net/core when new frame is available. + */ +static int ksdazzle_hard_xmit(struct sk_buff *skb, struct net_device *netdev) +{ + struct ksdazzle_cb *kingsun; + unsigned int wraplen; + int ret = 0; + + if (skb == NULL || netdev == NULL) + return -EINVAL; + + netif_stop_queue(netdev); + + /* the IRDA wrapping routines don't deal with non linear skb */ + SKB_LINEAR_ASSERT(skb); + + kingsun = netdev_priv(netdev); + + spin_lock(&kingsun->lock); + kingsun->new_speed = irda_get_next_speed(skb); + + /* Append data to the end of whatever data remains to be transmitted */ + wraplen = + async_wrap_skb(skb, kingsun->tx_buf_clear, KINGSUN_SND_FIFO_SIZE); + kingsun->tx_buf_clear_used = wraplen; + + if ((ret = ksdazzle_submit_tx_fragment(kingsun)) != 0) { + err("ksdazzle_hard_xmit: failed tx_urb submit: %d", ret); + switch (ret) { + case -ENODEV: + case -EPIPE: + break; + default: + kingsun->stats.tx_errors++; + netif_start_queue(netdev); + } + } else { + kingsun->stats.tx_packets++; + kingsun->stats.tx_bytes += skb->len; + + } + + dev_kfree_skb(skb); + spin_unlock(&kingsun->lock); + + return ret; +} + +/* Receive callback function */ +static void ksdazzle_rcv_irq(struct urb *urb) +{ + struct ksdazzle_cb *kingsun = urb->context; + + /* in process of stopping, just drop data */ + if (!netif_running(kingsun->netdev)) { + kingsun->receiving = 0; + return; + } + + /* unlink, shutdown, unplug, other nasties */ + if (urb->status != 0) { + err("ksdazzle_rcv_irq: urb asynchronously failed - %d", + urb->status); + kingsun->receiving = 0; + return; + } + + if (urb->actual_length > 0) { + __u8 *bytes = urb->transfer_buffer; + unsigned int i; + + for (i = 0; i < urb->actual_length; i++) { + async_unwrap_char(kingsun->netdev, &kingsun->stats, + &kingsun->rx_unwrap_buff, bytes[i]); + } + kingsun->netdev->last_rx = jiffies; + kingsun->receiving = + (kingsun->rx_unwrap_buff.state != OUTSIDE_FRAME) ? 1 : 0; + } + + /* This urb has already been filled in ksdazzle_net_open. It is assumed that + urb keeps the pointer to the payload buffer. + */ + urb->status = 0; + usb_submit_urb(urb, GFP_ATOMIC); +} + +/* + * Function ksdazzle_net_open (dev) + * + * Network device is taken up. Usually this is done by "ifconfig irda0 up" + */ +static int ksdazzle_net_open(struct net_device *netdev) +{ + struct ksdazzle_cb *kingsun = netdev_priv(netdev); + int err = -ENOMEM; + char hwname[16]; + + /* At this point, urbs are NULL, and skb is NULL (see ksdazzle_probe) */ + kingsun->receiving = 0; + + /* Initialize for SIR to copy data directly into skb. */ + kingsun->rx_unwrap_buff.in_frame = FALSE; + kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME; + kingsun->rx_unwrap_buff.truesize = IRDA_SKB_MAX_MTU; + kingsun->rx_unwrap_buff.skb = dev_alloc_skb(IRDA_SKB_MAX_MTU); + if (!kingsun->rx_unwrap_buff.skb) + goto free_mem; + + skb_reserve(kingsun->rx_unwrap_buff.skb, 1); + kingsun->rx_unwrap_buff.head = kingsun->rx_unwrap_buff.skb->data; + + kingsun->rx_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!kingsun->rx_urb) + goto free_mem; + + kingsun->tx_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!kingsun->tx_urb) + goto free_mem; + + kingsun->speed_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!kingsun->speed_urb) + goto free_mem; + + /* Initialize speed for dongle */ + kingsun->new_speed = 9600; + err = ksdazzle_change_speed(kingsun, 9600); + if (err < 0) + goto free_mem; + + /* + * Now that everything should be initialized properly, + * Open new IrLAP layer instance to take care of us... + */ + sprintf(hwname, "usb#%d", kingsun->usbdev->devnum); + kingsun->irlap = irlap_open(netdev, &kingsun->qos, hwname); + if (!kingsun->irlap) { + err("ksdazzle-sir: irlap_open failed"); + goto free_mem; + } + + /* Start reception. */ + usb_fill_int_urb(kingsun->rx_urb, kingsun->usbdev, + usb_rcvintpipe(kingsun->usbdev, kingsun->ep_in), + kingsun->rx_payload, 8, ksdazzle_rcv_irq, kingsun, 1); + kingsun->rx_urb->status = 0; + err = usb_submit_urb(kingsun->rx_urb, GFP_KERNEL); + if (err) { + err("ksdazzle-sir: first urb-submit failed: %d", err); + goto close_irlap; + } + + netif_start_queue(netdev); + + /* Situation at this point: + - all work buffers allocated + - urbs allocated and ready to fill + - max rx packet known (in max_rx) + - unwrap state machine initialized, in state outside of any frame + - receive request in progress + - IrLAP layer started, about to hand over packets to send + */ + + return 0; + + close_irlap: + irlap_close(kingsun->irlap); + free_mem: + usb_free_urb(kingsun->speed_urb); + kingsun->speed_urb = NULL; + usb_free_urb(kingsun->tx_urb); + kingsun->tx_urb = NULL; + usb_free_urb(kingsun->rx_urb); + kingsun->rx_urb = NULL; + if (kingsun->rx_unwrap_buff.skb) { + kfree_skb(kingsun->rx_unwrap_buff.skb); + kingsun->rx_unwrap_buff.skb = NULL; + kingsun->rx_unwrap_buff.head = NULL; + } + return err; +} + +/* + * Function ksdazzle_net_close (dev) + * + * Network device is taken down. Usually this is done by + * "ifconfig irda0 down" + */ +static int ksdazzle_net_close(struct net_device *netdev) +{ + struct ksdazzle_cb *kingsun = netdev_priv(netdev); + + /* Stop transmit processing */ + netif_stop_queue(netdev); + + /* Mop up receive && transmit urb's */ + usb_kill_urb(kingsun->tx_urb); + usb_free_urb(kingsun->tx_urb); + kingsun->tx_urb = NULL; + + usb_kill_urb(kingsun->speed_urb); + usb_free_urb(kingsun->speed_urb); + kingsun->speed_urb = NULL; + + usb_kill_urb(kingsun->rx_urb); + usb_free_urb(kingsun->rx_urb); + kingsun->rx_urb = NULL; + + kfree_skb(kingsun->rx_unwrap_buff.skb); + kingsun->rx_unwrap_buff.skb = NULL; + kingsun->rx_unwrap_buff.head = NULL; + kingsun->rx_unwrap_buff.in_frame = FALSE; + kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME; + kingsun->receiving = 0; + + /* Stop and remove instance of IrLAP */ + irlap_close(kingsun->irlap); + + kingsun->irlap = NULL; + + return 0; +} + +/* + * IOCTLs : Extra out-of-band network commands... + */ +static int ksdazzle_net_ioctl(struct net_device *netdev, struct ifreq *rq, + int cmd) +{ + struct if_irda_req *irq = (struct if_irda_req *)rq; + struct ksdazzle_cb *kingsun = netdev_priv(netdev); + int ret = 0; + + switch (cmd) { + case SIOCSBANDWIDTH: /* Set bandwidth */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + /* Check if the device is still there */ + if (netif_device_present(kingsun->netdev)) + return ksdazzle_change_speed(kingsun, + irq->ifr_baudrate); + break; + + case SIOCSMEDIABUSY: /* Set media busy */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + /* Check if the IrDA stack is still there */ + if (netif_running(kingsun->netdev)) + irda_device_set_media_busy(kingsun->netdev, TRUE); + break; + + case SIOCGRECEIVING: + /* Only approximately true */ + irq->ifr_receiving = kingsun->receiving; + break; + + default: + ret = -EOPNOTSUPP; + } + + return ret; +} + +/* + * Get device stats (for /proc/net/dev and ifconfig) + */ +static struct net_device_stats *ksdazzle_net_get_stats(struct net_device + *netdev) +{ + struct ksdazzle_cb *kingsun = netdev_priv(netdev); + return &kingsun->stats; +} + +/* + * This routine is called by the USB subsystem for each new device + * in the system. We need to check if the device is ours, and in + * this case start handling it. + */ +static int ksdazzle_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_host_interface *interface; + struct usb_endpoint_descriptor *endpoint; + + struct usb_device *dev = interface_to_usbdev(intf); + struct ksdazzle_cb *kingsun = NULL; + struct net_device *net = NULL; + int ret = -ENOMEM; + int pipe, maxp_in, maxp_out; + __u8 ep_in; + __u8 ep_out; + + /* Check that there really are two interrupt endpoints. Check based on the + one in drivers/usb/input/usbmouse.c + */ + interface = intf->cur_altsetting; + if (interface->desc.bNumEndpoints != 2) { + err("ksdazzle: expected 2 endpoints, found %d", + interface->desc.bNumEndpoints); + return -ENODEV; + } + endpoint = &interface->endpoint[KINGSUN_EP_IN].desc; + if (!usb_endpoint_is_int_in(endpoint)) { + err("ksdazzle: endpoint 0 is not interrupt IN"); + return -ENODEV; + } + + ep_in = endpoint->bEndpointAddress; + pipe = usb_rcvintpipe(dev, ep_in); + maxp_in = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); + if (maxp_in > 255 || maxp_in <= 1) { + err("ksdazzle: endpoint 0 has max packet size %d not in range [2..255]", maxp_in); + return -ENODEV; + } + + endpoint = &interface->endpoint[KINGSUN_EP_OUT].desc; + if (!usb_endpoint_is_int_out(endpoint)) { + err("ksdazzle: endpoint 1 is not interrupt OUT"); + return -ENODEV; + } + + ep_out = endpoint->bEndpointAddress; + pipe = usb_sndintpipe(dev, ep_out); + maxp_out = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); + + /* Allocate network device container. */ + net = alloc_irdadev(sizeof(*kingsun)); + if (!net) + goto err_out1; + + SET_MODULE_OWNER(net); + SET_NETDEV_DEV(net, &intf->dev); + kingsun = netdev_priv(net); + kingsun->netdev = net; + kingsun->usbdev = dev; + kingsun->ep_in = ep_in; + kingsun->ep_out = ep_out; + kingsun->irlap = NULL; + kingsun->tx_urb = NULL; + kingsun->tx_buf_clear = NULL; + kingsun->tx_buf_clear_used = 0; + kingsun->tx_buf_clear_sent = 0; + + kingsun->rx_urb = NULL; + kingsun->rx_unwrap_buff.in_frame = FALSE; + kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME; + kingsun->rx_unwrap_buff.skb = NULL; + kingsun->receiving = 0; + spin_lock_init(&kingsun->lock); + + kingsun->speed_setuprequest = NULL; + kingsun->speed_urb = NULL; + kingsun->speedparams.baudrate = 0; + + /* Allocate output buffer */ + kingsun->tx_buf_clear = kmalloc(KINGSUN_SND_FIFO_SIZE, GFP_KERNEL); + if (!kingsun->tx_buf_clear) + goto free_mem; + + /* Allocate and initialize speed setup packet */ + kingsun->speed_setuprequest = + kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); + if (!kingsun->speed_setuprequest) + goto free_mem; + kingsun->speed_setuprequest->bRequestType = + USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE; + kingsun->speed_setuprequest->bRequest = KINGSUN_REQ_SEND; + kingsun->speed_setuprequest->wValue = cpu_to_le16(0x0200); + kingsun->speed_setuprequest->wIndex = cpu_to_le16(0x0001); + kingsun->speed_setuprequest->wLength = + cpu_to_le16(sizeof(struct ksdazzle_speedparams)); + + printk(KERN_INFO "KingSun/Dazzle IRDA/USB found at address %d, " + "Vendor: %x, Product: %x\n", + dev->devnum, le16_to_cpu(dev->descriptor.idVendor), + le16_to_cpu(dev->descriptor.idProduct)); + + /* Initialize QoS for this device */ + irda_init_max_qos_capabilies(&kingsun->qos); + + /* Baud rates known to be supported. Please uncomment if devices (other + than a SonyEriccson K300 phone) can be shown to support higher speeds + with this dongle. + */ + kingsun->qos.baud_rate.bits = + IR_2400 | IR_9600 | IR_19200 | IR_38400 | IR_57600 | IR_115200; + kingsun->qos.min_turn_time.bits &= KINGSUN_MTT; + irda_qos_bits_to_value(&kingsun->qos); + + /* Override the network functions we need to use */ + net->hard_start_xmit = ksdazzle_hard_xmit; + net->open = ksdazzle_net_open; + net->stop = ksdazzle_net_close; + net->get_stats = ksdazzle_net_get_stats; + net->do_ioctl = ksdazzle_net_ioctl; + + ret = register_netdev(net); + if (ret != 0) + goto free_mem; + + info("IrDA: Registered KingSun/Dazzle device %s", net->name); + + usb_set_intfdata(intf, kingsun); + + /* Situation at this point: + - all work buffers allocated + - setup requests pre-filled + - urbs not allocated, set to NULL + - max rx packet known (is KINGSUN_FIFO_SIZE) + - unwrap state machine (partially) initialized, but skb == NULL + */ + + return 0; + + free_mem: + kfree(kingsun->speed_setuprequest); + kfree(kingsun->tx_buf_clear); + free_netdev(net); + err_out1: + return ret; +} + +/* + * The current device is removed, the USB layer tell us to shut it down... + */ +static void ksdazzle_disconnect(struct usb_interface *intf) +{ + struct ksdazzle_cb *kingsun = usb_get_intfdata(intf); + + if (!kingsun) + return; + + unregister_netdev(kingsun->netdev); + + /* Mop up receive && transmit urb's */ + usb_kill_urb(kingsun->speed_urb); + usb_free_urb(kingsun->speed_urb); + kingsun->speed_urb = NULL; + + usb_kill_urb(kingsun->tx_urb); + usb_free_urb(kingsun->tx_urb); + kingsun->tx_urb = NULL; + + usb_kill_urb(kingsun->rx_urb); + usb_free_urb(kingsun->rx_urb); + kingsun->rx_urb = NULL; + + kfree(kingsun->speed_setuprequest); + kfree(kingsun->tx_buf_clear); + free_netdev(kingsun->netdev); + + usb_set_intfdata(intf, NULL); +} + +#ifdef CONFIG_PM +/* USB suspend, so power off the transmitter/receiver */ +static int ksdazzle_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct ksdazzle_cb *kingsun = usb_get_intfdata(intf); + + netif_device_detach(kingsun->netdev); + if (kingsun->speed_urb != NULL) + usb_kill_urb(kingsun->speed_urb); + if (kingsun->tx_urb != NULL) + usb_kill_urb(kingsun->tx_urb); + if (kingsun->rx_urb != NULL) + usb_kill_urb(kingsun->rx_urb); + return 0; +} + +/* Coming out of suspend, so reset hardware */ +static int ksdazzle_resume(struct usb_interface *intf) +{ + struct ksdazzle_cb *kingsun = usb_get_intfdata(intf); + + if (kingsun->rx_urb != NULL) { + /* Setup request already filled in ksdazzle_probe */ + usb_submit_urb(kingsun->rx_urb, GFP_KERNEL); + } + netif_device_attach(kingsun->netdev); + + return 0; +} +#endif + +/* + * USB device callbacks + */ +static struct usb_driver irda_driver = { + .name = "ksdazzle-sir", + .probe = ksdazzle_probe, + .disconnect = ksdazzle_disconnect, + .id_table = dongles, +#ifdef CONFIG_PM + .suspend = ksdazzle_suspend, + .resume = ksdazzle_resume, +#endif +}; + +/* + * Module insertion + */ +static int __init ksdazzle_init(void) +{ + return usb_register(&irda_driver); +} + +module_init(ksdazzle_init); + +/* + * Module removal + */ +static void __exit ksdazzle_cleanup(void) +{ + /* Deregister the driver and remove all pending instances */ + usb_deregister(&irda_driver); +} + +module_exit(ksdazzle_cleanup); + +MODULE_AUTHOR("Alex Villacís Lasso "); +MODULE_DESCRIPTION("IrDA-USB Dongle Driver for KingSun Dazzle"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-70-g09d2 From 4b6aa59999a3a12dd4740a52299c6c33e85a8747 Mon Sep 17 00:00:00 2001 From: Alex Villacís Lasso Date: Tue, 28 Aug 2007 15:58:31 -0700 Subject: [IrDA]: Kingsun KS-959 IrDA USB driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This dongle does not follow the usb-irda specification, so it needs its own special driver. First, it uses control URBs for data transfer, instead of bulk or interrupt transfers; the only interrupt endpoint exposed seems to be a dummy to prevent the interface from being rejected. Second, it uses obfuscation and padding at the USB traffic level, for no apparent reason other than to make reverse engineering harder (full details on obfuscation in comments at beginning of source). Although it is advertised as a "4 Mbps FIR dongle", it apparently loses packets at speeds greater than 57600 bps. On plugin, this dongle reports vendor and device IDs: 0x07d0:0x4959 . The Windows driver that is used normally to control this dongle has a filename of KS-959.SYS . Signed-off-by: Alex Villacís Lasso Signed-off-by: Samuel Ortiz Signed-off-by: David S. Miller --- drivers/net/irda/Kconfig | 14 + drivers/net/irda/Makefile | 1 + drivers/net/irda/ks959-sir.c | 939 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 954 insertions(+) create mode 100644 drivers/net/irda/ks959-sir.c (limited to 'drivers') diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig index cfa7b8835d3..65806956728 100644 --- a/drivers/net/irda/Kconfig +++ b/drivers/net/irda/Kconfig @@ -176,6 +176,20 @@ config KSDAZZLE_DONGLE To compile it as a module, choose M here: the module will be called ksdazzle-sir. +config KS959_DONGLE + tristate "KingSun KS-959 IrDA-USB dongle (EXPERIMENTAL)" + depends on IRDA && USB && EXPERIMENTAL + help + Say Y or M here if you want to build support for the KingSun KS-959 + IrDA-USB bridge device driver. + + This USB bridge does not conform to the IrDA-USB device class + specification, and therefore needs its own specific driver. This + dongle supports SIR speeds only (9600 through 57600 bps). + + To compile it as a module, choose M here: the module will be called + ks959-sir. + comment "Old SIR device drivers" config IRPORT_SIR diff --git a/drivers/net/irda/Makefile b/drivers/net/irda/Makefile index e19da3b919a..fefbb590908 100644 --- a/drivers/net/irda/Makefile +++ b/drivers/net/irda/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_TOIM3232_DONGLE) += toim3232-sir.o obj-$(CONFIG_EP7211_DONGLE) += ep7211-sir.o obj-$(CONFIG_KINGSUN_DONGLE) += kingsun-sir.o obj-$(CONFIG_KSDAZZLE_DONGLE) += ksdazzle-sir.o +obj-$(CONFIG_KS959_DONGLE) += ks959-sir.o # The SIR helper module sir-dev-objs := sir_dev.o sir_dongle.o diff --git a/drivers/net/irda/ks959-sir.c b/drivers/net/irda/ks959-sir.c new file mode 100644 index 00000000000..407afba1a59 --- /dev/null +++ b/drivers/net/irda/ks959-sir.c @@ -0,0 +1,939 @@ +/***************************************************************************** +* +* Filename: ks959-sir.c +* Version: 0.1.2 +* Description: Irda KingSun KS-959 USB Dongle +* Status: Experimental +* Author: Alex Villacís Lasso +* with help from Domen Puncer +* +* Based on stir4200, mcs7780, kingsun-sir drivers. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + +/* + * Following is my most current (2007-07-17) understanding of how the Kingsun + * KS-959 dongle is supposed to work. This information was deduced by + * reverse-engineering and examining the USB traffic captured with USBSnoopy + * from the WinXP driver. Feel free to update here as more of the dongle is + * known. + * + * My most sincere thanks must go to Domen Puncer for + * invaluable help in cracking the obfuscation and padding required for this + * dongle. + * + * General: This dongle exposes one interface with one interrupt IN endpoint. + * However, the interrupt endpoint is NOT used at all for this dongle. Instead, + * this dongle uses control transfers for everything, including sending and + * receiving the IrDA frame data. Apparently the interrupt endpoint is just a + * dummy to ensure the dongle has a valid interface to present to the PC.And I + * thought the DonShine dongle was weird... In addition, this dongle uses + * obfuscation (?!?!), applied at the USB level, to hide the traffic, both sent + * and received, from the dongle. I call it obfuscation because the XOR keying + * and padding required to produce an USB traffic acceptable for the dongle can + * not be explained by any other technical requirement. + * + * Transmission: To transmit an IrDA frame, the driver must prepare a control + * URB with the following as a setup packet: + * bRequestType USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE + * bRequest 0x09 + * wValue + * wIndex 0x0000 + * wLength + * The payload packet must be manually wrapped and escaped (as in stir4200.c), + * then padded and obfuscated before being sent. Both padding and obfuscation + * are implemented in the procedure obfuscate_tx_buffer(). Suffice to say, the + * designer/programmer of the dongle used his name as a source for the + * obfuscation. WTF?! + * Apparently the dongle cannot handle payloads larger than 256 bytes. The + * driver has to perform fragmentation in order to send anything larger than + * this limit. + * + * Reception: To receive data, the driver must poll the dongle regularly (like + * kingsun-sir.c) with control URBs and the following as a setup packet: + * bRequestType USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE + * bRequest 0x01 + * wValue 0x0200 + * wIndex 0x0000 + * wLength 0x0800 (size of available buffer) + * If there is data to be read, it will be returned as the response payload. + * This data is (apparently) not padded, but it is obfuscated. To de-obfuscate + * it, the driver must XOR every byte, in sequence, with a value that starts at + * 1 and is incremented with each byte processed, and then with 0x55. The value + * incremented with each byte processed overflows as an unsigned char. The + * resulting bytes form a wrapped SIR frame that is unwrapped and unescaped + * as in stir4200.c The incremented value is NOT reset with each frame, but is + * kept across the entire session with the dongle. Also, the dongle inserts an + * extra garbage byte with value 0x95 (after decoding) every 0xff bytes, which + * must be skipped. + * + * Speed change: To change the speed of the dongle, the driver prepares a + * control URB with the following as a setup packet: + * bRequestType USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE + * bRequest 0x09 + * wValue 0x0200 + * wIndex 0x0001 + * wLength 0x0008 (length of the payload) + * The payload is a 8-byte record, apparently identical to the one used in + * drivers/usb/serial/cypress_m8.c to change speed: + * __u32 baudSpeed; + * unsigned int dataBits : 2; // 0 - 5 bits 3 - 8 bits + * unsigned int : 1; + * unsigned int stopBits : 1; + * unsigned int parityEnable : 1; + * unsigned int parityType : 1; + * unsigned int : 1; + * unsigned int reset : 1; + * unsigned char reserved[3]; // set to 0 + * + * For now only SIR speeds have been observed with this dongle. Therefore, + * nothing is known on what changes (if any) must be done to frame wrapping / + * unwrapping for higher than SIR speeds. This driver assumes no change is + * necessary and announces support for all the way to 57600 bps. Although the + * package announces support for up to 4MBps, tests with a Sony Ericcson K300 + * phone show corruption when receiving large frames at 115200 bps, the highest + * speed announced by the phone. However, transmission at 115200 bps is OK. Go + * figure. Since I don't know whether the phone or the dongle is at fault, max + * announced speed is 57600 bps until someone produces a device that can run + * at higher speeds with this dongle. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#define KS959_VENDOR_ID 0x07d0 +#define KS959_PRODUCT_ID 0x4959 + +/* These are the currently known USB ids */ +static struct usb_device_id dongles[] = { + /* KingSun Co,Ltd IrDA/USB Bridge */ + {USB_DEVICE(KS959_VENDOR_ID, KS959_PRODUCT_ID)}, + {} +}; + +MODULE_DEVICE_TABLE(usb, dongles); + +#define KINGSUN_MTT 0x07 +#define KINGSUN_REQ_RECV 0x01 +#define KINGSUN_REQ_SEND 0x09 + +#define KINGSUN_RCV_FIFO_SIZE 2048 /* Max length we can receive */ +#define KINGSUN_SND_FIFO_SIZE 2048 /* Max packet we can send */ +#define KINGSUN_SND_PACKET_SIZE 256 /* Max packet dongle can handle */ + +struct ks959_speedparams { + __le32 baudrate; /* baud rate, little endian */ + __u8 flags; + __u8 reserved[3]; +} __attribute__ ((packed)); + +#define KS_DATA_5_BITS 0x00 +#define KS_DATA_6_BITS 0x01 +#define KS_DATA_7_BITS 0x02 +#define KS_DATA_8_BITS 0x03 + +#define KS_STOP_BITS_1 0x00 +#define KS_STOP_BITS_2 0x08 + +#define KS_PAR_DISABLE 0x00 +#define KS_PAR_EVEN 0x10 +#define KS_PAR_ODD 0x30 +#define KS_RESET 0x80 + +struct ks959_cb { + struct usb_device *usbdev; /* init: probe_irda */ + struct net_device *netdev; /* network layer */ + struct irlap_cb *irlap; /* The link layer we are binded to */ + struct net_device_stats stats; /* network statistics */ + struct qos_info qos; + + struct usb_ctrlrequest *tx_setuprequest; + struct urb *tx_urb; + __u8 *tx_buf_clear; + unsigned int tx_buf_clear_used; + unsigned int tx_buf_clear_sent; + __u8 *tx_buf_xored; + + struct usb_ctrlrequest *rx_setuprequest; + struct urb *rx_urb; + __u8 *rx_buf; + __u8 rx_variable_xormask; + iobuff_t rx_unwrap_buff; + struct timeval rx_time; + + struct usb_ctrlrequest *speed_setuprequest; + struct urb *speed_urb; + struct ks959_speedparams speedparams; + unsigned int new_speed; + + spinlock_t lock; + int receiving; +}; + +/* Procedure to perform the obfuscation/padding expected by the dongle + * + * buf_cleartext (IN) Cleartext version of the IrDA frame to transmit + * len_cleartext (IN) Length of the cleartext version of IrDA frame + * buf_xoredtext (OUT) Obfuscated version of frame built by proc + * len_maxbuf (OUT) Maximum space available at buf_xoredtext + * + * (return) length of obfuscated frame with padding + * + * If not enough space (as indicated by len_maxbuf vs. required padding), + * zero is returned + * + * The value of lookup_string is actually a required portion of the algorithm. + * Seems the designer of the dongle wanted to state who exactly is responsible + * for implementing obfuscation. Send your best (or other) wishes to him ]:-) + */ +static unsigned int obfuscate_tx_buffer(const __u8 * buf_cleartext, + unsigned int len_cleartext, + __u8 * buf_xoredtext, + unsigned int len_maxbuf) +{ + unsigned int len_xoredtext; + + /* Calculate required length with padding, check for necessary space */ + len_xoredtext = ((len_cleartext + 7) & ~0x7) + 0x10; + if (len_xoredtext <= len_maxbuf) { + static const __u8 lookup_string[] = "wangshuofei19710"; + __u8 xor_mask; + + /* Unlike the WinXP driver, we *do* clear out the padding */ + memset(buf_xoredtext, 0, len_xoredtext); + + xor_mask = lookup_string[(len_cleartext & 0x0f) ^ 0x06] ^ 0x55; + + while (len_cleartext-- > 0) { + *buf_xoredtext++ = *buf_cleartext++ ^ xor_mask; + } + } else { + len_xoredtext = 0; + } + return len_xoredtext; +} + +/* Callback transmission routine */ +static void ks959_speed_irq(struct urb *urb) +{ + /* unlink, shutdown, unplug, other nasties */ + if (urb->status != 0) { + err("ks959_speed_irq: urb asynchronously failed - %d", + urb->status); + } +} + +/* Send a control request to change speed of the dongle */ +static int ks959_change_speed(struct ks959_cb *kingsun, unsigned speed) +{ + static unsigned int supported_speeds[] = { 2400, 9600, 19200, 38400, + 57600, 115200, 576000, 1152000, 4000000, 0 + }; + int err; + unsigned int i; + + if (kingsun->speed_setuprequest == NULL || kingsun->speed_urb == NULL) + return -ENOMEM; + + /* Check that requested speed is among the supported ones */ + for (i = 0; supported_speeds[i] && supported_speeds[i] != speed; i++) ; + if (supported_speeds[i] == 0) + return -EOPNOTSUPP; + + memset(&(kingsun->speedparams), 0, sizeof(struct ks959_speedparams)); + kingsun->speedparams.baudrate = cpu_to_le32(speed); + kingsun->speedparams.flags = KS_DATA_8_BITS; + + /* speed_setuprequest pre-filled in ks959_probe */ + usb_fill_control_urb(kingsun->speed_urb, kingsun->usbdev, + usb_sndctrlpipe(kingsun->usbdev, 0), + (unsigned char *)kingsun->speed_setuprequest, + &(kingsun->speedparams), + sizeof(struct ks959_speedparams), ks959_speed_irq, + kingsun); + kingsun->speed_urb->status = 0; + err = usb_submit_urb(kingsun->speed_urb, GFP_ATOMIC); + + return err; +} + +/* Submit one fragment of an IrDA frame to the dongle */ +static void ks959_send_irq(struct urb *urb); +static int ks959_submit_tx_fragment(struct ks959_cb *kingsun) +{ + unsigned int padlen; + unsigned int wraplen; + int ret; + + /* Check whether current plaintext can produce a padded buffer that fits + within the range handled by the dongle */ + wraplen = (KINGSUN_SND_PACKET_SIZE & ~0x7) - 0x10; + if (wraplen > kingsun->tx_buf_clear_used) + wraplen = kingsun->tx_buf_clear_used; + + /* Perform dongle obfuscation. Also remove the portion of the frame that + was just obfuscated and will now be sent to the dongle. */ + padlen = obfuscate_tx_buffer(kingsun->tx_buf_clear, wraplen, + kingsun->tx_buf_xored, + KINGSUN_SND_PACKET_SIZE); + + /* Calculate how much data can be transmitted in this urb */ + kingsun->tx_setuprequest->wValue = cpu_to_le16(wraplen); + kingsun->tx_setuprequest->wLength = cpu_to_le16(padlen); + /* Rest of the fields were filled in ks959_probe */ + usb_fill_control_urb(kingsun->tx_urb, kingsun->usbdev, + usb_sndctrlpipe(kingsun->usbdev, 0), + (unsigned char *)kingsun->tx_setuprequest, + kingsun->tx_buf_xored, padlen, + ks959_send_irq, kingsun); + kingsun->tx_urb->status = 0; + ret = usb_submit_urb(kingsun->tx_urb, GFP_ATOMIC); + + /* Remember how much data was sent, in order to update at callback */ + kingsun->tx_buf_clear_sent = (ret == 0) ? wraplen : 0; + return ret; +} + +/* Callback transmission routine */ +static void ks959_send_irq(struct urb *urb) +{ + struct ks959_cb *kingsun = urb->context; + struct net_device *netdev = kingsun->netdev; + int ret = 0; + + /* in process of stopping, just drop data */ + if (!netif_running(kingsun->netdev)) { + err("ks959_send_irq: Network not running!"); + return; + } + + /* unlink, shutdown, unplug, other nasties */ + if (urb->status != 0) { + err("ks959_send_irq: urb asynchronously failed - %d", + urb->status); + return; + } + + if (kingsun->tx_buf_clear_used > 0) { + /* Update data remaining to be sent */ + if (kingsun->tx_buf_clear_sent < kingsun->tx_buf_clear_used) { + memmove(kingsun->tx_buf_clear, + kingsun->tx_buf_clear + + kingsun->tx_buf_clear_sent, + kingsun->tx_buf_clear_used - + kingsun->tx_buf_clear_sent); + } + kingsun->tx_buf_clear_used -= kingsun->tx_buf_clear_sent; + kingsun->tx_buf_clear_sent = 0; + + if (kingsun->tx_buf_clear_used > 0) { + /* There is more data to be sent */ + if ((ret = ks959_submit_tx_fragment(kingsun)) != 0) { + err("ks959_send_irq: failed tx_urb submit: %d", + ret); + switch (ret) { + case -ENODEV: + case -EPIPE: + break; + default: + kingsun->stats.tx_errors++; + netif_start_queue(netdev); + } + } + } else { + /* All data sent, send next speed && wake network queue */ + if (kingsun->new_speed != -1 && + cpu_to_le32(kingsun->new_speed) != + kingsun->speedparams.baudrate) + ks959_change_speed(kingsun, kingsun->new_speed); + + netif_wake_queue(netdev); + } + } +} + +/* + * Called from net/core when new frame is available. + */ +static int ks959_hard_xmit(struct sk_buff *skb, struct net_device *netdev) +{ + struct ks959_cb *kingsun; + unsigned int wraplen; + int ret = 0; + + if (skb == NULL || netdev == NULL) + return -EINVAL; + + netif_stop_queue(netdev); + + /* the IRDA wrapping routines don't deal with non linear skb */ + SKB_LINEAR_ASSERT(skb); + + kingsun = netdev_priv(netdev); + + spin_lock(&kingsun->lock); + kingsun->new_speed = irda_get_next_speed(skb); + + /* Append data to the end of whatever data remains to be transmitted */ + wraplen = + async_wrap_skb(skb, kingsun->tx_buf_clear, KINGSUN_SND_FIFO_SIZE); + kingsun->tx_buf_clear_used = wraplen; + + if ((ret = ks959_submit_tx_fragment(kingsun)) != 0) { + err("ks959_hard_xmit: failed tx_urb submit: %d", ret); + switch (ret) { + case -ENODEV: + case -EPIPE: + break; + default: + kingsun->stats.tx_errors++; + netif_start_queue(netdev); + } + } else { + kingsun->stats.tx_packets++; + kingsun->stats.tx_bytes += skb->len; + + } + + dev_kfree_skb(skb); + spin_unlock(&kingsun->lock); + + return ret; +} + +/* Receive callback function */ +static void ks959_rcv_irq(struct urb *urb) +{ + struct ks959_cb *kingsun = urb->context; + int ret; + + /* in process of stopping, just drop data */ + if (!netif_running(kingsun->netdev)) { + kingsun->receiving = 0; + return; + } + + /* unlink, shutdown, unplug, other nasties */ + if (urb->status != 0) { + err("kingsun_rcv_irq: urb asynchronously failed - %d", + urb->status); + kingsun->receiving = 0; + return; + } + + if (urb->actual_length > 0) { + __u8 *bytes = urb->transfer_buffer; + unsigned int i; + + for (i = 0; i < urb->actual_length; i++) { + /* De-obfuscation implemented here: variable portion of + xormask is incremented, and then used with the encoded + byte for the XOR. The result of the operation is used + to unwrap the SIR frame. */ + kingsun->rx_variable_xormask++; + bytes[i] = + bytes[i] ^ kingsun->rx_variable_xormask ^ 0x55u; + + /* rx_variable_xormask doubles as an index counter so we + can skip the byte at 0xff (wrapped around to 0). + */ + if (kingsun->rx_variable_xormask != 0) { + async_unwrap_char(kingsun->netdev, + &kingsun->stats, + &kingsun->rx_unwrap_buff, + bytes[i]); + } + } + kingsun->netdev->last_rx = jiffies; + do_gettimeofday(&kingsun->rx_time); + kingsun->receiving = + (kingsun->rx_unwrap_buff.state != OUTSIDE_FRAME) ? 1 : 0; + } + + /* This urb has already been filled in kingsun_net_open. Setup + packet must be re-filled, but it is assumed that urb keeps the + pointer to the initial setup packet, as well as the payload buffer. + Setup packet is already pre-filled at ks959_probe. + */ + urb->status = 0; + ret = usb_submit_urb(urb, GFP_ATOMIC); +} + +/* + * Function kingsun_net_open (dev) + * + * Network device is taken up. Usually this is done by "ifconfig irda0 up" + */ +static int ks959_net_open(struct net_device *netdev) +{ + struct ks959_cb *kingsun = netdev_priv(netdev); + int err = -ENOMEM; + char hwname[16]; + + /* At this point, urbs are NULL, and skb is NULL (see kingsun_probe) */ + kingsun->receiving = 0; + + /* Initialize for SIR to copy data directly into skb. */ + kingsun->rx_unwrap_buff.in_frame = FALSE; + kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME; + kingsun->rx_unwrap_buff.truesize = IRDA_SKB_MAX_MTU; + kingsun->rx_unwrap_buff.skb = dev_alloc_skb(IRDA_SKB_MAX_MTU); + if (!kingsun->rx_unwrap_buff.skb) + goto free_mem; + + skb_reserve(kingsun->rx_unwrap_buff.skb, 1); + kingsun->rx_unwrap_buff.head = kingsun->rx_unwrap_buff.skb->data; + do_gettimeofday(&kingsun->rx_time); + + kingsun->rx_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!kingsun->rx_urb) + goto free_mem; + + kingsun->tx_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!kingsun->tx_urb) + goto free_mem; + + kingsun->speed_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!kingsun->speed_urb) + goto free_mem; + + /* Initialize speed for dongle */ + kingsun->new_speed = 9600; + err = ks959_change_speed(kingsun, 9600); + if (err < 0) + goto free_mem; + + /* + * Now that everything should be initialized properly, + * Open new IrLAP layer instance to take care of us... + */ + sprintf(hwname, "usb#%d", kingsun->usbdev->devnum); + kingsun->irlap = irlap_open(netdev, &kingsun->qos, hwname); + if (!kingsun->irlap) { + err("ks959-sir: irlap_open failed"); + goto free_mem; + } + + /* Start reception. Setup request already pre-filled in ks959_probe */ + usb_fill_control_urb(kingsun->rx_urb, kingsun->usbdev, + usb_rcvctrlpipe(kingsun->usbdev, 0), + (unsigned char *)kingsun->rx_setuprequest, + kingsun->rx_buf, KINGSUN_RCV_FIFO_SIZE, + ks959_rcv_irq, kingsun); + kingsun->rx_urb->status = 0; + err = usb_submit_urb(kingsun->rx_urb, GFP_KERNEL); + if (err) { + err("ks959-sir: first urb-submit failed: %d", err); + goto close_irlap; + } + + netif_start_queue(netdev); + + /* Situation at this point: + - all work buffers allocated + - urbs allocated and ready to fill + - max rx packet known (in max_rx) + - unwrap state machine initialized, in state outside of any frame + - receive request in progress + - IrLAP layer started, about to hand over packets to send + */ + + return 0; + + close_irlap: + irlap_close(kingsun->irlap); + free_mem: + usb_free_urb(kingsun->speed_urb); + kingsun->speed_urb = NULL; + usb_free_urb(kingsun->tx_urb); + kingsun->tx_urb = NULL; + usb_free_urb(kingsun->rx_urb); + kingsun->rx_urb = NULL; + if (kingsun->rx_unwrap_buff.skb) { + kfree_skb(kingsun->rx_unwrap_buff.skb); + kingsun->rx_unwrap_buff.skb = NULL; + kingsun->rx_unwrap_buff.head = NULL; + } + return err; +} + +/* + * Function kingsun_net_close (kingsun) + * + * Network device is taken down. Usually this is done by + * "ifconfig irda0 down" + */ +static int ks959_net_close(struct net_device *netdev) +{ + struct ks959_cb *kingsun = netdev_priv(netdev); + + /* Stop transmit processing */ + netif_stop_queue(netdev); + + /* Mop up receive && transmit urb's */ + usb_kill_urb(kingsun->tx_urb); + usb_free_urb(kingsun->tx_urb); + kingsun->tx_urb = NULL; + + usb_kill_urb(kingsun->speed_urb); + usb_free_urb(kingsun->speed_urb); + kingsun->speed_urb = NULL; + + usb_kill_urb(kingsun->rx_urb); + usb_free_urb(kingsun->rx_urb); + kingsun->rx_urb = NULL; + + kfree_skb(kingsun->rx_unwrap_buff.skb); + kingsun->rx_unwrap_buff.skb = NULL; + kingsun->rx_unwrap_buff.head = NULL; + kingsun->rx_unwrap_buff.in_frame = FALSE; + kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME; + kingsun->receiving = 0; + + /* Stop and remove instance of IrLAP */ + if (kingsun->irlap) + irlap_close(kingsun->irlap); + + kingsun->irlap = NULL; + + return 0; +} + +/* + * IOCTLs : Extra out-of-band network commands... + */ +static int ks959_net_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) +{ + struct if_irda_req *irq = (struct if_irda_req *)rq; + struct ks959_cb *kingsun = netdev_priv(netdev); + int ret = 0; + + switch (cmd) { + case SIOCSBANDWIDTH: /* Set bandwidth */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + /* Check if the device is still there */ + if (netif_device_present(kingsun->netdev)) + return ks959_change_speed(kingsun, irq->ifr_baudrate); + break; + + case SIOCSMEDIABUSY: /* Set media busy */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + /* Check if the IrDA stack is still there */ + if (netif_running(kingsun->netdev)) + irda_device_set_media_busy(kingsun->netdev, TRUE); + break; + + case SIOCGRECEIVING: + /* Only approximately true */ + irq->ifr_receiving = kingsun->receiving; + break; + + default: + ret = -EOPNOTSUPP; + } + + return ret; +} + +/* + * Get device stats (for /proc/net/dev and ifconfig) + */ +static struct net_device_stats *ks959_net_get_stats(struct net_device *netdev) +{ + struct ks959_cb *kingsun = netdev_priv(netdev); + return &kingsun->stats; +} + +/* + * This routine is called by the USB subsystem for each new device + * in the system. We need to check if the device is ours, and in + * this case start handling it. + */ +static int ks959_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *dev = interface_to_usbdev(intf); + struct ks959_cb *kingsun = NULL; + struct net_device *net = NULL; + int ret = -ENOMEM; + + /* Allocate network device container. */ + net = alloc_irdadev(sizeof(*kingsun)); + if (!net) + goto err_out1; + + SET_MODULE_OWNER(net); + SET_NETDEV_DEV(net, &intf->dev); + kingsun = netdev_priv(net); + kingsun->netdev = net; + kingsun->usbdev = dev; + kingsun->irlap = NULL; + kingsun->tx_setuprequest = NULL; + kingsun->tx_urb = NULL; + kingsun->tx_buf_clear = NULL; + kingsun->tx_buf_xored = NULL; + kingsun->tx_buf_clear_used = 0; + kingsun->tx_buf_clear_sent = 0; + + kingsun->rx_setuprequest = NULL; + kingsun->rx_urb = NULL; + kingsun->rx_buf = NULL; + kingsun->rx_variable_xormask = 0; + kingsun->rx_unwrap_buff.in_frame = FALSE; + kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME; + kingsun->rx_unwrap_buff.skb = NULL; + kingsun->receiving = 0; + spin_lock_init(&kingsun->lock); + + kingsun->speed_setuprequest = NULL; + kingsun->speed_urb = NULL; + kingsun->speedparams.baudrate = 0; + + /* Allocate input buffer */ + kingsun->rx_buf = kmalloc(KINGSUN_RCV_FIFO_SIZE, GFP_KERNEL); + if (!kingsun->rx_buf) + goto free_mem; + + /* Allocate input setup packet */ + kingsun->rx_setuprequest = + kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); + if (!kingsun->rx_setuprequest) + goto free_mem; + kingsun->rx_setuprequest->bRequestType = + USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE; + kingsun->rx_setuprequest->bRequest = KINGSUN_REQ_RECV; + kingsun->rx_setuprequest->wValue = cpu_to_le16(0x0200); + kingsun->rx_setuprequest->wIndex = 0; + kingsun->rx_setuprequest->wLength = cpu_to_le16(KINGSUN_RCV_FIFO_SIZE); + + /* Allocate output buffer */ + kingsun->tx_buf_clear = kmalloc(KINGSUN_SND_FIFO_SIZE, GFP_KERNEL); + if (!kingsun->tx_buf_clear) + goto free_mem; + kingsun->tx_buf_xored = kmalloc(KINGSUN_SND_PACKET_SIZE, GFP_KERNEL); + if (!kingsun->tx_buf_xored) + goto free_mem; + + /* Allocate and initialize output setup packet */ + kingsun->tx_setuprequest = + kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); + if (!kingsun->tx_setuprequest) + goto free_mem; + kingsun->tx_setuprequest->bRequestType = + USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE; + kingsun->tx_setuprequest->bRequest = KINGSUN_REQ_SEND; + kingsun->tx_setuprequest->wValue = 0; + kingsun->tx_setuprequest->wIndex = 0; + kingsun->tx_setuprequest->wLength = 0; + + /* Allocate and initialize speed setup packet */ + kingsun->speed_setuprequest = + kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); + if (!kingsun->speed_setuprequest) + goto free_mem; + kingsun->speed_setuprequest->bRequestType = + USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE; + kingsun->speed_setuprequest->bRequest = KINGSUN_REQ_SEND; + kingsun->speed_setuprequest->wValue = cpu_to_le16(0x0200); + kingsun->speed_setuprequest->wIndex = cpu_to_le16(0x0001); + kingsun->speed_setuprequest->wLength = + cpu_to_le16(sizeof(struct ks959_speedparams)); + + printk(KERN_INFO "KingSun KS-959 IRDA/USB found at address %d, " + "Vendor: %x, Product: %x\n", + dev->devnum, le16_to_cpu(dev->descriptor.idVendor), + le16_to_cpu(dev->descriptor.idProduct)); + + /* Initialize QoS for this device */ + irda_init_max_qos_capabilies(&kingsun->qos); + + /* Baud rates known to be supported. Please uncomment if devices (other + than a SonyEriccson K300 phone) can be shown to support higher speed + with this dongle. + */ + kingsun->qos.baud_rate.bits = + IR_2400 | IR_9600 | IR_19200 | IR_38400 | IR_57600; + kingsun->qos.min_turn_time.bits &= KINGSUN_MTT; + irda_qos_bits_to_value(&kingsun->qos); + + /* Override the network functions we need to use */ + net->hard_start_xmit = ks959_hard_xmit; + net->open = ks959_net_open; + net->stop = ks959_net_close; + net->get_stats = ks959_net_get_stats; + net->do_ioctl = ks959_net_ioctl; + + ret = register_netdev(net); + if (ret != 0) + goto free_mem; + + info("IrDA: Registered KingSun KS-959 device %s", net->name); + + usb_set_intfdata(intf, kingsun); + + /* Situation at this point: + - all work buffers allocated + - setup requests pre-filled + - urbs not allocated, set to NULL + - max rx packet known (is KINGSUN_FIFO_SIZE) + - unwrap state machine (partially) initialized, but skb == NULL + */ + + return 0; + + free_mem: + kfree(kingsun->speed_setuprequest); + kfree(kingsun->tx_setuprequest); + kfree(kingsun->tx_buf_xored); + kfree(kingsun->tx_buf_clear); + kfree(kingsun->rx_setuprequest); + kfree(kingsun->rx_buf); + free_netdev(net); + err_out1: + return ret; +} + +/* + * The current device is removed, the USB layer tell us to shut it down... + */ +static void ks959_disconnect(struct usb_interface *intf) +{ + struct ks959_cb *kingsun = usb_get_intfdata(intf); + + if (!kingsun) + return; + + unregister_netdev(kingsun->netdev); + + /* Mop up receive && transmit urb's */ + if (kingsun->speed_urb != NULL) { + usb_kill_urb(kingsun->speed_urb); + usb_free_urb(kingsun->speed_urb); + kingsun->speed_urb = NULL; + } + if (kingsun->tx_urb != NULL) { + usb_kill_urb(kingsun->tx_urb); + usb_free_urb(kingsun->tx_urb); + kingsun->tx_urb = NULL; + } + if (kingsun->rx_urb != NULL) { + usb_kill_urb(kingsun->rx_urb); + usb_free_urb(kingsun->rx_urb); + kingsun->rx_urb = NULL; + } + + kfree(kingsun->speed_setuprequest); + kfree(kingsun->tx_setuprequest); + kfree(kingsun->tx_buf_xored); + kfree(kingsun->tx_buf_clear); + kfree(kingsun->rx_setuprequest); + kfree(kingsun->rx_buf); + free_netdev(kingsun->netdev); + + usb_set_intfdata(intf, NULL); +} + +#ifdef CONFIG_PM +/* USB suspend, so power off the transmitter/receiver */ +static int ks959_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct ks959_cb *kingsun = usb_get_intfdata(intf); + + netif_device_detach(kingsun->netdev); + if (kingsun->speed_urb != NULL) + usb_kill_urb(kingsun->speed_urb); + if (kingsun->tx_urb != NULL) + usb_kill_urb(kingsun->tx_urb); + if (kingsun->rx_urb != NULL) + usb_kill_urb(kingsun->rx_urb); + return 0; +} + +/* Coming out of suspend, so reset hardware */ +static int ks959_resume(struct usb_interface *intf) +{ + struct ks959_cb *kingsun = usb_get_intfdata(intf); + + if (kingsun->rx_urb != NULL) { + /* Setup request already filled in ks959_probe */ + usb_submit_urb(kingsun->rx_urb, GFP_KERNEL); + } + netif_device_attach(kingsun->netdev); + + return 0; +} +#endif + +/* + * USB device callbacks + */ +static struct usb_driver irda_driver = { + .name = "ks959-sir", + .probe = ks959_probe, + .disconnect = ks959_disconnect, + .id_table = dongles, +#ifdef CONFIG_PM + .suspend = ks959_suspend, + .resume = ks959_resume, +#endif +}; + +/* + * Module insertion + */ +static int __init ks959_init(void) +{ + return usb_register(&irda_driver); +} + +module_init(ks959_init); + +/* + * Module removal + */ +static void __exit ks959_cleanup(void) +{ + /* Deregister the driver and remove all pending instances */ + usb_deregister(&irda_driver); +} + +module_exit(ks959_cleanup); + +MODULE_AUTHOR("Alex Villacís Lasso "); +MODULE_DESCRIPTION("IrDA-USB Dongle Driver for KingSun KS-959"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-70-g09d2 From aaa92e9a743c740005d8a592dbc1b3ca310d35b5 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 6 Sep 2007 03:36:10 -0700 Subject: [MAC80211]: remove IEEE80211_HW_DATA_NULLFUNC_ACK Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/rtl8187_dev.c | 3 +-- include/net/mac80211.h | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index 73f1ebc7eec..9db9ece31b4 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c @@ -606,8 +606,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, priv->mode = IEEE80211_IF_TYPE_MGMT; dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_WEP_INCLUDE_IV | - IEEE80211_HW_DATA_NULLFUNC_ACK; + IEEE80211_HW_WEP_INCLUDE_IV; dev->extra_tx_headroom = sizeof(struct rtl8187_tx_hdr); dev->queues = 1; dev->max_rssi = 65; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index e635ca41a0d..427ff6d3626 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -491,8 +491,7 @@ struct ieee80211_hw { #define IEEE80211_HW_WEP_INCLUDE_IV (1<<5) - /* will data nullfunc frames get proper TX status callback */ -#define IEEE80211_HW_DATA_NULLFUNC_ACK (1<<6) +/* hole at 6 */ /* Force software encryption for TKIP packets if WMM is enabled. */ #define IEEE80211_HW_NO_TKIP_WMM_HWACCEL (1<<7) -- cgit v1.2.3-70-g09d2 From ab0049b4a2f66074dff6af851b35bba888f53972 Mon Sep 17 00:00:00 2001 From: Andy Gospodarek Date: Thu, 6 Sep 2007 20:42:14 +0100 Subject: [TG3]: remove sparse warnings Removed sparse warnings from tg3 driver. The new logic seems fine (I don't immediately see where we are running over values for any of the variables that need to be saved). This patch compiles fine and I'm currently using a tg3 with the patched driver to post this patch as a basic proof of concept. Signed-off-by: Andy Gospodarek Signed-off-by: David S. Miller --- drivers/net/tg3.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index ef1e3d1173c..cbfa4df0959 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -4870,7 +4870,6 @@ static void tg3_restore_pci_state(struct tg3 *tp) pci_write_config_dword(tp->pdev, TG3PCI_X_CAPS, val); if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) { - u32 val; /* Chip reset on 5780 will reset MSI enable bit, * so need to restore it. @@ -5027,7 +5026,7 @@ static int tg3_chip_reset(struct tg3 *tp) tw32(GRC_MODE, tp->grc_mode); if (tp->pci_chip_rev_id == CHIPREV_ID_5705_A0) { - u32 val = tr32(0xc4); + val = tr32(0xc4); tw32(0xc4, val | (1 << 15)); } @@ -5056,7 +5055,7 @@ static int tg3_chip_reset(struct tg3 *tp) if ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) && tp->pci_chip_rev_id != CHIPREV_ID_5750_A0) { - u32 val = tr32(0x7c00); + val = tr32(0x7c00); tw32(0x7c00, val | (1 << 25)); } @@ -7991,7 +7990,7 @@ static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, buf = data; if (b_offset || odd_len) { buf = kmalloc(len, GFP_KERNEL); - if (buf == 0) + if (!buf) return -ENOMEM; if (b_offset) memcpy(buf, &start, 4); @@ -8420,7 +8419,7 @@ static void tg3_get_ethtool_stats (struct net_device *dev, static int tg3_test_nvram(struct tg3 *tp) { u32 *buf, csum, magic; - int i, j, err = 0, size; + int i, j, k, err = 0, size; if (tg3_nvram_read_swab(tp, 0, &magic) != 0) return -EIO; @@ -8474,7 +8473,6 @@ static int tg3_test_nvram(struct tg3 *tp) u8 data[NVRAM_SELFBOOT_DATA_SIZE]; u8 parity[NVRAM_SELFBOOT_DATA_SIZE]; u8 *buf8 = (u8 *) buf; - int j, k; /* Separate the parity bits and the data bytes. */ for (i = 0, j = 0, k = 0; i < NVRAM_SELFBOOT_HW_SIZE; i++) { @@ -10730,7 +10728,6 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) */ if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5700_BX) { u32 pm_reg; - u16 pci_cmd; tp->tg3_flags |= TG3_FLAG_PCIX_TARGET_HWBUG; @@ -11876,7 +11873,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, INIT_WORK(&tp->reset_task, tg3_reset_task); tp->regs = ioremap_nocache(tg3reg_base, tg3reg_len); - if (tp->regs == 0UL) { + if (!tp->regs) { printk(KERN_ERR PFX "Cannot map device registers, " "aborting.\n"); err = -ENOMEM; -- cgit v1.2.3-70-g09d2 From 457c4cbc5a3dde259d2a1f15d5f9785290397267 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 12 Sep 2007 12:01:34 +0200 Subject: [NET]: Make /proc/net per network namespace This patch makes /proc/net per network namespace. It modifies the global variables proc_net and proc_net_stat to be per network namespace. The proc_net file helpers are modified to take a network namespace argument, and all of their callers are fixed to pass &init_net for that argument. This ensures that all of the /proc/net files are only visible and usable in the initial network namespace until the code behind them has been updated to be handle multiple network namespaces. Making /proc/net per namespace is necessary as at least some files in /proc/net depend upon the set of network devices which is per network namespace, and even more files in /proc/net have contents that are relevant to a single network namespace. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- drivers/isdn/divert/divert_procfs.c | 7 ++-- drivers/isdn/hardware/eicon/diva_didd.c | 5 ++- drivers/isdn/hysdn/hysdn_procconf.c | 5 ++- drivers/net/bonding/bond_main.c | 7 ++-- drivers/net/hamradio/bpqether.c | 5 ++- drivers/net/hamradio/scc.c | 5 ++- drivers/net/hamradio/yam.c | 5 ++- drivers/net/ibmveth.c | 7 ++-- drivers/net/pppoe.c | 5 ++- drivers/net/pppol2tp.c | 5 ++- drivers/net/tokenring/lanstreamer.c | 5 ++- drivers/net/tokenring/olympic.c | 9 +++-- drivers/net/wireless/hostap/hostap_main.c | 7 ++-- drivers/net/wireless/strip.c | 5 ++- fs/proc/Makefile | 1 + fs/proc/internal.h | 5 +++ fs/proc/root.c | 8 ++-- include/linux/proc_fs.h | 44 ++++++++++------------ include/net/net_namespace.h | 5 +++ net/802/tr.c | 3 +- net/8021q/vlanproc.c | 5 ++- net/appletalk/atalk_proc.c | 7 ++-- net/atm/proc.c | 5 ++- net/ax25/af_ax25.c | 13 ++++--- net/core/dev.c | 19 +++++----- net/core/dev_mcast.c | 3 +- net/core/neighbour.c | 3 +- net/core/pktgen.c | 9 +++-- net/core/sock.c | 3 +- net/dccp/probe.c | 7 ++-- net/decnet/af_decnet.c | 5 ++- net/decnet/dn_dev.c | 5 ++- net/decnet/dn_neigh.c | 5 ++- net/decnet/dn_route.c | 5 ++- net/ieee80211/ieee80211_module.c | 7 ++-- net/ipv4/arp.c | 3 +- net/ipv4/fib_hash.c | 5 ++- net/ipv4/fib_trie.c | 17 +++++---- net/ipv4/igmp.c | 5 ++- net/ipv4/ipconfig.c | 3 +- net/ipv4/ipmr.c | 5 ++- net/ipv4/ipvs/ip_vs_app.c | 5 ++- net/ipv4/ipvs/ip_vs_conn.c | 5 ++- net/ipv4/ipvs/ip_vs_ctl.c | 9 +++-- net/ipv4/ipvs/ip_vs_lblcr.c | 5 ++- net/ipv4/netfilter/ip_queue.c | 8 ++-- net/ipv4/netfilter/ipt_CLUSTERIP.c | 3 +- net/ipv4/netfilter/ipt_recent.c | 5 ++- .../netfilter/nf_conntrack_l3proto_ipv4_compat.c | 17 +++++---- net/ipv4/proc.c | 11 +++--- net/ipv4/raw.c | 5 ++- net/ipv4/route.c | 7 ++-- net/ipv4/tcp_ipv4.c | 5 ++- net/ipv4/tcp_probe.c | 7 ++-- net/ipv4/udp.c | 5 ++- net/ipv6/addrconf.c | 7 ++-- net/ipv6/anycast.c | 5 ++- net/ipv6/ip6_flowlabel.c | 5 ++- net/ipv6/mcast.c | 9 +++-- net/ipv6/netfilter/ip6_queue.c | 7 ++-- net/ipv6/proc.c | 17 +++++---- net/ipv6/raw.c | 5 ++- net/ipv6/route.c | 9 +++-- net/ipx/ipx_proc.c | 7 ++-- net/irda/irproc.c | 5 ++- net/key/af_key.c | 5 ++- net/llc/llc_proc.c | 7 ++-- net/netfilter/core.c | 3 +- net/netfilter/nf_conntrack_expect.c | 5 ++- net/netfilter/nf_conntrack_standalone.c | 13 ++++--- net/netfilter/x_tables.c | 17 +++++---- net/netfilter/xt_hashlimit.c | 11 +++--- net/netlink/af_netlink.c | 3 +- net/netrom/af_netrom.c | 13 ++++--- net/packet/af_packet.c | 5 ++- net/rose/af_rose.c | 17 +++++---- net/rxrpc/af_rxrpc.c | 9 +++-- net/sched/sch_api.c | 3 +- net/sctp/protocol.c | 5 ++- net/sunrpc/stats.c | 5 ++- net/unix/af_unix.c | 5 ++- net/wanrouter/wanproc.c | 7 ++-- net/wireless/wext.c | 3 +- net/x25/x25_proc.c | 7 ++-- 84 files changed, 342 insertions(+), 261 deletions(-) (limited to 'drivers') diff --git a/drivers/isdn/divert/divert_procfs.c b/drivers/isdn/divert/divert_procfs.c index 559a0d0244c..4fd4c46892e 100644 --- a/drivers/isdn/divert/divert_procfs.c +++ b/drivers/isdn/divert/divert_procfs.c @@ -17,6 +17,7 @@ #include #endif #include +#include #include "isdn_divert.h" @@ -284,12 +285,12 @@ divert_dev_init(void) init_waitqueue_head(&rd_queue); #ifdef CONFIG_PROC_FS - isdn_proc_entry = proc_mkdir("net/isdn", NULL); + isdn_proc_entry = proc_mkdir("isdn", init_net.proc_net); if (!isdn_proc_entry) return (-1); isdn_divert_entry = create_proc_entry("divert", S_IFREG | S_IRUGO, isdn_proc_entry); if (!isdn_divert_entry) { - remove_proc_entry("net/isdn", NULL); + remove_proc_entry("isdn", init_net.proc_net); return (-1); } isdn_divert_entry->proc_fops = &isdn_fops; @@ -309,7 +310,7 @@ divert_dev_deinit(void) #ifdef CONFIG_PROC_FS remove_proc_entry("divert", isdn_proc_entry); - remove_proc_entry("net/isdn", NULL); + remove_proc_entry("isdn", init_net.proc_net); #endif /* CONFIG_PROC_FS */ return (0); diff --git a/drivers/isdn/hardware/eicon/diva_didd.c b/drivers/isdn/hardware/eicon/diva_didd.c index d755d904e62..993b14cf177 100644 --- a/drivers/isdn/hardware/eicon/diva_didd.c +++ b/drivers/isdn/hardware/eicon/diva_didd.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "platform.h" #include "di_defs.h" @@ -86,7 +87,7 @@ proc_read(char *page, char **start, off_t off, int count, int *eof, static int DIVA_INIT_FUNCTION create_proc(void) { - proc_net_eicon = proc_mkdir("net/eicon", NULL); + proc_net_eicon = proc_mkdir("eicon", init_net.proc_net); if (proc_net_eicon) { if ((proc_didd = @@ -102,7 +103,7 @@ static int DIVA_INIT_FUNCTION create_proc(void) static void remove_proc(void) { remove_proc_entry(DRIVERLNAME, proc_net_eicon); - remove_proc_entry("net/eicon", NULL); + remove_proc_entry("eicon", init_net.proc_net); } static int DIVA_INIT_FUNCTION divadidd_init(void) diff --git a/drivers/isdn/hysdn/hysdn_procconf.c b/drivers/isdn/hysdn/hysdn_procconf.c index dc477e0aab0..27d890b48f8 100644 --- a/drivers/isdn/hysdn/hysdn_procconf.c +++ b/drivers/isdn/hysdn/hysdn_procconf.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "hysdn_defs.h" @@ -392,7 +393,7 @@ hysdn_procconf_init(void) hysdn_card *card; unsigned char conf_name[20]; - hysdn_proc_entry = proc_mkdir(PROC_SUBDIR_NAME, proc_net); + hysdn_proc_entry = proc_mkdir(PROC_SUBDIR_NAME, init_net.proc_net); if (!hysdn_proc_entry) { printk(KERN_ERR "HYSDN: unable to create hysdn subdir\n"); return (-1); @@ -437,5 +438,5 @@ hysdn_procconf_release(void) card = card->next; /* point to next card */ } - remove_proc_entry(PROC_SUBDIR_NAME, proc_net); + remove_proc_entry(PROC_SUBDIR_NAME, init_net.proc_net); } diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 1afda3230de..5de648f90a4 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -75,6 +75,7 @@ #include #include #include +#include #include "bonding.h" #include "bond_3ad.h" #include "bond_alb.h" @@ -3144,7 +3145,7 @@ static void bond_create_proc_dir(void) { int len = strlen(DRV_NAME); - for (bond_proc_dir = proc_net->subdir; bond_proc_dir; + for (bond_proc_dir = init_net.proc_net->subdir; bond_proc_dir; bond_proc_dir = bond_proc_dir->next) { if ((bond_proc_dir->namelen == len) && !memcmp(bond_proc_dir->name, DRV_NAME, len)) { @@ -3153,7 +3154,7 @@ static void bond_create_proc_dir(void) } if (!bond_proc_dir) { - bond_proc_dir = proc_mkdir(DRV_NAME, proc_net); + bond_proc_dir = proc_mkdir(DRV_NAME, init_net.proc_net); if (bond_proc_dir) { bond_proc_dir->owner = THIS_MODULE; } else { @@ -3188,7 +3189,7 @@ static void bond_destroy_proc_dir(void) bond_proc_dir->owner = NULL; } } else { - remove_proc_entry(DRV_NAME, proc_net); + remove_proc_entry(DRV_NAME, init_net.proc_net); bond_proc_dir = NULL; } } diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index cc0ee93669e..1699d42d13c 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -83,6 +83,7 @@ #include #include +#include #include @@ -594,7 +595,7 @@ static int bpq_device_event(struct notifier_block *this,unsigned long event, voi static int __init bpq_init_driver(void) { #ifdef CONFIG_PROC_FS - if (!proc_net_fops_create("bpqether", S_IRUGO, &bpq_info_fops)) { + if (!proc_net_fops_create(&init_net, "bpqether", S_IRUGO, &bpq_info_fops)) { printk(KERN_ERR "bpq: cannot create /proc/net/bpqether entry.\n"); return -ENOENT; @@ -618,7 +619,7 @@ static void __exit bpq_cleanup_driver(void) unregister_netdevice_notifier(&bpq_dev_notifier); - proc_net_remove("bpqether"); + proc_net_remove(&init_net, "bpqether"); rtnl_lock(); while (!list_empty(&bpq_devices)) { diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c index 6fdaad5a457..39b3b82aa4a 100644 --- a/drivers/net/hamradio/scc.c +++ b/drivers/net/hamradio/scc.c @@ -174,6 +174,7 @@ #include #include +#include #include #include @@ -2114,7 +2115,7 @@ static int __init scc_init_driver (void) } rtnl_unlock(); - proc_net_fops_create("z8530drv", 0, &scc_net_seq_fops); + proc_net_fops_create(&init_net, "z8530drv", 0, &scc_net_seq_fops); return 0; } @@ -2169,7 +2170,7 @@ static void __exit scc_cleanup_driver(void) if (Vector_Latch) release_region(Vector_Latch, 1); - proc_net_remove("z8530drv"); + proc_net_remove(&init_net, "z8530drv"); } MODULE_AUTHOR("Joerg Reuter "); diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c index 467559debfd..401724ddafc 100644 --- a/drivers/net/hamradio/yam.c +++ b/drivers/net/hamradio/yam.c @@ -65,6 +65,7 @@ #include #include #include +#include #include #include @@ -1142,7 +1143,7 @@ static int __init yam_init_driver(void) yam_timer.expires = jiffies + HZ / 100; add_timer(&yam_timer); - proc_net_fops_create("yam", S_IRUGO, &yam_info_fops); + proc_net_fops_create(&init_net, "yam", S_IRUGO, &yam_info_fops); return 0; error: while (--i >= 0) { @@ -1174,7 +1175,7 @@ static void __exit yam_cleanup_driver(void) kfree(p); } - proc_net_remove("yam"); + proc_net_remove(&init_net, "yam"); } /* --------------------------------------------------------------------- */ diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 78e28ada1e2..0c35d72f5f8 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -97,7 +98,7 @@ static void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter); static struct kobj_type ktype_veth_pool; #ifdef CONFIG_PROC_FS -#define IBMVETH_PROC_DIR "net/ibmveth" +#define IBMVETH_PROC_DIR "ibmveth" static struct proc_dir_entry *ibmveth_proc_dir; #endif @@ -1091,7 +1092,7 @@ static int __devexit ibmveth_remove(struct vio_dev *dev) #ifdef CONFIG_PROC_FS static void ibmveth_proc_register_driver(void) { - ibmveth_proc_dir = proc_mkdir(IBMVETH_PROC_DIR, NULL); + ibmveth_proc_dir = proc_mkdir(IBMVETH_PROC_DIR, init_net.proc_net); if (ibmveth_proc_dir) { SET_MODULE_OWNER(ibmveth_proc_dir); } @@ -1099,7 +1100,7 @@ static void ibmveth_proc_register_driver(void) static void ibmveth_proc_unregister_driver(void) { - remove_proc_entry(IBMVETH_PROC_DIR, NULL); + remove_proc_entry(IBMVETH_PROC_DIR, init_net.proc_net); } static void *ibmveth_seq_start(struct seq_file *seq, loff_t *pos) diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index 9b30cd600a6..ee8ce195c53 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -78,6 +78,7 @@ #include #include +#include #include #include @@ -1042,7 +1043,7 @@ static int __init pppoe_proc_init(void) { struct proc_dir_entry *p; - p = create_proc_entry("net/pppoe", S_IRUGO, NULL); + p = create_proc_entry("pppoe", S_IRUGO, init_net.proc_net); if (!p) return -ENOMEM; @@ -1113,7 +1114,7 @@ static void __exit pppoe_exit(void) dev_remove_pack(&pppoes_ptype); dev_remove_pack(&pppoed_ptype); unregister_netdevice_notifier(&pppoe_notifier); - remove_proc_entry("net/pppoe", NULL); + remove_proc_entry("pppoe", init_net.proc_net); proto_unregister(&pppoe_sk_proto); } diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c index abe91cb595f..2eb424ba58e 100644 --- a/drivers/net/pppol2tp.c +++ b/drivers/net/pppol2tp.c @@ -91,6 +91,7 @@ #include #include #include +#include #include #include #include @@ -2444,7 +2445,7 @@ static int __init pppol2tp_init(void) goto out_unregister_pppol2tp_proto; #ifdef CONFIG_PROC_FS - pppol2tp_proc = create_proc_entry("pppol2tp", 0, proc_net); + pppol2tp_proc = create_proc_entry("pppol2tp", 0, init_net.proc_net); if (!pppol2tp_proc) { err = -ENOMEM; goto out_unregister_pppox_proto; @@ -2469,7 +2470,7 @@ static void __exit pppol2tp_exit(void) unregister_pppox_proto(PX_PROTO_OL2TP); #ifdef CONFIG_PROC_FS - remove_proc_entry("pppol2tp", proc_net); + remove_proc_entry("pppol2tp", init_net.proc_net); #endif proto_unregister(&pppol2tp_sk_proto); } diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c index 5d849c089a3..fc4495581f9 100644 --- a/drivers/net/tokenring/lanstreamer.c +++ b/drivers/net/tokenring/lanstreamer.c @@ -123,6 +123,7 @@ #include #include +#include #include #include @@ -250,7 +251,7 @@ static int __devinit streamer_init_one(struct pci_dev *pdev, #if STREAMER_NETWORK_MONITOR #ifdef CONFIG_PROC_FS if (!dev_streamer) - create_proc_read_entry("net/streamer_tr", 0, 0, + create_proc_read_entry("streamer_tr", 0, init_net.proc_net, streamer_proc_info, NULL); streamer_priv->next = dev_streamer; dev_streamer = streamer_priv; @@ -423,7 +424,7 @@ static void __devexit streamer_remove_one(struct pci_dev *pdev) } } if (!dev_streamer) - remove_proc_entry("net/streamer_tr", NULL); + remove_proc_entry("streamer_tr", init_net.proc_net); } #endif #endif diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c index 09b3cfb8e80..c323101a895 100644 --- a/drivers/net/tokenring/olympic.c +++ b/drivers/net/tokenring/olympic.c @@ -102,6 +102,7 @@ #include #include +#include #include #include @@ -268,9 +269,9 @@ static int __devinit olympic_probe(struct pci_dev *pdev, const struct pci_device printk("Olympic: %s registered as: %s\n",olympic_priv->olympic_card_name,dev->name); if (olympic_priv->olympic_network_monitor) { /* Must go after register_netdev as we need the device name */ char proc_name[20] ; - strcpy(proc_name,"net/olympic_") ; + strcpy(proc_name,"olympic_") ; strcat(proc_name,dev->name) ; - create_proc_read_entry(proc_name,0,NULL,olympic_proc_info,(void *)dev) ; + create_proc_read_entry(proc_name,0,init_net.proc_net,olympic_proc_info,(void *)dev) ; printk("Olympic: Network Monitor information: /proc/%s\n",proc_name); } return 0 ; @@ -1752,9 +1753,9 @@ static void __devexit olympic_remove_one(struct pci_dev *pdev) if (olympic_priv->olympic_network_monitor) { char proc_name[20] ; - strcpy(proc_name,"net/olympic_") ; + strcpy(proc_name,"olympic_") ; strcat(proc_name,dev->name) ; - remove_proc_entry(proc_name,NULL); + remove_proc_entry(proc_name,init_net.proc_net); } unregister_netdev(dev) ; iounmap(olympic_priv->olympic_mmio) ; diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c index 446de51bab7..9a470e80ca2 100644 --- a/drivers/net/wireless/hostap/hostap_main.c +++ b/drivers/net/wireless/hostap/hostap_main.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -1093,8 +1094,8 @@ struct proc_dir_entry *hostap_proc; static int __init hostap_init(void) { - if (proc_net != NULL) { - hostap_proc = proc_mkdir("hostap", proc_net); + if (init_net.proc_net != NULL) { + hostap_proc = proc_mkdir("hostap", init_net.proc_net); if (!hostap_proc) printk(KERN_WARNING "Failed to mkdir " "/proc/net/hostap\n"); @@ -1109,7 +1110,7 @@ static void __exit hostap_exit(void) { if (hostap_proc != NULL) { hostap_proc = NULL; - remove_proc_entry("hostap", proc_net); + remove_proc_entry("hostap", init_net.proc_net); } } diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c index ef32a5c1e81..edb214e8c74 100644 --- a/drivers/net/wireless/strip.c +++ b/drivers/net/wireless/strip.c @@ -107,6 +107,7 @@ static const char StripVersion[] = "1.3A-STUART.CHESHIRE"; #include #include #include +#include #include #include @@ -2787,7 +2788,7 @@ static int __init strip_init_driver(void) /* * Register the status file with /proc */ - proc_net_fops_create("strip", S_IFREG | S_IRUGO, &strip_seq_fops); + proc_net_fops_create(&init_net, "strip", S_IFREG | S_IRUGO, &strip_seq_fops); return status; } @@ -2809,7 +2810,7 @@ static void __exit strip_exit_driver(void) } /* Unregister with the /proc/net file here. */ - proc_net_remove("strip"); + proc_net_remove(&init_net, "strip"); if ((i = tty_unregister_ldisc(N_STRIP))) printk(KERN_ERR "STRIP: can't unregister line discipline (err = %d)\n", i); diff --git a/fs/proc/Makefile b/fs/proc/Makefile index bce38e3f06c..ebaba021354 100644 --- a/fs/proc/Makefile +++ b/fs/proc/Makefile @@ -11,6 +11,7 @@ proc-y += inode.o root.o base.o generic.o array.o \ proc_tty.o proc_misc.o proc-$(CONFIG_PROC_SYSCTL) += proc_sysctl.o +proc-$(CONFIG_NET) += proc_net.o proc-$(CONFIG_PROC_KCORE) += kcore.o proc-$(CONFIG_PROC_VMCORE) += vmcore.o proc-$(CONFIG_PROC_DEVICETREE) += proc_devtree.o diff --git a/fs/proc/internal.h b/fs/proc/internal.h index b215c3524fa..1820eb2ef76 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h @@ -16,6 +16,11 @@ extern int proc_sys_init(void); #else static inline void proc_sys_init(void) { } #endif +#ifdef CONFIG_NET +extern int proc_net_init(void); +#else +static inline int proc_net_init(void) { return 0; } +#endif struct vmalloc_info { unsigned long used; diff --git a/fs/proc/root.c b/fs/proc/root.c index 41f17037f73..cf3046638b0 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -21,7 +21,7 @@ #include "internal.h" -struct proc_dir_entry *proc_net, *proc_net_stat, *proc_bus, *proc_root_fs, *proc_root_driver; +struct proc_dir_entry *proc_bus, *proc_root_fs, *proc_root_driver; static int proc_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, struct vfsmount *mnt) @@ -61,8 +61,8 @@ void __init proc_root_init(void) return; } proc_misc_init(); - proc_net = proc_mkdir("net", NULL); - proc_net_stat = proc_mkdir("net/stat", NULL); + + proc_net_init(); #ifdef CONFIG_SYSVIPC proc_mkdir("sysvipc", NULL); @@ -159,7 +159,5 @@ EXPORT_SYMBOL(create_proc_entry); EXPORT_SYMBOL(remove_proc_entry); EXPORT_SYMBOL(proc_root); EXPORT_SYMBOL(proc_root_fs); -EXPORT_SYMBOL(proc_net); -EXPORT_SYMBOL(proc_net_stat); EXPORT_SYMBOL(proc_bus); EXPORT_SYMBOL(proc_root_driver); diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index cd13a78c5db..59646705f15 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -7,6 +7,7 @@ #include #include +struct net; struct completion; /* @@ -97,8 +98,6 @@ struct vmcore { extern struct proc_dir_entry proc_root; extern struct proc_dir_entry *proc_root_fs; -extern struct proc_dir_entry *proc_net; -extern struct proc_dir_entry *proc_net_stat; extern struct proc_dir_entry *proc_bus; extern struct proc_dir_entry *proc_root_driver; extern struct proc_dir_entry *proc_root_kcore; @@ -192,36 +191,21 @@ static inline struct proc_dir_entry *create_proc_info_entry(const char *name, if (res) res->get_info=get_info; return res; } - -static inline struct proc_dir_entry *proc_net_create(const char *name, - mode_t mode, get_info_t *get_info) -{ - return create_proc_info_entry(name,mode,proc_net,get_info); -} -static inline struct proc_dir_entry *proc_net_fops_create(const char *name, - mode_t mode, const struct file_operations *fops) -{ - struct proc_dir_entry *res = create_proc_entry(name, mode, proc_net); - if (res) - res->proc_fops = fops; - return res; -} - -static inline void proc_net_remove(const char *name) -{ - remove_proc_entry(name,proc_net); -} +extern struct proc_dir_entry *proc_net_create(struct net *net, + const char *name, mode_t mode, get_info_t *get_info); +extern struct proc_dir_entry *proc_net_fops_create(struct net *net, + const char *name, mode_t mode, const struct file_operations *fops); +extern void proc_net_remove(struct net *net, const char *name); #else #define proc_root_driver NULL -#define proc_net NULL #define proc_bus NULL -#define proc_net_fops_create(name, mode, fops) ({ (void)(mode), NULL; }) -#define proc_net_create(name, mode, info) ({ (void)(mode), NULL; }) -static inline void proc_net_remove(const char *name) {} +#define proc_net_fops_create(net, name, mode, fops) ({ (void)(mode), NULL; }) +#define proc_net_create(net, name, mode, info) ({ (void)(mode), NULL; }) +static inline void proc_net_remove(struct net *net, const char *name) {} static inline void proc_flush_task(struct task_struct *task) { } @@ -281,6 +265,16 @@ static inline struct proc_dir_entry *PDE(const struct inode *inode) return PROC_I(inode)->pde; } +static inline struct net *PDE_NET(struct proc_dir_entry *pde) +{ + return pde->parent->data; +} + +static inline struct net *PROC_NET(const struct inode *inode) +{ + return PDE_NET(PDE(inode)); +} + struct proc_maps_private { struct pid *pid; struct task_struct *task; diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 6344b77f81a..54724768134 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -8,6 +8,7 @@ #include #include +struct proc_dir_entry; struct net { atomic_t count; /* To decided when the network * namespace should be freed. @@ -17,6 +18,10 @@ struct net { */ struct list_head list; /* list of network namespaces */ struct work_struct work; /* work struct for freeing */ + + struct proc_dir_entry *proc_net; + struct proc_dir_entry *proc_net_stat; + struct proc_dir_entry *proc_net_root; }; extern struct net init_net; diff --git a/net/802/tr.c b/net/802/tr.c index e56e61a7f54..032c31e748e 100644 --- a/net/802/tr.c +++ b/net/802/tr.c @@ -36,6 +36,7 @@ #include #include #include +#include static void tr_add_rif_info(struct trh_hdr *trh, struct net_device *dev); static void rif_check_expire(unsigned long dummy); @@ -639,7 +640,7 @@ static int __init rif_init(void) rif_timer.function = rif_check_expire; add_timer(&rif_timer); - proc_net_fops_create("tr_rif", S_IRUGO, &rif_seq_fops); + proc_net_fops_create(&init_net, "tr_rif", S_IRUGO, &rif_seq_fops); return 0; } diff --git a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c index bd08aa09076..ac80e6b9ef5 100644 --- a/net/8021q/vlanproc.c +++ b/net/8021q/vlanproc.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "vlanproc.h" #include "vlan.h" @@ -143,7 +144,7 @@ void vlan_proc_cleanup(void) remove_proc_entry(name_conf, proc_vlan_dir); if (proc_vlan_dir) - proc_net_remove(name_root); + proc_net_remove(&init_net, name_root); /* Dynamically added entries should be cleaned up as their vlan_device * is removed, so we should not have to take care of it here... @@ -156,7 +157,7 @@ void vlan_proc_cleanup(void) int __init vlan_proc_init(void) { - proc_vlan_dir = proc_mkdir(name_root, proc_net); + proc_vlan_dir = proc_mkdir(name_root, init_net.proc_net); if (proc_vlan_dir) { proc_vlan_conf = create_proc_entry(name_conf, S_IFREG|S_IRUSR|S_IWUSR, diff --git a/net/appletalk/atalk_proc.c b/net/appletalk/atalk_proc.c index 87a582cc811..05d9652afcb 100644 --- a/net/appletalk/atalk_proc.c +++ b/net/appletalk/atalk_proc.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -271,7 +272,7 @@ int __init atalk_proc_init(void) struct proc_dir_entry *p; int rc = -ENOMEM; - atalk_proc_dir = proc_mkdir("atalk", proc_net); + atalk_proc_dir = proc_mkdir("atalk", init_net.proc_net); if (!atalk_proc_dir) goto out; atalk_proc_dir->owner = THIS_MODULE; @@ -306,7 +307,7 @@ out_socket: out_route: remove_proc_entry("interface", atalk_proc_dir); out_interface: - remove_proc_entry("atalk", proc_net); + remove_proc_entry("atalk", init_net.proc_net); goto out; } @@ -316,5 +317,5 @@ void __exit atalk_proc_exit(void) remove_proc_entry("route", atalk_proc_dir); remove_proc_entry("socket", atalk_proc_dir); remove_proc_entry("arp", atalk_proc_dir); - remove_proc_entry("atalk", proc_net); + remove_proc_entry("atalk", init_net.proc_net); } diff --git a/net/atm/proc.c b/net/atm/proc.c index 99fc1fe950e..3a6be64b051 100644 --- a/net/atm/proc.c +++ b/net/atm/proc.c @@ -22,6 +22,7 @@ #include #include #include /* for __init */ +#include #include #include #include @@ -475,7 +476,7 @@ static void atm_proc_dirs_remove(void) if (e->dirent) remove_proc_entry(e->name, atm_proc_root); } - remove_proc_entry("net/atm", NULL); + remove_proc_entry("atm", init_net.proc_net); } int __init atm_proc_init(void) @@ -483,7 +484,7 @@ int __init atm_proc_init(void) static struct atm_proc_entry *e; int ret; - atm_proc_root = proc_mkdir("net/atm",NULL); + atm_proc_root = proc_mkdir("atm", init_net.proc_net); if (!atm_proc_root) goto err_out; for (e = atm_proc_ents; e->name; e++) { diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index dae2a42d3d8..1d71f85680b 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -1998,9 +1999,9 @@ static int __init ax25_init(void) register_netdevice_notifier(&ax25_dev_notifier); ax25_register_sysctl(); - proc_net_fops_create("ax25_route", S_IRUGO, &ax25_route_fops); - proc_net_fops_create("ax25", S_IRUGO, &ax25_info_fops); - proc_net_fops_create("ax25_calls", S_IRUGO, &ax25_uid_fops); + proc_net_fops_create(&init_net, "ax25_route", S_IRUGO, &ax25_route_fops); + proc_net_fops_create(&init_net, "ax25", S_IRUGO, &ax25_info_fops); + proc_net_fops_create(&init_net, "ax25_calls", S_IRUGO, &ax25_uid_fops); out: return rc; } @@ -2014,9 +2015,9 @@ MODULE_ALIAS_NETPROTO(PF_AX25); static void __exit ax25_exit(void) { - proc_net_remove("ax25_route"); - proc_net_remove("ax25"); - proc_net_remove("ax25_calls"); + proc_net_remove(&init_net, "ax25_route"); + proc_net_remove(&init_net, "ax25"); + proc_net_remove(&init_net, "ax25_calls"); ax25_rt_free(); ax25_uid_free(); ax25_dev_free(); diff --git a/net/core/dev.c b/net/core/dev.c index 29cf00c5d86..618fb1c1dd4 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -92,6 +92,7 @@ #include #include #include +#include #include #include #include @@ -2556,24 +2557,24 @@ static int __init dev_proc_init(void) { int rc = -ENOMEM; - if (!proc_net_fops_create("dev", S_IRUGO, &dev_seq_fops)) + if (!proc_net_fops_create(&init_net, "dev", S_IRUGO, &dev_seq_fops)) goto out; - if (!proc_net_fops_create("softnet_stat", S_IRUGO, &softnet_seq_fops)) + if (!proc_net_fops_create(&init_net, "softnet_stat", S_IRUGO, &softnet_seq_fops)) goto out_dev; - if (!proc_net_fops_create("ptype", S_IRUGO, &ptype_seq_fops)) - goto out_dev2; + if (!proc_net_fops_create(&init_net, "ptype", S_IRUGO, &ptype_seq_fops)) + goto out_softnet; if (wext_proc_init()) - goto out_softnet; + goto out_ptype; rc = 0; out: return rc; +out_ptype: + proc_net_remove(&init_net, "ptype"); out_softnet: - proc_net_remove("ptype"); -out_dev2: - proc_net_remove("softnet_stat"); + proc_net_remove(&init_net, "softnet_stat"); out_dev: - proc_net_remove("dev"); + proc_net_remove(&init_net, "dev"); goto out; } #else diff --git a/net/core/dev_mcast.c b/net/core/dev_mcast.c index 20330c57261..8e069fc207c 100644 --- a/net/core/dev_mcast.c +++ b/net/core/dev_mcast.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -254,7 +255,7 @@ static const struct file_operations dev_mc_seq_fops = { void __init dev_mcast_init(void) { - proc_net_fops_create("dev_mcast", 0, &dev_mc_seq_fops); + proc_net_fops_create(&init_net, "dev_mcast", 0, &dev_mc_seq_fops); } EXPORT_SYMBOL(dev_mc_add); diff --git a/net/core/neighbour.c b/net/core/neighbour.c index ecd43c4a222..5f25f4f79b8 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -25,6 +25,7 @@ #include #endif #include +#include #include #include #include @@ -1350,7 +1351,7 @@ void neigh_table_init_no_netlink(struct neigh_table *tbl) panic("cannot create neighbour cache statistics"); #ifdef CONFIG_PROC_FS - tbl->pde = create_proc_entry(tbl->id, 0, proc_net_stat); + tbl->pde = create_proc_entry(tbl->id, 0, init_net.proc_net_stat); if (!tbl->pde) panic("cannot create neighbour proc dir entry"); tbl->pde->proc_fops = &neigh_stat_seq_fops; diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 84c0edeedf6..33d7247fb19 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -152,6 +152,7 @@ #include #include #include +#include #include #include #include @@ -3808,7 +3809,7 @@ static int __init pg_init(void) printk(KERN_INFO "%s", version); - pg_proc_dir = proc_mkdir(PG_PROC_DIR, proc_net); + pg_proc_dir = proc_mkdir(PG_PROC_DIR, init_net.proc_net); if (!pg_proc_dir) return -ENODEV; pg_proc_dir->owner = THIS_MODULE; @@ -3817,7 +3818,7 @@ static int __init pg_init(void) if (pe == NULL) { printk(KERN_ERR "pktgen: ERROR: cannot create %s " "procfs entry.\n", PGCTRL); - proc_net_remove(PG_PROC_DIR); + proc_net_remove(&init_net, PG_PROC_DIR); return -EINVAL; } @@ -3841,7 +3842,7 @@ static int __init pg_init(void) "all threads\n"); unregister_netdevice_notifier(&pktgen_notifier_block); remove_proc_entry(PGCTRL, pg_proc_dir); - proc_net_remove(PG_PROC_DIR); + proc_net_remove(&init_net, PG_PROC_DIR); return -ENODEV; } @@ -3868,7 +3869,7 @@ static void __exit pg_cleanup(void) /* Clean up proc file system */ remove_proc_entry(PGCTRL, pg_proc_dir); - proc_net_remove(PG_PROC_DIR); + proc_net_remove(&init_net, PG_PROC_DIR); } module_init(pg_init); diff --git a/net/core/sock.c b/net/core/sock.c index beb924c248e..bbc726a49d8 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -119,6 +119,7 @@ #include #include #include +#include #include #include #include @@ -1973,7 +1974,7 @@ static const struct file_operations proto_seq_fops = { static int __init proto_init(void) { /* register /proc/net/protocols */ - return proc_net_fops_create("protocols", S_IRUGO, &proto_seq_fops) == NULL ? -ENOBUFS : 0; + return proc_net_fops_create(&init_net, "protocols", S_IRUGO, &proto_seq_fops) == NULL ? -ENOBUFS : 0; } subsys_initcall(proto_init); diff --git a/net/dccp/probe.c b/net/dccp/probe.c index bae10b0f2fc..7053bb827bc 100644 --- a/net/dccp/probe.c +++ b/net/dccp/probe.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "dccp.h" #include "ccid.h" @@ -168,7 +169,7 @@ static __init int dccpprobe_init(void) if (IS_ERR(dccpw.fifo)) return PTR_ERR(dccpw.fifo); - if (!proc_net_fops_create(procname, S_IRUSR, &dccpprobe_fops)) + if (!proc_net_fops_create(&init_net, procname, S_IRUSR, &dccpprobe_fops)) goto err0; ret = register_jprobe(&dccp_send_probe); @@ -178,7 +179,7 @@ static __init int dccpprobe_init(void) pr_info("DCCP watch registered (port=%d)\n", port); return 0; err1: - proc_net_remove(procname); + proc_net_remove(&init_net, procname); err0: kfifo_free(dccpw.fifo); return ret; @@ -188,7 +189,7 @@ module_init(dccpprobe_init); static __exit void dccpprobe_exit(void) { kfifo_free(dccpw.fifo); - proc_net_remove(procname); + proc_net_remove(&init_net, procname); unregister_jprobe(&dccp_send_probe); } diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c index ed76d4aab4a..625d5955b8e 100644 --- a/net/decnet/af_decnet.c +++ b/net/decnet/af_decnet.c @@ -128,6 +128,7 @@ Version 0.0.6 2.1.110 07-aug-98 Eduardo Marcelo Serrat #include #include #include +#include #include #include #include @@ -2399,7 +2400,7 @@ static int __init decnet_init(void) dev_add_pack(&dn_dix_packet_type); register_netdevice_notifier(&dn_dev_notifier); - proc_net_fops_create("decnet", S_IRUGO, &dn_socket_seq_fops); + proc_net_fops_create(&init_net, "decnet", S_IRUGO, &dn_socket_seq_fops); dn_register_sysctl(); out: return rc; @@ -2428,7 +2429,7 @@ static void __exit decnet_exit(void) dn_neigh_cleanup(); dn_fib_cleanup(); - proc_net_remove("decnet"); + proc_net_remove(&init_net, "decnet"); proto_unregister(&dn_proto); } diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c index 8def68209ed..83cb0761336 100644 --- a/net/decnet/dn_dev.c +++ b/net/decnet/dn_dev.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -1462,7 +1463,7 @@ void __init dn_dev_init(void) rtnl_register(PF_DECnet, RTM_DELADDR, dn_nl_deladdr, NULL); rtnl_register(PF_DECnet, RTM_GETADDR, NULL, dn_nl_dump_ifaddr); - proc_net_fops_create("decnet_dev", S_IRUGO, &dn_dev_seq_fops); + proc_net_fops_create(&init_net, "decnet_dev", S_IRUGO, &dn_dev_seq_fops); #ifdef CONFIG_SYSCTL { @@ -1483,7 +1484,7 @@ void __exit dn_dev_cleanup(void) } #endif /* CONFIG_SYSCTL */ - proc_net_remove("decnet_dev"); + proc_net_remove(&init_net, "decnet_dev"); dn_dev_devices_off(); } diff --git a/net/decnet/dn_neigh.c b/net/decnet/dn_neigh.c index 174d8a7a6da..a424a8ddbaf 100644 --- a/net/decnet/dn_neigh.c +++ b/net/decnet/dn_neigh.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -611,11 +612,11 @@ static const struct file_operations dn_neigh_seq_fops = { void __init dn_neigh_init(void) { neigh_table_init(&dn_neigh_table); - proc_net_fops_create("decnet_neigh", S_IRUGO, &dn_neigh_seq_fops); + proc_net_fops_create(&init_net, "decnet_neigh", S_IRUGO, &dn_neigh_seq_fops); } void __exit dn_neigh_cleanup(void) { - proc_net_remove("decnet_neigh"); + proc_net_remove(&init_net, "decnet_neigh"); neigh_table_clear(&dn_neigh_table); } diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index a4a620971ef..4cfea9563d2 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -77,6 +77,7 @@ #include #include #include +#include #include #include #include @@ -1814,7 +1815,7 @@ void __init dn_route_init(void) dn_dst_ops.gc_thresh = (dn_rt_hash_mask + 1); - proc_net_fops_create("decnet_cache", S_IRUGO, &dn_rt_cache_seq_fops); + proc_net_fops_create(&init_net, "decnet_cache", S_IRUGO, &dn_rt_cache_seq_fops); #ifdef CONFIG_DECNET_ROUTER rtnl_register(PF_DECnet, RTM_GETROUTE, dn_cache_getroute, dn_fib_dump); @@ -1829,6 +1830,6 @@ void __exit dn_route_cleanup(void) del_timer(&dn_route_timer); dn_run_flush(0); - proc_net_remove("decnet_cache"); + proc_net_remove(&init_net, "decnet_cache"); } diff --git a/net/ieee80211/ieee80211_module.c b/net/ieee80211/ieee80211_module.c index 17ad278696e..69cb6aad25b 100644 --- a/net/ieee80211/ieee80211_module.c +++ b/net/ieee80211/ieee80211_module.c @@ -47,6 +47,7 @@ #include #include #include +#include #include #include @@ -264,7 +265,7 @@ static int __init ieee80211_init(void) struct proc_dir_entry *e; ieee80211_debug_level = debug; - ieee80211_proc = proc_mkdir(DRV_NAME, proc_net); + ieee80211_proc = proc_mkdir(DRV_NAME, init_net.proc_net); if (ieee80211_proc == NULL) { IEEE80211_ERROR("Unable to create " DRV_NAME " proc directory\n"); @@ -273,7 +274,7 @@ static int __init ieee80211_init(void) e = create_proc_entry("debug_level", S_IFREG | S_IRUGO | S_IWUSR, ieee80211_proc); if (!e) { - remove_proc_entry(DRV_NAME, proc_net); + remove_proc_entry(DRV_NAME, init_net.proc_net); ieee80211_proc = NULL; return -EIO; } @@ -293,7 +294,7 @@ static void __exit ieee80211_exit(void) #ifdef CONFIG_IEEE80211_DEBUG if (ieee80211_proc) { remove_proc_entry("debug_level", ieee80211_proc); - remove_proc_entry(DRV_NAME, proc_net); + remove_proc_entry(DRV_NAME, init_net.proc_net); ieee80211_proc = NULL; } #endif /* CONFIG_IEEE80211_DEBUG */ diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 9ab9d534fba..78dd3443016 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -103,6 +103,7 @@ #include #endif +#include #include #include #include @@ -1400,7 +1401,7 @@ static const struct file_operations arp_seq_fops = { static int __init arp_proc_init(void) { - if (!proc_net_fops_create("arp", S_IRUGO, &arp_seq_fops)) + if (!proc_net_fops_create(&init_net, "arp", S_IRUGO, &arp_seq_fops)) return -ENOMEM; return 0; } diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c index 9ad1d9ff9ce..9fafbeea8fe 100644 --- a/net/ipv4/fib_hash.c +++ b/net/ipv4/fib_hash.c @@ -35,6 +35,7 @@ #include #include +#include #include #include #include @@ -1068,13 +1069,13 @@ static const struct file_operations fib_seq_fops = { int __init fib_proc_init(void) { - if (!proc_net_fops_create("route", S_IRUGO, &fib_seq_fops)) + if (!proc_net_fops_create(&init_net, "route", S_IRUGO, &fib_seq_fops)) return -ENOMEM; return 0; } void __init fib_proc_exit(void) { - proc_net_remove("route"); + proc_net_remove(&init_net, "route"); } #endif /* CONFIG_PROC_FS */ diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 52b2891c63b..be34bd556d5 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -73,6 +73,7 @@ #include #include #include +#include #include #include #include @@ -2530,30 +2531,30 @@ static const struct file_operations fib_route_fops = { int __init fib_proc_init(void) { - if (!proc_net_fops_create("fib_trie", S_IRUGO, &fib_trie_fops)) + if (!proc_net_fops_create(&init_net, "fib_trie", S_IRUGO, &fib_trie_fops)) goto out1; - if (!proc_net_fops_create("fib_triestat", S_IRUGO, &fib_triestat_fops)) + if (!proc_net_fops_create(&init_net, "fib_triestat", S_IRUGO, &fib_triestat_fops)) goto out2; - if (!proc_net_fops_create("route", S_IRUGO, &fib_route_fops)) + if (!proc_net_fops_create(&init_net, "route", S_IRUGO, &fib_route_fops)) goto out3; return 0; out3: - proc_net_remove("fib_triestat"); + proc_net_remove(&init_net, "fib_triestat"); out2: - proc_net_remove("fib_trie"); + proc_net_remove(&init_net, "fib_trie"); out1: return -ENOMEM; } void __init fib_proc_exit(void) { - proc_net_remove("fib_trie"); - proc_net_remove("fib_triestat"); - proc_net_remove("route"); + proc_net_remove(&init_net, "fib_trie"); + proc_net_remove(&init_net, "fib_triestat"); + proc_net_remove(&init_net, "route"); } #endif /* CONFIG_PROC_FS */ diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index a646409c2d0..d78599a9dbd 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -91,6 +91,7 @@ #include #include +#include #include #include #include @@ -2613,8 +2614,8 @@ static const struct file_operations igmp_mcf_seq_fops = { int __init igmp_mc_proc_init(void) { - proc_net_fops_create("igmp", S_IRUGO, &igmp_mc_seq_fops); - proc_net_fops_create("mcfilter", S_IRUGO, &igmp_mcf_seq_fops); + proc_net_fops_create(&init_net, "igmp", S_IRUGO, &igmp_mc_seq_fops); + proc_net_fops_create(&init_net, "mcfilter", S_IRUGO, &igmp_mcf_seq_fops); return 0; } #endif diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index c5b24707753..5ae4849878a 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -55,6 +55,7 @@ #include #include #include +#include #include #include #include @@ -1253,7 +1254,7 @@ static int __init ip_auto_config(void) __be32 addr; #ifdef CONFIG_PROC_FS - proc_net_fops_create("pnp", S_IRUGO, &pnp_seq_fops); + proc_net_fops_create(&init_net, "pnp", S_IRUGO, &pnp_seq_fops); #endif /* CONFIG_PROC_FS */ if (!ic_enable) diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 7003cc1b7fe..35683e1a42e 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -1922,7 +1923,7 @@ void __init ip_mr_init(void) ipmr_expire_timer.function=ipmr_expire_process; register_netdevice_notifier(&ip_mr_notifier); #ifdef CONFIG_PROC_FS - proc_net_fops_create("ip_mr_vif", 0, &ipmr_vif_fops); - proc_net_fops_create("ip_mr_cache", 0, &ipmr_mfc_fops); + proc_net_fops_create(&init_net, "ip_mr_vif", 0, &ipmr_vif_fops); + proc_net_fops_create(&init_net, "ip_mr_cache", 0, &ipmr_mfc_fops); #endif } diff --git a/net/ipv4/ipvs/ip_vs_app.c b/net/ipv4/ipvs/ip_vs_app.c index 8d6901d4e94..341474eefa5 100644 --- a/net/ipv4/ipvs/ip_vs_app.c +++ b/net/ipv4/ipvs/ip_vs_app.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -616,12 +617,12 @@ int ip_vs_skb_replace(struct sk_buff *skb, gfp_t pri, int ip_vs_app_init(void) { /* we will replace it with proc_net_ipvs_create() soon */ - proc_net_fops_create("ip_vs_app", 0, &ip_vs_app_fops); + proc_net_fops_create(&init_net, "ip_vs_app", 0, &ip_vs_app_fops); return 0; } void ip_vs_app_cleanup(void) { - proc_net_remove("ip_vs_app"); + proc_net_remove(&init_net, "ip_vs_app"); } diff --git a/net/ipv4/ipvs/ip_vs_conn.c b/net/ipv4/ipvs/ip_vs_conn.c index d612a6a5d95..4b702f708d3 100644 --- a/net/ipv4/ipvs/ip_vs_conn.c +++ b/net/ipv4/ipvs/ip_vs_conn.c @@ -35,6 +35,7 @@ #include #include +#include #include @@ -922,7 +923,7 @@ int ip_vs_conn_init(void) rwlock_init(&__ip_vs_conntbl_lock_array[idx].l); } - proc_net_fops_create("ip_vs_conn", 0, &ip_vs_conn_fops); + proc_net_fops_create(&init_net, "ip_vs_conn", 0, &ip_vs_conn_fops); /* calculate the random value for connection hash */ get_random_bytes(&ip_vs_conn_rnd, sizeof(ip_vs_conn_rnd)); @@ -938,6 +939,6 @@ void ip_vs_conn_cleanup(void) /* Release the empty cache */ kmem_cache_destroy(ip_vs_conn_cachep); - proc_net_remove("ip_vs_conn"); + proc_net_remove(&init_net, "ip_vs_conn"); vfree(ip_vs_conn_tab); } diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c index f656d41d8d4..61d023d58b5 100644 --- a/net/ipv4/ipvs/ip_vs_ctl.c +++ b/net/ipv4/ipvs/ip_vs_ctl.c @@ -35,6 +35,7 @@ #include #include +#include #include #include #include @@ -2356,8 +2357,8 @@ int ip_vs_control_init(void) return ret; } - proc_net_fops_create("ip_vs", 0, &ip_vs_info_fops); - proc_net_fops_create("ip_vs_stats",0, &ip_vs_stats_fops); + proc_net_fops_create(&init_net, "ip_vs", 0, &ip_vs_info_fops); + proc_net_fops_create(&init_net, "ip_vs_stats",0, &ip_vs_stats_fops); sysctl_header = register_sysctl_table(vs_root_table); @@ -2390,8 +2391,8 @@ void ip_vs_control_cleanup(void) cancel_work_sync(&defense_work.work); ip_vs_kill_estimator(&ip_vs_stats); unregister_sysctl_table(sysctl_header); - proc_net_remove("ip_vs_stats"); - proc_net_remove("ip_vs"); + proc_net_remove(&init_net, "ip_vs_stats"); + proc_net_remove(&init_net, "ip_vs"); nf_unregister_sockopt(&ip_vs_sockopts); LeaveFunction(2); } diff --git a/net/ipv4/ipvs/ip_vs_lblcr.c b/net/ipv4/ipvs/ip_vs_lblcr.c index 6225acac7a3..6a1fec416ea 100644 --- a/net/ipv4/ipvs/ip_vs_lblcr.c +++ b/net/ipv4/ipvs/ip_vs_lblcr.c @@ -50,6 +50,7 @@ #include /* for proc_net_create/proc_net_remove */ #include +#include #include @@ -843,7 +844,7 @@ static int __init ip_vs_lblcr_init(void) INIT_LIST_HEAD(&ip_vs_lblcr_scheduler.n_list); sysctl_header = register_sysctl_table(lblcr_root_table); #ifdef CONFIG_IP_VS_LBLCR_DEBUG - proc_net_create("ip_vs_lblcr", 0, ip_vs_lblcr_getinfo); + proc_net_create(&init_net, "ip_vs_lblcr", 0, ip_vs_lblcr_getinfo); #endif return register_ip_vs_scheduler(&ip_vs_lblcr_scheduler); } @@ -852,7 +853,7 @@ static int __init ip_vs_lblcr_init(void) static void __exit ip_vs_lblcr_cleanup(void) { #ifdef CONFIG_IP_VS_LBLCR_DEBUG - proc_net_remove("ip_vs_lblcr"); + proc_net_remove(&init_net, "ip_vs_lblcr"); #endif unregister_sysctl_table(sysctl_header); unregister_ip_vs_scheduler(&ip_vs_lblcr_scheduler); diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index 702d94db19b..cb5e61a1d7a 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -674,7 +675,7 @@ static int __init ip_queue_init(void) goto cleanup_netlink_notifier; } - proc = proc_net_create(IPQ_PROC_FS_NAME, 0, ipq_get_info); + proc = proc_net_create(&init_net, IPQ_PROC_FS_NAME, 0, ipq_get_info); if (proc) proc->owner = THIS_MODULE; else { @@ -695,8 +696,7 @@ static int __init ip_queue_init(void) cleanup_sysctl: unregister_sysctl_table(ipq_sysctl_header); unregister_netdevice_notifier(&ipq_dev_notifier); - proc_net_remove(IPQ_PROC_FS_NAME); - + proc_net_remove(&init_net, IPQ_PROC_FS_NAME); cleanup_ipqnl: sock_release(ipqnl->sk_socket); mutex_lock(&ipqnl_mutex); @@ -715,7 +715,7 @@ static void __exit ip_queue_fini(void) unregister_sysctl_table(ipq_sysctl_header); unregister_netdevice_notifier(&ipq_dev_notifier); - proc_net_remove(IPQ_PROC_FS_NAME); + proc_net_remove(&init_net, IPQ_PROC_FS_NAME); sock_release(ipqnl->sk_socket); mutex_lock(&ipqnl_mutex); diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c index 69bd362b5fa..50fc9e009fe 100644 --- a/net/ipv4/netfilter/ipt_CLUSTERIP.c +++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #define CLUSTERIP_VERSION "0.8" @@ -726,7 +727,7 @@ static int __init ipt_clusterip_init(void) goto cleanup_target; #ifdef CONFIG_PROC_FS - clusterip_procdir = proc_mkdir("ipt_CLUSTERIP", proc_net); + clusterip_procdir = proc_mkdir("ipt_CLUSTERIP", init_net.proc_net); if (!clusterip_procdir) { printk(KERN_ERR "CLUSTERIP: Unable to proc dir entry\n"); ret = -ENOMEM; diff --git a/net/ipv4/netfilter/ipt_recent.c b/net/ipv4/netfilter/ipt_recent.c index 6d0c0f7364a..db2a79889f9 100644 --- a/net/ipv4/netfilter/ipt_recent.c +++ b/net/ipv4/netfilter/ipt_recent.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -487,7 +488,7 @@ static int __init ipt_recent_init(void) #ifdef CONFIG_PROC_FS if (err) return err; - proc_dir = proc_mkdir("ipt_recent", proc_net); + proc_dir = proc_mkdir("ipt_recent", init_net.proc_net); if (proc_dir == NULL) { xt_unregister_match(&recent_match); err = -ENOMEM; @@ -501,7 +502,7 @@ static void __exit ipt_recent_exit(void) BUG_ON(!list_empty(&tables)); xt_unregister_match(&recent_match); #ifdef CONFIG_PROC_FS - remove_proc_entry("ipt_recent", proc_net); + remove_proc_entry("ipt_recent", init_net.proc_net); #endif } diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c index b3dd5de9a25..a5ae2eabf0f 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -408,16 +409,16 @@ int __init nf_conntrack_ipv4_compat_init(void) { struct proc_dir_entry *proc, *proc_exp, *proc_stat; - proc = proc_net_fops_create("ip_conntrack", 0440, &ct_file_ops); + proc = proc_net_fops_create(&init_net, "ip_conntrack", 0440, &ct_file_ops); if (!proc) goto err1; - proc_exp = proc_net_fops_create("ip_conntrack_expect", 0440, + proc_exp = proc_net_fops_create(&init_net, "ip_conntrack_expect", 0440, &ip_exp_file_ops); if (!proc_exp) goto err2; - proc_stat = create_proc_entry("ip_conntrack", S_IRUGO, proc_net_stat); + proc_stat = create_proc_entry("ip_conntrack", S_IRUGO, init_net.proc_net_stat); if (!proc_stat) goto err3; @@ -427,16 +428,16 @@ int __init nf_conntrack_ipv4_compat_init(void) return 0; err3: - proc_net_remove("ip_conntrack_expect"); + proc_net_remove(&init_net, "ip_conntrack_expect"); err2: - proc_net_remove("ip_conntrack"); + proc_net_remove(&init_net, "ip_conntrack"); err1: return -ENOMEM; } void __exit nf_conntrack_ipv4_compat_fini(void) { - remove_proc_entry("ip_conntrack", proc_net_stat); - proc_net_remove("ip_conntrack_expect"); - proc_net_remove("ip_conntrack"); + remove_proc_entry("ip_conntrack", init_net.proc_net_stat); + proc_net_remove(&init_net, "ip_conntrack_expect"); + proc_net_remove(&init_net, "ip_conntrack"); } diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index 986d1c83a00..95a8f8f2de7 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c @@ -34,6 +34,7 @@ * 2 of the License, or (at your option) any later version. */ #include +#include #include #include #include @@ -383,20 +384,20 @@ int __init ip_misc_proc_init(void) { int rc = 0; - if (!proc_net_fops_create("netstat", S_IRUGO, &netstat_seq_fops)) + if (!proc_net_fops_create(&init_net, "netstat", S_IRUGO, &netstat_seq_fops)) goto out_netstat; - if (!proc_net_fops_create("snmp", S_IRUGO, &snmp_seq_fops)) + if (!proc_net_fops_create(&init_net, "snmp", S_IRUGO, &snmp_seq_fops)) goto out_snmp; - if (!proc_net_fops_create("sockstat", S_IRUGO, &sockstat_seq_fops)) + if (!proc_net_fops_create(&init_net, "sockstat", S_IRUGO, &sockstat_seq_fops)) goto out_sockstat; out: return rc; out_sockstat: - proc_net_remove("snmp"); + proc_net_remove(&init_net, "snmp"); out_snmp: - proc_net_remove("netstat"); + proc_net_remove(&init_net, "netstat"); out_netstat: rc = -ENOMEM; goto out; diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index c6d71526f62..216e01b0f44 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -59,6 +59,7 @@ #include #include #include +#include #include #include #include @@ -928,13 +929,13 @@ static const struct file_operations raw_seq_fops = { int __init raw_proc_init(void) { - if (!proc_net_fops_create("raw", S_IRUGO, &raw_seq_fops)) + if (!proc_net_fops_create(&init_net, "raw", S_IRUGO, &raw_seq_fops)) return -ENOMEM; return 0; } void __init raw_proc_exit(void) { - proc_net_remove("raw"); + proc_net_remove(&init_net, "raw"); } #endif /* CONFIG_PROC_FS */ diff --git a/net/ipv4/route.c b/net/ipv4/route.c index c7ca94bd152..efd2a9202d6 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -91,6 +91,7 @@ #include #include #include +#include #include #include #include @@ -3011,15 +3012,15 @@ int __init ip_rt_init(void) #ifdef CONFIG_PROC_FS { struct proc_dir_entry *rtstat_pde = NULL; /* keep gcc happy */ - if (!proc_net_fops_create("rt_cache", S_IRUGO, &rt_cache_seq_fops) || + if (!proc_net_fops_create(&init_net, "rt_cache", S_IRUGO, &rt_cache_seq_fops) || !(rtstat_pde = create_proc_entry("rt_cache", S_IRUGO, - proc_net_stat))) { + init_net.proc_net_stat))) { return -ENOMEM; } rtstat_pde->proc_fops = &rt_cpu_seq_fops; } #ifdef CONFIG_NET_CLS_ROUTE - create_proc_read_entry("rt_acct", 0, proc_net, ip_rt_acct_read, NULL); + create_proc_read_entry("rt_acct", 0, init_net.proc_net, ip_rt_acct_read, NULL); #endif #endif #ifdef CONFIG_XFRM diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index e089a978e12..8855e640e95 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -62,6 +62,7 @@ #include #include +#include #include #include #include @@ -2249,7 +2250,7 @@ int tcp_proc_register(struct tcp_seq_afinfo *afinfo) afinfo->seq_fops->llseek = seq_lseek; afinfo->seq_fops->release = seq_release_private; - p = proc_net_fops_create(afinfo->name, S_IRUGO, afinfo->seq_fops); + p = proc_net_fops_create(&init_net, afinfo->name, S_IRUGO, afinfo->seq_fops); if (p) p->data = afinfo; else @@ -2261,7 +2262,7 @@ void tcp_proc_unregister(struct tcp_seq_afinfo *afinfo) { if (!afinfo) return; - proc_net_remove(afinfo->name); + proc_net_remove(&init_net, afinfo->name); memset(afinfo->seq_fops, 0, sizeof(*afinfo->seq_fops)); } diff --git a/net/ipv4/tcp_probe.c b/net/ipv4/tcp_probe.c index b76398d1b45..87dd5bff315 100644 --- a/net/ipv4/tcp_probe.c +++ b/net/ipv4/tcp_probe.c @@ -26,6 +26,7 @@ #include #include #include +#include #include @@ -228,7 +229,7 @@ static __init int tcpprobe_init(void) if (!tcp_probe.log) goto err0; - if (!proc_net_fops_create(procname, S_IRUSR, &tcpprobe_fops)) + if (!proc_net_fops_create(&init_net, procname, S_IRUSR, &tcpprobe_fops)) goto err0; ret = register_jprobe(&tcp_jprobe); @@ -238,7 +239,7 @@ static __init int tcpprobe_init(void) pr_info("TCP probe registered (port=%d)\n", port); return 0; err1: - proc_net_remove(procname); + proc_net_remove(&init_net, procname); err0: kfree(tcp_probe.log); return ret; @@ -247,7 +248,7 @@ module_init(tcpprobe_init); static __exit void tcpprobe_exit(void) { - proc_net_remove(procname); + proc_net_remove(&init_net, procname); unregister_jprobe(&tcp_jprobe); kfree(tcp_probe.log); } diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index a581b543bff..ef4d901ee9a 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -98,6 +98,7 @@ #include #include #include +#include #include #include #include @@ -1566,7 +1567,7 @@ int udp_proc_register(struct udp_seq_afinfo *afinfo) afinfo->seq_fops->llseek = seq_lseek; afinfo->seq_fops->release = seq_release_private; - p = proc_net_fops_create(afinfo->name, S_IRUGO, afinfo->seq_fops); + p = proc_net_fops_create(&init_net, afinfo->name, S_IRUGO, afinfo->seq_fops); if (p) p->data = afinfo; else @@ -1578,7 +1579,7 @@ void udp_proc_unregister(struct udp_seq_afinfo *afinfo) { if (!afinfo) return; - proc_net_remove(afinfo->name); + proc_net_remove(&init_net, afinfo->name); memset(afinfo->seq_fops, 0, sizeof(*afinfo->seq_fops)); } diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 45b4c82148a..cd2db728d18 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -62,6 +62,7 @@ #include #include +#include #include #include @@ -2827,14 +2828,14 @@ static const struct file_operations if6_fops = { int __init if6_proc_init(void) { - if (!proc_net_fops_create("if_inet6", S_IRUGO, &if6_fops)) + if (!proc_net_fops_create(&init_net, "if_inet6", S_IRUGO, &if6_fops)) return -ENOMEM; return 0; } void if6_proc_exit(void) { - proc_net_remove("if_inet6"); + proc_net_remove(&init_net, "if_inet6"); } #endif /* CONFIG_PROC_FS */ @@ -4293,6 +4294,6 @@ void __exit addrconf_cleanup(void) rtnl_unlock(); #ifdef CONFIG_PROC_FS - proc_net_remove("if_inet6"); + proc_net_remove(&init_net, "if_inet6"); #endif } diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c index b8c533fbdb6..0bd665498d0 100644 --- a/net/ipv6/anycast.c +++ b/net/ipv6/anycast.c @@ -30,6 +30,7 @@ #include #include +#include #include #include @@ -578,7 +579,7 @@ static const struct file_operations ac6_seq_fops = { int __init ac6_proc_init(void) { - if (!proc_net_fops_create("anycast6", S_IRUGO, &ac6_seq_fops)) + if (!proc_net_fops_create(&init_net, "anycast6", S_IRUGO, &ac6_seq_fops)) return -ENOMEM; return 0; @@ -586,7 +587,7 @@ int __init ac6_proc_init(void) void ac6_proc_exit(void) { - proc_net_remove("anycast6"); + proc_net_remove(&init_net, "anycast6"); } #endif diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index 413a4ebb195..1791399c7f1 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -690,7 +691,7 @@ static const struct file_operations ip6fl_seq_fops = { void ip6_flowlabel_init(void) { #ifdef CONFIG_PROC_FS - proc_net_fops_create("ip6_flowlabel", S_IRUGO, &ip6fl_seq_fops); + proc_net_fops_create(&init_net, "ip6_flowlabel", S_IRUGO, &ip6fl_seq_fops); #endif } @@ -698,6 +699,6 @@ void ip6_flowlabel_cleanup(void) { del_timer(&ip6_fl_gc_timer); #ifdef CONFIG_PROC_FS - proc_net_remove("ip6_flowlabel"); + proc_net_remove(&init_net, "ip6_flowlabel"); #endif } diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index ae9881832a7..a41d5a0b50c 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -49,6 +49,7 @@ #include #include +#include #include #include @@ -2658,8 +2659,8 @@ int __init igmp6_init(struct net_proto_family *ops) np->hop_limit = 1; #ifdef CONFIG_PROC_FS - proc_net_fops_create("igmp6", S_IRUGO, &igmp6_mc_seq_fops); - proc_net_fops_create("mcfilter6", S_IRUGO, &igmp6_mcf_seq_fops); + proc_net_fops_create(&init_net, "igmp6", S_IRUGO, &igmp6_mc_seq_fops); + proc_net_fops_create(&init_net, "mcfilter6", S_IRUGO, &igmp6_mcf_seq_fops); #endif return 0; @@ -2671,7 +2672,7 @@ void igmp6_cleanup(void) igmp6_socket = NULL; /* for safety */ #ifdef CONFIG_PROC_FS - proc_net_remove("mcfilter6"); - proc_net_remove("igmp6"); + proc_net_remove(&init_net, "mcfilter6"); + proc_net_remove(&init_net, "igmp6"); #endif } diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index 0004db38af6..dfc58fbdb68 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -664,7 +665,7 @@ static int __init ip6_queue_init(void) goto cleanup_netlink_notifier; } - proc = proc_net_create(IPQ_PROC_FS_NAME, 0, ipq_get_info); + proc = proc_net_create(&init_net, IPQ_PROC_FS_NAME, 0, ipq_get_info); if (proc) proc->owner = THIS_MODULE; else { @@ -685,7 +686,7 @@ static int __init ip6_queue_init(void) cleanup_sysctl: unregister_sysctl_table(ipq_sysctl_header); unregister_netdevice_notifier(&ipq_dev_notifier); - proc_net_remove(IPQ_PROC_FS_NAME); + proc_net_remove(&init_net, IPQ_PROC_FS_NAME); cleanup_ipqnl: sock_release(ipqnl->sk_socket); @@ -705,7 +706,7 @@ static void __exit ip6_queue_fini(void) unregister_sysctl_table(ipq_sysctl_header); unregister_netdevice_notifier(&ipq_dev_notifier); - proc_net_remove(IPQ_PROC_FS_NAME); + proc_net_remove(&init_net, IPQ_PROC_FS_NAME); sock_release(ipqnl->sk_socket); mutex_lock(&ipqnl_mutex); diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index 920dc9cf6a8..a712a228948 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -231,22 +232,22 @@ int __init ipv6_misc_proc_init(void) { int rc = 0; - if (!proc_net_fops_create("snmp6", S_IRUGO, &snmp6_seq_fops)) + if (!proc_net_fops_create(&init_net, "snmp6", S_IRUGO, &snmp6_seq_fops)) goto proc_snmp6_fail; - proc_net_devsnmp6 = proc_mkdir("dev_snmp6", proc_net); + proc_net_devsnmp6 = proc_mkdir("dev_snmp6", init_net.proc_net); if (!proc_net_devsnmp6) goto proc_dev_snmp6_fail; - if (!proc_net_fops_create("sockstat6", S_IRUGO, &sockstat6_seq_fops)) + if (!proc_net_fops_create(&init_net, "sockstat6", S_IRUGO, &sockstat6_seq_fops)) goto proc_sockstat6_fail; out: return rc; proc_sockstat6_fail: - proc_net_remove("dev_snmp6"); + proc_net_remove(&init_net, "dev_snmp6"); proc_dev_snmp6_fail: - proc_net_remove("snmp6"); + proc_net_remove(&init_net, "snmp6"); proc_snmp6_fail: rc = -ENOMEM; goto out; @@ -254,8 +255,8 @@ proc_snmp6_fail: void ipv6_misc_proc_exit(void) { - proc_net_remove("sockstat6"); - proc_net_remove("dev_snmp6"); - proc_net_remove("snmp6"); + proc_net_remove(&init_net, "sockstat6"); + proc_net_remove(&init_net, "dev_snmp6"); + proc_net_remove(&init_net, "snmp6"); } diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 77167afa345..38a3d21c258 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -35,6 +35,7 @@ #include #include +#include #include #include #include @@ -1315,13 +1316,13 @@ static const struct file_operations raw6_seq_fops = { int __init raw6_proc_init(void) { - if (!proc_net_fops_create("raw6", S_IRUGO, &raw6_seq_fops)) + if (!proc_net_fops_create(&init_net, "raw6", S_IRUGO, &raw6_seq_fops)) return -ENOMEM; return 0; } void raw6_proc_exit(void) { - proc_net_remove("raw6"); + proc_net_remove(&init_net, "raw6"); } #endif /* CONFIG_PROC_FS */ diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 55ea80fac60..f4f0c341e5c 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -44,6 +44,7 @@ #include #endif +#include #include #include #include @@ -2561,11 +2562,11 @@ void __init ip6_route_init(void) fib6_init(); #ifdef CONFIG_PROC_FS - p = proc_net_create("ipv6_route", 0, rt6_proc_info); + p = proc_net_create(&init_net, "ipv6_route", 0, rt6_proc_info); if (p) p->owner = THIS_MODULE; - proc_net_fops_create("rt6_stats", S_IRUGO, &rt6_stats_seq_fops); + proc_net_fops_create(&init_net, "rt6_stats", S_IRUGO, &rt6_stats_seq_fops); #endif #ifdef CONFIG_XFRM xfrm6_init(); @@ -2585,8 +2586,8 @@ void ip6_route_cleanup(void) fib6_rules_cleanup(); #endif #ifdef CONFIG_PROC_FS - proc_net_remove("ipv6_route"); - proc_net_remove("rt6_stats"); + proc_net_remove(&init_net, "ipv6_route"); + proc_net_remove(&init_net, "rt6_stats"); #endif #ifdef CONFIG_XFRM xfrm6_fini(); diff --git a/net/ipx/ipx_proc.c b/net/ipx/ipx_proc.c index 4226e71ae1e..d483a00dc42 100644 --- a/net/ipx/ipx_proc.c +++ b/net/ipx/ipx_proc.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -353,7 +354,7 @@ int __init ipx_proc_init(void) struct proc_dir_entry *p; int rc = -ENOMEM; - ipx_proc_dir = proc_mkdir("ipx", proc_net); + ipx_proc_dir = proc_mkdir("ipx", init_net.proc_net); if (!ipx_proc_dir) goto out; @@ -381,7 +382,7 @@ out_socket: out_route: remove_proc_entry("interface", ipx_proc_dir); out_interface: - remove_proc_entry("ipx", proc_net); + remove_proc_entry("ipx", init_net.proc_net); goto out; } @@ -390,7 +391,7 @@ void __exit ipx_proc_exit(void) remove_proc_entry("interface", ipx_proc_dir); remove_proc_entry("route", ipx_proc_dir); remove_proc_entry("socket", ipx_proc_dir); - remove_proc_entry("ipx", proc_net); + remove_proc_entry("ipx", init_net.proc_net); } #else /* CONFIG_PROC_FS */ diff --git a/net/irda/irproc.c b/net/irda/irproc.c index 181cb51b48a..cae24fbda96 100644 --- a/net/irda/irproc.c +++ b/net/irda/irproc.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -66,7 +67,7 @@ void __init irda_proc_register(void) int i; struct proc_dir_entry *d; - proc_irda = proc_mkdir("irda", proc_net); + proc_irda = proc_mkdir("irda", init_net.proc_net); if (proc_irda == NULL) return; proc_irda->owner = THIS_MODULE; @@ -92,7 +93,7 @@ void irda_proc_unregister(void) for (i=0; i #include #include +#include #include #include @@ -3776,7 +3777,7 @@ static struct xfrm_mgr pfkeyv2_mgr = static void __exit ipsec_pfkey_exit(void) { xfrm_unregister_km(&pfkeyv2_mgr); - remove_proc_entry("net/pfkey", NULL); + remove_proc_entry("pfkey", init_net.proc_net); sock_unregister(PF_KEY); proto_unregister(&key_proto); } @@ -3793,7 +3794,7 @@ static int __init ipsec_pfkey_init(void) goto out_unregister_key_proto; #ifdef CONFIG_PROC_FS err = -ENOMEM; - if (create_proc_read_entry("net/pfkey", 0, NULL, pfkey_read_proc, NULL) == NULL) + if (create_proc_read_entry("pfkey", 0, init_net.proc_net, pfkey_read_proc, NULL) == NULL) goto out_sock_unregister; #endif err = xfrm_register_km(&pfkeyv2_mgr); diff --git a/net/llc/llc_proc.c b/net/llc/llc_proc.c index 49be6c902c8..4865d82896b 100644 --- a/net/llc/llc_proc.c +++ b/net/llc/llc_proc.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -231,7 +232,7 @@ int __init llc_proc_init(void) int rc = -ENOMEM; struct proc_dir_entry *p; - llc_proc_dir = proc_mkdir("llc", proc_net); + llc_proc_dir = proc_mkdir("llc", init_net.proc_net); if (!llc_proc_dir) goto out; llc_proc_dir->owner = THIS_MODULE; @@ -254,7 +255,7 @@ out: out_core: remove_proc_entry("socket", llc_proc_dir); out_socket: - remove_proc_entry("llc", proc_net); + remove_proc_entry("llc", init_net.proc_net); goto out; } @@ -262,5 +263,5 @@ void llc_proc_exit(void) { remove_proc_entry("socket", llc_proc_dir); remove_proc_entry("core", llc_proc_dir); - remove_proc_entry("llc", proc_net); + remove_proc_entry("llc", init_net.proc_net); } diff --git a/net/netfilter/core.c b/net/netfilter/core.c index 381a77cf0c9..a523fa4136e 100644 --- a/net/netfilter/core.c +++ b/net/netfilter/core.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include "nf_internals.h" @@ -293,7 +294,7 @@ void __init netfilter_init(void) } #ifdef CONFIG_PROC_FS - proc_net_netfilter = proc_mkdir("netfilter", proc_net); + proc_net_netfilter = proc_mkdir("netfilter", init_net.proc_net); if (!proc_net_netfilter) panic("cannot create netfilter proc entry"); #endif diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c index 3ac64e25f10..8a3e3af656b 100644 --- a/net/netfilter/nf_conntrack_expect.c +++ b/net/netfilter/nf_conntrack_expect.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -505,7 +506,7 @@ static int __init exp_proc_init(void) #ifdef CONFIG_PROC_FS struct proc_dir_entry *proc; - proc = proc_net_fops_create("nf_conntrack_expect", 0440, &exp_file_ops); + proc = proc_net_fops_create(&init_net, "nf_conntrack_expect", 0440, &exp_file_ops); if (!proc) return -ENOMEM; #endif /* CONFIG_PROC_FS */ @@ -515,7 +516,7 @@ static int __init exp_proc_init(void) static void exp_proc_remove(void) { #ifdef CONFIG_PROC_FS - proc_net_remove("nf_conntrack_expect"); + proc_net_remove(&init_net, "nf_conntrack_expect"); #endif /* CONFIG_PROC_FS */ } diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c index a4ce5e88799..2a19c5f1240 100644 --- a/net/netfilter/nf_conntrack_standalone.c +++ b/net/netfilter/nf_conntrack_standalone.c @@ -14,6 +14,7 @@ #include #include #include +#include #ifdef CONFIG_SYSCTL #include #endif @@ -420,10 +421,10 @@ static int __init nf_conntrack_standalone_init(void) return ret; #ifdef CONFIG_PROC_FS - proc = proc_net_fops_create("nf_conntrack", 0440, &ct_file_ops); + proc = proc_net_fops_create(&init_net, "nf_conntrack", 0440, &ct_file_ops); if (!proc) goto cleanup_init; - proc_stat = create_proc_entry("nf_conntrack", S_IRUGO, proc_net_stat); + proc_stat = create_proc_entry("nf_conntrack", S_IRUGO, init_net.proc_net_stat); if (!proc_stat) goto cleanup_proc; @@ -444,9 +445,9 @@ static int __init nf_conntrack_standalone_init(void) cleanup_proc_stat: #endif #ifdef CONFIG_PROC_FS - remove_proc_entry("nf_conntrack", proc_net_stat); + remove_proc_entry("nf_conntrack", init_net. proc_net_stat); cleanup_proc: - proc_net_remove("nf_conntrack"); + proc_net_remove(&init_net, "nf_conntrack"); cleanup_init: #endif /* CNFIG_PROC_FS */ nf_conntrack_cleanup(); @@ -459,8 +460,8 @@ static void __exit nf_conntrack_standalone_fini(void) unregister_sysctl_table(nf_ct_sysctl_header); #endif #ifdef CONFIG_PROC_FS - remove_proc_entry("nf_conntrack", proc_net_stat); - proc_net_remove("nf_conntrack"); + remove_proc_entry("nf_conntrack", init_net.proc_net_stat); + proc_net_remove(&init_net, "nf_conntrack"); #endif /* CNFIG_PROC_FS */ nf_conntrack_cleanup(); } diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index cc2baa6d5a7..d9a3bded0d0 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -795,7 +796,7 @@ int xt_proto_init(int af) #ifdef CONFIG_PROC_FS strlcpy(buf, xt_prefix[af], sizeof(buf)); strlcat(buf, FORMAT_TABLES, sizeof(buf)); - proc = proc_net_fops_create(buf, 0440, &xt_file_ops); + proc = proc_net_fops_create(&init_net, buf, 0440, &xt_file_ops); if (!proc) goto out; proc->data = (void *) ((unsigned long) af | (TABLE << 16)); @@ -803,14 +804,14 @@ int xt_proto_init(int af) strlcpy(buf, xt_prefix[af], sizeof(buf)); strlcat(buf, FORMAT_MATCHES, sizeof(buf)); - proc = proc_net_fops_create(buf, 0440, &xt_file_ops); + proc = proc_net_fops_create(&init_net, buf, 0440, &xt_file_ops); if (!proc) goto out_remove_tables; proc->data = (void *) ((unsigned long) af | (MATCH << 16)); strlcpy(buf, xt_prefix[af], sizeof(buf)); strlcat(buf, FORMAT_TARGETS, sizeof(buf)); - proc = proc_net_fops_create(buf, 0440, &xt_file_ops); + proc = proc_net_fops_create(&init_net, buf, 0440, &xt_file_ops); if (!proc) goto out_remove_matches; proc->data = (void *) ((unsigned long) af | (TARGET << 16)); @@ -822,12 +823,12 @@ int xt_proto_init(int af) out_remove_matches: strlcpy(buf, xt_prefix[af], sizeof(buf)); strlcat(buf, FORMAT_MATCHES, sizeof(buf)); - proc_net_remove(buf); + proc_net_remove(&init_net, buf); out_remove_tables: strlcpy(buf, xt_prefix[af], sizeof(buf)); strlcat(buf, FORMAT_TABLES, sizeof(buf)); - proc_net_remove(buf); + proc_net_remove(&init_net, buf); out: return -1; #endif @@ -841,15 +842,15 @@ void xt_proto_fini(int af) strlcpy(buf, xt_prefix[af], sizeof(buf)); strlcat(buf, FORMAT_TABLES, sizeof(buf)); - proc_net_remove(buf); + proc_net_remove(&init_net, buf); strlcpy(buf, xt_prefix[af], sizeof(buf)); strlcat(buf, FORMAT_TARGETS, sizeof(buf)); - proc_net_remove(buf); + proc_net_remove(&init_net, buf); strlcpy(buf, xt_prefix[af], sizeof(buf)); strlcat(buf, FORMAT_MATCHES, sizeof(buf)); - proc_net_remove(buf); + proc_net_remove(&init_net, buf); #endif /*CONFIG_PROC_FS*/ } EXPORT_SYMBOL_GPL(xt_proto_fini); diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c index bd45f9d3f7d..19103678bf2 100644 --- a/net/netfilter/xt_hashlimit.c +++ b/net/netfilter/xt_hashlimit.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -743,13 +744,13 @@ static int __init xt_hashlimit_init(void) printk(KERN_ERR "xt_hashlimit: unable to create slab cache\n"); goto err2; } - hashlimit_procdir4 = proc_mkdir("ipt_hashlimit", proc_net); + hashlimit_procdir4 = proc_mkdir("ipt_hashlimit", init_net.proc_net); if (!hashlimit_procdir4) { printk(KERN_ERR "xt_hashlimit: unable to create proc dir " "entry\n"); goto err3; } - hashlimit_procdir6 = proc_mkdir("ip6t_hashlimit", proc_net); + hashlimit_procdir6 = proc_mkdir("ip6t_hashlimit", init_net.proc_net); if (!hashlimit_procdir6) { printk(KERN_ERR "xt_hashlimit: unable to create proc dir " "entry\n"); @@ -757,7 +758,7 @@ static int __init xt_hashlimit_init(void) } return 0; err4: - remove_proc_entry("ipt_hashlimit", proc_net); + remove_proc_entry("ipt_hashlimit", init_net.proc_net); err3: kmem_cache_destroy(hashlimit_cachep); err2: @@ -769,8 +770,8 @@ err1: static void __exit xt_hashlimit_fini(void) { - remove_proc_entry("ipt_hashlimit", proc_net); - remove_proc_entry("ip6t_hashlimit", proc_net); + remove_proc_entry("ipt_hashlimit", init_net.proc_net); + remove_proc_entry("ip6t_hashlimit", init_net.proc_net); kmem_cache_destroy(hashlimit_cachep); xt_unregister_matches(xt_hashlimit, ARRAY_SIZE(xt_hashlimit)); } diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index a78d962e2c7..3982f13dab1 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -57,6 +57,7 @@ #include #include +#include #include #include #include @@ -1927,7 +1928,7 @@ static int __init netlink_proto_init(void) sock_register(&netlink_family_ops); #ifdef CONFIG_PROC_FS - proc_net_fops_create("netlink", 0, &netlink_seq_fops); + proc_net_fops_create(&init_net, "netlink", 0, &netlink_seq_fops); #endif /* The netlink device handler may be needed early. */ rtnetlink_init(); diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index dc9273295a3..15c8a92bd71 100644 --- a/net/netrom/af_netrom.c +++ b/net/netrom/af_netrom.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -1447,9 +1448,9 @@ static int __init nr_proto_init(void) nr_loopback_init(); - proc_net_fops_create("nr", S_IRUGO, &nr_info_fops); - proc_net_fops_create("nr_neigh", S_IRUGO, &nr_neigh_fops); - proc_net_fops_create("nr_nodes", S_IRUGO, &nr_nodes_fops); + proc_net_fops_create(&init_net, "nr", S_IRUGO, &nr_info_fops); + proc_net_fops_create(&init_net, "nr_neigh", S_IRUGO, &nr_neigh_fops); + proc_net_fops_create(&init_net, "nr_nodes", S_IRUGO, &nr_nodes_fops); out: return rc; fail: @@ -1477,9 +1478,9 @@ static void __exit nr_exit(void) { int i; - proc_net_remove("nr"); - proc_net_remove("nr_neigh"); - proc_net_remove("nr_nodes"); + proc_net_remove(&init_net, "nr"); + proc_net_remove(&init_net, "nr_neigh"); + proc_net_remove(&init_net, "nr_nodes"); nr_loopback_clear(); nr_rt_free(); diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 9c26dd9ee64..56502292f24 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -61,6 +61,7 @@ #include #include #include +#include #include #include #include @@ -1951,7 +1952,7 @@ static const struct file_operations packet_seq_fops = { static void __exit packet_exit(void) { - proc_net_remove("packet"); + proc_net_remove(&init_net, "packet"); unregister_netdevice_notifier(&packet_netdev_notifier); sock_unregister(PF_PACKET); proto_unregister(&packet_proto); @@ -1966,7 +1967,7 @@ static int __init packet_init(void) sock_register(&packet_family_ops); register_netdevice_notifier(&packet_netdev_notifier); - proc_net_fops_create("packet", 0, &packet_seq_fops); + proc_net_fops_create(&init_net, "packet", 0, &packet_seq_fops); out: return rc; } diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index 976c3cc86a2..48319f7991a 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -1576,10 +1577,10 @@ static int __init rose_proto_init(void) rose_add_loopback_neigh(); - proc_net_fops_create("rose", S_IRUGO, &rose_info_fops); - proc_net_fops_create("rose_neigh", S_IRUGO, &rose_neigh_fops); - proc_net_fops_create("rose_nodes", S_IRUGO, &rose_nodes_fops); - proc_net_fops_create("rose_routes", S_IRUGO, &rose_routes_fops); + proc_net_fops_create(&init_net, "rose", S_IRUGO, &rose_info_fops); + proc_net_fops_create(&init_net, "rose_neigh", S_IRUGO, &rose_neigh_fops); + proc_net_fops_create(&init_net, "rose_nodes", S_IRUGO, &rose_nodes_fops); + proc_net_fops_create(&init_net, "rose_routes", S_IRUGO, &rose_routes_fops); out: return rc; fail: @@ -1606,10 +1607,10 @@ static void __exit rose_exit(void) { int i; - proc_net_remove("rose"); - proc_net_remove("rose_neigh"); - proc_net_remove("rose_nodes"); - proc_net_remove("rose_routes"); + proc_net_remove(&init_net, "rose"); + proc_net_remove(&init_net, "rose_neigh"); + proc_net_remove(&init_net, "rose_nodes"); + proc_net_remove(&init_net, "rose_routes"); rose_loopback_clear(); rose_rt_free(); diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c index c58fa0d1be2..122d55d992e 100644 --- a/net/rxrpc/af_rxrpc.c +++ b/net/rxrpc/af_rxrpc.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include "ar-internal.h" @@ -829,8 +830,8 @@ static int __init af_rxrpc_init(void) } #ifdef CONFIG_PROC_FS - proc_net_fops_create("rxrpc_calls", 0, &rxrpc_call_seq_fops); - proc_net_fops_create("rxrpc_conns", 0, &rxrpc_connection_seq_fops); + proc_net_fops_create(&init_net, "rxrpc_calls", 0, &rxrpc_call_seq_fops); + proc_net_fops_create(&init_net, "rxrpc_conns", 0, &rxrpc_connection_seq_fops); #endif return 0; @@ -868,8 +869,8 @@ static void __exit af_rxrpc_exit(void) _debug("flush scheduled work"); flush_workqueue(rxrpc_workqueue); - proc_net_remove("rxrpc_conns"); - proc_net_remove("rxrpc_calls"); + proc_net_remove(&init_net, "rxrpc_conns"); + proc_net_remove(&init_net, "rxrpc_calls"); destroy_workqueue(rxrpc_workqueue); kmem_cache_destroy(rxrpc_call_jar); _leave(""); diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index dee0d5fb39c..efc383c58f1 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -1251,7 +1252,7 @@ static int __init pktsched_init(void) { register_qdisc(&pfifo_qdisc_ops); register_qdisc(&bfifo_qdisc_ops); - proc_net_fops_create("psched", 0, &psched_fops); + proc_net_fops_create(&init_net, "psched", 0, &psched_fops); rtnl_register(PF_UNSPEC, RTM_NEWQDISC, tc_modify_qdisc, NULL); rtnl_register(PF_UNSPEC, RTM_DELQDISC, tc_get_qdisc, NULL); diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 957c118a606..30929e3ca05 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -52,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -98,7 +99,7 @@ static __init int sctp_proc_init(void) { if (!proc_net_sctp) { struct proc_dir_entry *ent; - ent = proc_mkdir("net/sctp", NULL); + ent = proc_mkdir("sctp", init_net.proc_net); if (ent) { ent->owner = THIS_MODULE; proc_net_sctp = ent; @@ -131,7 +132,7 @@ static void sctp_proc_exit(void) if (proc_net_sctp) { proc_net_sctp = NULL; - remove_proc_entry("net/sctp", NULL); + remove_proc_entry("sctp", init_net.proc_net); } } diff --git a/net/sunrpc/stats.c b/net/sunrpc/stats.c index 74ba7d443df..4d4f3738b68 100644 --- a/net/sunrpc/stats.c +++ b/net/sunrpc/stats.c @@ -21,6 +21,7 @@ #include #include #include +#include #define RPCDBG_FACILITY RPCDBG_MISC @@ -265,7 +266,7 @@ rpc_proc_init(void) dprintk("RPC: registering /proc/net/rpc\n"); if (!proc_net_rpc) { struct proc_dir_entry *ent; - ent = proc_mkdir("rpc", proc_net); + ent = proc_mkdir("rpc", init_net.proc_net); if (ent) { ent->owner = THIS_MODULE; proc_net_rpc = ent; @@ -279,7 +280,7 @@ rpc_proc_exit(void) dprintk("RPC: unregistering /proc/net/rpc\n"); if (proc_net_rpc) { proc_net_rpc = NULL; - remove_proc_entry("net/rpc", NULL); + remove_proc_entry("rpc", init_net.proc_net); } } diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index a05c34260e7..2386090c3a1 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -103,6 +103,7 @@ #include #include #include +#include #include #include #include @@ -2135,7 +2136,7 @@ static int __init af_unix_init(void) sock_register(&unix_family_ops); #ifdef CONFIG_PROC_FS - proc_net_fops_create("unix", 0, &unix_seq_fops); + proc_net_fops_create(&init_net, "unix", 0, &unix_seq_fops); #endif unix_sysctl_register(); out: @@ -2146,7 +2147,7 @@ static void __exit af_unix_exit(void) { sock_unregister(PF_UNIX); unix_sysctl_unregister(); - proc_net_remove("unix"); + proc_net_remove(&init_net, "unix"); proto_unregister(&unix_proto); } diff --git a/net/wanrouter/wanproc.c b/net/wanrouter/wanproc.c index 236e7eaf1b7..f2e54c3f064 100644 --- a/net/wanrouter/wanproc.c +++ b/net/wanrouter/wanproc.c @@ -29,6 +29,7 @@ #include #include +#include #include #define PROC_STATS_FORMAT "%30s: %12lu\n" @@ -287,7 +288,7 @@ static const struct file_operations wandev_fops = { int __init wanrouter_proc_init(void) { struct proc_dir_entry *p; - proc_router = proc_mkdir(ROUTER_NAME, proc_net); + proc_router = proc_mkdir(ROUTER_NAME, init_net.proc_net); if (!proc_router) goto fail; @@ -303,7 +304,7 @@ int __init wanrouter_proc_init(void) fail_stat: remove_proc_entry("config", proc_router); fail_config: - remove_proc_entry(ROUTER_NAME, proc_net); + remove_proc_entry(ROUTER_NAME, init_net.proc_net); fail: return -ENOMEM; } @@ -316,7 +317,7 @@ void wanrouter_proc_cleanup(void) { remove_proc_entry("config", proc_router); remove_proc_entry("status", proc_router); - remove_proc_entry(ROUTER_NAME, proc_net); + remove_proc_entry(ROUTER_NAME, init_net.proc_net); } /* diff --git a/net/wireless/wext.c b/net/wireless/wext.c index debf5191a12..b8069afe041 100644 --- a/net/wireless/wext.c +++ b/net/wireless/wext.c @@ -93,6 +93,7 @@ #include /* ARPHRD_ETHER */ #include /* compare_ether_addr */ #include +#include #include /* Pretty obvious */ #include /* New driver API */ @@ -686,7 +687,7 @@ static const struct file_operations wireless_seq_fops = { int __init wext_proc_init(void) { /* Create /proc/net/wireless entry */ - if (!proc_net_fops_create("wireless", S_IRUGO, &wireless_seq_fops)) + if (!proc_net_fops_create(&init_net, "wireless", S_IRUGO, &wireless_seq_fops)) return -ENOMEM; return 0; diff --git a/net/x25/x25_proc.c b/net/x25/x25_proc.c index 7405b9c5b7f..7d55e50c936 100644 --- a/net/x25/x25_proc.c +++ b/net/x25/x25_proc.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -301,7 +302,7 @@ int __init x25_proc_init(void) struct proc_dir_entry *p; int rc = -ENOMEM; - x25_proc_dir = proc_mkdir("x25", proc_net); + x25_proc_dir = proc_mkdir("x25", init_net.proc_net); if (!x25_proc_dir) goto out; @@ -328,7 +329,7 @@ out_forward: out_socket: remove_proc_entry("route", x25_proc_dir); out_route: - remove_proc_entry("x25", proc_net); + remove_proc_entry("x25", init_net.proc_net); goto out; } @@ -337,7 +338,7 @@ void __exit x25_proc_exit(void) remove_proc_entry("forward", x25_proc_dir); remove_proc_entry("route", x25_proc_dir); remove_proc_entry("socket", x25_proc_dir); - remove_proc_entry("x25", proc_net); + remove_proc_entry("x25", init_net.proc_net); } #else /* CONFIG_PROC_FS */ -- cgit v1.2.3-70-g09d2 From 1b8d7ae42d02e483ad94035cca851e4f7fbecb40 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 8 Oct 2007 23:24:22 -0700 Subject: [NET]: Make socket creation namespace safe. This patch passes in the namespace a new socket should be created in and has the socket code do the appropriate reference counting. By virtue of this all socket create methods are touched. In addition the socket create methods are modified so that they will fail if you attempt to create a socket in a non-default network namespace. Failing if we attempt to create a socket outside of the default network namespace ensures that as we incrementally make the network stack network namespace aware we will not export functionality that someone has not audited and made certain is network namespace safe. Allowing us to partially enable network namespaces before all of the exotic protocols are supported. Any protocol layers I have missed will fail to compile because I now pass an extra parameter into the socket creation code. [ Integrated AF_IUCV build fixes from Andrew Morton... -DaveM ] Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- drivers/net/pppoe.c | 4 ++-- drivers/net/pppol2tp.c | 4 ++-- drivers/net/pppox.c | 7 +++++-- include/linux/if_pppox.h | 2 +- include/linux/net.h | 3 ++- include/net/iucv/af_iucv.h | 1 - include/net/llc_conn.h | 2 +- include/net/sock.h | 4 +++- net/appletalk/ddp.c | 7 +++++-- net/atm/common.c | 4 ++-- net/atm/common.h | 2 +- net/atm/pvc.c | 7 +++++-- net/atm/svc.c | 11 +++++++---- net/ax25/af_ax25.c | 9 ++++++--- net/bluetooth/af_bluetooth.c | 7 +++++-- net/bluetooth/bnep/sock.c | 4 ++-- net/bluetooth/cmtp/sock.c | 4 ++-- net/bluetooth/hci_sock.c | 4 ++-- net/bluetooth/hidp/sock.c | 4 ++-- net/bluetooth/l2cap.c | 10 +++++----- net/bluetooth/rfcomm/sock.c | 10 +++++----- net/bluetooth/sco.c | 10 +++++----- net/core/sock.c | 6 ++++-- net/decnet/af_decnet.c | 13 ++++++++----- net/econet/af_econet.c | 7 +++++-- net/ipv4/af_inet.c | 7 +++++-- net/ipv6/af_inet6.c | 7 +++++-- net/ipx/af_ipx.c | 7 +++++-- net/irda/af_irda.c | 11 +++++++---- net/iucv/af_iucv.c | 4 ++-- net/key/af_key.c | 7 +++++-- net/llc/af_llc.c | 7 +++++-- net/llc/llc_conn.c | 6 +++--- net/netlink/af_netlink.c | 15 +++++++++------ net/netrom/af_netrom.c | 9 ++++++--- net/packet/af_packet.c | 7 +++++-- net/rose/af_rose.c | 9 ++++++--- net/rxrpc/af_rxrpc.c | 7 +++++-- net/sctp/ipv6.c | 2 +- net/sctp/protocol.c | 2 +- net/socket.c | 9 +++++---- net/tipc/socket.c | 9 ++++++--- net/unix/af_unix.c | 13 ++++++++----- net/x25/af_x25.c | 13 ++++++++----- 44 files changed, 184 insertions(+), 113 deletions(-) (limited to 'drivers') diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index ee8ce195c53..53fcee26d6a 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -477,12 +477,12 @@ static struct proto pppoe_sk_proto = { * Initialize a new struct sock. * **********************************************************************/ -static int pppoe_create(struct socket *sock) +static int pppoe_create(struct net *net, struct socket *sock) { int error = -ENOMEM; struct sock *sk; - sk = sk_alloc(PF_PPPOX, GFP_KERNEL, &pppoe_sk_proto, 1); + sk = sk_alloc(net, PF_PPPOX, GFP_KERNEL, &pppoe_sk_proto, 1); if (!sk) goto out; diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c index 2eb424ba58e..921d4ef6d14 100644 --- a/drivers/net/pppol2tp.c +++ b/drivers/net/pppol2tp.c @@ -1411,12 +1411,12 @@ static struct proto pppol2tp_sk_proto = { /* socket() handler. Initialize a new struct sock. */ -static int pppol2tp_create(struct socket *sock) +static int pppol2tp_create(struct net *net, struct socket *sock) { int error = -ENOMEM; struct sock *sk; - sk = sk_alloc(PF_PPPOX, GFP_KERNEL, &pppol2tp_sk_proto, 1); + sk = sk_alloc(net, PF_PPPOX, GFP_KERNEL, &pppol2tp_sk_proto, 1); if (!sk) goto out; diff --git a/drivers/net/pppox.c b/drivers/net/pppox.c index 25c52b55c38..c6898c1fc54 100644 --- a/drivers/net/pppox.c +++ b/drivers/net/pppox.c @@ -104,10 +104,13 @@ int pppox_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) EXPORT_SYMBOL(pppox_ioctl); -static int pppox_create(struct socket *sock, int protocol) +static int pppox_create(struct net *net, struct socket *sock, int protocol) { int rc = -EPROTOTYPE; + if (net != &init_net) + return -EAFNOSUPPORT; + if (protocol < 0 || protocol > PX_MAX_PROTO) goto out; @@ -123,7 +126,7 @@ static int pppox_create(struct socket *sock, int protocol) !try_module_get(pppox_protos[protocol]->owner)) goto out; - rc = pppox_protos[protocol]->create(sock); + rc = pppox_protos[protocol]->create(net, sock); module_put(pppox_protos[protocol]->owner); out: diff --git a/include/linux/if_pppox.h b/include/linux/if_pppox.h index 25652545ba6..43cfc9f0c07 100644 --- a/include/linux/if_pppox.h +++ b/include/linux/if_pppox.h @@ -172,7 +172,7 @@ static inline struct sock *sk_pppox(struct pppox_sock *po) struct module; struct pppox_proto { - int (*create)(struct socket *sock); + int (*create)(struct net *net, struct socket *sock); int (*ioctl)(struct socket *sock, unsigned int cmd, unsigned long arg); struct module *owner; diff --git a/include/linux/net.h b/include/linux/net.h index efc45177b50..c136abce7ef 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -23,6 +23,7 @@ struct poll_table_struct; struct inode; +struct net; #define NPROTO 34 /* should be enough for now.. */ @@ -169,7 +170,7 @@ struct proto_ops { struct net_proto_family { int family; - int (*create)(struct socket *sock, int protocol); + int (*create)(struct net *net, struct socket *sock, int protocol); struct module *owner; }; diff --git a/include/net/iucv/af_iucv.h b/include/net/iucv/af_iucv.h index b6c468cd7f5..c661c6fd6fd 100644 --- a/include/net/iucv/af_iucv.h +++ b/include/net/iucv/af_iucv.h @@ -78,7 +78,6 @@ static void iucv_sock_destruct(struct sock *sk); static void iucv_sock_cleanup_listen(struct sock *parent); static void iucv_sock_kill(struct sock *sk); static void iucv_sock_close(struct sock *sk); -static int iucv_sock_create(struct socket *sock, int proto); static int iucv_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len); static int iucv_sock_connect(struct socket *sock, struct sockaddr *addr, diff --git a/include/net/llc_conn.h b/include/net/llc_conn.h index 00730d21b52..e2374e34989 100644 --- a/include/net/llc_conn.h +++ b/include/net/llc_conn.h @@ -93,7 +93,7 @@ static __inline__ char llc_backlog_type(struct sk_buff *skb) return skb->cb[sizeof(skb->cb) - 1]; } -extern struct sock *llc_sk_alloc(int family, gfp_t priority, +extern struct sock *llc_sk_alloc(struct net *net, int family, gfp_t priority, struct proto *prot); extern void llc_sk_free(struct sock *sk); diff --git a/include/net/sock.h b/include/net/sock.h index 9ef8b5fb793..74e1f7d90d7 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -56,6 +56,7 @@ #include #include #include +#include /* * This structure really needs to be cleaned up. @@ -776,7 +777,7 @@ extern void FASTCALL(release_sock(struct sock *sk)); SINGLE_DEPTH_NESTING) #define bh_unlock_sock(__sk) spin_unlock(&((__sk)->sk_lock.slock)) -extern struct sock *sk_alloc(int family, +extern struct sock *sk_alloc(struct net *net, int family, gfp_t priority, struct proto *prot, int zero_it); extern void sk_free(struct sock *sk); @@ -1005,6 +1006,7 @@ static inline void sock_copy(struct sock *nsk, const struct sock *osk) #endif memcpy(nsk, osk, osk->sk_prot->obj_size); + get_net(nsk->sk_net); #ifdef CONFIG_SECURITY_NETWORK nsk->sk_security = sptr; security_sk_clone(osk, nsk); diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index 594b5973954..fd1d52f0970 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -1026,11 +1026,14 @@ static struct proto ddp_proto = { * Create a socket. Initialise the socket, blank the addresses * set the state. */ -static int atalk_create(struct socket *sock, int protocol) +static int atalk_create(struct net *net, struct socket *sock, int protocol) { struct sock *sk; int rc = -ESOCKTNOSUPPORT; + if (net != &init_net) + return -EAFNOSUPPORT; + /* * We permit SOCK_DGRAM and RAW is an extension. It is trivial to do * and gives you the full ELAP frame. Should be handy for CAP 8) @@ -1038,7 +1041,7 @@ static int atalk_create(struct socket *sock, int protocol) if (sock->type != SOCK_RAW && sock->type != SOCK_DGRAM) goto out; rc = -ENOMEM; - sk = sk_alloc(PF_APPLETALK, GFP_KERNEL, &ddp_proto, 1); + sk = sk_alloc(net, PF_APPLETALK, GFP_KERNEL, &ddp_proto, 1); if (!sk) goto out; rc = 0; diff --git a/net/atm/common.c b/net/atm/common.c index 299ec1eb872..e166d9e0ffd 100644 --- a/net/atm/common.c +++ b/net/atm/common.c @@ -125,7 +125,7 @@ static struct proto vcc_proto = { .obj_size = sizeof(struct atm_vcc), }; -int vcc_create(struct socket *sock, int protocol, int family) +int vcc_create(struct net *net, struct socket *sock, int protocol, int family) { struct sock *sk; struct atm_vcc *vcc; @@ -133,7 +133,7 @@ int vcc_create(struct socket *sock, int protocol, int family) sock->sk = NULL; if (sock->type == SOCK_STREAM) return -EINVAL; - sk = sk_alloc(family, GFP_KERNEL, &vcc_proto, 1); + sk = sk_alloc(net, family, GFP_KERNEL, &vcc_proto, 1); if (!sk) return -ENOMEM; sock_init_data(sock, sk); diff --git a/net/atm/common.h b/net/atm/common.h index ad78c9e1117..16f32c1fa1c 100644 --- a/net/atm/common.h +++ b/net/atm/common.h @@ -10,7 +10,7 @@ #include /* for poll_table */ -int vcc_create(struct socket *sock, int protocol, int family); +int vcc_create(struct net *net, struct socket *sock, int protocol, int family); int vcc_release(struct socket *sock); int vcc_connect(struct socket *sock, int itf, short vpi, int vci); int vcc_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, diff --git a/net/atm/pvc.c b/net/atm/pvc.c index 848e6e191cc..43e8bf5ed00 100644 --- a/net/atm/pvc.c +++ b/net/atm/pvc.c @@ -124,10 +124,13 @@ static const struct proto_ops pvc_proto_ops = { }; -static int pvc_create(struct socket *sock,int protocol) +static int pvc_create(struct net *net, struct socket *sock,int protocol) { + if (net != &init_net) + return -EAFNOSUPPORT; + sock->ops = &pvc_proto_ops; - return vcc_create(sock, protocol, PF_ATMPVC); + return vcc_create(net, sock, protocol, PF_ATMPVC); } diff --git a/net/atm/svc.c b/net/atm/svc.c index 53d04c7992c..daf9a48a7db 100644 --- a/net/atm/svc.c +++ b/net/atm/svc.c @@ -25,7 +25,7 @@ #include "signaling.h" #include "addr.h" -static int svc_create(struct socket *sock,int protocol); +static int svc_create(struct net *net, struct socket *sock,int protocol); /* * Note: since all this is still nicely synchronized with the signaling demon, @@ -326,7 +326,7 @@ static int svc_accept(struct socket *sock,struct socket *newsock,int flags) lock_sock(sk); - error = svc_create(newsock,0); + error = svc_create(sk->sk_net, newsock,0); if (error) goto out; @@ -627,12 +627,15 @@ static const struct proto_ops svc_proto_ops = { }; -static int svc_create(struct socket *sock,int protocol) +static int svc_create(struct net *net, struct socket *sock,int protocol) { int error; + if (net != &init_net) + return -EAFNOSUPPORT; + sock->ops = &svc_proto_ops; - error = vcc_create(sock, protocol, AF_ATMSVC); + error = vcc_create(net, sock, protocol, AF_ATMSVC); if (error) return error; ATM_SD(sock)->local.sas_family = AF_ATMSVC; ATM_SD(sock)->remote.sas_family = AF_ATMSVC; diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index 1d71f85680b..def6c42ad16 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -780,11 +780,14 @@ static struct proto ax25_proto = { .obj_size = sizeof(struct sock), }; -static int ax25_create(struct socket *sock, int protocol) +static int ax25_create(struct net *net, struct socket *sock, int protocol) { struct sock *sk; ax25_cb *ax25; + if (net != &init_net) + return -EAFNOSUPPORT; + switch (sock->type) { case SOCK_DGRAM: if (protocol == 0 || protocol == PF_AX25) @@ -830,7 +833,7 @@ static int ax25_create(struct socket *sock, int protocol) return -ESOCKTNOSUPPORT; } - if ((sk = sk_alloc(PF_AX25, GFP_ATOMIC, &ax25_proto, 1)) == NULL) + if ((sk = sk_alloc(net, PF_AX25, GFP_ATOMIC, &ax25_proto, 1)) == NULL) return -ENOMEM; ax25 = sk->sk_protinfo = ax25_create_cb(); @@ -855,7 +858,7 @@ struct sock *ax25_make_new(struct sock *osk, struct ax25_dev *ax25_dev) struct sock *sk; ax25_cb *ax25, *oax25; - if ((sk = sk_alloc(PF_AX25, GFP_ATOMIC, osk->sk_prot, 1)) == NULL) + if ((sk = sk_alloc(osk->sk_net, PF_AX25, GFP_ATOMIC, osk->sk_prot, 1)) == NULL) return NULL; if ((ax25 = ax25_create_cb()) == NULL) { diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index d942b946ba0..1220d8a41eb 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -95,10 +95,13 @@ int bt_sock_unregister(int proto) } EXPORT_SYMBOL(bt_sock_unregister); -static int bt_sock_create(struct socket *sock, int proto) +static int bt_sock_create(struct net *net, struct socket *sock, int proto) { int err; + if (net != &init_net) + return -EAFNOSUPPORT; + if (proto < 0 || proto >= BT_MAX_PROTO) return -EINVAL; @@ -113,7 +116,7 @@ static int bt_sock_create(struct socket *sock, int proto) read_lock(&bt_proto_lock); if (bt_proto[proto] && try_module_get(bt_proto[proto]->owner)) { - err = bt_proto[proto]->create(sock, proto); + err = bt_proto[proto]->create(net, sock, proto); module_put(bt_proto[proto]->owner); } diff --git a/net/bluetooth/bnep/sock.c b/net/bluetooth/bnep/sock.c index 10292e77604..f718965f296 100644 --- a/net/bluetooth/bnep/sock.c +++ b/net/bluetooth/bnep/sock.c @@ -204,7 +204,7 @@ static struct proto bnep_proto = { .obj_size = sizeof(struct bt_sock) }; -static int bnep_sock_create(struct socket *sock, int protocol) +static int bnep_sock_create(struct net *net, struct socket *sock, int protocol) { struct sock *sk; @@ -213,7 +213,7 @@ static int bnep_sock_create(struct socket *sock, int protocol) if (sock->type != SOCK_RAW) return -ESOCKTNOSUPPORT; - sk = sk_alloc(PF_BLUETOOTH, GFP_ATOMIC, &bnep_proto, 1); + sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &bnep_proto, 1); if (!sk) return -ENOMEM; diff --git a/net/bluetooth/cmtp/sock.c b/net/bluetooth/cmtp/sock.c index 19be7861e51..cf700c20d11 100644 --- a/net/bluetooth/cmtp/sock.c +++ b/net/bluetooth/cmtp/sock.c @@ -195,7 +195,7 @@ static struct proto cmtp_proto = { .obj_size = sizeof(struct bt_sock) }; -static int cmtp_sock_create(struct socket *sock, int protocol) +static int cmtp_sock_create(struct net *net, struct socket *sock, int protocol) { struct sock *sk; @@ -204,7 +204,7 @@ static int cmtp_sock_create(struct socket *sock, int protocol) if (sock->type != SOCK_RAW) return -ESOCKTNOSUPPORT; - sk = sk_alloc(PF_BLUETOOTH, GFP_ATOMIC, &cmtp_proto, 1); + sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &cmtp_proto, 1); if (!sk) return -ENOMEM; diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 5ccea5fbd23..43dd6373bff 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -634,7 +634,7 @@ static struct proto hci_sk_proto = { .obj_size = sizeof(struct hci_pinfo) }; -static int hci_sock_create(struct socket *sock, int protocol) +static int hci_sock_create(struct net *net, struct socket *sock, int protocol) { struct sock *sk; @@ -645,7 +645,7 @@ static int hci_sock_create(struct socket *sock, int protocol) sock->ops = &hci_sock_ops; - sk = sk_alloc(PF_BLUETOOTH, GFP_ATOMIC, &hci_sk_proto, 1); + sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &hci_sk_proto, 1); if (!sk) return -ENOMEM; diff --git a/net/bluetooth/hidp/sock.c b/net/bluetooth/hidp/sock.c index 0c185257e55..1de2b6fbcac 100644 --- a/net/bluetooth/hidp/sock.c +++ b/net/bluetooth/hidp/sock.c @@ -246,7 +246,7 @@ static struct proto hidp_proto = { .obj_size = sizeof(struct bt_sock) }; -static int hidp_sock_create(struct socket *sock, int protocol) +static int hidp_sock_create(struct net *net, struct socket *sock, int protocol) { struct sock *sk; @@ -255,7 +255,7 @@ static int hidp_sock_create(struct socket *sock, int protocol) if (sock->type != SOCK_RAW) return -ESOCKTNOSUPPORT; - sk = sk_alloc(PF_BLUETOOTH, GFP_ATOMIC, &hidp_proto, 1); + sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &hidp_proto, 1); if (!sk) return -ENOMEM; diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index c4e4ce4ebb2..36ef27b625d 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -518,11 +518,11 @@ static struct proto l2cap_proto = { .obj_size = sizeof(struct l2cap_pinfo) }; -static struct sock *l2cap_sock_alloc(struct socket *sock, int proto, gfp_t prio) +static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio) { struct sock *sk; - sk = sk_alloc(PF_BLUETOOTH, prio, &l2cap_proto, 1); + sk = sk_alloc(net, PF_BLUETOOTH, prio, &l2cap_proto, 1); if (!sk) return NULL; @@ -543,7 +543,7 @@ static struct sock *l2cap_sock_alloc(struct socket *sock, int proto, gfp_t prio) return sk; } -static int l2cap_sock_create(struct socket *sock, int protocol) +static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol) { struct sock *sk; @@ -560,7 +560,7 @@ static int l2cap_sock_create(struct socket *sock, int protocol) sock->ops = &l2cap_sock_ops; - sk = l2cap_sock_alloc(sock, protocol, GFP_ATOMIC); + sk = l2cap_sock_alloc(net, sock, protocol, GFP_ATOMIC); if (!sk) return -ENOMEM; @@ -1425,7 +1425,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd goto response; } - sk = l2cap_sock_alloc(NULL, BTPROTO_L2CAP, GFP_ATOMIC); + sk = l2cap_sock_alloc(parent->sk_net, NULL, BTPROTO_L2CAP, GFP_ATOMIC); if (!sk) goto response; diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index 30586ab9e87..266b6972667 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -282,12 +282,12 @@ static struct proto rfcomm_proto = { .obj_size = sizeof(struct rfcomm_pinfo) }; -static struct sock *rfcomm_sock_alloc(struct socket *sock, int proto, gfp_t prio) +static struct sock *rfcomm_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio) { struct rfcomm_dlc *d; struct sock *sk; - sk = sk_alloc(PF_BLUETOOTH, prio, &rfcomm_proto, 1); + sk = sk_alloc(net, PF_BLUETOOTH, prio, &rfcomm_proto, 1); if (!sk) return NULL; @@ -323,7 +323,7 @@ static struct sock *rfcomm_sock_alloc(struct socket *sock, int proto, gfp_t prio return sk; } -static int rfcomm_sock_create(struct socket *sock, int protocol) +static int rfcomm_sock_create(struct net *net, struct socket *sock, int protocol) { struct sock *sk; @@ -336,7 +336,7 @@ static int rfcomm_sock_create(struct socket *sock, int protocol) sock->ops = &rfcomm_sock_ops; - sk = rfcomm_sock_alloc(sock, protocol, GFP_ATOMIC); + sk = rfcomm_sock_alloc(net, sock, protocol, GFP_ATOMIC); if (!sk) return -ENOMEM; @@ -868,7 +868,7 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc * goto done; } - sk = rfcomm_sock_alloc(NULL, BTPROTO_RFCOMM, GFP_ATOMIC); + sk = rfcomm_sock_alloc(parent->sk_net, NULL, BTPROTO_RFCOMM, GFP_ATOMIC); if (!sk) goto done; diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 3f5163e725e..65b6fb1c415 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -414,11 +414,11 @@ static struct proto sco_proto = { .obj_size = sizeof(struct sco_pinfo) }; -static struct sock *sco_sock_alloc(struct socket *sock, int proto, gfp_t prio) +static struct sock *sco_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio) { struct sock *sk; - sk = sk_alloc(PF_BLUETOOTH, prio, &sco_proto, 1); + sk = sk_alloc(net, PF_BLUETOOTH, prio, &sco_proto, 1); if (!sk) return NULL; @@ -439,7 +439,7 @@ static struct sock *sco_sock_alloc(struct socket *sock, int proto, gfp_t prio) return sk; } -static int sco_sock_create(struct socket *sock, int protocol) +static int sco_sock_create(struct net *net, struct socket *sock, int protocol) { struct sock *sk; @@ -452,7 +452,7 @@ static int sco_sock_create(struct socket *sock, int protocol) sock->ops = &sco_sock_ops; - sk = sco_sock_alloc(sock, protocol, GFP_ATOMIC); + sk = sco_sock_alloc(net, sock, protocol, GFP_ATOMIC); if (!sk) return -ENOMEM; @@ -807,7 +807,7 @@ static void sco_conn_ready(struct sco_conn *conn) bh_lock_sock(parent); - sk = sco_sock_alloc(NULL, BTPROTO_SCO, GFP_ATOMIC); + sk = sco_sock_alloc(parent->sk_net, NULL, BTPROTO_SCO, GFP_ATOMIC); if (!sk) { bh_unlock_sock(parent); goto done; diff --git a/net/core/sock.c b/net/core/sock.c index bbc726a49d8..a31455dc702 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -873,7 +873,7 @@ static inline void sock_lock_init(struct sock *sk) * @prot: struct proto associated with this new sock instance * @zero_it: if we should zero the newly allocated sock */ -struct sock *sk_alloc(int family, gfp_t priority, +struct sock *sk_alloc(struct net *net, int family, gfp_t priority, struct proto *prot, int zero_it) { struct sock *sk = NULL; @@ -894,6 +894,7 @@ struct sock *sk_alloc(int family, gfp_t priority, */ sk->sk_prot = sk->sk_prot_creator = prot; sock_lock_init(sk); + sk->sk_net = get_net(net); } if (security_sk_alloc(sk, family, priority)) @@ -933,6 +934,7 @@ void sk_free(struct sock *sk) __FUNCTION__, atomic_read(&sk->sk_omem_alloc)); security_sk_free(sk); + put_net(sk->sk_net); if (sk->sk_prot_creator->slab != NULL) kmem_cache_free(sk->sk_prot_creator->slab, sk); else @@ -942,7 +944,7 @@ void sk_free(struct sock *sk) struct sock *sk_clone(const struct sock *sk, const gfp_t priority) { - struct sock *newsk = sk_alloc(sk->sk_family, priority, sk->sk_prot, 0); + struct sock *newsk = sk_alloc(sk->sk_net, sk->sk_family, priority, sk->sk_prot, 0); if (newsk != NULL) { struct sk_filter *filter; diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c index 625d5955b8e..aca4c4930eb 100644 --- a/net/decnet/af_decnet.c +++ b/net/decnet/af_decnet.c @@ -471,10 +471,10 @@ static struct proto dn_proto = { .obj_size = sizeof(struct dn_sock), }; -static struct sock *dn_alloc_sock(struct socket *sock, gfp_t gfp) +static struct sock *dn_alloc_sock(struct net *net, struct socket *sock, gfp_t gfp) { struct dn_scp *scp; - struct sock *sk = sk_alloc(PF_DECnet, gfp, &dn_proto, 1); + struct sock *sk = sk_alloc(net, PF_DECnet, gfp, &dn_proto, 1); if (!sk) goto out; @@ -675,10 +675,13 @@ char *dn_addr2asc(__u16 addr, char *buf) -static int dn_create(struct socket *sock, int protocol) +static int dn_create(struct net *net, struct socket *sock, int protocol) { struct sock *sk; + if (net != &init_net) + return -EAFNOSUPPORT; + switch(sock->type) { case SOCK_SEQPACKET: if (protocol != DNPROTO_NSP) @@ -691,7 +694,7 @@ static int dn_create(struct socket *sock, int protocol) } - if ((sk = dn_alloc_sock(sock, GFP_KERNEL)) == NULL) + if ((sk = dn_alloc_sock(net, sock, GFP_KERNEL)) == NULL) return -ENOBUFS; sk->sk_protocol = protocol; @@ -1091,7 +1094,7 @@ static int dn_accept(struct socket *sock, struct socket *newsock, int flags) cb = DN_SKB_CB(skb); sk->sk_ack_backlog--; - newsk = dn_alloc_sock(newsock, sk->sk_allocation); + newsk = dn_alloc_sock(sk->sk_net, newsock, sk->sk_allocation); if (newsk == NULL) { release_sock(sk); kfree_skb(skb); diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c index 35c96bcc0f3..a2429dbcb86 100644 --- a/net/econet/af_econet.c +++ b/net/econet/af_econet.c @@ -608,12 +608,15 @@ static struct proto econet_proto = { * Create an Econet socket */ -static int econet_create(struct socket *sock, int protocol) +static int econet_create(struct net *net, struct socket *sock, int protocol) { struct sock *sk; struct econet_sock *eo; int err; + if (net != &init_net) + return -EAFNOSUPPORT; + /* Econet only provides datagram services. */ if (sock->type != SOCK_DGRAM) return -ESOCKTNOSUPPORT; @@ -621,7 +624,7 @@ static int econet_create(struct socket *sock, int protocol) sock->state = SS_UNCONNECTED; err = -ENOBUFS; - sk = sk_alloc(PF_ECONET, GFP_KERNEL, &econet_proto, 1); + sk = sk_alloc(net, PF_ECONET, GFP_KERNEL, &econet_proto, 1); if (sk == NULL) goto out; diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index e68103475cc..110a19edacc 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -241,7 +241,7 @@ EXPORT_SYMBOL(build_ehash_secret); * Create an inet socket. */ -static int inet_create(struct socket *sock, int protocol) +static int inet_create(struct net *net, struct socket *sock, int protocol) { struct sock *sk; struct list_head *p; @@ -253,6 +253,9 @@ static int inet_create(struct socket *sock, int protocol) int try_loading_module = 0; int err; + if (net != &init_net) + return -EAFNOSUPPORT; + if (sock->type != SOCK_RAW && sock->type != SOCK_DGRAM && !inet_ehash_secret) @@ -320,7 +323,7 @@ lookup_protocol: BUG_TRAP(answer_prot->slab != NULL); err = -ENOBUFS; - sk = sk_alloc(PF_INET, GFP_KERNEL, answer_prot, 1); + sk = sk_alloc(net, PF_INET, GFP_KERNEL, answer_prot, 1); if (sk == NULL) goto out; diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index b5f96372ad7..21931c86e95 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -81,7 +81,7 @@ static __inline__ struct ipv6_pinfo *inet6_sk_generic(struct sock *sk) return (struct ipv6_pinfo *)(((u8 *)sk) + offset); } -static int inet6_create(struct socket *sock, int protocol) +static int inet6_create(struct net *net, struct socket *sock, int protocol) { struct inet_sock *inet; struct ipv6_pinfo *np; @@ -94,6 +94,9 @@ static int inet6_create(struct socket *sock, int protocol) int try_loading_module = 0; int err; + if (net != &init_net) + return -EAFNOSUPPORT; + if (sock->type != SOCK_RAW && sock->type != SOCK_DGRAM && !inet_ehash_secret) @@ -159,7 +162,7 @@ lookup_protocol: BUG_TRAP(answer_prot->slab != NULL); err = -ENOBUFS; - sk = sk_alloc(PF_INET6, GFP_KERNEL, answer_prot, 1); + sk = sk_alloc(net, PF_INET6, GFP_KERNEL, answer_prot, 1); if (sk == NULL) goto out; diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c index 8400525177a..ee28babad22 100644 --- a/net/ipx/af_ipx.c +++ b/net/ipx/af_ipx.c @@ -1360,11 +1360,14 @@ static struct proto ipx_proto = { .obj_size = sizeof(struct ipx_sock), }; -static int ipx_create(struct socket *sock, int protocol) +static int ipx_create(struct net *net, struct socket *sock, int protocol) { int rc = -ESOCKTNOSUPPORT; struct sock *sk; + if (net != &init_net) + return -EAFNOSUPPORT; + /* * SPX support is not anymore in the kernel sources. If you want to * ressurrect it, completing it and making it understand shared skbs, @@ -1375,7 +1378,7 @@ static int ipx_create(struct socket *sock, int protocol) goto out; rc = -ENOMEM; - sk = sk_alloc(PF_IPX, GFP_KERNEL, &ipx_proto, 1); + sk = sk_alloc(net, PF_IPX, GFP_KERNEL, &ipx_proto, 1); if (!sk) goto out; #ifdef IPX_REFCNT_DEBUG diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c index c80949a7192..0328ae2654f 100644 --- a/net/irda/af_irda.c +++ b/net/irda/af_irda.c @@ -60,7 +60,7 @@ #include -static int irda_create(struct socket *sock, int protocol); +static int irda_create(struct net *net, struct socket *sock, int protocol); static const struct proto_ops irda_stream_ops; static const struct proto_ops irda_seqpacket_ops; @@ -831,7 +831,7 @@ static int irda_accept(struct socket *sock, struct socket *newsock, int flags) IRDA_DEBUG(2, "%s()\n", __FUNCTION__); - err = irda_create(newsock, sk->sk_protocol); + err = irda_create(sk->sk_net, newsock, sk->sk_protocol); if (err) return err; @@ -1057,13 +1057,16 @@ static struct proto irda_proto = { * Create IrDA socket * */ -static int irda_create(struct socket *sock, int protocol) +static int irda_create(struct net *net, struct socket *sock, int protocol) { struct sock *sk; struct irda_sock *self; IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + if (net != &init_net) + return -EAFNOSUPPORT; + /* Check for valid socket type */ switch (sock->type) { case SOCK_STREAM: /* For TTP connections with SAR disabled */ @@ -1075,7 +1078,7 @@ static int irda_create(struct socket *sock, int protocol) } /* Allocate networking socket */ - sk = sk_alloc(PF_IRDA, GFP_ATOMIC, &irda_proto, 1); + sk = sk_alloc(net, PF_IRDA, GFP_ATOMIC, &irda_proto, 1); if (sk == NULL) return -ENOMEM; diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index 53ae14c35f7..53668585e94 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -213,7 +213,7 @@ static struct sock *iucv_sock_alloc(struct socket *sock, int proto, gfp_t prio) { struct sock *sk; - sk = sk_alloc(PF_IUCV, prio, &iucv_proto, 1); + sk = sk_alloc(&init_net, PF_IUCV, prio, &iucv_proto, 1); if (!sk) return NULL; @@ -240,7 +240,7 @@ static struct sock *iucv_sock_alloc(struct socket *sock, int proto, gfp_t prio) } /* Create an IUCV socket */ -static int iucv_sock_create(struct socket *sock, int protocol) +static int iucv_sock_create(struct net *net, struct socket *sock, int protocol) { struct sock *sk; diff --git a/net/key/af_key.c b/net/key/af_key.c index 5b802bbb856..ff5c3d03005 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -136,11 +136,14 @@ static struct proto key_proto = { .obj_size = sizeof(struct pfkey_sock), }; -static int pfkey_create(struct socket *sock, int protocol) +static int pfkey_create(struct net *net, struct socket *sock, int protocol) { struct sock *sk; int err; + if (net != &init_net) + return -EAFNOSUPPORT; + if (!capable(CAP_NET_ADMIN)) return -EPERM; if (sock->type != SOCK_RAW) @@ -149,7 +152,7 @@ static int pfkey_create(struct socket *sock, int protocol) return -EPROTONOSUPPORT; err = -ENOMEM; - sk = sk_alloc(PF_KEY, GFP_KERNEL, &key_proto, 1); + sk = sk_alloc(net, PF_KEY, GFP_KERNEL, &key_proto, 1); if (sk == NULL) goto out; diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index 6b8a103cf9e..b48244156e7 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -150,14 +150,17 @@ static struct proto llc_proto = { * socket type we have available. * Returns 0 upon success, negative upon failure. */ -static int llc_ui_create(struct socket *sock, int protocol) +static int llc_ui_create(struct net *net, struct socket *sock, int protocol) { struct sock *sk; int rc = -ESOCKTNOSUPPORT; + if (net != &init_net) + return -EAFNOSUPPORT; + if (likely(sock->type == SOCK_DGRAM || sock->type == SOCK_STREAM)) { rc = -ENOMEM; - sk = llc_sk_alloc(PF_LLC, GFP_KERNEL, &llc_proto); + sk = llc_sk_alloc(net, PF_LLC, GFP_KERNEL, &llc_proto); if (sk) { rc = 0; llc_ui_sk_init(sock, sk); diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c index 3b8cfbe029a..8ebc2769dfd 100644 --- a/net/llc/llc_conn.c +++ b/net/llc/llc_conn.c @@ -700,7 +700,7 @@ static struct sock *llc_create_incoming_sock(struct sock *sk, struct llc_addr *saddr, struct llc_addr *daddr) { - struct sock *newsk = llc_sk_alloc(sk->sk_family, GFP_ATOMIC, + struct sock *newsk = llc_sk_alloc(sk->sk_net, sk->sk_family, GFP_ATOMIC, sk->sk_prot); struct llc_sock *newllc, *llc = llc_sk(sk); @@ -867,9 +867,9 @@ static void llc_sk_init(struct sock* sk) * Allocates a LLC sock and initializes it. Returns the new LLC sock * or %NULL if there's no memory available for one */ -struct sock *llc_sk_alloc(int family, gfp_t priority, struct proto *prot) +struct sock *llc_sk_alloc(struct net *net, int family, gfp_t priority, struct proto *prot) { - struct sock *sk = sk_alloc(family, priority, prot, 1); + struct sock *sk = sk_alloc(net, family, priority, prot, 1); if (!sk) goto out; diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 3982f13dab1..406a493300d 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -384,15 +384,15 @@ static struct proto netlink_proto = { .obj_size = sizeof(struct netlink_sock), }; -static int __netlink_create(struct socket *sock, struct mutex *cb_mutex, - int protocol) +static int __netlink_create(struct net *net, struct socket *sock, + struct mutex *cb_mutex, int protocol) { struct sock *sk; struct netlink_sock *nlk; sock->ops = &netlink_ops; - sk = sk_alloc(PF_NETLINK, GFP_KERNEL, &netlink_proto, 1); + sk = sk_alloc(net, PF_NETLINK, GFP_KERNEL, &netlink_proto, 1); if (!sk) return -ENOMEM; @@ -412,13 +412,16 @@ static int __netlink_create(struct socket *sock, struct mutex *cb_mutex, return 0; } -static int netlink_create(struct socket *sock, int protocol) +static int netlink_create(struct net *net, struct socket *sock, int protocol) { struct module *module = NULL; struct mutex *cb_mutex; struct netlink_sock *nlk; int err = 0; + if (net != &init_net) + return -EAFNOSUPPORT; + sock->state = SS_UNCONNECTED; if (sock->type != SOCK_RAW && sock->type != SOCK_DGRAM) @@ -441,7 +444,7 @@ static int netlink_create(struct socket *sock, int protocol) cb_mutex = nl_table[protocol].cb_mutex; netlink_unlock_table(); - if ((err = __netlink_create(sock, cb_mutex, protocol)) < 0) + if ((err = __netlink_create(net, sock, cb_mutex, protocol)) < 0) goto out_module; nlk = nlk_sk(sock->sk); @@ -1318,7 +1321,7 @@ netlink_kernel_create(int unit, unsigned int groups, if (sock_create_lite(PF_NETLINK, SOCK_DGRAM, unit, &sock)) return NULL; - if (__netlink_create(sock, cb_mutex, unit) < 0) + if (__netlink_create(&init_net, sock, cb_mutex, unit) < 0) goto out_sock_release; if (groups < 32) diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index 15c8a92bd71..e969d1bc765 100644 --- a/net/netrom/af_netrom.c +++ b/net/netrom/af_netrom.c @@ -409,15 +409,18 @@ static struct proto nr_proto = { .obj_size = sizeof(struct nr_sock), }; -static int nr_create(struct socket *sock, int protocol) +static int nr_create(struct net *net, struct socket *sock, int protocol) { struct sock *sk; struct nr_sock *nr; + if (net != &init_net) + return -EAFNOSUPPORT; + if (sock->type != SOCK_SEQPACKET || protocol != 0) return -ESOCKTNOSUPPORT; - if ((sk = sk_alloc(PF_NETROM, GFP_ATOMIC, &nr_proto, 1)) == NULL) + if ((sk = sk_alloc(net, PF_NETROM, GFP_ATOMIC, &nr_proto, 1)) == NULL) return -ENOMEM; nr = nr_sk(sk); @@ -459,7 +462,7 @@ static struct sock *nr_make_new(struct sock *osk) if (osk->sk_type != SOCK_SEQPACKET) return NULL; - if ((sk = sk_alloc(PF_NETROM, GFP_ATOMIC, osk->sk_prot, 1)) == NULL) + if ((sk = sk_alloc(osk->sk_net, PF_NETROM, GFP_ATOMIC, osk->sk_prot, 1)) == NULL) return NULL; nr = nr_sk(sk); diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 56502292f24..766b5faaed2 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -977,13 +977,16 @@ static struct proto packet_proto = { * Create a packet of type SOCK_PACKET. */ -static int packet_create(struct socket *sock, int protocol) +static int packet_create(struct net *net, struct socket *sock, int protocol) { struct sock *sk; struct packet_sock *po; __be16 proto = (__force __be16)protocol; /* weird, but documented */ int err; + if (net != &init_net) + return -EAFNOSUPPORT; + if (!capable(CAP_NET_RAW)) return -EPERM; if (sock->type != SOCK_DGRAM && sock->type != SOCK_RAW && @@ -993,7 +996,7 @@ static int packet_create(struct socket *sock, int protocol) sock->state = SS_UNCONNECTED; err = -ENOBUFS; - sk = sk_alloc(PF_PACKET, GFP_KERNEL, &packet_proto, 1); + sk = sk_alloc(net, PF_PACKET, GFP_KERNEL, &packet_proto, 1); if (sk == NULL) goto out; diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index 48319f7991a..67e06ab7f85 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c @@ -499,15 +499,18 @@ static struct proto rose_proto = { .obj_size = sizeof(struct rose_sock), }; -static int rose_create(struct socket *sock, int protocol) +static int rose_create(struct net *net, struct socket *sock, int protocol) { struct sock *sk; struct rose_sock *rose; + if (net != &init_net) + return -EAFNOSUPPORT; + if (sock->type != SOCK_SEQPACKET || protocol != 0) return -ESOCKTNOSUPPORT; - if ((sk = sk_alloc(PF_ROSE, GFP_ATOMIC, &rose_proto, 1)) == NULL) + if ((sk = sk_alloc(net, PF_ROSE, GFP_ATOMIC, &rose_proto, 1)) == NULL) return -ENOMEM; rose = rose_sk(sk); @@ -545,7 +548,7 @@ static struct sock *rose_make_new(struct sock *osk) if (osk->sk_type != SOCK_SEQPACKET) return NULL; - if ((sk = sk_alloc(PF_ROSE, GFP_ATOMIC, &rose_proto, 1)) == NULL) + if ((sk = sk_alloc(osk->sk_net, PF_ROSE, GFP_ATOMIC, &rose_proto, 1)) == NULL) return NULL; rose = rose_sk(sk); diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c index 122d55d992e..0803f305ed0 100644 --- a/net/rxrpc/af_rxrpc.c +++ b/net/rxrpc/af_rxrpc.c @@ -606,13 +606,16 @@ static unsigned int rxrpc_poll(struct file *file, struct socket *sock, /* * create an RxRPC socket */ -static int rxrpc_create(struct socket *sock, int protocol) +static int rxrpc_create(struct net *net, struct socket *sock, int protocol) { struct rxrpc_sock *rx; struct sock *sk; _enter("%p,%d", sock, protocol); + if (net != &init_net) + return -EAFNOSUPPORT; + /* we support transport protocol UDP only */ if (protocol != PF_INET) return -EPROTONOSUPPORT; @@ -623,7 +626,7 @@ static int rxrpc_create(struct socket *sock, int protocol) sock->ops = &rxrpc_rpc_ops; sock->state = SS_UNCONNECTED; - sk = sk_alloc(PF_RXRPC, GFP_KERNEL, &rxrpc_proto, 1); + sk = sk_alloc(net, PF_RXRPC, GFP_KERNEL, &rxrpc_proto, 1); if (!sk) return -ENOMEM; diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index ec29b97dbab..ddeb4882ec7 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -631,7 +631,7 @@ static struct sock *sctp_v6_create_accept_sk(struct sock *sk, struct ipv6_pinfo *newnp, *np = inet6_sk(sk); struct sctp6_sock *newsctp6sk; - newsk = sk_alloc(PF_INET6, GFP_KERNEL, sk->sk_prot, 1); + newsk = sk_alloc(sk->sk_net, PF_INET6, GFP_KERNEL, sk->sk_prot, 1); if (!newsk) goto out; diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 30929e3ca05..af67c839ef9 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -552,7 +552,7 @@ static struct sock *sctp_v4_create_accept_sk(struct sock *sk, { struct inet_sock *inet = inet_sk(sk); struct inet_sock *newinet; - struct sock *newsk = sk_alloc(PF_INET, GFP_KERNEL, sk->sk_prot, 1); + struct sock *newsk = sk_alloc(sk->sk_net, PF_INET, GFP_KERNEL, sk->sk_prot, 1); if (!newsk) goto out; diff --git a/net/socket.c b/net/socket.c index b09eb9036a1..a714c6d4e4a 100644 --- a/net/socket.c +++ b/net/socket.c @@ -84,6 +84,7 @@ #include #include #include +#include #include #include @@ -1071,7 +1072,7 @@ call_kill: return 0; } -static int __sock_create(int family, int type, int protocol, +static int __sock_create(struct net *net, int family, int type, int protocol, struct socket **res, int kern) { int err; @@ -1147,7 +1148,7 @@ static int __sock_create(int family, int type, int protocol, /* Now protected by module ref count */ rcu_read_unlock(); - err = pf->create(sock, protocol); + err = pf->create(net, sock, protocol); if (err < 0) goto out_module_put; @@ -1186,12 +1187,12 @@ out_release: int sock_create(int family, int type, int protocol, struct socket **res) { - return __sock_create(family, type, protocol, res, 0); + return __sock_create(current->nsproxy->net_ns, family, type, protocol, res, 0); } int sock_create_kern(int family, int type, int protocol, struct socket **res) { - return __sock_create(family, type, protocol, res, 1); + return __sock_create(&init_net, family, type, protocol, res, 1); } asmlinkage long sys_socket(int family, int type, int protocol) diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 84110172031..e36b4b5a522 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -162,13 +162,16 @@ static void advance_queue(struct tipc_sock *tsock) * * Returns 0 on success, errno otherwise */ -static int tipc_create(struct socket *sock, int protocol) +static int tipc_create(struct net *net, struct socket *sock, int protocol) { struct tipc_sock *tsock; struct tipc_port *port; struct sock *sk; u32 ref; + if (net != &init_net) + return -EAFNOSUPPORT; + if (unlikely(protocol != 0)) return -EPROTONOSUPPORT; @@ -198,7 +201,7 @@ static int tipc_create(struct socket *sock, int protocol) return -EPROTOTYPE; } - sk = sk_alloc(AF_TIPC, GFP_KERNEL, &tipc_proto, 1); + sk = sk_alloc(net, AF_TIPC, GFP_KERNEL, &tipc_proto, 1); if (!sk) { tipc_deleteport(ref); return -ENOMEM; @@ -1372,7 +1375,7 @@ static int accept(struct socket *sock, struct socket *newsock, int flags) } buf = skb_peek(&sock->sk->sk_receive_queue); - res = tipc_create(newsock, 0); + res = tipc_create(sock->sk->sk_net, newsock, 0); if (!res) { struct tipc_sock *new_tsock = tipc_sk(newsock->sk); struct tipc_portid id; diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 2386090c3a1..10e73122c34 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -594,7 +594,7 @@ static struct proto unix_proto = { */ static struct lock_class_key af_unix_sk_receive_queue_lock_key; -static struct sock * unix_create1(struct socket *sock) +static struct sock * unix_create1(struct net *net, struct socket *sock) { struct sock *sk = NULL; struct unix_sock *u; @@ -602,7 +602,7 @@ static struct sock * unix_create1(struct socket *sock) if (atomic_read(&unix_nr_socks) >= 2*get_max_files()) goto out; - sk = sk_alloc(PF_UNIX, GFP_KERNEL, &unix_proto, 1); + sk = sk_alloc(net, PF_UNIX, GFP_KERNEL, &unix_proto, 1); if (!sk) goto out; @@ -628,8 +628,11 @@ out: return sk; } -static int unix_create(struct socket *sock, int protocol) +static int unix_create(struct net *net, struct socket *sock, int protocol) { + if (net != &init_net) + return -EAFNOSUPPORT; + if (protocol && protocol != PF_UNIX) return -EPROTONOSUPPORT; @@ -655,7 +658,7 @@ static int unix_create(struct socket *sock, int protocol) return -ESOCKTNOSUPPORT; } - return unix_create1(sock) ? 0 : -ENOMEM; + return unix_create1(net, sock) ? 0 : -ENOMEM; } static int unix_release(struct socket *sock) @@ -1039,7 +1042,7 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr, err = -ENOMEM; /* create new sock for complete connection */ - newsk = unix_create1(NULL); + newsk = unix_create1(sk->sk_net, NULL); if (newsk == NULL) goto out; diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index 479927cb45c..2e9931571a4 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -466,10 +466,10 @@ static struct proto x25_proto = { .obj_size = sizeof(struct x25_sock), }; -static struct sock *x25_alloc_socket(void) +static struct sock *x25_alloc_socket(struct net *net) { struct x25_sock *x25; - struct sock *sk = sk_alloc(AF_X25, GFP_ATOMIC, &x25_proto, 1); + struct sock *sk = sk_alloc(net, AF_X25, GFP_ATOMIC, &x25_proto, 1); if (!sk) goto out; @@ -485,17 +485,20 @@ out: return sk; } -static int x25_create(struct socket *sock, int protocol) +static int x25_create(struct net *net, struct socket *sock, int protocol) { struct sock *sk; struct x25_sock *x25; int rc = -ESOCKTNOSUPPORT; + if (net != &init_net) + return -EAFNOSUPPORT; + if (sock->type != SOCK_SEQPACKET || protocol) goto out; rc = -ENOMEM; - if ((sk = x25_alloc_socket()) == NULL) + if ((sk = x25_alloc_socket(net)) == NULL) goto out; x25 = x25_sk(sk); @@ -543,7 +546,7 @@ static struct sock *x25_make_new(struct sock *osk) if (osk->sk_type != SOCK_SEQPACKET) goto out; - if ((sk = x25_alloc_socket()) == NULL) + if ((sk = x25_alloc_socket(osk->sk_net)) == NULL) goto out; x25 = x25_sk(sk); -- cgit v1.2.3-70-g09d2 From e730c15519d09ea528b4d2f1103681fa5937c0e6 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 17 Sep 2007 11:53:39 -0700 Subject: [NET]: Make packet reception network namespace safe This patch modifies every packet receive function registered with dev_add_pack() to drop packets if they are not from the initial network namespace. This should ensure that the various network stacks do not receive packets in a anything but the initial network namespace until the code has been converted and is ready for them. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- drivers/block/aoe/aoenet.c | 4 ++++ drivers/net/bonding/bond_3ad.c | 4 ++++ drivers/net/bonding/bond_alb.c | 3 +++ drivers/net/bonding/bond_main.c | 3 +++ drivers/net/hamradio/bpqether.c | 3 +++ drivers/net/pppoe.c | 6 ++++++ drivers/net/wan/hdlc.c | 7 +++++++ drivers/net/wan/lapbether.c | 3 +++ drivers/net/wan/syncppp.c | 6 ++++++ net/8021q/vlan_dev.c | 5 +++++ net/appletalk/aarp.c | 3 +++ net/appletalk/ddp.c | 6 ++++++ net/ax25/ax25_in.c | 5 +++++ net/bridge/br_stp_bpdu.c | 4 ++++ net/decnet/dn_route.c | 3 +++ net/econet/af_econet.c | 3 +++ net/ipv4/arp.c | 3 +++ net/ipv4/ip_input.c | 3 +++ net/ipv4/ipconfig.c | 6 ++++++ net/ipv6/ip6_input.c | 5 +++++ net/ipx/af_ipx.c | 3 +++ net/irda/irlap_frame.c | 3 +++ net/llc/llc_input.c | 4 ++++ net/packet/af_packet.c | 9 +++++++++ net/tipc/eth_media.c | 6 ++++++ net/x25/x25_dev.c | 3 +++ 26 files changed, 113 insertions(+) (limited to 'drivers') diff --git a/drivers/block/aoe/aoenet.c b/drivers/block/aoe/aoenet.c index f9ddfda4d9c..4dc0fb7da94 100644 --- a/drivers/block/aoe/aoenet.c +++ b/drivers/block/aoe/aoenet.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include "aoe.h" @@ -114,6 +115,9 @@ aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt, struct aoe_hdr *h; u32 n; + if (ifp->nd_net != &init_net) + goto exit; + skb = skb_share_check(skb, GFP_ATOMIC); if (skb == NULL) return 0; diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index f829e4ad8b4..94bd7394145 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "bonding.h" #include "bond_3ad.h" @@ -2448,6 +2449,9 @@ int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct pac struct slave *slave = NULL; int ret = NET_RX_DROP; + if (dev->nd_net != &init_net) + goto out; + if (!(dev->flags & IFF_MASTER)) goto out; diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index 92c3b6f6a8e..419a9f8fdd5 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -345,6 +345,9 @@ static int rlb_arp_recv(struct sk_buff *skb, struct net_device *bond_dev, struct struct arp_pkt *arp = (struct arp_pkt *)skb->data; int res = NET_RX_DROP; + if (bond_dev->nd_net != &init_net) + goto out; + if (!(bond_dev->flags & IFF_MASTER)) goto out; diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 5de648f90a4..e4e5fdc0430 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -2458,6 +2458,9 @@ static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct pack unsigned char *arp_ptr; u32 sip, tip; + if (dev->nd_net != &init_net) + goto out; + if (!(dev->priv_flags & IFF_BONDING) || !(dev->flags & IFF_MASTER)) goto out; diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index 1699d42d13c..85fb8e7efac 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -173,6 +173,9 @@ static int bpq_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_ty struct ethhdr *eth; struct bpqdev *bpq; + if (dev->nd_net != &init_net) + goto drop; + if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) return NET_RX_DROP; diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index 53fcee26d6a..60c0e4e1787 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -389,6 +389,9 @@ static int pppoe_rcv(struct sk_buff *skb, if (!(skb = skb_share_check(skb, GFP_ATOMIC))) goto out; + if (dev->nd_net != &init_net) + goto drop; + if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr))) goto drop; @@ -418,6 +421,9 @@ static int pppoe_disc_rcv(struct sk_buff *skb, struct pppoe_hdr *ph; struct pppox_sock *po; + if (dev->nd_net != &init_net) + goto abort; + if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr))) goto abort; diff --git a/drivers/net/wan/hdlc.c b/drivers/net/wan/hdlc.c index 65ad2e24caf..3b57350eacc 100644 --- a/drivers/net/wan/hdlc.c +++ b/drivers/net/wan/hdlc.c @@ -36,6 +36,7 @@ #include #include #include +#include static const char* version = "HDLC support module revision 1.21"; @@ -66,6 +67,12 @@ static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *p, struct net_device *orig_dev) { struct hdlc_device_desc *desc = dev_to_desc(dev); + + if (dev->nd_net != &init_net) { + kfree_skb(skb); + return 0; + } + if (desc->netif_rx) return desc->netif_rx(skb); diff --git a/drivers/net/wan/lapbether.c b/drivers/net/wan/lapbether.c index 6c302e9dbca..ca8b3c3cb93 100644 --- a/drivers/net/wan/lapbether.c +++ b/drivers/net/wan/lapbether.c @@ -91,6 +91,9 @@ static int lapbeth_rcv(struct sk_buff *skb, struct net_device *dev, struct packe int len, err; struct lapbethdev *lapbeth; + if (dev->nd_net != &init_net) + goto drop; + if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) return NET_RX_DROP; diff --git a/drivers/net/wan/syncppp.c b/drivers/net/wan/syncppp.c index 67fc67cfd45..5c71af6ea3a 100644 --- a/drivers/net/wan/syncppp.c +++ b/drivers/net/wan/syncppp.c @@ -51,6 +51,7 @@ #include #include +#include #include #include @@ -1445,6 +1446,11 @@ static void sppp_print_bytes (u_char *p, u16 len) static int sppp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *p, struct net_device *orig_dev) { + if (dev->nd_net != &init_net) { + kfree_skb(skb); + return 0; + } + if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) return NET_RX_DROP; sppp_input(dev,skb); diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 328759c32d6..6644e8f5f19 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -122,6 +122,11 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev, unsigned short vlan_TCI; __be16 proto; + if (dev->nd_net != &init_net) { + kfree_skb(skb); + return -1; + } + if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) return -1; diff --git a/net/appletalk/aarp.c b/net/appletalk/aarp.c index 80b54148460..9267f481879 100644 --- a/net/appletalk/aarp.c +++ b/net/appletalk/aarp.c @@ -713,6 +713,9 @@ static int aarp_rcv(struct sk_buff *skb, struct net_device *dev, struct atalk_addr sa, *ma, da; struct atalk_iface *ifa; + if (dev->nd_net != &init_net) + goto out0; + /* We only do Ethernet SNAP AARP. */ if (dev->type != ARPHRD_ETHER) goto out0; diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index fd1d52f0970..c1f1367cad4 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -1403,6 +1403,9 @@ static int atalk_rcv(struct sk_buff *skb, struct net_device *dev, int origlen; __u16 len_hops; + if (dev->nd_net != &init_net) + goto freeit; + /* Don't mangle buffer if shared */ if (!(skb = skb_share_check(skb, GFP_ATOMIC))) goto out; @@ -1488,6 +1491,9 @@ freeit: static int ltalk_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) { + if (dev->nd_net != &init_net) + goto freeit; + /* Expand any short form frames */ if (skb_mac_header(skb)[2] == 1) { struct ddpehdr *ddp; diff --git a/net/ax25/ax25_in.c b/net/ax25/ax25_in.c index 0ddaff0df21..3b7d1720c2e 100644 --- a/net/ax25/ax25_in.c +++ b/net/ax25/ax25_in.c @@ -451,6 +451,11 @@ int ax25_kiss_rcv(struct sk_buff *skb, struct net_device *dev, skb->sk = NULL; /* Initially we don't know who it's for */ skb->destructor = NULL; /* Who initializes this, dammit?! */ + if (dev->nd_net != &init_net) { + kfree_skb(skb); + return 0; + } + if ((*skb->data & 0x0F) != 0) { kfree_skb(skb); /* Not a KISS data frame */ return 0; diff --git a/net/bridge/br_stp_bpdu.c b/net/bridge/br_stp_bpdu.c index 14f0c888eec..0edbd2a1c3f 100644 --- a/net/bridge/br_stp_bpdu.c +++ b/net/bridge/br_stp_bpdu.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -141,6 +142,9 @@ int br_stp_rcv(struct sk_buff *skb, struct net_device *dev, struct net_bridge *br; const unsigned char *buf; + if (dev->nd_net != &init_net) + goto err; + if (!p) goto err; diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index 4cfea9563d2..580e786d0c3 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -584,6 +584,9 @@ int dn_route_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type struct dn_dev *dn = (struct dn_dev *)dev->dn_ptr; unsigned char padlen = 0; + if (dev->nd_net != &init_net) + goto dump_it; + if (dn == NULL) goto dump_it; diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c index a2429dbcb86..7de3006af20 100644 --- a/net/econet/af_econet.c +++ b/net/econet/af_econet.c @@ -1065,6 +1065,9 @@ static int econet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet struct sock *sk; struct ec_device *edev = dev->ec_ptr; + if (dev->nd_net != &init_net) + goto drop; + if (skb->pkt_type == PACKET_OTHERHOST) goto drop; diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 78dd3443016..bde129708e2 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -932,6 +932,9 @@ static int arp_rcv(struct sk_buff *skb, struct net_device *dev, { struct arphdr *arp; + if (dev->nd_net != &init_net) + goto freeskb; + /* ARP header, plus 2 device addresses, plus 2 IP addresses. */ if (!pskb_may_pull(skb, (sizeof(struct arphdr) + (2 * dev->addr_len) + diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index 97069399d86..41d8964591e 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -382,6 +382,9 @@ int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct iphdr *iph; u32 len; + if (dev->nd_net != &init_net) + goto drop; + /* When the interface is in promisc. mode, drop all the crap * that it receives, do not try to analyse it. */ diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index 5ae4849878a..08ff623371f 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -426,6 +426,9 @@ ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt unsigned char *sha, *tha; /* s for "source", t for "target" */ struct ic_device *d; + if (dev->nd_net != &init_net) + goto drop; + if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) return NET_RX_DROP; @@ -835,6 +838,9 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str struct ic_device *d; int len, ext_len; + if (dev->nd_net != &init_net) + goto drop; + /* Perform verifications before taking the lock. */ if (skb->pkt_type == PACKET_OTHERHOST) goto drop; diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index 30a5cb1b203..7d18cac3f11 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c @@ -61,6 +61,11 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt u32 pkt_len; struct inet6_dev *idev; + if (dev->nd_net != &init_net) { + kfree_skb(skb); + return 0; + } + if (skb->pkt_type == PACKET_OTHERHOST) { kfree_skb(skb); return 0; diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c index ee28babad22..f7b4d383c60 100644 --- a/net/ipx/af_ipx.c +++ b/net/ipx/af_ipx.c @@ -1647,6 +1647,9 @@ static int ipx_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_ty u16 ipx_pktsize; int rc = 0; + if (dev->nd_net != &init_net) + goto drop; + /* Not ours */ if (skb->pkt_type == PACKET_OTHERHOST) goto drop; diff --git a/net/irda/irlap_frame.c b/net/irda/irlap_frame.c index 25a3444a923..77ac27e8116 100644 --- a/net/irda/irlap_frame.c +++ b/net/irda/irlap_frame.c @@ -1326,6 +1326,9 @@ int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev, int command; __u8 control; + if (dev->nd_net != &init_net) + goto out; + /* FIXME: should we get our own field? */ self = (struct irlap_cb *) dev->atalk_ptr; diff --git a/net/llc/llc_input.c b/net/llc/llc_input.c index 099ed8fec14..c40c9b2a345 100644 --- a/net/llc/llc_input.c +++ b/net/llc/llc_input.c @@ -12,6 +12,7 @@ * See the GNU General Public License for more details. */ #include +#include #include #include #include @@ -145,6 +146,9 @@ int llc_rcv(struct sk_buff *skb, struct net_device *dev, int (*rcv)(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *); + if (dev->nd_net != &init_net) + goto drop; + /* * When the interface is in promisc. mode, drop all the crap that it * receives, do not try to analyse it. diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 766b5faaed2..cae1ee4f2ad 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -252,6 +252,9 @@ static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev, struct struct sock *sk; struct sockaddr_pkt *spkt; + if (dev->nd_net != &init_net) + goto out; + /* * When we registered the protocol we saved the socket in the data * field for just this event. @@ -452,6 +455,9 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet int skb_len = skb->len; unsigned int snaplen, res; + if (dev->nd_net != &init_net) + goto drop; + if (skb->pkt_type == PACKET_LOOPBACK) goto drop; @@ -568,6 +574,9 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe struct sk_buff *copy_skb = NULL; struct timeval tv; + if (dev->nd_net != &init_net) + goto drop; + if (skb->pkt_type == PACKET_LOOPBACK) goto drop; diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c index 711ca4b1f05..d2ed2370418 100644 --- a/net/tipc/eth_media.c +++ b/net/tipc/eth_media.c @@ -38,6 +38,7 @@ #include #include #include +#include #define MAX_ETH_BEARERS 2 #define ETH_LINK_PRIORITY TIPC_DEF_LINK_PRI @@ -100,6 +101,11 @@ static int recv_msg(struct sk_buff *buf, struct net_device *dev, struct eth_bearer *eb_ptr = (struct eth_bearer *)pt->af_packet_priv; u32 size; + if (dev->nd_net != &init_net) { + kfree_skb(buf); + return 0; + } + if (likely(eb_ptr->bearer)) { if (likely(buf->pkt_type <= PACKET_BROADCAST)) { size = msg_size((struct tipc_msg *)buf->data); diff --git a/net/x25/x25_dev.c b/net/x25/x25_dev.c index 848a6b6f90a..f0679d28311 100644 --- a/net/x25/x25_dev.c +++ b/net/x25/x25_dev.c @@ -95,6 +95,9 @@ int x25_lapb_receive_frame(struct sk_buff *skb, struct net_device *dev, struct sk_buff *nskb; struct x25_neigh *nb; + if (dev->nd_net != &init_net) + goto drop; + nskb = skb_copy(skb, GFP_ATOMIC); if (!nskb) goto drop; -- cgit v1.2.3-70-g09d2 From e9dc86534051b78e41e5b746cccc291b57a3a311 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 12 Sep 2007 13:02:17 +0200 Subject: [NET]: Make device event notification network namespace safe Every user of the network device notifiers is either a protocol stack or a pseudo device. If a protocol stack that does not have support for multiple network namespaces receives an event for a device that is not in the initial network namespace it quite possibly can get confused and do the wrong thing. To avoid problems until all of the protocol stacks are converted this patch modifies all netdev event handlers to ignore events on devices that are not in the initial network namespace. As the rest of the code is made network namespace aware these checks can be removed. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- arch/ia64/hp/sim/simeth.c | 3 +++ drivers/net/bonding/bond_main.c | 3 +++ drivers/net/hamradio/bpqether.c | 3 +++ drivers/net/pppoe.c | 3 +++ drivers/net/wan/dlci.c | 3 +++ drivers/net/wan/hdlc.c | 3 +++ drivers/net/wan/lapbether.c | 3 +++ net/8021q/vlan.c | 4 ++++ net/appletalk/aarp.c | 3 +++ net/appletalk/ddp.c | 3 +++ net/atm/clip.c | 3 +++ net/atm/mpc.c | 4 ++++ net/ax25/af_ax25.c | 3 +++ net/bridge/br_notify.c | 4 ++++ net/core/dst.c | 4 ++++ net/core/fib_rules.c | 4 ++++ net/core/pktgen.c | 3 +++ net/core/rtnetlink.c | 4 ++++ net/decnet/af_decnet.c | 3 +++ net/econet/af_econet.c | 3 +++ net/ipv4/arp.c | 3 +++ net/ipv4/devinet.c | 3 +++ net/ipv4/fib_frontend.c | 3 +++ net/ipv4/ipmr.c | 7 ++++++- net/ipv4/netfilter/ip_queue.c | 3 +++ net/ipv4/netfilter/ipt_MASQUERADE.c | 3 +++ net/ipv6/addrconf.c | 3 +++ net/ipv6/ndisc.c | 3 +++ net/ipv6/netfilter/ip6_queue.c | 3 +++ net/ipx/af_ipx.c | 3 +++ net/netfilter/nfnetlink_queue.c | 3 +++ net/netrom/af_netrom.c | 3 +++ net/packet/af_packet.c | 3 +++ net/rose/af_rose.c | 3 +++ net/tipc/eth_media.c | 3 +++ net/x25/af_x25.c | 3 +++ net/xfrm/xfrm_policy.c | 5 +++++ security/selinux/netif.c | 4 ++++ 38 files changed, 126 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/arch/ia64/hp/sim/simeth.c b/arch/ia64/hp/sim/simeth.c index 4017696ada6..08b117e2c54 100644 --- a/arch/ia64/hp/sim/simeth.c +++ b/arch/ia64/hp/sim/simeth.c @@ -294,6 +294,9 @@ simeth_device_event(struct notifier_block *this,unsigned long event, void *ptr) return NOTIFY_DONE; } + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + if ( event != NETDEV_UP && event != NETDEV_DOWN ) return NOTIFY_DONE; /* diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index e4e5fdc0430..cf97d8a6326 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -3299,6 +3299,9 @@ static int bond_netdev_event(struct notifier_block *this, unsigned long event, v { struct net_device *event_dev = (struct net_device *)ptr; + if (event_dev->nd_net != &init_net) + return NOTIFY_DONE; + dprintk("event_dev: %s, event: %lx\n", (event_dev ? event_dev->name : "None"), event); diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index 85fb8e7efac..df09210f735 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -563,6 +563,9 @@ static int bpq_device_event(struct notifier_block *this,unsigned long event, voi { struct net_device *dev = (struct net_device *)ptr; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + if (!dev_is_ethdev(dev)) return NOTIFY_DONE; diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index 60c0e4e1787..c5c70e4b1d3 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -301,6 +301,9 @@ static int pppoe_device_event(struct notifier_block *this, { struct net_device *dev = (struct net_device *) ptr; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + /* Only look at sockets that are using this specific device. */ switch (event) { case NETDEV_CHANGEMTU: diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c index 66be20c292b..61041d5186a 100644 --- a/drivers/net/wan/dlci.c +++ b/drivers/net/wan/dlci.c @@ -513,6 +513,9 @@ static int dlci_dev_event(struct notifier_block *unused, { struct net_device *dev = (struct net_device *) ptr; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + if (event == NETDEV_UNREGISTER) { struct dlci_local *dlp; diff --git a/drivers/net/wan/hdlc.c b/drivers/net/wan/hdlc.c index 3b57350eacc..ee23b91f23d 100644 --- a/drivers/net/wan/hdlc.c +++ b/drivers/net/wan/hdlc.c @@ -109,6 +109,9 @@ static int hdlc_device_event(struct notifier_block *this, unsigned long event, unsigned long flags; int on; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + if (dev->get_stats != hdlc_get_stats) return NOTIFY_DONE; /* not an HDLC device */ diff --git a/drivers/net/wan/lapbether.c b/drivers/net/wan/lapbether.c index ca8b3c3cb93..699b93406df 100644 --- a/drivers/net/wan/lapbether.c +++ b/drivers/net/wan/lapbether.c @@ -394,6 +394,9 @@ static int lapbeth_device_event(struct notifier_block *this, struct lapbethdev *lapbeth; struct net_device *dev = ptr; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + if (!dev_is_ethdev(dev)) return NOTIFY_DONE; diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 2a546919d6f..d0d36fdedbe 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include "vlan.h" @@ -603,6 +604,9 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, int i, flgs; struct net_device *vlandev; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + if (!grp) goto out; diff --git a/net/appletalk/aarp.c b/net/appletalk/aarp.c index 9267f481879..e9a51a69870 100644 --- a/net/appletalk/aarp.c +++ b/net/appletalk/aarp.c @@ -333,6 +333,9 @@ static int aarp_device_event(struct notifier_block *this, unsigned long event, struct net_device *dev = ptr; int ct; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + if (event == NETDEV_DOWN) { write_lock_bh(&aarp_lock); diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index c1f1367cad4..36fcdbf923c 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -649,6 +649,9 @@ static int ddp_device_event(struct notifier_block *this, unsigned long event, { struct net_device *dev = ptr; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + if (event == NETDEV_DOWN) /* Discard any use of this */ atalk_dev_down(dev); diff --git a/net/atm/clip.c b/net/atm/clip.c index 806ea98567c..741742f0079 100644 --- a/net/atm/clip.c +++ b/net/atm/clip.c @@ -612,6 +612,9 @@ static int clip_device_event(struct notifier_block *this, unsigned long event, { struct net_device *dev = arg; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + if (event == NETDEV_UNREGISTER) { neigh_ifdown(&clip_tbl, dev); return NOTIFY_DONE; diff --git a/net/atm/mpc.c b/net/atm/mpc.c index 7c85aa551d5..0968430a7f5 100644 --- a/net/atm/mpc.c +++ b/net/atm/mpc.c @@ -956,6 +956,10 @@ static int mpoa_event_listener(struct notifier_block *mpoa_notifier, unsigned lo struct lec_priv *priv; dev = (struct net_device *)dev_ptr; + + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + if (dev->name == NULL || strncmp(dev->name, "lec", 3)) return NOTIFY_DONE; /* we are only interested in lec:s */ diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index def6c42ad16..8d13a8bca0e 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -104,6 +104,9 @@ static int ax25_device_event(struct notifier_block *this, unsigned long event, { struct net_device *dev = (struct net_device *)ptr; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + /* Reject non AX.25 devices */ if (dev->type != ARPHRD_AX25) return NOTIFY_DONE; diff --git a/net/bridge/br_notify.c b/net/bridge/br_notify.c index c8451d3a070..07ac3ae68d8 100644 --- a/net/bridge/br_notify.c +++ b/net/bridge/br_notify.c @@ -15,6 +15,7 @@ #include #include +#include #include "br_private.h" @@ -36,6 +37,9 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v struct net_bridge_port *p = dev->br_port; struct net_bridge *br; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + /* not a port of a bridge */ if (p == NULL) return NOTIFY_DONE; diff --git a/net/core/dst.c b/net/core/dst.c index c6a05879d58..32267a16e01 100644 --- a/net/core/dst.c +++ b/net/core/dst.c @@ -15,6 +15,7 @@ #include #include #include +#include #include @@ -252,6 +253,9 @@ static int dst_dev_event(struct notifier_block *this, unsigned long event, void struct net_device *dev = ptr; struct dst_entry *dst; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + switch (event) { case NETDEV_UNREGISTER: case NETDEV_DOWN: diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index 8c5474e1668..9eabe1ae01d 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c @@ -11,6 +11,7 @@ #include #include #include +#include #include static LIST_HEAD(rules_ops); @@ -596,6 +597,9 @@ static int fib_rules_event(struct notifier_block *this, unsigned long event, struct net_device *dev = ptr; struct fib_rules_ops *ops; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + ASSERT_RTNL(); rcu_read_lock(); diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 33d7247fb19..d7c30ce095a 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -1975,6 +1975,9 @@ static int pktgen_device_event(struct notifier_block *unused, { struct net_device *dev = ptr; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + /* It is OK that we do not hold the group lock right now, * as we run under the RTNL lock. */ diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index dca9e80ba57..41859508bed 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1286,6 +1286,10 @@ static void rtnetlink_rcv(struct sock *sk, int len) static int rtnetlink_event(struct notifier_block *this, unsigned long event, void *ptr) { struct net_device *dev = ptr; + + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + switch (event) { case NETDEV_UNREGISTER: rtmsg_ifinfo(RTM_DELLINK, dev, ~0U); diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c index aca4c4930eb..83398da5d76 100644 --- a/net/decnet/af_decnet.c +++ b/net/decnet/af_decnet.c @@ -2089,6 +2089,9 @@ static int dn_device_event(struct notifier_block *this, unsigned long event, { struct net_device *dev = (struct net_device *)ptr; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + switch(event) { case NETDEV_UP: dn_dev_up(dev); diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c index 7de3006af20..f877f3b5c72 100644 --- a/net/econet/af_econet.c +++ b/net/econet/af_econet.c @@ -1122,6 +1122,9 @@ static int econet_notifier(struct notifier_block *this, unsigned long msg, void struct net_device *dev = (struct net_device *)data; struct ec_device *edev; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + switch (msg) { case NETDEV_UNREGISTER: /* A device has gone down - kill any data we hold for it. */ diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index bde129708e2..a11e7a5c1da 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -1205,6 +1205,9 @@ static int arp_netdev_event(struct notifier_block *this, unsigned long event, vo { struct net_device *dev = ptr; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + switch (event) { case NETDEV_CHANGEADDR: neigh_changeaddr(&arp_tbl, dev); diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 5dbe5803b7d..c5eb1a29a5c 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1051,6 +1051,9 @@ static int inetdev_event(struct notifier_block *this, unsigned long event, struct net_device *dev = ptr; struct in_device *in_dev = __in_dev_get_rtnl(dev); + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + ASSERT_RTNL(); if (!in_dev) { diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index eff6bce453e..cefb55ec3d6 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -860,6 +860,9 @@ static int fib_netdev_event(struct notifier_block *this, unsigned long event, vo struct net_device *dev = ptr; struct in_device *in_dev = __in_dev_get_rtnl(dev); + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + if (event == NETDEV_UNREGISTER) { fib_disable_ip(dev, 2); return NOTIFY_DONE; diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 35683e1a42e..036598835c6 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -1083,13 +1083,18 @@ int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg) static int ipmr_device_event(struct notifier_block *this, unsigned long event, void *ptr) { + struct net_device *dev = ptr; struct vif_device *v; int ct; + + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + if (event != NETDEV_UNREGISTER) return NOTIFY_DONE; v=&vif_table[0]; for (ct=0;ctdev==ptr) + if (v->dev==dev) vif_delete(ct); } return NOTIFY_DONE; diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index cb5e61a1d7a..d91856097f2 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c @@ -557,6 +557,9 @@ ipq_rcv_dev_event(struct notifier_block *this, { struct net_device *dev = ptr; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + /* Drop any packets associated with the downed device */ if (event == NETDEV_DOWN) ipq_dev_drop(dev->ifindex); diff --git a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c index 7c4e4be7c8b..3e0b562b2db 100644 --- a/net/ipv4/netfilter/ipt_MASQUERADE.c +++ b/net/ipv4/netfilter/ipt_MASQUERADE.c @@ -125,6 +125,9 @@ static int masq_device_event(struct notifier_block *this, { const struct net_device *dev = ptr; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + if (event == NETDEV_DOWN) { /* Device was downed. Search entire table for conntracks which were associated with that device, diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index cd2db728d18..1a678364652 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -2259,6 +2259,9 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, int run_pending = 0; int err; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + switch(event) { case NETDEV_REGISTER: if (!idev && dev->mtu >= IPV6_MIN_MTU) { diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 5b596659177..d2d44dc22f1 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1525,6 +1525,9 @@ static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, { struct net_device *dev = ptr; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + switch (event) { case NETDEV_CHANGEADDR: neigh_changeaddr(&nd_tbl, dev); diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index dfc58fbdb68..64536a3ef2f 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c @@ -547,6 +547,9 @@ ipq_rcv_dev_event(struct notifier_block *this, { struct net_device *dev = ptr; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + /* Drop any packets associated with the downed device */ if (event == NETDEV_DOWN) ipq_dev_drop(dev->ifindex); diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c index f7b4d383c60..24921f12e9a 100644 --- a/net/ipx/af_ipx.c +++ b/net/ipx/af_ipx.c @@ -347,6 +347,9 @@ static int ipxitf_device_event(struct notifier_block *notifier, struct net_device *dev = ptr; struct ipx_interface *i, *tmp; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + if (event != NETDEV_DOWN && event != NETDEV_UP) goto out; diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index bb65a38c816..5a8e8ff7664 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -734,6 +734,9 @@ nfqnl_rcv_dev_event(struct notifier_block *this, { struct net_device *dev = ptr; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + /* Drop any packets associated with the downed device */ if (event == NETDEV_DOWN) nfqnl_dev_drop(dev->ifindex); diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index e969d1bc765..3a4d479ea64 100644 --- a/net/netrom/af_netrom.c +++ b/net/netrom/af_netrom.c @@ -106,6 +106,9 @@ static int nr_device_event(struct notifier_block *this, unsigned long event, voi { struct net_device *dev = (struct net_device *)ptr; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + if (event != NETDEV_DOWN) return NOTIFY_DONE; diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index cae1ee4f2ad..ad0052524e8 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -1477,6 +1477,9 @@ static int packet_notifier(struct notifier_block *this, unsigned long msg, void struct hlist_node *node; struct net_device *dev = data; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + read_lock(&packet_sklist_lock); sk_for_each(sk, node, &packet_sklist) { struct packet_sock *po = pkt_sk(sk); diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index 67e06ab7f85..509defe53ee 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c @@ -197,6 +197,9 @@ static int rose_device_event(struct notifier_block *this, unsigned long event, { struct net_device *dev = (struct net_device *)ptr; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + if (event != NETDEV_DOWN) return NOTIFY_DONE; diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c index d2ed2370418..406f0d26fa8 100644 --- a/net/tipc/eth_media.c +++ b/net/tipc/eth_media.c @@ -198,6 +198,9 @@ static int recv_notification(struct notifier_block *nb, unsigned long evt, struct eth_bearer *eb_ptr = ð_bearers[0]; struct eth_bearer *stop = ð_bearers[MAX_ETH_BEARERS]; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + while ((eb_ptr->dev != dev)) { if (++eb_ptr == stop) return NOTIFY_DONE; /* couldn't find device */ diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index 2e9931571a4..fc416f9606a 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -191,6 +191,9 @@ static int x25_device_event(struct notifier_block *this, unsigned long event, struct net_device *dev = ptr; struct x25_neigh *nb; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + if (dev->type == ARPHRD_X25 #if defined(CONFIG_LLC) || defined(CONFIG_LLC_MODULE) || dev->type == ARPHRD_ETHER diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 36dd31c40f4..50682d3cd7a 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -2236,6 +2236,11 @@ static void xfrm_policy_unlock_afinfo(struct xfrm_policy_afinfo *afinfo) static int xfrm_dev_event(struct notifier_block *this, unsigned long event, void *ptr) { + struct net_device *dev = ptr; + + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + switch (event) { case NETDEV_DOWN: xfrm_flush_bundles(); diff --git a/security/selinux/netif.c b/security/selinux/netif.c index b10c34e8a74..e87ab948104 100644 --- a/security/selinux/netif.c +++ b/security/selinux/netif.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "security.h" #include "objsec.h" @@ -234,6 +235,9 @@ static int sel_netif_netdev_notifier_handler(struct notifier_block *this, { struct net_device *dev = ptr; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + if (event == NETDEV_DOWN) sel_netif_kill(dev); -- cgit v1.2.3-70-g09d2 From b4b510290b056b86611757ce1175a230f1080f53 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 12 Sep 2007 13:05:38 +0200 Subject: [NET]: Support multiple network namespaces with netlink Each netlink socket will live in exactly one network namespace, this includes the controlling kernel sockets. This patch updates all of the existing netlink protocols to only support the initial network namespace. Request by clients in other namespaces will get -ECONREFUSED. As they would if the kernel did not have the support for that netlink protocol compiled in. As each netlink protocol is updated to be multiple network namespace safe it can register multiple kernel sockets to acquire a presence in the rest of the network namespaces. The implementation in af_netlink is a simple filter implementation at hash table insertion and hash table look up time. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- drivers/connector/connector.c | 2 +- drivers/scsi/scsi_netlink.c | 2 +- drivers/scsi/scsi_transport_iscsi.c | 2 +- fs/ecryptfs/netlink.c | 2 +- include/linux/netlink.h | 6 ++- kernel/audit.c | 4 +- lib/kobject_uevent.c | 5 +- net/bridge/netfilter/ebt_ulog.c | 5 +- net/core/rtnetlink.c | 4 +- net/decnet/netfilter/dn_rtmsg.c | 3 +- net/ipv4/fib_frontend.c | 4 +- net/ipv4/inet_diag.c | 4 +- net/ipv4/netfilter/ip_queue.c | 6 +-- net/ipv4/netfilter/ipt_ULOG.c | 3 +- net/ipv6/netfilter/ip6_queue.c | 6 +-- net/netfilter/nfnetlink.c | 2 +- net/netfilter/nfnetlink_log.c | 3 +- net/netfilter/nfnetlink_queue.c | 3 +- net/netlink/af_netlink.c | 104 +++++++++++++++++++++++++++--------- net/netlink/genetlink.c | 4 +- net/xfrm/xfrm_user.c | 2 +- security/selinux/netlink.c | 5 +- 22 files changed, 121 insertions(+), 60 deletions(-) (limited to 'drivers') diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c index a7b9e9bb3e8..569070997cc 100644 --- a/drivers/connector/connector.c +++ b/drivers/connector/connector.c @@ -446,7 +446,7 @@ static int __devinit cn_init(void) dev->id.idx = cn_idx; dev->id.val = cn_val; - dev->nls = netlink_kernel_create(NETLINK_CONNECTOR, + dev->nls = netlink_kernel_create(&init_net, NETLINK_CONNECTOR, CN_NETLINK_USERS + 0xf, dev->input, NULL, THIS_MODULE); if (!dev->nls) diff --git a/drivers/scsi/scsi_netlink.c b/drivers/scsi/scsi_netlink.c index 4bf9aa547c7..163acf6ad2d 100644 --- a/drivers/scsi/scsi_netlink.c +++ b/drivers/scsi/scsi_netlink.c @@ -167,7 +167,7 @@ scsi_netlink_init(void) return; } - scsi_nl_sock = netlink_kernel_create(NETLINK_SCSITRANSPORT, + scsi_nl_sock = netlink_kernel_create(&init_net, NETLINK_SCSITRANSPORT, SCSI_NL_GRP_CNT, scsi_nl_rcv, NULL, THIS_MODULE); if (!scsi_nl_sock) { diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 34c1860a259..4916f01230d 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -1523,7 +1523,7 @@ static __init int iscsi_transport_init(void) if (err) goto unregister_conn_class; - nls = netlink_kernel_create(NETLINK_ISCSI, 1, iscsi_if_rx, NULL, + nls = netlink_kernel_create(&init_net, NETLINK_ISCSI, 1, iscsi_if_rx, NULL, THIS_MODULE); if (!nls) { err = -ENOBUFS; diff --git a/fs/ecryptfs/netlink.c b/fs/ecryptfs/netlink.c index fe9186312d7..056519cd92b 100644 --- a/fs/ecryptfs/netlink.c +++ b/fs/ecryptfs/netlink.c @@ -227,7 +227,7 @@ int ecryptfs_init_netlink(void) { int rc; - ecryptfs_nl_sock = netlink_kernel_create(NETLINK_ECRYPTFS, 0, + ecryptfs_nl_sock = netlink_kernel_create(&init_net, NETLINK_ECRYPTFS, 0, ecryptfs_receive_nl_message, NULL, THIS_MODULE); if (!ecryptfs_nl_sock) { diff --git a/include/linux/netlink.h b/include/linux/netlink.h index 83d8239f0cc..d2843ae4a83 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -27,6 +27,8 @@ #define MAX_LINKS 32 +struct net; + struct sockaddr_nl { sa_family_t nl_family; /* AF_NETLINK */ @@ -157,7 +159,8 @@ struct netlink_skb_parms #define NETLINK_CREDS(skb) (&NETLINK_CB((skb)).creds) -extern struct sock *netlink_kernel_create(int unit, unsigned int groups, +extern struct sock *netlink_kernel_create(struct net *net, + int unit,unsigned int groups, void (*input)(struct sock *sk, int len), struct mutex *cb_mutex, struct module *module); @@ -206,6 +209,7 @@ struct netlink_callback struct netlink_notify { + struct net *net; int pid; int protocol; }; diff --git a/kernel/audit.c b/kernel/audit.c index eb0f9165b40..f3c390f6c0b 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -876,8 +876,8 @@ static int __init audit_init(void) printk(KERN_INFO "audit: initializing netlink socket (%s)\n", audit_default ? "enabled" : "disabled"); - audit_sock = netlink_kernel_create(NETLINK_AUDIT, 0, audit_receive, - NULL, THIS_MODULE); + audit_sock = netlink_kernel_create(&init_net, NETLINK_AUDIT, 0, + audit_receive, NULL, THIS_MODULE); if (!audit_sock) audit_panic("cannot initialize netlink socket"); else diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index df02814699d..e06a8dcec0f 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c @@ -280,9 +280,8 @@ EXPORT_SYMBOL_GPL(add_uevent_var); #if defined(CONFIG_NET) static int __init kobject_uevent_init(void) { - uevent_sock = netlink_kernel_create(NETLINK_KOBJECT_UEVENT, 1, NULL, - NULL, THIS_MODULE); - + uevent_sock = netlink_kernel_create(&init_net, NETLINK_KOBJECT_UEVENT, + 1, NULL, NULL, THIS_MODULE); if (!uevent_sock) { printk(KERN_ERR "kobject_uevent: unable to create netlink socket!\n"); diff --git a/net/bridge/netfilter/ebt_ulog.c b/net/bridge/netfilter/ebt_ulog.c index 204c968fa86..e7cfd30bac7 100644 --- a/net/bridge/netfilter/ebt_ulog.c +++ b/net/bridge/netfilter/ebt_ulog.c @@ -300,8 +300,9 @@ static int __init ebt_ulog_init(void) spin_lock_init(&ulog_buffers[i].lock); } - ebtulognl = netlink_kernel_create(NETLINK_NFLOG, EBT_ULOG_MAXNLGROUPS, - NULL, NULL, THIS_MODULE); + ebtulognl = netlink_kernel_create(&init_net, NETLINK_NFLOG, + EBT_ULOG_MAXNLGROUPS, NULL, NULL, + THIS_MODULE); if (!ebtulognl) ret = -ENOMEM; else if ((ret = ebt_register_watcher(&ulog))) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 41859508bed..416768d1e0c 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1327,8 +1327,8 @@ void __init rtnetlink_init(void) if (!rta_buf) panic("rtnetlink_init: cannot allocate rta_buf\n"); - rtnl = netlink_kernel_create(NETLINK_ROUTE, RTNLGRP_MAX, rtnetlink_rcv, - &rtnl_mutex, THIS_MODULE); + rtnl = netlink_kernel_create(&init_net, NETLINK_ROUTE, RTNLGRP_MAX, + rtnetlink_rcv, &rtnl_mutex, THIS_MODULE); if (rtnl == NULL) panic("rtnetlink_init: cannot initialize rtnetlink\n"); netlink_set_nonroot(NETLINK_ROUTE, NL_NONROOT_RECV); diff --git a/net/decnet/netfilter/dn_rtmsg.c b/net/decnet/netfilter/dn_rtmsg.c index 696234688cf..ebb38feb4df 100644 --- a/net/decnet/netfilter/dn_rtmsg.c +++ b/net/decnet/netfilter/dn_rtmsg.c @@ -137,7 +137,8 @@ static int __init dn_rtmsg_init(void) { int rv = 0; - dnrmg = netlink_kernel_create(NETLINK_DNRTMSG, DNRNG_NLGRP_MAX, + dnrmg = netlink_kernel_create(&init_net, + NETLINK_DNRTMSG, DNRNG_NLGRP_MAX, dnrmg_receive_user_sk, NULL, THIS_MODULE); if (dnrmg == NULL) { printk(KERN_ERR "dn_rtmsg: Cannot create netlink socket"); diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index cefb55ec3d6..140bf7a8d87 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -816,8 +816,8 @@ static void nl_fib_input(struct sock *sk, int len) static void nl_fib_lookup_init(void) { - netlink_kernel_create(NETLINK_FIB_LOOKUP, 0, nl_fib_input, NULL, - THIS_MODULE); + netlink_kernel_create(&init_net, NETLINK_FIB_LOOKUP, 0, nl_fib_input, + NULL, THIS_MODULE); } static void fib_disable_ip(struct net_device *dev, int force) diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index 686ddd62f71..031cc4856b4 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c @@ -897,8 +897,8 @@ static int __init inet_diag_init(void) if (!inet_diag_table) goto out; - idiagnl = netlink_kernel_create(NETLINK_INET_DIAG, 0, inet_diag_rcv, - NULL, THIS_MODULE); + idiagnl = netlink_kernel_create(&init_net, NETLINK_INET_DIAG, 0, + inet_diag_rcv, NULL, THIS_MODULE); if (idiagnl == NULL) goto out_free_table; err = 0; diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index d91856097f2..82fda92e6b9 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c @@ -579,7 +579,7 @@ ipq_rcv_nl_event(struct notifier_block *this, if (event == NETLINK_URELEASE && n->protocol == NETLINK_FIREWALL && n->pid) { write_lock_bh(&queue_lock); - if (n->pid == peer_pid) + if ((n->net == &init_net) && (n->pid == peer_pid)) __ipq_reset(); write_unlock_bh(&queue_lock); } @@ -671,8 +671,8 @@ static int __init ip_queue_init(void) struct proc_dir_entry *proc; netlink_register_notifier(&ipq_nl_notifier); - ipqnl = netlink_kernel_create(NETLINK_FIREWALL, 0, ipq_rcv_sk, - NULL, THIS_MODULE); + ipqnl = netlink_kernel_create(&init_net, NETLINK_FIREWALL, 0, + ipq_rcv_sk, NULL, THIS_MODULE); if (ipqnl == NULL) { printk(KERN_ERR "ip_queue: failed to create netlink socket\n"); goto cleanup_netlink_notifier; diff --git a/net/ipv4/netfilter/ipt_ULOG.c b/net/ipv4/netfilter/ipt_ULOG.c index 6ca43e4ca7e..c636d6d6357 100644 --- a/net/ipv4/netfilter/ipt_ULOG.c +++ b/net/ipv4/netfilter/ipt_ULOG.c @@ -409,7 +409,8 @@ static int __init ipt_ulog_init(void) for (i = 0; i < ULOG_MAXNLGROUPS; i++) setup_timer(&ulog_buffers[i].timer, ulog_timer, i); - nflognl = netlink_kernel_create(NETLINK_NFLOG, ULOG_MAXNLGROUPS, NULL, + nflognl = netlink_kernel_create(&init_net, + NETLINK_NFLOG, ULOG_MAXNLGROUPS, NULL, NULL, THIS_MODULE); if (!nflognl) return -ENOMEM; diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index 64536a3ef2f..2f5a5245383 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c @@ -569,7 +569,7 @@ ipq_rcv_nl_event(struct notifier_block *this, if (event == NETLINK_URELEASE && n->protocol == NETLINK_IP6_FW && n->pid) { write_lock_bh(&queue_lock); - if (n->pid == peer_pid) + if ((n->net == &init_net) && (n->pid == peer_pid)) __ipq_reset(); write_unlock_bh(&queue_lock); } @@ -661,8 +661,8 @@ static int __init ip6_queue_init(void) struct proc_dir_entry *proc; netlink_register_notifier(&ipq_nl_notifier); - ipqnl = netlink_kernel_create(NETLINK_IP6_FW, 0, ipq_rcv_sk, NULL, - THIS_MODULE); + ipqnl = netlink_kernel_create(&init_net, NETLINK_IP6_FW, 0, ipq_rcv_sk, + NULL, THIS_MODULE); if (ipqnl == NULL) { printk(KERN_ERR "ip6_queue: failed to create netlink socket\n"); goto cleanup_netlink_notifier; diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c index 8797e6953ef..fa974e8e0ce 100644 --- a/net/netfilter/nfnetlink.c +++ b/net/netfilter/nfnetlink.c @@ -264,7 +264,7 @@ static int __init nfnetlink_init(void) { printk("Netfilter messages via NETLINK v%s.\n", nfversion); - nfnl = netlink_kernel_create(NETLINK_NETFILTER, NFNLGRP_MAX, + nfnl = netlink_kernel_create(&init_net, NETLINK_NETFILTER, NFNLGRP_MAX, nfnetlink_rcv, NULL, THIS_MODULE); if (!nfnl) { printk(KERN_ERR "cannot initialize nfnetlink!\n"); diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index 2351533a850..8e4001b8f76 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c @@ -706,7 +706,8 @@ nfulnl_rcv_nl_event(struct notifier_block *this, hlist_for_each_entry_safe(inst, tmp, t2, head, hlist) { UDEBUG("node = %p\n", inst); - if (n->pid == inst->peer_pid) + if ((n->net == &init_net) && + (n->pid == inst->peer_pid)) __instance_destroy(inst); } } diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index 5a8e8ff7664..c97369f48db 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -765,7 +765,8 @@ nfqnl_rcv_nl_event(struct notifier_block *this, struct hlist_head *head = &instance_table[i]; hlist_for_each_entry_safe(inst, tmp, t2, head, hlist) { - if (n->pid == inst->peer_pid) + if ((n->net == &init_net) && + (n->pid == inst->peer_pid)) __instance_destroy(inst); } } diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 406a493300d..3029f865cd6 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -211,7 +211,7 @@ netlink_unlock_table(void) wake_up(&nl_table_wait); } -static __inline__ struct sock *netlink_lookup(int protocol, u32 pid) +static __inline__ struct sock *netlink_lookup(struct net *net, int protocol, u32 pid) { struct nl_pid_hash *hash = &nl_table[protocol].hash; struct hlist_head *head; @@ -221,7 +221,7 @@ static __inline__ struct sock *netlink_lookup(int protocol, u32 pid) read_lock(&nl_table_lock); head = nl_pid_hashfn(hash, pid); sk_for_each(sk, node, head) { - if (nlk_sk(sk)->pid == pid) { + if ((sk->sk_net == net) && (nlk_sk(sk)->pid == pid)) { sock_hold(sk); goto found; } @@ -328,7 +328,7 @@ netlink_update_listeners(struct sock *sk) * makes sure updates are visible before bind or setsockopt return. */ } -static int netlink_insert(struct sock *sk, u32 pid) +static int netlink_insert(struct sock *sk, struct net *net, u32 pid) { struct nl_pid_hash *hash = &nl_table[sk->sk_protocol].hash; struct hlist_head *head; @@ -341,7 +341,7 @@ static int netlink_insert(struct sock *sk, u32 pid) head = nl_pid_hashfn(hash, pid); len = 0; sk_for_each(osk, node, head) { - if (nlk_sk(osk)->pid == pid) + if ((osk->sk_net == net) && (nlk_sk(osk)->pid == pid)) break; len++; } @@ -419,9 +419,6 @@ static int netlink_create(struct net *net, struct socket *sock, int protocol) struct netlink_sock *nlk; int err = 0; - if (net != &init_net) - return -EAFNOSUPPORT; - sock->state = SS_UNCONNECTED; if (sock->type != SOCK_RAW && sock->type != SOCK_DGRAM) @@ -481,6 +478,7 @@ static int netlink_release(struct socket *sock) if (nlk->pid && !nlk->subscriptions) { struct netlink_notify n = { + .net = sk->sk_net, .protocol = sk->sk_protocol, .pid = nlk->pid, }; @@ -509,6 +507,7 @@ static int netlink_release(struct socket *sock) static int netlink_autobind(struct socket *sock) { struct sock *sk = sock->sk; + struct net *net = sk->sk_net; struct nl_pid_hash *hash = &nl_table[sk->sk_protocol].hash; struct hlist_head *head; struct sock *osk; @@ -522,6 +521,8 @@ retry: netlink_table_grab(); head = nl_pid_hashfn(hash, pid); sk_for_each(osk, node, head) { + if ((osk->sk_net != net)) + continue; if (nlk_sk(osk)->pid == pid) { /* Bind collision, search negative pid values. */ pid = rover--; @@ -533,7 +534,7 @@ retry: } netlink_table_ungrab(); - err = netlink_insert(sk, pid); + err = netlink_insert(sk, net, pid); if (err == -EADDRINUSE) goto retry; @@ -598,6 +599,7 @@ static int netlink_realloc_groups(struct sock *sk) static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len) { struct sock *sk = sock->sk; + struct net *net = sk->sk_net; struct netlink_sock *nlk = nlk_sk(sk); struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr; int err; @@ -619,7 +621,7 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len return -EINVAL; } else { err = nladdr->nl_pid ? - netlink_insert(sk, nladdr->nl_pid) : + netlink_insert(sk, net, nladdr->nl_pid) : netlink_autobind(sock); if (err) return err; @@ -703,10 +705,12 @@ static void netlink_overrun(struct sock *sk) static struct sock *netlink_getsockbypid(struct sock *ssk, u32 pid) { int protocol = ssk->sk_protocol; + struct net *net; struct sock *sock; struct netlink_sock *nlk; - sock = netlink_lookup(protocol, pid); + net = ssk->sk_net; + sock = netlink_lookup(net, protocol, pid); if (!sock) return ERR_PTR(-ECONNREFUSED); @@ -887,6 +891,7 @@ static __inline__ int netlink_broadcast_deliver(struct sock *sk, struct sk_buff struct netlink_broadcast_data { struct sock *exclude_sk; + struct net *net; u32 pid; u32 group; int failure; @@ -909,6 +914,9 @@ static inline int do_one_broadcast(struct sock *sk, !test_bit(p->group - 1, nlk->groups)) goto out; + if ((sk->sk_net != p->net)) + goto out; + if (p->failure) { netlink_overrun(sk); goto out; @@ -947,6 +955,7 @@ out: int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid, u32 group, gfp_t allocation) { + struct net *net = ssk->sk_net; struct netlink_broadcast_data info; struct hlist_node *node; struct sock *sk; @@ -954,6 +963,7 @@ int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid, skb = netlink_trim(skb, allocation); info.exclude_sk = ssk; + info.net = net; info.pid = pid; info.group = group; info.failure = 0; @@ -1002,6 +1012,9 @@ static inline int do_one_set_err(struct sock *sk, if (sk == p->exclude_sk) goto out; + if (sk->sk_net != p->exclude_sk->sk_net) + goto out; + if (nlk->pid == p->pid || p->group - 1 >= nlk->ngroups || !test_bit(p->group - 1, nlk->groups)) goto out; @@ -1304,7 +1317,7 @@ static void netlink_data_ready(struct sock *sk, int len) */ struct sock * -netlink_kernel_create(int unit, unsigned int groups, +netlink_kernel_create(struct net *net, int unit, unsigned int groups, void (*input)(struct sock *sk, int len), struct mutex *cb_mutex, struct module *module) { @@ -1321,7 +1334,7 @@ netlink_kernel_create(int unit, unsigned int groups, if (sock_create_lite(PF_NETLINK, SOCK_DGRAM, unit, &sock)) return NULL; - if (__netlink_create(&init_net, sock, cb_mutex, unit) < 0) + if (__netlink_create(net, sock, cb_mutex, unit) < 0) goto out_sock_release; if (groups < 32) @@ -1336,18 +1349,20 @@ netlink_kernel_create(int unit, unsigned int groups, if (input) nlk_sk(sk)->data_ready = input; - if (netlink_insert(sk, 0)) + if (netlink_insert(sk, net, 0)) goto out_sock_release; nlk = nlk_sk(sk); nlk->flags |= NETLINK_KERNEL_SOCKET; netlink_table_grab(); - nl_table[unit].groups = groups; - nl_table[unit].listeners = listeners; - nl_table[unit].cb_mutex = cb_mutex; - nl_table[unit].module = module; - nl_table[unit].registered = 1; + if (!nl_table[unit].registered) { + nl_table[unit].groups = groups; + nl_table[unit].listeners = listeners; + nl_table[unit].cb_mutex = cb_mutex; + nl_table[unit].module = module; + nl_table[unit].registered = 1; + } netlink_table_ungrab(); return sk; @@ -1513,7 +1528,7 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, atomic_inc(&skb->users); cb->skb = skb; - sk = netlink_lookup(ssk->sk_protocol, NETLINK_CB(skb).pid); + sk = netlink_lookup(ssk->sk_net, ssk->sk_protocol, NETLINK_CB(skb).pid); if (sk == NULL) { netlink_destroy_callback(cb); return -ECONNREFUSED; @@ -1555,7 +1570,8 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err) if (!skb) { struct sock *sk; - sk = netlink_lookup(in_skb->sk->sk_protocol, + sk = netlink_lookup(in_skb->sk->sk_net, + in_skb->sk->sk_protocol, NETLINK_CB(in_skb).pid); if (sk) { sk->sk_err = ENOBUFS; @@ -1706,6 +1722,7 @@ int nlmsg_notify(struct sock *sk, struct sk_buff *skb, u32 pid, #ifdef CONFIG_PROC_FS struct nl_seq_iter { + struct net *net; int link; int hash_idx; }; @@ -1723,6 +1740,8 @@ static struct sock *netlink_seq_socket_idx(struct seq_file *seq, loff_t pos) for (j = 0; j <= hash->mask; j++) { sk_for_each(s, node, &hash->table[j]) { + if (iter->net != s->sk_net) + continue; if (off == pos) { iter->link = i; iter->hash_idx = j; @@ -1752,11 +1771,14 @@ static void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos) if (v == SEQ_START_TOKEN) return netlink_seq_socket_idx(seq, 0); - s = sk_next(v); + iter = seq->private; + s = v; + do { + s = sk_next(s); + } while (s && (iter->net != s->sk_net)); if (s) return s; - iter = seq->private; i = iter->link; j = iter->hash_idx + 1; @@ -1765,6 +1787,8 @@ static void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos) for (; j <= hash->mask; j++) { s = sk_head(&hash->table[j]); + while (s && (iter->net != s->sk_net)) + s = sk_next(s); if (s) { iter->link = i; iter->hash_idx = j; @@ -1835,15 +1859,24 @@ static int netlink_seq_open(struct inode *inode, struct file *file) seq = file->private_data; seq->private = iter; + iter->net = get_net(PROC_NET(inode)); return 0; } +static int netlink_seq_release(struct inode *inode, struct file *file) +{ + struct seq_file *seq = file->private_data; + struct nl_seq_iter *iter = seq->private; + put_net(iter->net); + return seq_release_private(inode, file); +} + static const struct file_operations netlink_seq_fops = { .owner = THIS_MODULE, .open = netlink_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release_private, + .release = netlink_seq_release, }; #endif @@ -1885,6 +1918,27 @@ static struct net_proto_family netlink_family_ops = { .owner = THIS_MODULE, /* for consistency 8) */ }; +static int netlink_net_init(struct net *net) +{ +#ifdef CONFIG_PROC_FS + if (!proc_net_fops_create(net, "netlink", 0, &netlink_seq_fops)) + return -ENOMEM; +#endif + return 0; +} + +static void netlink_net_exit(struct net *net) +{ +#ifdef CONFIG_PROC_FS + proc_net_remove(net, "netlink"); +#endif +} + +static struct pernet_operations netlink_net_ops = { + .init = netlink_net_init, + .exit = netlink_net_exit, +}; + static int __init netlink_proto_init(void) { struct sk_buff *dummy_skb; @@ -1930,9 +1984,7 @@ static int __init netlink_proto_init(void) } sock_register(&netlink_family_ops); -#ifdef CONFIG_PROC_FS - proc_net_fops_create(&init_net, "netlink", 0, &netlink_seq_fops); -#endif + register_pernet_subsys(&netlink_net_ops); /* The netlink device handler may be needed early. */ rtnetlink_init(); out: diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index 8c11ca4a212..af8fe26815f 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -782,8 +782,8 @@ static int __init genl_init(void) netlink_set_nonroot(NETLINK_GENERIC, NL_NONROOT_RECV); /* we'll bump the group number right afterwards */ - genl_sock = netlink_kernel_create(NETLINK_GENERIC, 0, genl_rcv, - NULL, THIS_MODULE); + genl_sock = netlink_kernel_create(&init_net, NETLINK_GENERIC, 0, + genl_rcv, NULL, THIS_MODULE); if (genl_sock == NULL) panic("GENL: Cannot initialize generic netlink\n"); diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 0d81c0f2391..1f8e7c22ddb 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -2399,7 +2399,7 @@ static int __init xfrm_user_init(void) printk(KERN_INFO "Initializing XFRM netlink socket\n"); - nlsk = netlink_kernel_create(NETLINK_XFRM, XFRMNLGRP_MAX, + nlsk = netlink_kernel_create(&init_net, NETLINK_XFRM, XFRMNLGRP_MAX, xfrm_netlink_rcv, NULL, THIS_MODULE); if (nlsk == NULL) return -ENOMEM; diff --git a/security/selinux/netlink.c b/security/selinux/netlink.c index f49046de63a..b59871d74da 100644 --- a/security/selinux/netlink.c +++ b/security/selinux/netlink.c @@ -17,6 +17,7 @@ #include #include #include +#include static struct sock *selnl; @@ -104,8 +105,8 @@ void selnl_notify_policyload(u32 seqno) static int __init selnl_init(void) { - selnl = netlink_kernel_create(NETLINK_SELINUX, SELNLGRP_MAX, NULL, NULL, - THIS_MODULE); + selnl = netlink_kernel_create(&init_net, NETLINK_SELINUX, + SELNLGRP_MAX, NULL, NULL, THIS_MODULE); if (selnl == NULL) panic("SELinux: Cannot create netlink socket."); netlink_set_nonroot(NETLINK_SELINUX, NL_NONROOT_RECV); -- cgit v1.2.3-70-g09d2 From 881d966b48b035ab3f3aeaae0f3d3f9b584f45b2 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 17 Sep 2007 11:56:21 -0700 Subject: [NET]: Make the device list and device lookups per namespace. This patch makes most of the generic device layer network namespace safe. This patch makes dev_base_head a network namespace variable, and then it picks up a few associated variables. The functions: dev_getbyhwaddr dev_getfirsthwbytype dev_get_by_flags dev_get_by_name __dev_get_by_name dev_get_by_index __dev_get_by_index dev_ioctl dev_ethtool dev_load wireless_process_ioctl were modified to take a network namespace argument, and deal with it. vlan_ioctl_set and brioctl_set were modified so their hooks will receive a network namespace argument. So basically anthing in the core of the network stack that was affected to by the change of dev_base was modified to handle multiple network namespaces. The rest of the network stack was simply modified to explicitly use &init_net the initial network namespace. This can be fixed when those components of the network stack are modified to handle multiple network namespaces. For now the ifindex generator is left global. Fundametally ifindex numbers are per namespace, or else we will have corner case problems with migration when we get that far. At the same time there are assumptions in the network stack that the ifindex of a network device won't change. Making the ifindex number global seems a good compromise until the network stack can cope with ifindex changes when you change namespaces, and the like. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- arch/s390/appldata/appldata_net_sum.c | 3 +- arch/sparc64/solaris/ioctl.c | 3 +- drivers/atm/idt77252.c | 2 +- drivers/block/aoe/aoecmd.c | 3 +- drivers/infiniband/hw/cxgb3/cxio_hal.c | 3 +- drivers/net/bonding/bond_main.c | 2 +- drivers/net/bonding/bond_sysfs.c | 3 +- drivers/net/eql.c | 9 +- drivers/net/ifb.c | 3 +- drivers/net/macvlan.c | 2 +- drivers/net/pppoe.c | 4 +- drivers/net/shaper.c | 3 +- drivers/net/tun.c | 3 +- drivers/net/veth.c | 2 +- drivers/net/wan/dlci.c | 4 +- drivers/net/wan/sbni.c | 3 +- drivers/net/wireless/strip.c | 2 +- drivers/parisc/led.c | 2 +- fs/afs/netdevices.c | 5 +- include/linux/if_bridge.h | 2 +- include/linux/if_vlan.h | 2 +- include/linux/netdevice.h | 66 ++++---- include/net/net_namespace.h | 4 + include/net/pkt_cls.h | 3 +- include/net/rtnetlink.h | 2 +- include/net/wext.h | 15 +- net/802/tr.c | 2 +- net/8021q/vlan.c | 6 +- net/8021q/vlan_netlink.c | 3 +- net/8021q/vlanproc.c | 6 +- net/appletalk/ddp.c | 6 +- net/atm/mpc.c | 2 +- net/ax25/af_ax25.c | 2 +- net/bridge/br_if.c | 4 +- net/bridge/br_ioctl.c | 7 +- net/bridge/br_netlink.c | 5 +- net/bridge/br_private.h | 2 +- net/core/dev.c | 271 ++++++++++++++++++++++----------- net/core/dev_mcast.c | 41 ++++- net/core/ethtool.c | 4 +- net/core/fib_rules.c | 4 +- net/core/neighbour.c | 6 +- net/core/netpoll.c | 2 +- net/core/pktgen.c | 2 +- net/core/rtnetlink.c | 35 +++-- net/core/sock.c | 3 +- net/decnet/af_decnet.c | 2 +- net/decnet/dn_dev.c | 20 +-- net/decnet/dn_fib.c | 8 +- net/decnet/dn_route.c | 6 +- net/decnet/sysctl_net_decnet.c | 4 +- net/econet/af_econet.c | 2 +- net/ipv4/arp.c | 4 +- net/ipv4/devinet.c | 18 +-- net/ipv4/fib_frontend.c | 2 +- net/ipv4/fib_semantics.c | 4 +- net/ipv4/icmp.c | 2 +- net/ipv4/igmp.c | 4 +- net/ipv4/ip_fragment.c | 2 +- net/ipv4/ip_gre.c | 4 +- net/ipv4/ip_sockglue.c | 2 +- net/ipv4/ipconfig.c | 2 +- net/ipv4/ipip.c | 4 +- net/ipv4/ipmr.c | 4 +- net/ipv4/ipvs/ip_vs_sync.c | 10 +- net/ipv4/netfilter/ipt_CLUSTERIP.c | 2 +- net/ipv4/route.c | 4 +- net/ipv6/addrconf.c | 28 ++-- net/ipv6/af_inet6.c | 2 +- net/ipv6/anycast.c | 12 +- net/ipv6/datagram.c | 2 +- net/ipv6/ip6_tunnel.c | 6 +- net/ipv6/ipv6_sockglue.c | 2 +- net/ipv6/mcast.c | 12 +- net/ipv6/raw.c | 2 +- net/ipv6/reassembly.c | 2 +- net/ipv6/route.c | 4 +- net/ipv6/sit.c | 4 +- net/ipx/af_ipx.c | 6 +- net/irda/irnetlink.c | 9 +- net/llc/af_llc.c | 4 +- net/llc/llc_core.c | 3 +- net/mac80211/ieee80211.c | 1 + net/mac80211/ieee80211_cfg.c | 3 +- net/mac80211/tx.c | 9 +- net/mac80211/util.c | 7 +- net/netrom/nr_route.c | 6 +- net/packet/af_packet.c | 18 +-- net/rose/rose_route.c | 8 +- net/sched/act_mirred.c | 3 +- net/sched/cls_api.c | 4 +- net/sched/em_meta.c | 2 +- net/sched/sch_api.c | 10 +- net/sctp/ipv6.c | 4 +- net/sctp/protocol.c | 2 +- net/socket.c | 22 +-- net/tipc/eth_media.c | 2 +- net/wireless/wext.c | 38 +++-- net/x25/x25_route.c | 2 +- 99 files changed, 555 insertions(+), 362 deletions(-) (limited to 'drivers') diff --git a/arch/s390/appldata/appldata_net_sum.c b/arch/s390/appldata/appldata_net_sum.c index 2180ac105b0..6c1815a4771 100644 --- a/arch/s390/appldata/appldata_net_sum.c +++ b/arch/s390/appldata/appldata_net_sum.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "appldata.h" @@ -107,7 +108,7 @@ static void appldata_get_net_sum_data(void *data) tx_dropped = 0; collisions = 0; read_lock(&dev_base_lock); - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { stats = dev->get_stats(dev); rx_packets += stats->rx_packets; tx_packets += stats->tx_packets; diff --git a/arch/sparc64/solaris/ioctl.c b/arch/sparc64/solaris/ioctl.c index 18352a49862..8ad10a6d993 100644 --- a/arch/sparc64/solaris/ioctl.c +++ b/arch/sparc64/solaris/ioctl.c @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -686,7 +687,7 @@ static inline int solaris_i(unsigned int fd, unsigned int cmd, u32 arg) int i = 0; read_lock_bh(&dev_base_lock); - for_each_netdev(d) + for_each_netdev(&init_net, d) i++; read_unlock_bh(&dev_base_lock); diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c index f8b1700f4c1..eee54c0cde6 100644 --- a/drivers/atm/idt77252.c +++ b/drivers/atm/idt77252.c @@ -3576,7 +3576,7 @@ init_card(struct atm_dev *dev) * XXX: */ sprintf(tname, "eth%d", card->index); - tmp = dev_get_by_name(tname); /* jhs: was "tmp = dev_get(tname);" */ + tmp = dev_get_by_name(&init_net, tname); /* jhs: was "tmp = dev_get(tname);" */ if (tmp) { memcpy(card->atmdev->esi, tmp->dev_addr, 6); diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index 01fbdd38e3b..30394f78cac 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include "aoe.h" @@ -194,7 +195,7 @@ aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff **tail) sl = sl_tail = NULL; read_lock(&dev_base_lock); - for_each_netdev(ifp) { + for_each_netdev(&init_net, ifp) { dev_hold(ifp); if (!is_aoe_netif(ifp)) goto cont; diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.c b/drivers/infiniband/hw/cxgb3/cxio_hal.c index beb2a381467..eec6a30840c 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_hal.c +++ b/drivers/infiniband/hw/cxgb3/cxio_hal.c @@ -37,6 +37,7 @@ #include #include #include +#include #include "cxio_resource.h" #include "cxio_hal.h" @@ -894,7 +895,7 @@ int cxio_rdev_open(struct cxio_rdev *rdev_p) if (cxio_hal_find_rdev_by_name(rdev_p->dev_name)) { return -EBUSY; } - netdev_p = dev_get_by_name(rdev_p->dev_name); + netdev_p = dev_get_by_name(&init_net, rdev_p->dev_name); if (!netdev_p) { return -EINVAL; } diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index cf97d8a6326..559fe9437e0 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -3719,7 +3719,7 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd } down_write(&(bonding_rwsem)); - slave_dev = dev_get_by_name(ifr->ifr_slave); + slave_dev = dev_get_by_name(&init_net, ifr->ifr_slave); dprintk("slave_dev=%p: \n", slave_dev); diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 60cccf2aa95..8289e27a360 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -35,6 +35,7 @@ #include #include #include +#include /* #define BONDING_DEBUG 1 */ #include "bonding.h" @@ -299,7 +300,7 @@ static ssize_t bonding_store_slaves(struct device *d, read_unlock_bh(&bond->lock); printk(KERN_INFO DRV_NAME ": %s: Adding slave %s.\n", bond->dev->name, ifname); - dev = dev_get_by_name(ifname); + dev = dev_get_by_name(&init_net, ifname); if (!dev) { printk(KERN_INFO DRV_NAME ": %s: Interface %s does not exist!\n", diff --git a/drivers/net/eql.c b/drivers/net/eql.c index 102218c4a90..f1cc66dcbdf 100644 --- a/drivers/net/eql.c +++ b/drivers/net/eql.c @@ -116,6 +116,7 @@ #include #include #include +#include #include #include @@ -412,7 +413,7 @@ static int eql_enslave(struct net_device *master_dev, slaving_request_t __user * if (copy_from_user(&srq, srqp, sizeof (slaving_request_t))) return -EFAULT; - slave_dev = dev_get_by_name(srq.slave_name); + slave_dev = dev_get_by_name(&init_net, srq.slave_name); if (slave_dev) { if ((master_dev->flags & IFF_UP) == IFF_UP) { /* slave is not a master & not already a slave: */ @@ -460,7 +461,7 @@ static int eql_emancipate(struct net_device *master_dev, slaving_request_t __use if (copy_from_user(&srq, srqp, sizeof (slaving_request_t))) return -EFAULT; - slave_dev = dev_get_by_name(srq.slave_name); + slave_dev = dev_get_by_name(&init_net, srq.slave_name); ret = -EINVAL; if (slave_dev) { spin_lock_bh(&eql->queue.lock); @@ -493,7 +494,7 @@ static int eql_g_slave_cfg(struct net_device *dev, slave_config_t __user *scp) if (copy_from_user(&sc, scp, sizeof (slave_config_t))) return -EFAULT; - slave_dev = dev_get_by_name(sc.slave_name); + slave_dev = dev_get_by_name(&init_net, sc.slave_name); if (!slave_dev) return -ENODEV; @@ -528,7 +529,7 @@ static int eql_s_slave_cfg(struct net_device *dev, slave_config_t __user *scp) if (copy_from_user(&sc, scp, sizeof (slave_config_t))) return -EFAULT; - slave_dev = dev_get_by_name(sc.slave_name); + slave_dev = dev_get_by_name(&init_net, sc.slave_name); if (!slave_dev) return -ENODEV; diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c index f5c3598e59a..b06c6db4383 100644 --- a/drivers/net/ifb.c +++ b/drivers/net/ifb.c @@ -34,6 +34,7 @@ #include #include #include +#include #define TX_TIMEOUT (2*HZ) @@ -97,7 +98,7 @@ static void ri_tasklet(unsigned long dev) stats->tx_packets++; stats->tx_bytes +=skb->len; - skb->dev = __dev_get_by_index(skb->iif); + skb->dev = __dev_get_by_index(&init_net, skb->iif); if (!skb->dev) { dev_kfree_skb(skb); stats->tx_dropped++; diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index dc74d006e01..2de073da182 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -376,7 +376,7 @@ static int macvlan_newlink(struct net_device *dev, if (!tb[IFLA_LINK]) return -EINVAL; - lowerdev = __dev_get_by_index(nla_get_u32(tb[IFLA_LINK])); + lowerdev = __dev_get_by_index(dev->nd_net, nla_get_u32(tb[IFLA_LINK])); if (lowerdev == NULL) return -ENODEV; diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index c5c70e4b1d3..2f130e06b6d 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -216,7 +216,7 @@ static inline struct pppox_sock *get_item_by_addr(struct sockaddr_pppox *sp) struct net_device *dev; int ifindex; - dev = dev_get_by_name(sp->sa_addr.pppoe.dev); + dev = dev_get_by_name(&init_net, sp->sa_addr.pppoe.dev); if(!dev) return NULL; ifindex = dev->ifindex; @@ -603,7 +603,7 @@ static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr, /* Don't re-bind if sid==0 */ if (sp->sa_addr.pppoe.sid != 0) { - dev = dev_get_by_name(sp->sa_addr.pppoe.dev); + dev = dev_get_by_name(&init_net, sp->sa_addr.pppoe.dev); error = -ENODEV; if (!dev) diff --git a/drivers/net/shaper.c b/drivers/net/shaper.c index 4c3d98ff4cd..3773b3858bd 100644 --- a/drivers/net/shaper.c +++ b/drivers/net/shaper.c @@ -86,6 +86,7 @@ #include #include +#include struct shaper_cb { unsigned long shapeclock; /* Time it should go out */ @@ -488,7 +489,7 @@ static int shaper_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { case SHAPER_SET_DEV: { - struct net_device *them=__dev_get_by_name(ss->ss_name); + struct net_device *them=__dev_get_by_name(&init_net, ss->ss_name); if(them==NULL) return -ENODEV; if(sh->dev) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 62b2b300501..691d264fbb6 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -62,6 +62,7 @@ #include #include #include +#include #include #include @@ -475,7 +476,7 @@ static int tun_set_iff(struct file *file, struct ifreq *ifr) !capable(CAP_NET_ADMIN)) return -EPERM; } - else if (__dev_get_by_name(ifr->ifr_name)) + else if (__dev_get_by_name(&init_net, ifr->ifr_name)) return -EINVAL; else { char *name; diff --git a/drivers/net/veth.c b/drivers/net/veth.c index ca1c6893b80..2c86a4459d8 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -345,7 +345,7 @@ static int veth_newlink(struct net_device *dev, else snprintf(ifname, IFNAMSIZ, DRV_NAME "%%d"); - peer = rtnl_create_link(ifname, &veth_link_ops, tbp); + peer = rtnl_create_link(dev->nd_net, ifname, &veth_link_ops, tbp); if (IS_ERR(peer)) return PTR_ERR(peer); diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c index 61041d5186a..bc12810157e 100644 --- a/drivers/net/wan/dlci.c +++ b/drivers/net/wan/dlci.c @@ -361,7 +361,7 @@ static int dlci_add(struct dlci_add *dlci) /* validate slave device */ - slave = dev_get_by_name(dlci->devname); + slave = dev_get_by_name(&init_net, dlci->devname); if (!slave) return -ENODEV; @@ -427,7 +427,7 @@ static int dlci_del(struct dlci_add *dlci) int err; /* validate slave device */ - master = __dev_get_by_name(dlci->devname); + master = __dev_get_by_name(&init_net, dlci->devname); if (!master) return(-ENODEV); diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c index 1cc18e787a6..8d7e01e8f56 100644 --- a/drivers/net/wan/sbni.c +++ b/drivers/net/wan/sbni.c @@ -54,6 +54,7 @@ #include #include +#include #include #include @@ -1361,7 +1362,7 @@ sbni_ioctl( struct net_device *dev, struct ifreq *ifr, int cmd ) if (copy_from_user( slave_name, ifr->ifr_data, sizeof slave_name )) return -EFAULT; - slave_dev = dev_get_by_name( slave_name ); + slave_dev = dev_get_by_name(&init_net, slave_name ); if( !slave_dev || !(slave_dev->flags & IFF_UP) ) { printk( KERN_ERR "%s: trying to enslave non-active " "device %s\n", dev->name, slave_name ); diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c index edb214e8c74..904e548e679 100644 --- a/drivers/net/wireless/strip.c +++ b/drivers/net/wireless/strip.c @@ -1972,7 +1972,7 @@ static struct net_device *get_strip_dev(struct strip *strip_info) sizeof(zero_address))) { struct net_device *dev; read_lock_bh(&dev_base_lock); - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { if (dev->type == strip_info->dev->type && !memcmp(dev->dev_addr, &strip_info->true_dev_addr, diff --git a/drivers/parisc/led.c b/drivers/parisc/led.c index e5d7ed92d6f..a6d6b2488ff 100644 --- a/drivers/parisc/led.c +++ b/drivers/parisc/led.c @@ -359,7 +359,7 @@ static __inline__ int led_get_net_activity(void) * for reading should be OK */ read_lock(&dev_base_lock); rcu_read_lock(); - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { struct net_device_stats *stats; struct in_device *in_dev = __in_dev_get_rcu(dev); if (!in_dev || !in_dev->ifa_list) diff --git a/fs/afs/netdevices.c b/fs/afs/netdevices.c index fc27d4b52e5..49f18942306 100644 --- a/fs/afs/netdevices.c +++ b/fs/afs/netdevices.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "internal.h" /* @@ -23,7 +24,7 @@ int afs_get_MAC_address(u8 *mac, size_t maclen) BUG(); rtnl_lock(); - dev = __dev_getfirstbyhwtype(ARPHRD_ETHER); + dev = __dev_getfirstbyhwtype(&init_net, ARPHRD_ETHER); if (dev) { memcpy(mac, dev->dev_addr, maclen); ret = 0; @@ -47,7 +48,7 @@ int afs_get_ipv4_interfaces(struct afs_interface *bufs, size_t maxbufs, ASSERT(maxbufs > 0); rtnl_lock(); - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { if (dev->type == ARPHRD_LOOPBACK && !wantloopback) continue; idev = __in_dev_get_rtnl(dev); diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h index 4ff211d9876..99e3a1a0009 100644 --- a/include/linux/if_bridge.h +++ b/include/linux/if_bridge.h @@ -104,7 +104,7 @@ struct __fdb_entry #include -extern void brioctl_set(int (*ioctl_hook)(unsigned int, void __user *)); +extern void brioctl_set(int (*ioctl_hook)(struct net *, unsigned int, void __user *)); extern struct sk_buff *(*br_handle_frame_hook)(struct net_bridge_port *p, struct sk_buff *skb); extern int (*br_should_route_hook)(struct sk_buff **pskb); diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h index f8443fdb124..976d4b1067d 100644 --- a/include/linux/if_vlan.h +++ b/include/linux/if_vlan.h @@ -62,7 +62,7 @@ struct vlan_hdr { #define VLAN_VID_MASK 0xfff /* found in socket.c */ -extern void vlan_ioctl_set(int (*hook)(void __user *)); +extern void vlan_ioctl_set(int (*hook)(struct net *, void __user *)); #define VLAN_NAME "vlan" diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index dc3c15b726b..7353b3e1f4f 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -741,44 +741,48 @@ struct packet_type { #include extern struct net_device loopback_dev; /* The loopback */ -extern struct list_head dev_base_head; /* All devices */ extern rwlock_t dev_base_lock; /* Device list lock */ -#define for_each_netdev(d) \ - list_for_each_entry(d, &dev_base_head, dev_list) -#define for_each_netdev_safe(d, n) \ - list_for_each_entry_safe(d, n, &dev_base_head, dev_list) -#define for_each_netdev_continue(d) \ - list_for_each_entry_continue(d, &dev_base_head, dev_list) -#define net_device_entry(lh) list_entry(lh, struct net_device, dev_list) - -static inline struct net_device *next_net_device(struct net_device *dev) -{ - struct list_head *lh; - lh = dev->dev_list.next; - return lh == &dev_base_head ? NULL : net_device_entry(lh); -} +#define for_each_netdev(net, d) \ + list_for_each_entry(d, &(net)->dev_base_head, dev_list) +#define for_each_netdev_safe(net, d, n) \ + list_for_each_entry_safe(d, n, &(net)->dev_base_head, dev_list) +#define for_each_netdev_continue(net, d) \ + list_for_each_entry_continue(d, &(net)->dev_base_head, dev_list) +#define net_device_entry(lh) list_entry(lh, struct net_device, dev_list) -static inline struct net_device *first_net_device(void) -{ - return list_empty(&dev_base_head) ? NULL : - net_device_entry(dev_base_head.next); -} +#define next_net_device(d) \ +({ \ + struct net_device *dev = d; \ + struct list_head *lh; \ + struct net *net; \ + \ + net = dev->nd_net; \ + lh = dev->dev_list.next; \ + lh == &net->dev_base_head ? NULL : net_device_entry(lh); \ +}) + +#define first_net_device(N) \ +({ \ + struct net *NET = (N); \ + list_empty(&NET->dev_base_head) ? NULL : \ + net_device_entry(NET->dev_base_head.next); \ +}) extern int netdev_boot_setup_check(struct net_device *dev); extern unsigned long netdev_boot_base(const char *prefix, int unit); -extern struct net_device *dev_getbyhwaddr(unsigned short type, char *hwaddr); -extern struct net_device *dev_getfirstbyhwtype(unsigned short type); -extern struct net_device *__dev_getfirstbyhwtype(unsigned short type); +extern struct net_device *dev_getbyhwaddr(struct net *net, unsigned short type, char *hwaddr); +extern struct net_device *dev_getfirstbyhwtype(struct net *net, unsigned short type); +extern struct net_device *__dev_getfirstbyhwtype(struct net *net, unsigned short type); extern void dev_add_pack(struct packet_type *pt); extern void dev_remove_pack(struct packet_type *pt); extern void __dev_remove_pack(struct packet_type *pt); -extern struct net_device *dev_get_by_flags(unsigned short flags, +extern struct net_device *dev_get_by_flags(struct net *net, unsigned short flags, unsigned short mask); -extern struct net_device *dev_get_by_name(const char *name); -extern struct net_device *__dev_get_by_name(const char *name); +extern struct net_device *dev_get_by_name(struct net *net, const char *name); +extern struct net_device *__dev_get_by_name(struct net *net, const char *name); extern int dev_alloc_name(struct net_device *dev, const char *name); extern int dev_open(struct net_device *dev); extern int dev_close(struct net_device *dev); @@ -790,8 +794,8 @@ extern void synchronize_net(void); extern int register_netdevice_notifier(struct notifier_block *nb); extern int unregister_netdevice_notifier(struct notifier_block *nb); extern int call_netdevice_notifiers(unsigned long val, void *v); -extern struct net_device *dev_get_by_index(int ifindex); -extern struct net_device *__dev_get_by_index(int ifindex); +extern struct net_device *dev_get_by_index(struct net *net, int ifindex); +extern struct net_device *__dev_get_by_index(struct net *net, int ifindex); extern int dev_restart(struct net_device *dev); #ifdef CONFIG_NETPOLL_TRAP extern int netpoll_trap(void); @@ -1007,8 +1011,8 @@ extern int netif_rx_ni(struct sk_buff *skb); #define HAVE_NETIF_RECEIVE_SKB 1 extern int netif_receive_skb(struct sk_buff *skb); extern int dev_valid_name(const char *name); -extern int dev_ioctl(unsigned int cmd, void __user *); -extern int dev_ethtool(struct ifreq *); +extern int dev_ioctl(struct net *net, unsigned int cmd, void __user *); +extern int dev_ethtool(struct net *net, struct ifreq *); extern unsigned dev_get_flags(const struct net_device *); extern int dev_change_flags(struct net_device *, unsigned); extern int dev_change_name(struct net_device *, char *); @@ -1327,7 +1331,7 @@ extern void dev_set_allmulti(struct net_device *dev, int inc); extern void netdev_state_change(struct net_device *dev); extern void netdev_features_change(struct net_device *dev); /* Load a device via the kmod */ -extern void dev_load(const char *name); +extern void dev_load(struct net *net, const char *name); extern void dev_mcast_init(void); extern int netdev_max_backlog; extern int weight_p; diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 54724768134..fac42db7f6d 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -22,6 +22,10 @@ struct net { struct proc_dir_entry *proc_net; struct proc_dir_entry *proc_net_stat; struct proc_dir_entry *proc_net_root; + + struct list_head dev_base_head; + struct hlist_head *dev_name_head; + struct hlist_head *dev_index_head; }; extern struct net init_net; diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h index 7968b1d6636..f285de69c61 100644 --- a/include/net/pkt_cls.h +++ b/include/net/pkt_cls.h @@ -2,6 +2,7 @@ #define __NET_PKT_CLS_H #include +#include #include #include @@ -351,7 +352,7 @@ tcf_match_indev(struct sk_buff *skb, char *indev) if (indev[0]) { if (!skb->iif) return 0; - dev = __dev_get_by_index(skb->iif); + dev = __dev_get_by_index(&init_net, skb->iif); if (!dev || strcmp(indev, dev->name)) return 0; } diff --git a/include/net/rtnetlink.h b/include/net/rtnetlink.h index 8218288ab7e..793863e09c6 100644 --- a/include/net/rtnetlink.h +++ b/include/net/rtnetlink.h @@ -78,7 +78,7 @@ extern void __rtnl_link_unregister(struct rtnl_link_ops *ops); extern int rtnl_link_register(struct rtnl_link_ops *ops); extern void rtnl_link_unregister(struct rtnl_link_ops *ops); -extern struct net_device *rtnl_create_link(char *ifname, +extern struct net_device *rtnl_create_link(struct net *net, char *ifname, const struct rtnl_link_ops *ops, struct nlattr *tb[]); extern const struct nla_policy ifla_policy[IFLA_MAX+1]; diff --git a/include/net/wext.h b/include/net/wext.h index c02b8decf3a..80b31d826b7 100644 --- a/include/net/wext.h +++ b/include/net/wext.h @@ -5,16 +5,23 @@ * wireless extensions interface to the core code */ +struct net; + #ifdef CONFIG_WIRELESS_EXT -extern int wext_proc_init(void); -extern int wext_handle_ioctl(struct ifreq *ifr, unsigned int cmd, +extern int wext_proc_init(struct net *net); +extern void wext_proc_exit(struct net *net); +extern int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd, void __user *arg); #else -static inline int wext_proc_init(void) +static inline int wext_proc_init(struct net *net) { return 0; } -static inline int wext_handle_ioctl(struct ifreq *ifr, unsigned int cmd, +static inline void wext_proc_exit(struct net *net) +{ + return; +} +static inline int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd, void __user *arg) { return -EINVAL; diff --git a/net/802/tr.c b/net/802/tr.c index 032c31e748e..55c76d77d32 100644 --- a/net/802/tr.c +++ b/net/802/tr.c @@ -533,7 +533,7 @@ static int rif_seq_show(struct seq_file *seq, void *v) seq_puts(seq, "if TR address TTL rcf routing segments\n"); else { - struct net_device *dev = dev_get_by_index(entry->iface); + struct net_device *dev = dev_get_by_index(&init_net, entry->iface); long ttl = (long) (entry->last_used + sysctl_tr_rif_timeout) - (long) jiffies; diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index d0d36fdedbe..a9ced0a6f4c 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -51,7 +51,7 @@ static char vlan_copyright[] = "Ben Greear "; static char vlan_buggyright[] = "David S. Miller "; static int vlan_device_event(struct notifier_block *, unsigned long, void *); -static int vlan_ioctl_handler(void __user *); +static int vlan_ioctl_handler(struct net *net, void __user *); static int unregister_vlan_dev(struct net_device *, unsigned short ); static struct notifier_block vlan_notifier_block = { @@ -697,7 +697,7 @@ out: * o execute requested action or pass command to the device driver * arg is really a struct vlan_ioctl_args __user *. */ -static int vlan_ioctl_handler(void __user *arg) +static int vlan_ioctl_handler(struct net *net, void __user *arg) { int err; unsigned short vid = 0; @@ -726,7 +726,7 @@ static int vlan_ioctl_handler(void __user *arg) case GET_VLAN_REALDEV_NAME_CMD: case GET_VLAN_VID_CMD: err = -ENODEV; - dev = __dev_get_by_name(args.device1); + dev = __dev_get_by_name(&init_net, args.device1); if (!dev) goto out; diff --git a/net/8021q/vlan_netlink.c b/net/8021q/vlan_netlink.c index 6cdd1e015e2..0996185e2ed 100644 --- a/net/8021q/vlan_netlink.c +++ b/net/8021q/vlan_netlink.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include "vlan.h" @@ -112,7 +113,7 @@ static int vlan_newlink(struct net_device *dev, if (!tb[IFLA_LINK]) return -EINVAL; - real_dev = __dev_get_by_index(nla_get_u32(tb[IFLA_LINK])); + real_dev = __dev_get_by_index(&init_net, nla_get_u32(tb[IFLA_LINK])); if (!real_dev) return -ENODEV; diff --git a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c index ac80e6b9ef5..6cefdf8e381 100644 --- a/net/8021q/vlanproc.c +++ b/net/8021q/vlanproc.c @@ -254,7 +254,7 @@ static void *vlan_seq_start(struct seq_file *seq, loff_t *pos) if (*pos == 0) return SEQ_START_TOKEN; - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { if (!is_vlan_dev(dev)) continue; @@ -273,9 +273,9 @@ static void *vlan_seq_next(struct seq_file *seq, void *v, loff_t *pos) dev = (struct net_device *)v; if (v == SEQ_START_TOKEN) - dev = net_device_entry(&dev_base_head); + dev = net_device_entry(&init_net.dev_base_head); - for_each_netdev_continue(dev) { + for_each_netdev_continue(&init_net, dev) { if (!is_vlan_dev(dev)) continue; diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index 36fcdbf923c..7c0b5151d52 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -677,7 +677,7 @@ static int atif_ioctl(int cmd, void __user *arg) if (copy_from_user(&atreq, arg, sizeof(atreq))) return -EFAULT; - dev = __dev_get_by_name(atreq.ifr_name); + dev = __dev_get_by_name(&init_net, atreq.ifr_name); if (!dev) return -ENODEV; @@ -901,7 +901,7 @@ static int atrtr_ioctl(unsigned int cmd, void __user *arg) if (copy_from_user(name, rt.rt_dev, IFNAMSIZ-1)) return -EFAULT; name[IFNAMSIZ-1] = '\0'; - dev = __dev_get_by_name(name); + dev = __dev_get_by_name(&init_net, name); if (!dev) return -ENODEV; } @@ -1273,7 +1273,7 @@ static __inline__ int is_ip_over_ddp(struct sk_buff *skb) static int handle_ip_over_ddp(struct sk_buff *skb) { - struct net_device *dev = __dev_get_by_name("ipddp0"); + struct net_device *dev = __dev_get_by_name(&init_net, "ipddp0"); struct net_device_stats *stats; /* This needs to be able to handle ipddp"N" devices */ diff --git a/net/atm/mpc.c b/net/atm/mpc.c index 0968430a7f5..2086396de17 100644 --- a/net/atm/mpc.c +++ b/net/atm/mpc.c @@ -244,7 +244,7 @@ static struct net_device *find_lec_by_itfnum(int itf) char name[IFNAMSIZ]; sprintf(name, "lec%d", itf); - dev = dev_get_by_name(name); + dev = dev_get_by_name(&init_net, name); return dev; } diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index 8d13a8bca0e..993e5c75e90 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -631,7 +631,7 @@ static int ax25_setsockopt(struct socket *sock, int level, int optname, break; } - dev = dev_get_by_name(devname); + dev = dev_get_by_name(&init_net, devname); if (dev == NULL) { res = -ENODEV; break; diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 9272f12f664..935784f736b 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -303,7 +303,7 @@ int br_del_bridge(const char *name) int ret = 0; rtnl_lock(); - dev = __dev_get_by_name(name); + dev = __dev_get_by_name(&init_net, name); if (dev == NULL) ret = -ENXIO; /* Could not find device */ @@ -444,7 +444,7 @@ void __exit br_cleanup_bridges(void) struct net_device *dev, *nxt; rtnl_lock(); - for_each_netdev_safe(dev, nxt) + for_each_netdev_safe(&init_net, dev, nxt) if (dev->priv_flags & IFF_EBRIDGE) del_br(dev->priv); rtnl_unlock(); diff --git a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c index bb15e9e259b..0655a5f07f5 100644 --- a/net/bridge/br_ioctl.c +++ b/net/bridge/br_ioctl.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include "br_private.h" @@ -27,7 +28,7 @@ static int get_bridge_ifindices(int *indices, int num) struct net_device *dev; int i = 0; - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { if (i >= num) break; if (dev->priv_flags & IFF_EBRIDGE) @@ -90,7 +91,7 @@ static int add_del_if(struct net_bridge *br, int ifindex, int isadd) if (!capable(CAP_NET_ADMIN)) return -EPERM; - dev = dev_get_by_index(ifindex); + dev = dev_get_by_index(&init_net, ifindex); if (dev == NULL) return -EINVAL; @@ -364,7 +365,7 @@ static int old_deviceless(void __user *uarg) return -EOPNOTSUPP; } -int br_ioctl_deviceless_stub(unsigned int cmd, void __user *uarg) +int br_ioctl_deviceless_stub(struct net *net, unsigned int cmd, void __user *uarg) { switch (cmd) { case SIOCGIFBR: diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index 0fcf6f07306..53ab8e0cb51 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -12,6 +12,7 @@ #include #include +#include #include "br_private.h" static inline size_t br_nlmsg_size(void) @@ -110,7 +111,7 @@ static int br_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) int idx; idx = 0; - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { /* not a bridge port */ if (dev->br_port == NULL || idx < cb->args[0]) goto skip; @@ -155,7 +156,7 @@ static int br_rtm_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) if (new_state > BR_STATE_BLOCKING) return -EINVAL; - dev = __dev_get_by_index(ifm->ifi_index); + dev = __dev_get_by_index(&init_net, ifm->ifi_index); if (!dev) return -ENODEV; diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index e6dc6f52990..f666f7b28ff 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -192,7 +192,7 @@ extern struct sk_buff *br_handle_frame(struct net_bridge_port *p, /* br_ioctl.c */ extern int br_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -extern int br_ioctl_deviceless_stub(unsigned int cmd, void __user *arg); +extern int br_ioctl_deviceless_stub(struct net *net, unsigned int cmd, void __user *arg); /* br_netfilter.c */ #ifdef CONFIG_BRIDGE_NETFILTER diff --git a/net/core/dev.c b/net/core/dev.c index 40fd66fbe4e..3a3d5ee7390 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -190,25 +190,22 @@ static struct net_dma net_dma = { * unregister_netdevice(), which must be called with the rtnl * semaphore held. */ -LIST_HEAD(dev_base_head); DEFINE_RWLOCK(dev_base_lock); -EXPORT_SYMBOL(dev_base_head); EXPORT_SYMBOL(dev_base_lock); #define NETDEV_HASHBITS 8 -static struct hlist_head dev_name_head[1<dev_name_head[hash & ((1 << NETDEV_HASHBITS) - 1)]; } -static inline struct hlist_head *dev_index_hash(int ifindex) +static inline struct hlist_head *dev_index_hash(struct net *net, int ifindex) { - return &dev_index_head[ifindex & ((1<dev_index_head[ifindex & ((1 << NETDEV_HASHBITS) - 1)]; } /* @@ -492,7 +489,7 @@ unsigned long netdev_boot_base(const char *prefix, int unit) * If device already registered then return base of 1 * to indicate not to probe for this interface */ - if (__dev_get_by_name(name)) + if (__dev_get_by_name(&init_net, name)) return 1; for (i = 0; i < NETDEV_BOOT_SETUP_MAX; i++) @@ -547,11 +544,11 @@ __setup("netdev=", netdev_boot_setup); * careful with locks. */ -struct net_device *__dev_get_by_name(const char *name) +struct net_device *__dev_get_by_name(struct net *net, const char *name) { struct hlist_node *p; - hlist_for_each(p, dev_name_hash(name)) { + hlist_for_each(p, dev_name_hash(net, name)) { struct net_device *dev = hlist_entry(p, struct net_device, name_hlist); if (!strncmp(dev->name, name, IFNAMSIZ)) @@ -571,12 +568,12 @@ struct net_device *__dev_get_by_name(const char *name) * matching device is found. */ -struct net_device *dev_get_by_name(const char *name) +struct net_device *dev_get_by_name(struct net *net, const char *name) { struct net_device *dev; read_lock(&dev_base_lock); - dev = __dev_get_by_name(name); + dev = __dev_get_by_name(net, name); if (dev) dev_hold(dev); read_unlock(&dev_base_lock); @@ -594,11 +591,11 @@ struct net_device *dev_get_by_name(const char *name) * or @dev_base_lock. */ -struct net_device *__dev_get_by_index(int ifindex) +struct net_device *__dev_get_by_index(struct net *net, int ifindex) { struct hlist_node *p; - hlist_for_each(p, dev_index_hash(ifindex)) { + hlist_for_each(p, dev_index_hash(net, ifindex)) { struct net_device *dev = hlist_entry(p, struct net_device, index_hlist); if (dev->ifindex == ifindex) @@ -618,12 +615,12 @@ struct net_device *__dev_get_by_index(int ifindex) * dev_put to indicate they have finished with it. */ -struct net_device *dev_get_by_index(int ifindex) +struct net_device *dev_get_by_index(struct net *net, int ifindex) { struct net_device *dev; read_lock(&dev_base_lock); - dev = __dev_get_by_index(ifindex); + dev = __dev_get_by_index(net, ifindex); if (dev) dev_hold(dev); read_unlock(&dev_base_lock); @@ -644,13 +641,13 @@ struct net_device *dev_get_by_index(int ifindex) * If the API was consistent this would be __dev_get_by_hwaddr */ -struct net_device *dev_getbyhwaddr(unsigned short type, char *ha) +struct net_device *dev_getbyhwaddr(struct net *net, unsigned short type, char *ha) { struct net_device *dev; ASSERT_RTNL(); - for_each_netdev(dev) + for_each_netdev(&init_net, dev) if (dev->type == type && !memcmp(dev->dev_addr, ha, dev->addr_len)) return dev; @@ -660,12 +657,12 @@ struct net_device *dev_getbyhwaddr(unsigned short type, char *ha) EXPORT_SYMBOL(dev_getbyhwaddr); -struct net_device *__dev_getfirstbyhwtype(unsigned short type) +struct net_device *__dev_getfirstbyhwtype(struct net *net, unsigned short type) { struct net_device *dev; ASSERT_RTNL(); - for_each_netdev(dev) + for_each_netdev(net, dev) if (dev->type == type) return dev; @@ -674,12 +671,12 @@ struct net_device *__dev_getfirstbyhwtype(unsigned short type) EXPORT_SYMBOL(__dev_getfirstbyhwtype); -struct net_device *dev_getfirstbyhwtype(unsigned short type) +struct net_device *dev_getfirstbyhwtype(struct net *net, unsigned short type) { struct net_device *dev; rtnl_lock(); - dev = __dev_getfirstbyhwtype(type); + dev = __dev_getfirstbyhwtype(net, type); if (dev) dev_hold(dev); rtnl_unlock(); @@ -699,13 +696,13 @@ EXPORT_SYMBOL(dev_getfirstbyhwtype); * dev_put to indicate they have finished with it. */ -struct net_device * dev_get_by_flags(unsigned short if_flags, unsigned short mask) +struct net_device * dev_get_by_flags(struct net *net, unsigned short if_flags, unsigned short mask) { struct net_device *dev, *ret; ret = NULL; read_lock(&dev_base_lock); - for_each_netdev(dev) { + for_each_netdev(net, dev) { if (((dev->flags ^ if_flags) & mask) == 0) { dev_hold(dev); ret = dev; @@ -763,6 +760,10 @@ int dev_alloc_name(struct net_device *dev, const char *name) const int max_netdevices = 8*PAGE_SIZE; long *inuse; struct net_device *d; + struct net *net; + + BUG_ON(!dev->nd_net); + net = dev->nd_net; p = strnchr(name, IFNAMSIZ-1, '%'); if (p) { @@ -779,7 +780,7 @@ int dev_alloc_name(struct net_device *dev, const char *name) if (!inuse) return -ENOMEM; - for_each_netdev(d) { + for_each_netdev(net, d) { if (!sscanf(d->name, name, &i)) continue; if (i < 0 || i >= max_netdevices) @@ -796,7 +797,7 @@ int dev_alloc_name(struct net_device *dev, const char *name) } snprintf(buf, sizeof(buf), name, i); - if (!__dev_get_by_name(buf)) { + if (!__dev_get_by_name(net, buf)) { strlcpy(dev->name, buf, IFNAMSIZ); return i; } @@ -822,9 +823,12 @@ int dev_change_name(struct net_device *dev, char *newname) char oldname[IFNAMSIZ]; int err = 0; int ret; + struct net *net; ASSERT_RTNL(); + BUG_ON(!dev->nd_net); + net = dev->nd_net; if (dev->flags & IFF_UP) return -EBUSY; @@ -839,7 +843,7 @@ int dev_change_name(struct net_device *dev, char *newname) return err; strcpy(newname, dev->name); } - else if (__dev_get_by_name(newname)) + else if (__dev_get_by_name(net, newname)) return -EEXIST; else strlcpy(dev->name, newname, IFNAMSIZ); @@ -849,7 +853,7 @@ rollback: write_lock_bh(&dev_base_lock); hlist_del(&dev->name_hlist); - hlist_add_head(&dev->name_hlist, dev_name_hash(dev->name)); + hlist_add_head(&dev->name_hlist, dev_name_hash(net, dev->name)); write_unlock_bh(&dev_base_lock); ret = raw_notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev); @@ -908,12 +912,12 @@ void netdev_state_change(struct net_device *dev) * available in this kernel then it becomes a nop. */ -void dev_load(const char *name) +void dev_load(struct net *net, const char *name) { struct net_device *dev; read_lock(&dev_base_lock); - dev = __dev_get_by_name(name); + dev = __dev_get_by_name(net, name); read_unlock(&dev_base_lock); if (!dev && capable(CAP_SYS_MODULE)) @@ -1052,6 +1056,8 @@ int dev_close(struct net_device *dev) } +static int dev_boot_phase = 1; + /* * Device change register/unregister. These are not inline or static * as we export them to the world. @@ -1075,23 +1081,27 @@ int register_netdevice_notifier(struct notifier_block *nb) { struct net_device *dev; struct net_device *last; + struct net *net; int err; rtnl_lock(); err = raw_notifier_chain_register(&netdev_chain, nb); if (err) goto unlock; + if (dev_boot_phase) + goto unlock; + for_each_net(net) { + for_each_netdev(net, dev) { + err = nb->notifier_call(nb, NETDEV_REGISTER, dev); + err = notifier_to_errno(err); + if (err) + goto rollback; + + if (!(dev->flags & IFF_UP)) + continue; - for_each_netdev(dev) { - err = nb->notifier_call(nb, NETDEV_REGISTER, dev); - err = notifier_to_errno(err); - if (err) - goto rollback; - - if (!(dev->flags & IFF_UP)) - continue; - - nb->notifier_call(nb, NETDEV_UP, dev); + nb->notifier_call(nb, NETDEV_UP, dev); + } } unlock: @@ -1100,15 +1110,17 @@ unlock: rollback: last = dev; - for_each_netdev(dev) { - if (dev == last) - break; + for_each_net(net) { + for_each_netdev(net, dev) { + if (dev == last) + break; - if (dev->flags & IFF_UP) { - nb->notifier_call(nb, NETDEV_GOING_DOWN, dev); - nb->notifier_call(nb, NETDEV_DOWN, dev); + if (dev->flags & IFF_UP) { + nb->notifier_call(nb, NETDEV_GOING_DOWN, dev); + nb->notifier_call(nb, NETDEV_DOWN, dev); + } + nb->notifier_call(nb, NETDEV_UNREGISTER, dev); } - nb->notifier_call(nb, NETDEV_UNREGISTER, dev); } goto unlock; } @@ -2187,7 +2199,7 @@ int register_gifconf(unsigned int family, gifconf_func_t * gifconf) * match. --pb */ -static int dev_ifname(struct ifreq __user *arg) +static int dev_ifname(struct net *net, struct ifreq __user *arg) { struct net_device *dev; struct ifreq ifr; @@ -2200,7 +2212,7 @@ static int dev_ifname(struct ifreq __user *arg) return -EFAULT; read_lock(&dev_base_lock); - dev = __dev_get_by_index(ifr.ifr_ifindex); + dev = __dev_get_by_index(net, ifr.ifr_ifindex); if (!dev) { read_unlock(&dev_base_lock); return -ENODEV; @@ -2220,7 +2232,7 @@ static int dev_ifname(struct ifreq __user *arg) * Thus we will need a 'compatibility mode'. */ -static int dev_ifconf(char __user *arg) +static int dev_ifconf(struct net *net, char __user *arg) { struct ifconf ifc; struct net_device *dev; @@ -2244,7 +2256,7 @@ static int dev_ifconf(char __user *arg) */ total = 0; - for_each_netdev(dev) { + for_each_netdev(net, dev) { for (i = 0; i < NPROTO; i++) { if (gifconf_list[i]) { int done; @@ -2278,6 +2290,7 @@ static int dev_ifconf(char __user *arg) */ void *dev_seq_start(struct seq_file *seq, loff_t *pos) { + struct net *net = seq->private; loff_t off; struct net_device *dev; @@ -2286,7 +2299,7 @@ void *dev_seq_start(struct seq_file *seq, loff_t *pos) return SEQ_START_TOKEN; off = 1; - for_each_netdev(dev) + for_each_netdev(net, dev) if (off++ == *pos) return dev; @@ -2295,9 +2308,10 @@ void *dev_seq_start(struct seq_file *seq, loff_t *pos) void *dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) { + struct net *net = seq->private; ++*pos; return v == SEQ_START_TOKEN ? - first_net_device() : next_net_device((struct net_device *)v); + first_net_device(net) : next_net_device((struct net_device *)v); } void dev_seq_stop(struct seq_file *seq, void *v) @@ -2393,7 +2407,22 @@ static const struct seq_operations dev_seq_ops = { static int dev_seq_open(struct inode *inode, struct file *file) { - return seq_open(file, &dev_seq_ops); + struct seq_file *seq; + int res; + res = seq_open(file, &dev_seq_ops); + if (!res) { + seq = file->private_data; + seq->private = get_net(PROC_NET(inode)); + } + return res; +} + +static int dev_seq_release(struct inode *inode, struct file *file) +{ + struct seq_file *seq = file->private_data; + struct net *net = seq->private; + put_net(net); + return seq_release(inode, file); } static const struct file_operations dev_seq_fops = { @@ -2401,7 +2430,7 @@ static const struct file_operations dev_seq_fops = { .open = dev_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release, + .release = dev_seq_release, }; static const struct seq_operations softnet_seq_ops = { @@ -2553,30 +2582,49 @@ static const struct file_operations ptype_seq_fops = { }; -static int __init dev_proc_init(void) +static int dev_proc_net_init(struct net *net) { int rc = -ENOMEM; - if (!proc_net_fops_create(&init_net, "dev", S_IRUGO, &dev_seq_fops)) + if (!proc_net_fops_create(net, "dev", S_IRUGO, &dev_seq_fops)) goto out; - if (!proc_net_fops_create(&init_net, "softnet_stat", S_IRUGO, &softnet_seq_fops)) + if (!proc_net_fops_create(net, "softnet_stat", S_IRUGO, &softnet_seq_fops)) goto out_dev; - if (!proc_net_fops_create(&init_net, "ptype", S_IRUGO, &ptype_seq_fops)) + if (!proc_net_fops_create(net, "ptype", S_IRUGO, &ptype_seq_fops)) goto out_softnet; - if (wext_proc_init()) + if (wext_proc_init(net)) goto out_ptype; rc = 0; out: return rc; out_ptype: - proc_net_remove(&init_net, "ptype"); + proc_net_remove(net, "ptype"); out_softnet: - proc_net_remove(&init_net, "softnet_stat"); + proc_net_remove(net, "softnet_stat"); out_dev: - proc_net_remove(&init_net, "dev"); + proc_net_remove(net, "dev"); goto out; } + +static void dev_proc_net_exit(struct net *net) +{ + wext_proc_exit(net); + + proc_net_remove(net, "ptype"); + proc_net_remove(net, "softnet_stat"); + proc_net_remove(net, "dev"); +} + +static struct pernet_operations dev_proc_ops = { + .init = dev_proc_net_init, + .exit = dev_proc_net_exit, +}; + +static int __init dev_proc_init(void) +{ + return register_pernet_subsys(&dev_proc_ops); +} #else #define dev_proc_init() 0 #endif /* CONFIG_PROC_FS */ @@ -3011,10 +3059,10 @@ int dev_set_mac_address(struct net_device *dev, struct sockaddr *sa) /* * Perform the SIOCxIFxxx calls. */ -static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd) +static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd) { int err; - struct net_device *dev = __dev_get_by_name(ifr->ifr_name); + struct net_device *dev = __dev_get_by_name(net, ifr->ifr_name); if (!dev) return -ENODEV; @@ -3167,7 +3215,7 @@ static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd) * positive or a negative errno code on error. */ -int dev_ioctl(unsigned int cmd, void __user *arg) +int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg) { struct ifreq ifr; int ret; @@ -3180,12 +3228,12 @@ int dev_ioctl(unsigned int cmd, void __user *arg) if (cmd == SIOCGIFCONF) { rtnl_lock(); - ret = dev_ifconf((char __user *) arg); + ret = dev_ifconf(net, (char __user *) arg); rtnl_unlock(); return ret; } if (cmd == SIOCGIFNAME) - return dev_ifname((struct ifreq __user *)arg); + return dev_ifname(net, (struct ifreq __user *)arg); if (copy_from_user(&ifr, arg, sizeof(struct ifreq))) return -EFAULT; @@ -3215,9 +3263,9 @@ int dev_ioctl(unsigned int cmd, void __user *arg) case SIOCGIFMAP: case SIOCGIFINDEX: case SIOCGIFTXQLEN: - dev_load(ifr.ifr_name); + dev_load(net, ifr.ifr_name); read_lock(&dev_base_lock); - ret = dev_ifsioc(&ifr, cmd); + ret = dev_ifsioc(net, &ifr, cmd); read_unlock(&dev_base_lock); if (!ret) { if (colon) @@ -3229,9 +3277,9 @@ int dev_ioctl(unsigned int cmd, void __user *arg) return ret; case SIOCETHTOOL: - dev_load(ifr.ifr_name); + dev_load(net, ifr.ifr_name); rtnl_lock(); - ret = dev_ethtool(&ifr); + ret = dev_ethtool(net, &ifr); rtnl_unlock(); if (!ret) { if (colon) @@ -3253,9 +3301,9 @@ int dev_ioctl(unsigned int cmd, void __user *arg) case SIOCSIFNAME: if (!capable(CAP_NET_ADMIN)) return -EPERM; - dev_load(ifr.ifr_name); + dev_load(net, ifr.ifr_name); rtnl_lock(); - ret = dev_ifsioc(&ifr, cmd); + ret = dev_ifsioc(net, &ifr, cmd); rtnl_unlock(); if (!ret) { if (colon) @@ -3294,9 +3342,9 @@ int dev_ioctl(unsigned int cmd, void __user *arg) /* fall through */ case SIOCBONDSLAVEINFOQUERY: case SIOCBONDINFOQUERY: - dev_load(ifr.ifr_name); + dev_load(net, ifr.ifr_name); rtnl_lock(); - ret = dev_ifsioc(&ifr, cmd); + ret = dev_ifsioc(net, &ifr, cmd); rtnl_unlock(); return ret; @@ -3316,9 +3364,9 @@ int dev_ioctl(unsigned int cmd, void __user *arg) if (cmd == SIOCWANDEV || (cmd >= SIOCDEVPRIVATE && cmd <= SIOCDEVPRIVATE + 15)) { - dev_load(ifr.ifr_name); + dev_load(net, ifr.ifr_name); rtnl_lock(); - ret = dev_ifsioc(&ifr, cmd); + ret = dev_ifsioc(net, &ifr, cmd); rtnl_unlock(); if (!ret && copy_to_user(arg, &ifr, sizeof(struct ifreq))) @@ -3327,7 +3375,7 @@ int dev_ioctl(unsigned int cmd, void __user *arg) } /* Take care of Wireless Extensions */ if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) - return wext_handle_ioctl(&ifr, cmd, arg); + return wext_handle_ioctl(net, &ifr, cmd, arg); return -EINVAL; } } @@ -3340,19 +3388,17 @@ int dev_ioctl(unsigned int cmd, void __user *arg) * number. The caller must hold the rtnl semaphore or the * dev_base_lock to be sure it remains unique. */ -static int dev_new_index(void) +static int dev_new_index(struct net *net) { static int ifindex; for (;;) { if (++ifindex <= 0) ifindex = 1; - if (!__dev_get_by_index(ifindex)) + if (!__dev_get_by_index(net, ifindex)) return ifindex; } } -static int dev_boot_phase = 1; - /* Delayed registration/unregisteration */ static DEFINE_SPINLOCK(net_todo_list_lock); static struct list_head net_todo_list = LIST_HEAD_INIT(net_todo_list); @@ -3386,6 +3432,7 @@ int register_netdevice(struct net_device *dev) struct hlist_head *head; struct hlist_node *p; int ret; + struct net *net; BUG_ON(dev_boot_phase); ASSERT_RTNL(); @@ -3394,6 +3441,8 @@ int register_netdevice(struct net_device *dev) /* When net_device's are persistent, this will be fatal. */ BUG_ON(dev->reg_state != NETREG_UNINITIALIZED); + BUG_ON(!dev->nd_net); + net = dev->nd_net; spin_lock_init(&dev->queue_lock); spin_lock_init(&dev->_xmit_lock); @@ -3418,12 +3467,12 @@ int register_netdevice(struct net_device *dev) goto err_uninit; } - dev->ifindex = dev_new_index(); + dev->ifindex = dev_new_index(net); if (dev->iflink == -1) dev->iflink = dev->ifindex; /* Check for existence of name */ - head = dev_name_hash(dev->name); + head = dev_name_hash(net, dev->name); hlist_for_each(p, head) { struct net_device *d = hlist_entry(p, struct net_device, name_hlist); @@ -3501,9 +3550,9 @@ int register_netdevice(struct net_device *dev) dev_init_scheduler(dev); write_lock_bh(&dev_base_lock); - list_add_tail(&dev->dev_list, &dev_base_head); + list_add_tail(&dev->dev_list, &net->dev_base_head); hlist_add_head(&dev->name_hlist, head); - hlist_add_head(&dev->index_hlist, dev_index_hash(dev->ifindex)); + hlist_add_head(&dev->index_hlist, dev_index_hash(net, dev->ifindex)); dev_hold(dev); write_unlock_bh(&dev_base_lock); @@ -4067,6 +4116,45 @@ int netdev_compute_features(unsigned long all, unsigned long one) } EXPORT_SYMBOL(netdev_compute_features); +/* Initialize per network namespace state */ +static int netdev_init(struct net *net) +{ + int i; + INIT_LIST_HEAD(&net->dev_base_head); + rwlock_init(&dev_base_lock); + + net->dev_name_head = kmalloc( + sizeof(*net->dev_name_head)*NETDEV_HASHENTRIES, GFP_KERNEL); + if (!net->dev_name_head) + return -ENOMEM; + + net->dev_index_head = kmalloc( + sizeof(*net->dev_index_head)*NETDEV_HASHENTRIES, GFP_KERNEL); + if (!net->dev_index_head) { + kfree(net->dev_name_head); + return -ENOMEM; + } + + for (i = 0; i < NETDEV_HASHENTRIES; i++) + INIT_HLIST_HEAD(&net->dev_name_head[i]); + + for (i = 0; i < NETDEV_HASHENTRIES; i++) + INIT_HLIST_HEAD(&net->dev_index_head[i]); + + return 0; +} + +static void netdev_exit(struct net *net) +{ + kfree(net->dev_name_head); + kfree(net->dev_index_head); +} + +static struct pernet_operations netdev_net_ops = { + .init = netdev_init, + .exit = netdev_exit, +}; + /* * Initialize the DEV module. At boot time this walks the device list and * unhooks any devices that fail to initialise (normally hardware not @@ -4094,11 +4182,8 @@ static int __init net_dev_init(void) for (i = 0; i < 16; i++) INIT_LIST_HEAD(&ptype_base[i]); - for (i = 0; i < ARRAY_SIZE(dev_name_head); i++) - INIT_HLIST_HEAD(&dev_name_head[i]); - - for (i = 0; i < ARRAY_SIZE(dev_index_head); i++) - INIT_HLIST_HEAD(&dev_index_head[i]); + if (register_pernet_subsys(&netdev_net_ops)) + goto out; /* * Initialise the packet receive queues. diff --git a/net/core/dev_mcast.c b/net/core/dev_mcast.c index 8e069fc207c..1c4f6198459 100644 --- a/net/core/dev_mcast.c +++ b/net/core/dev_mcast.c @@ -187,11 +187,12 @@ EXPORT_SYMBOL(dev_mc_unsync); #ifdef CONFIG_PROC_FS static void *dev_mc_seq_start(struct seq_file *seq, loff_t *pos) { + struct net *net = seq->private; struct net_device *dev; loff_t off = 0; read_lock(&dev_base_lock); - for_each_netdev(dev) { + for_each_netdev(net, dev) { if (off++ == *pos) return dev; } @@ -240,7 +241,22 @@ static const struct seq_operations dev_mc_seq_ops = { static int dev_mc_seq_open(struct inode *inode, struct file *file) { - return seq_open(file, &dev_mc_seq_ops); + struct seq_file *seq; + int res; + res = seq_open(file, &dev_mc_seq_ops); + if (!res) { + seq = file->private_data; + seq->private = get_net(PROC_NET(inode)); + } + return res; +} + +static int dev_mc_seq_release(struct inode *inode, struct file *file) +{ + struct seq_file *seq = file->private_data; + struct net *net = seq->private; + put_net(net); + return seq_release(inode, file); } static const struct file_operations dev_mc_seq_fops = { @@ -248,14 +264,31 @@ static const struct file_operations dev_mc_seq_fops = { .open = dev_mc_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release, + .release = dev_mc_seq_release, }; #endif +static int dev_mc_net_init(struct net *net) +{ + if (!proc_net_fops_create(net, "dev_mcast", 0, &dev_mc_seq_fops)) + return -ENOMEM; + return 0; +} + +static void dev_mc_net_exit(struct net *net) +{ + proc_net_remove(net, "dev_mcast"); +} + +static struct pernet_operations dev_mc_net_ops = { + .init = dev_mc_net_init, + .exit = dev_mc_net_exit, +}; + void __init dev_mcast_init(void) { - proc_net_fops_create(&init_net, "dev_mcast", 0, &dev_mc_seq_fops); + register_pernet_subsys(&dev_mc_net_ops); } EXPORT_SYMBOL(dev_mc_add); diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 7c43f032a7f..0d0b13cc1dd 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -779,9 +779,9 @@ static int ethtool_set_value(struct net_device *dev, char __user *useraddr, /* The main entry point in this file. Called from net/core/dev.c */ -int dev_ethtool(struct ifreq *ifr) +int dev_ethtool(struct net *net, struct ifreq *ifr) { - struct net_device *dev = __dev_get_by_name(ifr->ifr_name); + struct net_device *dev = __dev_get_by_name(net, ifr->ifr_name); void __user *useraddr = ifr->ifr_data; u32 ethcmd; int rc; diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index 9eabe1ae01d..1ba71baf87e 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c @@ -12,6 +12,7 @@ #include #include #include +#include #include static LIST_HEAD(rules_ops); @@ -198,6 +199,7 @@ errout: static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) { + struct net *net = skb->sk->sk_net; struct fib_rule_hdr *frh = nlmsg_data(nlh); struct fib_rules_ops *ops = NULL; struct fib_rule *rule, *r, *last = NULL; @@ -235,7 +237,7 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) rule->ifindex = -1; nla_strlcpy(rule->ifname, tb[FRA_IFNAME], IFNAMSIZ); - dev = __dev_get_by_name(rule->ifname); + dev = __dev_get_by_name(net, rule->ifname); if (dev) rule->ifindex = dev->ifindex; } diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 5f25f4f79b8..2c6577c1eed 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -1441,6 +1441,7 @@ int neigh_table_clear(struct neigh_table *tbl) static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { + struct net *net = skb->sk->sk_net; struct ndmsg *ndm; struct nlattr *dst_attr; struct neigh_table *tbl; @@ -1456,7 +1457,7 @@ static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) ndm = nlmsg_data(nlh); if (ndm->ndm_ifindex) { - dev = dev_get_by_index(ndm->ndm_ifindex); + dev = dev_get_by_index(net, ndm->ndm_ifindex); if (dev == NULL) { err = -ENODEV; goto out; @@ -1506,6 +1507,7 @@ out: static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { + struct net *net = skb->sk->sk_net; struct ndmsg *ndm; struct nlattr *tb[NDA_MAX+1]; struct neigh_table *tbl; @@ -1522,7 +1524,7 @@ static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) ndm = nlmsg_data(nlh); if (ndm->ndm_ifindex) { - dev = dev_get_by_index(ndm->ndm_ifindex); + dev = dev_get_by_index(net, ndm->ndm_ifindex); if (dev == NULL) { err = -ENODEV; goto out; diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 0952f936b29..bb7523a5b40 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -653,7 +653,7 @@ int netpoll_setup(struct netpoll *np) int err; if (np->dev_name) - ndev = dev_get_by_name(np->dev_name); + ndev = dev_get_by_name(&init_net, np->dev_name); if (!ndev) { printk(KERN_ERR "%s: %s doesn't exist, aborting.\n", np->name, np->dev_name); diff --git a/net/core/pktgen.c b/net/core/pktgen.c index d7c30ce095a..94e42be16da 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -2008,7 +2008,7 @@ static int pktgen_setup_dev(struct pktgen_dev *pkt_dev, const char *ifname) pkt_dev->odev = NULL; } - odev = dev_get_by_name(ifname); + odev = dev_get_by_name(&init_net, ifname); if (!odev) { printk(KERN_ERR "pktgen: no such netdevice: \"%s\"\n", ifname); return -ENODEV; diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 416768d1e0c..44f91bb1ae8 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -306,10 +306,13 @@ EXPORT_SYMBOL_GPL(rtnl_link_register); void __rtnl_link_unregister(struct rtnl_link_ops *ops) { struct net_device *dev, *n; + struct net *net; - for_each_netdev_safe(dev, n) { - if (dev->rtnl_link_ops == ops) - ops->dellink(dev); + for_each_net(net) { + for_each_netdev_safe(net, dev, n) { + if (dev->rtnl_link_ops == ops) + ops->dellink(dev); + } } list_del(&ops->list); } @@ -693,12 +696,13 @@ nla_put_failure: static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) { + struct net *net = skb->sk->sk_net; int idx; int s_idx = cb->args[0]; struct net_device *dev; idx = 0; - for_each_netdev(dev) { + for_each_netdev(net, dev) { if (idx < s_idx) goto cont; if (rtnl_fill_ifinfo(skb, dev, RTM_NEWLINK, @@ -858,6 +862,7 @@ errout: static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { + struct net *net = skb->sk->sk_net; struct ifinfomsg *ifm; struct net_device *dev; int err; @@ -876,9 +881,9 @@ static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) err = -EINVAL; ifm = nlmsg_data(nlh); if (ifm->ifi_index > 0) - dev = dev_get_by_index(ifm->ifi_index); + dev = dev_get_by_index(net, ifm->ifi_index); else if (tb[IFLA_IFNAME]) - dev = dev_get_by_name(ifname); + dev = dev_get_by_name(net, ifname); else goto errout; @@ -904,6 +909,7 @@ errout: static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { + struct net *net = skb->sk->sk_net; const struct rtnl_link_ops *ops; struct net_device *dev; struct ifinfomsg *ifm; @@ -920,9 +926,9 @@ static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) ifm = nlmsg_data(nlh); if (ifm->ifi_index > 0) - dev = __dev_get_by_index(ifm->ifi_index); + dev = __dev_get_by_index(net, ifm->ifi_index); else if (tb[IFLA_IFNAME]) - dev = __dev_get_by_name(ifname); + dev = __dev_get_by_name(net, ifname); else return -EINVAL; @@ -937,7 +943,7 @@ static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) return 0; } -struct net_device *rtnl_create_link(char *ifname, +struct net_device *rtnl_create_link(struct net *net, char *ifname, const struct rtnl_link_ops *ops, struct nlattr *tb[]) { int err; @@ -954,6 +960,7 @@ struct net_device *rtnl_create_link(char *ifname, goto err_free; } + dev->nd_net = net; dev->rtnl_link_ops = ops; if (tb[IFLA_MTU]) @@ -981,6 +988,7 @@ err: static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { + struct net *net = skb->sk->sk_net; const struct rtnl_link_ops *ops; struct net_device *dev; struct ifinfomsg *ifm; @@ -1004,9 +1012,9 @@ replay: ifm = nlmsg_data(nlh); if (ifm->ifi_index > 0) - dev = __dev_get_by_index(ifm->ifi_index); + dev = __dev_get_by_index(net, ifm->ifi_index); else if (ifname[0]) - dev = __dev_get_by_name(ifname); + dev = __dev_get_by_name(net, ifname); else dev = NULL; @@ -1092,7 +1100,7 @@ replay: if (!ifname[0]) snprintf(ifname, IFNAMSIZ, "%s%%d", ops->kind); - dev = rtnl_create_link(ifname, ops, tb); + dev = rtnl_create_link(net, ifname, ops, tb); if (IS_ERR(dev)) err = PTR_ERR(dev); @@ -1109,6 +1117,7 @@ replay: static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) { + struct net *net = skb->sk->sk_net; struct ifinfomsg *ifm; struct nlattr *tb[IFLA_MAX+1]; struct net_device *dev = NULL; @@ -1121,7 +1130,7 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) ifm = nlmsg_data(nlh); if (ifm->ifi_index > 0) { - dev = dev_get_by_index(ifm->ifi_index); + dev = dev_get_by_index(net, ifm->ifi_index); if (dev == NULL) return -ENODEV; } else diff --git a/net/core/sock.c b/net/core/sock.c index a31455dc702..4ed9b507c1e 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -367,6 +367,7 @@ static int sock_bindtodevice(struct sock *sk, char __user *optval, int optlen) { int ret = -ENOPROTOOPT; #ifdef CONFIG_NETDEVICES + struct net *net = sk->sk_net; char devname[IFNAMSIZ]; int index; @@ -395,7 +396,7 @@ static int sock_bindtodevice(struct sock *sk, char __user *optval, int optlen) if (devname[0] == '\0') { index = 0; } else { - struct net_device *dev = dev_get_by_name(devname); + struct net_device *dev = dev_get_by_name(net, devname); ret = -ENODEV; if (!dev) diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c index 83398da5d76..aabe98d9402 100644 --- a/net/decnet/af_decnet.c +++ b/net/decnet/af_decnet.c @@ -751,7 +751,7 @@ static int dn_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) if (dn_ntohs(saddr->sdn_nodeaddrl)) { read_lock(&dev_base_lock); ldev = NULL; - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { if (!dev->dn_ptr) continue; if (dn_dev_islocal(dev, dn_saddr2dn(saddr))) { diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c index 83cb0761336..ddfd2aff44d 100644 --- a/net/decnet/dn_dev.c +++ b/net/decnet/dn_dev.c @@ -513,7 +513,7 @@ int dn_dev_ioctl(unsigned int cmd, void __user *arg) ifr->ifr_name[IFNAMSIZ-1] = 0; #ifdef CONFIG_KMOD - dev_load(ifr->ifr_name); + dev_load(&init_net, ifr->ifr_name); #endif switch(cmd) { @@ -531,7 +531,7 @@ int dn_dev_ioctl(unsigned int cmd, void __user *arg) rtnl_lock(); - if ((dev = __dev_get_by_name(ifr->ifr_name)) == NULL) { + if ((dev = __dev_get_by_name(&init_net, ifr->ifr_name)) == NULL) { ret = -ENODEV; goto done; } @@ -629,7 +629,7 @@ static struct dn_dev *dn_dev_by_index(int ifindex) { struct net_device *dev; struct dn_dev *dn_dev = NULL; - dev = dev_get_by_index(ifindex); + dev = dev_get_by_index(&init_net, ifindex); if (dev) { dn_dev = dev->dn_ptr; dev_put(dev); @@ -694,7 +694,7 @@ static int dn_nl_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) return -EINVAL; ifm = nlmsg_data(nlh); - if ((dev = __dev_get_by_index(ifm->ifa_index)) == NULL) + if ((dev = __dev_get_by_index(&init_net, ifm->ifa_index)) == NULL) return -ENODEV; if ((dn_db = dev->dn_ptr) == NULL) { @@ -800,7 +800,7 @@ static int dn_nl_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) skip_naddr = cb->args[1]; idx = 0; - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { if (idx < skip_ndevs) goto cont; else if (idx > skip_ndevs) { @@ -1297,7 +1297,7 @@ void dn_dev_devices_off(void) struct net_device *dev; rtnl_lock(); - for_each_netdev(dev) + for_each_netdev(&init_net, dev) dn_dev_down(dev); rtnl_unlock(); @@ -1308,7 +1308,7 @@ void dn_dev_devices_on(void) struct net_device *dev; rtnl_lock(); - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { if (dev->flags & IFF_UP) dn_dev_up(dev); } @@ -1342,7 +1342,7 @@ static void *dn_dev_seq_start(struct seq_file *seq, loff_t *pos) return SEQ_START_TOKEN; i = 1; - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { if (!is_dn_dev(dev)) continue; @@ -1361,9 +1361,9 @@ static void *dn_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) dev = (struct net_device *)v; if (v == SEQ_START_TOKEN) - dev = net_device_entry(&dev_base_head); + dev = net_device_entry(&init_net.dev_base_head); - for_each_netdev_continue(dev) { + for_each_netdev_continue(&init_net, dev) { if (!is_dn_dev(dev)) continue; diff --git a/net/decnet/dn_fib.c b/net/decnet/dn_fib.c index d2bc19d4795..3760a20d10d 100644 --- a/net/decnet/dn_fib.c +++ b/net/decnet/dn_fib.c @@ -212,7 +212,7 @@ static int dn_fib_check_nh(const struct rtmsg *r, struct dn_fib_info *fi, struct return -EINVAL; if (dnet_addr_type(nh->nh_gw) != RTN_UNICAST) return -EINVAL; - if ((dev = __dev_get_by_index(nh->nh_oif)) == NULL) + if ((dev = __dev_get_by_index(&init_net, nh->nh_oif)) == NULL) return -ENODEV; if (!(dev->flags&IFF_UP)) return -ENETDOWN; @@ -255,7 +255,7 @@ out: if (nh->nh_flags&(RTNH_F_PERVASIVE|RTNH_F_ONLINK)) return -EINVAL; - dev = __dev_get_by_index(nh->nh_oif); + dev = __dev_get_by_index(&init_net, nh->nh_oif); if (dev == NULL || dev->dn_ptr == NULL) return -ENODEV; if (!(dev->flags&IFF_UP)) @@ -355,7 +355,7 @@ struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, struct dn_kern_rta if (nhs != 1 || nh->nh_gw) goto err_inval; nh->nh_scope = RT_SCOPE_NOWHERE; - nh->nh_dev = dev_get_by_index(fi->fib_nh->nh_oif); + nh->nh_dev = dev_get_by_index(&init_net, fi->fib_nh->nh_oif); err = -ENODEV; if (nh->nh_dev == NULL) goto failure; @@ -602,7 +602,7 @@ static void dn_fib_del_ifaddr(struct dn_ifaddr *ifa) /* Scan device list */ read_lock(&dev_base_lock); - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { dn_db = dev->dn_ptr; if (dn_db == NULL) continue; diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index 580e786d0c3..70b1c3fa00f 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -908,7 +908,7 @@ static int dn_route_output_slow(struct dst_entry **pprt, const struct flowi *old /* If we have an output interface, verify its a DECnet device */ if (oldflp->oif) { - dev_out = dev_get_by_index(oldflp->oif); + dev_out = dev_get_by_index(&init_net, oldflp->oif); err = -ENODEV; if (dev_out && dev_out->dn_ptr == NULL) { dev_put(dev_out); @@ -929,7 +929,7 @@ static int dn_route_output_slow(struct dst_entry **pprt, const struct flowi *old goto out; } read_lock(&dev_base_lock); - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { if (!dev->dn_ptr) continue; if (!dn_dev_islocal(dev, oldflp->fld_src)) @@ -1556,7 +1556,7 @@ static int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void if (fl.iif) { struct net_device *dev; - if ((dev = dev_get_by_index(fl.iif)) == NULL) { + if ((dev = dev_get_by_index(&init_net, fl.iif)) == NULL) { kfree_skb(skb); return -ENODEV; } diff --git a/net/decnet/sysctl_net_decnet.c b/net/decnet/sysctl_net_decnet.c index 52e40d7eb22..ae354a43fb9 100644 --- a/net/decnet/sysctl_net_decnet.c +++ b/net/decnet/sysctl_net_decnet.c @@ -259,7 +259,7 @@ static int dn_def_dev_strategy(ctl_table *table, int __user *name, int nlen, devname[newlen] = 0; - dev = dev_get_by_name(devname); + dev = dev_get_by_name(&init_net, devname); if (dev == NULL) return -ENODEV; @@ -299,7 +299,7 @@ static int dn_def_dev_handler(ctl_table *table, int write, devname[*lenp] = 0; strip_it(devname); - dev = dev_get_by_name(devname); + dev = dev_get_by_name(&init_net, devname); if (dev == NULL) return -ENODEV; diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c index f877f3b5c72..9938e76a8ff 100644 --- a/net/econet/af_econet.c +++ b/net/econet/af_econet.c @@ -662,7 +662,7 @@ static int ec_dev_ioctl(struct socket *sock, unsigned int cmd, void __user *arg) if (copy_from_user(&ifr, arg, sizeof(struct ifreq))) return -EFAULT; - if ((dev = dev_get_by_name(ifr.ifr_name)) == NULL) + if ((dev = dev_get_by_name(&init_net, ifr.ifr_name)) == NULL) return -ENODEV; sec = (struct sockaddr_ec *)&ifr.ifr_addr; diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index a11e7a5c1da..3a683006d76 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -981,7 +981,7 @@ static int arp_req_set(struct arpreq *r, struct net_device * dev) if (mask && mask != htonl(0xFFFFFFFF)) return -EINVAL; if (!dev && (r->arp_flags & ATF_COM)) { - dev = dev_getbyhwaddr(r->arp_ha.sa_family, r->arp_ha.sa_data); + dev = dev_getbyhwaddr(&init_net, r->arp_ha.sa_family, r->arp_ha.sa_data); if (!dev) return -ENODEV; } @@ -1169,7 +1169,7 @@ int arp_ioctl(unsigned int cmd, void __user *arg) rtnl_lock(); if (r.arp_dev[0]) { err = -ENODEV; - if ((dev = __dev_get_by_name(r.arp_dev)) == NULL) + if ((dev = __dev_get_by_name(&init_net, r.arp_dev)) == NULL) goto out; /* Mmmm... It is wrong... ARPHRD_NETROM==0 */ diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index c5eb1a29a5c..721b89b6096 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -420,7 +420,7 @@ struct in_device *inetdev_by_index(int ifindex) struct net_device *dev; struct in_device *in_dev = NULL; read_lock(&dev_base_lock); - dev = __dev_get_by_index(ifindex); + dev = __dev_get_by_index(&init_net, ifindex); if (dev) in_dev = in_dev_get(dev); read_unlock(&dev_base_lock); @@ -506,7 +506,7 @@ static struct in_ifaddr *rtm_to_ifaddr(struct nlmsghdr *nlh) goto errout; } - dev = __dev_get_by_index(ifm->ifa_index); + dev = __dev_get_by_index(&init_net, ifm->ifa_index); if (dev == NULL) { err = -ENODEV; goto errout; @@ -628,7 +628,7 @@ int devinet_ioctl(unsigned int cmd, void __user *arg) *colon = 0; #ifdef CONFIG_KMOD - dev_load(ifr.ifr_name); + dev_load(&init_net, ifr.ifr_name); #endif switch (cmd) { @@ -669,7 +669,7 @@ int devinet_ioctl(unsigned int cmd, void __user *arg) rtnl_lock(); ret = -ENODEV; - if ((dev = __dev_get_by_name(ifr.ifr_name)) == NULL) + if ((dev = __dev_get_by_name(&init_net, ifr.ifr_name)) == NULL) goto done; if (colon) @@ -909,7 +909,7 @@ no_in_dev: */ read_lock(&dev_base_lock); rcu_read_lock(); - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { if ((in_dev = __in_dev_get_rcu(dev)) == NULL) continue; @@ -988,7 +988,7 @@ __be32 inet_confirm_addr(const struct net_device *dev, __be32 dst, __be32 local, read_lock(&dev_base_lock); rcu_read_lock(); - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { if ((in_dev = __in_dev_get_rcu(dev))) { addr = confirm_addr_indev(in_dev, dst, local, scope); if (addr) @@ -1185,7 +1185,7 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) s_ip_idx = ip_idx = cb->args[1]; idx = 0; - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { if (idx < s_idx) goto cont; if (idx > s_idx) @@ -1244,7 +1244,7 @@ static void devinet_copy_dflt_conf(int i) struct net_device *dev; read_lock(&dev_base_lock); - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { struct in_device *in_dev; rcu_read_lock(); in_dev = __in_dev_get_rcu(dev); @@ -1333,7 +1333,7 @@ void inet_forward_change(void) IPV4_DEVCONF_DFLT(FORWARDING) = on; read_lock(&dev_base_lock); - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { struct in_device *in_dev; rcu_read_lock(); in_dev = __in_dev_get_rcu(dev); diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 140bf7a8d87..df17aab193b 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -334,7 +334,7 @@ static int rtentry_to_fib_config(int cmd, struct rtentry *rt, colon = strchr(devname, ':'); if (colon) *colon = 0; - dev = __dev_get_by_name(devname); + dev = __dev_get_by_name(&init_net, devname); if (!dev) return -ENODEV; cfg->fc_oif = dev->ifindex; diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index c434119deb5..d30fb68d5f4 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -533,7 +533,7 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi, return -EINVAL; if (inet_addr_type(nh->nh_gw) != RTN_UNICAST) return -EINVAL; - if ((dev = __dev_get_by_index(nh->nh_oif)) == NULL) + if ((dev = __dev_get_by_index(&init_net, nh->nh_oif)) == NULL) return -ENODEV; if (!(dev->flags&IFF_UP)) return -ENETDOWN; @@ -799,7 +799,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg) if (nhs != 1 || nh->nh_gw) goto err_inval; nh->nh_scope = RT_SCOPE_NOWHERE; - nh->nh_dev = dev_get_by_index(fi->fib_nh->nh_oif); + nh->nh_dev = dev_get_by_index(&init_net, fi->fib_nh->nh_oif); err = -ENODEV; if (nh->nh_dev == NULL) goto failure; diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 02a899bec19..68a22670f59 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -517,7 +517,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) struct net_device *dev = NULL; if (rt->fl.iif && sysctl_icmp_errors_use_inbound_ifaddr) - dev = dev_get_by_index(rt->fl.iif); + dev = dev_get_by_index(&init_net, rt->fl.iif); if (dev) { saddr = inet_select_addr(dev, 0, RT_SCOPE_LINK); diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index d78599a9dbd..ad500a43b35 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -2292,7 +2292,7 @@ static inline struct ip_mc_list *igmp_mc_get_first(struct seq_file *seq) struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq); state->in_dev = NULL; - for_each_netdev(state->dev) { + for_each_netdev(&init_net, state->dev) { struct in_device *in_dev; in_dev = in_dev_get(state->dev); if (!in_dev) @@ -2454,7 +2454,7 @@ static inline struct ip_sf_list *igmp_mcf_get_first(struct seq_file *seq) state->idev = NULL; state->im = NULL; - for_each_netdev(state->dev) { + for_each_netdev(&init_net, state->dev) { struct in_device *idev; idev = in_dev_get(state->dev); if (unlikely(idev == NULL)) diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 0231bdcb2ab..fabb86db763 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -292,7 +292,7 @@ static void ip_expire(unsigned long arg) if ((qp->last_in&FIRST_IN) && qp->fragments != NULL) { struct sk_buff *head = qp->fragments; /* Send an ICMP "Fragment Reassembly Timeout" message. */ - if ((head->dev = dev_get_by_index(qp->iif)) != NULL) { + if ((head->dev = dev_get_by_index(&init_net, qp->iif)) != NULL) { icmp_send(head, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0); dev_put(head->dev); } diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 5c14ed63e56..3106225c5e5 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -262,7 +262,7 @@ static struct ip_tunnel * ipgre_tunnel_locate(struct ip_tunnel_parm *parms, int int i; for (i=1; i<100; i++) { sprintf(name, "gre%d", i); - if (__dev_get_by_name(name) == NULL) + if (__dev_get_by_name(&init_net, name) == NULL) break; } if (i==100) @@ -1196,7 +1196,7 @@ static int ipgre_tunnel_init(struct net_device *dev) } if (!tdev && tunnel->parms.link) - tdev = __dev_get_by_index(tunnel->parms.link); + tdev = __dev_get_by_index(&init_net, tunnel->parms.link); if (tdev) { hlen = tdev->hard_header_len; diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 6b420aedcdc..b2b3053dfef 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -602,7 +602,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, dev_put(dev); } } else - dev = __dev_get_by_index(mreq.imr_ifindex); + dev = __dev_get_by_index(&init_net, mreq.imr_ifindex); err = -EADDRNOTAVAIL; diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index 08ff623371f..4303851749f 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -193,7 +193,7 @@ static int __init ic_open_devs(void) if (dev_change_flags(&loopback_dev, loopback_dev.flags | IFF_UP) < 0) printk(KERN_ERR "IP-Config: Failed to open %s\n", loopback_dev.name); - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { if (dev == &loopback_dev) continue; if (user_dev_name[0] ? !strcmp(dev->name, user_dev_name) : diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 396437242a1..652bd86e33a 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -225,7 +225,7 @@ static struct ip_tunnel * ipip_tunnel_locate(struct ip_tunnel_parm *parms, int c int i; for (i=1; i<100; i++) { sprintf(name, "tunl%d", i); - if (__dev_get_by_name(name) == NULL) + if (__dev_get_by_name(&init_net, name) == NULL) break; } if (i==100) @@ -822,7 +822,7 @@ static int ipip_tunnel_init(struct net_device *dev) } if (!tdev && tunnel->parms.link) - tdev = __dev_get_by_index(tunnel->parms.link); + tdev = __dev_get_by_index(&init_net, tunnel->parms.link); if (tdev) { dev->hard_header_len = tdev->hard_header_len + sizeof(struct iphdr); diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 036598835c6..b8b4b497fb5 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -125,7 +125,7 @@ struct net_device *ipmr_new_tunnel(struct vifctl *v) { struct net_device *dev; - dev = __dev_get_by_name("tunl0"); + dev = __dev_get_by_name(&init_net, "tunl0"); if (dev) { int err; @@ -149,7 +149,7 @@ struct net_device *ipmr_new_tunnel(struct vifctl *v) dev = NULL; - if (err == 0 && (dev = __dev_get_by_name(p.name)) != NULL) { + if (err == 0 && (dev = __dev_get_by_name(&init_net, p.name)) != NULL) { dev->flags |= IFF_MULTICAST; in_dev = __in_dev_get_rtnl(dev); diff --git a/net/ipv4/ipvs/ip_vs_sync.c b/net/ipv4/ipvs/ip_vs_sync.c index 356f067484e..1960747f354 100644 --- a/net/ipv4/ipvs/ip_vs_sync.c +++ b/net/ipv4/ipvs/ip_vs_sync.c @@ -387,7 +387,7 @@ static int set_mcast_if(struct sock *sk, char *ifname) struct net_device *dev; struct inet_sock *inet = inet_sk(sk); - if ((dev = __dev_get_by_name(ifname)) == NULL) + if ((dev = __dev_get_by_name(&init_net, ifname)) == NULL) return -ENODEV; if (sk->sk_bound_dev_if && dev->ifindex != sk->sk_bound_dev_if) @@ -412,7 +412,7 @@ static int set_sync_mesg_maxlen(int sync_state) int num; if (sync_state == IP_VS_STATE_MASTER) { - if ((dev = __dev_get_by_name(ip_vs_master_mcast_ifn)) == NULL) + if ((dev = __dev_get_by_name(&init_net, ip_vs_master_mcast_ifn)) == NULL) return -ENODEV; num = (dev->mtu - sizeof(struct iphdr) - @@ -423,7 +423,7 @@ static int set_sync_mesg_maxlen(int sync_state) IP_VS_DBG(7, "setting the maximum length of sync sending " "message %d.\n", sync_send_mesg_maxlen); } else if (sync_state == IP_VS_STATE_BACKUP) { - if ((dev = __dev_get_by_name(ip_vs_backup_mcast_ifn)) == NULL) + if ((dev = __dev_get_by_name(&init_net, ip_vs_backup_mcast_ifn)) == NULL) return -ENODEV; sync_recv_mesg_maxlen = dev->mtu - @@ -451,7 +451,7 @@ join_mcast_group(struct sock *sk, struct in_addr *addr, char *ifname) memset(&mreq, 0, sizeof(mreq)); memcpy(&mreq.imr_multiaddr, addr, sizeof(struct in_addr)); - if ((dev = __dev_get_by_name(ifname)) == NULL) + if ((dev = __dev_get_by_name(&init_net, ifname)) == NULL) return -ENODEV; if (sk->sk_bound_dev_if && dev->ifindex != sk->sk_bound_dev_if) return -EINVAL; @@ -472,7 +472,7 @@ static int bind_mcastif_addr(struct socket *sock, char *ifname) __be32 addr; struct sockaddr_in sin; - if ((dev = __dev_get_by_name(ifname)) == NULL) + if ((dev = __dev_get_by_name(&init_net, ifname)) == NULL) return -ENODEV; addr = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE); diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c index 50fc9e009fe..27f14e1ebd8 100644 --- a/net/ipv4/netfilter/ipt_CLUSTERIP.c +++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c @@ -401,7 +401,7 @@ checkentry(const char *tablename, return false; } - dev = dev_get_by_name(e->ip.iniface); + dev = dev_get_by_name(&init_net, e->ip.iniface); if (!dev) { printk(KERN_WARNING "CLUSTERIP: no such interface %s\n", e->ip.iniface); return false; diff --git a/net/ipv4/route.c b/net/ipv4/route.c index efd2a9202d6..396c631166a 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -2213,7 +2213,7 @@ static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp) if (oldflp->oif) { - dev_out = dev_get_by_index(oldflp->oif); + dev_out = dev_get_by_index(&init_net, oldflp->oif); err = -ENODEV; if (dev_out == NULL) goto out; @@ -2592,7 +2592,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void if (iif) { struct net_device *dev; - dev = __dev_get_by_index(iif); + dev = __dev_get_by_index(&init_net, iif); if (dev == NULL) { err = -ENODEV; goto errout_free; diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 1a678364652..ee55be97540 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -450,7 +450,7 @@ static void addrconf_forward_change(void) struct inet6_dev *idev; read_lock(&dev_base_lock); - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { rcu_read_lock(); idev = __in6_dev_get(dev); if (idev) { @@ -912,7 +912,7 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev, read_lock(&dev_base_lock); rcu_read_lock(); - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { struct inet6_dev *idev; struct inet6_ifaddr *ifa; @@ -1858,7 +1858,7 @@ int addrconf_set_dstaddr(void __user *arg) if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq))) goto err_exit; - dev = __dev_get_by_index(ireq.ifr6_ifindex); + dev = __dev_get_by_index(&init_net, ireq.ifr6_ifindex); err = -ENODEV; if (dev == NULL) @@ -1889,7 +1889,7 @@ int addrconf_set_dstaddr(void __user *arg) if (err == 0) { err = -ENOBUFS; - if ((dev = __dev_get_by_name(p.name)) == NULL) + if ((dev = __dev_get_by_name(&init_net, p.name)) == NULL) goto err_exit; err = dev_open(dev); } @@ -1919,7 +1919,7 @@ static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen, if (!valid_lft || prefered_lft > valid_lft) return -EINVAL; - if ((dev = __dev_get_by_index(ifindex)) == NULL) + if ((dev = __dev_get_by_index(&init_net, ifindex)) == NULL) return -ENODEV; if ((idev = addrconf_add_dev(dev)) == NULL) @@ -1970,7 +1970,7 @@ static int inet6_addr_del(int ifindex, struct in6_addr *pfx, int plen) struct inet6_dev *idev; struct net_device *dev; - if ((dev = __dev_get_by_index(ifindex)) == NULL) + if ((dev = __dev_get_by_index(&init_net, ifindex)) == NULL) return -ENODEV; if ((idev = __in6_dev_get(dev)) == NULL) @@ -2065,7 +2065,7 @@ static void sit_add_v4_addrs(struct inet6_dev *idev) return; } - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { struct in_device * in_dev = __in_dev_get_rtnl(dev); if (in_dev && (dev->flags & IFF_UP)) { struct in_ifaddr * ifa; @@ -2221,12 +2221,12 @@ static void ip6_tnl_add_linklocal(struct inet6_dev *idev) /* first try to inherit the link-local address from the link device */ if (idev->dev->iflink && - (link_dev = __dev_get_by_index(idev->dev->iflink))) { + (link_dev = __dev_get_by_index(&init_net, idev->dev->iflink))) { if (!ipv6_inherit_linklocal(idev, link_dev)) return; } /* then try to inherit it from any device */ - for_each_netdev(link_dev) { + for_each_netdev(&init_net, link_dev) { if (!ipv6_inherit_linklocal(idev, link_dev)) return; } @@ -3084,7 +3084,7 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) valid_lft = INFINITY_LIFE_TIME; } - dev = __dev_get_by_index(ifm->ifa_index); + dev = __dev_get_by_index(&init_net, ifm->ifa_index); if (dev == NULL) return -ENODEV; @@ -3268,7 +3268,7 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, s_ip_idx = ip_idx = cb->args[1]; idx = 0; - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { if (idx < s_idx) goto cont; if (idx > s_idx) @@ -3377,7 +3377,7 @@ static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr* nlh, ifm = nlmsg_data(nlh); if (ifm->ifa_index) - dev = __dev_get_by_index(ifm->ifa_index); + dev = __dev_get_by_index(&init_net, ifm->ifa_index); if ((ifa = ipv6_get_ifaddr(addr, dev, 1)) == NULL) { err = -EADDRNOTAVAIL; @@ -3589,7 +3589,7 @@ static int inet6_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) read_lock(&dev_base_lock); idx = 0; - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { if (idx < s_idx) goto cont; if ((idev = in6_dev_get(dev)) == NULL) @@ -4266,7 +4266,7 @@ void __exit addrconf_cleanup(void) * clean dev list. */ - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { if (__in6_dev_get(dev) == NULL) continue; addrconf_ifdown(dev, 1); diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 21931c86e95..e5c5aad44bb 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -302,7 +302,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) err = -EINVAL; goto out; } - dev = dev_get_by_index(sk->sk_bound_dev_if); + dev = dev_get_by_index(&init_net, sk->sk_bound_dev_if); if (!dev) { err = -ENODEV; goto out; diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c index 0bd665498d0..d407992c148 100644 --- a/net/ipv6/anycast.c +++ b/net/ipv6/anycast.c @@ -112,10 +112,10 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, struct in6_addr *addr) } else { /* router, no matching interface: just pick one */ - dev = dev_get_by_flags(IFF_UP, IFF_UP|IFF_LOOPBACK); + dev = dev_get_by_flags(&init_net, IFF_UP, IFF_UP|IFF_LOOPBACK); } } else - dev = dev_get_by_index(ifindex); + dev = dev_get_by_index(&init_net, ifindex); if (dev == NULL) { err = -ENODEV; @@ -196,7 +196,7 @@ int ipv6_sock_ac_drop(struct sock *sk, int ifindex, struct in6_addr *addr) write_unlock_bh(&ipv6_sk_ac_lock); - dev = dev_get_by_index(pac->acl_ifindex); + dev = dev_get_by_index(&init_net, pac->acl_ifindex); if (dev) { ipv6_dev_ac_dec(dev, &pac->acl_addr); dev_put(dev); @@ -224,7 +224,7 @@ void ipv6_sock_ac_close(struct sock *sk) if (pac->acl_ifindex != prev_index) { if (dev) dev_put(dev); - dev = dev_get_by_index(pac->acl_ifindex); + dev = dev_get_by_index(&init_net, pac->acl_ifindex); prev_index = pac->acl_ifindex; } if (dev) @@ -429,7 +429,7 @@ int ipv6_chk_acast_addr(struct net_device *dev, struct in6_addr *addr) if (dev) return ipv6_chk_acast_dev(dev, addr); read_lock(&dev_base_lock); - for_each_netdev(dev) + for_each_netdev(&init_net, dev) if (ipv6_chk_acast_dev(dev, addr)) { found = 1; break; @@ -453,7 +453,7 @@ static inline struct ifacaddr6 *ac6_get_first(struct seq_file *seq) struct ac6_iter_state *state = ac6_seq_private(seq); state->idev = NULL; - for_each_netdev(state->dev) { + for_each_netdev(&init_net, state->dev) { struct inet6_dev *idev; idev = in6_dev_get(state->dev); if (!idev) diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index fe0f49024a0..2ed689ac449 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c @@ -544,7 +544,7 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl, if (!src_info->ipi6_ifindex) return -EINVAL; else { - dev = dev_get_by_index(src_info->ipi6_ifindex); + dev = dev_get_by_index(&init_net, src_info->ipi6_ifindex); if (!dev) return -ENODEV; } diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index ca774d8e3be..937625e577c 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -235,7 +235,7 @@ static struct ip6_tnl *ip6_tnl_create(struct ip6_tnl_parm *p) int i; for (i = 1; i < IP6_TNL_MAX; i++) { sprintf(name, "ip6tnl%d", i); - if (__dev_get_by_name(name) == NULL) + if (__dev_get_by_name(&init_net, name) == NULL) break; } if (i == IP6_TNL_MAX) @@ -650,7 +650,7 @@ static inline int ip6_tnl_rcv_ctl(struct ip6_tnl *t) struct net_device *ldev = NULL; if (p->link) - ldev = dev_get_by_index(p->link); + ldev = dev_get_by_index(&init_net, p->link); if ((ipv6_addr_is_multicast(&p->laddr) || likely(ipv6_chk_addr(&p->laddr, ldev, 0))) && @@ -786,7 +786,7 @@ static inline int ip6_tnl_xmit_ctl(struct ip6_tnl *t) struct net_device *ldev = NULL; if (p->link) - ldev = dev_get_by_index(p->link); + ldev = dev_get_by_index(&init_net, p->link); if (unlikely(!ipv6_chk_addr(&p->laddr, ldev, 0))) printk(KERN_WARNING diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 74254fccbcc..eb330a44bac 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -542,7 +542,7 @@ done: if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != val) goto e_inval; - if (__dev_get_by_index(val) == NULL) { + if (__dev_get_by_index(&init_net, val) == NULL) { retv = -ENODEV; break; } diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index a41d5a0b50c..e2ab43c989d 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -215,7 +215,7 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, struct in6_addr *addr) dst_release(&rt->u.dst); } } else - dev = dev_get_by_index(ifindex); + dev = dev_get_by_index(&init_net, ifindex); if (dev == NULL) { sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); @@ -266,7 +266,7 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, struct in6_addr *addr) *lnk = mc_lst->next; write_unlock_bh(&ipv6_sk_mc_lock); - if ((dev = dev_get_by_index(mc_lst->ifindex)) != NULL) { + if ((dev = dev_get_by_index(&init_net, mc_lst->ifindex)) != NULL) { struct inet6_dev *idev = in6_dev_get(dev); (void) ip6_mc_leave_src(sk, mc_lst, idev); @@ -301,7 +301,7 @@ static struct inet6_dev *ip6_mc_find_dev(struct in6_addr *group, int ifindex) dst_release(&rt->u.dst); } } else - dev = dev_get_by_index(ifindex); + dev = dev_get_by_index(&init_net, ifindex); if (!dev) return NULL; @@ -332,7 +332,7 @@ void ipv6_sock_mc_close(struct sock *sk) np->ipv6_mc_list = mc_lst->next; write_unlock_bh(&ipv6_sk_mc_lock); - dev = dev_get_by_index(mc_lst->ifindex); + dev = dev_get_by_index(&init_net, mc_lst->ifindex); if (dev) { struct inet6_dev *idev = in6_dev_get(dev); @@ -2333,7 +2333,7 @@ static inline struct ifmcaddr6 *igmp6_mc_get_first(struct seq_file *seq) struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq); state->idev = NULL; - for_each_netdev(state->dev) { + for_each_netdev(&init_net, state->dev) { struct inet6_dev *idev; idev = in6_dev_get(state->dev); if (!idev) @@ -2477,7 +2477,7 @@ static inline struct ip6_sf_list *igmp6_mcf_get_first(struct seq_file *seq) state->idev = NULL; state->im = NULL; - for_each_netdev(state->dev) { + for_each_netdev(&init_net, state->dev) { struct inet6_dev *idev; idev = in6_dev_get(state->dev); if (unlikely(idev == NULL)) diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 38a3d21c258..bdd0974e677 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -283,7 +283,7 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) if (!sk->sk_bound_dev_if) goto out; - dev = dev_get_by_index(sk->sk_bound_dev_if); + dev = dev_get_by_index(&init_net, sk->sk_bound_dev_if); if (!dev) { err = -ENODEV; goto out; diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index de795c04e34..31601c99354 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -301,7 +301,7 @@ static void ip6_frag_expire(unsigned long data) fq_kill(fq); - dev = dev_get_by_index(fq->iif); + dev = dev_get_by_index(&init_net, fq->iif); if (!dev) goto out; diff --git a/net/ipv6/route.c b/net/ipv6/route.c index f4f0c341e5c..5bdd9d4010f 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1130,7 +1130,7 @@ int ip6_route_add(struct fib6_config *cfg) #endif if (cfg->fc_ifindex) { err = -ENODEV; - dev = dev_get_by_index(cfg->fc_ifindex); + dev = dev_get_by_index(&init_net, cfg->fc_ifindex); if (!dev) goto out; idev = in6_dev_get(dev); @@ -2265,7 +2265,7 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void if (iif) { struct net_device *dev; - dev = __dev_get_by_index(iif); + dev = __dev_get_by_index(&init_net, iif); if (!dev) { err = -ENODEV; goto errout; diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index eb20bb690ab..e79f419b173 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -167,7 +167,7 @@ static struct ip_tunnel * ipip6_tunnel_locate(struct ip_tunnel_parm *parms, int int i; for (i=1; i<100; i++) { sprintf(name, "sit%d", i); - if (__dev_get_by_name(name) == NULL) + if (__dev_get_by_name(&init_net, name) == NULL) break; } if (i==100) @@ -761,7 +761,7 @@ static int ipip6_tunnel_init(struct net_device *dev) } if (!tdev && tunnel->parms.link) - tdev = __dev_get_by_index(tunnel->parms.link); + tdev = __dev_get_by_index(&init_net, tunnel->parms.link); if (tdev) { dev->hard_header_len = tdev->hard_header_len + sizeof(struct iphdr); diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c index 24921f12e9a..29b063d4312 100644 --- a/net/ipx/af_ipx.c +++ b/net/ipx/af_ipx.c @@ -989,7 +989,7 @@ static int ipxitf_create(struct ipx_interface_definition *idef) if (intrfc) ipxitf_put(intrfc); - dev = dev_get_by_name(idef->ipx_device); + dev = dev_get_by_name(&init_net, idef->ipx_device); rc = -ENODEV; if (!dev) goto out; @@ -1097,7 +1097,7 @@ static int ipxitf_delete(struct ipx_interface_definition *idef) if (!dlink_type) goto out; - dev = __dev_get_by_name(idef->ipx_device); + dev = __dev_get_by_name(&init_net, idef->ipx_device); rc = -ENODEV; if (!dev) goto out; @@ -1192,7 +1192,7 @@ static int ipxitf_ioctl(unsigned int cmd, void __user *arg) if (copy_from_user(&ifr, arg, sizeof(ifr))) break; sipx = (struct sockaddr_ipx *)&ifr.ifr_addr; - dev = __dev_get_by_name(ifr.ifr_name); + dev = __dev_get_by_name(&init_net, ifr.ifr_name); rc = -ENODEV; if (!dev) break; diff --git a/net/irda/irnetlink.c b/net/irda/irnetlink.c index 1e429c92973..cd9ff176ecd 100644 --- a/net/irda/irnetlink.c +++ b/net/irda/irnetlink.c @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -30,7 +31,7 @@ static struct genl_family irda_nl_family = { .maxattr = IRDA_NL_CMD_MAX, }; -static struct net_device * ifname_to_netdev(struct genl_info *info) +static struct net_device * ifname_to_netdev(struct net *net, struct genl_info *info) { char * ifname; @@ -41,7 +42,7 @@ static struct net_device * ifname_to_netdev(struct genl_info *info) IRDA_DEBUG(5, "%s(): Looking for %s\n", __FUNCTION__, ifname); - return dev_get_by_name(ifname); + return dev_get_by_name(net, ifname); } static int irda_nl_set_mode(struct sk_buff *skb, struct genl_info *info) @@ -57,7 +58,7 @@ static int irda_nl_set_mode(struct sk_buff *skb, struct genl_info *info) IRDA_DEBUG(5, "%s(): Switching to mode: %d\n", __FUNCTION__, mode); - dev = ifname_to_netdev(info); + dev = ifname_to_netdev(&init_net, info); if (!dev) return -ENODEV; @@ -82,7 +83,7 @@ static int irda_nl_get_mode(struct sk_buff *skb, struct genl_info *info) void *hdr; int ret = -ENOBUFS; - dev = ifname_to_netdev(info); + dev = ifname_to_netdev(&init_net, info); if (!dev) return -ENODEV; diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index b48244156e7..49eacba824d 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -252,7 +252,7 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr) if (!sock_flag(sk, SOCK_ZAPPED)) goto out; rc = -ENODEV; - llc->dev = dev_getfirstbyhwtype(addr->sllc_arphrd); + llc->dev = dev_getfirstbyhwtype(&init_net, addr->sllc_arphrd); if (!llc->dev) goto out; rc = -EUSERS; @@ -303,7 +303,7 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen) goto out; rc = -ENODEV; rtnl_lock(); - llc->dev = dev_getbyhwaddr(addr->sllc_arphrd, addr->sllc_mac); + llc->dev = dev_getbyhwaddr(&init_net, addr->sllc_arphrd, addr->sllc_mac); rtnl_unlock(); if (!llc->dev) goto out; diff --git a/net/llc/llc_core.c b/net/llc/llc_core.c index d4b13a031fd..248b5903bb1 100644 --- a/net/llc/llc_core.c +++ b/net/llc/llc_core.c @@ -19,6 +19,7 @@ #include #include #include +#include #include LIST_HEAD(llc_sap_list); @@ -162,7 +163,7 @@ static int __init llc_init(void) { struct net_device *dev; - dev = first_net_device(); + dev = first_net_device(&init_net); if (dev != NULL) dev = next_net_device(dev); diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 73e314e33de..506cfa06b18 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "ieee80211_common.h" diff --git a/net/mac80211/ieee80211_cfg.c b/net/mac80211/ieee80211_cfg.c index 509096edb32..b1c13bc9c3c 100644 --- a/net/mac80211/ieee80211_cfg.c +++ b/net/mac80211/ieee80211_cfg.c @@ -8,6 +8,7 @@ #include #include +#include #include #include "ieee80211_i.h" #include "ieee80211_cfg.h" @@ -50,7 +51,7 @@ static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex) if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED)) return -ENODEV; - dev = dev_get_by_index(ifindex); + dev = dev_get_by_index(&init_net, ifindex); if (!dev) return 0; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index b65ff653624..9e952e37b7d 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -1018,7 +1019,7 @@ static int inline ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, struct net_device *dev; pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; - dev = dev_get_by_index(pkt_data->ifindex); + dev = dev_get_by_index(&init_net, pkt_data->ifindex); if (unlikely(dev && !is_ieee80211_device(dev, mdev))) { dev_put(dev); dev = NULL; @@ -1226,7 +1227,7 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, memset(&control, 0, sizeof(struct ieee80211_tx_control)); if (pkt_data->ifindex) - odev = dev_get_by_index(pkt_data->ifindex); + odev = dev_get_by_index(&init_net, pkt_data->ifindex); if (unlikely(odev && !is_ieee80211_device(odev, dev))) { dev_put(odev); odev = NULL; @@ -1722,7 +1723,7 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, int if_id, u8 *b_head, *b_tail; int bh_len, bt_len; - bdev = dev_get_by_index(if_id); + bdev = dev_get_by_index(&init_net, if_id); if (bdev) { sdata = IEEE80211_DEV_TO_SUB_IF(bdev); ap = &sdata->u.ap; @@ -1836,7 +1837,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, int if_id, struct ieee80211_sub_if_data *sdata; struct ieee80211_if_ap *bss = NULL; - bdev = dev_get_by_index(if_id); + bdev = dev_get_by_index(&init_net, if_id); if (bdev) { sdata = IEEE80211_DEV_TO_SUB_IF(bdev); bss = &sdata->u.ap; diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 07686bda26c..c970996ba6f 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include "ieee80211_i.h" @@ -318,7 +319,7 @@ __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, int if_id, size_t frame_len, int rate) { struct ieee80211_local *local = hw_to_local(hw); - struct net_device *bdev = dev_get_by_index(if_id); + struct net_device *bdev = dev_get_by_index(&init_net, if_id); struct ieee80211_sub_if_data *sdata; u16 dur; int erp; @@ -342,7 +343,7 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, int if_id, { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_rate *rate; - struct net_device *bdev = dev_get_by_index(if_id); + struct net_device *bdev = dev_get_by_index(&init_net, if_id); struct ieee80211_sub_if_data *sdata; int short_preamble; int erp; @@ -378,7 +379,7 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, int if_id, { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_rate *rate; - struct net_device *bdev = dev_get_by_index(if_id); + struct net_device *bdev = dev_get_by_index(&init_net, if_id); struct ieee80211_sub_if_data *sdata; int short_preamble; int erp; diff --git a/net/netrom/nr_route.c b/net/netrom/nr_route.c index 24fe4a66d29..e943c16552a 100644 --- a/net/netrom/nr_route.c +++ b/net/netrom/nr_route.c @@ -580,7 +580,7 @@ static struct net_device *nr_ax25_dev_get(char *devname) { struct net_device *dev; - if ((dev = dev_get_by_name(devname)) == NULL) + if ((dev = dev_get_by_name(&init_net, devname)) == NULL) return NULL; if ((dev->flags & IFF_UP) && dev->type == ARPHRD_AX25) @@ -598,7 +598,7 @@ struct net_device *nr_dev_first(void) struct net_device *dev, *first = NULL; read_lock(&dev_base_lock); - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM) if (first == NULL || strncmp(dev->name, first->name, 3) < 0) first = dev; @@ -618,7 +618,7 @@ struct net_device *nr_dev_get(ax25_address *addr) struct net_device *dev; read_lock(&dev_base_lock); - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM && ax25cmp(addr, (ax25_address *)dev->dev_addr) == 0) { dev_hold(dev); goto out; diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index ad0052524e8..745e2cb87c9 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -347,7 +347,7 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock, */ saddr->spkt_device[13] = 0; - dev = dev_get_by_name(saddr->spkt_device); + dev = dev_get_by_name(&init_net, saddr->spkt_device); err = -ENODEV; if (dev == NULL) goto out_unlock; @@ -742,7 +742,7 @@ static int packet_sendmsg(struct kiocb *iocb, struct socket *sock, } - dev = dev_get_by_index(ifindex); + dev = dev_get_by_index(&init_net, ifindex); err = -ENXIO; if (dev == NULL) goto out_unlock; @@ -937,7 +937,7 @@ static int packet_bind_spkt(struct socket *sock, struct sockaddr *uaddr, int add return -EINVAL; strlcpy(name,uaddr->sa_data,sizeof(name)); - dev = dev_get_by_name(name); + dev = dev_get_by_name(&init_net, name); if (dev) { err = packet_do_bind(sk, dev, pkt_sk(sk)->num); dev_put(dev); @@ -964,7 +964,7 @@ static int packet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len if (sll->sll_ifindex) { err = -ENODEV; - dev = dev_get_by_index(sll->sll_ifindex); + dev = dev_get_by_index(&init_net, sll->sll_ifindex); if (dev == NULL) goto out; } @@ -1161,7 +1161,7 @@ static int packet_getname_spkt(struct socket *sock, struct sockaddr *uaddr, return -EOPNOTSUPP; uaddr->sa_family = AF_PACKET; - dev = dev_get_by_index(pkt_sk(sk)->ifindex); + dev = dev_get_by_index(&init_net, pkt_sk(sk)->ifindex); if (dev) { strlcpy(uaddr->sa_data, dev->name, 15); dev_put(dev); @@ -1186,7 +1186,7 @@ static int packet_getname(struct socket *sock, struct sockaddr *uaddr, sll->sll_family = AF_PACKET; sll->sll_ifindex = po->ifindex; sll->sll_protocol = po->num; - dev = dev_get_by_index(po->ifindex); + dev = dev_get_by_index(&init_net, po->ifindex); if (dev) { sll->sll_hatype = dev->type; sll->sll_halen = dev->addr_len; @@ -1238,7 +1238,7 @@ static int packet_mc_add(struct sock *sk, struct packet_mreq_max *mreq) rtnl_lock(); err = -ENODEV; - dev = __dev_get_by_index(mreq->mr_ifindex); + dev = __dev_get_by_index(&init_net, mreq->mr_ifindex); if (!dev) goto done; @@ -1292,7 +1292,7 @@ static int packet_mc_drop(struct sock *sk, struct packet_mreq_max *mreq) if (--ml->count == 0) { struct net_device *dev; *mlp = ml->next; - dev = dev_get_by_index(ml->ifindex); + dev = dev_get_by_index(&init_net, ml->ifindex); if (dev) { packet_dev_mc(dev, ml, -1); dev_put(dev); @@ -1320,7 +1320,7 @@ static void packet_flush_mclist(struct sock *sk) struct net_device *dev; po->mclist = ml->next; - if ((dev = dev_get_by_index(ml->ifindex)) != NULL) { + if ((dev = dev_get_by_index(&init_net, ml->ifindex)) != NULL) { packet_dev_mc(dev, ml, -1); dev_put(dev); } diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c index 96f61a71b25..540c0f26ffe 100644 --- a/net/rose/rose_route.c +++ b/net/rose/rose_route.c @@ -583,7 +583,7 @@ static struct net_device *rose_ax25_dev_get(char *devname) { struct net_device *dev; - if ((dev = dev_get_by_name(devname)) == NULL) + if ((dev = dev_get_by_name(&init_net, devname)) == NULL) return NULL; if ((dev->flags & IFF_UP) && dev->type == ARPHRD_AX25) @@ -601,7 +601,7 @@ struct net_device *rose_dev_first(void) struct net_device *dev, *first = NULL; read_lock(&dev_base_lock); - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ROSE) if (first == NULL || strncmp(dev->name, first->name, 3) < 0) first = dev; @@ -619,7 +619,7 @@ struct net_device *rose_dev_get(rose_address *addr) struct net_device *dev; read_lock(&dev_base_lock); - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ROSE && rosecmp(addr, (rose_address *)dev->dev_addr) == 0) { dev_hold(dev); goto out; @@ -636,7 +636,7 @@ static int rose_dev_exists(rose_address *addr) struct net_device *dev; read_lock(&dev_base_lock); - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ROSE && rosecmp(addr, (rose_address *)dev->dev_addr) == 0) goto out; } diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c index 579578944ae..fd7bca4d5c2 100644 --- a/net/sched/act_mirred.c +++ b/net/sched/act_mirred.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -73,7 +74,7 @@ static int tcf_mirred_init(struct rtattr *rta, struct rtattr *est, parm = RTA_DATA(tb[TCA_MIRRED_PARMS-1]); if (parm->ifindex) { - dev = __dev_get_by_index(parm->ifindex); + dev = __dev_get_by_index(&init_net, parm->ifindex); if (dev == NULL) return -ENODEV; switch (dev->type) { diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 5f0fbca7393..03657976fd5 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -154,7 +154,7 @@ replay: /* Find head of filter chain. */ /* Find link */ - if ((dev = __dev_get_by_index(t->tcm_ifindex)) == NULL) + if ((dev = __dev_get_by_index(&init_net, t->tcm_ifindex)) == NULL) return -ENODEV; /* Find qdisc */ @@ -387,7 +387,7 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb) if (cb->nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*tcm))) return skb->len; - if ((dev = dev_get_by_index(tcm->tcm_ifindex)) == NULL) + if ((dev = dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL) return skb->len; if (!tcm->tcm_parent) diff --git a/net/sched/em_meta.c b/net/sched/em_meta.c index 650f09c8bd6..e9989610712 100644 --- a/net/sched/em_meta.c +++ b/net/sched/em_meta.c @@ -291,7 +291,7 @@ META_COLLECTOR(var_sk_bound_if) } else { struct net_device *dev; - dev = dev_get_by_index(skb->sk->sk_bound_dev_if); + dev = dev_get_by_index(&init_net, skb->sk->sk_bound_dev_if); *err = var_dev(dev, dst); if (dev) dev_put(dev); diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index efc383c58f1..39d32780c80 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -607,7 +607,7 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg) struct Qdisc *p = NULL; int err; - if ((dev = __dev_get_by_index(tcm->tcm_ifindex)) == NULL) + if ((dev = __dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL) return -ENODEV; if (clid) { @@ -674,7 +674,7 @@ replay: clid = tcm->tcm_parent; q = p = NULL; - if ((dev = __dev_get_by_index(tcm->tcm_ifindex)) == NULL) + if ((dev = __dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL) return -ENODEV; if (clid) { @@ -881,7 +881,7 @@ static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb) s_q_idx = q_idx = cb->args[1]; read_lock(&dev_base_lock); idx = 0; - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { if (idx < s_idx) goto cont; if (idx > s_idx) @@ -932,7 +932,7 @@ static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg) u32 qid = TC_H_MAJ(clid); int err; - if ((dev = __dev_get_by_index(tcm->tcm_ifindex)) == NULL) + if ((dev = __dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL) return -ENODEV; /* @@ -1115,7 +1115,7 @@ static int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb) if (cb->nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*tcm))) return 0; - if ((dev = dev_get_by_index(tcm->tcm_ifindex)) == NULL) + if ((dev = dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL) return 0; s_t = cb->args[0]; diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index ddeb4882ec7..9de3ddaa276 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -855,7 +855,7 @@ static int sctp_inet6_bind_verify(struct sctp_sock *opt, union sctp_addr *addr) if (type & IPV6_ADDR_LINKLOCAL) { if (!addr->v6.sin6_scope_id) return 0; - dev = dev_get_by_index(addr->v6.sin6_scope_id); + dev = dev_get_by_index(&init_net, addr->v6.sin6_scope_id); if (!dev) return 0; if (!ipv6_chk_addr(&addr->v6.sin6_addr, dev, 0)) { @@ -886,7 +886,7 @@ static int sctp_inet6_send_verify(struct sctp_sock *opt, union sctp_addr *addr) if (type & IPV6_ADDR_LINKLOCAL) { if (!addr->v6.sin6_scope_id) return 0; - dev = dev_get_by_index(addr->v6.sin6_scope_id); + dev = dev_get_by_index(&init_net, addr->v6.sin6_scope_id); if (!dev) return 0; dev_put(dev); diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index af67c839ef9..54edcd978f7 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -179,7 +179,7 @@ static void sctp_get_local_addr_list(void) struct sctp_af *af; read_lock(&dev_base_lock); - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { __list_for_each(pos, &sctp_address_families) { af = list_entry(pos, struct sctp_af, list); af->copy_addrlist(&sctp_local_addr_list, dev); diff --git a/net/socket.c b/net/socket.c index a714c6d4e4a..bc16eee4dc8 100644 --- a/net/socket.c +++ b/net/socket.c @@ -791,9 +791,9 @@ static ssize_t sock_aio_write(struct kiocb *iocb, const struct iovec *iov, */ static DEFINE_MUTEX(br_ioctl_mutex); -static int (*br_ioctl_hook) (unsigned int cmd, void __user *arg) = NULL; +static int (*br_ioctl_hook) (struct net *, unsigned int cmd, void __user *arg) = NULL; -void brioctl_set(int (*hook) (unsigned int, void __user *)) +void brioctl_set(int (*hook) (struct net *, unsigned int, void __user *)) { mutex_lock(&br_ioctl_mutex); br_ioctl_hook = hook; @@ -803,9 +803,9 @@ void brioctl_set(int (*hook) (unsigned int, void __user *)) EXPORT_SYMBOL(brioctl_set); static DEFINE_MUTEX(vlan_ioctl_mutex); -static int (*vlan_ioctl_hook) (void __user *arg); +static int (*vlan_ioctl_hook) (struct net *, void __user *arg); -void vlan_ioctl_set(int (*hook) (void __user *)) +void vlan_ioctl_set(int (*hook) (struct net *, void __user *)) { mutex_lock(&vlan_ioctl_mutex); vlan_ioctl_hook = hook; @@ -834,16 +834,20 @@ EXPORT_SYMBOL(dlci_ioctl_set); static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg) { struct socket *sock; + struct sock *sk; void __user *argp = (void __user *)arg; int pid, err; + struct net *net; sock = file->private_data; + sk = sock->sk; + net = sk->sk_net; if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) { - err = dev_ioctl(cmd, argp); + err = dev_ioctl(net, cmd, argp); } else #ifdef CONFIG_WIRELESS_EXT if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) { - err = dev_ioctl(cmd, argp); + err = dev_ioctl(net, cmd, argp); } else #endif /* CONFIG_WIRELESS_EXT */ switch (cmd) { @@ -869,7 +873,7 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg) mutex_lock(&br_ioctl_mutex); if (br_ioctl_hook) - err = br_ioctl_hook(cmd, argp); + err = br_ioctl_hook(net, cmd, argp); mutex_unlock(&br_ioctl_mutex); break; case SIOCGIFVLAN: @@ -880,7 +884,7 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg) mutex_lock(&vlan_ioctl_mutex); if (vlan_ioctl_hook) - err = vlan_ioctl_hook(argp); + err = vlan_ioctl_hook(net, argp); mutex_unlock(&vlan_ioctl_mutex); break; case SIOCADDDLCI: @@ -903,7 +907,7 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg) * to the NIC driver. */ if (err == -ENOIOCTLCMD) - err = dev_ioctl(cmd, argp); + err = dev_ioctl(net, cmd, argp); break; } return err; diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c index 406f0d26fa8..d6fc0575816 100644 --- a/net/tipc/eth_media.c +++ b/net/tipc/eth_media.c @@ -135,7 +135,7 @@ static int enable_bearer(struct tipc_bearer *tb_ptr) /* Find device with specified name */ - for_each_netdev(pdev){ + for_each_netdev(&init_net, pdev){ if (!strncmp(pdev->name, driver_name, IFNAMSIZ)) { dev = pdev; break; diff --git a/net/wireless/wext.c b/net/wireless/wext.c index b8069afe041..e8b3409d6c8 100644 --- a/net/wireless/wext.c +++ b/net/wireless/wext.c @@ -673,7 +673,22 @@ static const struct seq_operations wireless_seq_ops = { static int wireless_seq_open(struct inode *inode, struct file *file) { - return seq_open(file, &wireless_seq_ops); + struct seq_file *seq; + int res; + res = seq_open(file, &wireless_seq_ops); + if (!res) { + seq = file->private_data; + seq->private = get_net(PROC_NET(inode)); + } + return res; +} + +static int wireless_seq_release(struct inode *inode, struct file *file) +{ + struct seq_file *seq = file->private_data; + struct net *net = seq->private; + put_net(net); + return seq_release(inode, file); } static const struct file_operations wireless_seq_fops = { @@ -681,17 +696,22 @@ static const struct file_operations wireless_seq_fops = { .open = wireless_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release, + .release = wireless_seq_release, }; -int __init wext_proc_init(void) +int wext_proc_init(struct net *net) { /* Create /proc/net/wireless entry */ - if (!proc_net_fops_create(&init_net, "wireless", S_IRUGO, &wireless_seq_fops)) + if (!proc_net_fops_create(net, "wireless", S_IRUGO, &wireless_seq_fops)) return -ENOMEM; return 0; } + +void wext_proc_exit(struct net *net) +{ + proc_net_remove(net, "wireless"); +} #endif /* CONFIG_PROC_FS */ /************************** IOCTL SUPPORT **************************/ @@ -1011,7 +1031,7 @@ static int ioctl_private_call(struct net_device *dev, struct ifreq *ifr, * Main IOCTl dispatcher. * Check the type of IOCTL and call the appropriate wrapper... */ -static int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd) +static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd) { struct net_device *dev; iw_handler handler; @@ -1020,7 +1040,7 @@ static int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd) * The copy_to/from_user() of ifr is also dealt with in there */ /* Make sure the device exist */ - if ((dev = __dev_get_by_name(ifr->ifr_name)) == NULL) + if ((dev = __dev_get_by_name(net, ifr->ifr_name)) == NULL) return -ENODEV; /* A bunch of special cases, then the generic case... @@ -1054,7 +1074,7 @@ static int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd) } /* entry point from dev ioctl */ -int wext_handle_ioctl(struct ifreq *ifr, unsigned int cmd, +int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd, void __user *arg) { int ret; @@ -1066,9 +1086,9 @@ int wext_handle_ioctl(struct ifreq *ifr, unsigned int cmd, && !capable(CAP_NET_ADMIN)) return -EPERM; - dev_load(ifr->ifr_name); + dev_load(net, ifr->ifr_name); rtnl_lock(); - ret = wireless_process_ioctl(ifr, cmd); + ret = wireless_process_ioctl(net, ifr, cmd); rtnl_unlock(); if (IW_IS_GET(cmd) && copy_to_user(arg, ifr, sizeof(struct ifreq))) return -EFAULT; diff --git a/net/x25/x25_route.c b/net/x25/x25_route.c index 060fcfaa2f4..86b5b4da097 100644 --- a/net/x25/x25_route.c +++ b/net/x25/x25_route.c @@ -129,7 +129,7 @@ void x25_route_device_down(struct net_device *dev) */ struct net_device *x25_dev_get(char *devname) { - struct net_device *dev = dev_get_by_name(devname); + struct net_device *dev = dev_get_by_name(&init_net, devname); if (dev && (!(dev->flags & IFF_UP) || (dev->type != ARPHRD_X25 -- cgit v1.2.3-70-g09d2 From ce286d327341295f58d89864d746a524287cfdf9 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 12 Sep 2007 13:53:49 +0200 Subject: [NET]: Implement network device movement between namespaces This patch introduces NETIF_F_NETNS_LOCAL a flag to indicate a network device is local to a single network namespace and should never be moved. Useful for pseudo devices that we need an instance in each network namespace (like the loopback device) and for any device we find that cannot handle multiple network namespaces so we may trap them in the initial network namespace. This patch introduces the function dev_change_net_namespace a function used to move a network device from one network namespace to another. To the network device nothing special appears to happen, to the components of the network stack it appears as if the network device was unregistered in the network namespace it is in, and a new device was registered in the network namespace the device was moved to. This patch sets up a namespace device destructor that upon the exit of a network namespace moves all of the movable network devices to the initial network namespace so they are not lost. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- drivers/net/loopback.c | 3 +- include/linux/netdevice.h | 3 + net/core/dev.c | 189 +++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 184 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 5106c2328d1..e399f7b201e 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -222,7 +222,8 @@ struct net_device loopback_dev = { | NETIF_F_TSO #endif | NETIF_F_NO_CSUM | NETIF_F_HIGHDMA - | NETIF_F_LLTX, + | NETIF_F_LLTX + | NETIF_F_NETNS_LOCAL, .ethtool_ops = &loopback_ethtool_ops, }; diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 7353b3e1f4f..407658c64fb 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -449,6 +449,7 @@ struct net_device #define NETIF_F_VLAN_CHALLENGED 1024 /* Device cannot handle VLAN packets */ #define NETIF_F_GSO 2048 /* Enable software GSO. */ #define NETIF_F_LLTX 4096 /* LockLess TX */ +#define NETIF_F_NETNS_LOCAL 8192 /* Does not change network namespaces */ #define NETIF_F_MULTI_QUEUE 16384 /* Has multiple TX/RX queues */ #define NETIF_F_LRO 32768 /* large receive offload */ @@ -1016,6 +1017,8 @@ extern int dev_ethtool(struct net *net, struct ifreq *); extern unsigned dev_get_flags(const struct net_device *); extern int dev_change_flags(struct net_device *, unsigned); extern int dev_change_name(struct net_device *, char *); +extern int dev_change_net_namespace(struct net_device *, + struct net *, const char *); extern int dev_set_mtu(struct net_device *, int); extern int dev_set_mac_address(struct net_device *, struct sockaddr *); diff --git a/net/core/dev.c b/net/core/dev.c index 520ef7b2086..215b8e97690 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -208,6 +208,34 @@ static inline struct hlist_head *dev_index_hash(struct net *net, int ifindex) return &net->dev_index_head[ifindex & ((1 << NETDEV_HASHBITS) - 1)]; } +/* Device list insertion */ +static int list_netdevice(struct net_device *dev) +{ + struct net *net = dev->nd_net; + + ASSERT_RTNL(); + + write_lock_bh(&dev_base_lock); + list_add_tail(&dev->dev_list, &net->dev_base_head); + hlist_add_head(&dev->name_hlist, dev_name_hash(net, dev->name)); + hlist_add_head(&dev->index_hlist, dev_index_hash(net, dev->ifindex)); + write_unlock_bh(&dev_base_lock); + return 0; +} + +/* Device list removal */ +static void unlist_netdevice(struct net_device *dev) +{ + ASSERT_RTNL(); + + /* Unlink dev from the device chain */ + write_lock_bh(&dev_base_lock); + list_del(&dev->dev_list); + hlist_del(&dev->name_hlist); + hlist_del(&dev->index_hlist); + write_unlock_bh(&dev_base_lock); +} + /* * Our notifier list */ @@ -3571,12 +3599,8 @@ int register_netdevice(struct net_device *dev) set_bit(__LINK_STATE_PRESENT, &dev->state); dev_init_scheduler(dev); - write_lock_bh(&dev_base_lock); - list_add_tail(&dev->dev_list, &net->dev_base_head); - hlist_add_head(&dev->name_hlist, head); - hlist_add_head(&dev->index_hlist, dev_index_hash(net, dev->ifindex)); dev_hold(dev); - write_unlock_bh(&dev_base_lock); + list_netdevice(dev); /* Notify protocols, that a new device appeared. */ ret = raw_notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev); @@ -3883,11 +3907,7 @@ void unregister_netdevice(struct net_device *dev) dev_close(dev); /* And unlink it from device chain. */ - write_lock_bh(&dev_base_lock); - list_del(&dev->dev_list); - hlist_del(&dev->name_hlist); - hlist_del(&dev->index_hlist); - write_unlock_bh(&dev_base_lock); + unlist_netdevice(dev); dev->reg_state = NETREG_UNREGISTERING; @@ -3945,6 +3965,122 @@ void unregister_netdev(struct net_device *dev) EXPORT_SYMBOL(unregister_netdev); +/** + * dev_change_net_namespace - move device to different nethost namespace + * @dev: device + * @net: network namespace + * @pat: If not NULL name pattern to try if the current device name + * is already taken in the destination network namespace. + * + * This function shuts down a device interface and moves it + * to a new network namespace. On success 0 is returned, on + * a failure a netagive errno code is returned. + * + * Callers must hold the rtnl semaphore. + */ + +int dev_change_net_namespace(struct net_device *dev, struct net *net, const char *pat) +{ + char buf[IFNAMSIZ]; + const char *destname; + int err; + + ASSERT_RTNL(); + + /* Don't allow namespace local devices to be moved. */ + err = -EINVAL; + if (dev->features & NETIF_F_NETNS_LOCAL) + goto out; + + /* Ensure the device has been registrered */ + err = -EINVAL; + if (dev->reg_state != NETREG_REGISTERED) + goto out; + + /* Get out if there is nothing todo */ + err = 0; + if (dev->nd_net == net) + goto out; + + /* Pick the destination device name, and ensure + * we can use it in the destination network namespace. + */ + err = -EEXIST; + destname = dev->name; + if (__dev_get_by_name(net, destname)) { + /* We get here if we can't use the current device name */ + if (!pat) + goto out; + if (!dev_valid_name(pat)) + goto out; + if (strchr(pat, '%')) { + if (__dev_alloc_name(net, pat, buf) < 0) + goto out; + destname = buf; + } else + destname = pat; + if (__dev_get_by_name(net, destname)) + goto out; + } + + /* + * And now a mini version of register_netdevice unregister_netdevice. + */ + + /* If device is running close it first. */ + if (dev->flags & IFF_UP) + dev_close(dev); + + /* And unlink it from device chain */ + err = -ENODEV; + unlist_netdevice(dev); + + synchronize_net(); + + /* Shutdown queueing discipline. */ + dev_shutdown(dev); + + /* Notify protocols, that we are about to destroy + this device. They should clean all the things. + */ + call_netdevice_notifiers(NETDEV_UNREGISTER, dev); + + /* + * Flush the unicast and multicast chains + */ + dev_addr_discard(dev); + + /* Actually switch the network namespace */ + dev->nd_net = net; + + /* Assign the new device name */ + if (destname != dev->name) + strcpy(dev->name, destname); + + /* If there is an ifindex conflict assign a new one */ + if (__dev_get_by_index(net, dev->ifindex)) { + int iflink = (dev->iflink == dev->ifindex); + dev->ifindex = dev_new_index(net); + if (iflink) + dev->iflink = dev->ifindex; + } + + /* Fixup sysfs */ + err = device_rename(&dev->dev, dev->name); + BUG_ON(err); + + /* Add the device back in the hashes */ + list_netdevice(dev); + + /* Notify protocols, that a new device appeared. */ + call_netdevice_notifiers(NETDEV_REGISTER, dev); + + synchronize_net(); + err = 0; +out: + return err; +} + static int dev_cpu_callback(struct notifier_block *nfb, unsigned long action, void *ocpu) @@ -4177,6 +4313,36 @@ static struct pernet_operations netdev_net_ops = { .exit = netdev_exit, }; +static void default_device_exit(struct net *net) +{ + struct net_device *dev, *next; + /* + * Push all migratable of the network devices back to the + * initial network namespace + */ + rtnl_lock(); + for_each_netdev_safe(net, dev, next) { + int err; + + /* Ignore unmoveable devices (i.e. loopback) */ + if (dev->features & NETIF_F_NETNS_LOCAL) + continue; + + /* Push remaing network devices to init_net */ + err = dev_change_net_namespace(dev, &init_net, "dev%d"); + if (err) { + printk(KERN_WARNING "%s: failed to move %s to init_net: %d\n", + __func__, dev->name, err); + unregister_netdevice(dev); + } + } + rtnl_unlock(); +} + +static struct pernet_operations default_device_ops = { + .exit = default_device_exit, +}; + /* * Initialize the DEV module. At boot time this walks the device list and * unhooks any devices that fail to initialise (normally hardware not @@ -4207,6 +4373,9 @@ static int __init net_dev_init(void) if (register_pernet_subsys(&netdev_net_ops)) goto out; + if (register_pernet_device(&default_device_ops)) + goto out; + /* * Initialise the packet receive queues. */ -- cgit v1.2.3-70-g09d2 From abf07acbb9f122218095d0d221e0f949160ccc37 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 12 Sep 2007 14:54:14 +0200 Subject: [NETNS]: Fix loopback network namespace initialization. The core patchset of the network namespace sent by Eric Biederman does not do dynamic loopback creation. So there is no call to alloc_netdev_mq which fills the network namespace field of the netdevice. This patch assign the loopback to the init network namespace. Signed-off-by: Daniel Lezcano Signed-off-by: David S. Miller --- drivers/net/loopback.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index e399f7b201e..a328da72833 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -225,6 +225,7 @@ struct net_device loopback_dev = { | NETIF_F_LLTX | NETIF_F_NETNS_LOCAL, .ethtool_ops = &loopback_ethtool_ops, + .nd_net = &init_net, }; /* Setup and register the loopback device. */ -- cgit v1.2.3-70-g09d2 From 7848ba7d7a010ccb265617fc2bc053e2bdf06f48 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 14 Sep 2007 11:10:25 -0400 Subject: [MAC80211]: rework hardware crypto flags This patch reworks the various hardware crypto related flags to make them more local, i.e. put them with each key or each packet instead of into the hw struct. Signed-off-by: Johannes Berg Acked-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/rtl8187_dev.c | 3 +-- include/net/mac80211.h | 49 ++++++++++++-------------------------- net/mac80211/rx.c | 24 ++++++++----------- net/mac80211/tx.c | 5 ++-- net/mac80211/wpa.c | 43 +++++++++++---------------------- 5 files changed, 42 insertions(+), 82 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index 9db9ece31b4..7dbf11e30db 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c @@ -605,8 +605,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, priv->modes[1].channels = priv->channels; priv->mode = IEEE80211_IF_TYPE_MGMT; dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_WEP_INCLUDE_IV; + IEEE80211_HW_RX_INCLUDES_FCS; dev->extra_tx_headroom = sizeof(struct rtl8187_tx_hdr); dev->queues = 1; dev->max_rssi = 65; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index fcb7e3f9c66..9137579c12a 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -240,6 +240,8 @@ struct ieee80211_rx_status { #define RX_FLAG_MMIC_ERROR (1<<0) #define RX_FLAG_DECRYPTED (1<<1) #define RX_FLAG_RADIOTAP (1<<2) +#define RX_FLAG_MMIC_STRIPPED (1<<3) +#define RX_FLAG_IV_STRIPPED (1<<4) int flag; }; @@ -402,6 +404,16 @@ typedef enum { * that situation it should reject that key. */ #define IEEE80211_KEY_FLAG_WMM_STA (1<<0) +/* + * This flag should be set by the driver if it requires + * IV generation in software for this key. + */ +#define IEEE80211_KEY_FLAG_GENERATE_IV (1<<1) +/* + * This flag should be set by the driver if it requires + * MMIC generation in software for this key. + */ +#define IEEE80211_KEY_FLAG_GENERATE_MMIC (1<<2) struct ieee80211_key_conf { /* @@ -465,17 +477,7 @@ struct ieee80211_hw { */ #define IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE (1<<1) - /* - * Some devices handle decryption internally and do not - * indicate whether the frame was encrypted (unencrypted frames - * will be dropped by the hardware, unless specifically allowed - * through.) - * It is permissible to not handle all encrypted frames and fall - * back to software encryption; however, if this flag is set - * unencrypted frames must be dropped unless the driver is told - * otherwise via the set_ieee8021x() callback. - */ -#define IEEE80211_HW_DEVICE_HIDES_WEP (1<<2) +/* hole at 2 */ /* Whether RX frames passed to ieee80211_rx() include FCS in the end */ #define IEEE80211_HW_RX_INCLUDES_FCS (1<<3) @@ -488,32 +490,13 @@ struct ieee80211_hw { * can fetch them with ieee80211_get_buffered_bc(). */ #define IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING (1<<4) - /* - * This flag is only relevant if hardware encryption is used. - * If set, it has two meanings: - * 1) the IV and ICV are present in received frames that have - * been decrypted (unless IEEE80211_HW_DEVICE_HIDES_WEP is - * also set) - * 2) on transmission, the IV should be generated in software. - * - * Please let us know if you *don't* use this flag, the stack would - * really like to be able to get the IV to keep key statistics - * accurate. - */ -#define IEEE80211_HW_WEP_INCLUDE_IV (1<<5) +/* hole at 5 */ /* hole at 6 */ /* hole at 7 */ - /* - * Some devices handle Michael MIC internally and do not include MIC in - * the received packets passed up. This flag must be set for such - * devices. The 'encryption' frame control bit is expected to be still - * set in the IEEE 802.11 header with this option unlike with the - * IEEE80211_HW_DEVICE_HIDES_WEP flag. - */ -#define IEEE80211_HW_DEVICE_STRIPS_MIC (1<<8) +/* hole at 8 */ /* Device is capable of performing full monitor mode even during * normal operation. */ @@ -527,8 +510,6 @@ struct ieee80211_hw { * specified in the device's EEPROM */ #define IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED (1<<11) - /* calculate Michael MIC for an MSDU when doing hwcrypto */ -#define IEEE80211_HW_TKIP_INCLUDE_MMIC (1<<12) /* Do TKIP phase1 key mixing in stack to support cards only do * phase2 key mixing when doing hwcrypto */ #define IEEE80211_HW_TKIP_REQ_PHASE1_KEY (1<<13) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 8c6e2908921..28b8b6af4c4 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -363,7 +363,8 @@ ieee80211_rx_h_load_key(struct ieee80211_txrx_data *rx) * we somehow allow the driver to tell us which key * the hardware used if this flag is set? */ - if (!(rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV)) + if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) && + (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED)) return TXRX_CONTINUE; hdrlen = ieee80211_get_hdrlen(rx->fc); @@ -534,8 +535,8 @@ ieee80211_rx_h_wep_weak_iv_detection(struct ieee80211_txrx_data *rx) return TXRX_CONTINUE; /* Check for weak IVs, if hwaccel did not remove IV from the frame */ - if ((rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) || - !(rx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) + if (!(rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED) || + !(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) if (ieee80211_wep_is_weak_iv(rx->skb, rx->key)) rx->sta->wep_weak_iv_count++; @@ -559,15 +560,14 @@ ieee80211_rx_h_wep_decrypt(struct ieee80211_txrx_data *rx) return TXRX_DROP; } - if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED) || - !(rx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) { + if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) { if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key)) { if (net_ratelimit()) printk(KERN_DEBUG "%s: RX WEP frame, decrypt " "failed\n", rx->dev->name); return TXRX_DROP; } - } else if (rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) { + } else if (!(rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED)) { ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key); /* remove ICV */ skb_trim(rx->skb, rx->skb->len - 4); @@ -898,13 +898,10 @@ static ieee80211_txrx_result ieee80211_rx_h_drop_unencrypted(struct ieee80211_txrx_data *rx) { /* - * Pass through unencrypted frames if the hardware might have - * decrypted them already without telling us, but that can only - * be true if we either didn't find a key or the found key is - * uploaded to the hardware. + * Pass through unencrypted frames if the hardware has + * decrypted them already. */ - if ((rx->local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP) && - (!rx->key || (rx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))) + if (rx->u.rx.status->flag & RX_FLAG_DECRYPTED) return TXRX_CONTINUE; /* Drop unencrypted frames if key is set. */ @@ -1212,8 +1209,7 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev, goto ignore; } - if ((rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) && - rx->sdata->type == IEEE80211_IF_TYPE_AP && keyidx) { + if (rx->sdata->type == IEEE80211_IF_TYPE_AP && keyidx) { /* AP with Pairwise keys support should never receive Michael * MIC errors for non-zero keyidx because these are reserved * for group keys and only the AP is sending real multicast diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 08d221674bc..e2ae1e1fcc7 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -545,9 +545,8 @@ static int wep_encrypt_skb(struct ieee80211_txrx_data *tx, struct sk_buff *skb) return -1; } else { tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx; - if (tx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) { - if (ieee80211_wep_add_iv(tx->local, skb, tx->key) == - NULL) + if (tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) { + if (!ieee80211_wep_add_iv(tx->local, skb, tx->key)) return -1; } } diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 775f89e42a4..a23531cef5b 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -91,7 +91,7 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx) if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && !(tx->flags & IEEE80211_TXRXD_FRAGMENTED) && - !(tx->local->hw.flags & IEEE80211_HW_TKIP_INCLUDE_MMIC) && + !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) && !wpa_test) { /* hwaccel - with no need for preallocated room for Michael MIC */ @@ -138,26 +138,13 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx) /* * No way to verify the MIC if the hardware stripped it */ - if (rx->local->hw.flags & IEEE80211_HW_DEVICE_STRIPS_MIC) + if (rx->u.rx.status->flag & RX_FLAG_MMIC_STRIPPED) return TXRX_CONTINUE; if (!rx->key || rx->key->conf.alg != ALG_TKIP || !(rx->fc & IEEE80211_FCTL_PROTECTED) || !WLAN_FC_DATA_PRESENT(fc)) return TXRX_CONTINUE; - if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) && - (rx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) { - if (rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) { - if (skb->len < MICHAEL_MIC_LEN) - return TXRX_DROP; - } - /* Need to verify Michael MIC sometimes in software even when - * hwaccel is used. Atheros ar5212: fragmented frames and QoS - * frames. */ - if (!(rx->flags & IEEE80211_TXRXD_FRAGMENTED) && !wpa_test) - goto remove_mic; - } - if (ieee80211_get_hdr_info(skb, &sa, &da, &qos_tid, &data, &data_len) || data_len < MICHAEL_MIC_LEN) return TXRX_DROP; @@ -184,7 +171,6 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx) return TXRX_DROP; } - remove_mic: /* remove Michael MIC from payload */ skb_trim(skb, skb->len - MICHAEL_MIC_LEN); @@ -287,7 +273,7 @@ ieee80211_tx_h_tkip_encrypt(struct ieee80211_txrx_data *tx) ieee80211_tx_set_iswep(tx); if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && - !(tx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) && + !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) && !wpa_test) { /* hwaccel - with no need for preallocated room for IV/ICV */ tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx; @@ -330,11 +316,13 @@ ieee80211_rx_h_tkip_decrypt(struct ieee80211_txrx_data *rx) if (!rx->sta || skb->len - hdrlen < 12) return TXRX_DROP; - if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) && - (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) { - if (!(rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV)) { - /* Hardware takes care of all processing, including - * replay protection, so no need to continue here. */ + if (rx->u.rx.status->flag & RX_FLAG_DECRYPTED) { + if (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED) { + /* + * Hardware took care of all processing, including + * replay protection, and stripped the ICV/IV so + * we cannot do any checks here. + */ return TXRX_CONTINUE; } @@ -538,7 +526,7 @@ ieee80211_tx_h_ccmp_encrypt(struct ieee80211_txrx_data *tx) ieee80211_tx_set_iswep(tx); if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && - !(tx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV)) { + !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) { /* hwaccel - with no need for preallocated room for CCMP " * header or MIC fields */ tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx; @@ -585,8 +573,7 @@ ieee80211_rx_h_ccmp_decrypt(struct ieee80211_txrx_data *rx) return TXRX_DROP; if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) && - (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && - !(rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV)) + (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED)) return TXRX_CONTINUE; (void) ccmp_hdr2pn(pn, skb->data + hdrlen); @@ -605,10 +592,8 @@ ieee80211_rx_h_ccmp_decrypt(struct ieee80211_txrx_data *rx) return TXRX_DROP; } - if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) && - (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) { - /* hwaccel has already decrypted frame and verified MIC */ - } else { + if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) { + /* hardware didn't decrypt/verify MIC */ u8 *scratch, *b_0, *aad; scratch = key->u.ccmp.rx_crypto_buf; -- cgit v1.2.3-70-g09d2 From cc0b88cf5ecf13cdd750f08e201ce8fadcdb601f Mon Sep 17 00:00:00 2001 From: Michael Wu Date: Fri, 31 Aug 2007 01:15:25 -0400 Subject: [PATCH] Add adm8211 802.11b wireless driver This patch adds a mac80211 wireless driver for ADMtek ADM8211 based wireless cards. Signed-off-by: Michael Wu Signed-off-by: John W. Linville --- MAINTAINERS | 8 + drivers/net/wireless/Kconfig | 27 + drivers/net/wireless/Makefile | 2 + drivers/net/wireless/adm8211.c | 2063 ++++++++++++++++++++++++++++++++++++++++ drivers/net/wireless/adm8211.h | 659 +++++++++++++ 5 files changed, 2759 insertions(+) create mode 100644 drivers/net/wireless/adm8211.c create mode 100644 drivers/net/wireless/adm8211.h (limited to 'drivers') diff --git a/MAINTAINERS b/MAINTAINERS index 9a91d9e3f1f..e0861f7e1cc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -284,6 +284,14 @@ M: corentin.labbe@geomatys.fr L: lm-sensors@lm-sensors.org S: Maintained +ADM8211 WIRELESS DRIVER +P: Michael Wu +M: flamingice@sourmilk.net +L: linux-wireless@vger.kernel.org +W: http://linuxwireless.org/ +T: git kernel.org:/pub/scm/linux/kernel/git/mwu/mac80211-drivers.git +S: Maintained + ADT746X FAN DRIVER P: Colin Leroy M: colin@colino.net diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index ae27af0141c..86480afe535 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -558,6 +558,33 @@ config RTL8187 Thanks to Realtek for their support! +config ADM8211 + tristate "ADMtek ADM8211 support" + depends on MAC80211 && PCI && WLAN_80211 && EXPERIMENTAL + select CRC32 + select EEPROM_93CX6 + ---help--- + This driver is for ADM8211A, ADM8211B, and ADM8211C based cards. + These are PCI/mini-PCI/Cardbus 802.11b chips found in cards such as: + + Xterasys Cardbus XN-2411b + Blitz NetWave Point PC + TrendNet 221pc + Belkin F5D6001 + SMC 2635W + Linksys WPC11 v1 + Fiberline FL-WL-200X + 3com Office Connect (3CRSHPW796) + Corega WLPCIB-11 + SMC 2602W V2 EU + D-Link DWL-520 Revision C + + However, some of these cards have been replaced with other chips + like the RTL8180L (Xterasys Cardbus XN-2411b, Belkin F5D6001) or + the Ralink RT2400 (SMC2635W) without a model number change. + + Thanks to Infineon-ADMtek for their support of this driver. + source "drivers/net/wireless/hostap/Kconfig" source "drivers/net/wireless/bcm43xx/Kconfig" source "drivers/net/wireless/zd1211rw/Kconfig" diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 4eb6d975288..e9bffdae0a0 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -47,3 +47,5 @@ obj-$(CONFIG_LIBERTAS) += libertas/ rtl8187-objs := rtl8187_dev.o rtl8187_rtl8225.o obj-$(CONFIG_RTL8187) += rtl8187.o + +obj-$(CONFIG_ADM8211) += adm8211.o diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c new file mode 100644 index 00000000000..eec01fc1528 --- /dev/null +++ b/drivers/net/wireless/adm8211.c @@ -0,0 +1,2063 @@ + +/* + * Linux device driver for ADMtek ADM8211 (IEEE 802.11b MAC/BBP) + * + * Copyright (c) 2003, Jouni Malinen + * Copyright (c) 2004-2007, Michael Wu + * Some parts copyright (c) 2003 by David Young + * and used with permission. + * + * Much thanks to Infineon-ADMtek for their support of this driver. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. See README and COPYING for + * more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "adm8211.h" + +MODULE_AUTHOR("Michael Wu "); +MODULE_AUTHOR("Jouni Malinen "); +MODULE_DESCRIPTION("Driver for IEEE 802.11b wireless cards based on ADMtek ADM8211"); +MODULE_SUPPORTED_DEVICE("ADM8211"); +MODULE_LICENSE("GPL"); + +static unsigned int tx_ring_size __read_mostly = 16; +static unsigned int rx_ring_size __read_mostly = 16; + +module_param(tx_ring_size, uint, 0); +module_param(rx_ring_size, uint, 0); + +static const char version[] = KERN_INFO "adm8211: " +"Copyright 2003, Jouni Malinen ; " +"Copyright 2004-2007, Michael Wu \n"; + + +static struct pci_device_id adm8211_pci_id_table[] __devinitdata = { + /* ADMtek ADM8211 */ + { PCI_DEVICE(0x10B7, 0x6000) }, /* 3Com 3CRSHPW796 */ + { PCI_DEVICE(0x1200, 0x8201) }, /* ? */ + { PCI_DEVICE(0x1317, 0x8201) }, /* ADM8211A */ + { PCI_DEVICE(0x1317, 0x8211) }, /* ADM8211B/C */ + { 0 } +}; + +static void adm8211_eeprom_register_read(struct eeprom_93cx6 *eeprom) +{ + struct adm8211_priv *priv = eeprom->data; + u32 reg = ADM8211_CSR_READ(SPR); + + eeprom->reg_data_in = reg & ADM8211_SPR_SDI; + eeprom->reg_data_out = reg & ADM8211_SPR_SDO; + eeprom->reg_data_clock = reg & ADM8211_SPR_SCLK; + eeprom->reg_chip_select = reg & ADM8211_SPR_SCS; +} + +static void adm8211_eeprom_register_write(struct eeprom_93cx6 *eeprom) +{ + struct adm8211_priv *priv = eeprom->data; + u32 reg = 0x4000 | ADM8211_SPR_SRS; + + if (eeprom->reg_data_in) + reg |= ADM8211_SPR_SDI; + if (eeprom->reg_data_out) + reg |= ADM8211_SPR_SDO; + if (eeprom->reg_data_clock) + reg |= ADM8211_SPR_SCLK; + if (eeprom->reg_chip_select) + reg |= ADM8211_SPR_SCS; + + ADM8211_CSR_WRITE(SPR, reg); + ADM8211_CSR_READ(SPR); /* eeprom_delay */ +} + +static int adm8211_read_eeprom(struct ieee80211_hw *dev) +{ + struct adm8211_priv *priv = dev->priv; + unsigned int words, i; + struct ieee80211_chan_range chan_range; + u16 cr49; + struct eeprom_93cx6 eeprom = { + .data = priv, + .register_read = adm8211_eeprom_register_read, + .register_write = adm8211_eeprom_register_write + }; + + if (ADM8211_CSR_READ(CSR_TEST0) & ADM8211_CSR_TEST0_EPTYP) { + /* 256 * 16-bit = 512 bytes */ + eeprom.width = PCI_EEPROM_WIDTH_93C66; + words = 256; + } else { + /* 64 * 16-bit = 128 bytes */ + eeprom.width = PCI_EEPROM_WIDTH_93C46; + words = 64; + } + + priv->eeprom_len = words * 2; + priv->eeprom = kmalloc(priv->eeprom_len, GFP_KERNEL); + if (!priv->eeprom) + return -ENOMEM; + + eeprom_93cx6_multiread(&eeprom, 0, (__le16 __force *)priv->eeprom, words); + + cr49 = le16_to_cpu(priv->eeprom->cr49); + priv->rf_type = (cr49 >> 3) & 0x7; + switch (priv->rf_type) { + case ADM8211_TYPE_INTERSIL: + case ADM8211_TYPE_RFMD: + case ADM8211_TYPE_MARVEL: + case ADM8211_TYPE_AIROHA: + case ADM8211_TYPE_ADMTEK: + break; + + default: + if (priv->revid < ADM8211_REV_CA) + priv->rf_type = ADM8211_TYPE_RFMD; + else + priv->rf_type = ADM8211_TYPE_AIROHA; + + printk(KERN_WARNING "%s (adm8211): Unknown RFtype %d\n", + pci_name(priv->pdev), (cr49 >> 3) & 0x7); + } + + priv->bbp_type = cr49 & 0x7; + switch (priv->bbp_type) { + case ADM8211_TYPE_INTERSIL: + case ADM8211_TYPE_RFMD: + case ADM8211_TYPE_MARVEL: + case ADM8211_TYPE_AIROHA: + case ADM8211_TYPE_ADMTEK: + break; + default: + if (priv->revid < ADM8211_REV_CA) + priv->bbp_type = ADM8211_TYPE_RFMD; + else + priv->bbp_type = ADM8211_TYPE_ADMTEK; + + printk(KERN_WARNING "%s (adm8211): Unknown BBPtype: %d\n", + pci_name(priv->pdev), cr49 >> 3); + } + + if (priv->eeprom->country_code >= ARRAY_SIZE(cranges)) { + printk(KERN_WARNING "%s (adm8211): Invalid country code (%d)\n", + pci_name(priv->pdev), priv->eeprom->country_code); + + chan_range = cranges[2]; + } else + chan_range = cranges[priv->eeprom->country_code]; + + printk(KERN_DEBUG "%s (adm8211): Channel range: %d - %d\n", + pci_name(priv->pdev), (int)chan_range.min, (int)chan_range.max); + + priv->modes[0].num_channels = chan_range.max - chan_range.min + 1; + priv->modes[0].channels = priv->channels; + + memcpy(priv->channels, adm8211_channels, sizeof(adm8211_channels)); + + for (i = 1; i <= ARRAY_SIZE(adm8211_channels); i++) + if (i >= chan_range.min && i <= chan_range.max) + priv->channels[i - 1].flag = + IEEE80211_CHAN_W_SCAN | + IEEE80211_CHAN_W_ACTIVE_SCAN | + IEEE80211_CHAN_W_IBSS; + + switch (priv->eeprom->specific_bbptype) { + case ADM8211_BBP_RFMD3000: + case ADM8211_BBP_RFMD3002: + case ADM8211_BBP_ADM8011: + priv->specific_bbptype = priv->eeprom->specific_bbptype; + break; + + default: + if (priv->revid < ADM8211_REV_CA) + priv->specific_bbptype = ADM8211_BBP_RFMD3000; + else + priv->specific_bbptype = ADM8211_BBP_ADM8011; + + printk(KERN_WARNING "%s (adm8211): Unknown specific BBP: %d\n", + pci_name(priv->pdev), priv->eeprom->specific_bbptype); + } + + switch (priv->eeprom->specific_rftype) { + case ADM8211_RFMD2948: + case ADM8211_RFMD2958: + case ADM8211_RFMD2958_RF3000_CONTROL_POWER: + case ADM8211_MAX2820: + case ADM8211_AL2210L: + priv->transceiver_type = priv->eeprom->specific_rftype; + break; + + default: + if (priv->revid == ADM8211_REV_BA) + priv->transceiver_type = ADM8211_RFMD2958_RF3000_CONTROL_POWER; + else if (priv->revid == ADM8211_REV_CA) + priv->transceiver_type = ADM8211_AL2210L; + else if (priv->revid == ADM8211_REV_AB) + priv->transceiver_type = ADM8211_RFMD2948; + + printk(KERN_WARNING "%s (adm8211): Unknown transceiver: %d\n", + pci_name(priv->pdev), priv->eeprom->specific_rftype); + + break; + } + + printk(KERN_DEBUG "%s (adm8211): RFtype=%d BBPtype=%d Specific BBP=%d " + "Transceiver=%d\n", pci_name(priv->pdev), priv->rf_type, + priv->bbp_type, priv->specific_bbptype, priv->transceiver_type); + + return 0; +} + +static inline void adm8211_write_sram(struct ieee80211_hw *dev, + u32 addr, u32 data) +{ + struct adm8211_priv *priv = dev->priv; + + ADM8211_CSR_WRITE(WEPCTL, addr | ADM8211_WEPCTL_TABLE_WR | + (priv->revid < ADM8211_REV_BA ? + 0 : ADM8211_WEPCTL_SEL_WEPTABLE )); + ADM8211_CSR_READ(WEPCTL); + msleep(1); + + ADM8211_CSR_WRITE(WESK, data); + ADM8211_CSR_READ(WESK); + msleep(1); +} + +static void adm8211_write_sram_bytes(struct ieee80211_hw *dev, + unsigned int addr, u8 *buf, + unsigned int len) +{ + struct adm8211_priv *priv = dev->priv; + u32 reg = ADM8211_CSR_READ(WEPCTL); + unsigned int i; + + if (priv->revid < ADM8211_REV_BA) { + for (i = 0; i < len; i += 2) { + u16 val = buf[i] | (buf[i + 1] << 8); + adm8211_write_sram(dev, addr + i / 2, val); + } + } else { + for (i = 0; i < len; i += 4) { + u32 val = (buf[i + 0] << 0 ) | (buf[i + 1] << 8 ) | + (buf[i + 2] << 16) | (buf[i + 3] << 24); + adm8211_write_sram(dev, addr + i / 4, val); + } + } + + ADM8211_CSR_WRITE(WEPCTL, reg); +} + +static void adm8211_clear_sram(struct ieee80211_hw *dev) +{ + struct adm8211_priv *priv = dev->priv; + u32 reg = ADM8211_CSR_READ(WEPCTL); + unsigned int addr; + + for (addr = 0; addr < ADM8211_SRAM_SIZE; addr++) + adm8211_write_sram(dev, addr, 0); + + ADM8211_CSR_WRITE(WEPCTL, reg); +} + +static int adm8211_get_stats(struct ieee80211_hw *dev, + struct ieee80211_low_level_stats *stats) +{ + struct adm8211_priv *priv = dev->priv; + + memcpy(stats, &priv->stats, sizeof(*stats)); + + return 0; +} + +static void adm8211_set_rx_mode(struct ieee80211_hw *dev, + unsigned short flags, int mc_count) +{ + struct adm8211_priv *priv = dev->priv; + unsigned int bit_nr; + u32 mc_filter[2]; + struct dev_mc_list *mclist; + void *tmp; + + if (flags & IFF_PROMISC) { + priv->nar |= ADM8211_NAR_PR; + priv->nar &= ~ADM8211_NAR_MM; + mc_filter[1] = mc_filter[0] = ~0; + } else if ((flags & IFF_ALLMULTI) || (mc_count > -1)) { + priv->nar &= ~ADM8211_NAR_PR; + priv->nar |= ADM8211_NAR_MM; + mc_filter[1] = mc_filter[0] = ~0; + } else { + priv->nar &= ~(ADM8211_NAR_MM | ADM8211_NAR_PR); + mc_filter[1] = mc_filter[0] = 0; + mclist = NULL; + while ((mclist = ieee80211_get_mc_list_item(dev, mclist, &tmp))) { + bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; + + bit_nr &= 0x3F; + mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); + } + } + + ADM8211_IDLE_RX(); + + ADM8211_CSR_WRITE(MAR0, mc_filter[0]); + ADM8211_CSR_WRITE(MAR1, mc_filter[1]); + ADM8211_CSR_READ(NAR); + + if (flags & IFF_PROMISC) + dev->flags |= IEEE80211_HW_RX_INCLUDES_FCS; + else + dev->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS; + + ADM8211_RESTORE(); +} + +static int adm8211_get_tx_stats(struct ieee80211_hw *dev, + struct ieee80211_tx_queue_stats *stats) +{ + struct adm8211_priv *priv = dev->priv; + struct ieee80211_tx_queue_stats_data *data = &stats->data[0]; + + data->len = priv->cur_tx - priv->dirty_tx; + data->limit = priv->tx_ring_size - 2; + data->count = priv->dirty_tx; + + return 0; +} + +static void adm8211_interrupt_tci(struct ieee80211_hw *dev) +{ + struct adm8211_priv *priv = dev->priv; + unsigned int dirty_tx; + + spin_lock(&priv->lock); + + for (dirty_tx = priv->dirty_tx; priv->cur_tx - dirty_tx; dirty_tx++) { + unsigned int entry = dirty_tx % priv->tx_ring_size; + u32 status = le32_to_cpu(priv->tx_ring[entry].status); + struct adm8211_tx_ring_info *info; + struct sk_buff *skb; + + if (status & TDES0_CONTROL_OWN || + !(status & TDES0_CONTROL_DONE)) + break; + + info = &priv->tx_buffers[entry]; + skb = info->skb; + + /* TODO: check TDES0_STATUS_TUF and TDES0_STATUS_TRO */ + + pci_unmap_single(priv->pdev, info->mapping, + info->skb->len, PCI_DMA_TODEVICE); + + if (info->tx_control.flags & IEEE80211_TXCTL_REQ_TX_STATUS) { + struct ieee80211_tx_status tx_status = {{0}}; + struct ieee80211_hdr *hdr; + size_t hdrlen = info->hdrlen; + + skb_pull(skb, sizeof(struct adm8211_tx_hdr)); + hdr = (struct ieee80211_hdr *)skb_push(skb, hdrlen); + memcpy(hdr, skb->cb, hdrlen); + memcpy(&tx_status.control, &info->tx_control, + sizeof(tx_status.control)); + if (!(status & TDES0_STATUS_ES)) + tx_status.flags |= IEEE80211_TX_STATUS_ACK; + ieee80211_tx_status_irqsafe(dev, skb, &tx_status); + } else + dev_kfree_skb_irq(skb); + info->skb = NULL; + } + + if (priv->cur_tx - dirty_tx < priv->tx_ring_size - 2) + ieee80211_wake_queue(dev, 0); + + priv->dirty_tx = dirty_tx; + spin_unlock(&priv->lock); +} + + +static void adm8211_interrupt_rci(struct ieee80211_hw *dev) +{ + struct adm8211_priv *priv = dev->priv; + unsigned int entry = priv->cur_rx % priv->rx_ring_size; + u32 status; + unsigned int pktlen; + struct sk_buff *skb, *newskb; + unsigned int limit = priv->rx_ring_size; + static const u8 rate_tbl[] = {10, 20, 55, 110, 220}; + u8 rssi, rate; + + while (!(priv->rx_ring[entry].status & cpu_to_le32(RDES0_STATUS_OWN))) { + if (!limit--) + break; + + status = le32_to_cpu(priv->rx_ring[entry].status); + rate = (status & RDES0_STATUS_RXDR) >> 12; + rssi = le32_to_cpu(priv->rx_ring[entry].length) & + RDES1_STATUS_RSSI; + + pktlen = status & RDES0_STATUS_FL; + if (pktlen > RX_PKT_SIZE) { + if (net_ratelimit()) + printk(KERN_DEBUG "%s: frame too long (%d)\n", + wiphy_name(dev->wiphy), pktlen); + pktlen = RX_PKT_SIZE; + } + + if (!priv->soft_rx_crc && status & RDES0_STATUS_ES) { + skb = NULL; /* old buffer will be reused */ + /* TODO: update RX error stats */ + /* TODO: check RDES0_STATUS_CRC*E */ + } else if (pktlen < RX_COPY_BREAK) { + skb = dev_alloc_skb(pktlen); + if (skb) { + pci_dma_sync_single_for_cpu( + priv->pdev, + priv->rx_buffers[entry].mapping, + pktlen, PCI_DMA_FROMDEVICE); + memcpy(skb_put(skb, pktlen), + skb_tail_pointer(priv->rx_buffers[entry].skb), + pktlen); + pci_dma_sync_single_for_device( + priv->pdev, + priv->rx_buffers[entry].mapping, + RX_PKT_SIZE, PCI_DMA_FROMDEVICE); + } + } else { + newskb = dev_alloc_skb(RX_PKT_SIZE); + if (newskb) { + skb = priv->rx_buffers[entry].skb; + skb_put(skb, pktlen); + pci_unmap_single( + priv->pdev, + priv->rx_buffers[entry].mapping, + RX_PKT_SIZE, PCI_DMA_FROMDEVICE); + priv->rx_buffers[entry].skb = newskb; + priv->rx_buffers[entry].mapping = + pci_map_single(priv->pdev, + skb_tail_pointer(newskb), + RX_PKT_SIZE, + PCI_DMA_FROMDEVICE); + } else { + skb = NULL; + /* TODO: update rx dropped stats */ + } + + priv->rx_ring[entry].buffer1 = + cpu_to_le32(priv->rx_buffers[entry].mapping); + } + + priv->rx_ring[entry].status = cpu_to_le32(RDES0_STATUS_OWN | + RDES0_STATUS_SQL); + priv->rx_ring[entry].length = + cpu_to_le32(RX_PKT_SIZE | + (entry == priv->rx_ring_size - 1 ? + RDES1_CONTROL_RER : 0)); + + if (skb) { + struct ieee80211_rx_status rx_status = {0}; + + if (priv->revid < ADM8211_REV_CA) + rx_status.ssi = rssi; + else + rx_status.ssi = 100 - rssi; + + if (rate <= 4) + rx_status.rate = rate_tbl[rate]; + + rx_status.channel = priv->channel; + rx_status.freq = adm8211_channels[priv->channel - 1].freq; + rx_status.phymode = MODE_IEEE80211B; + + ieee80211_rx_irqsafe(dev, skb, &rx_status); + } + + entry = (++priv->cur_rx) % priv->rx_ring_size; + } + + /* TODO: check LPC and update stats? */ +} + + +static irqreturn_t adm8211_interrupt(int irq, void *dev_id) +{ +#define ADM8211_INT(x) \ +do { \ + if (unlikely(stsr & ADM8211_STSR_ ## x)) \ + printk(KERN_DEBUG "%s: " #x "\n", wiphy_name(dev->wiphy)); \ +} while (0) + + struct ieee80211_hw *dev = dev_id; + struct adm8211_priv *priv = dev->priv; + unsigned int count = 0; + u32 stsr; + + do { + stsr = ADM8211_CSR_READ(STSR); + ADM8211_CSR_WRITE(STSR, stsr); + if (stsr == 0xffffffff) + return IRQ_HANDLED; + + if (!(stsr & (ADM8211_STSR_NISS | ADM8211_STSR_AISS))) + break; + + if (stsr & ADM8211_STSR_RCI) + adm8211_interrupt_rci(dev); + if (stsr & ADM8211_STSR_TCI) + adm8211_interrupt_tci(dev); + + /*ADM8211_INT(LinkOn);*/ + /*ADM8211_INT(LinkOff);*/ + + ADM8211_INT(PCF); + ADM8211_INT(BCNTC); + ADM8211_INT(GPINT); + ADM8211_INT(ATIMTC); + ADM8211_INT(TSFTF); + ADM8211_INT(TSCZ); + ADM8211_INT(SQL); + ADM8211_INT(WEPTD); + ADM8211_INT(ATIME); + /*ADM8211_INT(TBTT);*/ + ADM8211_INT(TEIS); + ADM8211_INT(FBE); + ADM8211_INT(REIS); + ADM8211_INT(GPTT); + ADM8211_INT(RPS); + ADM8211_INT(RDU); + ADM8211_INT(TUF); + /*ADM8211_INT(TRT);*/ + /*ADM8211_INT(TLT);*/ + /*ADM8211_INT(TDU);*/ + ADM8211_INT(TPS); + + } while (count++ < 20); + + return IRQ_RETVAL(count); + +#undef ADM8211_INT +} + +#define WRITE_SYN(name,v_mask,v_shift,a_mask,a_shift,bits,prewrite,postwrite)\ +static void adm8211_rf_write_syn_ ## name (struct ieee80211_hw *dev, \ + u16 addr, u32 value) { \ + struct adm8211_priv *priv = dev->priv; \ + unsigned int i; \ + u32 reg, bitbuf; \ + \ + value &= v_mask; \ + addr &= a_mask; \ + bitbuf = (value << v_shift) | (addr << a_shift); \ + \ + ADM8211_CSR_WRITE(SYNRF, ADM8211_SYNRF_IF_SELECT_1); \ + ADM8211_CSR_READ(SYNRF); \ + ADM8211_CSR_WRITE(SYNRF, ADM8211_SYNRF_IF_SELECT_0); \ + ADM8211_CSR_READ(SYNRF); \ + \ + if (prewrite) { \ + ADM8211_CSR_WRITE(SYNRF, ADM8211_SYNRF_WRITE_SYNDATA_0); \ + ADM8211_CSR_READ(SYNRF); \ + } \ + \ + for (i = 0; i <= bits; i++) { \ + if (bitbuf & (1 << (bits - i))) \ + reg = ADM8211_SYNRF_WRITE_SYNDATA_1; \ + else \ + reg = ADM8211_SYNRF_WRITE_SYNDATA_0; \ + \ + ADM8211_CSR_WRITE(SYNRF, reg); \ + ADM8211_CSR_READ(SYNRF); \ + \ + ADM8211_CSR_WRITE(SYNRF, reg | ADM8211_SYNRF_WRITE_CLOCK_1); \ + ADM8211_CSR_READ(SYNRF); \ + ADM8211_CSR_WRITE(SYNRF, reg | ADM8211_SYNRF_WRITE_CLOCK_0); \ + ADM8211_CSR_READ(SYNRF); \ + } \ + \ + if (postwrite == 1) { \ + ADM8211_CSR_WRITE(SYNRF, reg | ADM8211_SYNRF_IF_SELECT_0); \ + ADM8211_CSR_READ(SYNRF); \ + } \ + if (postwrite == 2) { \ + ADM8211_CSR_WRITE(SYNRF, reg | ADM8211_SYNRF_IF_SELECT_1); \ + ADM8211_CSR_READ(SYNRF); \ + } \ + \ + ADM8211_CSR_WRITE(SYNRF, 0); \ + ADM8211_CSR_READ(SYNRF); \ +} + +WRITE_SYN(max2820, 0x00FFF, 0, 0x0F, 12, 15, 1, 1) +WRITE_SYN(al2210l, 0xFFFFF, 4, 0x0F, 0, 23, 1, 1) +WRITE_SYN(rfmd2958, 0x3FFFF, 0, 0x1F, 18, 23, 0, 1) +WRITE_SYN(rfmd2948, 0x0FFFF, 4, 0x0F, 0, 21, 0, 2) + +#undef WRITE_SYN + +static int adm8211_write_bbp(struct ieee80211_hw *dev, u8 addr, u8 data) +{ + struct adm8211_priv *priv = dev->priv; + unsigned int timeout; + u32 reg; + + timeout = 10; + while (timeout > 0) { + reg = ADM8211_CSR_READ(BBPCTL); + if (!(reg & (ADM8211_BBPCTL_WR | ADM8211_BBPCTL_RD))) + break; + timeout--; + msleep(2); + } + + if (timeout == 0) { + printk(KERN_DEBUG "%s: adm8211_write_bbp(%d,%d) failed" + " prewrite (reg=0x%08x)\n", + wiphy_name(dev->wiphy), addr, data, reg); + return -ETIMEDOUT; + } + + switch (priv->bbp_type) { + case ADM8211_TYPE_INTERSIL: + reg = ADM8211_BBPCTL_MMISEL; /* three wire interface */ + break; + case ADM8211_TYPE_RFMD: + reg = (0x20 << 24) | ADM8211_BBPCTL_TXCE | ADM8211_BBPCTL_CCAP | + (0x01 << 18); + break; + case ADM8211_TYPE_ADMTEK: + reg = (0x20 << 24) | ADM8211_BBPCTL_TXCE | ADM8211_BBPCTL_CCAP | + (0x05 << 18); + break; + } + reg |= ADM8211_BBPCTL_WR | (addr << 8) | data; + + ADM8211_CSR_WRITE(BBPCTL, reg); + + timeout = 10; + while (timeout > 0) { + reg = ADM8211_CSR_READ(BBPCTL); + if (!(reg & ADM8211_BBPCTL_WR)) + break; + timeout--; + msleep(2); + } + + if (timeout == 0) { + ADM8211_CSR_WRITE(BBPCTL, ADM8211_CSR_READ(BBPCTL) & + ~ADM8211_BBPCTL_WR); + printk(KERN_DEBUG "%s: adm8211_write_bbp(%d,%d) failed" + " postwrite (reg=0x%08x)\n", + wiphy_name(dev->wiphy), addr, data, reg); + return -ETIMEDOUT; + } + + return 0; +} + +static int adm8211_rf_set_channel(struct ieee80211_hw *dev, unsigned int chan) +{ + static const u32 adm8211_rfmd2958_reg5[] = + {0x22BD, 0x22D2, 0x22E8, 0x22FE, 0x2314, 0x232A, 0x2340, + 0x2355, 0x236B, 0x2381, 0x2397, 0x23AD, 0x23C2, 0x23F7}; + static const u32 adm8211_rfmd2958_reg6[] = + {0x05D17, 0x3A2E8, 0x2E8BA, 0x22E8B, 0x1745D, 0x0BA2E, 0x00000, + 0x345D1, 0x28BA2, 0x1D174, 0x11745, 0x05D17, 0x3A2E8, 0x11745}; + + struct adm8211_priv *priv = dev->priv; + u8 ant_power = priv->ant_power > 0x3F ? + priv->eeprom->antenna_power[chan - 1] : priv->ant_power; + u8 tx_power = priv->tx_power > 0x3F ? + priv->eeprom->tx_power[chan - 1] : priv->tx_power; + u8 lpf_cutoff = priv->lpf_cutoff == 0xFF ? + priv->eeprom->lpf_cutoff[chan - 1] : priv->lpf_cutoff; + u8 lnags_thresh = priv->lnags_threshold == 0xFF ? + priv->eeprom->lnags_threshold[chan - 1] : priv->lnags_threshold; + u32 reg; + + ADM8211_IDLE(); + + /* Program synthesizer to new channel */ + switch (priv->transceiver_type) { + case ADM8211_RFMD2958: + case ADM8211_RFMD2958_RF3000_CONTROL_POWER: + adm8211_rf_write_syn_rfmd2958(dev, 0x00, 0x04007); + adm8211_rf_write_syn_rfmd2958(dev, 0x02, 0x00033); + + adm8211_rf_write_syn_rfmd2958(dev, 0x05, + adm8211_rfmd2958_reg5[chan - 1]); + adm8211_rf_write_syn_rfmd2958(dev, 0x06, + adm8211_rfmd2958_reg6[chan - 1]); + break; + + case ADM8211_RFMD2948: + adm8211_rf_write_syn_rfmd2948(dev, SI4126_MAIN_CONF, + SI4126_MAIN_XINDIV2); + adm8211_rf_write_syn_rfmd2948(dev, SI4126_POWERDOWN, + SI4126_POWERDOWN_PDIB | + SI4126_POWERDOWN_PDRB); + adm8211_rf_write_syn_rfmd2948(dev, SI4126_PHASE_DET_GAIN, 0); + adm8211_rf_write_syn_rfmd2948(dev, SI4126_RF2_N_DIV, + (chan == 14 ? + 2110 : (2033 + (chan * 5)))); + adm8211_rf_write_syn_rfmd2948(dev, SI4126_IF_N_DIV, 1496); + adm8211_rf_write_syn_rfmd2948(dev, SI4126_RF2_R_DIV, 44); + adm8211_rf_write_syn_rfmd2948(dev, SI4126_IF_R_DIV, 44); + break; + + case ADM8211_MAX2820: + adm8211_rf_write_syn_max2820(dev, 0x3, + (chan == 14 ? 0x054 : (0x7 + (chan * 5)))); + break; + + case ADM8211_AL2210L: + adm8211_rf_write_syn_al2210l(dev, 0x0, + (chan == 14 ? 0x229B4 : (0x22967 + (chan * 5)))); + break; + + default: + printk(KERN_DEBUG "%s: unsupported transceiver type %d\n", + wiphy_name(dev->wiphy), priv->transceiver_type); + break; + } + + /* write BBP regs */ + if (priv->bbp_type == ADM8211_TYPE_RFMD) { + + /* SMC 2635W specific? adm8211b doesn't use the 2948 though.. */ + /* TODO: remove if SMC 2635W doesn't need this */ + if (priv->transceiver_type == ADM8211_RFMD2948) { + reg = ADM8211_CSR_READ(GPIO); + reg &= 0xfffc0000; + reg |= ADM8211_CSR_GPIO_EN0; + if (chan != 14) + reg |= ADM8211_CSR_GPIO_O0; + ADM8211_CSR_WRITE(GPIO, reg); + } + + if (priv->transceiver_type == ADM8211_RFMD2958) { + /* set PCNT2 */ + adm8211_rf_write_syn_rfmd2958(dev, 0x0B, 0x07100); + /* set PCNT1 P_DESIRED/MID_BIAS */ + reg = le16_to_cpu(priv->eeprom->cr49); + reg >>= 13; + reg <<= 15; + reg |= ant_power << 9; + adm8211_rf_write_syn_rfmd2958(dev, 0x0A, reg); + /* set TXRX TX_GAIN */ + adm8211_rf_write_syn_rfmd2958(dev, 0x09, 0x00050 | + (priv->revid < ADM8211_REV_CA ? tx_power : 0)); + } else { + reg = ADM8211_CSR_READ(PLCPHD); + reg &= 0xff00ffff; + reg |= tx_power << 18; + ADM8211_CSR_WRITE(PLCPHD, reg); + } + + ADM8211_CSR_WRITE(SYNRF, ADM8211_SYNRF_SELRF | + ADM8211_SYNRF_PE1 | ADM8211_SYNRF_PHYRST); + ADM8211_CSR_READ(SYNRF); + msleep(30); + + /* RF3000 BBP */ + if (priv->transceiver_type != ADM8211_RFMD2958) + adm8211_write_bbp(dev, RF3000_TX_VAR_GAIN__TX_LEN_EXT, + tx_power<<2); + adm8211_write_bbp(dev, RF3000_LOW_GAIN_CALIB, lpf_cutoff); + adm8211_write_bbp(dev, RF3000_HIGH_GAIN_CALIB, lnags_thresh); + adm8211_write_bbp(dev, 0x1c, priv->revid == ADM8211_REV_BA ? + priv->eeprom->cr28 : 0); + adm8211_write_bbp(dev, 0x1d, priv->eeprom->cr29); + + ADM8211_CSR_WRITE(SYNRF, 0); + + /* Nothing to do for ADMtek BBP */ + } else if (priv->bbp_type != ADM8211_TYPE_ADMTEK) + printk(KERN_DEBUG "%s: unsupported BBP type %d\n", + wiphy_name(dev->wiphy), priv->bbp_type); + + ADM8211_RESTORE(); + + /* update current channel for adhoc (and maybe AP mode) */ + reg = ADM8211_CSR_READ(CAP0); + reg &= ~0xF; + reg |= chan; + ADM8211_CSR_WRITE(CAP0, reg); + + return 0; +} + +static void adm8211_update_mode(struct ieee80211_hw *dev) +{ + struct adm8211_priv *priv = dev->priv; + + ADM8211_IDLE(); + + priv->soft_rx_crc = 0; + switch (priv->mode) { + case IEEE80211_IF_TYPE_STA: + priv->nar &= ~(ADM8211_NAR_PR | ADM8211_NAR_EA); + priv->nar |= ADM8211_NAR_ST | ADM8211_NAR_SR; + break; + case IEEE80211_IF_TYPE_IBSS: + priv->nar &= ~ADM8211_NAR_PR; + priv->nar |= ADM8211_NAR_EA | ADM8211_NAR_ST | ADM8211_NAR_SR; + + /* don't trust the error bits on rev 0x20 and up in adhoc */ + if (priv->revid >= ADM8211_REV_BA) + priv->soft_rx_crc = 1; + break; + case IEEE80211_IF_TYPE_MNTR: + priv->nar &= ~(ADM8211_NAR_EA | ADM8211_NAR_ST); + priv->nar |= ADM8211_NAR_PR | ADM8211_NAR_SR; + break; + } + + ADM8211_RESTORE(); +} + +static void adm8211_hw_init_syn(struct ieee80211_hw *dev) +{ + struct adm8211_priv *priv = dev->priv; + + switch (priv->transceiver_type) { + case ADM8211_RFMD2958: + case ADM8211_RFMD2958_RF3000_CONTROL_POWER: + /* comments taken from ADMtek vendor driver */ + + /* Reset RF2958 after power on */ + adm8211_rf_write_syn_rfmd2958(dev, 0x1F, 0x00000); + /* Initialize RF VCO Core Bias to maximum */ + adm8211_rf_write_syn_rfmd2958(dev, 0x0C, 0x3001F); + /* Initialize IF PLL */ + adm8211_rf_write_syn_rfmd2958(dev, 0x01, 0x29C03); + /* Initialize IF PLL Coarse Tuning */ + adm8211_rf_write_syn_rfmd2958(dev, 0x03, 0x1FF6F); + /* Initialize RF PLL */ + adm8211_rf_write_syn_rfmd2958(dev, 0x04, 0x29403); + /* Initialize RF PLL Coarse Tuning */ + adm8211_rf_write_syn_rfmd2958(dev, 0x07, 0x1456F); + /* Initialize TX gain and filter BW (R9) */ + adm8211_rf_write_syn_rfmd2958(dev, 0x09, + (priv->transceiver_type == ADM8211_RFMD2958 ? + 0x10050 : 0x00050)); + /* Initialize CAL register */ + adm8211_rf_write_syn_rfmd2958(dev, 0x08, 0x3FFF8); + break; + + case ADM8211_MAX2820: + adm8211_rf_write_syn_max2820(dev, 0x1, 0x01E); + adm8211_rf_write_syn_max2820(dev, 0x2, 0x001); + adm8211_rf_write_syn_max2820(dev, 0x3, 0x054); + adm8211_rf_write_syn_max2820(dev, 0x4, 0x310); + adm8211_rf_write_syn_max2820(dev, 0x5, 0x000); + break; + + case ADM8211_AL2210L: + adm8211_rf_write_syn_al2210l(dev, 0x0, 0x0196C); + adm8211_rf_write_syn_al2210l(dev, 0x1, 0x007CB); + adm8211_rf_write_syn_al2210l(dev, 0x2, 0x3582F); + adm8211_rf_write_syn_al2210l(dev, 0x3, 0x010A9); + adm8211_rf_write_syn_al2210l(dev, 0x4, 0x77280); + adm8211_rf_write_syn_al2210l(dev, 0x5, 0x45641); + adm8211_rf_write_syn_al2210l(dev, 0x6, 0xEA130); + adm8211_rf_write_syn_al2210l(dev, 0x7, 0x80000); + adm8211_rf_write_syn_al2210l(dev, 0x8, 0x7850F); + adm8211_rf_write_syn_al2210l(dev, 0x9, 0xF900C); + adm8211_rf_write_syn_al2210l(dev, 0xA, 0x00000); + adm8211_rf_write_syn_al2210l(dev, 0xB, 0x00000); + break; + + case ADM8211_RFMD2948: + default: + break; + } +} + +static int adm8211_hw_init_bbp(struct ieee80211_hw *dev) +{ + struct adm8211_priv *priv = dev->priv; + u32 reg; + + /* write addresses */ + if (priv->bbp_type == ADM8211_TYPE_INTERSIL) { + ADM8211_CSR_WRITE(MMIWA, 0x100E0C0A); + ADM8211_CSR_WRITE(MMIRD0, 0x00007C7E); + ADM8211_CSR_WRITE(MMIRD1, 0x00100000); + } else if (priv->bbp_type == ADM8211_TYPE_RFMD || + priv->bbp_type == ADM8211_TYPE_ADMTEK) { + /* check specific BBP type */ + switch (priv->specific_bbptype) { + case ADM8211_BBP_RFMD3000: + case ADM8211_BBP_RFMD3002: + ADM8211_CSR_WRITE(MMIWA, 0x00009101); + ADM8211_CSR_WRITE(MMIRD0, 0x00000301); + break; + + case ADM8211_BBP_ADM8011: + ADM8211_CSR_WRITE(MMIWA, 0x00008903); + ADM8211_CSR_WRITE(MMIRD0, 0x00001716); + + reg = ADM8211_CSR_READ(BBPCTL); + reg &= ~ADM8211_BBPCTL_TYPE; + reg |= 0x5 << 18; + ADM8211_CSR_WRITE(BBPCTL, reg); + break; + } + + switch (priv->revid) { + case ADM8211_REV_CA: + if (priv->transceiver_type == ADM8211_RFMD2958 || + priv->transceiver_type == ADM8211_RFMD2958_RF3000_CONTROL_POWER || + priv->transceiver_type == ADM8211_RFMD2948) + ADM8211_CSR_WRITE(SYNCTL, 0x1 << 22); + else if (priv->transceiver_type == ADM8211_MAX2820 || + priv->transceiver_type == ADM8211_AL2210L) + ADM8211_CSR_WRITE(SYNCTL, 0x3 << 22); + break; + + case ADM8211_REV_BA: + reg = ADM8211_CSR_READ(MMIRD1); + reg &= 0x0000FFFF; + reg |= 0x7e100000; + ADM8211_CSR_WRITE(MMIRD1, reg); + break; + + case ADM8211_REV_AB: + case ADM8211_REV_AF: + default: + ADM8211_CSR_WRITE(MMIRD1, 0x7e100000); + break; + } + + /* For RFMD */ + ADM8211_CSR_WRITE(MACTEST, 0x800); + } + + adm8211_hw_init_syn(dev); + + /* Set RF Power control IF pin to PE1+PHYRST# */ + ADM8211_CSR_WRITE(SYNRF, ADM8211_SYNRF_SELRF | + ADM8211_SYNRF_PE1 | ADM8211_SYNRF_PHYRST); + ADM8211_CSR_READ(SYNRF); + msleep(20); + + /* write BBP regs */ + if (priv->bbp_type == ADM8211_TYPE_RFMD) { + /* RF3000 BBP */ + /* another set: + * 11: c8 + * 14: 14 + * 15: 50 (chan 1..13; chan 14: d0) + * 1c: 00 + * 1d: 84 + */ + adm8211_write_bbp(dev, RF3000_CCA_CTRL, 0x80); + /* antenna selection: diversity */ + adm8211_write_bbp(dev, RF3000_DIVERSITY__RSSI, 0x80); + adm8211_write_bbp(dev, RF3000_TX_VAR_GAIN__TX_LEN_EXT, 0x74); + adm8211_write_bbp(dev, RF3000_LOW_GAIN_CALIB, 0x38); + adm8211_write_bbp(dev, RF3000_HIGH_GAIN_CALIB, 0x40); + + if (priv->eeprom->major_version < 2) { + adm8211_write_bbp(dev, 0x1c, 0x00); + adm8211_write_bbp(dev, 0x1d, 0x80); + } else { + if (priv->revid == ADM8211_REV_BA) + adm8211_write_bbp(dev, 0x1c, priv->eeprom->cr28); + else + adm8211_write_bbp(dev, 0x1c, 0x00); + + adm8211_write_bbp(dev, 0x1d, priv->eeprom->cr29); + } + } else if (priv->bbp_type == ADM8211_TYPE_ADMTEK) { + /* reset baseband */ + adm8211_write_bbp(dev, 0x00, 0xFF); + /* antenna selection: diversity */ + adm8211_write_bbp(dev, 0x07, 0x0A); + + /* TODO: find documentation for this */ + switch (priv->transceiver_type) { + case ADM8211_RFMD2958: + case ADM8211_RFMD2958_RF3000_CONTROL_POWER: + adm8211_write_bbp(dev, 0x00, 0x00); + adm8211_write_bbp(dev, 0x01, 0x00); + adm8211_write_bbp(dev, 0x02, 0x00); + adm8211_write_bbp(dev, 0x03, 0x00); + adm8211_write_bbp(dev, 0x06, 0x0f); + adm8211_write_bbp(dev, 0x09, 0x00); + adm8211_write_bbp(dev, 0x0a, 0x00); + adm8211_write_bbp(dev, 0x0b, 0x00); + adm8211_write_bbp(dev, 0x0c, 0x00); + adm8211_write_bbp(dev, 0x0f, 0xAA); + adm8211_write_bbp(dev, 0x10, 0x8c); + adm8211_write_bbp(dev, 0x11, 0x43); + adm8211_write_bbp(dev, 0x18, 0x40); + adm8211_write_bbp(dev, 0x20, 0x23); + adm8211_write_bbp(dev, 0x21, 0x02); + adm8211_write_bbp(dev, 0x22, 0x28); + adm8211_write_bbp(dev, 0x23, 0x30); + adm8211_write_bbp(dev, 0x24, 0x2d); + adm8211_write_bbp(dev, 0x28, 0x35); + adm8211_write_bbp(dev, 0x2a, 0x8c); + adm8211_write_bbp(dev, 0x2b, 0x81); + adm8211_write_bbp(dev, 0x2c, 0x44); + adm8211_write_bbp(dev, 0x2d, 0x0A); + adm8211_write_bbp(dev, 0x29, 0x40); + adm8211_write_bbp(dev, 0x60, 0x08); + adm8211_write_bbp(dev, 0x64, 0x01); + break; + + case ADM8211_MAX2820: + adm8211_write_bbp(dev, 0x00, 0x00); + adm8211_write_bbp(dev, 0x01, 0x00); + adm8211_write_bbp(dev, 0x02, 0x00); + adm8211_write_bbp(dev, 0x03, 0x00); + adm8211_write_bbp(dev, 0x06, 0x0f); + adm8211_write_bbp(dev, 0x09, 0x05); + adm8211_write_bbp(dev, 0x0a, 0x02); + adm8211_write_bbp(dev, 0x0b, 0x00); + adm8211_write_bbp(dev, 0x0c, 0x0f); + adm8211_write_bbp(dev, 0x0f, 0x55); + adm8211_write_bbp(dev, 0x10, 0x8d); + adm8211_write_bbp(dev, 0x11, 0x43); + adm8211_write_bbp(dev, 0x18, 0x4a); + adm8211_write_bbp(dev, 0x20, 0x20); + adm8211_write_bbp(dev, 0x21, 0x02); + adm8211_write_bbp(dev, 0x22, 0x23); + adm8211_write_bbp(dev, 0x23, 0x30); + adm8211_write_bbp(dev, 0x24, 0x2d); + adm8211_write_bbp(dev, 0x2a, 0x8c); + adm8211_write_bbp(dev, 0x2b, 0x81); + adm8211_write_bbp(dev, 0x2c, 0x44); + adm8211_write_bbp(dev, 0x29, 0x4a); + adm8211_write_bbp(dev, 0x60, 0x2b); + adm8211_write_bbp(dev, 0x64, 0x01); + break; + + case ADM8211_AL2210L: + adm8211_write_bbp(dev, 0x00, 0x00); + adm8211_write_bbp(dev, 0x01, 0x00); + adm8211_write_bbp(dev, 0x02, 0x00); + adm8211_write_bbp(dev, 0x03, 0x00); + adm8211_write_bbp(dev, 0x06, 0x0f); + adm8211_write_bbp(dev, 0x07, 0x05); + adm8211_write_bbp(dev, 0x08, 0x03); + adm8211_write_bbp(dev, 0x09, 0x00); + adm8211_write_bbp(dev, 0x0a, 0x00); + adm8211_write_bbp(dev, 0x0b, 0x00); + adm8211_write_bbp(dev, 0x0c, 0x10); + adm8211_write_bbp(dev, 0x0f, 0x55); + adm8211_write_bbp(dev, 0x10, 0x8d); + adm8211_write_bbp(dev, 0x11, 0x43); + adm8211_write_bbp(dev, 0x18, 0x4a); + adm8211_write_bbp(dev, 0x20, 0x20); + adm8211_write_bbp(dev, 0x21, 0x02); + adm8211_write_bbp(dev, 0x22, 0x23); + adm8211_write_bbp(dev, 0x23, 0x30); + adm8211_write_bbp(dev, 0x24, 0x2d); + adm8211_write_bbp(dev, 0x2a, 0xaa); + adm8211_write_bbp(dev, 0x2b, 0x81); + adm8211_write_bbp(dev, 0x2c, 0x44); + adm8211_write_bbp(dev, 0x29, 0xfa); + adm8211_write_bbp(dev, 0x60, 0x2d); + adm8211_write_bbp(dev, 0x64, 0x01); + break; + + case ADM8211_RFMD2948: + break; + + default: + printk(KERN_DEBUG "%s: unsupported transceiver %d\n", + wiphy_name(dev->wiphy), priv->transceiver_type); + break; + } + } else + printk(KERN_DEBUG "%s: unsupported BBP %d\n", + wiphy_name(dev->wiphy), priv->bbp_type); + + ADM8211_CSR_WRITE(SYNRF, 0); + + /* Set RF CAL control source to MAC control */ + reg = ADM8211_CSR_READ(SYNCTL); + reg |= ADM8211_SYNCTL_SELCAL; + ADM8211_CSR_WRITE(SYNCTL, reg); + + return 0; +} + +/* configures hw beacons/probe responses */ +static int adm8211_set_rate(struct ieee80211_hw *dev) +{ + struct adm8211_priv *priv = dev->priv; + u32 reg; + int i = 0; + u8 rate_buf[12] = {0}; + + /* write supported rates */ + if (priv->revid != ADM8211_REV_BA) { + rate_buf[0] = ARRAY_SIZE(adm8211_rates); + for (i = 0; i < ARRAY_SIZE(adm8211_rates); i++) + rate_buf[i + 1] = (adm8211_rates[i].rate / 5) | 0x80; + } else { + /* workaround for rev BA specific bug */ + rate_buf[0] = 0x04; + rate_buf[1] = 0x82; + rate_buf[2] = 0x04; + rate_buf[3] = 0x0b; + rate_buf[4] = 0x16; + } + + adm8211_write_sram_bytes(dev, ADM8211_SRAM_SUPP_RATE, rate_buf, + ARRAY_SIZE(adm8211_rates) + 1); + + reg = ADM8211_CSR_READ(PLCPHD) & 0x00FFFFFF; /* keep bits 0-23 */ + reg |= 1 << 15; /* short preamble */ + reg |= 110 << 24; + ADM8211_CSR_WRITE(PLCPHD, reg); + + /* MTMLT = 512 TU (max TX MSDU lifetime) + * BCNTSIG = plcp_signal (beacon, probe resp, and atim TX rate) + * SRTYLIM = 224 (short retry limit, TX header value is default) */ + ADM8211_CSR_WRITE(TXLMT, (512 << 16) | (110 << 8) | (224 << 0)); + + return 0; +} + +static void adm8211_hw_init(struct ieee80211_hw *dev) +{ + struct adm8211_priv *priv = dev->priv; + u32 reg; + u8 cline; + + reg = le32_to_cpu(ADM8211_CSR_READ(PAR)); + reg |= ADM8211_PAR_MRLE | ADM8211_PAR_MRME; + reg &= ~(ADM8211_PAR_BAR | ADM8211_PAR_CAL); + + if (!pci_set_mwi(priv->pdev)) { + reg |= 0x1 << 24; + pci_read_config_byte(priv->pdev, PCI_CACHE_LINE_SIZE, &cline); + + switch (cline) { + case 0x8: reg |= (0x1 << 14); + break; + case 0x16: reg |= (0x2 << 14); + break; + case 0x32: reg |= (0x3 << 14); + break; + default: reg |= (0x0 << 14); + break; + } + } + + ADM8211_CSR_WRITE(PAR, reg); + + reg = ADM8211_CSR_READ(CSR_TEST1); + reg &= ~(0xF << 28); + reg |= (1 << 28) | (1 << 31); + ADM8211_CSR_WRITE(CSR_TEST1, reg); + + /* lose link after 4 lost beacons */ + reg = (0x04 << 21) | ADM8211_WCSR_TSFTWE | ADM8211_WCSR_LSOE; + ADM8211_CSR_WRITE(WCSR, reg); + + /* Disable APM, enable receive FIFO threshold, and set drain receive + * threshold to store-and-forward */ + reg = ADM8211_CSR_READ(CMDR); + reg &= ~(ADM8211_CMDR_APM | ADM8211_CMDR_DRT); + reg |= ADM8211_CMDR_RTE | ADM8211_CMDR_DRT_SF; + ADM8211_CSR_WRITE(CMDR, reg); + + adm8211_set_rate(dev); + + /* 4-bit values: + * PWR1UP = 8 * 2 ms + * PWR0PAPE = 8 us or 5 us + * PWR1PAPE = 1 us or 3 us + * PWR0TRSW = 5 us + * PWR1TRSW = 12 us + * PWR0PE2 = 13 us + * PWR1PE2 = 1 us + * PWR0TXPE = 8 or 6 */ + if (priv->revid < ADM8211_REV_CA) + ADM8211_CSR_WRITE(TOFS2, 0x8815cd18); + else + ADM8211_CSR_WRITE(TOFS2, 0x8535cd16); + + /* Enable store and forward for transmit */ + priv->nar = ADM8211_NAR_SF | ADM8211_NAR_PB; + ADM8211_CSR_WRITE(NAR, priv->nar); + + /* Reset RF */ + ADM8211_CSR_WRITE(SYNRF, ADM8211_SYNRF_RADIO); + ADM8211_CSR_READ(SYNRF); + msleep(10); + ADM8211_CSR_WRITE(SYNRF, 0); + ADM8211_CSR_READ(SYNRF); + msleep(5); + + /* Set CFP Max Duration to 0x10 TU */ + reg = ADM8211_CSR_READ(CFPP); + reg &= ~(0xffff << 8); + reg |= 0x0010 << 8; + ADM8211_CSR_WRITE(CFPP, reg); + + /* USCNT = 0x16 (number of system clocks, 22 MHz, in 1us + * TUCNT = 0x3ff - Tu counter 1024 us */ + ADM8211_CSR_WRITE(TOFS0, (0x16 << 24) | 0x3ff); + + /* SLOT=20 us, SIFS=110 cycles of 22 MHz (5 us), + * DIFS=50 us, EIFS=100 us */ + if (priv->revid < ADM8211_REV_CA) + ADM8211_CSR_WRITE(IFST, (20 << 23) | (110 << 15) | + (50 << 9) | 100); + else + ADM8211_CSR_WRITE(IFST, (20 << 23) | (24 << 15) | + (50 << 9) | 100); + + /* PCNT = 1 (MAC idle time awake/sleep, unit S) + * RMRD = 2346 * 8 + 1 us (max RX duration) */ + ADM8211_CSR_WRITE(RMD, (1 << 16) | 18769); + + /* MART=65535 us, MIRT=256 us, TSFTOFST=0 us */ + ADM8211_CSR_WRITE(RSPT, 0xffffff00); + + /* Initialize BBP (and SYN) */ + adm8211_hw_init_bbp(dev); + + /* make sure interrupts are off */ + ADM8211_CSR_WRITE(IER, 0); + + /* ACK interrupts */ + ADM8211_CSR_WRITE(STSR, ADM8211_CSR_READ(STSR)); + + /* Setup WEP (turns it off for now) */ + reg = ADM8211_CSR_READ(MACTEST); + reg &= ~(7 << 20); + ADM8211_CSR_WRITE(MACTEST, reg); + + reg = ADM8211_CSR_READ(WEPCTL); + reg &= ~ADM8211_WEPCTL_WEPENABLE; + reg |= ADM8211_WEPCTL_WEPRXBYP; + ADM8211_CSR_WRITE(WEPCTL, reg); + + /* Clear the missed-packet counter. */ + ADM8211_CSR_READ(LPC); + + if (!priv->mac_addr) + return; + + /* set mac address */ + ADM8211_CSR_WRITE(PAR0, *(u32 *)priv->mac_addr); + ADM8211_CSR_WRITE(PAR1, *(u16 *)&priv->mac_addr[4]); +} + +static int adm8211_hw_reset(struct ieee80211_hw *dev) +{ + struct adm8211_priv *priv = dev->priv; + u32 reg, tmp; + int timeout = 100; + + /* Power-on issue */ + /* TODO: check if this is necessary */ + ADM8211_CSR_WRITE(FRCTL, 0); + + /* Reset the chip */ + tmp = ADM8211_CSR_READ(PAR); + ADM8211_CSR_WRITE(PAR, ADM8211_PAR_SWR); + + while ((ADM8211_CSR_READ(PAR) & ADM8211_PAR_SWR) && timeout--) + msleep(50); + + if (timeout <= 0) + return -ETIMEDOUT; + + ADM8211_CSR_WRITE(PAR, tmp); + + if (priv->revid == ADM8211_REV_BA && + (priv->transceiver_type == ADM8211_RFMD2958_RF3000_CONTROL_POWER || + priv->transceiver_type == ADM8211_RFMD2958)) { + reg = ADM8211_CSR_READ(CSR_TEST1); + reg |= (1 << 4) | (1 << 5); + ADM8211_CSR_WRITE(CSR_TEST1, reg); + } else if (priv->revid == ADM8211_REV_CA) { + reg = ADM8211_CSR_READ(CSR_TEST1); + reg &= ~((1 << 4) | (1 << 5)); + ADM8211_CSR_WRITE(CSR_TEST1, reg); + } + + ADM8211_CSR_WRITE(FRCTL, 0); + + reg = ADM8211_CSR_READ(CSR_TEST0); + reg |= ADM8211_CSR_TEST0_EPRLD; /* EEPROM Recall */ + ADM8211_CSR_WRITE(CSR_TEST0, reg); + + adm8211_clear_sram(dev); + + return 0; +} + +static u64 adm8211_get_tsft(struct ieee80211_hw *dev) +{ + struct adm8211_priv *priv = dev->priv; + u32 tsftl; + u64 tsft; + + tsftl = ADM8211_CSR_READ(TSFTL); + tsft = ADM8211_CSR_READ(TSFTH); + tsft <<= 32; + tsft |= tsftl; + + return tsft; +} + +static void adm8211_set_interval(struct ieee80211_hw *dev, + unsigned short bi, unsigned short li) +{ + struct adm8211_priv *priv = dev->priv; + u32 reg; + + /* BP (beacon interval) = data->beacon_interval + * LI (listen interval) = data->listen_interval (in beacon intervals) */ + reg = (bi << 16) | li; + ADM8211_CSR_WRITE(BPLI, reg); +} + +static void adm8211_set_bssid(struct ieee80211_hw *dev, u8 *bssid) +{ + struct adm8211_priv *priv = dev->priv; + u32 reg; + + reg = bssid[0] | (bssid[1] << 8) | (bssid[2] << 16) | (bssid[3] << 24); + ADM8211_CSR_WRITE(BSSID0, reg); + reg = ADM8211_CSR_READ(ABDA1); + reg &= 0x0000ffff; + reg |= (bssid[4] << 16) | (bssid[5] << 24); + ADM8211_CSR_WRITE(ABDA1, reg); +} + +static int adm8211_set_ssid(struct ieee80211_hw *dev, u8 *ssid, size_t ssid_len) +{ + struct adm8211_priv *priv = dev->priv; + u8 buf[36]; + + if (ssid_len > 32) + return -EINVAL; + + memset(buf, 0, sizeof(buf)); + buf[0] = ssid_len; + memcpy(buf + 1, ssid, ssid_len); + adm8211_write_sram_bytes(dev, ADM8211_SRAM_SSID, buf, 33); + /* TODO: configure beacon for adhoc? */ + return 0; +} + +static int adm8211_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) +{ + struct adm8211_priv *priv = dev->priv; + + if (conf->channel != priv->channel) { + priv->channel = conf->channel; + adm8211_rf_set_channel(dev, priv->channel); + } + + return 0; +} + +static int adm8211_config_interface(struct ieee80211_hw *dev, int if_id, + struct ieee80211_if_conf *conf) +{ + struct adm8211_priv *priv = dev->priv; + + if (memcmp(conf->bssid, priv->bssid, ETH_ALEN)) { + adm8211_set_bssid(dev, conf->bssid); + memcpy(priv->bssid, conf->bssid, ETH_ALEN); + } + + if (conf->ssid_len != priv->ssid_len || + memcmp(conf->ssid, priv->ssid, conf->ssid_len)) { + adm8211_set_ssid(dev, conf->ssid, conf->ssid_len); + priv->ssid_len = conf->ssid_len; + memcpy(priv->ssid, conf->ssid, conf->ssid_len); + } + + return 0; +} + +static int adm8211_add_interface(struct ieee80211_hw *dev, + struct ieee80211_if_init_conf *conf) +{ + struct adm8211_priv *priv = dev->priv; + /* NOTE: using IEEE80211_IF_TYPE_MGMT to indicate no mode selected */ + if (priv->mode != IEEE80211_IF_TYPE_MGMT) + return -1; + + switch (conf->type) { + case IEEE80211_IF_TYPE_STA: + case IEEE80211_IF_TYPE_MNTR: + priv->mode = conf->type; + break; + default: + return -EOPNOTSUPP; + } + + priv->mac_addr = conf->mac_addr; + + return 0; +} + +static void adm8211_remove_interface(struct ieee80211_hw *dev, + struct ieee80211_if_init_conf *conf) +{ + struct adm8211_priv *priv = dev->priv; + priv->mode = IEEE80211_IF_TYPE_MGMT; +} + +static int adm8211_init_rings(struct ieee80211_hw *dev) +{ + struct adm8211_priv *priv = dev->priv; + struct adm8211_desc *desc = NULL; + struct adm8211_rx_ring_info *rx_info; + struct adm8211_tx_ring_info *tx_info; + unsigned int i; + + for (i = 0; i < priv->rx_ring_size; i++) { + desc = &priv->rx_ring[i]; + desc->status = 0; + desc->length = cpu_to_le32(RX_PKT_SIZE); + priv->rx_buffers[i].skb = NULL; + } + /* Mark the end of RX ring; hw returns to base address after this + * descriptor */ + desc->length |= cpu_to_le32(RDES1_CONTROL_RER); + + for (i = 0; i < priv->rx_ring_size; i++) { + desc = &priv->rx_ring[i]; + rx_info = &priv->rx_buffers[i]; + + rx_info->skb = dev_alloc_skb(RX_PKT_SIZE); + if (rx_info->skb == NULL) + break; + rx_info->mapping = pci_map_single(priv->pdev, + skb_tail_pointer(rx_info->skb), + RX_PKT_SIZE, + PCI_DMA_FROMDEVICE); + desc->buffer1 = cpu_to_le32(rx_info->mapping); + desc->status = cpu_to_le32(RDES0_STATUS_OWN | RDES0_STATUS_SQL); + } + + /* Setup TX ring. TX buffers descriptors will be filled in as needed */ + for (i = 0; i < priv->tx_ring_size; i++) { + desc = &priv->tx_ring[i]; + tx_info = &priv->tx_buffers[i]; + + tx_info->skb = NULL; + tx_info->mapping = 0; + desc->status = 0; + } + desc->length = cpu_to_le32(TDES1_CONTROL_TER); + + priv->cur_rx = priv->cur_tx = priv->dirty_tx = 0; + ADM8211_CSR_WRITE(RDB, priv->rx_ring_dma); + ADM8211_CSR_WRITE(TDBD, priv->tx_ring_dma); + + return 0; +} + +static void adm8211_free_rings(struct ieee80211_hw *dev) +{ + struct adm8211_priv *priv = dev->priv; + unsigned int i; + + for (i = 0; i < priv->rx_ring_size; i++) { + if (!priv->rx_buffers[i].skb) + continue; + + pci_unmap_single( + priv->pdev, + priv->rx_buffers[i].mapping, + RX_PKT_SIZE, PCI_DMA_FROMDEVICE); + + dev_kfree_skb(priv->rx_buffers[i].skb); + } + + for (i = 0; i < priv->tx_ring_size; i++) { + if (!priv->tx_buffers[i].skb) + continue; + + pci_unmap_single(priv->pdev, + priv->tx_buffers[i].mapping, + priv->tx_buffers[i].skb->len, + PCI_DMA_TODEVICE); + + dev_kfree_skb(priv->tx_buffers[i].skb); + } +} + +static int adm8211_open(struct ieee80211_hw *dev) +{ + struct adm8211_priv *priv = dev->priv; + int retval; + + /* Power up MAC and RF chips */ + retval = adm8211_hw_reset(dev); + if (retval) { + printk(KERN_ERR "%s: hardware reset failed\n", + wiphy_name(dev->wiphy)); + goto fail; + } + + retval = adm8211_init_rings(dev); + if (retval) { + printk(KERN_ERR "%s: failed to initialize rings\n", + wiphy_name(dev->wiphy)); + goto fail; + } + + /* Init hardware */ + adm8211_hw_init(dev); + adm8211_rf_set_channel(dev, priv->channel); + + retval = request_irq(priv->pdev->irq, &adm8211_interrupt, + IRQF_SHARED, "adm8211", dev); + if (retval) { + printk(KERN_ERR "%s: failed to register IRQ handler\n", + wiphy_name(dev->wiphy)); + goto fail; + } + + ADM8211_CSR_WRITE(IER, ADM8211_IER_NIE | ADM8211_IER_AIE | + ADM8211_IER_RCIE | ADM8211_IER_TCIE | + ADM8211_IER_TDUIE | ADM8211_IER_GPTIE); + adm8211_update_mode(dev); + ADM8211_CSR_WRITE(RDR, 0); + + adm8211_set_interval(dev, 100, 10); + return 0; + +fail: + return retval; +} + +static int adm8211_stop(struct ieee80211_hw *dev) +{ + struct adm8211_priv *priv = dev->priv; + + priv->nar = 0; + ADM8211_CSR_WRITE(NAR, 0); + ADM8211_CSR_WRITE(IER, 0); + ADM8211_CSR_READ(NAR); + + free_irq(priv->pdev->irq, dev); + + adm8211_free_rings(dev); + return 0; +} + +static void adm8211_calc_durations(int *dur, int *plcp, size_t payload_len, int len, + int plcp_signal, int short_preamble) +{ + /* Alternative calculation from NetBSD: */ + +/* IEEE 802.11b durations for DSSS PHY in microseconds */ +#define IEEE80211_DUR_DS_LONG_PREAMBLE 144 +#define IEEE80211_DUR_DS_SHORT_PREAMBLE 72 +#define IEEE80211_DUR_DS_FAST_PLCPHDR 24 +#define IEEE80211_DUR_DS_SLOW_PLCPHDR 48 +#define IEEE80211_DUR_DS_SLOW_ACK 112 +#define IEEE80211_DUR_DS_FAST_ACK 56 +#define IEEE80211_DUR_DS_SLOW_CTS 112 +#define IEEE80211_DUR_DS_FAST_CTS 56 +#define IEEE80211_DUR_DS_SLOT 20 +#define IEEE80211_DUR_DS_SIFS 10 + + int remainder; + + *dur = (80 * (24 + payload_len) + plcp_signal - 1) + / plcp_signal; + + if (plcp_signal <= PLCP_SIGNAL_2M) + /* 1-2Mbps WLAN: send ACK/CTS at 1Mbps */ + *dur += 3 * (IEEE80211_DUR_DS_SIFS + + IEEE80211_DUR_DS_SHORT_PREAMBLE + + IEEE80211_DUR_DS_FAST_PLCPHDR) + + IEEE80211_DUR_DS_SLOW_CTS + IEEE80211_DUR_DS_SLOW_ACK; + else + /* 5-11Mbps WLAN: send ACK/CTS at 2Mbps */ + *dur += 3 * (IEEE80211_DUR_DS_SIFS + + IEEE80211_DUR_DS_SHORT_PREAMBLE + + IEEE80211_DUR_DS_FAST_PLCPHDR) + + IEEE80211_DUR_DS_FAST_CTS + IEEE80211_DUR_DS_FAST_ACK; + + /* lengthen duration if long preamble */ + if (!short_preamble) + *dur += 3 * (IEEE80211_DUR_DS_LONG_PREAMBLE - + IEEE80211_DUR_DS_SHORT_PREAMBLE) + + 3 * (IEEE80211_DUR_DS_SLOW_PLCPHDR - + IEEE80211_DUR_DS_FAST_PLCPHDR); + + + *plcp = (80 * len) / plcp_signal; + remainder = (80 * len) % plcp_signal; + if (plcp_signal == PLCP_SIGNAL_11M && + remainder <= 30 && remainder > 0) + *plcp = (*plcp | 0x8000) + 1; + else if (remainder) + (*plcp)++; +} + +/* Transmit skb w/adm8211_tx_hdr (802.11 header created by hardware) */ +static void adm8211_tx_raw(struct ieee80211_hw *dev, struct sk_buff *skb, + u16 plcp_signal, + struct ieee80211_tx_control *control, + size_t hdrlen) +{ + struct adm8211_priv *priv = dev->priv; + unsigned long flags; + dma_addr_t mapping; + unsigned int entry; + u32 flag; + + mapping = pci_map_single(priv->pdev, skb->data, skb->len, + PCI_DMA_TODEVICE); + + spin_lock_irqsave(&priv->lock, flags); + + if (priv->cur_tx - priv->dirty_tx == priv->tx_ring_size / 2) + flag = TDES1_CONTROL_IC | TDES1_CONTROL_LS | TDES1_CONTROL_FS; + else + flag = TDES1_CONTROL_LS | TDES1_CONTROL_FS; + + if (priv->cur_tx - priv->dirty_tx == priv->tx_ring_size - 2) + ieee80211_stop_queue(dev, 0); + + entry = priv->cur_tx % priv->tx_ring_size; + + priv->tx_buffers[entry].skb = skb; + priv->tx_buffers[entry].mapping = mapping; + memcpy(&priv->tx_buffers[entry].tx_control, control, sizeof(*control)); + priv->tx_buffers[entry].hdrlen = hdrlen; + priv->tx_ring[entry].buffer1 = cpu_to_le32(mapping); + + if (entry == priv->tx_ring_size - 1) + flag |= TDES1_CONTROL_TER; + priv->tx_ring[entry].length = cpu_to_le32(flag | skb->len); + + /* Set TX rate (SIGNAL field in PLCP PPDU format) */ + flag = TDES0_CONTROL_OWN | (plcp_signal << 20) | 8 /* ? */; + priv->tx_ring[entry].status = cpu_to_le32(flag); + + priv->cur_tx++; + + spin_unlock_irqrestore(&priv->lock, flags); + + /* Trigger transmit poll */ + ADM8211_CSR_WRITE(TDR, 0); +} + +/* Put adm8211_tx_hdr on skb and transmit */ +static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb, + struct ieee80211_tx_control *control) +{ + struct adm8211_tx_hdr *txhdr; + u16 fc; + size_t payload_len, hdrlen; + int plcp, dur, len, plcp_signal, short_preamble; + struct ieee80211_hdr *hdr; + + if (control->tx_rate < 0) { + short_preamble = 1; + plcp_signal = -control->tx_rate; + } else { + short_preamble = 0; + plcp_signal = control->tx_rate; + } + + hdr = (struct ieee80211_hdr *)skb->data; + fc = le16_to_cpu(hdr->frame_control) & ~IEEE80211_FCTL_PROTECTED; + hdrlen = ieee80211_get_hdrlen(fc); + memcpy(skb->cb, skb->data, hdrlen); + hdr = (struct ieee80211_hdr *)skb->cb; + skb_pull(skb, hdrlen); + payload_len = skb->len; + + txhdr = (struct adm8211_tx_hdr *) skb_push(skb, sizeof(*txhdr)); + memset(txhdr, 0, sizeof(*txhdr)); + memcpy(txhdr->da, ieee80211_get_DA(hdr), ETH_ALEN); + txhdr->signal = plcp_signal; + txhdr->frame_body_size = cpu_to_le16(payload_len); + txhdr->frame_control = hdr->frame_control; + + len = hdrlen + payload_len + FCS_LEN; + if (fc & IEEE80211_FCTL_PROTECTED) + len += 8; + + txhdr->frag = cpu_to_le16(0x0FFF); + adm8211_calc_durations(&dur, &plcp, payload_len, + len, plcp_signal, short_preamble); + txhdr->plcp_frag_head_len = cpu_to_le16(plcp); + txhdr->plcp_frag_tail_len = cpu_to_le16(plcp); + txhdr->dur_frag_head = cpu_to_le16(dur); + txhdr->dur_frag_tail = cpu_to_le16(dur); + + txhdr->header_control = cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_EXTEND_HEADER); + + if (short_preamble) + txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_SHORT_PREAMBLE); + + if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) + txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_RTS); + + if (fc & IEEE80211_FCTL_PROTECTED) + txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_WEP_ENGINE); + + txhdr->retry_limit = control->retry_limit; + + adm8211_tx_raw(dev, skb, plcp_signal, control, hdrlen); + + return NETDEV_TX_OK; +} + +static int adm8211_alloc_rings(struct ieee80211_hw *dev) +{ + struct adm8211_priv *priv = dev->priv; + unsigned int ring_size; + + priv->rx_buffers = kmalloc(sizeof(*priv->rx_buffers) * priv->rx_ring_size + + sizeof(*priv->tx_buffers) * priv->tx_ring_size, GFP_KERNEL); + if (!priv->rx_buffers) + return -ENOMEM; + + priv->tx_buffers = (void *)priv->rx_buffers + + sizeof(*priv->rx_buffers) * priv->rx_ring_size; + + /* Allocate TX/RX descriptors */ + ring_size = sizeof(struct adm8211_desc) * priv->rx_ring_size + + sizeof(struct adm8211_desc) * priv->tx_ring_size; + priv->rx_ring = pci_alloc_consistent(priv->pdev, ring_size, + &priv->rx_ring_dma); + + if (!priv->rx_ring) { + kfree(priv->rx_buffers); + priv->rx_buffers = NULL; + priv->tx_buffers = NULL; + return -ENOMEM; + } + + priv->tx_ring = (struct adm8211_desc *)(priv->rx_ring + + priv->rx_ring_size); + priv->tx_ring_dma = priv->rx_ring_dma + + sizeof(struct adm8211_desc) * priv->rx_ring_size; + + return 0; +} + +static const struct ieee80211_ops adm8211_ops = { + .tx = adm8211_tx, + .open = adm8211_open, + .stop = adm8211_stop, + .add_interface = adm8211_add_interface, + .remove_interface = adm8211_remove_interface, + .config = adm8211_config, + .config_interface = adm8211_config_interface, + .set_multicast_list = adm8211_set_rx_mode, + .get_stats = adm8211_get_stats, + .get_tx_stats = adm8211_get_tx_stats, + .get_tsf = adm8211_get_tsft +}; + +static int __devinit adm8211_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct ieee80211_hw *dev; + struct adm8211_priv *priv; + unsigned long mem_addr, mem_len; + unsigned int io_addr, io_len; + int err; + u32 reg; + u8 perm_addr[ETH_ALEN]; + +#ifndef MODULE + static unsigned int cardidx; + if (!cardidx++) + printk(version); +#endif + + err = pci_enable_device(pdev); + if (err) { + printk(KERN_ERR "%s (adm8211): Cannot enable new PCI device\n", + pci_name(pdev)); + return err; + } + + io_addr = pci_resource_start(pdev, 0); + io_len = pci_resource_len(pdev, 0); + mem_addr = pci_resource_start(pdev, 1); + mem_len = pci_resource_len(pdev, 1); + if (io_len < 256 || mem_len < 1024) { + printk(KERN_ERR "%s (adm8211): Too short PCI resources\n", + pci_name(pdev)); + goto err_disable_pdev; + } + + + /* check signature */ + pci_read_config_dword(pdev, 0x80 /* CR32 */, ®); + if (reg != ADM8211_SIG1 && reg != ADM8211_SIG2) { + printk(KERN_ERR "%s (adm8211): Invalid signature (0x%x)\n", + pci_name(pdev), reg); + goto err_disable_pdev; + } + + err = pci_request_regions(pdev, "adm8211"); + if (err) { + printk(KERN_ERR "%s (adm8211): Cannot obtain PCI resources\n", + pci_name(pdev)); + return err; /* someone else grabbed it? don't disable it */ + } + + if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) || + pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) { + printk(KERN_ERR "%s (adm8211): No suitable DMA available\n", + pci_name(pdev)); + goto err_free_reg; + } + + pci_set_master(pdev); + + dev = ieee80211_alloc_hw(sizeof(*priv), &adm8211_ops); + if (!dev) { + printk(KERN_ERR "%s (adm8211): ieee80211 alloc failed\n", + pci_name(pdev)); + err = -ENOMEM; + goto err_free_reg; + } + priv = dev->priv; + priv->pdev = pdev; + + spin_lock_init(&priv->lock); + + SET_IEEE80211_DEV(dev, &pdev->dev); + + pci_set_drvdata(pdev, dev); + + priv->map = pci_iomap(pdev, 1, mem_len); + if (!priv->map) + priv->map = pci_iomap(pdev, 0, io_len); + + if (!priv->map) { + printk(KERN_ERR "%s (adm8211): Cannot map device memory\n", + pci_name(pdev)); + goto err_free_dev; + } + + priv->rx_ring_size = rx_ring_size; + priv->tx_ring_size = tx_ring_size; + + if (adm8211_alloc_rings(dev)) { + printk(KERN_ERR "%s (adm8211): Cannot allocate TX/RX ring\n", + pci_name(pdev)); + goto err_iounmap; + } + + pci_read_config_byte(pdev, PCI_CLASS_REVISION, &priv->revid); + + *(u32 *)perm_addr = le32_to_cpu((__force __le32)ADM8211_CSR_READ(PAR0)); + *(u16 *)&perm_addr[4] = + le16_to_cpu((__force __le16)ADM8211_CSR_READ(PAR1) & 0xFFFF); + + if (!is_valid_ether_addr(perm_addr)) { + printk(KERN_WARNING "%s (adm8211): Invalid hwaddr in EEPROM!\n", + pci_name(pdev)); + random_ether_addr(perm_addr); + } + SET_IEEE80211_PERM_ADDR(dev, perm_addr); + + dev->extra_tx_headroom = sizeof(struct adm8211_tx_hdr); + dev->flags = IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED; + /* IEEE80211_HW_RX_INCLUDES_FCS in promisc mode */ + + dev->channel_change_time = 1000; + dev->max_rssi = 100; /* FIXME: find better value */ + + priv->modes[0].mode = MODE_IEEE80211B; + /* channel info filled in by adm8211_read_eeprom */ + memcpy(priv->rates, adm8211_rates, sizeof(adm8211_rates)); + priv->modes[0].num_rates = ARRAY_SIZE(adm8211_rates); + priv->modes[0].rates = priv->rates; + + dev->queues = 1; /* ADM8211C supports more, maybe ADM8211B too */ + + priv->retry_limit = 3; + priv->ant_power = 0x40; + priv->tx_power = 0x40; + priv->lpf_cutoff = 0xFF; + priv->lnags_threshold = 0xFF; + priv->mode = IEEE80211_IF_TYPE_MGMT; + + /* Power-on issue. EEPROM won't read correctly without */ + if (priv->revid >= ADM8211_REV_BA) { + ADM8211_CSR_WRITE(FRCTL, 0); + ADM8211_CSR_READ(FRCTL); + ADM8211_CSR_WRITE(FRCTL, 1); + ADM8211_CSR_READ(FRCTL); + msleep(100); + } + + err = adm8211_read_eeprom(dev); + if (err) { + printk(KERN_ERR "%s (adm8211): Can't alloc eeprom buffer\n", + pci_name(pdev)); + goto err_free_desc; + } + + priv->channel = priv->modes[0].channels[0].chan; + + err = ieee80211_register_hwmode(dev, &priv->modes[0]); + if (err) { + printk(KERN_ERR "%s (adm8211): Can't register hwmode\n", + pci_name(pdev)); + goto err_free_desc; + } + + err = ieee80211_register_hw(dev); + if (err) { + printk(KERN_ERR "%s (adm8211): Cannot register device\n", + pci_name(pdev)); + goto err_free_desc; + } + + printk(KERN_INFO "%s: hwaddr " MAC_FMT ", Rev 0x%02x\n", + wiphy_name(dev->wiphy), MAC_ARG(dev->wiphy->perm_addr), + priv->revid); + + return 0; + + err_free_desc: + pci_free_consistent(pdev, + sizeof(struct adm8211_desc) * priv->rx_ring_size + + sizeof(struct adm8211_desc) * priv->tx_ring_size, + priv->rx_ring, priv->rx_ring_dma); + kfree(priv->rx_buffers); + + err_iounmap: + pci_iounmap(pdev, priv->map); + + err_free_dev: + pci_set_drvdata(pdev, NULL); + ieee80211_free_hw(dev); + + err_free_reg: + pci_release_regions(pdev); + + err_disable_pdev: + pci_disable_device(pdev); + return err; +} + + +static void __devexit adm8211_remove(struct pci_dev *pdev) +{ + struct ieee80211_hw *dev = pci_get_drvdata(pdev); + struct adm8211_priv *priv; + + if (!dev) + return; + + ieee80211_unregister_hw(dev); + + priv = dev->priv; + + pci_free_consistent(pdev, + sizeof(struct adm8211_desc) * priv->rx_ring_size + + sizeof(struct adm8211_desc) * priv->tx_ring_size, + priv->rx_ring, priv->rx_ring_dma); + + kfree(priv->rx_buffers); + kfree(priv->eeprom); + pci_iounmap(pdev, priv->map); + pci_release_regions(pdev); + pci_disable_device(pdev); + ieee80211_free_hw(dev); +} + + +#ifdef CONFIG_PM +static int adm8211_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct ieee80211_hw *dev = pci_get_drvdata(pdev); + struct adm8211_priv *priv = dev->priv; + + if (priv->mode != IEEE80211_IF_TYPE_MGMT) { + ieee80211_stop_queues(dev); + adm8211_stop(dev); + } + + pci_save_state(pdev); + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + return 0; +} + +static int adm8211_resume(struct pci_dev *pdev) +{ + struct ieee80211_hw *dev = pci_get_drvdata(pdev); + struct adm8211_priv *priv = dev->priv; + + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + + if (priv->mode != IEEE80211_IF_TYPE_MGMT) { + adm8211_open(dev); + ieee80211_start_queues(dev); + } + + return 0; +} +#endif /* CONFIG_PM */ + + +MODULE_DEVICE_TABLE(pci, adm8211_pci_id_table); + +/* TODO: implement enable_wake */ +static struct pci_driver adm8211_driver = { + .name = "adm8211", + .id_table = adm8211_pci_id_table, + .probe = adm8211_probe, + .remove = __devexit_p(adm8211_remove), +#ifdef CONFIG_PM + .suspend = adm8211_suspend, + .resume = adm8211_resume, +#endif /* CONFIG_PM */ +}; + + + +static int __init adm8211_init(void) +{ +#ifdef MODULE + printk(version); +#endif + + return pci_register_driver(&adm8211_driver); +} + + +static void __exit adm8211_exit(void) +{ + pci_unregister_driver(&adm8211_driver); +} + + +module_init(adm8211_init); +module_exit(adm8211_exit); diff --git a/drivers/net/wireless/adm8211.h b/drivers/net/wireless/adm8211.h new file mode 100644 index 00000000000..795d895f5c9 --- /dev/null +++ b/drivers/net/wireless/adm8211.h @@ -0,0 +1,659 @@ +#ifndef ADM8211_H +#define ADM8211_H + +/* ADM8211 Registers */ + +/* CR32 (SIG) signature */ +#define ADM8211_SIG1 0x82011317 /* ADM8211A */ +#define ADM8211_SIG2 0x82111317 /* ADM8211B/ADM8211C */ + +#define ADM8211_CSR_READ(r) ioread32(&priv->map->r) +#define ADM8211_CSR_WRITE(r, val) iowrite32((val), &priv->map->r) + +/* CSR (Host Control and Status Registers) */ +struct adm8211_csr { + __le32 PAR; /* 0x00 CSR0 */ + __le32 FRCTL; /* 0x04 CSR0A */ + __le32 TDR; /* 0x08 CSR1 */ + __le32 WTDP; /* 0x0C CSR1A */ + __le32 RDR; /* 0x10 CSR2 */ + __le32 WRDP; /* 0x14 CSR2A */ + __le32 RDB; /* 0x18 CSR3 */ + __le32 TDBH; /* 0x1C CSR3A */ + __le32 TDBD; /* 0x20 CSR4 */ + __le32 TDBP; /* 0x24 CSR4A */ + __le32 STSR; /* 0x28 CSR5 */ + __le32 TDBB; /* 0x2C CSR5A */ + __le32 NAR; /* 0x30 CSR6 */ + __le32 CSR6A; /* reserved */ + __le32 IER; /* 0x38 CSR7 */ + __le32 TKIPSCEP; /* 0x3C CSR7A */ + __le32 LPC; /* 0x40 CSR8 */ + __le32 CSR_TEST1; /* 0x44 CSR8A */ + __le32 SPR; /* 0x48 CSR9 */ + __le32 CSR_TEST0; /* 0x4C CSR9A */ + __le32 WCSR; /* 0x50 CSR10 */ + __le32 WPDR; /* 0x54 CSR10A */ + __le32 GPTMR; /* 0x58 CSR11 */ + __le32 GPIO; /* 0x5C CSR11A */ + __le32 BBPCTL; /* 0x60 CSR12 */ + __le32 SYNCTL; /* 0x64 CSR12A */ + __le32 PLCPHD; /* 0x68 CSR13 */ + __le32 MMIWA; /* 0x6C CSR13A */ + __le32 MMIRD0; /* 0x70 CSR14 */ + __le32 MMIRD1; /* 0x74 CSR14A */ + __le32 TXBR; /* 0x78 CSR15 */ + __le32 SYNDATA; /* 0x7C CSR15A */ + __le32 ALCS; /* 0x80 CSR16 */ + __le32 TOFS2; /* 0x84 CSR17 */ + __le32 CMDR; /* 0x88 CSR18 */ + __le32 PCIC; /* 0x8C CSR19 */ + __le32 PMCSR; /* 0x90 CSR20 */ + __le32 PAR0; /* 0x94 CSR21 */ + __le32 PAR1; /* 0x98 CSR22 */ + __le32 MAR0; /* 0x9C CSR23 */ + __le32 MAR1; /* 0xA0 CSR24 */ + __le32 ATIMDA0; /* 0xA4 CSR25 */ + __le32 ABDA1; /* 0xA8 CSR26 */ + __le32 BSSID0; /* 0xAC CSR27 */ + __le32 TXLMT; /* 0xB0 CSR28 */ + __le32 MIBCNT; /* 0xB4 CSR29 */ + __le32 BCNT; /* 0xB8 CSR30 */ + __le32 TSFTH; /* 0xBC CSR31 */ + __le32 TSC; /* 0xC0 CSR32 */ + __le32 SYNRF; /* 0xC4 CSR33 */ + __le32 BPLI; /* 0xC8 CSR34 */ + __le32 CAP0; /* 0xCC CSR35 */ + __le32 CAP1; /* 0xD0 CSR36 */ + __le32 RMD; /* 0xD4 CSR37 */ + __le32 CFPP; /* 0xD8 CSR38 */ + __le32 TOFS0; /* 0xDC CSR39 */ + __le32 TOFS1; /* 0xE0 CSR40 */ + __le32 IFST; /* 0xE4 CSR41 */ + __le32 RSPT; /* 0xE8 CSR42 */ + __le32 TSFTL; /* 0xEC CSR43 */ + __le32 WEPCTL; /* 0xF0 CSR44 */ + __le32 WESK; /* 0xF4 CSR45 */ + __le32 WEPCNT; /* 0xF8 CSR46 */ + __le32 MACTEST; /* 0xFC CSR47 */ + __le32 FER; /* 0x100 */ + __le32 FEMR; /* 0x104 */ + __le32 FPSR; /* 0x108 */ + __le32 FFER; /* 0x10C */ +} __attribute__ ((packed)); + +/* CSR0 - PAR (PCI Address Register) */ +#define ADM8211_PAR_MWIE (1 << 24) +#define ADM8211_PAR_MRLE (1 << 23) +#define ADM8211_PAR_MRME (1 << 21) +#define ADM8211_PAR_RAP ((1 << 18) | (1 << 17)) +#define ADM8211_PAR_CAL ((1 << 15) | (1 << 14)) +#define ADM8211_PAR_PBL 0x00003f00 +#define ADM8211_PAR_BLE (1 << 7) +#define ADM8211_PAR_DSL 0x0000007c +#define ADM8211_PAR_BAR (1 << 1) +#define ADM8211_PAR_SWR (1 << 0) + +/* CSR1 - FRCTL (Frame Control Register) */ +#define ADM8211_FRCTL_PWRMGT (1 << 31) +#define ADM8211_FRCTL_MAXPSP (1 << 27) +#define ADM8211_FRCTL_DRVPRSP (1 << 26) +#define ADM8211_FRCTL_DRVBCON (1 << 25) +#define ADM8211_FRCTL_AID 0x0000ffff +#define ADM8211_FRCTL_AID_ON 0x0000c000 + +/* CSR5 - STSR (Status Register) */ +#define ADM8211_STSR_PCF (1 << 31) +#define ADM8211_STSR_BCNTC (1 << 30) +#define ADM8211_STSR_GPINT (1 << 29) +#define ADM8211_STSR_LinkOff (1 << 28) +#define ADM8211_STSR_ATIMTC (1 << 27) +#define ADM8211_STSR_TSFTF (1 << 26) +#define ADM8211_STSR_TSCZ (1 << 25) +#define ADM8211_STSR_LinkOn (1 << 24) +#define ADM8211_STSR_SQL (1 << 23) +#define ADM8211_STSR_WEPTD (1 << 22) +#define ADM8211_STSR_ATIME (1 << 21) +#define ADM8211_STSR_TBTT (1 << 20) +#define ADM8211_STSR_NISS (1 << 16) +#define ADM8211_STSR_AISS (1 << 15) +#define ADM8211_STSR_TEIS (1 << 14) +#define ADM8211_STSR_FBE (1 << 13) +#define ADM8211_STSR_REIS (1 << 12) +#define ADM8211_STSR_GPTT (1 << 11) +#define ADM8211_STSR_RPS (1 << 8) +#define ADM8211_STSR_RDU (1 << 7) +#define ADM8211_STSR_RCI (1 << 6) +#define ADM8211_STSR_TUF (1 << 5) +#define ADM8211_STSR_TRT (1 << 4) +#define ADM8211_STSR_TLT (1 << 3) +#define ADM8211_STSR_TDU (1 << 2) +#define ADM8211_STSR_TPS (1 << 1) +#define ADM8211_STSR_TCI (1 << 0) + +/* CSR6 - NAR (Network Access Register) */ +#define ADM8211_NAR_TXCF (1 << 31) +#define ADM8211_NAR_HF (1 << 30) +#define ADM8211_NAR_UTR (1 << 29) +#define ADM8211_NAR_SQ (1 << 28) +#define ADM8211_NAR_CFP (1 << 27) +#define ADM8211_NAR_SF (1 << 21) +#define ADM8211_NAR_TR ((1 << 15) | (1 << 14)) +#define ADM8211_NAR_ST (1 << 13) +#define ADM8211_NAR_OM ((1 << 11) | (1 << 10)) +#define ADM8211_NAR_MM (1 << 7) +#define ADM8211_NAR_PR (1 << 6) +#define ADM8211_NAR_EA (1 << 5) +#define ADM8211_NAR_PB (1 << 3) +#define ADM8211_NAR_STPDMA (1 << 2) +#define ADM8211_NAR_SR (1 << 1) +#define ADM8211_NAR_CTX (1 << 0) + +#define ADM8211_IDLE() \ +do { \ + if (priv->nar & (ADM8211_NAR_SR | ADM8211_NAR_ST)) { \ + ADM8211_CSR_WRITE(NAR, priv->nar & \ + ~(ADM8211_NAR_SR | ADM8211_NAR_ST));\ + ADM8211_CSR_READ(NAR); \ + msleep(20); \ + } \ +} while (0) + +#define ADM8211_IDLE_RX() \ +do { \ + if (priv->nar & ADM8211_NAR_SR) { \ + ADM8211_CSR_WRITE(NAR, priv->nar & ~ADM8211_NAR_SR); \ + ADM8211_CSR_READ(NAR); \ + mdelay(20); \ + } \ +} while (0) + +#define ADM8211_RESTORE() \ +do { \ + if (priv->nar & (ADM8211_NAR_SR | ADM8211_NAR_ST)) \ + ADM8211_CSR_WRITE(NAR, priv->nar); \ +} while (0) + +/* CSR7 - IER (Interrupt Enable Register) */ +#define ADM8211_IER_PCFIE (1 << 31) +#define ADM8211_IER_BCNTCIE (1 << 30) +#define ADM8211_IER_GPIE (1 << 29) +#define ADM8211_IER_LinkOffIE (1 << 28) +#define ADM8211_IER_ATIMTCIE (1 << 27) +#define ADM8211_IER_TSFTFIE (1 << 26) +#define ADM8211_IER_TSCZE (1 << 25) +#define ADM8211_IER_LinkOnIE (1 << 24) +#define ADM8211_IER_SQLIE (1 << 23) +#define ADM8211_IER_WEPIE (1 << 22) +#define ADM8211_IER_ATIMEIE (1 << 21) +#define ADM8211_IER_TBTTIE (1 << 20) +#define ADM8211_IER_NIE (1 << 16) +#define ADM8211_IER_AIE (1 << 15) +#define ADM8211_IER_TEIE (1 << 14) +#define ADM8211_IER_FBEIE (1 << 13) +#define ADM8211_IER_REIE (1 << 12) +#define ADM8211_IER_GPTIE (1 << 11) +#define ADM8211_IER_RSIE (1 << 8) +#define ADM8211_IER_RUIE (1 << 7) +#define ADM8211_IER_RCIE (1 << 6) +#define ADM8211_IER_TUIE (1 << 5) +#define ADM8211_IER_TRTIE (1 << 4) +#define ADM8211_IER_TLTTIE (1 << 3) +#define ADM8211_IER_TDUIE (1 << 2) +#define ADM8211_IER_TPSIE (1 << 1) +#define ADM8211_IER_TCIE (1 << 0) + +/* CSR9 - SPR (Serial Port Register) */ +#define ADM8211_SPR_SRS (1 << 11) +#define ADM8211_SPR_SDO (1 << 3) +#define ADM8211_SPR_SDI (1 << 2) +#define ADM8211_SPR_SCLK (1 << 1) +#define ADM8211_SPR_SCS (1 << 0) + +/* CSR9A - CSR_TEST0 */ +#define ADM8211_CSR_TEST0_EPNE (1 << 18) +#define ADM8211_CSR_TEST0_EPSNM (1 << 17) +#define ADM8211_CSR_TEST0_EPTYP (1 << 16) +#define ADM8211_CSR_TEST0_EPRLD (1 << 15) + +/* CSR10 - WCSR (Wake-up Control/Status Register) */ +#define ADM8211_WCSR_CRCT (1 << 30) +#define ADM8211_WCSR_TSFTWE (1 << 20) +#define ADM8211_WCSR_TIMWE (1 << 19) +#define ADM8211_WCSR_ATIMWE (1 << 18) +#define ADM8211_WCSR_KEYWE (1 << 17) +#define ADM8211_WCSR_MPRE (1 << 9) +#define ADM8211_WCSR_LSOE (1 << 8) +#define ADM8211_WCSR_KEYUP (1 << 6) +#define ADM8211_WCSR_TSFTW (1 << 5) +#define ADM8211_WCSR_TIMW (1 << 4) +#define ADM8211_WCSR_ATIMW (1 << 3) +#define ADM8211_WCSR_MPR (1 << 1) +#define ADM8211_WCSR_LSO (1 << 0) + +/* CSR11A - GPIO */ +#define ADM8211_CSR_GPIO_EN5 (1 << 17) +#define ADM8211_CSR_GPIO_EN4 (1 << 16) +#define ADM8211_CSR_GPIO_EN3 (1 << 15) +#define ADM8211_CSR_GPIO_EN2 (1 << 14) +#define ADM8211_CSR_GPIO_EN1 (1 << 13) +#define ADM8211_CSR_GPIO_EN0 (1 << 12) +#define ADM8211_CSR_GPIO_O5 (1 << 11) +#define ADM8211_CSR_GPIO_O4 (1 << 10) +#define ADM8211_CSR_GPIO_O3 (1 << 9) +#define ADM8211_CSR_GPIO_O2 (1 << 8) +#define ADM8211_CSR_GPIO_O1 (1 << 7) +#define ADM8211_CSR_GPIO_O0 (1 << 6) +#define ADM8211_CSR_GPIO_IN 0x0000003f + +/* CSR12 - BBPCTL (BBP Control port) */ +#define ADM8211_BBPCTL_MMISEL (1 << 31) +#define ADM8211_BBPCTL_SPICADD (0x7F << 24) +#define ADM8211_BBPCTL_RF3000 (0x20 << 24) +#define ADM8211_BBPCTL_TXCE (1 << 23) +#define ADM8211_BBPCTL_RXCE (1 << 22) +#define ADM8211_BBPCTL_CCAP (1 << 21) +#define ADM8211_BBPCTL_TYPE 0x001c0000 +#define ADM8211_BBPCTL_WR (1 << 17) +#define ADM8211_BBPCTL_RD (1 << 16) +#define ADM8211_BBPCTL_ADDR 0x0000ff00 +#define ADM8211_BBPCTL_DATA 0x000000ff + +/* CSR12A - SYNCTL (Synthesizer Control port) */ +#define ADM8211_SYNCTL_WR (1 << 31) +#define ADM8211_SYNCTL_RD (1 << 30) +#define ADM8211_SYNCTL_CS0 (1 << 29) +#define ADM8211_SYNCTL_CS1 (1 << 28) +#define ADM8211_SYNCTL_CAL (1 << 27) +#define ADM8211_SYNCTL_SELCAL (1 << 26) +#define ADM8211_SYNCTL_RFtype ((1 << 24) || (1 << 23) || (1 << 22)) +#define ADM8211_SYNCTL_RFMD (1 << 22) +#define ADM8211_SYNCTL_GENERAL (0x7 << 22) +/* SYNCTL 21:0 Data (Si4126: 18-bit data, 4-bit address) */ + +/* CSR18 - CMDR (Command Register) */ +#define ADM8211_CMDR_PM (1 << 19) +#define ADM8211_CMDR_APM (1 << 18) +#define ADM8211_CMDR_RTE (1 << 4) +#define ADM8211_CMDR_DRT ((1 << 3) | (1 << 2)) +#define ADM8211_CMDR_DRT_8DW (0x0 << 2) +#define ADM8211_CMDR_DRT_16DW (0x1 << 2) +#define ADM8211_CMDR_DRT_SF (0x2 << 2) + +/* CSR33 - SYNRF (SYNRF direct control) */ +#define ADM8211_SYNRF_SELSYN (1 << 31) +#define ADM8211_SYNRF_SELRF (1 << 30) +#define ADM8211_SYNRF_LERF (1 << 29) +#define ADM8211_SYNRF_LEIF (1 << 28) +#define ADM8211_SYNRF_SYNCLK (1 << 27) +#define ADM8211_SYNRF_SYNDATA (1 << 26) +#define ADM8211_SYNRF_PE1 (1 << 25) +#define ADM8211_SYNRF_PE2 (1 << 24) +#define ADM8211_SYNRF_PA_PE (1 << 23) +#define ADM8211_SYNRF_TR_SW (1 << 22) +#define ADM8211_SYNRF_TR_SWN (1 << 21) +#define ADM8211_SYNRF_RADIO (1 << 20) +#define ADM8211_SYNRF_CAL_EN (1 << 19) +#define ADM8211_SYNRF_PHYRST (1 << 18) + +#define ADM8211_SYNRF_IF_SELECT_0 (1 << 31) +#define ADM8211_SYNRF_IF_SELECT_1 ((1 << 31) | (1 << 28)) +#define ADM8211_SYNRF_WRITE_SYNDATA_0 (1 << 31) +#define ADM8211_SYNRF_WRITE_SYNDATA_1 ((1 << 31) | (1 << 26)) +#define ADM8211_SYNRF_WRITE_CLOCK_0 (1 << 31) +#define ADM8211_SYNRF_WRITE_CLOCK_1 ((1 << 31) | (1 << 27)) + +/* CSR44 - WEPCTL (WEP Control) */ +#define ADM8211_WEPCTL_WEPENABLE (1 << 31) +#define ADM8211_WEPCTL_WPAENABLE (1 << 30) +#define ADM8211_WEPCTL_CURRENT_TABLE (1 << 29) +#define ADM8211_WEPCTL_TABLE_WR (1 << 28) +#define ADM8211_WEPCTL_TABLE_RD (1 << 27) +#define ADM8211_WEPCTL_WEPRXBYP (1 << 25) +#define ADM8211_WEPCTL_SEL_WEPTABLE (1 << 23) +#define ADM8211_WEPCTL_ADDR (0x000001ff) + +/* CSR45 - WESK (Data Entry for Share/Individual Key) */ +#define ADM8211_WESK_DATA (0x0000ffff) + +/* FER (Function Event Register) */ +#define ADM8211_FER_INTR_EV_ENT (1 << 15) + + +/* Si4126 RF Synthesizer - Control Registers */ +#define SI4126_MAIN_CONF 0 +#define SI4126_PHASE_DET_GAIN 1 +#define SI4126_POWERDOWN 2 +#define SI4126_RF1_N_DIV 3 /* only Si4136 */ +#define SI4126_RF2_N_DIV 4 +#define SI4126_IF_N_DIV 5 +#define SI4126_RF1_R_DIV 6 /* only Si4136 */ +#define SI4126_RF2_R_DIV 7 +#define SI4126_IF_R_DIV 8 + +/* Main Configuration */ +#define SI4126_MAIN_XINDIV2 (1 << 6) +#define SI4126_MAIN_IFDIV ((1 << 11) | (1 << 10)) +/* Powerdown */ +#define SI4126_POWERDOWN_PDIB (1 << 1) +#define SI4126_POWERDOWN_PDRB (1 << 0) + + +/* RF3000 BBP - Control Port Registers */ +/* 0x00 - reserved */ +#define RF3000_MODEM_CTRL__RX_STATUS 0x01 +#define RF3000_CCA_CTRL 0x02 +#define RF3000_DIVERSITY__RSSI 0x03 +#define RF3000_RX_SIGNAL_FIELD 0x04 +#define RF3000_RX_LEN_MSB 0x05 +#define RF3000_RX_LEN_LSB 0x06 +#define RF3000_RX_SERVICE_FIELD 0x07 +#define RF3000_TX_VAR_GAIN__TX_LEN_EXT 0x11 +#define RF3000_TX_LEN_MSB 0x12 +#define RF3000_TX_LEN_LSB 0x13 +#define RF3000_LOW_GAIN_CALIB 0x14 +#define RF3000_HIGH_GAIN_CALIB 0x15 + +/* ADM8211 revisions */ +#define ADM8211_REV_AB 0x11 +#define ADM8211_REV_AF 0x15 +#define ADM8211_REV_BA 0x20 +#define ADM8211_REV_CA 0x30 + +struct adm8211_desc { + __le32 status; + __le32 length; + __le32 buffer1; + __le32 buffer2; +}; + +#define RDES0_STATUS_OWN (1 << 31) +#define RDES0_STATUS_ES (1 << 30) +#define RDES0_STATUS_SQL (1 << 29) +#define RDES0_STATUS_DE (1 << 28) +#define RDES0_STATUS_FS (1 << 27) +#define RDES0_STATUS_LS (1 << 26) +#define RDES0_STATUS_PCF (1 << 25) +#define RDES0_STATUS_SFDE (1 << 24) +#define RDES0_STATUS_SIGE (1 << 23) +#define RDES0_STATUS_CRC16E (1 << 22) +#define RDES0_STATUS_RXTOE (1 << 21) +#define RDES0_STATUS_CRC32E (1 << 20) +#define RDES0_STATUS_ICVE (1 << 19) +#define RDES0_STATUS_DA1 (1 << 17) +#define RDES0_STATUS_DA0 (1 << 16) +#define RDES0_STATUS_RXDR ((1 << 15) | (1 << 14) | (1 << 13) | (1 << 12)) +#define RDES0_STATUS_FL (0x00000fff) + +#define RDES1_CONTROL_RER (1 << 25) +#define RDES1_CONTROL_RCH (1 << 24) +#define RDES1_CONTROL_RBS2 (0x00fff000) +#define RDES1_CONTROL_RBS1 (0x00000fff) + +#define RDES1_STATUS_RSSI (0x0000007f) + + +#define TDES0_CONTROL_OWN (1 << 31) +#define TDES0_CONTROL_DONE (1 << 30) +#define TDES0_CONTROL_TXDR (0x0ff00000) + +#define TDES0_STATUS_OWN (1 << 31) +#define TDES0_STATUS_DONE (1 << 30) +#define TDES0_STATUS_ES (1 << 29) +#define TDES0_STATUS_TLT (1 << 28) +#define TDES0_STATUS_TRT (1 << 27) +#define TDES0_STATUS_TUF (1 << 26) +#define TDES0_STATUS_TRO (1 << 25) +#define TDES0_STATUS_SOFBR (1 << 24) +#define TDES0_STATUS_ACR (0x00000fff) + +#define TDES1_CONTROL_IC (1 << 31) +#define TDES1_CONTROL_LS (1 << 30) +#define TDES1_CONTROL_FS (1 << 29) +#define TDES1_CONTROL_TER (1 << 25) +#define TDES1_CONTROL_TCH (1 << 24) +#define TDES1_CONTROL_RBS2 (0x00fff000) +#define TDES1_CONTROL_RBS1 (0x00000fff) + +/* SRAM offsets */ +#define ADM8211_SRAM(x) (priv->revid < ADM8211_REV_BA ? \ + ADM8211_SRAM_A_ ## x : ADM8211_SRAM_B_ ## x) + +#define ADM8211_SRAM_INDIV_KEY 0x0000 +#define ADM8211_SRAM_A_SHARE_KEY 0x0160 +#define ADM8211_SRAM_B_SHARE_KEY 0x00c0 + +#define ADM8211_SRAM_A_SSID 0x0180 +#define ADM8211_SRAM_B_SSID 0x00d4 +#define ADM8211_SRAM_SSID ADM8211_SRAM(SSID) + +#define ADM8211_SRAM_A_SUPP_RATE 0x0191 +#define ADM8211_SRAM_B_SUPP_RATE 0x00dd +#define ADM8211_SRAM_SUPP_RATE ADM8211_SRAM(SUPP_RATE) + +#define ADM8211_SRAM_A_SIZE 0x0200 +#define ADM8211_SRAM_B_SIZE 0x01c0 +#define ADM8211_SRAM_SIZE ADM8211_SRAM(SIZE) + +struct adm8211_rx_ring_info { + struct sk_buff *skb; + dma_addr_t mapping; +}; + +struct adm8211_tx_ring_info { + struct sk_buff *skb; + dma_addr_t mapping; + struct ieee80211_tx_control tx_control; + size_t hdrlen; +}; + +#define PLCP_SIGNAL_1M 0x0a +#define PLCP_SIGNAL_2M 0x14 +#define PLCP_SIGNAL_5M5 0x37 +#define PLCP_SIGNAL_11M 0x6e + +struct adm8211_tx_hdr { + u8 da[6]; + u8 signal; /* PLCP signal / TX rate in 100 Kbps */ + u8 service; + __le16 frame_body_size; + __le16 frame_control; + __le16 plcp_frag_tail_len; + __le16 plcp_frag_head_len; + __le16 dur_frag_tail; + __le16 dur_frag_head; + u8 addr4[6]; + +#define ADM8211_TXHDRCTL_SHORT_PREAMBLE (1 << 0) +#define ADM8211_TXHDRCTL_MORE_FRAG (1 << 1) +#define ADM8211_TXHDRCTL_MORE_DATA (1 << 2) +#define ADM8211_TXHDRCTL_FRAG_NO (1 << 3) /* ? */ +#define ADM8211_TXHDRCTL_ENABLE_RTS (1 << 4) +#define ADM8211_TXHDRCTL_ENABLE_WEP_ENGINE (1 << 5) +#define ADM8211_TXHDRCTL_ENABLE_EXTEND_HEADER (1 << 15) /* ? */ + __le16 header_control; + __le16 frag; + u8 reserved_0; + u8 retry_limit; + + u32 wep2key0; + u32 wep2key1; + u32 wep2key2; + u32 wep2key3; + + u8 keyid; + u8 entry_control; // huh?? + u16 reserved_1; + u32 reserved_2; +} __attribute__ ((packed)); + + +#define RX_COPY_BREAK 128 +#define RX_PKT_SIZE 2500 + +struct adm8211_eeprom { + __le16 signature; /* 0x00 */ + u8 major_version; /* 0x02 */ + u8 minor_version; /* 0x03 */ + u8 reserved_1[4]; /* 0x04 */ + u8 hwaddr[6]; /* 0x08 */ + u8 reserved_2[8]; /* 0x1E */ + __le16 cr49; /* 0x16 */ + u8 cr03; /* 0x18 */ + u8 cr28; /* 0x19 */ + u8 cr29; /* 0x1A */ + u8 country_code; /* 0x1B */ + +/* specific bbp types */ +#define ADM8211_BBP_RFMD3000 0x00 +#define ADM8211_BBP_RFMD3002 0x01 +#define ADM8211_BBP_ADM8011 0x04 + u8 specific_bbptype; /* 0x1C */ + u8 specific_rftype; /* 0x1D */ + u8 reserved_3[2]; /* 0x1E */ + __le16 device_id; /* 0x20 */ + __le16 vendor_id; /* 0x22 */ + __le16 subsystem_id; /* 0x24 */ + __le16 subsystem_vendor_id; /* 0x26 */ + u8 maxlat; /* 0x28 */ + u8 mingnt; /* 0x29 */ + __le16 cis_pointer_low; /* 0x2A */ + __le16 cis_pointer_high; /* 0x2C */ + __le16 csr18; /* 0x2E */ + u8 reserved_4[16]; /* 0x30 */ + u8 d1_pwrdara; /* 0x40 */ + u8 d0_pwrdara; /* 0x41 */ + u8 d3_pwrdara; /* 0x42 */ + u8 d2_pwrdara; /* 0x43 */ + u8 antenna_power[14]; /* 0x44 */ + __le16 cis_wordcnt; /* 0x52 */ + u8 tx_power[14]; /* 0x54 */ + u8 lpf_cutoff[14]; /* 0x62 */ + u8 lnags_threshold[14]; /* 0x70 */ + __le16 checksum; /* 0x7E */ + u8 cis_data[0]; /* 0x80, 384 bytes */ +} __attribute__ ((packed)); + +static const struct ieee80211_rate adm8211_rates[] = { + { .rate = 10, + .val = 10, + .val2 = -10, + .flags = IEEE80211_RATE_CCK_2 }, + { .rate = 20, + .val = 20, + .val2 = -20, + .flags = IEEE80211_RATE_CCK_2 }, + { .rate = 55, + .val = 55, + .val2 = -55, + .flags = IEEE80211_RATE_CCK_2 }, + { .rate = 110, + .val = 110, + .val2 = -110, + .flags = IEEE80211_RATE_CCK_2 } +}; + +struct ieee80211_chan_range { + u8 min; + u8 max; +}; + +static const struct ieee80211_channel adm8211_channels[] = { + { .chan = 1, + .freq = 2412}, + { .chan = 2, + .freq = 2417}, + { .chan = 3, + .freq = 2422}, + { .chan = 4, + .freq = 2427}, + { .chan = 5, + .freq = 2432}, + { .chan = 6, + .freq = 2437}, + { .chan = 7, + .freq = 2442}, + { .chan = 8, + .freq = 2447}, + { .chan = 9, + .freq = 2452}, + { .chan = 10, + .freq = 2457}, + { .chan = 11, + .freq = 2462}, + { .chan = 12, + .freq = 2467}, + { .chan = 13, + .freq = 2472}, + { .chan = 14, + .freq = 2484}, +}; + +struct adm8211_priv { + struct pci_dev *pdev; + spinlock_t lock; + struct adm8211_csr __iomem *map; + struct adm8211_desc *rx_ring; + struct adm8211_desc *tx_ring; + dma_addr_t rx_ring_dma; + dma_addr_t tx_ring_dma; + struct adm8211_rx_ring_info *rx_buffers; + struct adm8211_tx_ring_info *tx_buffers; + unsigned int rx_ring_size, tx_ring_size; + unsigned int cur_tx, dirty_tx, cur_rx; + + struct ieee80211_low_level_stats stats; + struct ieee80211_hw_mode modes[1]; + struct ieee80211_channel channels[ARRAY_SIZE(adm8211_channels)]; + struct ieee80211_rate rates[ARRAY_SIZE(adm8211_rates)]; + int mode; + + int channel; + u8 bssid[ETH_ALEN]; + u8 ssid[32]; + size_t ssid_len; + u8 *mac_addr; + + u8 soft_rx_crc; + u8 retry_limit; + + u8 ant_power; + u8 tx_power; + u8 lpf_cutoff; + u8 lnags_threshold; + struct adm8211_eeprom *eeprom; + size_t eeprom_len; + + u8 revid; + + u32 nar; + +#define ADM8211_TYPE_INTERSIL 0x00 +#define ADM8211_TYPE_RFMD 0x01 +#define ADM8211_TYPE_MARVEL 0x02 +#define ADM8211_TYPE_AIROHA 0x03 +#define ADM8211_TYPE_ADMTEK 0x05 + unsigned int rf_type:3; + unsigned int bbp_type:3; + + u8 specific_bbptype; + enum { + ADM8211_RFMD2948 = 0x0, + ADM8211_RFMD2958 = 0x1, + ADM8211_RFMD2958_RF3000_CONTROL_POWER = 0x2, + ADM8211_MAX2820 = 0x8, + ADM8211_AL2210L = 0xC, /* Airoha */ + } transceiver_type; +}; + +static const struct ieee80211_chan_range cranges[] = { + {1, 11}, /* FCC */ + {1, 11}, /* IC */ + {1, 13}, /* ETSI */ + {10, 11}, /* SPAIN */ + {10, 13}, /* FRANCE */ + {14, 14}, /* MMK */ + {1, 14}, /* MMK2 */ +}; + +#endif /* ADM8211_H */ -- cgit v1.2.3-70-g09d2 From c5691235cf70ae2bd71c1f445eb991191530ec6c Mon Sep 17 00:00:00 2001 From: Ulrich Kunitz Date: Sat, 21 Jul 2007 22:42:13 +0100 Subject: [PATCH] zd1211rw: monitor all packets While in monitor mode the zd1211rw received only a limited set of packets. This patch forwards now all packets the device receives. Notify that while monitoring no FCS checks are done; so strange packets might appear in the network sniffer of your choice. ATTENTION: Support for multiple interfaces on a single ZD1211 device is currently broken. So this code works only on the first interface. Here is an example to put the device in monitor mode. iwconfig wlan0 mode monitor ifconfig wlan0 up iwconfig wlan0 channel 10 [dsd@gentoo.org: backport to mainline] Signed-off-by: Ulrich Kunitz Signed-off-by: Daniel Drake Signed-off-by: John W. Linville --- drivers/net/wireless/zd1211rw/zd_chip.h | 5 ---- drivers/net/wireless/zd1211rw/zd_mac.c | 44 ++++++++++++++++++++++++++++----- 2 files changed, 38 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h index f4698576ab7..8009b70213e 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.h +++ b/drivers/net/wireless/zd1211rw/zd_chip.h @@ -871,11 +871,6 @@ static inline int zd_chip_set_basic_rates(struct zd_chip *chip, u16 cr_rates) return r; } -static inline int zd_chip_set_rx_filter(struct zd_chip *chip, u32 filter) -{ - return zd_iowrite32(chip, CR_RX_FILTER, filter); -} - int zd_chip_lock_phy_regs(struct zd_chip *chip); int zd_chip_unlock_phy_regs(struct zd_chip *chip); diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 26869d107e5..7ec1fcf37fc 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -161,13 +161,33 @@ void zd_mac_clear(struct zd_mac *mac) ZD_MEMCLEAR(mac, sizeof(struct zd_mac)); } -static int reset_mode(struct zd_mac *mac) +static int set_rx_filter(struct zd_mac *mac) { struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); u32 filter = (ieee->iw_mode == IW_MODE_MONITOR) ? ~0 : STA_RX_FILTER; return zd_iowrite32(&mac->chip, CR_RX_FILTER, filter); } +static int set_sniffer(struct zd_mac *mac) +{ + struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); + return zd_iowrite32(&mac->chip, CR_SNIFFER_ON, + ieee->iw_mode == IW_MODE_MONITOR ? 1 : 0); + return 0; +} + +static int set_mc_hash(struct zd_mac *mac) +{ + struct zd_mc_hash hash; + struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); + + zd_mc_clear(&hash); + if (ieee->iw_mode == IW_MODE_MONITOR) + zd_mc_add_all(&hash); + + return zd_chip_set_multicast_hash(&mac->chip, &hash); +} + int zd_mac_open(struct net_device *netdev) { struct zd_mac *mac = zd_netdev_mac(netdev); @@ -194,7 +214,13 @@ int zd_mac_open(struct net_device *netdev) r = zd_chip_set_basic_rates(chip, CR_RATES_80211B | CR_RATES_80211G); if (r < 0) goto disable_int; - r = reset_mode(mac); + r = set_rx_filter(mac); + if (r) + goto disable_int; + r = set_sniffer(mac); + if (r) + goto disable_int; + r = set_mc_hash(mac); if (r) goto disable_int; r = zd_chip_switch_radio_on(chip); @@ -298,12 +324,14 @@ static void set_multicast_hash_handler(struct work_struct *work) void zd_mac_set_multicast_list(struct net_device *dev) { - struct zd_mc_hash hash; struct zd_mac *mac = zd_netdev_mac(dev); + struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); + struct zd_mc_hash hash; struct dev_mc_list *mc; unsigned long flags; - if (dev->flags & (IFF_PROMISC|IFF_ALLMULTI)) { + if (dev->flags & (IFF_PROMISC|IFF_ALLMULTI) || + ieee->iw_mode == IW_MODE_MONITOR) { zd_mc_add_all(&hash); } else { zd_mc_clear(&hash); @@ -628,8 +656,12 @@ int zd_mac_set_mode(struct zd_mac *mac, u32 mode) ieee->iw_mode = mode; spin_unlock_irq(&ieee->lock); - if (netif_running(mac->netdev)) - return reset_mode(mac); + if (netif_running(mac->netdev)) { + int r = set_rx_filter(mac); + if (r) + return r; + return set_sniffer(mac); + } return 0; } -- cgit v1.2.3-70-g09d2 From e12dcb05bf70dfa328173fd55b7c13e71dfdb453 Mon Sep 17 00:00:00 2001 From: Faidon Liambotis Date: Sun, 22 Jul 2007 16:16:36 +0300 Subject: [PATCH] Kconfig: order options Reorder the Atmel options so that the menu appears saner. Before: < > Hermes chipset 802.11b support (Orinoco/Prism2/Symbol) <*> Atmel at76c50x chipset 802.11b support < > Atmel at76c506 PCI cards (NEW) < > Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards < > Atmel at76c502/at76c504 PCMCIA cards (NEW) After: < > Hermes chipset 802.11b support (Orinoco/Prism2/Symbol) <*> Atmel at76c50x chipset 802.11b support < > Atmel at76c506 PCI cards (NEW) < > Atmel at76c502/at76c504 PCMCIA cards (NEW) < > Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards Signed-off-by: Faidon Liambotis Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 68 ++++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 86480afe535..8c103f92ed6 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -379,30 +379,6 @@ config PCI_HERMES common. Some of the built-in wireless adaptors in laptops are of this variety. -config ATMEL - tristate "Atmel at76c50x chipset 802.11b support" - depends on (PCI || PCMCIA) && WLAN_80211 - select WIRELESS_EXT - select FW_LOADER - select CRC32 - ---help--- - A driver 802.11b wireless cards based on the Atmel fast-vnet - chips. This driver supports standard Linux wireless extensions. - - Many cards based on this chipset do not have flash memory - and need their firmware loaded at start-up. If yours is - one of these, you will need to provide a firmware image - to be loaded into the card by the driver. The Atmel - firmware package can be downloaded from - - -config PCI_ATMEL - tristate "Atmel at76c506 PCI cards" - depends on ATMEL && PCI - ---help--- - Enable support for PCI and mini-PCI cards containing the - Atmel at76c506 chip. - config PCMCIA_HERMES tristate "Hermes PCMCIA card support" depends on PCMCIA && HERMES @@ -437,6 +413,40 @@ config PCMCIA_SPECTRUM for downloading Symbol firmware are available at +config ATMEL + tristate "Atmel at76c50x chipset 802.11b support" + depends on (PCI || PCMCIA) && WLAN_80211 + select WIRELESS_EXT + select FW_LOADER + select CRC32 + ---help--- + A driver 802.11b wireless cards based on the Atmel fast-vnet + chips. This driver supports standard Linux wireless extensions. + + Many cards based on this chipset do not have flash memory + and need their firmware loaded at start-up. If yours is + one of these, you will need to provide a firmware image + to be loaded into the card by the driver. The Atmel + firmware package can be downloaded from + + +config PCI_ATMEL + tristate "Atmel at76c506 PCI cards" + depends on ATMEL && PCI + ---help--- + Enable support for PCI and mini-PCI cards containing the + Atmel at76c506 chip. + +config PCMCIA_ATMEL + tristate "Atmel at76c502/at76c504 PCMCIA cards" + depends on ATMEL && PCMCIA + select WIRELESS_EXT + select FW_LOADER + select CRC32 + ---help--- + Enable support for PCMCIA cards containing the + Atmel at76c502 and at76c504 chips. + config AIRO_CS tristate "Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards" depends on PCMCIA && (BROKEN || !M32R) && WLAN_80211 @@ -462,16 +472,6 @@ config AIRO_CS for location). You also want to check out the PCMCIA-HOWTO, available from . -config PCMCIA_ATMEL - tristate "Atmel at76c502/at76c504 PCMCIA cards" - depends on ATMEL && PCMCIA - select WIRELESS_EXT - select FW_LOADER - select CRC32 - ---help--- - Enable support for PCMCIA cards containing the - Atmel at76c502 and at76c504 chips. - config PCMCIA_WL3501 tristate "Planet WL3501 PCMCIA cards" depends on EXPERIMENTAL && PCMCIA && WLAN_80211 -- cgit v1.2.3-70-g09d2 From cfbde697e48891f6216aa9fd14652e099d5cd5fb Mon Sep 17 00:00:00 2001 From: Faidon Liambotis Date: Sun, 22 Jul 2007 16:16:59 +0300 Subject: [PATCH] Kconfig: remove references of pcmcia-cs pcmcia-cs/cardmgr is deprecated and mentioning it in the help text is misleading. Signed-off-by: Faidon Liambotis Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 8c103f92ed6..adf0d207da8 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -63,11 +63,6 @@ config WAVELAN a Radio LAN (wireless Ethernet-like Local Area Network) using the radio frequencies 900 MHz and 2.4 GHz. - This driver support the ISA version of the WaveLAN card. A separate - driver for the PCMCIA (PC-card) hardware is available in David - Hinds' pcmcia-cs package (see the file - for location). - If you want to use an ISA WaveLAN card under Linux, say Y and read the Ethernet-HOWTO, available from . Some more specific @@ -390,12 +385,7 @@ config PCMCIA_HERMES such as the Linksys, D-Link and Farallon Skyline. It should also work on Symbol cards such as the 3Com AirConnect and Ericsson WLAN. - To use your PC-cards, you will need supporting software from David - Hinds' pcmcia-cs package (see the file - for location). You also want to check out the PCMCIA-HOWTO, - available from . - - You will also very likely also need the Wireless Tools in order to + You will very likely need the Wireless Tools in order to configure your card and that /etc/pcmcia/wireless.opts works: . @@ -467,11 +457,6 @@ config AIRO_CS and Cisco proprietary API, so both the Linux Wireless Tools and the Cisco Linux utilities can be used to configure the card. - To use your PC-cards, you will need supporting software from David - Hinds' pcmcia-cs package (see the file - for location). You also want to check out the PCMCIA-HOWTO, - available from . - config PCMCIA_WL3501 tristate "Planet WL3501 PCMCIA cards" depends on EXPERIMENTAL && PCMCIA && WLAN_80211 -- cgit v1.2.3-70-g09d2 From d73ae55ad46be6a0a11b9b71f9910c73c1b9dbb7 Mon Sep 17 00:00:00 2001 From: Bill Nottingham Date: Fri, 27 Jul 2007 19:43:17 -0400 Subject: [PATCH] remove gratuitous space in airo module description Currently the modinfo looks like: description: Support for Cisco/Aironet 802.11 wireless ethernet cards. Direct support for ISA/PCI/MPI cards and support for PCMCIA when used with airo_cs. Arguably, it should be cut at the end of the first sentence. This at least makes it somewhat more legible. Signed-off-by: Bill Nottingham Signed-off-by: John W. Linville --- drivers/net/wireless/airo.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index ee1cc14db38..a152797b951 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -241,8 +241,8 @@ static int proc_perm = 0644; MODULE_AUTHOR("Benjamin Reed"); MODULE_DESCRIPTION("Support for Cisco/Aironet 802.11 wireless ethernet \ - cards. Direct support for ISA/PCI/MPI cards and support \ - for PCMCIA when used with airo_cs."); +cards. Direct support for ISA/PCI/MPI cards and support \ +for PCMCIA when used with airo_cs."); MODULE_LICENSE("Dual BSD/GPL"); MODULE_SUPPORTED_DEVICE("Aironet 4500, 4800 and Cisco 340/350"); module_param_array(io, int, NULL, 0); -- cgit v1.2.3-70-g09d2 From 3623060abbf1cdd7f292645bea31d024e21792ef Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Mon, 30 Jul 2007 07:40:04 +0200 Subject: [PATCH] Use mutex instead of semaphore in the Host AP driver The Host AP driver uses a semaphore as mutex. Use the mutex API instead of the (binary) semaphore. Signed-off-by: Matthias Kaehlcke Acked-by: Satyam Sharma Signed-off-by: Andrew Morton Signed-off-by: John W. Linville --- drivers/net/wireless/hostap/hostap_hw.c | 14 +++++++------- drivers/net/wireless/hostap/hostap_wlan.h | 3 ++- 2 files changed, 9 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c index 959887b70ca..d3dacbceabb 100644 --- a/drivers/net/wireless/hostap/hostap_hw.c +++ b/drivers/net/wireless/hostap/hostap_hw.c @@ -825,7 +825,7 @@ static int hfa384x_get_rid(struct net_device *dev, u16 rid, void *buf, int len, local->hw_downloading) return -ENODEV; - res = down_interruptible(&local->rid_bap_sem); + res = mutex_lock_interruptible(&local->rid_bap_mtx); if (res) return res; @@ -834,7 +834,7 @@ static int hfa384x_get_rid(struct net_device *dev, u16 rid, void *buf, int len, printk(KERN_DEBUG "%s: hfa384x_get_rid: CMDCODE_ACCESS failed " "(res=%d, rid=%04x, len=%d)\n", dev->name, res, rid, len); - up(&local->rid_bap_sem); + mutex_unlock(&local->rid_bap_mtx); return res; } @@ -861,7 +861,7 @@ static int hfa384x_get_rid(struct net_device *dev, u16 rid, void *buf, int len, res = hfa384x_from_bap(dev, BAP0, buf, len); spin_unlock_bh(&local->baplock); - up(&local->rid_bap_sem); + mutex_unlock(&local->rid_bap_mtx); if (res) { if (res != -ENODATA) @@ -902,7 +902,7 @@ static int hfa384x_set_rid(struct net_device *dev, u16 rid, void *buf, int len) /* RID len in words and +1 for rec.rid */ rec.len = cpu_to_le16(len / 2 + len % 2 + 1); - res = down_interruptible(&local->rid_bap_sem); + res = mutex_lock_interruptible(&local->rid_bap_mtx); if (res) return res; @@ -917,12 +917,12 @@ static int hfa384x_set_rid(struct net_device *dev, u16 rid, void *buf, int len) if (res) { printk(KERN_DEBUG "%s: hfa384x_set_rid (rid=%04x, len=%d) - " "failed - res=%d\n", dev->name, rid, len, res); - up(&local->rid_bap_sem); + mutex_unlock(&local->rid_bap_mtx); return res; } res = hfa384x_cmd(dev, HFA384X_CMDCODE_ACCESS_WRITE, rid, NULL, NULL); - up(&local->rid_bap_sem); + mutex_unlock(&local->rid_bap_mtx); if (res) { printk(KERN_DEBUG "%s: hfa384x_set_rid: CMDCODE_ACCESS_WRITE " @@ -3171,7 +3171,7 @@ prism2_init_local_data(struct prism2_helper_functions *funcs, int card_idx, spin_lock_init(&local->cmdlock); spin_lock_init(&local->baplock); spin_lock_init(&local->lock); - init_MUTEX(&local->rid_bap_sem); + mutex_init(&local->rid_bap_mtx); if (card_idx < 0 || card_idx >= MAX_PARM_DEVICES) card_idx = 0; diff --git a/drivers/net/wireless/hostap/hostap_wlan.h b/drivers/net/wireless/hostap/hostap_wlan.h index 87a54aa6f4d..a42325c145b 100644 --- a/drivers/net/wireless/hostap/hostap_wlan.h +++ b/drivers/net/wireless/hostap/hostap_wlan.h @@ -3,6 +3,7 @@ #include #include +#include #include #include "hostap_config.h" @@ -641,7 +642,7 @@ struct local_info { * when removing entries from the list. * TX and RX paths can use read lock. */ spinlock_t cmdlock, baplock, lock; - struct semaphore rid_bap_sem; + struct mutex rid_bap_mtx; u16 infofid; /* MAC buffer id for info frame */ /* txfid, intransmitfid, next_txtid, and next_alloc are protected by * txfidlock */ -- cgit v1.2.3-70-g09d2 From 8951554dba0c7962ae72faece66e8f5085a777d6 Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Tue, 31 Jul 2007 23:34:50 +0200 Subject: [PATCH] drivers/net/wireless/prism54/oid_mgt.c: kmalloc + memset conversion to kzalloc Signed-off-by: Mariusz Kozlowski Acked-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/prism54/oid_mgt.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/prism54/oid_mgt.c b/drivers/net/wireless/prism54/oid_mgt.c index 42780320cd5..57a4ac34bed 100644 --- a/drivers/net/wireless/prism54/oid_mgt.c +++ b/drivers/net/wireless/prism54/oid_mgt.c @@ -244,13 +244,11 @@ mgt_init(islpci_private *priv) /* Alloc the cache */ for (i = 0; i < OID_NUM_LAST; i++) { if (isl_oid[i].flags & OID_FLAG_CACHED) { - priv->mib[i] = kmalloc(isl_oid[i].size * + priv->mib[i] = kzalloc(isl_oid[i].size * (isl_oid[i].range + 1), GFP_KERNEL); if (!priv->mib[i]) return -ENOMEM; - memset(priv->mib[i], 0, - isl_oid[i].size * (isl_oid[i].range + 1)); } else priv->mib[i] = NULL; } -- cgit v1.2.3-70-g09d2 From 6dbc9c89fb242873bd3e83890e59da3d6e462025 Mon Sep 17 00:00:00 2001 From: Yoann Padioleau Date: Fri, 3 Aug 2007 19:37:16 +0200 Subject: [PATCH] dev->priv to netdev_priv(dev), for drivers/net/wireless Replacing accesses to dev->priv to netdev_priv(dev). The replacment is safe when netdev_priv is used to access a private structure that is right next to the net_device structure in memory. Cf http://groups.google.com/group/comp.os.linux.development.system/browse_thread/thread/de19321bcd94dbb8/0d74a4adcd6177bd This is the case when the net_device structure was allocated with a call to alloc_netdev or one of its derivative. Signed-off-by: Yoann Padioleau Cc: mcgrof@gmail.com Cc: linux-wireless@vger.kernel.org Cc: akpm@linux-foundation.org Signed-off-by: John W. Linville --- drivers/net/wireless/arlan-proc.c | 14 +++---- drivers/net/wireless/hostap/hostap_cs.c | 2 +- drivers/net/wireless/hostap/hostap_hw.c | 2 +- drivers/net/wireless/hostap/hostap_ioctl.c | 14 +++---- drivers/net/wireless/orinoco_tmd.c | 2 +- drivers/net/wireless/prism54/isl_ioctl.c | 6 +-- drivers/net/wireless/ray_cs.c | 66 +++++++++++++++--------------- drivers/net/wireless/strip.c | 2 +- drivers/net/wireless/wl3501_cs.c | 66 +++++++++++++++--------------- 9 files changed, 87 insertions(+), 87 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/arlan-proc.c b/drivers/net/wireless/arlan-proc.c index 015abd928ab..c6e70dbc5de 100644 --- a/drivers/net/wireless/arlan-proc.c +++ b/drivers/net/wireless/arlan-proc.c @@ -435,7 +435,7 @@ static int arlan_sysctl_info(ctl_table * ctl, int write, struct file *filp, goto final; } else - priva = arlan_device[devnum]->priv; + priva = netdev_priv(arlan_device[devnum]); if (priva == NULL) { @@ -654,7 +654,7 @@ static int arlan_sysctl_info161719(ctl_table * ctl, int write, struct file *filp goto final; } else - priva = arlan_device[devnum]->priv; + priva = netdev_priv(arlan_device[devnum]); if (priva == NULL) { printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n "); @@ -688,7 +688,7 @@ static int arlan_sysctl_infotxRing(ctl_table * ctl, int write, struct file *filp goto final; } else - priva = arlan_device[devnum]->priv; + priva = netdev_priv(arlan_device[devnum]); if (priva == NULL) { printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n "); @@ -716,7 +716,7 @@ static int arlan_sysctl_inforxRing(ctl_table * ctl, int write, struct file *filp pos += sprintf(arlan_drive_info + pos, "No device found here \n"); goto final; } else - priva = arlan_device[devnum]->priv; + priva = netdev_priv(arlan_device[devnum]); if (priva == NULL) { printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n "); @@ -745,7 +745,7 @@ static int arlan_sysctl_info18(ctl_table * ctl, int write, struct file *filp, goto final; } else - priva = arlan_device[devnum]->priv; + priva = netdev_priv(arlan_device[devnum]); if (priva == NULL) { printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n "); @@ -780,7 +780,7 @@ static int arlan_configure(ctl_table * ctl, int write, struct file *filp, } else if (arlan_device[devnum] != NULL) { - priv = arlan_device[devnum]->priv; + priv = netdev_priv(arlan_device[devnum]); arlan_command(arlan_device[devnum], ARLAN_COMMAND_CLEAN_AND_CONF); } @@ -805,7 +805,7 @@ static int arlan_sysctl_reset(ctl_table * ctl, int write, struct file *filp, } else if (arlan_device[devnum] != NULL) { - priv = arlan_device[devnum]->priv; + priv = netdev_priv(arlan_device[devnum]); arlan_command(arlan_device[devnum], ARLAN_COMMAND_CLEAN_AND_RESET); } else diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c index 30e723f6597..f9cf22bda42 100644 --- a/drivers/net/wireless/hostap/hostap_cs.c +++ b/drivers/net/wireless/hostap/hostap_cs.c @@ -272,7 +272,7 @@ static int sandisk_enable_wireless(struct net_device *dev) { int res, ret = 0; conf_reg_t reg; - struct hostap_interface *iface = dev->priv; + struct hostap_interface *iface = netdev_priv(dev); local_info_t *local = iface->local; tuple_t tuple; cisparse_t *parse = NULL; diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c index d3dacbceabb..adedb971654 100644 --- a/drivers/net/wireless/hostap/hostap_hw.c +++ b/drivers/net/wireless/hostap/hostap_hw.c @@ -3424,7 +3424,7 @@ static void prism2_suspend(struct net_device *dev) struct local_info *local; union iwreq_data wrqu; - iface = dev->priv; + iface = netdev_priv(dev); local = iface->local; /* Send disconnect event, e.g., to trigger reassociation after resume diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c index 8c71077d653..d58ac84f4e9 100644 --- a/drivers/net/wireless/hostap/hostap_ioctl.c +++ b/drivers/net/wireless/hostap/hostap_ioctl.c @@ -3088,7 +3088,7 @@ static int prism2_ioctl_priv_download(local_info_t *local, struct iw_point *p) static int prism2_set_genericelement(struct net_device *dev, u8 *elem, size_t len) { - struct hostap_interface *iface = dev->priv; + struct hostap_interface *iface = netdev_priv(dev); local_info_t *local = iface->local; u8 *buf; @@ -3116,7 +3116,7 @@ static int prism2_ioctl_siwauth(struct net_device *dev, struct iw_request_info *info, struct iw_param *data, char *extra) { - struct hostap_interface *iface = dev->priv; + struct hostap_interface *iface = netdev_priv(dev); local_info_t *local = iface->local; switch (data->flags & IW_AUTH_INDEX) { @@ -3182,7 +3182,7 @@ static int prism2_ioctl_giwauth(struct net_device *dev, struct iw_request_info *info, struct iw_param *data, char *extra) { - struct hostap_interface *iface = dev->priv; + struct hostap_interface *iface = netdev_priv(dev); local_info_t *local = iface->local; switch (data->flags & IW_AUTH_INDEX) { @@ -3221,7 +3221,7 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev, struct iw_request_info *info, struct iw_point *erq, char *extra) { - struct hostap_interface *iface = dev->priv; + struct hostap_interface *iface = netdev_priv(dev); local_info_t *local = iface->local; struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; int i, ret = 0; @@ -3395,7 +3395,7 @@ static int prism2_ioctl_giwencodeext(struct net_device *dev, struct iw_request_info *info, struct iw_point *erq, char *extra) { - struct hostap_interface *iface = dev->priv; + struct hostap_interface *iface = netdev_priv(dev); local_info_t *local = iface->local; struct ieee80211_crypt_data **crypt; void *sta_ptr; @@ -3716,7 +3716,7 @@ static int prism2_ioctl_giwgenie(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *extra) { - struct hostap_interface *iface = dev->priv; + struct hostap_interface *iface = netdev_priv(dev); local_info_t *local = iface->local; int len = local->generic_elem_len - 2; @@ -3755,7 +3755,7 @@ static int prism2_ioctl_siwmlme(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *extra) { - struct hostap_interface *iface = dev->priv; + struct hostap_interface *iface = netdev_priv(dev); local_info_t *local = iface->local; struct iw_mlme *mlme = (struct iw_mlme *) extra; u16 reason; diff --git a/drivers/net/wireless/orinoco_tmd.c b/drivers/net/wireless/orinoco_tmd.c index 7c7b960c91d..b9c54d8fceb 100644 --- a/drivers/net/wireless/orinoco_tmd.c +++ b/drivers/net/wireless/orinoco_tmd.c @@ -190,7 +190,7 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev, static void __devexit orinoco_tmd_remove_one(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); struct orinoco_pci_card *card = priv->card; unregister_netdev(dev); diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c index 585f5996d29..f1066614dc3 100644 --- a/drivers/net/wireless/prism54/isl_ioctl.c +++ b/drivers/net/wireless/prism54/isl_ioctl.c @@ -1753,7 +1753,7 @@ prism54_get_oid(struct net_device *ndev, struct iw_request_info *info, int rvalue; enum oid_num_t n = dwrq->flags; - rvalue = mgt_get_request((islpci_private *) ndev->priv, n, 0, NULL, &r); + rvalue = mgt_get_request(netdev_priv(ndev), n, 0, NULL, &r); dwrq->length = mgt_response_to_str(n, &r, extra); if ((isl_oid[n].flags & OID_FLAG_TYPE) != OID_TYPE_U32) kfree(r.ptr); @@ -1766,7 +1766,7 @@ prism54_set_u32(struct net_device *ndev, struct iw_request_info *info, { u32 oid = uwrq[0], u = uwrq[1]; - return mgt_set_request((islpci_private *) ndev->priv, oid, 0, &u); + return mgt_set_request(netdev_priv(ndev), oid, 0, &u); } static int @@ -1775,7 +1775,7 @@ prism54_set_raw(struct net_device *ndev, struct iw_request_info *info, { u32 oid = dwrq->flags; - return mgt_set_request((islpci_private *) ndev->priv, oid, 0, extra); + return mgt_set_request(netdev_priv(ndev), oid, 0, extra); } void diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 3be624295a1..1d9dbf83001 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -314,7 +314,7 @@ static int ray_probe(struct pcmcia_device *p_dev) if (!dev) goto fail_alloc_dev; - local = dev->priv; + local = netdev_priv(dev); local->finder = p_dev; /* The io structure describes IO port mapping. None used here */ @@ -388,7 +388,7 @@ static void ray_detach(struct pcmcia_device *link) ray_release(link); - local = (ray_dev_t *)dev->priv; + local = netdev_priv(dev); del_timer(&local->timer); if (link->priv) { @@ -412,7 +412,7 @@ static int ray_config(struct pcmcia_device *link) win_req_t req; memreq_t mem; struct net_device *dev = (struct net_device *)link->priv; - ray_dev_t *local = (ray_dev_t *)dev->priv; + ray_dev_t *local = netdev_priv(dev); DEBUG(1, "ray_config(0x%p)\n", link); @@ -520,7 +520,7 @@ static int ray_init(struct net_device *dev) int i; UCHAR *p; struct ccs __iomem *pccs; - ray_dev_t *local = (ray_dev_t *)dev->priv; + ray_dev_t *local = netdev_priv(dev); struct pcmcia_device *link = local->finder; DEBUG(1, "ray_init(0x%p)\n", dev); if (!(pcmcia_dev_present(link))) { @@ -581,7 +581,7 @@ static int ray_init(struct net_device *dev) static int dl_startup_params(struct net_device *dev) { int ccsindex; - ray_dev_t *local = (ray_dev_t *)dev->priv; + ray_dev_t *local = netdev_priv(dev); struct ccs __iomem *pccs; struct pcmcia_device *link = local->finder; @@ -786,7 +786,7 @@ static void join_net(u_long data) static void ray_release(struct pcmcia_device *link) { struct net_device *dev = link->priv; - ray_dev_t *local = dev->priv; + ray_dev_t *local = netdev_priv(dev); int i; DEBUG(1, "ray_release(0x%p)\n", link); @@ -834,7 +834,7 @@ int ray_dev_init(struct net_device *dev) #ifdef RAY_IMMEDIATE_INIT int i; #endif /* RAY_IMMEDIATE_INIT */ - ray_dev_t *local = dev->priv; + ray_dev_t *local = netdev_priv(dev); struct pcmcia_device *link = local->finder; DEBUG(1,"ray_dev_init(dev=%p)\n",dev); @@ -868,7 +868,7 @@ int ray_dev_init(struct net_device *dev) /*===========================================================================*/ static int ray_dev_config(struct net_device *dev, struct ifmap *map) { - ray_dev_t *local = dev->priv; + ray_dev_t *local = netdev_priv(dev); struct pcmcia_device *link = local->finder; /* Dummy routine to satisfy device structure */ DEBUG(1,"ray_dev_config(dev=%p,ifmap=%p)\n",dev,map); @@ -882,7 +882,7 @@ static int ray_dev_config(struct net_device *dev, struct ifmap *map) /*===========================================================================*/ static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev) { - ray_dev_t *local = dev->priv; + ray_dev_t *local = netdev_priv(dev); struct pcmcia_device *link = local->finder; short length = skb->len; @@ -925,7 +925,7 @@ static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev) static int ray_hw_xmit(unsigned char* data, int len, struct net_device* dev, UCHAR msg_type) { - ray_dev_t *local = (ray_dev_t *)dev->priv; + ray_dev_t *local = netdev_priv(dev); struct ccs __iomem *pccs; int ccsindex; int offset; @@ -1099,7 +1099,7 @@ static int ray_set_freq(struct net_device *dev, struct iw_freq *fwrq, char *extra) { - ray_dev_t *local = (ray_dev_t *)dev->priv; + ray_dev_t *local = netdev_priv(dev); int err = -EINPROGRESS; /* Call commit handler */ /* Reject if card is already initialised */ @@ -1124,7 +1124,7 @@ static int ray_get_freq(struct net_device *dev, struct iw_freq *fwrq, char *extra) { - ray_dev_t *local = (ray_dev_t *)dev->priv; + ray_dev_t *local = netdev_priv(dev); fwrq->m = local->sparm.b5.a_hop_pattern; fwrq->e = 0; @@ -1140,7 +1140,7 @@ static int ray_set_essid(struct net_device *dev, struct iw_point *dwrq, char *extra) { - ray_dev_t *local = (ray_dev_t *)dev->priv; + ray_dev_t *local = netdev_priv(dev); /* Reject if card is already initialised */ if(local->card_status != CARD_AWAITING_PARAM) @@ -1173,7 +1173,7 @@ static int ray_get_essid(struct net_device *dev, struct iw_point *dwrq, char *extra) { - ray_dev_t *local = (ray_dev_t *)dev->priv; + ray_dev_t *local = netdev_priv(dev); /* Get the essid that was set */ memcpy(extra, local->sparm.b5.a_current_ess_id, IW_ESSID_MAX_SIZE); @@ -1194,7 +1194,7 @@ static int ray_get_wap(struct net_device *dev, struct sockaddr *awrq, char *extra) { - ray_dev_t *local = (ray_dev_t *)dev->priv; + ray_dev_t *local = netdev_priv(dev); memcpy(awrq->sa_data, local->bss_id, ETH_ALEN); awrq->sa_family = ARPHRD_ETHER; @@ -1211,7 +1211,7 @@ static int ray_set_rate(struct net_device *dev, struct iw_param *vwrq, char *extra) { - ray_dev_t *local = (ray_dev_t *)dev->priv; + ray_dev_t *local = netdev_priv(dev); /* Reject if card is already initialised */ if(local->card_status != CARD_AWAITING_PARAM) @@ -1240,7 +1240,7 @@ static int ray_get_rate(struct net_device *dev, struct iw_param *vwrq, char *extra) { - ray_dev_t *local = (ray_dev_t *)dev->priv; + ray_dev_t *local = netdev_priv(dev); if(local->net_default_tx_rate == 3) vwrq->value = 2000000; /* Hum... */ @@ -1260,7 +1260,7 @@ static int ray_set_rts(struct net_device *dev, struct iw_param *vwrq, char *extra) { - ray_dev_t *local = (ray_dev_t *)dev->priv; + ray_dev_t *local = netdev_priv(dev); int rthr = vwrq->value; /* Reject if card is already initialised */ @@ -1290,7 +1290,7 @@ static int ray_get_rts(struct net_device *dev, struct iw_param *vwrq, char *extra) { - ray_dev_t *local = (ray_dev_t *)dev->priv; + ray_dev_t *local = netdev_priv(dev); vwrq->value = (local->sparm.b5.a_rts_threshold[0] << 8) + local->sparm.b5.a_rts_threshold[1]; @@ -1309,7 +1309,7 @@ static int ray_set_frag(struct net_device *dev, struct iw_param *vwrq, char *extra) { - ray_dev_t *local = (ray_dev_t *)dev->priv; + ray_dev_t *local = netdev_priv(dev); int fthr = vwrq->value; /* Reject if card is already initialised */ @@ -1338,7 +1338,7 @@ static int ray_get_frag(struct net_device *dev, struct iw_param *vwrq, char *extra) { - ray_dev_t *local = (ray_dev_t *)dev->priv; + ray_dev_t *local = netdev_priv(dev); vwrq->value = (local->sparm.b5.a_frag_threshold[0] << 8) + local->sparm.b5.a_frag_threshold[1]; @@ -1357,7 +1357,7 @@ static int ray_set_mode(struct net_device *dev, __u32 *uwrq, char *extra) { - ray_dev_t *local = (ray_dev_t *)dev->priv; + ray_dev_t *local = netdev_priv(dev); int err = -EINPROGRESS; /* Call commit handler */ char card_mode = 1; @@ -1389,7 +1389,7 @@ static int ray_get_mode(struct net_device *dev, __u32 *uwrq, char *extra) { - ray_dev_t *local = (ray_dev_t *)dev->priv; + ray_dev_t *local = netdev_priv(dev); if(local->sparm.b5.a_network_type) *uwrq = IW_MODE_INFRA; @@ -1492,7 +1492,7 @@ static int ray_commit(struct net_device *dev, */ static iw_stats * ray_get_wireless_stats(struct net_device * dev) { - ray_dev_t * local = (ray_dev_t *) dev->priv; + ray_dev_t * local = netdev_priv(dev); struct pcmcia_device *link = local->finder; struct status __iomem *p = local->sram + STATUS_BASE; @@ -1580,7 +1580,7 @@ static const struct iw_handler_def ray_handler_def = /*===========================================================================*/ static int ray_open(struct net_device *dev) { - ray_dev_t *local = (ray_dev_t *)dev->priv; + ray_dev_t *local = netdev_priv(dev); struct pcmcia_device *link; link = local->finder; @@ -1614,7 +1614,7 @@ static int ray_open(struct net_device *dev) /*===========================================================================*/ static int ray_dev_close(struct net_device *dev) { - ray_dev_t *local = (ray_dev_t *)dev->priv; + ray_dev_t *local = netdev_priv(dev); struct pcmcia_device *link; link = local->finder; @@ -1773,7 +1773,7 @@ static int parse_addr(char *in_str, UCHAR *out) /*===========================================================================*/ static struct net_device_stats *ray_get_stats(struct net_device *dev) { - ray_dev_t *local = (ray_dev_t *)dev->priv; + ray_dev_t *local = netdev_priv(dev); struct pcmcia_device *link = local->finder; struct status __iomem *p = local->sram + STATUS_BASE; if (!(pcmcia_dev_present(link))) { @@ -1803,7 +1803,7 @@ static struct net_device_stats *ray_get_stats(struct net_device *dev) /*===========================================================================*/ static void ray_update_parm(struct net_device *dev, UCHAR objid, UCHAR *value, int len) { - ray_dev_t *local = (ray_dev_t *)dev->priv; + ray_dev_t *local = netdev_priv(dev); struct pcmcia_device *link = local->finder; int ccsindex; int i; @@ -1840,7 +1840,7 @@ static void ray_update_multi_list(struct net_device *dev, int all) int ccsindex; struct ccs __iomem *pccs; int i = 0; - ray_dev_t *local = (ray_dev_t *)dev->priv; + ray_dev_t *local = netdev_priv(dev); struct pcmcia_device *link = local->finder; void __iomem *p = local->sram + HOST_TO_ECF_BASE; @@ -1884,7 +1884,7 @@ static void ray_update_multi_list(struct net_device *dev, int all) /*===========================================================================*/ static void set_multicast_list(struct net_device *dev) { - ray_dev_t *local = (ray_dev_t *)dev->priv; + ray_dev_t *local = netdev_priv(dev); UCHAR promisc; DEBUG(2,"ray_cs set_multicast_list(%p)\n",dev); @@ -1935,7 +1935,7 @@ static irqreturn_t ray_interrupt(int irq, void *dev_id) DEBUG(4,"ray_cs: interrupt for *dev=%p\n",dev); - local = (ray_dev_t *)dev->priv; + local = netdev_priv(dev); link = (struct pcmcia_device *)local->finder; if (!pcmcia_dev_present(link)) { DEBUG(2,"ray_cs interrupt from device not present or suspended.\n"); @@ -2165,7 +2165,7 @@ static void rx_data(struct net_device *dev, struct rcs __iomem *prcs, unsigned i { struct sk_buff *skb = NULL; struct rcs __iomem *prcslink = prcs; - ray_dev_t *local = dev->priv; + ray_dev_t *local = netdev_priv(dev); UCHAR *rx_ptr; int total_len; int tmp; @@ -2618,7 +2618,7 @@ static int ray_cs_proc_read(char *buf, char **start, off_t offset, int len) dev = (struct net_device *)link->priv; if (!dev) return 0; - local = (ray_dev_t *)dev->priv; + local = netdev_priv(dev); if (!local) return 0; diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c index 904e548e679..c49d5a1f94a 100644 --- a/drivers/net/wireless/strip.c +++ b/drivers/net/wireless/strip.c @@ -2572,7 +2572,7 @@ static struct strip *strip_alloc(void) return NULL; /* If no more memory, return */ - strip_info = dev->priv; + strip_info = netdev_priv(dev); strip_info->dev = dev; strip_info->magic = STRIP_MAGIC; diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index c8b5c227193..72f3d97e7cb 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -859,7 +859,7 @@ static int wl3501_esbq_confirm(struct wl3501_card *this) static void wl3501_online(struct net_device *dev) { - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); printk(KERN_INFO "%s: Wireless LAN online. BSSID: " "%02X %02X %02X %02X %02X %02X\n", dev->name, @@ -907,7 +907,7 @@ static int wl3501_mgmt_association(struct wl3501_card *this) static void wl3501_mgmt_join_confirm(struct net_device *dev, u16 addr) { - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); struct wl3501_join_confirm sig; dprintk(3, "entry"); @@ -1046,7 +1046,7 @@ static inline void wl3501_start_confirm_interrupt(struct net_device *dev, static inline void wl3501_assoc_confirm_interrupt(struct net_device *dev, u16 addr) { - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); struct wl3501_assoc_confirm sig; dprintk(3, "entry"); @@ -1075,7 +1075,7 @@ static inline void wl3501_rx_interrupt(struct net_device *dev) int morepkts; u16 addr; u8 sig_id; - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); dprintk(3, "entry"); loop: @@ -1257,7 +1257,7 @@ fail: static int wl3501_close(struct net_device *dev) { - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); int rc = -ENODEV; unsigned long flags; struct pcmcia_device *link; @@ -1289,7 +1289,7 @@ static int wl3501_close(struct net_device *dev) */ static int wl3501_reset(struct net_device *dev) { - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); int rc = -ENODEV; wl3501_block_interrupt(this); @@ -1318,7 +1318,7 @@ out: static void wl3501_tx_timeout(struct net_device *dev) { - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); struct net_device_stats *stats = &this->stats; unsigned long flags; int rc; @@ -1344,7 +1344,7 @@ static void wl3501_tx_timeout(struct net_device *dev) static int wl3501_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { int enabled, rc; - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); unsigned long flags; spin_lock_irqsave(&this->lock, flags); @@ -1371,7 +1371,7 @@ static int wl3501_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) static int wl3501_open(struct net_device *dev) { int rc = -ENODEV; - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); unsigned long flags; struct pcmcia_device *link; link = this->p_dev; @@ -1410,14 +1410,14 @@ fail: static struct net_device_stats *wl3501_get_stats(struct net_device *dev) { - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); return &this->stats; } static struct iw_statistics *wl3501_get_wireless_stats(struct net_device *dev) { - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); struct iw_statistics *wstats = &this->wstats; u32 value; /* size checked: it is u32 */ @@ -1497,7 +1497,7 @@ static int wl3501_get_name(struct net_device *dev, struct iw_request_info *info, static int wl3501_set_freq(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); int channel = wrqu->freq.m; int rc = -EINVAL; @@ -1511,7 +1511,7 @@ static int wl3501_set_freq(struct net_device *dev, struct iw_request_info *info, static int wl3501_get_freq(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); wrqu->freq.m = wl3501_chan2freq[this->chan - 1] * 100000; wrqu->freq.e = 1; @@ -1526,7 +1526,7 @@ static int wl3501_set_mode(struct net_device *dev, struct iw_request_info *info, if (wrqu->mode == IW_MODE_INFRA || wrqu->mode == IW_MODE_ADHOC || wrqu->mode == IW_MODE_AUTO) { - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); this->net_type = wrqu->mode; rc = wl3501_reset(dev); @@ -1537,7 +1537,7 @@ static int wl3501_set_mode(struct net_device *dev, struct iw_request_info *info, static int wl3501_get_mode(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); wrqu->mode = this->net_type; return 0; @@ -1546,7 +1546,7 @@ static int wl3501_get_mode(struct net_device *dev, struct iw_request_info *info, static int wl3501_get_sens(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); wrqu->sens.value = this->rssi; wrqu->sens.disabled = !wrqu->sens.value; @@ -1577,7 +1577,7 @@ static int wl3501_get_range(struct net_device *dev, static int wl3501_set_wap(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); static const u8 bcast[ETH_ALEN] = { 255, 255, 255, 255, 255, 255 }; int rc = -EINVAL; @@ -1597,7 +1597,7 @@ out: static int wl3501_get_wap(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); wrqu->ap_addr.sa_family = ARPHRD_ETHER; memcpy(wrqu->ap_addr.sa_data, this->bssid, ETH_ALEN); @@ -1616,7 +1616,7 @@ static int wl3501_set_scan(struct net_device *dev, struct iw_request_info *info, static int wl3501_get_scan(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); int i; char *current_ev = extra; struct iw_event iwe; @@ -1666,7 +1666,7 @@ static int wl3501_set_essid(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); if (wrqu->data.flags) { iw_set_mgmt_info_element(IW_MGMT_INFO_ELEMENT_SSID, @@ -1683,7 +1683,7 @@ static int wl3501_get_essid(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); unsigned long flags; spin_lock_irqsave(&this->lock, flags); @@ -1697,7 +1697,7 @@ static int wl3501_get_essid(struct net_device *dev, static int wl3501_set_nick(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); if (wrqu->data.length > sizeof(this->nick)) return -E2BIG; @@ -1708,7 +1708,7 @@ static int wl3501_set_nick(struct net_device *dev, struct iw_request_info *info, static int wl3501_get_nick(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); strlcpy(extra, this->nick, 32); wrqu->data.length = strlen(extra); @@ -1733,7 +1733,7 @@ static int wl3501_get_rts_threshold(struct net_device *dev, union iwreq_data *wrqu, char *extra) { u16 threshold; /* size checked: it is u16 */ - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); int rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_RTS_THRESHOLD, &threshold, sizeof(threshold)); if (!rc) { @@ -1749,7 +1749,7 @@ static int wl3501_get_frag_threshold(struct net_device *dev, union iwreq_data *wrqu, char *extra) { u16 threshold; /* size checked: it is u16 */ - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); int rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_FRAG_THRESHOLD, &threshold, sizeof(threshold)); if (!rc) { @@ -1765,7 +1765,7 @@ static int wl3501_get_txpow(struct net_device *dev, union iwreq_data *wrqu, char *extra) { u16 txpow; - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); int rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_CURRENT_TX_PWR_LEVEL, &txpow, sizeof(txpow)); @@ -1787,7 +1787,7 @@ static int wl3501_get_retry(struct net_device *dev, union iwreq_data *wrqu, char *extra) { u8 retry; /* size checked: it is u8 */ - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); int rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_LONG_RETRY_LIMIT, &retry, sizeof(retry)); @@ -1814,7 +1814,7 @@ static int wl3501_get_encode(struct net_device *dev, union iwreq_data *wrqu, char *extra) { u8 implemented, restricted, keys[100], len_keys, tocopy; - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); int rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_PRIV_OPT_IMPLEMENTED, &implemented, sizeof(implemented)); @@ -1852,7 +1852,7 @@ static int wl3501_get_power(struct net_device *dev, union iwreq_data *wrqu, char *extra) { u8 pwr_state; - struct wl3501_card *this = dev->priv; + struct wl3501_card *this = netdev_priv(dev); int rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_CURRENT_PWR_STATE, &pwr_state, sizeof(pwr_state)); @@ -1937,7 +1937,7 @@ static int wl3501_probe(struct pcmcia_device *p_dev) dev->tx_timeout = wl3501_tx_timeout; dev->watchdog_timeo = 5 * HZ; dev->get_stats = wl3501_get_stats; - this = dev->priv; + this = netdev_priv(dev); this->wireless_data.spy_data = &this->spy_data; this->p_dev = p_dev; dev->wireless_data = &this->wireless_data; @@ -2006,7 +2006,7 @@ static int wl3501_config(struct pcmcia_device *link) SET_MODULE_OWNER(dev); - this = dev->priv; + this = netdev_priv(dev); /* * At this point, the dev_node_t structure(s) should be initialized and * arranged in a linked list at link->dev_node. @@ -2079,7 +2079,7 @@ static int wl3501_suspend(struct pcmcia_device *link) { struct net_device *dev = link->priv; - wl3501_pwr_mgmt(dev->priv, WL3501_SUSPEND); + wl3501_pwr_mgmt(netdev_priv(dev), WL3501_SUSPEND); if (link->open) netif_device_detach(dev); @@ -2090,7 +2090,7 @@ static int wl3501_resume(struct pcmcia_device *link) { struct net_device *dev = link->priv; - wl3501_pwr_mgmt(dev->priv, WL3501_RESUME); + wl3501_pwr_mgmt(netdev_priv(dev), WL3501_RESUME); if (link->open) { wl3501_reset(dev); netif_device_attach(dev); -- cgit v1.2.3-70-g09d2 From 0c9ca690e0117e1bf415d5f3e392e27c0c472c68 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 10:43:44 -0400 Subject: [PATCH] libertas: kill ieeetypes_capinfo bitfield, use ieee80211.h types Use standard BSS capability field constants from ieee80211.h. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/debugfs.c | 12 ++-- drivers/net/wireless/libertas/dev.h | 2 +- drivers/net/wireless/libertas/fw.c | 6 +- drivers/net/wireless/libertas/hostcmd.h | 20 ++---- drivers/net/wireless/libertas/join.c | 111 ++++++++++++++------------------ drivers/net/wireless/libertas/scan.c | 58 +++++++---------- drivers/net/wireless/libertas/scan.h | 4 +- drivers/net/wireless/libertas/types.h | 42 +----------- 8 files changed, 91 insertions(+), 164 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c index 715cbdaa1d4..e5cbfa8d6e3 100644 --- a/drivers/net/wireless/libertas/debugfs.c +++ b/drivers/net/wireless/libertas/debugfs.c @@ -70,18 +70,18 @@ static ssize_t libertas_getscantable(struct file *file, char __user *userbuf, mutex_lock(&priv->adapter->lock); list_for_each_entry (iter_bss, &priv->adapter->network_list, list) { - u16 cap; + u16 ibss = (iter_bss->capability & WLAN_CAPABILITY_IBSS); + u16 privacy = (iter_bss->capability & WLAN_CAPABILITY_PRIVACY); + u16 spectrum_mgmt = (iter_bss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT); - memcpy(&cap, &iter_bss->cap, sizeof(cap)); pos += snprintf(buf+pos, len-pos, "%02u| %03d | %03ld | " MAC_FMT " |", numscansdone, iter_bss->channel, iter_bss->rssi, MAC_ARG(iter_bss->bssid)); - pos += snprintf(buf+pos, len-pos, " %04x-", cap); + pos += snprintf(buf+pos, len-pos, " %04x-", iter_bss->capability); pos += snprintf(buf+pos, len-pos, "%c%c%c |", - iter_bss->cap.ibss ? 'A' : 'I', - iter_bss->cap.privacy ? 'P' : ' ', - iter_bss->cap.spectrummgmt ? 'S' : ' '); + ibss ? 'A' : 'I', privacy ? 'P' : ' ', + spectrum_mgmt ? 'S' : ' '); pos += snprintf(buf+pos, len-pos, " %08llx |", iter_bss->networktsf); pos += snprintf(buf+pos, len-pos, " %d |", SCAN_RSSI(iter_bss->rssi)); pos += snprintf(buf+pos, len-pos, " %s\n", diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 785192b884b..675c65dbc07 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -275,7 +275,7 @@ struct _wlan_adapter { u8 adhoccreate; /** capability Info used in Association, start, join */ - struct ieeetypes_capinfo capinfo; + u16 capability; /** MAC address information */ u8 current_addr[ETH_ALEN]; diff --git a/drivers/net/wireless/libertas/fw.c b/drivers/net/wireless/libertas/fw.c index 2dc84ff7a54..6c2b3c25b82 100644 --- a/drivers/net/wireless/libertas/fw.c +++ b/drivers/net/wireless/libertas/fw.c @@ -217,10 +217,8 @@ static void wlan_init_adapter(wlan_private * priv) adapter->is_datarate_auto = 1; adapter->beaconperiod = MRVDRV_BEACON_INTERVAL; - // set default value of capinfo. -#define SHORT_PREAMBLE_ALLOWED 1 - memset(&adapter->capinfo, 0, sizeof(adapter->capinfo)); - adapter->capinfo.shortpreamble = SHORT_PREAMBLE_ALLOWED; + // set default capabilities + adapter->capability = WLAN_CAPABILITY_SHORT_PREAMBLE; adapter->psmode = wlan802_11powermodecam; adapter->multipledtim = MRVDRV_DEFAULT_MULTIPLE_DTIM; diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index 09b898f6719..1322552fa6c 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -108,12 +108,6 @@ struct wlan_offset_value { u32 value; }; -struct WLAN_802_11_FIXED_IEs { - __le64 timestamp; - __le16 beaconinterval; - u16 capabilities; /* Actually struct ieeetypes_capinfo */ -}; - struct WLAN_802_11_VARIABLE_IEs { u8 elementid; u8 length; @@ -237,7 +231,7 @@ struct cmd_ds_802_11_deauthenticate { struct cmd_ds_802_11_associate { u8 peerstaaddr[6]; - struct ieeetypes_capinfo capinfo; + __le16 capability; __le16 listeninterval; __le16 bcnperiod; u8 dtimperiod; @@ -469,22 +463,22 @@ struct cmd_ds_802_11_ad_hoc_start { union IEEEtypes_ssparamset ssparamset; union ieeetypes_phyparamset phyparamset; __le16 probedelay; - struct ieeetypes_capinfo cap; + __le16 capability; u8 datarate[G_SUPPORTED_RATES]; u8 tlv_memory_size_pad[100]; } __attribute__ ((packed)); struct adhoc_bssdesc { - u8 BSSID[6]; - u8 SSID[32]; - u8 bsstype; + u8 bssid[6]; + u8 ssid[32]; + u8 type; __le16 beaconperiod; u8 dtimperiod; __le64 timestamp; __le64 localtime; union ieeetypes_phyparamset phyparamset; union IEEEtypes_ssparamset ssparamset; - struct ieeetypes_capinfo cap; + __le16 capability; u8 datarates[G_SUPPORTED_RATES]; /* DO NOT ADD ANY FIELDS TO THIS STRUCTURE. It is used below in the @@ -494,7 +488,7 @@ struct adhoc_bssdesc { } __attribute__ ((packed)); struct cmd_ds_802_11_ad_hoc_join { - struct adhoc_bssdesc bssdescriptor; + struct adhoc_bssdesc bss; __le16 failtimeout; __le16 probedelay; diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c index 78ac3064a0b..2db7fbfcaeb 100644 --- a/drivers/net/wireless/libertas/join.c +++ b/drivers/net/wireless/libertas/join.c @@ -17,8 +17,6 @@ #include "dev.h" #include "assoc.h" -#define AD_HOC_CAP_PRIVACY_ON 1 - /** * @brief This function finds out the common rates between rate1 and rate2. * @@ -121,7 +119,8 @@ int wlan_associate(wlan_private * priv, struct assoc_request * assoc_req) goto done; /* set preamble to firmware */ - if (adapter->capinfo.shortpreamble && assoc_req->bss.cap.shortpreamble) + if ( (adapter->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) + && (assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) adapter->preamble = cmd_type_short_preamble; else adapter->preamble = cmd_type_long_preamble; @@ -150,12 +149,12 @@ int libertas_start_adhoc_network(wlan_private * priv, struct assoc_request * ass adapter->adhoccreate = 1; - if (!adapter->capinfo.shortpreamble) { - lbs_deb_join("AdhocStart: Long preamble\n"); - adapter->preamble = cmd_type_long_preamble; - } else { + if (adapter->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) { lbs_deb_join("AdhocStart: Short preamble\n"); adapter->preamble = cmd_type_short_preamble; + } else { + lbs_deb_join("AdhocStart: Long preamble\n"); + adapter->preamble = cmd_type_long_preamble; } libertas_set_radio_control(priv); @@ -205,9 +204,10 @@ int libertas_join_adhoc_network(wlan_private * priv, struct assoc_request * asso return -1; } - /*Use shortpreamble only when both creator and card supports + /* Use shortpreamble only when both creator and card supports short preamble */ - if (!bss->cap.shortpreamble || !adapter->capinfo.shortpreamble) { + if ( !(bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) + || !(adapter->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) { lbs_deb_join("AdhocJoin: Long preamble\n"); adapter->preamble = cmd_type_long_preamble; } else { @@ -357,7 +357,7 @@ int libertas_cmd_80211_associate(wlan_private * priv, /* set the listen interval */ passo->listeninterval = cpu_to_le16(adapter->listeninterval); - pos += sizeof(passo->capinfo); + pos += sizeof(passo->capability); pos += sizeof(passo->listeninterval); pos += sizeof(passo->bcnperiod); pos += sizeof(passo->dtimperiod); @@ -427,12 +427,6 @@ int libertas_cmd_80211_associate(wlan_private * priv, lbs_deb_join("ASSOC_CMD: rates->header.len = %d\n", cpu_to_le16(rates->header.len)); - /* set IBSS field */ - if (bss->mode == IW_MODE_INFRA) { -#define CAPINFO_ESS_MODE 1 - passo->capinfo.ess = CAPINFO_ESS_MODE; - } - if (libertas_parse_dnld_countryinfo_11d(priv, bss)) { ret = -1; goto done; @@ -440,12 +434,13 @@ int libertas_cmd_80211_associate(wlan_private * priv, cmd->size = cpu_to_le16((u16) (pos - (u8 *) passo) + S_DS_GEN); - /* set the capability info at last */ - memcpy(&tmpcap, &bss->cap, sizeof(passo->capinfo)); - tmpcap &= CAPINFO_MASK; - lbs_deb_join("ASSOC_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n", + /* set the capability info */ + tmpcap = (bss->capability & CAPINFO_MASK); + if (bss->mode == IW_MODE_INFRA) + tmpcap |= WLAN_CAPABILITY_ESS; + passo->capability = cpu_to_le16(tmpcap); + lbs_deb_join("ASSOC_CMD: capability=%4X CAPINFO_MASK=%4X\n", tmpcap, CAPINFO_MASK); - memcpy(&passo->capinfo, &tmpcap, sizeof(passo->capinfo)); done: lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); @@ -461,6 +456,7 @@ int libertas_cmd_80211_ad_hoc_start(wlan_private * priv, int cmdappendsize = 0; int i; struct assoc_request * assoc_req = pdata_buf; + u16 tmpcap = 0; lbs_deb_enter(LBS_DEB_JOIN); @@ -518,19 +514,17 @@ int libertas_cmd_80211_ad_hoc_start(wlan_private * priv, adhs->ssparamset.ibssparamset.atimwindow = cpu_to_le16(adapter->atimwindow); /* set capability info */ - adhs->cap.ess = 0; - adhs->cap.ibss = 1; - - /* probedelay */ - adhs->probedelay = cpu_to_le16(cmd_scan_probe_delay_time); - - /* set up privacy in adapter->scantable[i] */ + tmpcap = WLAN_CAPABILITY_IBSS; if (assoc_req->secinfo.wep_enabled) { lbs_deb_join("ADHOC_S_CMD: WEP enabled, setting privacy on\n"); - adhs->cap.privacy = AD_HOC_CAP_PRIVACY_ON; + tmpcap |= WLAN_CAPABILITY_PRIVACY; } else { lbs_deb_join("ADHOC_S_CMD: WEP disabled, setting privacy off\n"); } + adhs->capability = cpu_to_le16(tmpcap); + + /* probedelay */ + adhs->probedelay = cpu_to_le16(cmd_scan_probe_delay_time); memset(adhs->datarate, 0, sizeof(adhs->datarate)); @@ -585,67 +579,58 @@ int libertas_cmd_80211_ad_hoc_join(wlan_private * priv, struct cmd_ds_command *cmd, void *pdata_buf) { wlan_adapter *adapter = priv->adapter; - struct cmd_ds_802_11_ad_hoc_join *padhocjoin = &cmd->params.adj; + struct cmd_ds_802_11_ad_hoc_join *join_cmd = &cmd->params.adj; struct assoc_request * assoc_req = pdata_buf; struct bss_descriptor *bss = &assoc_req->bss; int cmdappendsize = 0; int ret = 0; u8 *card_rates; int card_rates_size; - u16 tmpcap; int i; lbs_deb_enter(LBS_DEB_JOIN); cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_join); - padhocjoin->bssdescriptor.bsstype = cmd_bss_type_ibss; - - padhocjoin->bssdescriptor.beaconperiod = cpu_to_le16(bss->beaconperiod); - - memcpy(&padhocjoin->bssdescriptor.BSSID, &bss->bssid, ETH_ALEN); - memcpy(&padhocjoin->bssdescriptor.SSID, &bss->ssid, bss->ssid_len); + join_cmd->bss.type = cmd_bss_type_ibss; + join_cmd->bss.beaconperiod = cpu_to_le16(bss->beaconperiod); - memcpy(&padhocjoin->bssdescriptor.phyparamset, - &bss->phyparamset, sizeof(union ieeetypes_phyparamset)); + memcpy(&join_cmd->bss.bssid, &bss->bssid, ETH_ALEN); + memcpy(&join_cmd->bss.ssid, &bss->ssid, bss->ssid_len); - memcpy(&padhocjoin->bssdescriptor.ssparamset, - &bss->ssparamset, sizeof(union IEEEtypes_ssparamset)); + memcpy(&join_cmd->bss.phyparamset, &bss->phyparamset, + sizeof(union ieeetypes_phyparamset)); - memcpy(&tmpcap, &bss->cap, sizeof(struct ieeetypes_capinfo)); - tmpcap &= CAPINFO_MASK; + memcpy(&join_cmd->bss.ssparamset, &bss->ssparamset, + sizeof(union IEEEtypes_ssparamset)); + join_cmd->bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK); lbs_deb_join("ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n", - tmpcap, CAPINFO_MASK); - memcpy(&padhocjoin->bssdescriptor.cap, &tmpcap, - sizeof(struct ieeetypes_capinfo)); + bss->capability, CAPINFO_MASK); /* information on BSSID descriptor passed to FW */ lbs_deb_join( "ADHOC_J_CMD: BSSID = " MAC_FMT ", SSID = '%s'\n", - MAC_ARG(padhocjoin->bssdescriptor.BSSID), - padhocjoin->bssdescriptor.SSID); + MAC_ARG(join_cmd->bss.bssid), join_cmd->bss.ssid); /* failtimeout */ - padhocjoin->failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT); + join_cmd->failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT); /* probedelay */ - padhocjoin->probedelay = cpu_to_le16(cmd_scan_probe_delay_time); + join_cmd->probedelay = cpu_to_le16(cmd_scan_probe_delay_time); /* Copy Data rates from the rates recorded in scan response */ - memset(padhocjoin->bssdescriptor.datarates, 0, - sizeof(padhocjoin->bssdescriptor.datarates)); - memcpy(padhocjoin->bssdescriptor.datarates, bss->datarates, - min(sizeof(padhocjoin->bssdescriptor.datarates), - sizeof(bss->datarates))); + memset(join_cmd->bss.datarates, 0, sizeof(join_cmd->bss.datarates)); + memcpy(join_cmd->bss.datarates, bss->datarates, + min(sizeof(join_cmd->bss.datarates), sizeof(bss->datarates))); card_rates = libertas_supported_rates; card_rates_size = sizeof(libertas_supported_rates); adapter->curbssparams.channel = bss->channel; - if (get_common_rates(adapter, padhocjoin->bssdescriptor.datarates, - sizeof(padhocjoin->bssdescriptor.datarates), + if (get_common_rates(adapter, join_cmd->bss.datarates, + sizeof(join_cmd->bss.datarates), card_rates, card_rates_size)) { lbs_deb_join("ADHOC_J_CMD: get_common_rates returns error.\n"); ret = -1; @@ -653,8 +638,8 @@ int libertas_cmd_80211_ad_hoc_join(wlan_private * priv, } /* Find the last non zero */ - for (i = 0; i < sizeof(padhocjoin->bssdescriptor.datarates) - && padhocjoin->bssdescriptor.datarates[i]; i++) ; + for (i = 0; i < sizeof(join_cmd->bss.datarates) + && join_cmd->bss.datarates[i]; i++) ; adapter->curbssparams.numofrates = i; @@ -662,14 +647,16 @@ int libertas_cmd_80211_ad_hoc_join(wlan_private * priv, * Copy the adhoc joining rates to Current BSS State structure */ memcpy(adapter->curbssparams.datarates, - padhocjoin->bssdescriptor.datarates, + join_cmd->bss.datarates, adapter->curbssparams.numofrates); - padhocjoin->bssdescriptor.ssparamset.ibssparamset.atimwindow = + join_cmd->bss.ssparamset.ibssparamset.atimwindow = cpu_to_le16(bss->atimwindow); if (assoc_req->secinfo.wep_enabled) { - padhocjoin->bssdescriptor.cap.privacy = AD_HOC_CAP_PRIVACY_ON; + u16 tmp = le16_to_cpu(join_cmd->bss.capability); + tmp |= WLAN_CAPABILITY_PRIVACY; + join_cmd->bss.capability = cpu_to_le16(tmp); } if (adapter->psmode == wlan802_11powermodemax_psp) { diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index c3043dcb541..8753f9344f3 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -76,7 +76,7 @@ static inline int match_bss_no_security(struct wlan_802_11_security * secinfo, && !secinfo->WPA2enabled && match_bss->wpa_ie[0] != WPA_IE && match_bss->rsn_ie[0] != WPA2_IE - && !match_bss->privacy) { + && !(match_bss->capability & WLAN_CAPABILITY_PRIVACY)) { return 1; } return 0; @@ -88,7 +88,7 @@ static inline int match_bss_static_wep(struct wlan_802_11_security * secinfo, if ( secinfo->wep_enabled && !secinfo->WPAenabled && !secinfo->WPA2enabled - && match_bss->privacy) { + && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) { return 1; } return 0; @@ -101,7 +101,8 @@ static inline int match_bss_wpa(struct wlan_802_11_security * secinfo, && secinfo->WPAenabled && (match_bss->wpa_ie[0] == WPA_IE) /* privacy bit may NOT be set in some APs like LinkSys WRT54G - && bss->privacy */ + && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) { + */ ) { return 1; } @@ -115,7 +116,8 @@ static inline int match_bss_wpa2(struct wlan_802_11_security * secinfo, && secinfo->WPA2enabled && (match_bss->rsn_ie[0] == WPA2_IE) /* privacy bit may NOT be set in some APs like LinkSys WRT54G - && bss->privacy */ + && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) { + */ ) { return 1; } @@ -130,7 +132,7 @@ static inline int match_bss_dynamic_wep(struct wlan_802_11_security * secinfo, && !secinfo->WPA2enabled && (match_bss->wpa_ie[0] != WPA_IE) && (match_bss->rsn_ie[0] != WPA2_IE) - && match_bss->privacy) { + && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) { return 1; } return 0; @@ -177,7 +179,7 @@ static int is_network_compatible(wlan_adapter * adapter, adapter->secinfo.wep_enabled ? "e" : "d", adapter->secinfo.WPAenabled ? "e" : "d", adapter->secinfo.WPA2enabled ? "e" : "d", - bss->privacy); + (bss->capability & WLAN_CAPABILITY_PRIVACY)); goto done; } else if ((matched = match_bss_wpa2(&adapter->secinfo, bss))) { lbs_deb_scan( @@ -187,15 +189,14 @@ static int is_network_compatible(wlan_adapter * adapter, adapter->secinfo.wep_enabled ? "e" : "d", adapter->secinfo.WPAenabled ? "e" : "d", adapter->secinfo.WPA2enabled ? "e" : "d", - bss->privacy); + (bss->capability & WLAN_CAPABILITY_PRIVACY)); goto done; } else if ((matched = match_bss_dynamic_wep(&adapter->secinfo, bss))) { lbs_deb_scan( "is_network_compatible() dynamic WEP: " "wpa_ie=%#x wpa2_ie=%#x privacy=%#x\n", - bss->wpa_ie[0], - bss->rsn_ie[0], - bss->privacy); + bss->wpa_ie[0], bss->rsn_ie[0], + (bss->capability & WLAN_CAPABILITY_PRIVACY)); goto done; } @@ -207,7 +208,7 @@ static int is_network_compatible(wlan_adapter * adapter, adapter->secinfo.wep_enabled ? "e" : "d", adapter->secinfo.WPAenabled ? "e" : "d", adapter->secinfo.WPA2enabled ? "e" : "d", - bss->privacy); + (bss->capability & WLAN_CAPABILITY_PRIVACY)); done: lbs_deb_leave(LBS_DEB_SCAN); @@ -904,8 +905,6 @@ static int libertas_process_bss(struct bss_descriptor * bss, struct ieeetypes_dsparamset *pDS; struct ieeetypes_cfparamset *pCF; struct ieeetypes_ibssparamset *pibss; - struct ieeetypes_capinfo *pcap; - struct WLAN_802_11_FIXED_IEs fixedie; u8 *pcurrentptr; u8 *pRate; u8 elemlen; @@ -974,24 +973,28 @@ static int libertas_process_bss(struct bss_descriptor * bss, bytesleftforcurrentbeacon -= 1; /* time stamp is 8 bytes long */ - fixedie.timestamp = bss->timestamp = le64_to_cpup((void *)pcurrentptr); + bss->timestamp = le64_to_cpup((void *)pcurrentptr); pcurrentptr += 8; bytesleftforcurrentbeacon -= 8; /* beacon interval is 2 bytes long */ - fixedie.beaconinterval = bss->beaconperiod = le16_to_cpup((void *)pcurrentptr); + bss->beaconperiod = le16_to_cpup((void *)pcurrentptr); pcurrentptr += 2; bytesleftforcurrentbeacon -= 2; /* capability information is 2 bytes long */ - memcpy(&fixedie.capabilities, pcurrentptr, 2); - lbs_deb_scan("process_bss: fixedie.capabilities=0x%X\n", - fixedie.capabilities); - pcap = (struct ieeetypes_capinfo *) & fixedie.capabilities; - memcpy(&bss->cap, pcap, sizeof(struct ieeetypes_capinfo)); + bss->capability = le16_to_cpup((void *)pcurrentptr); + lbs_deb_scan("process_bss: capabilities = 0x%4X\n", bss->capability); pcurrentptr += 2; bytesleftforcurrentbeacon -= 2; + if (bss->capability & WLAN_CAPABILITY_PRIVACY) + lbs_deb_scan("process_bss: AP WEP enabled\n"); + if (bss->capability & WLAN_CAPABILITY_IBSS) + bss->mode = IW_MODE_ADHOC; + else + bss->mode = IW_MODE_INFRA; + /* rest of the current buffer are IE's */ lbs_deb_scan("process_bss: IE length for this AP = %d\n", bytesleftforcurrentbeacon); @@ -999,19 +1002,6 @@ static int libertas_process_bss(struct bss_descriptor * bss, lbs_dbg_hex("process_bss: IE info", (u8 *) pcurrentptr, bytesleftforcurrentbeacon); - if (pcap->privacy) { - lbs_deb_scan("process_bss: AP WEP enabled\n"); - bss->privacy = wlan802_11privfilter8021xWEP; - } else { - bss->privacy = wlan802_11privfilteracceptall; - } - - if (pcap->ibss == 1) { - bss->mode = IW_MODE_ADHOC; - } else { - bss->mode = IW_MODE_INFRA; - } - /* process variable IE */ while (bytesleftforcurrentbeacon >= 2) { elemID = (enum ieeetypes_elementid) (*((u8 *) pcurrentptr)); @@ -1550,7 +1540,7 @@ static inline char *libertas_translate_scan(wlan_private *priv, /* Add encryption capability */ iwe.cmd = SIOCGIWENCODE; - if (bss->privacy) { + if (bss->capability & WLAN_CAPABILITY_PRIVACY) { iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; } else { iwe.u.data.flags = IW_ENCODE_DISABLED; diff --git a/drivers/net/wireless/libertas/scan.h b/drivers/net/wireless/libertas/scan.h index bd019e5ff1e..2a095733f19 100644 --- a/drivers/net/wireless/libertas/scan.h +++ b/drivers/net/wireless/libertas/scan.h @@ -140,8 +140,7 @@ struct bss_descriptor { u8 ssid[IW_ESSID_MAX_SIZE + 1]; u8 ssid_len; - /* WEP encryption requirement */ - u32 privacy; + u16 capability; /* receive signal strength in dBm */ long rssi; @@ -160,7 +159,6 @@ struct bss_descriptor { union ieeetypes_phyparamset phyparamset; union IEEEtypes_ssparamset ssparamset; - struct ieeetypes_capinfo cap; u8 datarates[WLAN_SUPPORTED_RATES]; u64 networktsf; //!< TSF timestamp from the current firmware TSF diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h index 028e2f3b53d..f4be1293cd1 100644 --- a/drivers/net/wireless/libertas/types.h +++ b/drivers/net/wireless/libertas/types.h @@ -30,47 +30,7 @@ enum ieeetypes_elementid { EXTRA_IE = 133, } __attribute__ ((packed)); -#ifdef __BIG_ENDIAN -#define CAPINFO_MASK (~(0xda00)) -#else #define CAPINFO_MASK (~(0x00da)) -#endif - -struct ieeetypes_capinfo { -#ifdef __BIG_ENDIAN_BITFIELD - u8 chanagility:1; - u8 pbcc:1; - u8 shortpreamble:1; - u8 privacy:1; - u8 cfpollrqst:1; - u8 cfpollable:1; - u8 ibss:1; - u8 ess:1; - u8 rsrvd1:2; - u8 dsssofdm:1; - u8 rsvrd2:1; - u8 apsd:1; - u8 shortslottime:1; - u8 rsrvd3:1; - u8 spectrummgmt:1; -#else - u8 ess:1; - u8 ibss:1; - u8 cfpollable:1; - u8 cfpollrqst:1; - u8 privacy:1; - u8 shortpreamble:1; - u8 pbcc:1; - u8 chanagility:1; - u8 spectrummgmt:1; - u8 rsrvd3:1; - u8 shortslottime:1; - u8 apsd:1; - u8 rsvrd2:1; - u8 dsssofdm:1; - u8 rsrvd1:2; -#endif -} __attribute__ ((packed)); struct ieeetypes_cfparamset { u8 elementid; @@ -114,7 +74,7 @@ union ieeetypes_phyparamset { } __attribute__ ((packed)); struct ieeetypes_assocrsp { - struct ieeetypes_capinfo capability; + __le16 capability; __le16 statuscode; __le16 aid; u8 iebuffer[1]; -- cgit v1.2.3-70-g09d2 From 1443b6530d8db779082dc9fabbd894e2b551b101 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 10:45:55 -0400 Subject: [PATCH] libertas: rename WLAN_802_11_KEY to enc_key and clean up usage It doesn't touch hardware and therefore doesn't need endian notations either. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/assoc.c | 8 ++++---- drivers/net/wireless/libertas/cmd.c | 7 +++---- drivers/net/wireless/libertas/cmdresp.c | 19 ++++++++++--------- drivers/net/wireless/libertas/defs.h | 3 --- drivers/net/wireless/libertas/dev.h | 12 ++++++------ drivers/net/wireless/libertas/fw.c | 2 +- drivers/net/wireless/libertas/hostcmd.h | 16 ++++++---------- drivers/net/wireless/libertas/wext.c | 14 +++++++------- 8 files changed, 37 insertions(+), 44 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index afd5617dd92..307ebcb94b1 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -307,7 +307,7 @@ static int assoc_helper_wep_keys(wlan_private *priv, /* Copy WEP keys into adapter wep key fields */ for (i = 0; i < 4; i++) { memcpy(&adapter->wep_keys[i], &assoc_req->wep_keys[i], - sizeof(struct WLAN_802_11_KEY)); + sizeof(struct enc_key)); } adapter->wep_tx_keyidx = assoc_req->wep_tx_keyidx; @@ -703,7 +703,7 @@ struct assoc_request * wlan_get_association_request(wlan_adapter *adapter) int i; for (i = 0; i < 4; i++) { memcpy(&assoc_req->wep_keys[i], &adapter->wep_keys[i], - sizeof(struct WLAN_802_11_KEY)); + sizeof(struct enc_key)); } } @@ -712,12 +712,12 @@ struct assoc_request * wlan_get_association_request(wlan_adapter *adapter) if (!test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) { memcpy(&assoc_req->wpa_mcast_key, &adapter->wpa_mcast_key, - sizeof(struct WLAN_802_11_KEY)); + sizeof(struct enc_key)); } if (!test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) { memcpy(&assoc_req->wpa_unicast_key, &adapter->wpa_unicast_key, - sizeof(struct WLAN_802_11_KEY)); + sizeof(struct enc_key)); } if (!test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) { diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 4a8f5dc7023..355a3960323 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -181,7 +181,7 @@ static int wlan_cmd_802_11_set_wep(wlan_private * priv, /* Copy key types and material to host command structure */ for (i = 0; i < 4; i++) { - struct WLAN_802_11_KEY * pkey = &assoc_req->wep_keys[i]; + struct enc_key * pkey = &assoc_req->wep_keys[i]; switch (pkey->len) { case KEY_LEN_WEP_40: @@ -249,10 +249,8 @@ static int wlan_cmd_802_11_enable_rsn(wlan_private * priv, static void set_one_wpa_key(struct MrvlIEtype_keyParamSet * pkeyparamset, - struct WLAN_802_11_KEY * pkey) + struct enc_key * pkey) { - pkeyparamset->keytypeid = cpu_to_le16(pkey->type); - if (pkey->flags & KEY_INFO_WPA_ENABLED) { pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_ENABLED); } @@ -264,6 +262,7 @@ static void set_one_wpa_key(struct MrvlIEtype_keyParamSet * pkeyparamset, } pkeyparamset->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL); + pkeyparamset->keytypeid = cpu_to_le16(pkey->type); pkeyparamset->keylen = cpu_to_le16(pkey->len); memcpy(pkeyparamset->key, pkey->key, pkey->len); pkeyparamset->length = cpu_to_le16( sizeof(pkeyparamset->keytypeid) diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 6ac0d4752fa..89bd43c2efa 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -321,11 +321,12 @@ static int wlan_ret_802_11_key_material(wlan_private * priv, while (buf_ptr < resp_end) { struct MrvlIEtype_keyParamSet * pkeyparamset = (struct MrvlIEtype_keyParamSet *) buf_ptr; - struct WLAN_802_11_KEY * pkey; - u16 key_info = le16_to_cpu(pkeyparamset->keyinfo); + struct enc_key * pkey; u16 param_set_len = le16_to_cpu(pkeyparamset->length); - u8 * end; u16 key_len = le16_to_cpu(pkeyparamset->keylen); + u16 key_flags = le16_to_cpu(pkeyparamset->keyinfo); + u16 key_type = le16_to_cpu(pkeyparamset->keytypeid); + u8 * end; end = (u8 *) pkeyparamset + sizeof (pkeyparamset->type) + sizeof (pkeyparamset->length) @@ -334,20 +335,20 @@ static int wlan_ret_802_11_key_material(wlan_private * priv, if (end > resp_end) break; - if (key_info & KEY_INFO_WPA_UNICAST) + if (key_flags & KEY_INFO_WPA_UNICAST) pkey = &adapter->wpa_unicast_key; - else if (key_info & KEY_INFO_WPA_MCAST) + else if (key_flags & KEY_INFO_WPA_MCAST) pkey = &adapter->wpa_mcast_key; else break; /* Copy returned key into driver */ - memset(pkey, 0, sizeof(struct WLAN_802_11_KEY)); + memset(pkey, 0, sizeof(struct enc_key)); if (key_len > sizeof(pkey->key)) break; - pkey->type = le16_to_cpu(pkeyparamset->keytypeid); - pkey->flags = le16_to_cpu(pkeyparamset->keyinfo); - pkey->len = le16_to_cpu(pkeyparamset->keylen); + pkey->type = key_type; + pkey->flags = key_flags; + pkey->len = key_len; memcpy(pkey->key, pkeyparamset->key, pkey->len); buf_ptr = end + 1; diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h index 4dd43e59bda..de0756ee15a 100644 --- a/drivers/net/wireless/libertas/defs.h +++ b/drivers/net/wireless/libertas/defs.h @@ -218,9 +218,6 @@ static inline void lbs_dbg_hex(char *prompt, u8 * buf, int len) #define CMD_F_HOSTCMD (1 << 0) #define FW_CAPINFO_WPA (1 << 0) -/** WPA key LENGTH*/ -#define MRVL_MAX_KEY_WPA_KEY_LENGTH 32 - #define KEY_LEN_WPA_AES 16 #define KEY_LEN_WPA_TKIP 32 #define KEY_LEN_WEP_104 13 diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 675c65dbc07..184eee54857 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -188,12 +188,12 @@ struct assoc_request { u8 bssid[ETH_ALEN]; /** WEP keys */ - struct WLAN_802_11_KEY wep_keys[4]; + struct enc_key wep_keys[4]; u16 wep_tx_keyidx; /** WPA keys */ - struct WLAN_802_11_KEY wpa_mcast_key; - struct WLAN_802_11_KEY wpa_unicast_key; + struct enc_key wpa_mcast_key; + struct enc_key wpa_unicast_key; struct wlan_802_11_security secinfo; @@ -335,12 +335,12 @@ struct _wlan_adapter { struct wlan_802_11_security secinfo; /** WEP keys */ - struct WLAN_802_11_KEY wep_keys[4]; + struct enc_key wep_keys[4]; u16 wep_tx_keyidx; /** WPA keys */ - struct WLAN_802_11_KEY wpa_mcast_key; - struct WLAN_802_11_KEY wpa_unicast_key; + struct enc_key wpa_mcast_key; + struct enc_key wpa_unicast_key; /** WPA Information Elements*/ u8 wpa_ie[MAX_WPA_IE_LEN]; diff --git a/drivers/net/wireless/libertas/fw.c b/drivers/net/wireless/libertas/fw.c index 6c2b3c25b82..288e47c3355 100644 --- a/drivers/net/wireless/libertas/fw.c +++ b/drivers/net/wireless/libertas/fw.c @@ -181,7 +181,7 @@ static void wlan_init_adapter(wlan_private * priv) adapter->secinfo.wep_enabled = 0; for (i = 0; i < sizeof(adapter->wep_keys) / sizeof(adapter->wep_keys[0]); i++) - memset(&adapter->wep_keys[i], 0, sizeof(struct WLAN_802_11_KEY)); + memset(&adapter->wep_keys[i], 0, sizeof(struct enc_key)); adapter->wep_tx_keyidx = 0; adapter->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; adapter->mode = IW_MODE_INFRA; diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index 1322552fa6c..01a97d0fa98 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -83,16 +83,12 @@ struct cmd_ctrl_node { wait_queue_head_t cmdwait_q; }; -/* WLAN_802_11_KEY - * - * Generic structure to hold all key types. key type (WEP40, WEP104, TKIP, AES) - * is determined from the keylength field. - */ -struct WLAN_802_11_KEY { - __le32 len; - __le32 flags; /* KEY_INFO_* from wlan_defs.h */ - u8 key[MRVL_MAX_KEY_WPA_KEY_LENGTH]; - __le16 type; /* KEY_TYPE_* from wlan_defs.h */ +/* Generic structure to hold all key types. */ +struct enc_key { + u16 len; + u16 flags; /* KEY_INFO_* from wlan_defs.h */ + u16 type; /* KEY_TYPE_* from wlan_defs.h */ + u8 key[32]; }; struct IE_WPA { diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 2fcc3bf2108..f7df8c71a54 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -1325,7 +1325,7 @@ static int wlan_set_wep_key(struct assoc_request *assoc_req, int set_tx_key) { int ret = 0; - struct WLAN_802_11_KEY *pkey; + struct enc_key *pkey; lbs_deb_enter(LBS_DEB_WEXT); @@ -1344,7 +1344,7 @@ static int wlan_set_wep_key(struct assoc_request *assoc_req, pkey = &assoc_req->wep_keys[index]; if (key_length > 0) { - memset(pkey, 0, sizeof(struct WLAN_802_11_KEY)); + memset(pkey, 0, sizeof(struct enc_key)); pkey->type = KEY_TYPE_ID_WEP; /* Standardize the key length */ @@ -1412,11 +1412,11 @@ static void disable_wpa(struct assoc_request *assoc_req) { lbs_deb_enter(LBS_DEB_WEXT); - memset(&assoc_req->wpa_mcast_key, 0, sizeof (struct WLAN_802_11_KEY)); + memset(&assoc_req->wpa_mcast_key, 0, sizeof (struct enc_key)); assoc_req->wpa_mcast_key.flags = KEY_INFO_WPA_MCAST; set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags); - memset(&assoc_req->wpa_unicast_key, 0, sizeof (struct WLAN_802_11_KEY)); + memset(&assoc_req->wpa_unicast_key, 0, sizeof (struct enc_key)); assoc_req->wpa_unicast_key.flags = KEY_INFO_WPA_UNICAST; set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags); @@ -1567,7 +1567,7 @@ static int wlan_get_encodeext(struct net_device *dev, && (adapter->secinfo.WPAenabled || adapter->secinfo.WPA2enabled)) { /* WPA */ - struct WLAN_802_11_KEY * pkey = NULL; + struct enc_key * pkey = NULL; if ( adapter->wpa_mcast_key.len && (adapter->wpa_mcast_key.flags & KEY_INFO_WPA_ENABLED)) @@ -1679,7 +1679,7 @@ static int wlan_set_encodeext(struct net_device *dev, if (set_tx_key) set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags); } else if ((alg == IW_ENCODE_ALG_TKIP) || (alg == IW_ENCODE_ALG_CCMP)) { - struct WLAN_802_11_KEY * pkey; + struct enc_key * pkey; /* validate key length */ if (((alg == IW_ENCODE_ALG_TKIP) @@ -1702,7 +1702,7 @@ static int wlan_set_encodeext(struct net_device *dev, set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags); } - memset(pkey, 0, sizeof (struct WLAN_802_11_KEY)); + memset(pkey, 0, sizeof (struct enc_key)); memcpy(pkey->key, ext->key, ext->key_len); pkey->len = ext->key_len; if (pkey->len) -- cgit v1.2.3-70-g09d2 From 2950cd26308ced650cf7cc3199eae3eb27f9917f Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 10:47:17 -0400 Subject: [PATCH] libertas: clean up indentation in libertas_association_worker Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/assoc.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index 307ebcb94b1..36586db3e1f 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -556,7 +556,8 @@ void libertas_association_worker(struct work_struct *work) if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) { ret = assoc_helper_mode(priv, assoc_req); if (ret) { -lbs_deb_assoc("ASSOC(:%d) mode: ret = %d\n", __LINE__, ret); + lbs_deb_assoc("ASSOC(:%d) mode: ret = %d\n", + __LINE__, ret); goto out; } } @@ -574,7 +575,8 @@ lbs_deb_assoc("ASSOC(:%d) mode: ret = %d\n", __LINE__, ret); || test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) { ret = assoc_helper_wep_keys(priv, assoc_req); if (ret) { -lbs_deb_assoc("ASSOC(:%d) wep_keys: ret = %d\n", __LINE__, ret); + lbs_deb_assoc("ASSOC(:%d) wep_keys: ret = %d\n", + __LINE__, ret); goto out; } } @@ -582,7 +584,8 @@ lbs_deb_assoc("ASSOC(:%d) wep_keys: ret = %d\n", __LINE__, ret); if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) { ret = assoc_helper_secinfo(priv, assoc_req); if (ret) { -lbs_deb_assoc("ASSOC(:%d) secinfo: ret = %d\n", __LINE__, ret); + lbs_deb_assoc("ASSOC(:%d) secinfo: ret = %d\n", + __LINE__, ret); goto out; } } @@ -590,7 +593,8 @@ lbs_deb_assoc("ASSOC(:%d) secinfo: ret = %d\n", __LINE__, ret); if (test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) { ret = assoc_helper_wpa_ie(priv, assoc_req); if (ret) { -lbs_deb_assoc("ASSOC(:%d) wpa_ie: ret = %d\n", __LINE__, ret); + lbs_deb_assoc("ASSOC(:%d) wpa_ie: ret = %d\n", + __LINE__, ret); goto out; } } @@ -599,7 +603,8 @@ lbs_deb_assoc("ASSOC(:%d) wpa_ie: ret = %d\n", __LINE__, ret); || test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) { ret = assoc_helper_wpa_keys(priv, assoc_req); if (ret) { -lbs_deb_assoc("ASSOC(:%d) wpa_keys: ret = %d\n", __LINE__, ret); + lbs_deb_assoc("ASSOC(:%d) wpa_keys: ret = %d\n", + __LINE__, ret); goto out; } } -- cgit v1.2.3-70-g09d2 From ab6179711a5e46ed1db739bef7752d65ce836dce Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 10:48:02 -0400 Subject: [PATCH] libertas: clean up 802.11 IE post-scan handling Remove struct IE_WPA and just use direct checking of the IE bytes like ipw. Remove WLAN_802_11_VARIABLE_IEs because it's unused. Kill ieeetypes_elementid enum and just use MFIE_* from ieee80211.h. Also use struct ieee80211_info_element for scan buffer processing to simplify pointer usage. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/hostcmd.h | 13 --- drivers/net/wireless/libertas/scan.c | 199 ++++++++++++++------------------ drivers/net/wireless/libertas/types.h | 23 ---- 3 files changed, 84 insertions(+), 151 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index 01a97d0fa98..05ea54df71b 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -91,25 +91,12 @@ struct enc_key { u8 key[32]; }; -struct IE_WPA { - u8 elementid; - u8 len; - u8 oui[4]; - __le16 version; -}; - /* wlan_offset_value */ struct wlan_offset_value { u32 offset; u32 value; }; -struct WLAN_802_11_VARIABLE_IEs { - u8 elementid; - u8 length; - u8 data[1]; -}; - /* Define general data structure */ /* cmd_DS_GEN */ struct cmd_ds_gen { diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 8753f9344f3..2d6bc7811b2 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -74,8 +74,8 @@ static inline int match_bss_no_security(struct wlan_802_11_security * secinfo, if ( !secinfo->wep_enabled && !secinfo->WPAenabled && !secinfo->WPA2enabled - && match_bss->wpa_ie[0] != WPA_IE - && match_bss->rsn_ie[0] != WPA2_IE + && match_bss->wpa_ie[0] != MFIE_TYPE_GENERIC + && match_bss->rsn_ie[0] != MFIE_TYPE_RSN && !(match_bss->capability & WLAN_CAPABILITY_PRIVACY)) { return 1; } @@ -99,7 +99,7 @@ static inline int match_bss_wpa(struct wlan_802_11_security * secinfo, { if ( !secinfo->wep_enabled && secinfo->WPAenabled - && (match_bss->wpa_ie[0] == WPA_IE) + && (match_bss->wpa_ie[0] == MFIE_TYPE_GENERIC) /* privacy bit may NOT be set in some APs like LinkSys WRT54G && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) { */ @@ -114,7 +114,7 @@ static inline int match_bss_wpa2(struct wlan_802_11_security * secinfo, { if ( !secinfo->wep_enabled && secinfo->WPA2enabled - && (match_bss->rsn_ie[0] == WPA2_IE) + && (match_bss->rsn_ie[0] == MFIE_TYPE_RSN) /* privacy bit may NOT be set in some APs like LinkSys WRT54G && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) { */ @@ -130,8 +130,8 @@ static inline int match_bss_dynamic_wep(struct wlan_802_11_security * secinfo, if ( !secinfo->wep_enabled && !secinfo->WPAenabled && !secinfo->WPA2enabled - && (match_bss->wpa_ie[0] != WPA_IE) - && (match_bss->rsn_ie[0] != WPA2_IE) + && (match_bss->wpa_ie[0] != MFIE_TYPE_GENERIC) + && (match_bss->rsn_ie[0] != MFIE_TYPE_RSN) && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) { return 1; } @@ -900,24 +900,18 @@ void wlan_ret_802_11_scan_get_tlv_ptrs(struct mrvlietypes_data * ptlv, static int libertas_process_bss(struct bss_descriptor * bss, u8 ** pbeaconinfo, int *bytesleft) { - enum ieeetypes_elementid elemID; struct ieeetypes_fhparamset *pFH; struct ieeetypes_dsparamset *pDS; struct ieeetypes_cfparamset *pCF; struct ieeetypes_ibssparamset *pibss; - u8 *pcurrentptr; + u8 *pos, *end; u8 *pRate; - u8 elemlen; u8 bytestocopy; u8 ratesize; u16 beaconsize; u8 founddatarateie; - int bytesleftforcurrentbeacon; int ret; - struct IE_WPA *pIe; - const u8 oui01[4] = { 0x00, 0x50, 0xf2, 0x01 }; - struct ieeetypes_countryinfoset *pcountryinfo; lbs_deb_enter(LBS_DEB_ASSOC); @@ -934,29 +928,24 @@ static int libertas_process_bss(struct bss_descriptor * bss, } if (beaconsize == 0 || beaconsize > *bytesleft) { - *pbeaconinfo += *bytesleft; *bytesleft = 0; - return -1; } /* Initialize the current working beacon pointer for this BSS iteration */ - pcurrentptr = *pbeaconinfo; + pos = *pbeaconinfo; + end = pos + beaconsize; /* Advance the return beacon pointer past the current beacon */ *pbeaconinfo += beaconsize; *bytesleft -= beaconsize; - bytesleftforcurrentbeacon = beaconsize; - - memcpy(bss->bssid, pcurrentptr, ETH_ALEN); + memcpy(bss->bssid, pos, ETH_ALEN); lbs_deb_scan("process_bss: AP BSSID " MAC_FMT "\n", MAC_ARG(bss->bssid)); + pos += ETH_ALEN; - pcurrentptr += ETH_ALEN; - bytesleftforcurrentbeacon -= ETH_ALEN; - - if (bytesleftforcurrentbeacon < 12) { + if ((end - pos) < 12) { lbs_deb_scan("process_bss: Not enough bytes left\n"); return -1; } @@ -967,26 +956,22 @@ static int libertas_process_bss(struct bss_descriptor * bss, */ /* RSSI is 1 byte long */ - bss->rssi = *pcurrentptr; - lbs_deb_scan("process_bss: RSSI=%02X\n", *pcurrentptr); - pcurrentptr += 1; - bytesleftforcurrentbeacon -= 1; + bss->rssi = *pos; + lbs_deb_scan("process_bss: RSSI=%02X\n", *pos); + pos++; /* time stamp is 8 bytes long */ - bss->timestamp = le64_to_cpup((void *)pcurrentptr); - pcurrentptr += 8; - bytesleftforcurrentbeacon -= 8; + bss->timestamp = le64_to_cpup((void *) pos); + pos += 8; /* beacon interval is 2 bytes long */ - bss->beaconperiod = le16_to_cpup((void *)pcurrentptr); - pcurrentptr += 2; - bytesleftforcurrentbeacon -= 2; + bss->beaconperiod = le16_to_cpup((void *) pos); + pos += 2; /* capability information is 2 bytes long */ - bss->capability = le16_to_cpup((void *)pcurrentptr); + bss->capability = le16_to_cpup((void *) pos); lbs_deb_scan("process_bss: capabilities = 0x%4X\n", bss->capability); - pcurrentptr += 2; - bytesleftforcurrentbeacon -= 2; + pos += 2; if (bss->capability & WLAN_CAPABILITY_PRIVACY) lbs_deb_scan("process_bss: AP WEP enabled\n"); @@ -996,47 +981,39 @@ static int libertas_process_bss(struct bss_descriptor * bss, bss->mode = IW_MODE_INFRA; /* rest of the current buffer are IE's */ - lbs_deb_scan("process_bss: IE length for this AP = %d\n", - bytesleftforcurrentbeacon); - - lbs_dbg_hex("process_bss: IE info", (u8 *) pcurrentptr, - bytesleftforcurrentbeacon); + lbs_deb_scan("process_bss: IE length for this AP = %zd\n", end - pos); + lbs_dbg_hex("process_bss: IE info", pos, end - pos); /* process variable IE */ - while (bytesleftforcurrentbeacon >= 2) { - elemID = (enum ieeetypes_elementid) (*((u8 *) pcurrentptr)); - elemlen = *((u8 *) pcurrentptr + 1); + while (pos <= end - 2) { + struct ieee80211_info_element * elem = + (struct ieee80211_info_element *) pos; - if (bytesleftforcurrentbeacon < elemlen) { + if (pos + elem->len > end) { lbs_deb_scan("process_bss: error in processing IE, " "bytes left < IE length\n"); - bytesleftforcurrentbeacon = 0; - continue; + break; } - switch (elemID) { - case SSID: - bss->ssid_len = elemlen; - memcpy(bss->ssid, (pcurrentptr + 2), elemlen); + switch (elem->id) { + case MFIE_TYPE_SSID: + bss->ssid_len = elem->len; + memcpy(bss->ssid, elem->data, elem->len); lbs_deb_scan("ssid '%s', ssid length %u\n", escape_essid(bss->ssid, bss->ssid_len), bss->ssid_len); break; - case SUPPORTED_RATES: - memcpy(bss->datarates, (pcurrentptr + 2), elemlen); - memmove(bss->libertas_supported_rates, (pcurrentptr + 2), - elemlen); - ratesize = elemlen; + case MFIE_TYPE_RATES: + memcpy(bss->datarates, elem->data, elem->len); + memmove(bss->libertas_supported_rates, elem->data, + elem->len); + ratesize = elem->len; founddatarateie = 1; break; - case EXTRA_IE: - lbs_deb_scan("process_bss: EXTRA_IE Found!\n"); - break; - - case FH_PARAM_SET: - pFH = (struct ieeetypes_fhparamset *) pcurrentptr; + case MFIE_TYPE_FH_SET: + pFH = (struct ieeetypes_fhparamset *) pos; memmove(&bss->phyparamset.fhparamset, pFH, sizeof(struct ieeetypes_fhparamset)); #if 0 /* I think we can store these LE */ @@ -1045,21 +1022,21 @@ static int libertas_process_bss(struct bss_descriptor * bss, #endif break; - case DS_PARAM_SET: - pDS = (struct ieeetypes_dsparamset *) pcurrentptr; + case MFIE_TYPE_DS_SET: + pDS = (struct ieeetypes_dsparamset *) pos; bss->channel = pDS->currentchan; memcpy(&bss->phyparamset.dsparamset, pDS, sizeof(struct ieeetypes_dsparamset)); break; - case CF_PARAM_SET: - pCF = (struct ieeetypes_cfparamset *) pcurrentptr; + case MFIE_TYPE_CF_SET: + pCF = (struct ieeetypes_cfparamset *) pos; memcpy(&bss->ssparamset.cfparamset, pCF, sizeof(struct ieeetypes_cfparamset)); break; - case IBSS_PARAM_SET: - pibss = (struct ieeetypes_ibssparamset *) pcurrentptr; + case MFIE_TYPE_IBSS_SET: + pibss = (struct ieeetypes_ibssparamset *) pos; bss->atimwindow = le32_to_cpu(pibss->atimwindow); memmove(&bss->ssparamset.ibssparamset, pibss, sizeof(struct ieeetypes_ibssparamset)); @@ -1069,9 +1046,8 @@ static int libertas_process_bss(struct bss_descriptor * bss, #endif break; - /* Handle Country Info IE */ - case COUNTRY_INFO: - pcountryinfo = (struct ieeetypes_countryinfoset *) pcurrentptr; + case MFIE_TYPE_COUNTRY: + pcountryinfo = (struct ieeetypes_countryinfoset *) pos; if (pcountryinfo->len < sizeof(pcountryinfo->countrycode) || pcountryinfo->len > 254) { lbs_deb_scan("process_bss: 11D- Err " @@ -1089,62 +1065,55 @@ static int libertas_process_bss(struct bss_descriptor * bss, (u32) (pcountryinfo->len + 2)); break; - case EXTENDED_SUPPORTED_RATES: - /* - * only process extended supported rate - * if data rate is already found. - * data rate IE should come before + case MFIE_TYPE_RATES_EX: + /* only process extended supported rate if data rate is + * already found. Data rate IE should come before * extended supported rate IE */ - if (founddatarateie) { - if ((elemlen + ratesize) > WLAN_SUPPORTED_RATES) { - bytestocopy = - (WLAN_SUPPORTED_RATES - ratesize); - } else { - bytestocopy = elemlen; - } + if (!founddatarateie) + break; - pRate = (u8 *) bss->datarates; - pRate += ratesize; - memmove(pRate, (pcurrentptr + 2), bytestocopy); - pRate = (u8 *) bss->libertas_supported_rates; - pRate += ratesize; - memmove(pRate, (pcurrentptr + 2), bytestocopy); + if ((elem->len + ratesize) > WLAN_SUPPORTED_RATES) { + bytestocopy = + (WLAN_SUPPORTED_RATES - ratesize); + } else { + bytestocopy = elem->len; } - break; - - case VENDOR_SPECIFIC_221: -#define IE_ID_LEN_FIELDS_BYTES 2 - pIe = (struct IE_WPA *)pcurrentptr; - if (memcmp(pIe->oui, oui01, sizeof(oui01))) - break; - - bss->wpa_ie_len = min(elemlen + IE_ID_LEN_FIELDS_BYTES, - MAX_WPA_IE_LEN); - memcpy(bss->wpa_ie, pcurrentptr, bss->wpa_ie_len); - lbs_dbg_hex("process_bss: WPA IE", bss->wpa_ie, elemlen); + pRate = (u8 *) bss->datarates; + pRate += ratesize; + memmove(pRate, elem->data, bytestocopy); + pRate = (u8 *) bss->libertas_supported_rates; + pRate += ratesize; + memmove(pRate, elem->data, bytestocopy); break; - case WPA2_IE: - pIe = (struct IE_WPA *)pcurrentptr; - bss->rsn_ie_len = min(elemlen + IE_ID_LEN_FIELDS_BYTES, - MAX_WPA_IE_LEN); - memcpy(bss->rsn_ie, pcurrentptr, bss->rsn_ie_len); - lbs_dbg_hex("process_bss: RSN_IE", bss->rsn_ie, elemlen); + + case MFIE_TYPE_GENERIC: + if (elem->len >= 4 && + elem->data[0] == 0x00 && + elem->data[1] == 0x50 && + elem->data[2] == 0xf2 && + elem->data[3] == 0x01) { + bss->wpa_ie_len = min(elem->len + 2, + MAX_WPA_IE_LEN); + memcpy(bss->wpa_ie, elem, bss->wpa_ie_len); + lbs_dbg_hex("process_bss: WPA IE", bss->wpa_ie, + elem->len); + } break; - case TIM: + + case MFIE_TYPE_RSN: + bss->rsn_ie_len = min(elem->len + 2, MAX_WPA_IE_LEN); + memcpy(bss->rsn_ie, elem, bss->rsn_ie_len); + lbs_dbg_hex("process_bss: RSN_IE", bss->rsn_ie, elem->len); break; - case CHALLENGE_TEXT: + default: break; } - pcurrentptr += elemlen + 2; - - /* need to account for IE ID and IE len */ - bytesleftforcurrentbeacon -= (elemlen + 2); - - } /* while (bytesleftforcurrentbeacon > 2) */ + pos += elem->len + 2; + } /* Timestamp */ bss->last_scanned = jiffies; diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h index f4be1293cd1..2df352db155 100644 --- a/drivers/net/wireless/libertas/types.h +++ b/drivers/net/wireless/libertas/types.h @@ -7,29 +7,6 @@ #include #include -/** IEEE type definitions */ -enum ieeetypes_elementid { - SSID = 0, - SUPPORTED_RATES, - FH_PARAM_SET, - DS_PARAM_SET, - CF_PARAM_SET, - TIM, - IBSS_PARAM_SET, - COUNTRY_INFO = 7, - - CHALLENGE_TEXT = 16, - - EXTENDED_SUPPORTED_RATES = 50, - - VENDOR_SPECIFIC_221 = 221, - - WPA_IE = 221, - WPA2_IE = 48, - - EXTRA_IE = 133, -} __attribute__ ((packed)); - #define CAPINFO_MASK (~(0x00da)) struct ieeetypes_cfparamset { -- cgit v1.2.3-70-g09d2 From 1e838bf31c3a24596621026c7d1ca69da068af83 Mon Sep 17 00:00:00 2001 From: Luis Carlos Cobo Date: Thu, 2 Aug 2007 10:51:27 -0400 Subject: [PATCH] libertas: specific mesh scan for mshX interface With this patch, scanning with mshX interface will only return mesh networks. To differentiate them, a specific mesh IE in beacons/probe responses is used. This IE has been introduced in firmware release 5.110.14. Note: Even though there can be at most a single mesh per channel, this scan might return several networks in the same channel. If all nodes in a mesh network are associated to an AP, they won't produce beacons/probe responses, thus the network will not be listed. This will be fixed in future firmware releases. Scan on ethX interface is not filtered, so it will list both mesh and non-mesh networks. Signed-off-by: Luis Carlos Cobo Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/defs.h | 2 ++ drivers/net/wireless/libertas/scan.c | 10 ++++++++++ drivers/net/wireless/libertas/scan.h | 2 ++ 3 files changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h index de0756ee15a..a5d70c19768 100644 --- a/drivers/net/wireless/libertas/defs.h +++ b/drivers/net/wireless/libertas/defs.h @@ -156,6 +156,8 @@ static inline void lbs_dbg_hex(char *prompt, u8 * buf, int len) #define MRVDRV_MAX_BEACON_INTERVAL 1000 #define MRVDRV_BEACON_INTERVAL 100 +#define MARVELL_MESH_IE_LENGTH 9 + /** INT status Bit Definition*/ #define his_cmddnldrdy 0x01 #define his_cardevent 0x02 diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 2d6bc7811b2..a98feedf001 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -1099,6 +1099,12 @@ static int libertas_process_bss(struct bss_descriptor * bss, memcpy(bss->wpa_ie, elem, bss->wpa_ie_len); lbs_dbg_hex("process_bss: WPA IE", bss->wpa_ie, elem->len); + } else if (elem->len >= MARVELL_MESH_IE_LENGTH && + elem->data[0] == 0x00 && + elem->data[1] == 0x50 && + elem->data[2] == 0x43 && + elem->data[3] == 0x04) { + bss->mesh = 1; } break; @@ -1611,6 +1617,10 @@ int libertas_get_scan(struct net_device *dev, struct iw_request_info *info, break; } + /* For mesh device, list only mesh networks */ + if (dev == priv->mesh_dev && !iter_bss->mesh) + continue; + /* Prune old an old scan result */ stale_time = iter_bss->last_scanned + DEFAULT_MAX_SCAN_AGE; if (time_after(jiffies, stale_time)) { diff --git a/drivers/net/wireless/libertas/scan.h b/drivers/net/wireless/libertas/scan.h index 2a095733f19..23c539c2263 100644 --- a/drivers/net/wireless/libertas/scan.h +++ b/drivers/net/wireless/libertas/scan.h @@ -170,6 +170,8 @@ struct bss_descriptor { u8 rsn_ie[MAX_WPA_IE_LEN]; size_t rsn_ie_len; + u8 mesh; + struct list_head list; }; -- cgit v1.2.3-70-g09d2 From 9e22cb67d9a8acde7a5af6ed8cd5e74ebd6551b3 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 11:14:49 -0400 Subject: [PATCH] libertas: remove if_bootcmd.c Move the only function in it to if_usb.c, which was its only user anyway. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/Makefile | 1 - drivers/net/wireless/libertas/if_bootcmd.c | 40 ------------------------------ drivers/net/wireless/libertas/if_usb.c | 24 ++++++++++++++++++ drivers/net/wireless/libertas/if_usb.h | 1 - 4 files changed, 24 insertions(+), 42 deletions(-) delete mode 100644 drivers/net/wireless/libertas/if_bootcmd.c (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/Makefile b/drivers/net/wireless/libertas/Makefile index 32ed4136b0d..61e0d6e0790 100644 --- a/drivers/net/wireless/libertas/Makefile +++ b/drivers/net/wireless/libertas/Makefile @@ -5,7 +5,6 @@ libertas-objs := main.o fw.o wext.o \ debugfs.o \ ethtool.o assoc.o -usb8xxx-objs += if_bootcmd.o usb8xxx-objs += if_usb.o obj-$(CONFIG_LIBERTAS) += libertas.o diff --git a/drivers/net/wireless/libertas/if_bootcmd.c b/drivers/net/wireless/libertas/if_bootcmd.c deleted file mode 100644 index 8bca306ffad..00000000000 --- a/drivers/net/wireless/libertas/if_bootcmd.c +++ /dev/null @@ -1,40 +0,0 @@ -/** - * This file contains functions used in USB Boot command - * and Boot2/FW update - */ - -#include -#include -#include -#include - -#define DRV_NAME "usb8xxx" - -#include "defs.h" -#include "dev.h" -#include "if_usb.h" - -/** - * @brief This function issues Boot command to the Boot2 code - * @param ivalue 1:Boot from FW by USB-Download - * 2:Boot from FW in EEPROM - * @return 0 - */ -int if_usb_issue_boot_command(wlan_private *priv, int ivalue) -{ - struct usb_card_rec *cardp = priv->card; - struct bootcmdstr sbootcmd; - int i; - - /* Prepare command */ - sbootcmd.u32magicnumber = cpu_to_le32(BOOT_CMD_MAGIC_NUMBER); - sbootcmd.u8cmd_tag = ivalue; - for (i=0; i<11; i++) - sbootcmd.au8dumy[i]=0x00; - memcpy(cardp->bulk_out_buffer, &sbootcmd, sizeof(struct bootcmdstr)); - - /* Issue command */ - usb_tx_block(priv, cardp->bulk_out_buffer, sizeof(struct bootcmdstr)); - - return 0; -} diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index 998317571ec..11687b84c59 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -803,6 +803,30 @@ static int if_usb_register_dev(wlan_private * priv) return 0; } +/** + * @brief This function issues Boot command to the Boot2 code + * @param ivalue 1:Boot from FW by USB-Download + * 2:Boot from FW in EEPROM + * @return 0 + */ +static int if_usb_issue_boot_command(wlan_private *priv, int ivalue) +{ + struct usb_card_rec *cardp = priv->card; + struct bootcmdstr sbootcmd; + int i; + + /* Prepare command */ + sbootcmd.u32magicnumber = cpu_to_le32(BOOT_CMD_MAGIC_NUMBER); + sbootcmd.u8cmd_tag = ivalue; + for (i=0; i<11; i++) + sbootcmd.au8dumy[i]=0x00; + memcpy(cardp->bulk_out_buffer, &sbootcmd, sizeof(struct bootcmdstr)); + + /* Issue command */ + usb_tx_block(priv, cardp->bulk_out_buffer, sizeof(struct bootcmdstr)); + + return 0; +} static int if_usb_prog_firmware(wlan_private * priv) diff --git a/drivers/net/wireless/libertas/if_usb.h b/drivers/net/wireless/libertas/if_usb.h index 156bb485e1a..5da8c94ca4c 100644 --- a/drivers/net/wireless/libertas/if_usb.h +++ b/drivers/net/wireless/libertas/if_usb.h @@ -104,6 +104,5 @@ struct fwsyncheader { int usb_tx_block(wlan_private *priv, u8 *payload, u16 nb); void if_usb_free(struct usb_card_rec *cardp); -int if_usb_issue_boot_command(wlan_private *priv, int ivalue); #endif -- cgit v1.2.3-70-g09d2 From 492b6da7d220b37275efb03710d57215304149fa Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 11:16:07 -0400 Subject: [PATCH] libertas: fix mixed-case abuse in cmd_ds_802_11_scan Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/hostcmd.h | 2 +- drivers/net/wireless/libertas/scan.c | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index 05ea54df71b..e4fafbfa358 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -159,7 +159,7 @@ struct cmd_ds_802_11_subscribe_event { */ struct cmd_ds_802_11_scan { u8 bsstype; - u8 BSSID[ETH_ALEN]; + u8 bssid[ETH_ALEN]; u8 tlvbuffer[1]; #if 0 mrvlietypes_ssidparamset_t ssidParamSet; diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index a98feedf001..2937f79c4a0 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -1677,15 +1677,14 @@ int libertas_cmd_80211_scan(wlan_private * priv, /* Set fixed field variables in scan command */ pscan->bsstype = pscancfg->bsstype; - memcpy(pscan->BSSID, pscancfg->bssid, sizeof(pscan->BSSID)); + memcpy(pscan->bssid, pscancfg->bssid, ETH_ALEN); memcpy(pscan->tlvbuffer, pscancfg->tlvbuffer, pscancfg->tlvbufferlen); cmd->command = cpu_to_le16(cmd_802_11_scan); /* size is equal to the sizeof(fixed portions) + the TLV len + header */ - cmd->size = cpu_to_le16(sizeof(pscan->bsstype) - + sizeof(pscan->BSSID) - + pscancfg->tlvbufferlen + S_DS_GEN); + cmd->size = cpu_to_le16(sizeof(pscan->bsstype) + ETH_ALEN + + pscancfg->tlvbufferlen + S_DS_GEN); lbs_deb_scan("SCAN_CMD: command=%x, size=%x, seqnum=%x\n", le16_to_cpu(cmd->command), le16_to_cpu(cmd->size), -- cgit v1.2.3-70-g09d2 From ea8da92d70c4e320c282d4e94138e40e36880be3 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 11:18:23 -0400 Subject: [PATCH] libertas: fix mixed-case abuse in cmd_ds_802_11_ad_hoc_result Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/hostcmd.h | 4 ++-- drivers/net/wireless/libertas/join.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index e4fafbfa358..6b5e58c88c4 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -237,8 +237,8 @@ struct cmd_ds_802_11_associate_rsp { }; struct cmd_ds_802_11_ad_hoc_result { - u8 PAD[3]; - u8 BSSID[ETH_ALEN]; + u8 pad[3]; + u8 bssid[ETH_ALEN]; }; struct cmd_ds_802_11_set_wep { diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c index 2db7fbfcaeb..526b0b9db94 100644 --- a/drivers/net/wireless/libertas/join.c +++ b/drivers/net/wireless/libertas/join.c @@ -821,7 +821,7 @@ int libertas_ret_80211_ad_hoc_start(wlan_private * priv, if (command == cmd_ret_802_11_ad_hoc_start) { /* Update the created network descriptor with the new BSSID */ - memcpy(bss->bssid, padhocresult->BSSID, ETH_ALEN); + memcpy(bss->bssid, padhocresult->bssid, ETH_ALEN); } /* Set the BSSID from the joined/started descriptor */ -- cgit v1.2.3-70-g09d2 From b44898eb2c917cd397a0d8654f1c249dd3cdc67e Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 11:18:40 -0400 Subject: [PATCH] libertas: fix mixed-case abuse in cmd_ds_802_11_ad_hoc_start Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/hostcmd.h | 2 +- drivers/net/wireless/libertas/join.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index 6b5e58c88c4..23871c0f882 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -439,7 +439,7 @@ struct cmd_ds_802_11_rate_adapt_rateset { }; struct cmd_ds_802_11_ad_hoc_start { - u8 SSID[IW_ESSID_MAX_SIZE]; + u8 ssid[IW_ESSID_MAX_SIZE]; u8 bsstype; __le16 beaconperiod; u8 dtimperiod; diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c index 526b0b9db94..db467e7876f 100644 --- a/drivers/net/wireless/libertas/join.c +++ b/drivers/net/wireless/libertas/join.c @@ -479,8 +479,8 @@ int libertas_cmd_80211_ad_hoc_start(wlan_private * priv, * and operational rates. */ - memset(adhs->SSID, 0, IW_ESSID_MAX_SIZE); - memcpy(adhs->SSID, assoc_req->ssid, assoc_req->ssid_len); + memset(adhs->ssid, 0, IW_ESSID_MAX_SIZE); + memcpy(adhs->ssid, assoc_req->ssid, assoc_req->ssid_len); lbs_deb_join("ADHOC_S_CMD: SSID '%s', ssid length %u\n", escape_essid(assoc_req->ssid, assoc_req->ssid_len), -- cgit v1.2.3-70-g09d2 From 0aef64d75851c9f3545d0793f26486ed862306d8 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 11:31:18 -0400 Subject: [PATCH] libertas: re-uppercase command defines and other constants For readability. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/11d.c | 22 +- drivers/net/wireless/libertas/assoc.c | 68 ++--- drivers/net/wireless/libertas/cmd.c | 322 +++++++++++------------ drivers/net/wireless/libertas/cmdresp.c | 140 +++++----- drivers/net/wireless/libertas/debugfs.c | 92 +++---- drivers/net/wireless/libertas/defs.h | 50 ++-- drivers/net/wireless/libertas/ethtool.c | 8 +- drivers/net/wireless/libertas/fw.c | 24 +- drivers/net/wireless/libertas/host.h | 436 ++++++++++++++++---------------- drivers/net/wireless/libertas/hostcmd.h | 4 +- drivers/net/wireless/libertas/if_usb.c | 6 +- drivers/net/wireless/libertas/join.c | 74 +++--- drivers/net/wireless/libertas/main.c | 52 ++-- drivers/net/wireless/libertas/scan.c | 20 +- drivers/net/wireless/libertas/tx.c | 2 +- drivers/net/wireless/libertas/wext.c | 86 +++---- 16 files changed, 703 insertions(+), 703 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/11d.c b/drivers/net/wireless/libertas/11d.c index 4cf0ff7b833..26d85ec37d9 100644 --- a/drivers/net/wireless/libertas/11d.c +++ b/drivers/net/wireless/libertas/11d.c @@ -422,13 +422,13 @@ done: u8 libertas_get_scan_type_11d(u8 chan, struct parsed_region_chan_11d * parsed_region_chan) { - u8 scan_type = cmd_scan_type_passive; + u8 scan_type = CMD_SCAN_TYPE_PASSIVE; lbs_deb_enter(LBS_DEB_11D); if (wlan_channel_known_11d(chan, parsed_region_chan)) { lbs_deb_11d("11D: Found and do Active Scan\n"); - scan_type = cmd_scan_type_active; + scan_type = CMD_SCAN_TYPE_ACTIVE; } else { lbs_deb_11d("11D: Not Find and do Passive Scan\n"); } @@ -454,9 +454,9 @@ static int wlan_enable_11d(wlan_private * priv, u8 flag) /* send cmd to FW to enable/disable 11D function in FW */ ret = libertas_prepare_and_send_command(priv, - cmd_802_11_snmp_mib, - cmd_act_set, - cmd_option_waitforrsp, + CMD_802_11_SNMP_MIB, + CMD_ACT_SET, + CMD_OPTION_WAITFORRSP, OID_802_11D_ENABLE, &priv->adapter->enable11d); if (ret) @@ -479,9 +479,9 @@ static int set_domain_info_11d(wlan_private * priv) return 0; } - ret = libertas_prepare_and_send_command(priv, cmd_802_11d_domain_info, - cmd_act_set, - cmd_option_waitforrsp, 0, NULL); + ret = libertas_prepare_and_send_command(priv, CMD_802_11D_DOMAIN_INFO, + CMD_ACT_SET, + CMD_OPTION_WAITFORRSP, 0, NULL); if (ret) lbs_deb_11d("11D: Fail to dnld domain Info\n"); @@ -541,7 +541,7 @@ int libertas_cmd_802_11d_domain_info(wlan_private * priv, cmd->command = cpu_to_le16(cmdno); pdomaininfo->action = cpu_to_le16(cmdoption); - if (cmdoption == cmd_act_get) { + if (cmdoption == CMD_ACT_GET) { cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN); lbs_dbg_hex("11D: 802_11D_DOMAIN_INFO:", (u8 *) cmd, @@ -633,10 +633,10 @@ int libertas_ret_802_11d_domain_info(wlan_private * priv, } switch (action) { - case cmd_act_set: /*Proc Set action */ + case CMD_ACT_SET: /*Proc Set action */ break; - case cmd_act_get: + case CMD_ACT_GET: break; default: lbs_deb_11d("Invalid action:%d\n", domaininfo->action); diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index 36586db3e1f..5fdc96f289b 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -175,14 +175,14 @@ static int assoc_helper_mode(wlan_private *priv, if (assoc_req->mode == IW_MODE_INFRA) { if (adapter->psstate != PS_STATE_FULL_POWER) - libertas_ps_wakeup(priv, cmd_option_waitforrsp); - adapter->psmode = wlan802_11powermodecam; + libertas_ps_wakeup(priv, CMD_OPTION_WAITFORRSP); + adapter->psmode = WLAN802_11POWERMODECAM; } adapter->mode = assoc_req->mode; ret = libertas_prepare_and_send_command(priv, - cmd_802_11_snmp_mib, - 0, cmd_option_waitforrsp, + CMD_802_11_SNMP_MIB, + 0, CMD_OPTION_WAITFORRSP, OID_802_11_INFRASTRUCTURE_MODE, /* Shoot me now */ (void *) (size_t) assoc_req->mode); @@ -195,9 +195,9 @@ done: static int update_channel(wlan_private * priv) { /* the channel in f/w could be out of sync, get the current channel */ - return libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel, - cmd_opt_802_11_rf_channel_get, - cmd_option_waitforrsp, 0, NULL); + return libertas_prepare_and_send_command(priv, CMD_802_11_RF_CHANNEL, + CMD_OPT_802_11_RF_CHANNEL_GET, + CMD_OPTION_WAITFORRSP, 0, NULL); } void libertas_sync_channel(struct work_struct *work) @@ -227,9 +227,9 @@ static int assoc_helper_channel(wlan_private *priv, lbs_deb_assoc("ASSOC: channel: %d -> %d\n", adapter->curbssparams.channel, assoc_req->channel); - ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel, - cmd_opt_802_11_rf_channel_set, - cmd_option_waitforrsp, 0, &assoc_req->channel); + ret = libertas_prepare_and_send_command(priv, CMD_802_11_RF_CHANNEL, + CMD_OPT_802_11_RF_CHANNEL_SET, + CMD_OPTION_WAITFORRSP, 0, &assoc_req->channel); if (ret < 0) { lbs_deb_assoc("ASSOC: channel: error setting channel."); } @@ -278,15 +278,15 @@ static int assoc_helper_wep_keys(wlan_private *priv, || assoc_req->wep_keys[2].len || assoc_req->wep_keys[3].len) { ret = libertas_prepare_and_send_command(priv, - cmd_802_11_set_wep, - cmd_act_add, - cmd_option_waitforrsp, + CMD_802_11_SET_WEP, + CMD_ACT_ADD, + CMD_OPTION_WAITFORRSP, 0, assoc_req); } else { ret = libertas_prepare_and_send_command(priv, - cmd_802_11_set_wep, - cmd_act_remove, - cmd_option_waitforrsp, + CMD_802_11_SET_WEP, + CMD_ACT_REMOVE, + CMD_OPTION_WAITFORRSP, 0, NULL); } @@ -295,9 +295,9 @@ static int assoc_helper_wep_keys(wlan_private *priv, /* enable/disable the MAC's WEP packet filter */ if (assoc_req->secinfo.wep_enabled) - adapter->currentpacketfilter |= cmd_act_mac_wep_enable; + adapter->currentpacketfilter |= CMD_ACT_MAC_WEP_ENABLE; else - adapter->currentpacketfilter &= ~cmd_act_mac_wep_enable; + adapter->currentpacketfilter &= ~CMD_ACT_MAC_WEP_ENABLE; ret = libertas_set_mac_packet_filter(priv); if (ret) goto out; @@ -342,9 +342,9 @@ static int assoc_helper_secinfo(wlan_private *priv, /* Get RSN enabled/disabled */ ret = libertas_prepare_and_send_command(priv, - cmd_802_11_enable_rsn, - cmd_act_set, - cmd_option_waitforrsp, + CMD_802_11_ENABLE_RSN, + CMD_ACT_GET, + CMD_OPTION_WAITFORRSP, 0, &rsn); if (ret) { lbs_deb_assoc("Failed to get RSN status: %d", ret); @@ -359,9 +359,9 @@ static int assoc_helper_secinfo(wlan_private *priv, /* Set RSN enabled/disabled */ rsn = do_wpa; ret = libertas_prepare_and_send_command(priv, - cmd_802_11_enable_rsn, - cmd_act_set, - cmd_option_waitforrsp, + CMD_802_11_ENABLE_RSN, + CMD_ACT_SET, + CMD_OPTION_WAITFORRSP, 0, &rsn); out: @@ -378,9 +378,9 @@ static int assoc_helper_wpa_keys(wlan_private *priv, lbs_deb_enter(LBS_DEB_ASSOC); ret = libertas_prepare_and_send_command(priv, - cmd_802_11_key_material, - cmd_act_set, - cmd_option_waitforrsp, + CMD_802_11_KEY_MATERIAL, + CMD_ACT_SET, + CMD_OPTION_WAITFORRSP, 0, assoc_req); lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); @@ -412,7 +412,7 @@ static int assoc_helper_wpa_ie(wlan_private *priv, static int should_deauth_infrastructure(wlan_adapter *adapter, struct assoc_request * assoc_req) { - if (adapter->connect_status != libertas_connected) + if (adapter->connect_status != LIBERTAS_CONNECTED) return 0; if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) { @@ -453,7 +453,7 @@ static int should_deauth_infrastructure(wlan_adapter *adapter, static int should_stop_adhoc(wlan_adapter *adapter, struct assoc_request * assoc_req) { - if (adapter->connect_status != libertas_connected) + if (adapter->connect_status != LIBERTAS_CONNECTED) return 0; if (libertas_ssid_cmp(adapter->curbssparams.ssid, @@ -623,7 +623,7 @@ void libertas_association_worker(struct work_struct *work) success = 0; } - if (adapter->connect_status != libertas_connected) { + if (adapter->connect_status != LIBERTAS_CONNECTED) { lbs_deb_assoc("ASSOC: assoication attempt unsuccessful, " "not connected.\n"); success = 0; @@ -636,12 +636,12 @@ void libertas_association_worker(struct work_struct *work) adapter->curbssparams.ssid_len), MAC_ARG(adapter->curbssparams.bssid)); libertas_prepare_and_send_command(priv, - cmd_802_11_rssi, - 0, cmd_option_waitforrsp, 0, NULL); + CMD_802_11_RSSI, + 0, CMD_OPTION_WAITFORRSP, 0, NULL); libertas_prepare_and_send_command(priv, - cmd_802_11_get_log, - 0, cmd_option_waitforrsp, 0, NULL); + CMD_802_11_GET_LOG, + 0, CMD_OPTION_WAITFORRSP, 0, NULL); } else { ret = -1; } diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 355a3960323..e0eab6e3a9b 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -15,7 +15,7 @@ static void cleanup_cmdnode(struct cmd_ctrl_node *ptempnode); static u16 commands_allowed_in_ps[] = { - cmd_802_11_rssi, + CMD_802_11_RSSI, }; /** @@ -43,7 +43,7 @@ static int wlan_cmd_hw_spec(wlan_private * priv, struct cmd_ds_command *cmd) lbs_deb_enter(LBS_DEB_CMD); - cmd->command = cpu_to_le16(cmd_get_hw_spec); + cmd->command = cpu_to_le16(CMD_GET_HW_SPEC); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_get_hw_spec) + S_DS_GEN); memcpy(hwspec->permanentaddr, priv->adapter->current_addr, ETH_ALEN); @@ -60,13 +60,13 @@ static int wlan_cmd_802_11_ps_mode(wlan_private * priv, lbs_deb_enter(LBS_DEB_CMD); - cmd->command = cpu_to_le16(cmd_802_11_ps_mode); + cmd->command = cpu_to_le16(CMD_802_11_PS_MODE); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ps_mode) + S_DS_GEN); psm->action = cpu_to_le16(cmd_action); psm->multipledtim = 0; switch (cmd_action) { - case cmd_subcmd_enter_ps: + case CMD_SUBCMD_ENTER_PS: lbs_deb_cmd("PS command:" "SubCode- Enter PS\n"); lbs_deb_cmd("locallisteninterval = %d\n", adapter->locallisteninterval); @@ -79,11 +79,11 @@ static int wlan_cmd_802_11_ps_mode(wlan_private * priv, cpu_to_le16(priv->adapter->multipledtim); break; - case cmd_subcmd_exit_ps: + case CMD_SUBCMD_EXIT_PS: lbs_deb_cmd("PS command:" "SubCode- Exit PS\n"); break; - case cmd_subcmd_sleep_confirmed: + case CMD_SUBCMD_SLEEP_CONFIRMED: lbs_deb_cmd("PS command: SubCode- sleep confirm\n"); break; @@ -101,7 +101,7 @@ static int wlan_cmd_802_11_inactivity_timeout(wlan_private * priv, { u16 *timeout = pdata_buf; - cmd->command = cpu_to_le16(cmd_802_11_inactivity_timeout); + cmd->command = cpu_to_le16(CMD_802_11_INACTIVITY_TIMEOUT); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_inactivity_timeout) + S_DS_GEN); @@ -127,13 +127,13 @@ static int wlan_cmd_802_11_sleep_params(wlan_private * priv, cmd->size = cpu_to_le16((sizeof(struct cmd_ds_802_11_sleep_params)) + S_DS_GEN); - cmd->command = cpu_to_le16(cmd_802_11_sleep_params); + cmd->command = cpu_to_le16(CMD_802_11_SLEEP_PARAMS); - if (cmd_action == cmd_act_get) { + if (cmd_action == CMD_ACT_GET) { memset(&adapter->sp, 0, sizeof(struct sleep_params)); memset(sp, 0, sizeof(struct cmd_ds_802_11_sleep_params)); sp->action = cpu_to_le16(cmd_action); - } else if (cmd_action == cmd_act_set) { + } else if (cmd_action == CMD_ACT_SET) { sp->action = cpu_to_le16(cmd_action); sp->error = cpu_to_le16(adapter->sp.sp_error); sp->offset = cpu_to_le16(adapter->sp.sp_offset); @@ -159,10 +159,10 @@ static int wlan_cmd_802_11_set_wep(wlan_private * priv, lbs_deb_enter(LBS_DEB_CMD); - cmd->command = cpu_to_le16(cmd_802_11_set_wep); + cmd->command = cpu_to_le16(CMD_802_11_SET_WEP); cmd->size = cpu_to_le16(sizeof(*wep) + S_DS_GEN); - if (cmd_act == cmd_act_add) { + if (cmd_act == CMD_ACT_ADD) { int i; if (!assoc_req) { @@ -171,11 +171,11 @@ static int wlan_cmd_802_11_set_wep(wlan_private * priv, goto done; } - wep->action = cpu_to_le16(cmd_act_add); + wep->action = cpu_to_le16(CMD_ACT_ADD); /* default tx key index */ wep->keyindex = cpu_to_le16((u16)(assoc_req->wep_tx_keyidx & - (u32)cmd_WEP_KEY_INDEX_MASK)); + (u32)CMD_WEP_KEY_INDEX_MASK)); lbs_deb_cmd("Tx key Index: %u\n", le16_to_cpu(wep->keyindex)); @@ -186,13 +186,13 @@ static int wlan_cmd_802_11_set_wep(wlan_private * priv, switch (pkey->len) { case KEY_LEN_WEP_40: wep->keytype[i] = - cpu_to_le16(cmd_type_wep_40_bit); + cpu_to_le16(CMD_TYPE_WEP_40_BIT); memmove(&wep->keymaterial[i], pkey->key, pkey->len); break; case KEY_LEN_WEP_104: wep->keytype[i] = - cpu_to_le16(cmd_type_wep_104_bit); + cpu_to_le16(CMD_TYPE_WEP_104_BIT); memmove(&wep->keymaterial[i], pkey->key, pkey->len); break; @@ -206,13 +206,13 @@ static int wlan_cmd_802_11_set_wep(wlan_private * priv, break; } } - } else if (cmd_act == cmd_act_remove) { + } else if (cmd_act == CMD_ACT_REMOVE) { /* ACT_REMOVE clears _all_ WEP keys */ - wep->action = cpu_to_le16(cmd_act_remove); + wep->action = cpu_to_le16(CMD_ACT_REMOVE); /* default tx key index */ wep->keyindex = cpu_to_le16((u16)(adapter->wep_tx_keyidx & - (u32)cmd_WEP_KEY_INDEX_MASK)); + (u32)CMD_WEP_KEY_INDEX_MASK)); } ret = 0; @@ -232,15 +232,15 @@ static int wlan_cmd_802_11_enable_rsn(wlan_private * priv, lbs_deb_enter(LBS_DEB_CMD); - cmd->command = cpu_to_le16(cmd_802_11_enable_rsn); + cmd->command = cpu_to_le16(CMD_802_11_ENABLE_RSN); cmd->size = cpu_to_le16(sizeof(*penableRSN) + S_DS_GEN); penableRSN->action = cpu_to_le16(cmd_action); - if (cmd_action == cmd_act_set) { + if (cmd_action == CMD_ACT_SET) { if (*enable) - penableRSN->enable = cpu_to_le16(cmd_enable_rsn); + penableRSN->enable = cpu_to_le16(CMD_ENABLE_RSN); else - penableRSN->enable = cpu_to_le16(cmd_disable_rsn); + penableRSN->enable = cpu_to_le16(CMD_DISABLE_RSN); } lbs_deb_leave(LBS_DEB_CMD); @@ -284,10 +284,10 @@ static int wlan_cmd_802_11_key_material(wlan_private * priv, lbs_deb_enter(LBS_DEB_CMD); - cmd->command = cpu_to_le16(cmd_802_11_key_material); + cmd->command = cpu_to_le16(CMD_802_11_KEY_MATERIAL); pkeymaterial->action = cpu_to_le16(cmd_action); - if (cmd_action == cmd_act_get) { + if (cmd_action == CMD_ACT_GET) { cmd->size = cpu_to_le16(S_DS_GEN + sizeof (pkeymaterial->action)); ret = 0; goto done; @@ -323,7 +323,7 @@ static int wlan_cmd_802_11_reset(wlan_private * priv, { struct cmd_ds_802_11_reset *reset = &cmd->params.reset; - cmd->command = cpu_to_le16(cmd_802_11_reset); + cmd->command = cpu_to_le16(CMD_802_11_RESET); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_reset) + S_DS_GEN); reset->action = cpu_to_le16(cmd_action); @@ -333,7 +333,7 @@ static int wlan_cmd_802_11_reset(wlan_private * priv, static int wlan_cmd_802_11_get_log(wlan_private * priv, struct cmd_ds_command *cmd) { - cmd->command = cpu_to_le16(cmd_802_11_get_log); + cmd->command = cpu_to_le16(CMD_802_11_GET_LOG); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_get_log) + S_DS_GEN); @@ -343,7 +343,7 @@ static int wlan_cmd_802_11_get_log(wlan_private * priv, static int wlan_cmd_802_11_get_stat(wlan_private * priv, struct cmd_ds_command *cmd) { - cmd->command = cpu_to_le16(cmd_802_11_get_stat); + cmd->command = cpu_to_le16(CMD_802_11_GET_STAT); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_get_stat) + S_DS_GEN); @@ -363,15 +363,15 @@ static int wlan_cmd_802_11_snmp_mib(wlan_private * priv, lbs_deb_cmd("SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid); - cmd->command = cpu_to_le16(cmd_802_11_snmp_mib); + cmd->command = cpu_to_le16(CMD_802_11_SNMP_MIB); cmd->size = cpu_to_le16(sizeof(*pSNMPMIB) + S_DS_GEN); switch (cmd_oid) { case OID_802_11_INFRASTRUCTURE_MODE: { u8 mode = (u8) (size_t) pdata_buf; - pSNMPMIB->querytype = cpu_to_le16(cmd_act_set); - pSNMPMIB->oid = cpu_to_le16((u16) desired_bsstype_i); + pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET); + pSNMPMIB->oid = cpu_to_le16((u16) DESIRED_BSSTYPE_I); pSNMPMIB->bufsize = sizeof(u8); if (mode == IW_MODE_ADHOC) { ucTemp = SNMP_MIB_VALUE_ADHOC; @@ -389,10 +389,10 @@ static int wlan_cmd_802_11_snmp_mib(wlan_private * priv, { u32 ulTemp; - pSNMPMIB->oid = cpu_to_le16((u16) dot11d_i); + pSNMPMIB->oid = cpu_to_le16((u16) DOT11D_I); - if (cmd_action == cmd_act_set) { - pSNMPMIB->querytype = cmd_act_set; + if (cmd_action == CMD_ACT_SET) { + pSNMPMIB->querytype = CMD_ACT_SET; pSNMPMIB->bufsize = sizeof(u16); ulTemp = *(u32 *)pdata_buf; *((__le16 *)(pSNMPMIB->value)) = @@ -405,12 +405,12 @@ static int wlan_cmd_802_11_snmp_mib(wlan_private * priv, { u32 ulTemp; - pSNMPMIB->oid = cpu_to_le16((u16) fragthresh_i); + pSNMPMIB->oid = cpu_to_le16((u16) FRAGTHRESH_I); - if (cmd_action == cmd_act_get) { - pSNMPMIB->querytype = cpu_to_le16(cmd_act_get); - } else if (cmd_action == cmd_act_set) { - pSNMPMIB->querytype = cpu_to_le16(cmd_act_set); + if (cmd_action == CMD_ACT_GET) { + pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_GET); + } else if (cmd_action == CMD_ACT_SET) { + pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET); pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16)); ulTemp = *((u32 *) pdata_buf); *((__le16 *)(pSNMPMIB->value)) = @@ -425,12 +425,12 @@ static int wlan_cmd_802_11_snmp_mib(wlan_private * priv, { u32 ulTemp; - pSNMPMIB->oid = le16_to_cpu((u16) rtsthresh_i); + pSNMPMIB->oid = le16_to_cpu((u16) RTSTHRESH_I); - if (cmd_action == cmd_act_get) { - pSNMPMIB->querytype = cpu_to_le16(cmd_act_get); - } else if (cmd_action == cmd_act_set) { - pSNMPMIB->querytype = cpu_to_le16(cmd_act_set); + if (cmd_action == CMD_ACT_GET) { + pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_GET); + } else if (cmd_action == CMD_ACT_SET) { + pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET); pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16)); ulTemp = *((u32 *)pdata_buf); *(__le16 *)(pSNMPMIB->value) = @@ -440,12 +440,12 @@ static int wlan_cmd_802_11_snmp_mib(wlan_private * priv, break; } case OID_802_11_TX_RETRYCOUNT: - pSNMPMIB->oid = cpu_to_le16((u16) short_retrylim_i); + pSNMPMIB->oid = cpu_to_le16((u16) SHORT_RETRYLIM_I); - if (cmd_action == cmd_act_get) { - pSNMPMIB->querytype = cpu_to_le16(cmd_act_get); - } else if (cmd_action == cmd_act_set) { - pSNMPMIB->querytype = cpu_to_le16(cmd_act_set); + if (cmd_action == CMD_ACT_GET) { + pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_GET); + } else if (cmd_action == CMD_ACT_SET) { + pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET); pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16)); *((__le16 *)(pSNMPMIB->value)) = cpu_to_le16((u16) adapter->txretrycount); @@ -483,20 +483,20 @@ static int wlan_cmd_802_11_radio_control(wlan_private * priv, cmd->size = cpu_to_le16((sizeof(struct cmd_ds_802_11_radio_control)) + S_DS_GEN); - cmd->command = cpu_to_le16(cmd_802_11_radio_control); + cmd->command = cpu_to_le16(CMD_802_11_RADIO_CONTROL); pradiocontrol->action = cpu_to_le16(cmd_action); switch (adapter->preamble) { - case cmd_type_short_preamble: + case CMD_TYPE_SHORT_PREAMBLE: pradiocontrol->control = cpu_to_le16(SET_SHORT_PREAMBLE); break; - case cmd_type_long_preamble: + case CMD_TYPE_LONG_PREAMBLE: pradiocontrol->control = cpu_to_le16(SET_LONG_PREAMBLE); break; - case cmd_type_auto_preamble: + case CMD_TYPE_AUTO_PREAMBLE: default: pradiocontrol->control = cpu_to_le16(SET_AUTO_PREAMBLE); break; @@ -522,7 +522,7 @@ static int wlan_cmd_802_11_rf_tx_power(wlan_private * priv, cmd->size = cpu_to_le16((sizeof(struct cmd_ds_802_11_rf_tx_power)) + S_DS_GEN); - cmd->command = cpu_to_le16(cmd_802_11_rf_tx_power); + cmd->command = cpu_to_le16(CMD_802_11_RF_TX_POWER); prtp->action = cpu_to_le16(cmd_action); lbs_deb_cmd("RF_TX_POWER_CMD: size:%d cmd:0x%x Act:%d\n", @@ -530,23 +530,23 @@ static int wlan_cmd_802_11_rf_tx_power(wlan_private * priv, le16_to_cpu(prtp->action)); switch (cmd_action) { - case cmd_act_tx_power_opt_get: - prtp->action = cpu_to_le16(cmd_act_get); + case CMD_ACT_TX_POWER_OPT_GET: + prtp->action = cpu_to_le16(CMD_ACT_GET); prtp->currentlevel = 0; break; - case cmd_act_tx_power_opt_set_high: - prtp->action = cpu_to_le16(cmd_act_set); - prtp->currentlevel = cpu_to_le16(cmd_act_tx_power_index_high); + case CMD_ACT_TX_POWER_OPT_SET_HIGH: + prtp->action = cpu_to_le16(CMD_ACT_SET); + prtp->currentlevel = cpu_to_le16(CMD_ACT_TX_POWER_INDEX_HIGH); break; - case cmd_act_tx_power_opt_set_mid: - prtp->action = cpu_to_le16(cmd_act_set); - prtp->currentlevel = cpu_to_le16(cmd_act_tx_power_index_mid); + case CMD_ACT_TX_POWER_OPT_SET_MID: + prtp->action = cpu_to_le16(CMD_ACT_SET); + prtp->currentlevel = cpu_to_le16(CMD_ACT_TX_POWER_INDEX_MID); break; - case cmd_act_tx_power_opt_set_low: - prtp->action = cpu_to_le16(cmd_act_set); + case CMD_ACT_TX_POWER_OPT_SET_LOW: + prtp->action = cpu_to_le16(CMD_ACT_SET); prtp->currentlevel = cpu_to_le16(*((u16 *) pdata_buf)); break; } @@ -561,12 +561,12 @@ static int wlan_cmd_802_11_rf_antenna(wlan_private * priv, { struct cmd_ds_802_11_rf_antenna *rant = &cmd->params.rant; - cmd->command = cpu_to_le16(cmd_802_11_rf_antenna); + cmd->command = cpu_to_le16(CMD_802_11_RF_ANTENNA); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rf_antenna) + S_DS_GEN); rant->action = cpu_to_le16(cmd_action); - if ((cmd_action == cmd_act_set_rx) || (cmd_action == cmd_act_set_tx)) { + if ((cmd_action == CMD_ACT_SET_rx) || (cmd_action == CMD_ACT_SET_tx)) { rant->antennamode = cpu_to_le16((u16) (*(u32 *) pdata_buf)); } @@ -584,7 +584,7 @@ static int wlan_cmd_802_11_rate_adapt_rateset(wlan_private * priv, cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rate_adapt_rateset) + S_DS_GEN); - cmd->command = cpu_to_le16(cmd_802_11_rate_adapt_rateset); + cmd->command = cpu_to_le16(CMD_802_11_RATE_ADAPT_RATESET); lbs_deb_enter(LBS_DEB_CMD); @@ -608,17 +608,17 @@ static int wlan_cmd_802_11_data_rate(wlan_private * priv, cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_data_rate) + S_DS_GEN); - cmd->command = cpu_to_le16(cmd_802_11_data_rate); + cmd->command = cpu_to_le16(CMD_802_11_DATA_RATE); memset(pdatarate, 0, sizeof(struct cmd_ds_802_11_data_rate)); pdatarate->action = cpu_to_le16(cmd_action); - if (cmd_action == cmd_act_set_tx_fix_rate) { + if (cmd_action == CMD_ACT_SET_tx_fix_rate) { pdatarate->datarate[0] = libertas_data_rate_to_index(adapter->datarate); lbs_deb_cmd("Setting FW for fixed rate 0x%02X\n", adapter->datarate); - } else if (cmd_action == cmd_act_set_tx_auto) { + } else if (cmd_action == CMD_ACT_SET_tx_auto) { lbs_deb_cmd("Setting FW for AUTO rate\n"); } @@ -635,7 +635,7 @@ static int wlan_cmd_mac_multicast_adr(wlan_private * priv, cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_multicast_adr) + S_DS_GEN); - cmd->command = cpu_to_le16(cmd_mac_multicast_adr); + cmd->command = cpu_to_le16(CMD_MAC_MULTICAST_ADR); pMCastAdr->action = cpu_to_le16(cmd_action); pMCastAdr->nr_of_adrs = @@ -652,11 +652,11 @@ static int wlan_cmd_802_11_rf_channel(wlan_private * priv, { struct cmd_ds_802_11_rf_channel *rfchan = &cmd->params.rfchannel; - cmd->command = cpu_to_le16(cmd_802_11_rf_channel); + cmd->command = cpu_to_le16(CMD_802_11_RF_CHANNEL); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rf_channel) + S_DS_GEN); - if (option == cmd_opt_802_11_rf_channel_set) { + if (option == CMD_OPT_802_11_RF_CHANNEL_SET) { rfchan->currentchannel = cpu_to_le16(*((u16 *) pdata_buf)); } @@ -670,7 +670,7 @@ static int wlan_cmd_802_11_rssi(wlan_private * priv, { wlan_adapter *adapter = priv->adapter; - cmd->command = cpu_to_le16(cmd_802_11_rssi); + cmd->command = cpu_to_le16(CMD_802_11_RSSI); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rssi) + S_DS_GEN); cmd->params.rssi.N = cpu_to_le16(priv->adapter->bcn_avg_factor); @@ -696,7 +696,7 @@ static int wlan_cmd_reg_access(wlan_private * priv, offval = (struct wlan_offset_value *)pdata_buf; switch (cmdptr->command) { - case cmd_mac_reg_access: + case CMD_MAC_REG_ACCESS: { struct cmd_ds_mac_reg_access *macreg; @@ -714,7 +714,7 @@ static int wlan_cmd_reg_access(wlan_private * priv, break; } - case cmd_bbp_reg_access: + case CMD_BBP_REG_ACCESS: { struct cmd_ds_bbp_reg_access *bbpreg; @@ -733,7 +733,7 @@ static int wlan_cmd_reg_access(wlan_private * priv, break; } - case cmd_rf_reg_access: + case CMD_RF_REG_ACCESS: { struct cmd_ds_rf_reg_access *rfreg; @@ -766,14 +766,14 @@ static int wlan_cmd_802_11_mac_address(wlan_private * priv, { wlan_adapter *adapter = priv->adapter; - cmd->command = cpu_to_le16(cmd_802_11_mac_address); + cmd->command = cpu_to_le16(CMD_802_11_MAC_ADDRESS); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_mac_address) + S_DS_GEN); cmd->result = 0; cmd->params.macadd.action = cpu_to_le16(cmd_action); - if (cmd_action == cmd_act_set) { + if (cmd_action == CMD_ACT_SET) { memcpy(cmd->params.macadd.macadd, adapter->current_addr, ETH_ALEN); lbs_dbg_hex("SET_CMD: MAC ADDRESS-", adapter->current_addr, 6); @@ -790,7 +790,7 @@ static int wlan_cmd_802_11_eeprom_access(wlan_private * priv, lbs_deb_enter(LBS_DEB_CMD); - cmd->command = cpu_to_le16(cmd_802_11_eeprom_access); + cmd->command = cpu_to_le16(CMD_802_11_EEPROM_ACCESS); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_eeprom_access) + S_DS_GEN); cmd->result = 0; @@ -810,29 +810,29 @@ static int wlan_cmd_bt_access(wlan_private * priv, struct cmd_ds_bt_access *bt_access = &cmd->params.bt; lbs_deb_cmd("BT CMD(%d)\n", cmd_action); - cmd->command = cpu_to_le16(cmd_bt_access); + cmd->command = cpu_to_le16(CMD_BT_ACCESS); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_bt_access) + S_DS_GEN); cmd->result = 0; bt_access->action = cpu_to_le16(cmd_action); switch (cmd_action) { - case cmd_act_bt_access_add: + case CMD_ACT_BT_ACCESS_ADD: memcpy(bt_access->addr1, pdata_buf, 2 * ETH_ALEN); lbs_dbg_hex("BT_ADD: blinded mac address-", bt_access->addr1, 6); break; - case cmd_act_bt_access_del: + case CMD_ACT_BT_ACCESS_DEL: memcpy(bt_access->addr1, pdata_buf, 1 * ETH_ALEN); lbs_dbg_hex("BT_DEL: blinded mac address-", bt_access->addr1, 6); break; - case cmd_act_bt_access_list: + case CMD_ACT_BT_ACCESS_LIST: bt_access->id = cpu_to_le32(*(u32 *) pdata_buf); break; - case cmd_act_bt_access_reset: + case CMD_ACT_BT_ACCESS_RESET: break; - case cmd_act_bt_access_set_invert: + case CMD_ACT_BT_ACCESS_SET_INVERT: bt_access->id = cpu_to_le32(*(u32 *) pdata_buf); break; - case cmd_act_bt_access_get_invert: + case CMD_ACT_BT_ACCESS_GET_INVERT: break; default: break; @@ -847,7 +847,7 @@ static int wlan_cmd_fwt_access(wlan_private * priv, struct cmd_ds_fwt_access *fwt_access = &cmd->params.fwt; lbs_deb_cmd("FWT CMD(%d)\n", cmd_action); - cmd->command = cpu_to_le16(cmd_fwt_access); + cmd->command = cpu_to_le16(CMD_FWT_ACCESS); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access) + S_DS_GEN); cmd->result = 0; @@ -868,7 +868,7 @@ static int wlan_cmd_mesh_access(wlan_private * priv, struct cmd_ds_mesh_access *mesh_access = &cmd->params.mesh; lbs_deb_cmd("FWT CMD(%d)\n", cmd_action); - cmd->command = cpu_to_le16(cmd_mesh_access); + cmd->command = cpu_to_le16(CMD_MESH_ACCESS); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mesh_access) + S_DS_GEN); cmd->result = 0; @@ -901,9 +901,9 @@ void libertas_queue_cmd(wlan_adapter * adapter, struct cmd_ctrl_node *cmdnode, u } /* Exit_PS command needs to be queued in the header always. */ - if (cmdptr->command == cmd_802_11_ps_mode) { + if (cmdptr->command == CMD_802_11_PS_MODE) { struct cmd_ds_802_11_ps_mode *psm = &cmdptr->params.psmode; - if (psm->action == cpu_to_le16(cmd_subcmd_exit_ps)) { + if (psm->action == cpu_to_le16(CMD_SUBCMD_EXIT_PS)) { if (adapter->psstate != PS_STATE_FULL_POWER) addtail = 0; } @@ -1000,8 +1000,8 @@ static int DownloadcommandToStation(wlan_private * priv, lbs_dbg_hex("DNLD_CMD: command", cmdnode->bufvirtualaddr, cmdsize); /* Setup the timer after transmit command */ - if (command == cmd_802_11_scan || command == cmd_802_11_authenticate - || command == cmd_802_11_associate) + if (command == CMD_802_11_SCAN || command == CMD_802_11_AUTHENTICATE + || command == CMD_802_11_ASSOCIATE) mod_timer(&adapter->command_timer, jiffies + (10*HZ)); else mod_timer(&adapter->command_timer, jiffies + (5*HZ)); @@ -1020,7 +1020,7 @@ static int wlan_cmd_mac_control(wlan_private * priv, lbs_deb_enter(LBS_DEB_CMD); - cmd->command = cpu_to_le16(cmd_mac_control); + cmd->command = cpu_to_le16(CMD_MAC_CONTROL); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_control) + S_DS_GEN); mac->action = cpu_to_le16(priv->adapter->currentpacketfilter); @@ -1064,9 +1064,9 @@ int libertas_set_radio_control(wlan_private * priv) lbs_deb_enter(LBS_DEB_CMD); ret = libertas_prepare_and_send_command(priv, - cmd_802_11_radio_control, - cmd_act_set, - cmd_option_waitforrsp, 0, NULL); + CMD_802_11_RADIO_CONTROL, + CMD_ACT_SET, + CMD_OPTION_WAITFORRSP, 0, NULL); lbs_deb_cmd("RADIO_SET: on or off: 0x%X, preamble = 0x%X\n", priv->adapter->radioon, priv->adapter->preamble); @@ -1086,7 +1086,7 @@ int libertas_set_mac_packet_filter(wlan_private * priv) /* Send MAC control command to station */ ret = libertas_prepare_and_send_command(priv, - cmd_mac_control, 0, 0, 0, NULL); + CMD_MAC_CONTROL, 0, 0, 0, NULL); lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; @@ -1161,136 +1161,136 @@ int libertas_prepare_and_send_command(wlan_private * priv, cmdptr->result = 0; switch (cmd_no) { - case cmd_get_hw_spec: + case CMD_GET_HW_SPEC: ret = wlan_cmd_hw_spec(priv, cmdptr); break; - case cmd_802_11_ps_mode: + case CMD_802_11_PS_MODE: ret = wlan_cmd_802_11_ps_mode(priv, cmdptr, cmd_action); break; - case cmd_802_11_scan: + case CMD_802_11_SCAN: ret = libertas_cmd_80211_scan(priv, cmdptr, pdata_buf); break; - case cmd_mac_control: + case CMD_MAC_CONTROL: ret = wlan_cmd_mac_control(priv, cmdptr); break; - case cmd_802_11_associate: - case cmd_802_11_reassociate: + case CMD_802_11_ASSOCIATE: + case CMD_802_11_REASSOCIATE: ret = libertas_cmd_80211_associate(priv, cmdptr, pdata_buf); break; - case cmd_802_11_deauthenticate: + case CMD_802_11_DEAUTHENTICATE: ret = libertas_cmd_80211_deauthenticate(priv, cmdptr); break; - case cmd_802_11_set_wep: + case CMD_802_11_SET_WEP: ret = wlan_cmd_802_11_set_wep(priv, cmdptr, cmd_action, pdata_buf); break; - case cmd_802_11_ad_hoc_start: + case CMD_802_11_AD_HOC_START: ret = libertas_cmd_80211_ad_hoc_start(priv, cmdptr, pdata_buf); break; - case cmd_code_dnld: + case CMD_CODE_DNLD: break; - case cmd_802_11_reset: + case CMD_802_11_RESET: ret = wlan_cmd_802_11_reset(priv, cmdptr, cmd_action); break; - case cmd_802_11_get_log: + case CMD_802_11_GET_LOG: ret = wlan_cmd_802_11_get_log(priv, cmdptr); break; - case cmd_802_11_authenticate: + case CMD_802_11_AUTHENTICATE: ret = libertas_cmd_80211_authenticate(priv, cmdptr, pdata_buf); break; - case cmd_802_11_get_stat: + case CMD_802_11_GET_STAT: ret = wlan_cmd_802_11_get_stat(priv, cmdptr); break; - case cmd_802_11_snmp_mib: + case CMD_802_11_SNMP_MIB: ret = wlan_cmd_802_11_snmp_mib(priv, cmdptr, cmd_action, cmd_oid, pdata_buf); break; - case cmd_mac_reg_access: - case cmd_bbp_reg_access: - case cmd_rf_reg_access: + case CMD_MAC_REG_ACCESS: + case CMD_BBP_REG_ACCESS: + case CMD_RF_REG_ACCESS: ret = wlan_cmd_reg_access(priv, cmdptr, cmd_action, pdata_buf); break; - case cmd_802_11_rf_channel: + case CMD_802_11_RF_CHANNEL: ret = wlan_cmd_802_11_rf_channel(priv, cmdptr, cmd_action, pdata_buf); break; - case cmd_802_11_rf_tx_power: + case CMD_802_11_RF_TX_POWER: ret = wlan_cmd_802_11_rf_tx_power(priv, cmdptr, cmd_action, pdata_buf); break; - case cmd_802_11_radio_control: + case CMD_802_11_RADIO_CONTROL: ret = wlan_cmd_802_11_radio_control(priv, cmdptr, cmd_action); break; - case cmd_802_11_rf_antenna: + case CMD_802_11_RF_ANTENNA: ret = wlan_cmd_802_11_rf_antenna(priv, cmdptr, cmd_action, pdata_buf); break; - case cmd_802_11_data_rate: + case CMD_802_11_DATA_RATE: ret = wlan_cmd_802_11_data_rate(priv, cmdptr, cmd_action); break; - case cmd_802_11_rate_adapt_rateset: + case CMD_802_11_RATE_ADAPT_RATESET: ret = wlan_cmd_802_11_rate_adapt_rateset(priv, cmdptr, cmd_action); break; - case cmd_mac_multicast_adr: + case CMD_MAC_MULTICAST_ADR: ret = wlan_cmd_mac_multicast_adr(priv, cmdptr, cmd_action); break; - case cmd_802_11_ad_hoc_join: + case CMD_802_11_AD_HOC_JOIN: ret = libertas_cmd_80211_ad_hoc_join(priv, cmdptr, pdata_buf); break; - case cmd_802_11_rssi: + case CMD_802_11_RSSI: ret = wlan_cmd_802_11_rssi(priv, cmdptr); break; - case cmd_802_11_ad_hoc_stop: + case CMD_802_11_AD_HOC_STOP: ret = libertas_cmd_80211_ad_hoc_stop(priv, cmdptr); break; - case cmd_802_11_enable_rsn: + case CMD_802_11_ENABLE_RSN: ret = wlan_cmd_802_11_enable_rsn(priv, cmdptr, cmd_action, pdata_buf); break; - case cmd_802_11_key_material: + case CMD_802_11_KEY_MATERIAL: ret = wlan_cmd_802_11_key_material(priv, cmdptr, cmd_action, cmd_oid, pdata_buf); break; - case cmd_802_11_pairwise_tsc: + case CMD_802_11_PAIRWISE_TSC: break; - case cmd_802_11_group_tsc: + case CMD_802_11_GROUP_TSC: break; - case cmd_802_11_mac_address: + case CMD_802_11_MAC_ADDRESS: ret = wlan_cmd_802_11_mac_address(priv, cmdptr, cmd_action); break; - case cmd_802_11_eeprom_access: + case CMD_802_11_EEPROM_ACCESS: ret = wlan_cmd_802_11_eeprom_access(priv, cmdptr, cmd_action, pdata_buf); break; - case cmd_802_11_set_afc: - case cmd_802_11_get_afc: + case CMD_802_11_SET_AFC: + case CMD_802_11_GET_AFC: cmdptr->command = cpu_to_le16(cmd_no); cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_afc) + @@ -1302,22 +1302,22 @@ int libertas_prepare_and_send_command(wlan_private * priv, ret = 0; goto done; - case cmd_802_11d_domain_info: + case CMD_802_11D_DOMAIN_INFO: ret = libertas_cmd_802_11d_domain_info(priv, cmdptr, cmd_no, cmd_action); break; - case cmd_802_11_sleep_params: + case CMD_802_11_SLEEP_PARAMS: ret = wlan_cmd_802_11_sleep_params(priv, cmdptr, cmd_action); break; - case cmd_802_11_inactivity_timeout: + case CMD_802_11_INACTIVITY_TIMEOUT: ret = wlan_cmd_802_11_inactivity_timeout(priv, cmdptr, cmd_action, pdata_buf); libertas_set_cmd_ctrl_node(priv, cmdnode, 0, 0, pdata_buf); break; - case cmd_802_11_tpc_cfg: - cmdptr->command = cpu_to_le16(cmd_802_11_tpc_cfg); + case CMD_802_11_TPC_CFG: + cmdptr->command = cpu_to_le16(CMD_802_11_TPC_CFG); cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_tpc_cfg) + S_DS_GEN); @@ -1327,7 +1327,7 @@ int libertas_prepare_and_send_command(wlan_private * priv, ret = 0; break; - case cmd_802_11_led_gpio_ctrl: + case CMD_802_11_LED_GPIO_CTRL: { struct mrvlietypes_ledgpio *gpio = (struct mrvlietypes_ledgpio*) @@ -1338,7 +1338,7 @@ int libertas_prepare_and_send_command(wlan_private * priv, sizeof(struct cmd_ds_802_11_led_ctrl)); cmdptr->command = - cpu_to_le16(cmd_802_11_led_gpio_ctrl); + cpu_to_le16(CMD_802_11_LED_GPIO_CTRL); #define ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN 8 cmdptr->size = @@ -1349,8 +1349,8 @@ int libertas_prepare_and_send_command(wlan_private * priv, ret = 0; break; } - case cmd_802_11_pwr_cfg: - cmdptr->command = cpu_to_le16(cmd_802_11_pwr_cfg); + case CMD_802_11_PWR_CFG: + cmdptr->command = cpu_to_le16(CMD_802_11_PWR_CFG); cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_pwr_cfg) + S_DS_GEN); @@ -1359,26 +1359,26 @@ int libertas_prepare_and_send_command(wlan_private * priv, ret = 0; break; - case cmd_bt_access: + case CMD_BT_ACCESS: ret = wlan_cmd_bt_access(priv, cmdptr, cmd_action, pdata_buf); break; - case cmd_fwt_access: + case CMD_FWT_ACCESS: ret = wlan_cmd_fwt_access(priv, cmdptr, cmd_action, pdata_buf); break; - case cmd_mesh_access: + case CMD_MESH_ACCESS: ret = wlan_cmd_mesh_access(priv, cmdptr, cmd_action, pdata_buf); break; - case cmd_get_tsf: - cmdptr->command = cpu_to_le16(cmd_get_tsf); + case CMD_GET_TSF: + cmdptr->command = cpu_to_le16(CMD_GET_TSF); cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_get_tsf) + S_DS_GEN); ret = 0; break; - case cmd_802_11_tx_rate_query: - cmdptr->command = cpu_to_le16(cmd_802_11_tx_rate_query); + case CMD_802_11_TX_RATE_QUERY: + cmdptr->command = cpu_to_le16(CMD_802_11_TX_RATE_QUERY); cmdptr->size = cpu_to_le16(sizeof(struct cmd_tx_rate_query) + S_DS_GEN); adapter->txrate = 0; @@ -1404,7 +1404,7 @@ int libertas_prepare_and_send_command(wlan_private * priv, adapter->nr_cmd_pending++; wake_up_interruptible(&priv->mainthread.waitq); - if (wait_option & cmd_option_waitforrsp) { + if (wait_option & CMD_OPTION_WAITFORRSP) { lbs_deb_cmd("PREP_CMD: Wait for CMD response\n"); might_sleep(); wait_event_interruptible(cmdnode->cmdwait_q, @@ -1680,7 +1680,7 @@ int libertas_execute_next_command(wlan_private * priv) * immediately. */ if (cmdptr->command != - cpu_to_le16(cmd_802_11_ps_mode)) { + cpu_to_le16(CMD_802_11_PS_MODE)) { /* Prepare to send Exit PS, * this non PS command will be sent later */ if ((adapter->psstate == PS_STATE_SLEEP) @@ -1706,7 +1706,7 @@ int libertas_execute_next_command(wlan_private * priv) "EXEC_NEXT_CMD: PS cmd- action=0x%x\n", psm->action); if (psm->action != - cpu_to_le16(cmd_subcmd_exit_ps)) { + cpu_to_le16(CMD_SUBCMD_EXIT_PS)) { lbs_deb_cmd( "EXEC_NEXT_CMD: Ignore Enter PS cmd\n"); list_del((struct list_head *)cmdnode); @@ -1741,9 +1741,9 @@ int libertas_execute_next_command(wlan_private * priv) * check if in power save mode, if yes, put the device back * to PS mode */ - if ((adapter->psmode != wlan802_11powermodecam) && + if ((adapter->psmode != WLAN802_11POWERMODECAM) && (adapter->psstate == PS_STATE_FULL_POWER) && - (adapter->connect_status == libertas_connected)) { + (adapter->connect_status == LIBERTAS_CONNECTED)) { if (adapter->secinfo.WPAenabled || adapter->secinfo.WPA2enabled) { /* check for valid WPA group keys */ @@ -1845,8 +1845,8 @@ void libertas_ps_sleep(wlan_private * priv, int wait_option) * Remove this check if it is to be supported in IBSS mode also */ - libertas_prepare_and_send_command(priv, cmd_802_11_ps_mode, - cmd_subcmd_enter_ps, wait_option, 0, NULL); + libertas_prepare_and_send_command(priv, CMD_802_11_PS_MODE, + CMD_SUBCMD_ENTER_PS, wait_option, 0, NULL); lbs_deb_leave(LBS_DEB_CMD); } @@ -1864,12 +1864,12 @@ void libertas_ps_wakeup(wlan_private * priv, int wait_option) lbs_deb_enter(LBS_DEB_CMD); - Localpsmode = cpu_to_le32(wlan802_11powermodecam); + Localpsmode = cpu_to_le32(WLAN802_11POWERMODECAM); - lbs_deb_cmd("Exit_PS: Localpsmode = %d\n", wlan802_11powermodecam); + lbs_deb_cmd("Exit_PS: Localpsmode = %d\n", WLAN802_11POWERMODECAM); - libertas_prepare_and_send_command(priv, cmd_802_11_ps_mode, - cmd_subcmd_exit_ps, + libertas_prepare_and_send_command(priv, CMD_802_11_PS_MODE, + CMD_SUBCMD_EXIT_PS, wait_option, 0, &Localpsmode); lbs_deb_leave(LBS_DEB_CMD); diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 89bd43c2efa..4c15071984b 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -28,7 +28,7 @@ void libertas_mac_event_disconnected(wlan_private * priv) wlan_adapter *adapter = priv->adapter; union iwreq_data wrqu; - if (adapter->connect_status != libertas_connected) + if (adapter->connect_status != LIBERTAS_CONNECTED) return; lbs_deb_cmd("Handles disconnect event.\n"); @@ -69,7 +69,7 @@ void libertas_mac_event_disconnected(wlan_private * priv) escape_essid(adapter->prev_ssid, adapter->prev_ssid_len), adapter->prev_ssid_len); - adapter->connect_status = libertas_disconnected; + adapter->connect_status = LIBERTAS_DISCONNECTED; /* Save previous SSID and BSSID for possible reassociation */ memcpy(&adapter->prev_ssid, &adapter->curbssparams.ssid, @@ -124,7 +124,7 @@ static int wlan_ret_reg_access(wlan_private * priv, lbs_deb_enter(LBS_DEB_CMD); switch (type) { - case cmd_ret_mac_reg_access: + case CMD_RET_MAC_REG_ACCESS: { struct cmd_ds_mac_reg_access *reg = &resp->params.macreg; @@ -133,7 +133,7 @@ static int wlan_ret_reg_access(wlan_private * priv, break; } - case cmd_ret_bbp_reg_access: + case CMD_RET_BBP_REG_ACCESS: { struct cmd_ds_bbp_reg_access *reg = &resp->params.bbpreg; @@ -142,7 +142,7 @@ static int wlan_ret_reg_access(wlan_private * priv, break; } - case cmd_ret_rf_reg_access: + case CMD_RET_RF_REG_ACCESS: { struct cmd_ds_rf_reg_access *reg = &resp->params.rfreg; @@ -274,21 +274,21 @@ static int wlan_ret_802_11_snmp_mib(wlan_private * priv, querytype); lbs_deb_cmd("SNMP_RESP: Buf size = %x\n", le16_to_cpu(smib->bufsize)); - if (querytype == cmd_act_get) { + if (querytype == CMD_ACT_GET) { switch (oid) { - case fragthresh_i: + case FRAGTHRESH_I: priv->adapter->fragthsd = le16_to_cpu(*((__le16 *)(smib->value))); lbs_deb_cmd("SNMP_RESP: fragthsd =%u\n", priv->adapter->fragthsd); break; - case rtsthresh_i: + case RTSTHRESH_I: priv->adapter->rtsthsd = le16_to_cpu(*((__le16 *)(smib->value))); lbs_deb_cmd("SNMP_RESP: rtsthsd =%u\n", priv->adapter->rtsthsd); break; - case short_retrylim_i: + case SHORT_RETRYLIM_I: priv->adapter->txretrycount = le16_to_cpu(*((__le16 *)(smib->value))); lbs_deb_cmd("SNMP_RESP: txretrycount =%u\n", @@ -314,7 +314,7 @@ static int wlan_ret_802_11_key_material(wlan_private * priv, lbs_deb_enter(LBS_DEB_CMD); /* Copy the returned key to driver private data */ - if (action == cmd_act_get) { + if (action == CMD_ACT_GET) { u8 * buf_ptr = (u8 *) &pkeymaterial->keyParamSet; u8 * resp_end = (u8 *) (resp + le16_to_cpu(resp->size)); @@ -396,10 +396,10 @@ static int wlan_ret_802_11_rf_antenna(wlan_private * priv, wlan_adapter *adapter = priv->adapter; u16 action = le16_to_cpu(pAntenna->action); - if (action == cmd_act_get_rx) + if (action == CMD_ACT_GET_rx) adapter->rxantennamode = le16_to_cpu(pAntenna->antennamode); - if (action == cmd_act_get_tx) + if (action == CMD_ACT_GET_tx) adapter->txantennamode = le16_to_cpu(pAntenna->antennamode); lbs_deb_cmd("RF_ANT_RESP: action = 0x%x, mode = 0x%04x\n", @@ -416,7 +416,7 @@ static int wlan_ret_802_11_rate_adapt_rateset(wlan_private * priv, lbs_deb_enter(LBS_DEB_CMD); - if (rates->action == cmd_act_get) { + if (rates->action == CMD_ACT_GET) { adapter->enablehwauto = le16_to_cpu(rates->enablehwauto); adapter->ratebitmap = le16_to_cpu(rates->bitmap); } @@ -438,7 +438,7 @@ static int wlan_ret_802_11_data_rate(wlan_private * priv, (u8 *) pdatarate, sizeof(struct cmd_ds_802_11_data_rate)); dot11datarate = pdatarate->datarate[0]; - if (pdatarate->action == cpu_to_le16(cmd_act_get_tx_rate)) { + if (pdatarate->action == cpu_to_le16(CMD_ACT_GET_tx_rate)) { memcpy(adapter->libertas_supported_rates, pdatarate->datarate, sizeof(adapter->libertas_supported_rates)); } @@ -458,7 +458,7 @@ static int wlan_ret_802_11_rf_channel(wlan_private * priv, lbs_deb_enter(LBS_DEB_CMD); - if (action == cmd_opt_802_11_rf_channel_get + if (action == CMD_OPT_802_11_RF_CHANNEL_GET && adapter->curbssparams.channel != newchannel) { lbs_deb_cmd("channel Switch: %d to %d\n", adapter->curbssparams.channel, newchannel); @@ -547,7 +547,7 @@ static int libertas_ret_802_11_enable_rsn(wlan_private * priv, lbs_deb_enter(LBS_DEB_CMD); - if (enable_rsn->action == cpu_to_le16(cmd_act_get)) { + if (enable_rsn->action == cpu_to_le16(CMD_ACT_GET)) { if (pdata_buf) *pdata_buf = (u32) le16_to_cpu(enable_rsn->enable); } @@ -565,134 +565,134 @@ static inline int handle_cmd_response(u16 respcmd, wlan_adapter *adapter = priv->adapter; switch (respcmd) { - case cmd_ret_mac_reg_access: - case cmd_ret_bbp_reg_access: - case cmd_ret_rf_reg_access: + case CMD_RET_MAC_REG_ACCESS: + case CMD_RET_BBP_REG_ACCESS: + case CMD_RET_RF_REG_ACCESS: ret = wlan_ret_reg_access(priv, respcmd, resp); break; - case cmd_ret_hw_spec_info: + case CMD_RET_HW_SPEC_INFO: ret = wlan_ret_get_hw_spec(priv, resp); break; - case cmd_ret_802_11_scan: + case CMD_RET_802_11_SCAN: ret = libertas_ret_80211_scan(priv, resp); break; - case cmd_ret_802_11_get_log: + case CMD_RET_802_11_GET_LOG: ret = wlan_ret_get_log(priv, resp); break; - case cmd_ret_802_11_associate: - case cmd_ret_802_11_reassociate: + case CMD_RET_802_11_ASSOCIATE: + case CMD_RET_802_11_REASSOCIATE: ret = libertas_ret_80211_associate(priv, resp); break; - case cmd_ret_802_11_disassociate: - case cmd_ret_802_11_deauthenticate: + case CMD_RET_802_11_DISASSOCIATE: + case CMD_RET_802_11_DEAUTHENTICATE: ret = libertas_ret_80211_disassociate(priv, resp); break; - case cmd_ret_802_11_ad_hoc_start: - case cmd_ret_802_11_ad_hoc_join: + case CMD_RET_802_11_AD_HOC_START: + case CMD_RET_802_11_AD_HOC_JOIN: ret = libertas_ret_80211_ad_hoc_start(priv, resp); break; - case cmd_ret_802_11_stat: + case CMD_RET_802_11_STAT: ret = wlan_ret_802_11_stat(priv, resp); break; - case cmd_ret_802_11_snmp_mib: + case CMD_RET_802_11_SNMP_MIB: ret = wlan_ret_802_11_snmp_mib(priv, resp); break; - case cmd_ret_802_11_rf_tx_power: + case CMD_RET_802_11_RF_TX_POWER: ret = wlan_ret_802_11_rf_tx_power(priv, resp); break; - case cmd_ret_802_11_set_afc: - case cmd_ret_802_11_get_afc: + case CMD_RET_802_11_SET_AFC: + case CMD_RET_802_11_GET_AFC: spin_lock_irqsave(&adapter->driver_lock, flags); memmove(adapter->cur_cmd->pdata_buf, &resp->params.afc, sizeof(struct cmd_ds_802_11_afc)); spin_unlock_irqrestore(&adapter->driver_lock, flags); break; - case cmd_ret_802_11_rf_antenna: + case CMD_RET_802_11_RF_ANTENNA: ret = wlan_ret_802_11_rf_antenna(priv, resp); break; - case cmd_ret_mac_multicast_adr: - case cmd_ret_mac_control: - case cmd_ret_802_11_set_wep: - case cmd_ret_802_11_reset: - case cmd_ret_802_11_authenticate: - case cmd_ret_802_11_radio_control: - case cmd_ret_802_11_beacon_stop: + case CMD_RET_MAC_MULTICAST_ADR: + case CMD_RET_MAC_CONTROL: + case CMD_RET_802_11_SET_WEP: + case CMD_RET_802_11_RESET: + case CMD_RET_802_11_AUTHENTICATE: + case CMD_RET_802_11_RADIO_CONTROL: + case CMD_RET_802_11_BEACON_STOP: break; - case cmd_ret_802_11_enable_rsn: + case CMD_RET_802_11_ENABLE_RSN: ret = libertas_ret_802_11_enable_rsn(priv, resp); break; - case cmd_ret_802_11_data_rate: + case CMD_RET_802_11_DATA_RATE: ret = wlan_ret_802_11_data_rate(priv, resp); break; - case cmd_ret_802_11_rate_adapt_rateset: + case CMD_RET_802_11_RATE_ADAPT_RATESET: ret = wlan_ret_802_11_rate_adapt_rateset(priv, resp); break; - case cmd_ret_802_11_rf_channel: + case CMD_RET_802_11_RF_CHANNEL: ret = wlan_ret_802_11_rf_channel(priv, resp); break; - case cmd_ret_802_11_rssi: + case CMD_RET_802_11_RSSI: ret = wlan_ret_802_11_rssi(priv, resp); break; - case cmd_ret_802_11_mac_address: + case CMD_RET_802_11_MAC_ADDRESS: ret = wlan_ret_802_11_mac_address(priv, resp); break; - case cmd_ret_802_11_ad_hoc_stop: + case CMD_RET_802_11_AD_HOC_STOP: ret = libertas_ret_80211_ad_hoc_stop(priv, resp); break; - case cmd_ret_802_11_key_material: + case CMD_RET_802_11_KEY_MATERIAL: lbs_deb_cmd("CMD_RESP: KEY_MATERIAL command response\n"); ret = wlan_ret_802_11_key_material(priv, resp); break; - case cmd_ret_802_11_eeprom_access: + case CMD_RET_802_11_EEPROM_ACCESS: ret = wlan_ret_802_11_eeprom_access(priv, resp); break; - case cmd_ret_802_11d_domain_info: + case CMD_RET_802_11D_DOMAIN_INFO: ret = libertas_ret_802_11d_domain_info(priv, resp); break; - case cmd_ret_802_11_sleep_params: + case CMD_RET_802_11_SLEEP_PARAMS: ret = wlan_ret_802_11_sleep_params(priv, resp); break; - case cmd_ret_802_11_inactivity_timeout: + case CMD_RET_802_11_INACTIVITY_TIMEOUT: spin_lock_irqsave(&adapter->driver_lock, flags); *((u16 *) adapter->cur_cmd->pdata_buf) = le16_to_cpu(resp->params.inactivity_timeout.timeout); spin_unlock_irqrestore(&adapter->driver_lock, flags); break; - case cmd_ret_802_11_tpc_cfg: + case CMD_RET_802_11_TPC_CFG: spin_lock_irqsave(&adapter->driver_lock, flags); memmove(adapter->cur_cmd->pdata_buf, &resp->params.tpccfg, sizeof(struct cmd_ds_802_11_tpc_cfg)); spin_unlock_irqrestore(&adapter->driver_lock, flags); break; - case cmd_ret_802_11_led_gpio_ctrl: + case CMD_RET_802_11_LED_GPIO_CTRL: spin_lock_irqsave(&adapter->driver_lock, flags); memmove(adapter->cur_cmd->pdata_buf, &resp->params.ledgpio, sizeof(struct cmd_ds_802_11_led_ctrl)); spin_unlock_irqrestore(&adapter->driver_lock, flags); break; - case cmd_ret_802_11_pwr_cfg: + case CMD_RET_802_11_PWR_CFG: spin_lock_irqsave(&adapter->driver_lock, flags); memmove(adapter->cur_cmd->pdata_buf, &resp->params.pwrcfg, sizeof(struct cmd_ds_802_11_pwr_cfg)); @@ -700,32 +700,32 @@ static inline int handle_cmd_response(u16 respcmd, break; - case cmd_ret_get_tsf: + case CMD_RET_GET_TSF: spin_lock_irqsave(&adapter->driver_lock, flags); memcpy(priv->adapter->cur_cmd->pdata_buf, &resp->params.gettsf.tsfvalue, sizeof(u64)); spin_unlock_irqrestore(&adapter->driver_lock, flags); break; - case cmd_ret_bt_access: + case CMD_RET_BT_ACCESS: spin_lock_irqsave(&adapter->driver_lock, flags); if (adapter->cur_cmd->pdata_buf) memcpy(adapter->cur_cmd->pdata_buf, &resp->params.bt.addr1, 2 * ETH_ALEN); spin_unlock_irqrestore(&adapter->driver_lock, flags); break; - case cmd_ret_fwt_access: + case CMD_RET_FWT_ACCESS: spin_lock_irqsave(&adapter->driver_lock, flags); if (adapter->cur_cmd->pdata_buf) memcpy(adapter->cur_cmd->pdata_buf, &resp->params.fwt, sizeof(resp->params.fwt)); spin_unlock_irqrestore(&adapter->driver_lock, flags); break; - case cmd_ret_mesh_access: + case CMD_RET_MESH_ACCESS: if (adapter->cur_cmd->pdata_buf) memcpy(adapter->cur_cmd->pdata_buf, &resp->params.mesh, sizeof(resp->params.mesh)); break; - case cmd_rte_802_11_tx_rate_query: + case CMD_RTE_802_11_TX_RATE_QUERY: priv->adapter->txrate = resp->params.txrate.txrate; break; default: @@ -787,7 +787,7 @@ int libertas_process_rx_command(wlan_private * priv) /* Store the response code to cur_cmd_retcode. */ adapter->cur_cmd_retcode = result;; - if (respcmd == cmd_ret_802_11_ps_mode) { + if (respcmd == CMD_RET_802_11_PS_MODE) { struct cmd_ds_802_11_ps_mode *psmode = &resp->params.psmode; u16 action = le16_to_cpu(psmode->action); @@ -804,14 +804,14 @@ int libertas_process_rx_command(wlan_private * priv) * libertas_execute_next_command(). */ if (adapter->mode == IW_MODE_ADHOC && - action == cmd_subcmd_enter_ps) - adapter->psmode = wlan802_11powermodecam; - } else if (action == cmd_subcmd_enter_ps) { + action == CMD_SUBCMD_ENTER_PS) + adapter->psmode = WLAN802_11POWERMODECAM; + } else if (action == CMD_SUBCMD_ENTER_PS) { adapter->needtowakeup = 0; adapter->psstate = PS_STATE_AWAKE; lbs_deb_cmd("CMD_RESP: Enter_PS command response\n"); - if (adapter->connect_status != libertas_connected) { + if (adapter->connect_status != LIBERTAS_CONNECTED) { /* * When Deauth Event received before Enter_PS command * response, We need to wake up the firmware. @@ -825,7 +825,7 @@ int libertas_process_rx_command(wlan_private * priv) mutex_lock(&adapter->lock); spin_lock_irqsave(&adapter->driver_lock, flags); } - } else if (action == cmd_subcmd_exit_ps) { + } else if (action == CMD_SUBCMD_EXIT_PS) { adapter->needtowakeup = 0; adapter->psstate = PS_STATE_FULL_POWER; lbs_deb_cmd("CMD_RESP: Exit_PS command response\n"); @@ -857,8 +857,8 @@ int libertas_process_rx_command(wlan_private * priv) * Handling errors here */ switch (respcmd) { - case cmd_ret_hw_spec_info: - case cmd_ret_802_11_reset: + case CMD_RET_HW_SPEC_INFO: + case CMD_RET_802_11_RESET: lbs_deb_cmd("CMD_RESP: Reset command failed\n"); break; @@ -1003,7 +1003,7 @@ int libertas_process_event(wlan_private * priv) case MACREG_INT_CODE_MESH_AUTO_STARTED: lbs_pr_alert( "EVENT: MESH_AUTO_STARTED\n"); - adapter->connect_status = libertas_connected ; + adapter->connect_status = LIBERTAS_CONNECTED ; if (priv->mesh_open == 1) { netif_wake_queue(priv->mesh_dev) ; netif_carrier_on(priv->mesh_dev) ; diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c index e5cbfa8d6e3..a206f49f810 100644 --- a/drivers/net/wireless/libertas/debugfs.c +++ b/drivers/net/wireless/libertas/debugfs.c @@ -125,9 +125,9 @@ static ssize_t libertas_sleepparams_write(struct file *file, priv->adapter->sp.sp_reserved = p6; res = libertas_prepare_and_send_command(priv, - cmd_802_11_sleep_params, - cmd_act_set, - cmd_option_waitforrsp, 0, NULL); + CMD_802_11_SLEEP_PARAMS, + CMD_ACT_SET, + CMD_OPTION_WAITFORRSP, 0, NULL); if (!res) res = count; @@ -150,9 +150,9 @@ static ssize_t libertas_sleepparams_read(struct file *file, char __user *userbuf char *buf = (char *)addr; res = libertas_prepare_and_send_command(priv, - cmd_802_11_sleep_params, - cmd_act_get, - cmd_option_waitforrsp, 0, NULL); + CMD_802_11_SLEEP_PARAMS, + CMD_ACT_GET, + CMD_OPTION_WAITFORRSP, 0, NULL); if (res) { res = -EFAULT; goto out_unlock; @@ -386,7 +386,7 @@ static int libertas_event_initcmd(wlan_private *priv, void **response_buf, struct cmd_ctrl_node **cmdnode, struct cmd_ds_command **cmd) { - u16 wait_option = cmd_option_waitforrsp; + u16 wait_option = CMD_OPTION_WAITFORRSP; if (!(*cmdnode = libertas_get_free_cmd_ctrl_node(priv))) { lbs_deb_debugfs("failed libertas_get_free_cmd_ctrl_node\n"); @@ -402,7 +402,7 @@ static int libertas_event_initcmd(wlan_private *priv, void **response_buf, (*cmdnode)->cmdflags |= CMD_F_HOSTCMD; (*cmdnode)->cmdwaitqwoken = 0; *cmd = (struct cmd_ds_command *)(*cmdnode)->bufvirtualaddr; - (*cmd)->command = cpu_to_le16(cmd_802_11_subscribe_event); + (*cmd)->command = cpu_to_le16(CMD_802_11_SUBSCRIBE_EVENT); (*cmd)->seqnum = cpu_to_le16(++priv->adapter->seqnum); (*cmd)->result = 0; return 0; @@ -429,7 +429,7 @@ static ssize_t libertas_lowrssi_read(struct file *file, char __user *userbuf, } event = &pcmdptr->params.subscribe_event; - event->action = cpu_to_le16(cmd_act_get); + event->action = cpu_to_le16(CMD_ACT_GET); pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN); libertas_queue_cmd(adapter, pcmdnode, 1); wake_up_interruptible(&priv->mainthread.waitq); @@ -447,7 +447,7 @@ static ssize_t libertas_lowrssi_read(struct file *file, char __user *userbuf, return 0; } - if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) { + if (pcmdptr->command != cpu_to_le16(CMD_RET_802_11_SUBSCRIBE_EVENT)) { lbs_pr_err("command response incorrect!\n"); kfree(response_buf); free_page(addr); @@ -493,7 +493,7 @@ static u16 libertas_get_events_bitmap(wlan_private *priv) return res; event = &pcmdptr->params.subscribe_event; - event->action = cpu_to_le16(cmd_act_get); + event->action = cpu_to_le16(CMD_ACT_GET); pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN); libertas_queue_cmd(adapter, pcmdnode, 1); wake_up_interruptible(&priv->mainthread.waitq); @@ -511,7 +511,7 @@ static u16 libertas_get_events_bitmap(wlan_private *priv) return 0; } - if (pcmdptr->command != cmd_ret_802_11_subscribe_event) { + if (pcmdptr->command != CMD_RET_802_11_SUBSCRIBE_EVENT) { lbs_pr_err("command response incorrect!\n"); kfree(response_buf); return 0; @@ -559,7 +559,7 @@ static ssize_t libertas_lowrssi_write(struct file *file, goto out_unlock; event = &pcmdptr->params.subscribe_event; - event->action = cpu_to_le16(cmd_act_set); + event->action = cpu_to_le16(CMD_ACT_SET); pcmdptr->size = cpu_to_le16(S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event) + sizeof(struct mrvlietypes_rssithreshold)); @@ -591,7 +591,7 @@ static ssize_t libertas_lowrssi_write(struct file *file, return 0; } - if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) { + if (pcmdptr->command != cpu_to_le16(CMD_RET_802_11_SUBSCRIBE_EVENT)) { lbs_pr_err("command response incorrect!\n"); kfree(response_buf); free_page(addr); @@ -625,7 +625,7 @@ static ssize_t libertas_lowsnr_read(struct file *file, char __user *userbuf, } event = &pcmdptr->params.subscribe_event; - event->action = cpu_to_le16(cmd_act_get); + event->action = cpu_to_le16(CMD_ACT_GET); pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN); libertas_queue_cmd(adapter, pcmdnode, 1); wake_up_interruptible(&priv->mainthread.waitq); @@ -644,7 +644,7 @@ static ssize_t libertas_lowsnr_read(struct file *file, char __user *userbuf, return 0; } - if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) { + if (pcmdptr->command != cpu_to_le16(CMD_RET_802_11_SUBSCRIBE_EVENT)) { lbs_pr_err("command response incorrect!\n"); kfree(response_buf); free_page(addr); @@ -712,7 +712,7 @@ static ssize_t libertas_lowsnr_write(struct file *file, goto out_unlock; event = &pcmdptr->params.subscribe_event; - event->action = cpu_to_le16(cmd_act_set); + event->action = cpu_to_le16(CMD_ACT_SET); pcmdptr->size = cpu_to_le16(S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event) + sizeof(struct mrvlietypes_snrthreshold)); @@ -743,7 +743,7 @@ static ssize_t libertas_lowsnr_write(struct file *file, return 0; } - if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) { + if (pcmdptr->command != cpu_to_le16(CMD_RET_802_11_SUBSCRIBE_EVENT)) { lbs_pr_err("command response incorrect!\n"); kfree(response_buf); free_page(addr); @@ -778,7 +778,7 @@ static ssize_t libertas_failcount_read(struct file *file, char __user *userbuf, } event = &pcmdptr->params.subscribe_event; - event->action = cpu_to_le16(cmd_act_get); + event->action = cpu_to_le16(CMD_ACT_GET); pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN); libertas_queue_cmd(adapter, pcmdnode, 1); wake_up_interruptible(&priv->mainthread.waitq); @@ -797,7 +797,7 @@ static ssize_t libertas_failcount_read(struct file *file, char __user *userbuf, return 0; } - if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) { + if (pcmdptr->command != cpu_to_le16(CMD_RET_802_11_SUBSCRIBE_EVENT)) { lbs_pr_err("command response incorrect!\n"); kfree(response_buf); free_page(addr); @@ -864,7 +864,7 @@ static ssize_t libertas_failcount_write(struct file *file, goto out_unlock; event = &pcmdptr->params.subscribe_event; - event->action = cpu_to_le16(cmd_act_set); + event->action = cpu_to_le16(CMD_ACT_SET); pcmdptr->size = cpu_to_le16(S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event) + sizeof(struct mrvlietypes_failurecount)); @@ -895,7 +895,7 @@ static ssize_t libertas_failcount_write(struct file *file, return 0; } - if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) { + if (pcmdptr->command != cpu_to_le16(CMD_RET_802_11_SUBSCRIBE_EVENT)) { lbs_pr_err("command response incorrect!\n"); kfree(response_buf); free_page(addr); @@ -929,7 +929,7 @@ static ssize_t libertas_bcnmiss_read(struct file *file, char __user *userbuf, } event = &pcmdptr->params.subscribe_event; - event->action = cpu_to_le16(cmd_act_get); + event->action = cpu_to_le16(CMD_ACT_GET); pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN); libertas_queue_cmd(adapter, pcmdnode, 1); wake_up_interruptible(&priv->mainthread.waitq); @@ -948,7 +948,7 @@ static ssize_t libertas_bcnmiss_read(struct file *file, char __user *userbuf, return 0; } - if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) { + if (pcmdptr->command != cpu_to_le16(CMD_RET_802_11_SUBSCRIBE_EVENT)) { lbs_pr_err("command response incorrect!\n"); free_page(addr); kfree(response_buf); @@ -1015,7 +1015,7 @@ static ssize_t libertas_bcnmiss_write(struct file *file, goto out_unlock; event = &pcmdptr->params.subscribe_event; - event->action = cpu_to_le16(cmd_act_set); + event->action = cpu_to_le16(CMD_ACT_SET); pcmdptr->size = cpu_to_le16(S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event) + sizeof(struct mrvlietypes_beaconsmissed)); @@ -1045,7 +1045,7 @@ static ssize_t libertas_bcnmiss_write(struct file *file, return 0; } - if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) { + if (pcmdptr->command != cpu_to_le16(CMD_RET_802_11_SUBSCRIBE_EVENT)) { lbs_pr_err("command response incorrect!\n"); free_page(addr); kfree(response_buf); @@ -1079,7 +1079,7 @@ static ssize_t libertas_highrssi_read(struct file *file, char __user *userbuf, } event = &pcmdptr->params.subscribe_event; - event->action = cpu_to_le16(cmd_act_get); + event->action = cpu_to_le16(CMD_ACT_GET); pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN); libertas_queue_cmd(adapter, pcmdnode, 1); wake_up_interruptible(&priv->mainthread.waitq); @@ -1098,7 +1098,7 @@ static ssize_t libertas_highrssi_read(struct file *file, char __user *userbuf, return 0; } - if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) { + if (pcmdptr->command != cpu_to_le16(CMD_RET_802_11_SUBSCRIBE_EVENT)) { lbs_pr_err("command response incorrect!\n"); kfree(response_buf); free_page(addr); @@ -1166,7 +1166,7 @@ static ssize_t libertas_highrssi_write(struct file *file, goto out_unlock; event = &pcmdptr->params.subscribe_event; - event->action = cpu_to_le16(cmd_act_set); + event->action = cpu_to_le16(CMD_ACT_SET); pcmdptr->size = cpu_to_le16(S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event) + sizeof(struct mrvlietypes_rssithreshold)); @@ -1196,7 +1196,7 @@ static ssize_t libertas_highrssi_write(struct file *file, return 0; } - if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) { + if (pcmdptr->command != cpu_to_le16(CMD_RET_802_11_SUBSCRIBE_EVENT)) { lbs_pr_err("command response incorrect!\n"); kfree(response_buf); return 0; @@ -1229,7 +1229,7 @@ static ssize_t libertas_highsnr_read(struct file *file, char __user *userbuf, } event = &pcmdptr->params.subscribe_event; - event->action = cpu_to_le16(cmd_act_get); + event->action = cpu_to_le16(CMD_ACT_GET); pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN); libertas_queue_cmd(adapter, pcmdnode, 1); wake_up_interruptible(&priv->mainthread.waitq); @@ -1248,7 +1248,7 @@ static ssize_t libertas_highsnr_read(struct file *file, char __user *userbuf, return 0; } - if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) { + if (pcmdptr->command != cpu_to_le16(CMD_RET_802_11_SUBSCRIBE_EVENT)) { lbs_pr_err("command response incorrect!\n"); kfree(response_buf); free_page(addr); @@ -1316,7 +1316,7 @@ static ssize_t libertas_highsnr_write(struct file *file, goto out_unlock; event = &pcmdptr->params.subscribe_event; - event->action = cpu_to_le16(cmd_act_set); + event->action = cpu_to_le16(CMD_ACT_SET); pcmdptr->size = cpu_to_le16(S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event) + sizeof(struct mrvlietypes_snrthreshold)); @@ -1347,7 +1347,7 @@ static ssize_t libertas_highsnr_write(struct file *file, return 0; } - if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) { + if (pcmdptr->command != cpu_to_le16(CMD_RET_802_11_SUBSCRIBE_EVENT)) { lbs_pr_err("command response incorrect!\n"); kfree(response_buf); free_page(addr); @@ -1375,8 +1375,8 @@ static ssize_t libertas_rdmac_read(struct file *file, char __user *userbuf, offval.value = 0; ret = libertas_prepare_and_send_command(priv, - cmd_mac_reg_access, 0, - cmd_option_waitforrsp, 0, &offval); + CMD_MAC_REG_ACCESS, 0, + CMD_OPTION_WAITFORRSP, 0, &offval); mdelay(10); pos += snprintf(buf+pos, len-pos, "MAC[0x%x] = 0x%08x\n", priv->mac_offset, adapter->offsetvalue.value); @@ -1433,8 +1433,8 @@ static ssize_t libertas_wrmac_write(struct file *file, offval.offset = offset; offval.value = value; res = libertas_prepare_and_send_command(priv, - cmd_mac_reg_access, 1, - cmd_option_waitforrsp, 0, &offval); + CMD_MAC_REG_ACCESS, 1, + CMD_OPTION_WAITFORRSP, 0, &offval); mdelay(10); res = count; @@ -1458,8 +1458,8 @@ static ssize_t libertas_rdbbp_read(struct file *file, char __user *userbuf, offval.value = 0; ret = libertas_prepare_and_send_command(priv, - cmd_bbp_reg_access, 0, - cmd_option_waitforrsp, 0, &offval); + CMD_BBP_REG_ACCESS, 0, + CMD_OPTION_WAITFORRSP, 0, &offval); mdelay(10); pos += snprintf(buf+pos, len-pos, "BBP[0x%x] = 0x%08x\n", priv->bbp_offset, adapter->offsetvalue.value); @@ -1517,8 +1517,8 @@ static ssize_t libertas_wrbbp_write(struct file *file, offval.offset = offset; offval.value = value; res = libertas_prepare_and_send_command(priv, - cmd_bbp_reg_access, 1, - cmd_option_waitforrsp, 0, &offval); + CMD_BBP_REG_ACCESS, 1, + CMD_OPTION_WAITFORRSP, 0, &offval); mdelay(10); res = count; @@ -1542,8 +1542,8 @@ static ssize_t libertas_rdrf_read(struct file *file, char __user *userbuf, offval.value = 0; ret = libertas_prepare_and_send_command(priv, - cmd_rf_reg_access, 0, - cmd_option_waitforrsp, 0, &offval); + CMD_RF_REG_ACCESS, 0, + CMD_OPTION_WAITFORRSP, 0, &offval); mdelay(10); pos += snprintf(buf+pos, len-pos, "RF[0x%x] = 0x%08x\n", priv->rf_offset, adapter->offsetvalue.value); @@ -1601,8 +1601,8 @@ static ssize_t libertas_wrrf_write(struct file *file, offval.offset = offset; offval.value = value; res = libertas_prepare_and_send_command(priv, - cmd_rf_reg_access, 1, - cmd_option_waitforrsp, 0, &offval); + CMD_RF_REG_ACCESS, 1, + CMD_OPTION_WAITFORRSP, 0, &offval); mdelay(10); res = count; diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h index a5d70c19768..862292913c2 100644 --- a/drivers/net/wireless/libertas/defs.h +++ b/drivers/net/wireless/libertas/defs.h @@ -286,11 +286,11 @@ enum SNRNF_DATA { /** WLAN_802_11_POWER_MODE */ enum WLAN_802_11_POWER_MODE { - wlan802_11powermodecam, - wlan802_11powermodemax_psp, - wlan802_11Powermodefast_psp, + WLAN802_11POWERMODECAM, + WLAN802_11POWERMODEMAX_PSP, + WLAN802_11POWERMODEFAST_PSP, /*not a real mode, defined as an upper bound */ - wlan802_11powemodemax + WLAN802_11POWEMODEMAX }; /** PS_STATE */ @@ -310,14 +310,14 @@ enum DNLD_STATE { /** WLAN_MEDIA_STATE */ enum WLAN_MEDIA_STATE { - libertas_connected, - libertas_disconnected + LIBERTAS_CONNECTED, + LIBERTAS_DISCONNECTED }; /** WLAN_802_11_PRIVACY_FILTER */ enum WLAN_802_11_PRIVACY_FILTER { - wlan802_11privfilteracceptall, - wlan802_11privfilter8021xWEP + WLAN802_11PRIVFILTERACCEPTALL, + WLAN802_11PRIVFILTER8021XWEP }; /** mv_ms_type */ @@ -330,23 +330,23 @@ enum mv_ms_type { /** SNMP_MIB_INDEX_e */ enum SNMP_MIB_INDEX_e { - desired_bsstype_i = 0, - op_rateset_i, - bcnperiod_i, - dtimperiod_i, - assocrsp_timeout_i, - rtsthresh_i, - short_retrylim_i, - long_retrylim_i, - fragthresh_i, - dot11d_i, - dot11h_i, - manufid_i, - prodID_i, - manuf_oui_i, - manuf_name_i, - manuf_prodname_i, - manuf_prodver_i, + DESIRED_BSSTYPE_I = 0, + OP_RATESET_I, + BCNPERIOD_I, + DTIMPERIOD_I, + ASSOCRSP_TIMEOUT_I, + RTSTHRESH_I, + SHORT_RETRYLIM_I, + LONG_RETRYLIM_I, + FRAGTHRESH_I, + DOT11D_I, + DOT11H_I, + MANUFID_I, + PRODID_I, + MANUF_OUI_I, + MANUF_NAME_I, + MANUF_PRODNAME_I, + MANUF_PRODVER_I, }; /** KEY_TYPE_ID */ diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c index 96f1974685d..ec99cb82587 100644 --- a/drivers/net/wireless/libertas/ethtool.c +++ b/drivers/net/wireless/libertas/ethtool.c @@ -72,9 +72,9 @@ static int libertas_ethtool_get_eeprom(struct net_device *dev, regctrl.action, regctrl.offset, regctrl.NOB); ret = libertas_prepare_and_send_command(priv, - cmd_802_11_eeprom_access, + CMD_802_11_EEPROM_ACCESS, regctrl.action, - cmd_option_waitforrsp, 0, + CMD_OPTION_WAITFORRSP, 0, ®ctrl); if (ret) { @@ -138,8 +138,8 @@ static int libertas_ethtool_get_stats_count(struct net_device * dev) /* Get Mesh Statistics */ ret = libertas_prepare_and_send_command(priv, - cmd_mesh_access, cmd_act_mesh_get_stats, - cmd_option_waitforrsp, 0, &mesh_access); + CMD_MESH_ACCESS, CMD_ACT_MESH_GET_STATS, + CMD_OPTION_WAITFORRSP, 0, &mesh_access); if (ret) { ret = 0; diff --git a/drivers/net/wireless/libertas/fw.c b/drivers/net/wireless/libertas/fw.c index 288e47c3355..39b0a094b62 100644 --- a/drivers/net/wireless/libertas/fw.c +++ b/drivers/net/wireless/libertas/fw.c @@ -99,8 +99,8 @@ static int wlan_setup_station_hw(wlan_private * priv, char *fw_name) */ memset(adapter->current_addr, 0xff, ETH_ALEN); - ret = libertas_prepare_and_send_command(priv, cmd_get_hw_spec, - 0, cmd_option_waitforrsp, 0, NULL); + ret = libertas_prepare_and_send_command(priv, CMD_GET_HW_SPEC, + 0, CMD_OPTION_WAITFORRSP, 0, NULL); if (ret) { ret = -1; @@ -110,9 +110,9 @@ static int wlan_setup_station_hw(wlan_private * priv, char *fw_name) libertas_set_mac_packet_filter(priv); /* Get the supported Data rates */ - ret = libertas_prepare_and_send_command(priv, cmd_802_11_data_rate, - cmd_act_get_tx_rate, - cmd_option_waitforrsp, 0, NULL); + ret = libertas_prepare_and_send_command(priv, CMD_802_11_DATA_RATE, + CMD_ACT_GET_tx_rate, + CMD_OPTION_WAITFORRSP, 0, NULL); if (ret) { ret = -1; @@ -145,12 +145,12 @@ static int wlan_allocate_adapter(wlan_private * priv) memset(&adapter->libertas_ps_confirm_sleep, 0, sizeof(struct PS_CMD_ConfirmSleep)); adapter->libertas_ps_confirm_sleep.seqnum = cpu_to_le16(++adapter->seqnum); adapter->libertas_ps_confirm_sleep.command = - cpu_to_le16(cmd_802_11_ps_mode); + cpu_to_le16(CMD_802_11_PS_MODE); adapter->libertas_ps_confirm_sleep.size = cpu_to_le16(sizeof(struct PS_CMD_ConfirmSleep)); adapter->libertas_ps_confirm_sleep.result = 0; adapter->libertas_ps_confirm_sleep.action = - cpu_to_le16(cmd_subcmd_sleep_confirmed); + cpu_to_le16(CMD_SUBCMD_SLEEP_CONFIRMED); return 0; } @@ -168,14 +168,14 @@ static void wlan_init_adapter(wlan_private * priv) /* ATIM params */ adapter->atimwindow = 0; - adapter->connect_status = libertas_disconnected; + adapter->connect_status = LIBERTAS_DISCONNECTED; memset(adapter->current_addr, 0xff, ETH_ALEN); /* scan type */ - adapter->scantype = cmd_scan_type_active; + adapter->scantype = CMD_SCAN_TYPE_ACTIVE; /* scan mode */ - adapter->scanmode = cmd_bss_type_any; + adapter->scanmode = CMD_BSS_TYPE_ANY; /* 802.11 specific */ adapter->secinfo.wep_enabled = 0; @@ -208,7 +208,7 @@ static void wlan_init_adapter(wlan_private * priv) adapter->surpriseremoved = 0; adapter->currentpacketfilter = - cmd_act_mac_rx_on | cmd_act_mac_tx_on; + CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON; adapter->radioon = RADIO_ON; adapter->txantenna = RF_ANTENNA_2; @@ -220,7 +220,7 @@ static void wlan_init_adapter(wlan_private * priv) // set default capabilities adapter->capability = WLAN_CAPABILITY_SHORT_PREAMBLE; - adapter->psmode = wlan802_11powermodecam; + adapter->psmode = WLAN802_11POWERMODECAM; adapter->multipledtim = MRVDRV_DEFAULT_MULTIPLE_DTIM; adapter->listeninterval = MRVDRV_DEFAULT_LISTEN_INTERVAL; diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index 7509cc10af3..4bd2e88116c 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -20,224 +20,224 @@ #define OID_802_11_TX_RETRYCOUNT 0x0000801D #define OID_802_11D_ENABLE 0x00008020 -#define cmd_option_waitforrsp 0x0002 +#define CMD_OPTION_WAITFORRSP 0x0002 /** Host command ID */ -#define cmd_code_dnld 0x0002 -#define cmd_get_hw_spec 0x0003 -#define cmd_eeprom_update 0x0004 -#define cmd_802_11_reset 0x0005 -#define cmd_802_11_scan 0x0006 -#define cmd_802_11_get_log 0x000b -#define cmd_mac_multicast_adr 0x0010 -#define cmd_802_11_authenticate 0x0011 -#define cmd_802_11_eeprom_access 0x0059 -#define cmd_802_11_associate 0x0050 -#define cmd_802_11_set_wep 0x0013 -#define cmd_802_11_get_stat 0x0014 -#define cmd_802_3_get_stat 0x0015 -#define cmd_802_11_snmp_mib 0x0016 -#define cmd_mac_reg_map 0x0017 -#define cmd_bbp_reg_map 0x0018 -#define cmd_mac_reg_access 0x0019 -#define cmd_bbp_reg_access 0x001a -#define cmd_rf_reg_access 0x001b -#define cmd_802_11_radio_control 0x001c -#define cmd_802_11_rf_channel 0x001d -#define cmd_802_11_rf_tx_power 0x001e -#define cmd_802_11_rssi 0x001f -#define cmd_802_11_rf_antenna 0x0020 +#define CMD_CODE_DNLD 0x0002 +#define CMD_GET_HW_SPEC 0x0003 +#define CMD_EEPROM_UPDATE 0x0004 +#define CMD_802_11_RESET 0x0005 +#define CMD_802_11_SCAN 0x0006 +#define CMD_802_11_GET_LOG 0x000b +#define CMD_MAC_MULTICAST_ADR 0x0010 +#define CMD_802_11_AUTHENTICATE 0x0011 +#define CMD_802_11_EEPROM_ACCESS 0x0059 +#define CMD_802_11_ASSOCIATE 0x0050 +#define CMD_802_11_SET_WEP 0x0013 +#define CMD_802_11_GET_STAT 0x0014 +#define CMD_802_3_GET_STAT 0x0015 +#define CMD_802_11_SNMP_MIB 0x0016 +#define CMD_MAC_REG_MAP 0x0017 +#define CMD_BBP_REG_MAP 0x0018 +#define CMD_MAC_REG_ACCESS 0x0019 +#define CMD_BBP_REG_ACCESS 0x001a +#define CMD_RF_REG_ACCESS 0x001b +#define CMD_802_11_RADIO_CONTROL 0x001c +#define CMD_802_11_RF_CHANNEL 0x001d +#define CMD_802_11_RF_TX_POWER 0x001e +#define CMD_802_11_RSSI 0x001f +#define CMD_802_11_RF_ANTENNA 0x0020 -#define cmd_802_11_ps_mode 0x0021 +#define CMD_802_11_PS_MODE 0x0021 -#define cmd_802_11_data_rate 0x0022 -#define cmd_rf_reg_map 0x0023 -#define cmd_802_11_deauthenticate 0x0024 -#define cmd_802_11_reassociate 0x0025 -#define cmd_802_11_disassociate 0x0026 -#define cmd_mac_control 0x0028 -#define cmd_802_11_ad_hoc_start 0x002b -#define cmd_802_11_ad_hoc_join 0x002c +#define CMD_802_11_DATA_RATE 0x0022 +#define CMD_RF_REG_MAP 0x0023 +#define CMD_802_11_DEAUTHENTICATE 0x0024 +#define CMD_802_11_REASSOCIATE 0x0025 +#define CMD_802_11_DISASSOCIATE 0x0026 +#define CMD_MAC_CONTROL 0x0028 +#define CMD_802_11_AD_HOC_START 0x002b +#define CMD_802_11_AD_HOC_JOIN 0x002c -#define cmd_802_11_query_tkip_reply_cntrs 0x002e -#define cmd_802_11_enable_rsn 0x002f -#define cmd_802_11_pairwise_tsc 0x0036 -#define cmd_802_11_group_tsc 0x0037 -#define cmd_802_11_key_material 0x005e +#define CMD_802_11_QUERY_TKIP_REPLY_CNTRS 0x002e +#define CMD_802_11_ENABLE_RSN 0x002f +#define CMD_802_11_PAIRWISE_TSC 0x0036 +#define CMD_802_11_GROUP_TSC 0x0037 +#define CMD_802_11_KEY_MATERIAL 0x005e -#define cmd_802_11_set_afc 0x003c -#define cmd_802_11_get_afc 0x003d +#define CMD_802_11_SET_AFC 0x003c +#define CMD_802_11_GET_AFC 0x003d -#define cmd_802_11_ad_hoc_stop 0x0040 +#define CMD_802_11_AD_HOC_STOP 0x0040 -#define cmd_802_11_beacon_stop 0x0049 +#define CMD_802_11_BEACON_STOP 0x0049 -#define cmd_802_11_mac_address 0x004D -#define cmd_802_11_eeprom_access 0x0059 +#define CMD_802_11_MAC_ADDRESS 0x004D +#define CMD_802_11_EEPROM_ACCESS 0x0059 -#define cmd_802_11_band_config 0x0058 +#define CMD_802_11_BAND_CONFIG 0x0058 -#define cmd_802_11d_domain_info 0x005b +#define CMD_802_11D_DOMAIN_INFO 0x005b -#define cmd_802_11_sleep_params 0x0066 +#define CMD_802_11_SLEEP_PARAMS 0x0066 -#define cmd_802_11_inactivity_timeout 0x0067 +#define CMD_802_11_INACTIVITY_TIMEOUT 0x0067 -#define cmd_802_11_tpc_cfg 0x0072 -#define cmd_802_11_pwr_cfg 0x0073 +#define CMD_802_11_TPC_CFG 0x0072 +#define CMD_802_11_PWR_CFG 0x0073 -#define cmd_802_11_led_gpio_ctrl 0x004e +#define CMD_802_11_LED_GPIO_CTRL 0x004e -#define cmd_802_11_subscribe_event 0x0075 +#define CMD_802_11_SUBSCRIBE_EVENT 0x0075 -#define cmd_802_11_rate_adapt_rateset 0x0076 +#define CMD_802_11_RATE_ADAPT_RATESET 0x0076 -#define cmd_802_11_tx_rate_query 0x007f +#define CMD_802_11_TX_RATE_QUERY 0x007f -#define cmd_get_tsf 0x0080 +#define CMD_GET_TSF 0x0080 -#define cmd_bt_access 0x0087 -#define cmd_ret_bt_access 0x8087 +#define CMD_BT_ACCESS 0x0087 +#define CMD_RET_BT_ACCESS 0x8087 -#define cmd_fwt_access 0x0095 -#define cmd_ret_fwt_access 0x8095 +#define CMD_FWT_ACCESS 0x0095 +#define CMD_RET_FWT_ACCESS 0x8095 -#define cmd_mesh_access 0x009b -#define cmd_ret_mesh_access 0x809b +#define CMD_MESH_ACCESS 0x009b +#define CMD_RET_MESH_ACCESS 0x809b /* For the IEEE Power Save */ -#define cmd_subcmd_enter_ps 0x0030 -#define cmd_subcmd_exit_ps 0x0031 -#define cmd_subcmd_sleep_confirmed 0x0034 -#define cmd_subcmd_full_powerdown 0x0035 -#define cmd_subcmd_full_powerup 0x0036 +#define CMD_SUBCMD_ENTER_PS 0x0030 +#define CMD_SUBCMD_EXIT_PS 0x0031 +#define CMD_SUBCMD_SLEEP_CONFIRMED 0x0034 +#define CMD_SUBCMD_FULL_POWERDOWN 0x0035 +#define CMD_SUBCMD_FULL_POWERUP 0x0036 /* command RET code, MSB is set to 1 */ -#define cmd_ret_hw_spec_info 0x8003 -#define cmd_ret_eeprom_update 0x8004 -#define cmd_ret_802_11_reset 0x8005 -#define cmd_ret_802_11_scan 0x8006 -#define cmd_ret_802_11_get_log 0x800b -#define cmd_ret_mac_control 0x8028 -#define cmd_ret_mac_multicast_adr 0x8010 -#define cmd_ret_802_11_authenticate 0x8011 -#define cmd_ret_802_11_deauthenticate 0x8024 -#define cmd_ret_802_11_associate 0x8012 -#define cmd_ret_802_11_reassociate 0x8025 -#define cmd_ret_802_11_disassociate 0x8026 -#define cmd_ret_802_11_set_wep 0x8013 -#define cmd_ret_802_11_stat 0x8014 -#define cmd_ret_802_3_stat 0x8015 -#define cmd_ret_802_11_snmp_mib 0x8016 -#define cmd_ret_mac_reg_map 0x8017 -#define cmd_ret_bbp_reg_map 0x8018 -#define cmd_ret_rf_reg_map 0x8023 -#define cmd_ret_mac_reg_access 0x8019 -#define cmd_ret_bbp_reg_access 0x801a -#define cmd_ret_rf_reg_access 0x801b -#define cmd_ret_802_11_radio_control 0x801c -#define cmd_ret_802_11_rf_channel 0x801d -#define cmd_ret_802_11_rssi 0x801f -#define cmd_ret_802_11_rf_tx_power 0x801e -#define cmd_ret_802_11_rf_antenna 0x8020 -#define cmd_ret_802_11_ps_mode 0x8021 -#define cmd_ret_802_11_data_rate 0x8022 +#define CMD_RET_HW_SPEC_INFO 0x8003 +#define CMD_RET_EEPROM_UPDATE 0x8004 +#define CMD_RET_802_11_RESET 0x8005 +#define CMD_RET_802_11_SCAN 0x8006 +#define CMD_RET_802_11_GET_LOG 0x800b +#define CMD_RET_MAC_CONTROL 0x8028 +#define CMD_RET_MAC_MULTICAST_ADR 0x8010 +#define CMD_RET_802_11_AUTHENTICATE 0x8011 +#define CMD_RET_802_11_DEAUTHENTICATE 0x8024 +#define CMD_RET_802_11_ASSOCIATE 0x8012 +#define CMD_RET_802_11_REASSOCIATE 0x8025 +#define CMD_RET_802_11_DISASSOCIATE 0x8026 +#define CMD_RET_802_11_SET_WEP 0x8013 +#define CMD_RET_802_11_STAT 0x8014 +#define CMD_RET_802_3_STAT 0x8015 +#define CMD_RET_802_11_SNMP_MIB 0x8016 +#define CMD_RET_MAC_REG_MAP 0x8017 +#define CMD_RET_BBP_REG_MAP 0x8018 +#define CMD_RET_RF_REG_MAP 0x8023 +#define CMD_RET_MAC_REG_ACCESS 0x8019 +#define CMD_RET_BBP_REG_ACCESS 0x801a +#define CMD_RET_RF_REG_ACCESS 0x801b +#define CMD_RET_802_11_RADIO_CONTROL 0x801c +#define CMD_RET_802_11_RF_CHANNEL 0x801d +#define CMD_RET_802_11_RSSI 0x801f +#define CMD_RET_802_11_RF_TX_POWER 0x801e +#define CMD_RET_802_11_RF_ANTENNA 0x8020 +#define CMD_RET_802_11_PS_MODE 0x8021 +#define CMD_RET_802_11_DATA_RATE 0x8022 -#define cmd_ret_802_11_ad_hoc_start 0x802B -#define cmd_ret_802_11_ad_hoc_join 0x802C +#define CMD_RET_802_11_AD_HOC_START 0x802B +#define CMD_RET_802_11_AD_HOC_JOIN 0x802C -#define cmd_ret_802_11_query_tkip_reply_cntrs 0x802e -#define cmd_ret_802_11_enable_rsn 0x802f -#define cmd_ret_802_11_pairwise_tsc 0x8036 -#define cmd_ret_802_11_group_tsc 0x8037 -#define cmd_ret_802_11_key_material 0x805e +#define CMD_RET_802_11_QUERY_TKIP_REPLY_CNTRS 0x802e +#define CMD_RET_802_11_ENABLE_RSN 0x802f +#define CMD_RET_802_11_PAIRWISE_TSC 0x8036 +#define CMD_RET_802_11_GROUP_TSC 0x8037 +#define CMD_RET_802_11_KEY_MATERIAL 0x805e -#define cmd_enable_rsn 0x0001 -#define cmd_disable_rsn 0x0000 +#define CMD_ENABLE_RSN 0x0001 +#define CMD_DISABLE_RSN 0x0000 -#define cmd_act_set 0x0001 -#define cmd_act_get 0x0000 +#define CMD_ACT_SET 0x0001 +#define CMD_ACT_GET 0x0000 -#define cmd_act_get_AES (cmd_act_get + 2) -#define cmd_act_set_AES (cmd_act_set + 2) -#define cmd_act_remove_aes (cmd_act_set + 3) +#define CMD_ACT_GET_AES (CMD_ACT_GET + 2) +#define CMD_ACT_SET_AES (CMD_ACT_SET + 2) +#define CMD_ACT_REMOVE_AES (CMD_ACT_SET + 3) -#define cmd_ret_802_11_set_afc 0x803c -#define cmd_ret_802_11_get_afc 0x803d +#define CMD_RET_802_11_SET_AFC 0x803c +#define CMD_RET_802_11_GET_AFC 0x803d -#define cmd_ret_802_11_ad_hoc_stop 0x8040 +#define CMD_RET_802_11_AD_HOC_STOP 0x8040 -#define cmd_ret_802_11_beacon_stop 0x8049 +#define CMD_RET_802_11_BEACON_STOP 0x8049 -#define cmd_ret_802_11_mac_address 0x804D -#define cmd_ret_802_11_eeprom_access 0x8059 +#define CMD_RET_802_11_MAC_ADDRESS 0x804D +#define CMD_RET_802_11_EEPROM_ACCESS 0x8059 -#define cmd_ret_802_11_band_config 0x8058 +#define CMD_RET_802_11_BAND_CONFIG 0x8058 -#define cmd_ret_802_11_sleep_params 0x8066 +#define CMD_RET_802_11_SLEEP_PARAMS 0x8066 -#define cmd_ret_802_11_inactivity_timeout 0x8067 +#define CMD_RET_802_11_INACTIVITY_TIMEOUT 0x8067 -#define cmd_ret_802_11d_domain_info (0x8000 | \ - cmd_802_11d_domain_info) +#define CMD_RET_802_11D_DOMAIN_INFO (0x8000 | \ + CMD_802_11D_DOMAIN_INFO) -#define cmd_ret_802_11_tpc_cfg (cmd_802_11_tpc_cfg | 0x8000) -#define cmd_ret_802_11_pwr_cfg (cmd_802_11_pwr_cfg | 0x8000) +#define CMD_RET_802_11_TPC_CFG (CMD_802_11_TPC_CFG | 0x8000) +#define CMD_RET_802_11_PWR_CFG (CMD_802_11_PWR_CFG | 0x8000) -#define cmd_ret_802_11_led_gpio_ctrl 0x804e +#define CMD_RET_802_11_LED_GPIO_CTRL 0x804e -#define cmd_ret_802_11_subscribe_event (cmd_802_11_subscribe_event | 0x8000) +#define CMD_RET_802_11_SUBSCRIBE_EVENT (CMD_802_11_SUBSCRIBE_EVENT | 0x8000) -#define cmd_ret_802_11_rate_adapt_rateset (cmd_802_11_rate_adapt_rateset | 0x8000) +#define CMD_RET_802_11_RATE_ADAPT_RATESET (CMD_802_11_RATE_ADAPT_RATESET | 0x8000) -#define cmd_rte_802_11_tx_rate_query (cmd_802_11_tx_rate_query | 0x8000) +#define CMD_RTE_802_11_TX_RATE_QUERY (CMD_802_11_TX_RATE_QUERY | 0x8000) -#define cmd_ret_get_tsf 0x8080 +#define CMD_RET_GET_TSF 0x8080 -/* Define action or option for cmd_802_11_set_wep */ -#define cmd_act_add 0x0002 -#define cmd_act_remove 0x0004 -#define cmd_act_use_default 0x0008 +/* Define action or option for CMD_802_11_SET_WEP */ +#define CMD_ACT_ADD 0x0002 +#define CMD_ACT_REMOVE 0x0004 +#define CMD_ACT_USE_DEFAULT 0x0008 -#define cmd_type_wep_40_bit 0x0001 -#define cmd_type_wep_104_bit 0x0002 +#define CMD_TYPE_WEP_40_BIT 0x0001 +#define CMD_TYPE_WEP_104_BIT 0x0002 -#define cmd_NUM_OF_WEP_KEYS 4 +#define CMD_NUM_OF_WEP_KEYS 4 -#define cmd_WEP_KEY_INDEX_MASK 0x3fff +#define CMD_WEP_KEY_INDEX_MASK 0x3fff -/* Define action or option for cmd_802_11_reset */ -#define cmd_act_halt 0x0003 +/* Define action or option for CMD_802_11_RESET */ +#define CMD_ACT_HALT 0x0003 -/* Define action or option for cmd_802_11_scan */ -#define cmd_bss_type_bss 0x0001 -#define cmd_bss_type_ibss 0x0002 -#define cmd_bss_type_any 0x0003 +/* Define action or option for CMD_802_11_SCAN */ +#define CMD_BSS_TYPE_BSS 0x0001 +#define CMD_BSS_TYPE_IBSS 0x0002 +#define CMD_BSS_TYPE_ANY 0x0003 -/* Define action or option for cmd_802_11_scan */ -#define cmd_scan_type_active 0x0000 -#define cmd_scan_type_passive 0x0001 +/* Define action or option for CMD_802_11_SCAN */ +#define CMD_SCAN_TYPE_ACTIVE 0x0000 +#define CMD_SCAN_TYPE_PASSIVE 0x0001 -#define cmd_scan_radio_type_bg 0 +#define CMD_SCAN_RADIO_TYPE_BG 0 -#define cmd_scan_probe_delay_time 0 +#define CMD_SCAN_PROBE_DELAY_TIME 0 -/* Define action or option for cmd_mac_control */ -#define cmd_act_mac_rx_on 0x0001 -#define cmd_act_mac_tx_on 0x0002 -#define cmd_act_mac_loopback_on 0x0004 -#define cmd_act_mac_wep_enable 0x0008 -#define cmd_act_mac_int_enable 0x0010 -#define cmd_act_mac_multicast_enable 0x0020 -#define cmd_act_mac_broadcast_enable 0x0040 -#define cmd_act_mac_promiscuous_enable 0x0080 -#define cmd_act_mac_all_multicast_enable 0x0100 -#define cmd_act_mac_strict_protection_enable 0x0400 +/* Define action or option for CMD_MAC_CONTROL */ +#define CMD_ACT_MAC_RX_ON 0x0001 +#define CMD_ACT_MAC_TX_ON 0x0002 +#define CMD_ACT_MAC_LOOPBACK_ON 0x0004 +#define CMD_ACT_MAC_WEP_ENABLE 0x0008 +#define CMD_ACT_MAC_INT_ENABLE 0x0010 +#define CMD_ACT_MAC_MULTICAST_ENABLE 0x0020 +#define CMD_ACT_MAC_BROADCAST_ENABLE 0x0040 +#define CMD_ACT_MAC_PROMISCUOUS_ENABLE 0x0080 +#define CMD_ACT_MAC_ALL_MULTICAST_ENABLE 0x0100 +#define CMD_ACT_MAC_STRICT_PROTECTION_ENABLE 0x0400 -/* Define action or option for cmd_802_11_radio_control */ -#define cmd_type_auto_preamble 0x0001 -#define cmd_type_short_preamble 0x0002 -#define cmd_type_long_preamble 0x0003 +/* Define action or option for CMD_802_11_RADIO_CONTROL */ +#define CMD_TYPE_AUTO_PREAMBLE 0x0001 +#define CMD_TYPE_SHORT_PREAMBLE 0x0002 +#define CMD_TYPE_LONG_PREAMBLE 0x0003 #define TURN_ON_RF 0x01 #define RADIO_ON 0x01 @@ -248,70 +248,70 @@ #define SET_LONG_PREAMBLE 0x01 /* Define action or option for CMD_802_11_RF_CHANNEL */ -#define cmd_opt_802_11_rf_channel_get 0x00 -#define cmd_opt_802_11_rf_channel_set 0x01 - -/* Define action or option for cmd_802_11_rf_tx_power */ -#define cmd_act_tx_power_opt_get 0x0000 -#define cmd_act_tx_power_opt_set_high 0x8007 -#define cmd_act_tx_power_opt_set_mid 0x8004 -#define cmd_act_tx_power_opt_set_low 0x8000 - -#define cmd_act_tx_power_index_high 0x0007 -#define cmd_act_tx_power_index_mid 0x0004 -#define cmd_act_tx_power_index_low 0x0000 - -/* Define action or option for cmd_802_11_data_rate */ -#define cmd_act_set_tx_auto 0x0000 -#define cmd_act_set_tx_fix_rate 0x0001 -#define cmd_act_get_tx_rate 0x0002 - -#define cmd_act_set_rx 0x0001 -#define cmd_act_set_tx 0x0002 -#define cmd_act_set_both 0x0003 -#define cmd_act_get_rx 0x0004 -#define cmd_act_get_tx 0x0008 -#define cmd_act_get_both 0x000c - -/* Define action or option for cmd_802_11_ps_mode */ -#define cmd_type_cam 0x0000 -#define cmd_type_max_psp 0x0001 -#define cmd_type_fast_psp 0x0002 - -/* Define action or option for cmd_bt_access */ -enum cmd_bt_access_opts { +#define CMD_OPT_802_11_RF_CHANNEL_GET 0x00 +#define CMD_OPT_802_11_RF_CHANNEL_SET 0x01 + +/* Define action or option for CMD_802_11_RF_TX_POWER */ +#define CMD_ACT_TX_POWER_OPT_GET 0x0000 +#define CMD_ACT_TX_POWER_OPT_SET_HIGH 0x8007 +#define CMD_ACT_TX_POWER_OPT_SET_MID 0x8004 +#define CMD_ACT_TX_POWER_OPT_SET_LOW 0x8000 + +#define CMD_ACT_TX_POWER_INDEX_HIGH 0x0007 +#define CMD_ACT_TX_POWER_INDEX_MID 0x0004 +#define CMD_ACT_TX_POWER_INDEX_LOW 0x0000 + +/* Define action or option for CMD_802_11_DATA_RATE */ +#define CMD_ACT_SET_tx_auto 0x0000 +#define CMD_ACT_SET_tx_fix_rate 0x0001 +#define CMD_ACT_GET_tx_rate 0x0002 + +#define CMD_ACT_SET_rx 0x0001 +#define CMD_ACT_SET_tx 0x0002 +#define CMD_ACT_SET_both 0x0003 +#define CMD_ACT_GET_rx 0x0004 +#define CMD_ACT_GET_tx 0x0008 +#define CMD_ACT_GET_both 0x000c + +/* Define action or option for CMD_802_11_PS_MODE */ +#define CMD_TYPE_CAM 0x0000 +#define CMD_TYPE_MAX_PSP 0x0001 +#define CMD_TYPE_FAST_PSP 0x0002 + +/* Define action or option for CMD_BT_ACCESS */ +enum CMD_BT_ACCESS_opts { /* The bt commands start at 5 instead of 1 because the old dft commands * are mapped to 1-4. These old commands are no longer maintained and * should not be called. */ - cmd_act_bt_access_add = 5, - cmd_act_bt_access_del, - cmd_act_bt_access_list, - cmd_act_bt_access_reset, - cmd_act_bt_access_set_invert, - cmd_act_bt_access_get_invert + CMD_ACT_BT_ACCESS_ADD = 5, + CMD_ACT_BT_ACCESS_DEL, + CMD_ACT_BT_ACCESS_LIST, + CMD_ACT_BT_ACCESS_RESET, + CMD_ACT_BT_ACCESS_SET_INVERT, + CMD_ACT_BT_ACCESS_GET_INVERT }; -/* Define action or option for cmd_fwt_access */ -enum cmd_fwt_access_opts { - cmd_act_fwt_access_add = 1, - cmd_act_fwt_access_del, - cmd_act_fwt_access_lookup, - cmd_act_fwt_access_list, - cmd_act_fwt_access_list_route, - cmd_act_fwt_access_list_neighbor, - cmd_act_fwt_access_reset, - cmd_act_fwt_access_cleanup, - cmd_act_fwt_access_time, +/* Define action or option for CMD_FWT_ACCESS */ +enum CMD_FWT_ACCESS_opts { + CMD_ACT_FWT_ACCESS_ADD = 1, + CMD_ACT_FWT_ACCESS_DEL, + CMD_ACT_FWT_ACCESS_LOOKUP, + CMD_ACT_FWT_ACCESS_LIST, + CMD_ACT_FWT_ACCESS_LIST_route, + CMD_ACT_FWT_ACCESS_LIST_neighbor, + CMD_ACT_FWT_ACCESS_RESET, + CMD_ACT_FWT_ACCESS_CLEANUP, + CMD_ACT_FWT_ACCESS_TIME, }; -/* Define action or option for cmd_mesh_access */ -enum cmd_mesh_access_opts { - cmd_act_mesh_get_ttl = 1, - cmd_act_mesh_set_ttl, - cmd_act_mesh_get_stats, - cmd_act_mesh_get_anycast, - cmd_act_mesh_set_anycast, +/* Define action or option for CMD_MESH_ACCESS */ +enum CMD_MESH_ACCESS_opts { + CMD_ACT_MESH_GET_TTL = 1, + CMD_ACT_MESH_SET_TTL, + CMD_ACT_MESH_GET_STATS, + CMD_ACT_MESH_GET_ANYCAST, + CMD_ACT_MESH_SET_ANYCAST, }; /** Card Event definition */ diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index 23871c0f882..76c5fdeb256 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -108,7 +108,7 @@ struct cmd_ds_gen { #define S_DS_GEN sizeof(struct cmd_ds_gen) /* - * Define data structure for cmd_get_hw_spec + * Define data structure for CMD_GET_HW_SPEC * This structure defines the response for the GET_HW_SPEC command */ struct cmd_ds_get_hw_spec { @@ -155,7 +155,7 @@ struct cmd_ds_802_11_subscribe_event { /* * This scan handle Country Information IE(802.11d compliant) - * Define data structure for cmd_802_11_scan + * Define data structure for CMD_802_11_SCAN */ struct cmd_ds_802_11_scan { u8 bsstype; diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index 11687b84c59..cf522c6ef57 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -78,7 +78,7 @@ static void if_usb_write_bulk_callback(struct urb *urb) /* Wake main thread if commands are pending */ if (!adapter->cur_cmd) wake_up_interruptible(&priv->mainthread.waitq); - if ((adapter->connect_status == libertas_connected)) { + if ((adapter->connect_status == LIBERTAS_CONNECTED)) { netif_wake_queue(dev); netif_wake_queue(priv->mesh_dev); } @@ -758,8 +758,8 @@ static int if_usb_reset_device(wlan_private *priv) int ret; lbs_deb_enter(LBS_DEB_USB); - ret = libertas_prepare_and_send_command(priv, cmd_802_11_reset, - cmd_act_halt, 0, 0, NULL); + ret = libertas_prepare_and_send_command(priv, CMD_802_11_RESET, + CMD_ACT_HALT, 0, 0, NULL); msleep_interruptible(10); lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret); diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c index db467e7876f..3530c23da79 100644 --- a/drivers/net/wireless/libertas/join.c +++ b/drivers/net/wireless/libertas/join.c @@ -88,7 +88,7 @@ int libertas_send_deauth(wlan_private * priv) int ret = 0; if (adapter->mode == IW_MODE_INFRA && - adapter->connect_status == libertas_connected) + adapter->connect_status == LIBERTAS_CONNECTED) ret = libertas_send_deauthentication(priv); else ret = -ENOTSUPP; @@ -111,8 +111,8 @@ int wlan_associate(wlan_private * priv, struct assoc_request * assoc_req) lbs_deb_enter(LBS_DEB_JOIN); - ret = libertas_prepare_and_send_command(priv, cmd_802_11_authenticate, - 0, cmd_option_waitforrsp, + ret = libertas_prepare_and_send_command(priv, CMD_802_11_AUTHENTICATE, + 0, CMD_OPTION_WAITFORRSP, 0, assoc_req->bss.bssid); if (ret) @@ -121,14 +121,14 @@ int wlan_associate(wlan_private * priv, struct assoc_request * assoc_req) /* set preamble to firmware */ if ( (adapter->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) && (assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) - adapter->preamble = cmd_type_short_preamble; + adapter->preamble = CMD_TYPE_SHORT_PREAMBLE; else - adapter->preamble = cmd_type_long_preamble; + adapter->preamble = CMD_TYPE_LONG_PREAMBLE; libertas_set_radio_control(priv); - ret = libertas_prepare_and_send_command(priv, cmd_802_11_associate, - 0, cmd_option_waitforrsp, 0, assoc_req); + ret = libertas_prepare_and_send_command(priv, CMD_802_11_ASSOCIATE, + 0, CMD_OPTION_WAITFORRSP, 0, assoc_req); done: lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); @@ -151,10 +151,10 @@ int libertas_start_adhoc_network(wlan_private * priv, struct assoc_request * ass if (adapter->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) { lbs_deb_join("AdhocStart: Short preamble\n"); - adapter->preamble = cmd_type_short_preamble; + adapter->preamble = CMD_TYPE_SHORT_PREAMBLE; } else { lbs_deb_join("AdhocStart: Long preamble\n"); - adapter->preamble = cmd_type_long_preamble; + adapter->preamble = CMD_TYPE_LONG_PREAMBLE; } libertas_set_radio_control(priv); @@ -162,8 +162,8 @@ int libertas_start_adhoc_network(wlan_private * priv, struct assoc_request * ass lbs_deb_join("AdhocStart: channel = %d\n", assoc_req->channel); lbs_deb_join("AdhocStart: band = %d\n", assoc_req->band); - ret = libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_start, - 0, cmd_option_waitforrsp, 0, assoc_req); + ret = libertas_prepare_and_send_command(priv, CMD_802_11_AD_HOC_START, + 0, CMD_OPTION_WAITFORRSP, 0, assoc_req); return ret; } @@ -209,10 +209,10 @@ int libertas_join_adhoc_network(wlan_private * priv, struct assoc_request * asso if ( !(bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) || !(adapter->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) { lbs_deb_join("AdhocJoin: Long preamble\n"); - adapter->preamble = cmd_type_long_preamble; + adapter->preamble = CMD_TYPE_LONG_PREAMBLE; } else { lbs_deb_join("AdhocJoin: Short preamble\n"); - adapter->preamble = cmd_type_short_preamble; + adapter->preamble = CMD_TYPE_SHORT_PREAMBLE; } libertas_set_radio_control(priv); @@ -222,8 +222,8 @@ int libertas_join_adhoc_network(wlan_private * priv, struct assoc_request * asso adapter->adhoccreate = 0; - ret = libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_join, - 0, cmd_option_waitforrsp, + ret = libertas_prepare_and_send_command(priv, CMD_802_11_AD_HOC_JOIN, + 0, CMD_OPTION_WAITFORRSP, OID_802_11_SSID, assoc_req); return ret; @@ -231,8 +231,8 @@ int libertas_join_adhoc_network(wlan_private * priv, struct assoc_request * asso int libertas_stop_adhoc_network(wlan_private * priv) { - return libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_stop, - 0, cmd_option_waitforrsp, 0, NULL); + return libertas_prepare_and_send_command(priv, CMD_802_11_AD_HOC_STOP, + 0, CMD_OPTION_WAITFORRSP, 0, NULL); } /** @@ -243,8 +243,8 @@ int libertas_stop_adhoc_network(wlan_private * priv) */ int libertas_send_deauthentication(wlan_private * priv) { - return libertas_prepare_and_send_command(priv, cmd_802_11_deauthenticate, - 0, cmd_option_waitforrsp, 0, NULL); + return libertas_prepare_and_send_command(priv, CMD_802_11_DEAUTHENTICATE, + 0, CMD_OPTION_WAITFORRSP, 0, NULL); } /** @@ -267,7 +267,7 @@ int libertas_cmd_80211_authenticate(wlan_private * priv, lbs_deb_enter(LBS_DEB_JOIN); - cmd->command = cpu_to_le16(cmd_802_11_authenticate); + cmd->command = cpu_to_le16(CMD_802_11_AUTHENTICATE); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_authenticate) + S_DS_GEN); @@ -307,7 +307,7 @@ int libertas_cmd_80211_deauthenticate(wlan_private * priv, lbs_deb_enter(LBS_DEB_JOIN); - cmd->command = cpu_to_le16(cmd_802_11_deauthenticate); + cmd->command = cpu_to_le16(CMD_802_11_DEAUTHENTICATE); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_deauthenticate) + S_DS_GEN); @@ -349,7 +349,7 @@ int libertas_cmd_80211_associate(wlan_private * priv, goto done; } - cmd->command = cpu_to_le16(cmd_802_11_associate); + cmd->command = cpu_to_le16(CMD_802_11_ASSOCIATE); memcpy(passo->peerstaaddr, bss->bssid, sizeof(passo->peerstaaddr)); pos += sizeof(passo->peerstaaddr); @@ -465,7 +465,7 @@ int libertas_cmd_80211_ad_hoc_start(wlan_private * priv, goto done; } - cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_start); + cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_START); /* * Fill in the parameters for 2 data structures: @@ -487,7 +487,7 @@ int libertas_cmd_80211_ad_hoc_start(wlan_private * priv, assoc_req->ssid_len); /* set the BSS type */ - adhs->bsstype = cmd_bss_type_ibss; + adhs->bsstype = CMD_BSS_TYPE_IBSS; adapter->mode = IW_MODE_ADHOC; adhs->beaconperiod = cpu_to_le16(adapter->beaconperiod); @@ -524,7 +524,7 @@ int libertas_cmd_80211_ad_hoc_start(wlan_private * priv, adhs->capability = cpu_to_le16(tmpcap); /* probedelay */ - adhs->probedelay = cpu_to_le16(cmd_scan_probe_delay_time); + adhs->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME); memset(adhs->datarate, 0, sizeof(adhs->datarate)); @@ -569,7 +569,7 @@ done: int libertas_cmd_80211_ad_hoc_stop(wlan_private * priv, struct cmd_ds_command *cmd) { - cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_stop); + cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_STOP); cmd->size = cpu_to_le16(S_DS_GEN); return 0; @@ -590,9 +590,9 @@ int libertas_cmd_80211_ad_hoc_join(wlan_private * priv, lbs_deb_enter(LBS_DEB_JOIN); - cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_join); + cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_JOIN); - join_cmd->bss.type = cmd_bss_type_ibss; + join_cmd->bss.type = CMD_BSS_TYPE_IBSS; join_cmd->bss.beaconperiod = cpu_to_le16(bss->beaconperiod); memcpy(&join_cmd->bss.bssid, &bss->bssid, ETH_ALEN); @@ -617,7 +617,7 @@ int libertas_cmd_80211_ad_hoc_join(wlan_private * priv, join_cmd->failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT); /* probedelay */ - join_cmd->probedelay = cpu_to_le16(cmd_scan_probe_delay_time); + join_cmd->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME); /* Copy Data rates from the rates recorded in scan response */ memset(join_cmd->bss.datarates, 0, sizeof(join_cmd->bss.datarates)); @@ -659,14 +659,14 @@ int libertas_cmd_80211_ad_hoc_join(wlan_private * priv, join_cmd->bss.capability = cpu_to_le16(tmp); } - if (adapter->psmode == wlan802_11powermodemax_psp) { + if (adapter->psmode == WLAN802_11POWERMODEMAX_PSP) { /* wake up first */ __le32 Localpsmode; - Localpsmode = cpu_to_le32(wlan802_11powermodecam); + Localpsmode = cpu_to_le32(WLAN802_11POWERMODECAM); ret = libertas_prepare_and_send_command(priv, - cmd_802_11_ps_mode, - cmd_act_set, + CMD_802_11_PS_MODE, + CMD_ACT_SET, 0, 0, &Localpsmode); if (ret) { @@ -722,7 +722,7 @@ int libertas_ret_80211_associate(wlan_private * priv, le16_to_cpu(resp->size) - S_DS_GEN); /* Send a Media Connected event, according to the Spec */ - adapter->connect_status = libertas_connected; + adapter->connect_status = LIBERTAS_CONNECTED; lbs_deb_join("ASSOC_RESP: assocated to '%s'\n", escape_essid(bss->ssid, bss->ssid_len)); @@ -802,7 +802,7 @@ int libertas_ret_80211_ad_hoc_start(wlan_private * priv, */ if (result) { lbs_deb_join("ADHOC_RESP: failed\n"); - if (adapter->connect_status == libertas_connected) { + if (adapter->connect_status == LIBERTAS_CONNECTED) { libertas_mac_event_disconnected(priv); } ret = -1; @@ -817,9 +817,9 @@ int libertas_ret_80211_ad_hoc_start(wlan_private * priv, escape_essid(bss->ssid, bss->ssid_len)); /* Send a Media Connected event, according to the Spec */ - adapter->connect_status = libertas_connected; + adapter->connect_status = LIBERTAS_CONNECTED; - if (command == cmd_ret_802_11_ad_hoc_start) { + if (command == CMD_RET_802_11_AD_HOC_START) { /* Update the created network descriptor with the new BSSID */ memcpy(bss->bssid, padhocresult->bssid, ETH_ALEN); } diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 9f366242c39..2315eb61836 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -187,9 +187,9 @@ static ssize_t libertas_anycast_get(struct device * dev, memset(&mesh_access, 0, sizeof(mesh_access)); libertas_prepare_and_send_command(to_net_dev(dev)->priv, - cmd_mesh_access, - cmd_act_mesh_get_anycast, - cmd_option_waitforrsp, 0, (void *)&mesh_access); + CMD_MESH_ACCESS, + CMD_ACT_MESH_GET_ANYCAST, + CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access); return snprintf(buf, 12, "0x%X\n", le32_to_cpu(mesh_access.data[0])); } @@ -208,9 +208,9 @@ static ssize_t libertas_anycast_set(struct device * dev, mesh_access.data[0] = cpu_to_le32(datum); libertas_prepare_and_send_command((to_net_dev(dev))->priv, - cmd_mesh_access, - cmd_act_mesh_set_anycast, - cmd_option_waitforrsp, 0, (void *)&mesh_access); + CMD_MESH_ACCESS, + CMD_ACT_MESH_SET_ANYCAST, + CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access); return strlen(buf); } @@ -264,7 +264,7 @@ static int wlan_dev_open(struct net_device *dev) priv->open = 1; - if (adapter->connect_status == libertas_connected) { + if (adapter->connect_status == LIBERTAS_CONNECTED) { netif_carrier_on(priv->dev); netif_carrier_on(priv->mesh_dev); } else { @@ -439,7 +439,7 @@ static void wlan_tx_timeout(struct net_device *dev) libertas_send_tx_feedback(priv); } else wake_up_interruptible(&priv->mainthread.waitq); - } else if (priv->adapter->connect_status == libertas_connected) { + } else if (priv->adapter->connect_status == LIBERTAS_CONNECTED) { netif_wake_queue(priv->dev); netif_wake_queue(priv->mesh_dev); } @@ -480,9 +480,9 @@ static int wlan_set_mac_address(struct net_device *dev, void *addr) lbs_dbg_hex("addr:", phwaddr->sa_data, ETH_ALEN); memcpy(adapter->current_addr, phwaddr->sa_data, ETH_ALEN); - ret = libertas_prepare_and_send_command(priv, cmd_802_11_mac_address, - cmd_act_set, - cmd_option_waitforrsp, 0, NULL); + ret = libertas_prepare_and_send_command(priv, CMD_802_11_MAC_ADDRESS, + CMD_ACT_SET, + CMD_OPTION_WAITFORRSP, 0, NULL); if (ret) { lbs_deb_net("set MAC address failed\n"); @@ -528,36 +528,36 @@ static void wlan_set_multicast_list(struct net_device *dev) if (dev->flags & IFF_PROMISC) { lbs_deb_net("enable promiscuous mode\n"); adapter->currentpacketfilter |= - cmd_act_mac_promiscuous_enable; + CMD_ACT_MAC_PROMISCUOUS_ENABLE; adapter->currentpacketfilter &= - ~(cmd_act_mac_all_multicast_enable | - cmd_act_mac_multicast_enable); + ~(CMD_ACT_MAC_ALL_MULTICAST_ENABLE | + CMD_ACT_MAC_MULTICAST_ENABLE); } else { /* Multicast */ adapter->currentpacketfilter &= - ~cmd_act_mac_promiscuous_enable; + ~CMD_ACT_MAC_PROMISCUOUS_ENABLE; if (dev->flags & IFF_ALLMULTI || dev->mc_count > MRVDRV_MAX_MULTICAST_LIST_SIZE) { lbs_deb_net( "enabling all multicast\n"); adapter->currentpacketfilter |= - cmd_act_mac_all_multicast_enable; + CMD_ACT_MAC_ALL_MULTICAST_ENABLE; adapter->currentpacketfilter &= - ~cmd_act_mac_multicast_enable; + ~CMD_ACT_MAC_MULTICAST_ENABLE; } else { adapter->currentpacketfilter &= - ~cmd_act_mac_all_multicast_enable; + ~CMD_ACT_MAC_ALL_MULTICAST_ENABLE; if (!dev->mc_count) { lbs_deb_net("no multicast addresses, " "disabling multicast\n"); adapter->currentpacketfilter &= - ~cmd_act_mac_multicast_enable; + ~CMD_ACT_MAC_MULTICAST_ENABLE; } else { int i; adapter->currentpacketfilter |= - cmd_act_mac_multicast_enable; + CMD_ACT_MAC_MULTICAST_ENABLE; adapter->nr_of_multicastmacaddr = wlan_copy_multicast_address(adapter, dev); @@ -577,8 +577,8 @@ static void wlan_set_multicast_list(struct net_device *dev) } /* send multicast addresses to firmware */ libertas_prepare_and_send_command(priv, - cmd_mac_multicast_adr, - cmd_act_set, 0, 0, + CMD_MAC_MULTICAST_ADR, + CMD_ACT_SET, 0, 0, NULL); } } @@ -711,7 +711,7 @@ static int wlan_service_main_thread(void *data) if (adapter->psstate == PS_STATE_PRE_SLEEP) { if (!priv->dnld_sent && !adapter->cur_cmd) { if (adapter->connect_status == - libertas_connected) { + LIBERTAS_CONNECTED) { lbs_deb_thread( "main_thread: PRE_SLEEP--intcounter=%d currenttxskb=%p " "dnld_sent=%d cur_cmd=%p, confirm now\n", @@ -1005,9 +1005,9 @@ int libertas_remove_card(wlan_private *priv) cancel_delayed_work(&priv->assoc_work); destroy_workqueue(priv->assoc_thread); - if (adapter->psmode == wlan802_11powermodemax_psp) { - adapter->psmode = wlan802_11powermodecam; - libertas_ps_wakeup(priv, cmd_option_waitforrsp); + if (adapter->psmode == WLAN802_11POWERMODEMAX_PSP) { + adapter->psmode = WLAN802_11POWERMODECAM; + libertas_ps_wakeup(priv, CMD_OPTION_WAITFORRSP); } memset(wrqu.ap_addr.sa_data, 0xaa, ETH_ALEN); diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 2937f79c4a0..2cac47fc4cd 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -255,7 +255,7 @@ static void wlan_scan_create_channel_list(wlan_private * priv, for (rgnidx = 0; rgnidx < ARRAY_SIZE(adapter->region_channel); rgnidx++) { if (priv->adapter->enable11d && - adapter->connect_status != libertas_connected) { + adapter->connect_status != LIBERTAS_CONNECTED) { /* Scan all the supported chan for the first scan */ if (!adapter->universal_channel[rgnidx].valid) continue; @@ -287,11 +287,11 @@ static void wlan_scan_create_channel_list(wlan_private * priv, case BAND_G: default: scanchanlist[chanidx].radiotype = - cmd_scan_radio_type_bg; + CMD_SCAN_RADIO_TYPE_BG; break; } - if (scantype == cmd_scan_type_passive) { + if (scantype == CMD_SCAN_TYPE_PASSIVE) { scanchanlist[chanidx].maxscantime = cpu_to_le16(MRVDRV_PASSIVE_SCAN_CHAN_TIME); scanchanlist[chanidx].chanscanmode.passivescan = @@ -486,7 +486,7 @@ wlan_scan_setup_scan_config(wlan_private * priv, scantype = puserscanin->chanlist[chanidx].scantype; - if (scantype == cmd_scan_type_passive) { + if (scantype == CMD_SCAN_TYPE_PASSIVE) { (pscanchanlist + chanidx)->chanscanmode.passivescan = 1; } else { @@ -498,7 +498,7 @@ wlan_scan_setup_scan_config(wlan_private * priv, scandur = puserscanin->chanlist[chanidx].scantime; } else { - if (scantype == cmd_scan_type_passive) { + if (scantype == CMD_SCAN_TYPE_PASSIVE) { scandur = MRVDRV_PASSIVE_SCAN_CHAN_TIME; } else { scandur = MRVDRV_ACTIVE_SCAN_CHAN_TIME; @@ -668,7 +668,7 @@ static int wlan_scan_channel_list(wlan_private * priv, } /* Send the scan command to the firmware with the specified cfg */ - ret = libertas_prepare_and_send_command(priv, cmd_802_11_scan, 0, + ret = libertas_prepare_and_send_command(priv, CMD_802_11_SCAN, 0, 0, 0, pscancfgout); if (scanned >= 2 && !full_scan) { ret = 0; @@ -816,7 +816,7 @@ int wlan_scan_networks(wlan_private * priv, mutex_unlock(&adapter->lock); #endif - if (priv->adapter->connect_status == libertas_connected) { + if (priv->adapter->connect_status == LIBERTAS_CONNECTED) { netif_carrier_on(priv->dev); netif_wake_queue(priv->dev); netif_carrier_on(priv->mesh_dev); @@ -1603,8 +1603,8 @@ int libertas_get_scan(struct net_device *dev, struct iw_request_info *info, /* Update RSSI if current BSS is a locally created ad-hoc BSS */ if ((adapter->mode == IW_MODE_ADHOC) && adapter->adhoccreate) { - libertas_prepare_and_send_command(priv, cmd_802_11_rssi, 0, - cmd_option_waitforrsp, 0, NULL); + libertas_prepare_and_send_command(priv, CMD_802_11_RSSI, 0, + CMD_OPTION_WAITFORRSP, 0, NULL); } mutex_lock(&adapter->lock); @@ -1680,7 +1680,7 @@ int libertas_cmd_80211_scan(wlan_private * priv, memcpy(pscan->bssid, pscancfg->bssid, ETH_ALEN); memcpy(pscan->tlvbuffer, pscancfg->tlvbuffer, pscancfg->tlvbufferlen); - cmd->command = cpu_to_le16(cmd_802_11_scan); + cmd->command = cpu_to_le16(CMD_802_11_SCAN); /* size is equal to the sizeof(fixed portions) + the TLV len + header */ cmd->size = cpu_to_le16(sizeof(pscan->bsstype) + ETH_ALEN diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c index 17c437635a0..c2271020aaf 100644 --- a/drivers/net/wireless/libertas/tx.c +++ b/drivers/net/wireless/libertas/tx.c @@ -283,7 +283,7 @@ void libertas_send_tx_feedback(wlan_private * priv) libertas_upload_rx_packet(priv, adapter->currenttxskb); adapter->currenttxskb = NULL; priv->adapter->TxLockFlag = 0; - if (priv->adapter->connect_status == libertas_connected) { + if (priv->adapter->connect_status == LIBERTAS_CONNECTED) { netif_wake_queue(priv->dev); netif_wake_queue(priv->mesh_dev); } diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index f7df8c71a54..7cfca5f3a5e 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -177,9 +177,9 @@ int wlan_radio_ioctl(wlan_private * priv, u8 option) adapter->radioon = option; ret = libertas_prepare_and_send_command(priv, - cmd_802_11_radio_control, - cmd_act_set, - cmd_option_waitforrsp, 0, NULL); + CMD_802_11_RADIO_CONTROL, + CMD_ACT_SET, + CMD_OPTION_WAITFORRSP, 0, NULL); } lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); @@ -221,7 +221,7 @@ static int get_active_data_rates(wlan_adapter * adapter, lbs_deb_enter(LBS_DEB_WEXT); - if (adapter->connect_status != libertas_connected) { + if (adapter->connect_status != LIBERTAS_CONNECTED) { if (adapter->mode == IW_MODE_INFRA) { lbs_deb_wext("infra\n"); k = copyrates(rates, k, libertas_supported_rates, @@ -305,7 +305,7 @@ static int wlan_get_wap(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); - if (adapter->connect_status == libertas_connected) { + if (adapter->connect_status == LIBERTAS_CONNECTED) { memcpy(awrq->sa_data, adapter->curbssparams.bssid, ETH_ALEN); } else { memset(awrq->sa_data, 0, ETH_ALEN); @@ -382,7 +382,7 @@ static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info, /* Use nickname to indicate that mesh is on */ - if (adapter->connect_status == libertas_connected) { + if (adapter->connect_status == LIBERTAS_CONNECTED) { strncpy(extra, "Mesh", 12); extra[12] = '\0'; dwrq->length = strlen(extra) + 1; @@ -414,8 +414,8 @@ static int wlan_set_rts(struct net_device *dev, struct iw_request_info *info, adapter->rtsthsd = rthr; } - ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib, - cmd_act_set, cmd_option_waitforrsp, + ret = libertas_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB, + CMD_ACT_SET, CMD_OPTION_WAITFORRSP, OID_802_11_RTS_THRESHOLD, &rthr); lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); @@ -432,8 +432,8 @@ static int wlan_get_rts(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); adapter->rtsthsd = 0; - ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib, - cmd_act_get, cmd_option_waitforrsp, + ret = libertas_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB, + CMD_ACT_GET, CMD_OPTION_WAITFORRSP, OID_802_11_RTS_THRESHOLD, NULL); if (ret) goto out; @@ -467,8 +467,8 @@ static int wlan_set_frag(struct net_device *dev, struct iw_request_info *info, adapter->fragthsd = fthr; } - ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib, - cmd_act_set, cmd_option_waitforrsp, + ret = libertas_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB, + CMD_ACT_SET, CMD_OPTION_WAITFORRSP, OID_802_11_FRAGMENTATION_THRESHOLD, &fthr); lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); @@ -486,8 +486,8 @@ static int wlan_get_frag(struct net_device *dev, struct iw_request_info *info, adapter->fragthsd = 0; ret = libertas_prepare_and_send_command(priv, - cmd_802_11_snmp_mib, - cmd_act_get, cmd_option_waitforrsp, + CMD_802_11_SNMP_MIB, + CMD_ACT_GET, CMD_OPTION_WAITFORRSP, OID_802_11_FRAGMENTATION_THRESHOLD, NULL); if (ret) goto out; @@ -539,9 +539,9 @@ static int wlan_get_txpow(struct net_device *dev, lbs_deb_enter(LBS_DEB_WEXT); ret = libertas_prepare_and_send_command(priv, - cmd_802_11_rf_tx_power, - cmd_act_tx_power_opt_get, - cmd_option_waitforrsp, 0, NULL); + CMD_802_11_RF_TX_POWER, + CMD_ACT_TX_POWER_OPT_GET, + CMD_OPTION_WAITFORRSP, 0, NULL); if (ret) goto out; @@ -581,9 +581,9 @@ static int wlan_set_retry(struct net_device *dev, struct iw_request_info *info, /* Adding 1 to convert retry count to try count */ adapter->txretrycount = vwrq->value + 1; - ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib, - cmd_act_set, - cmd_option_waitforrsp, + ret = libertas_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB, + CMD_ACT_SET, + CMD_OPTION_WAITFORRSP, OID_802_11_TX_RETRYCOUNT, NULL); if (ret) @@ -608,8 +608,8 @@ static int wlan_get_retry(struct net_device *dev, struct iw_request_info *info, adapter->txretrycount = 0; ret = libertas_prepare_and_send_command(priv, - cmd_802_11_snmp_mib, - cmd_act_get, cmd_option_waitforrsp, + CMD_802_11_SNMP_MIB, + CMD_ACT_GET, CMD_OPTION_WAITFORRSP, OID_802_11_TX_RETRYCOUNT, NULL); if (ret) goto out; @@ -698,7 +698,7 @@ static int wlan_get_range(struct net_device *dev, struct iw_request_info *info, range->num_frequency = 0; if (priv->adapter->enable11d && - adapter->connect_status == libertas_connected) { + adapter->connect_status == LIBERTAS_CONNECTED) { u8 chan_no; u8 band; @@ -858,9 +858,9 @@ static int wlan_set_power(struct net_device *dev, struct iw_request_info *info, */ if (vwrq->disabled) { - adapter->psmode = wlan802_11powermodecam; + adapter->psmode = WLAN802_11POWERMODECAM; if (adapter->psstate != PS_STATE_FULL_POWER) { - libertas_ps_wakeup(priv, cmd_option_waitforrsp); + libertas_ps_wakeup(priv, CMD_OPTION_WAITFORRSP); } return 0; @@ -875,14 +875,14 @@ static int wlan_set_power(struct net_device *dev, struct iw_request_info *info, return -EINVAL; } - if (adapter->psmode != wlan802_11powermodecam) { + if (adapter->psmode != WLAN802_11POWERMODECAM) { return 0; } - adapter->psmode = wlan802_11powermodemax_psp; + adapter->psmode = WLAN802_11POWERMODEMAX_PSP; - if (adapter->connect_status == libertas_connected) { - libertas_ps_sleep(priv, cmd_option_waitforrsp); + if (adapter->connect_status == LIBERTAS_CONNECTED) { + libertas_ps_sleep(priv, CMD_OPTION_WAITFORRSP); } lbs_deb_leave(LBS_DEB_WEXT); @@ -900,8 +900,8 @@ static int wlan_get_power(struct net_device *dev, struct iw_request_info *info, mode = adapter->psmode; - if ((vwrq->disabled = (mode == wlan802_11powermodecam)) - || adapter->connect_status == libertas_disconnected) + if ((vwrq->disabled = (mode == WLAN802_11POWERMODECAM)) + || adapter->connect_status == LIBERTAS_DISCONNECTED) { goto out; } @@ -937,7 +937,7 @@ static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev) priv->wstats.status = adapter->mode; /* If we're not associated, all quality values are meaningless */ - if (adapter->connect_status != libertas_connected) + if (adapter->connect_status != LIBERTAS_CONNECTED) goto out; /* Quality by RSSI */ @@ -1000,9 +1000,9 @@ static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev) stats_valid = 1; /* update stats asynchronously for future calls */ - libertas_prepare_and_send_command(priv, cmd_802_11_rssi, 0, + libertas_prepare_and_send_command(priv, CMD_802_11_RSSI, 0, 0, 0, NULL); - libertas_prepare_and_send_command(priv, cmd_802_11_get_log, 0, + libertas_prepare_and_send_command(priv, CMD_802_11_GET_LOG, 0, 0, 0, NULL); out: if (!stats_valid) { @@ -1128,7 +1128,7 @@ static int wlan_set_rate(struct net_device *dev, struct iw_request_info *info, lbs_deb_wext("vwrq->value %d\n", vwrq->value); if (vwrq->value == -1) { - action = cmd_act_set_tx_auto; // Auto + action = CMD_ACT_SET_tx_auto; // Auto adapter->is_datarate_auto = 1; adapter->datarate = 0; } else { @@ -1155,12 +1155,12 @@ static int wlan_set_rate(struct net_device *dev, struct iw_request_info *info, } adapter->datarate = data_rate; - action = cmd_act_set_tx_fix_rate; + action = CMD_ACT_SET_tx_fix_rate; adapter->is_datarate_auto = 0; } - ret = libertas_prepare_and_send_command(priv, cmd_802_11_data_rate, - action, cmd_option_waitforrsp, 0, NULL); + ret = libertas_prepare_and_send_command(priv, CMD_802_11_DATA_RATE, + action, CMD_OPTION_WAITFORRSP, 0, NULL); lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); return ret; @@ -1976,7 +1976,7 @@ static int wlan_set_txpow(struct net_device *dev, struct iw_request_info *info, return 0; } - adapter->preamble = cmd_type_auto_preamble; + adapter->preamble = CMD_TYPE_AUTO_PREAMBLE; wlan_radio_ioctl(priv, RADIO_ON); @@ -1993,9 +1993,9 @@ static int wlan_set_txpow(struct net_device *dev, struct iw_request_info *info, lbs_deb_wext("txpower set %d dbm\n", dbm); ret = libertas_prepare_and_send_command(priv, - cmd_802_11_rf_tx_power, - cmd_act_tx_power_opt_set_low, - cmd_option_waitforrsp, 0, (void *)&dbm); + CMD_802_11_RF_TX_POWER, + CMD_ACT_TX_POWER_OPT_SET_LOW, + CMD_OPTION_WAITFORRSP, 0, (void *)&dbm); lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); return ret; @@ -2017,7 +2017,7 @@ static int wlan_get_essid(struct net_device *dev, struct iw_request_info *info, /* * Get the current SSID */ - if (adapter->connect_status == libertas_connected) { + if (adapter->connect_status == LIBERTAS_CONNECTED) { memcpy(extra, adapter->curbssparams.ssid, adapter->curbssparams.ssid_len); extra[adapter->curbssparams.ssid_len] = '\0'; -- cgit v1.2.3-70-g09d2 From 2ca10e6d6a3052e7a8380b20588a7b1985ea1197 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 11:31:49 -0400 Subject: [PATCH] libertas: fix debug build breakage due to field rename Missed when fixing mixed-case structure field names. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/join.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c index 3530c23da79..381739d6ed9 100644 --- a/drivers/net/wireless/libertas/join.c +++ b/drivers/net/wireless/libertas/join.c @@ -845,7 +845,7 @@ int libertas_ret_80211_ad_hoc_start(wlan_private * priv, lbs_deb_join("ADHOC_RESP: - Joined/Started Ad Hoc\n"); lbs_deb_join("ADHOC_RESP: channel = %d\n", adapter->curbssparams.channel); lbs_deb_join("ADHOC_RESP: BSSID = " MAC_FMT "\n", - MAC_ARG(padhocresult->BSSID)); + MAC_ARG(padhocresult->bssid)); done: lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); -- cgit v1.2.3-70-g09d2 From fe3361507af44d00d5b42b91c1626321765a11bc Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 11:32:25 -0400 Subject: [PATCH] libertas: remove thread.h and make kthread usage clearer Remove the thread.h abstractions and opencode kthread stuff to make it clearer. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 4 +-- drivers/net/wireless/libertas/debugfs.c | 26 ++++++++--------- drivers/net/wireless/libertas/dev.h | 4 +-- drivers/net/wireless/libertas/fw.c | 2 +- drivers/net/wireless/libertas/if_usb.c | 2 +- drivers/net/wireless/libertas/main.c | 36 +++++++++++------------ drivers/net/wireless/libertas/thread.h | 52 --------------------------------- 7 files changed, 37 insertions(+), 89 deletions(-) delete mode 100644 drivers/net/wireless/libertas/thread.h (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index e0eab6e3a9b..401a630ed4e 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -1134,7 +1134,7 @@ int libertas_prepare_and_send_command(wlan_private * priv, lbs_deb_cmd("PREP_CMD: No free cmdnode\n"); /* Wake up main thread to execute next command */ - wake_up_interruptible(&priv->mainthread.waitq); + wake_up_interruptible(&priv->waitq); ret = -1; goto done; } @@ -1402,7 +1402,7 @@ int libertas_prepare_and_send_command(wlan_private * priv, libertas_queue_cmd(adapter, cmdnode, 1); adapter->nr_cmd_pending++; - wake_up_interruptible(&priv->mainthread.waitq); + wake_up_interruptible(&priv->waitq); if (wait_option & CMD_OPTION_WAITFORRSP) { lbs_deb_cmd("PREP_CMD: Wait for CMD response\n"); diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c index a206f49f810..9439005db4e 100644 --- a/drivers/net/wireless/libertas/debugfs.c +++ b/drivers/net/wireless/libertas/debugfs.c @@ -432,7 +432,7 @@ static ssize_t libertas_lowrssi_read(struct file *file, char __user *userbuf, event->action = cpu_to_le16(CMD_ACT_GET); pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN); libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->mainthread.waitq); + wake_up_interruptible(&priv->waitq); /* Sleep until response is generated by FW */ wait_event_interruptible(pcmdnode->cmdwait_q, @@ -496,7 +496,7 @@ static u16 libertas_get_events_bitmap(wlan_private *priv) event->action = cpu_to_le16(CMD_ACT_GET); pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN); libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->mainthread.waitq); + wake_up_interruptible(&priv->waitq); /* Sleep until response is generated by FW */ wait_event_interruptible(pcmdnode->cmdwait_q, @@ -575,7 +575,7 @@ static ssize_t libertas_lowrssi_write(struct file *file, event->events = cpu_to_le16(event_bitmap); libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->mainthread.waitq); + wake_up_interruptible(&priv->waitq); /* Sleep until response is generated by FW */ wait_event_interruptible(pcmdnode->cmdwait_q, @@ -628,7 +628,7 @@ static ssize_t libertas_lowsnr_read(struct file *file, char __user *userbuf, event->action = cpu_to_le16(CMD_ACT_GET); pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN); libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->mainthread.waitq); + wake_up_interruptible(&priv->waitq); /* Sleep until response is generated by FW */ wait_event_interruptible(pcmdnode->cmdwait_q, @@ -727,7 +727,7 @@ static ssize_t libertas_lowsnr_write(struct file *file, event->events = cpu_to_le16(event_bitmap); libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->mainthread.waitq); + wake_up_interruptible(&priv->waitq); /* Sleep until response is generated by FW */ wait_event_interruptible(pcmdnode->cmdwait_q, @@ -781,7 +781,7 @@ static ssize_t libertas_failcount_read(struct file *file, char __user *userbuf, event->action = cpu_to_le16(CMD_ACT_GET); pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN); libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->mainthread.waitq); + wake_up_interruptible(&priv->waitq); /* Sleep until response is generated by FW */ wait_event_interruptible(pcmdnode->cmdwait_q, @@ -879,7 +879,7 @@ static ssize_t libertas_failcount_write(struct file *file, event->events = cpu_to_le16(event_bitmap); libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->mainthread.waitq); + wake_up_interruptible(&priv->waitq); /* Sleep until response is generated by FW */ wait_event_interruptible(pcmdnode->cmdwait_q, @@ -932,7 +932,7 @@ static ssize_t libertas_bcnmiss_read(struct file *file, char __user *userbuf, event->action = cpu_to_le16(CMD_ACT_GET); pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN); libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->mainthread.waitq); + wake_up_interruptible(&priv->waitq); /* Sleep until response is generated by FW */ wait_event_interruptible(pcmdnode->cmdwait_q, @@ -1029,7 +1029,7 @@ static ssize_t libertas_bcnmiss_write(struct file *file, event->events = cpu_to_le16(event_bitmap); libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->mainthread.waitq); + wake_up_interruptible(&priv->waitq); /* Sleep until response is generated by FW */ wait_event_interruptible(pcmdnode->cmdwait_q, @@ -1082,7 +1082,7 @@ static ssize_t libertas_highrssi_read(struct file *file, char __user *userbuf, event->action = cpu_to_le16(CMD_ACT_GET); pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN); libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->mainthread.waitq); + wake_up_interruptible(&priv->waitq); /* Sleep until response is generated by FW */ wait_event_interruptible(pcmdnode->cmdwait_q, @@ -1181,7 +1181,7 @@ static ssize_t libertas_highrssi_write(struct file *file, event->events = cpu_to_le16(event_bitmap); libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->mainthread.waitq); + wake_up_interruptible(&priv->waitq); /* Sleep until response is generated by FW */ wait_event_interruptible(pcmdnode->cmdwait_q, @@ -1232,7 +1232,7 @@ static ssize_t libertas_highsnr_read(struct file *file, char __user *userbuf, event->action = cpu_to_le16(CMD_ACT_GET); pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN); libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->mainthread.waitq); + wake_up_interruptible(&priv->waitq); /* Sleep until response is generated by FW */ wait_event_interruptible(pcmdnode->cmdwait_q, @@ -1331,7 +1331,7 @@ static ssize_t libertas_highsnr_write(struct file *file, event->events = cpu_to_le16(event_bitmap); libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->mainthread.waitq); + wake_up_interruptible(&priv->waitq); /* Sleep until response is generated by FW */ wait_event_interruptible(pcmdnode->cmdwait_q, diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 184eee54857..c6fb703f665 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -14,7 +14,6 @@ #include "defs.h" #include "scan.h" -#include "thread.h" extern struct ethtool_ops libertas_ethtool_ops; @@ -146,7 +145,8 @@ struct _wlan_private { struct device *hotplug_device; /** thread to service interrupts */ - struct wlan_thread mainthread; + struct task_struct *main_thread; + wait_queue_head_t waitq; struct delayed_work assoc_work; struct workqueue_struct *assoc_thread; diff --git a/drivers/net/wireless/libertas/fw.c b/drivers/net/wireless/libertas/fw.c index 39b0a094b62..e7177598f94 100644 --- a/drivers/net/wireless/libertas/fw.c +++ b/drivers/net/wireless/libertas/fw.c @@ -341,7 +341,7 @@ static void command_timer_fn(unsigned long data) lbs_deb_fw("re-sending same command because of timeout\n"); libertas_queue_cmd(adapter, ptempnode, 0); - wake_up_interruptible(&priv->mainthread.waitq); + wake_up_interruptible(&priv->waitq); return; } diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index cf522c6ef57..a3334f63a80 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -77,7 +77,7 @@ static void if_usb_write_bulk_callback(struct urb *urb) priv->dnld_sent = DNLD_RES_RECEIVED; /* Wake main thread if commands are pending */ if (!adapter->cur_cmd) - wake_up_interruptible(&priv->mainthread.waitq); + wake_up_interruptible(&priv->waitq); if ((adapter->connect_status == LIBERTAS_CONNECTED)) { netif_wake_queue(dev); netif_wake_queue(priv->mesh_dev); diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 2315eb61836..e24875de8dc 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -438,7 +439,7 @@ static void wlan_tx_timeout(struct net_device *dev) priv->adapter->eventcause = 0x01000000; libertas_send_tx_feedback(priv); } else - wake_up_interruptible(&priv->mainthread.waitq); + wake_up_interruptible(&priv->waitq); } else if (priv->adapter->connect_status == LIBERTAS_CONNECTED) { netif_wake_queue(priv->dev); netif_wake_queue(priv->mesh_dev); @@ -599,28 +600,25 @@ static void wlan_set_multicast_list(struct net_device *dev) * @param data A pointer to wlan_thread structure * @return 0 */ -static int wlan_service_main_thread(void *data) +static int libertas_thread(void *data) { - struct wlan_thread *thread = data; - wlan_private *priv = thread->priv; + struct net_device *dev = data; + wlan_private *priv = dev->priv; wlan_adapter *adapter = priv->adapter; wait_queue_t wait; u8 ireg = 0; lbs_deb_enter(LBS_DEB_THREAD); - wlan_activate_thread(thread); - init_waitqueue_entry(&wait, current); - set_freezable(); for (;;) { lbs_deb_thread( "main-thread 111: intcounter=%d " "currenttxskb=%p dnld_sent=%d\n", adapter->intcounter, adapter->currenttxskb, priv->dnld_sent); - add_wait_queue(&thread->waitq, &wait); + add_wait_queue(&priv->waitq, &wait); set_current_state(TASK_INTERRUPTIBLE); spin_lock_irq(&adapter->driver_lock); if ((adapter->psstate == PS_STATE_SLEEP) || @@ -643,7 +641,7 @@ static int wlan_service_main_thread(void *data) adapter->currenttxskb, priv->dnld_sent); set_current_state(TASK_RUNNING); - remove_wait_queue(&thread->waitq, &wait); + remove_wait_queue(&priv->waitq, &wait); try_to_freeze(); lbs_deb_thread("main-thread 333: intcounter=%d currenttxskb=%p " @@ -758,7 +756,6 @@ static int wlan_service_main_thread(void *data) del_timer(&adapter->command_timer); adapter->nr_cmd_pending = 0; wake_up_all(&adapter->cmd_pending); - wlan_deactivate_thread(thread); lbs_deb_leave(LBS_DEB_THREAD); return 0; @@ -841,10 +838,13 @@ int libertas_activate_card(wlan_private *priv, char *fw_name) lbs_deb_enter(LBS_DEB_MAIN); - lbs_deb_thread("Starting kthread...\n"); - priv->mainthread.priv = priv; - wlan_create_thread(wlan_service_main_thread, - &priv->mainthread, "wlan_main_service"); + lbs_deb_thread("Starting main thread...\n"); + init_waitqueue_head(&priv->waitq); + priv->main_thread = kthread_run(libertas_thread, dev, "libertas_main"); + if (IS_ERR(priv->main_thread)) { + lbs_deb_thread("Error creating main thread.\n"); + goto done; + } priv->assoc_thread = create_singlethread_workqueue("libertas_assoc"); @@ -884,8 +884,8 @@ err_init_fw: err_registerdev: destroy_workqueue(priv->assoc_thread); /* Stop the thread servicing the interrupts */ - wake_up_interruptible(&priv->mainthread.waitq); - wlan_terminate_thread(&priv->mainthread); + wake_up_interruptible(&priv->waitq); + kthread_stop(priv->main_thread); done: lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret); return ret; @@ -1017,7 +1017,7 @@ int libertas_remove_card(wlan_private *priv) adapter->surpriseremoved = 1; /* Stop the thread servicing the interrupts */ - wlan_terminate_thread(&priv->mainthread); + kthread_stop(priv->main_thread); libertas_debugfs_remove_one(priv); @@ -1151,7 +1151,7 @@ void libertas_interrupt(struct net_device *dev) netif_wake_queue(priv->mesh_dev); } - wake_up_interruptible(&priv->mainthread.waitq); + wake_up_interruptible(&priv->waitq); lbs_deb_leave(LBS_DEB_THREAD); } diff --git a/drivers/net/wireless/libertas/thread.h b/drivers/net/wireless/libertas/thread.h deleted file mode 100644 index b1f34d92ff3..00000000000 --- a/drivers/net/wireless/libertas/thread.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef __WLAN_THREAD_H_ -#define __WLAN_THREAD_H_ - -#include - -struct wlan_thread { - struct task_struct *task; - wait_queue_head_t waitq; - pid_t pid; - void *priv; -}; - -static inline void wlan_activate_thread(struct wlan_thread * thr) -{ - /** Record the thread pid */ - thr->pid = current->pid; - - /** Initialize the wait queue */ - init_waitqueue_head(&thr->waitq); -} - -static inline void wlan_deactivate_thread(struct wlan_thread * thr) -{ - lbs_deb_enter(LBS_DEB_THREAD); - - thr->pid = 0; - - lbs_deb_leave(LBS_DEB_THREAD); -} - -static inline void wlan_create_thread(int (*wlanfunc) (void *), - struct wlan_thread * thr, char *name) -{ - thr->task = kthread_run(wlanfunc, thr, "%s", name); -} - -static inline int wlan_terminate_thread(struct wlan_thread * thr) -{ - lbs_deb_enter(LBS_DEB_THREAD); - - /* Check if the thread is active or not */ - if (!thr->pid) { - printk(KERN_ERR "Thread does not exist\n"); - return -1; - } - kthread_stop(thr->task); - - lbs_deb_leave(LBS_DEB_THREAD); - return 0; -} - -#endif -- cgit v1.2.3-70-g09d2 From 276c015e1bf8d158df336bc2676c142e4bc391c1 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 11:34:24 -0400 Subject: [PATCH] libertas: new mesh control knobs Support for new mesh control knobs on firmware 5.220.11.p4: Signed-off-by: Luis Carlos Cobo Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/host.h | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index 4bd2e88116c..7af921b0832 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -312,6 +312,14 @@ enum CMD_MESH_ACCESS_opts { CMD_ACT_MESH_GET_STATS, CMD_ACT_MESH_GET_ANYCAST, CMD_ACT_MESH_SET_ANYCAST, + CMD_ACT_MESH_SET_LINK_COSTS, + CMD_ACT_MESH_GET_LINK_COSTS, + CMD_ACT_MESH_SET_BCAST_RATE, + CMD_ACT_MESH_GET_BCAST_RATE, + CMD_ACT_MESH_SET_RREQ_DELAY, + CMD_ACT_MESH_GET_RREQ_DELAY, + CMD_ACT_MESH_SET_ROUTE_EXP, + CMD_ACT_MESH_GET_ROUTE_EXP, }; /** Card Event definition */ -- cgit v1.2.3-70-g09d2 From 125dcabf724bdfbe55240aef3b35b0ca16f3d61d Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 11:34:47 -0400 Subject: [PATCH] libertas: bump version to 322.p1 Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index e24875de8dc..b9e4bf29322 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -22,7 +22,7 @@ #include "debugfs.h" #include "assoc.h" -#define DRIVER_RELEASE_VERSION "322.p0" +#define DRIVER_RELEASE_VERSION "322.p1" const char libertas_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION #ifdef DEBUG "-dbg" -- cgit v1.2.3-70-g09d2 From ffcae953ac021f5051a201c18e133cb0ce38c2b9 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 11:35:46 -0400 Subject: [PATCH] libertas: fix more mixed-case abuse Mistakently introduced by a previous patch to upper-case all command constants. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 6 +++--- drivers/net/wireless/libertas/cmdresp.c | 6 +++--- drivers/net/wireless/libertas/fw.c | 2 +- drivers/net/wireless/libertas/host.h | 24 ++++++++++++------------ drivers/net/wireless/libertas/wext.c | 4 ++-- 5 files changed, 21 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 401a630ed4e..c96ced963d6 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -566,7 +566,7 @@ static int wlan_cmd_802_11_rf_antenna(wlan_private * priv, S_DS_GEN); rant->action = cpu_to_le16(cmd_action); - if ((cmd_action == CMD_ACT_SET_rx) || (cmd_action == CMD_ACT_SET_tx)) { + if ((cmd_action == CMD_ACT_SET_RX) || (cmd_action == CMD_ACT_SET_TX)) { rant->antennamode = cpu_to_le16((u16) (*(u32 *) pdata_buf)); } @@ -614,11 +614,11 @@ static int wlan_cmd_802_11_data_rate(wlan_private * priv, pdatarate->action = cpu_to_le16(cmd_action); - if (cmd_action == CMD_ACT_SET_tx_fix_rate) { + if (cmd_action == CMD_ACT_SET_TX_FIX_RATE) { pdatarate->datarate[0] = libertas_data_rate_to_index(adapter->datarate); lbs_deb_cmd("Setting FW for fixed rate 0x%02X\n", adapter->datarate); - } else if (cmd_action == CMD_ACT_SET_tx_auto) { + } else if (cmd_action == CMD_ACT_SET_TX_AUTO) { lbs_deb_cmd("Setting FW for AUTO rate\n"); } diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 4c15071984b..d90279269e7 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -396,10 +396,10 @@ static int wlan_ret_802_11_rf_antenna(wlan_private * priv, wlan_adapter *adapter = priv->adapter; u16 action = le16_to_cpu(pAntenna->action); - if (action == CMD_ACT_GET_rx) + if (action == CMD_ACT_GET_RX) adapter->rxantennamode = le16_to_cpu(pAntenna->antennamode); - if (action == CMD_ACT_GET_tx) + if (action == CMD_ACT_GET_TX) adapter->txantennamode = le16_to_cpu(pAntenna->antennamode); lbs_deb_cmd("RF_ANT_RESP: action = 0x%x, mode = 0x%04x\n", @@ -438,7 +438,7 @@ static int wlan_ret_802_11_data_rate(wlan_private * priv, (u8 *) pdatarate, sizeof(struct cmd_ds_802_11_data_rate)); dot11datarate = pdatarate->datarate[0]; - if (pdatarate->action == cpu_to_le16(CMD_ACT_GET_tx_rate)) { + if (pdatarate->action == cpu_to_le16(CMD_ACT_GET_TX_RATE)) { memcpy(adapter->libertas_supported_rates, pdatarate->datarate, sizeof(adapter->libertas_supported_rates)); } diff --git a/drivers/net/wireless/libertas/fw.c b/drivers/net/wireless/libertas/fw.c index e7177598f94..d214692eb20 100644 --- a/drivers/net/wireless/libertas/fw.c +++ b/drivers/net/wireless/libertas/fw.c @@ -111,7 +111,7 @@ static int wlan_setup_station_hw(wlan_private * priv, char *fw_name) /* Get the supported Data rates */ ret = libertas_prepare_and_send_command(priv, CMD_802_11_DATA_RATE, - CMD_ACT_GET_tx_rate, + CMD_ACT_GET_TX_RATE, CMD_OPTION_WAITFORRSP, 0, NULL); if (ret) { diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index 7af921b0832..308ccdbed34 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -262,16 +262,16 @@ #define CMD_ACT_TX_POWER_INDEX_LOW 0x0000 /* Define action or option for CMD_802_11_DATA_RATE */ -#define CMD_ACT_SET_tx_auto 0x0000 -#define CMD_ACT_SET_tx_fix_rate 0x0001 -#define CMD_ACT_GET_tx_rate 0x0002 +#define CMD_ACT_SET_TX_AUTO 0x0000 +#define CMD_ACT_SET_TX_FIX_RATE 0x0001 +#define CMD_ACT_GET_TX_RATE 0x0002 -#define CMD_ACT_SET_rx 0x0001 -#define CMD_ACT_SET_tx 0x0002 -#define CMD_ACT_SET_both 0x0003 -#define CMD_ACT_GET_rx 0x0004 -#define CMD_ACT_GET_tx 0x0008 -#define CMD_ACT_GET_both 0x000c +#define CMD_ACT_SET_RX 0x0001 +#define CMD_ACT_SET_TX 0x0002 +#define CMD_ACT_SET_BOTH 0x0003 +#define CMD_ACT_GET_RX 0x0004 +#define CMD_ACT_GET_TX 0x0008 +#define CMD_ACT_GET_BOTH 0x000c /* Define action or option for CMD_802_11_PS_MODE */ #define CMD_TYPE_CAM 0x0000 @@ -279,7 +279,7 @@ #define CMD_TYPE_FAST_PSP 0x0002 /* Define action or option for CMD_BT_ACCESS */ -enum CMD_BT_ACCESS_opts { +enum cmd_bt_access_opts { /* The bt commands start at 5 instead of 1 because the old dft commands * are mapped to 1-4. These old commands are no longer maintained and * should not be called. @@ -293,7 +293,7 @@ enum CMD_BT_ACCESS_opts { }; /* Define action or option for CMD_FWT_ACCESS */ -enum CMD_FWT_ACCESS_opts { +enum cmd_fwt_access_opts { CMD_ACT_FWT_ACCESS_ADD = 1, CMD_ACT_FWT_ACCESS_DEL, CMD_ACT_FWT_ACCESS_LOOKUP, @@ -306,7 +306,7 @@ enum CMD_FWT_ACCESS_opts { }; /* Define action or option for CMD_MESH_ACCESS */ -enum CMD_MESH_ACCESS_opts { +enum cmd_mesh_access_opts { CMD_ACT_MESH_GET_TTL = 1, CMD_ACT_MESH_SET_TTL, CMD_ACT_MESH_GET_STATS, diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 7cfca5f3a5e..115f02c010a 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -1128,7 +1128,7 @@ static int wlan_set_rate(struct net_device *dev, struct iw_request_info *info, lbs_deb_wext("vwrq->value %d\n", vwrq->value); if (vwrq->value == -1) { - action = CMD_ACT_SET_tx_auto; // Auto + action = CMD_ACT_SET_TX_AUTO; // Auto adapter->is_datarate_auto = 1; adapter->datarate = 0; } else { @@ -1155,7 +1155,7 @@ static int wlan_set_rate(struct net_device *dev, struct iw_request_info *info, } adapter->datarate = data_rate; - action = CMD_ACT_SET_tx_fix_rate; + action = CMD_ACT_SET_TX_FIX_RATE; adapter->is_datarate_auto = 0; } -- cgit v1.2.3-70-g09d2 From eedc2a319154a64f5ca7f281c92b7af3691fe73c Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 11:36:22 -0400 Subject: [PATCH] libertas: move generic firmware reset command to common code It's not USB specific, so move it out of the USB interface code. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/decl.h | 2 +- drivers/net/wireless/libertas/if_usb.c | 30 ++++++++++-------------------- drivers/net/wireless/libertas/main.c | 14 ++++++++++++++ 3 files changed, 25 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h index 40f56bb1eac..846e79a77f6 100644 --- a/drivers/net/wireless/libertas/decl.h +++ b/drivers/net/wireless/libertas/decl.h @@ -86,6 +86,6 @@ int libertas_activate_card(wlan_private *priv, char *fw_name); int libertas_remove_card(wlan_private *priv); int libertas_add_mesh(wlan_private *priv, struct device *dev); void libertas_remove_mesh(wlan_private *priv); - +int libertas_reset_device(wlan_private *priv); #endif /* _WLAN_DECL_H_ */ diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index a3334f63a80..e38fce73cf7 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -15,6 +15,7 @@ #include "defs.h" #include "dev.h" #include "if_usb.h" +#include "decl.h" #define MESSAGE_HEADER_LEN 4 @@ -44,7 +45,6 @@ MODULE_DEVICE_TABLE(usb, if_usb_table); static void if_usb_receive(struct urb *urb); static void if_usb_receive_fwload(struct urb *urb); -static int if_usb_reset_device(wlan_private *priv); static int if_usb_register_dev(wlan_private * priv); static int if_usb_unregister_dev(wlan_private *); static int if_usb_prog_firmware(wlan_private *); @@ -355,17 +355,20 @@ static int if_prog_firmware(wlan_private * priv) return 0; } -static int libertas_do_reset(wlan_private *priv) +static int if_usb_reset_device(wlan_private *priv) { int ret; struct usb_card_rec *cardp = priv->card; lbs_deb_enter(LBS_DEB_USB); + /* Try a USB port reset first, if that fails send the reset + * command to the firmware. + */ ret = usb_reset_device(cardp->udev); if (!ret) { msleep(10); - if_usb_reset_device(priv); + ret = libertas_reset_device(priv); msleep(10); } @@ -753,19 +756,6 @@ static int if_usb_read_event_cause(wlan_private * priv) return 0; } -static int if_usb_reset_device(wlan_private *priv) -{ - int ret; - - lbs_deb_enter(LBS_DEB_USB); - ret = libertas_prepare_and_send_command(priv, CMD_802_11_RESET, - CMD_ACT_HALT, 0, 0, NULL); - msleep_interruptible(10); - - lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret); - return ret; -} - static int if_usb_unregister_dev(wlan_private * priv) { int ret = 0; @@ -775,7 +765,7 @@ static int if_usb_unregister_dev(wlan_private * priv) * again. */ if (priv) - if_usb_reset_device(priv); + libertas_reset_device(priv); return ret; } @@ -862,7 +852,7 @@ restart: if (cardp->bootcmdresp == 0) { if (--reset_count >= 0) { - libertas_do_reset(priv); + if_usb_reset_device(priv); goto restart; } return -1; @@ -892,7 +882,7 @@ restart: if (!cardp->fwdnldover) { lbs_pr_info("failed to load fw, resetting device!\n"); if (--reset_count >= 0) { - libertas_do_reset(priv); + if_usb_reset_device(priv); goto restart; } @@ -995,7 +985,7 @@ static void if_usb_exit_module(void) lbs_deb_enter(LBS_DEB_MAIN); list_for_each_entry_safe(cardp, cardp_temp, &usb_devices, list) - if_usb_reset_device((wlan_private *) cardp->priv); + libertas_reset_device((wlan_private *) cardp->priv); /* API unregisters the driver from USB subsystem */ usb_deregister(&if_usb_driver); diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index b9e4bf29322..589c583ddbe 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1157,6 +1157,20 @@ void libertas_interrupt(struct net_device *dev) } EXPORT_SYMBOL_GPL(libertas_interrupt); +int libertas_reset_device(wlan_private *priv) +{ + int ret; + + lbs_deb_enter(LBS_DEB_MAIN); + ret = libertas_prepare_and_send_command(priv, CMD_802_11_RESET, + CMD_ACT_HALT, 0, 0, NULL); + msleep_interruptible(10); + + lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret); + return ret; +} +EXPORT_SYMBOL_GPL(libertas_reset_device); + static int libertas_init_module(void) { lbs_deb_enter(LBS_DEB_MAIN); -- cgit v1.2.3-70-g09d2 From e52414728b930f0adcbc38c6498dd03b3568fe99 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 11:39:19 -0400 Subject: [PATCH] libertas: wlan_ -> libertas_ function prefix renames for main.c Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/main.c | 71 ++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 589c583ddbe..26948595d95 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -256,7 +256,7 @@ static int pre_open_check(struct net_device *dev) * @param dev A pointer to net_device structure * @return 0 */ -static int wlan_dev_open(struct net_device *dev) +static int libertas_dev_open(struct net_device *dev) { wlan_private *priv = (wlan_private *) dev->priv; wlan_adapter *adapter = priv->adapter; @@ -282,7 +282,7 @@ static int wlan_dev_open(struct net_device *dev) * @param dev A pointer to net_device structure * @return 0 */ -static int mesh_open(struct net_device *dev) +static int libertas_mesh_open(struct net_device *dev) { wlan_private *priv = (wlan_private *) dev->priv ; @@ -291,7 +291,7 @@ static int mesh_open(struct net_device *dev) priv->mesh_open = 1 ; netif_wake_queue(priv->mesh_dev); if (priv->infra_open == 0) - return wlan_dev_open(priv->dev) ; + return libertas_dev_open(priv->dev) ; return 0; } @@ -301,7 +301,7 @@ static int mesh_open(struct net_device *dev) * @param dev A pointer to net_device structure * @return 0 */ -static int wlan_open(struct net_device *dev) +static int libertas_open(struct net_device *dev) { wlan_private *priv = (wlan_private *) dev->priv ; @@ -310,11 +310,11 @@ static int wlan_open(struct net_device *dev) priv->infra_open = 1 ; netif_wake_queue(priv->dev); if (priv->open == 0) - return wlan_dev_open(priv->dev) ; + return libertas_dev_open(priv->dev) ; return 0; } -static int wlan_dev_close(struct net_device *dev) +static int libertas_dev_close(struct net_device *dev) { wlan_private *priv = dev->priv; @@ -333,14 +333,14 @@ static int wlan_dev_close(struct net_device *dev) * @param dev A pointer to net_device structure * @return 0 */ -static int mesh_close(struct net_device *dev) +static int libertas_mesh_close(struct net_device *dev) { wlan_private *priv = (wlan_private *) (dev->priv); priv->mesh_open = 0; netif_stop_queue(priv->mesh_dev); if (priv->infra_open == 0) - return wlan_dev_close(dev); + return libertas_dev_close(dev); else return 0; } @@ -351,20 +351,20 @@ static int mesh_close(struct net_device *dev) * @param dev A pointer to net_device structure * @return 0 */ -static int wlan_close(struct net_device *dev) +static int libertas_close(struct net_device *dev) { wlan_private *priv = (wlan_private *) dev->priv; netif_stop_queue(dev); priv->infra_open = 0; if (priv->mesh_open == 0) - return wlan_dev_close(dev); + return libertas_dev_close(dev); else return 0; } -static int wlan_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +static int libertas_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { int ret = 0; wlan_private *priv = dev->priv; @@ -387,10 +387,11 @@ done: } /** - * @brief Mark mesh packets and handover them to wlan_hard_start_xmit + * @brief Mark mesh packets and handover them to libertas_hard_start_xmit * */ -static int mesh_pre_start_xmit(struct sk_buff *skb, struct net_device *dev) +static int libertas_mesh_pre_start_xmit(struct sk_buff *skb, + struct net_device *dev) { wlan_private *priv = dev->priv; int ret; @@ -399,16 +400,16 @@ static int mesh_pre_start_xmit(struct sk_buff *skb, struct net_device *dev) SET_MESH_FRAME(skb); - ret = wlan_hard_start_xmit(skb, priv->dev); + ret = libertas_hard_start_xmit(skb, priv->dev); lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret); return ret; } /** - * @brief Mark non-mesh packets and handover them to wlan_hard_start_xmit + * @brief Mark non-mesh packets and handover them to libertas_hard_start_xmit * */ -static int wlan_pre_start_xmit(struct sk_buff *skb, struct net_device *dev) +static int libertas_pre_start_xmit(struct sk_buff *skb, struct net_device *dev) { int ret; @@ -416,12 +417,12 @@ static int wlan_pre_start_xmit(struct sk_buff *skb, struct net_device *dev) UNSET_MESH_FRAME(skb); - ret = wlan_hard_start_xmit(skb, dev); + ret = libertas_hard_start_xmit(skb, dev); lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret); return ret; } -static void wlan_tx_timeout(struct net_device *dev) +static void libertas_tx_timeout(struct net_device *dev) { wlan_private *priv = (wlan_private *) dev->priv; @@ -454,14 +455,14 @@ static void wlan_tx_timeout(struct net_device *dev) * @param dev A pointer to wlan_private structure * @return A pointer to net_device_stats structure */ -static struct net_device_stats *wlan_get_stats(struct net_device *dev) +static struct net_device_stats *libertas_get_stats(struct net_device *dev) { wlan_private *priv = (wlan_private *) dev->priv; return &priv->stats; } -static int wlan_set_mac_address(struct net_device *dev, void *addr) +static int libertas_set_mac_address(struct net_device *dev, void *addr) { int ret = 0; wlan_private *priv = (wlan_private *) dev->priv; @@ -501,7 +502,7 @@ done: return ret; } -static int wlan_copy_multicast_address(wlan_adapter * adapter, +static int libertas_copy_multicast_address(wlan_adapter * adapter, struct net_device *dev) { int i = 0; @@ -516,7 +517,7 @@ static int wlan_copy_multicast_address(wlan_adapter * adapter, } -static void wlan_set_multicast_list(struct net_device *dev) +static void libertas_set_multicast_list(struct net_device *dev) { wlan_private *priv = dev->priv; wlan_adapter *adapter = priv->adapter; @@ -561,7 +562,7 @@ static void wlan_set_multicast_list(struct net_device *dev) CMD_ACT_MAC_MULTICAST_ENABLE; adapter->nr_of_multicastmacaddr = - wlan_copy_multicast_address(adapter, dev); + libertas_copy_multicast_address(adapter, dev); lbs_deb_net("multicast addresses: %d\n", dev->mc_count); @@ -796,12 +797,12 @@ wlan_private *libertas_add_card(void *card, struct device *dmdev) SET_MODULE_OWNER(dev); /* Setup the OS Interface to our functions */ - dev->open = wlan_open; - dev->hard_start_xmit = wlan_pre_start_xmit; - dev->stop = wlan_close; - dev->set_mac_address = wlan_set_mac_address; - dev->tx_timeout = wlan_tx_timeout; - dev->get_stats = wlan_get_stats; + dev->open = libertas_open; + dev->hard_start_xmit = libertas_pre_start_xmit; + dev->stop = libertas_close; + dev->set_mac_address = libertas_set_mac_address; + dev->tx_timeout = libertas_tx_timeout; + dev->get_stats = libertas_get_stats; dev->watchdog_timeo = 5 * HZ; dev->ethtool_ops = &libertas_ethtool_ops; #ifdef WIRELESS_EXT @@ -810,7 +811,7 @@ wlan_private *libertas_add_card(void *card, struct device *dmdev) #define NETIF_F_DYNALLOC 16 dev->features |= NETIF_F_DYNALLOC; dev->flags |= IFF_BROADCAST | IFF_MULTICAST; - dev->set_multicast_list = wlan_set_multicast_list; + dev->set_multicast_list = libertas_set_multicast_list; SET_NETDEV_DEV(dev, dmdev); @@ -917,11 +918,11 @@ int libertas_add_mesh(wlan_private *priv, struct device *dev) SET_MODULE_OWNER(mesh_dev); - mesh_dev->open = mesh_open; - mesh_dev->hard_start_xmit = mesh_pre_start_xmit; - mesh_dev->stop = mesh_close; - mesh_dev->get_stats = wlan_get_stats; - mesh_dev->set_mac_address = wlan_set_mac_address; + mesh_dev->open = libertas_mesh_open; + mesh_dev->hard_start_xmit = libertas_mesh_pre_start_xmit; + mesh_dev->stop = libertas_mesh_close; + mesh_dev->get_stats = libertas_get_stats; + mesh_dev->set_mac_address = libertas_set_mac_address; mesh_dev->ethtool_ops = &libertas_ethtool_ops; memcpy(mesh_dev->dev_addr, priv->dev->dev_addr, sizeof(priv->dev->dev_addr)); -- cgit v1.2.3-70-g09d2 From 8c5127657549d055ac9d709cdea73902a6ef392c Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 11:40:45 -0400 Subject: [PATCH] libertas: simplify and clean up data rate handling Remove unused/duplicated fields and consolidate static data rate arrays, for example the libertas_supported_rates[] and datarates[] arrays in the bss_descriptor structure, and the libertas_supported_rates field in the wlan_adapter structure. Introduce libertas_fw_index_to_data_rate and libertas_data_rate_to_fw_index functions and use them everywhere firmware requires a rate index rather than a rate array. The firmware requires the 4 basic rates to have the MSB set, but most other stuff doesn't, like WEXT and mesh ioctls. Therefore, only set the MSB on basic rates when pushing rate arrays to firmware instead of doing a ton of (rate & 0x7f) everywhere. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 7 +- drivers/net/wireless/libertas/cmdresp.c | 17 ++- drivers/net/wireless/libertas/decl.h | 4 +- drivers/net/wireless/libertas/defs.h | 11 +- drivers/net/wireless/libertas/dev.h | 16 +-- drivers/net/wireless/libertas/fw.c | 9 +- drivers/net/wireless/libertas/hostcmd.h | 8 +- drivers/net/wireless/libertas/join.c | 203 +++++++++++++++++--------------- drivers/net/wireless/libertas/join.h | 2 + drivers/net/wireless/libertas/main.c | 57 +++++++-- drivers/net/wireless/libertas/rx.c | 9 +- drivers/net/wireless/libertas/scan.c | 54 +++------ drivers/net/wireless/libertas/scan.h | 4 +- drivers/net/wireless/libertas/wext.c | 163 +++++++------------------ 14 files changed, 241 insertions(+), 323 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index c96ced963d6..c3fc074b6e3 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -607,17 +607,14 @@ static int wlan_cmd_802_11_data_rate(wlan_private * priv, cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_data_rate) + S_DS_GEN); - cmd->command = cpu_to_le16(CMD_802_11_DATA_RATE); - memset(pdatarate, 0, sizeof(struct cmd_ds_802_11_data_rate)); - pdatarate->action = cpu_to_le16(cmd_action); if (cmd_action == CMD_ACT_SET_TX_FIX_RATE) { - pdatarate->datarate[0] = libertas_data_rate_to_index(adapter->datarate); + pdatarate->rates[0] = libertas_data_rate_to_fw_index(adapter->cur_rate); lbs_deb_cmd("Setting FW for fixed rate 0x%02X\n", - adapter->datarate); + adapter->cur_rate); } else if (cmd_action == CMD_ACT_SET_TX_AUTO) { lbs_deb_cmd("Setting FW for AUTO rate\n"); } diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index d90279269e7..577c434089b 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -430,21 +430,18 @@ static int wlan_ret_802_11_data_rate(wlan_private * priv, { struct cmd_ds_802_11_data_rate *pdatarate = &resp->params.drate; wlan_adapter *adapter = priv->adapter; - u8 dot11datarate; lbs_deb_enter(LBS_DEB_CMD); - lbs_dbg_hex("DATA_RATE_RESP: data_rate- ", - (u8 *) pdatarate, sizeof(struct cmd_ds_802_11_data_rate)); + lbs_dbg_hex("DATA_RATE_RESP: data_rate- ", (u8 *) pdatarate, + sizeof(struct cmd_ds_802_11_data_rate)); - dot11datarate = pdatarate->datarate[0]; - if (pdatarate->action == cpu_to_le16(CMD_ACT_GET_TX_RATE)) { - memcpy(adapter->libertas_supported_rates, pdatarate->datarate, - sizeof(adapter->libertas_supported_rates)); - } - adapter->datarate = libertas_index_to_data_rate(dot11datarate); + /* FIXME: get actual rates FW can do if this command actually returns + * all data rates supported. + */ + adapter->cur_rate = libertas_fw_index_to_data_rate(pdatarate->rates[0]); - lbs_deb_enter(LBS_DEB_CMD); + lbs_deb_leave(LBS_DEB_CMD); return 0; } diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h index 846e79a77f6..129b021d35f 100644 --- a/drivers/net/wireless/libertas/decl.h +++ b/drivers/net/wireless/libertas/decl.h @@ -44,8 +44,8 @@ int libertas_execute_next_command(wlan_private * priv); int libertas_process_event(wlan_private * priv); void libertas_interrupt(struct net_device *); int libertas_set_radio_control(wlan_private * priv); -u32 libertas_index_to_data_rate(u8 index); -u8 libertas_data_rate_to_index(u32 rate); +u32 libertas_fw_index_to_data_rate(u8 index); +u8 libertas_data_rate_to_fw_index(u32 rate); void libertas_get_fwversion(wlan_adapter * adapter, char *fwversion, int maxlen); void libertas_upload_rx_packet(wlan_private * priv, struct sk_buff *skb); diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h index 862292913c2..a1c6dae1ba4 100644 --- a/drivers/net/wireless/libertas/defs.h +++ b/drivers/net/wireless/libertas/defs.h @@ -246,10 +246,7 @@ static inline void lbs_dbg_hex(char *prompt, u8 * buf, int len) ((((int)(AVG) * (N -1)) + ((u16)(SNRNF) * \ AVG_SCALE)) / N)) -#define B_SUPPORTED_RATES 8 -#define G_SUPPORTED_RATES 14 - -#define WLAN_SUPPORTED_RATES 14 +#define MAX_RATES 14 #define MAX_LEDS 8 @@ -263,11 +260,7 @@ typedef struct _wlan_adapter wlan_adapter; extern const char libertas_driver_version[]; extern u16 libertas_region_code_to_index[MRVDRV_MAX_REGION_CODE]; -extern u8 libertas_supported_rates[G_SUPPORTED_RATES]; - -extern u8 libertas_adhoc_rates_g[G_SUPPORTED_RATES]; - -extern u8 libertas_adhoc_rates_b[4]; +extern u8 libertas_bg_rates[MAX_RATES]; /** ENUM definition*/ /** SNRNF_TYPE */ diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index c6fb703f665..6acb8fb8733 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -72,10 +72,8 @@ struct current_bss_params { u8 band; /** channel */ u8 channel; - /** number of rates supported */ - int numofrates; - /** supported rates*/ - u8 datarates[WLAN_SUPPORTED_RATES]; + /** zero-terminated array of supported data rates */ + u8 rates[MAX_RATES + 1]; }; /** sleep_params */ @@ -296,9 +294,6 @@ struct _wlan_adapter { u32 fragthsd; u32 rtsthsd; - u32 datarate; - u8 is_datarate_auto; - u16 listeninterval; u16 prescan; u8 txretrycount; @@ -364,10 +359,9 @@ struct _wlan_adapter { u8 radioon; u32 preamble; - /** Multi bands Parameter*/ - u8 libertas_supported_rates[G_SUPPORTED_RATES]; - - /** Blue Tooth Co-existence Arbitration */ + /** data rate stuff */ + u8 cur_rate; + u8 auto_rate; /** sleep_params */ struct sleep_params sp; diff --git a/drivers/net/wireless/libertas/fw.c b/drivers/net/wireless/libertas/fw.c index d214692eb20..6c259878da9 100644 --- a/drivers/net/wireless/libertas/fw.c +++ b/drivers/net/wireless/libertas/fw.c @@ -214,7 +214,10 @@ static void wlan_init_adapter(wlan_private * priv) adapter->txantenna = RF_ANTENNA_2; adapter->rxantenna = RF_ANTENNA_AUTO; - adapter->is_datarate_auto = 1; + adapter->auto_rate = 1; + adapter->cur_rate = 0; + adapter->adhoc_grate_enabled = 0; + adapter->beaconperiod = MRVDRV_BEACON_INTERVAL; // set default capabilities @@ -229,10 +232,6 @@ static void wlan_init_adapter(wlan_private * priv) adapter->needtowakeup = 0; adapter->locallisteninterval = 0; /* default value in firmware will be used */ - adapter->datarate = 0; // Initially indicate the rate as auto - - adapter->adhoc_grate_enabled = 0; - adapter->intcounter = 0; adapter->currenttxskb = NULL; diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index 76c5fdeb256..44cf39c8d1b 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -428,8 +428,8 @@ struct PS_CMD_ConfirmSleep { struct cmd_ds_802_11_data_rate { __le16 action; - __le16 reserverd; - u8 datarate[G_SUPPORTED_RATES]; + __le16 reserved; + u8 rates[MAX_RATES]; }; struct cmd_ds_802_11_rate_adapt_rateset { @@ -447,7 +447,7 @@ struct cmd_ds_802_11_ad_hoc_start { union ieeetypes_phyparamset phyparamset; __le16 probedelay; __le16 capability; - u8 datarate[G_SUPPORTED_RATES]; + u8 rates[MAX_RATES]; u8 tlv_memory_size_pad[100]; } __attribute__ ((packed)); @@ -462,7 +462,7 @@ struct adhoc_bssdesc { union ieeetypes_phyparamset phyparamset; union IEEEtypes_ssparamset ssparamset; __le16 capability; - u8 datarates[G_SUPPORTED_RATES]; + u8 rates[MAX_RATES]; /* DO NOT ADD ANY FIELDS TO THIS STRUCTURE. It is used below in the * Adhoc join command and will cause a binary layout mismatch with diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c index 381739d6ed9..78e398d6f5f 100644 --- a/drivers/net/wireless/libertas/join.c +++ b/drivers/net/wireless/libertas/join.c @@ -17,8 +17,12 @@ #include "dev.h" #include "assoc.h" +/* Supported rates for ad-hoc B mode */ +u8 adhoc_rates_b[5] = { 0x02, 0x04, 0x0b, 0x16, 0x00 }; + + /** - * @brief This function finds out the common rates between rate1 and rate2. + * @brief This function finds common rates between rate1 and card rates. * * It will fill common rates in rate1 as output if found. * @@ -27,61 +31,87 @@ * * @param adapter A pointer to wlan_adapter structure * @param rate1 the buffer which keeps input and output - * @param rate1_size the size of rate1 buffer - * @param rate2 the buffer which keeps rate2 - * @param rate2_size the size of rate2 buffer. + * @param rate1_size the size of rate1 buffer; new size of buffer on return * * @return 0 or -1 */ -static int get_common_rates(wlan_adapter * adapter, u8 * rate1, - int rate1_size, u8 * rate2, int rate2_size) +static int get_common_rates(wlan_adapter * adapter, u8 * rates, u16 *rates_size) { - u8 *ptr = rate1; - int ret = 0; + u8 *card_rates = libertas_bg_rates; + size_t num_card_rates = sizeof(libertas_bg_rates); + int ret = 0, i, j; u8 tmp[30]; - int i; + size_t tmp_size = 0; - memset(&tmp, 0, sizeof(tmp)); - memcpy(&tmp, rate1, min_t(size_t, rate1_size, sizeof(tmp))); - memset(rate1, 0, rate1_size); - - /* Mask the top bit of the original values */ - for (i = 0; tmp[i] && i < sizeof(tmp); i++) - tmp[i] &= 0x7F; - - for (i = 0; rate2[i] && i < rate2_size; i++) { - /* Check for Card Rate in tmp, excluding the top bit */ - if (strchr(tmp, rate2[i] & 0x7F)) { - /* values match, so copy the Card Rate to rate1 */ - *rate1++ = rate2[i]; + /* For each rate in card_rates that exists in rate1, copy to tmp */ + for (i = 0; card_rates[i] && (i < num_card_rates); i++) { + for (j = 0; rates[j] && (j < *rates_size); j++) { + if (rates[j] == card_rates[i]) + tmp[tmp_size++] = card_rates[i]; } } - lbs_dbg_hex("rate1 (AP) rates:", tmp, sizeof(tmp)); - lbs_dbg_hex("rate2 (Card) rates:", rate2, rate2_size); - lbs_dbg_hex("Common rates:", ptr, rate1_size); - lbs_deb_join("Tx datarate is set to 0x%X\n", adapter->datarate); + lbs_dbg_hex("rate1 (AP) rates:", rates, *rates_size); + lbs_dbg_hex("rate2 (Card) rates:", card_rates, num_card_rates); + lbs_dbg_hex("Common rates:", tmp, tmp_size); + lbs_deb_join("Tx datarate is currently 0x%X\n", adapter->cur_rate); - if (!adapter->is_datarate_auto) { - while (*ptr) { - if ((*ptr & 0x7f) == adapter->datarate) { - ret = 0; + if (!adapter->auto_rate) { + for (i = 0; i < tmp_size; i++) { + if (tmp[i] == adapter->cur_rate) goto done; - } - ptr++; } - lbs_pr_alert( "Previously set fixed data rate %#x isn't " - "compatible with the network.\n", adapter->datarate); - + lbs_pr_alert("Previously set fixed data rate %#x isn't " + "compatible with the network.\n", adapter->cur_rate); ret = -1; goto done; } - ret = 0; + done: + memset(rates, 0, *rates_size); + *rates_size = min_t(int, tmp_size, *rates_size); + memcpy(rates, tmp, *rates_size); return ret; } + +/** + * @brief Sets the MSB on basic rates as the firmware requires + * + * Scan through an array and set the MSB for basic data rates. + * + * @param rates buffer of data rates + * @param len size of buffer + */ +static void libertas_set_basic_rate_flags(u8 * rates, size_t len) +{ + int i; + + for (i = 0; i < len; i++) { + if (rates[i] == 0x02 || rates[i] == 0x04 || + rates[i] == 0x0b || rates[i] == 0x16) + rates[i] |= 0x80; + } +} + +/** + * @brief Unsets the MSB on basic rates + * + * Scan through an array and unset the MSB for basic data rates. + * + * @param rates buffer of data rates + * @param len size of buffer + */ +void libertas_unset_basic_rate_flags(u8 * rates, size_t len) +{ + int i; + + for (i = 0; i < len; i++) + rates[i] &= 0x7f; +} + + int libertas_send_deauth(wlan_private * priv) { wlan_adapter *adapter = priv->adapter; @@ -330,9 +360,7 @@ int libertas_cmd_80211_associate(wlan_private * priv, int ret = 0; struct assoc_request * assoc_req = pdata_buf; struct bss_descriptor * bss = &assoc_req->bss; - u8 *card_rates; u8 *pos; - int card_rates_size; u16 tmpcap, tmplen; struct mrvlietypes_ssidparamset *ssid; struct mrvlietypes_phyparamset *phy; @@ -386,23 +414,24 @@ int libertas_cmd_80211_associate(wlan_private * priv, rates = (struct mrvlietypes_ratesparamset *) pos; rates->header.type = cpu_to_le16(TLV_TYPE_RATES); - - memcpy(&rates->rates, &bss->libertas_supported_rates, WLAN_SUPPORTED_RATES); - - card_rates = libertas_supported_rates; - card_rates_size = sizeof(libertas_supported_rates); - - if (get_common_rates(adapter, rates->rates, WLAN_SUPPORTED_RATES, - card_rates, card_rates_size)) { + memcpy(&rates->rates, &bss->rates, MAX_RATES); + tmplen = MAX_RATES; + if (get_common_rates(adapter, rates->rates, &tmplen)) { ret = -1; goto done; } - - tmplen = min_t(size_t, strlen(rates->rates), WLAN_SUPPORTED_RATES); - adapter->curbssparams.numofrates = tmplen; - pos += sizeof(rates->header) + tmplen; rates->header.len = cpu_to_le16(tmplen); + lbs_deb_join("ASSOC_CMD: num rates = %u\n", tmplen); + + /* Copy the infra. association rates into Current BSS state structure */ + memset(&adapter->curbssparams.rates, 0, sizeof(adapter->curbssparams.rates)); + memcpy(&adapter->curbssparams.rates, &rates->rates, tmplen); + + /* Set MSB on basic rates as the firmware requires, but _after_ + * copying to current bss rates. + */ + libertas_set_basic_rate_flags(rates->rates, tmplen); if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) { rsn = (struct mrvlietypes_rsnparamset *) pos; @@ -419,14 +448,6 @@ int libertas_cmd_80211_associate(wlan_private * priv, /* update curbssparams */ adapter->curbssparams.channel = bss->phyparamset.dsparamset.currentchan; - /* Copy the infra. association rates into Current BSS state structure */ - memcpy(&adapter->curbssparams.datarates, &rates->rates, - min_t(size_t, sizeof(adapter->curbssparams.datarates), - cpu_to_le16(rates->header.len))); - - lbs_deb_join("ASSOC_CMD: rates->header.len = %d\n", - cpu_to_le16(rates->header.len)); - if (libertas_parse_dnld_countryinfo_11d(priv, bss)) { ret = -1; goto done; @@ -454,9 +475,9 @@ int libertas_cmd_80211_ad_hoc_start(wlan_private * priv, struct cmd_ds_802_11_ad_hoc_start *adhs = &cmd->params.ads; int ret = 0; int cmdappendsize = 0; - int i; struct assoc_request * assoc_req = pdata_buf; u16 tmpcap = 0; + size_t ratesize = 0; lbs_deb_enter(LBS_DEB_JOIN); @@ -526,28 +547,26 @@ int libertas_cmd_80211_ad_hoc_start(wlan_private * priv, /* probedelay */ adhs->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME); - memset(adhs->datarate, 0, sizeof(adhs->datarate)); - + memset(adhs->rates, 0, sizeof(adhs->rates)); if (adapter->adhoc_grate_enabled) { - memcpy(adhs->datarate, libertas_adhoc_rates_g, - min(sizeof(adhs->datarate), sizeof(libertas_adhoc_rates_g))); + ratesize = min(sizeof(adhs->rates), sizeof(libertas_bg_rates)); + memcpy(adhs->rates, libertas_bg_rates, ratesize); } else { - memcpy(adhs->datarate, libertas_adhoc_rates_b, - min(sizeof(adhs->datarate), sizeof(libertas_adhoc_rates_b))); + ratesize = min(sizeof(adhs->rates), sizeof(adhoc_rates_b)); + memcpy(adhs->rates, adhoc_rates_b, ratesize); } - /* Find the last non zero */ - for (i = 0; i < sizeof(adhs->datarate) && adhs->datarate[i]; i++) ; - - adapter->curbssparams.numofrates = i; - /* Copy the ad-hoc creating rates into Current BSS state structure */ - memcpy(&adapter->curbssparams.datarates, - &adhs->datarate, adapter->curbssparams.numofrates); + memset(&adapter->curbssparams.rates, 0, sizeof(adapter->curbssparams.rates)); + memcpy(&adapter->curbssparams.rates, &adhs->rates, ratesize); + + /* Set MSB on basic rates as the firmware requires, but _after_ + * copying to current bss rates. + */ + libertas_set_basic_rate_flags(adhs->rates, ratesize); lbs_deb_join("ADHOC_S_CMD: rates=%02x %02x %02x %02x \n", - adhs->datarate[0], adhs->datarate[1], - adhs->datarate[2], adhs->datarate[3]); + adhs->rates[0], adhs->rates[1], adhs->rates[2], adhs->rates[3]); lbs_deb_join("ADHOC_S_CMD: AD HOC Start command is ready\n"); @@ -584,9 +603,7 @@ int libertas_cmd_80211_ad_hoc_join(wlan_private * priv, struct bss_descriptor *bss = &assoc_req->bss; int cmdappendsize = 0; int ret = 0; - u8 *card_rates; - int card_rates_size; - int i; + u16 ratesize = 0; lbs_deb_enter(LBS_DEB_JOIN); @@ -619,36 +636,26 @@ int libertas_cmd_80211_ad_hoc_join(wlan_private * priv, /* probedelay */ join_cmd->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME); - /* Copy Data rates from the rates recorded in scan response */ - memset(join_cmd->bss.datarates, 0, sizeof(join_cmd->bss.datarates)); - memcpy(join_cmd->bss.datarates, bss->datarates, - min(sizeof(join_cmd->bss.datarates), sizeof(bss->datarates))); - - card_rates = libertas_supported_rates; - card_rates_size = sizeof(libertas_supported_rates); - adapter->curbssparams.channel = bss->channel; - if (get_common_rates(adapter, join_cmd->bss.datarates, - sizeof(join_cmd->bss.datarates), - card_rates, card_rates_size)) { + /* Copy Data rates from the rates recorded in scan response */ + memset(join_cmd->bss.rates, 0, sizeof(join_cmd->bss.rates)); + ratesize = min_t(u16, sizeof(join_cmd->bss.rates), MAX_RATES); + memcpy(join_cmd->bss.rates, bss->rates, ratesize); + if (get_common_rates(adapter, join_cmd->bss.rates, &ratesize)) { lbs_deb_join("ADHOC_J_CMD: get_common_rates returns error.\n"); ret = -1; goto done; } - /* Find the last non zero */ - for (i = 0; i < sizeof(join_cmd->bss.datarates) - && join_cmd->bss.datarates[i]; i++) ; - - adapter->curbssparams.numofrates = i; + /* Copy the ad-hoc creating rates into Current BSS state structure */ + memset(&adapter->curbssparams.rates, 0, sizeof(adapter->curbssparams.rates)); + memcpy(&adapter->curbssparams.rates, join_cmd->bss.rates, ratesize); - /* - * Copy the adhoc joining rates to Current BSS State structure + /* Set MSB on basic rates as the firmware requires, but _after_ + * copying to current bss rates. */ - memcpy(adapter->curbssparams.datarates, - join_cmd->bss.datarates, - adapter->curbssparams.numofrates); + libertas_set_basic_rate_flags(join_cmd->bss.rates, ratesize); join_cmd->bss.ssparamset.ibssparamset.atimwindow = cpu_to_le16(bss->atimwindow); diff --git a/drivers/net/wireless/libertas/join.h b/drivers/net/wireless/libertas/join.h index d522630ff8c..8ea5ae30f4a 100644 --- a/drivers/net/wireless/libertas/join.h +++ b/drivers/net/wireless/libertas/join.h @@ -53,4 +53,6 @@ extern int libertas_do_adhocstop_ioctl(wlan_private * priv); int wlan_associate(wlan_private * priv, struct assoc_request * assoc_req); +void libertas_unset_basic_rate_flags(u8 * rates, size_t len); + #endif diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 26948595d95..03217f5537a 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -150,29 +150,60 @@ static struct region_cfp_table region_cfp_table[] = { }; /** - * the rates supported + * the table to keep region code */ -u8 libertas_supported_rates[G_SUPPORTED_RATES] = - { 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c, -0 }; +u16 libertas_region_code_to_index[MRVDRV_MAX_REGION_CODE] = + { 0x10, 0x20, 0x30, 0x31, 0x32, 0x40 }; /** - * the rates supported for ad-hoc G mode + * 802.11b/g supported bitrates (in 500Kb/s units) */ -u8 libertas_adhoc_rates_g[G_SUPPORTED_RATES] = - { 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c, -0 }; +u8 libertas_bg_rates[MAX_RATES] = + { 0x02, 0x04, 0x0b, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c, +0x00, 0x00 }; /** - * the rates supported for ad-hoc B mode + * FW rate table. FW refers to rates by their index in this table, not by the + * rate value itself. Values of 0x00 are + * reserved positions. */ -u8 libertas_adhoc_rates_b[4] = { 0x82, 0x84, 0x8b, 0x96 }; +static u8 fw_data_rates[MAX_RATES] = + { 0x02, 0x04, 0x0B, 0x16, 0x00, 0x0C, 0x12, + 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x00 +}; /** - * the table to keep region code + * @brief use index to get the data rate + * + * @param idx The index of data rate + * @return data rate or 0 */ -u16 libertas_region_code_to_index[MRVDRV_MAX_REGION_CODE] = - { 0x10, 0x20, 0x30, 0x31, 0x32, 0x40 }; +u32 libertas_fw_index_to_data_rate(u8 idx) +{ + if (idx >= sizeof(fw_data_rates)) + idx = 0; + return fw_data_rates[idx]; +} + +/** + * @brief use rate to get the index + * + * @param rate data rate + * @return index or 0 + */ +u8 libertas_data_rate_to_fw_index(u32 rate) +{ + u8 i; + + if (!rate) + return 0; + + for (i = 0; i < sizeof(fw_data_rates); i++) { + if (rate == fw_data_rates[i]) + return i; + } + return 0; +} /** * Attributes exported through sysfs diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c index 769c86fb950..e78636d6651 100644 --- a/drivers/net/wireless/libertas/rx.c +++ b/drivers/net/wireless/libertas/rx.c @@ -260,8 +260,8 @@ int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *skb) /* Take the data rate from the rxpd structure * only if the rate is auto */ - if (adapter->is_datarate_auto) - adapter->datarate = libertas_index_to_data_rate(p_rx_pd->rx_rate); + if (adapter->auto_rate) + adapter->cur_rate = libertas_fw_index_to_data_rate(p_rx_pd->rx_rate); wlan_compute_rssi(priv, p_rx_pd); @@ -424,9 +424,8 @@ static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb) /* Take the data rate from the rxpd structure * only if the rate is auto */ - if (adapter->is_datarate_auto) { - adapter->datarate = libertas_index_to_data_rate(prxpd->rx_rate); - } + if (adapter->auto_rate) + adapter->cur_rate = libertas_fw_index_to_data_rate(prxpd->rx_rate); wlan_compute_rssi(priv, prxpd); diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 2cac47fc4cd..790e9888ea2 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -17,6 +17,7 @@ #include "decl.h" #include "dev.h" #include "scan.h" +#include "join.h" //! Approximate amount of data needed to pass a scan result back to iwlist #define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN \ @@ -904,22 +905,14 @@ static int libertas_process_bss(struct bss_descriptor * bss, struct ieeetypes_dsparamset *pDS; struct ieeetypes_cfparamset *pCF; struct ieeetypes_ibssparamset *pibss; - u8 *pos, *end; - u8 *pRate; - u8 bytestocopy; - u8 ratesize; - u16 beaconsize; - u8 founddatarateie; - int ret; - struct ieeetypes_countryinfoset *pcountryinfo; + u8 *pos, *end, *p; + u8 n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0; + u16 beaconsize = 0; + int ret; lbs_deb_enter(LBS_DEB_ASSOC); - founddatarateie = 0; - ratesize = 0; - beaconsize = 0; - if (*bytesleft >= sizeof(beaconsize)) { /* Extract & convert beacon size from the command buffer */ beaconsize = le16_to_cpup((void *)*pbeaconinfo); @@ -1005,11 +998,9 @@ static int libertas_process_bss(struct bss_descriptor * bss, break; case MFIE_TYPE_RATES: - memcpy(bss->datarates, elem->data, elem->len); - memmove(bss->libertas_supported_rates, elem->data, - elem->len); - ratesize = elem->len; - founddatarateie = 1; + n_basic_rates = min_t(u8, MAX_RATES, elem->len); + memcpy(bss->rates, elem->data, n_basic_rates); + got_basic_rates = 1; break; case MFIE_TYPE_FH_SET: @@ -1070,22 +1061,15 @@ static int libertas_process_bss(struct bss_descriptor * bss, * already found. Data rate IE should come before * extended supported rate IE */ - if (!founddatarateie) + if (!got_basic_rates) break; - if ((elem->len + ratesize) > WLAN_SUPPORTED_RATES) { - bytestocopy = - (WLAN_SUPPORTED_RATES - ratesize); - } else { - bytestocopy = elem->len; - } + n_ex_rates = elem->len; + if (n_basic_rates + n_ex_rates > MAX_RATES) + n_ex_rates = MAX_RATES - n_basic_rates; - pRate = (u8 *) bss->datarates; - pRate += ratesize; - memmove(pRate, elem->data, bytestocopy); - pRate = (u8 *) bss->libertas_supported_rates; - pRate += ratesize; - memmove(pRate, elem->data, bytestocopy); + p = bss->rates + n_basic_rates; + memcpy(p, elem->data, n_ex_rates); break; case MFIE_TYPE_GENERIC: @@ -1123,6 +1107,7 @@ static int libertas_process_bss(struct bss_descriptor * bss, /* Timestamp */ bss->last_scanned = jiffies; + libertas_unset_basic_rate_flags(bss->rates, sizeof(bss->rates)); ret = 0; @@ -1530,12 +1515,9 @@ static inline char *libertas_translate_scan(wlan_private *priv, iwe.u.bitrate.disabled = 0; iwe.u.bitrate.value = 0; - for (j = 0; j < sizeof(bss->libertas_supported_rates); j++) { - u8 rate = bss->libertas_supported_rates[j]; - if (rate == 0) - break; /* no more rates */ - /* Bit rate given in 500 kb/s units (+ 0x80) */ - iwe.u.bitrate.value = (rate & 0x7f) * 500000; + for (j = 0; bss->rates[j] && (j < sizeof(bss->rates)); j++) { + /* Bit rate given in 500 kb/s units */ + iwe.u.bitrate.value = bss->rates[j] * 500000; current_val = iwe_stream_add_value(start, current_val, stop, &iwe, IW_EV_PARAM_LEN); } diff --git a/drivers/net/wireless/libertas/scan.h b/drivers/net/wireless/libertas/scan.h index 23c539c2263..8c3508b3257 100644 --- a/drivers/net/wireless/libertas/scan.h +++ b/drivers/net/wireless/libertas/scan.h @@ -152,14 +152,14 @@ struct bss_descriptor { u32 atimwindow; u8 mode; - u8 libertas_supported_rates[WLAN_SUPPORTED_RATES]; + /* zero-terminated array of supported data rates */ + u8 rates[MAX_RATES + 1]; __le64 timestamp; //!< TSF value included in the beacon/probe response unsigned long last_scanned; union ieeetypes_phyparamset phyparamset; union IEEEtypes_ssparamset ssparamset; - u8 datarates[WLAN_SUPPORTED_RATES]; u64 networktsf; //!< TSF timestamp from the current firmware TSF diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 115f02c010a..0b805e32993 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -21,14 +21,6 @@ #include "assoc.h" -/** - * the rates supported by the card - */ -static u8 libertas_wlan_data_rates[WLAN_SUPPORTED_RATES] = - { 0x02, 0x04, 0x0B, 0x16, 0x00, 0x0C, 0x12, - 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x00 -}; - /** * @brief Convert mw value to dbm value * @@ -187,57 +179,21 @@ int wlan_radio_ioctl(wlan_private * priv, u8 option) } /** - * @brief Copy rates - * - * @param dest A pointer to Dest Buf - * @param src A pointer to Src Buf - * @param len The len of Src Buf - * @return Number of rates copyed - */ -static inline int copyrates(u8 * dest, int pos, u8 * src, int len) -{ - int i; - - for (i = 0; i < len && src[i]; i++, pos++) { - if (pos >= sizeof(u8) * WLAN_SUPPORTED_RATES) - break; - dest[pos] = src[i]; - } - - return pos; -} - -/** - * @brief Get active data rates + * @brief Copy active data rates based on adapter mode and status * * @param adapter A pointer to wlan_adapter structure * @param rate The buf to return the active rates - * @return The number of rates */ -static int get_active_data_rates(wlan_adapter * adapter, - u8* rates) +static void copy_active_data_rates(wlan_adapter * adapter, u8 * rates) { - int k = 0; - lbs_deb_enter(LBS_DEB_WEXT); - if (adapter->connect_status != LIBERTAS_CONNECTED) { - if (adapter->mode == IW_MODE_INFRA) { - lbs_deb_wext("infra\n"); - k = copyrates(rates, k, libertas_supported_rates, - sizeof(libertas_supported_rates)); - } else { - lbs_deb_wext("Adhoc G\n"); - k = copyrates(rates, k, libertas_adhoc_rates_g, - sizeof(libertas_adhoc_rates_g)); - } - } else { - k = copyrates(rates, 0, adapter->curbssparams.datarates, - adapter->curbssparams.numofrates); - } + if (adapter->connect_status != LIBERTAS_CONNECTED) + memcpy(rates, libertas_bg_rates, MAX_RATES); + else + memcpy(rates, adapter->curbssparams.rates, MAX_RATES); - lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", k); - return k; + lbs_deb_leave(LBS_DEB_WEXT); } static int wlan_get_name(struct net_device *dev, struct iw_request_info *info, @@ -673,7 +629,7 @@ static int wlan_get_range(struct net_device *dev, struct iw_request_info *info, wlan_adapter *adapter = priv->adapter; struct iw_range *range = (struct iw_range *)extra; struct chan_freq_power *cfp; - u8 rates[WLAN_SUPPORTED_RATES]; + u8 rates[MAX_RATES + 1]; u8 flag = 0; @@ -686,12 +642,10 @@ static int wlan_get_range(struct net_device *dev, struct iw_request_info *info, range->max_nwid = 0; memset(rates, 0, sizeof(rates)); - range->num_bitrates = get_active_data_rates(adapter, rates); - - for (i = 0; i < min_t(__u8, range->num_bitrates, IW_MAX_BITRATES) && rates[i]; - i++) { - range->bitrate[i] = (rates[i] & 0x7f) * 500000; - } + copy_active_data_rates(adapter, rates); + range->num_bitrates = strnlen(rates, IW_MAX_BITRATES); + for (i = 0; i < range->num_bitrates; i++) + range->bitrate[i] = rates[i] * 500000; range->num_bitrates = i; lbs_deb_wext("IW_MAX_BITRATES %d, num_bitrates %d\n", IW_MAX_BITRATES, range->num_bitrates); @@ -1080,88 +1034,46 @@ out: return ret; } -/** - * @brief use index to get the data rate - * - * @param index The index of data rate - * @return data rate or 0 - */ -u32 libertas_index_to_data_rate(u8 index) -{ - if (index >= sizeof(libertas_wlan_data_rates)) - index = 0; - - return libertas_wlan_data_rates[index]; -} - -/** - * @brief use rate to get the index - * - * @param rate data rate - * @return index or 0 - */ -u8 libertas_data_rate_to_index(u32 rate) -{ - u8 *ptr; - - if (rate) - if ((ptr = memchr(libertas_wlan_data_rates, (u8) rate, - sizeof(libertas_wlan_data_rates)))) - return (ptr - libertas_wlan_data_rates); - - return 0; -} - static int wlan_set_rate(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { wlan_private *priv = dev->priv; wlan_adapter *adapter = priv->adapter; - u32 data_rate; + u32 new_rate; u16 action; - int ret = 0; - u8 rates[WLAN_SUPPORTED_RATES]; - u8 *rate; + int ret = -EINVAL; + u8 rates[MAX_RATES + 1]; lbs_deb_enter(LBS_DEB_WEXT); - lbs_deb_wext("vwrq->value %d\n", vwrq->value); + /* Auto rate? */ if (vwrq->value == -1) { - action = CMD_ACT_SET_TX_AUTO; // Auto - adapter->is_datarate_auto = 1; - adapter->datarate = 0; + action = CMD_ACT_SET_TX_AUTO; + adapter->auto_rate = 1; + adapter->cur_rate = 0; } else { - if (vwrq->value % 100000) { - return -EINVAL; - } - - data_rate = vwrq->value / 500000; + if (vwrq->value % 100000) + goto out; memset(rates, 0, sizeof(rates)); - get_active_data_rates(adapter, rates); - rate = rates; - while (*rate) { - lbs_deb_wext("rate=0x%X, wanted data_rate 0x%X\n", *rate, - data_rate); - if ((*rate & 0x7f) == (data_rate & 0x7f)) - break; - rate++; - } - if (!*rate) { - lbs_pr_alert("fixed data rate 0x%X out " - "of range\n", data_rate); - return -EINVAL; + copy_active_data_rates(adapter, rates); + new_rate = vwrq->value / 500000; + if (!memchr(rates, new_rate, sizeof(rates))) { + lbs_pr_alert("fixed data rate 0x%X out of range\n", + new_rate); + goto out; } - adapter->datarate = data_rate; + adapter->cur_rate = new_rate; action = CMD_ACT_SET_TX_FIX_RATE; - adapter->is_datarate_auto = 0; + adapter->auto_rate = 0; } ret = libertas_prepare_and_send_command(priv, CMD_802_11_DATA_RATE, action, CMD_OPTION_WAITFORRSP, 0, NULL); +out: lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); return ret; } @@ -1174,14 +1086,19 @@ static int wlan_get_rate(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); - if (adapter->is_datarate_auto) { - vwrq->fixed = 0; + if (adapter->connect_status == LIBERTAS_CONNECTED) { + vwrq->value = adapter->cur_rate * 500000; + + if (adapter->auto_rate) + vwrq->fixed = 0; + else + vwrq->fixed = 1; + } else { - vwrq->fixed = 1; + vwrq->fixed = 0; + vwrq->value = 0; } - vwrq->value = adapter->datarate * 500000; - lbs_deb_leave(LBS_DEB_WEXT); return 0; } -- cgit v1.2.3-70-g09d2 From 1df4e8fe91d5bab3fd7ae7f115e43c52010cd4ad Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 11:45:12 -0400 Subject: [PATCH] libertas: remove fw.c Firmware download is quite different for different hardware. The SDIO and CF cards have two flat files that need to be downloaded, whereas the USB driver needs only one file, but with an internal structure. The code that handles this (USB only) structured file is currently in fw.c. This patch moves this code into if_usb.c. The remaining functions in fw.c have not much to do with firmware, they are various card- and network-stack initialisation functions. I've moved them into main.c. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/Makefile | 2 +- drivers/net/wireless/libertas/decl.h | 5 +- drivers/net/wireless/libertas/fw.c | 346 --------------------------------- drivers/net/wireless/libertas/if_usb.c | 78 +++++++- drivers/net/wireless/libertas/main.c | 278 +++++++++++++++++++++++++- 5 files changed, 354 insertions(+), 355 deletions(-) delete mode 100644 drivers/net/wireless/libertas/fw.c (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/Makefile b/drivers/net/wireless/libertas/Makefile index 61e0d6e0790..b56b4c55de3 100644 --- a/drivers/net/wireless/libertas/Makefile +++ b/drivers/net/wireless/libertas/Makefile @@ -1,4 +1,4 @@ -libertas-objs := main.o fw.o wext.o \ +libertas-objs := main.o wext.o \ rx.o tx.o cmd.o \ cmdresp.o scan.o \ join.o 11d.o \ diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h index 129b021d35f..113cfc1395e 100644 --- a/drivers/net/wireless/libertas/decl.h +++ b/drivers/net/wireless/libertas/decl.h @@ -75,14 +75,11 @@ void libertas_mac_event_disconnected(wlan_private * priv); void libertas_send_iwevcustom_event(wlan_private * priv, s8 * str); -/* fw.c */ -int libertas_init_fw(wlan_private * priv, char *fw_name); - /* main.c */ struct chan_freq_power *libertas_get_region_cfp_table(u8 region, u8 band, int *cfp_no); wlan_private *libertas_add_card(void *card, struct device *dmdev); -int libertas_activate_card(wlan_private *priv, char *fw_name); +int libertas_activate_card(wlan_private *priv); int libertas_remove_card(wlan_private *priv); int libertas_add_mesh(wlan_private *priv, struct device *dev); void libertas_remove_mesh(wlan_private *priv); diff --git a/drivers/net/wireless/libertas/fw.c b/drivers/net/wireless/libertas/fw.c deleted file mode 100644 index 6c259878da9..00000000000 --- a/drivers/net/wireless/libertas/fw.c +++ /dev/null @@ -1,346 +0,0 @@ -/** - * This file contains the initialization for FW and HW - */ -#include - -#include "host.h" -#include "defs.h" -#include "decl.h" -#include "dev.h" -#include "wext.h" -#include "if_usb.h" - -/** - * @brief This function checks the validity of Boot2/FW image. - * - * @param data pointer to image - * len image length - * @return 0 or -1 - */ -static int check_fwfile_format(u8 *data, u32 totlen) -{ - u32 bincmd, exit; - u32 blksize, offset, len; - int ret; - - ret = 1; - exit = len = 0; - - do { - struct fwheader *fwh = (void *)data; - - bincmd = le32_to_cpu(fwh->dnldcmd); - blksize = le32_to_cpu(fwh->datalength); - switch (bincmd) { - case FW_HAS_DATA_TO_RECV: - offset = sizeof(struct fwheader) + blksize; - data += offset; - len += offset; - if (len >= totlen) - exit = 1; - break; - case FW_HAS_LAST_BLOCK: - exit = 1; - ret = 0; - break; - default: - exit = 1; - break; - } - } while (!exit); - - if (ret) - lbs_pr_err("firmware file format check FAIL\n"); - else - lbs_deb_fw("firmware file format check PASS\n"); - - return ret; -} - -/** - * @brief This function downloads firmware image, gets - * HW spec from firmware and set basic parameters to - * firmware. - * - * @param priv A pointer to wlan_private structure - * @return 0 or -1 - */ -static int wlan_setup_station_hw(wlan_private * priv, char *fw_name) -{ - int ret = -1; - wlan_adapter *adapter = priv->adapter; - - lbs_deb_enter(LBS_DEB_FW); - - if ((ret = request_firmware(&priv->firmware, fw_name, - priv->hotplug_device)) < 0) { - lbs_pr_err("request_firmware() failed with %#x\n", ret); - lbs_pr_err("firmware %s not found\n", fw_name); - goto done; - } - - if (check_fwfile_format(priv->firmware->data, priv->firmware->size)) { - release_firmware(priv->firmware); - goto done; - } - - ret = priv->hw_prog_firmware(priv); - - release_firmware(priv->firmware); - - if (ret) { - lbs_deb_fw("bootloader in invalid state\n"); - ret = -1; - goto done; - } - - /* - * Read MAC address from HW - */ - memset(adapter->current_addr, 0xff, ETH_ALEN); - - ret = libertas_prepare_and_send_command(priv, CMD_GET_HW_SPEC, - 0, CMD_OPTION_WAITFORRSP, 0, NULL); - - if (ret) { - ret = -1; - goto done; - } - - libertas_set_mac_packet_filter(priv); - - /* Get the supported Data rates */ - ret = libertas_prepare_and_send_command(priv, CMD_802_11_DATA_RATE, - CMD_ACT_GET_TX_RATE, - CMD_OPTION_WAITFORRSP, 0, NULL); - - if (ret) { - ret = -1; - goto done; - } - - ret = 0; -done: - lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret); - return ret; -} - -static int wlan_allocate_adapter(wlan_private * priv) -{ - size_t bufsize; - wlan_adapter *adapter = priv->adapter; - - /* Allocate buffer to store the BSSID list */ - bufsize = MAX_NETWORK_COUNT * sizeof(struct bss_descriptor); - adapter->networks = kzalloc(bufsize, GFP_KERNEL); - if (!adapter->networks) { - lbs_pr_err("Out of memory allocating beacons\n"); - libertas_free_adapter(priv); - return -ENOMEM; - } - - /* Allocate the command buffers */ - libertas_allocate_cmd_buffer(priv); - - memset(&adapter->libertas_ps_confirm_sleep, 0, sizeof(struct PS_CMD_ConfirmSleep)); - adapter->libertas_ps_confirm_sleep.seqnum = cpu_to_le16(++adapter->seqnum); - adapter->libertas_ps_confirm_sleep.command = - cpu_to_le16(CMD_802_11_PS_MODE); - adapter->libertas_ps_confirm_sleep.size = - cpu_to_le16(sizeof(struct PS_CMD_ConfirmSleep)); - adapter->libertas_ps_confirm_sleep.result = 0; - adapter->libertas_ps_confirm_sleep.action = - cpu_to_le16(CMD_SUBCMD_SLEEP_CONFIRMED); - - return 0; -} - -static void wlan_init_adapter(wlan_private * priv) -{ - wlan_adapter *adapter = priv->adapter; - int i; - - adapter->scanprobes = 0; - - adapter->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR; - adapter->data_avg_factor = DEFAULT_DATA_AVG_FACTOR; - - /* ATIM params */ - adapter->atimwindow = 0; - - adapter->connect_status = LIBERTAS_DISCONNECTED; - memset(adapter->current_addr, 0xff, ETH_ALEN); - - /* scan type */ - adapter->scantype = CMD_SCAN_TYPE_ACTIVE; - - /* scan mode */ - adapter->scanmode = CMD_BSS_TYPE_ANY; - - /* 802.11 specific */ - adapter->secinfo.wep_enabled = 0; - for (i = 0; i < sizeof(adapter->wep_keys) / sizeof(adapter->wep_keys[0]); - i++) - memset(&adapter->wep_keys[i], 0, sizeof(struct enc_key)); - adapter->wep_tx_keyidx = 0; - adapter->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; - adapter->mode = IW_MODE_INFRA; - - adapter->pending_assoc_req = NULL; - adapter->in_progress_assoc_req = NULL; - - /* Initialize scan result lists */ - INIT_LIST_HEAD(&adapter->network_free_list); - INIT_LIST_HEAD(&adapter->network_list); - for (i = 0; i < MAX_NETWORK_COUNT; i++) { - list_add_tail(&adapter->networks[i].list, - &adapter->network_free_list); - } - - mutex_init(&adapter->lock); - - adapter->prescan = 1; - - memset(&adapter->curbssparams, 0, sizeof(adapter->curbssparams)); - adapter->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL; - - /* PnP and power profile */ - adapter->surpriseremoved = 0; - - adapter->currentpacketfilter = - CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON; - - adapter->radioon = RADIO_ON; - adapter->txantenna = RF_ANTENNA_2; - adapter->rxantenna = RF_ANTENNA_AUTO; - - adapter->auto_rate = 1; - adapter->cur_rate = 0; - adapter->adhoc_grate_enabled = 0; - - adapter->beaconperiod = MRVDRV_BEACON_INTERVAL; - - // set default capabilities - adapter->capability = WLAN_CAPABILITY_SHORT_PREAMBLE; - - adapter->psmode = WLAN802_11POWERMODECAM; - adapter->multipledtim = MRVDRV_DEFAULT_MULTIPLE_DTIM; - - adapter->listeninterval = MRVDRV_DEFAULT_LISTEN_INTERVAL; - - adapter->psstate = PS_STATE_FULL_POWER; - adapter->needtowakeup = 0; - adapter->locallisteninterval = 0; /* default value in firmware will be used */ - - adapter->intcounter = 0; - - adapter->currenttxskb = NULL; - adapter->pkttxctrl = 0; - - memset(&adapter->tx_queue_ps, 0, NR_TX_QUEUE*sizeof(struct sk_buff*)); - adapter->tx_queue_idx = 0; - spin_lock_init(&adapter->txqueue_lock); - - return; -} - -static void command_timer_fn(unsigned long data); - -int libertas_init_fw(wlan_private * priv, char *fw_name) -{ - int ret = -1; - wlan_adapter *adapter = priv->adapter; - - lbs_deb_enter(LBS_DEB_FW); - - /* Allocate adapter structure */ - if ((ret = wlan_allocate_adapter(priv)) != 0) - goto done; - - /* init adapter structure */ - wlan_init_adapter(priv); - - /* init timer etc. */ - setup_timer(&adapter->command_timer, command_timer_fn, - (unsigned long)priv); - - /* download fimrware etc. */ - if ((ret = wlan_setup_station_hw(priv, fw_name)) != 0) { - del_timer_sync(&adapter->command_timer); - goto done; - } - - /* init 802.11d */ - libertas_init_11d(priv); - - ret = 0; -done: - lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret); - return ret; -} - -void libertas_free_adapter(wlan_private * priv) -{ - wlan_adapter *adapter = priv->adapter; - - if (!adapter) { - lbs_deb_fw("why double free adapter?\n"); - return; - } - - lbs_deb_fw("free command buffer\n"); - libertas_free_cmd_buffer(priv); - - lbs_deb_fw("free command_timer\n"); - del_timer(&adapter->command_timer); - - lbs_deb_fw("free scan results table\n"); - kfree(adapter->networks); - adapter->networks = NULL; - - /* Free the adapter object itself */ - lbs_deb_fw("free adapter\n"); - kfree(adapter); - priv->adapter = NULL; -} - -/** - * This function handles the timeout of command sending. - * It will re-send the same command again. - */ -static void command_timer_fn(unsigned long data) -{ - wlan_private *priv = (wlan_private *)data; - wlan_adapter *adapter = priv->adapter; - struct cmd_ctrl_node *ptempnode; - struct cmd_ds_command *cmd; - unsigned long flags; - - ptempnode = adapter->cur_cmd; - if (ptempnode == NULL) { - lbs_deb_fw("ptempnode empty\n"); - return; - } - - cmd = (struct cmd_ds_command *)ptempnode->bufvirtualaddr; - if (!cmd) { - lbs_deb_fw("cmd is NULL\n"); - return; - } - - lbs_deb_fw("command_timer_fn fired, cmd %x\n", cmd->command); - - if (!adapter->fw_ready) - return; - - spin_lock_irqsave(&adapter->driver_lock, flags); - adapter->cur_cmd = NULL; - spin_unlock_irqrestore(&adapter->driver_lock, flags); - - lbs_deb_fw("re-sending same command because of timeout\n"); - libertas_queue_cmd(adapter, ptempnode, 0); - - wake_up_interruptible(&priv->waitq); - - return; -} diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index e38fce73cf7..ac1cfc253fd 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -216,7 +216,7 @@ static int if_usb_probe(struct usb_interface *intf, priv->hw_get_int_status = if_usb_get_int_status; priv->hw_read_event_cause = if_usb_read_event_cause; - if (libertas_activate_card(priv, libertas_fw_name)) + if (libertas_activate_card(priv)) goto err_activate_card; list_add_tail(&cardp->list, &usb_devices); @@ -819,7 +819,7 @@ static int if_usb_issue_boot_command(wlan_private *priv, int ivalue) } -static int if_usb_prog_firmware(wlan_private * priv) +static int if_usb_do_prog_firmware(wlan_private * priv) { struct usb_card_rec *cardp = priv->card; int i = 0; @@ -903,6 +903,80 @@ done: return ret; } +/** + * @brief This function checks the validity of Boot2/FW image. + * + * @param data pointer to image + * len image length + * @return 0 or -1 + */ +static int check_fwfile_format(u8 *data, u32 totlen) +{ + u32 bincmd, exit; + u32 blksize, offset, len; + int ret; + + ret = 1; + exit = len = 0; + + do { + struct fwheader *fwh = (void *)data; + + bincmd = le32_to_cpu(fwh->dnldcmd); + blksize = le32_to_cpu(fwh->datalength); + switch (bincmd) { + case FW_HAS_DATA_TO_RECV: + offset = sizeof(struct fwheader) + blksize; + data += offset; + len += offset; + if (len >= totlen) + exit = 1; + break; + case FW_HAS_LAST_BLOCK: + exit = 1; + ret = 0; + break; + default: + exit = 1; + break; + } + } while (!exit); + + if (ret) + lbs_pr_err("firmware file format check FAIL\n"); + else + lbs_deb_fw("firmware file format check PASS\n"); + + return ret; +} + + +static int if_usb_prog_firmware(wlan_private *priv) +{ + int ret = -1; + + lbs_deb_enter(LBS_DEB_FW); + + if ((ret = request_firmware(&priv->firmware, libertas_fw_name, + priv->hotplug_device)) < 0) { + lbs_pr_err("request_firmware() failed with %#x\n", ret); + lbs_pr_err("firmware %s not found\n", libertas_fw_name); + goto done; + } + + if (check_fwfile_format(priv->firmware->data, priv->firmware->size)) { + release_firmware(priv->firmware); + goto done; + } + + ret = if_usb_do_prog_firmware(priv); + + release_firmware(priv->firmware); +done: + return ret; +} + + #ifdef CONFIG_PM static int if_usb_suspend(struct usb_interface *intf, pm_message_t message) { diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 03217f5537a..7e417eacbc7 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -793,6 +793,280 @@ static int libertas_thread(void *data) return 0; } +/** + * @brief This function downloads firmware image, gets + * HW spec from firmware and set basic parameters to + * firmware. + * + * @param priv A pointer to wlan_private structure + * @return 0 or -1 + */ +static int wlan_setup_station_hw(wlan_private * priv) +{ + int ret = -1; + wlan_adapter *adapter = priv->adapter; + + lbs_deb_enter(LBS_DEB_FW); + + ret = priv->hw_prog_firmware(priv); + + if (ret) { + lbs_deb_fw("bootloader in invalid state\n"); + ret = -1; + goto done; + } + + /* + * Read MAC address from HW + */ + memset(adapter->current_addr, 0xff, ETH_ALEN); + + ret = libertas_prepare_and_send_command(priv, CMD_GET_HW_SPEC, + 0, CMD_OPTION_WAITFORRSP, 0, NULL); + + if (ret) { + ret = -1; + goto done; + } + + libertas_set_mac_packet_filter(priv); + + /* Get the supported Data rates */ + ret = libertas_prepare_and_send_command(priv, CMD_802_11_DATA_RATE, + CMD_ACT_GET_TX_RATE, + CMD_OPTION_WAITFORRSP, 0, NULL); + + if (ret) { + ret = -1; + goto done; + } + + ret = 0; +done: + lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret); + return ret; +} + +static void command_timer_fn(unsigned long data); + +/** + * This function handles the timeout of command sending. + * It will re-send the same command again. + */ +static void command_timer_fn(unsigned long data) +{ + wlan_private *priv = (wlan_private *)data; + wlan_adapter *adapter = priv->adapter; + struct cmd_ctrl_node *ptempnode; + struct cmd_ds_command *cmd; + unsigned long flags; + + ptempnode = adapter->cur_cmd; + if (ptempnode == NULL) { + lbs_deb_fw("ptempnode empty\n"); + return; + } + + cmd = (struct cmd_ds_command *)ptempnode->bufvirtualaddr; + if (!cmd) { + lbs_deb_fw("cmd is NULL\n"); + return; + } + + lbs_deb_fw("command_timer_fn fired, cmd %x\n", cmd->command); + + if (!adapter->fw_ready) + return; + + spin_lock_irqsave(&adapter->driver_lock, flags); + adapter->cur_cmd = NULL; + spin_unlock_irqrestore(&adapter->driver_lock, flags); + + lbs_deb_fw("re-sending same command because of timeout\n"); + libertas_queue_cmd(adapter, ptempnode, 0); + + wake_up_interruptible(&priv->waitq); + + return; +} + +static int wlan_allocate_adapter(wlan_private * priv) +{ + size_t bufsize; + wlan_adapter *adapter = priv->adapter; + + /* Allocate buffer to store the BSSID list */ + bufsize = MAX_NETWORK_COUNT * sizeof(struct bss_descriptor); + adapter->networks = kzalloc(bufsize, GFP_KERNEL); + if (!adapter->networks) { + lbs_pr_err("Out of memory allocating beacons\n"); + libertas_free_adapter(priv); + return -ENOMEM; + } + + /* Allocate the command buffers */ + libertas_allocate_cmd_buffer(priv); + + memset(&adapter->libertas_ps_confirm_sleep, 0, sizeof(struct PS_CMD_ConfirmSleep)); + adapter->libertas_ps_confirm_sleep.seqnum = cpu_to_le16(++adapter->seqnum); + adapter->libertas_ps_confirm_sleep.command = + cpu_to_le16(CMD_802_11_PS_MODE); + adapter->libertas_ps_confirm_sleep.size = + cpu_to_le16(sizeof(struct PS_CMD_ConfirmSleep)); + adapter->libertas_ps_confirm_sleep.result = 0; + adapter->libertas_ps_confirm_sleep.action = + cpu_to_le16(CMD_SUBCMD_SLEEP_CONFIRMED); + + return 0; +} + +static void wlan_init_adapter(wlan_private * priv) +{ + wlan_adapter *adapter = priv->adapter; + int i; + + adapter->scanprobes = 0; + + adapter->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR; + adapter->data_avg_factor = DEFAULT_DATA_AVG_FACTOR; + + /* ATIM params */ + adapter->atimwindow = 0; + + adapter->connect_status = LIBERTAS_DISCONNECTED; + memset(adapter->current_addr, 0xff, ETH_ALEN); + + /* scan type */ + adapter->scantype = CMD_SCAN_TYPE_ACTIVE; + + /* scan mode */ + adapter->scanmode = CMD_BSS_TYPE_ANY; + + /* 802.11 specific */ + adapter->secinfo.wep_enabled = 0; + for (i = 0; i < sizeof(adapter->wep_keys) / sizeof(adapter->wep_keys[0]); + i++) + memset(&adapter->wep_keys[i], 0, sizeof(struct enc_key)); + adapter->wep_tx_keyidx = 0; + adapter->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; + adapter->mode = IW_MODE_INFRA; + + adapter->pending_assoc_req = NULL; + adapter->in_progress_assoc_req = NULL; + + /* Initialize scan result lists */ + INIT_LIST_HEAD(&adapter->network_free_list); + INIT_LIST_HEAD(&adapter->network_list); + for (i = 0; i < MAX_NETWORK_COUNT; i++) { + list_add_tail(&adapter->networks[i].list, + &adapter->network_free_list); + } + + mutex_init(&adapter->lock); + + adapter->prescan = 1; + + memset(&adapter->curbssparams, 0, sizeof(adapter->curbssparams)); + adapter->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL; + + /* PnP and power profile */ + adapter->surpriseremoved = 0; + + adapter->currentpacketfilter = + CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON; + + adapter->radioon = RADIO_ON; + adapter->txantenna = RF_ANTENNA_2; + adapter->rxantenna = RF_ANTENNA_AUTO; + + adapter->auto_rate = 1; + adapter->cur_rate = 0; + adapter->adhoc_grate_enabled = 0; + + adapter->beaconperiod = MRVDRV_BEACON_INTERVAL; + + // set default capabilities + adapter->capability = WLAN_CAPABILITY_SHORT_PREAMBLE; + + adapter->psmode = WLAN802_11POWERMODECAM; + adapter->multipledtim = MRVDRV_DEFAULT_MULTIPLE_DTIM; + + adapter->listeninterval = MRVDRV_DEFAULT_LISTEN_INTERVAL; + + adapter->psstate = PS_STATE_FULL_POWER; + adapter->needtowakeup = 0; + adapter->locallisteninterval = 0; /* default value in firmware will be used */ + + adapter->intcounter = 0; + + adapter->currenttxskb = NULL; + adapter->pkttxctrl = 0; + + memset(&adapter->tx_queue_ps, 0, NR_TX_QUEUE*sizeof(struct sk_buff*)); + adapter->tx_queue_idx = 0; + spin_lock_init(&adapter->txqueue_lock); + + return; +} + +void libertas_free_adapter(wlan_private * priv) +{ + wlan_adapter *adapter = priv->adapter; + + if (!adapter) { + lbs_deb_fw("why double free adapter?\n"); + return; + } + + lbs_deb_fw("free command buffer\n"); + libertas_free_cmd_buffer(priv); + + lbs_deb_fw("free command_timer\n"); + del_timer(&adapter->command_timer); + + lbs_deb_fw("free scan results table\n"); + kfree(adapter->networks); + adapter->networks = NULL; + + /* Free the adapter object itself */ + lbs_deb_fw("free adapter\n"); + kfree(adapter); + priv->adapter = NULL; +} + +static int libertas_init_fw(wlan_private * priv) +{ + int ret = -1; + wlan_adapter *adapter = priv->adapter; + + lbs_deb_enter(LBS_DEB_FW); + + /* Allocate adapter structure */ + if ((ret = wlan_allocate_adapter(priv)) != 0) + goto done; + + /* init adapter structure */ + wlan_init_adapter(priv); + + /* init timer etc. */ + setup_timer(&adapter->command_timer, command_timer_fn, + (unsigned long)priv); + + /* download fimrware etc. */ + if ((ret = wlan_setup_station_hw(priv)) != 0) { + del_timer_sync(&adapter->command_timer); + goto done; + } + + /* init 802.11d */ + libertas_init_11d(priv); + + ret = 0; +done: + lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret); + return ret; +} + /** * @brief This function adds the card. it will probe the * card, allocate the wlan_priv and initialize the device. @@ -863,7 +1137,7 @@ done: } EXPORT_SYMBOL_GPL(libertas_add_card); -int libertas_activate_card(wlan_private *priv, char *fw_name) +int libertas_activate_card(wlan_private *priv) { struct net_device *dev = priv->dev; int ret = -1; @@ -894,7 +1168,7 @@ int libertas_activate_card(wlan_private *priv, char *fw_name) } /* init FW and HW */ - if (fw_name && libertas_init_fw(priv, fw_name)) { + if (libertas_init_fw(priv)) { lbs_pr_err("firmware init failed\n"); goto err_registerdev; } -- cgit v1.2.3-70-g09d2 From c23a24f6ae083e058ed1e9472979df09915ffdf5 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 11:45:30 -0400 Subject: [PATCH] libertas: fix one more sparse warning adhoc_rates_b is only used locally, so make it static Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/join.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c index 78e398d6f5f..f71c172101a 100644 --- a/drivers/net/wireless/libertas/join.c +++ b/drivers/net/wireless/libertas/join.c @@ -18,7 +18,7 @@ #include "assoc.h" /* Supported rates for ad-hoc B mode */ -u8 adhoc_rates_b[5] = { 0x02, 0x04, 0x0b, 0x16, 0x00 }; +static u8 adhoc_rates_b[5] = { 0x02, 0x04, 0x0b, 0x16, 0x00 }; /** -- cgit v1.2.3-70-g09d2 From ac558ca2ae878bd7a77831cda684702a2fa23d95 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 11:49:06 -0400 Subject: [PATCH] libertas: make more functions static & remove unused functions Some functions where declared in header files, but used only once. They are now static functions. After doing this, I found out that some functions weren't used at all. I removed this dead code. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/11d.c | 44 ------------------------------ drivers/net/wireless/libertas/11d.h | 4 --- drivers/net/wireless/libertas/cmd.c | 2 +- drivers/net/wireless/libertas/decl.h | 7 ----- drivers/net/wireless/libertas/if_usb.c | 8 ++++-- drivers/net/wireless/libertas/if_usb.h | 3 -- drivers/net/wireless/libertas/join.c | 14 ---------- drivers/net/wireless/libertas/join.h | 33 ++++++++++------------ drivers/net/wireless/libertas/main.c | 50 +++++++++++++++++----------------- drivers/net/wireless/libertas/scan.c | 35 +----------------------- drivers/net/wireless/libertas/scan.h | 19 +++++-------- drivers/net/wireless/libertas/wext.c | 2 +- drivers/net/wireless/libertas/wext.h | 4 --- 13 files changed, 54 insertions(+), 171 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/11d.c b/drivers/net/wireless/libertas/11d.c index 26d85ec37d9..ba4cbcb5911 100644 --- a/drivers/net/wireless/libertas/11d.c +++ b/drivers/net/wireless/libertas/11d.c @@ -446,25 +446,6 @@ void libertas_init_11d(wlan_private * priv) return; } -static int wlan_enable_11d(wlan_private * priv, u8 flag) -{ - int ret; - - priv->adapter->enable11d = flag; - - /* send cmd to FW to enable/disable 11D function in FW */ - ret = libertas_prepare_and_send_command(priv, - CMD_802_11_SNMP_MIB, - CMD_ACT_SET, - CMD_OPTION_WAITFORRSP, - OID_802_11D_ENABLE, - &priv->adapter->enable11d); - if (ret) - lbs_deb_11d("11D: Fail to enable 11D \n"); - - return 0; -} - /** * @brief This function sets DOMAIN INFO to FW * @param priv pointer to wlan_private @@ -577,31 +558,6 @@ done: return 0; } -/** - * @brief This function implements private cmd: enable/disable 11D - * @param priv pointer to wlan_private - * @param wrq pointer to user data - * @return 0 or -1 - */ -int libertas_cmd_enable_11d(wlan_private * priv, struct iwreq *wrq) -{ - int data = 0; - int *val; - - lbs_deb_enter(LBS_DEB_11D); - data = SUBCMD_DATA(wrq); - - lbs_deb_11d("enable 11D: %s\n", - (data == 1) ? "enable" : "Disable"); - - wlan_enable_11d(priv, data); - val = (int *)wrq->u.name; - *val = priv->adapter->enable11d; - - lbs_deb_enter(LBS_DEB_11D); - return 0; -} - /** * @brief This function parses countryinfo from AP and download country info to FW * @param priv pointer to wlan_private diff --git a/drivers/net/wireless/libertas/11d.h b/drivers/net/wireless/libertas/11d.h index 73e42e71291..3a6d1f8db78 100644 --- a/drivers/net/wireless/libertas/11d.h +++ b/drivers/net/wireless/libertas/11d.h @@ -83,8 +83,6 @@ u8 libertas_get_scan_type_11d(u8 chan, u32 libertas_chan_2_freq(u8 chan, u8 band); -enum state_11d libertas_get_state_11d(wlan_private * priv); - void libertas_init_11d(wlan_private * priv); int libertas_set_universaltable(wlan_private * priv, u8 band); @@ -93,8 +91,6 @@ int libertas_cmd_802_11d_domain_info(wlan_private * priv, struct cmd_ds_command *cmd, u16 cmdno, u16 cmdOption); -int libertas_cmd_enable_11d(wlan_private * priv, struct iwreq *wrq); - int libertas_ret_802_11d_domain_info(wlan_private * priv, struct cmd_ds_command *resp); diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index c3fc074b6e3..85b57377070 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -1045,7 +1045,7 @@ done: return; } -void libertas_cleanup_and_insert_cmd(wlan_private * priv, struct cmd_ctrl_node *ptempcmd) +static void libertas_cleanup_and_insert_cmd(wlan_private * priv, struct cmd_ctrl_node *ptempcmd) { unsigned long flags; diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h index 113cfc1395e..095edf6a4c2 100644 --- a/drivers/net/wireless/libertas/decl.h +++ b/drivers/net/wireless/libertas/decl.h @@ -15,14 +15,9 @@ struct wlan_private; struct sk_buff; struct net_device; -extern char *libertas_fw_name; - -void libertas_free_adapter(wlan_private * priv); int libertas_set_mac_packet_filter(wlan_private * priv); -int libertas_send_null_packet(wlan_private * priv, u8 pwr_mgmt); void libertas_send_tx_feedback(wlan_private * priv); -u8 libertas_check_last_packet_indication(wlan_private * priv); int libertas_free_cmd_buffer(wlan_private * priv); struct cmd_ctrl_node; @@ -53,8 +48,6 @@ void libertas_upload_rx_packet(wlan_private * priv, struct sk_buff *skb); /** The proc fs interface */ int libertas_process_rx_command(wlan_private * priv); int libertas_process_tx(wlan_private * priv, struct sk_buff *skb); -void libertas_cleanup_and_insert_cmd(wlan_private * priv, - struct cmd_ctrl_node *ptempcmd); void __libertas_cleanup_and_insert_cmd(wlan_private * priv, struct cmd_ctrl_node *ptempcmd); diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index ac1cfc253fd..c28d9747b86 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -22,7 +22,7 @@ static const char usbdriver_name[] = "usb8xxx"; static u8 *default_fw_name = "usb8388.bin"; -char *libertas_fw_name = NULL; +static char *libertas_fw_name = NULL; module_param_named(fw_name, libertas_fw_name, charp, 0644); /* @@ -51,6 +51,8 @@ static int if_usb_prog_firmware(wlan_private *); static int if_usb_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb); static int if_usb_get_int_status(wlan_private * priv, u8 *); static int if_usb_read_event_cause(wlan_private *); +static int usb_tx_block(wlan_private *priv, u8 *payload, u16 nb); +static void if_usb_free(struct usb_card_rec *cardp); /** * @brief call back function to handle the status of the URB @@ -92,7 +94,7 @@ static void if_usb_write_bulk_callback(struct urb *urb) * @param cardp pointer usb_card_rec * @return N/A */ -void if_usb_free(struct usb_card_rec *cardp) +static void if_usb_free(struct usb_card_rec *cardp) { lbs_deb_enter(LBS_DEB_USB); @@ -384,7 +386,7 @@ static int if_usb_reset_device(wlan_private *priv) * @param nb data length * @return 0 or -1 */ -int usb_tx_block(wlan_private * priv, u8 * payload, u16 nb) +static int usb_tx_block(wlan_private * priv, u8 * payload, u16 nb) { /* pointer to card structure */ struct usb_card_rec *cardp = priv->card; diff --git a/drivers/net/wireless/libertas/if_usb.h b/drivers/net/wireless/libertas/if_usb.h index 5da8c94ca4c..8b3b4f1e47f 100644 --- a/drivers/net/wireless/libertas/if_usb.h +++ b/drivers/net/wireless/libertas/if_usb.h @@ -102,7 +102,4 @@ struct fwsyncheader { #define FW_DATA_XMIT_SIZE \ sizeof(struct fwheader) + le32_to_cpu(fwdata->fwheader.datalength) + sizeof(u32) -int usb_tx_block(wlan_private *priv, u8 *payload, u16 nb); -void if_usb_free(struct usb_card_rec *cardp); - #endif diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c index f71c172101a..f9799c3b81c 100644 --- a/drivers/net/wireless/libertas/join.c +++ b/drivers/net/wireless/libertas/join.c @@ -112,20 +112,6 @@ void libertas_unset_basic_rate_flags(u8 * rates, size_t len) } -int libertas_send_deauth(wlan_private * priv) -{ - wlan_adapter *adapter = priv->adapter; - int ret = 0; - - if (adapter->mode == IW_MODE_INFRA && - adapter->connect_status == LIBERTAS_CONNECTED) - ret = libertas_send_deauthentication(priv); - else - ret = -ENOTSUPP; - - return ret; -} - /** * @brief Associate to a specific BSS discovered in a scan * diff --git a/drivers/net/wireless/libertas/join.h b/drivers/net/wireless/libertas/join.h index 8ea5ae30f4a..894a072b9f8 100644 --- a/drivers/net/wireless/libertas/join.h +++ b/drivers/net/wireless/libertas/join.h @@ -12,44 +12,39 @@ #include "dev.h" struct cmd_ds_command; -extern int libertas_cmd_80211_authenticate(wlan_private * priv, +int libertas_cmd_80211_authenticate(wlan_private * priv, struct cmd_ds_command *cmd, void *pdata_buf); -extern int libertas_cmd_80211_ad_hoc_join(wlan_private * priv, +int libertas_cmd_80211_ad_hoc_join(wlan_private * priv, struct cmd_ds_command *cmd, void *pdata_buf); -extern int libertas_cmd_80211_ad_hoc_stop(wlan_private * priv, +int libertas_cmd_80211_ad_hoc_stop(wlan_private * priv, struct cmd_ds_command *cmd); -extern int libertas_cmd_80211_ad_hoc_start(wlan_private * priv, +int libertas_cmd_80211_ad_hoc_start(wlan_private * priv, struct cmd_ds_command *cmd, void *pdata_buf); -extern int libertas_cmd_80211_deauthenticate(wlan_private * priv, +int libertas_cmd_80211_deauthenticate(wlan_private * priv, struct cmd_ds_command *cmd); -extern int libertas_cmd_80211_associate(wlan_private * priv, +int libertas_cmd_80211_associate(wlan_private * priv, struct cmd_ds_command *cmd, void *pdata_buf); -extern int libertas_ret_80211_ad_hoc_start(wlan_private * priv, +int libertas_ret_80211_ad_hoc_start(wlan_private * priv, struct cmd_ds_command *resp); -extern int libertas_ret_80211_ad_hoc_stop(wlan_private * priv, +int libertas_ret_80211_ad_hoc_stop(wlan_private * priv, struct cmd_ds_command *resp); -extern int libertas_ret_80211_disassociate(wlan_private * priv, +int libertas_ret_80211_disassociate(wlan_private * priv, struct cmd_ds_command *resp); -extern int libertas_ret_80211_associate(wlan_private * priv, +int libertas_ret_80211_associate(wlan_private * priv, struct cmd_ds_command *resp); -extern int libertas_reassociation_thread(void *data); - -extern int libertas_start_adhoc_network(wlan_private * priv, +int libertas_start_adhoc_network(wlan_private * priv, struct assoc_request * assoc_req); -extern int libertas_join_adhoc_network(wlan_private * priv, +int libertas_join_adhoc_network(wlan_private * priv, struct assoc_request * assoc_req); -extern int libertas_stop_adhoc_network(wlan_private * priv); - -extern int libertas_send_deauthentication(wlan_private * priv); -extern int libertas_send_deauth(wlan_private * priv); +int libertas_stop_adhoc_network(wlan_private * priv); -extern int libertas_do_adhocstop_ioctl(wlan_private * priv); +int libertas_send_deauthentication(wlan_private * priv); int wlan_associate(wlan_private * priv, struct assoc_request * assoc_req); diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 7e417eacbc7..e8555de6576 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -890,6 +890,31 @@ static void command_timer_fn(unsigned long data) return; } +static void libertas_free_adapter(wlan_private * priv) +{ + wlan_adapter *adapter = priv->adapter; + + if (!adapter) { + lbs_deb_fw("why double free adapter?\n"); + return; + } + + lbs_deb_fw("free command buffer\n"); + libertas_free_cmd_buffer(priv); + + lbs_deb_fw("free command_timer\n"); + del_timer(&adapter->command_timer); + + lbs_deb_fw("free scan results table\n"); + kfree(adapter->networks); + adapter->networks = NULL; + + /* Free the adapter object itself */ + lbs_deb_fw("free adapter\n"); + kfree(adapter); + priv->adapter = NULL; +} + static int wlan_allocate_adapter(wlan_private * priv) { size_t bufsize; @@ -1009,31 +1034,6 @@ static void wlan_init_adapter(wlan_private * priv) return; } -void libertas_free_adapter(wlan_private * priv) -{ - wlan_adapter *adapter = priv->adapter; - - if (!adapter) { - lbs_deb_fw("why double free adapter?\n"); - return; - } - - lbs_deb_fw("free command buffer\n"); - libertas_free_cmd_buffer(priv); - - lbs_deb_fw("free command_timer\n"); - del_timer(&adapter->command_timer); - - lbs_deb_fw("free scan results table\n"); - kfree(adapter->networks); - adapter->networks = NULL; - - /* Free the adapter object itself */ - lbs_deb_fw("free adapter\n"); - kfree(adapter); - priv->adapter = NULL; -} - static int libertas_init_fw(wlan_private * priv) { int ret = -1; diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 790e9888ea2..683fa1ba5ca 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -1254,7 +1254,7 @@ out: * * @return index in BSSID list */ -struct bss_descriptor * libertas_find_best_ssid_in_list(wlan_adapter * adapter, +static struct bss_descriptor * libertas_find_best_ssid_in_list(wlan_adapter * adapter, u8 mode) { u8 bestrssi = 0; @@ -1386,39 +1386,6 @@ out: return ret; } -/** - * @brief scan an AP with specific BSSID - * - * @param priv A pointer to wlan_private structure - * @param bssid A pointer to AP's bssid - * @param keeppreviousscan Flag used to save/clear scan table before scan - * - * @return 0-success, otherwise fail - */ -int libertas_send_specific_bssid_scan(wlan_private * priv, u8 * bssid, u8 clear_bssid) -{ - struct wlan_ioctl_user_scan_cfg scancfg; - - lbs_deb_enter(LBS_DEB_ASSOC); - - if (bssid == NULL) - goto out; - - memset(&scancfg, 0x00, sizeof(scancfg)); - memcpy(scancfg.bssid, bssid, ETH_ALEN); - scancfg.clear_bssid = clear_bssid; - - wlan_scan_networks(priv, &scancfg, 1); - if (priv->adapter->surpriseremoved) - return -1; - wait_event_interruptible(priv->adapter->cmd_pending, - !priv->adapter->nr_cmd_pending); - -out: - lbs_deb_leave(LBS_DEB_ASSOC); - return 0; -} - static inline char *libertas_translate_scan(wlan_private *priv, char *start, char *stop, struct bss_descriptor *bss) diff --git a/drivers/net/wireless/libertas/scan.h b/drivers/net/wireless/libertas/scan.h index 8c3508b3257..def0db5c4e6 100644 --- a/drivers/net/wireless/libertas/scan.h +++ b/drivers/net/wireless/libertas/scan.h @@ -175,31 +175,26 @@ struct bss_descriptor { struct list_head list; }; -extern int libertas_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len); +int libertas_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len); struct bss_descriptor * libertas_find_ssid_in_list(wlan_adapter * adapter, u8 *ssid, u8 ssid_len, u8 * bssid, u8 mode, int channel); -struct bss_descriptor * libertas_find_best_ssid_in_list(wlan_adapter * adapter, - u8 mode); - -extern struct bss_descriptor * libertas_find_bssid_in_list(wlan_adapter * adapter, +struct bss_descriptor * libertas_find_bssid_in_list(wlan_adapter * adapter, u8 * bssid, u8 mode); int libertas_find_best_network_ssid(wlan_private * priv, u8 *out_ssid, u8 *out_ssid_len, u8 preferred_mode, u8 *out_mode); -extern int libertas_send_specific_ssid_scan(wlan_private * priv, u8 *ssid, +int libertas_send_specific_ssid_scan(wlan_private * priv, u8 *ssid, u8 ssid_len, u8 clear_ssid); -extern int libertas_send_specific_bssid_scan(wlan_private * priv, - u8 * bssid, u8 clear_bssid); -extern int libertas_cmd_80211_scan(wlan_private * priv, +int libertas_cmd_80211_scan(wlan_private * priv, struct cmd_ds_command *cmd, void *pdata_buf); -extern int libertas_ret_80211_scan(wlan_private * priv, +int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp); int wlan_scan_networks(wlan_private * priv, @@ -211,9 +206,9 @@ struct ifreq; struct iw_point; struct iw_param; struct iw_request_info; -extern int libertas_get_scan(struct net_device *dev, struct iw_request_info *info, +int libertas_get_scan(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra); -extern int libertas_set_scan(struct net_device *dev, struct iw_request_info *info, +int libertas_set_scan(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra); #endif /* _WLAN_SCAN_H */ diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 0b805e32993..e8c0629f9a4 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -157,7 +157,7 @@ static struct chan_freq_power *find_cfp_by_band_and_freq(wlan_adapter * adapter, * @option Radio Option * @return 0 --success, otherwise fail */ -int wlan_radio_ioctl(wlan_private * priv, u8 option) +static int wlan_radio_ioctl(wlan_private * priv, u8 option) { int ret = 0; wlan_adapter *adapter = priv->adapter; diff --git a/drivers/net/wireless/libertas/wext.h b/drivers/net/wireless/libertas/wext.h index 3d5196c9553..5b0bbc99a21 100644 --- a/drivers/net/wireless/libertas/wext.h +++ b/drivers/net/wireless/libertas/wext.h @@ -4,9 +4,6 @@ #ifndef _WLAN_WEXT_H_ #define _WLAN_WEXT_H_ -#define SUBCMD_OFFSET 4 -#define SUBCMD_DATA(x) *((int *)(x->u.name + SUBCMD_OFFSET)) - /** wlan_ioctl_regrdwr */ struct wlan_ioctl_regrdwr { /** Which register to access */ @@ -25,6 +22,5 @@ struct wlan_ioctl_regrdwr { extern struct iw_handler_def libertas_handler_def; extern struct iw_handler_def mesh_handler_def; -int wlan_radio_ioctl(wlan_private * priv, u8 option); #endif /* _WLAN_WEXT_H_ */ -- cgit v1.2.3-70-g09d2 From c95c7f930ec6fee029c8e7957ab95b3967578070 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 11:49:45 -0400 Subject: [PATCH] libertas: uppercase some #defines Usually constants defined by #define are in ALL_UPPERCASE. This patch fixes this. I also shuffled the bits around so that they match the bit positions in the host-interrupt-state register of the CF/SDIO card :-) Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/defs.h | 8 +++++--- drivers/net/wireless/libertas/if_usb.c | 6 +++--- drivers/net/wireless/libertas/main.c | 8 ++++---- 3 files changed, 12 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h index a1c6dae1ba4..eee8a49e358 100644 --- a/drivers/net/wireless/libertas/defs.h +++ b/drivers/net/wireless/libertas/defs.h @@ -159,9 +159,11 @@ static inline void lbs_dbg_hex(char *prompt, u8 * buf, int len) #define MARVELL_MESH_IE_LENGTH 9 /** INT status Bit Definition*/ -#define his_cmddnldrdy 0x01 -#define his_cardevent 0x02 -#define his_cmdupldrdy 0x04 +#define MRVDRV_TX_DNLD_RDY 0x0001 +#define MRVDRV_RX_UPLD_RDY 0x0002 +#define MRVDRV_CMD_DNLD_RDY 0x0004 +#define MRVDRV_CMD_UPLD_RDY 0x0008 +#define MRVDRV_CARDEVENT 0x0010 #define SBI_EVENT_CAUSE_SHIFT 3 diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index c28d9747b86..5efdeac6e20 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -601,11 +601,11 @@ static inline void process_cmdrequest(int recvlength, u8 *recvbuff, * data to clear the interrupt */ if (!priv->adapter->cur_cmd) { cmdbuf = priv->upld_buf; - priv->adapter->hisregcpy &= ~his_cmdupldrdy; + priv->adapter->hisregcpy &= ~MRVDRV_CMD_UPLD_RDY; } else cmdbuf = priv->adapter->cur_cmd->bufvirtualaddr; - cardp->usb_int_cause |= his_cmdupldrdy; + cardp->usb_int_cause |= MRVDRV_CMD_UPLD_RDY; priv->upld_len = (recvlength - MESSAGE_HEADER_LEN); memcpy(cmdbuf, recvbuff + MESSAGE_HEADER_LEN, priv->upld_len); @@ -682,7 +682,7 @@ static void if_usb_receive(struct urb *urb) break; } cardp->usb_event_cause <<= 3; - cardp->usb_int_cause |= his_cardevent; + cardp->usb_int_cause |= MRVDRV_CARDEVENT; kfree_skb(skb); libertas_interrupt(priv->dev); spin_unlock(&priv->adapter->driver_lock); diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index e8555de6576..170dc2394d2 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -711,20 +711,20 @@ static int libertas_thread(void *data) adapter->currenttxskb, priv->dnld_sent); /* command response? */ - if (adapter->hisregcpy & his_cmdupldrdy) { + if (adapter->hisregcpy & MRVDRV_CMD_UPLD_RDY) { lbs_deb_thread("main-thread: cmd response ready\n"); - adapter->hisregcpy &= ~his_cmdupldrdy; + adapter->hisregcpy &= ~MRVDRV_CMD_UPLD_RDY; spin_unlock_irq(&adapter->driver_lock); libertas_process_rx_command(priv); spin_lock_irq(&adapter->driver_lock); } /* Any Card Event */ - if (adapter->hisregcpy & his_cardevent) { + if (adapter->hisregcpy & MRVDRV_CARDEVENT) { lbs_deb_thread("main-thread: Card Event Activity\n"); - adapter->hisregcpy &= ~his_cardevent; + adapter->hisregcpy &= ~MRVDRV_CARDEVENT; if (priv->hw_read_event_cause(priv)) { lbs_pr_alert( -- cgit v1.2.3-70-g09d2 From 3cf840914bd467fa4cc76af1a01bba4d2813131c Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 11:50:12 -0400 Subject: [PATCH] libertas: access mesh_dev more carefully The CF/SDIO firmware doesn't support Mesh, so priv->mesh_dev is NULL there. Protect all accesses. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/join.c | 12 ++++++++---- drivers/net/wireless/libertas/main.c | 16 ++++++++++------ drivers/net/wireless/libertas/scan.c | 12 ++++++++---- drivers/net/wireless/libertas/tx.c | 12 ++++++++---- 4 files changed, 34 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c index f9799c3b81c..da47c225e10 100644 --- a/drivers/net/wireless/libertas/join.c +++ b/drivers/net/wireless/libertas/join.c @@ -739,8 +739,10 @@ int libertas_ret_80211_associate(wlan_private * priv, netif_carrier_on(priv->dev); netif_wake_queue(priv->dev); - netif_carrier_on(priv->mesh_dev); - netif_wake_queue(priv->mesh_dev); + if (priv->mesh_dev) { + netif_carrier_on(priv->mesh_dev); + netif_wake_queue(priv->mesh_dev); + } lbs_deb_join("ASSOC_RESP: Associated \n"); @@ -827,8 +829,10 @@ int libertas_ret_80211_ad_hoc_start(wlan_private * priv, netif_carrier_on(priv->dev); netif_wake_queue(priv->dev); - netif_carrier_on(priv->mesh_dev); - netif_wake_queue(priv->mesh_dev); + if (priv->mesh_dev) { + netif_carrier_on(priv->mesh_dev); + netif_wake_queue(priv->mesh_dev); + } memset(&wrqu, 0, sizeof(wrqu)); memcpy(wrqu.ap_addr.sa_data, adapter->curbssparams.bssid, ETH_ALEN); diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 170dc2394d2..b4e2cd19c3b 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -298,10 +298,12 @@ static int libertas_dev_open(struct net_device *dev) if (adapter->connect_status == LIBERTAS_CONNECTED) { netif_carrier_on(priv->dev); - netif_carrier_on(priv->mesh_dev); + if (priv->mesh_dev) + netif_carrier_on(priv->mesh_dev); } else { netif_carrier_off(priv->dev); - netif_carrier_off(priv->mesh_dev); + if (priv->mesh_dev) + netif_carrier_off(priv->mesh_dev); } lbs_deb_leave(LBS_DEB_NET); @@ -408,7 +410,8 @@ static int libertas_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) } netif_stop_queue(priv->dev); - netif_stop_queue(priv->mesh_dev); + if (priv->mesh_dev) + netif_stop_queue(priv->mesh_dev); if (libertas_process_tx(priv, skb) == 0) dev->trans_start = jiffies; @@ -474,7 +477,8 @@ static void libertas_tx_timeout(struct net_device *dev) wake_up_interruptible(&priv->waitq); } else if (priv->adapter->connect_status == LIBERTAS_CONNECTED) { netif_wake_queue(priv->dev); - netif_wake_queue(priv->mesh_dev); + if (priv->mesh_dev) + netif_wake_queue(priv->mesh_dev); } lbs_deb_leave(LBS_DEB_TX); @@ -1254,7 +1258,6 @@ int libertas_add_mesh(wlan_private *priv, struct device *dev) ret = 0; goto done; - err_unregister: unregister_netdev(mesh_dev); @@ -1454,7 +1457,8 @@ void libertas_interrupt(struct net_device *dev) if (priv->adapter->psstate == PS_STATE_SLEEP) { priv->adapter->psstate = PS_STATE_AWAKE; netif_wake_queue(dev); - netif_wake_queue(priv->mesh_dev); + if (priv->mesh_dev) + netif_wake_queue(priv->mesh_dev); } wake_up_interruptible(&priv->waitq); diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 683fa1ba5ca..7f045ec2441 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -793,8 +793,10 @@ int wlan_scan_networks(wlan_private * priv, if (!scancurrentchanonly) { netif_stop_queue(priv->dev); netif_carrier_off(priv->dev); - netif_stop_queue(priv->mesh_dev); - netif_carrier_off(priv->mesh_dev); + if (priv->mesh_dev) { + netif_stop_queue(priv->mesh_dev); + netif_carrier_off(priv->mesh_dev); + } } ret = wlan_scan_channel_list(priv, @@ -820,8 +822,10 @@ int wlan_scan_networks(wlan_private * priv, if (priv->adapter->connect_status == LIBERTAS_CONNECTED) { netif_carrier_on(priv->dev); netif_wake_queue(priv->dev); - netif_carrier_on(priv->mesh_dev); - netif_wake_queue(priv->mesh_dev); + if (priv->mesh_dev) { + netif_carrier_on(priv->mesh_dev); + netif_wake_queue(priv->mesh_dev); + } } out: diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c index c2271020aaf..7c383014a27 100644 --- a/drivers/net/wireless/libertas/tx.c +++ b/drivers/net/wireless/libertas/tx.c @@ -159,7 +159,8 @@ done: skb_orphan(skb); /* stop processing outgoing pkts */ netif_stop_queue(priv->dev); - netif_stop_queue(priv->mesh_dev); + if (priv->mesh_dev) + netif_stop_queue(priv->mesh_dev); /* freeze any packets already in our queues */ priv->adapter->TxLockFlag = 1; } else { @@ -198,10 +199,12 @@ static void wlan_tx_queue(wlan_private *priv, struct sk_buff *skb) adapter->tx_queue_ps[adapter->tx_queue_idx++] = skb; if (adapter->tx_queue_idx == NR_TX_QUEUE) { netif_stop_queue(priv->dev); - netif_stop_queue(priv->mesh_dev); + if (priv->mesh_dev) + netif_stop_queue(priv->mesh_dev); } else { netif_start_queue(priv->dev); - netif_start_queue(priv->mesh_dev); + if (priv->mesh_dev) + netif_start_queue(priv->mesh_dev); } spin_unlock(&adapter->txqueue_lock); @@ -285,7 +288,8 @@ void libertas_send_tx_feedback(wlan_private * priv) priv->adapter->TxLockFlag = 0; if (priv->adapter->connect_status == LIBERTAS_CONNECTED) { netif_wake_queue(priv->dev); - netif_wake_queue(priv->mesh_dev); + if (priv->mesh_dev) + netif_wake_queue(priv->mesh_dev); } } EXPORT_SYMBOL_GPL(libertas_send_tx_feedback); -- cgit v1.2.3-70-g09d2 From 0a6d0555e90850b7ce90e8937858f11b6b98b6d4 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 11:50:35 -0400 Subject: [PATCH] libertas: tune hardware info output This changes the output of hardware related info from: libertas: GET_HW_SPEC: FWReleaseVersion- 5.0.11.p0 libertas: GET_HW_SPEC: Permanent addr- 0:16:41:72:f6:a8 libertas: GET_HW_SPEC: hwifversion=0x2 version=0x213 to: libertas: GET_HW_SPEC: FWReleaseVersion: 5.0.11.p0 libertas: GET_HW_SPEC: Permanent addr: 00:16:41:72:f6:a8 libertas: GET_HW_SPEC: hwifversion: 0x2, version: 0x213 Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmdresp.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 577c434089b..bb1d72b2b52 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -173,14 +173,12 @@ static int wlan_ret_get_hw_spec(wlan_private * priv, memcpy(adapter->fwreleasenumber, hwspec->fwreleasenumber, 4); - lbs_deb_cmd("GET_HW_SPEC: FWReleaseVersion- %u.%u.%u.p%u\n", + lbs_deb_cmd("GET_HW_SPEC: FWReleaseVersion: %u.%u.%u.p%u\n", adapter->fwreleasenumber[2], adapter->fwreleasenumber[1], adapter->fwreleasenumber[0], adapter->fwreleasenumber[3]); - lbs_deb_cmd("GET_HW_SPEC: Permanent addr- %2x:%2x:%2x:%2x:%2x:%2x\n", - hwspec->permanentaddr[0], hwspec->permanentaddr[1], - hwspec->permanentaddr[2], hwspec->permanentaddr[3], - hwspec->permanentaddr[4], hwspec->permanentaddr[5]); - lbs_deb_cmd("GET_HW_SPEC: hwifversion=0x%X version=0x%X\n", + lbs_deb_cmd("GET_HW_SPEC: Permanent addr: " MAC_FMT "\n", + MAC_ARG(hwspec->permanentaddr)); + lbs_deb_cmd("GET_HW_SPEC: hwifversion: 0x%x version:0x%x\n", hwspec->hwifversion, hwspec->version); adapter->regioncode = le16_to_cpu(hwspec->regioncode); -- cgit v1.2.3-70-g09d2 From f455eb1a4ba2bf0ff1bde7844bf3a811269d2d79 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 11:51:18 -0400 Subject: [PATCH] libertas: remove debugmode There is nowhere any place that set's this variable. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/defs.h | 3 --- drivers/net/wireless/libertas/dev.h | 1 - drivers/net/wireless/libertas/rx.c | 4 ---- drivers/net/wireless/libertas/tx.c | 8 -------- 4 files changed, 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h index eee8a49e358..e47fadf3722 100644 --- a/drivers/net/wireless/libertas/defs.h +++ b/drivers/net/wireless/libertas/defs.h @@ -149,9 +149,6 @@ static inline void lbs_dbg_hex(char *prompt, u8 * buf, int len) #define MRVDRV_CHANNELS_PER_SCAN 4 #define MRVDRV_MAX_CHANNELS_PER_SCAN 14 -#define MRVDRV_DEBUG_RX_PATH 0x00000001 -#define MRVDRV_DEBUG_TX_PATH 0x00000002 - #define MRVDRV_MIN_BEACON_INTERVAL 20 #define MRVDRV_MAX_BEACON_INTERVAL 1000 #define MRVDRV_BEACON_INTERVAL 100 diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 6acb8fb8733..7c565cbf8cc 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -393,7 +393,6 @@ struct _wlan_adapter { u16 txrate; u32 linkmode; u32 radiomode; - u32 debugmode; u8 fw_ready; u8 last_scanned_channel; diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c index e78636d6651..c9251abbb96 100644 --- a/drivers/net/wireless/libertas/rx.c +++ b/drivers/net/wireless/libertas/rx.c @@ -172,10 +172,6 @@ int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *skb) lbs_deb_enter(LBS_DEB_RX); - if (priv->adapter->debugmode & MRVDRV_DEBUG_RX_PATH) - lbs_dbg_hex("RX packet: ", skb->data, - min_t(unsigned int, skb->len, 100)); - if (priv->adapter->linkmode == WLAN_LINKMODE_802_11) return process_rxed_802_11_packet(priv, skb); diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c index 7c383014a27..7743d3f30f6 100644 --- a/drivers/net/wireless/libertas/tx.c +++ b/drivers/net/wireless/libertas/tx.c @@ -72,10 +72,6 @@ static int SendSinglePacket(wlan_private * priv, struct sk_buff *skb) if (priv->adapter->surpriseremoved) return -1; - if ((priv->adapter->debugmode & MRVDRV_DEBUG_TX_PATH) != 0) - lbs_dbg_hex("TX packet: ", skb->data, - min_t(unsigned int, skb->len, 100)); - if (!skb->len || (skb->len > MRVDRV_ETH_TX_PACKET_BUFFER_SIZE)) { lbs_deb_tx("tx err: skb length %d 0 or > %zd\n", skb->len, MRVDRV_ETH_TX_PACKET_BUFFER_SIZE); @@ -267,10 +263,6 @@ void libertas_send_tx_feedback(wlan_private * priv) radiotap_hdr = (struct tx_radiotap_hdr *)adapter->currenttxskb->data; - if ((adapter->debugmode & MRVDRV_DEBUG_TX_PATH) != 0) - lbs_dbg_hex("TX feedback: ", (u8 *) radiotap_hdr, - min_t(unsigned int, adapter->currenttxskb->len, 100)); - txfail = (status >> 24); #if 0 -- cgit v1.2.3-70-g09d2 From a9f38d023b65c9fe2602303c1101c868be4fcbcc Mon Sep 17 00:00:00 2001 From: Luis Carlos Cobo Date: Thu, 2 Aug 2007 11:52:29 -0400 Subject: [PATCH] Support for mesh autostart deactivation through sysfs echo 0 > /sys/class/net/mshX/autostart_enabled This is supported from Marvell firmware version 5.110.16.p0 (to be released). Signed-off-by: Luis Carlos Cobo Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/host.h | 2 ++ drivers/net/wireless/libertas/main.c | 48 ++++++++++++++++++++++++++++++++++-- 2 files changed, 48 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index 308ccdbed34..12d5dd9af40 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -320,6 +320,8 @@ enum cmd_mesh_access_opts { CMD_ACT_MESH_GET_RREQ_DELAY, CMD_ACT_MESH_SET_ROUTE_EXP, CMD_ACT_MESH_GET_ROUTE_EXP, + CMD_ACT_MESH_SET_AUTOSTART_ENABLED, + CMD_ACT_MESH_GET_AUTOSTART_ENABLED, }; /** Card Event definition */ diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index b4e2cd19c3b..717b33616ea 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -252,6 +252,50 @@ static ssize_t libertas_anycast_set(struct device * dev, */ static DEVICE_ATTR(anycast_mask, 0644, libertas_anycast_get, libertas_anycast_set); +static ssize_t libertas_autostart_enabled_get(struct device * dev, + struct device_attribute *attr, char * buf) +{ + struct cmd_ds_mesh_access mesh_access; + + memset(&mesh_access, 0, sizeof(mesh_access)); + libertas_prepare_and_send_command(to_net_dev(dev)->priv, + CMD_MESH_ACCESS, + CMD_ACT_MESH_GET_AUTOSTART_ENABLED, + CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access); + + return sprintf(buf, "%d\n", le32_to_cpu(mesh_access.data[0])); +} + +static ssize_t libertas_autostart_enabled_set(struct device * dev, + struct device_attribute *attr, const char * buf, size_t count) +{ + struct cmd_ds_mesh_access mesh_access; + uint32_t datum; + + memset(&mesh_access, 0, sizeof(mesh_access)); + sscanf(buf, "%d", &datum); + mesh_access.data[0] = cpu_to_le32(datum); + + libertas_prepare_and_send_command((to_net_dev(dev))->priv, + CMD_MESH_ACCESS, + CMD_ACT_MESH_SET_AUTOSTART_ENABLED, + CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access); + return strlen(buf); +} + +static DEVICE_ATTR(autostart_enabled, 0644, + libertas_autostart_enabled_get, libertas_autostart_enabled_set); + +static struct attribute *libertas_mesh_sysfs_entries[] = { + &dev_attr_anycast_mask.attr, + &dev_attr_autostart_enabled.attr, + NULL, +}; + +static struct attribute_group libertas_mesh_attr_group = { + .attrs = libertas_mesh_sysfs_entries, +}; + /** * @brief Check if the device can be open and wait if necessary. * @@ -1250,7 +1294,7 @@ int libertas_add_mesh(wlan_private *priv, struct device *dev) goto err_free; } - ret = device_create_file(&(mesh_dev->dev), &dev_attr_anycast_mask); + ret = sysfs_create_group(&(mesh_dev->dev.kobj), &libertas_mesh_attr_group); if (ret) goto err_unregister; @@ -1359,7 +1403,7 @@ void libertas_remove_mesh(wlan_private *priv) netif_stop_queue(mesh_dev); netif_carrier_off(priv->mesh_dev); - device_remove_file(&(mesh_dev->dev), &dev_attr_anycast_mask); + sysfs_remove_group(&(mesh_dev->dev.kobj), &libertas_mesh_attr_group); unregister_netdev(mesh_dev); priv->mesh_dev = NULL ; -- cgit v1.2.3-70-g09d2 From ece561919326236c7fb791a5e883f0eb76af029e Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 11:53:06 -0400 Subject: [PATCH] libertas: make the hex dumper nicer Currently, when you define LBS_DEB_HEX, you get every hex dump in the whole driver, e.g. for LBS_DEB_CMD, LBS_DEB_RX, LBS_DEB_TX etc. This patch makes sure that you only get the hexdump that you're interested in. Renamed lbs_dbg_hex() into lbs_deb_hex(), like the other lbs_deb_XXX() macros. Made lbs_deb_hex() issue a line feed (and a new prompt) after 16 bytes. As lbs_deb_hex() now prints the ":" after the prompt by itself, removed the misc colons in the various *.c files. lbs_deb_XXX() now print the debug category as well. As lbs_deb_XXX() --- and especially lbs_deb_11d() --- now print the category, I removed various "11D:" prefixes in 11d.c as well. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/11d.c | 62 ++++++++++++------------- drivers/net/wireless/libertas/cmd.c | 12 ++--- drivers/net/wireless/libertas/cmdresp.c | 6 +-- drivers/net/wireless/libertas/defs.h | 80 ++++++++++++++++++--------------- drivers/net/wireless/libertas/join.c | 10 ++--- drivers/net/wireless/libertas/main.c | 6 +-- drivers/net/wireless/libertas/rx.c | 13 +++--- drivers/net/wireless/libertas/scan.c | 12 ++--- drivers/net/wireless/libertas/tx.c | 6 +-- 9 files changed, 105 insertions(+), 102 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/11d.c b/drivers/net/wireless/libertas/11d.c index ba4cbcb5911..8b366ef2fe9 100644 --- a/drivers/net/wireless/libertas/11d.c +++ b/drivers/net/wireless/libertas/11d.c @@ -124,17 +124,17 @@ static u8 wlan_channel_known_11d(u8 chan, u8 nr_chan = parsed_region_chan->nr_chan; u8 i = 0; - lbs_dbg_hex("11D:parsed_region_chan:", (char *)chanpwr, + lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (char *)chanpwr, sizeof(struct chan_power_11d) * nr_chan); for (i = 0; i < nr_chan; i++) { if (chan == chanpwr[i].chan) { - lbs_deb_11d("11D: Found Chan:%d\n", chan); + lbs_deb_11d("found chan %d\n", chan); return 1; } } - lbs_deb_11d("11D: Not Find Chan:%d\n", chan); + lbs_deb_11d("chan %d not found\n", chan); return 0; } @@ -174,8 +174,8 @@ static int generate_domain_info_11d(struct parsed_region_chan_11d memcpy(domaininfo->countrycode, parsed_region_chan->countrycode, COUNTRY_CODE_LEN); - lbs_deb_11d("11D:nrchan=%d\n", nr_chan); - lbs_dbg_hex("11D:parsed_region_chan:", (char *)parsed_region_chan, + lbs_deb_11d("nrchan %d\n", nr_chan); + lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (char *)parsed_region_chan, sizeof(struct parsed_region_chan_11d)); for (i = 0; i < nr_chan; i++) { @@ -213,7 +213,7 @@ static int generate_domain_info_11d(struct parsed_region_chan_11d domaininfo->nr_subband = nr_subband; lbs_deb_11d("nr_subband=%x\n", domaininfo->nr_subband); - lbs_dbg_hex("11D:domaininfo:", (char *)domaininfo, + lbs_deb_hex(LBS_DEB_11D, "domaininfo", (char *)domaininfo, COUNTRY_CODE_LEN + 1 + sizeof(struct ieeetypes_subbandset) * nr_subband); return 0; @@ -233,13 +233,13 @@ static void wlan_generate_parsed_region_chan_11d(struct region_channel * region_ struct chan_freq_power *cfp; if (region_chan == NULL) { - lbs_deb_11d("11D: region_chan is NULL\n"); + lbs_deb_11d("region_chan is NULL\n"); return; } cfp = region_chan->CFP; if (cfp == NULL) { - lbs_deb_11d("11D: cfp equal NULL \n"); + lbs_deb_11d("cfp is NULL \n"); return; } @@ -248,19 +248,19 @@ static void wlan_generate_parsed_region_chan_11d(struct region_channel * region_ memcpy(parsed_region_chan->countrycode, wlan_code_2_region(region_chan->region), COUNTRY_CODE_LEN); - lbs_deb_11d("11D: region[0x%x] band[%d]\n", parsed_region_chan->region, + lbs_deb_11d("region 0x%x, band %d\n", parsed_region_chan->region, parsed_region_chan->band); for (i = 0; i < region_chan->nrcfp; i++, cfp++) { parsed_region_chan->chanpwr[i].chan = cfp->channel; parsed_region_chan->chanpwr[i].pwr = cfp->maxtxpower; - lbs_deb_11d("11D: Chan[%d] Pwr[%d]\n", + lbs_deb_11d("chan %d, pwr %d\n", parsed_region_chan->chanpwr[i].chan, parsed_region_chan->chanpwr[i].pwr); } parsed_region_chan->nr_chan = region_chan->nrcfp; - lbs_deb_11d("11D: nrchan[%d]\n", parsed_region_chan->nr_chan); + lbs_deb_11d("nrchan %d\n", parsed_region_chan->nr_chan); return; } @@ -336,7 +336,7 @@ static int parse_domain_info_11d(struct ieeetypes_countryinfofullset* 6. Others */ - lbs_dbg_hex("CountryInfo:", (u8 *) countryinfo, 30); + lbs_deb_hex(LBS_DEB_11D, "countryinfo", (u8 *) countryinfo, 30); if ((*(countryinfo->countrycode)) == 0 || (countryinfo->len <= COUNTRY_CODE_LEN)) { @@ -349,7 +349,7 @@ static int parse_domain_info_11d(struct ieeetypes_countryinfofullset* wlan_region_2_code(countryinfo->countrycode); lbs_deb_11d("regioncode=%x\n", (u8) parsed_region_chan->region); - lbs_dbg_hex("CountryCode:", (char *)countryinfo->countrycode, + lbs_deb_hex(LBS_DEB_11D, "countrycode", (char *)countryinfo->countrycode, COUNTRY_CODE_LEN); parsed_region_chan->band = band; @@ -364,7 +364,7 @@ static int parse_domain_info_11d(struct ieeetypes_countryinfofullset* if (countryinfo->subband[j].firstchan <= lastchan) { /*Step2&3. Check First Chan Num increment and no overlap */ - lbs_deb_11d("11D: Chan[%d>%d] Overlap\n", + lbs_deb_11d("chan %d>%d, overlap\n", countryinfo->subband[j].firstchan, lastchan); continue; } @@ -393,7 +393,7 @@ static int parse_domain_info_11d(struct ieeetypes_countryinfofullset* } else { /*not supported and ignore the chan */ lbs_deb_11d( - "11D:i[%d] chan[%d] unsupported in region[%x] band[%d]\n", + "i %d, chan %d unsupported in region %x, band %d\n", i, curchan, region, band); } } @@ -405,7 +405,7 @@ static int parse_domain_info_11d(struct ieeetypes_countryinfofullset* parsed_region_chan->nr_chan = idx; lbs_deb_11d("nrchan=%x\n", parsed_region_chan->nr_chan); - lbs_dbg_hex("11D:parsed_region_chan:", (u8 *) parsed_region_chan, + lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (u8 *) parsed_region_chan, 2 + COUNTRY_CODE_LEN + sizeof(struct parsed_region_chan_11d) * idx); done: @@ -427,10 +427,10 @@ u8 libertas_get_scan_type_11d(u8 chan, lbs_deb_enter(LBS_DEB_11D); if (wlan_channel_known_11d(chan, parsed_region_chan)) { - lbs_deb_11d("11D: Found and do Active Scan\n"); + lbs_deb_11d("found, do active scan\n"); scan_type = CMD_SCAN_TYPE_ACTIVE; } else { - lbs_deb_11d("11D: Not Find and do Passive Scan\n"); + lbs_deb_11d("not found, do passive scan\n"); } lbs_deb_leave_args(LBS_DEB_11D, "ret scan_type %d", scan_type); @@ -456,7 +456,7 @@ static int set_domain_info_11d(wlan_private * priv) int ret; if (!priv->adapter->enable11d) { - lbs_deb_11d("11D: dnld domain Info with 11d disabled\n"); + lbs_deb_11d("dnld domain Info with 11d disabled\n"); return 0; } @@ -464,7 +464,7 @@ static int set_domain_info_11d(wlan_private * priv) CMD_ACT_SET, CMD_OPTION_WAITFORRSP, 0, NULL); if (ret) - lbs_deb_11d("11D: Fail to dnld domain Info\n"); + lbs_deb_11d("fail to dnld domain info\n"); return ret; } @@ -486,7 +486,7 @@ int libertas_set_universaltable(wlan_private * priv, u8 band) adapter->universal_channel[i].nrcfp = sizeof(channel_freq_power_UN_BG) / size; - lbs_deb_11d("11D: BG-band nrcfp=%d\n", + lbs_deb_11d("BG-band nrcfp %d\n", adapter->universal_channel[i].nrcfp); adapter->universal_channel[i].CFP = channel_freq_power_UN_BG; @@ -525,7 +525,7 @@ int libertas_cmd_802_11d_domain_info(wlan_private * priv, if (cmdoption == CMD_ACT_GET) { cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN); - lbs_dbg_hex("11D: 802_11D_DOMAIN_INFO:", (u8 *) cmd, + lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd, (int)(cmd->size)); goto done; } @@ -551,7 +551,7 @@ int libertas_cmd_802_11d_domain_info(wlan_private * priv, cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN); } - lbs_dbg_hex("11D:802_11D_DOMAIN_INFO:", (u8 *) cmd, le16_to_cpu(cmd->size)); + lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd, le16_to_cpu(cmd->size)); done: lbs_deb_enter(LBS_DEB_11D); @@ -575,13 +575,13 @@ int libertas_ret_802_11d_domain_info(wlan_private * priv, lbs_deb_enter(LBS_DEB_11D); - lbs_dbg_hex("11D DOMAIN Info Rsp Data:", (u8 *) resp, + lbs_deb_hex(LBS_DEB_11D, "domain info resp", (u8 *) resp, (int)le16_to_cpu(resp->size)); nr_subband = (le16_to_cpu(domain->header.len) - COUNTRY_CODE_LEN) / sizeof(struct ieeetypes_subbandset); - lbs_deb_11d("11D Domain Info Resp: nr_subband=%d\n", nr_subband); + lbs_deb_11d("domain info resp: nr_subband %d\n", nr_subband); if (nr_subband > MRVDRV_MAX_SUBBAND_802_11D) { lbs_deb_11d("Invalid Numrer of Subband returned!!\n"); @@ -623,7 +623,7 @@ int libertas_parse_dnld_countryinfo_11d(wlan_private * priv, &adapter->parsed_region_chan); if (ret == -1) { - lbs_deb_11d("11D: Err Parse domain_info from AP..\n"); + lbs_deb_11d("error parsing domain_info from AP\n"); goto done; } @@ -635,7 +635,7 @@ int libertas_parse_dnld_countryinfo_11d(wlan_private * priv, ret = set_domain_info_11d(priv); if (ret) { - lbs_deb_11d("11D: Err set domainInfo to FW\n"); + lbs_deb_11d("error setting domain info\n"); goto done; } } @@ -659,7 +659,7 @@ int libertas_create_dnld_countryinfo_11d(wlan_private * priv) u8 j; lbs_deb_enter(LBS_DEB_11D); - lbs_deb_11d("11D:curbssparams.band[%d]\n", adapter->curbssparams.band); + lbs_deb_11d("curbssparams.band %d\n", adapter->curbssparams.band); if (priv->adapter->enable11d) { /* update parsed_region_chan_11; dnld domaininf to FW */ @@ -668,7 +668,7 @@ int libertas_create_dnld_countryinfo_11d(wlan_private * priv) sizeof(adapter->region_channel[0]); j++) { region_chan = &adapter->region_channel[j]; - lbs_deb_11d("11D:[%d] region_chan->band[%d]\n", j, + lbs_deb_11d("%d region_chan->band %d\n", j, region_chan->band); if (!region_chan || !region_chan->valid @@ -681,7 +681,7 @@ int libertas_create_dnld_countryinfo_11d(wlan_private * priv) if (j >= sizeof(adapter->region_channel) / sizeof(adapter->region_channel[0])) { - lbs_deb_11d("11D:region_chan not found. band[%d]\n", + lbs_deb_11d("region_chan not found, band %d\n", adapter->curbssparams.band); ret = -1; goto done; @@ -701,7 +701,7 @@ int libertas_create_dnld_countryinfo_11d(wlan_private * priv) ret = set_domain_info_11d(priv); if (ret) { - lbs_deb_11d("11D: Err set domainInfo to FW\n"); + lbs_deb_11d("error setting domain info\n"); goto done; } diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 85b57377070..8d2f9bad868 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -773,7 +773,7 @@ static int wlan_cmd_802_11_mac_address(wlan_private * priv, if (cmd_action == CMD_ACT_SET) { memcpy(cmd->params.macadd.macadd, adapter->current_addr, ETH_ALEN); - lbs_dbg_hex("SET_CMD: MAC ADDRESS-", adapter->current_addr, 6); + lbs_deb_hex(LBS_DEB_CMD, "SET_CMD: MAC addr", adapter->current_addr, 6); } return 0; @@ -815,11 +815,11 @@ static int wlan_cmd_bt_access(wlan_private * priv, switch (cmd_action) { case CMD_ACT_BT_ACCESS_ADD: memcpy(bt_access->addr1, pdata_buf, 2 * ETH_ALEN); - lbs_dbg_hex("BT_ADD: blinded mac address-", bt_access->addr1, 6); + lbs_deb_hex(LBS_DEB_MESH, "BT_ADD: blinded MAC addr", bt_access->addr1, 6); break; case CMD_ACT_BT_ACCESS_DEL: memcpy(bt_access->addr1, pdata_buf, 1 * ETH_ALEN); - lbs_dbg_hex("BT_DEL: blinded mac address-", bt_access->addr1, 6); + lbs_deb_hex(LBS_DEB_MESH, "BT_DEL: blinded MAC addr", bt_access->addr1, 6); break; case CMD_ACT_BT_ACCESS_LIST: bt_access->id = cpu_to_le32(*(u32 *) pdata_buf); @@ -993,8 +993,8 @@ static int DownloadcommandToStation(wlan_private * priv, goto done; } - lbs_deb_cmd("DNLD_CMD: Sent command 0x%x @ %lu\n", command, jiffies); - lbs_dbg_hex("DNLD_CMD: command", cmdnode->bufvirtualaddr, cmdsize); + lbs_deb_cmd("DNLD_CMD: sent command 0x%x, jiffies %lu\n", command, jiffies); + lbs_deb_hex(LBS_DEB_CMD, "command", cmdnode->bufvirtualaddr, cmdsize); /* Setup the timer after transmit command */ if (command == CMD_802_11_SCAN || command == CMD_802_11_AUTHENTICATE @@ -1801,7 +1801,7 @@ static int sendconfirmsleep(wlan_private * priv, u8 * cmdptr, u16 size) lbs_deb_cmd("SEND_SLEEPC_CMD: Before download, size of cmd = %d\n", size); - lbs_dbg_hex("SEND_SLEEPC_CMD: Sleep confirm command", cmdptr, size); + lbs_deb_hex(LBS_DEB_CMD, "sleep confirm command", cmdptr, size); ret = priv->hw_host_to_card(priv, MVMS_CMD, cmdptr, size); priv->dnld_sent = DNLD_RES_RECEIVED; diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index bb1d72b2b52..6166bbc0528 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -431,7 +431,7 @@ static int wlan_ret_802_11_data_rate(wlan_private * priv, lbs_deb_enter(LBS_DEB_CMD); - lbs_dbg_hex("DATA_RATE_RESP: data_rate- ", (u8 *) pdatarate, + lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP: data_rate- ", (u8 *) pdatarate, sizeof(struct cmd_ds_802_11_data_rate)); /* FIXME: get actual rates FW can do if this command actually returns @@ -512,7 +512,7 @@ static int wlan_ret_802_11_eeprom_access(wlan_private * priv, memcpy(&pbuf->value, (u8 *) & resp->params.rdeeprom.value, le16_to_cpu(resp->params.rdeeprom.bytecount)); - lbs_dbg_hex("adapter", (char *)&pbuf->value, + lbs_deb_hex(LBS_DEB_CMD, "adapter", (char *)&pbuf->value, le16_to_cpu(resp->params.rdeeprom.bytecount)); } return 0; @@ -758,7 +758,7 @@ int libertas_process_rx_command(wlan_private * priv) } resp = (struct cmd_ds_command *)(adapter->cur_cmd->bufvirtualaddr); - lbs_dbg_hex("CMD_RESP:", adapter->cur_cmd->bufvirtualaddr, + lbs_deb_hex(LBS_DEB_CMD, "CMD_RESP", adapter->cur_cmd->bufvirtualaddr, priv->upld_len); respcmd = le16_to_cpu(resp->command); diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h index e47fadf3722..7c5b7f7b45d 100644 --- a/drivers/net/wireless/libertas/defs.h +++ b/drivers/net/wireless/libertas/defs.h @@ -43,43 +43,43 @@ extern unsigned int libertas_debug; #ifdef DEBUG -#define LBS_DEB_LL(grp, fmt, args...) \ +#define LBS_DEB_LL(grp, grpnam, fmt, args...) \ do { if ((libertas_debug & (grp)) == (grp)) \ - printk(KERN_DEBUG DRV_NAME "%s: " fmt, \ + printk(KERN_DEBUG DRV_NAME grpnam "%s: " fmt, \ in_interrupt() ? " (INT)" : "", ## args); } while (0) #else -#define LBS_DEB_LL(grp, fmt, args...) do {} while (0) +#define LBS_DEB_LL(grp, grpnam, fmt, args...) do {} while (0) #endif #define lbs_deb_enter(grp) \ - LBS_DEB_LL(grp | LBS_DEB_ENTER, "%s():%d enter\n", __FUNCTION__, __LINE__); + LBS_DEB_LL(grp | LBS_DEB_ENTER, " enter", "%s():%d\n", __FUNCTION__, __LINE__); #define lbs_deb_enter_args(grp, fmt, args...) \ - LBS_DEB_LL(grp | LBS_DEB_ENTER, "%s(" fmt "):%d\n", __FUNCTION__, ## args, __LINE__); + LBS_DEB_LL(grp | LBS_DEB_ENTER, " enter", "%s(" fmt "):%d\n", __FUNCTION__, ## args, __LINE__); #define lbs_deb_leave(grp) \ - LBS_DEB_LL(grp | LBS_DEB_LEAVE, "%s():%d leave\n", __FUNCTION__, __LINE__); + LBS_DEB_LL(grp | LBS_DEB_LEAVE, " leave", "%s():%d\n", __FUNCTION__, __LINE__); #define lbs_deb_leave_args(grp, fmt, args...) \ - LBS_DEB_LL(grp | LBS_DEB_LEAVE, "%s():%d leave, " fmt "\n", \ + LBS_DEB_LL(grp | LBS_DEB_LEAVE, " leave", "%s():%d, " fmt "\n", \ __FUNCTION__, __LINE__, ##args); -#define lbs_deb_main(fmt, args...) LBS_DEB_LL(LBS_DEB_MAIN, fmt, ##args) -#define lbs_deb_net(fmt, args...) LBS_DEB_LL(LBS_DEB_NET, fmt, ##args) -#define lbs_deb_mesh(fmt, args...) LBS_DEB_LL(LBS_DEB_MESH, fmt, ##args) -#define lbs_deb_wext(fmt, args...) LBS_DEB_LL(LBS_DEB_WEXT, fmt, ##args) -#define lbs_deb_ioctl(fmt, args...) LBS_DEB_LL(LBS_DEB_IOCTL, fmt, ##args) -#define lbs_deb_scan(fmt, args...) LBS_DEB_LL(LBS_DEB_SCAN, fmt, ##args) -#define lbs_deb_assoc(fmt, args...) LBS_DEB_LL(LBS_DEB_ASSOC, fmt, ##args) -#define lbs_deb_join(fmt, args...) LBS_DEB_LL(LBS_DEB_JOIN, fmt, ##args) -#define lbs_deb_11d(fmt, args...) LBS_DEB_LL(LBS_DEB_11D, fmt, ##args) -#define lbs_deb_debugfs(fmt, args...) LBS_DEB_LL(LBS_DEB_DEBUGFS, fmt, ##args) -#define lbs_deb_ethtool(fmt, args...) LBS_DEB_LL(LBS_DEB_ETHTOOL, fmt, ##args) -#define lbs_deb_host(fmt, args...) LBS_DEB_LL(LBS_DEB_HOST, fmt, ##args) -#define lbs_deb_cmd(fmt, args...) LBS_DEB_LL(LBS_DEB_CMD, fmt, ##args) -#define lbs_deb_rx(fmt, args...) LBS_DEB_LL(LBS_DEB_RX, fmt, ##args) -#define lbs_deb_tx(fmt, args...) LBS_DEB_LL(LBS_DEB_TX, fmt, ##args) -#define lbs_deb_fw(fmt, args...) LBS_DEB_LL(LBS_DEB_FW, fmt, ##args) -#define lbs_deb_usb(fmt, args...) LBS_DEB_LL(LBS_DEB_USB, fmt, ##args) -#define lbs_deb_usbd(dev, fmt, args...) LBS_DEB_LL(LBS_DEB_USB, "%s:" fmt, (dev)->bus_id, ##args) -#define lbs_deb_cs(fmt, args...) LBS_DEB_LL(LBS_DEB_CS, fmt, ##args) -#define lbs_deb_thread(fmt, args...) LBS_DEB_LL(LBS_DEB_THREAD, fmt, ##args) +#define lbs_deb_main(fmt, args...) LBS_DEB_LL(LBS_DEB_MAIN, " main", fmt, ##args) +#define lbs_deb_net(fmt, args...) LBS_DEB_LL(LBS_DEB_NET, " net", fmt, ##args) +#define lbs_deb_mesh(fmt, args...) LBS_DEB_LL(LBS_DEB_MESH, " mesh", fmt, ##args) +#define lbs_deb_wext(fmt, args...) LBS_DEB_LL(LBS_DEB_WEXT, " wext", fmt, ##args) +#define lbs_deb_ioctl(fmt, args...) LBS_DEB_LL(LBS_DEB_IOCTL, " ioctl", fmt, ##args) +#define lbs_deb_scan(fmt, args...) LBS_DEB_LL(LBS_DEB_SCAN, " scan", fmt, ##args) +#define lbs_deb_assoc(fmt, args...) LBS_DEB_LL(LBS_DEB_ASSOC, " assoc", fmt, ##args) +#define lbs_deb_join(fmt, args...) LBS_DEB_LL(LBS_DEB_JOIN, " join", fmt, ##args) +#define lbs_deb_11d(fmt, args...) LBS_DEB_LL(LBS_DEB_11D, " 11d", fmt, ##args) +#define lbs_deb_debugfs(fmt, args...) LBS_DEB_LL(LBS_DEB_DEBUGFS, " debugfs", fmt, ##args) +#define lbs_deb_ethtool(fmt, args...) LBS_DEB_LL(LBS_DEB_ETHTOOL, " ethtool", fmt, ##args) +#define lbs_deb_host(fmt, args...) LBS_DEB_LL(LBS_DEB_HOST, " host", fmt, ##args) +#define lbs_deb_cmd(fmt, args...) LBS_DEB_LL(LBS_DEB_CMD, " cmd", fmt, ##args) +#define lbs_deb_rx(fmt, args...) LBS_DEB_LL(LBS_DEB_RX, " rx", fmt, ##args) +#define lbs_deb_tx(fmt, args...) LBS_DEB_LL(LBS_DEB_TX, " tx", fmt, ##args) +#define lbs_deb_fw(fmt, args...) LBS_DEB_LL(LBS_DEB_FW, " fw", fmt, ##args) +#define lbs_deb_usb(fmt, args...) LBS_DEB_LL(LBS_DEB_USB, " usb", fmt, ##args) +#define lbs_deb_usbd(dev, fmt, args...) LBS_DEB_LL(LBS_DEB_USB, " usbd", "%s:" fmt, (dev)->bus_id, ##args) +#define lbs_deb_cs(fmt, args...) LBS_DEB_LL(LBS_DEB_CS, " cs", fmt, ##args) +#define lbs_deb_thread(fmt, args...) LBS_DEB_LL(LBS_DEB_THREAD, " thread", fmt, ##args) #define lbs_pr_info(format, args...) \ printk(KERN_INFO DRV_NAME": " format, ## args) @@ -89,22 +89,28 @@ do { if ((libertas_debug & (grp)) == (grp)) \ printk(KERN_ALERT DRV_NAME": " format, ## args) #ifdef DEBUG -static inline void lbs_dbg_hex(char *prompt, u8 * buf, int len) +static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, int len) { int i = 0; - if (!(libertas_debug & LBS_DEB_HEX)) - return; - - printk(KERN_DEBUG "%s: ", prompt); - for (i = 1; i <= len; i++) { - printk("%02x ", (u8) * buf); - buf++; + if (len && + (libertas_debug & LBS_DEB_HEX) && + (libertas_debug & grp)) + { + for (i = 1; i <= len; i++) { + if ((i & 0xf) == 1) { + if (i != 1) + printk("\n"); + printk(DRV_NAME " %s: ", prompt); + } + printk("%02x ", (u8) * buf); + buf++; + } + printk("\n"); } - printk("\n"); } #else -#define lbs_dbg_hex(x,y,z) do {} while (0) +#define lbs_deb_hex(grp,prompt,buf,len) do {} while (0) #endif diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c index da47c225e10..2b538ab51d4 100644 --- a/drivers/net/wireless/libertas/join.c +++ b/drivers/net/wireless/libertas/join.c @@ -51,9 +51,9 @@ static int get_common_rates(wlan_adapter * adapter, u8 * rates, u16 *rates_size) } } - lbs_dbg_hex("rate1 (AP) rates:", rates, *rates_size); - lbs_dbg_hex("rate2 (Card) rates:", card_rates, num_card_rates); - lbs_dbg_hex("Common rates:", tmp, tmp_size); + lbs_deb_hex(LBS_DEB_JOIN, "AP rates ", rates, *rates_size); + lbs_deb_hex(LBS_DEB_JOIN, "card rates ", card_rates, num_card_rates); + lbs_deb_hex(LBS_DEB_JOIN, "common rates", tmp, tmp_size); lbs_deb_join("Tx datarate is currently 0x%X\n", adapter->cur_rate); if (!adapter->auto_rate) { @@ -426,7 +426,7 @@ int libertas_cmd_80211_associate(wlan_private * priv, tmplen = (u16) assoc_req->wpa_ie[1]; rsn->header.len = cpu_to_le16(tmplen); memcpy(rsn->rsnie, &assoc_req->wpa_ie[2], tmplen); - lbs_dbg_hex("ASSOC_CMD: RSN IE", (u8 *) rsn, + lbs_deb_hex(LBS_DEB_JOIN, "ASSOC_CMD: RSN IE", (u8 *) rsn, sizeof(rsn->header) + tmplen); pos += sizeof(rsn->header) + tmplen; } @@ -711,7 +711,7 @@ int libertas_ret_80211_associate(wlan_private * priv, goto done; } - lbs_dbg_hex("ASSOC_RESP:", (void *)&resp->params, + lbs_deb_hex(LBS_DEB_JOIN, "ASSOC_RESP", (void *)&resp->params, le16_to_cpu(resp->size) - S_DS_GEN); /* Send a Media Connected event, according to the Spec */ diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 717b33616ea..2713f57e9bc 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -556,9 +556,9 @@ static int libertas_set_mac_address(struct net_device *dev, void *addr) memset(adapter->current_addr, 0, ETH_ALEN); /* dev->dev_addr is 8 bytes */ - lbs_dbg_hex("dev->dev_addr:", dev->dev_addr, ETH_ALEN); + lbs_deb_hex(LBS_DEB_NET, "dev->dev_addr", dev->dev_addr, ETH_ALEN); - lbs_dbg_hex("addr:", phwaddr->sa_data, ETH_ALEN); + lbs_deb_hex(LBS_DEB_NET, "addr", phwaddr->sa_data, ETH_ALEN); memcpy(adapter->current_addr, phwaddr->sa_data, ETH_ALEN); ret = libertas_prepare_and_send_command(priv, CMD_802_11_MAC_ADDRESS, @@ -571,7 +571,7 @@ static int libertas_set_mac_address(struct net_device *dev, void *addr) goto done; } - lbs_dbg_hex("adapter->macaddr:", adapter->current_addr, ETH_ALEN); + lbs_deb_hex(LBS_DEB_NET, "adapter->macaddr", adapter->current_addr, ETH_ALEN); memcpy(dev->dev_addr, adapter->current_addr, ETH_ALEN); if (priv->mesh_dev) memcpy(priv->mesh_dev->dev_addr, adapter->current_addr, ETH_ALEN); diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c index c9251abbb96..25d45c646d7 100644 --- a/drivers/net/wireless/libertas/rx.c +++ b/drivers/net/wireless/libertas/rx.c @@ -182,7 +182,7 @@ int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *skb) else UNSET_MESH_FRAME(skb); - lbs_dbg_hex("RX Data: Before chop rxpd", skb->data, + lbs_deb_hex(LBS_DEB_RX, "RX Data: Before chop rxpd", skb->data, min_t(unsigned int, skb->len, 100)); if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) { @@ -206,9 +206,9 @@ int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *skb) lbs_deb_rx("rx data: skb->len-sizeof(RxPd) = %d-%zd = %zd\n", skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd)); - lbs_dbg_hex("RX Data: Dest", p_rx_pkt->eth803_hdr.dest_addr, + lbs_deb_hex(LBS_DEB_RX, "RX Data: Dest", p_rx_pkt->eth803_hdr.dest_addr, sizeof(p_rx_pkt->eth803_hdr.dest_addr)); - lbs_dbg_hex("RX Data: Src", p_rx_pkt->eth803_hdr.src_addr, + lbs_deb_hex(LBS_DEB_RX, "RX Data: Src", p_rx_pkt->eth803_hdr.src_addr, sizeof(p_rx_pkt->eth803_hdr.src_addr)); if (memcmp(&p_rx_pkt->rfc1042_hdr, @@ -240,7 +240,7 @@ int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *skb) */ hdrchop = (u8 *) p_ethhdr - (u8 *) p_rx_pkt; } else { - lbs_dbg_hex("RX Data: LLC/SNAP", + lbs_deb_hex(LBS_DEB_RX, "RX Data: LLC/SNAP", (u8 *) & p_rx_pkt->rfc1042_hdr, sizeof(p_rx_pkt->rfc1042_hdr)); @@ -336,7 +336,7 @@ static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb) p_rx_pkt = (struct rx80211packethdr *) skb->data; prxpd = &p_rx_pkt->rx_pd; - // lbs_dbg_hex("RX Data: Before chop rxpd", skb->data, min(skb->len, 100)); + // lbs_deb_hex(LBS_DEB_RX, "RX Data: Before chop rxpd", skb->data, min(skb->len, 100)); if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) { lbs_deb_rx("rx err: frame received wit bad length\n"); @@ -385,8 +385,6 @@ static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb) radiotap_hdr.rx_flags |= IEEE80211_RADIOTAP_F_RX_BADFCS; //memset(radiotap_hdr.pad, 0x11, IEEE80211_RADIOTAP_HDRLEN - 18); - // lbs_dbg_hex1("RX radiomode packet BEF: ", skb->data, min(skb->len, 100)); - /* chop the rxpd */ skb_pull(skb, sizeof(struct rxpd)); @@ -404,7 +402,6 @@ static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb) rx_radiotap_hdr)); memcpy(pradiotap_hdr, &radiotap_hdr, sizeof(struct rx_radiotap_hdr)); - //lbs_dbg_hex1("RX radiomode packet AFT: ", skb->data, min(skb->len, 100)); break; default: diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 7f045ec2441..f471157c02d 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -867,7 +867,7 @@ void wlan_ret_802_11_scan_get_tlv_ptrs(struct mrvlietypes_data * ptlv, *ptsftlv = NULL; lbs_deb_scan("SCAN_RESP: tlvbufsize = %d\n", tlvbufsize); - lbs_dbg_hex("SCAN_RESP: TLV Buf", (u8 *) ptlv, tlvbufsize); + lbs_deb_hex(LBS_DEB_SCAN, "SCAN_RESP: TLV Buf", (u8 *) ptlv, tlvbufsize); while (tlvbufleft >= sizeof(struct mrvlietypesheader)) { tlvtype = le16_to_cpu(pcurrenttlv->header.type); @@ -979,7 +979,7 @@ static int libertas_process_bss(struct bss_descriptor * bss, /* rest of the current buffer are IE's */ lbs_deb_scan("process_bss: IE length for this AP = %zd\n", end - pos); - lbs_dbg_hex("process_bss: IE info", pos, end - pos); + lbs_deb_hex(LBS_DEB_SCAN, "process_bss: IE info", pos, end - pos); /* process variable IE */ while (pos <= end - 2) { @@ -1055,7 +1055,7 @@ static int libertas_process_bss(struct bss_descriptor * bss, memcpy(&bss->countryinfo, pcountryinfo, pcountryinfo->len + 2); - lbs_dbg_hex("process_bss: 11D- CountryInfo:", + lbs_deb_hex(LBS_DEB_SCAN, "process_bss: 11d countryinfo", (u8 *) pcountryinfo, (u32) (pcountryinfo->len + 2)); break; @@ -1085,7 +1085,7 @@ static int libertas_process_bss(struct bss_descriptor * bss, bss->wpa_ie_len = min(elem->len + 2, MAX_WPA_IE_LEN); memcpy(bss->wpa_ie, elem, bss->wpa_ie_len); - lbs_dbg_hex("process_bss: WPA IE", bss->wpa_ie, + lbs_deb_hex(LBS_DEB_SCAN, "process_bss: WPA IE", bss->wpa_ie, elem->len); } else if (elem->len >= MARVELL_MESH_IE_LENGTH && elem->data[0] == 0x00 && @@ -1099,7 +1099,7 @@ static int libertas_process_bss(struct bss_descriptor * bss, case MFIE_TYPE_RSN: bss->rsn_ie_len = min(elem->len + 2, MAX_WPA_IE_LEN); memcpy(bss->rsn_ie, elem, bss->rsn_ie_len); - lbs_dbg_hex("process_bss: RSN_IE", bss->rsn_ie, elem->len); + lbs_deb_hex(LBS_DEB_SCAN, "process_bss: RSN_IE", bss->rsn_ie, elem->len); break; default: @@ -1154,7 +1154,7 @@ struct bss_descriptor * libertas_find_bssid_in_list(wlan_adapter * adapter, if (!bssid) return NULL; - lbs_dbg_hex("libertas_find_BSSID_in_list: looking for ", + lbs_deb_hex(LBS_DEB_SCAN, "looking for", bssid, ETH_ALEN); /* Look through the scan table for a compatible match. The loop will diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c index 7743d3f30f6..56d84027ec2 100644 --- a/drivers/net/wireless/libertas/tx.c +++ b/drivers/net/wireless/libertas/tx.c @@ -116,7 +116,7 @@ static int SendSinglePacket(wlan_private * priv, struct sk_buff *skb) else memcpy(plocaltxpd->tx_dest_addr_high, p802x_hdr, ETH_ALEN); - lbs_dbg_hex("txpd", (u8 *) plocaltxpd, sizeof(struct txpd)); + lbs_deb_hex(LBS_DEB_TX, "txpd", (u8 *) plocaltxpd, sizeof(struct txpd)); if (IS_MESH_FRAME(skb)) { plocaltxpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME); @@ -126,7 +126,7 @@ static int SendSinglePacket(wlan_private * priv, struct sk_buff *skb) ptr += sizeof(struct txpd); - lbs_dbg_hex("Tx Data", (u8 *) p802x_hdr, le16_to_cpu(plocaltxpd->tx_packet_length)); + lbs_deb_hex(LBS_DEB_TX, "Tx Data", (u8 *) p802x_hdr, le16_to_cpu(plocaltxpd->tx_packet_length)); memcpy(ptr, p802x_hdr, le16_to_cpu(plocaltxpd->tx_packet_length)); ret = priv->hw_host_to_card(priv, MVMS_DAT, priv->adapter->tmptxbuf, @@ -218,7 +218,7 @@ int libertas_process_tx(wlan_private * priv, struct sk_buff *skb) int ret = -1; lbs_deb_enter(LBS_DEB_TX); - lbs_dbg_hex("TX Data", skb->data, min_t(unsigned int, skb->len, 100)); + lbs_deb_hex(LBS_DEB_TX, "TX Data", skb->data, min_t(unsigned int, skb->len, 100)); if (priv->dnld_sent) { lbs_pr_alert( "TX error: dnld_sent = %d, not sending\n", -- cgit v1.2.3-70-g09d2 From 6b63cd0f420c3c3002024da6c9eff252a3772021 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 11:53:36 -0400 Subject: [PATCH] libertas: remove a hundred CMD_RET_xxx definitions types.h contains the same amount of CMD_RET_xxx and CMD_xxx definitions. They contains the same info: the firmware command opcode and, when the firmware sends back a result, the command opcode ORed with 0x8000. Having the same data twice in the source code is redundant and can lead to errors (e.g. if you update or delete only one instance). This patch removed all CMD_RET_xxx definitions and introduces a simple CMD_RET() macro. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmdresp.c | 101 ++++++++++++++++---------------- drivers/net/wireless/libertas/debugfs.c | 26 ++++---- drivers/net/wireless/libertas/host.h | 87 ++++----------------------- drivers/net/wireless/libertas/join.c | 2 +- 4 files changed, 76 insertions(+), 140 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 6166bbc0528..ae11e1f2739 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -124,7 +124,7 @@ static int wlan_ret_reg_access(wlan_private * priv, lbs_deb_enter(LBS_DEB_CMD); switch (type) { - case CMD_RET_MAC_REG_ACCESS: + case CMD_RET(CMD_MAC_REG_ACCESS): { struct cmd_ds_mac_reg_access *reg = &resp->params.macreg; @@ -133,7 +133,7 @@ static int wlan_ret_reg_access(wlan_private * priv, break; } - case CMD_RET_BBP_REG_ACCESS: + case CMD_RET(CMD_BBP_REG_ACCESS): { struct cmd_ds_bbp_reg_access *reg = &resp->params.bbpreg; @@ -142,7 +142,7 @@ static int wlan_ret_reg_access(wlan_private * priv, break; } - case CMD_RET_RF_REG_ACCESS: + case CMD_RET(CMD_RF_REG_ACCESS): { struct cmd_ds_rf_reg_access *reg = &resp->params.rfreg; @@ -560,134 +560,135 @@ static inline int handle_cmd_response(u16 respcmd, wlan_adapter *adapter = priv->adapter; switch (respcmd) { - case CMD_RET_MAC_REG_ACCESS: - case CMD_RET_BBP_REG_ACCESS: - case CMD_RET_RF_REG_ACCESS: + case CMD_RET(CMD_MAC_REG_ACCESS): + case CMD_RET(CMD_BBP_REG_ACCESS): + case CMD_RET(CMD_RF_REG_ACCESS): ret = wlan_ret_reg_access(priv, respcmd, resp); break; - case CMD_RET_HW_SPEC_INFO: + case CMD_RET(CMD_GET_HW_SPEC): ret = wlan_ret_get_hw_spec(priv, resp); break; - case CMD_RET_802_11_SCAN: + case CMD_RET(CMD_802_11_SCAN): ret = libertas_ret_80211_scan(priv, resp); break; - case CMD_RET_802_11_GET_LOG: + case CMD_RET(CMD_802_11_GET_LOG): ret = wlan_ret_get_log(priv, resp); break; case CMD_RET_802_11_ASSOCIATE: - case CMD_RET_802_11_REASSOCIATE: + case CMD_RET(CMD_802_11_ASSOCIATE): + case CMD_RET(CMD_802_11_REASSOCIATE): ret = libertas_ret_80211_associate(priv, resp); break; - case CMD_RET_802_11_DISASSOCIATE: - case CMD_RET_802_11_DEAUTHENTICATE: + case CMD_RET(CMD_802_11_DISASSOCIATE): + case CMD_RET(CMD_802_11_DEAUTHENTICATE): ret = libertas_ret_80211_disassociate(priv, resp); break; - case CMD_RET_802_11_AD_HOC_START: - case CMD_RET_802_11_AD_HOC_JOIN: + case CMD_RET(CMD_802_11_AD_HOC_START): + case CMD_RET(CMD_802_11_AD_HOC_JOIN): ret = libertas_ret_80211_ad_hoc_start(priv, resp); break; - case CMD_RET_802_11_STAT: + case CMD_RET(CMD_802_11_GET_STAT): ret = wlan_ret_802_11_stat(priv, resp); break; - case CMD_RET_802_11_SNMP_MIB: + case CMD_RET(CMD_802_11_SNMP_MIB): ret = wlan_ret_802_11_snmp_mib(priv, resp); break; - case CMD_RET_802_11_RF_TX_POWER: + case CMD_RET(CMD_802_11_RF_TX_POWER): ret = wlan_ret_802_11_rf_tx_power(priv, resp); break; - case CMD_RET_802_11_SET_AFC: - case CMD_RET_802_11_GET_AFC: + case CMD_RET(CMD_802_11_SET_AFC): + case CMD_RET(CMD_802_11_GET_AFC): spin_lock_irqsave(&adapter->driver_lock, flags); memmove(adapter->cur_cmd->pdata_buf, &resp->params.afc, sizeof(struct cmd_ds_802_11_afc)); spin_unlock_irqrestore(&adapter->driver_lock, flags); break; - case CMD_RET_802_11_RF_ANTENNA: + case CMD_RET(CMD_802_11_RF_ANTENNA): ret = wlan_ret_802_11_rf_antenna(priv, resp); break; - case CMD_RET_MAC_MULTICAST_ADR: - case CMD_RET_MAC_CONTROL: - case CMD_RET_802_11_SET_WEP: - case CMD_RET_802_11_RESET: - case CMD_RET_802_11_AUTHENTICATE: - case CMD_RET_802_11_RADIO_CONTROL: - case CMD_RET_802_11_BEACON_STOP: + case CMD_RET(CMD_MAC_MULTICAST_ADR): + case CMD_RET(CMD_MAC_CONTROL): + case CMD_RET(CMD_802_11_SET_WEP): + case CMD_RET(CMD_802_11_RESET): + case CMD_RET(CMD_802_11_AUTHENTICATE): + case CMD_RET(CMD_802_11_RADIO_CONTROL): + case CMD_RET(CMD_802_11_BEACON_STOP): break; - case CMD_RET_802_11_ENABLE_RSN: + case CMD_RET(CMD_802_11_ENABLE_RSN): ret = libertas_ret_802_11_enable_rsn(priv, resp); break; - case CMD_RET_802_11_DATA_RATE: + case CMD_RET(CMD_802_11_DATA_RATE): ret = wlan_ret_802_11_data_rate(priv, resp); break; - case CMD_RET_802_11_RATE_ADAPT_RATESET: + case CMD_RET(CMD_802_11_RATE_ADAPT_RATESET): ret = wlan_ret_802_11_rate_adapt_rateset(priv, resp); break; - case CMD_RET_802_11_RF_CHANNEL: + case CMD_RET(CMD_802_11_RF_CHANNEL): ret = wlan_ret_802_11_rf_channel(priv, resp); break; - case CMD_RET_802_11_RSSI: + case CMD_RET(CMD_802_11_RSSI): ret = wlan_ret_802_11_rssi(priv, resp); break; - case CMD_RET_802_11_MAC_ADDRESS: + case CMD_RET(CMD_802_11_MAC_ADDRESS): ret = wlan_ret_802_11_mac_address(priv, resp); break; - case CMD_RET_802_11_AD_HOC_STOP: + case CMD_RET(CMD_802_11_AD_HOC_STOP): ret = libertas_ret_80211_ad_hoc_stop(priv, resp); break; - case CMD_RET_802_11_KEY_MATERIAL: + case CMD_RET(CMD_802_11_KEY_MATERIAL): lbs_deb_cmd("CMD_RESP: KEY_MATERIAL command response\n"); ret = wlan_ret_802_11_key_material(priv, resp); break; - case CMD_RET_802_11_EEPROM_ACCESS: + case CMD_RET(CMD_802_11_EEPROM_ACCESS): ret = wlan_ret_802_11_eeprom_access(priv, resp); break; - case CMD_RET_802_11D_DOMAIN_INFO: + case CMD_RET(CMD_802_11D_DOMAIN_INFO): ret = libertas_ret_802_11d_domain_info(priv, resp); break; - case CMD_RET_802_11_SLEEP_PARAMS: + case CMD_RET(CMD_802_11_SLEEP_PARAMS): ret = wlan_ret_802_11_sleep_params(priv, resp); break; - case CMD_RET_802_11_INACTIVITY_TIMEOUT: + case CMD_RET(CMD_802_11_INACTIVITY_TIMEOUT): spin_lock_irqsave(&adapter->driver_lock, flags); *((u16 *) adapter->cur_cmd->pdata_buf) = le16_to_cpu(resp->params.inactivity_timeout.timeout); spin_unlock_irqrestore(&adapter->driver_lock, flags); break; - case CMD_RET_802_11_TPC_CFG: + case CMD_RET(CMD_802_11_TPC_CFG): spin_lock_irqsave(&adapter->driver_lock, flags); memmove(adapter->cur_cmd->pdata_buf, &resp->params.tpccfg, sizeof(struct cmd_ds_802_11_tpc_cfg)); spin_unlock_irqrestore(&adapter->driver_lock, flags); break; - case CMD_RET_802_11_LED_GPIO_CTRL: + case CMD_RET(CMD_802_11_LED_GPIO_CTRL): spin_lock_irqsave(&adapter->driver_lock, flags); memmove(adapter->cur_cmd->pdata_buf, &resp->params.ledgpio, sizeof(struct cmd_ds_802_11_led_ctrl)); spin_unlock_irqrestore(&adapter->driver_lock, flags); break; - case CMD_RET_802_11_PWR_CFG: + case CMD_RET(CMD_802_11_PWR_CFG): spin_lock_irqsave(&adapter->driver_lock, flags); memmove(adapter->cur_cmd->pdata_buf, &resp->params.pwrcfg, sizeof(struct cmd_ds_802_11_pwr_cfg)); @@ -695,32 +696,32 @@ static inline int handle_cmd_response(u16 respcmd, break; - case CMD_RET_GET_TSF: + case CMD_RET(CMD_GET_TSF): spin_lock_irqsave(&adapter->driver_lock, flags); memcpy(priv->adapter->cur_cmd->pdata_buf, &resp->params.gettsf.tsfvalue, sizeof(u64)); spin_unlock_irqrestore(&adapter->driver_lock, flags); break; - case CMD_RET_BT_ACCESS: + case CMD_RET(CMD_BT_ACCESS): spin_lock_irqsave(&adapter->driver_lock, flags); if (adapter->cur_cmd->pdata_buf) memcpy(adapter->cur_cmd->pdata_buf, &resp->params.bt.addr1, 2 * ETH_ALEN); spin_unlock_irqrestore(&adapter->driver_lock, flags); break; - case CMD_RET_FWT_ACCESS: + case CMD_RET(CMD_FWT_ACCESS): spin_lock_irqsave(&adapter->driver_lock, flags); if (adapter->cur_cmd->pdata_buf) memcpy(adapter->cur_cmd->pdata_buf, &resp->params.fwt, sizeof(resp->params.fwt)); spin_unlock_irqrestore(&adapter->driver_lock, flags); break; - case CMD_RET_MESH_ACCESS: + case CMD_RET(CMD_MESH_ACCESS): if (adapter->cur_cmd->pdata_buf) memcpy(adapter->cur_cmd->pdata_buf, &resp->params.mesh, sizeof(resp->params.mesh)); break; - case CMD_RTE_802_11_TX_RATE_QUERY: + case CMD_RET(CMD_802_11_TX_RATE_QUERY): priv->adapter->txrate = resp->params.txrate.txrate; break; default: @@ -782,7 +783,7 @@ int libertas_process_rx_command(wlan_private * priv) /* Store the response code to cur_cmd_retcode. */ adapter->cur_cmd_retcode = result;; - if (respcmd == CMD_RET_802_11_PS_MODE) { + if (respcmd == CMD_RET(CMD_802_11_PS_MODE)) { struct cmd_ds_802_11_ps_mode *psmode = &resp->params.psmode; u16 action = le16_to_cpu(psmode->action); @@ -852,8 +853,8 @@ int libertas_process_rx_command(wlan_private * priv) * Handling errors here */ switch (respcmd) { - case CMD_RET_HW_SPEC_INFO: - case CMD_RET_802_11_RESET: + case CMD_RET(CMD_GET_HW_SPEC): + case CMD_RET(CMD_802_11_RESET): lbs_deb_cmd("CMD_RESP: Reset command failed\n"); break; diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c index 9439005db4e..4b9533a6651 100644 --- a/drivers/net/wireless/libertas/debugfs.c +++ b/drivers/net/wireless/libertas/debugfs.c @@ -447,7 +447,7 @@ static ssize_t libertas_lowrssi_read(struct file *file, char __user *userbuf, return 0; } - if (pcmdptr->command != cpu_to_le16(CMD_RET_802_11_SUBSCRIBE_EVENT)) { + if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) { lbs_pr_err("command response incorrect!\n"); kfree(response_buf); free_page(addr); @@ -511,7 +511,7 @@ static u16 libertas_get_events_bitmap(wlan_private *priv) return 0; } - if (pcmdptr->command != CMD_RET_802_11_SUBSCRIBE_EVENT) { + if (pcmdptr->command != CMD_RET(CMD_802_11_SUBSCRIBE_EVENT)) { lbs_pr_err("command response incorrect!\n"); kfree(response_buf); return 0; @@ -591,7 +591,7 @@ static ssize_t libertas_lowrssi_write(struct file *file, return 0; } - if (pcmdptr->command != cpu_to_le16(CMD_RET_802_11_SUBSCRIBE_EVENT)) { + if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) { lbs_pr_err("command response incorrect!\n"); kfree(response_buf); free_page(addr); @@ -644,7 +644,7 @@ static ssize_t libertas_lowsnr_read(struct file *file, char __user *userbuf, return 0; } - if (pcmdptr->command != cpu_to_le16(CMD_RET_802_11_SUBSCRIBE_EVENT)) { + if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) { lbs_pr_err("command response incorrect!\n"); kfree(response_buf); free_page(addr); @@ -743,7 +743,7 @@ static ssize_t libertas_lowsnr_write(struct file *file, return 0; } - if (pcmdptr->command != cpu_to_le16(CMD_RET_802_11_SUBSCRIBE_EVENT)) { + if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) { lbs_pr_err("command response incorrect!\n"); kfree(response_buf); free_page(addr); @@ -797,7 +797,7 @@ static ssize_t libertas_failcount_read(struct file *file, char __user *userbuf, return 0; } - if (pcmdptr->command != cpu_to_le16(CMD_RET_802_11_SUBSCRIBE_EVENT)) { + if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) { lbs_pr_err("command response incorrect!\n"); kfree(response_buf); free_page(addr); @@ -895,7 +895,7 @@ static ssize_t libertas_failcount_write(struct file *file, return 0; } - if (pcmdptr->command != cpu_to_le16(CMD_RET_802_11_SUBSCRIBE_EVENT)) { + if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) { lbs_pr_err("command response incorrect!\n"); kfree(response_buf); free_page(addr); @@ -948,7 +948,7 @@ static ssize_t libertas_bcnmiss_read(struct file *file, char __user *userbuf, return 0; } - if (pcmdptr->command != cpu_to_le16(CMD_RET_802_11_SUBSCRIBE_EVENT)) { + if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) { lbs_pr_err("command response incorrect!\n"); free_page(addr); kfree(response_buf); @@ -1045,7 +1045,7 @@ static ssize_t libertas_bcnmiss_write(struct file *file, return 0; } - if (pcmdptr->command != cpu_to_le16(CMD_RET_802_11_SUBSCRIBE_EVENT)) { + if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) { lbs_pr_err("command response incorrect!\n"); free_page(addr); kfree(response_buf); @@ -1098,7 +1098,7 @@ static ssize_t libertas_highrssi_read(struct file *file, char __user *userbuf, return 0; } - if (pcmdptr->command != cpu_to_le16(CMD_RET_802_11_SUBSCRIBE_EVENT)) { + if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) { lbs_pr_err("command response incorrect!\n"); kfree(response_buf); free_page(addr); @@ -1196,7 +1196,7 @@ static ssize_t libertas_highrssi_write(struct file *file, return 0; } - if (pcmdptr->command != cpu_to_le16(CMD_RET_802_11_SUBSCRIBE_EVENT)) { + if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) { lbs_pr_err("command response incorrect!\n"); kfree(response_buf); return 0; @@ -1248,7 +1248,7 @@ static ssize_t libertas_highsnr_read(struct file *file, char __user *userbuf, return 0; } - if (pcmdptr->command != cpu_to_le16(CMD_RET_802_11_SUBSCRIBE_EVENT)) { + if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) { lbs_pr_err("command response incorrect!\n"); kfree(response_buf); free_page(addr); @@ -1347,7 +1347,7 @@ static ssize_t libertas_highsnr_write(struct file *file, return 0; } - if (pcmdptr->command != cpu_to_le16(CMD_RET_802_11_SUBSCRIBE_EVENT)) { + if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) { lbs_pr_err("command response incorrect!\n"); kfree(response_buf); free_page(addr); diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index 12d5dd9af40..c6b44c83159 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -22,7 +22,17 @@ #define CMD_OPTION_WAITFORRSP 0x0002 -/** Host command ID */ +/** Host command IDs */ + +/* Return command are almost always the same as the host command, but with + * bit 15 set high. There are a few exceptions, though... + */ +#define CMD_RET(cmd) (0x8000 | cmd) + +/* Return command convention exceptions: */ +#define CMD_RET_802_11_ASSOCIATE 0x8012 + +/* Command codes */ #define CMD_CODE_DNLD 0x0002 #define CMD_GET_HW_SPEC 0x0003 #define CMD_EEPROM_UPDATE 0x0004 @@ -97,13 +107,10 @@ #define CMD_GET_TSF 0x0080 #define CMD_BT_ACCESS 0x0087 -#define CMD_RET_BT_ACCESS 0x8087 #define CMD_FWT_ACCESS 0x0095 -#define CMD_RET_FWT_ACCESS 0x8095 #define CMD_MESH_ACCESS 0x009b -#define CMD_RET_MESH_ACCESS 0x809b /* For the IEEE Power Save */ #define CMD_SUBCMD_ENTER_PS 0x0030 @@ -112,46 +119,6 @@ #define CMD_SUBCMD_FULL_POWERDOWN 0x0035 #define CMD_SUBCMD_FULL_POWERUP 0x0036 -/* command RET code, MSB is set to 1 */ -#define CMD_RET_HW_SPEC_INFO 0x8003 -#define CMD_RET_EEPROM_UPDATE 0x8004 -#define CMD_RET_802_11_RESET 0x8005 -#define CMD_RET_802_11_SCAN 0x8006 -#define CMD_RET_802_11_GET_LOG 0x800b -#define CMD_RET_MAC_CONTROL 0x8028 -#define CMD_RET_MAC_MULTICAST_ADR 0x8010 -#define CMD_RET_802_11_AUTHENTICATE 0x8011 -#define CMD_RET_802_11_DEAUTHENTICATE 0x8024 -#define CMD_RET_802_11_ASSOCIATE 0x8012 -#define CMD_RET_802_11_REASSOCIATE 0x8025 -#define CMD_RET_802_11_DISASSOCIATE 0x8026 -#define CMD_RET_802_11_SET_WEP 0x8013 -#define CMD_RET_802_11_STAT 0x8014 -#define CMD_RET_802_3_STAT 0x8015 -#define CMD_RET_802_11_SNMP_MIB 0x8016 -#define CMD_RET_MAC_REG_MAP 0x8017 -#define CMD_RET_BBP_REG_MAP 0x8018 -#define CMD_RET_RF_REG_MAP 0x8023 -#define CMD_RET_MAC_REG_ACCESS 0x8019 -#define CMD_RET_BBP_REG_ACCESS 0x801a -#define CMD_RET_RF_REG_ACCESS 0x801b -#define CMD_RET_802_11_RADIO_CONTROL 0x801c -#define CMD_RET_802_11_RF_CHANNEL 0x801d -#define CMD_RET_802_11_RSSI 0x801f -#define CMD_RET_802_11_RF_TX_POWER 0x801e -#define CMD_RET_802_11_RF_ANTENNA 0x8020 -#define CMD_RET_802_11_PS_MODE 0x8021 -#define CMD_RET_802_11_DATA_RATE 0x8022 - -#define CMD_RET_802_11_AD_HOC_START 0x802B -#define CMD_RET_802_11_AD_HOC_JOIN 0x802C - -#define CMD_RET_802_11_QUERY_TKIP_REPLY_CNTRS 0x802e -#define CMD_RET_802_11_ENABLE_RSN 0x802f -#define CMD_RET_802_11_PAIRWISE_TSC 0x8036 -#define CMD_RET_802_11_GROUP_TSC 0x8037 -#define CMD_RET_802_11_KEY_MATERIAL 0x805e - #define CMD_ENABLE_RSN 0x0001 #define CMD_DISABLE_RSN 0x0000 @@ -162,38 +129,6 @@ #define CMD_ACT_SET_AES (CMD_ACT_SET + 2) #define CMD_ACT_REMOVE_AES (CMD_ACT_SET + 3) -#define CMD_RET_802_11_SET_AFC 0x803c -#define CMD_RET_802_11_GET_AFC 0x803d - -#define CMD_RET_802_11_AD_HOC_STOP 0x8040 - -#define CMD_RET_802_11_BEACON_STOP 0x8049 - -#define CMD_RET_802_11_MAC_ADDRESS 0x804D -#define CMD_RET_802_11_EEPROM_ACCESS 0x8059 - -#define CMD_RET_802_11_BAND_CONFIG 0x8058 - -#define CMD_RET_802_11_SLEEP_PARAMS 0x8066 - -#define CMD_RET_802_11_INACTIVITY_TIMEOUT 0x8067 - -#define CMD_RET_802_11D_DOMAIN_INFO (0x8000 | \ - CMD_802_11D_DOMAIN_INFO) - -#define CMD_RET_802_11_TPC_CFG (CMD_802_11_TPC_CFG | 0x8000) -#define CMD_RET_802_11_PWR_CFG (CMD_802_11_PWR_CFG | 0x8000) - -#define CMD_RET_802_11_LED_GPIO_CTRL 0x804e - -#define CMD_RET_802_11_SUBSCRIBE_EVENT (CMD_802_11_SUBSCRIBE_EVENT | 0x8000) - -#define CMD_RET_802_11_RATE_ADAPT_RATESET (CMD_802_11_RATE_ADAPT_RATESET | 0x8000) - -#define CMD_RTE_802_11_TX_RATE_QUERY (CMD_802_11_TX_RATE_QUERY | 0x8000) - -#define CMD_RET_GET_TSF 0x8080 - /* Define action or option for CMD_802_11_SET_WEP */ #define CMD_ACT_ADD 0x0002 #define CMD_ACT_REMOVE 0x0004 diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c index 2b538ab51d4..08034917d4b 100644 --- a/drivers/net/wireless/libertas/join.c +++ b/drivers/net/wireless/libertas/join.c @@ -814,7 +814,7 @@ int libertas_ret_80211_ad_hoc_start(wlan_private * priv, /* Send a Media Connected event, according to the Spec */ adapter->connect_status = LIBERTAS_CONNECTED; - if (command == CMD_RET_802_11_AD_HOC_START) { + if (command == CMD_RET(CMD_802_11_AD_HOC_START)) { /* Update the created network descriptor with the new BSSID */ memcpy(bss->bssid, padhocresult->bssid, ETH_ALEN); } -- cgit v1.2.3-70-g09d2 From a6c8700f36cd8f217420bbe26721094824fab8de Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 11:54:10 -0400 Subject: [PATCH] libertas: use LBS_DEB_HOST for host-to-card communications ... and LBS_DEB_CMD for command execution. Also tidies misc comments to give a consistent output. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmdresp.c | 147 +++++++++++++++++--------------- 1 file changed, 78 insertions(+), 69 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index ae11e1f2739..197d0451784 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -31,7 +31,7 @@ void libertas_mac_event_disconnected(wlan_private * priv) if (adapter->connect_status != LIBERTAS_CONNECTED) return; - lbs_deb_cmd("Handles disconnect event.\n"); + lbs_deb_enter(LBS_DEB_CMD); memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN); wrqu.ap_addr.sa_family = ARPHRD_ETHER; @@ -61,11 +61,11 @@ void libertas_mac_event_disconnected(wlan_private * priv) adapter->nextSNRNF = 0; adapter->numSNRNF = 0; adapter->rxpd_rate = 0; - lbs_deb_cmd("Current SSID='%s', ssid length=%u\n", + lbs_deb_cmd("current SSID '%s', length %u\n", escape_essid(adapter->curbssparams.ssid, adapter->curbssparams.ssid_len), adapter->curbssparams.ssid_len); - lbs_deb_cmd("Previous SSID='%s', ssid length=%u\n", + lbs_deb_cmd("previous SSID '%s', length %u\n", escape_essid(adapter->prev_ssid, adapter->prev_ssid_len), adapter->prev_ssid_len); @@ -86,9 +86,10 @@ void libertas_mac_event_disconnected(wlan_private * priv) if (adapter->psstate != PS_STATE_FULL_POWER) { /* make firmware to exit PS mode */ - lbs_deb_cmd("Disconnected, so exit PS mode.\n"); + lbs_deb_cmd("disconnected, so exit PS mode\n"); libertas_ps_wakeup(priv, 0); } + lbs_deb_leave(LBS_DEB_CMD); } /** @@ -102,6 +103,7 @@ static void handle_mic_failureevent(wlan_private * priv, u32 event) { char buf[50]; + lbs_deb_enter(LBS_DEB_CMD); memset(buf, 0, sizeof(buf)); sprintf(buf, "%s", "MLME-MICHAELMICFAILURE.indication "); @@ -113,6 +115,7 @@ static void handle_mic_failureevent(wlan_private * priv, u32 event) } libertas_send_iwevcustom_event(priv, buf); + lbs_deb_leave(LBS_DEB_CMD); } static int wlan_ret_reg_access(wlan_private * priv, @@ -173,12 +176,12 @@ static int wlan_ret_get_hw_spec(wlan_private * priv, memcpy(adapter->fwreleasenumber, hwspec->fwreleasenumber, 4); - lbs_deb_cmd("GET_HW_SPEC: FWReleaseVersion: %u.%u.%u.p%u\n", + lbs_deb_cmd("GET_HW_SPEC: firmware release %u.%u.%up%u\n", adapter->fwreleasenumber[2], adapter->fwreleasenumber[1], adapter->fwreleasenumber[0], adapter->fwreleasenumber[3]); - lbs_deb_cmd("GET_HW_SPEC: Permanent addr: " MAC_FMT "\n", + lbs_deb_cmd("GET_HW_SPEC: MAC addr " MAC_FMT "\n", MAC_ARG(hwspec->permanentaddr)); - lbs_deb_cmd("GET_HW_SPEC: hwifversion: 0x%x version:0x%x\n", + lbs_deb_cmd("GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x\n", hwspec->hwifversion, hwspec->version); adapter->regioncode = le16_to_cpu(hwspec->regioncode); @@ -228,8 +231,8 @@ static int wlan_ret_802_11_sleep_params(wlan_private * priv, lbs_deb_enter(LBS_DEB_CMD); - lbs_deb_cmd("error=%x offset=%x stabletime=%x calcontrol=%x\n" - " extsleepclk=%x\n", le16_to_cpu(sp->error), + lbs_deb_cmd("error 0x%x, offset 0x%x, stabletime 0x%x, calcontrol 0x%x " + "extsleepclk 0x%x\n", le16_to_cpu(sp->error), le16_to_cpu(sp->offset), le16_to_cpu(sp->stabletime), sp->calcontrol, sp->externalsleepclk); @@ -247,6 +250,7 @@ static int wlan_ret_802_11_sleep_params(wlan_private * priv, static int wlan_ret_802_11_stat(wlan_private * priv, struct cmd_ds_command *resp) { + lbs_deb_enter(LBS_DEB_CMD); /* currently adapter->wlan802_11Stat is unused struct cmd_ds_802_11_get_stat *p11Stat = &resp->params.gstat; @@ -256,6 +260,7 @@ static int wlan_ret_802_11_stat(wlan_private * priv, memcpy(&adapter->wlan802_11Stat, p11Stat, sizeof(struct cmd_ds_802_11_get_stat)); */ + lbs_deb_leave(LBS_DEB_CMD); return 0; } @@ -268,28 +273,28 @@ static int wlan_ret_802_11_snmp_mib(wlan_private * priv, lbs_deb_enter(LBS_DEB_CMD); - lbs_deb_cmd("SNMP_RESP: value of the oid = %x, querytype=%x\n", oid, + lbs_deb_cmd("SNMP_RESP: oid 0x%x, querytype 0x%x\n", oid, querytype); - lbs_deb_cmd("SNMP_RESP: Buf size = %x\n", le16_to_cpu(smib->bufsize)); + lbs_deb_cmd("SNMP_RESP: Buf size %d\n", le16_to_cpu(smib->bufsize)); if (querytype == CMD_ACT_GET) { switch (oid) { case FRAGTHRESH_I: priv->adapter->fragthsd = le16_to_cpu(*((__le16 *)(smib->value))); - lbs_deb_cmd("SNMP_RESP: fragthsd =%u\n", + lbs_deb_cmd("SNMP_RESP: frag threshold %u\n", priv->adapter->fragthsd); break; case RTSTHRESH_I: priv->adapter->rtsthsd = le16_to_cpu(*((__le16 *)(smib->value))); - lbs_deb_cmd("SNMP_RESP: rtsthsd =%u\n", + lbs_deb_cmd("SNMP_RESP: rts threshold %u\n", priv->adapter->rtsthsd); break; case SHORT_RETRYLIM_I: priv->adapter->txretrycount = le16_to_cpu(*((__le16 *)(smib->value))); - lbs_deb_cmd("SNMP_RESP: txretrycount =%u\n", + lbs_deb_cmd("SNMP_RESP: tx retry count %u\n", priv->adapter->rtsthsd); break; default: @@ -381,9 +386,9 @@ static int wlan_ret_802_11_rf_tx_power(wlan_private * priv, adapter->txpowerlevel = le16_to_cpu(rtp->currentlevel); - lbs_deb_cmd("Current TxPower Level = %d\n", adapter->txpowerlevel); + lbs_deb_cmd("TX power currently %d\n", adapter->txpowerlevel); - lbs_deb_enter(LBS_DEB_CMD); + lbs_deb_leave(LBS_DEB_CMD); return 0; } @@ -394,15 +399,17 @@ static int wlan_ret_802_11_rf_antenna(wlan_private * priv, wlan_adapter *adapter = priv->adapter; u16 action = le16_to_cpu(pAntenna->action); + lbs_deb_enter(LBS_DEB_CMD); if (action == CMD_ACT_GET_RX) adapter->rxantennamode = le16_to_cpu(pAntenna->antennamode); if (action == CMD_ACT_GET_TX) adapter->txantennamode = le16_to_cpu(pAntenna->antennamode); - lbs_deb_cmd("RF_ANT_RESP: action = 0x%x, mode = 0x%04x\n", + lbs_deb_cmd("RF_ANT_RESP: action 0x%x, mode 0x%04x\n", action, le16_to_cpu(pAntenna->antennamode)); + lbs_deb_leave(LBS_DEB_CMD); return 0; } @@ -419,7 +426,7 @@ static int wlan_ret_802_11_rate_adapt_rateset(wlan_private * priv, adapter->ratebitmap = le16_to_cpu(rates->bitmap); } - lbs_deb_enter(LBS_DEB_CMD); + lbs_deb_leave(LBS_DEB_CMD); return 0; } @@ -431,13 +438,14 @@ static int wlan_ret_802_11_data_rate(wlan_private * priv, lbs_deb_enter(LBS_DEB_CMD); - lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP: data_rate- ", (u8 *) pdatarate, + lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) pdatarate, sizeof(struct cmd_ds_802_11_data_rate)); /* FIXME: get actual rates FW can do if this command actually returns * all data rates supported. */ adapter->cur_rate = libertas_fw_index_to_data_rate(pdatarate->rates[0]); + lbs_deb_cmd("DATA_RATE: current rate 0x%02x\n", adapter->cur_rate); lbs_deb_leave(LBS_DEB_CMD); return 0; @@ -455,7 +463,7 @@ static int wlan_ret_802_11_rf_channel(wlan_private * priv, if (action == CMD_OPT_802_11_RF_CHANNEL_GET && adapter->curbssparams.channel != newchannel) { - lbs_deb_cmd("channel Switch: %d to %d\n", + lbs_deb_cmd("channel switch from %d to %d\n", adapter->curbssparams.channel, newchannel); /* Update the channel again */ @@ -472,6 +480,8 @@ static int wlan_ret_802_11_rssi(wlan_private * priv, struct cmd_ds_802_11_rssi_rsp *rssirsp = &resp->params.rssirsp; wlan_adapter *adapter = priv->adapter; + lbs_deb_enter(LBS_DEB_CMD); + /* store the non average value */ adapter->SNR[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->SNR); adapter->NF[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->noisefloor); @@ -487,9 +497,11 @@ static int wlan_ret_802_11_rssi(wlan_private * priv, CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_AVG] / AVG_SCALE, adapter->NF[TYPE_BEACON][TYPE_AVG] / AVG_SCALE); - lbs_deb_cmd("Beacon RSSI value = 0x%x\n", + lbs_deb_cmd("RSSI: beacon %d, avg %d\n", + adapter->RSSI[TYPE_BEACON][TYPE_NOAVG], adapter->RSSI[TYPE_BEACON][TYPE_AVG]); + lbs_deb_leave(LBS_DEB_CMD); return 0; } @@ -500,11 +512,11 @@ static int wlan_ret_802_11_eeprom_access(wlan_private * priv, struct wlan_ioctl_regrdwr *pbuf; pbuf = (struct wlan_ioctl_regrdwr *) adapter->prdeeprom; - lbs_deb_cmd("eeprom read len=%x\n", + lbs_deb_enter_args(LBS_DEB_CMD, "len %d", le16_to_cpu(resp->params.rdeeprom.bytecount)); if (pbuf->NOB < le16_to_cpu(resp->params.rdeeprom.bytecount)) { pbuf->NOB = 0; - lbs_deb_cmd("eeprom read return length is too big\n"); + lbs_deb_cmd("EEPROM read length too big\n"); return -1; } pbuf->NOB = le16_to_cpu(resp->params.rdeeprom.bytecount); @@ -512,9 +524,10 @@ static int wlan_ret_802_11_eeprom_access(wlan_private * priv, memcpy(&pbuf->value, (u8 *) & resp->params.rdeeprom.value, le16_to_cpu(resp->params.rdeeprom.bytecount)); - lbs_deb_hex(LBS_DEB_CMD, "adapter", (char *)&pbuf->value, + lbs_deb_hex(LBS_DEB_CMD, "EEPROM", (char *)&pbuf->value, le16_to_cpu(resp->params.rdeeprom.bytecount)); } + lbs_deb_leave(LBS_DEB_CMD); return 0; } @@ -529,7 +542,7 @@ static int wlan_ret_get_log(wlan_private * priv, /* Stored little-endian */ memcpy(&adapter->logmsg, logmessage, sizeof(struct cmd_ds_802_11_get_log)); - lbs_deb_enter(LBS_DEB_CMD); + lbs_deb_leave(LBS_DEB_CMD); return 0; } @@ -547,7 +560,7 @@ static int libertas_ret_802_11_enable_rsn(wlan_private * priv, *pdata_buf = (u32) le16_to_cpu(enable_rsn->enable); } - lbs_deb_enter(LBS_DEB_CMD); + lbs_deb_leave(LBS_DEB_CMD); return 0; } @@ -559,6 +572,8 @@ static inline int handle_cmd_response(u16 respcmd, unsigned long flags; wlan_adapter *adapter = priv->adapter; + lbs_deb_enter(LBS_DEB_HOST); + switch (respcmd) { case CMD_RET(CMD_MAC_REG_ACCESS): case CMD_RET(CMD_BBP_REG_ACCESS): @@ -654,7 +669,6 @@ static inline int handle_cmd_response(u16 respcmd, break; case CMD_RET(CMD_802_11_KEY_MATERIAL): - lbs_deb_cmd("CMD_RESP: KEY_MATERIAL command response\n"); ret = wlan_ret_802_11_key_material(priv, resp); break; @@ -725,10 +739,11 @@ static inline int handle_cmd_response(u16 respcmd, priv->adapter->txrate = resp->params.txrate.txrate; break; default: - lbs_deb_cmd("CMD_RESP: Unknown command response %#x\n", + lbs_deb_host("CMD_RESP: unknown cmd response 0x%04x\n", resp->command); break; } + lbs_deb_leave(LBS_DEB_HOST); return ret; } @@ -741,9 +756,7 @@ int libertas_process_rx_command(wlan_private * priv) ulong flags; u16 result; - lbs_deb_enter(LBS_DEB_CMD); - - lbs_deb_cmd("CMD_RESP: @ %lu\n", jiffies); + lbs_deb_enter(LBS_DEB_HOST); /* Now we got response from FW, cancel the command timer */ del_timer(&adapter->command_timer); @@ -752,25 +765,23 @@ int libertas_process_rx_command(wlan_private * priv) spin_lock_irqsave(&adapter->driver_lock, flags); if (!adapter->cur_cmd) { - lbs_deb_cmd("CMD_RESP: NULL cur_cmd=%p\n", adapter->cur_cmd); + lbs_deb_host("CMD_RESP: cur_cmd is NULL\n"); ret = -1; spin_unlock_irqrestore(&adapter->driver_lock, flags); goto done; } resp = (struct cmd_ds_command *)(adapter->cur_cmd->bufvirtualaddr); - lbs_deb_hex(LBS_DEB_CMD, "CMD_RESP", adapter->cur_cmd->bufvirtualaddr, - priv->upld_len); - respcmd = le16_to_cpu(resp->command); - result = le16_to_cpu(resp->result); - lbs_deb_cmd("CMD_RESP: %x result: %d length: %d\n", respcmd, - result, priv->upld_len); + lbs_deb_host("CMD_RESP: response 0x%04x, size %d, jiffies %lu\n", + respcmd, priv->upld_len, jiffies); + lbs_deb_hex(LBS_DEB_HOST, "CMD_RESP", adapter->cur_cmd->bufvirtualaddr, + priv->upld_len); if (!(respcmd & 0x8000)) { - lbs_deb_cmd("Invalid response to command!"); + lbs_deb_host("invalid response!\n"); adapter->cur_cmd_retcode = -1; __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd); adapter->nr_cmd_pending--; @@ -787,12 +798,12 @@ int libertas_process_rx_command(wlan_private * priv) struct cmd_ds_802_11_ps_mode *psmode = &resp->params.psmode; u16 action = le16_to_cpu(psmode->action); - lbs_deb_cmd( - "CMD_RESP: PS_MODE cmd reply result=%#x action=0x%X\n", + lbs_deb_host( + "CMD_RESP: PS_MODE cmd reply result 0x%x, action 0x%x\n", result, action); if (result) { - lbs_deb_cmd("CMD_RESP: PS command failed- %#x \n", + lbs_deb_host("CMD_RESP: PS command failed with 0x%x\n", result); /* * We should not re-try enter-ps command in @@ -806,14 +817,14 @@ int libertas_process_rx_command(wlan_private * priv) adapter->needtowakeup = 0; adapter->psstate = PS_STATE_AWAKE; - lbs_deb_cmd("CMD_RESP: Enter_PS command response\n"); + lbs_deb_host("CMD_RESP: ENTER_PS command response\n"); if (adapter->connect_status != LIBERTAS_CONNECTED) { /* * When Deauth Event received before Enter_PS command * response, We need to wake up the firmware. */ - lbs_deb_cmd( - "Disconnected, Going to invoke libertas_ps_wakeup\n"); + lbs_deb_host( + "disconnected, invoking libertas_ps_wakeup\n"); spin_unlock_irqrestore(&adapter->driver_lock, flags); mutex_unlock(&adapter->lock); @@ -824,9 +835,9 @@ int libertas_process_rx_command(wlan_private * priv) } else if (action == CMD_SUBCMD_EXIT_PS) { adapter->needtowakeup = 0; adapter->psstate = PS_STATE_FULL_POWER; - lbs_deb_cmd("CMD_RESP: Exit_PS command response\n"); + lbs_deb_host("CMD_RESP: EXIT_PS command response\n"); } else { - lbs_deb_cmd("CMD_RESP: PS- action=0x%X\n", action); + lbs_deb_host("CMD_RESP: PS action 0x%X\n", action); } __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd); @@ -847,15 +858,15 @@ int libertas_process_rx_command(wlan_private * priv) /* If the command is not successful, cleanup and return failure */ if ((result != 0 || !(respcmd & 0x8000))) { - lbs_deb_cmd("CMD_RESP: command reply %#x result=%#x\n", - respcmd, result); + lbs_deb_host("CMD_RESP: error 0x%04x in command reply 0x%04x\n", + result, respcmd); /* * Handling errors here */ switch (respcmd) { case CMD_RET(CMD_GET_HW_SPEC): case CMD_RET(CMD_802_11_RESET): - lbs_deb_cmd("CMD_RESP: Reset command failed\n"); + lbs_deb_host("CMD_RESP: reset failed\n"); break; } @@ -885,7 +896,7 @@ int libertas_process_rx_command(wlan_private * priv) done: mutex_unlock(&adapter->lock); - lbs_deb_enter_args(LBS_DEB_CMD, "ret %d", ret); + lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret); return ret; } @@ -901,7 +912,7 @@ int libertas_process_event(wlan_private * priv) lbs_deb_enter(LBS_DEB_CMD); - lbs_deb_cmd("EVENT Cause %x\n", eventcause); + lbs_deb_cmd("event cause 0x%x\n", eventcause); switch (eventcause >> SBI_EVENT_CAUSE_SHIFT) { case MACREG_INT_CODE_LINK_SENSED: @@ -909,28 +920,27 @@ int libertas_process_event(wlan_private * priv) break; case MACREG_INT_CODE_DEAUTHENTICATED: - lbs_deb_cmd("EVENT: Deauthenticated\n"); + lbs_deb_cmd("EVENT: deauthenticated\n"); libertas_mac_event_disconnected(priv); break; case MACREG_INT_CODE_DISASSOCIATED: - lbs_deb_cmd("EVENT: Disassociated\n"); + lbs_deb_cmd("EVENT: disassociated\n"); libertas_mac_event_disconnected(priv); break; case MACREG_INT_CODE_LINK_LOSE_NO_SCAN: - lbs_deb_cmd("EVENT: Link lost\n"); + lbs_deb_cmd("EVENT: link lost\n"); libertas_mac_event_disconnected(priv); break; case MACREG_INT_CODE_PS_SLEEP: - lbs_deb_cmd("EVENT: SLEEP\n"); - lbs_deb_cmd("_"); + lbs_deb_cmd("EVENT: sleep\n"); /* handle unexpected PS SLEEP event */ if (adapter->psstate == PS_STATE_FULL_POWER) { lbs_deb_cmd( - "EVENT: In FULL POWER mode - ignore PS SLEEP\n"); + "EVENT: in FULL POWER mode, ignoreing PS_SLEEP\n"); break; } adapter->psstate = PS_STATE_PRE_SLEEP; @@ -940,8 +950,7 @@ int libertas_process_event(wlan_private * priv) break; case MACREG_INT_CODE_PS_AWAKE: - lbs_deb_cmd("EVENT: AWAKE \n"); - lbs_deb_cmd("|"); + lbs_deb_cmd("EVENT: awake\n"); /* handle unexpected PS AWAKE event */ if (adapter->psstate == PS_STATE_FULL_POWER) { @@ -959,7 +968,7 @@ int libertas_process_event(wlan_private * priv) * adapter->needtowakeup will be set to FALSE * in libertas_ps_wakeup() */ - lbs_deb_cmd("Waking up...\n"); + lbs_deb_cmd("waking up ...\n"); libertas_ps_wakeup(priv, 0); } break; @@ -978,27 +987,27 @@ int libertas_process_event(wlan_private * priv) break; case MACREG_INT_CODE_ADHOC_BCN_LOST: - lbs_deb_cmd("EVENT: HWAC - ADHOC BCN LOST\n"); + lbs_deb_cmd("EVENT: ADHOC beacon lost\n"); break; case MACREG_INT_CODE_RSSI_LOW: - lbs_pr_alert( "EVENT: RSSI_LOW\n"); + lbs_pr_alert("EVENT: rssi low\n"); break; case MACREG_INT_CODE_SNR_LOW: - lbs_pr_alert( "EVENT: SNR_LOW\n"); + lbs_pr_alert("EVENT: snr low\n"); break; case MACREG_INT_CODE_MAX_FAIL: - lbs_pr_alert( "EVENT: MAX_FAIL\n"); + lbs_pr_alert("EVENT: max fail\n"); break; case MACREG_INT_CODE_RSSI_HIGH: - lbs_pr_alert( "EVENT: RSSI_HIGH\n"); + lbs_pr_alert("EVENT: rssi high\n"); break; case MACREG_INT_CODE_SNR_HIGH: - lbs_pr_alert( "EVENT: SNR_HIGH\n"); + lbs_pr_alert("EVENT: snr high\n"); break; case MACREG_INT_CODE_MESH_AUTO_STARTED: - lbs_pr_alert( "EVENT: MESH_AUTO_STARTED\n"); + lbs_pr_alert("EVENT: MESH_AUTO_STARTED\n"); adapter->connect_status = LIBERTAS_CONNECTED ; if (priv->mesh_open == 1) { netif_wake_queue(priv->mesh_dev) ; @@ -1009,7 +1018,7 @@ int libertas_process_event(wlan_private * priv) break; default: - lbs_pr_alert( "EVENT: unknown event id: %#x\n", + lbs_pr_alert("EVENT: unknown event id 0x%04x\n", eventcause >> SBI_EVENT_CAUSE_SHIFT); break; } -- cgit v1.2.3-70-g09d2 From 8ff12da121af175a14c4cedbba0fd16ff0cfc07a Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 11:54:31 -0400 Subject: [PATCH] libertas: use LBS_DEB_HOST for host-to-card communications ... and LBS_DEB_CMD for command execution. Also tidies misc comments to give a consistent output. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 259 ++++++++++++++++++----------------- drivers/net/wireless/libertas/main.c | 2 +- 2 files changed, 137 insertions(+), 124 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 8d2f9bad868..d3402e1b760 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -68,7 +68,7 @@ static int wlan_cmd_802_11_ps_mode(wlan_private * priv, switch (cmd_action) { case CMD_SUBCMD_ENTER_PS: lbs_deb_cmd("PS command:" "SubCode- Enter PS\n"); - lbs_deb_cmd("locallisteninterval = %d\n", + lbs_deb_cmd("locallisteninterval %d\n", adapter->locallisteninterval); psm->locallisteninterval = @@ -101,6 +101,8 @@ static int wlan_cmd_802_11_inactivity_timeout(wlan_private * priv, { u16 *timeout = pdata_buf; + lbs_deb_enter(LBS_DEB_CMD); + cmd->command = cpu_to_le16(CMD_802_11_INACTIVITY_TIMEOUT); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_inactivity_timeout) @@ -113,6 +115,7 @@ static int wlan_cmd_802_11_inactivity_timeout(wlan_private * priv, else cmd->params.inactivity_timeout.timeout = 0; + lbs_deb_leave(LBS_DEB_CMD); return 0; } @@ -177,8 +180,6 @@ static int wlan_cmd_802_11_set_wep(wlan_private * priv, wep->keyindex = cpu_to_le16((u16)(assoc_req->wep_tx_keyidx & (u32)CMD_WEP_KEY_INDEX_MASK)); - lbs_deb_cmd("Tx key Index: %u\n", le16_to_cpu(wep->keyindex)); - /* Copy key types and material to host command structure */ for (i = 0; i < 4; i++) { struct enc_key * pkey = &assoc_req->wep_keys[i]; @@ -189,17 +190,19 @@ static int wlan_cmd_802_11_set_wep(wlan_private * priv, cpu_to_le16(CMD_TYPE_WEP_40_BIT); memmove(&wep->keymaterial[i], pkey->key, pkey->len); + lbs_deb_cmd("SET_WEP: add key %d (40 bit)\n", i); break; case KEY_LEN_WEP_104: wep->keytype[i] = cpu_to_le16(CMD_TYPE_WEP_104_BIT); memmove(&wep->keymaterial[i], pkey->key, pkey->len); + lbs_deb_cmd("SET_WEP: add key %d (104 bit)\n", i); break; case 0: break; default: - lbs_deb_cmd("Invalid WEP key %d length of %d\n", + lbs_deb_cmd("SET_WEP: invalid key %d, length %d\n", i, pkey->len); ret = -1; goto done; @@ -213,6 +216,7 @@ static int wlan_cmd_802_11_set_wep(wlan_private * priv, /* default tx key index */ wep->keyindex = cpu_to_le16((u16)(adapter->wep_tx_keyidx & (u32)CMD_WEP_KEY_INDEX_MASK)); + lbs_deb_cmd("SET_WEP: remove key %d\n", adapter->wep_tx_keyidx); } ret = 0; @@ -241,6 +245,7 @@ static int wlan_cmd_802_11_enable_rsn(wlan_private * priv, penableRSN->enable = cpu_to_le16(CMD_ENABLE_RSN); else penableRSN->enable = cpu_to_le16(CMD_DISABLE_RSN); + lbs_deb_cmd("ENABLE_RSN: %d\n", *enable); } lbs_deb_leave(LBS_DEB_CMD); @@ -251,6 +256,8 @@ static int wlan_cmd_802_11_enable_rsn(wlan_private * priv, static void set_one_wpa_key(struct MrvlIEtype_keyParamSet * pkeyparamset, struct enc_key * pkey) { + lbs_deb_enter(LBS_DEB_CMD); + if (pkey->flags & KEY_INFO_WPA_ENABLED) { pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_ENABLED); } @@ -269,6 +276,7 @@ static void set_one_wpa_key(struct MrvlIEtype_keyParamSet * pkeyparamset, + sizeof(pkeyparamset->keyinfo) + sizeof(pkeyparamset->keylen) + sizeof(pkeyparamset->key)); + lbs_deb_leave(LBS_DEB_CMD); } static int wlan_cmd_802_11_key_material(wlan_private * priv, @@ -323,30 +331,37 @@ static int wlan_cmd_802_11_reset(wlan_private * priv, { struct cmd_ds_802_11_reset *reset = &cmd->params.reset; + lbs_deb_enter(LBS_DEB_CMD); + cmd->command = cpu_to_le16(CMD_802_11_RESET); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_reset) + S_DS_GEN); reset->action = cpu_to_le16(cmd_action); + lbs_deb_leave(LBS_DEB_CMD); return 0; } static int wlan_cmd_802_11_get_log(wlan_private * priv, struct cmd_ds_command *cmd) { + lbs_deb_enter(LBS_DEB_CMD); cmd->command = cpu_to_le16(CMD_802_11_GET_LOG); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_get_log) + S_DS_GEN); + lbs_deb_leave(LBS_DEB_CMD); return 0; } static int wlan_cmd_802_11_get_stat(wlan_private * priv, struct cmd_ds_command *cmd) { + lbs_deb_enter(LBS_DEB_CMD); cmd->command = cpu_to_le16(CMD_802_11_GET_STAT); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_get_stat) + S_DS_GEN); + lbs_deb_leave(LBS_DEB_CMD); return 0; } @@ -462,7 +477,7 @@ static int wlan_cmd_802_11_snmp_mib(wlan_private * priv, le16_to_cpu(cmd->seqnum), le16_to_cpu(cmd->result)); lbs_deb_cmd( - "SNMP_CMD: action=0x%x, oid=0x%x, oidsize=0x%x, value=0x%x\n", + "SNMP_CMD: action 0x%x, oid 0x%x, oidsize 0x%x, value 0x%x\n", le16_to_cpu(pSNMPMIB->querytype), le16_to_cpu(pSNMPMIB->oid), le16_to_cpu(pSNMPMIB->bufsize), le16_to_cpu(*(__le16 *) pSNMPMIB->value)); @@ -561,6 +576,7 @@ static int wlan_cmd_802_11_rf_antenna(wlan_private * priv, { struct cmd_ds_802_11_rf_antenna *rant = &cmd->params.rant; + lbs_deb_enter(LBS_DEB_CMD); cmd->command = cpu_to_le16(CMD_802_11_RF_ANTENNA); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rf_antenna) + S_DS_GEN); @@ -570,6 +586,7 @@ static int wlan_cmd_802_11_rf_antenna(wlan_private * priv, rant->antennamode = cpu_to_le16((u16) (*(u32 *) pdata_buf)); } + lbs_deb_leave(LBS_DEB_CMD); return 0; } @@ -581,13 +598,12 @@ static int wlan_cmd_802_11_rate_adapt_rateset(wlan_private * priv, *rateadapt = &cmd->params.rateset; wlan_adapter *adapter = priv->adapter; + lbs_deb_enter(LBS_DEB_CMD); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rate_adapt_rateset) + S_DS_GEN); cmd->command = cpu_to_le16(CMD_802_11_RATE_ADAPT_RATESET); - lbs_deb_enter(LBS_DEB_CMD); - rateadapt->action = cpu_to_le16(cmd_action); rateadapt->enablehwauto = cpu_to_le16(adapter->enablehwauto); rateadapt->bitmap = cpu_to_le16(adapter->ratebitmap); @@ -613,10 +629,10 @@ static int wlan_cmd_802_11_data_rate(wlan_private * priv, if (cmd_action == CMD_ACT_SET_TX_FIX_RATE) { pdatarate->rates[0] = libertas_data_rate_to_fw_index(adapter->cur_rate); - lbs_deb_cmd("Setting FW for fixed rate 0x%02X\n", + lbs_deb_cmd("DATA_RATE: set fixed 0x%02X\n", adapter->cur_rate); } else if (cmd_action == CMD_ACT_SET_TX_AUTO) { - lbs_deb_cmd("Setting FW for AUTO rate\n"); + lbs_deb_cmd("DATA_RATE: setting auto\n"); } lbs_deb_leave(LBS_DEB_CMD); @@ -630,16 +646,19 @@ static int wlan_cmd_mac_multicast_adr(wlan_private * priv, struct cmd_ds_mac_multicast_adr *pMCastAdr = &cmd->params.madr; wlan_adapter *adapter = priv->adapter; + lbs_deb_enter(LBS_DEB_CMD); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_multicast_adr) + S_DS_GEN); cmd->command = cpu_to_le16(CMD_MAC_MULTICAST_ADR); + lbs_deb_cmd("MULTICAST_ADR: setting %d addresses\n", pMCastAdr->nr_of_adrs); pMCastAdr->action = cpu_to_le16(cmd_action); pMCastAdr->nr_of_adrs = cpu_to_le16((u16) adapter->nr_of_multicastmacaddr); memcpy(pMCastAdr->maclist, adapter->multicastlist, adapter->nr_of_multicastmacaddr * ETH_ALEN); + lbs_deb_leave(LBS_DEB_CMD); return 0; } @@ -649,6 +668,7 @@ static int wlan_cmd_802_11_rf_channel(wlan_private * priv, { struct cmd_ds_802_11_rf_channel *rfchan = &cmd->params.rfchannel; + lbs_deb_enter(LBS_DEB_CMD); cmd->command = cpu_to_le16(CMD_802_11_RF_CHANNEL); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rf_channel) + S_DS_GEN); @@ -659,6 +679,7 @@ static int wlan_cmd_802_11_rf_channel(wlan_private * priv, rfchan->action = cpu_to_le16(option); + lbs_deb_leave(LBS_DEB_CMD); return 0; } @@ -667,6 +688,7 @@ static int wlan_cmd_802_11_rssi(wlan_private * priv, { wlan_adapter *adapter = priv->adapter; + lbs_deb_enter(LBS_DEB_CMD); cmd->command = cpu_to_le16(CMD_802_11_RSSI); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rssi) + S_DS_GEN); cmd->params.rssi.N = cpu_to_le16(priv->adapter->bcn_avg_factor); @@ -679,6 +701,7 @@ static int wlan_cmd_802_11_rssi(wlan_private * priv, adapter->RSSI[TYPE_BEACON][TYPE_NOAVG] = 0; adapter->RSSI[TYPE_BEACON][TYPE_AVG] = 0; + lbs_deb_leave(LBS_DEB_CMD); return 0; } @@ -763,6 +786,7 @@ static int wlan_cmd_802_11_mac_address(wlan_private * priv, { wlan_adapter *adapter = priv->adapter; + lbs_deb_enter(LBS_DEB_CMD); cmd->command = cpu_to_le16(CMD_802_11_MAC_ADDRESS); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_mac_address) + S_DS_GEN); @@ -776,6 +800,7 @@ static int wlan_cmd_802_11_mac_address(wlan_private * priv, lbs_deb_hex(LBS_DEB_CMD, "SET_CMD: MAC addr", adapter->current_addr, 6); } + lbs_deb_leave(LBS_DEB_CMD); return 0; } @@ -797,6 +822,7 @@ static int wlan_cmd_802_11_eeprom_access(wlan_private * priv, cmd->params.rdeeprom.bytecount = cpu_to_le16(ea->NOB); cmd->params.rdeeprom.value = 0; + lbs_deb_leave(LBS_DEB_CMD); return 0; } @@ -805,7 +831,7 @@ static int wlan_cmd_bt_access(wlan_private * priv, u16 cmd_action, void *pdata_buf) { struct cmd_ds_bt_access *bt_access = &cmd->params.bt; - lbs_deb_cmd("BT CMD(%d)\n", cmd_action); + lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action); cmd->command = cpu_to_le16(CMD_BT_ACCESS); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_bt_access) + S_DS_GEN); @@ -834,6 +860,7 @@ static int wlan_cmd_bt_access(wlan_private * priv, default: break; } + lbs_deb_leave(LBS_DEB_CMD); return 0; } @@ -842,7 +869,7 @@ static int wlan_cmd_fwt_access(wlan_private * priv, u16 cmd_action, void *pdata_buf) { struct cmd_ds_fwt_access *fwt_access = &cmd->params.fwt; - lbs_deb_cmd("FWT CMD(%d)\n", cmd_action); + lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action); cmd->command = cpu_to_le16(CMD_FWT_ACCESS); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access) + S_DS_GEN); @@ -855,6 +882,7 @@ static int wlan_cmd_fwt_access(wlan_private * priv, fwt_access->action = cpu_to_le16(cmd_action); + lbs_deb_leave(LBS_DEB_CMD); return 0; } @@ -863,7 +891,7 @@ static int wlan_cmd_mesh_access(wlan_private * priv, u16 cmd_action, void *pdata_buf) { struct cmd_ds_mesh_access *mesh_access = &cmd->params.mesh; - lbs_deb_cmd("FWT CMD(%d)\n", cmd_action); + lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action); cmd->command = cpu_to_le16(CMD_MESH_ACCESS); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mesh_access) + S_DS_GEN); @@ -876,6 +904,7 @@ static int wlan_cmd_mesh_access(wlan_private * priv, mesh_access->action = cpu_to_le16(cmd_action); + lbs_deb_leave(LBS_DEB_CMD); return 0; } @@ -884,16 +913,16 @@ void libertas_queue_cmd(wlan_adapter * adapter, struct cmd_ctrl_node *cmdnode, u unsigned long flags; struct cmd_ds_command *cmdptr; - lbs_deb_enter(LBS_DEB_CMD); + lbs_deb_enter(LBS_DEB_HOST); if (!cmdnode) { - lbs_deb_cmd("QUEUE_CMD: cmdnode is NULL\n"); + lbs_deb_host("QUEUE_CMD: cmdnode is NULL\n"); goto done; } cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr; if (!cmdptr) { - lbs_deb_cmd("QUEUE_CMD: cmdptr is NULL\n"); + lbs_deb_host("QUEUE_CMD: cmdptr is NULL\n"); goto done; } @@ -916,17 +945,16 @@ void libertas_queue_cmd(wlan_adapter * adapter, struct cmd_ctrl_node *cmdnode, u spin_unlock_irqrestore(&adapter->driver_lock, flags); - lbs_deb_cmd("QUEUE_CMD: Inserted node=%p, cmd=0x%x in cmdpendingq\n", - cmdnode, + lbs_deb_host("QUEUE_CMD: inserted command 0x%04x into cmdpendingq\n", le16_to_cpu(((struct cmd_ds_gen*)cmdnode->bufvirtualaddr)->command)); done: - lbs_deb_leave(LBS_DEB_CMD); + lbs_deb_leave(LBS_DEB_HOST); } /* * TODO: Fix the issue when DownloadcommandToStation is being called the - * second time when the command timesout. All the cmdptr->xxx are in little + * second time when the command times out. All the cmdptr->xxx are in little * endian and therefore all the comparissions will fail. * For now - we are not performing the endian conversion the second time - but * for PS and DEEP_SLEEP we need to worry @@ -941,11 +969,10 @@ static int DownloadcommandToStation(wlan_private * priv, u16 cmdsize; u16 command; - lbs_deb_enter(LBS_DEB_CMD); + lbs_deb_enter(LBS_DEB_HOST); if (!adapter || !cmdnode) { - lbs_deb_cmd("DNLD_CMD: adapter = %p, cmdnode = %p\n", - adapter, cmdnode); + lbs_deb_host("DNLD_CMD: adapter or cmdmode is NULL\n"); if (cmdnode) { spin_lock_irqsave(&adapter->driver_lock, flags); __libertas_cleanup_and_insert_cmd(priv, cmdnode); @@ -957,11 +984,9 @@ static int DownloadcommandToStation(wlan_private * priv, cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr; - spin_lock_irqsave(&adapter->driver_lock, flags); if (!cmdptr || !cmdptr->size) { - lbs_deb_cmd("DNLD_CMD: cmdptr is Null or cmd size is Zero, " - "Not sending\n"); + lbs_deb_host("DNLD_CMD: cmdptr is NULL or zero\n"); __libertas_cleanup_and_insert_cmd(priv, cmdnode); spin_unlock_irqrestore(&adapter->driver_lock, flags); ret = -1; @@ -971,20 +996,21 @@ static int DownloadcommandToStation(wlan_private * priv, adapter->cur_cmd = cmdnode; adapter->cur_cmd_retcode = 0; spin_unlock_irqrestore(&adapter->driver_lock, flags); - lbs_deb_cmd("DNLD_CMD:: Before download, size of cmd = %d\n", - le16_to_cpu(cmdptr->size)); cmdsize = cmdptr->size; - command = cpu_to_le16(cmdptr->command); + lbs_deb_host("DNLD_CMD: command 0x%04x, size %d, jiffies %lu\n", + command, le16_to_cpu(cmdptr->size), jiffies); + lbs_deb_hex(LBS_DEB_HOST, "DNLD_CMD", cmdnode->bufvirtualaddr, cmdsize); + cmdnode->cmdwaitqwoken = 0; cmdsize = cpu_to_le16(cmdsize); ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmdptr, cmdsize); if (ret != 0) { - lbs_deb_cmd("DNLD_CMD: Host to Card failed\n"); + lbs_deb_host("DNLD_CMD: hw_host_to_card failed\n"); spin_lock_irqsave(&adapter->driver_lock, flags); __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd); adapter->cur_cmd = NULL; @@ -993,8 +1019,7 @@ static int DownloadcommandToStation(wlan_private * priv, goto done; } - lbs_deb_cmd("DNLD_CMD: sent command 0x%x, jiffies %lu\n", command, jiffies); - lbs_deb_hex(LBS_DEB_CMD, "command", cmdnode->bufvirtualaddr, cmdsize); + lbs_deb_cmd("DNLD_CMD: sent command 0x%04x, jiffies %lu\n", command, jiffies); /* Setup the timer after transmit command */ if (command == CMD_802_11_SCAN || command == CMD_802_11_AUTHENTICATE @@ -1006,7 +1031,7 @@ static int DownloadcommandToStation(wlan_private * priv, ret = 0; done: - lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); + lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret); return ret; } @@ -1021,7 +1046,7 @@ static int wlan_cmd_mac_control(wlan_private * priv, cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_control) + S_DS_GEN); mac->action = cpu_to_le16(priv->adapter->currentpacketfilter); - lbs_deb_cmd("wlan_cmd_mac_control(): action=0x%X size=%d\n", + lbs_deb_cmd("MAC_CONTROL: action 0x%x, size %d\n", le16_to_cpu(mac->action), le16_to_cpu(cmd->size)); lbs_deb_leave(LBS_DEB_CMD); @@ -1037,12 +1062,10 @@ void __libertas_cleanup_and_insert_cmd(wlan_private * priv, struct cmd_ctrl_node wlan_adapter *adapter = priv->adapter; if (!ptempcmd) - goto done; + return; cleanup_cmdnode(ptempcmd); list_add_tail((struct list_head *)ptempcmd, &adapter->cmdfreeq); -done: - return; } static void libertas_cleanup_and_insert_cmd(wlan_private * priv, struct cmd_ctrl_node *ptempcmd) @@ -1065,7 +1088,7 @@ int libertas_set_radio_control(wlan_private * priv) CMD_ACT_SET, CMD_OPTION_WAITFORRSP, 0, NULL); - lbs_deb_cmd("RADIO_SET: on or off: 0x%X, preamble = 0x%X\n", + lbs_deb_cmd("RADIO_SET: radio %d, preamble %d\n", priv->adapter->radioon, priv->adapter->preamble); lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); @@ -1078,9 +1101,6 @@ int libertas_set_mac_packet_filter(wlan_private * priv) lbs_deb_enter(LBS_DEB_CMD); - lbs_deb_cmd("libertas_set_mac_packet_filter value = %x\n", - priv->adapter->currentpacketfilter); - /* Send MAC control command to station */ ret = libertas_prepare_and_send_command(priv, CMD_MAC_CONTROL, 0, 0, 0, NULL); @@ -1111,16 +1131,16 @@ int libertas_prepare_and_send_command(wlan_private * priv, struct cmd_ds_command *cmdptr; unsigned long flags; - lbs_deb_enter(LBS_DEB_CMD); + lbs_deb_enter(LBS_DEB_HOST); if (!adapter) { - lbs_deb_cmd("PREP_CMD: adapter is Null\n"); + lbs_deb_host("PREP_CMD: adapter is NULL\n"); ret = -1; goto done; } if (adapter->surpriseremoved) { - lbs_deb_cmd("PREP_CMD: Card is Removed\n"); + lbs_deb_host("PREP_CMD: card removed\n"); ret = -1; goto done; } @@ -1128,7 +1148,7 @@ int libertas_prepare_and_send_command(wlan_private * priv, cmdnode = libertas_get_free_cmd_ctrl_node(priv); if (cmdnode == NULL) { - lbs_deb_cmd("PREP_CMD: No free cmdnode\n"); + lbs_deb_host("PREP_CMD: cmdnode is NULL\n"); /* Wake up main thread to execute next command */ wake_up_interruptible(&priv->waitq); @@ -1140,11 +1160,10 @@ int libertas_prepare_and_send_command(wlan_private * priv, cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr; - lbs_deb_cmd("PREP_CMD: Val of cmd ptr=%p, command=0x%X\n", - cmdptr, cmd_no); + lbs_deb_host("PREP_CMD: command 0x%04x\n", cmd_no); if (!cmdptr) { - lbs_deb_cmd("PREP_CMD: bufvirtualaddr of cmdnode is NULL\n"); + lbs_deb_host("PREP_CMD: cmdptr is NULL\n"); libertas_cleanup_and_insert_cmd(priv, cmdnode); ret = -1; goto done; @@ -1382,14 +1401,14 @@ int libertas_prepare_and_send_command(wlan_private * priv, ret = 0; break; default: - lbs_deb_cmd("PREP_CMD: unknown command- %#x\n", cmd_no); + lbs_deb_host("PREP_CMD: unknown command 0x%04x\n", cmd_no); ret = -1; break; } /* return error, since the command preparation failed */ if (ret != 0) { - lbs_deb_cmd("PREP_CMD: command preparation failed\n"); + lbs_deb_host("PREP_CMD: command preparation failed\n"); libertas_cleanup_and_insert_cmd(priv, cmdnode); ret = -1; goto done; @@ -1402,7 +1421,7 @@ int libertas_prepare_and_send_command(wlan_private * priv, wake_up_interruptible(&priv->waitq); if (wait_option & CMD_OPTION_WAITFORRSP) { - lbs_deb_cmd("PREP_CMD: Wait for CMD response\n"); + lbs_deb_host("PREP_CMD: wait for response\n"); might_sleep(); wait_event_interruptible(cmdnode->cmdwait_q, cmdnode->cmdwaitqwoken); @@ -1410,7 +1429,7 @@ int libertas_prepare_and_send_command(wlan_private * priv, spin_lock_irqsave(&adapter->driver_lock, flags); if (adapter->cur_cmd_retcode) { - lbs_deb_cmd("PREP_CMD: command failed with return code=%d\n", + lbs_deb_host("PREP_CMD: command failed with return code %d\n", adapter->cur_cmd_retcode); adapter->cur_cmd_retcode = 0; ret = -1; @@ -1418,7 +1437,7 @@ int libertas_prepare_and_send_command(wlan_private * priv, spin_unlock_irqrestore(&adapter->driver_lock, flags); done: - lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); + lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret); return ret; } EXPORT_SYMBOL_GPL(libertas_prepare_and_send_command); @@ -1439,14 +1458,13 @@ int libertas_allocate_cmd_buffer(wlan_private * priv) u8 *ptempvirtualaddr; wlan_adapter *adapter = priv->adapter; - lbs_deb_enter(LBS_DEB_CMD); + lbs_deb_enter(LBS_DEB_HOST); /* Allocate and initialize cmdCtrlNode */ ulbufsize = sizeof(struct cmd_ctrl_node) * MRVDRV_NUM_OF_CMD_BUFFER; if (!(tempcmd_array = kzalloc(ulbufsize, GFP_KERNEL))) { - lbs_deb_cmd( - "ALLOC_CMD_BUF: failed to allocate tempcmd_array\n"); + lbs_deb_host("ALLOC_CMD_BUF: tempcmd_array is NULL\n"); ret = -1; goto done; } @@ -1456,8 +1474,7 @@ int libertas_allocate_cmd_buffer(wlan_private * priv) ulbufsize = MRVDRV_SIZE_OF_CMD_BUFFER; for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) { if (!(ptempvirtualaddr = kzalloc(ulbufsize, GFP_KERNEL))) { - lbs_deb_cmd( - "ALLOC_CMD_BUF: ptempvirtualaddr: out of memory\n"); + lbs_deb_host("ALLOC_CMD_BUF: ptempvirtualaddr is NULL\n"); ret = -1; goto done; } @@ -1474,7 +1491,7 @@ int libertas_allocate_cmd_buffer(wlan_private * priv) ret = 0; done: - lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); + lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret); return ret; } @@ -1491,11 +1508,11 @@ int libertas_free_cmd_buffer(wlan_private * priv) struct cmd_ctrl_node *tempcmd_array; wlan_adapter *adapter = priv->adapter; - lbs_deb_enter(LBS_DEB_CMD); + lbs_deb_enter(LBS_DEB_HOST); /* need to check if cmd array is allocated or not */ if (adapter->cmd_array == NULL) { - lbs_deb_cmd("FREE_CMD_BUF: cmd_array is Null\n"); + lbs_deb_host("FREE_CMD_BUF: cmd_array is NULL\n"); goto done; } @@ -1505,7 +1522,6 @@ int libertas_free_cmd_buffer(wlan_private * priv) ulbufsize = MRVDRV_SIZE_OF_CMD_BUFFER; for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) { if (tempcmd_array[i].bufvirtualaddr) { - lbs_deb_cmd("Free all the array\n"); kfree(tempcmd_array[i].bufvirtualaddr); tempcmd_array[i].bufvirtualaddr = NULL; } @@ -1513,13 +1529,12 @@ int libertas_free_cmd_buffer(wlan_private * priv) /* Release cmd_ctrl_node */ if (adapter->cmd_array) { - lbs_deb_cmd("Free cmd_array\n"); kfree(adapter->cmd_array); adapter->cmd_array = NULL; } done: - lbs_deb_leave(LBS_DEB_CMD); + lbs_deb_leave(LBS_DEB_HOST); return 0; } @@ -1536,6 +1551,8 @@ struct cmd_ctrl_node *libertas_get_free_cmd_ctrl_node(wlan_private * priv) wlan_adapter *adapter = priv->adapter; unsigned long flags; + lbs_deb_enter(LBS_DEB_HOST); + if (!adapter) return NULL; @@ -1545,21 +1562,16 @@ struct cmd_ctrl_node *libertas_get_free_cmd_ctrl_node(wlan_private * priv) tempnode = (struct cmd_ctrl_node *)adapter->cmdfreeq.next; list_del((struct list_head *)tempnode); } else { - lbs_deb_cmd("GET_CMD_NODE: cmd_ctrl_node is not available\n"); + lbs_deb_host("GET_CMD_NODE: cmd_ctrl_node is not available\n"); tempnode = NULL; } spin_unlock_irqrestore(&adapter->driver_lock, flags); - if (tempnode) { - /* - lbs_pr_debug(3, "GET_CMD_NODE: cmdCtrlNode available\n"); - lbs_pr_debug(3, "GET_CMD_NODE: cmdCtrlNode Address = %p\n", - tempnode); - */ + if (tempnode) cleanup_cmdnode(tempnode); - } + lbs_deb_leave(LBS_DEB_HOST); return tempnode; } @@ -1571,6 +1583,8 @@ struct cmd_ctrl_node *libertas_get_free_cmd_ctrl_node(wlan_private * priv) */ static void cleanup_cmdnode(struct cmd_ctrl_node *ptempnode) { + lbs_deb_enter(LBS_DEB_HOST); + if (!ptempnode) return; ptempnode->cmdwaitqwoken = 1; @@ -1582,7 +1596,8 @@ static void cleanup_cmdnode(struct cmd_ctrl_node *ptempnode) if (ptempnode->bufvirtualaddr != NULL) memset(ptempnode->bufvirtualaddr, 0, MRVDRV_SIZE_OF_CMD_BUFFER); - return; + + lbs_deb_leave(LBS_DEB_HOST); } /** @@ -1599,7 +1614,7 @@ void libertas_set_cmd_ctrl_node(wlan_private * priv, struct cmd_ctrl_node *ptempnode, u32 cmd_oid, u16 wait_option, void *pdata_buf) { - lbs_deb_enter(LBS_DEB_CMD); + lbs_deb_enter(LBS_DEB_HOST); if (!ptempnode) return; @@ -1608,7 +1623,7 @@ void libertas_set_cmd_ctrl_node(wlan_private * priv, ptempnode->wait_option = wait_option; ptempnode->pdata_buf = pdata_buf; - lbs_deb_leave(LBS_DEB_CMD); + lbs_deb_leave(LBS_DEB_HOST); } /** @@ -1627,12 +1642,15 @@ int libertas_execute_next_command(wlan_private * priv) unsigned long flags; int ret = 0; - lbs_deb_enter(LBS_DEB_CMD); + // Debug group is LBS_DEB_THREAD and not LBS_DEB_HOST, because the + // only caller to us is libertas_thread() and we get even when a + // data packet is received + lbs_deb_enter(LBS_DEB_THREAD); spin_lock_irqsave(&adapter->driver_lock, flags); if (adapter->cur_cmd) { - lbs_pr_alert( "EXEC_NEXT_CMD: there is command in processing!\n"); + lbs_pr_alert( "EXEC_NEXT_CMD: already processing command!\n"); spin_unlock_irqrestore(&adapter->driver_lock, flags); ret = -1; goto done; @@ -1646,22 +1664,20 @@ int libertas_execute_next_command(wlan_private * priv) spin_unlock_irqrestore(&adapter->driver_lock, flags); if (cmdnode) { - lbs_deb_cmd( - "EXEC_NEXT_CMD: Got next command from cmdpendingq\n"); cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr; if (is_command_allowed_in_ps(cmdptr->command)) { if ((adapter->psstate == PS_STATE_SLEEP) || (adapter->psstate == PS_STATE_PRE_SLEEP)) { - lbs_deb_cmd( - "EXEC_NEXT_CMD: Cannot send cmd 0x%x in psstate %d\n", + lbs_deb_host( + "EXEC_NEXT_CMD: cannot send cmd 0x%04x in psstate %d\n", le16_to_cpu(cmdptr->command), adapter->psstate); ret = -1; goto done; } - lbs_deb_cmd("EXEC_NEXT_CMD: OK to send command " - "0x%x in psstate %d\n", + lbs_deb_host("EXEC_NEXT_CMD: OK to send command " + "0x%04x in psstate %d\n", le16_to_cpu(cmdptr->command), adapter->psstate); } else if (adapter->psstate != PS_STATE_FULL_POWER) { @@ -1699,13 +1715,13 @@ int libertas_execute_next_command(wlan_private * priv) struct cmd_ds_802_11_ps_mode *psm = &cmdptr->params.psmode; - lbs_deb_cmd( - "EXEC_NEXT_CMD: PS cmd- action=0x%x\n", + lbs_deb_host( + "EXEC_NEXT_CMD: PS cmd, action 0x%02x\n", psm->action); if (psm->action != cpu_to_le16(CMD_SUBCMD_EXIT_PS)) { - lbs_deb_cmd( - "EXEC_NEXT_CMD: Ignore Enter PS cmd\n"); + lbs_deb_host( + "EXEC_NEXT_CMD: ignore ENTER_PS cmd\n"); list_del((struct list_head *)cmdnode); libertas_cleanup_and_insert_cmd(priv, cmdnode); @@ -1715,8 +1731,8 @@ int libertas_execute_next_command(wlan_private * priv) if ((adapter->psstate == PS_STATE_SLEEP) || (adapter->psstate == PS_STATE_PRE_SLEEP)) { - lbs_deb_cmd( - "EXEC_NEXT_CMD: Ignore ExitPS cmd in sleep\n"); + lbs_deb_host( + "EXEC_NEXT_CMD: ignore EXIT_PS cmd in sleep\n"); list_del((struct list_head *)cmdnode); libertas_cleanup_and_insert_cmd(priv, cmdnode); adapter->needtowakeup = 1; @@ -1725,12 +1741,12 @@ int libertas_execute_next_command(wlan_private * priv) goto done; } - lbs_deb_cmd( - "EXEC_NEXT_CMD: Sending Exit_PS down...\n"); + lbs_deb_host( + "EXEC_NEXT_CMD: sending EXIT_PS\n"); } } list_del((struct list_head *)cmdnode); - lbs_deb_cmd("EXEC_NEXT_CMD: Sending 0x%04X command\n", + lbs_deb_host("EXEC_NEXT_CMD: sending command 0x%04x\n", le16_to_cpu(cmdptr->command)); DownloadcommandToStation(priv, cmdnode); } else { @@ -1746,15 +1762,15 @@ int libertas_execute_next_command(wlan_private * priv) /* check for valid WPA group keys */ if (adapter->wpa_mcast_key.len || adapter->wpa_unicast_key.len) { - lbs_deb_cmd( + lbs_deb_host( "EXEC_NEXT_CMD: WPA enabled and GTK_SET" " go back to PS_SLEEP"); libertas_ps_sleep(priv, 0); } } else { - lbs_deb_cmd( - "EXEC_NEXT_CMD: command PendQ is empty," - " go back to PS_SLEEP"); + lbs_deb_host( + "EXEC_NEXT_CMD: cmdpendingq empty, " + "go back to PS_SLEEP"); libertas_ps_sleep(priv, 0); } } @@ -1762,7 +1778,7 @@ int libertas_execute_next_command(wlan_private * priv) ret = 0; done: - lbs_deb_leave(LBS_DEB_CMD); + lbs_deb_leave(LBS_DEB_THREAD); return ret; } @@ -1771,7 +1787,7 @@ void libertas_send_iwevcustom_event(wlan_private * priv, s8 * str) union iwreq_data iwrq; u8 buf[50]; - lbs_deb_enter(LBS_DEB_CMD); + lbs_deb_enter(LBS_DEB_WEXT); memset(&iwrq, 0, sizeof(union iwreq_data)); memset(buf, 0, sizeof(buf)); @@ -1781,13 +1797,13 @@ void libertas_send_iwevcustom_event(wlan_private * priv, s8 * str) iwrq.data.length = strlen(buf) + 1 + IW_EV_LCP_LEN; /* Send Event to upper layer */ - lbs_deb_cmd("Event Indication string = %s\n", (char *)buf); - lbs_deb_cmd("Event Indication String length = %d\n", iwrq.data.length); + lbs_deb_wext("event indication string %s\n", (char *)buf); + lbs_deb_wext("event indication length %d\n", iwrq.data.length); + lbs_deb_wext("sending wireless event IWEVCUSTOM for %s\n", str); - lbs_deb_cmd("Sending wireless event IWEVCUSTOM for %s\n", str); wireless_send_event(priv->dev, IWEVCUSTOM, &iwrq, buf); - lbs_deb_leave(LBS_DEB_CMD); + lbs_deb_leave(LBS_DEB_WEXT); } static int sendconfirmsleep(wlan_private * priv, u8 * cmdptr, u16 size) @@ -1796,19 +1812,19 @@ static int sendconfirmsleep(wlan_private * priv, u8 * cmdptr, u16 size) wlan_adapter *adapter = priv->adapter; int ret = 0; - lbs_deb_enter(LBS_DEB_CMD); + lbs_deb_enter(LBS_DEB_HOST); - lbs_deb_cmd("SEND_SLEEPC_CMD: Before download, size of cmd = %d\n", + lbs_deb_host("SEND_SLEEPC_CMD: before download, cmd size %d\n", size); - lbs_deb_hex(LBS_DEB_CMD, "sleep confirm command", cmdptr, size); + lbs_deb_hex(LBS_DEB_HOST, "sleep confirm command", cmdptr, size); ret = priv->hw_host_to_card(priv, MVMS_CMD, cmdptr, size); priv->dnld_sent = DNLD_RES_RECEIVED; spin_lock_irqsave(&adapter->driver_lock, flags); if (adapter->intcounter || adapter->currenttxskb) - lbs_deb_cmd("SEND_SLEEPC_CMD: intcounter=%d currenttxskb=%p\n", + lbs_deb_host("SEND_SLEEPC_CMD: intcounter %d, currenttxskb %p\n", adapter->intcounter, adapter->currenttxskb); spin_unlock_irqrestore(&adapter->driver_lock, flags); @@ -1820,22 +1836,21 @@ static int sendconfirmsleep(wlan_private * priv, u8 * cmdptr, u16 size) if (!adapter->intcounter) { adapter->psstate = PS_STATE_SLEEP; } else { - lbs_deb_cmd("SEND_SLEEPC_CMD: After sent,IntC=%d\n", + lbs_deb_host("SEND_SLEEPC_CMD: after sent, intcounter %d\n", adapter->intcounter); } spin_unlock_irqrestore(&adapter->driver_lock, flags); - lbs_deb_cmd("SEND_SLEEPC_CMD: Sent Confirm Sleep command\n"); - lbs_deb_cmd("+"); + lbs_deb_host("SEND_SLEEPC_CMD: sent confirm sleep\n"); } - lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); + lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret); return ret; } void libertas_ps_sleep(wlan_private * priv, int wait_option) { - lbs_deb_enter(LBS_DEB_CMD); + lbs_deb_enter(LBS_DEB_HOST); /* * PS is currently supported only in Infrastructure mode @@ -1845,11 +1860,11 @@ void libertas_ps_sleep(wlan_private * priv, int wait_option) libertas_prepare_and_send_command(priv, CMD_802_11_PS_MODE, CMD_SUBCMD_ENTER_PS, wait_option, 0, NULL); - lbs_deb_leave(LBS_DEB_CMD); + lbs_deb_leave(LBS_DEB_HOST); } /** - * @brief This function sends Eixt_PS command to firmware. + * @brief This function sends Exit_PS command to firmware. * * @param priv A pointer to wlan_private structure * @param wait_option wait response or not @@ -1859,17 +1874,15 @@ void libertas_ps_wakeup(wlan_private * priv, int wait_option) { __le32 Localpsmode; - lbs_deb_enter(LBS_DEB_CMD); + lbs_deb_enter(LBS_DEB_HOST); Localpsmode = cpu_to_le32(WLAN802_11POWERMODECAM); - lbs_deb_cmd("Exit_PS: Localpsmode = %d\n", WLAN802_11POWERMODECAM); - libertas_prepare_and_send_command(priv, CMD_802_11_PS_MODE, CMD_SUBCMD_EXIT_PS, wait_option, 0, &Localpsmode); - lbs_deb_leave(LBS_DEB_CMD); + lbs_deb_leave(LBS_DEB_HOST); } /** @@ -1886,31 +1899,31 @@ void libertas_ps_confirm_sleep(wlan_private * priv, u16 psmode) wlan_adapter *adapter = priv->adapter; u8 allowed = 1; - lbs_deb_enter(LBS_DEB_CMD); + lbs_deb_enter(LBS_DEB_HOST); if (priv->dnld_sent) { allowed = 0; - lbs_deb_cmd("D"); + lbs_deb_host("dnld_sent was set"); } spin_lock_irqsave(&adapter->driver_lock, flags); if (adapter->cur_cmd) { allowed = 0; - lbs_deb_cmd("C"); + lbs_deb_host("cur_cmd was set"); } if (adapter->intcounter > 0) { allowed = 0; - lbs_deb_cmd("I%d", adapter->intcounter); + lbs_deb_host("intcounter %d", adapter->intcounter); } spin_unlock_irqrestore(&adapter->driver_lock, flags); if (allowed) { - lbs_deb_cmd("Sending libertas_ps_confirm_sleep\n"); + lbs_deb_host("sending libertas_ps_confirm_sleep\n"); sendconfirmsleep(priv, (u8 *) & adapter->libertas_ps_confirm_sleep, sizeof(struct PS_CMD_ConfirmSleep)); } else { - lbs_deb_cmd("Sleep Confirm has been delayed\n"); + lbs_deb_host("sleep confirm has been delayed\n"); } - lbs_deb_leave(LBS_DEB_CMD); + lbs_deb_leave(LBS_DEB_HOST); } diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 2713f57e9bc..1b6b09d5f97 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1319,7 +1319,7 @@ static void wake_pending_cmdnodes(wlan_private *priv) struct cmd_ctrl_node *cmdnode; unsigned long flags; - lbs_deb_enter(LBS_DEB_CMD); + lbs_deb_enter(LBS_DEB_HOST); spin_lock_irqsave(&priv->adapter->driver_lock, flags); list_for_each_entry(cmdnode, &priv->adapter->cmdpendingq, list) { -- cgit v1.2.3-70-g09d2 From 9cdc6d295b97dc4a36569ddd0b0540aeba351149 Mon Sep 17 00:00:00 2001 From: Luis Carlos Cobo Date: Thu, 2 Aug 2007 11:55:22 -0400 Subject: [PATCH] libertas: Avoid MESH_AUTOSTARTED spam on console Signed-off-by: Luis Carlos Cobo Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmdresp.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 197d0451784..bf672f51f16 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -1007,13 +1007,13 @@ int libertas_process_event(wlan_private * priv) break; case MACREG_INT_CODE_MESH_AUTO_STARTED: - lbs_pr_alert("EVENT: MESH_AUTO_STARTED\n"); - adapter->connect_status = LIBERTAS_CONNECTED ; + lbs_pr_info("EVENT: MESH_AUTO_STARTED\n"); + adapter->connect_status = LIBERTAS_CONNECTED; if (priv->mesh_open == 1) { - netif_wake_queue(priv->mesh_dev) ; - netif_carrier_on(priv->mesh_dev) ; + netif_wake_queue(priv->mesh_dev); + netif_carrier_on(priv->mesh_dev); } - adapter->mode = IW_MODE_ADHOC ; + adapter->mode = IW_MODE_ADHOC; schedule_work(&priv->sync_channel); break; -- cgit v1.2.3-70-g09d2 From 27590d06e136167101c8c6347e7c2885c7f014b9 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Wed, 3 Oct 2007 17:25:41 -0700 Subject: [PATCH] add support for Marvell 8385 CF cards This patch adds support for Marvell based 8385 compact flash cards. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/Kconfig | 7 + drivers/net/wireless/libertas/Makefile | 2 + drivers/net/wireless/libertas/if_cs.c | 1005 ++++++++++++++++++++++++++++++++ 3 files changed, 1014 insertions(+) create mode 100644 drivers/net/wireless/libertas/if_cs.c (limited to 'drivers') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index adf0d207da8..8d1541bbe25 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -275,6 +275,13 @@ config LIBERTAS_USB ---help--- A driver for Marvell Libertas 8388 USB devices. +config LIBERTAS_CS + tristate "Marvell Libertas 8385 CompactFlash 802.11b/g cards" + depends on LIBERTAS && PCMCIA && EXPERIMENTAL + select FW_LOADER + ---help--- + A driver for Marvell Libertas 8385 CompactFlash devices. + config LIBERTAS_DEBUG bool "Enable full debugging output in the Libertas module." depends on LIBERTAS diff --git a/drivers/net/wireless/libertas/Makefile b/drivers/net/wireless/libertas/Makefile index b56b4c55de3..c469d569f09 100644 --- a/drivers/net/wireless/libertas/Makefile +++ b/drivers/net/wireless/libertas/Makefile @@ -6,6 +6,8 @@ libertas-objs := main.o wext.o \ ethtool.o assoc.o usb8xxx-objs += if_usb.o +libertas_cs-objs += if_cs.o obj-$(CONFIG_LIBERTAS) += libertas.o obj-$(CONFIG_LIBERTAS_USB) += usb8xxx.o +obj-$(CONFIG_LIBERTAS_CS) += libertas_cs.o diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c new file mode 100644 index 00000000000..888f023a74e --- /dev/null +++ b/drivers/net/wireless/libertas/if_cs.c @@ -0,0 +1,1005 @@ +/* + + Driver for the Marvell 8385 based compact flash WLAN cards. + + (C) 2007 by Holger Schurig + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#define DRV_NAME "libertas_cs" + +#include "decl.h" +#include "defs.h" +#include "dev.h" + + +/********************************************************************/ +/* Module stuff */ +/********************************************************************/ + +MODULE_AUTHOR("Holger Schurig "); +MODULE_DESCRIPTION("Driver for Marvell 83xx compact flash WLAN cards"); +MODULE_LICENSE("GPL"); + + + +/********************************************************************/ +/* Data structures */ +/********************************************************************/ + +struct if_cs_card { + struct pcmcia_device *p_dev; + wlan_private *priv; + void __iomem *iobase; +}; + + + +/********************************************************************/ +/* Hardware access */ +/********************************************************************/ + +/* This define enables wrapper functions which allow you + to dump all register accesses. You normally won't this, + except for development */ +/* #define DEBUG_IO */ + +#ifdef DEBUG_IO +static int debug_output = 0; +#else +/* This way the compiler optimizes the printk's away */ +#define debug_output 0 +#endif + +static inline unsigned int if_cs_read8(struct if_cs_card *card, uint reg) +{ + unsigned int val = ioread8(card->iobase + reg); + if (debug_output) + printk(KERN_INFO "##inb %08x<%02x\n", reg, val); + return val; +} +static inline unsigned int if_cs_read16(struct if_cs_card *card, uint reg) +{ + unsigned int val = ioread16(card->iobase + reg); + if (debug_output) + printk(KERN_INFO "##inw %08x<%04x\n", reg, val); + return val; +} +static inline void if_cs_read16_rep( + struct if_cs_card *card, + uint reg, + void *buf, + unsigned long count) +{ + if (debug_output) + printk(KERN_INFO "##insw %08x<(0x%lx words)\n", + reg, count); + ioread16_rep(card->iobase + reg, buf, count); +} + +static inline void if_cs_write8(struct if_cs_card *card, uint reg, u8 val) +{ + if (debug_output) + printk(KERN_INFO "##outb %08x>%02x\n", reg, val); + iowrite8(val, card->iobase + reg); +} + +static inline void if_cs_write16(struct if_cs_card *card, uint reg, u16 val) +{ + if (debug_output) + printk(KERN_INFO "##outw %08x>%04x\n", reg, val); + iowrite16(val, card->iobase + reg); +} + +static inline void if_cs_write16_rep( + struct if_cs_card *card, + uint reg, + void *buf, + unsigned long count) +{ + if (debug_output) + printk(KERN_INFO "##outsw %08x>(0x%lx words)\n", + reg, count); + iowrite16_rep(card->iobase + reg, buf, count); +} + + +/* + * I know that polling/delaying is frowned upon. However, this procedure + * with polling is needed while downloading the firmware. At this stage, + * the hardware does unfortunately not create any interrupts. + * + * Fortunately, this function is never used once the firmware is in + * the card. :-) + * + * As a reference, see the "Firmware Specification v5.1", page 18 + * and 19. I did not follow their suggested timing to the word, + * but this works nice & fast anyway. + */ +static int if_cs_poll_while_fw_download(struct if_cs_card *card, uint addr, u8 reg) +{ + int i; + + for (i = 0; i < 500; i++) { + u8 val = if_cs_read8(card, addr); + if (val == reg) + return i; + udelay(100); + } + return -ETIME; +} + + + +/* Host control registers and their bit definitions */ + +#define IF_CS_H_STATUS 0x00000000 +#define IF_CS_H_STATUS_TX_OVER 0x0001 +#define IF_CS_H_STATUS_RX_OVER 0x0002 +#define IF_CS_H_STATUS_DNLD_OVER 0x0004 + +#define IF_CS_H_INT_CAUSE 0x00000002 +#define IF_CS_H_IC_TX_OVER 0x0001 +#define IF_CS_H_IC_RX_OVER 0x0002 +#define IF_CS_H_IC_DNLD_OVER 0x0004 +#define IF_CS_H_IC_HOST_EVENT 0x0008 +#define IF_CS_H_IC_MASK 0x001f + +#define IF_CS_H_INT_MASK 0x00000004 +#define IF_CS_H_IM_MASK 0x001f + +#define IF_CS_H_WRITE_LEN 0x00000014 + +#define IF_CS_H_WRITE 0x00000016 + +#define IF_CS_H_CMD_LEN 0x00000018 + +#define IF_CS_H_CMD 0x0000001A + +#define IF_CS_C_READ_LEN 0x00000024 + +#define IF_CS_H_READ 0x00000010 + +/* Card control registers and their bit definitions */ + +#define IF_CS_C_STATUS 0x00000020 +#define IF_CS_C_S_TX_DNLD_RDY 0x0001 +#define IF_CS_C_S_RX_UPLD_RDY 0x0002 +#define IF_CS_C_S_CMD_DNLD_RDY 0x0004 +#define IF_CS_C_S_CMD_UPLD_RDY 0x0008 +#define IF_CS_C_S_CARDEVENT 0x0010 +#define IF_CS_C_S_MASK 0x001f +#define IF_CS_C_S_STATUS_MASK 0x7f00 +/* The following definitions should be the same as the MRVDRV_ ones */ + +#if MRVDRV_CMD_DNLD_RDY != IF_CS_C_S_CMD_DNLD_RDY +#error MRVDRV_CMD_DNLD_RDY and IF_CS_C_S_CMD_DNLD_RDY not in sync +#endif +#if MRVDRV_CMD_UPLD_RDY != IF_CS_C_S_CMD_UPLD_RDY +#error MRVDRV_CMD_UPLD_RDY and IF_CS_C_S_CMD_UPLD_RDY not in sync +#endif +#if MRVDRV_CARDEVENT != IF_CS_C_S_CARDEVENT +#error MRVDRV_CARDEVENT and IF_CS_C_S_CARDEVENT not in sync +#endif + +#define IF_CS_C_INT_CAUSE 0x00000022 +#define IF_CS_C_IC_MASK 0x001f + +#define IF_CS_C_SQ_READ_LOW 0x00000028 +#define IF_CS_C_SQ_HELPER_OK 0x10 + +#define IF_CS_C_CMD_LEN 0x00000030 + +#define IF_CS_C_CMD 0x00000012 + +#define IF_CS_SCRATCH 0x0000003F + + + +/********************************************************************/ +/* Interrupts */ +/********************************************************************/ + +static inline void if_cs_enable_ints(struct if_cs_card *card) +{ + lbs_deb_enter(LBS_DEB_CS); + if_cs_write16(card, IF_CS_H_INT_MASK, 0); +} + +static inline void if_cs_disable_ints(struct if_cs_card *card) +{ + lbs_deb_enter(LBS_DEB_CS); + if_cs_write16(card, IF_CS_H_INT_MASK, IF_CS_H_IM_MASK); +} + +static irqreturn_t if_cs_interrupt(int irq, void *data) +{ + struct if_cs_card *card = (struct if_cs_card *)data; + u16 int_cause; + + lbs_deb_enter(LBS_DEB_CS); + + int_cause = if_cs_read16(card, IF_CS_C_INT_CAUSE); + switch (int_cause) { + case 0x0000: + /* not for us */ + return IRQ_NONE; + case 0xffff: + /* if one reads junk, then probably the card was removed */ + card->priv->adapter->surpriseremoved = 1; + break; + case IF_CS_H_IC_TX_OVER: + if (card->priv->adapter->connect_status == LIBERTAS_CONNECTED) + netif_wake_queue(card->priv->dev); + /* fallthrought */ + default: + /* clear interrupt */ + if_cs_write16(card, IF_CS_C_INT_CAUSE, int_cause & IF_CS_C_IC_MASK); + if_cs_disable_ints(card); + } + + libertas_interrupt(card->priv->dev); + + return IRQ_HANDLED; +} + + + + +/********************************************************************/ +/* I/O */ +/********************************************************************/ + +/* + * Called from if_cs_host_to_card to send a command to the hardware + */ +static int if_cs_send_cmd(wlan_private *priv, u8 *buf, u16 nb) +{ + struct if_cs_card *card = (struct if_cs_card *)priv->card; + int ret = -1; + int loops = 0; + + lbs_deb_enter(LBS_DEB_CS); + + /* Is hardware ready? */ + while (1) { + u16 val = if_cs_read16(card, IF_CS_C_STATUS); + if (val & IF_CS_C_S_CMD_DNLD_RDY) + break; + if (++loops > 100) { + lbs_pr_err("card not ready for commands\n"); + goto done; + } + mdelay(1); + } + + if_cs_write16(card, IF_CS_H_CMD_LEN, nb); + + if_cs_write16_rep(card, IF_CS_H_CMD, buf, nb / 2); + /* Are we supposed to transfer an odd amount of bytes? */ + if (nb & 1) + if_cs_write8(card, IF_CS_H_CMD, buf[nb-1]); + + /* "Assert the download over interrupt command in the Host + * status register" */ + if_cs_write16(card, IF_CS_H_STATUS, IF_CS_H_STATUS_DNLD_OVER); + + /* "Assert the download over interrupt command in the Card + * interrupt case register" */ + if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_DNLD_OVER); + ret = 0; + +done: + lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret); + return ret; +} + + +/* + * Called from if_cs_host_to_card to send a data to the hardware + */ +static void if_cs_send_data(wlan_private *priv, u8 *buf, u16 nb) +{ + struct if_cs_card *card = (struct if_cs_card *)priv->card; + + lbs_deb_enter(LBS_DEB_CS); + + if_cs_write16(card, IF_CS_H_WRITE_LEN, nb); + + /* write even number of bytes, then odd byte if necessary */ + if_cs_write16_rep(card, IF_CS_H_WRITE, buf, nb / 2); + if (nb & 1) + if_cs_write8(card, IF_CS_H_WRITE, buf[nb-1]); + + if_cs_write16(card, IF_CS_H_STATUS, IF_CS_H_STATUS_TX_OVER); + if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_STATUS_TX_OVER); + + lbs_deb_leave(LBS_DEB_CS); +} + + +/* + * Get the command result out of the card. + */ +static int if_cs_receive_cmdres(wlan_private *priv, u8* data, u32 *len) +{ + int ret = -1; + u16 val; + + lbs_deb_enter(LBS_DEB_CS); + + /* is hardware ready? */ + val = if_cs_read16(priv->card, IF_CS_C_STATUS); + if ((val & IF_CS_C_S_CMD_UPLD_RDY) == 0) { + lbs_pr_err("card not ready for CMD\n"); + goto out; + } + + *len = if_cs_read16(priv->card, IF_CS_C_CMD_LEN); + if ((*len == 0) || (*len > MRVDRV_SIZE_OF_CMD_BUFFER)) { + lbs_pr_err("card cmd buffer has invalid # of bytes (%d)\n", *len); + goto out; + } + + /* read even number of bytes, then odd byte if necessary */ + if_cs_read16_rep(priv->card, IF_CS_C_CMD, data, *len/sizeof(u16)); + if (*len & 1) + data[*len-1] = if_cs_read8(priv->card, IF_CS_C_CMD); + + ret = 0; +out: + lbs_deb_leave_args(LBS_DEB_CS, "ret %d, len %d", ret, *len); + return ret; +} + + +static struct sk_buff *if_cs_receive_data(wlan_private *priv) +{ + struct sk_buff *skb = NULL; + u16 len; + u8 *data; + + lbs_deb_enter(LBS_DEB_CS); + + len = if_cs_read16(priv->card, IF_CS_C_READ_LEN); + if (len == 0 || len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) { + lbs_pr_err("card data buffer has invalid # of bytes (%d)\n", len); + priv->stats.rx_dropped++; + printk(KERN_INFO "##HS %s:%d TODO\n", __FUNCTION__, __LINE__); + goto dat_err; + } + + //TODO: skb = dev_alloc_skb(len+ETH_FRAME_LEN+MRVDRV_SNAP_HEADER_LEN+EXTRA_LEN); + skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE); + if (!skb) + goto out; + data = skb_put(skb, len); + + /* read even number of bytes, then odd byte if necessary */ + if_cs_read16_rep(priv->card, IF_CS_H_READ, data, len/sizeof(u16)); + if (len & 1) + data[len-1] = if_cs_read8(priv->card, IF_CS_H_READ); + +dat_err: + if_cs_write16(priv->card, IF_CS_H_STATUS, IF_CS_H_STATUS_RX_OVER); + if_cs_write16(priv->card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_RX_OVER); + +out: + lbs_deb_leave_args(LBS_DEB_CS, "ret %p", skb); + return skb; +} + + + +/********************************************************************/ +/* Firmware */ +/********************************************************************/ + +/* + * Tries to program the helper firmware. + * + * Return 0 on success + */ +static int if_cs_prog_helper(struct if_cs_card *card) +{ + int ret = 0; + int sent = 0; + u8 scratch; + const struct firmware *fw; + + lbs_deb_enter(LBS_DEB_CS); + + scratch = if_cs_read8(card, IF_CS_SCRATCH); + + /* "If the value is 0x5a, the firmware is already + * downloaded successfully" + */ + if (scratch == 0x5a) + goto done; + + /* "If the value is != 00, it is invalid value of register */ + if (scratch != 0x00) { + ret = -ENODEV; + goto done; + } + + /* TODO: make firmware file configurable */ + ret = request_firmware(&fw, "libertas_cs_helper.fw", + &handle_to_dev(card->p_dev)); + if (ret) { + lbs_pr_err("can't load helper firmware\n"); + ret = -ENODEV; + goto done; + } + lbs_deb_cs("helper size %d\n", fw->size); + + /* "Set the 5 bytes of the helper image to 0" */ + /* Not needed, this contains an ARM branch instruction */ + + for (;;) { + /* "the number of bytes to send is 256" */ + int count = 256; + int remain = fw->size - sent; + + if (remain < count) + count = remain; + /* printk(KERN_INFO "//HS %d loading %d of %d bytes\n", + __LINE__, sent, fw->size); */ + + /* "write the number of bytes to be sent to the I/O Command + * write length register" */ + if_cs_write16(card, IF_CS_H_CMD_LEN, count); + + /* "write this to I/O Command port register as 16 bit writes */ + if (count) + if_cs_write16_rep(card, IF_CS_H_CMD, + &fw->data[sent], + count >> 1); + + /* "Assert the download over interrupt command in the Host + * status register" */ + if_cs_write8(card, IF_CS_H_STATUS, IF_CS_H_STATUS_DNLD_OVER); + + /* "Assert the download over interrupt command in the Card + * interrupt case register" */ + if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_DNLD_OVER); + + /* "The host polls the Card Status register ... for 50 ms before + declaring a failure */ + ret = if_cs_poll_while_fw_download(card, IF_CS_C_STATUS, + IF_CS_C_S_CMD_DNLD_RDY); + if (ret < 0) { + lbs_pr_err("can't download helper at 0x%x, ret %d\n", + sent, ret); + goto done; + } + + if (count == 0) + break; + + sent += count; + } + + release_firmware(fw); + ret = 0; + +done: + lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret); + return ret; +} + + +static int if_cs_prog_real(struct if_cs_card *card) +{ + const struct firmware *fw; + int ret = 0; + int retry = 0; + int len = 0; + int sent; + + lbs_deb_enter(LBS_DEB_CS); + + /* TODO: make firmware file configurable */ + ret = request_firmware(&fw, "libertas_cs.fw", + &handle_to_dev(card->p_dev)); + if (ret) { + lbs_pr_err("can't load firmware\n"); + ret = -ENODEV; + goto done; + } + lbs_deb_cs("fw size %d\n", fw->size); + + ret = if_cs_poll_while_fw_download(card, IF_CS_C_SQ_READ_LOW, IF_CS_C_SQ_HELPER_OK); + if (ret < 0) { + int i; + lbs_pr_err("helper firmware doesn't answer\n"); + for (i = 0; i < 0x50; i += 2) + printk(KERN_INFO "## HS %02x: %04x\n", + i, if_cs_read16(card, i)); + goto err_release; + } + + for (sent = 0; sent < fw->size; sent += len) { + len = if_cs_read16(card, IF_CS_C_SQ_READ_LOW); + /* printk(KERN_INFO "//HS %d loading %d of %d bytes\n", + __LINE__, sent, fw->size); */ + if (len & 1) { + retry++; + lbs_pr_info("odd, need to retry this firmware block\n"); + } else { + retry = 0; + } + + if (retry > 20) { + lbs_pr_err("could not download firmware\n"); + ret = -ENODEV; + goto err_release; + } + if (retry) { + sent -= len; + } + + + if_cs_write16(card, IF_CS_H_CMD_LEN, len); + + if_cs_write16_rep(card, IF_CS_H_CMD, + &fw->data[sent], + (len+1) >> 1); + if_cs_write8(card, IF_CS_H_STATUS, IF_CS_H_STATUS_DNLD_OVER); + if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_DNLD_OVER); + + ret = if_cs_poll_while_fw_download(card, IF_CS_C_STATUS, + IF_CS_C_S_CMD_DNLD_RDY); + if (ret < 0) { + lbs_pr_err("can't download firmware at 0x%x\n", sent); + goto err_release; + } + } + + ret = if_cs_poll_while_fw_download(card, IF_CS_SCRATCH, 0x5a); + if (ret < 0) { + lbs_pr_err("firmware download failed\n"); + goto err_release; + } + + ret = 0; + goto done; + + +err_release: + release_firmware(fw); + +done: + lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret); + return ret; +} + + + +/********************************************************************/ +/* Callback functions for libertas.ko */ +/********************************************************************/ + +static int if_cs_register_dev(wlan_private *priv) +{ + struct if_cs_card *card = (struct if_cs_card *)priv->card; + + lbs_deb_enter(LBS_DEB_CS); + + card->priv = priv; + + return 0; +} + + +static int if_cs_unregister_dev(wlan_private *priv) +{ + lbs_deb_enter(LBS_DEB_CS); + + /* + * Nothing special here. Because the device's power gets turned off + * anyway, there's no need to send a RESET command like in if_usb.c + */ + + return 0; +} + + +/* + * This callback is a dummy. The reason is that the USB code needs + * to have various things set up in order to be able to download the + * firmware. That's not needed in our case. + * + * On the contrary, if libertas_add_card() has been called and we're + * then later called via libertas_activate_card(), but without a valid + * firmware, then it's quite tedious to tear down the half-installed + * card. Therefore, we download the firmware before calling adding/ + * activating the card in the first place. If that doesn't work, we + * won't call into libertas.ko at all. + */ + +static int if_cs_prog_firmware(wlan_private *priv) +{ + priv->adapter->fw_ready = 1; + return 0; +} + + +/* Send commands or data packets to the card */ +static int if_cs_host_to_card(wlan_private *priv, u8 type, u8 *buf, u16 nb) +{ + int ret = -1; + + lbs_deb_enter_args(LBS_DEB_CS, "type %d, bytes %d", type, nb); + + switch (type) { + case MVMS_DAT: + priv->dnld_sent = DNLD_CMD_SENT; + if_cs_send_data(priv, buf, nb); + ret = 0; + break; + case MVMS_CMD: + ret = if_cs_send_cmd(priv, buf, nb); + break; + default: + lbs_pr_err("%s: unsupported type %d\n", __FUNCTION__, type); + } + + lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret); + return ret; +} + + +static int if_cs_get_int_status(wlan_private *priv, u8 *ireg) +{ + struct if_cs_card *card = (struct if_cs_card *)priv->card; + //wlan_adapter *adapter = priv->adapter; + int ret = 0; + u16 int_cause; + u8 *cmdbuf; + *ireg = 0; + + lbs_deb_enter(LBS_DEB_CS); + + if (priv->adapter->surpriseremoved) + goto out; + + int_cause = if_cs_read16(card, IF_CS_C_INT_CAUSE) & IF_CS_C_IC_MASK; + if_cs_write16(card, IF_CS_C_INT_CAUSE, int_cause); + + *ireg = if_cs_read16(card, IF_CS_C_STATUS) & IF_CS_C_S_MASK; + if_cs_enable_ints(card); + + if (!*ireg) + goto sbi_get_int_status_exit; + +sbi_get_int_status_exit: + + /* is there a data packet for us? */ + if (*ireg & IF_CS_C_S_RX_UPLD_RDY) { + struct sk_buff *skb = if_cs_receive_data(priv); + libertas_process_rxed_packet(priv, skb); + *ireg &= ~IF_CS_C_S_RX_UPLD_RDY; + } + + if (*ireg & IF_CS_C_S_TX_DNLD_RDY) { + priv->dnld_sent = DNLD_RES_RECEIVED; + } + + /* Card has a command result for us */ + if (*ireg & IF_CS_C_S_CMD_UPLD_RDY) { + spin_lock(&priv->adapter->driver_lock); + if (!priv->adapter->cur_cmd) { + cmdbuf = priv->upld_buf; + priv->adapter->hisregcpy &= ~IF_CS_C_S_RX_UPLD_RDY; + } else { + cmdbuf = priv->adapter->cur_cmd->bufvirtualaddr; + } + + ret = if_cs_receive_cmdres(priv, cmdbuf, &priv->upld_len); + spin_unlock(&priv->adapter->driver_lock); + if (ret < 0) + lbs_pr_err("could not receive cmd from card\n"); + } + +out: + lbs_deb_leave_args(LBS_DEB_CS, "ret %d, ireg 0x%x, hisregcpy 0x%x", ret, *ireg, priv->adapter->hisregcpy); + return ret; +} + + +static int if_cs_read_event_cause(wlan_private *priv) +{ + lbs_deb_enter(LBS_DEB_CS); + + priv->adapter->eventcause = (if_cs_read16(priv->card, IF_CS_C_STATUS) & IF_CS_C_S_STATUS_MASK) >> 5; + if_cs_write16(priv->card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_HOST_EVENT); + + return 0; +} + + + +/********************************************************************/ +/* Card Services */ +/********************************************************************/ + +/* + * After a card is removed, if_cs_release() will unregister the + * device, and release the PCMCIA configuration. If the device is + * still open, this will be postponed until it is closed. + */ +static void if_cs_release(struct pcmcia_device *p_dev) +{ + struct if_cs_card *card = p_dev->priv; + + lbs_deb_enter(LBS_DEB_CS); + + pcmcia_disable_device(p_dev); + free_irq(p_dev->irq.AssignedIRQ, card); + if (card->iobase) + ioport_unmap(card->iobase); + + lbs_deb_leave(LBS_DEB_CS); +} + + +/* + * This creates an "instance" of the driver, allocating local data + * structures for one device. The device is registered with Card + * Services. + * + * The dev_link structure is initialized, but we don't actually + * configure the card at this point -- we wait until we receive a card + * insertion event. + */ +static int if_cs_probe(struct pcmcia_device *p_dev) +{ + int ret = -ENOMEM; + wlan_private *priv; + struct if_cs_card *card; + /* CIS parsing */ + tuple_t tuple; + cisparse_t parse; + cistpl_cftable_entry_t *cfg = &parse.cftable_entry; + cistpl_io_t *io = &cfg->io; + u_char buf[64]; + + lbs_deb_enter(LBS_DEB_CS); + + card = kzalloc(sizeof(struct if_cs_card), GFP_KERNEL); + if (!card) { + lbs_pr_err("error in kzalloc\n"); + goto out; + } + card->p_dev = p_dev; + p_dev->priv = card; + + p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; + p_dev->irq.Handler = NULL; + p_dev->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; + + p_dev->conf.Attributes = 0; + p_dev->conf.IntType = INT_MEMORY_AND_IO; + + tuple.Attributes = 0; + tuple.TupleData = buf; + tuple.TupleDataMax = sizeof(buf); + tuple.TupleOffset = 0; + + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + if ((ret = pcmcia_get_first_tuple(p_dev, &tuple)) != 0 || + (ret = pcmcia_get_tuple_data(p_dev, &tuple)) != 0 || + (ret = pcmcia_parse_tuple(p_dev, &tuple, &parse)) != 0) + { + lbs_pr_err("error in pcmcia_get_first_tuple etc\n"); + goto out1; + } + + p_dev->conf.ConfigIndex = cfg->index; + + /* Do we need to allocate an interrupt? */ + if (cfg->irq.IRQInfo1) { + p_dev->conf.Attributes |= CONF_ENABLE_IRQ; + } + + /* IO window settings */ + if (cfg->io.nwin != 1) { + lbs_pr_err("wrong CIS (check number of IO windows)\n"); + ret = -ENODEV; + goto out1; + } + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + p_dev->io.BasePort1 = io->win[0].base; + p_dev->io.NumPorts1 = io->win[0].len; + + /* This reserves IO space but doesn't actually enable it */ + ret = pcmcia_request_io(p_dev, &p_dev->io); + if (ret) { + lbs_pr_err("error in pcmcia_request_io\n"); + goto out1; + } + + /* + * Allocate an interrupt line. Note that this does not assign + * a handler to the interrupt, unless the 'Handler' member of + * the irq structure is initialized. + */ + if (p_dev->conf.Attributes & CONF_ENABLE_IRQ) { + ret = pcmcia_request_irq(p_dev, &p_dev->irq); + if (ret) { + lbs_pr_err("error in pcmcia_request_irq\n"); + goto out1; + } + } + + /* Initialize io access */ + card->iobase = ioport_map(p_dev->io.BasePort1, p_dev->io.NumPorts1); + if (!card->iobase) { + lbs_pr_err("error in ioport_map\n"); + ret = -EIO; + goto out1; + } + + /* + * This actually configures the PCMCIA socket -- setting up + * the I/O windows and the interrupt mapping, and putting the + * card and host interface into "Memory and IO" mode. + */ + ret = pcmcia_request_configuration(p_dev, &p_dev->conf); + if (ret) { + lbs_pr_err("error in pcmcia_request_configuration\n"); + goto out2; + } + + /* Finally, report what we've done */ + lbs_deb_cs("irq %d, io 0x%04x-0x%04x\n", + p_dev->irq.AssignedIRQ, p_dev->io.BasePort1, + p_dev->io.BasePort1 + p_dev->io.NumPorts1 - 1); + + if_cs_enable_ints(card); + + /* Load the firmware early, before calling into libertas.ko */ + ret = if_cs_prog_helper(card); + if (ret == 0) + ret = if_cs_prog_real(card); + if (ret) + goto out2; + + /* Make this card known to the libertas driver */ + priv = libertas_add_card(card, &p_dev->dev); + if (!priv) { + ret = -ENOMEM; + goto out2; + } + + /* Store pointers to our call-back functions */ + priv->card = card; + priv->hw_register_dev = if_cs_register_dev; + priv->hw_unregister_dev = if_cs_unregister_dev; + priv->hw_prog_firmware = if_cs_prog_firmware; + priv->hw_host_to_card = if_cs_host_to_card; + priv->hw_get_int_status = if_cs_get_int_status; + priv->hw_read_event_cause = if_cs_read_event_cause; + + /* Now actually get the IRQ */ + ret = request_irq(p_dev->irq.AssignedIRQ, if_cs_interrupt, + IRQF_SHARED, DRV_NAME, card); + if (ret) { + lbs_pr_err("error in request_irq\n"); + goto out3; + } + + /* And finally bring the card up */ + if (libertas_activate_card(priv) != 0) { + lbs_pr_err("could not activate card\n"); + goto out3; + } + + ret = 0; + goto out; + +out3: + libertas_remove_card(priv); +out2: + ioport_unmap(card->iobase); +out1: + pcmcia_disable_device(p_dev); +out: + lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret); + return ret; +} + + +/* + * This deletes a driver "instance". The device is de-registered with + * Card Services. If it has been released, all local data structures + * are freed. Otherwise, the structures will be freed when the device + * is released. + */ +static void if_cs_detach(struct pcmcia_device *p_dev) +{ + struct if_cs_card *card = p_dev->priv; + + lbs_deb_enter(LBS_DEB_CS); + + libertas_remove_card(card->priv); + if_cs_release(p_dev); + kfree(card); + + lbs_deb_leave(LBS_DEB_CS); +} + + + +/********************************************************************/ +/* Module initialization */ +/********************************************************************/ + +static struct pcmcia_device_id if_cs_ids[] = { + PCMCIA_DEVICE_MANF_CARD(0x02df, 0x8103), + PCMCIA_DEVICE_NULL, +}; +MODULE_DEVICE_TABLE(pcmcia, if_cs_ids); + + +static struct pcmcia_driver libertas_driver = { + .owner = THIS_MODULE, + .drv = { + .name = DRV_NAME, + }, + .probe = if_cs_probe, + .remove = if_cs_detach, + .id_table = if_cs_ids, +}; + + +static int __init if_cs_init(void) +{ + int ret; + + lbs_deb_enter(LBS_DEB_CS); + ret = pcmcia_register_driver(&libertas_driver); + lbs_deb_leave(LBS_DEB_CS); + return ret; +} + + +static void __exit if_cs_exit(void) +{ + lbs_deb_enter(LBS_DEB_CS); + pcmcia_unregister_driver(&libertas_driver); + lbs_deb_leave(LBS_DEB_CS); +} + + +module_init(if_cs_init); +module_exit(if_cs_exit); -- cgit v1.2.3-70-g09d2 From 4d4ce1ad02f02e593086fabdad69953ecbd99d9c Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 13:04:28 -0400 Subject: [PATCH] libertas: remove unused adapter->prev_XXXX variables There were just used in some debug output, but nowhere else. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmdresp.c | 9 --------- drivers/net/wireless/libertas/dev.h | 4 ---- 2 files changed, 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index bf672f51f16..8e99c2de183 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -65,18 +65,9 @@ void libertas_mac_event_disconnected(wlan_private * priv) escape_essid(adapter->curbssparams.ssid, adapter->curbssparams.ssid_len), adapter->curbssparams.ssid_len); - lbs_deb_cmd("previous SSID '%s', length %u\n", - escape_essid(adapter->prev_ssid, adapter->prev_ssid_len), - adapter->prev_ssid_len); adapter->connect_status = LIBERTAS_DISCONNECTED; - /* Save previous SSID and BSSID for possible reassociation */ - memcpy(&adapter->prev_ssid, &adapter->curbssparams.ssid, - IW_ESSID_MAX_SIZE); - adapter->prev_ssid_len = adapter->curbssparams.ssid_len; - memcpy(adapter->prev_bssid, adapter->curbssparams.bssid, ETH_ALEN); - /* Clear out associated SSID and BSSID since connection is * no longer valid. */ diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 7c565cbf8cc..7c0ee0f9184 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -257,10 +257,6 @@ struct _wlan_adapter { /* IW_MODE_* */ u8 mode; - u8 prev_ssid[IW_ESSID_MAX_SIZE + 1]; - u8 prev_ssid_len; - u8 prev_bssid[ETH_ALEN]; - /* Scan results list */ struct list_head network_list; struct list_head network_free_list; -- cgit v1.2.3-70-g09d2 From fdde7084e033263f48d26d5b24ecf626aed29b5b Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 13:05:08 -0400 Subject: [PATCH] libertas: remove adapter->{rx,tx}antenna There was nowhere any code that used the values of those variables. This patch also removes two static functions that are now unused. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 25 ------------------------- drivers/net/wireless/libertas/cmdresp.c | 24 ------------------------ drivers/net/wireless/libertas/dev.h | 6 ------ drivers/net/wireless/libertas/main.c | 2 -- 4 files changed, 57 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index d3402e1b760..2a5defe011e 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -570,26 +570,6 @@ static int wlan_cmd_802_11_rf_tx_power(wlan_private * priv, return 0; } -static int wlan_cmd_802_11_rf_antenna(wlan_private * priv, - struct cmd_ds_command *cmd, - u16 cmd_action, void *pdata_buf) -{ - struct cmd_ds_802_11_rf_antenna *rant = &cmd->params.rant; - - lbs_deb_enter(LBS_DEB_CMD); - cmd->command = cpu_to_le16(CMD_802_11_RF_ANTENNA); - cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rf_antenna) + - S_DS_GEN); - - rant->action = cpu_to_le16(cmd_action); - if ((cmd_action == CMD_ACT_SET_RX) || (cmd_action == CMD_ACT_SET_TX)) { - rant->antennamode = cpu_to_le16((u16) (*(u32 *) pdata_buf)); - } - - lbs_deb_leave(LBS_DEB_CMD); - return 0; -} - static int wlan_cmd_802_11_rate_adapt_rateset(wlan_private * priv, struct cmd_ds_command *cmd, u16 cmd_action) @@ -1252,11 +1232,6 @@ int libertas_prepare_and_send_command(wlan_private * priv, ret = wlan_cmd_802_11_radio_control(priv, cmdptr, cmd_action); break; - case CMD_802_11_RF_ANTENNA: - ret = wlan_cmd_802_11_rf_antenna(priv, cmdptr, - cmd_action, pdata_buf); - break; - case CMD_802_11_DATA_RATE: ret = wlan_cmd_802_11_data_rate(priv, cmdptr, cmd_action); break; diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 8e99c2de183..affb1eeb6a5 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -383,27 +383,6 @@ static int wlan_ret_802_11_rf_tx_power(wlan_private * priv, return 0; } -static int wlan_ret_802_11_rf_antenna(wlan_private * priv, - struct cmd_ds_command *resp) -{ - struct cmd_ds_802_11_rf_antenna *pAntenna = &resp->params.rant; - wlan_adapter *adapter = priv->adapter; - u16 action = le16_to_cpu(pAntenna->action); - - lbs_deb_enter(LBS_DEB_CMD); - if (action == CMD_ACT_GET_RX) - adapter->rxantennamode = le16_to_cpu(pAntenna->antennamode); - - if (action == CMD_ACT_GET_TX) - adapter->txantennamode = le16_to_cpu(pAntenna->antennamode); - - lbs_deb_cmd("RF_ANT_RESP: action 0x%x, mode 0x%04x\n", - action, le16_to_cpu(pAntenna->antennamode)); - - lbs_deb_leave(LBS_DEB_CMD); - return 0; -} - static int wlan_ret_802_11_rate_adapt_rateset(wlan_private * priv, struct cmd_ds_command *resp) { @@ -620,9 +599,6 @@ static inline int handle_cmd_response(u16 respcmd, spin_unlock_irqrestore(&adapter->driver_lock, flags); break; - case CMD_RET(CMD_802_11_RF_ANTENNA): - ret = wlan_ret_802_11_rf_antenna(priv, resp); - break; case CMD_RET(CMD_MAC_MULTICAST_ADR): case CMD_RET(CMD_MAC_CONTROL): diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 7c0ee0f9184..765c0c4f641 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -284,9 +284,6 @@ struct _wlan_adapter { /** control G rates */ u8 adhoc_grate_enabled; - u32 txantenna; - u32 rxantenna; - u32 fragthsd; u32 rtsthsd; @@ -337,9 +334,6 @@ struct _wlan_adapter { u8 wpa_ie[MAX_WPA_IE_LEN]; u8 wpa_ie_len; - u16 rxantennamode; - u16 txantennamode; - /** Requested Signal Strength*/ u16 bcn_avg_factor; u16 data_avg_factor; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 1b6b09d5f97..5b4a1343559 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1049,8 +1049,6 @@ static void wlan_init_adapter(wlan_private * priv) CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON; adapter->radioon = RADIO_ON; - adapter->txantenna = RF_ANTENNA_2; - adapter->rxantenna = RF_ANTENNA_AUTO; adapter->auto_rate = 1; adapter->cur_rate = 0; -- cgit v1.2.3-70-g09d2 From 6e22a855b27ddc0725c134cc428ee668e56ac9f8 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 13:05:32 -0400 Subject: [PATCH] libertas: remove adapter->prescan The value 1 was assigned to it and there was nowhere any code that would have changed that to 0. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/assoc.c | 6 ++---- drivers/net/wireless/libertas/dev.h | 1 - drivers/net/wireless/libertas/main.c | 2 -- 3 files changed, 2 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index 5fdc96f289b..ffeec2fa60a 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -57,10 +57,8 @@ static int assoc_helper_essid(wlan_private *priv, lbs_deb_assoc("New SSID requested: '%s'\n", escape_essid(assoc_req->ssid, assoc_req->ssid_len)); if (assoc_req->mode == IW_MODE_INFRA) { - if (adapter->prescan) { - libertas_send_specific_ssid_scan(priv, assoc_req->ssid, - assoc_req->ssid_len, 0); - } + libertas_send_specific_ssid_scan(priv, assoc_req->ssid, + assoc_req->ssid_len, 0); bss = libertas_find_ssid_in_list(adapter, assoc_req->ssid, assoc_req->ssid_len, NULL, IW_MODE_INFRA, channel); diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 765c0c4f641..83876a3c41c 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -288,7 +288,6 @@ struct _wlan_adapter { u32 rtsthsd; u16 listeninterval; - u16 prescan; u8 txretrycount; /** Tx-related variables (for single packet tx) */ diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 5b4a1343559..e354ebbca4b 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1037,8 +1037,6 @@ static void wlan_init_adapter(wlan_private * priv) mutex_init(&adapter->lock); - adapter->prescan = 1; - memset(&adapter->curbssparams, 0, sizeof(adapter->curbssparams)); adapter->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL; -- cgit v1.2.3-70-g09d2 From e2aa334bee4ae9fe27f26b0732c0443d2f11a8af Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 13:05:53 -0400 Subject: [PATCH] libertas: remove adapter->scanprobes The variable was initialized to 0 and nowhere else to anything different. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/dev.h | 1 - drivers/net/wireless/libertas/main.c | 2 -- drivers/net/wireless/libertas/scan.c | 5 ++--- 3 files changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 83876a3c41c..1dcfb05f544 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -375,7 +375,6 @@ struct _wlan_adapter { struct wlan_offset_value offsetvalue; struct cmd_ds_802_11_get_log logmsg; - u16 scanprobes; u32 pkttxctrl; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index e354ebbca4b..1d439cd3f43 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -998,8 +998,6 @@ static void wlan_init_adapter(wlan_private * priv) wlan_adapter *adapter = priv->adapter; int i; - adapter->scanprobes = 0; - adapter->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR; adapter->data_avg_factor = DEFAULT_DATA_AVG_FACTOR; diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index f471157c02d..7e4b0ab108d 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -416,8 +416,7 @@ wlan_scan_setup_scan_config(wlan_private * priv, scanmode); /* Set the number of probes to send, use adapter setting if unset */ - numprobes = (puserscanin->numprobes ? puserscanin->numprobes : - adapter->scanprobes); + numprobes = puserscanin->numprobes ? puserscanin->numprobes : 0; /* * Set the BSSID filter to the incoming configuration, @@ -450,7 +449,7 @@ wlan_scan_setup_scan_config(wlan_private * priv, } } else { pscancfgout->bsstype = adapter->scanmode; - numprobes = adapter->scanprobes; + numprobes = 0; } /* If the input config or adapter has the number of Probes set, add tlv */ -- cgit v1.2.3-70-g09d2 From fcff0e0856351b201016cd9267cadcf6a8e988d5 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 13:06:11 -0400 Subject: [PATCH] libertas: remove adapter->pkttxctrl The variable was initialized to 0 and nowhere else changed, so basically the per-packet TX control wasn't used. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/dev.h | 2 -- drivers/net/wireless/libertas/main.c | 1 - drivers/net/wireless/libertas/tx.c | 5 ----- 3 files changed, 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 1dcfb05f544..aad92ded730 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -376,8 +376,6 @@ struct _wlan_adapter { struct cmd_ds_802_11_get_log logmsg; - u32 pkttxctrl; - u16 txrate; u32 linkmode; u32 radiomode; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 1d439cd3f43..da418dbe886 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1067,7 +1067,6 @@ static void wlan_init_adapter(wlan_private * priv) adapter->intcounter = 0; adapter->currenttxskb = NULL; - adapter->pkttxctrl = 0; memset(&adapter->tx_queue_ps, 0, NR_TX_QUEUE*sizeof(struct sk_buff*)); adapter->tx_queue_idx = 0; diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c index 56d84027ec2..bb6e17506a4 100644 --- a/drivers/net/wireless/libertas/tx.c +++ b/drivers/net/wireless/libertas/tx.c @@ -58,7 +58,6 @@ static u32 convert_radiotap_rate_to_mv(u8 rate) */ static int SendSinglePacket(wlan_private * priv, struct sk_buff *skb) { - wlan_adapter *adapter = priv->adapter; int ret = 0; struct txpd localtxpd; struct txpd *plocaltxpd = &localtxpd; @@ -86,9 +85,6 @@ static int SendSinglePacket(wlan_private * priv, struct sk_buff *skb) /* offset of actual data */ plocaltxpd->tx_packet_location = cpu_to_le32(sizeof(struct txpd)); - /* TxCtrl set by user or default */ - plocaltxpd->tx_control = cpu_to_le32(adapter->pkttxctrl); - p802x_hdr = skb->data; if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) { @@ -99,7 +95,6 @@ static int SendSinglePacket(wlan_private * priv, struct sk_buff *skb) new_rate = convert_radiotap_rate_to_mv(pradiotap_hdr->rate); if (new_rate != 0) { /* use new tx_control[4:0] */ - new_rate |= (adapter->pkttxctrl & ~0x1f); plocaltxpd->tx_control = cpu_to_le32(new_rate); } -- cgit v1.2.3-70-g09d2 From b20c520763a6fe1aabde27f6ba017a67f22f90d5 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 13:06:54 -0400 Subject: [PATCH] libertas: fix WEXT quality reporting Found by Ronak and others at Marvell. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/wext.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index e8c0629f9a4..7d14f9c2aff 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -949,7 +949,7 @@ static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev) priv->wstats.discard.misc = le16_to_cpu(adapter->logmsg.ackfailure); /* Calculate quality */ - priv->wstats.qual.qual = max(quality, (u32)100); + priv->wstats.qual.qual = min_t(u32, quality, 100); priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; stats_valid = 1; -- cgit v1.2.3-70-g09d2 From cad9d9b17a4ab80da1593de004a1163b359de268 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 13:07:15 -0400 Subject: [PATCH] libertas: remove adapter->txrate The value of txrate was only set by a CMD_802_11_TX_RATE_QUERY command, but there was no code in the driver that ever issued this command. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 7 ------- drivers/net/wireless/libertas/cmdresp.c | 3 --- drivers/net/wireless/libertas/dev.h | 1 - drivers/net/wireless/libertas/wext.c | 2 +- 4 files changed, 1 insertion(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 2a5defe011e..0da013f3b0d 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -1368,13 +1368,6 @@ int libertas_prepare_and_send_command(wlan_private * priv, S_DS_GEN); ret = 0; break; - case CMD_802_11_TX_RATE_QUERY: - cmdptr->command = cpu_to_le16(CMD_802_11_TX_RATE_QUERY); - cmdptr->size = cpu_to_le16(sizeof(struct cmd_tx_rate_query) + - S_DS_GEN); - adapter->txrate = 0; - ret = 0; - break; default: lbs_deb_host("PREP_CMD: unknown command 0x%04x\n", cmd_no); ret = -1; diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index affb1eeb6a5..e91d819555e 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -702,9 +702,6 @@ static inline int handle_cmd_response(u16 respcmd, memcpy(adapter->cur_cmd->pdata_buf, &resp->params.mesh, sizeof(resp->params.mesh)); break; - case CMD_RET(CMD_802_11_TX_RATE_QUERY): - priv->adapter->txrate = resp->params.txrate.txrate; - break; default: lbs_deb_host("CMD_RESP: unknown cmd response 0x%04x\n", resp->command); diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index aad92ded730..9e18f012333 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -376,7 +376,6 @@ struct _wlan_adapter { struct cmd_ds_802_11_get_log logmsg; - u16 txrate; u32 linkmode; u32 radiomode; u8 fw_ready; diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 7d14f9c2aff..1fb0f91e538 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -949,7 +949,7 @@ static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev) priv->wstats.discard.misc = le16_to_cpu(adapter->logmsg.ackfailure); /* Calculate quality */ - priv->wstats.qual.qual = min_t(u32, quality, 100); + priv->wstats.qual.qual = min_t(u8, quality, 100); priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; stats_valid = 1; -- cgit v1.2.3-70-g09d2 From caef47a0dc2b17ea6fb0119d3678b4b21ae70daa Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 13:07:56 -0400 Subject: [PATCH] libertas: remove adapter->rxpd_rate No code uses the contents of this variable, so it can go. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmdresp.c | 1 - drivers/net/wireless/libertas/dev.h | 1 - drivers/net/wireless/libertas/rx.c | 2 -- 3 files changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index e91d819555e..7aec0d4e20f 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -60,7 +60,6 @@ void libertas_mac_event_disconnected(wlan_private * priv) memset(adapter->rawNF, 0x00, sizeof(adapter->rawNF)); adapter->nextSNRNF = 0; adapter->numSNRNF = 0; - adapter->rxpd_rate = 0; lbs_deb_cmd("current SSID '%s', length %u\n", escape_essid(adapter->curbssparams.ssid, adapter->curbssparams.ssid_len), diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 9e18f012333..850518e9cbc 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -343,7 +343,6 @@ struct _wlan_adapter { u8 rawNF[DEFAULT_DATA_AVG_FACTOR]; u16 nextSNRNF; u16 numSNRNF; - u16 rxpd_rate; u8 radioon; u32 preamble; diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c index 25d45c646d7..2473931f815 100644 --- a/drivers/net/wireless/libertas/rx.c +++ b/drivers/net/wireless/libertas/rx.c @@ -117,8 +117,6 @@ static void wlan_compute_rssi(wlan_private * priv, struct rxpd *p_rx_pd) adapter->NF[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->nf; wlan_save_rawSNRNF(priv, p_rx_pd); - adapter->rxpd_rate = p_rx_pd->rx_rate; - adapter->SNR[TYPE_RXPD][TYPE_AVG] = wlan_getavgsnr(priv) * AVG_SCALE; adapter->NF[TYPE_RXPD][TYPE_AVG] = wlan_getavgnf(priv) * AVG_SCALE; lbs_deb_rx("after computing SNR: SNR-avg = %d, NF-avg = %d\n", -- cgit v1.2.3-70-g09d2 From a783f1ee5b112a0258762877ec7c1ce8810f3cd8 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 13:08:24 -0400 Subject: [PATCH] libertas: remove adapter->{data,bcn}_avg_factor Those two variables were initialized with some default values, but there is no code that would ever change them. So we could use as well the defaults directly. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 2 +- drivers/net/wireless/libertas/dev.h | 2 -- drivers/net/wireless/libertas/main.c | 3 --- drivers/net/wireless/libertas/rx.c | 4 ++-- 4 files changed, 3 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 0da013f3b0d..72e76e4ec7a 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -671,7 +671,7 @@ static int wlan_cmd_802_11_rssi(wlan_private * priv, lbs_deb_enter(LBS_DEB_CMD); cmd->command = cpu_to_le16(CMD_802_11_RSSI); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rssi) + S_DS_GEN); - cmd->params.rssi.N = cpu_to_le16(priv->adapter->bcn_avg_factor); + cmd->params.rssi.N = cpu_to_le16(DEFAULT_BCN_AVG_FACTOR); /* reset Beacon SNR/NF/RSSI values */ adapter->SNR[TYPE_BEACON][TYPE_NOAVG] = 0; diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 850518e9cbc..76234000e5b 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -334,8 +334,6 @@ struct _wlan_adapter { u8 wpa_ie_len; /** Requested Signal Strength*/ - u16 bcn_avg_factor; - u16 data_avg_factor; u16 SNR[MAX_TYPE_B][MAX_TYPE_AVG]; u16 NF[MAX_TYPE_B][MAX_TYPE_AVG]; u8 RSSI[MAX_TYPE_B][MAX_TYPE_AVG]; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index da418dbe886..6ba3fa498e9 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -998,9 +998,6 @@ static void wlan_init_adapter(wlan_private * priv) wlan_adapter *adapter = priv->adapter; int i; - adapter->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR; - adapter->data_avg_factor = DEFAULT_DATA_AVG_FACTOR; - /* ATIM params */ adapter->atimwindow = 0; diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c index 2473931f815..83a7765fd23 100644 --- a/drivers/net/wireless/libertas/rx.c +++ b/drivers/net/wireless/libertas/rx.c @@ -85,12 +85,12 @@ static u8 wlan_getavgnf(wlan_private * priv) static void wlan_save_rawSNRNF(wlan_private * priv, struct rxpd *p_rx_pd) { wlan_adapter *adapter = priv->adapter; - if (adapter->numSNRNF < adapter->data_avg_factor) + if (adapter->numSNRNF < DEFAULT_DATA_AVG_FACTOR) adapter->numSNRNF++; adapter->rawSNR[adapter->nextSNRNF] = p_rx_pd->snr; adapter->rawNF[adapter->nextSNRNF] = p_rx_pd->nf; adapter->nextSNRNF++; - if (adapter->nextSNRNF >= adapter->data_avg_factor) + if (adapter->nextSNRNF >= DEFAULT_DATA_AVG_FACTOR) adapter->nextSNRNF = 0; return; } -- cgit v1.2.3-70-g09d2 From 97605c3eb3dee943a45584be92c46be1305b3ef5 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 13:09:15 -0400 Subject: [PATCH] libertas: remove adapter->nullpktinterval No code ever initialized this variable, so it was 0 because of kzalloc(). But no other code changes it, making it rather useless. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 3 +-- drivers/net/wireless/libertas/dev.h | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 72e76e4ec7a..f5d4971f13a 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -73,8 +73,7 @@ static int wlan_cmd_802_11_ps_mode(wlan_private * priv, psm->locallisteninterval = cpu_to_le16(adapter->locallisteninterval); - psm->nullpktinterval = - cpu_to_le16(adapter->nullpktinterval); + psm->nullpktinterval = 0; psm->multipledtim = cpu_to_le16(priv->adapter->multipledtim); break; diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 76234000e5b..6e78e315a8b 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -313,7 +313,6 @@ struct _wlan_adapter { struct PS_CMD_ConfirmSleep libertas_ps_confirm_sleep; u16 locallisteninterval; - u16 nullpktinterval; struct assoc_request * pending_assoc_req; struct assoc_request * in_progress_assoc_req; -- cgit v1.2.3-70-g09d2 From 252cf0d10f76d3edcd808d462dcfbd544875a0be Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 13:09:34 -0400 Subject: [PATCH] libertas: remove adapter->locallisteninterval locallisteninterval was initialized with 0, but there is no code that changes it, rendering it rather useless. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 6 +----- drivers/net/wireless/libertas/dev.h | 1 - drivers/net/wireless/libertas/main.c | 1 - 3 files changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index f5d4971f13a..276d981e7d3 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -56,7 +56,6 @@ static int wlan_cmd_802_11_ps_mode(wlan_private * priv, u16 cmd_action) { struct cmd_ds_802_11_ps_mode *psm = &cmd->params.psmode; - wlan_adapter *adapter = priv->adapter; lbs_deb_enter(LBS_DEB_CMD); @@ -68,11 +67,8 @@ static int wlan_cmd_802_11_ps_mode(wlan_private * priv, switch (cmd_action) { case CMD_SUBCMD_ENTER_PS: lbs_deb_cmd("PS command:" "SubCode- Enter PS\n"); - lbs_deb_cmd("locallisteninterval %d\n", - adapter->locallisteninterval); - psm->locallisteninterval = - cpu_to_le16(adapter->locallisteninterval); + psm->locallisteninterval = 0; psm->nullpktinterval = 0; psm->multipledtim = cpu_to_le16(priv->adapter->multipledtim); diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 6e78e315a8b..cf4ed5d0145 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -312,7 +312,6 @@ struct _wlan_adapter { u8 needtowakeup; struct PS_CMD_ConfirmSleep libertas_ps_confirm_sleep; - u16 locallisteninterval; struct assoc_request * pending_assoc_req; struct assoc_request * in_progress_assoc_req; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 6ba3fa498e9..c35605acf82 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1059,7 +1059,6 @@ static void wlan_init_adapter(wlan_private * priv) adapter->psstate = PS_STATE_FULL_POWER; adapter->needtowakeup = 0; - adapter->locallisteninterval = 0; /* default value in firmware will be used */ adapter->intcounter = 0; -- cgit v1.2.3-70-g09d2 From 56c4656e84d068ecc4da670799216e5b2aaee50e Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 13:09:49 -0400 Subject: [PATCH] libertas: remove adapter->multipledtim multipledtim was initialized with MRVDRV_DEFAULT_MULTIPLE_DTIM and then kept at that value, so we could use that define directly. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 2 +- drivers/net/wireless/libertas/dev.h | 1 - drivers/net/wireless/libertas/main.c | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 276d981e7d3..517489a0606 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -71,7 +71,7 @@ static int wlan_cmd_802_11_ps_mode(wlan_private * priv, psm->locallisteninterval = 0; psm->nullpktinterval = 0; psm->multipledtim = - cpu_to_le16(priv->adapter->multipledtim); + cpu_to_le16(MRVDRV_DEFAULT_MULTIPLE_DTIM); break; case CMD_SUBCMD_EXIT_PS: diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index cf4ed5d0145..0f383e3f6f0 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -307,7 +307,6 @@ struct _wlan_adapter { u16 psmode; /* Wlan802_11PowermodeCAM=disable Wlan802_11PowermodeMAX_PSP=enable */ - u16 multipledtim; u32 psstate; u8 needtowakeup; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index c35605acf82..df06d40ffde 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1053,7 +1053,6 @@ static void wlan_init_adapter(wlan_private * priv) adapter->capability = WLAN_CAPABILITY_SHORT_PREAMBLE; adapter->psmode = WLAN802_11POWERMODECAM; - adapter->multipledtim = MRVDRV_DEFAULT_MULTIPLE_DTIM; adapter->listeninterval = MRVDRV_DEFAULT_LISTEN_INTERVAL; -- cgit v1.2.3-70-g09d2 From ae596ce2f77d1542fe44ea483bd0ca7f61baeccd Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 13:10:05 -0400 Subject: [PATCH] libertas: remove adapter->atimwindow This varaible was initialized with 0 but there is no code that would ever change it's value. So it can go away. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/dev.h | 1 - drivers/net/wireless/libertas/join.c | 2 +- drivers/net/wireless/libertas/main.c | 3 --- 3 files changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 0f383e3f6f0..693058ad023 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -303,7 +303,6 @@ struct _wlan_adapter { /** POWER MANAGEMENT AND PnP SUPPORT */ u8 surpriseremoved; - u16 atimwindow; u16 psmode; /* Wlan802_11PowermodeCAM=disable Wlan802_11PowermodeMAX_PSP=enable */ diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c index 08034917d4b..0bded0c9149 100644 --- a/drivers/net/wireless/libertas/join.c +++ b/drivers/net/wireless/libertas/join.c @@ -518,7 +518,7 @@ int libertas_cmd_80211_ad_hoc_start(wlan_private * priv, adhs->ssparamset.ibssparamset.elementid = IBSS_PARA_IE_ID; adhs->ssparamset.ibssparamset.len = IBSS_PARA_IE_LEN; - adhs->ssparamset.ibssparamset.atimwindow = cpu_to_le16(adapter->atimwindow); + adhs->ssparamset.ibssparamset.atimwindow = 0; /* set capability info */ tmpcap = WLAN_CAPABILITY_IBSS; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index df06d40ffde..d227e453f98 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -998,9 +998,6 @@ static void wlan_init_adapter(wlan_private * priv) wlan_adapter *adapter = priv->adapter; int i; - /* ATIM params */ - adapter->atimwindow = 0; - adapter->connect_status = LIBERTAS_DISCONNECTED; memset(adapter->current_addr, 0xff, ETH_ALEN); -- cgit v1.2.3-70-g09d2 From 956deb867a97ac137c164a5d2d12b0c82fb6776d Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 13:10:41 -0400 Subject: [PATCH] libertas: remove adapter->regiontableindex The value was computed, but then never used. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmdresp.c | 2 -- drivers/net/wireless/libertas/dev.h | 1 - 2 files changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 7aec0d4e20f..53671e96b04 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -179,7 +179,6 @@ static int wlan_ret_get_hw_spec(wlan_private * priv, for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) { /* use the region code to search for the index */ if (adapter->regioncode == libertas_region_code_to_index[i]) { - adapter->regiontableindex = (u16) i; break; } } @@ -187,7 +186,6 @@ static int wlan_ret_get_hw_spec(wlan_private * priv, /* if it's unidentified region code, use the default (USA) */ if (i >= MRVDRV_MAX_REGION_CODE) { adapter->regioncode = 0x10; - adapter->regiontableindex = 0; lbs_pr_info("unidentified region code; using the default (USA)\n"); } diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 693058ad023..16e7ec11425 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -298,7 +298,6 @@ struct _wlan_adapter { u16 currentpacketfilter; u32 connect_status; u16 regioncode; - u16 regiontableindex; u16 txpowerlevel; /** POWER MANAGEMENT AND PnP SUPPORT */ -- cgit v1.2.3-70-g09d2 From 0aabc0a5d5657df254255c9049a97cc96229bcba Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 13:10:59 -0400 Subject: [PATCH] libertas: remove adapter->listeninterval listeninterval was initialized with MRVDRV_DEFAULT_LISTEN_INTERVAL, but there exists that would ever change it. So we can use this define directly. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/dev.h | 1 - drivers/net/wireless/libertas/join.c | 2 +- drivers/net/wireless/libertas/main.c | 2 -- 3 files changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 16e7ec11425..4738afa61e3 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -287,7 +287,6 @@ struct _wlan_adapter { u32 fragthsd; u32 rtsthsd; - u16 listeninterval; u8 txretrycount; /** Tx-related variables (for single packet tx) */ diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c index 0bded0c9149..e335a7e4ada 100644 --- a/drivers/net/wireless/libertas/join.c +++ b/drivers/net/wireless/libertas/join.c @@ -369,7 +369,7 @@ int libertas_cmd_80211_associate(wlan_private * priv, pos += sizeof(passo->peerstaaddr); /* set the listen interval */ - passo->listeninterval = cpu_to_le16(adapter->listeninterval); + passo->listeninterval = cpu_to_le16(MRVDRV_DEFAULT_LISTEN_INTERVAL); pos += sizeof(passo->capability); pos += sizeof(passo->listeninterval); diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index d227e453f98..d3316e41346 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1051,8 +1051,6 @@ static void wlan_init_adapter(wlan_private * priv) adapter->psmode = WLAN802_11POWERMODECAM; - adapter->listeninterval = MRVDRV_DEFAULT_LISTEN_INTERVAL; - adapter->psstate = PS_STATE_FULL_POWER; adapter->needtowakeup = 0; -- cgit v1.2.3-70-g09d2 From 85c93e5189b7402b4f9f4324c284bb91e8e8fb85 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 13:11:19 -0400 Subject: [PATCH] libertas: remove adapter->adhoc_grate_enabled The variable was initialized with 0 (false). There is no code that would ever change it, so we can use the false-patch directly. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/dev.h | 2 -- drivers/net/wireless/libertas/join.c | 9 ++------- drivers/net/wireless/libertas/main.c | 1 - 3 files changed, 2 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 4738afa61e3..90e9405903b 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -281,8 +281,6 @@ struct _wlan_adapter { u16 enablehwauto; u16 ratebitmap; - /** control G rates */ - u8 adhoc_grate_enabled; u32 fragthsd; u32 rtsthsd; diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c index e335a7e4ada..95c21bae60f 100644 --- a/drivers/net/wireless/libertas/join.c +++ b/drivers/net/wireless/libertas/join.c @@ -534,13 +534,8 @@ int libertas_cmd_80211_ad_hoc_start(wlan_private * priv, adhs->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME); memset(adhs->rates, 0, sizeof(adhs->rates)); - if (adapter->adhoc_grate_enabled) { - ratesize = min(sizeof(adhs->rates), sizeof(libertas_bg_rates)); - memcpy(adhs->rates, libertas_bg_rates, ratesize); - } else { - ratesize = min(sizeof(adhs->rates), sizeof(adhoc_rates_b)); - memcpy(adhs->rates, adhoc_rates_b, ratesize); - } + ratesize = min(sizeof(adhs->rates), sizeof(adhoc_rates_b)); + memcpy(adhs->rates, adhoc_rates_b, ratesize); /* Copy the ad-hoc creating rates into Current BSS state structure */ memset(&adapter->curbssparams.rates, 0, sizeof(adapter->curbssparams.rates)); diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index d3316e41346..ab8dcbf5bfc 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1042,7 +1042,6 @@ static void wlan_init_adapter(wlan_private * priv) adapter->auto_rate = 1; adapter->cur_rate = 0; - adapter->adhoc_grate_enabled = 0; adapter->beaconperiod = MRVDRV_BEACON_INTERVAL; -- cgit v1.2.3-70-g09d2 From 2c85103da3c88a06a7c01eece709482d85eff07f Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 13:11:38 -0400 Subject: [PATCH] libertas: remove adapter->beaconperiod beaconperiod was initialized with MRVDRV_BEACON_INTERVAL, but there is no code that would ever change it's value. We can use the define directly. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/dev.h | 1 - drivers/net/wireless/libertas/join.c | 2 +- drivers/net/wireless/libertas/main.c | 2 -- 3 files changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 90e9405903b..602a93e8892 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -265,7 +265,6 @@ struct _wlan_adapter { u8 scantype; u32 scanmode; - u16 beaconperiod; u8 adhoccreate; /** capability Info used in Association, start, join */ diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c index 95c21bae60f..c16d1f625d1 100644 --- a/drivers/net/wireless/libertas/join.c +++ b/drivers/net/wireless/libertas/join.c @@ -496,7 +496,7 @@ int libertas_cmd_80211_ad_hoc_start(wlan_private * priv, /* set the BSS type */ adhs->bsstype = CMD_BSS_TYPE_IBSS; adapter->mode = IW_MODE_ADHOC; - adhs->beaconperiod = cpu_to_le16(adapter->beaconperiod); + adhs->beaconperiod = cpu_to_le16(MRVDRV_BEACON_INTERVAL); /* set Physical param set */ #define DS_PARA_IE_ID 3 diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index ab8dcbf5bfc..1c8760ca864 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1043,8 +1043,6 @@ static void wlan_init_adapter(wlan_private * priv) adapter->auto_rate = 1; adapter->cur_rate = 0; - adapter->beaconperiod = MRVDRV_BEACON_INTERVAL; - // set default capabilities adapter->capability = WLAN_CAPABILITY_SHORT_PREAMBLE; -- cgit v1.2.3-70-g09d2 From d65ead886a193682f88b07aaf11d46127735a2b5 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 13:12:12 -0400 Subject: [PATCH] libertas: remove adapter->scanmode scanmode was initialized with CMD_BSS_TYPE_ANY, but there is no code that ever can store another value there, so it can go away. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/dev.h | 1 - drivers/net/wireless/libertas/main.c | 3 --- drivers/net/wireless/libertas/scan.c | 6 ++---- 3 files changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 602a93e8892..a33c523d0e9 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -263,7 +263,6 @@ struct _wlan_adapter { struct bss_descriptor *networks; u8 scantype; - u32 scanmode; u8 adhoccreate; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 1c8760ca864..7845cc346af 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1004,9 +1004,6 @@ static void wlan_init_adapter(wlan_private * priv) /* scan type */ adapter->scantype = CMD_SCAN_TYPE_ACTIVE; - /* scan mode */ - adapter->scanmode = CMD_BSS_TYPE_ANY; - /* 802.11 specific */ adapter->secinfo.wep_enabled = 0; for (i = 0; i < sizeof(adapter->wep_keys) / sizeof(adapter->wep_keys[0]); diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 7e4b0ab108d..33ee459315a 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -361,7 +361,6 @@ wlan_scan_setup_scan_config(wlan_private * priv, u8 * pfilteredscan, u8 * pscancurrentonly) { - wlan_adapter *adapter = priv->adapter; struct mrvlietypes_numprobes *pnumprobestlv; struct mrvlietypes_ssidparamset *pssidtlv; struct wlan_scan_cmd_config * pscancfgout = NULL; @@ -412,8 +411,7 @@ wlan_scan_setup_scan_config(wlan_private * priv, /* Set the bss type scan filter, use adapter setting if unset */ pscancfgout->bsstype = - (puserscanin->bsstype ? puserscanin->bsstype : adapter-> - scanmode); + puserscanin->bsstype ? puserscanin->bsstype : CMD_BSS_TYPE_ANY; /* Set the number of probes to send, use adapter setting if unset */ numprobes = puserscanin->numprobes ? puserscanin->numprobes : 0; @@ -448,7 +446,7 @@ wlan_scan_setup_scan_config(wlan_private * priv, *pfilteredscan = 1; } } else { - pscancfgout->bsstype = adapter->scanmode; + pscancfgout->bsstype = CMD_BSS_TYPE_ANY; numprobes = 0; } -- cgit v1.2.3-70-g09d2 From 4f2fdaaf0e4209bff3b18dc14c915b61f5fa5cd2 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 13:12:27 -0400 Subject: [PATCH] libertas: remove adapter->scantype scantype was initialized with CMD_SCAN_TYPE_ACTIVE, but there is no code that would ever change it, so we can use that variable directly. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/dev.h | 2 -- drivers/net/wireless/libertas/main.c | 3 --- drivers/net/wireless/libertas/scan.c | 2 +- 3 files changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index a33c523d0e9..f6b1402509f 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -262,8 +262,6 @@ struct _wlan_adapter { struct list_head network_free_list; struct bss_descriptor *networks; - u8 scantype; - u8 adhoccreate; /** capability Info used in Association, start, join */ diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 7845cc346af..9ccc9524153 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1001,9 +1001,6 @@ static void wlan_init_adapter(wlan_private * priv) adapter->connect_status = LIBERTAS_DISCONNECTED; memset(adapter->current_addr, 0xff, ETH_ALEN); - /* scan type */ - adapter->scantype = CMD_SCAN_TYPE_ACTIVE; - /* 802.11 specific */ adapter->secinfo.wep_enabled = 0; for (i = 0; i < sizeof(adapter->wep_keys) / sizeof(adapter->wep_keys[0]); diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 33ee459315a..4f621a6ec97 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -252,7 +252,7 @@ static void wlan_scan_create_channel_list(wlan_private * priv, * be changed to passive on a per channel basis if restricted by * regulatory requirements (11d or 11h) */ - scantype = adapter->scantype; + scantype = CMD_SCAN_TYPE_ACTIVE; for (rgnidx = 0; rgnidx < ARRAY_SIZE(adapter->region_channel); rgnidx++) { if (priv->adapter->enable11d && -- cgit v1.2.3-70-g09d2 From a2235ed40210081e51bec4bb1be64e4b3511501e Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 13:12:45 -0400 Subject: [PATCH] libertas: remove bss_descriptior->networktsf This value was parsed out, but then nowhere used ... except in some debugfs output. I can't imagine anyone wanting to use this value for anything real (as no other driver exports it), so bye-bye. Along this, made the columns of /sys/kernel/debug/libertas_wireless/*/getscantable align again. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/debugfs.c | 7 ++-- drivers/net/wireless/libertas/scan.c | 69 --------------------------------- drivers/net/wireless/libertas/scan.h | 4 +- 3 files changed, 5 insertions(+), 75 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c index 4b9533a6651..63e747ac49d 100644 --- a/drivers/net/wireless/libertas/debugfs.c +++ b/drivers/net/wireless/libertas/debugfs.c @@ -66,7 +66,7 @@ static ssize_t libertas_getscantable(struct file *file, char __user *userbuf, struct bss_descriptor * iter_bss; pos += snprintf(buf+pos, len-pos, - "# | ch | ss | bssid | cap | TSF | Qual | SSID \n"); + "# | ch | rssi | bssid | cap | Qual | SSID \n"); mutex_lock(&priv->adapter->lock); list_for_each_entry (iter_bss, &priv->adapter->network_list, list) { @@ -75,15 +75,14 @@ static ssize_t libertas_getscantable(struct file *file, char __user *userbuf, u16 spectrum_mgmt = (iter_bss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT); pos += snprintf(buf+pos, len-pos, - "%02u| %03d | %03ld | " MAC_FMT " |", + "%02u| %03d | %04ld | " MAC_FMT " |", numscansdone, iter_bss->channel, iter_bss->rssi, MAC_ARG(iter_bss->bssid)); pos += snprintf(buf+pos, len-pos, " %04x-", iter_bss->capability); pos += snprintf(buf+pos, len-pos, "%c%c%c |", ibss ? 'A' : 'I', privacy ? 'P' : ' ', spectrum_mgmt ? 'S' : ' '); - pos += snprintf(buf+pos, len-pos, " %08llx |", iter_bss->networktsf); - pos += snprintf(buf+pos, len-pos, " %d |", SCAN_RSSI(iter_bss->rssi)); + pos += snprintf(buf+pos, len-pos, " %04d |", SCAN_RSSI(iter_bss->rssi)); pos += snprintf(buf+pos, len-pos, " %s\n", escape_essid(iter_bss->ssid, iter_bss->ssid_len)); diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 4f621a6ec97..aea2e90b555 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -836,58 +836,6 @@ out: return ret; } -/** - * @brief Inspect the scan response buffer for pointers to expected TLVs - * - * TLVs can be included at the end of the scan response BSS information. - * Parse the data in the buffer for pointers to TLVs that can potentially - * be passed back in the response - * - * @param ptlv Pointer to the start of the TLV buffer to parse - * @param tlvbufsize size of the TLV buffer - * @param ptsftlv Output parameter: Pointer to the TSF TLV if found - * - * @return void - */ -static -void wlan_ret_802_11_scan_get_tlv_ptrs(struct mrvlietypes_data * ptlv, - int tlvbufsize, - struct mrvlietypes_tsftimestamp ** ptsftlv) -{ - struct mrvlietypes_data *pcurrenttlv; - int tlvbufleft; - u16 tlvtype; - u16 tlvlen; - - pcurrenttlv = ptlv; - tlvbufleft = tlvbufsize; - *ptsftlv = NULL; - - lbs_deb_scan("SCAN_RESP: tlvbufsize = %d\n", tlvbufsize); - lbs_deb_hex(LBS_DEB_SCAN, "SCAN_RESP: TLV Buf", (u8 *) ptlv, tlvbufsize); - - while (tlvbufleft >= sizeof(struct mrvlietypesheader)) { - tlvtype = le16_to_cpu(pcurrenttlv->header.type); - tlvlen = le16_to_cpu(pcurrenttlv->header.len); - - switch (tlvtype) { - case TLV_TYPE_TSFTIMESTAMP: - *ptsftlv = (struct mrvlietypes_tsftimestamp *) pcurrenttlv; - break; - - default: - lbs_deb_scan("SCAN_RESP: Unhandled TLV = %d\n", - tlvtype); - /* Give up, this seems corrupted */ - return; - } /* switch */ - - tlvbufleft -= (sizeof(ptlv->header) + tlvlen); - pcurrenttlv = - (struct mrvlietypes_data *) (pcurrenttlv->Data + tlvlen); - } /* while */ -} - /** * @brief Interpret a BSS scan response returned from the firmware * @@ -1684,8 +1632,6 @@ int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp) { wlan_adapter *adapter = priv->adapter; struct cmd_ds_802_11_scan_rsp *pscan; - struct mrvlietypes_data *ptlv; - struct mrvlietypes_tsftimestamp *ptsftlv; struct bss_descriptor * iter_bss; struct bss_descriptor * safe; u8 *pbssinfo; @@ -1734,11 +1680,6 @@ int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp) + sizeof(pscan->nr_sets) + S_DS_GEN); - ptlv = (struct mrvlietypes_data *) (pscan->bssdesc_and_tlvbuffer + bytesleft); - - /* Search the TLV buffer space in the scan response for any valid TLVs */ - wlan_ret_802_11_scan_get_tlv_ptrs(ptlv, tlvbufsize, &ptsftlv); - /* * Process each scan response returned (pscan->nr_sets). Save * the information in the newbssentry and then insert into the @@ -1791,16 +1732,6 @@ int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp) new.bssid[0], new.bssid[1], new.bssid[2], new.bssid[3], new.bssid[4], new.bssid[5]); - /* - * If the TSF TLV was appended to the scan results, save the - * this entries TSF value in the networktsf field. The - * networktsf is the firmware's TSF value at the time the - * beacon or probe response was received. - */ - if (ptsftlv) { - new.networktsf = le64_to_cpup(&ptsftlv->tsftable[idx]); - } - /* Copy the locally created newbssentry to the scan table */ memcpy(found, &new, offsetof(struct bss_descriptor, list)); } diff --git a/drivers/net/wireless/libertas/scan.h b/drivers/net/wireless/libertas/scan.h index def0db5c4e6..28decf39153 100644 --- a/drivers/net/wireless/libertas/scan.h +++ b/drivers/net/wireless/libertas/scan.h @@ -151,7 +151,9 @@ struct bss_descriptor { u32 atimwindow; + /* IW_MODE_AUTO, IW_MODE_ADHOC, IW_MODE_INFRA */ u8 mode; + /* zero-terminated array of supported data rates */ u8 rates[MAX_RATES + 1]; @@ -161,8 +163,6 @@ struct bss_descriptor { union ieeetypes_phyparamset phyparamset; union IEEEtypes_ssparamset ssparamset; - u64 networktsf; //!< TSF timestamp from the current firmware TSF - struct ieeetypes_countryinfofullset countryinfo; u8 wpa_ie[MAX_WPA_IE_LEN]; -- cgit v1.2.3-70-g09d2 From bee093d6132569eee13b2c45058b550c9544a5b8 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 13:13:00 -0400 Subject: [PATCH] libertas: remove bss_descriptor->timestamp Noone used this variable. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/scan.c | 1 - drivers/net/wireless/libertas/scan.h | 1 - 2 files changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index aea2e90b555..5c730b9d956 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -903,7 +903,6 @@ static int libertas_process_bss(struct bss_descriptor * bss, pos++; /* time stamp is 8 bytes long */ - bss->timestamp = le64_to_cpup((void *) pos); pos += 8; /* beacon interval is 2 bytes long */ diff --git a/drivers/net/wireless/libertas/scan.h b/drivers/net/wireless/libertas/scan.h index 28decf39153..9bb1a435c28 100644 --- a/drivers/net/wireless/libertas/scan.h +++ b/drivers/net/wireless/libertas/scan.h @@ -157,7 +157,6 @@ struct bss_descriptor { /* zero-terminated array of supported data rates */ u8 rates[MAX_RATES + 1]; - __le64 timestamp; //!< TSF value included in the beacon/probe response unsigned long last_scanned; union ieeetypes_phyparamset phyparamset; -- cgit v1.2.3-70-g09d2 From 9556d2120ceecc158b324fa01e30704ff9f42ae3 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 2 Aug 2007 13:14:07 -0400 Subject: [PATCH] libertas: fix two debug statements in cmdresp.c Purely cosmetic: this moves an lbs_deb_enter() to the proper place and changes an erraneous lbs_deb_enter_args() into lbs_deb_leave_args() Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmdresp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 53671e96b04..93bf63bad0f 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -867,12 +867,12 @@ int libertas_process_event(wlan_private * priv) wlan_adapter *adapter = priv->adapter; u32 eventcause; + lbs_deb_enter(LBS_DEB_CMD); + spin_lock_irq(&adapter->driver_lock); eventcause = adapter->eventcause; spin_unlock_irq(&adapter->driver_lock); - lbs_deb_enter(LBS_DEB_CMD); - lbs_deb_cmd("event cause 0x%x\n", eventcause); switch (eventcause >> SBI_EVENT_CAUSE_SHIFT) { @@ -988,6 +988,6 @@ int libertas_process_event(wlan_private * priv) adapter->eventcause = 0; spin_unlock_irq(&adapter->driver_lock); - lbs_deb_enter_args(LBS_DEB_CMD, "ret %d", ret); + lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; } -- cgit v1.2.3-70-g09d2 From 0edef215e405fef3c6569511a9aebeeb3f6cd799 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 13:14:29 -0400 Subject: [PATCH] libertas: send association events on adhoc reassociation Send association event to userspace when reassociating to the same ad-hoc network, because it's still an association. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/join.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c index c16d1f625d1..0ebf2f8acbf 100644 --- a/drivers/net/wireless/libertas/join.c +++ b/drivers/net/wireless/libertas/join.c @@ -209,15 +209,26 @@ int libertas_join_adhoc_network(wlan_private * priv, struct assoc_request * asso bss->ssid_len); /* check if the requested SSID is already joined */ - if (adapter->curbssparams.ssid_len + if ( adapter->curbssparams.ssid_len && !libertas_ssid_cmp(adapter->curbssparams.ssid, adapter->curbssparams.ssid_len, bss->ssid, bss->ssid_len) - && (adapter->mode == IW_MODE_ADHOC)) { - lbs_deb_join( - "ADHOC_J_CMD: New ad-hoc SSID is the same as current, " - "not attempting to re-join"); - return -1; + && (adapter->mode == IW_MODE_ADHOC) + && (adapter->connect_status == LIBERTAS_CONNECTED)) { + union iwreq_data wrqu; + + lbs_deb_join("ADHOC_J_CMD: New ad-hoc SSID is the same as " + "current, not attempting to re-join"); + + /* Send the re-association event though, because the association + * request really was successful, even if just a null-op. + */ + memset(&wrqu, 0, sizeof(wrqu)); + memcpy(wrqu.ap_addr.sa_data, adapter->curbssparams.bssid, + ETH_ALEN); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); + goto out; } /* Use shortpreamble only when both creator and card supports @@ -242,6 +253,7 @@ int libertas_join_adhoc_network(wlan_private * priv, struct assoc_request * asso 0, CMD_OPTION_WAITFORRSP, OID_802_11_SSID, assoc_req); +out: return ret; } -- cgit v1.2.3-70-g09d2 From 00af0157e0a603e2a2ce0896179f2dd43f0f28ab Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 13:14:56 -0400 Subject: [PATCH] libertas: push mesh beacon bit to userspace in scan results Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/scan.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 5c730b9d956..8d4e1ee2739 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -1334,6 +1334,8 @@ out: return ret; } +#define MAX_CUSTOM_LEN 64 + static inline char *libertas_translate_scan(wlan_private *priv, char *start, char *stop, struct bss_descriptor *bss) @@ -1467,6 +1469,18 @@ static inline char *libertas_translate_scan(wlan_private *priv, start = iwe_stream_add_point(start, stop, &iwe, buf); } + if (bss->mesh) { + char custom[MAX_CUSTOM_LEN]; + char *p = custom; + + iwe.cmd = IWEVCUSTOM; + p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), + "mesh-type: olpc"); + iwe.u.data.length = p - custom; + if (iwe.u.data.length) + start = iwe_stream_add_point(start, stop, &iwe, custom); + } + return start; } -- cgit v1.2.3-70-g09d2 From b37e5842f5ab66f8d0533ee62ffe35c26ae800a3 Mon Sep 17 00:00:00 2001 From: Luis Carlos Cobo Date: Thu, 2 Aug 2007 13:15:40 -0400 Subject: [PATCH] libertas: revert CAPINFO_MASK to its original value CAPINFO_MASK changed on commits 981f187b and a091095b. Reverting to the original value. Also move CAPINFO_MASK into the sole user, join.c. CAPINFO_MASK should be in host CPU byte order; capability is converted to device byte order elsewhere. This fixes OLPC ticket #2161 Signed-off-by: Luis Carlos Cobo Acked-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/join.c | 4 ++++ drivers/net/wireless/libertas/types.h | 2 -- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c index 0ebf2f8acbf..ccb0df1967f 100644 --- a/drivers/net/wireless/libertas/join.c +++ b/drivers/net/wireless/libertas/join.c @@ -20,6 +20,10 @@ /* Supported rates for ad-hoc B mode */ static u8 adhoc_rates_b[5] = { 0x02, 0x04, 0x0b, 0x16, 0x00 }; +/* The firmware needs certain bits masked out of the beacon-derviced capability + * field when associating/joining to BSSs. + */ +#define CAPINFO_MASK (~(0xda00)) /** * @brief This function finds common rates between rate1 and card rates. diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h index 2df352db155..a43a5f63c87 100644 --- a/drivers/net/wireless/libertas/types.h +++ b/drivers/net/wireless/libertas/types.h @@ -7,8 +7,6 @@ #include #include -#define CAPINFO_MASK (~(0x00da)) - struct ieeetypes_cfparamset { u8 elementid; u8 len; -- cgit v1.2.3-70-g09d2 From d21b31fd53626f9c1d14fc676793dbe86b44d1c6 Mon Sep 17 00:00:00 2001 From: Luis Carlos Cobo Date: Thu, 2 Aug 2007 13:16:02 -0400 Subject: [PATCH] libertas: keep mesh autostart enabled while asleep After loading the firmware, mesh autostart will be disabled. After that, the user will still be able to enable or disable it at will. On suspend, it will be always activated and later on resume it will go back to the state it had before going to sleep. Signed-off-by: Luis Carlos Cobo Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/dev.h | 1 + drivers/net/wireless/libertas/if_usb.c | 26 ++++++++++++++++++++++++++ drivers/net/wireless/libertas/main.c | 23 ++++++++++++++++++++++- 3 files changed, 49 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index f6b1402509f..397c5fca0ff 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -103,6 +103,7 @@ struct _wlan_private { int open; int mesh_open; int infra_open; + int mesh_autostart_enabled; char name[DEV_NAME_LEN]; diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index 5efdeac6e20..670e1d23c04 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -990,6 +990,19 @@ static int if_usb_suspend(struct usb_interface *intf, pm_message_t message) if (priv->adapter->psstate != PS_STATE_FULL_POWER) return -1; + if (priv->mesh_dev && !priv->mesh_autostart_enabled) { + /* Mesh autostart must be activated while sleeping + * On resume it will go back to the current state + */ + struct cmd_ds_mesh_access mesh_access; + memset(&mesh_access, 0, sizeof(mesh_access)); + mesh_access.data[0] = cpu_to_le32(1); + libertas_prepare_and_send_command(priv, + CMD_MESH_ACCESS, + CMD_ACT_MESH_SET_AUTOSTART_ENABLED, + CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access); + } + netif_device_detach(cardp->eth_dev); netif_device_detach(priv->mesh_dev); @@ -1017,6 +1030,19 @@ static int if_usb_resume(struct usb_interface *intf) netif_device_attach(cardp->eth_dev); netif_device_attach(priv->mesh_dev); + if (priv->mesh_dev && !priv->mesh_autostart_enabled) { + /* Mesh autostart was activated while sleeping + * Disable it if appropriate + */ + struct cmd_ds_mesh_access mesh_access; + memset(&mesh_access, 0, sizeof(mesh_access)); + mesh_access.data[0] = cpu_to_le32(0); + libertas_prepare_and_send_command(priv, + CMD_MESH_ACCESS, + CMD_ACT_MESH_SET_AUTOSTART_ENABLED, + CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access); + } + lbs_deb_leave(LBS_DEB_USB); return 0; } diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 9ccc9524153..a3a17caae43 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -271,15 +271,20 @@ static ssize_t libertas_autostart_enabled_set(struct device * dev, { struct cmd_ds_mesh_access mesh_access; uint32_t datum; + wlan_private * priv = (to_net_dev(dev))->priv; + int ret; memset(&mesh_access, 0, sizeof(mesh_access)); sscanf(buf, "%d", &datum); mesh_access.data[0] = cpu_to_le32(datum); - libertas_prepare_and_send_command((to_net_dev(dev))->priv, + ret = libertas_prepare_and_send_command(priv, CMD_MESH_ACCESS, CMD_ACT_MESH_SET_AUTOSTART_ENABLED, CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access); + if (ret == 0) + priv->mesh_autostart_enabled = datum ? 1 : 0; + return strlen(buf); } @@ -853,6 +858,7 @@ static int wlan_setup_station_hw(wlan_private * priv) { int ret = -1; wlan_adapter *adapter = priv->adapter; + struct cmd_ds_mesh_access mesh_access; lbs_deb_enter(LBS_DEB_FW); @@ -889,6 +895,21 @@ static int wlan_setup_station_hw(wlan_private * priv) goto done; } + /* Disable mesh autostart */ + if (priv->mesh_dev) { + memset(&mesh_access, 0, sizeof(mesh_access)); + mesh_access.data[0] = cpu_to_le32(0); + ret = libertas_prepare_and_send_command(priv, + CMD_MESH_ACCESS, + CMD_ACT_MESH_SET_AUTOSTART_ENABLED, + CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access); + if (ret) { + ret = -1; + goto done; + } + priv->mesh_autostart_enabled = 0; + } + ret = 0; done: lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret); -- cgit v1.2.3-70-g09d2 From 9483f03150cbfa1f706355b7f9d218d6086c6fce Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Thu, 2 Aug 2007 13:16:30 -0400 Subject: [PATCH] libertas: fix a few wext abuses... o SIOCGIWNAME is not designed to return the version number of the driver. On the other hand, you are free to abuse SIOCGIWNICKN for that purpose. o Don't attempt to fix the WE19/WE20 transition in the driver, because your fixes are bogus, and redundant with the code in the kernel (you may endup with +2, you can't read 32 char ESSID...). o In SIOCSIWTXPOW, if you specified in iwrange that you want dBm, you should only get dBm, which allow to reduce code bloat. Signed-off-by: Jean Tourrilhes Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/wext.c | 120 ++++++++--------------------------- 1 file changed, 27 insertions(+), 93 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 1fb0f91e538..15395bf0a2a 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -21,52 +21,6 @@ #include "assoc.h" -/** - * @brief Convert mw value to dbm value - * - * @param mw the value of mw - * @return the value of dbm - */ -static int mw_to_dbm(int mw) -{ - if (mw < 2) - return 0; - else if (mw < 3) - return 3; - else if (mw < 4) - return 5; - else if (mw < 6) - return 7; - else if (mw < 7) - return 8; - else if (mw < 8) - return 9; - else if (mw < 10) - return 10; - else if (mw < 13) - return 11; - else if (mw < 16) - return 12; - else if (mw < 20) - return 13; - else if (mw < 25) - return 14; - else if (mw < 32) - return 15; - else if (mw < 40) - return 16; - else if (mw < 50) - return 17; - else if (mw < 63) - return 18; - else if (mw < 79) - return 19; - else if (mw < 100) - return 20; - else - return 21; -} - /** * @brief Find the channel frequency power info with specific channel * @@ -199,28 +153,11 @@ static void copy_active_data_rates(wlan_adapter * adapter, u8 * rates) static int wlan_get_name(struct net_device *dev, struct iw_request_info *info, char *cwrq, char *extra) { - const char *cp; - char comm[6] = { "COMM-" }; - char mrvl[6] = { "MRVL-" }; - int cnt; lbs_deb_enter(LBS_DEB_WEXT); - strcpy(cwrq, mrvl); - - cp = strstr(libertas_driver_version, comm); - if (cp == libertas_driver_version) //skip leading "COMM-" - cp = libertas_driver_version + strlen(comm); - else - cp = libertas_driver_version; - - cnt = strlen(mrvl); - cwrq += cnt; - while (cnt < 16 && (*cp != '-')) { - *cwrq++ = toupper(*cp++); - cnt++; - } - *cwrq = '\0'; + /* We could add support for 802.11n here as needed. Jean II */ + snprintf(cwrq, IFNAMSIZ, "IEEE 802.11b/g"); lbs_deb_leave(LBS_DEB_WEXT); return 0; @@ -300,29 +237,37 @@ static int wlan_set_nick(struct net_device *dev, struct iw_request_info *info, static int wlan_get_nick(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; + const char *cp; + char comm[6] = { "COMM-" }; + char mrvl[6] = { "MRVL-" }; + int cnt; lbs_deb_enter(LBS_DEB_WEXT); /* - * Get the Nick Name saved + * Nick Name is not used internally in this mode, + * therefore return something useful instead. Jean II */ - mutex_lock(&adapter->lock); - strncpy(extra, adapter->nodename, 16); - mutex_unlock(&adapter->lock); + strcpy(extra, mrvl); - extra[16] = '\0'; + cp = strstr(libertas_driver_version, comm); + if (cp == libertas_driver_version) //skip leading "COMM-" + cp = libertas_driver_version + strlen(comm); + else + cp = libertas_driver_version; - /* - * If none, we may want to get the one that was set - */ + cnt = strlen(mrvl); + extra += cnt; + while (cnt < 16 && (*cp != '-')) { + *extra++ = toupper(*cp++); + cnt++; + } /* * Push it out ! */ - dwrq->length = strlen(extra) + 1; + dwrq->length = cnt; lbs_deb_leave(LBS_DEB_WEXT); return 0; @@ -341,12 +286,12 @@ static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info, if (adapter->connect_status == LIBERTAS_CONNECTED) { strncpy(extra, "Mesh", 12); extra[12] = '\0'; - dwrq->length = strlen(extra) + 1; + dwrq->length = strlen(extra); } else { extra[0] = '\0'; - dwrq->length = 1 ; + dwrq->length = 0; } lbs_deb_leave(LBS_DEB_WEXT); @@ -1897,8 +1842,10 @@ static int wlan_set_txpow(struct net_device *dev, struct iw_request_info *info, wlan_radio_ioctl(priv, RADIO_ON); + /* Userspace check in iwrange if it should use dBm or mW, + * therefore this should never happen... Jean II */ if ((vwrq->flags & IW_TXPOW_TYPE) == IW_TXPOW_MWATT) { - dbm = (u16) mw_to_dbm(vwrq->value); + return -EOPNOTSUPP; } else dbm = (u16) vwrq->value; @@ -1946,12 +1893,7 @@ static int wlan_get_essid(struct net_device *dev, struct iw_request_info *info, * If none, we may want to get the one that was set */ - /* To make the driver backward compatible with WPA supplicant v0.2.4 */ - if (dwrq->length == 32) /* check with WPA supplicant buffer size */ - dwrq->length = min_t(size_t, adapter->curbssparams.ssid_len, - IW_ESSID_MAX_SIZE); - else - dwrq->length = adapter->curbssparams.ssid_len + 1; + dwrq->length = adapter->curbssparams.ssid_len; dwrq->flags = 1; /* active */ @@ -1972,14 +1914,6 @@ static int wlan_set_essid(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); - /* - * WE-20 and earlier NULL pad the end of the SSID and increment - * SSID length so it can be used like a string. WE-21 and later don't, - * but some userspace tools aren't able to cope with the change. - */ - if ((in_ssid_len > 0) && (extra[in_ssid_len - 1] == '\0')) - in_ssid_len--; - /* Check the size of the string */ if (in_ssid_len > IW_ESSID_MAX_SIZE) { ret = -E2BIG; -- cgit v1.2.3-70-g09d2 From 965f8bbc6c92233600b176f4c80299f6766df9bd Mon Sep 17 00:00:00 2001 From: Luis Carlos Cobo Date: Thu, 2 Aug 2007 13:16:55 -0400 Subject: [PATCH] libertas: monitor mode support for OLPC firmware Driver support for the monitor mode support that will be available in the next OLPC 'bleeding edge' Marvell firmware release (most likely, 5.110.16.p2). To activate monitor mode, echo mode > /sys/class/net/{ethX,mshX}/device/libertas_rtap where mode is the hex mask that specifies which frames to sniff (in short, 0x1 for data, 0x2 for all management but beacons, 0x4 for beacons). Any non zero mode will activate the monitor mode, inhibiting transmission in ethX and mshX interfaces and routing all the incoming traffic to a new rtapX interface that will output the packets in 802.11+radiotap headers format. Signed-off-by: Luis Carlos Cobo Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 25 ++++++ drivers/net/wireless/libertas/dev.h | 7 +- drivers/net/wireless/libertas/host.h | 2 + drivers/net/wireless/libertas/hostcmd.h | 6 ++ drivers/net/wireless/libertas/if_usb.c | 2 + drivers/net/wireless/libertas/main.c | 153 +++++++++++++++++++++++++++++++- drivers/net/wireless/libertas/rx.c | 49 +++++----- drivers/net/wireless/libertas/tx.c | 8 +- drivers/net/wireless/libertas/wext.h | 5 +- 9 files changed, 217 insertions(+), 40 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 517489a0606..cd3bddb243b 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -565,6 +565,26 @@ static int wlan_cmd_802_11_rf_tx_power(wlan_private * priv, return 0; } +static int wlan_cmd_802_11_monitor_mode(wlan_private * priv, + struct cmd_ds_command *cmd, + u16 cmd_action, void *pdata_buf) +{ + struct cmd_ds_802_11_monitor_mode *monitor = &cmd->params.monitor; + + cmd->command = cpu_to_le16(CMD_802_11_MONITOR_MODE); + cmd->size = + cpu_to_le16(sizeof(struct cmd_ds_802_11_monitor_mode) + + S_DS_GEN); + + monitor->action = cpu_to_le16(cmd_action); + if (cmd_action == CMD_ACT_SET) { + monitor->mode = + cpu_to_le16((u16) (*(u32 *) pdata_buf)); + } + + return 0; +} + static int wlan_cmd_802_11_rate_adapt_rateset(wlan_private * priv, struct cmd_ds_command *cmd, u16 cmd_action) @@ -1239,6 +1259,11 @@ int libertas_prepare_and_send_command(wlan_private * priv, ret = wlan_cmd_mac_multicast_adr(priv, cmdptr, cmd_action); break; + case CMD_802_11_MONITOR_MODE: + ret = wlan_cmd_802_11_monitor_mode(priv, cmdptr, + cmd_action, pdata_buf); + break; + case CMD_802_11_AD_HOC_JOIN: ret = libertas_cmd_80211_ad_hoc_join(priv, cmdptr, pdata_buf); break; diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 397c5fca0ff..5697fec0cb1 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -112,7 +112,9 @@ struct _wlan_private { struct net_device *dev; struct net_device_stats stats; - struct net_device *mesh_dev ; /* Virtual device */ + struct net_device *mesh_dev; /* Virtual device */ + struct net_device *rtap_net_dev; + struct ieee80211_device *ieee; struct iw_statistics wstats; struct wlan_mesh_stats mstats; @@ -362,8 +364,7 @@ struct _wlan_adapter { struct cmd_ds_802_11_get_log logmsg; - u32 linkmode; - u32 radiomode; + u32 monitormode; u8 fw_ready; u8 last_scanned_channel; diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index c6b44c83159..4ccdbf9c473 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -110,6 +110,8 @@ #define CMD_FWT_ACCESS 0x0095 +#define CMD_802_11_MONITOR_MODE 0x0098 + #define CMD_MESH_ACCESS 0x009b /* For the IEEE Power Save */ diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index 44cf39c8d1b..52884eaf2ed 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -405,6 +405,11 @@ struct cmd_ds_802_11_rf_antenna { }; +struct cmd_ds_802_11_monitor_mode { + u16 action; + u16 mode; +}; + struct cmd_ds_802_11_ps_mode { __le16 action; __le16 nullpktinterval; @@ -623,6 +628,7 @@ struct cmd_ds_command { struct cmd_ds_802_11_snmp_mib smib; struct cmd_ds_802_11_rf_tx_power txp; struct cmd_ds_802_11_rf_antenna rant; + struct cmd_ds_802_11_monitor_mode monitor; struct cmd_ds_802_11_data_rate drate; struct cmd_ds_802_11_rate_adapt_rateset rateset; struct cmd_ds_mac_multicast_adr madr; diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index 670e1d23c04..d28802fb244 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -208,6 +208,8 @@ static int if_usb_probe(struct usb_interface *intf, if (!(priv = libertas_add_card(cardp, &udev->dev))) goto dealloc; + udev->dev.driver_data = priv; + if (libertas_add_mesh(priv, &udev->dev)) goto err_add_mesh; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index a3a17caae43..9a46339ce47 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -21,6 +21,7 @@ #include "wext.h" #include "debugfs.h" #include "assoc.h" +#include "join.h" #define DRIVER_RELEASE_VERSION "322.p1" const char libertas_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION @@ -246,6 +247,66 @@ static ssize_t libertas_anycast_set(struct device * dev, return strlen(buf); } +int libertas_add_rtap(wlan_private *priv); +void libertas_remove_rtap(wlan_private *priv); + +/** + * Get function for sysfs attribute rtap + */ +static ssize_t libertas_rtap_get(struct device * dev, + struct device_attribute *attr, char * buf) +{ + wlan_private *priv = (wlan_private *) dev->driver_data; + wlan_adapter *adapter = priv->adapter; + return snprintf(buf, 5, "0x%X\n", adapter->monitormode); +} + +/** + * Set function for sysfs attribute rtap + */ +static ssize_t libertas_rtap_set(struct device * dev, + struct device_attribute *attr, const char * buf, size_t count) +{ + int monitor_mode; + wlan_private *priv = (wlan_private *) dev->driver_data; + wlan_adapter *adapter = priv->adapter; + + sscanf(buf, "%x", &monitor_mode); + if (monitor_mode != WLAN_MONITOR_OFF) { + if(adapter->monitormode == monitor_mode) + return strlen(buf); + if (adapter->monitormode == WLAN_MONITOR_OFF) { + if (adapter->mode == IW_MODE_INFRA) + libertas_send_deauthentication(priv); + else if (adapter->mode == IW_MODE_ADHOC) + libertas_stop_adhoc_network(priv); + libertas_add_rtap(priv); + } + adapter->monitormode = monitor_mode; + } + + else { + if(adapter->monitormode == WLAN_MONITOR_OFF) + return strlen(buf); + adapter->monitormode = WLAN_MONITOR_OFF; + libertas_remove_rtap(priv); + netif_wake_queue(priv->dev); + netif_wake_queue(priv->mesh_dev); + } + + libertas_prepare_and_send_command(priv, + CMD_802_11_MONITOR_MODE, CMD_ACT_SET, + CMD_OPTION_WAITFORRSP, 0, &adapter->monitormode); + return strlen(buf); +} + +/** + * libertas_rtap attribute to be exported per mshX interface + * through sysfs (/sys/class/net/mshX/libertas-rtap) + */ +static DEVICE_ATTR(libertas_rtap, 0644, libertas_rtap_get, + libertas_rtap_set ); + /** * anycast_mask attribute to be exported per mshX interface * through sysfs (/sys/class/net/mshX/anycast_mask) @@ -480,6 +541,10 @@ static int libertas_mesh_pre_start_xmit(struct sk_buff *skb, int ret; lbs_deb_enter(LBS_DEB_MESH); + if(priv->adapter->monitormode != WLAN_MONITOR_OFF) { + netif_stop_queue(dev); + return -EOPNOTSUPP; + } SET_MESH_FRAME(skb); @@ -494,10 +559,16 @@ static int libertas_mesh_pre_start_xmit(struct sk_buff *skb, */ static int libertas_pre_start_xmit(struct sk_buff *skb, struct net_device *dev) { + wlan_private *priv = dev->priv; int ret; lbs_deb_enter(LBS_DEB_NET); + if(priv->adapter->monitormode != WLAN_MONITOR_OFF) { + netif_stop_queue(dev); + return -EOPNOTSUPP; + } + UNSET_MESH_FRAME(skb); ret = libertas_hard_start_xmit(skb, dev); @@ -517,7 +588,7 @@ static void libertas_tx_timeout(struct net_device *dev) dev->trans_start = jiffies; if (priv->adapter->currenttxskb) { - if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) { + if (priv->adapter->monitormode != WLAN_MONITOR_OFF) { /* If we are here, we have not received feedback from the previous packet. Assume TX_FAIL and move on. */ priv->adapter->eventcause = 0x01000000; @@ -1169,6 +1240,9 @@ wlan_private *libertas_add_card(void *card, struct device *dmdev) spin_lock_init(&priv->adapter->driver_lock); init_waitqueue_head(&priv->adapter->cmd_pending); priv->adapter->nr_cmd_pending = 0; + priv->rtap_net_dev = NULL; + if (device_create_file(dmdev, &dev_attr_libertas_rtap)) + goto err_kzalloc; goto done; err_kzalloc: @@ -1333,6 +1407,7 @@ int libertas_remove_card(wlan_private *priv) lbs_deb_enter(LBS_DEB_NET); + libertas_remove_rtap(priv); if (!priv) goto out; @@ -1342,6 +1417,7 @@ int libertas_remove_card(wlan_private *priv) goto out; dev = priv->dev; + device_remove_file(priv->hotplug_device, &dev_attr_libertas_rtap); netif_stop_queue(priv->dev); netif_carrier_off(priv->dev); @@ -1537,6 +1613,81 @@ static void libertas_exit_module(void) lbs_deb_leave(LBS_DEB_MAIN); } +/* + * rtap interface support fuctions + */ + +static int libertas_rtap_open(struct net_device *dev) +{ + netif_carrier_off(dev); + netif_stop_queue(dev); + return 0; +} + +static int libertas_rtap_stop(struct net_device *dev) +{ + return 0; +} + +static int libertas_rtap_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + netif_stop_queue(dev); + return -EOPNOTSUPP; +} + +static struct net_device_stats *libertas_rtap_get_stats(struct net_device *dev) +{ + wlan_private *priv = dev->priv; + return &priv->ieee->stats; +} + + +void libertas_remove_rtap(wlan_private *priv) +{ + if (priv->rtap_net_dev == NULL) + return; + unregister_netdev(priv->rtap_net_dev); + free_ieee80211(priv->rtap_net_dev); + priv->rtap_net_dev = NULL; +} + +int libertas_add_rtap(wlan_private *priv) +{ + int rc = 0; + + if (priv->rtap_net_dev) + return -EPERM; + + priv->rtap_net_dev = alloc_ieee80211(0); + if (priv->rtap_net_dev == NULL) + return -ENOMEM; + + + priv->ieee = netdev_priv(priv->rtap_net_dev); + + strcpy(priv->rtap_net_dev->name, "rtap%d"); + + priv->rtap_net_dev->type = ARPHRD_IEEE80211_RADIOTAP; + priv->rtap_net_dev->open = libertas_rtap_open; + priv->rtap_net_dev->stop = libertas_rtap_stop; + priv->rtap_net_dev->get_stats = libertas_rtap_get_stats; + priv->rtap_net_dev->hard_start_xmit = libertas_rtap_hard_start_xmit; + priv->rtap_net_dev->set_multicast_list = libertas_set_multicast_list; + priv->rtap_net_dev->priv = priv; + + priv->ieee->iw_mode = IW_MODE_MONITOR; + + rc = register_netdev(priv->rtap_net_dev); + if (rc) { + free_ieee80211(priv->rtap_net_dev); + priv->rtap_net_dev = NULL; + return rc; + } + + return 0; +} + + module_init(libertas_init_module); module_exit(libertas_exit_module); diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c index 83a7765fd23..09def943b91 100644 --- a/drivers/net/wireless/libertas/rx.c +++ b/drivers/net/wireless/libertas/rx.c @@ -138,12 +138,15 @@ void libertas_upload_rx_packet(wlan_private * priv, struct sk_buff *skb) { lbs_deb_rx("skb->data %p\n", skb->data); - if (priv->mesh_dev && IS_MESH_FRAME(skb)) - skb->protocol = eth_type_trans(skb, priv->mesh_dev); - else - skb->protocol = eth_type_trans(skb, priv->dev); + if (priv->adapter->monitormode != WLAN_MONITOR_OFF) { + skb->protocol = eth_type_trans(skb, priv->rtap_net_dev); + } else { + if (priv->mesh_dev && IS_MESH_FRAME(skb)) + skb->protocol = eth_type_trans(skb, priv->mesh_dev); + else + skb->protocol = eth_type_trans(skb, priv->dev); + } skb->ip_summed = CHECKSUM_UNNECESSARY; - netif_rx(skb); } @@ -170,7 +173,7 @@ int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *skb) lbs_deb_enter(LBS_DEB_RX); - if (priv->adapter->linkmode == WLAN_LINKMODE_802_11) + if (priv->adapter->monitormode != WLAN_MONITOR_OFF) return process_rxed_802_11_packet(priv, skb); p_rx_pkt = (struct rxpackethdr *) skb->data; @@ -290,21 +293,22 @@ static u8 convert_mv_rate_to_radiotap(u8 rate) return 11; case 3: /* 11 Mbps */ return 22; - case 4: /* 6 Mbps */ + /* case 4: reserved */ + case 5: /* 6 Mbps */ return 12; - case 5: /* 9 Mbps */ + case 6: /* 9 Mbps */ return 18; - case 6: /* 12 Mbps */ + case 7: /* 12 Mbps */ return 24; - case 7: /* 18 Mbps */ + case 8: /* 18 Mbps */ return 36; - case 8: /* 24 Mbps */ + case 9: /* 24 Mbps */ return 48; - case 9: /* 36 Mbps */ + case 10: /* 36 Mbps */ return 72; - case 10: /* 48 Mbps */ + case 11: /* 48 Mbps */ return 96; - case 11: /* 54 Mbps */ + case 12: /* 54 Mbps */ return 108; } lbs_pr_alert("Invalid Marvell WLAN rate %i\n", rate); @@ -355,14 +359,13 @@ static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb) skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd)); /* create the exported radio header */ - switch (priv->adapter->radiomode) { - case WLAN_RADIOMODE_NONE: + if(priv->adapter->monitormode == WLAN_MONITOR_OFF) { /* no radio header */ /* chop the rxpd */ skb_pull(skb, sizeof(struct rxpd)); - break; + } - case WLAN_RADIOMODE_RADIOTAP: + else { /* radiotap header */ radiotap_hdr.hdr.it_version = 0; /* XXX must check this value for pad */ @@ -400,16 +403,6 @@ static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb) rx_radiotap_hdr)); memcpy(pradiotap_hdr, &radiotap_hdr, sizeof(struct rx_radiotap_hdr)); - break; - - default: - /* unknown header */ - lbs_pr_alert("Unknown radiomode %i\n", - priv->adapter->radiomode); - /* don't export any header */ - /* chop the rxpd */ - skb_pull(skb, sizeof(struct rxpd)); - break; } /* Take the data rate from the rxpd structure diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c index bb6e17506a4..fbec06c10dd 100644 --- a/drivers/net/wireless/libertas/tx.c +++ b/drivers/net/wireless/libertas/tx.c @@ -86,7 +86,7 @@ static int SendSinglePacket(wlan_private * priv, struct sk_buff *skb) plocaltxpd->tx_packet_location = cpu_to_le32(sizeof(struct txpd)); p802x_hdr = skb->data; - if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) { + if (priv->adapter->monitormode != WLAN_MONITOR_OFF) { /* locate radiotap header */ pradiotap_hdr = (struct tx_radiotap_hdr *)skb->data; @@ -106,7 +106,7 @@ static int SendSinglePacket(wlan_private * priv, struct sk_buff *skb) } /* copy destination address from 802.3 or 802.11 header */ - if (priv->adapter->linkmode == WLAN_LINKMODE_802_11) + if (priv->adapter->monitormode != WLAN_MONITOR_OFF) memcpy(plocaltxpd->tx_dest_addr_high, p802x_hdr + 4, ETH_ALEN); else memcpy(plocaltxpd->tx_dest_addr_high, p802x_hdr, ETH_ALEN); @@ -144,7 +144,7 @@ done: priv->stats.tx_errors++; } - if (!ret && priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) { + if (!ret && priv->adapter->monitormode != WLAN_MONITOR_OFF) { /* Keep the skb to echo it back once Tx feedback is received from FW */ skb_orphan(skb); @@ -252,7 +252,7 @@ void libertas_send_tx_feedback(wlan_private * priv) int txfail; int try_count; - if (adapter->radiomode != WLAN_RADIOMODE_RADIOTAP || + if (adapter->monitormode == WLAN_MONITOR_OFF || adapter->currenttxskb == NULL) return; diff --git a/drivers/net/wireless/libertas/wext.h b/drivers/net/wireless/libertas/wext.h index 5b0bbc99a21..6aa444c7de8 100644 --- a/drivers/net/wireless/libertas/wext.h +++ b/drivers/net/wireless/libertas/wext.h @@ -15,10 +15,7 @@ struct wlan_ioctl_regrdwr { u32 value; }; -#define WLAN_LINKMODE_802_3 0 -#define WLAN_LINKMODE_802_11 2 -#define WLAN_RADIOMODE_NONE 0 -#define WLAN_RADIOMODE_RADIOTAP 2 +#define WLAN_MONITOR_OFF 0 extern struct iw_handler_def libertas_handler_def; extern struct iw_handler_def mesh_handler_def; -- cgit v1.2.3-70-g09d2 From 5707708111ca6c4e9a1160acffdc98a98d95e462 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 13:17:41 -0400 Subject: [PATCH] libertas: fix assignment of WEP key type keytype is a u8 Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index cd3bddb243b..257d6443f6c 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -181,15 +181,13 @@ static int wlan_cmd_802_11_set_wep(wlan_private * priv, switch (pkey->len) { case KEY_LEN_WEP_40: - wep->keytype[i] = - cpu_to_le16(CMD_TYPE_WEP_40_BIT); + wep->keytype[i] = (u8)CMD_TYPE_WEP_40_BIT; memmove(&wep->keymaterial[i], pkey->key, pkey->len); lbs_deb_cmd("SET_WEP: add key %d (40 bit)\n", i); break; case KEY_LEN_WEP_104: - wep->keytype[i] = - cpu_to_le16(CMD_TYPE_WEP_104_BIT); + wep->keytype[i] = (u8)CMD_TYPE_WEP_104_BIT; memmove(&wep->keymaterial[i], pkey->key, pkey->len); lbs_deb_cmd("SET_WEP: add key %d (104 bit)\n", i); -- cgit v1.2.3-70-g09d2 From b031ac10264fa9b805d84b4a440407ac950390cf Mon Sep 17 00:00:00 2001 From: Eugene Teo Date: Thu, 2 Aug 2007 13:18:07 -0400 Subject: [PATCH] drivers/net/wireless/libertas/cmd.c: fix adapter->driver_lock dereference adapter is NULL if cmdnode is not. Signed-off-by: Eugene Teo Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 257d6443f6c..72e8e27a6fb 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -958,7 +958,7 @@ static int DownloadcommandToStation(wlan_private * priv, unsigned long flags; struct cmd_ds_command *cmdptr; wlan_adapter *adapter = priv->adapter; - int ret = 0; + int ret = -1; u16 cmdsize; u16 command; @@ -966,12 +966,6 @@ static int DownloadcommandToStation(wlan_private * priv, if (!adapter || !cmdnode) { lbs_deb_host("DNLD_CMD: adapter or cmdmode is NULL\n"); - if (cmdnode) { - spin_lock_irqsave(&adapter->driver_lock, flags); - __libertas_cleanup_and_insert_cmd(priv, cmdnode); - spin_unlock_irqrestore(&adapter->driver_lock, flags); - } - ret = -1; goto done; } @@ -982,7 +976,6 @@ static int DownloadcommandToStation(wlan_private * priv, lbs_deb_host("DNLD_CMD: cmdptr is NULL or zero\n"); __libertas_cleanup_and_insert_cmd(priv, cmdnode); spin_unlock_irqrestore(&adapter->driver_lock, flags); - ret = -1; goto done; } @@ -1008,7 +1001,6 @@ static int DownloadcommandToStation(wlan_private * priv, __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd); adapter->cur_cmd = NULL; spin_unlock_irqrestore(&adapter->driver_lock, flags); - ret = -1; goto done; } -- cgit v1.2.3-70-g09d2 From 2afc0c5d71a3dec6d35f3a234ed986d635ef41ad Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 13:19:04 -0400 Subject: [PATCH] libertas: push WEXT scan requests to a work queue Push WEXT scan requests to a workqueue and have each partial scan queue the next part, then only report results when the complete scan has finished. Full scans don't go through the work queue. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/assoc.h | 2 +- drivers/net/wireless/libertas/dev.h | 3 +- drivers/net/wireless/libertas/main.c | 10 ++- drivers/net/wireless/libertas/scan.c | 139 +++++++++++++++++++--------------- drivers/net/wireless/libertas/scan.h | 2 + 5 files changed, 91 insertions(+), 65 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/assoc.h b/drivers/net/wireless/libertas/assoc.h index 5e9c31f0932..e09b7490abb 100644 --- a/drivers/net/wireless/libertas/assoc.h +++ b/drivers/net/wireless/libertas/assoc.h @@ -17,7 +17,7 @@ static inline void wlan_postpone_association_work(wlan_private *priv) if (priv->adapter->surpriseremoved) return; cancel_delayed_work(&priv->assoc_work); - queue_delayed_work(priv->assoc_thread, &priv->assoc_work, ASSOC_DELAY); + queue_delayed_work(priv->work_thread, &priv->assoc_work, ASSOC_DELAY); } static inline void wlan_cancel_association_work(wlan_private *priv) diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 5697fec0cb1..762c4792774 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -148,9 +148,10 @@ struct _wlan_private { /** thread to service interrupts */ struct task_struct *main_thread; wait_queue_head_t waitq; + struct workqueue_struct *work_thread; + struct delayed_work scan_work; struct delayed_work assoc_work; - struct workqueue_struct *assoc_thread; struct work_struct sync_channel; /** Hardware access */ diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 9a46339ce47..bcd845060d4 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1269,9 +1269,10 @@ int libertas_activate_card(wlan_private *priv) goto done; } - priv->assoc_thread = - create_singlethread_workqueue("libertas_assoc"); + priv->work_thread = create_singlethread_workqueue("libertas_worker"); INIT_DELAYED_WORK(&priv->assoc_work, libertas_association_worker); + INIT_DELAYED_WORK(&priv->scan_work, libertas_scan_worker); + INIT_WORK(&priv->sync_channel, libertas_sync_channel); /* @@ -1305,7 +1306,7 @@ int libertas_activate_card(wlan_private *priv) err_init_fw: priv->hw_unregister_dev(priv); err_registerdev: - destroy_workqueue(priv->assoc_thread); + destroy_workqueue(priv->work_thread); /* Stop the thread servicing the interrupts */ wake_up_interruptible(&priv->waitq); kthread_stop(priv->main_thread); @@ -1426,8 +1427,9 @@ int libertas_remove_card(wlan_private *priv) unregister_netdev(dev); + cancel_delayed_work(&priv->scan_work); cancel_delayed_work(&priv->assoc_work); - destroy_workqueue(priv->assoc_thread); + destroy_workqueue(priv->work_thread); if (adapter->psmode == WLAN802_11POWERMODEMAX_PSP) { adapter->psmode = WLAN802_11POWERMODECAM; diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 8d4e1ee2739..e2e9ebcd834 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -314,6 +314,16 @@ static void wlan_scan_create_channel_list(wlan_private * priv, } } + +/* Delayed partial scan worker */ +void libertas_scan_worker(struct work_struct *work) +{ + wlan_private *priv = container_of(work, wlan_private, scan_work.work); + + wlan_scan_networks(priv, NULL, 0); +} + + /** * @brief Construct a wlan_scan_cmd_config structure to use in issue scan cmds * @@ -408,7 +418,6 @@ wlan_scan_setup_scan_config(wlan_private * priv, *pscancurrentonly = 0; if (puserscanin) { - /* Set the bss type scan filter, use adapter setting if unset */ pscancfgout->bsstype = puserscanin->bsstype ? puserscanin->bsstype : CMD_BSS_TYPE_ANY; @@ -468,59 +477,57 @@ wlan_scan_setup_scan_config(wlan_private * priv, */ *ppchantlvout = (struct mrvlietypes_chanlistparamset *) ptlvpos; - if (puserscanin && puserscanin->chanlist[0].channumber) { + if (!puserscanin || !puserscanin->chanlist[0].channumber) { + /* Create a default channel scan list */ + lbs_deb_scan("Scan: Creating full region channel list\n"); + wlan_scan_create_channel_list(priv, pscanchanlist, + *pfilteredscan); + goto out; + } - lbs_deb_scan("Scan: Using supplied channel list\n"); + lbs_deb_scan("Scan: Using supplied channel list\n"); + for (chanidx = 0; + chanidx < WLAN_IOCTL_USER_SCAN_CHAN_MAX + && puserscanin->chanlist[chanidx].channumber; chanidx++) { - for (chanidx = 0; - chanidx < WLAN_IOCTL_USER_SCAN_CHAN_MAX - && puserscanin->chanlist[chanidx].channumber; chanidx++) { + channel = puserscanin->chanlist[chanidx].channumber; + (pscanchanlist + chanidx)->channumber = channel; - channel = puserscanin->chanlist[chanidx].channumber; - (pscanchanlist + chanidx)->channumber = channel; + radiotype = puserscanin->chanlist[chanidx].radiotype; + (pscanchanlist + chanidx)->radiotype = radiotype; - radiotype = puserscanin->chanlist[chanidx].radiotype; - (pscanchanlist + chanidx)->radiotype = radiotype; + scantype = puserscanin->chanlist[chanidx].scantype; - scantype = puserscanin->chanlist[chanidx].scantype; + if (scantype == CMD_SCAN_TYPE_PASSIVE) { + (pscanchanlist + + chanidx)->chanscanmode.passivescan = 1; + } else { + (pscanchanlist + + chanidx)->chanscanmode.passivescan = 0; + } + if (puserscanin->chanlist[chanidx].scantime) { + scandur = puserscanin->chanlist[chanidx].scantime; + } else { if (scantype == CMD_SCAN_TYPE_PASSIVE) { - (pscanchanlist + - chanidx)->chanscanmode.passivescan = 1; - } else { - (pscanchanlist + - chanidx)->chanscanmode.passivescan = 0; - } - - if (puserscanin->chanlist[chanidx].scantime) { - scandur = - puserscanin->chanlist[chanidx].scantime; + scandur = MRVDRV_PASSIVE_SCAN_CHAN_TIME; } else { - if (scantype == CMD_SCAN_TYPE_PASSIVE) { - scandur = MRVDRV_PASSIVE_SCAN_CHAN_TIME; - } else { - scandur = MRVDRV_ACTIVE_SCAN_CHAN_TIME; - } + scandur = MRVDRV_ACTIVE_SCAN_CHAN_TIME; } - - (pscanchanlist + chanidx)->minscantime = - cpu_to_le16(scandur); - (pscanchanlist + chanidx)->maxscantime = - cpu_to_le16(scandur); } - /* Check if we are only scanning the current channel */ - if ((chanidx == 1) && (puserscanin->chanlist[0].channumber - == - priv->adapter->curbssparams.channel)) { - *pscancurrentonly = 1; - lbs_deb_scan("Scan: Scanning current channel only"); - } + (pscanchanlist + chanidx)->minscantime = + cpu_to_le16(scandur); + (pscanchanlist + chanidx)->maxscantime = + cpu_to_le16(scandur); + } - } else { - lbs_deb_scan("Scan: Creating full region channel list\n"); - wlan_scan_create_channel_list(priv, pscanchanlist, - *pfilteredscan); + /* Check if we are only scanning the current channel */ + if ((chanidx == 1) && + (puserscanin->chanlist[0].channumber == + priv->adapter->curbssparams.channel)) { + *pscancurrentonly = 1; + lbs_deb_scan("Scan: Scanning current channel only"); } out: @@ -604,12 +611,12 @@ static int wlan_scan_channel_list(wlan_private * priv, while (tlvidx < maxchanperscan && ptmpchan->channumber && !doneearly && scanned < 2) { - lbs_deb_scan( - "Scan: Chan(%3d), Radio(%d), mode(%d,%d), Dur(%d)\n", - ptmpchan->channumber, ptmpchan->radiotype, - ptmpchan->chanscanmode.passivescan, - ptmpchan->chanscanmode.disablechanfilt, - ptmpchan->maxscantime); + lbs_deb_scan("Scan: Chan(%3d), Radio(%d), mode(%d,%d), " + "Dur(%d)\n", + ptmpchan->channumber, ptmpchan->radiotype, + ptmpchan->chanscanmode.passivescan, + ptmpchan->chanscanmode.disablechanfilt, + ptmpchan->maxscantime); /* Copy the current channel TLV to the command being prepared */ memcpy(pchantlvout->chanscanparam + tlvidx, @@ -678,9 +685,18 @@ static int wlan_scan_channel_list(wlan_private * priv, done: priv->adapter->last_scanned_channel = ptmpchan->channumber; - /* Tell userspace the scan table has been updated */ - memset(&wrqu, 0, sizeof(union iwreq_data)); - wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL); + if (priv->adapter->last_scanned_channel) { + /* Schedule the next part of the partial scan */ + if (!full_scan && !priv->adapter->surpriseremoved) { + cancel_delayed_work(&priv->scan_work); + queue_delayed_work(priv->work_thread, &priv->scan_work, + msecs_to_jiffies(300)); + } + } else { + /* All done, tell userspace the scan table has been updated */ + memset(&wrqu, 0, sizeof(union iwreq_data)); + wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL); + } lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret); return ret; @@ -747,8 +763,8 @@ clear_selected_scan_list_entries(wlan_adapter * adapter, * @return 0 or < 0 if error */ int wlan_scan_networks(wlan_private * priv, - const struct wlan_ioctl_user_scan_cfg * puserscanin, - int full_scan) + const struct wlan_ioctl_user_scan_cfg * puserscanin, + int full_scan) { wlan_adapter * adapter = priv->adapter; struct mrvlietypes_chanlistparamset *pchantlvout; @@ -763,7 +779,13 @@ int wlan_scan_networks(wlan_private * priv, int i = 0; #endif - lbs_deb_enter(LBS_DEB_ASSOC); + lbs_deb_enter(LBS_DEB_SCAN); + + /* Cancel any partial outstanding partial scans if this scan + * is a full scan. + */ + if (full_scan && delayed_work_pending(&priv->scan_work)) + cancel_delayed_work(&priv->scan_work); scan_chan_list = kzalloc(sizeof(struct chanscanparamset) * WLAN_IOCTL_USER_SCAN_CHAN_MAX, GFP_KERNEL); @@ -1289,7 +1311,10 @@ int libertas_set_scan(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_SCAN); - wlan_scan_networks(priv, NULL, 0); + if (!delayed_work_pending(&priv->scan_work)) { + queue_delayed_work(priv->work_thread, &priv->scan_work, + msecs_to_jiffies(50)); + } if (adapter->surpriseremoved) return -1; @@ -1508,10 +1533,6 @@ int libertas_get_scan(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_ASSOC); - /* If we've got an uncompleted scan, schedule the next part */ - if (!adapter->nr_cmd_pending && adapter->last_scanned_channel) - wlan_scan_networks(priv, NULL, 0); - /* Update RSSI if current BSS is a locally created ad-hoc BSS */ if ((adapter->mode == IW_MODE_ADHOC) && adapter->adhoccreate) { libertas_prepare_and_send_command(priv, CMD_802_11_RSSI, 0, diff --git a/drivers/net/wireless/libertas/scan.h b/drivers/net/wireless/libertas/scan.h index 9bb1a435c28..c29c031bef8 100644 --- a/drivers/net/wireless/libertas/scan.h +++ b/drivers/net/wireless/libertas/scan.h @@ -210,4 +210,6 @@ int libertas_get_scan(struct net_device *dev, struct iw_request_info *info, int libertas_set_scan(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra); +void libertas_scan_worker(struct work_struct *work); + #endif /* _WLAN_SCAN_H */ -- cgit v1.2.3-70-g09d2 From 63f0023bc34073bea8452a4770540c954f98208f Mon Sep 17 00:00:00 2001 From: Luis Carlos Cobo Date: Thu, 2 Aug 2007 13:19:24 -0400 Subject: [PATCH] libertas: pass boot2 version to firmware Boot2 version used to be hardcoded in the uploaded firmware, this patch preserves the boot2 version before uploading firmware and sends it to the firmware again on resume. Signed-off-by: Luis Carlos Cobo Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 15 +++++++++++++++ drivers/net/wireless/libertas/dev.h | 1 + drivers/net/wireless/libertas/host.h | 2 ++ drivers/net/wireless/libertas/hostcmd.h | 6 ++++++ drivers/net/wireless/libertas/if_usb.c | 1 + drivers/net/wireless/libertas/main.c | 4 ++++ 6 files changed, 29 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 72e8e27a6fb..98092b99535 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -901,6 +901,17 @@ static int wlan_cmd_mesh_access(wlan_private * priv, return 0; } +static int wlan_cmd_set_boot2_ver(wlan_private * priv, + struct cmd_ds_command *cmd, + u16 cmd_action, void *pdata_buf) +{ + struct cmd_ds_set_boot2_ver *boot2_ver = &cmd->params.boot2_ver; + cmd->command = cpu_to_le16(CMD_SET_BOOT2_VER); + cmd->size = cpu_to_le16(sizeof(struct cmd_ds_set_boot2_ver) + S_DS_GEN); + boot2_ver->version = priv->boot2_version; + return 0; +} + void libertas_queue_cmd(wlan_adapter * adapter, struct cmd_ctrl_node *cmdnode, u8 addtail) { unsigned long flags; @@ -1372,6 +1383,10 @@ int libertas_prepare_and_send_command(wlan_private * priv, ret = wlan_cmd_mesh_access(priv, cmdptr, cmd_action, pdata_buf); break; + case CMD_SET_BOOT2_VER: + ret = wlan_cmd_set_boot2_ver(priv, cmdptr, cmd_action, pdata_buf); + break; + case CMD_GET_TSF: cmdptr->command = cpu_to_le16(CMD_GET_TSF); cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_get_tsf) + diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 762c4792774..a3c94d7388a 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -104,6 +104,7 @@ struct _wlan_private { int mesh_open; int infra_open; int mesh_autostart_enabled; + __le16 boot2_version; char name[DEV_NAME_LEN]; diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index 4ccdbf9c473..68fa11b3a2d 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -114,6 +114,8 @@ #define CMD_MESH_ACCESS 0x009b +#define CMD_SET_BOOT2_VER 0x00a5 + /* For the IEEE Power Save */ #define CMD_SUBCMD_ENTER_PS 0x0030 #define CMD_SUBCMD_EXIT_PS 0x0031 diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index 52884eaf2ed..e1045dc02cc 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -410,6 +410,11 @@ struct cmd_ds_802_11_monitor_mode { u16 mode; }; +struct cmd_ds_set_boot2_ver { + u16 action; + u16 version; +}; + struct cmd_ds_802_11_ps_mode { __le16 action; __le16 nullpktinterval; @@ -660,6 +665,7 @@ struct cmd_ds_command { struct cmd_ds_bt_access bt; struct cmd_ds_fwt_access fwt; struct cmd_ds_mesh_access mesh; + struct cmd_ds_set_boot2_ver boot2_ver; struct cmd_ds_get_tsf gettsf; struct cmd_ds_802_11_subscribe_event subscribe_event; } params; diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index d28802fb244..53d479688ff 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -219,6 +219,7 @@ static int if_usb_probe(struct usb_interface *intf, priv->hw_host_to_card = if_usb_host_to_card; priv->hw_get_int_status = if_usb_get_int_status; priv->hw_read_event_cause = if_usb_read_event_cause; + priv->boot2_version = udev->descriptor.bcdDevice; if (libertas_activate_card(priv)) goto err_activate_card; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index bcd845060d4..e20cd4e9ffc 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -981,6 +981,10 @@ static int wlan_setup_station_hw(wlan_private * priv) priv->mesh_autostart_enabled = 0; } + /* Set the boot2 version in firmware */ + ret = libertas_prepare_and_send_command(priv, CMD_SET_BOOT2_VER, + 0, CMD_OPTION_WAITFORRSP, 0, NULL); + ret = 0; done: lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret); -- cgit v1.2.3-70-g09d2 From 81173e34d454c353d9f0a53760609f3b9d30a311 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 13:19:56 -0400 Subject: [PATCH] libertas: fix misspelling in debug message Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/assoc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index ffeec2fa60a..3131afcf459 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -622,7 +622,7 @@ void libertas_association_worker(struct work_struct *work) } if (adapter->connect_status != LIBERTAS_CONNECTED) { - lbs_deb_assoc("ASSOC: assoication attempt unsuccessful, " + lbs_deb_assoc("ASSOC: association attempt unsuccessful, " "not connected.\n"); success = 0; } -- cgit v1.2.3-70-g09d2 From 5612c0140ac58b51209a24c8fd6a92ceb472aabe Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 13:20:12 -0400 Subject: [PATCH] libertas: ignore spurious mesh autostart events Don't trust the firmware to always send them at the right time, ignore them when the driver thinks mesh autostart is disabled. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmdresp.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 93bf63bad0f..c43b2725e5b 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -968,6 +968,11 @@ int libertas_process_event(wlan_private * priv) break; case MACREG_INT_CODE_MESH_AUTO_STARTED: + /* Ignore spurious autostart events if autostart is disabled */ + if (!priv->mesh_autostart_enabled) { + lbs_pr_info("EVENT: MESH_AUTO_STARTED (ignoring)\n"); + break; + } lbs_pr_info("EVENT: MESH_AUTO_STARTED\n"); adapter->connect_status = LIBERTAS_CONNECTED; if (priv->mesh_open == 1) { -- cgit v1.2.3-70-g09d2 From c7fdf26995d5d6ebf1c3314ad001b9a4983c3f04 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Aug 2007 13:20:29 -0400 Subject: [PATCH] libertas: better descriptions for association errors Describe the association response status code the firmware returns, based on mail to libertas-dev from Ronak. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/join.c | 53 +++++++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c index ccb0df1967f..ce49d3f2561 100644 --- a/drivers/net/wireless/libertas/join.c +++ b/drivers/net/wireless/libertas/join.c @@ -700,6 +700,7 @@ int libertas_ret_80211_associate(wlan_private * priv, union iwreq_data wrqu; struct ieeetypes_assocrsp *passocrsp; struct bss_descriptor * bss; + u16 status_code; lbs_deb_enter(LBS_DEB_JOIN); @@ -712,12 +713,56 @@ int libertas_ret_80211_associate(wlan_private * priv, passocrsp = (struct ieeetypes_assocrsp *) & resp->params; - if (le16_to_cpu(passocrsp->statuscode)) { - libertas_mac_event_disconnected(priv); + /* + * Older FW versions map the IEEE 802.11 Status Code in the association + * response to the following values returned in passocrsp->statuscode: + * + * IEEE Status Code Marvell Status Code + * 0 -> 0x0000 ASSOC_RESULT_SUCCESS + * 13 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED + * 14 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED + * 15 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED + * 16 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED + * others -> 0x0003 ASSOC_RESULT_REFUSED + * + * Other response codes: + * 0x0001 -> ASSOC_RESULT_INVALID_PARAMETERS (unused) + * 0x0002 -> ASSOC_RESULT_TIMEOUT (internal timer expired waiting for + * association response from the AP) + */ - lbs_deb_join("ASSOC_RESP: Association failed, status code = %d\n", - le16_to_cpu(passocrsp->statuscode)); + status_code = le16_to_cpu(passocrsp->statuscode); + switch (status_code) { + case 0x00: + lbs_deb_join("ASSOC_RESP: Association succeeded\n"); + break; + case 0x01: + lbs_deb_join("ASSOC_RESP: Association failed; invalid " + "parameters (status code %d)\n", status_code); + break; + case 0x02: + lbs_deb_join("ASSOC_RESP: Association failed; internal timer " + "expired while waiting for the AP (status code %d)" + "\n", status_code); + break; + case 0x03: + lbs_deb_join("ASSOC_RESP: Association failed; association " + "was refused by the AP (status code %d)\n", + status_code); + break; + case 0x04: + lbs_deb_join("ASSOC_RESP: Association failed; authentication " + "was refused by the AP (status code %d)\n", + status_code); + break; + default: + lbs_deb_join("ASSOC_RESP: Association failed; reason unknown " + "(status code %d)\n", status_code); + break; + } + if (status_code) { + libertas_mac_event_disconnected(priv); ret = -1; goto done; } -- cgit v1.2.3-70-g09d2 From 8362cd413e8116306fafbaf414f0419db0595142 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 3 Aug 2007 09:40:55 -0400 Subject: [PATCH] libertas: fix sparse-reported problems A few fields being converted to the wrong sized type, and a few missed endian conversions. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/11d.c | 2 +- drivers/net/wireless/libertas/cmdresp.c | 4 ++-- drivers/net/wireless/libertas/debugfs.c | 2 +- drivers/net/wireless/libertas/if_usb.c | 30 +++++++++++++----------------- drivers/net/wireless/libertas/rx.c | 4 ++-- drivers/net/wireless/libertas/wext.c | 8 ++++---- 6 files changed, 23 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/11d.c b/drivers/net/wireless/libertas/11d.c index 8b366ef2fe9..9cf0211de67 100644 --- a/drivers/net/wireless/libertas/11d.c +++ b/drivers/net/wireless/libertas/11d.c @@ -543,7 +543,7 @@ int libertas_cmd_802_11d_domain_info(wlan_private * priv, nr_subband * sizeof(struct ieeetypes_subbandset)); cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) + - domain->header.len + + le16_to_cpu(domain->header.len) + sizeof(struct mrvlietypesheader) + S_DS_GEN); } else { diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index c43b2725e5b..4c36e63ae7b 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -812,8 +812,8 @@ int libertas_process_rx_command(wlan_private * priv) if (adapter->cur_cmd->cmdflags & CMD_F_HOSTCMD) { /* Copy the response back to response buffer */ - memcpy(adapter->cur_cmd->pdata_buf, resp, resp->size); - + memcpy(adapter->cur_cmd->pdata_buf, resp, + le16_to_cpu(resp->size)); adapter->cur_cmd->cmdflags &= ~CMD_F_HOSTCMD; } diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c index 63e747ac49d..6d95148e872 100644 --- a/drivers/net/wireless/libertas/debugfs.c +++ b/drivers/net/wireless/libertas/debugfs.c @@ -510,7 +510,7 @@ static u16 libertas_get_events_bitmap(wlan_private *priv) return 0; } - if (pcmdptr->command != CMD_RET(CMD_802_11_SUBSCRIBE_EVENT)) { + if (le16_to_cpu(pcmdptr->command) != CMD_RET(CMD_802_11_SUBSCRIBE_EVENT)) { lbs_pr_err("command response incorrect!\n"); kfree(response_buf); return 0; diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index 53d479688ff..364eae374b9 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -639,11 +639,13 @@ static void if_usb_receive(struct urb *urb) int recvlength = urb->actual_length; u8 *recvbuff = NULL; - u32 recvtype; + u32 recvtype = 0; lbs_deb_enter(LBS_DEB_USB); if (recvlength) { + __le32 tmp; + if (urb->status) { lbs_deb_usbd(&cardp->udev->dev, "URB status is failed\n"); @@ -652,18 +654,14 @@ static void if_usb_receive(struct urb *urb) } recvbuff = skb->data + IPFIELD_ALIGN_OFFSET; - memcpy(&recvtype, recvbuff, sizeof(u32)); - lbs_deb_usbd(&cardp->udev->dev, - "Recv length = 0x%x\n", recvlength); + memcpy(&tmp, recvbuff, sizeof(u32)); + recvtype = le32_to_cpu(tmp); lbs_deb_usbd(&cardp->udev->dev, - "Receive type = 0x%X\n", recvtype); - recvtype = le32_to_cpu(recvtype); - lbs_deb_usbd(&cardp->udev->dev, - "Receive type after = 0x%X\n", recvtype); + "Recv length = 0x%x, Recv type = 0x%X\n", + recvlength, recvtype); } else if (urb->status) goto rx_exit; - switch (recvtype) { case CMD_TYPE_DATA: process_cmdtypedata(recvlength, skb, cardp, priv); @@ -691,6 +689,8 @@ static void if_usb_receive(struct urb *urb) spin_unlock(&priv->adapter->driver_lock); goto rx_exit; default: + lbs_deb_usbd(&cardp->udev->dev, "Unknown command type 0x%X\n", + recvtype); kfree_skb(skb); break; } @@ -711,21 +711,19 @@ rx_exit: */ static int if_usb_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb) { - int ret = -1; - u32 tmp; struct usb_card_rec *cardp = (struct usb_card_rec *)priv->card; lbs_deb_usbd(&cardp->udev->dev,"*** type = %u\n", type); lbs_deb_usbd(&cardp->udev->dev,"size after = %d\n", nb); if (type == MVMS_CMD) { - tmp = cpu_to_le32(CMD_TYPE_REQUEST); + __le32 tmp = cpu_to_le32(CMD_TYPE_REQUEST); priv->dnld_sent = DNLD_CMD_SENT; memcpy(cardp->bulk_out_buffer, (u8 *) & tmp, MESSAGE_HEADER_LEN); } else { - tmp = cpu_to_le32(CMD_TYPE_DATA); + __le32 tmp = cpu_to_le32(CMD_TYPE_DATA); priv->dnld_sent = DNLD_DATA_SENT; memcpy(cardp->bulk_out_buffer, (u8 *) & tmp, MESSAGE_HEADER_LEN); @@ -733,10 +731,8 @@ static int if_usb_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 n memcpy((cardp->bulk_out_buffer + MESSAGE_HEADER_LEN), payload, nb); - ret = - usb_tx_block(priv, cardp->bulk_out_buffer, nb + MESSAGE_HEADER_LEN); - - return ret; + return usb_tx_block(priv, cardp->bulk_out_buffer, + nb + MESSAGE_HEADER_LEN); } /* called with adapter->driver_lock held */ diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c index 09def943b91..0420e5b9ff9 100644 --- a/drivers/net/wireless/libertas/rx.c +++ b/drivers/net/wireless/libertas/rx.c @@ -370,8 +370,8 @@ static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb) radiotap_hdr.hdr.it_version = 0; /* XXX must check this value for pad */ radiotap_hdr.hdr.it_pad = 0; - radiotap_hdr.hdr.it_len = sizeof(struct rx_radiotap_hdr); - radiotap_hdr.hdr.it_present = RX_RADIOTAP_PRESENT; + radiotap_hdr.hdr.it_len = cpu_to_le16 (sizeof(struct rx_radiotap_hdr)); + radiotap_hdr.hdr.it_present = cpu_to_le32 (RX_RADIOTAP_PRESENT); /* unknown values */ radiotap_hdr.flags = 0; radiotap_hdr.chan_freq = 0; diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 15395bf0a2a..3f628223bc6 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -872,7 +872,7 @@ static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev) /* Quality by TX errors */ priv->wstats.discard.retries = priv->stats.tx_errors; - tx_retries = le16_to_cpu(adapter->logmsg.retry); + tx_retries = le32_to_cpu(adapter->logmsg.retry); if (tx_retries > 75) tx_qual = (90 - tx_retries) * POOR / 15; @@ -888,10 +888,10 @@ static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev) (PERFECT - VERY_GOOD) / 50 + VERY_GOOD; quality = min(quality, tx_qual); - priv->wstats.discard.code = le16_to_cpu(adapter->logmsg.wepundecryptable); - priv->wstats.discard.fragment = le16_to_cpu(adapter->logmsg.rxfrag); + priv->wstats.discard.code = le32_to_cpu(adapter->logmsg.wepundecryptable); + priv->wstats.discard.fragment = le32_to_cpu(adapter->logmsg.rxfrag); priv->wstats.discard.retries = tx_retries; - priv->wstats.discard.misc = le16_to_cpu(adapter->logmsg.ackfailure); + priv->wstats.discard.misc = le32_to_cpu(adapter->logmsg.ackfailure); /* Calculate quality */ priv->wstats.qual.qual = min_t(u8, quality, 100); -- cgit v1.2.3-70-g09d2 From 7856a541ad83e84d260abb652c39299972ba310c Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 3 Aug 2007 09:43:03 -0400 Subject: [PATCH] libertas: bump driver version Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index e20cd4e9ffc..f0213eca680 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -23,7 +23,7 @@ #include "assoc.h" #include "join.h" -#define DRIVER_RELEASE_VERSION "322.p1" +#define DRIVER_RELEASE_VERSION "323.p0" const char libertas_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION #ifdef DEBUG "-dbg" -- cgit v1.2.3-70-g09d2 From af096046f63a065b692018cd4b8f5e7525c3e56a Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Tue, 24 Jul 2007 01:30:36 -0400 Subject: [netdrvr] skfp: remove a bunch of dead code The driver has not compiled in anything except PCI support for many years (see drivers/net/skfp/Makefile). This driver is also unmaintained for many years, so arguments for keeping the cross-OS, cross-bus (ISA, EISA, MCA) code do not exist. Signed-off-by: Jeff Garzik --- drivers/net/skfp/drvfbi.c | 693 +------------------------------------ drivers/net/skfp/h/mbuf.h | 4 - drivers/net/skfp/h/skfbi.h | 783 +----------------------------------------- drivers/net/skfp/h/skfbiinc.h | 26 -- drivers/net/skfp/h/targethw.h | 33 +- drivers/net/skfp/hwt.c | 42 +-- 6 files changed, 8 insertions(+), 1573 deletions(-) (limited to 'drivers') diff --git a/drivers/net/skfp/drvfbi.c b/drivers/net/skfp/drvfbi.c index 4fe624b0dd2..be2ee6519ef 100644 --- a/drivers/net/skfp/drvfbi.c +++ b/drivers/net/skfp/drvfbi.c @@ -43,25 +43,6 @@ static const char ID_sccs[] = "@(#)drvfbi.c 1.63 99/02/11 (C) SK " ; /* * valid configuration values are: */ -#ifdef ISA -const int opt_ints[] = {8, 3, 4, 5, 9, 10, 11, 12, 15} ; -const int opt_iops[] = {8, - 0x100, 0x120, 0x180, 0x1a0, 0x220, 0x240, 0x320, 0x340}; -const int opt_dmas[] = {4, 3, 5, 6, 7} ; -const int opt_eproms[] = {15, 0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, - 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc} ; -#endif -#ifdef EISA -const int opt_ints[] = {5, 9, 10, 11} ; -const int opt_dmas[] = {0, 5, 6, 7} ; -const int opt_eproms[] = {0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, - 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc} ; -#endif - -#ifdef MCA -int opt_ints[] = {3, 11, 10, 9} ; /* FM1 */ -int opt_eproms[] = {0, 0xc4, 0xc8, 0xcc, 0xd0, 0xd4, 0xd8, 0xdc} ; -#endif /* MCA */ /* * xPOS_ID:xxxx @@ -78,17 +59,9 @@ int opt_eproms[] = {0, 0xc4, 0xc8, 0xcc, 0xd0, 0xd4, 0xd8, 0xdc} ; */ #ifndef MULT_OEM #ifndef OEM_CONCEPT -#ifndef MCA const u_char oem_id[] = "xPOS_ID:xxxx" ; -#else -const u_char oem_id[] = "xPOSID1:xxxx" ; /* FM1 card id. */ -#endif #else /* OEM_CONCEPT */ -#ifndef MCA const u_char oem_id[] = OEM_ID ; -#else -const u_char oem_id[] = OEM_ID1 ; /* FM1 card id. */ -#endif /* MCA */ #endif /* OEM_CONCEPT */ #define ID_BYTE0 8 #define OEMID(smc,i) oem_id[ID_BYTE0 + i] @@ -109,23 +82,6 @@ extern int AIX_vpdReadByte() ; /* Prototype of a local function. */ static void smt_stop_watchdog(struct s_smc *smc); -#ifdef MCA -static int read_card_id() ; -static void DisableSlotAccess() ; -static void EnableSlotAccess() ; -#ifdef AIX -extern int attach_POS_addr() ; -extern int detach_POS_addr() ; -extern u_char read_POS() ; -extern void write_POS() ; -extern int AIX_vpdReadByte() ; -#else -#define read_POS(smc,a1,a2) ((u_char) inp(a1)) -#define write_POS(smc,a1,a2,a3) outp((a1),(a3)) -#endif -#endif /* MCA */ - - /* * FDDI card reset */ @@ -139,51 +95,6 @@ static void card_start(struct s_smc *smc) smt_stop_watchdog(smc) ; -#ifdef ISA - outpw(CSR_A,0) ; /* reset for all chips */ - for (i = 10 ; i ; i--) /* delay for PLC's */ - (void)inpw(ISR_A) ; - OUT_82c54_TIMER(3,COUNT(2) | RW_OP(3) | TMODE(2)) ; - /* counter 2, mode 2 */ - OUT_82c54_TIMER(2,97) ; /* LSB */ - OUT_82c54_TIMER(2,0) ; /* MSB ( 15.6 us ) */ - outpw(CSR_A,CS_CRESET) ; -#endif -#ifdef EISA - outpw(CSR_A,0) ; /* reset for all chips */ - for (i = 10 ; i ; i--) /* delay for PLC's */ - (void)inpw(ISR_A) ; - outpw(CSR_A,CS_CRESET) ; - smc->hw.led = (2<<6) ; - outpw(CSR_A,CS_CRESET | smc->hw.led) ; -#endif -#ifdef MCA - outp(ADDR(CARD_DIS),0) ; /* reset for all chips */ - for (i = 10 ; i ; i--) /* delay for PLC's */ - (void)inpw(ISR_A) ; - outp(ADDR(CARD_EN),0) ; - /* first I/O after reset must not be a access to FORMAC or PLC */ - - /* - * bus timeout (MCA) - */ - OUT_82c54_TIMER(3,COUNT(2) | RW_OP(3) | TMODE(3)) ; - /* counter 2, mode 3 */ - OUT_82c54_TIMER(2,(2*24)) ; /* 3.9 us * 2 square wave */ - OUT_82c54_TIMER(2,0) ; /* MSB */ - - /* POS 102 indicated an activ Check Line or Buss Error monitoring */ - if (inpw(CSA_A) & (POS_EN_CHKINT | POS_EN_BUS_ERR)) { - outp(ADDR(IRQ_CHCK_EN),0) ; - } - - if (!((i = inpw(CSR_A)) & CS_SAS)) { - if (!(i & CS_BYSTAT)) { - outp(ADDR(BYPASS(STAT_INS)),0) ;/* insert station */ - } - } - outpw(LEDR_A,LED_1) ; /* yellow */ -#endif /* MCA */ #ifdef PCI /* * make sure no transfer activity is pending @@ -253,15 +164,7 @@ void card_stop(struct s_smc *smc) { smt_stop_watchdog(smc) ; smc->hw.mac_ring_is_up = 0 ; /* ring down */ -#ifdef ISA - outpw(CSR_A,0) ; /* reset for all chips */ -#endif -#ifdef EISA - outpw(CSR_A,0) ; /* reset for all chips */ -#endif -#ifdef MCA - outp(ADDR(CARD_DIS),0) ; /* reset for all chips */ -#endif + #ifdef PCI /* * make sure no transfer activity is pending @@ -284,60 +187,6 @@ void mac1_irq(struct s_smc *smc, u_short stu, u_short stl) { int restart_tx = 0 ; again: -#ifndef PCI -#ifndef ISA -/* - * FORMAC+ bug modified the queue pointer if many read/write accesses happens!? - */ - if (stl & (FM_SPCEPDS | /* parit/coding err. syn.q.*/ - FM_SPCEPDA0 | /* parit/coding err. a.q.0 */ - FM_SPCEPDA1 | /* parit/coding err. a.q.1 */ - FM_SPCEPDA2)) { /* parit/coding err. a.q.2 */ - SMT_PANIC(smc,SMT_E0132, SMT_E0132_MSG) ; - } - if (stl & (FM_STBURS | /* tx buffer underrun syn.q.*/ - FM_STBURA0 | /* tx buffer underrun a.q.0 */ - FM_STBURA1 | /* tx buffer underrun a.q.1 */ - FM_STBURA2)) { /* tx buffer underrun a.q.2 */ - SMT_PANIC(smc,SMT_E0133, SMT_E0133_MSG) ; - } -#endif - if ( (stu & (FM_SXMTABT | /* transmit abort */ -#ifdef SYNC - FM_STXABRS | /* syn. tx abort */ -#endif /* SYNC */ - FM_STXABRA0)) || /* asyn. tx abort */ - (stl & (FM_SQLCKS | /* lock for syn. q. */ - FM_SQLCKA0)) ) { /* lock for asyn. q. */ - formac_tx_restart(smc) ; /* init tx */ - restart_tx = 1 ; - stu = inpw(FM_A(FM_ST1U)) ; - stl = inpw(FM_A(FM_ST1L)) ; - stu &= ~ (FM_STECFRMA0 | FM_STEFRMA0 | FM_STEFRMS) ; - if (stu || stl) - goto again ; - } - -#ifndef SYNC - if (stu & (FM_STECFRMA0 | /* end of chain asyn tx */ - FM_STEFRMA0)) { /* end of frame asyn tx */ - /* free tx_queue */ - smc->hw.n_a_send = 0 ; - if (++smc->hw.fp.tx_free < smc->hw.fp.tx_max) { - start_next_send(smc); - } - restart_tx = 1 ; - } -#else /* SYNC */ - if (stu & (FM_STEFRMA0 | /* end of asyn tx */ - FM_STEFRMS)) { /* end of sync tx */ - restart_tx = 1 ; - } -#endif /* SYNC */ - if (restart_tx) - llc_restart_tx(smc) ; -} -#else /* PCI */ /* * parity error: note encoding error is not possible in tag mode @@ -378,7 +227,7 @@ again: if (restart_tx) llc_restart_tx(smc) ; } -#endif /* PCI */ + /* * interrupt source= plc1 * this function is called in nwfbisr.asm @@ -387,10 +236,6 @@ void plc1_irq(struct s_smc *smc) { u_short st = inpw(PLC(PB,PL_INTR_EVENT)) ; -#if (defined(ISA) || defined(EISA)) - /* reset PLC Int. bits */ - outpw(PLC1_I,inpw(PLC1_I)) ; -#endif plc_irq(smc,PB,st) ; } @@ -402,10 +247,6 @@ void plc2_irq(struct s_smc *smc) { u_short st = inpw(PLC(PA,PL_INTR_EVENT)) ; -#if (defined(ISA) || defined(EISA)) - /* reset PLC Int. bits */ - outpw(PLC2_I,inpw(PLC2_I)) ; -#endif plc_irq(smc,PA,st) ; } @@ -446,43 +287,15 @@ void read_address(struct s_smc *smc, u_char *mac_addr) char PmdType ; int i ; -#if (defined(ISA) || defined(MCA)) - for (i = 0; i < 4 ;i++) { /* read mac address from board */ - smc->hw.fddi_phys_addr.a[i] = - bitrev8(inpw(PR_A(i+SA_MAC))); - } - for (i = 4; i < 6; i++) { - smc->hw.fddi_phys_addr.a[i] = - bitrev8(inpw(PR_A(i+SA_MAC+PRA_OFF))); - } -#endif -#ifdef EISA - /* - * Note: We get trouble on an Alpha machine if we make a inpw() - * instead of inp() - */ - for (i = 0; i < 4 ;i++) { /* read mac address from board */ - smc->hw.fddi_phys_addr.a[i] = - bitrev8(inp(PR_A(i+SA_MAC))); - } - for (i = 4; i < 6; i++) { - smc->hw.fddi_phys_addr.a[i] = - bitrev8(inp(PR_A(i+SA_MAC+PRA_OFF))); - } -#endif #ifdef PCI for (i = 0; i < 6; i++) { /* read mac address from board */ smc->hw.fddi_phys_addr.a[i] = bitrev8(inp(ADDR(B2_MAC_0+i))); } #endif -#ifndef PCI - ConnectorType = inpw(PR_A(SA_PMD_TYPE)) & 0xff ; - PmdType = inpw(PR_A(SA_PMD_TYPE+1)) & 0xff ; -#else + ConnectorType = inp(ADDR(B2_CONN_TYP)) ; PmdType = inp(ADDR(B2_PMD_TYP)) ; -#endif smc->y[PA].pmd_type[PMD_SK_CONN] = smc->y[PB].pmd_type[PMD_SK_CONN] = ConnectorType ; @@ -512,20 +325,12 @@ void init_board(struct s_smc *smc, u_char *mac_addr) card_start(smc) ; read_address(smc,mac_addr) ; -#ifndef PCI - if (inpw(CSR_A) & CS_SAS) -#else if (!(inp(ADDR(B0_DAS)) & DAS_AVAIL)) -#endif smc->s.sas = SMT_SAS ; /* Single att. station */ else smc->s.sas = SMT_DAS ; /* Dual att. station */ -#ifndef PCI - if (inpw(CSR_A) & CS_BYSTAT) -#else if (!(inp(ADDR(B0_DAS)) & DAS_BYP_ST)) -#endif smc->mib.fddiSMTBypassPresent = 0 ; /* without opt. bypass */ else @@ -538,42 +343,12 @@ void init_board(struct s_smc *smc, u_char *mac_addr) */ void sm_pm_bypass_req(struct s_smc *smc, int mode) { -#if (defined(ISA) || defined(EISA)) - int csra_v ; -#endif - DB_ECMN(1,"ECM : sm_pm_bypass_req(%s)\n",(mode == BP_INSERT) ? "BP_INSERT" : "BP_DEINSERT",0) ; if (smc->s.sas != SMT_DAS) return ; -#if (defined(ISA) || defined(EISA)) - - csra_v = inpw(CSR_A) & ~CS_BYPASS ; -#ifdef EISA - csra_v |= smc->hw.led ; -#endif - - switch(mode) { - case BP_INSERT : - outpw(CSR_A,csra_v | CS_BYPASS) ; - break ; - case BP_DEINSERT : - outpw(CSR_A,csra_v) ; - break ; - } -#endif /* ISA / EISA */ -#ifdef MCA - switch(mode) { - case BP_INSERT : - outp(ADDR(BYPASS(STAT_INS)),0) ;/* insert station */ - break ; - case BP_DEINSERT : - outp(ADDR(BYPASS(STAT_BYP)),0) ; /* bypass station */ - break ; - } -#endif #ifdef PCI switch(mode) { case BP_INSERT : @@ -591,31 +366,14 @@ void sm_pm_bypass_req(struct s_smc *smc, int mode) */ int sm_pm_bypass_present(struct s_smc *smc) { -#ifndef PCI - return( (inpw(CSR_A) & CS_BYSTAT) ? FALSE : TRUE ) ; -#else return( (inp(ADDR(B0_DAS)) & DAS_BYP_ST) ? TRUE: FALSE) ; -#endif } void plc_clear_irq(struct s_smc *smc, int p) { SK_UNUSED(p) ; -#if (defined(ISA) || defined(EISA)) - switch (p) { - case PA : - /* reset PLC Int. bits */ - outpw(PLC2_I,inpw(PLC2_I)) ; - break ; - case PB : - /* reset PLC Int. bits */ - outpw(PLC1_I,inpw(PLC1_I)) ; - break ; - } -#else SK_UNUSED(smc) ; -#endif } @@ -645,51 +403,6 @@ static void led_indication(struct s_smc *smc, int led_event) phy = &smc->y[PB] ; mib_b = phy->mib ; -#ifdef EISA - /* Ring up = yellow led OFF*/ - if (led_event == LED_Y_ON) { - smc->hw.led |= CS_LED_1 ; - } - else if (led_event == LED_Y_OFF) { - smc->hw.led &= ~CS_LED_1 ; - } - else { - /* Link at Port A or B = green led ON */ - if (mib_a->fddiPORTPCMState == PC8_ACTIVE || - mib_b->fddiPORTPCMState == PC8_ACTIVE) { - smc->hw.led |= CS_LED_0 ; - } - else { - smc->hw.led &= ~CS_LED_0 ; - } - } -#endif -#ifdef MCA - led_state = inpw(LEDR_A) ; - - /* Ring up = yellow led OFF*/ - if (led_event == LED_Y_ON) { - led_state |= LED_1 ; - } - else if (led_event == LED_Y_OFF) { - led_state &= ~LED_1 ; - } - else { - led_state &= ~(LED_2|LED_0) ; - - /* Link at Port A = green led A ON */ - if (mib_a->fddiPORTPCMState == PC8_ACTIVE) { - led_state |= LED_2 ; - } - - /* Link at Port B/S = green led B ON */ - if (mib_b->fddiPORTPCMState == PC8_ACTIVE) { - led_state |= LED_0 ; - } - } - - outpw(LEDR_A, led_state) ; -#endif /* MCA */ #ifdef PCI led_state = 0 ; @@ -824,406 +537,6 @@ int set_oi_id_def(struct s_smc *smc) } #endif /* MULT_OEM */ - -#ifdef MCA -/************************ - * - * BEGIN_MANUAL_ENTRY() - * - * exist_board - * - * Check if an MCA board is present in the specified slot. - * - * int exist_board( - * struct s_smc *smc, - * int slot) ; - * In - * smc - A pointer to the SMT Context struct. - * - * slot - The number of the slot to inspect. - * Out - * 0 = No adapter present. - * 1 = Found FM1 adapter. - * - * Pseudo - * Read MCA ID - * for all valid OEM_IDs - * compare with ID read - * if equal, return 1 - * return(0 - * - * Note - * The smc pointer must be valid now. - * - * END_MANUAL_ENTRY() - * - ************************/ -#define LONG_CARD_ID(lo, hi) ((((hi) & 0xff) << 8) | ((lo) & 0xff)) -int exist_board(struct s_smc *smc, int slot) -{ -#ifdef MULT_OEM - SK_LOC_DECL(u_char,id[2]) ; - int idi ; -#endif /* MULT_OEM */ - - /* No longer valid. */ - if (smc == NULL) - return(0) ; - -#ifndef MULT_OEM - if (read_card_id(smc, slot) - == LONG_CARD_ID(OEMID(smc,0), OEMID(smc,1))) - return (1) ; /* Found FM adapter. */ - -#else /* MULT_OEM */ - idi = read_card_id(smc, slot) ; - id[0] = idi & 0xff ; - id[1] = idi >> 8 ; - - smc->hw.oem_id = (struct s_oem_ids *) &oem_ids[0] ; - for (; smc->hw.oem_id->oi_status != OI_STAT_LAST; smc->hw.oem_id++) { - if (smc->hw.oem_id->oi_status < smc->hw.oem_min_status) - continue ; - - if (is_equal_num(&id[0],&OEMID(smc,0),2)) - return (1) ; - } -#endif /* MULT_OEM */ - return (0) ; /* No adapter found. */ -} - -/************************ - * - * read_card_id - * - * Read the MCA card id from the specified slot. - * In - * smc - A pointer to the SMT Context struct. - * CAVEAT: This pointer may be NULL and *must not* be used within this - * function. It's only purpose is for drivers that need some information - * for the inp() and outp() macros. - * - * slot - The number of the slot for which the card id is returned. - * Out - * Returns the card id read from the specified slot. If an illegal slot - * number is specified, the function returns zero. - * - ************************/ -static int read_card_id(struct s_smc *smc, int slot) -/* struct s_smc *smc ; Do not use. */ -{ - int card_id ; - - SK_UNUSED(smc) ; /* Make LINT happy. */ - if ((slot < 1) || (slot > 15)) /* max 16 slots, 0 = motherboard */ - return (0) ; /* Illegal slot number specified. */ - - EnableSlotAccess(smc, slot) ; - - card_id = ((read_POS(smc,POS_ID_HIGH,slot - 1) & 0xff) << 8) | - (read_POS(smc,POS_ID_LOW,slot - 1) & 0xff) ; - - DisableSlotAccess(smc) ; - - return (card_id) ; -} - -/************************ - * - * BEGIN_MANUAL_ENTRY() - * - * get_board_para - * - * Get adapter configuration information. Fill all board specific - * parameters within the 'smc' structure. - * - * int get_board_para( - * struct s_smc *smc, - * int slot) ; - * In - * smc - A pointer to the SMT Context struct, to which this function will - * write some adapter configuration data. - * - * slot - The number of the slot, in which the adapter is installed. - * Out - * 0 = No adapter present. - * 1 = Ok. - * 2 = Adapter present, but card enable bit not set. - * - * END_MANUAL_ENTRY() - * - ************************/ -int get_board_para(struct s_smc *smc, int slot) -{ - int val ; - int i ; - - /* Check if adapter present & get type of adapter. */ - switch (exist_board(smc, slot)) { - case 0: /* Adapter not present. */ - return (0) ; - case 1: /* FM Rev. 1 */ - smc->hw.rev = FM1_REV ; - smc->hw.VFullRead = 0x0a ; - smc->hw.VFullWrite = 0x05 ; - smc->hw.DmaWriteExtraBytes = 8 ; /* 2 extra words. */ - break ; - } - smc->hw.slot = slot ; - - EnableSlotAccess(smc, slot) ; - - if (!(read_POS(smc,POS_102, slot - 1) & POS_CARD_EN)) { - DisableSlotAccess(smc) ; - return (2) ; /* Card enable bit not set. */ - } - - val = read_POS(smc,POS_104, slot - 1) ; /* I/O, IRQ */ - -#ifndef MEM_MAPPED_IO /* is defined by the operating system */ - i = val & POS_IOSEL ; /* I/O base addr. (0x0200 .. 0xfe00) */ - smc->hw.iop = (i + 1) * 0x0400 - 0x200 ; -#endif - i = ((val & POS_IRQSEL) >> 6) & 0x03 ; /* IRQ <0, 1> */ - smc->hw.irq = opt_ints[i] ; - - /* FPROM base addr. */ - i = ((read_POS(smc,POS_103, slot - 1) & POS_MSEL) >> 4) & 0x07 ; - smc->hw.eprom = opt_eproms[i] ; - - DisableSlotAccess(smc) ; - - /* before this, the smc->hw.iop must be set !!! */ - smc->hw.slot_32 = inpw(CSF_A) & SLOT_32 ; - - return (1) ; -} - -/* Enable access to specified MCA slot. */ -static void EnableSlotAccess(struct s_smc *smc, int slot) -{ - SK_UNUSED(slot) ; - -#ifndef AIX - SK_UNUSED(smc) ; - - /* System mode. */ - outp(POS_SYS_SETUP, POS_SYSTEM) ; - - /* Select slot. */ - outp(POS_CHANNEL_POS, POS_CHANNEL_BIT | (slot-1)) ; -#else - attach_POS_addr (smc) ; -#endif -} - -/* Disable access to MCA slot formerly enabled via EnableSlotAccess(). */ -static void DisableSlotAccess(struct s_smc *smc) -{ -#ifndef AIX - SK_UNUSED(smc) ; - - outp(POS_CHANNEL_POS, 0) ; -#else - detach_POS_addr (smc) ; -#endif -} -#endif /* MCA */ - -#ifdef EISA -#ifndef MEM_MAPPED_IO -#define SADDR(slot) (((slot)<<12)&0xf000) -#else /* MEM_MAPPED_IO */ -#define SADDR(slot) (smc->hw.iop) -#endif /* MEM_MAPPED_IO */ - -/************************ - * - * BEGIN_MANUAL_ENTRY() - * - * exist_board - * - * Check if an EISA board is present in the specified slot. - * - * int exist_board( - * struct s_smc *smc, - * int slot) ; - * In - * smc - A pointer to the SMT Context struct. - * - * slot - The number of the slot to inspect. - * Out - * 0 = No adapter present. - * 1 = Found adapter. - * - * Pseudo - * Read EISA ID - * for all valid OEM_IDs - * compare with ID read - * if equal, return 1 - * return(0 - * - * Note - * The smc pointer must be valid now. - * - ************************/ -int exist_board(struct s_smc *smc, int slot) -{ - int i ; -#ifdef MULT_OEM - SK_LOC_DECL(u_char,id[4]) ; -#endif /* MULT_OEM */ - - /* No longer valid. */ - if (smc == NULL) - return(0); - - SK_UNUSED(slot) ; - -#ifndef MULT_OEM - for (i = 0 ; i < 4 ; i++) { - if (inp(SADDR(slot)+PRA(i)) != OEMID(smc,i)) - return(0) ; - } - return(1) ; -#else /* MULT_OEM */ - for (i = 0 ; i < 4 ; i++) - id[i] = inp(SADDR(slot)+PRA(i)) ; - - smc->hw.oem_id = (struct s_oem_ids *) &oem_ids[0] ; - - for (; smc->hw.oem_id->oi_status != OI_STAT_LAST; smc->hw.oem_id++) { - if (smc->hw.oem_id->oi_status < smc->hw.oem_min_status) - continue ; - - if (is_equal_num(&id[0],&OEMID(smc,0),4)) - return (1) ; - } - return (0) ; /* No adapter found. */ -#endif /* MULT_OEM */ -} - - -int get_board_para(struct s_smc *smc, int slot) -{ - int i ; - - if (!exist_board(smc,slot)) - return(0) ; - - smc->hw.slot = slot ; -#ifndef MEM_MAPPED_IO /* if defined by the operating system */ - smc->hw.iop = SADDR(slot) ; -#endif - - if (!(inp(C0_A(0))&CFG_CARD_EN)) { - return(2) ; /* CFG_CARD_EN bit not set! */ - } - - smc->hw.irq = opt_ints[(inp(C1_A(0)) & CFG_IRQ_SEL)] ; - smc->hw.dma = opt_dmas[((inp(C1_A(0)) & CFG_DRQ_SEL)>>3)] ; - - if ((i = inp(C2_A(0)) & CFG_EPROM_SEL) != 0x0f) - smc->hw.eprom = opt_eproms[i] ; - else - smc->hw.eprom = 0 ; - - smc->hw.DmaWriteExtraBytes = 8 ; - - return(1) ; -} -#endif /* EISA */ - -#ifdef ISA -#ifndef MULT_OEM -const u_char sklogo[6] = SKLOGO_STR ; -#define SIZE_SKLOGO(smc) sizeof(sklogo) -#define SKLOGO(smc,i) sklogo[i] -#else /* MULT_OEM */ -#define SIZE_SKLOGO(smc) smc->hw.oem_id->oi_logo_len -#define SKLOGO(smc,i) smc->hw.oem_id->oi_logo[i] -#endif /* MULT_OEM */ - - -int exist_board(struct s_smc *smc, HW_PTR port) -{ - int i ; -#ifdef MULT_OEM - int bytes_read ; - u_char board_logo[15] ; - SK_LOC_DECL(u_char,id[4]) ; -#endif /* MULT_OEM */ - - /* No longer valid. */ - if (smc == NULL) - return(0); - - SK_UNUSED(smc) ; -#ifndef MULT_OEM - for (i = SADDRL ; i < (signed) (SADDRL+SIZE_SKLOGO(smc)) ; i++) { - if ((u_char)inpw((PRA(i)+port)) != SKLOGO(smc,i-SADDRL)) { - return(0) ; - } - } - - /* check MAC address (S&K or other) */ - for (i = 0 ; i < 3 ; i++) { - if ((u_char)inpw((PRA(i)+port)) != OEMID(smc,i)) - return(0) ; - } - return(1) ; -#else /* MULT_OEM */ - smc->hw.oem_id = (struct s_oem_ids *) &oem_ids[0] ; - board_logo[0] = (u_char)inpw((PRA(SADDRL)+port)) ; - bytes_read = 1 ; - - for (; smc->hw.oem_id->oi_status != OI_STAT_LAST; smc->hw.oem_id++) { - if (smc->hw.oem_id->oi_status < smc->hw.oem_min_status) - continue ; - - /* Test all read bytes with current OEM_entry */ - /* for (i=0; (ihw.iop) -#define ADDRS(smc,a) ((a)+(smc)->hw.iop) -#endif - -/* - * FDDI-Fx (x := {I(SA), E(ISA), M(CA), P(CI)}) + * FDDI-Fx (x := {I(SA), P(CI)}) * address calculation & function defines */ -#ifdef EISA - -/* - * Configuration PROM: !! all 8-Bit IO's !! - * |<- MAC-Address ->| - * /-+--+--+--+--+-//-+--+--+--+--+-//-+--+--+--+--+-//-+--+--+--+--+-/ - * val: |PROD_ID0..3| | free | |00|00|5A|40| |nn|mm|00|00| - * /-+--+--+--+--+-//-+--+--+--+--+-//-+--+--+--+--+-//-+--+--+--+--+-/ - * IO- ^ ^ ^ ^ ^ - * port 0C80 0C83 0C88 0C90 0C98 - * | \ - * | \ - * | \______________________________________________ - * EISA Expansion Board Product ID: \ - * BIT: |7 6 5 4 3 2 1 0| \ - * | PROD_ID0 | PROD_ID1 | PROD_ID2 | PROD_ID3 | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * |0| MAN_C0 | MAN_C1 | MAN_C2 | PROD1 | PROD0 | REV1 | REV0 | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ^=reserved | product numb. | revision numb | - * MAN_Cx = compressed manufacterer code (x:=0..2) - * ASCII : 'A'..'Z' : 0x41..0x5A -> compr.(c-0x40) : 0x01..0x1A (5Bits!) - */ - -#ifndef MULT_OEM -#ifndef OEM_CONCEPT -#define MAN_C0 ('S'-0x40) -#define MAN_C1 ('K'-0x40) -#define MAN_C2 ('D'-0x40) -#define PROD_ID0 (u_char)((MAN_C0<<2) | (MAN_C1>>3)) -#define PROD_ID1 (u_char)(((MAN_C1<<5) & 0xff) | MAN_C2) -#define PROD_ID2 (u_char)(1) /* prod. nr. */ -#define PROD_ID3 (u_char)(0) /* rev. nr. */ - -#ifndef OEM_USER_DATA -#define OEM_USER_DATA "SK-NET FDDI V2.0 Userdata" -#endif -#else /* OEM_CONCEPT */ - -/* MAN_C(0|1|2) no longer present (ra). */ -#define PROD_ID0 (u_char)OEM_PROD_ID0 -#define PROD_ID1 (u_char)OEM_PROD_ID1 -#define PROD_ID2 (u_char)OEM_PROD_ID2 -#define PROD_ID3 (u_char)OEM_PROD_ID3 -#endif /* OEM_CONCEPT */ - -#define SKLOGO PROD_ID0, PROD_ID1, PROD_ID2, PROD_ID3 -#endif /* MULT_OEM */ - -#define SADDRL (0) /* start address SKLOGO */ -#define SA_MAC (0x10) /* start addr. MAC_AD within the PROM */ -#define PRA_OFF (4) -#define SA_PMD_TYPE (8) /* start addr. PMD-Type */ - -#define SKFDDI_PSZ 32 /* address PROM size */ - -/* - * address transmission from logical to physical offset address on board - */ -#define FMA(a) (0x0400|((a)<<1)) /* FORMAC+ (r/w) */ -#define P1A(a) (0x0800|((a)<<1)) /* PLC1 (r/w) */ -#define P2A(a) (0x0840|((a)<<1)) /* PLC2 (r/w) */ -#define TIA(a) (0x0880|((a)<<1)) /* Timer (r/w) */ -#define PRA(a) (0x0c80| (a)) /* configuration PROM */ -#define C0A(a) (0x0c84| (a)) /* config. RAM */ -#define C1A(a) (0x0ca0| (a)) /* IRQ-, DMA-nr., EPROM type */ -#define C2A(a) (0x0ca4| (a)) /* EPROM and PAGE selector */ - -#define CONF C0A(0) /* config RAM (card enable bit port) */ -#define PGRA C2A(0) /* Flash page register */ -#define CDID PRA(0) /* Card ID I/O port addr. offset */ - - -/* - * physical address offset + slot specific IO-Port base address - */ -#define FM_A(a) (FMA(a)+smc->hw.iop) /* FORMAC Plus physical addr */ -#define P1_A(a) (P1A(a)+smc->hw.iop) /* PLC1 (r/w) */ -#define P2_A(a) (P2A(a)+smc->hw.iop) /* PLC2 (r/w) */ -#define TI_A(a) (TIA(a)+smc->hw.iop) /* Timer (r/w) */ -#define PR_A(a) (PRA(a)+smc->hw.iop) /* config. PROM */ -#define C0_A(a) (C0A(a)+smc->hw.iop) /* config. RAM */ -#define C1_A(a) (C1A(a)+smc->hw.iop) /* config. RAM */ -#define C2_A(a) (C2A(a)+smc->hw.iop) /* config. RAM */ - - -#define CSRA 0x0008 /* control/status register address (r/w) */ -#define ISRA 0x0008 /* int. source register address (upper 8Bits) */ -#define PLC1I 0x001a /* clear PLC1 interrupt (write only) */ -#define PLC2I 0x0020 /* clear PLC2 interrupt (write only) */ -#define CSFA 0x001c /* control/status FIFO BUSY flags (read only) */ -#define RQAA 0x001c /* Request reg. (write only) */ -#define WCTA 0x001e /* word counter (r/w) */ -#define FFLAG 0x005e /* FLAG/V_FULL (FIFO almost full, write only)*/ - -#define CSR_A (CSRA+smc->hw.iop) /* control/status register address (r/w) */ -#ifdef UNIX -#define CSR_AS(smc) (CSRA+(smc)->hw.iop) /* control/status register address (r/w) */ -#endif -#define ISR_A (ISRA+smc->hw.iop) /* int. source register address (upper 8Bits) */ -#define PLC1_I (PLC1I+smc->hw.iop) /* clear PLC1 internupt (write only) */ -#define PLC2_I (PLC2I+smc->hw.iop) /* clear PLC2 interrupt (write only) */ -#define CSF_A (CSFA+smc->hw.iop) /* control/status FIFO BUSY flags (r/w) */ -#define RQA_A (RQAA+smc->hw.iop) /* Request reg. (write only) */ -#define WCT_A (WCTA+smc->hw.iop) /* word counter (r/w) */ -#define FFLAG_A (FFLAG+smc->hw.iop) /* FLAG/V_FULL (FIFO almost full, write only)*/ - -/* - * control/status register CSRA bits - */ -/* write */ -#define CS_CRESET 0x01 /* Card reset (0=reset) */ -#define CS_RESET_FIFO 0x02 /* FIFO reset (0=reset) */ -#define CS_IMSK 0x04 /* enable IRQ (1=enable, 0=disable) */ -#define CS_EN_IRQ_TC 0x08 /* enable IRQ from transfer counter */ -#define CS_BYPASS 0x20 /* bypass switch (0=remove, 1=insert)*/ -#define CS_LED_0 0x40 /* switch LED 0 */ -#define CS_LED_1 0x80 /* switch LED 1 */ -/* read */ -#define CS_BYSTAT 0x40 /* 0=Bypass exist, 1= ..not */ -#define CS_SAS 0x80 /* single attachement station (=1) */ - -/* - * control/status register CSFA bits (FIFO) - */ -#define CSF_MUX0 0x01 -#define CSF_MUX1 0x02 -#define CSF_HSREQ0 0x04 -#define CSF_HSREQ1 0x08 -#define CSF_HSREQ2 0x10 -#define CSF_BUSY_DMA 0x40 -#define CSF_BUSY_FIFO 0x80 - -/* - * Interrupt source register ISRA (upper 8 data bits) read only & low activ. - */ -#define IS_MINTR1 0x0100 /* FORMAC ST1U/L & ~IMSK1U/L*/ -#define IS_MINTR2 0x0200 /* FORMAC ST2U/L & ~IMSK2U/L*/ -#define IS_PLINT1 0x0400 /* PLC1 */ -#define IS_PLINT2 0x0800 /* PLC2 */ -#define IS_TIMINT 0x1000 /* Timer 82C54-2 */ -#define IS_TC 0x2000 /* transf. counter */ - -#define ALL_IRSR (IS_MINTR1|IS_MINTR2|IS_PLINT1|IS_PLINT2|IS_TIMINT|IS_TC) - -/* - * CONFIG<0> RAM (C0_A()) - */ -#define CFG_CARD_EN 0x01 /* card enable */ - -/* - * CONFIG<1> RAM (C1_A()) - */ -#define CFG_IRQ_SEL 0x03 /* IRQ select (4 nr.) */ -#define CFG_IRQ_TT 0x04 /* IRQ trigger type (LEVEL/EDGE) */ -#define CFG_DRQ_SEL 0x18 /* DMA requ. (4 nr.) */ -#define CFG_BOOT_EN 0x20 /* 0=BOOT-, 1=Application Software */ -#define CFG_PROG_EN 0x40 /* V_Prog for FLASH_PROM (1=on) */ - -/* - * CONFIG<2> RAM (C2_A()) - */ -#define CFG_EPROM_SEL 0x0f /* FPROM start address selection */ -#define CFG_PAGE 0xf0 /* FPROM page selection */ - - -#define READ_PROM(a) ((u_char)inp(a)) -#define GET_PAGE(i) outp(C2_A(0),((int)(i)<<4) | (inp(C2_A(0)) & ~CFG_PAGE)) -#define FPROM_SW() (inp(C1_A(0)) & CFG_BOOT_EN) - -#define MAX_PAGES 16 /* 16 pages */ -#define MAX_FADDR 0x2000 /* 8K per page */ -#define VPP_ON() outp(C1_A(0),inp(C1_A(0)) | CFG_PROG_EN) -#define VPP_OFF() outp(C1_A(0),inp(C1_A(0)) & ~CFG_PROG_EN) - -#define DMA_BUSY() (inpw(CSF_A) & CSF_BUSY_DMA) -#define FIFO_BUSY() (inpw(CSF_A) & CSF_BUSY_FIFO) -#define DMA_FIFO_BUSY() (inpw(CSF_A) & (CSF_BUSY_DMA | CSF_BUSY_FIFO)) -#define BUS_CHECK() - -#ifdef UNISYS -/* For UNISYS use another macro with drv_usecewait function */ -#define CHECK_DMA() {u_long k = 1000000; \ - while (k && (DMA_BUSY())) { k--; drv_usecwait(20); } \ - if (!k) SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ; } -#else -#define CHECK_DMA() {u_long k = 1000000 ;\ - while (k && (DMA_BUSY())) k-- ;\ - if (!k) SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ; } -#endif - -#define CHECK_FIFO() {u_long k = 1000000 ;\ - while (k && (FIFO_BUSY())) k-- ;\ - if (!k) SMT_PANIC(smc,HWM_E0019,HWM_E0019_MSG) ; } - -#define CHECK_DMA_FIFO() {u_long k = 1000000 ;\ - while (k && (DMA_FIFO_BUSY())) k-- ;\ - if (!k) SMT_PANIC(smc,HWM_E0004,HWM_E0004_MSG) ; } - -#define GET_ISR() ~inpw(ISR_A) -#define CHECK_ISR() ~inpw(ISR_A) - -#ifndef UNIX -#ifndef WINNT -#define CLI_FBI() outpw(CSR_A,(inpw(CSR_A)&\ - (CS_CRESET|CS_BYPASS))|CS_RESET_FIFO|smc->hw.led) -#else /* WINNT */ -#define CLI_FBI() outpw(CSR_A,(l_inpw(CSR_A)&\ - (CS_CRESET|CS_BYPASS))|CS_RESET_FIFO|smc->hw.led) -#endif /* WINNT */ -#else /* UNIX */ -#define CLI_FBI(smc) outpw(CSR_AS(smc),(inpw(CSR_AS(smc))&\ - (CS_CRESET|CS_BYPASS))|CS_RESET_FIFO|(smc)->hw.led) -#endif - -#ifndef UNIX -#define STI_FBI() outpw(CSR_A,(inpw(CSR_A)&\ - (CS_CRESET|CS_BYPASS|CS_RESET_FIFO))|CS_IMSK|smc->hw.led) -#else -#define STI_FBI(smc) outpw(CSR_AS(smc),(inpw(CSR_AS(smc))&\ - (CS_CRESET|CS_BYPASS|CS_RESET_FIFO))|CS_IMSK|(smc)->hw.led) -#endif - -/* EISA DMA Controller */ -#define DMA_WRITE_SINGLE_MASK_BIT_M 0x0a /* Master DMA Controller */ -#define DMA_WRITE_SINGLE_MASK_BIT_S 0xd4 /* Slave DMA Controller */ -#define DMA_CLEAR_BYTE_POINTER_M 0x0c -#define DMA_CLEAR_BYTE_POINTER_S 0xd8 - -#endif /* EISA */ - -#ifdef MCA - -/* - * POS Register: !! all I/O's are 8-Bit !! - */ -#define POS_SYS_SETUP 0x94 /* system setup register */ -#define POS_SYSTEM 0xff /* system mode */ - -#define POS_CHANNEL_POS 0x96 /* register slot ID */ -#define POS_CHANNEL_BIT 0x08 /* mask for -"- */ - -#define POS_BASE 0x100 /* POS base address */ -#define POS_ID_LOW POS_BASE /* card ID low */ -#define POS_ID_HIGH (POS_BASE+1) /* card ID high */ -#define POS_102 (POS_BASE+2) /* card en., arbitration level .. */ -#define POS_103 (POS_BASE+3) /* FPROM addr, page */ -#define POS_104 (POS_BASE+4) /* I/O, IRQ */ -#define POS_105 (POS_BASE+5) /* POS_CHCK */ -#define POS_106 (POS_BASE+6) /* to read VPD */ -#define POS_107 (POS_BASE+7) /* added without function */ - -/* FM1 card IDs */ -#define FM1_CARD_ID0 0x83 -#define FM1_CARD_ID1 0 - -#define FM1_IBM_ID0 0x9c -#define FM1_IBM_ID1 0x8f - - -/* FM2 card IDs */ -#define FM2_CARD_ID0 0xab -#define FM2_CARD_ID1 0 - -#define FM2_IBM_ID0 0x7e -#define FM2_IBM_ID1 0x8f - -/* Board revision. */ -#define FM1_REV 0 -#define FM2_REV 1 - -#define MAX_SLOT 8 - -/* - * POS_102 - */ -#define POS_CARD_EN 0x01 /* card enable =1 */ -#define POS_SDAT_EN 0x02 /* enable 32-bit streaming data mode */ -#define POS_EN_CHKINT 0x04 /* enable int. from check line asserted */ -#define POS_EN_BUS_ERR 0x08 /* enable int. on invalid busmaster transf. */ -#define POS_FAIRNESS 0x10 /* fairnes on =1 */ -/* attention: arbitration level used with bit 0 POS 105 */ -#define POS_LARBIT 0xe0 /* arbitration level (0,0,0)->level = 0x8 - (1,1,1)->level = 0xf */ -/* - * POS_103 - */ -#define POS_PAGE 0x07 /* FPROM page selection */ -#define POS_BOOT_EN 0x08 /* boot PROM enable =1 */ -#define POS_MSEL 0x70 /* memory start address for FPROM mapping */ -#define PROG_EN 0x80 /* FM1: Vpp prog on/off */ -#define POS_SDR 0x80 /* FM2: Streaming data bit */ - -/* - * POS_104 - */ -#define POS_IOSEL 0x3f /* selected I/O base address */ -#define POS_IRQSEL 0xc0 /* selected interrupt */ - -/* - * POS_105 - */ -#define POS_CHCK 0x80 -#define POS_SYNC_ERR 0x20 /* FM2: synchronous error reporting */ -#define POS_PAR_DATA 0x10 /* FM2: data parity enable bit */ -#define POS_PAR_ADDR 0x08 /* FM2: address parity enable bit */ -#define POS_IRQHSEL 0x02 /* FM2: Highest bit for IRQ_selection */ -#define POS_HARBIT 0x01 /* Highest bit in Bus arbitration selection */ - -#define SA_MAC (0) /* start addr. MAC_AD within the PROM */ -#define PRA_OFF (0) -#define SA_PMD_TYPE (8) /* start addr. PMD-Type */ - -/* - * address transmission from logical to physical offset address on board - */ -#define FMA(a) (0x0100|((a)<<1)) /* FORMAC+ (r/w) */ -#define P2(a) (0x00c0|((a)<<1)) /* PLC2 (r/w) (DAS) */ -#define P1(a) (0x0080|((a)<<1)) /* PLC1 (r/w) */ -#define TI(a) (0x0060|((a)<<1)) /* Timer (r/w) */ -#define PR(a) (0x0040|((a)<<1)) /* configuration PROM */ -#define CS(a) (0x0020| (a)) /* control/status */ -#define FF(a) (0x0010|((a)<<1)) /* FIFO ASIC */ -#define CT(a) (0x0000|((a)<<1)) /* counter */ - -/* - * counter - */ -#define ACLA CT(0) /* address counter low */ -#define ACHA CT(1) /* address counter high */ -#define BCN CT(2) /* byte counter */ -#define MUX CT(3) /* MUX-register */ -#define WCN CT(0x08) /* word counter */ -#define FFLG CT(0x09) /* FIFO Flags */ - -/* - * test/control register (FM2 only) - */ -#define CNT_TST 0x018 /* Counter test control register */ -#define CNT_STP 0x01a /* Counter test step reg. (8 Bit) */ - -/* - * CS register (read only) - */ -#define CSRA CS(0) /* control/status register address */ -#define CSFA CS(2) /* control/status FIFO BUSY ... */ -#define ISRA CS(4) /* first int. source register address */ -#define ISR2 CS(6) /* second int. source register address */ -#define LEDR CS(0x0c) /* LED register r/w */ -#define CSIL CS(0x10) /* I/O mapped POS_ID_low (100) */ -#define CSIH CS(0x12) /* - " - POS_ID_HIGH (101) */ -#define CSA CS(0x14) /* - " - POS_102 */ -#define CSM CS(0x0e) /* - " - POS_103 */ -#define CSM_FM1 CS(0x16) /* - " - POS_103 (copy in FM1) */ -#define CSI CS(0x18) /* - " - POS_104 */ -#define CSS CS(0x1a) /* - " - POS_105 */ -#define CSP_06 CS(0x1c) /* - " - POS_106 */ -#define WDOG_ST 0x1c /* Watchdog status (FM2 only) */ -#define WDOG_EN 0x1c /* Watchdog enabling (FM2 only, 8Bit) */ -#define WDOG_DIS 0x1e /* Watchdog disabling (FM2 only, 8Bit) */ - -#define PGRA CSM /* Flash page register */ - - -#define WCTA FF(0) /* word counter */ -#define FFLAG FF(1) /* FLAG/V_FULL (FIFO almost full, write only)*/ - -/* - * Timer register (FM2 only) - */ -#define RTM_CNT 0x28 /* RTM Counter */ -#define TI_DIV 0x60 /* Timer Prescaler */ -#define TI_CH1 0x62 /* Timer channel 1 counter */ -#define TI_STOP 0x64 /* Stop timer on channel 1 */ -#define TI_STRT 0x66 /* Start timer on channel 1 */ -#define TI_INI2 0x68 /* Timer: Bus master preemption */ -#define TI_CNT2 0x6a /* Timer */ -#define TI_INI3 0x6c /* Timer: Streaming data */ -#define TI_CNT3 0x6e /* Timer */ -#define WDOG_LO 0x70 /* Watchdog counter low */ -#define WDOG_HI 0x72 /* Watchdog counter high */ -#define RTM_PRE 0x74 /* restr. token prescaler */ -#define RTM_TIM 0x76 /* restr. token timer */ - -/* - * Recommended Timeout values (for FM2 timer only) - */ -#define TOUT_BM_PRE 188 /* 3.76 usec */ -#define TOUT_S_DAT 374 /* 7.48 usec */ - -/* - * CS register (write only) - */ -#define HSR(p) CS(0x18|(p)) /* Host request register */ - -#define RTM_PUT 0x36 /* restr. token counter write */ -#define RTM_GET 0x28 /* - " - clear */ -#define RTM_CLEAR 0x34 /* - " - read */ - -/* - * BCN Bit definitions - */ -#define BCN_BUSY 0x8000 /* DMA Busy flag */ -#define BCN_AZERO 0x4000 /* Almost zero flag (BCN < 4) */ -#define BCN_STREAM 0x2000 /* Allow streaming data (BCN >= 8) */ - -/* - * WCN Bit definitions - */ -#define WCN_ZERO 0x2000 /* Zero flag (counted to zero) */ -#define WCN_AZERO 0x1000 /* Almost zero flag (BCN < 4) */ - -/* - * CNT_TST Bit definitions - */ -#define CNT_MODE 0x01 /* Go into test mode */ -#define CNT_D32 0x02 /* 16/32 BIT test mode */ - -/* - * FIFO Flag FIFO Flags/Vfull register - */ -#define FF_VFULL 0x003f /* V_full value mask */ -#define FFLG_FULL 0x2000 /* FULL flag */ -#define FFLG_A_FULL 0x1000 /* Almost full flag */ -#define FFLG_VFULL 0x0800 /* V_full Flag */ -#define FFLG_A_EMP 0x0400 /* almost empty flag */ -#define FFLG_EMP 0x0200 /* empty flag */ -#define FFLG_T_EMP 0x0100 /* totally empty flag */ - -/* - * WDOG Watchdog status register - */ -#define WDOG_ALM 0x01 /* Watchdog alarm Bit */ -#define WDOG_ACT 0x02 /* Watchdog active Bit */ - -/* - * CS(0) CONTROLS - */ -#define CS_CRESET 0x0001 -#define FIFO_RST 0x0002 -#define CS_IMSK 0x0004 -#define EN_IRQ_CHCK 0x0008 -#define EN_IRQ_TOKEN 0x0010 -#define EN_IRQ_TC 0x0020 -#define TOKEN_STATUS 0x0040 -#define RTM_CHANGE 0x0080 - -#define CS_SAS 0x0100 -#define CS_BYSTAT 0x0200 /* bypass connected (0=conn.) */ -#define CS_BYPASS 0x0400 /* bypass on/off indication */ - -/* - * CS(2) FIFOSTAT - */ -#define HSREQ 0x0007 -#define BIGDIR 0x0008 -#define CSF_BUSY_FIFO 0x0010 -#define CSF_BUSY_DMA 0x0020 -#define SLOT_32 0x0040 - -#define LED_0 0x0001 -#define LED_1 0x0002 -#define LED_2 0x0100 - -#define MAX_PAGES 8 /* pages */ -#define MAX_FADDR 0x4000 /* 16K per page */ - -/* - * IRQ = ISRA || ISR2 ; - * - * ISRA = IRQ_OTH_EN && (IS_LAN | IS_BUS) ; - * ISR2 = IRQ_TC_EN && IS_TC ; - * - * IS_LAN = (IS_MINTR1 | IS_MINTR2 | IS_PLINT1 | IS_PLINT2 | IS_TIMINT) || - * (IRQ_EN_TOKEN && IS_TOKEN) ; - * IS_BUS = IRQ_CHCK_EN && (IS_BUSERR | IS_CHCK_L) ; - */ -/* - * ISRA !!! activ high !!! - */ -#define IS_MINTR1 0x0001 /* FORMAC ST1U/L & ~IMSK1U/L*/ -#define IS_MINTR2 0x0002 /* FORMAC ST2U/L & ~IMSK2U/L*/ -#define IS_PLINT1 0x0004 /* PLC1 */ -#define IS_PLINT2 0x0008 /* PLC2 */ -#define IS_TIMINT 0x0010 /* Timer 82C54-2 */ -#define IS_TOKEN 0x0020 /* restrictet token monitoring */ -#define IS_CHCK_L 0x0040 /* check line asserted */ -#define IS_BUSERR 0x0080 /* bus error */ -/* - * ISR2 - */ -#define IS_TC 0x0001 /* terminal count irq */ -#define IS_SFDBKRTN 0x0002 /* selected feedback return */ -#define IS_D16 0x0004 /* DS16 */ -#define IS_D32 0x0008 /* DS32 */ -#define IS_DPEI 0x0010 /* Data Parity Indication */ - -#define ALL_IRSR 0x00ff - -#define FM_A(a) ADDR(FMA(a)) /* FORMAC Plus physical addr */ -#define P1_A(a) ADDR(P1(a)) /* PLC1 (r/w) */ -#define P2_A(a) ADDR(P2(a)) /* PLC2 (r/w) (DAS) */ -#define TI_A(a) ADDR(TI(a)) /* Timer (r/w) FM1 only! */ -#define PR_A(a) ADDR(PR(a)) /* config. PROM */ -#define CS_A(a) ADDR(CS(a)) /* control/status */ - -#define ISR1_A ADDR(ISRA) /* first int. source register address */ -#define ISR2_A ADDR(ISR2) /* second -"- */ -#define CSR_A ADDR(CSRA) /* control/status register address */ -#define CSF_A ADDR(CSFA) /* control/status FIFO BUSY flags (r/w) */ - -#define CSIL_A ADDR(CSIL) /* I/O mapped POS_ID_low (102) */ -#define CSIH_A ADDR(CSIH) /* - " - POS_ID_HIGH (101) */ -#define CSA_A ADDR(CSA) /* - " - POS_102 */ -#define CSI_A ADDR(CSI) /* - " - POS_104 */ -#define CSM_A ADDR(CSM) /* - " - POS_103 */ -#define CSM_FM1_A ADDR(CSM_FM1) /* - " - POS_103 (2nd copy, FM1) */ -#define CSP_06_A ADDR(CSP_06) /* - " - POS_106 */ - -#define WCT_A ADDR(WCTA) /* word counter (r/w) */ -#define FFLAG_A ADDR(FFLAG) /* FLAG/V_FULL (FIFO almost full, write only)*/ - -#define ACL_A ADDR(ACLA) /* address counter low */ -#define ACH_A ADDR(ACHA) /* address counter high */ -#define BCN_A ADDR(BCN) /* byte counter */ -#define MUX_A ADDR(MUX) /* MUX-register */ - -#define ISR_A ADDR(ISRA) /* Interrupt Source Register */ -#define FIFO_RESET_A ADDR(FIFO_RESET) /* reset the FIFO */ -#define FIFO_EN_A ADDR(FIFO_EN) /* enable the FIFO */ - -#define WDOG_EN_A ADDR(WDOG_EN) /* reset and start the WDOG */ -#define WDOG_DIS_A ADDR(WDOG_DIS) /* disable the WDOG */ -/* - * all control reg. (read!) are 8 bit (except PAGE_RG_A and LEDR_A) - */ -#define HSR_A(p) ADDR(HSR(p)) /* Host request register */ - -#define STAT_BYP 0 /* bypass station */ -#define STAT_INS 2 /* insert station */ -#define BYPASS(o) CS(0x10|(o)) /* o=STAT_BYP || STAT_INS */ - -#define IRQ_TC_EN CS(0x0b) /* enable/disable IRQ on TC */ -#define IRQ_TC_DIS CS(0x0a) -#define IRQ_TOKEN_EN CS(9) /* enable/disable IRQ on restr. Token */ -#define IRQ_TOKEN_DIS CS(8) -#define IRQ_CHCK_EN CS(7) /* -"- IRQ after CHCK line */ -#define IRQ_CHCK_DIS CS(6) -#define IRQ_OTH_EN CS(5) /* -"- other IRQ's */ -#define IRQ_OTH_DIS CS(4) -#define FIFO_EN CS(3) /* disable (reset), enable FIFO */ -#define FIFO_RESET CS(2) -#define CARD_EN CS(1) /* disable (reset), enable card */ -#define CARD_DIS CS(0) - -#define LEDR_A ADDR(LEDR) /* D0=green, D1=yellow, D8=L2 */ -#define PAGE_RG_A ADDR(CSM) /* D<2..0> */ -#define IRQ_CHCK_EN_A ADDR(IRQ_CHCK_EN) -#define IRQ_CHCK_DIS_A ADDR(IRQ_CHCK_DIS) - -#define GET_PAGE(bank) outpw(PAGE_RG_A,(inpw(PAGE_RG_A) &\ - (~POS_PAGE)) |(int) (bank)) -#define VPP_ON() if (smc->hw.rev == FM1_REV) { \ - outpw(PAGE_RG_A, \ - (inpw(PAGE_RG_A) & POS_PAGE) | PROG_EN); \ - } -#define VPP_OFF() if (smc->hw.rev == FM1_REV) { \ - outpw(PAGE_RG_A,(inpw(PAGE_RG_A) & POS_PAGE)); \ - } - -#define SKFDDI_PSZ 16 /* address PROM size */ - -#define READ_PROM(a) ((u_char)inp(a)) - -#define GET_ISR() ~inpw(ISR1_A) -#ifndef TCI -#define CHECK_ISR() ~inpw(ISR1_A) -#define CHECK_ISR_SMP(iop) ~inpw((iop)+ISRA) -#else -#define CHECK_ISR() (~inpw(ISR1_A) | ~inpw(ISR2_A)) -#define CHECK_ISR_SMP(iop) (~inpw((iop)+ISRA) | ~inpw((iop)+ISR2)) -#endif - -#define DMA_BUSY() (inpw(CSF_A) & CSF_BUSY_DMA) -#define FIFO_BUSY() (inpw(CSF_A) & CSF_BUSY_FIFO) -#define DMA_FIFO_BUSY() (inpw(CSF_A) & (CSF_BUSY_DMA | CSF_BUSY_FIFO)) -#define BUS_CHECK() { int i ; \ - if ((i = GET_ISR()) & IS_BUSERR) \ - SMT_PANIC(smc,HWM_E0020,HWM_E0020_MSG) ; \ - if (i & IS_CHCK_L) \ - SMT_PANIC(smc,HWM_E0014,HWM_E0014_MSG) ; \ - } - -#define CHECK_DMA() { u_long k = 10000 ; \ - while (k && (DMA_BUSY())) { \ - k-- ; \ - BUS_CHECK() ; \ - } \ - if (!k) SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ; } - -#define CHECK_FIFO() {u_long k = 1000000 ;\ - while (k && (FIFO_BUSY())) k-- ;\ - if (!k) SMT_PANIC(smc,HWM_E0019,HWM_E0019_MSG) ; } - -#define CHECK_DMA_FIFO() {u_long k = 1000000 ;\ - while (k && (DMA_FIFO_BUSY())) { \ - k-- ;\ - BUS_CHECK() ; \ - } \ - if (!k) SMT_PANIC(smc,HWM_E0004,HWM_E0004_MSG) ; } - -#ifndef UNIX -#define CLI_FBI() outp(ADDR(IRQ_OTH_DIS),0) -#else -#define CLI_FBI(smc) outp(ADDRS((smc),IRQ_OTH_DIS),0) -#endif - -#ifndef TCI -#define CLI_FBI_SMP(iop) outp((iop)+IRQ_OTH_DIS,0) -#else -#define CLI_FBI_SMP(iop) outp((iop)+IRQ_OTH_DIS,0) ;\ - outp((iop)+IRQ_TC_DIS,0) -#endif - -#ifndef UNIX -#define STI_FBI() outp(ADDR(IRQ_OTH_EN),0) -#else -#define STI_FBI(smc) outp(ADDRS((smc),IRQ_OTH_EN),0) -#endif - -/* - * Terminal count primitives - */ -#define CLI_TCI(smc) outp(ADDRS((smc),IRQ_TC_DIS),0) -#define STI_TCI(smc) outp(ADDRS((smc),IRQ_TC_EN),0) -#define CHECK_TC(smc,k) {(k) = 10000 ;\ - while ((k) && (~inpw(ISR2_A) & IS_TC)) (k)-- ;\ - if (!k) SMT_PANIC(smc,HWM_E0018,HWM_E0018_MSG) ; } - -#endif /* MCA */ - -#ifdef ISA - -/* - * address transmission from logic NPADDR6-0 to physical offset address on board - */ -#define FMA(a) (0x8000|(((a)&0x07)<<1)|(((a)&0x78)<<7)) /* FORMAC+ (r/w) */ -#define PRA(a) (0x1000|(((a)&0x07)<<1)|(((a)&0x18)<<7)) /* PROM (read only)*/ -#define P1A(a) (0x4000|(((a)&0x07)<<1)|(((a)&0x18)<<7)) /* PLC1 (r/w) */ -#define P2A(a) (0x5000|(((a)&0x07)<<1)|(((a)&0x18)<<7)) /* PLC2 (r/w) */ -#define TIA(a) (0x6000|(((a)&0x03)<<1)) /* Timer (r/w) */ - -#define ISRA 0x0000 /* int. source register address (read only) */ -#define ACLA 0x0000 /* address counter low address (write only) */ -#define ACHA 0x0002 /* address counter high address (write only) */ -#define TRCA 0x0004 /* transfer counter address (write only) */ -#define PGRA 0x0006 /* page register address (write only) */ -#define RQAA 0x2000 /* Request reg. (write only) */ -#define CSRA 0x3000 /* control/status register address (r/w) */ - -/* - * physical address offset + IO-Port base address - */ -#define FM_A(a) (FMA(a)+smc->hw.iop) /* FORMAC Plus physical addr */ -#define PR_A(a) (PRA(a)+smc->hw.iop) /* PROM (read only)*/ -#define P1_A(a) (P1A(a)+smc->hw.iop) /* PLC1 (r/w) */ -#define P2_A(a) (P2A(a)+smc->hw.iop) /* PLC2 (r/w) */ -#define TI_A(a) (TIA(a)+smc->hw.iop) /* Timer (r/w) */ - -#define ISR_A (0x0000+smc->hw.iop) /* int. source register address (read only) */ -#define ACL_A (0x0000+smc->hw.iop) /* address counter low address (write only) */ -#define ACH_A (0x0002+smc->hw.iop) /* address counter high address (write only)*/ -#define TRC_A (0x0004+smc->hw.iop) /* transfer counter address (write only) */ -#define PGR_A (0x0006+smc->hw.iop) /* page register address (write only) */ -#define RQA_A (0x2000+smc->hw.iop) /* Request reg. (write only) */ -#define CSR_A (0x3000+smc->hw.iop) /* control/status register address (r/w) */ -#ifdef UNIX -#define CSR_AS(smc) (0x3000+(smc)->hw.iop) /* control/status register address */ -#endif -#define PLC1_I (0x3400+smc->hw.iop) /* clear PLC1 interrupt bit */ -#define PLC2_I (0x3800+smc->hw.iop) /* clear PLC2 interrupt bit */ - -#ifndef MULT_OEM -#ifndef OEM_CONCEPT -#define SKLOGO_STR "SKFDDI" -#else /* OEM_CONCEPT */ -#define SKLOGO_STR OEM_FDDI_LOGO -#endif /* OEM_CONCEPT */ -#endif /* MULT_OEM */ -#define SADDRL (24) /* start address SKLOGO */ -#define SA_MAC (0) /* start addr. MAC_AD within the PROM */ -#define PRA_OFF (0) -#define SA_PMD_TYPE (8) /* start addr. PMD-Type */ - -#define CDID (PRA(SADDRL)) /* Card ID int/O port addr. offset */ -#define NEXT_CDID ((PRA(SADDRL+1)) - CDID) - -#define SKFDDI_PSZ 32 /* address PROM size */ - -#define READ_PROM(a) ((u_char)inpw(a)) -#define GET_PAGE(i) outpw(PGR_A,(int)(i)) - -#define MAX_PAGES 16 /* 16 pages */ -#define MAX_FADDR 0x2000 /* 8K per page */ -#define VPP_OFF() outpw(CSR_A,(inpw(CSR_A) & (CS_CRESET|CS_BYPASS))) -#define VPP_ON() outpw(CSR_A,(inpw(CSR_A) & (CS_CRESET|CS_BYPASS)) | \ - CS_VPPSW) - -/* - * control/status register CSRA bits (log. addr: 0x3000) - */ -/* write */ -#define CS_CRESET 0x01 /* Card reset (0=reset) */ -#define CS_IMSK 0x02 /* enable IRQ (1=enable, 0=disable) */ -#define CS_RESINT1 0x04 /* PLINT1 reset */ -#define CS_VPPSW 0x10 /* 12V power switch (0=off, 1=on) */ -#define CS_BYPASS 0x20 /* bypass switch (0=remove, 1=insert)*/ -#define CS_RESINT2 0x40 /* PLINT2 reset */ -/* read */ -#define CS_BUSY 0x04 /* master transfer activ (=1) */ -#define CS_SW_EPROM 0x08 /* 0=Application Soft. 1=BOOT-EPROM */ -#define CS_BYSTAT 0x40 /* 0=Bypass exist, 1= ..not */ -#define CS_SAS 0x80 /* single attachement station (=1) */ - -/* - * Interrupt source register ISRA (log. addr: 0x0000) read only & low activ. - */ -#define IS_MINTR1 0x01 /* FORMAC ST1U/L && ~IMSK1U/L*/ -#define IS_MINTR2 0x02 /* FORMAC ST2U/L && ~IMSK2U/L*/ -#define IS_PLINT1 0x04 /* PLC1 */ -#define IS_PLINT2 0x08 /* PLC2 */ -#define IS_TIMINT 0x10 /* Timer 82C54-2 */ - -#define ALL_IRSR (IS_MINTR1|IS_MINTR2|IS_PLINT1|IS_PLINT2|IS_TIMINT) - -#define FPROM_SW() (inpw(CSR_A)&CS_SW_EPROM) -#define DMA_BUSY() (inpw(CSR_A)&CS_BUSY) -#define CHECK_FIFO() -#define BUS_CHECK() - -/* - * set Host Request register (wr.) - */ -#define SET_HRQ(qup) outpw(RQA_A+((qup)<<1),0) - -#ifndef UNIX -#ifndef WINNT -#define CLI_FBI() outpw(CSR_A,(inpw(CSR_A)&(CS_CRESET|CS_BYPASS|CS_VPPSW))) -#else -#define CLI_FBI() outpw(CSR_A,(l_inpw(CSR_A) & \ - (CS_CRESET|CS_BYPASS|CS_VPPSW))) -#endif -#else -#define CLI_FBI(smc) outpw(CSR_AS(smc),(inpw(CSR_AS(smc))& \ - (CS_CRESET|CS_BYPASS|CS_VPPSW))) -#endif - -#ifndef UNIX -#define STI_FBI() outpw(CSR_A,(inpw(CSR_A) & \ - (CS_CRESET|CS_BYPASS|CS_VPPSW)) | CS_IMSK) -#else -#define STI_FBI(smc) outpw(CSR_AS(smc),(inpw(CSR_AS(smc)) & \ - (CS_CRESET|CS_BYPASS|CS_VPPSW)) | CS_IMSK) -#endif - -#define CHECK_DMA() {unsigned k = 10000 ;\ - while (k && (DMA_BUSY())) k-- ;\ - if (!k) SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ; } - -#define GET_ISR() ~inpw(ISR_A) - -#endif /* ISA */ - /*--------------------------------------------------------------------------*/ #ifdef PCI diff --git a/drivers/net/skfp/h/skfbiinc.h b/drivers/net/skfp/h/skfbiinc.h index 79d55ad2cd2..ac2d7192f1c 100644 --- a/drivers/net/skfp/h/skfbiinc.h +++ b/drivers/net/skfp/h/skfbiinc.h @@ -22,32 +22,6 @@ */ #define ERR_FLAGS (FS_MSRABT | FS_SEAC2 | FS_SFRMERR | FS_SFRMTY1) -#ifdef ISA -#define DMA_BUSY_CHECK CSRA -#define IMASK_FAST (IS_PLINT1 | IS_PLINT2 | IS_TIMINT) -#define HRQR (RQAA+(RQ_RRQ<<1)) -#define HRQW (RQAA+(RQ_WA2<<1)) -#define HRQA0 (RQAA+(RQ_WA0<<1)) -#define HRQSQ (RQAA+(RQ_WSQ<<1)) -#endif - -#ifdef EISA -#define DMA_BUSY_CHECK CSRA -#define DMA_HIGH_WORD 0x0400 -#define DMA_MASK_M 0x0a -#define DMA_MODE_M 0x0b -#define DMA_BYTE_PTR_M 0x0c -#define DMA_MASK_S 0x0d4 -#define DMA_MODE_S 0x0d6 -#define DMA_BYTE_PTR_S 0x0d8 -#define IMASK_FAST (IS_PLINT1 | IS_PLINT2 | IS_TIMINT | IS_TC) -#endif /* EISA */ - -#ifdef MCA -#define IMASK_FAST (IS_PLINT1 | IS_PLINT2 | IS_TIMINT | IS_TOKEN | \ - IS_CHCK_L | IS_BUSERR) -#endif - #ifdef PCI #define IMASK_FAST (IS_PLINT1 | IS_PLINT2 | IS_TIMINT | IS_TOKEN | \ IS_MINTR2 | IS_MINTR3 | IS_R1_P | \ diff --git a/drivers/net/skfp/h/targethw.h b/drivers/net/skfp/h/targethw.h index 22c4923241d..626dc726359 100644 --- a/drivers/net/skfp/h/targethw.h +++ b/drivers/net/skfp/h/targethw.h @@ -53,11 +53,6 @@ struct s_oem_ids { u_char oi_sub_id[4] ; /* sub id bytes, representation as */ /* defined by hardware, */ #endif -#ifdef ISA - u_char oi_logo_len ; /* the length of the adapter logo */ - u_char oi_logo[6] ; /* the adapter logo */ - u_char oi_reserved1 ; -#endif /* ISA */ } ; #endif /* MULT_OEM */ @@ -70,43 +65,17 @@ struct s_smt_hw { short dma ; /* DMA channel */ short irq ; /* IRQ level */ short eprom ; /* FLASH prom */ -#ifndef PCI - short DmaWriteExtraBytes ; /* add bytes for DMA write */ -#endif #ifndef SYNC u_short n_a_send ; /* pending send requests */ #endif -#if (defined(EISA) || defined(MCA) || defined(PCI)) +#if defined(PCI) short slot ; /* slot number */ short max_slots ; /* maximum number of slots */ -#endif - -#if (defined(PCI) || defined(MCA)) short wdog_used ; /* TRUE if the watch dog is used */ #endif -#ifdef MCA - short slot_32 ; /* 32bit slot (1) or 16bit slot (0) */ - short rev ; /* Board revision (FMx_REV). */ - short VFullRead ; /* V_full value for DMA read */ - short VFullWrite ; /* V_full value for DMA write */ -#endif - -#ifdef EISA - short led ; /* LED for FE card */ - - short dma_rmode ; /* read mode */ - short dma_wmode ; /* write mode */ - short dma_emode ; /* extend mode */ - - /* DMA controller channel dependent io addresses */ - u_short dma_base_word_count ; - u_short dma_base_address ; - u_short dma_base_address_page ; -#endif - #ifdef PCI u_short pci_handle ; /* handle to access the BIOS func */ u_long is_imask ; /* int maske for the int source reg */ diff --git a/drivers/net/skfp/hwt.c b/drivers/net/skfp/hwt.c index e01f8a0f35c..053151468f9 100644 --- a/drivers/net/skfp/hwt.c +++ b/drivers/net/skfp/hwt.c @@ -77,25 +77,10 @@ void hwt_start(struct s_smc *smc, u_long time) */ if (!cnt) cnt++ ; -#ifndef PCI - /* - * 6.25MHz -> CLK0 : T0 (cnt0 = 16us) -> OUT0 - * OUT0 -> CLK1 : T1 (cnt1) OUT1 -> ISRA(IS_TIMINT) - */ - OUT_82c54_TIMER(3,1<<6 | 3<<4 | 0<<1) ; /* counter 1, mode 0 */ - OUT_82c54_TIMER(1,cnt & 0xff) ; /* LSB */ - OUT_82c54_TIMER(1,(cnt>>8) & 0xff) ; /* MSB */ - /* - * start timer by switching counter 0 to mode 3 - * T0 resolution 16 us (CLK0=0.16us) - */ - OUT_82c54_TIMER(3,0<<6 | 3<<4 | 3<<1) ; /* counter 0, mode 3 */ - OUT_82c54_TIMER(0,100) ; /* LSB */ - OUT_82c54_TIMER(0,0) ; /* MSB */ -#else /* PCI */ + outpd(ADDR(B2_TI_INI), (u_long) cnt * 200) ; /* Load timer value. */ outpw(ADDR(B2_TI_CRTL), TIM_START) ; /* Start timer. */ -#endif /* PCI */ + smc->hw.timer_activ = TRUE ; } @@ -115,15 +100,8 @@ void hwt_start(struct s_smc *smc, u_long time) ************************/ void hwt_stop(struct s_smc *smc) { -#ifndef PCI - /* stop counter 0 by switching to mode 0 */ - OUT_82c54_TIMER(3,0<<6 | 3<<4 | 0<<1) ; /* counter 0, mode 0 */ - OUT_82c54_TIMER(0,0) ; /* LSB */ - OUT_82c54_TIMER(0,0) ; /* MSB */ -#else /* PCI */ outpw(ADDR(B2_TI_CRTL), TIM_STOP) ; outpw(ADDR(B2_TI_CRTL), TIM_CL_IRQ) ; -#endif /* PCI */ smc->hw.timer_activ = FALSE ; } @@ -168,11 +146,6 @@ void hwt_init(struct s_smc *smc) void hwt_restart(struct s_smc *smc) { hwt_stop(smc) ; -#ifndef PCI - OUT_82c54_TIMER(3,1<<6 | 3<<4 | 0<<1) ; /* counter 1, mode 0 */ - OUT_82c54_TIMER(1,1 ) ; /* LSB */ - OUT_82c54_TIMER(1,0 ) ; /* MSB */ -#endif } /************************ @@ -191,21 +164,12 @@ void hwt_restart(struct s_smc *smc) u_long hwt_read(struct s_smc *smc) { u_short tr ; -#ifndef PCI - u_short is ; -#else u_long is ; -#endif if (smc->hw.timer_activ) { hwt_stop(smc) ; -#ifndef PCI - OUT_82c54_TIMER(3,1<<6) ; /* latch command */ - tr = IN_82c54_TIMER(1) & 0xff ; - tr += (IN_82c54_TIMER(1) & 0xff)<<8 ; -#else /* PCI */ tr = (u_short)((inpd(ADDR(B2_TI_VAL))/200) & 0xffff) ; -#endif /* PCI */ + is = GET_ISR() ; /* Check if timer expired (or wraparound). */ if ((tr > smc->hw.t_start) || (is & IS_TIMINT)) { -- cgit v1.2.3-70-g09d2 From eda105317fece79fa7e8478214ff7450f5a3f9dd Mon Sep 17 00:00:00 2001 From: Yoann Padioleau Date: Mon, 23 Jul 2007 15:18:21 +0200 Subject: dev->priv to netdev_priv(dev), drivers/net/tokenring/ Replacing accesses to dev->priv to netdev_priv(dev). The replacment is safe when netdev_priv is used to access a private structure that is right next to the net_device structure in memory. Cf http://groups.google.com/group/comp.os.linux.development.system/browse_thread/thread/de19321bcd94dbb8/0d74a4adcd6177bd This is the case when the net_device structure was allocated with a call to alloc_netdev or one of its derivative. Here is an excerpt of the semantic patch that performs the transformation @ rule1 @ type T; struct net_device *dev; @@ dev = ( alloc_netdev | alloc_etherdev | alloc_trdev ) (sizeof(T), ...) @ rule1bis @ struct net_device *dev; expression E; @@ dev->priv = E @ rule2 depends on rule1 && !rule1bis @ struct net_device *dev; type rule1.T; @@ - (T*) dev->priv + netdev_priv(dev) PS: I have performed the same transformation on the whole kernel and it affects around 70 files, most of them in drivers/net/. Should I split my patch for each subnet directories ? (wireless/, wan/, etc) Thanks to Thomas Surrel for helping me refining my semantic patch. Signed-off-by: Yoann Padioleau 3c359.c | 58 +++++++++++++++++++++++++++++----------------------------- ibmtr.c | 38 +++++++++++++++++++------------------- lanstreamer.c | 32 ++++++++++++++++---------------- madgemc.c | 4 ++-- olympic.c | 36 ++++++++++++++++++------------------ tmspci.c | 4 ++-- 6 files changed, 86 insertions(+), 86 deletions(-) Signed-off-by: Jeff Garzik --- drivers/net/tokenring/3c359.c | 58 ++++++++++++++++++------------------- drivers/net/tokenring/ibmtr.c | 38 ++++++++++++------------ drivers/net/tokenring/lanstreamer.c | 32 ++++++++++---------- drivers/net/tokenring/madgemc.c | 4 +-- drivers/net/tokenring/olympic.c | 36 +++++++++++------------ drivers/net/tokenring/tmspci.c | 4 +-- 6 files changed, 86 insertions(+), 86 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c index 9f1b6ab9c22..6612db8ec21 100644 --- a/drivers/net/tokenring/3c359.c +++ b/drivers/net/tokenring/3c359.c @@ -156,7 +156,7 @@ static void print_rx_state(struct net_device *dev) ; static void print_tx_state(struct net_device *dev) { - struct xl_private *xl_priv = (struct xl_private *)dev->priv ; + struct xl_private *xl_priv = netdev_priv(dev); struct xl_tx_desc *txd ; u8 __iomem *xl_mmio = xl_priv->xl_mmio ; int i ; @@ -179,7 +179,7 @@ static void print_tx_state(struct net_device *dev) static void print_rx_state(struct net_device *dev) { - struct xl_private *xl_priv = (struct xl_private *)dev->priv ; + struct xl_private *xl_priv = netdev_priv(dev); struct xl_rx_desc *rxd ; u8 __iomem *xl_mmio = xl_priv->xl_mmio ; int i ; @@ -213,7 +213,7 @@ static void print_rx_state(struct net_device *dev) static u16 xl_ee_read(struct net_device *dev, int ee_addr) { - struct xl_private *xl_priv = (struct xl_private *)dev->priv ; + struct xl_private *xl_priv = netdev_priv(dev); u8 __iomem *xl_mmio = xl_priv->xl_mmio ; /* Wait for EEProm to not be busy */ @@ -245,7 +245,7 @@ static u16 xl_ee_read(struct net_device *dev, int ee_addr) static void xl_ee_write(struct net_device *dev, int ee_addr, u16 ee_value) { - struct xl_private *xl_priv = (struct xl_private *)dev->priv ; + struct xl_private *xl_priv = netdev_priv(dev); u8 __iomem *xl_mmio = xl_priv->xl_mmio ; /* Wait for EEProm to not be busy */ @@ -305,11 +305,11 @@ static int __devinit xl_probe(struct pci_dev *pdev, pci_release_regions(pdev) ; return -ENOMEM ; } - xl_priv = dev->priv ; + xl_priv = netdev_priv(dev); #if XL_DEBUG printk("pci_device: %p, dev:%p, dev->priv: %p, ba[0]: %10x, ba[1]:%10x\n", - pdev, dev, dev->priv, (unsigned int)pdev->resource[0].start, (unsigned int)pdev->resource[1].start) ; + pdev, dev, netdev_priv(dev), (unsigned int)pdev->resource[0].start, (unsigned int)pdev->resource[1].start); #endif dev->irq=pdev->irq; @@ -365,7 +365,7 @@ static int __devinit xl_probe(struct pci_dev *pdev, static int __devinit xl_init(struct net_device *dev) { - struct xl_private *xl_priv = (struct xl_private *)dev->priv ; + struct xl_private *xl_priv = netdev_priv(dev); printk(KERN_INFO "%s \n", version); printk(KERN_INFO "%s: I/O at %hx, MMIO at %p, using irq %d\n", @@ -385,7 +385,7 @@ static int __devinit xl_init(struct net_device *dev) static int xl_hw_reset(struct net_device *dev) { - struct xl_private *xl_priv = (struct xl_private *)dev->priv ; + struct xl_private *xl_priv = netdev_priv(dev); u8 __iomem *xl_mmio = xl_priv->xl_mmio ; unsigned long t ; u16 i ; @@ -568,7 +568,7 @@ static int xl_hw_reset(struct net_device *dev) static int xl_open(struct net_device *dev) { - struct xl_private *xl_priv=(struct xl_private *)dev->priv; + struct xl_private *xl_priv=netdev_priv(dev); u8 __iomem *xl_mmio = xl_priv->xl_mmio ; u8 i ; u16 hwaddr[3] ; /* Should be u8[6] but we get word return values */ @@ -726,7 +726,7 @@ static int xl_open(struct net_device *dev) static int xl_open_hw(struct net_device *dev) { - struct xl_private *xl_priv=(struct xl_private *)dev->priv; + struct xl_private *xl_priv=netdev_priv(dev); u8 __iomem *xl_mmio = xl_priv->xl_mmio ; u16 vsoff ; char ver_str[33]; @@ -875,7 +875,7 @@ static int xl_open_hw(struct net_device *dev) static void adv_rx_ring(struct net_device *dev) /* Advance rx_ring, cut down on bloat in xl_rx */ { - struct xl_private *xl_priv=(struct xl_private *)dev->priv; + struct xl_private *xl_priv=netdev_priv(dev); int prev_ring_loc ; prev_ring_loc = (xl_priv->rx_ring_tail + XL_RX_RING_SIZE - 1) & (XL_RX_RING_SIZE - 1); @@ -890,7 +890,7 @@ static void adv_rx_ring(struct net_device *dev) /* Advance rx_ring, cut down on static void xl_rx(struct net_device *dev) { - struct xl_private *xl_priv=(struct xl_private *)dev->priv; + struct xl_private *xl_priv=netdev_priv(dev); u8 __iomem * xl_mmio = xl_priv->xl_mmio ; struct sk_buff *skb, *skb2 ; int frame_length = 0, copy_len = 0 ; @@ -997,7 +997,7 @@ static void xl_rx(struct net_device *dev) static void xl_reset(struct net_device *dev) { - struct xl_private *xl_priv=(struct xl_private *)dev->priv; + struct xl_private *xl_priv=netdev_priv(dev); u8 __iomem * xl_mmio = xl_priv->xl_mmio ; unsigned long t; @@ -1020,7 +1020,7 @@ static void xl_reset(struct net_device *dev) static void xl_freemem(struct net_device *dev) { - struct xl_private *xl_priv=(struct xl_private *)dev->priv ; + struct xl_private *xl_priv=netdev_priv(dev); int i ; for (i=0;ipriv; + struct xl_private *xl_priv =netdev_priv(dev); u8 __iomem * xl_mmio = xl_priv->xl_mmio ; u16 intstatus, macstatus ; @@ -1171,7 +1171,7 @@ static irqreturn_t xl_interrupt(int irq, void *dev_id) static int xl_xmit(struct sk_buff *skb, struct net_device *dev) { - struct xl_private *xl_priv=(struct xl_private *)dev->priv; + struct xl_private *xl_priv=netdev_priv(dev); struct xl_tx_desc *txd ; int tx_head, tx_tail, tx_prev ; unsigned long flags ; @@ -1232,7 +1232,7 @@ static int xl_xmit(struct sk_buff *skb, struct net_device *dev) static void xl_dn_comp(struct net_device *dev) { - struct xl_private *xl_priv=(struct xl_private *)dev->priv; + struct xl_private *xl_priv=netdev_priv(dev); u8 __iomem * xl_mmio = xl_priv->xl_mmio ; struct xl_tx_desc *txd ; @@ -1268,7 +1268,7 @@ static void xl_dn_comp(struct net_device *dev) static int xl_close(struct net_device *dev) { - struct xl_private *xl_priv = (struct xl_private *) dev->priv ; + struct xl_private *xl_priv = netdev_priv(dev); u8 __iomem * xl_mmio = xl_priv->xl_mmio ; unsigned long t ; @@ -1366,7 +1366,7 @@ static int xl_close(struct net_device *dev) static void xl_set_rx_mode(struct net_device *dev) { - struct xl_private *xl_priv = (struct xl_private *) dev->priv ; + struct xl_private *xl_priv = netdev_priv(dev); struct dev_mc_list *dmi ; unsigned char dev_mc_address[4] ; u16 options ; @@ -1407,7 +1407,7 @@ static void xl_set_rx_mode(struct net_device *dev) static void xl_srb_bh(struct net_device *dev) { - struct xl_private *xl_priv = (struct xl_private *) dev->priv ; + struct xl_private *xl_priv = netdev_priv(dev); u8 __iomem * xl_mmio = xl_priv->xl_mmio ; u8 srb_cmd, ret_code ; int i ; @@ -1476,14 +1476,14 @@ static void xl_srb_bh(struct net_device *dev) static struct net_device_stats * xl_get_stats(struct net_device *dev) { - struct xl_private *xl_priv = (struct xl_private *) dev->priv ; + struct xl_private *xl_priv = netdev_priv(dev); return (struct net_device_stats *) &xl_priv->xl_stats; } static int xl_set_mac_address (struct net_device *dev, void *addr) { struct sockaddr *saddr = addr ; - struct xl_private *xl_priv = (struct xl_private *)dev->priv ; + struct xl_private *xl_priv = netdev_priv(dev); if (netif_running(dev)) { printk(KERN_WARNING "%s: Cannot set mac/laa address while card is open\n", dev->name) ; @@ -1504,7 +1504,7 @@ static int xl_set_mac_address (struct net_device *dev, void *addr) static void xl_arb_cmd(struct net_device *dev) { - struct xl_private *xl_priv = (struct xl_private *) dev->priv; + struct xl_private *xl_priv = netdev_priv(dev); u8 __iomem * xl_mmio = xl_priv->xl_mmio ; u8 arb_cmd ; u16 lan_status, lan_status_diff ; @@ -1632,7 +1632,7 @@ static void xl_arb_cmd(struct net_device *dev) static void xl_asb_cmd(struct net_device *dev) { - struct xl_private *xl_priv = (struct xl_private *) dev->priv ; + struct xl_private *xl_priv = netdev_priv(dev); u8 __iomem * xl_mmio = xl_priv->xl_mmio ; if (xl_priv->asb_queued == 1) @@ -1663,7 +1663,7 @@ static void xl_asb_cmd(struct net_device *dev) */ static void xl_asb_bh(struct net_device *dev) { - struct xl_private *xl_priv = (struct xl_private *) dev->priv ; + struct xl_private *xl_priv = netdev_priv(dev); u8 __iomem * xl_mmio = xl_priv->xl_mmio ; u8 ret_code ; @@ -1691,7 +1691,7 @@ static void xl_asb_bh(struct net_device *dev) static void xl_srb_cmd(struct net_device *dev, int srb_cmd) { - struct xl_private *xl_priv = (struct xl_private *) dev->priv ; + struct xl_private *xl_priv = netdev_priv(dev); u8 __iomem * xl_mmio = xl_priv->xl_mmio ; switch (srb_cmd) { @@ -1748,7 +1748,7 @@ static void xl_srb_cmd(struct net_device *dev, int srb_cmd) static void xl_wait_misr_flags(struct net_device *dev) { - struct xl_private *xl_priv = (struct xl_private *) dev->priv ; + struct xl_private *xl_priv = netdev_priv(dev); u8 __iomem * xl_mmio = xl_priv->xl_mmio ; int i ; @@ -1773,7 +1773,7 @@ static void xl_wait_misr_flags(struct net_device *dev) static int xl_change_mtu(struct net_device *dev, int mtu) { - struct xl_private *xl_priv = (struct xl_private *) dev->priv; + struct xl_private *xl_priv = netdev_priv(dev); u16 max_mtu ; if (xl_priv->xl_ring_speed == 4) @@ -1795,7 +1795,7 @@ static int xl_change_mtu(struct net_device *dev, int mtu) static void __devexit xl_remove_one (struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - struct xl_private *xl_priv=(struct xl_private *)dev->priv; + struct xl_private *xl_priv=netdev_priv(dev); unregister_netdev(dev); iounmap(xl_priv->xl_mmio) ; diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c index 1e8958ee2d0..51409698fe2 100644 --- a/drivers/net/tokenring/ibmtr.c +++ b/drivers/net/tokenring/ibmtr.c @@ -327,7 +327,7 @@ static void ibmtr_cleanup_card(struct net_device *dev) release_region(dev->base_addr, IBMTR_IO_EXTENT); { - struct tok_info *ti = (struct tok_info *) dev->priv; + struct tok_info *ti = netdev_priv(dev); iounmap(ti->mmio); iounmap(ti->sram_virt); } @@ -384,7 +384,7 @@ static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr) unsigned char segment, intr=0, irq=0, i, j, cardpresent=NOTOK, temp=0; void __iomem * t_mmio = NULL; - struct tok_info *ti = dev->priv; + struct tok_info *ti = netdev_priv(dev); void __iomem *cd_chanid; unsigned char *tchanid, ctemp; #ifndef PCMCIA @@ -823,7 +823,7 @@ static unsigned char __devinit get_sram_size(struct tok_info *adapt_info) static int __devinit trdev_init(struct net_device *dev) { - struct tok_info *ti = (struct tok_info *) dev->priv; + struct tok_info *ti = netdev_priv(dev); SET_PAGE(ti->srb_page); ti->open_failure = NO ; @@ -846,7 +846,7 @@ static int tok_init_card(struct net_device *dev) unsigned long i; PIOaddr = dev->base_addr; - ti = (struct tok_info *) dev->priv; + ti = netdev_priv(dev); /* Special processing for first interrupt after reset */ ti->do_tok_int = FIRST_INT; /* Reset adapter */ @@ -868,7 +868,7 @@ static int tok_init_card(struct net_device *dev) /*****************************************************************************/ static int tok_open(struct net_device *dev) { - struct tok_info *ti = (struct tok_info *) dev->priv; + struct tok_info *ti = netdev_priv(dev); int i; /*the case we were left in a failure state during a previous open */ @@ -927,7 +927,7 @@ static void tok_open_adapter(unsigned long dev_addr) struct tok_info *ti; int i; - ti = (struct tok_info *) dev->priv; + ti = netdev_priv(dev); SET_PAGE(ti->init_srb_page); writeb(~SRB_RESP_INT, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD); for (i = 0; i < sizeof(struct dir_open_adapter); i++) @@ -962,7 +962,7 @@ static void tok_open_adapter(unsigned long dev_addr) static void open_sap(unsigned char type, struct net_device *dev) { int i; - struct tok_info *ti = (struct tok_info *) dev->priv; + struct tok_info *ti = netdev_priv(dev); SET_PAGE(ti->srb_page); for (i = 0; i < sizeof(struct dlc_open_sap); i++) @@ -986,7 +986,7 @@ static void open_sap(unsigned char type, struct net_device *dev) static void tok_set_multicast_list(struct net_device *dev) { - struct tok_info *ti = (struct tok_info *) dev->priv; + struct tok_info *ti = netdev_priv(dev); struct dev_mc_list *mclist; unsigned char address[4]; @@ -1029,7 +1029,7 @@ static int tok_send_packet(struct sk_buff *skb, struct net_device *dev) { struct tok_info *ti; unsigned long flags; - ti = (struct tok_info *) dev->priv; + ti = netdev_priv(dev); netif_stop_queue(dev); @@ -1051,7 +1051,7 @@ static int tok_send_packet(struct sk_buff *skb, struct net_device *dev) static int tok_close(struct net_device *dev) { - struct tok_info *ti = (struct tok_info *) dev->priv; + struct tok_info *ti = netdev_priv(dev); /* Important for PCMCIA hot unplug, otherwise, we'll pull the card, */ /* unloading the module from memory, and then if a timer pops, ouch */ @@ -1094,7 +1094,7 @@ static void __iomem *map_address(struct tok_info *ti, unsigned index, __u8 *page static void dir_open_adapter (struct net_device *dev) { - struct tok_info *ti = (struct tok_info *) dev->priv; + struct tok_info *ti = netdev_priv(dev); unsigned char ret_code; __u16 err; @@ -1179,7 +1179,7 @@ static irqreturn_t tok_interrupt(int irq, void *dev_id) #if TR_VERBOSE DPRINTK("Int from tok_driver, dev : %p irq%d\n", dev,irq); #endif - ti = (struct tok_info *) dev->priv; + ti = netdev_priv(dev); if (ti->sram_phys & 1) return IRQ_NONE; /* PCMCIA card extraction flag */ spin_lock(&(ti->lock)); @@ -1498,7 +1498,7 @@ static void initial_tok_int(struct net_device *dev) struct tok_info *ti; unsigned char init_status; /*BMS 12/2000*/ - ti = (struct tok_info *) dev->priv; + ti = netdev_priv(dev); ti->do_tok_int = NOT_FIRST; @@ -1560,7 +1560,7 @@ static void initial_tok_int(struct net_device *dev) static void tr_tx(struct net_device *dev) { - struct tok_info *ti = (struct tok_info *) dev->priv; + struct tok_info *ti = netdev_priv(dev); struct trh_hdr *trhdr = (struct trh_hdr *) ti->current_skb->data; unsigned int hdr_len; __u32 dhb=0,dhb_base; @@ -1674,7 +1674,7 @@ static void tr_tx(struct net_device *dev) static void tr_rx(struct net_device *dev) { - struct tok_info *ti = (struct tok_info *) dev->priv; + struct tok_info *ti = netdev_priv(dev); __u32 rbuffer; void __iomem *rbuf, *rbufdata, *llc; __u8 rbuffer_page = 0; @@ -1846,7 +1846,7 @@ static void ibmtr_reset_timer(struct timer_list *tmr, struct net_device *dev) void tok_rerun(unsigned long dev_addr){ struct net_device *dev = (struct net_device *)dev_addr; - struct tok_info *ti = (struct tok_info *) dev->priv; + struct tok_info *ti = netdev_priv(dev); if ( ti->open_action == RESTART){ ti->do_tok_int = FIRST_INT; @@ -1868,7 +1868,7 @@ static void ibmtr_readlog(struct net_device *dev) { struct tok_info *ti; - ti = (struct tok_info *) dev->priv; + ti = netdev_priv(dev); ti->readlog_pending = 0; SET_PAGE(ti->srb_page); @@ -1891,7 +1891,7 @@ static struct net_device_stats *tok_get_stats(struct net_device *dev) { struct tok_info *toki; - toki = (struct tok_info *) dev->priv; + toki = netdev_priv(dev); return (struct net_device_stats *) &toki->tr_stats; } @@ -1899,7 +1899,7 @@ static struct net_device_stats *tok_get_stats(struct net_device *dev) static int ibmtr_change_mtu(struct net_device *dev, int mtu) { - struct tok_info *ti = (struct tok_info *) dev->priv; + struct tok_info *ti = netdev_priv(dev); if (ti->ring_speed == 16 && mtu > ti->maxmtu16) return -EINVAL; diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c index fc4495581f9..49c4270ef5f 100644 --- a/drivers/net/tokenring/lanstreamer.c +++ b/drivers/net/tokenring/lanstreamer.c @@ -246,7 +246,7 @@ static int __devinit streamer_init_one(struct pci_dev *pdev, } SET_MODULE_OWNER(dev); - streamer_priv = dev->priv; + streamer_priv = netdev_priv(dev); #if STREAMER_NETWORK_MONITOR #ifdef CONFIG_PROC_FS @@ -405,7 +405,7 @@ static void __devexit streamer_remove_one(struct pci_dev *pdev) return; } - streamer_priv=dev->priv; + streamer_priv=netdev_priv(dev); if (streamer_priv == NULL) { printk(KERN_ERR "lanstreamer::streamer_remove_one, ERROR dev->priv is NULL\n"); return; @@ -449,7 +449,7 @@ static int streamer_reset(struct net_device *dev) struct sk_buff *skb = NULL; __u16 misr; - streamer_priv = (struct streamer_private *) dev->priv; + streamer_priv = netdev_priv(dev); streamer_mmio = streamer_priv->streamer_mmio; writew(readw(streamer_mmio + BCTL) | BCTL_SOFTRESET, streamer_mmio + BCTL); @@ -588,7 +588,7 @@ static int streamer_reset(struct net_device *dev) static int streamer_open(struct net_device *dev) { - struct streamer_private *streamer_priv = (struct streamer_private *) dev->priv; + struct streamer_private *streamer_priv = netdev_priv(dev); __u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio; unsigned long flags; char open_error[255]; @@ -905,7 +905,7 @@ static int streamer_open(struct net_device *dev) static void streamer_rx(struct net_device *dev) { struct streamer_private *streamer_priv = - (struct streamer_private *) dev->priv; + netdev_priv(dev); __u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio; struct streamer_rx_desc *rx_desc; int rx_ring_last_received, length, frame_length, buffer_cnt = 0; @@ -1030,7 +1030,7 @@ static irqreturn_t streamer_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; struct streamer_private *streamer_priv = - (struct streamer_private *) dev->priv; + netdev_priv(dev); __u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio; __u16 sisr; __u16 misr; @@ -1153,7 +1153,7 @@ static irqreturn_t streamer_interrupt(int irq, void *dev_id) static int streamer_xmit(struct sk_buff *skb, struct net_device *dev) { struct streamer_private *streamer_priv = - (struct streamer_private *) dev->priv; + netdev_priv(dev); __u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio; unsigned long flags ; @@ -1204,7 +1204,7 @@ static int streamer_xmit(struct sk_buff *skb, struct net_device *dev) static int streamer_close(struct net_device *dev) { struct streamer_private *streamer_priv = - (struct streamer_private *) dev->priv; + netdev_priv(dev); __u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio; unsigned long flags; int i; @@ -1270,7 +1270,7 @@ static int streamer_close(struct net_device *dev) static void streamer_set_rx_mode(struct net_device *dev) { struct streamer_private *streamer_priv = - (struct streamer_private *) dev->priv; + netdev_priv(dev); __u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio; __u8 options = 0; struct dev_mc_list *dmi; @@ -1329,7 +1329,7 @@ static void streamer_set_rx_mode(struct net_device *dev) static void streamer_srb_bh(struct net_device *dev) { - struct streamer_private *streamer_priv = (struct streamer_private *) dev->priv; + struct streamer_private *streamer_priv = netdev_priv(dev); __u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio; __u16 srb_word; @@ -1494,14 +1494,14 @@ static void streamer_srb_bh(struct net_device *dev) static struct net_device_stats *streamer_get_stats(struct net_device *dev) { struct streamer_private *streamer_priv; - streamer_priv = (struct streamer_private *) dev->priv; + streamer_priv = netdev_priv(dev); return (struct net_device_stats *) &streamer_priv->streamer_stats; } static int streamer_set_mac_address(struct net_device *dev, void *addr) { struct sockaddr *saddr = addr; - struct streamer_private *streamer_priv = (struct streamer_private *) dev->priv; + struct streamer_private *streamer_priv = netdev_priv(dev); if (netif_running(dev)) { @@ -1526,7 +1526,7 @@ static int streamer_set_mac_address(struct net_device *dev, void *addr) static void streamer_arb_cmd(struct net_device *dev) { struct streamer_private *streamer_priv = - (struct streamer_private *) dev->priv; + netdev_priv(dev); __u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio; __u8 header_len; __u16 frame_len, buffer_len; @@ -1741,7 +1741,7 @@ drop_frame: static void streamer_asb_bh(struct net_device *dev) { struct streamer_private *streamer_priv = - (struct streamer_private *) dev->priv; + netdev_priv(dev); __u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio; if (streamer_priv->asb_queued == 1) @@ -1785,7 +1785,7 @@ static void streamer_asb_bh(struct net_device *dev) static int streamer_change_mtu(struct net_device *dev, int mtu) { struct streamer_private *streamer_priv = - (struct streamer_private *) dev->priv; + netdev_priv(dev); __u16 max_mtu; if (streamer_priv->streamer_ring_speed == 4) @@ -1849,7 +1849,7 @@ static int streamer_proc_info(char *buffer, char **start, off_t offset, static int sprintf_info(char *buffer, struct net_device *dev) { struct streamer_private *streamer_priv = - (struct streamer_private *) dev->priv; + netdev_priv(dev); __u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio; struct streamer_adapter_addr_table sat; struct streamer_parameters_table spt; diff --git a/drivers/net/tokenring/madgemc.c b/drivers/net/tokenring/madgemc.c index f8f4d74f01f..9eafc2e25ab 100644 --- a/drivers/net/tokenring/madgemc.c +++ b/drivers/net/tokenring/madgemc.c @@ -690,7 +690,7 @@ static int madgemc_close(struct net_device *dev) static int madgemc_mcaproc(char *buf, int slot, void *d) { struct net_device *dev = (struct net_device *)d; - struct net_local *tp = dev->priv; + struct net_local *tp = netdev_priv(dev); struct card_info *curcard = tp->tmspriv; int len = 0; @@ -736,7 +736,7 @@ static int __devexit madgemc_remove(struct device *device) BUG_ON(!dev); - tp = dev->priv; + tp = netdev_priv(dev); card = tp->tmspriv; kfree(card); tp->tmspriv = NULL; diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c index c323101a895..b57f65b2591 100644 --- a/drivers/net/tokenring/olympic.c +++ b/drivers/net/tokenring/olympic.c @@ -220,14 +220,14 @@ static int __devinit olympic_probe(struct pci_dev *pdev, const struct pci_device goto op_release_dev; } - olympic_priv = dev->priv ; + olympic_priv = netdev_priv(dev) ; spin_lock_init(&olympic_priv->olympic_lock) ; init_waitqueue_head(&olympic_priv->srb_wait); init_waitqueue_head(&olympic_priv->trb_wait); #if OLYMPIC_DEBUG - printk(KERN_INFO "pci_device: %p, dev:%p, dev->priv: %p\n", pdev, dev, dev->priv); + printk(KERN_INFO "pci_device: %p, dev:%p, dev->priv: %p\n", pdev, dev, netdev_priv(dev)); #endif dev->irq=pdev->irq; dev->base_addr=pci_resource_start(pdev, 0); @@ -298,7 +298,7 @@ static int __devinit olympic_init(struct net_device *dev) unsigned long t; unsigned int uaa_addr; - olympic_priv=(struct olympic_private *)dev->priv; + olympic_priv=netdev_priv(dev); olympic_mmio=olympic_priv->olympic_mmio; printk("%s \n", version); @@ -436,7 +436,7 @@ static int __devinit olympic_init(struct net_device *dev) static int olympic_open(struct net_device *dev) { - struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv; + struct olympic_private *olympic_priv=netdev_priv(dev); u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio,*init_srb; unsigned long flags, t; int i, open_finished = 1 ; @@ -756,7 +756,7 @@ out: */ static void olympic_rx(struct net_device *dev) { - struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv; + struct olympic_private *olympic_priv=netdev_priv(dev); u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio; struct olympic_rx_status *rx_status; struct olympic_rx_desc *rx_desc ; @@ -898,7 +898,7 @@ static void olympic_rx(struct net_device *dev) static void olympic_freemem(struct net_device *dev) { - struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv; + struct olympic_private *olympic_priv=netdev_priv(dev); int i; for(i=0;ipriv; + struct olympic_private *olympic_priv=netdev_priv(dev); u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio; u32 sisr; u8 __iomem *adapter_check_area ; @@ -1047,7 +1047,7 @@ static irqreturn_t olympic_interrupt(int irq, void *dev_id) static int olympic_xmit(struct sk_buff *skb, struct net_device *dev) { - struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv; + struct olympic_private *olympic_priv=netdev_priv(dev); u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio; unsigned long flags ; @@ -1078,7 +1078,7 @@ static int olympic_xmit(struct sk_buff *skb, struct net_device *dev) static int olympic_close(struct net_device *dev) { - struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv; + struct olympic_private *olympic_priv=netdev_priv(dev); u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio,*srb; unsigned long t,flags; @@ -1148,7 +1148,7 @@ static int olympic_close(struct net_device *dev) static void olympic_set_rx_mode(struct net_device *dev) { - struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv ; + struct olympic_private *olympic_priv = netdev_priv(dev); u8 __iomem *olympic_mmio = olympic_priv->olympic_mmio ; u8 options = 0; u8 __iomem *srb; @@ -1216,7 +1216,7 @@ static void olympic_set_rx_mode(struct net_device *dev) static void olympic_srb_bh(struct net_device *dev) { - struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv ; + struct olympic_private *olympic_priv = netdev_priv(dev); u8 __iomem *olympic_mmio = olympic_priv->olympic_mmio ; u8 __iomem *srb; @@ -1362,14 +1362,14 @@ static void olympic_srb_bh(struct net_device *dev) static struct net_device_stats * olympic_get_stats(struct net_device *dev) { struct olympic_private *olympic_priv ; - olympic_priv=(struct olympic_private *) dev->priv; + olympic_priv=netdev_priv(dev); return (struct net_device_stats *) &olympic_priv->olympic_stats; } static int olympic_set_mac_address (struct net_device *dev, void *addr) { struct sockaddr *saddr = addr ; - struct olympic_private *olympic_priv = (struct olympic_private *)dev->priv ; + struct olympic_private *olympic_priv = netdev_priv(dev); if (netif_running(dev)) { printk(KERN_WARNING "%s: Cannot set mac/laa address while card is open\n", dev->name) ; @@ -1390,7 +1390,7 @@ static int olympic_set_mac_address (struct net_device *dev, void *addr) static void olympic_arb_cmd(struct net_device *dev) { - struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv; + struct olympic_private *olympic_priv = netdev_priv(dev); u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio; u8 __iomem *arb_block, *asb_block, *srb ; u8 header_len ; @@ -1576,7 +1576,7 @@ drop_frame: static void olympic_asb_bh(struct net_device *dev) { - struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv ; + struct olympic_private *olympic_priv = netdev_priv(dev); u8 __iomem *arb_block, *asb_block ; arb_block = (olympic_priv->olympic_lap + olympic_priv->arb) ; @@ -1616,7 +1616,7 @@ static void olympic_asb_bh(struct net_device *dev) static int olympic_change_mtu(struct net_device *dev, int mtu) { - struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv; + struct olympic_private *olympic_priv = netdev_priv(dev); u16 max_mtu ; if (olympic_priv->olympic_ring_speed == 4) @@ -1638,7 +1638,7 @@ static int olympic_change_mtu(struct net_device *dev, int mtu) static int olympic_proc_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data) { struct net_device *dev = (struct net_device *)data ; - struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv; + struct olympic_private *olympic_priv=netdev_priv(dev); u8 __iomem *oat = (olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr) ; u8 __iomem *opt = (olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr) ; int size = 0 ; @@ -1749,7 +1749,7 @@ static int olympic_proc_info(char *buffer, char **start, off_t offset, int lengt static void __devexit olympic_remove_one(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev) ; - struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv; + struct olympic_private *olympic_priv=netdev_priv(dev); if (olympic_priv->olympic_network_monitor) { char proc_name[20] ; diff --git a/drivers/net/tokenring/tmspci.c b/drivers/net/tokenring/tmspci.c index 3b2f00b9b7b..aec75c930c2 100644 --- a/drivers/net/tokenring/tmspci.c +++ b/drivers/net/tokenring/tmspci.c @@ -149,7 +149,7 @@ static int __devinit tms_pci_attach(struct pci_dev *pdev, const struct pci_devic goto err_out_irq; } - tp = dev->priv; + tp = netdev_priv(dev); tp->setnselout = tms_pci_setnselout_pins; tp->sifreadb = tms_pci_sifreadb; @@ -210,7 +210,7 @@ static void tms_pci_read_eeprom(struct net_device *dev) static unsigned short tms_pci_setnselout_pins(struct net_device *dev) { unsigned short val = 0; - struct net_local *tp = dev->priv; + struct net_local *tp = netdev_priv(dev); struct card_info *cardinfo = tp->tmspriv; if(tp->DataRate == SPEED_4) -- cgit v1.2.3-70-g09d2 From c54f5c240239fb8391a3b541f916764dd496f2e6 Mon Sep 17 00:00:00 2001 From: Denis Cheng Date: Wed, 18 Jul 2007 15:24:49 +0800 Subject: drivers/net/cxgb3: removed several unneeded zero initilization Cc: linux-bugs@chelsio.com Signed-off-by: Denis Cheng Signed-off-by: Jeff Garzik --- drivers/net/cxgb3/cxgb3_main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index 5db7d4e27ec..57fc199e061 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -793,7 +793,7 @@ release_tpsram: */ static int cxgb_up(struct adapter *adap) { - int err = 0; + int err; int must_load; if (!(adap->flags & FULL_INIT_DONE)) { @@ -907,7 +907,7 @@ static int offload_open(struct net_device *dev) struct adapter *adapter = pi->adapter; struct t3cdev *tdev = dev2t3cdev(dev); int adap_up = adapter->open_device_map & PORT_MASK; - int err = 0; + int err; if (test_and_set_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) return 0; @@ -1566,7 +1566,7 @@ static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, struct adapter *adapter = pi->adapter; u32 aligned_offset, aligned_len, *p; u8 *buf; - int err = 0; + int err; if (eeprom->magic != EEPROM_MAGIC) return -EINVAL; -- cgit v1.2.3-70-g09d2 From bbfb86c5776ff481d246fcd5d8deb67701e05c00 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 25 Jul 2007 12:31:57 +0100 Subject: IOC3: Switch hw checksumming to ethtool configurable. Signed-off-by: Ralf Baechle Signed-off-by: Jeff Garzik --- drivers/net/Kconfig | 20 -------------------- drivers/net/ioc3-eth.c | 48 ++++++++++++++++++++++++++++++++---------------- 2 files changed, 32 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 10ed28ef356..734f8403c80 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -486,26 +486,6 @@ config SGI_IOC3_ETH the Ethernet-HOWTO, available from . -config SGI_IOC3_ETH_HW_RX_CSUM - bool "Receive hardware checksums" - depends on SGI_IOC3_ETH && INET - default y - help - The SGI IOC3 network adapter supports TCP and UDP checksums in - hardware to offload processing of these checksums from the CPU. At - the moment only acceleration of IPv4 is supported. This option - enables offloading for checksums on receive. If unsure, say Y. - -config SGI_IOC3_ETH_HW_TX_CSUM - bool "Transmit hardware checksums" - depends on SGI_IOC3_ETH && INET - default y - help - The SGI IOC3 network adapter supports TCP and UDP checksums in - hardware to offload processing of these checksums from the CPU. At - the moment only acceleration of IPv4 is supported. This option - enables offloading for checksums on transmit. If unsure, say Y. - config MIPS_SIM_NET tristate "MIPS simulator Network device" depends on MIPS_SIM diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c index 0834ef0eddb..c030030e586 100644 --- a/drivers/net/ioc3-eth.c +++ b/drivers/net/ioc3-eth.c @@ -5,7 +5,7 @@ * * Driver for SGI's IOC3 based Ethernet cards as found in the PCI card. * - * Copyright (C) 1999, 2000, 2001, 2003 Ralf Baechle + * Copyright (C) 1999, 2000, 01, 03, 06 Ralf Baechle * Copyright (C) 1995, 1999, 2000, 2001 by Silicon Graphics, Inc. * * References: @@ -62,12 +62,7 @@ #include #include #include -#include -#include -#include -#include #include -#include #include /* @@ -95,6 +90,9 @@ struct ioc3_private { u32 emcr, ehar_h, ehar_l; spinlock_t ioc3_lock; struct mii_if_info mii; + unsigned long flags; +#define IOC3_FLAG_RX_CHECKSUMS 1 + struct pci_dev *pdev; /* Members used by autonegotiation */ @@ -521,8 +519,6 @@ static struct net_device_stats *ioc3_get_stats(struct net_device *dev) return &ip->stats; } -#ifdef CONFIG_SGI_IOC3_ETH_HW_RX_CSUM - static void ioc3_tcpudp_checksum(struct sk_buff *skb, uint32_t hwsum, int len) { struct ethhdr *eh = eth_hdr(skb); @@ -590,7 +586,6 @@ static void ioc3_tcpudp_checksum(struct sk_buff *skb, uint32_t hwsum, int len) if (csum == 0xffff) skb->ip_summed = CHECKSUM_UNNECESSARY; } -#endif /* CONFIG_SGI_IOC3_ETH_HW_RX_CSUM */ static inline void ioc3_rx(struct ioc3_private *ip) { @@ -625,9 +620,9 @@ static inline void ioc3_rx(struct ioc3_private *ip) goto next; } -#ifdef CONFIG_SGI_IOC3_ETH_HW_RX_CSUM - ioc3_tcpudp_checksum(skb, w0 & ERXBUF_IPCKSUM_MASK,len); -#endif + if (likely(ip->flags & IOC3_FLAG_RX_CHECKSUMS)) + ioc3_tcpudp_checksum(skb, + w0 & ERXBUF_IPCKSUM_MASK, len); netif_rx(skb); @@ -1338,9 +1333,7 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent) dev->set_multicast_list = ioc3_set_multicast_list; dev->set_mac_address = ioc3_set_mac_address; dev->ethtool_ops = &ioc3_ethtool_ops; -#ifdef CONFIG_SGI_IOC3_ETH_HW_TX_CSUM dev->features = NETIF_F_IP_CSUM; -#endif sw_physid1 = ioc3_mdio_read(dev, ip->mii.phy_id, MII_PHYSID1); sw_physid2 = ioc3_mdio_read(dev, ip->mii.phy_id, MII_PHYSID2); @@ -1430,7 +1423,6 @@ static int ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev) uint32_t w0 = 0; int produce; -#ifdef CONFIG_SGI_IOC3_ETH_HW_TX_CSUM /* * IOC3 has a fairly simple minded checksumming hardware which simply * adds up the 1's complement checksum for the entire packet and @@ -1478,7 +1470,6 @@ static int ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev) w0 = ETXD_DOCHECKSUM | (csoff << ETXD_CHKOFF_SHIFT); } -#endif /* CONFIG_SGI_IOC3_ETH_HW_TX_CSUM */ spin_lock_irq(&ip->ioc3_lock); @@ -1633,12 +1624,37 @@ static u32 ioc3_get_link(struct net_device *dev) return rc; } +static u32 ioc3_get_rx_csum(struct net_device *dev) +{ + struct ioc3_private *ip = netdev_priv(dev); + + return ip->flags & IOC3_FLAG_RX_CHECKSUMS; +} + +static int ioc3_set_rx_csum(struct net_device *dev, u32 data) +{ + struct ioc3_private *ip = netdev_priv(dev); + + spin_lock_bh(&ip->ioc3_lock); + if (data) + ip->flags |= IOC3_FLAG_RX_CHECKSUMS; + else + ip->flags &= ~IOC3_FLAG_RX_CHECKSUMS; + spin_unlock_bh(&ip->ioc3_lock); + + return 0; +} + static const struct ethtool_ops ioc3_ethtool_ops = { .get_drvinfo = ioc3_get_drvinfo, .get_settings = ioc3_get_settings, .set_settings = ioc3_set_settings, .nway_reset = ioc3_nway_reset, .get_link = ioc3_get_link, + .get_rx_csum = ioc3_get_rx_csum, + .set_rx_csum = ioc3_set_rx_csum, + .get_tx_csum = ethtool_op_get_tx_csum, + .set_tx_csum = ethtool_op_set_tx_csum }; static int ioc3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -- cgit v1.2.3-70-g09d2 From a967b14035c5efe4c92623dde3776ffc7a79118c Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 2 Aug 2007 16:31:25 -0400 Subject: drivers/net/skfp: Remove dead code referencing pci_find_device() Signed-off-by: Jeff Garzik --- drivers/net/skfp/drvfbi.c | 40 ---------------------------------------- drivers/net/skfp/h/skfbi.h | 5 ----- 2 files changed, 45 deletions(-) (limited to 'drivers') diff --git a/drivers/net/skfp/drvfbi.c b/drivers/net/skfp/drvfbi.c index be2ee6519ef..c77cc14b322 100644 --- a/drivers/net/skfp/drvfbi.c +++ b/drivers/net/skfp/drvfbi.c @@ -537,46 +537,6 @@ int set_oi_id_def(struct s_smc *smc) } #endif /* MULT_OEM */ -#ifdef PCI -#ifdef USE_BIOS_FUN -int exist_board(struct s_smc *smc, int slot) -{ - u_short dev_id ; - u_short ven_id ; - int found ; - int i ; - - found = FALSE ; /* make sure we returned with adatper not found*/ - /* if an empty oemids.h was included */ - -#ifdef MULT_OEM - smc->hw.oem_id = (struct s_oem_ids *) &oem_ids[0] ; - for (; smc->hw.oem_id->oi_status != OI_STAT_LAST; smc->hw.oem_id++) { - if (smc->hw.oem_id->oi_status < smc->hw.oem_min_status) - continue ; -#endif - ven_id = OEMID(smc,0) + (OEMID(smc,1) << 8) ; - dev_id = OEMID(smc,2) + (OEMID(smc,3) << 8) ; - for (i = 0; i < slot; i++) { - if (pci_find_device(i,&smc->hw.pci_handle, - dev_id,ven_id) != 0) { - - found = FALSE ; - } else { - found = TRUE ; - } - } - if (found) { - return(1) ; /* adapter was found */ - } -#ifdef MULT_OEM - } -#endif - return(0) ; /* adapter was not found */ -} -#endif /* PCI */ -#endif /* USE_BIOS_FUNC */ - void driver_get_bia(struct s_smc *smc, struct fddi_addr *bia_addr) { int i ; diff --git a/drivers/net/skfp/h/skfbi.h b/drivers/net/skfp/h/skfbi.h index d25c9f84984..c1ba26c06d7 100644 --- a/drivers/net/skfp/h/skfbi.h +++ b/drivers/net/skfp/h/skfbi.h @@ -15,11 +15,6 @@ #ifndef _SKFBI_H_ #define _SKFBI_H_ -#ifdef SYNC -#define exist_board_far exist_board -#define get_board_para_far get_board_para -#endif - /* * FDDI-Fx (x := {I(SA), P(CI)}) * address calculation & function defines -- cgit v1.2.3-70-g09d2 From c477f3348abb5f6fb8b627cfdb1d7ae4b8fe613b Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Tue, 31 Jul 2007 23:58:36 +0200 Subject: drivers/net/sb1250-mac.c: kmalloc + memset conversion to kcalloc Signed-off-by: Mariusz Kozlowski drivers/net/sb1250-mac.c | 76286 -> 76199 (-87 bytes) drivers/net/sb1250-mac.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) Signed-off-by: Jeff Garzik --- drivers/net/sb1250-mac.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index 53845ebb649..b6cafac9720 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -780,10 +780,8 @@ static void sbdma_initctx(sbmacdma_t *d, * And context table */ - d->sbdma_ctxtable = (struct sk_buff **) - kmalloc(d->sbdma_maxdescr*sizeof(struct sk_buff *), GFP_KERNEL); - - memset(d->sbdma_ctxtable,0,d->sbdma_maxdescr*sizeof(struct sk_buff *)); + d->sbdma_ctxtable = kcalloc(d->sbdma_maxdescr, + sizeof(struct sk_buff *), GFP_KERNEL); #ifdef CONFIG_SBMAC_COALESCE /* -- cgit v1.2.3-70-g09d2 From ae94607d19028f9805e82da8975c66d3858fcfd8 Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Wed, 1 Aug 2007 00:11:50 +0200 Subject: drivers/net/via-velocity.c: mostly kmalloc + memset conversion to kcalloc Signed-off-by: Mariusz Kozlowski drivers/net/via-velocity.c | 88263 -> 88120 (-143 bytes) drivers/net/via-velocity.o | 254264 -> 253828 (-436 bytes) drivers/net/via-velocity.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) Signed-off-by: Jeff Garzik --- drivers/net/via-velocity.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index 93574add406..a4729bc385f 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -1071,14 +1071,12 @@ static int velocity_rx_refill(struct velocity_info *vptr) static int velocity_init_rd_ring(struct velocity_info *vptr) { - int ret = -ENOMEM; - unsigned int rsize = sizeof(struct velocity_rd_info) * - vptr->options.numrx; + int ret; - vptr->rd_info = kmalloc(rsize, GFP_KERNEL); - if(vptr->rd_info == NULL) - goto out; - memset(vptr->rd_info, 0, rsize); + vptr->rd_info = kcalloc(vptr->options.numrx, + sizeof(struct velocity_rd_info), GFP_KERNEL); + if (!vptr->rd_info) + return -ENOMEM; vptr->rd_filled = vptr->rd_dirty = vptr->rd_curr = 0; @@ -1088,7 +1086,7 @@ static int velocity_init_rd_ring(struct velocity_info *vptr) "%s: failed to allocate RX buffer.\n", vptr->dev->name); velocity_free_rd_ring(vptr); } -out: + return ret; } @@ -1142,21 +1140,19 @@ static int velocity_init_td_ring(struct velocity_info *vptr) dma_addr_t curr; struct tx_desc *td; struct velocity_td_info *td_info; - unsigned int tsize = sizeof(struct velocity_td_info) * - vptr->options.numtx; /* Init the TD ring entries */ for (j = 0; j < vptr->num_txq; j++) { curr = vptr->td_pool_dma[j]; - vptr->td_infos[j] = kmalloc(tsize, GFP_KERNEL); - if(vptr->td_infos[j] == NULL) - { + vptr->td_infos[j] = kcalloc(vptr->options.numtx, + sizeof(struct velocity_td_info), + GFP_KERNEL); + if (!vptr->td_infos[j]) { while(--j >= 0) kfree(vptr->td_infos[j]); return -ENOMEM; } - memset(vptr->td_infos[j], 0, tsize); for (i = 0; i < vptr->options.numtx; i++, curr += sizeof(struct tx_desc)) { td = &(vptr->td_rings[j][i]); -- cgit v1.2.3-70-g09d2 From 6cc92cddb13a7874dcd7751c84b0e61738815077 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 8 Aug 2007 02:16:04 -0400 Subject: [netdrvr] 8139cp, 8139too: convert to generic DMA Signed-off-by: Jeff Garzik --- drivers/net/8139cp.c | 31 +++++++++++++++++-------------- drivers/net/8139too.c | 20 ++++++++++---------- 2 files changed, 27 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index 7f18ca23d9f..2dec3d6ae01 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -562,7 +562,7 @@ rx_status_loop: skb_reserve(new_skb, RX_OFFSET); - pci_unmap_single(cp->pdev, mapping, + dma_unmap_single(&cp->pdev->dev, mapping, buflen, PCI_DMA_FROMDEVICE); /* Handle checksum offloading for incoming packets. */ @@ -573,7 +573,7 @@ rx_status_loop: skb_put(skb, len); - mapping = pci_map_single(cp->pdev, new_skb->data, buflen, + mapping = dma_map_single(&cp->pdev->dev, new_skb->data, buflen, PCI_DMA_FROMDEVICE); cp->rx_skb[rx_tail] = new_skb; @@ -701,7 +701,7 @@ static void cp_tx (struct cp_private *cp) skb = cp->tx_skb[tx_tail]; BUG_ON(!skb); - pci_unmap_single(cp->pdev, le64_to_cpu(txd->addr), + dma_unmap_single(&cp->pdev->dev, le64_to_cpu(txd->addr), le32_to_cpu(txd->opts1) & 0xffff, PCI_DMA_TODEVICE); @@ -779,7 +779,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) dma_addr_t mapping; len = skb->len; - mapping = pci_map_single(cp->pdev, skb->data, len, PCI_DMA_TODEVICE); + mapping = dma_map_single(&cp->pdev->dev, skb->data, len, PCI_DMA_TODEVICE); CP_VLAN_TX_TAG(txd, vlan_tag); txd->addr = cpu_to_le64(mapping); wmb(); @@ -815,7 +815,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) */ first_eor = eor; first_len = skb_headlen(skb); - first_mapping = pci_map_single(cp->pdev, skb->data, + first_mapping = dma_map_single(&cp->pdev->dev, skb->data, first_len, PCI_DMA_TODEVICE); cp->tx_skb[entry] = skb; entry = NEXT_TX(entry); @@ -827,7 +827,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) dma_addr_t mapping; len = this_frag->size; - mapping = pci_map_single(cp->pdev, + mapping = dma_map_single(&cp->pdev->dev, ((void *) page_address(this_frag->page) + this_frag->page_offset), len, PCI_DMA_TODEVICE); @@ -1066,8 +1066,8 @@ static int cp_refill_rx (struct cp_private *cp) skb_reserve(skb, RX_OFFSET); - mapping = pci_map_single(cp->pdev, skb->data, cp->rx_buf_sz, - PCI_DMA_FROMDEVICE); + mapping = dma_map_single(&cp->pdev->dev, skb->data, + cp->rx_buf_sz, PCI_DMA_FROMDEVICE); cp->rx_skb[i] = skb; cp->rx_ring[i].opts2 = 0; @@ -1107,7 +1107,8 @@ static int cp_alloc_rings (struct cp_private *cp) { void *mem; - mem = pci_alloc_consistent(cp->pdev, CP_RING_BYTES, &cp->ring_dma); + mem = dma_alloc_coherent(&cp->pdev->dev, CP_RING_BYTES, + &cp->ring_dma, GFP_KERNEL); if (!mem) return -ENOMEM; @@ -1125,7 +1126,7 @@ static void cp_clean_rings (struct cp_private *cp) for (i = 0; i < CP_RX_RING_SIZE; i++) { if (cp->rx_skb[i]) { desc = cp->rx_ring + i; - pci_unmap_single(cp->pdev, le64_to_cpu(desc->addr), + dma_unmap_single(&cp->pdev->dev,le64_to_cpu(desc->addr), cp->rx_buf_sz, PCI_DMA_FROMDEVICE); dev_kfree_skb(cp->rx_skb[i]); } @@ -1136,7 +1137,7 @@ static void cp_clean_rings (struct cp_private *cp) struct sk_buff *skb = cp->tx_skb[i]; desc = cp->tx_ring + i; - pci_unmap_single(cp->pdev, le64_to_cpu(desc->addr), + dma_unmap_single(&cp->pdev->dev,le64_to_cpu(desc->addr), le32_to_cpu(desc->opts1) & 0xffff, PCI_DMA_TODEVICE); if (le32_to_cpu(desc->opts1) & LastFrag) @@ -1155,7 +1156,8 @@ static void cp_clean_rings (struct cp_private *cp) static void cp_free_rings (struct cp_private *cp) { cp_clean_rings(cp); - pci_free_consistent(cp->pdev, CP_RING_BYTES, cp->rx_ring, cp->ring_dma); + dma_free_coherent(&cp->pdev->dev, CP_RING_BYTES, cp->rx_ring, + cp->ring_dma); cp->rx_ring = NULL; cp->tx_ring = NULL; } @@ -1519,7 +1521,8 @@ static void cp_get_ethtool_stats (struct net_device *dev, dma_addr_t dma; int i; - nic_stats = pci_alloc_consistent(cp->pdev, sizeof(*nic_stats), &dma); + nic_stats = dma_alloc_coherent(&cp->pdev->dev, sizeof(*nic_stats), + &dma, GFP_KERNEL); if (!nic_stats) return; @@ -1554,7 +1557,7 @@ static void cp_get_ethtool_stats (struct net_device *dev, tmp_stats[i++] = cp->cp_stats.rx_frags; BUG_ON(i != CP_NUM_STATS); - pci_free_consistent(cp->pdev, sizeof(*nic_stats), nic_stats, dma); + dma_free_coherent(&cp->pdev->dev, sizeof(*nic_stats), nic_stats, dma); } static const struct ethtool_ops cp_ethtool_ops = { diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index 20af6baecfc..76d3048a1a6 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -1316,18 +1316,18 @@ static int rtl8139_open (struct net_device *dev) if (retval) return retval; - tp->tx_bufs = pci_alloc_consistent(tp->pci_dev, TX_BUF_TOT_LEN, - &tp->tx_bufs_dma); - tp->rx_ring = pci_alloc_consistent(tp->pci_dev, RX_BUF_TOT_LEN, - &tp->rx_ring_dma); + tp->tx_bufs = dma_alloc_coherent(&tp->pci_dev->dev, TX_BUF_TOT_LEN, + &tp->tx_bufs_dma, GFP_KERNEL); + tp->rx_ring = dma_alloc_coherent(&tp->pci_dev->dev, RX_BUF_TOT_LEN, + &tp->rx_ring_dma, GFP_KERNEL); if (tp->tx_bufs == NULL || tp->rx_ring == NULL) { free_irq(dev->irq, dev); if (tp->tx_bufs) - pci_free_consistent(tp->pci_dev, TX_BUF_TOT_LEN, + dma_free_coherent(&tp->pci_dev->dev, TX_BUF_TOT_LEN, tp->tx_bufs, tp->tx_bufs_dma); if (tp->rx_ring) - pci_free_consistent(tp->pci_dev, RX_BUF_TOT_LEN, + dma_free_coherent(&tp->pci_dev->dev, RX_BUF_TOT_LEN, tp->rx_ring, tp->rx_ring_dma); return -ENOMEM; @@ -2246,10 +2246,10 @@ static int rtl8139_close (struct net_device *dev) rtl8139_tx_clear (tp); - pci_free_consistent(tp->pci_dev, RX_BUF_TOT_LEN, - tp->rx_ring, tp->rx_ring_dma); - pci_free_consistent(tp->pci_dev, TX_BUF_TOT_LEN, - tp->tx_bufs, tp->tx_bufs_dma); + dma_free_coherent(&tp->pci_dev->dev, RX_BUF_TOT_LEN, + tp->rx_ring, tp->rx_ring_dma); + dma_free_coherent(&tp->pci_dev->dev, TX_BUF_TOT_LEN, + tp->tx_bufs, tp->tx_bufs_dma); tp->rx_ring = NULL; tp->tx_bufs = NULL; -- cgit v1.2.3-70-g09d2 From 28006c65a74403a8c4a1846aa7f08981e0d0b44a Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Sat, 15 Sep 2007 12:36:46 -0700 Subject: [8139too]: tab-align enums and structs; remove dead code * (main change) tab-align hardware register value enums, and hw struct * MMIO_FLUSH_AUDIT_COMPLETE has been defined to 1 for a while. Remove the code activated when it is set to zero. Signed-off-by: Jeff Garzik Signed-off-by: David S. Miller --- drivers/net/8139too.c | 344 +++++++++++++++++++++++++------------------------- 1 file changed, 169 insertions(+), 175 deletions(-) (limited to 'drivers') diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index 76d3048a1a6..7ba470ee217 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -291,198 +291,197 @@ static struct { /* Symbolic offsets to registers. */ enum RTL8139_registers { - MAC0 = 0, /* Ethernet hardware address. */ - MAR0 = 8, /* Multicast filter. */ - TxStatus0 = 0x10, /* Transmit status (Four 32bit registers). */ - TxAddr0 = 0x20, /* Tx descriptors (also four 32bit). */ - RxBuf = 0x30, - ChipCmd = 0x37, - RxBufPtr = 0x38, - RxBufAddr = 0x3A, - IntrMask = 0x3C, - IntrStatus = 0x3E, - TxConfig = 0x40, - RxConfig = 0x44, - Timer = 0x48, /* A general-purpose counter. */ - RxMissed = 0x4C, /* 24 bits valid, write clears. */ - Cfg9346 = 0x50, - Config0 = 0x51, - Config1 = 0x52, - FlashReg = 0x54, - MediaStatus = 0x58, - Config3 = 0x59, - Config4 = 0x5A, /* absent on RTL-8139A */ - HltClk = 0x5B, - MultiIntr = 0x5C, - TxSummary = 0x60, - BasicModeCtrl = 0x62, - BasicModeStatus = 0x64, - NWayAdvert = 0x66, - NWayLPAR = 0x68, - NWayExpansion = 0x6A, + MAC0 = 0, /* Ethernet hardware address. */ + MAR0 = 8, /* Multicast filter. */ + TxStatus0 = 0x10, /* Transmit status (Four 32bit registers). */ + TxAddr0 = 0x20, /* Tx descriptors (also four 32bit). */ + RxBuf = 0x30, + ChipCmd = 0x37, + RxBufPtr = 0x38, + RxBufAddr = 0x3A, + IntrMask = 0x3C, + IntrStatus = 0x3E, + TxConfig = 0x40, + RxConfig = 0x44, + Timer = 0x48, /* A general-purpose counter. */ + RxMissed = 0x4C, /* 24 bits valid, write clears. */ + Cfg9346 = 0x50, + Config0 = 0x51, + Config1 = 0x52, + FlashReg = 0x54, + MediaStatus = 0x58, + Config3 = 0x59, + Config4 = 0x5A, /* absent on RTL-8139A */ + HltClk = 0x5B, + MultiIntr = 0x5C, + TxSummary = 0x60, + BasicModeCtrl = 0x62, + BasicModeStatus = 0x64, + NWayAdvert = 0x66, + NWayLPAR = 0x68, + NWayExpansion = 0x6A, /* Undocumented registers, but required for proper operation. */ - FIFOTMS = 0x70, /* FIFO Control and test. */ - CSCR = 0x74, /* Chip Status and Configuration Register. */ - PARA78 = 0x78, - PARA7c = 0x7c, /* Magic transceiver parameter register. */ - Config5 = 0xD8, /* absent on RTL-8139A */ + FIFOTMS = 0x70, /* FIFO Control and test. */ + CSCR = 0x74, /* Chip Status and Configuration Register. */ + PARA78 = 0x78, + PARA7c = 0x7c, /* Magic transceiver parameter register. */ + Config5 = 0xD8, /* absent on RTL-8139A */ }; enum ClearBitMasks { - MultiIntrClear = 0xF000, - ChipCmdClear = 0xE2, - Config1Clear = (1<<7)|(1<<6)|(1<<3)|(1<<2)|(1<<1), + MultiIntrClear = 0xF000, + ChipCmdClear = 0xE2, + Config1Clear = (1<<7)|(1<<6)|(1<<3)|(1<<2)|(1<<1), }; enum ChipCmdBits { - CmdReset = 0x10, - CmdRxEnb = 0x08, - CmdTxEnb = 0x04, - RxBufEmpty = 0x01, + CmdReset = 0x10, + CmdRxEnb = 0x08, + CmdTxEnb = 0x04, + RxBufEmpty = 0x01, }; /* Interrupt register bits, using my own meaningful names. */ enum IntrStatusBits { - PCIErr = 0x8000, - PCSTimeout = 0x4000, - RxFIFOOver = 0x40, - RxUnderrun = 0x20, - RxOverflow = 0x10, - TxErr = 0x08, - TxOK = 0x04, - RxErr = 0x02, - RxOK = 0x01, - - RxAckBits = RxFIFOOver | RxOverflow | RxOK, + PCIErr = 0x8000, + PCSTimeout = 0x4000, + RxFIFOOver = 0x40, + RxUnderrun = 0x20, + RxOverflow = 0x10, + TxErr = 0x08, + TxOK = 0x04, + RxErr = 0x02, + RxOK = 0x01, + + RxAckBits = RxFIFOOver | RxOverflow | RxOK, }; enum TxStatusBits { - TxHostOwns = 0x2000, - TxUnderrun = 0x4000, - TxStatOK = 0x8000, - TxOutOfWindow = 0x20000000, - TxAborted = 0x40000000, - TxCarrierLost = 0x80000000, + TxHostOwns = 0x2000, + TxUnderrun = 0x4000, + TxStatOK = 0x8000, + TxOutOfWindow = 0x20000000, + TxAborted = 0x40000000, + TxCarrierLost = 0x80000000, }; enum RxStatusBits { - RxMulticast = 0x8000, - RxPhysical = 0x4000, - RxBroadcast = 0x2000, - RxBadSymbol = 0x0020, - RxRunt = 0x0010, - RxTooLong = 0x0008, - RxCRCErr = 0x0004, - RxBadAlign = 0x0002, - RxStatusOK = 0x0001, + RxMulticast = 0x8000, + RxPhysical = 0x4000, + RxBroadcast = 0x2000, + RxBadSymbol = 0x0020, + RxRunt = 0x0010, + RxTooLong = 0x0008, + RxCRCErr = 0x0004, + RxBadAlign = 0x0002, + RxStatusOK = 0x0001, }; /* Bits in RxConfig. */ enum rx_mode_bits { - AcceptErr = 0x20, - AcceptRunt = 0x10, - AcceptBroadcast = 0x08, - AcceptMulticast = 0x04, - AcceptMyPhys = 0x02, - AcceptAllPhys = 0x01, + AcceptErr = 0x20, + AcceptRunt = 0x10, + AcceptBroadcast = 0x08, + AcceptMulticast = 0x04, + AcceptMyPhys = 0x02, + AcceptAllPhys = 0x01, }; /* Bits in TxConfig. */ enum tx_config_bits { - /* Interframe Gap Time. Only TxIFG96 doesn't violate IEEE 802.3 */ - TxIFGShift = 24, - TxIFG84 = (0 << TxIFGShift), /* 8.4us / 840ns (10 / 100Mbps) */ - TxIFG88 = (1 << TxIFGShift), /* 8.8us / 880ns (10 / 100Mbps) */ - TxIFG92 = (2 << TxIFGShift), /* 9.2us / 920ns (10 / 100Mbps) */ - TxIFG96 = (3 << TxIFGShift), /* 9.6us / 960ns (10 / 100Mbps) */ - - TxLoopBack = (1 << 18) | (1 << 17), /* enable loopback test mode */ - TxCRC = (1 << 16), /* DISABLE appending CRC to end of Tx packets */ - TxClearAbt = (1 << 0), /* Clear abort (WO) */ - TxDMAShift = 8, /* DMA burst value (0-7) is shifted this many bits */ - TxRetryShift = 4, /* TXRR value (0-15) is shifted this many bits */ - - TxVersionMask = 0x7C800000, /* mask out version bits 30-26, 23 */ + TxIFGShift = 24, + TxIFG84 = (0 << TxIFGShift), /* 8.4us / 840ns (10 / 100Mbps) */ + TxIFG88 = (1 << TxIFGShift), /* 8.8us / 880ns (10 / 100Mbps) */ + TxIFG92 = (2 << TxIFGShift), /* 9.2us / 920ns (10 / 100Mbps) */ + TxIFG96 = (3 << TxIFGShift), /* 9.6us / 960ns (10 / 100Mbps) */ + + TxLoopBack = (1 << 18) | (1 << 17), /* enable loopback test mode */ + TxCRC = (1 << 16), /* DISABLE Tx pkt CRC append */ + TxClearAbt = (1 << 0), /* Clear abort (WO) */ + TxDMAShift = 8, /* DMA burst value (0-7) is shifted X many bits */ + TxRetryShift = 4, /* TXRR value (0-15) is shifted X many bits */ + + TxVersionMask = 0x7C800000, /* mask out version bits 30-26, 23 */ }; /* Bits in Config1 */ enum Config1Bits { - Cfg1_PM_Enable = 0x01, - Cfg1_VPD_Enable = 0x02, - Cfg1_PIO = 0x04, - Cfg1_MMIO = 0x08, - LWAKE = 0x10, /* not on 8139, 8139A */ + Cfg1_PM_Enable = 0x01, + Cfg1_VPD_Enable = 0x02, + Cfg1_PIO = 0x04, + Cfg1_MMIO = 0x08, + LWAKE = 0x10, /* not on 8139, 8139A */ Cfg1_Driver_Load = 0x20, - Cfg1_LED0 = 0x40, - Cfg1_LED1 = 0x80, - SLEEP = (1 << 1), /* only on 8139, 8139A */ - PWRDN = (1 << 0), /* only on 8139, 8139A */ + Cfg1_LED0 = 0x40, + Cfg1_LED1 = 0x80, + SLEEP = (1 << 1), /* only on 8139, 8139A */ + PWRDN = (1 << 0), /* only on 8139, 8139A */ }; /* Bits in Config3 */ enum Config3Bits { - Cfg3_FBtBEn = (1 << 0), /* 1 = Fast Back to Back */ - Cfg3_FuncRegEn = (1 << 1), /* 1 = enable CardBus Function registers */ - Cfg3_CLKRUN_En = (1 << 2), /* 1 = enable CLKRUN */ - Cfg3_CardB_En = (1 << 3), /* 1 = enable CardBus registers */ - Cfg3_LinkUp = (1 << 4), /* 1 = wake up on link up */ - Cfg3_Magic = (1 << 5), /* 1 = wake up on Magic Packet (tm) */ - Cfg3_PARM_En = (1 << 6), /* 0 = software can set twister parameters */ - Cfg3_GNTSel = (1 << 7), /* 1 = delay 1 clock from PCI GNT signal */ + Cfg3_FBtBEn = (1 << 0), /* 1 = Fast Back to Back */ + Cfg3_FuncRegEn = (1 << 1), /* 1 = enable CardBus Function registers */ + Cfg3_CLKRUN_En = (1 << 2), /* 1 = enable CLKRUN */ + Cfg3_CardB_En = (1 << 3), /* 1 = enable CardBus registers */ + Cfg3_LinkUp = (1 << 4), /* 1 = wake up on link up */ + Cfg3_Magic = (1 << 5), /* 1 = wake up on Magic Packet (tm) */ + Cfg3_PARM_En = (1 << 6), /* 0 = software can set twister parameters */ + Cfg3_GNTSel = (1 << 7), /* 1 = delay 1 clock from PCI GNT signal */ }; /* Bits in Config4 */ enum Config4Bits { - LWPTN = (1 << 2), /* not on 8139, 8139A */ + LWPTN = (1 << 2), /* not on 8139, 8139A */ }; /* Bits in Config5 */ enum Config5Bits { - Cfg5_PME_STS = (1 << 0), /* 1 = PCI reset resets PME_Status */ - Cfg5_LANWake = (1 << 1), /* 1 = enable LANWake signal */ - Cfg5_LDPS = (1 << 2), /* 0 = save power when link is down */ - Cfg5_FIFOAddrPtr = (1 << 3), /* Realtek internal SRAM testing */ - Cfg5_UWF = (1 << 4), /* 1 = accept unicast wakeup frame */ - Cfg5_MWF = (1 << 5), /* 1 = accept multicast wakeup frame */ - Cfg5_BWF = (1 << 6), /* 1 = accept broadcast wakeup frame */ + Cfg5_PME_STS = (1 << 0), /* 1 = PCI reset resets PME_Status */ + Cfg5_LANWake = (1 << 1), /* 1 = enable LANWake signal */ + Cfg5_LDPS = (1 << 2), /* 0 = save power when link is down */ + Cfg5_FIFOAddrPtr= (1 << 3), /* Realtek internal SRAM testing */ + Cfg5_UWF = (1 << 4), /* 1 = accept unicast wakeup frame */ + Cfg5_MWF = (1 << 5), /* 1 = accept multicast wakeup frame */ + Cfg5_BWF = (1 << 6), /* 1 = accept broadcast wakeup frame */ }; enum RxConfigBits { /* rx fifo threshold */ - RxCfgFIFOShift = 13, - RxCfgFIFONone = (7 << RxCfgFIFOShift), + RxCfgFIFOShift = 13, + RxCfgFIFONone = (7 << RxCfgFIFOShift), /* Max DMA burst */ - RxCfgDMAShift = 8, + RxCfgDMAShift = 8, RxCfgDMAUnlimited = (7 << RxCfgDMAShift), /* rx ring buffer length */ - RxCfgRcv8K = 0, - RxCfgRcv16K = (1 << 11), - RxCfgRcv32K = (1 << 12), - RxCfgRcv64K = (1 << 11) | (1 << 12), + RxCfgRcv8K = 0, + RxCfgRcv16K = (1 << 11), + RxCfgRcv32K = (1 << 12), + RxCfgRcv64K = (1 << 11) | (1 << 12), /* Disable packet wrap at end of Rx buffer. (not possible with 64k) */ - RxNoWrap = (1 << 7), + RxNoWrap = (1 << 7), }; /* Twister tuning parameters from RealTek. Completely undocumented, but required to tune bad links on some boards. */ enum CSCRBits { - CSCR_LinkOKBit = 0x0400, - CSCR_LinkChangeBit = 0x0800, - CSCR_LinkStatusBits = 0x0f000, - CSCR_LinkDownOffCmd = 0x003c0, - CSCR_LinkDownCmd = 0x0f3c0, + CSCR_LinkOKBit = 0x0400, + CSCR_LinkChangeBit = 0x0800, + CSCR_LinkStatusBits = 0x0f000, + CSCR_LinkDownOffCmd = 0x003c0, + CSCR_LinkDownCmd = 0x0f3c0, }; enum Cfg9346Bits { - Cfg9346_Lock = 0x00, - Cfg9346_Unlock = 0xC0, + Cfg9346_Lock = 0x00, + Cfg9346_Unlock = 0xC0, }; typedef enum { - CH_8139 = 0, + CH_8139 = 0, CH_8139_K, CH_8139A, CH_8139A_G, @@ -495,8 +494,8 @@ typedef enum { } chip_t; enum chip_flags { - HasHltClk = (1 << 0), - HasLWake = (1 << 1), + HasHltClk = (1 << 0), + HasLWake = (1 << 1), }; #define HW_REVID(b30, b29, b28, b27, b26, b23, b22) \ @@ -569,38 +568,46 @@ struct rtl_extra_stats { }; struct rtl8139_private { - void __iomem *mmio_addr; - int drv_flags; - struct pci_dev *pci_dev; - u32 msg_enable; - struct napi_struct napi; - struct net_device *dev; - struct net_device_stats stats; - unsigned char *rx_ring; - unsigned int cur_rx; /* Index into the Rx buffer of next Rx pkt. */ - unsigned int tx_flag; - unsigned long cur_tx; - unsigned long dirty_tx; - unsigned char *tx_buf[NUM_TX_DESC]; /* Tx bounce buffers */ - unsigned char *tx_bufs; /* Tx bounce buffer region. */ - dma_addr_t rx_ring_dma; - dma_addr_t tx_bufs_dma; - signed char phys[4]; /* MII device addresses. */ - char twistie, twist_row, twist_col; /* Twister tune state. */ - unsigned int watchdog_fired : 1; - unsigned int default_port : 4; /* Last dev->if_port value. */ - unsigned int have_thread : 1; - spinlock_t lock; - spinlock_t rx_lock; - chip_t chipset; - u32 rx_config; - struct rtl_extra_stats xstats; - - struct delayed_work thread; - - struct mii_if_info mii; - unsigned int regs_len; - unsigned long fifo_copy_timeout; + void __iomem *mmio_addr; + int drv_flags; + struct pci_dev *pci_dev; + u32 msg_enable; + struct napi_struct napi; + struct net_device *dev; + struct net_device_stats stats; + + unsigned char *rx_ring; + unsigned int cur_rx; /* RX buf index of next pkt */ + dma_addr_t rx_ring_dma; + + unsigned int tx_flag; + unsigned long cur_tx; + unsigned long dirty_tx; + unsigned char *tx_buf[NUM_TX_DESC]; /* Tx bounce buffers */ + unsigned char *tx_bufs; /* Tx bounce buffer region. */ + dma_addr_t tx_bufs_dma; + + signed char phys[4]; /* MII device addresses. */ + + /* Twister tune state. */ + char twistie, twist_row, twist_col; + + unsigned int watchdog_fired : 1; + unsigned int default_port : 4; /* Last dev->if_port value. */ + unsigned int have_thread : 1; + + spinlock_t lock; + spinlock_t rx_lock; + + chip_t chipset; + u32 rx_config; + struct rtl_extra_stats xstats; + + struct delayed_work thread; + + struct mii_if_info mii; + unsigned int regs_len; + unsigned long fifo_copy_timeout; }; MODULE_AUTHOR ("Jeff Garzik "); @@ -648,24 +655,11 @@ static const struct ethtool_ops rtl8139_ethtool_ops; #define RTL_W16_F(reg, val16) do { iowrite16 ((val16), ioaddr + (reg)); ioread16 (ioaddr + (reg)); } while (0) #define RTL_W32_F(reg, val32) do { iowrite32 ((val32), ioaddr + (reg)); ioread32 (ioaddr + (reg)); } while (0) - -#define MMIO_FLUSH_AUDIT_COMPLETE 1 -#if MMIO_FLUSH_AUDIT_COMPLETE - /* write MMIO register */ #define RTL_W8(reg, val8) iowrite8 ((val8), ioaddr + (reg)) #define RTL_W16(reg, val16) iowrite16 ((val16), ioaddr + (reg)) #define RTL_W32(reg, val32) iowrite32 ((val32), ioaddr + (reg)) -#else - -/* write MMIO register, then flush */ -#define RTL_W8 RTL_W8_F -#define RTL_W16 RTL_W16_F -#define RTL_W32 RTL_W32_F - -#endif /* MMIO_FLUSH_AUDIT_COMPLETE */ - /* read MMIO register */ #define RTL_R8(reg) ioread8 (ioaddr + (reg)) #define RTL_R16(reg) ioread16 (ioaddr + (reg)) -- cgit v1.2.3-70-g09d2 From 8abc4d5b84f23edccf405aa591aae7d9b967e8d2 Mon Sep 17 00:00:00 2001 From: Sivakumar Subramani Date: Sat, 15 Sep 2007 13:11:34 -0700 Subject: [S2IO]: Making MSIX as default intr_type - Making MSIX as default intr_type - Driver will test MSI-X by issuing test MSI-X vector and if fails it will fallback to INTA Signed-off-by: Sivakumar Subramani Signed-off-by: Ramkrishna Vepa Signed-off-by: Jeff Garzik Signed-off-by: David S. Miller --- drivers/net/s2io-regs.h | 2 +- drivers/net/s2io.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++-- drivers/net/s2io.h | 6 ++++ 3 files changed, 98 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/s2io-regs.h b/drivers/net/s2io-regs.h index cfa26791447..83e3e47a9e3 100644 --- a/drivers/net/s2io-regs.h +++ b/drivers/net/s2io-regs.h @@ -220,7 +220,7 @@ struct XENA_dev_config { u64 scheduled_int_ctrl; #define SCHED_INT_CTRL_TIMER_EN BIT(0) #define SCHED_INT_CTRL_ONE_SHOT BIT(1) -#define SCHED_INT_CTRL_INT2MSI TBD +#define SCHED_INT_CTRL_INT2MSI(val) vBIT(val,10,6) #define SCHED_INT_PERIOD TBD u64 txreqtimeout; diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index dd012322cdb..588938204e2 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -37,7 +37,7 @@ * tx_fifo_len: This too is an array of 8. Each element defines the number of * Tx descriptors that can be associated with each corresponding FIFO. * intr_type: This defines the type of interrupt. The values can be 0(INTA), - * 2(MSI_X). Default value is '0(INTA)' + * 2(MSI_X). Default value is '2(MSI_X)' * lro: Specifies whether to enable Large Receive Offload (LRO) or not. * Possible values '1' for enable '0' for disable. Default is '0' * lro_max_pkts: This parameter defines maximum number of packets can be @@ -428,7 +428,7 @@ S2IO_PARM_INT(l3l4hdr_size, 128); /* Frequency of Rx desc syncs expressed as power of 2 */ S2IO_PARM_INT(rxsync_frequency, 3); /* Interrupt type. Values can be 0(INTA), 2(MSI_X) */ -S2IO_PARM_INT(intr_type, 0); +S2IO_PARM_INT(intr_type, 2); /* Large receive offload feature */ S2IO_PARM_INT(lro, 0); /* Max pkts to be aggregated by LRO at one time. If not specified, @@ -3773,6 +3773,59 @@ static int s2io_enable_msi_x(struct s2io_nic *nic) return 0; } +/* Handle software interrupt used during MSI(X) test */ +static irqreturn_t __devinit s2io_test_intr(int irq, void *dev_id) +{ + struct s2io_nic *sp = dev_id; + + sp->msi_detected = 1; + wake_up(&sp->msi_wait); + + return IRQ_HANDLED; +} + +/* Test interrupt path by forcing a a software IRQ */ +static int __devinit s2io_test_msi(struct s2io_nic *sp) +{ + struct pci_dev *pdev = sp->pdev; + struct XENA_dev_config __iomem *bar0 = sp->bar0; + int err; + u64 val64, saved64; + + err = request_irq(sp->entries[1].vector, s2io_test_intr, 0, + sp->name, sp); + if (err) { + DBG_PRINT(ERR_DBG, "%s: PCI %s: cannot assign irq %d\n", + sp->dev->name, pci_name(pdev), pdev->irq); + return err; + } + + init_waitqueue_head (&sp->msi_wait); + sp->msi_detected = 0; + + saved64 = val64 = readq(&bar0->scheduled_int_ctrl); + val64 |= SCHED_INT_CTRL_ONE_SHOT; + val64 |= SCHED_INT_CTRL_TIMER_EN; + val64 |= SCHED_INT_CTRL_INT2MSI(1); + writeq(val64, &bar0->scheduled_int_ctrl); + + wait_event_timeout(sp->msi_wait, sp->msi_detected, HZ/10); + + if (!sp->msi_detected) { + /* MSI(X) test failed, go back to INTx mode */ + DBG_PRINT(ERR_DBG, "%s: PCI %s: No interrupt was generated" + "using MSI(X) during test\n", sp->dev->name, + pci_name(pdev)); + + err = -EOPNOTSUPP; + } + + free_irq(sp->entries[1].vector, sp); + + writeq(saved64, &bar0->scheduled_int_ctrl); + + return err; +} /* ********************************************************* * * Functions defined below concern the OS part of the driver * * ********************************************************* */ @@ -3803,6 +3856,42 @@ static int s2io_open(struct net_device *dev) napi_enable(&sp->napi); + if (sp->intr_type == MSI_X) { + int ret = s2io_enable_msi_x(sp); + + if (!ret) { + u16 msi_control; + + ret = s2io_test_msi(sp); + + /* rollback MSI-X, will re-enable during add_isr() */ + kfree(sp->entries); + sp->mac_control.stats_info->sw_stat.mem_freed += + (MAX_REQUESTED_MSI_X * + sizeof(struct msix_entry)); + kfree(sp->s2io_entries); + sp->mac_control.stats_info->sw_stat.mem_freed += + (MAX_REQUESTED_MSI_X * + sizeof(struct s2io_msix_entry)); + sp->entries = NULL; + sp->s2io_entries = NULL; + + pci_read_config_word(sp->pdev, 0x42, &msi_control); + msi_control &= 0xFFFE; /* Disable MSI */ + pci_write_config_word(sp->pdev, 0x42, msi_control); + + pci_disable_msix(sp->pdev); + + } + if (ret) { + + DBG_PRINT(ERR_DBG, + "%s: MSI-X requested but failed to enable\n", + dev->name); + sp->intr_type = INTA; + } + } + /* Initialize H/W and enable interrupts */ err = s2io_card_up(sp); if (err) { diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 420fefb9918..62398fab2e9 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -412,6 +412,10 @@ struct config_param { struct tx_fifo_config tx_cfg[MAX_TX_FIFOS]; /*Per-Tx FIFO config */ u32 max_txds; /*Max no. of Tx buffer descriptor per TxDL */ u64 tx_intr_type; +#define INTA 0 +#define MSI_X 2 + u8 intr_type; + /* Specifies if Tx Intr is UTILZ or PER_LIST type. */ /* Rx Side */ @@ -862,6 +866,8 @@ struct s2io_nic { struct vlan_group *vlgrp; #define MSIX_FLG 0xA5 struct msix_entry *entries; + int msi_detected; + wait_queue_head_t msi_wait; struct s2io_msix_entry *s2io_entries; char desc[MAX_REQUESTED_MSI_X][25]; -- cgit v1.2.3-70-g09d2 From c77dd43e77c530a12a466865805d2068ede96860 Mon Sep 17 00:00:00 2001 From: Sivakumar Subramani Date: Mon, 6 Aug 2007 05:36:28 -0400 Subject: S2IO: Fixes in MSIX related code. - Calling store_xmsi_data to store the MSI-X datas during initialization in s2io-init_nic function - Disabling NAPI when MSI-X is enabled - Freeing sp->entries and sp->s2io_entries in s2io_rem_isr Signed-off-by: Sivakumar Subramani Signed-off-by: Ramkrishna Vepa Signed-off-by: Jeff Garzik --- drivers/net/s2io.c | 19 +++++++++++++++++++ drivers/net/s2io.h | 1 + 2 files changed, 20 insertions(+) (limited to 'drivers') diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 588938204e2..e7b432c508f 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -3892,6 +3892,12 @@ static int s2io_open(struct net_device *dev) } } + /* NAPI doesn't work well with MSI(X) */ + if (sp->intr_type != INTA) { + if(sp->config.napi) + sp->config.napi = 0; + } + /* Initialize H/W and enable interrupts */ err = s2io_card_up(sp); if (err) { @@ -6471,6 +6477,7 @@ static void s2io_rem_isr(struct s2io_nic * sp) { int cnt = 0; struct net_device *dev = sp->dev; + struct swStat *stats = &sp->mac_control.stats_info->sw_stat; if (sp->intr_type == MSI_X) { int i; @@ -6483,6 +6490,16 @@ static void s2io_rem_isr(struct s2io_nic * sp) free_irq(vector, arg); } + + kfree(sp->entries); + stats->mem_freed += + (MAX_REQUESTED_MSI_X * sizeof(struct msix_entry)); + kfree(sp->s2io_entries); + stats->mem_freed += + (MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry)); + sp->entries = NULL; + sp->s2io_entries = NULL; + pci_read_config_word(sp->pdev, 0x42, &msi_control); msi_control &= 0xFFFE; /* Disable MSI */ pci_write_config_word(sp->pdev, 0x42, msi_control); @@ -7377,6 +7394,8 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) dev->addr_len = ETH_ALEN; memcpy(dev->dev_addr, sp->def_mac_addr, ETH_ALEN); + /* Store the values of the MSIX table in the s2io_nic structure */ + store_xmsi_data(sp); /* reset Nic and bring it to known state */ s2io_reset(sp); diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 62398fab2e9..724948d217b 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -415,6 +415,7 @@ struct config_param { #define INTA 0 #define MSI_X 2 u8 intr_type; + u8 napi; /* Specifies if Tx Intr is UTILZ or PER_LIST type. */ -- cgit v1.2.3-70-g09d2 From 92c487996dfc01c6c1f7c660d076037a3a01a6ae Mon Sep 17 00:00:00 2001 From: Sivakumar Subramani Date: Mon, 6 Aug 2007 05:38:19 -0400 Subject: S2IO: Fixed Link LED issue when MSI-X is enabled -Fixed Link LED issue when MSI-X is enabled. Signed-off-by: Sivakumar Subramani Signed-off-by: Ramkrishna Vepa Signed-off-by: Jeff Garzik --- drivers/net/s2io.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index e7b432c508f..e7431c58da4 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -84,7 +84,7 @@ #include "s2io.h" #include "s2io-regs.h" -#define DRV_VERSION "2.0.25.1" +#define DRV_VERSION "2.0.26.1" /* S2io Driver name & version. */ static char s2io_driver_name[] = "Neterion"; @@ -6201,13 +6201,10 @@ static void s2io_set_link(struct work_struct *work) netif_stop_queue(dev); } } - val64 = readq(&bar0->adapter_status); - if (!LINK_IS_UP(val64)) { - DBG_PRINT(ERR_DBG, "%s:", dev->name); - DBG_PRINT(ERR_DBG, " Link down after enabling "); - DBG_PRINT(ERR_DBG, "device \n"); - } else - s2io_link(nic, LINK_UP); + val64 = readq(&bar0->adapter_control); + val64 |= ADAPTER_LED_ON; + writeq(val64, &bar0->adapter_control); + s2io_link(nic, LINK_UP); } else { if (CARDS_WITH_FAULTY_LINK_INDICATORS(nic->device_type, subid)) { @@ -6216,6 +6213,10 @@ static void s2io_set_link(struct work_struct *work) writeq(val64, &bar0->gpio_control); val64 = readq(&bar0->gpio_control); } + /* turn off LED */ + val64 = readq(&bar0->adapter_control); + val64 = val64 &(~ADAPTER_LED_ON); + writeq(val64, &bar0->adapter_control); s2io_link(nic, LINK_DOWN); } clear_bit(0, &(nic->link_state)); -- cgit v1.2.3-70-g09d2 From 2808d2e83f9b48c2f68930b6746fed8efabc41e9 Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Wed, 8 Aug 2007 13:20:26 +0200 Subject: net/tulip/xircom_cb.c: remove superfulous priv assignment Unpatched version does sth like this: dev = alloc_etherdev(... private = netdev_priv(dev); ... dev->priv = private; which doesn't make much sense (does it?) because this is done in alloc_netdev() already. struct net_device *alloc_netdev(... { ... if (sizeof_priv) dev->priv = netdev_priv(dev); This patch removes superfluous code. Signed-off-by: Mariusz Kozlowski drivers/net/tulip/xircom_cb.c | 32853 -> 32831 (-22 bytes) drivers/net/tulip/xircom_cb.o | 123984 -> 123984 (0 bytes) drivers/net/tulip/xircom_cb.c | 1 - 1 file changed, 1 deletion(-) Signed-off-by: Jeff Garzik --- drivers/net/tulip/xircom_cb.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c index 16a54e6b8d4..4b239dcbef7 100644 --- a/drivers/net/tulip/xircom_cb.c +++ b/drivers/net/tulip/xircom_cb.c @@ -271,7 +271,6 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_ dev->hard_start_xmit = &xircom_start_xmit; dev->stop = &xircom_close; dev->get_stats = &xircom_get_stats; - dev->priv = private; #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = &xircom_poll_controller; #endif -- cgit v1.2.3-70-g09d2 From 10096974adb6d62b9f8cf65c266632ea73040936 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Tue, 14 Aug 2007 01:24:56 -0400 Subject: [netdrvr] ns83820: add ethtool media support Split out from patch authored by Dan Faerch . Signed-off-by: Jeff Garzik --- drivers/net/ns83820.c | 151 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 148 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c index ea80e6cb3de..6e65d61a3fe 100644 --- a/drivers/net/ns83820.c +++ b/drivers/net/ns83820.c @@ -1,4 +1,4 @@ -#define VERSION "0.22" +#define VERSION "0.23" /* ns83820.c by Benjamin LaHaise with contributions. * * Questions/comments/discussion to linux-ns83820@kvack.org. @@ -1247,6 +1247,149 @@ static struct net_device_stats *ns83820_get_stats(struct net_device *ndev) return &dev->stats; } +/* Let ethtool retrieve info */ +static int ns83820_get_settings(struct net_device *ndev, + struct ethtool_cmd *cmd) +{ + struct ns83820 *dev = PRIV(ndev); + u32 cfg, tanar, tbicr; + int have_optical = 0; + int fullduplex = 0; + + /* + * Here's the list of available ethtool commands from other drivers: + * cmd->advertising = + * cmd->speed = + * cmd->duplex = + * cmd->port = 0; + * cmd->phy_address = + * cmd->transceiver = 0; + * cmd->autoneg = + * cmd->maxtxpkt = 0; + * cmd->maxrxpkt = 0; + */ + + /* read current configuration */ + cfg = readl(dev->base + CFG) ^ SPDSTS_POLARITY; + tanar = readl(dev->base + TANAR); + tbicr = readl(dev->base + TBICR); + + if (dev->CFG_cache & CFG_TBI_EN) { + /* we have an optical interface */ + have_optical = 1; + fullduplex = (cfg & CFG_DUPSTS) ? 1 : 0; + + } else { + /* We have copper */ + fullduplex = (cfg & CFG_DUPSTS) ? 1 : 0; + } + + cmd->supported = SUPPORTED_Autoneg; + + /* we have optical interface */ + if (dev->CFG_cache & CFG_TBI_EN) { + cmd->supported |= SUPPORTED_1000baseT_Half | + SUPPORTED_1000baseT_Full | + SUPPORTED_FIBRE; + cmd->port = PORT_FIBRE; + } /* TODO: else copper related support */ + + cmd->duplex = fullduplex ? DUPLEX_FULL : DUPLEX_HALF; + switch (cfg / CFG_SPDSTS0 & 3) { + case 2: + cmd->speed = SPEED_1000; + break; + case 1: + cmd->speed = SPEED_100; + break; + default: + cmd->speed = SPEED_10; + break; + } + cmd->autoneg = (tbicr & TBICR_MR_AN_ENABLE) ? 1: 0; + return 0; +} + +/* Let ethool change settings*/ +static int ns83820_set_settings(struct net_device *ndev, + struct ethtool_cmd *cmd) +{ + struct ns83820 *dev = PRIV(ndev); + u32 cfg, tanar; + int have_optical = 0; + int fullduplex = 0; + + /* read current configuration */ + cfg = readl(dev->base + CFG) ^ SPDSTS_POLARITY; + tanar = readl(dev->base + TANAR); + + if (dev->CFG_cache & CFG_TBI_EN) { + /* we have optical */ + have_optical = 1; + fullduplex = (tanar & TANAR_FULL_DUP); + + } else { + /* we have copper */ + fullduplex = cfg & CFG_DUPSTS; + } + + spin_lock_irq(&dev->misc_lock); + spin_lock(&dev->tx_lock); + + /* Set duplex */ + if (cmd->duplex != fullduplex) { + if (have_optical) { + /*set full duplex*/ + if (cmd->duplex == DUPLEX_FULL) { + /* force full duplex */ + writel(readl(dev->base + TXCFG) + | TXCFG_CSI | TXCFG_HBI | TXCFG_ATP, + dev->base + TXCFG); + writel(readl(dev->base + RXCFG) | RXCFG_RX_FD, + dev->base + RXCFG); + /* Light up full duplex LED */ + writel(readl(dev->base + GPIOR) | GPIOR_GP1_OUT, + dev->base + GPIOR); + } else { + /*TODO: set half duplex */ + } + + } else { + /*we have copper*/ + /* TODO: Set duplex for copper cards */ + } + printk(KERN_INFO "%s: Duplex set via ethtool\n", + ndev->name); + } + + /* Set autonegotiation */ + if (1) { + if (cmd->autoneg == AUTONEG_ENABLE) { + /* restart auto negotiation */ + writel(TBICR_MR_AN_ENABLE | TBICR_MR_RESTART_AN, + dev->base + TBICR); + writel(TBICR_MR_AN_ENABLE, dev->base + TBICR); + dev->linkstate = LINK_AUTONEGOTIATE; + + printk(KERN_INFO "%s: autoneg enabled via ethtool\n", + ndev->name); + } else { + /* disable auto negotiation */ + writel(0x00000000, dev->base + TBICR); + } + + printk(KERN_INFO "%s: autoneg %s via ethtool\n", ndev->name, + cmd->autoneg ? "ENABLED" : "DISABLED"); + } + + phy_intr(ndev); + spin_unlock(&dev->tx_lock); + spin_unlock_irq(&dev->misc_lock); + + return 0; +} +/* end ethtool get/set support -df */ + static void ns83820_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *info) { struct ns83820 *dev = PRIV(ndev); @@ -1263,8 +1406,10 @@ static u32 ns83820_get_link(struct net_device *ndev) } static const struct ethtool_ops ops = { - .get_drvinfo = ns83820_get_drvinfo, - .get_link = ns83820_get_link + .get_settings = ns83820_get_settings, + .set_settings = ns83820_set_settings, + .get_drvinfo = ns83820_get_drvinfo, + .get_link = ns83820_get_link }; /* this function is called in irq context from the ISR */ -- cgit v1.2.3-70-g09d2 From bf1e9a080d7766bd65b8d8eb837ecde8b03dcc31 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Fri, 10 Aug 2007 14:05:20 -0700 Subject: Clean up duplicate includes in drivers/net/ This patch cleans up duplicate includes in drivers/net/ Signed-off-by: Jesper Juhl Acked-by: "John W. Linville" Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/atl1/atl1_main.c | 1 - drivers/net/bfin_mac.c | 5 ----- drivers/net/bonding/bond_sysfs.c | 1 - drivers/net/fs_enet/fs_enet-main.c | 2 -- drivers/net/gianfar.h | 1 - drivers/net/gianfar_ethtool.c | 1 - drivers/net/irda/kingsun-sir.c | 1 - drivers/net/irda/mcs7780.c | 1 - drivers/net/mipsnet.c | 1 - drivers/net/netxen/netxen_nic_main.c | 1 - drivers/net/qla3xxx.c | 1 - drivers/net/tsi108_eth.c | 1 - drivers/net/wireless/ipw2200.h | 1 - drivers/net/wireless/zd1211rw/zd_def.h | 1 - 14 files changed, 19 deletions(-) (limited to 'drivers') diff --git a/drivers/net/atl1/atl1_main.c b/drivers/net/atl1/atl1_main.c index f23e13c8f9a..469ff95be55 100644 --- a/drivers/net/atl1/atl1_main.c +++ b/drivers/net/atl1/atl1_main.c @@ -76,7 +76,6 @@ #include #include #include -#include #include #include diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c index 2bb97d46468..3354c534335 100644 --- a/drivers/net/bfin_mac.c +++ b/drivers/net/bfin_mac.c @@ -47,15 +47,10 @@ #include #include #include - #include #include #include - #include -#include -#include -#include #include #include diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 8289e27a360..a771853219d 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index c509cb13222..5dc89d507e6 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -38,8 +38,6 @@ #include #include -#include - #include #include #include diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h index b8714e00482..c16cc8b946a 100644 --- a/drivers/net/gianfar.h +++ b/drivers/net/gianfar.h @@ -45,7 +45,6 @@ #include #include #include -#include #include #include "gianfar_mii.h" diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c index 7b411c1514d..2470903fbc7 100644 --- a/drivers/net/gianfar_ethtool.c +++ b/drivers/net/gianfar_ethtool.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/irda/kingsun-sir.c b/drivers/net/irda/kingsun-sir.c index 4e5101a45c3..a4adb74cccd 100644 --- a/drivers/net/irda/kingsun-sir.c +++ b/drivers/net/irda/kingsun-sir.c @@ -66,7 +66,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/irda/mcs7780.c b/drivers/net/irda/mcs7780.c index 0de867288a4..bfc57525bd6 100644 --- a/drivers/net/irda/mcs7780.c +++ b/drivers/net/irda/mcs7780.c @@ -50,7 +50,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/mipsnet.c b/drivers/net/mipsnet.c index 9853c74f6bb..c0f5ad38fb1 100644 --- a/drivers/net/mipsnet.c +++ b/drivers/net/mipsnet.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index a10bbefbdad..af16553e18b 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -39,7 +39,6 @@ #include "netxen_nic_phan_reg.h" #include -#include #include MODULE_DESCRIPTION("NetXen Multi port (1/10) Gigabit Network Driver"); diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c index bf9f8f64ba6..e39232320e3 100755 --- a/drivers/net/qla3xxx.c +++ b/drivers/net/qla3xxx.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include diff --git a/drivers/net/tsi108_eth.c b/drivers/net/tsi108_eth.c index b3069ee34bd..a1d305b9b12 100644 --- a/drivers/net/tsi108_eth.c +++ b/drivers/net/tsi108_eth.c @@ -47,7 +47,6 @@ #include #include #include -#include #include #include diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index 626a240a87d..9c973b96bb4 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h @@ -45,7 +45,6 @@ #include #include -#include #include #include diff --git a/drivers/net/wireless/zd1211rw/zd_def.h b/drivers/net/wireless/zd1211rw/zd_def.h index deb99d1eaa7..505b4d7dd0e 100644 --- a/drivers/net/wireless/zd1211rw/zd_def.h +++ b/drivers/net/wireless/zd1211rw/zd_def.h @@ -21,7 +21,6 @@ #include #include #include -#include typedef u16 __nocast zd_addr_t; -- cgit v1.2.3-70-g09d2 From acb2cc8b20d6cb9e65c1e442d59a2449d8774157 Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Sat, 15 Sep 2007 13:14:05 -0700 Subject: [PATCH] drivers/net: remove superfluous memset This patch covers something like this: dev = alloc_*dev(... ... priv = netdev_priv(dev); memset(priv, 0, sizeof(*priv)); The memset() here is superfluous. alloc_netdev() uses kzalloc() to allocate needed memory so there is no need to zero the priv region twice. Signed-off-by: Mariusz Kozlowski Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik Signed-off-by: David S. Miller --- drivers/net/fs_enet/fs_enet-main.c | 1 - drivers/net/myri10ge/myri10ge.c | 1 - drivers/net/netxen/netxen_nic_main.c | 1 - drivers/net/sunlance.c | 1 - drivers/net/usb/pegasus.c | 1 - drivers/net/usb/rtl8150.c | 1 - 6 files changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index 5dc89d507e6..2812b524eda 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -956,7 +956,6 @@ static struct net_device *fs_init_instance(struct device *dev, SET_MODULE_OWNER(ndev); fep = netdev_priv(ndev); - memset(fep, 0, privsize); /* clear everything */ fep->dev = dev; dev_set_drvdata(dev, ndev); diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 48b23c59240..6dc28b82493 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -2956,7 +2956,6 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) SET_NETDEV_DEV(netdev, &pdev->dev); mgp = netdev_priv(netdev); - memset(mgp, 0, sizeof(*mgp)); mgp->dev = netdev; netif_napi_add(netdev, &mgp->napi, myri10ge_poll, myri10ge_napi_weight); diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index af16553e18b..dcd66a6b490 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -329,7 +329,6 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) SET_NETDEV_DEV(netdev, &pdev->dev); adapter = netdev->priv; - memset(adapter, 0 , sizeof(struct netxen_adapter)); adapter->ahw.pdev = pdev; adapter->ahw.pci_func = pci_func_id; diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c index 68e4f660367..e94b752f9f3 100644 --- a/drivers/net/sunlance.c +++ b/drivers/net/sunlance.c @@ -1335,7 +1335,6 @@ static int __devinit sparc_lance_probe_one(struct sbus_dev *sdev, return -ENOMEM; lp = netdev_priv(dev); - memset(lp, 0, sizeof(*lp)); if (sparc_lance_debug && version_printed++ == 0) printk (KERN_INFO "%s", version); diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c index 04cba6bf3d5..06838928ef4 100644 --- a/drivers/net/usb/pegasus.c +++ b/drivers/net/usb/pegasus.c @@ -1306,7 +1306,6 @@ static int pegasus_probe(struct usb_interface *intf, } pegasus = netdev_priv(net); - memset(pegasus, 0, sizeof (struct pegasus)); pegasus->dev_index = dev_index; init_waitqueue_head(&pegasus->ctrl_wait); diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c index fa598f0340c..3b3a57ea267 100644 --- a/drivers/net/usb/rtl8150.c +++ b/drivers/net/usb/rtl8150.c @@ -905,7 +905,6 @@ static int rtl8150_probe(struct usb_interface *intf, } dev = netdev_priv(netdev); - memset(dev, 0, sizeof(rtl8150_t)); dev->intr_buff = kmalloc(INTBUFSIZE, GFP_KERNEL); if (!dev->intr_buff) { -- cgit v1.2.3-70-g09d2 From b1c9e0f7806d1f627f534fd0f83f235087496f7a Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Fri, 10 Aug 2007 23:29:33 -0700 Subject: cxgb3 - MAC workaround update Update the MAC workaround to deal with switches that do not honor pause frames. Signed-off-by: Divy Le Ray Signed-off-by: Jeff Garzik --- drivers/net/cxgb3/common.h | 1 + drivers/net/cxgb3/xgmac.c | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h index 2129210a67c..1746003eb46 100644 --- a/drivers/net/cxgb3/common.h +++ b/drivers/net/cxgb3/common.h @@ -507,6 +507,7 @@ struct cmac { unsigned int tx_xcnt; u64 tx_mcnt; unsigned int rx_xcnt; + unsigned int rx_ocnt; u64 rx_mcnt; unsigned int toggle_cnt; unsigned int txen; diff --git a/drivers/net/cxgb3/xgmac.c b/drivers/net/cxgb3/xgmac.c index c302b1a30cb..1d1c3919ab6 100644 --- a/drivers/net/cxgb3/xgmac.c +++ b/drivers/net/cxgb3/xgmac.c @@ -437,12 +437,13 @@ int t3_mac_enable(struct cmac *mac, int which) struct mac_stats *s = &mac->stats; if (which & MAC_DIRECTION_TX) { - t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN); t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); t3_write_reg(adap, A_TP_PIO_DATA, 0xc0ede401); t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE); t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx, 1 << idx); + t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN); + t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CNT_CH0 + idx); mac->tx_mcnt = s->tx_frames; mac->tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap, @@ -454,6 +455,7 @@ int t3_mac_enable(struct cmac *mac, int which) mac->rx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap, A_XGM_RX_SPI4_SOP_EOP_CNT + oft))); + mac->rx_ocnt = s->rx_fifo_ovfl; mac->txen = F_TXEN; mac->toggle_cnt = 0; } @@ -464,24 +466,19 @@ int t3_mac_enable(struct cmac *mac, int which) int t3_mac_disable(struct cmac *mac, int which) { - int idx = macidx(mac); struct adapter *adap = mac->adapter; - int val; if (which & MAC_DIRECTION_TX) { t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0); - t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); - t3_write_reg(adap, A_TP_PIO_DATA, 0xc000001f); - t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE); - t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx, 1 << idx); mac->txen = 0; } if (which & MAC_DIRECTION_RX) { + int val = F_MAC_RESET_; + t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset, F_PCS_RESET_, 0); msleep(100); t3_write_reg(adap, A_XGM_RX_CTRL + mac->offset, 0); - val = F_MAC_RESET_; if (is_10G(adap)) val |= F_PCS_RESET_; else if (uses_xaui(adap)) @@ -541,11 +538,14 @@ int t3b2_mac_watchdog_task(struct cmac *mac) } rxcheck: - if (rx_mcnt != mac->rx_mcnt) + if (rx_mcnt != mac->rx_mcnt) { rx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap, A_XGM_RX_SPI4_SOP_EOP_CNT + - mac->offset))); - else + mac->offset))) + + (s->rx_fifo_ovfl - + mac->rx_ocnt); + mac->rx_ocnt = s->rx_fifo_ovfl; + } else goto out; if (mac->rx_mcnt != s->rx_frames && rx_xcnt == 0 && -- cgit v1.2.3-70-g09d2 From c821d55c67213e96e6e0feb7418746a25fea6e4d Mon Sep 17 00:00:00 2001 From: Surya Prabhakar N Date: Mon, 13 Aug 2007 15:43:30 +0530 Subject: drivers/net/tokenring/3c359.c Hi, Replacing kmalloc with kzalloc and cleaning up memset in drivers/net/tokenring/3c359.c Signed-off-by: Surya Prabhakar Signed-off-by: Jeff Garzik --- drivers/net/tokenring/3c359.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c index 6612db8ec21..f4251d35599 100644 --- a/drivers/net/tokenring/3c359.c +++ b/drivers/net/tokenring/3c359.c @@ -641,14 +641,14 @@ static int xl_open(struct net_device *dev) * Now to set up the Rx and Tx buffer structures */ /* These MUST be on 8 byte boundaries */ - xl_priv->xl_tx_ring = kmalloc((sizeof(struct xl_tx_desc) * XL_TX_RING_SIZE) + 7, GFP_DMA | GFP_KERNEL) ; + xl_priv->xl_tx_ring = kzalloc((sizeof(struct xl_tx_desc) * XL_TX_RING_SIZE) + 7, GFP_DMA | GFP_KERNEL); if (xl_priv->xl_tx_ring == NULL) { printk(KERN_WARNING "%s: Not enough memory to allocate rx buffers.\n", dev->name); free_irq(dev->irq,dev); return -ENOMEM; } - xl_priv->xl_rx_ring = kmalloc((sizeof(struct xl_rx_desc) * XL_RX_RING_SIZE) +7, GFP_DMA | GFP_KERNEL) ; + xl_priv->xl_rx_ring = kzalloc((sizeof(struct xl_rx_desc) * XL_RX_RING_SIZE) +7, GFP_DMA | GFP_KERNEL); if (xl_priv->xl_tx_ring == NULL) { printk(KERN_WARNING "%s: Not enough memory to allocate rx buffers.\n", dev->name); @@ -656,8 +656,6 @@ static int xl_open(struct net_device *dev) kfree(xl_priv->xl_tx_ring); return -ENOMEM; } - memset(xl_priv->xl_tx_ring,0,sizeof(struct xl_tx_desc) * XL_TX_RING_SIZE) ; - memset(xl_priv->xl_rx_ring,0,sizeof(struct xl_rx_desc) * XL_RX_RING_SIZE) ; /* Setup Rx Ring */ for (i=0 ; i < XL_RX_RING_SIZE ; i++) { -- cgit v1.2.3-70-g09d2 From 2d6d749d124d93bd03982467f515b1b88f4c1e44 Mon Sep 17 00:00:00 2001 From: Richard Knutsson Date: Tue, 14 Aug 2007 02:07:09 +0200 Subject: drivers/net/tokenring: Convert to generic boolean Convert to generic boolean Signed-off-by: Richard Knutsson Signed-off-by: Jeff Garzik --- drivers/net/tokenring/ibmtr.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c index 51409698fe2..65e21eb7e68 100644 --- a/drivers/net/tokenring/ibmtr.c +++ b/drivers/net/tokenring/ibmtr.c @@ -116,9 +116,6 @@ in the event that chatty debug messages are desired - jjs 12/30/98 */ #define ENABLE_PAGING 1 #endif -#define FALSE 0 -#define TRUE (!FALSE) - /* changes the output format of driver initialization */ #define TR_VERBOSE 0 @@ -1542,7 +1539,7 @@ static void initial_tok_int(struct net_device *dev) ti->ring_speed = init_status & 0x01 ? 16 : 4; DPRINTK("Initial interrupt : %d Mbps, shared RAM base %08x.\n", ti->ring_speed, (unsigned int)dev->mem_start); - ti->auto_speedsave=readb(ti->init_srb+INIT_STATUS_2_OFST)&4?TRUE:FALSE; + ti->auto_speedsave = (readb(ti->init_srb+INIT_STATUS_2_OFST) & 4) != 0; if (ti->open_mode == MANUAL) wake_up(&ti->wait_for_reset); else tok_open_adapter((unsigned long)dev); -- cgit v1.2.3-70-g09d2 From df570f93337ddb46f1e30dd167c27b5fdcec637b Mon Sep 17 00:00:00 2001 From: Richard Knutsson Date: Tue, 14 Aug 2007 01:49:40 +0200 Subject: drivers/net/3c505: Convert to generic boolean Convert to generic boolean Signed-off-by: Richard Knutsson Signed-off-by: Jeff Garzik --- drivers/net/3c505.c | 67 +++++++++++++++++++++-------------------------------- 1 file changed, 26 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c index e985a85a562..acede307c05 100644 --- a/drivers/net/3c505.c +++ b/drivers/net/3c505.c @@ -167,21 +167,6 @@ static int elp_debug; * 3 = messages when interrupts received */ -/***************************************************************** - * - * useful macros - * - *****************************************************************/ - -#ifndef TRUE -#define TRUE 1 -#endif - -#ifndef FALSE -#define FALSE 0 -#endif - - /***************************************************************** * * List of I/O-addresses we try to auto-sense @@ -270,7 +255,7 @@ static inline void set_hsf(struct net_device *dev, int hsf) spin_unlock_irqrestore(&adapter->lock, flags); } -static int start_receive(struct net_device *, pcb_struct *); +static bool start_receive(struct net_device *, pcb_struct *); static inline void adapter_reset(struct net_device *dev) { @@ -328,28 +313,28 @@ static inline void check_3c505_dma(struct net_device *dev) } /* Primitive functions used by send_pcb() */ -static inline unsigned int send_pcb_slow(unsigned int base_addr, unsigned char byte) +static inline bool send_pcb_slow(unsigned int base_addr, unsigned char byte) { unsigned long timeout; outb_command(byte, base_addr); for (timeout = jiffies + 5*HZ/100; time_before(jiffies, timeout);) { if (inb_status(base_addr) & HCRE) - return FALSE; + return false; } printk(KERN_WARNING "3c505: send_pcb_slow timed out\n"); - return TRUE; + return true; } -static inline unsigned int send_pcb_fast(unsigned int base_addr, unsigned char byte) +static inline bool send_pcb_fast(unsigned int base_addr, unsigned char byte) { unsigned int timeout; outb_command(byte, base_addr); for (timeout = 0; timeout < 40000; timeout++) { if (inb_status(base_addr) & HCRE) - return FALSE; + return false; } printk(KERN_WARNING "3c505: send_pcb_fast timed out\n"); - return TRUE; + return true; } /* Check to see if the receiver needs restarting, and kick it if so */ @@ -386,7 +371,7 @@ static inline void prime_rx(struct net_device *dev) * timeout is reduced to 500us). */ -static int send_pcb(struct net_device *dev, pcb_struct * pcb) +static bool send_pcb(struct net_device *dev, pcb_struct * pcb) { int i; unsigned long timeout; @@ -396,14 +381,14 @@ static int send_pcb(struct net_device *dev, pcb_struct * pcb) check_3c505_dma(dev); if (adapter->dmaing && adapter->current_dma.direction == 0) - return FALSE; + return false; /* Avoid contention */ if (test_and_set_bit(1, &adapter->send_pcb_semaphore)) { if (elp_debug >= 3) { printk(KERN_DEBUG "%s: send_pcb entered while threaded\n", dev->name); } - return FALSE; + return false; } /* * load each byte into the command register and @@ -435,7 +420,7 @@ static int send_pcb(struct net_device *dev, pcb_struct * pcb) switch (GET_ASF(dev->base_addr)) { case ASF_PCB_ACK: adapter->send_pcb_semaphore = 0; - return TRUE; + return true; case ASF_PCB_NAK: #ifdef ELP_DEBUG @@ -453,7 +438,7 @@ static int send_pcb(struct net_device *dev, pcb_struct * pcb) spin_unlock_irqrestore(&adapter->lock, flags); abort: adapter->send_pcb_semaphore = 0; - return FALSE; + return false; } @@ -470,7 +455,7 @@ static int send_pcb(struct net_device *dev, pcb_struct * pcb) * *****************************************************************/ -static int receive_pcb(struct net_device *dev, pcb_struct * pcb) +static bool receive_pcb(struct net_device *dev, pcb_struct * pcb) { int i, j; int total_length; @@ -487,7 +472,7 @@ static int receive_pcb(struct net_device *dev, pcb_struct * pcb) while (((stat = get_status(dev->base_addr)) & ACRF) == 0 && time_before(jiffies, timeout)); if (time_after_eq(jiffies, timeout)) { TIMEOUT_MSG(__LINE__); - return FALSE; + return false; } pcb->command = inb_command(dev->base_addr); @@ -497,14 +482,14 @@ static int receive_pcb(struct net_device *dev, pcb_struct * pcb) if (time_after_eq(jiffies, timeout)) { TIMEOUT_MSG(__LINE__); printk(KERN_INFO "%s: status %02x\n", dev->name, stat); - return FALSE; + return false; } pcb->length = inb_command(dev->base_addr); if (pcb->length > MAX_PCB_DATA) { INVALID_PCB_MSG(pcb->length); adapter_reset(dev); - return FALSE; + return false; } /* read the data */ spin_lock_irqsave(&adapter->lock, flags); @@ -519,7 +504,7 @@ static int receive_pcb(struct net_device *dev, pcb_struct * pcb) spin_unlock_irqrestore(&adapter->lock, flags); if (j >= 20000) { TIMEOUT_MSG(__LINE__); - return FALSE; + return false; } /* woops, the last "data" byte was really the length! */ total_length = pcb->data.raw[--i]; @@ -529,7 +514,7 @@ static int receive_pcb(struct net_device *dev, pcb_struct * pcb) if (elp_debug >= 2) printk(KERN_WARNING "%s: mangled PCB received\n", dev->name); set_hsf(dev, HSF_PCB_NAK); - return FALSE; + return false; } if (pcb->command == CMD_RECEIVE_PACKET_COMPLETE) { @@ -538,14 +523,14 @@ static int receive_pcb(struct net_device *dev, pcb_struct * pcb) set_hsf(dev, HSF_PCB_NAK); printk(KERN_WARNING "%s: PCB rejected, transfer in progress and backlog full\n", dev->name); pcb->command = 0; - return TRUE; + return true; } else { pcb->command = 0xff; } } } set_hsf(dev, HSF_PCB_ACK); - return TRUE; + return true; } /****************************************************** @@ -555,9 +540,9 @@ static int receive_pcb(struct net_device *dev, pcb_struct * pcb) * ******************************************************/ -static int start_receive(struct net_device *dev, pcb_struct * tx_pcb) +static bool start_receive(struct net_device *dev, pcb_struct * tx_pcb) { - int status; + bool status; elp_device *adapter = dev->priv; if (elp_debug >= 3) @@ -984,7 +969,7 @@ static int elp_open(struct net_device *dev) * ******************************************************/ -static int send_packet(struct net_device *dev, struct sk_buff *skb) +static bool send_packet(struct net_device *dev, struct sk_buff *skb) { elp_device *adapter = dev->priv; unsigned long target; @@ -998,7 +983,7 @@ static int send_packet(struct net_device *dev, struct sk_buff *skb) if (test_and_set_bit(0, (void *) &adapter->busy)) { if (elp_debug >= 2) printk(KERN_DEBUG "%s: transmit blocked\n", dev->name); - return FALSE; + return false; } adapter->stats.tx_bytes += nlen; @@ -1015,7 +1000,7 @@ static int send_packet(struct net_device *dev, struct sk_buff *skb) if (!send_pcb(dev, &adapter->tx_pcb)) { adapter->busy = 0; - return FALSE; + return false; } /* if this happens, we die */ if (test_and_set_bit(0, (void *) &adapter->dmaing)) @@ -1047,7 +1032,7 @@ static int send_packet(struct net_device *dev, struct sk_buff *skb) if (elp_debug >= 3) printk(KERN_DEBUG "%s: DMA transfer started\n", dev->name); - return TRUE; + return true; } /* -- cgit v1.2.3-70-g09d2 From 5dcddfae63bd26da0f11a8e40f0ae555b5ac624e Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Tue, 7 Aug 2007 14:56:42 -0700 Subject: xen-netfront: remove dead code This patch removes some residual dead code left over from removing the "flip" receive mode. This patch doesn't change the generated output at all, since gcc already realized it was dead. This resolves the "regression" reported by Adrian. Signed-off-by: Jeremy Fitzhardinge Cc: Adrian Bunk Cc: Michal Piotrowski Signed-off-by: Jeff Garzik --- drivers/net/xen-netfront.c | 37 ++----------------------------------- 1 file changed, 2 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 70e551c19e3..b4de126825e 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -214,11 +214,9 @@ static void xennet_alloc_rx_buffers(struct net_device *dev) struct page *page; int i, batch_target, notify; RING_IDX req_prod = np->rx.req_prod_pvt; - struct xen_memory_reservation reservation; grant_ref_t ref; unsigned long pfn; void *vaddr; - int nr_flips; struct xen_netif_rx_request *req; if (unlikely(!netif_carrier_ok(dev))) @@ -268,7 +266,7 @@ no_skb: np->rx_target = np->rx_max_target; refill: - for (nr_flips = i = 0; ; i++) { + for (i = 0; ; i++) { skb = __skb_dequeue(&np->rx_batch); if (skb == NULL) break; @@ -297,38 +295,7 @@ no_skb: req->gref = ref; } - if (nr_flips != 0) { - reservation.extent_start = np->rx_pfn_array; - reservation.nr_extents = nr_flips; - reservation.extent_order = 0; - reservation.address_bits = 0; - reservation.domid = DOMID_SELF; - - if (!xen_feature(XENFEAT_auto_translated_physmap)) { - /* After all PTEs have been zapped, flush the TLB. */ - np->rx_mcl[i-1].args[MULTI_UVMFLAGS_INDEX] = - UVMF_TLB_FLUSH|UVMF_ALL; - - /* Give away a batch of pages. */ - np->rx_mcl[i].op = __HYPERVISOR_memory_op; - np->rx_mcl[i].args[0] = XENMEM_decrease_reservation; - np->rx_mcl[i].args[1] = (unsigned long)&reservation; - - /* Zap PTEs and give away pages in one big - * multicall. */ - (void)HYPERVISOR_multicall(np->rx_mcl, i+1); - - /* Check return status of HYPERVISOR_memory_op(). */ - if (unlikely(np->rx_mcl[i].result != i)) - panic("Unable to reduce memory reservation\n"); - } else { - if (HYPERVISOR_memory_op(XENMEM_decrease_reservation, - &reservation) != i) - panic("Unable to reduce memory reservation\n"); - } - } else { - wmb(); /* barrier so backend seens requests */ - } + wmb(); /* barrier so backend seens requests */ /* Above is a suitable barrier to ensure backend will see requests. */ np->rx.req_prod_pvt = req_prod + i; -- cgit v1.2.3-70-g09d2 From ffe143741f9e0fc3731fe6fe977a2273da4837bd Mon Sep 17 00:00:00 2001 From: Ulrich Kunitz Date: Mon, 6 Aug 2007 01:23:54 +0100 Subject: [PATCH] zd1211rw: removed noisy debug messages While developing the driver we added a lot of debug messages for setting hardware registers. These messages make the reading of the log files difficult and are of no use anymore. This patch removes those messages in zd_chip.c. Signed-off-by: Ulrich Kunitz Signed-off-by: Daniel Drake Signed-off-by: John W. Linville --- drivers/net/wireless/zd1211rw/zd_chip.c | 18 ------------------ 1 file changed, 18 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c index c39f1984b84..7e3c0625129 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.c +++ b/drivers/net/wireless/zd1211rw/zd_chip.c @@ -500,8 +500,6 @@ int zd_chip_lock_phy_regs(struct zd_chip *chip) return r; } - dev_dbg_f(zd_chip_dev(chip), - "CR_REG1: 0x%02x -> 0x%02x\n", tmp, tmp & ~UNLOCK_PHY_REGS); tmp &= ~UNLOCK_PHY_REGS; r = zd_iowrite32_locked(chip, tmp, CR_REG1); @@ -523,8 +521,6 @@ int zd_chip_unlock_phy_regs(struct zd_chip *chip) return r; } - dev_dbg_f(zd_chip_dev(chip), - "CR_REG1: 0x%02x -> 0x%02x\n", tmp, tmp | UNLOCK_PHY_REGS); tmp |= UNLOCK_PHY_REGS; r = zd_iowrite32_locked(chip, tmp, CR_REG1); @@ -841,8 +837,6 @@ static int get_aw_pt_bi(struct zd_chip *chip, struct aw_pt_bi *s) s->atim_wnd_period = values[0]; s->pre_tbtt = values[1]; s->beacon_interval = values[2]; - dev_dbg_f(zd_chip_dev(chip), "aw %u pt %u bi %u\n", - s->atim_wnd_period, s->pre_tbtt, s->beacon_interval); return 0; } @@ -864,9 +858,6 @@ static int set_aw_pt_bi(struct zd_chip *chip, struct aw_pt_bi *s) reqs[2].addr = CR_BCN_INTERVAL; reqs[2].value = s->beacon_interval; - dev_dbg_f(zd_chip_dev(chip), - "aw %u pt %u bi %u\n", s->atim_wnd_period, s->pre_tbtt, - s->beacon_interval); return zd_iowrite32a_locked(chip, reqs, ARRAY_SIZE(reqs)); } @@ -1160,16 +1151,12 @@ out: static int update_pwr_int(struct zd_chip *chip, u8 channel) { u8 value = chip->pwr_int_values[channel - 1]; - dev_dbg_f(zd_chip_dev(chip), "channel %d pwr_int %#04x\n", - channel, value); return zd_iowrite16_locked(chip, value, CR31); } static int update_pwr_cal(struct zd_chip *chip, u8 channel) { u8 value = chip->pwr_cal_values[channel-1]; - dev_dbg_f(zd_chip_dev(chip), "channel %d pwr_cal %#04x\n", - channel, value); return zd_iowrite16_locked(chip, value, CR68); } @@ -1184,9 +1171,6 @@ static int update_ofdm_cal(struct zd_chip *chip, u8 channel) ioreqs[2].addr = CR65; ioreqs[2].value = chip->ofdm_cal_values[OFDM_54M_INDEX][channel-1]; - dev_dbg_f(zd_chip_dev(chip), - "channel %d ofdm_cal 36M %#04x 48M %#04x 54M %#04x\n", - channel, ioreqs[0].value, ioreqs[1].value, ioreqs[2].value); return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); } @@ -1638,7 +1622,5 @@ int zd_chip_set_multicast_hash(struct zd_chip *chip, { CR_GROUP_HASH_P2, hash->high }, }; - dev_dbg_f(zd_chip_dev(chip), "hash l 0x%08x h 0x%08x\n", - ioreqs[0].value, ioreqs[1].value); return zd_iowrite32a(chip, ioreqs, ARRAY_SIZE(ioreqs)); } -- cgit v1.2.3-70-g09d2 From 8e97afe56984237af2115368ca0a5c525049cbd2 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Mon, 6 Aug 2007 01:24:19 +0100 Subject: [PATCH] zd1211rw: Add ID for Sitecom WL-162 Tested by Giuseppe Lippolis zd1211b chip 0cde:001a v4810 high 00-60-b3 AL2230_RF pa0 g--NS Signed-off-by: Daniel Drake Signed-off-by: John W. Linville --- drivers/net/wireless/zd1211rw/zd_usb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index a9c339ef116..6e2c41eb50c 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -74,6 +74,7 @@ static struct usb_device_id usb_ids[] = { { USB_DEVICE(0x0411, 0x00da), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x2019, 0x5303), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x129b, 0x1667), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x0cde, 0x001a), .driver_info = DEVICE_ZD1211B }, /* "Driverless" devices that need ejecting */ { USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER }, { USB_DEVICE(0x0ace, 0x20ff), .driver_info = DEVICE_INSTALLER }, -- cgit v1.2.3-70-g09d2 From 64f222cce2605420470d7a1f678783bdc2754af6 Mon Sep 17 00:00:00 2001 From: Ulrich Kunitz Date: Mon, 6 Aug 2007 01:24:31 +0100 Subject: [PATCH] zd1211rw: consistent handling of ZD1211 specific rates As pointed out by Daniel Drake, the zd1211rw driver used several different rate values and names throughout the driver. He has written a patch to change it and tweaked it after some pretty wild ideas from my side. But the discussion helped me to understand the problem better and I think I have nailed it down with this patch. A zd-rate will consist from now on of a four-bit "pure" rate value and a modulation type flag as used in the ZD1211 control set used for packet transmission. This is consistent with the usage in the zd_rates table. If possible these zd-rates should be used in the code. Signed-off-by: Ulrich Kunitz Signed-off-by: Daniel Drake Signed-off-by: John W. Linville --- drivers/net/wireless/zd1211rw/zd_chip.c | 51 +++++++------- drivers/net/wireless/zd1211rw/zd_ieee80211.h | 43 +++++++----- drivers/net/wireless/zd1211rw/zd_mac.c | 99 ++++++++-------------------- drivers/net/wireless/zd1211rw/zd_mac.h | 65 ++++++++++++------ 4 files changed, 126 insertions(+), 132 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c index 7e3c0625129..495904218b1 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.c +++ b/drivers/net/wireless/zd1211rw/zd_chip.c @@ -1009,19 +1009,19 @@ int zd_chip_set_rts_cts_rate_locked(struct zd_chip *chip, u32 value = 0; /* Modulation bit */ - if (ZD_CS_TYPE(rts_rate) == ZD_CS_OFDM) + if (ZD_MODULATION_TYPE(rts_rate) == ZD_OFDM) rts_mod = ZD_RX_OFDM; dev_dbg_f(zd_chip_dev(chip), "rts_rate=%x preamble=%x\n", rts_rate, preamble); - value |= rts_rate << RTSCTS_SH_RTS_RATE; + value |= ZD_PURE_RATE(rts_rate) << RTSCTS_SH_RTS_RATE; value |= rts_mod << RTSCTS_SH_RTS_MOD_TYPE; value |= preamble << RTSCTS_SH_RTS_PMB_TYPE; value |= preamble << RTSCTS_SH_CTS_PMB_TYPE; /* We always send 11M self-CTS messages, like the vendor driver. */ - value |= ZD_CCK_RATE_11M << RTSCTS_SH_CTS_RATE; + value |= ZD_PURE_RATE(ZD_CCK_RATE_11M) << RTSCTS_SH_CTS_RATE; value |= ZD_RX_CCK << RTSCTS_SH_CTS_MOD_TYPE; return zd_iowrite32_locked(chip, value, CR_RTS_CTS_RATE); @@ -1328,7 +1328,7 @@ int zd_chip_set_basic_rates_locked(struct zd_chip *chip, u16 cr_rates) return zd_iowrite32_locked(chip, cr_rates, CR_BASIC_RATE_TBL); } -static int ofdm_qual_db(u8 status_quality, u8 rate, unsigned int size) +static int ofdm_qual_db(u8 status_quality, u8 zd_rate, unsigned int size) { static const u16 constants[] = { 715, 655, 585, 540, 470, 410, 360, 315, @@ -1342,7 +1342,7 @@ static int ofdm_qual_db(u8 status_quality, u8 rate, unsigned int size) /* It seems that their quality parameter is somehow per signal * and is now transferred per bit. */ - switch (rate) { + switch (zd_rate) { case ZD_OFDM_RATE_6M: case ZD_OFDM_RATE_12M: case ZD_OFDM_RATE_24M: @@ -1369,7 +1369,7 @@ static int ofdm_qual_db(u8 status_quality, u8 rate, unsigned int size) break; } - switch (rate) { + switch (zd_rate) { case ZD_OFDM_RATE_6M: case ZD_OFDM_RATE_9M: i += 3; @@ -1393,11 +1393,11 @@ static int ofdm_qual_db(u8 status_quality, u8 rate, unsigned int size) return i; } -static int ofdm_qual_percent(u8 status_quality, u8 rate, unsigned int size) +static int ofdm_qual_percent(u8 status_quality, u8 zd_rate, unsigned int size) { int r; - r = ofdm_qual_db(status_quality, rate, size); + r = ofdm_qual_db(status_quality, zd_rate, size); ZD_ASSERT(r >= 0); if (r < 0) r = 0; @@ -1458,12 +1458,17 @@ static int cck_qual_percent(u8 status_quality) return r <= 100 ? r : 100; } +static inline u8 zd_rate_from_ofdm_plcp_header(const void *rx_frame) +{ + return ZD_OFDM | zd_ofdm_plcp_header_rate(rx_frame); +} + u8 zd_rx_qual_percent(const void *rx_frame, unsigned int size, const struct rx_status *status) { return (status->frame_status&ZD_RX_OFDM) ? ofdm_qual_percent(status->signal_quality_ofdm, - zd_ofdm_plcp_header_rate(rx_frame), + zd_rate_from_ofdm_plcp_header(rx_frame), size) : cck_qual_percent(status->signal_quality_cck); } @@ -1479,32 +1484,32 @@ u8 zd_rx_strength_percent(u8 rssi) u16 zd_rx_rate(const void *rx_frame, const struct rx_status *status) { static const u16 ofdm_rates[] = { - [ZD_OFDM_RATE_6M] = 60, - [ZD_OFDM_RATE_9M] = 90, - [ZD_OFDM_RATE_12M] = 120, - [ZD_OFDM_RATE_18M] = 180, - [ZD_OFDM_RATE_24M] = 240, - [ZD_OFDM_RATE_36M] = 360, - [ZD_OFDM_RATE_48M] = 480, - [ZD_OFDM_RATE_54M] = 540, + [ZD_OFDM_PLCP_RATE_6M] = 60, + [ZD_OFDM_PLCP_RATE_9M] = 90, + [ZD_OFDM_PLCP_RATE_12M] = 120, + [ZD_OFDM_PLCP_RATE_18M] = 180, + [ZD_OFDM_PLCP_RATE_24M] = 240, + [ZD_OFDM_PLCP_RATE_36M] = 360, + [ZD_OFDM_PLCP_RATE_48M] = 480, + [ZD_OFDM_PLCP_RATE_54M] = 540, }; u16 rate; if (status->frame_status & ZD_RX_OFDM) { + /* Deals with PLCP OFDM rate (not zd_rates) */ u8 ofdm_rate = zd_ofdm_plcp_header_rate(rx_frame); rate = ofdm_rates[ofdm_rate & 0xf]; } else { - u8 cck_rate = zd_cck_plcp_header_rate(rx_frame); - switch (cck_rate) { - case ZD_CCK_SIGNAL_1M: + switch (zd_cck_plcp_header_signal(rx_frame)) { + case ZD_CCK_PLCP_SIGNAL_1M: rate = 10; break; - case ZD_CCK_SIGNAL_2M: + case ZD_CCK_PLCP_SIGNAL_2M: rate = 20; break; - case ZD_CCK_SIGNAL_5M5: + case ZD_CCK_PLCP_SIGNAL_5M5: rate = 55; break; - case ZD_CCK_SIGNAL_11M: + case ZD_CCK_PLCP_SIGNAL_11M: rate = 110; break; default: diff --git a/drivers/net/wireless/zd1211rw/zd_ieee80211.h b/drivers/net/wireless/zd1211rw/zd_ieee80211.h index c4f36d39642..fbf6491dce7 100644 --- a/drivers/net/wireless/zd1211rw/zd_ieee80211.h +++ b/drivers/net/wireless/zd1211rw/zd_ieee80211.h @@ -43,21 +43,25 @@ struct ofdm_plcp_header { __le16 service; } __attribute__((packed)); -static inline u8 zd_ofdm_plcp_header_rate( - const struct ofdm_plcp_header *header) +static inline u8 zd_ofdm_plcp_header_rate(const struct ofdm_plcp_header *header) { return header->prefix[0] & 0xf; } -/* These are referred to as zd_rates */ -#define ZD_OFDM_RATE_6M 0xb -#define ZD_OFDM_RATE_9M 0xf -#define ZD_OFDM_RATE_12M 0xa -#define ZD_OFDM_RATE_18M 0xe -#define ZD_OFDM_RATE_24M 0x9 -#define ZD_OFDM_RATE_36M 0xd -#define ZD_OFDM_RATE_48M 0x8 -#define ZD_OFDM_RATE_54M 0xc +/* The following defines give the encoding of the 4-bit rate field in the + * OFDM (802.11a/802.11g) PLCP header. Notify that these values are used to + * define the zd-rate values for OFDM. + * + * See the struct zd_ctrlset definition in zd_mac.h. + */ +#define ZD_OFDM_PLCP_RATE_6M 0xb +#define ZD_OFDM_PLCP_RATE_9M 0xf +#define ZD_OFDM_PLCP_RATE_12M 0xa +#define ZD_OFDM_PLCP_RATE_18M 0xe +#define ZD_OFDM_PLCP_RATE_24M 0x9 +#define ZD_OFDM_PLCP_RATE_36M 0xd +#define ZD_OFDM_PLCP_RATE_48M 0x8 +#define ZD_OFDM_PLCP_RATE_54M 0xc struct cck_plcp_header { u8 signal; @@ -66,15 +70,22 @@ struct cck_plcp_header { __le16 crc16; } __attribute__((packed)); -static inline u8 zd_cck_plcp_header_rate(const struct cck_plcp_header *header) +static inline u8 zd_cck_plcp_header_signal(const struct cck_plcp_header *header) { return header->signal; } -#define ZD_CCK_SIGNAL_1M 0x0a -#define ZD_CCK_SIGNAL_2M 0x14 -#define ZD_CCK_SIGNAL_5M5 0x37 -#define ZD_CCK_SIGNAL_11M 0x6e +/* These defines give the encodings of the signal field in the 802.11b PLCP + * header. The signal field gives the bit rate of the following packet. Even + * if technically wrong we use CCK here also for the 1 MBit/s and 2 MBit/s + * rate to stay consistent with Zydas and our use of the term. + * + * Notify that these values are *not* used in the zd-rates. + */ +#define ZD_CCK_PLCP_SIGNAL_1M 0x0a +#define ZD_CCK_PLCP_SIGNAL_2M 0x14 +#define ZD_CCK_PLCP_SIGNAL_5M5 0x37 +#define ZD_CCK_PLCP_SIGNAL_11M 0x6e enum ieee80211_std { IEEE80211B = 0x01, diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 7ec1fcf37fc..451308d7095 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -610,28 +610,6 @@ u8 zd_mac_get_channel(struct zd_mac *mac) return channel; } -/* If wrong rate is given, we are falling back to the slowest rate: 1MBit/s */ -static u8 zd_rate_typed(u8 zd_rate) -{ - static const u8 typed_rates[16] = { - [ZD_CCK_RATE_1M] = ZD_CS_CCK|ZD_CCK_RATE_1M, - [ZD_CCK_RATE_2M] = ZD_CS_CCK|ZD_CCK_RATE_2M, - [ZD_CCK_RATE_5_5M] = ZD_CS_CCK|ZD_CCK_RATE_5_5M, - [ZD_CCK_RATE_11M] = ZD_CS_CCK|ZD_CCK_RATE_11M, - [ZD_OFDM_RATE_6M] = ZD_CS_OFDM|ZD_OFDM_RATE_6M, - [ZD_OFDM_RATE_9M] = ZD_CS_OFDM|ZD_OFDM_RATE_9M, - [ZD_OFDM_RATE_12M] = ZD_CS_OFDM|ZD_OFDM_RATE_12M, - [ZD_OFDM_RATE_18M] = ZD_CS_OFDM|ZD_OFDM_RATE_18M, - [ZD_OFDM_RATE_24M] = ZD_CS_OFDM|ZD_OFDM_RATE_24M, - [ZD_OFDM_RATE_36M] = ZD_CS_OFDM|ZD_OFDM_RATE_36M, - [ZD_OFDM_RATE_48M] = ZD_CS_OFDM|ZD_OFDM_RATE_48M, - [ZD_OFDM_RATE_54M] = ZD_CS_OFDM|ZD_OFDM_RATE_54M, - }; - - ZD_ASSERT(ZD_CS_RATE_MASK == 0x0f); - return typed_rates[zd_rate & ZD_CS_RATE_MASK]; -} - int zd_mac_set_mode(struct zd_mac *mac, u32 mode) { struct ieee80211_device *ieee; @@ -739,25 +717,30 @@ int zd_mac_get_range(struct zd_mac *mac, struct iw_range *range) static int zd_calc_tx_length_us(u8 *service, u8 zd_rate, u16 tx_length) { + /* ZD_PURE_RATE() must be used to remove the modulation type flag of + * the zd-rate values. */ static const u8 rate_divisor[] = { - [ZD_CCK_RATE_1M] = 1, - [ZD_CCK_RATE_2M] = 2, - [ZD_CCK_RATE_5_5M] = 11, /* bits must be doubled */ - [ZD_CCK_RATE_11M] = 11, - [ZD_OFDM_RATE_6M] = 6, - [ZD_OFDM_RATE_9M] = 9, - [ZD_OFDM_RATE_12M] = 12, - [ZD_OFDM_RATE_18M] = 18, - [ZD_OFDM_RATE_24M] = 24, - [ZD_OFDM_RATE_36M] = 36, - [ZD_OFDM_RATE_48M] = 48, - [ZD_OFDM_RATE_54M] = 54, + [ZD_PURE_RATE(ZD_CCK_RATE_1M)] = 1, + [ZD_PURE_RATE(ZD_CCK_RATE_2M)] = 2, + + /* bits must be doubled */ + [ZD_PURE_RATE(ZD_CCK_RATE_5_5M)] = 11, + + [ZD_PURE_RATE(ZD_CCK_RATE_11M)] = 11, + [ZD_PURE_RATE(ZD_OFDM_RATE_6M)] = 6, + [ZD_PURE_RATE(ZD_OFDM_RATE_9M)] = 9, + [ZD_PURE_RATE(ZD_OFDM_RATE_12M)] = 12, + [ZD_PURE_RATE(ZD_OFDM_RATE_18M)] = 18, + [ZD_PURE_RATE(ZD_OFDM_RATE_24M)] = 24, + [ZD_PURE_RATE(ZD_OFDM_RATE_36M)] = 36, + [ZD_PURE_RATE(ZD_OFDM_RATE_48M)] = 48, + [ZD_PURE_RATE(ZD_OFDM_RATE_54M)] = 54, }; u32 bits = (u32)tx_length * 8; u32 divisor; - divisor = rate_divisor[zd_rate]; + divisor = rate_divisor[ZD_PURE_RATE(zd_rate)]; if (divisor == 0) return -EINVAL; @@ -780,52 +763,24 @@ static int zd_calc_tx_length_us(u8 *service, u8 zd_rate, u16 tx_length) return bits/divisor; } -enum { - R2M_SHORT_PREAMBLE = 0x01, - R2M_11A = 0x02, -}; - -static u8 zd_rate_to_modulation(u8 zd_rate, int flags) -{ - u8 modulation; - - modulation = zd_rate_typed(zd_rate); - if (flags & R2M_SHORT_PREAMBLE) { - switch (ZD_CS_RATE(modulation)) { - case ZD_CCK_RATE_2M: - case ZD_CCK_RATE_5_5M: - case ZD_CCK_RATE_11M: - modulation |= ZD_CS_CCK_PREA_SHORT; - return modulation; - } - } - if (flags & R2M_11A) { - if (ZD_CS_TYPE(modulation) == ZD_CS_OFDM) - modulation |= ZD_CS_OFDM_MODE_11A; - } - return modulation; -} - static void cs_set_modulation(struct zd_mac *mac, struct zd_ctrlset *cs, struct ieee80211_hdr_4addr *hdr) { struct ieee80211softmac_device *softmac = ieee80211_priv(mac->netdev); u16 ftype = WLAN_FC_GET_TYPE(le16_to_cpu(hdr->frame_ctl)); - u8 rate, zd_rate; + u8 rate; int is_mgt = (ftype == IEEE80211_FTYPE_MGMT) != 0; int is_multicast = is_multicast_ether_addr(hdr->addr1); int short_preamble = ieee80211softmac_short_preamble_ok(softmac, is_multicast, is_mgt); - int flags = 0; - /* FIXME: 802.11a? */ rate = ieee80211softmac_suggest_txrate(softmac, is_multicast, is_mgt); + cs->modulation = rate_to_zd_rate(rate); - if (short_preamble) - flags |= R2M_SHORT_PREAMBLE; - - zd_rate = rate_to_zd_rate(rate); - cs->modulation = zd_rate_to_modulation(zd_rate, flags); + /* Set short preamble bit when appropriate */ + if (short_preamble && ZD_MODULATION_TYPE(cs->modulation) == ZD_CCK + && cs->modulation != ZD_CCK_RATE_1M) + cs->modulation |= ZD_CCK_PREA_SHORT; } static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs, @@ -864,7 +819,7 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs, cs->control |= ZD_CS_RTS; /* Use CTS-to-self protection if required */ - if (ZD_CS_TYPE(cs->modulation) == ZD_CS_OFDM && + if (ZD_MODULATION_TYPE(cs->modulation) == ZD_OFDM && ieee80211softmac_protection_needed(softmac)) { /* FIXME: avoid sending RTS *and* self-CTS, is that correct? */ cs->control &= ~ZD_CS_RTS; @@ -925,7 +880,7 @@ static int fill_ctrlset(struct zd_mac *mac, * - see line 53 of zdinlinef.h */ cs->service = 0; - r = zd_calc_tx_length_us(&cs->service, ZD_CS_RATE(cs->modulation), + r = zd_calc_tx_length_us(&cs->service, ZD_RATE(cs->modulation), le16_to_cpu(cs->tx_length)); if (r < 0) return r; @@ -934,7 +889,7 @@ static int fill_ctrlset(struct zd_mac *mac, if (next_frag_len == 0) { cs->next_frame_length = 0; } else { - r = zd_calc_tx_length_us(NULL, ZD_CS_RATE(cs->modulation), + r = zd_calc_tx_length_us(NULL, ZD_RATE(cs->modulation), next_frag_len); if (r < 0) return r; diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h index 9f9344eb50f..1b15bde3ff6 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.h +++ b/drivers/net/wireless/zd1211rw/zd_mac.h @@ -40,28 +40,51 @@ struct zd_ctrlset { #define ZD_CS_RESERVED_SIZE 25 -/* zd_crtlset field modulation */ -#define ZD_CS_RATE_MASK 0x0f -#define ZD_CS_TYPE_MASK 0x10 -#define ZD_CS_RATE(modulation) ((modulation) & ZD_CS_RATE_MASK) -#define ZD_CS_TYPE(modulation) ((modulation) & ZD_CS_TYPE_MASK) - -#define ZD_CS_CCK 0x00 -#define ZD_CS_OFDM 0x10 - -/* These are referred to as zd_rates */ -#define ZD_CCK_RATE_1M 0x00 -#define ZD_CCK_RATE_2M 0x01 -#define ZD_CCK_RATE_5_5M 0x02 -#define ZD_CCK_RATE_11M 0x03 -/* The rates for OFDM are encoded as in the PLCP header. Use ZD_OFDM_RATE_*. +/* The field modulation of struct zd_ctrlset controls the bit rate, the use + * of short or long preambles in 802.11b (CCK mode) or the use of 802.11a or + * 802.11g in OFDM mode. + * + * The term zd-rate is used for the combination of the modulation type flag + * and the "pure" rate value. */ - -/* bit 5 is preamble (when in CCK mode), or a/g selection (when in OFDM mode) */ -#define ZD_CS_CCK_PREA_LONG 0x00 -#define ZD_CS_CCK_PREA_SHORT 0x20 -#define ZD_CS_OFDM_MODE_11G 0x00 -#define ZD_CS_OFDM_MODE_11A 0x20 +#define ZD_PURE_RATE_MASK 0x0f +#define ZD_MODULATION_TYPE_MASK 0x10 +#define ZD_RATE_MASK (ZD_PURE_RATE_MASK|ZD_MODULATION_TYPE_MASK) +#define ZD_PURE_RATE(modulation) ((modulation) & ZD_PURE_RATE_MASK) +#define ZD_MODULATION_TYPE(modulation) ((modulation) & ZD_MODULATION_TYPE_MASK) +#define ZD_RATE(modulation) ((modulation) & ZD_RATE_MASK) + +/* The two possible modulation types. Notify that 802.11b doesn't use the CCK + * codeing for the 1 and 2 MBit/s rate. We stay with the term here to remain + * consistent with uses the term at other places. + */ +#define ZD_CCK 0x00 +#define ZD_OFDM 0x10 + +/* The ZD1211 firmware uses proprietary encodings of the 802.11b (CCK) rates. + * For OFDM the PLCP rate encodings are used. We combine these "pure" rates + * with the modulation type flag and call the resulting values zd-rates. + */ +#define ZD_CCK_RATE_1M (ZD_CCK|0x00) +#define ZD_CCK_RATE_2M (ZD_CCK|0x01) +#define ZD_CCK_RATE_5_5M (ZD_CCK|0x02) +#define ZD_CCK_RATE_11M (ZD_CCK|0x03) +#define ZD_OFDM_RATE_6M (ZD_OFDM|ZD_OFDM_PLCP_RATE_6M) +#define ZD_OFDM_RATE_9M (ZD_OFDM|ZD_OFDM_PLCP_RATE_9M) +#define ZD_OFDM_RATE_12M (ZD_OFDM|ZD_OFDM_PLCP_RATE_12M) +#define ZD_OFDM_RATE_18M (ZD_OFDM|ZD_OFDM_PLCP_RATE_18M) +#define ZD_OFDM_RATE_24M (ZD_OFDM|ZD_OFDM_PLCP_RATE_24M) +#define ZD_OFDM_RATE_36M (ZD_OFDM|ZD_OFDM_PLCP_RATE_36M) +#define ZD_OFDM_RATE_48M (ZD_OFDM|ZD_OFDM_PLCP_RATE_48M) +#define ZD_OFDM_RATE_54M (ZD_OFDM|ZD_OFDM_PLCP_RATE_54M) + +/* The bit 5 of the zd_ctrlset modulation field controls the preamble in CCK + * mode or the 802.11a/802.11g selection in OFDM mode. + */ +#define ZD_CCK_PREA_LONG 0x00 +#define ZD_CCK_PREA_SHORT 0x20 +#define ZD_OFDM_MODE_11G 0x00 +#define ZD_OFDM_MODE_11A 0x20 /* zd_ctrlset control field */ #define ZD_CS_NEED_RANDOM_BACKOFF 0x01 -- cgit v1.2.3-70-g09d2 From 475fed1e22e58508cf50c882db68c7b29842d4d5 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Mon, 6 Aug 2007 02:25:18 +0100 Subject: [PATCH] zd1211rw: Add ID for ZyXEL M-202 XtremeMIMO Tested by Nathen Meyers FCC ID: SI5WUB221Z zd1211b chip 0586:340a v4810 high 00-13-49 AL2230_RF pa0 ----S Despite the product name, I'm pretty sure this isn't a MIMO device. It appears just to be a normal ZD1211B and we have never heard of these devices having more than 1 RF. I guess they named this product this way to make it appear that it fits in with the rest of their XtremeMIMO product range. Signed-off-by: Daniel Drake Signed-off-by: John W. Linville --- drivers/net/wireless/zd1211rw/zd_usb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index 6e2c41eb50c..e49628b7d4c 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -75,6 +75,7 @@ static struct usb_device_id usb_ids[] = { { USB_DEVICE(0x2019, 0x5303), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x129b, 0x1667), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x0cde, 0x001a), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x0586, 0x340a), .driver_info = DEVICE_ZD1211B }, /* "Driverless" devices that need ejecting */ { USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER }, { USB_DEVICE(0x0ace, 0x20ff), .driver_info = DEVICE_INSTALLER }, -- cgit v1.2.3-70-g09d2 From 7563a0b4b5c28b9695f7136fa0ef0cc4cbe1b0c6 Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Tue, 7 Aug 2007 00:50:22 +0200 Subject: [PATCH] drivers/net/wireless/wl3501_cs.c: remove redundant memset Signed-off-by: Mariusz Kozlowski Signed-off-by: John W. Linville --- drivers/net/wireless/wl3501_cs.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index 72f3d97e7cb..732b59f1989 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -1841,7 +1841,6 @@ static int wl3501_get_encode(struct net_device *dev, tocopy = min_t(u8, len_keys, wrqu->encoding.length); tocopy = min_t(u8, tocopy, 100); wrqu->encoding.length = tocopy; - memset(extra, 0, tocopy); memcpy(extra, keys, tocopy); out: return rc; -- cgit v1.2.3-70-g09d2 From b1b1907dceadddc7d7317f8ae85a5efec44125d8 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 20 Aug 2007 11:10:45 -0400 Subject: [PATCH] libertas: fix inadvertant removal of bits from commit 831441862956fffa17b9801db37e6ea1650b0f69 Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index f0213eca680..ce1c18ee628 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -768,6 +768,7 @@ static int libertas_thread(void *data) init_waitqueue_entry(&wait, current); + set_freezable(); for (;;) { lbs_deb_thread( "main-thread 111: intcounter=%d " "currenttxskb=%p dnld_sent=%d\n", -- cgit v1.2.3-70-g09d2 From 954ee164f4f4598afc172c0ec3865d0352e55a0b Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 20 Aug 2007 11:43:25 -0400 Subject: [PATCH] libertas: reorganize and simplify init sequence This patch moves all firmware load responsibility into the interface-specific code and gets rid of the firmware pointer in the generic card structure. It also removes 3 fairly unecessary callbacks: hw_register_dev, hw_unregister_dev, and hw_prog_firmware. It also makes the init sequence from interface probe functions more logical, as there are paired add/remove and start/stop calls into generic libertas code. Because the USB driver code uses the same TX URB callback for both firmware upload (where the generic libertas structure isn't initialized yet) and for normal operation (where it is), some bits of USB code have to deal with 'priv' being NULL. All USB firmware upload bits have been changed to not require 'priv' at all, but simply the USB card structure. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/decl.h | 3 +- drivers/net/wireless/libertas/dev.h | 4 - drivers/net/wireless/libertas/if_cs.c | 54 +---- drivers/net/wireless/libertas/if_usb.c | 365 +++++++++++++---------------- drivers/net/wireless/libertas/if_usb.h | 4 +- drivers/net/wireless/libertas/main.c | 405 +++++++++++++-------------------- 6 files changed, 334 insertions(+), 501 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h index 095edf6a4c2..87fea9d5b90 100644 --- a/drivers/net/wireless/libertas/decl.h +++ b/drivers/net/wireless/libertas/decl.h @@ -72,8 +72,9 @@ void libertas_send_iwevcustom_event(wlan_private * priv, s8 * str); struct chan_freq_power *libertas_get_region_cfp_table(u8 region, u8 band, int *cfp_no); wlan_private *libertas_add_card(void *card, struct device *dmdev); -int libertas_activate_card(wlan_private *priv); int libertas_remove_card(wlan_private *priv); +int libertas_start_card(wlan_private *priv); +int libertas_stop_card(wlan_private *priv); int libertas_add_mesh(wlan_private *priv, struct device *dev); void libertas_remove_mesh(wlan_private *priv); int libertas_reset_device(wlan_private *priv); diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index a3c94d7388a..1fb807aa91b 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -143,7 +143,6 @@ struct _wlan_private { all other bits reserved 0 */ u8 dnld_sent; - const struct firmware *firmware; struct device *hotplug_device; /** thread to service interrupts */ @@ -156,9 +155,6 @@ struct _wlan_private { struct work_struct sync_channel; /** Hardware access */ - int (*hw_register_dev) (wlan_private * priv); - int (*hw_unregister_dev) (wlan_private *); - int (*hw_prog_firmware) (wlan_private *); int (*hw_host_to_card) (wlan_private * priv, u8 type, u8 * payload, u16 nb); int (*hw_get_int_status) (wlan_private * priv, u8 *); int (*hw_read_event_cause) (wlan_private *); diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c index 888f023a74e..4dffc5cc0d1 100644 --- a/drivers/net/wireless/libertas/if_cs.c +++ b/drivers/net/wireless/libertas/if_cs.c @@ -608,51 +608,6 @@ done: /* Callback functions for libertas.ko */ /********************************************************************/ -static int if_cs_register_dev(wlan_private *priv) -{ - struct if_cs_card *card = (struct if_cs_card *)priv->card; - - lbs_deb_enter(LBS_DEB_CS); - - card->priv = priv; - - return 0; -} - - -static int if_cs_unregister_dev(wlan_private *priv) -{ - lbs_deb_enter(LBS_DEB_CS); - - /* - * Nothing special here. Because the device's power gets turned off - * anyway, there's no need to send a RESET command like in if_usb.c - */ - - return 0; -} - - -/* - * This callback is a dummy. The reason is that the USB code needs - * to have various things set up in order to be able to download the - * firmware. That's not needed in our case. - * - * On the contrary, if libertas_add_card() has been called and we're - * then later called via libertas_activate_card(), but without a valid - * firmware, then it's quite tedious to tear down the half-installed - * card. Therefore, we download the firmware before calling adding/ - * activating the card in the first place. If that doesn't work, we - * won't call into libertas.ko at all. - */ - -static int if_cs_prog_firmware(wlan_private *priv) -{ - priv->adapter->fw_ready = 1; - return 0; -} - - /* Send commands or data packets to the card */ static int if_cs_host_to_card(wlan_private *priv, u8 type, u8 *buf, u16 nb) { @@ -902,14 +857,14 @@ static int if_cs_probe(struct pcmcia_device *p_dev) } /* Store pointers to our call-back functions */ + card->priv = priv; priv->card = card; - priv->hw_register_dev = if_cs_register_dev; - priv->hw_unregister_dev = if_cs_unregister_dev; - priv->hw_prog_firmware = if_cs_prog_firmware; priv->hw_host_to_card = if_cs_host_to_card; priv->hw_get_int_status = if_cs_get_int_status; priv->hw_read_event_cause = if_cs_read_event_cause; + priv->adapter->fw_ready = 1; + /* Now actually get the IRQ */ ret = request_irq(p_dev->irq.AssignedIRQ, if_cs_interrupt, IRQF_SHARED, DRV_NAME, card); @@ -919,7 +874,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev) } /* And finally bring the card up */ - if (libertas_activate_card(priv) != 0) { + if (libertas_start_card(priv) != 0) { lbs_pr_err("could not activate card\n"); goto out3; } @@ -951,6 +906,7 @@ static void if_cs_detach(struct pcmcia_device *p_dev) lbs_deb_enter(LBS_DEB_CS); + libertas_stop_card(card->priv); libertas_remove_card(card->priv); if_cs_release(p_dev); kfree(card); diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index 364eae374b9..105a00a7025 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -45,14 +45,14 @@ MODULE_DEVICE_TABLE(usb, if_usb_table); static void if_usb_receive(struct urb *urb); static void if_usb_receive_fwload(struct urb *urb); -static int if_usb_register_dev(wlan_private * priv); -static int if_usb_unregister_dev(wlan_private *); -static int if_usb_prog_firmware(wlan_private *); +static int if_usb_prog_firmware(struct usb_card_rec *cardp); static int if_usb_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb); static int if_usb_get_int_status(wlan_private * priv, u8 *); static int if_usb_read_event_cause(wlan_private *); -static int usb_tx_block(wlan_private *priv, u8 *payload, u16 nb); +static int usb_tx_block(struct usb_card_rec *cardp, u8 *payload, u16 nb); static void if_usb_free(struct usb_card_rec *cardp); +static int if_usb_submit_rx_urb(struct usb_card_rec *cardp); +static int if_usb_reset_device(struct usb_card_rec *cardp); /** * @brief call back function to handle the status of the URB @@ -61,29 +61,40 @@ static void if_usb_free(struct usb_card_rec *cardp); */ static void if_usb_write_bulk_callback(struct urb *urb) { - wlan_private *priv = (wlan_private *) (urb->context); - wlan_adapter *adapter = priv->adapter; - struct net_device *dev = priv->dev; + struct usb_card_rec *cardp = (struct usb_card_rec *) urb->context; /* handle the transmission complete validations */ - if (urb->status != 0) { - /* print the failure status number for debug */ - lbs_pr_info("URB in failure status: %d\n", urb->status); - } else { + if (urb->status == 0) { + wlan_private *priv = cardp->priv; + /* lbs_deb_usbd(&urb->dev->dev, "URB status is successfull\n"); lbs_deb_usbd(&urb->dev->dev, "Actual length transmitted %d\n", urb->actual_length); */ - priv->dnld_sent = DNLD_RES_RECEIVED; - /* Wake main thread if commands are pending */ - if (!adapter->cur_cmd) - wake_up_interruptible(&priv->waitq); - if ((adapter->connect_status == LIBERTAS_CONNECTED)) { - netif_wake_queue(dev); - netif_wake_queue(priv->mesh_dev); + + /* Used for both firmware TX and regular TX. priv isn't + * valid at firmware load time. + */ + if (priv) { + wlan_adapter *adapter = priv->adapter; + struct net_device *dev = priv->dev; + + priv->dnld_sent = DNLD_RES_RECEIVED; + + /* Wake main thread if commands are pending */ + if (!adapter->cur_cmd) + wake_up_interruptible(&priv->waitq); + + if ((adapter->connect_status == LIBERTAS_CONNECTED)) { + netif_wake_queue(dev); + netif_wake_queue(priv->mesh_dev); + } } + } else { + /* print the failure status number for debug */ + lbs_pr_info("URB in failure status: %d\n", urb->status); } return; @@ -205,24 +216,35 @@ static int if_usb_probe(struct usb_interface *intf, } } + /* Upload firmware */ + cardp->rinfo.cardp = cardp; + if (if_usb_prog_firmware(cardp)) { + lbs_deb_usbd(&udev->dev, "FW upload failed"); + goto err_prog_firmware; + } + if (!(priv = libertas_add_card(cardp, &udev->dev))) - goto dealloc; + goto err_prog_firmware; - udev->dev.driver_data = priv; + cardp->priv = priv; if (libertas_add_mesh(priv, &udev->dev)) goto err_add_mesh; - priv->hw_register_dev = if_usb_register_dev; - priv->hw_unregister_dev = if_usb_unregister_dev; - priv->hw_prog_firmware = if_usb_prog_firmware; + cardp->eth_dev = priv->dev; + priv->hw_host_to_card = if_usb_host_to_card; priv->hw_get_int_status = if_usb_get_int_status; priv->hw_read_event_cause = if_usb_read_event_cause; priv->boot2_version = udev->descriptor.bcdDevice; - if (libertas_activate_card(priv)) - goto err_activate_card; + /* Delay 200 ms to waiting for the FW ready */ + if_usb_submit_rx_urb(cardp); + msleep_interruptible(200); + priv->adapter->fw_ready = 1; + + if (libertas_start_card(priv)) + goto err_start_card; list_add_tail(&cardp->list, &usb_devices); @@ -231,11 +253,12 @@ static int if_usb_probe(struct usb_interface *intf, return 0; -err_activate_card: +err_start_card: libertas_remove_mesh(priv); err_add_mesh: - free_netdev(priv->dev); - kfree(priv->adapter); + libertas_remove_card(priv); +err_prog_firmware: + if_usb_reset_device(cardp); dealloc: if_usb_free(cardp); @@ -252,21 +275,22 @@ static void if_usb_disconnect(struct usb_interface *intf) { struct usb_card_rec *cardp = usb_get_intfdata(intf); wlan_private *priv = (wlan_private *) cardp->priv; - wlan_adapter *adapter = NULL; - adapter = priv->adapter; + lbs_deb_enter(LBS_DEB_MAIN); - /* - * Update Surprise removed to TRUE - */ - adapter->surpriseremoved = 1; + /* Update Surprise removed to TRUE */ + cardp->surprise_removed = 1; list_del(&cardp->list); - /* card is removed and we can call wlan_remove_card */ - lbs_deb_usbd(&cardp->udev->dev, "call remove card\n"); - libertas_remove_mesh(priv); - libertas_remove_card(priv); + if (priv) { + wlan_adapter *adapter = priv->adapter; + + adapter->surpriseremoved = 1; + libertas_stop_card(priv); + libertas_remove_mesh(priv); + libertas_remove_card(priv); + } /* Unlink and free urb */ if_usb_free(cardp); @@ -274,7 +298,7 @@ static void if_usb_disconnect(struct usb_interface *intf) usb_set_intfdata(intf, NULL); usb_put_dev(interface_to_usbdev(intf)); - return; + lbs_deb_leave(LBS_DEB_MAIN); } /** @@ -282,12 +306,11 @@ static void if_usb_disconnect(struct usb_interface *intf) * @param priv pointer to wlan_private * @return 0 */ -static int if_prog_firmware(wlan_private * priv) +static int if_prog_firmware(struct usb_card_rec *cardp) { - struct usb_card_rec *cardp = priv->card; struct FWData *fwdata; struct fwheader *fwheader; - u8 *firmware = priv->firmware->data; + u8 *firmware = cardp->fw->data; fwdata = kmalloc(sizeof(struct FWData), GFP_ATOMIC); @@ -335,7 +358,7 @@ static int if_prog_firmware(wlan_private * priv) cardp->totalbytes); */ memcpy(cardp->bulk_out_buffer, fwheader, FW_DATA_XMIT_SIZE); - usb_tx_block(priv, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE); + usb_tx_block(cardp, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE); } else if (fwdata->fwheader.dnldcmd == cpu_to_le32(FW_HAS_LAST_BLOCK)) { /* @@ -345,7 +368,7 @@ static int if_prog_firmware(wlan_private * priv) "Donwloading FW JUMP BLOCK\n"); */ memcpy(cardp->bulk_out_buffer, fwheader, FW_DATA_XMIT_SIZE); - usb_tx_block(priv, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE); + usb_tx_block(cardp, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE); cardp->fwfinalblk = 1; } @@ -360,10 +383,10 @@ static int if_prog_firmware(wlan_private * priv) return 0; } -static int if_usb_reset_device(wlan_private *priv) +static int if_usb_reset_device(struct usb_card_rec *cardp) { int ret; - struct usb_card_rec *cardp = priv->card; + wlan_private * priv = cardp->priv; lbs_deb_enter(LBS_DEB_USB); @@ -371,7 +394,7 @@ static int if_usb_reset_device(wlan_private *priv) * command to the firmware. */ ret = usb_reset_device(cardp->udev); - if (!ret) { + if (!ret && priv) { msleep(10); ret = libertas_reset_device(priv); msleep(10); @@ -389,14 +412,12 @@ static int if_usb_reset_device(wlan_private *priv) * @param nb data length * @return 0 or -1 */ -static int usb_tx_block(wlan_private * priv, u8 * payload, u16 nb) +static int usb_tx_block(struct usb_card_rec *cardp, u8 * payload, u16 nb) { - /* pointer to card structure */ - struct usb_card_rec *cardp = priv->card; int ret = -1; /* check if device is removed */ - if (priv->adapter->surpriseremoved) { + if (cardp->surprise_removed) { lbs_deb_usbd(&cardp->udev->dev, "Device removed\n"); goto tx_ret; } @@ -404,7 +425,7 @@ static int usb_tx_block(wlan_private * priv, u8 * payload, u16 nb) usb_fill_bulk_urb(cardp->tx_urb, cardp->udev, usb_sndbulkpipe(cardp->udev, cardp->bulk_out_endpointAddr), - payload, nb, if_usb_write_bulk_callback, priv); + payload, nb, if_usb_write_bulk_callback, cardp); cardp->tx_urb->transfer_flags |= URB_ZERO_PACKET; @@ -421,11 +442,9 @@ tx_ret: return ret; } -static int __if_usb_submit_rx_urb(wlan_private * priv, - void (*callbackfn) - (struct urb *urb)) +static int __if_usb_submit_rx_urb(struct usb_card_rec *cardp, + void (*callbackfn)(struct urb *urb)) { - struct usb_card_rec *cardp = priv->card; struct sk_buff *skb; struct read_cb_info *rinfo = &cardp->rinfo; int ret = -1; @@ -461,22 +480,21 @@ rx_ret: return ret; } -static inline int if_usb_submit_rx_urb_fwload(wlan_private * priv) +static int if_usb_submit_rx_urb_fwload(struct usb_card_rec *cardp) { - return __if_usb_submit_rx_urb(priv, &if_usb_receive_fwload); + return __if_usb_submit_rx_urb(cardp, &if_usb_receive_fwload); } -static inline int if_usb_submit_rx_urb(wlan_private * priv) +static int if_usb_submit_rx_urb(struct usb_card_rec *cardp) { - return __if_usb_submit_rx_urb(priv, &if_usb_receive); + return __if_usb_submit_rx_urb(cardp, &if_usb_receive); } static void if_usb_receive_fwload(struct urb *urb) { struct read_cb_info *rinfo = (struct read_cb_info *)urb->context; - wlan_private *priv = rinfo->priv; struct sk_buff *skb = rinfo->skb; - struct usb_card_rec *cardp = (struct usb_card_rec *)priv->card; + struct usb_card_rec *cardp = (struct usb_card_rec *)rinfo->cardp; struct fwsyncheader *syncfwheader; struct bootcmdrespStr bootcmdresp; @@ -492,7 +510,7 @@ static void if_usb_receive_fwload(struct urb *urb) sizeof(bootcmdresp)); if (le16_to_cpu(cardp->udev->descriptor.bcdDevice) < 0x3106) { kfree_skb(skb); - if_usb_submit_rx_urb_fwload(priv); + if_usb_submit_rx_urb_fwload(cardp); cardp->bootcmdresp = 1; lbs_deb_usbd(&cardp->udev->dev, "Received valid boot command response\n"); @@ -516,7 +534,7 @@ static void if_usb_receive_fwload(struct urb *urb) "Received valid boot command response\n"); } kfree_skb(skb); - if_usb_submit_rx_urb_fwload(priv); + if_usb_submit_rx_urb_fwload(cardp); return; } @@ -552,9 +570,9 @@ static void if_usb_receive_fwload(struct urb *urb) goto exit; } - if_prog_firmware(priv); + if_prog_firmware(cardp); - if_usb_submit_rx_urb_fwload(priv); + if_usb_submit_rx_urb_fwload(cardp); exit: kfree(syncfwheader); @@ -633,9 +651,9 @@ static inline void process_cmdrequest(int recvlength, u8 *recvbuff, static void if_usb_receive(struct urb *urb) { struct read_cb_info *rinfo = (struct read_cb_info *)urb->context; - wlan_private *priv = rinfo->priv; struct sk_buff *skb = rinfo->skb; - struct usb_card_rec *cardp = (struct usb_card_rec *)priv->card; + struct usb_card_rec *cardp = (struct usb_card_rec *) rinfo->cardp; + wlan_private * priv = cardp->priv; int recvlength = urb->actual_length; u8 *recvbuff = NULL; @@ -696,7 +714,7 @@ static void if_usb_receive(struct urb *urb) } setup_for_next: - if_usb_submit_rx_urb(priv); + if_usb_submit_rx_urb(cardp); rx_exit: lbs_deb_leave(LBS_DEB_USB); } @@ -731,7 +749,7 @@ static int if_usb_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 n memcpy((cardp->bulk_out_buffer + MESSAGE_HEADER_LEN), payload, nb); - return usb_tx_block(priv, cardp->bulk_out_buffer, + return usb_tx_block(cardp, cardp->bulk_out_buffer, nb + MESSAGE_HEADER_LEN); } @@ -751,46 +769,10 @@ static int if_usb_get_int_status(wlan_private * priv, u8 * ireg) static int if_usb_read_event_cause(wlan_private * priv) { struct usb_card_rec *cardp = priv->card; + priv->adapter->eventcause = cardp->usb_event_cause; /* Re-submit rx urb here to avoid event lost issue */ - if_usb_submit_rx_urb(priv); - return 0; -} - -static int if_usb_unregister_dev(wlan_private * priv) -{ - int ret = 0; - - /* Need to send a Reset command to device before USB resources freed - * and wlan_remove_card() called, then device can handle FW download - * again. - */ - if (priv) - libertas_reset_device(priv); - - return ret; -} - - -/** - * @brief This function register usb device and initialize parameter - * @param priv pointer to wlan_private - * @return 0 or -1 - */ -static int if_usb_register_dev(wlan_private * priv) -{ - struct usb_card_rec *cardp = (struct usb_card_rec *)priv->card; - - lbs_deb_enter(LBS_DEB_USB); - - cardp->priv = priv; - cardp->eth_dev = priv->dev; - priv->hotplug_device = &(cardp->udev->dev); - - lbs_deb_usbd(&cardp->udev->dev, "udev pointer is at %p\n", - cardp->udev); - - lbs_deb_leave(LBS_DEB_USB); + if_usb_submit_rx_urb(cardp); return 0; } @@ -800,10 +782,9 @@ static int if_usb_register_dev(wlan_private * priv) * 2:Boot from FW in EEPROM * @return 0 */ -static int if_usb_issue_boot_command(wlan_private *priv, int ivalue) +static int if_usb_issue_boot_command(struct usb_card_rec *cardp, int ivalue) { - struct usb_card_rec *cardp = priv->card; - struct bootcmdstr sbootcmd; + struct bootcmdstr sbootcmd; int i; /* Prepare command */ @@ -814,28 +795,83 @@ static int if_usb_issue_boot_command(wlan_private *priv, int ivalue) memcpy(cardp->bulk_out_buffer, &sbootcmd, sizeof(struct bootcmdstr)); /* Issue command */ - usb_tx_block(priv, cardp->bulk_out_buffer, sizeof(struct bootcmdstr)); + usb_tx_block(cardp, cardp->bulk_out_buffer, sizeof(struct bootcmdstr)); return 0; } -static int if_usb_do_prog_firmware(wlan_private * priv) +/** + * @brief This function checks the validity of Boot2/FW image. + * + * @param data pointer to image + * len image length + * @return 0 or -1 + */ +static int check_fwfile_format(u8 *data, u32 totlen) +{ + u32 bincmd, exit; + u32 blksize, offset, len; + int ret; + + ret = 1; + exit = len = 0; + + do { + struct fwheader *fwh = (void *)data; + + bincmd = le32_to_cpu(fwh->dnldcmd); + blksize = le32_to_cpu(fwh->datalength); + switch (bincmd) { + case FW_HAS_DATA_TO_RECV: + offset = sizeof(struct fwheader) + blksize; + data += offset; + len += offset; + if (len >= totlen) + exit = 1; + break; + case FW_HAS_LAST_BLOCK: + exit = 1; + ret = 0; + break; + default: + exit = 1; + break; + } + } while (!exit); + + if (ret) + lbs_pr_err("firmware file format check FAIL\n"); + else + lbs_deb_fw("firmware file format check PASS\n"); + + return ret; +} + + +static int if_usb_prog_firmware(struct usb_card_rec *cardp) { - struct usb_card_rec *cardp = priv->card; int i = 0; static int reset_count = 10; int ret = 0; lbs_deb_enter(LBS_DEB_USB); - cardp->rinfo.priv = priv; + if ((ret = request_firmware(&cardp->fw, libertas_fw_name, + &cardp->udev->dev)) < 0) { + lbs_pr_err("request_firmware() failed with %#x\n", ret); + lbs_pr_err("firmware %s not found\n", libertas_fw_name); + goto done; + } + + if (check_fwfile_format(cardp->fw->data, cardp->fw->size)) + goto release_fw; restart: - if (if_usb_submit_rx_urb_fwload(priv) < 0) { + if (if_usb_submit_rx_urb_fwload(cardp) < 0) { lbs_deb_usbd(&cardp->udev->dev, "URB submission is failed\n"); ret = -1; - goto done; + goto release_fw; } cardp->bootcmdresp = 0; @@ -843,7 +879,7 @@ restart: int j = 0; i++; /* Issue Boot command = 1, Boot from Download-FW */ - if_usb_issue_boot_command(priv, BOOT_CMD_FW_BY_USB); + if_usb_issue_boot_command(cardp, BOOT_CMD_FW_BY_USB); /* wait for command response */ do { j++; @@ -853,14 +889,13 @@ restart: if (cardp->bootcmdresp == 0) { if (--reset_count >= 0) { - if_usb_reset_device(priv); + if_usb_reset_device(cardp); goto restart; } return -1; } i = 0; - priv->adapter->fw_ready = 0; cardp->totalbytes = 0; cardp->fwlastblksent = 0; @@ -870,113 +905,37 @@ restart: cardp->totalbytes = 0; cardp->fwfinalblk = 0; - if_prog_firmware(priv); + if_prog_firmware(cardp); do { lbs_deb_usbd(&cardp->udev->dev,"Wlan sched timeout\n"); i++; msleep_interruptible(100); - if (priv->adapter->surpriseremoved || i >= 20) + if (cardp->surprise_removed || i >= 20) break; } while (!cardp->fwdnldover); if (!cardp->fwdnldover) { lbs_pr_info("failed to load fw, resetting device!\n"); if (--reset_count >= 0) { - if_usb_reset_device(priv); + if_usb_reset_device(cardp); goto restart; } lbs_pr_info("FW download failure, time = %d ms\n", i * 100); ret = -1; - goto done; + goto release_fw; } - if_usb_submit_rx_urb(priv); - - /* Delay 200 ms to waiting for the FW ready */ - msleep_interruptible(200); - - priv->adapter->fw_ready = 1; +release_fw: + release_firmware(cardp->fw); + cardp->fw = NULL; done: lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret); return ret; } -/** - * @brief This function checks the validity of Boot2/FW image. - * - * @param data pointer to image - * len image length - * @return 0 or -1 - */ -static int check_fwfile_format(u8 *data, u32 totlen) -{ - u32 bincmd, exit; - u32 blksize, offset, len; - int ret; - - ret = 1; - exit = len = 0; - - do { - struct fwheader *fwh = (void *)data; - - bincmd = le32_to_cpu(fwh->dnldcmd); - blksize = le32_to_cpu(fwh->datalength); - switch (bincmd) { - case FW_HAS_DATA_TO_RECV: - offset = sizeof(struct fwheader) + blksize; - data += offset; - len += offset; - if (len >= totlen) - exit = 1; - break; - case FW_HAS_LAST_BLOCK: - exit = 1; - ret = 0; - break; - default: - exit = 1; - break; - } - } while (!exit); - - if (ret) - lbs_pr_err("firmware file format check FAIL\n"); - else - lbs_deb_fw("firmware file format check PASS\n"); - - return ret; -} - - -static int if_usb_prog_firmware(wlan_private *priv) -{ - int ret = -1; - - lbs_deb_enter(LBS_DEB_FW); - - if ((ret = request_firmware(&priv->firmware, libertas_fw_name, - priv->hotplug_device)) < 0) { - lbs_pr_err("request_firmware() failed with %#x\n", ret); - lbs_pr_err("firmware %s not found\n", libertas_fw_name); - goto done; - } - - if (check_fwfile_format(priv->firmware->data, priv->firmware->size)) { - release_firmware(priv->firmware); - goto done; - } - - ret = if_usb_do_prog_firmware(priv); - - release_firmware(priv->firmware); -done: - return ret; -} - #ifdef CONFIG_PM static int if_usb_suspend(struct usb_interface *intf, pm_message_t message) diff --git a/drivers/net/wireless/libertas/if_usb.h b/drivers/net/wireless/libertas/if_usb.h index 8b3b4f1e47f..e07a10ed28b 100644 --- a/drivers/net/wireless/libertas/if_usb.h +++ b/drivers/net/wireless/libertas/if_usb.h @@ -38,7 +38,7 @@ struct bootcmdrespStr /* read callback private data */ struct read_cb_info { - wlan_private *priv; + struct usb_card_rec *cardp; struct sk_buff *skb; }; @@ -58,6 +58,7 @@ struct usb_card_rec { int bulk_out_size; u8 bulk_out_endpointAddr; + const struct firmware *fw; u8 CRC_OK; u32 fwseqnum; u32 lastseqnum; @@ -65,6 +66,7 @@ struct usb_card_rec { u32 fwlastblksent; u8 fwdnldover; u8 fwfinalblk; + u8 surprise_removed; u32 usb_event_cause; u8 usb_int_cause; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index ce1c18ee628..6304bd97d39 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -791,7 +791,6 @@ static int libertas_thread(void *data) } else spin_unlock_irq(&adapter->driver_lock); - lbs_deb_thread( "main-thread 222 (waking up): intcounter=%d currenttxskb=%p " "dnld_sent=%d\n", adapter->intcounter, @@ -926,7 +925,7 @@ static int libertas_thread(void *data) * @param priv A pointer to wlan_private structure * @return 0 or -1 */ -static int wlan_setup_station_hw(wlan_private * priv) +static int wlan_setup_firmware(wlan_private * priv) { int ret = -1; wlan_adapter *adapter = priv->adapter; @@ -934,14 +933,6 @@ static int wlan_setup_station_hw(wlan_private * priv) lbs_deb_enter(LBS_DEB_FW); - ret = priv->hw_prog_firmware(priv); - - if (ret) { - lbs_deb_fw("bootloader in invalid state\n"); - ret = -1; - goto done; - } - /* * Read MAC address from HW */ @@ -992,8 +983,6 @@ done: return ret; } -static void command_timer_fn(unsigned long data); - /** * This function handles the timeout of command sending. * It will re-send the same command again. @@ -1035,155 +1024,99 @@ static void command_timer_fn(unsigned long data) return; } -static void libertas_free_adapter(wlan_private * priv) +static int libertas_init_adapter(wlan_private * priv) { wlan_adapter *adapter = priv->adapter; - - if (!adapter) { - lbs_deb_fw("why double free adapter?\n"); - return; - } - - lbs_deb_fw("free command buffer\n"); - libertas_free_cmd_buffer(priv); - - lbs_deb_fw("free command_timer\n"); - del_timer(&adapter->command_timer); - - lbs_deb_fw("free scan results table\n"); - kfree(adapter->networks); - adapter->networks = NULL; - - /* Free the adapter object itself */ - lbs_deb_fw("free adapter\n"); - kfree(adapter); - priv->adapter = NULL; -} - -static int wlan_allocate_adapter(wlan_private * priv) -{ size_t bufsize; - wlan_adapter *adapter = priv->adapter; + int i, ret = 0; /* Allocate buffer to store the BSSID list */ bufsize = MAX_NETWORK_COUNT * sizeof(struct bss_descriptor); adapter->networks = kzalloc(bufsize, GFP_KERNEL); if (!adapter->networks) { lbs_pr_err("Out of memory allocating beacons\n"); - libertas_free_adapter(priv); - return -ENOMEM; + ret = -1; + goto out; } - /* Allocate the command buffers */ - libertas_allocate_cmd_buffer(priv); + /* Initialize scan result lists */ + INIT_LIST_HEAD(&adapter->network_free_list); + INIT_LIST_HEAD(&adapter->network_list); + for (i = 0; i < MAX_NETWORK_COUNT; i++) { + list_add_tail(&adapter->networks[i].list, + &adapter->network_free_list); + } - memset(&adapter->libertas_ps_confirm_sleep, 0, sizeof(struct PS_CMD_ConfirmSleep)); adapter->libertas_ps_confirm_sleep.seqnum = cpu_to_le16(++adapter->seqnum); adapter->libertas_ps_confirm_sleep.command = cpu_to_le16(CMD_802_11_PS_MODE); adapter->libertas_ps_confirm_sleep.size = cpu_to_le16(sizeof(struct PS_CMD_ConfirmSleep)); - adapter->libertas_ps_confirm_sleep.result = 0; adapter->libertas_ps_confirm_sleep.action = cpu_to_le16(CMD_SUBCMD_SLEEP_CONFIRMED); - return 0; -} - -static void wlan_init_adapter(wlan_private * priv) -{ - wlan_adapter *adapter = priv->adapter; - int i; - - adapter->connect_status = LIBERTAS_DISCONNECTED; memset(adapter->current_addr, 0xff, ETH_ALEN); - /* 802.11 specific */ - adapter->secinfo.wep_enabled = 0; - for (i = 0; i < sizeof(adapter->wep_keys) / sizeof(adapter->wep_keys[0]); - i++) - memset(&adapter->wep_keys[i], 0, sizeof(struct enc_key)); - adapter->wep_tx_keyidx = 0; + adapter->connect_status = LIBERTAS_DISCONNECTED; adapter->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; adapter->mode = IW_MODE_INFRA; - - adapter->pending_assoc_req = NULL; - adapter->in_progress_assoc_req = NULL; - - /* Initialize scan result lists */ - INIT_LIST_HEAD(&adapter->network_free_list); - INIT_LIST_HEAD(&adapter->network_list); - for (i = 0; i < MAX_NETWORK_COUNT; i++) { - list_add_tail(&adapter->networks[i].list, - &adapter->network_free_list); - } - - mutex_init(&adapter->lock); - - memset(&adapter->curbssparams, 0, sizeof(adapter->curbssparams)); adapter->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL; - - /* PnP and power profile */ - adapter->surpriseremoved = 0; - - adapter->currentpacketfilter = - CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON; - + adapter->currentpacketfilter = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON; adapter->radioon = RADIO_ON; - adapter->auto_rate = 1; - adapter->cur_rate = 0; - - // set default capabilities adapter->capability = WLAN_CAPABILITY_SHORT_PREAMBLE; - adapter->psmode = WLAN802_11POWERMODECAM; - adapter->psstate = PS_STATE_FULL_POWER; - adapter->needtowakeup = 0; - adapter->intcounter = 0; - - adapter->currenttxskb = NULL; + mutex_init(&adapter->lock); memset(&adapter->tx_queue_ps, 0, NR_TX_QUEUE*sizeof(struct sk_buff*)); adapter->tx_queue_idx = 0; spin_lock_init(&adapter->txqueue_lock); - return; -} + setup_timer(&adapter->command_timer, command_timer_fn, + (unsigned long)priv); -static int libertas_init_fw(wlan_private * priv) -{ - int ret = -1; - wlan_adapter *adapter = priv->adapter; + INIT_LIST_HEAD(&adapter->cmdfreeq); + INIT_LIST_HEAD(&adapter->cmdpendingq); - lbs_deb_enter(LBS_DEB_FW); + spin_lock_init(&adapter->driver_lock); + init_waitqueue_head(&adapter->cmd_pending); + adapter->nr_cmd_pending = 0; - /* Allocate adapter structure */ - if ((ret = wlan_allocate_adapter(priv)) != 0) - goto done; + /* Allocate the command buffers */ + if (libertas_allocate_cmd_buffer(priv)) { + lbs_pr_err("Out of memory allocating command buffers\n"); + ret = -1; + } - /* init adapter structure */ - wlan_init_adapter(priv); +out: + return ret; +} - /* init timer etc. */ - setup_timer(&adapter->command_timer, command_timer_fn, - (unsigned long)priv); +static void libertas_free_adapter(wlan_private * priv) +{ + wlan_adapter *adapter = priv->adapter; - /* download fimrware etc. */ - if ((ret = wlan_setup_station_hw(priv)) != 0) { - del_timer_sync(&adapter->command_timer); - goto done; + if (!adapter) { + lbs_deb_fw("why double free adapter?\n"); + return; } - /* init 802.11d */ - libertas_init_11d(priv); + lbs_deb_fw("free command buffer\n"); + libertas_free_cmd_buffer(priv); - ret = 0; -done: - lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret); - return ret; + lbs_deb_fw("free command_timer\n"); + del_timer(&adapter->command_timer); + + lbs_deb_fw("free scan results table\n"); + kfree(adapter->networks); + adapter->networks = NULL; + + /* Free the adapter object itself */ + lbs_deb_fw("free adapter\n"); + kfree(adapter); + priv->adapter = NULL; } /** @@ -1203,9 +1136,9 @@ wlan_private *libertas_add_card(void *card, struct device *dmdev) /* Allocate an Ethernet device and register it */ if (!(dev = alloc_etherdev(sizeof(wlan_private)))) { lbs_pr_err("init ethX device failed\n"); - return NULL; + goto done; } - priv = dev->priv; + dmdev->driver_data = priv = dev->priv; /* allocate buffer for wlan_adapter */ if (!(priv->adapter = kzalloc(sizeof(wlan_adapter), GFP_KERNEL))) { @@ -1213,10 +1146,16 @@ wlan_private *libertas_add_card(void *card, struct device *dmdev) goto err_kzalloc; } + if (libertas_init_adapter(priv)) { + lbs_pr_err("failed to initialize adapter structure.\n"); + goto err_init_adapter; + } + priv->dev = dev; priv->card = card; priv->mesh_open = 0; priv->infra_open = 0; + priv->hotplug_device = dmdev; SET_MODULE_OWNER(dev); @@ -1239,87 +1178,144 @@ wlan_private *libertas_add_card(void *card, struct device *dmdev) SET_NETDEV_DEV(dev, dmdev); - INIT_LIST_HEAD(&priv->adapter->cmdfreeq); - INIT_LIST_HEAD(&priv->adapter->cmdpendingq); - - spin_lock_init(&priv->adapter->driver_lock); - init_waitqueue_head(&priv->adapter->cmd_pending); - priv->adapter->nr_cmd_pending = 0; priv->rtap_net_dev = NULL; if (device_create_file(dmdev, &dev_attr_libertas_rtap)) - goto err_kzalloc; + goto err_init_adapter; + + lbs_deb_thread("Starting main thread...\n"); + init_waitqueue_head(&priv->waitq); + priv->main_thread = kthread_run(libertas_thread, dev, "libertas_main"); + if (IS_ERR(priv->main_thread)) { + lbs_deb_thread("Error creating main thread.\n"); + goto err_kthread_run; + } + + priv->work_thread = create_singlethread_workqueue("libertas_worker"); + INIT_DELAYED_WORK(&priv->assoc_work, libertas_association_worker); + INIT_DELAYED_WORK(&priv->scan_work, libertas_scan_worker); + INIT_WORK(&priv->sync_channel, libertas_sync_channel); + goto done; +err_kthread_run: + device_remove_file(dmdev, &dev_attr_libertas_rtap); + +err_init_adapter: + libertas_free_adapter(priv); + err_kzalloc: free_netdev(dev); priv = NULL; + done: lbs_deb_leave_args(LBS_DEB_NET, "priv %p", priv); return priv; } EXPORT_SYMBOL_GPL(libertas_add_card); -int libertas_activate_card(wlan_private *priv) + +int libertas_remove_card(wlan_private *priv) { + wlan_adapter *adapter = priv->adapter; struct net_device *dev = priv->dev; - int ret = -1; + union iwreq_data wrqu; lbs_deb_enter(LBS_DEB_MAIN); - lbs_deb_thread("Starting main thread...\n"); - init_waitqueue_head(&priv->waitq); - priv->main_thread = kthread_run(libertas_thread, dev, "libertas_main"); - if (IS_ERR(priv->main_thread)) { - lbs_deb_thread("Error creating main thread.\n"); - goto done; - } + libertas_remove_rtap(priv); - priv->work_thread = create_singlethread_workqueue("libertas_worker"); - INIT_DELAYED_WORK(&priv->assoc_work, libertas_association_worker); - INIT_DELAYED_WORK(&priv->scan_work, libertas_scan_worker); + dev = priv->dev; + device_remove_file(priv->hotplug_device, &dev_attr_libertas_rtap); - INIT_WORK(&priv->sync_channel, libertas_sync_channel); + cancel_delayed_work(&priv->scan_work); + cancel_delayed_work(&priv->assoc_work); + destroy_workqueue(priv->work_thread); - /* - * Register the device. Fillup the private data structure with - * relevant information from the card and request for the required - * IRQ. - */ - if (priv->hw_register_dev(priv) < 0) { - lbs_pr_err("failed to register WLAN device\n"); - goto err_registerdev; + if (adapter->psmode == WLAN802_11POWERMODEMAX_PSP) { + adapter->psmode = WLAN802_11POWERMODECAM; + libertas_ps_wakeup(priv, CMD_OPTION_WAITFORRSP); } - /* init FW and HW */ - if (libertas_init_fw(priv)) { - lbs_pr_err("firmware init failed\n"); - goto err_registerdev; - } + memset(wrqu.ap_addr.sa_data, 0xaa, ETH_ALEN); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); + + /* Stop the thread servicing the interrupts */ + adapter->surpriseremoved = 1; + kthread_stop(priv->main_thread); + + libertas_free_adapter(priv); + + priv->dev = NULL; + free_netdev(dev); + + lbs_deb_leave(LBS_DEB_MAIN); + return 0; +} +EXPORT_SYMBOL_GPL(libertas_remove_card); + + +int libertas_start_card(wlan_private *priv) +{ + struct net_device *dev = priv->dev; + int ret = -1; + + lbs_deb_enter(LBS_DEB_MAIN); + + /* poke the firmware */ + ret = wlan_setup_firmware(priv); + if (ret) + goto done; + + /* init 802.11d */ + libertas_init_11d(priv); if (register_netdev(dev)) { lbs_pr_err("cannot register ethX device\n"); - goto err_init_fw; + goto done; } - lbs_pr_info("%s: Marvell WLAN 802.11 adapter\n", dev->name); - libertas_debugfs_init_one(priv, dev); + lbs_pr_info("%s: Marvell WLAN 802.11 adapter\n", dev->name); + ret = 0; - goto done; -err_init_fw: - priv->hw_unregister_dev(priv); -err_registerdev: - destroy_workqueue(priv->work_thread); - /* Stop the thread servicing the interrupts */ - wake_up_interruptible(&priv->waitq); - kthread_stop(priv->main_thread); done: - lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret); + lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret); return ret; } -EXPORT_SYMBOL_GPL(libertas_activate_card); +EXPORT_SYMBOL_GPL(libertas_start_card); + + +int libertas_stop_card(wlan_private *priv) +{ + struct net_device *dev = priv->dev; + int ret = -1; + struct cmd_ctrl_node *cmdnode; + unsigned long flags; + + lbs_deb_enter(LBS_DEB_MAIN); + + netif_stop_queue(priv->dev); + netif_carrier_off(priv->dev); + + libertas_debugfs_remove_one(priv); + + /* Flush pending command nodes */ + spin_lock_irqsave(&priv->adapter->driver_lock, flags); + list_for_each_entry(cmdnode, &priv->adapter->cmdpendingq, list) { + cmdnode->cmdwaitqwoken = 1; + wake_up_interruptible(&cmdnode->cmdwait_q); + } + spin_unlock_irqrestore(&priv->adapter->driver_lock, flags); + + unregister_netdev(dev); + + lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret); + return ret; +} +EXPORT_SYMBOL_GPL(libertas_stop_card); /** @@ -1389,89 +1385,12 @@ done: } EXPORT_SYMBOL_GPL(libertas_add_mesh); -static void wake_pending_cmdnodes(wlan_private *priv) -{ - struct cmd_ctrl_node *cmdnode; - unsigned long flags; - - lbs_deb_enter(LBS_DEB_HOST); - - spin_lock_irqsave(&priv->adapter->driver_lock, flags); - list_for_each_entry(cmdnode, &priv->adapter->cmdpendingq, list) { - cmdnode->cmdwaitqwoken = 1; - wake_up_interruptible(&cmdnode->cmdwait_q); - } - spin_unlock_irqrestore(&priv->adapter->driver_lock, flags); -} - - -int libertas_remove_card(wlan_private *priv) -{ - wlan_adapter *adapter; - struct net_device *dev; - union iwreq_data wrqu; - - lbs_deb_enter(LBS_DEB_NET); - - libertas_remove_rtap(priv); - if (!priv) - goto out; - - adapter = priv->adapter; - - if (!adapter) - goto out; - - dev = priv->dev; - device_remove_file(priv->hotplug_device, &dev_attr_libertas_rtap); - - netif_stop_queue(priv->dev); - netif_carrier_off(priv->dev); - - wake_pending_cmdnodes(priv); - - unregister_netdev(dev); - - cancel_delayed_work(&priv->scan_work); - cancel_delayed_work(&priv->assoc_work); - destroy_workqueue(priv->work_thread); - - if (adapter->psmode == WLAN802_11POWERMODEMAX_PSP) { - adapter->psmode = WLAN802_11POWERMODECAM; - libertas_ps_wakeup(priv, CMD_OPTION_WAITFORRSP); - } - - memset(wrqu.ap_addr.sa_data, 0xaa, ETH_ALEN); - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); - - adapter->surpriseremoved = 1; - - /* Stop the thread servicing the interrupts */ - kthread_stop(priv->main_thread); - - libertas_debugfs_remove_one(priv); - - lbs_deb_net("free adapter\n"); - libertas_free_adapter(priv); - - lbs_deb_net("unregister finish\n"); - - priv->dev = NULL; - free_netdev(dev); - -out: - lbs_deb_leave(LBS_DEB_NET); - return 0; -} -EXPORT_SYMBOL_GPL(libertas_remove_card); - void libertas_remove_mesh(wlan_private *priv) { struct net_device *mesh_dev; - lbs_deb_enter(LBS_DEB_NET); + lbs_deb_enter(LBS_DEB_MAIN); if (!priv) goto out; @@ -1488,7 +1407,7 @@ void libertas_remove_mesh(wlan_private *priv) free_netdev(mesh_dev); out: - lbs_deb_leave(LBS_DEB_NET); + lbs_deb_leave(LBS_DEB_MAIN); } EXPORT_SYMBOL_GPL(libertas_remove_mesh); -- cgit v1.2.3-70-g09d2 From 64f104e89b2b30107a21c5f05c3e2ffa6291e129 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 20 Aug 2007 11:45:16 -0400 Subject: [PATCH] libertas: don't stomp on interface-specific private data Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 6304bd97d39..3feddcc750e 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -256,7 +256,7 @@ void libertas_remove_rtap(wlan_private *priv); static ssize_t libertas_rtap_get(struct device * dev, struct device_attribute *attr, char * buf) { - wlan_private *priv = (wlan_private *) dev->driver_data; + wlan_private *priv = (wlan_private *) (to_net_dev(dev))->priv; wlan_adapter *adapter = priv->adapter; return snprintf(buf, 5, "0x%X\n", adapter->monitormode); } @@ -268,7 +268,7 @@ static ssize_t libertas_rtap_set(struct device * dev, struct device_attribute *attr, const char * buf, size_t count) { int monitor_mode; - wlan_private *priv = (wlan_private *) dev->driver_data; + wlan_private *priv = (wlan_private *) (to_net_dev(dev))->priv; wlan_adapter *adapter = priv->adapter; sscanf(buf, "%x", &monitor_mode); @@ -1138,7 +1138,7 @@ wlan_private *libertas_add_card(void *card, struct device *dmdev) lbs_pr_err("init ethX device failed\n"); goto done; } - dmdev->driver_data = priv = dev->priv; + priv = dev->priv; /* allocate buffer for wlan_adapter */ if (!(priv->adapter = kzalloc(sizeof(wlan_adapter), GFP_KERNEL))) { -- cgit v1.2.3-70-g09d2 From b6e99dd6e2c5262e3c2b976d1d5f2c9405433d9a Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 20 Aug 2007 12:22:15 -0400 Subject: [PATCH] libertas: send reset command directly instead of calling libertas_reset_device Ensures that any platform specific code that might live in libertas_reset_device (for example, OLPC tells the EC to do a GPIO-toggled reset of the wireless from libertas_reset_device) isn't called. Could be handled better by interface-specific callbacks and a flag for "other hardware reset". Signed-off-by: Dan Williams Signed-off-by: Marcelo Tosatti Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/if_usb.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index 105a00a7025..8a3c70e5407 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -1044,8 +1044,10 @@ static void if_usb_exit_module(void) lbs_deb_enter(LBS_DEB_MAIN); - list_for_each_entry_safe(cardp, cardp_temp, &usb_devices, list) - libertas_reset_device((wlan_private *) cardp->priv); + list_for_each_entry_safe(cardp, cardp_temp, &usb_devices, list) { + libertas_prepare_and_send_command(cardp->priv, CMD_802_11_RESET, + CMD_ACT_HALT, 0, 0, NULL); + } /* API unregisters the driver from USB subsystem */ usb_deregister(&if_usb_driver); -- cgit v1.2.3-70-g09d2 From 794760f750655d987499d7a5034519afc84af63b Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 20 Aug 2007 12:24:42 -0400 Subject: [PATCH] libertas: properly end commands on hardware failure Make sure that errors reported by the hardware layer is properly handled. Otherwise commands tend to get stuck in limbo. Signed-off-by: Pierre Ossman Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 98092b99535..33dbed09fc7 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -1009,7 +1009,9 @@ static int DownloadcommandToStation(wlan_private * priv, if (ret != 0) { lbs_deb_host("DNLD_CMD: hw_host_to_card failed\n"); spin_lock_irqsave(&adapter->driver_lock, flags); + adapter->cur_cmd_retcode = ret; __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd); + adapter->nr_cmd_pending--; adapter->cur_cmd = NULL; spin_unlock_irqrestore(&adapter->driver_lock, flags); goto done; -- cgit v1.2.3-70-g09d2 From 70500f5443be1b27ea2c9ab71ce9dc2250af7b19 Mon Sep 17 00:00:00 2001 From: Marek VaÅ¡ut Date: Mon, 20 Aug 2007 12:55:41 -0400 Subject: [PATCH] libertas: region code values specified as 8bit This patch strips away possible mess in regioncode (eg. on my card - 88W8305 chipset - I get 0x3031 instead of expected 0x0031 and as a result the driver defaults to USA region which is obviously incorrect). Following patch fixes the issue. Signed-off-by: Marek Vasut Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmdresp.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 4c36e63ae7b..d64ad87db45 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -174,7 +174,11 @@ static int wlan_ret_get_hw_spec(wlan_private * priv, lbs_deb_cmd("GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x\n", hwspec->hwifversion, hwspec->version); - adapter->regioncode = le16_to_cpu(hwspec->regioncode); + /* Clamp region code to 8-bit since FW spec indicates that it should + * only ever be 8-bit, even though the field size is 16-bit. Some firmware + * returns non-zero high 8 bits here. + */ + adapter->regioncode = le16_to_cpu(hwspec->regioncode) & 0xFF; for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) { /* use the region code to search for the index */ -- cgit v1.2.3-70-g09d2 From 4b04f19625dcf43171b0b8d53be050a8f144c43d Mon Sep 17 00:00:00 2001 From: Brajesh Dave Date: Mon, 20 Aug 2007 13:09:13 -0400 Subject: [PATCH] libertas: advertise 11g ad-hoc rates Advertise support for 802.11g bitrates when starting adhoc networks, not just 802.11b bitrates. Signed-off-by: Brajesh Dave Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/join.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c index ce49d3f2561..72f81208bf2 100644 --- a/drivers/net/wireless/libertas/join.c +++ b/drivers/net/wireless/libertas/join.c @@ -550,8 +550,8 @@ int libertas_cmd_80211_ad_hoc_start(wlan_private * priv, adhs->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME); memset(adhs->rates, 0, sizeof(adhs->rates)); - ratesize = min(sizeof(adhs->rates), sizeof(adhoc_rates_b)); - memcpy(adhs->rates, adhoc_rates_b, ratesize); + ratesize = min(sizeof(adhs->rates), sizeof(libertas_bg_rates)); + memcpy(adhs->rates, libertas_bg_rates, ratesize); /* Copy the ad-hoc creating rates into Current BSS state structure */ memset(&adapter->curbssparams.rates, 0, sizeof(adapter->curbssparams.rates)); -- cgit v1.2.3-70-g09d2 From 655b4d16ac5e551e5c8dac5812156edfd87bf822 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Fri, 24 Aug 2007 11:48:16 -0400 Subject: [PATCH] net: Kill some unneeded allocation return value casts in libertas kmalloc() and friends return void*, no need to cast it. Signed-off-by: Jesper Juhl Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/debugfs.c | 2 +- drivers/net/wireless/libertas/ethtool.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c index 6d95148e872..816f42e4f5b 100644 --- a/drivers/net/wireless/libertas/debugfs.c +++ b/drivers/net/wireless/libertas/debugfs.c @@ -1838,7 +1838,7 @@ static ssize_t wlan_debugfs_write(struct file *f, const char __user *buf, char *p2; struct debug_data *d = (struct debug_data *)f->private_data; - pdata = (char *)kmalloc(cnt, GFP_KERNEL); + pdata = kmalloc(cnt, GFP_KERNEL); if (pdata == NULL) return 0; diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c index ec99cb82587..d793d843f7d 100644 --- a/drivers/net/wireless/libertas/ethtool.c +++ b/drivers/net/wireless/libertas/ethtool.c @@ -60,8 +60,7 @@ static int libertas_ethtool_get_eeprom(struct net_device *dev, // mutex_lock(&priv->mutex); - adapter->prdeeprom = - (char *)kmalloc(eeprom->len+sizeof(regctrl), GFP_KERNEL); + adapter->prdeeprom = kmalloc(eeprom->len+sizeof(regctrl), GFP_KERNEL); if (!adapter->prdeeprom) return -ENOMEM; memcpy(adapter->prdeeprom, ®ctrl, sizeof(regctrl)); -- cgit v1.2.3-70-g09d2 From 4ecd41bd0ff5dfcb4f2c59d980f9196c160882be Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 21 Aug 2007 02:15:45 -0700 Subject: [PATCH] libertas: printk warning fixes drivers/net/wireless/libertas/if_cs.c: In function 'if_cs_prog_helper': drivers/net/wireless/libertas/if_cs.c:462: warning: format '%d' expects type 'int', but argument 3 has type 'size_t' drivers/net/wireless/libertas/if_cs.c: In function 'if_cs_prog_real': drivers/net/wireless/libertas/if_cs.c:538: warning: format '%d' expects type 'int', but argument 3 has type 'size_t' Signed-off-by: Andrew Morton Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/if_cs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c index 4dffc5cc0d1..09c87df5c2f 100644 --- a/drivers/net/wireless/libertas/if_cs.c +++ b/drivers/net/wireless/libertas/if_cs.c @@ -459,7 +459,7 @@ static int if_cs_prog_helper(struct if_cs_card *card) ret = -ENODEV; goto done; } - lbs_deb_cs("helper size %d\n", fw->size); + lbs_deb_cs("helper size %td\n", fw->size); /* "Set the 5 bytes of the helper image to 0" */ /* Not needed, this contains an ARM branch instruction */ @@ -535,7 +535,7 @@ static int if_cs_prog_real(struct if_cs_card *card) ret = -ENODEV; goto done; } - lbs_deb_cs("fw size %d\n", fw->size); + lbs_deb_cs("fw size %td\n", fw->size); ret = if_cs_poll_while_fw_download(card, IF_CS_C_SQ_READ_LOW, IF_CS_C_SQ_HELPER_OK); if (ret < 0) { -- cgit v1.2.3-70-g09d2 From cbdb9e43d1fc50cfa509b1006e7252dc4ea53aa0 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 28 Aug 2007 17:35:02 -0400 Subject: [PATCH] libertas: remove unused adhoc_rates_b definition Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/join.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c index 72f81208bf2..0ad1362b14e 100644 --- a/drivers/net/wireless/libertas/join.c +++ b/drivers/net/wireless/libertas/join.c @@ -17,9 +17,6 @@ #include "dev.h" #include "assoc.h" -/* Supported rates for ad-hoc B mode */ -static u8 adhoc_rates_b[5] = { 0x02, 0x04, 0x0b, 0x16, 0x00 }; - /* The firmware needs certain bits masked out of the beacon-derviced capability * field when associating/joining to BSSs. */ -- cgit v1.2.3-70-g09d2 From bc7f75fa97884d41efbfde1397b621fefb2550b4 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Mon, 17 Sep 2007 12:30:59 -0700 Subject: [E1000E]: New pci-express e1000 driver (currently for ICH9 devices only) This driver implements support for the ICH9 on-board LAN ethernet device. The device is similar to ICH8. The driver encompasses code to support 82571/2/3, es2lan and ICH8 devices as well, but those device IDs are disabled and will be "lifted" from the e1000 driver over one at a time once this driver receives some more live time. Changes to the last snapshot posted are exclusively in the internal hardware API organization. Many thanks to Jeff Garzik for jumping in and getting this organized with a keen eye on the future layout. [ Integrated napi_struct patch from Auke as well... -DaveM ] Signed-off-by: Auke Kok Signed-off-by: Jeff Garzik Signed-off-by: David S. Miller --- drivers/net/Kconfig | 23 + drivers/net/Makefile | 1 + drivers/net/e1000e/82571.c | 1351 +++++++++++++ drivers/net/e1000e/Makefile | 37 + drivers/net/e1000e/defines.h | 739 +++++++ drivers/net/e1000e/e1000.h | 514 +++++ drivers/net/e1000e/es2lan.c | 1232 ++++++++++++ drivers/net/e1000e/ethtool.c | 1774 +++++++++++++++++ drivers/net/e1000e/hw.h | 864 ++++++++ drivers/net/e1000e/ich8lan.c | 2225 +++++++++++++++++++++ drivers/net/e1000e/lib.c | 2487 +++++++++++++++++++++++ drivers/net/e1000e/netdev.c | 4441 ++++++++++++++++++++++++++++++++++++++++++ drivers/net/e1000e/param.c | 382 ++++ drivers/net/e1000e/phy.c | 1773 +++++++++++++++++ 14 files changed, 17843 insertions(+) create mode 100644 drivers/net/e1000e/82571.c create mode 100644 drivers/net/e1000e/Makefile create mode 100644 drivers/net/e1000e/defines.h create mode 100644 drivers/net/e1000e/e1000.h create mode 100644 drivers/net/e1000e/es2lan.c create mode 100644 drivers/net/e1000e/ethtool.c create mode 100644 drivers/net/e1000e/hw.h create mode 100644 drivers/net/e1000e/ich8lan.c create mode 100644 drivers/net/e1000e/lib.c create mode 100644 drivers/net/e1000e/netdev.c create mode 100644 drivers/net/e1000e/param.c create mode 100644 drivers/net/e1000e/phy.c (limited to 'drivers') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 734f8403c80..502dd0eb880 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2055,6 +2055,29 @@ config E1000_DISABLE_PACKET_SPLIT If in doubt, say N. +config E1000E + tristate "Intel(R) PRO/1000 PCI-Express Gigabit Ethernet support" + depends on PCI + ---help--- + This driver supports the PCI-Express Intel(R) PRO/1000 gigabit + ethernet family of adapters. For PCI or PCI-X e1000 adapters, + use the regular e1000 driver For more information on how to + identify your adapter, go to the Adapter & Driver ID Guide at: + + + + For general information and support, go to the Intel support + website at: + + + + More specific information on configuring the driver is in + . + + To compile this driver as a module, choose M here and read + . The module + will be called e1000e. + source "drivers/net/ixp2000/Kconfig" config MYRI_SBUS diff --git a/drivers/net/Makefile b/drivers/net/Makefile index d6f7302ab72..0d2b4bee587 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -3,6 +3,7 @@ # obj-$(CONFIG_E1000) += e1000/ +obj-$(CONFIG_E1000E) += e1000e/ obj-$(CONFIG_IBM_EMAC) += ibm_emac/ obj-$(CONFIG_IXGB) += ixgb/ obj-$(CONFIG_CHELSIO_T1) += chelsio/ diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c new file mode 100644 index 00000000000..cf70522fc85 --- /dev/null +++ b/drivers/net/e1000e/82571.c @@ -0,0 +1,1351 @@ +/******************************************************************************* + + Intel PRO/1000 Linux driver + Copyright(c) 1999 - 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +/* + * 82571EB Gigabit Ethernet Controller + * 82571EB Gigabit Ethernet Controller (Fiber) + * 82572EI Gigabit Ethernet Controller (Copper) + * 82572EI Gigabit Ethernet Controller (Fiber) + * 82572EI Gigabit Ethernet Controller + * 82573V Gigabit Ethernet Controller (Copper) + * 82573E Gigabit Ethernet Controller (Copper) + * 82573L Gigabit Ethernet Controller + */ + +#include +#include +#include + +#include "e1000.h" + +#define ID_LED_RESERVED_F746 0xF746 +#define ID_LED_DEFAULT_82573 ((ID_LED_DEF1_DEF2 << 12) | \ + (ID_LED_OFF1_ON2 << 8) | \ + (ID_LED_DEF1_DEF2 << 4) | \ + (ID_LED_DEF1_DEF2)) + +#define E1000_GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000 + +static s32 e1000_get_phy_id_82571(struct e1000_hw *hw); +static s32 e1000_setup_copper_link_82571(struct e1000_hw *hw); +static s32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw); +static s32 e1000_write_nvm_eewr_82571(struct e1000_hw *hw, u16 offset, + u16 words, u16 *data); +static s32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw); +static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw); +static s32 e1000_setup_link_82571(struct e1000_hw *hw); +static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw); + +/** + * e1000_init_phy_params_82571 - Init PHY func ptrs. + * @hw: pointer to the HW structure + * + * This is a function pointer entry point called by the api module. + **/ +static s32 e1000_init_phy_params_82571(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + + if (hw->media_type != e1000_media_type_copper) { + phy->type = e1000_phy_none; + return 0; + } + + phy->addr = 1; + phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; + phy->reset_delay_us = 100; + + switch (hw->mac.type) { + case e1000_82571: + case e1000_82572: + phy->type = e1000_phy_igp_2; + break; + case e1000_82573: + phy->type = e1000_phy_m88; + break; + default: + return -E1000_ERR_PHY; + break; + } + + /* This can only be done after all function pointers are setup. */ + ret_val = e1000_get_phy_id_82571(hw); + + /* Verify phy id */ + switch (hw->mac.type) { + case e1000_82571: + case e1000_82572: + if (phy->id != IGP01E1000_I_PHY_ID) + return -E1000_ERR_PHY; + break; + case e1000_82573: + if (phy->id != M88E1111_I_PHY_ID) + return -E1000_ERR_PHY; + break; + default: + return -E1000_ERR_PHY; + break; + } + + return 0; +} + +/** + * e1000_init_nvm_params_82571 - Init NVM func ptrs. + * @hw: pointer to the HW structure + * + * This is a function pointer entry point called by the api module. + **/ +static s32 e1000_init_nvm_params_82571(struct e1000_hw *hw) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + u32 eecd = er32(EECD); + u16 size; + + nvm->opcode_bits = 8; + nvm->delay_usec = 1; + switch (nvm->override) { + case e1000_nvm_override_spi_large: + nvm->page_size = 32; + nvm->address_bits = 16; + break; + case e1000_nvm_override_spi_small: + nvm->page_size = 8; + nvm->address_bits = 8; + break; + default: + nvm->page_size = eecd & E1000_EECD_ADDR_BITS ? 32 : 8; + nvm->address_bits = eecd & E1000_EECD_ADDR_BITS ? 16 : 8; + break; + } + + switch (hw->mac.type) { + case e1000_82573: + if (((eecd >> 15) & 0x3) == 0x3) { + nvm->type = e1000_nvm_flash_hw; + nvm->word_size = 2048; + /* Autonomous Flash update bit must be cleared due + * to Flash update issue. + */ + eecd &= ~E1000_EECD_AUPDEN; + ew32(EECD, eecd); + break; + } + /* Fall Through */ + default: + nvm->type = e1000_nvm_eeprom_spi; + size = (u16)((eecd & E1000_EECD_SIZE_EX_MASK) >> + E1000_EECD_SIZE_EX_SHIFT); + /* Added to a constant, "size" becomes the left-shift value + * for setting word_size. + */ + size += NVM_WORD_SIZE_BASE_SHIFT; + nvm->word_size = 1 << size; + break; + } + + return 0; +} + +/** + * e1000_init_mac_params_82571 - Init MAC func ptrs. + * @hw: pointer to the HW structure + * + * This is a function pointer entry point called by the api module. + **/ +static s32 e1000_init_mac_params_82571(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + struct e1000_mac_info *mac = &hw->mac; + struct e1000_mac_operations *func = &mac->ops; + + /* Set media type */ + switch (adapter->pdev->device) { + case E1000_DEV_ID_82571EB_FIBER: + case E1000_DEV_ID_82572EI_FIBER: + case E1000_DEV_ID_82571EB_QUAD_FIBER: + hw->media_type = e1000_media_type_fiber; + break; + case E1000_DEV_ID_82571EB_SERDES: + case E1000_DEV_ID_82572EI_SERDES: + hw->media_type = e1000_media_type_internal_serdes; + break; + default: + hw->media_type = e1000_media_type_copper; + break; + } + + /* Set mta register count */ + mac->mta_reg_count = 128; + /* Set rar entry count */ + mac->rar_entry_count = E1000_RAR_ENTRIES; + /* Set if manageability features are enabled. */ + mac->arc_subsystem_valid = + (er32(FWSM) & E1000_FWSM_MODE_MASK) ? 1 : 0; + + /* check for link */ + switch (hw->media_type) { + case e1000_media_type_copper: + func->setup_physical_interface = e1000_setup_copper_link_82571; + func->check_for_link = e1000e_check_for_copper_link; + func->get_link_up_info = e1000e_get_speed_and_duplex_copper; + break; + case e1000_media_type_fiber: + func->setup_physical_interface = e1000_setup_fiber_serdes_link_82571; + func->check_for_link = e1000e_check_for_fiber_link; + func->get_link_up_info = e1000e_get_speed_and_duplex_fiber_serdes; + break; + case e1000_media_type_internal_serdes: + func->setup_physical_interface = e1000_setup_fiber_serdes_link_82571; + func->check_for_link = e1000e_check_for_serdes_link; + func->get_link_up_info = e1000e_get_speed_and_duplex_fiber_serdes; + break; + default: + return -E1000_ERR_CONFIG; + break; + } + + return 0; +} + +static s32 e1000_get_invariants_82571(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + static int global_quad_port_a; /* global port a indication */ + struct pci_dev *pdev = adapter->pdev; + u16 eeprom_data = 0; + int is_port_b = er32(STATUS) & E1000_STATUS_FUNC_1; + s32 rc; + + rc = e1000_init_mac_params_82571(adapter); + if (rc) + return rc; + + rc = e1000_init_nvm_params_82571(hw); + if (rc) + return rc; + + rc = e1000_init_phy_params_82571(hw); + if (rc) + return rc; + + /* tag quad port adapters first, it's used below */ + switch (pdev->device) { + case E1000_DEV_ID_82571EB_QUAD_COPPER: + case E1000_DEV_ID_82571EB_QUAD_FIBER: + case E1000_DEV_ID_82571EB_QUAD_COPPER_LP: + adapter->flags |= FLAG_IS_QUAD_PORT; + /* mark the first port */ + if (global_quad_port_a == 0) + adapter->flags |= FLAG_IS_QUAD_PORT_A; + /* Reset for multiple quad port adapters */ + global_quad_port_a++; + if (global_quad_port_a == 4) + global_quad_port_a = 0; + break; + default: + break; + } + + switch (adapter->hw.mac.type) { + case e1000_82571: + /* these dual ports don't have WoL on port B at all */ + if (((pdev->device == E1000_DEV_ID_82571EB_FIBER) || + (pdev->device == E1000_DEV_ID_82571EB_SERDES) || + (pdev->device == E1000_DEV_ID_82571EB_COPPER)) && + (is_port_b)) + adapter->flags &= ~FLAG_HAS_WOL; + /* quad ports only support WoL on port A */ + if (adapter->flags & FLAG_IS_QUAD_PORT && + (!adapter->flags & FLAG_IS_QUAD_PORT_A)) + adapter->flags &= ~FLAG_HAS_WOL; + break; + + case e1000_82573: + if (pdev->device == E1000_DEV_ID_82573L) { + e1000_read_nvm(&adapter->hw, NVM_INIT_3GIO_3, 1, + &eeprom_data); + if (eeprom_data & NVM_WORD1A_ASPM_MASK) + adapter->flags &= ~FLAG_HAS_JUMBO_FRAMES; + } + break; + default: + break; + } + + return 0; +} + +/** + * e1000_get_phy_id_82571 - Retrieve the PHY ID and revision + * @hw: pointer to the HW structure + * + * Reads the PHY registers and stores the PHY ID and possibly the PHY + * revision in the hardware structure. + **/ +static s32 e1000_get_phy_id_82571(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + + switch (hw->mac.type) { + case e1000_82571: + case e1000_82572: + /* The 82571 firmware may still be configuring the PHY. + * In this case, we cannot access the PHY until the + * configuration is done. So we explicitly set the + * PHY ID. */ + phy->id = IGP01E1000_I_PHY_ID; + break; + case e1000_82573: + return e1000e_get_phy_id(hw); + break; + default: + return -E1000_ERR_PHY; + break; + } + + return 0; +} + +/** + * e1000_get_hw_semaphore_82571 - Acquire hardware semaphore + * @hw: pointer to the HW structure + * + * Acquire the HW semaphore to access the PHY or NVM + **/ +static s32 e1000_get_hw_semaphore_82571(struct e1000_hw *hw) +{ + u32 swsm; + s32 timeout = hw->nvm.word_size + 1; + s32 i = 0; + + /* Get the FW semaphore. */ + for (i = 0; i < timeout; i++) { + swsm = er32(SWSM); + ew32(SWSM, swsm | E1000_SWSM_SWESMBI); + + /* Semaphore acquired if bit latched */ + if (er32(SWSM) & E1000_SWSM_SWESMBI) + break; + + udelay(50); + } + + if (i == timeout) { + /* Release semaphores */ + e1000e_put_hw_semaphore(hw); + hw_dbg(hw, "Driver can't access the NVM\n"); + return -E1000_ERR_NVM; + } + + return 0; +} + +/** + * e1000_put_hw_semaphore_82571 - Release hardware semaphore + * @hw: pointer to the HW structure + * + * Release hardware semaphore used to access the PHY or NVM + **/ +static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw) +{ + u32 swsm; + + swsm = er32(SWSM); + + swsm &= ~E1000_SWSM_SWESMBI; + + ew32(SWSM, swsm); +} + +/** + * e1000_acquire_nvm_82571 - Request for access to the EEPROM + * @hw: pointer to the HW structure + * + * To gain access to the EEPROM, first we must obtain a hardware semaphore. + * Then for non-82573 hardware, set the EEPROM access request bit and wait + * for EEPROM access grant bit. If the access grant bit is not set, release + * hardware semaphore. + **/ +static s32 e1000_acquire_nvm_82571(struct e1000_hw *hw) +{ + s32 ret_val; + + ret_val = e1000_get_hw_semaphore_82571(hw); + if (ret_val) + return ret_val; + + if (hw->mac.type != e1000_82573) + ret_val = e1000e_acquire_nvm(hw); + + if (ret_val) + e1000_put_hw_semaphore_82571(hw); + + return ret_val; +} + +/** + * e1000_release_nvm_82571 - Release exclusive access to EEPROM + * @hw: pointer to the HW structure + * + * Stop any current commands to the EEPROM and clear the EEPROM request bit. + **/ +static void e1000_release_nvm_82571(struct e1000_hw *hw) +{ + e1000e_release_nvm(hw); + e1000_put_hw_semaphore_82571(hw); +} + +/** + * e1000_write_nvm_82571 - Write to EEPROM using appropriate interface + * @hw: pointer to the HW structure + * @offset: offset within the EEPROM to be written to + * @words: number of words to write + * @data: 16 bit word(s) to be written to the EEPROM + * + * For non-82573 silicon, write data to EEPROM at offset using SPI interface. + * + * If e1000e_update_nvm_checksum is not called after this function, the + * EEPROM will most likley contain an invalid checksum. + **/ +static s32 e1000_write_nvm_82571(struct e1000_hw *hw, u16 offset, u16 words, + u16 *data) +{ + s32 ret_val; + + switch (hw->mac.type) { + case e1000_82573: + ret_val = e1000_write_nvm_eewr_82571(hw, offset, words, data); + break; + case e1000_82571: + case e1000_82572: + ret_val = e1000e_write_nvm_spi(hw, offset, words, data); + break; + default: + ret_val = -E1000_ERR_NVM; + break; + } + + return ret_val; +} + +/** + * e1000_update_nvm_checksum_82571 - Update EEPROM checksum + * @hw: pointer to the HW structure + * + * Updates the EEPROM checksum by reading/adding each word of the EEPROM + * up to the checksum. Then calculates the EEPROM checksum and writes the + * value to the EEPROM. + **/ +static s32 e1000_update_nvm_checksum_82571(struct e1000_hw *hw) +{ + u32 eecd; + s32 ret_val; + u16 i; + + ret_val = e1000e_update_nvm_checksum_generic(hw); + if (ret_val) + return ret_val; + + /* If our nvm is an EEPROM, then we're done + * otherwise, commit the checksum to the flash NVM. */ + if (hw->nvm.type != e1000_nvm_flash_hw) + return ret_val; + + /* Check for pending operations. */ + for (i = 0; i < E1000_FLASH_UPDATES; i++) { + msleep(1); + if ((er32(EECD) & E1000_EECD_FLUPD) == 0) + break; + } + + if (i == E1000_FLASH_UPDATES) + return -E1000_ERR_NVM; + + /* Reset the firmware if using STM opcode. */ + if ((er32(FLOP) & 0xFF00) == E1000_STM_OPCODE) { + /* The enabling of and the actual reset must be done + * in two write cycles. + */ + ew32(HICR, E1000_HICR_FW_RESET_ENABLE); + e1e_flush(); + ew32(HICR, E1000_HICR_FW_RESET); + } + + /* Commit the write to flash */ + eecd = er32(EECD) | E1000_EECD_FLUPD; + ew32(EECD, eecd); + + for (i = 0; i < E1000_FLASH_UPDATES; i++) { + msleep(1); + if ((er32(EECD) & E1000_EECD_FLUPD) == 0) + break; + } + + if (i == E1000_FLASH_UPDATES) + return -E1000_ERR_NVM; + + return 0; +} + +/** + * e1000_validate_nvm_checksum_82571 - Validate EEPROM checksum + * @hw: pointer to the HW structure + * + * Calculates the EEPROM checksum by reading/adding each word of the EEPROM + * and then verifies that the sum of the EEPROM is equal to 0xBABA. + **/ +static s32 e1000_validate_nvm_checksum_82571(struct e1000_hw *hw) +{ + if (hw->nvm.type == e1000_nvm_flash_hw) + e1000_fix_nvm_checksum_82571(hw); + + return e1000e_validate_nvm_checksum_generic(hw); +} + +/** + * e1000_write_nvm_eewr_82571 - Write to EEPROM for 82573 silicon + * @hw: pointer to the HW structure + * @offset: offset within the EEPROM to be written to + * @words: number of words to write + * @data: 16 bit word(s) to be written to the EEPROM + * + * After checking for invalid values, poll the EEPROM to ensure the previous + * command has completed before trying to write the next word. After write + * poll for completion. + * + * If e1000e_update_nvm_checksum is not called after this function, the + * EEPROM will most likley contain an invalid checksum. + **/ +static s32 e1000_write_nvm_eewr_82571(struct e1000_hw *hw, u16 offset, + u16 words, u16 *data) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + u32 i; + u32 eewr = 0; + s32 ret_val = 0; + + /* A check for invalid values: offset too large, too many words, + * and not enough words. */ + if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) || + (words == 0)) { + hw_dbg(hw, "nvm parameter(s) out of bounds\n"); + return -E1000_ERR_NVM; + } + + for (i = 0; i < words; i++) { + eewr = (data[i] << E1000_NVM_RW_REG_DATA) | + ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) | + E1000_NVM_RW_REG_START; + + ret_val = e1000e_poll_eerd_eewr_done(hw, E1000_NVM_POLL_WRITE); + if (ret_val) + break; + + ew32(EEWR, eewr); + + ret_val = e1000e_poll_eerd_eewr_done(hw, E1000_NVM_POLL_WRITE); + if (ret_val) + break; + } + + return ret_val; +} + +/** + * e1000_get_cfg_done_82571 - Poll for configuration done + * @hw: pointer to the HW structure + * + * Reads the management control register for the config done bit to be set. + **/ +static s32 e1000_get_cfg_done_82571(struct e1000_hw *hw) +{ + s32 timeout = PHY_CFG_TIMEOUT; + + while (timeout) { + if (er32(EEMNGCTL) & + E1000_NVM_CFG_DONE_PORT_0) + break; + msleep(1); + timeout--; + } + if (!timeout) { + hw_dbg(hw, "MNG configuration cycle has not completed.\n"); + return -E1000_ERR_RESET; + } + + return 0; +} + +/** + * e1000_set_d0_lplu_state_82571 - Set Low Power Linkup D0 state + * @hw: pointer to the HW structure + * @active: TRUE to enable LPLU, FALSE to disable + * + * Sets the LPLU D0 state according to the active flag. When activating LPLU + * this function also disables smart speed and vice versa. LPLU will not be + * activated unless the device autonegotiation advertisement meets standards + * of either 10 or 10/100 or 10/100/1000 at all duplexes. This is a function + * pointer entry point only called by PHY setup routines. + **/ +static s32 e1000_set_d0_lplu_state_82571(struct e1000_hw *hw, bool active) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 data; + + ret_val = e1e_rphy(hw, IGP02E1000_PHY_POWER_MGMT, &data); + if (ret_val) + return ret_val; + + if (active) { + data |= IGP02E1000_PM_D0_LPLU; + ret_val = e1e_wphy(hw, IGP02E1000_PHY_POWER_MGMT, data); + if (ret_val) + return ret_val; + + /* When LPLU is enabled, we should disable SmartSpeed */ + ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG, &data); + data &= ~IGP01E1000_PSCFR_SMART_SPEED; + ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG, data); + if (ret_val) + return ret_val; + } else { + data &= ~IGP02E1000_PM_D0_LPLU; + ret_val = e1e_wphy(hw, IGP02E1000_PHY_POWER_MGMT, data); + /* LPLU and SmartSpeed are mutually exclusive. LPLU is used + * during Dx states where the power conservation is most + * important. During driver activity we should enable + * SmartSpeed, so performance is maintained. */ + if (phy->smart_speed == e1000_smart_speed_on) { + ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG, + &data); + if (ret_val) + return ret_val; + + data |= IGP01E1000_PSCFR_SMART_SPEED; + ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG, + data); + if (ret_val) + return ret_val; + } else if (phy->smart_speed == e1000_smart_speed_off) { + ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG, + &data); + if (ret_val) + return ret_val; + + data &= ~IGP01E1000_PSCFR_SMART_SPEED; + ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG, + data); + if (ret_val) + return ret_val; + } + } + + return 0; +} + +/** + * e1000_reset_hw_82571 - Reset hardware + * @hw: pointer to the HW structure + * + * This resets the hardware into a known state. This is a + * function pointer entry point called by the api module. + **/ +static s32 e1000_reset_hw_82571(struct e1000_hw *hw) +{ + u32 ctrl; + u32 extcnf_ctrl; + u32 ctrl_ext; + u32 icr; + s32 ret_val; + u16 i = 0; + + /* Prevent the PCI-E bus from sticking if there is no TLP connection + * on the last TLP read/write transaction when MAC is reset. + */ + ret_val = e1000e_disable_pcie_master(hw); + if (ret_val) + hw_dbg(hw, "PCI-E Master disable polling has failed.\n"); + + hw_dbg(hw, "Masking off all interrupts\n"); + ew32(IMC, 0xffffffff); + + ew32(RCTL, 0); + ew32(TCTL, E1000_TCTL_PSP); + e1e_flush(); + + msleep(10); + + /* Must acquire the MDIO ownership before MAC reset. + * Ownership defaults to firmware after a reset. */ + if (hw->mac.type == e1000_82573) { + extcnf_ctrl = er32(EXTCNF_CTRL); + extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP; + + do { + ew32(EXTCNF_CTRL, extcnf_ctrl); + extcnf_ctrl = er32(EXTCNF_CTRL); + + if (extcnf_ctrl & E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP) + break; + + extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP; + + msleep(2); + i++; + } while (i < MDIO_OWNERSHIP_TIMEOUT); + } + + ctrl = er32(CTRL); + + hw_dbg(hw, "Issuing a global reset to MAC\n"); + ew32(CTRL, ctrl | E1000_CTRL_RST); + + if (hw->nvm.type == e1000_nvm_flash_hw) { + udelay(10); + ctrl_ext = er32(CTRL_EXT); + ctrl_ext |= E1000_CTRL_EXT_EE_RST; + ew32(CTRL_EXT, ctrl_ext); + e1e_flush(); + } + + ret_val = e1000e_get_auto_rd_done(hw); + if (ret_val) + /* We don't want to continue accessing MAC registers. */ + return ret_val; + + /* Phy configuration from NVM just starts after EECD_AUTO_RD is set. + * Need to wait for Phy configuration completion before accessing + * NVM and Phy. + */ + if (hw->mac.type == e1000_82573) + msleep(25); + + /* Clear any pending interrupt events. */ + ew32(IMC, 0xffffffff); + icr = er32(ICR); + + return 0; +} + +/** + * e1000_init_hw_82571 - Initialize hardware + * @hw: pointer to the HW structure + * + * This inits the hardware readying it for operation. + **/ +static s32 e1000_init_hw_82571(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + u32 reg_data; + s32 ret_val; + u16 i; + u16 rar_count = mac->rar_entry_count; + + e1000_initialize_hw_bits_82571(hw); + + /* Initialize identification LED */ + ret_val = e1000e_id_led_init(hw); + if (ret_val) { + hw_dbg(hw, "Error initializing identification LED\n"); + return ret_val; + } + + /* Disabling VLAN filtering */ + hw_dbg(hw, "Initializing the IEEE VLAN\n"); + e1000e_clear_vfta(hw); + + /* Setup the receive address. */ + /* If, however, a locally administered address was assigned to the + * 82571, we must reserve a RAR for it to work around an issue where + * resetting one port will reload the MAC on the other port. + */ + if (e1000e_get_laa_state_82571(hw)) + rar_count--; + e1000e_init_rx_addrs(hw, rar_count); + + /* Zero out the Multicast HASH table */ + hw_dbg(hw, "Zeroing the MTA\n"); + for (i = 0; i < mac->mta_reg_count; i++) + E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0); + + /* Setup link and flow control */ + ret_val = e1000_setup_link_82571(hw); + + /* Set the transmit descriptor write-back policy */ + reg_data = er32(TXDCTL); + reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) | + E1000_TXDCTL_FULL_TX_DESC_WB | + E1000_TXDCTL_COUNT_DESC; + ew32(TXDCTL, reg_data); + + /* ...for both queues. */ + if (mac->type != e1000_82573) { + reg_data = er32(TXDCTL1); + reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) | + E1000_TXDCTL_FULL_TX_DESC_WB | + E1000_TXDCTL_COUNT_DESC; + ew32(TXDCTL1, reg_data); + } else { + e1000e_enable_tx_pkt_filtering(hw); + reg_data = er32(GCR); + reg_data |= E1000_GCR_L1_ACT_WITHOUT_L0S_RX; + ew32(GCR, reg_data); + } + + /* Clear all of the statistics registers (clear on read). It is + * important that we do this after we have tried to establish link + * because the symbol error count will increment wildly if there + * is no link. + */ + e1000_clear_hw_cntrs_82571(hw); + + return ret_val; +} + +/** + * e1000_initialize_hw_bits_82571 - Initialize hardware-dependent bits + * @hw: pointer to the HW structure + * + * Initializes required hardware-dependent bits needed for normal operation. + **/ +static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw) +{ + u32 reg; + + /* Transmit Descriptor Control 0 */ + reg = er32(TXDCTL); + reg |= (1 << 22); + ew32(TXDCTL, reg); + + /* Transmit Descriptor Control 1 */ + reg = er32(TXDCTL1); + reg |= (1 << 22); + ew32(TXDCTL1, reg); + + /* Transmit Arbitration Control 0 */ + reg = er32(TARC0); + reg &= ~(0xF << 27); /* 30:27 */ + switch (hw->mac.type) { + case e1000_82571: + case e1000_82572: + reg |= (1 << 23) | (1 << 24) | (1 << 25) | (1 << 26); + break; + default: + break; + } + ew32(TARC0, reg); + + /* Transmit Arbitration Control 1 */ + reg = er32(TARC1); + switch (hw->mac.type) { + case e1000_82571: + case e1000_82572: + reg &= ~((1 << 29) | (1 << 30)); + reg |= (1 << 22) | (1 << 24) | (1 << 25) | (1 << 26); + if (er32(TCTL) & E1000_TCTL_MULR) + reg &= ~(1 << 28); + else + reg |= (1 << 28); + ew32(TARC1, reg); + break; + default: + break; + } + + /* Device Control */ + if (hw->mac.type == e1000_82573) { + reg = er32(CTRL); + reg &= ~(1 << 29); + ew32(CTRL, reg); + } + + /* Extended Device Control */ + if (hw->mac.type == e1000_82573) { + reg = er32(CTRL_EXT); + reg &= ~(1 << 23); + reg |= (1 << 22); + ew32(CTRL_EXT, reg); + } +} + +/** + * e1000e_clear_vfta - Clear VLAN filter table + * @hw: pointer to the HW structure + * + * Clears the register array which contains the VLAN filter table by + * setting all the values to 0. + **/ +void e1000e_clear_vfta(struct e1000_hw *hw) +{ + u32 offset; + u32 vfta_value = 0; + u32 vfta_offset = 0; + u32 vfta_bit_in_reg = 0; + + if (hw->mac.type == e1000_82573) { + if (hw->mng_cookie.vlan_id != 0) { + /* The VFTA is a 4096b bit-field, each identifying + * a single VLAN ID. The following operations + * determine which 32b entry (i.e. offset) into the + * array we want to set the VLAN ID (i.e. bit) of + * the manageability unit. + */ + vfta_offset = (hw->mng_cookie.vlan_id >> + E1000_VFTA_ENTRY_SHIFT) & + E1000_VFTA_ENTRY_MASK; + vfta_bit_in_reg = 1 << (hw->mng_cookie.vlan_id & + E1000_VFTA_ENTRY_BIT_SHIFT_MASK); + } + } + for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) { + /* If the offset we want to clear is the same offset of the + * manageability VLAN ID, then clear all bits except that of + * the manageability unit. + */ + vfta_value = (offset == vfta_offset) ? vfta_bit_in_reg : 0; + E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, vfta_value); + e1e_flush(); + } +} + +/** + * e1000_mc_addr_list_update_82571 - Update Multicast addresses + * @hw: pointer to the HW structure + * @mc_addr_list: array of multicast addresses to program + * @mc_addr_count: number of multicast addresses to program + * @rar_used_count: the first RAR register free to program + * @rar_count: total number of supported Receive Address Registers + * + * Updates the Receive Address Registers and Multicast Table Array. + * The caller must have a packed mc_addr_list of multicast addresses. + * The parameter rar_count will usually be hw->mac.rar_entry_count + * unless there are workarounds that change this. + **/ +static void e1000_mc_addr_list_update_82571(struct e1000_hw *hw, + u8 *mc_addr_list, + u32 mc_addr_count, + u32 rar_used_count, + u32 rar_count) +{ + if (e1000e_get_laa_state_82571(hw)) + rar_count--; + + e1000e_mc_addr_list_update_generic(hw, mc_addr_list, mc_addr_count, + rar_used_count, rar_count); +} + +/** + * e1000_setup_link_82571 - Setup flow control and link settings + * @hw: pointer to the HW structure + * + * Determines which flow control settings to use, then configures flow + * control. Calls the appropriate media-specific link configuration + * function. Assuming the adapter has a valid link partner, a valid link + * should be established. Assumes the hardware has previously been reset + * and the transmitter and receiver are not enabled. + **/ +static s32 e1000_setup_link_82571(struct e1000_hw *hw) +{ + /* 82573 does not have a word in the NVM to determine + * the default flow control setting, so we explicitly + * set it to full. + */ + if (hw->mac.type == e1000_82573) + hw->mac.fc = e1000_fc_full; + + return e1000e_setup_link(hw); +} + +/** + * e1000_setup_copper_link_82571 - Configure copper link settings + * @hw: pointer to the HW structure + * + * Configures the link for auto-neg or forced speed and duplex. Then we check + * for link, once link is established calls to configure collision distance + * and flow control are called. + **/ +static s32 e1000_setup_copper_link_82571(struct e1000_hw *hw) +{ + u32 ctrl; + u32 led_ctrl; + s32 ret_val; + + ctrl = er32(CTRL); + ctrl |= E1000_CTRL_SLU; + ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); + ew32(CTRL, ctrl); + + switch (hw->phy.type) { + case e1000_phy_m88: + ret_val = e1000e_copper_link_setup_m88(hw); + break; + case e1000_phy_igp_2: + ret_val = e1000e_copper_link_setup_igp(hw); + /* Setup activity LED */ + led_ctrl = er32(LEDCTL); + led_ctrl &= IGP_ACTIVITY_LED_MASK; + led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE); + ew32(LEDCTL, led_ctrl); + break; + default: + return -E1000_ERR_PHY; + break; + } + + if (ret_val) + return ret_val; + + ret_val = e1000e_setup_copper_link(hw); + + return ret_val; +} + +/** + * e1000_setup_fiber_serdes_link_82571 - Setup link for fiber/serdes + * @hw: pointer to the HW structure + * + * Configures collision distance and flow control for fiber and serdes links. + * Upon successful setup, poll for link. + **/ +static s32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw) +{ + switch (hw->mac.type) { + case e1000_82571: + case e1000_82572: + /* If SerDes loopback mode is entered, there is no form + * of reset to take the adapter out of that mode. So we + * have to explicitly take the adapter out of loopback + * mode. This prevents drivers from twidling their thumbs + * if another tool failed to take it out of loopback mode. + */ + ew32(SCTL, + E1000_SCTL_DISABLE_SERDES_LOOPBACK); + break; + default: + break; + } + + return e1000e_setup_fiber_serdes_link(hw); +} + +/** + * e1000_valid_led_default_82571 - Verify a valid default LED config + * @hw: pointer to the HW structure + * @data: pointer to the NVM (EEPROM) + * + * Read the EEPROM for the current default LED configuration. If the + * LED configuration is not valid, set to a valid LED configuration. + **/ +static s32 e1000_valid_led_default_82571(struct e1000_hw *hw, u16 *data) +{ + s32 ret_val; + + ret_val = e1000_read_nvm(hw, NVM_ID_LED_SETTINGS, 1, data); + if (ret_val) { + hw_dbg(hw, "NVM Read Error\n"); + return ret_val; + } + + if (hw->mac.type == e1000_82573 && + *data == ID_LED_RESERVED_F746) + *data = ID_LED_DEFAULT_82573; + else if (*data == ID_LED_RESERVED_0000 || + *data == ID_LED_RESERVED_FFFF) + *data = ID_LED_DEFAULT; + + return 0; +} + +/** + * e1000e_get_laa_state_82571 - Get locally administered address state + * @hw: pointer to the HW structure + * + * Retrieve and return the current locally administed address state. + **/ +bool e1000e_get_laa_state_82571(struct e1000_hw *hw) +{ + if (hw->mac.type != e1000_82571) + return 0; + + return hw->dev_spec.e82571.laa_is_present; +} + +/** + * e1000e_set_laa_state_82571 - Set locally administered address state + * @hw: pointer to the HW structure + * @state: enable/disable locally administered address + * + * Enable/Disable the current locally administed address state. + **/ +void e1000e_set_laa_state_82571(struct e1000_hw *hw, bool state) +{ + if (hw->mac.type != e1000_82571) + return; + + hw->dev_spec.e82571.laa_is_present = state; + + /* If workaround is activated... */ + if (state) + /* Hold a copy of the LAA in RAR[14] This is done so that + * between the time RAR[0] gets clobbered and the time it + * gets fixed, the actual LAA is in one of the RARs and no + * incoming packets directed to this port are dropped. + * Eventually the LAA will be in RAR[0] and RAR[14]. + */ + e1000e_rar_set(hw, hw->mac.addr, hw->mac.rar_entry_count - 1); +} + +/** + * e1000_fix_nvm_checksum_82571 - Fix EEPROM checksum + * @hw: pointer to the HW structure + * + * Verifies that the EEPROM has completed the update. After updating the + * EEPROM, we need to check bit 15 in work 0x23 for the checksum fix. If + * the checksum fix is not implemented, we need to set the bit and update + * the checksum. Otherwise, if bit 15 is set and the checksum is incorrect, + * we need to return bad checksum. + **/ +static s32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + s32 ret_val; + u16 data; + + if (nvm->type != e1000_nvm_flash_hw) + return 0; + + /* Check bit 4 of word 10h. If it is 0, firmware is done updating + * 10h-12h. Checksum may need to be fixed. + */ + ret_val = e1000_read_nvm(hw, 0x10, 1, &data); + if (ret_val) + return ret_val; + + if (!(data & 0x10)) { + /* Read 0x23 and check bit 15. This bit is a 1 + * when the checksum has already been fixed. If + * the checksum is still wrong and this bit is a + * 1, we need to return bad checksum. Otherwise, + * we need to set this bit to a 1 and update the + * checksum. + */ + ret_val = e1000_read_nvm(hw, 0x23, 1, &data); + if (ret_val) + return ret_val; + + if (!(data & 0x8000)) { + data |= 0x8000; + ret_val = e1000_write_nvm(hw, 0x23, 1, &data); + if (ret_val) + return ret_val; + ret_val = e1000e_update_nvm_checksum(hw); + } + } + + return 0; +} + +/** + * e1000_clear_hw_cntrs_82571 - Clear device specific hardware counters + * @hw: pointer to the HW structure + * + * Clears the hardware counters by reading the counter registers. + **/ +static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw) +{ + u32 temp; + + e1000e_clear_hw_cntrs_base(hw); + + temp = er32(PRC64); + temp = er32(PRC127); + temp = er32(PRC255); + temp = er32(PRC511); + temp = er32(PRC1023); + temp = er32(PRC1522); + temp = er32(PTC64); + temp = er32(PTC127); + temp = er32(PTC255); + temp = er32(PTC511); + temp = er32(PTC1023); + temp = er32(PTC1522); + + temp = er32(ALGNERRC); + temp = er32(RXERRC); + temp = er32(TNCRS); + temp = er32(CEXTERR); + temp = er32(TSCTC); + temp = er32(TSCTFC); + + temp = er32(MGTPRC); + temp = er32(MGTPDC); + temp = er32(MGTPTC); + + temp = er32(IAC); + temp = er32(ICRXOC); + + temp = er32(ICRXPTC); + temp = er32(ICRXATC); + temp = er32(ICTXPTC); + temp = er32(ICTXATC); + temp = er32(ICTXQEC); + temp = er32(ICTXQMTC); + temp = er32(ICRXDMTC); +} + +static struct e1000_mac_operations e82571_mac_ops = { + .mng_mode_enab = E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT, + /* .check_for_link: media type dependent */ + .cleanup_led = e1000e_cleanup_led_generic, + .clear_hw_cntrs = e1000_clear_hw_cntrs_82571, + .get_bus_info = e1000e_get_bus_info_pcie, + /* .get_link_up_info: media type dependent */ + .led_on = e1000e_led_on_generic, + .led_off = e1000e_led_off_generic, + .mc_addr_list_update = e1000_mc_addr_list_update_82571, + .reset_hw = e1000_reset_hw_82571, + .init_hw = e1000_init_hw_82571, + .setup_link = e1000_setup_link_82571, + /* .setup_physical_interface: media type dependent */ +}; + +static struct e1000_phy_operations e82_phy_ops_igp = { + .acquire_phy = e1000_get_hw_semaphore_82571, + .check_reset_block = e1000e_check_reset_block_generic, + .commit_phy = NULL, + .force_speed_duplex = e1000e_phy_force_speed_duplex_igp, + .get_cfg_done = e1000_get_cfg_done_82571, + .get_cable_length = e1000e_get_cable_length_igp_2, + .get_phy_info = e1000e_get_phy_info_igp, + .read_phy_reg = e1000e_read_phy_reg_igp, + .release_phy = e1000_put_hw_semaphore_82571, + .reset_phy = e1000e_phy_hw_reset_generic, + .set_d0_lplu_state = e1000_set_d0_lplu_state_82571, + .set_d3_lplu_state = e1000e_set_d3_lplu_state, + .write_phy_reg = e1000e_write_phy_reg_igp, +}; + +static struct e1000_phy_operations e82_phy_ops_m88 = { + .acquire_phy = e1000_get_hw_semaphore_82571, + .check_reset_block = e1000e_check_reset_block_generic, + .commit_phy = e1000e_phy_sw_reset, + .force_speed_duplex = e1000e_phy_force_speed_duplex_m88, + .get_cfg_done = e1000e_get_cfg_done, + .get_cable_length = e1000e_get_cable_length_m88, + .get_phy_info = e1000e_get_phy_info_m88, + .read_phy_reg = e1000e_read_phy_reg_m88, + .release_phy = e1000_put_hw_semaphore_82571, + .reset_phy = e1000e_phy_hw_reset_generic, + .set_d0_lplu_state = e1000_set_d0_lplu_state_82571, + .set_d3_lplu_state = e1000e_set_d3_lplu_state, + .write_phy_reg = e1000e_write_phy_reg_m88, +}; + +static struct e1000_nvm_operations e82571_nvm_ops = { + .acquire_nvm = e1000_acquire_nvm_82571, + .read_nvm = e1000e_read_nvm_spi, + .release_nvm = e1000_release_nvm_82571, + .update_nvm = e1000_update_nvm_checksum_82571, + .valid_led_default = e1000_valid_led_default_82571, + .validate_nvm = e1000_validate_nvm_checksum_82571, + .write_nvm = e1000_write_nvm_82571, +}; + +static struct e1000_nvm_operations e82573_nvm_ops = { + .acquire_nvm = e1000_acquire_nvm_82571, + .read_nvm = e1000e_read_nvm_eerd, + .release_nvm = e1000_release_nvm_82571, + .update_nvm = e1000_update_nvm_checksum_82571, + .valid_led_default = e1000_valid_led_default_82571, + .validate_nvm = e1000_validate_nvm_checksum_82571, + .write_nvm = e1000_write_nvm_82571, +}; + +struct e1000_info e1000_82571_info = { + .mac = e1000_82571, + .flags = FLAG_HAS_HW_VLAN_FILTER + | FLAG_HAS_JUMBO_FRAMES + | FLAG_HAS_STATS_PTC_PRC + | FLAG_HAS_WOL + | FLAG_APME_IN_CTRL3 + | FLAG_RX_CSUM_ENABLED + | FLAG_HAS_CTRLEXT_ON_LOAD + | FLAG_HAS_STATS_ICR_ICT + | FLAG_HAS_SMART_POWER_DOWN + | FLAG_RESET_OVERWRITES_LAA /* errata */ + | FLAG_TARC_SPEED_MODE_BIT /* errata */ + | FLAG_APME_CHECK_PORT_B, + .pba = 38, + .get_invariants = e1000_get_invariants_82571, + .mac_ops = &e82571_mac_ops, + .phy_ops = &e82_phy_ops_igp, + .nvm_ops = &e82571_nvm_ops, +}; + +struct e1000_info e1000_82572_info = { + .mac = e1000_82572, + .flags = FLAG_HAS_HW_VLAN_FILTER + | FLAG_HAS_JUMBO_FRAMES + | FLAG_HAS_STATS_PTC_PRC + | FLAG_HAS_WOL + | FLAG_APME_IN_CTRL3 + | FLAG_RX_CSUM_ENABLED + | FLAG_HAS_CTRLEXT_ON_LOAD + | FLAG_HAS_STATS_ICR_ICT + | FLAG_TARC_SPEED_MODE_BIT, /* errata */ + .pba = 38, + .get_invariants = e1000_get_invariants_82571, + .mac_ops = &e82571_mac_ops, + .phy_ops = &e82_phy_ops_igp, + .nvm_ops = &e82571_nvm_ops, +}; + +struct e1000_info e1000_82573_info = { + .mac = e1000_82573, + .flags = FLAG_HAS_HW_VLAN_FILTER + | FLAG_HAS_JUMBO_FRAMES + | FLAG_HAS_STATS_PTC_PRC + | FLAG_HAS_WOL + | FLAG_APME_IN_CTRL3 + | FLAG_RX_CSUM_ENABLED + | FLAG_HAS_STATS_ICR_ICT + | FLAG_HAS_SMART_POWER_DOWN + | FLAG_HAS_AMT + | FLAG_HAS_ASPM + | FLAG_HAS_ERT + | FLAG_HAS_SWSM_ON_LOAD, + .pba = 20, + .get_invariants = e1000_get_invariants_82571, + .mac_ops = &e82571_mac_ops, + .phy_ops = &e82_phy_ops_m88, + .nvm_ops = &e82573_nvm_ops, +}; + diff --git a/drivers/net/e1000e/Makefile b/drivers/net/e1000e/Makefile new file mode 100644 index 00000000000..650f866e7ac --- /dev/null +++ b/drivers/net/e1000e/Makefile @@ -0,0 +1,37 @@ +################################################################################ +# +# Intel PRO/1000 Linux driver +# Copyright(c) 1999 - 2007 Intel Corporation. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms and conditions of the GNU General Public License, +# version 2, as published by the Free Software Foundation. +# +# This program is distributed in the hope it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +# +# The full GNU General Public License is included in this distribution in +# the file called "COPYING". +# +# Contact Information: +# Linux NICS +# e1000-devel Mailing List +# Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 +# +################################################################################ + +# +# Makefile for the Intel(R) PRO/1000 ethernet driver +# + +obj-$(CONFIG_E1000E) += e1000e.o + +e1000e-objs := 82571.o ich8lan.o es2lan.o \ + lib.o phy.o param.o ethtool.o netdev.o + diff --git a/drivers/net/e1000e/defines.h b/drivers/net/e1000e/defines.h new file mode 100644 index 00000000000..b32ed45b4b3 --- /dev/null +++ b/drivers/net/e1000e/defines.h @@ -0,0 +1,739 @@ +/******************************************************************************* + + Intel PRO/1000 Linux driver + Copyright(c) 1999 - 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#ifndef _E1000_DEFINES_H_ +#define _E1000_DEFINES_H_ + +#define E1000_TXD_POPTS_IXSM 0x01 /* Insert IP checksum */ +#define E1000_TXD_POPTS_TXSM 0x02 /* Insert TCP/UDP checksum */ +#define E1000_TXD_CMD_EOP 0x01000000 /* End of Packet */ +#define E1000_TXD_CMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */ +#define E1000_TXD_CMD_IC 0x04000000 /* Insert Checksum */ +#define E1000_TXD_CMD_RS 0x08000000 /* Report Status */ +#define E1000_TXD_CMD_RPS 0x10000000 /* Report Packet Sent */ +#define E1000_TXD_CMD_DEXT 0x20000000 /* Descriptor extension (0 = legacy) */ +#define E1000_TXD_CMD_VLE 0x40000000 /* Add VLAN tag */ +#define E1000_TXD_CMD_IDE 0x80000000 /* Enable Tidv register */ +#define E1000_TXD_STAT_DD 0x00000001 /* Descriptor Done */ +#define E1000_TXD_STAT_EC 0x00000002 /* Excess Collisions */ +#define E1000_TXD_STAT_LC 0x00000004 /* Late Collisions */ +#define E1000_TXD_STAT_TU 0x00000008 /* Transmit underrun */ +#define E1000_TXD_CMD_TCP 0x01000000 /* TCP packet */ +#define E1000_TXD_CMD_IP 0x02000000 /* IP packet */ +#define E1000_TXD_CMD_TSE 0x04000000 /* TCP Seg enable */ +#define E1000_TXD_STAT_TC 0x00000004 /* Tx Underrun */ + +/* Number of Transmit and Receive Descriptors must be a multiple of 8 */ +#define REQ_TX_DESCRIPTOR_MULTIPLE 8 +#define REQ_RX_DESCRIPTOR_MULTIPLE 8 + +/* Definitions for power management and wakeup registers */ +/* Wake Up Control */ +#define E1000_WUC_APME 0x00000001 /* APM Enable */ +#define E1000_WUC_PME_EN 0x00000002 /* PME Enable */ + +/* Wake Up Filter Control */ +#define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */ +#define E1000_WUFC_MAG 0x00000002 /* Magic Packet Wakeup Enable */ +#define E1000_WUFC_EX 0x00000004 /* Directed Exact Wakeup Enable */ +#define E1000_WUFC_MC 0x00000008 /* Directed Multicast Wakeup Enable */ +#define E1000_WUFC_BC 0x00000010 /* Broadcast Wakeup Enable */ + +/* Extended Device Control */ +#define E1000_CTRL_EXT_SDP7_DATA 0x00000080 /* Value of SW Defineable Pin 7 */ +#define E1000_CTRL_EXT_EE_RST 0x00002000 /* Reinitialize from EEPROM */ +#define E1000_CTRL_EXT_RO_DIS 0x00020000 /* Relaxed Ordering disable */ +#define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000 +#define E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES 0x00C00000 +#define E1000_CTRL_EXT_DRV_LOAD 0x10000000 /* Driver loaded bit for FW */ +#define E1000_CTRL_EXT_IAME 0x08000000 /* Interrupt acknowledge Auto-mask */ +#define E1000_CTRL_EXT_INT_TIMER_CLR 0x20000000 /* Clear Interrupt timers after IMS clear */ + +/* Receive Decriptor bit definitions */ +#define E1000_RXD_STAT_DD 0x01 /* Descriptor Done */ +#define E1000_RXD_STAT_EOP 0x02 /* End of Packet */ +#define E1000_RXD_STAT_IXSM 0x04 /* Ignore checksum */ +#define E1000_RXD_STAT_VP 0x08 /* IEEE VLAN Packet */ +#define E1000_RXD_STAT_UDPCS 0x10 /* UDP xsum caculated */ +#define E1000_RXD_STAT_TCPCS 0x20 /* TCP xsum calculated */ +#define E1000_RXD_ERR_CE 0x01 /* CRC Error */ +#define E1000_RXD_ERR_SE 0x02 /* Symbol Error */ +#define E1000_RXD_ERR_SEQ 0x04 /* Sequence Error */ +#define E1000_RXD_ERR_CXE 0x10 /* Carrier Extension Error */ +#define E1000_RXD_ERR_TCPE 0x20 /* TCP/UDP Checksum Error */ +#define E1000_RXD_ERR_RXE 0x80 /* Rx Data Error */ +#define E1000_RXD_SPC_VLAN_MASK 0x0FFF /* VLAN ID is in lower 12 bits */ + +#define E1000_RXDEXT_STATERR_CE 0x01000000 +#define E1000_RXDEXT_STATERR_SE 0x02000000 +#define E1000_RXDEXT_STATERR_SEQ 0x04000000 +#define E1000_RXDEXT_STATERR_CXE 0x10000000 +#define E1000_RXDEXT_STATERR_RXE 0x80000000 + +/* mask to determine if packets should be dropped due to frame errors */ +#define E1000_RXD_ERR_FRAME_ERR_MASK ( \ + E1000_RXD_ERR_CE | \ + E1000_RXD_ERR_SE | \ + E1000_RXD_ERR_SEQ | \ + E1000_RXD_ERR_CXE | \ + E1000_RXD_ERR_RXE) + +/* Same mask, but for extended and packet split descriptors */ +#define E1000_RXDEXT_ERR_FRAME_ERR_MASK ( \ + E1000_RXDEXT_STATERR_CE | \ + E1000_RXDEXT_STATERR_SE | \ + E1000_RXDEXT_STATERR_SEQ | \ + E1000_RXDEXT_STATERR_CXE | \ + E1000_RXDEXT_STATERR_RXE) + +#define E1000_RXDPS_HDRSTAT_HDRSP 0x00008000 + +/* Management Control */ +#define E1000_MANC_SMBUS_EN 0x00000001 /* SMBus Enabled - RO */ +#define E1000_MANC_ASF_EN 0x00000002 /* ASF Enabled - RO */ +#define E1000_MANC_ARP_EN 0x00002000 /* Enable ARP Request Filtering */ +#define E1000_MANC_RCV_TCO_EN 0x00020000 /* Receive TCO Packets Enabled */ +#define E1000_MANC_BLK_PHY_RST_ON_IDE 0x00040000 /* Block phy resets */ +#define E1000_MANC_EN_MAC_ADDR_FILTER 0x00100000 /* Enable MAC address + * filtering */ +#define E1000_MANC_EN_MNG2HOST 0x00200000 /* Enable MNG packets to host + * memory */ + +/* Receive Control */ +#define E1000_RCTL_EN 0x00000002 /* enable */ +#define E1000_RCTL_SBP 0x00000004 /* store bad packet */ +#define E1000_RCTL_UPE 0x00000008 /* unicast promiscuous enable */ +#define E1000_RCTL_MPE 0x00000010 /* multicast promiscuous enab */ +#define E1000_RCTL_LPE 0x00000020 /* long packet enable */ +#define E1000_RCTL_LBM_NO 0x00000000 /* no loopback mode */ +#define E1000_RCTL_LBM_MAC 0x00000040 /* MAC loopback mode */ +#define E1000_RCTL_LBM_TCVR 0x000000C0 /* tcvr loopback mode */ +#define E1000_RCTL_DTYP_PS 0x00000400 /* Packet Split descriptor */ +#define E1000_RCTL_RDMTS_HALF 0x00000000 /* rx desc min threshold size */ +#define E1000_RCTL_MO_SHIFT 12 /* multicast offset shift */ +#define E1000_RCTL_BAM 0x00008000 /* broadcast enable */ +/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */ +#define E1000_RCTL_SZ_2048 0x00000000 /* rx buffer size 2048 */ +#define E1000_RCTL_SZ_1024 0x00010000 /* rx buffer size 1024 */ +#define E1000_RCTL_SZ_512 0x00020000 /* rx buffer size 512 */ +#define E1000_RCTL_SZ_256 0x00030000 /* rx buffer size 256 */ +/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */ +#define E1000_RCTL_SZ_16384 0x00010000 /* rx buffer size 16384 */ +#define E1000_RCTL_SZ_8192 0x00020000 /* rx buffer size 8192 */ +#define E1000_RCTL_SZ_4096 0x00030000 /* rx buffer size 4096 */ +#define E1000_RCTL_VFE 0x00040000 /* vlan filter enable */ +#define E1000_RCTL_CFIEN 0x00080000 /* canonical form enable */ +#define E1000_RCTL_CFI 0x00100000 /* canonical form indicator */ +#define E1000_RCTL_BSEX 0x02000000 /* Buffer size extension */ +#define E1000_RCTL_SECRC 0x04000000 /* Strip Ethernet CRC */ + +/* Use byte values for the following shift parameters + * Usage: + * psrctl |= (((ROUNDUP(value0, 128) >> E1000_PSRCTL_BSIZE0_SHIFT) & + * E1000_PSRCTL_BSIZE0_MASK) | + * ((ROUNDUP(value1, 1024) >> E1000_PSRCTL_BSIZE1_SHIFT) & + * E1000_PSRCTL_BSIZE1_MASK) | + * ((ROUNDUP(value2, 1024) << E1000_PSRCTL_BSIZE2_SHIFT) & + * E1000_PSRCTL_BSIZE2_MASK) | + * ((ROUNDUP(value3, 1024) << E1000_PSRCTL_BSIZE3_SHIFT) |; + * E1000_PSRCTL_BSIZE3_MASK)) + * where value0 = [128..16256], default=256 + * value1 = [1024..64512], default=4096 + * value2 = [0..64512], default=4096 + * value3 = [0..64512], default=0 + */ + +#define E1000_PSRCTL_BSIZE0_MASK 0x0000007F +#define E1000_PSRCTL_BSIZE1_MASK 0x00003F00 +#define E1000_PSRCTL_BSIZE2_MASK 0x003F0000 +#define E1000_PSRCTL_BSIZE3_MASK 0x3F000000 + +#define E1000_PSRCTL_BSIZE0_SHIFT 7 /* Shift _right_ 7 */ +#define E1000_PSRCTL_BSIZE1_SHIFT 2 /* Shift _right_ 2 */ +#define E1000_PSRCTL_BSIZE2_SHIFT 6 /* Shift _left_ 6 */ +#define E1000_PSRCTL_BSIZE3_SHIFT 14 /* Shift _left_ 14 */ + +/* SWFW_SYNC Definitions */ +#define E1000_SWFW_EEP_SM 0x1 +#define E1000_SWFW_PHY0_SM 0x2 +#define E1000_SWFW_PHY1_SM 0x4 + +/* Device Control */ +#define E1000_CTRL_FD 0x00000001 /* Full duplex.0=half; 1=full */ +#define E1000_CTRL_GIO_MASTER_DISABLE 0x00000004 /*Blocks new Master requests */ +#define E1000_CTRL_LRST 0x00000008 /* Link reset. 0=normal,1=reset */ +#define E1000_CTRL_ASDE 0x00000020 /* Auto-speed detect enable */ +#define E1000_CTRL_SLU 0x00000040 /* Set link up (Force Link) */ +#define E1000_CTRL_ILOS 0x00000080 /* Invert Loss-Of Signal */ +#define E1000_CTRL_SPD_SEL 0x00000300 /* Speed Select Mask */ +#define E1000_CTRL_SPD_10 0x00000000 /* Force 10Mb */ +#define E1000_CTRL_SPD_100 0x00000100 /* Force 100Mb */ +#define E1000_CTRL_SPD_1000 0x00000200 /* Force 1Gb */ +#define E1000_CTRL_FRCSPD 0x00000800 /* Force Speed */ +#define E1000_CTRL_FRCDPX 0x00001000 /* Force Duplex */ +#define E1000_CTRL_SWDPIN0 0x00040000 /* SWDPIN 0 value */ +#define E1000_CTRL_SWDPIN1 0x00080000 /* SWDPIN 1 value */ +#define E1000_CTRL_SWDPIO0 0x00400000 /* SWDPIN 0 Input or output */ +#define E1000_CTRL_RST 0x04000000 /* Global reset */ +#define E1000_CTRL_RFCE 0x08000000 /* Receive Flow Control enable */ +#define E1000_CTRL_TFCE 0x10000000 /* Transmit flow control enable */ +#define E1000_CTRL_VME 0x40000000 /* IEEE VLAN mode enable */ +#define E1000_CTRL_PHY_RST 0x80000000 /* PHY Reset */ + +/* Bit definitions for the Management Data IO (MDIO) and Management Data + * Clock (MDC) pins in the Device Control Register. + */ + +/* Device Status */ +#define E1000_STATUS_FD 0x00000001 /* Full duplex.0=half,1=full */ +#define E1000_STATUS_LU 0x00000002 /* Link up.0=no,1=link */ +#define E1000_STATUS_FUNC_MASK 0x0000000C /* PCI Function Mask */ +#define E1000_STATUS_FUNC_SHIFT 2 +#define E1000_STATUS_FUNC_1 0x00000004 /* Function 1 */ +#define E1000_STATUS_TXOFF 0x00000010 /* transmission paused */ +#define E1000_STATUS_SPEED_10 0x00000000 /* Speed 10Mb/s */ +#define E1000_STATUS_SPEED_100 0x00000040 /* Speed 100Mb/s */ +#define E1000_STATUS_SPEED_1000 0x00000080 /* Speed 1000Mb/s */ +#define E1000_STATUS_LAN_INIT_DONE 0x00000200 /* Lan Init Completion by NVM */ +#define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Status of Master requests. */ + +/* Constants used to intrepret the masked PCI-X bus speed. */ + +#define HALF_DUPLEX 1 +#define FULL_DUPLEX 2 + + +#define ADVERTISE_10_HALF 0x0001 +#define ADVERTISE_10_FULL 0x0002 +#define ADVERTISE_100_HALF 0x0004 +#define ADVERTISE_100_FULL 0x0008 +#define ADVERTISE_1000_HALF 0x0010 /* Not used, just FYI */ +#define ADVERTISE_1000_FULL 0x0020 + +/* 1000/H is not supported, nor spec-compliant. */ +#define E1000_ALL_SPEED_DUPLEX ( ADVERTISE_10_HALF | ADVERTISE_10_FULL | \ + ADVERTISE_100_HALF | ADVERTISE_100_FULL | \ + ADVERTISE_1000_FULL) +#define E1000_ALL_NOT_GIG ( ADVERTISE_10_HALF | ADVERTISE_10_FULL | \ + ADVERTISE_100_HALF | ADVERTISE_100_FULL) +#define E1000_ALL_100_SPEED (ADVERTISE_100_HALF | ADVERTISE_100_FULL) +#define E1000_ALL_10_SPEED (ADVERTISE_10_HALF | ADVERTISE_10_FULL) +#define E1000_ALL_HALF_DUPLEX (ADVERTISE_10_HALF | ADVERTISE_100_HALF) + +#define AUTONEG_ADVERTISE_SPEED_DEFAULT E1000_ALL_SPEED_DUPLEX + +/* LED Control */ +#define E1000_LEDCTL_LED0_MODE_MASK 0x0000000F +#define E1000_LEDCTL_LED0_MODE_SHIFT 0 +#define E1000_LEDCTL_LED0_IVRT 0x00000040 +#define E1000_LEDCTL_LED0_BLINK 0x00000080 + +#define E1000_LEDCTL_MODE_LED_ON 0xE +#define E1000_LEDCTL_MODE_LED_OFF 0xF + +/* Transmit Descriptor bit definitions */ +#define E1000_TXD_DTYP_D 0x00100000 /* Data Descriptor */ +#define E1000_TXD_POPTS_IXSM 0x01 /* Insert IP checksum */ +#define E1000_TXD_POPTS_TXSM 0x02 /* Insert TCP/UDP checksum */ +#define E1000_TXD_CMD_EOP 0x01000000 /* End of Packet */ +#define E1000_TXD_CMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */ +#define E1000_TXD_CMD_IC 0x04000000 /* Insert Checksum */ +#define E1000_TXD_CMD_RS 0x08000000 /* Report Status */ +#define E1000_TXD_CMD_RPS 0x10000000 /* Report Packet Sent */ +#define E1000_TXD_CMD_DEXT 0x20000000 /* Descriptor extension (0 = legacy) */ +#define E1000_TXD_CMD_VLE 0x40000000 /* Add VLAN tag */ +#define E1000_TXD_CMD_IDE 0x80000000 /* Enable Tidv register */ +#define E1000_TXD_STAT_DD 0x00000001 /* Descriptor Done */ +#define E1000_TXD_STAT_EC 0x00000002 /* Excess Collisions */ +#define E1000_TXD_STAT_LC 0x00000004 /* Late Collisions */ +#define E1000_TXD_STAT_TU 0x00000008 /* Transmit underrun */ +#define E1000_TXD_CMD_TCP 0x01000000 /* TCP packet */ +#define E1000_TXD_CMD_IP 0x02000000 /* IP packet */ +#define E1000_TXD_CMD_TSE 0x04000000 /* TCP Seg enable */ +#define E1000_TXD_STAT_TC 0x00000004 /* Tx Underrun */ + +/* Transmit Control */ +#define E1000_TCTL_EN 0x00000002 /* enable tx */ +#define E1000_TCTL_PSP 0x00000008 /* pad short packets */ +#define E1000_TCTL_CT 0x00000ff0 /* collision threshold */ +#define E1000_TCTL_COLD 0x003ff000 /* collision distance */ +#define E1000_TCTL_RTLC 0x01000000 /* Re-transmit on late collision */ +#define E1000_TCTL_MULR 0x10000000 /* Multiple request support */ + +/* Transmit Arbitration Count */ + +/* SerDes Control */ +#define E1000_SCTL_DISABLE_SERDES_LOOPBACK 0x0400 + +/* Receive Checksum Control */ +#define E1000_RXCSUM_TUOFL 0x00000200 /* TCP / UDP checksum offload */ +#define E1000_RXCSUM_IPPCSE 0x00001000 /* IP payload checksum enable */ + +/* Header split receive */ +#define E1000_RFCTL_EXTEN 0x00008000 +#define E1000_RFCTL_IPV6_EX_DIS 0x00010000 +#define E1000_RFCTL_NEW_IPV6_EXT_DIS 0x00020000 + +/* Collision related configuration parameters */ +#define E1000_COLLISION_THRESHOLD 15 +#define E1000_CT_SHIFT 4 +#define E1000_COLLISION_DISTANCE 63 +#define E1000_COLD_SHIFT 12 + +/* Default values for the transmit IPG register */ +#define DEFAULT_82543_TIPG_IPGT_COPPER 8 + +#define E1000_TIPG_IPGT_MASK 0x000003FF + +#define DEFAULT_82543_TIPG_IPGR1 8 +#define E1000_TIPG_IPGR1_SHIFT 10 + +#define DEFAULT_82543_TIPG_IPGR2 6 +#define DEFAULT_80003ES2LAN_TIPG_IPGR2 7 +#define E1000_TIPG_IPGR2_SHIFT 20 + +#define MAX_JUMBO_FRAME_SIZE 0x3F00 + +/* Extended Configuration Control and Size */ +#define E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP 0x00000020 +#define E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE 0x00000001 +#define E1000_EXTCNF_CTRL_SWFLAG 0x00000020 +#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK 0x00FF0000 +#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT 16 +#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK 0x0FFF0000 +#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT 16 + +#define E1000_PHY_CTRL_D0A_LPLU 0x00000002 +#define E1000_PHY_CTRL_NOND0A_LPLU 0x00000004 +#define E1000_PHY_CTRL_NOND0A_GBE_DISABLE 0x00000008 +#define E1000_PHY_CTRL_GBE_DISABLE 0x00000040 + +#define E1000_KABGTXD_BGSQLBIAS 0x00050000 + +/* PBA constants */ +#define E1000_PBA_8K 0x0008 /* 8KB, default Rx allocation */ +#define E1000_PBA_16K 0x0010 /* 16KB, default TX allocation */ + +#define E1000_PBS_16K E1000_PBA_16K + +#define IFS_MAX 80 +#define IFS_MIN 40 +#define IFS_RATIO 4 +#define IFS_STEP 10 +#define MIN_NUM_XMITS 1000 + +/* SW Semaphore Register */ +#define E1000_SWSM_SMBI 0x00000001 /* Driver Semaphore bit */ +#define E1000_SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */ +#define E1000_SWSM_DRV_LOAD 0x00000008 /* Driver Loaded Bit */ + +/* Interrupt Cause Read */ +#define E1000_ICR_TXDW 0x00000001 /* Transmit desc written back */ +#define E1000_ICR_LSC 0x00000004 /* Link Status Change */ +#define E1000_ICR_RXSEQ 0x00000008 /* rx sequence error */ +#define E1000_ICR_RXDMT0 0x00000010 /* rx desc min. threshold (0) */ +#define E1000_ICR_RXT0 0x00000080 /* rx timer intr (ring 0) */ +#define E1000_ICR_INT_ASSERTED 0x80000000 /* If this bit asserted, the driver should claim the interrupt */ + +/* This defines the bits that are set in the Interrupt Mask + * Set/Read Register. Each bit is documented below: + * o RXT0 = Receiver Timer Interrupt (ring 0) + * o TXDW = Transmit Descriptor Written Back + * o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0) + * o RXSEQ = Receive Sequence Error + * o LSC = Link Status Change + */ +#define IMS_ENABLE_MASK ( \ + E1000_IMS_RXT0 | \ + E1000_IMS_TXDW | \ + E1000_IMS_RXDMT0 | \ + E1000_IMS_RXSEQ | \ + E1000_IMS_LSC) + +/* Interrupt Mask Set */ +#define E1000_IMS_TXDW E1000_ICR_TXDW /* Transmit desc written back */ +#define E1000_IMS_LSC E1000_ICR_LSC /* Link Status Change */ +#define E1000_IMS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */ +#define E1000_IMS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */ +#define E1000_IMS_RXT0 E1000_ICR_RXT0 /* rx timer intr */ + +/* Interrupt Cause Set */ +#define E1000_ICS_LSC E1000_ICR_LSC /* Link Status Change */ +#define E1000_ICS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */ + +/* Transmit Descriptor Control */ +#define E1000_TXDCTL_PTHRESH 0x0000003F /* TXDCTL Prefetch Threshold */ +#define E1000_TXDCTL_WTHRESH 0x003F0000 /* TXDCTL Writeback Threshold */ +#define E1000_TXDCTL_FULL_TX_DESC_WB 0x01010000 /* GRAN=1, WTHRESH=1 */ +#define E1000_TXDCTL_MAX_TX_DESC_PREFETCH 0x0100001F /* GRAN=1, PTHRESH=31 */ +#define E1000_TXDCTL_COUNT_DESC 0x00400000 /* Enable the counting of desc. + still to be processed. */ + +/* Flow Control Constants */ +#define FLOW_CONTROL_ADDRESS_LOW 0x00C28001 +#define FLOW_CONTROL_ADDRESS_HIGH 0x00000100 +#define FLOW_CONTROL_TYPE 0x8808 + +/* 802.1q VLAN Packet Size */ +#define E1000_VLAN_FILTER_TBL_SIZE 128 /* VLAN Filter Table (4096 bits) */ + +/* Receive Address */ +/* Number of high/low register pairs in the RAR. The RAR (Receive Address + * Registers) holds the directed and multicast addresses that we monitor. + * Technically, we have 16 spots. However, we reserve one of these spots + * (RAR[15]) for our directed address used by controllers with + * manageability enabled, allowing us room for 15 multicast addresses. + */ +#define E1000_RAR_ENTRIES 15 +#define E1000_RAH_AV 0x80000000 /* Receive descriptor valid */ + +/* Error Codes */ +#define E1000_ERR_NVM 1 +#define E1000_ERR_PHY 2 +#define E1000_ERR_CONFIG 3 +#define E1000_ERR_PARAM 4 +#define E1000_ERR_MAC_INIT 5 +#define E1000_ERR_PHY_TYPE 6 +#define E1000_ERR_RESET 9 +#define E1000_ERR_MASTER_REQUESTS_PENDING 10 +#define E1000_ERR_HOST_INTERFACE_COMMAND 11 +#define E1000_BLK_PHY_RESET 12 +#define E1000_ERR_SWFW_SYNC 13 +#define E1000_NOT_IMPLEMENTED 14 + +/* Loop limit on how long we wait for auto-negotiation to complete */ +#define FIBER_LINK_UP_LIMIT 50 +#define COPPER_LINK_UP_LIMIT 10 +#define PHY_AUTO_NEG_LIMIT 45 +#define PHY_FORCE_LIMIT 20 +/* Number of 100 microseconds we wait for PCI Express master disable */ +#define MASTER_DISABLE_TIMEOUT 800 +/* Number of milliseconds we wait for PHY configuration done after MAC reset */ +#define PHY_CFG_TIMEOUT 100 +/* Number of 2 milliseconds we wait for acquiring MDIO ownership. */ +#define MDIO_OWNERSHIP_TIMEOUT 10 +/* Number of milliseconds for NVM auto read done after MAC reset. */ +#define AUTO_READ_DONE_TIMEOUT 10 + +/* Flow Control */ +#define E1000_FCRTL_XONE 0x80000000 /* Enable XON frame transmission */ + +/* Transmit Configuration Word */ +#define E1000_TXCW_FD 0x00000020 /* TXCW full duplex */ +#define E1000_TXCW_PAUSE 0x00000080 /* TXCW sym pause request */ +#define E1000_TXCW_ASM_DIR 0x00000100 /* TXCW astm pause direction */ +#define E1000_TXCW_PAUSE_MASK 0x00000180 /* TXCW pause request mask */ +#define E1000_TXCW_ANE 0x80000000 /* Auto-neg enable */ + +/* Receive Configuration Word */ +#define E1000_RXCW_IV 0x08000000 /* Receive config invalid */ +#define E1000_RXCW_C 0x20000000 /* Receive config */ +#define E1000_RXCW_SYNCH 0x40000000 /* Receive config synch */ + +/* PCI Express Control */ +#define E1000_GCR_RXD_NO_SNOOP 0x00000001 +#define E1000_GCR_RXDSCW_NO_SNOOP 0x00000002 +#define E1000_GCR_RXDSCR_NO_SNOOP 0x00000004 +#define E1000_GCR_TXD_NO_SNOOP 0x00000008 +#define E1000_GCR_TXDSCW_NO_SNOOP 0x00000010 +#define E1000_GCR_TXDSCR_NO_SNOOP 0x00000020 + +#define PCIE_NO_SNOOP_ALL (E1000_GCR_RXD_NO_SNOOP | \ + E1000_GCR_RXDSCW_NO_SNOOP | \ + E1000_GCR_RXDSCR_NO_SNOOP | \ + E1000_GCR_TXD_NO_SNOOP | \ + E1000_GCR_TXDSCW_NO_SNOOP | \ + E1000_GCR_TXDSCR_NO_SNOOP) + +/* PHY Control Register */ +#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */ +#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */ +#define MII_CR_POWER_DOWN 0x0800 /* Power down */ +#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */ +#define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */ +#define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */ +#define MII_CR_SPEED_1000 0x0040 +#define MII_CR_SPEED_100 0x2000 +#define MII_CR_SPEED_10 0x0000 + +/* PHY Status Register */ +#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */ +#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */ + +/* Autoneg Advertisement Register */ +#define NWAY_AR_10T_HD_CAPS 0x0020 /* 10T Half Duplex Capable */ +#define NWAY_AR_10T_FD_CAPS 0x0040 /* 10T Full Duplex Capable */ +#define NWAY_AR_100TX_HD_CAPS 0x0080 /* 100TX Half Duplex Capable */ +#define NWAY_AR_100TX_FD_CAPS 0x0100 /* 100TX Full Duplex Capable */ +#define NWAY_AR_PAUSE 0x0400 /* Pause operation desired */ +#define NWAY_AR_ASM_DIR 0x0800 /* Asymmetric Pause Direction bit */ + +/* Link Partner Ability Register (Base Page) */ +#define NWAY_LPAR_PAUSE 0x0400 /* LP Pause operation desired */ +#define NWAY_LPAR_ASM_DIR 0x0800 /* LP Asymmetric Pause Direction bit */ + +/* Autoneg Expansion Register */ + +/* 1000BASE-T Control Register */ +#define CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */ +#define CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */ + /* 0=DTE device */ +#define CR_1000T_MS_VALUE 0x0800 /* 1=Configure PHY as Master */ + /* 0=Configure PHY as Slave */ +#define CR_1000T_MS_ENABLE 0x1000 /* 1=Master/Slave manual config value */ + /* 0=Automatic Master/Slave config */ + +/* 1000BASE-T Status Register */ +#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */ +#define SR_1000T_LOCAL_RX_STATUS 0x2000 /* Local receiver OK */ + + +/* PHY 1000 MII Register/Bit Definitions */ +/* PHY Registers defined by IEEE */ +#define PHY_CONTROL 0x00 /* Control Register */ +#define PHY_STATUS 0x01 /* Status Regiser */ +#define PHY_ID1 0x02 /* Phy Id Reg (word 1) */ +#define PHY_ID2 0x03 /* Phy Id Reg (word 2) */ +#define PHY_AUTONEG_ADV 0x04 /* Autoneg Advertisement */ +#define PHY_LP_ABILITY 0x05 /* Link Partner Ability (Base Page) */ +#define PHY_1000T_CTRL 0x09 /* 1000Base-T Control Reg */ +#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */ + +/* NVM Control */ +#define E1000_EECD_SK 0x00000001 /* NVM Clock */ +#define E1000_EECD_CS 0x00000002 /* NVM Chip Select */ +#define E1000_EECD_DI 0x00000004 /* NVM Data In */ +#define E1000_EECD_DO 0x00000008 /* NVM Data Out */ +#define E1000_EECD_REQ 0x00000040 /* NVM Access Request */ +#define E1000_EECD_GNT 0x00000080 /* NVM Access Grant */ +#define E1000_EECD_SIZE 0x00000200 /* NVM Size (0=64 word 1=256 word) */ +#define E1000_EECD_ADDR_BITS 0x00000400 /* NVM Addressing bits based on type + * (0-small, 1-large) */ +#define E1000_NVM_GRANT_ATTEMPTS 1000 /* NVM # attempts to gain grant */ +#define E1000_EECD_AUTO_RD 0x00000200 /* NVM Auto Read done */ +#define E1000_EECD_SIZE_EX_MASK 0x00007800 /* NVM Size */ +#define E1000_EECD_SIZE_EX_SHIFT 11 +#define E1000_EECD_FLUPD 0x00080000 /* Update FLASH */ +#define E1000_EECD_AUPDEN 0x00100000 /* Enable Autonomous FLASH update */ +#define E1000_EECD_SEC1VAL 0x00400000 /* Sector One Valid */ + +#define E1000_NVM_RW_REG_DATA 16 /* Offset to data in NVM read/write registers */ +#define E1000_NVM_RW_REG_DONE 2 /* Offset to READ/WRITE done bit */ +#define E1000_NVM_RW_REG_START 1 /* Start operation */ +#define E1000_NVM_RW_ADDR_SHIFT 2 /* Shift to the address bits */ +#define E1000_NVM_POLL_WRITE 1 /* Flag for polling for write complete */ +#define E1000_NVM_POLL_READ 0 /* Flag for polling for read complete */ +#define E1000_FLASH_UPDATES 2000 + +/* NVM Word Offsets */ +#define NVM_ID_LED_SETTINGS 0x0004 +#define NVM_INIT_CONTROL2_REG 0x000F +#define NVM_INIT_CONTROL3_PORT_B 0x0014 +#define NVM_INIT_3GIO_3 0x001A +#define NVM_INIT_CONTROL3_PORT_A 0x0024 +#define NVM_CFG 0x0012 +#define NVM_CHECKSUM_REG 0x003F + +#define E1000_NVM_CFG_DONE_PORT_0 0x40000 /* MNG config cycle done */ +#define E1000_NVM_CFG_DONE_PORT_1 0x80000 /* ...for second port */ + +/* Mask bits for fields in Word 0x0f of the NVM */ +#define NVM_WORD0F_PAUSE_MASK 0x3000 +#define NVM_WORD0F_PAUSE 0x1000 +#define NVM_WORD0F_ASM_DIR 0x2000 + +/* Mask bits for fields in Word 0x1a of the NVM */ +#define NVM_WORD1A_ASPM_MASK 0x000C + +/* For checksumming, the sum of all words in the NVM should equal 0xBABA. */ +#define NVM_SUM 0xBABA + +/* PBA (printed board assembly) number words */ +#define NVM_PBA_OFFSET_0 8 +#define NVM_PBA_OFFSET_1 9 + +#define NVM_WORD_SIZE_BASE_SHIFT 6 + +/* NVM Commands - SPI */ +#define NVM_MAX_RETRY_SPI 5000 /* Max wait of 5ms, for RDY signal */ +#define NVM_READ_OPCODE_SPI 0x03 /* NVM read opcode */ +#define NVM_WRITE_OPCODE_SPI 0x02 /* NVM write opcode */ +#define NVM_A8_OPCODE_SPI 0x08 /* opcode bit-3 = address bit-8 */ +#define NVM_WREN_OPCODE_SPI 0x06 /* NVM set Write Enable latch */ +#define NVM_RDSR_OPCODE_SPI 0x05 /* NVM read Status register */ + +/* SPI NVM Status Register */ +#define NVM_STATUS_RDY_SPI 0x01 + +/* Word definitions for ID LED Settings */ +#define ID_LED_RESERVED_0000 0x0000 +#define ID_LED_RESERVED_FFFF 0xFFFF +#define ID_LED_DEFAULT ((ID_LED_OFF1_ON2 << 12) | \ + (ID_LED_OFF1_OFF2 << 8) | \ + (ID_LED_DEF1_DEF2 << 4) | \ + (ID_LED_DEF1_DEF2)) +#define ID_LED_DEF1_DEF2 0x1 +#define ID_LED_DEF1_ON2 0x2 +#define ID_LED_DEF1_OFF2 0x3 +#define ID_LED_ON1_DEF2 0x4 +#define ID_LED_ON1_ON2 0x5 +#define ID_LED_ON1_OFF2 0x6 +#define ID_LED_OFF1_DEF2 0x7 +#define ID_LED_OFF1_ON2 0x8 +#define ID_LED_OFF1_OFF2 0x9 + +#define IGP_ACTIVITY_LED_MASK 0xFFFFF0FF +#define IGP_ACTIVITY_LED_ENABLE 0x0300 +#define IGP_LED3_MODE 0x07000000 + +/* PCI/PCI-X/PCI-EX Config space */ +#define PCI_HEADER_TYPE_REGISTER 0x0E +#define PCIE_LINK_STATUS 0x12 + +#define PCI_HEADER_TYPE_MULTIFUNC 0x80 +#define PCIE_LINK_WIDTH_MASK 0x3F0 +#define PCIE_LINK_WIDTH_SHIFT 4 + +#define PHY_REVISION_MASK 0xFFFFFFF0 +#define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */ +#define MAX_PHY_MULTI_PAGE_REG 0xF + +/* Bit definitions for valid PHY IDs. */ +/* I = Integrated + * E = External + */ +#define M88E1000_E_PHY_ID 0x01410C50 +#define M88E1000_I_PHY_ID 0x01410C30 +#define M88E1011_I_PHY_ID 0x01410C20 +#define IGP01E1000_I_PHY_ID 0x02A80380 +#define M88E1111_I_PHY_ID 0x01410CC0 +#define GG82563_E_PHY_ID 0x01410CA0 +#define IGP03E1000_E_PHY_ID 0x02A80390 +#define IFE_E_PHY_ID 0x02A80330 +#define IFE_PLUS_E_PHY_ID 0x02A80320 +#define IFE_C_E_PHY_ID 0x02A80310 + +/* M88E1000 Specific Registers */ +#define M88E1000_PHY_SPEC_CTRL 0x10 /* PHY Specific Control Register */ +#define M88E1000_PHY_SPEC_STATUS 0x11 /* PHY Specific Status Register */ +#define M88E1000_EXT_PHY_SPEC_CTRL 0x14 /* Extended PHY Specific Control */ + +#define M88E1000_PHY_PAGE_SELECT 0x1D /* Reg 29 for page number setting */ +#define M88E1000_PHY_GEN_CONTROL 0x1E /* Its meaning depends on reg 29 */ + +/* M88E1000 PHY Specific Control Register */ +#define M88E1000_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reversal enabled */ +#define M88E1000_PSCR_MDI_MANUAL_MODE 0x0000 /* MDI Crossover Mode bits 6:5 */ + /* Manual MDI configuration */ +#define M88E1000_PSCR_MDIX_MANUAL_MODE 0x0020 /* Manual MDIX configuration */ +#define M88E1000_PSCR_AUTO_X_1000T 0x0040 /* 1000BASE-T: Auto crossover, + * 100BASE-TX/10BASE-T: + * MDI Mode + */ +#define M88E1000_PSCR_AUTO_X_MODE 0x0060 /* Auto crossover enabled + * all speeds. + */ + /* 1=Enable Extended 10BASE-T distance + * (Lower 10BASE-T RX Threshold) + * 0=Normal 10BASE-T RX Threshold */ + /* 1=5-Bit interface in 100BASE-TX + * 0=MII interface in 100BASE-TX */ +#define M88E1000_PSCR_ASSERT_CRS_ON_TX 0x0800 /* 1=Assert CRS on Transmit */ + +/* M88E1000 PHY Specific Status Register */ +#define M88E1000_PSSR_REV_POLARITY 0x0002 /* 1=Polarity reversed */ +#define M88E1000_PSSR_DOWNSHIFT 0x0020 /* 1=Downshifted */ +#define M88E1000_PSSR_MDIX 0x0040 /* 1=MDIX; 0=MDI */ +#define M88E1000_PSSR_CABLE_LENGTH 0x0380 /* 0=<50M;1=50-80M;2=80-110M; + * 3=110-140M;4=>140M */ +#define M88E1000_PSSR_SPEED 0xC000 /* Speed, bits 14:15 */ +#define M88E1000_PSSR_1000MBS 0x8000 /* 10=1000Mbs */ + +#define M88E1000_PSSR_CABLE_LENGTH_SHIFT 7 + +/* Number of times we will attempt to autonegotiate before downshifting if we + * are the master */ +#define M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK 0x0C00 +#define M88E1000_EPSCR_MASTER_DOWNSHIFT_1X 0x0000 +/* Number of times we will attempt to autonegotiate before downshifting if we + * are the slave */ +#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK 0x0300 +#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X 0x0100 +#define M88E1000_EPSCR_TX_CLK_25 0x0070 /* 25 MHz TX_CLK */ + +/* M88EC018 Rev 2 specific DownShift settings */ +#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK 0x0E00 +#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X 0x0800 + +/* Bits... + * 15-5: page + * 4-0: register offset + */ +#define GG82563_PAGE_SHIFT 5 +#define GG82563_REG(page, reg) \ + (((page) << GG82563_PAGE_SHIFT) | ((reg) & MAX_PHY_REG_ADDRESS)) +#define GG82563_MIN_ALT_REG 30 + +/* GG82563 Specific Registers */ +#define GG82563_PHY_SPEC_CTRL \ + GG82563_REG(0, 16) /* PHY Specific Control */ +#define GG82563_PHY_PAGE_SELECT \ + GG82563_REG(0, 22) /* Page Select */ +#define GG82563_PHY_SPEC_CTRL_2 \ + GG82563_REG(0, 26) /* PHY Specific Control 2 */ +#define GG82563_PHY_PAGE_SELECT_ALT \ + GG82563_REG(0, 29) /* Alternate Page Select */ + +#define GG82563_PHY_MAC_SPEC_CTRL \ + GG82563_REG(2, 21) /* MAC Specific Control Register */ + +#define GG82563_PHY_DSP_DISTANCE \ + GG82563_REG(5, 26) /* DSP Distance */ + +/* Page 193 - Port Control Registers */ +#define GG82563_PHY_KMRN_MODE_CTRL \ + GG82563_REG(193, 16) /* Kumeran Mode Control */ +#define GG82563_PHY_PWR_MGMT_CTRL \ + GG82563_REG(193, 20) /* Power Management Control */ + +/* Page 194 - KMRN Registers */ +#define GG82563_PHY_INBAND_CTRL \ + GG82563_REG(194, 18) /* Inband Control */ + +/* MDI Control */ +#define E1000_MDIC_REG_SHIFT 16 +#define E1000_MDIC_PHY_SHIFT 21 +#define E1000_MDIC_OP_WRITE 0x04000000 +#define E1000_MDIC_OP_READ 0x08000000 +#define E1000_MDIC_READY 0x10000000 +#define E1000_MDIC_ERROR 0x40000000 + +/* SerDes Control */ +#define E1000_GEN_POLL_TIMEOUT 640 + +#endif /* _E1000_DEFINES_H_ */ diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h new file mode 100644 index 00000000000..d2499bb07c1 --- /dev/null +++ b/drivers/net/e1000e/e1000.h @@ -0,0 +1,514 @@ +/******************************************************************************* + + Intel PRO/1000 Linux driver + Copyright(c) 1999 - 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +/* Linux PRO/1000 Ethernet Driver main header file */ + +#ifndef _E1000_H_ +#define _E1000_H_ + +#include +#include +#include +#include +#include + +#include "hw.h" + +struct e1000_info; + +#define ndev_printk(level, netdev, format, arg...) \ + printk(level "%s: %s: " format, (netdev)->dev.parent->bus_id, \ + (netdev)->name, ## arg) + +#ifdef DEBUG +#define ndev_dbg(netdev, format, arg...) \ + ndev_printk(KERN_DEBUG , netdev, format, ## arg) +#else +#define ndev_dbg(netdev, format, arg...) do { (void)(netdev); } while (0) +#endif + +#define ndev_err(netdev, format, arg...) \ + ndev_printk(KERN_ERR , netdev, format, ## arg) +#define ndev_info(netdev, format, arg...) \ + ndev_printk(KERN_INFO , netdev, format, ## arg) +#define ndev_warn(netdev, format, arg...) \ + ndev_printk(KERN_WARNING , netdev, format, ## arg) +#define ndev_notice(netdev, format, arg...) \ + ndev_printk(KERN_NOTICE , netdev, format, ## arg) + + +/* TX/RX descriptor defines */ +#define E1000_DEFAULT_TXD 256 +#define E1000_MAX_TXD 4096 +#define E1000_MIN_TXD 80 + +#define E1000_DEFAULT_RXD 256 +#define E1000_MAX_RXD 4096 +#define E1000_MIN_RXD 80 + +/* Early Receive defines */ +#define E1000_ERT_2048 0x100 + +#define E1000_FC_PAUSE_TIME 0x0680 /* 858 usec */ + +/* How many Tx Descriptors do we need to call netif_wake_queue ? */ +/* How many Rx Buffers do we bundle into one write to the hardware ? */ +#define E1000_RX_BUFFER_WRITE 16 /* Must be power of 2 */ + +#define AUTO_ALL_MODES 0 +#define E1000_EEPROM_APME 0x0400 + +#define E1000_MNG_VLAN_NONE (-1) + +/* Number of packet split data buffers (not including the header buffer) */ +#define PS_PAGE_BUFFERS (MAX_PS_BUFFERS - 1) + +enum e1000_boards { + board_82571, + board_82572, + board_82573, + board_80003es2lan, + board_ich8lan, + board_ich9lan, +}; + +struct e1000_queue_stats { + u64 packets; + u64 bytes; +}; + +struct e1000_ps_page { + struct page *page; + u64 dma; /* must be u64 - written to hw */ +}; + +/* + * wrappers around a pointer to a socket buffer, + * so a DMA handle can be stored along with the buffer + */ +struct e1000_buffer { + dma_addr_t dma; + struct sk_buff *skb; + union { + /* TX */ + struct { + unsigned long time_stamp; + u16 length; + u16 next_to_watch; + }; + /* RX */ + struct page *page; + }; + +}; + +struct e1000_ring { + void *desc; /* pointer to ring memory */ + dma_addr_t dma; /* phys address of ring */ + unsigned int size; /* length of ring in bytes */ + unsigned int count; /* number of desc. in ring */ + + u16 next_to_use; + u16 next_to_clean; + + u16 head; + u16 tail; + + /* array of buffer information structs */ + struct e1000_buffer *buffer_info; + + /* arrays of page information for packet split */ + struct e1000_ps_page *ps_pages; + struct sk_buff *rx_skb_top; + + struct e1000_queue_stats stats; +}; + +/* board specific private data structure */ +struct e1000_adapter { + struct timer_list watchdog_timer; + struct timer_list phy_info_timer; + struct timer_list blink_timer; + + struct work_struct reset_task; + struct work_struct watchdog_task; + + const struct e1000_info *ei; + + struct vlan_group *vlgrp; + u32 bd_number; + u32 rx_buffer_len; + u16 mng_vlan_id; + u16 link_speed; + u16 link_duplex; + + spinlock_t tx_queue_lock; /* prevent concurrent tail updates */ + + /* this is still needed for 82571 and above */ + atomic_t irq_sem; + + /* track device up/down/testing state */ + unsigned long state; + + /* Interrupt Throttle Rate */ + u32 itr; + u32 itr_setting; + u16 tx_itr; + u16 rx_itr; + + /* + * TX + */ + struct e1000_ring *tx_ring /* One per active queue */ + ____cacheline_aligned_in_smp; + + struct napi_struct napi; + + unsigned long tx_queue_len; + unsigned int restart_queue; + u32 txd_cmd; + + bool detect_tx_hung; + u8 tx_timeout_factor; + + u32 tx_int_delay; + u32 tx_abs_int_delay; + + unsigned int total_tx_bytes; + unsigned int total_tx_packets; + unsigned int total_rx_bytes; + unsigned int total_rx_packets; + + /* TX stats */ + u64 tpt_old; + u64 colc_old; + u64 gotcl_old; + u32 gotcl; + u32 tx_timeout_count; + u32 tx_fifo_head; + u32 tx_head_addr; + u32 tx_fifo_size; + u32 tx_dma_failed; + + /* + * RX + */ + bool (*clean_rx) (struct e1000_adapter *adapter, + int *work_done, int work_to_do) + ____cacheline_aligned_in_smp; + void (*alloc_rx_buf) (struct e1000_adapter *adapter, + int cleaned_count); + struct e1000_ring *rx_ring; + + u32 rx_int_delay; + u32 rx_abs_int_delay; + + /* RX stats */ + u64 hw_csum_err; + u64 hw_csum_good; + u64 rx_hdr_split; + u64 gorcl_old; + u32 gorcl; + u32 alloc_rx_buff_failed; + u32 rx_dma_failed; + + unsigned int rx_ps_pages; + u16 rx_ps_bsize0; + + /* OS defined structs */ + struct net_device *netdev; + struct pci_dev *pdev; + struct net_device_stats net_stats; + spinlock_t stats_lock; /* prevent concurrent stats updates */ + + /* structs defined in e1000_hw.h */ + struct e1000_hw hw; + + struct e1000_hw_stats stats; + struct e1000_phy_info phy_info; + struct e1000_phy_stats phy_stats; + + struct e1000_ring test_tx_ring; + struct e1000_ring test_rx_ring; + u32 test_icr; + + u32 msg_enable; + + u32 eeprom_wol; + u32 wol; + u32 pba; + + u8 fc_autoneg; + + unsigned long led_status; + + unsigned int flags; +}; + +struct e1000_info { + enum e1000_mac_type mac; + unsigned int flags; + u32 pba; + s32 (*get_invariants)(struct e1000_adapter *); + struct e1000_mac_operations *mac_ops; + struct e1000_phy_operations *phy_ops; + struct e1000_nvm_operations *nvm_ops; +}; + +/* hardware capability, feature, and workaround flags */ +#define FLAG_HAS_AMT (1 << 0) +#define FLAG_HAS_FLASH (1 << 1) +#define FLAG_HAS_HW_VLAN_FILTER (1 << 2) +#define FLAG_HAS_WOL (1 << 3) +#define FLAG_HAS_ERT (1 << 4) +#define FLAG_HAS_CTRLEXT_ON_LOAD (1 << 5) +#define FLAG_HAS_SWSM_ON_LOAD (1 << 6) +#define FLAG_HAS_JUMBO_FRAMES (1 << 7) +#define FLAG_HAS_ASPM (1 << 8) +#define FLAG_HAS_STATS_ICR_ICT (1 << 9) +#define FLAG_HAS_STATS_PTC_PRC (1 << 10) +#define FLAG_HAS_SMART_POWER_DOWN (1 << 11) +#define FLAG_IS_QUAD_PORT_A (1 << 12) +#define FLAG_IS_QUAD_PORT (1 << 13) +#define FLAG_TIPG_MEDIUM_FOR_80003ESLAN (1 << 14) +#define FLAG_APME_IN_WUC (1 << 15) +#define FLAG_APME_IN_CTRL3 (1 << 16) +#define FLAG_APME_CHECK_PORT_B (1 << 17) +#define FLAG_DISABLE_FC_PAUSE_TIME (1 << 18) +#define FLAG_NO_WAKE_UCAST (1 << 19) +#define FLAG_MNG_PT_ENABLED (1 << 20) +#define FLAG_RESET_OVERWRITES_LAA (1 << 21) +#define FLAG_TARC_SPEED_MODE_BIT (1 << 22) +#define FLAG_TARC_SET_BIT_ZERO (1 << 23) +#define FLAG_RX_NEEDS_RESTART (1 << 24) +#define FLAG_LSC_GIG_SPEED_DROP (1 << 25) +#define FLAG_SMART_POWER_DOWN (1 << 26) +#define FLAG_MSI_ENABLED (1 << 27) +#define FLAG_RX_CSUM_ENABLED (1 << 28) +#define FLAG_TSO_FORCE (1 << 29) + +#define E1000_RX_DESC_PS(R, i) \ + (&(((union e1000_rx_desc_packet_split *)((R).desc))[i])) +#define E1000_GET_DESC(R, i, type) (&(((struct type *)((R).desc))[i])) +#define E1000_RX_DESC(R, i) E1000_GET_DESC(R, i, e1000_rx_desc) +#define E1000_TX_DESC(R, i) E1000_GET_DESC(R, i, e1000_tx_desc) +#define E1000_CONTEXT_DESC(R, i) E1000_GET_DESC(R, i, e1000_context_desc) + +enum e1000_state_t { + __E1000_TESTING, + __E1000_RESETTING, + __E1000_DOWN +}; + +enum latency_range { + lowest_latency = 0, + low_latency = 1, + bulk_latency = 2, + latency_invalid = 255 +}; + +extern char e1000e_driver_name[]; +extern const char e1000e_driver_version[]; + +extern void e1000e_check_options(struct e1000_adapter *adapter); +extern void e1000e_set_ethtool_ops(struct net_device *netdev); + +extern int e1000e_up(struct e1000_adapter *adapter); +extern void e1000e_down(struct e1000_adapter *adapter); +extern void e1000e_reinit_locked(struct e1000_adapter *adapter); +extern void e1000e_reset(struct e1000_adapter *adapter); +extern void e1000e_power_up_phy(struct e1000_adapter *adapter); +extern int e1000e_setup_rx_resources(struct e1000_adapter *adapter); +extern int e1000e_setup_tx_resources(struct e1000_adapter *adapter); +extern void e1000e_free_rx_resources(struct e1000_adapter *adapter); +extern void e1000e_free_tx_resources(struct e1000_adapter *adapter); +extern void e1000e_update_stats(struct e1000_adapter *adapter); + +extern unsigned int copybreak; + +extern char *e1000e_get_hw_dev_name(struct e1000_hw *hw); + +extern struct e1000_info e1000_82571_info; +extern struct e1000_info e1000_82572_info; +extern struct e1000_info e1000_82573_info; +extern struct e1000_info e1000_ich8_info; +extern struct e1000_info e1000_ich9_info; +extern struct e1000_info e1000_es2_info; + +extern s32 e1000e_read_part_num(struct e1000_hw *hw, u32 *part_num); + +extern s32 e1000e_commit_phy(struct e1000_hw *hw); + +extern bool e1000e_enable_mng_pass_thru(struct e1000_hw *hw); + +extern bool e1000e_get_laa_state_82571(struct e1000_hw *hw); +extern void e1000e_set_laa_state_82571(struct e1000_hw *hw, bool state); + +extern void e1000e_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw, + bool state); +extern void e1000e_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw); +extern void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw); + +extern s32 e1000e_check_for_copper_link(struct e1000_hw *hw); +extern s32 e1000e_check_for_fiber_link(struct e1000_hw *hw); +extern s32 e1000e_check_for_serdes_link(struct e1000_hw *hw); +extern s32 e1000e_cleanup_led_generic(struct e1000_hw *hw); +extern s32 e1000e_led_on_generic(struct e1000_hw *hw); +extern s32 e1000e_led_off_generic(struct e1000_hw *hw); +extern s32 e1000e_get_bus_info_pcie(struct e1000_hw *hw); +extern s32 e1000e_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 *speed, u16 *duplex); +extern s32 e1000e_get_speed_and_duplex_fiber_serdes(struct e1000_hw *hw, u16 *speed, u16 *duplex); +extern s32 e1000e_disable_pcie_master(struct e1000_hw *hw); +extern s32 e1000e_get_auto_rd_done(struct e1000_hw *hw); +extern s32 e1000e_id_led_init(struct e1000_hw *hw); +extern void e1000e_clear_hw_cntrs_base(struct e1000_hw *hw); +extern s32 e1000e_setup_fiber_serdes_link(struct e1000_hw *hw); +extern s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw); +extern s32 e1000e_copper_link_setup_igp(struct e1000_hw *hw); +extern s32 e1000e_setup_link(struct e1000_hw *hw); +extern void e1000e_clear_vfta(struct e1000_hw *hw); +extern void e1000e_init_rx_addrs(struct e1000_hw *hw, u16 rar_count); +extern void e1000e_mc_addr_list_update_generic(struct e1000_hw *hw, + u8 *mc_addr_list, u32 mc_addr_count, + u32 rar_used_count, u32 rar_count); +extern void e1000e_rar_set(struct e1000_hw *hw, u8 *addr, u32 index); +extern s32 e1000e_set_fc_watermarks(struct e1000_hw *hw); +extern void e1000e_set_pcie_no_snoop(struct e1000_hw *hw, u32 no_snoop); +extern s32 e1000e_get_hw_semaphore(struct e1000_hw *hw); +extern s32 e1000e_valid_led_default(struct e1000_hw *hw, u16 *data); +extern void e1000e_config_collision_dist(struct e1000_hw *hw); +extern s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw); +extern s32 e1000e_force_mac_fc(struct e1000_hw *hw); +extern s32 e1000e_blink_led(struct e1000_hw *hw); +extern void e1000e_write_vfta(struct e1000_hw *hw, u32 offset, u32 value); +extern void e1000e_reset_adaptive(struct e1000_hw *hw); +extern void e1000e_update_adaptive(struct e1000_hw *hw); + +extern s32 e1000e_setup_copper_link(struct e1000_hw *hw); +extern s32 e1000e_get_phy_id(struct e1000_hw *hw); +extern void e1000e_put_hw_semaphore(struct e1000_hw *hw); +extern s32 e1000e_check_reset_block_generic(struct e1000_hw *hw); +extern s32 e1000e_phy_force_speed_duplex_igp(struct e1000_hw *hw); +extern s32 e1000e_get_cable_length_igp_2(struct e1000_hw *hw); +extern s32 e1000e_get_phy_info_igp(struct e1000_hw *hw); +extern s32 e1000e_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data); +extern s32 e1000e_phy_hw_reset_generic(struct e1000_hw *hw); +extern s32 e1000e_set_d3_lplu_state(struct e1000_hw *hw, bool active); +extern s32 e1000e_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data); +extern s32 e1000e_phy_sw_reset(struct e1000_hw *hw); +extern s32 e1000e_phy_force_speed_duplex_m88(struct e1000_hw *hw); +extern s32 e1000e_get_cfg_done(struct e1000_hw *hw); +extern s32 e1000e_get_cable_length_m88(struct e1000_hw *hw); +extern s32 e1000e_get_phy_info_m88(struct e1000_hw *hw); +extern s32 e1000e_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data); +extern s32 e1000e_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data); +extern enum e1000_phy_type e1000e_get_phy_type_from_id(u32 phy_id); +extern void e1000e_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl); +extern s32 e1000e_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data); +extern s32 e1000e_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data); +extern s32 e1000e_phy_has_link_generic(struct e1000_hw *hw, u32 iterations, + u32 usec_interval, bool *success); +extern s32 e1000e_phy_reset_dsp(struct e1000_hw *hw); +extern s32 e1000e_check_downshift(struct e1000_hw *hw); + +static inline s32 e1000_phy_hw_reset(struct e1000_hw *hw) +{ + return hw->phy.ops.reset_phy(hw); +} + +static inline s32 e1000_check_reset_block(struct e1000_hw *hw) +{ + return hw->phy.ops.check_reset_block(hw); +} + +static inline s32 e1e_rphy(struct e1000_hw *hw, u32 offset, u16 *data) +{ + return hw->phy.ops.read_phy_reg(hw, offset, data); +} + +static inline s32 e1e_wphy(struct e1000_hw *hw, u32 offset, u16 data) +{ + return hw->phy.ops.write_phy_reg(hw, offset, data); +} + +static inline s32 e1000_get_cable_length(struct e1000_hw *hw) +{ + return hw->phy.ops.get_cable_length(hw); +} + +extern s32 e1000e_acquire_nvm(struct e1000_hw *hw); +extern s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data); +extern s32 e1000e_update_nvm_checksum_generic(struct e1000_hw *hw); +extern s32 e1000e_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg); +extern s32 e1000e_read_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data); +extern s32 e1000e_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data); +extern s32 e1000e_validate_nvm_checksum_generic(struct e1000_hw *hw); +extern void e1000e_release_nvm(struct e1000_hw *hw); +extern void e1000e_reload_nvm(struct e1000_hw *hw); +extern s32 e1000e_read_mac_addr(struct e1000_hw *hw); + +static inline s32 e1000_validate_nvm_checksum(struct e1000_hw *hw) +{ + return hw->nvm.ops.validate_nvm(hw); +} + +static inline s32 e1000e_update_nvm_checksum(struct e1000_hw *hw) +{ + return hw->nvm.ops.update_nvm(hw); +} + +static inline s32 e1000_read_nvm(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) +{ + return hw->nvm.ops.read_nvm(hw, offset, words, data); +} + +static inline s32 e1000_write_nvm(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) +{ + return hw->nvm.ops.write_nvm(hw, offset, words, data); +} + +static inline s32 e1000_get_phy_info(struct e1000_hw *hw) +{ + return hw->phy.ops.get_phy_info(hw); +} + +extern bool e1000e_check_mng_mode(struct e1000_hw *hw); +extern bool e1000e_enable_tx_pkt_filtering(struct e1000_hw *hw); +extern s32 e1000e_mng_write_dhcp_info(struct e1000_hw *hw, u8 *buffer, u16 length); + +static inline u32 __er32(struct e1000_hw *hw, unsigned long reg) +{ + return readl(hw->hw_addr + reg); +} + +static inline void __ew32(struct e1000_hw *hw, unsigned long reg, u32 val) +{ + writel(val, hw->hw_addr + reg); +} + +#endif /* _E1000_H_ */ diff --git a/drivers/net/e1000e/es2lan.c b/drivers/net/e1000e/es2lan.c new file mode 100644 index 00000000000..88657adf965 --- /dev/null +++ b/drivers/net/e1000e/es2lan.c @@ -0,0 +1,1232 @@ +/******************************************************************************* + + Intel PRO/1000 Linux driver + Copyright(c) 1999 - 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +/* + * 80003ES2LAN Gigabit Ethernet Controller (Copper) + * 80003ES2LAN Gigabit Ethernet Controller (Serdes) + */ + +#include +#include +#include +#include + +#include "e1000.h" + +#define E1000_KMRNCTRLSTA_OFFSET_FIFO_CTRL 0x00 +#define E1000_KMRNCTRLSTA_OFFSET_INB_CTRL 0x02 +#define E1000_KMRNCTRLSTA_OFFSET_HD_CTRL 0x10 + +#define E1000_KMRNCTRLSTA_FIFO_CTRL_RX_BYPASS 0x0008 +#define E1000_KMRNCTRLSTA_FIFO_CTRL_TX_BYPASS 0x0800 +#define E1000_KMRNCTRLSTA_INB_CTRL_DIS_PADDING 0x0010 + +#define E1000_KMRNCTRLSTA_HD_CTRL_10_100_DEFAULT 0x0004 +#define E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT 0x0000 + +#define E1000_TCTL_EXT_GCEX_MASK 0x000FFC00 /* Gigabit Carry Extend Padding */ +#define DEFAULT_TCTL_EXT_GCEX_80003ES2LAN 0x00010000 + +#define DEFAULT_TIPG_IPGT_1000_80003ES2LAN 0x8 +#define DEFAULT_TIPG_IPGT_10_100_80003ES2LAN 0x9 + +/* GG82563 PHY Specific Status Register (Page 0, Register 16 */ +#define GG82563_PSCR_POLARITY_REVERSAL_DISABLE 0x0002 /* 1=Reversal Disab. */ +#define GG82563_PSCR_CROSSOVER_MODE_MASK 0x0060 +#define GG82563_PSCR_CROSSOVER_MODE_MDI 0x0000 /* 00=Manual MDI */ +#define GG82563_PSCR_CROSSOVER_MODE_MDIX 0x0020 /* 01=Manual MDIX */ +#define GG82563_PSCR_CROSSOVER_MODE_AUTO 0x0060 /* 11=Auto crossover */ + +/* PHY Specific Control Register 2 (Page 0, Register 26) */ +#define GG82563_PSCR2_REVERSE_AUTO_NEG 0x2000 + /* 1=Reverse Auto-Negotiation */ + +/* MAC Specific Control Register (Page 2, Register 21) */ +/* Tx clock speed for Link Down and 1000BASE-T for the following speeds */ +#define GG82563_MSCR_TX_CLK_MASK 0x0007 +#define GG82563_MSCR_TX_CLK_10MBPS_2_5 0x0004 +#define GG82563_MSCR_TX_CLK_100MBPS_25 0x0005 +#define GG82563_MSCR_TX_CLK_1000MBPS_25 0x0007 + +#define GG82563_MSCR_ASSERT_CRS_ON_TX 0x0010 /* 1=Assert */ + +/* DSP Distance Register (Page 5, Register 26) */ +#define GG82563_DSPD_CABLE_LENGTH 0x0007 /* 0 = <50M + 1 = 50-80M + 2 = 80-110M + 3 = 110-140M + 4 = >140M */ + +/* Kumeran Mode Control Register (Page 193, Register 16) */ +#define GG82563_KMCR_PASS_FALSE_CARRIER 0x0800 + +/* Power Management Control Register (Page 193, Register 20) */ +#define GG82563_PMCR_ENABLE_ELECTRICAL_IDLE 0x0001 + /* 1=Enable SERDES Electrical Idle */ + +/* In-Band Control Register (Page 194, Register 18) */ +#define GG82563_ICR_DIS_PADDING 0x0010 /* Disable Padding */ + +/* A table for the GG82563 cable length where the range is defined + * with a lower bound at "index" and the upper bound at + * "index + 5". + */ +static const u16 e1000_gg82563_cable_length_table[] = + { 0, 60, 115, 150, 150, 60, 115, 150, 180, 180, 0xFF }; + +static s32 e1000_setup_copper_link_80003es2lan(struct e1000_hw *hw); +static s32 e1000_acquire_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask); +static void e1000_release_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask); +static void e1000_initialize_hw_bits_80003es2lan(struct e1000_hw *hw); +static void e1000_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw); +static s32 e1000_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw); +static s32 e1000_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, u16 duplex); + +/** + * e1000_init_phy_params_80003es2lan - Init ESB2 PHY func ptrs. + * @hw: pointer to the HW structure + * + * This is a function pointer entry point called by the api module. + **/ +static s32 e1000_init_phy_params_80003es2lan(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + + if (hw->media_type != e1000_media_type_copper) { + phy->type = e1000_phy_none; + return 0; + } + + phy->addr = 1; + phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; + phy->reset_delay_us = 100; + phy->type = e1000_phy_gg82563; + + /* This can only be done after all function pointers are setup. */ + ret_val = e1000e_get_phy_id(hw); + + /* Verify phy id */ + if (phy->id != GG82563_E_PHY_ID) + return -E1000_ERR_PHY; + + return ret_val; +} + +/** + * e1000_init_nvm_params_80003es2lan - Init ESB2 NVM func ptrs. + * @hw: pointer to the HW structure + * + * This is a function pointer entry point called by the api module. + **/ +static s32 e1000_init_nvm_params_80003es2lan(struct e1000_hw *hw) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + u32 eecd = er32(EECD); + u16 size; + + nvm->opcode_bits = 8; + nvm->delay_usec = 1; + switch (nvm->override) { + case e1000_nvm_override_spi_large: + nvm->page_size = 32; + nvm->address_bits = 16; + break; + case e1000_nvm_override_spi_small: + nvm->page_size = 8; + nvm->address_bits = 8; + break; + default: + nvm->page_size = eecd & E1000_EECD_ADDR_BITS ? 32 : 8; + nvm->address_bits = eecd & E1000_EECD_ADDR_BITS ? 16 : 8; + break; + } + + nvm->type = e1000_nvm_eeprom_spi; + + size = (u16)((eecd & E1000_EECD_SIZE_EX_MASK) >> + E1000_EECD_SIZE_EX_SHIFT); + + /* Added to a constant, "size" becomes the left-shift value + * for setting word_size. + */ + size += NVM_WORD_SIZE_BASE_SHIFT; + nvm->word_size = 1 << size; + + return 0; +} + +/** + * e1000_init_mac_params_80003es2lan - Init ESB2 MAC func ptrs. + * @hw: pointer to the HW structure + * + * This is a function pointer entry point called by the api module. + **/ +static s32 e1000_init_mac_params_80003es2lan(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + struct e1000_mac_info *mac = &hw->mac; + struct e1000_mac_operations *func = &mac->ops; + + /* Set media type */ + switch (adapter->pdev->device) { + case E1000_DEV_ID_80003ES2LAN_SERDES_DPT: + hw->media_type = e1000_media_type_internal_serdes; + break; + default: + hw->media_type = e1000_media_type_copper; + break; + } + + /* Set mta register count */ + mac->mta_reg_count = 128; + /* Set rar entry count */ + mac->rar_entry_count = E1000_RAR_ENTRIES; + /* Set if manageability features are enabled. */ + mac->arc_subsystem_valid = + (er32(FWSM) & E1000_FWSM_MODE_MASK) ? 1 : 0; + + /* check for link */ + switch (hw->media_type) { + case e1000_media_type_copper: + func->setup_physical_interface = e1000_setup_copper_link_80003es2lan; + func->check_for_link = e1000e_check_for_copper_link; + break; + case e1000_media_type_fiber: + func->setup_physical_interface = e1000e_setup_fiber_serdes_link; + func->check_for_link = e1000e_check_for_fiber_link; + break; + case e1000_media_type_internal_serdes: + func->setup_physical_interface = e1000e_setup_fiber_serdes_link; + func->check_for_link = e1000e_check_for_serdes_link; + break; + default: + return -E1000_ERR_CONFIG; + break; + } + + return 0; +} + +static s32 e1000_get_invariants_80003es2lan(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + s32 rc; + + rc = e1000_init_mac_params_80003es2lan(adapter); + if (rc) + return rc; + + rc = e1000_init_nvm_params_80003es2lan(hw); + if (rc) + return rc; + + rc = e1000_init_phy_params_80003es2lan(hw); + if (rc) + return rc; + + return 0; +} + +/** + * e1000_acquire_phy_80003es2lan - Acquire rights to access PHY + * @hw: pointer to the HW structure + * + * A wrapper to acquire access rights to the correct PHY. This is a + * function pointer entry point called by the api module. + **/ +static s32 e1000_acquire_phy_80003es2lan(struct e1000_hw *hw) +{ + u16 mask; + + mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM; + + return e1000_acquire_swfw_sync_80003es2lan(hw, mask); +} + +/** + * e1000_release_phy_80003es2lan - Release rights to access PHY + * @hw: pointer to the HW structure + * + * A wrapper to release access rights to the correct PHY. This is a + * function pointer entry point called by the api module. + **/ +static void e1000_release_phy_80003es2lan(struct e1000_hw *hw) +{ + u16 mask; + + mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM; + e1000_release_swfw_sync_80003es2lan(hw, mask); +} + +/** + * e1000_acquire_nvm_80003es2lan - Acquire rights to access NVM + * @hw: pointer to the HW structure + * + * Acquire the semaphore to access the EEPROM. This is a function + * pointer entry point called by the api module. + **/ +static s32 e1000_acquire_nvm_80003es2lan(struct e1000_hw *hw) +{ + s32 ret_val; + + ret_val = e1000_acquire_swfw_sync_80003es2lan(hw, E1000_SWFW_EEP_SM); + if (ret_val) + return ret_val; + + ret_val = e1000e_acquire_nvm(hw); + + if (ret_val) + e1000_release_swfw_sync_80003es2lan(hw, E1000_SWFW_EEP_SM); + + return ret_val; +} + +/** + * e1000_release_nvm_80003es2lan - Relinquish rights to access NVM + * @hw: pointer to the HW structure + * + * Release the semaphore used to access the EEPROM. This is a + * function pointer entry point called by the api module. + **/ +static void e1000_release_nvm_80003es2lan(struct e1000_hw *hw) +{ + e1000e_release_nvm(hw); + e1000_release_swfw_sync_80003es2lan(hw, E1000_SWFW_EEP_SM); +} + +/** + * e1000_acquire_swfw_sync_80003es2lan - Acquire SW/FW semaphore + * @hw: pointer to the HW structure + * @mask: specifies which semaphore to acquire + * + * Acquire the SW/FW semaphore to access the PHY or NVM. The mask + * will also specify which port we're acquiring the lock for. + **/ +static s32 e1000_acquire_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask) +{ + u32 swfw_sync; + u32 swmask = mask; + u32 fwmask = mask << 16; + s32 i = 0; + s32 timeout = 200; + + while (i < timeout) { + if (e1000e_get_hw_semaphore(hw)) + return -E1000_ERR_SWFW_SYNC; + + swfw_sync = er32(SW_FW_SYNC); + if (!(swfw_sync & (fwmask | swmask))) + break; + + /* Firmware currently using resource (fwmask) + * or other software thread using resource (swmask) */ + e1000e_put_hw_semaphore(hw); + mdelay(5); + i++; + } + + if (i == timeout) { + hw_dbg(hw, + "Driver can't access resource, SW_FW_SYNC timeout.\n"); + return -E1000_ERR_SWFW_SYNC; + } + + swfw_sync |= swmask; + ew32(SW_FW_SYNC, swfw_sync); + + e1000e_put_hw_semaphore(hw); + + return 0; +} + +/** + * e1000_release_swfw_sync_80003es2lan - Release SW/FW semaphore + * @hw: pointer to the HW structure + * @mask: specifies which semaphore to acquire + * + * Release the SW/FW semaphore used to access the PHY or NVM. The mask + * will also specify which port we're releasing the lock for. + **/ +static void e1000_release_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask) +{ + u32 swfw_sync; + + while (e1000e_get_hw_semaphore(hw) != 0); + /* Empty */ + + swfw_sync = er32(SW_FW_SYNC); + swfw_sync &= ~mask; + ew32(SW_FW_SYNC, swfw_sync); + + e1000e_put_hw_semaphore(hw); +} + +/** + * e1000_read_phy_reg_gg82563_80003es2lan - Read GG82563 PHY register + * @hw: pointer to the HW structure + * @offset: offset of the register to read + * @data: pointer to the data returned from the operation + * + * Read the GG82563 PHY register. This is a function pointer entry + * point called by the api module. + **/ +static s32 e1000_read_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw, + u32 offset, u16 *data) +{ + s32 ret_val; + u32 page_select; + u16 temp; + + /* Select Configuration Page */ + if ((offset & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG) + page_select = GG82563_PHY_PAGE_SELECT; + else + /* Use Alternative Page Select register to access + * registers 30 and 31 + */ + page_select = GG82563_PHY_PAGE_SELECT_ALT; + + temp = (u16)((u16)offset >> GG82563_PAGE_SHIFT); + ret_val = e1000e_write_phy_reg_m88(hw, page_select, temp); + if (ret_val) + return ret_val; + + /* The "ready" bit in the MDIC register may be incorrectly set + * before the device has completed the "Page Select" MDI + * transaction. So we wait 200us after each MDI command... + */ + udelay(200); + + /* ...and verify the command was successful. */ + ret_val = e1000e_read_phy_reg_m88(hw, page_select, &temp); + + if (((u16)offset >> GG82563_PAGE_SHIFT) != temp) { + ret_val = -E1000_ERR_PHY; + return ret_val; + } + + udelay(200); + + ret_val = e1000e_read_phy_reg_m88(hw, + MAX_PHY_REG_ADDRESS & offset, + data); + + udelay(200); + + return ret_val; +} + +/** + * e1000_write_phy_reg_gg82563_80003es2lan - Write GG82563 PHY register + * @hw: pointer to the HW structure + * @offset: offset of the register to read + * @data: value to write to the register + * + * Write to the GG82563 PHY register. This is a function pointer entry + * point called by the api module. + **/ +static s32 e1000_write_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw, + u32 offset, u16 data) +{ + s32 ret_val; + u32 page_select; + u16 temp; + + /* Select Configuration Page */ + if ((offset & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG) + page_select = GG82563_PHY_PAGE_SELECT; + else + /* Use Alternative Page Select register to access + * registers 30 and 31 + */ + page_select = GG82563_PHY_PAGE_SELECT_ALT; + + temp = (u16)((u16)offset >> GG82563_PAGE_SHIFT); + ret_val = e1000e_write_phy_reg_m88(hw, page_select, temp); + if (ret_val) + return ret_val; + + + /* The "ready" bit in the MDIC register may be incorrectly set + * before the device has completed the "Page Select" MDI + * transaction. So we wait 200us after each MDI command... + */ + udelay(200); + + /* ...and verify the command was successful. */ + ret_val = e1000e_read_phy_reg_m88(hw, page_select, &temp); + + if (((u16)offset >> GG82563_PAGE_SHIFT) != temp) + return -E1000_ERR_PHY; + + udelay(200); + + ret_val = e1000e_write_phy_reg_m88(hw, + MAX_PHY_REG_ADDRESS & offset, + data); + + udelay(200); + + return ret_val; +} + +/** + * e1000_write_nvm_80003es2lan - Write to ESB2 NVM + * @hw: pointer to the HW structure + * @offset: offset of the register to read + * @words: number of words to write + * @data: buffer of data to write to the NVM + * + * Write "words" of data to the ESB2 NVM. This is a function + * pointer entry point called by the api module. + **/ +static s32 e1000_write_nvm_80003es2lan(struct e1000_hw *hw, u16 offset, + u16 words, u16 *data) +{ + return e1000e_write_nvm_spi(hw, offset, words, data); +} + +/** + * e1000_get_cfg_done_80003es2lan - Wait for configuration to complete + * @hw: pointer to the HW structure + * + * Wait a specific amount of time for manageability processes to complete. + * This is a function pointer entry point called by the phy module. + **/ +static s32 e1000_get_cfg_done_80003es2lan(struct e1000_hw *hw) +{ + s32 timeout = PHY_CFG_TIMEOUT; + u32 mask = E1000_NVM_CFG_DONE_PORT_0; + + if (hw->bus.func == 1) + mask = E1000_NVM_CFG_DONE_PORT_1; + + while (timeout) { + if (er32(EEMNGCTL) & mask) + break; + msleep(1); + timeout--; + } + if (!timeout) { + hw_dbg(hw, "MNG configuration cycle has not completed.\n"); + return -E1000_ERR_RESET; + } + + return 0; +} + +/** + * e1000_phy_force_speed_duplex_80003es2lan - Force PHY speed and duplex + * @hw: pointer to the HW structure + * + * Force the speed and duplex settings onto the PHY. This is a + * function pointer entry point called by the phy module. + **/ +static s32 e1000_phy_force_speed_duplex_80003es2lan(struct e1000_hw *hw) +{ + s32 ret_val; + u16 phy_data; + bool link; + + /* Clear Auto-Crossover to force MDI manually. M88E1000 requires MDI + * forced whenever speed and duplex are forced. + */ + ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); + if (ret_val) + return ret_val; + + phy_data &= ~GG82563_PSCR_CROSSOVER_MODE_AUTO; + ret_val = e1e_wphy(hw, GG82563_PHY_SPEC_CTRL, phy_data); + if (ret_val) + return ret_val; + + hw_dbg(hw, "GG82563 PSCR: %X\n", phy_data); + + ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_data); + if (ret_val) + return ret_val; + + e1000e_phy_force_speed_duplex_setup(hw, &phy_data); + + /* Reset the phy to commit changes. */ + phy_data |= MII_CR_RESET; + + ret_val = e1e_wphy(hw, PHY_CONTROL, phy_data); + if (ret_val) + return ret_val; + + udelay(1); + + if (hw->phy.wait_for_link) { + hw_dbg(hw, "Waiting for forced speed/duplex link " + "on GG82563 phy.\n"); + + ret_val = e1000e_phy_has_link_generic(hw, PHY_FORCE_LIMIT, + 100000, &link); + if (ret_val) + return ret_val; + + if (!link) { + /* We didn't get link. + * Reset the DSP and cross our fingers. + */ + ret_val = e1000e_phy_reset_dsp(hw); + if (ret_val) + return ret_val; + } + + /* Try once more */ + ret_val = e1000e_phy_has_link_generic(hw, PHY_FORCE_LIMIT, + 100000, &link); + if (ret_val) + return ret_val; + } + + ret_val = e1e_rphy(hw, GG82563_PHY_MAC_SPEC_CTRL, &phy_data); + if (ret_val) + return ret_val; + + /* Resetting the phy means we need to verify the TX_CLK corresponds + * to the link speed. 10Mbps -> 2.5MHz, else 25MHz. + */ + phy_data &= ~GG82563_MSCR_TX_CLK_MASK; + if (hw->mac.forced_speed_duplex & E1000_ALL_10_SPEED) + phy_data |= GG82563_MSCR_TX_CLK_10MBPS_2_5; + else + phy_data |= GG82563_MSCR_TX_CLK_100MBPS_25; + + /* In addition, we must re-enable CRS on Tx for both half and full + * duplex. + */ + phy_data |= GG82563_MSCR_ASSERT_CRS_ON_TX; + ret_val = e1e_wphy(hw, GG82563_PHY_MAC_SPEC_CTRL, phy_data); + + return ret_val; +} + +/** + * e1000_get_cable_length_80003es2lan - Set approximate cable length + * @hw: pointer to the HW structure + * + * Find the approximate cable length as measured by the GG82563 PHY. + * This is a function pointer entry point called by the phy module. + **/ +static s32 e1000_get_cable_length_80003es2lan(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_data; + u16 index; + + ret_val = e1e_rphy(hw, GG82563_PHY_DSP_DISTANCE, &phy_data); + if (ret_val) + return ret_val; + + index = phy_data & GG82563_DSPD_CABLE_LENGTH; + phy->min_cable_length = e1000_gg82563_cable_length_table[index]; + phy->max_cable_length = e1000_gg82563_cable_length_table[index+5]; + + phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2; + + return 0; +} + +/** + * e1000_get_link_up_info_80003es2lan - Report speed and duplex + * @hw: pointer to the HW structure + * @speed: pointer to speed buffer + * @duplex: pointer to duplex buffer + * + * Retrieve the current speed and duplex configuration. + * This is a function pointer entry point called by the api module. + **/ +static s32 e1000_get_link_up_info_80003es2lan(struct e1000_hw *hw, u16 *speed, + u16 *duplex) +{ + s32 ret_val; + + if (hw->media_type == e1000_media_type_copper) { + ret_val = e1000e_get_speed_and_duplex_copper(hw, + speed, + duplex); + if (ret_val) + return ret_val; + if (*speed == SPEED_1000) + ret_val = e1000_cfg_kmrn_1000_80003es2lan(hw); + else + ret_val = e1000_cfg_kmrn_10_100_80003es2lan(hw, + *duplex); + } else { + ret_val = e1000e_get_speed_and_duplex_fiber_serdes(hw, + speed, + duplex); + } + + return ret_val; +} + +/** + * e1000_reset_hw_80003es2lan - Reset the ESB2 controller + * @hw: pointer to the HW structure + * + * Perform a global reset to the ESB2 controller. + * This is a function pointer entry point called by the api module. + **/ +static s32 e1000_reset_hw_80003es2lan(struct e1000_hw *hw) +{ + u32 ctrl; + u32 icr; + s32 ret_val; + + /* Prevent the PCI-E bus from sticking if there is no TLP connection + * on the last TLP read/write transaction when MAC is reset. + */ + ret_val = e1000e_disable_pcie_master(hw); + if (ret_val) + hw_dbg(hw, "PCI-E Master disable polling has failed.\n"); + + hw_dbg(hw, "Masking off all interrupts\n"); + ew32(IMC, 0xffffffff); + + ew32(RCTL, 0); + ew32(TCTL, E1000_TCTL_PSP); + e1e_flush(); + + msleep(10); + + ctrl = er32(CTRL); + + hw_dbg(hw, "Issuing a global reset to MAC\n"); + ew32(CTRL, ctrl | E1000_CTRL_RST); + + ret_val = e1000e_get_auto_rd_done(hw); + if (ret_val) + /* We don't want to continue accessing MAC registers. */ + return ret_val; + + /* Clear any pending interrupt events. */ + ew32(IMC, 0xffffffff); + icr = er32(ICR); + + return 0; +} + +/** + * e1000_init_hw_80003es2lan - Initialize the ESB2 controller + * @hw: pointer to the HW structure + * + * Initialize the hw bits, LED, VFTA, MTA, link and hw counters. + * This is a function pointer entry point called by the api module. + **/ +static s32 e1000_init_hw_80003es2lan(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + u32 reg_data; + s32 ret_val; + u16 i; + + e1000_initialize_hw_bits_80003es2lan(hw); + + /* Initialize identification LED */ + ret_val = e1000e_id_led_init(hw); + if (ret_val) { + hw_dbg(hw, "Error initializing identification LED\n"); + return ret_val; + } + + /* Disabling VLAN filtering */ + hw_dbg(hw, "Initializing the IEEE VLAN\n"); + e1000e_clear_vfta(hw); + + /* Setup the receive address. */ + e1000e_init_rx_addrs(hw, mac->rar_entry_count); + + /* Zero out the Multicast HASH table */ + hw_dbg(hw, "Zeroing the MTA\n"); + for (i = 0; i < mac->mta_reg_count; i++) + E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0); + + /* Setup link and flow control */ + ret_val = e1000e_setup_link(hw); + + /* Set the transmit descriptor write-back policy */ + reg_data = er32(TXDCTL); + reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) | + E1000_TXDCTL_FULL_TX_DESC_WB | E1000_TXDCTL_COUNT_DESC; + ew32(TXDCTL, reg_data); + + /* ...for both queues. */ + reg_data = er32(TXDCTL1); + reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) | + E1000_TXDCTL_FULL_TX_DESC_WB | E1000_TXDCTL_COUNT_DESC; + ew32(TXDCTL1, reg_data); + + /* Enable retransmit on late collisions */ + reg_data = er32(TCTL); + reg_data |= E1000_TCTL_RTLC; + ew32(TCTL, reg_data); + + /* Configure Gigabit Carry Extend Padding */ + reg_data = er32(TCTL_EXT); + reg_data &= ~E1000_TCTL_EXT_GCEX_MASK; + reg_data |= DEFAULT_TCTL_EXT_GCEX_80003ES2LAN; + ew32(TCTL_EXT, reg_data); + + /* Configure Transmit Inter-Packet Gap */ + reg_data = er32(TIPG); + reg_data &= ~E1000_TIPG_IPGT_MASK; + reg_data |= DEFAULT_TIPG_IPGT_1000_80003ES2LAN; + ew32(TIPG, reg_data); + + reg_data = E1000_READ_REG_ARRAY(hw, E1000_FFLT, 0x0001); + reg_data &= ~0x00100000; + E1000_WRITE_REG_ARRAY(hw, E1000_FFLT, 0x0001, reg_data); + + /* Clear all of the statistics registers (clear on read). It is + * important that we do this after we have tried to establish link + * because the symbol error count will increment wildly if there + * is no link. + */ + e1000_clear_hw_cntrs_80003es2lan(hw); + + return ret_val; +} + +/** + * e1000_initialize_hw_bits_80003es2lan - Init hw bits of ESB2 + * @hw: pointer to the HW structure + * + * Initializes required hardware-dependent bits needed for normal operation. + **/ +static void e1000_initialize_hw_bits_80003es2lan(struct e1000_hw *hw) +{ + u32 reg; + + /* Transmit Descriptor Control 0 */ + reg = er32(TXDCTL); + reg |= (1 << 22); + ew32(TXDCTL, reg); + + /* Transmit Descriptor Control 1 */ + reg = er32(TXDCTL1); + reg |= (1 << 22); + ew32(TXDCTL1, reg); + + /* Transmit Arbitration Control 0 */ + reg = er32(TARC0); + reg &= ~(0xF << 27); /* 30:27 */ + if (hw->media_type != e1000_media_type_copper) + reg &= ~(1 << 20); + ew32(TARC0, reg); + + /* Transmit Arbitration Control 1 */ + reg = er32(TARC1); + if (er32(TCTL) & E1000_TCTL_MULR) + reg &= ~(1 << 28); + else + reg |= (1 << 28); + ew32(TARC1, reg); +} + +/** + * e1000_copper_link_setup_gg82563_80003es2lan - Configure GG82563 Link + * @hw: pointer to the HW structure + * + * Setup some GG82563 PHY registers for obtaining link + **/ +static s32 e1000_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u32 ctrl_ext; + u16 data; + + ret_val = e1e_rphy(hw, GG82563_PHY_MAC_SPEC_CTRL, + &data); + if (ret_val) + return ret_val; + + data |= GG82563_MSCR_ASSERT_CRS_ON_TX; + /* Use 25MHz for both link down and 1000Base-T for Tx clock. */ + data |= GG82563_MSCR_TX_CLK_1000MBPS_25; + + ret_val = e1e_wphy(hw, GG82563_PHY_MAC_SPEC_CTRL, + data); + if (ret_val) + return ret_val; + + /* Options: + * MDI/MDI-X = 0 (default) + * 0 - Auto for all speeds + * 1 - MDI mode + * 2 - MDI-X mode + * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes) + */ + ret_val = e1e_rphy(hw, GG82563_PHY_SPEC_CTRL, &data); + if (ret_val) + return ret_val; + + data &= ~GG82563_PSCR_CROSSOVER_MODE_MASK; + + switch (phy->mdix) { + case 1: + data |= GG82563_PSCR_CROSSOVER_MODE_MDI; + break; + case 2: + data |= GG82563_PSCR_CROSSOVER_MODE_MDIX; + break; + case 0: + default: + data |= GG82563_PSCR_CROSSOVER_MODE_AUTO; + break; + } + + /* Options: + * disable_polarity_correction = 0 (default) + * Automatic Correction for Reversed Cable Polarity + * 0 - Disabled + * 1 - Enabled + */ + data &= ~GG82563_PSCR_POLARITY_REVERSAL_DISABLE; + if (phy->disable_polarity_correction) + data |= GG82563_PSCR_POLARITY_REVERSAL_DISABLE; + + ret_val = e1e_wphy(hw, GG82563_PHY_SPEC_CTRL, data); + if (ret_val) + return ret_val; + + /* SW Reset the PHY so all changes take effect */ + ret_val = e1000e_commit_phy(hw); + if (ret_val) { + hw_dbg(hw, "Error Resetting the PHY\n"); + return ret_val; + } + + /* Bypass RX and TX FIFO's */ + ret_val = e1000e_write_kmrn_reg(hw, + E1000_KMRNCTRLSTA_OFFSET_FIFO_CTRL, + E1000_KMRNCTRLSTA_FIFO_CTRL_RX_BYPASS | + E1000_KMRNCTRLSTA_FIFO_CTRL_TX_BYPASS); + if (ret_val) + return ret_val; + + ret_val = e1e_rphy(hw, GG82563_PHY_SPEC_CTRL_2, &data); + if (ret_val) + return ret_val; + + data &= ~GG82563_PSCR2_REVERSE_AUTO_NEG; + ret_val = e1e_wphy(hw, GG82563_PHY_SPEC_CTRL_2, data); + if (ret_val) + return ret_val; + + ctrl_ext = er32(CTRL_EXT); + ctrl_ext &= ~(E1000_CTRL_EXT_LINK_MODE_MASK); + ew32(CTRL_EXT, ctrl_ext); + + ret_val = e1e_rphy(hw, GG82563_PHY_PWR_MGMT_CTRL, &data); + if (ret_val) + return ret_val; + + /* Do not init these registers when the HW is in IAMT mode, since the + * firmware will have already initialized them. We only initialize + * them if the HW is not in IAMT mode. + */ + if (!e1000e_check_mng_mode(hw)) { + /* Enable Electrical Idle on the PHY */ + data |= GG82563_PMCR_ENABLE_ELECTRICAL_IDLE; + ret_val = e1e_wphy(hw, GG82563_PHY_PWR_MGMT_CTRL, data); + if (ret_val) + return ret_val; + + ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, &data); + if (ret_val) + return ret_val; + + data &= ~GG82563_KMCR_PASS_FALSE_CARRIER; + ret_val = e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, data); + if (ret_val) + return ret_val; + } + + /* Workaround: Disable padding in Kumeran interface in the MAC + * and in the PHY to avoid CRC errors. + */ + ret_val = e1e_rphy(hw, GG82563_PHY_INBAND_CTRL, &data); + if (ret_val) + return ret_val; + + data |= GG82563_ICR_DIS_PADDING; + ret_val = e1e_wphy(hw, GG82563_PHY_INBAND_CTRL, data); + if (ret_val) + return ret_val; + + return 0; +} + +/** + * e1000_setup_copper_link_80003es2lan - Setup Copper Link for ESB2 + * @hw: pointer to the HW structure + * + * Essentially a wrapper for setting up all things "copper" related. + * This is a function pointer entry point called by the mac module. + **/ +static s32 e1000_setup_copper_link_80003es2lan(struct e1000_hw *hw) +{ + u32 ctrl; + s32 ret_val; + u16 reg_data; + + ctrl = er32(CTRL); + ctrl |= E1000_CTRL_SLU; + ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); + ew32(CTRL, ctrl); + + /* Set the mac to wait the maximum time between each + * iteration and increase the max iterations when + * polling the phy; this fixes erroneous timeouts at 10Mbps. */ + ret_val = e1000e_write_kmrn_reg(hw, GG82563_REG(0x34, 4), 0xFFFF); + if (ret_val) + return ret_val; + ret_val = e1000e_read_kmrn_reg(hw, GG82563_REG(0x34, 9), ®_data); + if (ret_val) + return ret_val; + reg_data |= 0x3F; + ret_val = e1000e_write_kmrn_reg(hw, GG82563_REG(0x34, 9), reg_data); + if (ret_val) + return ret_val; + ret_val = e1000e_read_kmrn_reg(hw, + E1000_KMRNCTRLSTA_OFFSET_INB_CTRL, + ®_data); + if (ret_val) + return ret_val; + reg_data |= E1000_KMRNCTRLSTA_INB_CTRL_DIS_PADDING; + ret_val = e1000e_write_kmrn_reg(hw, + E1000_KMRNCTRLSTA_OFFSET_INB_CTRL, + reg_data); + if (ret_val) + return ret_val; + + ret_val = e1000_copper_link_setup_gg82563_80003es2lan(hw); + if (ret_val) + return ret_val; + + ret_val = e1000e_setup_copper_link(hw); + + return 0; +} + +/** + * e1000_cfg_kmrn_10_100_80003es2lan - Apply "quirks" for 10/100 operation + * @hw: pointer to the HW structure + * @duplex: current duplex setting + * + * Configure the KMRN interface by applying last minute quirks for + * 10/100 operation. + **/ +static s32 e1000_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, u16 duplex) +{ + s32 ret_val; + u32 tipg; + u16 reg_data; + + reg_data = E1000_KMRNCTRLSTA_HD_CTRL_10_100_DEFAULT; + ret_val = e1000e_write_kmrn_reg(hw, + E1000_KMRNCTRLSTA_OFFSET_HD_CTRL, + reg_data); + if (ret_val) + return ret_val; + + /* Configure Transmit Inter-Packet Gap */ + tipg = er32(TIPG); + tipg &= ~E1000_TIPG_IPGT_MASK; + tipg |= DEFAULT_TIPG_IPGT_10_100_80003ES2LAN; + ew32(TIPG, tipg); + + ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, ®_data); + if (ret_val) + return ret_val; + + if (duplex == HALF_DUPLEX) + reg_data |= GG82563_KMCR_PASS_FALSE_CARRIER; + else + reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER; + + ret_val = e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data); + + return 0; +} + +/** + * e1000_cfg_kmrn_1000_80003es2lan - Apply "quirks" for gigabit operation + * @hw: pointer to the HW structure + * + * Configure the KMRN interface by applying last minute quirks for + * gigabit operation. + **/ +static s32 e1000_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw) +{ + s32 ret_val; + u16 reg_data; + u32 tipg; + + reg_data = E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT; + ret_val = e1000e_write_kmrn_reg(hw, + E1000_KMRNCTRLSTA_OFFSET_HD_CTRL, + reg_data); + if (ret_val) + return ret_val; + + /* Configure Transmit Inter-Packet Gap */ + tipg = er32(TIPG); + tipg &= ~E1000_TIPG_IPGT_MASK; + tipg |= DEFAULT_TIPG_IPGT_1000_80003ES2LAN; + ew32(TIPG, tipg); + + ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, ®_data); + if (ret_val) + return ret_val; + + reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER; + ret_val = e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data); + + return ret_val; +} + +/** + * e1000_clear_hw_cntrs_80003es2lan - Clear device specific hardware counters + * @hw: pointer to the HW structure + * + * Clears the hardware counters by reading the counter registers. + **/ +static void e1000_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw) +{ + u32 temp; + + e1000e_clear_hw_cntrs_base(hw); + + temp = er32(PRC64); + temp = er32(PRC127); + temp = er32(PRC255); + temp = er32(PRC511); + temp = er32(PRC1023); + temp = er32(PRC1522); + temp = er32(PTC64); + temp = er32(PTC127); + temp = er32(PTC255); + temp = er32(PTC511); + temp = er32(PTC1023); + temp = er32(PTC1522); + + temp = er32(ALGNERRC); + temp = er32(RXERRC); + temp = er32(TNCRS); + temp = er32(CEXTERR); + temp = er32(TSCTC); + temp = er32(TSCTFC); + + temp = er32(MGTPRC); + temp = er32(MGTPDC); + temp = er32(MGTPTC); + + temp = er32(IAC); + temp = er32(ICRXOC); + + temp = er32(ICRXPTC); + temp = er32(ICRXATC); + temp = er32(ICTXPTC); + temp = er32(ICTXATC); + temp = er32(ICTXQEC); + temp = er32(ICTXQMTC); + temp = er32(ICRXDMTC); +} + +static struct e1000_mac_operations es2_mac_ops = { + .mng_mode_enab = E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT, + /* check_for_link dependent on media type */ + .cleanup_led = e1000e_cleanup_led_generic, + .clear_hw_cntrs = e1000_clear_hw_cntrs_80003es2lan, + .get_bus_info = e1000e_get_bus_info_pcie, + .get_link_up_info = e1000_get_link_up_info_80003es2lan, + .led_on = e1000e_led_on_generic, + .led_off = e1000e_led_off_generic, + .mc_addr_list_update = e1000e_mc_addr_list_update_generic, + .reset_hw = e1000_reset_hw_80003es2lan, + .init_hw = e1000_init_hw_80003es2lan, + .setup_link = e1000e_setup_link, + /* setup_physical_interface dependent on media type */ +}; + +static struct e1000_phy_operations es2_phy_ops = { + .acquire_phy = e1000_acquire_phy_80003es2lan, + .check_reset_block = e1000e_check_reset_block_generic, + .commit_phy = e1000e_phy_sw_reset, + .force_speed_duplex = e1000_phy_force_speed_duplex_80003es2lan, + .get_cfg_done = e1000_get_cfg_done_80003es2lan, + .get_cable_length = e1000_get_cable_length_80003es2lan, + .get_phy_info = e1000e_get_phy_info_m88, + .read_phy_reg = e1000_read_phy_reg_gg82563_80003es2lan, + .release_phy = e1000_release_phy_80003es2lan, + .reset_phy = e1000e_phy_hw_reset_generic, + .set_d0_lplu_state = NULL, + .set_d3_lplu_state = e1000e_set_d3_lplu_state, + .write_phy_reg = e1000_write_phy_reg_gg82563_80003es2lan, +}; + +static struct e1000_nvm_operations es2_nvm_ops = { + .acquire_nvm = e1000_acquire_nvm_80003es2lan, + .read_nvm = e1000e_read_nvm_eerd, + .release_nvm = e1000_release_nvm_80003es2lan, + .update_nvm = e1000e_update_nvm_checksum_generic, + .valid_led_default = e1000e_valid_led_default, + .validate_nvm = e1000e_validate_nvm_checksum_generic, + .write_nvm = e1000_write_nvm_80003es2lan, +}; + +struct e1000_info e1000_es2_info = { + .mac = e1000_80003es2lan, + .flags = FLAG_HAS_HW_VLAN_FILTER + | FLAG_HAS_JUMBO_FRAMES + | FLAG_HAS_STATS_PTC_PRC + | FLAG_HAS_WOL + | FLAG_APME_IN_CTRL3 + | FLAG_RX_CSUM_ENABLED + | FLAG_HAS_CTRLEXT_ON_LOAD + | FLAG_HAS_STATS_ICR_ICT + | FLAG_RX_NEEDS_RESTART /* errata */ + | FLAG_TARC_SET_BIT_ZERO /* errata */ + | FLAG_APME_CHECK_PORT_B + | FLAG_DISABLE_FC_PAUSE_TIME /* errata */ + | FLAG_TIPG_MEDIUM_FOR_80003ESLAN, + .pba = 38, + .get_invariants = e1000_get_invariants_80003es2lan, + .mac_ops = &es2_mac_ops, + .phy_ops = &es2_phy_ops, + .nvm_ops = &es2_nvm_ops, +}; + diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c new file mode 100644 index 00000000000..0e80406bfbd --- /dev/null +++ b/drivers/net/e1000e/ethtool.c @@ -0,0 +1,1774 @@ +/******************************************************************************* + + Intel PRO/1000 Linux driver + Copyright(c) 1999 - 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +/* ethtool support for e1000 */ + +#include +#include +#include +#include + +#include "e1000.h" + +struct e1000_stats { + char stat_string[ETH_GSTRING_LEN]; + int sizeof_stat; + int stat_offset; +}; + +#define E1000_STAT(m) sizeof(((struct e1000_adapter *)0)->m), \ + offsetof(struct e1000_adapter, m) +static const struct e1000_stats e1000_gstrings_stats[] = { + { "rx_packets", E1000_STAT(stats.gprc) }, + { "tx_packets", E1000_STAT(stats.gptc) }, + { "rx_bytes", E1000_STAT(stats.gorcl) }, + { "tx_bytes", E1000_STAT(stats.gotcl) }, + { "rx_broadcast", E1000_STAT(stats.bprc) }, + { "tx_broadcast", E1000_STAT(stats.bptc) }, + { "rx_multicast", E1000_STAT(stats.mprc) }, + { "tx_multicast", E1000_STAT(stats.mptc) }, + { "rx_errors", E1000_STAT(net_stats.rx_errors) }, + { "tx_errors", E1000_STAT(net_stats.tx_errors) }, + { "tx_dropped", E1000_STAT(net_stats.tx_dropped) }, + { "multicast", E1000_STAT(stats.mprc) }, + { "collisions", E1000_STAT(stats.colc) }, + { "rx_length_errors", E1000_STAT(net_stats.rx_length_errors) }, + { "rx_over_errors", E1000_STAT(net_stats.rx_over_errors) }, + { "rx_crc_errors", E1000_STAT(stats.crcerrs) }, + { "rx_frame_errors", E1000_STAT(net_stats.rx_frame_errors) }, + { "rx_no_buffer_count", E1000_STAT(stats.rnbc) }, + { "rx_missed_errors", E1000_STAT(stats.mpc) }, + { "tx_aborted_errors", E1000_STAT(stats.ecol) }, + { "tx_carrier_errors", E1000_STAT(stats.tncrs) }, + { "tx_fifo_errors", E1000_STAT(net_stats.tx_fifo_errors) }, + { "tx_heartbeat_errors", E1000_STAT(net_stats.tx_heartbeat_errors) }, + { "tx_window_errors", E1000_STAT(stats.latecol) }, + { "tx_abort_late_coll", E1000_STAT(stats.latecol) }, + { "tx_deferred_ok", E1000_STAT(stats.dc) }, + { "tx_single_coll_ok", E1000_STAT(stats.scc) }, + { "tx_multi_coll_ok", E1000_STAT(stats.mcc) }, + { "tx_timeout_count", E1000_STAT(tx_timeout_count) }, + { "tx_restart_queue", E1000_STAT(restart_queue) }, + { "rx_long_length_errors", E1000_STAT(stats.roc) }, + { "rx_short_length_errors", E1000_STAT(stats.ruc) }, + { "rx_align_errors", E1000_STAT(stats.algnerrc) }, + { "tx_tcp_seg_good", E1000_STAT(stats.tsctc) }, + { "tx_tcp_seg_failed", E1000_STAT(stats.tsctfc) }, + { "rx_flow_control_xon", E1000_STAT(stats.xonrxc) }, + { "rx_flow_control_xoff", E1000_STAT(stats.xoffrxc) }, + { "tx_flow_control_xon", E1000_STAT(stats.xontxc) }, + { "tx_flow_control_xoff", E1000_STAT(stats.xofftxc) }, + { "rx_long_byte_count", E1000_STAT(stats.gorcl) }, + { "rx_csum_offload_good", E1000_STAT(hw_csum_good) }, + { "rx_csum_offload_errors", E1000_STAT(hw_csum_err) }, + { "rx_header_split", E1000_STAT(rx_hdr_split) }, + { "alloc_rx_buff_failed", E1000_STAT(alloc_rx_buff_failed) }, + { "tx_smbus", E1000_STAT(stats.mgptc) }, + { "rx_smbus", E1000_STAT(stats.mgprc) }, + { "dropped_smbus", E1000_STAT(stats.mgpdc) }, + { "rx_dma_failed", E1000_STAT(rx_dma_failed) }, + { "tx_dma_failed", E1000_STAT(tx_dma_failed) }, +}; + +#define E1000_GLOBAL_STATS_LEN \ + sizeof(e1000_gstrings_stats) / sizeof(struct e1000_stats) +#define E1000_STATS_LEN (E1000_GLOBAL_STATS_LEN) +static const char e1000_gstrings_test[][ETH_GSTRING_LEN] = { + "Register test (offline)", "Eeprom test (offline)", + "Interrupt test (offline)", "Loopback test (offline)", + "Link test (on/offline)" +}; +#define E1000_TEST_LEN sizeof(e1000_gstrings_test) / ETH_GSTRING_LEN + +static int e1000_get_settings(struct net_device *netdev, + struct ethtool_cmd *ecmd) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + + if (hw->media_type == e1000_media_type_copper) { + + ecmd->supported = (SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full | + SUPPORTED_Autoneg | + SUPPORTED_TP); + if (hw->phy.type == e1000_phy_ife) + ecmd->supported &= ~SUPPORTED_1000baseT_Full; + ecmd->advertising = ADVERTISED_TP; + + if (hw->mac.autoneg == 1) { + ecmd->advertising |= ADVERTISED_Autoneg; + /* the e1000 autoneg seems to match ethtool nicely */ + ecmd->advertising |= hw->phy.autoneg_advertised; + } + + ecmd->port = PORT_TP; + ecmd->phy_address = hw->phy.addr; + ecmd->transceiver = XCVR_INTERNAL; + + } else { + ecmd->supported = (SUPPORTED_1000baseT_Full | + SUPPORTED_FIBRE | + SUPPORTED_Autoneg); + + ecmd->advertising = (ADVERTISED_1000baseT_Full | + ADVERTISED_FIBRE | + ADVERTISED_Autoneg); + + ecmd->port = PORT_FIBRE; + ecmd->transceiver = XCVR_EXTERNAL; + } + + if (er32(STATUS) & E1000_STATUS_LU) { + + adapter->hw.mac.ops.get_link_up_info(hw, &adapter->link_speed, + &adapter->link_duplex); + ecmd->speed = adapter->link_speed; + + /* unfortunately FULL_DUPLEX != DUPLEX_FULL + * and HALF_DUPLEX != DUPLEX_HALF */ + + if (adapter->link_duplex == FULL_DUPLEX) + ecmd->duplex = DUPLEX_FULL; + else + ecmd->duplex = DUPLEX_HALF; + } else { + ecmd->speed = -1; + ecmd->duplex = -1; + } + + ecmd->autoneg = ((hw->media_type == e1000_media_type_fiber) || + hw->mac.autoneg) ? AUTONEG_ENABLE : AUTONEG_DISABLE; + return 0; +} + +static int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx) +{ + struct e1000_mac_info *mac = &adapter->hw.mac; + + mac->autoneg = 0; + + /* Fiber NICs only allow 1000 gbps Full duplex */ + if ((adapter->hw.media_type == e1000_media_type_fiber) && + spddplx != (SPEED_1000 + DUPLEX_FULL)) { + ndev_err(adapter->netdev, "Unsupported Speed/Duplex " + "configuration\n"); + return -EINVAL; + } + + switch (spddplx) { + case SPEED_10 + DUPLEX_HALF: + mac->forced_speed_duplex = ADVERTISE_10_HALF; + break; + case SPEED_10 + DUPLEX_FULL: + mac->forced_speed_duplex = ADVERTISE_10_FULL; + break; + case SPEED_100 + DUPLEX_HALF: + mac->forced_speed_duplex = ADVERTISE_100_HALF; + break; + case SPEED_100 + DUPLEX_FULL: + mac->forced_speed_duplex = ADVERTISE_100_FULL; + break; + case SPEED_1000 + DUPLEX_FULL: + mac->autoneg = 1; + adapter->hw.phy.autoneg_advertised = ADVERTISE_1000_FULL; + break; + case SPEED_1000 + DUPLEX_HALF: /* not supported */ + default: + ndev_err(adapter->netdev, "Unsupported Speed/Duplex " + "configuration\n"); + return -EINVAL; + } + return 0; +} + +static int e1000_set_settings(struct net_device *netdev, + struct ethtool_cmd *ecmd) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + + /* When SoL/IDER sessions are active, autoneg/speed/duplex + * cannot be changed */ + if (e1000_check_reset_block(hw)) { + ndev_err(netdev, "Cannot change link " + "characteristics when SoL/IDER is active.\n"); + return -EINVAL; + } + + while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) + msleep(1); + + if (ecmd->autoneg == AUTONEG_ENABLE) { + hw->mac.autoneg = 1; + if (hw->media_type == e1000_media_type_fiber) + hw->phy.autoneg_advertised = ADVERTISED_1000baseT_Full | + ADVERTISED_FIBRE | + ADVERTISED_Autoneg; + else + hw->phy.autoneg_advertised = ecmd->advertising | + ADVERTISED_TP | + ADVERTISED_Autoneg; + ecmd->advertising = hw->phy.autoneg_advertised; + } else { + if (e1000_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex)) { + clear_bit(__E1000_RESETTING, &adapter->state); + return -EINVAL; + } + } + + /* reset the link */ + + if (netif_running(adapter->netdev)) { + e1000e_down(adapter); + e1000e_up(adapter); + } else { + e1000e_reset(adapter); + } + + clear_bit(__E1000_RESETTING, &adapter->state); + return 0; +} + +static void e1000_get_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *pause) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + + pause->autoneg = + (adapter->fc_autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE); + + if (hw->mac.fc == e1000_fc_rx_pause) { + pause->rx_pause = 1; + } else if (hw->mac.fc == e1000_fc_tx_pause) { + pause->tx_pause = 1; + } else if (hw->mac.fc == e1000_fc_full) { + pause->rx_pause = 1; + pause->tx_pause = 1; + } +} + +static int e1000_set_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *pause) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + int retval = 0; + + adapter->fc_autoneg = pause->autoneg; + + while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) + msleep(1); + + if (pause->rx_pause && pause->tx_pause) + hw->mac.fc = e1000_fc_full; + else if (pause->rx_pause && !pause->tx_pause) + hw->mac.fc = e1000_fc_rx_pause; + else if (!pause->rx_pause && pause->tx_pause) + hw->mac.fc = e1000_fc_tx_pause; + else if (!pause->rx_pause && !pause->tx_pause) + hw->mac.fc = e1000_fc_none; + + hw->mac.original_fc = hw->mac.fc; + + if (adapter->fc_autoneg == AUTONEG_ENABLE) { + if (netif_running(adapter->netdev)) { + e1000e_down(adapter); + e1000e_up(adapter); + } else { + e1000e_reset(adapter); + } + } else { + retval = ((hw->media_type == e1000_media_type_fiber) ? + hw->mac.ops.setup_link(hw) : e1000e_force_mac_fc(hw)); + } + + clear_bit(__E1000_RESETTING, &adapter->state); + return retval; +} + +static u32 e1000_get_rx_csum(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + return (adapter->flags & FLAG_RX_CSUM_ENABLED); +} + +static int e1000_set_rx_csum(struct net_device *netdev, u32 data) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + + if (data) + adapter->flags |= FLAG_RX_CSUM_ENABLED; + else + adapter->flags &= ~FLAG_RX_CSUM_ENABLED; + + if (netif_running(netdev)) + e1000e_reinit_locked(adapter); + else + e1000e_reset(adapter); + return 0; +} + +static u32 e1000_get_tx_csum(struct net_device *netdev) +{ + return ((netdev->features & NETIF_F_HW_CSUM) != 0); +} + +static int e1000_set_tx_csum(struct net_device *netdev, u32 data) +{ + if (data) + netdev->features |= NETIF_F_HW_CSUM; + else + netdev->features &= ~NETIF_F_HW_CSUM; + + return 0; +} + +static int e1000_set_tso(struct net_device *netdev, u32 data) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + + if (data) { + netdev->features |= NETIF_F_TSO; + netdev->features |= NETIF_F_TSO6; + } else { + netdev->features &= ~NETIF_F_TSO; + netdev->features &= ~NETIF_F_TSO6; + } + + ndev_info(netdev, "TSO is %s\n", + data ? "Enabled" : "Disabled"); + adapter->flags |= FLAG_TSO_FORCE; + return 0; +} + +static u32 e1000_get_msglevel(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + return adapter->msg_enable; +} + +static void e1000_set_msglevel(struct net_device *netdev, u32 data) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + adapter->msg_enable = data; +} + +static int e1000_get_regs_len(struct net_device *netdev) +{ +#define E1000_REGS_LEN 32 /* overestimate */ + return E1000_REGS_LEN * sizeof(u32); +} + +static void e1000_get_regs(struct net_device *netdev, + struct ethtool_regs *regs, void *p) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + u32 *regs_buff = p; + u16 phy_data; + u8 revision_id; + + memset(p, 0, E1000_REGS_LEN * sizeof(u32)); + + pci_read_config_byte(adapter->pdev, PCI_REVISION_ID, &revision_id); + + regs->version = (1 << 24) | (revision_id << 16) | adapter->pdev->device; + + regs_buff[0] = er32(CTRL); + regs_buff[1] = er32(STATUS); + + regs_buff[2] = er32(RCTL); + regs_buff[3] = er32(RDLEN); + regs_buff[4] = er32(RDH); + regs_buff[5] = er32(RDT); + regs_buff[6] = er32(RDTR); + + regs_buff[7] = er32(TCTL); + regs_buff[8] = er32(TDLEN); + regs_buff[9] = er32(TDH); + regs_buff[10] = er32(TDT); + regs_buff[11] = er32(TIDV); + + regs_buff[12] = adapter->hw.phy.type; /* PHY type (IGP=1, M88=0) */ + if (hw->phy.type == e1000_phy_m88) { + e1e_rphy(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); + regs_buff[13] = (u32)phy_data; /* cable length */ + regs_buff[14] = 0; /* Dummy (to align w/ IGP phy reg dump) */ + regs_buff[15] = 0; /* Dummy (to align w/ IGP phy reg dump) */ + regs_buff[16] = 0; /* Dummy (to align w/ IGP phy reg dump) */ + e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); + regs_buff[17] = (u32)phy_data; /* extended 10bt distance */ + regs_buff[18] = regs_buff[13]; /* cable polarity */ + regs_buff[19] = 0; /* Dummy (to align w/ IGP phy reg dump) */ + regs_buff[20] = regs_buff[17]; /* polarity correction */ + /* phy receive errors */ + regs_buff[22] = adapter->phy_stats.receive_errors; + regs_buff[23] = regs_buff[13]; /* mdix mode */ + } + regs_buff[21] = adapter->phy_stats.idle_errors; /* phy idle errors */ + e1e_rphy(hw, PHY_1000T_STATUS, &phy_data); + regs_buff[24] = (u32)phy_data; /* phy local receiver status */ + regs_buff[25] = regs_buff[24]; /* phy remote receiver status */ +} + +static int e1000_get_eeprom_len(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + return adapter->hw.nvm.word_size * 2; +} + +static int e1000_get_eeprom(struct net_device *netdev, + struct ethtool_eeprom *eeprom, u8 *bytes) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + u16 *eeprom_buff; + int first_word; + int last_word; + int ret_val = 0; + u16 i; + + if (eeprom->len == 0) + return -EINVAL; + + eeprom->magic = adapter->pdev->vendor | (adapter->pdev->device << 16); + + first_word = eeprom->offset >> 1; + last_word = (eeprom->offset + eeprom->len - 1) >> 1; + + eeprom_buff = kmalloc(sizeof(u16) * + (last_word - first_word + 1), GFP_KERNEL); + if (!eeprom_buff) + return -ENOMEM; + + if (hw->nvm.type == e1000_nvm_eeprom_spi) { + ret_val = e1000_read_nvm(hw, first_word, + last_word - first_word + 1, + eeprom_buff); + } else { + for (i = 0; i < last_word - first_word + 1; i++) { + ret_val = e1000_read_nvm(hw, first_word + i, 1, + &eeprom_buff[i]); + if (ret_val) + break; + } + } + + /* Device's eeprom is always little-endian, word addressable */ + for (i = 0; i < last_word - first_word + 1; i++) + le16_to_cpus(&eeprom_buff[i]); + + memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 1), eeprom->len); + kfree(eeprom_buff); + + return ret_val; +} + +static int e1000_set_eeprom(struct net_device *netdev, + struct ethtool_eeprom *eeprom, u8 *bytes) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + u16 *eeprom_buff; + void *ptr; + int max_len; + int first_word; + int last_word; + int ret_val = 0; + u16 i; + + if (eeprom->len == 0) + return -EOPNOTSUPP; + + if (eeprom->magic != (adapter->pdev->vendor | (adapter->pdev->device << 16))) + return -EFAULT; + + max_len = hw->nvm.word_size * 2; + + first_word = eeprom->offset >> 1; + last_word = (eeprom->offset + eeprom->len - 1) >> 1; + eeprom_buff = kmalloc(max_len, GFP_KERNEL); + if (!eeprom_buff) + return -ENOMEM; + + ptr = (void *)eeprom_buff; + + if (eeprom->offset & 1) { + /* need read/modify/write of first changed EEPROM word */ + /* only the second byte of the word is being modified */ + ret_val = e1000_read_nvm(hw, first_word, 1, &eeprom_buff[0]); + ptr++; + } + if (((eeprom->offset + eeprom->len) & 1) && (ret_val == 0)) + /* need read/modify/write of last changed EEPROM word */ + /* only the first byte of the word is being modified */ + ret_val = e1000_read_nvm(hw, last_word, 1, + &eeprom_buff[last_word - first_word]); + + /* Device's eeprom is always little-endian, word addressable */ + for (i = 0; i < last_word - first_word + 1; i++) + le16_to_cpus(&eeprom_buff[i]); + + memcpy(ptr, bytes, eeprom->len); + + for (i = 0; i < last_word - first_word + 1; i++) + eeprom_buff[i] = cpu_to_le16(eeprom_buff[i]); + + ret_val = e1000_write_nvm(hw, first_word, + last_word - first_word + 1, eeprom_buff); + + /* Update the checksum over the first part of the EEPROM if needed + * and flush shadow RAM for 82573 controllers */ + if ((ret_val == 0) && ((first_word <= NVM_CHECKSUM_REG) || + (hw->mac.type == e1000_82573))) + e1000e_update_nvm_checksum(hw); + + kfree(eeprom_buff); + return ret_val; +} + +static void e1000_get_drvinfo(struct net_device *netdev, + struct ethtool_drvinfo *drvinfo) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + char firmware_version[32]; + u16 eeprom_data; + + strncpy(drvinfo->driver, e1000e_driver_name, 32); + strncpy(drvinfo->version, e1000e_driver_version, 32); + + /* EEPROM image version # is reported as firmware version # for + * PCI-E controllers */ + e1000_read_nvm(&adapter->hw, 5, 1, &eeprom_data); + sprintf(firmware_version, "%d.%d-%d", + (eeprom_data & 0xF000) >> 12, + (eeprom_data & 0x0FF0) >> 4, + eeprom_data & 0x000F); + + strncpy(drvinfo->fw_version, firmware_version, 32); + strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32); + drvinfo->n_stats = E1000_STATS_LEN; + drvinfo->testinfo_len = E1000_TEST_LEN; + drvinfo->regdump_len = e1000_get_regs_len(netdev); + drvinfo->eedump_len = e1000_get_eeprom_len(netdev); +} + +static void e1000_get_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ring) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_ring *tx_ring = adapter->tx_ring; + struct e1000_ring *rx_ring = adapter->rx_ring; + + ring->rx_max_pending = E1000_MAX_RXD; + ring->tx_max_pending = E1000_MAX_TXD; + ring->rx_mini_max_pending = 0; + ring->rx_jumbo_max_pending = 0; + ring->rx_pending = rx_ring->count; + ring->tx_pending = tx_ring->count; + ring->rx_mini_pending = 0; + ring->rx_jumbo_pending = 0; +} + +static int e1000_set_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ring) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_ring *tx_ring, *tx_old; + struct e1000_ring *rx_ring, *rx_old; + int err; + + if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) + return -EINVAL; + + while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) + msleep(1); + + if (netif_running(adapter->netdev)) + e1000e_down(adapter); + + tx_old = adapter->tx_ring; + rx_old = adapter->rx_ring; + + err = -ENOMEM; + tx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL); + if (!tx_ring) + goto err_alloc_tx; + + rx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL); + if (!rx_ring) + goto err_alloc_rx; + + adapter->tx_ring = tx_ring; + adapter->rx_ring = rx_ring; + + rx_ring->count = max(ring->rx_pending, (u32)E1000_MIN_RXD); + rx_ring->count = min(rx_ring->count, (u32)(E1000_MAX_RXD)); + rx_ring->count = ALIGN(rx_ring->count, REQ_RX_DESCRIPTOR_MULTIPLE); + + tx_ring->count = max(ring->tx_pending, (u32)E1000_MIN_TXD); + tx_ring->count = min(tx_ring->count, (u32)(E1000_MAX_TXD)); + tx_ring->count = ALIGN(tx_ring->count, REQ_TX_DESCRIPTOR_MULTIPLE); + + if (netif_running(adapter->netdev)) { + /* Try to get new resources before deleting old */ + err = e1000e_setup_rx_resources(adapter); + if (err) + goto err_setup_rx; + err = e1000e_setup_tx_resources(adapter); + if (err) + goto err_setup_tx; + + /* save the new, restore the old in order to free it, + * then restore the new back again */ + adapter->rx_ring = rx_old; + adapter->tx_ring = tx_old; + e1000e_free_rx_resources(adapter); + e1000e_free_tx_resources(adapter); + kfree(tx_old); + kfree(rx_old); + adapter->rx_ring = rx_ring; + adapter->tx_ring = tx_ring; + err = e1000e_up(adapter); + if (err) + goto err_setup; + } + + clear_bit(__E1000_RESETTING, &adapter->state); + return 0; +err_setup_tx: + e1000e_free_rx_resources(adapter); +err_setup_rx: + adapter->rx_ring = rx_old; + adapter->tx_ring = tx_old; + kfree(rx_ring); +err_alloc_rx: + kfree(tx_ring); +err_alloc_tx: + e1000e_up(adapter); +err_setup: + clear_bit(__E1000_RESETTING, &adapter->state); + return err; +} + +#define REG_PATTERN_TEST(R, M, W) REG_PATTERN_TEST_ARRAY(R, 0, M, W) +#define REG_PATTERN_TEST_ARRAY(reg, offset, mask, writeable) \ +{ \ + u32 _pat; \ + u32 _value; \ + u32 _test[] = {0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF}; \ + for (_pat = 0; _pat < ARRAY_SIZE(_test); _pat++) { \ + E1000_WRITE_REG_ARRAY(hw, reg, offset, \ + (_test[_pat] & writeable)); \ + _value = E1000_READ_REG_ARRAY(hw, reg, offset); \ + if (_value != (_test[_pat] & writeable & mask)) { \ + ndev_err(netdev, "pattern test reg %04X " \ + "failed: got 0x%08X expected 0x%08X\n", \ + reg + offset, \ + value, (_test[_pat] & writeable & mask)); \ + *data = reg; \ + return 1; \ + } \ + } \ +} + +#define REG_SET_AND_CHECK(R, M, W) \ +{ \ + u32 _value; \ + __ew32(hw, R, W & M); \ + _value = __er32(hw, R); \ + if ((W & M) != (_value & M)) { \ + ndev_err(netdev, "set/check reg %04X test failed: " \ + "got 0x%08X expected 0x%08X\n", R, (_value & M), \ + (W & M)); \ + *data = R; \ + return 1; \ + } \ +} + +static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data) +{ + struct e1000_hw *hw = &adapter->hw; + struct e1000_mac_info *mac = &adapter->hw.mac; + struct net_device *netdev = adapter->netdev; + u32 value; + u32 before; + u32 after; + u32 i; + u32 toggle; + + /* The status register is Read Only, so a write should fail. + * Some bits that get toggled are ignored. + */ + switch (mac->type) { + /* there are several bits on newer hardware that are r/w */ + case e1000_82571: + case e1000_82572: + case e1000_80003es2lan: + toggle = 0x7FFFF3FF; + break; + case e1000_82573: + case e1000_ich8lan: + case e1000_ich9lan: + toggle = 0x7FFFF033; + break; + default: + toggle = 0xFFFFF833; + break; + } + + before = er32(STATUS); + value = (er32(STATUS) & toggle); + ew32(STATUS, toggle); + after = er32(STATUS) & toggle; + if (value != after) { + ndev_err(netdev, "failed STATUS register test got: " + "0x%08X expected: 0x%08X\n", after, value); + *data = 1; + return 1; + } + /* restore previous status */ + ew32(STATUS, before); + + if ((mac->type != e1000_ich8lan) && + (mac->type != e1000_ich9lan)) { + REG_PATTERN_TEST(E1000_FCAL, 0xFFFFFFFF, 0xFFFFFFFF); + REG_PATTERN_TEST(E1000_FCAH, 0x0000FFFF, 0xFFFFFFFF); + REG_PATTERN_TEST(E1000_FCT, 0x0000FFFF, 0xFFFFFFFF); + REG_PATTERN_TEST(E1000_VET, 0x0000FFFF, 0xFFFFFFFF); + } + + REG_PATTERN_TEST(E1000_RDTR, 0x0000FFFF, 0xFFFFFFFF); + REG_PATTERN_TEST(E1000_RDBAH, 0xFFFFFFFF, 0xFFFFFFFF); + REG_PATTERN_TEST(E1000_RDLEN, 0x000FFF80, 0x000FFFFF); + REG_PATTERN_TEST(E1000_RDH, 0x0000FFFF, 0x0000FFFF); + REG_PATTERN_TEST(E1000_RDT, 0x0000FFFF, 0x0000FFFF); + REG_PATTERN_TEST(E1000_FCRTH, 0x0000FFF8, 0x0000FFF8); + REG_PATTERN_TEST(E1000_FCTTV, 0x0000FFFF, 0x0000FFFF); + REG_PATTERN_TEST(E1000_TIPG, 0x3FFFFFFF, 0x3FFFFFFF); + REG_PATTERN_TEST(E1000_TDBAH, 0xFFFFFFFF, 0xFFFFFFFF); + REG_PATTERN_TEST(E1000_TDLEN, 0x000FFF80, 0x000FFFFF); + + REG_SET_AND_CHECK(E1000_RCTL, 0xFFFFFFFF, 0x00000000); + + before = (((mac->type == e1000_ich8lan) || + (mac->type == e1000_ich9lan)) ? 0x06C3B33E : 0x06DFB3FE); + REG_SET_AND_CHECK(E1000_RCTL, before, 0x003FFFFB); + REG_SET_AND_CHECK(E1000_TCTL, 0xFFFFFFFF, 0x00000000); + + REG_SET_AND_CHECK(E1000_RCTL, 0xFFFFFFFF, 0x01FFFFFF); + REG_PATTERN_TEST(E1000_RDBAL, 0xFFFFF000, 0xFFFFFFFF); + REG_PATTERN_TEST(E1000_TXCW, 0x0000FFFF, 0x0000FFFF); + REG_PATTERN_TEST(E1000_TDBAL, 0xFFFFF000, 0xFFFFFFFF); + + for (i = 0; i < mac->mta_reg_count; i++) + REG_PATTERN_TEST_ARRAY(E1000_MTA, i, 0xFFFFFFFF, 0xFFFFFFFF); + + *data = 0; + return 0; +} + +static int e1000_eeprom_test(struct e1000_adapter *adapter, u64 *data) +{ + u16 temp; + u16 checksum = 0; + u16 i; + + *data = 0; + /* Read and add up the contents of the EEPROM */ + for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) { + if ((e1000_read_nvm(&adapter->hw, i, 1, &temp)) < 0) { + *data = 1; + break; + } + checksum += temp; + } + + /* If Checksum is not Correct return error else test passed */ + if ((checksum != (u16) NVM_SUM) && !(*data)) + *data = 2; + + return *data; +} + +static irqreturn_t e1000_test_intr(int irq, void *data) +{ + struct net_device *netdev = (struct net_device *) data; + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + + adapter->test_icr |= er32(ICR); + + return IRQ_HANDLED; +} + +static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) +{ + struct net_device *netdev = adapter->netdev; + struct e1000_hw *hw = &adapter->hw; + u32 mask; + u32 shared_int = 1; + u32 irq = adapter->pdev->irq; + int i; + + *data = 0; + + /* NOTE: we don't test MSI interrupts here, yet */ + /* Hook up test interrupt handler just for this test */ + if (!request_irq(irq, &e1000_test_intr, IRQF_PROBE_SHARED, netdev->name, + netdev)) { + shared_int = 0; + } else if (request_irq(irq, &e1000_test_intr, IRQF_SHARED, + netdev->name, netdev)) { + *data = 1; + return -1; + } + ndev_info(netdev, "testing %s interrupt\n", + (shared_int ? "shared" : "unshared")); + + /* Disable all the interrupts */ + ew32(IMC, 0xFFFFFFFF); + msleep(10); + + /* Test each interrupt */ + for (i = 0; i < 10; i++) { + + if (((adapter->hw.mac.type == e1000_ich8lan) || + (adapter->hw.mac.type == e1000_ich9lan)) && i == 8) + continue; + + /* Interrupt to test */ + mask = 1 << i; + + if (!shared_int) { + /* Disable the interrupt to be reported in + * the cause register and then force the same + * interrupt and see if one gets posted. If + * an interrupt was posted to the bus, the + * test failed. + */ + adapter->test_icr = 0; + ew32(IMC, mask); + ew32(ICS, mask); + msleep(10); + + if (adapter->test_icr & mask) { + *data = 3; + break; + } + } + + /* Enable the interrupt to be reported in + * the cause register and then force the same + * interrupt and see if one gets posted. If + * an interrupt was not posted to the bus, the + * test failed. + */ + adapter->test_icr = 0; + ew32(IMS, mask); + ew32(ICS, mask); + msleep(10); + + if (!(adapter->test_icr & mask)) { + *data = 4; + break; + } + + if (!shared_int) { + /* Disable the other interrupts to be reported in + * the cause register and then force the other + * interrupts and see if any get posted. If + * an interrupt was posted to the bus, the + * test failed. + */ + adapter->test_icr = 0; + ew32(IMC, ~mask & 0x00007FFF); + ew32(ICS, ~mask & 0x00007FFF); + msleep(10); + + if (adapter->test_icr) { + *data = 5; + break; + } + } + } + + /* Disable all the interrupts */ + ew32(IMC, 0xFFFFFFFF); + msleep(10); + + /* Unhook test interrupt handler */ + free_irq(irq, netdev); + + return *data; +} + +static void e1000_free_desc_rings(struct e1000_adapter *adapter) +{ + struct e1000_ring *tx_ring = &adapter->test_tx_ring; + struct e1000_ring *rx_ring = &adapter->test_rx_ring; + struct pci_dev *pdev = adapter->pdev; + int i; + + if (tx_ring->desc && tx_ring->buffer_info) { + for (i = 0; i < tx_ring->count; i++) { + if (tx_ring->buffer_info[i].dma) + pci_unmap_single(pdev, + tx_ring->buffer_info[i].dma, + tx_ring->buffer_info[i].length, + PCI_DMA_TODEVICE); + if (tx_ring->buffer_info[i].skb) + dev_kfree_skb(tx_ring->buffer_info[i].skb); + } + } + + if (rx_ring->desc && rx_ring->buffer_info) { + for (i = 0; i < rx_ring->count; i++) { + if (rx_ring->buffer_info[i].dma) + pci_unmap_single(pdev, + rx_ring->buffer_info[i].dma, + 2048, PCI_DMA_FROMDEVICE); + if (rx_ring->buffer_info[i].skb) + dev_kfree_skb(rx_ring->buffer_info[i].skb); + } + } + + if (tx_ring->desc) { + dma_free_coherent(&pdev->dev, tx_ring->size, tx_ring->desc, + tx_ring->dma); + tx_ring->desc = NULL; + } + if (rx_ring->desc) { + dma_free_coherent(&pdev->dev, rx_ring->size, rx_ring->desc, + rx_ring->dma); + rx_ring->desc = NULL; + } + + kfree(tx_ring->buffer_info); + tx_ring->buffer_info = NULL; + kfree(rx_ring->buffer_info); + rx_ring->buffer_info = NULL; +} + +static int e1000_setup_desc_rings(struct e1000_adapter *adapter) +{ + struct e1000_ring *tx_ring = &adapter->test_tx_ring; + struct e1000_ring *rx_ring = &adapter->test_rx_ring; + struct pci_dev *pdev = adapter->pdev; + struct e1000_hw *hw = &adapter->hw; + u32 rctl; + int size; + int i; + int ret_val; + + /* Setup Tx descriptor ring and Tx buffers */ + + if (!tx_ring->count) + tx_ring->count = E1000_DEFAULT_TXD; + + size = tx_ring->count * sizeof(struct e1000_buffer); + tx_ring->buffer_info = kmalloc(size, GFP_KERNEL); + if (!tx_ring->buffer_info) { + ret_val = 1; + goto err_nomem; + } + memset(tx_ring->buffer_info, 0, size); + + tx_ring->size = tx_ring->count * sizeof(struct e1000_tx_desc); + tx_ring->size = ALIGN(tx_ring->size, 4096); + tx_ring->desc = dma_alloc_coherent(&pdev->dev, tx_ring->size, + &tx_ring->dma, GFP_KERNEL); + if (!tx_ring->desc) { + ret_val = 2; + goto err_nomem; + } + memset(tx_ring->desc, 0, tx_ring->size); + tx_ring->next_to_use = 0; + tx_ring->next_to_clean = 0; + + ew32(TDBAL, + ((u64) tx_ring->dma & 0x00000000FFFFFFFF)); + ew32(TDBAH, ((u64) tx_ring->dma >> 32)); + ew32(TDLEN, + tx_ring->count * sizeof(struct e1000_tx_desc)); + ew32(TDH, 0); + ew32(TDT, 0); + ew32(TCTL, + E1000_TCTL_PSP | E1000_TCTL_EN | + E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT | + E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT); + + for (i = 0; i < tx_ring->count; i++) { + struct e1000_tx_desc *tx_desc = E1000_TX_DESC(*tx_ring, i); + struct sk_buff *skb; + unsigned int skb_size = 1024; + + skb = alloc_skb(skb_size, GFP_KERNEL); + if (!skb) { + ret_val = 3; + goto err_nomem; + } + skb_put(skb, skb_size); + tx_ring->buffer_info[i].skb = skb; + tx_ring->buffer_info[i].length = skb->len; + tx_ring->buffer_info[i].dma = + pci_map_single(pdev, skb->data, skb->len, + PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(tx_ring->buffer_info[i].dma)) { + ret_val = 4; + goto err_nomem; + } + tx_desc->buffer_addr = cpu_to_le64( + tx_ring->buffer_info[i].dma); + tx_desc->lower.data = cpu_to_le32(skb->len); + tx_desc->lower.data |= cpu_to_le32(E1000_TXD_CMD_EOP | + E1000_TXD_CMD_IFCS | + E1000_TXD_CMD_RPS); + tx_desc->upper.data = 0; + } + + /* Setup Rx descriptor ring and Rx buffers */ + + if (!rx_ring->count) + rx_ring->count = E1000_DEFAULT_RXD; + + size = rx_ring->count * sizeof(struct e1000_buffer); + rx_ring->buffer_info = kmalloc(size, GFP_KERNEL); + if (!rx_ring->buffer_info) { + ret_val = 5; + goto err_nomem; + } + memset(rx_ring->buffer_info, 0, size); + + rx_ring->size = rx_ring->count * sizeof(struct e1000_rx_desc); + rx_ring->desc = dma_alloc_coherent(&pdev->dev, rx_ring->size, + &rx_ring->dma, GFP_KERNEL); + if (!rx_ring->desc) { + ret_val = 6; + goto err_nomem; + } + memset(rx_ring->desc, 0, rx_ring->size); + rx_ring->next_to_use = 0; + rx_ring->next_to_clean = 0; + + rctl = er32(RCTL); + ew32(RCTL, rctl & ~E1000_RCTL_EN); + ew32(RDBAL, ((u64) rx_ring->dma & 0xFFFFFFFF)); + ew32(RDBAH, ((u64) rx_ring->dma >> 32)); + ew32(RDLEN, rx_ring->size); + ew32(RDH, 0); + ew32(RDT, 0); + rctl = E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_SZ_2048 | + E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF | + (adapter->hw.mac.mc_filter_type << E1000_RCTL_MO_SHIFT); + ew32(RCTL, rctl); + + for (i = 0; i < rx_ring->count; i++) { + struct e1000_rx_desc *rx_desc = E1000_RX_DESC(*rx_ring, i); + struct sk_buff *skb; + + skb = alloc_skb(2048 + NET_IP_ALIGN, GFP_KERNEL); + if (!skb) { + ret_val = 7; + goto err_nomem; + } + skb_reserve(skb, NET_IP_ALIGN); + rx_ring->buffer_info[i].skb = skb; + rx_ring->buffer_info[i].dma = + pci_map_single(pdev, skb->data, 2048, + PCI_DMA_FROMDEVICE); + if (pci_dma_mapping_error(rx_ring->buffer_info[i].dma)) { + ret_val = 8; + goto err_nomem; + } + rx_desc->buffer_addr = + cpu_to_le64(rx_ring->buffer_info[i].dma); + memset(skb->data, 0x00, skb->len); + } + + return 0; + +err_nomem: + e1000_free_desc_rings(adapter); + return ret_val; +} + +static void e1000_phy_disable_receiver(struct e1000_adapter *adapter) +{ + /* Write out to PHY registers 29 and 30 to disable the Receiver. */ + e1e_wphy(&adapter->hw, 29, 0x001F); + e1e_wphy(&adapter->hw, 30, 0x8FFC); + e1e_wphy(&adapter->hw, 29, 0x001A); + e1e_wphy(&adapter->hw, 30, 0x8FF0); +} + +static int e1000_integrated_phy_loopback(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 ctrl_reg = 0; + u32 stat_reg = 0; + + adapter->hw.mac.autoneg = 0; + + if (adapter->hw.phy.type == e1000_phy_m88) { + /* Auto-MDI/MDIX Off */ + e1e_wphy(hw, M88E1000_PHY_SPEC_CTRL, 0x0808); + /* reset to update Auto-MDI/MDIX */ + e1e_wphy(hw, PHY_CONTROL, 0x9140); + /* autoneg off */ + e1e_wphy(hw, PHY_CONTROL, 0x8140); + } else if (adapter->hw.phy.type == e1000_phy_gg82563) + e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, 0x1CC); + + ctrl_reg = er32(CTRL); + + if (adapter->hw.phy.type == e1000_phy_ife) { + /* force 100, set loopback */ + e1e_wphy(hw, PHY_CONTROL, 0x6100); + + /* Now set up the MAC to the same speed/duplex as the PHY. */ + ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */ + ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */ + E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */ + E1000_CTRL_SPD_100 |/* Force Speed to 100 */ + E1000_CTRL_FD); /* Force Duplex to FULL */ + } else { + /* force 1000, set loopback */ + e1e_wphy(hw, PHY_CONTROL, 0x4140); + + /* Now set up the MAC to the same speed/duplex as the PHY. */ + ctrl_reg = er32(CTRL); + ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */ + ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */ + E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */ + E1000_CTRL_SPD_1000 |/* Force Speed to 1000 */ + E1000_CTRL_FD); /* Force Duplex to FULL */ + } + + if (adapter->hw.media_type == e1000_media_type_copper && + adapter->hw.phy.type == e1000_phy_m88) { + ctrl_reg |= E1000_CTRL_ILOS; /* Invert Loss of Signal */ + } else { + /* Set the ILOS bit on the fiber Nic if half duplex link is + * detected. */ + stat_reg = er32(STATUS); + if ((stat_reg & E1000_STATUS_FD) == 0) + ctrl_reg |= (E1000_CTRL_ILOS | E1000_CTRL_SLU); + } + + ew32(CTRL, ctrl_reg); + + /* Disable the receiver on the PHY so when a cable is plugged in, the + * PHY does not begin to autoneg when a cable is reconnected to the NIC. + */ + if (adapter->hw.phy.type == e1000_phy_m88) + e1000_phy_disable_receiver(adapter); + + udelay(500); + + return 0; +} + +static int e1000_set_82571_fiber_loopback(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 ctrl = er32(CTRL); + int link = 0; + + /* special requirements for 82571/82572 fiber adapters */ + + /* jump through hoops to make sure link is up because serdes + * link is hardwired up */ + ctrl |= E1000_CTRL_SLU; + ew32(CTRL, ctrl); + + /* disable autoneg */ + ctrl = er32(TXCW); + ctrl &= ~(1 << 31); + ew32(TXCW, ctrl); + + link = (er32(STATUS) & E1000_STATUS_LU); + + if (!link) { + /* set invert loss of signal */ + ctrl = er32(CTRL); + ctrl |= E1000_CTRL_ILOS; + ew32(CTRL, ctrl); + } + + /* special write to serdes control register to enable SerDes analog + * loopback */ +#define E1000_SERDES_LB_ON 0x410 + ew32(SCTL, E1000_SERDES_LB_ON); + msleep(10); + + return 0; +} + +/* only call this for fiber/serdes connections to es2lan */ +static int e1000_set_es2lan_mac_loopback(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 ctrlext = er32(CTRL_EXT); + u32 ctrl = er32(CTRL); + + /* save CTRL_EXT to restore later, reuse an empty variable (unused + on mac_type 80003es2lan) */ + adapter->tx_fifo_head = ctrlext; + + /* clear the serdes mode bits, putting the device into mac loopback */ + ctrlext &= ~E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES; + ew32(CTRL_EXT, ctrlext); + + /* force speed to 1000/FD, link up */ + ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100); + ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX | + E1000_CTRL_SPD_1000 | E1000_CTRL_FD); + ew32(CTRL, ctrl); + + /* set mac loopback */ + ctrl = er32(RCTL); + ctrl |= E1000_RCTL_LBM_MAC; + ew32(RCTL, ctrl); + + /* set testing mode parameters (no need to reset later) */ +#define KMRNCTRLSTA_OPMODE (0x1F << 16) +#define KMRNCTRLSTA_OPMODE_1GB_FD_GMII 0x0582 + ew32(KMRNCTRLSTA, + (KMRNCTRLSTA_OPMODE | KMRNCTRLSTA_OPMODE_1GB_FD_GMII)); + + return 0; +} + +static int e1000_setup_loopback_test(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 rctl; + + if (hw->media_type == e1000_media_type_fiber || + hw->media_type == e1000_media_type_internal_serdes) { + switch (hw->mac.type) { + case e1000_80003es2lan: + return e1000_set_es2lan_mac_loopback(adapter); + break; + case e1000_82571: + case e1000_82572: + return e1000_set_82571_fiber_loopback(adapter); + break; + default: + rctl = er32(RCTL); + rctl |= E1000_RCTL_LBM_TCVR; + ew32(RCTL, rctl); + return 0; + } + } else if (hw->media_type == e1000_media_type_copper) { + return e1000_integrated_phy_loopback(adapter); + } + + return 7; +} + +static void e1000_loopback_cleanup(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 rctl; + u16 phy_reg; + + rctl = er32(RCTL); + rctl &= ~(E1000_RCTL_LBM_TCVR | E1000_RCTL_LBM_MAC); + ew32(RCTL, rctl); + + switch (hw->mac.type) { + case e1000_80003es2lan: + if (hw->media_type == e1000_media_type_fiber || + hw->media_type == e1000_media_type_internal_serdes) { + /* restore CTRL_EXT, stealing space from tx_fifo_head */ + ew32(CTRL_EXT, + adapter->tx_fifo_head); + adapter->tx_fifo_head = 0; + } + /* fall through */ + case e1000_82571: + case e1000_82572: + if (hw->media_type == e1000_media_type_fiber || + hw->media_type == e1000_media_type_internal_serdes) { +#define E1000_SERDES_LB_OFF 0x400 + ew32(SCTL, E1000_SERDES_LB_OFF); + msleep(10); + break; + } + /* Fall Through */ + default: + hw->mac.autoneg = 1; + if (hw->phy.type == e1000_phy_gg82563) + e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, 0x180); + e1e_rphy(hw, PHY_CONTROL, &phy_reg); + if (phy_reg & MII_CR_LOOPBACK) { + phy_reg &= ~MII_CR_LOOPBACK; + e1e_wphy(hw, PHY_CONTROL, phy_reg); + e1000e_commit_phy(hw); + } + break; + } +} + +static void e1000_create_lbtest_frame(struct sk_buff *skb, + unsigned int frame_size) +{ + memset(skb->data, 0xFF, frame_size); + frame_size &= ~1; + memset(&skb->data[frame_size / 2], 0xAA, frame_size / 2 - 1); + memset(&skb->data[frame_size / 2 + 10], 0xBE, 1); + memset(&skb->data[frame_size / 2 + 12], 0xAF, 1); +} + +static int e1000_check_lbtest_frame(struct sk_buff *skb, + unsigned int frame_size) +{ + frame_size &= ~1; + if (*(skb->data + 3) == 0xFF) + if ((*(skb->data + frame_size / 2 + 10) == 0xBE) && + (*(skb->data + frame_size / 2 + 12) == 0xAF)) + return 0; + return 13; +} + +static int e1000_run_loopback_test(struct e1000_adapter *adapter) +{ + struct e1000_ring *tx_ring = &adapter->test_tx_ring; + struct e1000_ring *rx_ring = &adapter->test_rx_ring; + struct pci_dev *pdev = adapter->pdev; + struct e1000_hw *hw = &adapter->hw; + int i, j, k, l; + int lc; + int good_cnt; + int ret_val = 0; + unsigned long time; + + ew32(RDT, rx_ring->count - 1); + + /* Calculate the loop count based on the largest descriptor ring + * The idea is to wrap the largest ring a number of times using 64 + * send/receive pairs during each loop + */ + + if (rx_ring->count <= tx_ring->count) + lc = ((tx_ring->count / 64) * 2) + 1; + else + lc = ((rx_ring->count / 64) * 2) + 1; + + k = 0; + l = 0; + for (j = 0; j <= lc; j++) { /* loop count loop */ + for (i = 0; i < 64; i++) { /* send the packets */ + e1000_create_lbtest_frame( + tx_ring->buffer_info[i].skb, 1024); + pci_dma_sync_single_for_device(pdev, + tx_ring->buffer_info[k].dma, + tx_ring->buffer_info[k].length, + PCI_DMA_TODEVICE); + k++; + if (k == tx_ring->count) + k = 0; + } + ew32(TDT, k); + msleep(200); + time = jiffies; /* set the start time for the receive */ + good_cnt = 0; + do { /* receive the sent packets */ + pci_dma_sync_single_for_cpu(pdev, + rx_ring->buffer_info[l].dma, 2048, + PCI_DMA_FROMDEVICE); + + ret_val = e1000_check_lbtest_frame( + rx_ring->buffer_info[l].skb, 1024); + if (!ret_val) + good_cnt++; + l++; + if (l == rx_ring->count) + l = 0; + /* time + 20 msecs (200 msecs on 2.4) is more than + * enough time to complete the receives, if it's + * exceeded, break and error off + */ + } while ((good_cnt < 64) && !time_after(jiffies, time + 20)); + if (good_cnt != 64) { + ret_val = 13; /* ret_val is the same as mis-compare */ + break; + } + if (jiffies >= (time + 2)) { + ret_val = 14; /* error code for time out error */ + break; + } + } /* end loop count loop */ + return ret_val; +} + +static int e1000_loopback_test(struct e1000_adapter *adapter, u64 *data) +{ + /* PHY loopback cannot be performed if SoL/IDER + * sessions are active */ + if (e1000_check_reset_block(&adapter->hw)) { + ndev_err(adapter->netdev, "Cannot do PHY loopback test " + "when SoL/IDER is active.\n"); + *data = 0; + goto out; + } + + *data = e1000_setup_desc_rings(adapter); + if (data) + goto out; + + *data = e1000_setup_loopback_test(adapter); + if (data) + goto err_loopback; + + *data = e1000_run_loopback_test(adapter); + e1000_loopback_cleanup(adapter); + +err_loopback: + e1000_free_desc_rings(adapter); +out: + return *data; +} + +static int e1000_link_test(struct e1000_adapter *adapter, u64 *data) +{ + struct e1000_hw *hw = &adapter->hw; + + *data = 0; + if (hw->media_type == e1000_media_type_internal_serdes) { + int i = 0; + hw->mac.serdes_has_link = 0; + + /* On some blade server designs, link establishment + * could take as long as 2-3 minutes */ + do { + hw->mac.ops.check_for_link(hw); + if (hw->mac.serdes_has_link) + return *data; + msleep(20); + } while (i++ < 3750); + + *data = 1; + } else { + hw->mac.ops.check_for_link(hw); + if (hw->mac.autoneg) + msleep(4000); + + if (!(er32(STATUS) & + E1000_STATUS_LU)) + *data = 1; + } + return *data; +} + +static int e1000_diag_test_count(struct net_device *netdev) +{ + return E1000_TEST_LEN; +} + +static void e1000_diag_test(struct net_device *netdev, + struct ethtool_test *eth_test, u64 *data) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + u16 autoneg_advertised; + u8 forced_speed_duplex; + u8 autoneg; + bool if_running = netif_running(netdev); + + set_bit(__E1000_TESTING, &adapter->state); + if (eth_test->flags == ETH_TEST_FL_OFFLINE) { + /* Offline tests */ + + /* save speed, duplex, autoneg settings */ + autoneg_advertised = adapter->hw.phy.autoneg_advertised; + forced_speed_duplex = adapter->hw.mac.forced_speed_duplex; + autoneg = adapter->hw.mac.autoneg; + + ndev_info(netdev, "offline testing starting\n"); + + /* Link test performed before hardware reset so autoneg doesn't + * interfere with test result */ + if (e1000_link_test(adapter, &data[4])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + if (if_running) + /* indicate we're in test mode */ + dev_close(netdev); + else + e1000e_reset(adapter); + + if (e1000_reg_test(adapter, &data[0])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + e1000e_reset(adapter); + if (e1000_eeprom_test(adapter, &data[1])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + e1000e_reset(adapter); + if (e1000_intr_test(adapter, &data[2])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + e1000e_reset(adapter); + /* make sure the phy is powered up */ + e1000e_power_up_phy(adapter); + if (e1000_loopback_test(adapter, &data[3])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + /* restore speed, duplex, autoneg settings */ + adapter->hw.phy.autoneg_advertised = autoneg_advertised; + adapter->hw.mac.forced_speed_duplex = forced_speed_duplex; + adapter->hw.mac.autoneg = autoneg; + + /* force this routine to wait until autoneg complete/timeout */ + adapter->hw.phy.wait_for_link = 1; + e1000e_reset(adapter); + adapter->hw.phy.wait_for_link = 0; + + clear_bit(__E1000_TESTING, &adapter->state); + if (if_running) + dev_open(netdev); + } else { + ndev_info(netdev, "online testing starting\n"); + /* Online tests */ + if (e1000_link_test(adapter, &data[4])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + /* Online tests aren't run; pass by default */ + data[0] = 0; + data[1] = 0; + data[2] = 0; + data[3] = 0; + + clear_bit(__E1000_TESTING, &adapter->state); + } + msleep_interruptible(4 * 1000); +} + +static void e1000_get_wol(struct net_device *netdev, + struct ethtool_wolinfo *wol) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + + wol->supported = 0; + wol->wolopts = 0; + + if (!(adapter->flags & FLAG_HAS_WOL)) + return; + + wol->supported = WAKE_UCAST | WAKE_MCAST | + WAKE_BCAST | WAKE_MAGIC; + + /* apply any specific unsupported masks here */ + if (adapter->flags & FLAG_NO_WAKE_UCAST) { + wol->supported &= ~WAKE_UCAST; + + if (adapter->wol & E1000_WUFC_EX) + ndev_err(netdev, "Interface does not support " + "directed (unicast) frame wake-up packets\n"); + } + + if (adapter->wol & E1000_WUFC_EX) + wol->wolopts |= WAKE_UCAST; + if (adapter->wol & E1000_WUFC_MC) + wol->wolopts |= WAKE_MCAST; + if (adapter->wol & E1000_WUFC_BC) + wol->wolopts |= WAKE_BCAST; + if (adapter->wol & E1000_WUFC_MAG) + wol->wolopts |= WAKE_MAGIC; +} + +static int e1000_set_wol(struct net_device *netdev, + struct ethtool_wolinfo *wol) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + + if (wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE)) + return -EOPNOTSUPP; + + if (!(adapter->flags & FLAG_HAS_WOL)) + return wol->wolopts ? -EOPNOTSUPP : 0; + + /* these settings will always override what we currently have */ + adapter->wol = 0; + + if (wol->wolopts & WAKE_UCAST) + adapter->wol |= E1000_WUFC_EX; + if (wol->wolopts & WAKE_MCAST) + adapter->wol |= E1000_WUFC_MC; + if (wol->wolopts & WAKE_BCAST) + adapter->wol |= E1000_WUFC_BC; + if (wol->wolopts & WAKE_MAGIC) + adapter->wol |= E1000_WUFC_MAG; + + return 0; +} + +/* toggle LED 4 times per second = 2 "blinks" per second */ +#define E1000_ID_INTERVAL (HZ/4) + +/* bit defines for adapter->led_status */ +#define E1000_LED_ON 0 + +static void e1000_led_blink_callback(unsigned long data) +{ + struct e1000_adapter *adapter = (struct e1000_adapter *) data; + + if (test_and_change_bit(E1000_LED_ON, &adapter->led_status)) + adapter->hw.mac.ops.led_off(&adapter->hw); + else + adapter->hw.mac.ops.led_on(&adapter->hw); + + mod_timer(&adapter->blink_timer, jiffies + E1000_ID_INTERVAL); +} + +static int e1000_phys_id(struct net_device *netdev, u32 data) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + + if (!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ)) + data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ); + + if (adapter->hw.phy.type == e1000_phy_ife) { + if (!adapter->blink_timer.function) { + init_timer(&adapter->blink_timer); + adapter->blink_timer.function = + e1000_led_blink_callback; + adapter->blink_timer.data = (unsigned long) adapter; + } + mod_timer(&adapter->blink_timer, jiffies); + msleep_interruptible(data * 1000); + del_timer_sync(&adapter->blink_timer); + e1e_wphy(&adapter->hw, + IFE_PHY_SPECIAL_CONTROL_LED, 0); + } else { + e1000e_blink_led(&adapter->hw); + msleep_interruptible(data * 1000); + } + + adapter->hw.mac.ops.led_off(&adapter->hw); + clear_bit(E1000_LED_ON, &adapter->led_status); + adapter->hw.mac.ops.cleanup_led(&adapter->hw); + + return 0; +} + +static int e1000_nway_reset(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + if (netif_running(netdev)) + e1000e_reinit_locked(adapter); + return 0; +} + +static int e1000_get_stats_count(struct net_device *netdev) +{ + return E1000_STATS_LEN; +} + +static void e1000_get_ethtool_stats(struct net_device *netdev, + struct ethtool_stats *stats, + u64 *data) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + int i; + + e1000e_update_stats(adapter); + for (i = 0; i < E1000_GLOBAL_STATS_LEN; i++) { + char *p = (char *)adapter+e1000_gstrings_stats[i].stat_offset; + data[i] = (e1000_gstrings_stats[i].sizeof_stat == + sizeof(u64)) ? *(u64 *)p : *(u32 *)p; + } +} + +static void e1000_get_strings(struct net_device *netdev, u32 stringset, + u8 *data) +{ + u8 *p = data; + int i; + + switch (stringset) { + case ETH_SS_TEST: + memcpy(data, *e1000_gstrings_test, + E1000_TEST_LEN*ETH_GSTRING_LEN); + break; + case ETH_SS_STATS: + for (i = 0; i < E1000_GLOBAL_STATS_LEN; i++) { + memcpy(p, e1000_gstrings_stats[i].stat_string, + ETH_GSTRING_LEN); + p += ETH_GSTRING_LEN; + } + break; + } +} + +static const struct ethtool_ops e1000_ethtool_ops = { + .get_settings = e1000_get_settings, + .set_settings = e1000_set_settings, + .get_drvinfo = e1000_get_drvinfo, + .get_regs_len = e1000_get_regs_len, + .get_regs = e1000_get_regs, + .get_wol = e1000_get_wol, + .set_wol = e1000_set_wol, + .get_msglevel = e1000_get_msglevel, + .set_msglevel = e1000_set_msglevel, + .nway_reset = e1000_nway_reset, + .get_link = ethtool_op_get_link, + .get_eeprom_len = e1000_get_eeprom_len, + .get_eeprom = e1000_get_eeprom, + .set_eeprom = e1000_set_eeprom, + .get_ringparam = e1000_get_ringparam, + .set_ringparam = e1000_set_ringparam, + .get_pauseparam = e1000_get_pauseparam, + .set_pauseparam = e1000_set_pauseparam, + .get_rx_csum = e1000_get_rx_csum, + .set_rx_csum = e1000_set_rx_csum, + .get_tx_csum = e1000_get_tx_csum, + .set_tx_csum = e1000_set_tx_csum, + .get_sg = ethtool_op_get_sg, + .set_sg = ethtool_op_set_sg, + .get_tso = ethtool_op_get_tso, + .set_tso = e1000_set_tso, + .self_test_count = e1000_diag_test_count, + .self_test = e1000_diag_test, + .get_strings = e1000_get_strings, + .phys_id = e1000_phys_id, + .get_stats_count = e1000_get_stats_count, + .get_ethtool_stats = e1000_get_ethtool_stats, +}; + +void e1000e_set_ethtool_ops(struct net_device *netdev) +{ + SET_ETHTOOL_OPS(netdev, &e1000_ethtool_ops); +} diff --git a/drivers/net/e1000e/hw.h b/drivers/net/e1000e/hw.h new file mode 100644 index 00000000000..848217a3825 --- /dev/null +++ b/drivers/net/e1000e/hw.h @@ -0,0 +1,864 @@ +/******************************************************************************* + + Intel PRO/1000 Linux driver + Copyright(c) 1999 - 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#ifndef _E1000_HW_H_ +#define _E1000_HW_H_ + +#include + +struct e1000_hw; +struct e1000_adapter; + +#include "defines.h" + +#define er32(reg) __er32(hw, E1000_##reg) +#define ew32(reg,val) __ew32(hw, E1000_##reg, (val)) +#define e1e_flush() er32(STATUS) + +#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) \ + (writel((value), ((a)->hw_addr + reg + ((offset) << 2)))) + +#define E1000_READ_REG_ARRAY(a, reg, offset) \ + (readl((a)->hw_addr + reg + ((offset) << 2))) + +enum e1e_registers { + E1000_CTRL = 0x00000, /* Device Control - RW */ + E1000_STATUS = 0x00008, /* Device Status - RO */ + E1000_EECD = 0x00010, /* EEPROM/Flash Control - RW */ + E1000_EERD = 0x00014, /* EEPROM Read - RW */ + E1000_CTRL_EXT = 0x00018, /* Extended Device Control - RW */ + E1000_FLA = 0x0001C, /* Flash Access - RW */ + E1000_MDIC = 0x00020, /* MDI Control - RW */ + E1000_SCTL = 0x00024, /* SerDes Control - RW */ + E1000_FCAL = 0x00028, /* Flow Control Address Low - RW */ + E1000_FCAH = 0x0002C, /* Flow Control Address High -RW */ + E1000_FEXTNVM = 0x00028, /* Future Extended NVM - RW */ + E1000_FCT = 0x00030, /* Flow Control Type - RW */ + E1000_VET = 0x00038, /* VLAN Ether Type - RW */ + E1000_ICR = 0x000C0, /* Interrupt Cause Read - R/clr */ + E1000_ITR = 0x000C4, /* Interrupt Throttling Rate - RW */ + E1000_ICS = 0x000C8, /* Interrupt Cause Set - WO */ + E1000_IMS = 0x000D0, /* Interrupt Mask Set - RW */ + E1000_IMC = 0x000D8, /* Interrupt Mask Clear - WO */ + E1000_IAM = 0x000E0, /* Interrupt Acknowledge Auto Mask */ + E1000_RCTL = 0x00100, /* RX Control - RW */ + E1000_FCTTV = 0x00170, /* Flow Control Transmit Timer Value - RW */ + E1000_TXCW = 0x00178, /* TX Configuration Word - RW */ + E1000_RXCW = 0x00180, /* RX Configuration Word - RO */ + E1000_TCTL = 0x00400, /* TX Control - RW */ + E1000_TCTL_EXT = 0x00404, /* Extended TX Control - RW */ + E1000_TIPG = 0x00410, /* TX Inter-packet gap -RW */ + E1000_AIT = 0x00458, /* Adaptive Interframe Spacing Throttle - RW */ + E1000_LEDCTL = 0x00E00, /* LED Control - RW */ + E1000_EXTCNF_CTRL = 0x00F00, /* Extended Configuration Control */ + E1000_EXTCNF_SIZE = 0x00F08, /* Extended Configuration Size */ + E1000_PHY_CTRL = 0x00F10, /* PHY Control Register in CSR */ + E1000_PBA = 0x01000, /* Packet Buffer Allocation - RW */ + E1000_PBS = 0x01008, /* Packet Buffer Size */ + E1000_EEMNGCTL = 0x01010, /* MNG EEprom Control */ + E1000_EEWR = 0x0102C, /* EEPROM Write Register - RW */ + E1000_FLOP = 0x0103C, /* FLASH Opcode Register */ + E1000_ERT = 0x02008, /* Early Rx Threshold - RW */ + E1000_FCRTL = 0x02160, /* Flow Control Receive Threshold Low - RW */ + E1000_FCRTH = 0x02168, /* Flow Control Receive Threshold High - RW */ + E1000_PSRCTL = 0x02170, /* Packet Split Receive Control - RW */ + E1000_RDBAL = 0x02800, /* RX Descriptor Base Address Low - RW */ + E1000_RDBAH = 0x02804, /* RX Descriptor Base Address High - RW */ + E1000_RDLEN = 0x02808, /* RX Descriptor Length - RW */ + E1000_RDH = 0x02810, /* RX Descriptor Head - RW */ + E1000_RDT = 0x02818, /* RX Descriptor Tail - RW */ + E1000_RDTR = 0x02820, /* RX Delay Timer - RW */ + E1000_RADV = 0x0282C, /* RX Interrupt Absolute Delay Timer - RW */ + +/* Convenience macros + * + * Note: "_n" is the queue number of the register to be written to. + * + * Example usage: + * E1000_RDBAL_REG(current_rx_queue) + * + */ +#define E1000_RDBAL_REG(_n) (E1000_RDBAL + (_n << 8)) + E1000_KABGTXD = 0x03004, /* AFE Band Gap Transmit Ref Data */ + E1000_TDBAL = 0x03800, /* TX Descriptor Base Address Low - RW */ + E1000_TDBAH = 0x03804, /* TX Descriptor Base Address High - RW */ + E1000_TDLEN = 0x03808, /* TX Descriptor Length - RW */ + E1000_TDH = 0x03810, /* TX Descriptor Head - RW */ + E1000_TDT = 0x03818, /* TX Descriptor Tail - RW */ + E1000_TIDV = 0x03820, /* TX Interrupt Delay Value - RW */ + E1000_TXDCTL = 0x03828, /* TX Descriptor Control - RW */ + E1000_TADV = 0x0382C, /* TX Interrupt Absolute Delay Val - RW */ + E1000_TARC0 = 0x03840, /* TX Arbitration Count (0) */ + E1000_TXDCTL1 = 0x03928, /* TX Descriptor Control (1) - RW */ + E1000_TARC1 = 0x03940, /* TX Arbitration Count (1) */ + E1000_CRCERRS = 0x04000, /* CRC Error Count - R/clr */ + E1000_ALGNERRC = 0x04004, /* Alignment Error Count - R/clr */ + E1000_SYMERRS = 0x04008, /* Symbol Error Count - R/clr */ + E1000_RXERRC = 0x0400C, /* Receive Error Count - R/clr */ + E1000_MPC = 0x04010, /* Missed Packet Count - R/clr */ + E1000_SCC = 0x04014, /* Single Collision Count - R/clr */ + E1000_ECOL = 0x04018, /* Excessive Collision Count - R/clr */ + E1000_MCC = 0x0401C, /* Multiple Collision Count - R/clr */ + E1000_LATECOL = 0x04020, /* Late Collision Count - R/clr */ + E1000_COLC = 0x04028, /* Collision Count - R/clr */ + E1000_DC = 0x04030, /* Defer Count - R/clr */ + E1000_TNCRS = 0x04034, /* TX-No CRS - R/clr */ + E1000_SEC = 0x04038, /* Sequence Error Count - R/clr */ + E1000_CEXTERR = 0x0403C, /* Carrier Extension Error Count - R/clr */ + E1000_RLEC = 0x04040, /* Receive Length Error Count - R/clr */ + E1000_XONRXC = 0x04048, /* XON RX Count - R/clr */ + E1000_XONTXC = 0x0404C, /* XON TX Count - R/clr */ + E1000_XOFFRXC = 0x04050, /* XOFF RX Count - R/clr */ + E1000_XOFFTXC = 0x04054, /* XOFF TX Count - R/clr */ + E1000_FCRUC = 0x04058, /* Flow Control RX Unsupported Count- R/clr */ + E1000_PRC64 = 0x0405C, /* Packets RX (64 bytes) - R/clr */ + E1000_PRC127 = 0x04060, /* Packets RX (65-127 bytes) - R/clr */ + E1000_PRC255 = 0x04064, /* Packets RX (128-255 bytes) - R/clr */ + E1000_PRC511 = 0x04068, /* Packets RX (255-511 bytes) - R/clr */ + E1000_PRC1023 = 0x0406C, /* Packets RX (512-1023 bytes) - R/clr */ + E1000_PRC1522 = 0x04070, /* Packets RX (1024-1522 bytes) - R/clr */ + E1000_GPRC = 0x04074, /* Good Packets RX Count - R/clr */ + E1000_BPRC = 0x04078, /* Broadcast Packets RX Count - R/clr */ + E1000_MPRC = 0x0407C, /* Multicast Packets RX Count - R/clr */ + E1000_GPTC = 0x04080, /* Good Packets TX Count - R/clr */ + E1000_GORCL = 0x04088, /* Good Octets RX Count Low - R/clr */ + E1000_GORCH = 0x0408C, /* Good Octets RX Count High - R/clr */ + E1000_GOTCL = 0x04090, /* Good Octets TX Count Low - R/clr */ + E1000_GOTCH = 0x04094, /* Good Octets TX Count High - R/clr */ + E1000_RNBC = 0x040A0, /* RX No Buffers Count - R/clr */ + E1000_RUC = 0x040A4, /* RX Undersize Count - R/clr */ + E1000_RFC = 0x040A8, /* RX Fragment Count - R/clr */ + E1000_ROC = 0x040AC, /* RX Oversize Count - R/clr */ + E1000_RJC = 0x040B0, /* RX Jabber Count - R/clr */ + E1000_MGTPRC = 0x040B4, /* Management Packets RX Count - R/clr */ + E1000_MGTPDC = 0x040B8, /* Management Packets Dropped Count - R/clr */ + E1000_MGTPTC = 0x040BC, /* Management Packets TX Count - R/clr */ + E1000_TORL = 0x040C0, /* Total Octets RX Low - R/clr */ + E1000_TORH = 0x040C4, /* Total Octets RX High - R/clr */ + E1000_TOTL = 0x040C8, /* Total Octets TX Low - R/clr */ + E1000_TOTH = 0x040CC, /* Total Octets TX High - R/clr */ + E1000_TPR = 0x040D0, /* Total Packets RX - R/clr */ + E1000_TPT = 0x040D4, /* Total Packets TX - R/clr */ + E1000_PTC64 = 0x040D8, /* Packets TX (64 bytes) - R/clr */ + E1000_PTC127 = 0x040DC, /* Packets TX (65-127 bytes) - R/clr */ + E1000_PTC255 = 0x040E0, /* Packets TX (128-255 bytes) - R/clr */ + E1000_PTC511 = 0x040E4, /* Packets TX (256-511 bytes) - R/clr */ + E1000_PTC1023 = 0x040E8, /* Packets TX (512-1023 bytes) - R/clr */ + E1000_PTC1522 = 0x040EC, /* Packets TX (1024-1522 Bytes) - R/clr */ + E1000_MPTC = 0x040F0, /* Multicast Packets TX Count - R/clr */ + E1000_BPTC = 0x040F4, /* Broadcast Packets TX Count - R/clr */ + E1000_TSCTC = 0x040F8, /* TCP Segmentation Context TX - R/clr */ + E1000_TSCTFC = 0x040FC, /* TCP Segmentation Context TX Fail - R/clr */ + E1000_IAC = 0x04100, /* Interrupt Assertion Count */ + E1000_ICRXPTC = 0x04104, /* Irq Cause Rx Packet Timer Expire Count */ + E1000_ICRXATC = 0x04108, /* Irq Cause Rx Abs Timer Expire Count */ + E1000_ICTXPTC = 0x0410C, /* Irq Cause Tx Packet Timer Expire Count */ + E1000_ICTXATC = 0x04110, /* Irq Cause Tx Abs Timer Expire Count */ + E1000_ICTXQEC = 0x04118, /* Irq Cause Tx Queue Empty Count */ + E1000_ICTXQMTC = 0x0411C, /* Irq Cause Tx Queue MinThreshold Count */ + E1000_ICRXDMTC = 0x04120, /* Irq Cause Rx Desc MinThreshold Count */ + E1000_ICRXOC = 0x04124, /* Irq Cause Receiver Overrun Count */ + E1000_RXCSUM = 0x05000, /* RX Checksum Control - RW */ + E1000_RFCTL = 0x05008, /* Receive Filter Control*/ + E1000_MTA = 0x05200, /* Multicast Table Array - RW Array */ + E1000_RA = 0x05400, /* Receive Address - RW Array */ + E1000_VFTA = 0x05600, /* VLAN Filter Table Array - RW Array */ + E1000_WUC = 0x05800, /* Wakeup Control - RW */ + E1000_WUFC = 0x05808, /* Wakeup Filter Control - RW */ + E1000_WUS = 0x05810, /* Wakeup Status - RO */ + E1000_MANC = 0x05820, /* Management Control - RW */ + E1000_FFLT = 0x05F00, /* Flexible Filter Length Table - RW Array */ + E1000_HOST_IF = 0x08800, /* Host Interface */ + + E1000_KMRNCTRLSTA = 0x00034, /* MAC-PHY interface - RW */ + E1000_MANC2H = 0x05860, /* Management Control To Host - RW */ + E1000_SW_FW_SYNC = 0x05B5C, /* Software-Firmware Synchronization - RW */ + E1000_GCR = 0x05B00, /* PCI-Ex Control */ + E1000_FACTPS = 0x05B30, /* Function Active and Power State to MNG */ + E1000_SWSM = 0x05B50, /* SW Semaphore */ + E1000_FWSM = 0x05B54, /* FW Semaphore */ + E1000_HICR = 0x08F00, /* Host Inteface Control */ +}; + +/* RSS registers */ + +/* IGP01E1000 Specific Registers */ +#define IGP01E1000_PHY_PORT_CONFIG 0x10 /* Port Config */ +#define IGP01E1000_PHY_PORT_STATUS 0x11 /* Status */ +#define IGP01E1000_PHY_PORT_CTRL 0x12 /* Control */ +#define IGP01E1000_PHY_LINK_HEALTH 0x13 /* PHY Link Health */ +#define IGP02E1000_PHY_POWER_MGMT 0x19 /* Power Management */ +#define IGP01E1000_PHY_PAGE_SELECT 0x1F /* Page Select */ + +#define IGP01E1000_PHY_PCS_INIT_REG 0x00B4 +#define IGP01E1000_PHY_POLARITY_MASK 0x0078 + +#define IGP01E1000_PSCR_AUTO_MDIX 0x1000 +#define IGP01E1000_PSCR_FORCE_MDI_MDIX 0x2000 /* 0=MDI, 1=MDIX */ + +#define IGP01E1000_PSCFR_SMART_SPEED 0x0080 + +#define IGP02E1000_PM_SPD 0x0001 /* Smart Power Down */ +#define IGP02E1000_PM_D0_LPLU 0x0002 /* For D0a states */ +#define IGP02E1000_PM_D3_LPLU 0x0004 /* For all other states */ + +#define IGP01E1000_PLHR_SS_DOWNGRADE 0x8000 + +#define IGP01E1000_PSSR_POLARITY_REVERSED 0x0002 +#define IGP01E1000_PSSR_MDIX 0x0008 +#define IGP01E1000_PSSR_SPEED_MASK 0xC000 +#define IGP01E1000_PSSR_SPEED_1000MBPS 0xC000 + +#define IGP02E1000_PHY_CHANNEL_NUM 4 +#define IGP02E1000_PHY_AGC_A 0x11B1 +#define IGP02E1000_PHY_AGC_B 0x12B1 +#define IGP02E1000_PHY_AGC_C 0x14B1 +#define IGP02E1000_PHY_AGC_D 0x18B1 + +#define IGP02E1000_AGC_LENGTH_SHIFT 9 /* Course - 15:13, Fine - 12:9 */ +#define IGP02E1000_AGC_LENGTH_MASK 0x7F +#define IGP02E1000_AGC_RANGE 15 + +/* manage.c */ +#define E1000_VFTA_ENTRY_SHIFT 5 +#define E1000_VFTA_ENTRY_MASK 0x7F +#define E1000_VFTA_ENTRY_BIT_SHIFT_MASK 0x1F + +#define E1000_HICR_EN 0x01 /* Enable bit - RO */ +#define E1000_HICR_C 0x02 /* Driver sets this bit when done + * to put command in RAM */ +#define E1000_HICR_FW_RESET_ENABLE 0x40 +#define E1000_HICR_FW_RESET 0x80 + +#define E1000_FWSM_MODE_MASK 0xE +#define E1000_FWSM_MODE_SHIFT 1 + +#define E1000_MNG_IAMT_MODE 0x3 +#define E1000_MNG_DHCP_COOKIE_LENGTH 0x10 +#define E1000_MNG_DHCP_COOKIE_OFFSET 0x6F0 +#define E1000_MNG_DHCP_COMMAND_TIMEOUT 10 +#define E1000_MNG_DHCP_TX_PAYLOAD_CMD 64 +#define E1000_MNG_DHCP_COOKIE_STATUS_PARSING 0x1 +#define E1000_MNG_DHCP_COOKIE_STATUS_VLAN 0x2 + +/* nvm.c */ +#define E1000_STM_OPCODE 0xDB00 + +#define E1000_KMRNCTRLSTA_OFFSET 0x001F0000 +#define E1000_KMRNCTRLSTA_OFFSET_SHIFT 16 +#define E1000_KMRNCTRLSTA_REN 0x00200000 +#define E1000_KMRNCTRLSTA_DIAG_OFFSET 0x3 /* Kumeran Diagnostic */ +#define E1000_KMRNCTRLSTA_DIAG_NELPBK 0x1000 /* Nearend Loopback mode */ + +#define IFE_PHY_EXTENDED_STATUS_CONTROL 0x10 +#define IFE_PHY_SPECIAL_CONTROL 0x11 /* 100BaseTx PHY Special Control */ +#define IFE_PHY_SPECIAL_CONTROL_LED 0x1B /* PHY Special and LED Control */ +#define IFE_PHY_MDIX_CONTROL 0x1C /* MDI/MDI-X Control */ + +/* IFE PHY Extended Status Control */ +#define IFE_PESC_POLARITY_REVERSED 0x0100 + +/* IFE PHY Special Control */ +#define IFE_PSC_AUTO_POLARITY_DISABLE 0x0010 +#define IFE_PSC_FORCE_POLARITY 0x0020 + +/* IFE PHY Special Control and LED Control */ +#define IFE_PSCL_PROBE_MODE 0x0020 +#define IFE_PSCL_PROBE_LEDS_OFF 0x0006 /* Force LEDs 0 and 2 off */ +#define IFE_PSCL_PROBE_LEDS_ON 0x0007 /* Force LEDs 0 and 2 on */ + +/* IFE PHY MDIX Control */ +#define IFE_PMC_MDIX_STATUS 0x0020 /* 1=MDI-X, 0=MDI */ +#define IFE_PMC_FORCE_MDIX 0x0040 /* 1=force MDI-X, 0=force MDI */ +#define IFE_PMC_AUTO_MDIX 0x0080 /* 1=enable auto MDI/MDI-X, 0=disable */ + +#define E1000_CABLE_LENGTH_UNDEFINED 0xFF + +#define E1000_DEV_ID_82571EB_COPPER 0x105E +#define E1000_DEV_ID_82571EB_FIBER 0x105F +#define E1000_DEV_ID_82571EB_SERDES 0x1060 +#define E1000_DEV_ID_82571EB_QUAD_COPPER 0x10A4 +#define E1000_DEV_ID_82571EB_QUAD_FIBER 0x10A5 +#define E1000_DEV_ID_82571EB_QUAD_COPPER_LP 0x10BC +#define E1000_DEV_ID_82572EI_COPPER 0x107D +#define E1000_DEV_ID_82572EI_FIBER 0x107E +#define E1000_DEV_ID_82572EI_SERDES 0x107F +#define E1000_DEV_ID_82572EI 0x10B9 +#define E1000_DEV_ID_82573E 0x108B +#define E1000_DEV_ID_82573E_IAMT 0x108C +#define E1000_DEV_ID_82573L 0x109A + +#define E1000_DEV_ID_80003ES2LAN_COPPER_DPT 0x1096 +#define E1000_DEV_ID_80003ES2LAN_SERDES_DPT 0x1098 +#define E1000_DEV_ID_80003ES2LAN_COPPER_SPT 0x10BA +#define E1000_DEV_ID_80003ES2LAN_SERDES_SPT 0x10BB + +#define E1000_DEV_ID_ICH8_IGP_M_AMT 0x1049 +#define E1000_DEV_ID_ICH8_IGP_AMT 0x104A +#define E1000_DEV_ID_ICH8_IGP_C 0x104B +#define E1000_DEV_ID_ICH8_IFE 0x104C +#define E1000_DEV_ID_ICH8_IFE_GT 0x10C4 +#define E1000_DEV_ID_ICH8_IFE_G 0x10C5 +#define E1000_DEV_ID_ICH8_IGP_M 0x104D +#define E1000_DEV_ID_ICH9_IGP_AMT 0x10BD +#define E1000_DEV_ID_ICH9_IGP_C 0x294C +#define E1000_DEV_ID_ICH9_IFE 0x10C0 +#define E1000_DEV_ID_ICH9_IFE_GT 0x10C3 +#define E1000_DEV_ID_ICH9_IFE_G 0x10C2 + +#define E1000_FUNC_1 1 + +enum e1000_mac_type { + e1000_82571, + e1000_82572, + e1000_82573, + e1000_80003es2lan, + e1000_ich8lan, + e1000_ich9lan, +}; + +enum e1000_media_type { + e1000_media_type_unknown = 0, + e1000_media_type_copper = 1, + e1000_media_type_fiber = 2, + e1000_media_type_internal_serdes = 3, + e1000_num_media_types +}; + +enum e1000_nvm_type { + e1000_nvm_unknown = 0, + e1000_nvm_none, + e1000_nvm_eeprom_spi, + e1000_nvm_flash_hw, + e1000_nvm_flash_sw +}; + +enum e1000_nvm_override { + e1000_nvm_override_none = 0, + e1000_nvm_override_spi_small, + e1000_nvm_override_spi_large +}; + +enum e1000_phy_type { + e1000_phy_unknown = 0, + e1000_phy_none, + e1000_phy_m88, + e1000_phy_igp, + e1000_phy_igp_2, + e1000_phy_gg82563, + e1000_phy_igp_3, + e1000_phy_ife, +}; + +enum e1000_bus_width { + e1000_bus_width_unknown = 0, + e1000_bus_width_pcie_x1, + e1000_bus_width_pcie_x2, + e1000_bus_width_pcie_x4 = 4, + e1000_bus_width_32, + e1000_bus_width_64, + e1000_bus_width_reserved +}; + +enum e1000_1000t_rx_status { + e1000_1000t_rx_status_not_ok = 0, + e1000_1000t_rx_status_ok, + e1000_1000t_rx_status_undefined = 0xFF +}; + +enum e1000_rev_polarity{ + e1000_rev_polarity_normal = 0, + e1000_rev_polarity_reversed, + e1000_rev_polarity_undefined = 0xFF +}; + +enum e1000_fc_mode { + e1000_fc_none = 0, + e1000_fc_rx_pause, + e1000_fc_tx_pause, + e1000_fc_full, + e1000_fc_default = 0xFF +}; + +enum e1000_ms_type { + e1000_ms_hw_default = 0, + e1000_ms_force_master, + e1000_ms_force_slave, + e1000_ms_auto +}; + +enum e1000_smart_speed { + e1000_smart_speed_default = 0, + e1000_smart_speed_on, + e1000_smart_speed_off +}; + +/* Receive Descriptor */ +struct e1000_rx_desc { + u64 buffer_addr; /* Address of the descriptor's data buffer */ + u16 length; /* Length of data DMAed into data buffer */ + u16 csum; /* Packet checksum */ + u8 status; /* Descriptor status */ + u8 errors; /* Descriptor Errors */ + u16 special; +}; + +/* Receive Descriptor - Extended */ +union e1000_rx_desc_extended { + struct { + u64 buffer_addr; + u64 reserved; + } read; + struct { + struct { + u32 mrq; /* Multiple Rx Queues */ + union { + u32 rss; /* RSS Hash */ + struct { + u16 ip_id; /* IP id */ + u16 csum; /* Packet Checksum */ + } csum_ip; + } hi_dword; + } lower; + struct { + u32 status_error; /* ext status/error */ + u16 length; + u16 vlan; /* VLAN tag */ + } upper; + } wb; /* writeback */ +}; + +#define MAX_PS_BUFFERS 4 +/* Receive Descriptor - Packet Split */ +union e1000_rx_desc_packet_split { + struct { + /* one buffer for protocol header(s), three data buffers */ + u64 buffer_addr[MAX_PS_BUFFERS]; + } read; + struct { + struct { + u32 mrq; /* Multiple Rx Queues */ + union { + u32 rss; /* RSS Hash */ + struct { + u16 ip_id; /* IP id */ + u16 csum; /* Packet Checksum */ + } csum_ip; + } hi_dword; + } lower; + struct { + u32 status_error; /* ext status/error */ + u16 length0; /* length of buffer 0 */ + u16 vlan; /* VLAN tag */ + } middle; + struct { + u16 header_status; + u16 length[3]; /* length of buffers 1-3 */ + } upper; + u64 reserved; + } wb; /* writeback */ +}; + +/* Transmit Descriptor */ +struct e1000_tx_desc { + u64 buffer_addr; /* Address of the descriptor's data buffer */ + union { + u32 data; + struct { + u16 length; /* Data buffer length */ + u8 cso; /* Checksum offset */ + u8 cmd; /* Descriptor control */ + } flags; + } lower; + union { + u32 data; + struct { + u8 status; /* Descriptor status */ + u8 css; /* Checksum start */ + u16 special; + } fields; + } upper; +}; + +/* Offload Context Descriptor */ +struct e1000_context_desc { + union { + u32 ip_config; + struct { + u8 ipcss; /* IP checksum start */ + u8 ipcso; /* IP checksum offset */ + u16 ipcse; /* IP checksum end */ + } ip_fields; + } lower_setup; + union { + u32 tcp_config; + struct { + u8 tucss; /* TCP checksum start */ + u8 tucso; /* TCP checksum offset */ + u16 tucse; /* TCP checksum end */ + } tcp_fields; + } upper_setup; + u32 cmd_and_length; + union { + u32 data; + struct { + u8 status; /* Descriptor status */ + u8 hdr_len; /* Header length */ + u16 mss; /* Maximum segment size */ + } fields; + } tcp_seg_setup; +}; + +/* Offload data descriptor */ +struct e1000_data_desc { + u64 buffer_addr; /* Address of the descriptor's buffer address */ + union { + u32 data; + struct { + u16 length; /* Data buffer length */ + u8 typ_len_ext; + u8 cmd; + } flags; + } lower; + union { + u32 data; + struct { + u8 status; /* Descriptor status */ + u8 popts; /* Packet Options */ + u16 special; /* */ + } fields; + } upper; +}; + +/* Statistics counters collected by the MAC */ +struct e1000_hw_stats { + u64 crcerrs; + u64 algnerrc; + u64 symerrs; + u64 rxerrc; + u64 mpc; + u64 scc; + u64 ecol; + u64 mcc; + u64 latecol; + u64 colc; + u64 dc; + u64 tncrs; + u64 sec; + u64 cexterr; + u64 rlec; + u64 xonrxc; + u64 xontxc; + u64 xoffrxc; + u64 xofftxc; + u64 fcruc; + u64 prc64; + u64 prc127; + u64 prc255; + u64 prc511; + u64 prc1023; + u64 prc1522; + u64 gprc; + u64 bprc; + u64 mprc; + u64 gptc; + u64 gorcl; + u64 gorch; + u64 gotcl; + u64 gotch; + u64 rnbc; + u64 ruc; + u64 rfc; + u64 roc; + u64 rjc; + u64 mgprc; + u64 mgpdc; + u64 mgptc; + u64 torl; + u64 torh; + u64 totl; + u64 toth; + u64 tpr; + u64 tpt; + u64 ptc64; + u64 ptc127; + u64 ptc255; + u64 ptc511; + u64 ptc1023; + u64 ptc1522; + u64 mptc; + u64 bptc; + u64 tsctc; + u64 tsctfc; + u64 iac; + u64 icrxptc; + u64 icrxatc; + u64 ictxptc; + u64 ictxatc; + u64 ictxqec; + u64 ictxqmtc; + u64 icrxdmtc; + u64 icrxoc; +}; + +struct e1000_phy_stats { + u32 idle_errors; + u32 receive_errors; +}; + +struct e1000_host_mng_dhcp_cookie { + u32 signature; + u8 status; + u8 reserved0; + u16 vlan_id; + u32 reserved1; + u16 reserved2; + u8 reserved3; + u8 checksum; +}; + +/* Host Interface "Rev 1" */ +struct e1000_host_command_header { + u8 command_id; + u8 command_length; + u8 command_options; + u8 checksum; +}; + +#define E1000_HI_MAX_DATA_LENGTH 252 +struct e1000_host_command_info { + struct e1000_host_command_header command_header; + u8 command_data[E1000_HI_MAX_DATA_LENGTH]; +}; + +/* Host Interface "Rev 2" */ +struct e1000_host_mng_command_header { + u8 command_id; + u8 checksum; + u16 reserved1; + u16 reserved2; + u16 command_length; +}; + +#define E1000_HI_MAX_MNG_DATA_LENGTH 0x6F8 +struct e1000_host_mng_command_info { + struct e1000_host_mng_command_header command_header; + u8 command_data[E1000_HI_MAX_MNG_DATA_LENGTH]; +}; + +/* Function pointers and static data for the MAC. */ +struct e1000_mac_operations { + u32 mng_mode_enab; + + s32 (*check_for_link)(struct e1000_hw *); + s32 (*cleanup_led)(struct e1000_hw *); + void (*clear_hw_cntrs)(struct e1000_hw *); + s32 (*get_bus_info)(struct e1000_hw *); + s32 (*get_link_up_info)(struct e1000_hw *, u16 *, u16 *); + s32 (*led_on)(struct e1000_hw *); + s32 (*led_off)(struct e1000_hw *); + void (*mc_addr_list_update)(struct e1000_hw *, u8 *, u32, u32, + u32); + s32 (*reset_hw)(struct e1000_hw *); + s32 (*init_hw)(struct e1000_hw *); + s32 (*setup_link)(struct e1000_hw *); + s32 (*setup_physical_interface)(struct e1000_hw *); +}; + +/* Function pointers for the PHY. */ +struct e1000_phy_operations { + s32 (*acquire_phy)(struct e1000_hw *); + s32 (*check_reset_block)(struct e1000_hw *); + s32 (*commit_phy)(struct e1000_hw *); + s32 (*force_speed_duplex)(struct e1000_hw *); + s32 (*get_cfg_done)(struct e1000_hw *hw); + s32 (*get_cable_length)(struct e1000_hw *); + s32 (*get_phy_info)(struct e1000_hw *); + s32 (*read_phy_reg)(struct e1000_hw *, u32, u16 *); + void (*release_phy)(struct e1000_hw *); + s32 (*reset_phy)(struct e1000_hw *); + s32 (*set_d0_lplu_state)(struct e1000_hw *, bool); + s32 (*set_d3_lplu_state)(struct e1000_hw *, bool); + s32 (*write_phy_reg)(struct e1000_hw *, u32, u16); +}; + +/* Function pointers for the NVM. */ +struct e1000_nvm_operations { + s32 (*acquire_nvm)(struct e1000_hw *); + s32 (*read_nvm)(struct e1000_hw *, u16, u16, u16 *); + void (*release_nvm)(struct e1000_hw *); + s32 (*update_nvm)(struct e1000_hw *); + s32 (*valid_led_default)(struct e1000_hw *, u16 *); + s32 (*validate_nvm)(struct e1000_hw *); + s32 (*write_nvm)(struct e1000_hw *, u16, u16, u16 *); +}; + +struct e1000_mac_info { + struct e1000_mac_operations ops; + + u8 addr[6]; + u8 perm_addr[6]; + + enum e1000_mac_type type; + enum e1000_fc_mode fc; + enum e1000_fc_mode original_fc; + + u32 collision_delta; + u32 ledctl_default; + u32 ledctl_mode1; + u32 ledctl_mode2; + u32 max_frame_size; + u32 mc_filter_type; + u32 min_frame_size; + u32 tx_packet_delta; + u32 txcw; + + u16 current_ifs_val; + u16 ifs_max_val; + u16 ifs_min_val; + u16 ifs_ratio; + u16 ifs_step_size; + u16 mta_reg_count; + u16 rar_entry_count; + u16 fc_high_water; + u16 fc_low_water; + u16 fc_pause_time; + + u8 forced_speed_duplex; + + bool arc_subsystem_valid; + bool autoneg; + bool autoneg_failed; + bool get_link_status; + bool in_ifs_mode; + bool serdes_has_link; + bool tx_pkt_filtering; +}; + +struct e1000_phy_info { + struct e1000_phy_operations ops; + + enum e1000_phy_type type; + + enum e1000_1000t_rx_status local_rx; + enum e1000_1000t_rx_status remote_rx; + enum e1000_ms_type ms_type; + enum e1000_ms_type original_ms_type; + enum e1000_rev_polarity cable_polarity; + enum e1000_smart_speed smart_speed; + + u32 addr; + u32 id; + u32 reset_delay_us; /* in usec */ + u32 revision; + + u16 autoneg_advertised; + u16 autoneg_mask; + u16 cable_length; + u16 max_cable_length; + u16 min_cable_length; + + u8 mdix; + + bool disable_polarity_correction; + bool is_mdix; + bool polarity_correction; + bool speed_downgraded; + bool wait_for_link; +}; + +struct e1000_nvm_info { + struct e1000_nvm_operations ops; + + enum e1000_nvm_type type; + enum e1000_nvm_override override; + + u32 flash_bank_size; + u32 flash_base_addr; + + u16 word_size; + u16 delay_usec; + u16 address_bits; + u16 opcode_bits; + u16 page_size; +}; + +struct e1000_bus_info { + enum e1000_bus_width width; + + u16 func; +}; + +struct e1000_dev_spec_82571 { + bool laa_is_present; +}; + +struct e1000_shadow_ram { + u16 value; + bool modified; +}; + +#define E1000_ICH8_SHADOW_RAM_WORDS 2048 + +struct e1000_dev_spec_ich8lan { + bool kmrn_lock_loss_workaround_enabled; + struct e1000_shadow_ram shadow_ram[E1000_ICH8_SHADOW_RAM_WORDS]; +}; + +struct e1000_hw { + struct e1000_adapter *adapter; + + u8 __iomem *hw_addr; + u8 __iomem *flash_address; + + struct e1000_mac_info mac; + struct e1000_phy_info phy; + struct e1000_nvm_info nvm; + struct e1000_bus_info bus; + struct e1000_host_mng_dhcp_cookie mng_cookie; + + union { + struct e1000_dev_spec_82571 e82571; + struct e1000_dev_spec_ich8lan ich8lan; + } dev_spec; + + enum e1000_media_type media_type; +}; + +#ifdef DEBUG +#define hw_dbg(hw, format, arg...) \ + printk(KERN_DEBUG, "%s: " format, e1000_get_hw_dev_name(hw), ##arg); +#else +static inline int __attribute__ ((format (printf, 2, 3))) +hw_dbg(struct e1000_hw *hw, const char *format, ...) +{ + return 0; +} +#endif + +#endif diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c new file mode 100644 index 00000000000..8f8139de1f4 --- /dev/null +++ b/drivers/net/e1000e/ich8lan.c @@ -0,0 +1,2225 @@ +/******************************************************************************* + + Intel PRO/1000 Linux driver + Copyright(c) 1999 - 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +/* + * 82562G-2 10/100 Network Connection + * 82562GT 10/100 Network Connection + * 82562GT-2 10/100 Network Connection + * 82562V 10/100 Network Connection + * 82562V-2 10/100 Network Connection + * 82566DC-2 Gigabit Network Connection + * 82566DC Gigabit Network Connection + * 82566DM-2 Gigabit Network Connection + * 82566DM Gigabit Network Connection + * 82566MC Gigabit Network Connection + * 82566MM Gigabit Network Connection + */ + +#include +#include +#include +#include + +#include "e1000.h" + +#define ICH_FLASH_GFPREG 0x0000 +#define ICH_FLASH_HSFSTS 0x0004 +#define ICH_FLASH_HSFCTL 0x0006 +#define ICH_FLASH_FADDR 0x0008 +#define ICH_FLASH_FDATA0 0x0010 + +#define ICH_FLASH_READ_COMMAND_TIMEOUT 500 +#define ICH_FLASH_WRITE_COMMAND_TIMEOUT 500 +#define ICH_FLASH_ERASE_COMMAND_TIMEOUT 3000000 +#define ICH_FLASH_LINEAR_ADDR_MASK 0x00FFFFFF +#define ICH_FLASH_CYCLE_REPEAT_COUNT 10 + +#define ICH_CYCLE_READ 0 +#define ICH_CYCLE_WRITE 2 +#define ICH_CYCLE_ERASE 3 + +#define FLASH_GFPREG_BASE_MASK 0x1FFF +#define FLASH_SECTOR_ADDR_SHIFT 12 + +#define ICH_FLASH_SEG_SIZE_256 256 +#define ICH_FLASH_SEG_SIZE_4K 4096 +#define ICH_FLASH_SEG_SIZE_8K 8192 +#define ICH_FLASH_SEG_SIZE_64K 65536 + + +#define E1000_ICH_FWSM_RSPCIPHY 0x00000040 /* Reset PHY on PCI Reset */ + +#define E1000_ICH_MNG_IAMT_MODE 0x2 + +#define ID_LED_DEFAULT_ICH8LAN ((ID_LED_DEF1_DEF2 << 12) | \ + (ID_LED_DEF1_OFF2 << 8) | \ + (ID_LED_DEF1_ON2 << 4) | \ + (ID_LED_DEF1_DEF2)) + +#define E1000_ICH_NVM_SIG_WORD 0x13 +#define E1000_ICH_NVM_SIG_MASK 0xC000 + +#define E1000_ICH8_LAN_INIT_TIMEOUT 1500 + +#define E1000_FEXTNVM_SW_CONFIG 1 +#define E1000_FEXTNVM_SW_CONFIG_ICH8M (1 << 27) /* Bit redefined for ICH8M :/ */ + +#define PCIE_ICH8_SNOOP_ALL PCIE_NO_SNOOP_ALL + +#define E1000_ICH_RAR_ENTRIES 7 + +#define PHY_PAGE_SHIFT 5 +#define PHY_REG(page, reg) (((page) << PHY_PAGE_SHIFT) | \ + ((reg) & MAX_PHY_REG_ADDRESS)) +#define IGP3_KMRN_DIAG PHY_REG(770, 19) /* KMRN Diagnostic */ +#define IGP3_VR_CTRL PHY_REG(776, 18) /* Voltage Regulator Control */ + +#define IGP3_KMRN_DIAG_PCS_LOCK_LOSS 0x0002 +#define IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK 0x0300 +#define IGP3_VR_CTRL_MODE_SHUTDOWN 0x0200 + +/* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */ +/* Offset 04h HSFSTS */ +union ich8_hws_flash_status { + struct ich8_hsfsts { + u16 flcdone :1; /* bit 0 Flash Cycle Done */ + u16 flcerr :1; /* bit 1 Flash Cycle Error */ + u16 dael :1; /* bit 2 Direct Access error Log */ + u16 berasesz :2; /* bit 4:3 Sector Erase Size */ + u16 flcinprog :1; /* bit 5 flash cycle in Progress */ + u16 reserved1 :2; /* bit 13:6 Reserved */ + u16 reserved2 :6; /* bit 13:6 Reserved */ + u16 fldesvalid :1; /* bit 14 Flash Descriptor Valid */ + u16 flockdn :1; /* bit 15 Flash Config Lock-Down */ + } hsf_status; + u16 regval; +}; + +/* ICH GbE Flash Hardware Sequencing Flash control Register bit breakdown */ +/* Offset 06h FLCTL */ +union ich8_hws_flash_ctrl { + struct ich8_hsflctl { + u16 flcgo :1; /* 0 Flash Cycle Go */ + u16 flcycle :2; /* 2:1 Flash Cycle */ + u16 reserved :5; /* 7:3 Reserved */ + u16 fldbcount :2; /* 9:8 Flash Data Byte Count */ + u16 flockdn :6; /* 15:10 Reserved */ + } hsf_ctrl; + u16 regval; +}; + +/* ICH Flash Region Access Permissions */ +union ich8_hws_flash_regacc { + struct ich8_flracc { + u32 grra :8; /* 0:7 GbE region Read Access */ + u32 grwa :8; /* 8:15 GbE region Write Access */ + u32 gmrag :8; /* 23:16 GbE Master Read Access Grant */ + u32 gmwag :8; /* 31:24 GbE Master Write Access Grant */ + } hsf_flregacc; + u16 regval; +}; + +static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw); +static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw); +static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw); +static s32 e1000_check_polarity_ife_ich8lan(struct e1000_hw *hw); +static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank); +static s32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw, + u32 offset, u8 byte); +static s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw, u32 offset, + u16 *data); +static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset, + u8 size, u16 *data); +static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw); +static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw); + +static inline u16 __er16flash(struct e1000_hw *hw, unsigned long reg) +{ + return readw(hw->flash_address + reg); +} + +static inline u32 __er32flash(struct e1000_hw *hw, unsigned long reg) +{ + return readl(hw->flash_address + reg); +} + +static inline void __ew16flash(struct e1000_hw *hw, unsigned long reg, u16 val) +{ + writew(val, hw->flash_address + reg); +} + +static inline void __ew32flash(struct e1000_hw *hw, unsigned long reg, u32 val) +{ + writel(val, hw->flash_address + reg); +} + +#define er16flash(reg) __er16flash(hw, (reg)) +#define er32flash(reg) __er32flash(hw, (reg)) +#define ew16flash(reg,val) __ew16flash(hw, (reg), (val)) +#define ew32flash(reg,val) __ew32flash(hw, (reg), (val)) + +/** + * e1000_init_phy_params_ich8lan - Initialize PHY function pointers + * @hw: pointer to the HW structure + * + * Initialize family-specific PHY parameters and function pointers. + **/ +static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 i = 0; + + phy->addr = 1; + phy->reset_delay_us = 100; + + phy->id = 0; + while ((e1000_phy_unknown == e1000e_get_phy_type_from_id(phy->id)) && + (i++ < 100)) { + msleep(1); + ret_val = e1000e_get_phy_id(hw); + if (ret_val) + return ret_val; + } + + /* Verify phy id */ + switch (phy->id) { + case IGP03E1000_E_PHY_ID: + phy->type = e1000_phy_igp_3; + phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; + break; + case IFE_E_PHY_ID: + case IFE_PLUS_E_PHY_ID: + case IFE_C_E_PHY_ID: + phy->type = e1000_phy_ife; + phy->autoneg_mask = E1000_ALL_NOT_GIG; + break; + default: + return -E1000_ERR_PHY; + break; + } + + return 0; +} + +/** + * e1000_init_nvm_params_ich8lan - Initialize NVM function pointers + * @hw: pointer to the HW structure + * + * Initialize family-specific NVM parameters and function + * pointers. + **/ +static s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; + u32 gfpreg; + u32 sector_base_addr; + u32 sector_end_addr; + u16 i; + + /* Can't read flash registers if the register set isn't mapped. + */ + if (!hw->flash_address) { + hw_dbg(hw, "ERROR: Flash registers not mapped\n"); + return -E1000_ERR_CONFIG; + } + + nvm->type = e1000_nvm_flash_sw; + + gfpreg = er32flash(ICH_FLASH_GFPREG); + + /* sector_X_addr is a "sector"-aligned address (4096 bytes) + * Add 1 to sector_end_addr since this sector is included in + * the overall size. */ + sector_base_addr = gfpreg & FLASH_GFPREG_BASE_MASK; + sector_end_addr = ((gfpreg >> 16) & FLASH_GFPREG_BASE_MASK) + 1; + + /* flash_base_addr is byte-aligned */ + nvm->flash_base_addr = sector_base_addr << FLASH_SECTOR_ADDR_SHIFT; + + /* find total size of the NVM, then cut in half since the total + * size represents two separate NVM banks. */ + nvm->flash_bank_size = (sector_end_addr - sector_base_addr) + << FLASH_SECTOR_ADDR_SHIFT; + nvm->flash_bank_size /= 2; + /* Adjust to word count */ + nvm->flash_bank_size /= sizeof(u16); + + nvm->word_size = E1000_ICH8_SHADOW_RAM_WORDS; + + /* Clear shadow ram */ + for (i = 0; i < nvm->word_size; i++) { + dev_spec->shadow_ram[i].modified = 0; + dev_spec->shadow_ram[i].value = 0xFFFF; + } + + return 0; +} + +/** + * e1000_init_mac_params_ich8lan - Initialize MAC function pointers + * @hw: pointer to the HW structure + * + * Initialize family-specific MAC parameters and function + * pointers. + **/ +static s32 e1000_init_mac_params_ich8lan(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + struct e1000_mac_info *mac = &hw->mac; + + /* Set media type function pointer */ + hw->media_type = e1000_media_type_copper; + + /* Set mta register count */ + mac->mta_reg_count = 32; + /* Set rar entry count */ + mac->rar_entry_count = E1000_ICH_RAR_ENTRIES; + if (mac->type == e1000_ich8lan) + mac->rar_entry_count--; + /* Set if manageability features are enabled. */ + mac->arc_subsystem_valid = 1; + + /* Enable PCS Lock-loss workaround for ICH8 */ + if (mac->type == e1000_ich8lan) + e1000e_set_kmrn_lock_loss_workaround_ich8lan(hw, 1); + + return 0; +} + +static s32 e1000_get_invariants_ich8lan(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + s32 rc; + + rc = e1000_init_mac_params_ich8lan(adapter); + if (rc) + return rc; + + rc = e1000_init_nvm_params_ich8lan(hw); + if (rc) + return rc; + + rc = e1000_init_phy_params_ich8lan(hw); + if (rc) + return rc; + + if ((adapter->hw.mac.type == e1000_ich8lan) && + (adapter->hw.phy.type == e1000_phy_igp_3)) + adapter->flags |= FLAG_LSC_GIG_SPEED_DROP; + + return 0; +} + +/** + * e1000_acquire_swflag_ich8lan - Acquire software control flag + * @hw: pointer to the HW structure + * + * Acquires the software control flag for performing NVM and PHY + * operations. This is a function pointer entry point only called by + * read/write routines for the PHY and NVM parts. + **/ +static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw) +{ + u32 extcnf_ctrl; + u32 timeout = PHY_CFG_TIMEOUT; + + while (timeout) { + extcnf_ctrl = er32(EXTCNF_CTRL); + extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG; + ew32(EXTCNF_CTRL, extcnf_ctrl); + + extcnf_ctrl = er32(EXTCNF_CTRL); + if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG) + break; + mdelay(1); + timeout--; + } + + if (!timeout) { + hw_dbg(hw, "FW or HW has locked the resource for too long.\n"); + return -E1000_ERR_CONFIG; + } + + return 0; +} + +/** + * e1000_release_swflag_ich8lan - Release software control flag + * @hw: pointer to the HW structure + * + * Releases the software control flag for performing NVM and PHY operations. + * This is a function pointer entry point only called by read/write + * routines for the PHY and NVM parts. + **/ +static void e1000_release_swflag_ich8lan(struct e1000_hw *hw) +{ + u32 extcnf_ctrl; + + extcnf_ctrl = er32(EXTCNF_CTRL); + extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG; + ew32(EXTCNF_CTRL, extcnf_ctrl); +} + +/** + * e1000_check_reset_block_ich8lan - Check if PHY reset is blocked + * @hw: pointer to the HW structure + * + * Checks if firmware is blocking the reset of the PHY. + * This is a function pointer entry point only called by + * reset routines. + **/ +static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw) +{ + u32 fwsm; + + fwsm = er32(FWSM); + + return (fwsm & E1000_ICH_FWSM_RSPCIPHY) ? 0 : E1000_BLK_PHY_RESET; +} + +/** + * e1000_phy_force_speed_duplex_ich8lan - Force PHY speed & duplex + * @hw: pointer to the HW structure + * + * Forces the speed and duplex settings of the PHY. + * This is a function pointer entry point only called by + * PHY setup routines. + **/ +static s32 e1000_phy_force_speed_duplex_ich8lan(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 data; + bool link; + + if (phy->type != e1000_phy_ife) { + ret_val = e1000e_phy_force_speed_duplex_igp(hw); + return ret_val; + } + + ret_val = e1e_rphy(hw, PHY_CONTROL, &data); + if (ret_val) + return ret_val; + + e1000e_phy_force_speed_duplex_setup(hw, &data); + + ret_val = e1e_wphy(hw, PHY_CONTROL, data); + if (ret_val) + return ret_val; + + /* Disable MDI-X support for 10/100 */ + ret_val = e1e_rphy(hw, IFE_PHY_MDIX_CONTROL, &data); + if (ret_val) + return ret_val; + + data &= ~IFE_PMC_AUTO_MDIX; + data &= ~IFE_PMC_FORCE_MDIX; + + ret_val = e1e_wphy(hw, IFE_PHY_MDIX_CONTROL, data); + if (ret_val) + return ret_val; + + hw_dbg(hw, "IFE PMC: %X\n", data); + + udelay(1); + + if (phy->wait_for_link) { + hw_dbg(hw, "Waiting for forced speed/duplex link on IFE phy.\n"); + + ret_val = e1000e_phy_has_link_generic(hw, + PHY_FORCE_LIMIT, + 100000, + &link); + if (ret_val) + return ret_val; + + if (!link) + hw_dbg(hw, "Link taking longer than expected.\n"); + + /* Try once more */ + ret_val = e1000e_phy_has_link_generic(hw, + PHY_FORCE_LIMIT, + 100000, + &link); + if (ret_val) + return ret_val; + } + + return 0; +} + +/** + * e1000_phy_hw_reset_ich8lan - Performs a PHY reset + * @hw: pointer to the HW structure + * + * Resets the PHY + * This is a function pointer entry point called by drivers + * or other shared routines. + **/ +static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + u32 i; + u32 data, cnf_size, cnf_base_addr, sw_cfg_mask; + s32 ret_val; + u16 loop = E1000_ICH8_LAN_INIT_TIMEOUT; + u16 word_addr, reg_data, reg_addr, phy_page = 0; + + ret_val = e1000e_phy_hw_reset_generic(hw); + if (ret_val) + return ret_val; + + /* Initialize the PHY from the NVM on ICH platforms. This + * is needed due to an issue where the NVM configuration is + * not properly autoloaded after power transitions. + * Therefore, after each PHY reset, we will load the + * configuration data out of the NVM manually. + */ + if (hw->mac.type == e1000_ich8lan && phy->type == e1000_phy_igp_3) { + struct e1000_adapter *adapter = hw->adapter; + + /* Check if SW needs configure the PHY */ + if ((adapter->pdev->device == E1000_DEV_ID_ICH8_IGP_M_AMT) || + (adapter->pdev->device == E1000_DEV_ID_ICH8_IGP_M)) + sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M; + else + sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG; + + data = er32(FEXTNVM); + if (!(data & sw_cfg_mask)) + return 0; + + /* Wait for basic configuration completes before proceeding*/ + do { + data = er32(STATUS); + data &= E1000_STATUS_LAN_INIT_DONE; + udelay(100); + } while ((!data) && --loop); + + /* If basic configuration is incomplete before the above loop + * count reaches 0, loading the configuration from NVM will + * leave the PHY in a bad state possibly resulting in no link. + */ + if (loop == 0) { + hw_dbg(hw, "LAN_INIT_DONE not set, increase timeout\n"); + } + + /* Clear the Init Done bit for the next init event */ + data = er32(STATUS); + data &= ~E1000_STATUS_LAN_INIT_DONE; + ew32(STATUS, data); + + /* Make sure HW does not configure LCD from PHY + * extended configuration before SW configuration */ + data = er32(EXTCNF_CTRL); + if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE) + return 0; + + cnf_size = er32(EXTCNF_SIZE); + cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK; + cnf_size >>= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT; + if (!cnf_size) + return 0; + + cnf_base_addr = data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK; + cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT; + + /* Configure LCD from extended configuration + * region. */ + + /* cnf_base_addr is in DWORD */ + word_addr = (u16)(cnf_base_addr << 1); + + for (i = 0; i < cnf_size; i++) { + ret_val = e1000_read_nvm(hw, + (word_addr + i * 2), + 1, + ®_data); + if (ret_val) + return ret_val; + + ret_val = e1000_read_nvm(hw, + (word_addr + i * 2 + 1), + 1, + ®_addr); + if (ret_val) + return ret_val; + + /* Save off the PHY page for future writes. */ + if (reg_addr == IGP01E1000_PHY_PAGE_SELECT) { + phy_page = reg_data; + continue; + } + + reg_addr |= phy_page; + + ret_val = e1e_wphy(hw, (u32)reg_addr, reg_data); + if (ret_val) + return ret_val; + } + } + + return 0; +} + +/** + * e1000_get_phy_info_ife_ich8lan - Retrieves various IFE PHY states + * @hw: pointer to the HW structure + * + * Populates "phy" structure with various feature states. + * This function is only called by other family-specific + * routines. + **/ +static s32 e1000_get_phy_info_ife_ich8lan(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 data; + bool link; + + ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link); + if (ret_val) + return ret_val; + + if (!link) { + hw_dbg(hw, "Phy info is only valid if link is up\n"); + return -E1000_ERR_CONFIG; + } + + ret_val = e1e_rphy(hw, IFE_PHY_SPECIAL_CONTROL, &data); + if (ret_val) + return ret_val; + phy->polarity_correction = (!(data & IFE_PSC_AUTO_POLARITY_DISABLE)); + + if (phy->polarity_correction) { + ret_val = e1000_check_polarity_ife_ich8lan(hw); + if (ret_val) + return ret_val; + } else { + /* Polarity is forced */ + phy->cable_polarity = (data & IFE_PSC_FORCE_POLARITY) + ? e1000_rev_polarity_reversed + : e1000_rev_polarity_normal; + } + + ret_val = e1e_rphy(hw, IFE_PHY_MDIX_CONTROL, &data); + if (ret_val) + return ret_val; + + phy->is_mdix = (data & IFE_PMC_MDIX_STATUS); + + /* The following parameters are undefined for 10/100 operation. */ + phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED; + phy->local_rx = e1000_1000t_rx_status_undefined; + phy->remote_rx = e1000_1000t_rx_status_undefined; + + return 0; +} + +/** + * e1000_get_phy_info_ich8lan - Calls appropriate PHY type get_phy_info + * @hw: pointer to the HW structure + * + * Wrapper for calling the get_phy_info routines for the appropriate phy type. + * This is a function pointer entry point called by drivers + * or other shared routines. + **/ +static s32 e1000_get_phy_info_ich8lan(struct e1000_hw *hw) +{ + switch (hw->phy.type) { + case e1000_phy_ife: + return e1000_get_phy_info_ife_ich8lan(hw); + break; + case e1000_phy_igp_3: + return e1000e_get_phy_info_igp(hw); + break; + default: + break; + } + + return -E1000_ERR_PHY_TYPE; +} + +/** + * e1000_check_polarity_ife_ich8lan - Check cable polarity for IFE PHY + * @hw: pointer to the HW structure + * + * Polarity is determined on the polarity reveral feature being enabled. + * This function is only called by other family-specific + * routines. + **/ +static s32 e1000_check_polarity_ife_ich8lan(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_data, offset, mask; + + /* Polarity is determined based on the reversal feature + * being enabled. + */ + if (phy->polarity_correction) { + offset = IFE_PHY_EXTENDED_STATUS_CONTROL; + mask = IFE_PESC_POLARITY_REVERSED; + } else { + offset = IFE_PHY_SPECIAL_CONTROL; + mask = IFE_PSC_FORCE_POLARITY; + } + + ret_val = e1e_rphy(hw, offset, &phy_data); + + if (!ret_val) + phy->cable_polarity = (phy_data & mask) + ? e1000_rev_polarity_reversed + : e1000_rev_polarity_normal; + + return ret_val; +} + +/** + * e1000_set_d0_lplu_state_ich8lan - Set Low Power Linkup D0 state + * @hw: pointer to the HW structure + * @active: TRUE to enable LPLU, FALSE to disable + * + * Sets the LPLU D0 state according to the active flag. When + * activating LPLU this function also disables smart speed + * and vice versa. LPLU will not be activated unless the + * device autonegotiation advertisement meets standards of + * either 10 or 10/100 or 10/100/1000 at all duplexes. + * This is a function pointer entry point only called by + * PHY setup routines. + **/ +static s32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, bool active) +{ + struct e1000_phy_info *phy = &hw->phy; + u32 phy_ctrl; + s32 ret_val = 0; + u16 data; + + if (phy->type != e1000_phy_igp_3) + return ret_val; + + phy_ctrl = er32(PHY_CTRL); + + if (active) { + phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU; + ew32(PHY_CTRL, phy_ctrl); + + /* Call gig speed drop workaround on LPLU before accessing + * any PHY registers */ + if ((hw->mac.type == e1000_ich8lan) && + (hw->phy.type == e1000_phy_igp_3)) + e1000e_gig_downshift_workaround_ich8lan(hw); + + /* When LPLU is enabled, we should disable SmartSpeed */ + ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG, &data); + data &= ~IGP01E1000_PSCFR_SMART_SPEED; + ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG, data); + if (ret_val) + return ret_val; + } else { + phy_ctrl &= ~E1000_PHY_CTRL_D0A_LPLU; + ew32(PHY_CTRL, phy_ctrl); + + /* LPLU and SmartSpeed are mutually exclusive. LPLU is used + * during Dx states where the power conservation is most + * important. During driver activity we should enable + * SmartSpeed, so performance is maintained. */ + if (phy->smart_speed == e1000_smart_speed_on) { + ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG, + &data); + if (ret_val) + return ret_val; + + data |= IGP01E1000_PSCFR_SMART_SPEED; + ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG, + data); + if (ret_val) + return ret_val; + } else if (phy->smart_speed == e1000_smart_speed_off) { + ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG, + &data); + if (ret_val) + return ret_val; + + data &= ~IGP01E1000_PSCFR_SMART_SPEED; + ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG, + data); + if (ret_val) + return ret_val; + } + } + + return 0; +} + +/** + * e1000_set_d3_lplu_state_ich8lan - Set Low Power Linkup D3 state + * @hw: pointer to the HW structure + * @active: TRUE to enable LPLU, FALSE to disable + * + * Sets the LPLU D3 state according to the active flag. When + * activating LPLU this function also disables smart speed + * and vice versa. LPLU will not be activated unless the + * device autonegotiation advertisement meets standards of + * either 10 or 10/100 or 10/100/1000 at all duplexes. + * This is a function pointer entry point only called by + * PHY setup routines. + **/ +static s32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw, bool active) +{ + struct e1000_phy_info *phy = &hw->phy; + u32 phy_ctrl; + s32 ret_val; + u16 data; + + phy_ctrl = er32(PHY_CTRL); + + if (!active) { + phy_ctrl &= ~E1000_PHY_CTRL_NOND0A_LPLU; + ew32(PHY_CTRL, phy_ctrl); + /* LPLU and SmartSpeed are mutually exclusive. LPLU is used + * during Dx states where the power conservation is most + * important. During driver activity we should enable + * SmartSpeed, so performance is maintained. */ + if (phy->smart_speed == e1000_smart_speed_on) { + ret_val = e1e_rphy(hw, + IGP01E1000_PHY_PORT_CONFIG, + &data); + if (ret_val) + return ret_val; + + data |= IGP01E1000_PSCFR_SMART_SPEED; + ret_val = e1e_wphy(hw, + IGP01E1000_PHY_PORT_CONFIG, + data); + if (ret_val) + return ret_val; + } else if (phy->smart_speed == e1000_smart_speed_off) { + ret_val = e1e_rphy(hw, + IGP01E1000_PHY_PORT_CONFIG, + &data); + if (ret_val) + return ret_val; + + data &= ~IGP01E1000_PSCFR_SMART_SPEED; + ret_val = e1e_wphy(hw, + IGP01E1000_PHY_PORT_CONFIG, + data); + if (ret_val) + return ret_val; + } + } else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) || + (phy->autoneg_advertised == E1000_ALL_NOT_GIG) || + (phy->autoneg_advertised == E1000_ALL_10_SPEED)) { + phy_ctrl |= E1000_PHY_CTRL_NOND0A_LPLU; + ew32(PHY_CTRL, phy_ctrl); + + /* Call gig speed drop workaround on LPLU before accessing + * any PHY registers */ + if ((hw->mac.type == e1000_ich8lan) && + (hw->phy.type == e1000_phy_igp_3)) + e1000e_gig_downshift_workaround_ich8lan(hw); + + /* When LPLU is enabled, we should disable SmartSpeed */ + ret_val = e1e_rphy(hw, + IGP01E1000_PHY_PORT_CONFIG, + &data); + if (ret_val) + return ret_val; + + data &= ~IGP01E1000_PSCFR_SMART_SPEED; + ret_val = e1e_wphy(hw, + IGP01E1000_PHY_PORT_CONFIG, + data); + } + + return 0; +} + +/** + * e1000_read_nvm_ich8lan - Read word(s) from the NVM + * @hw: pointer to the HW structure + * @offset: The offset (in bytes) of the word(s) to read. + * @words: Size of data to read in words + * @data: Pointer to the word(s) to read at offset. + * + * Reads a word(s) from the NVM using the flash access registers. + **/ +static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words, + u16 *data) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; + u32 act_offset; + s32 ret_val; + u16 i, word; + + if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) || + (words == 0)) { + hw_dbg(hw, "nvm parameter(s) out of bounds\n"); + return -E1000_ERR_NVM; + } + + ret_val = e1000_acquire_swflag_ich8lan(hw); + if (ret_val) + return ret_val; + + /* Start with the bank offset, then add the relative offset. */ + act_offset = (er32(EECD) & E1000_EECD_SEC1VAL) + ? nvm->flash_bank_size + : 0; + act_offset += offset; + + for (i = 0; i < words; i++) { + if ((dev_spec->shadow_ram) && + (dev_spec->shadow_ram[offset+i].modified)) { + data[i] = dev_spec->shadow_ram[offset+i].value; + } else { + ret_val = e1000_read_flash_word_ich8lan(hw, + act_offset + i, + &word); + if (ret_val) + break; + data[i] = word; + } + } + + e1000_release_swflag_ich8lan(hw); + + return ret_val; +} + +/** + * e1000_flash_cycle_init_ich8lan - Initialize flash + * @hw: pointer to the HW structure + * + * This function does initial flash setup so that a new read/write/erase cycle + * can be started. + **/ +static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw) +{ + union ich8_hws_flash_status hsfsts; + s32 ret_val = -E1000_ERR_NVM; + s32 i = 0; + + hsfsts.regval = er16flash(ICH_FLASH_HSFSTS); + + /* Check if the flash descriptor is valid */ + if (hsfsts.hsf_status.fldesvalid == 0) { + hw_dbg(hw, "Flash descriptor invalid. " + "SW Sequencing must be used."); + return -E1000_ERR_NVM; + } + + /* Clear FCERR and DAEL in hw status by writing 1 */ + hsfsts.hsf_status.flcerr = 1; + hsfsts.hsf_status.dael = 1; + + ew16flash(ICH_FLASH_HSFSTS, hsfsts.regval); + + /* Either we should have a hardware SPI cycle in progress + * bit to check against, in order to start a new cycle or + * FDONE bit should be changed in the hardware so that it + * is 1 after harware reset, which can then be used as an + * indication whether a cycle is in progress or has been + * completed. + */ + + if (hsfsts.hsf_status.flcinprog == 0) { + /* There is no cycle running at present, + * so we can start a cycle */ + /* Begin by setting Flash Cycle Done. */ + hsfsts.hsf_status.flcdone = 1; + ew16flash(ICH_FLASH_HSFSTS, hsfsts.regval); + ret_val = 0; + } else { + /* otherwise poll for sometime so the current + * cycle has a chance to end before giving up. */ + for (i = 0; i < ICH_FLASH_READ_COMMAND_TIMEOUT; i++) { + hsfsts.regval = __er16flash(hw, ICH_FLASH_HSFSTS); + if (hsfsts.hsf_status.flcinprog == 0) { + ret_val = 0; + break; + } + udelay(1); + } + if (ret_val == 0) { + /* Successful in waiting for previous cycle to timeout, + * now set the Flash Cycle Done. */ + hsfsts.hsf_status.flcdone = 1; + ew16flash(ICH_FLASH_HSFSTS, hsfsts.regval); + } else { + hw_dbg(hw, "Flash controller busy, cannot get access"); + } + } + + return ret_val; +} + +/** + * e1000_flash_cycle_ich8lan - Starts flash cycle (read/write/erase) + * @hw: pointer to the HW structure + * @timeout: maximum time to wait for completion + * + * This function starts a flash cycle and waits for its completion. + **/ +static s32 e1000_flash_cycle_ich8lan(struct e1000_hw *hw, u32 timeout) +{ + union ich8_hws_flash_ctrl hsflctl; + union ich8_hws_flash_status hsfsts; + s32 ret_val = -E1000_ERR_NVM; + u32 i = 0; + + /* Start a cycle by writing 1 in Flash Cycle Go in Hw Flash Control */ + hsflctl.regval = er16flash(ICH_FLASH_HSFCTL); + hsflctl.hsf_ctrl.flcgo = 1; + ew16flash(ICH_FLASH_HSFCTL, hsflctl.regval); + + /* wait till FDONE bit is set to 1 */ + do { + hsfsts.regval = er16flash(ICH_FLASH_HSFSTS); + if (hsfsts.hsf_status.flcdone == 1) + break; + udelay(1); + } while (i++ < timeout); + + if (hsfsts.hsf_status.flcdone == 1 && hsfsts.hsf_status.flcerr == 0) + return 0; + + return ret_val; +} + +/** + * e1000_read_flash_word_ich8lan - Read word from flash + * @hw: pointer to the HW structure + * @offset: offset to data location + * @data: pointer to the location for storing the data + * + * Reads the flash word at offset into data. Offset is converted + * to bytes before read. + **/ +static s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw, u32 offset, + u16 *data) +{ + /* Must convert offset into bytes. */ + offset <<= 1; + + return e1000_read_flash_data_ich8lan(hw, offset, 2, data); +} + +/** + * e1000_read_flash_data_ich8lan - Read byte or word from NVM + * @hw: pointer to the HW structure + * @offset: The offset (in bytes) of the byte or word to read. + * @size: Size of data to read, 1=byte 2=word + * @data: Pointer to the word to store the value read. + * + * Reads a byte or word from the NVM using the flash access registers. + **/ +static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset, + u8 size, u16 *data) +{ + union ich8_hws_flash_status hsfsts; + union ich8_hws_flash_ctrl hsflctl; + u32 flash_linear_addr; + u32 flash_data = 0; + s32 ret_val = -E1000_ERR_NVM; + u8 count = 0; + + if (size < 1 || size > 2 || offset > ICH_FLASH_LINEAR_ADDR_MASK) + return -E1000_ERR_NVM; + + flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & offset) + + hw->nvm.flash_base_addr; + + do { + udelay(1); + /* Steps */ + ret_val = e1000_flash_cycle_init_ich8lan(hw); + if (ret_val != 0) + break; + + hsflctl.regval = er16flash(ICH_FLASH_HSFCTL); + /* 0b/1b corresponds to 1 or 2 byte size, respectively. */ + hsflctl.hsf_ctrl.fldbcount = size - 1; + hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_READ; + ew16flash(ICH_FLASH_HSFCTL, hsflctl.regval); + + ew32flash(ICH_FLASH_FADDR, flash_linear_addr); + + ret_val = e1000_flash_cycle_ich8lan(hw, + ICH_FLASH_READ_COMMAND_TIMEOUT); + + /* Check if FCERR is set to 1, if set to 1, clear it + * and try the whole sequence a few more times, else + * read in (shift in) the Flash Data0, the order is + * least significant byte first msb to lsb */ + if (ret_val == 0) { + flash_data = er32flash(ICH_FLASH_FDATA0); + if (size == 1) { + *data = (u8)(flash_data & 0x000000FF); + } else if (size == 2) { + *data = (u16)(flash_data & 0x0000FFFF); + } + break; + } else { + /* If we've gotten here, then things are probably + * completely hosed, but if the error condition is + * detected, it won't hurt to give it another try... + * ICH_FLASH_CYCLE_REPEAT_COUNT times. + */ + hsfsts.regval = er16flash(ICH_FLASH_HSFSTS); + if (hsfsts.hsf_status.flcerr == 1) { + /* Repeat for some time before giving up. */ + continue; + } else if (hsfsts.hsf_status.flcdone == 0) { + hw_dbg(hw, "Timeout error - flash cycle " + "did not complete."); + break; + } + } + } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT); + + return ret_val; +} + +/** + * e1000_write_nvm_ich8lan - Write word(s) to the NVM + * @hw: pointer to the HW structure + * @offset: The offset (in bytes) of the word(s) to write. + * @words: Size of data to write in words + * @data: Pointer to the word(s) to write at offset. + * + * Writes a byte or word to the NVM using the flash access registers. + **/ +static s32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words, + u16 *data) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; + s32 ret_val; + u16 i; + + if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) || + (words == 0)) { + hw_dbg(hw, "nvm parameter(s) out of bounds\n"); + return -E1000_ERR_NVM; + } + + ret_val = e1000_acquire_swflag_ich8lan(hw); + if (ret_val) + return ret_val; + + for (i = 0; i < words; i++) { + dev_spec->shadow_ram[offset+i].modified = 1; + dev_spec->shadow_ram[offset+i].value = data[i]; + } + + e1000_release_swflag_ich8lan(hw); + + return 0; +} + +/** + * e1000_update_nvm_checksum_ich8lan - Update the checksum for NVM + * @hw: pointer to the HW structure + * + * The NVM checksum is updated by calling the generic update_nvm_checksum, + * which writes the checksum to the shadow ram. The changes in the shadow + * ram are then committed to the EEPROM by processing each bank at a time + * checking for the modified bit and writing only the pending changes. + * After a succesful commit, the shadow ram is cleared and is ready for + * future writes. + **/ +static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; + u32 i, act_offset, new_bank_offset, old_bank_offset; + s32 ret_val; + u16 data; + + ret_val = e1000e_update_nvm_checksum_generic(hw); + if (ret_val) + return ret_val;; + + if (nvm->type != e1000_nvm_flash_sw) + return ret_val;; + + ret_val = e1000_acquire_swflag_ich8lan(hw); + if (ret_val) + return ret_val;; + + /* We're writing to the opposite bank so if we're on bank 1, + * write to bank 0 etc. We also need to erase the segment that + * is going to be written */ + if (!(er32(EECD) & E1000_EECD_SEC1VAL)) { + new_bank_offset = nvm->flash_bank_size; + old_bank_offset = 0; + e1000_erase_flash_bank_ich8lan(hw, 1); + } else { + old_bank_offset = nvm->flash_bank_size; + new_bank_offset = 0; + e1000_erase_flash_bank_ich8lan(hw, 0); + } + + for (i = 0; i < E1000_ICH8_SHADOW_RAM_WORDS; i++) { + /* Determine whether to write the value stored + * in the other NVM bank or a modified value stored + * in the shadow RAM */ + if (dev_spec->shadow_ram[i].modified) { + data = dev_spec->shadow_ram[i].value; + } else { + e1000_read_flash_word_ich8lan(hw, + i + old_bank_offset, + &data); + } + + /* If the word is 0x13, then make sure the signature bits + * (15:14) are 11b until the commit has completed. + * This will allow us to write 10b which indicates the + * signature is valid. We want to do this after the write + * has completed so that we don't mark the segment valid + * while the write is still in progress */ + if (i == E1000_ICH_NVM_SIG_WORD) + data |= E1000_ICH_NVM_SIG_MASK; + + /* Convert offset to bytes. */ + act_offset = (i + new_bank_offset) << 1; + + udelay(100); + /* Write the bytes to the new bank. */ + ret_val = e1000_retry_write_flash_byte_ich8lan(hw, + act_offset, + (u8)data); + if (ret_val) + break; + + udelay(100); + ret_val = e1000_retry_write_flash_byte_ich8lan(hw, + act_offset + 1, + (u8)(data >> 8)); + if (ret_val) + break; + } + + /* Don't bother writing the segment valid bits if sector + * programming failed. */ + if (ret_val) { + hw_dbg(hw, "Flash commit failed.\n"); + e1000_release_swflag_ich8lan(hw); + return ret_val; + } + + /* Finally validate the new segment by setting bit 15:14 + * to 10b in word 0x13 , this can be done without an + * erase as well since these bits are 11 to start with + * and we need to change bit 14 to 0b */ + act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD; + e1000_read_flash_word_ich8lan(hw, act_offset, &data); + data &= 0xBFFF; + ret_val = e1000_retry_write_flash_byte_ich8lan(hw, + act_offset * 2 + 1, + (u8)(data >> 8)); + if (ret_val) { + e1000_release_swflag_ich8lan(hw); + return ret_val; + } + + /* And invalidate the previously valid segment by setting + * its signature word (0x13) high_byte to 0b. This can be + * done without an erase because flash erase sets all bits + * to 1's. We can write 1's to 0's without an erase */ + act_offset = (old_bank_offset + E1000_ICH_NVM_SIG_WORD) * 2 + 1; + ret_val = e1000_retry_write_flash_byte_ich8lan(hw, act_offset, 0); + if (ret_val) { + e1000_release_swflag_ich8lan(hw); + return ret_val; + } + + /* Great! Everything worked, we can now clear the cached entries. */ + for (i = 0; i < E1000_ICH8_SHADOW_RAM_WORDS; i++) { + dev_spec->shadow_ram[i].modified = 0; + dev_spec->shadow_ram[i].value = 0xFFFF; + } + + e1000_release_swflag_ich8lan(hw); + + /* Reload the EEPROM, or else modifications will not appear + * until after the next adapter reset. + */ + e1000e_reload_nvm(hw); + msleep(10); + + return ret_val; +} + +/** + * e1000_validate_nvm_checksum_ich8lan - Validate EEPROM checksum + * @hw: pointer to the HW structure + * + * Check to see if checksum needs to be fixed by reading bit 6 in word 0x19. + * If the bit is 0, that the EEPROM had been modified, but the checksum was not + * calculated, in which case we need to calculate the checksum and set bit 6. + **/ +static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw) +{ + s32 ret_val; + u16 data; + + /* Read 0x19 and check bit 6. If this bit is 0, the checksum + * needs to be fixed. This bit is an indication that the NVM + * was prepared by OEM software and did not calculate the + * checksum...a likely scenario. + */ + ret_val = e1000_read_nvm(hw, 0x19, 1, &data); + if (ret_val) + return ret_val; + + if ((data & 0x40) == 0) { + data |= 0x40; + ret_val = e1000_write_nvm(hw, 0x19, 1, &data); + if (ret_val) + return ret_val; + ret_val = e1000e_update_nvm_checksum(hw); + if (ret_val) + return ret_val; + } + + return e1000e_validate_nvm_checksum_generic(hw); +} + +/** + * e1000_write_flash_data_ich8lan - Writes bytes to the NVM + * @hw: pointer to the HW structure + * @offset: The offset (in bytes) of the byte/word to read. + * @size: Size of data to read, 1=byte 2=word + * @data: The byte(s) to write to the NVM. + * + * Writes one/two bytes to the NVM using the flash access registers. + **/ +static s32 e1000_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset, + u8 size, u16 data) +{ + union ich8_hws_flash_status hsfsts; + union ich8_hws_flash_ctrl hsflctl; + u32 flash_linear_addr; + u32 flash_data = 0; + s32 ret_val; + u8 count = 0; + + if (size < 1 || size > 2 || data > size * 0xff || + offset > ICH_FLASH_LINEAR_ADDR_MASK) + return -E1000_ERR_NVM; + + flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & offset) + + hw->nvm.flash_base_addr; + + do { + udelay(1); + /* Steps */ + ret_val = e1000_flash_cycle_init_ich8lan(hw); + if (ret_val) + break; + + hsflctl.regval = er16flash(ICH_FLASH_HSFCTL); + /* 0b/1b corresponds to 1 or 2 byte size, respectively. */ + hsflctl.hsf_ctrl.fldbcount = size -1; + hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_WRITE; + ew16flash(ICH_FLASH_HSFCTL, hsflctl.regval); + + ew32flash(ICH_FLASH_FADDR, flash_linear_addr); + + if (size == 1) + flash_data = (u32)data & 0x00FF; + else + flash_data = (u32)data; + + ew32flash(ICH_FLASH_FDATA0, flash_data); + + /* check if FCERR is set to 1 , if set to 1, clear it + * and try the whole sequence a few more times else done */ + ret_val = e1000_flash_cycle_ich8lan(hw, + ICH_FLASH_WRITE_COMMAND_TIMEOUT); + if (!ret_val) + break; + + /* If we're here, then things are most likely + * completely hosed, but if the error condition + * is detected, it won't hurt to give it another + * try...ICH_FLASH_CYCLE_REPEAT_COUNT times. + */ + hsfsts.regval = er16flash(ICH_FLASH_HSFSTS); + if (hsfsts.hsf_status.flcerr == 1) + /* Repeat for some time before giving up. */ + continue; + if (hsfsts.hsf_status.flcdone == 0) { + hw_dbg(hw, "Timeout error - flash cycle " + "did not complete."); + break; + } + } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT); + + return ret_val; +} + +/** + * e1000_write_flash_byte_ich8lan - Write a single byte to NVM + * @hw: pointer to the HW structure + * @offset: The index of the byte to read. + * @data: The byte to write to the NVM. + * + * Writes a single byte to the NVM using the flash access registers. + **/ +static s32 e1000_write_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset, + u8 data) +{ + u16 word = (u16)data; + + return e1000_write_flash_data_ich8lan(hw, offset, 1, word); +} + +/** + * e1000_retry_write_flash_byte_ich8lan - Writes a single byte to NVM + * @hw: pointer to the HW structure + * @offset: The offset of the byte to write. + * @byte: The byte to write to the NVM. + * + * Writes a single byte to the NVM using the flash access registers. + * Goes through a retry algorithm before giving up. + **/ +static s32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw, + u32 offset, u8 byte) +{ + s32 ret_val; + u16 program_retries; + + ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte); + if (!ret_val) + return ret_val; + + for (program_retries = 0; program_retries < 100; program_retries++) { + hw_dbg(hw, "Retrying Byte %2.2X at offset %u\n", byte, offset); + udelay(100); + ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte); + if (!ret_val) + break; + } + if (program_retries == 100) + return -E1000_ERR_NVM; + + return 0; +} + +/** + * e1000_erase_flash_bank_ich8lan - Erase a bank (4k) from NVM + * @hw: pointer to the HW structure + * @bank: 0 for first bank, 1 for second bank, etc. + * + * Erases the bank specified. Each bank is a 4k block. Banks are 0 based. + * bank N is 4096 * N + flash_reg_addr. + **/ +static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + union ich8_hws_flash_status hsfsts; + union ich8_hws_flash_ctrl hsflctl; + u32 flash_linear_addr; + /* bank size is in 16bit words - adjust to bytes */ + u32 flash_bank_size = nvm->flash_bank_size * 2; + s32 ret_val; + s32 count = 0; + s32 iteration; + s32 sector_size; + s32 j; + + hsfsts.regval = er16flash(ICH_FLASH_HSFSTS); + + /* Determine HW Sector size: Read BERASE bits of hw flash status + * register */ + /* 00: The Hw sector is 256 bytes, hence we need to erase 16 + * consecutive sectors. The start index for the nth Hw sector + * can be calculated as = bank * 4096 + n * 256 + * 01: The Hw sector is 4K bytes, hence we need to erase 1 sector. + * The start index for the nth Hw sector can be calculated + * as = bank * 4096 + * 10: The Hw sector is 8K bytes, nth sector = bank * 8192 + * (ich9 only, otherwise error condition) + * 11: The Hw sector is 64K bytes, nth sector = bank * 65536 + */ + switch (hsfsts.hsf_status.berasesz) { + case 0: + /* Hw sector size 256 */ + sector_size = ICH_FLASH_SEG_SIZE_256; + iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_256; + break; + case 1: + sector_size = ICH_FLASH_SEG_SIZE_4K; + iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_4K; + break; + case 2: + if (hw->mac.type == e1000_ich9lan) { + sector_size = ICH_FLASH_SEG_SIZE_8K; + iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_8K; + } else { + return -E1000_ERR_NVM; + } + break; + case 3: + sector_size = ICH_FLASH_SEG_SIZE_64K; + iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_64K; + break; + default: + return -E1000_ERR_NVM; + } + + /* Start with the base address, then add the sector offset. */ + flash_linear_addr = hw->nvm.flash_base_addr; + flash_linear_addr += (bank) ? (sector_size * iteration) : 0; + + for (j = 0; j < iteration ; j++) { + do { + /* Steps */ + ret_val = e1000_flash_cycle_init_ich8lan(hw); + if (ret_val) + return ret_val; + + /* Write a value 11 (block Erase) in Flash + * Cycle field in hw flash control */ + hsflctl.regval = er16flash(ICH_FLASH_HSFCTL); + hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_ERASE; + ew16flash(ICH_FLASH_HSFCTL, hsflctl.regval); + + /* Write the last 24 bits of an index within the + * block into Flash Linear address field in Flash + * Address. + */ + flash_linear_addr += (j * sector_size); + ew32flash(ICH_FLASH_FADDR, flash_linear_addr); + + ret_val = e1000_flash_cycle_ich8lan(hw, + ICH_FLASH_ERASE_COMMAND_TIMEOUT); + if (ret_val == 0) + break; + + /* Check if FCERR is set to 1. If 1, + * clear it and try the whole sequence + * a few more times else Done */ + hsfsts.regval = er16flash(ICH_FLASH_HSFSTS); + if (hsfsts.hsf_status.flcerr == 1) + /* repeat for some time before + * giving up */ + continue; + else if (hsfsts.hsf_status.flcdone == 0) + return ret_val; + } while (++count < ICH_FLASH_CYCLE_REPEAT_COUNT); + } + + return 0; +} + +/** + * e1000_valid_led_default_ich8lan - Set the default LED settings + * @hw: pointer to the HW structure + * @data: Pointer to the LED settings + * + * Reads the LED default settings from the NVM to data. If the NVM LED + * settings is all 0's or F's, set the LED default to a valid LED default + * setting. + **/ +static s32 e1000_valid_led_default_ich8lan(struct e1000_hw *hw, u16 *data) +{ + s32 ret_val; + + ret_val = e1000_read_nvm(hw, NVM_ID_LED_SETTINGS, 1, data); + if (ret_val) { + hw_dbg(hw, "NVM Read Error\n"); + return ret_val; + } + + if (*data == ID_LED_RESERVED_0000 || + *data == ID_LED_RESERVED_FFFF) + *data = ID_LED_DEFAULT_ICH8LAN; + + return 0; +} + +/** + * e1000_get_bus_info_ich8lan - Get/Set the bus type and width + * @hw: pointer to the HW structure + * + * ICH8 use the PCI Express bus, but does not contain a PCI Express Capability + * register, so the the bus width is hard coded. + **/ +static s32 e1000_get_bus_info_ich8lan(struct e1000_hw *hw) +{ + struct e1000_bus_info *bus = &hw->bus; + s32 ret_val; + + ret_val = e1000e_get_bus_info_pcie(hw); + + /* ICH devices are "PCI Express"-ish. They have + * a configuration space, but do not contain + * PCI Express Capability registers, so bus width + * must be hardcoded. + */ + if (bus->width == e1000_bus_width_unknown) + bus->width = e1000_bus_width_pcie_x1; + + return ret_val; +} + +/** + * e1000_reset_hw_ich8lan - Reset the hardware + * @hw: pointer to the HW structure + * + * Does a full reset of the hardware which includes a reset of the PHY and + * MAC. + **/ +static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw) +{ + u32 ctrl, icr, kab; + s32 ret_val; + + /* Prevent the PCI-E bus from sticking if there is no TLP connection + * on the last TLP read/write transaction when MAC is reset. + */ + ret_val = e1000e_disable_pcie_master(hw); + if (ret_val) { + hw_dbg(hw, "PCI-E Master disable polling has failed.\n"); + } + + hw_dbg(hw, "Masking off all interrupts\n"); + ew32(IMC, 0xffffffff); + + /* Disable the Transmit and Receive units. Then delay to allow + * any pending transactions to complete before we hit the MAC + * with the global reset. + */ + ew32(RCTL, 0); + ew32(TCTL, E1000_TCTL_PSP); + e1e_flush(); + + msleep(10); + + /* Workaround for ICH8 bit corruption issue in FIFO memory */ + if (hw->mac.type == e1000_ich8lan) { + /* Set Tx and Rx buffer allocation to 8k apiece. */ + ew32(PBA, E1000_PBA_8K); + /* Set Packet Buffer Size to 16k. */ + ew32(PBS, E1000_PBS_16K); + } + + ctrl = er32(CTRL); + + if (!e1000_check_reset_block(hw)) { + /* PHY HW reset requires MAC CORE reset at the same + * time to make sure the interface between MAC and the + * external PHY is reset. + */ + ctrl |= E1000_CTRL_PHY_RST; + } + ret_val = e1000_acquire_swflag_ich8lan(hw); + hw_dbg(hw, "Issuing a global reset to ich8lan"); + ew32(CTRL, (ctrl | E1000_CTRL_RST)); + msleep(20); + + ret_val = e1000e_get_auto_rd_done(hw); + if (ret_val) { + /* + * When auto config read does not complete, do not + * return with an error. This can happen in situations + * where there is no eeprom and prevents getting link. + */ + hw_dbg(hw, "Auto Read Done did not complete\n"); + } + + ew32(IMC, 0xffffffff); + icr = er32(ICR); + + kab = er32(KABGTXD); + kab |= E1000_KABGTXD_BGSQLBIAS; + ew32(KABGTXD, kab); + + return ret_val; +} + +/** + * e1000_init_hw_ich8lan - Initialize the hardware + * @hw: pointer to the HW structure + * + * Prepares the hardware for transmit and receive by doing the following: + * - initialize hardware bits + * - initialize LED identification + * - setup receive address registers + * - setup flow control + * - setup transmit discriptors + * - clear statistics + **/ +static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + u32 ctrl_ext, txdctl, snoop; + s32 ret_val; + u16 i; + + e1000_initialize_hw_bits_ich8lan(hw); + + /* Initialize identification LED */ + ret_val = e1000e_id_led_init(hw); + if (ret_val) { + hw_dbg(hw, "Error initializing identification LED\n"); + return ret_val; + } + + /* Setup the receive address. */ + e1000e_init_rx_addrs(hw, mac->rar_entry_count); + + /* Zero out the Multicast HASH table */ + hw_dbg(hw, "Zeroing the MTA\n"); + for (i = 0; i < mac->mta_reg_count; i++) + E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0); + + /* Setup link and flow control */ + ret_val = e1000_setup_link_ich8lan(hw); + + /* Set the transmit descriptor write-back policy for both queues */ + txdctl = er32(TXDCTL); + txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) | + E1000_TXDCTL_FULL_TX_DESC_WB; + txdctl = (txdctl & ~E1000_TXDCTL_PTHRESH) | + E1000_TXDCTL_MAX_TX_DESC_PREFETCH; + ew32(TXDCTL, txdctl); + txdctl = er32(TXDCTL1); + txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) | + E1000_TXDCTL_FULL_TX_DESC_WB; + txdctl = (txdctl & ~E1000_TXDCTL_PTHRESH) | + E1000_TXDCTL_MAX_TX_DESC_PREFETCH; + ew32(TXDCTL1, txdctl); + + /* ICH8 has opposite polarity of no_snoop bits. + * By default, we should use snoop behavior. */ + if (mac->type == e1000_ich8lan) + snoop = PCIE_ICH8_SNOOP_ALL; + else + snoop = (u32) ~(PCIE_NO_SNOOP_ALL); + e1000e_set_pcie_no_snoop(hw, snoop); + + ctrl_ext = er32(CTRL_EXT); + ctrl_ext |= E1000_CTRL_EXT_RO_DIS; + ew32(CTRL_EXT, ctrl_ext); + + /* Clear all of the statistics registers (clear on read). It is + * important that we do this after we have tried to establish link + * because the symbol error count will increment wildly if there + * is no link. + */ + e1000_clear_hw_cntrs_ich8lan(hw); + + return 0; +} +/** + * e1000_initialize_hw_bits_ich8lan - Initialize required hardware bits + * @hw: pointer to the HW structure + * + * Sets/Clears required hardware bits necessary for correctly setting up the + * hardware for transmit and receive. + **/ +static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw) +{ + u32 reg; + + /* Extended Device Control */ + reg = er32(CTRL_EXT); + reg |= (1 << 22); + ew32(CTRL_EXT, reg); + + /* Transmit Descriptor Control 0 */ + reg = er32(TXDCTL); + reg |= (1 << 22); + ew32(TXDCTL, reg); + + /* Transmit Descriptor Control 1 */ + reg = er32(TXDCTL1); + reg |= (1 << 22); + ew32(TXDCTL1, reg); + + /* Transmit Arbitration Control 0 */ + reg = er32(TARC0); + if (hw->mac.type == e1000_ich8lan) + reg |= (1 << 28) | (1 << 29); + reg |= (1 << 23) | (1 << 24) | (1 << 26) | (1 << 27); + ew32(TARC0, reg); + + /* Transmit Arbitration Control 1 */ + reg = er32(TARC1); + if (er32(TCTL) & E1000_TCTL_MULR) + reg &= ~(1 << 28); + else + reg |= (1 << 28); + reg |= (1 << 24) | (1 << 26) | (1 << 30); + ew32(TARC1, reg); + + /* Device Status */ + if (hw->mac.type == e1000_ich8lan) { + reg = er32(STATUS); + reg &= ~(1 << 31); + ew32(STATUS, reg); + } +} + +/** + * e1000_setup_link_ich8lan - Setup flow control and link settings + * @hw: pointer to the HW structure + * + * Determines which flow control settings to use, then configures flow + * control. Calls the appropriate media-specific link configuration + * function. Assuming the adapter has a valid link partner, a valid link + * should be established. Assumes the hardware has previously been reset + * and the transmitter and receiver are not enabled. + **/ +static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + s32 ret_val; + + if (e1000_check_reset_block(hw)) + return 0; + + /* ICH parts do not have a word in the NVM to determine + * the default flow control setting, so we explicitly + * set it to full. + */ + if (mac->fc == e1000_fc_default) + mac->fc = e1000_fc_full; + + mac->original_fc = mac->fc; + + hw_dbg(hw, "After fix-ups FlowControl is now = %x\n", mac->fc); + + /* Continue to configure the copper link. */ + ret_val = e1000_setup_copper_link_ich8lan(hw); + if (ret_val) + return ret_val; + + ew32(FCTTV, mac->fc_pause_time); + + return e1000e_set_fc_watermarks(hw); +} + +/** + * e1000_setup_copper_link_ich8lan - Configure MAC/PHY interface + * @hw: pointer to the HW structure + * + * Configures the kumeran interface to the PHY to wait the appropriate time + * when polling the PHY, then call the generic setup_copper_link to finish + * configuring the copper link. + **/ +static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw) +{ + u32 ctrl; + s32 ret_val; + u16 reg_data; + + ctrl = er32(CTRL); + ctrl |= E1000_CTRL_SLU; + ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); + ew32(CTRL, ctrl); + + /* Set the mac to wait the maximum time between each iteration + * and increase the max iterations when polling the phy; + * this fixes erroneous timeouts at 10Mbps. */ + ret_val = e1000e_write_kmrn_reg(hw, GG82563_REG(0x34, 4), 0xFFFF); + if (ret_val) + return ret_val; + ret_val = e1000e_read_kmrn_reg(hw, GG82563_REG(0x34, 9), ®_data); + if (ret_val) + return ret_val; + reg_data |= 0x3F; + ret_val = e1000e_write_kmrn_reg(hw, GG82563_REG(0x34, 9), reg_data); + if (ret_val) + return ret_val; + + if (hw->phy.type == e1000_phy_igp_3) { + ret_val = e1000e_copper_link_setup_igp(hw); + if (ret_val) + return ret_val; + } + + return e1000e_setup_copper_link(hw); +} + +/** + * e1000_get_link_up_info_ich8lan - Get current link speed and duplex + * @hw: pointer to the HW structure + * @speed: pointer to store current link speed + * @duplex: pointer to store the current link duplex + * + * Calls the generic get_speed_and_duplex to retreive the current link + * information and then calls the Kumeran lock loss workaround for links at + * gigabit speeds. + **/ +static s32 e1000_get_link_up_info_ich8lan(struct e1000_hw *hw, u16 *speed, + u16 *duplex) +{ + s32 ret_val; + + ret_val = e1000e_get_speed_and_duplex_copper(hw, speed, duplex); + if (ret_val) + return ret_val; + + if ((hw->mac.type == e1000_ich8lan) && + (hw->phy.type == e1000_phy_igp_3) && + (*speed == SPEED_1000)) { + ret_val = e1000_kmrn_lock_loss_workaround_ich8lan(hw); + } + + return ret_val; +} + +/** + * e1000_kmrn_lock_loss_workaround_ich8lan - Kumeran workaround + * @hw: pointer to the HW structure + * + * Work-around for 82566 Kumeran PCS lock loss: + * On link status change (i.e. PCI reset, speed change) and link is up and + * speed is gigabit- + * 0) if workaround is optionally disabled do nothing + * 1) wait 1ms for Kumeran link to come up + * 2) check Kumeran Diagnostic register PCS lock loss bit + * 3) if not set the link is locked (all is good), otherwise... + * 4) reset the PHY + * 5) repeat up to 10 times + * Note: this is only called for IGP3 copper when speed is 1gb. + **/ +static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw) +{ + struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; + u32 phy_ctrl; + s32 ret_val; + u16 i, data; + bool link; + + if (!dev_spec->kmrn_lock_loss_workaround_enabled) + return 0; + + /* Make sure link is up before proceeding. If not just return. + * Attempting this while link is negotiating fouled up link + * stability */ + ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link); + if (!link) + return 0; + + for (i = 0; i < 10; i++) { + /* read once to clear */ + ret_val = e1e_rphy(hw, IGP3_KMRN_DIAG, &data); + if (ret_val) + return ret_val; + /* and again to get new status */ + ret_val = e1e_rphy(hw, IGP3_KMRN_DIAG, &data); + if (ret_val) + return ret_val; + + /* check for PCS lock */ + if (!(data & IGP3_KMRN_DIAG_PCS_LOCK_LOSS)) + return 0; + + /* Issue PHY reset */ + e1000_phy_hw_reset(hw); + mdelay(5); + } + /* Disable GigE link negotiation */ + phy_ctrl = er32(PHY_CTRL); + phy_ctrl |= (E1000_PHY_CTRL_GBE_DISABLE | + E1000_PHY_CTRL_NOND0A_GBE_DISABLE); + ew32(PHY_CTRL, phy_ctrl); + + /* Call gig speed drop workaround on Giga disable before accessing + * any PHY registers */ + e1000e_gig_downshift_workaround_ich8lan(hw); + + /* unable to acquire PCS lock */ + return -E1000_ERR_PHY; +} + +/** + * e1000_set_kmrn_lock_loss_workaound_ich8lan - Set Kumeran workaround state + * @hw: pointer to the HW structure + * @state: boolean value used to set the current Kumaran workaround state + * + * If ICH8, set the current Kumeran workaround state (enabled - TRUE + * /disabled - FALSE). + **/ +void e1000e_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw, + bool state) +{ + struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; + + if (hw->mac.type != e1000_ich8lan) { + hw_dbg(hw, "Workaround applies to ICH8 only.\n"); + return; + } + + dev_spec->kmrn_lock_loss_workaround_enabled = state; +} + +/** + * e1000_ipg3_phy_powerdown_workaround_ich8lan - Power down workaround on D3 + * @hw: pointer to the HW structure + * + * Workaround for 82566 power-down on D3 entry: + * 1) disable gigabit link + * 2) write VR power-down enable + * 3) read it back + * Continue if successful, else issue LCD reset and repeat + **/ +void e1000e_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw) +{ + u32 reg; + u16 data; + u8 retry = 0; + + if (hw->phy.type != e1000_phy_igp_3) + return; + + /* Try the workaround twice (if needed) */ + do { + /* Disable link */ + reg = er32(PHY_CTRL); + reg |= (E1000_PHY_CTRL_GBE_DISABLE | + E1000_PHY_CTRL_NOND0A_GBE_DISABLE); + ew32(PHY_CTRL, reg); + + /* Call gig speed drop workaround on Giga disable before + * accessing any PHY registers */ + if (hw->mac.type == e1000_ich8lan) + e1000e_gig_downshift_workaround_ich8lan(hw); + + /* Write VR power-down enable */ + e1e_rphy(hw, IGP3_VR_CTRL, &data); + data &= ~IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK; + e1e_wphy(hw, IGP3_VR_CTRL, data | IGP3_VR_CTRL_MODE_SHUTDOWN); + + /* Read it back and test */ + e1e_rphy(hw, IGP3_VR_CTRL, &data); + data &= IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK; + if ((data == IGP3_VR_CTRL_MODE_SHUTDOWN) || retry) + break; + + /* Issue PHY reset and repeat at most one more time */ + reg = er32(CTRL); + ew32(CTRL, reg | E1000_CTRL_PHY_RST); + retry++; + } while (retry); +} + +/** + * e1000e_gig_downshift_workaround_ich8lan - WoL from S5 stops working + * @hw: pointer to the HW structure + * + * Steps to take when dropping from 1Gb/s (eg. link cable removal (LSC), + * LPLU, Giga disable, MDIC PHY reset): + * 1) Set Kumeran Near-end loopback + * 2) Clear Kumeran Near-end loopback + * Should only be called for ICH8[m] devices with IGP_3 Phy. + **/ +void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw) +{ + s32 ret_val; + u16 reg_data; + + if ((hw->mac.type != e1000_ich8lan) || + (hw->phy.type != e1000_phy_igp_3)) + return; + + ret_val = e1000e_read_kmrn_reg(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET, + ®_data); + if (ret_val) + return; + reg_data |= E1000_KMRNCTRLSTA_DIAG_NELPBK; + ret_val = e1000e_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET, + reg_data); + if (ret_val) + return; + reg_data &= ~E1000_KMRNCTRLSTA_DIAG_NELPBK; + ret_val = e1000e_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET, + reg_data); +} + +/** + * e1000_cleanup_led_ich8lan - Restore the default LED operation + * @hw: pointer to the HW structure + * + * Return the LED back to the default configuration. + **/ +static s32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw) +{ + if (hw->phy.type == e1000_phy_ife) + return e1e_wphy(hw, IFE_PHY_SPECIAL_CONTROL_LED, 0); + + ew32(LEDCTL, hw->mac.ledctl_default); + return 0; +} + +/** + * e1000_led_on_ich8lan - Turn LED's on + * @hw: pointer to the HW structure + * + * Turn on the LED's. + **/ +static s32 e1000_led_on_ich8lan(struct e1000_hw *hw) +{ + if (hw->phy.type == e1000_phy_ife) + return e1e_wphy(hw, IFE_PHY_SPECIAL_CONTROL_LED, + (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_ON)); + + ew32(LEDCTL, hw->mac.ledctl_mode2); + return 0; +} + +/** + * e1000_led_off_ich8lan - Turn LED's off + * @hw: pointer to the HW structure + * + * Turn off the LED's. + **/ +static s32 e1000_led_off_ich8lan(struct e1000_hw *hw) +{ + if (hw->phy.type == e1000_phy_ife) + return e1e_wphy(hw, IFE_PHY_SPECIAL_CONTROL_LED, + (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_OFF)); + + ew32(LEDCTL, hw->mac.ledctl_mode1); + return 0; +} + +/** + * e1000_clear_hw_cntrs_ich8lan - Clear statistical counters + * @hw: pointer to the HW structure + * + * Clears hardware counters specific to the silicon family and calls + * clear_hw_cntrs_generic to clear all general purpose counters. + **/ +static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw) +{ + u32 temp; + + e1000e_clear_hw_cntrs_base(hw); + + temp = er32(ALGNERRC); + temp = er32(RXERRC); + temp = er32(TNCRS); + temp = er32(CEXTERR); + temp = er32(TSCTC); + temp = er32(TSCTFC); + + temp = er32(MGTPRC); + temp = er32(MGTPDC); + temp = er32(MGTPTC); + + temp = er32(IAC); + temp = er32(ICRXOC); + +} + +static struct e1000_mac_operations ich8_mac_ops = { + .mng_mode_enab = E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT, + .check_for_link = e1000e_check_for_copper_link, + .cleanup_led = e1000_cleanup_led_ich8lan, + .clear_hw_cntrs = e1000_clear_hw_cntrs_ich8lan, + .get_bus_info = e1000_get_bus_info_ich8lan, + .get_link_up_info = e1000_get_link_up_info_ich8lan, + .led_on = e1000_led_on_ich8lan, + .led_off = e1000_led_off_ich8lan, + .mc_addr_list_update = e1000e_mc_addr_list_update_generic, + .reset_hw = e1000_reset_hw_ich8lan, + .init_hw = e1000_init_hw_ich8lan, + .setup_link = e1000_setup_link_ich8lan, + .setup_physical_interface= e1000_setup_copper_link_ich8lan, +}; + +static struct e1000_phy_operations ich8_phy_ops = { + .acquire_phy = e1000_acquire_swflag_ich8lan, + .check_reset_block = e1000_check_reset_block_ich8lan, + .commit_phy = NULL, + .force_speed_duplex = e1000_phy_force_speed_duplex_ich8lan, + .get_cfg_done = e1000e_get_cfg_done, + .get_cable_length = e1000e_get_cable_length_igp_2, + .get_phy_info = e1000_get_phy_info_ich8lan, + .read_phy_reg = e1000e_read_phy_reg_igp, + .release_phy = e1000_release_swflag_ich8lan, + .reset_phy = e1000_phy_hw_reset_ich8lan, + .set_d0_lplu_state = e1000_set_d0_lplu_state_ich8lan, + .set_d3_lplu_state = e1000_set_d3_lplu_state_ich8lan, + .write_phy_reg = e1000e_write_phy_reg_igp, +}; + +static struct e1000_nvm_operations ich8_nvm_ops = { + .acquire_nvm = e1000_acquire_swflag_ich8lan, + .read_nvm = e1000_read_nvm_ich8lan, + .release_nvm = e1000_release_swflag_ich8lan, + .update_nvm = e1000_update_nvm_checksum_ich8lan, + .valid_led_default = e1000_valid_led_default_ich8lan, + .validate_nvm = e1000_validate_nvm_checksum_ich8lan, + .write_nvm = e1000_write_nvm_ich8lan, +}; + +struct e1000_info e1000_ich8_info = { + .mac = e1000_ich8lan, + .flags = FLAG_HAS_WOL + | FLAG_RX_CSUM_ENABLED + | FLAG_HAS_CTRLEXT_ON_LOAD + | FLAG_HAS_AMT + | FLAG_HAS_FLASH + | FLAG_APME_IN_WUC, + .pba = 8, + .get_invariants = e1000_get_invariants_ich8lan, + .mac_ops = &ich8_mac_ops, + .phy_ops = &ich8_phy_ops, + .nvm_ops = &ich8_nvm_ops, +}; + +struct e1000_info e1000_ich9_info = { + .mac = e1000_ich9lan, + .flags = FLAG_HAS_JUMBO_FRAMES + | FLAG_HAS_WOL + | FLAG_RX_CSUM_ENABLED + | FLAG_HAS_CTRLEXT_ON_LOAD + | FLAG_HAS_AMT + | FLAG_HAS_ERT + | FLAG_HAS_FLASH + | FLAG_APME_IN_WUC, + .pba = 10, + .get_invariants = e1000_get_invariants_ich8lan, + .mac_ops = &ich8_mac_ops, + .phy_ops = &ich8_phy_ops, + .nvm_ops = &ich8_nvm_ops, +}; + diff --git a/drivers/net/e1000e/lib.c b/drivers/net/e1000e/lib.c new file mode 100644 index 00000000000..3bbfe605e11 --- /dev/null +++ b/drivers/net/e1000e/lib.c @@ -0,0 +1,2487 @@ +/******************************************************************************* + + Intel PRO/1000 Linux driver + Copyright(c) 1999 - 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#include +#include +#include +#include + +#include "e1000.h" + +enum e1000_mng_mode { + e1000_mng_mode_none = 0, + e1000_mng_mode_asf, + e1000_mng_mode_pt, + e1000_mng_mode_ipmi, + e1000_mng_mode_host_if_only +}; + +#define E1000_FACTPS_MNGCG 0x20000000 + +#define E1000_IAMT_SIGNATURE 0x544D4149 /* Intel(R) Active Management + * Technology signature */ + +/** + * e1000e_get_bus_info_pcie - Get PCIe bus information + * @hw: pointer to the HW structure + * + * Determines and stores the system bus information for a particular + * network interface. The following bus information is determined and stored: + * bus speed, bus width, type (PCIe), and PCIe function. + **/ +s32 e1000e_get_bus_info_pcie(struct e1000_hw *hw) +{ + struct e1000_bus_info *bus = &hw->bus; + struct e1000_adapter *adapter = hw->adapter; + u32 status; + u16 pcie_link_status, pci_header_type, cap_offset; + + cap_offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP); + if (!cap_offset) { + bus->width = e1000_bus_width_unknown; + } else { + pci_read_config_word(adapter->pdev, + cap_offset + PCIE_LINK_STATUS, + &pcie_link_status); + bus->width = (enum e1000_bus_width)((pcie_link_status & + PCIE_LINK_WIDTH_MASK) >> + PCIE_LINK_WIDTH_SHIFT); + } + + pci_read_config_word(adapter->pdev, PCI_HEADER_TYPE_REGISTER, + &pci_header_type); + if (pci_header_type & PCI_HEADER_TYPE_MULTIFUNC) { + status = er32(STATUS); + bus->func = (status & E1000_STATUS_FUNC_MASK) + >> E1000_STATUS_FUNC_SHIFT; + } else { + bus->func = 0; + } + + return 0; +} + +/** + * e1000e_write_vfta - Write value to VLAN filter table + * @hw: pointer to the HW structure + * @offset: register offset in VLAN filter table + * @value: register value written to VLAN filter table + * + * Writes value at the given offset in the register array which stores + * the VLAN filter table. + **/ +void e1000e_write_vfta(struct e1000_hw *hw, u32 offset, u32 value) +{ + E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, value); + e1e_flush(); +} + +/** + * e1000e_init_rx_addrs - Initialize receive address's + * @hw: pointer to the HW structure + * @rar_count: receive address registers + * + * Setups the receive address registers by setting the base receive address + * register to the devices MAC address and clearing all the other receive + * address registers to 0. + **/ +void e1000e_init_rx_addrs(struct e1000_hw *hw, u16 rar_count) +{ + u32 i; + + /* Setup the receive address */ + hw_dbg(hw, "Programming MAC Address into RAR[0]\n"); + + e1000e_rar_set(hw, hw->mac.addr, 0); + + /* Zero out the other (rar_entry_count - 1) receive addresses */ + hw_dbg(hw, "Clearing RAR[1-%u]\n", rar_count-1); + for (i = 1; i < rar_count; i++) { + E1000_WRITE_REG_ARRAY(hw, E1000_RA, (i << 1), 0); + e1e_flush(); + E1000_WRITE_REG_ARRAY(hw, E1000_RA, ((i << 1) + 1), 0); + e1e_flush(); + } +} + +/** + * e1000e_rar_set - Set receive address register + * @hw: pointer to the HW structure + * @addr: pointer to the receive address + * @index: receive address array register + * + * Sets the receive address array register at index to the address passed + * in by addr. + **/ +void e1000e_rar_set(struct e1000_hw *hw, u8 *addr, u32 index) +{ + u32 rar_low, rar_high; + + /* HW expects these in little endian so we reverse the byte order + * from network order (big endian) to little endian + */ + rar_low = ((u32) addr[0] | + ((u32) addr[1] << 8) | + ((u32) addr[2] << 16) | ((u32) addr[3] << 24)); + + rar_high = ((u32) addr[4] | ((u32) addr[5] << 8)); + + rar_high |= E1000_RAH_AV; + + E1000_WRITE_REG_ARRAY(hw, E1000_RA, (index << 1), rar_low); + E1000_WRITE_REG_ARRAY(hw, E1000_RA, ((index << 1) + 1), rar_high); +} + +/** + * e1000_mta_set - Set multicast filter table address + * @hw: pointer to the HW structure + * @hash_value: determines the MTA register and bit to set + * + * The multicast table address is a register array of 32-bit registers. + * The hash_value is used to determine what register the bit is in, the + * current value is read, the new bit is OR'd in and the new value is + * written back into the register. + **/ +static void e1000_mta_set(struct e1000_hw *hw, u32 hash_value) +{ + u32 hash_bit, hash_reg, mta; + + /* The MTA is a register array of 32-bit registers. It is + * treated like an array of (32*mta_reg_count) bits. We want to + * set bit BitArray[hash_value]. So we figure out what register + * the bit is in, read it, OR in the new bit, then write + * back the new value. The (hw->mac.mta_reg_count - 1) serves as a + * mask to bits 31:5 of the hash value which gives us the + * register we're modifying. The hash bit within that register + * is determined by the lower 5 bits of the hash value. + */ + hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1); + hash_bit = hash_value & 0x1F; + + mta = E1000_READ_REG_ARRAY(hw, E1000_MTA, hash_reg); + + mta |= (1 << hash_bit); + + E1000_WRITE_REG_ARRAY(hw, E1000_MTA, hash_reg, mta); + e1e_flush(); +} + +/** + * e1000_hash_mc_addr - Generate a multicast hash value + * @hw: pointer to the HW structure + * @mc_addr: pointer to a multicast address + * + * Generates a multicast address hash value which is used to determine + * the multicast filter table array address and new table value. See + * e1000_mta_set_generic() + **/ +static u32 e1000_hash_mc_addr(struct e1000_hw *hw, u8 *mc_addr) +{ + u32 hash_value, hash_mask; + u8 bit_shift = 0; + + /* Register count multiplied by bits per register */ + hash_mask = (hw->mac.mta_reg_count * 32) - 1; + + /* For a mc_filter_type of 0, bit_shift is the number of left-shifts + * where 0xFF would still fall within the hash mask. */ + while (hash_mask >> bit_shift != 0xFF) + bit_shift++; + + /* The portion of the address that is used for the hash table + * is determined by the mc_filter_type setting. + * The algorithm is such that there is a total of 8 bits of shifting. + * The bit_shift for a mc_filter_type of 0 represents the number of + * left-shifts where the MSB of mc_addr[5] would still fall within + * the hash_mask. Case 0 does this exactly. Since there are a total + * of 8 bits of shifting, then mc_addr[4] will shift right the + * remaining number of bits. Thus 8 - bit_shift. The rest of the + * cases are a variation of this algorithm...essentially raising the + * number of bits to shift mc_addr[5] left, while still keeping the + * 8-bit shifting total. + */ + /* For example, given the following Destination MAC Address and an + * mta register count of 128 (thus a 4096-bit vector and 0xFFF mask), + * we can see that the bit_shift for case 0 is 4. These are the hash + * values resulting from each mc_filter_type... + * [0] [1] [2] [3] [4] [5] + * 01 AA 00 12 34 56 + * LSB MSB + * + * case 0: hash_value = ((0x34 >> 4) | (0x56 << 4)) & 0xFFF = 0x563 + * case 1: hash_value = ((0x34 >> 3) | (0x56 << 5)) & 0xFFF = 0xAC6 + * case 2: hash_value = ((0x34 >> 2) | (0x56 << 6)) & 0xFFF = 0x163 + * case 3: hash_value = ((0x34 >> 0) | (0x56 << 8)) & 0xFFF = 0x634 + */ + switch (hw->mac.mc_filter_type) { + default: + case 0: + break; + case 1: + bit_shift += 1; + break; + case 2: + bit_shift += 2; + break; + case 3: + bit_shift += 4; + break; + } + + hash_value = hash_mask & (((mc_addr[4] >> (8 - bit_shift)) | + (((u16) mc_addr[5]) << bit_shift))); + + return hash_value; +} + +/** + * e1000e_mc_addr_list_update_generic - Update Multicast addresses + * @hw: pointer to the HW structure + * @mc_addr_list: array of multicast addresses to program + * @mc_addr_count: number of multicast addresses to program + * @rar_used_count: the first RAR register free to program + * @rar_count: total number of supported Receive Address Registers + * + * Updates the Receive Address Registers and Multicast Table Array. + * The caller must have a packed mc_addr_list of multicast addresses. + * The parameter rar_count will usually be hw->mac.rar_entry_count + * unless there are workarounds that change this. + **/ +void e1000e_mc_addr_list_update_generic(struct e1000_hw *hw, + u8 *mc_addr_list, u32 mc_addr_count, + u32 rar_used_count, u32 rar_count) +{ + u32 hash_value; + u32 i; + + /* Load the first set of multicast addresses into the exact + * filters (RAR). If there are not enough to fill the RAR + * array, clear the filters. + */ + for (i = rar_used_count; i < rar_count; i++) { + if (mc_addr_count) { + e1000e_rar_set(hw, mc_addr_list, i); + mc_addr_count--; + mc_addr_list += ETH_ALEN; + } else { + E1000_WRITE_REG_ARRAY(hw, E1000_RA, i << 1, 0); + e1e_flush(); + E1000_WRITE_REG_ARRAY(hw, E1000_RA, (i << 1) + 1, 0); + e1e_flush(); + } + } + + /* Clear the old settings from the MTA */ + hw_dbg(hw, "Clearing MTA\n"); + for (i = 0; i < hw->mac.mta_reg_count; i++) { + E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0); + e1e_flush(); + } + + /* Load any remaining multicast addresses into the hash table. */ + for (; mc_addr_count > 0; mc_addr_count--) { + hash_value = e1000_hash_mc_addr(hw, mc_addr_list); + hw_dbg(hw, "Hash value = 0x%03X\n", hash_value); + e1000_mta_set(hw, hash_value); + mc_addr_list += ETH_ALEN; + } +} + +/** + * e1000e_clear_hw_cntrs_base - Clear base hardware counters + * @hw: pointer to the HW structure + * + * Clears the base hardware counters by reading the counter registers. + **/ +void e1000e_clear_hw_cntrs_base(struct e1000_hw *hw) +{ + u32 temp; + + temp = er32(CRCERRS); + temp = er32(SYMERRS); + temp = er32(MPC); + temp = er32(SCC); + temp = er32(ECOL); + temp = er32(MCC); + temp = er32(LATECOL); + temp = er32(COLC); + temp = er32(DC); + temp = er32(SEC); + temp = er32(RLEC); + temp = er32(XONRXC); + temp = er32(XONTXC); + temp = er32(XOFFRXC); + temp = er32(XOFFTXC); + temp = er32(FCRUC); + temp = er32(GPRC); + temp = er32(BPRC); + temp = er32(MPRC); + temp = er32(GPTC); + temp = er32(GORCL); + temp = er32(GORCH); + temp = er32(GOTCL); + temp = er32(GOTCH); + temp = er32(RNBC); + temp = er32(RUC); + temp = er32(RFC); + temp = er32(ROC); + temp = er32(RJC); + temp = er32(TORL); + temp = er32(TORH); + temp = er32(TOTL); + temp = er32(TOTH); + temp = er32(TPR); + temp = er32(TPT); + temp = er32(MPTC); + temp = er32(BPTC); +} + +/** + * e1000e_check_for_copper_link - Check for link (Copper) + * @hw: pointer to the HW structure + * + * Checks to see of the link status of the hardware has changed. If a + * change in link status has been detected, then we read the PHY registers + * to get the current speed/duplex if link exists. + **/ +s32 e1000e_check_for_copper_link(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + s32 ret_val; + bool link; + + /* We only want to go out to the PHY registers to see if Auto-Neg + * has completed and/or if our link status has changed. The + * get_link_status flag is set upon receiving a Link Status + * Change or Rx Sequence Error interrupt. + */ + if (!mac->get_link_status) + return 0; + + /* First we want to see if the MII Status Register reports + * link. If so, then we want to get the current speed/duplex + * of the PHY. + */ + ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link); + if (ret_val) + return ret_val; + + if (!link) + return ret_val; /* No link detected */ + + mac->get_link_status = 0; + + /* Check if there was DownShift, must be checked + * immediately after link-up */ + e1000e_check_downshift(hw); + + /* If we are forcing speed/duplex, then we simply return since + * we have already determined whether we have link or not. + */ + if (!mac->autoneg) { + ret_val = -E1000_ERR_CONFIG; + return ret_val; + } + + /* Auto-Neg is enabled. Auto Speed Detection takes care + * of MAC speed/duplex configuration. So we only need to + * configure Collision Distance in the MAC. + */ + e1000e_config_collision_dist(hw); + + /* Configure Flow Control now that Auto-Neg has completed. + * First, we need to restore the desired flow control + * settings because we may have had to re-autoneg with a + * different link partner. + */ + ret_val = e1000e_config_fc_after_link_up(hw); + if (ret_val) { + hw_dbg(hw, "Error configuring flow control\n"); + } + + return ret_val; +} + +/** + * e1000e_check_for_fiber_link - Check for link (Fiber) + * @hw: pointer to the HW structure + * + * Checks for link up on the hardware. If link is not up and we have + * a signal, then we need to force link up. + **/ +s32 e1000e_check_for_fiber_link(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + u32 rxcw; + u32 ctrl; + u32 status; + s32 ret_val; + + ctrl = er32(CTRL); + status = er32(STATUS); + rxcw = er32(RXCW); + + /* If we don't have link (auto-negotiation failed or link partner + * cannot auto-negotiate), the cable is plugged in (we have signal), + * and our link partner is not trying to auto-negotiate with us (we + * are receiving idles or data), we need to force link up. We also + * need to give auto-negotiation time to complete, in case the cable + * was just plugged in. The autoneg_failed flag does this. + */ + /* (ctrl & E1000_CTRL_SWDPIN1) == 1 == have signal */ + if ((ctrl & E1000_CTRL_SWDPIN1) && (!(status & E1000_STATUS_LU)) && + (!(rxcw & E1000_RXCW_C))) { + if (mac->autoneg_failed == 0) { + mac->autoneg_failed = 1; + return 0; + } + hw_dbg(hw, "NOT RXing /C/, disable AutoNeg and force link.\n"); + + /* Disable auto-negotiation in the TXCW register */ + ew32(TXCW, (mac->txcw & ~E1000_TXCW_ANE)); + + /* Force link-up and also force full-duplex. */ + ctrl = er32(CTRL); + ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD); + ew32(CTRL, ctrl); + + /* Configure Flow Control after forcing link up. */ + ret_val = e1000e_config_fc_after_link_up(hw); + if (ret_val) { + hw_dbg(hw, "Error configuring flow control\n"); + return ret_val; + } + } else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) { + /* If we are forcing link and we are receiving /C/ ordered + * sets, re-enable auto-negotiation in the TXCW register + * and disable forced link in the Device Control register + * in an attempt to auto-negotiate with our link partner. + */ + hw_dbg(hw, "RXing /C/, enable AutoNeg and stop forcing link.\n"); + ew32(TXCW, mac->txcw); + ew32(CTRL, (ctrl & ~E1000_CTRL_SLU)); + + mac->serdes_has_link = 1; + } + + return 0; +} + +/** + * e1000e_check_for_serdes_link - Check for link (Serdes) + * @hw: pointer to the HW structure + * + * Checks for link up on the hardware. If link is not up and we have + * a signal, then we need to force link up. + **/ +s32 e1000e_check_for_serdes_link(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + u32 rxcw; + u32 ctrl; + u32 status; + s32 ret_val; + + ctrl = er32(CTRL); + status = er32(STATUS); + rxcw = er32(RXCW); + + /* If we don't have link (auto-negotiation failed or link partner + * cannot auto-negotiate), and our link partner is not trying to + * auto-negotiate with us (we are receiving idles or data), + * we need to force link up. We also need to give auto-negotiation + * time to complete. + */ + /* (ctrl & E1000_CTRL_SWDPIN1) == 1 == have signal */ + if ((!(status & E1000_STATUS_LU)) && (!(rxcw & E1000_RXCW_C))) { + if (mac->autoneg_failed == 0) { + mac->autoneg_failed = 1; + return 0; + } + hw_dbg(hw, "NOT RXing /C/, disable AutoNeg and force link.\n"); + + /* Disable auto-negotiation in the TXCW register */ + ew32(TXCW, (mac->txcw & ~E1000_TXCW_ANE)); + + /* Force link-up and also force full-duplex. */ + ctrl = er32(CTRL); + ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD); + ew32(CTRL, ctrl); + + /* Configure Flow Control after forcing link up. */ + ret_val = e1000e_config_fc_after_link_up(hw); + if (ret_val) { + hw_dbg(hw, "Error configuring flow control\n"); + return ret_val; + } + } else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) { + /* If we are forcing link and we are receiving /C/ ordered + * sets, re-enable auto-negotiation in the TXCW register + * and disable forced link in the Device Control register + * in an attempt to auto-negotiate with our link partner. + */ + hw_dbg(hw, "RXing /C/, enable AutoNeg and stop forcing link.\n"); + ew32(TXCW, mac->txcw); + ew32(CTRL, (ctrl & ~E1000_CTRL_SLU)); + + mac->serdes_has_link = 1; + } else if (!(E1000_TXCW_ANE & er32(TXCW))) { + /* If we force link for non-auto-negotiation switch, check + * link status based on MAC synchronization for internal + * serdes media type. + */ + /* SYNCH bit and IV bit are sticky. */ + udelay(10); + if (E1000_RXCW_SYNCH & er32(RXCW)) { + if (!(rxcw & E1000_RXCW_IV)) { + mac->serdes_has_link = 1; + hw_dbg(hw, "SERDES: Link is up.\n"); + } + } else { + mac->serdes_has_link = 0; + hw_dbg(hw, "SERDES: Link is down.\n"); + } + } + + if (E1000_TXCW_ANE & er32(TXCW)) { + status = er32(STATUS); + mac->serdes_has_link = (status & E1000_STATUS_LU); + } + + return 0; +} + +/** + * e1000_set_default_fc_generic - Set flow control default values + * @hw: pointer to the HW structure + * + * Read the EEPROM for the default values for flow control and store the + * values. + **/ +static s32 e1000_set_default_fc_generic(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + s32 ret_val; + u16 nvm_data; + + if (mac->fc != e1000_fc_default) + return 0; + + /* Read and store word 0x0F of the EEPROM. This word contains bits + * that determine the hardware's default PAUSE (flow control) mode, + * a bit that determines whether the HW defaults to enabling or + * disabling auto-negotiation, and the direction of the + * SW defined pins. If there is no SW over-ride of the flow + * control setting, then the variable hw->fc will + * be initialized based on a value in the EEPROM. + */ + ret_val = e1000_read_nvm(hw, NVM_INIT_CONTROL2_REG, 1, &nvm_data); + + if (ret_val) { + hw_dbg(hw, "NVM Read Error\n"); + return ret_val; + } + + if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == 0) + mac->fc = e1000_fc_none; + else if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == + NVM_WORD0F_ASM_DIR) + mac->fc = e1000_fc_tx_pause; + else + mac->fc = e1000_fc_full; + + return 0; +} + +/** + * e1000e_setup_link - Setup flow control and link settings + * @hw: pointer to the HW structure + * + * Determines which flow control settings to use, then configures flow + * control. Calls the appropriate media-specific link configuration + * function. Assuming the adapter has a valid link partner, a valid link + * should be established. Assumes the hardware has previously been reset + * and the transmitter and receiver are not enabled. + **/ +s32 e1000e_setup_link(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + s32 ret_val; + + /* In the case of the phy reset being blocked, we already have a link. + * We do not need to set it up again. + */ + if (e1000_check_reset_block(hw)) + return 0; + + ret_val = e1000_set_default_fc_generic(hw); + if (ret_val) + return ret_val; + + /* We want to save off the original Flow Control configuration just + * in case we get disconnected and then reconnected into a different + * hub or switch with different Flow Control capabilities. + */ + mac->original_fc = mac->fc; + + hw_dbg(hw, "After fix-ups FlowControl is now = %x\n", mac->fc); + + /* Call the necessary media_type subroutine to configure the link. */ + ret_val = mac->ops.setup_physical_interface(hw); + if (ret_val) + return ret_val; + + /* Initialize the flow control address, type, and PAUSE timer + * registers to their default values. This is done even if flow + * control is disabled, because it does not hurt anything to + * initialize these registers. + */ + hw_dbg(hw, "Initializing the Flow Control address, type and timer regs\n"); + ew32(FCT, FLOW_CONTROL_TYPE); + ew32(FCAH, FLOW_CONTROL_ADDRESS_HIGH); + ew32(FCAL, FLOW_CONTROL_ADDRESS_LOW); + + ew32(FCTTV, mac->fc_pause_time); + + return e1000e_set_fc_watermarks(hw); +} + +/** + * e1000_commit_fc_settings_generic - Configure flow control + * @hw: pointer to the HW structure + * + * Write the flow control settings to the Transmit Config Word Register (TXCW) + * base on the flow control settings in e1000_mac_info. + **/ +static s32 e1000_commit_fc_settings_generic(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + u32 txcw; + + /* Check for a software override of the flow control settings, and + * setup the device accordingly. If auto-negotiation is enabled, then + * software will have to set the "PAUSE" bits to the correct value in + * the Transmit Config Word Register (TXCW) and re-start auto- + * negotiation. However, if auto-negotiation is disabled, then + * software will have to manually configure the two flow control enable + * bits in the CTRL register. + * + * The possible values of the "fc" parameter are: + * 0: Flow control is completely disabled + * 1: Rx flow control is enabled (we can receive pause frames, + * but not send pause frames). + * 2: Tx flow control is enabled (we can send pause frames but we + * do not support receiving pause frames). + * 3: Both Rx and TX flow control (symmetric) are enabled. + */ + switch (mac->fc) { + case e1000_fc_none: + /* Flow control completely disabled by a software over-ride. */ + txcw = (E1000_TXCW_ANE | E1000_TXCW_FD); + break; + case e1000_fc_rx_pause: + /* RX Flow control is enabled and TX Flow control is disabled + * by a software over-ride. Since there really isn't a way to + * advertise that we are capable of RX Pause ONLY, we will + * advertise that we support both symmetric and asymmetric RX + * PAUSE. Later, we will disable the adapter's ability to send + * PAUSE frames. + */ + txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK); + break; + case e1000_fc_tx_pause: + /* TX Flow control is enabled, and RX Flow control is disabled, + * by a software over-ride. + */ + txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR); + break; + case e1000_fc_full: + /* Flow control (both RX and TX) is enabled by a software + * over-ride. + */ + txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK); + break; + default: + hw_dbg(hw, "Flow control param set incorrectly\n"); + return -E1000_ERR_CONFIG; + break; + } + + ew32(TXCW, txcw); + mac->txcw = txcw; + + return 0; +} + +/** + * e1000_poll_fiber_serdes_link_generic - Poll for link up + * @hw: pointer to the HW structure + * + * Polls for link up by reading the status register, if link fails to come + * up with auto-negotiation, then the link is forced if a signal is detected. + **/ +static s32 e1000_poll_fiber_serdes_link_generic(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + u32 i, status; + s32 ret_val; + + /* If we have a signal (the cable is plugged in, or assumed true for + * serdes media) then poll for a "Link-Up" indication in the Device + * Status Register. Time-out if a link isn't seen in 500 milliseconds + * seconds (Auto-negotiation should complete in less than 500 + * milliseconds even if the other end is doing it in SW). + */ + for (i = 0; i < FIBER_LINK_UP_LIMIT; i++) { + msleep(10); + status = er32(STATUS); + if (status & E1000_STATUS_LU) + break; + } + if (i == FIBER_LINK_UP_LIMIT) { + hw_dbg(hw, "Never got a valid link from auto-neg!!!\n"); + mac->autoneg_failed = 1; + /* AutoNeg failed to achieve a link, so we'll call + * mac->check_for_link. This routine will force the + * link up if we detect a signal. This will allow us to + * communicate with non-autonegotiating link partners. + */ + ret_val = mac->ops.check_for_link(hw); + if (ret_val) { + hw_dbg(hw, "Error while checking for link\n"); + return ret_val; + } + mac->autoneg_failed = 0; + } else { + mac->autoneg_failed = 0; + hw_dbg(hw, "Valid Link Found\n"); + } + + return 0; +} + +/** + * e1000e_setup_fiber_serdes_link - Setup link for fiber/serdes + * @hw: pointer to the HW structure + * + * Configures collision distance and flow control for fiber and serdes + * links. Upon successful setup, poll for link. + **/ +s32 e1000e_setup_fiber_serdes_link(struct e1000_hw *hw) +{ + u32 ctrl; + s32 ret_val; + + ctrl = er32(CTRL); + + /* Take the link out of reset */ + ctrl &= ~E1000_CTRL_LRST; + + e1000e_config_collision_dist(hw); + + ret_val = e1000_commit_fc_settings_generic(hw); + if (ret_val) + return ret_val; + + /* Since auto-negotiation is enabled, take the link out of reset (the + * link will be in reset, because we previously reset the chip). This + * will restart auto-negotiation. If auto-negotiation is successful + * then the link-up status bit will be set and the flow control enable + * bits (RFCE and TFCE) will be set according to their negotiated value. + */ + hw_dbg(hw, "Auto-negotiation enabled\n"); + + ew32(CTRL, ctrl); + e1e_flush(); + msleep(1); + + /* For these adapters, the SW defineable pin 1 is set when the optics + * detect a signal. If we have a signal, then poll for a "Link-Up" + * indication. + */ + if (hw->media_type == e1000_media_type_internal_serdes || + (er32(CTRL) & E1000_CTRL_SWDPIN1)) { + ret_val = e1000_poll_fiber_serdes_link_generic(hw); + } else { + hw_dbg(hw, "No signal detected\n"); + } + + return 0; +} + +/** + * e1000e_config_collision_dist - Configure collision distance + * @hw: pointer to the HW structure + * + * Configures the collision distance to the default value and is used + * during link setup. Currently no func pointer exists and all + * implementations are handled in the generic version of this function. + **/ +void e1000e_config_collision_dist(struct e1000_hw *hw) +{ + u32 tctl; + + tctl = er32(TCTL); + + tctl &= ~E1000_TCTL_COLD; + tctl |= E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT; + + ew32(TCTL, tctl); + e1e_flush(); +} + +/** + * e1000e_set_fc_watermarks - Set flow control high/low watermarks + * @hw: pointer to the HW structure + * + * Sets the flow control high/low threshold (watermark) registers. If + * flow control XON frame transmission is enabled, then set XON frame + * tansmission as well. + **/ +s32 e1000e_set_fc_watermarks(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + u32 fcrtl = 0, fcrth = 0; + + /* Set the flow control receive threshold registers. Normally, + * these registers will be set to a default threshold that may be + * adjusted later by the driver's runtime code. However, if the + * ability to transmit pause frames is not enabled, then these + * registers will be set to 0. + */ + if (mac->fc & e1000_fc_tx_pause) { + /* We need to set up the Receive Threshold high and low water + * marks as well as (optionally) enabling the transmission of + * XON frames. + */ + fcrtl = mac->fc_low_water; + fcrtl |= E1000_FCRTL_XONE; + fcrth = mac->fc_high_water; + } + ew32(FCRTL, fcrtl); + ew32(FCRTH, fcrth); + + return 0; +} + +/** + * e1000e_force_mac_fc - Force the MAC's flow control settings + * @hw: pointer to the HW structure + * + * Force the MAC's flow control settings. Sets the TFCE and RFCE bits in the + * device control register to reflect the adapter settings. TFCE and RFCE + * need to be explicitly set by software when a copper PHY is used because + * autonegotiation is managed by the PHY rather than the MAC. Software must + * also configure these bits when link is forced on a fiber connection. + **/ +s32 e1000e_force_mac_fc(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + u32 ctrl; + + ctrl = er32(CTRL); + + /* Because we didn't get link via the internal auto-negotiation + * mechanism (we either forced link or we got link via PHY + * auto-neg), we have to manually enable/disable transmit an + * receive flow control. + * + * The "Case" statement below enables/disable flow control + * according to the "mac->fc" parameter. + * + * The possible values of the "fc" parameter are: + * 0: Flow control is completely disabled + * 1: Rx flow control is enabled (we can receive pause + * frames but not send pause frames). + * 2: Tx flow control is enabled (we can send pause frames + * frames but we do not receive pause frames). + * 3: Both Rx and TX flow control (symmetric) is enabled. + * other: No other values should be possible at this point. + */ + hw_dbg(hw, "mac->fc = %u\n", mac->fc); + + switch (mac->fc) { + case e1000_fc_none: + ctrl &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE)); + break; + case e1000_fc_rx_pause: + ctrl &= (~E1000_CTRL_TFCE); + ctrl |= E1000_CTRL_RFCE; + break; + case e1000_fc_tx_pause: + ctrl &= (~E1000_CTRL_RFCE); + ctrl |= E1000_CTRL_TFCE; + break; + case e1000_fc_full: + ctrl |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE); + break; + default: + hw_dbg(hw, "Flow control param set incorrectly\n"); + return -E1000_ERR_CONFIG; + } + + ew32(CTRL, ctrl); + + return 0; +} + +/** + * e1000e_config_fc_after_link_up - Configures flow control after link + * @hw: pointer to the HW structure + * + * Checks the status of auto-negotiation after link up to ensure that the + * speed and duplex were not forced. If the link needed to be forced, then + * flow control needs to be forced also. If auto-negotiation is enabled + * and did not fail, then we configure flow control based on our link + * partner. + **/ +s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + s32 ret_val = 0; + u16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg; + u16 speed, duplex; + + /* Check for the case where we have fiber media and auto-neg failed + * so we had to force link. In this case, we need to force the + * configuration of the MAC to match the "fc" parameter. + */ + if (mac->autoneg_failed) { + if (hw->media_type == e1000_media_type_fiber || + hw->media_type == e1000_media_type_internal_serdes) + ret_val = e1000e_force_mac_fc(hw); + } else { + if (hw->media_type == e1000_media_type_copper) + ret_val = e1000e_force_mac_fc(hw); + } + + if (ret_val) { + hw_dbg(hw, "Error forcing flow control settings\n"); + return ret_val; + } + + /* Check for the case where we have copper media and auto-neg is + * enabled. In this case, we need to check and see if Auto-Neg + * has completed, and if so, how the PHY and link partner has + * flow control configured. + */ + if ((hw->media_type == e1000_media_type_copper) && mac->autoneg) { + /* Read the MII Status Register and check to see if AutoNeg + * has completed. We read this twice because this reg has + * some "sticky" (latched) bits. + */ + ret_val = e1e_rphy(hw, PHY_STATUS, &mii_status_reg); + if (ret_val) + return ret_val; + ret_val = e1e_rphy(hw, PHY_STATUS, &mii_status_reg); + if (ret_val) + return ret_val; + + if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) { + hw_dbg(hw, "Copper PHY and Auto Neg " + "has not completed.\n"); + return ret_val; + } + + /* The AutoNeg process has completed, so we now need to + * read both the Auto Negotiation Advertisement + * Register (Address 4) and the Auto_Negotiation Base + * Page Ability Register (Address 5) to determine how + * flow control was negotiated. + */ + ret_val = e1e_rphy(hw, PHY_AUTONEG_ADV, &mii_nway_adv_reg); + if (ret_val) + return ret_val; + ret_val = e1e_rphy(hw, PHY_LP_ABILITY, &mii_nway_lp_ability_reg); + if (ret_val) + return ret_val; + + /* Two bits in the Auto Negotiation Advertisement Register + * (Address 4) and two bits in the Auto Negotiation Base + * Page Ability Register (Address 5) determine flow control + * for both the PHY and the link partner. The following + * table, taken out of the IEEE 802.3ab/D6.0 dated March 25, + * 1999, describes these PAUSE resolution bits and how flow + * control is determined based upon these settings. + * NOTE: DC = Don't Care + * + * LOCAL DEVICE | LINK PARTNER + * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution + *-------|---------|-------|---------|-------------------- + * 0 | 0 | DC | DC | e1000_fc_none + * 0 | 1 | 0 | DC | e1000_fc_none + * 0 | 1 | 1 | 0 | e1000_fc_none + * 0 | 1 | 1 | 1 | e1000_fc_tx_pause + * 1 | 0 | 0 | DC | e1000_fc_none + * 1 | DC | 1 | DC | e1000_fc_full + * 1 | 1 | 0 | 0 | e1000_fc_none + * 1 | 1 | 0 | 1 | e1000_fc_rx_pause + * + */ + /* Are both PAUSE bits set to 1? If so, this implies + * Symmetric Flow Control is enabled at both ends. The + * ASM_DIR bits are irrelevant per the spec. + * + * For Symmetric Flow Control: + * + * LOCAL DEVICE | LINK PARTNER + * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result + *-------|---------|-------|---------|-------------------- + * 1 | DC | 1 | DC | E1000_fc_full + * + */ + if ((mii_nway_adv_reg & NWAY_AR_PAUSE) && + (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) { + /* Now we need to check if the user selected RX ONLY + * of pause frames. In this case, we had to advertise + * FULL flow control because we could not advertise RX + * ONLY. Hence, we must now check to see if we need to + * turn OFF the TRANSMISSION of PAUSE frames. + */ + if (mac->original_fc == e1000_fc_full) { + mac->fc = e1000_fc_full; + hw_dbg(hw, "Flow Control = FULL.\r\n"); + } else { + mac->fc = e1000_fc_rx_pause; + hw_dbg(hw, "Flow Control = " + "RX PAUSE frames only.\r\n"); + } + } + /* For receiving PAUSE frames ONLY. + * + * LOCAL DEVICE | LINK PARTNER + * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result + *-------|---------|-------|---------|-------------------- + * 0 | 1 | 1 | 1 | e1000_fc_tx_pause + * + */ + else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) && + (mii_nway_adv_reg & NWAY_AR_ASM_DIR) && + (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && + (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { + mac->fc = e1000_fc_tx_pause; + hw_dbg(hw, "Flow Control = TX PAUSE frames only.\r\n"); + } + /* For transmitting PAUSE frames ONLY. + * + * LOCAL DEVICE | LINK PARTNER + * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result + *-------|---------|-------|---------|-------------------- + * 1 | 1 | 0 | 1 | e1000_fc_rx_pause + * + */ + else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) && + (mii_nway_adv_reg & NWAY_AR_ASM_DIR) && + !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && + (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { + mac->fc = e1000_fc_rx_pause; + hw_dbg(hw, "Flow Control = RX PAUSE frames only.\r\n"); + } + /* Per the IEEE spec, at this point flow control should be + * disabled. However, we want to consider that we could + * be connected to a legacy switch that doesn't advertise + * desired flow control, but can be forced on the link + * partner. So if we advertised no flow control, that is + * what we will resolve to. If we advertised some kind of + * receive capability (Rx Pause Only or Full Flow Control) + * and the link partner advertised none, we will configure + * ourselves to enable Rx Flow Control only. We can do + * this safely for two reasons: If the link partner really + * didn't want flow control enabled, and we enable Rx, no + * harm done since we won't be receiving any PAUSE frames + * anyway. If the intent on the link partner was to have + * flow control enabled, then by us enabling RX only, we + * can at least receive pause frames and process them. + * This is a good idea because in most cases, since we are + * predominantly a server NIC, more times than not we will + * be asked to delay transmission of packets than asking + * our link partner to pause transmission of frames. + */ + else if ((mac->original_fc == e1000_fc_none) || + (mac->original_fc == e1000_fc_tx_pause)) { + mac->fc = e1000_fc_none; + hw_dbg(hw, "Flow Control = NONE.\r\n"); + } else { + mac->fc = e1000_fc_rx_pause; + hw_dbg(hw, "Flow Control = RX PAUSE frames only.\r\n"); + } + + /* Now we need to do one last check... If we auto- + * negotiated to HALF DUPLEX, flow control should not be + * enabled per IEEE 802.3 spec. + */ + ret_val = mac->ops.get_link_up_info(hw, &speed, &duplex); + if (ret_val) { + hw_dbg(hw, "Error getting link speed and duplex\n"); + return ret_val; + } + + if (duplex == HALF_DUPLEX) + mac->fc = e1000_fc_none; + + /* Now we call a subroutine to actually force the MAC + * controller to use the correct flow control settings. + */ + ret_val = e1000e_force_mac_fc(hw); + if (ret_val) { + hw_dbg(hw, "Error forcing flow control settings\n"); + return ret_val; + } + } + + return 0; +} + +/** + * e1000e_get_speed_and_duplex_copper - Retreive current speed/duplex + * @hw: pointer to the HW structure + * @speed: stores the current speed + * @duplex: stores the current duplex + * + * Read the status register for the current speed/duplex and store the current + * speed and duplex for copper connections. + **/ +s32 e1000e_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 *speed, u16 *duplex) +{ + u32 status; + + status = er32(STATUS); + if (status & E1000_STATUS_SPEED_1000) { + *speed = SPEED_1000; + hw_dbg(hw, "1000 Mbs, "); + } else if (status & E1000_STATUS_SPEED_100) { + *speed = SPEED_100; + hw_dbg(hw, "100 Mbs, "); + } else { + *speed = SPEED_10; + hw_dbg(hw, "10 Mbs, "); + } + + if (status & E1000_STATUS_FD) { + *duplex = FULL_DUPLEX; + hw_dbg(hw, "Full Duplex\n"); + } else { + *duplex = HALF_DUPLEX; + hw_dbg(hw, "Half Duplex\n"); + } + + return 0; +} + +/** + * e1000e_get_speed_and_duplex_fiber_serdes - Retreive current speed/duplex + * @hw: pointer to the HW structure + * @speed: stores the current speed + * @duplex: stores the current duplex + * + * Sets the speed and duplex to gigabit full duplex (the only possible option) + * for fiber/serdes links. + **/ +s32 e1000e_get_speed_and_duplex_fiber_serdes(struct e1000_hw *hw, u16 *speed, u16 *duplex) +{ + *speed = SPEED_1000; + *duplex = FULL_DUPLEX; + + return 0; +} + +/** + * e1000e_get_hw_semaphore - Acquire hardware semaphore + * @hw: pointer to the HW structure + * + * Acquire the HW semaphore to access the PHY or NVM + **/ +s32 e1000e_get_hw_semaphore(struct e1000_hw *hw) +{ + u32 swsm; + s32 timeout = hw->nvm.word_size + 1; + s32 i = 0; + + /* Get the SW semaphore */ + while (i < timeout) { + swsm = er32(SWSM); + if (!(swsm & E1000_SWSM_SMBI)) + break; + + udelay(50); + i++; + } + + if (i == timeout) { + hw_dbg(hw, "Driver can't access device - SMBI bit is set.\n"); + return -E1000_ERR_NVM; + } + + /* Get the FW semaphore. */ + for (i = 0; i < timeout; i++) { + swsm = er32(SWSM); + ew32(SWSM, swsm | E1000_SWSM_SWESMBI); + + /* Semaphore acquired if bit latched */ + if (er32(SWSM) & E1000_SWSM_SWESMBI) + break; + + udelay(50); + } + + if (i == timeout) { + /* Release semaphores */ + e1000e_put_hw_semaphore(hw); + hw_dbg(hw, "Driver can't access the NVM\n"); + return -E1000_ERR_NVM; + } + + return 0; +} + +/** + * e1000e_put_hw_semaphore - Release hardware semaphore + * @hw: pointer to the HW structure + * + * Release hardware semaphore used to access the PHY or NVM + **/ +void e1000e_put_hw_semaphore(struct e1000_hw *hw) +{ + u32 swsm; + + swsm = er32(SWSM); + swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI); + ew32(SWSM, swsm); +} + +/** + * e1000e_get_auto_rd_done - Check for auto read completion + * @hw: pointer to the HW structure + * + * Check EEPROM for Auto Read done bit. + **/ +s32 e1000e_get_auto_rd_done(struct e1000_hw *hw) +{ + s32 i = 0; + + while (i < AUTO_READ_DONE_TIMEOUT) { + if (er32(EECD) & E1000_EECD_AUTO_RD) + break; + msleep(1); + i++; + } + + if (i == AUTO_READ_DONE_TIMEOUT) { + hw_dbg(hw, "Auto read by HW from NVM has not completed.\n"); + return -E1000_ERR_RESET; + } + + return 0; +} + +/** + * e1000e_valid_led_default - Verify a valid default LED config + * @hw: pointer to the HW structure + * @data: pointer to the NVM (EEPROM) + * + * Read the EEPROM for the current default LED configuration. If the + * LED configuration is not valid, set to a valid LED configuration. + **/ +s32 e1000e_valid_led_default(struct e1000_hw *hw, u16 *data) +{ + s32 ret_val; + + ret_val = e1000_read_nvm(hw, NVM_ID_LED_SETTINGS, 1, data); + if (ret_val) { + hw_dbg(hw, "NVM Read Error\n"); + return ret_val; + } + + if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF) + *data = ID_LED_DEFAULT; + + return 0; +} + +/** + * e1000e_id_led_init - + * @hw: pointer to the HW structure + * + **/ +s32 e1000e_id_led_init(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + s32 ret_val; + const u32 ledctl_mask = 0x000000FF; + const u32 ledctl_on = E1000_LEDCTL_MODE_LED_ON; + const u32 ledctl_off = E1000_LEDCTL_MODE_LED_OFF; + u16 data, i, temp; + const u16 led_mask = 0x0F; + + ret_val = hw->nvm.ops.valid_led_default(hw, &data); + if (ret_val) + return ret_val; + + mac->ledctl_default = er32(LEDCTL); + mac->ledctl_mode1 = mac->ledctl_default; + mac->ledctl_mode2 = mac->ledctl_default; + + for (i = 0; i < 4; i++) { + temp = (data >> (i << 2)) & led_mask; + switch (temp) { + case ID_LED_ON1_DEF2: + case ID_LED_ON1_ON2: + case ID_LED_ON1_OFF2: + mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3)); + mac->ledctl_mode1 |= ledctl_on << (i << 3); + break; + case ID_LED_OFF1_DEF2: + case ID_LED_OFF1_ON2: + case ID_LED_OFF1_OFF2: + mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3)); + mac->ledctl_mode1 |= ledctl_off << (i << 3); + break; + default: + /* Do nothing */ + break; + } + switch (temp) { + case ID_LED_DEF1_ON2: + case ID_LED_ON1_ON2: + case ID_LED_OFF1_ON2: + mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3)); + mac->ledctl_mode2 |= ledctl_on << (i << 3); + break; + case ID_LED_DEF1_OFF2: + case ID_LED_ON1_OFF2: + case ID_LED_OFF1_OFF2: + mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3)); + mac->ledctl_mode2 |= ledctl_off << (i << 3); + break; + default: + /* Do nothing */ + break; + } + } + + return 0; +} + +/** + * e1000e_cleanup_led_generic - Set LED config to default operation + * @hw: pointer to the HW structure + * + * Remove the current LED configuration and set the LED configuration + * to the default value, saved from the EEPROM. + **/ +s32 e1000e_cleanup_led_generic(struct e1000_hw *hw) +{ + ew32(LEDCTL, hw->mac.ledctl_default); + return 0; +} + +/** + * e1000e_blink_led - Blink LED + * @hw: pointer to the HW structure + * + * Blink the led's which are set to be on. + **/ +s32 e1000e_blink_led(struct e1000_hw *hw) +{ + u32 ledctl_blink = 0; + u32 i; + + if (hw->media_type == e1000_media_type_fiber) { + /* always blink LED0 for PCI-E fiber */ + ledctl_blink = E1000_LEDCTL_LED0_BLINK | + (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED0_MODE_SHIFT); + } else { + /* set the blink bit for each LED that's "on" (0x0E) + * in ledctl_mode2 */ + ledctl_blink = hw->mac.ledctl_mode2; + for (i = 0; i < 4; i++) + if (((hw->mac.ledctl_mode2 >> (i * 8)) & 0xFF) == + E1000_LEDCTL_MODE_LED_ON) + ledctl_blink |= (E1000_LEDCTL_LED0_BLINK << + (i * 8)); + } + + ew32(LEDCTL, ledctl_blink); + + return 0; +} + +/** + * e1000e_led_on_generic - Turn LED on + * @hw: pointer to the HW structure + * + * Turn LED on. + **/ +s32 e1000e_led_on_generic(struct e1000_hw *hw) +{ + u32 ctrl; + + switch (hw->media_type) { + case e1000_media_type_fiber: + ctrl = er32(CTRL); + ctrl &= ~E1000_CTRL_SWDPIN0; + ctrl |= E1000_CTRL_SWDPIO0; + ew32(CTRL, ctrl); + break; + case e1000_media_type_copper: + ew32(LEDCTL, hw->mac.ledctl_mode2); + break; + default: + break; + } + + return 0; +} + +/** + * e1000e_led_off_generic - Turn LED off + * @hw: pointer to the HW structure + * + * Turn LED off. + **/ +s32 e1000e_led_off_generic(struct e1000_hw *hw) +{ + u32 ctrl; + + switch (hw->media_type) { + case e1000_media_type_fiber: + ctrl = er32(CTRL); + ctrl |= E1000_CTRL_SWDPIN0; + ctrl |= E1000_CTRL_SWDPIO0; + ew32(CTRL, ctrl); + break; + case e1000_media_type_copper: + ew32(LEDCTL, hw->mac.ledctl_mode1); + break; + default: + break; + } + + return 0; +} + +/** + * e1000e_set_pcie_no_snoop - Set PCI-express capabilities + * @hw: pointer to the HW structure + * @no_snoop: bitmap of snoop events + * + * Set the PCI-express register to snoop for events enabled in 'no_snoop'. + **/ +void e1000e_set_pcie_no_snoop(struct e1000_hw *hw, u32 no_snoop) +{ + u32 gcr; + + if (no_snoop) { + gcr = er32(GCR); + gcr &= ~(PCIE_NO_SNOOP_ALL); + gcr |= no_snoop; + ew32(GCR, gcr); + } +} + +/** + * e1000e_disable_pcie_master - Disables PCI-express master access + * @hw: pointer to the HW structure + * + * Returns 0 if successful, else returns -10 + * (-E1000_ERR_MASTER_REQUESTS_PENDING) if master disable bit has not casued + * the master requests to be disabled. + * + * Disables PCI-Express master access and verifies there are no pending + * requests. + **/ +s32 e1000e_disable_pcie_master(struct e1000_hw *hw) +{ + u32 ctrl; + s32 timeout = MASTER_DISABLE_TIMEOUT; + + ctrl = er32(CTRL); + ctrl |= E1000_CTRL_GIO_MASTER_DISABLE; + ew32(CTRL, ctrl); + + while (timeout) { + if (!(er32(STATUS) & + E1000_STATUS_GIO_MASTER_ENABLE)) + break; + udelay(100); + timeout--; + } + + if (!timeout) { + hw_dbg(hw, "Master requests are pending.\n"); + return -E1000_ERR_MASTER_REQUESTS_PENDING; + } + + return 0; +} + +/** + * e1000e_reset_adaptive - Reset Adaptive Interframe Spacing + * @hw: pointer to the HW structure + * + * Reset the Adaptive Interframe Spacing throttle to default values. + **/ +void e1000e_reset_adaptive(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + + mac->current_ifs_val = 0; + mac->ifs_min_val = IFS_MIN; + mac->ifs_max_val = IFS_MAX; + mac->ifs_step_size = IFS_STEP; + mac->ifs_ratio = IFS_RATIO; + + mac->in_ifs_mode = 0; + ew32(AIT, 0); +} + +/** + * e1000e_update_adaptive - Update Adaptive Interframe Spacing + * @hw: pointer to the HW structure + * + * Update the Adaptive Interframe Spacing Throttle value based on the + * time between transmitted packets and time between collisions. + **/ +void e1000e_update_adaptive(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + + if ((mac->collision_delta * mac->ifs_ratio) > mac->tx_packet_delta) { + if (mac->tx_packet_delta > MIN_NUM_XMITS) { + mac->in_ifs_mode = 1; + if (mac->current_ifs_val < mac->ifs_max_val) { + if (!mac->current_ifs_val) + mac->current_ifs_val = mac->ifs_min_val; + else + mac->current_ifs_val += + mac->ifs_step_size; + ew32(AIT, + mac->current_ifs_val); + } + } + } else { + if (mac->in_ifs_mode && + (mac->tx_packet_delta <= MIN_NUM_XMITS)) { + mac->current_ifs_val = 0; + mac->in_ifs_mode = 0; + ew32(AIT, 0); + } + } +} + +/** + * e1000_raise_eec_clk - Raise EEPROM clock + * @hw: pointer to the HW structure + * @eecd: pointer to the EEPROM + * + * Enable/Raise the EEPROM clock bit. + **/ +static void e1000_raise_eec_clk(struct e1000_hw *hw, u32 *eecd) +{ + *eecd = *eecd | E1000_EECD_SK; + ew32(EECD, *eecd); + e1e_flush(); + udelay(hw->nvm.delay_usec); +} + +/** + * e1000_lower_eec_clk - Lower EEPROM clock + * @hw: pointer to the HW structure + * @eecd: pointer to the EEPROM + * + * Clear/Lower the EEPROM clock bit. + **/ +static void e1000_lower_eec_clk(struct e1000_hw *hw, u32 *eecd) +{ + *eecd = *eecd & ~E1000_EECD_SK; + ew32(EECD, *eecd); + e1e_flush(); + udelay(hw->nvm.delay_usec); +} + +/** + * e1000_shift_out_eec_bits - Shift data bits our to the EEPROM + * @hw: pointer to the HW structure + * @data: data to send to the EEPROM + * @count: number of bits to shift out + * + * We need to shift 'count' bits out to the EEPROM. So, the value in the + * "data" parameter will be shifted out to the EEPROM one bit at a time. + * In order to do this, "data" must be broken down into bits. + **/ +static void e1000_shift_out_eec_bits(struct e1000_hw *hw, u16 data, u16 count) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + u32 eecd = er32(EECD); + u32 mask; + + mask = 0x01 << (count - 1); + if (nvm->type == e1000_nvm_eeprom_spi) + eecd |= E1000_EECD_DO; + + do { + eecd &= ~E1000_EECD_DI; + + if (data & mask) + eecd |= E1000_EECD_DI; + + ew32(EECD, eecd); + e1e_flush(); + + udelay(nvm->delay_usec); + + e1000_raise_eec_clk(hw, &eecd); + e1000_lower_eec_clk(hw, &eecd); + + mask >>= 1; + } while (mask); + + eecd &= ~E1000_EECD_DI; + ew32(EECD, eecd); +} + +/** + * e1000_shift_in_eec_bits - Shift data bits in from the EEPROM + * @hw: pointer to the HW structure + * @count: number of bits to shift in + * + * In order to read a register from the EEPROM, we need to shift 'count' bits + * in from the EEPROM. Bits are "shifted in" by raising the clock input to + * the EEPROM (setting the SK bit), and then reading the value of the data out + * "DO" bit. During this "shifting in" process the data in "DI" bit should + * always be clear. + **/ +static u16 e1000_shift_in_eec_bits(struct e1000_hw *hw, u16 count) +{ + u32 eecd; + u32 i; + u16 data; + + eecd = er32(EECD); + + eecd &= ~(E1000_EECD_DO | E1000_EECD_DI); + data = 0; + + for (i = 0; i < count; i++) { + data <<= 1; + e1000_raise_eec_clk(hw, &eecd); + + eecd = er32(EECD); + + eecd &= ~E1000_EECD_DI; + if (eecd & E1000_EECD_DO) + data |= 1; + + e1000_lower_eec_clk(hw, &eecd); + } + + return data; +} + +/** + * e1000e_poll_eerd_eewr_done - Poll for EEPROM read/write completion + * @hw: pointer to the HW structure + * @ee_reg: EEPROM flag for polling + * + * Polls the EEPROM status bit for either read or write completion based + * upon the value of 'ee_reg'. + **/ +s32 e1000e_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg) +{ + u32 attempts = 100000; + u32 i, reg = 0; + + for (i = 0; i < attempts; i++) { + if (ee_reg == E1000_NVM_POLL_READ) + reg = er32(EERD); + else + reg = er32(EEWR); + + if (reg & E1000_NVM_RW_REG_DONE) + return 0; + + udelay(5); + } + + return -E1000_ERR_NVM; +} + +/** + * e1000e_acquire_nvm - Generic request for access to EEPROM + * @hw: pointer to the HW structure + * + * Set the EEPROM access request bit and wait for EEPROM access grant bit. + * Return successful if access grant bit set, else clear the request for + * EEPROM access and return -E1000_ERR_NVM (-1). + **/ +s32 e1000e_acquire_nvm(struct e1000_hw *hw) +{ + u32 eecd = er32(EECD); + s32 timeout = E1000_NVM_GRANT_ATTEMPTS; + + ew32(EECD, eecd | E1000_EECD_REQ); + eecd = er32(EECD); + + while (timeout) { + if (eecd & E1000_EECD_GNT) + break; + udelay(5); + eecd = er32(EECD); + timeout--; + } + + if (!timeout) { + eecd &= ~E1000_EECD_REQ; + ew32(EECD, eecd); + hw_dbg(hw, "Could not acquire NVM grant\n"); + return -E1000_ERR_NVM; + } + + return 0; +} + +/** + * e1000_standby_nvm - Return EEPROM to standby state + * @hw: pointer to the HW structure + * + * Return the EEPROM to a standby state. + **/ +static void e1000_standby_nvm(struct e1000_hw *hw) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + u32 eecd = er32(EECD); + + if (nvm->type == e1000_nvm_eeprom_spi) { + /* Toggle CS to flush commands */ + eecd |= E1000_EECD_CS; + ew32(EECD, eecd); + e1e_flush(); + udelay(nvm->delay_usec); + eecd &= ~E1000_EECD_CS; + ew32(EECD, eecd); + e1e_flush(); + udelay(nvm->delay_usec); + } +} + +/** + * e1000_stop_nvm - Terminate EEPROM command + * @hw: pointer to the HW structure + * + * Terminates the current command by inverting the EEPROM's chip select pin. + **/ +static void e1000_stop_nvm(struct e1000_hw *hw) +{ + u32 eecd; + + eecd = er32(EECD); + if (hw->nvm.type == e1000_nvm_eeprom_spi) { + /* Pull CS high */ + eecd |= E1000_EECD_CS; + e1000_lower_eec_clk(hw, &eecd); + } +} + +/** + * e1000e_release_nvm - Release exclusive access to EEPROM + * @hw: pointer to the HW structure + * + * Stop any current commands to the EEPROM and clear the EEPROM request bit. + **/ +void e1000e_release_nvm(struct e1000_hw *hw) +{ + u32 eecd; + + e1000_stop_nvm(hw); + + eecd = er32(EECD); + eecd &= ~E1000_EECD_REQ; + ew32(EECD, eecd); +} + +/** + * e1000_ready_nvm_eeprom - Prepares EEPROM for read/write + * @hw: pointer to the HW structure + * + * Setups the EEPROM for reading and writing. + **/ +static s32 e1000_ready_nvm_eeprom(struct e1000_hw *hw) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + u32 eecd = er32(EECD); + u16 timeout = 0; + u8 spi_stat_reg; + + if (nvm->type == e1000_nvm_eeprom_spi) { + /* Clear SK and CS */ + eecd &= ~(E1000_EECD_CS | E1000_EECD_SK); + ew32(EECD, eecd); + udelay(1); + timeout = NVM_MAX_RETRY_SPI; + + /* Read "Status Register" repeatedly until the LSB is cleared. + * The EEPROM will signal that the command has been completed + * by clearing bit 0 of the internal status register. If it's + * not cleared within 'timeout', then error out. */ + while (timeout) { + e1000_shift_out_eec_bits(hw, NVM_RDSR_OPCODE_SPI, + hw->nvm.opcode_bits); + spi_stat_reg = (u8)e1000_shift_in_eec_bits(hw, 8); + if (!(spi_stat_reg & NVM_STATUS_RDY_SPI)) + break; + + udelay(5); + e1000_standby_nvm(hw); + timeout--; + } + + if (!timeout) { + hw_dbg(hw, "SPI NVM Status error\n"); + return -E1000_ERR_NVM; + } + } + + return 0; +} + +/** + * e1000e_read_nvm_spi - Read EEPROM's using SPI + * @hw: pointer to the HW structure + * @offset: offset of word in the EEPROM to read + * @words: number of words to read + * @data: word read from the EEPROM + * + * Reads a 16 bit word from the EEPROM. + **/ +s32 e1000e_read_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + u32 i = 0; + s32 ret_val; + u16 word_in; + u8 read_opcode = NVM_READ_OPCODE_SPI; + + /* A check for invalid values: offset too large, too many words, + * and not enough words. */ + if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) || + (words == 0)) { + hw_dbg(hw, "nvm parameter(s) out of bounds\n"); + return -E1000_ERR_NVM; + } + + ret_val = nvm->ops.acquire_nvm(hw); + if (ret_val) + return ret_val; + + ret_val = e1000_ready_nvm_eeprom(hw); + if (ret_val) { + nvm->ops.release_nvm(hw); + return ret_val; + } + + e1000_standby_nvm(hw); + + if ((nvm->address_bits == 8) && (offset >= 128)) + read_opcode |= NVM_A8_OPCODE_SPI; + + /* Send the READ command (opcode + addr) */ + e1000_shift_out_eec_bits(hw, read_opcode, nvm->opcode_bits); + e1000_shift_out_eec_bits(hw, (u16)(offset*2), nvm->address_bits); + + /* Read the data. SPI NVMs increment the address with each byte + * read and will roll over if reading beyond the end. This allows + * us to read the whole NVM from any offset */ + for (i = 0; i < words; i++) { + word_in = e1000_shift_in_eec_bits(hw, 16); + data[i] = (word_in >> 8) | (word_in << 8); + } + + nvm->ops.release_nvm(hw); + return 0; +} + +/** + * e1000e_read_nvm_eerd - Reads EEPROM using EERD register + * @hw: pointer to the HW structure + * @offset: offset of word in the EEPROM to read + * @words: number of words to read + * @data: word read from the EEPROM + * + * Reads a 16 bit word from the EEPROM using the EERD register. + **/ +s32 e1000e_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + u32 i, eerd = 0; + s32 ret_val = 0; + + /* A check for invalid values: offset too large, too many words, + * and not enough words. */ + if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) || + (words == 0)) { + hw_dbg(hw, "nvm parameter(s) out of bounds\n"); + return -E1000_ERR_NVM; + } + + for (i = 0; i < words; i++) { + eerd = ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) + + E1000_NVM_RW_REG_START; + + ew32(EERD, eerd); + ret_val = e1000e_poll_eerd_eewr_done(hw, E1000_NVM_POLL_READ); + if (ret_val) + break; + + data[i] = (er32(EERD) >> + E1000_NVM_RW_REG_DATA); + } + + return ret_val; +} + +/** + * e1000e_write_nvm_spi - Write to EEPROM using SPI + * @hw: pointer to the HW structure + * @offset: offset within the EEPROM to be written to + * @words: number of words to write + * @data: 16 bit word(s) to be written to the EEPROM + * + * Writes data to EEPROM at offset using SPI interface. + * + * If e1000e_update_nvm_checksum is not called after this function , the + * EEPROM will most likley contain an invalid checksum. + **/ +s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + s32 ret_val; + u16 widx = 0; + + /* A check for invalid values: offset too large, too many words, + * and not enough words. */ + if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) || + (words == 0)) { + hw_dbg(hw, "nvm parameter(s) out of bounds\n"); + return -E1000_ERR_NVM; + } + + ret_val = nvm->ops.acquire_nvm(hw); + if (ret_val) + return ret_val; + + msleep(10); + + while (widx < words) { + u8 write_opcode = NVM_WRITE_OPCODE_SPI; + + ret_val = e1000_ready_nvm_eeprom(hw); + if (ret_val) { + nvm->ops.release_nvm(hw); + return ret_val; + } + + e1000_standby_nvm(hw); + + /* Send the WRITE ENABLE command (8 bit opcode) */ + e1000_shift_out_eec_bits(hw, NVM_WREN_OPCODE_SPI, + nvm->opcode_bits); + + e1000_standby_nvm(hw); + + /* Some SPI eeproms use the 8th address bit embedded in the + * opcode */ + if ((nvm->address_bits == 8) && (offset >= 128)) + write_opcode |= NVM_A8_OPCODE_SPI; + + /* Send the Write command (8-bit opcode + addr) */ + e1000_shift_out_eec_bits(hw, write_opcode, nvm->opcode_bits); + e1000_shift_out_eec_bits(hw, (u16)((offset + widx) * 2), + nvm->address_bits); + + /* Loop to allow for up to whole page write of eeprom */ + while (widx < words) { + u16 word_out = data[widx]; + word_out = (word_out >> 8) | (word_out << 8); + e1000_shift_out_eec_bits(hw, word_out, 16); + widx++; + + if ((((offset + widx) * 2) % nvm->page_size) == 0) { + e1000_standby_nvm(hw); + break; + } + } + } + + msleep(10); + return 0; +} + +/** + * e1000e_read_mac_addr - Read device MAC address + * @hw: pointer to the HW structure + * + * Reads the device MAC address from the EEPROM and stores the value. + * Since devices with two ports use the same EEPROM, we increment the + * last bit in the MAC address for the second port. + **/ +s32 e1000e_read_mac_addr(struct e1000_hw *hw) +{ + s32 ret_val; + u16 offset, nvm_data, i; + + for (i = 0; i < ETH_ALEN; i += 2) { + offset = i >> 1; + ret_val = e1000_read_nvm(hw, offset, 1, &nvm_data); + if (ret_val) { + hw_dbg(hw, "NVM Read Error\n"); + return ret_val; + } + hw->mac.perm_addr[i] = (u8)(nvm_data & 0xFF); + hw->mac.perm_addr[i+1] = (u8)(nvm_data >> 8); + } + + /* Flip last bit of mac address if we're on second port */ + if (hw->bus.func == E1000_FUNC_1) + hw->mac.perm_addr[5] ^= 1; + + for (i = 0; i < ETH_ALEN; i++) + hw->mac.addr[i] = hw->mac.perm_addr[i]; + + return 0; +} + +/** + * e1000e_validate_nvm_checksum_generic - Validate EEPROM checksum + * @hw: pointer to the HW structure + * + * Calculates the EEPROM checksum by reading/adding each word of the EEPROM + * and then verifies that the sum of the EEPROM is equal to 0xBABA. + **/ +s32 e1000e_validate_nvm_checksum_generic(struct e1000_hw *hw) +{ + s32 ret_val; + u16 checksum = 0; + u16 i, nvm_data; + + for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) { + ret_val = e1000_read_nvm(hw, i, 1, &nvm_data); + if (ret_val) { + hw_dbg(hw, "NVM Read Error\n"); + return ret_val; + } + checksum += nvm_data; + } + + if (checksum != (u16) NVM_SUM) { + hw_dbg(hw, "NVM Checksum Invalid\n"); + return -E1000_ERR_NVM; + } + + return 0; +} + +/** + * e1000e_update_nvm_checksum_generic - Update EEPROM checksum + * @hw: pointer to the HW structure + * + * Updates the EEPROM checksum by reading/adding each word of the EEPROM + * up to the checksum. Then calculates the EEPROM checksum and writes the + * value to the EEPROM. + **/ +s32 e1000e_update_nvm_checksum_generic(struct e1000_hw *hw) +{ + s32 ret_val; + u16 checksum = 0; + u16 i, nvm_data; + + for (i = 0; i < NVM_CHECKSUM_REG; i++) { + ret_val = e1000_read_nvm(hw, i, 1, &nvm_data); + if (ret_val) { + hw_dbg(hw, "NVM Read Error while updating checksum.\n"); + return ret_val; + } + checksum += nvm_data; + } + checksum = (u16) NVM_SUM - checksum; + ret_val = e1000_write_nvm(hw, NVM_CHECKSUM_REG, 1, &checksum); + if (ret_val) + hw_dbg(hw, "NVM Write Error while updating checksum.\n"); + + return ret_val; +} + +/** + * e1000e_reload_nvm - Reloads EEPROM + * @hw: pointer to the HW structure + * + * Reloads the EEPROM by setting the "Reinitialize from EEPROM" bit in the + * extended control register. + **/ +void e1000e_reload_nvm(struct e1000_hw *hw) +{ + u32 ctrl_ext; + + udelay(10); + ctrl_ext = er32(CTRL_EXT); + ctrl_ext |= E1000_CTRL_EXT_EE_RST; + ew32(CTRL_EXT, ctrl_ext); + e1e_flush(); +} + +/** + * e1000_calculate_checksum - Calculate checksum for buffer + * @buffer: pointer to EEPROM + * @length: size of EEPROM to calculate a checksum for + * + * Calculates the checksum for some buffer on a specified length. The + * checksum calculated is returned. + **/ +static u8 e1000_calculate_checksum(u8 *buffer, u32 length) +{ + u32 i; + u8 sum = 0; + + if (!buffer) + return 0; + + for (i = 0; i < length; i++) + sum += buffer[i]; + + return (u8) (0 - sum); +} + +/** + * e1000_mng_enable_host_if - Checks host interface is enabled + * @hw: pointer to the HW structure + * + * Returns E1000_success upon success, else E1000_ERR_HOST_INTERFACE_COMMAND + * + * This function checks whether the HOST IF is enabled for command operaton + * and also checks whether the previous command is completed. It busy waits + * in case of previous command is not completed. + **/ +static s32 e1000_mng_enable_host_if(struct e1000_hw *hw) +{ + u32 hicr; + u8 i; + + /* Check that the host interface is enabled. */ + hicr = er32(HICR); + if ((hicr & E1000_HICR_EN) == 0) { + hw_dbg(hw, "E1000_HOST_EN bit disabled.\n"); + return -E1000_ERR_HOST_INTERFACE_COMMAND; + } + /* check the previous command is completed */ + for (i = 0; i < E1000_MNG_DHCP_COMMAND_TIMEOUT; i++) { + hicr = er32(HICR); + if (!(hicr & E1000_HICR_C)) + break; + mdelay(1); + } + + if (i == E1000_MNG_DHCP_COMMAND_TIMEOUT) { + hw_dbg(hw, "Previous command timeout failed .\n"); + return -E1000_ERR_HOST_INTERFACE_COMMAND; + } + + return 0; +} + +/** + * e1000e_check_mng_mode - check managament mode + * @hw: pointer to the HW structure + * + * Reads the firmware semaphore register and returns true (>0) if + * manageability is enabled, else false (0). + **/ +bool e1000e_check_mng_mode(struct e1000_hw *hw) +{ + u32 fwsm = er32(FWSM); + + return (fwsm & E1000_FWSM_MODE_MASK) == hw->mac.ops.mng_mode_enab; +} + +/** + * e1000e_enable_tx_pkt_filtering - Enable packet filtering on TX + * @hw: pointer to the HW structure + * + * Enables packet filtering on transmit packets if manageability is enabled + * and host interface is enabled. + **/ +bool e1000e_enable_tx_pkt_filtering(struct e1000_hw *hw) +{ + struct e1000_host_mng_dhcp_cookie *hdr = &hw->mng_cookie; + u32 *buffer = (u32 *)&hw->mng_cookie; + u32 offset; + s32 ret_val, hdr_csum, csum; + u8 i, len; + + /* No manageability, no filtering */ + if (!e1000e_check_mng_mode(hw)) { + hw->mac.tx_pkt_filtering = 0; + return 0; + } + + /* If we can't read from the host interface for whatever + * reason, disable filtering. + */ + ret_val = e1000_mng_enable_host_if(hw); + if (ret_val != 0) { + hw->mac.tx_pkt_filtering = 0; + return ret_val; + } + + /* Read in the header. Length and offset are in dwords. */ + len = E1000_MNG_DHCP_COOKIE_LENGTH >> 2; + offset = E1000_MNG_DHCP_COOKIE_OFFSET >> 2; + for (i = 0; i < len; i++) + *(buffer + i) = E1000_READ_REG_ARRAY(hw, E1000_HOST_IF, offset + i); + hdr_csum = hdr->checksum; + hdr->checksum = 0; + csum = e1000_calculate_checksum((u8 *)hdr, + E1000_MNG_DHCP_COOKIE_LENGTH); + /* If either the checksums or signature don't match, then + * the cookie area isn't considered valid, in which case we + * take the safe route of assuming Tx filtering is enabled. + */ + if ((hdr_csum != csum) || (hdr->signature != E1000_IAMT_SIGNATURE)) { + hw->mac.tx_pkt_filtering = 1; + return 1; + } + + /* Cookie area is valid, make the final check for filtering. */ + if (!(hdr->status & E1000_MNG_DHCP_COOKIE_STATUS_PARSING)) { + hw->mac.tx_pkt_filtering = 0; + return 0; + } + + hw->mac.tx_pkt_filtering = 1; + return 1; +} + +/** + * e1000_mng_write_cmd_header - Writes manageability command header + * @hw: pointer to the HW structure + * @hdr: pointer to the host interface command header + * + * Writes the command header after does the checksum calculation. + **/ +static s32 e1000_mng_write_cmd_header(struct e1000_hw *hw, + struct e1000_host_mng_command_header *hdr) +{ + u16 i, length = sizeof(struct e1000_host_mng_command_header); + + /* Write the whole command header structure with new checksum. */ + + hdr->checksum = e1000_calculate_checksum((u8 *)hdr, length); + + length >>= 2; + /* Write the relevant command block into the ram area. */ + for (i = 0; i < length; i++) { + E1000_WRITE_REG_ARRAY(hw, E1000_HOST_IF, i, + *((u32 *) hdr + i)); + e1e_flush(); + } + + return 0; +} + +/** + * e1000_mng_host_if_write - Writes to the manageability host interface + * @hw: pointer to the HW structure + * @buffer: pointer to the host interface buffer + * @length: size of the buffer + * @offset: location in the buffer to write to + * @sum: sum of the data (not checksum) + * + * This function writes the buffer content at the offset given on the host if. + * It also does alignment considerations to do the writes in most efficient + * way. Also fills up the sum of the buffer in *buffer parameter. + **/ +static s32 e1000_mng_host_if_write(struct e1000_hw *hw, u8 *buffer, + u16 length, u16 offset, u8 *sum) +{ + u8 *tmp; + u8 *bufptr = buffer; + u32 data = 0; + u16 remaining, i, j, prev_bytes; + + /* sum = only sum of the data and it is not checksum */ + + if (length == 0 || offset + length > E1000_HI_MAX_MNG_DATA_LENGTH) + return -E1000_ERR_PARAM; + + tmp = (u8 *)&data; + prev_bytes = offset & 0x3; + offset >>= 2; + + if (prev_bytes) { + data = E1000_READ_REG_ARRAY(hw, E1000_HOST_IF, offset); + for (j = prev_bytes; j < sizeof(u32); j++) { + *(tmp + j) = *bufptr++; + *sum += *(tmp + j); + } + E1000_WRITE_REG_ARRAY(hw, E1000_HOST_IF, offset, data); + length -= j - prev_bytes; + offset++; + } + + remaining = length & 0x3; + length -= remaining; + + /* Calculate length in DWORDs */ + length >>= 2; + + /* The device driver writes the relevant command block into the + * ram area. */ + for (i = 0; i < length; i++) { + for (j = 0; j < sizeof(u32); j++) { + *(tmp + j) = *bufptr++; + *sum += *(tmp + j); + } + + E1000_WRITE_REG_ARRAY(hw, E1000_HOST_IF, offset + i, data); + } + if (remaining) { + for (j = 0; j < sizeof(u32); j++) { + if (j < remaining) + *(tmp + j) = *bufptr++; + else + *(tmp + j) = 0; + + *sum += *(tmp + j); + } + E1000_WRITE_REG_ARRAY(hw, E1000_HOST_IF, offset + i, data); + } + + return 0; +} + +/** + * e1000e_mng_write_dhcp_info - Writes DHCP info to host interface + * @hw: pointer to the HW structure + * @buffer: pointer to the host interface + * @length: size of the buffer + * + * Writes the DHCP information to the host interface. + **/ +s32 e1000e_mng_write_dhcp_info(struct e1000_hw *hw, u8 *buffer, u16 length) +{ + struct e1000_host_mng_command_header hdr; + s32 ret_val; + u32 hicr; + + hdr.command_id = E1000_MNG_DHCP_TX_PAYLOAD_CMD; + hdr.command_length = length; + hdr.reserved1 = 0; + hdr.reserved2 = 0; + hdr.checksum = 0; + + /* Enable the host interface */ + ret_val = e1000_mng_enable_host_if(hw); + if (ret_val) + return ret_val; + + /* Populate the host interface with the contents of "buffer". */ + ret_val = e1000_mng_host_if_write(hw, buffer, length, + sizeof(hdr), &(hdr.checksum)); + if (ret_val) + return ret_val; + + /* Write the manageability command header */ + ret_val = e1000_mng_write_cmd_header(hw, &hdr); + if (ret_val) + return ret_val; + + /* Tell the ARC a new command is pending. */ + hicr = er32(HICR); + ew32(HICR, hicr | E1000_HICR_C); + + return 0; +} + +/** + * e1000e_enable_mng_pass_thru - Enable processing of ARP's + * @hw: pointer to the HW structure + * + * Verifies the hardware needs to allow ARPs to be processed by the host. + **/ +bool e1000e_enable_mng_pass_thru(struct e1000_hw *hw) +{ + u32 manc; + u32 fwsm, factps; + bool ret_val = 0; + + manc = er32(MANC); + + if (!(manc & E1000_MANC_RCV_TCO_EN) || + !(manc & E1000_MANC_EN_MAC_ADDR_FILTER)) + return ret_val; + + if (hw->mac.arc_subsystem_valid) { + fwsm = er32(FWSM); + factps = er32(FACTPS); + + if (!(factps & E1000_FACTPS_MNGCG) && + ((fwsm & E1000_FWSM_MODE_MASK) == + (e1000_mng_mode_pt << E1000_FWSM_MODE_SHIFT))) { + ret_val = 1; + return ret_val; + } + } else { + if ((manc & E1000_MANC_SMBUS_EN) && + !(manc & E1000_MANC_ASF_EN)) { + ret_val = 1; + return ret_val; + } + } + + return ret_val; +} + +s32 e1000e_read_part_num(struct e1000_hw *hw, u32 *part_num) +{ + s32 ret_val; + u16 nvm_data; + + ret_val = e1000_read_nvm(hw, NVM_PBA_OFFSET_0, 1, &nvm_data); + if (ret_val) { + hw_dbg(hw, "NVM Read Error\n"); + return ret_val; + } + *part_num = (u32)(nvm_data << 16); + + ret_val = e1000_read_nvm(hw, NVM_PBA_OFFSET_1, 1, &nvm_data); + if (ret_val) { + hw_dbg(hw, "NVM Read Error\n"); + return ret_val; + } + *part_num |= nvm_data; + + return 0; +} diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c new file mode 100644 index 00000000000..eeb40ccbcb2 --- /dev/null +++ b/drivers/net/e1000e/netdev.c @@ -0,0 +1,4441 @@ +/******************************************************************************* + + Intel PRO/1000 Linux driver + Copyright(c) 1999 - 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "e1000.h" + +#define DRV_VERSION "0.2.0" +char e1000e_driver_name[] = "e1000e"; +const char e1000e_driver_version[] = DRV_VERSION; + +static const struct e1000_info *e1000_info_tbl[] = { + [board_82571] = &e1000_82571_info, + [board_82572] = &e1000_82572_info, + [board_82573] = &e1000_82573_info, + [board_80003es2lan] = &e1000_es2_info, + [board_ich8lan] = &e1000_ich8_info, + [board_ich9lan] = &e1000_ich9_info, +}; + +#ifdef DEBUG +/** + * e1000_get_hw_dev_name - return device name string + * used by hardware layer to print debugging information + **/ +char *e1000e_get_hw_dev_name(struct e1000_hw *hw) +{ + struct e1000_adapter *adapter = hw->back; + struct net_device *netdev = adapter->netdev; + return netdev->name; +} +#endif + +/** + * e1000_desc_unused - calculate if we have unused descriptors + **/ +static int e1000_desc_unused(struct e1000_ring *ring) +{ + if (ring->next_to_clean > ring->next_to_use) + return ring->next_to_clean - ring->next_to_use - 1; + + return ring->count + ring->next_to_clean - ring->next_to_use - 1; +} + +/** + * e1000_receive_skb - helper function to handle rx indications + * @adapter: board private structure + * @status: descriptor status field as written by hardware + * @vlan: descriptor vlan field as written by hardware (no le/be conversion) + * @skb: pointer to sk_buff to be indicated to stack + **/ +static void e1000_receive_skb(struct e1000_adapter *adapter, + struct net_device *netdev, + struct sk_buff *skb, + u8 status, u16 vlan) +{ + skb->protocol = eth_type_trans(skb, netdev); + + if (adapter->vlgrp && (status & E1000_RXD_STAT_VP)) + vlan_hwaccel_receive_skb(skb, adapter->vlgrp, + le16_to_cpu(vlan) & + E1000_RXD_SPC_VLAN_MASK); + else + netif_receive_skb(skb); + + netdev->last_rx = jiffies; +} + +/** + * e1000_rx_checksum - Receive Checksum Offload for 82543 + * @adapter: board private structure + * @status_err: receive descriptor status and error fields + * @csum: receive descriptor csum field + * @sk_buff: socket buffer with received data + **/ +static void e1000_rx_checksum(struct e1000_adapter *adapter, u32 status_err, + u32 csum, struct sk_buff *skb) +{ + u16 status = (u16)status_err; + u8 errors = (u8)(status_err >> 24); + skb->ip_summed = CHECKSUM_NONE; + + /* Ignore Checksum bit is set */ + if (status & E1000_RXD_STAT_IXSM) + return; + /* TCP/UDP checksum error bit is set */ + if (errors & E1000_RXD_ERR_TCPE) { + /* let the stack verify checksum errors */ + adapter->hw_csum_err++; + return; + } + + /* TCP/UDP Checksum has not been calculated */ + if (!(status & (E1000_RXD_STAT_TCPCS | E1000_RXD_STAT_UDPCS))) + return; + + /* It must be a TCP or UDP packet with a valid checksum */ + if (status & E1000_RXD_STAT_TCPCS) { + /* TCP checksum is good */ + skb->ip_summed = CHECKSUM_UNNECESSARY; + } else { + /* IP fragment with UDP payload */ + /* Hardware complements the payload checksum, so we undo it + * and then put the value in host order for further stack use. + */ + csum = ntohl(csum ^ 0xFFFF); + skb->csum = csum; + skb->ip_summed = CHECKSUM_COMPLETE; + } + adapter->hw_csum_good++; +} + +/** + * e1000_alloc_rx_buffers - Replace used receive buffers; legacy & extended + * @adapter: address of board private structure + **/ +static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter, + int cleaned_count) +{ + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + struct e1000_ring *rx_ring = adapter->rx_ring; + struct e1000_rx_desc *rx_desc; + struct e1000_buffer *buffer_info; + struct sk_buff *skb; + unsigned int i; + unsigned int bufsz = adapter->rx_buffer_len + NET_IP_ALIGN; + + i = rx_ring->next_to_use; + buffer_info = &rx_ring->buffer_info[i]; + + while (cleaned_count--) { + skb = buffer_info->skb; + if (skb) { + skb_trim(skb, 0); + goto map_skb; + } + + skb = netdev_alloc_skb(netdev, bufsz); + if (!skb) { + /* Better luck next round */ + adapter->alloc_rx_buff_failed++; + break; + } + + /* Make buffer alignment 2 beyond a 16 byte boundary + * this will result in a 16 byte aligned IP header after + * the 14 byte MAC header is removed + */ + skb_reserve(skb, NET_IP_ALIGN); + + buffer_info->skb = skb; +map_skb: + buffer_info->dma = pci_map_single(pdev, skb->data, + adapter->rx_buffer_len, + PCI_DMA_FROMDEVICE); + if (pci_dma_mapping_error(buffer_info->dma)) { + dev_err(&pdev->dev, "RX DMA map failed\n"); + adapter->rx_dma_failed++; + break; + } + + rx_desc = E1000_RX_DESC(*rx_ring, i); + rx_desc->buffer_addr = cpu_to_le64(buffer_info->dma); + + i++; + if (i == rx_ring->count) + i = 0; + buffer_info = &rx_ring->buffer_info[i]; + } + + if (rx_ring->next_to_use != i) { + rx_ring->next_to_use = i; + if (i-- == 0) + i = (rx_ring->count - 1); + + /* Force memory writes to complete before letting h/w + * know there are new descriptors to fetch. (Only + * applicable for weak-ordered memory model archs, + * such as IA-64). */ + wmb(); + writel(i, adapter->hw.hw_addr + rx_ring->tail); + } +} + +/** + * e1000_alloc_rx_buffers_ps - Replace used receive buffers; packet split + * @adapter: address of board private structure + **/ +static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter, + int cleaned_count) +{ + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + union e1000_rx_desc_packet_split *rx_desc; + struct e1000_ring *rx_ring = adapter->rx_ring; + struct e1000_buffer *buffer_info; + struct e1000_ps_page *ps_page; + struct sk_buff *skb; + unsigned int i, j; + + i = rx_ring->next_to_use; + buffer_info = &rx_ring->buffer_info[i]; + + while (cleaned_count--) { + rx_desc = E1000_RX_DESC_PS(*rx_ring, i); + + for (j = 0; j < PS_PAGE_BUFFERS; j++) { + ps_page = &rx_ring->ps_pages[(i * PS_PAGE_BUFFERS) + + j]; + if (j < adapter->rx_ps_pages) { + if (!ps_page->page) { + ps_page->page = alloc_page(GFP_ATOMIC); + if (!ps_page->page) { + adapter->alloc_rx_buff_failed++; + goto no_buffers; + } + ps_page->dma = pci_map_page(pdev, + ps_page->page, + 0, PAGE_SIZE, + PCI_DMA_FROMDEVICE); + if (pci_dma_mapping_error( + ps_page->dma)) { + dev_err(&adapter->pdev->dev, + "RX DMA page map failed\n"); + adapter->rx_dma_failed++; + goto no_buffers; + } + } + /* + * Refresh the desc even if buffer_addrs + * didn't change because each write-back + * erases this info. + */ + rx_desc->read.buffer_addr[j+1] = + cpu_to_le64(ps_page->dma); + } else { + rx_desc->read.buffer_addr[j+1] = ~0; + } + } + + skb = netdev_alloc_skb(netdev, + adapter->rx_ps_bsize0 + NET_IP_ALIGN); + + if (!skb) { + adapter->alloc_rx_buff_failed++; + break; + } + + /* Make buffer alignment 2 beyond a 16 byte boundary + * this will result in a 16 byte aligned IP header after + * the 14 byte MAC header is removed + */ + skb_reserve(skb, NET_IP_ALIGN); + + buffer_info->skb = skb; + buffer_info->dma = pci_map_single(pdev, skb->data, + adapter->rx_ps_bsize0, + PCI_DMA_FROMDEVICE); + if (pci_dma_mapping_error(buffer_info->dma)) { + dev_err(&pdev->dev, "RX DMA map failed\n"); + adapter->rx_dma_failed++; + /* cleanup skb */ + dev_kfree_skb_any(skb); + buffer_info->skb = NULL; + break; + } + + rx_desc->read.buffer_addr[0] = cpu_to_le64(buffer_info->dma); + + i++; + if (i == rx_ring->count) + i = 0; + buffer_info = &rx_ring->buffer_info[i]; + } + +no_buffers: + if (rx_ring->next_to_use != i) { + rx_ring->next_to_use = i; + + if (!(i--)) + i = (rx_ring->count - 1); + + /* Force memory writes to complete before letting h/w + * know there are new descriptors to fetch. (Only + * applicable for weak-ordered memory model archs, + * such as IA-64). */ + wmb(); + /* Hardware increments by 16 bytes, but packet split + * descriptors are 32 bytes...so we increment tail + * twice as much. + */ + writel(i<<1, adapter->hw.hw_addr + rx_ring->tail); + } +} + +/** + * e1000_alloc_rx_buffers_jumbo - Replace used jumbo receive buffers + * + * @adapter: address of board private structure + * @cleaned_count: number of buffers to allocate this pass + **/ +static void e1000_alloc_rx_buffers_jumbo(struct e1000_adapter *adapter, + int cleaned_count) +{ + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + struct e1000_ring *rx_ring = adapter->rx_ring; + struct e1000_rx_desc *rx_desc; + struct e1000_buffer *buffer_info; + struct sk_buff *skb; + unsigned int i; + unsigned int bufsz = 256 - + 16 /*for skb_reserve */ - + NET_IP_ALIGN; + + i = rx_ring->next_to_use; + buffer_info = &rx_ring->buffer_info[i]; + + while (cleaned_count--) { + skb = buffer_info->skb; + if (skb) { + skb_trim(skb, 0); + goto check_page; + } + + skb = netdev_alloc_skb(netdev, bufsz); + if (!skb) { + /* Better luck next round */ + adapter->alloc_rx_buff_failed++; + break; + } + + /* Make buffer alignment 2 beyond a 16 byte boundary + * this will result in a 16 byte aligned IP header after + * the 14 byte MAC header is removed + */ + skb_reserve(skb, NET_IP_ALIGN); + + buffer_info->skb = skb; +check_page: + /* allocate a new page if necessary */ + if (!buffer_info->page) { + buffer_info->page = alloc_page(GFP_ATOMIC); + if (!buffer_info->page) { + adapter->alloc_rx_buff_failed++; + break; + } + } + + if (!buffer_info->dma) + buffer_info->dma = pci_map_page(pdev, + buffer_info->page, 0, + PAGE_SIZE, + PCI_DMA_FROMDEVICE); + if (pci_dma_mapping_error(buffer_info->dma)) { + dev_err(&adapter->pdev->dev, "RX DMA page map failed\n"); + adapter->rx_dma_failed++; + break; + } + + rx_desc = E1000_RX_DESC(*rx_ring, i); + rx_desc->buffer_addr = cpu_to_le64(buffer_info->dma); + + i++; + if (i == rx_ring->count) + i = 0; + buffer_info = &rx_ring->buffer_info[i]; + } + + if (rx_ring->next_to_use != i) { + rx_ring->next_to_use = i; + if (i-- == 0) + i = (rx_ring->count - 1); + + /* Force memory writes to complete before letting h/w + * know there are new descriptors to fetch. (Only + * applicable for weak-ordered memory model archs, + * such as IA-64). */ + wmb(); + writel(i, adapter->hw.hw_addr + rx_ring->tail); + } +} + +/** + * e1000_clean_rx_irq - Send received data up the network stack; legacy + * @adapter: board private structure + * + * the return value indicates whether actual cleaning was done, there + * is no guarantee that everything was cleaned + **/ +static bool e1000_clean_rx_irq(struct e1000_adapter *adapter, + int *work_done, int work_to_do) +{ + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + struct e1000_ring *rx_ring = adapter->rx_ring; + struct e1000_rx_desc *rx_desc, *next_rxd; + struct e1000_buffer *buffer_info, *next_buffer; + u32 length; + unsigned int i; + int cleaned_count = 0; + bool cleaned = 0; + unsigned int total_rx_bytes = 0, total_rx_packets = 0; + + i = rx_ring->next_to_clean; + rx_desc = E1000_RX_DESC(*rx_ring, i); + buffer_info = &rx_ring->buffer_info[i]; + + while (rx_desc->status & E1000_RXD_STAT_DD) { + struct sk_buff *skb; + u8 status; + + if (*work_done >= work_to_do) + break; + (*work_done)++; + + status = rx_desc->status; + skb = buffer_info->skb; + buffer_info->skb = NULL; + + prefetch(skb->data - NET_IP_ALIGN); + + i++; + if (i == rx_ring->count) + i = 0; + next_rxd = E1000_RX_DESC(*rx_ring, i); + prefetch(next_rxd); + + next_buffer = &rx_ring->buffer_info[i]; + + cleaned = 1; + cleaned_count++; + pci_unmap_single(pdev, + buffer_info->dma, + adapter->rx_buffer_len, + PCI_DMA_FROMDEVICE); + buffer_info->dma = 0; + + length = le16_to_cpu(rx_desc->length); + + /* !EOP means multiple descriptors were used to store a single + * packet, also make sure the frame isn't just CRC only */ + if (!(status & E1000_RXD_STAT_EOP) || (length <= 4)) { + /* All receives must fit into a single buffer */ + ndev_dbg(netdev, "%s: Receive packet consumed " + "multiple buffers\n", netdev->name); + /* recycle */ + buffer_info->skb = skb; + goto next_desc; + } + + if (rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK) { + /* recycle */ + buffer_info->skb = skb; + goto next_desc; + } + + /* adjust length to remove Ethernet CRC */ + length -= 4; + + /* probably a little skewed due to removing CRC */ + total_rx_bytes += length; + total_rx_packets++; + + /* code added for copybreak, this should improve + * performance for small packets with large amounts + * of reassembly being done in the stack */ + if (length < copybreak) { + struct sk_buff *new_skb = + netdev_alloc_skb(netdev, length + NET_IP_ALIGN); + if (new_skb) { + skb_reserve(new_skb, NET_IP_ALIGN); + memcpy(new_skb->data - NET_IP_ALIGN, + skb->data - NET_IP_ALIGN, + length + NET_IP_ALIGN); + /* save the skb in buffer_info as good */ + buffer_info->skb = skb; + skb = new_skb; + } + /* else just continue with the old one */ + } + /* end copybreak code */ + skb_put(skb, length); + + /* Receive Checksum Offload */ + e1000_rx_checksum(adapter, + (u32)(status) | + ((u32)(rx_desc->errors) << 24), + le16_to_cpu(rx_desc->csum), skb); + + e1000_receive_skb(adapter, netdev, skb,status,rx_desc->special); + +next_desc: + rx_desc->status = 0; + + /* return some buffers to hardware, one at a time is too slow */ + if (cleaned_count >= E1000_RX_BUFFER_WRITE) { + adapter->alloc_rx_buf(adapter, cleaned_count); + cleaned_count = 0; + } + + /* use prefetched values */ + rx_desc = next_rxd; + buffer_info = next_buffer; + } + rx_ring->next_to_clean = i; + + cleaned_count = e1000_desc_unused(rx_ring); + if (cleaned_count) + adapter->alloc_rx_buf(adapter, cleaned_count); + + adapter->total_rx_packets += total_rx_packets; + adapter->total_rx_bytes += total_rx_bytes; + return cleaned; +} + +static void e1000_consume_page(struct e1000_buffer *bi, struct sk_buff *skb, + u16 length) +{ + bi->page = NULL; + skb->len += length; + skb->data_len += length; + skb->truesize += length; +} + +static void e1000_put_txbuf(struct e1000_adapter *adapter, + struct e1000_buffer *buffer_info) +{ + if (buffer_info->dma) { + pci_unmap_page(adapter->pdev, buffer_info->dma, + buffer_info->length, PCI_DMA_TODEVICE); + buffer_info->dma = 0; + } + if (buffer_info->skb) { + dev_kfree_skb_any(buffer_info->skb); + buffer_info->skb = NULL; + } +} + +static void e1000_print_tx_hang(struct e1000_adapter *adapter) +{ + struct e1000_ring *tx_ring = adapter->tx_ring; + unsigned int i = tx_ring->next_to_clean; + unsigned int eop = tx_ring->buffer_info[i].next_to_watch; + struct e1000_tx_desc *eop_desc = E1000_TX_DESC(*tx_ring, eop); + struct net_device *netdev = adapter->netdev; + + /* detected Tx unit hang */ + ndev_err(netdev, + "Detected Tx Unit Hang:\n" + " TDH <%x>\n" + " TDT <%x>\n" + " next_to_use <%x>\n" + " next_to_clean <%x>\n" + "buffer_info[next_to_clean]:\n" + " time_stamp <%lx>\n" + " next_to_watch <%x>\n" + " jiffies <%lx>\n" + " next_to_watch.status <%x>\n", + readl(adapter->hw.hw_addr + tx_ring->head), + readl(adapter->hw.hw_addr + tx_ring->tail), + tx_ring->next_to_use, + tx_ring->next_to_clean, + tx_ring->buffer_info[eop].time_stamp, + eop, + jiffies, + eop_desc->upper.fields.status); +} + +/** + * e1000_clean_tx_irq - Reclaim resources after transmit completes + * @adapter: board private structure + * + * the return value indicates whether actual cleaning was done, there + * is no guarantee that everything was cleaned + **/ +static bool e1000_clean_tx_irq(struct e1000_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + struct e1000_hw *hw = &adapter->hw; + struct e1000_ring *tx_ring = adapter->tx_ring; + struct e1000_tx_desc *tx_desc, *eop_desc; + struct e1000_buffer *buffer_info; + unsigned int i, eop; + unsigned int count = 0; + bool cleaned = 0; + unsigned int total_tx_bytes = 0, total_tx_packets = 0; + + i = tx_ring->next_to_clean; + eop = tx_ring->buffer_info[i].next_to_watch; + eop_desc = E1000_TX_DESC(*tx_ring, eop); + + while (eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) { + for (cleaned = 0; !cleaned; ) { + tx_desc = E1000_TX_DESC(*tx_ring, i); + buffer_info = &tx_ring->buffer_info[i]; + cleaned = (i == eop); + + if (cleaned) { + struct sk_buff *skb = buffer_info->skb; + unsigned int segs, bytecount; + segs = skb_shinfo(skb)->gso_segs ?: 1; + /* multiply data chunks by size of headers */ + bytecount = ((segs - 1) * skb_headlen(skb)) + + skb->len; + total_tx_packets += segs; + total_tx_bytes += bytecount; + } + + e1000_put_txbuf(adapter, buffer_info); + tx_desc->upper.data = 0; + + i++; + if (i == tx_ring->count) + i = 0; + } + + eop = tx_ring->buffer_info[i].next_to_watch; + eop_desc = E1000_TX_DESC(*tx_ring, eop); +#define E1000_TX_WEIGHT 64 + /* weight of a sort for tx, to avoid endless transmit cleanup */ + if (count++ == E1000_TX_WEIGHT) + break; + } + + tx_ring->next_to_clean = i; + +#define TX_WAKE_THRESHOLD 32 + if (cleaned && netif_carrier_ok(netdev) && + e1000_desc_unused(tx_ring) >= TX_WAKE_THRESHOLD) { + /* Make sure that anybody stopping the queue after this + * sees the new next_to_clean. + */ + smp_mb(); + + if (netif_queue_stopped(netdev) && + !(test_bit(__E1000_DOWN, &adapter->state))) { + netif_wake_queue(netdev); + ++adapter->restart_queue; + } + } + + if (adapter->detect_tx_hung) { + /* Detect a transmit hang in hardware, this serializes the + * check with the clearing of time_stamp and movement of i */ + adapter->detect_tx_hung = 0; + if (tx_ring->buffer_info[eop].dma && + time_after(jiffies, tx_ring->buffer_info[eop].time_stamp + + (adapter->tx_timeout_factor * HZ)) + && !(er32(STATUS) & + E1000_STATUS_TXOFF)) { + e1000_print_tx_hang(adapter); + netif_stop_queue(netdev); + } + } + adapter->total_tx_bytes += total_tx_bytes; + adapter->total_tx_packets += total_tx_packets; + return cleaned; +} + +/** + * e1000_clean_rx_irq_jumbo - Send received data up the network stack; legacy + * @adapter: board private structure + * + * the return value indicates whether actual cleaning was done, there + * is no guarantee that everything was cleaned + **/ +static bool e1000_clean_rx_irq_jumbo(struct e1000_adapter *adapter, + int *work_done, int work_to_do) +{ + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + struct e1000_ring *rx_ring = adapter->rx_ring; + struct e1000_rx_desc *rx_desc, *next_rxd; + struct e1000_buffer *buffer_info, *next_buffer; + u32 length; + unsigned int i; + int cleaned_count = 0; + bool cleaned = 0; + unsigned int total_rx_bytes = 0, total_rx_packets = 0; + + i = rx_ring->next_to_clean; + rx_desc = E1000_RX_DESC(*rx_ring, i); + buffer_info = &rx_ring->buffer_info[i]; + + while (rx_desc->status & E1000_RXD_STAT_DD) { + struct sk_buff *skb; + u8 status; + + if (*work_done >= work_to_do) + break; + (*work_done)++; + + status = rx_desc->status; + skb = buffer_info->skb; + buffer_info->skb = NULL; + + i++; + if (i == rx_ring->count) + i = 0; + next_rxd = E1000_RX_DESC(*rx_ring, i); + prefetch(next_rxd); + + next_buffer = &rx_ring->buffer_info[i]; + + cleaned = 1; + cleaned_count++; + pci_unmap_page(pdev, + buffer_info->dma, + PAGE_SIZE, + PCI_DMA_FROMDEVICE); + buffer_info->dma = 0; + + length = le16_to_cpu(rx_desc->length); + + /* errors is only valid for DD + EOP descriptors */ + if ((status & E1000_RXD_STAT_EOP) && + (rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK)) { + /* recycle both page and skb */ + buffer_info->skb = skb; + /* an error means any chain goes out the window too */ + if (rx_ring->rx_skb_top) + dev_kfree_skb(rx_ring->rx_skb_top); + rx_ring->rx_skb_top = NULL; + goto next_desc; + } + +#define rxtop rx_ring->rx_skb_top + if (!(status & E1000_RXD_STAT_EOP)) { + /* this descriptor is only the beginning (or middle) */ + if (!rxtop) { + /* this is the beginning of a chain */ + rxtop = skb; + skb_fill_page_desc(rxtop, 0, buffer_info->page, + 0, length); + } else { + /* this is the middle of a chain */ + skb_fill_page_desc(rxtop, + skb_shinfo(rxtop)->nr_frags, + buffer_info->page, 0, + length); + /* re-use the skb, only consumed the page */ + buffer_info->skb = skb; + } + e1000_consume_page(buffer_info, rxtop, length); + goto next_desc; + } else { + if (rxtop) { + /* end of the chain */ + skb_fill_page_desc(rxtop, + skb_shinfo(rxtop)->nr_frags, + buffer_info->page, 0, length); + /* re-use the current skb, we only consumed the + * page */ + buffer_info->skb = skb; + skb = rxtop; + rxtop = NULL; + e1000_consume_page(buffer_info, skb, length); + } else { + /* no chain, got EOP, this buf is the packet + * copybreak to save the put_page/alloc_page */ + if (length <= copybreak && + skb_tailroom(skb) >= length) { + u8 *vaddr; + vaddr = kmap_atomic(buffer_info->page, + KM_SKB_DATA_SOFTIRQ); + memcpy(skb_tail_pointer(skb), + vaddr, length); + kunmap_atomic(vaddr, + KM_SKB_DATA_SOFTIRQ); + /* re-use the page, so don't erase + * buffer_info->page */ + skb_put(skb, length); + } else { + skb_fill_page_desc(skb, 0, + buffer_info->page, 0, + length); + e1000_consume_page(buffer_info, skb, + length); + } + } + } + + /* Receive Checksum Offload XXX recompute due to CRC strip? */ + e1000_rx_checksum(adapter, + (u32)(status) | + ((u32)(rx_desc->errors) << 24), + le16_to_cpu(rx_desc->csum), skb); + + pskb_trim(skb, skb->len - 4); + + /* probably a little skewed due to removing CRC */ + total_rx_bytes += skb->len; + total_rx_packets++; + + /* eth type trans needs skb->data to point to something */ + if (!pskb_may_pull(skb, ETH_HLEN)) { + ndev_err(netdev, "__pskb_pull_tail failed.\n"); + dev_kfree_skb(skb); + goto next_desc; + } + + e1000_receive_skb(adapter, netdev, skb,status,rx_desc->special); + +next_desc: + rx_desc->status = 0; + + /* return some buffers to hardware, one at a time is too slow */ + if (cleaned_count >= E1000_RX_BUFFER_WRITE) { + adapter->alloc_rx_buf(adapter, cleaned_count); + cleaned_count = 0; + } + + /* use prefetched values */ + rx_desc = next_rxd; + buffer_info = next_buffer; + } + rx_ring->next_to_clean = i; + + cleaned_count = e1000_desc_unused(rx_ring); + if (cleaned_count) + adapter->alloc_rx_buf(adapter, cleaned_count); + + adapter->total_rx_packets += total_rx_packets; + adapter->total_rx_bytes += total_rx_bytes; + return cleaned; +} + +/** + * e1000_clean_rx_irq_ps - Send received data up the network stack; packet split + * @adapter: board private structure + * + * the return value indicates whether actual cleaning was done, there + * is no guarantee that everything was cleaned + **/ +static bool e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, + int *work_done, int work_to_do) +{ + union e1000_rx_desc_packet_split *rx_desc, *next_rxd; + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + struct e1000_ring *rx_ring = adapter->rx_ring; + struct e1000_buffer *buffer_info, *next_buffer; + struct e1000_ps_page *ps_page; + struct sk_buff *skb; + unsigned int i, j; + u32 length, staterr; + int cleaned_count = 0; + bool cleaned = 0; + unsigned int total_rx_bytes = 0, total_rx_packets = 0; + + i = rx_ring->next_to_clean; + rx_desc = E1000_RX_DESC_PS(*rx_ring, i); + staterr = le32_to_cpu(rx_desc->wb.middle.status_error); + buffer_info = &rx_ring->buffer_info[i]; + + while (staterr & E1000_RXD_STAT_DD) { + if (*work_done >= work_to_do) + break; + (*work_done)++; + skb = buffer_info->skb; + + /* in the packet split case this is header only */ + prefetch(skb->data - NET_IP_ALIGN); + + i++; + if (i == rx_ring->count) + i = 0; + next_rxd = E1000_RX_DESC_PS(*rx_ring, i); + prefetch(next_rxd); + + next_buffer = &rx_ring->buffer_info[i]; + + cleaned = 1; + cleaned_count++; + pci_unmap_single(pdev, buffer_info->dma, + adapter->rx_ps_bsize0, + PCI_DMA_FROMDEVICE); + buffer_info->dma = 0; + + if (!(staterr & E1000_RXD_STAT_EOP)) { + ndev_dbg(netdev, "%s: Packet Split buffers didn't pick " + "up the full packet\n", netdev->name); + dev_kfree_skb_irq(skb); + goto next_desc; + } + + if (staterr & E1000_RXDEXT_ERR_FRAME_ERR_MASK) { + dev_kfree_skb_irq(skb); + goto next_desc; + } + + length = le16_to_cpu(rx_desc->wb.middle.length0); + + if (!length) { + ndev_dbg(netdev, "%s: Last part of the packet spanning" + " multiple descriptors\n", netdev->name); + dev_kfree_skb_irq(skb); + goto next_desc; + } + + /* Good Receive */ + skb_put(skb, length); + + { + /* this looks ugly, but it seems compiler issues make it + more efficient than reusing j */ + int l1 = le16_to_cpu(rx_desc->wb.upper.length[0]); + + /* page alloc/put takes too long and effects small packet + * throughput, so unsplit small packets and save the alloc/put*/ + if (l1 && (l1 <= copybreak) && + ((length + l1) <= adapter->rx_ps_bsize0)) { + u8 *vaddr; + + ps_page = &rx_ring->ps_pages[i * PS_PAGE_BUFFERS]; + + /* there is no documentation about how to call + * kmap_atomic, so we can't hold the mapping + * very long */ + pci_dma_sync_single_for_cpu(pdev, ps_page->dma, + PAGE_SIZE, PCI_DMA_FROMDEVICE); + vaddr = kmap_atomic(ps_page->page, KM_SKB_DATA_SOFTIRQ); + memcpy(skb_tail_pointer(skb), vaddr, l1); + kunmap_atomic(vaddr, KM_SKB_DATA_SOFTIRQ); + pci_dma_sync_single_for_device(pdev, ps_page->dma, + PAGE_SIZE, PCI_DMA_FROMDEVICE); + /* remove the CRC */ + l1 -= 4; + skb_put(skb, l1); + goto copydone; + } /* if */ + } + + for (j = 0; j < PS_PAGE_BUFFERS; j++) { + length = le16_to_cpu(rx_desc->wb.upper.length[j]); + if (!length) + break; + + ps_page = &rx_ring->ps_pages[(i * PS_PAGE_BUFFERS) + j]; + pci_unmap_page(pdev, ps_page->dma, PAGE_SIZE, + PCI_DMA_FROMDEVICE); + ps_page->dma = 0; + skb_fill_page_desc(skb, j, ps_page->page, 0, length); + ps_page->page = NULL; + skb->len += length; + skb->data_len += length; + skb->truesize += length; + } + + /* strip the ethernet crc, problem is we're using pages now so + * this whole operation can get a little cpu intensive */ + pskb_trim(skb, skb->len - 4); + +copydone: + total_rx_bytes += skb->len; + total_rx_packets++; + + e1000_rx_checksum(adapter, staterr, le16_to_cpu( + rx_desc->wb.lower.hi_dword.csum_ip.csum), skb); + + if (rx_desc->wb.upper.header_status & + cpu_to_le16(E1000_RXDPS_HDRSTAT_HDRSP)) + adapter->rx_hdr_split++; + + e1000_receive_skb(adapter, netdev, skb, + staterr, rx_desc->wb.middle.vlan); + +next_desc: + rx_desc->wb.middle.status_error &= cpu_to_le32(~0xFF); + buffer_info->skb = NULL; + + /* return some buffers to hardware, one at a time is too slow */ + if (cleaned_count >= E1000_RX_BUFFER_WRITE) { + adapter->alloc_rx_buf(adapter, cleaned_count); + cleaned_count = 0; + } + + /* use prefetched values */ + rx_desc = next_rxd; + buffer_info = next_buffer; + + staterr = le32_to_cpu(rx_desc->wb.middle.status_error); + } + rx_ring->next_to_clean = i; + + cleaned_count = e1000_desc_unused(rx_ring); + if (cleaned_count) + adapter->alloc_rx_buf(adapter, cleaned_count); + + adapter->total_rx_packets += total_rx_packets; + adapter->total_rx_bytes += total_rx_bytes; + return cleaned; +} + +/** + * e1000_clean_rx_ring - Free Rx Buffers per Queue + * @adapter: board private structure + **/ +static void e1000_clean_rx_ring(struct e1000_adapter *adapter) +{ + struct e1000_ring *rx_ring = adapter->rx_ring; + struct e1000_buffer *buffer_info; + struct e1000_ps_page *ps_page; + struct pci_dev *pdev = adapter->pdev; + unsigned long size; + unsigned int i, j; + + /* Free all the Rx ring sk_buffs */ + for (i = 0; i < rx_ring->count; i++) { + buffer_info = &rx_ring->buffer_info[i]; + if (buffer_info->dma) { + if (adapter->clean_rx == e1000_clean_rx_irq) + pci_unmap_single(pdev, buffer_info->dma, + adapter->rx_buffer_len, + PCI_DMA_FROMDEVICE); + else if (adapter->clean_rx == e1000_clean_rx_irq_jumbo) + pci_unmap_page(pdev, buffer_info->dma, + PAGE_SIZE, PCI_DMA_FROMDEVICE); + else if (adapter->clean_rx == e1000_clean_rx_irq_ps) + pci_unmap_single(pdev, buffer_info->dma, + adapter->rx_ps_bsize0, + PCI_DMA_FROMDEVICE); + buffer_info->dma = 0; + } + + if (buffer_info->page) { + put_page(buffer_info->page); + buffer_info->page = NULL; + } + + if (buffer_info->skb) { + dev_kfree_skb(buffer_info->skb); + buffer_info->skb = NULL; + } + + for (j = 0; j < PS_PAGE_BUFFERS; j++) { + ps_page = &rx_ring->ps_pages[(i * PS_PAGE_BUFFERS) + + j]; + if (!ps_page->page) + break; + pci_unmap_page(pdev, ps_page->dma, PAGE_SIZE, + PCI_DMA_FROMDEVICE); + ps_page->dma = 0; + put_page(ps_page->page); + ps_page->page = NULL; + } + } + + /* there also may be some cached data from a chained receive */ + if (rx_ring->rx_skb_top) { + dev_kfree_skb(rx_ring->rx_skb_top); + rx_ring->rx_skb_top = NULL; + } + + size = sizeof(struct e1000_buffer) * rx_ring->count; + memset(rx_ring->buffer_info, 0, size); + size = sizeof(struct e1000_ps_page) + * (rx_ring->count * PS_PAGE_BUFFERS); + memset(rx_ring->ps_pages, 0, size); + + /* Zero out the descriptor ring */ + memset(rx_ring->desc, 0, rx_ring->size); + + rx_ring->next_to_clean = 0; + rx_ring->next_to_use = 0; + + writel(0, adapter->hw.hw_addr + rx_ring->head); + writel(0, adapter->hw.hw_addr + rx_ring->tail); +} + +/** + * e1000_intr_msi - Interrupt Handler + * @irq: interrupt number + * @data: pointer to a network interface device structure + **/ +static irqreturn_t e1000_intr_msi(int irq, void *data) +{ + struct net_device *netdev = data; + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + u32 icr = er32(ICR); + + /* read ICR disables interrupts using IAM, so keep up with our + * enable/disable accounting */ + atomic_inc(&adapter->irq_sem); + + if (icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { + hw->mac.get_link_status = 1; + /* ICH8 workaround-- Call gig speed drop workaround on cable + * disconnect (LSC) before accessing any PHY registers */ + if ((adapter->flags & FLAG_LSC_GIG_SPEED_DROP) && + (!(er32(STATUS) & E1000_STATUS_LU))) + e1000e_gig_downshift_workaround_ich8lan(hw); + + /* 80003ES2LAN workaround-- For packet buffer work-around on + * link down event; disable receives here in the ISR and reset + * adapter in watchdog */ + if (netif_carrier_ok(netdev) && + adapter->flags & FLAG_RX_NEEDS_RESTART) { + /* disable receives */ + u32 rctl = er32(RCTL); + ew32(RCTL, rctl & ~E1000_RCTL_EN); + } + /* guard against interrupt when we're going down */ + if (!test_bit(__E1000_DOWN, &adapter->state)) + mod_timer(&adapter->watchdog_timer, jiffies + 1); + } + + if (netif_rx_schedule_prep(netdev, &adapter->napi)) { + adapter->total_tx_bytes = 0; + adapter->total_tx_packets = 0; + adapter->total_rx_bytes = 0; + adapter->total_rx_packets = 0; + __netif_rx_schedule(netdev, &adapter->napi); + } else { + atomic_dec(&adapter->irq_sem); + } + + return IRQ_HANDLED; +} + +/** + * e1000_intr - Interrupt Handler + * @irq: interrupt number + * @data: pointer to a network interface device structure + **/ +static irqreturn_t e1000_intr(int irq, void *data) +{ + struct net_device *netdev = data; + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + + u32 rctl, icr = er32(ICR); + if (!icr) + return IRQ_NONE; /* Not our interrupt */ + + /* IMS will not auto-mask if INT_ASSERTED is not set, and if it is + * not set, then the adapter didn't send an interrupt */ + if (!(icr & E1000_ICR_INT_ASSERTED)) + return IRQ_NONE; + + /* Interrupt Auto-Mask...upon reading ICR, + * interrupts are masked. No need for the + * IMC write, but it does mean we should + * account for it ASAP. */ + atomic_inc(&adapter->irq_sem); + + if (icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { + hw->mac.get_link_status = 1; + /* ICH8 workaround-- Call gig speed drop workaround on cable + * disconnect (LSC) before accessing any PHY registers */ + if ((adapter->flags & FLAG_LSC_GIG_SPEED_DROP) && + (!(er32(STATUS) & E1000_STATUS_LU))) + e1000e_gig_downshift_workaround_ich8lan(hw); + + /* 80003ES2LAN workaround-- + * For packet buffer work-around on link down event; + * disable receives here in the ISR and + * reset adapter in watchdog + */ + if (netif_carrier_ok(netdev) && + (adapter->flags & FLAG_RX_NEEDS_RESTART)) { + /* disable receives */ + rctl = er32(RCTL); + ew32(RCTL, rctl & ~E1000_RCTL_EN); + } + /* guard against interrupt when we're going down */ + if (!test_bit(__E1000_DOWN, &adapter->state)) + mod_timer(&adapter->watchdog_timer, jiffies + 1); + } + + if (netif_rx_schedule_prep(netdev, &adapter->napi)) { + adapter->total_tx_bytes = 0; + adapter->total_tx_packets = 0; + adapter->total_rx_bytes = 0; + adapter->total_rx_packets = 0; + __netif_rx_schedule(netdev, &adapter->napi); + } else { + atomic_dec(&adapter->irq_sem); + } + + return IRQ_HANDLED; +} + +static int e1000_request_irq(struct e1000_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + void (*handler) = &e1000_intr; + int irq_flags = IRQF_SHARED; + int err; + + err = pci_enable_msi(adapter->pdev); + if (err) { + ndev_warn(netdev, + "Unable to allocate MSI interrupt Error: %d\n", err); + } else { + adapter->flags |= FLAG_MSI_ENABLED; + handler = &e1000_intr_msi; + irq_flags = 0; + } + + err = request_irq(adapter->pdev->irq, handler, irq_flags, netdev->name, + netdev); + if (err) { + if (adapter->flags & FLAG_MSI_ENABLED) + pci_disable_msi(adapter->pdev); + ndev_err(netdev, + "Unable to allocate interrupt Error: %d\n", err); + } + + return err; +} + +static void e1000_free_irq(struct e1000_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + + free_irq(adapter->pdev->irq, netdev); + if (adapter->flags & FLAG_MSI_ENABLED) { + pci_disable_msi(adapter->pdev); + adapter->flags &= ~FLAG_MSI_ENABLED; + } +} + +/** + * e1000_irq_disable - Mask off interrupt generation on the NIC + **/ +static void e1000_irq_disable(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + + atomic_inc(&adapter->irq_sem); + ew32(IMC, ~0); + e1e_flush(); + synchronize_irq(adapter->pdev->irq); +} + +/** + * e1000_irq_enable - Enable default interrupt generation settings + **/ +static void e1000_irq_enable(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + + if (atomic_dec_and_test(&adapter->irq_sem)) { + ew32(IMS, IMS_ENABLE_MASK); + e1e_flush(); + } +} + +/** + * e1000_get_hw_control - get control of the h/w from f/w + * @adapter: address of board private structure + * + * e1000_get_hw_control sets {CTRL_EXT|FWSM}:DRV_LOAD bit. + * For ASF and Pass Through versions of f/w this means that + * the driver is loaded. For AMT version (only with 82573) + * of the f/w this means that the network i/f is open. + **/ +static void e1000_get_hw_control(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 ctrl_ext; + u32 swsm; + + /* Let firmware know the driver has taken over */ + if (adapter->flags & FLAG_HAS_SWSM_ON_LOAD) { + swsm = er32(SWSM); + ew32(SWSM, swsm | E1000_SWSM_DRV_LOAD); + } else if (adapter->flags & FLAG_HAS_CTRLEXT_ON_LOAD) { + ctrl_ext = er32(CTRL_EXT); + ew32(CTRL_EXT, + ctrl_ext | E1000_CTRL_EXT_DRV_LOAD); + } +} + +/** + * e1000_release_hw_control - release control of the h/w to f/w + * @adapter: address of board private structure + * + * e1000_release_hw_control resets {CTRL_EXT|FWSM}:DRV_LOAD bit. + * For ASF and Pass Through versions of f/w this means that the + * driver is no longer loaded. For AMT version (only with 82573) i + * of the f/w this means that the network i/f is closed. + * + **/ +static void e1000_release_hw_control(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 ctrl_ext; + u32 swsm; + + /* Let firmware taken over control of h/w */ + if (adapter->flags & FLAG_HAS_SWSM_ON_LOAD) { + swsm = er32(SWSM); + ew32(SWSM, swsm & ~E1000_SWSM_DRV_LOAD); + } else if (adapter->flags & FLAG_HAS_CTRLEXT_ON_LOAD) { + ctrl_ext = er32(CTRL_EXT); + ew32(CTRL_EXT, + ctrl_ext & ~E1000_CTRL_EXT_DRV_LOAD); + } +} + +static void e1000_release_manageability(struct e1000_adapter *adapter) +{ + if (adapter->flags & FLAG_MNG_PT_ENABLED) { + struct e1000_hw *hw = &adapter->hw; + + u32 manc = er32(MANC); + + /* re-enable hardware interception of ARP */ + manc |= E1000_MANC_ARP_EN; + manc &= ~E1000_MANC_EN_MNG2HOST; + + /* don't explicitly have to mess with MANC2H since + * MANC has an enable disable that gates MANC2H */ + ew32(MANC, manc); + } +} + +/** + * @e1000_alloc_ring - allocate memory for a ring structure + **/ +static int e1000_alloc_ring_dma(struct e1000_adapter *adapter, + struct e1000_ring *ring) +{ + struct pci_dev *pdev = adapter->pdev; + + ring->desc = dma_alloc_coherent(&pdev->dev, ring->size, &ring->dma, + GFP_KERNEL); + if (!ring->desc) + return -ENOMEM; + + return 0; +} + +/** + * e1000e_setup_tx_resources - allocate Tx resources (Descriptors) + * @adapter: board private structure + * + * Return 0 on success, negative on failure + **/ +int e1000e_setup_tx_resources(struct e1000_adapter *adapter) +{ + struct e1000_ring *tx_ring = adapter->tx_ring; + int err = -ENOMEM, size; + + size = sizeof(struct e1000_buffer) * tx_ring->count; + tx_ring->buffer_info = vmalloc(size); + if (!tx_ring->buffer_info) + goto err; + memset(tx_ring->buffer_info, 0, size); + + /* round up to nearest 4K */ + tx_ring->size = tx_ring->count * sizeof(struct e1000_tx_desc); + tx_ring->size = ALIGN(tx_ring->size, 4096); + + err = e1000_alloc_ring_dma(adapter, tx_ring); + if (err) + goto err; + + tx_ring->next_to_use = 0; + tx_ring->next_to_clean = 0; + spin_lock_init(&adapter->tx_queue_lock); + + return 0; +err: + vfree(tx_ring->buffer_info); + ndev_err(adapter->netdev, + "Unable to allocate memory for the transmit descriptor ring\n"); + return err; +} + +/** + * e1000e_setup_rx_resources - allocate Rx resources (Descriptors) + * @adapter: board private structure + * + * Returns 0 on success, negative on failure + **/ +int e1000e_setup_rx_resources(struct e1000_adapter *adapter) +{ + struct e1000_ring *rx_ring = adapter->rx_ring; + int size, desc_len, err = -ENOMEM; + + size = sizeof(struct e1000_buffer) * rx_ring->count; + rx_ring->buffer_info = vmalloc(size); + if (!rx_ring->buffer_info) + goto err; + memset(rx_ring->buffer_info, 0, size); + + rx_ring->ps_pages = kcalloc(rx_ring->count * PS_PAGE_BUFFERS, + sizeof(struct e1000_ps_page), + GFP_KERNEL); + if (!rx_ring->ps_pages) + goto err; + + desc_len = sizeof(union e1000_rx_desc_packet_split); + + /* Round up to nearest 4K */ + rx_ring->size = rx_ring->count * desc_len; + rx_ring->size = ALIGN(rx_ring->size, 4096); + + err = e1000_alloc_ring_dma(adapter, rx_ring); + if (err) + goto err; + + rx_ring->next_to_clean = 0; + rx_ring->next_to_use = 0; + rx_ring->rx_skb_top = NULL; + + return 0; +err: + vfree(rx_ring->buffer_info); + kfree(rx_ring->ps_pages); + ndev_err(adapter->netdev, + "Unable to allocate memory for the transmit descriptor ring\n"); + return err; +} + +/** + * e1000_clean_tx_ring - Free Tx Buffers + * @adapter: board private structure + **/ +static void e1000_clean_tx_ring(struct e1000_adapter *adapter) +{ + struct e1000_ring *tx_ring = adapter->tx_ring; + struct e1000_buffer *buffer_info; + unsigned long size; + unsigned int i; + + for (i = 0; i < tx_ring->count; i++) { + buffer_info = &tx_ring->buffer_info[i]; + e1000_put_txbuf(adapter, buffer_info); + } + + size = sizeof(struct e1000_buffer) * tx_ring->count; + memset(tx_ring->buffer_info, 0, size); + + memset(tx_ring->desc, 0, tx_ring->size); + + tx_ring->next_to_use = 0; + tx_ring->next_to_clean = 0; + + writel(0, adapter->hw.hw_addr + tx_ring->head); + writel(0, adapter->hw.hw_addr + tx_ring->tail); +} + +/** + * e1000e_free_tx_resources - Free Tx Resources per Queue + * @adapter: board private structure + * + * Free all transmit software resources + **/ +void e1000e_free_tx_resources(struct e1000_adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + struct e1000_ring *tx_ring = adapter->tx_ring; + + e1000_clean_tx_ring(adapter); + + vfree(tx_ring->buffer_info); + tx_ring->buffer_info = NULL; + + dma_free_coherent(&pdev->dev, tx_ring->size, tx_ring->desc, + tx_ring->dma); + tx_ring->desc = NULL; +} + +/** + * e1000e_free_rx_resources - Free Rx Resources + * @adapter: board private structure + * + * Free all receive software resources + **/ + +void e1000e_free_rx_resources(struct e1000_adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + struct e1000_ring *rx_ring = adapter->rx_ring; + + e1000_clean_rx_ring(adapter); + + vfree(rx_ring->buffer_info); + rx_ring->buffer_info = NULL; + + kfree(rx_ring->ps_pages); + rx_ring->ps_pages = NULL; + + dma_free_coherent(&pdev->dev, rx_ring->size, rx_ring->desc, + rx_ring->dma); + rx_ring->desc = NULL; +} + +/** + * e1000_update_itr - update the dynamic ITR value based on statistics + * Stores a new ITR value based on packets and byte + * counts during the last interrupt. The advantage of per interrupt + * computation is faster updates and more accurate ITR for the current + * traffic pattern. Constants in this function were computed + * based on theoretical maximum wire speed and thresholds were set based + * on testing data as well as attempting to minimize response time + * while increasing bulk throughput. + * this functionality is controlled by the InterruptThrottleRate module + * parameter (see e1000_param.c) + * @adapter: pointer to adapter + * @itr_setting: current adapter->itr + * @packets: the number of packets during this measurement interval + * @bytes: the number of bytes during this measurement interval + **/ +static unsigned int e1000_update_itr(struct e1000_adapter *adapter, + u16 itr_setting, int packets, + int bytes) +{ + unsigned int retval = itr_setting; + + if (packets == 0) + goto update_itr_done; + + switch (itr_setting) { + case lowest_latency: + /* handle TSO and jumbo frames */ + if (bytes/packets > 8000) + retval = bulk_latency; + else if ((packets < 5) && (bytes > 512)) { + retval = low_latency; + } + break; + case low_latency: /* 50 usec aka 20000 ints/s */ + if (bytes > 10000) { + /* this if handles the TSO accounting */ + if (bytes/packets > 8000) { + retval = bulk_latency; + } else if ((packets < 10) || ((bytes/packets) > 1200)) { + retval = bulk_latency; + } else if ((packets > 35)) { + retval = lowest_latency; + } + } else if (bytes/packets > 2000) { + retval = bulk_latency; + } else if (packets <= 2 && bytes < 512) { + retval = lowest_latency; + } + break; + case bulk_latency: /* 250 usec aka 4000 ints/s */ + if (bytes > 25000) { + if (packets > 35) { + retval = low_latency; + } + } else if (bytes < 6000) { + retval = low_latency; + } + break; + } + +update_itr_done: + return retval; +} + +static void e1000_set_itr(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u16 current_itr; + u32 new_itr = adapter->itr; + + /* for non-gigabit speeds, just fix the interrupt rate at 4000 */ + if (adapter->link_speed != SPEED_1000) { + current_itr = 0; + new_itr = 4000; + goto set_itr_now; + } + + adapter->tx_itr = e1000_update_itr(adapter, + adapter->tx_itr, + adapter->total_tx_packets, + adapter->total_tx_bytes); + /* conservative mode (itr 3) eliminates the lowest_latency setting */ + if (adapter->itr_setting == 3 && adapter->tx_itr == lowest_latency) + adapter->tx_itr = low_latency; + + adapter->rx_itr = e1000_update_itr(adapter, + adapter->rx_itr, + adapter->total_rx_packets, + adapter->total_rx_bytes); + /* conservative mode (itr 3) eliminates the lowest_latency setting */ + if (adapter->itr_setting == 3 && adapter->rx_itr == lowest_latency) + adapter->rx_itr = low_latency; + + current_itr = max(adapter->rx_itr, adapter->tx_itr); + + switch (current_itr) { + /* counts and packets in update_itr are dependent on these numbers */ + case lowest_latency: + new_itr = 70000; + break; + case low_latency: + new_itr = 20000; /* aka hwitr = ~200 */ + break; + case bulk_latency: + new_itr = 4000; + break; + default: + break; + } + +set_itr_now: + if (new_itr != adapter->itr) { + /* this attempts to bias the interrupt rate towards Bulk + * by adding intermediate steps when interrupt rate is + * increasing */ + new_itr = new_itr > adapter->itr ? + min(adapter->itr + (new_itr >> 2), new_itr) : + new_itr; + adapter->itr = new_itr; + ew32(ITR, 1000000000 / (new_itr * 256)); + } +} + +/** + * e1000_clean - NAPI Rx polling callback + * @adapter: board private structure + **/ +static int e1000_clean(struct napi_struct *napi, int budget) +{ + struct e1000_adapter *adapter = container_of(napi, struct e1000_adapter, napi); + struct net_device *poll_dev = adapter->netdev; + int tx_cleaned = 0, work_done = 0; + + /* Must NOT use netdev_priv macro here. */ + adapter = poll_dev->priv; + + /* Keep link state information with original netdev */ + if (!netif_carrier_ok(poll_dev)) + goto quit_polling; + + /* e1000_clean is called per-cpu. This lock protects + * tx_ring from being cleaned by multiple cpus + * simultaneously. A failure obtaining the lock means + * tx_ring is currently being cleaned anyway. */ + if (spin_trylock(&adapter->tx_queue_lock)) { + tx_cleaned = e1000_clean_tx_irq(adapter); + spin_unlock(&adapter->tx_queue_lock); + } + + adapter->clean_rx(adapter, &work_done, budget); + + /* If no Tx and not enough Rx work done, exit the polling mode */ + if ((!tx_cleaned && (work_done < budget)) || + !netif_running(poll_dev)) { +quit_polling: + if (adapter->itr_setting & 3) + e1000_set_itr(adapter); + netif_rx_complete(poll_dev, napi); + e1000_irq_enable(adapter); + } + + return work_done; +} + +static void e1000_vlan_rx_add_vid(struct net_device *netdev, u16 vid) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + u32 vfta, index; + + /* don't update vlan cookie if already programmed */ + if ((adapter->hw.mng_cookie.status & + E1000_MNG_DHCP_COOKIE_STATUS_VLAN) && + (vid == adapter->mng_vlan_id)) + return; + /* add VID to filter table */ + index = (vid >> 5) & 0x7F; + vfta = E1000_READ_REG_ARRAY(hw, E1000_VFTA, index); + vfta |= (1 << (vid & 0x1F)); + e1000e_write_vfta(hw, index, vfta); +} + +static void e1000_vlan_rx_kill_vid(struct net_device *netdev, u16 vid) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + u32 vfta, index; + + e1000_irq_disable(adapter); + vlan_group_set_device(adapter->vlgrp, vid, NULL); + e1000_irq_enable(adapter); + + if ((adapter->hw.mng_cookie.status & + E1000_MNG_DHCP_COOKIE_STATUS_VLAN) && + (vid == adapter->mng_vlan_id)) { + /* release control to f/w */ + e1000_release_hw_control(adapter); + return; + } + + /* remove VID from filter table */ + index = (vid >> 5) & 0x7F; + vfta = E1000_READ_REG_ARRAY(hw, E1000_VFTA, index); + vfta &= ~(1 << (vid & 0x1F)); + e1000e_write_vfta(hw, index, vfta); +} + +static void e1000_update_mng_vlan(struct e1000_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + u16 vid = adapter->hw.mng_cookie.vlan_id; + u16 old_vid = adapter->mng_vlan_id; + + if (!adapter->vlgrp) + return; + + if (!vlan_group_get_device(adapter->vlgrp, vid)) { + adapter->mng_vlan_id = E1000_MNG_VLAN_NONE; + if (adapter->hw.mng_cookie.status & + E1000_MNG_DHCP_COOKIE_STATUS_VLAN) { + e1000_vlan_rx_add_vid(netdev, vid); + adapter->mng_vlan_id = vid; + } + + if ((old_vid != (u16)E1000_MNG_VLAN_NONE) && + (vid != old_vid) && + !vlan_group_get_device(adapter->vlgrp, old_vid)) + e1000_vlan_rx_kill_vid(netdev, old_vid); + } else { + adapter->mng_vlan_id = vid; + } +} + + +static void e1000_vlan_rx_register(struct net_device *netdev, + struct vlan_group *grp) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + u32 ctrl, rctl; + + e1000_irq_disable(adapter); + adapter->vlgrp = grp; + + if (grp) { + /* enable VLAN tag insert/strip */ + ctrl = er32(CTRL); + ctrl |= E1000_CTRL_VME; + ew32(CTRL, ctrl); + + if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER) { + /* enable VLAN receive filtering */ + rctl = er32(RCTL); + rctl |= E1000_RCTL_VFE; + rctl &= ~E1000_RCTL_CFIEN; + ew32(RCTL, rctl); + e1000_update_mng_vlan(adapter); + } + } else { + /* disable VLAN tag insert/strip */ + ctrl = er32(CTRL); + ctrl &= ~E1000_CTRL_VME; + ew32(CTRL, ctrl); + + if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER) { + /* disable VLAN filtering */ + rctl = er32(RCTL); + rctl &= ~E1000_RCTL_VFE; + ew32(RCTL, rctl); + if (adapter->mng_vlan_id != + (u16)E1000_MNG_VLAN_NONE) { + e1000_vlan_rx_kill_vid(netdev, + adapter->mng_vlan_id); + adapter->mng_vlan_id = E1000_MNG_VLAN_NONE; + } + } + } + + e1000_irq_enable(adapter); +} + +static void e1000_restore_vlan(struct e1000_adapter *adapter) +{ + u16 vid; + + e1000_vlan_rx_register(adapter->netdev, adapter->vlgrp); + + if (!adapter->vlgrp) + return; + + for (vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) { + if (!vlan_group_get_device(adapter->vlgrp, vid)) + continue; + e1000_vlan_rx_add_vid(adapter->netdev, vid); + } +} + +static void e1000_init_manageability(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 manc, manc2h; + + if (!(adapter->flags & FLAG_MNG_PT_ENABLED)) + return; + + manc = er32(MANC); + + /* disable hardware interception of ARP */ + manc &= ~(E1000_MANC_ARP_EN); + + /* enable receiving management packets to the host. this will probably + * generate destination unreachable messages from the host OS, but + * the packets will be handled on SMBUS */ + manc |= E1000_MANC_EN_MNG2HOST; + manc2h = er32(MANC2H); +#define E1000_MNG2HOST_PORT_623 (1 << 5) +#define E1000_MNG2HOST_PORT_664 (1 << 6) + manc2h |= E1000_MNG2HOST_PORT_623; + manc2h |= E1000_MNG2HOST_PORT_664; + ew32(MANC2H, manc2h); + ew32(MANC, manc); +} + +/** + * e1000_configure_tx - Configure 8254x Transmit Unit after Reset + * @adapter: board private structure + * + * Configure the Tx unit of the MAC after a reset. + **/ +static void e1000_configure_tx(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + struct e1000_ring *tx_ring = adapter->tx_ring; + u64 tdba; + u32 tdlen, tctl, tipg, tarc; + u32 ipgr1, ipgr2; + + /* Setup the HW Tx Head and Tail descriptor pointers */ + tdba = tx_ring->dma; + tdlen = tx_ring->count * sizeof(struct e1000_tx_desc); + ew32(TDBAL, (tdba & DMA_32BIT_MASK)); + ew32(TDBAH, (tdba >> 32)); + ew32(TDLEN, tdlen); + ew32(TDH, 0); + ew32(TDT, 0); + tx_ring->head = E1000_TDH; + tx_ring->tail = E1000_TDT; + + /* Set the default values for the Tx Inter Packet Gap timer */ + tipg = DEFAULT_82543_TIPG_IPGT_COPPER; /* 8 */ + ipgr1 = DEFAULT_82543_TIPG_IPGR1; /* 8 */ + ipgr2 = DEFAULT_82543_TIPG_IPGR2; /* 6 */ + + if (adapter->flags & FLAG_TIPG_MEDIUM_FOR_80003ESLAN) + ipgr2 = DEFAULT_80003ES2LAN_TIPG_IPGR2; /* 7 */ + + tipg |= ipgr1 << E1000_TIPG_IPGR1_SHIFT; + tipg |= ipgr2 << E1000_TIPG_IPGR2_SHIFT; + ew32(TIPG, tipg); + + /* Set the Tx Interrupt Delay register */ + ew32(TIDV, adapter->tx_int_delay); + /* tx irq moderation */ + ew32(TADV, adapter->tx_abs_int_delay); + + /* Program the Transmit Control Register */ + tctl = er32(TCTL); + tctl &= ~E1000_TCTL_CT; + tctl |= E1000_TCTL_PSP | E1000_TCTL_RTLC | + (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT); + + if (adapter->flags & FLAG_TARC_SPEED_MODE_BIT) { + tarc = er32(TARC0); + /* set the speed mode bit, we'll clear it if we're not at + * gigabit link later */ +#define SPEED_MODE_BIT (1 << 21) + tarc |= SPEED_MODE_BIT; + ew32(TARC0, tarc); + } + + /* errata: program both queues to unweighted RR */ + if (adapter->flags & FLAG_TARC_SET_BIT_ZERO) { + tarc = er32(TARC0); + tarc |= 1; + ew32(TARC0, tarc); + tarc = er32(TARC1); + tarc |= 1; + ew32(TARC1, tarc); + } + + e1000e_config_collision_dist(hw); + + /* Setup Transmit Descriptor Settings for eop descriptor */ + adapter->txd_cmd = E1000_TXD_CMD_EOP | E1000_TXD_CMD_IFCS; + + /* only set IDE if we are delaying interrupts using the timers */ + if (adapter->tx_int_delay) + adapter->txd_cmd |= E1000_TXD_CMD_IDE; + + /* enable Report Status bit */ + adapter->txd_cmd |= E1000_TXD_CMD_RS; + + ew32(TCTL, tctl); + + adapter->tx_queue_len = adapter->netdev->tx_queue_len; +} + +/** + * e1000_setup_rctl - configure the receive control registers + * @adapter: Board private structure + **/ +#define PAGE_USE_COUNT(S) (((S) >> PAGE_SHIFT) + \ + (((S) & (PAGE_SIZE - 1)) ? 1 : 0)) +static void e1000_setup_rctl(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 rctl, rfctl; + u32 psrctl = 0; + u32 pages = 0; + + /* Program MC offset vector base */ + rctl = er32(RCTL); + rctl &= ~(3 << E1000_RCTL_MO_SHIFT); + rctl |= E1000_RCTL_EN | E1000_RCTL_BAM | + E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF | + (adapter->hw.mac.mc_filter_type << E1000_RCTL_MO_SHIFT); + + /* Do not Store bad packets */ + rctl &= ~E1000_RCTL_SBP; + + /* Enable Long Packet receive */ + if (adapter->netdev->mtu <= ETH_DATA_LEN) + rctl &= ~E1000_RCTL_LPE; + else + rctl |= E1000_RCTL_LPE; + + /* Setup buffer sizes */ + rctl &= ~E1000_RCTL_SZ_4096; + rctl |= E1000_RCTL_BSEX; + switch (adapter->rx_buffer_len) { + case 256: + rctl |= E1000_RCTL_SZ_256; + rctl &= ~E1000_RCTL_BSEX; + break; + case 512: + rctl |= E1000_RCTL_SZ_512; + rctl &= ~E1000_RCTL_BSEX; + break; + case 1024: + rctl |= E1000_RCTL_SZ_1024; + rctl &= ~E1000_RCTL_BSEX; + break; + case 2048: + default: + rctl |= E1000_RCTL_SZ_2048; + rctl &= ~E1000_RCTL_BSEX; + break; + case 4096: + rctl |= E1000_RCTL_SZ_4096; + break; + case 8192: + rctl |= E1000_RCTL_SZ_8192; + break; + case 16384: + rctl |= E1000_RCTL_SZ_16384; + break; + } + + /* + * 82571 and greater support packet-split where the protocol + * header is placed in skb->data and the packet data is + * placed in pages hanging off of skb_shinfo(skb)->nr_frags. + * In the case of a non-split, skb->data is linearly filled, + * followed by the page buffers. Therefore, skb->data is + * sized to hold the largest protocol header. + * + * allocations using alloc_page take too long for regular MTU + * so only enable packet split for jumbo frames + * + * Using pages when the page size is greater than 16k wastes + * a lot of memory, since we allocate 3 pages at all times + * per packet. + */ + adapter->rx_ps_pages = 0; + pages = PAGE_USE_COUNT(adapter->netdev->mtu); + if ((pages <= 3) && (PAGE_SIZE <= 16384) && (rctl & E1000_RCTL_LPE)) + adapter->rx_ps_pages = pages; + + if (adapter->rx_ps_pages) { + /* Configure extra packet-split registers */ + rfctl = er32(RFCTL); + rfctl |= E1000_RFCTL_EXTEN; + /* disable packet split support for IPv6 extension headers, + * because some malformed IPv6 headers can hang the RX */ + rfctl |= (E1000_RFCTL_IPV6_EX_DIS | + E1000_RFCTL_NEW_IPV6_EXT_DIS); + + ew32(RFCTL, rfctl); + + /* disable the stripping of CRC because it breaks + * BMC firmware connected over SMBUS */ + rctl |= E1000_RCTL_DTYP_PS /* | E1000_RCTL_SECRC */; + + psrctl |= adapter->rx_ps_bsize0 >> + E1000_PSRCTL_BSIZE0_SHIFT; + + switch (adapter->rx_ps_pages) { + case 3: + psrctl |= PAGE_SIZE << + E1000_PSRCTL_BSIZE3_SHIFT; + case 2: + psrctl |= PAGE_SIZE << + E1000_PSRCTL_BSIZE2_SHIFT; + case 1: + psrctl |= PAGE_SIZE >> + E1000_PSRCTL_BSIZE1_SHIFT; + break; + } + + ew32(PSRCTL, psrctl); + } + + ew32(RCTL, rctl); +} + +/** + * e1000_configure_rx - Configure Receive Unit after Reset + * @adapter: board private structure + * + * Configure the Rx unit of the MAC after a reset. + **/ +static void e1000_configure_rx(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + struct e1000_ring *rx_ring = adapter->rx_ring; + u64 rdba; + u32 rdlen, rctl, rxcsum, ctrl_ext; + + if (adapter->rx_ps_pages) { + /* this is a 32 byte descriptor */ + rdlen = rx_ring->count * + sizeof(union e1000_rx_desc_packet_split); + adapter->clean_rx = e1000_clean_rx_irq_ps; + adapter->alloc_rx_buf = e1000_alloc_rx_buffers_ps; + } else if (adapter->netdev->mtu > ETH_FRAME_LEN + VLAN_HLEN + 4) { + rdlen = rx_ring->count * + sizeof(struct e1000_rx_desc); + adapter->clean_rx = e1000_clean_rx_irq_jumbo; + adapter->alloc_rx_buf = e1000_alloc_rx_buffers_jumbo; + } else { + rdlen = rx_ring->count * + sizeof(struct e1000_rx_desc); + adapter->clean_rx = e1000_clean_rx_irq; + adapter->alloc_rx_buf = e1000_alloc_rx_buffers; + } + + /* disable receives while setting up the descriptors */ + rctl = er32(RCTL); + ew32(RCTL, rctl & ~E1000_RCTL_EN); + e1e_flush(); + msleep(10); + + /* set the Receive Delay Timer Register */ + ew32(RDTR, adapter->rx_int_delay); + + /* irq moderation */ + ew32(RADV, adapter->rx_abs_int_delay); + if (adapter->itr_setting != 0) + ew32(ITR, + 1000000000 / (adapter->itr * 256)); + + ctrl_ext = er32(CTRL_EXT); + /* Reset delay timers after every interrupt */ + ctrl_ext |= E1000_CTRL_EXT_INT_TIMER_CLR; + /* Auto-Mask interrupts upon ICR access */ + ctrl_ext |= E1000_CTRL_EXT_IAME; + ew32(IAM, 0xffffffff); + ew32(CTRL_EXT, ctrl_ext); + e1e_flush(); + + /* Setup the HW Rx Head and Tail Descriptor Pointers and + * the Base and Length of the Rx Descriptor Ring */ + rdba = rx_ring->dma; + ew32(RDBAL, (rdba & DMA_32BIT_MASK)); + ew32(RDBAH, (rdba >> 32)); + ew32(RDLEN, rdlen); + ew32(RDH, 0); + ew32(RDT, 0); + rx_ring->head = E1000_RDH; + rx_ring->tail = E1000_RDT; + + /* Enable Receive Checksum Offload for TCP and UDP */ + rxcsum = er32(RXCSUM); + if (adapter->flags & FLAG_RX_CSUM_ENABLED) { + rxcsum |= E1000_RXCSUM_TUOFL; + + /* IPv4 payload checksum for UDP fragments must be + * used in conjunction with packet-split. */ + if (adapter->rx_ps_pages) + rxcsum |= E1000_RXCSUM_IPPCSE; + } else { + rxcsum &= ~E1000_RXCSUM_TUOFL; + /* no need to clear IPPCSE as it defaults to 0 */ + } + ew32(RXCSUM, rxcsum); + + /* Enable early receives on supported devices, only takes effect when + * packet size is equal or larger than the specified value (in 8 byte + * units), e.g. using jumbo frames when setting to E1000_ERT_2048 */ + if ((adapter->flags & FLAG_HAS_ERT) && + (adapter->netdev->mtu > ETH_DATA_LEN)) + ew32(ERT, E1000_ERT_2048); + + /* Enable Receives */ + ew32(RCTL, rctl); +} + +/** + * e1000_mc_addr_list_update - Update Multicast addresses + * @hw: pointer to the HW structure + * @mc_addr_list: array of multicast addresses to program + * @mc_addr_count: number of multicast addresses to program + * @rar_used_count: the first RAR register free to program + * @rar_count: total number of supported Receive Address Registers + * + * Updates the Receive Address Registers and Multicast Table Array. + * The caller must have a packed mc_addr_list of multicast addresses. + * The parameter rar_count will usually be hw->mac.rar_entry_count + * unless there are workarounds that change this. Currently no func pointer + * exists and all implementations are handled in the generic version of this + * function. + **/ +static void e1000_mc_addr_list_update(struct e1000_hw *hw, u8 *mc_addr_list, + u32 mc_addr_count, u32 rar_used_count, + u32 rar_count) +{ + hw->mac.ops.mc_addr_list_update(hw, mc_addr_list, mc_addr_count, + rar_used_count, rar_count); +} + +/** + * e1000_set_multi - Multicast and Promiscuous mode set + * @netdev: network interface device structure + * + * The set_multi entry point is called whenever the multicast address + * list or the network interface flags are updated. This routine is + * responsible for configuring the hardware for proper multicast, + * promiscuous mode, and all-multi behavior. + **/ +static void e1000_set_multi(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + struct e1000_mac_info *mac = &hw->mac; + struct dev_mc_list *mc_ptr; + u8 *mta_list; + u32 rctl; + int i; + + /* Check for Promiscuous and All Multicast modes */ + + rctl = er32(RCTL); + + if (netdev->flags & IFF_PROMISC) { + rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE); + } else if (netdev->flags & IFF_ALLMULTI) { + rctl |= E1000_RCTL_MPE; + rctl &= ~E1000_RCTL_UPE; + } else { + rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE); + } + + ew32(RCTL, rctl); + + if (netdev->mc_count) { + mta_list = kmalloc(netdev->mc_count * 6, GFP_ATOMIC); + if (!mta_list) + return; + + /* prepare a packed array of only addresses. */ + mc_ptr = netdev->mc_list; + + for (i = 0; i < netdev->mc_count; i++) { + if (!mc_ptr) + break; + memcpy(mta_list + (i*ETH_ALEN), mc_ptr->dmi_addr, + ETH_ALEN); + mc_ptr = mc_ptr->next; + } + + e1000_mc_addr_list_update(hw, mta_list, i, 1, + mac->rar_entry_count); + kfree(mta_list); + } else { + /* + * if we're called from probe, we might not have + * anything to do here, so clear out the list + */ + e1000_mc_addr_list_update(hw, NULL, 0, 1, + mac->rar_entry_count); + } +} + +/** + * e1000_configure - configure the hardware for RX and TX + * @adapter: private board structure + **/ +static void e1000_configure(struct e1000_adapter *adapter) +{ + e1000_set_multi(adapter->netdev); + + e1000_restore_vlan(adapter); + e1000_init_manageability(adapter); + + e1000_configure_tx(adapter); + e1000_setup_rctl(adapter); + e1000_configure_rx(adapter); + adapter->alloc_rx_buf(adapter, + e1000_desc_unused(adapter->rx_ring)); +} + +/** + * e1000e_power_up_phy - restore link in case the phy was powered down + * @adapter: address of board private structure + * + * The phy may be powered down to save power and turn off link when the + * driver is unloaded and wake on lan is not enabled (among others) + * *** this routine MUST be followed by a call to e1000e_reset *** + **/ +void e1000e_power_up_phy(struct e1000_adapter *adapter) +{ + u16 mii_reg = 0; + + /* Just clear the power down bit to wake the phy back up */ + if (adapter->hw.media_type == e1000_media_type_copper) { + /* according to the manual, the phy will retain its + * settings across a power-down/up cycle */ + e1e_rphy(&adapter->hw, PHY_CONTROL, &mii_reg); + mii_reg &= ~MII_CR_POWER_DOWN; + e1e_wphy(&adapter->hw, PHY_CONTROL, mii_reg); + } + + adapter->hw.mac.ops.setup_link(&adapter->hw); +} + +/** + * e1000_power_down_phy - Power down the PHY + * + * Power down the PHY so no link is implied when interface is down + * The PHY cannot be powered down is management or WoL is active + */ +static void e1000_power_down_phy(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u16 mii_reg; + + /* WoL is enabled */ + if (!adapter->wol) + return; + + /* non-copper PHY? */ + if (adapter->hw.media_type != e1000_media_type_copper) + return; + + /* reset is blocked because of a SoL/IDER session */ + if (e1000e_check_mng_mode(hw) || + e1000_check_reset_block(hw)) + return; + + /* managebility (AMT) is enabled */ + if (er32(MANC) & E1000_MANC_SMBUS_EN) + return; + + /* power down the PHY */ + e1e_rphy(hw, PHY_CONTROL, &mii_reg); + mii_reg |= MII_CR_POWER_DOWN; + e1e_wphy(hw, PHY_CONTROL, mii_reg); + mdelay(1); +} + +/** + * e1000e_reset - bring the hardware into a known good state + * + * This function boots the hardware and enables some settings that + * require a configuration cycle of the hardware - those cannot be + * set/changed during runtime. After reset the device needs to be + * properly configured for rx, tx etc. + */ +void e1000e_reset(struct e1000_adapter *adapter) +{ + struct e1000_mac_info *mac = &adapter->hw.mac; + struct e1000_hw *hw = &adapter->hw; + u32 tx_space, min_tx_space, min_rx_space; + u16 hwm; + + if (mac->max_frame_size > ETH_FRAME_LEN + ETH_FCS_LEN ) { + /* To maintain wire speed transmits, the Tx FIFO should be + * large enough to accommodate two full transmit packets, + * rounded up to the next 1KB and expressed in KB. Likewise, + * the Rx FIFO should be large enough to accommodate at least + * one full receive packet and is similarly rounded up and + * expressed in KB. */ + adapter->pba = er32(PBA); + /* upper 16 bits has Tx packet buffer allocation size in KB */ + tx_space = adapter->pba >> 16; + /* lower 16 bits has Rx packet buffer allocation size in KB */ + adapter->pba &= 0xffff; + /* the tx fifo also stores 16 bytes of information about the tx + * but don't include ethernet FCS because hardware appends it */ + min_tx_space = (mac->max_frame_size + + sizeof(struct e1000_tx_desc) - + ETH_FCS_LEN) * 2; + min_tx_space = ALIGN(min_tx_space, 1024); + min_tx_space >>= 10; + /* software strips receive CRC, so leave room for it */ + min_rx_space = mac->max_frame_size; + min_rx_space = ALIGN(min_rx_space, 1024); + min_rx_space >>= 10; + + /* If current Tx allocation is less than the min Tx FIFO size, + * and the min Tx FIFO size is less than the current Rx FIFO + * allocation, take space away from current Rx allocation */ + if (tx_space < min_tx_space && + ((min_tx_space - tx_space) < adapter->pba)) { + adapter->pba -= - (min_tx_space - tx_space); + + /* if short on rx space, rx wins and must trump tx + * adjustment or use Early Receive if available */ + if ((adapter->pba < min_rx_space) && + (!(adapter->flags & FLAG_HAS_ERT))) + /* ERT enabled in e1000_configure_rx */ + adapter->pba = min_rx_space; + } + } + + ew32(PBA, adapter->pba); + + /* flow control settings */ + /* The high water mark must be low enough to fit one full frame + * (or the size used for early receive) above it in the Rx FIFO. + * Set it to the lower of: + * - 90% of the Rx FIFO size, and + * - the full Rx FIFO size minus the early receive size (for parts + * with ERT support assuming ERT set to E1000_ERT_2048), or + * - the full Rx FIFO size minus one full frame */ + if (adapter->flags & FLAG_HAS_ERT) + hwm = min(((adapter->pba << 10) * 9 / 10), + ((adapter->pba << 10) - (E1000_ERT_2048 << 3))); + else + hwm = min(((adapter->pba << 10) * 9 / 10), + ((adapter->pba << 10) - mac->max_frame_size)); + + mac->fc_high_water = hwm & 0xFFF8; /* 8-byte granularity */ + mac->fc_low_water = mac->fc_high_water - 8; + + if (adapter->flags & FLAG_DISABLE_FC_PAUSE_TIME) + mac->fc_pause_time = 0xFFFF; + else + mac->fc_pause_time = E1000_FC_PAUSE_TIME; + mac->fc = mac->original_fc; + + /* Allow time for pending master requests to run */ + mac->ops.reset_hw(hw); + ew32(WUC, 0); + + if (mac->ops.init_hw(hw)) + ndev_err(adapter->netdev, "Hardware Error\n"); + + e1000_update_mng_vlan(adapter); + + /* Enable h/w to recognize an 802.1Q VLAN Ethernet packet */ + ew32(VET, ETH_P_8021Q); + + e1000e_reset_adaptive(hw); + e1000_get_phy_info(hw); + + if (!(adapter->flags & FLAG_SMART_POWER_DOWN)) { + u16 phy_data = 0; + /* speed up time to link by disabling smart power down, ignore + * the return value of this function because there is nothing + * different we would do if it failed */ + e1e_rphy(hw, IGP02E1000_PHY_POWER_MGMT, &phy_data); + phy_data &= ~IGP02E1000_PM_SPD; + e1e_wphy(hw, IGP02E1000_PHY_POWER_MGMT, phy_data); + } + + e1000_release_manageability(adapter); +} + +int e1000e_up(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + + /* hardware has been reset, we need to reload some things */ + e1000_configure(adapter); + + clear_bit(__E1000_DOWN, &adapter->state); + + napi_enable(&adapter->napi); + e1000_irq_enable(adapter); + + /* fire a link change interrupt to start the watchdog */ + ew32(ICS, E1000_ICS_LSC); + return 0; +} + +void e1000e_down(struct e1000_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + struct e1000_hw *hw = &adapter->hw; + u32 tctl, rctl; + + /* signal that we're down so the interrupt handler does not + * reschedule our watchdog timer */ + set_bit(__E1000_DOWN, &adapter->state); + + /* disable receives in the hardware */ + rctl = er32(RCTL); + ew32(RCTL, rctl & ~E1000_RCTL_EN); + /* flush and sleep below */ + + netif_stop_queue(netdev); + + /* disable transmits in the hardware */ + tctl = er32(TCTL); + tctl &= ~E1000_TCTL_EN; + ew32(TCTL, tctl); + /* flush both disables and wait for them to finish */ + e1e_flush(); + msleep(10); + + napi_disable(&adapter->napi); + e1000_irq_disable(adapter); + + del_timer_sync(&adapter->watchdog_timer); + del_timer_sync(&adapter->phy_info_timer); + + netdev->tx_queue_len = adapter->tx_queue_len; + netif_carrier_off(netdev); + adapter->link_speed = 0; + adapter->link_duplex = 0; + + e1000e_reset(adapter); + e1000_clean_tx_ring(adapter); + e1000_clean_rx_ring(adapter); + + /* + * TODO: for power management, we could drop the link and + * pci_disable_device here. + */ +} + +void e1000e_reinit_locked(struct e1000_adapter *adapter) +{ + might_sleep(); + while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) + msleep(1); + e1000e_down(adapter); + e1000e_up(adapter); + clear_bit(__E1000_RESETTING, &adapter->state); +} + +/** + * e1000_sw_init - Initialize general software structures (struct e1000_adapter) + * @adapter: board private structure to initialize + * + * e1000_sw_init initializes the Adapter private data structure. + * Fields are initialized based on PCI device information and + * OS network device settings (MTU size). + **/ +static int __devinit e1000_sw_init(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + struct net_device *netdev = adapter->netdev; + + adapter->rx_buffer_len = ETH_FRAME_LEN + VLAN_HLEN + ETH_FCS_LEN; + adapter->rx_ps_bsize0 = 128; + hw->mac.max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN; + hw->mac.min_frame_size = ETH_ZLEN + ETH_FCS_LEN; + + adapter->tx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL); + if (!adapter->tx_ring) + goto err; + + adapter->rx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL); + if (!adapter->rx_ring) + goto err; + + spin_lock_init(&adapter->tx_queue_lock); + + /* Explicitly disable IRQ since the NIC can be in any state. */ + atomic_set(&adapter->irq_sem, 0); + e1000_irq_disable(adapter); + + spin_lock_init(&adapter->stats_lock); + + set_bit(__E1000_DOWN, &adapter->state); + return 0; + +err: + ndev_err(netdev, "Unable to allocate memory for queues\n"); + kfree(adapter->rx_ring); + kfree(adapter->tx_ring); + return -ENOMEM; +} + +/** + * e1000_open - Called when a network interface is made active + * @netdev: network interface device structure + * + * Returns 0 on success, negative value on failure + * + * The open entry point is called when a network interface is made + * active by the system (IFF_UP). At this point all resources needed + * for transmit and receive operations are allocated, the interrupt + * handler is registered with the OS, the watchdog timer is started, + * and the stack is notified that the interface is ready. + **/ +static int e1000_open(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + int err; + + /* disallow open during test */ + if (test_bit(__E1000_TESTING, &adapter->state)) + return -EBUSY; + + /* allocate transmit descriptors */ + err = e1000e_setup_tx_resources(adapter); + if (err) + goto err_setup_tx; + + /* allocate receive descriptors */ + err = e1000e_setup_rx_resources(adapter); + if (err) + goto err_setup_rx; + + e1000e_power_up_phy(adapter); + + adapter->mng_vlan_id = E1000_MNG_VLAN_NONE; + if ((adapter->hw.mng_cookie.status & + E1000_MNG_DHCP_COOKIE_STATUS_VLAN)) + e1000_update_mng_vlan(adapter); + + /* If AMT is enabled, let the firmware know that the network + * interface is now open */ + if ((adapter->flags & FLAG_HAS_AMT) && + e1000e_check_mng_mode(&adapter->hw)) + e1000_get_hw_control(adapter); + + /* before we allocate an interrupt, we must be ready to handle it. + * Setting DEBUG_SHIRQ in the kernel makes it fire an interrupt + * as soon as we call pci_request_irq, so we have to setup our + * clean_rx handler before we do so. */ + e1000_configure(adapter); + + err = e1000_request_irq(adapter); + if (err) + goto err_req_irq; + + /* From here on the code is the same as e1000e_up() */ + clear_bit(__E1000_DOWN, &adapter->state); + + napi_enable(&adapter->napi); + + e1000_irq_enable(adapter); + + /* fire a link status change interrupt to start the watchdog */ + ew32(ICS, E1000_ICS_LSC); + + return 0; + +err_req_irq: + e1000_release_hw_control(adapter); + e1000_power_down_phy(adapter); + e1000e_free_rx_resources(adapter); +err_setup_rx: + e1000e_free_tx_resources(adapter); +err_setup_tx: + e1000e_reset(adapter); + + return err; +} + +/** + * e1000_close - Disables a network interface + * @netdev: network interface device structure + * + * Returns 0, this is not allowed to fail + * + * The close entry point is called when an interface is de-activated + * by the OS. The hardware is still under the drivers control, but + * needs to be disabled. A global MAC reset is issued to stop the + * hardware, and all transmit and receive resources are freed. + **/ +static int e1000_close(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + + WARN_ON(test_bit(__E1000_RESETTING, &adapter->state)); + e1000e_down(adapter); + e1000_power_down_phy(adapter); + e1000_free_irq(adapter); + + e1000e_free_tx_resources(adapter); + e1000e_free_rx_resources(adapter); + + /* kill manageability vlan ID if supported, but not if a vlan with + * the same ID is registered on the host OS (let 8021q kill it) */ + if ((adapter->hw.mng_cookie.status & + E1000_MNG_DHCP_COOKIE_STATUS_VLAN) && + !(adapter->vlgrp && + vlan_group_get_device(adapter->vlgrp, adapter->mng_vlan_id))) + e1000_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id); + + /* If AMT is enabled, let the firmware know that the network + * interface is now closed */ + if ((adapter->flags & FLAG_HAS_AMT) && + e1000e_check_mng_mode(&adapter->hw)) + e1000_release_hw_control(adapter); + + return 0; +} +/** + * e1000_set_mac - Change the Ethernet Address of the NIC + * @netdev: network interface device structure + * @p: pointer to an address structure + * + * Returns 0 on success, negative on failure + **/ +static int e1000_set_mac(struct net_device *netdev, void *p) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct sockaddr *addr = p; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; + + memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); + memcpy(adapter->hw.mac.addr, addr->sa_data, netdev->addr_len); + + e1000e_rar_set(&adapter->hw, adapter->hw.mac.addr, 0); + + if (adapter->flags & FLAG_RESET_OVERWRITES_LAA) { + /* activate the work around */ + e1000e_set_laa_state_82571(&adapter->hw, 1); + + /* Hold a copy of the LAA in RAR[14] This is done so that + * between the time RAR[0] gets clobbered and the time it + * gets fixed (in e1000_watchdog), the actual LAA is in one + * of the RARs and no incoming packets directed to this port + * are dropped. Eventually the LAA will be in RAR[0] and + * RAR[14] */ + e1000e_rar_set(&adapter->hw, + adapter->hw.mac.addr, + adapter->hw.mac.rar_entry_count - 1); + } + + return 0; +} + +/* Need to wait a few seconds after link up to get diagnostic information from + * the phy */ +static void e1000_update_phy_info(unsigned long data) +{ + struct e1000_adapter *adapter = (struct e1000_adapter *) data; + e1000_get_phy_info(&adapter->hw); +} + +/** + * e1000e_update_stats - Update the board statistics counters + * @adapter: board private structure + **/ +void e1000e_update_stats(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + struct pci_dev *pdev = adapter->pdev; + unsigned long irq_flags; + u16 phy_tmp; + +#define PHY_IDLE_ERROR_COUNT_MASK 0x00FF + + /* + * Prevent stats update while adapter is being reset, or if the pci + * connection is down. + */ + if (adapter->link_speed == 0) + return; + if (pci_channel_offline(pdev)) + return; + + spin_lock_irqsave(&adapter->stats_lock, irq_flags); + + /* these counters are modified from e1000_adjust_tbi_stats, + * called from the interrupt context, so they must only + * be written while holding adapter->stats_lock + */ + + adapter->stats.crcerrs += er32(CRCERRS); + adapter->stats.gprc += er32(GPRC); + adapter->stats.gorcl += er32(GORCL); + adapter->stats.gorch += er32(GORCH); + adapter->stats.bprc += er32(BPRC); + adapter->stats.mprc += er32(MPRC); + adapter->stats.roc += er32(ROC); + + if (adapter->flags & FLAG_HAS_STATS_PTC_PRC) { + adapter->stats.prc64 += er32(PRC64); + adapter->stats.prc127 += er32(PRC127); + adapter->stats.prc255 += er32(PRC255); + adapter->stats.prc511 += er32(PRC511); + adapter->stats.prc1023 += er32(PRC1023); + adapter->stats.prc1522 += er32(PRC1522); + adapter->stats.symerrs += er32(SYMERRS); + adapter->stats.sec += er32(SEC); + } + + adapter->stats.mpc += er32(MPC); + adapter->stats.scc += er32(SCC); + adapter->stats.ecol += er32(ECOL); + adapter->stats.mcc += er32(MCC); + adapter->stats.latecol += er32(LATECOL); + adapter->stats.dc += er32(DC); + adapter->stats.rlec += er32(RLEC); + adapter->stats.xonrxc += er32(XONRXC); + adapter->stats.xontxc += er32(XONTXC); + adapter->stats.xoffrxc += er32(XOFFRXC); + adapter->stats.xofftxc += er32(XOFFTXC); + adapter->stats.fcruc += er32(FCRUC); + adapter->stats.gptc += er32(GPTC); + adapter->stats.gotcl += er32(GOTCL); + adapter->stats.gotch += er32(GOTCH); + adapter->stats.rnbc += er32(RNBC); + adapter->stats.ruc += er32(RUC); + adapter->stats.rfc += er32(RFC); + adapter->stats.rjc += er32(RJC); + adapter->stats.torl += er32(TORL); + adapter->stats.torh += er32(TORH); + adapter->stats.totl += er32(TOTL); + adapter->stats.toth += er32(TOTH); + adapter->stats.tpr += er32(TPR); + + if (adapter->flags & FLAG_HAS_STATS_PTC_PRC) { + adapter->stats.ptc64 += er32(PTC64); + adapter->stats.ptc127 += er32(PTC127); + adapter->stats.ptc255 += er32(PTC255); + adapter->stats.ptc511 += er32(PTC511); + adapter->stats.ptc1023 += er32(PTC1023); + adapter->stats.ptc1522 += er32(PTC1522); + } + + adapter->stats.mptc += er32(MPTC); + adapter->stats.bptc += er32(BPTC); + + /* used for adaptive IFS */ + + hw->mac.tx_packet_delta = er32(TPT); + adapter->stats.tpt += hw->mac.tx_packet_delta; + hw->mac.collision_delta = er32(COLC); + adapter->stats.colc += hw->mac.collision_delta; + + adapter->stats.algnerrc += er32(ALGNERRC); + adapter->stats.rxerrc += er32(RXERRC); + adapter->stats.tncrs += er32(TNCRS); + adapter->stats.cexterr += er32(CEXTERR); + adapter->stats.tsctc += er32(TSCTC); + adapter->stats.tsctfc += er32(TSCTFC); + + adapter->stats.iac += er32(IAC); + + if (adapter->flags & FLAG_HAS_STATS_ICR_ICT) { + adapter->stats.icrxoc += er32(ICRXOC); + adapter->stats.icrxptc += er32(ICRXPTC); + adapter->stats.icrxatc += er32(ICRXATC); + adapter->stats.ictxptc += er32(ICTXPTC); + adapter->stats.ictxatc += er32(ICTXATC); + adapter->stats.ictxqec += er32(ICTXQEC); + adapter->stats.ictxqmtc += er32(ICTXQMTC); + adapter->stats.icrxdmtc += er32(ICRXDMTC); + } + + /* Fill out the OS statistics structure */ + adapter->net_stats.rx_packets = adapter->stats.gprc; + adapter->net_stats.tx_packets = adapter->stats.gptc; + adapter->net_stats.rx_bytes = adapter->stats.gorcl; + adapter->net_stats.tx_bytes = adapter->stats.gotcl; + adapter->net_stats.multicast = adapter->stats.mprc; + adapter->net_stats.collisions = adapter->stats.colc; + + /* Rx Errors */ + + /* RLEC on some newer hardware can be incorrect so build + * our own version based on RUC and ROC */ + adapter->net_stats.rx_errors = adapter->stats.rxerrc + + adapter->stats.crcerrs + adapter->stats.algnerrc + + adapter->stats.ruc + adapter->stats.roc + + adapter->stats.cexterr; + adapter->net_stats.rx_length_errors = adapter->stats.ruc + + adapter->stats.roc; + adapter->net_stats.rx_crc_errors = adapter->stats.crcerrs; + adapter->net_stats.rx_frame_errors = adapter->stats.algnerrc; + adapter->net_stats.rx_missed_errors = adapter->stats.mpc; + + /* Tx Errors */ + adapter->net_stats.tx_errors = adapter->stats.ecol + + adapter->stats.latecol; + adapter->net_stats.tx_aborted_errors = adapter->stats.ecol; + adapter->net_stats.tx_window_errors = adapter->stats.latecol; + adapter->net_stats.tx_carrier_errors = adapter->stats.tncrs; + + /* Tx Dropped needs to be maintained elsewhere */ + + /* Phy Stats */ + if (hw->media_type == e1000_media_type_copper) { + if ((adapter->link_speed == SPEED_1000) && + (!e1e_rphy(hw, PHY_1000T_STATUS, &phy_tmp))) { + phy_tmp &= PHY_IDLE_ERROR_COUNT_MASK; + adapter->phy_stats.idle_errors += phy_tmp; + } + } + + /* Management Stats */ + adapter->stats.mgptc += er32(MGTPTC); + adapter->stats.mgprc += er32(MGTPRC); + adapter->stats.mgpdc += er32(MGTPDC); + + spin_unlock_irqrestore(&adapter->stats_lock, irq_flags); +} + +static void e1000_print_link_info(struct e1000_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + struct e1000_hw *hw = &adapter->hw; + u32 ctrl = er32(CTRL); + + ndev_info(netdev, + "Link is Up %d Mbps %s, Flow Control: %s\n", + adapter->link_speed, + (adapter->link_duplex == FULL_DUPLEX) ? + "Full Duplex" : "Half Duplex", + ((ctrl & E1000_CTRL_TFCE) && (ctrl & E1000_CTRL_RFCE)) ? + "RX/TX" : + ((ctrl & E1000_CTRL_RFCE) ? "RX" : + ((ctrl & E1000_CTRL_TFCE) ? "TX" : "None" ))); +} + +/** + * e1000_watchdog - Timer Call-back + * @data: pointer to adapter cast into an unsigned long + **/ +static void e1000_watchdog(unsigned long data) +{ + struct e1000_adapter *adapter = (struct e1000_adapter *) data; + + /* Do the rest outside of interrupt context */ + schedule_work(&adapter->watchdog_task); + + /* TODO: make this use queue_delayed_work() */ +} + +static void e1000_watchdog_task(struct work_struct *work) +{ + struct e1000_adapter *adapter = container_of(work, + struct e1000_adapter, watchdog_task); + + struct net_device *netdev = adapter->netdev; + struct e1000_mac_info *mac = &adapter->hw.mac; + struct e1000_ring *tx_ring = adapter->tx_ring; + struct e1000_hw *hw = &adapter->hw; + u32 link, tctl; + s32 ret_val; + int tx_pending = 0; + + if ((netif_carrier_ok(netdev)) && + (er32(STATUS) & E1000_STATUS_LU)) + goto link_up; + + ret_val = mac->ops.check_for_link(hw); + if ((ret_val == E1000_ERR_PHY) && + (adapter->hw.phy.type == e1000_phy_igp_3) && + (er32(CTRL) & + E1000_PHY_CTRL_GBE_DISABLE)) { + /* See e1000_kmrn_lock_loss_workaround_ich8lan() */ + ndev_info(netdev, + "Gigabit has been disabled, downgrading speed\n"); + } + + if ((e1000e_enable_tx_pkt_filtering(hw)) && + (adapter->mng_vlan_id != adapter->hw.mng_cookie.vlan_id)) + e1000_update_mng_vlan(adapter); + + if ((adapter->hw.media_type == e1000_media_type_internal_serdes) && + !(er32(TXCW) & E1000_TXCW_ANE)) + link = adapter->hw.mac.serdes_has_link; + else + link = er32(STATUS) & E1000_STATUS_LU; + + if (link) { + if (!netif_carrier_ok(netdev)) { + bool txb2b = 1; + mac->ops.get_link_up_info(&adapter->hw, + &adapter->link_speed, + &adapter->link_duplex); + e1000_print_link_info(adapter); + /* tweak tx_queue_len according to speed/duplex + * and adjust the timeout factor */ + netdev->tx_queue_len = adapter->tx_queue_len; + adapter->tx_timeout_factor = 1; + switch (adapter->link_speed) { + case SPEED_10: + txb2b = 0; + netdev->tx_queue_len = 10; + adapter->tx_timeout_factor = 14; + break; + case SPEED_100: + txb2b = 0; + netdev->tx_queue_len = 100; + /* maybe add some timeout factor ? */ + break; + } + + /* workaround: re-program speed mode bit after + * link-up event */ + if ((adapter->flags & FLAG_TARC_SPEED_MODE_BIT) && + !txb2b) { + u32 tarc0; + tarc0 = er32(TARC0); + tarc0 &= ~SPEED_MODE_BIT; + ew32(TARC0, tarc0); + } + + /* disable TSO for pcie and 10/100 speeds, to avoid + * some hardware issues */ + if (!(adapter->flags & FLAG_TSO_FORCE)) { + switch (adapter->link_speed) { + case SPEED_10: + case SPEED_100: + ndev_info(netdev, + "10/100 speed: disabling TSO\n"); + netdev->features &= ~NETIF_F_TSO; + netdev->features &= ~NETIF_F_TSO6; + break; + case SPEED_1000: + netdev->features |= NETIF_F_TSO; + netdev->features |= NETIF_F_TSO6; + break; + default: + /* oops */ + break; + } + } + + /* enable transmits in the hardware, need to do this + * after setting TARC0 */ + tctl = er32(TCTL); + tctl |= E1000_TCTL_EN; + ew32(TCTL, tctl); + + netif_carrier_on(netdev); + netif_wake_queue(netdev); + + if (!test_bit(__E1000_DOWN, &adapter->state)) + mod_timer(&adapter->phy_info_timer, + round_jiffies(jiffies + 2 * HZ)); + } else { + /* make sure the receive unit is started */ + if (adapter->flags & FLAG_RX_NEEDS_RESTART) { + u32 rctl = er32(RCTL); + ew32(RCTL, rctl | + E1000_RCTL_EN); + } + } + } else { + if (netif_carrier_ok(netdev)) { + adapter->link_speed = 0; + adapter->link_duplex = 0; + ndev_info(netdev, "Link is Down\n"); + netif_carrier_off(netdev); + netif_stop_queue(netdev); + if (!test_bit(__E1000_DOWN, &adapter->state)) + mod_timer(&adapter->phy_info_timer, + round_jiffies(jiffies + 2 * HZ)); + + if (adapter->flags & FLAG_RX_NEEDS_RESTART) + schedule_work(&adapter->reset_task); + } + } + +link_up: + e1000e_update_stats(adapter); + + mac->tx_packet_delta = adapter->stats.tpt - adapter->tpt_old; + adapter->tpt_old = adapter->stats.tpt; + mac->collision_delta = adapter->stats.colc - adapter->colc_old; + adapter->colc_old = adapter->stats.colc; + + adapter->gorcl = adapter->stats.gorcl - adapter->gorcl_old; + adapter->gorcl_old = adapter->stats.gorcl; + adapter->gotcl = adapter->stats.gotcl - adapter->gotcl_old; + adapter->gotcl_old = adapter->stats.gotcl; + + e1000e_update_adaptive(&adapter->hw); + + if (!netif_carrier_ok(netdev)) { + tx_pending = (e1000_desc_unused(tx_ring) + 1 < + tx_ring->count); + if (tx_pending) { + /* We've lost link, so the controller stops DMA, + * but we've got queued Tx work that's never going + * to get done, so reset controller to flush Tx. + * (Do the reset outside of interrupt context). */ + adapter->tx_timeout_count++; + schedule_work(&adapter->reset_task); + } + } + + /* Cause software interrupt to ensure rx ring is cleaned */ + ew32(ICS, E1000_ICS_RXDMT0); + + /* Force detection of hung controller every watchdog period */ + adapter->detect_tx_hung = 1; + + /* With 82571 controllers, LAA may be overwritten due to controller + * reset from the other port. Set the appropriate LAA in RAR[0] */ + if (e1000e_get_laa_state_82571(hw)) + e1000e_rar_set(hw, adapter->hw.mac.addr, 0); + + /* Reset the timer */ + if (!test_bit(__E1000_DOWN, &adapter->state)) + mod_timer(&adapter->watchdog_timer, + round_jiffies(jiffies + 2 * HZ)); +} + +#define E1000_TX_FLAGS_CSUM 0x00000001 +#define E1000_TX_FLAGS_VLAN 0x00000002 +#define E1000_TX_FLAGS_TSO 0x00000004 +#define E1000_TX_FLAGS_IPV4 0x00000008 +#define E1000_TX_FLAGS_VLAN_MASK 0xffff0000 +#define E1000_TX_FLAGS_VLAN_SHIFT 16 + +static int e1000_tso(struct e1000_adapter *adapter, + struct sk_buff *skb) +{ + struct e1000_ring *tx_ring = adapter->tx_ring; + struct e1000_context_desc *context_desc; + struct e1000_buffer *buffer_info; + unsigned int i; + u32 cmd_length = 0; + u16 ipcse = 0, tucse, mss; + u8 ipcss, ipcso, tucss, tucso, hdr_len; + int err; + + if (skb_is_gso(skb)) { + if (skb_header_cloned(skb)) { + err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC); + if (err) + return err; + } + + hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); + mss = skb_shinfo(skb)->gso_size; + if (skb->protocol == htons(ETH_P_IP)) { + struct iphdr *iph = ip_hdr(skb); + iph->tot_len = 0; + iph->check = 0; + tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr, + iph->daddr, 0, + IPPROTO_TCP, + 0); + cmd_length = E1000_TXD_CMD_IP; + ipcse = skb_transport_offset(skb) - 1; + } else if (skb_shinfo(skb)->gso_type == SKB_GSO_TCPV6) { + ipv6_hdr(skb)->payload_len = 0; + tcp_hdr(skb)->check = + ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, + &ipv6_hdr(skb)->daddr, + 0, IPPROTO_TCP, 0); + ipcse = 0; + } + ipcss = skb_network_offset(skb); + ipcso = (void *)&(ip_hdr(skb)->check) - (void *)skb->data; + tucss = skb_transport_offset(skb); + tucso = (void *)&(tcp_hdr(skb)->check) - (void *)skb->data; + tucse = 0; + + cmd_length |= (E1000_TXD_CMD_DEXT | E1000_TXD_CMD_TSE | + E1000_TXD_CMD_TCP | (skb->len - (hdr_len))); + + i = tx_ring->next_to_use; + context_desc = E1000_CONTEXT_DESC(*tx_ring, i); + buffer_info = &tx_ring->buffer_info[i]; + + context_desc->lower_setup.ip_fields.ipcss = ipcss; + context_desc->lower_setup.ip_fields.ipcso = ipcso; + context_desc->lower_setup.ip_fields.ipcse = cpu_to_le16(ipcse); + context_desc->upper_setup.tcp_fields.tucss = tucss; + context_desc->upper_setup.tcp_fields.tucso = tucso; + context_desc->upper_setup.tcp_fields.tucse = cpu_to_le16(tucse); + context_desc->tcp_seg_setup.fields.mss = cpu_to_le16(mss); + context_desc->tcp_seg_setup.fields.hdr_len = hdr_len; + context_desc->cmd_and_length = cpu_to_le32(cmd_length); + + buffer_info->time_stamp = jiffies; + buffer_info->next_to_watch = i; + + i++; + if (i == tx_ring->count) + i = 0; + tx_ring->next_to_use = i; + + return 1; + } + + return 0; +} + +static bool e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb) +{ + struct e1000_ring *tx_ring = adapter->tx_ring; + struct e1000_context_desc *context_desc; + struct e1000_buffer *buffer_info; + unsigned int i; + u8 css; + + if (skb->ip_summed == CHECKSUM_PARTIAL) { + css = skb_transport_offset(skb); + + i = tx_ring->next_to_use; + buffer_info = &tx_ring->buffer_info[i]; + context_desc = E1000_CONTEXT_DESC(*tx_ring, i); + + context_desc->lower_setup.ip_config = 0; + context_desc->upper_setup.tcp_fields.tucss = css; + context_desc->upper_setup.tcp_fields.tucso = + css + skb->csum_offset; + context_desc->upper_setup.tcp_fields.tucse = 0; + context_desc->tcp_seg_setup.data = 0; + context_desc->cmd_and_length = cpu_to_le32(E1000_TXD_CMD_DEXT); + + buffer_info->time_stamp = jiffies; + buffer_info->next_to_watch = i; + + i++; + if (i == tx_ring->count) + i = 0; + tx_ring->next_to_use = i; + + return 1; + } + + return 0; +} + +#define E1000_MAX_PER_TXD 8192 +#define E1000_MAX_TXD_PWR 12 + +static int e1000_tx_map(struct e1000_adapter *adapter, + struct sk_buff *skb, unsigned int first, + unsigned int max_per_txd, unsigned int nr_frags, + unsigned int mss) +{ + struct e1000_ring *tx_ring = adapter->tx_ring; + struct e1000_buffer *buffer_info; + unsigned int len = skb->len - skb->data_len; + unsigned int offset = 0, size, count = 0, i; + unsigned int f; + + i = tx_ring->next_to_use; + + while (len) { + buffer_info = &tx_ring->buffer_info[i]; + size = min(len, max_per_txd); + + /* Workaround for premature desc write-backs + * in TSO mode. Append 4-byte sentinel desc */ + if (mss && !nr_frags && size == len && size > 8) + size -= 4; + + buffer_info->length = size; + /* set time_stamp *before* dma to help avoid a possible race */ + buffer_info->time_stamp = jiffies; + buffer_info->dma = + pci_map_single(adapter->pdev, + skb->data + offset, + size, + PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(buffer_info->dma)) { + dev_err(&adapter->pdev->dev, "TX DMA map failed\n"); + adapter->tx_dma_failed++; + return -1; + } + buffer_info->next_to_watch = i; + + len -= size; + offset += size; + count++; + i++; + if (i == tx_ring->count) + i = 0; + } + + for (f = 0; f < nr_frags; f++) { + struct skb_frag_struct *frag; + + frag = &skb_shinfo(skb)->frags[f]; + len = frag->size; + offset = frag->page_offset; + + while (len) { + buffer_info = &tx_ring->buffer_info[i]; + size = min(len, max_per_txd); + /* Workaround for premature desc write-backs + * in TSO mode. Append 4-byte sentinel desc */ + if (mss && f == (nr_frags-1) && size == len && size > 8) + size -= 4; + + buffer_info->length = size; + buffer_info->time_stamp = jiffies; + buffer_info->dma = + pci_map_page(adapter->pdev, + frag->page, + offset, + size, + PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(buffer_info->dma)) { + dev_err(&adapter->pdev->dev, + "TX DMA page map failed\n"); + adapter->tx_dma_failed++; + return -1; + } + + buffer_info->next_to_watch = i; + + len -= size; + offset += size; + count++; + + i++; + if (i == tx_ring->count) + i = 0; + } + } + + if (i == 0) + i = tx_ring->count - 1; + else + i--; + + tx_ring->buffer_info[i].skb = skb; + tx_ring->buffer_info[first].next_to_watch = i; + + return count; +} + +static void e1000_tx_queue(struct e1000_adapter *adapter, + int tx_flags, int count) +{ + struct e1000_ring *tx_ring = adapter->tx_ring; + struct e1000_tx_desc *tx_desc = NULL; + struct e1000_buffer *buffer_info; + u32 txd_upper = 0, txd_lower = E1000_TXD_CMD_IFCS; + unsigned int i; + + if (tx_flags & E1000_TX_FLAGS_TSO) { + txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D | + E1000_TXD_CMD_TSE; + txd_upper |= E1000_TXD_POPTS_TXSM << 8; + + if (tx_flags & E1000_TX_FLAGS_IPV4) + txd_upper |= E1000_TXD_POPTS_IXSM << 8; + } + + if (tx_flags & E1000_TX_FLAGS_CSUM) { + txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D; + txd_upper |= E1000_TXD_POPTS_TXSM << 8; + } + + if (tx_flags & E1000_TX_FLAGS_VLAN) { + txd_lower |= E1000_TXD_CMD_VLE; + txd_upper |= (tx_flags & E1000_TX_FLAGS_VLAN_MASK); + } + + i = tx_ring->next_to_use; + + while (count--) { + buffer_info = &tx_ring->buffer_info[i]; + tx_desc = E1000_TX_DESC(*tx_ring, i); + tx_desc->buffer_addr = cpu_to_le64(buffer_info->dma); + tx_desc->lower.data = + cpu_to_le32(txd_lower | buffer_info->length); + tx_desc->upper.data = cpu_to_le32(txd_upper); + + i++; + if (i == tx_ring->count) + i = 0; + } + + tx_desc->lower.data |= cpu_to_le32(adapter->txd_cmd); + + /* Force memory writes to complete before letting h/w + * know there are new descriptors to fetch. (Only + * applicable for weak-ordered memory model archs, + * such as IA-64). */ + wmb(); + + tx_ring->next_to_use = i; + writel(i, adapter->hw.hw_addr + tx_ring->tail); + /* we need this if more than one processor can write to our tail + * at a time, it synchronizes IO on IA64/Altix systems */ + mmiowb(); +} + +#define MINIMUM_DHCP_PACKET_SIZE 282 +static int e1000_transfer_dhcp_info(struct e1000_adapter *adapter, + struct sk_buff *skb) +{ + struct e1000_hw *hw = &adapter->hw; + u16 length, offset; + + if (vlan_tx_tag_present(skb)) { + if (!((vlan_tx_tag_get(skb) == adapter->hw.mng_cookie.vlan_id) + && (adapter->hw.mng_cookie.status & + E1000_MNG_DHCP_COOKIE_STATUS_VLAN))) + return 0; + } + + if (skb->len <= MINIMUM_DHCP_PACKET_SIZE) + return 0; + + if (((struct ethhdr *) skb->data)->h_proto != htons(ETH_P_IP)) + return 0; + + { + const struct iphdr *ip = (struct iphdr *)((u8 *)skb->data+14); + struct udphdr *udp; + + if (ip->protocol != IPPROTO_UDP) + return 0; + + udp = (struct udphdr *)((u8 *)ip + (ip->ihl << 2)); + if (ntohs(udp->dest) != 67) + return 0; + + offset = (u8 *)udp + 8 - skb->data; + length = skb->len - offset; + return e1000e_mng_write_dhcp_info(hw, (u8 *)udp + 8, length); + } + + return 0; +} + +static int __e1000_maybe_stop_tx(struct net_device *netdev, int size) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + + netif_stop_queue(netdev); + /* Herbert's original patch had: + * smp_mb__after_netif_stop_queue(); + * but since that doesn't exist yet, just open code it. */ + smp_mb(); + + /* We need to check again in a case another CPU has just + * made room available. */ + if (e1000_desc_unused(adapter->tx_ring) < size) + return -EBUSY; + + /* A reprieve! */ + netif_start_queue(netdev); + ++adapter->restart_queue; + return 0; +} + +static int e1000_maybe_stop_tx(struct net_device *netdev, int size) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + + if (e1000_desc_unused(adapter->tx_ring) >= size) + return 0; + return __e1000_maybe_stop_tx(netdev, size); +} + +#define TXD_USE_COUNT(S, X) (((S) >> (X)) + 1 ) +static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_ring *tx_ring = adapter->tx_ring; + unsigned int first; + unsigned int max_per_txd = E1000_MAX_PER_TXD; + unsigned int max_txd_pwr = E1000_MAX_TXD_PWR; + unsigned int tx_flags = 0; + unsigned int len = skb->len; + unsigned long irq_flags; + unsigned int nr_frags = 0; + unsigned int mss = 0; + int count = 0; + int tso; + unsigned int f; + len -= skb->data_len; + + if (test_bit(__E1000_DOWN, &adapter->state)) { + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + + if (skb->len <= 0) { + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + + mss = skb_shinfo(skb)->gso_size; + /* The controller does a simple calculation to + * make sure there is enough room in the FIFO before + * initiating the DMA for each buffer. The calc is: + * 4 = ceil(buffer len/mss). To make sure we don't + * overrun the FIFO, adjust the max buffer len if mss + * drops. */ + if (mss) { + u8 hdr_len; + max_per_txd = min(mss << 2, max_per_txd); + max_txd_pwr = fls(max_per_txd) - 1; + + /* TSO Workaround for 82571/2/3 Controllers -- if skb->data + * points to just header, pull a few bytes of payload from + * frags into skb->data */ + hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); + if (skb->data_len && (hdr_len == (skb->len - skb->data_len))) { + unsigned int pull_size; + + pull_size = min((unsigned int)4, skb->data_len); + if (!__pskb_pull_tail(skb, pull_size)) { + ndev_err(netdev, + "__pskb_pull_tail failed.\n"); + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + len = skb->len - skb->data_len; + } + } + + /* reserve a descriptor for the offload context */ + if ((mss) || (skb->ip_summed == CHECKSUM_PARTIAL)) + count++; + count++; + + count += TXD_USE_COUNT(len, max_txd_pwr); + + nr_frags = skb_shinfo(skb)->nr_frags; + for (f = 0; f < nr_frags; f++) + count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size, + max_txd_pwr); + + if (adapter->hw.mac.tx_pkt_filtering) + e1000_transfer_dhcp_info(adapter, skb); + + if (!spin_trylock_irqsave(&adapter->tx_queue_lock, irq_flags)) + /* Collision - tell upper layer to requeue */ + return NETDEV_TX_LOCKED; + + /* need: count + 2 desc gap to keep tail from touching + * head, otherwise try next time */ + if (e1000_maybe_stop_tx(netdev, count + 2)) { + spin_unlock_irqrestore(&adapter->tx_queue_lock, irq_flags); + return NETDEV_TX_BUSY; + } + + if (adapter->vlgrp && vlan_tx_tag_present(skb)) { + tx_flags |= E1000_TX_FLAGS_VLAN; + tx_flags |= (vlan_tx_tag_get(skb) << E1000_TX_FLAGS_VLAN_SHIFT); + } + + first = tx_ring->next_to_use; + + tso = e1000_tso(adapter, skb); + if (tso < 0) { + dev_kfree_skb_any(skb); + spin_unlock_irqrestore(&adapter->tx_queue_lock, irq_flags); + return NETDEV_TX_OK; + } + + if (tso) + tx_flags |= E1000_TX_FLAGS_TSO; + else if (e1000_tx_csum(adapter, skb)) + tx_flags |= E1000_TX_FLAGS_CSUM; + + /* Old method was to assume IPv4 packet by default if TSO was enabled. + * 82571 hardware supports TSO capabilities for IPv6 as well... + * no longer assume, we must. */ + if (skb->protocol == htons(ETH_P_IP)) + tx_flags |= E1000_TX_FLAGS_IPV4; + + count = e1000_tx_map(adapter, skb, first, max_per_txd, nr_frags, mss); + if (count < 0) { + /* handle pci_map_single() error in e1000_tx_map */ + dev_kfree_skb_any(skb); + spin_unlock_irqrestore(&adapter->tx_queue_lock, irq_flags); + return NETDEV_TX_BUSY; + } + + e1000_tx_queue(adapter, tx_flags, count); + + netdev->trans_start = jiffies; + + /* Make sure there is space in the ring for the next send. */ + e1000_maybe_stop_tx(netdev, MAX_SKB_FRAGS + 2); + + spin_unlock_irqrestore(&adapter->tx_queue_lock, irq_flags); + return NETDEV_TX_OK; +} + +/** + * e1000_tx_timeout - Respond to a Tx Hang + * @netdev: network interface device structure + **/ +static void e1000_tx_timeout(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + + /* Do the reset outside of interrupt context */ + adapter->tx_timeout_count++; + schedule_work(&adapter->reset_task); +} + +static void e1000_reset_task(struct work_struct *work) +{ + struct e1000_adapter *adapter; + adapter = container_of(work, struct e1000_adapter, reset_task); + + e1000e_reinit_locked(adapter); +} + +/** + * e1000_get_stats - Get System Network Statistics + * @netdev: network interface device structure + * + * Returns the address of the device statistics structure. + * The statistics are actually updated from the timer callback. + **/ +static struct net_device_stats *e1000_get_stats(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + + /* only return the current stats */ + return &adapter->net_stats; +} + +/** + * e1000_change_mtu - Change the Maximum Transfer Unit + * @netdev: network interface device structure + * @new_mtu: new value for maximum frame size + * + * Returns 0 on success, negative on failure + **/ +static int e1000_change_mtu(struct net_device *netdev, int new_mtu) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN; + + if ((max_frame < ETH_ZLEN + ETH_FCS_LEN) || + (max_frame > MAX_JUMBO_FRAME_SIZE)) { + ndev_err(netdev, "Invalid MTU setting\n"); + return -EINVAL; + } + + /* Jumbo frame size limits */ + if (max_frame > ETH_FRAME_LEN + ETH_FCS_LEN) { + if (!(adapter->flags & FLAG_HAS_JUMBO_FRAMES)) { + ndev_err(netdev, "Jumbo Frames not supported.\n"); + return -EINVAL; + } + if (adapter->hw.phy.type == e1000_phy_ife) { + ndev_err(netdev, "Jumbo Frames not supported.\n"); + return -EINVAL; + } + } + +#define MAX_STD_JUMBO_FRAME_SIZE 9234 + if (max_frame > MAX_STD_JUMBO_FRAME_SIZE) { + ndev_err(netdev, "MTU > 9216 not supported.\n"); + return -EINVAL; + } + + while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) + msleep(1); + /* e1000e_down has a dependency on max_frame_size */ + adapter->hw.mac.max_frame_size = max_frame; + if (netif_running(netdev)) + e1000e_down(adapter); + + /* NOTE: netdev_alloc_skb reserves 16 bytes, and typically NET_IP_ALIGN + * means we reserve 2 more, this pushes us to allocate from the next + * larger slab size. + * i.e. RXBUFFER_2048 --> size-4096 slab + * however with the new *_jumbo* routines, jumbo receives will use + * fragmented skbs */ + + if (max_frame <= 256) + adapter->rx_buffer_len = 256; + else if (max_frame <= 512) + adapter->rx_buffer_len = 512; + else if (max_frame <= 1024) + adapter->rx_buffer_len = 1024; + else if (max_frame <= 2048) + adapter->rx_buffer_len = 2048; + else + adapter->rx_buffer_len = 4096; + + /* adjust allocation if LPE protects us, and we aren't using SBP */ + if ((max_frame == ETH_FRAME_LEN + ETH_FCS_LEN) || + (max_frame == ETH_FRAME_LEN + VLAN_HLEN + ETH_FCS_LEN)) + adapter->rx_buffer_len = ETH_FRAME_LEN + VLAN_HLEN + + ETH_FCS_LEN ; + + ndev_info(netdev, "changing MTU from %d to %d\n", + netdev->mtu, new_mtu); + netdev->mtu = new_mtu; + + if (netif_running(netdev)) + e1000e_up(adapter); + else + e1000e_reset(adapter); + + clear_bit(__E1000_RESETTING, &adapter->state); + + return 0; +} + +static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, + int cmd) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + struct mii_ioctl_data *data = if_mii(ifr); + unsigned long irq_flags; + + if (adapter->hw.media_type != e1000_media_type_copper) + return -EOPNOTSUPP; + + switch (cmd) { + case SIOCGMIIPHY: + data->phy_id = adapter->hw.phy.addr; + break; + case SIOCGMIIREG: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + spin_lock_irqsave(&adapter->stats_lock, irq_flags); + if (e1e_rphy(&adapter->hw, data->reg_num & 0x1F, + &data->val_out)) { + spin_unlock_irqrestore(&adapter->stats_lock, irq_flags); + return -EIO; + } + spin_unlock_irqrestore(&adapter->stats_lock, irq_flags); + break; + case SIOCSMIIREG: + default: + return -EOPNOTSUPP; + } + return 0; +} + +static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) +{ + switch (cmd) { + case SIOCGMIIPHY: + case SIOCGMIIREG: + case SIOCSMIIREG: + return e1000_mii_ioctl(netdev, ifr, cmd); + default: + return -EOPNOTSUPP; + } +} + +static int e1000_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + u32 ctrl, ctrl_ext, rctl, status; + u32 wufc = adapter->wol; + int retval = 0; + + netif_device_detach(netdev); + + if (netif_running(netdev)) { + WARN_ON(test_bit(__E1000_RESETTING, &adapter->state)); + e1000e_down(adapter); + e1000_free_irq(adapter); + } + + retval = pci_save_state(pdev); + if (retval) + return retval; + + status = er32(STATUS); + if (status & E1000_STATUS_LU) + wufc &= ~E1000_WUFC_LNKC; + + if (wufc) { + e1000_setup_rctl(adapter); + e1000_set_multi(netdev); + + /* turn on all-multi mode if wake on multicast is enabled */ + if (wufc & E1000_WUFC_MC) { + rctl = er32(RCTL); + rctl |= E1000_RCTL_MPE; + ew32(RCTL, rctl); + } + + ctrl = er32(CTRL); + /* advertise wake from D3Cold */ + #define E1000_CTRL_ADVD3WUC 0x00100000 + /* phy power management enable */ + #define E1000_CTRL_EN_PHY_PWR_MGMT 0x00200000 + ctrl |= E1000_CTRL_ADVD3WUC | + E1000_CTRL_EN_PHY_PWR_MGMT; + ew32(CTRL, ctrl); + + if (adapter->hw.media_type == e1000_media_type_fiber || + adapter->hw.media_type == e1000_media_type_internal_serdes) { + /* keep the laser running in D3 */ + ctrl_ext = er32(CTRL_EXT); + ctrl_ext |= E1000_CTRL_EXT_SDP7_DATA; + ew32(CTRL_EXT, ctrl_ext); + } + + /* Allow time for pending master requests to run */ + e1000e_disable_pcie_master(&adapter->hw); + + ew32(WUC, E1000_WUC_PME_EN); + ew32(WUFC, wufc); + pci_enable_wake(pdev, PCI_D3hot, 1); + pci_enable_wake(pdev, PCI_D3cold, 1); + } else { + ew32(WUC, 0); + ew32(WUFC, 0); + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_enable_wake(pdev, PCI_D3cold, 0); + } + + e1000_release_manageability(adapter); + + /* make sure adapter isn't asleep if manageability is enabled */ + if (adapter->flags & FLAG_MNG_PT_ENABLED) { + pci_enable_wake(pdev, PCI_D3hot, 1); + pci_enable_wake(pdev, PCI_D3cold, 1); + } + + if (adapter->hw.phy.type == e1000_phy_igp_3) + e1000e_igp3_phy_powerdown_workaround_ich8lan(&adapter->hw); + + /* Release control of h/w to f/w. If f/w is AMT enabled, this + * would have already happened in close and is redundant. */ + e1000_release_hw_control(adapter); + + pci_disable_device(pdev); + + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + + return 0; +} + +#ifdef CONFIG_PM +static int e1000_resume(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + u32 err; + + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + err = pci_enable_device(pdev); + if (err) { + dev_err(&pdev->dev, + "Cannot enable PCI device from suspend\n"); + return err; + } + + pci_set_master(pdev); + + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_enable_wake(pdev, PCI_D3cold, 0); + + if (netif_running(netdev)) { + err = e1000_request_irq(adapter); + if (err) + return err; + } + + e1000e_power_up_phy(adapter); + e1000e_reset(adapter); + ew32(WUS, ~0); + + e1000_init_manageability(adapter); + + if (netif_running(netdev)) + e1000e_up(adapter); + + netif_device_attach(netdev); + + /* If the controller has AMT, do not set DRV_LOAD until the interface + * is up. For all other cases, let the f/w know that the h/w is now + * under the control of the driver. */ + if (!(adapter->flags & FLAG_HAS_AMT) || !e1000e_check_mng_mode(&adapter->hw)) + e1000_get_hw_control(adapter); + + return 0; +} +#endif + +static void e1000_shutdown(struct pci_dev *pdev) +{ + e1000_suspend(pdev, PMSG_SUSPEND); +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +/* + * Polling 'interrupt' - used by things like netconsole to send skbs + * without having to re-enable interrupts. It's not called while + * the interrupt routine is executing. + */ +static void e1000_netpoll(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + + disable_irq(adapter->pdev->irq); + e1000_intr(adapter->pdev->irq, netdev); + + e1000_clean_tx_irq(adapter); + + enable_irq(adapter->pdev->irq); +} +#endif + +/** + * e1000_io_error_detected - called when PCI error is detected + * @pdev: Pointer to PCI device + * @state: The current pci connection state + * + * This function is called after a PCI bus error affecting + * this device has been detected. + */ +static pci_ers_result_t e1000_io_error_detected(struct pci_dev *pdev, + pci_channel_state_t state) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct e1000_adapter *adapter = netdev_priv(netdev); + + netif_device_detach(netdev); + + if (netif_running(netdev)) + e1000e_down(adapter); + pci_disable_device(pdev); + + /* Request a slot slot reset. */ + return PCI_ERS_RESULT_NEED_RESET; +} + +/** + * e1000_io_slot_reset - called after the pci bus has been reset. + * @pdev: Pointer to PCI device + * + * Restart the card from scratch, as if from a cold-boot. Implementation + * resembles the first-half of the e1000_resume routine. + */ +static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + + if (pci_enable_device(pdev)) { + dev_err(&pdev->dev, + "Cannot re-enable PCI device after reset.\n"); + return PCI_ERS_RESULT_DISCONNECT; + } + pci_set_master(pdev); + + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_enable_wake(pdev, PCI_D3cold, 0); + + e1000e_reset(adapter); + ew32(WUS, ~0); + + return PCI_ERS_RESULT_RECOVERED; +} + +/** + * e1000_io_resume - called when traffic can start flowing again. + * @pdev: Pointer to PCI device + * + * This callback is called when the error recovery driver tells us that + * its OK to resume normal operation. Implementation resembles the + * second-half of the e1000_resume routine. + */ +static void e1000_io_resume(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct e1000_adapter *adapter = netdev_priv(netdev); + + e1000_init_manageability(adapter); + + if (netif_running(netdev)) { + if (e1000e_up(adapter)) { + dev_err(&pdev->dev, + "can't bring device back up after reset\n"); + return; + } + } + + netif_device_attach(netdev); + + /* If the controller has AMT, do not set DRV_LOAD until the interface + * is up. For all other cases, let the f/w know that the h/w is now + * under the control of the driver. */ + if (!(adapter->flags & FLAG_HAS_AMT) || + !e1000e_check_mng_mode(&adapter->hw)) + e1000_get_hw_control(adapter); + +} + +static void e1000_print_device_info(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + struct net_device *netdev = adapter->netdev; + u32 part_num; + + /* print bus type/speed/width info */ + ndev_info(netdev, "(PCI Express:2.5GB/s:%s) " + "%02x:%02x:%02x:%02x:%02x:%02x\n", + /* bus width */ + ((hw->bus.width == e1000_bus_width_pcie_x4) ? "Width x4" : + "Width x1"), + /* MAC address */ + netdev->dev_addr[0], netdev->dev_addr[1], + netdev->dev_addr[2], netdev->dev_addr[3], + netdev->dev_addr[4], netdev->dev_addr[5]); + ndev_info(netdev, "Intel(R) PRO/%s Network Connection\n", + (hw->phy.type == e1000_phy_ife) + ? "10/100" : "1000"); + e1000e_read_part_num(hw, &part_num); + ndev_info(netdev, "MAC: %d, PHY: %d, PBA No: %06x-%03x\n", + hw->mac.type, hw->phy.type, + (part_num >> 8), (part_num & 0xff)); +} + +/** + * e1000_probe - Device Initialization Routine + * @pdev: PCI device information struct + * @ent: entry in e1000_pci_tbl + * + * Returns 0 on success, negative on failure + * + * e1000_probe initializes an adapter identified by a pci_dev structure. + * The OS initialization, configuring of the adapter private structure, + * and a hardware reset occur. + **/ +static int __devinit e1000_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct net_device *netdev; + struct e1000_adapter *adapter; + struct e1000_hw *hw; + const struct e1000_info *ei = e1000_info_tbl[ent->driver_data]; + unsigned long mmio_start, mmio_len; + unsigned long flash_start, flash_len; + + static int cards_found; + int i, err, pci_using_dac; + u16 eeprom_data = 0; + u16 eeprom_apme_mask = E1000_EEPROM_APME; + + err = pci_enable_device(pdev); + if (err) + return err; + + pci_using_dac = 0; + err = pci_set_dma_mask(pdev, DMA_64BIT_MASK); + if (!err) { + err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); + if (!err) + pci_using_dac = 1; + } else { + err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (err) { + err = pci_set_consistent_dma_mask(pdev, + DMA_32BIT_MASK); + if (err) { + dev_err(&pdev->dev, "No usable DMA " + "configuration, aborting\n"); + goto err_dma; + } + } + } + + err = pci_request_regions(pdev, e1000e_driver_name); + if (err) + goto err_pci_reg; + + pci_set_master(pdev); + + err = -ENOMEM; + netdev = alloc_etherdev(sizeof(struct e1000_adapter)); + if (!netdev) + goto err_alloc_etherdev; + + SET_MODULE_OWNER(netdev); + SET_NETDEV_DEV(netdev, &pdev->dev); + + pci_set_drvdata(pdev, netdev); + adapter = netdev_priv(netdev); + hw = &adapter->hw; + adapter->netdev = netdev; + adapter->pdev = pdev; + adapter->ei = ei; + adapter->pba = ei->pba; + adapter->flags = ei->flags; + adapter->hw.adapter = adapter; + adapter->hw.mac.type = ei->mac; + adapter->msg_enable = (1 << NETIF_MSG_DRV | NETIF_MSG_PROBE) - 1; + + mmio_start = pci_resource_start(pdev, 0); + mmio_len = pci_resource_len(pdev, 0); + + err = -EIO; + adapter->hw.hw_addr = ioremap(mmio_start, mmio_len); + if (!adapter->hw.hw_addr) + goto err_ioremap; + + if ((adapter->flags & FLAG_HAS_FLASH) && + (pci_resource_flags(pdev, 1) & IORESOURCE_MEM)) { + flash_start = pci_resource_start(pdev, 1); + flash_len = pci_resource_len(pdev, 1); + adapter->hw.flash_address = ioremap(flash_start, flash_len); + if (!adapter->hw.flash_address) + goto err_flashmap; + } + + /* construct the net_device struct */ + netdev->open = &e1000_open; + netdev->stop = &e1000_close; + netdev->hard_start_xmit = &e1000_xmit_frame; + netdev->get_stats = &e1000_get_stats; + netdev->set_multicast_list = &e1000_set_multi; + netdev->set_mac_address = &e1000_set_mac; + netdev->change_mtu = &e1000_change_mtu; + netdev->do_ioctl = &e1000_ioctl; + e1000e_set_ethtool_ops(netdev); + netdev->tx_timeout = &e1000_tx_timeout; + netdev->watchdog_timeo = 5 * HZ; + netif_napi_add(netdev, &adapter->napi, e1000_clean, 64); + netdev->vlan_rx_register = e1000_vlan_rx_register; + netdev->vlan_rx_add_vid = e1000_vlan_rx_add_vid; + netdev->vlan_rx_kill_vid = e1000_vlan_rx_kill_vid; +#ifdef CONFIG_NET_POLL_CONTROLLER + netdev->poll_controller = e1000_netpoll; +#endif + strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1); + + netdev->mem_start = mmio_start; + netdev->mem_end = mmio_start + mmio_len; + + adapter->bd_number = cards_found++; + + /* setup adapter struct */ + err = e1000_sw_init(adapter); + if (err) + goto err_sw_init; + + err = -EIO; + + memcpy(&hw->mac.ops, ei->mac_ops, sizeof(hw->mac.ops)); + memcpy(&hw->nvm.ops, ei->nvm_ops, sizeof(hw->nvm.ops)); + memcpy(&hw->phy.ops, ei->phy_ops, sizeof(hw->phy.ops)); + + err = ei->get_invariants(adapter); + if (err) + goto err_hw_init; + + hw->mac.ops.get_bus_info(&adapter->hw); + + adapter->hw.phy.wait_for_link = 0; + + /* Copper options */ + if (adapter->hw.media_type == e1000_media_type_copper) { + adapter->hw.phy.mdix = AUTO_ALL_MODES; + adapter->hw.phy.disable_polarity_correction = 0; + adapter->hw.phy.ms_type = e1000_ms_hw_default; + } + + if (e1000_check_reset_block(&adapter->hw)) + ndev_info(netdev, + "PHY reset is blocked due to SOL/IDER session.\n"); + + netdev->features = NETIF_F_SG | + NETIF_F_HW_CSUM | + NETIF_F_HW_VLAN_TX | + NETIF_F_HW_VLAN_RX; + + if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER) + netdev->features |= NETIF_F_HW_VLAN_FILTER; + + netdev->features |= NETIF_F_TSO; + netdev->features |= NETIF_F_TSO6; + + if (pci_using_dac) + netdev->features |= NETIF_F_HIGHDMA; + + /* We should not be using LLTX anymore, but we are still TX faster with + * it. */ + netdev->features |= NETIF_F_LLTX; + + if (e1000e_enable_mng_pass_thru(&adapter->hw)) + adapter->flags |= FLAG_MNG_PT_ENABLED; + + /* before reading the NVM, reset the controller to + * put the device in a known good starting state */ + adapter->hw.mac.ops.reset_hw(&adapter->hw); + + /* + * systems with ASPM and others may see the checksum fail on the first + * attempt. Let's give it a few tries + */ + for (i = 0;; i++) { + if (e1000_validate_nvm_checksum(&adapter->hw) >= 0) + break; + if (i == 2) { + ndev_err(netdev, "The NVM Checksum Is Not Valid\n"); + err = -EIO; + goto err_eeprom; + } + } + + /* copy the MAC address out of the NVM */ + if (e1000e_read_mac_addr(&adapter->hw)) + ndev_err(netdev, "NVM Read Error while reading MAC address\n"); + + memcpy(netdev->dev_addr, adapter->hw.mac.addr, netdev->addr_len); + memcpy(netdev->perm_addr, adapter->hw.mac.addr, netdev->addr_len); + + if (!is_valid_ether_addr(netdev->perm_addr)) { + ndev_err(netdev, "Invalid MAC Address: " + "%02x:%02x:%02x:%02x:%02x:%02x\n", + netdev->perm_addr[0], netdev->perm_addr[1], + netdev->perm_addr[2], netdev->perm_addr[3], + netdev->perm_addr[4], netdev->perm_addr[5]); + err = -EIO; + goto err_eeprom; + } + + init_timer(&adapter->watchdog_timer); + adapter->watchdog_timer.function = &e1000_watchdog; + adapter->watchdog_timer.data = (unsigned long) adapter; + + init_timer(&adapter->phy_info_timer); + adapter->phy_info_timer.function = &e1000_update_phy_info; + adapter->phy_info_timer.data = (unsigned long) adapter; + + INIT_WORK(&adapter->reset_task, e1000_reset_task); + INIT_WORK(&adapter->watchdog_task, e1000_watchdog_task); + + e1000e_check_options(adapter); + + /* Initialize link parameters. User can change them with ethtool */ + adapter->hw.mac.autoneg = 1; + adapter->hw.mac.original_fc = e1000_fc_default; + adapter->hw.mac.fc = e1000_fc_default; + adapter->hw.phy.autoneg_advertised = 0x2f; + + /* ring size defaults */ + adapter->rx_ring->count = 256; + adapter->tx_ring->count = 256; + + /* + * Initial Wake on LAN setting - If APM wake is enabled in + * the EEPROM, enable the ACPI Magic Packet filter + */ + if (adapter->flags & FLAG_APME_IN_WUC) { + /* APME bit in EEPROM is mapped to WUC.APME */ + eeprom_data = er32(WUC); + eeprom_apme_mask = E1000_WUC_APME; + } else if (adapter->flags & FLAG_APME_IN_CTRL3) { + if (adapter->flags & FLAG_APME_CHECK_PORT_B && + (adapter->hw.bus.func == 1)) + e1000_read_nvm(&adapter->hw, + NVM_INIT_CONTROL3_PORT_B, 1, &eeprom_data); + else + e1000_read_nvm(&adapter->hw, + NVM_INIT_CONTROL3_PORT_A, 1, &eeprom_data); + } + + /* fetch WoL from EEPROM */ + if (eeprom_data & eeprom_apme_mask) + adapter->eeprom_wol |= E1000_WUFC_MAG; + + /* + * now that we have the eeprom settings, apply the special cases + * where the eeprom may be wrong or the board simply won't support + * wake on lan on a particular port + */ + if (!(adapter->flags & FLAG_HAS_WOL)) + adapter->eeprom_wol = 0; + + /* initialize the wol settings based on the eeprom settings */ + adapter->wol = adapter->eeprom_wol; + + /* reset the hardware with the new settings */ + e1000e_reset(adapter); + + /* If the controller has AMT, do not set DRV_LOAD until the interface + * is up. For all other cases, let the f/w know that the h/w is now + * under the control of the driver. */ + if (!(adapter->flags & FLAG_HAS_AMT) || + !e1000e_check_mng_mode(&adapter->hw)) + e1000_get_hw_control(adapter); + + /* tell the stack to leave us alone until e1000_open() is called */ + netif_carrier_off(netdev); + netif_stop_queue(netdev); + + strcpy(netdev->name, "eth%d"); + err = register_netdev(netdev); + if (err) + goto err_register; + + e1000_print_device_info(adapter); + + return 0; + +err_register: +err_hw_init: + e1000_release_hw_control(adapter); +err_eeprom: + if (!e1000_check_reset_block(&adapter->hw)) + e1000_phy_hw_reset(&adapter->hw); + + if (adapter->hw.flash_address) + iounmap(adapter->hw.flash_address); + +err_flashmap: + kfree(adapter->tx_ring); + kfree(adapter->rx_ring); +err_sw_init: + iounmap(adapter->hw.hw_addr); +err_ioremap: + free_netdev(netdev); +err_alloc_etherdev: + pci_release_regions(pdev); +err_pci_reg: +err_dma: + pci_disable_device(pdev); + return err; +} + +/** + * e1000_remove - Device Removal Routine + * @pdev: PCI device information struct + * + * e1000_remove is called by the PCI subsystem to alert the driver + * that it should release a PCI device. The could be caused by a + * Hot-Plug event, or because the driver is going to be removed from + * memory. + **/ +static void __devexit e1000_remove(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct e1000_adapter *adapter = netdev_priv(netdev); + + /* flush_scheduled work may reschedule our watchdog task, so + * explicitly disable watchdog tasks from being rescheduled */ + set_bit(__E1000_DOWN, &adapter->state); + del_timer_sync(&adapter->watchdog_timer); + del_timer_sync(&adapter->phy_info_timer); + + flush_scheduled_work(); + + e1000_release_manageability(adapter); + + /* Release control of h/w to f/w. If f/w is AMT enabled, this + * would have already happened in close and is redundant. */ + e1000_release_hw_control(adapter); + + unregister_netdev(netdev); + + if (!e1000_check_reset_block(&adapter->hw)) + e1000_phy_hw_reset(&adapter->hw); + + kfree(adapter->tx_ring); + kfree(adapter->rx_ring); + + iounmap(adapter->hw.hw_addr); + if (adapter->hw.flash_address) + iounmap(adapter->hw.flash_address); + pci_release_regions(pdev); + + free_netdev(netdev); + + pci_disable_device(pdev); +} + +/* PCI Error Recovery (ERS) */ +static struct pci_error_handlers e1000_err_handler = { + .error_detected = e1000_io_error_detected, + .slot_reset = e1000_io_slot_reset, + .resume = e1000_io_resume, +}; + +static struct pci_device_id e1000_pci_tbl[] = { + /* + * Support for 82571/2/3, es2lan and ich8 will be phased in + * stepwise. + + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_COPPER), board_82571 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_FIBER), board_82571 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_COPPER), board_82571 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_COPPER_LP), board_82571 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_FIBER), board_82571 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_SERDES), board_82571 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI), board_82572 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI_COPPER), board_82572 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI_FIBER), board_82572 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI_SERDES), board_82572 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82573E), board_82573 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82573E_IAMT), board_82573 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82573L), board_82573 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_COPPER_DPT), + board_80003es2lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_COPPER_SPT), + board_80003es2lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_SERDES_DPT), + board_80003es2lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_SERDES_SPT), + board_80003es2lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IFE), board_ich8lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IFE_G), board_ich8lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IFE_GT), board_ich8lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IGP_AMT), board_ich8lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IGP_C), board_ich8lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IGP_M), board_ich8lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IGP_M_AMT), board_ich8lan }, + */ + + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IFE), board_ich9lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IFE_G), board_ich9lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IFE_GT), board_ich9lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_AMT), board_ich9lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_C), board_ich9lan }, + + { } /* terminate list */ +}; +MODULE_DEVICE_TABLE(pci, e1000_pci_tbl); + +/* PCI Device API Driver */ +static struct pci_driver e1000_driver = { + .name = e1000e_driver_name, + .id_table = e1000_pci_tbl, + .probe = e1000_probe, + .remove = __devexit_p(e1000_remove), +#ifdef CONFIG_PM + /* Power Managment Hooks */ + .suspend = e1000_suspend, + .resume = e1000_resume, +#endif + .shutdown = e1000_shutdown, + .err_handler = &e1000_err_handler +}; + +/** + * e1000_init_module - Driver Registration Routine + * + * e1000_init_module is the first routine called when the driver is + * loaded. All it does is register with the PCI subsystem. + **/ +static int __init e1000_init_module(void) +{ + int ret; + printk(KERN_INFO "%s: Intel(R) PRO/1000 Network Driver - %s\n", + e1000e_driver_name, e1000e_driver_version); + printk(KERN_INFO "%s: Copyright (c) 1999-2007 Intel Corporation.\n", + e1000e_driver_name); + ret = pci_register_driver(&e1000_driver); + + return ret; +} +module_init(e1000_init_module); + +/** + * e1000_exit_module - Driver Exit Cleanup Routine + * + * e1000_exit_module is called just before the driver is removed + * from memory. + **/ +static void __exit e1000_exit_module(void) +{ + pci_unregister_driver(&e1000_driver); +} +module_exit(e1000_exit_module); + + +MODULE_AUTHOR("Intel Corporation, "); +MODULE_DESCRIPTION("Intel(R) PRO/1000 Network Driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); + +/* e1000_main.c */ diff --git a/drivers/net/e1000e/param.c b/drivers/net/e1000e/param.c new file mode 100644 index 00000000000..e4e655efb23 --- /dev/null +++ b/drivers/net/e1000e/param.c @@ -0,0 +1,382 @@ +/******************************************************************************* + + Intel PRO/1000 Linux driver + Copyright(c) 1999 - 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#include + +#include "e1000.h" + +/* This is the only thing that needs to be changed to adjust the + * maximum number of ports that the driver can manage. + */ + +#define E1000_MAX_NIC 32 + +#define OPTION_UNSET -1 +#define OPTION_DISABLED 0 +#define OPTION_ENABLED 1 + +#define COPYBREAK_DEFAULT 256 +unsigned int copybreak = COPYBREAK_DEFAULT; +module_param(copybreak, uint, 0644); +MODULE_PARM_DESC(copybreak, + "Maximum size of packet that is copied to a new buffer on receive"); + +/* All parameters are treated the same, as an integer array of values. + * This macro just reduces the need to repeat the same declaration code + * over and over (plus this helps to avoid typo bugs). + */ + +#define E1000_PARAM_INIT { [0 ... E1000_MAX_NIC] = OPTION_UNSET } +#define E1000_PARAM(X, desc) \ + static int __devinitdata X[E1000_MAX_NIC+1] = E1000_PARAM_INIT; \ + static int num_##X; \ + module_param_array_named(X, X, int, &num_##X, 0); \ + MODULE_PARM_DESC(X, desc); + + +/* Transmit Interrupt Delay in units of 1.024 microseconds + * Tx interrupt delay needs to typically be set to something non zero + * + * Valid Range: 0-65535 + */ +E1000_PARAM(TxIntDelay, "Transmit Interrupt Delay"); +#define DEFAULT_TIDV 8 +#define MAX_TXDELAY 0xFFFF +#define MIN_TXDELAY 0 + +/* Transmit Absolute Interrupt Delay in units of 1.024 microseconds + * + * Valid Range: 0-65535 + */ +E1000_PARAM(TxAbsIntDelay, "Transmit Absolute Interrupt Delay"); +#define DEFAULT_TADV 32 +#define MAX_TXABSDELAY 0xFFFF +#define MIN_TXABSDELAY 0 + +/* Receive Interrupt Delay in units of 1.024 microseconds + * hardware will likely hang if you set this to anything but zero. + * + * Valid Range: 0-65535 + */ +E1000_PARAM(RxIntDelay, "Receive Interrupt Delay"); +#define DEFAULT_RDTR 0 +#define MAX_RXDELAY 0xFFFF +#define MIN_RXDELAY 0 + +/* Receive Absolute Interrupt Delay in units of 1.024 microseconds + * + * Valid Range: 0-65535 + */ +E1000_PARAM(RxAbsIntDelay, "Receive Absolute Interrupt Delay"); +#define DEFAULT_RADV 8 +#define MAX_RXABSDELAY 0xFFFF +#define MIN_RXABSDELAY 0 + +/* Interrupt Throttle Rate (interrupts/sec) + * + * Valid Range: 100-100000 (0=off, 1=dynamic, 3=dynamic conservative) + */ +E1000_PARAM(InterruptThrottleRate, "Interrupt Throttling Rate"); +#define DEFAULT_ITR 3 +#define MAX_ITR 100000 +#define MIN_ITR 100 + +/* Enable Smart Power Down of the PHY + * + * Valid Range: 0, 1 + * + * Default Value: 0 (disabled) + */ +E1000_PARAM(SmartPowerDownEnable, "Enable PHY smart power down"); + +/* Enable Kumeran Lock Loss workaround + * + * Valid Range: 0, 1 + * + * Default Value: 1 (enabled) + */ +E1000_PARAM(KumeranLockLoss, "Enable Kumeran lock loss workaround"); + +struct e1000_option { + enum { enable_option, range_option, list_option } type; + char *name; + char *err; + int def; + union { + struct { /* range_option info */ + int min; + int max; + } r; + struct { /* list_option info */ + int nr; + struct e1000_opt_list { int i; char *str; } *p; + } l; + } arg; +}; + +static int __devinit e1000_validate_option(int *value, + struct e1000_option *opt, + struct e1000_adapter *adapter) +{ + if (*value == OPTION_UNSET) { + *value = opt->def; + return 0; + } + + switch (opt->type) { + case enable_option: + switch (*value) { + case OPTION_ENABLED: + ndev_info(adapter->netdev, "%s Enabled\n", opt->name); + return 0; + case OPTION_DISABLED: + ndev_info(adapter->netdev, "%s Disabled\n", opt->name); + return 0; + } + break; + case range_option: + if (*value >= opt->arg.r.min && *value <= opt->arg.r.max) { + ndev_info(adapter->netdev, + "%s set to %i\n", opt->name, *value); + return 0; + } + break; + case list_option: { + int i; + struct e1000_opt_list *ent; + + for (i = 0; i < opt->arg.l.nr; i++) { + ent = &opt->arg.l.p[i]; + if (*value == ent->i) { + if (ent->str[0] != '\0') + ndev_info(adapter->netdev, "%s\n", + ent->str); + return 0; + } + } + } + break; + default: + BUG(); + } + + ndev_info(adapter->netdev, "Invalid %s value specified (%i) %s\n", + opt->name, *value, opt->err); + *value = opt->def; + return -1; +} + +/** + * e1000e_check_options - Range Checking for Command Line Parameters + * @adapter: board private structure + * + * This routine checks all command line parameters for valid user + * input. If an invalid value is given, or if no user specified + * value exists, a default value is used. The final value is stored + * in a variable in the adapter structure. + **/ +void __devinit e1000e_check_options(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + struct net_device *netdev = adapter->netdev; + int bd = adapter->bd_number; + + if (bd >= E1000_MAX_NIC) { + ndev_notice(netdev, + "Warning: no configuration for board #%i\n", bd); + ndev_notice(netdev, "Using defaults for all values\n"); + } + + { /* Transmit Interrupt Delay */ + struct e1000_option opt = { + .type = range_option, + .name = "Transmit Interrupt Delay", + .err = "using default of " + __MODULE_STRING(DEFAULT_TIDV), + .def = DEFAULT_TIDV, + .arg = { .r = { .min = MIN_TXDELAY, + .max = MAX_TXDELAY } } + }; + + if (num_TxIntDelay > bd) { + adapter->tx_int_delay = TxIntDelay[bd]; + e1000_validate_option(&adapter->tx_int_delay, &opt, + adapter); + } else { + adapter->tx_int_delay = opt.def; + } + } + { /* Transmit Absolute Interrupt Delay */ + struct e1000_option opt = { + .type = range_option, + .name = "Transmit Absolute Interrupt Delay", + .err = "using default of " + __MODULE_STRING(DEFAULT_TADV), + .def = DEFAULT_TADV, + .arg = { .r = { .min = MIN_TXABSDELAY, + .max = MAX_TXABSDELAY } } + }; + + if (num_TxAbsIntDelay > bd) { + adapter->tx_abs_int_delay = TxAbsIntDelay[bd]; + e1000_validate_option(&adapter->tx_abs_int_delay, &opt, + adapter); + } else { + adapter->tx_abs_int_delay = opt.def; + } + } + { /* Receive Interrupt Delay */ + struct e1000_option opt = { + .type = range_option, + .name = "Receive Interrupt Delay", + .err = "using default of " + __MODULE_STRING(DEFAULT_RDTR), + .def = DEFAULT_RDTR, + .arg = { .r = { .min = MIN_RXDELAY, + .max = MAX_RXDELAY } } + }; + + /* modify min and default if 82573 for slow ping w/a, + * a value greater than 8 needs to be set for RDTR */ + if (adapter->flags & FLAG_HAS_ASPM) { + opt.def = 32; + opt.arg.r.min = 8; + } + + if (num_RxIntDelay > bd) { + adapter->rx_int_delay = RxIntDelay[bd]; + e1000_validate_option(&adapter->rx_int_delay, &opt, + adapter); + } else { + adapter->rx_int_delay = opt.def; + } + } + { /* Receive Absolute Interrupt Delay */ + struct e1000_option opt = { + .type = range_option, + .name = "Receive Absolute Interrupt Delay", + .err = "using default of " + __MODULE_STRING(DEFAULT_RADV), + .def = DEFAULT_RADV, + .arg = { .r = { .min = MIN_RXABSDELAY, + .max = MAX_RXABSDELAY } } + }; + + if (num_RxAbsIntDelay > bd) { + adapter->rx_abs_int_delay = RxAbsIntDelay[bd]; + e1000_validate_option(&adapter->rx_abs_int_delay, &opt, + adapter); + } else { + adapter->rx_abs_int_delay = opt.def; + } + } + { /* Interrupt Throttling Rate */ + struct e1000_option opt = { + .type = range_option, + .name = "Interrupt Throttling Rate (ints/sec)", + .err = "using default of " + __MODULE_STRING(DEFAULT_ITR), + .def = DEFAULT_ITR, + .arg = { .r = { .min = MIN_ITR, + .max = MAX_ITR } } + }; + + if (num_InterruptThrottleRate > bd) { + adapter->itr = InterruptThrottleRate[bd]; + switch (adapter->itr) { + case 0: + ndev_info(netdev, "%s turned off\n", + opt.name); + break; + case 1: + ndev_info(netdev, + "%s set to dynamic mode\n", + opt.name); + adapter->itr_setting = adapter->itr; + adapter->itr = 20000; + break; + case 3: + ndev_info(netdev, + "%s set to dynamic conservative mode\n", + opt.name); + adapter->itr_setting = adapter->itr; + adapter->itr = 20000; + break; + default: + e1000_validate_option(&adapter->itr, &opt, + adapter); + /* + * save the setting, because the dynamic bits + * change itr. clear the lower two bits + * because they are used as control + */ + adapter->itr_setting = adapter->itr & ~3; + break; + } + } else { + adapter->itr_setting = opt.def; + adapter->itr = 20000; + } + } + { /* Smart Power Down */ + struct e1000_option opt = { + .type = enable_option, + .name = "PHY Smart Power Down", + .err = "defaulting to Disabled", + .def = OPTION_DISABLED + }; + + if (num_SmartPowerDownEnable > bd) { + int spd = SmartPowerDownEnable[bd]; + e1000_validate_option(&spd, &opt, adapter); + if ((adapter->flags & FLAG_HAS_SMART_POWER_DOWN) + && spd) + adapter->flags |= FLAG_SMART_POWER_DOWN; + } + } + { /* Kumeran Lock Loss Workaround */ + struct e1000_option opt = { + .type = enable_option, + .name = "Kumeran Lock Loss Workaround", + .err = "defaulting to Enabled", + .def = OPTION_ENABLED + }; + + if (num_KumeranLockLoss > bd) { + int kmrn_lock_loss = KumeranLockLoss[bd]; + e1000_validate_option(&kmrn_lock_loss, &opt, adapter); + if (hw->mac.type == e1000_ich8lan) + e1000e_set_kmrn_lock_loss_workaround_ich8lan(hw, + kmrn_lock_loss); + } else { + if (hw->mac.type == e1000_ich8lan) + e1000e_set_kmrn_lock_loss_workaround_ich8lan(hw, + opt.def); + } + } +} diff --git a/drivers/net/e1000e/phy.c b/drivers/net/e1000e/phy.c new file mode 100644 index 00000000000..793231810ae --- /dev/null +++ b/drivers/net/e1000e/phy.c @@ -0,0 +1,1773 @@ +/******************************************************************************* + + Intel PRO/1000 Linux driver + Copyright(c) 1999 - 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#include + +#include "e1000.h" + +static s32 e1000_get_phy_cfg_done(struct e1000_hw *hw); +static s32 e1000_phy_force_speed_duplex(struct e1000_hw *hw); +static s32 e1000_set_d0_lplu_state(struct e1000_hw *hw, bool active); +static s32 e1000_wait_autoneg(struct e1000_hw *hw); + +/* Cable length tables */ +static const u16 e1000_m88_cable_length_table[] = + { 0, 50, 80, 110, 140, 140, E1000_CABLE_LENGTH_UNDEFINED }; + +static const u16 e1000_igp_2_cable_length_table[] = + { 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11, 13, 16, 18, 21, 0, 0, 0, 3, + 6, 10, 13, 16, 19, 23, 26, 29, 32, 35, 38, 41, 6, 10, 14, 18, 22, + 26, 30, 33, 37, 41, 44, 48, 51, 54, 58, 61, 21, 26, 31, 35, 40, + 44, 49, 53, 57, 61, 65, 68, 72, 75, 79, 82, 40, 45, 51, 56, 61, + 66, 70, 75, 79, 83, 87, 91, 94, 98, 101, 104, 60, 66, 72, 77, 82, + 87, 92, 96, 100, 104, 108, 111, 114, 117, 119, 121, 83, 89, 95, + 100, 105, 109, 113, 116, 119, 122, 124, 104, 109, 114, 118, 121, + 124}; +#define IGP02E1000_CABLE_LENGTH_TABLE_SIZE \ + (sizeof(e1000_igp_2_cable_length_table) / \ + sizeof(e1000_igp_2_cable_length_table[0])) + +/** + * e1000e_check_reset_block_generic - Check if PHY reset is blocked + * @hw: pointer to the HW structure + * + * Read the PHY management control register and check whether a PHY reset + * is blocked. If a reset is not blocked return 0, otherwise + * return E1000_BLK_PHY_RESET (12). + **/ +s32 e1000e_check_reset_block_generic(struct e1000_hw *hw) +{ + u32 manc; + + manc = er32(MANC); + + return (manc & E1000_MANC_BLK_PHY_RST_ON_IDE) ? + E1000_BLK_PHY_RESET : 0; +} + +/** + * e1000e_get_phy_id - Retrieve the PHY ID and revision + * @hw: pointer to the HW structure + * + * Reads the PHY registers and stores the PHY ID and possibly the PHY + * revision in the hardware structure. + **/ +s32 e1000e_get_phy_id(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_id; + + ret_val = e1e_rphy(hw, PHY_ID1, &phy_id); + if (ret_val) + return ret_val; + + phy->id = (u32)(phy_id << 16); + udelay(20); + ret_val = e1e_rphy(hw, PHY_ID2, &phy_id); + if (ret_val) + return ret_val; + + phy->id |= (u32)(phy_id & PHY_REVISION_MASK); + phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK); + + return 0; +} + +/** + * e1000e_phy_reset_dsp - Reset PHY DSP + * @hw: pointer to the HW structure + * + * Reset the digital signal processor. + **/ +s32 e1000e_phy_reset_dsp(struct e1000_hw *hw) +{ + s32 ret_val; + + ret_val = e1e_wphy(hw, M88E1000_PHY_GEN_CONTROL, 0xC1); + if (ret_val) + return ret_val; + + return e1e_wphy(hw, M88E1000_PHY_GEN_CONTROL, 0); +} + +/** + * e1000_read_phy_reg_mdic - Read MDI control register + * @hw: pointer to the HW structure + * @offset: register offset to be read + * @data: pointer to the read data + * + * Reads the MDI control regsiter in the PHY at offset and stores the + * information read to data. + **/ +static s32 e1000_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data) +{ + struct e1000_phy_info *phy = &hw->phy; + u32 i, mdic = 0; + + if (offset > MAX_PHY_REG_ADDRESS) { + hw_dbg(hw, "PHY Address %d is out of range\n", offset); + return -E1000_ERR_PARAM; + } + + /* Set up Op-code, Phy Address, and register offset in the MDI + * Control register. The MAC will take care of interfacing with the + * PHY to retrieve the desired data. + */ + mdic = ((offset << E1000_MDIC_REG_SHIFT) | + (phy->addr << E1000_MDIC_PHY_SHIFT) | + (E1000_MDIC_OP_READ)); + + ew32(MDIC, mdic); + + /* Poll the ready bit to see if the MDI read completed */ + for (i = 0; i < 64; i++) { + udelay(50); + mdic = er32(MDIC); + if (mdic & E1000_MDIC_READY) + break; + } + if (!(mdic & E1000_MDIC_READY)) { + hw_dbg(hw, "MDI Read did not complete\n"); + return -E1000_ERR_PHY; + } + if (mdic & E1000_MDIC_ERROR) { + hw_dbg(hw, "MDI Error\n"); + return -E1000_ERR_PHY; + } + *data = (u16) mdic; + + return 0; +} + +/** + * e1000_write_phy_reg_mdic - Write MDI control register + * @hw: pointer to the HW structure + * @offset: register offset to write to + * @data: data to write to register at offset + * + * Writes data to MDI control register in the PHY at offset. + **/ +static s32 e1000_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data) +{ + struct e1000_phy_info *phy = &hw->phy; + u32 i, mdic = 0; + + if (offset > MAX_PHY_REG_ADDRESS) { + hw_dbg(hw, "PHY Address %d is out of range\n", offset); + return -E1000_ERR_PARAM; + } + + /* Set up Op-code, Phy Address, and register offset in the MDI + * Control register. The MAC will take care of interfacing with the + * PHY to retrieve the desired data. + */ + mdic = (((u32)data) | + (offset << E1000_MDIC_REG_SHIFT) | + (phy->addr << E1000_MDIC_PHY_SHIFT) | + (E1000_MDIC_OP_WRITE)); + + ew32(MDIC, mdic); + + /* Poll the ready bit to see if the MDI read completed */ + for (i = 0; i < E1000_GEN_POLL_TIMEOUT; i++) { + udelay(5); + mdic = er32(MDIC); + if (mdic & E1000_MDIC_READY) + break; + } + if (!(mdic & E1000_MDIC_READY)) { + hw_dbg(hw, "MDI Write did not complete\n"); + return -E1000_ERR_PHY; + } + + return 0; +} + +/** + * e1000e_read_phy_reg_m88 - Read m88 PHY register + * @hw: pointer to the HW structure + * @offset: register offset to be read + * @data: pointer to the read data + * + * Acquires semaphore, if necessary, then reads the PHY register at offset + * and storing the retrieved information in data. Release any acquired + * semaphores before exiting. + **/ +s32 e1000e_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data) +{ + s32 ret_val; + + ret_val = hw->phy.ops.acquire_phy(hw); + if (ret_val) + return ret_val; + + ret_val = e1000_read_phy_reg_mdic(hw, + MAX_PHY_REG_ADDRESS & offset, + data); + + hw->phy.ops.release_phy(hw); + + return ret_val; +} + +/** + * e1000e_write_phy_reg_m88 - Write m88 PHY register + * @hw: pointer to the HW structure + * @offset: register offset to write to + * @data: data to write at register offset + * + * Acquires semaphore, if necessary, then writes the data to PHY register + * at the offset. Release any acquired semaphores before exiting. + **/ +s32 e1000e_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data) +{ + s32 ret_val; + + ret_val = hw->phy.ops.acquire_phy(hw); + if (ret_val) + return ret_val; + + ret_val = e1000_write_phy_reg_mdic(hw, + MAX_PHY_REG_ADDRESS & offset, + data); + + hw->phy.ops.release_phy(hw); + + return ret_val; +} + +/** + * e1000e_read_phy_reg_igp - Read igp PHY register + * @hw: pointer to the HW structure + * @offset: register offset to be read + * @data: pointer to the read data + * + * Acquires semaphore, if necessary, then reads the PHY register at offset + * and storing the retrieved information in data. Release any acquired + * semaphores before exiting. + **/ +s32 e1000e_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data) +{ + s32 ret_val; + + ret_val = hw->phy.ops.acquire_phy(hw); + if (ret_val) + return ret_val; + + if (offset > MAX_PHY_MULTI_PAGE_REG) { + ret_val = e1000_write_phy_reg_mdic(hw, + IGP01E1000_PHY_PAGE_SELECT, + (u16)offset); + if (ret_val) { + hw->phy.ops.release_phy(hw); + return ret_val; + } + } + + ret_val = e1000_read_phy_reg_mdic(hw, + MAX_PHY_REG_ADDRESS & offset, + data); + + hw->phy.ops.release_phy(hw); + + return ret_val; +} + +/** + * e1000e_write_phy_reg_igp - Write igp PHY register + * @hw: pointer to the HW structure + * @offset: register offset to write to + * @data: data to write at register offset + * + * Acquires semaphore, if necessary, then writes the data to PHY register + * at the offset. Release any acquired semaphores before exiting. + **/ +s32 e1000e_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data) +{ + s32 ret_val; + + ret_val = hw->phy.ops.acquire_phy(hw); + if (ret_val) + return ret_val; + + if (offset > MAX_PHY_MULTI_PAGE_REG) { + ret_val = e1000_write_phy_reg_mdic(hw, + IGP01E1000_PHY_PAGE_SELECT, + (u16)offset); + if (ret_val) { + hw->phy.ops.release_phy(hw); + return ret_val; + } + } + + ret_val = e1000_write_phy_reg_mdic(hw, + MAX_PHY_REG_ADDRESS & offset, + data); + + hw->phy.ops.release_phy(hw); + + return ret_val; +} + +/** + * e1000e_read_kmrn_reg - Read kumeran register + * @hw: pointer to the HW structure + * @offset: register offset to be read + * @data: pointer to the read data + * + * Acquires semaphore, if necessary. Then reads the PHY register at offset + * using the kumeran interface. The information retrieved is stored in data. + * Release any acquired semaphores before exiting. + **/ +s32 e1000e_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data) +{ + u32 kmrnctrlsta; + s32 ret_val; + + ret_val = hw->phy.ops.acquire_phy(hw); + if (ret_val) + return ret_val; + + kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) & + E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN; + ew32(KMRNCTRLSTA, kmrnctrlsta); + + udelay(2); + + kmrnctrlsta = er32(KMRNCTRLSTA); + *data = (u16)kmrnctrlsta; + + hw->phy.ops.release_phy(hw); + + return ret_val; +} + +/** + * e1000e_write_kmrn_reg - Write kumeran register + * @hw: pointer to the HW structure + * @offset: register offset to write to + * @data: data to write at register offset + * + * Acquires semaphore, if necessary. Then write the data to PHY register + * at the offset using the kumeran interface. Release any acquired semaphores + * before exiting. + **/ +s32 e1000e_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data) +{ + u32 kmrnctrlsta; + s32 ret_val; + + ret_val = hw->phy.ops.acquire_phy(hw); + if (ret_val) + return ret_val; + + kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) & + E1000_KMRNCTRLSTA_OFFSET) | data; + ew32(KMRNCTRLSTA, kmrnctrlsta); + + udelay(2); + hw->phy.ops.release_phy(hw); + + return ret_val; +} + +/** + * e1000e_copper_link_setup_m88 - Setup m88 PHY's for copper link + * @hw: pointer to the HW structure + * + * Sets up MDI/MDI-X and polarity for m88 PHY's. If necessary, transmit clock + * and downshift values are set also. + **/ +s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_data; + + /* Enable CRS on TX. This must be set for half-duplex operation. */ + ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); + if (ret_val) + return ret_val; + + phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; + + /* Options: + * MDI/MDI-X = 0 (default) + * 0 - Auto for all speeds + * 1 - MDI mode + * 2 - MDI-X mode + * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes) + */ + phy_data &= ~M88E1000_PSCR_AUTO_X_MODE; + + switch (phy->mdix) { + case 1: + phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE; + break; + case 2: + phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE; + break; + case 3: + phy_data |= M88E1000_PSCR_AUTO_X_1000T; + break; + case 0: + default: + phy_data |= M88E1000_PSCR_AUTO_X_MODE; + break; + } + + /* Options: + * disable_polarity_correction = 0 (default) + * Automatic Correction for Reversed Cable Polarity + * 0 - Disabled + * 1 - Enabled + */ + phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL; + if (phy->disable_polarity_correction == 1) + phy_data |= M88E1000_PSCR_POLARITY_REVERSAL; + + ret_val = e1e_wphy(hw, M88E1000_PHY_SPEC_CTRL, phy_data); + if (ret_val) + return ret_val; + + if (phy->revision < 4) { + /* Force TX_CLK in the Extended PHY Specific Control Register + * to 25MHz clock. + */ + ret_val = e1e_rphy(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data); + if (ret_val) + return ret_val; + + phy_data |= M88E1000_EPSCR_TX_CLK_25; + + if ((phy->revision == 2) && + (phy->id == M88E1111_I_PHY_ID)) { + /* 82573L PHY - set the downshift counter to 5x. */ + phy_data &= ~M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK; + phy_data |= M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X; + } else { + /* Configure Master and Slave downshift values */ + phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK | + M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK); + phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X | + M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X); + } + ret_val = e1e_wphy(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data); + if (ret_val) + return ret_val; + } + + /* Commit the changes. */ + ret_val = e1000e_commit_phy(hw); + if (ret_val) + hw_dbg(hw, "Error committing the PHY changes\n"); + + return ret_val; +} + +/** + * e1000e_copper_link_setup_igp - Setup igp PHY's for copper link + * @hw: pointer to the HW structure + * + * Sets up LPLU, MDI/MDI-X, polarity, Smartspeed and Master/Slave config for + * igp PHY's. + **/ +s32 e1000e_copper_link_setup_igp(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 data; + + ret_val = e1000_phy_hw_reset(hw); + if (ret_val) { + hw_dbg(hw, "Error resetting the PHY.\n"); + return ret_val; + } + + /* Wait 15ms for MAC to configure PHY from NVM settings. */ + msleep(15); + + /* disable lplu d0 during driver init */ + ret_val = e1000_set_d0_lplu_state(hw, 0); + if (ret_val) { + hw_dbg(hw, "Error Disabling LPLU D0\n"); + return ret_val; + } + /* Configure mdi-mdix settings */ + ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CTRL, &data); + if (ret_val) + return ret_val; + + data &= ~IGP01E1000_PSCR_AUTO_MDIX; + + switch (phy->mdix) { + case 1: + data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX; + break; + case 2: + data |= IGP01E1000_PSCR_FORCE_MDI_MDIX; + break; + case 0: + default: + data |= IGP01E1000_PSCR_AUTO_MDIX; + break; + } + ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CTRL, data); + if (ret_val) + return ret_val; + + /* set auto-master slave resolution settings */ + if (hw->mac.autoneg) { + /* when autonegotiation advertisement is only 1000Mbps then we + * should disable SmartSpeed and enable Auto MasterSlave + * resolution as hardware default. */ + if (phy->autoneg_advertised == ADVERTISE_1000_FULL) { + /* Disable SmartSpeed */ + ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG, + &data); + if (ret_val) + return ret_val; + + data &= ~IGP01E1000_PSCFR_SMART_SPEED; + ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG, + data); + if (ret_val) + return ret_val; + + /* Set auto Master/Slave resolution process */ + ret_val = e1e_rphy(hw, PHY_1000T_CTRL, &data); + if (ret_val) + return ret_val; + + data &= ~CR_1000T_MS_ENABLE; + ret_val = e1e_wphy(hw, PHY_1000T_CTRL, data); + if (ret_val) + return ret_val; + } + + ret_val = e1e_rphy(hw, PHY_1000T_CTRL, &data); + if (ret_val) + return ret_val; + + /* load defaults for future use */ + phy->original_ms_type = (data & CR_1000T_MS_ENABLE) ? + ((data & CR_1000T_MS_VALUE) ? + e1000_ms_force_master : + e1000_ms_force_slave) : + e1000_ms_auto; + + switch (phy->ms_type) { + case e1000_ms_force_master: + data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE); + break; + case e1000_ms_force_slave: + data |= CR_1000T_MS_ENABLE; + data &= ~(CR_1000T_MS_VALUE); + break; + case e1000_ms_auto: + data &= ~CR_1000T_MS_ENABLE; + default: + break; + } + ret_val = e1e_wphy(hw, PHY_1000T_CTRL, data); + } + + return ret_val; +} + +/** + * e1000_phy_setup_autoneg - Configure PHY for auto-negotiation + * @hw: pointer to the HW structure + * + * Reads the MII auto-neg advertisement register and/or the 1000T control + * register and if the PHY is already setup for auto-negotiation, then + * return successful. Otherwise, setup advertisement and flow control to + * the appropriate values for the wanted auto-negotiation. + **/ +static s32 e1000_phy_setup_autoneg(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 mii_autoneg_adv_reg; + u16 mii_1000t_ctrl_reg = 0; + + phy->autoneg_advertised &= phy->autoneg_mask; + + /* Read the MII Auto-Neg Advertisement Register (Address 4). */ + ret_val = e1e_rphy(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg); + if (ret_val) + return ret_val; + + if (phy->autoneg_mask & ADVERTISE_1000_FULL) { + /* Read the MII 1000Base-T Control Register (Address 9). */ + ret_val = e1e_rphy(hw, PHY_1000T_CTRL, &mii_1000t_ctrl_reg); + if (ret_val) + return ret_val; + } + + /* Need to parse both autoneg_advertised and fc and set up + * the appropriate PHY registers. First we will parse for + * autoneg_advertised software override. Since we can advertise + * a plethora of combinations, we need to check each bit + * individually. + */ + + /* First we clear all the 10/100 mb speed bits in the Auto-Neg + * Advertisement Register (Address 4) and the 1000 mb speed bits in + * the 1000Base-T Control Register (Address 9). + */ + mii_autoneg_adv_reg &= ~(NWAY_AR_100TX_FD_CAPS | + NWAY_AR_100TX_HD_CAPS | + NWAY_AR_10T_FD_CAPS | + NWAY_AR_10T_HD_CAPS); + mii_1000t_ctrl_reg &= ~(CR_1000T_HD_CAPS | CR_1000T_FD_CAPS); + + hw_dbg(hw, "autoneg_advertised %x\n", phy->autoneg_advertised); + + /* Do we want to advertise 10 Mb Half Duplex? */ + if (phy->autoneg_advertised & ADVERTISE_10_HALF) { + hw_dbg(hw, "Advertise 10mb Half duplex\n"); + mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS; + } + + /* Do we want to advertise 10 Mb Full Duplex? */ + if (phy->autoneg_advertised & ADVERTISE_10_FULL) { + hw_dbg(hw, "Advertise 10mb Full duplex\n"); + mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS; + } + + /* Do we want to advertise 100 Mb Half Duplex? */ + if (phy->autoneg_advertised & ADVERTISE_100_HALF) { + hw_dbg(hw, "Advertise 100mb Half duplex\n"); + mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS; + } + + /* Do we want to advertise 100 Mb Full Duplex? */ + if (phy->autoneg_advertised & ADVERTISE_100_FULL) { + hw_dbg(hw, "Advertise 100mb Full duplex\n"); + mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS; + } + + /* We do not allow the Phy to advertise 1000 Mb Half Duplex */ + if (phy->autoneg_advertised & ADVERTISE_1000_HALF) + hw_dbg(hw, "Advertise 1000mb Half duplex request denied!\n"); + + /* Do we want to advertise 1000 Mb Full Duplex? */ + if (phy->autoneg_advertised & ADVERTISE_1000_FULL) { + hw_dbg(hw, "Advertise 1000mb Full duplex\n"); + mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS; + } + + /* Check for a software override of the flow control settings, and + * setup the PHY advertisement registers accordingly. If + * auto-negotiation is enabled, then software will have to set the + * "PAUSE" bits to the correct value in the Auto-Negotiation + * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto- + * negotiation. + * + * The possible values of the "fc" parameter are: + * 0: Flow control is completely disabled + * 1: Rx flow control is enabled (we can receive pause frames + * but not send pause frames). + * 2: Tx flow control is enabled (we can send pause frames + * but we do not support receiving pause frames). + * 3: Both Rx and TX flow control (symmetric) are enabled. + * other: No software override. The flow control configuration + * in the EEPROM is used. + */ + switch (hw->mac.fc) { + case e1000_fc_none: + /* Flow control (RX & TX) is completely disabled by a + * software over-ride. + */ + mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); + break; + case e1000_fc_rx_pause: + /* RX Flow control is enabled, and TX Flow control is + * disabled, by a software over-ride. + */ + /* Since there really isn't a way to advertise that we are + * capable of RX Pause ONLY, we will advertise that we + * support both symmetric and asymmetric RX PAUSE. Later + * (in e1000e_config_fc_after_link_up) we will disable the + * hw's ability to send PAUSE frames. + */ + mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); + break; + case e1000_fc_tx_pause: + /* TX Flow control is enabled, and RX Flow control is + * disabled, by a software over-ride. + */ + mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR; + mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE; + break; + case e1000_fc_full: + /* Flow control (both RX and TX) is enabled by a software + * over-ride. + */ + mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); + break; + default: + hw_dbg(hw, "Flow control param set incorrectly\n"); + ret_val = -E1000_ERR_CONFIG; + return ret_val; + } + + ret_val = e1e_wphy(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg); + if (ret_val) + return ret_val; + + hw_dbg(hw, "Auto-Neg Advertising %x\n", mii_autoneg_adv_reg); + + if (phy->autoneg_mask & ADVERTISE_1000_FULL) { + ret_val = e1e_wphy(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg); + } + + return ret_val; +} + +/** + * e1000_copper_link_autoneg - Setup/Enable autoneg for copper link + * @hw: pointer to the HW structure + * + * Performs initial bounds checking on autoneg advertisement parameter, then + * configure to advertise the full capability. Setup the PHY to autoneg + * and restart the negotiation process between the link partner. If + * wait_for_link, then wait for autoneg to complete before exiting. + **/ +static s32 e1000_copper_link_autoneg(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_ctrl; + + /* Perform some bounds checking on the autoneg advertisement + * parameter. + */ + phy->autoneg_advertised &= phy->autoneg_mask; + + /* If autoneg_advertised is zero, we assume it was not defaulted + * by the calling code so we set to advertise full capability. + */ + if (phy->autoneg_advertised == 0) + phy->autoneg_advertised = phy->autoneg_mask; + + hw_dbg(hw, "Reconfiguring auto-neg advertisement params\n"); + ret_val = e1000_phy_setup_autoneg(hw); + if (ret_val) { + hw_dbg(hw, "Error Setting up Auto-Negotiation\n"); + return ret_val; + } + hw_dbg(hw, "Restarting Auto-Neg\n"); + + /* Restart auto-negotiation by setting the Auto Neg Enable bit and + * the Auto Neg Restart bit in the PHY control register. + */ + ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_ctrl); + if (ret_val) + return ret_val; + + phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG); + ret_val = e1e_wphy(hw, PHY_CONTROL, phy_ctrl); + if (ret_val) + return ret_val; + + /* Does the user want to wait for Auto-Neg to complete here, or + * check at a later time (for example, callback routine). + */ + if (phy->wait_for_link) { + ret_val = e1000_wait_autoneg(hw); + if (ret_val) { + hw_dbg(hw, "Error while waiting for " + "autoneg to complete\n"); + return ret_val; + } + } + + hw->mac.get_link_status = 1; + + return ret_val; +} + +/** + * e1000e_setup_copper_link - Configure copper link settings + * @hw: pointer to the HW structure + * + * Calls the appropriate function to configure the link for auto-neg or forced + * speed and duplex. Then we check for link, once link is established calls + * to configure collision distance and flow control are called. If link is + * not established, we return -E1000_ERR_PHY (-2). + **/ +s32 e1000e_setup_copper_link(struct e1000_hw *hw) +{ + s32 ret_val; + bool link; + + if (hw->mac.autoneg) { + /* Setup autoneg and flow control advertisement and perform + * autonegotiation. */ + ret_val = e1000_copper_link_autoneg(hw); + if (ret_val) + return ret_val; + } else { + /* PHY will be set to 10H, 10F, 100H or 100F + * depending on user settings. */ + hw_dbg(hw, "Forcing Speed and Duplex\n"); + ret_val = e1000_phy_force_speed_duplex(hw); + if (ret_val) { + hw_dbg(hw, "Error Forcing Speed and Duplex\n"); + return ret_val; + } + } + + /* Check link status. Wait up to 100 microseconds for link to become + * valid. + */ + ret_val = e1000e_phy_has_link_generic(hw, + COPPER_LINK_UP_LIMIT, + 10, + &link); + if (ret_val) + return ret_val; + + if (link) { + hw_dbg(hw, "Valid link established!!!\n"); + e1000e_config_collision_dist(hw); + ret_val = e1000e_config_fc_after_link_up(hw); + } else { + hw_dbg(hw, "Unable to establish link!!!\n"); + } + + return ret_val; +} + +/** + * e1000e_phy_force_speed_duplex_igp - Force speed/duplex for igp PHY + * @hw: pointer to the HW structure + * + * Calls the PHY setup function to force speed and duplex. Clears the + * auto-crossover to force MDI manually. Waits for link and returns + * successful if link up is successful, else -E1000_ERR_PHY (-2). + **/ +s32 e1000e_phy_force_speed_duplex_igp(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_data; + bool link; + + ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_data); + if (ret_val) + return ret_val; + + e1000e_phy_force_speed_duplex_setup(hw, &phy_data); + + ret_val = e1e_wphy(hw, PHY_CONTROL, phy_data); + if (ret_val) + return ret_val; + + /* Clear Auto-Crossover to force MDI manually. IGP requires MDI + * forced whenever speed and duplex are forced. + */ + ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data); + if (ret_val) + return ret_val; + + phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX; + phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX; + + ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CTRL, phy_data); + if (ret_val) + return ret_val; + + hw_dbg(hw, "IGP PSCR: %X\n", phy_data); + + udelay(1); + + if (phy->wait_for_link) { + hw_dbg(hw, "Waiting for forced speed/duplex link on IGP phy.\n"); + + ret_val = e1000e_phy_has_link_generic(hw, + PHY_FORCE_LIMIT, + 100000, + &link); + if (ret_val) + return ret_val; + + if (!link) + hw_dbg(hw, "Link taking longer than expected.\n"); + + /* Try once more */ + ret_val = e1000e_phy_has_link_generic(hw, + PHY_FORCE_LIMIT, + 100000, + &link); + if (ret_val) + return ret_val; + } + + return ret_val; +} + +/** + * e1000e_phy_force_speed_duplex_m88 - Force speed/duplex for m88 PHY + * @hw: pointer to the HW structure + * + * Calls the PHY setup function to force speed and duplex. Clears the + * auto-crossover to force MDI manually. Resets the PHY to commit the + * changes. If time expires while waiting for link up, we reset the DSP. + * After reset, TX_CLK and CRS on TX must be set. Return successful upon + * successful completion, else return corresponding error code. + **/ +s32 e1000e_phy_force_speed_duplex_m88(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_data; + bool link; + + /* Clear Auto-Crossover to force MDI manually. M88E1000 requires MDI + * forced whenever speed and duplex are forced. + */ + ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); + if (ret_val) + return ret_val; + + phy_data &= ~M88E1000_PSCR_AUTO_X_MODE; + ret_val = e1e_wphy(hw, M88E1000_PHY_SPEC_CTRL, phy_data); + if (ret_val) + return ret_val; + + hw_dbg(hw, "M88E1000 PSCR: %X\n", phy_data); + + ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_data); + if (ret_val) + return ret_val; + + e1000e_phy_force_speed_duplex_setup(hw, &phy_data); + + /* Reset the phy to commit changes. */ + phy_data |= MII_CR_RESET; + + ret_val = e1e_wphy(hw, PHY_CONTROL, phy_data); + if (ret_val) + return ret_val; + + udelay(1); + + if (phy->wait_for_link) { + hw_dbg(hw, "Waiting for forced speed/duplex link on M88 phy.\n"); + + ret_val = e1000e_phy_has_link_generic(hw, PHY_FORCE_LIMIT, + 100000, &link); + if (ret_val) + return ret_val; + + if (!link) { + /* We didn't get link. + * Reset the DSP and cross our fingers. + */ + ret_val = e1e_wphy(hw, M88E1000_PHY_PAGE_SELECT, 0x001d); + if (ret_val) + return ret_val; + ret_val = e1000e_phy_reset_dsp(hw); + if (ret_val) + return ret_val; + } + + /* Try once more */ + ret_val = e1000e_phy_has_link_generic(hw, PHY_FORCE_LIMIT, + 100000, &link); + if (ret_val) + return ret_val; + } + + ret_val = e1e_rphy(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data); + if (ret_val) + return ret_val; + + /* Resetting the phy means we need to re-force TX_CLK in the + * Extended PHY Specific Control Register to 25MHz clock from + * the reset value of 2.5MHz. + */ + phy_data |= M88E1000_EPSCR_TX_CLK_25; + ret_val = e1e_wphy(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data); + if (ret_val) + return ret_val; + + /* In addition, we must re-enable CRS on Tx for both half and full + * duplex. + */ + ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); + if (ret_val) + return ret_val; + + phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; + ret_val = e1e_wphy(hw, M88E1000_PHY_SPEC_CTRL, phy_data); + + return ret_val; +} + +/** + * e1000e_phy_force_speed_duplex_setup - Configure forced PHY speed/duplex + * @hw: pointer to the HW structure + * @phy_ctrl: pointer to current value of PHY_CONTROL + * + * Forces speed and duplex on the PHY by doing the following: disable flow + * control, force speed/duplex on the MAC, disable auto speed detection, + * disable auto-negotiation, configure duplex, configure speed, configure + * the collision distance, write configuration to CTRL register. The + * caller must write to the PHY_CONTROL register for these settings to + * take affect. + **/ +void e1000e_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl) +{ + struct e1000_mac_info *mac = &hw->mac; + u32 ctrl; + + /* Turn off flow control when forcing speed/duplex */ + mac->fc = e1000_fc_none; + + /* Force speed/duplex on the mac */ + ctrl = er32(CTRL); + ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); + ctrl &= ~E1000_CTRL_SPD_SEL; + + /* Disable Auto Speed Detection */ + ctrl &= ~E1000_CTRL_ASDE; + + /* Disable autoneg on the phy */ + *phy_ctrl &= ~MII_CR_AUTO_NEG_EN; + + /* Forcing Full or Half Duplex? */ + if (mac->forced_speed_duplex & E1000_ALL_HALF_DUPLEX) { + ctrl &= ~E1000_CTRL_FD; + *phy_ctrl &= ~MII_CR_FULL_DUPLEX; + hw_dbg(hw, "Half Duplex\n"); + } else { + ctrl |= E1000_CTRL_FD; + *phy_ctrl |= MII_CR_FULL_DUPLEX; + hw_dbg(hw, "Full Duplex\n"); + } + + /* Forcing 10mb or 100mb? */ + if (mac->forced_speed_duplex & E1000_ALL_100_SPEED) { + ctrl |= E1000_CTRL_SPD_100; + *phy_ctrl |= MII_CR_SPEED_100; + *phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10); + hw_dbg(hw, "Forcing 100mb\n"); + } else { + ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100); + *phy_ctrl |= MII_CR_SPEED_10; + *phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100); + hw_dbg(hw, "Forcing 10mb\n"); + } + + e1000e_config_collision_dist(hw); + + ew32(CTRL, ctrl); +} + +/** + * e1000e_set_d3_lplu_state - Sets low power link up state for D3 + * @hw: pointer to the HW structure + * @active: boolean used to enable/disable lplu + * + * Success returns 0, Failure returns 1 + * + * The low power link up (lplu) state is set to the power management level D3 + * and SmartSpeed is disabled when active is true, else clear lplu for D3 + * and enable Smartspeed. LPLU and Smartspeed are mutually exclusive. LPLU + * is used during Dx states where the power conservation is most important. + * During driver activity, SmartSpeed should be enabled so performance is + * maintained. + **/ +s32 e1000e_set_d3_lplu_state(struct e1000_hw *hw, bool active) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 data; + + ret_val = e1e_rphy(hw, IGP02E1000_PHY_POWER_MGMT, &data); + if (ret_val) + return ret_val; + + if (!active) { + data &= ~IGP02E1000_PM_D3_LPLU; + ret_val = e1e_wphy(hw, + IGP02E1000_PHY_POWER_MGMT, + data); + if (ret_val) + return ret_val; + /* LPLU and SmartSpeed are mutually exclusive. LPLU is used + * during Dx states where the power conservation is most + * important. During driver activity we should enable + * SmartSpeed, so performance is maintained. */ + if (phy->smart_speed == e1000_smart_speed_on) { + ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG, + &data); + if (ret_val) + return ret_val; + + data |= IGP01E1000_PSCFR_SMART_SPEED; + ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG, + data); + if (ret_val) + return ret_val; + } else if (phy->smart_speed == e1000_smart_speed_off) { + ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG, + &data); + if (ret_val) + return ret_val; + + data &= ~IGP01E1000_PSCFR_SMART_SPEED; + ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG, + data); + if (ret_val) + return ret_val; + } + } else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) || + (phy->autoneg_advertised == E1000_ALL_NOT_GIG) || + (phy->autoneg_advertised == E1000_ALL_10_SPEED)) { + data |= IGP02E1000_PM_D3_LPLU; + ret_val = e1e_wphy(hw, IGP02E1000_PHY_POWER_MGMT, data); + if (ret_val) + return ret_val; + + /* When LPLU is enabled, we should disable SmartSpeed */ + ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG, &data); + if (ret_val) + return ret_val; + + data &= ~IGP01E1000_PSCFR_SMART_SPEED; + ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG, data); + } + + return ret_val; +} + +/** + * e1000e_check_downshift - Checks whether a downshift in speed occured + * @hw: pointer to the HW structure + * + * Success returns 0, Failure returns 1 + * + * A downshift is detected by querying the PHY link health. + **/ +s32 e1000e_check_downshift(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_data, offset, mask; + + switch (phy->type) { + case e1000_phy_m88: + case e1000_phy_gg82563: + offset = M88E1000_PHY_SPEC_STATUS; + mask = M88E1000_PSSR_DOWNSHIFT; + break; + case e1000_phy_igp_2: + case e1000_phy_igp_3: + offset = IGP01E1000_PHY_LINK_HEALTH; + mask = IGP01E1000_PLHR_SS_DOWNGRADE; + break; + default: + /* speed downshift not supported */ + phy->speed_downgraded = 0; + return 0; + } + + ret_val = e1e_rphy(hw, offset, &phy_data); + + if (!ret_val) + phy->speed_downgraded = (phy_data & mask); + + return ret_val; +} + +/** + * e1000_check_polarity_m88 - Checks the polarity. + * @hw: pointer to the HW structure + * + * Success returns 0, Failure returns -E1000_ERR_PHY (-2) + * + * Polarity is determined based on the PHY specific status register. + **/ +static s32 e1000_check_polarity_m88(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 data; + + ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_STATUS, &data); + + if (!ret_val) + phy->cable_polarity = (data & M88E1000_PSSR_REV_POLARITY) + ? e1000_rev_polarity_reversed + : e1000_rev_polarity_normal; + + return ret_val; +} + +/** + * e1000_check_polarity_igp - Checks the polarity. + * @hw: pointer to the HW structure + * + * Success returns 0, Failure returns -E1000_ERR_PHY (-2) + * + * Polarity is determined based on the PHY port status register, and the + * current speed (since there is no polarity at 100Mbps). + **/ +static s32 e1000_check_polarity_igp(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 data, offset, mask; + + /* Polarity is determined based on the speed of + * our connection. */ + ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_STATUS, &data); + if (ret_val) + return ret_val; + + if ((data & IGP01E1000_PSSR_SPEED_MASK) == + IGP01E1000_PSSR_SPEED_1000MBPS) { + offset = IGP01E1000_PHY_PCS_INIT_REG; + mask = IGP01E1000_PHY_POLARITY_MASK; + } else { + /* This really only applies to 10Mbps since + * there is no polarity for 100Mbps (always 0). + */ + offset = IGP01E1000_PHY_PORT_STATUS; + mask = IGP01E1000_PSSR_POLARITY_REVERSED; + } + + ret_val = e1e_rphy(hw, offset, &data); + + if (!ret_val) + phy->cable_polarity = (data & mask) + ? e1000_rev_polarity_reversed + : e1000_rev_polarity_normal; + + return ret_val; +} + +/** + * e1000_wait_autoneg - Wait for auto-neg compeletion + * @hw: pointer to the HW structure + * + * Waits for auto-negotiation to complete or for the auto-negotiation time + * limit to expire, which ever happens first. + **/ +static s32 e1000_wait_autoneg(struct e1000_hw *hw) +{ + s32 ret_val = 0; + u16 i, phy_status; + + /* Break after autoneg completes or PHY_AUTO_NEG_LIMIT expires. */ + for (i = PHY_AUTO_NEG_LIMIT; i > 0; i--) { + ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status); + if (ret_val) + break; + ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status); + if (ret_val) + break; + if (phy_status & MII_SR_AUTONEG_COMPLETE) + break; + msleep(100); + } + + /* PHY_AUTO_NEG_TIME expiration doesn't guarantee auto-negotiation + * has completed. + */ + return ret_val; +} + +/** + * e1000e_phy_has_link_generic - Polls PHY for link + * @hw: pointer to the HW structure + * @iterations: number of times to poll for link + * @usec_interval: delay between polling attempts + * @success: pointer to whether polling was successful or not + * + * Polls the PHY status register for link, 'iterations' number of times. + **/ +s32 e1000e_phy_has_link_generic(struct e1000_hw *hw, u32 iterations, + u32 usec_interval, bool *success) +{ + s32 ret_val = 0; + u16 i, phy_status; + + for (i = 0; i < iterations; i++) { + /* Some PHYs require the PHY_STATUS register to be read + * twice due to the link bit being sticky. No harm doing + * it across the board. + */ + ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status); + if (ret_val) + break; + ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status); + if (ret_val) + break; + if (phy_status & MII_SR_LINK_STATUS) + break; + if (usec_interval >= 1000) + mdelay(usec_interval/1000); + else + udelay(usec_interval); + } + + *success = (i < iterations); + + return ret_val; +} + +/** + * e1000e_get_cable_length_m88 - Determine cable length for m88 PHY + * @hw: pointer to the HW structure + * + * Reads the PHY specific status register to retrieve the cable length + * information. The cable length is determined by averaging the minimum and + * maximum values to get the "average" cable length. The m88 PHY has four + * possible cable length values, which are: + * Register Value Cable Length + * 0 < 50 meters + * 1 50 - 80 meters + * 2 80 - 110 meters + * 3 110 - 140 meters + * 4 > 140 meters + **/ +s32 e1000e_get_cable_length_m88(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_data, index; + + ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); + if (ret_val) + return ret_val; + + index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >> + M88E1000_PSSR_CABLE_LENGTH_SHIFT; + phy->min_cable_length = e1000_m88_cable_length_table[index]; + phy->max_cable_length = e1000_m88_cable_length_table[index+1]; + + phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2; + + return ret_val; +} + +/** + * e1000e_get_cable_length_igp_2 - Determine cable length for igp2 PHY + * @hw: pointer to the HW structure + * + * The automatic gain control (agc) normalizes the amplitude of the + * received signal, adjusting for the attenuation produced by the + * cable. By reading the AGC registers, which reperesent the + * cobination of course and fine gain value, the value can be put + * into a lookup table to obtain the approximate cable length + * for each channel. + **/ +s32 e1000e_get_cable_length_igp_2(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_data, i, agc_value = 0; + u16 cur_agc_index, max_agc_index = 0; + u16 min_agc_index = IGP02E1000_CABLE_LENGTH_TABLE_SIZE - 1; + u16 agc_reg_array[IGP02E1000_PHY_CHANNEL_NUM] = + {IGP02E1000_PHY_AGC_A, + IGP02E1000_PHY_AGC_B, + IGP02E1000_PHY_AGC_C, + IGP02E1000_PHY_AGC_D}; + + /* Read the AGC registers for all channels */ + for (i = 0; i < IGP02E1000_PHY_CHANNEL_NUM; i++) { + ret_val = e1e_rphy(hw, agc_reg_array[i], &phy_data); + if (ret_val) + return ret_val; + + /* Getting bits 15:9, which represent the combination of + * course and fine gain values. The result is a number + * that can be put into the lookup table to obtain the + * approximate cable length. */ + cur_agc_index = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) & + IGP02E1000_AGC_LENGTH_MASK; + + /* Array index bound check. */ + if ((cur_agc_index >= IGP02E1000_CABLE_LENGTH_TABLE_SIZE) || + (cur_agc_index == 0)) + return -E1000_ERR_PHY; + + /* Remove min & max AGC values from calculation. */ + if (e1000_igp_2_cable_length_table[min_agc_index] > + e1000_igp_2_cable_length_table[cur_agc_index]) + min_agc_index = cur_agc_index; + if (e1000_igp_2_cable_length_table[max_agc_index] < + e1000_igp_2_cable_length_table[cur_agc_index]) + max_agc_index = cur_agc_index; + + agc_value += e1000_igp_2_cable_length_table[cur_agc_index]; + } + + agc_value -= (e1000_igp_2_cable_length_table[min_agc_index] + + e1000_igp_2_cable_length_table[max_agc_index]); + agc_value /= (IGP02E1000_PHY_CHANNEL_NUM - 2); + + /* Calculate cable length with the error range of +/- 10 meters. */ + phy->min_cable_length = ((agc_value - IGP02E1000_AGC_RANGE) > 0) ? + (agc_value - IGP02E1000_AGC_RANGE) : 0; + phy->max_cable_length = agc_value + IGP02E1000_AGC_RANGE; + + phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2; + + return ret_val; +} + +/** + * e1000e_get_phy_info_m88 - Retrieve PHY information + * @hw: pointer to the HW structure + * + * Valid for only copper links. Read the PHY status register (sticky read) + * to verify that link is up. Read the PHY special control register to + * determine the polarity and 10base-T extended distance. Read the PHY + * special status register to determine MDI/MDIx and current speed. If + * speed is 1000, then determine cable length, local and remote receiver. + **/ +s32 e1000e_get_phy_info_m88(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_data; + bool link; + + if (hw->media_type != e1000_media_type_copper) { + hw_dbg(hw, "Phy info is only valid for copper media\n"); + return -E1000_ERR_CONFIG; + } + + ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link); + if (ret_val) + return ret_val; + + if (!link) { + hw_dbg(hw, "Phy info is only valid if link is up\n"); + return -E1000_ERR_CONFIG; + } + + ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); + if (ret_val) + return ret_val; + + phy->polarity_correction = (phy_data & + M88E1000_PSCR_POLARITY_REVERSAL); + + ret_val = e1000_check_polarity_m88(hw); + if (ret_val) + return ret_val; + + ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); + if (ret_val) + return ret_val; + + phy->is_mdix = (phy_data & M88E1000_PSSR_MDIX); + + if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) { + ret_val = e1000_get_cable_length(hw); + if (ret_val) + return ret_val; + + ret_val = e1e_rphy(hw, PHY_1000T_STATUS, &phy_data); + if (ret_val) + return ret_val; + + phy->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) + ? e1000_1000t_rx_status_ok + : e1000_1000t_rx_status_not_ok; + + phy->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS) + ? e1000_1000t_rx_status_ok + : e1000_1000t_rx_status_not_ok; + } else { + /* Set values to "undefined" */ + phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED; + phy->local_rx = e1000_1000t_rx_status_undefined; + phy->remote_rx = e1000_1000t_rx_status_undefined; + } + + return ret_val; +} + +/** + * e1000e_get_phy_info_igp - Retrieve igp PHY information + * @hw: pointer to the HW structure + * + * Read PHY status to determine if link is up. If link is up, then + * set/determine 10base-T extended distance and polarity correction. Read + * PHY port status to determine MDI/MDIx and speed. Based on the speed, + * determine on the cable length, local and remote receiver. + **/ +s32 e1000e_get_phy_info_igp(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 data; + bool link; + + ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link); + if (ret_val) + return ret_val; + + if (!link) { + hw_dbg(hw, "Phy info is only valid if link is up\n"); + return -E1000_ERR_CONFIG; + } + + phy->polarity_correction = 1; + + ret_val = e1000_check_polarity_igp(hw); + if (ret_val) + return ret_val; + + ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_STATUS, &data); + if (ret_val) + return ret_val; + + phy->is_mdix = (data & IGP01E1000_PSSR_MDIX); + + if ((data & IGP01E1000_PSSR_SPEED_MASK) == + IGP01E1000_PSSR_SPEED_1000MBPS) { + ret_val = e1000_get_cable_length(hw); + if (ret_val) + return ret_val; + + ret_val = e1e_rphy(hw, PHY_1000T_STATUS, &data); + if (ret_val) + return ret_val; + + phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS) + ? e1000_1000t_rx_status_ok + : e1000_1000t_rx_status_not_ok; + + phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS) + ? e1000_1000t_rx_status_ok + : e1000_1000t_rx_status_not_ok; + } else { + phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED; + phy->local_rx = e1000_1000t_rx_status_undefined; + phy->remote_rx = e1000_1000t_rx_status_undefined; + } + + return ret_val; +} + +/** + * e1000e_phy_sw_reset - PHY software reset + * @hw: pointer to the HW structure + * + * Does a software reset of the PHY by reading the PHY control register and + * setting/write the control register reset bit to the PHY. + **/ +s32 e1000e_phy_sw_reset(struct e1000_hw *hw) +{ + s32 ret_val; + u16 phy_ctrl; + + ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_ctrl); + if (ret_val) + return ret_val; + + phy_ctrl |= MII_CR_RESET; + ret_val = e1e_wphy(hw, PHY_CONTROL, phy_ctrl); + if (ret_val) + return ret_val; + + udelay(1); + + return ret_val; +} + +/** + * e1000e_phy_hw_reset_generic - PHY hardware reset + * @hw: pointer to the HW structure + * + * Verify the reset block is not blocking us from resetting. Acquire + * semaphore (if necessary) and read/set/write the device control reset + * bit in the PHY. Wait the appropriate delay time for the device to + * reset and relase the semaphore (if necessary). + **/ +s32 e1000e_phy_hw_reset_generic(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u32 ctrl; + + ret_val = e1000_check_reset_block(hw); + if (ret_val) + return 0; + + ret_val = phy->ops.acquire_phy(hw); + if (ret_val) + return ret_val; + + ctrl = er32(CTRL); + ew32(CTRL, ctrl | E1000_CTRL_PHY_RST); + e1e_flush(); + + udelay(phy->reset_delay_us); + + ew32(CTRL, ctrl); + e1e_flush(); + + udelay(150); + + phy->ops.release_phy(hw); + + return e1000_get_phy_cfg_done(hw); +} + +/** + * e1000e_get_cfg_done - Generic configuration done + * @hw: pointer to the HW structure + * + * Generic function to wait 10 milli-seconds for configuration to complete + * and return success. + **/ +s32 e1000e_get_cfg_done(struct e1000_hw *hw) +{ + mdelay(10); + return 0; +} + +/* Internal function pointers */ + +/** + * e1000_get_phy_cfg_done - Generic PHY configuration done + * @hw: pointer to the HW structure + * + * Return success if silicon family did not implement a family specific + * get_cfg_done function. + **/ +static s32 e1000_get_phy_cfg_done(struct e1000_hw *hw) +{ + if (hw->phy.ops.get_cfg_done) + return hw->phy.ops.get_cfg_done(hw); + + return 0; +} + +/** + * e1000_phy_force_speed_duplex - Generic force PHY speed/duplex + * @hw: pointer to the HW structure + * + * When the silicon family has not implemented a forced speed/duplex + * function for the PHY, simply return 0. + **/ +static s32 e1000_phy_force_speed_duplex(struct e1000_hw *hw) +{ + if (hw->phy.ops.force_speed_duplex) + return hw->phy.ops.force_speed_duplex(hw); + + return 0; +} + +/** + * e1000e_get_phy_type_from_id - Get PHY type from id + * @phy_id: phy_id read from the phy + * + * Returns the phy type from the id. + **/ +enum e1000_phy_type e1000e_get_phy_type_from_id(u32 phy_id) +{ + enum e1000_phy_type phy_type = e1000_phy_unknown; + + switch (phy_id) { + case M88E1000_I_PHY_ID: + case M88E1000_E_PHY_ID: + case M88E1111_I_PHY_ID: + case M88E1011_I_PHY_ID: + phy_type = e1000_phy_m88; + break; + case IGP01E1000_I_PHY_ID: /* IGP 1 & 2 share this */ + phy_type = e1000_phy_igp_2; + break; + case GG82563_E_PHY_ID: + phy_type = e1000_phy_gg82563; + break; + case IGP03E1000_E_PHY_ID: + phy_type = e1000_phy_igp_3; + break; + case IFE_E_PHY_ID: + case IFE_PLUS_E_PHY_ID: + case IFE_C_E_PHY_ID: + phy_type = e1000_phy_ife; + break; + default: + phy_type = e1000_phy_unknown; + break; + } + return phy_type; +} + +/** + * e1000e_commit_phy - Soft PHY reset + * @hw: pointer to the HW structure + * + * Performs a soft PHY reset on those that apply. This is a function pointer + * entry point called by drivers. + **/ +s32 e1000e_commit_phy(struct e1000_hw *hw) +{ + if (hw->phy.ops.commit_phy) + return hw->phy.ops.commit_phy(hw); + + return 0; +} + +/** + * e1000_set_d0_lplu_state - Sets low power link up state for D0 + * @hw: pointer to the HW structure + * @active: boolean used to enable/disable lplu + * + * Success returns 0, Failure returns 1 + * + * The low power link up (lplu) state is set to the power management level D0 + * and SmartSpeed is disabled when active is true, else clear lplu for D0 + * and enable Smartspeed. LPLU and Smartspeed are mutually exclusive. LPLU + * is used during Dx states where the power conservation is most important. + * During driver activity, SmartSpeed should be enabled so performance is + * maintained. This is a function pointer entry point called by drivers. + **/ +static s32 e1000_set_d0_lplu_state(struct e1000_hw *hw, bool active) +{ + if (hw->phy.ops.set_d0_lplu_state) + return hw->phy.ops.set_d0_lplu_state(hw, active); + + return 0; +} -- cgit v1.2.3-70-g09d2 From a11a6544c0bf6c0871f2379ad0c5ad0210691e73 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Fri, 3 Aug 2007 13:52:19 +0200 Subject: support for USB autosuspend in the asix driver this implements support for USB autosuspend in the asix USB ethernet driver. Signed-off-by: Oliver Neukum Signed-off-by: Jeff Garzik --- drivers/net/usb/asix.c | 1 + drivers/net/usb/usbnet.c | 30 +++++++++++++++++++++++++----- drivers/net/usb/usbnet.h | 1 + 3 files changed, 27 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c index 6d95cacd528..61daa096de6 100644 --- a/drivers/net/usb/asix.c +++ b/drivers/net/usb/asix.c @@ -1474,6 +1474,7 @@ static struct usb_driver asix_driver = { .suspend = usbnet_suspend, .resume = usbnet_resume, .disconnect = usbnet_disconnect, + .supports_autosuspend = 1, }; static int __init asix_init(void) diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 37bf4f2c0a4..3034d1aea37 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -590,6 +590,7 @@ static int usbnet_stop (struct net_device *net) dev->flags = 0; del_timer_sync (&dev->delay); tasklet_kill (&dev->bh); + usb_autopm_put_interface(dev->intf); return 0; } @@ -603,9 +604,19 @@ static int usbnet_stop (struct net_device *net) static int usbnet_open (struct net_device *net) { struct usbnet *dev = netdev_priv(net); - int retval = 0; + int retval; struct driver_info *info = dev->driver_info; + if ((retval = usb_autopm_get_interface(dev->intf)) < 0) { + if (netif_msg_ifup (dev)) + devinfo (dev, + "resumption fail (%d) usbnet usb-%s-%s, %s", + retval, + dev->udev->bus->bus_name, dev->udev->devpath, + info->description); + goto done_nopm; + } + // put into "known safe" state if (info->reset && (retval = info->reset (dev)) < 0) { if (netif_msg_ifup (dev)) @@ -659,7 +670,10 @@ static int usbnet_open (struct net_device *net) // delay posting reads until we're fully open tasklet_schedule (&dev->bh); + return retval; done: + usb_autopm_put_interface(dev->intf); +done_nopm: return retval; } @@ -1143,6 +1157,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) dev = netdev_priv(net); dev->udev = xdev; + dev->intf = udev; dev->driver_info = info; dev->driver_name = name; dev->msg_enable = netif_msg_init (msg_level, NETIF_MSG_DRV @@ -1267,12 +1282,18 @@ int usbnet_suspend (struct usb_interface *intf, pm_message_t message) struct usbnet *dev = usb_get_intfdata(intf); if (!dev->suspend_count++) { - /* accelerate emptying of the rx and queues, to avoid + /* + * accelerate emptying of the rx and queues, to avoid * having everything error out. */ netif_device_detach (dev->net); (void) unlink_urbs (dev, &dev->rxq); (void) unlink_urbs (dev, &dev->txq); + /* + * reattach so runtime management can use and + * wake the device + */ + netif_device_attach (dev->net); } return 0; } @@ -1282,10 +1303,9 @@ int usbnet_resume (struct usb_interface *intf) { struct usbnet *dev = usb_get_intfdata(intf); - if (!--dev->suspend_count) { - netif_device_attach (dev->net); + if (!--dev->suspend_count) tasklet_schedule (&dev->bh); - } + return 0; } EXPORT_SYMBOL_GPL(usbnet_resume); diff --git a/drivers/net/usb/usbnet.h b/drivers/net/usb/usbnet.h index a6c5820767d..1fae4347e83 100644 --- a/drivers/net/usb/usbnet.h +++ b/drivers/net/usb/usbnet.h @@ -28,6 +28,7 @@ struct usbnet { /* housekeeping */ struct usb_device *udev; + struct usb_interface *intf; struct driver_info *driver_info; const char *driver_name; wait_queue_head_t *wait; -- cgit v1.2.3-70-g09d2 From 917270c6ed7a99d4300ce57508246813ea8613b0 Mon Sep 17 00:00:00 2001 From: Don Fry Date: Sun, 26 Aug 2007 21:22:32 -0700 Subject: pcnet32: add suspend and resume capability Add suspend and resume capability to the driver. Tested both to ram and to disk on x86_64 platform. Signed-off-by: Don Fry Signed-off-by: Jeff Garzik --- drivers/net/pcnet32.c | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index a9973490dba..db87429b956 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -23,11 +23,11 @@ #define DRV_NAME "pcnet32" #ifdef CONFIG_PCNET32_NAPI -#define DRV_VERSION "1.33-NAPI" +#define DRV_VERSION "1.34-NAPI" #else -#define DRV_VERSION "1.33" +#define DRV_VERSION "1.34" #endif -#define DRV_RELDATE "27.Jun.2006" +#define DRV_RELDATE "14.Aug.2007" #define PFX DRV_NAME ": " static const char *const version = @@ -2955,6 +2955,33 @@ static void pcnet32_watchdog(struct net_device *dev) mod_timer(&(lp->watchdog_timer), PCNET32_WATCHDOG_TIMEOUT); } +static int pcnet32_pm_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *dev = pci_get_drvdata(pdev); + + if (netif_running(dev)) { + netif_device_detach(dev); + pcnet32_close(dev); + } + pci_save_state(pdev); + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + return 0; +} + +static int pcnet32_pm_resume(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + + if (netif_running(dev)) { + pcnet32_open(dev); + netif_device_attach(dev); + } + return 0; +} + static void __devexit pcnet32_remove_one(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); @@ -2978,6 +3005,8 @@ static struct pci_driver pcnet32_driver = { .probe = pcnet32_probe_pci, .remove = __devexit_p(pcnet32_remove_one), .id_table = pcnet32_pci_tbl, + .suspend = pcnet32_pm_suspend, + .resume = pcnet32_pm_resume, }; /* An additional parameter that may be passed in... */ -- cgit v1.2.3-70-g09d2 From b6aec32a7774a398c4a194ad6b6392528b5a7a5b Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 14 Aug 2007 20:09:02 +0200 Subject: uli526x: Add suspend and resume routines (updated) Add suspend/resume support to the uli526x network driver (tested on x86_64, with 'Ethernet controller: ALi Corporation M5263 Ethernet Controller, rev 40'). This patch is based on the suspend/resume code in the tg3 driver. Signed-off-by: Rafael J. Wysocki Signed-off-by: Jeff Garzik --- drivers/net/tulip/uli526x.c | 108 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 102 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c index ca2548eb7d6..e26ce44561c 100644 --- a/drivers/net/tulip/uli526x.c +++ b/drivers/net/tulip/uli526x.c @@ -1110,19 +1110,15 @@ static void uli526x_timer(unsigned long data) /* - * Dynamic reset the ULI526X board * Stop ULI526X board * Free Tx/Rx allocated memory - * Reset ULI526X board - * Re-initialize ULI526X board + * Init system variable */ -static void uli526x_dynamic_reset(struct net_device *dev) +static void uli526x_reset_prepare(struct net_device *dev) { struct uli526x_board_info *db = netdev_priv(dev); - ULI526X_DBUG(0, "uli526x_dynamic_reset()", 0); - /* Sopt MAC controller */ db->cr6_data &= ~(CR6_RXSC | CR6_TXSC); /* Disable Tx/Rx */ update_cr6(db->cr6_data, dev->base_addr); @@ -1141,6 +1137,22 @@ static void uli526x_dynamic_reset(struct net_device *dev) db->link_failed = 1; db->init=1; db->wait_reset = 0; +} + + +/* + * Dynamic reset the ULI526X board + * Stop ULI526X board + * Free Tx/Rx allocated memory + * Reset ULI526X board + * Re-initialize ULI526X board + */ + +static void uli526x_dynamic_reset(struct net_device *dev) +{ + ULI526X_DBUG(0, "uli526x_dynamic_reset()", 0); + + uli526x_reset_prepare(dev); /* Re-initialize ULI526X board */ uli526x_init(dev); @@ -1150,6 +1162,88 @@ static void uli526x_dynamic_reset(struct net_device *dev) } +#ifdef CONFIG_PM + +/* + * Suspend the interface. + */ + +static int uli526x_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *dev = pci_get_drvdata(pdev); + pci_power_t power_state; + int err; + + ULI526X_DBUG(0, "uli526x_suspend", 0); + + if (!netdev_priv(dev)) + return 0; + + pci_save_state(pdev); + + if (!netif_running(dev)) + return 0; + + netif_device_detach(dev); + uli526x_reset_prepare(dev); + + power_state = pci_choose_state(pdev, state); + pci_enable_wake(pdev, power_state, 0); + err = pci_set_power_state(pdev, power_state); + if (err) { + netif_device_attach(dev); + /* Re-initialize ULI526X board */ + uli526x_init(dev); + /* Restart upper layer interface */ + netif_wake_queue(dev); + } + + return err; +} + +/* + * Resume the interface. + */ + +static int uli526x_resume(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + int err; + + ULI526X_DBUG(0, "uli526x_resume", 0); + + if (!netdev_priv(dev)) + return 0; + + pci_restore_state(pdev); + + if (!netif_running(dev)) + return 0; + + err = pci_set_power_state(pdev, PCI_D0); + if (err) { + printk(KERN_WARNING "%s: Could not put device into D0\n", + dev->name); + return err; + } + + netif_device_attach(dev); + /* Re-initialize ULI526X board */ + uli526x_init(dev); + /* Restart upper layer interface */ + netif_wake_queue(dev); + + return 0; +} + +#else /* !CONFIG_PM */ + +#define uli526x_suspend NULL +#define uli526x_resume NULL + +#endif /* !CONFIG_PM */ + + /* * free all allocated rx buffer */ @@ -1689,6 +1783,8 @@ static struct pci_driver uli526x_driver = { .id_table = uli526x_pci_tbl, .probe = uli526x_init_one, .remove = __devexit_p(uli526x_remove_one), + .suspend = uli526x_suspend, + .resume = uli526x_resume, }; MODULE_AUTHOR("Peer Chen, peer.chen@uli.com.tw"); -- cgit v1.2.3-70-g09d2 From df950828b0ee51ff63c49c67d561bfd3d6096788 Mon Sep 17 00:00:00 2001 From: Komuro Date: Mon, 13 Aug 2007 09:45:41 +0900 Subject: dl2k: add Sundance/Tamarack TC902x Gigabit Ethernet Adapter support Actually, D-Link modified the VendorID/ProductID of the TC902x. The TC902x is the original chipset. Signed-off-by: Komuro Signed-off-by: Jeff Garzik --- drivers/net/Kconfig | 7 ++++--- drivers/net/dl2k.c | 23 +++++++++++++++-------- drivers/net/dl2k.h | 1 + 3 files changed, 20 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 502dd0eb880..eeac2f49aae 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1995,14 +1995,15 @@ config ACENIC_OMIT_TIGON_I The safe and default value for this is N. config DL2K - tristate "D-Link DL2000-based Gigabit Ethernet support" + tristate "DL2000/TC902x-based Gigabit Ethernet support" depends on PCI select CRC32 help - This driver supports D-Link 2000-based gigabit ethernet cards, which - includes + This driver supports DL2000/TC902x-based Gigabit ethernet cards, + which includes D-Link DGE-550T Gigabit Ethernet Adapter. D-Link DL2000-based Gigabit Ethernet Adapter. + Sundance/Tamarack TC902x Gigabit Ethernet Adapter. To compile this driver as a module, choose M here: the module will be called dl2k. diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c index 04e3710c908..ca21a1888ff 100644 --- a/drivers/net/dl2k.c +++ b/drivers/net/dl2k.c @@ -10,9 +10,9 @@ (at your option) any later version. */ -#define DRV_NAME "D-Link DL2000-based linux driver" -#define DRV_VERSION "v1.18" -#define DRV_RELDATE "2006/06/27" +#define DRV_NAME "DL2000/TC902x-based linux driver" +#define DRV_VERSION "v1.19" +#define DRV_RELDATE "2007/08/12" #include "dl2k.h" #include @@ -339,17 +339,24 @@ parse_eeprom (struct net_device *dev) #ifdef MEM_MAPPING ioaddr = dev->base_addr; #endif - /* Check CRC */ - crc = ~ether_crc_le (256 - 4, sromdata); - if (psrom->crc != crc) { - printk (KERN_ERR "%s: EEPROM data CRC error.\n", dev->name); - return -1; + if (np->pdev->vendor == PCI_VENDOR_ID_DLINK) { /* D-Link Only */ + /* Check CRC */ + crc = ~ether_crc_le (256 - 4, sromdata); + if (psrom->crc != crc) { + printk (KERN_ERR "%s: EEPROM data CRC error.\n", + dev->name); + return -1; + } } /* Set MAC address */ for (i = 0; i < 6; i++) dev->dev_addr[i] = psrom->mac_addr[i]; + if (np->pdev->vendor != PCI_VENDOR_ID_DLINK) { + return 0; + } + /* Parse Software Information Block */ i = 0x30; psib = (u8 *) sromdata; diff --git a/drivers/net/dl2k.h b/drivers/net/dl2k.h index e443065a452..5b801775f42 100644 --- a/drivers/net/dl2k.h +++ b/drivers/net/dl2k.h @@ -692,6 +692,7 @@ struct netdev_private { static const struct pci_device_id rio_pci_tbl[] = { {0x1186, 0x4000, PCI_ANY_ID, PCI_ANY_ID, }, + {0x13f0, 0x1021, PCI_ANY_ID, PCI_ANY_ID, }, { } }; MODULE_DEVICE_TABLE (pci, rio_pci_tbl); -- cgit v1.2.3-70-g09d2 From f4ff28720f45354573dcf4e0eb5a2dc5452cb3e1 Mon Sep 17 00:00:00 2001 From: Brian King Date: Sat, 15 Sep 2007 13:36:07 -0700 Subject: ibmveth: Enable TCP checksum offload This patchset enables TCP checksum offload support for IPV4 on ibmveth. This completely eliminates the generation and checking of the checksum for packets that are completely virtual and never touch a physical network. A simple TCP_STREAM netperf run on a virtual network with maximum mtu set yielded a ~30% increase in throughput. This feature is enabled by default on systems that support it, but can be disabled with a module option. Signed-off-by: Brian King Signed-off-by: Jeff Garzik Signed-off-by: David S. Miller --- drivers/net/ibmveth.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++ drivers/net/ibmveth.h | 41 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 92 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 0c35d72f5f8..9353890dcda 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -47,6 +47,8 @@ #include #include #include +#include +#include #include #include #include @@ -132,6 +134,11 @@ static inline int ibmveth_rxq_frame_length(struct ibmveth_adapter *adapter) return (adapter->rx_queue.queue_addr[adapter->rx_queue.index].length); } +static inline int ibmveth_rxq_csum_good(struct ibmveth_adapter *adapter) +{ + return (adapter->rx_queue.queue_addr[adapter->rx_queue.index].csum_good); +} + /* setup the initial settings for a buffer pool */ static void ibmveth_init_buffer_pool(struct ibmveth_buff_pool *pool, u32 pool_index, u32 pool_size, u32 buff_size, u32 pool_active) { @@ -695,6 +702,24 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) desc[0].fields.length, DMA_TO_DEVICE); desc[0].fields.valid = 1; + if (skb->ip_summed == CHECKSUM_PARTIAL && + ip_hdr(skb)->protocol != IPPROTO_TCP && skb_checksum_help(skb)) { + ibmveth_error_printk("tx: failed to checksum packet\n"); + tx_dropped++; + goto out; + } + + if (skb->ip_summed == CHECKSUM_PARTIAL) { + unsigned char *buf = skb_transport_header(skb) + skb->csum_offset; + + desc[0].fields.no_csum = 1; + desc[0].fields.csum_good = 1; + + /* Need to zero out the checksum */ + buf[0] = 0; + buf[1] = 0; + } + if(dma_mapping_error(desc[0].fields.address)) { ibmveth_error_printk("tx: unable to map initial fragment\n"); tx_map_failed++; @@ -713,6 +738,10 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) frag->size, DMA_TO_DEVICE); desc[curfrag+1].fields.length = frag->size; desc[curfrag+1].fields.valid = 1; + if (skb->ip_summed == CHECKSUM_PARTIAL) { + desc[curfrag+1].fields.no_csum = 1; + desc[curfrag+1].fields.csum_good = 1; + } if(dma_mapping_error(desc[curfrag+1].fields.address)) { ibmveth_error_printk("tx: unable to map fragment %d\n", curfrag); @@ -801,7 +830,11 @@ static int ibmveth_poll(struct napi_struct *napi, int budget) } else { int length = ibmveth_rxq_frame_length(adapter); int offset = ibmveth_rxq_frame_offset(adapter); + int csum_good = ibmveth_rxq_csum_good(adapter); + skb = ibmveth_rxq_get_buffer(adapter); + if (csum_good) + skb->ip_summed = CHECKSUM_UNNECESSARY; ibmveth_rxq_harvest_buffer(adapter); @@ -962,8 +995,10 @@ static void ibmveth_poll_controller(struct net_device *dev) static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id) { int rc, i; + long ret; struct net_device *netdev; struct ibmveth_adapter *adapter; + union ibmveth_illan_attributes set_attr, ret_attr; unsigned char *mac_addr_p; unsigned int *mcastFilterSize_p; @@ -1057,6 +1092,24 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ ibmveth_debug_printk("registering netdev...\n"); + ret = h_illan_attributes(dev->unit_address, 0, 0, &ret_attr.desc); + + if (ret == H_SUCCESS && !ret_attr.fields.active_trunk && + !ret_attr.fields.trunk_priority && + ret_attr.fields.csum_offload_padded_pkt_support) { + set_attr.desc = 0; + set_attr.fields.tcp_csum_offload_ipv4 = 1; + + ret = h_illan_attributes(dev->unit_address, 0, set_attr.desc, + &ret_attr.desc); + + if (ret == H_SUCCESS) + netdev->features |= NETIF_F_IP_CSUM; + else + ret = h_illan_attributes(dev->unit_address, set_attr.desc, + 0, &ret_attr.desc); + } + rc = register_netdev(netdev); if(rc) { diff --git a/drivers/net/ibmveth.h b/drivers/net/ibmveth.h index e05694126f8..3f10f0f4447 100644 --- a/drivers/net/ibmveth.h +++ b/drivers/net/ibmveth.h @@ -67,6 +67,21 @@ static inline long h_send_logical_lan(unsigned long unit_address, return rc; } +static inline long h_illan_attributes(unsigned long unit_address, + unsigned long reset_mask, unsigned long set_mask, + unsigned long *ret_attributes) +{ + long rc; + unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; + + rc = plpar_hcall(H_ILLAN_ATTRIBUTES, retbuf, unit_address, + reset_mask, set_mask); + + *ret_attributes = retbuf[0]; + + return rc; +} + #define h_multicast_ctrl(ua, cmd, mac) \ plpar_hcall_norets(H_MULTICAST_CTRL, ua, cmd, mac) @@ -142,7 +157,9 @@ struct ibmveth_adapter { struct ibmveth_buf_desc_fields { u32 valid : 1; u32 toggle : 1; - u32 reserved : 6; + u32 reserved : 4; + u32 no_csum : 1; + u32 csum_good : 1; u32 length : 24; u32 address; }; @@ -152,10 +169,30 @@ union ibmveth_buf_desc { struct ibmveth_buf_desc_fields fields; }; +struct ibmveth_illan_attributes_fields { + u32 reserved; + u32 reserved2 : 18; + u32 csum_offload_padded_pkt_support : 1; + u32 reserved3 : 1; + u32 trunk_priority : 4; + u32 reserved4 : 5; + u32 tcp_csum_offload_ipv6 : 1; + u32 tcp_csum_offload_ipv4 : 1; + u32 active_trunk : 1; +}; + +union ibmveth_illan_attributes { + u64 desc; + struct ibmveth_illan_attributes_fields fields; +}; + struct ibmveth_rx_q_entry { u16 toggle : 1; u16 valid : 1; - u16 reserved : 14; + u16 reserved : 4; + u16 no_csum : 1; + u16 csum_good : 1; + u16 reserved2 : 8; u16 offset; u32 length; u64 correlator; -- cgit v1.2.3-70-g09d2 From 5fc7e01cb77132f96e171a37f9f792270b1603f6 Mon Sep 17 00:00:00 2001 From: Brian King Date: Fri, 17 Aug 2007 09:16:31 -0500 Subject: ibmveth: Implement ethtool hooks to enable/disable checksum offload This patch adds the appropriate ethtool hooks to allow for enabling/disabling of hypervisor assisted checksum offload for TCP. Signed-off-by: Brian King Signed-off-by: Jeff Garzik --- drivers/net/ibmveth.c | 125 +++++++++++++++++++++++++++++++++++++++++++++++++- drivers/net/ibmveth.h | 1 + 2 files changed, 124 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 9353890dcda..9c16928e20e 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -652,12 +652,132 @@ static u32 netdev_get_link(struct net_device *dev) { return 1; } +static void ibmveth_set_rx_csum_flags(struct net_device *dev, u32 data) +{ + struct ibmveth_adapter *adapter = dev->priv; + + if (data) + adapter->rx_csum = 1; + else { + /* + * Since the ibmveth firmware interface does not have the concept of + * separate tx/rx checksum offload enable, if rx checksum is disabled + * we also have to disable tx checksum offload. Once we disable rx + * checksum offload, we are no longer allowed to send tx buffers that + * are not properly checksummed. + */ + adapter->rx_csum = 0; + dev->features &= ~NETIF_F_IP_CSUM; + } +} + +static void ibmveth_set_tx_csum_flags(struct net_device *dev, u32 data) +{ + struct ibmveth_adapter *adapter = dev->priv; + + if (data) { + dev->features |= NETIF_F_IP_CSUM; + adapter->rx_csum = 1; + } else + dev->features &= ~NETIF_F_IP_CSUM; +} + +static int ibmveth_set_csum_offload(struct net_device *dev, u32 data, + void (*done) (struct net_device *, u32)) +{ + struct ibmveth_adapter *adapter = dev->priv; + union ibmveth_illan_attributes set_attr, clr_attr, ret_attr; + long ret; + int rc1 = 0, rc2 = 0; + int restart = 0; + + if (netif_running(dev)) { + restart = 1; + adapter->pool_config = 1; + ibmveth_close(dev); + adapter->pool_config = 0; + } + + set_attr.desc = 0; + clr_attr.desc = 0; + + if (data) + set_attr.fields.tcp_csum_offload_ipv4 = 1; + else + clr_attr.fields.tcp_csum_offload_ipv4 = 1; + + ret = h_illan_attributes(adapter->vdev->unit_address, 0, 0, &ret_attr.desc); + + if (ret == H_SUCCESS && !ret_attr.fields.active_trunk && + !ret_attr.fields.trunk_priority && + ret_attr.fields.csum_offload_padded_pkt_support) { + ret = h_illan_attributes(adapter->vdev->unit_address, clr_attr.desc, + set_attr.desc, &ret_attr.desc); + + if (ret != H_SUCCESS) { + rc1 = -EIO; + ibmveth_error_printk("unable to change checksum offload settings." + " %d rc=%ld\n", data, ret); + + ret = h_illan_attributes(adapter->vdev->unit_address, + set_attr.desc, clr_attr.desc, &ret_attr.desc); + } else + done(dev, data); + } else { + rc1 = -EIO; + ibmveth_error_printk("unable to change checksum offload settings." + " %d rc=%ld ret_attr=%lx\n", data, ret, ret_attr.desc); + } + + if (restart) + rc2 = ibmveth_open(dev); + + return rc1 ? rc1 : rc2; +} + +static int ibmveth_set_rx_csum(struct net_device *dev, u32 data) +{ + struct ibmveth_adapter *adapter = dev->priv; + + if ((data && adapter->rx_csum) || (!data && !adapter->rx_csum)) + return 0; + + return ibmveth_set_csum_offload(dev, data, ibmveth_set_rx_csum_flags); +} + +static int ibmveth_set_tx_csum(struct net_device *dev, u32 data) +{ + struct ibmveth_adapter *adapter = dev->priv; + int rc = 0; + + if (data && (dev->features & NETIF_F_IP_CSUM)) + return 0; + if (!data && !(dev->features & NETIF_F_IP_CSUM)) + return 0; + + if (data && !adapter->rx_csum) + rc = ibmveth_set_csum_offload(dev, data, ibmveth_set_tx_csum_flags); + else + ibmveth_set_tx_csum_flags(dev, data); + + return rc; +} + +static u32 ibmveth_get_rx_csum(struct net_device *dev) +{ + struct ibmveth_adapter *adapter = dev->priv; + return adapter->rx_csum; +} + static const struct ethtool_ops netdev_ethtool_ops = { .get_drvinfo = netdev_get_drvinfo, .get_settings = netdev_get_settings, .get_link = netdev_get_link, .get_sg = ethtool_op_get_sg, .get_tx_csum = ethtool_op_get_tx_csum, + .set_tx_csum = ibmveth_set_tx_csum, + .get_rx_csum = ibmveth_get_rx_csum, + .set_rx_csum = ibmveth_set_rx_csum, }; static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) @@ -1103,9 +1223,10 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ ret = h_illan_attributes(dev->unit_address, 0, set_attr.desc, &ret_attr.desc); - if (ret == H_SUCCESS) + if (ret == H_SUCCESS) { + adapter->rx_csum = 1; netdev->features |= NETIF_F_IP_CSUM; - else + } else ret = h_illan_attributes(dev->unit_address, set_attr.desc, 0, &ret_attr.desc); } diff --git a/drivers/net/ibmveth.h b/drivers/net/ibmveth.h index 3f10f0f4447..43b068d9a55 100644 --- a/drivers/net/ibmveth.h +++ b/drivers/net/ibmveth.h @@ -138,6 +138,7 @@ struct ibmveth_adapter { struct ibmveth_buff_pool rx_buff_pool[IbmVethNumBufferPools]; struct ibmveth_rx_q rx_queue; int pool_config; + int rx_csum; /* adapter specific stats */ u64 replenish_task_cycles; -- cgit v1.2.3-70-g09d2 From 80e536770c2fcb8d2b7be9f5a36b85c36fd5943a Mon Sep 17 00:00:00 2001 From: Brian King Date: Fri, 17 Aug 2007 09:16:37 -0500 Subject: ibmveth: Add ethtool TSO handlers Add handlers for get_tso and get_ufo to prevent errors being printed by ethtool. Signed-off-by: Brian King Signed-off-by: Jeff Garzik --- drivers/net/ibmveth.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 9c16928e20e..9bf0f92d3a5 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -778,6 +778,8 @@ static const struct ethtool_ops netdev_ethtool_ops = { .set_tx_csum = ibmveth_set_tx_csum, .get_rx_csum = ibmveth_get_rx_csum, .set_rx_csum = ibmveth_set_rx_csum, + .get_tso = ethtool_op_get_tso, + .get_ufo = ethtool_op_get_ufo, }; static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -- cgit v1.2.3-70-g09d2 From ddbb4de9672097da2c0f19c6ebca0ebb5672e9b8 Mon Sep 17 00:00:00 2001 From: Brian King Date: Fri, 17 Aug 2007 09:16:43 -0500 Subject: ibmveth: Add ethtool driver stats hooks Add ethtool hooks to ibmveth to retrieve driver statistics. Signed-off-by: Brian King Signed-off-by: Jeff Garzik --- drivers/net/ibmveth.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 9bf0f92d3a5..40cb00e37df 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -113,6 +113,28 @@ MODULE_DESCRIPTION("IBM i/pSeries Virtual Ethernet Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(ibmveth_driver_version); +struct ibmveth_stat { + char name[ETH_GSTRING_LEN]; + int offset; +}; + +#define IBMVETH_STAT_OFF(stat) offsetof(struct ibmveth_adapter, stat) +#define IBMVETH_GET_STAT(a, off) *((u64 *)(((unsigned long)(a)) + off)) + +struct ibmveth_stat ibmveth_stats[] = { + { "replenish_task_cycles", IBMVETH_STAT_OFF(replenish_task_cycles) }, + { "replenish_no_mem", IBMVETH_STAT_OFF(replenish_no_mem) }, + { "replenish_add_buff_failure", IBMVETH_STAT_OFF(replenish_add_buff_failure) }, + { "replenish_add_buff_success", IBMVETH_STAT_OFF(replenish_add_buff_success) }, + { "rx_invalid_buffer", IBMVETH_STAT_OFF(rx_invalid_buffer) }, + { "rx_no_buffer", IBMVETH_STAT_OFF(rx_no_buffer) }, + { "tx_multidesc_send", IBMVETH_STAT_OFF(tx_multidesc_send) }, + { "tx_linearized", IBMVETH_STAT_OFF(tx_linearized) }, + { "tx_linearize_failed", IBMVETH_STAT_OFF(tx_linearize_failed) }, + { "tx_map_failed", IBMVETH_STAT_OFF(tx_map_failed) }, + { "tx_send_failed", IBMVETH_STAT_OFF(tx_send_failed) }, +}; + /* simple methods of getting data from the current rxq entry */ static inline int ibmveth_rxq_pending_buffer(struct ibmveth_adapter *adapter) { @@ -769,6 +791,32 @@ static u32 ibmveth_get_rx_csum(struct net_device *dev) return adapter->rx_csum; } +static void ibmveth_get_strings(struct net_device *dev, u32 stringset, u8 *data) +{ + int i; + + if (stringset != ETH_SS_STATS) + return; + + for (i = 0; i < ARRAY_SIZE(ibmveth_stats); i++, data += ETH_GSTRING_LEN) + memcpy(data, ibmveth_stats[i].name, ETH_GSTRING_LEN); +} + +static int ibmveth_get_stats_count(struct net_device *dev) +{ + return ARRAY_SIZE(ibmveth_stats); +} + +static void ibmveth_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, u64 *data) +{ + int i; + struct ibmveth_adapter *adapter = dev->priv; + + for (i = 0; i < ARRAY_SIZE(ibmveth_stats); i++) + data[i] = IBMVETH_GET_STAT(adapter, ibmveth_stats[i].offset); +} + static const struct ethtool_ops netdev_ethtool_ops = { .get_drvinfo = netdev_get_drvinfo, .get_settings = netdev_get_settings, @@ -780,6 +828,9 @@ static const struct ethtool_ops netdev_ethtool_ops = { .set_rx_csum = ibmveth_set_rx_csum, .get_tso = ethtool_op_get_tso, .get_ufo = ethtool_op_get_ufo, + .get_strings = ibmveth_get_strings, + .get_stats_count = ibmveth_get_stats_count, + .get_ethtool_stats = ibmveth_get_ethtool_stats, }; static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -- cgit v1.2.3-70-g09d2 From 3449a2ab31681420515e242920e755262b4f41e9 Mon Sep 17 00:00:00 2001 From: Brian King Date: Fri, 17 Aug 2007 09:16:49 -0500 Subject: ibmveth: Remove dead frag processing code Removes dead frag processing code from ibmveth. Since NETIF_F_SG was not set, this code was never executed. Also, since the ibmveth interface can only handle 6 fragments, core networking code would need to be modified in order to efficiently enable this support. Signed-off-by: Brian King Signed-off-by: Jeff Garzik --- drivers/net/ibmveth.c | 100 +++++++++----------------------------------------- drivers/net/ibmveth.h | 5 --- 2 files changed, 17 insertions(+), 88 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 40cb00e37df..f6be7b29c84 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -28,7 +28,6 @@ /**************************************************************************/ /* TODO: - - remove frag processing code - no longer needed - add support for sysfs - possibly remove procfs support */ @@ -128,9 +127,6 @@ struct ibmveth_stat ibmveth_stats[] = { { "replenish_add_buff_success", IBMVETH_STAT_OFF(replenish_add_buff_success) }, { "rx_invalid_buffer", IBMVETH_STAT_OFF(rx_invalid_buffer) }, { "rx_no_buffer", IBMVETH_STAT_OFF(rx_no_buffer) }, - { "tx_multidesc_send", IBMVETH_STAT_OFF(tx_multidesc_send) }, - { "tx_linearized", IBMVETH_STAT_OFF(tx_linearized) }, - { "tx_linearize_failed", IBMVETH_STAT_OFF(tx_linearize_failed) }, { "tx_map_failed", IBMVETH_STAT_OFF(tx_map_failed) }, { "tx_send_failed", IBMVETH_STAT_OFF(tx_send_failed) }, }; @@ -843,9 +839,8 @@ static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) { struct ibmveth_adapter *adapter = netdev->priv; - union ibmveth_buf_desc desc[IbmVethMaxSendFrags]; + union ibmveth_buf_desc desc; unsigned long lpar_rc; - int nfrags = 0, curfrag; unsigned long correlator; unsigned long flags; unsigned int retry_count; @@ -855,25 +850,11 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) unsigned int tx_send_failed = 0; unsigned int tx_map_failed = 0; - - if ((skb_shinfo(skb)->nr_frags + 1) > IbmVethMaxSendFrags) { - tx_dropped++; - goto out; - } - - memset(&desc, 0, sizeof(desc)); - - /* nfrags = number of frags after the initial fragment */ - nfrags = skb_shinfo(skb)->nr_frags; - - if(nfrags) - adapter->tx_multidesc_send++; - - /* map the initial fragment */ - desc[0].fields.length = nfrags ? skb->len - skb->data_len : skb->len; - desc[0].fields.address = dma_map_single(&adapter->vdev->dev, skb->data, - desc[0].fields.length, DMA_TO_DEVICE); - desc[0].fields.valid = 1; + desc.desc = 0; + desc.fields.length = skb->len; + desc.fields.address = dma_map_single(&adapter->vdev->dev, skb->data, + desc.fields.length, DMA_TO_DEVICE); + desc.fields.valid = 1; if (skb->ip_summed == CHECKSUM_PARTIAL && ip_hdr(skb)->protocol != IPPROTO_TCP && skb_checksum_help(skb)) { @@ -885,75 +866,34 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) if (skb->ip_summed == CHECKSUM_PARTIAL) { unsigned char *buf = skb_transport_header(skb) + skb->csum_offset; - desc[0].fields.no_csum = 1; - desc[0].fields.csum_good = 1; + desc.fields.no_csum = 1; + desc.fields.csum_good = 1; /* Need to zero out the checksum */ buf[0] = 0; buf[1] = 0; } - if(dma_mapping_error(desc[0].fields.address)) { - ibmveth_error_printk("tx: unable to map initial fragment\n"); + if (dma_mapping_error(desc.fields.address)) { + ibmveth_error_printk("tx: unable to map xmit buffer\n"); tx_map_failed++; tx_dropped++; goto out; } - curfrag = nfrags; - - /* map fragments past the initial portion if there are any */ - while(curfrag--) { - skb_frag_t *frag = &skb_shinfo(skb)->frags[curfrag]; - desc[curfrag+1].fields.address - = dma_map_single(&adapter->vdev->dev, - page_address(frag->page) + frag->page_offset, - frag->size, DMA_TO_DEVICE); - desc[curfrag+1].fields.length = frag->size; - desc[curfrag+1].fields.valid = 1; - if (skb->ip_summed == CHECKSUM_PARTIAL) { - desc[curfrag+1].fields.no_csum = 1; - desc[curfrag+1].fields.csum_good = 1; - } - - if(dma_mapping_error(desc[curfrag+1].fields.address)) { - ibmveth_error_printk("tx: unable to map fragment %d\n", curfrag); - tx_map_failed++; - tx_dropped++; - /* Free all the mappings we just created */ - while(curfrag < nfrags) { - dma_unmap_single(&adapter->vdev->dev, - desc[curfrag+1].fields.address, - desc[curfrag+1].fields.length, - DMA_TO_DEVICE); - curfrag++; - } - goto out; - } - } - /* send the frame. Arbitrarily set retrycount to 1024 */ correlator = 0; retry_count = 1024; do { lpar_rc = h_send_logical_lan(adapter->vdev->unit_address, - desc[0].desc, - desc[1].desc, - desc[2].desc, - desc[3].desc, - desc[4].desc, - desc[5].desc, - correlator, - &correlator); + desc.desc, 0, 0, 0, 0, 0, + correlator, &correlator); } while ((lpar_rc == H_BUSY) && (retry_count--)); if(lpar_rc != H_SUCCESS && lpar_rc != H_DROPPED) { - int i; ibmveth_error_printk("tx: h_send_logical_lan failed with rc=%ld\n", lpar_rc); - for(i = 0; i < 6; i++) { - ibmveth_error_printk("tx: desc[%i] valid=%d, len=%d, address=0x%d\n", i, - desc[i].fields.valid, desc[i].fields.length, desc[i].fields.address); - } + ibmveth_error_printk("tx: valid=%d, len=%d, address=0x%08x\n", + desc.fields.valid, desc.fields.length, desc.fields.address); tx_send_failed++; tx_dropped++; } else { @@ -962,11 +902,8 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) netdev->trans_start = jiffies; } - do { - dma_unmap_single(&adapter->vdev->dev, - desc[nfrags].fields.address, - desc[nfrags].fields.length, DMA_TO_DEVICE); - } while(--nfrags >= 0); + dma_unmap_single(&adapter->vdev->dev, desc.fields.address, + desc.fields.length, DMA_TO_DEVICE); out: spin_lock_irqsave(&adapter->stats_lock, flags); adapter->stats.tx_dropped += tx_dropped; @@ -1366,10 +1303,7 @@ static int ibmveth_seq_show(struct seq_file *seq, void *v) firmware_mac[3], firmware_mac[4], firmware_mac[5]); seq_printf(seq, "\nAdapter Statistics:\n"); - seq_printf(seq, " TX: skbuffs linearized: %ld\n", adapter->tx_linearized); - seq_printf(seq, " multi-descriptor sends: %ld\n", adapter->tx_multidesc_send); - seq_printf(seq, " skb_linearize failures: %ld\n", adapter->tx_linearize_failed); - seq_printf(seq, " vio_map_single failres: %ld\n", adapter->tx_map_failed); + seq_printf(seq, " TX: vio_map_single failres: %ld\n", adapter->tx_map_failed); seq_printf(seq, " send failures: %ld\n", adapter->tx_send_failed); seq_printf(seq, " RX: replenish task cycles: %ld\n", adapter->replenish_task_cycles); seq_printf(seq, " alloc_skb_failures: %ld\n", adapter->replenish_no_mem); diff --git a/drivers/net/ibmveth.h b/drivers/net/ibmveth.h index 43b068d9a55..30f9fc67b0c 100644 --- a/drivers/net/ibmveth.h +++ b/drivers/net/ibmveth.h @@ -25,8 +25,6 @@ #ifndef _IBMVETH_H #define _IBMVETH_H -#define IbmVethMaxSendFrags 6 - /* constants for H_MULTICAST_CTRL */ #define IbmVethMcastReceptionModifyBit 0x80000UL #define IbmVethMcastReceptionEnableBit 0x20000UL @@ -147,9 +145,6 @@ struct ibmveth_adapter { u64 replenish_add_buff_success; u64 rx_invalid_buffer; u64 rx_no_buffer; - u64 tx_multidesc_send; - u64 tx_linearized; - u64 tx_linearize_failed; u64 tx_map_failed; u64 tx_send_failed; spinlock_t stats_lock; -- cgit v1.2.3-70-g09d2 From 79ef4a4dd44cd4f9942975b0f625bd01549a2aa9 Mon Sep 17 00:00:00 2001 From: Brian King Date: Fri, 17 Aug 2007 09:16:56 -0500 Subject: ibmveth: Remove use of bitfields Removes the use of bitfields from the ibmveth driver. This results in slightly smaller object code. Signed-off-by: Brian King Signed-off-by: Jeff Garzik --- drivers/net/ibmveth.c | 90 +++++++++++++++++++++++++-------------------------- drivers/net/ibmveth.h | 56 +++++++++++++------------------- 2 files changed, 68 insertions(+), 78 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index f6be7b29c84..2dff9f2800c 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -132,19 +132,29 @@ struct ibmveth_stat ibmveth_stats[] = { }; /* simple methods of getting data from the current rxq entry */ +static inline u32 ibmveth_rxq_flags(struct ibmveth_adapter *adapter) +{ + return adapter->rx_queue.queue_addr[adapter->rx_queue.index].flags_off; +} + +static inline int ibmveth_rxq_toggle(struct ibmveth_adapter *adapter) +{ + return (ibmveth_rxq_flags(adapter) & IBMVETH_RXQ_TOGGLE) >> IBMVETH_RXQ_TOGGLE_SHIFT; +} + static inline int ibmveth_rxq_pending_buffer(struct ibmveth_adapter *adapter) { - return (adapter->rx_queue.queue_addr[adapter->rx_queue.index].toggle == adapter->rx_queue.toggle); + return (ibmveth_rxq_toggle(adapter) == adapter->rx_queue.toggle); } static inline int ibmveth_rxq_buffer_valid(struct ibmveth_adapter *adapter) { - return (adapter->rx_queue.queue_addr[adapter->rx_queue.index].valid); + return (ibmveth_rxq_flags(adapter) & IBMVETH_RXQ_VALID); } static inline int ibmveth_rxq_frame_offset(struct ibmveth_adapter *adapter) { - return (adapter->rx_queue.queue_addr[adapter->rx_queue.index].offset); + return (ibmveth_rxq_flags(adapter) & IBMVETH_RXQ_OFF_MASK); } static inline int ibmveth_rxq_frame_length(struct ibmveth_adapter *adapter) @@ -154,7 +164,7 @@ static inline int ibmveth_rxq_frame_length(struct ibmveth_adapter *adapter) static inline int ibmveth_rxq_csum_good(struct ibmveth_adapter *adapter) { - return (adapter->rx_queue.queue_addr[adapter->rx_queue.index].csum_good); + return (ibmveth_rxq_flags(adapter) & IBMVETH_RXQ_CSUM_GOOD); } /* setup the initial settings for a buffer pool */ @@ -254,9 +264,7 @@ static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter, struc correlator = ((u64)pool->index << 32) | index; *(u64*)skb->data = correlator; - desc.desc = 0; - desc.fields.valid = 1; - desc.fields.length = pool->buff_size; + desc.fields.flags_len = IBMVETH_BUF_VALID | pool->buff_size; desc.fields.address = dma_addr; lpar_rc = h_add_logical_lan_buffer(adapter->vdev->unit_address, desc.desc); @@ -397,9 +405,8 @@ static void ibmveth_rxq_recycle_buffer(struct ibmveth_adapter *adapter) return; } - desc.desc = 0; - desc.fields.valid = 1; - desc.fields.length = adapter->rx_buff_pool[pool].buff_size; + desc.fields.flags_len = IBMVETH_BUF_VALID | + adapter->rx_buff_pool[pool].buff_size; desc.fields.address = adapter->rx_buff_pool[pool].dma_addr[index]; lpar_rc = h_add_logical_lan_buffer(adapter->vdev->unit_address, desc.desc); @@ -555,9 +562,7 @@ static int ibmveth_open(struct net_device *netdev) memcpy(&mac_address, netdev->dev_addr, netdev->addr_len); mac_address = mac_address >> 16; - rxq_desc.desc = 0; - rxq_desc.fields.valid = 1; - rxq_desc.fields.length = adapter->rx_queue.queue_len; + rxq_desc.fields.flags_len = IBMVETH_BUF_VALID | adapter->rx_queue.queue_len; rxq_desc.fields.address = adapter->rx_queue.queue_dma; ibmveth_debug_printk("buffer list @ 0x%p\n", adapter->buffer_list_addr); @@ -704,7 +709,7 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data, void (*done) (struct net_device *, u32)) { struct ibmveth_adapter *adapter = dev->priv; - union ibmveth_illan_attributes set_attr, clr_attr, ret_attr; + u64 set_attr, clr_attr, ret_attr; long ret; int rc1 = 0, rc2 = 0; int restart = 0; @@ -716,21 +721,21 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data, adapter->pool_config = 0; } - set_attr.desc = 0; - clr_attr.desc = 0; + set_attr = 0; + clr_attr = 0; if (data) - set_attr.fields.tcp_csum_offload_ipv4 = 1; + set_attr = IBMVETH_ILLAN_IPV4_TCP_CSUM; else - clr_attr.fields.tcp_csum_offload_ipv4 = 1; + clr_attr = IBMVETH_ILLAN_IPV4_TCP_CSUM; - ret = h_illan_attributes(adapter->vdev->unit_address, 0, 0, &ret_attr.desc); + ret = h_illan_attributes(adapter->vdev->unit_address, 0, 0, &ret_attr); - if (ret == H_SUCCESS && !ret_attr.fields.active_trunk && - !ret_attr.fields.trunk_priority && - ret_attr.fields.csum_offload_padded_pkt_support) { - ret = h_illan_attributes(adapter->vdev->unit_address, clr_attr.desc, - set_attr.desc, &ret_attr.desc); + if (ret == H_SUCCESS && !(ret_attr & IBMVETH_ILLAN_ACTIVE_TRUNK) && + !(ret_attr & IBMVETH_ILLAN_TRUNK_PRI_MASK) && + (ret_attr & IBMVETH_ILLAN_PADDED_PKT_CSUM)) { + ret = h_illan_attributes(adapter->vdev->unit_address, clr_attr, + set_attr, &ret_attr); if (ret != H_SUCCESS) { rc1 = -EIO; @@ -738,13 +743,13 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data, " %d rc=%ld\n", data, ret); ret = h_illan_attributes(adapter->vdev->unit_address, - set_attr.desc, clr_attr.desc, &ret_attr.desc); + set_attr, clr_attr, &ret_attr); } else done(dev, data); } else { rc1 = -EIO; ibmveth_error_printk("unable to change checksum offload settings." - " %d rc=%ld ret_attr=%lx\n", data, ret, ret_attr.desc); + " %d rc=%ld ret_attr=%lx\n", data, ret, ret_attr); } if (restart) @@ -850,11 +855,9 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) unsigned int tx_send_failed = 0; unsigned int tx_map_failed = 0; - desc.desc = 0; - desc.fields.length = skb->len; + desc.fields.flags_len = IBMVETH_BUF_VALID | skb->len; desc.fields.address = dma_map_single(&adapter->vdev->dev, skb->data, - desc.fields.length, DMA_TO_DEVICE); - desc.fields.valid = 1; + skb->len, DMA_TO_DEVICE); if (skb->ip_summed == CHECKSUM_PARTIAL && ip_hdr(skb)->protocol != IPPROTO_TCP && skb_checksum_help(skb)) { @@ -866,8 +869,7 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) if (skb->ip_summed == CHECKSUM_PARTIAL) { unsigned char *buf = skb_transport_header(skb) + skb->csum_offset; - desc.fields.no_csum = 1; - desc.fields.csum_good = 1; + desc.fields.flags_len |= (IBMVETH_BUF_NO_CSUM | IBMVETH_BUF_CSUM_GOOD); /* Need to zero out the checksum */ buf[0] = 0; @@ -893,7 +895,8 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) if(lpar_rc != H_SUCCESS && lpar_rc != H_DROPPED) { ibmveth_error_printk("tx: h_send_logical_lan failed with rc=%ld\n", lpar_rc); ibmveth_error_printk("tx: valid=%d, len=%d, address=0x%08x\n", - desc.fields.valid, desc.fields.length, desc.fields.address); + (desc.fields.flags_len & IBMVETH_BUF_VALID) ? 1 : 0, + skb->len, desc.fields.address); tx_send_failed++; tx_dropped++; } else { @@ -903,7 +906,7 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) } dma_unmap_single(&adapter->vdev->dev, desc.fields.address, - desc.fields.length, DMA_TO_DEVICE); + skb->len, DMA_TO_DEVICE); out: spin_lock_irqsave(&adapter->stats_lock, flags); adapter->stats.tx_dropped += tx_dropped; @@ -1108,7 +1111,7 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ long ret; struct net_device *netdev; struct ibmveth_adapter *adapter; - union ibmveth_illan_attributes set_attr, ret_attr; + u64 set_attr, ret_attr; unsigned char *mac_addr_p; unsigned int *mcastFilterSize_p; @@ -1202,23 +1205,20 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ ibmveth_debug_printk("registering netdev...\n"); - ret = h_illan_attributes(dev->unit_address, 0, 0, &ret_attr.desc); + ret = h_illan_attributes(dev->unit_address, 0, 0, &ret_attr); - if (ret == H_SUCCESS && !ret_attr.fields.active_trunk && - !ret_attr.fields.trunk_priority && - ret_attr.fields.csum_offload_padded_pkt_support) { - set_attr.desc = 0; - set_attr.fields.tcp_csum_offload_ipv4 = 1; + if (ret == H_SUCCESS && !(ret_attr & IBMVETH_ILLAN_ACTIVE_TRUNK) && + !(ret_attr & IBMVETH_ILLAN_TRUNK_PRI_MASK) && + (ret_attr & IBMVETH_ILLAN_PADDED_PKT_CSUM)) { + set_attr = IBMVETH_ILLAN_IPV4_TCP_CSUM; - ret = h_illan_attributes(dev->unit_address, 0, set_attr.desc, - &ret_attr.desc); + ret = h_illan_attributes(dev->unit_address, 0, set_attr, &ret_attr); if (ret == H_SUCCESS) { adapter->rx_csum = 1; netdev->features |= NETIF_F_IP_CSUM; } else - ret = h_illan_attributes(dev->unit_address, set_attr.desc, - 0, &ret_attr.desc); + ret = h_illan_attributes(dev->unit_address, set_attr, 0, &ret_attr); } rc = register_netdev(netdev); diff --git a/drivers/net/ibmveth.h b/drivers/net/ibmveth.h index 30f9fc67b0c..41f61cd1885 100644 --- a/drivers/net/ibmveth.h +++ b/drivers/net/ibmveth.h @@ -39,6 +39,12 @@ #define IbmVethMcastRemoveFilter 0x2UL #define IbmVethMcastClearFilterTable 0x3UL +#define IBMVETH_ILLAN_PADDED_PKT_CSUM 0x0000000000002000ULL +#define IBMVETH_ILLAN_TRUNK_PRI_MASK 0x0000000000000F00ULL +#define IBMVETH_ILLAN_IPV6_TCP_CSUM 0x0000000000000004ULL +#define IBMVETH_ILLAN_IPV4_TCP_CSUM 0x0000000000000002ULL +#define IBMVETH_ILLAN_ACTIVE_TRUNK 0x0000000000000001ULL + /* hcall macros */ #define h_register_logical_lan(ua, buflst, rxq, fltlst, mac) \ plpar_hcall_norets(H_REGISTER_LOGICAL_LAN, ua, buflst, rxq, fltlst, mac) @@ -151,13 +157,13 @@ struct ibmveth_adapter { }; struct ibmveth_buf_desc_fields { - u32 valid : 1; - u32 toggle : 1; - u32 reserved : 4; - u32 no_csum : 1; - u32 csum_good : 1; - u32 length : 24; - u32 address; + u32 flags_len; +#define IBMVETH_BUF_VALID 0x80000000 +#define IBMVETH_BUF_TOGGLE 0x40000000 +#define IBMVETH_BUF_NO_CSUM 0x02000000 +#define IBMVETH_BUF_CSUM_GOOD 0x01000000 +#define IBMVETH_BUF_LEN_MASK 0x00FFFFFF + u32 address; }; union ibmveth_buf_desc { @@ -165,33 +171,17 @@ union ibmveth_buf_desc { struct ibmveth_buf_desc_fields fields; }; -struct ibmveth_illan_attributes_fields { - u32 reserved; - u32 reserved2 : 18; - u32 csum_offload_padded_pkt_support : 1; - u32 reserved3 : 1; - u32 trunk_priority : 4; - u32 reserved4 : 5; - u32 tcp_csum_offload_ipv6 : 1; - u32 tcp_csum_offload_ipv4 : 1; - u32 active_trunk : 1; -}; - -union ibmveth_illan_attributes { - u64 desc; - struct ibmveth_illan_attributes_fields fields; -}; - struct ibmveth_rx_q_entry { - u16 toggle : 1; - u16 valid : 1; - u16 reserved : 4; - u16 no_csum : 1; - u16 csum_good : 1; - u16 reserved2 : 8; - u16 offset; - u32 length; - u64 correlator; + u32 flags_off; +#define IBMVETH_RXQ_TOGGLE 0x80000000 +#define IBMVETH_RXQ_TOGGLE_SHIFT 31 +#define IBMVETH_RXQ_VALID 0x40000000 +#define IBMVETH_RXQ_NO_CSUM 0x02000000 +#define IBMVETH_RXQ_CSUM_GOOD 0x01000000 +#define IBMVETH_RXQ_OFF_MASK 0x0000FFFF + + u32 length; + u64 correlator; }; #endif /* _IBMVETH_H */ -- cgit v1.2.3-70-g09d2 From c8303d10daeacb5dd7714d99f03e15cc6b91a71e Mon Sep 17 00:00:00 2001 From: Mark Hindley Date: Thu, 16 Aug 2007 11:28:40 +0100 Subject: 3c59x: check return of pci_enable_device() Check return of pci_enable_device in vortex_up(). Also modify vortex_up to return error to callers. Handle failure of vortex_up in vortex_open and vortex_resume. Signed-off-by: Mark Hindley Signed-off-by: Jeff Garzik --- drivers/net/3c59x.c | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index a8c0f436cdd..29e558913eb 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -705,7 +705,7 @@ static struct { static int vortex_probe1(struct device *gendev, void __iomem *ioaddr, int irq, int chip_idx, int card_idx); -static void vortex_up(struct net_device *dev); +static int vortex_up(struct net_device *dev); static void vortex_down(struct net_device *dev, int final); static int vortex_open(struct net_device *dev); static void mdio_sync(void __iomem *ioaddr, int bits); @@ -841,8 +841,11 @@ static int vortex_resume(struct pci_dev *pdev) return -EBUSY; } if (netif_running(dev)) { - vortex_up(dev); - netif_device_attach(dev); + err = vortex_up(dev); + if (err) + return err; + else + netif_device_attach(dev); } } return 0; @@ -1484,19 +1487,24 @@ static void vortex_check_media(struct net_device *dev, unsigned int init) } } -static void +static int vortex_up(struct net_device *dev) { struct vortex_private *vp = netdev_priv(dev); void __iomem *ioaddr = vp->ioaddr; unsigned int config; - int i, mii_reg1, mii_reg5; + int i, mii_reg1, mii_reg5, err; if (VORTEX_PCI(vp)) { pci_set_power_state(VORTEX_PCI(vp), PCI_D0); /* Go active */ if (vp->pm_state_valid) pci_restore_state(VORTEX_PCI(vp)); - pci_enable_device(VORTEX_PCI(vp)); + err = pci_enable_device(VORTEX_PCI(vp)); + if (err) { + printk(KERN_WARNING "%s: Could not enable device \n", + dev->name); + goto err_out; + } } /* Before initializing select the active media port. */ @@ -1661,6 +1669,8 @@ vortex_up(struct net_device *dev) if (vp->cb_fn_base) /* The PCMCIA people are idiots. */ iowrite32(0x8000, vp->cb_fn_base + 4); netif_start_queue (dev); +err_out: + return err; } static int @@ -1674,7 +1684,7 @@ vortex_open(struct net_device *dev) if ((retval = request_irq(dev->irq, vp->full_bus_master_rx ? &boomerang_interrupt : &vortex_interrupt, IRQF_SHARED, dev->name, dev))) { printk(KERN_ERR "%s: Could not reserve IRQ %d\n", dev->name, dev->irq); - goto out; + goto err; } if (vp->full_bus_master_rx) { /* Boomerang bus master. */ @@ -1703,20 +1713,22 @@ vortex_open(struct net_device *dev) } } retval = -ENOMEM; - goto out_free_irq; + goto err_free_irq; } /* Wrap the ring. */ vp->rx_ring[i-1].next = cpu_to_le32(vp->rx_ring_dma); } - vortex_up(dev); - return 0; + retval = vortex_up(dev); + if (!retval) + goto out; -out_free_irq: +err_free_irq: free_irq(dev->irq, dev); -out: +err: if (vortex_debug > 1) printk(KERN_ERR "%s: vortex_open() fails: returning %d\n", dev->name, retval); +out: return retval; } -- cgit v1.2.3-70-g09d2 From 52b810d3055f0a49472d05500c6fea5aeabd01a6 Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Tue, 21 Aug 2007 20:49:05 -0700 Subject: cxgb3 - Update rx coalescing length Reduce Rx coalescing length to 12288 Large bursts from the adapter to the host create back pressure on the chip. Reducing the burst size avoids the issue. Signed-off-by: Divy Le Ray Signed-off-by: Jeff Garzik --- drivers/net/cxgb3/common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h index 1746003eb46..d6c77607a11 100644 --- a/drivers/net/cxgb3/common.h +++ b/drivers/net/cxgb3/common.h @@ -104,7 +104,7 @@ enum { PROTO_SRAM_LINES = 128, /* size of TP sram */ }; -#define MAX_RX_COALESCING_LEN 16224U +#define MAX_RX_COALESCING_LEN 12288U enum { PAUSE_RX = 1 << 0, -- cgit v1.2.3-70-g09d2 From 6e3f03b72c1e11e19ea233a411a782f7231ba13f Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Tue, 21 Aug 2007 20:49:10 -0700 Subject: cxgb3 - SGE doorbell overflow warning Log doorbell Fifo overflow Signed-off-by: Divy Le Ray Signed-off-by: Jeff Garzik --- drivers/net/cxgb3/regs.h | 8 ++++++++ drivers/net/cxgb3/sge.c | 4 ++++ 2 files changed, 12 insertions(+) (limited to 'drivers') diff --git a/drivers/net/cxgb3/regs.h b/drivers/net/cxgb3/regs.h index aa80313c922..282427877ea 100644 --- a/drivers/net/cxgb3/regs.h +++ b/drivers/net/cxgb3/regs.h @@ -172,6 +172,14 @@ #define A_SG_INT_CAUSE 0x5c +#define S_HIPIODRBDROPERR 11 +#define V_HIPIODRBDROPERR(x) ((x) << S_HIPIODRBDROPERR) +#define F_HIPIODRBDROPERR V_HIPIODRBDROPERR(1U) + +#define S_LOPIODRBDROPERR 10 +#define V_LOPIODRBDROPERR(x) ((x) << S_LOPIODRBDROPERR) +#define F_LOPIODRBDROPERR V_LOPIODRBDROPERR(1U) + #define S_RSPQDISABLED 3 #define V_RSPQDISABLED(x) ((x) << S_RSPQDISABLED) #define F_RSPQDISABLED V_RSPQDISABLED(1U) diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c index 069c1aca8a6..9233bbba9e9 100644 --- a/drivers/net/cxgb3/sge.c +++ b/drivers/net/cxgb3/sge.c @@ -2458,6 +2458,10 @@ void t3_sge_err_intr_handler(struct adapter *adapter) "(0x%x)\n", (v >> S_RSPQ0DISABLED) & 0xff); } + if (status & (F_HIPIODRBDROPERR | F_LOPIODRBDROPERR)) + CH_ALERT(adapter, "SGE dropped %s priority doorbell\n", + status & F_HIPIODRBDROPERR ? "high" : "lo"); + t3_write_reg(adapter, A_SG_INT_CAUSE, status); if (status & (F_RSPQCREDITOVERFOW | F_RSPQDISABLED)) t3_fatal_err(adapter); -- cgit v1.2.3-70-g09d2 From 27186dc325c3bbb937a27a2467cefd64e2505158 Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Tue, 21 Aug 2007 20:49:15 -0700 Subject: cxgb3 - use immediate data for offload Tx Send small TX_DATA work requests as immediate data even when there are fragments. this avoids doing multiple DMAs for small fragmented packets. The driver already implements this optimization for small contiguous packets. Signed-off-by: Divy Le Ray Signed-off-by: Jeff Garzik --- drivers/net/cxgb3/sge.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c index 9233bbba9e9..540ce5fa1d3 100644 --- a/drivers/net/cxgb3/sge.c +++ b/drivers/net/cxgb3/sge.c @@ -1179,8 +1179,8 @@ int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev) * * Writes a packet as immediate data into a Tx descriptor. The packet * contains a work request at its beginning. We must write the packet - * carefully so the SGE doesn't read accidentally before it's written in - * its entirety. + * carefully so the SGE doesn't read it accidentally before it's written + * in its entirety. */ static inline void write_imm(struct tx_desc *d, struct sk_buff *skb, unsigned int len, unsigned int gen) @@ -1188,7 +1188,11 @@ static inline void write_imm(struct tx_desc *d, struct sk_buff *skb, struct work_request_hdr *from = (struct work_request_hdr *)skb->data; struct work_request_hdr *to = (struct work_request_hdr *)d; - memcpy(&to[1], &from[1], len - sizeof(*from)); + if (likely(!skb->data_len)) + memcpy(&to[1], &from[1], len - sizeof(*from)); + else + skb_copy_bits(skb, sizeof(*from), &to[1], len - sizeof(*from)); + to->wr_hi = from->wr_hi | htonl(F_WR_SOP | F_WR_EOP | V_WR_BCNTLFLT(len & 7)); wmb(); @@ -1258,7 +1262,7 @@ static inline void reclaim_completed_tx_imm(struct sge_txq *q) static inline int immediate(const struct sk_buff *skb) { - return skb->len <= WR_LEN && !skb->data_len; + return skb->len <= WR_LEN; } /** @@ -1464,12 +1468,13 @@ static void write_ofld_wr(struct adapter *adap, struct sk_buff *skb, */ static inline unsigned int calc_tx_descs_ofld(const struct sk_buff *skb) { - unsigned int flits, cnt = skb_shinfo(skb)->nr_frags; + unsigned int flits, cnt; - if (skb->len <= WR_LEN && cnt == 0) + if (skb->len <= WR_LEN) return 1; /* packet fits as immediate data */ flits = skb_transport_offset(skb) / 8; /* headers */ + cnt = skb_shinfo(skb)->nr_frags; if (skb->tail != skb->transport_header) cnt++; return flits_to_desc(flits + sgl_len(cnt)); -- cgit v1.2.3-70-g09d2 From e22bb45d772b5e5c850a6223c2a3245f520de641 Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Tue, 21 Aug 2007 20:49:21 -0700 Subject: cxgb3 - Expose HW memory page info A HW issue requires limiting the receive window size to 23 pages of internal memory. These pages can be configured to different sizes, thus the RDMA driver needs to know the page size to enforce the upper limit. Also assign explicit enum values. Signed-off-by: Divy Le Ray Signed-off-by: Jeff Garzik --- drivers/net/cxgb3/cxgb3_ctl_defs.h | 52 +++++++++++++++++++++++--------------- drivers/net/cxgb3/cxgb3_offload.c | 7 +++++ 2 files changed, 38 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/net/cxgb3/cxgb3_ctl_defs.h b/drivers/net/cxgb3/cxgb3_ctl_defs.h index 2095ddacff7..6c4f3206691 100644 --- a/drivers/net/cxgb3/cxgb3_ctl_defs.h +++ b/drivers/net/cxgb3/cxgb3_ctl_defs.h @@ -33,27 +33,29 @@ #define _CXGB3_OFFLOAD_CTL_DEFS_H enum { - GET_MAX_OUTSTANDING_WR, - GET_TX_MAX_CHUNK, - GET_TID_RANGE, - GET_STID_RANGE, - GET_RTBL_RANGE, - GET_L2T_CAPACITY, - GET_MTUS, - GET_WR_LEN, - GET_IFF_FROM_MAC, - GET_DDP_PARAMS, - GET_PORTS, - - ULP_ISCSI_GET_PARAMS, - ULP_ISCSI_SET_PARAMS, - - RDMA_GET_PARAMS, - RDMA_CQ_OP, - RDMA_CQ_SETUP, - RDMA_CQ_DISABLE, - RDMA_CTRL_QP_SETUP, - RDMA_GET_MEM, + GET_MAX_OUTSTANDING_WR = 0, + GET_TX_MAX_CHUNK = 1, + GET_TID_RANGE = 2, + GET_STID_RANGE = 3, + GET_RTBL_RANGE = 4, + GET_L2T_CAPACITY = 5, + GET_MTUS = 6, + GET_WR_LEN = 7, + GET_IFF_FROM_MAC = 8, + GET_DDP_PARAMS = 9, + GET_PORTS = 10, + + ULP_ISCSI_GET_PARAMS = 11, + ULP_ISCSI_SET_PARAMS = 12, + + RDMA_GET_PARAMS = 13, + RDMA_CQ_OP = 14, + RDMA_CQ_SETUP = 15, + RDMA_CQ_DISABLE = 16, + RDMA_CTRL_QP_SETUP = 17, + RDMA_GET_MEM = 18, + + GET_RX_PAGE_INFO = 50, }; /* @@ -161,4 +163,12 @@ struct rdma_ctrlqp_setup { unsigned long long base_addr; unsigned int size; }; + +/* + * Offload TX/RX page information. + */ +struct ofld_page_info { + unsigned int page_size; /* Page size, should be a power of 2 */ + unsigned int num; /* Number of pages */ +}; #endif /* _CXGB3_OFFLOAD_CTL_DEFS_H */ diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c index bdff7baeb59..bac9214170a 100644 --- a/drivers/net/cxgb3/cxgb3_offload.c +++ b/drivers/net/cxgb3/cxgb3_offload.c @@ -317,6 +317,8 @@ static int cxgb_offload_ctl(struct t3cdev *tdev, unsigned int req, void *data) struct iff_mac *iffmacp; struct ddp_params *ddpp; struct adap_ports *ports; + struct ofld_page_info *rx_page_info; + struct tp_params *tp = &adapter->params.tp; int i; switch (req) { @@ -382,6 +384,11 @@ static int cxgb_offload_ctl(struct t3cdev *tdev, unsigned int req, void *data) if (!offload_running(adapter)) return -EAGAIN; return cxgb_rdma_ctl(adapter, req, data); + case GET_RX_PAGE_INFO: + rx_page_info = data; + rx_page_info->page_size = tp->rx_pg_size; + rx_page_info->num = tp->rx_num_pgs; + break; default: return -EOPNOTSUPP; } -- cgit v1.2.3-70-g09d2 From c9a6ce500d78932c43361eae28c3de81b3660c77 Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Tue, 21 Aug 2007 20:49:26 -0700 Subject: cxgb3 - tighten checks on TID values Enforce validity checks on connection ids Signed-off-by: Divy Le Ray Signed-off-by: Jeff Garzik --- drivers/net/cxgb3/cxgb3_defs.h | 20 ++++++++++++++++++-- drivers/net/cxgb3/cxgb3_offload.c | 28 +++++++++++++++++++++++----- 2 files changed, 41 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/cxgb3/cxgb3_defs.h b/drivers/net/cxgb3/cxgb3_defs.h index 483a594210a..45e92164c26 100644 --- a/drivers/net/cxgb3/cxgb3_defs.h +++ b/drivers/net/cxgb3/cxgb3_defs.h @@ -79,9 +79,17 @@ static inline struct t3c_tid_entry *lookup_tid(const struct tid_info *t, static inline struct t3c_tid_entry *lookup_stid(const struct tid_info *t, unsigned int tid) { + union listen_entry *e; + if (tid < t->stid_base || tid >= t->stid_base + t->nstids) return NULL; - return &(stid2entry(t, tid)->t3c_tid); + + e = stid2entry(t, tid); + if ((void *)e->next >= (void *)t->tid_tab && + (void *)e->next < (void *)&t->atid_tab[t->natids]) + return NULL; + + return &e->t3c_tid; } /* @@ -90,9 +98,17 @@ static inline struct t3c_tid_entry *lookup_stid(const struct tid_info *t, static inline struct t3c_tid_entry *lookup_atid(const struct tid_info *t, unsigned int tid) { + union active_open_entry *e; + if (tid < t->atid_base || tid >= t->atid_base + t->natids) return NULL; - return &(atid2entry(t, tid)->t3c_tid); + + e = atid2entry(t, tid); + if ((void *)e->next >= (void *)t->tid_tab && + (void *)e->next < (void *)&t->atid_tab[t->natids]) + return NULL; + + return &e->t3c_tid; } int process_rx(struct t3cdev *dev, struct sk_buff **skbs, int n); diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c index bac9214170a..1c8eec38bde 100644 --- a/drivers/net/cxgb3/cxgb3_offload.c +++ b/drivers/net/cxgb3/cxgb3_offload.c @@ -57,7 +57,7 @@ static DEFINE_RWLOCK(adapter_list_lock); static LIST_HEAD(adapter_list); static const unsigned int MAX_ATIDS = 64 * 1024; -static const unsigned int ATID_BASE = 0x100000; +static const unsigned int ATID_BASE = 0x10000; static inline int offload_activated(struct t3cdev *tdev) { @@ -694,10 +694,19 @@ static int do_cr(struct t3cdev *dev, struct sk_buff *skb) { struct cpl_pass_accept_req *req = cplhdr(skb); unsigned int stid = G_PASS_OPEN_TID(ntohl(req->tos_tid)); + struct tid_info *t = &(T3C_DATA(dev))->tid_maps; struct t3c_tid_entry *t3c_tid; + unsigned int tid = GET_TID(req); - t3c_tid = lookup_stid(&(T3C_DATA(dev))->tid_maps, stid); - if (t3c_tid->ctx && t3c_tid->client->handlers && + if (unlikely(tid >= t->ntids)) { + printk("%s: passive open TID %u too large\n", + dev->name, tid); + t3_fatal_err(tdev2adap(dev)); + return CPL_RET_BUF_DONE; + } + + t3c_tid = lookup_stid(t, stid); + if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers && t3c_tid->client->handlers[CPL_PASS_ACCEPT_REQ]) { return t3c_tid->client->handlers[CPL_PASS_ACCEPT_REQ] (dev, skb, t3c_tid->ctx); @@ -779,16 +788,25 @@ static int do_act_establish(struct t3cdev *dev, struct sk_buff *skb) { struct cpl_act_establish *req = cplhdr(skb); unsigned int atid = G_PASS_OPEN_TID(ntohl(req->tos_tid)); + struct tid_info *t = &(T3C_DATA(dev))->tid_maps; struct t3c_tid_entry *t3c_tid; + unsigned int tid = GET_TID(req); - t3c_tid = lookup_atid(&(T3C_DATA(dev))->tid_maps, atid); + if (unlikely(tid >= t->ntids)) { + printk("%s: active establish TID %u too large\n", + dev->name, tid); + t3_fatal_err(tdev2adap(dev)); + return CPL_RET_BUF_DONE; + } + + t3c_tid = lookup_atid(t, atid); if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers && t3c_tid->client->handlers[CPL_ACT_ESTABLISH]) { return t3c_tid->client->handlers[CPL_ACT_ESTABLISH] (dev, skb, t3c_tid->ctx); } else { printk(KERN_ERR "%s: received clientless CPL command 0x%x\n", - dev->name, CPL_PASS_ACCEPT_REQ); + dev->name, CPL_ACT_ESTABLISH); return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG; } } -- cgit v1.2.3-70-g09d2 From c64c2eaeaaf04f9c8a303508f804ba256435d79f Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Tue, 21 Aug 2007 20:49:31 -0700 Subject: cxgb3 - Fatal error update Stop the MAC when a fatal error is detected. Signed-off-by: Divy Le Ray Signed-off-by: Jeff Garzik --- drivers/net/cxgb3/cxgb3_main.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index 57fc199e061..c00f2df05bc 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -2297,6 +2297,10 @@ void t3_fatal_err(struct adapter *adapter) if (adapter->flags & FULL_INIT_DONE) { t3_sge_stop(adapter); + t3_write_reg(adapter, A_XGM_TX_CTRL, 0); + t3_write_reg(adapter, A_XGM_RX_CTRL, 0); + t3_write_reg(adapter, XGM_REG(A_XGM_TX_CTRL, 1), 0); + t3_write_reg(adapter, XGM_REG(A_XGM_RX_CTRL, 1), 0); t3_intr_disable(adapter); } CH_ALERT(adapter, "encountered fatal error, operation suspended\n"); -- cgit v1.2.3-70-g09d2 From 167cdf5fbc64ab8f4eae2cd6d9d0892478d569d7 Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Tue, 21 Aug 2007 20:49:36 -0700 Subject: cxgb3 - log adapter serial number Log HW serial number when cxgb3 module is loaded. Signed-off-by: Divy Le Ray Signed-off-by: Jeff Garzik --- drivers/net/cxgb3/common.h | 2 ++ drivers/net/cxgb3/cxgb3_main.c | 6 ++++-- drivers/net/cxgb3/t3_hw.c | 3 ++- 3 files changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h index d6c77607a11..510e93f90b9 100644 --- a/drivers/net/cxgb3/common.h +++ b/drivers/net/cxgb3/common.h @@ -97,6 +97,7 @@ enum { MAX_NPORTS = 2, /* max # of ports */ MAX_FRAME_SIZE = 10240, /* max MAC frame size, including header + FCS */ EEPROMSIZE = 8192, /* Serial EEPROM size */ + SERNUM_LEN = 16, /* Serial # length */ RSS_TABLE_SIZE = 64, /* size of RSS lookup and mapping tables */ TCB_SIZE = 128, /* TCB size */ NMTUS = 16, /* size of MTU table */ @@ -391,6 +392,7 @@ struct vpd_params { unsigned int uclk; unsigned int mdc; unsigned int mem_timing; + u8 sn[SERNUM_LEN + 1]; u8 eth_base[6]; u8 port_type[MAX_NPORTS]; unsigned short xauicfg[2]; diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index c00f2df05bc..3ee465dd0b0 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -2360,10 +2360,12 @@ static void __devinit print_port_info(struct adapter *adap, (adap->flags & USING_MSIX) ? " MSI-X" : (adap->flags & USING_MSI) ? " MSI" : ""); if (adap->name == dev->name && adap->params.vpd.mclk) - printk(KERN_INFO "%s: %uMB CM, %uMB PMTX, %uMB PMRX\n", + printk(KERN_INFO + "%s: %uMB CM, %uMB PMTX, %uMB PMRX, S/N: %s\n", adap->name, t3_mc7_size(&adap->cm) >> 20, t3_mc7_size(&adap->pmtx) >> 20, - t3_mc7_size(&adap->pmrx) >> 20); + t3_mc7_size(&adap->pmrx) >> 20, + adap->params.vpd.sn); } } diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c index b02d15daf5d..3f7f06b6ee6 100644 --- a/drivers/net/cxgb3/t3_hw.c +++ b/drivers/net/cxgb3/t3_hw.c @@ -505,7 +505,7 @@ struct t3_vpd { u8 vpdr_len[2]; VPD_ENTRY(pn, 16); /* part number */ VPD_ENTRY(ec, 16); /* EC level */ - VPD_ENTRY(sn, 16); /* serial number */ + VPD_ENTRY(sn, SERNUM_LEN); /* serial number */ VPD_ENTRY(na, 12); /* MAC address base */ VPD_ENTRY(cclk, 6); /* core clock */ VPD_ENTRY(mclk, 6); /* mem clock */ @@ -648,6 +648,7 @@ static int get_vpd_params(struct adapter *adapter, struct vpd_params *p) p->uclk = simple_strtoul(vpd.uclk_data, NULL, 10); p->mdc = simple_strtoul(vpd.mdc_data, NULL, 10); p->mem_timing = simple_strtoul(vpd.mt_data, NULL, 10); + memcpy(p->sn, vpd.sn_data, SERNUM_LEN); /* Old eeproms didn't have port information */ if (adapter->params.rev == 0 && !vpd.port0_data[0]) { -- cgit v1.2.3-70-g09d2 From 3f61e4278c8489c1d026a45b0903cd4230d1ec07 Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Tue, 21 Aug 2007 20:49:41 -0700 Subject: cxgb3 - Update internal memory management Set PM1 internal memory to round robin mode It balances access to this internal memory for multiport adapters. Signed-off-by: Divy Le Ray Signed-off-by: Jeff Garzik --- drivers/net/cxgb3/regs.h | 2 ++ drivers/net/cxgb3/t3_hw.c | 2 ++ 2 files changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/net/cxgb3/regs.h b/drivers/net/cxgb3/regs.h index 282427877ea..5e1bc0dec5f 100644 --- a/drivers/net/cxgb3/regs.h +++ b/drivers/net/cxgb3/regs.h @@ -1326,6 +1326,7 @@ #define V_D0_WEIGHT(x) ((x) << S_D0_WEIGHT) #define A_PM1_RX_CFG 0x5c0 +#define A_PM1_RX_MODE 0x5c4 #define A_PM1_RX_INT_ENABLE 0x5d8 @@ -1394,6 +1395,7 @@ #define A_PM1_RX_INT_CAUSE 0x5dc #define A_PM1_TX_CFG 0x5e0 +#define A_PM1_TX_MODE 0x5e4 #define A_PM1_TX_INT_ENABLE 0x5f8 diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c index 3f7f06b6ee6..e958bbe3062 100644 --- a/drivers/net/cxgb3/t3_hw.c +++ b/drivers/net/cxgb3/t3_hw.c @@ -3223,6 +3223,8 @@ int t3_init_hw(struct adapter *adapter, u32 fw_params) t3_set_reg_field(adapter, A_PCIX_CFG, 0, F_CLIDECEN); t3_write_reg(adapter, A_PM1_RX_CFG, 0xffffffff); + t3_write_reg(adapter, A_PM1_RX_MODE, 0); + t3_write_reg(adapter, A_PM1_TX_MODE, 0); init_hw_for_avail_ports(adapter, adapter->params.nports); t3_sge_init(adapter, &adapter->params.sge); -- cgit v1.2.3-70-g09d2 From 5b296bc9e1e5570ce60262e62af066f70180cb99 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 29 Aug 2007 12:58:11 -0700 Subject: sky2: use debugfs rename Use debugfs rename to handle device neame changes. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sky2.c | 56 +++++++++++++++++++++++------------------------------- 1 file changed, 24 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index a0d75b0f379..d10af8ed93d 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -3841,42 +3841,34 @@ static int sky2_device_event(struct notifier_block *unused, unsigned long event, void *ptr) { struct net_device *dev = ptr; + struct sky2_port *sky2 = netdev_priv(dev); - if (dev->open == sky2_up) { - struct sky2_port *sky2 = netdev_priv(dev); + if (dev->open != sky2_up || !sky2_debug) + return NOTIFY_DONE; - switch(event) { - case NETDEV_CHANGENAME: - if (!netif_running(dev)) - break; - /* fallthrough */ - case NETDEV_DOWN: - case NETDEV_GOING_DOWN: - if (sky2->debugfs) { - printk(KERN_DEBUG PFX "%s: remove debugfs\n", - dev->name); - debugfs_remove(sky2->debugfs); - sky2->debugfs = NULL; - } + switch(event) { + case NETDEV_CHANGENAME: + if (sky2->debugfs) { + sky2->debugfs = debugfs_rename(sky2_debug, sky2->debugfs, + sky2_debug, dev->name); + } + break; - if (event != NETDEV_CHANGENAME) - break; - /* fallthrough for changename */ - case NETDEV_UP: - if (sky2_debug) { - struct dentry *d; - d = debugfs_create_file(dev->name, S_IRUGO, - sky2_debug, dev, - &sky2_debug_fops); - if (d == NULL || IS_ERR(d)) - printk(KERN_INFO PFX - "%s: debugfs create failed\n", - dev->name); - else - sky2->debugfs = d; - } - break; + case NETDEV_GOING_DOWN: + if (sky2->debugfs) { + printk(KERN_DEBUG PFX "%s: remove debugfs\n", + dev->name); + debugfs_remove(sky2->debugfs); + sky2->debugfs = NULL; } + break; + + case NETDEV_UP: + sky2->debugfs = debugfs_create_file(dev->name, S_IRUGO, + sky2_debug, dev, + &sky2_debug_fops); + if (IS_ERR(sky2->debugfs)) + sky2->debugfs = NULL; } return NOTIFY_DONE; -- cgit v1.2.3-70-g09d2 From efcf6e2febbfe5b2ab497421e2f7f188e1741cf9 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 29 Aug 2007 12:58:12 -0700 Subject: sky2: document GPHY_CTRL bits Add documentation of GPHY_CTRL register bits even if driver is not using them (yet). Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sky2.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'drivers') diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index f18f8752118..3d4f1903d62 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -1850,6 +1850,28 @@ enum { /* GPHY_CTRL 32 bit GPHY Control Reg (YUKON only) */ enum { + GPC_TX_PAUSE = 1<<30, /* Tx pause enabled (ro) */ + GPC_RX_PAUSE = 1<<29, /* Rx pause enabled (ro) */ + GPC_SPEED = 3<<27, /* PHY speed (ro) */ + GPC_LINK = 1<<26, /* Link up (ro) */ + GPC_DUPLEX = 1<<25, /* Duplex (ro) */ + GPC_CLOCK = 1<<24, /* 125Mhz clock stable (ro) */ + + GPC_PDOWN = 1<<23, /* Internal regulator 2.5 power down */ + GPC_TSTMODE = 1<<22, /* Test mode */ + GPC_REG18 = 1<<21, /* Reg18 Power down */ + GPC_REG12SEL = 3<<19, /* Reg12 power setting */ + GPC_REG18SEL = 3<<17, /* Reg18 power setting */ + GPC_SPILOCK = 1<<16, /* SPI lock (ASF) */ + + GPC_LEDMUX = 3<<14, /* LED Mux */ + GPC_INTPOL = 1<<13, /* Interrupt polarity */ + GPC_DETECT = 1<<12, /* Energy detect */ + GPC_1000HD = 1<<11, /* Enable 1000Mbit HD */ + GPC_SLAVE = 1<<10, /* Slave mode */ + GPC_PAUSE = 1<<9, /* Pause enable */ + GPC_LEDCTL = 3<<6, /* GPHY Leds */ + GPC_RST_CLR = 1<<1, /* Clear GPHY Reset */ GPC_RST_SET = 1<<0, /* Set GPHY Reset */ }; -- cgit v1.2.3-70-g09d2 From 8c4c00f3710f9e5653ed465e88271664f3163930 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 29 Aug 2007 12:58:13 -0700 Subject: sky2: dont restrict config space access Take out the code that protects driver from accessing the PCI config space. We are old enough to run with scissors now. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sky2.c | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index d10af8ed93d..77bfcf0dda3 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -610,7 +610,6 @@ static void sky2_phy_power(struct sky2_hw *hw, unsigned port, int onoff) if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1) onoff = !onoff; - sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); reg1 = sky2_pci_read32(hw, PCI_DEV_REG1); if (onoff) /* Turn off phy power saving */ @@ -620,7 +619,6 @@ static void sky2_phy_power(struct sky2_hw *hw, unsigned port, int onoff) sky2_pci_write32(hw, PCI_DEV_REG1, reg1); sky2_pci_read32(hw, PCI_DEV_REG1); - sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); udelay(100); } @@ -688,11 +686,9 @@ static void sky2_wol_init(struct sky2_port *sky2) sky2_write16(hw, WOL_REGS(port, WOL_CTRL_STAT), ctrl); /* Turn on legacy PCI-Express PME mode */ - sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); reg1 = sky2_pci_read32(hw, PCI_DEV_REG1); reg1 |= PCI_Y2_PME_LEGACY; sky2_pci_write32(hw, PCI_DEV_REG1, reg1); - sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); /* block receiver */ sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET); @@ -2438,10 +2434,8 @@ static void sky2_hw_intr(struct sky2_hw *hw) dev_err(&hw->pdev->dev, "PCI hardware error (0x%x)\n", pci_err); - sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); sky2_pci_write16(hw, PCI_STATUS, pci_err | PCI_STATUS_ERROR_BITS); - sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); } if (status & Y2_IS_PCI_EXP) { @@ -2455,11 +2449,8 @@ static void sky2_hw_intr(struct sky2_hw *hw) pex_err); /* clear the interrupt */ - sky2_write32(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); sky2_pci_write32(hw, PEX_UNC_ERR_STAT, 0xffffffffUL); - sky2_write32(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); - if (pex_err & PEX_FATAL_ERRORS) { u32 hwmsk = sky2_read32(hw, B0_HWE_IMSK); hwmsk &= ~Y2_IS_PCI_EXP; @@ -2804,7 +2795,6 @@ static void sky2_reset(struct sky2_hw *hw) /* clear PCI errors, if any */ status = sky2_pci_read16(hw, PCI_STATUS); - sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); sky2_pci_write16(hw, PCI_STATUS, status | PCI_STATUS_ERROR_BITS); @@ -2827,8 +2817,6 @@ static void sky2_reset(struct sky2_hw *hw) | GMC_BYP_RETR_ON); } - sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); - /* Clear I2C IRQ noise */ sky2_write32(hw, B2_I2C_IRQ, 1); -- cgit v1.2.3-70-g09d2 From 555382cbfc6d2187b53888190755e56f52308cd6 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 29 Aug 2007 12:58:14 -0700 Subject: sky2: advanced error reporting Use the kernel interfaces for advanced error reporting. This should be cleaner and clear up errors on boot. For those systems with busted BIOS's that don't correctly support mmconfig, advanced error reporting will be disabled. The PCI registers for advanced error reporting start at 0x100 which is too large to be accessed by legacy functions. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sky2.c | 47 +++++++++++++++++++++++++++-------------------- drivers/net/sky2.h | 41 ----------------------------------------- 2 files changed, 27 insertions(+), 61 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 77bfcf0dda3..b81d81746c2 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -2421,7 +2422,11 @@ static void sky2_hw_error(struct sky2_hw *hw, unsigned port, u32 status) static void sky2_hw_intr(struct sky2_hw *hw) { + struct pci_dev *pdev = hw->pdev; u32 status = sky2_read32(hw, B0_HWE_ISRC); + u32 hwmsk = sky2_read32(hw, B0_HWE_IMSK); + + status &= hwmsk; if (status & Y2_IS_TIST_OV) sky2_write8(hw, GMAC_TI_ST_CTRL, GMT_ST_CLR_IRQ); @@ -2431,7 +2436,7 @@ static void sky2_hw_intr(struct sky2_hw *hw) pci_err = sky2_pci_read16(hw, PCI_STATUS); if (net_ratelimit()) - dev_err(&hw->pdev->dev, "PCI hardware error (0x%x)\n", + dev_err(&pdev->dev, "PCI hardware error (0x%x)\n", pci_err); sky2_pci_write16(hw, PCI_STATUS, @@ -2440,22 +2445,13 @@ static void sky2_hw_intr(struct sky2_hw *hw) if (status & Y2_IS_PCI_EXP) { /* PCI-Express uncorrectable Error occurred */ - u32 pex_err; - - pex_err = sky2_pci_read32(hw, PEX_UNC_ERR_STAT); + int pos = pci_find_aer_capability(hw->pdev); + u32 err; + pci_read_config_dword(pdev, pos + PCI_ERR_UNCOR_STATUS, &err); if (net_ratelimit()) - dev_err(&hw->pdev->dev, "PCI Express error (0x%x)\n", - pex_err); - - /* clear the interrupt */ - sky2_pci_write32(hw, PEX_UNC_ERR_STAT, - 0xffffffffUL); - if (pex_err & PEX_FATAL_ERRORS) { - u32 hwmsk = sky2_read32(hw, B0_HWE_IMSK); - hwmsk &= ~Y2_IS_PCI_EXP; - sky2_write32(hw, B0_HWE_IMSK, hwmsk); - } + dev_err(&pdev->dev, "PCI Express error (0x%x)\n", err); + pci_cleanup_aer_uncorrect_error_status(pdev); } if (status & Y2_HWE_L1_MASK) @@ -2775,8 +2771,10 @@ static int __devinit sky2_init(struct sky2_hw *hw) static void sky2_reset(struct sky2_hw *hw) { + struct pci_dev *pdev = hw->pdev; u16 status; - int i; + int i, cap; + u32 hwe_mask = Y2_HWE_ALL_MASK; /* disable ASF */ if (hw->chip_id == CHIP_ID_YUKON_EX) { @@ -2800,10 +2798,19 @@ static void sky2_reset(struct sky2_hw *hw) sky2_write8(hw, B0_CTST, CS_MRST_CLR); - /* clear any PEX errors */ - if (pci_find_capability(hw->pdev, PCI_CAP_ID_EXP)) - sky2_pci_write32(hw, PEX_UNC_ERR_STAT, 0xffffffffUL); + cap = pci_find_capability(pdev, PCI_CAP_ID_EXP); + if (cap) { + /* Check for advanced error reporting */ + pci_cleanup_aer_uncorrect_error_status(pdev); + pci_cleanup_aer_correct_error_status(pdev); + /* If error bit is stuck on ignore it */ + if (sky2_read32(hw, B0_HWE_ISRC) & Y2_IS_PCI_EXP) + dev_info(&pdev->dev, "ignoring stuck error report bit\n"); + + else if (pci_enable_pcie_error_reporting(pdev)) + hwe_mask |= Y2_IS_PCI_EXP; + } sky2_power_on(hw); @@ -2855,7 +2862,7 @@ static void sky2_reset(struct sky2_hw *hw) sky2_write8(hw, RAM_BUFFER(i, B3_RI_RTO_XS2), SK_RI_TO_53); } - sky2_write32(hw, B0_HWE_IMSK, Y2_HWE_ALL_MASK); + sky2_write32(hw, B0_HWE_IMSK, hwe_mask); for (i = 0; i < hw->ports; i++) sky2_gmac_reset(hw, i); diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index 3d4f1903d62..6f5e162709b 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -18,14 +18,6 @@ enum { PCI_CFG_REG_1 = 0x94, }; -enum { - PEX_DEV_CAP = 0xe4, - PEX_DEV_CTRL = 0xe8, - PEX_DEV_STA = 0xea, - PEX_LNK_STAT = 0xf2, - PEX_UNC_ERR_STAT= 0x104, -}; - /* Yukon-2 */ enum pci_dev_reg_1 { PCI_Y2_PIG_ENA = 1<<31, /* Enable Plug-in-Go (YUKON-2) */ @@ -151,38 +143,6 @@ enum pci_cfg_reg1 { PCI_STATUS_REC_TARGET_ABORT | \ PCI_STATUS_PARITY) -enum pex_dev_ctrl { - PEX_DC_MAX_RRS_MSK = 7<<12, /* Bit 14..12: Max. Read Request Size */ - PEX_DC_EN_NO_SNOOP = 1<<11,/* Enable No Snoop */ - PEX_DC_EN_AUX_POW = 1<<10,/* Enable AUX Power */ - PEX_DC_EN_PHANTOM = 1<<9, /* Enable Phantom Functions */ - PEX_DC_EN_EXT_TAG = 1<<8, /* Enable Extended Tag Field */ - PEX_DC_MAX_PLS_MSK = 7<<5, /* Bit 7.. 5: Max. Payload Size Mask */ - PEX_DC_EN_REL_ORD = 1<<4, /* Enable Relaxed Ordering */ - PEX_DC_EN_UNS_RQ_RP = 1<<3, /* Enable Unsupported Request Reporting */ - PEX_DC_EN_FAT_ER_RP = 1<<2, /* Enable Fatal Error Reporting */ - PEX_DC_EN_NFA_ER_RP = 1<<1, /* Enable Non-Fatal Error Reporting */ - PEX_DC_EN_COR_ER_RP = 1<<0, /* Enable Correctable Error Reporting */ -}; -#define PEX_DC_MAX_RD_RQ_SIZE(x) (((x)<<12) & PEX_DC_MAX_RRS_MSK) - -/* PEX_UNC_ERR_STAT PEX Uncorrectable Errors Status Register (Yukon-2) */ -enum pex_err { - PEX_UNSUP_REQ = 1<<20, /* Unsupported Request Error */ - - PEX_MALFOR_TLP = 1<<18, /* Malformed TLP */ - - PEX_UNEXP_COMP = 1<<16, /* Unexpected Completion */ - - PEX_COMP_TO = 1<<14, /* Completion Timeout */ - PEX_FLOW_CTRL_P = 1<<13, /* Flow Control Protocol Error */ - PEX_POIS_TLP = 1<<12, /* Poisoned TLP */ - - PEX_DATA_LINK_P = 1<<4, /* Data Link Protocol Error */ - PEX_FATAL_ERRORS= (PEX_MALFOR_TLP | PEX_FLOW_CTRL_P | PEX_DATA_LINK_P), -}; - - enum csr_regs { B0_RAP = 0x0000, B0_CTST = 0x0004, @@ -419,7 +379,6 @@ enum { Y2_IS_PAR_RX2 | Y2_IS_TCP_TXS2| Y2_IS_TCP_TXA2, Y2_HWE_ALL_MASK = Y2_IS_TIST_OV | Y2_IS_MST_ERR | Y2_IS_IRQ_STAT | - Y2_IS_PCI_EXP | Y2_HWE_L1_MASK | Y2_HWE_L2_MASK, }; -- cgit v1.2.3-70-g09d2 From 167f53d05fccb47b6eeadac7f6705b3f2f042d03 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 25 Sep 2007 19:01:02 -0700 Subject: sky2: use pci_config access functions Use the PCI layer config access functions. The driver was using the memory mapped window in device, to workaround issues accessing the advanced error reporting registers. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik Signed-off-by: David S. Miller --- drivers/net/sky2.c | 93 ++++++++++++++++++++++++++++++------------------------ drivers/net/sky2.h | 21 ------------ 2 files changed, 51 insertions(+), 63 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index b81d81746c2..941a6088252 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -223,21 +223,22 @@ static void sky2_power_on(struct sky2_hw *hw) sky2_write8(hw, B2_Y2_CLK_GATE, 0); if (hw->flags & SKY2_HW_ADV_POWER_CTL) { + struct pci_dev *pdev = hw->pdev; u32 reg; - sky2_pci_write32(hw, PCI_DEV_REG3, 0); + pci_write_config_dword(pdev, PCI_DEV_REG3, 0); - reg = sky2_pci_read32(hw, PCI_DEV_REG4); + pci_read_config_dword(pdev, PCI_DEV_REG4, ®); /* set all bits to 0 except bits 15..12 and 8 */ reg &= P_ASPM_CONTROL_MSK; - sky2_pci_write32(hw, PCI_DEV_REG4, reg); + pci_write_config_dword(pdev, PCI_DEV_REG4, reg); - reg = sky2_pci_read32(hw, PCI_DEV_REG5); + pci_read_config_dword(pdev, PCI_DEV_REG5, ®); /* set all bits to 0 except bits 28 & 27 */ reg &= P_CTL_TIM_VMAIN_AV_MSK; - sky2_pci_write32(hw, PCI_DEV_REG5, reg); + pci_write_config_dword(pdev, PCI_DEV_REG5, reg); - sky2_pci_write32(hw, PCI_CFG_REG_1, 0); + pci_write_config_dword(pdev, PCI_CFG_REG_1, 0); /* Enable workaround for dev 4.107 on Yukon-Ultra & Extreme */ reg = sky2_read32(hw, B2_GP_IO); @@ -603,6 +604,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) static void sky2_phy_power(struct sky2_hw *hw, unsigned port, int onoff) { + struct pci_dev *pdev = hw->pdev; u32 reg1; static const u32 phy_power[] = { PCI_Y2_PHY1_POWD, PCI_Y2_PHY2_POWD }; @@ -611,15 +613,16 @@ static void sky2_phy_power(struct sky2_hw *hw, unsigned port, int onoff) if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1) onoff = !onoff; - reg1 = sky2_pci_read32(hw, PCI_DEV_REG1); + pci_read_config_dword(pdev, PCI_DEV_REG1, ®1); if (onoff) /* Turn off phy power saving */ reg1 &= ~phy_power[port]; else reg1 |= phy_power[port]; - sky2_pci_write32(hw, PCI_DEV_REG1, reg1); - sky2_pci_read32(hw, PCI_DEV_REG1); + pci_write_config_dword(pdev, PCI_DEV_REG1, reg1); + pci_read_config_dword(pdev, PCI_DEV_REG1, ®1); + udelay(100); } @@ -687,9 +690,9 @@ static void sky2_wol_init(struct sky2_port *sky2) sky2_write16(hw, WOL_REGS(port, WOL_CTRL_STAT), ctrl); /* Turn on legacy PCI-Express PME mode */ - reg1 = sky2_pci_read32(hw, PCI_DEV_REG1); + pci_read_config_dword(hw->pdev, PCI_DEV_REG1, ®1); reg1 |= PCI_Y2_PME_LEGACY; - sky2_pci_write32(hw, PCI_DEV_REG1, reg1); + pci_write_config_dword(hw->pdev, PCI_DEV_REG1, reg1); /* block receiver */ sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET); @@ -1306,9 +1309,9 @@ static int sky2_up(struct net_device *dev) struct sky2_port *osky2 = netdev_priv(otherdev); u16 cmd; - cmd = sky2_pci_read16(hw, cap + PCI_X_CMD); + pci_read_config_word(hw->pdev, cap + PCI_X_CMD, &cmd); cmd &= ~PCI_X_CMD_MAX_SPLIT; - sky2_pci_write16(hw, cap + PCI_X_CMD, cmd); + pci_write_config_word(hw->pdev, cap + PCI_X_CMD, cmd); sky2->rx_csum = 0; osky2->rx_csum = 0; @@ -2434,13 +2437,13 @@ static void sky2_hw_intr(struct sky2_hw *hw) if (status & (Y2_IS_MST_ERR | Y2_IS_IRQ_STAT)) { u16 pci_err; - pci_err = sky2_pci_read16(hw, PCI_STATUS); + pci_read_config_word(pdev, PCI_STATUS, &pci_err); if (net_ratelimit()) dev_err(&pdev->dev, "PCI hardware error (0x%x)\n", pci_err); - sky2_pci_write16(hw, PCI_STATUS, - pci_err | PCI_STATUS_ERROR_BITS); + pci_write_config_word(pdev, PCI_STATUS, + pci_err | PCI_STATUS_ERROR_BITS); } if (status & Y2_IS_PCI_EXP) { @@ -2694,10 +2697,13 @@ static inline u32 sky2_clk2us(const struct sky2_hw *hw, u32 clk) static int __devinit sky2_init(struct sky2_hw *hw) { + int rc; u8 t8; - /* Enable all clocks */ - sky2_pci_write32(hw, PCI_DEV_REG3, 0); + /* Enable all clocks and check for bad PCI access */ + rc = pci_write_config_dword(hw->pdev, PCI_DEV_REG3, 0); + if (rc) + return rc; sky2_write8(hw, B0_CTST, CS_RST_CLR); @@ -2791,10 +2797,9 @@ static void sky2_reset(struct sky2_hw *hw) sky2_write8(hw, B0_CTST, CS_RST_CLR); /* clear PCI errors, if any */ - status = sky2_pci_read16(hw, PCI_STATUS); - - sky2_pci_write16(hw, PCI_STATUS, status | PCI_STATUS_ERROR_BITS); - + pci_read_config_word(pdev, PCI_STATUS, &status); + status |= PCI_STATUS_ERROR_BITS; + pci_write_config_word(pdev, PCI_STATUS, status); sky2_write8(hw, B0_CTST, CS_MRST_CLR); @@ -3606,26 +3611,31 @@ static int sky2_get_eeprom_len(struct net_device *dev) struct sky2_port *sky2 = netdev_priv(dev); u16 reg2; - reg2 = sky2_pci_read32(sky2->hw, PCI_DEV_REG2); + pci_read_config_word(sky2->hw->pdev, PCI_DEV_REG2, ®2); return 1 << ( ((reg2 & PCI_VPD_ROM_SZ) >> 14) + 8); } -static u32 sky2_vpd_read(struct sky2_hw *hw, int cap, u16 offset) +static u32 sky2_vpd_read(struct pci_dev *pdev, int cap, u16 offset) { - sky2_pci_write16(hw, cap + PCI_VPD_ADDR, offset); + u32 val; - while (!(sky2_pci_read16(hw, cap + PCI_VPD_ADDR) & PCI_VPD_ADDR_F)) - cpu_relax(); - return sky2_pci_read32(hw, cap + PCI_VPD_DATA); + pci_write_config_word(pdev, cap + PCI_VPD_ADDR, offset); + + do { + pci_read_config_word(pdev, cap + PCI_VPD_ADDR, &offset); + } while (!(offset & PCI_VPD_ADDR_F)); + + pci_read_config_dword(pdev, cap + PCI_VPD_DATA, &val); + return val; } -static void sky2_vpd_write(struct sky2_hw *hw, int cap, u16 offset, u32 val) +static void sky2_vpd_write(struct pci_dev *pdev, int cap, u16 offset, u32 val) { - sky2_pci_write32(hw, cap + PCI_VPD_DATA, val); - sky2_pci_write16(hw, cap + PCI_VPD_ADDR, offset | PCI_VPD_ADDR_F); + pci_write_config_word(pdev, cap + PCI_VPD_DATA, val); + pci_write_config_dword(pdev, cap + PCI_VPD_ADDR, offset | PCI_VPD_ADDR_F); do { - cpu_relax(); - } while (sky2_pci_read16(hw, cap + PCI_VPD_ADDR) & PCI_VPD_ADDR_F); + pci_read_config_word(pdev, cap + PCI_VPD_ADDR, &offset); + } while (offset & PCI_VPD_ADDR_F); } static int sky2_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, @@ -3642,7 +3652,7 @@ static int sky2_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom eeprom->magic = SKY2_EEPROM_MAGIC; while (length > 0) { - u32 val = sky2_vpd_read(sky2->hw, cap, offset); + u32 val = sky2_vpd_read(sky2->hw->pdev, cap, offset); int n = min_t(int, length, sizeof(val)); memcpy(data, &val, n); @@ -3672,10 +3682,10 @@ static int sky2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom int n = min_t(int, length, sizeof(val)); if (n < sizeof(val)) - val = sky2_vpd_read(sky2->hw, cap, offset); + val = sky2_vpd_read(sky2->hw->pdev, cap, offset); memcpy(&val, data, n); - sky2_vpd_write(sky2->hw, cap, offset, val); + sky2_vpd_write(sky2->hw->pdev, cap, offset, val); length -= n; data += n; @@ -4116,15 +4126,14 @@ static int __devinit sky2_probe(struct pci_dev *pdev, */ { u32 reg; - reg = sky2_pci_read32(hw, PCI_DEV_REG2); + pci_read_config_dword(pdev,PCI_DEV_REG2, ®); reg &= ~PCI_REV_DESC; - sky2_pci_write32(hw, PCI_DEV_REG2, reg); + pci_write_config_dword(pdev, PCI_DEV_REG2, reg); } #endif /* ring for status responses */ - hw->st_le = pci_alloc_consistent(hw->pdev, STATUS_LE_BYTES, - &hw->st_dma); + hw->st_le = pci_alloc_consistent(pdev, STATUS_LE_BYTES, &hw->st_dma); if (!hw->st_le) goto err_out_iounmap; @@ -4201,7 +4210,7 @@ err_out_free_netdev: free_netdev(dev); err_out_free_pci: sky2_write8(hw, B0_CTST, CS_RST_SET); - pci_free_consistent(hw->pdev, STATUS_LE_BYTES, hw->st_le, hw->st_dma); + pci_free_consistent(pdev, STATUS_LE_BYTES, hw->st_le, hw->st_dma); err_out_iounmap: iounmap(hw->regs); err_out_free_hw: @@ -4312,7 +4321,7 @@ static int sky2_resume(struct pci_dev *pdev) if (hw->chip_id == CHIP_ID_YUKON_EX || hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_FE_P) - sky2_pci_write32(hw, PCI_DEV_REG3, 0); + pci_write_config_dword(pdev, PCI_DEV_REG3, 0); sky2_reset(hw); diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index 6f5e162709b..f4a3c2f403e 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -2129,25 +2129,4 @@ static inline void gma_set_addr(struct sky2_hw *hw, unsigned port, unsigned reg, gma_write16(hw, port, reg+4,(u16) addr[2] | ((u16) addr[3] << 8)); gma_write16(hw, port, reg+8,(u16) addr[4] | ((u16) addr[5] << 8)); } - -/* PCI config space access */ -static inline u32 sky2_pci_read32(const struct sky2_hw *hw, unsigned reg) -{ - return sky2_read32(hw, Y2_CFG_SPC + reg); -} - -static inline u16 sky2_pci_read16(const struct sky2_hw *hw, unsigned reg) -{ - return sky2_read16(hw, Y2_CFG_SPC + reg); -} - -static inline void sky2_pci_write32(struct sky2_hw *hw, unsigned reg, u32 val) -{ - sky2_write32(hw, Y2_CFG_SPC + reg, val); -} - -static inline void sky2_pci_write16(struct sky2_hw *hw, unsigned reg, u16 val) -{ - sky2_write16(hw, Y2_CFG_SPC + reg, val); -} #endif -- cgit v1.2.3-70-g09d2 From ced13330bb687780ce1d46f5404521cc0ea40481 Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Sat, 25 Aug 2007 20:32:59 +0200 Subject: bmac: add simple ethtool support for network manager NetworkManager will not start dhcpd on an interface unless it reports link-up state via ethtool. Signed-off-by: Olaf Hering Signed-off-by: Jeff Garzik --- drivers/net/bmac.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c index 9b8d7d9dbe8..1eb95b60300 100644 --- a/drivers/net/bmac.c +++ b/drivers/net/bmac.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -1246,6 +1247,17 @@ static void bmac_reset_and_enable(struct net_device *dev) } spin_unlock_irqrestore(&bp->lock, flags); } +static void bmac_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) +{ + struct bmac_data *bp = netdev_priv(dev); + strcpy(info->driver, "bmac"); + strcpy(info->bus_info, bp->mdev->ofdev.dev.bus_id); +} + +static const struct ethtool_ops bmac_ethtool_ops = { + .get_drvinfo = bmac_get_drvinfo, + .get_link = ethtool_op_get_link, +}; static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_device_id *match) { @@ -1311,6 +1323,7 @@ static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_device_i dev->open = bmac_open; dev->stop = bmac_close; + dev->ethtool_ops = &bmac_ethtool_ops; dev->hard_start_xmit = bmac_output; dev->get_stats = bmac_stats; dev->set_multicast_list = bmac_set_multicast; -- cgit v1.2.3-70-g09d2 From a85b94222d8b95e184941183f28b06b637cc4dee Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Sat, 15 Sep 2007 13:40:59 -0700 Subject: pasemi_mac: Abstract out register access Abstract out the PCI config read/write accesses into reg read/write ones, still calling the pci accessors on the back end. Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik Signed-off-by: David S. Miller --- drivers/net/pasemi_mac.c | 195 ++++++++++++++++++++++++----------------------- 1 file changed, 101 insertions(+), 94 deletions(-) (limited to 'drivers') diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index e63cc335a4b..c3a0fc64de0 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -81,6 +81,48 @@ MODULE_PARM_DESC(debug, "PA Semi MAC bitmapped debugging message enable value"); static struct pasdma_status *dma_status; +static unsigned int read_iob_reg(struct pasemi_mac *mac, unsigned int reg) +{ + unsigned int val; + + pci_read_config_dword(mac->iob_pdev, reg, &val); + return val; +} + +static void write_iob_reg(struct pasemi_mac *mac, unsigned int reg, + unsigned int val) +{ + pci_write_config_dword(mac->iob_pdev, reg, val); +} + +static unsigned int read_mac_reg(struct pasemi_mac *mac, unsigned int reg) +{ + unsigned int val; + + pci_read_config_dword(mac->pdev, reg, &val); + return val; +} + +static void write_mac_reg(struct pasemi_mac *mac, unsigned int reg, + unsigned int val) +{ + pci_write_config_dword(mac->pdev, reg, val); +} + +static unsigned int read_dma_reg(struct pasemi_mac *mac, unsigned int reg) +{ + unsigned int val; + + pci_read_config_dword(mac->dma_pdev, reg, &val); + return val; +} + +static void write_dma_reg(struct pasemi_mac *mac, unsigned int reg, + unsigned int val) +{ + pci_write_config_dword(mac->dma_pdev, reg, val); +} + static int pasemi_get_mac_addr(struct pasemi_mac *mac) { struct pci_dev *pdev = mac->pdev; @@ -166,22 +208,21 @@ static int pasemi_mac_setup_rx_resources(struct net_device *dev) memset(ring->buffers, 0, RX_RING_SIZE * sizeof(u64)); - pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXCHAN_BASEL(chan_id), - PAS_DMA_RXCHAN_BASEL_BRBL(ring->dma)); + write_dma_reg(mac, PAS_DMA_RXCHAN_BASEL(chan_id), PAS_DMA_RXCHAN_BASEL_BRBL(ring->dma)); - pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXCHAN_BASEU(chan_id), - PAS_DMA_RXCHAN_BASEU_BRBH(ring->dma >> 32) | - PAS_DMA_RXCHAN_BASEU_SIZ(RX_RING_SIZE >> 2)); + write_dma_reg(mac, PAS_DMA_RXCHAN_BASEU(chan_id), + PAS_DMA_RXCHAN_BASEU_BRBH(ring->dma >> 32) | + PAS_DMA_RXCHAN_BASEU_SIZ(RX_RING_SIZE >> 2)); - pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXCHAN_CFG(chan_id), - PAS_DMA_RXCHAN_CFG_HBU(1)); + write_dma_reg(mac, PAS_DMA_RXCHAN_CFG(chan_id), + PAS_DMA_RXCHAN_CFG_HBU(1)); - pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXINT_BASEL(mac->dma_if), - PAS_DMA_RXINT_BASEL_BRBL(__pa(ring->buffers))); + write_dma_reg(mac, PAS_DMA_RXINT_BASEL(mac->dma_if), + PAS_DMA_RXINT_BASEL_BRBL(__pa(ring->buffers))); - pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXINT_BASEU(mac->dma_if), - PAS_DMA_RXINT_BASEU_BRBH(__pa(ring->buffers) >> 32) | - PAS_DMA_RXINT_BASEU_SIZ(RX_RING_SIZE >> 3)); + write_dma_reg(mac, PAS_DMA_RXINT_BASEU(mac->dma_if), + PAS_DMA_RXINT_BASEU_BRBH(__pa(ring->buffers) >> 32) | + PAS_DMA_RXINT_BASEU_SIZ(RX_RING_SIZE >> 3)); ring->next_to_fill = 0; ring->next_to_clean = 0; @@ -233,18 +274,18 @@ static int pasemi_mac_setup_tx_resources(struct net_device *dev) memset(ring->desc, 0, TX_RING_SIZE * sizeof(struct pas_dma_xct_descr)); - pci_write_config_dword(mac->dma_pdev, PAS_DMA_TXCHAN_BASEL(chan_id), - PAS_DMA_TXCHAN_BASEL_BRBL(ring->dma)); + write_dma_reg(mac, PAS_DMA_TXCHAN_BASEL(chan_id), + PAS_DMA_TXCHAN_BASEL_BRBL(ring->dma)); val = PAS_DMA_TXCHAN_BASEU_BRBH(ring->dma >> 32); val |= PAS_DMA_TXCHAN_BASEU_SIZ(TX_RING_SIZE >> 2); - pci_write_config_dword(mac->dma_pdev, PAS_DMA_TXCHAN_BASEU(chan_id), val); + write_dma_reg(mac, PAS_DMA_TXCHAN_BASEU(chan_id), val); - pci_write_config_dword(mac->dma_pdev, PAS_DMA_TXCHAN_CFG(chan_id), - PAS_DMA_TXCHAN_CFG_TY_IFACE | - PAS_DMA_TXCHAN_CFG_TATTR(mac->dma_if) | - PAS_DMA_TXCHAN_CFG_UP | - PAS_DMA_TXCHAN_CFG_WT(2)); + write_dma_reg(mac, PAS_DMA_TXCHAN_CFG(chan_id), + PAS_DMA_TXCHAN_CFG_TY_IFACE | + PAS_DMA_TXCHAN_CFG_TATTR(mac->dma_if) | + PAS_DMA_TXCHAN_CFG_UP | + PAS_DMA_TXCHAN_CFG_WT(2)); ring->next_to_use = 0; ring->next_to_clean = 0; @@ -383,12 +424,8 @@ static void pasemi_mac_replenish_rx_ring(struct net_device *dev) wmb(); - pci_write_config_dword(mac->dma_pdev, - PAS_DMA_RXCHAN_INCR(mac->dma_rxch), - limit - count); - pci_write_config_dword(mac->dma_pdev, - PAS_DMA_RXINT_INCR(mac->dma_if), - limit - count); + write_dma_reg(mac, PAS_DMA_RXCHAN_INCR(mac->dma_rxch), limit - count); + write_dma_reg(mac, PAS_DMA_RXINT_INCR(mac->dma_if), limit - count); mac->rx->next_to_fill += limit - count; } @@ -404,9 +441,7 @@ static void pasemi_mac_restart_rx_intr(struct pasemi_mac *mac) reg = PAS_IOB_DMA_RXCH_RESET_PCNT(pcnt) | PAS_IOB_DMA_RXCH_RESET_PINTC; - pci_write_config_dword(mac->iob_pdev, - PAS_IOB_DMA_RXCH_RESET(mac->dma_rxch), - reg); + write_iob_reg(mac, PAS_IOB_DMA_RXCH_RESET(mac->dma_rxch), reg); } static void pasemi_mac_restart_tx_intr(struct pasemi_mac *mac) @@ -418,8 +453,7 @@ static void pasemi_mac_restart_tx_intr(struct pasemi_mac *mac) reg = PAS_IOB_DMA_TXCH_RESET_PCNT(pcnt) | PAS_IOB_DMA_TXCH_RESET_PINTC; - pci_write_config_dword(mac->iob_pdev, - PAS_IOB_DMA_TXCH_RESET(mac->dma_txch), reg); + write_iob_reg(mac, PAS_IOB_DMA_TXCH_RESET(mac->dma_txch), reg); } @@ -574,8 +608,6 @@ static irqreturn_t pasemi_mac_rx_intr(int irq, void *data) * all others. */ - pci_read_config_dword(mac->dma_pdev, PAS_DMA_RXINT_RCMDSTA(mac->dma_if), ®); - reg = 0; if (*mac->rx_status & PAS_STATUS_SOFT) reg |= PAS_IOB_DMA_RXCH_RESET_SINTC; @@ -586,9 +618,7 @@ static irqreturn_t pasemi_mac_rx_intr(int irq, void *data) netif_rx_schedule(dev, &mac->napi); - pci_write_config_dword(mac->iob_pdev, - PAS_IOB_DMA_RXCH_RESET(mac->dma_rxch), reg); - + write_iob_reg(mac, PAS_IOB_DMA_RXCH_RESET(mac->dma_rxch), reg); return IRQ_HANDLED; } @@ -613,9 +643,7 @@ static irqreturn_t pasemi_mac_tx_intr(int irq, void *data) if (*mac->tx_status & PAS_STATUS_ERROR) reg |= PAS_IOB_DMA_TXCH_RESET_DINTC; - pci_write_config_dword(mac->iob_pdev, - PAS_IOB_DMA_TXCH_RESET(mac->dma_txch), - reg); + write_iob_reg(mac, PAS_IOB_DMA_TXCH_RESET(mac->dma_txch), reg); return IRQ_HANDLED; } @@ -641,7 +669,7 @@ static void pasemi_adjust_link(struct net_device *dev) } else netif_carrier_on(dev); - pci_read_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, &flags); + flags = read_mac_reg(mac, PAS_MAC_CFG_PCFG); new_flags = flags & ~(PAS_MAC_CFG_PCFG_HD | PAS_MAC_CFG_PCFG_SPD_M | PAS_MAC_CFG_PCFG_TSR_M); @@ -673,7 +701,7 @@ static void pasemi_adjust_link(struct net_device *dev) mac->link = mac->phydev->link; if (new_flags != flags) - pci_write_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, new_flags); + write_mac_reg(mac, PAS_MAC_CFG_PCFG, new_flags); if (msg && netif_msg_link(mac)) printk(KERN_INFO "%s: Link is up at %d Mbps, %s duplex.\n", @@ -736,39 +764,37 @@ static int pasemi_mac_open(struct net_device *dev) int ret; /* enable rx section */ - pci_write_config_dword(mac->dma_pdev, PAS_DMA_COM_RXCMD, - PAS_DMA_COM_RXCMD_EN); + write_dma_reg(mac, PAS_DMA_COM_RXCMD, PAS_DMA_COM_RXCMD_EN); /* enable tx section */ - pci_write_config_dword(mac->dma_pdev, PAS_DMA_COM_TXCMD, - PAS_DMA_COM_TXCMD_EN); + write_dma_reg(mac, PAS_DMA_COM_TXCMD, PAS_DMA_COM_TXCMD_EN); flags = PAS_MAC_CFG_TXP_FCE | PAS_MAC_CFG_TXP_FPC(3) | PAS_MAC_CFG_TXP_SL(3) | PAS_MAC_CFG_TXP_COB(0xf) | PAS_MAC_CFG_TXP_TIFT(8) | PAS_MAC_CFG_TXP_TIFG(12); - pci_write_config_dword(mac->pdev, PAS_MAC_CFG_TXP, flags); + write_mac_reg(mac, PAS_MAC_CFG_TXP, flags); flags = PAS_MAC_CFG_PCFG_S1 | PAS_MAC_CFG_PCFG_PE | PAS_MAC_CFG_PCFG_PR | PAS_MAC_CFG_PCFG_CE; flags |= PAS_MAC_CFG_PCFG_TSR_1G | PAS_MAC_CFG_PCFG_SPD_1G; - pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_RXCH_CFG(mac->dma_rxch), - PAS_IOB_DMA_RXCH_CFG_CNTTH(0)); + write_iob_reg(mac, PAS_IOB_DMA_RXCH_CFG(mac->dma_rxch), + PAS_IOB_DMA_RXCH_CFG_CNTTH(0)); - pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_TXCH_CFG(mac->dma_txch), - PAS_IOB_DMA_TXCH_CFG_CNTTH(32)); + write_iob_reg(mac, PAS_IOB_DMA_TXCH_CFG(mac->dma_txch), + PAS_IOB_DMA_TXCH_CFG_CNTTH(32)); /* Clear out any residual packet count state from firmware */ pasemi_mac_restart_rx_intr(mac); pasemi_mac_restart_tx_intr(mac); /* 0xffffff is max value, about 16ms */ - pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_COM_TIMEOUTCFG, - PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(0xffffff)); + write_iob_reg(mac, PAS_IOB_DMA_COM_TIMEOUTCFG, + PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(0xffffff)); - pci_write_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, flags); + write_mac_reg(mac, PAS_MAC_CFG_PCFG, flags); ret = pasemi_mac_setup_rx_resources(dev); if (ret) @@ -778,25 +804,22 @@ static int pasemi_mac_open(struct net_device *dev) if (ret) goto out_tx_resources; - pci_write_config_dword(mac->pdev, PAS_MAC_IPC_CHNL, - PAS_MAC_IPC_CHNL_DCHNO(mac->dma_rxch) | - PAS_MAC_IPC_CHNL_BCH(mac->dma_rxch)); + write_mac_reg(mac, PAS_MAC_IPC_CHNL, + PAS_MAC_IPC_CHNL_DCHNO(mac->dma_rxch) | + PAS_MAC_IPC_CHNL_BCH(mac->dma_rxch)); /* enable rx if */ - pci_write_config_dword(mac->dma_pdev, - PAS_DMA_RXINT_RCMDSTA(mac->dma_if), - PAS_DMA_RXINT_RCMDSTA_EN); + write_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if), + PAS_DMA_RXINT_RCMDSTA_EN); /* enable rx channel */ - pci_write_config_dword(mac->dma_pdev, - PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch), - PAS_DMA_RXCHAN_CCMDSTA_EN | - PAS_DMA_RXCHAN_CCMDSTA_DU); + write_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch), + PAS_DMA_RXCHAN_CCMDSTA_EN | + PAS_DMA_RXCHAN_CCMDSTA_DU); /* enable tx channel */ - pci_write_config_dword(mac->dma_pdev, - PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch), - PAS_DMA_TXCHAN_TCMDSTA_EN); + write_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch), + PAS_DMA_TXCHAN_TCMDSTA_EN); pasemi_mac_replenish_rx_ring(dev); @@ -876,20 +899,12 @@ static int pasemi_mac_close(struct net_device *dev) pasemi_mac_clean_rx(mac, RX_RING_SIZE); /* Disable interface */ - pci_write_config_dword(mac->dma_pdev, - PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch), - PAS_DMA_TXCHAN_TCMDSTA_ST); - pci_write_config_dword(mac->dma_pdev, - PAS_DMA_RXINT_RCMDSTA(mac->dma_if), - PAS_DMA_RXINT_RCMDSTA_ST); - pci_write_config_dword(mac->dma_pdev, - PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch), - PAS_DMA_RXCHAN_CCMDSTA_ST); + write_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch), PAS_DMA_TXCHAN_TCMDSTA_ST); + write_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if), PAS_DMA_RXINT_RCMDSTA_ST); + write_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch), PAS_DMA_RXCHAN_CCMDSTA_ST); for (retries = 0; retries < MAX_RETRIES; retries++) { - pci_read_config_dword(mac->dma_pdev, - PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch), - &stat); + stat = read_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch)); if (!(stat & PAS_DMA_TXCHAN_TCMDSTA_ACT)) break; cond_resched(); @@ -899,9 +914,7 @@ static int pasemi_mac_close(struct net_device *dev) dev_err(&mac->dma_pdev->dev, "Failed to stop tx channel\n"); for (retries = 0; retries < MAX_RETRIES; retries++) { - pci_read_config_dword(mac->dma_pdev, - PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch), - &stat); + stat = read_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch)); if (!(stat & PAS_DMA_RXCHAN_CCMDSTA_ACT)) break; cond_resched(); @@ -911,9 +924,7 @@ static int pasemi_mac_close(struct net_device *dev) dev_err(&mac->dma_pdev->dev, "Failed to stop rx channel\n"); for (retries = 0; retries < MAX_RETRIES; retries++) { - pci_read_config_dword(mac->dma_pdev, - PAS_DMA_RXINT_RCMDSTA(mac->dma_if), - &stat); + stat = read_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if)); if (!(stat & PAS_DMA_RXINT_RCMDSTA_ACT)) break; cond_resched(); @@ -926,12 +937,9 @@ static int pasemi_mac_close(struct net_device *dev) * stopping, since you can't disable when active. */ - pci_write_config_dword(mac->dma_pdev, - PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch), 0); - pci_write_config_dword(mac->dma_pdev, - PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch), 0); - pci_write_config_dword(mac->dma_pdev, - PAS_DMA_RXINT_RCMDSTA(mac->dma_if), 0); + write_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch), 0); + write_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch), 0); + write_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if), 0); free_irq(mac->tx_irq, dev); free_irq(mac->rx_irq, dev); @@ -1012,8 +1020,7 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&txring->lock, flags); - pci_write_config_dword(mac->dma_pdev, - PAS_DMA_TXCHAN_INCR(mac->dma_txch), 1); + write_dma_reg(mac, PAS_DMA_TXCHAN_INCR(mac->dma_txch), 1); return NETDEV_TX_OK; @@ -1036,7 +1043,7 @@ static void pasemi_mac_set_rx_mode(struct net_device *dev) struct pasemi_mac *mac = netdev_priv(dev); unsigned int flags; - pci_read_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, &flags); + flags = read_mac_reg(mac, PAS_MAC_CFG_PCFG); /* Set promiscuous */ if (dev->flags & IFF_PROMISC) @@ -1044,7 +1051,7 @@ static void pasemi_mac_set_rx_mode(struct net_device *dev) else flags &= ~PAS_MAC_CFG_PCFG_PR; - pci_write_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, flags); + write_mac_reg(mac, PAS_MAC_CFG_PCFG, flags); } -- cgit v1.2.3-70-g09d2 From b6e05a1b67a4b2e122d78a3f0b7ec7c779bd903c Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Sat, 15 Sep 2007 13:44:07 -0700 Subject: pasemi_mac: Stop using the pci config space accessors for register read/writes Move away from using the pci config access functions for simple register access. Our device has all of the registers in the config space (hey, from the hardware point of view it looks reasonable :-), so we need to somehow get to it. Newer firmwares have it in the device tree such that we can just get it and ioremap it there (in case it ever moves in future products). For now, provide a hardcoded fallback for older firmwares. [ Resolved napi_struct conflicts... -DaveM ] Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik Signed-off-by: David S. Miller --- drivers/net/pasemi_mac.c | 132 ++++++++++++++++++++++++++++++++--------------- drivers/net/pasemi_mac.h | 3 ++ 2 files changed, 94 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index c3a0fc64de0..be311e9404b 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -83,44 +83,35 @@ static struct pasdma_status *dma_status; static unsigned int read_iob_reg(struct pasemi_mac *mac, unsigned int reg) { - unsigned int val; - - pci_read_config_dword(mac->iob_pdev, reg, &val); - return val; + return in_le32(mac->iob_regs+reg); } static void write_iob_reg(struct pasemi_mac *mac, unsigned int reg, unsigned int val) { - pci_write_config_dword(mac->iob_pdev, reg, val); + out_le32(mac->iob_regs+reg, val); } static unsigned int read_mac_reg(struct pasemi_mac *mac, unsigned int reg) { - unsigned int val; - - pci_read_config_dword(mac->pdev, reg, &val); - return val; + return in_le32(mac->regs+reg); } static void write_mac_reg(struct pasemi_mac *mac, unsigned int reg, unsigned int val) { - pci_write_config_dword(mac->pdev, reg, val); + out_le32(mac->regs+reg, val); } static unsigned int read_dma_reg(struct pasemi_mac *mac, unsigned int reg) { - unsigned int val; - - pci_read_config_dword(mac->dma_pdev, reg, &val); - return val; + return in_le32(mac->dma_regs+reg); } static void write_dma_reg(struct pasemi_mac *mac, unsigned int reg, unsigned int val) { - pci_write_config_dword(mac->dma_pdev, reg, val); + out_le32(mac->dma_regs+reg, val); } static int pasemi_get_mac_addr(struct pasemi_mac *mac) @@ -585,7 +576,6 @@ static int pasemi_mac_clean_tx(struct pasemi_mac *mac) } mac->tx->next_to_clean += count; spin_unlock_irqrestore(&mac->tx->lock, flags); - netif_wake_queue(mac->netdev); return count; @@ -1071,6 +1061,73 @@ static int pasemi_mac_poll(struct napi_struct *napi, int budget) return pkts; } +static void __iomem * __devinit map_onedev(struct pci_dev *p, int index) +{ + struct device_node *dn; + void __iomem *ret; + + dn = pci_device_to_OF_node(p); + if (!dn) + goto fallback; + + ret = of_iomap(dn, index); + if (!ret) + goto fallback; + + return ret; +fallback: + /* This is hardcoded and ugly, but we have some firmware versions + * that don't provide the register space in the device tree. Luckily + * they are at well-known locations so we can just do the math here. + */ + return ioremap(0xe0000000 + (p->devfn << 12), 0x2000); +} + +static int __devinit pasemi_mac_map_regs(struct pasemi_mac *mac) +{ + struct resource res; + struct device_node *dn; + int err; + + mac->dma_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa007, NULL); + if (!mac->dma_pdev) { + dev_err(&mac->pdev->dev, "Can't find DMA Controller\n"); + return -ENODEV; + } + + mac->iob_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa001, NULL); + if (!mac->iob_pdev) { + dev_err(&mac->pdev->dev, "Can't find I/O Bridge\n"); + return -ENODEV; + } + + mac->regs = map_onedev(mac->pdev, 0); + mac->dma_regs = map_onedev(mac->dma_pdev, 0); + mac->iob_regs = map_onedev(mac->iob_pdev, 0); + + if (!mac->regs || !mac->dma_regs || !mac->iob_regs) { + dev_err(&mac->pdev->dev, "Can't map registers\n"); + return -ENODEV; + } + + /* The dma status structure is located in the I/O bridge, and + * is cache coherent. + */ + if (!dma_status) { + dn = pci_device_to_OF_node(mac->iob_pdev); + if (dn) + err = of_address_to_resource(dn, 1, &res); + if (!dn || err) { + /* Fallback for old firmware */ + res.start = 0xfd800000; + res.end = res.start + 0x1000; + } + dma_status = __ioremap(res.start, res.end-res.start, 0); + } + + return 0; +} + static int __devinit pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -1099,26 +1156,11 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) mac->pdev = pdev; mac->netdev = dev; - mac->dma_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa007, NULL); netif_napi_add(dev, &mac->napi, pasemi_mac_poll, 64); dev->features = NETIF_F_HW_CSUM; - if (!mac->dma_pdev) { - dev_err(&pdev->dev, "Can't find DMA Controller\n"); - err = -ENODEV; - goto out_free_netdev; - } - - mac->iob_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa001, NULL); - - if (!mac->iob_pdev) { - dev_err(&pdev->dev, "Can't find I/O Bridge\n"); - err = -ENODEV; - goto out_put_dma_pdev; - } - /* These should come out of the device tree eventually */ mac->dma_txch = index; mac->dma_rxch = index; @@ -1157,12 +1199,9 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) dev->get_stats = pasemi_mac_get_stats; dev->set_multicast_list = pasemi_mac_set_rx_mode; - /* The dma status structure is located in the I/O bridge, and - * is cache coherent. - */ - if (!dma_status) - /* XXXOJN This should come from the device tree */ - dma_status = __ioremap(0xfd800000, 0x1000, 0); + err = pasemi_mac_map_regs(mac); + if (err) + goto out; mac->rx_status = &dma_status->rx_sta[mac->dma_rxch]; mac->tx_status = &dma_status->tx_sta[mac->dma_txch]; @@ -1189,10 +1228,17 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) return err; out: - pci_dev_put(mac->iob_pdev); -out_put_dma_pdev: - pci_dev_put(mac->dma_pdev); -out_free_netdev: + if (mac->iob_pdev) + pci_dev_put(mac->iob_pdev); + if (mac->dma_pdev) + pci_dev_put(mac->dma_pdev); + if (mac->dma_regs) + iounmap(mac->dma_regs); + if (mac->iob_regs) + iounmap(mac->iob_regs); + if (mac->regs) + iounmap(mac->regs); + free_netdev(dev); out_disable_device: pci_disable_device(pdev); @@ -1216,6 +1262,10 @@ static void __devexit pasemi_mac_remove(struct pci_dev *pdev) pci_dev_put(mac->dma_pdev); pci_dev_put(mac->iob_pdev); + iounmap(mac->regs); + iounmap(mac->dma_regs); + iounmap(mac->iob_regs); + pci_set_drvdata(pdev, NULL); free_netdev(netdev); } diff --git a/drivers/net/pasemi_mac.h b/drivers/net/pasemi_mac.h index 85d3b7856e5..ef443640c76 100644 --- a/drivers/net/pasemi_mac.h +++ b/drivers/net/pasemi_mac.h @@ -52,6 +52,9 @@ struct pasemi_mac_rxring { struct pasemi_mac { struct net_device *netdev; + void __iomem *regs; + void __iomem *dma_regs; + void __iomem *iob_regs; struct pci_dev *pdev; struct pci_dev *dma_pdev; struct pci_dev *iob_pdev; -- cgit v1.2.3-70-g09d2 From c0efd52b8b1951c20878208fdcbab0468f816804 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 22 Aug 2007 09:12:52 -0500 Subject: pasemi_mac: Enable L2 caching of packet headers Enable settings to target l2 for the first few cachelines of the packet, since we'll access them to get to the various headers. Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik --- drivers/net/pasemi_mac.c | 5 ++++- drivers/net/pasemi_mac.h | 8 ++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index be311e9404b..46d5c0eef78 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -206,7 +206,7 @@ static int pasemi_mac_setup_rx_resources(struct net_device *dev) PAS_DMA_RXCHAN_BASEU_SIZ(RX_RING_SIZE >> 2)); write_dma_reg(mac, PAS_DMA_RXCHAN_CFG(chan_id), - PAS_DMA_RXCHAN_CFG_HBU(1)); + PAS_DMA_RXCHAN_CFG_HBU(2)); write_dma_reg(mac, PAS_DMA_RXINT_BASEL(mac->dma_if), PAS_DMA_RXINT_BASEL_BRBL(__pa(ring->buffers))); @@ -215,6 +215,9 @@ static int pasemi_mac_setup_rx_resources(struct net_device *dev) PAS_DMA_RXINT_BASEU_BRBH(__pa(ring->buffers) >> 32) | PAS_DMA_RXINT_BASEU_SIZ(RX_RING_SIZE >> 3)); + write_dma_reg(mac, PAS_DMA_RXINT_CFG(mac->dma_if), + PAS_DMA_RXINT_CFG_DHL(2)); + ring->next_to_fill = 0; ring->next_to_clean = 0; diff --git a/drivers/net/pasemi_mac.h b/drivers/net/pasemi_mac.h index ef443640c76..fbbc17a31db 100644 --- a/drivers/net/pasemi_mac.h +++ b/drivers/net/pasemi_mac.h @@ -219,6 +219,14 @@ enum { #define PAS_DMA_RXINT_RCMDSTA_ACT 0x00010000 #define PAS_DMA_RXINT_RCMDSTA_DROPS_M 0xfffe0000 #define PAS_DMA_RXINT_RCMDSTA_DROPS_S 17 +#define PAS_DMA_RXINT_CFG(i) (0x204+(i)*_PAS_DMA_RXINT_STRIDE) +#define PAS_DMA_RXINT_CFG_DHL_M 0x07000000 +#define PAS_DMA_RXINT_CFG_DHL_S 24 +#define PAS_DMA_RXINT_CFG_DHL(x) (((x) << PAS_DMA_RXINT_CFG_DHL_S) & \ + PAS_DMA_RXINT_CFG_DHL_M) +#define PAS_DMA_RXINT_CFG_WIF 0x00000002 +#define PAS_DMA_RXINT_CFG_WIL 0x00000001 + #define PAS_DMA_RXINT_INCR(i) (0x210+(i)*_PAS_DMA_RXINT_STRIDE) #define PAS_DMA_RXINT_INCR_INCR_M 0x0000ffff #define PAS_DMA_RXINT_INCR_INCR_S 0 -- cgit v1.2.3-70-g09d2 From 73344863e426a3c56c7f3ac80fc6f1d4cb10460b Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 22 Aug 2007 09:12:55 -0500 Subject: pasemi_mac: Fix memcpy amount for short receives Fix up memcpy for short receives. Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik --- drivers/net/pasemi_mac.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 46d5c0eef78..0d80b9d48c2 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -506,9 +506,7 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) netdev_alloc_skb(mac->netdev, len + NET_IP_ALIGN); if (new_skb) { skb_reserve(new_skb, NET_IP_ALIGN); - memcpy(new_skb->data - NET_IP_ALIGN, - skb->data - NET_IP_ALIGN, - len + NET_IP_ALIGN); + memcpy(new_skb->data, skb->data, len); /* save the skb in buffer_info as good */ skb = new_skb; } -- cgit v1.2.3-70-g09d2 From 26fcfa95aef980cab4ff1ea55979c30e772dd0dd Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 22 Aug 2007 09:12:59 -0500 Subject: pasemi_mac: RX performance tweaks Various RX performance tweaks, do some explicit prefetching of packet data, etc. Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik --- drivers/net/pasemi_mac.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 0d80b9d48c2..f71a6864cdc 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -471,6 +471,7 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) rmb(); dp = &RX_DESC(mac, n); + prefetchw(dp); macrx = dp->macrx; if (!(macrx & XCT_MACRX_O)) @@ -492,8 +493,10 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) if (info->dma == dma) break; } + prefetchw(info); skb = info->skb; + prefetchw(skb); info->dma = 0; pci_unmap_single(mac->dma_pdev, dma, skb->len, @@ -516,9 +519,7 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) skb_put(skb, len); - skb->protocol = eth_type_trans(skb, mac->netdev); - - if ((macrx & XCT_MACRX_HTY_M) == XCT_MACRX_HTY_IPV4_OK) { + if (likely((macrx & XCT_MACRX_HTY_M) == XCT_MACRX_HTY_IPV4_OK)) { skb->ip_summed = CHECKSUM_COMPLETE; skb->csum = (macrx & XCT_MACRX_CSUM_M) >> XCT_MACRX_CSUM_S; @@ -528,6 +529,7 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) mac->stats.rx_bytes += len; mac->stats.rx_packets++; + skb->protocol = eth_type_trans(skb, mac->netdev); netif_receive_skb(skb); dp->ptr = 0; @@ -559,7 +561,7 @@ static int pasemi_mac_clean_tx(struct pasemi_mac *mac) for (i = start; i < mac->tx->next_to_use; i++) { dp = &TX_DESC(mac, i); - if (!dp || (dp->mactx & XCT_MACTX_O)) + if (unlikely(dp->mactx & XCT_MACTX_O)) break; count++; @@ -948,7 +950,7 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev) struct pasemi_mac_txring *txring; struct pasemi_mac_buffer *info; struct pas_dma_xct_descr *dp; - u64 dflags; + u64 dflags, mactx, ptr; dma_addr_t map; int flags; @@ -976,6 +978,9 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev) if (dma_mapping_error(map)) return NETDEV_TX_BUSY; + mactx = dflags | XCT_MACTX_LLEN(skb->len); + ptr = XCT_PTR_LEN(skb->len) | XCT_PTR_ADDR(map); + txring = mac->tx; spin_lock_irqsave(&txring->lock, flags); @@ -996,12 +1001,11 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev) } } - dp = &TX_DESC(mac, txring->next_to_use); info = &TX_DESC_INFO(mac, txring->next_to_use); - dp->mactx = dflags | XCT_MACTX_LLEN(skb->len); - dp->ptr = XCT_PTR_LEN(skb->len) | XCT_PTR_ADDR(map); + dp->mactx = mactx; + dp->ptr = ptr; info->dma = map; info->skb = skb; -- cgit v1.2.3-70-g09d2 From 02df6cfa09c2ccebe685bfd54a708e1f50b00a81 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 22 Aug 2007 09:13:03 -0500 Subject: pasemi_mac: Batch up TX buffer frees Postpone pci unmap and skb free of the transmitted buffers to outside of the tx ring lock, batching them up 32 at a time. Also increase the count threshold to 128. Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik --- drivers/net/pasemi_mac.c | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index f71a6864cdc..4836d405cd5 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -551,37 +551,56 @@ static int pasemi_mac_clean_tx(struct pasemi_mac *mac) int i; struct pasemi_mac_buffer *info; struct pas_dma_xct_descr *dp; - int start, count; + unsigned int start, count, limit; + unsigned int total_count; int flags; + struct sk_buff *skbs[32]; + dma_addr_t dmas[32]; + total_count = 0; +restart: spin_lock_irqsave(&mac->tx->lock, flags); start = mac->tx->next_to_clean; + limit = min(mac->tx->next_to_use, start+32); + count = 0; - for (i = start; i < mac->tx->next_to_use; i++) { + for (i = start; i < limit; i++) { dp = &TX_DESC(mac, i); + if (unlikely(dp->mactx & XCT_MACTX_O)) + /* Not yet transmitted */ break; - count++; - info = &TX_DESC_INFO(mac, i); - - pci_unmap_single(mac->dma_pdev, info->dma, - info->skb->len, PCI_DMA_TODEVICE); - dev_kfree_skb_irq(info->skb); + skbs[count] = info->skb; + dmas[count] = info->dma; info->skb = NULL; info->dma = 0; dp->mactx = 0; dp->ptr = 0; + + count++; } mac->tx->next_to_clean += count; spin_unlock_irqrestore(&mac->tx->lock, flags); netif_wake_queue(mac->netdev); - return count; + for (i = 0; i < count; i++) { + pci_unmap_single(mac->dma_pdev, dmas[i], + skbs[i]->len, PCI_DMA_TODEVICE); + dev_kfree_skb_irq(skbs[i]); + } + + total_count += count; + + /* If the batch was full, try to clean more */ + if (count == 32) + goto restart; + + return total_count; } @@ -777,7 +796,7 @@ static int pasemi_mac_open(struct net_device *dev) PAS_IOB_DMA_RXCH_CFG_CNTTH(0)); write_iob_reg(mac, PAS_IOB_DMA_TXCH_CFG(mac->dma_txch), - PAS_IOB_DMA_TXCH_CFG_CNTTH(32)); + PAS_IOB_DMA_TXCH_CFG_CNTTH(128)); /* Clear out any residual packet count state from firmware */ pasemi_mac_restart_rx_intr(mac); -- cgit v1.2.3-70-g09d2 From 021fa22e01d3d0425d3d15df48f523b69a3a11c4 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 22 Aug 2007 09:13:11 -0500 Subject: pasemi_mac: Fix TX ring wrap checking The old logic didn't detect full (tx) ring cases properly, causing overruns and general badness. Clean it up a bit and abstract out the ring size checks, always making sure to leave 1 slot open. Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik --- drivers/net/pasemi_mac.c | 25 ++++++++++++++----------- drivers/net/pasemi_mac.h | 2 +- 2 files changed, 15 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 4836d405cd5..dc710a0826b 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -69,6 +69,10 @@ #define RX_DESC_INFO(mac, num) ((mac)->rx->desc_info[(num) & (RX_RING_SIZE-1)]) #define RX_BUFF(mac, num) ((mac)->rx->buffers[(num) & (RX_RING_SIZE-1)]) +#define RING_USED(ring) (((ring)->next_to_fill - (ring)->next_to_clean) \ + & ((ring)->size - 1)) +#define RING_AVAIL(ring) ((ring->size) - RING_USED(ring)) + #define BUF_SIZE 1646 /* 1500 MTU + ETH_HLEN + VLAN_HLEN + 2 64B cachelines */ MODULE_LICENSE("GPL"); @@ -174,6 +178,7 @@ static int pasemi_mac_setup_rx_resources(struct net_device *dev) spin_lock_init(&ring->lock); + ring->size = RX_RING_SIZE; ring->desc_info = kzalloc(sizeof(struct pasemi_mac_buffer) * RX_RING_SIZE, GFP_KERNEL); @@ -253,6 +258,7 @@ static int pasemi_mac_setup_tx_resources(struct net_device *dev) spin_lock_init(&ring->lock); + ring->size = TX_RING_SIZE; ring->desc_info = kzalloc(sizeof(struct pasemi_mac_buffer) * TX_RING_SIZE, GFP_KERNEL); if (!ring->desc_info) @@ -281,7 +287,7 @@ static int pasemi_mac_setup_tx_resources(struct net_device *dev) PAS_DMA_TXCHAN_CFG_UP | PAS_DMA_TXCHAN_CFG_WT(2)); - ring->next_to_use = 0; + ring->next_to_fill = 0; ring->next_to_clean = 0; snprintf(ring->irq_name, sizeof(ring->irq_name), @@ -376,9 +382,7 @@ static void pasemi_mac_replenish_rx_ring(struct net_device *dev) int start = mac->rx->next_to_fill; unsigned int limit, count; - limit = (mac->rx->next_to_clean + RX_RING_SIZE - - mac->rx->next_to_fill) & (RX_RING_SIZE - 1); - + limit = RING_AVAIL(mac->rx); /* Check to see if we're doing first-time setup */ if (unlikely(mac->rx->next_to_clean == 0 && mac->rx->next_to_fill == 0)) limit = RX_RING_SIZE; @@ -562,7 +566,7 @@ restart: spin_lock_irqsave(&mac->tx->lock, flags); start = mac->tx->next_to_clean; - limit = min(mac->tx->next_to_use, start+32); + limit = min(mac->tx->next_to_fill, start+32); count = 0; @@ -1004,14 +1008,13 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev) spin_lock_irqsave(&txring->lock, flags); - if (txring->next_to_clean - txring->next_to_use == TX_RING_SIZE) { + if (RING_AVAIL(txring) <= 1) { spin_unlock_irqrestore(&txring->lock, flags); pasemi_mac_clean_tx(mac); pasemi_mac_restart_tx_intr(mac); spin_lock_irqsave(&txring->lock, flags); - if (txring->next_to_clean - txring->next_to_use == - TX_RING_SIZE) { + if (RING_AVAIL(txring) <= 1) { /* Still no room -- stop the queue and wait for tx * intr when there's room. */ @@ -1020,15 +1023,15 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev) } } - dp = &TX_DESC(mac, txring->next_to_use); - info = &TX_DESC_INFO(mac, txring->next_to_use); + dp = &TX_DESC(mac, txring->next_to_fill); + info = &TX_DESC_INFO(mac, txring->next_to_fill); dp->mactx = mactx; dp->ptr = ptr; info->dma = map; info->skb = skb; - txring->next_to_use++; + txring->next_to_fill++; mac->stats.tx_packets++; mac->stats.tx_bytes += skb->len; diff --git a/drivers/net/pasemi_mac.h b/drivers/net/pasemi_mac.h index fbbc17a31db..c5b0adbc182 100644 --- a/drivers/net/pasemi_mac.h +++ b/drivers/net/pasemi_mac.h @@ -31,7 +31,7 @@ struct pasemi_mac_txring { struct pas_dma_xct_descr *desc; dma_addr_t dma; unsigned int size; - unsigned int next_to_use; + unsigned int next_to_fill; unsigned int next_to_clean; struct pasemi_mac_buffer *desc_info; char irq_name[10]; /* "eth%d tx" */ -- cgit v1.2.3-70-g09d2 From 38bf3184e8c4b8cd4285a24b6f69a300b32f0062 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 22 Aug 2007 09:13:24 -0500 Subject: pasemi_mac: Fix RX checksum flags RX side flag to use is CHECKSUM_UNNECESSARY, not CHECKSUM_COMPLETE. Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik --- drivers/net/pasemi_mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index dc710a0826b..0bfdd79de6c 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -524,7 +524,7 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) skb_put(skb, len); if (likely((macrx & XCT_MACRX_HTY_M) == XCT_MACRX_HTY_IPV4_OK)) { - skb->ip_summed = CHECKSUM_COMPLETE; + skb->ip_summed = CHECKSUM_UNNECESSARY; skb->csum = (macrx & XCT_MACRX_CSUM_M) >> XCT_MACRX_CSUM_S; } else -- cgit v1.2.3-70-g09d2 From 6fba848a9a4bbe03f61b22bf0e4063d7ed4c561a Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Sat, 15 Sep 2007 13:51:11 -0700 Subject: pasemi_mac: Enable LLTX Enable LLTX on pasemi_mac: we're already doing sufficient locking in the driver to enable it. [ Resolved merge conflicts with napi_struct changes... -DaveM ] Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik Signed-off-by: David S. Miller --- drivers/net/pasemi_mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 0bfdd79de6c..916a76e28a8 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -1186,7 +1186,7 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netif_napi_add(dev, &mac->napi, pasemi_mac_poll, 64); - dev->features = NETIF_F_HW_CSUM; + dev->features = NETIF_F_HW_CSUM | NETIF_F_LLTX; /* These should come out of the device tree eventually */ mac->dma_txch = index; -- cgit v1.2.3-70-g09d2 From 829185e97fba67ededd3eb025147bafcc0ca7557 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Sat, 15 Sep 2007 13:53:19 -0700 Subject: pasemi_mac: Clean TX ring in poll Unfortunately there's no timeout for how long a packet can sit on the TX ring after completion before an interrupt is generated, and we want to have a threshold that's larger than one packet per interrupt. So we have to have a timer that occasionally cleans the TX ring even though there hasn't been an interrupt. Instead of setting up a dedicated timer for this, just clean it in the NAPI poll routine instead. [ Resolved conflicts with napi_struct changes... -DaveM ] Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik Signed-off-by: David S. Miller --- drivers/net/pasemi_mac.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 916a76e28a8..48c117038fe 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -1078,6 +1078,7 @@ static int pasemi_mac_poll(struct napi_struct *napi, int budget) struct net_device *dev = mac->netdev; int pkts; + pasemi_mac_clean_tx(mac); pkts = pasemi_mac_clean_rx(mac, budget); if (pkts < budget) { /* all done, no more packets present */ -- cgit v1.2.3-70-g09d2 From 173261ed37e7a98cedfcc808eb07eeceee66e078 Mon Sep 17 00:00:00 2001 From: Masakazu Mokuno Date: Fri, 31 Aug 2007 22:22:32 +0900 Subject: PS3: changed the way to handle tx skbs The PS3 virtual network device requires a vlan tag in the sending packet to select the destination device, ethernet port or wireless. As the vlan tag field is in the middle of the passed data, we should insert it into the packet data. To avoid copying much of the packet data, the driver used two tx descriptors for one tx skb; one descriptor was for sending a small static buffer which contained vlan tag and copied header (two mac addresses), one was for the residual data after the vlan field. This patch changes the way to insert the vlan tag. By changing netdev->hard_header_len, we can make the headroom for moving mac address fields in the skb buffer. Then we can send one tx skb with one tx descriptor. This also gives us a tx throughut gain of approx. 20% according to netperf results. Signed-off-by: Masakazu Mokuno CC: Geoff Levand Signed-off-by: Jeff Garzik --- drivers/net/ps3_gelic_net.c | 140 ++++++++++++++++++++------------------------ 1 file changed, 63 insertions(+), 77 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c index 92561c0450b..31c3092e66a 100644 --- a/drivers/net/ps3_gelic_net.c +++ b/drivers/net/ps3_gelic_net.c @@ -351,19 +351,13 @@ static int gelic_net_alloc_rx_skbs(struct gelic_net_card *card) static void gelic_net_release_tx_descr(struct gelic_net_card *card, struct gelic_net_descr *descr) { - struct sk_buff *skb; + struct sk_buff *skb = descr->skb; + BUG_ON(!(descr->data_status & (1 << GELIC_NET_TXDESC_TAIL))); - if (descr->data_status & (1 << GELIC_NET_TXDESC_TAIL)) { - /* 2nd descriptor */ - skb = descr->skb; - dma_unmap_single(ctodev(card), descr->buf_addr, skb->len, - DMA_TO_DEVICE); - dev_kfree_skb_any(skb); - } else { - dma_unmap_single(ctodev(card), descr->buf_addr, - descr->buf_size, DMA_TO_DEVICE); - } + dma_unmap_single(ctodev(card), descr->buf_addr, skb->len, + DMA_TO_DEVICE); + dev_kfree_skb_any(skb); descr->buf_addr = 0; descr->buf_size = 0; @@ -426,7 +420,7 @@ static void gelic_net_release_tx_chain(struct gelic_net_card *card, int stop) release ++; } out: - if (!stop && (2 < release)) + if (!stop && release) netif_wake_queue(card->netdev); } @@ -593,13 +587,10 @@ gelic_net_get_next_tx_descr(struct gelic_net_card *card) { if (!card->tx_chain.head) return NULL; - /* see if we can two consecutive free descrs */ + /* see if the next descriptor is free */ if (card->tx_chain.tail != card->tx_chain.head->next && gelic_net_get_descr_status(card->tx_chain.head) == - GELIC_NET_DESCR_NOT_IN_USE && - card->tx_chain.tail != card->tx_chain.head->next->next && - gelic_net_get_descr_status(card->tx_chain.head->next) == - GELIC_NET_DESCR_NOT_IN_USE ) + GELIC_NET_DESCR_NOT_IN_USE) return card->tx_chain.head; else return NULL; @@ -610,44 +601,66 @@ gelic_net_get_next_tx_descr(struct gelic_net_card *card) * gelic_net_set_txdescr_cmdstat - sets the tx descriptor command field * @descr: descriptor structure to fill out * @skb: packet to consider - * @middle: middle of frame * * fills out the command and status field of the descriptor structure, * depending on hardware checksum settings. This function assumes a wmb() * has executed before. */ static void gelic_net_set_txdescr_cmdstat(struct gelic_net_descr *descr, - struct sk_buff *skb, int middle) + struct sk_buff *skb) { - u32 eofr; - - if (middle) - eofr = 0; - else - eofr = GELIC_NET_DMAC_CMDSTAT_END_FRAME; - if (skb->ip_summed != CHECKSUM_PARTIAL) - descr->dmac_cmd_status = GELIC_NET_DMAC_CMDSTAT_NOCS | eofr; + descr->dmac_cmd_status = GELIC_NET_DMAC_CMDSTAT_NOCS | + GELIC_NET_DMAC_CMDSTAT_END_FRAME; else { /* is packet ip? * if yes: tcp? udp? */ if (skb->protocol == htons(ETH_P_IP)) { if (ip_hdr(skb)->protocol == IPPROTO_TCP) descr->dmac_cmd_status = - GELIC_NET_DMAC_CMDSTAT_TCPCS | eofr; + GELIC_NET_DMAC_CMDSTAT_TCPCS | + GELIC_NET_DMAC_CMDSTAT_END_FRAME; + else if (ip_hdr(skb)->protocol == IPPROTO_UDP) descr->dmac_cmd_status = - GELIC_NET_DMAC_CMDSTAT_UDPCS | eofr; + GELIC_NET_DMAC_CMDSTAT_UDPCS | + GELIC_NET_DMAC_CMDSTAT_END_FRAME; else /* * the stack should checksum non-tcp and non-udp * packets on his own: NETIF_F_IP_CSUM */ descr->dmac_cmd_status = - GELIC_NET_DMAC_CMDSTAT_NOCS | eofr; + GELIC_NET_DMAC_CMDSTAT_NOCS | + GELIC_NET_DMAC_CMDSTAT_END_FRAME; } } } +static inline struct sk_buff *gelic_put_vlan_tag(struct sk_buff *skb, + unsigned short tag) +{ + struct vlan_ethhdr *veth; + static unsigned int c; + + if (skb_headroom(skb) < VLAN_HLEN) { + struct sk_buff *sk_tmp = skb; + pr_debug("%s: hd=%d c=%ud\n", __func__, skb_headroom(skb), c); + skb = skb_realloc_headroom(sk_tmp, VLAN_HLEN); + if (!skb) + return NULL; + dev_kfree_skb_any(sk_tmp); + } + veth = (struct vlan_ethhdr *)skb_push(skb, VLAN_HLEN); + + /* Move the mac addresses to the top of buffer */ + memmove(skb->data, skb->data + VLAN_HLEN, 2 * ETH_ALEN); + + veth->h_vlan_proto = __constant_htons(ETH_P_8021Q); + veth->h_vlan_TCI = htons(tag); + + return skb; +} + /** * gelic_net_prepare_tx_descr_v - get dma address of skb_data * @card: card structure @@ -661,65 +674,35 @@ static int gelic_net_prepare_tx_descr_v(struct gelic_net_card *card, struct gelic_net_descr *descr, struct sk_buff *skb) { - dma_addr_t buf[2]; - unsigned int vlan_len; - struct gelic_net_descr *sec_descr = descr->next; - - if (skb->len < GELIC_NET_VLAN_POS) - return -EINVAL; + dma_addr_t buf; - vlan_len = GELIC_NET_VLAN_POS; - memcpy(&descr->vlan, skb->data, vlan_len); if (card->vlan_index != -1) { - /* internal vlan tag used */ - descr->vlan.h_vlan_proto = htons(ETH_P_8021Q); /* vlan 0x8100*/ - descr->vlan.h_vlan_TCI = htons(card->vlan_id[card->vlan_index]); - vlan_len += VLAN_HLEN; /* added for above two lines */ - } - - /* map data area */ - buf[0] = dma_map_single(ctodev(card), &descr->vlan, - vlan_len, DMA_TO_DEVICE); - - if (!buf[0]) { - dev_err(ctodev(card), - "dma map 1 failed (%p, %i). Dropping packet\n", - skb->data, vlan_len); - return -ENOMEM; + struct sk_buff *skb_tmp; + skb_tmp = gelic_put_vlan_tag(skb, + card->vlan_id[card->vlan_index]); + if (!skb_tmp) + return -ENOMEM; + skb = skb_tmp; } - buf[1] = dma_map_single(ctodev(card), skb->data + GELIC_NET_VLAN_POS, - skb->len - GELIC_NET_VLAN_POS, - DMA_TO_DEVICE); + buf = dma_map_single(ctodev(card), skb->data, skb->len, DMA_TO_DEVICE); - if (!buf[1]) { + if (!buf) { dev_err(ctodev(card), "dma map 2 failed (%p, %i). Dropping packet\n", - skb->data + GELIC_NET_VLAN_POS, - skb->len - GELIC_NET_VLAN_POS); - dma_unmap_single(ctodev(card), buf[0], vlan_len, - DMA_TO_DEVICE); + skb->data, skb->len); return -ENOMEM; } - /* first descr */ - descr->buf_addr = buf[0]; - descr->buf_size = vlan_len; - descr->skb = NULL; /* not used */ + descr->buf_addr = buf; + descr->buf_size = skb->len; + descr->skb = skb; descr->data_status = 0; - descr->next_descr_addr = descr->next->bus_addr; - gelic_net_set_txdescr_cmdstat(descr, skb, 1); /* not the frame end */ - - /* second descr */ - sec_descr->buf_addr = buf[1]; - sec_descr->buf_size = skb->len - GELIC_NET_VLAN_POS; - sec_descr->skb = skb; - sec_descr->data_status = 0; - sec_descr->next_descr_addr = 0; /* terminate hw descr */ - gelic_net_set_txdescr_cmdstat(sec_descr, skb, 0); + descr->next_descr_addr = 0; /* terminate hw descr */ + gelic_net_set_txdescr_cmdstat(descr, skb); /* bump free descriptor pointer */ - card->tx_chain.head = sec_descr->next; + card->tx_chain.head = descr->next; return 0; } @@ -1425,8 +1408,11 @@ static int gelic_net_setup_netdev(struct gelic_net_card *card) dev_dbg(ctodev(card), "vlan_id:%d, %lx\n", i, v1); } } - if (card->vlan_id[GELIC_NET_VLAN_WIRED - 1]) + + if (card->vlan_id[GELIC_NET_VLAN_WIRED - 1]) { card->vlan_index = GELIC_NET_VLAN_WIRED - 1; + netdev->hard_header_len += VLAN_HLEN; + } status = register_netdev(netdev); if (status) { -- cgit v1.2.3-70-g09d2 From dc029ad97f267cbd1c2e978a443eb5ae93a55328 Mon Sep 17 00:00:00 2001 From: Masakazu Mokuno Date: Fri, 31 Aug 2007 22:25:09 +0900 Subject: PS3: Remove the workaround no longer needed Removed the workaround that was needed for PS3 firmware versions prior to the first release. Signed-off-by: Masakazu Mokuno CC: Geoff Levand Signed-off-by: Jeff Garzik --- drivers/net/ps3_gelic_net.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c index 31c3092e66a..93c2c39a4a4 100644 --- a/drivers/net/ps3_gelic_net.c +++ b/drivers/net/ps3_gelic_net.c @@ -716,25 +716,17 @@ static int gelic_net_kick_txdma(struct gelic_net_card *card, struct gelic_net_descr *descr) { int status = 0; - int count = 10; if (card->tx_dma_progress) return 0; if (gelic_net_get_descr_status(descr) == GELIC_NET_DESCR_CARDOWNED) { card->tx_dma_progress = 1; - /* sometimes we need retry here */ - while (count--) { - status = lv1_net_start_tx_dma(bus_id(card), - dev_id(card), - descr->bus_addr, 0); - if (!status) - break; - } - if (!count) + status = lv1_net_start_tx_dma(bus_id(card), dev_id(card), + descr->bus_addr, 0); + if (status) dev_info(ctodev(card), "lv1_net_start_txdma failed," \ - "status=%d %#lx\n", - status, card->irq_status); + "status=%d\n", status); } return status; } -- cgit v1.2.3-70-g09d2 From 9a799d71034c4e2b168740c8a8530591011313d5 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Sat, 15 Sep 2007 14:07:45 -0700 Subject: ixgbe: driver for Intel(R) 82598 PCI-Express 10GbE adapters (v4) This patch adds support for the Intel 82598 PCI-Express 10GbE chipset. Devices will be available on the market soon. This version of the driver is largely the same as the last release: * Driver uses a single RX and single TX queue, each using 1 MSI-X irq vector. * Driver runs in NAPI mode only * Driver is largely multiqueue-ready (TM) Changes since 20070803: * removed wrappers for hardware functions * incorporated e1000e-style HW api reorganization code * sparse/checkpatch cleanups, namespace cleanups * driver prints out extra debugging information at load time identifying adapter board number, mac, phy types * removed ixgbe_api.c, ixgbe_api.h, ixgbe_osdep.h * driver update to 1.1.18 * removed ixgbe.txt which contained no useful info anymore [ Integrated napi_struct changes from Auke as well... -DaveM ] Signed-off-by: Auke Kok Signed-off-by: Ayyappan Veeraiyan Signed-off-by: Jeff Garzik Signed-off-by: David S. Miller --- MAINTAINERS | 10 +- drivers/net/Kconfig | 27 +- drivers/net/Makefile | 1 + drivers/net/ixgbe/Makefile | 36 + drivers/net/ixgbe/ixgbe.h | 259 ++++ drivers/net/ixgbe/ixgbe_82598.c | 589 ++++++++ drivers/net/ixgbe/ixgbe_common.c | 1175 +++++++++++++++ drivers/net/ixgbe/ixgbe_common.h | 86 ++ drivers/net/ixgbe/ixgbe_ethtool.c | 943 ++++++++++++ drivers/net/ixgbe/ixgbe_main.c | 2873 +++++++++++++++++++++++++++++++++++++ drivers/net/ixgbe/ixgbe_phy.c | 494 +++++++ drivers/net/ixgbe/ixgbe_phy.h | 50 + drivers/net/ixgbe/ixgbe_type.h | 1332 +++++++++++++++++ 13 files changed, 7867 insertions(+), 8 deletions(-) create mode 100644 drivers/net/ixgbe/Makefile create mode 100644 drivers/net/ixgbe/ixgbe.h create mode 100644 drivers/net/ixgbe/ixgbe_82598.c create mode 100644 drivers/net/ixgbe/ixgbe_common.c create mode 100644 drivers/net/ixgbe/ixgbe_common.h create mode 100644 drivers/net/ixgbe/ixgbe_ethtool.c create mode 100644 drivers/net/ixgbe/ixgbe_main.c create mode 100644 drivers/net/ixgbe/ixgbe_phy.c create mode 100644 drivers/net/ixgbe/ixgbe_phy.h create mode 100644 drivers/net/ixgbe/ixgbe_type.h (limited to 'drivers') diff --git a/MAINTAINERS b/MAINTAINERS index e0861f7e1cc..c35eb125e1c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2030,16 +2030,14 @@ W: http://sourceforge.net/projects/e1000/ S: Supported INTEL PRO/10GbE SUPPORT -P: Jeff Kirsher -M: jeffrey.t.kirsher@intel.com P: Ayyappan Veeraiyan M: ayyappan.veeraiyan@intel.com -P: John Ronciak -M: john.ronciak@intel.com -P: Jesse Brandeburg -M: jesse.brandeburg@intel.com P: Auke Kok M: auke-jan.h.kok@intel.com +P: Jesse Brandeburg +M: jesse.brandeburg@intel.com +P: John Ronciak +M: john.ronciak@intel.com L: e1000-devel@lists.sourceforge.net W: http://sourceforge.net/projects/e1000/ S: Supported diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index eeac2f49aae..76db0bc9452 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2518,12 +2518,35 @@ config EHEA To compile the driver as a module, choose M here. The module will be called ehea. +config IXGBE + tristate "Intel(R) 10GbE PCI Express adapters support" + depends on PCI + ---help--- + This driver supports Intel(R) 10GbE PCI Express family of + adapters. For more information on how to identify your adapter, go + to the Adapter & Driver ID Guide at: + + + + For general information and support, go to the Intel support + website at: + + + + More specific information on configuring the driver is in + . + + To compile this driver as a module, choose M here and read + . The module + will be called ixgbe. + config IXGB tristate "Intel(R) PRO/10GbE support" depends on PCI ---help--- - This driver supports Intel(R) PRO/10GbE family of - adapters. For more information on how to identify your adapter, go + This driver supports Intel(R) PRO/10GbE family of adapters for + PCI-X type cards. For PCI-E type cards, use the "ixgbe" driver + instead. For more information on how to identify your adapter, go to the Adapter & Driver ID Guide at: diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 0d2b4bee587..c23ffdbe259 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_E1000) += e1000/ obj-$(CONFIG_E1000E) += e1000e/ obj-$(CONFIG_IBM_EMAC) += ibm_emac/ +obj-$(CONFIG_IXGBE) += ixgbe/ obj-$(CONFIG_IXGB) += ixgb/ obj-$(CONFIG_CHELSIO_T1) += chelsio/ obj-$(CONFIG_CHELSIO_T3) += cxgb3/ diff --git a/drivers/net/ixgbe/Makefile b/drivers/net/ixgbe/Makefile new file mode 100644 index 00000000000..ccd83d9f579 --- /dev/null +++ b/drivers/net/ixgbe/Makefile @@ -0,0 +1,36 @@ +################################################################################ +# +# Intel 10 Gigabit PCI Express Linux driver +# Copyright(c) 1999 - 2007 Intel Corporation. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms and conditions of the GNU General Public License, +# version 2, as published by the Free Software Foundation. +# +# This program is distributed in the hope it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +# +# The full GNU General Public License is included in this distribution in +# the file called "COPYING". +# +# Contact Information: +# Linux NICS +# e1000-devel Mailing List +# Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 +# +################################################################################ + +# +# Makefile for the Intel(R) 10GbE PCI Express ethernet driver +# + +obj-$(CONFIG_IXGBE) += ixgbe.o + +ixgbe-objs := ixgbe_main.o ixgbe_common.o ixgbe_ethtool.o \ + ixgbe_82598.o ixgbe_phy.o diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h new file mode 100644 index 00000000000..c160a7d91e2 --- /dev/null +++ b/drivers/net/ixgbe/ixgbe.h @@ -0,0 +1,259 @@ +/******************************************************************************* + + Intel 10 Gigabit PCI Express Linux driver + Copyright(c) 1999 - 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#ifndef _IXGBE_H_ +#define _IXGBE_H_ + +#include +#include +#include + +#include "ixgbe_type.h" +#include "ixgbe_common.h" + + +#define IXGBE_ERR(args...) printk(KERN_ERR "ixgbe: " args) + +#define PFX "ixgbe: " +#define DPRINTK(nlevel, klevel, fmt, args...) \ + ((void)((NETIF_MSG_##nlevel & adapter->msg_enable) && \ + printk(KERN_##klevel PFX "%s: %s: " fmt, adapter->netdev->name, \ + __FUNCTION__ , ## args))) + +/* TX/RX descriptor defines */ +#define IXGBE_DEFAULT_TXD 1024 +#define IXGBE_MAX_TXD 4096 +#define IXGBE_MIN_TXD 64 + +#define IXGBE_DEFAULT_RXD 1024 +#define IXGBE_MAX_RXD 4096 +#define IXGBE_MIN_RXD 64 + +#define IXGBE_DEFAULT_RXQ 1 +#define IXGBE_MAX_RXQ 1 +#define IXGBE_MIN_RXQ 1 + +#define IXGBE_DEFAULT_ITR_RX_USECS 125 /* 8k irqs/sec */ +#define IXGBE_DEFAULT_ITR_TX_USECS 250 /* 4k irqs/sec */ +#define IXGBE_MIN_ITR_USECS 100 /* 500k irqs/sec */ +#define IXGBE_MAX_ITR_USECS 10000 /* 100 irqs/sec */ + +/* flow control */ +#define IXGBE_DEFAULT_FCRTL 0x10000 +#define IXGBE_MIN_FCRTL 0 +#define IXGBE_MAX_FCRTL 0x7FF80 +#define IXGBE_DEFAULT_FCRTH 0x20000 +#define IXGBE_MIN_FCRTH 0 +#define IXGBE_MAX_FCRTH 0x7FFF0 +#define IXGBE_DEFAULT_FCPAUSE 0x6800 /* may be too long */ +#define IXGBE_MIN_FCPAUSE 0 +#define IXGBE_MAX_FCPAUSE 0xFFFF + +/* Supported Rx Buffer Sizes */ +#define IXGBE_RXBUFFER_64 64 /* Used for packet split */ +#define IXGBE_RXBUFFER_128 128 /* Used for packet split */ +#define IXGBE_RXBUFFER_256 256 /* Used for packet split */ +#define IXGBE_RXBUFFER_2048 2048 + +#define IXGBE_RX_HDR_SIZE IXGBE_RXBUFFER_256 + +#define MAXIMUM_ETHERNET_VLAN_SIZE (ETH_FRAME_LEN + ETH_FCS_LEN + VLAN_HLEN) + +/* How many Tx Descriptors do we need to call netif_wake_queue? */ +#define IXGBE_TX_QUEUE_WAKE 16 + +/* How many Rx Buffers do we bundle into one write to the hardware ? */ +#define IXGBE_RX_BUFFER_WRITE 16 /* Must be power of 2 */ + +#define IXGBE_TX_FLAGS_CSUM (u32)(1) +#define IXGBE_TX_FLAGS_VLAN (u32)(1 << 1) +#define IXGBE_TX_FLAGS_TSO (u32)(1 << 2) +#define IXGBE_TX_FLAGS_IPV4 (u32)(1 << 3) +#define IXGBE_TX_FLAGS_VLAN_MASK 0xffff0000 +#define IXGBE_TX_FLAGS_VLAN_SHIFT 16 + +/* wrapper around a pointer to a socket buffer, + * so a DMA handle can be stored along with the buffer */ +struct ixgbe_tx_buffer { + struct sk_buff *skb; + dma_addr_t dma; + unsigned long time_stamp; + u16 length; + u16 next_to_watch; +}; + +struct ixgbe_rx_buffer { + struct sk_buff *skb; + dma_addr_t dma; + struct page *page; + dma_addr_t page_dma; +}; + +struct ixgbe_queue_stats { + u64 packets; + u64 bytes; +}; + +struct ixgbe_ring { + struct ixgbe_adapter *adapter; /* backlink */ + void *desc; /* descriptor ring memory */ + dma_addr_t dma; /* phys. address of descriptor ring */ + unsigned int size; /* length in bytes */ + unsigned int count; /* amount of descriptors */ + unsigned int next_to_use; + unsigned int next_to_clean; + + union { + struct ixgbe_tx_buffer *tx_buffer_info; + struct ixgbe_rx_buffer *rx_buffer_info; + }; + + u16 head; + u16 tail; + + /* To protect race between sender and clean_tx_irq */ + spinlock_t tx_lock; + + struct ixgbe_queue_stats stats; + + u32 eims_value; + u16 itr_register; + + char name[IFNAMSIZ + 5]; + u16 work_limit; /* max work per interrupt */ +}; + +/* Helper macros to switch between ints/sec and what the register uses. + * And yes, it's the same math going both ways. + */ +#define EITR_INTS_PER_SEC_TO_REG(_eitr) \ + ((_eitr) ? (1000000000 / ((_eitr) * 256)) : 0) +#define EITR_REG_TO_INTS_PER_SEC EITR_INTS_PER_SEC_TO_REG + +#define IXGBE_DESC_UNUSED(R) \ + ((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->count) + \ + (R)->next_to_clean - (R)->next_to_use - 1) + +#define IXGBE_RX_DESC_ADV(R, i) \ + (&(((union ixgbe_adv_rx_desc *)((R).desc))[i])) +#define IXGBE_TX_DESC_ADV(R, i) \ + (&(((union ixgbe_adv_tx_desc *)((R).desc))[i])) +#define IXGBE_TX_CTXTDESC_ADV(R, i) \ + (&(((struct ixgbe_adv_tx_context_desc *)((R).desc))[i])) + +#define IXGBE_MAX_JUMBO_FRAME_SIZE 16128 + +/* board specific private data structure */ +struct ixgbe_adapter { + struct timer_list watchdog_timer; + struct vlan_group *vlgrp; + u16 bd_number; + u16 rx_buf_len; + atomic_t irq_sem; + struct work_struct reset_task; + + /* TX */ + struct ixgbe_ring *tx_ring; /* One per active queue */ + struct napi_struct napi; + u64 restart_queue; + u64 lsc_int; + u64 hw_tso_ctxt; + u64 hw_tso6_ctxt; + u32 tx_timeout_count; + bool detect_tx_hung; + + /* RX */ + struct ixgbe_ring *rx_ring; /* One per active queue */ + u64 hw_csum_tx_good; + u64 hw_csum_rx_error; + u64 hw_csum_rx_good; + u64 non_eop_descs; + int num_tx_queues; + int num_rx_queues; + struct msix_entry *msix_entries; + + u64 rx_hdr_split; + u32 alloc_rx_page_failed; + u32 alloc_rx_buff_failed; + + u32 flags; +#define IXGBE_FLAG_RX_CSUM_ENABLED (u32)(1) +#define IXGBE_FLAG_MSI_ENABLED (u32)(1 << 1) +#define IXGBE_FLAG_MSIX_ENABLED (u32)(1 << 2) +#define IXGBE_FLAG_RX_PS_ENABLED (u32)(1 << 3) +#define IXGBE_FLAG_IN_NETPOLL (u32)(1 << 4) + + /* Interrupt Throttle Rate */ + u32 rx_eitr; + u32 tx_eitr; + + /* OS defined structs */ + struct net_device *netdev; + struct pci_dev *pdev; + struct net_device_stats net_stats; + + /* structs defined in ixgbe_hw.h */ + struct ixgbe_hw hw; + u16 msg_enable; + struct ixgbe_hw_stats stats; + char lsc_name[IFNAMSIZ + 5]; + + unsigned long state; + u64 tx_busy; +}; + +enum ixbge_state_t { + __IXGBE_TESTING, + __IXGBE_RESETTING, + __IXGBE_DOWN +}; + +enum ixgbe_boards { + board_82598AF, + board_82598EB, + board_82598AT, +}; + +extern struct ixgbe_info ixgbe_82598AF_info; +extern struct ixgbe_info ixgbe_82598EB_info; +extern struct ixgbe_info ixgbe_82598AT_info; + +extern char ixgbe_driver_name[]; +extern char ixgbe_driver_version[]; + +extern int ixgbe_up(struct ixgbe_adapter *adapter); +extern void ixgbe_down(struct ixgbe_adapter *adapter); +extern void ixgbe_reset(struct ixgbe_adapter *adapter); +extern void ixgbe_update_stats(struct ixgbe_adapter *adapter); +extern void ixgbe_set_ethtool_ops(struct net_device *netdev); +extern int ixgbe_setup_rx_resources(struct ixgbe_adapter *adapter, + struct ixgbe_ring *rxdr); +extern int ixgbe_setup_tx_resources(struct ixgbe_adapter *adapter, + struct ixgbe_ring *txdr); + +#endif /* _IXGBE_H_ */ diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c new file mode 100644 index 00000000000..00ee20125ca --- /dev/null +++ b/drivers/net/ixgbe/ixgbe_82598.c @@ -0,0 +1,589 @@ +/******************************************************************************* + + Intel 10 Gigabit PCI Express Linux driver + Copyright(c) 1999 - 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#include +#include +#include + +#include "ixgbe_type.h" +#include "ixgbe_common.h" +#include "ixgbe_phy.h" + +#define IXGBE_82598_MAX_TX_QUEUES 32 +#define IXGBE_82598_MAX_RX_QUEUES 64 +#define IXGBE_82598_RAR_ENTRIES 16 + +static s32 ixgbe_get_invariants_82598(struct ixgbe_hw *hw); +static s32 ixgbe_get_link_settings_82598(struct ixgbe_hw *hw, u32 *speed, + bool *autoneg); +static s32 ixgbe_get_copper_link_settings_82598(struct ixgbe_hw *hw, + u32 *speed, bool *autoneg); +static enum ixgbe_media_type ixgbe_get_media_type_82598(struct ixgbe_hw *hw); +static s32 ixgbe_setup_mac_link_82598(struct ixgbe_hw *hw); +static s32 ixgbe_check_mac_link_82598(struct ixgbe_hw *hw, u32 *speed, + bool *link_up); +static s32 ixgbe_setup_mac_link_speed_82598(struct ixgbe_hw *hw, u32 speed, + bool autoneg, + bool autoneg_wait_to_complete); +static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw); +static s32 ixgbe_check_copper_link_82598(struct ixgbe_hw *hw, u32 *speed, + bool *link_up); +static s32 ixgbe_setup_copper_link_speed_82598(struct ixgbe_hw *hw, u32 speed, + bool autoneg, + bool autoneg_wait_to_complete); +static s32 ixgbe_reset_hw_82598(struct ixgbe_hw *hw); + + +static s32 ixgbe_get_invariants_82598(struct ixgbe_hw *hw) +{ + hw->mac.num_rx_queues = IXGBE_82598_MAX_TX_QUEUES; + hw->mac.num_tx_queues = IXGBE_82598_MAX_RX_QUEUES; + hw->mac.num_rx_addrs = IXGBE_82598_RAR_ENTRIES; + + return 0; +} + +/** + * ixgbe_get_link_settings_82598 - Determines default link settings + * @hw: pointer to hardware structure + * @speed: pointer to link speed + * @autoneg: boolean auto-negotiation value + * + * Determines the default link settings by reading the AUTOC register. + **/ +static s32 ixgbe_get_link_settings_82598(struct ixgbe_hw *hw, u32 *speed, + bool *autoneg) +{ + s32 status = 0; + s32 autoc_reg; + + autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC); + + if (hw->mac.link_settings_loaded) { + autoc_reg &= ~IXGBE_AUTOC_LMS_ATTACH_TYPE; + autoc_reg &= ~IXGBE_AUTOC_LMS_MASK; + autoc_reg |= hw->mac.link_attach_type; + autoc_reg |= hw->mac.link_mode_select; + } + + switch (autoc_reg & IXGBE_AUTOC_LMS_MASK) { + case IXGBE_AUTOC_LMS_1G_LINK_NO_AN: + *speed = IXGBE_LINK_SPEED_1GB_FULL; + *autoneg = false; + break; + + case IXGBE_AUTOC_LMS_10G_LINK_NO_AN: + *speed = IXGBE_LINK_SPEED_10GB_FULL; + *autoneg = false; + break; + + case IXGBE_AUTOC_LMS_1G_AN: + *speed = IXGBE_LINK_SPEED_1GB_FULL; + *autoneg = true; + break; + + case IXGBE_AUTOC_LMS_KX4_AN: + case IXGBE_AUTOC_LMS_KX4_AN_1G_AN: + *speed = IXGBE_LINK_SPEED_UNKNOWN; + if (autoc_reg & IXGBE_AUTOC_KX4_SUPP) + *speed |= IXGBE_LINK_SPEED_10GB_FULL; + if (autoc_reg & IXGBE_AUTOC_KX_SUPP) + *speed |= IXGBE_LINK_SPEED_1GB_FULL; + *autoneg = true; + break; + + default: + status = IXGBE_ERR_LINK_SETUP; + break; + } + + return status; +} + +/** + * ixgbe_get_copper_link_settings_82598 - Determines default link settings + * @hw: pointer to hardware structure + * @speed: pointer to link speed + * @autoneg: boolean auto-negotiation value + * + * Determines the default link settings by reading the AUTOC register. + **/ +static s32 ixgbe_get_copper_link_settings_82598(struct ixgbe_hw *hw, + u32 *speed, bool *autoneg) +{ + s32 status = IXGBE_ERR_LINK_SETUP; + u16 speed_ability; + + *speed = 0; + *autoneg = true; + + status = ixgbe_read_phy_reg(hw, IXGBE_MDIO_PHY_SPEED_ABILITY, + IXGBE_MDIO_PMA_PMD_DEV_TYPE, + &speed_ability); + + if (status == 0) { + if (speed_ability & IXGBE_MDIO_PHY_SPEED_10G) + *speed |= IXGBE_LINK_SPEED_10GB_FULL; + if (speed_ability & IXGBE_MDIO_PHY_SPEED_1G) + *speed |= IXGBE_LINK_SPEED_1GB_FULL; + } + + return status; +} + +/** + * ixgbe_get_media_type_82598 - Determines media type + * @hw: pointer to hardware structure + * + * Returns the media type (fiber, copper, backplane) + **/ +static enum ixgbe_media_type ixgbe_get_media_type_82598(struct ixgbe_hw *hw) +{ + enum ixgbe_media_type media_type; + + /* Media type for I82598 is based on device ID */ + switch (hw->device_id) { + case IXGBE_DEV_ID_82598AF_DUAL_PORT: + case IXGBE_DEV_ID_82598AF_SINGLE_PORT: + case IXGBE_DEV_ID_82598EB_CX4: + media_type = ixgbe_media_type_fiber; + break; + case IXGBE_DEV_ID_82598AT_DUAL_PORT: + media_type = ixgbe_media_type_copper; + break; + default: + media_type = ixgbe_media_type_unknown; + break; + } + + return media_type; +} + +/** + * ixgbe_setup_mac_link_82598 - Configures MAC link settings + * @hw: pointer to hardware structure + * + * Configures link settings based on values in the ixgbe_hw struct. + * Restarts the link. Performs autonegotiation if needed. + **/ +static s32 ixgbe_setup_mac_link_82598(struct ixgbe_hw *hw) +{ + u32 autoc_reg; + u32 links_reg; + u32 i; + s32 status = 0; + + autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC); + + if (hw->mac.link_settings_loaded) { + autoc_reg &= ~IXGBE_AUTOC_LMS_ATTACH_TYPE; + autoc_reg &= ~IXGBE_AUTOC_LMS_MASK; + autoc_reg |= hw->mac.link_attach_type; + autoc_reg |= hw->mac.link_mode_select; + + IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg); + msleep(50); + } + + /* Restart link */ + autoc_reg |= IXGBE_AUTOC_AN_RESTART; + IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg); + + /* Only poll for autoneg to complete if specified to do so */ + if (hw->phy.autoneg_wait_to_complete) { + if (hw->mac.link_mode_select == IXGBE_AUTOC_LMS_KX4_AN || + hw->mac.link_mode_select == IXGBE_AUTOC_LMS_KX4_AN_1G_AN) { + links_reg = 0; /* Just in case Autoneg time = 0 */ + for (i = 0; i < IXGBE_AUTO_NEG_TIME; i++) { + links_reg = IXGBE_READ_REG(hw, IXGBE_LINKS); + if (links_reg & IXGBE_LINKS_KX_AN_COMP) + break; + msleep(100); + } + if (!(links_reg & IXGBE_LINKS_KX_AN_COMP)) { + status = IXGBE_ERR_AUTONEG_NOT_COMPLETE; + hw_dbg(hw, + "Autonegotiation did not complete.\n"); + } + } + } + + /* + * We want to save off the original Flow Control configuration just in + * case we get disconnected and then reconnected into a different hub + * or switch with different Flow Control capabilities. + */ + hw->fc.type = hw->fc.original_type; + ixgbe_setup_fc(hw, 0); + + /* Add delay to filter out noises during initial link setup */ + msleep(50); + + return status; +} + +/** + * ixgbe_check_mac_link_82598 - Get link/speed status + * @hw: pointer to hardware structure + * @speed: pointer to link speed + * @link_up: true is link is up, false otherwise + * + * Reads the links register to determine if link is up and the current speed + **/ +static s32 ixgbe_check_mac_link_82598(struct ixgbe_hw *hw, u32 *speed, + bool *link_up) +{ + u32 links_reg; + + links_reg = IXGBE_READ_REG(hw, IXGBE_LINKS); + + if (links_reg & IXGBE_LINKS_UP) + *link_up = true; + else + *link_up = false; + + if (links_reg & IXGBE_LINKS_SPEED) + *speed = IXGBE_LINK_SPEED_10GB_FULL; + else + *speed = IXGBE_LINK_SPEED_1GB_FULL; + + return 0; +} + +/** + * ixgbe_setup_mac_link_speed_82598 - Set MAC link speed + * @hw: pointer to hardware structure + * @speed: new link speed + * @autoneg: true if auto-negotiation enabled + * @autoneg_wait_to_complete: true if waiting is needed to complete + * + * Set the link speed in the AUTOC register and restarts link. + **/ +static s32 ixgbe_setup_mac_link_speed_82598(struct ixgbe_hw *hw, + u32 speed, bool autoneg, + bool autoneg_wait_to_complete) +{ + s32 status = 0; + + /* If speed is 10G, then check for CX4 or XAUI. */ + if ((speed == IXGBE_LINK_SPEED_10GB_FULL) && + (!(hw->mac.link_attach_type & IXGBE_AUTOC_10G_KX4))) + hw->mac.link_mode_select = IXGBE_AUTOC_LMS_10G_LINK_NO_AN; + else if ((speed == IXGBE_LINK_SPEED_1GB_FULL) && (!autoneg)) + hw->mac.link_mode_select = IXGBE_AUTOC_LMS_1G_LINK_NO_AN; + else if (autoneg) { + /* BX mode - Autonegotiate 1G */ + if (!(hw->mac.link_attach_type & IXGBE_AUTOC_1G_PMA_PMD)) + hw->mac.link_mode_select = IXGBE_AUTOC_LMS_1G_AN; + else /* KX/KX4 mode */ + hw->mac.link_mode_select = IXGBE_AUTOC_LMS_KX4_AN_1G_AN; + } else { + status = IXGBE_ERR_LINK_SETUP; + } + + if (status == 0) { + hw->phy.autoneg_wait_to_complete = autoneg_wait_to_complete; + + hw->mac.link_settings_loaded = true; + /* + * Setup and restart the link based on the new values in + * ixgbe_hw This will write the AUTOC register based on the new + * stored values + */ + hw->phy.ops.setup(hw); + } + + return status; +} + + +/** + * ixgbe_setup_copper_link_82598 - Setup copper link settings + * @hw: pointer to hardware structure + * + * Configures link settings based on values in the ixgbe_hw struct. + * Restarts the link. Performs autonegotiation if needed. Restart + * phy and wait for autonegotiate to finish. Then synchronize the + * MAC and PHY. + **/ +static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw) +{ + s32 status; + u32 speed = 0; + bool link_up = false; + + /* Set up MAC */ + hw->phy.ops.setup(hw); + + /* Restart autonegotiation on PHY */ + status = hw->phy.ops.setup(hw); + + /* Synchronize MAC to PHY speed */ + if (status == 0) + status = hw->phy.ops.check(hw, &speed, &link_up); + + return status; +} + +/** + * ixgbe_check_copper_link_82598 - Syncs MAC & PHY link settings + * @hw: pointer to hardware structure + * @speed: pointer to link speed + * @link_up: true if link is up, false otherwise + * + * Reads the mac link, phy link, and synchronizes the MAC to PHY. + **/ +static s32 ixgbe_check_copper_link_82598(struct ixgbe_hw *hw, u32 *speed, + bool *link_up) +{ + s32 status; + u32 phy_speed = 0; + bool phy_link = false; + + /* This is the speed and link the MAC is set at */ + hw->phy.ops.check(hw, speed, link_up); + + /* + * Check current speed and link status of the PHY register. + * This is a vendor specific register and may have to + * be changed for other copper PHYs. + */ + status = hw->phy.ops.check(hw, &phy_speed, &phy_link); + + if ((status == 0) && (phy_link)) { + /* + * Check current link status of the MACs link's register + * matches that of the speed in the PHY register + */ + if (*speed != phy_speed) { + /* + * The copper PHY requires 82598 attach type to be XAUI + * for 10G and BX for 1G + */ + hw->mac.link_attach_type = + (IXGBE_AUTOC_10G_XAUI | IXGBE_AUTOC_1G_BX); + + /* Synchronize the MAC speed to the PHY speed */ + status = hw->phy.ops.setup_speed(hw, phy_speed, false, + false); + if (status == 0) + hw->phy.ops.check(hw, speed, link_up); + else + status = IXGBE_ERR_LINK_SETUP; + } + } else { + *link_up = phy_link; + } + + return status; +} + +/** + * ixgbe_setup_copper_link_speed_82598 - Set the PHY autoneg advertised field + * @hw: pointer to hardware structure + * @speed: new link speed + * @autoneg: true if autonegotiation enabled + * @autoneg_wait_to_complete: true if waiting is needed to complete + * + * Sets the link speed in the AUTOC register in the MAC and restarts link. + **/ +static s32 ixgbe_setup_copper_link_speed_82598(struct ixgbe_hw *hw, u32 speed, + bool autoneg, + bool autoneg_wait_to_complete) +{ + s32 status; + bool link_up = 0; + + /* Setup the PHY according to input speed */ + status = hw->phy.ops.setup_speed(hw, speed, autoneg, + autoneg_wait_to_complete); + + /* Synchronize MAC to PHY speed */ + if (status == 0) + status = hw->phy.ops.check(hw, &speed, &link_up); + + return status; +} + +/** + * ixgbe_reset_hw_82598 - Performs hardware reset + * @hw: pointer to hardware structure + * + * Resets the hardware by reseting the transmit and receive units, masks and + * clears all interrupts, performing a PHY reset, and performing a link (MAC) + * reset. + **/ +static s32 ixgbe_reset_hw_82598(struct ixgbe_hw *hw) +{ + s32 status = 0; + u32 ctrl; + u32 gheccr; + u32 i; + u32 autoc; + u8 analog_val; + + /* Call adapter stop to disable tx/rx and clear interrupts */ + ixgbe_stop_adapter(hw); + + /* + * Power up the Atlas TX lanes if they are currently powered down. + * Atlas TX lanes are powered down for MAC loopback tests, but + * they are not automatically restored on reset. + */ + ixgbe_read_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, &analog_val); + if (analog_val & IXGBE_ATLAS_PDN_TX_REG_EN) { + /* Enable TX Atlas so packets can be transmitted again */ + ixgbe_read_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, &analog_val); + analog_val &= ~IXGBE_ATLAS_PDN_TX_REG_EN; + ixgbe_write_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, analog_val); + + ixgbe_read_analog_reg8(hw, IXGBE_ATLAS_PDN_10G, &analog_val); + analog_val &= ~IXGBE_ATLAS_PDN_TX_10G_QL_ALL; + ixgbe_write_analog_reg8(hw, IXGBE_ATLAS_PDN_10G, analog_val); + + ixgbe_read_analog_reg8(hw, IXGBE_ATLAS_PDN_1G, &analog_val); + analog_val &= ~IXGBE_ATLAS_PDN_TX_1G_QL_ALL; + ixgbe_write_analog_reg8(hw, IXGBE_ATLAS_PDN_1G, analog_val); + + ixgbe_read_analog_reg8(hw, IXGBE_ATLAS_PDN_AN, &analog_val); + analog_val &= ~IXGBE_ATLAS_PDN_TX_AN_QL_ALL; + ixgbe_write_analog_reg8(hw, IXGBE_ATLAS_PDN_AN, analog_val); + } + + /* Reset PHY */ + ixgbe_reset_phy(hw); + + /* + * Prevent the PCI-E bus from from hanging by disabling PCI-E master + * access and verify no pending requests before reset + */ + if (ixgbe_disable_pcie_master(hw) != 0) { + status = IXGBE_ERR_MASTER_REQUESTS_PENDING; + hw_dbg(hw, "PCI-E Master disable polling has failed.\n"); + } + + /* + * Issue global reset to the MAC. This needs to be a SW reset. + * If link reset is used, it might reset the MAC when mng is using it + */ + ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL); + IXGBE_WRITE_REG(hw, IXGBE_CTRL, (ctrl | IXGBE_CTRL_RST)); + IXGBE_WRITE_FLUSH(hw); + + /* Poll for reset bit to self-clear indicating reset is complete */ + for (i = 0; i < 10; i++) { + udelay(1); + ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL); + if (!(ctrl & IXGBE_CTRL_RST)) + break; + } + if (ctrl & IXGBE_CTRL_RST) { + status = IXGBE_ERR_RESET_FAILED; + hw_dbg(hw, "Reset polling failed to complete.\n"); + } + + msleep(50); + + gheccr = IXGBE_READ_REG(hw, IXGBE_GHECCR); + gheccr &= ~((1 << 21) | (1 << 18) | (1 << 9) | (1 << 6)); + IXGBE_WRITE_REG(hw, IXGBE_GHECCR, gheccr); + + /* + * AUTOC register which stores link settings gets cleared + * and reloaded from EEPROM after reset. We need to restore + * our stored value from init in case SW changed the attach + * type or speed. If this is the first time and link settings + * have not been stored, store default settings from AUTOC. + */ + autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC); + if (hw->mac.link_settings_loaded) { + autoc &= ~(IXGBE_AUTOC_LMS_ATTACH_TYPE); + autoc &= ~(IXGBE_AUTOC_LMS_MASK); + autoc |= hw->mac.link_attach_type; + autoc |= hw->mac.link_mode_select; + IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc); + } else { + hw->mac.link_attach_type = + (autoc & IXGBE_AUTOC_LMS_ATTACH_TYPE); + hw->mac.link_mode_select = (autoc & IXGBE_AUTOC_LMS_MASK); + hw->mac.link_settings_loaded = true; + } + + /* Store the permanent mac address */ + ixgbe_get_mac_addr(hw, hw->mac.perm_addr); + + return status; +} + +static struct ixgbe_mac_operations mac_ops_82598 = { + .reset = &ixgbe_reset_hw_82598, + .get_media_type = &ixgbe_get_media_type_82598, +}; + +static struct ixgbe_phy_operations phy_ops_82598EB = { + .setup = &ixgbe_setup_copper_link_82598, + .check = &ixgbe_check_copper_link_82598, + .setup_speed = &ixgbe_setup_copper_link_speed_82598, + .get_settings = &ixgbe_get_copper_link_settings_82598, +}; + +struct ixgbe_info ixgbe_82598EB_info = { + .mac = ixgbe_mac_82598EB, + .get_invariants = &ixgbe_get_invariants_82598, + .mac_ops = &mac_ops_82598, + .phy_ops = &phy_ops_82598EB, +}; + +static struct ixgbe_phy_operations phy_ops_82598AT = { + .setup = &ixgbe_setup_tnx_phy_link, + .check = &ixgbe_check_tnx_phy_link, + .setup_speed = &ixgbe_setup_tnx_phy_link_speed, + .get_settings = &ixgbe_get_copper_link_settings_82598, +}; + +struct ixgbe_info ixgbe_82598AT_info = { + .mac = ixgbe_mac_82598EB, + .get_invariants = &ixgbe_get_invariants_82598, + .mac_ops = &mac_ops_82598, + .phy_ops = &phy_ops_82598AT, +}; + +static struct ixgbe_phy_operations phy_ops_82598AF = { + .setup = &ixgbe_setup_mac_link_82598, + .check = &ixgbe_check_mac_link_82598, + .setup_speed = &ixgbe_setup_mac_link_speed_82598, + .get_settings = &ixgbe_get_link_settings_82598, +}; + +struct ixgbe_info ixgbe_82598AF_info = { + .mac = ixgbe_mac_82598EB, + .get_invariants = &ixgbe_get_invariants_82598, + .mac_ops = &mac_ops_82598, + .phy_ops = &phy_ops_82598AF, +}; + diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c new file mode 100644 index 00000000000..512e3b22ed0 --- /dev/null +++ b/drivers/net/ixgbe/ixgbe_common.c @@ -0,0 +1,1175 @@ +/******************************************************************************* + + Intel 10 Gigabit PCI Express Linux driver + Copyright(c) 1999 - 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#include +#include +#include + +#include "ixgbe_common.h" +#include "ixgbe_phy.h" + +static s32 ixgbe_clear_hw_cntrs(struct ixgbe_hw *hw); + +static s32 ixgbe_poll_eeprom_eerd_done(struct ixgbe_hw *hw); +static s32 ixgbe_get_eeprom_semaphore(struct ixgbe_hw *hw); +static void ixgbe_release_eeprom_semaphore(struct ixgbe_hw *hw); +static u16 ixgbe_calc_eeprom_checksum(struct ixgbe_hw *hw); + +static s32 ixgbe_clear_vfta(struct ixgbe_hw *hw); +static s32 ixgbe_init_rx_addrs(struct ixgbe_hw *hw); +static s32 ixgbe_mta_vector(struct ixgbe_hw *hw, u8 *mc_addr); +static void ixgbe_add_mc_addr(struct ixgbe_hw *hw, u8 *mc_addr); + +/** + * ixgbe_start_hw - Prepare hardware for TX/RX + * @hw: pointer to hardware structure + * + * Starts the hardware by filling the bus info structure and media type, clears + * all on chip counters, initializes receive address registers, multicast + * table, VLAN filter table, calls routine to set up link and flow control + * settings, and leaves transmit and receive units disabled and uninitialized + **/ +s32 ixgbe_start_hw(struct ixgbe_hw *hw) +{ + u32 ctrl_ext; + + /* Set the media type */ + hw->phy.media_type = hw->mac.ops.get_media_type(hw); + + /* Identify the PHY */ + ixgbe_identify_phy(hw); + + /* + * Store MAC address from RAR0, clear receive address registers, and + * clear the multicast table + */ + ixgbe_init_rx_addrs(hw); + + /* Clear the VLAN filter table */ + ixgbe_clear_vfta(hw); + + /* Set up link */ + hw->phy.ops.setup(hw); + + /* Clear statistics registers */ + ixgbe_clear_hw_cntrs(hw); + + /* Set No Snoop Disable */ + ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT); + ctrl_ext |= IXGBE_CTRL_EXT_NS_DIS; + IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext); + + /* Clear adapter stopped flag */ + hw->adapter_stopped = false; + + return 0; +} + +/** + * ixgbe_init_hw - Generic hardware initialization + * @hw: pointer to hardware structure + * + * Initialize the hardware by reseting the hardware, filling the bus info + * structure and media type, clears all on chip counters, initializes receive + * address registers, multicast table, VLAN filter table, calls routine to set + * up link and flow control settings, and leaves transmit and receive units + * disabled and uninitialized + **/ +s32 ixgbe_init_hw(struct ixgbe_hw *hw) +{ + /* Reset the hardware */ + hw->mac.ops.reset(hw); + + /* Start the HW */ + ixgbe_start_hw(hw); + + return 0; +} + +/** + * ixgbe_clear_hw_cntrs - Generic clear hardware counters + * @hw: pointer to hardware structure + * + * Clears all hardware statistics counters by reading them from the hardware + * Statistics counters are clear on read. + **/ +static s32 ixgbe_clear_hw_cntrs(struct ixgbe_hw *hw) +{ + u16 i = 0; + + IXGBE_READ_REG(hw, IXGBE_CRCERRS); + IXGBE_READ_REG(hw, IXGBE_ILLERRC); + IXGBE_READ_REG(hw, IXGBE_ERRBC); + IXGBE_READ_REG(hw, IXGBE_MSPDC); + for (i = 0; i < 8; i++) + IXGBE_READ_REG(hw, IXGBE_MPC(i)); + + IXGBE_READ_REG(hw, IXGBE_MLFC); + IXGBE_READ_REG(hw, IXGBE_MRFC); + IXGBE_READ_REG(hw, IXGBE_RLEC); + IXGBE_READ_REG(hw, IXGBE_LXONTXC); + IXGBE_READ_REG(hw, IXGBE_LXONRXC); + IXGBE_READ_REG(hw, IXGBE_LXOFFTXC); + IXGBE_READ_REG(hw, IXGBE_LXOFFRXC); + + for (i = 0; i < 8; i++) { + IXGBE_READ_REG(hw, IXGBE_PXONTXC(i)); + IXGBE_READ_REG(hw, IXGBE_PXONRXC(i)); + IXGBE_READ_REG(hw, IXGBE_PXOFFTXC(i)); + IXGBE_READ_REG(hw, IXGBE_PXOFFRXC(i)); + } + + IXGBE_READ_REG(hw, IXGBE_PRC64); + IXGBE_READ_REG(hw, IXGBE_PRC127); + IXGBE_READ_REG(hw, IXGBE_PRC255); + IXGBE_READ_REG(hw, IXGBE_PRC511); + IXGBE_READ_REG(hw, IXGBE_PRC1023); + IXGBE_READ_REG(hw, IXGBE_PRC1522); + IXGBE_READ_REG(hw, IXGBE_GPRC); + IXGBE_READ_REG(hw, IXGBE_BPRC); + IXGBE_READ_REG(hw, IXGBE_MPRC); + IXGBE_READ_REG(hw, IXGBE_GPTC); + IXGBE_READ_REG(hw, IXGBE_GORCL); + IXGBE_READ_REG(hw, IXGBE_GORCH); + IXGBE_READ_REG(hw, IXGBE_GOTCL); + IXGBE_READ_REG(hw, IXGBE_GOTCH); + for (i = 0; i < 8; i++) + IXGBE_READ_REG(hw, IXGBE_RNBC(i)); + IXGBE_READ_REG(hw, IXGBE_RUC); + IXGBE_READ_REG(hw, IXGBE_RFC); + IXGBE_READ_REG(hw, IXGBE_ROC); + IXGBE_READ_REG(hw, IXGBE_RJC); + IXGBE_READ_REG(hw, IXGBE_MNGPRC); + IXGBE_READ_REG(hw, IXGBE_MNGPDC); + IXGBE_READ_REG(hw, IXGBE_MNGPTC); + IXGBE_READ_REG(hw, IXGBE_TORL); + IXGBE_READ_REG(hw, IXGBE_TORH); + IXGBE_READ_REG(hw, IXGBE_TPR); + IXGBE_READ_REG(hw, IXGBE_TPT); + IXGBE_READ_REG(hw, IXGBE_PTC64); + IXGBE_READ_REG(hw, IXGBE_PTC127); + IXGBE_READ_REG(hw, IXGBE_PTC255); + IXGBE_READ_REG(hw, IXGBE_PTC511); + IXGBE_READ_REG(hw, IXGBE_PTC1023); + IXGBE_READ_REG(hw, IXGBE_PTC1522); + IXGBE_READ_REG(hw, IXGBE_MPTC); + IXGBE_READ_REG(hw, IXGBE_BPTC); + for (i = 0; i < 16; i++) { + IXGBE_READ_REG(hw, IXGBE_QPRC(i)); + IXGBE_READ_REG(hw, IXGBE_QBRC(i)); + IXGBE_READ_REG(hw, IXGBE_QPTC(i)); + IXGBE_READ_REG(hw, IXGBE_QBTC(i)); + } + + return 0; +} + +/** + * ixgbe_get_mac_addr - Generic get MAC address + * @hw: pointer to hardware structure + * @mac_addr: Adapter MAC address + * + * Reads the adapter's MAC address from first Receive Address Register (RAR0) + * A reset of the adapter must be performed prior to calling this function + * in order for the MAC address to have been loaded from the EEPROM into RAR0 + **/ +s32 ixgbe_get_mac_addr(struct ixgbe_hw *hw, u8 *mac_addr) +{ + u32 rar_high; + u32 rar_low; + u16 i; + + rar_high = IXGBE_READ_REG(hw, IXGBE_RAH(0)); + rar_low = IXGBE_READ_REG(hw, IXGBE_RAL(0)); + + for (i = 0; i < 4; i++) + mac_addr[i] = (u8)(rar_low >> (i*8)); + + for (i = 0; i < 2; i++) + mac_addr[i+4] = (u8)(rar_high >> (i*8)); + + return 0; +} + +s32 ixgbe_read_part_num(struct ixgbe_hw *hw, u32 *part_num) +{ + s32 ret_val; + u16 data; + + ret_val = ixgbe_read_eeprom(hw, IXGBE_PBANUM0_PTR, &data); + if (ret_val) { + hw_dbg(hw, "NVM Read Error\n"); + return ret_val; + } + *part_num = (u32)(data << 16); + + ret_val = ixgbe_read_eeprom(hw, IXGBE_PBANUM1_PTR, &data); + if (ret_val) { + hw_dbg(hw, "NVM Read Error\n"); + return ret_val; + } + *part_num |= data; + + return 0; +} + +/** + * ixgbe_stop_adapter - Generic stop TX/RX units + * @hw: pointer to hardware structure + * + * Sets the adapter_stopped flag within ixgbe_hw struct. Clears interrupts, + * disables transmit and receive units. The adapter_stopped flag is used by + * the shared code and drivers to determine if the adapter is in a stopped + * state and should not touch the hardware. + **/ +s32 ixgbe_stop_adapter(struct ixgbe_hw *hw) +{ + u32 number_of_queues; + u32 reg_val; + u16 i; + + /* + * Set the adapter_stopped flag so other driver functions stop touching + * the hardware + */ + hw->adapter_stopped = true; + + /* Disable the receive unit */ + reg_val = IXGBE_READ_REG(hw, IXGBE_RXCTRL); + reg_val &= ~(IXGBE_RXCTRL_RXEN); + IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, reg_val); + msleep(2); + + /* Clear interrupt mask to stop from interrupts being generated */ + IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_IRQ_CLEAR_MASK); + + /* Clear any pending interrupts */ + IXGBE_READ_REG(hw, IXGBE_EICR); + + /* Disable the transmit unit. Each queue must be disabled. */ + number_of_queues = hw->mac.num_tx_queues; + for (i = 0; i < number_of_queues; i++) { + reg_val = IXGBE_READ_REG(hw, IXGBE_TXDCTL(i)); + if (reg_val & IXGBE_TXDCTL_ENABLE) { + reg_val &= ~IXGBE_TXDCTL_ENABLE; + IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(i), reg_val); + } + } + + return 0; +} + +/** + * ixgbe_led_on - Turns on the software controllable LEDs. + * @hw: pointer to hardware structure + * @index: led number to turn on + **/ +s32 ixgbe_led_on(struct ixgbe_hw *hw, u32 index) +{ + u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); + + /* To turn on the LED, set mode to ON. */ + led_reg &= ~IXGBE_LED_MODE_MASK(index); + led_reg |= IXGBE_LED_ON << IXGBE_LED_MODE_SHIFT(index); + IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, led_reg); + + return 0; +} + +/** + * ixgbe_led_off - Turns off the software controllable LEDs. + * @hw: pointer to hardware structure + * @index: led number to turn off + **/ +s32 ixgbe_led_off(struct ixgbe_hw *hw, u32 index) +{ + u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); + + /* To turn off the LED, set mode to OFF. */ + led_reg &= ~IXGBE_LED_MODE_MASK(index); + led_reg |= IXGBE_LED_OFF << IXGBE_LED_MODE_SHIFT(index); + IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, led_reg); + + return 0; +} + + +/** + * ixgbe_init_eeprom - Initialize EEPROM params + * @hw: pointer to hardware structure + * + * Initializes the EEPROM parameters ixgbe_eeprom_info within the + * ixgbe_hw struct in order to set up EEPROM access. + **/ +s32 ixgbe_init_eeprom(struct ixgbe_hw *hw) +{ + struct ixgbe_eeprom_info *eeprom = &hw->eeprom; + u32 eec; + u16 eeprom_size; + + if (eeprom->type == ixgbe_eeprom_uninitialized) { + eeprom->type = ixgbe_eeprom_none; + + /* + * Check for EEPROM present first. + * If not present leave as none + */ + eec = IXGBE_READ_REG(hw, IXGBE_EEC); + if (eec & IXGBE_EEC_PRES) { + eeprom->type = ixgbe_eeprom_spi; + + /* + * SPI EEPROM is assumed here. This code would need to + * change if a future EEPROM is not SPI. + */ + eeprom_size = (u16)((eec & IXGBE_EEC_SIZE) >> + IXGBE_EEC_SIZE_SHIFT); + eeprom->word_size = 1 << (eeprom_size + + IXGBE_EEPROM_WORD_SIZE_SHIFT); + } + + if (eec & IXGBE_EEC_ADDR_SIZE) + eeprom->address_bits = 16; + else + eeprom->address_bits = 8; + hw_dbg(hw, "Eeprom params: type = %d, size = %d, address bits: " + "%d\n", eeprom->type, eeprom->word_size, + eeprom->address_bits); + } + + return 0; +} + +/** + * ixgbe_read_eeprom - Read EEPROM word using EERD + * @hw: pointer to hardware structure + * @offset: offset of word in the EEPROM to read + * @data: word read from the EEPROM + * + * Reads a 16 bit word from the EEPROM using the EERD register. + **/ +s32 ixgbe_read_eeprom(struct ixgbe_hw *hw, u16 offset, u16 *data) +{ + u32 eerd; + s32 status; + + eerd = (offset << IXGBE_EEPROM_READ_ADDR_SHIFT) + + IXGBE_EEPROM_READ_REG_START; + + IXGBE_WRITE_REG(hw, IXGBE_EERD, eerd); + status = ixgbe_poll_eeprom_eerd_done(hw); + + if (status == 0) + *data = (IXGBE_READ_REG(hw, IXGBE_EERD) >> + IXGBE_EEPROM_READ_REG_DATA); + else + hw_dbg(hw, "Eeprom read timed out\n"); + + return status; +} + +/** + * ixgbe_poll_eeprom_eerd_done - Poll EERD status + * @hw: pointer to hardware structure + * + * Polls the status bit (bit 1) of the EERD to determine when the read is done. + **/ +static s32 ixgbe_poll_eeprom_eerd_done(struct ixgbe_hw *hw) +{ + u32 i; + u32 reg; + s32 status = IXGBE_ERR_EEPROM; + + for (i = 0; i < IXGBE_EERD_ATTEMPTS; i++) { + reg = IXGBE_READ_REG(hw, IXGBE_EERD); + if (reg & IXGBE_EEPROM_READ_REG_DONE) { + status = 0; + break; + } + udelay(5); + } + return status; +} + +/** + * ixgbe_get_eeprom_semaphore - Get hardware semaphore + * @hw: pointer to hardware structure + * + * Sets the hardware semaphores so EEPROM access can occur for bit-bang method + **/ +static s32 ixgbe_get_eeprom_semaphore(struct ixgbe_hw *hw) +{ + s32 status = IXGBE_ERR_EEPROM; + u32 timeout; + u32 i; + u32 swsm; + + /* Set timeout value based on size of EEPROM */ + timeout = hw->eeprom.word_size + 1; + + /* Get SMBI software semaphore between device drivers first */ + for (i = 0; i < timeout; i++) { + /* + * If the SMBI bit is 0 when we read it, then the bit will be + * set and we have the semaphore + */ + swsm = IXGBE_READ_REG(hw, IXGBE_SWSM); + if (!(swsm & IXGBE_SWSM_SMBI)) { + status = 0; + break; + } + msleep(1); + } + + /* Now get the semaphore between SW/FW through the SWESMBI bit */ + if (status == 0) { + for (i = 0; i < timeout; i++) { + swsm = IXGBE_READ_REG(hw, IXGBE_SWSM); + + /* Set the SW EEPROM semaphore bit to request access */ + swsm |= IXGBE_SWSM_SWESMBI; + IXGBE_WRITE_REG(hw, IXGBE_SWSM, swsm); + + /* + * If we set the bit successfully then we got the + * semaphore. + */ + swsm = IXGBE_READ_REG(hw, IXGBE_SWSM); + if (swsm & IXGBE_SWSM_SWESMBI) + break; + + udelay(50); + } + + /* + * Release semaphores and return error if SW EEPROM semaphore + * was not granted because we don't have access to the EEPROM + */ + if (i >= timeout) { + hw_dbg(hw, "Driver can't access the Eeprom - Semaphore " + "not granted.\n"); + ixgbe_release_eeprom_semaphore(hw); + status = IXGBE_ERR_EEPROM; + } + } + + return status; +} + +/** + * ixgbe_release_eeprom_semaphore - Release hardware semaphore + * @hw: pointer to hardware structure + * + * This function clears hardware semaphore bits. + **/ +static void ixgbe_release_eeprom_semaphore(struct ixgbe_hw *hw) +{ + u32 swsm; + + swsm = IXGBE_READ_REG(hw, IXGBE_SWSM); + + /* Release both semaphores by writing 0 to the bits SWESMBI and SMBI */ + swsm &= ~(IXGBE_SWSM_SWESMBI | IXGBE_SWSM_SMBI); + IXGBE_WRITE_REG(hw, IXGBE_SWSM, swsm); +} + +/** + * ixgbe_calc_eeprom_checksum - Calculates and returns the checksum + * @hw: pointer to hardware structure + **/ +static u16 ixgbe_calc_eeprom_checksum(struct ixgbe_hw *hw) +{ + u16 i; + u16 j; + u16 checksum = 0; + u16 length = 0; + u16 pointer = 0; + u16 word = 0; + + /* Include 0x0-0x3F in the checksum */ + for (i = 0; i < IXGBE_EEPROM_CHECKSUM; i++) { + if (ixgbe_read_eeprom(hw, i, &word) != 0) { + hw_dbg(hw, "EEPROM read failed\n"); + break; + } + checksum += word; + } + + /* Include all data from pointers except for the fw pointer */ + for (i = IXGBE_PCIE_ANALOG_PTR; i < IXGBE_FW_PTR; i++) { + ixgbe_read_eeprom(hw, i, &pointer); + + /* Make sure the pointer seems valid */ + if (pointer != 0xFFFF && pointer != 0) { + ixgbe_read_eeprom(hw, pointer, &length); + + if (length != 0xFFFF && length != 0) { + for (j = pointer+1; j <= pointer+length; j++) { + ixgbe_read_eeprom(hw, j, &word); + checksum += word; + } + } + } + } + + checksum = (u16)IXGBE_EEPROM_SUM - checksum; + + return checksum; +} + +/** + * ixgbe_validate_eeprom_checksum - Validate EEPROM checksum + * @hw: pointer to hardware structure + * @checksum_val: calculated checksum + * + * Performs checksum calculation and validates the EEPROM checksum. If the + * caller does not need checksum_val, the value can be NULL. + **/ +s32 ixgbe_validate_eeprom_checksum(struct ixgbe_hw *hw, u16 *checksum_val) +{ + s32 status; + u16 checksum; + u16 read_checksum = 0; + + /* + * Read the first word from the EEPROM. If this times out or fails, do + * not continue or we could be in for a very long wait while every + * EEPROM read fails + */ + status = ixgbe_read_eeprom(hw, 0, &checksum); + + if (status == 0) { + checksum = ixgbe_calc_eeprom_checksum(hw); + + ixgbe_read_eeprom(hw, IXGBE_EEPROM_CHECKSUM, &read_checksum); + + /* + * Verify read checksum from EEPROM is the same as + * calculated checksum + */ + if (read_checksum != checksum) + status = IXGBE_ERR_EEPROM_CHECKSUM; + + /* If the user cares, return the calculated checksum */ + if (checksum_val) + *checksum_val = checksum; + } else { + hw_dbg(hw, "EEPROM read failed\n"); + } + + return status; +} + +/** + * ixgbe_validate_mac_addr - Validate MAC address + * @mac_addr: pointer to MAC address. + * + * Tests a MAC address to ensure it is a valid Individual Address + **/ +s32 ixgbe_validate_mac_addr(u8 *mac_addr) +{ + s32 status = 0; + + /* Make sure it is not a multicast address */ + if (IXGBE_IS_MULTICAST(mac_addr)) + status = IXGBE_ERR_INVALID_MAC_ADDR; + /* Not a broadcast address */ + else if (IXGBE_IS_BROADCAST(mac_addr)) + status = IXGBE_ERR_INVALID_MAC_ADDR; + /* Reject the zero address */ + else if (mac_addr[0] == 0 && mac_addr[1] == 0 && mac_addr[2] == 0 && + mac_addr[3] == 0 && mac_addr[4] == 0 && mac_addr[5] == 0) + status = IXGBE_ERR_INVALID_MAC_ADDR; + + return status; +} + +/** + * ixgbe_set_rar - Set RX address register + * @hw: pointer to hardware structure + * @addr: Address to put into receive address register + * @index: Receive address register to write + * @vind: Vind to set RAR to + * @enable_addr: set flag that address is active + * + * Puts an ethernet address into a receive address register. + **/ +s32 ixgbe_set_rar(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vind, + u32 enable_addr) +{ + u32 rar_low, rar_high; + + /* + * HW expects these in little endian so we reverse the byte order from + * network order (big endian) to little endian + */ + rar_low = ((u32)addr[0] | + ((u32)addr[1] << 8) | + ((u32)addr[2] << 16) | + ((u32)addr[3] << 24)); + + rar_high = ((u32)addr[4] | + ((u32)addr[5] << 8) | + ((vind << IXGBE_RAH_VIND_SHIFT) & IXGBE_RAH_VIND_MASK)); + + if (enable_addr != 0) + rar_high |= IXGBE_RAH_AV; + + IXGBE_WRITE_REG(hw, IXGBE_RAL(index), rar_low); + IXGBE_WRITE_REG(hw, IXGBE_RAH(index), rar_high); + + return 0; +} + +/** + * ixgbe_init_rx_addrs - Initializes receive address filters. + * @hw: pointer to hardware structure + * + * Places the MAC address in receive address register 0 and clears the rest + * of the receive addresss registers. Clears the multicast table. Assumes + * the receiver is in reset when the routine is called. + **/ +static s32 ixgbe_init_rx_addrs(struct ixgbe_hw *hw) +{ + u32 i; + u32 rar_entries = hw->mac.num_rx_addrs; + + /* + * If the current mac address is valid, assume it is a software override + * to the permanent address. + * Otherwise, use the permanent address from the eeprom. + */ + if (ixgbe_validate_mac_addr(hw->mac.addr) == + IXGBE_ERR_INVALID_MAC_ADDR) { + /* Get the MAC address from the RAR0 for later reference */ + ixgbe_get_mac_addr(hw, hw->mac.addr); + + hw_dbg(hw, " Keeping Current RAR0 Addr =%.2X %.2X %.2X ", + hw->mac.addr[0], hw->mac.addr[1], + hw->mac.addr[2]); + hw_dbg(hw, "%.2X %.2X %.2X\n", hw->mac.addr[3], + hw->mac.addr[4], hw->mac.addr[5]); + } else { + /* Setup the receive address. */ + hw_dbg(hw, "Overriding MAC Address in RAR[0]\n"); + hw_dbg(hw, " New MAC Addr =%.2X %.2X %.2X ", + hw->mac.addr[0], hw->mac.addr[1], + hw->mac.addr[2]); + hw_dbg(hw, "%.2X %.2X %.2X\n", hw->mac.addr[3], + hw->mac.addr[4], hw->mac.addr[5]); + + ixgbe_set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV); + } + + hw->addr_ctrl.rar_used_count = 1; + + /* Zero out the other receive addresses. */ + hw_dbg(hw, "Clearing RAR[1-15]\n"); + for (i = 1; i < rar_entries; i++) { + IXGBE_WRITE_REG(hw, IXGBE_RAL(i), 0); + IXGBE_WRITE_REG(hw, IXGBE_RAH(i), 0); + } + + /* Clear the MTA */ + hw->addr_ctrl.mc_addr_in_rar_count = 0; + hw->addr_ctrl.mta_in_use = 0; + IXGBE_WRITE_REG(hw, IXGBE_MCSTCTRL, hw->mac.mc_filter_type); + + hw_dbg(hw, " Clearing MTA\n"); + for (i = 0; i < IXGBE_MC_TBL_SIZE; i++) + IXGBE_WRITE_REG(hw, IXGBE_MTA(i), 0); + + return 0; +} + +/** + * ixgbe_mta_vector - Determines bit-vector in multicast table to set + * @hw: pointer to hardware structure + * @mc_addr: the multicast address + * + * Extracts the 12 bits, from a multicast address, to determine which + * bit-vector to set in the multicast table. The hardware uses 12 bits, from + * incoming rx multicast addresses, to determine the bit-vector to check in + * the MTA. Which of the 4 combination, of 12-bits, the hardware uses is set + * by the MO field of the MCSTCTRL. The MO field is set during initalization + * to mc_filter_type. + **/ +static s32 ixgbe_mta_vector(struct ixgbe_hw *hw, u8 *mc_addr) +{ + u32 vector = 0; + + switch (hw->mac.mc_filter_type) { + case 0: /* use bits [47:36] of the address */ + vector = ((mc_addr[4] >> 4) | (((u16)mc_addr[5]) << 4)); + break; + case 1: /* use bits [46:35] of the address */ + vector = ((mc_addr[4] >> 3) | (((u16)mc_addr[5]) << 5)); + break; + case 2: /* use bits [45:34] of the address */ + vector = ((mc_addr[4] >> 2) | (((u16)mc_addr[5]) << 6)); + break; + case 3: /* use bits [43:32] of the address */ + vector = ((mc_addr[4]) | (((u16)mc_addr[5]) << 8)); + break; + default: /* Invalid mc_filter_type */ + hw_dbg(hw, "MC filter type param set incorrectly\n"); + break; + } + + /* vector can only be 12-bits or boundary will be exceeded */ + vector &= 0xFFF; + return vector; +} + +/** + * ixgbe_set_mta - Set bit-vector in multicast table + * @hw: pointer to hardware structure + * @hash_value: Multicast address hash value + * + * Sets the bit-vector in the multicast table. + **/ +static void ixgbe_set_mta(struct ixgbe_hw *hw, u8 *mc_addr) +{ + u32 vector; + u32 vector_bit; + u32 vector_reg; + u32 mta_reg; + + hw->addr_ctrl.mta_in_use++; + + vector = ixgbe_mta_vector(hw, mc_addr); + hw_dbg(hw, " bit-vector = 0x%03X\n", vector); + + /* + * The MTA is a register array of 128 32-bit registers. It is treated + * like an array of 4096 bits. We want to set bit + * BitArray[vector_value]. So we figure out what register the bit is + * in, read it, OR in the new bit, then write back the new value. The + * register is determined by the upper 7 bits of the vector value and + * the bit within that register are determined by the lower 5 bits of + * the value. + */ + vector_reg = (vector >> 5) & 0x7F; + vector_bit = vector & 0x1F; + mta_reg = IXGBE_READ_REG(hw, IXGBE_MTA(vector_reg)); + mta_reg |= (1 << vector_bit); + IXGBE_WRITE_REG(hw, IXGBE_MTA(vector_reg), mta_reg); +} + +/** + * ixgbe_add_mc_addr - Adds a multicast address. + * @hw: pointer to hardware structure + * @mc_addr: new multicast address + * + * Adds it to unused receive address register or to the multicast table. + **/ +static void ixgbe_add_mc_addr(struct ixgbe_hw *hw, u8 *mc_addr) +{ + u32 rar_entries = hw->mac.num_rx_addrs; + + hw_dbg(hw, " MC Addr =%.2X %.2X %.2X %.2X %.2X %.2X\n", + mc_addr[0], mc_addr[1], mc_addr[2], + mc_addr[3], mc_addr[4], mc_addr[5]); + + /* + * Place this multicast address in the RAR if there is room, + * else put it in the MTA + */ + if (hw->addr_ctrl.rar_used_count < rar_entries) { + ixgbe_set_rar(hw, hw->addr_ctrl.rar_used_count, + mc_addr, 0, IXGBE_RAH_AV); + hw_dbg(hw, "Added a multicast address to RAR[%d]\n", + hw->addr_ctrl.rar_used_count); + hw->addr_ctrl.rar_used_count++; + hw->addr_ctrl.mc_addr_in_rar_count++; + } else { + ixgbe_set_mta(hw, mc_addr); + } + + hw_dbg(hw, "ixgbe_add_mc_addr Complete\n"); +} + +/** + * ixgbe_update_mc_addr_list - Updates MAC list of multicast addresses + * @hw: pointer to hardware structure + * @mc_addr_list: the list of new multicast addresses + * @mc_addr_count: number of addresses + * @pad: number of bytes between addresses in the list + * + * The given list replaces any existing list. Clears the MC addrs from receive + * address registers and the multicast table. Uses unsed receive address + * registers for the first multicast addresses, and hashes the rest into the + * multicast table. + **/ +s32 ixgbe_update_mc_addr_list(struct ixgbe_hw *hw, u8 *mc_addr_list, + u32 mc_addr_count, u32 pad) +{ + u32 i; + u32 rar_entries = hw->mac.num_rx_addrs; + + /* + * Set the new number of MC addresses that we are being requested to + * use. + */ + hw->addr_ctrl.num_mc_addrs = mc_addr_count; + hw->addr_ctrl.rar_used_count -= hw->addr_ctrl.mc_addr_in_rar_count; + hw->addr_ctrl.mc_addr_in_rar_count = 0; + hw->addr_ctrl.mta_in_use = 0; + + /* Zero out the other receive addresses. */ + hw_dbg(hw, "Clearing RAR[1-15]\n"); + for (i = hw->addr_ctrl.rar_used_count; i < rar_entries; i++) { + IXGBE_WRITE_REG(hw, IXGBE_RAL(i), 0); + IXGBE_WRITE_REG(hw, IXGBE_RAH(i), 0); + } + + /* Clear the MTA */ + hw_dbg(hw, " Clearing MTA\n"); + for (i = 0; i < IXGBE_MC_TBL_SIZE; i++) + IXGBE_WRITE_REG(hw, IXGBE_MTA(i), 0); + + /* Add the new addresses */ + for (i = 0; i < mc_addr_count; i++) { + hw_dbg(hw, " Adding the multicast addresses:\n"); + ixgbe_add_mc_addr(hw, mc_addr_list + + (i * (IXGBE_ETH_LENGTH_OF_ADDRESS + pad))); + } + + /* Enable mta */ + if (hw->addr_ctrl.mta_in_use > 0) + IXGBE_WRITE_REG(hw, IXGBE_MCSTCTRL, + IXGBE_MCSTCTRL_MFE | hw->mac.mc_filter_type); + + hw_dbg(hw, "ixgbe_update_mc_addr_list Complete\n"); + return 0; +} + +/** + * ixgbe_clear_vfta - Clear VLAN filter table + * @hw: pointer to hardware structure + * + * Clears the VLAN filer table, and the VMDq index associated with the filter + **/ +static s32 ixgbe_clear_vfta(struct ixgbe_hw *hw) +{ + u32 offset; + u32 vlanbyte; + + for (offset = 0; offset < IXGBE_VLAN_FILTER_TBL_SIZE; offset++) + IXGBE_WRITE_REG(hw, IXGBE_VFTA(offset), 0); + + for (vlanbyte = 0; vlanbyte < 4; vlanbyte++) + for (offset = 0; offset < IXGBE_VLAN_FILTER_TBL_SIZE; offset++) + IXGBE_WRITE_REG(hw, IXGBE_VFTAVIND(vlanbyte, offset), + 0); + + return 0; +} + +/** + * ixgbe_set_vfta - Set VLAN filter table + * @hw: pointer to hardware structure + * @vlan: VLAN id to write to VLAN filter + * @vind: VMDq output index that maps queue to VLAN id in VFTA + * @vlan_on: boolean flag to turn on/off VLAN in VFTA + * + * Turn on/off specified VLAN in the VLAN filter table. + **/ +s32 ixgbe_set_vfta(struct ixgbe_hw *hw, u32 vlan, u32 vind, + bool vlan_on) +{ + u32 VftaIndex; + u32 BitOffset; + u32 VftaReg; + u32 VftaByte; + + /* Determine 32-bit word position in array */ + VftaIndex = (vlan >> 5) & 0x7F; /* upper seven bits */ + + /* Determine the location of the (VMD) queue index */ + VftaByte = ((vlan >> 3) & 0x03); /* bits (4:3) indicating byte array */ + BitOffset = (vlan & 0x7) << 2; /* lower 3 bits indicate nibble */ + + /* Set the nibble for VMD queue index */ + VftaReg = IXGBE_READ_REG(hw, IXGBE_VFTAVIND(VftaByte, VftaIndex)); + VftaReg &= (~(0x0F << BitOffset)); + VftaReg |= (vind << BitOffset); + IXGBE_WRITE_REG(hw, IXGBE_VFTAVIND(VftaByte, VftaIndex), VftaReg); + + /* Determine the location of the bit for this VLAN id */ + BitOffset = vlan & 0x1F; /* lower five bits */ + + VftaReg = IXGBE_READ_REG(hw, IXGBE_VFTA(VftaIndex)); + if (vlan_on) + /* Turn on this VLAN id */ + VftaReg |= (1 << BitOffset); + else + /* Turn off this VLAN id */ + VftaReg &= ~(1 << BitOffset); + IXGBE_WRITE_REG(hw, IXGBE_VFTA(VftaIndex), VftaReg); + + return 0; +} + +/** + * ixgbe_setup_fc - Configure flow control settings + * @hw: pointer to hardware structure + * @packetbuf_num: packet buffer number (0-7) + * + * Configures the flow control settings based on SW configuration. + * This function is used for 802.3x flow control configuration only. + **/ +s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packetbuf_num) +{ + u32 frctl_reg; + u32 rmcs_reg; + + if (packetbuf_num < 0 || packetbuf_num > 7) + hw_dbg(hw, "Invalid packet buffer number [%d], expected range" + "is 0-7\n", packetbuf_num); + + frctl_reg = IXGBE_READ_REG(hw, IXGBE_FCTRL); + frctl_reg &= ~(IXGBE_FCTRL_RFCE | IXGBE_FCTRL_RPFCE); + + rmcs_reg = IXGBE_READ_REG(hw, IXGBE_RMCS); + rmcs_reg &= ~(IXGBE_RMCS_TFCE_PRIORITY | IXGBE_RMCS_TFCE_802_3X); + + /* + * We want to save off the original Flow Control configuration just in + * case we get disconnected and then reconnected into a different hub + * or switch with different Flow Control capabilities. + */ + hw->fc.type = hw->fc.original_type; + + /* + * The possible values of the "flow_control" parameter are: + * 0: Flow control is completely disabled + * 1: Rx flow control is enabled (we can receive pause frames but not + * send pause frames). + * 2: Tx flow control is enabled (we can send pause frames but we do not + * support receiving pause frames) + * 3: Both Rx and TX flow control (symmetric) are enabled. + * other: Invalid. + */ + switch (hw->fc.type) { + case ixgbe_fc_none: + break; + case ixgbe_fc_rx_pause: + /* + * RX Flow control is enabled, + * and TX Flow control is disabled. + */ + frctl_reg |= IXGBE_FCTRL_RFCE; + break; + case ixgbe_fc_tx_pause: + /* + * TX Flow control is enabled, and RX Flow control is disabled, + * by a software over-ride. + */ + rmcs_reg |= IXGBE_RMCS_TFCE_802_3X; + break; + case ixgbe_fc_full: + /* + * Flow control (both RX and TX) is enabled by a software + * over-ride. + */ + frctl_reg |= IXGBE_FCTRL_RFCE; + rmcs_reg |= IXGBE_RMCS_TFCE_802_3X; + break; + default: + /* We should never get here. The value should be 0-3. */ + hw_dbg(hw, "Flow control param set incorrectly\n"); + break; + } + + /* Enable 802.3x based flow control settings. */ + IXGBE_WRITE_REG(hw, IXGBE_FCTRL, frctl_reg); + IXGBE_WRITE_REG(hw, IXGBE_RMCS, rmcs_reg); + + /* + * We need to set up the Receive Threshold high and low water + * marks as well as (optionally) enabling the transmission of + * XON frames. + */ + if (hw->fc.type & ixgbe_fc_tx_pause) { + if (hw->fc.send_xon) { + IXGBE_WRITE_REG(hw, IXGBE_FCRTL(packetbuf_num), + (hw->fc.low_water | IXGBE_FCRTL_XONE)); + } else { + IXGBE_WRITE_REG(hw, IXGBE_FCRTL(packetbuf_num), + hw->fc.low_water); + } + IXGBE_WRITE_REG(hw, IXGBE_FCRTH(packetbuf_num), + (hw->fc.high_water)|IXGBE_FCRTH_FCEN); + } + + IXGBE_WRITE_REG(hw, IXGBE_FCTTV(0), hw->fc.pause_time); + IXGBE_WRITE_REG(hw, IXGBE_FCRTV, (hw->fc.pause_time >> 1)); + + return 0; +} + +/** + * ixgbe_disable_pcie_master - Disable PCI-express master access + * @hw: pointer to hardware structure + * + * Disables PCI-Express master access and verifies there are no pending + * requests. IXGBE_ERR_MASTER_REQUESTS_PENDING is returned if master disable + * bit hasn't caused the master requests to be disabled, else 0 + * is returned signifying master requests disabled. + **/ +s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw) +{ + u32 ctrl; + s32 i; + s32 status = IXGBE_ERR_MASTER_REQUESTS_PENDING; + + ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL); + ctrl |= IXGBE_CTRL_GIO_DIS; + IXGBE_WRITE_REG(hw, IXGBE_CTRL, ctrl); + + for (i = 0; i < IXGBE_PCI_MASTER_DISABLE_TIMEOUT; i++) { + if (!(IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_GIO)) { + status = 0; + break; + } + udelay(100); + } + + return status; +} + + +/** + * ixgbe_acquire_swfw_sync - Aquire SWFW semaphore + * @hw: pointer to hardware structure + * @mask: Mask to specify wich semaphore to acquire + * + * Aquires the SWFW semaphore throught the GSSR register for the specified + * function (CSR, PHY0, PHY1, EEPROM, Flash) + **/ +s32 ixgbe_acquire_swfw_sync(struct ixgbe_hw *hw, u16 mask) +{ + u32 gssr; + u32 swmask = mask; + u32 fwmask = mask << 5; + s32 timeout = 200; + + while (timeout) { + if (ixgbe_get_eeprom_semaphore(hw)) + return -IXGBE_ERR_SWFW_SYNC; + + gssr = IXGBE_READ_REG(hw, IXGBE_GSSR); + if (!(gssr & (fwmask | swmask))) + break; + + /* + * Firmware currently using resource (fwmask) or other software + * thread currently using resource (swmask) + */ + ixgbe_release_eeprom_semaphore(hw); + msleep(5); + timeout--; + } + + if (!timeout) { + hw_dbg(hw, "Driver can't access resource, GSSR timeout.\n"); + return -IXGBE_ERR_SWFW_SYNC; + } + + gssr |= swmask; + IXGBE_WRITE_REG(hw, IXGBE_GSSR, gssr); + + ixgbe_release_eeprom_semaphore(hw); + return 0; +} + +/** + * ixgbe_release_swfw_sync - Release SWFW semaphore + * @hw: pointer to hardware structure + * @mask: Mask to specify wich semaphore to release + * + * Releases the SWFW semaphore throught the GSSR register for the specified + * function (CSR, PHY0, PHY1, EEPROM, Flash) + **/ +void ixgbe_release_swfw_sync(struct ixgbe_hw *hw, u16 mask) +{ + u32 gssr; + u32 swmask = mask; + + ixgbe_get_eeprom_semaphore(hw); + + gssr = IXGBE_READ_REG(hw, IXGBE_GSSR); + gssr &= ~swmask; + IXGBE_WRITE_REG(hw, IXGBE_GSSR, gssr); + + ixgbe_release_eeprom_semaphore(hw); +} + +/** + * ixgbe_read_analog_reg8- Reads 8 bit 82598 Atlas analog register + * @hw: pointer to hardware structure + * @reg: analog register to read + * @val: read value + * + * Performs write operation to analog register specified. + **/ +s32 ixgbe_read_analog_reg8(struct ixgbe_hw *hw, u32 reg, u8 *val) +{ + u32 atlas_ctl; + + IXGBE_WRITE_REG(hw, IXGBE_ATLASCTL, + IXGBE_ATLASCTL_WRITE_CMD | (reg << 8)); + IXGBE_WRITE_FLUSH(hw); + udelay(10); + atlas_ctl = IXGBE_READ_REG(hw, IXGBE_ATLASCTL); + *val = (u8)atlas_ctl; + + return 0; +} + +/** + * ixgbe_write_analog_reg8- Writes 8 bit Atlas analog register + * @hw: pointer to hardware structure + * @reg: atlas register to write + * @val: value to write + * + * Performs write operation to Atlas analog register specified. + **/ +s32 ixgbe_write_analog_reg8(struct ixgbe_hw *hw, u32 reg, u8 val) +{ + u32 atlas_ctl; + + atlas_ctl = (reg << 8) | val; + IXGBE_WRITE_REG(hw, IXGBE_ATLASCTL, atlas_ctl); + IXGBE_WRITE_FLUSH(hw); + udelay(10); + + return 0; +} + diff --git a/drivers/net/ixgbe/ixgbe_common.h b/drivers/net/ixgbe/ixgbe_common.h new file mode 100644 index 00000000000..de6ddd5d04a --- /dev/null +++ b/drivers/net/ixgbe/ixgbe_common.h @@ -0,0 +1,86 @@ +/******************************************************************************* + + Intel 10 Gigabit PCI Express Linux driver + Copyright(c) 1999 - 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#ifndef _IXGBE_COMMON_H_ +#define _IXGBE_COMMON_H_ + +#include "ixgbe_type.h" + +s32 ixgbe_init_hw(struct ixgbe_hw *hw); +s32 ixgbe_start_hw(struct ixgbe_hw *hw); +s32 ixgbe_get_mac_addr(struct ixgbe_hw *hw, u8 *mac_addr); +s32 ixgbe_stop_adapter(struct ixgbe_hw *hw); +s32 ixgbe_read_part_num(struct ixgbe_hw *hw, u32 *part_num); + +s32 ixgbe_led_on(struct ixgbe_hw *hw, u32 index); +s32 ixgbe_led_off(struct ixgbe_hw *hw, u32 index); + +s32 ixgbe_init_eeprom(struct ixgbe_hw *hw); +s32 ixgbe_read_eeprom(struct ixgbe_hw *hw, u16 offset, u16 *data); +s32 ixgbe_validate_eeprom_checksum(struct ixgbe_hw *hw, u16 *checksum_val); + +s32 ixgbe_set_rar(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vind, + u32 enable_addr); +s32 ixgbe_update_mc_addr_list(struct ixgbe_hw *hw, u8 *mc_addr_list, + u32 mc_addr_count, u32 pad); +s32 ixgbe_set_vfta(struct ixgbe_hw *hw, u32 vlan, u32 vind, bool vlan_on); +s32 ixgbe_validate_mac_addr(u8 *mac_addr); + +s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packtetbuf_num); + +s32 ixgbe_acquire_swfw_sync(struct ixgbe_hw *hw, u16 mask); +void ixgbe_release_swfw_sync(struct ixgbe_hw *hw, u16 mask); +s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw); + +s32 ixgbe_read_analog_reg8(struct ixgbe_hw *hw, u32 reg, u8 *val); +s32 ixgbe_write_analog_reg8(struct ixgbe_hw *hw, u32 reg, u8 val); + +#define IXGBE_WRITE_REG(a, reg, value) writel((value), ((a)->hw_addr + (reg))) + +#define IXGBE_READ_REG(a, reg) readl((a)->hw_addr + (reg)) + +#define IXGBE_WRITE_REG_ARRAY(a, reg, offset, value) (\ + writel((value), ((a)->hw_addr + (reg) + ((offset) << 2)))) + +#define IXGBE_READ_REG_ARRAY(a, reg, offset) (\ + readl((a)->hw_addr + (reg) + ((offset) << 2))) + +#define IXGBE_WRITE_FLUSH(a) IXGBE_READ_REG(a, IXGBE_STATUS) + +#ifdef DEBUG +#define hw_dbg(hw, format, arg...) \ +printk(KERN_DEBUG, "%s: " format, ixgbe_get_hw_dev_name(hw), ##arg); +#else +static inline int __attribute__ ((format (printf, 2, 3))) +hw_dbg(struct ixgbe_hw *hw, const char *format, ...) +{ + return 0; +} +#endif + +#endif /* IXGBE_COMMON */ diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c new file mode 100644 index 00000000000..43a2a46e287 --- /dev/null +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -0,0 +1,943 @@ +/******************************************************************************* + + Intel 10 Gigabit PCI Express Linux driver + Copyright(c) 1999 - 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +/* ethtool support for ixgbe */ + +#include +#include +#include +#include +#include +#include +#include + +#include "ixgbe.h" + + +#define IXGBE_ALL_RAR_ENTRIES 16 + +struct ixgbe_stats { + char stat_string[ETH_GSTRING_LEN]; + int sizeof_stat; + int stat_offset; +}; + +#define IXGBE_STAT(m) sizeof(((struct ixgbe_adapter *)0)->m), \ + offsetof(struct ixgbe_adapter, m) +static struct ixgbe_stats ixgbe_gstrings_stats[] = { + {"rx_packets", IXGBE_STAT(net_stats.rx_packets)}, + {"tx_packets", IXGBE_STAT(net_stats.tx_packets)}, + {"rx_bytes", IXGBE_STAT(net_stats.rx_bytes)}, + {"tx_bytes", IXGBE_STAT(net_stats.tx_bytes)}, + {"lsc_int", IXGBE_STAT(lsc_int)}, + {"tx_busy", IXGBE_STAT(tx_busy)}, + {"non_eop_descs", IXGBE_STAT(non_eop_descs)}, + {"rx_errors", IXGBE_STAT(net_stats.rx_errors)}, + {"tx_errors", IXGBE_STAT(net_stats.tx_errors)}, + {"rx_dropped", IXGBE_STAT(net_stats.rx_dropped)}, + {"tx_dropped", IXGBE_STAT(net_stats.tx_dropped)}, + {"multicast", IXGBE_STAT(net_stats.multicast)}, + {"broadcast", IXGBE_STAT(stats.bprc)}, + {"rx_no_buffer_count", IXGBE_STAT(stats.rnbc[0]) }, + {"collisions", IXGBE_STAT(net_stats.collisions)}, + {"rx_over_errors", IXGBE_STAT(net_stats.rx_over_errors)}, + {"rx_crc_errors", IXGBE_STAT(net_stats.rx_crc_errors)}, + {"rx_frame_errors", IXGBE_STAT(net_stats.rx_frame_errors)}, + {"rx_fifo_errors", IXGBE_STAT(net_stats.rx_fifo_errors)}, + {"rx_missed_errors", IXGBE_STAT(net_stats.rx_missed_errors)}, + {"tx_aborted_errors", IXGBE_STAT(net_stats.tx_aborted_errors)}, + {"tx_carrier_errors", IXGBE_STAT(net_stats.tx_carrier_errors)}, + {"tx_fifo_errors", IXGBE_STAT(net_stats.tx_fifo_errors)}, + {"tx_heartbeat_errors", IXGBE_STAT(net_stats.tx_heartbeat_errors)}, + {"tx_timeout_count", IXGBE_STAT(tx_timeout_count)}, + {"tx_restart_queue", IXGBE_STAT(restart_queue)}, + {"rx_long_length_errors", IXGBE_STAT(stats.roc)}, + {"rx_short_length_errors", IXGBE_STAT(stats.ruc)}, + {"tx_tcp4_seg_ctxt", IXGBE_STAT(hw_tso_ctxt)}, + {"tx_tcp6_seg_ctxt", IXGBE_STAT(hw_tso6_ctxt)}, + {"tx_flow_control_xon", IXGBE_STAT(stats.lxontxc)}, + {"rx_flow_control_xon", IXGBE_STAT(stats.lxonrxc)}, + {"tx_flow_control_xoff", IXGBE_STAT(stats.lxofftxc)}, + {"rx_flow_control_xoff", IXGBE_STAT(stats.lxoffrxc)}, + {"rx_csum_offload_good", IXGBE_STAT(hw_csum_rx_good)}, + {"rx_csum_offload_errors", IXGBE_STAT(hw_csum_rx_error)}, + {"tx_csum_offload_ctxt", IXGBE_STAT(hw_csum_tx_good)}, + {"rx_header_split", IXGBE_STAT(rx_hdr_split)}, + {"alloc_rx_page_failed", IXGBE_STAT(alloc_rx_page_failed)}, + {"alloc_rx_buff_failed", IXGBE_STAT(alloc_rx_buff_failed)}, +}; + +#define IXGBE_QUEUE_STATS_LEN \ + ((((struct ixgbe_adapter *)netdev->priv)->num_tx_queues + \ + ((struct ixgbe_adapter *)netdev->priv)->num_rx_queues) * \ + (sizeof(struct ixgbe_queue_stats) / sizeof(u64))) +#define IXGBE_GLOBAL_STATS_LEN \ + sizeof(ixgbe_gstrings_stats) / sizeof(struct ixgbe_stats) +#define IXGBE_STATS_LEN (IXGBE_GLOBAL_STATS_LEN + IXGBE_QUEUE_STATS_LEN) + +static int ixgbe_get_settings(struct net_device *netdev, + struct ethtool_cmd *ecmd) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE); + ecmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE); + ecmd->port = PORT_FIBRE; + ecmd->transceiver = XCVR_EXTERNAL; + + if (netif_carrier_ok(adapter->netdev)) { + ecmd->speed = SPEED_10000; + ecmd->duplex = DUPLEX_FULL; + } else { + ecmd->speed = -1; + ecmd->duplex = -1; + } + + ecmd->autoneg = AUTONEG_DISABLE; + return 0; +} + +static int ixgbe_set_settings(struct net_device *netdev, + struct ethtool_cmd *ecmd) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + if (ecmd->autoneg == AUTONEG_ENABLE || + ecmd->speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL) + return -EINVAL; + + if (netif_running(adapter->netdev)) { + ixgbe_down(adapter); + ixgbe_reset(adapter); + ixgbe_up(adapter); + } else { + ixgbe_reset(adapter); + } + + return 0; +} + +static void ixgbe_get_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *pause) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_hw *hw = &adapter->hw; + + pause->autoneg = AUTONEG_DISABLE; + + if (hw->fc.type == ixgbe_fc_rx_pause) { + pause->rx_pause = 1; + } else if (hw->fc.type == ixgbe_fc_tx_pause) { + pause->tx_pause = 1; + } else if (hw->fc.type == ixgbe_fc_full) { + pause->rx_pause = 1; + pause->tx_pause = 1; + } +} + +static int ixgbe_set_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *pause) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_hw *hw = &adapter->hw; + + if (pause->autoneg == AUTONEG_ENABLE) + return -EINVAL; + + if (pause->rx_pause && pause->tx_pause) + hw->fc.type = ixgbe_fc_full; + else if (pause->rx_pause && !pause->tx_pause) + hw->fc.type = ixgbe_fc_rx_pause; + else if (!pause->rx_pause && pause->tx_pause) + hw->fc.type = ixgbe_fc_tx_pause; + else if (!pause->rx_pause && !pause->tx_pause) + hw->fc.type = ixgbe_fc_none; + + hw->fc.original_type = hw->fc.type; + + if (netif_running(adapter->netdev)) { + ixgbe_down(adapter); + ixgbe_up(adapter); + } else { + ixgbe_reset(adapter); + } + + return 0; +} + +static u32 ixgbe_get_rx_csum(struct net_device *netdev) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + return (adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED); +} + +static int ixgbe_set_rx_csum(struct net_device *netdev, u32 data) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + if (data) + adapter->flags |= IXGBE_FLAG_RX_CSUM_ENABLED; + else + adapter->flags &= ~IXGBE_FLAG_RX_CSUM_ENABLED; + + if (netif_running(netdev)) { + ixgbe_down(adapter); + ixgbe_up(adapter); + } else { + ixgbe_reset(adapter); + } + + return 0; +} + +static u32 ixgbe_get_tx_csum(struct net_device *netdev) +{ + return (netdev->features & NETIF_F_HW_CSUM) != 0; +} + +static int ixgbe_set_tx_csum(struct net_device *netdev, u32 data) +{ + if (data) + netdev->features |= NETIF_F_HW_CSUM; + else + netdev->features &= ~NETIF_F_HW_CSUM; + + return 0; +} + +static int ixgbe_set_tso(struct net_device *netdev, u32 data) +{ + + if (data) { + netdev->features |= NETIF_F_TSO; + netdev->features |= NETIF_F_TSO6; + } else { + netdev->features &= ~NETIF_F_TSO; + netdev->features &= ~NETIF_F_TSO6; + } + return 0; +} + +static u32 ixgbe_get_msglevel(struct net_device *netdev) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + return adapter->msg_enable; +} + +static void ixgbe_set_msglevel(struct net_device *netdev, u32 data) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + adapter->msg_enable = data; +} + +static int ixgbe_get_regs_len(struct net_device *netdev) +{ +#define IXGBE_REGS_LEN 1128 + return IXGBE_REGS_LEN * sizeof(u32); +} + +#define IXGBE_GET_STAT(_A_, _R_) _A_->stats._R_ + +static void ixgbe_get_regs(struct net_device *netdev, + struct ethtool_regs *regs, void *p) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_hw *hw = &adapter->hw; + u32 *regs_buff = p; + u8 i; + + memset(p, 0, IXGBE_REGS_LEN * sizeof(u32)); + + regs->version = (1 << 24) | hw->revision_id << 16 | hw->device_id; + + /* General Registers */ + regs_buff[0] = IXGBE_READ_REG(hw, IXGBE_CTRL); + regs_buff[1] = IXGBE_READ_REG(hw, IXGBE_STATUS); + regs_buff[2] = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT); + regs_buff[3] = IXGBE_READ_REG(hw, IXGBE_ESDP); + regs_buff[4] = IXGBE_READ_REG(hw, IXGBE_EODSDP); + regs_buff[5] = IXGBE_READ_REG(hw, IXGBE_LEDCTL); + regs_buff[6] = IXGBE_READ_REG(hw, IXGBE_FRTIMER); + regs_buff[7] = IXGBE_READ_REG(hw, IXGBE_TCPTIMER); + + /* NVM Register */ + regs_buff[8] = IXGBE_READ_REG(hw, IXGBE_EEC); + regs_buff[9] = IXGBE_READ_REG(hw, IXGBE_EERD); + regs_buff[10] = IXGBE_READ_REG(hw, IXGBE_FLA); + regs_buff[11] = IXGBE_READ_REG(hw, IXGBE_EEMNGCTL); + regs_buff[12] = IXGBE_READ_REG(hw, IXGBE_EEMNGDATA); + regs_buff[13] = IXGBE_READ_REG(hw, IXGBE_FLMNGCTL); + regs_buff[14] = IXGBE_READ_REG(hw, IXGBE_FLMNGDATA); + regs_buff[15] = IXGBE_READ_REG(hw, IXGBE_FLMNGCNT); + regs_buff[16] = IXGBE_READ_REG(hw, IXGBE_FLOP); + regs_buff[17] = IXGBE_READ_REG(hw, IXGBE_GRC); + + /* Interrupt */ + regs_buff[18] = IXGBE_READ_REG(hw, IXGBE_EICR); + regs_buff[19] = IXGBE_READ_REG(hw, IXGBE_EICS); + regs_buff[20] = IXGBE_READ_REG(hw, IXGBE_EIMS); + regs_buff[21] = IXGBE_READ_REG(hw, IXGBE_EIMC); + regs_buff[22] = IXGBE_READ_REG(hw, IXGBE_EIAC); + regs_buff[23] = IXGBE_READ_REG(hw, IXGBE_EIAM); + regs_buff[24] = IXGBE_READ_REG(hw, IXGBE_EITR(0)); + regs_buff[25] = IXGBE_READ_REG(hw, IXGBE_IVAR(0)); + regs_buff[26] = IXGBE_READ_REG(hw, IXGBE_MSIXT); + regs_buff[27] = IXGBE_READ_REG(hw, IXGBE_MSIXPBA); + regs_buff[28] = IXGBE_READ_REG(hw, IXGBE_PBACL); + regs_buff[29] = IXGBE_READ_REG(hw, IXGBE_GPIE); + + /* Flow Control */ + regs_buff[30] = IXGBE_READ_REG(hw, IXGBE_PFCTOP); + regs_buff[31] = IXGBE_READ_REG(hw, IXGBE_FCTTV(0)); + regs_buff[32] = IXGBE_READ_REG(hw, IXGBE_FCTTV(1)); + regs_buff[33] = IXGBE_READ_REG(hw, IXGBE_FCTTV(2)); + regs_buff[34] = IXGBE_READ_REG(hw, IXGBE_FCTTV(3)); + for (i = 0; i < 8; i++) + regs_buff[35 + i] = IXGBE_READ_REG(hw, IXGBE_FCRTL(i)); + for (i = 0; i < 8; i++) + regs_buff[43 + i] = IXGBE_READ_REG(hw, IXGBE_FCRTH(i)); + regs_buff[51] = IXGBE_READ_REG(hw, IXGBE_FCRTV); + regs_buff[52] = IXGBE_READ_REG(hw, IXGBE_TFCS); + + /* Receive DMA */ + for (i = 0; i < 64; i++) + regs_buff[53 + i] = IXGBE_READ_REG(hw, IXGBE_RDBAL(i)); + for (i = 0; i < 64; i++) + regs_buff[117 + i] = IXGBE_READ_REG(hw, IXGBE_RDBAH(i)); + for (i = 0; i < 64; i++) + regs_buff[181 + i] = IXGBE_READ_REG(hw, IXGBE_RDLEN(i)); + for (i = 0; i < 64; i++) + regs_buff[245 + i] = IXGBE_READ_REG(hw, IXGBE_RDH(i)); + for (i = 0; i < 64; i++) + regs_buff[309 + i] = IXGBE_READ_REG(hw, IXGBE_RDT(i)); + for (i = 0; i < 64; i++) + regs_buff[373 + i] = IXGBE_READ_REG(hw, IXGBE_RXDCTL(i)); + for (i = 0; i < 16; i++) + regs_buff[437 + i] = IXGBE_READ_REG(hw, IXGBE_SRRCTL(i)); + for (i = 0; i < 16; i++) + regs_buff[453 + i] = IXGBE_READ_REG(hw, IXGBE_DCA_RXCTRL(i)); + regs_buff[469] = IXGBE_READ_REG(hw, IXGBE_RDRXCTL); + for (i = 0; i < 8; i++) + regs_buff[470 + i] = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(i)); + regs_buff[478] = IXGBE_READ_REG(hw, IXGBE_RXCTRL); + regs_buff[479] = IXGBE_READ_REG(hw, IXGBE_DROPEN); + + /* Receive */ + regs_buff[480] = IXGBE_READ_REG(hw, IXGBE_RXCSUM); + regs_buff[481] = IXGBE_READ_REG(hw, IXGBE_RFCTL); + for (i = 0; i < 16; i++) + regs_buff[482 + i] = IXGBE_READ_REG(hw, IXGBE_RAL(i)); + for (i = 0; i < 16; i++) + regs_buff[498 + i] = IXGBE_READ_REG(hw, IXGBE_RAH(i)); + regs_buff[514] = IXGBE_READ_REG(hw, IXGBE_PSRTYPE); + regs_buff[515] = IXGBE_READ_REG(hw, IXGBE_FCTRL); + regs_buff[516] = IXGBE_READ_REG(hw, IXGBE_VLNCTRL); + regs_buff[517] = IXGBE_READ_REG(hw, IXGBE_MCSTCTRL); + regs_buff[518] = IXGBE_READ_REG(hw, IXGBE_MRQC); + regs_buff[519] = IXGBE_READ_REG(hw, IXGBE_VMD_CTL); + for (i = 0; i < 8; i++) + regs_buff[520 + i] = IXGBE_READ_REG(hw, IXGBE_IMIR(i)); + for (i = 0; i < 8; i++) + regs_buff[528 + i] = IXGBE_READ_REG(hw, IXGBE_IMIREXT(i)); + regs_buff[536] = IXGBE_READ_REG(hw, IXGBE_IMIRVP); + + /* Transmit */ + for (i = 0; i < 32; i++) + regs_buff[537 + i] = IXGBE_READ_REG(hw, IXGBE_TDBAL(i)); + for (i = 0; i < 32; i++) + regs_buff[569 + i] = IXGBE_READ_REG(hw, IXGBE_TDBAH(i)); + for (i = 0; i < 32; i++) + regs_buff[601 + i] = IXGBE_READ_REG(hw, IXGBE_TDLEN(i)); + for (i = 0; i < 32; i++) + regs_buff[633 + i] = IXGBE_READ_REG(hw, IXGBE_TDH(i)); + for (i = 0; i < 32; i++) + regs_buff[665 + i] = IXGBE_READ_REG(hw, IXGBE_TDT(i)); + for (i = 0; i < 32; i++) + regs_buff[697 + i] = IXGBE_READ_REG(hw, IXGBE_TXDCTL(i)); + for (i = 0; i < 32; i++) + regs_buff[729 + i] = IXGBE_READ_REG(hw, IXGBE_TDWBAL(i)); + for (i = 0; i < 32; i++) + regs_buff[761 + i] = IXGBE_READ_REG(hw, IXGBE_TDWBAH(i)); + regs_buff[793] = IXGBE_READ_REG(hw, IXGBE_DTXCTL); + for (i = 0; i < 16; i++) + regs_buff[794 + i] = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL(i)); + regs_buff[810] = IXGBE_READ_REG(hw, IXGBE_TIPG); + for (i = 0; i < 8; i++) + regs_buff[811 + i] = IXGBE_READ_REG(hw, IXGBE_TXPBSIZE(i)); + regs_buff[819] = IXGBE_READ_REG(hw, IXGBE_MNGTXMAP); + + /* Wake Up */ + regs_buff[820] = IXGBE_READ_REG(hw, IXGBE_WUC); + regs_buff[821] = IXGBE_READ_REG(hw, IXGBE_WUFC); + regs_buff[822] = IXGBE_READ_REG(hw, IXGBE_WUS); + regs_buff[823] = IXGBE_READ_REG(hw, IXGBE_IPAV); + regs_buff[824] = IXGBE_READ_REG(hw, IXGBE_IP4AT); + regs_buff[825] = IXGBE_READ_REG(hw, IXGBE_IP6AT); + regs_buff[826] = IXGBE_READ_REG(hw, IXGBE_WUPL); + regs_buff[827] = IXGBE_READ_REG(hw, IXGBE_WUPM); + regs_buff[828] = IXGBE_READ_REG(hw, IXGBE_FHFT); + + /* DCE */ + regs_buff[829] = IXGBE_READ_REG(hw, IXGBE_RMCS); + regs_buff[830] = IXGBE_READ_REG(hw, IXGBE_DPMCS); + regs_buff[831] = IXGBE_READ_REG(hw, IXGBE_PDPMCS); + regs_buff[832] = IXGBE_READ_REG(hw, IXGBE_RUPPBMR); + for (i = 0; i < 8; i++) + regs_buff[833 + i] = IXGBE_READ_REG(hw, IXGBE_RT2CR(i)); + for (i = 0; i < 8; i++) + regs_buff[841 + i] = IXGBE_READ_REG(hw, IXGBE_RT2SR(i)); + for (i = 0; i < 8; i++) + regs_buff[849 + i] = IXGBE_READ_REG(hw, IXGBE_TDTQ2TCCR(i)); + for (i = 0; i < 8; i++) + regs_buff[857 + i] = IXGBE_READ_REG(hw, IXGBE_TDTQ2TCSR(i)); + for (i = 0; i < 8; i++) + regs_buff[865 + i] = IXGBE_READ_REG(hw, IXGBE_TDPT2TCCR(i)); + for (i = 0; i < 8; i++) + regs_buff[873 + i] = IXGBE_READ_REG(hw, IXGBE_TDPT2TCSR(i)); + + /* Statistics */ + regs_buff[881] = IXGBE_GET_STAT(adapter, crcerrs); + regs_buff[882] = IXGBE_GET_STAT(adapter, illerrc); + regs_buff[883] = IXGBE_GET_STAT(adapter, errbc); + regs_buff[884] = IXGBE_GET_STAT(adapter, mspdc); + for (i = 0; i < 8; i++) + regs_buff[885 + i] = IXGBE_GET_STAT(adapter, mpc[i]); + regs_buff[893] = IXGBE_GET_STAT(adapter, mlfc); + regs_buff[894] = IXGBE_GET_STAT(adapter, mrfc); + regs_buff[895] = IXGBE_GET_STAT(adapter, rlec); + regs_buff[896] = IXGBE_GET_STAT(adapter, lxontxc); + regs_buff[897] = IXGBE_GET_STAT(adapter, lxonrxc); + regs_buff[898] = IXGBE_GET_STAT(adapter, lxofftxc); + regs_buff[899] = IXGBE_GET_STAT(adapter, lxoffrxc); + for (i = 0; i < 8; i++) + regs_buff[900 + i] = IXGBE_GET_STAT(adapter, pxontxc[i]); + for (i = 0; i < 8; i++) + regs_buff[908 + i] = IXGBE_GET_STAT(adapter, pxonrxc[i]); + for (i = 0; i < 8; i++) + regs_buff[916 + i] = IXGBE_GET_STAT(adapter, pxofftxc[i]); + for (i = 0; i < 8; i++) + regs_buff[924 + i] = IXGBE_GET_STAT(adapter, pxoffrxc[i]); + regs_buff[932] = IXGBE_GET_STAT(adapter, prc64); + regs_buff[933] = IXGBE_GET_STAT(adapter, prc127); + regs_buff[934] = IXGBE_GET_STAT(adapter, prc255); + regs_buff[935] = IXGBE_GET_STAT(adapter, prc511); + regs_buff[936] = IXGBE_GET_STAT(adapter, prc1023); + regs_buff[937] = IXGBE_GET_STAT(adapter, prc1522); + regs_buff[938] = IXGBE_GET_STAT(adapter, gprc); + regs_buff[939] = IXGBE_GET_STAT(adapter, bprc); + regs_buff[940] = IXGBE_GET_STAT(adapter, mprc); + regs_buff[941] = IXGBE_GET_STAT(adapter, gptc); + regs_buff[942] = IXGBE_GET_STAT(adapter, gorc); + regs_buff[944] = IXGBE_GET_STAT(adapter, gotc); + for (i = 0; i < 8; i++) + regs_buff[946 + i] = IXGBE_GET_STAT(adapter, rnbc[i]); + regs_buff[954] = IXGBE_GET_STAT(adapter, ruc); + regs_buff[955] = IXGBE_GET_STAT(adapter, rfc); + regs_buff[956] = IXGBE_GET_STAT(adapter, roc); + regs_buff[957] = IXGBE_GET_STAT(adapter, rjc); + regs_buff[958] = IXGBE_GET_STAT(adapter, mngprc); + regs_buff[959] = IXGBE_GET_STAT(adapter, mngpdc); + regs_buff[960] = IXGBE_GET_STAT(adapter, mngptc); + regs_buff[961] = IXGBE_GET_STAT(adapter, tor); + regs_buff[963] = IXGBE_GET_STAT(adapter, tpr); + regs_buff[964] = IXGBE_GET_STAT(adapter, tpt); + regs_buff[965] = IXGBE_GET_STAT(adapter, ptc64); + regs_buff[966] = IXGBE_GET_STAT(adapter, ptc127); + regs_buff[967] = IXGBE_GET_STAT(adapter, ptc255); + regs_buff[968] = IXGBE_GET_STAT(adapter, ptc511); + regs_buff[969] = IXGBE_GET_STAT(adapter, ptc1023); + regs_buff[970] = IXGBE_GET_STAT(adapter, ptc1522); + regs_buff[971] = IXGBE_GET_STAT(adapter, mptc); + regs_buff[972] = IXGBE_GET_STAT(adapter, bptc); + regs_buff[973] = IXGBE_GET_STAT(adapter, xec); + for (i = 0; i < 16; i++) + regs_buff[974 + i] = IXGBE_GET_STAT(adapter, qprc[i]); + for (i = 0; i < 16; i++) + regs_buff[990 + i] = IXGBE_GET_STAT(adapter, qptc[i]); + for (i = 0; i < 16; i++) + regs_buff[1006 + i] = IXGBE_GET_STAT(adapter, qbrc[i]); + for (i = 0; i < 16; i++) + regs_buff[1022 + i] = IXGBE_GET_STAT(adapter, qbtc[i]); + + /* MAC */ + regs_buff[1038] = IXGBE_READ_REG(hw, IXGBE_PCS1GCFIG); + regs_buff[1039] = IXGBE_READ_REG(hw, IXGBE_PCS1GLCTL); + regs_buff[1040] = IXGBE_READ_REG(hw, IXGBE_PCS1GLSTA); + regs_buff[1041] = IXGBE_READ_REG(hw, IXGBE_PCS1GDBG0); + regs_buff[1042] = IXGBE_READ_REG(hw, IXGBE_PCS1GDBG1); + regs_buff[1043] = IXGBE_READ_REG(hw, IXGBE_PCS1GANA); + regs_buff[1044] = IXGBE_READ_REG(hw, IXGBE_PCS1GANLP); + regs_buff[1045] = IXGBE_READ_REG(hw, IXGBE_PCS1GANNP); + regs_buff[1046] = IXGBE_READ_REG(hw, IXGBE_PCS1GANLPNP); + regs_buff[1047] = IXGBE_READ_REG(hw, IXGBE_HLREG0); + regs_buff[1048] = IXGBE_READ_REG(hw, IXGBE_HLREG1); + regs_buff[1049] = IXGBE_READ_REG(hw, IXGBE_PAP); + regs_buff[1050] = IXGBE_READ_REG(hw, IXGBE_MACA); + regs_buff[1051] = IXGBE_READ_REG(hw, IXGBE_APAE); + regs_buff[1052] = IXGBE_READ_REG(hw, IXGBE_ARD); + regs_buff[1053] = IXGBE_READ_REG(hw, IXGBE_AIS); + regs_buff[1054] = IXGBE_READ_REG(hw, IXGBE_MSCA); + regs_buff[1055] = IXGBE_READ_REG(hw, IXGBE_MSRWD); + regs_buff[1056] = IXGBE_READ_REG(hw, IXGBE_MLADD); + regs_buff[1057] = IXGBE_READ_REG(hw, IXGBE_MHADD); + regs_buff[1058] = IXGBE_READ_REG(hw, IXGBE_TREG); + regs_buff[1059] = IXGBE_READ_REG(hw, IXGBE_PCSS1); + regs_buff[1060] = IXGBE_READ_REG(hw, IXGBE_PCSS2); + regs_buff[1061] = IXGBE_READ_REG(hw, IXGBE_XPCSS); + regs_buff[1062] = IXGBE_READ_REG(hw, IXGBE_SERDESC); + regs_buff[1063] = IXGBE_READ_REG(hw, IXGBE_MACS); + regs_buff[1064] = IXGBE_READ_REG(hw, IXGBE_AUTOC); + regs_buff[1065] = IXGBE_READ_REG(hw, IXGBE_LINKS); + regs_buff[1066] = IXGBE_READ_REG(hw, IXGBE_AUTOC2); + regs_buff[1067] = IXGBE_READ_REG(hw, IXGBE_AUTOC3); + regs_buff[1068] = IXGBE_READ_REG(hw, IXGBE_ANLP1); + regs_buff[1069] = IXGBE_READ_REG(hw, IXGBE_ANLP2); + regs_buff[1070] = IXGBE_READ_REG(hw, IXGBE_ATLASCTL); + + /* Diagnostic */ + regs_buff[1071] = IXGBE_READ_REG(hw, IXGBE_RDSTATCTL); + for (i = 0; i < 8; i++) + regs_buff[1072] = IXGBE_READ_REG(hw, IXGBE_RDSTAT(i)); + regs_buff[1080] = IXGBE_READ_REG(hw, IXGBE_RDHMPN); + regs_buff[1081] = IXGBE_READ_REG(hw, IXGBE_RIC_DW0); + regs_buff[1082] = IXGBE_READ_REG(hw, IXGBE_RIC_DW1); + regs_buff[1083] = IXGBE_READ_REG(hw, IXGBE_RIC_DW2); + regs_buff[1084] = IXGBE_READ_REG(hw, IXGBE_RIC_DW3); + regs_buff[1085] = IXGBE_READ_REG(hw, IXGBE_RDPROBE); + regs_buff[1086] = IXGBE_READ_REG(hw, IXGBE_TDSTATCTL); + for (i = 0; i < 8; i++) + regs_buff[1087] = IXGBE_READ_REG(hw, IXGBE_TDSTAT(i)); + regs_buff[1095] = IXGBE_READ_REG(hw, IXGBE_TDHMPN); + regs_buff[1096] = IXGBE_READ_REG(hw, IXGBE_TIC_DW0); + regs_buff[1097] = IXGBE_READ_REG(hw, IXGBE_TIC_DW1); + regs_buff[1098] = IXGBE_READ_REG(hw, IXGBE_TIC_DW2); + regs_buff[1099] = IXGBE_READ_REG(hw, IXGBE_TIC_DW3); + regs_buff[1100] = IXGBE_READ_REG(hw, IXGBE_TDPROBE); + regs_buff[1101] = IXGBE_READ_REG(hw, IXGBE_TXBUFCTRL); + regs_buff[1102] = IXGBE_READ_REG(hw, IXGBE_TXBUFDATA0); + regs_buff[1103] = IXGBE_READ_REG(hw, IXGBE_TXBUFDATA1); + regs_buff[1104] = IXGBE_READ_REG(hw, IXGBE_TXBUFDATA2); + regs_buff[1105] = IXGBE_READ_REG(hw, IXGBE_TXBUFDATA3); + regs_buff[1106] = IXGBE_READ_REG(hw, IXGBE_RXBUFCTRL); + regs_buff[1107] = IXGBE_READ_REG(hw, IXGBE_RXBUFDATA0); + regs_buff[1108] = IXGBE_READ_REG(hw, IXGBE_RXBUFDATA1); + regs_buff[1109] = IXGBE_READ_REG(hw, IXGBE_RXBUFDATA2); + regs_buff[1110] = IXGBE_READ_REG(hw, IXGBE_RXBUFDATA3); + for (i = 0; i < 8; i++) + regs_buff[1111] = IXGBE_READ_REG(hw, IXGBE_PCIE_DIAG(i)); + regs_buff[1119] = IXGBE_READ_REG(hw, IXGBE_RFVAL); + regs_buff[1120] = IXGBE_READ_REG(hw, IXGBE_MDFTC1); + regs_buff[1121] = IXGBE_READ_REG(hw, IXGBE_MDFTC2); + regs_buff[1122] = IXGBE_READ_REG(hw, IXGBE_MDFTFIFO1); + regs_buff[1123] = IXGBE_READ_REG(hw, IXGBE_MDFTFIFO2); + regs_buff[1124] = IXGBE_READ_REG(hw, IXGBE_MDFTS); + regs_buff[1125] = IXGBE_READ_REG(hw, IXGBE_PCIEECCCTL); + regs_buff[1126] = IXGBE_READ_REG(hw, IXGBE_PBTXECC); + regs_buff[1127] = IXGBE_READ_REG(hw, IXGBE_PBRXECC); +} + +static int ixgbe_get_eeprom_len(struct net_device *netdev) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + return adapter->hw.eeprom.word_size * 2; +} + +static int ixgbe_get_eeprom(struct net_device *netdev, + struct ethtool_eeprom *eeprom, u8 *bytes) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_hw *hw = &adapter->hw; + u16 *eeprom_buff; + int first_word, last_word, eeprom_len; + int ret_val = 0; + u16 i; + + if (eeprom->len == 0) + return -EINVAL; + + eeprom->magic = hw->vendor_id | (hw->device_id << 16); + + first_word = eeprom->offset >> 1; + last_word = (eeprom->offset + eeprom->len - 1) >> 1; + eeprom_len = last_word - first_word + 1; + + eeprom_buff = kmalloc(sizeof(u16) * eeprom_len, GFP_KERNEL); + if (!eeprom_buff) + return -ENOMEM; + + for (i = 0; i < eeprom_len; i++) { + if ((ret_val = ixgbe_read_eeprom(hw, first_word + i, + &eeprom_buff[i]))) + break; + } + + /* Device's eeprom is always little-endian, word addressable */ + for (i = 0; i < eeprom_len; i++) + le16_to_cpus(&eeprom_buff[i]); + + memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 1), eeprom->len); + kfree(eeprom_buff); + + return ret_val; +} + +static void ixgbe_get_drvinfo(struct net_device *netdev, + struct ethtool_drvinfo *drvinfo) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + strncpy(drvinfo->driver, ixgbe_driver_name, 32); + strncpy(drvinfo->version, ixgbe_driver_version, 32); + strncpy(drvinfo->fw_version, "N/A", 32); + strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32); + drvinfo->n_stats = IXGBE_STATS_LEN; + drvinfo->regdump_len = ixgbe_get_regs_len(netdev); +} + +static void ixgbe_get_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ring) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_ring *tx_ring = adapter->tx_ring; + struct ixgbe_ring *rx_ring = adapter->rx_ring; + + ring->rx_max_pending = IXGBE_MAX_RXD; + ring->tx_max_pending = IXGBE_MAX_TXD; + ring->rx_mini_max_pending = 0; + ring->rx_jumbo_max_pending = 0; + ring->rx_pending = rx_ring->count; + ring->tx_pending = tx_ring->count; + ring->rx_mini_pending = 0; + ring->rx_jumbo_pending = 0; +} + +static int ixgbe_set_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ring) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_tx_buffer *old_buf; + struct ixgbe_rx_buffer *old_rx_buf; + void *old_desc; + int i, err; + u32 new_rx_count, new_tx_count, old_size; + dma_addr_t old_dma; + + if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) + return -EINVAL; + + new_rx_count = max(ring->rx_pending, (u32)IXGBE_MIN_RXD); + new_rx_count = min(new_rx_count, (u32)IXGBE_MAX_RXD); + new_rx_count = ALIGN(new_rx_count, IXGBE_REQ_RX_DESCRIPTOR_MULTIPLE); + + new_tx_count = max(ring->tx_pending, (u32)IXGBE_MIN_TXD); + new_tx_count = min(new_tx_count, (u32)IXGBE_MAX_TXD); + new_tx_count = ALIGN(new_tx_count, IXGBE_REQ_TX_DESCRIPTOR_MULTIPLE); + + if ((new_tx_count == adapter->tx_ring->count) && + (new_rx_count == adapter->rx_ring->count)) { + /* nothing to do */ + return 0; + } + + if (netif_running(adapter->netdev)) + ixgbe_down(adapter); + + /* + * We can't just free everything and then setup again, + * because the ISRs in MSI-X mode get passed pointers + * to the tx and rx ring structs. + */ + if (new_tx_count != adapter->tx_ring->count) { + for (i = 0; i < adapter->num_tx_queues; i++) { + /* Save existing descriptor ring */ + old_buf = adapter->tx_ring[i].tx_buffer_info; + old_desc = adapter->tx_ring[i].desc; + old_size = adapter->tx_ring[i].size; + old_dma = adapter->tx_ring[i].dma; + /* Try to allocate a new one */ + adapter->tx_ring[i].tx_buffer_info = NULL; + adapter->tx_ring[i].desc = NULL; + adapter->tx_ring[i].count = new_tx_count; + err = ixgbe_setup_tx_resources(adapter, + &adapter->tx_ring[i]); + if (err) { + /* Restore the old one so at least + the adapter still works, even if + we failed the request */ + adapter->tx_ring[i].tx_buffer_info = old_buf; + adapter->tx_ring[i].desc = old_desc; + adapter->tx_ring[i].size = old_size; + adapter->tx_ring[i].dma = old_dma; + goto err_setup; + } + /* Free the old buffer manually */ + vfree(old_buf); + pci_free_consistent(adapter->pdev, old_size, + old_desc, old_dma); + } + } + + if (new_rx_count != adapter->rx_ring->count) { + for (i = 0; i < adapter->num_rx_queues; i++) { + + old_rx_buf = adapter->rx_ring[i].rx_buffer_info; + old_desc = adapter->rx_ring[i].desc; + old_size = adapter->rx_ring[i].size; + old_dma = adapter->rx_ring[i].dma; + + adapter->rx_ring[i].rx_buffer_info = NULL; + adapter->rx_ring[i].desc = NULL; + adapter->rx_ring[i].dma = 0; + adapter->rx_ring[i].count = new_rx_count; + err = ixgbe_setup_rx_resources(adapter, + &adapter->rx_ring[i]); + if (err) { + adapter->rx_ring[i].rx_buffer_info = old_rx_buf; + adapter->rx_ring[i].desc = old_desc; + adapter->rx_ring[i].size = old_size; + adapter->rx_ring[i].dma = old_dma; + goto err_setup; + } + + vfree(old_rx_buf); + pci_free_consistent(adapter->pdev, old_size, old_desc, + old_dma); + } + } + + err = 0; +err_setup: + if (netif_running(adapter->netdev)) + ixgbe_up(adapter); + + return err; +} + +static int ixgbe_get_stats_count(struct net_device *netdev) +{ + return IXGBE_STATS_LEN; +} + +static void ixgbe_get_ethtool_stats(struct net_device *netdev, + struct ethtool_stats *stats, u64 *data) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + u64 *queue_stat; + int stat_count = sizeof(struct ixgbe_queue_stats) / sizeof(u64); + int j, k; + int i; + + ixgbe_update_stats(adapter); + for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++) { + char *p = (char *)adapter + ixgbe_gstrings_stats[i].stat_offset; + data[i] = (ixgbe_gstrings_stats[i].sizeof_stat == + sizeof(u64)) ? *(u64 *)p : *(u32 *)p; + } + for (j = 0; j < adapter->num_tx_queues; j++) { + queue_stat = (u64 *)&adapter->tx_ring[j].stats; + for (k = 0; k < stat_count; k++) + data[i + k] = queue_stat[k]; + i += k; + } + for (j = 0; j < adapter->num_rx_queues; j++) { + queue_stat = (u64 *)&adapter->rx_ring[j].stats; + for (k = 0; k < stat_count; k++) + data[i + k] = queue_stat[k]; + i += k; + } +} + +static void ixgbe_get_strings(struct net_device *netdev, u32 stringset, + u8 *data) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + u8 *p = data; + int i; + + switch (stringset) { + case ETH_SS_STATS: + for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++) { + memcpy(p, ixgbe_gstrings_stats[i].stat_string, + ETH_GSTRING_LEN); + p += ETH_GSTRING_LEN; + } + for (i = 0; i < adapter->num_tx_queues; i++) { + sprintf(p, "tx_queue_%u_packets", i); + p += ETH_GSTRING_LEN; + sprintf(p, "tx_queue_%u_bytes", i); + p += ETH_GSTRING_LEN; + } + for (i = 0; i < adapter->num_rx_queues; i++) { + sprintf(p, "rx_queue_%u_packets", i); + p += ETH_GSTRING_LEN; + sprintf(p, "rx_queue_%u_bytes", i); + p += ETH_GSTRING_LEN; + } +/* BUG_ON(p - data != IXGBE_STATS_LEN * ETH_GSTRING_LEN); */ + break; + } +} + + +static void ixgbe_get_wol(struct net_device *netdev, + struct ethtool_wolinfo *wol) +{ + wol->supported = 0; + wol->wolopts = 0; + + return; +} + +static int ixgbe_nway_reset(struct net_device *netdev) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + if (netif_running(netdev)) { + ixgbe_down(adapter); + ixgbe_reset(adapter); + ixgbe_up(adapter); + } + + return 0; +} + +static int ixgbe_phys_id(struct net_device *netdev, u32 data) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + u32 led_reg = IXGBE_READ_REG(&adapter->hw, IXGBE_LEDCTL); + u32 i; + + if (!data || data > 300) + data = 300; + + for (i = 0; i < (data * 1000); i += 400) { + ixgbe_led_on(&adapter->hw, IXGBE_LED_ON); + msleep_interruptible(200); + ixgbe_led_off(&adapter->hw, IXGBE_LED_ON); + msleep_interruptible(200); + } + + /* Restore LED settings */ + IXGBE_WRITE_REG(&adapter->hw, IXGBE_LEDCTL, led_reg); + + return 0; +} + +static int ixgbe_get_coalesce(struct net_device *netdev, + struct ethtool_coalesce *ec) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + if (adapter->rx_eitr == 0) + ec->rx_coalesce_usecs = 0; + else + ec->rx_coalesce_usecs = 1000000 / adapter->rx_eitr; + + if (adapter->tx_eitr == 0) + ec->tx_coalesce_usecs = 0; + else + ec->tx_coalesce_usecs = 1000000 / adapter->tx_eitr; + + ec->tx_max_coalesced_frames_irq = adapter->tx_ring[0].work_limit; + return 0; +} + +static int ixgbe_set_coalesce(struct net_device *netdev, + struct ethtool_coalesce *ec) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + if ((ec->rx_coalesce_usecs > IXGBE_MAX_ITR_USECS) || + ((ec->rx_coalesce_usecs > 0) && + (ec->rx_coalesce_usecs < IXGBE_MIN_ITR_USECS))) + return -EINVAL; + if ((ec->tx_coalesce_usecs > IXGBE_MAX_ITR_USECS) || + ((ec->tx_coalesce_usecs > 0) && + (ec->tx_coalesce_usecs < IXGBE_MIN_ITR_USECS))) + return -EINVAL; + + /* convert to rate of irq's per second */ + if (ec->rx_coalesce_usecs == 0) + adapter->rx_eitr = 0; + else + adapter->rx_eitr = (1000000 / ec->rx_coalesce_usecs); + + if (ec->tx_coalesce_usecs == 0) + adapter->tx_eitr = 0; + else + adapter->tx_eitr = (1000000 / ec->tx_coalesce_usecs); + + if (ec->tx_max_coalesced_frames_irq) + adapter->tx_ring[0].work_limit = + ec->tx_max_coalesced_frames_irq; + + if (netif_running(netdev)) { + ixgbe_down(adapter); + ixgbe_up(adapter); + } + + return 0; +} + + +static struct ethtool_ops ixgbe_ethtool_ops = { + .get_settings = ixgbe_get_settings, + .set_settings = ixgbe_set_settings, + .get_drvinfo = ixgbe_get_drvinfo, + .get_regs_len = ixgbe_get_regs_len, + .get_regs = ixgbe_get_regs, + .get_wol = ixgbe_get_wol, + .nway_reset = ixgbe_nway_reset, + .get_link = ethtool_op_get_link, + .get_eeprom_len = ixgbe_get_eeprom_len, + .get_eeprom = ixgbe_get_eeprom, + .get_ringparam = ixgbe_get_ringparam, + .set_ringparam = ixgbe_set_ringparam, + .get_pauseparam = ixgbe_get_pauseparam, + .set_pauseparam = ixgbe_set_pauseparam, + .get_rx_csum = ixgbe_get_rx_csum, + .set_rx_csum = ixgbe_set_rx_csum, + .get_tx_csum = ixgbe_get_tx_csum, + .set_tx_csum = ixgbe_set_tx_csum, + .get_sg = ethtool_op_get_sg, + .set_sg = ethtool_op_set_sg, + .get_msglevel = ixgbe_get_msglevel, + .set_msglevel = ixgbe_set_msglevel, + .get_tso = ethtool_op_get_tso, + .set_tso = ixgbe_set_tso, + .get_strings = ixgbe_get_strings, + .phys_id = ixgbe_phys_id, + .get_stats_count = ixgbe_get_stats_count, + .get_ethtool_stats = ixgbe_get_ethtool_stats, + .get_coalesce = ixgbe_get_coalesce, + .set_coalesce = ixgbe_set_coalesce, +}; + +void ixgbe_set_ethtool_ops(struct net_device *netdev) +{ + SET_ETHTOOL_OPS(netdev, &ixgbe_ethtool_ops); +} diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c new file mode 100644 index 00000000000..a08a46224c2 --- /dev/null +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -0,0 +1,2873 @@ +/******************************************************************************* + + Intel 10 Gigabit PCI Express Linux driver + Copyright(c) 1999 - 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ixgbe.h" +#include "ixgbe_common.h" + +char ixgbe_driver_name[] = "ixgbe"; +static char ixgbe_driver_string[] = + "Intel(R) 10 Gigabit PCI Express Network Driver"; + +#define DRV_VERSION "1.1.18" +char ixgbe_driver_version[] = DRV_VERSION; +static char ixgbe_copyright[] = "Copyright (c) 1999-2007 Intel Corporation."; + +static const struct ixgbe_info *ixgbe_info_tbl[] = { + [board_82598AF] = &ixgbe_82598AF_info, + [board_82598EB] = &ixgbe_82598EB_info, + [board_82598AT] = &ixgbe_82598AT_info, +}; + +/* ixgbe_pci_tbl - PCI Device ID Table + * + * Wildcard entries (PCI_ANY_ID) should come last + * Last entry must be all 0s + * + * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, + * Class, Class Mask, private data (not used) } + */ +static struct pci_device_id ixgbe_pci_tbl[] = { + {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AF_DUAL_PORT), + board_82598AF }, + {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AF_SINGLE_PORT), + board_82598AF }, + {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AT_DUAL_PORT), + board_82598AT }, + {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_CX4), + board_82598EB }, + + /* required last entry */ + {0, } +}; +MODULE_DEVICE_TABLE(pci, ixgbe_pci_tbl); + +MODULE_AUTHOR("Intel Corporation, "); +MODULE_DESCRIPTION("Intel(R) 10 Gigabit PCI Express Network Driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); + +#define DEFAULT_DEBUG_LEVEL_SHIFT 3 + + +#ifdef DEBUG +/** + * ixgbe_get_hw_dev_name - return device name string + * used by hardware layer to print debugging information + **/ +char *ixgbe_get_hw_dev_name(struct ixgbe_hw *hw) +{ + struct ixgbe_adapter *adapter = hw->back; + struct net_device *netdev = adapter->netdev; + return netdev->name; +} +#endif + +static void ixgbe_set_ivar(struct ixgbe_adapter *adapter, u16 int_alloc_entry, + u8 msix_vector) +{ + u32 ivar, index; + + msix_vector |= IXGBE_IVAR_ALLOC_VAL; + index = (int_alloc_entry >> 2) & 0x1F; + ivar = IXGBE_READ_REG(&adapter->hw, IXGBE_IVAR(index)); + ivar &= ~(0xFF << (8 * (int_alloc_entry & 0x3))); + ivar |= (msix_vector << (8 * (int_alloc_entry & 0x3))); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_IVAR(index), ivar); +} + +static void ixgbe_unmap_and_free_tx_resource(struct ixgbe_adapter *adapter, + struct ixgbe_tx_buffer + *tx_buffer_info) +{ + if (tx_buffer_info->dma) { + pci_unmap_page(adapter->pdev, + tx_buffer_info->dma, + tx_buffer_info->length, PCI_DMA_TODEVICE); + tx_buffer_info->dma = 0; + } + if (tx_buffer_info->skb) { + dev_kfree_skb_any(tx_buffer_info->skb); + tx_buffer_info->skb = NULL; + } + /* tx_buffer_info must be completely set up in the transmit path */ +} + +static inline bool ixgbe_check_tx_hang(struct ixgbe_adapter *adapter, + struct ixgbe_ring *tx_ring, + unsigned int eop, + union ixgbe_adv_tx_desc *eop_desc) +{ + /* Detect a transmit hang in hardware, this serializes the + * check with the clearing of time_stamp and movement of i */ + adapter->detect_tx_hung = false; + if (tx_ring->tx_buffer_info[eop].dma && + time_after(jiffies, tx_ring->tx_buffer_info[eop].time_stamp + HZ) && + !(IXGBE_READ_REG(&adapter->hw, IXGBE_TFCS) & IXGBE_TFCS_TXOFF)) { + /* detected Tx unit hang */ + DPRINTK(DRV, ERR, "Detected Tx Unit Hang\n" + " TDH <%x>\n" + " TDT <%x>\n" + " next_to_use <%x>\n" + " next_to_clean <%x>\n" + "tx_buffer_info[next_to_clean]\n" + " time_stamp <%lx>\n" + " next_to_watch <%x>\n" + " jiffies <%lx>\n" + " next_to_watch.status <%x>\n", + readl(adapter->hw.hw_addr + tx_ring->head), + readl(adapter->hw.hw_addr + tx_ring->tail), + tx_ring->next_to_use, + tx_ring->next_to_clean, + tx_ring->tx_buffer_info[eop].time_stamp, + eop, jiffies, eop_desc->wb.status); + return true; + } + + return false; +} + +/** + * ixgbe_clean_tx_irq - Reclaim resources after transmit completes + * @adapter: board private structure + **/ +static bool ixgbe_clean_tx_irq(struct ixgbe_adapter *adapter, + struct ixgbe_ring *tx_ring) +{ + struct net_device *netdev = adapter->netdev; + union ixgbe_adv_tx_desc *tx_desc, *eop_desc; + struct ixgbe_tx_buffer *tx_buffer_info; + unsigned int i, eop; + bool cleaned = false; + int count = 0; + + i = tx_ring->next_to_clean; + eop = tx_ring->tx_buffer_info[i].next_to_watch; + eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop); + while (eop_desc->wb.status & cpu_to_le32(IXGBE_TXD_STAT_DD)) { + for (cleaned = false; !cleaned;) { + tx_desc = IXGBE_TX_DESC_ADV(*tx_ring, i); + tx_buffer_info = &tx_ring->tx_buffer_info[i]; + cleaned = (i == eop); + + tx_ring->stats.bytes += tx_buffer_info->length; + ixgbe_unmap_and_free_tx_resource(adapter, + tx_buffer_info); + tx_desc->wb.status = 0; + + i++; + if (i == tx_ring->count) + i = 0; + } + + tx_ring->stats.packets++; + + eop = tx_ring->tx_buffer_info[i].next_to_watch; + eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop); + + /* weight of a sort for tx, avoid endless transmit cleanup */ + if (count++ >= tx_ring->work_limit) + break; + } + + tx_ring->next_to_clean = i; + +#define TX_WAKE_THRESHOLD 32 + spin_lock(&tx_ring->tx_lock); + + if (cleaned && netif_carrier_ok(netdev) && + (IXGBE_DESC_UNUSED(tx_ring) >= TX_WAKE_THRESHOLD) && + !test_bit(__IXGBE_DOWN, &adapter->state)) + netif_wake_queue(netdev); + + spin_unlock(&tx_ring->tx_lock); + + if (adapter->detect_tx_hung) + if (ixgbe_check_tx_hang(adapter, tx_ring, eop, eop_desc)) + netif_stop_queue(netdev); + + if (count >= tx_ring->work_limit) + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, tx_ring->eims_value); + + return cleaned; +} + +/** + * ixgbe_receive_skb - Send a completed packet up the stack + * @adapter: board private structure + * @skb: packet to send up + * @is_vlan: packet has a VLAN tag + * @tag: VLAN tag from descriptor + **/ +static void ixgbe_receive_skb(struct ixgbe_adapter *adapter, + struct sk_buff *skb, bool is_vlan, + u16 tag) +{ + if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL)) { + if (adapter->vlgrp && is_vlan) + vlan_hwaccel_receive_skb(skb, adapter->vlgrp, tag); + else + netif_receive_skb(skb); + } else { + + if (adapter->vlgrp && is_vlan) + vlan_hwaccel_rx(skb, adapter->vlgrp, tag); + else + netif_rx(skb); + } +} + +static inline void ixgbe_rx_checksum(struct ixgbe_adapter *adapter, + u32 status_err, + struct sk_buff *skb) +{ + skb->ip_summed = CHECKSUM_NONE; + + /* Ignore Checksum bit is set */ + if ((status_err & IXGBE_RXD_STAT_IXSM) || + !(adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED)) + return; + /* TCP/UDP checksum error bit is set */ + if (status_err & (IXGBE_RXDADV_ERR_TCPE | IXGBE_RXDADV_ERR_IPE)) { + /* let the stack verify checksum errors */ + adapter->hw_csum_rx_error++; + return; + } + /* It must be a TCP or UDP packet with a valid checksum */ + if (status_err & (IXGBE_RXD_STAT_L4CS | IXGBE_RXD_STAT_UDPCS)) + skb->ip_summed = CHECKSUM_UNNECESSARY; + adapter->hw_csum_rx_good++; +} + +/** + * ixgbe_alloc_rx_buffers - Replace used receive buffers; packet split + * @adapter: address of board private structure + **/ +static void ixgbe_alloc_rx_buffers(struct ixgbe_adapter *adapter, + struct ixgbe_ring *rx_ring, + int cleaned_count) +{ + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + union ixgbe_adv_rx_desc *rx_desc; + struct ixgbe_rx_buffer *rx_buffer_info; + struct sk_buff *skb; + unsigned int i; + unsigned int bufsz = adapter->rx_buf_len + NET_IP_ALIGN; + + i = rx_ring->next_to_use; + rx_buffer_info = &rx_ring->rx_buffer_info[i]; + + while (cleaned_count--) { + rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i); + + if (!rx_buffer_info->page && + (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED)) { + rx_buffer_info->page = alloc_page(GFP_ATOMIC); + if (!rx_buffer_info->page) { + adapter->alloc_rx_page_failed++; + goto no_buffers; + } + rx_buffer_info->page_dma = + pci_map_page(pdev, rx_buffer_info->page, + 0, PAGE_SIZE, PCI_DMA_FROMDEVICE); + } + + if (!rx_buffer_info->skb) { + skb = netdev_alloc_skb(netdev, bufsz); + + if (!skb) { + adapter->alloc_rx_buff_failed++; + goto no_buffers; + } + + /* + * Make buffer alignment 2 beyond a 16 byte boundary + * this will result in a 16 byte aligned IP header after + * the 14 byte MAC header is removed + */ + skb_reserve(skb, NET_IP_ALIGN); + + rx_buffer_info->skb = skb; + rx_buffer_info->dma = pci_map_single(pdev, skb->data, + bufsz, + PCI_DMA_FROMDEVICE); + } + /* Refresh the desc even if buffer_addrs didn't change because + * each write-back erases this info. */ + if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) { + rx_desc->read.pkt_addr = + cpu_to_le64(rx_buffer_info->page_dma); + rx_desc->read.hdr_addr = + cpu_to_le64(rx_buffer_info->dma); + } else { + rx_desc->read.pkt_addr = + cpu_to_le64(rx_buffer_info->dma); + } + + i++; + if (i == rx_ring->count) + i = 0; + rx_buffer_info = &rx_ring->rx_buffer_info[i]; + } +no_buffers: + if (rx_ring->next_to_use != i) { + rx_ring->next_to_use = i; + if (i-- == 0) + i = (rx_ring->count - 1); + + /* + * Force memory writes to complete before letting h/w + * know there are new descriptors to fetch. (Only + * applicable for weak-ordered memory model archs, + * such as IA-64). + */ + wmb(); + writel(i, adapter->hw.hw_addr + rx_ring->tail); + } +} + +static bool ixgbe_clean_rx_irq(struct ixgbe_adapter *adapter, + struct ixgbe_ring *rx_ring, + int *work_done, int work_to_do) +{ + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + union ixgbe_adv_rx_desc *rx_desc, *next_rxd; + struct ixgbe_rx_buffer *rx_buffer_info, *next_buffer; + struct sk_buff *skb; + unsigned int i; + u32 upper_len, len, staterr; + u16 hdr_info, vlan_tag; + bool is_vlan, cleaned = false; + int cleaned_count = 0; + + i = rx_ring->next_to_clean; + upper_len = 0; + rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i); + staterr = le32_to_cpu(rx_desc->wb.upper.status_error); + rx_buffer_info = &rx_ring->rx_buffer_info[i]; + is_vlan = (staterr & IXGBE_RXD_STAT_VP); + vlan_tag = le16_to_cpu(rx_desc->wb.upper.vlan); + + while (staterr & IXGBE_RXD_STAT_DD) { + if (*work_done >= work_to_do) + break; + (*work_done)++; + + if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) { + hdr_info = + le16_to_cpu(rx_desc->wb.lower.lo_dword.hdr_info); + len = + ((hdr_info & IXGBE_RXDADV_HDRBUFLEN_MASK) >> + IXGBE_RXDADV_HDRBUFLEN_SHIFT); + if (hdr_info & IXGBE_RXDADV_SPH) + adapter->rx_hdr_split++; + if (len > IXGBE_RX_HDR_SIZE) + len = IXGBE_RX_HDR_SIZE; + upper_len = le16_to_cpu(rx_desc->wb.upper.length); + } else + len = le16_to_cpu(rx_desc->wb.upper.length); + + cleaned = true; + skb = rx_buffer_info->skb; + prefetch(skb->data - NET_IP_ALIGN); + rx_buffer_info->skb = NULL; + + if (len && !skb_shinfo(skb)->nr_frags) { + pci_unmap_single(pdev, rx_buffer_info->dma, + adapter->rx_buf_len + NET_IP_ALIGN, + PCI_DMA_FROMDEVICE); + skb_put(skb, len); + } + + if (upper_len) { + pci_unmap_page(pdev, rx_buffer_info->page_dma, + PAGE_SIZE, PCI_DMA_FROMDEVICE); + rx_buffer_info->page_dma = 0; + skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags, + rx_buffer_info->page, 0, upper_len); + rx_buffer_info->page = NULL; + + skb->len += upper_len; + skb->data_len += upper_len; + skb->truesize += upper_len; + } + + i++; + if (i == rx_ring->count) + i = 0; + next_buffer = &rx_ring->rx_buffer_info[i]; + + next_rxd = IXGBE_RX_DESC_ADV(*rx_ring, i); + prefetch(next_rxd); + + cleaned_count++; + if (staterr & IXGBE_RXD_STAT_EOP) { + rx_ring->stats.packets++; + rx_ring->stats.bytes += skb->len; + } else { + rx_buffer_info->skb = next_buffer->skb; + rx_buffer_info->dma = next_buffer->dma; + next_buffer->skb = skb; + adapter->non_eop_descs++; + goto next_desc; + } + + if (staterr & IXGBE_RXDADV_ERR_FRAME_ERR_MASK) { + dev_kfree_skb_irq(skb); + goto next_desc; + } + + ixgbe_rx_checksum(adapter, staterr, skb); + skb->protocol = eth_type_trans(skb, netdev); + ixgbe_receive_skb(adapter, skb, is_vlan, vlan_tag); + netdev->last_rx = jiffies; + +next_desc: + rx_desc->wb.upper.status_error = 0; + + /* return some buffers to hardware, one at a time is too slow */ + if (cleaned_count >= IXGBE_RX_BUFFER_WRITE) { + ixgbe_alloc_rx_buffers(adapter, rx_ring, cleaned_count); + cleaned_count = 0; + } + + /* use prefetched values */ + rx_desc = next_rxd; + rx_buffer_info = next_buffer; + + staterr = le32_to_cpu(rx_desc->wb.upper.status_error); + is_vlan = (staterr & IXGBE_RXD_STAT_VP); + vlan_tag = le16_to_cpu(rx_desc->wb.upper.vlan); + } + + rx_ring->next_to_clean = i; + cleaned_count = IXGBE_DESC_UNUSED(rx_ring); + + if (cleaned_count) + ixgbe_alloc_rx_buffers(adapter, rx_ring, cleaned_count); + + return cleaned; +} + +#define IXGBE_MAX_INTR 10 +/** + * ixgbe_configure_msix - Configure MSI-X hardware + * @adapter: board private structure + * + * ixgbe_configure_msix sets up the hardware to properly generate MSI-X + * interrupts. + **/ +static void ixgbe_configure_msix(struct ixgbe_adapter *adapter) +{ + int i, vector = 0; + + for (i = 0; i < adapter->num_tx_queues; i++) { + ixgbe_set_ivar(adapter, IXGBE_IVAR_TX_QUEUE(i), + IXGBE_MSIX_VECTOR(vector)); + writel(EITR_INTS_PER_SEC_TO_REG(adapter->tx_eitr), + adapter->hw.hw_addr + adapter->tx_ring[i].itr_register); + vector++; + } + + for (i = 0; i < adapter->num_rx_queues; i++) { + ixgbe_set_ivar(adapter, IXGBE_IVAR_RX_QUEUE(i), + IXGBE_MSIX_VECTOR(vector)); + writel(EITR_INTS_PER_SEC_TO_REG(adapter->rx_eitr), + adapter->hw.hw_addr + adapter->rx_ring[i].itr_register); + vector++; + } + + vector = adapter->num_tx_queues + adapter->num_rx_queues; + ixgbe_set_ivar(adapter, IXGBE_IVAR_OTHER_CAUSES_INDEX, + IXGBE_MSIX_VECTOR(vector)); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EITR(vector), 1950); +} + +static irqreturn_t ixgbe_msix_lsc(int irq, void *data) +{ + struct net_device *netdev = data; + struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_hw *hw = &adapter->hw; + u32 eicr = IXGBE_READ_REG(hw, IXGBE_EICR); + + if (eicr & IXGBE_EICR_LSC) { + adapter->lsc_int++; + if (!test_bit(__IXGBE_DOWN, &adapter->state)) + mod_timer(&adapter->watchdog_timer, jiffies); + } + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, IXGBE_EIMS_OTHER); + + return IRQ_HANDLED; +} + +static irqreturn_t ixgbe_msix_clean_tx(int irq, void *data) +{ + struct ixgbe_ring *txr = data; + struct ixgbe_adapter *adapter = txr->adapter; + + ixgbe_clean_tx_irq(adapter, txr); + + return IRQ_HANDLED; +} + +static irqreturn_t ixgbe_msix_clean_rx(int irq, void *data) +{ + struct ixgbe_ring *rxr = data; + struct ixgbe_adapter *adapter = rxr->adapter; + + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, rxr->eims_value); + netif_rx_schedule(adapter->netdev, &adapter->napi); + return IRQ_HANDLED; +} + +static int ixgbe_clean_rxonly(struct napi_struct *napi, int budget) +{ + struct ixgbe_adapter *adapter = container_of(napi, + struct ixgbe_adapter, napi); + struct net_device *netdev = adapter->netdev; + int work_done = 0; + struct ixgbe_ring *rxr = adapter->rx_ring; + + /* Keep link state information with original netdev */ + if (!netif_carrier_ok(netdev)) + goto quit_polling; + + ixgbe_clean_rx_irq(adapter, rxr, &work_done, budget); + + /* If no Tx and not enough Rx work done, exit the polling mode */ + if ((work_done < budget) || !netif_running(netdev)) { +quit_polling: + netif_rx_complete(netdev, napi); + if (!test_bit(__IXGBE_DOWN, &adapter->state)) + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, + rxr->eims_value); + } + + return work_done; +} + +/** + * ixgbe_setup_msix - Initialize MSI-X interrupts + * + * ixgbe_setup_msix allocates MSI-X vectors and requests + * interrutps from the kernel. + **/ +static int ixgbe_setup_msix(struct ixgbe_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + int i, int_vector = 0, err = 0; + int max_msix_count; + + /* +1 for the LSC interrupt */ + max_msix_count = adapter->num_rx_queues + adapter->num_tx_queues + 1; + adapter->msix_entries = kcalloc(max_msix_count, + sizeof(struct msix_entry), GFP_KERNEL); + if (!adapter->msix_entries) + return -ENOMEM; + + for (i = 0; i < max_msix_count; i++) + adapter->msix_entries[i].entry = i; + + err = pci_enable_msix(adapter->pdev, adapter->msix_entries, + max_msix_count); + if (err) + goto out; + + for (i = 0; i < adapter->num_tx_queues; i++) { + sprintf(adapter->tx_ring[i].name, "%s-tx%d", netdev->name, i); + err = request_irq(adapter->msix_entries[int_vector].vector, + &ixgbe_msix_clean_tx, + 0, + adapter->tx_ring[i].name, + &(adapter->tx_ring[i])); + if (err) { + DPRINTK(PROBE, ERR, + "request_irq failed for MSIX interrupt " + "Error: %d\n", err); + goto release_irqs; + } + adapter->tx_ring[i].eims_value = + (1 << IXGBE_MSIX_VECTOR(int_vector)); + adapter->tx_ring[i].itr_register = IXGBE_EITR(int_vector); + int_vector++; + } + + for (i = 0; i < adapter->num_rx_queues; i++) { + if (strlen(netdev->name) < (IFNAMSIZ - 5)) + sprintf(adapter->rx_ring[i].name, + "%s-rx%d", netdev->name, i); + else + memcpy(adapter->rx_ring[i].name, + netdev->name, IFNAMSIZ); + err = request_irq(adapter->msix_entries[int_vector].vector, + &ixgbe_msix_clean_rx, 0, + adapter->rx_ring[i].name, + &(adapter->rx_ring[i])); + if (err) { + DPRINTK(PROBE, ERR, + "request_irq failed for MSIX interrupt " + "Error: %d\n", err); + goto release_irqs; + } + + adapter->rx_ring[i].eims_value = + (1 << IXGBE_MSIX_VECTOR(int_vector)); + adapter->rx_ring[i].itr_register = IXGBE_EITR(int_vector); + int_vector++; + } + + sprintf(adapter->lsc_name, "%s-lsc", netdev->name); + err = request_irq(adapter->msix_entries[int_vector].vector, + &ixgbe_msix_lsc, 0, adapter->lsc_name, netdev); + if (err) { + DPRINTK(PROBE, ERR, + "request_irq for msix_lsc failed: %d\n", err); + goto release_irqs; + } + + /* FIXME: implement netif_napi_remove() instead */ + adapter->napi.poll = ixgbe_clean_rxonly; + adapter->flags |= IXGBE_FLAG_MSIX_ENABLED; + return 0; + +release_irqs: + int_vector--; + for (; int_vector >= adapter->num_tx_queues; int_vector--) + free_irq(adapter->msix_entries[int_vector].vector, + &(adapter->rx_ring[int_vector - + adapter->num_tx_queues])); + + for (; int_vector >= 0; int_vector--) + free_irq(adapter->msix_entries[int_vector].vector, + &(adapter->tx_ring[int_vector])); +out: + kfree(adapter->msix_entries); + adapter->msix_entries = NULL; + adapter->flags &= ~IXGBE_FLAG_MSIX_ENABLED; + return err; +} + +/** + * ixgbe_intr - Interrupt Handler + * @irq: interrupt number + * @data: pointer to a network interface device structure + * @pt_regs: CPU registers structure + **/ +static irqreturn_t ixgbe_intr(int irq, void *data) +{ + struct net_device *netdev = data; + struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_hw *hw = &adapter->hw; + u32 eicr; + + eicr = IXGBE_READ_REG(hw, IXGBE_EICR); + + if (!eicr) + return IRQ_NONE; /* Not our interrupt */ + + if (eicr & IXGBE_EICR_LSC) { + adapter->lsc_int++; + if (!test_bit(__IXGBE_DOWN, &adapter->state)) + mod_timer(&adapter->watchdog_timer, jiffies); + } + if (netif_rx_schedule_prep(netdev, &adapter->napi)) { + /* Disable interrupts and register for poll. The flush of the + * posted write is intentionally left out. */ + atomic_inc(&adapter->irq_sem); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, ~0); + __netif_rx_schedule(netdev, &adapter->napi); + } + + return IRQ_HANDLED; +} + +/** + * ixgbe_request_irq - initialize interrupts + * @adapter: board private structure + * + * Attempts to configure interrupts using the best available + * capabilities of the hardware and kernel. + **/ +static int ixgbe_request_irq(struct ixgbe_adapter *adapter, u32 *num_rx_queues) +{ + struct net_device *netdev = adapter->netdev; + int flags, err; + irqreturn_t(*handler) (int, void *) = &ixgbe_intr; + + flags = IRQF_SHARED; + + err = ixgbe_setup_msix(adapter); + if (!err) + goto request_done; + + /* + * if we can't do MSI-X, fall through and try MSI + * No need to reallocate memory since we're decreasing the number of + * queues. We just won't use the other ones, also it is freed correctly + * on ixgbe_remove. + */ + *num_rx_queues = 1; + + /* do MSI */ + err = pci_enable_msi(adapter->pdev); + if (!err) { + adapter->flags |= IXGBE_FLAG_MSI_ENABLED; + flags &= ~IRQF_SHARED; + handler = &ixgbe_intr; + } + + err = request_irq(adapter->pdev->irq, handler, flags, + netdev->name, netdev); + if (err) + DPRINTK(PROBE, ERR, "request_irq failed, Error %d\n", err); + +request_done: + return err; +} + +static void ixgbe_free_irq(struct ixgbe_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + + if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { + int i; + + for (i = 0; i < adapter->num_tx_queues; i++) + free_irq(adapter->msix_entries[i].vector, + &(adapter->tx_ring[i])); + for (i = 0; i < adapter->num_rx_queues; i++) + free_irq(adapter->msix_entries[i + + adapter->num_tx_queues].vector, + &(adapter->rx_ring[i])); + i = adapter->num_rx_queues + adapter->num_tx_queues; + free_irq(adapter->msix_entries[i].vector, netdev); + pci_disable_msix(adapter->pdev); + kfree(adapter->msix_entries); + adapter->msix_entries = NULL; + adapter->flags &= ~IXGBE_FLAG_MSIX_ENABLED; + return; + } + + free_irq(adapter->pdev->irq, netdev); + if (adapter->flags & IXGBE_FLAG_MSI_ENABLED) { + pci_disable_msi(adapter->pdev); + adapter->flags &= ~IXGBE_FLAG_MSI_ENABLED; + } +} + +/** + * ixgbe_irq_disable - Mask off interrupt generation on the NIC + * @adapter: board private structure + **/ +static inline void ixgbe_irq_disable(struct ixgbe_adapter *adapter) +{ + atomic_inc(&adapter->irq_sem); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, ~0); + IXGBE_WRITE_FLUSH(&adapter->hw); + synchronize_irq(adapter->pdev->irq); +} + +/** + * ixgbe_irq_enable - Enable default interrupt generation settings + * @adapter: board private structure + **/ +static inline void ixgbe_irq_enable(struct ixgbe_adapter *adapter) +{ + if (atomic_dec_and_test(&adapter->irq_sem)) { + if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIAC, + (IXGBE_EIMS_ENABLE_MASK & + ~(IXGBE_EIMS_OTHER | IXGBE_EIMS_LSC))); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, + IXGBE_EIMS_ENABLE_MASK); + IXGBE_WRITE_FLUSH(&adapter->hw); + } +} + +/** + * ixgbe_configure_msi_and_legacy - Initialize PIN (INTA...) and MSI interrupts + * + **/ +static void ixgbe_configure_msi_and_legacy(struct ixgbe_adapter *adapter) +{ + int i; + struct ixgbe_hw *hw = &adapter->hw; + + if (adapter->rx_eitr) + IXGBE_WRITE_REG(hw, IXGBE_EITR(0), + EITR_INTS_PER_SEC_TO_REG(adapter->rx_eitr)); + + /* for re-triggering the interrupt in non-NAPI mode */ + adapter->rx_ring[0].eims_value = (1 << IXGBE_MSIX_VECTOR(0)); + adapter->tx_ring[0].eims_value = (1 << IXGBE_MSIX_VECTOR(0)); + + ixgbe_set_ivar(adapter, IXGBE_IVAR_RX_QUEUE(0), 0); + for (i = 0; i < adapter->num_tx_queues; i++) + ixgbe_set_ivar(adapter, IXGBE_IVAR_TX_QUEUE(i), i); +} + +/** + * ixgbe_configure_tx - Configure 8254x Transmit Unit after Reset + * @adapter: board private structure + * + * Configure the Tx unit of the MAC after a reset. + **/ +static void ixgbe_configure_tx(struct ixgbe_adapter *adapter) +{ + u64 tdba; + struct ixgbe_hw *hw = &adapter->hw; + u32 i, tdlen; + + /* Setup the HW Tx Head and Tail descriptor pointers */ + for (i = 0; i < adapter->num_tx_queues; i++) { + tdba = adapter->tx_ring[i].dma; + tdlen = adapter->tx_ring[i].count * + sizeof(union ixgbe_adv_tx_desc); + IXGBE_WRITE_REG(hw, IXGBE_TDBAL(i), (tdba & DMA_32BIT_MASK)); + IXGBE_WRITE_REG(hw, IXGBE_TDBAH(i), (tdba >> 32)); + IXGBE_WRITE_REG(hw, IXGBE_TDLEN(i), tdlen); + IXGBE_WRITE_REG(hw, IXGBE_TDH(i), 0); + IXGBE_WRITE_REG(hw, IXGBE_TDT(i), 0); + adapter->tx_ring[i].head = IXGBE_TDH(i); + adapter->tx_ring[i].tail = IXGBE_TDT(i); + } + + IXGBE_WRITE_REG(hw, IXGBE_TIPG, IXGBE_TIPG_FIBER_DEFAULT); +} + +#define PAGE_USE_COUNT(S) (((S) >> PAGE_SHIFT) + \ + (((S) & (PAGE_SIZE - 1)) ? 1 : 0)) + +#define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT 2 +/** + * ixgbe_configure_rx - Configure 8254x Receive Unit after Reset + * @adapter: board private structure + * + * Configure the Rx unit of the MAC after a reset. + **/ +static void ixgbe_configure_rx(struct ixgbe_adapter *adapter) +{ + u64 rdba; + struct ixgbe_hw *hw = &adapter->hw; + struct net_device *netdev = adapter->netdev; + int max_frame = netdev->mtu + ETH_HLEN + ETH_FCS_LEN; + u32 rdlen, rxctrl, rxcsum; + u32 random[10]; + u32 reta, mrqc; + int i; + u32 fctrl, hlreg0; + u32 srrctl; + u32 pages; + + /* Decide whether to use packet split mode or not */ + if (netdev->mtu > ETH_DATA_LEN) + adapter->flags |= IXGBE_FLAG_RX_PS_ENABLED; + else + adapter->flags &= ~IXGBE_FLAG_RX_PS_ENABLED; + + /* Set the RX buffer length according to the mode */ + if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) { + adapter->rx_buf_len = IXGBE_RX_HDR_SIZE; + } else { + if (netdev->mtu <= ETH_DATA_LEN) + adapter->rx_buf_len = MAXIMUM_ETHERNET_VLAN_SIZE; + else + adapter->rx_buf_len = ALIGN(max_frame, 1024); + } + + fctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL); + fctrl |= IXGBE_FCTRL_BAM; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, fctrl); + + hlreg0 = IXGBE_READ_REG(hw, IXGBE_HLREG0); + if (adapter->netdev->mtu <= ETH_DATA_LEN) + hlreg0 &= ~IXGBE_HLREG0_JUMBOEN; + else + hlreg0 |= IXGBE_HLREG0_JUMBOEN; + IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg0); + + pages = PAGE_USE_COUNT(adapter->netdev->mtu); + + srrctl = IXGBE_READ_REG(&adapter->hw, IXGBE_SRRCTL(0)); + srrctl &= ~IXGBE_SRRCTL_BSIZEHDR_MASK; + srrctl &= ~IXGBE_SRRCTL_BSIZEPKT_MASK; + + if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) { + srrctl |= PAGE_SIZE >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; + srrctl |= IXGBE_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS; + srrctl |= ((IXGBE_RX_HDR_SIZE << + IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT) & + IXGBE_SRRCTL_BSIZEHDR_MASK); + } else { + srrctl |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF; + + if (adapter->rx_buf_len == MAXIMUM_ETHERNET_VLAN_SIZE) + srrctl |= + IXGBE_RXBUFFER_2048 >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; + else + srrctl |= + adapter->rx_buf_len >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; + } + IXGBE_WRITE_REG(&adapter->hw, IXGBE_SRRCTL(0), srrctl); + + rdlen = adapter->rx_ring[0].count * sizeof(union ixgbe_adv_rx_desc); + /* disable receives while setting up the descriptors */ + rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL); + IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl & ~IXGBE_RXCTRL_RXEN); + + /* Setup the HW Rx Head and Tail Descriptor Pointers and + * the Base and Length of the Rx Descriptor Ring */ + for (i = 0; i < adapter->num_rx_queues; i++) { + rdba = adapter->rx_ring[i].dma; + IXGBE_WRITE_REG(hw, IXGBE_RDBAL(i), (rdba & DMA_32BIT_MASK)); + IXGBE_WRITE_REG(hw, IXGBE_RDBAH(i), (rdba >> 32)); + IXGBE_WRITE_REG(hw, IXGBE_RDLEN(i), rdlen); + IXGBE_WRITE_REG(hw, IXGBE_RDH(i), 0); + IXGBE_WRITE_REG(hw, IXGBE_RDT(i), 0); + adapter->rx_ring[i].head = IXGBE_RDH(i); + adapter->rx_ring[i].tail = IXGBE_RDT(i); + } + + if (adapter->num_rx_queues > 1) { + /* Random 40bytes used as random key in RSS hash function */ + get_random_bytes(&random[0], 40); + + switch (adapter->num_rx_queues) { + case 8: + case 4: + /* Bits [3:0] in each byte refers the Rx queue no */ + reta = 0x00010203; + break; + case 2: + reta = 0x00010001; + break; + default: + reta = 0x00000000; + break; + } + + /* Fill out redirection table */ + for (i = 0; i < 32; i++) { + IXGBE_WRITE_REG_ARRAY(hw, IXGBE_RETA(0), i, reta); + if (adapter->num_rx_queues > 4) { + i++; + IXGBE_WRITE_REG_ARRAY(hw, IXGBE_RETA(0), i, + 0x04050607); + } + } + + /* Fill out hash function seeds */ + for (i = 0; i < 10; i++) + IXGBE_WRITE_REG_ARRAY(hw, IXGBE_RSSRK(0), i, random[i]); + + mrqc = IXGBE_MRQC_RSSEN + /* Perform hash on these packet types */ + | IXGBE_MRQC_RSS_FIELD_IPV4 + | IXGBE_MRQC_RSS_FIELD_IPV4_TCP + | IXGBE_MRQC_RSS_FIELD_IPV4_UDP + | IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP + | IXGBE_MRQC_RSS_FIELD_IPV6_EX + | IXGBE_MRQC_RSS_FIELD_IPV6 + | IXGBE_MRQC_RSS_FIELD_IPV6_TCP + | IXGBE_MRQC_RSS_FIELD_IPV6_UDP + | IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP; + IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc); + + /* Multiqueue and packet checksumming are mutually exclusive. */ + rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM); + rxcsum |= IXGBE_RXCSUM_PCSD; + IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum); + } else { + /* Enable Receive Checksum Offload for TCP and UDP */ + rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM); + if (adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED) { + /* Enable IPv4 payload checksum for UDP fragments + * Must be used in conjunction with packet-split. */ + rxcsum |= IXGBE_RXCSUM_IPPCSE; + } else { + /* don't need to clear IPPCSE as it defaults to 0 */ + } + IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum); + } + /* Enable Receives */ + IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl); + rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL); +} + +static void ixgbe_vlan_rx_register(struct net_device *netdev, + struct vlan_group *grp) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + u32 ctrl; + + ixgbe_irq_disable(adapter); + adapter->vlgrp = grp; + + if (grp) { + /* enable VLAN tag insert/strip */ + ctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_VLNCTRL); + ctrl |= IXGBE_VLNCTRL_VME | IXGBE_VLNCTRL_VFE; + ctrl &= ~IXGBE_VLNCTRL_CFIEN; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_VLNCTRL, ctrl); + } + + ixgbe_irq_enable(adapter); +} + +static void ixgbe_vlan_rx_add_vid(struct net_device *netdev, u16 vid) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + /* add VID to filter table */ + ixgbe_set_vfta(&adapter->hw, vid, 0, true); +} + +static void ixgbe_vlan_rx_kill_vid(struct net_device *netdev, u16 vid) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + ixgbe_irq_disable(adapter); + vlan_group_set_device(adapter->vlgrp, vid, NULL); + ixgbe_irq_enable(adapter); + + /* remove VID from filter table */ + ixgbe_set_vfta(&adapter->hw, vid, 0, false); +} + +static void ixgbe_restore_vlan(struct ixgbe_adapter *adapter) +{ + ixgbe_vlan_rx_register(adapter->netdev, adapter->vlgrp); + + if (adapter->vlgrp) { + u16 vid; + for (vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) { + if (!vlan_group_get_device(adapter->vlgrp, vid)) + continue; + ixgbe_vlan_rx_add_vid(adapter->netdev, vid); + } + } +} + +/** + * ixgbe_set_multi - Multicast and Promiscuous mode set + * @netdev: network interface device structure + * + * The set_multi entry point is called whenever the multicast address + * list or the network interface flags are updated. This routine is + * responsible for configuring the hardware for proper multicast, + * promiscuous mode, and all-multi behavior. + **/ +static void ixgbe_set_multi(struct net_device *netdev) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_hw *hw = &adapter->hw; + struct dev_mc_list *mc_ptr; + u8 *mta_list; + u32 fctrl; + int i; + + /* Check for Promiscuous and All Multicast modes */ + + fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL); + + if (netdev->flags & IFF_PROMISC) { + fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); + } else if (netdev->flags & IFF_ALLMULTI) { + fctrl |= IXGBE_FCTRL_MPE; + fctrl &= ~IXGBE_FCTRL_UPE; + } else { + fctrl &= ~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); + } + + IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl); + + if (netdev->mc_count) { + mta_list = kcalloc(netdev->mc_count, ETH_ALEN, GFP_ATOMIC); + if (!mta_list) + return; + + /* Shared function expects packed array of only addresses. */ + mc_ptr = netdev->mc_list; + + for (i = 0; i < netdev->mc_count; i++) { + if (!mc_ptr) + break; + memcpy(mta_list + (i * ETH_ALEN), mc_ptr->dmi_addr, + ETH_ALEN); + mc_ptr = mc_ptr->next; + } + + ixgbe_update_mc_addr_list(hw, mta_list, i, 0); + kfree(mta_list); + } else { + ixgbe_update_mc_addr_list(hw, NULL, 0, 0); + } + +} + +static void ixgbe_configure(struct ixgbe_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + int i; + + ixgbe_set_multi(netdev); + + ixgbe_restore_vlan(adapter); + + ixgbe_configure_tx(adapter); + ixgbe_configure_rx(adapter); + for (i = 0; i < adapter->num_rx_queues; i++) + ixgbe_alloc_rx_buffers(adapter, &adapter->rx_ring[i], + (adapter->rx_ring[i].count - 1)); +} + +static int ixgbe_up_complete(struct ixgbe_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + int i; + u32 gpie = 0; + struct ixgbe_hw *hw = &adapter->hw; + u32 txdctl, rxdctl, mhadd; + int max_frame = netdev->mtu + ETH_HLEN + ETH_FCS_LEN; + + if (adapter->flags & (IXGBE_FLAG_MSIX_ENABLED | + IXGBE_FLAG_MSI_ENABLED)) { + if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { + gpie = (IXGBE_GPIE_MSIX_MODE | IXGBE_GPIE_EIAME | + IXGBE_GPIE_PBA_SUPPORT | IXGBE_GPIE_OCD); + } else { + /* MSI only */ + gpie = (IXGBE_GPIE_EIAME | + IXGBE_GPIE_PBA_SUPPORT); + } + IXGBE_WRITE_REG(&adapter->hw, IXGBE_GPIE, gpie); + gpie = IXGBE_READ_REG(&adapter->hw, IXGBE_GPIE); + } + + mhadd = IXGBE_READ_REG(hw, IXGBE_MHADD); + + if (max_frame != (mhadd >> IXGBE_MHADD_MFS_SHIFT)) { + mhadd &= ~IXGBE_MHADD_MFS_MASK; + mhadd |= max_frame << IXGBE_MHADD_MFS_SHIFT; + + IXGBE_WRITE_REG(hw, IXGBE_MHADD, mhadd); + } + + for (i = 0; i < adapter->num_tx_queues; i++) { + txdctl = IXGBE_READ_REG(&adapter->hw, IXGBE_TXDCTL(i)); + txdctl |= IXGBE_TXDCTL_ENABLE; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_TXDCTL(i), txdctl); + } + + for (i = 0; i < adapter->num_rx_queues; i++) { + rxdctl = IXGBE_READ_REG(&adapter->hw, IXGBE_RXDCTL(i)); + rxdctl |= IXGBE_RXDCTL_ENABLE; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXDCTL(i), rxdctl); + } + /* enable all receives */ + rxdctl = IXGBE_READ_REG(hw, IXGBE_RXCTRL); + rxdctl |= (IXGBE_RXCTRL_DMBYPS | IXGBE_RXCTRL_RXEN); + IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxdctl); + + if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) + ixgbe_configure_msix(adapter); + else + ixgbe_configure_msi_and_legacy(adapter); + + clear_bit(__IXGBE_DOWN, &adapter->state); + napi_enable(&adapter->napi); + ixgbe_irq_enable(adapter); + + /* bring the link up in the watchdog, this could race with our first + * link up interrupt but shouldn't be a problem */ + mod_timer(&adapter->watchdog_timer, jiffies); + return 0; +} + +int ixgbe_up(struct ixgbe_adapter *adapter) +{ + /* hardware has been reset, we need to reload some things */ + ixgbe_configure(adapter); + + return ixgbe_up_complete(adapter); +} + +void ixgbe_reset(struct ixgbe_adapter *adapter) +{ + if (ixgbe_init_hw(&adapter->hw)) + DPRINTK(PROBE, ERR, "Hardware Error\n"); + + /* reprogram the RAR[0] in case user changed it. */ + ixgbe_set_rar(&adapter->hw, 0, adapter->hw.mac.addr, 0, IXGBE_RAH_AV); + +} + +#ifdef CONFIG_PM +static int ixgbe_resume(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct ixgbe_adapter *adapter = netdev_priv(netdev); + u32 err, num_rx_queues = adapter->num_rx_queues; + + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + err = pci_enable_device(pdev); + if (err) { + printk(KERN_ERR "ixgbe: Cannot enable PCI device from " \ + "suspend\n"); + return err; + } + pci_set_master(pdev); + + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_enable_wake(pdev, PCI_D3cold, 0); + + if (netif_running(netdev)) { + err = ixgbe_request_irq(adapter, &num_rx_queues); + if (err) + return err; + } + + ixgbe_reset(adapter); + + if (netif_running(netdev)) + ixgbe_up(adapter); + + netif_device_attach(netdev); + + return 0; +} +#endif + +/** + * ixgbe_clean_rx_ring - Free Rx Buffers per Queue + * @adapter: board private structure + * @rx_ring: ring to free buffers from + **/ +static void ixgbe_clean_rx_ring(struct ixgbe_adapter *adapter, + struct ixgbe_ring *rx_ring) +{ + struct pci_dev *pdev = adapter->pdev; + unsigned long size; + unsigned int i; + + /* Free all the Rx ring sk_buffs */ + + for (i = 0; i < rx_ring->count; i++) { + struct ixgbe_rx_buffer *rx_buffer_info; + + rx_buffer_info = &rx_ring->rx_buffer_info[i]; + if (rx_buffer_info->dma) { + pci_unmap_single(pdev, rx_buffer_info->dma, + adapter->rx_buf_len, + PCI_DMA_FROMDEVICE); + rx_buffer_info->dma = 0; + } + if (rx_buffer_info->skb) { + dev_kfree_skb(rx_buffer_info->skb); + rx_buffer_info->skb = NULL; + } + if (!rx_buffer_info->page) + continue; + pci_unmap_page(pdev, rx_buffer_info->page_dma, PAGE_SIZE, + PCI_DMA_FROMDEVICE); + rx_buffer_info->page_dma = 0; + + put_page(rx_buffer_info->page); + rx_buffer_info->page = NULL; + } + + size = sizeof(struct ixgbe_rx_buffer) * rx_ring->count; + memset(rx_ring->rx_buffer_info, 0, size); + + /* Zero out the descriptor ring */ + memset(rx_ring->desc, 0, rx_ring->size); + + rx_ring->next_to_clean = 0; + rx_ring->next_to_use = 0; + + writel(0, adapter->hw.hw_addr + rx_ring->head); + writel(0, adapter->hw.hw_addr + rx_ring->tail); +} + +/** + * ixgbe_clean_tx_ring - Free Tx Buffers + * @adapter: board private structure + * @tx_ring: ring to be cleaned + **/ +static void ixgbe_clean_tx_ring(struct ixgbe_adapter *adapter, + struct ixgbe_ring *tx_ring) +{ + struct ixgbe_tx_buffer *tx_buffer_info; + unsigned long size; + unsigned int i; + + /* Free all the Tx ring sk_buffs */ + + for (i = 0; i < tx_ring->count; i++) { + tx_buffer_info = &tx_ring->tx_buffer_info[i]; + ixgbe_unmap_and_free_tx_resource(adapter, tx_buffer_info); + } + + size = sizeof(struct ixgbe_tx_buffer) * tx_ring->count; + memset(tx_ring->tx_buffer_info, 0, size); + + /* Zero out the descriptor ring */ + memset(tx_ring->desc, 0, tx_ring->size); + + tx_ring->next_to_use = 0; + tx_ring->next_to_clean = 0; + + writel(0, adapter->hw.hw_addr + tx_ring->head); + writel(0, adapter->hw.hw_addr + tx_ring->tail); +} + +/** + * ixgbe_clean_all_tx_rings - Free Tx Buffers for all queues + * @adapter: board private structure + **/ +static void ixgbe_clean_all_tx_rings(struct ixgbe_adapter *adapter) +{ + int i; + + for (i = 0; i < adapter->num_tx_queues; i++) + ixgbe_clean_tx_ring(adapter, &adapter->tx_ring[i]); +} + +/** + * ixgbe_clean_all_rx_rings - Free Rx Buffers for all queues + * @adapter: board private structure + **/ +static void ixgbe_clean_all_rx_rings(struct ixgbe_adapter *adapter) +{ + int i; + + for (i = 0; i < adapter->num_rx_queues; i++) + ixgbe_clean_rx_ring(adapter, &adapter->rx_ring[i]); +} + +void ixgbe_down(struct ixgbe_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + u32 rxctrl; + + /* signal that we are down to the interrupt handler */ + set_bit(__IXGBE_DOWN, &adapter->state); + + /* disable receives */ + rxctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_RXCTRL); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXCTRL, + rxctrl & ~IXGBE_RXCTRL_RXEN); + + netif_tx_disable(netdev); + + /* disable transmits in the hardware */ + + /* flush both disables */ + IXGBE_WRITE_FLUSH(&adapter->hw); + msleep(10); + + ixgbe_irq_disable(adapter); + + napi_disable(&adapter->napi); + del_timer_sync(&adapter->watchdog_timer); + + netif_carrier_off(netdev); + netif_stop_queue(netdev); + + ixgbe_reset(adapter); + ixgbe_clean_all_tx_rings(adapter); + ixgbe_clean_all_rx_rings(adapter); + +} + +static int ixgbe_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct ixgbe_adapter *adapter = netdev_priv(netdev); +#ifdef CONFIG_PM + int retval = 0; +#endif + + netif_device_detach(netdev); + + if (netif_running(netdev)) { + ixgbe_down(adapter); + ixgbe_free_irq(adapter); + } + +#ifdef CONFIG_PM + retval = pci_save_state(pdev); + if (retval) + return retval; +#endif + + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_enable_wake(pdev, PCI_D3cold, 0); + + pci_disable_device(pdev); + + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + + return 0; +} + +static void ixgbe_shutdown(struct pci_dev *pdev) +{ + ixgbe_suspend(pdev, PMSG_SUSPEND); +} + +/** + * ixgbe_clean - NAPI Rx polling callback + * @adapter: board private structure + **/ +static int ixgbe_clean(struct napi_struct *napi, int budget) +{ + struct ixgbe_adapter *adapter = container_of(napi, + struct ixgbe_adapter, napi); + struct net_device *netdev = adapter->netdev; + int tx_cleaned = 0, work_done = 0; + + /* Keep link state information with original netdev */ + if (!netif_carrier_ok(adapter->netdev)) + goto quit_polling; + + /* In non-MSIX case, there is no multi-Tx/Rx queue */ + tx_cleaned = ixgbe_clean_tx_irq(adapter, adapter->tx_ring); + ixgbe_clean_rx_irq(adapter, &adapter->rx_ring[0], &work_done, + budget); + + /* If no Tx and not enough Rx work done, exit the polling mode */ + if ((!tx_cleaned && (work_done < budget)) || + !netif_running(adapter->netdev)) { +quit_polling: + netif_rx_complete(netdev, napi); + ixgbe_irq_enable(adapter); + } + + return work_done; +} + +/** + * ixgbe_tx_timeout - Respond to a Tx Hang + * @netdev: network interface device structure + **/ +static void ixgbe_tx_timeout(struct net_device *netdev) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + /* Do the reset outside of interrupt context */ + schedule_work(&adapter->reset_task); +} + +static void ixgbe_reset_task(struct work_struct *work) +{ + struct ixgbe_adapter *adapter; + adapter = container_of(work, struct ixgbe_adapter, reset_task); + + adapter->tx_timeout_count++; + + ixgbe_down(adapter); + ixgbe_up(adapter); +} + +/** + * ixgbe_alloc_queues - Allocate memory for all rings + * @adapter: board private structure to initialize + * + * We allocate one ring per queue at run-time since we don't know the + * number of queues at compile-time. The polling_netdev array is + * intended for Multiqueue, but should work fine with a single queue. + **/ +static int __devinit ixgbe_alloc_queues(struct ixgbe_adapter *adapter) +{ + int i; + + adapter->tx_ring = kcalloc(adapter->num_tx_queues, + sizeof(struct ixgbe_ring), GFP_KERNEL); + if (!adapter->tx_ring) + return -ENOMEM; + + for (i = 0; i < adapter->num_tx_queues; i++) + adapter->tx_ring[i].count = IXGBE_DEFAULT_TXD; + + adapter->rx_ring = kcalloc(adapter->num_rx_queues, + sizeof(struct ixgbe_ring), GFP_KERNEL); + if (!adapter->rx_ring) { + kfree(adapter->tx_ring); + return -ENOMEM; + } + + for (i = 0; i < adapter->num_rx_queues; i++) { + adapter->rx_ring[i].adapter = adapter; + adapter->rx_ring[i].itr_register = IXGBE_EITR(i); + adapter->rx_ring[i].count = IXGBE_DEFAULT_RXD; + } + + return 0; +} + +/** + * ixgbe_sw_init - Initialize general software structures (struct ixgbe_adapter) + * @adapter: board private structure to initialize + * + * ixgbe_sw_init initializes the Adapter private data structure. + * Fields are initialized based on PCI device information and + * OS network device settings (MTU size). + **/ +static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + struct pci_dev *pdev = adapter->pdev; + + /* default flow control settings */ + hw->fc.original_type = ixgbe_fc_full; + hw->fc.type = ixgbe_fc_full; + + hw->mac.link_mode_select = IXGBE_AUTOC_LMS_10G_LINK_NO_AN; + if (hw->mac.ops.reset(hw)) { + dev_err(&pdev->dev, "HW Init failed\n"); + return -EIO; + } + if (hw->phy.ops.setup_speed(hw, IXGBE_LINK_SPEED_10GB_FULL, true, + false)) { + dev_err(&pdev->dev, "Link Speed setup failed\n"); + return -EIO; + } + + /* initialize eeprom parameters */ + if (ixgbe_init_eeprom(hw)) { + dev_err(&pdev->dev, "EEPROM initialization failed\n"); + return -EIO; + } + + /* Set the default values */ + adapter->num_rx_queues = IXGBE_DEFAULT_RXQ; + adapter->num_tx_queues = 1; + adapter->flags |= IXGBE_FLAG_RX_CSUM_ENABLED; + + if (ixgbe_alloc_queues(adapter)) { + dev_err(&pdev->dev, "Unable to allocate memory for queues\n"); + return -ENOMEM; + } + + atomic_set(&adapter->irq_sem, 1); + set_bit(__IXGBE_DOWN, &adapter->state); + + return 0; +} + +/** + * ixgbe_setup_tx_resources - allocate Tx resources (Descriptors) + * @adapter: board private structure + * @txdr: tx descriptor ring (for a specific queue) to setup + * + * Return 0 on success, negative on failure + **/ +int ixgbe_setup_tx_resources(struct ixgbe_adapter *adapter, + struct ixgbe_ring *txdr) +{ + struct pci_dev *pdev = adapter->pdev; + int size; + + size = sizeof(struct ixgbe_tx_buffer) * txdr->count; + txdr->tx_buffer_info = vmalloc(size); + if (!txdr->tx_buffer_info) { + DPRINTK(PROBE, ERR, + "Unable to allocate memory for the transmit descriptor ring\n"); + return -ENOMEM; + } + memset(txdr->tx_buffer_info, 0, size); + + /* round up to nearest 4K */ + txdr->size = txdr->count * sizeof(union ixgbe_adv_tx_desc); + txdr->size = ALIGN(txdr->size, 4096); + + txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma); + if (!txdr->desc) { + vfree(txdr->tx_buffer_info); + DPRINTK(PROBE, ERR, + "Memory allocation failed for the tx desc ring\n"); + return -ENOMEM; + } + + txdr->adapter = adapter; + txdr->next_to_use = 0; + txdr->next_to_clean = 0; + txdr->work_limit = txdr->count; + spin_lock_init(&txdr->tx_lock); + + return 0; +} + +/** + * ixgbe_setup_rx_resources - allocate Rx resources (Descriptors) + * @adapter: board private structure + * @rxdr: rx descriptor ring (for a specific queue) to setup + * + * Returns 0 on success, negative on failure + **/ +int ixgbe_setup_rx_resources(struct ixgbe_adapter *adapter, + struct ixgbe_ring *rxdr) +{ + struct pci_dev *pdev = adapter->pdev; + int size, desc_len; + + size = sizeof(struct ixgbe_rx_buffer) * rxdr->count; + rxdr->rx_buffer_info = vmalloc(size); + if (!rxdr->rx_buffer_info) { + DPRINTK(PROBE, ERR, + "vmalloc allocation failed for the rx desc ring\n"); + return -ENOMEM; + } + memset(rxdr->rx_buffer_info, 0, size); + + desc_len = sizeof(union ixgbe_adv_rx_desc); + + /* Round up to nearest 4K */ + rxdr->size = rxdr->count * desc_len; + rxdr->size = ALIGN(rxdr->size, 4096); + + rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma); + + if (!rxdr->desc) { + DPRINTK(PROBE, ERR, + "Memory allocation failed for the rx desc ring\n"); + vfree(rxdr->rx_buffer_info); + return -ENOMEM; + } + + rxdr->next_to_clean = 0; + rxdr->next_to_use = 0; + rxdr->adapter = adapter; + + return 0; +} + +/** + * ixgbe_free_tx_resources - Free Tx Resources per Queue + * @adapter: board private structure + * @tx_ring: Tx descriptor ring for a specific queue + * + * Free all transmit software resources + **/ +static void ixgbe_free_tx_resources(struct ixgbe_adapter *adapter, + struct ixgbe_ring *tx_ring) +{ + struct pci_dev *pdev = adapter->pdev; + + ixgbe_clean_tx_ring(adapter, tx_ring); + + vfree(tx_ring->tx_buffer_info); + tx_ring->tx_buffer_info = NULL; + + pci_free_consistent(pdev, tx_ring->size, tx_ring->desc, tx_ring->dma); + + tx_ring->desc = NULL; +} + +/** + * ixgbe_free_all_tx_resources - Free Tx Resources for All Queues + * @adapter: board private structure + * + * Free all transmit software resources + **/ +static void ixgbe_free_all_tx_resources(struct ixgbe_adapter *adapter) +{ + int i; + + for (i = 0; i < adapter->num_tx_queues; i++) + ixgbe_free_tx_resources(adapter, &adapter->tx_ring[i]); +} + +/** + * ixgbe_free_rx_resources - Free Rx Resources + * @adapter: board private structure + * @rx_ring: ring to clean the resources from + * + * Free all receive software resources + **/ +static void ixgbe_free_rx_resources(struct ixgbe_adapter *adapter, + struct ixgbe_ring *rx_ring) +{ + struct pci_dev *pdev = adapter->pdev; + + ixgbe_clean_rx_ring(adapter, rx_ring); + + vfree(rx_ring->rx_buffer_info); + rx_ring->rx_buffer_info = NULL; + + pci_free_consistent(pdev, rx_ring->size, rx_ring->desc, rx_ring->dma); + + rx_ring->desc = NULL; +} + +/** + * ixgbe_free_all_rx_resources - Free Rx Resources for All Queues + * @adapter: board private structure + * + * Free all receive software resources + **/ +static void ixgbe_free_all_rx_resources(struct ixgbe_adapter *adapter) +{ + int i; + + for (i = 0; i < adapter->num_rx_queues; i++) + ixgbe_free_rx_resources(adapter, &adapter->rx_ring[i]); +} + +/** + * ixgbe_setup_all_tx_resources - wrapper to allocate Tx resources + * (Descriptors) for all queues + * @adapter: board private structure + * + * If this function returns with an error, then it's possible one or + * more of the rings is populated (while the rest are not). It is the + * callers duty to clean those orphaned rings. + * + * Return 0 on success, negative on failure + **/ +static int ixgbe_setup_all_tx_resources(struct ixgbe_adapter *adapter) +{ + int i, err = 0; + + for (i = 0; i < adapter->num_tx_queues; i++) { + err = ixgbe_setup_tx_resources(adapter, &adapter->tx_ring[i]); + if (err) { + DPRINTK(PROBE, ERR, + "Allocation for Tx Queue %u failed\n", i); + break; + } + } + + return err; +} + +/** + * ixgbe_setup_all_rx_resources - wrapper to allocate Rx resources + * (Descriptors) for all queues + * @adapter: board private structure + * + * If this function returns with an error, then it's possible one or + * more of the rings is populated (while the rest are not). It is the + * callers duty to clean those orphaned rings. + * + * Return 0 on success, negative on failure + **/ + +static int ixgbe_setup_all_rx_resources(struct ixgbe_adapter *adapter) +{ + int i, err = 0; + + for (i = 0; i < adapter->num_rx_queues; i++) { + err = ixgbe_setup_rx_resources(adapter, &adapter->rx_ring[i]); + if (err) { + DPRINTK(PROBE, ERR, + "Allocation for Rx Queue %u failed\n", i); + break; + } + } + + return err; +} + +/** + * ixgbe_change_mtu - Change the Maximum Transfer Unit + * @netdev: network interface device structure + * @new_mtu: new value for maximum frame size + * + * Returns 0 on success, negative on failure + **/ +static int ixgbe_change_mtu(struct net_device *netdev, int new_mtu) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN; + + if ((max_frame < (ETH_ZLEN + ETH_FCS_LEN)) || + (max_frame > IXGBE_MAX_JUMBO_FRAME_SIZE)) + return -EINVAL; + + netdev->mtu = new_mtu; + + if (netif_running(netdev)) { + ixgbe_down(adapter); + ixgbe_up(adapter); + } + + return 0; +} + +/** + * ixgbe_open - Called when a network interface is made active + * @netdev: network interface device structure + * + * Returns 0 on success, negative value on failure + * + * The open entry point is called when a network interface is made + * active by the system (IFF_UP). At this point all resources needed + * for transmit and receive operations are allocated, the interrupt + * handler is registered with the OS, the watchdog timer is started, + * and the stack is notified that the interface is ready. + **/ +static int ixgbe_open(struct net_device *netdev) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + int err; + u32 ctrl_ext; + u32 num_rx_queues = adapter->num_rx_queues; + + /* Let firmware know the driver has taken over */ + ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT, + ctrl_ext | IXGBE_CTRL_EXT_DRV_LOAD); + +try_intr_reinit: + /* allocate transmit descriptors */ + err = ixgbe_setup_all_tx_resources(adapter); + if (err) + goto err_setup_tx; + + if (!(adapter->flags & IXGBE_FLAG_MSIX_ENABLED)) { + num_rx_queues = 1; + adapter->num_rx_queues = num_rx_queues; + } + + /* allocate receive descriptors */ + err = ixgbe_setup_all_rx_resources(adapter); + if (err) + goto err_setup_rx; + + ixgbe_configure(adapter); + + err = ixgbe_request_irq(adapter, &num_rx_queues); + if (err) + goto err_req_irq; + + /* ixgbe_request might have reduced num_rx_queues */ + if (num_rx_queues < adapter->num_rx_queues) { + /* We didn't get MSI-X, so we need to release everything, + * set our Rx queue count to num_rx_queues, and redo the + * whole init process. + */ + ixgbe_free_irq(adapter); + if (adapter->flags & IXGBE_FLAG_MSI_ENABLED) { + pci_disable_msi(adapter->pdev); + adapter->flags &= ~IXGBE_FLAG_MSI_ENABLED; + } + ixgbe_free_all_rx_resources(adapter); + ixgbe_free_all_tx_resources(adapter); + adapter->num_rx_queues = num_rx_queues; + + /* Reset the hardware, and start over. */ + ixgbe_reset(adapter); + + goto try_intr_reinit; + } + + err = ixgbe_up_complete(adapter); + if (err) + goto err_up; + + return 0; + +err_up: + ixgbe_free_irq(adapter); +err_req_irq: + ixgbe_free_all_rx_resources(adapter); +err_setup_rx: + ixgbe_free_all_tx_resources(adapter); +err_setup_tx: + ixgbe_reset(adapter); + + return err; +} + +/** + * ixgbe_close - Disables a network interface + * @netdev: network interface device structure + * + * Returns 0, this is not allowed to fail + * + * The close entry point is called when an interface is de-activated + * by the OS. The hardware is still under the drivers control, but + * needs to be disabled. A global MAC reset is issued to stop the + * hardware, and all transmit and receive resources are freed. + **/ +static int ixgbe_close(struct net_device *netdev) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + u32 ctrl_ext; + + ixgbe_down(adapter); + ixgbe_free_irq(adapter); + + ixgbe_free_all_tx_resources(adapter); + ixgbe_free_all_rx_resources(adapter); + + ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT, + ctrl_ext & ~IXGBE_CTRL_EXT_DRV_LOAD); + + return 0; +} + +/** + * ixgbe_update_stats - Update the board statistics counters. + * @adapter: board private structure + **/ +void ixgbe_update_stats(struct ixgbe_adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + u64 good_rx, missed_rx, bprc; + + adapter->stats.crcerrs += IXGBE_READ_REG(hw, IXGBE_CRCERRS); + good_rx = IXGBE_READ_REG(hw, IXGBE_GPRC); + missed_rx = IXGBE_READ_REG(hw, IXGBE_MPC(0)); + missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(1)); + missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(2)); + missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(3)); + missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(4)); + missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(5)); + missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(6)); + missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(7)); + adapter->stats.gprc += (good_rx - missed_rx); + + adapter->stats.mpc[0] += missed_rx; + adapter->stats.gorc += IXGBE_READ_REG(hw, IXGBE_GORCH); + bprc = IXGBE_READ_REG(hw, IXGBE_BPRC); + adapter->stats.bprc += bprc; + adapter->stats.mprc += IXGBE_READ_REG(hw, IXGBE_MPRC); + adapter->stats.mprc -= bprc; + adapter->stats.roc += IXGBE_READ_REG(hw, IXGBE_ROC); + adapter->stats.prc64 += IXGBE_READ_REG(hw, IXGBE_PRC64); + adapter->stats.prc127 += IXGBE_READ_REG(hw, IXGBE_PRC127); + adapter->stats.prc255 += IXGBE_READ_REG(hw, IXGBE_PRC255); + adapter->stats.prc511 += IXGBE_READ_REG(hw, IXGBE_PRC511); + adapter->stats.prc1023 += IXGBE_READ_REG(hw, IXGBE_PRC1023); + adapter->stats.prc1522 += IXGBE_READ_REG(hw, IXGBE_PRC1522); + + adapter->stats.rlec += IXGBE_READ_REG(hw, IXGBE_RLEC); + adapter->stats.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXC); + adapter->stats.lxontxc += IXGBE_READ_REG(hw, IXGBE_LXONTXC); + adapter->stats.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXC); + adapter->stats.lxofftxc += IXGBE_READ_REG(hw, IXGBE_LXOFFTXC); + adapter->stats.ruc += IXGBE_READ_REG(hw, IXGBE_RUC); + adapter->stats.gptc += IXGBE_READ_REG(hw, IXGBE_GPTC); + adapter->stats.gotc += IXGBE_READ_REG(hw, IXGBE_GOTCH); + adapter->stats.rnbc[0] += IXGBE_READ_REG(hw, IXGBE_RNBC(0)); + adapter->stats.ruc += IXGBE_READ_REG(hw, IXGBE_RUC); + adapter->stats.rfc += IXGBE_READ_REG(hw, IXGBE_RFC); + adapter->stats.rjc += IXGBE_READ_REG(hw, IXGBE_RJC); + adapter->stats.tor += IXGBE_READ_REG(hw, IXGBE_TORH); + adapter->stats.tpr += IXGBE_READ_REG(hw, IXGBE_TPR); + adapter->stats.ptc64 += IXGBE_READ_REG(hw, IXGBE_PTC64); + adapter->stats.ptc127 += IXGBE_READ_REG(hw, IXGBE_PTC127); + adapter->stats.ptc255 += IXGBE_READ_REG(hw, IXGBE_PTC255); + adapter->stats.ptc511 += IXGBE_READ_REG(hw, IXGBE_PTC511); + adapter->stats.ptc1023 += IXGBE_READ_REG(hw, IXGBE_PTC1023); + adapter->stats.ptc1522 += IXGBE_READ_REG(hw, IXGBE_PTC1522); + adapter->stats.mptc += IXGBE_READ_REG(hw, IXGBE_MPTC); + adapter->stats.bptc += IXGBE_READ_REG(hw, IXGBE_BPTC); + + /* Fill out the OS statistics structure */ + adapter->net_stats.rx_packets = adapter->stats.gprc; + adapter->net_stats.tx_packets = adapter->stats.gptc; + adapter->net_stats.rx_bytes = adapter->stats.gorc; + adapter->net_stats.tx_bytes = adapter->stats.gotc; + adapter->net_stats.multicast = adapter->stats.mprc; + + /* Rx Errors */ + adapter->net_stats.rx_errors = adapter->stats.crcerrs + + adapter->stats.rlec; + adapter->net_stats.rx_dropped = 0; + adapter->net_stats.rx_length_errors = adapter->stats.rlec; + adapter->net_stats.rx_crc_errors = adapter->stats.crcerrs; + adapter->net_stats.rx_missed_errors = adapter->stats.mpc[0]; + +} + +/** + * ixgbe_watchdog - Timer Call-back + * @data: pointer to adapter cast into an unsigned long + **/ +static void ixgbe_watchdog(unsigned long data) +{ + struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)data; + struct net_device *netdev = adapter->netdev; + bool link_up; + u32 link_speed = 0; + + adapter->hw.phy.ops.check(&adapter->hw, &(link_speed), &link_up); + + if (link_up) { + if (!netif_carrier_ok(netdev)) { + u32 frctl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL); + u32 rmcs = IXGBE_READ_REG(&adapter->hw, IXGBE_RMCS); +#define FLOW_RX (frctl & IXGBE_FCTRL_RFCE) +#define FLOW_TX (rmcs & IXGBE_RMCS_TFCE_802_3X) + DPRINTK(LINK, INFO, "NIC Link is Up %s, " + "Flow Control: %s\n", + (link_speed == IXGBE_LINK_SPEED_10GB_FULL ? + "10 Gbps" : + (link_speed == IXGBE_LINK_SPEED_1GB_FULL ? + "1 Gpbs" : "unknown speed")), + ((FLOW_RX && FLOW_TX) ? "RX/TX" : + (FLOW_RX ? "RX" : + (FLOW_TX ? "TX" : "None")))); + + netif_carrier_on(netdev); + netif_wake_queue(netdev); + } else { + /* Force detection of hung controller */ + adapter->detect_tx_hung = true; + } + } else { + if (netif_carrier_ok(netdev)) { + DPRINTK(LINK, INFO, "NIC Link is Down\n"); + netif_carrier_off(netdev); + netif_stop_queue(netdev); + } + } + + ixgbe_update_stats(adapter); + + /* Reset the timer */ + if (!test_bit(__IXGBE_DOWN, &adapter->state)) + mod_timer(&adapter->watchdog_timer, + round_jiffies(jiffies + 2 * HZ)); +} + +#define IXGBE_MAX_TXD_PWR 14 +#define IXGBE_MAX_DATA_PER_TXD (1 << IXGBE_MAX_TXD_PWR) + +/* Tx Descriptors needed, worst case */ +#define TXD_USE_COUNT(S) (((S) >> IXGBE_MAX_TXD_PWR) + \ + (((S) & (IXGBE_MAX_DATA_PER_TXD - 1)) ? 1 : 0)) +#define DESC_NEEDED (TXD_USE_COUNT(IXGBE_MAX_DATA_PER_TXD) /* skb->data */ + \ + MAX_SKB_FRAGS * TXD_USE_COUNT(PAGE_SIZE) + 1) /* for context */ + +static int ixgbe_tso(struct ixgbe_adapter *adapter, + struct ixgbe_ring *tx_ring, struct sk_buff *skb, + u32 tx_flags, u8 *hdr_len) +{ + struct ixgbe_adv_tx_context_desc *context_desc; + unsigned int i; + int err; + struct ixgbe_tx_buffer *tx_buffer_info; + u32 vlan_macip_lens = 0, type_tucmd_mlhl = 0; + u32 mss_l4len_idx = 0, l4len; + *hdr_len = 0; + + if (skb_is_gso(skb)) { + if (skb_header_cloned(skb)) { + err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC); + if (err) + return err; + } + l4len = tcp_hdrlen(skb); + *hdr_len += l4len; + + if (skb->protocol == ntohs(ETH_P_IP)) { + struct iphdr *iph = ip_hdr(skb); + iph->tot_len = 0; + iph->check = 0; + tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr, + iph->daddr, 0, + IPPROTO_TCP, + 0); + adapter->hw_tso_ctxt++; + } else if (skb_shinfo(skb)->gso_type == SKB_GSO_TCPV6) { + ipv6_hdr(skb)->payload_len = 0; + tcp_hdr(skb)->check = + ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, + &ipv6_hdr(skb)->daddr, + 0, IPPROTO_TCP, 0); + adapter->hw_tso6_ctxt++; + } + + i = tx_ring->next_to_use; + + tx_buffer_info = &tx_ring->tx_buffer_info[i]; + context_desc = IXGBE_TX_CTXTDESC_ADV(*tx_ring, i); + + /* VLAN MACLEN IPLEN */ + if (tx_flags & IXGBE_TX_FLAGS_VLAN) + vlan_macip_lens |= + (tx_flags & IXGBE_TX_FLAGS_VLAN_MASK); + vlan_macip_lens |= ((skb_network_offset(skb)) << + IXGBE_ADVTXD_MACLEN_SHIFT); + *hdr_len += skb_network_offset(skb); + vlan_macip_lens |= + (skb_transport_header(skb) - skb_network_header(skb)); + *hdr_len += + (skb_transport_header(skb) - skb_network_header(skb)); + context_desc->vlan_macip_lens = cpu_to_le32(vlan_macip_lens); + context_desc->seqnum_seed = 0; + + /* ADV DTYP TUCMD MKRLOC/ISCSIHEDLEN */ + type_tucmd_mlhl |= (IXGBE_TXD_CMD_DEXT | + IXGBE_ADVTXD_DTYP_CTXT); + + if (skb->protocol == ntohs(ETH_P_IP)) + type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV4; + type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_TCP; + context_desc->type_tucmd_mlhl = cpu_to_le32(type_tucmd_mlhl); + + /* MSS L4LEN IDX */ + mss_l4len_idx |= + (skb_shinfo(skb)->gso_size << IXGBE_ADVTXD_MSS_SHIFT); + mss_l4len_idx |= (l4len << IXGBE_ADVTXD_L4LEN_SHIFT); + context_desc->mss_l4len_idx = cpu_to_le32(mss_l4len_idx); + + tx_buffer_info->time_stamp = jiffies; + tx_buffer_info->next_to_watch = i; + + i++; + if (i == tx_ring->count) + i = 0; + tx_ring->next_to_use = i; + + return true; + } + return false; +} + +static bool ixgbe_tx_csum(struct ixgbe_adapter *adapter, + struct ixgbe_ring *tx_ring, + struct sk_buff *skb, u32 tx_flags) +{ + struct ixgbe_adv_tx_context_desc *context_desc; + unsigned int i; + struct ixgbe_tx_buffer *tx_buffer_info; + u32 vlan_macip_lens = 0, type_tucmd_mlhl = 0; + + if (skb->ip_summed == CHECKSUM_PARTIAL || + (tx_flags & IXGBE_TX_FLAGS_VLAN)) { + i = tx_ring->next_to_use; + tx_buffer_info = &tx_ring->tx_buffer_info[i]; + context_desc = IXGBE_TX_CTXTDESC_ADV(*tx_ring, i); + + if (tx_flags & IXGBE_TX_FLAGS_VLAN) + vlan_macip_lens |= + (tx_flags & IXGBE_TX_FLAGS_VLAN_MASK); + vlan_macip_lens |= (skb_network_offset(skb) << + IXGBE_ADVTXD_MACLEN_SHIFT); + if (skb->ip_summed == CHECKSUM_PARTIAL) + vlan_macip_lens |= (skb_transport_header(skb) - + skb_network_header(skb)); + + context_desc->vlan_macip_lens = cpu_to_le32(vlan_macip_lens); + context_desc->seqnum_seed = 0; + + type_tucmd_mlhl |= (IXGBE_TXD_CMD_DEXT | + IXGBE_ADVTXD_DTYP_CTXT); + + if (skb->ip_summed == CHECKSUM_PARTIAL) { + if (skb->protocol == ntohs(ETH_P_IP)) + type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV4; + + if (skb->sk->sk_protocol == IPPROTO_TCP) + type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_TCP; + } + + context_desc->type_tucmd_mlhl = cpu_to_le32(type_tucmd_mlhl); + context_desc->mss_l4len_idx = 0; + + tx_buffer_info->time_stamp = jiffies; + tx_buffer_info->next_to_watch = i; + adapter->hw_csum_tx_good++; + i++; + if (i == tx_ring->count) + i = 0; + tx_ring->next_to_use = i; + + return true; + } + return false; +} + +static int ixgbe_tx_map(struct ixgbe_adapter *adapter, + struct ixgbe_ring *tx_ring, + struct sk_buff *skb, unsigned int first) +{ + struct ixgbe_tx_buffer *tx_buffer_info; + unsigned int len = skb->len; + unsigned int offset = 0, size, count = 0, i; + unsigned int nr_frags = skb_shinfo(skb)->nr_frags; + unsigned int f; + + len -= skb->data_len; + + i = tx_ring->next_to_use; + + while (len) { + tx_buffer_info = &tx_ring->tx_buffer_info[i]; + size = min(len, (uint)IXGBE_MAX_DATA_PER_TXD); + + tx_buffer_info->length = size; + tx_buffer_info->dma = pci_map_single(adapter->pdev, + skb->data + offset, + size, PCI_DMA_TODEVICE); + tx_buffer_info->time_stamp = jiffies; + tx_buffer_info->next_to_watch = i; + + len -= size; + offset += size; + count++; + i++; + if (i == tx_ring->count) + i = 0; + } + + for (f = 0; f < nr_frags; f++) { + struct skb_frag_struct *frag; + + frag = &skb_shinfo(skb)->frags[f]; + len = frag->size; + offset = frag->page_offset; + + while (len) { + tx_buffer_info = &tx_ring->tx_buffer_info[i]; + size = min(len, (uint)IXGBE_MAX_DATA_PER_TXD); + + tx_buffer_info->length = size; + tx_buffer_info->dma = pci_map_page(adapter->pdev, + frag->page, + offset, + size, PCI_DMA_TODEVICE); + tx_buffer_info->time_stamp = jiffies; + tx_buffer_info->next_to_watch = i; + + len -= size; + offset += size; + count++; + i++; + if (i == tx_ring->count) + i = 0; + } + } + if (i == 0) + i = tx_ring->count - 1; + else + i = i - 1; + tx_ring->tx_buffer_info[i].skb = skb; + tx_ring->tx_buffer_info[first].next_to_watch = i; + + return count; +} + +static void ixgbe_tx_queue(struct ixgbe_adapter *adapter, + struct ixgbe_ring *tx_ring, + int tx_flags, int count, u32 paylen, u8 hdr_len) +{ + union ixgbe_adv_tx_desc *tx_desc = NULL; + struct ixgbe_tx_buffer *tx_buffer_info; + u32 olinfo_status = 0, cmd_type_len = 0; + unsigned int i; + u32 txd_cmd = IXGBE_TXD_CMD_EOP | IXGBE_TXD_CMD_RS | IXGBE_TXD_CMD_IFCS; + + cmd_type_len |= IXGBE_ADVTXD_DTYP_DATA; + + cmd_type_len |= IXGBE_ADVTXD_DCMD_IFCS | IXGBE_ADVTXD_DCMD_DEXT; + + if (tx_flags & IXGBE_TX_FLAGS_VLAN) + cmd_type_len |= IXGBE_ADVTXD_DCMD_VLE; + + if (tx_flags & IXGBE_TX_FLAGS_TSO) { + cmd_type_len |= IXGBE_ADVTXD_DCMD_TSE; + + olinfo_status |= IXGBE_TXD_POPTS_TXSM << + IXGBE_ADVTXD_POPTS_SHIFT; + + if (tx_flags & IXGBE_TX_FLAGS_IPV4) + olinfo_status |= IXGBE_TXD_POPTS_IXSM << + IXGBE_ADVTXD_POPTS_SHIFT; + + } else if (tx_flags & IXGBE_TX_FLAGS_CSUM) + olinfo_status |= IXGBE_TXD_POPTS_TXSM << + IXGBE_ADVTXD_POPTS_SHIFT; + + olinfo_status |= ((paylen - hdr_len) << IXGBE_ADVTXD_PAYLEN_SHIFT); + + i = tx_ring->next_to_use; + while (count--) { + tx_buffer_info = &tx_ring->tx_buffer_info[i]; + tx_desc = IXGBE_TX_DESC_ADV(*tx_ring, i); + tx_desc->read.buffer_addr = cpu_to_le64(tx_buffer_info->dma); + tx_desc->read.cmd_type_len = + cpu_to_le32(cmd_type_len | tx_buffer_info->length); + tx_desc->read.olinfo_status = cpu_to_le32(olinfo_status); + + i++; + if (i == tx_ring->count) + i = 0; + } + + tx_desc->read.cmd_type_len |= cpu_to_le32(txd_cmd); + + /* + * Force memory writes to complete before letting h/w + * know there are new descriptors to fetch. (Only + * applicable for weak-ordered memory model archs, + * such as IA-64). + */ + wmb(); + + tx_ring->next_to_use = i; + writel(i, adapter->hw.hw_addr + tx_ring->tail); +} + +static int ixgbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_ring *tx_ring; + unsigned int len = skb->len; + unsigned int first; + unsigned int tx_flags = 0; + unsigned long flags = 0; + u8 hdr_len; + int tso; + unsigned int mss = 0; + int count = 0; + unsigned int f; + unsigned int nr_frags = skb_shinfo(skb)->nr_frags; + len -= skb->data_len; + + tx_ring = adapter->tx_ring; + + if (skb->len <= 0) { + dev_kfree_skb(skb); + return NETDEV_TX_OK; + } + mss = skb_shinfo(skb)->gso_size; + + if (mss) + count++; + else if (skb->ip_summed == CHECKSUM_PARTIAL) + count++; + + count += TXD_USE_COUNT(len); + for (f = 0; f < nr_frags; f++) + count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size); + + spin_lock_irqsave(&tx_ring->tx_lock, flags); + if (IXGBE_DESC_UNUSED(tx_ring) < (count + 2)) { + adapter->tx_busy++; + netif_stop_queue(netdev); + spin_unlock_irqrestore(&tx_ring->tx_lock, flags); + return NETDEV_TX_BUSY; + } + spin_unlock_irqrestore(&tx_ring->tx_lock, flags); + if (adapter->vlgrp && vlan_tx_tag_present(skb)) { + tx_flags |= IXGBE_TX_FLAGS_VLAN; + tx_flags |= (vlan_tx_tag_get(skb) << IXGBE_TX_FLAGS_VLAN_SHIFT); + } + + if (skb->protocol == ntohs(ETH_P_IP)) + tx_flags |= IXGBE_TX_FLAGS_IPV4; + first = tx_ring->next_to_use; + tso = ixgbe_tso(adapter, tx_ring, skb, tx_flags, &hdr_len); + if (tso < 0) { + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + + if (tso) + tx_flags |= IXGBE_TX_FLAGS_TSO; + else if (ixgbe_tx_csum(adapter, tx_ring, skb, tx_flags) && + (skb->ip_summed == CHECKSUM_PARTIAL)) + tx_flags |= IXGBE_TX_FLAGS_CSUM; + + ixgbe_tx_queue(adapter, tx_ring, tx_flags, + ixgbe_tx_map(adapter, tx_ring, skb, first), + skb->len, hdr_len); + + netdev->trans_start = jiffies; + + spin_lock_irqsave(&tx_ring->tx_lock, flags); + /* Make sure there is space in the ring for the next send. */ + if (IXGBE_DESC_UNUSED(tx_ring) < DESC_NEEDED) + netif_stop_queue(netdev); + spin_unlock_irqrestore(&tx_ring->tx_lock, flags); + + return NETDEV_TX_OK; +} + +/** + * ixgbe_get_stats - Get System Network Statistics + * @netdev: network interface device structure + * + * Returns the address of the device statistics structure. + * The statistics are actually updated from the timer callback. + **/ +static struct net_device_stats *ixgbe_get_stats(struct net_device *netdev) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + /* only return the current stats */ + return &adapter->net_stats; +} + +/** + * ixgbe_set_mac - Change the Ethernet Address of the NIC + * @netdev: network interface device structure + * @p: pointer to an address structure + * + * Returns 0 on success, negative on failure + **/ +static int ixgbe_set_mac(struct net_device *netdev, void *p) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct sockaddr *addr = p; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; + + memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); + memcpy(adapter->hw.mac.addr, addr->sa_data, netdev->addr_len); + + ixgbe_set_rar(&adapter->hw, 0, adapter->hw.mac.addr, 0, IXGBE_RAH_AV); + + return 0; +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +/* + * Polling 'interrupt' - used by things like netconsole to send skbs + * without having to re-enable interrupts. It's not called while + * the interrupt routine is executing. + */ +static void ixgbe_netpoll(struct net_device *netdev) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + disable_irq(adapter->pdev->irq); + adapter->flags |= IXGBE_FLAG_IN_NETPOLL; + ixgbe_intr(adapter->pdev->irq, netdev); + adapter->flags &= ~IXGBE_FLAG_IN_NETPOLL; + enable_irq(adapter->pdev->irq); +} +#endif + +/** + * ixgbe_probe - Device Initialization Routine + * @pdev: PCI device information struct + * @ent: entry in ixgbe_pci_tbl + * + * Returns 0 on success, negative on failure + * + * ixgbe_probe initializes an adapter identified by a pci_dev structure. + * The OS initialization, configuring of the adapter private structure, + * and a hardware reset occur. + **/ +static int __devinit ixgbe_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct net_device *netdev; + struct ixgbe_adapter *adapter = NULL; + struct ixgbe_hw *hw; + const struct ixgbe_info *ii = ixgbe_info_tbl[ent->driver_data]; + unsigned long mmio_start, mmio_len; + static int cards_found; + int i, err, pci_using_dac; + u16 link_status, link_speed, link_width; + u32 part_num; + + err = pci_enable_device(pdev); + if (err) + return err; + + if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK) && + !pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) { + pci_using_dac = 1; + } else { + err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (err) { + err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); + if (err) { + dev_err(&pdev->dev, "No usable DMA " + "configuration, aborting\n"); + goto err_dma; + } + } + pci_using_dac = 0; + } + + err = pci_request_regions(pdev, ixgbe_driver_name); + if (err) { + dev_err(&pdev->dev, "pci_request_regions failed 0x%x\n", err); + goto err_pci_reg; + } + + pci_set_master(pdev); + + netdev = alloc_etherdev(sizeof(struct ixgbe_adapter)); + if (!netdev) { + err = -ENOMEM; + goto err_alloc_etherdev; + } + + SET_MODULE_OWNER(netdev); + SET_NETDEV_DEV(netdev, &pdev->dev); + + pci_set_drvdata(pdev, netdev); + adapter = netdev_priv(netdev); + + adapter->netdev = netdev; + adapter->pdev = pdev; + hw = &adapter->hw; + hw->back = adapter; + adapter->msg_enable = (1 << DEFAULT_DEBUG_LEVEL_SHIFT) - 1; + + mmio_start = pci_resource_start(pdev, 0); + mmio_len = pci_resource_len(pdev, 0); + + hw->hw_addr = ioremap(mmio_start, mmio_len); + if (!hw->hw_addr) { + err = -EIO; + goto err_ioremap; + } + + for (i = 1; i <= 5; i++) { + if (pci_resource_len(pdev, i) == 0) + continue; + } + + netdev->open = &ixgbe_open; + netdev->stop = &ixgbe_close; + netdev->hard_start_xmit = &ixgbe_xmit_frame; + netdev->get_stats = &ixgbe_get_stats; + netdev->set_multicast_list = &ixgbe_set_multi; + netdev->set_mac_address = &ixgbe_set_mac; + netdev->change_mtu = &ixgbe_change_mtu; + ixgbe_set_ethtool_ops(netdev); + netdev->tx_timeout = &ixgbe_tx_timeout; + netdev->watchdog_timeo = 5 * HZ; + netif_napi_add(netdev, &adapter->napi, ixgbe_clean, 64); + netdev->vlan_rx_register = ixgbe_vlan_rx_register; + netdev->vlan_rx_add_vid = ixgbe_vlan_rx_add_vid; + netdev->vlan_rx_kill_vid = ixgbe_vlan_rx_kill_vid; +#ifdef CONFIG_NET_POLL_CONTROLLER + netdev->poll_controller = ixgbe_netpoll; +#endif + strcpy(netdev->name, pci_name(pdev)); + + netdev->mem_start = mmio_start; + netdev->mem_end = mmio_start + mmio_len; + + adapter->bd_number = cards_found; + + /* PCI config space info */ + hw->vendor_id = pdev->vendor; + hw->device_id = pdev->device; + hw->revision_id = pdev->revision; + hw->subsystem_vendor_id = pdev->subsystem_vendor; + hw->subsystem_device_id = pdev->subsystem_device; + + /* Setup hw api */ + memcpy(&hw->mac.ops, ii->mac_ops, sizeof(hw->mac.ops)); + memcpy(&hw->phy.ops, ii->phy_ops, sizeof(hw->phy.ops)); + + err = ii->get_invariants(hw); + if (err) + goto err_hw_init; + + /* setup the private structure */ + err = ixgbe_sw_init(adapter); + if (err) + goto err_sw_init; + + netdev->features = NETIF_F_SG | + NETIF_F_HW_CSUM | + NETIF_F_HW_VLAN_TX | + NETIF_F_HW_VLAN_RX | + NETIF_F_HW_VLAN_FILTER; + + netdev->features |= NETIF_F_TSO; + + netdev->features |= NETIF_F_TSO6; + if (pci_using_dac) + netdev->features |= NETIF_F_HIGHDMA; + + + /* make sure the EEPROM is good */ + if (ixgbe_validate_eeprom_checksum(hw, NULL) < 0) { + dev_err(&pdev->dev, "The EEPROM Checksum Is Not Valid\n"); + err = -EIO; + goto err_eeprom; + } + + memcpy(netdev->dev_addr, hw->mac.perm_addr, netdev->addr_len); + memcpy(netdev->perm_addr, hw->mac.perm_addr, netdev->addr_len); + + if (ixgbe_validate_mac_addr(netdev->dev_addr)) { + err = -EIO; + goto err_eeprom; + } + + init_timer(&adapter->watchdog_timer); + adapter->watchdog_timer.function = &ixgbe_watchdog; + adapter->watchdog_timer.data = (unsigned long)adapter; + + INIT_WORK(&adapter->reset_task, ixgbe_reset_task); + + /* initialize default flow control settings */ + hw->fc.original_type = ixgbe_fc_full; + hw->fc.type = ixgbe_fc_full; + hw->fc.high_water = IXGBE_DEFAULT_FCRTH; + hw->fc.low_water = IXGBE_DEFAULT_FCRTL; + hw->fc.pause_time = IXGBE_DEFAULT_FCPAUSE; + + /* Interrupt Throttle Rate */ + adapter->rx_eitr = (1000000 / IXGBE_DEFAULT_ITR_RX_USECS); + adapter->tx_eitr = (1000000 / IXGBE_DEFAULT_ITR_TX_USECS); + + /* print bus type/speed/width info */ + pci_read_config_word(pdev, IXGBE_PCI_LINK_STATUS, &link_status); + link_speed = link_status & IXGBE_PCI_LINK_SPEED; + link_width = link_status & IXGBE_PCI_LINK_WIDTH; + dev_info(&pdev->dev, "(PCI Express:%s:%s) " + "%02x:%02x:%02x:%02x:%02x:%02x\n", + ((link_speed == IXGBE_PCI_LINK_SPEED_5000) ? "5.0Gb/s" : + (link_speed == IXGBE_PCI_LINK_SPEED_2500) ? "2.5Gb/s" : + "Unknown"), + ((link_width == IXGBE_PCI_LINK_WIDTH_8) ? "Width x8" : + (link_width == IXGBE_PCI_LINK_WIDTH_4) ? "Width x4" : + (link_width == IXGBE_PCI_LINK_WIDTH_2) ? "Width x2" : + (link_width == IXGBE_PCI_LINK_WIDTH_1) ? "Width x1" : + "Unknown"), + netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2], + netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]); + ixgbe_read_part_num(hw, &part_num); + dev_info(&pdev->dev, "MAC: %d, PHY: %d, PBA No: %06x-%03x\n", + hw->mac.type, hw->phy.type, + (part_num >> 8), (part_num & 0xff)); + + /* reset the hardware with the new settings */ + ixgbe_start_hw(hw); + + netif_carrier_off(netdev); + netif_stop_queue(netdev); + + strcpy(netdev->name, "eth%d"); + err = register_netdev(netdev); + if (err) + goto err_register; + + + dev_info(&pdev->dev, "Intel(R) 10 Gigabit Network Connection\n"); + cards_found++; + return 0; + +err_register: +err_hw_init: +err_sw_init: +err_eeprom: + iounmap(hw->hw_addr); +err_ioremap: + free_netdev(netdev); +err_alloc_etherdev: + pci_release_regions(pdev); +err_pci_reg: +err_dma: + pci_disable_device(pdev); + return err; +} + +/** + * ixgbe_remove - Device Removal Routine + * @pdev: PCI device information struct + * + * ixgbe_remove is called by the PCI subsystem to alert the driver + * that it should release a PCI device. The could be caused by a + * Hot-Plug event, or because the driver is going to be removed from + * memory. + **/ +static void __devexit ixgbe_remove(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + set_bit(__IXGBE_DOWN, &adapter->state); + del_timer_sync(&adapter->watchdog_timer); + + flush_scheduled_work(); + + unregister_netdev(netdev); + + kfree(adapter->tx_ring); + kfree(adapter->rx_ring); + + iounmap(adapter->hw.hw_addr); + pci_release_regions(pdev); + + free_netdev(netdev); + + pci_disable_device(pdev); +} + +/** + * ixgbe_io_error_detected - called when PCI error is detected + * @pdev: Pointer to PCI device + * @state: The current pci connection state + * + * This function is called after a PCI bus error affecting + * this device has been detected. + */ +static pci_ers_result_t ixgbe_io_error_detected(struct pci_dev *pdev, + pci_channel_state_t state) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct ixgbe_adapter *adapter = netdev->priv; + + netif_device_detach(netdev); + + if (netif_running(netdev)) + ixgbe_down(adapter); + pci_disable_device(pdev); + + /* Request a slot slot reset. */ + return PCI_ERS_RESULT_NEED_RESET; +} + +/** + * ixgbe_io_slot_reset - called after the pci bus has been reset. + * @pdev: Pointer to PCI device + * + * Restart the card from scratch, as if from a cold-boot. + */ +static pci_ers_result_t ixgbe_io_slot_reset(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct ixgbe_adapter *adapter = netdev->priv; + + if (pci_enable_device(pdev)) { + DPRINTK(PROBE, ERR, + "Cannot re-enable PCI device after reset.\n"); + return PCI_ERS_RESULT_DISCONNECT; + } + pci_set_master(pdev); + + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_enable_wake(pdev, PCI_D3cold, 0); + + ixgbe_reset(adapter); + + return PCI_ERS_RESULT_RECOVERED; +} + +/** + * ixgbe_io_resume - called when traffic can start flowing again. + * @pdev: Pointer to PCI device + * + * This callback is called when the error recovery driver tells us that + * its OK to resume normal operation. + */ +static void ixgbe_io_resume(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct ixgbe_adapter *adapter = netdev->priv; + + if (netif_running(netdev)) { + if (ixgbe_up(adapter)) { + DPRINTK(PROBE, INFO, "ixgbe_up failed after reset\n"); + return; + } + } + + netif_device_attach(netdev); + +} + +static struct pci_error_handlers ixgbe_err_handler = { + .error_detected = ixgbe_io_error_detected, + .slot_reset = ixgbe_io_slot_reset, + .resume = ixgbe_io_resume, +}; + +static struct pci_driver ixgbe_driver = { + .name = ixgbe_driver_name, + .id_table = ixgbe_pci_tbl, + .probe = ixgbe_probe, + .remove = __devexit_p(ixgbe_remove), +#ifdef CONFIG_PM + .suspend = ixgbe_suspend, + .resume = ixgbe_resume, +#endif + .shutdown = ixgbe_shutdown, + .err_handler = &ixgbe_err_handler +}; + +/** + * ixgbe_init_module - Driver Registration Routine + * + * ixgbe_init_module is the first routine called when the driver is + * loaded. All it does is register with the PCI subsystem. + **/ +static int __init ixgbe_init_module(void) +{ + int ret; + printk(KERN_INFO "%s: %s - version %s\n", ixgbe_driver_name, + ixgbe_driver_string, ixgbe_driver_version); + + printk(KERN_INFO "%s: %s\n", ixgbe_driver_name, ixgbe_copyright); + + ret = pci_register_driver(&ixgbe_driver); + return ret; +} +module_init(ixgbe_init_module); + +/** + * ixgbe_exit_module - Driver Exit Cleanup Routine + * + * ixgbe_exit_module is called just before the driver is removed + * from memory. + **/ +static void __exit ixgbe_exit_module(void) +{ + pci_unregister_driver(&ixgbe_driver); +} +module_exit(ixgbe_exit_module); + +/* ixgbe_main.c */ diff --git a/drivers/net/ixgbe/ixgbe_phy.c b/drivers/net/ixgbe/ixgbe_phy.c new file mode 100644 index 00000000000..8002931ae82 --- /dev/null +++ b/drivers/net/ixgbe/ixgbe_phy.c @@ -0,0 +1,494 @@ +/******************************************************************************* + + Intel 10 Gigabit PCI Express Linux driver + Copyright(c) 1999 - 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#include +#include +#include + +#include "ixgbe_common.h" +#include "ixgbe_phy.h" + +static enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id); +static s32 ixgbe_get_phy_id(struct ixgbe_hw *hw); +static bool ixgbe_validate_phy_addr(struct ixgbe_hw *hw, u32 phy_addr); +static s32 ixgbe_write_phy_reg(struct ixgbe_hw *hw, u32 reg_addr, + u32 device_type, u16 phy_data); + +/** + * ixgbe_identify_phy - Get physical layer module + * @hw: pointer to hardware structure + * + * Determines the physical layer module found on the current adapter. + **/ +s32 ixgbe_identify_phy(struct ixgbe_hw *hw) +{ + s32 status = IXGBE_ERR_PHY_ADDR_INVALID; + u32 phy_addr; + + for (phy_addr = 0; phy_addr < IXGBE_MAX_PHY_ADDR; phy_addr++) { + if (ixgbe_validate_phy_addr(hw, phy_addr)) { + hw->phy.addr = phy_addr; + ixgbe_get_phy_id(hw); + hw->phy.type = ixgbe_get_phy_type_from_id(hw->phy.id); + status = 0; + break; + } + } + return status; +} + +/** + * ixgbe_validate_phy_addr - Determines phy address is valid + * @hw: pointer to hardware structure + * + **/ +static bool ixgbe_validate_phy_addr(struct ixgbe_hw *hw, u32 phy_addr) +{ + u16 phy_id = 0; + bool valid = false; + + hw->phy.addr = phy_addr; + ixgbe_read_phy_reg(hw, + IXGBE_MDIO_PHY_ID_HIGH, + IXGBE_MDIO_PMA_PMD_DEV_TYPE, + &phy_id); + + if (phy_id != 0xFFFF && phy_id != 0x0) + valid = true; + + return valid; +} + +/** + * ixgbe_get_phy_id - Get the phy type + * @hw: pointer to hardware structure + * + **/ +static s32 ixgbe_get_phy_id(struct ixgbe_hw *hw) +{ + u32 status; + u16 phy_id_high = 0; + u16 phy_id_low = 0; + + status = ixgbe_read_phy_reg(hw, + IXGBE_MDIO_PHY_ID_HIGH, + IXGBE_MDIO_PMA_PMD_DEV_TYPE, + &phy_id_high); + + if (status == 0) { + hw->phy.id = (u32)(phy_id_high << 16); + status = ixgbe_read_phy_reg(hw, + IXGBE_MDIO_PHY_ID_LOW, + IXGBE_MDIO_PMA_PMD_DEV_TYPE, + &phy_id_low); + hw->phy.id |= (u32)(phy_id_low & IXGBE_PHY_REVISION_MASK); + hw->phy.revision = (u32)(phy_id_low & ~IXGBE_PHY_REVISION_MASK); + } + + return status; +} + +/** + * ixgbe_get_phy_type_from_id - Get the phy type + * @hw: pointer to hardware structure + * + **/ +static enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id) +{ + enum ixgbe_phy_type phy_type; + + switch (phy_id) { + case TN1010_PHY_ID: + phy_type = ixgbe_phy_tn; + break; + case QT2022_PHY_ID: + phy_type = ixgbe_phy_qt; + break; + default: + phy_type = ixgbe_phy_unknown; + break; + } + + return phy_type; +} + +/** + * ixgbe_reset_phy - Performs a PHY reset + * @hw: pointer to hardware structure + **/ +s32 ixgbe_reset_phy(struct ixgbe_hw *hw) +{ + /* + * Perform soft PHY reset to the PHY_XS. + * This will cause a soft reset to the PHY + */ + return ixgbe_write_phy_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL, + IXGBE_MDIO_PHY_XS_DEV_TYPE, + IXGBE_MDIO_PHY_XS_RESET); +} + +/** + * ixgbe_read_phy_reg - Reads a value from a specified PHY register + * @hw: pointer to hardware structure + * @reg_addr: 32 bit address of PHY register to read + * @phy_data: Pointer to read data from PHY register + **/ +s32 ixgbe_read_phy_reg(struct ixgbe_hw *hw, u32 reg_addr, + u32 device_type, u16 *phy_data) +{ + u32 command; + u32 i; + u32 timeout = 10; + u32 data; + s32 status = 0; + u16 gssr; + + if (IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1) + gssr = IXGBE_GSSR_PHY1_SM; + else + gssr = IXGBE_GSSR_PHY0_SM; + + if (ixgbe_acquire_swfw_sync(hw, gssr) != 0) + status = IXGBE_ERR_SWFW_SYNC; + + if (status == 0) { + /* Setup and write the address cycle command */ + command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) | + (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) | + (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) | + (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND)); + + IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); + + /* + * Check every 10 usec to see if the address cycle completed. + * The MDI Command bit will clear when the operation is + * complete + */ + for (i = 0; i < timeout; i++) { + udelay(10); + + command = IXGBE_READ_REG(hw, IXGBE_MSCA); + + if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) + break; + } + + if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) { + hw_dbg(hw, "PHY address command did not complete.\n"); + status = IXGBE_ERR_PHY; + } + + if (status == 0) { + /* + * Address cycle complete, setup and write the read + * command + */ + command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) | + (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) | + (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) | + (IXGBE_MSCA_READ | IXGBE_MSCA_MDI_COMMAND)); + + IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); + + /* + * Check every 10 usec to see if the address cycle + * completed. The MDI Command bit will clear when the + * operation is complete + */ + for (i = 0; i < timeout; i++) { + udelay(10); + + command = IXGBE_READ_REG(hw, IXGBE_MSCA); + + if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) + break; + } + + if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) { + hw_dbg(hw, + "PHY read command didn't complete\n"); + status = IXGBE_ERR_PHY; + } else { + /* + * Read operation is complete. Get the data + * from MSRWD + */ + data = IXGBE_READ_REG(hw, IXGBE_MSRWD); + data >>= IXGBE_MSRWD_READ_DATA_SHIFT; + *phy_data = (u16)(data); + } + } + + ixgbe_release_swfw_sync(hw, gssr); + } + return status; +} + +/** + * ixgbe_write_phy_reg - Writes a value to specified PHY register + * @hw: pointer to hardware structure + * @reg_addr: 32 bit PHY register to write + * @device_type: 5 bit device type + * @phy_data: Data to write to the PHY register + **/ +static s32 ixgbe_write_phy_reg(struct ixgbe_hw *hw, u32 reg_addr, + u32 device_type, u16 phy_data) +{ + u32 command; + u32 i; + u32 timeout = 10; + s32 status = 0; + u16 gssr; + + if (IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1) + gssr = IXGBE_GSSR_PHY1_SM; + else + gssr = IXGBE_GSSR_PHY0_SM; + + if (ixgbe_acquire_swfw_sync(hw, gssr) != 0) + status = IXGBE_ERR_SWFW_SYNC; + + if (status == 0) { + /* Put the data in the MDI single read and write data register*/ + IXGBE_WRITE_REG(hw, IXGBE_MSRWD, (u32)phy_data); + + /* Setup and write the address cycle command */ + command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) | + (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) | + (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) | + (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND)); + + IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); + + /* + * Check every 10 usec to see if the address cycle completed. + * The MDI Command bit will clear when the operation is + * complete + */ + for (i = 0; i < timeout; i++) { + udelay(10); + + command = IXGBE_READ_REG(hw, IXGBE_MSCA); + + if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) { + hw_dbg(hw, "PHY address cmd didn't complete\n"); + break; + } + } + + if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) + status = IXGBE_ERR_PHY; + + if (status == 0) { + /* + * Address cycle complete, setup and write the write + * command + */ + command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) | + (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) | + (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) | + (IXGBE_MSCA_WRITE | IXGBE_MSCA_MDI_COMMAND)); + + IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); + + /* + * Check every 10 usec to see if the address cycle + * completed. The MDI Command bit will clear when the + * operation is complete + */ + for (i = 0; i < timeout; i++) { + udelay(10); + + command = IXGBE_READ_REG(hw, IXGBE_MSCA); + + if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) { + hw_dbg(hw, "PHY write command did not " + "complete.\n"); + break; + } + } + + if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) + status = IXGBE_ERR_PHY; + } + + ixgbe_release_swfw_sync(hw, gssr); + } + + return status; +} + +/** + * ixgbe_setup_tnx_phy_link - Set and restart autoneg + * @hw: pointer to hardware structure + * + * Restart autonegotiation and PHY and waits for completion. + **/ +s32 ixgbe_setup_tnx_phy_link(struct ixgbe_hw *hw) +{ + s32 status = IXGBE_NOT_IMPLEMENTED; + u32 time_out; + u32 max_time_out = 10; + u16 autoneg_speed_selection_register = 0x10; + u16 autoneg_restart_mask = 0x0200; + u16 autoneg_complete_mask = 0x0020; + u16 autoneg_reg = 0; + + /* + * Set advertisement settings in PHY based on autoneg_advertised + * settings. If autoneg_advertised = 0, then advertise default values + * txn devices cannot be "forced" to a autoneg 10G and fail. But can + * for a 1G. + */ + ixgbe_read_phy_reg(hw, + autoneg_speed_selection_register, + IXGBE_MDIO_AUTO_NEG_DEV_TYPE, + &autoneg_reg); + + if (hw->phy.autoneg_advertised == IXGBE_LINK_SPEED_1GB_FULL) + autoneg_reg &= 0xEFFF; /* 0 in bit 12 is 1G operation */ + else + autoneg_reg |= 0x1000; /* 1 in bit 12 is 10G/1G operation */ + + ixgbe_write_phy_reg(hw, + autoneg_speed_selection_register, + IXGBE_MDIO_AUTO_NEG_DEV_TYPE, + autoneg_reg); + + + /* Restart PHY autonegotiation and wait for completion */ + ixgbe_read_phy_reg(hw, + IXGBE_MDIO_AUTO_NEG_CONTROL, + IXGBE_MDIO_AUTO_NEG_DEV_TYPE, + &autoneg_reg); + + autoneg_reg |= autoneg_restart_mask; + + ixgbe_write_phy_reg(hw, + IXGBE_MDIO_AUTO_NEG_CONTROL, + IXGBE_MDIO_AUTO_NEG_DEV_TYPE, + autoneg_reg); + + /* Wait for autonegotiation to finish */ + for (time_out = 0; time_out < max_time_out; time_out++) { + udelay(10); + /* Restart PHY autonegotiation and wait for completion */ + status = ixgbe_read_phy_reg(hw, + IXGBE_MDIO_AUTO_NEG_STATUS, + IXGBE_MDIO_AUTO_NEG_DEV_TYPE, + &autoneg_reg); + + autoneg_reg &= autoneg_complete_mask; + if (autoneg_reg == autoneg_complete_mask) { + status = 0; + break; + } + } + + if (time_out == max_time_out) + status = IXGBE_ERR_LINK_SETUP; + + return status; +} + +/** + * ixgbe_check_tnx_phy_link - Determine link and speed status + * @hw: pointer to hardware structure + * + * Reads the VS1 register to determine if link is up and the current speed for + * the PHY. + **/ +s32 ixgbe_check_tnx_phy_link(struct ixgbe_hw *hw, u32 *speed, + bool *link_up) +{ + s32 status = 0; + u32 time_out; + u32 max_time_out = 10; + u16 phy_link = 0; + u16 phy_speed = 0; + u16 phy_data = 0; + + /* Initialize speed and link to default case */ + *link_up = false; + *speed = IXGBE_LINK_SPEED_10GB_FULL; + + /* + * Check current speed and link status of the PHY register. + * This is a vendor specific register and may have to + * be changed for other copper PHYs. + */ + for (time_out = 0; time_out < max_time_out; time_out++) { + udelay(10); + if (phy_link == IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS) { + *link_up = true; + if (phy_speed == + IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS) + *speed = IXGBE_LINK_SPEED_1GB_FULL; + break; + } else { + status = ixgbe_read_phy_reg(hw, + IXGBE_MDIO_VENDOR_SPECIFIC_1_STATUS, + IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, + &phy_data); + phy_link = phy_data & + IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS; + phy_speed = phy_data & + IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS; + } + } + + return status; +} + +/** + * ixgbe_setup_tnx_phy_link_speed - Sets the auto advertised capabilities + * @hw: pointer to hardware structure + * @speed: new link speed + * @autoneg: true if autonegotiation enabled + **/ +s32 ixgbe_setup_tnx_phy_link_speed(struct ixgbe_hw *hw, u32 speed, + bool autoneg, + bool autoneg_wait_to_complete) +{ + /* + * Clear autoneg_advertised and set new values based on input link + * speed. + */ + hw->phy.autoneg_advertised = 0; + + if (speed & IXGBE_LINK_SPEED_10GB_FULL) + hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_10GB_FULL; + if (speed & IXGBE_LINK_SPEED_1GB_FULL) + hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_1GB_FULL; + + /* Setup link based on the new speed settings */ + ixgbe_setup_tnx_phy_link(hw); + + return 0; +} diff --git a/drivers/net/ixgbe/ixgbe_phy.h b/drivers/net/ixgbe/ixgbe_phy.h new file mode 100644 index 00000000000..199e8f670f3 --- /dev/null +++ b/drivers/net/ixgbe/ixgbe_phy.h @@ -0,0 +1,50 @@ +/******************************************************************************* + + Intel 10 Gigabit PCI Express Linux driver + Copyright(c) 1999 - 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#ifndef _IXGBE_PHY_H_ +#define _IXGBE_PHY_H_ + +#include "ixgbe_type.h" + +s32 ixgbe_init_shared_code_phy(struct ixgbe_hw *hw); +s32 ixgbe_setup_phy_link(struct ixgbe_hw *hw); +s32 ixgbe_check_phy_link(struct ixgbe_hw *hw, u32 *speed, bool *link_up); +s32 ixgbe_setup_phy_link_speed(struct ixgbe_hw *hw, u32 speed, bool autoneg, + bool autoneg_wait_to_complete); +s32 ixgbe_identify_phy(struct ixgbe_hw *hw); +s32 ixgbe_reset_phy(struct ixgbe_hw *hw); +s32 ixgbe_read_phy_reg(struct ixgbe_hw *hw, u32 reg_addr, + u32 device_type, u16 *phy_data); + +/* PHY specific */ +s32 ixgbe_setup_tnx_phy_link(struct ixgbe_hw *hw); +s32 ixgbe_check_tnx_phy_link(struct ixgbe_hw *hw, u32 *speed, bool *link_up); +s32 ixgbe_setup_tnx_phy_link_speed(struct ixgbe_hw *hw, u32 speed, bool autoneg, + bool autoneg_wait_to_complete); + +#endif /* _IXGBE_PHY_H_ */ diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h new file mode 100644 index 00000000000..fdcde16a2a9 --- /dev/null +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -0,0 +1,1332 @@ +/******************************************************************************* + + Intel 10 Gigabit PCI Express Linux driver + Copyright(c) 1999 - 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#ifndef _IXGBE_TYPE_H_ +#define _IXGBE_TYPE_H_ + +#include + +/* Vendor ID */ +#define IXGBE_INTEL_VENDOR_ID 0x8086 + +/* Device IDs */ +#define IXGBE_DEV_ID_82598AF_DUAL_PORT 0x10C6 +#define IXGBE_DEV_ID_82598AF_SINGLE_PORT 0x10C7 +#define IXGBE_DEV_ID_82598AT_DUAL_PORT 0x10C8 +#define IXGBE_DEV_ID_82598EB_CX4 0x10DD + +/* General Registers */ +#define IXGBE_CTRL 0x00000 +#define IXGBE_STATUS 0x00008 +#define IXGBE_CTRL_EXT 0x00018 +#define IXGBE_ESDP 0x00020 +#define IXGBE_EODSDP 0x00028 +#define IXGBE_LEDCTL 0x00200 +#define IXGBE_FRTIMER 0x00048 +#define IXGBE_TCPTIMER 0x0004C + +/* NVM Registers */ +#define IXGBE_EEC 0x10010 +#define IXGBE_EERD 0x10014 +#define IXGBE_FLA 0x1001C +#define IXGBE_EEMNGCTL 0x10110 +#define IXGBE_EEMNGDATA 0x10114 +#define IXGBE_FLMNGCTL 0x10118 +#define IXGBE_FLMNGDATA 0x1011C +#define IXGBE_FLMNGCNT 0x10120 +#define IXGBE_FLOP 0x1013C +#define IXGBE_GRC 0x10200 + +/* Interrupt Registers */ +#define IXGBE_EICR 0x00800 +#define IXGBE_EICS 0x00808 +#define IXGBE_EIMS 0x00880 +#define IXGBE_EIMC 0x00888 +#define IXGBE_EIAC 0x00810 +#define IXGBE_EIAM 0x00890 +#define IXGBE_EITR(_i) (0x00820 + ((_i) * 4)) /* 0x820-0x86c */ +#define IXGBE_IVAR(_i) (0x00900 + ((_i) * 4)) /* 24 at 0x900-0x960 */ +#define IXGBE_MSIXT 0x00000 /* MSI-X Table. 0x0000 - 0x01C */ +#define IXGBE_MSIXPBA 0x02000 /* MSI-X Pending bit array */ +#define IXGBE_PBACL 0x11068 +#define IXGBE_GPIE 0x00898 + +/* Flow Control Registers */ +#define IXGBE_PFCTOP 0x03008 +#define IXGBE_FCTTV(_i) (0x03200 + ((_i) * 4)) /* 4 of these (0-3) */ +#define IXGBE_FCRTL(_i) (0x03220 + ((_i) * 8)) /* 8 of these (0-7) */ +#define IXGBE_FCRTH(_i) (0x03260 + ((_i) * 8)) /* 8 of these (0-7) */ +#define IXGBE_FCRTV 0x032A0 +#define IXGBE_TFCS 0x0CE00 + +/* Receive DMA Registers */ +#define IXGBE_RDBAL(_i) (0x01000 + ((_i) * 0x40)) /* 64 of each (0-63)*/ +#define IXGBE_RDBAH(_i) (0x01004 + ((_i) * 0x40)) +#define IXGBE_RDLEN(_i) (0x01008 + ((_i) * 0x40)) +#define IXGBE_RDH(_i) (0x01010 + ((_i) * 0x40)) +#define IXGBE_RDT(_i) (0x01018 + ((_i) * 0x40)) +#define IXGBE_RXDCTL(_i) (0x01028 + ((_i) * 0x40)) +#define IXGBE_RSCCTL(_i) (0x0102C + ((_i) * 0x40)) +#define IXGBE_SRRCTL(_i) (0x02100 + ((_i) * 4)) + /* array of 16 (0x02100-0x0213C) */ +#define IXGBE_DCA_RXCTRL(_i) (0x02200 + ((_i) * 4)) + /* array of 16 (0x02200-0x0223C) */ +#define IXGBE_RDRXCTL 0x02F00 +#define IXGBE_RXPBSIZE(_i) (0x03C00 + ((_i) * 4)) + /* 8 of these 0x03C00 - 0x03C1C */ +#define IXGBE_RXCTRL 0x03000 +#define IXGBE_DROPEN 0x03D04 +#define IXGBE_RXPBSIZE_SHIFT 10 + +/* Receive Registers */ +#define IXGBE_RXCSUM 0x05000 +#define IXGBE_RFCTL 0x05008 +#define IXGBE_MTA(_i) (0x05200 + ((_i) * 4)) + /* Multicast Table Array - 128 entries */ +#define IXGBE_RAL(_i) (0x05400 + ((_i) * 8)) /* 16 of these (0-15) */ +#define IXGBE_RAH(_i) (0x05404 + ((_i) * 8)) /* 16 of these (0-15) */ +#define IXGBE_PSRTYPE 0x05480 + /* 0x5480-0x54BC Packet split receive type */ +#define IXGBE_VFTA(_i) (0x0A000 + ((_i) * 4)) + /* array of 4096 1-bit vlan filters */ +#define IXGBE_VFTAVIND(_j, _i) (0x0A200 + ((_j) * 0x200) + ((_i) * 4)) + /*array of 4096 4-bit vlan vmdq indicies */ +#define IXGBE_FCTRL 0x05080 +#define IXGBE_VLNCTRL 0x05088 +#define IXGBE_MCSTCTRL 0x05090 +#define IXGBE_MRQC 0x05818 +#define IXGBE_VMD_CTL 0x0581C +#define IXGBE_IMIR(_i) (0x05A80 + ((_i) * 4)) /* 8 of these (0-7) */ +#define IXGBE_IMIREXT(_i) (0x05AA0 + ((_i) * 4)) /* 8 of these (0-7) */ +#define IXGBE_IMIRVP 0x05AC0 +#define IXGBE_RETA(_i) (0x05C00 + ((_i) * 4)) /* 32 of these (0-31) */ +#define IXGBE_RSSRK(_i) (0x05C80 + ((_i) * 4)) /* 10 of these (0-9) */ + +/* Transmit DMA registers */ +#define IXGBE_TDBAL(_i) (0x06000 + ((_i) * 0x40))/* 32 of these (0-31)*/ +#define IXGBE_TDBAH(_i) (0x06004 + ((_i) * 0x40)) +#define IXGBE_TDLEN(_i) (0x06008 + ((_i) * 0x40)) +#define IXGBE_TDH(_i) (0x06010 + ((_i) * 0x40)) +#define IXGBE_TDT(_i) (0x06018 + ((_i) * 0x40)) +#define IXGBE_TXDCTL(_i) (0x06028 + ((_i) * 0x40)) +#define IXGBE_TDWBAL(_i) (0x06038 + ((_i) * 0x40)) +#define IXGBE_TDWBAH(_i) (0x0603C + ((_i) * 0x40)) +#define IXGBE_DTXCTL 0x07E00 +#define IXGBE_DCA_TXCTRL(_i) (0x07200 + ((_i) * 4)) + /* there are 16 of these (0-15) */ +#define IXGBE_TIPG 0x0CB00 +#define IXGBE_TXPBSIZE(_i) (0x0CC00 + ((_i) *0x04)) + /* there are 8 of these */ +#define IXGBE_MNGTXMAP 0x0CD10 +#define IXGBE_TIPG_FIBER_DEFAULT 3 +#define IXGBE_TXPBSIZE_SHIFT 10 + +/* Wake up registers */ +#define IXGBE_WUC 0x05800 +#define IXGBE_WUFC 0x05808 +#define IXGBE_WUS 0x05810 +#define IXGBE_IPAV 0x05838 +#define IXGBE_IP4AT 0x05840 /* IPv4 table 0x5840-0x5858 */ +#define IXGBE_IP6AT 0x05880 /* IPv6 table 0x5880-0x588F */ +#define IXGBE_WUPL 0x05900 +#define IXGBE_WUPM 0x05A00 /* wake up pkt memory 0x5A00-0x5A7C */ +#define IXGBE_FHFT 0x09000 /* Flex host filter table 9000-93FC */ + +/* Music registers */ +#define IXGBE_RMCS 0x03D00 +#define IXGBE_DPMCS 0x07F40 +#define IXGBE_PDPMCS 0x0CD00 +#define IXGBE_RUPPBMR 0x050A0 +#define IXGBE_RT2CR(_i) (0x03C20 + ((_i) * 4)) /* 8 of these (0-7) */ +#define IXGBE_RT2SR(_i) (0x03C40 + ((_i) * 4)) /* 8 of these (0-7) */ +#define IXGBE_TDTQ2TCCR(_i) (0x0602C + ((_i) * 0x40)) /* 8 of these (0-7) */ +#define IXGBE_TDTQ2TCSR(_i) (0x0622C + ((_i) * 0x40)) /* 8 of these (0-7) */ +#define IXGBE_TDPT2TCCR(_i) (0x0CD20 + ((_i) * 4)) /* 8 of these (0-7) */ +#define IXGBE_TDPT2TCSR(_i) (0x0CD40 + ((_i) * 4)) /* 8 of these (0-7) */ + +/* Stats registers */ +#define IXGBE_CRCERRS 0x04000 +#define IXGBE_ILLERRC 0x04004 +#define IXGBE_ERRBC 0x04008 +#define IXGBE_MSPDC 0x04010 +#define IXGBE_MPC(_i) (0x03FA0 + ((_i) * 4)) /* 8 of these 3FA0-3FBC*/ +#define IXGBE_MLFC 0x04034 +#define IXGBE_MRFC 0x04038 +#define IXGBE_RLEC 0x04040 +#define IXGBE_LXONTXC 0x03F60 +#define IXGBE_LXONRXC 0x0CF60 +#define IXGBE_LXOFFTXC 0x03F68 +#define IXGBE_LXOFFRXC 0x0CF68 +#define IXGBE_PXONTXC(_i) (0x03F00 + ((_i) * 4)) /* 8 of these 3F00-3F1C*/ +#define IXGBE_PXONRXC(_i) (0x0CF00 + ((_i) * 4)) /* 8 of these CF00-CF1C*/ +#define IXGBE_PXOFFTXC(_i) (0x03F20 + ((_i) * 4)) /* 8 of these 3F20-3F3C*/ +#define IXGBE_PXOFFRXC(_i) (0x0CF20 + ((_i) * 4)) /* 8 of these CF20-CF3C*/ +#define IXGBE_PRC64 0x0405C +#define IXGBE_PRC127 0x04060 +#define IXGBE_PRC255 0x04064 +#define IXGBE_PRC511 0x04068 +#define IXGBE_PRC1023 0x0406C +#define IXGBE_PRC1522 0x04070 +#define IXGBE_GPRC 0x04074 +#define IXGBE_BPRC 0x04078 +#define IXGBE_MPRC 0x0407C +#define IXGBE_GPTC 0x04080 +#define IXGBE_GORCL 0x04088 +#define IXGBE_GORCH 0x0408C +#define IXGBE_GOTCL 0x04090 +#define IXGBE_GOTCH 0x04094 +#define IXGBE_RNBC(_i) (0x03FC0 + ((_i) * 4)) /* 8 of these 3FC0-3FDC*/ +#define IXGBE_RUC 0x040A4 +#define IXGBE_RFC 0x040A8 +#define IXGBE_ROC 0x040AC +#define IXGBE_RJC 0x040B0 +#define IXGBE_MNGPRC 0x040B4 +#define IXGBE_MNGPDC 0x040B8 +#define IXGBE_MNGPTC 0x0CF90 +#define IXGBE_TORL 0x040C0 +#define IXGBE_TORH 0x040C4 +#define IXGBE_TPR 0x040D0 +#define IXGBE_TPT 0x040D4 +#define IXGBE_PTC64 0x040D8 +#define IXGBE_PTC127 0x040DC +#define IXGBE_PTC255 0x040E0 +#define IXGBE_PTC511 0x040E4 +#define IXGBE_PTC1023 0x040E8 +#define IXGBE_PTC1522 0x040EC +#define IXGBE_MPTC 0x040F0 +#define IXGBE_BPTC 0x040F4 +#define IXGBE_XEC 0x04120 + +#define IXGBE_RQSMR(_i) (0x02300 + ((_i) * 4)) /* 16 of these */ +#define IXGBE_TQSMR(_i) (0x07300 + ((_i) * 4)) /* 8 of these */ + +#define IXGBE_QPRC(_i) (0x01030 + ((_i) * 0x40)) /* 16 of these */ +#define IXGBE_QPTC(_i) (0x06030 + ((_i) * 0x40)) /* 16 of these */ +#define IXGBE_QBRC(_i) (0x01034 + ((_i) * 0x40)) /* 16 of these */ +#define IXGBE_QBTC(_i) (0x06034 + ((_i) * 0x40)) /* 16 of these */ + +/* Management */ +#define IXGBE_MAVTV(_i) (0x05010 + ((_i) * 4)) /* 8 of these (0-7) */ +#define IXGBE_MFUTP(_i) (0x05030 + ((_i) * 4)) /* 8 of these (0-7) */ +#define IXGBE_MANC 0x05820 +#define IXGBE_MFVAL 0x05824 +#define IXGBE_MANC2H 0x05860 +#define IXGBE_MDEF(_i) (0x05890 + ((_i) * 4)) /* 8 of these (0-7) */ +#define IXGBE_MIPAF 0x058B0 +#define IXGBE_MMAL(_i) (0x05910 + ((_i) * 8)) /* 4 of these (0-3) */ +#define IXGBE_MMAH(_i) (0x05914 + ((_i) * 8)) /* 4 of these (0-3) */ +#define IXGBE_FTFT 0x09400 /* 0x9400-0x97FC */ + +/* ARC Subsystem registers */ +#define IXGBE_HICR 0x15F00 +#define IXGBE_FWSTS 0x15F0C +#define IXGBE_HSMC0R 0x15F04 +#define IXGBE_HSMC1R 0x15F08 +#define IXGBE_SWSR 0x15F10 +#define IXGBE_HFDR 0x15FE8 +#define IXGBE_FLEX_MNG 0x15800 /* 0x15800 - 0x15EFC */ + +/* PCI-E registers */ +#define IXGBE_GCR 0x11000 +#define IXGBE_GTV 0x11004 +#define IXGBE_FUNCTAG 0x11008 +#define IXGBE_GLT 0x1100C +#define IXGBE_GSCL_1 0x11010 +#define IXGBE_GSCL_2 0x11014 +#define IXGBE_GSCL_3 0x11018 +#define IXGBE_GSCL_4 0x1101C +#define IXGBE_GSCN_0 0x11020 +#define IXGBE_GSCN_1 0x11024 +#define IXGBE_GSCN_2 0x11028 +#define IXGBE_GSCN_3 0x1102C +#define IXGBE_FACTPS 0x10150 +#define IXGBE_PCIEANACTL 0x11040 +#define IXGBE_SWSM 0x10140 +#define IXGBE_FWSM 0x10148 +#define IXGBE_GSSR 0x10160 +#define IXGBE_MREVID 0x11064 +#define IXGBE_DCA_ID 0x11070 +#define IXGBE_DCA_CTRL 0x11074 + +/* Diagnostic Registers */ +#define IXGBE_RDSTATCTL 0x02C20 +#define IXGBE_RDSTAT(_i) (0x02C00 + ((_i) * 4)) /* 0x02C00-0x02C1C */ +#define IXGBE_RDHMPN 0x02F08 +#define IXGBE_RIC_DW0 0x02F10 +#define IXGBE_RIC_DW1 0x02F14 +#define IXGBE_RIC_DW2 0x02F18 +#define IXGBE_RIC_DW3 0x02F1C +#define IXGBE_RDPROBE 0x02F20 +#define IXGBE_TDSTATCTL 0x07C20 +#define IXGBE_TDSTAT(_i) (0x07C00 + ((_i) * 4)) /* 0x07C00 - 0x07C1C */ +#define IXGBE_TDHMPN 0x07F08 +#define IXGBE_TIC_DW0 0x07F10 +#define IXGBE_TIC_DW1 0x07F14 +#define IXGBE_TIC_DW2 0x07F18 +#define IXGBE_TIC_DW3 0x07F1C +#define IXGBE_TDPROBE 0x07F20 +#define IXGBE_TXBUFCTRL 0x0C600 +#define IXGBE_TXBUFDATA0 0x0C610 +#define IXGBE_TXBUFDATA1 0x0C614 +#define IXGBE_TXBUFDATA2 0x0C618 +#define IXGBE_TXBUFDATA3 0x0C61C +#define IXGBE_RXBUFCTRL 0x03600 +#define IXGBE_RXBUFDATA0 0x03610 +#define IXGBE_RXBUFDATA1 0x03614 +#define IXGBE_RXBUFDATA2 0x03618 +#define IXGBE_RXBUFDATA3 0x0361C +#define IXGBE_PCIE_DIAG(_i) (0x11090 + ((_i) * 4)) /* 8 of these */ +#define IXGBE_RFVAL 0x050A4 +#define IXGBE_MDFTC1 0x042B8 +#define IXGBE_MDFTC2 0x042C0 +#define IXGBE_MDFTFIFO1 0x042C4 +#define IXGBE_MDFTFIFO2 0x042C8 +#define IXGBE_MDFTS 0x042CC +#define IXGBE_RXDATAWRPTR(_i) (0x03700 + ((_i) * 4)) /* 8 of these 3700-370C*/ +#define IXGBE_RXDESCWRPTR(_i) (0x03710 + ((_i) * 4)) /* 8 of these 3710-371C*/ +#define IXGBE_RXDATARDPTR(_i) (0x03720 + ((_i) * 4)) /* 8 of these 3720-372C*/ +#define IXGBE_RXDESCRDPTR(_i) (0x03730 + ((_i) * 4)) /* 8 of these 3730-373C*/ +#define IXGBE_TXDATAWRPTR(_i) (0x0C700 + ((_i) * 4)) /* 8 of these C700-C70C*/ +#define IXGBE_TXDESCWRPTR(_i) (0x0C710 + ((_i) * 4)) /* 8 of these C710-C71C*/ +#define IXGBE_TXDATARDPTR(_i) (0x0C720 + ((_i) * 4)) /* 8 of these C720-C72C*/ +#define IXGBE_TXDESCRDPTR(_i) (0x0C730 + ((_i) * 4)) /* 8 of these C730-C73C*/ +#define IXGBE_PCIEECCCTL 0x1106C +#define IXGBE_PBTXECC 0x0C300 +#define IXGBE_PBRXECC 0x03300 +#define IXGBE_GHECCR 0x110B0 + +/* MAC Registers */ +#define IXGBE_PCS1GCFIG 0x04200 +#define IXGBE_PCS1GLCTL 0x04208 +#define IXGBE_PCS1GLSTA 0x0420C +#define IXGBE_PCS1GDBG0 0x04210 +#define IXGBE_PCS1GDBG1 0x04214 +#define IXGBE_PCS1GANA 0x04218 +#define IXGBE_PCS1GANLP 0x0421C +#define IXGBE_PCS1GANNP 0x04220 +#define IXGBE_PCS1GANLPNP 0x04224 +#define IXGBE_HLREG0 0x04240 +#define IXGBE_HLREG1 0x04244 +#define IXGBE_PAP 0x04248 +#define IXGBE_MACA 0x0424C +#define IXGBE_APAE 0x04250 +#define IXGBE_ARD 0x04254 +#define IXGBE_AIS 0x04258 +#define IXGBE_MSCA 0x0425C +#define IXGBE_MSRWD 0x04260 +#define IXGBE_MLADD 0x04264 +#define IXGBE_MHADD 0x04268 +#define IXGBE_TREG 0x0426C +#define IXGBE_PCSS1 0x04288 +#define IXGBE_PCSS2 0x0428C +#define IXGBE_XPCSS 0x04290 +#define IXGBE_SERDESC 0x04298 +#define IXGBE_MACS 0x0429C +#define IXGBE_AUTOC 0x042A0 +#define IXGBE_LINKS 0x042A4 +#define IXGBE_AUTOC2 0x042A8 +#define IXGBE_AUTOC3 0x042AC +#define IXGBE_ANLP1 0x042B0 +#define IXGBE_ANLP2 0x042B4 +#define IXGBE_ATLASCTL 0x04800 + +/* RSCCTL Bit Masks */ +#define IXGBE_RSCCTL_RSCEN 0x01 +#define IXGBE_RSCCTL_MAXDESC_1 0x00 +#define IXGBE_RSCCTL_MAXDESC_4 0x04 +#define IXGBE_RSCCTL_MAXDESC_8 0x08 +#define IXGBE_RSCCTL_MAXDESC_16 0x0C + +/* CTRL Bit Masks */ +#define IXGBE_CTRL_GIO_DIS 0x00000004 /* Global IO Master Disable bit */ +#define IXGBE_CTRL_LNK_RST 0x00000008 /* Link Reset. Resets everything. */ +#define IXGBE_CTRL_RST 0x04000000 /* Reset (SW) */ + +/* FACTPS */ +#define IXGBE_FACTPS_LFS 0x40000000 /* LAN Function Select */ + +/* MHADD Bit Masks */ +#define IXGBE_MHADD_MFS_MASK 0xFFFF0000 +#define IXGBE_MHADD_MFS_SHIFT 16 + +/* Extended Device Control */ +#define IXGBE_CTRL_EXT_NS_DIS 0x00010000 /* No Snoop disable */ +#define IXGBE_CTRL_EXT_RO_DIS 0x00020000 /* Relaxed Ordering disable */ +#define IXGBE_CTRL_EXT_DRV_LOAD 0x10000000 /* Driver loaded bit for FW */ + +/* Direct Cache Access (DCA) definitions */ +#define IXGBE_DCA_CTRL_DCA_ENABLE 0x00000000 /* DCA Enable */ +#define IXGBE_DCA_CTRL_DCA_DISABLE 0x00000001 /* DCA Disable */ + +#define IXGBE_DCA_CTRL_DCA_MODE_CB1 0x00 /* DCA Mode CB1 */ +#define IXGBE_DCA_CTRL_DCA_MODE_CB2 0x02 /* DCA Mode CB2 */ + +#define IXGBE_DCA_RXCTRL_CPUID_MASK 0x0000001F /* Rx CPUID Mask */ +#define IXGBE_DCA_RXCTRL_DESC_DCA_EN (1 << 5) /* DCA Rx Desc enable */ +#define IXGBE_DCA_RXCTRL_HEAD_DCA_EN (1 << 6) /* DCA Rx Desc header enable */ +#define IXGBE_DCA_RXCTRL_DATA_DCA_EN (1 << 7) /* DCA Rx Desc payload enable */ + +#define IXGBE_DCA_TXCTRL_CPUID_MASK 0x0000001F /* Tx CPUID Mask */ +#define IXGBE_DCA_TXCTRL_DESC_DCA_EN (1 << 5) /* DCA Tx Desc enable */ +#define IXGBE_DCA_TXCTRL_TX_WB_RO_EN (1 << 11) /* TX Desc writeback RO bit */ +#define IXGBE_DCA_MAX_QUEUES_82598 16 /* DCA regs only on 16 queues */ + +/* MSCA Bit Masks */ +#define IXGBE_MSCA_NP_ADDR_MASK 0x0000FFFF /* MDI Address (new protocol) */ +#define IXGBE_MSCA_NP_ADDR_SHIFT 0 +#define IXGBE_MSCA_DEV_TYPE_MASK 0x001F0000 /* Device Type (new protocol) */ +#define IXGBE_MSCA_DEV_TYPE_SHIFT 16 /* Register Address (old protocol */ +#define IXGBE_MSCA_PHY_ADDR_MASK 0x03E00000 /* PHY Address mask */ +#define IXGBE_MSCA_PHY_ADDR_SHIFT 21 /* PHY Address shift*/ +#define IXGBE_MSCA_OP_CODE_MASK 0x0C000000 /* OP CODE mask */ +#define IXGBE_MSCA_OP_CODE_SHIFT 26 /* OP CODE shift */ +#define IXGBE_MSCA_ADDR_CYCLE 0x00000000 /* OP CODE 00 (addr cycle) */ +#define IXGBE_MSCA_WRITE 0x04000000 /* OP CODE 01 (write) */ +#define IXGBE_MSCA_READ 0x08000000 /* OP CODE 10 (read) */ +#define IXGBE_MSCA_READ_AUTOINC 0x0C000000 /* OP CODE 11 (read, auto inc)*/ +#define IXGBE_MSCA_ST_CODE_MASK 0x30000000 /* ST Code mask */ +#define IXGBE_MSCA_ST_CODE_SHIFT 28 /* ST Code shift */ +#define IXGBE_MSCA_NEW_PROTOCOL 0x00000000 /* ST CODE 00 (new protocol) */ +#define IXGBE_MSCA_OLD_PROTOCOL 0x10000000 /* ST CODE 01 (old protocol) */ +#define IXGBE_MSCA_MDI_COMMAND 0x40000000 /* Initiate MDI command */ +#define IXGBE_MSCA_MDI_IN_PROG_EN 0x80000000 /* MDI in progress enable */ + +/* MSRWD bit masks */ +#define IXGBE_MSRWD_WRITE_DATA_MASK 0x0000FFFF +#define IXGBE_MSRWD_WRITE_DATA_SHIFT 0 +#define IXGBE_MSRWD_READ_DATA_MASK 0xFFFF0000 +#define IXGBE_MSRWD_READ_DATA_SHIFT 16 + +/* Atlas registers */ +#define IXGBE_ATLAS_PDN_LPBK 0x24 +#define IXGBE_ATLAS_PDN_10G 0xB +#define IXGBE_ATLAS_PDN_1G 0xC +#define IXGBE_ATLAS_PDN_AN 0xD + +/* Atlas bit masks */ +#define IXGBE_ATLASCTL_WRITE_CMD 0x00010000 +#define IXGBE_ATLAS_PDN_TX_REG_EN 0x10 +#define IXGBE_ATLAS_PDN_TX_10G_QL_ALL 0xF0 +#define IXGBE_ATLAS_PDN_TX_1G_QL_ALL 0xF0 +#define IXGBE_ATLAS_PDN_TX_AN_QL_ALL 0xF0 + +/* Device Type definitions for new protocol MDIO commands */ +#define IXGBE_MDIO_PMA_PMD_DEV_TYPE 0x1 +#define IXGBE_MDIO_PCS_DEV_TYPE 0x3 +#define IXGBE_MDIO_PHY_XS_DEV_TYPE 0x4 +#define IXGBE_MDIO_AUTO_NEG_DEV_TYPE 0x7 +#define IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE 0x1E /* Device 30 */ + +#define IXGBE_MDIO_VENDOR_SPECIFIC_1_CONTROL 0x0 /* VS1 Control Reg */ +#define IXGBE_MDIO_VENDOR_SPECIFIC_1_STATUS 0x1 /* VS1 Status Reg */ +#define IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS 0x0008 /* 1 = Link Up */ +#define IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS 0x0010 /* 0 - 10G, 1 - 1G */ +#define IXGBE_MDIO_VENDOR_SPECIFIC_1_10G_SPEED 0x0018 +#define IXGBE_MDIO_VENDOR_SPECIFIC_1_1G_SPEED 0x0010 + +#define IXGBE_MDIO_AUTO_NEG_CONTROL 0x0 /* AUTO_NEG Control Reg */ +#define IXGBE_MDIO_AUTO_NEG_STATUS 0x1 /* AUTO_NEG Status Reg */ +#define IXGBE_MDIO_PHY_XS_CONTROL 0x0 /* PHY_XS Control Reg */ +#define IXGBE_MDIO_PHY_XS_RESET 0x8000 /* PHY_XS Reset */ +#define IXGBE_MDIO_PHY_ID_HIGH 0x2 /* PHY ID High Reg*/ +#define IXGBE_MDIO_PHY_ID_LOW 0x3 /* PHY ID Low Reg*/ +#define IXGBE_MDIO_PHY_SPEED_ABILITY 0x4 /* Speed Abilty Reg */ +#define IXGBE_MDIO_PHY_SPEED_10G 0x0001 /* 10G capable */ +#define IXGBE_MDIO_PHY_SPEED_1G 0x0010 /* 1G capable */ + +#define IXGBE_PHY_REVISION_MASK 0xFFFFFFF0 +#define IXGBE_MAX_PHY_ADDR 32 + +/* PHY IDs*/ +#define TN1010_PHY_ID 0x00A19410 +#define QT2022_PHY_ID 0x0043A400 + +/* General purpose Interrupt Enable */ +#define IXGBE_GPIE_MSIX_MODE 0x00000010 /* MSI-X mode */ +#define IXGBE_GPIE_OCD 0x00000020 /* Other Clear Disable */ +#define IXGBE_GPIE_EIMEN 0x00000040 /* Immediate Interrupt Enable */ +#define IXGBE_GPIE_EIAME 0x40000000 +#define IXGBE_GPIE_PBA_SUPPORT 0x80000000 + +/* Transmit Flow Control status */ +#define IXGBE_TFCS_TXOFF 0x00000001 +#define IXGBE_TFCS_TXOFF0 0x00000100 +#define IXGBE_TFCS_TXOFF1 0x00000200 +#define IXGBE_TFCS_TXOFF2 0x00000400 +#define IXGBE_TFCS_TXOFF3 0x00000800 +#define IXGBE_TFCS_TXOFF4 0x00001000 +#define IXGBE_TFCS_TXOFF5 0x00002000 +#define IXGBE_TFCS_TXOFF6 0x00004000 +#define IXGBE_TFCS_TXOFF7 0x00008000 + +/* TCP Timer */ +#define IXGBE_TCPTIMER_KS 0x00000100 +#define IXGBE_TCPTIMER_COUNT_ENABLE 0x00000200 +#define IXGBE_TCPTIMER_COUNT_FINISH 0x00000400 +#define IXGBE_TCPTIMER_LOOP 0x00000800 +#define IXGBE_TCPTIMER_DURATION_MASK 0x000000FF + +/* HLREG0 Bit Masks */ +#define IXGBE_HLREG0_TXCRCEN 0x00000001 /* bit 0 */ +#define IXGBE_HLREG0_RXCRCSTRP 0x00000002 /* bit 1 */ +#define IXGBE_HLREG0_JUMBOEN 0x00000004 /* bit 2 */ +#define IXGBE_HLREG0_TXPADEN 0x00000400 /* bit 10 */ +#define IXGBE_HLREG0_TXPAUSEEN 0x00001000 /* bit 12 */ +#define IXGBE_HLREG0_RXPAUSEEN 0x00004000 /* bit 14 */ +#define IXGBE_HLREG0_LPBK 0x00008000 /* bit 15 */ +#define IXGBE_HLREG0_MDCSPD 0x00010000 /* bit 16 */ +#define IXGBE_HLREG0_CONTMDC 0x00020000 /* bit 17 */ +#define IXGBE_HLREG0_CTRLFLTR 0x00040000 /* bit 18 */ +#define IXGBE_HLREG0_PREPEND 0x00F00000 /* bits 20-23 */ +#define IXGBE_HLREG0_PRIPAUSEEN 0x01000000 /* bit 24 */ +#define IXGBE_HLREG0_RXPAUSERECDA 0x06000000 /* bits 25-26 */ +#define IXGBE_HLREG0_RXLNGTHERREN 0x08000000 /* bit 27 */ +#define IXGBE_HLREG0_RXPADSTRIPEN 0x10000000 /* bit 28 */ + +/* VMD_CTL bitmasks */ +#define IXGBE_VMD_CTL_VMDQ_EN 0x00000001 +#define IXGBE_VMD_CTL_VMDQ_FILTER 0x00000002 + +/* RDHMPN and TDHMPN bitmasks */ +#define IXGBE_RDHMPN_RDICADDR 0x007FF800 +#define IXGBE_RDHMPN_RDICRDREQ 0x00800000 +#define IXGBE_RDHMPN_RDICADDR_SHIFT 11 +#define IXGBE_TDHMPN_TDICADDR 0x003FF800 +#define IXGBE_TDHMPN_TDICRDREQ 0x00800000 +#define IXGBE_TDHMPN_TDICADDR_SHIFT 11 + +/* Receive Checksum Control */ +#define IXGBE_RXCSUM_IPPCSE 0x00001000 /* IP payload checksum enable */ +#define IXGBE_RXCSUM_PCSD 0x00002000 /* packet checksum disabled */ + +/* FCRTL Bit Masks */ +#define IXGBE_FCRTL_XONE 0x80000000 /* bit 31, XON enable */ +#define IXGBE_FCRTH_FCEN 0x80000000 /* Rx Flow control enable */ + +/* PAP bit masks*/ +#define IXGBE_PAP_TXPAUSECNT_MASK 0x0000FFFF /* Pause counter mask */ + +/* RMCS Bit Masks */ +#define IXGBE_RMCS_RRM 0x00000002 /* Receive Recylce Mode enable */ +/* Receive Arbitration Control: 0 Round Robin, 1 DFP */ +#define IXGBE_RMCS_RAC 0x00000004 +#define IXGBE_RMCS_DFP IXGBE_RMCS_RAC /* Deficit Fixed Priority ena */ +#define IXGBE_RMCS_TFCE_802_3X 0x00000008 /* Tx Priority flow control ena */ +#define IXGBE_RMCS_TFCE_PRIORITY 0x00000010 /* Tx Priority flow control ena */ +#define IXGBE_RMCS_ARBDIS 0x00000040 /* Arbitration disable bit */ + +/* Interrupt register bitmasks */ + +/* Extended Interrupt Cause Read */ +#define IXGBE_EICR_RTX_QUEUE 0x0000FFFF /* RTx Queue Interrupt */ +#define IXGBE_EICR_LSC 0x00100000 /* Link Status Change */ +#define IXGBE_EICR_MNG 0x00400000 /* Managability Event Interrupt */ +#define IXGBE_EICR_PBUR 0x10000000 /* Packet Buffer Handler Error */ +#define IXGBE_EICR_DHER 0x20000000 /* Descriptor Handler Error */ +#define IXGBE_EICR_TCP_TIMER 0x40000000 /* TCP Timer */ +#define IXGBE_EICR_OTHER 0x80000000 /* Interrupt Cause Active */ + +/* Extended Interrupt Cause Set */ +#define IXGBE_EICS_RTX_QUEUE IXGBE_EICR_RTX_QUEUE /* RTx Queue Interrupt */ +#define IXGBE_EICS_LSC IXGBE_EICR_LSC /* Link Status Change */ +#define IXGBE_EICR_GPI_SDP0 0x01000000 /* Gen Purpose Interrupt on SDP0 */ +#define IXGBE_EICS_MNG IXGBE_EICR_MNG /* MNG Event Interrupt */ +#define IXGBE_EICS_PBUR IXGBE_EICR_PBUR /* Pkt Buf Handler Error */ +#define IXGBE_EICS_DHER IXGBE_EICR_DHER /* Desc Handler Error */ +#define IXGBE_EICS_TCP_TIMER IXGBE_EICR_TCP_TIMER /* TCP Timer */ +#define IXGBE_EICS_OTHER IXGBE_EICR_OTHER /* INT Cause Active */ + +/* Extended Interrupt Mask Set */ +#define IXGBE_EIMS_RTX_QUEUE IXGBE_EICR_RTX_QUEUE /* RTx Queue Interrupt */ +#define IXGBE_EIMS_LSC IXGBE_EICR_LSC /* Link Status Change */ +#define IXGBE_EIMS_MNG IXGBE_EICR_MNG /* MNG Event Interrupt */ +#define IXGBE_EIMS_PBUR IXGBE_EICR_PBUR /* Pkt Buf Handler Error */ +#define IXGBE_EIMS_DHER IXGBE_EICR_DHER /* Descr Handler Error */ +#define IXGBE_EIMS_TCP_TIMER IXGBE_EICR_TCP_TIMER /* TCP Timer */ +#define IXGBE_EIMS_OTHER IXGBE_EICR_OTHER /* INT Cause Active */ + +/* Extended Interrupt Mask Clear */ +#define IXGBE_EIMC_RTX_QUEUE IXGBE_EICR_RTX_QUEUE /* RTx Queue Interrupt */ +#define IXGBE_EIMC_LSC IXGBE_EICR_LSC /* Link Status Change */ +#define IXGBE_EIMC_MNG IXGBE_EICR_MNG /* MNG Event Interrupt */ +#define IXGBE_EIMC_PBUR IXGBE_EICR_PBUR /* Pkt Buf Handler Error */ +#define IXGBE_EIMC_DHER IXGBE_EICR_DHER /* Desc Handler Error */ +#define IXGBE_EIMC_TCP_TIMER IXGBE_EICR_TCP_TIMER /* TCP Timer */ +#define IXGBE_EIMC_OTHER IXGBE_EICR_OTHER /* INT Cause Active */ + +#define IXGBE_EIMS_ENABLE_MASK (\ + IXGBE_EIMS_RTX_QUEUE | \ + IXGBE_EIMS_LSC | \ + IXGBE_EIMS_TCP_TIMER | \ + IXGBE_EIMS_OTHER) + +/* Immediate Interrupt RX (A.K.A. Low Latency Interrupt) */ +#define IXGBE_IMIR_PORT_IM_EN 0x00010000 /* TCP port enable */ +#define IXGBE_IMIR_PORT_BP 0x00020000 /* TCP port check bypass */ +#define IXGBE_IMIREXT_SIZE_BP 0x00001000 /* Packet size bypass */ +#define IXGBE_IMIREXT_CTRL_URG 0x00002000 /* Check URG bit in header */ +#define IXGBE_IMIREXT_CTRL_ACK 0x00004000 /* Check ACK bit in header */ +#define IXGBE_IMIREXT_CTRL_PSH 0x00008000 /* Check PSH bit in header */ +#define IXGBE_IMIREXT_CTRL_RST 0x00010000 /* Check RST bit in header */ +#define IXGBE_IMIREXT_CTRL_SYN 0x00020000 /* Check SYN bit in header */ +#define IXGBE_IMIREXT_CTRL_FIN 0x00040000 /* Check FIN bit in header */ +#define IXGBE_IMIREXT_CTRL_BP 0x00080000 /* Bypass check of control bits */ + +/* Interrupt clear mask */ +#define IXGBE_IRQ_CLEAR_MASK 0xFFFFFFFF + +/* Interrupt Vector Allocation Registers */ +#define IXGBE_IVAR_REG_NUM 25 +#define IXGBE_IVAR_TXRX_ENTRY 96 +#define IXGBE_IVAR_RX_ENTRY 64 +#define IXGBE_IVAR_RX_QUEUE(_i) (0 + (_i)) +#define IXGBE_IVAR_TX_QUEUE(_i) (64 + (_i)) +#define IXGBE_IVAR_TX_ENTRY 32 + +#define IXGBE_IVAR_TCP_TIMER_INDEX 96 /* 0 based index */ +#define IXGBE_IVAR_OTHER_CAUSES_INDEX 97 /* 0 based index */ + +#define IXGBE_MSIX_VECTOR(_i) (0 + (_i)) + +#define IXGBE_IVAR_ALLOC_VAL 0x80 /* Interrupt Allocation valid */ + +/* VLAN Control Bit Masks */ +#define IXGBE_VLNCTRL_VET 0x0000FFFF /* bits 0-15 */ +#define IXGBE_VLNCTRL_CFI 0x10000000 /* bit 28 */ +#define IXGBE_VLNCTRL_CFIEN 0x20000000 /* bit 29 */ +#define IXGBE_VLNCTRL_VFE 0x40000000 /* bit 30 */ +#define IXGBE_VLNCTRL_VME 0x80000000 /* bit 31 */ + +#define IXGBE_ETHERNET_IEEE_VLAN_TYPE 0x8100 /* 802.1q protocol */ + +/* STATUS Bit Masks */ +#define IXGBE_STATUS_LAN_ID 0x0000000C /* LAN ID */ +#define IXGBE_STATUS_GIO 0x00080000 /* GIO Master Enable Status */ + +#define IXGBE_STATUS_LAN_ID_0 0x00000000 /* LAN ID 0 */ +#define IXGBE_STATUS_LAN_ID_1 0x00000004 /* LAN ID 1 */ + +/* ESDP Bit Masks */ +#define IXGBE_ESDP_SDP4 0x00000001 /* SDP4 Data Value */ +#define IXGBE_ESDP_SDP5 0x00000002 /* SDP5 Data Value */ +#define IXGBE_ESDP_SDP4_DIR 0x00000004 /* SDP4 IO direction */ +#define IXGBE_ESDP_SDP5_DIR 0x00000008 /* SDP5 IO direction */ + +/* LEDCTL Bit Masks */ +#define IXGBE_LED_IVRT_BASE 0x00000040 +#define IXGBE_LED_BLINK_BASE 0x00000080 +#define IXGBE_LED_MODE_MASK_BASE 0x0000000F +#define IXGBE_LED_OFFSET(_base, _i) (_base << (8 * (_i))) +#define IXGBE_LED_MODE_SHIFT(_i) (8*(_i)) +#define IXGBE_LED_IVRT(_i) IXGBE_LED_OFFSET(IXGBE_LED_IVRT_BASE, _i) +#define IXGBE_LED_BLINK(_i) IXGBE_LED_OFFSET(IXGBE_LED_BLINK_BASE, _i) +#define IXGBE_LED_MODE_MASK(_i) IXGBE_LED_OFFSET(IXGBE_LED_MODE_MASK_BASE, _i) + +/* LED modes */ +#define IXGBE_LED_LINK_UP 0x0 +#define IXGBE_LED_LINK_10G 0x1 +#define IXGBE_LED_MAC 0x2 +#define IXGBE_LED_FILTER 0x3 +#define IXGBE_LED_LINK_ACTIVE 0x4 +#define IXGBE_LED_LINK_1G 0x5 +#define IXGBE_LED_ON 0xE +#define IXGBE_LED_OFF 0xF + +/* AUTOC Bit Masks */ +#define IXGBE_AUTOC_KX4_SUPP 0x80000000 +#define IXGBE_AUTOC_KX_SUPP 0x40000000 +#define IXGBE_AUTOC_PAUSE 0x30000000 +#define IXGBE_AUTOC_RF 0x08000000 +#define IXGBE_AUTOC_PD_TMR 0x06000000 +#define IXGBE_AUTOC_AN_RX_LOOSE 0x01000000 +#define IXGBE_AUTOC_AN_RX_DRIFT 0x00800000 +#define IXGBE_AUTOC_AN_RX_ALIGN 0x007C0000 +#define IXGBE_AUTOC_AN_RESTART 0x00001000 +#define IXGBE_AUTOC_FLU 0x00000001 +#define IXGBE_AUTOC_LMS_SHIFT 13 +#define IXGBE_AUTOC_LMS_MASK (0x7 << IXGBE_AUTOC_LMS_SHIFT) +#define IXGBE_AUTOC_LMS_1G_LINK_NO_AN (0x0 << IXGBE_AUTOC_LMS_SHIFT) +#define IXGBE_AUTOC_LMS_10G_LINK_NO_AN (0x1 << IXGBE_AUTOC_LMS_SHIFT) +#define IXGBE_AUTOC_LMS_1G_AN (0x2 << IXGBE_AUTOC_LMS_SHIFT) +#define IXGBE_AUTOC_LMS_KX4_AN (0x4 << IXGBE_AUTOC_LMS_SHIFT) +#define IXGBE_AUTOC_LMS_KX4_AN_1G_AN (0x6 << IXGBE_AUTOC_LMS_SHIFT) +#define IXGBE_AUTOC_LMS_ATTACH_TYPE (0x7 << IXGBE_AUTOC_10G_PMA_PMD_SHIFT) + +#define IXGBE_AUTOC_1G_PMA_PMD 0x00000200 +#define IXGBE_AUTOC_10G_PMA_PMD 0x00000180 +#define IXGBE_AUTOC_10G_PMA_PMD_SHIFT 7 +#define IXGBE_AUTOC_1G_PMA_PMD_SHIFT 9 +#define IXGBE_AUTOC_10G_XAUI (0x0 << IXGBE_AUTOC_10G_PMA_PMD_SHIFT) +#define IXGBE_AUTOC_10G_KX4 (0x1 << IXGBE_AUTOC_10G_PMA_PMD_SHIFT) +#define IXGBE_AUTOC_10G_CX4 (0x2 << IXGBE_AUTOC_10G_PMA_PMD_SHIFT) +#define IXGBE_AUTOC_1G_BX (0x0 << IXGBE_AUTOC_1G_PMA_PMD_SHIFT) +#define IXGBE_AUTOC_1G_KX (0x1 << IXGBE_AUTOC_1G_PMA_PMD_SHIFT) + +/* LINKS Bit Masks */ +#define IXGBE_LINKS_KX_AN_COMP 0x80000000 +#define IXGBE_LINKS_UP 0x40000000 +#define IXGBE_LINKS_SPEED 0x20000000 +#define IXGBE_LINKS_MODE 0x18000000 +#define IXGBE_LINKS_RX_MODE 0x06000000 +#define IXGBE_LINKS_TX_MODE 0x01800000 +#define IXGBE_LINKS_XGXS_EN 0x00400000 +#define IXGBE_LINKS_PCS_1G_EN 0x00200000 +#define IXGBE_LINKS_1G_AN_EN 0x00100000 +#define IXGBE_LINKS_KX_AN_IDLE 0x00080000 +#define IXGBE_LINKS_1G_SYNC 0x00040000 +#define IXGBE_LINKS_10G_ALIGN 0x00020000 +#define IXGBE_LINKS_10G_LANE_SYNC 0x00017000 +#define IXGBE_LINKS_TL_FAULT 0x00001000 +#define IXGBE_LINKS_SIGNAL 0x00000F00 + +#define IXGBE_AUTO_NEG_TIME 45 /* 4.5 Seconds */ + +/* SW Semaphore Register bitmasks */ +#define IXGBE_SWSM_SMBI 0x00000001 /* Driver Semaphore bit */ +#define IXGBE_SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */ +#define IXGBE_SWSM_WMNG 0x00000004 /* Wake MNG Clock */ + +/* GSSR definitions */ +#define IXGBE_GSSR_EEP_SM 0x0001 +#define IXGBE_GSSR_PHY0_SM 0x0002 +#define IXGBE_GSSR_PHY1_SM 0x0004 +#define IXGBE_GSSR_MAC_CSR_SM 0x0008 +#define IXGBE_GSSR_FLASH_SM 0x0010 + +/* EEC Register */ +#define IXGBE_EEC_SK 0x00000001 /* EEPROM Clock */ +#define IXGBE_EEC_CS 0x00000002 /* EEPROM Chip Select */ +#define IXGBE_EEC_DI 0x00000004 /* EEPROM Data In */ +#define IXGBE_EEC_DO 0x00000008 /* EEPROM Data Out */ +#define IXGBE_EEC_FWE_MASK 0x00000030 /* FLASH Write Enable */ +#define IXGBE_EEC_FWE_DIS 0x00000010 /* Disable FLASH writes */ +#define IXGBE_EEC_FWE_EN 0x00000020 /* Enable FLASH writes */ +#define IXGBE_EEC_FWE_SHIFT 4 +#define IXGBE_EEC_REQ 0x00000040 /* EEPROM Access Request */ +#define IXGBE_EEC_GNT 0x00000080 /* EEPROM Access Grant */ +#define IXGBE_EEC_PRES 0x00000100 /* EEPROM Present */ +#define IXGBE_EEC_ARD 0x00000200 /* EEPROM Auto Read Done */ +/* EEPROM Addressing bits based on type (0-small, 1-large) */ +#define IXGBE_EEC_ADDR_SIZE 0x00000400 +#define IXGBE_EEC_SIZE 0x00007800 /* EEPROM Size */ + +#define IXGBE_EEC_SIZE_SHIFT 11 +#define IXGBE_EEPROM_WORD_SIZE_SHIFT 6 +#define IXGBE_EEPROM_OPCODE_BITS 8 + +/* Checksum and EEPROM pointers */ +#define IXGBE_EEPROM_CHECKSUM 0x3F +#define IXGBE_EEPROM_SUM 0xBABA +#define IXGBE_PCIE_ANALOG_PTR 0x03 +#define IXGBE_ATLAS0_CONFIG_PTR 0x04 +#define IXGBE_ATLAS1_CONFIG_PTR 0x05 +#define IXGBE_PCIE_GENERAL_PTR 0x06 +#define IXGBE_PCIE_CONFIG0_PTR 0x07 +#define IXGBE_PCIE_CONFIG1_PTR 0x08 +#define IXGBE_CORE0_PTR 0x09 +#define IXGBE_CORE1_PTR 0x0A +#define IXGBE_MAC0_PTR 0x0B +#define IXGBE_MAC1_PTR 0x0C +#define IXGBE_CSR0_CONFIG_PTR 0x0D +#define IXGBE_CSR1_CONFIG_PTR 0x0E +#define IXGBE_FW_PTR 0x0F +#define IXGBE_PBANUM0_PTR 0x15 +#define IXGBE_PBANUM1_PTR 0x16 + +/* EEPROM Commands - SPI */ +#define IXGBE_EEPROM_MAX_RETRY_SPI 5000 /* Max wait 5ms for RDY signal */ +#define IXGBE_EEPROM_STATUS_RDY_SPI 0x01 +#define IXGBE_EEPROM_READ_OPCODE_SPI 0x03 /* EEPROM read opcode */ +#define IXGBE_EEPROM_WRITE_OPCODE_SPI 0x02 /* EEPROM write opcode */ +#define IXGBE_EEPROM_A8_OPCODE_SPI 0x08 /* opcode bit-3 = addr bit-8 */ +#define IXGBE_EEPROM_WREN_OPCODE_SPI 0x06 /* EEPROM set Write Ena latch */ +/* EEPROM reset Write Enbale latch */ +#define IXGBE_EEPROM_WRDI_OPCODE_SPI 0x04 +#define IXGBE_EEPROM_RDSR_OPCODE_SPI 0x05 /* EEPROM read Status reg */ +#define IXGBE_EEPROM_WRSR_OPCODE_SPI 0x01 /* EEPROM write Status reg */ +#define IXGBE_EEPROM_ERASE4K_OPCODE_SPI 0x20 /* EEPROM ERASE 4KB */ +#define IXGBE_EEPROM_ERASE64K_OPCODE_SPI 0xD8 /* EEPROM ERASE 64KB */ +#define IXGBE_EEPROM_ERASE256_OPCODE_SPI 0xDB /* EEPROM ERASE 256B */ + +/* EEPROM Read Register */ +#define IXGBE_EEPROM_READ_REG_DATA 16 /* data offset in EEPROM read reg */ +#define IXGBE_EEPROM_READ_REG_DONE 2 /* Offset to READ done bit */ +#define IXGBE_EEPROM_READ_REG_START 1 /* First bit to start operation */ +#define IXGBE_EEPROM_READ_ADDR_SHIFT 2 /* Shift to the address bits */ + +#define IXGBE_ETH_LENGTH_OF_ADDRESS 6 + +#ifndef IXGBE_EEPROM_GRANT_ATTEMPTS +#define IXGBE_EEPROM_GRANT_ATTEMPTS 1000 /* EEPROM # attempts to gain grant */ +#endif + +#ifndef IXGBE_EERD_ATTEMPTS +/* Number of 5 microseconds we wait for EERD read to complete */ +#define IXGBE_EERD_ATTEMPTS 100000 +#endif + +/* PCI Bus Info */ +#define IXGBE_PCI_LINK_STATUS 0xB2 +#define IXGBE_PCI_LINK_WIDTH 0x3F0 +#define IXGBE_PCI_LINK_WIDTH_1 0x10 +#define IXGBE_PCI_LINK_WIDTH_2 0x20 +#define IXGBE_PCI_LINK_WIDTH_4 0x40 +#define IXGBE_PCI_LINK_WIDTH_8 0x80 +#define IXGBE_PCI_LINK_SPEED 0xF +#define IXGBE_PCI_LINK_SPEED_2500 0x1 +#define IXGBE_PCI_LINK_SPEED_5000 0x2 + +/* Number of 100 microseconds we wait for PCI Express master disable */ +#define IXGBE_PCI_MASTER_DISABLE_TIMEOUT 800 + +/* PHY Types */ +#define IXGBE_M88E1145_E_PHY_ID 0x01410CD0 + +/* Check whether address is multicast. This is little-endian specific check.*/ +#define IXGBE_IS_MULTICAST(Address) \ + (bool)(((u8 *)(Address))[0] & ((u8)0x01)) + +/* Check whether an address is broadcast. */ +#define IXGBE_IS_BROADCAST(Address) \ + ((((u8 *)(Address))[0] == ((u8)0xff)) && \ + (((u8 *)(Address))[1] == ((u8)0xff))) + +/* RAH */ +#define IXGBE_RAH_VIND_MASK 0x003C0000 +#define IXGBE_RAH_VIND_SHIFT 18 +#define IXGBE_RAH_AV 0x80000000 + +/* Filters */ +#define IXGBE_MC_TBL_SIZE 128 /* Multicast Filter Table (4096 bits) */ +#define IXGBE_VLAN_FILTER_TBL_SIZE 128 /* VLAN Filter Table (4096 bits) */ + +/* Header split receive */ +#define IXGBE_RFCTL_ISCSI_DIS 0x00000001 +#define IXGBE_RFCTL_ISCSI_DWC_MASK 0x0000003E +#define IXGBE_RFCTL_ISCSI_DWC_SHIFT 1 +#define IXGBE_RFCTL_NFSW_DIS 0x00000040 +#define IXGBE_RFCTL_NFSR_DIS 0x00000080 +#define IXGBE_RFCTL_NFS_VER_MASK 0x00000300 +#define IXGBE_RFCTL_NFS_VER_SHIFT 8 +#define IXGBE_RFCTL_NFS_VER_2 0 +#define IXGBE_RFCTL_NFS_VER_3 1 +#define IXGBE_RFCTL_NFS_VER_4 2 +#define IXGBE_RFCTL_IPV6_DIS 0x00000400 +#define IXGBE_RFCTL_IPV6_XSUM_DIS 0x00000800 +#define IXGBE_RFCTL_IPFRSP_DIS 0x00004000 +#define IXGBE_RFCTL_IPV6_EX_DIS 0x00010000 +#define IXGBE_RFCTL_NEW_IPV6_EXT_DIS 0x00020000 + +/* Transmit Config masks */ +#define IXGBE_TXDCTL_ENABLE 0x02000000 /* Enable specific Tx Queue */ +#define IXGBE_TXDCTL_SWFLSH 0x04000000 /* Tx Desc. write-back flushing */ +/* Enable short packet padding to 64 bytes */ +#define IXGBE_TX_PAD_ENABLE 0x00000400 +#define IXGBE_JUMBO_FRAME_ENABLE 0x00000004 /* Allow jumbo frames */ +/* This allows for 16K packets + 4k for vlan */ +#define IXGBE_MAX_FRAME_SZ 0x40040000 + +#define IXGBE_TDWBAL_HEAD_WB_ENABLE 0x1 /* Tx head write-back enable */ +#define IXGBE_TDWBAL_SEQNUM_WB_ENABLE 0x2 /* Tx seq. # write-back enable */ + +/* Receive Config masks */ +#define IXGBE_RXCTRL_RXEN 0x00000001 /* Enable Receiver */ +#define IXGBE_RXCTRL_DMBYPS 0x00000002 /* Descriptor Monitor Bypass */ +#define IXGBE_RXDCTL_ENABLE 0x02000000 /* Enable specific Rx Queue */ + +#define IXGBE_FCTRL_SBP 0x00000002 /* Store Bad Packet */ +#define IXGBE_FCTRL_MPE 0x00000100 /* Multicast Promiscuous Ena*/ +#define IXGBE_FCTRL_UPE 0x00000200 /* Unicast Promiscuous Ena */ +#define IXGBE_FCTRL_BAM 0x00000400 /* Broadcast Accept Mode */ +#define IXGBE_FCTRL_PMCF 0x00001000 /* Pass MAC Control Frames */ +#define IXGBE_FCTRL_DPF 0x00002000 /* Discard Pause Frame */ +/* Receive Priority Flow Control Enbale */ +#define IXGBE_FCTRL_RPFCE 0x00004000 +#define IXGBE_FCTRL_RFCE 0x00008000 /* Receive Flow Control Ena */ + +/* Multiple Receive Queue Control */ +#define IXGBE_MRQC_RSSEN 0x00000001 /* RSS Enable */ +#define IXGBE_MRQC_RSS_FIELD_MASK 0xFFFF0000 +#define IXGBE_MRQC_RSS_FIELD_IPV4_TCP 0x00010000 +#define IXGBE_MRQC_RSS_FIELD_IPV4 0x00020000 +#define IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP 0x00040000 +#define IXGBE_MRQC_RSS_FIELD_IPV6_EX 0x00080000 +#define IXGBE_MRQC_RSS_FIELD_IPV6 0x00100000 +#define IXGBE_MRQC_RSS_FIELD_IPV6_TCP 0x00200000 +#define IXGBE_MRQC_RSS_FIELD_IPV4_UDP 0x00400000 +#define IXGBE_MRQC_RSS_FIELD_IPV6_UDP 0x00800000 +#define IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP 0x01000000 + +#define IXGBE_TXD_POPTS_IXSM 0x01 /* Insert IP checksum */ +#define IXGBE_TXD_POPTS_TXSM 0x02 /* Insert TCP/UDP checksum */ +#define IXGBE_TXD_CMD_EOP 0x01000000 /* End of Packet */ +#define IXGBE_TXD_CMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */ +#define IXGBE_TXD_CMD_IC 0x04000000 /* Insert Checksum */ +#define IXGBE_TXD_CMD_RS 0x08000000 /* Report Status */ +#define IXGBE_TXD_CMD_DEXT 0x20000000 /* Descriptor extension (0 = legacy) */ +#define IXGBE_TXD_CMD_VLE 0x40000000 /* Add VLAN tag */ +#define IXGBE_TXD_STAT_DD 0x00000001 /* Descriptor Done */ + +/* Receive Descriptor bit definitions */ +#define IXGBE_RXD_STAT_DD 0x01 /* Descriptor Done */ +#define IXGBE_RXD_STAT_EOP 0x02 /* End of Packet */ +#define IXGBE_RXD_STAT_IXSM 0x04 /* Ignore checksum */ +#define IXGBE_RXD_STAT_VP 0x08 /* IEEE VLAN Packet */ +#define IXGBE_RXD_STAT_UDPCS 0x10 /* UDP xsum caculated */ +#define IXGBE_RXD_STAT_L4CS 0x20 /* L4 xsum calculated */ +#define IXGBE_RXD_STAT_IPCS 0x40 /* IP xsum calculated */ +#define IXGBE_RXD_STAT_PIF 0x80 /* passed in-exact filter */ +#define IXGBE_RXD_STAT_CRCV 0x100 /* Speculative CRC Valid */ +#define IXGBE_RXD_STAT_VEXT 0x200 /* 1st VLAN found */ +#define IXGBE_RXD_STAT_UDPV 0x400 /* Valid UDP checksum */ +#define IXGBE_RXD_STAT_DYNINT 0x800 /* Pkt caused INT via DYNINT */ +#define IXGBE_RXD_STAT_ACK 0x8000 /* ACK Packet indication */ +#define IXGBE_RXD_ERR_CE 0x01 /* CRC Error */ +#define IXGBE_RXD_ERR_LE 0x02 /* Length Error */ +#define IXGBE_RXD_ERR_PE 0x08 /* Packet Error */ +#define IXGBE_RXD_ERR_OSE 0x10 /* Oversize Error */ +#define IXGBE_RXD_ERR_USE 0x20 /* Undersize Error */ +#define IXGBE_RXD_ERR_TCPE 0x40 /* TCP/UDP Checksum Error */ +#define IXGBE_RXD_ERR_IPE 0x80 /* IP Checksum Error */ +#define IXGBE_RXDADV_HBO 0x00800000 +#define IXGBE_RXDADV_ERR_CE 0x01000000 /* CRC Error */ +#define IXGBE_RXDADV_ERR_LE 0x02000000 /* Length Error */ +#define IXGBE_RXDADV_ERR_PE 0x08000000 /* Packet Error */ +#define IXGBE_RXDADV_ERR_OSE 0x10000000 /* Oversize Error */ +#define IXGBE_RXDADV_ERR_USE 0x20000000 /* Undersize Error */ +#define IXGBE_RXDADV_ERR_TCPE 0x40000000 /* TCP/UDP Checksum Error */ +#define IXGBE_RXDADV_ERR_IPE 0x80000000 /* IP Checksum Error */ +#define IXGBE_RXD_VLAN_ID_MASK 0x0FFF /* VLAN ID is in lower 12 bits */ +#define IXGBE_RXD_PRI_MASK 0xE000 /* Priority is in upper 3 bits */ +#define IXGBE_RXD_PRI_SHIFT 13 +#define IXGBE_RXD_CFI_MASK 0x1000 /* CFI is bit 12 */ +#define IXGBE_RXD_CFI_SHIFT 12 + +/* SRRCTL bit definitions */ +#define IXGBE_SRRCTL_BSIZEPKT_SHIFT 10 /* so many KBs */ +#define IXGBE_SRRCTL_BSIZEPKT_MASK 0x0000007F +#define IXGBE_SRRCTL_BSIZEHDR_MASK 0x00003F00 +#define IXGBE_SRRCTL_DESCTYPE_LEGACY 0x00000000 +#define IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF 0x02000000 +#define IXGBE_SRRCTL_DESCTYPE_HDR_SPLIT 0x04000000 +#define IXGBE_SRRCTL_DESCTYPE_HDR_REPLICATION_LARGE_PKT 0x08000000 +#define IXGBE_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS 0x0A000000 + +#define IXGBE_RXDPS_HDRSTAT_HDRSP 0x00008000 +#define IXGBE_RXDPS_HDRSTAT_HDRLEN_MASK 0x000003FF + +#define IXGBE_RXDADV_RSSTYPE_MASK 0x0000000F +#define IXGBE_RXDADV_PKTTYPE_MASK 0x0000FFF0 +#define IXGBE_RXDADV_HDRBUFLEN_MASK 0x00007FE0 +#define IXGBE_RXDADV_HDRBUFLEN_SHIFT 5 +#define IXGBE_RXDADV_SPLITHEADER_EN 0x00001000 +#define IXGBE_RXDADV_SPH 0x8000 + +/* RSS Hash results */ +#define IXGBE_RXDADV_RSSTYPE_NONE 0x00000000 +#define IXGBE_RXDADV_RSSTYPE_IPV4_TCP 0x00000001 +#define IXGBE_RXDADV_RSSTYPE_IPV4 0x00000002 +#define IXGBE_RXDADV_RSSTYPE_IPV6_TCP 0x00000003 +#define IXGBE_RXDADV_RSSTYPE_IPV6_EX 0x00000004 +#define IXGBE_RXDADV_RSSTYPE_IPV6 0x00000005 +#define IXGBE_RXDADV_RSSTYPE_IPV6_TCP_EX 0x00000006 +#define IXGBE_RXDADV_RSSTYPE_IPV4_UDP 0x00000007 +#define IXGBE_RXDADV_RSSTYPE_IPV6_UDP 0x00000008 +#define IXGBE_RXDADV_RSSTYPE_IPV6_UDP_EX 0x00000009 + +/* RSS Packet Types as indicated in the receive descriptor. */ +#define IXGBE_RXDADV_PKTTYPE_NONE 0x00000000 +#define IXGBE_RXDADV_PKTTYPE_IPV4 0x00000010 /* IPv4 hdr present */ +#define IXGBE_RXDADV_PKTTYPE_IPV4_EX 0x00000020 /* IPv4 hdr + extensions */ +#define IXGBE_RXDADV_PKTTYPE_IPV6 0x00000040 /* IPv6 hdr present */ +#define IXGBE_RXDADV_PKTTYPE_IPV6_EX 0x00000080 /* IPv6 hdr + extensions */ +#define IXGBE_RXDADV_PKTTYPE_TCP 0x00000100 /* TCP hdr present */ +#define IXGBE_RXDADV_PKTTYPE_UDP 0x00000200 /* UDP hdr present */ +#define IXGBE_RXDADV_PKTTYPE_SCTP 0x00000400 /* SCTP hdr present */ +#define IXGBE_RXDADV_PKTTYPE_NFS 0x00000800 /* NFS hdr present */ + +/* Masks to determine if packets should be dropped due to frame errors */ +#define IXGBE_RXD_ERR_FRAME_ERR_MASK (\ + IXGBE_RXD_ERR_CE | \ + IXGBE_RXD_ERR_LE | \ + IXGBE_RXD_ERR_PE | \ + IXGBE_RXD_ERR_OSE | \ + IXGBE_RXD_ERR_USE) + +#define IXGBE_RXDADV_ERR_FRAME_ERR_MASK (\ + IXGBE_RXDADV_ERR_CE | \ + IXGBE_RXDADV_ERR_LE | \ + IXGBE_RXDADV_ERR_PE | \ + IXGBE_RXDADV_ERR_OSE | \ + IXGBE_RXDADV_ERR_USE) + +/* Multicast bit mask */ +#define IXGBE_MCSTCTRL_MFE 0x4 + +/* Number of Transmit and Receive Descriptors must be a multiple of 8 */ +#define IXGBE_REQ_TX_DESCRIPTOR_MULTIPLE 8 +#define IXGBE_REQ_RX_DESCRIPTOR_MULTIPLE 8 +#define IXGBE_REQ_TX_BUFFER_GRANULARITY 1024 + +/* Vlan-specific macros */ +#define IXGBE_RX_DESC_SPECIAL_VLAN_MASK 0x0FFF /* VLAN ID in lower 12 bits */ +#define IXGBE_RX_DESC_SPECIAL_PRI_MASK 0xE000 /* Priority in upper 3 bits */ +#define IXGBE_RX_DESC_SPECIAL_PRI_SHIFT 0x000D /* Priority in upper 3 of 16 */ +#define IXGBE_TX_DESC_SPECIAL_PRI_SHIFT IXGBE_RX_DESC_SPECIAL_PRI_SHIFT + +/* Transmit Descriptor - Legacy */ +struct ixgbe_legacy_tx_desc { + u64 buffer_addr; /* Address of the descriptor's data buffer */ + union { + u32 data; + struct { + u16 length; /* Data buffer length */ + u8 cso; /* Checksum offset */ + u8 cmd; /* Descriptor control */ + } flags; + } lower; + union { + u32 data; + struct { + u8 status; /* Descriptor status */ + u8 css; /* Checksum start */ + u16 vlan; + } fields; + } upper; +}; + +/* Transmit Descriptor - Advanced */ +union ixgbe_adv_tx_desc { + struct { + u64 buffer_addr; /* Address of descriptor's data buf */ + u32 cmd_type_len; + u32 olinfo_status; + } read; + struct { + u64 rsvd; /* Reserved */ + u32 nxtseq_seed; + u32 status; + } wb; +}; + +/* Receive Descriptor - Legacy */ +struct ixgbe_legacy_rx_desc { + u64 buffer_addr; /* Address of the descriptor's data buffer */ + u16 length; /* Length of data DMAed into data buffer */ + u16 csum; /* Packet checksum */ + u8 status; /* Descriptor status */ + u8 errors; /* Descriptor Errors */ + u16 vlan; +}; + +/* Receive Descriptor - Advanced */ +union ixgbe_adv_rx_desc { + struct { + u64 pkt_addr; /* Packet buffer address */ + u64 hdr_addr; /* Header buffer address */ + } read; + struct { + struct { + struct { + u16 pkt_info; /* RSS type, Packet type */ + u16 hdr_info; /* Split Header, header len */ + } lo_dword; + union { + u32 rss; /* RSS Hash */ + struct { + u16 ip_id; /* IP id */ + u16 csum; /* Packet Checksum */ + } csum_ip; + } hi_dword; + } lower; + struct { + u32 status_error; /* ext status/error */ + u16 length; /* Packet length */ + u16 vlan; /* VLAN tag */ + } upper; + } wb; /* writeback */ +}; + +/* Context descriptors */ +struct ixgbe_adv_tx_context_desc { + u32 vlan_macip_lens; + u32 seqnum_seed; + u32 type_tucmd_mlhl; + u32 mss_l4len_idx; +}; + +/* Adv Transmit Descriptor Config Masks */ +#define IXGBE_ADVTXD_DTALEN_MASK 0x0000FFFF /* Data buffer length(bytes) */ +#define IXGBE_ADVTXD_DTYP_MASK 0x00F00000 /* DTYP mask */ +#define IXGBE_ADVTXD_DTYP_CTXT 0x00200000 /* Advanced Context Desc */ +#define IXGBE_ADVTXD_DTYP_DATA 0x00300000 /* Advanced Data Descriptor */ +#define IXGBE_ADVTXD_DCMD_EOP IXGBE_TXD_CMD_EOP /* End of Packet */ +#define IXGBE_ADVTXD_DCMD_IFCS IXGBE_TXD_CMD_IFCS /* Insert FCS */ +#define IXGBE_ADVTXD_DCMD_RDMA 0x04000000 /* RDMA */ +#define IXGBE_ADVTXD_DCMD_RS IXGBE_TXD_CMD_RS /* Report Status */ +#define IXGBE_ADVTXD_DCMD_DDTYP_ISCSI 0x10000000 /* DDP hdr type or iSCSI */ +#define IXGBE_ADVTXD_DCMD_DEXT IXGBE_TXD_CMD_DEXT /* Desc ext (1=Adv) */ +#define IXGBE_ADVTXD_DCMD_VLE IXGBE_TXD_CMD_VLE /* VLAN pkt enable */ +#define IXGBE_ADVTXD_DCMD_TSE 0x80000000 /* TCP Seg enable */ +#define IXGBE_ADVTXD_STAT_DD IXGBE_TXD_STAT_DD /* Descriptor Done */ +#define IXGBE_ADVTXD_STAT_SN_CRC 0x00000002 /* NXTSEQ/SEED present in WB */ +#define IXGBE_ADVTXD_STAT_RSV 0x0000000C /* STA Reserved */ +#define IXGBE_ADVTXD_IDX_SHIFT 4 /* Adv desc Index shift */ +#define IXGBE_ADVTXD_POPTS_SHIFT 8 /* Adv desc POPTS shift */ +#define IXGBE_ADVTXD_POPTS_IXSM (IXGBE_TXD_POPTS_IXSM << \ + IXGBE_ADVTXD_POPTS_SHIFT) +#define IXGBE_ADVTXD_POPTS_TXSM (IXGBE_TXD_POPTS_TXSM << \ + IXGBE_ADVTXD_POPTS_SHIFT) +#define IXGBE_ADVTXD_POPTS_EOM 0x00000400 /* Enable L bit-RDMA DDP hdr */ +#define IXGBE_ADVTXD_POPTS_ISCO_1ST 0x00000000 /* 1st TSO of iSCSI PDU */ +#define IXGBE_ADVTXD_POPTS_ISCO_MDL 0x00000800 /* Middle TSO of iSCSI PDU */ +#define IXGBE_ADVTXD_POPTS_ISCO_LAST 0x00001000 /* Last TSO of iSCSI PDU */ +#define IXGBE_ADVTXD_POPTS_ISCO_FULL 0x00001800 /* 1st&Last TSO-full iSCSI PDU*/ +#define IXGBE_ADVTXD_POPTS_RSV 0x00002000 /* POPTS Reserved */ +#define IXGBE_ADVTXD_PAYLEN_SHIFT 14 /* Adv desc PAYLEN shift */ +#define IXGBE_ADVTXD_MACLEN_SHIFT 9 /* Adv ctxt desc mac len shift */ +#define IXGBE_ADVTXD_VLAN_SHIFT 16 /* Adv ctxt vlan tag shift */ +#define IXGBE_ADVTXD_TUCMD_IPV4 0x00000400 /* IP Packet Type: 1=IPv4 */ +#define IXGBE_ADVTXD_TUCMD_IPV6 0x00000000 /* IP Packet Type: 0=IPv6 */ +#define IXGBE_ADVTXD_TUCMD_L4T_UDP 0x00000000 /* L4 Packet TYPE of UDP */ +#define IXGBE_ADVTXD_TUCMD_L4T_TCP 0x00000800 /* L4 Packet TYPE of TCP */ +#define IXGBE_ADVTXD_TUCMD_MKRREQ 0x00002000 /* Req requires Markers and CRC */ +#define IXGBE_ADVTXD_L4LEN_SHIFT 8 /* Adv ctxt L4LEN shift */ +#define IXGBE_ADVTXD_MSS_SHIFT 16 /* Adv ctxt MSS shift */ + +/* Link speed */ +#define IXGBE_LINK_SPEED_UNKNOWN 0 +#define IXGBE_LINK_SPEED_100_FULL 0x0008 +#define IXGBE_LINK_SPEED_1GB_FULL 0x0020 +#define IXGBE_LINK_SPEED_10GB_FULL 0x0080 + + +enum ixgbe_eeprom_type { + ixgbe_eeprom_uninitialized = 0, + ixgbe_eeprom_spi, + ixgbe_eeprom_none /* No NVM support */ +}; + +enum ixgbe_mac_type { + ixgbe_mac_unknown = 0, + ixgbe_mac_82598EB, + ixgbe_num_macs +}; + +enum ixgbe_phy_type { + ixgbe_phy_unknown = 0, + ixgbe_phy_tn, + ixgbe_phy_qt, + ixgbe_phy_xaui +}; + +enum ixgbe_media_type { + ixgbe_media_type_unknown = 0, + ixgbe_media_type_fiber, + ixgbe_media_type_copper, + ixgbe_media_type_backplane +}; + +/* Flow Control Settings */ +enum ixgbe_fc_type { + ixgbe_fc_none = 0, + ixgbe_fc_rx_pause, + ixgbe_fc_tx_pause, + ixgbe_fc_full, + ixgbe_fc_default +}; + +struct ixgbe_addr_filter_info { + u32 num_mc_addrs; + u32 rar_used_count; + u32 mc_addr_in_rar_count; + u32 mta_in_use; +}; + +/* Flow control parameters */ +struct ixgbe_fc_info { + u32 high_water; /* Flow Control High-water */ + u32 low_water; /* Flow Control Low-water */ + u16 pause_time; /* Flow Control Pause timer */ + bool send_xon; /* Flow control send XON */ + bool strict_ieee; /* Strict IEEE mode */ + enum ixgbe_fc_type type; /* Type of flow control */ + enum ixgbe_fc_type original_type; +}; + +/* Statistics counters collected by the MAC */ +struct ixgbe_hw_stats { + u64 crcerrs; + u64 illerrc; + u64 errbc; + u64 mspdc; + u64 mpctotal; + u64 mpc[8]; + u64 mlfc; + u64 mrfc; + u64 rlec; + u64 lxontxc; + u64 lxonrxc; + u64 lxofftxc; + u64 lxoffrxc; + u64 pxontxc[8]; + u64 pxonrxc[8]; + u64 pxofftxc[8]; + u64 pxoffrxc[8]; + u64 prc64; + u64 prc127; + u64 prc255; + u64 prc511; + u64 prc1023; + u64 prc1522; + u64 gprc; + u64 bprc; + u64 mprc; + u64 gptc; + u64 gorc; + u64 gotc; + u64 rnbc[8]; + u64 ruc; + u64 rfc; + u64 roc; + u64 rjc; + u64 mngprc; + u64 mngpdc; + u64 mngptc; + u64 tor; + u64 tpr; + u64 tpt; + u64 ptc64; + u64 ptc127; + u64 ptc255; + u64 ptc511; + u64 ptc1023; + u64 ptc1522; + u64 mptc; + u64 bptc; + u64 xec; + u64 rqsmr[16]; + u64 tqsmr[8]; + u64 qprc[16]; + u64 qptc[16]; + u64 qbrc[16]; + u64 qbtc[16]; +}; + +/* forward declaration */ +struct ixgbe_hw; + +struct ixgbe_mac_operations { + s32 (*reset)(struct ixgbe_hw *); + enum ixgbe_media_type (*get_media_type)(struct ixgbe_hw *); +}; + +struct ixgbe_phy_operations { + s32 (*setup)(struct ixgbe_hw *); + s32 (*check)(struct ixgbe_hw *, u32 *, bool *); + s32 (*setup_speed)(struct ixgbe_hw *, u32, bool, bool); + s32 (*get_settings)(struct ixgbe_hw *, u32 *, bool *); +}; + +struct ixgbe_mac_info { + struct ixgbe_mac_operations ops; + enum ixgbe_mac_type type; + u8 addr[IXGBE_ETH_LENGTH_OF_ADDRESS]; + u8 perm_addr[IXGBE_ETH_LENGTH_OF_ADDRESS]; + s32 mc_filter_type; + u32 num_rx_queues; + u32 num_tx_queues; + u32 num_rx_addrs; + u32 link_attach_type; + u32 link_mode_select; + bool link_settings_loaded; +}; + + +struct ixgbe_eeprom_info { + enum ixgbe_eeprom_type type; + u16 word_size; + u16 address_bits; +}; + +struct ixgbe_phy_info { + struct ixgbe_phy_operations ops; + + enum ixgbe_phy_type type; + u32 addr; + u32 id; + u32 revision; + enum ixgbe_media_type media_type; + u32 autoneg_advertised; + bool autoneg_wait_to_complete; +}; + +struct ixgbe_info { + enum ixgbe_mac_type mac; + s32 (*get_invariants)(struct ixgbe_hw *); + struct ixgbe_mac_operations *mac_ops; + struct ixgbe_phy_operations *phy_ops; +}; + +struct ixgbe_hw { + u8 __iomem *hw_addr; + void *back; + struct ixgbe_mac_info mac; + struct ixgbe_addr_filter_info addr_ctrl; + struct ixgbe_fc_info fc; + struct ixgbe_phy_info phy; + struct ixgbe_eeprom_info eeprom; + u16 device_id; + u16 vendor_id; + u16 subsystem_device_id; + u16 subsystem_vendor_id; + u8 revision_id; + bool adapter_stopped; +}; + +/* Error Codes */ +#define IXGBE_ERR_EEPROM -1 +#define IXGBE_ERR_EEPROM_CHECKSUM -2 +#define IXGBE_ERR_PHY -3 +#define IXGBE_ERR_CONFIG -4 +#define IXGBE_ERR_PARAM -5 +#define IXGBE_ERR_MAC_TYPE -6 +#define IXGBE_ERR_UNKNOWN_PHY -7 +#define IXGBE_ERR_LINK_SETUP -8 +#define IXGBE_ERR_ADAPTER_STOPPED -9 +#define IXGBE_ERR_INVALID_MAC_ADDR -10 +#define IXGBE_ERR_DEVICE_NOT_SUPPORTED -11 +#define IXGBE_ERR_MASTER_REQUESTS_PENDING -12 +#define IXGBE_ERR_INVALID_LINK_SETTINGS -13 +#define IXGBE_ERR_AUTONEG_NOT_COMPLETE -14 +#define IXGBE_ERR_RESET_FAILED -15 +#define IXGBE_ERR_SWFW_SYNC -16 +#define IXGBE_ERR_PHY_ADDR_INVALID -17 +#define IXGBE_NOT_IMPLEMENTED 0x7FFFFFFF + +#endif /* _IXGBE_TYPE_H_ */ -- cgit v1.2.3-70-g09d2 From 34c6417b7087a4818e7dca2e5d66c3361cee80a1 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 6 Sep 2007 11:51:37 -0700 Subject: e100: timer power saving Since E100 timer is 2HZ, use rounding to make timer occur on the correct boundary. Signed-off-by: Stephen Hemminger Signed-off-by: Auke Kok Signed-off-by: Jeff Garzik --- drivers/net/e100.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/e100.c b/drivers/net/e100.c index e25f5ec2b27..10907f158ba 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -1605,7 +1605,8 @@ static void e100_watchdog(unsigned long data) else nic->flags &= ~ich_10h_workaround; - mod_timer(&nic->watchdog, jiffies + E100_WATCHDOG_PERIOD); + mod_timer(&nic->watchdog, + round_jiffies(jiffies + E100_WATCHDOG_PERIOD)); } static void e100_xmit_prepare(struct nic *nic, struct cb *cb, -- cgit v1.2.3-70-g09d2 From a5a3b4601bfa3c7671944067d4e4b04bf647e6d9 Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Wed, 5 Sep 2007 15:58:09 -0700 Subject: cxgb3 - Firmware update Update firmware version. Allow the driver to be up and running with older FW image Signed-off-by: Divy Le Ray Signed-off-by: Jeff Garzik --- drivers/net/cxgb3/common.h | 2 +- drivers/net/cxgb3/cxgb3_main.c | 9 +++++---- drivers/net/cxgb3/t3_hw.c | 20 +++++++++++++++----- drivers/net/cxgb3/version.h | 2 +- 4 files changed, 22 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h index 510e93f90b9..ada5e4b89cd 100644 --- a/drivers/net/cxgb3/common.h +++ b/drivers/net/cxgb3/common.h @@ -690,7 +690,7 @@ int t3_read_flash(struct adapter *adapter, unsigned int addr, unsigned int nwords, u32 *data, int byte_oriented); int t3_load_fw(struct adapter *adapter, const u8 * fw_data, unsigned int size); int t3_get_fw_version(struct adapter *adapter, u32 *vers); -int t3_check_fw_version(struct adapter *adapter); +int t3_check_fw_version(struct adapter *adapter, int *must_load); int t3_init_hw(struct adapter *adapter, u32 fw_params); void mac_prep(struct cmac *mac, struct adapter *adapter, int index); void early_hw_init(struct adapter *adapter, const struct adapter_info *ai); diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index 3ee465dd0b0..8f1d602a883 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -797,11 +797,12 @@ static int cxgb_up(struct adapter *adap) int must_load; if (!(adap->flags & FULL_INIT_DONE)) { - err = t3_check_fw_version(adap); - if (err == -EINVAL) + err = t3_check_fw_version(adap, &must_load); + if (err == -EINVAL) { err = upgrade_fw(adap); - if (err) - goto out; + if (err && must_load) + goto out; + } err = t3_check_tpsram_version(adap, &must_load); if (err == -EINVAL) { diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c index e958bbe3062..2b49b96a6fd 100644 --- a/drivers/net/cxgb3/t3_hw.c +++ b/drivers/net/cxgb3/t3_hw.c @@ -960,16 +960,18 @@ int t3_get_fw_version(struct adapter *adapter, u32 *vers) /** * t3_check_fw_version - check if the FW is compatible with this driver * @adapter: the adapter - * + * @must_load: set to 1 if loading a new FW image is required + * Checks if an adapter's FW is compatible with the driver. Returns 0 * if the versions are compatible, a negative error otherwise. */ -int t3_check_fw_version(struct adapter *adapter) +int t3_check_fw_version(struct adapter *adapter, int *must_load) { int ret; u32 vers; unsigned int type, major, minor; + *must_load = 1; ret = t3_get_fw_version(adapter, &vers); if (ret) return ret; @@ -982,9 +984,17 @@ int t3_check_fw_version(struct adapter *adapter) minor == FW_VERSION_MINOR) return 0; - CH_ERR(adapter, "found wrong FW version(%u.%u), " - "driver needs version %u.%u\n", major, minor, - FW_VERSION_MAJOR, FW_VERSION_MINOR); + if (major != FW_VERSION_MAJOR) + CH_ERR(adapter, "found wrong FW version(%u.%u), " + "driver needs version %u.%u\n", major, minor, + FW_VERSION_MAJOR, FW_VERSION_MINOR); + else { + *must_load = 0; + CH_WARN(adapter, "found wrong FW minor version(%u.%u), " + "driver compiled for version %u.%u\n", major, minor, + FW_VERSION_MAJOR, FW_VERSION_MINOR); + } + return -EINVAL; } diff --git a/drivers/net/cxgb3/version.h b/drivers/net/cxgb3/version.h index eb508bf8022..ef1c6339c80 100644 --- a/drivers/net/cxgb3/version.h +++ b/drivers/net/cxgb3/version.h @@ -39,6 +39,6 @@ /* Firmware version */ #define FW_VERSION_MAJOR 4 -#define FW_VERSION_MINOR 3 +#define FW_VERSION_MINOR 6 #define FW_VERSION_MICRO 0 #endif /* __CHELSIO_VERSION_H */ -- cgit v1.2.3-70-g09d2 From 3eea3337a08a2ed2addac1551a9d446f2c16acd5 Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Wed, 5 Sep 2007 15:58:15 -0700 Subject: cxgb3 - log and clear PEX errors Clear pciE PEX errors late at module load time. Log details when PEX errors occur. Signed-off-by: Divy Le Ray Signed-off-by: Jeff Garzik --- drivers/net/cxgb3/t3_hw.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c index 2b49b96a6fd..cdcfc132e37 100644 --- a/drivers/net/cxgb3/t3_hw.c +++ b/drivers/net/cxgb3/t3_hw.c @@ -1358,6 +1358,10 @@ static void pcie_intr_handler(struct adapter *adapter) {0} }; + if (t3_read_reg(adapter, A_PCIE_INT_CAUSE) & F_PEXERR) + CH_ALERT(adapter, "PEX error code 0x%x\n", + t3_read_reg(adapter, A_PCIE_PEX_ERR)); + if (t3_handle_intr_status(adapter, A_PCIE_INT_CAUSE, PCIE_INTR_MASK, pcie_intr_info, adapter->irq_stats)) t3_fatal_err(adapter); @@ -1809,6 +1813,8 @@ void t3_intr_clear(struct adapter *adapter) for (i = 0; i < ARRAY_SIZE(cause_reg_addr); ++i) t3_write_reg(adapter, cause_reg_addr[i], 0xffffffff); + if (is_pcie(adapter)) + t3_write_reg(adapter, A_PCIE_PEX_ERR, 0xffffffff); t3_write_reg(adapter, A_PL_INT_CAUSE0, 0xffffffff); t3_read_reg(adapter, A_PL_INT_CAUSE0); /* flush */ } -- cgit v1.2.3-70-g09d2 From b4687ff753c2c5c330989efed7cdf1a6bc6b512e Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Wed, 5 Sep 2007 15:58:20 -0700 Subject: cxgb3 - remove false positive in xgmac workaround Qualify toggling of xgmac tx enable with not getting pause frames, we might not make forward progress because the peer is sending lots of pause frames. Signed-off-by: Divy Le Ray Signed-off-by: Jeff Garzik --- drivers/net/cxgb3/common.h | 1 + drivers/net/cxgb3/xgmac.c | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h index ada5e4b89cd..7e9e43d1074 100644 --- a/drivers/net/cxgb3/common.h +++ b/drivers/net/cxgb3/common.h @@ -513,6 +513,7 @@ struct cmac { u64 rx_mcnt; unsigned int toggle_cnt; unsigned int txen; + u64 rx_pause; struct mac_stats stats; }; diff --git a/drivers/net/cxgb3/xgmac.c b/drivers/net/cxgb3/xgmac.c index 1d1c3919ab6..ff9e9dcbd87 100644 --- a/drivers/net/cxgb3/xgmac.c +++ b/drivers/net/cxgb3/xgmac.c @@ -452,6 +452,7 @@ int t3_mac_enable(struct cmac *mac, int which) A_XGM_TX_SPI4_SOP_EOP_CNT + oft))); mac->rx_mcnt = s->rx_frames; + mac->rx_pause = s->rx_pause; mac->rx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap, A_XGM_RX_SPI4_SOP_EOP_CNT + oft))); @@ -504,7 +505,7 @@ int t3b2_mac_watchdog_task(struct cmac *mac) tx_xcnt = 1; /* By default tx_xcnt is making progress */ tx_tcnt = mac->tx_tcnt; /* If tx_mcnt is progressing ignore tx_tcnt */ rx_xcnt = 1; /* By default rx_xcnt is making progress */ - if (tx_mcnt == mac->tx_mcnt) { + if (tx_mcnt == mac->tx_mcnt && mac->rx_pause == s->rx_pause) { tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap, A_XGM_TX_SPI4_SOP_EOP_CNT + mac->offset))); @@ -560,6 +561,7 @@ out: mac->tx_mcnt = s->tx_frames; mac->rx_xcnt = rx_xcnt; mac->rx_mcnt = s->rx_frames; + mac->rx_pause = s->rx_pause; if (status == 1) { t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0); t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset); /* flush */ -- cgit v1.2.3-70-g09d2 From 1c17ae8af93bed203d9760702882e9f747a51912 Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Wed, 5 Sep 2007 15:58:25 -0700 Subject: cxgb3 - Set the CQ_ERR bit in CQ contexts. The cxgb3 driver is incorrectly configuring the HW CQ context for CQ's that use overflow-avoidance. Namely the RDMA control CQ. This results in a bad DMA from the device to bus address 0. The solution is to set the CQ_ERR bit in the context for these types of CQs. Signed-off-by: Divy Le Ray Signed-off-by: Jeff Garzik --- drivers/net/cxgb3/sge_defs.h | 4 ++++ drivers/net/cxgb3/t3_hw.c | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/cxgb3/sge_defs.h b/drivers/net/cxgb3/sge_defs.h index 514869e26a7..29b6c800b23 100644 --- a/drivers/net/cxgb3/sge_defs.h +++ b/drivers/net/cxgb3/sge_defs.h @@ -106,6 +106,10 @@ #define V_CQ_GEN(x) ((x) << S_CQ_GEN) #define F_CQ_GEN V_CQ_GEN(1U) +#define S_CQ_ERR 30 +#define V_CQ_ERR(x) ((x) << S_CQ_ERR) +#define F_CQ_ERR V_CQ_ERR(1U) + #define S_CQ_OVERFLOW_MODE 31 #define V_CQ_OVERFLOW_MODE(x) ((x) << S_CQ_OVERFLOW_MODE) #define F_CQ_OVERFLOW_MODE V_CQ_OVERFLOW_MODE(1U) diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c index cdcfc132e37..bff1d028a96 100644 --- a/drivers/net/cxgb3/t3_hw.c +++ b/drivers/net/cxgb3/t3_hw.c @@ -2046,7 +2046,8 @@ int t3_sge_init_cqcntxt(struct adapter *adapter, unsigned int id, u64 base_addr, base_addr >>= 32; t3_write_reg(adapter, A_SG_CONTEXT_DATA2, V_CQ_BASE_HI((u32) base_addr) | V_CQ_RSPQ(rspq) | - V_CQ_GEN(1) | V_CQ_OVERFLOW_MODE(ovfl_mode)); + V_CQ_GEN(1) | V_CQ_OVERFLOW_MODE(ovfl_mode) | + V_CQ_ERR(ovfl_mode)); t3_write_reg(adapter, A_SG_CONTEXT_DATA3, V_CQ_CREDITS(credits) | V_CQ_CREDIT_THRES(credit_thres)); return t3_sge_write_context(adapter, id, F_CQ); -- cgit v1.2.3-70-g09d2 From bb9366af7b4addb27156585baccadc4b6d30f223 Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Wed, 5 Sep 2007 15:58:30 -0700 Subject: cxgb3 - CQ context operations time out too soon. Currently, the driver only tries up to 5 times (5us) to get the results of a CQ context operation. Testing has shown the chip can take as much as 50us to return the response on SG_CONTEXT_CMD operations. So we up the retry count to 100 to cover high loads. Signed-off-by: Divy Le Ray Signed-off-by: Jeff Garzik --- drivers/net/cxgb3/t3_hw.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c index bff1d028a96..05832932144 100644 --- a/drivers/net/cxgb3/t3_hw.c +++ b/drivers/net/cxgb3/t3_hw.c @@ -1870,6 +1870,8 @@ void t3_port_intr_clear(struct adapter *adapter, int idx) phy->ops->intr_clear(phy); } +#define SG_CONTEXT_CMD_ATTEMPTS 100 + /** * t3_sge_write_context - write an SGE context * @adapter: the adapter @@ -1889,7 +1891,7 @@ static int t3_sge_write_context(struct adapter *adapter, unsigned int id, t3_write_reg(adapter, A_SG_CONTEXT_CMD, V_CONTEXT_CMD_OPCODE(1) | type | V_CONTEXT(id)); return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, - 0, 5, 1); + 0, SG_CONTEXT_CMD_ATTEMPTS, 1); } /** @@ -2075,7 +2077,7 @@ int t3_sge_enable_ecntxt(struct adapter *adapter, unsigned int id, int enable) t3_write_reg(adapter, A_SG_CONTEXT_CMD, V_CONTEXT_CMD_OPCODE(1) | F_EGRESS | V_CONTEXT(id)); return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, - 0, 5, 1); + 0, SG_CONTEXT_CMD_ATTEMPTS, 1); } /** @@ -2099,7 +2101,7 @@ int t3_sge_disable_fl(struct adapter *adapter, unsigned int id) t3_write_reg(adapter, A_SG_CONTEXT_CMD, V_CONTEXT_CMD_OPCODE(1) | F_FREELIST | V_CONTEXT(id)); return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, - 0, 5, 1); + 0, SG_CONTEXT_CMD_ATTEMPTS, 1); } /** @@ -2123,7 +2125,7 @@ int t3_sge_disable_rspcntxt(struct adapter *adapter, unsigned int id) t3_write_reg(adapter, A_SG_CONTEXT_CMD, V_CONTEXT_CMD_OPCODE(1) | F_RESPONSEQ | V_CONTEXT(id)); return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, - 0, 5, 1); + 0, SG_CONTEXT_CMD_ATTEMPTS, 1); } /** @@ -2147,7 +2149,7 @@ int t3_sge_disable_cqcntxt(struct adapter *adapter, unsigned int id) t3_write_reg(adapter, A_SG_CONTEXT_CMD, V_CONTEXT_CMD_OPCODE(1) | F_CQ | V_CONTEXT(id)); return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, - 0, 5, 1); + 0, SG_CONTEXT_CMD_ATTEMPTS, 1); } /** @@ -2172,7 +2174,7 @@ int t3_sge_cqcntxt_op(struct adapter *adapter, unsigned int id, unsigned int op, t3_write_reg(adapter, A_SG_CONTEXT_CMD, V_CONTEXT_CMD_OPCODE(op) | V_CONTEXT(id) | F_CQ); if (t3_wait_op_done_val(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, - 0, 5, 1, &val)) + 0, SG_CONTEXT_CMD_ATTEMPTS, 1, &val)) return -EIO; if (op >= 2 && op < 7) { @@ -2182,7 +2184,8 @@ int t3_sge_cqcntxt_op(struct adapter *adapter, unsigned int id, unsigned int op, t3_write_reg(adapter, A_SG_CONTEXT_CMD, V_CONTEXT_CMD_OPCODE(0) | F_CQ | V_CONTEXT(id)); if (t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, - F_CONTEXT_CMD_BUSY, 0, 5, 1)) + F_CONTEXT_CMD_BUSY, 0, + SG_CONTEXT_CMD_ATTEMPTS, 1)) return -EIO; return G_CQ_INDEX(t3_read_reg(adapter, A_SG_CONTEXT_DATA0)); } @@ -2208,7 +2211,7 @@ static int t3_sge_read_context(unsigned int type, struct adapter *adapter, t3_write_reg(adapter, A_SG_CONTEXT_CMD, V_CONTEXT_CMD_OPCODE(0) | type | V_CONTEXT(id)); if (t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, 0, - 5, 1)) + SG_CONTEXT_CMD_ATTEMPTS, 1)) return -EIO; data[0] = t3_read_reg(adapter, A_SG_CONTEXT_DATA0); data[1] = t3_read_reg(adapter, A_SG_CONTEXT_DATA1); -- cgit v1.2.3-70-g09d2 From 1aafee265723818d903766212015b6116885bc6f Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Wed, 5 Sep 2007 15:58:36 -0700 Subject: cxgb3 - Add T3C rev add driver recognition for T3C rev board. Signed-off-by: Divy Le Ray Signed-off-by: Jeff Garzik --- drivers/net/cxgb3/common.h | 1 + drivers/net/cxgb3/cxgb3_main.c | 3 +++ 2 files changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h index 7e9e43d1074..d3f276c2c01 100644 --- a/drivers/net/cxgb3/common.h +++ b/drivers/net/cxgb3/common.h @@ -438,6 +438,7 @@ enum { /* chip revisions */ T3_REV_A = 0, T3_REV_B = 2, T3_REV_B2 = 3, + T3_REV_C = 4, }; struct trace_params { diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index 8f1d602a883..a6723ae79bd 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -733,6 +733,9 @@ static inline char t3rev2char(struct adapter *adapter) case T3_REV_B2: rev = 'b'; break; + case T3_REV_C: + rev = 'c'; + break; } return rev; } -- cgit v1.2.3-70-g09d2 From dc67369573eee33a4b1220d416cb7dd3501dccbc Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Wed, 5 Sep 2007 15:58:41 -0700 Subject: cxgb3 - Update engine microcode version The new microcode engine version is set to 1.1.0 Signed-off-by: Divy Le Ray Signed-off-by: Jeff Garzik --- drivers/net/cxgb3/common.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h index d3f276c2c01..3e5b0db7784 100644 --- a/drivers/net/cxgb3/common.h +++ b/drivers/net/cxgb3/common.h @@ -127,8 +127,8 @@ enum { /* adapter interrupt-maintained statistics */ enum { TP_VERSION_MAJOR = 1, - TP_VERSION_MINOR = 0, - TP_VERSION_MICRO = 44 + TP_VERSION_MINOR = 1, + TP_VERSION_MICRO = 0 }; #define S_TP_VERSION_MAJOR 16 -- cgit v1.2.3-70-g09d2 From 99cd149efe824cf27c5d34506002a0fbfa831c0f Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 4 Sep 2007 14:41:01 +0100 Subject: sgiseeq: replace use of dma_cache_wback_inv The sgiseeq driver is one of the few remaining users of the ancient cache banging DMA API. Replaced with the modern days DMA API. Signed-off-by: Ralf Baechle Signed-off-by: Jeff Garzik --- drivers/net/sgiseeq.c | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c index 0fb74cb51c4..eb67b024e41 100644 --- a/drivers/net/sgiseeq.c +++ b/drivers/net/sgiseeq.c @@ -75,6 +75,7 @@ struct sgiseeq_init_block { /* Note the name ;-) */ struct sgiseeq_private { struct sgiseeq_init_block *srings; + dma_addr_t srings_dma; /* Ptrs to the descriptors in uncached space. */ struct sgiseeq_rx_desc *rx_desc; @@ -643,13 +644,20 @@ static int __init sgiseeq_probe(struct platform_device *pdev) sp = netdev_priv(dev); /* Make private data page aligned */ - sr = (struct sgiseeq_init_block *) get_zeroed_page(GFP_KERNEL); + sr = dma_alloc_coherent(&pdev->dev, sizeof(*sp->srings), + &sp->srings_dma, GFP_KERNEL); if (!sr) { printk(KERN_ERR "Sgiseeq: Page alloc failed, aborting.\n"); err = -ENOMEM; goto err_out_free_dev; } sp->srings = sr; + sp->rx_desc = sp->srings->rxvector; + sp->tx_desc = sp->srings->txvector; + + /* A couple calculations now, saves many cycles later. */ + setup_rx_ring(sp->rx_desc, SEEQ_RX_BUFFERS); + setup_tx_ring(sp->tx_desc, SEEQ_TX_BUFFERS); memcpy(dev->dev_addr, pd->mac, ETH_ALEN); @@ -662,19 +670,6 @@ static int __init sgiseeq_probe(struct platform_device *pdev) sp->name = sgiseeqstr; sp->mode = SEEQ_RCMD_RBCAST; - sp->rx_desc = (struct sgiseeq_rx_desc *) - CKSEG1ADDR(ALIGNED(&sp->srings->rxvector[0])); - dma_cache_wback_inv((unsigned long)&sp->srings->rxvector, - sizeof(sp->srings->rxvector)); - sp->tx_desc = (struct sgiseeq_tx_desc *) - CKSEG1ADDR(ALIGNED(&sp->srings->txvector[0])); - dma_cache_wback_inv((unsigned long)&sp->srings->txvector, - sizeof(sp->srings->txvector)); - - /* A couple calculations now, saves many cycles later. */ - setup_rx_ring(sp->rx_desc, SEEQ_RX_BUFFERS); - setup_tx_ring(sp->tx_desc, SEEQ_TX_BUFFERS); - /* Setup PIO and DMA transfer timing */ sp->hregs->pconfig = 0x161; sp->hregs->dconfig = HPC3_EDCFG_FIRQ | HPC3_EDCFG_FEOP | @@ -732,7 +727,8 @@ static int __exit sgiseeq_remove(struct platform_device *pdev) struct sgiseeq_private *sp = netdev_priv(dev); unregister_netdev(dev); - free_page((unsigned long) sp->srings); + dma_free_coherent(&pdev->dev, sizeof(*sp->srings), sp->srings, + sp->srings_dma); free_netdev(dev); platform_set_drvdata(pdev, NULL); -- cgit v1.2.3-70-g09d2 From ed9f0e0bf3ceb44334ca9b70779a50b2e79b7f97 Mon Sep 17 00:00:00 2001 From: Thomas Bogendoerfer Date: Sat, 8 Sep 2007 21:46:49 +0200 Subject: remove setup of platform device from jazzsonic.c remove setup platform device from jazzsonic, which is done in arch code now Signed-off-by: Thomas Bogendoerfer Signed-off-by: Jeff Garzik --- drivers/net/jazzsonic.c | 61 ++++++------------------------------------------- 1 file changed, 7 insertions(+), 54 deletions(-) (limited to 'drivers') diff --git a/drivers/net/jazzsonic.c b/drivers/net/jazzsonic.c index 75f6f441e87..b71e6633f42 100644 --- a/drivers/net/jazzsonic.c +++ b/drivers/net/jazzsonic.c @@ -45,7 +45,6 @@ #include static char jazz_sonic_string[] = "jazzsonic"; -static struct platform_device *jazz_sonic_device; #define SONIC_MEM_SIZE 0x100 @@ -69,14 +68,6 @@ static unsigned int sonic_debug = SONIC_DEBUG; static unsigned int sonic_debug = 1; #endif -/* - * Base address and interrupt of the SONIC controller on JAZZ boards - */ -static struct { - unsigned int port; - unsigned int irq; -} sonic_portlist[] = { {JAZZ_ETHERNET_BASE, JAZZ_ETHERNET_IRQ}, {0, 0}}; - /* * We cannot use station (ethernet) address prefixes to detect the * sonic controller since these are board manufacturer depended. @@ -215,13 +206,12 @@ static int __init jazz_sonic_probe(struct platform_device *pdev) { struct net_device *dev; struct sonic_local *lp; + struct resource *res; int err = 0; int i; - /* - * Don't probe if we're not running on a Jazz board. - */ - if (mips_machgroup != MACH_GROUP_JAZZ) + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) return -ENODEV; dev = alloc_etherdev(sizeof(struct sonic_local)); @@ -235,20 +225,9 @@ static int __init jazz_sonic_probe(struct platform_device *pdev) netdev_boot_setup_check(dev); - if (dev->base_addr >= KSEG0) { /* Check a single specified location. */ - err = sonic_probe1(dev); - } else if (dev->base_addr != 0) { /* Don't probe at all. */ - err = -ENXIO; - } else { - for (i = 0; sonic_portlist[i].port; i++) { - dev->base_addr = sonic_portlist[i].port; - dev->irq = sonic_portlist[i].irq; - if (sonic_probe1(dev) == 0) - break; - } - if (!sonic_portlist[i].port) - err = -ENODEV; - } + dev->base_addr = res->start; + dev->irq = platform_get_irq(pdev, 0); + err = sonic_probe1(dev); if (err) goto out; err = register_netdev(dev); @@ -303,38 +282,12 @@ static struct platform_driver jazz_sonic_driver = { static int __init jazz_sonic_init_module(void) { - int err; - - if ((err = platform_driver_register(&jazz_sonic_driver))) { - printk(KERN_ERR "Driver registration failed\n"); - return err; - } - - jazz_sonic_device = platform_device_alloc(jazz_sonic_string, 0); - if (!jazz_sonic_device) - goto out_unregister; - - if (platform_device_add(jazz_sonic_device)) { - platform_device_put(jazz_sonic_device); - jazz_sonic_device = NULL; - } - - return 0; - -out_unregister: - platform_driver_unregister(&jazz_sonic_driver); - - return -ENOMEM; + return platform_driver_register(&jazz_sonic_driver); } static void __exit jazz_sonic_cleanup_module(void) { platform_driver_unregister(&jazz_sonic_driver); - - if (jazz_sonic_device) { - platform_device_unregister(jazz_sonic_device); - jazz_sonic_device = NULL; - } } module_init(jazz_sonic_init_module); -- cgit v1.2.3-70-g09d2 From 9caab4587b8320c54fc666a6c820e966e6403aea Mon Sep 17 00:00:00 2001 From: Sivakumar Subramani Date: Thu, 6 Sep 2007 06:21:54 -0400 Subject: S2io: Enable all the error and alarm indications - Added support to unmask entire set of device errors and alarams. Alarm interrupts are generated for a myriad of purposes, ranging from illegal operations or requests to internal state machine errors and uncorrectable data corruption errors. In several cases the adapter can recover gracefully from unexpected events; however, in some cases, a device reset may be necessary. This patch handles alarms generated by all the blocks within the device. The adapter generates the following types of alarms: 1. Link state transitions (local/remote fault) or other link-related problems. 2. Problems with any device peripherals, including the EEPROM, FLASH, etc. 3. Correctable ECC errors (single-bit errors) on internal data structures or frame data. 4. Uncorrectable ECC errors (multi-bit errors) on internal data structures or frame data. 5. State machine errors, which indicate that internal control structures have become corrupted. 6. PCI related errors, including parity errors or illegal transactions. 7. Other unexpected events. - Implemented Jeff's review comments to use do_s2io_write_bits function to avoid duplicate codes. Signed-off-by: Sivakumar Subramani Signed-off-by: Santosh Rastapur Signed-off-by: Ramkrishna Vepa Signed-off-by: Jeff Garzik --- drivers/net/s2io-regs.h | 116 +++++++++++++++++++++-- drivers/net/s2io.c | 246 +++++++++++++++++++++++++++++++++--------------- drivers/net/s2io.h | 1 + 3 files changed, 278 insertions(+), 85 deletions(-) (limited to 'drivers') diff --git a/drivers/net/s2io-regs.h b/drivers/net/s2io-regs.h index 83e3e47a9e3..aef66e2d98d 100644 --- a/drivers/net/s2io-regs.h +++ b/drivers/net/s2io-regs.h @@ -325,33 +325,66 @@ struct XENA_dev_config { #define TXDMA_TPA_INT BIT(5) #define TXDMA_SM_INT BIT(6) u64 pfc_err_reg; +#define PFC_ECC_SG_ERR BIT(7) +#define PFC_ECC_DB_ERR BIT(15) +#define PFC_SM_ERR_ALARM BIT(23) +#define PFC_MISC_0_ERR BIT(31) +#define PFC_MISC_1_ERR BIT(32) +#define PFC_PCIX_ERR BIT(39) u64 pfc_err_mask; u64 pfc_err_alarm; u64 tda_err_reg; +#define TDA_Fn_ECC_SG_ERR vBIT(0xff,0,8) +#define TDA_Fn_ECC_DB_ERR vBIT(0xff,8,8) +#define TDA_SM0_ERR_ALARM BIT(22) +#define TDA_SM1_ERR_ALARM BIT(23) +#define TDA_PCIX_ERR BIT(39) u64 tda_err_mask; u64 tda_err_alarm; u64 pcc_err_reg; -#define PCC_FB_ECC_DB_ERR vBIT(0xFF, 16, 8) +#define PCC_FB_ECC_SG_ERR vBIT(0xFF,0,8) +#define PCC_TXB_ECC_SG_ERR vBIT(0xFF,8,8) +#define PCC_FB_ECC_DB_ERR vBIT(0xFF,16, 8) +#define PCC_TXB_ECC_DB_ERR vBIT(0xff,24,8) +#define PCC_SM_ERR_ALARM vBIT(0xff,32,8) +#define PCC_WR_ERR_ALARM vBIT(0xff,40,8) +#define PCC_N_SERR vBIT(0xff,48,8) +#define PCC_6_COF_OV_ERR BIT(56) +#define PCC_7_COF_OV_ERR BIT(57) +#define PCC_6_LSO_OV_ERR BIT(58) +#define PCC_7_LSO_OV_ERR BIT(59) #define PCC_ENABLE_FOUR vBIT(0x0F,0,8) - u64 pcc_err_mask; u64 pcc_err_alarm; u64 tti_err_reg; +#define TTI_ECC_SG_ERR BIT(7) +#define TTI_ECC_DB_ERR BIT(15) +#define TTI_SM_ERR_ALARM BIT(23) u64 tti_err_mask; u64 tti_err_alarm; u64 lso_err_reg; +#define LSO6_SEND_OFLOW BIT(12) +#define LSO7_SEND_OFLOW BIT(13) +#define LSO6_ABORT BIT(14) +#define LSO7_ABORT BIT(15) +#define LSO6_SM_ERR_ALARM BIT(22) +#define LSO7_SM_ERR_ALARM BIT(23) u64 lso_err_mask; u64 lso_err_alarm; u64 tpa_err_reg; +#define TPA_TX_FRM_DROP BIT(7) +#define TPA_SM_ERR_ALARM BIT(23) + u64 tpa_err_mask; u64 tpa_err_alarm; u64 sm_err_reg; +#define SM_SM_ERR_ALARM BIT(15) u64 sm_err_mask; u64 sm_err_alarm; @@ -450,22 +483,52 @@ struct XENA_dev_config { #define RXDMA_INT_RTI_INT_M BIT(3) u64 rda_err_reg; +#define RDA_RXDn_ECC_SG_ERR vBIT(0xFF,0,8) +#define RDA_RXDn_ECC_DB_ERR vBIT(0xFF,8,8) +#define RDA_FRM_ECC_SG_ERR BIT(23) +#define RDA_FRM_ECC_DB_N_AERR BIT(31) +#define RDA_SM1_ERR_ALARM BIT(38) +#define RDA_SM0_ERR_ALARM BIT(39) +#define RDA_MISC_ERR BIT(47) +#define RDA_PCIX_ERR BIT(55) +#define RDA_RXD_ECC_DB_SERR BIT(63) u64 rda_err_mask; u64 rda_err_alarm; u64 rc_err_reg; +#define RC_PRCn_ECC_SG_ERR vBIT(0xFF,0,8) +#define RC_PRCn_ECC_DB_ERR vBIT(0xFF,8,8) +#define RC_FTC_ECC_SG_ERR BIT(23) +#define RC_FTC_ECC_DB_ERR BIT(31) +#define RC_PRCn_SM_ERR_ALARM vBIT(0xFF,32,8) +#define RC_FTC_SM_ERR_ALARM BIT(47) +#define RC_RDA_FAIL_WR_Rn vBIT(0xFF,48,8) u64 rc_err_mask; u64 rc_err_alarm; u64 prc_pcix_err_reg; +#define PRC_PCI_AB_RD_Rn vBIT(0xFF,0,8) +#define PRC_PCI_DP_RD_Rn vBIT(0xFF,8,8) +#define PRC_PCI_AB_WR_Rn vBIT(0xFF,16,8) +#define PRC_PCI_DP_WR_Rn vBIT(0xFF,24,8) +#define PRC_PCI_AB_F_WR_Rn vBIT(0xFF,32,8) +#define PRC_PCI_DP_F_WR_Rn vBIT(0xFF,40,8) u64 prc_pcix_err_mask; u64 prc_pcix_err_alarm; u64 rpa_err_reg; +#define RPA_ECC_SG_ERR BIT(7) +#define RPA_ECC_DB_ERR BIT(15) +#define RPA_FLUSH_REQUEST BIT(22) +#define RPA_SM_ERR_ALARM BIT(23) +#define RPA_CREDIT_ERR BIT(31) u64 rpa_err_mask; u64 rpa_err_alarm; u64 rti_err_reg; +#define RTI_ECC_SG_ERR BIT(7) +#define RTI_ECC_DB_ERR BIT(15) +#define RTI_SM_ERR_ALARM BIT(23) u64 rti_err_mask; u64 rti_err_alarm; @@ -582,17 +645,43 @@ struct XENA_dev_config { #define MAC_INT_STATUS_RMAC_INT BIT(1) u64 mac_tmac_err_reg; -#define TMAC_ERR_REG_TMAC_ECC_DB_ERR BIT(15) -#define TMAC_ERR_REG_TMAC_TX_BUF_OVRN BIT(23) -#define TMAC_ERR_REG_TMAC_TX_CRI_ERR BIT(31) +#define TMAC_ECC_SG_ERR BIT(7) +#define TMAC_ECC_DB_ERR BIT(15) +#define TMAC_TX_BUF_OVRN BIT(23) +#define TMAC_TX_CRI_ERR BIT(31) +#define TMAC_TX_SM_ERR BIT(39) +#define TMAC_DESC_ECC_SG_ERR BIT(47) +#define TMAC_DESC_ECC_DB_ERR BIT(55) + u64 mac_tmac_err_mask; u64 mac_tmac_err_alarm; u64 mac_rmac_err_reg; -#define RMAC_ERR_REG_RX_BUFF_OVRN BIT(0) -#define RMAC_ERR_REG_RTS_ECC_DB_ERR BIT(14) -#define RMAC_ERR_REG_ECC_DB_ERR BIT(15) -#define RMAC_LINK_STATE_CHANGE_INT BIT(31) +#define RMAC_RX_BUFF_OVRN BIT(0) +#define RMAC_FRM_RCVD_INT BIT(1) +#define RMAC_UNUSED_INT BIT(2) +#define RMAC_RTS_PNUM_ECC_SG_ERR BIT(5) +#define RMAC_RTS_DS_ECC_SG_ERR BIT(6) +#define RMAC_RD_BUF_ECC_SG_ERR BIT(7) +#define RMAC_RTH_MAP_ECC_SG_ERR BIT(8) +#define RMAC_RTH_SPDM_ECC_SG_ERR BIT(9) +#define RMAC_RTS_VID_ECC_SG_ERR BIT(10) +#define RMAC_DA_SHADOW_ECC_SG_ERR BIT(11) +#define RMAC_RTS_PNUM_ECC_DB_ERR BIT(13) +#define RMAC_RTS_DS_ECC_DB_ERR BIT(14) +#define RMAC_RD_BUF_ECC_DB_ERR BIT(15) +#define RMAC_RTH_MAP_ECC_DB_ERR BIT(16) +#define RMAC_RTH_SPDM_ECC_DB_ERR BIT(17) +#define RMAC_RTS_VID_ECC_DB_ERR BIT(18) +#define RMAC_DA_SHADOW_ECC_DB_ERR BIT(19) +#define RMAC_LINK_STATE_CHANGE_INT BIT(31) +#define RMAC_RX_SM_ERR BIT(39) +#define RMAC_SINGLE_ECC_ERR (BIT(5) | BIT(6) | BIT(7) |\ + BIT(8) | BIT(9) | BIT(10)|\ + BIT(11)) +#define RMAC_DOUBLE_ECC_ERR (BIT(13) | BIT(14) | BIT(15) |\ + BIT(16) | BIT(17) | BIT(18)|\ + BIT(19)) u64 mac_rmac_err_mask; u64 mac_rmac_err_alarm; @@ -750,6 +839,7 @@ struct XENA_dev_config { BIT(17) | BIT(19)) #define MC_ERR_REG_ECC_ALL_DBL (BIT(10) | BIT(11) | BIT(12) |\ BIT(13) | BIT(18) | BIT(20)) +#define PLL_LOCK_N BIT(39) u64 mc_err_mask; u64 mc_err_alarm; @@ -823,11 +913,17 @@ struct XENA_dev_config { #define XGXS_INT_MASK_RXGXS BIT(1) u64 xgxs_txgxs_err_reg; -#define TXGXS_ECC_DB_ERR BIT(15) +#define TXGXS_ECC_SG_ERR BIT(7) +#define TXGXS_ECC_DB_ERR BIT(15) +#define TXGXS_ESTORE_UFLOW BIT(31) +#define TXGXS_TX_SM_ERR BIT(39) + u64 xgxs_txgxs_err_mask; u64 xgxs_txgxs_err_alarm; u64 xgxs_rxgxs_err_reg; +#define RXGXS_ESTORE_OFLOW BIT(7) +#define RXGXS_RX_SM_ERR BIT(39) u64 xgxs_rxgxs_err_mask; u64 xgxs_rxgxs_err_alarm; diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index e7431c58da4..63473027b46 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -892,8 +892,9 @@ static void free_shared_mem(struct s2io_nic *nic) k++; } kfree(mac_control->rings[i].ba[j]); - nic->mac_control.stats_info->sw_stat.mem_freed += (sizeof(struct buffAdd) * - (rxd_count[nic->rxd_mode] + 1)); + nic->mac_control.stats_info->sw_stat.mem_freed += + (sizeof(struct buffAdd) * + (rxd_count[nic->rxd_mode] + 1)); } kfree(mac_control->rings[i].ba); nic->mac_control.stats_info->sw_stat.mem_freed += @@ -1731,7 +1732,150 @@ static int s2io_link_fault_indication(struct s2io_nic *nic) else return MAC_RMAC_ERR_TIMER; } +/** + * do_s2io_write_bits - update alarm bits in alarm register + * @value: alarm bits + * @flag: interrupt status + * @addr: address value + * Description: update alarm bits in alarm register + * Return Value: + * NONE. + */ +static void do_s2io_write_bits(u64 value, int flag, void __iomem *addr) +{ + u64 temp64; + + temp64 = readq(addr); + + if(flag == ENABLE_INTRS) + temp64 &= ~((u64) value); + else + temp64 |= ((u64) value); + writeq(temp64, addr); +} +void en_dis_err_alarms(struct s2io_nic *nic, u16 mask, int flag) +{ + struct XENA_dev_config __iomem *bar0 = nic->bar0; + register u64 gen_int_mask = 0; + + if (mask & TX_DMA_INTR) { + + gen_int_mask |= TXDMA_INT_M; + + do_s2io_write_bits(TXDMA_TDA_INT | TXDMA_PFC_INT | + TXDMA_PCC_INT | TXDMA_TTI_INT | + TXDMA_LSO_INT | TXDMA_TPA_INT | + TXDMA_SM_INT, flag, &bar0->txdma_int_mask); + + do_s2io_write_bits(PFC_ECC_DB_ERR | PFC_SM_ERR_ALARM | + PFC_MISC_0_ERR | PFC_MISC_1_ERR | + PFC_PCIX_ERR | PFC_ECC_SG_ERR, flag, + &bar0->pfc_err_mask); + + do_s2io_write_bits(TDA_Fn_ECC_DB_ERR | TDA_SM0_ERR_ALARM | + TDA_SM1_ERR_ALARM | TDA_Fn_ECC_SG_ERR | + TDA_PCIX_ERR, flag, &bar0->tda_err_mask); + + do_s2io_write_bits(PCC_FB_ECC_DB_ERR | PCC_TXB_ECC_DB_ERR | + PCC_SM_ERR_ALARM | PCC_WR_ERR_ALARM | + PCC_N_SERR | PCC_6_COF_OV_ERR | + PCC_7_COF_OV_ERR | PCC_6_LSO_OV_ERR | + PCC_7_LSO_OV_ERR | PCC_FB_ECC_SG_ERR | + PCC_TXB_ECC_SG_ERR, flag, &bar0->pcc_err_mask); + + do_s2io_write_bits(TTI_SM_ERR_ALARM | TTI_ECC_SG_ERR | + TTI_ECC_DB_ERR, flag, &bar0->tti_err_mask); + + do_s2io_write_bits(LSO6_ABORT | LSO7_ABORT | + LSO6_SM_ERR_ALARM | LSO7_SM_ERR_ALARM | + LSO6_SEND_OFLOW | LSO7_SEND_OFLOW, + flag, &bar0->lso_err_mask); + + do_s2io_write_bits(TPA_SM_ERR_ALARM | TPA_TX_FRM_DROP, + flag, &bar0->tpa_err_mask); + + do_s2io_write_bits(SM_SM_ERR_ALARM, flag, &bar0->sm_err_mask); + + } + + if (mask & TX_MAC_INTR) { + gen_int_mask |= TXMAC_INT_M; + do_s2io_write_bits(MAC_INT_STATUS_TMAC_INT, flag, + &bar0->mac_int_mask); + do_s2io_write_bits(TMAC_TX_BUF_OVRN | TMAC_TX_SM_ERR | + TMAC_ECC_SG_ERR | TMAC_ECC_DB_ERR | + TMAC_DESC_ECC_SG_ERR | TMAC_DESC_ECC_DB_ERR, + flag, &bar0->mac_tmac_err_mask); + } + + if (mask & TX_XGXS_INTR) { + gen_int_mask |= TXXGXS_INT_M; + do_s2io_write_bits(XGXS_INT_STATUS_TXGXS, flag, + &bar0->xgxs_int_mask); + do_s2io_write_bits(TXGXS_ESTORE_UFLOW | TXGXS_TX_SM_ERR | + TXGXS_ECC_SG_ERR | TXGXS_ECC_DB_ERR, + flag, &bar0->xgxs_txgxs_err_mask); + } + + if (mask & RX_DMA_INTR) { + gen_int_mask |= RXDMA_INT_M; + do_s2io_write_bits(RXDMA_INT_RC_INT_M | RXDMA_INT_RPA_INT_M | + RXDMA_INT_RDA_INT_M | RXDMA_INT_RTI_INT_M, + flag, &bar0->rxdma_int_mask); + do_s2io_write_bits(RC_PRCn_ECC_DB_ERR | RC_FTC_ECC_DB_ERR | + RC_PRCn_SM_ERR_ALARM | RC_FTC_SM_ERR_ALARM | + RC_PRCn_ECC_SG_ERR | RC_FTC_ECC_SG_ERR | + RC_RDA_FAIL_WR_Rn, flag, &bar0->rc_err_mask); + do_s2io_write_bits(PRC_PCI_AB_RD_Rn | PRC_PCI_AB_WR_Rn | + PRC_PCI_AB_F_WR_Rn | PRC_PCI_DP_RD_Rn | + PRC_PCI_DP_WR_Rn | PRC_PCI_DP_F_WR_Rn, flag, + &bar0->prc_pcix_err_mask); + do_s2io_write_bits(RPA_SM_ERR_ALARM | RPA_CREDIT_ERR | + RPA_ECC_SG_ERR | RPA_ECC_DB_ERR, flag, + &bar0->rpa_err_mask); + do_s2io_write_bits(RDA_RXDn_ECC_DB_ERR | RDA_FRM_ECC_DB_N_AERR | + RDA_SM1_ERR_ALARM | RDA_SM0_ERR_ALARM | + RDA_RXD_ECC_DB_SERR | RDA_RXDn_ECC_SG_ERR | + RDA_FRM_ECC_SG_ERR | RDA_MISC_ERR|RDA_PCIX_ERR, + flag, &bar0->rda_err_mask); + do_s2io_write_bits(RTI_SM_ERR_ALARM | + RTI_ECC_SG_ERR | RTI_ECC_DB_ERR, + flag, &bar0->rti_err_mask); + } + + if (mask & RX_MAC_INTR) { + gen_int_mask |= RXMAC_INT_M; + do_s2io_write_bits(MAC_INT_STATUS_RMAC_INT, flag, + &bar0->mac_int_mask); + do_s2io_write_bits(RMAC_RX_BUFF_OVRN | RMAC_RX_SM_ERR | + RMAC_UNUSED_INT | RMAC_SINGLE_ECC_ERR | + RMAC_DOUBLE_ECC_ERR | + RMAC_LINK_STATE_CHANGE_INT, + flag, &bar0->mac_rmac_err_mask); + } + + if (mask & RX_XGXS_INTR) + { + gen_int_mask |= RXXGXS_INT_M; + do_s2io_write_bits(XGXS_INT_STATUS_RXGXS, flag, + &bar0->xgxs_int_mask); + do_s2io_write_bits(RXGXS_ESTORE_OFLOW | RXGXS_RX_SM_ERR, flag, + &bar0->xgxs_rxgxs_err_mask); + } + + if (mask & MC_INTR) { + gen_int_mask |= MC_INT_M; + do_s2io_write_bits(MC_INT_MASK_MC_INT, flag, &bar0->mc_int_mask); + do_s2io_write_bits(MC_ERR_REG_SM_ERR | MC_ERR_REG_ECC_ALL_SNG | + MC_ERR_REG_ECC_ALL_DBL | PLL_LOCK_N, flag, + &bar0->mc_err_mask); + } + nic->general_int_mask = gen_int_mask; + + /* Remove this line when alarm interrupts are enabled */ + nic->general_int_mask = 0; +} /** * en_dis_able_nic_intrs - Enable or Disable the interrupts * @nic: device private variable, @@ -1746,17 +1890,16 @@ static int s2io_link_fault_indication(struct s2io_nic *nic) static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag) { struct XENA_dev_config __iomem *bar0 = nic->bar0; - register u64 val64 = 0, temp64 = 0; + register u64 temp64 = 0, intr_mask = 0; + + intr_mask = nic->general_int_mask; /* Top level interrupt classification */ /* PIC Interrupts */ - if ((mask & (TX_PIC_INTR | RX_PIC_INTR))) { + if (mask & TX_PIC_INTR) { /* Enable PIC Intrs in the general intr mask register */ - val64 = TXPIC_INT_M; + intr_mask |= TXPIC_INT_M; if (flag == ENABLE_INTRS) { - temp64 = readq(&bar0->general_int_mask); - temp64 &= ~((u64) val64); - writeq(temp64, &bar0->general_int_mask); /* * If Hercules adapter enable GPIO otherwise * disable all PCIX, Flash, MDIO, IIC and GPIO @@ -1765,64 +1908,25 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag) */ if (s2io_link_fault_indication(nic) == LINK_UP_DOWN_INTERRUPT ) { - temp64 = readq(&bar0->pic_int_mask); - temp64 &= ~((u64) PIC_INT_GPIO); - writeq(temp64, &bar0->pic_int_mask); - temp64 = readq(&bar0->gpio_int_mask); - temp64 &= ~((u64) GPIO_INT_MASK_LINK_UP); - writeq(temp64, &bar0->gpio_int_mask); - } else { + do_s2io_write_bits(PIC_INT_GPIO, flag, + &bar0->pic_int_mask); + do_s2io_write_bits(GPIO_INT_MASK_LINK_UP, flag, + &bar0->gpio_int_mask); + } else writeq(DISABLE_ALL_INTRS, &bar0->pic_int_mask); - } - /* - * No MSI Support is available presently, so TTI and - * RTI interrupts are also disabled. - */ } else if (flag == DISABLE_INTRS) { /* * Disable PIC Intrs in the general * intr mask register */ writeq(DISABLE_ALL_INTRS, &bar0->pic_int_mask); - temp64 = readq(&bar0->general_int_mask); - val64 |= temp64; - writeq(val64, &bar0->general_int_mask); - } - } - - /* MAC Interrupts */ - /* Enabling/Disabling MAC interrupts */ - if (mask & (TX_MAC_INTR | RX_MAC_INTR)) { - val64 = TXMAC_INT_M | RXMAC_INT_M; - if (flag == ENABLE_INTRS) { - temp64 = readq(&bar0->general_int_mask); - temp64 &= ~((u64) val64); - writeq(temp64, &bar0->general_int_mask); - /* - * All MAC block error interrupts are disabled for now - * TODO - */ - } else if (flag == DISABLE_INTRS) { - /* - * Disable MAC Intrs in the general intr mask register - */ - writeq(DISABLE_ALL_INTRS, &bar0->mac_int_mask); - writeq(DISABLE_ALL_INTRS, - &bar0->mac_rmac_err_mask); - - temp64 = readq(&bar0->general_int_mask); - val64 |= temp64; - writeq(val64, &bar0->general_int_mask); } } /* Tx traffic interrupts */ if (mask & TX_TRAFFIC_INTR) { - val64 = TXTRAFFIC_INT_M; + intr_mask |= TXTRAFFIC_INT_M; if (flag == ENABLE_INTRS) { - temp64 = readq(&bar0->general_int_mask); - temp64 &= ~((u64) val64); - writeq(temp64, &bar0->general_int_mask); /* * Enable all the Tx side interrupts * writing 0 Enables all 64 TX interrupt levels @@ -1834,19 +1938,13 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag) * register. */ writeq(DISABLE_ALL_INTRS, &bar0->tx_traffic_mask); - temp64 = readq(&bar0->general_int_mask); - val64 |= temp64; - writeq(val64, &bar0->general_int_mask); } } /* Rx traffic interrupts */ if (mask & RX_TRAFFIC_INTR) { - val64 = RXTRAFFIC_INT_M; + intr_mask |= RXTRAFFIC_INT_M; if (flag == ENABLE_INTRS) { - temp64 = readq(&bar0->general_int_mask); - temp64 &= ~((u64) val64); - writeq(temp64, &bar0->general_int_mask); /* writing 0 Enables all 8 RX interrupt levels */ writeq(0x0, &bar0->rx_traffic_mask); } else if (flag == DISABLE_INTRS) { @@ -1855,11 +1953,17 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag) * register. */ writeq(DISABLE_ALL_INTRS, &bar0->rx_traffic_mask); - temp64 = readq(&bar0->general_int_mask); - val64 |= temp64; - writeq(val64, &bar0->general_int_mask); } } + + temp64 = readq(&bar0->general_int_mask); + if (flag == ENABLE_INTRS) + temp64 &= ~((u64) intr_mask); + else + temp64 = DISABLE_ALL_INTRS; + writeq(temp64, &bar0->general_int_mask); + + nic->general_int_mask = readq(&bar0->general_int_mask); } /** @@ -2062,14 +2166,6 @@ static int start_nic(struct s2io_nic *nic) val64 &= ~ADAPTER_ECC_EN; writeq(val64, &bar0->adapter_control); - /* - * Clearing any possible Link state change interrupts that - * could have popped up just before Enabling the card. - */ - val64 = readq(&bar0->mac_rmac_err_reg); - if (val64) - writeq(val64, &bar0->mac_rmac_err_reg); - /* * Verify if the device is ready to be enabled, if so enable * it. @@ -2223,9 +2319,9 @@ static void stop_nic(struct s2io_nic *nic) config = &nic->config; /* Disable all interrupts */ + en_dis_err_alarms(nic, ENA_ALL_INTRS, DISABLE_INTRS); interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR; - interruptible |= TX_PIC_INTR | RX_PIC_INTR; - interruptible |= TX_MAC_INTR | RX_MAC_INTR; + interruptible |= TX_PIC_INTR; en_dis_able_nic_intrs(nic, interruptible, DISABLE_INTRS); /* Clearing Adapter_En bit of ADAPTER_CONTROL Register */ @@ -6666,12 +6762,12 @@ static int s2io_card_up(struct s2io_nic * sp) tasklet_init(&sp->task, s2io_tasklet, (unsigned long) dev); /* Enable select interrupts */ + en_dis_err_alarms(sp, ENA_ALL_INTRS, ENABLE_INTRS); if (sp->intr_type != INTA) en_dis_able_nic_intrs(sp, ENA_ALL_INTRS, DISABLE_INTRS); else { interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR; - interruptible |= TX_PIC_INTR | RX_PIC_INTR; - interruptible |= TX_MAC_INTR | RX_MAC_INTR; + interruptible |= TX_PIC_INTR; en_dis_able_nic_intrs(sp, interruptible, ENABLE_INTRS); } diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 724948d217b..b9654dfeb87 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -893,6 +893,7 @@ struct s2io_nic { spinlock_t rx_lock; atomic_t isr_cnt; + u64 general_int_mask; u64 *ufo_in_band_v; #define VPD_STRING_LEN 80 u8 product_name[VPD_STRING_LEN]; -- cgit v1.2.3-70-g09d2 From 8116f3cf4a2a5a4fa2335e6f32023ac50506698f Mon Sep 17 00:00:00 2001 From: Sivakumar Subramani Date: Mon, 17 Sep 2007 13:05:35 -0700 Subject: [S2IO]: Handle and monitor all of the device errors and alarms - Added support to poll entire set of device errors and alarams. - A note on how device errors and alarms are handled: - The adapter will automatically recover from uncorrectable ECC errors. Packets containing corrupted data will be dropped (not transmitted) or tagged as invalid before being passed to the host. - The adapter cannot recover from any internal state machine errors. A state machine error requires a device reset. - Any internal error that could potentially result in .store trampling. (undesirable PCI behaviour)is tagged as a "serious error". In such cases the adapter will give up its ability to be a bus master. In this situation the host will still be able to read internal device registers in order to generate an error report. A device reset is necessary to return to normal operation. - In the event of a pcix data parity error, the adapter will automatically disable itself. Adapter_En will automatically transition from '1' to '0' and the adapter will enter its clean-up routine. Once the device has achieved quiescence, an adapter reset should be performed. - Replaced alarm_intr_handler() with s2io_handle_errors(). - Added statistic counters to monitor the alarms. [ Fix warnings wrt. do_s2io_chk_alarm_bit(), Callers pass in an "unsigned long long *" but the function takes a "u64 *" which is different on many 64-bit platforms. -DaveM ] Signed-off-by: Sivakumar Subramani Signed-off-by: Santosh Rastapur Signed-off-by: Ramkrishna Vepa Signed-off-by: Jeff Garzik --- drivers/net/s2io.c | 469 ++++++++++++++++++++++++++++++++++++++--------------- drivers/net/s2io.h | 24 ++- 2 files changed, 357 insertions(+), 136 deletions(-) (limited to 'drivers') diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 63473027b46..182643ff81e 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -263,7 +263,14 @@ static char ethtool_driver_stats_keys[][ETH_GSTRING_LEN] = { {"serious_err_cnt"}, {"soft_reset_cnt"}, {"fifo_full_cnt"}, - {"ring_full_cnt"}, + {"ring_0_full_cnt"}, + {"ring_1_full_cnt"}, + {"ring_2_full_cnt"}, + {"ring_3_full_cnt"}, + {"ring_4_full_cnt"}, + {"ring_5_full_cnt"}, + {"ring_6_full_cnt"}, + {"ring_7_full_cnt"}, ("alarm_transceiver_temp_high"), ("alarm_transceiver_temp_low"), ("alarm_laser_bias_current_high"), @@ -303,7 +310,24 @@ static char ethtool_driver_stats_keys[][ETH_GSTRING_LEN] = { ("rx_tcode_fcs_err_cnt"), ("rx_tcode_buf_size_err_cnt"), ("rx_tcode_rxd_corrupt_cnt"), - ("rx_tcode_unkn_err_cnt") + ("rx_tcode_unkn_err_cnt"), + {"tda_err_cnt"}, + {"pfc_err_cnt"}, + {"pcc_err_cnt"}, + {"tti_err_cnt"}, + {"tpa_err_cnt"}, + {"sm_err_cnt"}, + {"lso_err_cnt"}, + {"mac_tmac_err_cnt"}, + {"mac_rmac_err_cnt"}, + {"xgxs_txgxs_err_cnt"}, + {"xgxs_rxgxs_err_cnt"}, + {"rc_err_cnt"}, + {"prc_pcix_err_cnt"}, + {"rpa_err_cnt"}, + {"rda_err_cnt"}, + {"rti_err_cnt"}, + {"mc_err_cnt"} }; #define S2IO_XENA_STAT_LEN sizeof(ethtool_xena_stats_keys)/ ETH_GSTRING_LEN @@ -1732,6 +1756,7 @@ static int s2io_link_fault_indication(struct s2io_nic *nic) else return MAC_RMAC_ERR_TIMER; } + /** * do_s2io_write_bits - update alarm bits in alarm register * @value: alarm bits @@ -3251,135 +3276,6 @@ static void s2io_updt_xpak_counter(struct net_device *dev) stat_info->xpak_stat.warn_laser_output_power_low++; } -/** - * alarm_intr_handler - Alarm Interrrupt handler - * @nic: device private variable - * Description: If the interrupt was neither because of Rx packet or Tx - * complete, this function is called. If the interrupt was to indicate - * a loss of link, the OSM link status handler is invoked for any other - * alarm interrupt the block that raised the interrupt is displayed - * and a H/W reset is issued. - * Return Value: - * NONE -*/ - -static void alarm_intr_handler(struct s2io_nic *nic) -{ - struct net_device *dev = (struct net_device *) nic->dev; - struct XENA_dev_config __iomem *bar0 = nic->bar0; - register u64 val64 = 0, err_reg = 0; - u64 cnt; - int i; - if (atomic_read(&nic->card_state) == CARD_DOWN) - return; - if (pci_channel_offline(nic->pdev)) - return; - nic->mac_control.stats_info->sw_stat.ring_full_cnt = 0; - /* Handling the XPAK counters update */ - if(nic->mac_control.stats_info->xpak_stat.xpak_timer_count < 72000) { - /* waiting for an hour */ - nic->mac_control.stats_info->xpak_stat.xpak_timer_count++; - } else { - s2io_updt_xpak_counter(dev); - /* reset the count to zero */ - nic->mac_control.stats_info->xpak_stat.xpak_timer_count = 0; - } - - /* Handling link status change error Intr */ - if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER) { - err_reg = readq(&bar0->mac_rmac_err_reg); - writeq(err_reg, &bar0->mac_rmac_err_reg); - if (err_reg & RMAC_LINK_STATE_CHANGE_INT) { - schedule_work(&nic->set_link_task); - } - } - - /* Handling Ecc errors */ - val64 = readq(&bar0->mc_err_reg); - writeq(val64, &bar0->mc_err_reg); - if (val64 & (MC_ERR_REG_ECC_ALL_SNG | MC_ERR_REG_ECC_ALL_DBL)) { - if (val64 & MC_ERR_REG_ECC_ALL_DBL) { - nic->mac_control.stats_info->sw_stat. - double_ecc_errs++; - DBG_PRINT(INIT_DBG, "%s: Device indicates ", - dev->name); - DBG_PRINT(INIT_DBG, "double ECC error!!\n"); - if (nic->device_type != XFRAME_II_DEVICE) { - /* Reset XframeI only if critical error */ - if (val64 & (MC_ERR_REG_MIRI_ECC_DB_ERR_0 | - MC_ERR_REG_MIRI_ECC_DB_ERR_1)) { - netif_stop_queue(dev); - schedule_work(&nic->rst_timer_task); - nic->mac_control.stats_info->sw_stat. - soft_reset_cnt++; - } - } - } else { - nic->mac_control.stats_info->sw_stat. - single_ecc_errs++; - } - } - - /* In case of a serious error, the device will be Reset. */ - val64 = readq(&bar0->serr_source); - if (val64 & SERR_SOURCE_ANY) { - nic->mac_control.stats_info->sw_stat.serious_err_cnt++; - DBG_PRINT(ERR_DBG, "%s: Device indicates ", dev->name); - DBG_PRINT(ERR_DBG, "serious error %llx!!\n", - (unsigned long long)val64); - netif_stop_queue(dev); - schedule_work(&nic->rst_timer_task); - nic->mac_control.stats_info->sw_stat.soft_reset_cnt++; - } - - /* - * Also as mentioned in the latest Errata sheets if the PCC_FB_ECC - * Error occurs, the adapter will be recycled by disabling the - * adapter enable bit and enabling it again after the device - * becomes Quiescent. - */ - val64 = readq(&bar0->pcc_err_reg); - writeq(val64, &bar0->pcc_err_reg); - if (val64 & PCC_FB_ECC_DB_ERR) { - u64 ac = readq(&bar0->adapter_control); - ac &= ~(ADAPTER_CNTL_EN); - writeq(ac, &bar0->adapter_control); - ac = readq(&bar0->adapter_control); - schedule_work(&nic->set_link_task); - } - /* Check for data parity error */ - val64 = readq(&bar0->pic_int_status); - if (val64 & PIC_INT_GPIO) { - val64 = readq(&bar0->gpio_int_reg); - if (val64 & GPIO_INT_REG_DP_ERR_INT) { - nic->mac_control.stats_info->sw_stat.parity_err_cnt++; - schedule_work(&nic->rst_timer_task); - nic->mac_control.stats_info->sw_stat.soft_reset_cnt++; - } - } - - /* Check for ring full counter */ - if (nic->device_type & XFRAME_II_DEVICE) { - val64 = readq(&bar0->ring_bump_counter1); - for (i=0; i<4; i++) { - cnt = ( val64 & vBIT(0xFFFF,(i*16),16)); - cnt >>= 64 - ((i+1)*16); - nic->mac_control.stats_info->sw_stat.ring_full_cnt - += cnt; - } - - val64 = readq(&bar0->ring_bump_counter2); - for (i=0; i<4; i++) { - cnt = ( val64 & vBIT(0xFFFF,(i*16),16)); - cnt >>= 64 - ((i+1)*16); - nic->mac_control.stats_info->sw_stat.ring_full_cnt - += cnt; - } - } - - /* Other type of interrupts are not being handled now, TODO */ -} - /** * wait_for_cmd_complete - waits for a command to complete. * @sp : private member of the device structure, which is a pointer to the @@ -4246,8 +4142,9 @@ static void s2io_alarm_handle(unsigned long data) { struct s2io_nic *sp = (struct s2io_nic *)data; + struct net_device *dev = sp->dev; - alarm_intr_handler(sp); + s2io_handle_errors(dev); mod_timer(&sp->alarm_timer, jiffies + HZ / 2); } @@ -4365,6 +4262,292 @@ static void s2io_txpic_intr_handle(struct s2io_nic *sp) val64 = readq(&bar0->gpio_int_mask); } +/** + * do_s2io_chk_alarm_bit - Check for alarm and incrment the counter + * @value: alarm bits + * @addr: address value + * @cnt: counter variable + * Description: Check for alarm and increment the counter + * Return Value: + * 1 - if alarm bit set + * 0 - if alarm bit is not set + */ +int do_s2io_chk_alarm_bit(u64 value, void __iomem * addr, + unsigned long long *cnt) +{ + u64 val64; + val64 = readq(addr); + if ( val64 & value ) { + writeq(val64, addr); + (*cnt)++; + return 1; + } + return 0; + +} + +/** + * s2io_handle_errors - Xframe error indication handler + * @nic: device private variable + * Description: Handle alarms such as loss of link, single or + * double ECC errors, critical and serious errors. + * Return Value: + * NONE + */ +static void s2io_handle_errors(void * dev_id) +{ + struct net_device *dev = (struct net_device *) dev_id; + struct s2io_nic *sp = dev->priv; + struct XENA_dev_config __iomem *bar0 = sp->bar0; + u64 temp64 = 0,val64=0; + int i = 0; + + struct swStat *sw_stat = &sp->mac_control.stats_info->sw_stat; + struct xpakStat *stats = &sp->mac_control.stats_info->xpak_stat; + + if (unlikely(atomic_read(&sp->card_state) == CARD_DOWN)) + return; + + if (pci_channel_offline(sp->pdev)) + return; + + memset(&sw_stat->ring_full_cnt, 0, + sizeof(sw_stat->ring_full_cnt)); + + /* Handling the XPAK counters update */ + if(stats->xpak_timer_count < 72000) { + /* waiting for an hour */ + stats->xpak_timer_count++; + } else { + s2io_updt_xpak_counter(dev); + /* reset the count to zero */ + stats->xpak_timer_count = 0; + } + + /* Handling link status change error Intr */ + if (s2io_link_fault_indication(sp) == MAC_RMAC_ERR_TIMER) { + val64 = readq(&bar0->mac_rmac_err_reg); + writeq(val64, &bar0->mac_rmac_err_reg); + if (val64 & RMAC_LINK_STATE_CHANGE_INT) + schedule_work(&sp->set_link_task); + } + + /* In case of a serious error, the device will be Reset. */ + if (do_s2io_chk_alarm_bit(SERR_SOURCE_ANY, &bar0->serr_source, + &sw_stat->serious_err_cnt)) + goto reset; + + /* Check for data parity error */ + if (do_s2io_chk_alarm_bit(GPIO_INT_REG_DP_ERR_INT, &bar0->gpio_int_reg, + &sw_stat->parity_err_cnt)) + goto reset; + + /* Check for ring full counter */ + if (sp->device_type == XFRAME_II_DEVICE) { + val64 = readq(&bar0->ring_bump_counter1); + for (i=0; i<4; i++) { + temp64 = ( val64 & vBIT(0xFFFF,(i*16),16)); + temp64 >>= 64 - ((i+1)*16); + sw_stat->ring_full_cnt[i] += temp64; + } + + val64 = readq(&bar0->ring_bump_counter2); + for (i=0; i<4; i++) { + temp64 = ( val64 & vBIT(0xFFFF,(i*16),16)); + temp64 >>= 64 - ((i+1)*16); + sw_stat->ring_full_cnt[i+4] += temp64; + } + } + + val64 = readq(&bar0->txdma_int_status); + /*check for pfc_err*/ + if (val64 & TXDMA_PFC_INT) { + if (do_s2io_chk_alarm_bit(PFC_ECC_DB_ERR | PFC_SM_ERR_ALARM| + PFC_MISC_0_ERR | PFC_MISC_1_ERR| + PFC_PCIX_ERR, &bar0->pfc_err_reg, + &sw_stat->pfc_err_cnt)) + goto reset; + do_s2io_chk_alarm_bit(PFC_ECC_SG_ERR, &bar0->pfc_err_reg, + &sw_stat->pfc_err_cnt); + } + + /*check for tda_err*/ + if (val64 & TXDMA_TDA_INT) { + if(do_s2io_chk_alarm_bit(TDA_Fn_ECC_DB_ERR | TDA_SM0_ERR_ALARM | + TDA_SM1_ERR_ALARM, &bar0->tda_err_reg, + &sw_stat->tda_err_cnt)) + goto reset; + do_s2io_chk_alarm_bit(TDA_Fn_ECC_SG_ERR | TDA_PCIX_ERR, + &bar0->tda_err_reg, &sw_stat->tda_err_cnt); + } + /*check for pcc_err*/ + if (val64 & TXDMA_PCC_INT) { + if (do_s2io_chk_alarm_bit(PCC_SM_ERR_ALARM | PCC_WR_ERR_ALARM + | PCC_N_SERR | PCC_6_COF_OV_ERR + | PCC_7_COF_OV_ERR | PCC_6_LSO_OV_ERR + | PCC_7_LSO_OV_ERR | PCC_FB_ECC_DB_ERR + | PCC_TXB_ECC_DB_ERR, &bar0->pcc_err_reg, + &sw_stat->pcc_err_cnt)) + goto reset; + do_s2io_chk_alarm_bit(PCC_FB_ECC_SG_ERR | PCC_TXB_ECC_SG_ERR, + &bar0->pcc_err_reg, &sw_stat->pcc_err_cnt); + } + + /*check for tti_err*/ + if (val64 & TXDMA_TTI_INT) { + if (do_s2io_chk_alarm_bit(TTI_SM_ERR_ALARM, &bar0->tti_err_reg, + &sw_stat->tti_err_cnt)) + goto reset; + do_s2io_chk_alarm_bit(TTI_ECC_SG_ERR | TTI_ECC_DB_ERR, + &bar0->tti_err_reg, &sw_stat->tti_err_cnt); + } + + /*check for lso_err*/ + if (val64 & TXDMA_LSO_INT) { + if (do_s2io_chk_alarm_bit(LSO6_ABORT | LSO7_ABORT + | LSO6_SM_ERR_ALARM | LSO7_SM_ERR_ALARM, + &bar0->lso_err_reg, &sw_stat->lso_err_cnt)) + goto reset; + do_s2io_chk_alarm_bit(LSO6_SEND_OFLOW | LSO7_SEND_OFLOW, + &bar0->lso_err_reg, &sw_stat->lso_err_cnt); + } + + /*check for tpa_err*/ + if (val64 & TXDMA_TPA_INT) { + if (do_s2io_chk_alarm_bit(TPA_SM_ERR_ALARM, &bar0->tpa_err_reg, + &sw_stat->tpa_err_cnt)) + goto reset; + do_s2io_chk_alarm_bit(TPA_TX_FRM_DROP, &bar0->tpa_err_reg, + &sw_stat->tpa_err_cnt); + } + + /*check for sm_err*/ + if (val64 & TXDMA_SM_INT) { + if (do_s2io_chk_alarm_bit(SM_SM_ERR_ALARM, &bar0->sm_err_reg, + &sw_stat->sm_err_cnt)) + goto reset; + } + + val64 = readq(&bar0->mac_int_status); + if (val64 & MAC_INT_STATUS_TMAC_INT) { + if (do_s2io_chk_alarm_bit(TMAC_TX_BUF_OVRN | TMAC_TX_SM_ERR, + &bar0->mac_tmac_err_reg, + &sw_stat->mac_tmac_err_cnt)) + goto reset; + do_s2io_chk_alarm_bit(TMAC_ECC_SG_ERR | TMAC_ECC_DB_ERR + | TMAC_DESC_ECC_SG_ERR | TMAC_DESC_ECC_DB_ERR, + &bar0->mac_tmac_err_reg, + &sw_stat->mac_tmac_err_cnt); + } + + val64 = readq(&bar0->xgxs_int_status); + if (val64 & XGXS_INT_STATUS_TXGXS) { + if (do_s2io_chk_alarm_bit(TXGXS_ESTORE_UFLOW | TXGXS_TX_SM_ERR, + &bar0->xgxs_txgxs_err_reg, + &sw_stat->xgxs_txgxs_err_cnt)) + goto reset; + do_s2io_chk_alarm_bit(TXGXS_ECC_SG_ERR | TXGXS_ECC_DB_ERR, + &bar0->xgxs_txgxs_err_reg, + &sw_stat->xgxs_txgxs_err_cnt); + } + + val64 = readq(&bar0->rxdma_int_status); + if (val64 & RXDMA_INT_RC_INT_M) { + if (do_s2io_chk_alarm_bit(RC_PRCn_ECC_DB_ERR | RC_FTC_ECC_DB_ERR + | RC_PRCn_SM_ERR_ALARM |RC_FTC_SM_ERR_ALARM, + &bar0->rc_err_reg, &sw_stat->rc_err_cnt)) + goto reset; + do_s2io_chk_alarm_bit(RC_PRCn_ECC_SG_ERR | RC_FTC_ECC_SG_ERR + | RC_RDA_FAIL_WR_Rn, &bar0->rc_err_reg, + &sw_stat->rc_err_cnt); + if (do_s2io_chk_alarm_bit(PRC_PCI_AB_RD_Rn | PRC_PCI_AB_WR_Rn + | PRC_PCI_AB_F_WR_Rn, &bar0->prc_pcix_err_reg, + &sw_stat->prc_pcix_err_cnt)) + goto reset; + do_s2io_chk_alarm_bit(PRC_PCI_DP_RD_Rn | PRC_PCI_DP_WR_Rn + | PRC_PCI_DP_F_WR_Rn, &bar0->prc_pcix_err_reg, + &sw_stat->prc_pcix_err_cnt); + } + + if (val64 & RXDMA_INT_RPA_INT_M) { + if (do_s2io_chk_alarm_bit(RPA_SM_ERR_ALARM | RPA_CREDIT_ERR, + &bar0->rpa_err_reg, &sw_stat->rpa_err_cnt)) + goto reset; + do_s2io_chk_alarm_bit(RPA_ECC_SG_ERR | RPA_ECC_DB_ERR, + &bar0->rpa_err_reg, &sw_stat->rpa_err_cnt); + } + + if (val64 & RXDMA_INT_RDA_INT_M) { + if (do_s2io_chk_alarm_bit(RDA_RXDn_ECC_DB_ERR + | RDA_FRM_ECC_DB_N_AERR | RDA_SM1_ERR_ALARM + | RDA_SM0_ERR_ALARM | RDA_RXD_ECC_DB_SERR, + &bar0->rda_err_reg, &sw_stat->rda_err_cnt)) + goto reset; + do_s2io_chk_alarm_bit(RDA_RXDn_ECC_SG_ERR | RDA_FRM_ECC_SG_ERR + | RDA_MISC_ERR | RDA_PCIX_ERR, + &bar0->rda_err_reg, &sw_stat->rda_err_cnt); + } + + if (val64 & RXDMA_INT_RTI_INT_M) { + if (do_s2io_chk_alarm_bit(RTI_SM_ERR_ALARM, &bar0->rti_err_reg, + &sw_stat->rti_err_cnt)) + goto reset; + do_s2io_chk_alarm_bit(RTI_ECC_SG_ERR | RTI_ECC_DB_ERR, + &bar0->rti_err_reg, &sw_stat->rti_err_cnt); + } + + val64 = readq(&bar0->mac_int_status); + if (val64 & MAC_INT_STATUS_RMAC_INT) { + if (do_s2io_chk_alarm_bit(RMAC_RX_BUFF_OVRN | RMAC_RX_SM_ERR, + &bar0->mac_rmac_err_reg, + &sw_stat->mac_rmac_err_cnt)) + goto reset; + do_s2io_chk_alarm_bit(RMAC_UNUSED_INT|RMAC_SINGLE_ECC_ERR| + RMAC_DOUBLE_ECC_ERR, &bar0->mac_rmac_err_reg, + &sw_stat->mac_rmac_err_cnt); + } + + val64 = readq(&bar0->xgxs_int_status); + if (val64 & XGXS_INT_STATUS_RXGXS) { + if (do_s2io_chk_alarm_bit(RXGXS_ESTORE_OFLOW | RXGXS_RX_SM_ERR, + &bar0->xgxs_rxgxs_err_reg, + &sw_stat->xgxs_rxgxs_err_cnt)) + goto reset; + } + + val64 = readq(&bar0->mc_int_status); + if(val64 & MC_INT_STATUS_MC_INT) { + if (do_s2io_chk_alarm_bit(MC_ERR_REG_SM_ERR, &bar0->mc_err_reg, + &sw_stat->mc_err_cnt)) + goto reset; + + /* Handling Ecc errors */ + if (val64 & (MC_ERR_REG_ECC_ALL_SNG | MC_ERR_REG_ECC_ALL_DBL)) { + writeq(val64, &bar0->mc_err_reg); + if (val64 & MC_ERR_REG_ECC_ALL_DBL) { + sw_stat->double_ecc_errs++; + if (sp->device_type != XFRAME_II_DEVICE) { + /* + * Reset XframeI only if critical error + */ + if (val64 & + (MC_ERR_REG_MIRI_ECC_DB_ERR_0 | + MC_ERR_REG_MIRI_ECC_DB_ERR_1)) + goto reset; + } + } else + sw_stat->single_ecc_errs++; + } + } + return; + +reset: + netif_stop_queue(dev); + schedule_work(&sp->rst_timer_task); + sw_stat->soft_reset_cnt++; + return; +} + /** * s2io_isr - ISR handler of the device . * @irq: the irq of the device. @@ -5754,7 +5937,7 @@ static void s2io_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *estats, u64 * tmp_stats) { - int i = 0; + int i = 0, k; struct s2io_nic *sp = dev->priv; struct stat_block *stat_info = sp->mac_control.stats_info; @@ -5949,7 +6132,8 @@ static void s2io_get_ethtool_stats(struct net_device *dev, tmp_stats[i++] = stat_info->sw_stat.serious_err_cnt; tmp_stats[i++] = stat_info->sw_stat.soft_reset_cnt; tmp_stats[i++] = stat_info->sw_stat.fifo_full_cnt; - tmp_stats[i++] = stat_info->sw_stat.ring_full_cnt; + for (k = 0; k < MAX_RX_RINGS; k++) + tmp_stats[i++] = stat_info->sw_stat.ring_full_cnt[k]; tmp_stats[i++] = stat_info->xpak_stat.alarm_transceiver_temp_high; tmp_stats[i++] = stat_info->xpak_stat.alarm_transceiver_temp_low; tmp_stats[i++] = stat_info->xpak_stat.alarm_laser_bias_current_high; @@ -6006,6 +6190,23 @@ static void s2io_get_ethtool_stats(struct net_device *dev, tmp_stats[i++] = stat_info->sw_stat.rx_buf_size_err_cnt; tmp_stats[i++] = stat_info->sw_stat.rx_rxd_corrupt_cnt; tmp_stats[i++] = stat_info->sw_stat.rx_unkn_err_cnt; + tmp_stats[i++] = stat_info->sw_stat.tda_err_cnt; + tmp_stats[i++] = stat_info->sw_stat.pfc_err_cnt; + tmp_stats[i++] = stat_info->sw_stat.pcc_err_cnt; + tmp_stats[i++] = stat_info->sw_stat.tti_err_cnt; + tmp_stats[i++] = stat_info->sw_stat.tpa_err_cnt; + tmp_stats[i++] = stat_info->sw_stat.sm_err_cnt; + tmp_stats[i++] = stat_info->sw_stat.lso_err_cnt; + tmp_stats[i++] = stat_info->sw_stat.mac_tmac_err_cnt; + tmp_stats[i++] = stat_info->sw_stat.mac_rmac_err_cnt; + tmp_stats[i++] = stat_info->sw_stat.xgxs_txgxs_err_cnt; + tmp_stats[i++] = stat_info->sw_stat.xgxs_rxgxs_err_cnt; + tmp_stats[i++] = stat_info->sw_stat.rc_err_cnt; + tmp_stats[i++] = stat_info->sw_stat.prc_pcix_err_cnt; + tmp_stats[i++] = stat_info->sw_stat.rpa_err_cnt; + tmp_stats[i++] = stat_info->sw_stat.rda_err_cnt; + tmp_stats[i++] = stat_info->sw_stat.rti_err_cnt; + tmp_stats[i++] = stat_info->sw_stat.mc_err_cnt; } static int s2io_ethtool_get_regs_len(struct net_device *dev) diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index b9654dfeb87..1e2e72d6aad 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -91,7 +91,7 @@ struct swStat { unsigned long long serious_err_cnt; unsigned long long soft_reset_cnt; unsigned long long fifo_full_cnt; - unsigned long long ring_full_cnt; + unsigned long long ring_full_cnt[8]; /* LRO statistics */ unsigned long long clubbed_frms_cnt; unsigned long long sending_both; @@ -126,6 +126,26 @@ struct swStat { unsigned long long rx_buf_size_err_cnt; unsigned long long rx_rxd_corrupt_cnt; unsigned long long rx_unkn_err_cnt; + + /* Error/alarm statistics*/ + unsigned long long tda_err_cnt; + unsigned long long pfc_err_cnt; + unsigned long long pcc_err_cnt; + unsigned long long tti_err_cnt; + unsigned long long lso_err_cnt; + unsigned long long tpa_err_cnt; + unsigned long long sm_err_cnt; + unsigned long long mac_tmac_err_cnt; + unsigned long long mac_rmac_err_cnt; + unsigned long long xgxs_txgxs_err_cnt; + unsigned long long xgxs_rxgxs_err_cnt; + unsigned long long rc_err_cnt; + unsigned long long prc_pcix_err_cnt; + unsigned long long rpa_err_cnt; + unsigned long long rda_err_cnt; + unsigned long long rti_err_cnt; + unsigned long long mc_err_cnt; + }; /* Xpak releated alarm and warnings */ @@ -1018,7 +1038,7 @@ static void free_shared_mem(struct s2io_nic *sp); static int init_nic(struct s2io_nic *nic); static void rx_intr_handler(struct ring_info *ring_data); static void tx_intr_handler(struct fifo_info *fifo_data); -static void alarm_intr_handler(struct s2io_nic *sp); +static void s2io_handle_errors(void * dev_id); static int s2io_starter(void); static void s2io_closer(void); -- cgit v1.2.3-70-g09d2 From eaae7f72304f2cd095e68ab39629c0f32815dcf2 Mon Sep 17 00:00:00 2001 From: Sivakumar Subramani Date: Sat, 15 Sep 2007 14:14:22 -0700 Subject: S2io: Cleanup - removed unused variable intr_type - Removed the unused variable, intr_type, in device private structure. [ Resolve conflicts with napi_struct changes... -DaveM ] Signed-off-by: Sivakumar Subramani Signed-off-by: Santosh Rastapur Signed-off-by: Ramkrishna Vepa Signed-off-by: Jeff Garzik Signed-off-by: David S. Miller --- drivers/net/s2io.c | 34 +++++++++++++++++----------------- drivers/net/s2io.h | 5 ----- 2 files changed, 17 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 182643ff81e..2ee2a2b4b27 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -1611,7 +1611,7 @@ static int init_nic(struct s2io_nic *nic) val64 = RTI_DATA2_MEM_RX_UFC_A(0x1) | RTI_DATA2_MEM_RX_UFC_B(0x2) ; - if (nic->intr_type == MSI_X) + if (nic->config.intr_type == MSI_X) val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x20) | \ RTI_DATA2_MEM_RX_UFC_D(0x40)); else @@ -1749,7 +1749,7 @@ static int init_nic(struct s2io_nic *nic) static int s2io_link_fault_indication(struct s2io_nic *nic) { - if (nic->intr_type != INTA) + if (nic->config.intr_type != INTA) return MAC_RMAC_ERR_TIMER; if (nic->device_type == XFRAME_II_DEVICE) return LINK_UP_DOWN_INTERRUPT; @@ -3549,7 +3549,7 @@ static int s2io_set_swapper(struct s2io_nic * sp) SWAPPER_CTRL_RXF_W_FE | SWAPPER_CTRL_XMSI_FE | SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE); - if (sp->intr_type == INTA) + if (sp->config.intr_type == INTA) val64 |= SWAPPER_CTRL_XMSI_SE; writeq(val64, &bar0->swapper_ctrl); #else @@ -3572,7 +3572,7 @@ static int s2io_set_swapper(struct s2io_nic * sp) SWAPPER_CTRL_RXF_W_FE | SWAPPER_CTRL_XMSI_FE | SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE); - if (sp->intr_type == INTA) + if (sp->config.intr_type == INTA) val64 |= SWAPPER_CTRL_XMSI_SE; writeq(val64, &bar0->swapper_ctrl); #endif @@ -3848,7 +3848,7 @@ static int s2io_open(struct net_device *dev) napi_enable(&sp->napi); - if (sp->intr_type == MSI_X) { + if (sp->config.intr_type == MSI_X) { int ret = s2io_enable_msi_x(sp); if (!ret) { @@ -3880,12 +3880,12 @@ static int s2io_open(struct net_device *dev) DBG_PRINT(ERR_DBG, "%s: MSI-X requested but failed to enable\n", dev->name); - sp->intr_type = INTA; + sp->config.intr_type = INTA; } } /* NAPI doesn't work well with MSI(X) */ - if (sp->intr_type != INTA) { + if (sp->config.intr_type != INTA) { if(sp->config.napi) sp->config.napi = 0; } @@ -3910,7 +3910,7 @@ static int s2io_open(struct net_device *dev) hw_init_failed: napi_disable(&sp->napi); - if (sp->intr_type == MSI_X) { + if (sp->config.intr_type == MSI_X) { if (sp->entries) { kfree(sp->entries); sp->mac_control.stats_info->sw_stat.mem_freed @@ -6697,18 +6697,18 @@ static int s2io_add_isr(struct s2io_nic * sp) struct net_device *dev = sp->dev; int err = 0; - if (sp->intr_type == MSI_X) + if (sp->config.intr_type == MSI_X) ret = s2io_enable_msi_x(sp); if (ret) { DBG_PRINT(ERR_DBG, "%s: Defaulting to INTA\n", dev->name); - sp->intr_type = INTA; + sp->config.intr_type = INTA; } /* Store the values of the MSIX table in the struct s2io_nic structure */ store_xmsi_data(sp); /* After proper initialization of H/W, register ISR */ - if (sp->intr_type == MSI_X) { + if (sp->config.intr_type == MSI_X) { int i, msix_tx_cnt=0,msix_rx_cnt=0; for (i=1; (sp->s2io_entries[i].in_use == MSIX_FLG); i++) { @@ -6760,7 +6760,7 @@ static int s2io_add_isr(struct s2io_nic * sp) printk("MSI-X-TX %d entries enabled\n",msix_tx_cnt); printk("MSI-X-RX %d entries enabled\n",msix_rx_cnt); } - if (sp->intr_type == INTA) { + if (sp->config.intr_type == INTA) { err = request_irq((int) sp->pdev->irq, s2io_isr, IRQF_SHARED, sp->name, dev); if (err) { @@ -6777,7 +6777,7 @@ static void s2io_rem_isr(struct s2io_nic * sp) struct net_device *dev = sp->dev; struct swStat *stats = &sp->mac_control.stats_info->sw_stat; - if (sp->intr_type == MSI_X) { + if (sp->config.intr_type == MSI_X) { int i; u16 msi_control; @@ -6950,7 +6950,7 @@ static int s2io_card_up(struct s2io_nic * sp) /* Add interrupt service routine */ if (s2io_add_isr(sp) != 0) { - if (sp->intr_type == MSI_X) + if (sp->config.intr_type == MSI_X) s2io_rem_isr(sp); s2io_reset(sp); free_rx_buffers(sp); @@ -6964,7 +6964,7 @@ static int s2io_card_up(struct s2io_nic * sp) /* Enable select interrupts */ en_dis_err_alarms(sp, ENA_ALL_INTRS, ENABLE_INTRS); - if (sp->intr_type != INTA) + if (sp->config.intr_type != INTA) en_dis_able_nic_intrs(sp, ENA_ALL_INTRS, DISABLE_INTRS); else { interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR; @@ -7491,7 +7491,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) if (rx_ring_mode == 2) sp->rxd_mode = RXD_MODE_3B; - sp->intr_type = dev_intr_type; + sp->config.intr_type = dev_intr_type; if ((pdev->device == PCI_DEVICE_ID_HERC_WIN) || (pdev->device == PCI_DEVICE_ID_HERC_UNI)) @@ -7770,7 +7770,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) if (napi) DBG_PRINT(ERR_DBG, "%s: NAPI enabled\n", dev->name); - switch(sp->intr_type) { + switch(sp->config.intr_type) { case INTA: DBG_PRINT(ERR_DBG, "%s: Interrupt type INTA\n", dev->name); break; diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 1e2e72d6aad..c01abc1d89a 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -906,11 +906,6 @@ struct s2io_nic { unsigned long sending_both; u8 lro; u16 lro_max_aggr_per_sess; - -#define INTA 0 -#define MSI_X 2 - u8 intr_type; - spinlock_t rx_lock; atomic_t isr_cnt; u64 general_int_mask; -- cgit v1.2.3-70-g09d2 From 92b84437a6cddf5dc00ab179e38d2baa2264d46a Mon Sep 17 00:00:00 2001 From: Sivakumar Subramani Date: Thu, 6 Sep 2007 06:51:14 -0400 Subject: S2io: Check for device state before handling traffic - Added check to return from the traffic handling function, if the card status is DOWN. - Implemented Jeff's comments on incorrect return value in s2io_poll function. Signed-off-by: Sivakumar Subramani Signed-off-by: Santosh Rastapur Signed-off-by: Ramkrishna Vepa Signed-off-by: Jeff Garzik --- drivers/net/s2io.c | 56 ++++++++++++++++++++++++++++++++++++------------------ drivers/net/s2io.h | 12 ++++++++---- 2 files changed, 46 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 2ee2a2b4b27..d167bc0ae95 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -130,6 +130,11 @@ static inline int rx_buffer_level(struct s2io_nic * sp, int rxb_size, int ring) return 0; } +static inline int is_s2io_card_up(const struct s2io_nic * sp) +{ + return test_bit(__S2IO_STATE_CARD_UP, &sp->state); +} + /* Ethtool related variables and Macros. */ static char s2io_gstrings[][ETH_GSTRING_LEN] = { "Register test\t(offline)", @@ -2711,6 +2716,12 @@ static int s2io_poll(struct napi_struct *napi, int budget) int i; atomic_inc(&nic->isr_cnt); + + if (!is_s2io_card_up(nic)) { + atomic_dec(&nic->isr_cnt); + return 0; + } + mac_control = &nic->mac_control; config = &nic->config; @@ -2837,12 +2848,6 @@ static void rx_intr_handler(struct ring_info *ring_data) struct RxD3* rxdp3; spin_lock(&nic->rx_lock); - if (atomic_read(&nic->card_state) == CARD_DOWN) { - DBG_PRINT(INTR_DBG, "%s: %s going down for reset\n", - __FUNCTION__, dev->name); - spin_unlock(&nic->rx_lock); - return; - } get_info = ring_data->rx_curr_get_info; get_block = get_info.block_index; @@ -3990,7 +3995,7 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) } spin_lock_irqsave(&sp->tx_lock, flags); - if (atomic_read(&sp->card_state) == CARD_DOWN) { + if (!is_s2io_card_up(sp)) { DBG_PRINT(TX_DBG, "%s: Card going down for reset\n", dev->name); spin_unlock_irqrestore(&sp->tx_lock, flags); @@ -4184,6 +4189,11 @@ static irqreturn_t s2io_msix_ring_handle(int irq, void *dev_id) atomic_inc(&sp->isr_cnt); + if (!is_s2io_card_up(sp)) { + atomic_dec(&sp->isr_cnt); + return IRQ_HANDLED; + } + rx_intr_handler(ring); s2io_chk_rx_buffers(sp, ring->ring_no); @@ -4197,6 +4207,12 @@ static irqreturn_t s2io_msix_fifo_handle(int irq, void *dev_id) struct s2io_nic *sp = fifo->nic; atomic_inc(&sp->isr_cnt); + + if (!is_s2io_card_up(sp)) { + atomic_dec(&sp->isr_cnt); + return IRQ_HANDLED; + } + tx_intr_handler(fifo); atomic_dec(&sp->isr_cnt); return IRQ_HANDLED; @@ -4305,7 +4321,7 @@ static void s2io_handle_errors(void * dev_id) struct swStat *sw_stat = &sp->mac_control.stats_info->sw_stat; struct xpakStat *stats = &sp->mac_control.stats_info->xpak_stat; - if (unlikely(atomic_read(&sp->card_state) == CARD_DOWN)) + if (!is_s2io_card_up(sp)) return; if (pci_channel_offline(sp->pdev)) @@ -4576,6 +4592,12 @@ static irqreturn_t s2io_isr(int irq, void *dev_id) return IRQ_NONE; atomic_inc(&sp->isr_cnt); + + if (!is_s2io_card_up(sp)) { + atomic_dec(&sp->isr_cnt); + return IRQ_NONE; + } + mac_control = &sp->mac_control; config = &sp->config; @@ -4664,7 +4686,7 @@ static void s2io_updt_stats(struct s2io_nic *sp) u64 val64; int cnt = 0; - if (atomic_read(&sp->card_state) == CARD_UP) { + if (is_s2io_card_up(sp)) { /* Apprx 30us on a 133 MHz bus */ val64 = SET_UPDT_CLICKS(10) | STAT_CFG_ONE_SHOT_EN | STAT_CFG_STAT_EN; @@ -6460,7 +6482,7 @@ static void s2io_set_link(struct work_struct *work) if (!netif_running(dev)) goto out_unlock; - if (test_and_set_bit(0, &(nic->link_state))) { + if (test_and_set_bit(__S2IO_STATE_LINK_TASK, &(nic->state))) { /* The card is being reset, no point doing anything */ goto out_unlock; } @@ -6516,7 +6538,7 @@ static void s2io_set_link(struct work_struct *work) writeq(val64, &bar0->adapter_control); s2io_link(nic, LINK_DOWN); } - clear_bit(0, &(nic->link_state)); + clear_bit(__S2IO_STATE_LINK_TASK, &(nic->state)); out_unlock: rtnl_unlock(); @@ -6825,10 +6847,10 @@ static void do_s2io_card_down(struct s2io_nic * sp, int do_io) del_timer_sync(&sp->alarm_timer); /* If s2io_set_link task is executing, wait till it completes. */ - while (test_and_set_bit(0, &(sp->link_state))) { + while (test_and_set_bit(__S2IO_STATE_LINK_TASK, &(sp->state))) { msleep(50); } - atomic_set(&sp->card_state, CARD_DOWN); + clear_bit(__S2IO_STATE_CARD_UP, &sp->state); /* disable Tx and Rx traffic on the NIC */ if (do_io) @@ -6879,7 +6901,7 @@ static void do_s2io_card_down(struct s2io_nic * sp, int do_io) free_rx_buffers(sp); spin_unlock_irqrestore(&sp->rx_lock, flags); - clear_bit(0, &(sp->link_state)); + clear_bit(__S2IO_STATE_LINK_TASK, &(sp->state)); } static void s2io_card_down(struct s2io_nic * sp) @@ -6972,8 +6994,7 @@ static int s2io_card_up(struct s2io_nic * sp) en_dis_able_nic_intrs(sp, interruptible, ENABLE_INTRS); } - - atomic_set(&sp->card_state, CARD_UP); + set_bit(__S2IO_STATE_CARD_UP, &sp->state); return 0; } @@ -7701,9 +7722,8 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) * Initialize the tasklet status and link state flags * and the card state parameter */ - atomic_set(&(sp->card_state), 0); sp->tasklet_status = 0; - sp->link_state = 0; + sp->state = 0; /* Initialize spinlocks */ spin_lock_init(&sp->tx_lock); diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index c01abc1d89a..33e812ea7d1 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -802,6 +802,13 @@ struct lro { u8 saw_ts; }; +/* These flags represent the devices temporary state */ +enum s2io_device_state_t +{ + __S2IO_STATE_LINK_TASK=0, + __S2IO_STATE_CARD_UP +}; + /* Structure representing one instance of the NIC */ struct s2io_nic { int rxd_mode; @@ -880,10 +887,6 @@ struct s2io_nic { int task_flag; unsigned long long start_time; -#define CARD_DOWN 1 -#define CARD_UP 2 - atomic_t card_state; - volatile unsigned long link_state; struct vlan_group *vlgrp; #define MSIX_FLG 0xA5 struct msix_entry *entries; @@ -906,6 +909,7 @@ struct s2io_nic { unsigned long sending_both; u8 lro; u16 lro_max_aggr_per_sess; + volatile unsigned long state; spinlock_t rx_lock; atomic_t isr_cnt; u64 general_int_mask; -- cgit v1.2.3-70-g09d2 From 596c5c97431eab8465739c169401ea611127b9ad Mon Sep 17 00:00:00 2001 From: Sivakumar Subramani Date: Sat, 15 Sep 2007 14:24:03 -0700 Subject: S2io: code Optimization of isr function - Code Optimization of s2io_isr function. - Isr check using per device napi variable instead of driver global. - Reduced from 3 to 1 if condition before check for processing packet receive packets. - Implemented Jeff's comment to use synchronize_irq. Removed the isr_cnt variable as it became redundant. - One time de assert the interrupts by writing all F's to the general_int_mask register instead of de asserting by clearing the source of interrupts with multiple writes which causes loss of interrupts (race conditions). It is entirely possible that before the driver has a chance to mask the asserted alarm bit, another alarm/traffic interrupt bit gets asserted as well. In this case Herc will keep the INTA line asserted and the bridge will not send a new Assert_INTA message upstream. [ Resolved conflicts due to napi_struct changes... -DaveM ] Signed-off-by: Sivakumar Subramani Signed-off-by: Santosh Rastapur Signed-off-by: Ramkrishna Vepa Signed-off-by: Jeff Garzik Signed-off-by: David S. Miller --- drivers/net/s2io.c | 157 +++++++++++++++++++++-------------------------------- drivers/net/s2io.h | 1 - 2 files changed, 61 insertions(+), 97 deletions(-) (limited to 'drivers') diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index d167bc0ae95..ac6b9b93c02 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -84,7 +84,7 @@ #include "s2io.h" #include "s2io-regs.h" -#define DRV_VERSION "2.0.26.1" +#define DRV_VERSION "2.0.26.2" /* S2io Driver name & version. */ static char s2io_driver_name[] = "Neterion"; @@ -2715,12 +2715,8 @@ static int s2io_poll(struct napi_struct *napi, int budget) struct XENA_dev_config __iomem *bar0 = nic->bar0; int i; - atomic_inc(&nic->isr_cnt); - - if (!is_s2io_card_up(nic)) { - atomic_dec(&nic->isr_cnt); + if (!is_s2io_card_up(nic)) return 0; - } mac_control = &nic->mac_control; config = &nic->config; @@ -2752,7 +2748,6 @@ static int s2io_poll(struct napi_struct *napi, int budget) /* Re enable the Rx interrupts. */ writeq(0x0, &bar0->rx_traffic_mask); readl(&bar0->rx_traffic_mask); - atomic_dec(&nic->isr_cnt); return pkt_cnt; no_rx: @@ -2763,7 +2758,6 @@ no_rx: break; } } - atomic_dec(&nic->isr_cnt); return pkt_cnt; } @@ -2791,7 +2785,6 @@ static void s2io_netpoll(struct net_device *dev) disable_irq(dev->irq); - atomic_inc(&nic->isr_cnt); mac_control = &nic->mac_control; config = &nic->config; @@ -2816,7 +2809,6 @@ static void s2io_netpoll(struct net_device *dev) break; } } - atomic_dec(&nic->isr_cnt); enable_irq(dev->irq); return; } @@ -4187,17 +4179,12 @@ static irqreturn_t s2io_msix_ring_handle(int irq, void *dev_id) struct ring_info *ring = (struct ring_info *)dev_id; struct s2io_nic *sp = ring->nic; - atomic_inc(&sp->isr_cnt); - - if (!is_s2io_card_up(sp)) { - atomic_dec(&sp->isr_cnt); + if (!is_s2io_card_up(sp)) return IRQ_HANDLED; - } rx_intr_handler(ring); s2io_chk_rx_buffers(sp, ring->ring_no); - atomic_dec(&sp->isr_cnt); return IRQ_HANDLED; } @@ -4206,15 +4193,10 @@ static irqreturn_t s2io_msix_fifo_handle(int irq, void *dev_id) struct fifo_info *fifo = (struct fifo_info *)dev_id; struct s2io_nic *sp = fifo->nic; - atomic_inc(&sp->isr_cnt); - - if (!is_s2io_card_up(sp)) { - atomic_dec(&sp->isr_cnt); + if (!is_s2io_card_up(sp)) return IRQ_HANDLED; - } tx_intr_handler(fifo); - atomic_dec(&sp->isr_cnt); return IRQ_HANDLED; } static void s2io_txpic_intr_handle(struct s2io_nic *sp) @@ -4591,12 +4573,8 @@ static irqreturn_t s2io_isr(int irq, void *dev_id) if (pci_channel_offline(sp->pdev)) return IRQ_NONE; - atomic_inc(&sp->isr_cnt); - - if (!is_s2io_card_up(sp)) { - atomic_dec(&sp->isr_cnt); + if (!is_s2io_card_up(sp)) return IRQ_NONE; - } mac_control = &sp->mac_control; config = &sp->config; @@ -4607,73 +4585,75 @@ static irqreturn_t s2io_isr(int irq, void *dev_id) * 1. Rx of packet. * 2. Tx complete. * 3. Link down. - * 4. Error in any functional blocks of the NIC. */ reason = readq(&bar0->general_int_status); - if (!reason) { - /* The interrupt was not raised by us. */ - atomic_dec(&sp->isr_cnt); - return IRQ_NONE; - } - else if (unlikely(reason == S2IO_MINUS_ONE) ) { - /* Disable device and get out */ - atomic_dec(&sp->isr_cnt); - return IRQ_NONE; + if (unlikely(reason == S2IO_MINUS_ONE) ) { + /* Nothing much can be done. Get out */ + return IRQ_HANDLED; } - if (napi) { - if (reason & GEN_INTR_RXTRAFFIC) { - if (likely (netif_rx_schedule_prep(dev, &sp->napi))) { - __netif_rx_schedule(dev, &sp->napi); - writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_mask); + if (reason & (GEN_INTR_RXTRAFFIC | + GEN_INTR_TXTRAFFIC | GEN_INTR_TXPIC)) + { + writeq(S2IO_MINUS_ONE, &bar0->general_int_mask); + + if (config->napi) { + if (reason & GEN_INTR_RXTRAFFIC) { + if (likely(netif_rx_schedule_prep(dev, + &sp->napi))) { + __netif_rx_schedule(dev, &sp->napi); + writeq(S2IO_MINUS_ONE, + &bar0->rx_traffic_mask); + } else + writeq(S2IO_MINUS_ONE, + &bar0->rx_traffic_int); } - else + } else { + /* + * rx_traffic_int reg is an R1 register, writing all 1's + * will ensure that the actual interrupt causing bit + * get's cleared and hence a read can be avoided. + */ + if (reason & GEN_INTR_RXTRAFFIC) writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int); + + for (i = 0; i < config->rx_ring_num; i++) + rx_intr_handler(&mac_control->rings[i]); } - } else { + /* - * Rx handler is called by default, without checking for the - * cause of interrupt. - * rx_traffic_int reg is an R1 register, writing all 1's + * tx_traffic_int reg is an R1 register, writing all 1's * will ensure that the actual interrupt causing bit get's * cleared and hence a read can be avoided. */ - if (reason & GEN_INTR_RXTRAFFIC) - writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int); + if (reason & GEN_INTR_TXTRAFFIC) + writeq(S2IO_MINUS_ONE, &bar0->tx_traffic_int); - for (i = 0; i < config->rx_ring_num; i++) { - rx_intr_handler(&mac_control->rings[i]); - } - } + for (i = 0; i < config->tx_fifo_num; i++) + tx_intr_handler(&mac_control->fifos[i]); - /* - * tx_traffic_int reg is an R1 register, writing all 1's - * will ensure that the actual interrupt causing bit get's - * cleared and hence a read can be avoided. - */ - if (reason & GEN_INTR_TXTRAFFIC) - writeq(S2IO_MINUS_ONE, &bar0->tx_traffic_int); + if (reason & GEN_INTR_TXPIC) + s2io_txpic_intr_handle(sp); - for (i = 0; i < config->tx_fifo_num; i++) - tx_intr_handler(&mac_control->fifos[i]); + /* + * Reallocate the buffers from the interrupt handler itself. + */ + if (!config->napi) { + for (i = 0; i < config->rx_ring_num; i++) + s2io_chk_rx_buffers(sp, i); + } + writeq(sp->general_int_mask, &bar0->general_int_mask); + readl(&bar0->general_int_status); - if (reason & GEN_INTR_TXPIC) - s2io_txpic_intr_handle(sp); - /* - * If the Rx buffer count is below the panic threshold then - * reallocate the buffers from the interrupt handler itself, - * else schedule a tasklet to reallocate the buffers. - */ - if (!napi) { - for (i = 0; i < config->rx_ring_num; i++) - s2io_chk_rx_buffers(sp, i); - } + return IRQ_HANDLED; - writeq(0, &bar0->general_int_mask); - readl(&bar0->general_int_status); + } + else if (!reason) { + /* The interrupt was not raised by us */ + return IRQ_NONE; + } - atomic_dec(&sp->isr_cnt); return IRQ_HANDLED; } @@ -6795,7 +6775,6 @@ static int s2io_add_isr(struct s2io_nic * sp) } static void s2io_rem_isr(struct s2io_nic * sp) { - int cnt = 0; struct net_device *dev = sp->dev; struct swStat *stats = &sp->mac_control.stats_info->sw_stat; @@ -6808,6 +6787,7 @@ static void s2io_rem_isr(struct s2io_nic * sp) int vector = sp->entries[i].vector; void *arg = sp->s2io_entries[i].arg; + synchronize_irq(vector); free_irq(vector, arg); } @@ -6826,16 +6806,9 @@ static void s2io_rem_isr(struct s2io_nic * sp) pci_disable_msix(sp->pdev); } else { + synchronize_irq(sp->pdev->irq); free_irq(sp->pdev->irq, dev); } - /* Waiting till all Interrupt handlers are complete */ - cnt = 0; - do { - msleep(10); - if (!atomic_read(&sp->isr_cnt)) - break; - cnt++; - } while(cnt < 5); } static void do_s2io_card_down(struct s2io_nic * sp, int do_io) @@ -7365,19 +7338,12 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type) if (*dev_intr_type != INTA) napi = 0; -#ifndef CONFIG_PCI_MSI - if (*dev_intr_type != INTA) { - DBG_PRINT(ERR_DBG, "s2io: This kernel does not support" - "MSI/MSI-X. Defaulting to INTA\n"); - *dev_intr_type = INTA; - } -#else if ((*dev_intr_type != INTA) && (*dev_intr_type != MSI_X)) { DBG_PRINT(ERR_DBG, "s2io: Wrong intr_type requested. " "Defaulting to INTA\n"); *dev_intr_type = INTA; } -#endif + if ((*dev_intr_type == MSI_X) && ((pdev->device != PCI_DEVICE_ID_HERC_WIN) && (pdev->device != PCI_DEVICE_ID_HERC_UNI))) { @@ -7535,6 +7501,8 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) mac_control = &sp->mac_control; config = &sp->config; + config->napi = napi; + /* Tx side parameters. */ config->tx_fifo_num = tx_fifo_num; for (i = 0; i < MAX_TX_FIFOS; i++) { @@ -7582,9 +7550,6 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) for (i = 0; i < config->rx_ring_num; i++) atomic_set(&sp->rx_bufs_left[i], 0); - /* Initialize the number of ISRs currently running */ - atomic_set(&sp->isr_cnt, 0); - /* initialize the shared memory used by the NIC and the host */ if (init_shared_mem(sp)) { DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 33e812ea7d1..1a70cf02c91 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -911,7 +911,6 @@ struct s2io_nic { u16 lro_max_aggr_per_sess; volatile unsigned long state; spinlock_t rx_lock; - atomic_t isr_cnt; u64 general_int_mask; u64 *ufo_in_band_v; #define VPD_STRING_LEN 80 -- cgit v1.2.3-70-g09d2 From 10d024c1b2fd58af8362670d7d6e5ae52fc33353 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 17 Sep 2007 13:11:17 -0700 Subject: [NET]: Nuke SET_MODULE_OWNER macro. It's been a useless no-op for long enough in 2.6 so I figured it's time to remove it. The number of people that could object because they're maintaining unified 2.4 and 2.6 drivers is probably rather small. [ Handled drivers added by netdev tree and some missed IRDA cases... -DaveM ] Signed-off-by: Ralf Baechle Signed-off-by: Jeff Garzik Signed-off-by: David S. Miller --- drivers/ieee1394/eth1394.c | 1 - drivers/infiniband/hw/amso1100/c2.c | 1 - drivers/infiniband/hw/amso1100/c2_provider.c | 1 - drivers/infiniband/ulp/ipoib/ipoib_main.c | 2 -- drivers/message/fusion/mptlan.c | 2 -- drivers/net/3c501.c | 2 -- drivers/net/3c503.c | 2 -- drivers/net/3c505.c | 2 -- drivers/net/3c507.c | 2 -- drivers/net/3c509.c | 6 ------ drivers/net/3c515.c | 2 -- drivers/net/3c523.c | 1 - drivers/net/3c527.c | 2 -- drivers/net/3c59x.c | 1 - drivers/net/8139cp.c | 1 - drivers/net/8139too.c | 1 - drivers/net/82596.c | 1 - drivers/net/a2065.c | 1 - drivers/net/ac3200.c | 2 -- drivers/net/acenic.c | 1 - drivers/net/amd8111e.c | 1 - drivers/net/apne.c | 1 - drivers/net/appletalk/cops.c | 2 -- drivers/net/appletalk/ipddp.c | 1 - drivers/net/appletalk/ltpc.c | 2 -- drivers/net/arcnet/com90io.c | 2 -- drivers/net/ariadne.c | 1 - drivers/net/arm/at91_ether.c | 1 - drivers/net/arm/ether1.c | 1 - drivers/net/arm/ether3.c | 1 - drivers/net/arm/etherh.c | 1 - drivers/net/at1700.c | 2 -- drivers/net/atarilance.c | 1 - drivers/net/atl1/atl1_main.c | 1 - drivers/net/atp.c | 1 - drivers/net/b44.c | 1 - drivers/net/bfin_mac.c | 1 - drivers/net/bmac.c | 1 - drivers/net/bnx2.c | 1 - drivers/net/bonding/bond_main.c | 2 -- drivers/net/cassini.c | 1 - drivers/net/chelsio/cxgb2.c | 1 - drivers/net/cs89x0.c | 1 - drivers/net/cxgb3/cxgb3_main.c | 1 - drivers/net/de600.c | 1 - drivers/net/de620.c | 2 -- drivers/net/defxx.c | 1 - drivers/net/dgrs.c | 2 -- drivers/net/dl2k.c | 1 - drivers/net/dm9000.c | 1 - drivers/net/dummy.c | 1 - drivers/net/e100.c | 1 - drivers/net/e1000/e1000_main.c | 1 - drivers/net/e1000e/netdev.c | 1 - drivers/net/e2100.c | 2 -- drivers/net/eepro.c | 4 ---- drivers/net/eepro100.c | 1 - drivers/net/eexpress.c | 2 -- drivers/net/ehea/ehea_main.c | 2 -- drivers/net/epic100.c | 1 - drivers/net/eql.c | 2 -- drivers/net/es3210.c | 2 -- drivers/net/eth16i.c | 2 -- drivers/net/ewrk3.c | 1 - drivers/net/fealnx.c | 1 - drivers/net/fec_8xx/fec_main.c | 1 - drivers/net/forcedeth.c | 1 - drivers/net/fs_enet/fs_enet-main.c | 1 - drivers/net/gianfar.c | 1 - drivers/net/hamachi.c | 1 - drivers/net/hamradio/6pack.c | 2 -- drivers/net/hp-plus.c | 2 -- drivers/net/hp.c | 2 -- drivers/net/hp100.c | 5 ----- drivers/net/hydra.c | 1 - drivers/net/ibm_emac/ibm_emac_core.c | 1 - drivers/net/ibmlana.c | 2 -- drivers/net/ibmveth.c | 4 ---- drivers/net/ifb.c | 1 - drivers/net/ioc3-eth.c | 1 - drivers/net/irda/ali-ircc.c | 4 ---- drivers/net/irda/donauboe.c | 1 - drivers/net/irda/irda-usb.c | 1 - drivers/net/irda/irport.c | 2 -- drivers/net/irda/kingsun-sir.c | 1 - drivers/net/irda/ks959-sir.c | 1 - drivers/net/irda/ksdazzle-sir.c | 1 - drivers/net/irda/mcs7780.c | 2 -- drivers/net/irda/nsc-ircc.c | 1 - drivers/net/irda/sir_dev.c | 2 -- drivers/net/irda/smsc-ircc2.c | 2 -- drivers/net/irda/stir4200.c | 1 - drivers/net/irda/via-ircc.c | 3 --- drivers/net/irda/vlsi_ir.c | 2 -- drivers/net/irda/w83977af_ir.c | 3 --- drivers/net/isa-skeleton.c | 2 -- drivers/net/ixgb/ixgb_main.c | 1 - drivers/net/ixgbe/ixgbe_main.c | 1 - drivers/net/ixp2000/enp2611.c | 1 - drivers/net/jazzsonic.c | 1 - drivers/net/lance.c | 1 - drivers/net/lguest_net.c | 2 -- drivers/net/lne390.c | 2 -- drivers/net/mac8390.c | 2 -- drivers/net/mac89x0.c | 2 -- drivers/net/macb.c | 1 - drivers/net/mace.c | 1 - drivers/net/macmace.c | 1 - drivers/net/macsonic.c | 1 - drivers/net/mv643xx_eth.c | 1 - drivers/net/mvme147.c | 2 -- drivers/net/myri_sbus.c | 1 - drivers/net/natsemi.c | 1 - drivers/net/ne-h8300.c | 2 -- drivers/net/ne.c | 2 -- drivers/net/ne2.c | 2 -- drivers/net/ne2k-pci.c | 1 - drivers/net/ne3210.c | 1 - drivers/net/netx-eth.c | 1 - drivers/net/netxen/netxen_nic_main.c | 1 - drivers/net/ni5010.c | 2 -- drivers/net/ni52.c | 2 -- drivers/net/ni65.c | 1 - drivers/net/ns83820.c | 1 - drivers/net/pasemi_mac.c | 1 - drivers/net/pci-skeleton.c | 1 - drivers/net/pcmcia/3c589_cs.c | 1 - drivers/net/pcmcia/axnet_cs.c | 3 --- drivers/net/pcmcia/fmvj18x_cs.c | 1 - drivers/net/pcmcia/nmclan_cs.c | 1 - drivers/net/pcmcia/pcnet_cs.c | 1 - drivers/net/pcmcia/smc91c92_cs.c | 1 - drivers/net/pcmcia/xirc2ps_cs.c | 1 - drivers/net/pcnet32.c | 1 - drivers/net/plip.c | 1 - drivers/net/ps3_gelic_net.c | 1 - drivers/net/qla3xxx.c | 1 - drivers/net/r8169.c | 1 - drivers/net/rionet.c | 2 -- drivers/net/rrunner.c | 1 - drivers/net/s2io.c | 1 - drivers/net/sb1000.c | 1 - drivers/net/shaper.c | 2 -- drivers/net/sis190.c | 1 - drivers/net/sis900.c | 1 - drivers/net/sk98lin/skge.c | 1 - drivers/net/skfp/skfddi.c | 1 - drivers/net/skge.c | 1 - drivers/net/sky2.c | 1 - drivers/net/slip.c | 2 -- drivers/net/smc-mca.c | 1 - drivers/net/smc-ultra.c | 2 -- drivers/net/smc-ultra32.c | 2 -- drivers/net/smc911x.c | 1 - drivers/net/smc9194.c | 2 -- drivers/net/smc91x.c | 1 - drivers/net/spider_net.c | 1 - drivers/net/starfire.c | 1 - drivers/net/stnic.c | 1 - drivers/net/sun3_82586.c | 1 - drivers/net/sun3lance.c | 1 - drivers/net/sunbmac.c | 1 - drivers/net/sundance.c | 1 - drivers/net/sungem.c | 1 - drivers/net/sunhme.c | 2 -- drivers/net/sunlance.c | 1 - drivers/net/sunqe.c | 1 - drivers/net/tc35815.c | 1 - drivers/net/tg3.c | 1 - drivers/net/tlan.c | 1 - drivers/net/tokenring/3c359.c | 1 - drivers/net/tokenring/abyss.c | 2 -- drivers/net/tokenring/lanstreamer.c | 1 - drivers/net/tokenring/madgemc.c | 1 - drivers/net/tokenring/olympic.c | 1 - drivers/net/tokenring/proteon.c | 1 - drivers/net/tokenring/skisa.c | 1 - drivers/net/tokenring/smctr.c | 2 -- drivers/net/tokenring/tmspci.c | 1 - drivers/net/tsi108_eth.c | 1 - drivers/net/tulip/de2104x.c | 1 - drivers/net/tulip/de4x5.c | 1 - drivers/net/tulip/dmfe.c | 1 - drivers/net/tulip/tulip_core.c | 1 - drivers/net/tulip/uli526x.c | 1 - drivers/net/tulip/winbond-840.c | 1 - drivers/net/tulip/xircom_cb.c | 1 - drivers/net/tulip/xircom_tulip_cb.c | 1 - drivers/net/tun.c | 1 - drivers/net/typhoon.c | 1 - drivers/net/ucc_geth.c | 1 - drivers/net/usb/kaweth.c | 2 -- drivers/net/usb/pegasus.c | 1 - drivers/net/usb/rtl8150.c | 1 - drivers/net/usb/usbnet.c | 1 - drivers/net/via-rhine.c | 1 - drivers/net/via-velocity.c | 1 - drivers/net/wan/c101.c | 1 - drivers/net/wan/cycx_x25.c | 1 - drivers/net/wan/dscc4.c | 1 - drivers/net/wan/hostess_sv11.c | 2 -- drivers/net/wan/lapbether.c | 1 - drivers/net/wan/lmc/lmc_main.c | 1 - drivers/net/wan/n2.c | 1 - drivers/net/wan/pc300too.c | 1 - drivers/net/wan/pci200syn.c | 1 - drivers/net/wan/sbni.c | 2 -- drivers/net/wan/sdla.c | 1 - drivers/net/wan/wanxl.c | 1 - drivers/net/wd.c | 2 -- drivers/net/wireless/airo.c | 1 - drivers/net/wireless/airport.c | 1 - drivers/net/wireless/arlan-main.c | 2 -- drivers/net/wireless/atmel.c | 1 - drivers/net/wireless/bcm43xx/bcm43xx_main.c | 1 - drivers/net/wireless/ipw2100.c | 2 -- drivers/net/wireless/ipw2200.c | 1 - drivers/net/wireless/libertas/main.c | 4 ---- drivers/net/wireless/netwave_cs.c | 1 - drivers/net/wireless/orinoco_cs.c | 1 - drivers/net/wireless/orinoco_nortel.c | 1 - drivers/net/wireless/orinoco_pci.c | 1 - drivers/net/wireless/orinoco_plx.c | 1 - drivers/net/wireless/orinoco_tmd.c | 1 - drivers/net/wireless/prism54/islpci_dev.c | 1 - drivers/net/wireless/ray_cs.c | 1 - drivers/net/wireless/spectrum_cs.c | 1 - drivers/net/wireless/strip.c | 2 -- drivers/net/wireless/wavelan.c | 1 - drivers/net/wireless/wavelan_cs.c | 1 - drivers/net/wireless/wl3501_cs.c | 2 -- drivers/net/wireless/zd1211rw/zd_netdev.c | 1 - drivers/net/xen-netfront.c | 1 - drivers/net/yellowfin.c | 1 - drivers/net/znet.c | 2 -- drivers/net/zorro8390.c | 1 - drivers/s390/net/claw.c | 1 - drivers/s390/net/ctcmain.c | 1 - drivers/s390/net/lcs.c | 1 - drivers/s390/net/netiucv.c | 1 - drivers/s390/net/qeth_main.c | 1 - drivers/usb/gadget/ether.c | 1 - include/linux/netdevice.h | 1 - net/8021q/vlan.c | 2 -- net/bridge/br_device.c | 1 - net/ipv4/ip_gre.c | 1 - net/ipv4/ipip.c | 2 -- net/ipv6/ip6_tunnel.c | 1 - net/ipv6/sit.c | 1 - net/irda/irlan/irlan_eth.c | 2 -- net/sched/sch_teql.c | 1 - 251 files changed, 341 deletions(-) (limited to 'drivers') diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c index 3a9d7e2d4de..33b80817d68 100644 --- a/drivers/ieee1394/eth1394.c +++ b/drivers/ieee1394/eth1394.c @@ -598,7 +598,6 @@ static void ether1394_add_host(struct hpsb_host *host) goto out; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &host->device); priv = netdev_priv(dev); diff --git a/drivers/infiniband/hw/amso1100/c2.c b/drivers/infiniband/hw/amso1100/c2.c index 0aecea67f3e..f283a9f0c23 100644 --- a/drivers/infiniband/hw/amso1100/c2.c +++ b/drivers/infiniband/hw/amso1100/c2.c @@ -886,7 +886,6 @@ static struct net_device *c2_devinit(struct c2_dev *c2dev, return NULL; } - SET_MODULE_OWNER(netdev); SET_NETDEV_DEV(netdev, &c2dev->pcidev->dev); netdev->open = c2_up; diff --git a/drivers/infiniband/hw/amso1100/c2_provider.c b/drivers/infiniband/hw/amso1100/c2_provider.c index 997cf153076..7a6cece6ea9 100644 --- a/drivers/infiniband/hw/amso1100/c2_provider.c +++ b/drivers/infiniband/hw/amso1100/c2_provider.c @@ -715,7 +715,6 @@ static int c2_pseudo_change_mtu(struct net_device *netdev, int new_mtu) static void setup(struct net_device *netdev) { - SET_MODULE_OWNER(netdev); netdev->open = c2_pseudo_up; netdev->stop = c2_pseudo_down; netdev->hard_start_xmit = c2_pseudo_xmit_frame; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index a59ff07ec3c..b1c3d6cd8eb 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -978,8 +978,6 @@ static void ipoib_setup(struct net_device *dev) netif_carrier_off(dev); - SET_MODULE_OWNER(dev); - priv->dev = dev; spin_lock_init(&priv->lock); diff --git a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c index 01fc397fdd9..3da4c37846e 100644 --- a/drivers/message/fusion/mptlan.c +++ b/drivers/message/fusion/mptlan.c @@ -1427,8 +1427,6 @@ mpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum) dlprintk((KERN_INFO MYNAM ": Finished registering dev " "and setting initial values\n")); - SET_MODULE_OWNER(dev); - if (register_netdev(dev) != 0) { free_netdev(dev); dev = NULL; diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c index 4bee99ba7db..98e0bc4628a 100644 --- a/drivers/net/3c501.c +++ b/drivers/net/3c501.c @@ -174,8 +174,6 @@ struct net_device * __init el1_probe(int unit) mem_start = dev->mem_start & 7; } - SET_MODULE_OWNER(dev); - if (io > 0x1ff) { /* Check a single specified location. */ err = el1_probe1(dev, io); } else if (io != 0) { diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c index bc7e906571d..f9e7ffbcb77 100644 --- a/drivers/net/3c503.c +++ b/drivers/net/3c503.c @@ -95,8 +95,6 @@ static int __init do_el2_probe(struct net_device *dev) int base_addr = dev->base_addr; int irq = dev->irq; - SET_MODULE_OWNER(dev); - if (base_addr > 0x1ff) /* Check a single specified location. */ return el2_probe1(dev, base_addr); else if (base_addr != 0) /* Don't probe at all. */ diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c index acede307c05..c05bb3fc57a 100644 --- a/drivers/net/3c505.c +++ b/drivers/net/3c505.c @@ -1387,8 +1387,6 @@ static int __init elplus_setup(struct net_device *dev) unsigned long cookie = 0; int err = -ENODEV; - SET_MODULE_OWNER(dev); - /* * setup adapter structure */ diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c index eed4299dc42..fac6edff2b8 100644 --- a/drivers/net/3c507.c +++ b/drivers/net/3c507.c @@ -327,8 +327,6 @@ struct net_device * __init el16_probe(int unit) mem_start = dev->mem_start & 15; } - SET_MODULE_OWNER(dev); - if (io > 0x1ff) /* Check a single specified location. */ err = el16_probe1(dev, io); else if (io != 0) diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index 127f60841b1..7466987d845 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -432,7 +432,6 @@ __again: return -ENOMEM; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &idev->dev); pnp_cards++; @@ -524,8 +523,6 @@ no_pnp: if (!dev) return -ENOMEM; - SET_MODULE_OWNER(dev); - netdev_boot_setup_check(dev); /* Set passed-in IRQ or I/O Addr. */ @@ -644,7 +641,6 @@ static int __init el3_mca_probe(struct device *device) return -ENOMEM; } - SET_MODULE_OWNER(dev); netdev_boot_setup_check(dev); memcpy(dev->dev_addr, phys_addr, sizeof(phys_addr)); @@ -704,8 +700,6 @@ static int __init el3_eisa_probe (struct device *device) return -ENOMEM; } - SET_MODULE_OWNER(dev); - netdev_boot_setup_check(dev); memcpy(dev->dev_addr, phys_addr, sizeof(phys_addr)); diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c index 290166d5e7d..38a2ebea9b4 100644 --- a/drivers/net/3c515.c +++ b/drivers/net/3c515.c @@ -501,8 +501,6 @@ static struct net_device *corkscrew_scan(int unit) netdev_boot_setup_check(dev); } - SET_MODULE_OWNER(dev); - #ifdef __ISAPNP__ if(nopnp == 1) goto no_pnp; diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c index ab18343e58e..10852b2a40a 100644 --- a/drivers/net/3c523.c +++ b/drivers/net/3c523.c @@ -423,7 +423,6 @@ static int __init do_elmc_probe(struct net_device *dev) int retval; struct priv *pr = dev->priv; - SET_MODULE_OWNER(dev); if (MCA_bus == 0) { return -ENODEV; } diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c index c7b571be20e..5b5f44cdfc1 100644 --- a/drivers/net/3c527.c +++ b/drivers/net/3c527.c @@ -257,8 +257,6 @@ struct net_device *__init mc32_probe(int unit) if (unit >= 0) sprintf(dev->name, "eth%d", unit); - SET_MODULE_OWNER(dev); - /* Do not check any supplied i/o locations. POS registers usually don't fail :) */ diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 29e558913eb..ad0f6a729d2 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -1036,7 +1036,6 @@ static int __devinit vortex_probe1(struct device *gendev, printk (KERN_ERR PFX "unable to allocate etherdev, aborting\n"); goto out; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, gendev); vp = netdev_priv(dev); diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index 2dec3d6ae01..30310ed9f75 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -1845,7 +1845,6 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) dev = alloc_etherdev(sizeof(struct cp_private)); if (!dev) return -ENOMEM; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); cp = netdev_priv(dev); diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index 7ba470ee217..28c1aaf1fe1 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -766,7 +766,6 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev, dev_err(&pdev->dev, "Unable to alloc new net device\n"); return -ENOMEM; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); tp = netdev_priv(dev); diff --git a/drivers/net/82596.c b/drivers/net/82596.c index d915837193c..43dffdca708 100644 --- a/drivers/net/82596.c +++ b/drivers/net/82596.c @@ -1234,7 +1234,6 @@ struct net_device * __init i82596_probe(int unit) DEB(DEB_PROBE,printk(KERN_INFO "%s", version)); /* The 82596-specific entries in the device structure. */ - SET_MODULE_OWNER(dev); dev->open = i596_open; dev->stop = i596_close; dev->hard_start_xmit = i596_start_xmit; diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c index a45de6975bf..fa0c6cb3d79 100644 --- a/drivers/net/a2065.c +++ b/drivers/net/a2065.c @@ -746,7 +746,6 @@ static int __devinit a2065_init_one(struct zorro_dev *z, return -ENOMEM; } - SET_MODULE_OWNER(dev); priv = netdev_priv(dev); r1->name = dev->name; diff --git a/drivers/net/ac3200.c b/drivers/net/ac3200.c index 644c408515d..65b2de56ed2 100644 --- a/drivers/net/ac3200.c +++ b/drivers/net/ac3200.c @@ -103,8 +103,6 @@ static int __init do_ac3200_probe(struct net_device *dev) int irq = dev->irq; int mem_start = dev->mem_start; - SET_MODULE_OWNER(dev); - if (ioaddr > 0x1ff) /* Check a single specified location. */ return ac_probe1(ioaddr, dev); else if (ioaddr > 0) /* Don't probe at all. */ diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c index 62e660a7938..ca00f41e4d8 100644 --- a/drivers/net/acenic.c +++ b/drivers/net/acenic.c @@ -465,7 +465,6 @@ static int __devinit acenic_probe_one(struct pci_dev *pdev, return -ENOMEM; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); ap = dev->priv; diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c index cf06fc067e9..afb60a5927a 100644 --- a/drivers/net/amd8111e.c +++ b/drivers/net/amd8111e.c @@ -1982,7 +1982,6 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev, goto err_free_reg; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); #if AMD8111E_VLAN_TAG_USED diff --git a/drivers/net/apne.c b/drivers/net/apne.c index 954191119d3..b073810f9fd 100644 --- a/drivers/net/apne.c +++ b/drivers/net/apne.c @@ -148,7 +148,6 @@ struct net_device * __init apne_probe(int unit) sprintf(dev->name, "eth%d", unit); netdev_boot_setup_check(dev); } - SET_MODULE_OWNER(dev); /* disable pcmcia irq for readtuple */ pcmcia_disable_irq(); diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c index da6ffa8cd81..c4b560d42a6 100644 --- a/drivers/net/appletalk/cops.c +++ b/drivers/net/appletalk/cops.c @@ -235,8 +235,6 @@ struct net_device * __init cops_probe(int unit) base_addr = dev->base_addr = io; } - SET_MODULE_OWNER(dev); - if (base_addr > 0x1ff) { /* Check a single specified location. */ err = cops_probe1(dev, base_addr); } else if (base_addr != 0) { /* Don't probe at all. */ diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c index f22e46dfd77..56cb9679402 100644 --- a/drivers/net/appletalk/ipddp.c +++ b/drivers/net/appletalk/ipddp.c @@ -65,7 +65,6 @@ static struct net_device * __init ipddp_init(void) if (!dev) return ERR_PTR(-ENOMEM); - SET_MODULE_OWNER(dev); strcpy(dev->name, "ipddp%d"); if (version_printed++ == 0) diff --git a/drivers/net/appletalk/ltpc.c b/drivers/net/appletalk/ltpc.c index 6a6cbd331a1..cb4744e5690 100644 --- a/drivers/net/appletalk/ltpc.c +++ b/drivers/net/appletalk/ltpc.c @@ -1046,8 +1046,6 @@ struct net_device * __init ltpc_probe(void) if (!dev) goto out; - SET_MODULE_OWNER(dev); - /* probe for the I/O port address */ if (io != 0x240 && request_region(0x220,8,"ltpc")) { diff --git a/drivers/net/arcnet/com90io.c b/drivers/net/arcnet/com90io.c index 1f030273541..6599f1046c7 100644 --- a/drivers/net/arcnet/com90io.c +++ b/drivers/net/arcnet/com90io.c @@ -398,8 +398,6 @@ static int __init com90io_init(void) if (!dev) return -ENOMEM; - SET_MODULE_OWNER(dev); - dev->base_addr = io; dev->irq = irq; if (dev->irq == 2) diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c index bc5a38a6705..2c020a36177 100644 --- a/drivers/net/ariadne.c +++ b/drivers/net/ariadne.c @@ -183,7 +183,6 @@ static int __devinit ariadne_init_one(struct zorro_dev *z, return -ENOMEM; } - SET_MODULE_OWNER(dev); priv = netdev_priv(dev); r1->name = dev->name; diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c index ef2cc80256a..619810a01e5 100644 --- a/drivers/net/arm/at91_ether.c +++ b/drivers/net/arm/at91_ether.c @@ -986,7 +986,6 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add dev->base_addr = AT91_VA_BASE_EMAC; dev->irq = AT91RM9200_ID_EMAC; - SET_MODULE_OWNER(dev); /* Install the interrupt handler */ if (request_irq(dev->irq, at91ether_interrupt, 0, dev->name, dev)) { diff --git a/drivers/net/arm/ether1.c b/drivers/net/arm/ether1.c index 80f33b6d571..6ec8a587c1d 100644 --- a/drivers/net/arm/ether1.c +++ b/drivers/net/arm/ether1.c @@ -1009,7 +1009,6 @@ ether1_probe(struct expansion_card *ec, const struct ecard_id *id) goto release; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &ec->dev); dev->irq = ec->irq; diff --git a/drivers/net/arm/ether3.c b/drivers/net/arm/ether3.c index 3805506a3ab..4a914748c0e 100644 --- a/drivers/net/arm/ether3.c +++ b/drivers/net/arm/ether3.c @@ -789,7 +789,6 @@ ether3_probe(struct expansion_card *ec, const struct ecard_id *id) goto release; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &ec->dev); priv(dev)->base = ecardm_iomap(ec, ECARD_RES_MEMC, 0, 0); diff --git a/drivers/net/arm/etherh.c b/drivers/net/arm/etherh.c index 0d37d9d1fd7..5d093b3ddcd 100644 --- a/drivers/net/arm/etherh.c +++ b/drivers/net/arm/etherh.c @@ -661,7 +661,6 @@ etherh_probe(struct expansion_card *ec, const struct ecard_id *id) goto release; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &ec->dev); dev->open = etherh_open; diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c index bed8e0ebaf1..d20148e69fa 100644 --- a/drivers/net/at1700.c +++ b/drivers/net/at1700.c @@ -225,8 +225,6 @@ struct net_device * __init at1700_probe(int unit) dev->irq = irq; } - SET_MODULE_OWNER(dev); - if (io > 0x1ff) { /* Check a single specified location. */ err = at1700_probe1(dev, io); } else if (io != 0) { /* Don't probe at all. */ diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c index dfa8b9ba4c8..97cca505cf9 100644 --- a/drivers/net/atarilance.c +++ b/drivers/net/atarilance.c @@ -390,7 +390,6 @@ struct net_device * __init atarilance_probe(int unit) sprintf(dev->name, "eth%d", unit); netdev_boot_setup_check(dev); } - SET_MODULE_OWNER(dev); for( i = 0; i < N_LANCE_ADDR; ++i ) { if (lance_probe1( dev, &lance_addr_list[i] )) { diff --git a/drivers/net/atl1/atl1_main.c b/drivers/net/atl1/atl1_main.c index 469ff95be55..e1a9223d0c1 100644 --- a/drivers/net/atl1/atl1_main.c +++ b/drivers/net/atl1/atl1_main.c @@ -2234,7 +2234,6 @@ static int __devinit atl1_probe(struct pci_dev *pdev, err = -ENOMEM; goto err_alloc_etherdev; } - SET_MODULE_OWNER(netdev); SET_NETDEV_DEV(netdev, &pdev->dev); pci_set_drvdata(pdev, netdev); diff --git a/drivers/net/atp.c b/drivers/net/atp.c index 82d78ff8399..6020d5ec38b 100644 --- a/drivers/net/atp.c +++ b/drivers/net/atp.c @@ -299,7 +299,6 @@ static int __init atp_probe1(long ioaddr) dev = alloc_etherdev(sizeof(struct net_local)); if (!dev) return -ENOMEM; - SET_MODULE_OWNER(dev); /* Find the IRQ used by triggering an interrupt. */ write_reg_byte(ioaddr, CMR2, 0x01); /* No accept mode, IRQ out. */ diff --git a/drivers/net/b44.c b/drivers/net/b44.c index b92b3e25c42..6d193705a3b 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -2151,7 +2151,6 @@ static int __devinit b44_init_one(struct pci_dev *pdev, goto err_out_free_res; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev,&pdev->dev); /* No interesting netdevice features in this card... */ diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c index 3354c534335..e5bbcbe8de5 100644 --- a/drivers/net/bfin_mac.c +++ b/drivers/net/bfin_mac.c @@ -941,7 +941,6 @@ static int bfin_mac_probe(struct platform_device *pdev) return -ENOMEM; } - SET_MODULE_OWNER(ndev); SET_NETDEV_DEV(ndev, &pdev->dev); platform_set_drvdata(pdev, ndev); diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c index 1eb95b60300..ee157f5a5db 100644 --- a/drivers/net/bmac.c +++ b/drivers/net/bmac.c @@ -1291,7 +1291,6 @@ static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_device_i } bp = netdev_priv(dev); - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &mdev->ofdev.dev); macio_set_drvdata(mdev, dev); diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index ab028ad0423..61debba873a 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -6474,7 +6474,6 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) u32 reg; u64 dma_mask, persist_dma_mask; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); bp = netdev_priv(dev); diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 559fe9437e0..88ff72ac9b0 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4674,8 +4674,6 @@ int bond_create(char *name, struct bond_params *params, struct bonding **newbond goto out_netdev; } - SET_MODULE_OWNER(bond_dev); - res = register_netdevice(bond_dev); if (res < 0) { goto out_bond; diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c index 13f14df21e6..f44f3d2a4b4 100644 --- a/drivers/net/cassini.c +++ b/drivers/net/cassini.c @@ -4900,7 +4900,6 @@ static int __devinit cas_init_one(struct pci_dev *pdev, err = -ENOMEM; goto err_out_disable_pdev; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); err = pci_request_regions(pdev, dev->name); diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c index 593736c7550..884aa0cd000 100644 --- a/drivers/net/chelsio/cxgb2.c +++ b/drivers/net/chelsio/cxgb2.c @@ -1036,7 +1036,6 @@ static int __devinit init_one(struct pci_dev *pdev, goto out_free_dev; } - SET_MODULE_OWNER(netdev); SET_NETDEV_DEV(netdev, &pdev->dev); if (!adapter) { diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c index 9774bb1b3e8..2b4c9219391 100644 --- a/drivers/net/cs89x0.c +++ b/drivers/net/cs89x0.c @@ -517,7 +517,6 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) int eeprom_buff[CHKSUM_LEN]; int retval; - SET_MODULE_OWNER(dev); /* Initialize the device structure. */ if (!modular) { memset(lp, 0, sizeof(*lp)); diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index a6723ae79bd..19937498589 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -2465,7 +2465,6 @@ static int __devinit init_one(struct pci_dev *pdev, goto out_free_dev; } - SET_MODULE_OWNER(netdev); SET_NETDEV_DEV(netdev, &pdev->dev); adapter->port[i] = netdev; diff --git a/drivers/net/de600.c b/drivers/net/de600.c index dae97b860da..5dd0d9c0eac 100644 --- a/drivers/net/de600.c +++ b/drivers/net/de600.c @@ -394,7 +394,6 @@ static struct net_device * __init de600_probe(void) if (!dev) return ERR_PTR(-ENOMEM); - SET_MODULE_OWNER(dev); if (!request_region(DE600_IO, 3, "de600")) { printk(KERN_WARNING "DE600: port 0x%x busy\n", DE600_IO); diff --git a/drivers/net/de620.c b/drivers/net/de620.c index dc489242617..a92c207b883 100644 --- a/drivers/net/de620.c +++ b/drivers/net/de620.c @@ -823,8 +823,6 @@ struct net_device * __init de620_probe(int unit) if (!dev) goto out; - SET_MODULE_OWNER(dev); - spin_lock_init(&de620_lock); /* diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c index 9c8e3f9f5e5..b07613e61f5 100644 --- a/drivers/net/defxx.c +++ b/drivers/net/defxx.c @@ -539,7 +539,6 @@ static int __devinit dfx_register(struct device *bdev) goto err_out; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, bdev); bp = netdev_priv(dev); diff --git a/drivers/net/dgrs.c b/drivers/net/dgrs.c index df62c0232f3..ddedb76303d 100644 --- a/drivers/net/dgrs.c +++ b/drivers/net/dgrs.c @@ -1272,7 +1272,6 @@ dgrs_found_device( priv->chan = 1; priv->devtbl[0] = dev; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, pdev); ret = dgrs_probe1(dev); @@ -1320,7 +1319,6 @@ dgrs_found_device( if (ret) goto fail; - SET_MODULE_OWNER(devN); SET_NETDEV_DEV(dev, pdev); ret = register_netdev(devN); diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c index ca21a1888ff..12486e13b85 100644 --- a/drivers/net/dl2k.c +++ b/drivers/net/dl2k.c @@ -116,7 +116,6 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent) err = -ENOMEM; goto err_out_res; } - SET_MODULE_OWNER (dev); SET_NETDEV_DEV(dev, &pdev->dev); #ifdef MEM_MAPPING diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index 738aa590651..857eb366bb1 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -416,7 +416,6 @@ dm9000_probe(struct platform_device *pdev) return -ENOMEM; } - SET_MODULE_OWNER(ndev); SET_NETDEV_DEV(ndev, &pdev->dev); PRINTK2("dm9000_probe()"); diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c index 756a6bcb038..84e14f397d9 100644 --- a/drivers/net/dummy.c +++ b/drivers/net/dummy.c @@ -71,7 +71,6 @@ static void dummy_setup(struct net_device *dev) dev->change_mtu = NULL; dev->flags |= IFF_NOARP; dev->flags &= ~IFF_MULTICAST; - SET_MODULE_OWNER(dev); random_ether_addr(dev->dev_addr); } diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 10907f158ba..f9aa13e04ad 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -2604,7 +2604,6 @@ static int __devinit e100_probe(struct pci_dev *pdev, goto err_out_free_res; } - SET_MODULE_OWNER(netdev); SET_NETDEV_DEV(netdev, &pdev->dev); if (use_io) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 723568d6e44..7befb706ad5 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -897,7 +897,6 @@ e1000_probe(struct pci_dev *pdev, if (!netdev) goto err_alloc_etherdev; - SET_MODULE_OWNER(netdev); SET_NETDEV_DEV(netdev, &pdev->dev); pci_set_drvdata(pdev, netdev); diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index eeb40ccbcb2..885d9467f40 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -4040,7 +4040,6 @@ static int __devinit e1000_probe(struct pci_dev *pdev, if (!netdev) goto err_alloc_etherdev; - SET_MODULE_OWNER(netdev); SET_NETDEV_DEV(netdev, &pdev->dev); pci_set_drvdata(pdev, netdev); diff --git a/drivers/net/e2100.c b/drivers/net/e2100.c index b2b0a96218c..6390f51ea6f 100644 --- a/drivers/net/e2100.c +++ b/drivers/net/e2100.c @@ -124,8 +124,6 @@ static int __init do_e2100_probe(struct net_device *dev) int base_addr = dev->base_addr; int irq = dev->irq; - SET_MODULE_OWNER(dev); - if (base_addr > 0x1ff) /* Check a single specified location. */ return e21_probe1(dev, base_addr); else if (base_addr != 0) /* Don't probe at all. */ diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c index 47680237f78..6eb84f14c88 100644 --- a/drivers/net/eepro.c +++ b/drivers/net/eepro.c @@ -537,8 +537,6 @@ static int __init do_eepro_probe(struct net_device *dev) int base_addr = dev->base_addr; int irq = dev->irq; - SET_MODULE_OWNER(dev); - #ifdef PnPWakeup /* XXXX for multiple cards should this only be run once? */ @@ -594,8 +592,6 @@ struct net_device * __init eepro_probe(int unit) if (!dev) return ERR_PTR(-ENODEV); - SET_MODULE_OWNER(dev); - sprintf(dev->name, "eth%d", unit); netdev_boot_setup_check(dev); diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c index 3c54014acec..f8b69ceb2be 100644 --- a/drivers/net/eepro100.c +++ b/drivers/net/eepro100.c @@ -635,7 +635,6 @@ static int __devinit speedo_found1(struct pci_dev *pdev, return -1; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); if (dev->mem_start > 0) diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c index 7934ea37f94..6c91bfa72bb 100644 --- a/drivers/net/eexpress.c +++ b/drivers/net/eexpress.c @@ -341,8 +341,6 @@ static int __init do_express_probe(struct net_device *dev) int dev_irq = dev->irq; int err; - SET_MODULE_OWNER(dev); - dev->if_port = 0xff; /* not set */ #ifdef CONFIG_MCA_LEGACY diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index b8e00391a5e..62d6c1e5f9d 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -2710,8 +2710,6 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter, SET_NETDEV_DEV(dev, port_dev); /* initialize net_device structure */ - SET_MODULE_OWNER(dev); - memcpy(dev->dev_addr, &port->mac_addr, ETH_ALEN); dev->open = ehea_open; diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index f8446e373bd..122ffd2f082 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -352,7 +352,6 @@ static int __devinit epic_init_one (struct pci_dev *pdev, dev_err(&pdev->dev, "no memory for eth device\n"); goto err_out_free_res; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); #ifdef USE_IO_OPS diff --git a/drivers/net/eql.c b/drivers/net/eql.c index f1cc66dcbdf..7266f6dbdd9 100644 --- a/drivers/net/eql.c +++ b/drivers/net/eql.c @@ -167,8 +167,6 @@ static void __init eql_setup(struct net_device *dev) { equalizer_t *eql = netdev_priv(dev); - SET_MODULE_OWNER(dev); - init_timer(&eql->timer); eql->timer.data = (unsigned long) eql; eql->timer.expires = jiffies + EQL_DEFAULT_RESCHED_IVAL; diff --git a/drivers/net/es3210.c b/drivers/net/es3210.c index 822e5bfd1a7..238fa8aff02 100644 --- a/drivers/net/es3210.c +++ b/drivers/net/es3210.c @@ -130,8 +130,6 @@ static int __init do_es_probe(struct net_device *dev) int irq = dev->irq; int mem_start = dev->mem_start; - SET_MODULE_OWNER(dev); - if (ioaddr > 0x1ff) /* Check a single specified location. */ return es_probe1(dev, ioaddr); else if (ioaddr > 0) /* Don't probe at all. */ diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c index 04abf59e500..0e3b33717ca 100644 --- a/drivers/net/eth16i.c +++ b/drivers/net/eth16i.c @@ -436,8 +436,6 @@ static int __init do_eth16i_probe(struct net_device *dev) int ioaddr; int base_addr = dev->base_addr; - SET_MODULE_OWNER(dev); - if(eth16i_debug > 4) printk(KERN_DEBUG "Probing started for %s\n", cardname); diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c index cb0792c187b..6a5d0436e89 100644 --- a/drivers/net/ewrk3.c +++ b/drivers/net/ewrk3.c @@ -356,7 +356,6 @@ struct net_device * __init ewrk3_probe(int unit) sprintf(dev->name, "eth%d", unit); netdev_boot_setup_check(dev); } - SET_MODULE_OWNER(dev); err = ewrk3_probe1(dev, dev->base_addr, dev->irq); if (err) diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c index ff9f177d715..e9353072a96 100644 --- a/drivers/net/fealnx.c +++ b/drivers/net/fealnx.c @@ -527,7 +527,6 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev, err = -ENOMEM; goto err_out_unmap; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); /* read ethernet id */ diff --git a/drivers/net/fec_8xx/fec_main.c b/drivers/net/fec_8xx/fec_main.c index 6348fb93ca9..6f214ab12ff 100644 --- a/drivers/net/fec_8xx/fec_main.c +++ b/drivers/net/fec_8xx/fec_main.c @@ -1103,7 +1103,6 @@ int fec_8xx_init_one(const struct fec_platform_info *fpi, err = -ENOMEM; goto err; } - SET_MODULE_OWNER(dev); fep = netdev_priv(dev); fep->dev = dev; diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 24c1294614f..050a8f14eda 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -5004,7 +5004,6 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i np->dev = dev; np->pci_dev = pci_dev; spin_lock_init(&np->lock); - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pci_dev->dev); init_timer(&np->oom_kick); diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index 2812b524eda..f6789a8db8c 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -953,7 +953,6 @@ static struct net_device *fs_init_instance(struct device *dev, err = -ENOMEM; goto err; } - SET_MODULE_OWNER(ndev); fep = netdev_priv(ndev); diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index bd2de325bbd..002f8baaab2 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -254,7 +254,6 @@ static int gfar_probe(struct platform_device *pdev) /* Set the dev->base_addr to the gfar reg region */ dev->base_addr = (unsigned long) (priv->regs); - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); /* Fill in the dev structure */ diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c index 15254dc7876..da12b3db023 100644 --- a/drivers/net/hamachi.c +++ b/drivers/net/hamachi.c @@ -613,7 +613,6 @@ static int __devinit hamachi_init_one (struct pci_dev *pdev, if (!dev) goto err_out_iounmap; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); #ifdef TX_CHECKSUM diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index 760d04a671f..0a847326a5e 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -345,8 +345,6 @@ static void sp_setup(struct net_device *dev) memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN); memcpy(dev->dev_addr, &ax25_defaddr, AX25_ADDR_LEN); - SET_MODULE_OWNER(dev); - dev->flags = 0; } diff --git a/drivers/net/hp-plus.c b/drivers/net/hp-plus.c index 99a36cc3f8d..8d4f810fa28 100644 --- a/drivers/net/hp-plus.c +++ b/drivers/net/hp-plus.c @@ -122,8 +122,6 @@ static int __init do_hpp_probe(struct net_device *dev) int base_addr = dev->base_addr; int irq = dev->irq; - SET_MODULE_OWNER(dev); - if (base_addr > 0x1ff) /* Check a single specified location. */ return hpp_probe1(dev, base_addr); else if (base_addr != 0) /* Don't probe at all. */ diff --git a/drivers/net/hp.c b/drivers/net/hp.c index 635b13c2e2a..1f11126de35 100644 --- a/drivers/net/hp.c +++ b/drivers/net/hp.c @@ -86,8 +86,6 @@ static int __init do_hp_probe(struct net_device *dev) int base_addr = dev->base_addr; int irq = dev->irq; - SET_MODULE_OWNER(dev); - if (base_addr > 0x1ff) /* Check a single specified location. */ return hp_probe1(dev, base_addr); else if (base_addr != 0) /* Don't probe at all. */ diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c index 8caa591c564..406d6525e22 100644 --- a/drivers/net/hp100.c +++ b/drivers/net/hp100.c @@ -404,8 +404,6 @@ struct net_device * __init hp100_probe(int unit) if (!dev) return ERR_PTR(-ENODEV); - SET_MODULE_OWNER(dev); - #ifdef HP100_DEBUG_B hp100_outw(0x4200, TRACE); printk("hp100: %s: probe\n", dev->name); @@ -2843,7 +2841,6 @@ static int __init hp100_eisa_probe (struct device *gendev) if (!dev) return -ENOMEM; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &edev->dev); err = hp100_probe1(dev, edev->base_addr + 0xC38, HP100_BUS_EISA, NULL); @@ -2896,7 +2893,6 @@ static int __devinit hp100_pci_probe (struct pci_dev *pdev, goto out0; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); pci_read_config_word(pdev, PCI_COMMAND, &pci_command); @@ -2993,7 +2989,6 @@ static int __init hp100_isa_init(void) return -ENOMEM; } - SET_MODULE_OWNER(dev); err = hp100_isa_probe(dev, hp100_port[i]); if (!err) diff --git a/drivers/net/hydra.c b/drivers/net/hydra.c index f970bfbb9db..31300a9dd96 100644 --- a/drivers/net/hydra.c +++ b/drivers/net/hydra.c @@ -112,7 +112,6 @@ static int __devinit hydra_init(struct zorro_dev *z) dev = ____alloc_ei_netdev(0); if (!dev) return -ENOMEM; - SET_MODULE_OWNER(dev); for(j = 0; j < ETHER_ADDR_LEN; j++) dev->dev_addr[j] = *((u8 *)(board + HYDRA_ADDRPROM + 2*j)); diff --git a/drivers/net/ibm_emac/ibm_emac_core.c b/drivers/net/ibm_emac/ibm_emac_core.c index f752e5fc65b..354616b0b57 100644 --- a/drivers/net/ibm_emac/ibm_emac_core.c +++ b/drivers/net/ibm_emac/ibm_emac_core.c @@ -1962,7 +1962,6 @@ static int __init emac_probe(struct ocp_device *ocpdev) dev->ndev = ndev; dev->ldev = &ocpdev->dev; dev->def = ocpdev->def; - SET_MODULE_OWNER(ndev); /* Find MAL device we are connected to */ maldev = diff --git a/drivers/net/ibmlana.c b/drivers/net/ibmlana.c index fe85d6fcba3..67d82fa7659 100644 --- a/drivers/net/ibmlana.c +++ b/drivers/net/ibmlana.c @@ -907,8 +907,6 @@ static int ibmlana_probe(struct net_device *dev) ibmlana_priv *priv; ibmlana_medium medium; - SET_MODULE_OWNER(dev); - /* can't work without an MCA bus ;-) */ if (MCA_bus == 0) return -ENODEV; diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 2dff9f2800c..db908c40dbe 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -1142,8 +1142,6 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ if(!netdev) return -ENOMEM; - SET_MODULE_OWNER(netdev); - adapter = netdev->priv; dev->dev.driver_data = netdev; @@ -1258,7 +1256,6 @@ static void ibmveth_proc_register_driver(void) { ibmveth_proc_dir = proc_mkdir(IBMVETH_PROC_DIR, init_net.proc_net); if (ibmveth_proc_dir) { - SET_MODULE_OWNER(ibmveth_proc_dir); } } @@ -1356,7 +1353,6 @@ static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter) } else { entry->data = (void *) adapter; entry->proc_fops = &ibmveth_proc_fops; - SET_MODULE_OWNER(entry); } } return; diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c index b06c6db4383..448e618b697 100644 --- a/drivers/net/ifb.c +++ b/drivers/net/ifb.c @@ -152,7 +152,6 @@ static void ifb_setup(struct net_device *dev) dev->change_mtu = NULL; dev->flags |= IFF_NOARP; dev->flags &= ~IFF_MULTICAST; - SET_MODULE_OWNER(dev); random_ether_addr(dev->dev_addr); } diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c index c030030e586..05d2bc15144 100644 --- a/drivers/net/ioc3-eth.c +++ b/drivers/net/ioc3-eth.c @@ -1273,7 +1273,6 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (err) goto out_free; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); ip = netdev_priv(dev); diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c index f9c889c0dd0..9f584521304 100644 --- a/drivers/net/irda/ali-ircc.c +++ b/drivers/net/irda/ali-ircc.c @@ -360,10 +360,6 @@ static int ali_ircc_open(int i, chipio_t *info) self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0; self->tx_fifo.tail = self->tx_buff.head; - - /* Keep track of module usage */ - SET_MODULE_OWNER(dev); - /* Override the network functions we need to use */ dev->hard_start_xmit = ali_ircc_sir_hard_xmit; dev->open = ali_ircc_net_open; diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c index 3ca47bf6dfe..3e5eca1aa98 100644 --- a/drivers/net/irda/donauboe.c +++ b/drivers/net/irda/donauboe.c @@ -1660,7 +1660,6 @@ toshoboe_open (struct pci_dev *pci_dev, const struct pci_device_id *pdid) } #endif - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pci_dev->dev); dev->hard_start_xmit = toshoboe_hard_xmit; dev->open = toshoboe_net_open; diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c index 3b0fd83fa26..c6355c00fd7 100644 --- a/drivers/net/irda/irda-usb.c +++ b/drivers/net/irda/irda-usb.c @@ -1635,7 +1635,6 @@ static int irda_usb_probe(struct usb_interface *intf, if (!net) goto err_out; - SET_MODULE_OWNER(net); SET_NETDEV_DEV(net, &intf->dev); self = net->priv; self->netdev = net; diff --git a/drivers/net/irda/irport.c b/drivers/net/irda/irport.c index 20732458f5a..c79caa5d3d7 100644 --- a/drivers/net/irda/irport.c +++ b/drivers/net/irda/irport.c @@ -175,8 +175,6 @@ irport_open(int i, unsigned int iobase, unsigned int irq) self->tx_buff.data = self->tx_buff.head; self->netdev = dev; - /* Keep track of module usage */ - SET_MODULE_OWNER(dev); /* May be overridden by piggyback drivers */ self->interrupt = irport_interrupt; diff --git a/drivers/net/irda/kingsun-sir.c b/drivers/net/irda/kingsun-sir.c index a4adb74cccd..648e54b3f00 100644 --- a/drivers/net/irda/kingsun-sir.c +++ b/drivers/net/irda/kingsun-sir.c @@ -487,7 +487,6 @@ static int kingsun_probe(struct usb_interface *intf, if(!net) goto err_out1; - SET_MODULE_OWNER(net); SET_NETDEV_DEV(net, &intf->dev); kingsun = netdev_priv(net); kingsun->irlap = NULL; diff --git a/drivers/net/irda/ks959-sir.c b/drivers/net/irda/ks959-sir.c index 407afba1a59..8c257a51341 100644 --- a/drivers/net/irda/ks959-sir.c +++ b/drivers/net/irda/ks959-sir.c @@ -697,7 +697,6 @@ static int ks959_probe(struct usb_interface *intf, if (!net) goto err_out1; - SET_MODULE_OWNER(net); SET_NETDEV_DEV(net, &intf->dev); kingsun = netdev_priv(net); kingsun->netdev = net; diff --git a/drivers/net/irda/ksdazzle-sir.c b/drivers/net/irda/ksdazzle-sir.c index 12b0e7a15be..af60f2435a3 100644 --- a/drivers/net/irda/ksdazzle-sir.c +++ b/drivers/net/irda/ksdazzle-sir.c @@ -628,7 +628,6 @@ static int ksdazzle_probe(struct usb_interface *intf, if (!net) goto err_out1; - SET_MODULE_OWNER(net); SET_NETDEV_DEV(net, &intf->dev); kingsun = netdev_priv(net); kingsun->netdev = net; diff --git a/drivers/net/irda/mcs7780.c b/drivers/net/irda/mcs7780.c index bfc57525bd6..808939b9f8f 100644 --- a/drivers/net/irda/mcs7780.c +++ b/drivers/net/irda/mcs7780.c @@ -898,8 +898,6 @@ static int mcs_probe(struct usb_interface *intf, IRDA_DEBUG(1, "MCS7780 USB-IrDA bridge found at %d.\n", udev->devnum); - /* what is it realy for? */ - SET_MODULE_OWNER(ndev); SET_NETDEV_DEV(ndev, &intf->dev); ret = usb_reset_configuration(udev); diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c index d96c89751a7..12b9378c587 100644 --- a/drivers/net/irda/nsc-ircc.c +++ b/drivers/net/irda/nsc-ircc.c @@ -437,7 +437,6 @@ static int __init nsc_ircc_open(chipio_t *info) self->tx_fifo.tail = self->tx_buff.head; /* Override the network functions we need to use */ - SET_MODULE_OWNER(dev); dev->hard_start_xmit = nsc_ircc_hard_xmit_sir; dev->open = nsc_ircc_net_open; dev->stop = nsc_ircc_net_close; diff --git a/drivers/net/irda/sir_dev.c b/drivers/net/irda/sir_dev.c index 9d6c8f391b2..bbe4e094c42 100644 --- a/drivers/net/irda/sir_dev.c +++ b/drivers/net/irda/sir_dev.c @@ -913,8 +913,6 @@ struct sir_dev * sirdev_get_instance(const struct sir_driver *drv, const char *n dev->drv = drv; dev->netdev = ndev; - SET_MODULE_OWNER(ndev); - /* Override the network functions we need to use */ ndev->hard_start_xmit = sirdev_hard_xmit; ndev->open = sirdev_open; diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c index 36ab98386be..029fdde2a4d 100644 --- a/drivers/net/irda/smsc-ircc2.c +++ b/drivers/net/irda/smsc-ircc2.c @@ -519,8 +519,6 @@ static int __init smsc_ircc_open(unsigned int fir_base, unsigned int sir_base, u goto err_out1; } - SET_MODULE_OWNER(dev); - dev->hard_start_xmit = smsc_ircc_hard_xmit_sir; #if SMSC_IRCC2_C_NET_TIMEOUT dev->tx_timeout = smsc_ircc_timeout; diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c index 755aa444a4d..1afaee0fa7e 100644 --- a/drivers/net/irda/stir4200.c +++ b/drivers/net/irda/stir4200.c @@ -1034,7 +1034,6 @@ static int stir_probe(struct usb_interface *intf, if(!net) goto err_out1; - SET_MODULE_OWNER(net); SET_NETDEV_DEV(net, &intf->dev); stir = netdev_priv(net); stir->netdev = net; diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c index ff5358574d0..126ec7c8680 100644 --- a/drivers/net/irda/via-ircc.c +++ b/drivers/net/irda/via-ircc.c @@ -429,9 +429,6 @@ static __devinit int via_ircc_open(int i, chipio_t * info, unsigned int id) self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0; self->tx_fifo.tail = self->tx_buff.head; - /* Keep track of module usage */ - SET_MODULE_OWNER(dev); - /* Override the network functions we need to use */ dev->hard_start_xmit = via_ircc_hard_xmit_sir; dev->open = via_ircc_net_open; diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c index 0538ca9ce05..acd082a96a4 100644 --- a/drivers/net/irda/vlsi_ir.c +++ b/drivers/net/irda/vlsi_ir.c @@ -1584,8 +1584,6 @@ static int vlsi_irda_init(struct net_device *ndev) vlsi_irda_dev_t *idev = ndev->priv; struct pci_dev *pdev = idev->pdev; - SET_MODULE_OWNER(ndev); - ndev->irq = pdev->irq; ndev->base_addr = pci_resource_start(pdev,0); diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c index 5182e800cc1..9fd2451b0fb 100644 --- a/drivers/net/irda/w83977af_ir.c +++ b/drivers/net/irda/w83977af_ir.c @@ -232,9 +232,6 @@ int w83977af_open(int i, unsigned int iobase, unsigned int irq, self->rx_buff.data = self->rx_buff.head; self->netdev = dev; - /* Keep track of module usage */ - SET_MODULE_OWNER(dev); - /* Override the network functions we need to use */ dev->hard_start_xmit = w83977af_hard_xmit; dev->open = w83977af_net_open; diff --git a/drivers/net/isa-skeleton.c b/drivers/net/isa-skeleton.c index 0343f12d2ff..54178111eec 100644 --- a/drivers/net/isa-skeleton.c +++ b/drivers/net/isa-skeleton.c @@ -133,8 +133,6 @@ static int __init do_netcard_probe(struct net_device *dev) int base_addr = dev->base_addr; int irq = dev->irq; - SET_MODULE_OWNER(dev); - if (base_addr > 0x1ff) /* Check a single specified location. */ return netcard_probe1(dev, base_addr); else if (base_addr != 0) /* Don't probe at all. */ diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index e3f27c67fb2..d444de58ba3 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -382,7 +382,6 @@ ixgb_probe(struct pci_dev *pdev, goto err_alloc_etherdev; } - SET_MODULE_OWNER(netdev); SET_NETDEV_DEV(netdev, &pdev->dev); pci_set_drvdata(pdev, netdev); diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index a08a46224c2..b75f1c6efc4 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -2548,7 +2548,6 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, goto err_alloc_etherdev; } - SET_MODULE_OWNER(netdev); SET_NETDEV_DEV(netdev, &pdev->dev); pci_set_drvdata(pdev, netdev); diff --git a/drivers/net/ixp2000/enp2611.c b/drivers/net/ixp2000/enp2611.c index d3f4235c585..b02a981c87a 100644 --- a/drivers/net/ixp2000/enp2611.c +++ b/drivers/net/ixp2000/enp2611.c @@ -210,7 +210,6 @@ static int __init enp2611_init_module(void) return -ENOMEM; } - SET_MODULE_OWNER(nds[i]); nds[i]->get_stats = enp2611_get_stats; pm3386_init_port(i); pm3386_get_mac(i, nds[i]->dev_addr); diff --git a/drivers/net/jazzsonic.c b/drivers/net/jazzsonic.c index b71e6633f42..13847a3e43e 100644 --- a/drivers/net/jazzsonic.c +++ b/drivers/net/jazzsonic.c @@ -221,7 +221,6 @@ static int __init jazz_sonic_probe(struct platform_device *pdev) lp = netdev_priv(dev); lp->device = &pdev->dev; SET_NETDEV_DEV(dev, &pdev->dev); - SET_MODULE_OWNER(dev); netdev_boot_setup_check(dev); diff --git a/drivers/net/lance.c b/drivers/net/lance.c index a4e5fab1262..7b17212d687 100644 --- a/drivers/net/lance.c +++ b/drivers/net/lance.c @@ -521,7 +521,6 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int /* We can't allocate dev->priv from alloc_etherdev() because it must a ISA DMA-able region. */ - SET_MODULE_OWNER(dev); chipname = chip_table[lance_version].name; printk("%s: %s at %#3x,", dev->name, chipname, ioaddr); diff --git a/drivers/net/lguest_net.c b/drivers/net/lguest_net.c index cab57911a80..7f34c92bcd8 100644 --- a/drivers/net/lguest_net.c +++ b/drivers/net/lguest_net.c @@ -460,8 +460,6 @@ static int lguestnet_probe(struct lguest_device *lgdev) if (!dev) return -ENOMEM; - SET_MODULE_OWNER(dev); - /* Ethernet defaults with some changes */ ether_setup(dev); dev->set_mac_address = NULL; diff --git a/drivers/net/lne390.c b/drivers/net/lne390.c index 0a08d0c4e7b..2dd39698321 100644 --- a/drivers/net/lne390.c +++ b/drivers/net/lne390.c @@ -111,8 +111,6 @@ static int __init do_lne390_probe(struct net_device *dev) int mem_start = dev->mem_start; int ret; - SET_MODULE_OWNER(dev); - if (ioaddr > 0x1ff) { /* Check a single specified location. */ if (!request_region(ioaddr, LNE390_IO_EXTENT, DRV_NAME)) return -EBUSY; diff --git a/drivers/net/mac8390.c b/drivers/net/mac8390.c index 90b0c3ed4bb..9e700749bb3 100644 --- a/drivers/net/mac8390.c +++ b/drivers/net/mac8390.c @@ -313,8 +313,6 @@ struct net_device * __init mac8390_probe(int unit) if (unit >= 0) sprintf(dev->name, "eth%d", unit); - SET_MODULE_OWNER(dev); - while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK, NUBUS_TYPE_ETHERNET, ndev))) { /* Have we seen it already? */ if (slots & (1<board->slot)) diff --git a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c index 62c1c6262fe..f6f3fdfe41d 100644 --- a/drivers/net/mac89x0.c +++ b/drivers/net/mac89x0.c @@ -191,8 +191,6 @@ struct net_device * __init mac89x0_probe(int unit) netdev_boot_setup_check(dev); } - SET_MODULE_OWNER(dev); - if (once_is_enough) goto out; once_is_enough = 1; diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 74c3f7a7ae4..c6707580c30 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -1085,7 +1085,6 @@ static int __devinit macb_probe(struct platform_device *pdev) goto err_out; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); /* TODO: Actually, we have some interesting features... */ diff --git a/drivers/net/mace.c b/drivers/net/mace.c index 52b9332810c..de3b002e9a4 100644 --- a/drivers/net/mace.c +++ b/drivers/net/mace.c @@ -143,7 +143,6 @@ static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_i rc = -ENOMEM; goto err_release; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &mdev->ofdev.dev); mp = dev->priv; diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c index 9a343b96597..5d2daa24887 100644 --- a/drivers/net/macmace.c +++ b/drivers/net/macmace.c @@ -210,7 +210,6 @@ static int __devinit mace_probe(struct platform_device *pdev) mp->device = &pdev->dev; SET_NETDEV_DEV(dev, &pdev->dev); - SET_MODULE_OWNER(dev); dev->base_addr = (u32)MACE_BASE; mp->mace = (volatile struct mace *) MACE_BASE; diff --git a/drivers/net/macsonic.c b/drivers/net/macsonic.c index e9ecdbf352a..a55a8399344 100644 --- a/drivers/net/macsonic.c +++ b/drivers/net/macsonic.c @@ -576,7 +576,6 @@ static int __init mac_sonic_probe(struct platform_device *pdev) lp = netdev_priv(dev); lp->device = &pdev->dev; SET_NETDEV_DEV(dev, &pdev->dev); - SET_MODULE_OWNER(dev); /* This will catch fatal stuff like -ENOMEM as well as success */ err = mac_onboard_sonic_probe(dev); diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 702eba54916..6317bba9587 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -1425,7 +1425,6 @@ static int mv643xx_eth_probe(struct platform_device *pdev) mv643xx_eth_update_pscr(dev, &cmd); mv643xx_set_settings(dev, &cmd); - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); err = register_netdev(dev); if (err) diff --git a/drivers/net/mvme147.c b/drivers/net/mvme147.c index e246d00bba6..837ad0f2b05 100644 --- a/drivers/net/mvme147.c +++ b/drivers/net/mvme147.c @@ -79,8 +79,6 @@ struct net_device * __init mvme147lance_probe(int unit) if (unit >= 0) sprintf(dev->name, "eth%d", unit); - SET_MODULE_OWNER(dev); - /* Fill the dev fields */ dev->base_addr = (unsigned long)MVME147_LANCE_BASE; dev->open = &m147lance_open; diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c index 13444da9327..331b76c4956 100644 --- a/drivers/net/myri_sbus.c +++ b/drivers/net/myri_sbus.c @@ -908,7 +908,6 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev) if (version_printed++ == 0) printk(version); - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &sdev->ofdev.dev); mp = (struct myri_eth *) dev->priv; diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index 43cfa4b3e29..5ee4e8795d2 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -837,7 +837,6 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, dev = alloc_etherdev(sizeof (struct netdev_private)); if (!dev) return -ENOMEM; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); i = pci_request_regions(pdev, DRV_NAME); diff --git a/drivers/net/ne-h8300.c b/drivers/net/ne-h8300.c index 38fd525f0f1..a0f35361fbe 100644 --- a/drivers/net/ne-h8300.c +++ b/drivers/net/ne-h8300.c @@ -149,8 +149,6 @@ static int __init do_ne_probe(struct net_device *dev) { unsigned int base_addr = dev->base_addr; - SET_MODULE_OWNER(dev); - /* First check any supplied i/o locations. User knows best. */ if (base_addr > 0x1ff) /* Check a single specified location. */ return ne_probe1(dev, base_addr); diff --git a/drivers/net/ne.c b/drivers/net/ne.c index c9f74bf5f49..c81befc3a7a 100644 --- a/drivers/net/ne.c +++ b/drivers/net/ne.c @@ -191,8 +191,6 @@ static int __init do_ne_probe(struct net_device *dev) int orig_irq = dev->irq; #endif - SET_MODULE_OWNER(dev); - /* First check any supplied i/o locations. User knows best. */ if (base_addr > 0x1ff) /* Check a single specified location. */ return ne_probe1(dev, base_addr); diff --git a/drivers/net/ne2.c b/drivers/net/ne2.c index 089b5bb702f..d1a4b8d7122 100644 --- a/drivers/net/ne2.c +++ b/drivers/net/ne2.c @@ -251,8 +251,6 @@ static int __init do_ne2_probe(struct net_device *dev) int i; int adapter_found = 0; - SET_MODULE_OWNER(dev); - /* Do not check any supplied i/o locations. POS registers usually don't fail :) */ diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c index f81d9398d60..230a0f1e03f 100644 --- a/drivers/net/ne2k-pci.c +++ b/drivers/net/ne2k-pci.c @@ -265,7 +265,6 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev, dev_err(&pdev->dev, "cannot allocate ethernet device\n"); goto err_out_free_res; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); /* Reset card. Who knows what dain-bramaged state it was left in. */ diff --git a/drivers/net/ne3210.c b/drivers/net/ne3210.c index 1a6fed76d4c..b1bf8331e87 100644 --- a/drivers/net/ne3210.c +++ b/drivers/net/ne3210.c @@ -106,7 +106,6 @@ static int __init ne3210_eisa_probe (struct device *device) return -ENOMEM; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, device); device->driver_data = dev; ioaddr = edev->base_addr; diff --git a/drivers/net/netx-eth.c b/drivers/net/netx-eth.c index 2b8da0a5499..6fee405d840 100644 --- a/drivers/net/netx-eth.c +++ b/drivers/net/netx-eth.c @@ -390,7 +390,6 @@ static int netx_eth_drv_probe(struct platform_device *pdev) ret = -ENOMEM; goto exit; } - SET_MODULE_OWNER(ndev); SET_NETDEV_DEV(ndev, &pdev->dev); platform_set_drvdata(pdev, ndev); diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index dcd66a6b490..1b165a8c74f 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -325,7 +325,6 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out_free_res; } - SET_MODULE_OWNER(netdev); SET_NETDEV_DEV(netdev, &pdev->dev); adapter = netdev->priv; diff --git a/drivers/net/ni5010.c b/drivers/net/ni5010.c index 22a3b3dc7d8..cc1d09a21c0 100644 --- a/drivers/net/ni5010.c +++ b/drivers/net/ni5010.c @@ -135,8 +135,6 @@ struct net_device * __init ni5010_probe(int unit) PRINTK2((KERN_DEBUG "%s: Entering ni5010_probe\n", dev->name)); - SET_MODULE_OWNER(dev); - if (io > 0x1ff) { /* Check a single specified location. */ err = ni5010_probe1(dev, io); } else if (io != 0) { /* Don't probe at all. */ diff --git a/drivers/net/ni52.c b/drivers/net/ni52.c index 5e7999db209..6b3384a24f0 100644 --- a/drivers/net/ni52.c +++ b/drivers/net/ni52.c @@ -382,8 +382,6 @@ struct net_device * __init ni52_probe(int unit) memend = dev->mem_end; } - SET_MODULE_OWNER(dev); - if (io > 0x1ff) { /* Check a single specified location. */ err = ni52_probe1(dev, io); } else if (io > 0) { /* Don't probe at all. */ diff --git a/drivers/net/ni65.c b/drivers/net/ni65.c index 4ef5fe34519..09768524511 100644 --- a/drivers/net/ni65.c +++ b/drivers/net/ni65.c @@ -550,7 +550,6 @@ static int __init ni65_probe1(struct net_device *dev,int ioaddr) } dev->base_addr = ioaddr; - SET_MODULE_OWNER(dev); dev->open = ni65_open; dev->stop = ni65_close; dev->hard_start_xmit = ni65_send_packet; diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c index 6e65d61a3fe..de495b69729 100644 --- a/drivers/net/ns83820.c +++ b/drivers/net/ns83820.c @@ -1988,7 +1988,6 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_ spin_lock_init(&dev->misc_lock); dev->pci_dev = pci_dev; - SET_MODULE_OWNER(ndev); SET_NETDEV_DEV(ndev, &pci_dev->dev); INIT_WORK(&dev->tq_refill, queue_refill); diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 48c117038fe..723685ee57a 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -1176,7 +1176,6 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto out_disable_device; } - SET_MODULE_OWNER(dev); pci_set_drvdata(pdev, dev); SET_NETDEV_DEV(dev, &pdev->dev); diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c index 3cdbe118200..a4b16484a5f 100644 --- a/drivers/net/pci-skeleton.c +++ b/drivers/net/pci-skeleton.c @@ -604,7 +604,6 @@ static int __devinit netdrv_init_board (struct pci_dev *pdev, DPRINTK ("EXIT, returning -ENOMEM\n"); return -ENOMEM; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); tp = dev->priv; diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c index 503f2685fb7..2136c80c058 100644 --- a/drivers/net/pcmcia/3c589_cs.c +++ b/drivers/net/pcmcia/3c589_cs.c @@ -197,7 +197,6 @@ static int tc589_probe(struct pcmcia_device *link) link->conf.ConfigIndex = 1; /* The EL3-specific entries in the device structure. */ - SET_MODULE_OWNER(dev); dev->hard_start_xmit = &el3_start_xmit; dev->set_config = &el3_config; dev->get_stats = &el3_get_stats; diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index 50dff1b81d3..a9db59d2a2f 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -1728,9 +1728,6 @@ static void axdev_setup(struct net_device *dev) if (ei_debug > 1) printk(version_8390); - SET_MODULE_OWNER(dev); - - ei_local = (struct ei_device *)netdev_priv(dev); spin_lock_init(&ei_local->page_lock); diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c index 85d5f2ca4bb..7f29e95a064 100644 --- a/drivers/net/pcmcia/fmvj18x_cs.c +++ b/drivers/net/pcmcia/fmvj18x_cs.c @@ -259,7 +259,6 @@ static int fmvj18x_probe(struct pcmcia_device *link) link->conf.IntType = INT_MEMORY_AND_IO; /* The FMVJ18x specific entries in the device structure. */ - SET_MODULE_OWNER(dev); dev->hard_start_xmit = &fjn_start_xmit; dev->set_config = &fjn_config; dev->get_stats = &fjn_get_stats; diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c index 997c2d0c83b..1bb2ffa294d 100644 --- a/drivers/net/pcmcia/nmclan_cs.c +++ b/drivers/net/pcmcia/nmclan_cs.c @@ -474,7 +474,6 @@ static int nmclan_probe(struct pcmcia_device *link) lp->tx_free_frames=AM2150_MAX_TX_FRAMES; - SET_MODULE_OWNER(dev); dev->hard_start_xmit = &mace_start_xmit; dev->set_config = &mace_config; dev->get_stats = &mace_get_stats; diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index 63de89e93b7..49857c1b506 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -259,7 +259,6 @@ static int pcnet_probe(struct pcmcia_device *link) link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; - SET_MODULE_OWNER(dev); dev->open = &pcnet_open; dev->stop = &pcnet_close; dev->set_config = &set_config; diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index af6728cb49c..b25f1985d03 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -336,7 +336,6 @@ static int smc91c92_probe(struct pcmcia_device *link) link->conf.IntType = INT_MEMORY_AND_IO; /* The SMC91c92-specific entries in the device structure. */ - SET_MODULE_OWNER(dev); dev->hard_start_xmit = &smc_start_xmit; dev->get_stats = &smc_get_stats; dev->set_config = &s9k_config; diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index 258d6f39618..d5c2d2c8c85 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -580,7 +580,6 @@ xirc2ps_probe(struct pcmcia_device *link) link->irq.Instance = dev; /* Fill in card specific entries */ - SET_MODULE_OWNER(dev); dev->hard_start_xmit = &do_start_xmit; dev->set_config = &do_config; dev->get_stats = &do_get_stats; diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index db87429b956..724d90bd1fe 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -1822,7 +1822,6 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) spin_lock_init(&lp->lock); - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); lp->name = chipname; lp->shared_irq = shared; diff --git a/drivers/net/plip.c b/drivers/net/plip.c index 8754cf3356b..2cfab4b3665 100644 --- a/drivers/net/plip.c +++ b/drivers/net/plip.c @@ -1278,7 +1278,6 @@ static void plip_attach (struct parport *port) strcpy(dev->name, name); - SET_MODULE_OWNER(dev); dev->irq = port->irq; dev->base_addr = port->base; if (port->irq == -1) { diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c index 93c2c39a4a4..f375bbbd660 100644 --- a/drivers/net/ps3_gelic_net.c +++ b/drivers/net/ps3_gelic_net.c @@ -1349,7 +1349,6 @@ static int gelic_net_setup_netdev(struct gelic_net_card *card) int status; u64 v1, v2; - SET_MODULE_OWNER(netdev); SET_NETDEV_DEV(netdev, &card->dev->core); spin_lock_init(&card->tx_dma_lock); diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c index e39232320e3..309199bb7d1 100755 --- a/drivers/net/qla3xxx.c +++ b/drivers/net/qla3xxx.c @@ -4011,7 +4011,6 @@ static int __devinit ql3xxx_probe(struct pci_dev *pdev, goto err_out_free_regions; } - SET_MODULE_OWNER(ndev); SET_NETDEV_DEV(ndev, &pdev->dev); pci_set_drvdata(pdev, ndev); diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 3f2306e3f51..b8809a8ef20 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -1506,7 +1506,6 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) goto out; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); tp = netdev_priv(dev); tp->dev = dev; diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c index df6b73872fd..25a9dd821aa 100644 --- a/drivers/net/rionet.c +++ b/drivers/net/rionet.c @@ -471,8 +471,6 @@ static int rionet_setup_netdev(struct rio_mport *mport) ndev->features = NETIF_F_LLTX; SET_ETHTOOL_OPS(ndev, &rionet_ethtool_ops); - SET_MODULE_OWNER(ndev); - spin_lock_init(&rnet->lock); spin_lock_init(&rnet->tx_lock); diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c index 5c2e41fac6d..41f877d482c 100644 --- a/drivers/net/rrunner.c +++ b/drivers/net/rrunner.c @@ -109,7 +109,6 @@ static int __devinit rr_init_one(struct pci_dev *pdev, rrpriv = netdev_priv(dev); - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); if (pci_request_regions(pdev, "rrunner")) { diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index ac6b9b93c02..f77049b34e1 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -7463,7 +7463,6 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) pci_set_master(pdev); pci_set_drvdata(pdev, dev); - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); /* Private member variable initialized to s2io NIC structure */ diff --git a/drivers/net/sb1000.c b/drivers/net/sb1000.c index 1de3eec1a79..aeaa75f549e 100644 --- a/drivers/net/sb1000.c +++ b/drivers/net/sb1000.c @@ -189,7 +189,6 @@ sb1000_probe_one(struct pnp_dev *pdev, const struct pnp_device_id *id) */ dev->flags = IFF_POINTOPOINT|IFF_NOARP; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); if (sb1000_debug > 0) diff --git a/drivers/net/shaper.c b/drivers/net/shaper.c index 3773b3858bd..b56721a68a8 100644 --- a/drivers/net/shaper.c +++ b/drivers/net/shaper.c @@ -533,8 +533,6 @@ static void __init shaper_setup(struct net_device *dev) * Set up the shaper. */ - SET_MODULE_OWNER(dev); - shaper_init_priv(dev); dev->open = shaper_open; diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index 038ccfbafdd..e810ae942cd 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c @@ -1421,7 +1421,6 @@ static struct net_device * __devinit sis190_init_board(struct pci_dev *pdev) goto err_out_0; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); tp = netdev_priv(dev); diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index 7c6e4808399..e1930c3ee75 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -430,7 +430,6 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev, net_dev = alloc_etherdev(sizeof(struct sis900_private)); if (!net_dev) return -ENOMEM; - SET_MODULE_OWNER(net_dev); SET_NETDEV_DEV(net_dev, &pci_dev->dev); /* We do a request_region() to register /proc/ioports info. */ diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c index 7dc9c9ebf5e..20890e44f99 100644 --- a/drivers/net/sk98lin/skge.c +++ b/drivers/net/sk98lin/skge.c @@ -4877,7 +4877,6 @@ static int __devinit skge_probe_one(struct pci_dev *pdev, goto out_free_netdev; } - SET_MODULE_OWNER(dev); dev->open = &SkGeOpen; dev->stop = &SkGeClose; dev->hard_start_xmit = &SkGeXmit; diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c index a7ef6c8b772..ca508708229 100644 --- a/drivers/net/skfp/skfddi.c +++ b/drivers/net/skfp/skfddi.c @@ -262,7 +262,6 @@ static int skfp_init_one(struct pci_dev *pdev, dev->do_ioctl = &skfp_ioctl; dev->header_cache_update = NULL; /* not supported */ - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); /* Initialize board structure with bus-specific info */ diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 0bf46ed4e68..47a144d000d 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -3549,7 +3549,6 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port, return NULL; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &hw->pdev->dev); dev->open = skge_up; dev->stop = skge_down; diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 941a6088252..1b9e5f40dde 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -3924,7 +3924,6 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, return NULL; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &hw->pdev->dev); dev->irq = hw->pdev->irq; dev->open = sky2_up; diff --git a/drivers/net/slip.c b/drivers/net/slip.c index 3fd4735006f..335b7cc80eb 100644 --- a/drivers/net/slip.c +++ b/drivers/net/slip.c @@ -639,8 +639,6 @@ static void sl_setup(struct net_device *dev) dev->addr_len = 0; dev->tx_queue_len = 10; - SET_MODULE_OWNER(dev); - /* New-style flags. */ dev->flags = IFF_NOARP|IFF_POINTOPOINT|IFF_MULTICAST; } diff --git a/drivers/net/smc-mca.c b/drivers/net/smc-mca.c index ae1ae343bee..3b43fa8fd08 100644 --- a/drivers/net/smc-mca.c +++ b/drivers/net/smc-mca.c @@ -264,7 +264,6 @@ static int __init ultramca_probe(struct device *gen_dev) if(!dev) return -ENODEV; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, gen_dev); mca_device_set_name(mca_dev, smc_mca_adapter_names[adapter]); mca_device_set_claim(mca_dev, 1); diff --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c index a52b22d7db6..d02bd7bc1ba 100644 --- a/drivers/net/smc-ultra.c +++ b/drivers/net/smc-ultra.c @@ -142,8 +142,6 @@ static int __init do_ultra_probe(struct net_device *dev) int base_addr = dev->base_addr; int irq = dev->irq; - SET_MODULE_OWNER(dev); - #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = &ultra_poll; #endif diff --git a/drivers/net/smc-ultra32.c b/drivers/net/smc-ultra32.c index 88a30e56c64..043a5002029 100644 --- a/drivers/net/smc-ultra32.c +++ b/drivers/net/smc-ultra32.c @@ -132,8 +132,6 @@ struct net_device * __init ultra32_probe(int unit) netdev_boot_setup_check(dev); } - SET_MODULE_OWNER(dev); - irq = dev->irq; /* EISA spec allows for up to 16 slots, but 8 is typical. */ diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index db43e42bee3..5f03e44ad13 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -2181,7 +2181,6 @@ static int smc911x_drv_probe(struct platform_device *pdev) ret = -ENOMEM; goto release_1; } - SET_MODULE_OWNER(ndev); SET_NETDEV_DEV(ndev, &pdev->dev); ndev->dma = (unsigned char)-1; diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c index 36c1ebadbf2..0a79516d196 100644 --- a/drivers/net/smc9194.c +++ b/drivers/net/smc9194.c @@ -744,8 +744,6 @@ struct net_device * __init smc_init(int unit) irq = dev->irq; } - SET_MODULE_OWNER(dev); - if (io > 0x1ff) { /* Check a single specified location. */ err = smc_probe(dev, io); } else if (io != 0) { /* Don't probe at all. */ diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index 01cc3c742c3..c5837ab5c96 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -2212,7 +2212,6 @@ static int smc_drv_probe(struct platform_device *pdev) ret = -ENOMEM; goto out_release_io; } - SET_MODULE_OWNER(ndev); SET_NETDEV_DEV(ndev, &pdev->dev); ndev->dma = (unsigned char)-1; diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 6d8f2bb7e0f..edc736eb3b8 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -2324,7 +2324,6 @@ spider_net_setup_netdev(struct spider_net_card *card) struct sockaddr addr; const u8 *mac; - SET_MODULE_OWNER(netdev); SET_NETDEV_DEV(netdev, &card->pdev->dev); pci_set_drvdata(card->pdev, netdev); diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index 3b9336c3420..5785429ca0e 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -719,7 +719,6 @@ static int __devinit starfire_init_one(struct pci_dev *pdev, printk(KERN_ERR DRV_NAME " %d: cannot alloc etherdev, aborting\n", card_idx); return -ENOMEM; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); irq = pdev->irq; diff --git a/drivers/net/stnic.c b/drivers/net/stnic.c index e6f90427160..b65be5d70fe 100644 --- a/drivers/net/stnic.c +++ b/drivers/net/stnic.c @@ -112,7 +112,6 @@ static int __init stnic_probe(void) dev = alloc_ei_netdev(); if (!dev) return -ENOMEM; - SET_MODULE_OWNER(dev); #ifdef CONFIG_SH_STANDARD_BIOS sh_bios_get_node_addr (stnic_eadr); diff --git a/drivers/net/sun3_82586.c b/drivers/net/sun3_82586.c index b77ab6e8fd3..9b2a7f7bb25 100644 --- a/drivers/net/sun3_82586.c +++ b/drivers/net/sun3_82586.c @@ -311,7 +311,6 @@ struct net_device * __init sun3_82586_probe(int unit) sprintf(dev->name, "eth%d", unit); netdev_boot_setup_check(dev); } - SET_MODULE_OWNER(dev); dev->irq = IE_IRQ; dev->base_addr = ioaddr; diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c index f1548c03332..c67632dcac4 100644 --- a/drivers/net/sun3lance.c +++ b/drivers/net/sun3lance.c @@ -274,7 +274,6 @@ struct net_device * __init sun3lance_probe(int unit) sprintf(dev->name, "eth%d", unit); netdev_boot_setup_check(dev); } - SET_MODULE_OWNER(dev); if (!lance_probe(dev)) goto out; diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c index b3e0158def4..4ba3e4857e9 100644 --- a/drivers/net/sunbmac.c +++ b/drivers/net/sunbmac.c @@ -1087,7 +1087,6 @@ static int __init bigmac_ether_init(struct sbus_dev *qec_sdev) dev = alloc_etherdev(sizeof(struct bigmac)); if (!dev) return -ENOMEM; - SET_MODULE_OWNER(dev); if (version_printed++ == 0) printk(KERN_INFO "%s", version); diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index a8f2af8f778..3c553dcc2b9 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -485,7 +485,6 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, dev = alloc_etherdev(sizeof(*np)); if (!dev) return -ENOMEM; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); if (pci_request_regions(pdev, DRV_NAME)) diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index bf821e96f7b..869ac44c51f 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -3023,7 +3023,6 @@ static int __devinit gem_init_one(struct pci_dev *pdev, err = -ENOMEM; goto err_disable_device; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); gp = dev->priv; diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index 8b35f13318e..170580c1312 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -2680,7 +2680,6 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe dev = alloc_etherdev(sizeof(struct happy_meal)); if (!dev) goto err_out; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &sdev->ofdev.dev); if (hme_version_printed++ == 0) @@ -3022,7 +3021,6 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev, err = -ENOMEM; if (!dev) goto err_out; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); if (hme_version_printed++ == 0) diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c index e94b752f9f3..17d66c1185c 100644 --- a/drivers/net/sunlance.c +++ b/drivers/net/sunlance.c @@ -1457,7 +1457,6 @@ no_link_test: lp->dregs = NULL; lp->dev = dev; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &sdev->ofdev.dev); dev->open = &lance_open; dev->stop = &lance_close; diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c index 1b65ae8a1c7..b5c2974fd62 100644 --- a/drivers/net/sunqe.c +++ b/drivers/net/sunqe.c @@ -898,7 +898,6 @@ static int __init qec_ether_init(struct sbus_dev *sdev) /* Stop this QE. */ qe_stop(qe); - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &sdev->ofdev.dev); dev->open = qe_open; diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c index b5e0dff6723..df8237360f5 100644 --- a/drivers/net/tc35815.c +++ b/drivers/net/tc35815.c @@ -685,7 +685,6 @@ static int __devinit tc35815_init_one (struct pci_dev *pdev, dev_err(&pdev->dev, "unable to alloc new ethernet\n"); return -ENOMEM; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); lp = dev->priv; lp->dev = dev; diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index cbfa4df0959..369a172a04a 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -11826,7 +11826,6 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, goto err_out_free_res; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); #if TG3_VLAN_TAG_USED diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c index 74eb12107e6..c99ce74a7af 100644 --- a/drivers/net/tlan.c +++ b/drivers/net/tlan.c @@ -556,7 +556,6 @@ static int __devinit TLan_probe1(struct pci_dev *pdev, rc = -ENOMEM; goto err_out_regions; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); priv = netdev_priv(dev); diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c index f4251d35599..88d03c085d5 100644 --- a/drivers/net/tokenring/3c359.c +++ b/drivers/net/tokenring/3c359.c @@ -344,7 +344,6 @@ static int __devinit xl_probe(struct pci_dev *pdev, dev->set_multicast_list=&xl_set_rx_mode; dev->get_stats=&xl_get_stats ; dev->set_mac_address=&xl_set_mac_address ; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); pci_set_drvdata(pdev,dev) ; diff --git a/drivers/net/tokenring/abyss.c b/drivers/net/tokenring/abyss.c index 1bdd3beefbe..22fad511240 100644 --- a/drivers/net/tokenring/abyss.c +++ b/drivers/net/tokenring/abyss.c @@ -116,8 +116,6 @@ static int __devinit abyss_attach(struct pci_dev *pdev, const struct pci_device_ if (!dev) return -ENOMEM; - SET_MODULE_OWNER(dev); - if (!request_region(pci_ioaddr, ABYSS_IO_EXTENT, dev->name)) { ret = -EBUSY; goto err_out_trdev; diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c index 49c4270ef5f..f114fb729f5 100644 --- a/drivers/net/tokenring/lanstreamer.c +++ b/drivers/net/tokenring/lanstreamer.c @@ -245,7 +245,6 @@ static int __devinit streamer_init_one(struct pci_dev *pdev, return -ENOMEM; } - SET_MODULE_OWNER(dev); streamer_priv = netdev_priv(dev); #if STREAMER_NETWORK_MONITOR diff --git a/drivers/net/tokenring/madgemc.c b/drivers/net/tokenring/madgemc.c index 9eafc2e25ab..d0ce2ce675d 100644 --- a/drivers/net/tokenring/madgemc.c +++ b/drivers/net/tokenring/madgemc.c @@ -168,7 +168,6 @@ static int __devinit madgemc_probe(struct device *device) goto getout; } - SET_MODULE_OWNER(dev); dev->dma = 0; card = kmalloc(sizeof(struct card_info), GFP_KERNEL); diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c index b57f65b2591..a149d5e2965 100644 --- a/drivers/net/tokenring/olympic.c +++ b/drivers/net/tokenring/olympic.c @@ -261,7 +261,6 @@ static int __devinit olympic_probe(struct pci_dev *pdev, const struct pci_device dev->set_multicast_list=&olympic_set_rx_mode; dev->get_stats=&olympic_get_stats ; dev->set_mac_address=&olympic_set_mac_address ; - SET_MODULE_OWNER(dev) ; SET_NETDEV_DEV(dev, &pdev->dev); pci_set_drvdata(pdev,dev) ; diff --git a/drivers/net/tokenring/proteon.c b/drivers/net/tokenring/proteon.c index cb7dbb63c9d..85d156dea03 100644 --- a/drivers/net/tokenring/proteon.c +++ b/drivers/net/tokenring/proteon.c @@ -126,7 +126,6 @@ static int __init setup_card(struct net_device *dev, struct device *pdev) if (!dev) return -ENOMEM; - SET_MODULE_OWNER(dev); if (dev->base_addr) /* probe specific location */ err = proteon_probe1(dev, dev->base_addr); else { diff --git a/drivers/net/tokenring/skisa.c b/drivers/net/tokenring/skisa.c index 33afea31d87..ecbddc80a2a 100644 --- a/drivers/net/tokenring/skisa.c +++ b/drivers/net/tokenring/skisa.c @@ -143,7 +143,6 @@ static int __init setup_card(struct net_device *dev, struct device *pdev) if (!dev) return -ENOMEM; - SET_MODULE_OWNER(dev); if (dev->base_addr) /* probe specific location */ err = sk_isa_probe1(dev, dev->base_addr); else { diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c index f83bb5cb0d3..93da3a36cde 100644 --- a/drivers/net/tokenring/smctr.c +++ b/drivers/net/tokenring/smctr.c @@ -3583,8 +3583,6 @@ struct net_device __init *smctr_probe(int unit) if (!dev) return ERR_PTR(-ENOMEM); - SET_MODULE_OWNER(dev); - if (unit >= 0) { sprintf(dev->name, "tr%d", unit); netdev_boot_setup_check(dev); diff --git a/drivers/net/tokenring/tmspci.c b/drivers/net/tokenring/tmspci.c index aec75c930c2..ecdd8511a67 100644 --- a/drivers/net/tokenring/tmspci.c +++ b/drivers/net/tokenring/tmspci.c @@ -115,7 +115,6 @@ static int __devinit tms_pci_attach(struct pci_dev *pdev, const struct pci_devic dev = alloc_trdev(sizeof(struct net_local)); if (!dev) return -ENOMEM; - SET_MODULE_OWNER(dev); if (!request_region(pci_ioaddr, TMS_PCI_IO_EXTENT, dev->name)) { ret = -EBUSY; diff --git a/drivers/net/tsi108_eth.c b/drivers/net/tsi108_eth.c index a1d305b9b12..fe3225df0d3 100644 --- a/drivers/net/tsi108_eth.c +++ b/drivers/net/tsi108_eth.c @@ -1607,7 +1607,6 @@ tsi108_init_one(struct platform_device *pdev) */ dev->features = NETIF_F_HIGHDMA; - SET_MODULE_OWNER(dev); spin_lock_init(&data->txlock); spin_lock_init(&data->misclock); diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index d380e0b3f05..bd04e93908e 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -1944,7 +1944,6 @@ static int __devinit de_init_one (struct pci_dev *pdev, if (!dev) return -ENOMEM; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); dev->open = de_open; dev->stop = de_close; diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c index 09902891a6e..ba7f47c2dcf 100644 --- a/drivers/net/tulip/de4x5.c +++ b/drivers/net/tulip/de4x5.c @@ -1261,7 +1261,6 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev) } /* The DE4X5-specific entries in the device structure. */ - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, gendev); dev->open = &de4x5_open; dev->hard_start_xmit = &de4x5_queue_pkt; diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c index dab74feb44b..e2596e9ab1d 100644 --- a/drivers/net/tulip/dmfe.c +++ b/drivers/net/tulip/dmfe.c @@ -372,7 +372,6 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev, dev = alloc_etherdev(sizeof(*db)); if (dev == NULL) return -ENOMEM; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) { diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index 7040a59fa3c..66977aaa717 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -1345,7 +1345,6 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, return -ENOMEM; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); if (pci_resource_len (pdev, 0) < tulip_tbl[chip_idx].io_size) { printk (KERN_ERR PFX "%s: I/O region (0x%llx@0x%llx) too small, " diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c index e26ce44561c..2b7257d97c3 100644 --- a/drivers/net/tulip/uli526x.c +++ b/drivers/net/tulip/uli526x.c @@ -268,7 +268,6 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev, dev = alloc_etherdev(sizeof(*db)); if (dev == NULL) return -ENOMEM; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) { diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c index 5824f6a3549..396f8455cd3 100644 --- a/drivers/net/tulip/winbond-840.c +++ b/drivers/net/tulip/winbond-840.c @@ -370,7 +370,6 @@ static int __devinit w840_probe1 (struct pci_dev *pdev, dev = alloc_etherdev(sizeof(*np)); if (!dev) return -ENOMEM; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); if (pci_request_regions(pdev, DRV_NAME)) diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c index 4b239dcbef7..de8c92083e9 100644 --- a/drivers/net/tulip/xircom_cb.c +++ b/drivers/net/tulip/xircom_cb.c @@ -252,7 +252,6 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_ goto tx_buf_fail; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); diff --git a/drivers/net/tulip/xircom_tulip_cb.c b/drivers/net/tulip/xircom_tulip_cb.c index fc439f33335..c3f8e303c6c 100644 --- a/drivers/net/tulip/xircom_tulip_cb.c +++ b/drivers/net/tulip/xircom_tulip_cb.c @@ -547,7 +547,6 @@ static int __devinit xircom_init_one(struct pci_dev *pdev, const struct pci_devi printk (KERN_ERR DRV_NAME "%d: cannot alloc etherdev, aborting\n", board_idx); return -ENOMEM; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); dev->base_addr = ioaddr; diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 691d264fbb6..8b3ec335385 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -435,7 +435,6 @@ static void tun_setup(struct net_device *dev) tun->owner = -1; tun->group = -1; - SET_MODULE_OWNER(dev); dev->open = tun_net_open; dev->hard_start_xmit = tun_net_xmit; dev->stop = tun_net_close; diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index 0377b8b64c7..84d99fc7789 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -2332,7 +2332,6 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) err = -ENOMEM; goto error_out; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); err = pci_enable_device(pdev); diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 72f617bf252..8da41229594 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -3957,7 +3957,6 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma /* Set the dev->base_addr to the gfar reg region */ dev->base_addr = (unsigned long)(ug_info->uf_info.regs); - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, device); /* Fill in the dev structure */ diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c index 524dc5f5e46..58a53a64175 100644 --- a/drivers/net/usb/kaweth.c +++ b/drivers/net/usb/kaweth.c @@ -1152,8 +1152,6 @@ err_fw: INIT_DELAYED_WORK(&kaweth->lowmem_work, kaweth_resubmit_tl); - SET_MODULE_OWNER(netdev); - usb_set_intfdata(intf, kaweth); #if 0 diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c index 06838928ef4..432a2f05446 100644 --- a/drivers/net/usb/pegasus.c +++ b/drivers/net/usb/pegasus.c @@ -1321,7 +1321,6 @@ static int pegasus_probe(struct usb_interface *intf, pegasus->intf = intf; pegasus->usb = dev; pegasus->net = net; - SET_MODULE_OWNER(net); net->open = pegasus_open; net->stop = pegasus_close; net->watchdog_timeo = PEGASUS_TX_TIMEOUT; diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c index 3b3a57ea267..33cbc306226 100644 --- a/drivers/net/usb/rtl8150.c +++ b/drivers/net/usb/rtl8150.c @@ -917,7 +917,6 @@ static int rtl8150_probe(struct usb_interface *intf, dev->udev = udev; dev->netdev = netdev; - SET_MODULE_OWNER(netdev); netdev->open = rtl8150_open; netdev->stop = rtl8150_close; netdev->do_ioctl = rtl8150_ioctl; diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 3034d1aea37..3542ca5fb0f 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -1173,7 +1173,6 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) init_timer (&dev->delay); mutex_init (&dev->phy_mutex); - SET_MODULE_OWNER (net); dev->net = net; strcpy (net->name, "usb%d"); memcpy (net->dev_addr, node_id, sizeof node_id); diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index 7a5899059c4..987f5b937e3 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -702,7 +702,6 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, printk(KERN_ERR "alloc_etherdev failed\n"); goto err_out; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); rp = netdev_priv(dev); diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index a4729bc385f..511a74c6e78 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -712,7 +712,6 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi /* Chain it all together */ - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); vptr = netdev_priv(dev); diff --git a/drivers/net/wan/c101.c b/drivers/net/wan/c101.c index 8ead774d14c..c4c8eab8574 100644 --- a/drivers/net/wan/c101.c +++ b/drivers/net/wan/c101.c @@ -363,7 +363,6 @@ static int __init c101_run(unsigned long irq, unsigned long winbase) hdlc = dev_to_hdlc(dev); spin_lock_init(&card->lock); - SET_MODULE_OWNER(dev); dev->irq = irq; dev->mem_start = winbase; dev->mem_end = winbase + C101_MAPPED_RAM_SIZE - 1; diff --git a/drivers/net/wan/cycx_x25.c b/drivers/net/wan/cycx_x25.c index a8af28b273d..46e053106d4 100644 --- a/drivers/net/wan/cycx_x25.c +++ b/drivers/net/wan/cycx_x25.c @@ -508,7 +508,6 @@ static int cycx_netdevice_init(struct net_device *dev) /* Set transmit buffer queue length */ dev->tx_queue_len = 10; - SET_MODULE_OWNER(dev); /* Initialize socket buffers */ cycx_x25_set_chan_state(dev, WAN_DISCONNECTED); diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c index 50d2f9108dc..33dc713b530 100644 --- a/drivers/net/wan/dscc4.c +++ b/drivers/net/wan/dscc4.c @@ -925,7 +925,6 @@ static int dscc4_found1(struct pci_dev *pdev, void __iomem *ioaddr) d->do_ioctl = dscc4_ioctl; d->tx_timeout = dscc4_tx_timeout; d->watchdog_timeo = TX_TIMEOUT; - SET_MODULE_OWNER(d); SET_NETDEV_DEV(d, &pdev->dev); dpriv->dev_id = i; diff --git a/drivers/net/wan/hostess_sv11.c b/drivers/net/wan/hostess_sv11.c index bf5f8d9b5c8..83dbc924fcb 100644 --- a/drivers/net/wan/hostess_sv11.c +++ b/drivers/net/wan/hostess_sv11.c @@ -241,8 +241,6 @@ static struct sv11_device *sv11_init(int iobase, int irq) if(!sv->netdev.dev) goto fail2; - SET_MODULE_OWNER(sv->netdev.dev); - dev=&sv->sync; /* diff --git a/drivers/net/wan/lapbether.c b/drivers/net/wan/lapbether.c index 699b93406df..36e683ccae5 100644 --- a/drivers/net/wan/lapbether.c +++ b/drivers/net/wan/lapbether.c @@ -329,7 +329,6 @@ static void lapbeth_setup(struct net_device *dev) dev->hard_header_len = 3; dev->mtu = 1000; dev->addr_len = 0; - SET_MODULE_OWNER(dev); } /* diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c index ae132c1c545..5ea877221f4 100644 --- a/drivers/net/wan/lmc/lmc_main.c +++ b/drivers/net/wan/lmc/lmc_main.c @@ -883,7 +883,6 @@ static int __devinit lmc_init_one(struct pci_dev *pdev, dev->base_addr = pci_resource_start(pdev, 0); dev->irq = pdev->irq; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); /* diff --git a/drivers/net/wan/n2.c b/drivers/net/wan/n2.c index cbdf0b748bd..0a566b0daac 100644 --- a/drivers/net/wan/n2.c +++ b/drivers/net/wan/n2.c @@ -459,7 +459,6 @@ static int __init n2_run(unsigned long io, unsigned long irq, port->log_node = 1; spin_lock_init(&port->lock); - SET_MODULE_OWNER(dev); dev->irq = irq; dev->mem_start = winbase; dev->mem_end = winbase + USE_WINDOWSIZE - 1; diff --git a/drivers/net/wan/pc300too.c b/drivers/net/wan/pc300too.c index 6353cb5c658..bf1b0159042 100644 --- a/drivers/net/wan/pc300too.c +++ b/drivers/net/wan/pc300too.c @@ -468,7 +468,6 @@ static int __devinit pc300_pci_init_one(struct pci_dev *pdev, port->phy_node = i; spin_lock_init(&port->lock); - SET_MODULE_OWNER(dev); dev->irq = card->irq; dev->mem_start = ramphys; dev->mem_end = ramphys + ramsize - 1; diff --git a/drivers/net/wan/pci200syn.c b/drivers/net/wan/pci200syn.c index 092e51d8903..b595b64e753 100644 --- a/drivers/net/wan/pci200syn.c +++ b/drivers/net/wan/pci200syn.c @@ -415,7 +415,6 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev, port->phy_node = i; spin_lock_init(&port->lock); - SET_MODULE_OWNER(dev); dev->irq = card->irq; dev->mem_start = ramphys; dev->mem_end = ramphys + ramsize - 1; diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c index 8d7e01e8f56..76db40d200d 100644 --- a/drivers/net/wan/sbni.c +++ b/drivers/net/wan/sbni.c @@ -216,8 +216,6 @@ static void __init sbni_devsetup(struct net_device *dev) dev->get_stats = &sbni_get_stats; dev->set_multicast_list = &set_multicast_list; dev->do_ioctl = &sbni_ioctl; - - SET_MODULE_OWNER( dev ); } int __init sbni_probe(int unit) diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c index 792e588d7d6..b39a541b250 100644 --- a/drivers/net/wan/sdla.c +++ b/drivers/net/wan/sdla.c @@ -1603,7 +1603,6 @@ static void setup_sdla(struct net_device *dev) netdev_boot_setup_check(dev); - SET_MODULE_OWNER(dev); dev->flags = 0; dev->type = 0xFFFF; dev->hard_header_len = 0; diff --git a/drivers/net/wan/wanxl.c b/drivers/net/wan/wanxl.c index 3c78f985638..8e320b76ae0 100644 --- a/drivers/net/wan/wanxl.c +++ b/drivers/net/wan/wanxl.c @@ -779,7 +779,6 @@ static int __devinit wanxl_pci_init_one(struct pci_dev *pdev, port->dev = dev; hdlc = dev_to_hdlc(dev); spin_lock_init(&port->lock); - SET_MODULE_OWNER(dev); dev->tx_queue_len = 50; dev->do_ioctl = wanxl_ioctl; dev->open = wanxl_open; diff --git a/drivers/net/wd.c b/drivers/net/wd.c index a0326818ff2..cef365881ac 100644 --- a/drivers/net/wd.c +++ b/drivers/net/wd.c @@ -93,8 +93,6 @@ static int __init do_wd_probe(struct net_device *dev) int mem_start = dev->mem_start; int mem_end = dev->mem_end; - SET_MODULE_OWNER(dev); - if (base_addr > 0x1ff) { /* Check a user specified location. */ r = request_region(base_addr, WD_IO_EXTENT, "wd-probe"); if ( r == NULL) diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index a152797b951..80ae7599953 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -2870,7 +2870,6 @@ static struct net_device *_init_airo_card( unsigned short irq, int port, dev->base_addr = port; SET_NETDEV_DEV(dev, dmdev); - SET_MODULE_OWNER(dev); reset_card (dev, 1); msleep(400); diff --git a/drivers/net/wireless/airport.c b/drivers/net/wireless/airport.c index 7d5b8c2cc61..6f7eb9f5922 100644 --- a/drivers/net/wireless/airport.c +++ b/drivers/net/wireless/airport.c @@ -197,7 +197,6 @@ airport_attach(struct macio_dev *mdev, const struct of_device_id *match) return -EBUSY; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &mdev->ofdev.dev); macio_set_drvdata(mdev, dev); diff --git a/drivers/net/wireless/arlan-main.c b/drivers/net/wireless/arlan-main.c index 498e8486d12..3eaaab0ba0c 100644 --- a/drivers/net/wireless/arlan-main.c +++ b/drivers/net/wireless/arlan-main.c @@ -1792,8 +1792,6 @@ struct net_device * __init arlan_probe(int unit) if (!dev) return ERR_PTR(-ENOMEM); - SET_MODULE_OWNER(dev); - if (unit >= 0) { sprintf(dev->name, "eth%d", unit); netdev_boot_setup_check(dev); diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index 51a7db53afa..47dbdf95ea6 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -1603,7 +1603,6 @@ struct net_device *init_atmel_card(unsigned short irq, unsigned long port, dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5] ); - SET_MODULE_OWNER(dev); return dev; err_out_res: diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index dfbd01eaaf3..e038d072398 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -4092,7 +4092,6 @@ static int __devinit bcm43xx_init_one(struct pci_dev *pdev, goto out; } /* initialize the net_device struct */ - SET_MODULE_OWNER(net_dev); SET_NETDEV_DEV(net_dev, &pdev->dev); net_dev->open = bcm43xx_net_open; diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index 8990585bd22..12a6887cb9f 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -6239,8 +6239,6 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev, IPW_DEBUG_INFO("Attempting to register device...\n"); - SET_MODULE_OWNER(dev); - printk(KERN_INFO DRV_NAME ": Detected Intel PRO/Wireless 2100 Network Connection\n"); diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 61497c46746..afad8bb7e33 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -11625,7 +11625,6 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto out_destroy_workqueue; } - SET_MODULE_OWNER(net_dev); SET_NETDEV_DEV(net_dev, &pdev->dev); mutex_lock(&priv->mutex); diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 3feddcc750e..cb0359df355 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1157,8 +1157,6 @@ wlan_private *libertas_add_card(void *card, struct device *dmdev) priv->infra_open = 0; priv->hotplug_device = dmdev; - SET_MODULE_OWNER(dev); - /* Setup the OS Interface to our functions */ dev->open = libertas_open; dev->hard_start_xmit = libertas_pre_start_xmit; @@ -1340,8 +1338,6 @@ int libertas_add_mesh(wlan_private *priv, struct device *dev) mesh_dev->priv = priv; priv->mesh_dev = mesh_dev; - SET_MODULE_OWNER(mesh_dev); - mesh_dev->open = libertas_mesh_open; mesh_dev->hard_start_xmit = libertas_mesh_pre_start_xmit; mesh_dev->stop = libertas_mesh_close; diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c index 45b00e13ab2..389fdd313c7 100644 --- a/drivers/net/wireless/netwave_cs.c +++ b/drivers/net/wireless/netwave_cs.c @@ -412,7 +412,6 @@ static int netwave_probe(struct pcmcia_device *link) spin_lock_init(&priv->spinlock); /* Netwave specific entries in the device structure */ - SET_MODULE_OWNER(dev); dev->hard_start_xmit = &netwave_start_xmit; dev->get_stats = &netwave_get_stats; dev->set_multicast_list = &set_multicast_list; diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c index d1e502236b2..8b7f5768a10 100644 --- a/drivers/net/wireless/orinoco_cs.c +++ b/drivers/net/wireless/orinoco_cs.c @@ -313,7 +313,6 @@ orinoco_cs_config(struct pcmcia_device *link) /* Ok, we have the configuration, prepare to register the netdev */ dev->base_addr = link->io.BasePort1; dev->irq = link->irq.AssignedIRQ; - SET_MODULE_OWNER(dev); card->node.major = card->node.minor = 0; SET_NETDEV_DEV(dev, &handle_to_dev(link)); diff --git a/drivers/net/wireless/orinoco_nortel.c b/drivers/net/wireless/orinoco_nortel.c index eaf3d13b851..35ec5fcf81a 100644 --- a/drivers/net/wireless/orinoco_nortel.c +++ b/drivers/net/wireless/orinoco_nortel.c @@ -193,7 +193,6 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev, card = priv->card; card->bridge_io = bridge_io; card->attr_io = attr_io; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING); diff --git a/drivers/net/wireless/orinoco_pci.c b/drivers/net/wireless/orinoco_pci.c index 97a8b4ff32b..2547d5dac0d 100644 --- a/drivers/net/wireless/orinoco_pci.c +++ b/drivers/net/wireless/orinoco_pci.c @@ -148,7 +148,6 @@ static int orinoco_pci_init_one(struct pci_dev *pdev, priv = netdev_priv(dev); card = priv->card; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); hermes_struct_init(&priv->hw, hermes_io, HERMES_32BIT_REGSPACING); diff --git a/drivers/net/wireless/orinoco_plx.c b/drivers/net/wireless/orinoco_plx.c index 31162ac25a9..98fe165337d 100644 --- a/drivers/net/wireless/orinoco_plx.c +++ b/drivers/net/wireless/orinoco_plx.c @@ -232,7 +232,6 @@ static int orinoco_plx_init_one(struct pci_dev *pdev, card = priv->card; card->bridge_io = bridge_io; card->attr_io = attr_io; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING); diff --git a/drivers/net/wireless/orinoco_tmd.c b/drivers/net/wireless/orinoco_tmd.c index b9c54d8fceb..df493185a4a 100644 --- a/drivers/net/wireless/orinoco_tmd.c +++ b/drivers/net/wireless/orinoco_tmd.c @@ -134,7 +134,6 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev, priv = netdev_priv(dev); card = priv->card; card->bridge_io = bridge_io; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING); diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c index 084795355b7..219dd651dc4 100644 --- a/drivers/net/wireless/prism54/islpci_dev.c +++ b/drivers/net/wireless/prism54/islpci_dev.c @@ -808,7 +808,6 @@ islpci_setup(struct pci_dev *pdev) if (!ndev) return ndev; - SET_MODULE_OWNER(ndev); pci_set_drvdata(pdev, ndev); #if defined(SET_NETDEV_DEV) SET_NETDEV_DEV(ndev, &pdev->dev); diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 1d9dbf83001..1b0e9707049 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -356,7 +356,6 @@ static int ray_probe(struct pcmcia_device *p_dev) dev->set_multicast_list = &set_multicast_list; DEBUG(2,"ray_cs ray_attach calling ether_setup.)\n"); - SET_MODULE_OWNER(dev); dev->init = &ray_dev_init; dev->open = &ray_open; dev->stop = &ray_dev_close; diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c index af70460f008..98df9bc7836 100644 --- a/drivers/net/wireless/spectrum_cs.c +++ b/drivers/net/wireless/spectrum_cs.c @@ -782,7 +782,6 @@ spectrum_cs_config(struct pcmcia_device *link) /* Ok, we have the configuration, prepare to register the netdev */ dev->base_addr = link->io.BasePort1; dev->irq = link->irq.AssignedIRQ; - SET_MODULE_OWNER(dev); card->node.major = card->node.minor = 0; /* Reset card and download firmware */ diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c index c49d5a1f94a..404cd151231 100644 --- a/drivers/net/wireless/strip.c +++ b/drivers/net/wireless/strip.c @@ -2508,8 +2508,6 @@ static void strip_dev_setup(struct net_device *dev) * Finish setting up the DEVICE info. */ - SET_MODULE_OWNER(dev); - dev->trans_start = 0; dev->last_rx = 0; dev->tx_queue_len = 30; /* Drop after 30 frames queued */ diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c index 1cf090d60ed..b876bf65935 100644 --- a/drivers/net/wireless/wavelan.c +++ b/drivers/net/wireless/wavelan.c @@ -4177,7 +4177,6 @@ static int __init wavelan_config(struct net_device *dev, unsigned short ioaddr) /* Init spinlock */ spin_lock_init(&lp->spinlock); - SET_MODULE_OWNER(dev); dev->open = wavelan_open; dev->stop = wavelan_close; dev->hard_start_xmit = wavelan_packet_xmit; diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index 5740d4d4267..1cc5180ab1e 100644 --- a/drivers/net/wireless/wavelan_cs.c +++ b/drivers/net/wireless/wavelan_cs.c @@ -4577,7 +4577,6 @@ wavelan_probe(struct pcmcia_device *p_dev) lp->dev = dev; /* wavelan NET3 callbacks */ - SET_MODULE_OWNER(dev); dev->open = &wavelan_open; dev->stop = &wavelan_close; dev->hard_start_xmit = &wavelan_packet_xmit; diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index 732b59f1989..cfde68cff94 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -2003,8 +2003,6 @@ static int wl3501_config(struct pcmcia_device *link) goto failed; } - SET_MODULE_OWNER(dev); - this = netdev_priv(dev); /* * At this point, the dev_node_t structure(s) should be initialized and diff --git a/drivers/net/wireless/zd1211rw/zd_netdev.c b/drivers/net/wireless/zd1211rw/zd_netdev.c index 8bda48de31e..047cab3d87d 100644 --- a/drivers/net/wireless/zd1211rw/zd_netdev.c +++ b/drivers/net/wireless/zd1211rw/zd_netdev.c @@ -233,7 +233,6 @@ struct net_device *zd_netdev_alloc(struct usb_interface *intf) return NULL; } - SET_MODULE_OWNER(netdev); SET_NETDEV_DEV(netdev, &intf->dev); dev_dbg_f(&intf->dev, "netdev->flags %#06hx\n", netdev->flags); diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index b4de126825e..8eeb068dc4a 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -1176,7 +1176,6 @@ static struct net_device * __devinit xennet_create_dev(struct xenbus_device *dev netdev->features = NETIF_F_IP_CSUM; SET_ETHTOOL_OPS(netdev, &xennet_ethtool_ops); - SET_MODULE_OWNER(netdev); SET_NETDEV_DEV(netdev, &dev->dev); np->netdev = netdev; diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c index 870c5393c21..29e96950be6 100644 --- a/drivers/net/yellowfin.c +++ b/drivers/net/yellowfin.c @@ -392,7 +392,6 @@ static int __devinit yellowfin_init_one(struct pci_dev *pdev, printk (KERN_ERR PFX "cannot allocate ethernet device\n"); return -ENOMEM; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); np = netdev_priv(dev); diff --git a/drivers/net/znet.c b/drivers/net/znet.c index 4032e9f6f9b..dcd4e1b136b 100644 --- a/drivers/net/znet.c +++ b/drivers/net/znet.c @@ -388,8 +388,6 @@ static int __init znet_probe (void) if (!dev) return -ENOMEM; - SET_MODULE_OWNER (dev); - znet = dev->priv; netinfo = (struct netidblk *)p; diff --git a/drivers/net/zorro8390.c b/drivers/net/zorro8390.c index d85e2ea0b6a..a45f9952a3f 100644 --- a/drivers/net/zorro8390.c +++ b/drivers/net/zorro8390.c @@ -125,7 +125,6 @@ static int __devinit zorro8390_init_one(struct zorro_dev *z, dev = ____alloc_ei_netdev(0); if (!dev) return -ENOMEM; - SET_MODULE_OWNER(dev); if (!request_mem_region(ioaddr, NE_IO_EXTENT*2, DRV_NAME)) { free_netdev(dev); return -EBUSY; diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c index 023455a0b34..399695f7b1a 100644 --- a/drivers/s390/net/claw.c +++ b/drivers/s390/net/claw.c @@ -3891,7 +3891,6 @@ claw_init_netdevice(struct net_device * dev) dev->type = ARPHRD_SLIP; dev->tx_queue_len = 1300; dev->flags = IFF_POINTOPOINT | IFF_NOARP; - SET_MODULE_OWNER(dev); #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit\n",dev->name,__FUNCTION__); #endif diff --git a/drivers/s390/net/ctcmain.c b/drivers/s390/net/ctcmain.c index 92e8a37b502..44993723373 100644 --- a/drivers/s390/net/ctcmain.c +++ b/drivers/s390/net/ctcmain.c @@ -2823,7 +2823,6 @@ ctc_init_netdevice(struct net_device * dev, int alloc_device, dev->type = ARPHRD_SLIP; dev->tx_queue_len = 100; dev->flags = IFF_POINTOPOINT | IFF_NOARP; - SET_MODULE_OWNER(dev); return dev; } diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index 08a994fdd1a..e4b11afbbc9 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -2145,7 +2145,6 @@ lcs_new_device(struct ccwgroup_device *ccwgdev) card->dev->stop = lcs_stop_device; card->dev->hard_start_xmit = lcs_start_xmit; card->dev->get_stats = lcs_getstats; - SET_MODULE_OWNER(dev); memcpy(card->dev->dev_addr, card->mac, LCS_MAC_LENGTH); #ifdef CONFIG_IP_MULTICAST if (!lcs_check_multicast_support(card)) diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index 26888947433..4d18d6419dd 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c @@ -1904,7 +1904,6 @@ static void netiucv_setup_netdevice(struct net_device *dev) dev->type = ARPHRD_SLIP; dev->tx_queue_len = NETIUCV_QUEUELEN_DEFAULT; dev->flags = IFF_POINTOPOINT | IFF_NOARP; - SET_MODULE_OWNER(dev); } /** diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index f3e6fbeb212..8c46978e0af 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c @@ -6649,7 +6649,6 @@ qeth_netdev_init(struct net_device *dev) dev->mtu = card->info.initial_mtu; if (card->info.type != QETH_CARD_TYPE_OSN) SET_ETHTOOL_OPS(dev, &qeth_ethtool_ops); - SET_MODULE_OWNER(dev); return 0; } diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 593e23507b1..f70055473a0 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -2484,7 +2484,6 @@ autoconf_fail: /* network device setup */ dev->net = net; - SET_MODULE_OWNER (net); strcpy (net->name, "usb%d"); dev->cdc = cdc; dev->zlp = zlp; diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 625240ce27f..de387c5400b 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -702,7 +702,6 @@ static inline void *netdev_priv(const struct net_device *dev) return dev->priv; } -#define SET_MODULE_OWNER(dev) do { } while (0) /* Set the sysfs physical device reference for the network logical device * if set prior to registration will cause a symlink during initialization. */ diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index a9ced0a6f4c..4d003e39175 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -350,8 +350,6 @@ static int vlan_dev_init(struct net_device *dev) void vlan_setup(struct net_device *new_dev) { - SET_MODULE_OWNER(new_dev); - ether_setup(new_dev); /* new_dev->ifindex = 0; it will be set when added to diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index 99292e8e1d0..f803e39eee2 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c @@ -171,7 +171,6 @@ void br_dev_setup(struct net_device *dev) dev->set_multicast_list = br_dev_set_multicast_list; dev->change_mtu = br_change_mtu; dev->destructor = free_netdev; - SET_MODULE_OWNER(dev); SET_ETHTOOL_OPS(dev, &br_ethtool_ops); dev->stop = br_dev_stop; dev->tx_queue_len = 0; diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 3106225c5e5..ffa9f1c9dcb 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -1132,7 +1132,6 @@ static int ipgre_close(struct net_device *dev) static void ipgre_tunnel_setup(struct net_device *dev) { - SET_MODULE_OWNER(dev); dev->uninit = ipgre_tunnel_uninit; dev->destructor = free_netdev; dev->hard_start_xmit = ipgre_tunnel_xmit; diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 652bd86e33a..5cd5bbe1379 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -237,7 +237,6 @@ static struct ip_tunnel * ipip_tunnel_locate(struct ip_tunnel_parm *parms, int c return NULL; nt = netdev_priv(dev); - SET_MODULE_OWNER(dev); dev->init = ipip_tunnel_init; nt->parms = *parms; @@ -775,7 +774,6 @@ static int ipip_tunnel_change_mtu(struct net_device *dev, int new_mtu) static void ipip_tunnel_setup(struct net_device *dev) { - SET_MODULE_OWNER(dev); dev->uninit = ipip_tunnel_uninit; dev->hard_start_xmit = ipip_tunnel_xmit; dev->get_stats = ipip_tunnel_get_stats; diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 937625e577c..2320cc27ff9 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -1313,7 +1313,6 @@ ip6_tnl_change_mtu(struct net_device *dev, int new_mtu) static void ip6_tnl_dev_setup(struct net_device *dev) { - SET_MODULE_OWNER(dev); dev->uninit = ip6_tnl_dev_uninit; dev->destructor = free_netdev; dev->hard_start_xmit = ip6_tnl_xmit; diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index e79f419b173..466657a9a8b 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -714,7 +714,6 @@ static int ipip6_tunnel_change_mtu(struct net_device *dev, int new_mtu) static void ipip6_tunnel_setup(struct net_device *dev) { - SET_MODULE_OWNER(dev); dev->uninit = ipip6_tunnel_uninit; dev->destructor = free_netdev; dev->hard_start_xmit = ipip6_tunnel_xmit; diff --git a/net/irda/irlan/irlan_eth.c b/net/irda/irlan/irlan_eth.c index c421521c0a9..340f04a36b0 100644 --- a/net/irda/irlan/irlan_eth.c +++ b/net/irda/irlan/irlan_eth.c @@ -60,8 +60,6 @@ static void irlan_eth_setup(struct net_device *dev) dev->set_multicast_list = irlan_eth_set_multicast_list; dev->destructor = free_netdev; - SET_MODULE_OWNER(dev); - ether_setup(dev); /* diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c index 0968184ea6b..146f453d737 100644 --- a/net/sched/sch_teql.c +++ b/net/sched/sch_teql.c @@ -432,7 +432,6 @@ static __init void teql_master_setup(struct net_device *dev) dev->tx_queue_len = 100; dev->flags = IFF_NOARP; dev->hard_header_len = LL_MAX_HEADER; - SET_MODULE_OWNER(dev); } static LIST_HEAD(master_dev_list); -- cgit v1.2.3-70-g09d2 From ff8ac60948ba819b89e9c87083e8050fc2f89999 Mon Sep 17 00:00:00 2001 From: Denis Cheng Date: Sun, 2 Sep 2007 18:30:18 +0800 Subject: drivers/net/: all drivers/net/ cleanup with ARRAY_SIZE Signed-off-by: Denis Cheng Signed-off-by: Jeff Garzik --- drivers/net/apne.c | 2 +- drivers/net/arm/am79c961a.c | 2 +- drivers/net/atarilance.c | 2 +- drivers/net/atl1/atl1_hw.c | 2 +- drivers/net/bnx2.c | 2 +- drivers/net/cs89x0.c | 6 +++--- drivers/net/e1000/e1000_ethtool.c | 3 +-- drivers/net/fec_8xx/fec_mii.c | 5 ++--- drivers/net/ibm_emac/ibm_emac_debug.c | 8 ++++---- drivers/net/irda/actisys-sir.c | 2 +- drivers/net/ixgb/ixgb_ethtool.c | 3 +-- drivers/net/lp486e.c | 4 +--- drivers/net/mv643xx_eth.c | 3 +-- drivers/net/ne-h8300.c | 2 +- drivers/net/ne.c | 2 +- drivers/net/ne2.c | 2 +- drivers/net/ne2k-pci.c | 2 +- drivers/net/netxen/netxen_nic.h | 2 +- drivers/net/netxen/netxen_nic_hw.c | 2 +- drivers/net/pcmcia/axnet_cs.c | 2 +- drivers/net/pcmcia/pcnet_cs.c | 4 ++-- drivers/net/phy/phy.c | 2 +- drivers/net/skfp/smt.c | 2 +- drivers/net/skfp/srf.c | 4 ++-- drivers/net/tulip/de4x5.c | 6 +++--- drivers/net/wireless/airo.c | 6 +++--- drivers/net/wireless/hostap/hostap_ioctl.c | 6 +++--- drivers/net/wireless/ipw2100.c | 7 +++---- drivers/net/wireless/libertas/main.c | 14 +++++++------- drivers/net/wireless/libertas/wext.c | 4 ++-- drivers/net/wireless/netwave_cs.c | 6 +++--- drivers/net/wireless/prism54/isl_ioctl.c | 7 +++---- drivers/net/wireless/ray_cs.c | 6 +++--- drivers/net/wireless/wavelan.c | 6 +++--- drivers/net/wireless/wavelan_cs.c | 6 +++--- drivers/net/wireless/wl3501_cs.c | 2 +- drivers/net/zorro8390.c | 2 +- 37 files changed, 70 insertions(+), 78 deletions(-) (limited to 'drivers') diff --git a/drivers/net/apne.c b/drivers/net/apne.c index b073810f9fd..b5a974a964c 100644 --- a/drivers/net/apne.c +++ b/drivers/net/apne.c @@ -246,7 +246,7 @@ static int __init apne_probe1(struct net_device *dev, int ioaddr) {0x00, NE_EN0_RSARHI}, {E8390_RREAD+E8390_START, NE_CMD}, }; - for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++) { + for (i = 0; i < ARRAY_SIZE(program_seq); i++) { outb(program_seq[i].value, ioaddr + program_seq[i].offset); } diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c index 2143eeb7a2b..77964556776 100644 --- a/drivers/net/arm/am79c961a.c +++ b/drivers/net/arm/am79c961a.c @@ -414,7 +414,7 @@ static void am79c961_setmulticastlist (struct net_device *dev) /* * Update the multicast hash table */ - for (i = 0; i < sizeof(multi_hash) / sizeof(multi_hash[0]); i++) + for (i = 0; i < ARRAY_SIZE(multi_hash); i++) write_rreg(dev->base_addr, i + LADRL, multi_hash[i]); /* diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c index 97cca505cf9..17b9dbf7bd6 100644 --- a/drivers/net/atarilance.c +++ b/drivers/net/atarilance.c @@ -263,7 +263,7 @@ struct lance_addr { (highest byte stripped) */ }; -#define N_LANCE_ADDR (sizeof(lance_addr_list)/sizeof(*lance_addr_list)) +#define N_LANCE_ADDR ARRAY_SIZE(lance_addr_list) /* Definitions for the Lance */ diff --git a/drivers/net/atl1/atl1_hw.c b/drivers/net/atl1/atl1_hw.c index ef886bdeac1..9d3bd22e3a8 100644 --- a/drivers/net/atl1/atl1_hw.c +++ b/drivers/net/atl1/atl1_hw.c @@ -603,7 +603,7 @@ static struct atl1_spi_flash_dev flash_table[] = { static void atl1_init_flash_opcode(struct atl1_hw *hw) { - if (hw->flash_vendor >= sizeof(flash_table) / sizeof(flash_table[0])) + if (hw->flash_vendor >= ARRAY_SIZE(flash_table)) hw->flash_vendor = 0; /* ATMEL */ /* Init OP table */ diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 61debba873a..f1e7204f78c 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -3492,7 +3492,7 @@ bnx2_init_nvram(struct bnx2 *bp) /* Determine the selected interface. */ val = REG_RD(bp, BNX2_NVM_CFG1); - entry_count = sizeof(flash_table) / sizeof(struct flash_spec); + entry_count = ARRAY_SIZE(flash_table); if (val & 0x40000000) { diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c index 2b4c9219391..4cf82cf5ac1 100644 --- a/drivers/net/cs89x0.c +++ b/drivers/net/cs89x0.c @@ -805,7 +805,7 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) i = cs8900_irq_map[0]; #else /* Translate the IRQ using the IRQ mapping table. */ - if (i >= sizeof(cs8900_irq_map)/sizeof(cs8900_irq_map[0])) + if (i >= ARRAY_SIZE(cs8900_irq_map)) printk("\ncs89x0: invalid ISA interrupt number %d\n", i); else i = cs8900_irq_map[i]; @@ -1246,11 +1246,11 @@ write_irq(struct net_device *dev, int chip_type, int irq) if (chip_type == CS8900) { /* Search the mapping table for the corresponding IRQ pin. */ - for (i = 0; i != sizeof(cs8900_irq_map)/sizeof(cs8900_irq_map[0]); i++) + for (i = 0; i != ARRAY_SIZE(cs8900_irq_map); i++) if (cs8900_irq_map[i] == irq) break; /* Not found */ - if (i == sizeof(cs8900_irq_map)/sizeof(cs8900_irq_map[0])) + if (i == ARRAY_SIZE(cs8900_irq_map)) i = 3; writereg(dev, PP_CS8900_ISAINT, i); } else { diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index 9ecc3adcf6c..76d16aaf05b 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -106,8 +106,7 @@ static const struct e1000_stats e1000_gstrings_stats[] = { }; #define E1000_QUEUE_STATS_LEN 0 -#define E1000_GLOBAL_STATS_LEN \ - sizeof(e1000_gstrings_stats) / sizeof(struct e1000_stats) +#define E1000_GLOBAL_STATS_LEN ARRAY_SIZE(e1000_gstrings_stats) #define E1000_STATS_LEN (E1000_GLOBAL_STATS_LEN + E1000_QUEUE_STATS_LEN) static const char e1000_gstrings_test[][ETH_GSTRING_LEN] = { "Register test (offline)", "Eeprom test (offline)", diff --git a/drivers/net/fec_8xx/fec_mii.c b/drivers/net/fec_8xx/fec_mii.c index b3fa0d6a159..e8e10a02d20 100644 --- a/drivers/net/fec_8xx/fec_mii.c +++ b/drivers/net/fec_8xx/fec_mii.c @@ -308,12 +308,11 @@ int fec_mii_phy_id_detect(struct net_device *dev) return -1; } - for (i = 0, phy = phy_info; i < sizeof(phy_info) / sizeof(phy_info[0]); - i++, phy++) + for (i = 0, phy = phy_info; i < ARRAY_SIZE(phy_info); i++, phy++) if (phy->id == (phy_hwid >> 4) || phy->id == 0) break; - if (i >= sizeof(phy_info) / sizeof(phy_info[0])) { + if (i >= ARRAY_SIZE(phy_info)) { printk(KERN_ERR DRV_MODULE_NAME ": %s PHY id 0x%08x is not supported!\n", dev->name, phy_hwid); diff --git a/drivers/net/ibm_emac/ibm_emac_debug.c b/drivers/net/ibm_emac/ibm_emac_debug.c index 92f970d402d..1f70906cfb9 100644 --- a/drivers/net/ibm_emac/ibm_emac_debug.c +++ b/drivers/net/ibm_emac/ibm_emac_debug.c @@ -132,7 +132,7 @@ void emac_dbg_register(int idx, struct ocp_enet_private *dev) { unsigned long flags; - if (idx >= sizeof(__emacs) / sizeof(__emacs[0])) { + if (idx >= ARRAY_SIZE(__emacs)) { printk(KERN_WARNING "invalid index %d when registering EMAC for debugging\n", idx); @@ -148,7 +148,7 @@ void mal_dbg_register(int idx, struct ibm_ocp_mal *mal) { unsigned long flags; - if (idx >= sizeof(__mals) / sizeof(__mals[0])) { + if (idx >= ARRAY_SIZE(__mals)) { printk(KERN_WARNING "invalid index %d when registering MAL for debugging\n", idx); @@ -167,11 +167,11 @@ void emac_dbg_dump_all(void) local_irq_save(flags); - for (i = 0; i < sizeof(__mals) / sizeof(__mals[0]); ++i) + for (i = 0; i < ARRAY_SIZE(__mals); ++i) if (__mals[i]) emac_mal_dump(__mals[i]); - for (i = 0; i < sizeof(__emacs) / sizeof(__emacs[0]); ++i) + for (i = 0; i < ARRAY_SIZE(__emacs); ++i) if (__emacs[i]) emac_mac_dump(i, __emacs[i]); diff --git a/drivers/net/irda/actisys-sir.c b/drivers/net/irda/actisys-sir.c index 9715ab5572e..ccf6ec548a6 100644 --- a/drivers/net/irda/actisys-sir.c +++ b/drivers/net/irda/actisys-sir.c @@ -67,7 +67,7 @@ static int actisys_reset(struct sir_dev *); /* Note : the 220L doesn't support 38400, but we will fix that below */ static unsigned baud_rates[] = { 9600, 19200, 57600, 115200, 38400 }; -#define MAX_SPEEDS (sizeof(baud_rates)/sizeof(baud_rates[0])) +#define MAX_SPEEDS ARRAY_SIZE(baud_rates) static struct dongle_driver act220l = { .owner = THIS_MODULE, diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c index 0413cd95eda..21d35bc5390 100644 --- a/drivers/net/ixgb/ixgb_ethtool.c +++ b/drivers/net/ixgb/ixgb_ethtool.c @@ -94,8 +94,7 @@ static struct ixgb_stats ixgb_gstrings_stats[] = { {"tx_csum_offload_errors", IXGB_STAT(hw_csum_tx_error)} }; -#define IXGB_STATS_LEN \ - sizeof(ixgb_gstrings_stats) / sizeof(struct ixgb_stats) +#define IXGB_STATS_LEN ARRAY_SIZE(ixgb_gstrings_stats) static int ixgb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) diff --git a/drivers/net/lp486e.c b/drivers/net/lp486e.c index 5fc18da1873..408ae6eb6a8 100644 --- a/drivers/net/lp486e.c +++ b/drivers/net/lp486e.c @@ -515,8 +515,6 @@ CLEAR_INT(void) { outb(0, IOADDR+8); } -#define SIZE(x) (sizeof(x)/sizeof((x)[0])) - #if 0 /* selftest or dump */ static void @@ -532,7 +530,7 @@ i596_port_do(struct net_device *dev, int portcmd, char *cmdname) { mdelay(30); /* random, unmotivated */ printk("lp486e i82596 %s result:\n", cmdname); - for (m = SIZE(lp->dump.dump); m && lp->dump.dump[m-1] == 0; m--) + for (m = ARRAY_SIZE(lp->dump.dump); m && lp->dump.dump[m-1] == 0; m--) ; for (i = 0; i < m; i++) { printk(" %04x", lp->dump.dump[i]); diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 6317bba9587..2a808e265a3 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -2680,8 +2680,7 @@ static const struct mv643xx_stats mv643xx_gstrings_stats[] = { { "late_collision", MV643XX_STAT(mib_counters.late_collision) }, }; -#define MV643XX_STATS_LEN \ - sizeof(mv643xx_gstrings_stats) / sizeof(struct mv643xx_stats) +#define MV643XX_STATS_LEN ARRAY_SIZE(mv643xx_gstrings_stats) static void mv643xx_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo) diff --git a/drivers/net/ne-h8300.c b/drivers/net/ne-h8300.c index a0f35361fbe..2b85d1b5334 100644 --- a/drivers/net/ne-h8300.c +++ b/drivers/net/ne-h8300.c @@ -257,7 +257,7 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr) {E8390_RREAD+E8390_START, E8390_CMD}, }; - for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++) + for (i = 0; i < ARRAY_SIZE(program_seq); i++) outb_p(program_seq[i].value, ioaddr + program_seq[i].offset); } diff --git a/drivers/net/ne.c b/drivers/net/ne.c index c81befc3a7a..27d87985bb6 100644 --- a/drivers/net/ne.c +++ b/drivers/net/ne.c @@ -375,7 +375,7 @@ static int __init ne_probe1(struct net_device *dev, unsigned long ioaddr) {E8390_RREAD+E8390_START, E8390_CMD}, }; - for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++) + for (i = 0; i < ARRAY_SIZE(program_seq); i++) outb_p(program_seq[i].value, ioaddr + program_seq[i].offset); } diff --git a/drivers/net/ne2.c b/drivers/net/ne2.c index d1a4b8d7122..f73073b1218 100644 --- a/drivers/net/ne2.c +++ b/drivers/net/ne2.c @@ -430,7 +430,7 @@ static int __init ne2_probe1(struct net_device *dev, int slot) {E8390_RREAD+E8390_START, E8390_CMD}, }; - for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++) + for (i = 0; i < ARRAY_SIZE(program_seq); i++) outb_p(program_seq[i].value, base_addr + program_seq[i].offset); diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c index 230a0f1e03f..7ec362b2e3e 100644 --- a/drivers/net/ne2k-pci.c +++ b/drivers/net/ne2k-pci.c @@ -307,7 +307,7 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev, {0x00, EN0_RSARHI}, {E8390_RREAD+E8390_START, E8390_CMD}, }; - for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++) + for (i = 0; i < ARRAY_SIZE(program_seq); i++) outb(program_seq[i].value, ioaddr + program_seq[i].offset); } diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index aaa34939485..7bbd5d14175 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -1119,7 +1119,7 @@ static const struct netxen_brdinfo netxen_boards[] = { {NETXEN_BRDTYPE_P2_SB31_2G, 2, "Dual Gb"}, }; -#define NUM_SUPPORTED_BOARDS (sizeof(netxen_boards)/sizeof(struct netxen_brdinfo)) +#define NUM_SUPPORTED_BOARDS ARRAY_SIZE(netxen_boards) static inline void get_brd_port_by_type(u32 type, int *ports) { diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index a7b8d7f2325..2c19b8df98f 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -569,7 +569,7 @@ int netxen_is_flash_supported(struct netxen_adapter *adapter) /* if the flash size less than 4Mb, make huge war cry and die */ for (j = 1; j < 4; j++) { addr = j * NETXEN_NIC_WINDOW_MARGIN; - for (i = 0; i < (sizeof(locs) / sizeof(locs[0])); i++) { + for (i = 0; i < ARRAY_SIZE(locs); i++) { if (netxen_rom_fast_read(adapter, locs[i], &val01) == 0 && netxen_rom_fast_read(adapter, (addr + locs[i]), &val02) == 0) { diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index a9db59d2a2f..28eea206766 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -232,7 +232,7 @@ static int get_prom(struct pcmcia_device *link) axnet_reset_8390(dev); mdelay(10); - for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++) + for (i = 0; i < ARRAY_SIZE(program_seq); i++) outb_p(program_seq[i].value, ioaddr + program_seq[i].offset); for (i = 0; i < 6; i += 2) { diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index 49857c1b506..8ce251cd320 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -207,7 +207,7 @@ static hw_info_t hw_info[] = { { /* PCMCIA Technology OEM */ 0x01c8, 0x00, 0xa0, 0x0c, 0 } }; -#define NR_INFO (sizeof(hw_info)/sizeof(hw_info_t)) +#define NR_INFO ARRAY_SIZE(hw_info) static hw_info_t default_info = { 0, 0, 0, 0, 0 }; static hw_info_t dl10019_info = { 0, 0, 0, 0, IS_DL10019|HAS_MII }; @@ -374,7 +374,7 @@ static hw_info_t *get_prom(struct pcmcia_device *link) pcnet_reset_8390(dev); mdelay(10); - for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++) + for (i = 0; i < ARRAY_SIZE(program_seq); i++) outb_p(program_seq[i].value, ioaddr + program_seq[i].offset); for (i = 0; i < 32; i++) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index cb230f44d6f..17c1e1555d8 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -204,7 +204,7 @@ static const struct phy_setting settings[] = { }, }; -#define MAX_NUM_SETTINGS (sizeof(settings)/sizeof(struct phy_setting)) +#define MAX_NUM_SETTINGS ARRAY_SIZE(settings) /** * phy_find_setting - find a PHY settings array entry that matches speed & duplex diff --git a/drivers/net/skfp/smt.c b/drivers/net/skfp/smt.c index 75afc1f07ba..ced2c8f76be 100644 --- a/drivers/net/skfp/smt.c +++ b/drivers/net/skfp/smt.c @@ -1654,7 +1654,7 @@ static const struct smt_pdef { { SMT_P4053, 0, SWAP_SMT_P4053 } , } ; -#define N_SMT_PLEN (sizeof(smt_pdef)/sizeof(smt_pdef[0])) +#define N_SMT_PLEN ARRAY_SIZE(smt_pdef) int smt_check_para(struct s_smc *smc, struct smt_header *sm, const u_short list[]) diff --git a/drivers/net/skfp/srf.c b/drivers/net/skfp/srf.c index 16573aca8b6..6caf713b744 100644 --- a/drivers/net/skfp/srf.c +++ b/drivers/net/skfp/srf.c @@ -43,7 +43,7 @@ static void clear_reported(struct s_smc *smc); static void smt_send_srf(struct s_smc *smc); static struct s_srf_evc *smt_get_evc(struct s_smc *smc, int code, int index); -#define MAX_EVCS (sizeof(smc->evcs)/sizeof(smc->evcs[0])) +#define MAX_EVCS ARRAY_SIZE(smc->evcs) struct evc_init { u_char code ; @@ -67,7 +67,7 @@ static const struct evc_init evc_inits[] = { { SMT_EVENT_PORT_PATH_CHANGE, INDEX_PORT,NUMPHYS,SMT_P4053 } , } ; -#define MAX_INIT_EVC (sizeof(evc_inits)/sizeof(evc_inits[0])) +#define MAX_INIT_EVC ARRAY_SIZE(evc_inits) void smt_init_evc(struct s_smc *smc) { diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c index ba7f47c2dcf..ee4215ca63f 100644 --- a/drivers/net/tulip/de4x5.c +++ b/drivers/net/tulip/de4x5.c @@ -3945,7 +3945,7 @@ create_packet(struct net_device *dev, char *frame, int len) static int EISA_signature(char *name, struct device *device) { - int i, status = 0, siglen = sizeof(de4x5_signatures)/sizeof(c_char *); + int i, status = 0, siglen = ARRAY_SIZE(de4x5_signatures); struct eisa_device *edev; *name = '\0'; @@ -3966,7 +3966,7 @@ EISA_signature(char *name, struct device *device) static int PCI_signature(char *name, struct de4x5_private *lp) { - int i, status = 0, siglen = sizeof(de4x5_signatures)/sizeof(c_char *); + int i, status = 0, siglen = ARRAY_SIZE(de4x5_signatures); if (lp->chipset == DC21040) { strcpy(name, "DE434/5"); @@ -5072,7 +5072,7 @@ mii_get_phy(struct net_device *dev) { struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; - int i, j, k, n, limit=sizeof(phy_info)/sizeof(struct phy_table); + int i, j, k, n, limit=ARRAY_SIZE(phy_info); int id; lp->active = 0; diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 80ae7599953..7d717c4d984 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -7578,9 +7578,9 @@ static const iw_handler airo_private_handler[] = static const struct iw_handler_def airo_handler_def = { - .num_standard = sizeof(airo_handler)/sizeof(iw_handler), - .num_private = sizeof(airo_private_handler)/sizeof(iw_handler), - .num_private_args = sizeof(airo_private_args)/sizeof(struct iw_priv_args), + .num_standard = ARRAY_SIZE(airo_handler), + .num_private = ARRAY_SIZE(airo_private_handler), + .num_private_args = ARRAY_SIZE(airo_private_args), .standard = airo_handler, .private = airo_private_handler, .private_args = airo_private_args, diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c index d58ac84f4e9..730b3541e32 100644 --- a/drivers/net/wireless/hostap/hostap_ioctl.c +++ b/drivers/net/wireless/hostap/hostap_ioctl.c @@ -3976,9 +3976,9 @@ static const iw_handler prism2_private_handler[] = const struct iw_handler_def hostap_iw_handler_def = { - .num_standard = sizeof(prism2_handler) / sizeof(iw_handler), - .num_private = sizeof(prism2_private_handler) / sizeof(iw_handler), - .num_private_args = sizeof(prism2_priv) / sizeof(struct iw_priv_args), + .num_standard = ARRAY_SIZE(prism2_handler), + .num_private = ARRAY_SIZE(prism2_private_handler), + .num_private_args = ARRAY_SIZE(prism2_priv), .standard = (iw_handler *) prism2_handler, .private = (iw_handler *) prism2_private_handler, .private_args = (struct iw_priv_args *) prism2_priv, diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index 12a6887cb9f..b3c07b93afc 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -8277,10 +8277,9 @@ static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device *dev) static struct iw_handler_def ipw2100_wx_handler_def = { .standard = ipw2100_wx_handlers, - .num_standard = sizeof(ipw2100_wx_handlers) / sizeof(iw_handler), - .num_private = sizeof(ipw2100_private_handler) / sizeof(iw_handler), - .num_private_args = sizeof(ipw2100_private_args) / - sizeof(struct iw_priv_args), + .num_standard = ARRAY_SIZE(ipw2100_wx_handlers), + .num_private = ARRAY_SIZE(ipw2100_private_handler), + .num_private_args = ARRAY_SIZE(ipw2100_private_args), .private = (iw_handler *) ipw2100_private_handler, .private_args = (struct iw_priv_args *)ipw2100_private_args, .get_wireless_stats = ipw2100_wx_wireless_stats, diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index cb0359df355..a54171af7b9 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -123,28 +123,28 @@ struct region_cfp_table { static struct region_cfp_table region_cfp_table[] = { {0x10, /*US FCC */ channel_freq_power_US_BG, - sizeof(channel_freq_power_US_BG) / sizeof(struct chan_freq_power), + ARRAY_SIZE(channel_freq_power_US_BG), } , {0x20, /*CANADA IC */ channel_freq_power_US_BG, - sizeof(channel_freq_power_US_BG) / sizeof(struct chan_freq_power), + ARRAY_SIZE(channel_freq_power_US_BG), } , {0x30, /*EU*/ channel_freq_power_EU_BG, - sizeof(channel_freq_power_EU_BG) / sizeof(struct chan_freq_power), + ARRAY_SIZE(channel_freq_power_EU_BG), } , {0x31, /*SPAIN*/ channel_freq_power_SPN_BG, - sizeof(channel_freq_power_SPN_BG) / sizeof(struct chan_freq_power), + ARRAY_SIZE(channel_freq_power_SPN_BG), } , {0x32, /*FRANCE*/ channel_freq_power_FR_BG, - sizeof(channel_freq_power_FR_BG) / sizeof(struct chan_freq_power), + ARRAY_SIZE(channel_freq_power_FR_BG), } , {0x40, /*JAPAN*/ channel_freq_power_JPN_BG, - sizeof(channel_freq_power_JPN_BG) / sizeof(struct chan_freq_power), + ARRAY_SIZE(channel_freq_power_JPN_BG), } , /*Add new region here */ @@ -1422,7 +1422,7 @@ struct chan_freq_power *libertas_get_region_cfp_table(u8 region, u8 band, int *c lbs_deb_enter(LBS_DEB_MAIN); - end = sizeof(region_cfp_table)/sizeof(struct region_cfp_table); + end = ARRAY_SIZE(region_cfp_table); for (i = 0; i < end ; i++) { lbs_deb_main("region_cfp_table[i].region=%d\n", diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 3f628223bc6..f8036efd729 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -2149,13 +2149,13 @@ static const iw_handler mesh_wlan_handler[] = { (iw_handler) NULL, /* SIOCSIWPMKSA */ }; struct iw_handler_def libertas_handler_def = { - .num_standard = sizeof(wlan_handler) / sizeof(iw_handler), + .num_standard = ARRAY_SIZE(wlan_handler), .standard = (iw_handler *) wlan_handler, .get_wireless_stats = wlan_get_wireless_stats, }; struct iw_handler_def mesh_handler_def = { - .num_standard = sizeof(mesh_wlan_handler) / sizeof(iw_handler), + .num_standard = ARRAY_SIZE(mesh_wlan_handler), .standard = (iw_handler *) mesh_wlan_handler, .get_wireless_stats = wlan_get_wireless_stats, }; diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c index 389fdd313c7..d8a59afa717 100644 --- a/drivers/net/wireless/netwave_cs.c +++ b/drivers/net/wireless/netwave_cs.c @@ -709,9 +709,9 @@ static const iw_handler netwave_private_handler[] = static const struct iw_handler_def netwave_handler_def = { - .num_standard = sizeof(netwave_handler)/sizeof(iw_handler), - .num_private = sizeof(netwave_private_handler)/sizeof(iw_handler), - .num_private_args = sizeof(netwave_private_args)/sizeof(struct iw_priv_args), + .num_standard = ARRAY_SIZE(netwave_handler), + .num_private = ARRAY_SIZE(netwave_private_handler), + .num_private_args = ARRAY_SIZE(netwave_private_args), .standard = (iw_handler *) netwave_handler, .private = (iw_handler *) netwave_private_handler, .private_args = (struct iw_priv_args *) netwave_private_args, diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c index f1066614dc3..77ea13bf0c0 100644 --- a/drivers/net/wireless/prism54/isl_ioctl.c +++ b/drivers/net/wireless/prism54/isl_ioctl.c @@ -3239,10 +3239,9 @@ static const iw_handler prism54_private_handler[] = { }; const struct iw_handler_def prism54_handler_def = { - .num_standard = sizeof (prism54_handler) / sizeof (iw_handler), - .num_private = sizeof (prism54_private_handler) / sizeof (iw_handler), - .num_private_args = - sizeof (prism54_private_args) / sizeof (struct iw_priv_args), + .num_standard = ARRAY_SIZE(prism54_handler), + .num_private = ARRAY_SIZE(prism54_private_handler), + .num_private_args = ARRAY_SIZE(prism54_private_args), .standard = (iw_handler *) prism54_handler, .private = (iw_handler *) prism54_private_handler, .private_args = (struct iw_priv_args *) prism54_private_args, diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 1b0e9707049..429bca8d0b5 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -1567,9 +1567,9 @@ static const struct iw_priv_args ray_private_args[] = { static const struct iw_handler_def ray_handler_def = { - .num_standard = sizeof(ray_handler)/sizeof(iw_handler), - .num_private = sizeof(ray_private_handler)/sizeof(iw_handler), - .num_private_args = sizeof(ray_private_args)/sizeof(struct iw_priv_args), + .num_standard = ARRAY_SIZE(ray_handler), + .num_private = ARRAY_SIZE(ray_private_handler), + .num_private_args = ARRAY_SIZE(ray_private_args), .standard = ray_handler, .private = ray_private_handler, .private_args = ray_private_args, diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c index b876bf65935..33ed9fe95f3 100644 --- a/drivers/net/wireless/wavelan.c +++ b/drivers/net/wireless/wavelan.c @@ -2400,9 +2400,9 @@ static const struct iw_priv_args wavelan_private_args[] = { static const struct iw_handler_def wavelan_handler_def = { - .num_standard = sizeof(wavelan_handler)/sizeof(iw_handler), - .num_private = sizeof(wavelan_private_handler)/sizeof(iw_handler), - .num_private_args = sizeof(wavelan_private_args)/sizeof(struct iw_priv_args), + .num_standard = ARRAY_SIZE(wavelan_handler), + .num_private = ARRAY_SIZE(wavelan_private_handler), + .num_private_args = ARRAY_SIZE(wavelan_private_args), .standard = wavelan_handler, .private = wavelan_private_handler, .private_args = wavelan_private_args, diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index 1cc5180ab1e..9b7f4495786 100644 --- a/drivers/net/wireless/wavelan_cs.c +++ b/drivers/net/wireless/wavelan_cs.c @@ -2719,9 +2719,9 @@ static const iw_handler wavelan_private_handler[] = static const struct iw_handler_def wavelan_handler_def = { - .num_standard = sizeof(wavelan_handler)/sizeof(iw_handler), - .num_private = sizeof(wavelan_private_handler)/sizeof(iw_handler), - .num_private_args = sizeof(wavelan_private_args)/sizeof(struct iw_priv_args), + .num_standard = ARRAY_SIZE(wavelan_handler), + .num_private = ARRAY_SIZE(wavelan_private_handler), + .num_private_args = ARRAY_SIZE(wavelan_private_args), .standard = wavelan_handler, .private = wavelan_private_handler, .private_args = wavelan_private_args, diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index cfde68cff94..2690f291e3f 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -1893,7 +1893,7 @@ static const iw_handler wl3501_handler[] = { }; static const struct iw_handler_def wl3501_handler_def = { - .num_standard = sizeof(wl3501_handler) / sizeof(iw_handler), + .num_standard = ARRAY_SIZE(wl3501_handler), .standard = (iw_handler *)wl3501_handler, .get_wireless_stats = wl3501_get_wireless_stats, }; diff --git a/drivers/net/zorro8390.c b/drivers/net/zorro8390.c index a45f9952a3f..fb215eb6dcf 100644 --- a/drivers/net/zorro8390.c +++ b/drivers/net/zorro8390.c @@ -190,7 +190,7 @@ static int __devinit zorro8390_init(struct net_device *dev, {0x00, NE_EN0_RSARHI}, {E8390_RREAD+E8390_START, NE_CMD}, }; - for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++) { + for (i = 0; i < ARRAY_SIZE(program_seq); i++) { z_writeb(program_seq[i].value, ioaddr + program_seq[i].offset); } } -- cgit v1.2.3-70-g09d2 From 09f75cd7bf13720738e6a196cc0107ce9a5bd5a0 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 3 Oct 2007 17:41:50 -0700 Subject: [NET] drivers/net: statistics cleanup #1 -- save memory and shrink code We now have struct net_device_stats embedded in struct net_device, and the default ->get_stats() hook does the obvious thing for us. Run through drivers/net/* and remove the driver-local storage of statistics, and driver-local ->get_stats() hook where applicable. This was just the low-hanging fruit in drivers/net; plenty more drivers remain to be updated. [ Resolved conflicts with napi_struct changes and fix sunqe build regression... -DaveM ] Signed-off-by: Jeff Garzik Signed-off-by: David S. Miller --- drivers/net/3c501.c | 41 +++++------------- drivers/net/3c501.h | 2 - drivers/net/3c507.c | 52 ++++++++-------------- drivers/net/7990.c | 47 +++++++++----------- drivers/net/7990.h | 2 - drivers/net/82596.c | 65 ++++++++++++---------------- drivers/net/a2065.c | 51 +++++++++------------- drivers/net/at1700.c | 39 ++++++----------- drivers/net/atarilance.c | 58 +++++++++---------------- drivers/net/atp.c | 49 ++++++++------------- drivers/net/au1000_eth.c | 23 ++-------- drivers/net/au1000_eth.h | 1 - drivers/net/bfin_mac.c | 25 +++-------- drivers/net/bfin_mac.h | 2 - drivers/net/bmac.c | 48 ++++++++------------- drivers/net/de600.c | 15 ++----- drivers/net/de600.h | 1 - drivers/net/de620.c | 26 +++-------- drivers/net/declance.c | 52 +++++++++------------- drivers/net/depca.c | 42 +++++++----------- drivers/net/dgrs.c | 24 ++--------- drivers/net/dm9000.c | 29 +++---------- drivers/net/e100.c | 23 ++++------ drivers/net/eepro.c | 47 ++++++++------------ drivers/net/eexpress.c | 56 +++++++++--------------- drivers/net/eql.c | 12 +----- drivers/net/eth16i.c | 49 ++++++++------------- drivers/net/ewrk3.c | 37 ++++++---------- drivers/net/fec.c | 50 +++++++++------------ drivers/net/gianfar.c | 40 +++++++---------- drivers/net/hplance.c | 1 - drivers/net/ibmlana.c | 37 ++++++---------- drivers/net/ibmlana.h | 1 - drivers/net/ibmveth.c | 18 +++----- drivers/net/ifb.c | 20 +-------- drivers/net/iseries_veth.c | 23 +++------- drivers/net/lib82596.c | 64 ++++++++++++--------------- drivers/net/lp486e.c | 56 ++++++++++-------------- drivers/net/mace.c | 59 +++++++++++-------------- drivers/net/macmace.c | 49 ++++++++------------- drivers/net/meth.c | 28 +++++------- drivers/net/mipsnet.c | 26 +++-------- drivers/net/mv643xx_eth.c | 25 ++--------- drivers/net/myri_sbus.c | 20 ++++----- drivers/net/myri_sbus.h | 1 - drivers/net/netx-eth.c | 18 +++----- drivers/net/ni5010.c | 47 ++++++-------------- drivers/net/pasemi_mac.c | 17 ++------ drivers/net/pasemi_mac.h | 1 - drivers/net/pci-skeleton.c | 74 ++++++++++---------------------- drivers/net/plip.c | 32 +++++--------- drivers/net/qla3xxx.c | 23 ++++------ drivers/net/qla3xxx.h | 1 - drivers/net/rionet.c | 20 +++------ drivers/net/rrunner.c | 31 +++++-------- drivers/net/rrunner.h | 2 - drivers/net/saa9730.c | 93 ++++++++++++++++++--------------------- drivers/net/saa9730.h | 1 - drivers/net/sb1000.c | 19 +++----- drivers/net/sb1250-mac.c | 39 +++++------------ drivers/net/seeq8005.c | 33 +++++--------- drivers/net/sgiseeq.c | 39 ++++++----------- drivers/net/shaper.c | 15 ++----- drivers/net/sis190.c | 19 +++----- drivers/net/sis900.c | 56 ++++++++---------------- drivers/net/smc911x.c | 77 ++++++++++++--------------------- drivers/net/smc9194.c | 59 ++++++++----------------- drivers/net/smc91x.c | 69 +++++++++++------------------ drivers/net/spider_net.c | 49 +++++++-------------- drivers/net/spider_net.h | 1 - drivers/net/sun3lance.c | 53 +++++++++-------------- drivers/net/sunlance.c | 87 +++++++++++++++++-------------------- drivers/net/sunqe.c | 105 +++++++++++++++++++++------------------------ drivers/net/sunqe.h | 1 - drivers/net/tun.c | 23 ++++------ drivers/net/ucc_geth.c | 27 ++++-------- drivers/net/ucc_geth.h | 1 - drivers/net/xen-netfront.c | 27 ++++-------- drivers/net/yellowfin.c | 63 +++++++++++---------------- drivers/net/znet.c | 50 ++++++++------------- include/linux/if_eql.h | 1 - include/linux/if_shaper.h | 1 - include/linux/if_tun.h | 1 - 83 files changed, 948 insertions(+), 1763 deletions(-) (limited to 'drivers') diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c index 98e0bc4628a..be71868d151 100644 --- a/drivers/net/3c501.c +++ b/drivers/net/3c501.c @@ -315,7 +315,6 @@ static int __init el1_probe1(struct net_device *dev, int ioaddr) dev->tx_timeout = &el_timeout; dev->watchdog_timeo = HZ; dev->stop = &el1_close; - dev->get_stats = &el1_get_stats; dev->set_multicast_list = &set_multicast_list; dev->ethtool_ops = &netdev_ethtool_ops; return 0; @@ -374,7 +373,7 @@ static void el_timeout(struct net_device *dev) if (el_debug) printk (KERN_DEBUG "%s: transmit timed out, txsr %#2x axsr=%02x rxsr=%02x.\n", dev->name, inb(TX_STATUS), inb(AX_STATUS), inb(RX_STATUS)); - lp->stats.tx_errors++; + dev->stats.tx_errors++; outb(TX_NORM, TX_CMD); outb(RX_NORM, RX_CMD); outb(AX_OFF, AX_CMD); /* Just trigger a false interrupt. */ @@ -441,7 +440,7 @@ static int el_start_xmit(struct sk_buff *skb, struct net_device *dev) lp->tx_pkt_start = gp_start; lp->collisions = 0; - lp->stats.tx_bytes += skb->len; + dev->stats.tx_bytes += skb->len; /* * Command mode with status cleared should [in theory] @@ -588,7 +587,7 @@ static irqreturn_t el_interrupt(int irq, void *dev_id) printk (KERN_DEBUG "%s: Transmit failed 16 times, Ethernet jammed?\n",dev->name); outb(AX_SYS, AX_CMD); lp->txing = 0; - lp->stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; netif_wake_queue(dev); } else if (txsr & TX_COLLISION) @@ -606,7 +605,7 @@ static irqreturn_t el_interrupt(int irq, void *dev_id) outb(AX_SYS, AX_CMD); outw(lp->tx_pkt_start, GP_LOW); outb(AX_XMIT, AX_CMD); - lp->stats.collisions++; + dev->stats.collisions++; spin_unlock(&lp->lock); goto out; } @@ -615,7 +614,7 @@ static irqreturn_t el_interrupt(int irq, void *dev_id) /* * It worked.. we will now fall through and receive */ - lp->stats.tx_packets++; + dev->stats.tx_packets++; if (el_debug > 6) printk(KERN_DEBUG " Tx succeeded %s\n", (txsr & TX_RDY) ? "." : "but tx is busy!"); @@ -640,10 +639,10 @@ static irqreturn_t el_interrupt(int irq, void *dev_id) * Just reading rx_status fixes most errors. */ if (rxsr & RX_MISSED) - lp->stats.rx_missed_errors++; + dev->stats.rx_missed_errors++; else if (rxsr & RX_RUNT) { /* Handled to avoid board lock-up. */ - lp->stats.rx_length_errors++; + dev->stats.rx_length_errors++; if (el_debug > 5) printk(KERN_DEBUG " runt.\n"); } @@ -694,7 +693,6 @@ out: static void el_receive(struct net_device *dev) { - struct net_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; int pkt_len; struct sk_buff *skb; @@ -708,7 +706,7 @@ static void el_receive(struct net_device *dev) { if (el_debug) printk(KERN_DEBUG "%s: bogus packet, length=%d\n", dev->name, pkt_len); - lp->stats.rx_over_errors++; + dev->stats.rx_over_errors++; return; } @@ -727,7 +725,7 @@ static void el_receive(struct net_device *dev) if (skb == NULL) { printk(KERN_INFO "%s: Memory squeeze, dropping packet.\n", dev->name); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; return; } else @@ -742,8 +740,8 @@ static void el_receive(struct net_device *dev) skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); dev->last_rx = jiffies; - lp->stats.rx_packets++; - lp->stats.rx_bytes+=pkt_len; + dev->stats.rx_packets++; + dev->stats.rx_bytes+=pkt_len; } return; } @@ -810,23 +808,6 @@ static int el1_close(struct net_device *dev) return 0; } -/** - * el1_get_stats: - * @dev: The card to get the statistics for - * - * In smarter devices this function is needed to pull statistics off the - * board itself. The 3c501 has no hardware statistics. We maintain them all - * so they are by definition always up to date. - * - * Returns the statistics for the card from the card private data - */ - -static struct net_device_stats *el1_get_stats(struct net_device *dev) -{ - struct net_local *lp = netdev_priv(dev); - return &lp->stats; -} - /** * set_multicast_list: * @dev: The device to adjust diff --git a/drivers/net/3c501.h b/drivers/net/3c501.h index c56a2c62f7d..cfec64efff7 100644 --- a/drivers/net/3c501.h +++ b/drivers/net/3c501.h @@ -11,7 +11,6 @@ static irqreturn_t el_interrupt(int irq, void *dev_id); static void el_receive(struct net_device *dev); static void el_reset(struct net_device *dev); static int el1_close(struct net_device *dev); -static struct net_device_stats *el1_get_stats(struct net_device *dev); static void set_multicast_list(struct net_device *dev); static const struct ethtool_ops netdev_ethtool_ops; @@ -29,7 +28,6 @@ static int el_debug = EL_DEBUG; struct net_local { - struct net_device_stats stats; int tx_pkt_start; /* The length of the current Tx packet. */ int collisions; /* Tx collisions this packet */ int loading; /* Spot buffer load collisions */ diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c index fac6edff2b8..3d06271c3a8 100644 --- a/drivers/net/3c507.c +++ b/drivers/net/3c507.c @@ -118,7 +118,6 @@ enum commands { /* Information that need to be kept for each board. */ struct net_local { - struct net_device_stats stats; int last_restart; ushort rx_head; ushort rx_tail; @@ -289,7 +288,6 @@ static int el16_send_packet(struct sk_buff *skb, struct net_device *dev); static irqreturn_t el16_interrupt(int irq, void *dev_id); static void el16_rx(struct net_device *dev); static int el16_close(struct net_device *dev); -static struct net_device_stats *el16_get_stats(struct net_device *dev); static void el16_tx_timeout (struct net_device *dev); static void hardware_send_packet(struct net_device *dev, void *buf, short length, short pad); @@ -455,7 +453,6 @@ static int __init el16_probe1(struct net_device *dev, int ioaddr) dev->open = el16_open; dev->stop = el16_close; dev->hard_start_xmit = el16_send_packet; - dev->get_stats = el16_get_stats; dev->tx_timeout = el16_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; dev->ethtool_ops = &netdev_ethtool_ops; @@ -489,7 +486,7 @@ static void el16_tx_timeout (struct net_device *dev) readw(shmem + iSCB_STATUS) & 0x8000 ? "IRQ conflict" : "network cable problem"); /* Try to restart the adaptor. */ - if (lp->last_restart == lp->stats.tx_packets) { + if (lp->last_restart == dev->stats.tx_packets) { if (net_debug > 1) printk ("Resetting board.\n"); /* Completely reset the adaptor. */ @@ -501,7 +498,7 @@ static void el16_tx_timeout (struct net_device *dev) printk ("Kicking board.\n"); writew(0xf000 | CUC_START | RX_START, shmem + iSCB_CMD); outb (0, ioaddr + SIGNAL_CA); /* Issue channel-attn. */ - lp->last_restart = lp->stats.tx_packets; + lp->last_restart = dev->stats.tx_packets; } dev->trans_start = jiffies; netif_wake_queue (dev); @@ -520,7 +517,7 @@ static int el16_send_packet (struct sk_buff *skb, struct net_device *dev) spin_lock_irqsave (&lp->lock, flags); - lp->stats.tx_bytes += length; + dev->stats.tx_bytes += length; /* Disable the 82586's input to the interrupt line. */ outb (0x80, ioaddr + MISC_CTRL); @@ -579,14 +576,14 @@ static irqreturn_t el16_interrupt(int irq, void *dev_id) } /* Tx unsuccessful or some interesting status bit set. */ if (!(tx_status & 0x2000) || (tx_status & 0x0f3f)) { - lp->stats.tx_errors++; - if (tx_status & 0x0600) lp->stats.tx_carrier_errors++; - if (tx_status & 0x0100) lp->stats.tx_fifo_errors++; - if (!(tx_status & 0x0040)) lp->stats.tx_heartbeat_errors++; - if (tx_status & 0x0020) lp->stats.tx_aborted_errors++; - lp->stats.collisions += tx_status & 0xf; + dev->stats.tx_errors++; + if (tx_status & 0x0600) dev->stats.tx_carrier_errors++; + if (tx_status & 0x0100) dev->stats.tx_fifo_errors++; + if (!(tx_status & 0x0040)) dev->stats.tx_heartbeat_errors++; + if (tx_status & 0x0020) dev->stats.tx_aborted_errors++; + dev->stats.collisions += tx_status & 0xf; } - lp->stats.tx_packets++; + dev->stats.tx_packets++; if (net_debug > 5) printk("Reaped %x, Tx status %04x.\n" , lp->tx_reap, tx_status); lp->tx_reap += TX_BUF_SIZE; @@ -665,17 +662,6 @@ static int el16_close(struct net_device *dev) return 0; } -/* Get the current statistics. This may be called with the card open or - closed. */ -static struct net_device_stats *el16_get_stats(struct net_device *dev) -{ - struct net_local *lp = netdev_priv(dev); - - /* ToDo: decide if there are any useful statistics from the SCB. */ - - return &lp->stats; -} - /* Initialize the Rx-block list. */ static void init_rx_bufs(struct net_device *dev) { @@ -852,12 +838,12 @@ static void el16_rx(struct net_device *dev) pkt_len); } else if ((frame_status & 0x2000) == 0) { /* Frame Rxed, but with error. */ - lp->stats.rx_errors++; - if (frame_status & 0x0800) lp->stats.rx_crc_errors++; - if (frame_status & 0x0400) lp->stats.rx_frame_errors++; - if (frame_status & 0x0200) lp->stats.rx_fifo_errors++; - if (frame_status & 0x0100) lp->stats.rx_over_errors++; - if (frame_status & 0x0080) lp->stats.rx_length_errors++; + dev->stats.rx_errors++; + if (frame_status & 0x0800) dev->stats.rx_crc_errors++; + if (frame_status & 0x0400) dev->stats.rx_frame_errors++; + if (frame_status & 0x0200) dev->stats.rx_fifo_errors++; + if (frame_status & 0x0100) dev->stats.rx_over_errors++; + if (frame_status & 0x0080) dev->stats.rx_length_errors++; } else { /* Malloc up new buffer. */ struct sk_buff *skb; @@ -866,7 +852,7 @@ static void el16_rx(struct net_device *dev) skb = dev_alloc_skb(pkt_len+2); if (skb == NULL) { printk("%s: Memory squeeze, dropping packet.\n", dev->name); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; break; } @@ -878,8 +864,8 @@ static void el16_rx(struct net_device *dev) skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); dev->last_rx = jiffies; - lp->stats.rx_packets++; - lp->stats.rx_bytes += pkt_len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; } /* Clear the status word and set End-of-List on the rx frame. */ diff --git a/drivers/net/7990.c b/drivers/net/7990.c index e89ace109a5..224e0bff1ae 100644 --- a/drivers/net/7990.c +++ b/drivers/net/7990.c @@ -305,18 +305,18 @@ static int lance_rx (struct net_device *dev) /* We got an incomplete frame? */ if ((bits & LE_R1_POK) != LE_R1_POK) { - lp->stats.rx_over_errors++; - lp->stats.rx_errors++; + dev->stats.rx_over_errors++; + dev->stats.rx_errors++; continue; } else if (bits & LE_R1_ERR) { /* Count only the end frame as a rx error, * not the beginning */ - if (bits & LE_R1_BUF) lp->stats.rx_fifo_errors++; - if (bits & LE_R1_CRC) lp->stats.rx_crc_errors++; - if (bits & LE_R1_OFL) lp->stats.rx_over_errors++; - if (bits & LE_R1_FRA) lp->stats.rx_frame_errors++; - if (bits & LE_R1_EOP) lp->stats.rx_errors++; + if (bits & LE_R1_BUF) dev->stats.rx_fifo_errors++; + if (bits & LE_R1_CRC) dev->stats.rx_crc_errors++; + if (bits & LE_R1_OFL) dev->stats.rx_over_errors++; + if (bits & LE_R1_FRA) dev->stats.rx_frame_errors++; + if (bits & LE_R1_EOP) dev->stats.rx_errors++; } else { len = (rd->mblength & 0xfff) - 4; skb = dev_alloc_skb (len+2); @@ -324,7 +324,7 @@ static int lance_rx (struct net_device *dev) if (skb == 0) { printk ("%s: Memory squeeze, deferring packet.\n", dev->name); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; rd->mblength = 0; rd->rmd1_bits = LE_R1_OWN; lp->rx_new = (lp->rx_new + 1) & lp->rx_ring_mod_mask; @@ -339,8 +339,8 @@ static int lance_rx (struct net_device *dev) skb->protocol = eth_type_trans (skb, dev); netif_rx (skb); dev->last_rx = jiffies; - lp->stats.rx_packets++; - lp->stats.rx_bytes += len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += len; } /* Return the packet to the pool */ @@ -377,12 +377,12 @@ static int lance_tx (struct net_device *dev) if (td->tmd1_bits & LE_T1_ERR) { status = td->misc; - lp->stats.tx_errors++; - if (status & LE_T3_RTY) lp->stats.tx_aborted_errors++; - if (status & LE_T3_LCOL) lp->stats.tx_window_errors++; + dev->stats.tx_errors++; + if (status & LE_T3_RTY) dev->stats.tx_aborted_errors++; + if (status & LE_T3_LCOL) dev->stats.tx_window_errors++; if (status & LE_T3_CLOS) { - lp->stats.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; if (lp->auto_select) { lp->tpe = 1 - lp->tpe; printk("%s: Carrier Lost, trying %s\n", @@ -400,7 +400,7 @@ static int lance_tx (struct net_device *dev) /* buffer errors and underflows turn off the transmitter */ /* Restart the adapter */ if (status & (LE_T3_BUF|LE_T3_UFL)) { - lp->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; printk ("%s: Tx: ERR_BUF|ERR_UFL, restarting\n", dev->name); @@ -420,13 +420,13 @@ static int lance_tx (struct net_device *dev) /* One collision before packet was sent. */ if (td->tmd1_bits & LE_T1_EONE) - lp->stats.collisions++; + dev->stats.collisions++; /* More than one collision, be optimistic. */ if (td->tmd1_bits & LE_T1_EMORE) - lp->stats.collisions += 2; + dev->stats.collisions += 2; - lp->stats.tx_packets++; + dev->stats.tx_packets++; } j = (j + 1) & lp->tx_ring_mod_mask; @@ -471,9 +471,9 @@ lance_interrupt (int irq, void *dev_id) /* Log misc errors. */ if (csr0 & LE_C0_BABL) - lp->stats.tx_errors++; /* Tx babble. */ + dev->stats.tx_errors++; /* Tx babble. */ if (csr0 & LE_C0_MISS) - lp->stats.rx_errors++; /* Missed a Rx frame. */ + dev->stats.rx_errors++; /* Missed a Rx frame. */ if (csr0 & LE_C0_MERR) { printk("%s: Bus master arbitration failure, status %4.4x.\n", dev->name, csr0); @@ -589,13 +589,6 @@ int lance_start_xmit (struct sk_buff *skb, struct net_device *dev) return 0; } -struct net_device_stats *lance_get_stats (struct net_device *dev) -{ - struct lance_private *lp = netdev_priv(dev); - - return &lp->stats; -} - /* taken from the depca driver via a2065.c */ static void lance_load_multicast (struct net_device *dev) { diff --git a/drivers/net/7990.h b/drivers/net/7990.h index b1212b5ed92..0a5837b9642 100644 --- a/drivers/net/7990.h +++ b/drivers/net/7990.h @@ -111,7 +111,6 @@ struct lance_private int lance_log_rx_bufs, lance_log_tx_bufs; int rx_ring_mod_mask, tx_ring_mod_mask; - struct net_device_stats stats; int tpe; /* TPE is selected */ int auto_select; /* cable-selection is by carrier */ unsigned short busmaster_regval; @@ -246,7 +245,6 @@ struct lance_private extern int lance_open(struct net_device *dev); extern int lance_close (struct net_device *dev); extern int lance_start_xmit (struct sk_buff *skb, struct net_device *dev); -extern struct net_device_stats *lance_get_stats (struct net_device *dev); extern void lance_set_multicast (struct net_device *dev); extern void lance_tx_timeout(struct net_device *dev); #ifdef CONFIG_NET_POLL_CONTROLLER diff --git a/drivers/net/82596.c b/drivers/net/82596.c index 43dffdca708..6b03416731d 100644 --- a/drivers/net/82596.c +++ b/drivers/net/82596.c @@ -326,7 +326,6 @@ struct i596_private { struct i596_cmd *cmd_head; int cmd_backlog; unsigned long last_cmd; - struct net_device_stats stats; struct i596_rfd rfds[RX_RING_SIZE]; struct i596_rbd rbds[RX_RING_SIZE]; struct tx_cmd tx_cmds[TX_RING_SIZE]; @@ -360,7 +359,6 @@ static int i596_open(struct net_device *dev); static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev); static irqreturn_t i596_interrupt(int irq, void *dev_id); static int i596_close(struct net_device *dev); -static struct net_device_stats *i596_get_stats(struct net_device *dev); static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd); static void i596_tx_timeout (struct net_device *dev); static void print_eth(unsigned char *buf, char *str); @@ -828,7 +826,7 @@ memory_squeeze: if (skb == NULL) { /* XXX tulip.c can defer packets here!! */ printk(KERN_WARNING "%s: i596_rx Memory squeeze, dropping packet.\n", dev->name); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; } else { if (!rx_in_place) { @@ -844,28 +842,28 @@ memory_squeeze: #endif netif_rx(skb); dev->last_rx = jiffies; - lp->stats.rx_packets++; - lp->stats.rx_bytes+=pkt_len; + dev->stats.rx_packets++; + dev->stats.rx_bytes+=pkt_len; } } else { DEB(DEB_ERRORS, printk(KERN_DEBUG "%s: Error, rfd.stat = 0x%04x\n", dev->name, rfd->stat)); - lp->stats.rx_errors++; + dev->stats.rx_errors++; if ((rfd->stat) & 0x0001) - lp->stats.collisions++; + dev->stats.collisions++; if ((rfd->stat) & 0x0080) - lp->stats.rx_length_errors++; + dev->stats.rx_length_errors++; if ((rfd->stat) & 0x0100) - lp->stats.rx_over_errors++; + dev->stats.rx_over_errors++; if ((rfd->stat) & 0x0200) - lp->stats.rx_fifo_errors++; + dev->stats.rx_fifo_errors++; if ((rfd->stat) & 0x0400) - lp->stats.rx_frame_errors++; + dev->stats.rx_frame_errors++; if ((rfd->stat) & 0x0800) - lp->stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; if ((rfd->stat) & 0x1000) - lp->stats.rx_length_errors++; + dev->stats.rx_length_errors++; } /* Clear the buffer descriptor count and EOF + F flags */ @@ -916,8 +914,8 @@ static void i596_cleanup_cmd(struct net_device *dev, struct i596_private *lp) dev_kfree_skb(skb); - lp->stats.tx_errors++; - lp->stats.tx_aborted_errors++; + dev->stats.tx_errors++; + dev->stats.tx_aborted_errors++; ptr->v_next = ptr->b_next = I596_NULL; tx_cmd->cmd.command = 0; /* Mark as free */ @@ -1038,10 +1036,10 @@ static void i596_tx_timeout (struct net_device *dev) DEB(DEB_ERRORS,printk(KERN_ERR "%s: transmit timed out, status resetting.\n", dev->name)); - lp->stats.tx_errors++; + dev->stats.tx_errors++; /* Try to restart the adaptor */ - if (lp->last_restart == lp->stats.tx_packets) { + if (lp->last_restart == dev->stats.tx_packets) { DEB(DEB_ERRORS,printk(KERN_ERR "Resetting board.\n")); /* Shutdown and restart */ i596_reset (dev, lp, ioaddr); @@ -1050,7 +1048,7 @@ static void i596_tx_timeout (struct net_device *dev) DEB(DEB_ERRORS,printk(KERN_ERR "Kicking board.\n")); lp->scb.command = CUC_START | RX_START; CA (dev); - lp->last_restart = lp->stats.tx_packets; + lp->last_restart = dev->stats.tx_packets; } dev->trans_start = jiffies; @@ -1082,7 +1080,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev) if (tx_cmd->cmd.command) { printk(KERN_NOTICE "%s: xmit ring full, dropping packet.\n", dev->name); - lp->stats.tx_dropped++; + dev->stats.tx_dropped++; dev_kfree_skb(skb); } else { @@ -1107,8 +1105,8 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev) DEB(DEB_TXADDR,print_eth(skb->data, "tx-queued")); i596_add_cmd(dev, &tx_cmd->cmd); - lp->stats.tx_packets++; - lp->stats.tx_bytes += length; + dev->stats.tx_packets++; + dev->stats.tx_bytes += length; } netif_start_queue(dev); @@ -1237,7 +1235,6 @@ struct net_device * __init i82596_probe(int unit) dev->open = i596_open; dev->stop = i596_close; dev->hard_start_xmit = i596_start_xmit; - dev->get_stats = i596_get_stats; dev->set_multicast_list = set_multicast_list; dev->tx_timeout = i596_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; @@ -1343,17 +1340,17 @@ static irqreturn_t i596_interrupt(int irq, void *dev_id) if ((ptr->status) & STAT_OK) { DEB(DEB_TXADDR,print_eth(skb->data, "tx-done")); } else { - lp->stats.tx_errors++; + dev->stats.tx_errors++; if ((ptr->status) & 0x0020) - lp->stats.collisions++; + dev->stats.collisions++; if (!((ptr->status) & 0x0040)) - lp->stats.tx_heartbeat_errors++; + dev->stats.tx_heartbeat_errors++; if ((ptr->status) & 0x0400) - lp->stats.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; if ((ptr->status) & 0x0800) - lp->stats.collisions++; + dev->stats.collisions++; if ((ptr->status) & 0x1000) - lp->stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; } dev_kfree_skb_irq(skb); @@ -1408,8 +1405,8 @@ static irqreturn_t i596_interrupt(int irq, void *dev_id) if (netif_running(dev)) { DEB(DEB_ERRORS,printk(KERN_ERR "%s: i596 interrupt receive unit inactive, status 0x%x\n", dev->name, status)); ack_cmd |= RX_START; - lp->stats.rx_errors++; - lp->stats.rx_fifo_errors++; + dev->stats.rx_errors++; + dev->stats.rx_fifo_errors++; rebuild_rx_bufs(dev); } } @@ -1492,14 +1489,6 @@ static int i596_close(struct net_device *dev) return 0; } -static struct net_device_stats * - i596_get_stats(struct net_device *dev) -{ - struct i596_private *lp = dev->priv; - - return &lp->stats; -} - /* * Set or clear the multicast filter for this adaptor. */ diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c index fa0c6cb3d79..77773ce52ef 100644 --- a/drivers/net/a2065.c +++ b/drivers/net/a2065.c @@ -119,7 +119,6 @@ struct lance_private { int lance_log_rx_bufs, lance_log_tx_bufs; int rx_ring_mod_mask, tx_ring_mod_mask; - struct net_device_stats stats; int tpe; /* cable-selection is TPE */ int auto_select; /* cable-selection by carrier */ unsigned short busmaster_regval; @@ -294,18 +293,18 @@ static int lance_rx (struct net_device *dev) /* We got an incomplete frame? */ if ((bits & LE_R1_POK) != LE_R1_POK) { - lp->stats.rx_over_errors++; - lp->stats.rx_errors++; + dev->stats.rx_over_errors++; + dev->stats.rx_errors++; continue; } else if (bits & LE_R1_ERR) { /* Count only the end frame as a rx error, * not the beginning */ - if (bits & LE_R1_BUF) lp->stats.rx_fifo_errors++; - if (bits & LE_R1_CRC) lp->stats.rx_crc_errors++; - if (bits & LE_R1_OFL) lp->stats.rx_over_errors++; - if (bits & LE_R1_FRA) lp->stats.rx_frame_errors++; - if (bits & LE_R1_EOP) lp->stats.rx_errors++; + if (bits & LE_R1_BUF) dev->stats.rx_fifo_errors++; + if (bits & LE_R1_CRC) dev->stats.rx_crc_errors++; + if (bits & LE_R1_OFL) dev->stats.rx_over_errors++; + if (bits & LE_R1_FRA) dev->stats.rx_frame_errors++; + if (bits & LE_R1_EOP) dev->stats.rx_errors++; } else { len = (rd->mblength & 0xfff) - 4; skb = dev_alloc_skb (len+2); @@ -313,7 +312,7 @@ static int lance_rx (struct net_device *dev) if (skb == 0) { printk(KERN_WARNING "%s: Memory squeeze, " "deferring packet.\n", dev->name); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; rd->mblength = 0; rd->rmd1_bits = LE_R1_OWN; lp->rx_new = (lp->rx_new + 1) & lp->rx_ring_mod_mask; @@ -328,8 +327,8 @@ static int lance_rx (struct net_device *dev) skb->protocol = eth_type_trans (skb, dev); netif_rx (skb); dev->last_rx = jiffies; - lp->stats.rx_packets++; - lp->stats.rx_bytes += len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += len; } /* Return the packet to the pool */ @@ -364,12 +363,12 @@ static int lance_tx (struct net_device *dev) if (td->tmd1_bits & LE_T1_ERR) { status = td->misc; - lp->stats.tx_errors++; - if (status & LE_T3_RTY) lp->stats.tx_aborted_errors++; - if (status & LE_T3_LCOL) lp->stats.tx_window_errors++; + dev->stats.tx_errors++; + if (status & LE_T3_RTY) dev->stats.tx_aborted_errors++; + if (status & LE_T3_LCOL) dev->stats.tx_window_errors++; if (status & LE_T3_CLOS) { - lp->stats.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; if (lp->auto_select) { lp->tpe = 1 - lp->tpe; printk(KERN_ERR "%s: Carrier Lost, " @@ -388,7 +387,7 @@ static int lance_tx (struct net_device *dev) /* buffer errors and underflows turn off the transmitter */ /* Restart the adapter */ if (status & (LE_T3_BUF|LE_T3_UFL)) { - lp->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; printk(KERN_ERR "%s: Tx: ERR_BUF|ERR_UFL, " "restarting\n", dev->name); @@ -408,13 +407,13 @@ static int lance_tx (struct net_device *dev) /* One collision before packet was sent. */ if (td->tmd1_bits & LE_T1_EONE) - lp->stats.collisions++; + dev->stats.collisions++; /* More than one collision, be optimistic. */ if (td->tmd1_bits & LE_T1_EMORE) - lp->stats.collisions += 2; + dev->stats.collisions += 2; - lp->stats.tx_packets++; + dev->stats.tx_packets++; } j = (j + 1) & lp->tx_ring_mod_mask; @@ -459,9 +458,9 @@ static irqreturn_t lance_interrupt (int irq, void *dev_id) /* Log misc errors. */ if (csr0 & LE_C0_BABL) - lp->stats.tx_errors++; /* Tx babble. */ + dev->stats.tx_errors++; /* Tx babble. */ if (csr0 & LE_C0_MISS) - lp->stats.rx_errors++; /* Missed a Rx frame. */ + dev->stats.rx_errors++; /* Missed a Rx frame. */ if (csr0 & LE_C0_MERR) { printk(KERN_ERR "%s: Bus master arbitration failure, status " "%4.4x.\n", dev->name, csr0); @@ -606,7 +605,7 @@ static int lance_start_xmit (struct sk_buff *skb, struct net_device *dev) /* Now, give the packet to the lance */ ib->btx_ring [entry].tmd1_bits = (LE_T1_POK|LE_T1_OWN); lp->tx_new = (lp->tx_new+1) & lp->tx_ring_mod_mask; - lp->stats.tx_bytes += skblen; + dev->stats.tx_bytes += skblen; if (TX_BUFFS_AVAIL <= 0) netif_stop_queue(dev); @@ -621,13 +620,6 @@ static int lance_start_xmit (struct sk_buff *skb, struct net_device *dev) return status; } -static struct net_device_stats *lance_get_stats (struct net_device *dev) -{ - struct lance_private *lp = netdev_priv(dev); - - return &lp->stats; -} - /* taken from the depca driver */ static void lance_load_multicast (struct net_device *dev) { @@ -782,7 +774,6 @@ static int __devinit a2065_init_one(struct zorro_dev *z, dev->hard_start_xmit = &lance_start_xmit; dev->tx_timeout = &lance_tx_timeout; dev->watchdog_timeo = 5*HZ; - dev->get_stats = &lance_get_stats; dev->set_multicast_list = &lance_set_multicast; dev->dma = 0; diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c index d20148e69fa..a124fdb2bce 100644 --- a/drivers/net/at1700.c +++ b/drivers/net/at1700.c @@ -109,7 +109,6 @@ typedef unsigned char uchar; /* Information that need to be kept for each board. */ struct net_local { - struct net_device_stats stats; spinlock_t lock; unsigned char mc_filter[8]; uint jumpered:1; /* Set iff the board has jumper config. */ @@ -164,7 +163,6 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev); static irqreturn_t net_interrupt(int irq, void *dev_id); static void net_rx(struct net_device *dev); static int net_close(struct net_device *dev); -static struct net_device_stats *net_get_stats(struct net_device *dev); static void set_rx_mode(struct net_device *dev); static void net_tx_timeout (struct net_device *dev); @@ -456,7 +454,6 @@ found: dev->open = net_open; dev->stop = net_close; dev->hard_start_xmit = net_send_packet; - dev->get_stats = net_get_stats; dev->set_multicast_list = &set_rx_mode; dev->tx_timeout = net_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; @@ -571,7 +568,7 @@ static void net_tx_timeout (struct net_device *dev) dev->name, inw(ioaddr + TX_STATUS), inw(ioaddr + TX_INTR), inw(ioaddr + TX_MODE), inw(ioaddr + CONFIG_0), inw(ioaddr + DATAPORT), inw(ioaddr + TX_START), inw(ioaddr + MODE13 - 1), inw(ioaddr + RX_CTRL)); - lp->stats.tx_errors++; + dev->stats.tx_errors++; /* ToDo: We should try to restart the adaptor... */ outw(0xffff, ioaddr + MODE24); outw (0xffff, ioaddr + TX_STATUS); @@ -691,10 +688,10 @@ static irqreturn_t net_interrupt(int irq, void *dev_id) printk("%s: 16 Collision occur during Txing.\n", dev->name); /* Cancel sending a packet. */ outb(0x03, ioaddr + COL16CNTL); - lp->stats.collisions++; + dev->stats.collisions++; } if (status & 0x82) { - lp->stats.tx_packets++; + dev->stats.tx_packets++; /* The Tx queue has any packets and is not being transferred a packet from the host, start transmitting. */ @@ -719,7 +716,6 @@ static irqreturn_t net_interrupt(int irq, void *dev_id) static void net_rx(struct net_device *dev) { - struct net_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; int boguscount = 5; @@ -738,11 +734,11 @@ net_rx(struct net_device *dev) #endif if ((status & 0xF0) != 0x20) { /* There was an error. */ - lp->stats.rx_errors++; - if (status & 0x08) lp->stats.rx_length_errors++; - if (status & 0x04) lp->stats.rx_frame_errors++; - if (status & 0x02) lp->stats.rx_crc_errors++; - if (status & 0x01) lp->stats.rx_over_errors++; + dev->stats.rx_errors++; + if (status & 0x08) dev->stats.rx_length_errors++; + if (status & 0x04) dev->stats.rx_frame_errors++; + if (status & 0x02) dev->stats.rx_crc_errors++; + if (status & 0x01) dev->stats.rx_over_errors++; } else { /* Malloc up new buffer. */ struct sk_buff *skb; @@ -753,7 +749,7 @@ net_rx(struct net_device *dev) /* Prime the FIFO and then flush the packet. */ inw(ioaddr + DATAPORT); inw(ioaddr + DATAPORT); outb(0x05, ioaddr + RX_CTRL); - lp->stats.rx_errors++; + dev->stats.rx_errors++; break; } skb = dev_alloc_skb(pkt_len+3); @@ -763,7 +759,7 @@ net_rx(struct net_device *dev) /* Prime the FIFO and then flush the packet. */ inw(ioaddr + DATAPORT); inw(ioaddr + DATAPORT); outb(0x05, ioaddr + RX_CTRL); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; break; } skb_reserve(skb,2); @@ -772,8 +768,8 @@ net_rx(struct net_device *dev) skb->protocol=eth_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; - lp->stats.rx_packets++; - lp->stats.rx_bytes += pkt_len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; } if (--boguscount <= 0) break; @@ -822,17 +818,6 @@ static int net_close(struct net_device *dev) return 0; } -/* Get the current statistics. - This may be called with the card open or closed. - There are no on-chip counters, so this function is trivial. -*/ -static struct net_device_stats * -net_get_stats(struct net_device *dev) -{ - struct net_local *lp = netdev_priv(dev); - return &lp->stats; -} - /* Set the multicast/promiscuous mode for this adaptor. */ diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c index 17b9dbf7bd6..8bf548e1cb4 100644 --- a/drivers/net/atarilance.c +++ b/drivers/net/atarilance.c @@ -224,7 +224,6 @@ struct lance_private { int dirty_tx; /* Ring entries to be freed. */ /* copy function */ void *(*memcpy_f)( void *, const void *, size_t ); - struct net_device_stats stats; /* This must be long for set_bit() */ long tx_full; spinlock_t devlock; @@ -347,7 +346,6 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ); static irqreturn_t lance_interrupt( int irq, void *dev_id ); static int lance_rx( struct net_device *dev ); static int lance_close( struct net_device *dev ); -static struct net_device_stats *lance_get_stats( struct net_device *dev ); static void set_multicast_list( struct net_device *dev ); static int lance_set_mac_address( struct net_device *dev, void *addr ); static void lance_tx_timeout (struct net_device *dev); @@ -631,7 +629,6 @@ static unsigned long __init lance_probe1( struct net_device *dev, dev->open = &lance_open; dev->hard_start_xmit = &lance_start_xmit; dev->stop = &lance_close; - dev->get_stats = &lance_get_stats; dev->set_multicast_list = &set_multicast_list; dev->set_mac_address = &lance_set_mac_address; @@ -639,13 +636,6 @@ static unsigned long __init lance_probe1( struct net_device *dev, dev->tx_timeout = lance_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; - -#if 0 - dev->start = 0; -#endif - - memset( &lp->stats, 0, sizeof(lp->stats) ); - return( 1 ); } @@ -753,7 +743,7 @@ static void lance_tx_timeout (struct net_device *dev) * little endian mode. */ REGA( CSR3 ) = CSR3_BSWP | (lp->cardtype == PAM_CARD ? CSR3_ACON : 0); - lp->stats.tx_errors++; + dev->stats.tx_errors++; #ifndef final_version { int i; DPRINTK( 2, ( "Ring data: dirty_tx %d cur_tx %d%s cur_rx %d\n", @@ -841,7 +831,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) head->misc = 0; lp->memcpy_f( PKTBUF_ADDR(head), (void *)skb->data, skb->len ); head->flag = TMD1_OWN_CHIP | TMD1_ENP | TMD1_STP; - lp->stats.tx_bytes += skb->len; + dev->stats.tx_bytes += skb->len; dev_kfree_skb( skb ); lp->cur_tx++; while( lp->cur_tx >= TX_RING_SIZE && lp->dirty_tx >= TX_RING_SIZE ) { @@ -912,13 +902,13 @@ static irqreturn_t lance_interrupt( int irq, void *dev_id ) if (status & TMD1_ERR) { /* There was an major error, log it. */ int err_status = MEM->tx_head[entry].misc; - lp->stats.tx_errors++; - if (err_status & TMD3_RTRY) lp->stats.tx_aborted_errors++; - if (err_status & TMD3_LCAR) lp->stats.tx_carrier_errors++; - if (err_status & TMD3_LCOL) lp->stats.tx_window_errors++; + dev->stats.tx_errors++; + if (err_status & TMD3_RTRY) dev->stats.tx_aborted_errors++; + if (err_status & TMD3_LCAR) dev->stats.tx_carrier_errors++; + if (err_status & TMD3_LCOL) dev->stats.tx_window_errors++; if (err_status & TMD3_UFLO) { /* Ackk! On FIFO errors the Tx unit is turned off! */ - lp->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; /* Remove this verbosity later! */ DPRINTK( 1, ( "%s: Tx FIFO error! Status %04x\n", dev->name, csr0 )); @@ -927,8 +917,8 @@ static irqreturn_t lance_interrupt( int irq, void *dev_id ) } } else { if (status & (TMD1_MORE | TMD1_ONE | TMD1_DEF)) - lp->stats.collisions++; - lp->stats.tx_packets++; + dev->stats.collisions++; + dev->stats.tx_packets++; } /* XXX MSch: free skb?? */ @@ -955,8 +945,8 @@ static irqreturn_t lance_interrupt( int irq, void *dev_id ) } /* Log misc errors. */ - if (csr0 & CSR0_BABL) lp->stats.tx_errors++; /* Tx babble. */ - if (csr0 & CSR0_MISS) lp->stats.rx_errors++; /* Missed a Rx frame. */ + if (csr0 & CSR0_BABL) dev->stats.tx_errors++; /* Tx babble. */ + if (csr0 & CSR0_MISS) dev->stats.rx_errors++; /* Missed a Rx frame. */ if (csr0 & CSR0_MERR) { DPRINTK( 1, ( "%s: Bus master arbitration failure (?!?), " "status %04x.\n", dev->name, csr0 )); @@ -997,11 +987,11 @@ static int lance_rx( struct net_device *dev ) buffers it's possible for a jabber packet to use two buffers, with only the last correctly noting the error. */ if (status & RMD1_ENP) /* Only count a general error at the */ - lp->stats.rx_errors++; /* end of a packet.*/ - if (status & RMD1_FRAM) lp->stats.rx_frame_errors++; - if (status & RMD1_OFLO) lp->stats.rx_over_errors++; - if (status & RMD1_CRC) lp->stats.rx_crc_errors++; - if (status & RMD1_BUFF) lp->stats.rx_fifo_errors++; + dev->stats.rx_errors++; /* end of a packet.*/ + if (status & RMD1_FRAM) dev->stats.rx_frame_errors++; + if (status & RMD1_OFLO) dev->stats.rx_over_errors++; + if (status & RMD1_CRC) dev->stats.rx_crc_errors++; + if (status & RMD1_BUFF) dev->stats.rx_fifo_errors++; head->flag &= (RMD1_ENP|RMD1_STP); } else { /* Malloc up new buffer, compatible with net-3. */ @@ -1010,7 +1000,7 @@ static int lance_rx( struct net_device *dev ) if (pkt_len < 60) { printk( "%s: Runt packet!\n", dev->name ); - lp->stats.rx_errors++; + dev->stats.rx_errors++; } else { skb = dev_alloc_skb( pkt_len+2 ); @@ -1023,7 +1013,7 @@ static int lance_rx( struct net_device *dev ) break; if (i > RX_RING_SIZE - 2) { - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; head->flag |= RMD1_OWN_CHIP; lp->cur_rx++; } @@ -1052,8 +1042,8 @@ static int lance_rx( struct net_device *dev ) skb->protocol = eth_type_trans( skb, dev ); netif_rx( skb ); dev->last_rx = jiffies; - lp->stats.rx_packets++; - lp->stats.rx_bytes += pkt_len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; } } @@ -1090,14 +1080,6 @@ static int lance_close( struct net_device *dev ) } -static struct net_device_stats *lance_get_stats( struct net_device *dev ) - -{ struct lance_private *lp = (struct lance_private *)dev->priv; - - return &lp->stats; -} - - /* Set or clear the multicast filter for this adaptor. num_addrs == -1 Promiscuous mode, receive all packets num_addrs == 0 Normal mode, clear multicast list diff --git a/drivers/net/atp.c b/drivers/net/atp.c index 6020d5ec38b..cec2e3672cd 100644 --- a/drivers/net/atp.c +++ b/drivers/net/atp.c @@ -171,7 +171,6 @@ static char mux_8012[] = { 0xff, 0xf7, 0xff, 0xfb, 0xf3, 0xfb, 0xff, 0xf7,}; struct net_local { spinlock_t lock; struct net_device *next_module; - struct net_device_stats stats; struct timer_list timer; /* Media selection timer. */ long last_rx_time; /* Last Rx, in jiffies, to handle Rx hang. */ int saved_tx_size; @@ -205,7 +204,6 @@ static irqreturn_t atp_interrupt(int irq, void *dev_id); static void net_rx(struct net_device *dev); static void read_block(long ioaddr, int length, unsigned char *buffer, int data_mode); static int net_close(struct net_device *dev); -static struct net_device_stats *net_get_stats(struct net_device *dev); static void set_rx_mode_8002(struct net_device *dev); static void set_rx_mode_8012(struct net_device *dev); static void tx_timeout(struct net_device *dev); @@ -348,7 +346,6 @@ static int __init atp_probe1(long ioaddr) dev->open = net_open; dev->stop = net_close; dev->hard_start_xmit = atp_send_packet; - dev->get_stats = net_get_stats; dev->set_multicast_list = lp->chip_type == RTL8002 ? &set_rx_mode_8002 : &set_rx_mode_8012; dev->tx_timeout = tx_timeout; @@ -538,18 +535,17 @@ static void write_packet(long ioaddr, int length, unsigned char *packet, int pad static void tx_timeout(struct net_device *dev) { - struct net_local *np = netdev_priv(dev); long ioaddr = dev->base_addr; printk(KERN_WARNING "%s: Transmit timed out, %s?\n", dev->name, inb(ioaddr + PAR_CONTROL) & 0x10 ? "network cable problem" : "IRQ conflict"); - np->stats.tx_errors++; + dev->stats.tx_errors++; /* Try to restart the adapter. */ hardware_init(dev); dev->trans_start = jiffies; netif_wake_queue(dev); - np->stats.tx_errors++; + dev->stats.tx_errors++; } static int atp_send_packet(struct sk_buff *skb, struct net_device *dev) @@ -629,7 +625,7 @@ static irqreturn_t atp_interrupt(int irq, void *dev_instance) /* We acknowledged the normal Rx interrupt, so if the interrupt is still outstanding we must have a Rx error. */ if (read_status & (CMR1_IRQ << 3)) { /* Overrun. */ - lp->stats.rx_over_errors++; + dev->stats.rx_over_errors++; /* Set to no-accept mode long enough to remove a packet. */ write_reg_high(ioaddr, CMR2, CMR2h_OFF); net_rx(dev); @@ -649,9 +645,9 @@ static irqreturn_t atp_interrupt(int irq, void *dev_instance) and reinitialize the adapter. */ write_reg(ioaddr, ISR, ISR_TxErr + ISR_TxOK); if (status & (ISR_TxErr<<3)) { - lp->stats.collisions++; + dev->stats.collisions++; if (++lp->re_tx > 15) { - lp->stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; hardware_init(dev); break; } @@ -660,7 +656,7 @@ static irqreturn_t atp_interrupt(int irq, void *dev_instance) write_reg(ioaddr, CMR1, CMR1_ReXmit + CMR1_Xmit); } else { /* Finish up the transmit. */ - lp->stats.tx_packets++; + dev->stats.tx_packets++; lp->pac_cnt_in_tx_buf--; if ( lp->saved_tx_size) { trigger_send(ioaddr, lp->saved_tx_size); @@ -678,7 +674,7 @@ static irqreturn_t atp_interrupt(int irq, void *dev_instance) "%ld jiffies status %02x CMR1 %02x.\n", dev->name, num_tx_since_rx, jiffies - dev->last_rx, status, (read_nibble(ioaddr, CMR1) >> 3) & 15); - lp->stats.rx_missed_errors++; + dev->stats.rx_missed_errors++; hardware_init(dev); num_tx_since_rx = 0; break; @@ -735,13 +731,13 @@ static void atp_timed_checker(unsigned long data) struct net_local *lp = netdev_priv(atp_timed_dev); write_reg_byte(ioaddr, PAR0 + i, atp_timed_dev->dev_addr[i]); if (i == 2) - lp->stats.tx_errors++; + dev->stats.tx_errors++; else if (i == 3) - lp->stats.tx_dropped++; + dev->stats.tx_dropped++; else if (i == 4) - lp->stats.collisions++; + dev->stats.collisions++; else - lp->stats.rx_errors++; + dev->stats.rx_errors++; } #endif } @@ -765,14 +761,14 @@ static void net_rx(struct net_device *dev) printk(KERN_DEBUG " rx_count %04x %04x %04x %04x..", rx_head.pad, rx_head.rx_count, rx_head.rx_status, rx_head.cur_addr); if ((rx_head.rx_status & 0x77) != 0x01) { - lp->stats.rx_errors++; - if (rx_head.rx_status & 0x0004) lp->stats.rx_frame_errors++; - else if (rx_head.rx_status & 0x0002) lp->stats.rx_crc_errors++; + dev->stats.rx_errors++; + if (rx_head.rx_status & 0x0004) dev->stats.rx_frame_errors++; + else if (rx_head.rx_status & 0x0002) dev->stats.rx_crc_errors++; if (net_debug > 3) printk(KERN_DEBUG "%s: Unknown ATP Rx error %04x.\n", dev->name, rx_head.rx_status); if (rx_head.rx_status & 0x0020) { - lp->stats.rx_fifo_errors++; + dev->stats.rx_fifo_errors++; write_reg_high(ioaddr, CMR1, CMR1h_TxENABLE); write_reg_high(ioaddr, CMR1, CMR1h_RxENABLE | CMR1h_TxENABLE); } else if (rx_head.rx_status & 0x0050) @@ -787,7 +783,7 @@ static void net_rx(struct net_device *dev) if (skb == NULL) { printk(KERN_ERR "%s: Memory squeeze, dropping packet.\n", dev->name); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; goto done; } @@ -796,8 +792,8 @@ static void net_rx(struct net_device *dev) skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; - lp->stats.rx_packets++; - lp->stats.rx_bytes += pkt_len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; } done: write_reg(ioaddr, CMR1, CMR1_NextPkt); @@ -849,15 +845,6 @@ net_close(struct net_device *dev) return 0; } -/* Get the current statistics. This may be called with the card open or - closed. */ -static struct net_device_stats * -net_get_stats(struct net_device *dev) -{ - struct net_local *lp = netdev_priv(dev); - return &lp->stats; -} - /* * Set or clear the multicast filter for this adapter. */ diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c index e86b3691765..b46c5d8a77b 100644 --- a/drivers/net/au1000_eth.c +++ b/drivers/net/au1000_eth.c @@ -90,7 +90,6 @@ static int au1000_rx(struct net_device *); static irqreturn_t au1000_interrupt(int, void *); static void au1000_tx_timeout(struct net_device *); static void set_rx_mode(struct net_device *); -static struct net_device_stats *au1000_get_stats(struct net_device *); static int au1000_ioctl(struct net_device *, struct ifreq *, int); static int mdio_read(struct net_device *, int, int); static void mdio_write(struct net_device *, int, int, u16); @@ -772,7 +771,6 @@ static struct net_device * au1000_probe(int port_num) dev->open = au1000_open; dev->hard_start_xmit = au1000_tx; dev->stop = au1000_close; - dev->get_stats = au1000_get_stats; dev->set_multicast_list = &set_rx_mode; dev->do_ioctl = &au1000_ioctl; SET_ETHTOOL_OPS(dev, &au1000_ethtool_ops); @@ -1038,7 +1036,7 @@ static void __exit au1000_cleanup_module(void) static void update_tx_stats(struct net_device *dev, u32 status) { struct au1000_private *aup = (struct au1000_private *) dev->priv; - struct net_device_stats *ps = &aup->stats; + struct net_device_stats *ps = &dev->stats; if (status & TX_FRAME_ABORTED) { if (!aup->phy_dev || (DUPLEX_FULL == aup->phy_dev->duplex)) { @@ -1094,7 +1092,7 @@ static void au1000_tx_ack(struct net_device *dev) static int au1000_tx(struct sk_buff *skb, struct net_device *dev) { struct au1000_private *aup = (struct au1000_private *) dev->priv; - struct net_device_stats *ps = &aup->stats; + struct net_device_stats *ps = &dev->stats; volatile tx_dma_t *ptxd; u32 buff_stat; db_dest_t *pDB; @@ -1148,7 +1146,7 @@ static int au1000_tx(struct sk_buff *skb, struct net_device *dev) static inline void update_rx_stats(struct net_device *dev, u32 status) { struct au1000_private *aup = (struct au1000_private *) dev->priv; - struct net_device_stats *ps = &aup->stats; + struct net_device_stats *ps = &dev->stats; ps->rx_packets++; if (status & RX_MCAST_FRAME) @@ -1201,7 +1199,7 @@ static int au1000_rx(struct net_device *dev) printk(KERN_ERR "%s: Memory squeeze, dropping packet.\n", dev->name); - aup->stats.rx_dropped++; + dev->stats.rx_dropped++; continue; } skb_reserve(skb, 2); /* 16 byte IP header align */ @@ -1324,18 +1322,5 @@ static int au1000_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) return phy_mii_ioctl(aup->phy_dev, if_mii(rq), cmd); } -static struct net_device_stats *au1000_get_stats(struct net_device *dev) -{ - struct au1000_private *aup = (struct au1000_private *) dev->priv; - - if (au1000_debug > 4) - printk("%s: au1000_get_stats: dev=%p\n", dev->name, dev); - - if (netif_device_present(dev)) { - return &aup->stats; - } - return 0; -} - module_init(au1000_init_module); module_exit(au1000_cleanup_module); diff --git a/drivers/net/au1000_eth.h b/drivers/net/au1000_eth.h index 52fe00dd6d2..f3baeaa1285 100644 --- a/drivers/net/au1000_eth.h +++ b/drivers/net/au1000_eth.h @@ -115,6 +115,5 @@ struct au1000_private { u32 vaddr; /* virtual address of rx/tx buffers */ dma_addr_t dma_addr; /* dma address of rx/tx buffers */ - struct net_device_stats stats; spinlock_t lock; /* Serialise access to device */ }; diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c index e5bbcbe8de5..cebe55440e1 100644 --- a/drivers/net/bfin_mac.c +++ b/drivers/net/bfin_mac.c @@ -579,8 +579,8 @@ out: adjust_tx_list(); current_tx_ptr = current_tx_ptr->next; dev->trans_start = jiffies; - lp->stats.tx_packets++; - lp->stats.tx_bytes += (skb->len); + dev->stats.tx_packets++; + dev->stats.tx_bytes += (skb->len); return 0; } @@ -596,7 +596,7 @@ static void bf537mac_rx(struct net_device *dev) if (!new_skb) { printk(KERN_NOTICE DRV_NAME ": rx: low on mem - packet dropped\n"); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; goto out; } /* reserve 2 bytes for RXDWA padding */ @@ -618,8 +618,8 @@ static void bf537mac_rx(struct net_device *dev) #endif netif_rx(skb); - lp->stats.rx_packets++; - lp->stats.rx_bytes += len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += len; current_rx_ptr->status.status_word = 0x00000000; current_rx_ptr = current_rx_ptr->next; @@ -732,20 +732,6 @@ static void bf537mac_timeout(struct net_device *dev) netif_wake_queue(dev); } -/* - * Get the current statistics. - * This may be called with the card open or closed. - */ -static struct net_device_stats *bf537mac_query_statistics(struct net_device - *dev) -{ - struct bf537mac_local *lp = netdev_priv(dev); - - pr_debug("%s: %s\n", dev->name, __FUNCTION__); - - return &lp->stats; -} - /* * This routine will, depending on the values passed to it, * either make it accept multicast packets, go into @@ -891,7 +877,6 @@ static int __init bf537mac_probe(struct net_device *dev) dev->stop = bf537mac_close; dev->hard_start_xmit = bf537mac_hard_start_xmit; dev->tx_timeout = bf537mac_timeout; - dev->get_stats = bf537mac_query_statistics; dev->set_multicast_list = bf537mac_set_multicast_list; #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = bf537mac_poll; diff --git a/drivers/net/bfin_mac.h b/drivers/net/bfin_mac.h index af87189b85f..b8272469228 100644 --- a/drivers/net/bfin_mac.h +++ b/drivers/net/bfin_mac.h @@ -104,8 +104,6 @@ struct bf537mac_local { * can find out semi-useless statistics of how well the card is * performing */ - struct net_device_stats stats; - int version; int FlowEnabled; /* record if data flow is active */ diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c index ee157f5a5db..2761441f664 100644 --- a/drivers/net/bmac.c +++ b/drivers/net/bmac.c @@ -75,7 +75,6 @@ struct bmac_data { int tx_fill; int tx_empty; unsigned char tx_fullup; - struct net_device_stats stats; struct timer_list tx_timeout; int timeout_active; int sleeping; @@ -145,7 +144,6 @@ static unsigned char *bmac_emergency_rxbuf; static int bmac_open(struct net_device *dev); static int bmac_close(struct net_device *dev); static int bmac_transmit_packet(struct sk_buff *skb, struct net_device *dev); -static struct net_device_stats *bmac_stats(struct net_device *dev); static void bmac_set_multicast(struct net_device *dev); static void bmac_reset_and_enable(struct net_device *dev); static void bmac_start_chip(struct net_device *dev); @@ -668,7 +666,7 @@ static int bmac_transmit_packet(struct sk_buff *skb, struct net_device *dev) bp->tx_bufs[bp->tx_fill] = skb; bp->tx_fill = i; - bp->stats.tx_bytes += skb->len; + dev->stats.tx_bytes += skb->len; dbdma_continue(td); @@ -707,8 +705,8 @@ static irqreturn_t bmac_rxdma_intr(int irq, void *dev_id) nb = RX_BUFLEN - residual - 2; if (nb < (ETHERMINPACKET - ETHERCRC)) { skb = NULL; - bp->stats.rx_length_errors++; - bp->stats.rx_errors++; + dev->stats.rx_length_errors++; + dev->stats.rx_errors++; } else { skb = bp->rx_bufs[i]; bp->rx_bufs[i] = NULL; @@ -719,10 +717,10 @@ static irqreturn_t bmac_rxdma_intr(int irq, void *dev_id) skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; - ++bp->stats.rx_packets; - bp->stats.rx_bytes += nb; + ++dev->stats.rx_packets; + dev->stats.rx_bytes += nb; } else { - ++bp->stats.rx_dropped; + ++dev->stats.rx_dropped; } dev->last_rx = jiffies; if ((skb = bp->rx_bufs[i]) == NULL) { @@ -785,7 +783,7 @@ static irqreturn_t bmac_txdma_intr(int irq, void *dev_id) } if (bp->tx_bufs[bp->tx_empty]) { - ++bp->stats.tx_packets; + ++dev->stats.tx_packets; dev_kfree_skb_irq(bp->tx_bufs[bp->tx_empty]); } bp->tx_bufs[bp->tx_empty] = NULL; @@ -807,13 +805,6 @@ static irqreturn_t bmac_txdma_intr(int irq, void *dev_id) return IRQ_HANDLED; } -static struct net_device_stats *bmac_stats(struct net_device *dev) -{ - struct bmac_data *p = netdev_priv(dev); - - return &p->stats; -} - #ifndef SUNHME_MULTICAST /* Real fast bit-reversal algorithm, 6-bit values */ static int reverse6[64] = { @@ -1080,17 +1071,17 @@ static irqreturn_t bmac_misc_intr(int irq, void *dev_id) } /* XXDEBUG(("bmac_misc_intr, status=%#08x\n", status)); */ /* bmac_txdma_intr_inner(irq, dev_id); */ - /* if (status & FrameReceived) bp->stats.rx_dropped++; */ - if (status & RxErrorMask) bp->stats.rx_errors++; - if (status & RxCRCCntExp) bp->stats.rx_crc_errors++; - if (status & RxLenCntExp) bp->stats.rx_length_errors++; - if (status & RxOverFlow) bp->stats.rx_over_errors++; - if (status & RxAlignCntExp) bp->stats.rx_frame_errors++; - - /* if (status & FrameSent) bp->stats.tx_dropped++; */ - if (status & TxErrorMask) bp->stats.tx_errors++; - if (status & TxUnderrun) bp->stats.tx_fifo_errors++; - if (status & TxNormalCollExp) bp->stats.collisions++; + /* if (status & FrameReceived) dev->stats.rx_dropped++; */ + if (status & RxErrorMask) dev->stats.rx_errors++; + if (status & RxCRCCntExp) dev->stats.rx_crc_errors++; + if (status & RxLenCntExp) dev->stats.rx_length_errors++; + if (status & RxOverFlow) dev->stats.rx_over_errors++; + if (status & RxAlignCntExp) dev->stats.rx_frame_errors++; + + /* if (status & FrameSent) dev->stats.tx_dropped++; */ + if (status & TxErrorMask) dev->stats.tx_errors++; + if (status & TxUnderrun) dev->stats.tx_fifo_errors++; + if (status & TxNormalCollExp) dev->stats.collisions++; return IRQ_HANDLED; } @@ -1324,7 +1315,6 @@ static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_device_i dev->stop = bmac_close; dev->ethtool_ops = &bmac_ethtool_ops; dev->hard_start_xmit = bmac_output; - dev->get_stats = bmac_stats; dev->set_multicast_list = bmac_set_multicast; dev->set_mac_address = bmac_set_address; @@ -1542,7 +1532,7 @@ static void bmac_tx_timeout(unsigned long data) XXDEBUG((KERN_DEBUG "bmac: tx empty=%d fill=%d fullup=%d\n", bp->tx_empty, bp->tx_fill, bp->tx_fullup)); i = bp->tx_empty; - ++bp->stats.tx_errors; + ++dev->stats.tx_errors; if (i != bp->tx_fill) { dev_kfree_skb(bp->tx_bufs[i]); bp->tx_bufs[i] = NULL; diff --git a/drivers/net/de600.c b/drivers/net/de600.c index 5dd0d9c0eac..421c2ca4971 100644 --- a/drivers/net/de600.c +++ b/drivers/net/de600.c @@ -154,11 +154,6 @@ static int de600_close(struct net_device *dev) return 0; } -static struct net_device_stats *get_stats(struct net_device *dev) -{ - return (struct net_device_stats *)(dev->priv); -} - static inline void trigger_interrupt(struct net_device *dev) { de600_put_command(FLIP_IRQ); @@ -308,7 +303,7 @@ static int de600_tx_intr(struct net_device *dev, int irq_status) if (!(irq_status & TX_FAILED16)) { tx_fifo_out = (tx_fifo_out + 1) % TX_PAGES; ++free_tx_pages; - ((struct net_device_stats *)(dev->priv))->tx_packets++; + dev->stats.tx_packets++; netif_wake_queue(dev); } @@ -375,8 +370,8 @@ static void de600_rx_intr(struct net_device *dev) /* update stats */ dev->last_rx = jiffies; - ((struct net_device_stats *)(dev->priv))->rx_packets++; /* count all receives */ - ((struct net_device_stats *)(dev->priv))->rx_bytes += size; /* count all received bytes */ + dev->stats.rx_packets++; /* count all receives */ + dev->stats.rx_bytes += size; /* count all received bytes */ /* * If any worth-while packets have been received, netif_rx() @@ -390,7 +385,7 @@ static struct net_device * __init de600_probe(void) struct net_device *dev; int err; - dev = alloc_etherdev(sizeof(struct net_device_stats)); + dev = alloc_etherdev(0); if (!dev) return ERR_PTR(-ENOMEM); @@ -448,8 +443,6 @@ static struct net_device * __init de600_probe(void) printk(":%02X",dev->dev_addr[i]); printk("\n"); - dev->get_stats = get_stats; - dev->open = de600_open; dev->stop = de600_close; dev->hard_start_xmit = &de600_start_xmit; diff --git a/drivers/net/de600.h b/drivers/net/de600.h index 1288e48ba70..e80ecbabcf4 100644 --- a/drivers/net/de600.h +++ b/drivers/net/de600.h @@ -121,7 +121,6 @@ static u8 de600_read_byte(unsigned char type, struct net_device *dev); /* Put in the device structure. */ static int de600_open(struct net_device *dev); static int de600_close(struct net_device *dev); -static struct net_device_stats *get_stats(struct net_device *dev); static int de600_start_xmit(struct sk_buff *skb, struct net_device *dev); /* Dispatch from interrupts. */ diff --git a/drivers/net/de620.c b/drivers/net/de620.c index a92c207b883..4b93902906b 100644 --- a/drivers/net/de620.c +++ b/drivers/net/de620.c @@ -216,7 +216,6 @@ MODULE_PARM_DESC(de620_debug, "DE-620 debug level (0-2)"); /* Put in the device structure. */ static int de620_open(struct net_device *); static int de620_close(struct net_device *); -static struct net_device_stats *get_stats(struct net_device *); static void de620_set_multicast_list(struct net_device *); static int de620_start_xmit(struct sk_buff *, struct net_device *); @@ -478,16 +477,6 @@ static int de620_close(struct net_device *dev) return 0; } -/********************************************* - * - * Return current statistics - * - */ -static struct net_device_stats *get_stats(struct net_device *dev) -{ - return (struct net_device_stats *)(dev->priv); -} - /********************************************* * * Set or clear the multicast filter for this adaptor. @@ -579,7 +568,7 @@ static int de620_start_xmit(struct sk_buff *skb, struct net_device *dev) if(!(using_txbuf == (TXBF0 | TXBF1))) netif_wake_queue(dev); - ((struct net_device_stats *)(dev->priv))->tx_packets++; + dev->stats.tx_packets++; spin_unlock_irqrestore(&de620_lock, flags); dev_kfree_skb (skb); return 0; @@ -660,7 +649,7 @@ static int de620_rx_intr(struct net_device *dev) /* You win some, you lose some. And sometimes plenty... */ adapter_init(dev); netif_wake_queue(dev); - ((struct net_device_stats *)(dev->priv))->rx_over_errors++; + dev->stats.rx_over_errors++; return 0; } @@ -680,7 +669,7 @@ static int de620_rx_intr(struct net_device *dev) next_rx_page = header_buf.Rx_NextPage; /* at least a try... */ de620_send_command(dev, W_DUMMY); de620_set_register(dev, W_NPRF, next_rx_page); - ((struct net_device_stats *)(dev->priv))->rx_over_errors++; + dev->stats.rx_over_errors++; return 0; } next_rx_page = pagelink; @@ -693,7 +682,7 @@ static int de620_rx_intr(struct net_device *dev) skb = dev_alloc_skb(size+2); if (skb == NULL) { /* Yeah, but no place to put it... */ printk(KERN_WARNING "%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, size); - ((struct net_device_stats *)(dev->priv))->rx_dropped++; + dev->stats.rx_dropped++; } else { /* Yep! Go get it! */ skb_reserve(skb,2); /* Align */ @@ -706,8 +695,8 @@ static int de620_rx_intr(struct net_device *dev) netif_rx(skb); /* deliver it "upstairs" */ dev->last_rx = jiffies; /* count all receives */ - ((struct net_device_stats *)(dev->priv))->rx_packets++; - ((struct net_device_stats *)(dev->priv))->rx_bytes += size; + dev->stats.rx_packets++; + dev->stats.rx_bytes += size; } } @@ -819,7 +808,7 @@ struct net_device * __init de620_probe(int unit) int err = -ENOMEM; int i; - dev = alloc_etherdev(sizeof(struct net_device_stats)); + dev = alloc_etherdev(0); if (!dev) goto out; @@ -879,7 +868,6 @@ struct net_device * __init de620_probe(int unit) else printk(" UTP)\n"); - dev->get_stats = get_stats; dev->open = de620_open; dev->stop = de620_close; dev->hard_start_xmit = de620_start_xmit; diff --git a/drivers/net/declance.c b/drivers/net/declance.c index b2577f40124..7e7ac3330e6 100644 --- a/drivers/net/declance.c +++ b/drivers/net/declance.c @@ -258,8 +258,6 @@ struct lance_private { int rx_new, tx_new; int rx_old, tx_old; - struct net_device_stats stats; - unsigned short busmaster_regval; struct timer_list multicast_timer; @@ -583,22 +581,22 @@ static int lance_rx(struct net_device *dev) /* We got an incomplete frame? */ if ((bits & LE_R1_POK) != LE_R1_POK) { - lp->stats.rx_over_errors++; - lp->stats.rx_errors++; + dev->stats.rx_over_errors++; + dev->stats.rx_errors++; } else if (bits & LE_R1_ERR) { /* Count only the end frame as a rx error, * not the beginning */ if (bits & LE_R1_BUF) - lp->stats.rx_fifo_errors++; + dev->stats.rx_fifo_errors++; if (bits & LE_R1_CRC) - lp->stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; if (bits & LE_R1_OFL) - lp->stats.rx_over_errors++; + dev->stats.rx_over_errors++; if (bits & LE_R1_FRA) - lp->stats.rx_frame_errors++; + dev->stats.rx_frame_errors++; if (bits & LE_R1_EOP) - lp->stats.rx_errors++; + dev->stats.rx_errors++; } else { len = (*rds_ptr(rd, mblength, lp->type) & 0xfff) - 4; skb = dev_alloc_skb(len + 2); @@ -606,7 +604,7 @@ static int lance_rx(struct net_device *dev) if (skb == 0) { printk("%s: Memory squeeze, deferring packet.\n", dev->name); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; *rds_ptr(rd, mblength, lp->type) = 0; *rds_ptr(rd, rmd1, lp->type) = ((lp->rx_buf_ptr_lnc[entry] >> 16) & @@ -614,7 +612,7 @@ static int lance_rx(struct net_device *dev) lp->rx_new = (entry + 1) & RX_RING_MOD_MASK; return 0; } - lp->stats.rx_bytes += len; + dev->stats.rx_bytes += len; skb_reserve(skb, 2); /* 16 byte align */ skb_put(skb, len); /* make room */ @@ -625,7 +623,7 @@ static int lance_rx(struct net_device *dev) skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; - lp->stats.rx_packets++; + dev->stats.rx_packets++; } /* Return the packet to the pool */ @@ -660,14 +658,14 @@ static void lance_tx(struct net_device *dev) if (*tds_ptr(td, tmd1, lp->type) & LE_T1_ERR) { status = *tds_ptr(td, misc, lp->type); - lp->stats.tx_errors++; + dev->stats.tx_errors++; if (status & LE_T3_RTY) - lp->stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; if (status & LE_T3_LCOL) - lp->stats.tx_window_errors++; + dev->stats.tx_window_errors++; if (status & LE_T3_CLOS) { - lp->stats.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; printk("%s: Carrier Lost\n", dev->name); /* Stop the lance */ writereg(&ll->rap, LE_CSR0); @@ -681,7 +679,7 @@ static void lance_tx(struct net_device *dev) * transmitter, restart the adapter. */ if (status & (LE_T3_BUF | LE_T3_UFL)) { - lp->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; printk("%s: Tx: ERR_BUF|ERR_UFL, restarting\n", dev->name); @@ -702,13 +700,13 @@ static void lance_tx(struct net_device *dev) /* One collision before packet was sent. */ if (*tds_ptr(td, tmd1, lp->type) & LE_T1_EONE) - lp->stats.collisions++; + dev->stats.collisions++; /* More than one collision, be optimistic. */ if (*tds_ptr(td, tmd1, lp->type) & LE_T1_EMORE) - lp->stats.collisions += 2; + dev->stats.collisions += 2; - lp->stats.tx_packets++; + dev->stats.tx_packets++; } j = (j + 1) & TX_RING_MOD_MASK; } @@ -754,10 +752,10 @@ static irqreturn_t lance_interrupt(const int irq, void *dev_id) lance_tx(dev); if (csr0 & LE_C0_BABL) - lp->stats.tx_errors++; + dev->stats.tx_errors++; if (csr0 & LE_C0_MISS) - lp->stats.rx_errors++; + dev->stats.rx_errors++; if (csr0 & LE_C0_MERR) { printk("%s: Memory error, status %04x\n", dev->name, csr0); @@ -912,7 +910,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) len = ETH_ZLEN; } - lp->stats.tx_bytes += len; + dev->stats.tx_bytes += len; entry = lp->tx_new; *lib_ptr(ib, btx_ring[entry].length, lp->type) = (-len); @@ -938,13 +936,6 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) return 0; } -static struct net_device_stats *lance_get_stats(struct net_device *dev) -{ - struct lance_private *lp = netdev_priv(dev); - - return &lp->stats; -} - static void lance_load_multicast(struct net_device *dev) { struct lance_private *lp = netdev_priv(dev); @@ -1244,7 +1235,6 @@ static int __init dec_lance_probe(struct device *bdev, const int type) dev->hard_start_xmit = &lance_start_xmit; dev->tx_timeout = &lance_tx_timeout; dev->watchdog_timeo = 5*HZ; - dev->get_stats = &lance_get_stats; dev->set_multicast_list = &lance_set_multicast; /* lp->ll is the location of the registers for lance card */ diff --git a/drivers/net/depca.c b/drivers/net/depca.c index 183497020bf..28fa2bdc8c7 100644 --- a/drivers/net/depca.c +++ b/drivers/net/depca.c @@ -485,7 +485,6 @@ struct depca_private { /* Kernel-only (not device) fields */ int rx_new, tx_new; /* The next free ring entry */ int rx_old, tx_old; /* The ring entries to be free()ed. */ - struct net_device_stats stats; spinlock_t lock; struct { /* Private stats counters */ u32 bins[DEPCA_PKT_STAT_SZ]; @@ -522,7 +521,6 @@ static irqreturn_t depca_interrupt(int irq, void *dev_id); static int depca_close(struct net_device *dev); static int depca_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static void depca_tx_timeout(struct net_device *dev); -static struct net_device_stats *depca_get_stats(struct net_device *dev); static void set_multicast_list(struct net_device *dev); /* @@ -801,7 +799,6 @@ static int __init depca_hw_init (struct net_device *dev, struct device *device) dev->open = &depca_open; dev->hard_start_xmit = &depca_start_xmit; dev->stop = &depca_close; - dev->get_stats = &depca_get_stats; dev->set_multicast_list = &set_multicast_list; dev->do_ioctl = &depca_ioctl; dev->tx_timeout = depca_tx_timeout; @@ -1026,15 +1023,15 @@ static int depca_rx(struct net_device *dev) } if (status & R_ENP) { /* Valid frame status */ if (status & R_ERR) { /* There was an error. */ - lp->stats.rx_errors++; /* Update the error stats. */ + dev->stats.rx_errors++; /* Update the error stats. */ if (status & R_FRAM) - lp->stats.rx_frame_errors++; + dev->stats.rx_frame_errors++; if (status & R_OFLO) - lp->stats.rx_over_errors++; + dev->stats.rx_over_errors++; if (status & R_CRC) - lp->stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; if (status & R_BUFF) - lp->stats.rx_fifo_errors++; + dev->stats.rx_fifo_errors++; } else { short len, pkt_len = readw(&lp->rx_ring[entry].msg_length) - 4; struct sk_buff *skb; @@ -1063,8 +1060,8 @@ static int depca_rx(struct net_device *dev) ** Update stats */ dev->last_rx = jiffies; - lp->stats.rx_packets++; - lp->stats.rx_bytes += pkt_len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; for (i = 1; i < DEPCA_PKT_STAT_SZ - 1; i++) { if (pkt_len < (i * DEPCA_PKT_BIN_SZ)) { lp->pktStats.bins[i]++; @@ -1087,7 +1084,7 @@ static int depca_rx(struct net_device *dev) } } else { printk("%s: Memory squeeze, deferring packet.\n", dev->name); - lp->stats.rx_dropped++; /* Really, deferred. */ + dev->stats.rx_dropped++; /* Really, deferred. */ break; } } @@ -1125,24 +1122,24 @@ static int depca_tx(struct net_device *dev) break; } else if (status & T_ERR) { /* An error occurred. */ status = readl(&lp->tx_ring[entry].misc); - lp->stats.tx_errors++; + dev->stats.tx_errors++; if (status & TMD3_RTRY) - lp->stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; if (status & TMD3_LCAR) - lp->stats.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; if (status & TMD3_LCOL) - lp->stats.tx_window_errors++; + dev->stats.tx_window_errors++; if (status & TMD3_UFLO) - lp->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; if (status & (TMD3_BUFF | TMD3_UFLO)) { /* Trigger an immediate send demand. */ outw(CSR0, DEPCA_ADDR); outw(INEA | TDMD, DEPCA_DATA); } } else if (status & (T_MORE | T_ONE)) { - lp->stats.collisions++; + dev->stats.collisions++; } else { - lp->stats.tx_packets++; + dev->stats.tx_packets++; } /* Update all the pointers */ @@ -1234,15 +1231,6 @@ static int InitRestartDepca(struct net_device *dev) return status; } -static struct net_device_stats *depca_get_stats(struct net_device *dev) -{ - struct depca_private *lp = (struct depca_private *) dev->priv; - - /* Null body since there is no framing error counter */ - - return &lp->stats; -} - /* ** Set or clear the multicast filter for this adaptor. */ diff --git a/drivers/net/dgrs.c b/drivers/net/dgrs.c index ddedb76303d..a9ef79da3dc 100644 --- a/drivers/net/dgrs.c +++ b/drivers/net/dgrs.c @@ -193,11 +193,6 @@ static int dgrs_nicmode; */ typedef struct { - /* - * Stuff for generic ethercard I/F - */ - struct net_device_stats stats; - /* * DGRS specific data */ @@ -499,7 +494,7 @@ dgrs_rcv_frame( if ((skb = dev_alloc_skb(len+5)) == NULL) { printk("%s: dev_alloc_skb failed for rcv buffer\n", devN->name); - ++privN->stats.rx_dropped; + ++dev0->stats.rx_dropped; /* discarding the frame */ goto out; } @@ -667,8 +662,8 @@ again: skb->protocol = eth_type_trans(skb, devN); netif_rx(skb); devN->last_rx = jiffies; - ++privN->stats.rx_packets; - privN->stats.rx_bytes += len; + ++devN->stats.rx_packets; + devN->stats.rx_bytes += len; out: cbp->xmit.status = I596_CB_STATUS_C | I596_CB_STATUS_OK; @@ -776,7 +771,7 @@ frame_done: priv0->rfdp->status = I596_RFD_C | I596_RFD_OK; priv0->rfdp = (I596_RFD *) S2H(priv0->rfdp->next); - ++privN->stats.tx_packets; + ++devN->stats.tx_packets; dev_kfree_skb (skb); return (0); @@ -805,16 +800,6 @@ static int dgrs_close( struct net_device *dev ) return (0); } -/* - * Get statistics - */ -static struct net_device_stats *dgrs_get_stats( struct net_device *dev ) -{ - DGRS_PRIV *priv = (DGRS_PRIV *) dev->priv; - - return (&priv->stats); -} - /* * Set multicast list and/or promiscuous mode */ @@ -1213,7 +1198,6 @@ dgrs_probe1(struct net_device *dev) */ dev->open = &dgrs_open; dev->stop = &dgrs_close; - dev->get_stats = &dgrs_get_stats; dev->hard_start_xmit = &dgrs_start_xmit; dev->set_multicast_list = &dgrs_set_multicast_list; dev->do_ioctl = &dgrs_ioctl; diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index 857eb366bb1..f691ef61b2d 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -148,7 +148,6 @@ typedef struct board_info { struct resource *irq_res; struct timer_list timer; - struct net_device_stats stats; unsigned char srom[128]; spinlock_t lock; @@ -166,8 +165,6 @@ static int dm9000_stop(struct net_device *); static void dm9000_timer(unsigned long); static void dm9000_init_dm9000(struct net_device *); -static struct net_device_stats *dm9000_get_stats(struct net_device *); - static irqreturn_t dm9000_interrupt(int, void *); static int dm9000_phy_read(struct net_device *dev, int phyaddr_unsused, int reg); @@ -558,7 +555,6 @@ dm9000_probe(struct platform_device *pdev) ndev->tx_timeout = &dm9000_timeout; ndev->watchdog_timeo = msecs_to_jiffies(watchdog); ndev->stop = &dm9000_stop; - ndev->get_stats = &dm9000_get_stats; ndev->set_multicast_list = &dm9000_hash_table; #ifdef CONFIG_NET_POLL_CONTROLLER ndev->poll_controller = &dm9000_poll_controller; @@ -713,7 +709,7 @@ dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev) writeb(DM9000_MWCMD, db->io_addr); (db->outblk)(db->io_data, skb->data, skb->len); - db->stats.tx_bytes += skb->len; + dev->stats.tx_bytes += skb->len; db->tx_pkt_cnt++; /* TX control: First packet immediately send, second packet queue */ @@ -790,7 +786,7 @@ dm9000_tx_done(struct net_device *dev, board_info_t * db) if (tx_status & (NSR_TX2END | NSR_TX1END)) { /* One packet sent complete */ db->tx_pkt_cnt--; - db->stats.tx_packets++; + dev->stats.tx_packets++; /* Queue packet check & send */ if (db->tx_pkt_cnt > 0) { @@ -851,17 +847,6 @@ dm9000_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -/* - * Get statistics from driver. - */ -static struct net_device_stats * -dm9000_get_stats(struct net_device *dev) -{ - board_info_t *db = (board_info_t *) dev->priv; - return &db->stats; -} - - /* * A periodic timer routine * Dynamic media sense, allocated Rx buffer... @@ -939,15 +924,15 @@ dm9000_rx(struct net_device *dev) GoodPacket = false; if (rxhdr.RxStatus & 0x100) { PRINTK1("fifo error\n"); - db->stats.rx_fifo_errors++; + dev->stats.rx_fifo_errors++; } if (rxhdr.RxStatus & 0x200) { PRINTK1("crc error\n"); - db->stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; } if (rxhdr.RxStatus & 0x8000) { PRINTK1("length error\n"); - db->stats.rx_length_errors++; + dev->stats.rx_length_errors++; } } @@ -960,12 +945,12 @@ dm9000_rx(struct net_device *dev) /* Read received packet from RX SRAM */ (db->inblk)(db->io_data, rdptr, RxLen); - db->stats.rx_bytes += RxLen; + dev->stats.rx_bytes += RxLen; /* Pass to upper layer */ skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - db->stats.rx_packets++; + dev->stats.rx_packets++; } else { /* need to dump the packet's data */ diff --git a/drivers/net/e100.c b/drivers/net/e100.c index f9aa13e04ad..99126564f1a 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -558,7 +558,6 @@ struct nic { enum mac mac; enum phy phy; struct params params; - struct net_device_stats net_stats; struct timer_list watchdog; struct timer_list blink_timer; struct mii_if_info mii; @@ -1483,7 +1482,8 @@ static void e100_set_multicast_list(struct net_device *netdev) static void e100_update_stats(struct nic *nic) { - struct net_device_stats *ns = &nic->net_stats; + struct net_device *dev = nic->netdev; + struct net_device_stats *ns = &dev->stats; struct stats *s = &nic->mem->stats; u32 *complete = (nic->mac < mac_82558_D101_A4) ? &s->fc_xmt_pause : (nic->mac < mac_82559_D101M) ? (u32 *)&s->xmt_tco_frames : @@ -1661,6 +1661,7 @@ static int e100_xmit_frame(struct sk_buff *skb, struct net_device *netdev) static int e100_tx_clean(struct nic *nic) { + struct net_device *dev = nic->netdev; struct cb *cb; int tx_cleaned = 0; @@ -1675,8 +1676,8 @@ static int e100_tx_clean(struct nic *nic) cb->status); if(likely(cb->skb != NULL)) { - nic->net_stats.tx_packets++; - nic->net_stats.tx_bytes += cb->skb->len; + dev->stats.tx_packets++; + dev->stats.tx_bytes += cb->skb->len; pci_unmap_single(nic->pdev, le32_to_cpu(cb->u.tcb.tbd.buf_addr), @@ -1807,6 +1808,7 @@ static int e100_rx_alloc_skb(struct nic *nic, struct rx *rx) static int e100_rx_indicate(struct nic *nic, struct rx *rx, unsigned int *work_done, unsigned int work_to_do) { + struct net_device *dev = nic->netdev; struct sk_buff *skb = rx->skb; struct rfd *rfd = (struct rfd *)skb->data; u16 rfd_status, actual_size; @@ -1851,8 +1853,8 @@ static int e100_rx_indicate(struct nic *nic, struct rx *rx, nic->rx_over_length_errors++; dev_kfree_skb_any(skb); } else { - nic->net_stats.rx_packets++; - nic->net_stats.rx_bytes += actual_size; + dev->stats.rx_packets++; + dev->stats.rx_bytes += actual_size; nic->netdev->last_rx = jiffies; netif_receive_skb(skb); if(work_done) @@ -2015,12 +2017,6 @@ static void e100_netpoll(struct net_device *netdev) } #endif -static struct net_device_stats *e100_get_stats(struct net_device *netdev) -{ - struct nic *nic = netdev_priv(netdev); - return &nic->net_stats; -} - static int e100_set_mac_address(struct net_device *netdev, void *p) { struct nic *nic = netdev_priv(netdev); @@ -2457,7 +2453,7 @@ static void e100_get_ethtool_stats(struct net_device *netdev, int i; for(i = 0; i < E100_NET_STATS_LEN; i++) - data[i] = ((unsigned long *)&nic->net_stats)[i]; + data[i] = ((unsigned long *)&netdev->stats)[i]; data[i++] = nic->tx_deferred; data[i++] = nic->tx_single_collisions; @@ -2562,7 +2558,6 @@ static int __devinit e100_probe(struct pci_dev *pdev, netdev->open = e100_open; netdev->stop = e100_close; netdev->hard_start_xmit = e100_xmit_frame; - netdev->get_stats = e100_get_stats; netdev->set_multicast_list = e100_set_multicast_list; netdev->set_mac_address = e100_set_mac_address; netdev->change_mtu = e100_change_mtu; diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c index 6eb84f14c88..54811f6f766 100644 --- a/drivers/net/eepro.c +++ b/drivers/net/eepro.c @@ -192,7 +192,6 @@ static unsigned int net_debug = NET_DEBUG; /* Information that need to be kept for each board. */ struct eepro_local { - struct net_device_stats stats; unsigned rx_start; unsigned tx_start; /* start of the transmit chain */ int tx_last; /* pointer to last packet in the transmit chain */ @@ -315,7 +314,6 @@ static irqreturn_t eepro_interrupt(int irq, void *dev_id); static void eepro_rx(struct net_device *dev); static void eepro_transmit_interrupt(struct net_device *dev); static int eepro_close(struct net_device *dev); -static struct net_device_stats *eepro_get_stats(struct net_device *dev); static void set_multicast_list(struct net_device *dev); static void eepro_tx_timeout (struct net_device *dev); @@ -514,7 +512,7 @@ buffer (transmit-buffer = 32K - receive-buffer). /* a complete sel reset */ #define eepro_complete_selreset(ioaddr) { \ - lp->stats.tx_errors++;\ + dev->stats.tx_errors++;\ eepro_sel_reset(ioaddr);\ lp->tx_end = \ lp->xmt_lower_limit;\ @@ -856,7 +854,6 @@ static int __init eepro_probe1(struct net_device *dev, int autoprobe) dev->open = eepro_open; dev->stop = eepro_close; dev->hard_start_xmit = eepro_send_packet; - dev->get_stats = eepro_get_stats; dev->set_multicast_list = &set_multicast_list; dev->tx_timeout = eepro_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; @@ -1154,9 +1151,9 @@ static int eepro_send_packet(struct sk_buff *skb, struct net_device *dev) if (hardware_send_packet(dev, buf, length)) /* we won't wake queue here because we're out of space */ - lp->stats.tx_dropped++; + dev->stats.tx_dropped++; else { - lp->stats.tx_bytes+=skb->len; + dev->stats.tx_bytes+=skb->len; dev->trans_start = jiffies; netif_wake_queue(dev); } @@ -1166,7 +1163,7 @@ static int eepro_send_packet(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb (skb); /* You might need to clean up and record Tx statistics here. */ - /* lp->stats.tx_aborted_errors++; */ + /* dev->stats.tx_aborted_errors++; */ if (net_debug > 5) printk(KERN_DEBUG "%s: exiting eepro_send_packet routine.\n", dev->name); @@ -1273,16 +1270,6 @@ static int eepro_close(struct net_device *dev) return 0; } -/* Get the current statistics. This may be called with the card open or - closed. */ -static struct net_device_stats * -eepro_get_stats(struct net_device *dev) -{ - struct eepro_local *lp = netdev_priv(dev); - - return &lp->stats; -} - /* Set or clear the multicast filter for this adaptor. */ static void @@ -1575,12 +1562,12 @@ eepro_rx(struct net_device *dev) /* Malloc up new buffer. */ struct sk_buff *skb; - lp->stats.rx_bytes+=rcv_size; + dev->stats.rx_bytes+=rcv_size; rcv_size &= 0x3fff; skb = dev_alloc_skb(rcv_size+5); if (skb == NULL) { printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; rcv_car = lp->rx_start + RCV_HEADER + rcv_size; lp->rx_start = rcv_next_frame; outw(rcv_next_frame, ioaddr + HOST_ADDRESS_REG); @@ -1602,28 +1589,28 @@ eepro_rx(struct net_device *dev) skb->protocol = eth_type_trans(skb,dev); netif_rx(skb); dev->last_rx = jiffies; - lp->stats.rx_packets++; + dev->stats.rx_packets++; } else { /* Not sure will ever reach here, I set the 595 to discard bad received frames */ - lp->stats.rx_errors++; + dev->stats.rx_errors++; if (rcv_status & 0x0100) - lp->stats.rx_over_errors++; + dev->stats.rx_over_errors++; else if (rcv_status & 0x0400) - lp->stats.rx_frame_errors++; + dev->stats.rx_frame_errors++; else if (rcv_status & 0x0800) - lp->stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; printk(KERN_DEBUG "%s: event = %#x, status = %#x, next = %#x, size = %#x\n", dev->name, rcv_event, rcv_status, rcv_next_frame, rcv_size); } if (rcv_status & 0x1000) - lp->stats.rx_length_errors++; + dev->stats.rx_length_errors++; rcv_car = lp->rx_start + RCV_HEADER + rcv_size; lp->rx_start = rcv_next_frame; @@ -1666,11 +1653,11 @@ eepro_transmit_interrupt(struct net_device *dev) netif_wake_queue (dev); if (xmt_status & TX_OK) - lp->stats.tx_packets++; + dev->stats.tx_packets++; else { - lp->stats.tx_errors++; + dev->stats.tx_errors++; if (xmt_status & 0x0400) { - lp->stats.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; printk(KERN_DEBUG "%s: carrier error\n", dev->name); printk(KERN_DEBUG "%s: XMT status = %#x\n", @@ -1684,11 +1671,11 @@ eepro_transmit_interrupt(struct net_device *dev) } } if (xmt_status & 0x000f) { - lp->stats.collisions += (xmt_status & 0x000f); + dev->stats.collisions += (xmt_status & 0x000f); } if ((xmt_status & 0x0040) == 0x0) { - lp->stats.tx_heartbeat_errors++; + dev->stats.tx_heartbeat_errors++; } } } diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c index 6c91bfa72bb..9c85e50014b 100644 --- a/drivers/net/eexpress.c +++ b/drivers/net/eexpress.c @@ -135,7 +135,6 @@ struct net_local { - struct net_device_stats stats; unsigned long last_tx; /* jiffies when last transmit started */ unsigned long init_time; /* jiffies when eexp_hw_init586 called */ unsigned short rx_first; /* first rx buf, same as RX_BUF_START */ @@ -247,7 +246,6 @@ static char mca_irqmap[] = { 12, 9, 3, 4, 5, 10, 11, 15 }; static int eexp_open(struct net_device *dev); static int eexp_close(struct net_device *dev); static void eexp_timeout(struct net_device *dev); -static struct net_device_stats *eexp_stats(struct net_device *dev); static int eexp_xmit(struct sk_buff *buf, struct net_device *dev); static irqreturn_t eexp_irq(int irq, void *dev_addr); @@ -532,17 +530,6 @@ static int eexp_close(struct net_device *dev) return 0; } -/* - * Return interface stats - */ - -static struct net_device_stats *eexp_stats(struct net_device *dev) -{ - struct net_local *lp = netdev_priv(dev); - - return &lp->stats; -} - /* * This gets called when a higher level thinks we are broken. Check that * nothing has become jammed in the CU. @@ -646,7 +633,7 @@ static void eexp_timeout(struct net_device *dev) printk(KERN_INFO "%s: transmit timed out, %s?\n", dev->name, (SCB_complete(status)?"lost interrupt": "board on fire")); - lp->stats.tx_errors++; + dev->stats.tx_errors++; lp->last_tx = jiffies; if (!SCB_complete(status)) { scb_command(dev, SCB_CUabort); @@ -694,7 +681,7 @@ static int eexp_xmit(struct sk_buff *buf, struct net_device *dev) { unsigned short *data = (unsigned short *)buf->data; - lp->stats.tx_bytes += length; + dev->stats.tx_bytes += length; eexp_hw_tx_pio(dev,data,length); } @@ -843,7 +830,7 @@ static irqreturn_t eexp_irq(int irq, void *dev_info) outw(rbd+8, ioaddr+READ_PTR); printk("[%04x]\n", inw(ioaddr+DATAPORT)); #endif - lp->stats.rx_errors++; + dev->stats.rx_errors++; #if 1 eexp_hw_rxinit(dev); #else @@ -952,17 +939,17 @@ static void eexp_hw_rx_pio(struct net_device *dev) } else if (!FD_OK(status)) { - lp->stats.rx_errors++; + dev->stats.rx_errors++; if (FD_CRC(status)) - lp->stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; if (FD_Align(status)) - lp->stats.rx_frame_errors++; + dev->stats.rx_frame_errors++; if (FD_Resrc(status)) - lp->stats.rx_fifo_errors++; + dev->stats.rx_fifo_errors++; if (FD_DMA(status)) - lp->stats.rx_over_errors++; + dev->stats.rx_over_errors++; if (FD_Short(status)) - lp->stats.rx_length_errors++; + dev->stats.rx_length_errors++; } else { @@ -972,7 +959,7 @@ static void eexp_hw_rx_pio(struct net_device *dev) if (skb == NULL) { printk(KERN_WARNING "%s: Memory squeeze, dropping packet\n",dev->name); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; break; } skb_reserve(skb, 2); @@ -981,8 +968,8 @@ static void eexp_hw_rx_pio(struct net_device *dev) skb->protocol = eth_type_trans(skb,dev); netif_rx(skb); dev->last_rx = jiffies; - lp->stats.rx_packets++; - lp->stats.rx_bytes += pkt_len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; } outw(rx_block, ioaddr+WRITE_PTR); outw(0, ioaddr+DATAPORT); @@ -1053,7 +1040,7 @@ static void eexp_hw_tx_pio(struct net_device *dev, unsigned short *buf, outw(0xFFFF, ioaddr+SIGNAL_CA); } - lp->stats.tx_packets++; + dev->stats.tx_packets++; lp->last_tx = jiffies; } @@ -1180,7 +1167,6 @@ static int __init eexp_hw_probe(struct net_device *dev, unsigned short ioaddr) dev->open = eexp_open; dev->stop = eexp_close; dev->hard_start_xmit = eexp_xmit; - dev->get_stats = eexp_stats; dev->set_multicast_list = &eexp_set_multicast; dev->tx_timeout = eexp_timeout; dev->watchdog_timeo = 2*HZ; @@ -1263,35 +1249,35 @@ static unsigned short eexp_hw_lasttxstat(struct net_device *dev) else { lp->last_tx_restart = 0; - lp->stats.collisions += Stat_NoColl(status); + dev->stats.collisions += Stat_NoColl(status); if (!Stat_OK(status)) { char *whatsup = NULL; - lp->stats.tx_errors++; + dev->stats.tx_errors++; if (Stat_Abort(status)) - lp->stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; if (Stat_TNoCar(status)) { whatsup = "aborted, no carrier"; - lp->stats.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; } if (Stat_TNoCTS(status)) { whatsup = "aborted, lost CTS"; - lp->stats.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; } if (Stat_TNoDMA(status)) { whatsup = "FIFO underran"; - lp->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; } if (Stat_TXColl(status)) { whatsup = "aborted, too many collisions"; - lp->stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; } if (whatsup) printk(KERN_INFO "%s: transmit %s\n", dev->name, whatsup); } else - lp->stats.tx_packets++; + dev->stats.tx_packets++; } if (tx_block == TX_BUF_START+((lp->num_tx_bufs-1)*TX_BUF_SIZE)) lp->tx_reap = tx_block = TX_BUF_START; diff --git a/drivers/net/eql.c b/drivers/net/eql.c index 7266f6dbdd9..18f1364d3d5 100644 --- a/drivers/net/eql.c +++ b/drivers/net/eql.c @@ -128,7 +128,6 @@ static int eql_open(struct net_device *dev); static int eql_close(struct net_device *dev); static int eql_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); static int eql_slave_xmit(struct sk_buff *skb, struct net_device *dev); -static struct net_device_stats *eql_get_stats(struct net_device *dev); #define eql_is_slave(dev) ((dev->flags & IFF_SLAVE) == IFF_SLAVE) #define eql_is_master(dev) ((dev->flags & IFF_MASTER) == IFF_MASTER) @@ -180,7 +179,6 @@ static void __init eql_setup(struct net_device *dev) dev->stop = eql_close; dev->do_ioctl = eql_ioctl; dev->hard_start_xmit = eql_slave_xmit; - dev->get_stats = eql_get_stats; /* * Now we undo some of the things that eth_setup does @@ -337,9 +335,9 @@ static int eql_slave_xmit(struct sk_buff *skb, struct net_device *dev) skb->priority = 1; slave->bytes_queued += skb->len; dev_queue_xmit(skb); - eql->stats.tx_packets++; + dev->stats.tx_packets++; } else { - eql->stats.tx_dropped++; + dev->stats.tx_dropped++; dev_kfree_skb(skb); } @@ -348,12 +346,6 @@ static int eql_slave_xmit(struct sk_buff *skb, struct net_device *dev) return 0; } -static struct net_device_stats * eql_get_stats(struct net_device *dev) -{ - equalizer_t *eql = netdev_priv(dev); - return &eql->stats; -} - /* * Private ioctl functions */ diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c index 0e3b33717ca..243fc6b354b 100644 --- a/drivers/net/eth16i.c +++ b/drivers/net/eth16i.c @@ -380,7 +380,6 @@ static unsigned int eth16i_debug = ETH16I_DEBUG; /* Information for each board */ struct eth16i_local { - struct net_device_stats stats; unsigned char tx_started; unsigned char tx_buf_busy; unsigned short tx_queue; /* Number of packets in transmit buffer */ @@ -426,8 +425,6 @@ static int eth16i_set_irq(struct net_device *dev); static ushort eth16i_parse_mediatype(const char* s); #endif -static struct net_device_stats *eth16i_get_stats(struct net_device *dev); - static char cardname[] __initdata = "ICL EtherTeam 16i/32"; static int __init do_eth16i_probe(struct net_device *dev) @@ -557,7 +554,6 @@ static int __init eth16i_probe1(struct net_device *dev, int ioaddr) dev->open = eth16i_open; dev->stop = eth16i_close; dev->hard_start_xmit = eth16i_tx; - dev->get_stats = eth16i_get_stats; dev->set_multicast_list = eth16i_multicast; dev->tx_timeout = eth16i_timeout; dev->watchdog_timeo = TX_TIMEOUT; @@ -1045,7 +1041,7 @@ static void eth16i_timeout(struct net_device *dev) printk(KERN_DEBUG "lp->tx_queue_len = %d\n", lp->tx_queue_len); printk(KERN_DEBUG "lp->tx_started = %d\n", lp->tx_started); } - lp->stats.tx_errors++; + dev->stats.tx_errors++; eth16i_reset(dev); dev->trans_start = jiffies; outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG); @@ -1130,7 +1126,6 @@ static int eth16i_tx(struct sk_buff *skb, struct net_device *dev) static void eth16i_rx(struct net_device *dev) { - struct eth16i_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; int boguscount = MAX_RX_LOOP; @@ -1149,16 +1144,16 @@ static void eth16i_rx(struct net_device *dev) inb(ioaddr + RECEIVE_MODE_REG), status); if( !(status & PKT_GOOD) ) { - lp->stats.rx_errors++; + dev->stats.rx_errors++; if( (pkt_len < ETH_ZLEN) || (pkt_len > ETH_FRAME_LEN) ) { - lp->stats.rx_length_errors++; + dev->stats.rx_length_errors++; eth16i_reset(dev); return; } else { eth16i_skip_packet(dev); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; } } else { /* Ok so now we should have a good packet */ @@ -1169,7 +1164,7 @@ static void eth16i_rx(struct net_device *dev) printk(KERN_WARNING "%s: Could'n allocate memory for packet (len %d)\n", dev->name, pkt_len); eth16i_skip_packet(dev); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; break; } @@ -1212,8 +1207,8 @@ static void eth16i_rx(struct net_device *dev) } netif_rx(skb); dev->last_rx = jiffies; - lp->stats.rx_packets++; - lp->stats.rx_bytes += pkt_len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; } /* else */ @@ -1250,32 +1245,32 @@ static irqreturn_t eth16i_interrupt(int irq, void *dev_id) if( status & 0x7f00 ) { - lp->stats.rx_errors++; + dev->stats.rx_errors++; if(status & (BUS_RD_ERR << 8) ) printk(KERN_WARNING "%s: Bus read error.\n",dev->name); - if(status & (SHORT_PKT_ERR << 8) ) lp->stats.rx_length_errors++; - if(status & (ALIGN_ERR << 8) ) lp->stats.rx_frame_errors++; - if(status & (CRC_ERR << 8) ) lp->stats.rx_crc_errors++; - if(status & (RX_BUF_OVERFLOW << 8) ) lp->stats.rx_over_errors++; + if(status & (SHORT_PKT_ERR << 8) ) dev->stats.rx_length_errors++; + if(status & (ALIGN_ERR << 8) ) dev->stats.rx_frame_errors++; + if(status & (CRC_ERR << 8) ) dev->stats.rx_crc_errors++; + if(status & (RX_BUF_OVERFLOW << 8) ) dev->stats.rx_over_errors++; } if( status & 0x001a) { - lp->stats.tx_errors++; + dev->stats.tx_errors++; - if(status & CR_LOST) lp->stats.tx_carrier_errors++; - if(status & TX_JABBER_ERR) lp->stats.tx_window_errors++; + if(status & CR_LOST) dev->stats.tx_carrier_errors++; + if(status & TX_JABBER_ERR) dev->stats.tx_window_errors++; #if 0 if(status & COLLISION) { - lp->stats.collisions += + dev->stats.collisions += ((inb(ioaddr+TRANSMIT_MODE_REG) & 0xF0) >> 4); } #endif if(status & COLLISIONS_16) { if(lp->col_16 < MAX_COL_16) { lp->col_16++; - lp->stats.collisions++; + dev->stats.collisions++; /* Resume transmitting, skip failed packet */ outb(0x02, ioaddr + COL_16_REG); } @@ -1288,8 +1283,8 @@ static irqreturn_t eth16i_interrupt(int irq, void *dev_id) if( status & 0x00ff ) { /* Let's check the transmit status reg */ if(status & TX_DONE) { /* The transmit has been done */ - lp->stats.tx_packets = lp->tx_buffered_packets; - lp->stats.tx_bytes += lp->tx_buffered_bytes; + dev->stats.tx_packets = lp->tx_buffered_packets; + dev->stats.tx_bytes += lp->tx_buffered_bytes; lp->col_16 = 0; if(lp->tx_queue) { /* Is there still packets ? */ @@ -1369,12 +1364,6 @@ static void eth16i_multicast(struct net_device *dev) } } -static struct net_device_stats *eth16i_get_stats(struct net_device *dev) -{ - struct eth16i_local *lp = netdev_priv(dev); - return &lp->stats; -} - static void eth16i_select_regbank(unsigned char banknbr, int ioaddr) { unsigned char data; diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c index 6a5d0436e89..142aa225d89 100644 --- a/drivers/net/ewrk3.c +++ b/drivers/net/ewrk3.c @@ -275,7 +275,6 @@ struct ewrk3_private { u_long shmem_base; /* Shared memory start address */ void __iomem *shmem; u_long shmem_length; /* Shared memory window length */ - struct net_device_stats stats; /* Public stats */ struct ewrk3_stats pktStats; /* Private stats counters */ u_char irq_mask; /* Adapter IRQ mask bits */ u_char mPage; /* Maximum 2kB Page number */ @@ -302,7 +301,6 @@ static int ewrk3_open(struct net_device *dev); static int ewrk3_queue_pkt(struct sk_buff *skb, struct net_device *dev); static irqreturn_t ewrk3_interrupt(int irq, void *dev_id); static int ewrk3_close(struct net_device *dev); -static struct net_device_stats *ewrk3_get_stats(struct net_device *dev); static void set_multicast_list(struct net_device *dev); static int ewrk3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static const struct ethtool_ops ethtool_ops_203; @@ -611,7 +609,6 @@ ewrk3_hw_init(struct net_device *dev, u_long iobase) dev->open = ewrk3_open; dev->hard_start_xmit = ewrk3_queue_pkt; dev->stop = ewrk3_close; - dev->get_stats = ewrk3_get_stats; dev->set_multicast_list = set_multicast_list; dev->do_ioctl = ewrk3_ioctl; if (lp->adapter_name[4] == '3') @@ -863,7 +860,7 @@ static int ewrk3_queue_pkt (struct sk_buff *skb, struct net_device *dev) ENABLE_IRQs; spin_unlock_irq (&lp->hw_lock); - lp->stats.tx_bytes += skb->len; + dev->stats.tx_bytes += skb->len; dev->trans_start = jiffies; dev_kfree_skb (skb); @@ -980,13 +977,13 @@ static int ewrk3_rx(struct net_device *dev) } if (!(rx_status & R_ROK)) { /* There was an error. */ - lp->stats.rx_errors++; /* Update the error stats. */ + dev->stats.rx_errors++; /* Update the error stats. */ if (rx_status & R_DBE) - lp->stats.rx_frame_errors++; + dev->stats.rx_frame_errors++; if (rx_status & R_CRC) - lp->stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; if (rx_status & R_PLL) - lp->stats.rx_fifo_errors++; + dev->stats.rx_fifo_errors++; } else { struct sk_buff *skb; @@ -1037,11 +1034,11 @@ static int ewrk3_rx(struct net_device *dev) ** Update stats */ dev->last_rx = jiffies; - lp->stats.rx_packets++; - lp->stats.rx_bytes += pkt_len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; } else { printk("%s: Insufficient memory; nuking packet.\n", dev->name); - lp->stats.rx_dropped++; /* Really, deferred. */ + dev->stats.rx_dropped++; /* Really, deferred. */ break; } } @@ -1071,11 +1068,11 @@ static int ewrk3_tx(struct net_device *dev) while ((tx_status = inb(EWRK3_TDQ)) > 0) { /* Whilst there's old buffers */ if (tx_status & T_VSTS) { /* The status is valid */ if (tx_status & T_TXE) { - lp->stats.tx_errors++; + dev->stats.tx_errors++; if (tx_status & T_NCL) - lp->stats.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; if (tx_status & T_LCL) - lp->stats.tx_window_errors++; + dev->stats.tx_window_errors++; if (tx_status & T_CTU) { if ((tx_status & T_COLL) ^ T_XUR) { lp->pktStats.tx_underruns++; @@ -1084,13 +1081,13 @@ static int ewrk3_tx(struct net_device *dev) } } else if (tx_status & T_COLL) { if ((tx_status & T_COLL) ^ T_XCOLL) { - lp->stats.collisions++; + dev->stats.collisions++; } else { lp->pktStats.excessive_collisions++; } } } else { - lp->stats.tx_packets++; + dev->stats.tx_packets++; } } } @@ -1133,14 +1130,6 @@ static int ewrk3_close(struct net_device *dev) return 0; } -static struct net_device_stats *ewrk3_get_stats(struct net_device *dev) -{ - struct ewrk3_private *lp = netdev_priv(dev); - - /* Null body since there is no framing error counter */ - return &lp->stats; -} - /* ** Set or clear the multicast filter for this adapter. */ diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 4e8df910c00..4419c3cee99 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -204,7 +204,6 @@ struct fec_enet_private { cbd_t *tx_bd_base; cbd_t *cur_rx, *cur_tx; /* The next free ring entry */ cbd_t *dirty_tx; /* The ring entries to be free()ed. */ - struct net_device_stats stats; uint tx_full; spinlock_t lock; @@ -234,7 +233,6 @@ static irqreturn_t fec_enet_interrupt(int irq, void * dev_id); static void fec_enet_tx(struct net_device *dev); static void fec_enet_rx(struct net_device *dev); static int fec_enet_close(struct net_device *dev); -static struct net_device_stats *fec_enet_get_stats(struct net_device *dev); static void set_multicast_list(struct net_device *dev); static void fec_restart(struct net_device *dev, int duplex); static void fec_stop(struct net_device *dev); @@ -359,7 +357,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) */ fep->tx_skbuff[fep->skb_cur] = skb; - fep->stats.tx_bytes += skb->len; + dev->stats.tx_bytes += skb->len; fep->skb_cur = (fep->skb_cur+1) & TX_RING_MOD_MASK; /* Push the data cache so the CPM does not get stale memory @@ -409,7 +407,7 @@ fec_timeout(struct net_device *dev) struct fec_enet_private *fep = netdev_priv(dev); printk("%s: transmit timed out.\n", dev->name); - fep->stats.tx_errors++; + dev->stats.tx_errors++; #ifndef final_version { int i; @@ -511,19 +509,19 @@ fec_enet_tx(struct net_device *dev) if (status & (BD_ENET_TX_HB | BD_ENET_TX_LC | BD_ENET_TX_RL | BD_ENET_TX_UN | BD_ENET_TX_CSL)) { - fep->stats.tx_errors++; + dev->stats.tx_errors++; if (status & BD_ENET_TX_HB) /* No heartbeat */ - fep->stats.tx_heartbeat_errors++; + dev->stats.tx_heartbeat_errors++; if (status & BD_ENET_TX_LC) /* Late collision */ - fep->stats.tx_window_errors++; + dev->stats.tx_window_errors++; if (status & BD_ENET_TX_RL) /* Retrans limit */ - fep->stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; if (status & BD_ENET_TX_UN) /* Underrun */ - fep->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; if (status & BD_ENET_TX_CSL) /* Carrier lost */ - fep->stats.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; } else { - fep->stats.tx_packets++; + dev->stats.tx_packets++; } #ifndef final_version @@ -534,7 +532,7 @@ fec_enet_tx(struct net_device *dev) * but we eventually sent the packet OK. */ if (status & BD_ENET_TX_DEF) - fep->stats.collisions++; + dev->stats.collisions++; /* Free the sk buffer associated with this last transmit. */ @@ -607,17 +605,17 @@ while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) { /* Check for errors. */ if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO | BD_ENET_RX_CR | BD_ENET_RX_OV)) { - fep->stats.rx_errors++; + dev->stats.rx_errors++; if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH)) { /* Frame too long or too short. */ - fep->stats.rx_length_errors++; + dev->stats.rx_length_errors++; } if (status & BD_ENET_RX_NO) /* Frame alignment */ - fep->stats.rx_frame_errors++; + dev->stats.rx_frame_errors++; if (status & BD_ENET_RX_CR) /* CRC Error */ - fep->stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; if (status & BD_ENET_RX_OV) /* FIFO overrun */ - fep->stats.rx_fifo_errors++; + dev->stats.rx_fifo_errors++; } /* Report late collisions as a frame error. @@ -625,16 +623,16 @@ while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) { * have in the buffer. So, just drop this frame on the floor. */ if (status & BD_ENET_RX_CL) { - fep->stats.rx_errors++; - fep->stats.rx_frame_errors++; + dev->stats.rx_errors++; + dev->stats.rx_frame_errors++; goto rx_processing_done; } /* Process the incoming frame. */ - fep->stats.rx_packets++; + dev->stats.rx_packets++; pkt_len = bdp->cbd_datlen; - fep->stats.rx_bytes += pkt_len; + dev->stats.rx_bytes += pkt_len; data = (__u8*)__va(bdp->cbd_bufaddr); /* This does 16 byte alignment, exactly what we need. @@ -646,7 +644,7 @@ while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) { if (skb == NULL) { printk("%s: Memory squeeze, dropping packet.\n", dev->name); - fep->stats.rx_dropped++; + dev->stats.rx_dropped++; } else { skb_put(skb,pkt_len-4); /* Make room */ skb_copy_to_linear_data(skb, data, pkt_len-4); @@ -2220,13 +2218,6 @@ fec_enet_close(struct net_device *dev) return 0; } -static struct net_device_stats *fec_enet_get_stats(struct net_device *dev) -{ - struct fec_enet_private *fep = netdev_priv(dev); - - return &fep->stats; -} - /* Set or clear the multicast filter for this adaptor. * Skeleton taken from sunlance driver. * The CPM Ethernet implementation allows Multicast as well as individual @@ -2462,7 +2453,6 @@ int __init fec_enet_init(struct net_device *dev) dev->tx_timeout = fec_timeout; dev->watchdog_timeo = TX_TIMEOUT; dev->stop = fec_enet_close; - dev->get_stats = fec_enet_get_stats; dev->set_multicast_list = set_multicast_list; for (i=0; ipoll_controller = gfar_netpoll; #endif dev->stop = gfar_close; - dev->get_stats = gfar_get_stats; dev->change_mtu = gfar_change_mtu; dev->mtu = 1500; dev->set_multicast_list = gfar_set_multi; @@ -1013,7 +1011,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) unsigned long flags; /* Update transmit stats */ - priv->stats.tx_bytes += skb->len; + dev->stats.tx_bytes += skb->len; /* Lock priv now */ spin_lock_irqsave(&priv->txlock, flags); @@ -1086,7 +1084,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) if (txbdp == priv->dirty_tx) { netif_stop_queue(dev); - priv->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; } /* Update the current txbd to the next one */ @@ -1119,14 +1117,6 @@ static int gfar_close(struct net_device *dev) return 0; } -/* returns a net_device_stats structure pointer */ -static struct net_device_stats * gfar_get_stats(struct net_device *dev) -{ - struct gfar_private *priv = netdev_priv(dev); - - return &(priv->stats); -} - /* Changes the mac address if the controller is not running. */ int gfar_set_mac_address(struct net_device *dev) { @@ -1238,7 +1228,7 @@ static void gfar_timeout(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); - priv->stats.tx_errors++; + dev->stats.tx_errors++; if (dev->flags & IFF_UP) { stop_gfar(dev); @@ -1268,12 +1258,12 @@ static irqreturn_t gfar_transmit(int irq, void *dev_id) if ((bdp == priv->cur_tx) && (netif_queue_stopped(dev) == 0)) break; - priv->stats.tx_packets++; + dev->stats.tx_packets++; /* Deferred means some collisions occurred during transmit, */ /* but we eventually sent the packet. */ if (bdp->status & TXBD_DEF) - priv->stats.collisions++; + dev->stats.collisions++; /* Free the sk buffer associated with this TxBD */ dev_kfree_skb_irq(priv->tx_skbuff[priv->skb_dirtytx]); @@ -1345,7 +1335,7 @@ struct sk_buff * gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp) static inline void count_errors(unsigned short status, struct gfar_private *priv) { - struct net_device_stats *stats = &priv->stats; + struct net_device_stats *stats = &dev->stats; struct gfar_extra_stats *estats = &priv->extra_stats; /* If the packet was truncated, none of the other errors @@ -1470,7 +1460,7 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, if (NULL == skb) { if (netif_msg_rx_err(priv)) printk(KERN_WARNING "%s: Missing skb!!.\n", dev->name); - priv->stats.rx_dropped++; + dev->stats.rx_dropped++; priv->extra_stats.rx_skbmissing++; } else { int ret; @@ -1528,7 +1518,7 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit) (RXBD_LARGE | RXBD_SHORT | RXBD_NONOCTET | RXBD_CRCERR | RXBD_OVERRUN | RXBD_TRUNCATED))) { /* Increment the number of packets */ - priv->stats.rx_packets++; + dev->stats.rx_packets++; howmany++; /* Remove the FCS from the packet length */ @@ -1536,7 +1526,7 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit) gfar_process_frame(dev, skb, pkt_len); - priv->stats.rx_bytes += pkt_len; + dev->stats.rx_bytes += pkt_len; } else { count_errors(bdp->status, priv); @@ -1916,17 +1906,17 @@ static irqreturn_t gfar_error(int irq, void *dev_id) /* Update the error counters */ if (events & IEVENT_TXE) { - priv->stats.tx_errors++; + dev->stats.tx_errors++; if (events & IEVENT_LC) - priv->stats.tx_window_errors++; + dev->stats.tx_window_errors++; if (events & IEVENT_CRL) - priv->stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; if (events & IEVENT_XFUN) { if (netif_msg_tx_err(priv)) printk(KERN_DEBUG "%s: TX FIFO underrun, " "packet dropped.\n", dev->name); - priv->stats.tx_dropped++; + dev->stats.tx_dropped++; priv->extra_stats.tx_underrun++; /* Reactivate the Tx Queues */ @@ -1936,7 +1926,7 @@ static irqreturn_t gfar_error(int irq, void *dev_id) printk(KERN_DEBUG "%s: Transmit Error\n", dev->name); } if (events & IEVENT_BSY) { - priv->stats.rx_errors++; + dev->stats.rx_errors++; priv->extra_stats.rx_bsy++; gfar_receive(irq, dev_id); @@ -1951,7 +1941,7 @@ static irqreturn_t gfar_error(int irq, void *dev_id) dev->name, gfar_read(&priv->regs->rstat)); } if (events & IEVENT_BABR) { - priv->stats.rx_errors++; + dev->stats.rx_errors++; priv->extra_stats.rx_babr++; if (netif_msg_rx_err(priv)) diff --git a/drivers/net/hplance.c b/drivers/net/hplance.c index c991cb82ff2..be6e5bc7c88 100644 --- a/drivers/net/hplance.c +++ b/drivers/net/hplance.c @@ -141,7 +141,6 @@ static void __init hplance_init(struct net_device *dev, struct dio_dev *d) dev->poll_controller = lance_poll; #endif dev->hard_start_xmit = &lance_start_xmit; - dev->get_stats = &lance_get_stats; dev->set_multicast_list = &lance_set_multicast; dev->dma = 0; diff --git a/drivers/net/ibmlana.c b/drivers/net/ibmlana.c index 67d82fa7659..eebf39acf58 100644 --- a/drivers/net/ibmlana.c +++ b/drivers/net/ibmlana.c @@ -591,7 +591,7 @@ static void irqrx_handler(struct net_device *dev) skb = dev_alloc_skb(rda.length + 2); if (skb == NULL) - priv->stat.rx_dropped++; + dev->stats.rx_dropped++; else { /* copy out data */ @@ -606,8 +606,8 @@ static void irqrx_handler(struct net_device *dev) /* bookkeeping */ dev->last_rx = jiffies; - priv->stat.rx_packets++; - priv->stat.rx_bytes += rda.length; + dev->stats.rx_packets++; + dev->stats.rx_bytes += rda.length; /* pass to the upper layers */ netif_rx(skb); @@ -617,11 +617,11 @@ static void irqrx_handler(struct net_device *dev) /* otherwise check error status bits and increase statistics */ else { - priv->stat.rx_errors++; + dev->stats.rx_errors++; if (rda.status & RCREG_FAER) - priv->stat.rx_frame_errors++; + dev->stats.rx_frame_errors++; if (rda.status & RCREG_CRCR) - priv->stat.rx_crc_errors++; + dev->stats.rx_crc_errors++; } /* descriptor processed, will become new last descriptor in queue */ @@ -656,8 +656,8 @@ static void irqtx_handler(struct net_device *dev) memcpy_fromio(&tda, priv->base + priv->tdastart + (priv->currtxdescr * sizeof(tda_t)), sizeof(tda_t)); /* update statistics */ - priv->stat.tx_packets++; - priv->stat.tx_bytes += tda.length; + dev->stats.tx_packets++; + dev->stats.tx_bytes += tda.length; /* update our pointers */ priv->txused[priv->currtxdescr] = 0; @@ -680,15 +680,15 @@ static void irqtxerr_handler(struct net_device *dev) memcpy_fromio(&tda, priv->base + priv->tdastart + (priv->currtxdescr * sizeof(tda_t)), sizeof(tda_t)); /* update statistics */ - priv->stat.tx_errors++; + dev->stats.tx_errors++; if (tda.status & (TCREG_NCRS | TCREG_CRSL)) - priv->stat.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; if (tda.status & TCREG_EXC) - priv->stat.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; if (tda.status & TCREG_OWC) - priv->stat.tx_window_errors++; + dev->stats.tx_window_errors++; if (tda.status & TCREG_FU) - priv->stat.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; /* update our pointers */ priv->txused[priv->currtxdescr] = 0; @@ -824,7 +824,7 @@ static int ibmlana_tx(struct sk_buff *skb, struct net_device *dev) if (priv->txusedcnt >= TXBUFCNT) { retval = -EIO; - priv->stat.tx_dropped++; + dev->stats.tx_dropped++; goto tx_done; } @@ -876,14 +876,6 @@ tx_done: return retval; } -/* return pointer to Ethernet statistics */ - -static struct net_device_stats *ibmlana_stats(struct net_device *dev) -{ - ibmlana_priv *priv = netdev_priv(dev); - return &priv->stat; -} - /* switch receiver mode. */ static void ibmlana_set_multicast_list(struct net_device *dev) @@ -978,7 +970,6 @@ static int ibmlana_probe(struct net_device *dev) dev->stop = ibmlana_close; dev->hard_start_xmit = ibmlana_tx; dev->do_ioctl = NULL; - dev->get_stats = ibmlana_stats; dev->set_multicast_list = ibmlana_set_multicast_list; dev->flags |= IFF_MULTICAST; diff --git a/drivers/net/ibmlana.h b/drivers/net/ibmlana.h index 6b58bab9e30..aa3ddbdee4b 100644 --- a/drivers/net/ibmlana.h +++ b/drivers/net/ibmlana.h @@ -26,7 +26,6 @@ typedef enum { typedef struct { unsigned int slot; /* MCA-Slot-# */ - struct net_device_stats stat; /* packet statistics */ int realirq; /* memorizes actual IRQ, even when currently not allocated */ ibmlana_medium medium; /* physical cannector */ diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index db908c40dbe..bdbf3dead4e 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -87,7 +87,6 @@ static int ibmveth_close(struct net_device *dev); static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); static int ibmveth_poll(struct napi_struct *napi, int budget); static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *dev); -static struct net_device_stats *ibmveth_get_stats(struct net_device *dev); static void ibmveth_set_multicast_list(struct net_device *dev); static int ibmveth_change_mtu(struct net_device *dev, int new_mtu); static void ibmveth_proc_register_driver(void); @@ -909,9 +908,9 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) skb->len, DMA_TO_DEVICE); out: spin_lock_irqsave(&adapter->stats_lock, flags); - adapter->stats.tx_dropped += tx_dropped; - adapter->stats.tx_bytes += tx_bytes; - adapter->stats.tx_packets += tx_packets; + netdev->stats.tx_dropped += tx_dropped; + netdev->stats.tx_bytes += tx_bytes; + netdev->stats.tx_packets += tx_packets; adapter->tx_send_failed += tx_send_failed; adapter->tx_map_failed += tx_map_failed; spin_unlock_irqrestore(&adapter->stats_lock, flags); @@ -957,8 +956,8 @@ static int ibmveth_poll(struct napi_struct *napi, int budget) netif_receive_skb(skb); /* send it up */ - adapter->stats.rx_packets++; - adapter->stats.rx_bytes += length; + netdev->stats.rx_packets++; + netdev->stats.rx_bytes += length; frames_processed++; netdev->last_rx = jiffies; } @@ -1003,12 +1002,6 @@ static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance) return IRQ_HANDLED; } -static struct net_device_stats *ibmveth_get_stats(struct net_device *dev) -{ - struct ibmveth_adapter *adapter = dev->priv; - return &adapter->stats; -} - static void ibmveth_set_multicast_list(struct net_device *netdev) { struct ibmveth_adapter *adapter = netdev->priv; @@ -1170,7 +1163,6 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ netdev->open = ibmveth_open; netdev->stop = ibmveth_close; netdev->hard_start_xmit = ibmveth_start_xmit; - netdev->get_stats = ibmveth_get_stats; netdev->set_multicast_list = ibmveth_set_multicast_list; netdev->do_ioctl = ibmveth_ioctl; netdev->ethtool_ops = &netdev_ethtool_ops; diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c index 448e618b697..15949d3df17 100644 --- a/drivers/net/ifb.c +++ b/drivers/net/ifb.c @@ -40,7 +40,6 @@ #define TX_Q_LIMIT 32 struct ifb_private { - struct net_device_stats stats; struct tasklet_struct ifb_tasklet; int tasklet_pending; /* mostly debug stats leave in for now */ @@ -61,7 +60,6 @@ static int numifbs = 2; static void ri_tasklet(unsigned long dev); static int ifb_xmit(struct sk_buff *skb, struct net_device *dev); -static struct net_device_stats *ifb_get_stats(struct net_device *dev); static int ifb_open(struct net_device *dev); static int ifb_close(struct net_device *dev); @@ -70,7 +68,7 @@ static void ri_tasklet(unsigned long dev) struct net_device *_dev = (struct net_device *)dev; struct ifb_private *dp = netdev_priv(_dev); - struct net_device_stats *stats = &dp->stats; + struct net_device_stats *stats = &_dev->stats; struct sk_buff *skb; dp->st_task_enter++; @@ -140,7 +138,6 @@ resched: static void ifb_setup(struct net_device *dev) { /* Initialize the device structure. */ - dev->get_stats = ifb_get_stats; dev->hard_start_xmit = ifb_xmit; dev->open = &ifb_open; dev->stop = &ifb_close; @@ -158,7 +155,7 @@ static void ifb_setup(struct net_device *dev) static int ifb_xmit(struct sk_buff *skb, struct net_device *dev) { struct ifb_private *dp = netdev_priv(dev); - struct net_device_stats *stats = &dp->stats; + struct net_device_stats *stats = &dev->stats; int ret = 0; u32 from = G_TC_FROM(skb->tc_verd); @@ -185,19 +182,6 @@ static int ifb_xmit(struct sk_buff *skb, struct net_device *dev) return ret; } -static struct net_device_stats *ifb_get_stats(struct net_device *dev) -{ - struct ifb_private *dp = netdev_priv(dev); - struct net_device_stats *stats = &dp->stats; - - pr_debug("tasklets stats %ld:%ld:%ld:%ld:%ld:%ld:%ld:%ld:%ld \n", - dp->st_task_enter, dp->st_txq_refl_try, dp->st_rxq_enter, - dp->st_rx2tx_tran, dp->st_rxq_notenter, dp->st_rx_frm_egr, - dp->st_rx_frm_ing, dp->st_rxq_check, dp->st_rxq_rsch); - - return stats; -} - static int ifb_close(struct net_device *dev) { struct ifb_private *dp = netdev_priv(dev); diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c index 0433c41f902..97bd9dc2e52 100644 --- a/drivers/net/iseries_veth.c +++ b/drivers/net/iseries_veth.c @@ -196,7 +196,6 @@ struct veth_lpar_connection { struct veth_port { struct device *dev; - struct net_device_stats stats; u64 mac_addr; HvLpIndexMap lpar_map; @@ -936,9 +935,6 @@ static void veth_release_connection(struct kobject *kobj) static int veth_open(struct net_device *dev) { - struct veth_port *port = (struct veth_port *) dev->priv; - - memset(&port->stats, 0, sizeof (port->stats)); netif_start_queue(dev); return 0; } @@ -949,13 +945,6 @@ static int veth_close(struct net_device *dev) return 0; } -static struct net_device_stats *veth_get_stats(struct net_device *dev) -{ - struct veth_port *port = (struct veth_port *) dev->priv; - - return &port->stats; -} - static int veth_change_mtu(struct net_device *dev, int new_mtu) { if ((new_mtu < 68) || (new_mtu > VETH_MAX_MTU)) @@ -1084,7 +1073,6 @@ static struct net_device * __init veth_probe_one(int vlan, dev->open = veth_open; dev->hard_start_xmit = veth_start_xmit; dev->stop = veth_close; - dev->get_stats = veth_get_stats; dev->change_mtu = veth_change_mtu; dev->set_mac_address = NULL; dev->set_multicast_list = veth_set_multicast_list; @@ -1183,7 +1171,6 @@ static void veth_transmit_to_many(struct sk_buff *skb, HvLpIndexMap lpmask, struct net_device *dev) { - struct veth_port *port = (struct veth_port *) dev->priv; int i, success, error; success = error = 0; @@ -1199,11 +1186,11 @@ static void veth_transmit_to_many(struct sk_buff *skb, } if (error) - port->stats.tx_errors++; + dev->stats.tx_errors++; if (success) { - port->stats.tx_packets++; - port->stats.tx_bytes += skb->len; + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; } } @@ -1541,8 +1528,8 @@ static void veth_receive(struct veth_lpar_connection *cnx, skb->protocol = eth_type_trans(skb, dev); skb->ip_summed = CHECKSUM_NONE; netif_rx(skb); /* send it up */ - port->stats.rx_packets++; - port->stats.rx_bytes += length; + dev->stats.rx_packets++; + dev->stats.rx_bytes += length; } while (startchunk += nchunks, startchunk < VETH_MAX_FRAMES_PER_MSG); /* Ack it */ diff --git a/drivers/net/lib82596.c b/drivers/net/lib82596.c index 5884f5bd04a..afa4638052a 100644 --- a/drivers/net/lib82596.c +++ b/drivers/net/lib82596.c @@ -322,7 +322,6 @@ struct i596_private { struct i596_cmd *cmd_head; int cmd_backlog; u32 last_cmd; - struct net_device_stats stats; int next_tx_cmd; int options; spinlock_t lock; /* serialize access to chip */ @@ -352,7 +351,6 @@ static int i596_open(struct net_device *dev); static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev); static irqreturn_t i596_interrupt(int irq, void *dev_id); static int i596_close(struct net_device *dev); -static struct net_device_stats *i596_get_stats(struct net_device *dev); static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd); static void i596_tx_timeout (struct net_device *dev); static void print_eth(unsigned char *buf, char *str); @@ -725,7 +723,7 @@ memory_squeeze: printk(KERN_ERR "%s: i596_rx Memory squeeze, dropping packet.\n", dev->name); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; } else { if (!rx_in_place) { /* 16 byte align the data fields */ @@ -742,28 +740,28 @@ memory_squeeze: skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; - lp->stats.rx_packets++; - lp->stats.rx_bytes += pkt_len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; } } else { DEB(DEB_ERRORS, printk(KERN_DEBUG "%s: Error, rfd.stat = 0x%04x\n", dev->name, rfd->stat)); - lp->stats.rx_errors++; + dev->stats.rx_errors++; if (rfd->stat & SWAP16(0x0100)) - lp->stats.collisions++; + dev->stats.collisions++; if (rfd->stat & SWAP16(0x8000)) - lp->stats.rx_length_errors++; + dev->stats.rx_length_errors++; if (rfd->stat & SWAP16(0x0001)) - lp->stats.rx_over_errors++; + dev->stats.rx_over_errors++; if (rfd->stat & SWAP16(0x0002)) - lp->stats.rx_fifo_errors++; + dev->stats.rx_fifo_errors++; if (rfd->stat & SWAP16(0x0004)) - lp->stats.rx_frame_errors++; + dev->stats.rx_frame_errors++; if (rfd->stat & SWAP16(0x0008)) - lp->stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; if (rfd->stat & SWAP16(0x0010)) - lp->stats.rx_length_errors++; + dev->stats.rx_length_errors++; } /* Clear the buffer descriptor count and EOF + F flags */ @@ -821,8 +819,8 @@ static inline void i596_cleanup_cmd(struct net_device *dev, struct i596_private dev_kfree_skb(skb); - lp->stats.tx_errors++; - lp->stats.tx_aborted_errors++; + dev->stats.tx_errors++; + dev->stats.tx_aborted_errors++; ptr->v_next = NULL; ptr->b_next = I596_NULL; @@ -951,10 +949,10 @@ static void i596_tx_timeout (struct net_device *dev) "%s: transmit timed out, status resetting.\n", dev->name)); - lp->stats.tx_errors++; + dev->stats.tx_errors++; /* Try to restart the adaptor */ - if (lp->last_restart == lp->stats.tx_packets) { + if (lp->last_restart == dev->stats.tx_packets) { DEB(DEB_ERRORS, printk(KERN_DEBUG "Resetting board.\n")); /* Shutdown and restart */ i596_reset (dev, lp); @@ -964,7 +962,7 @@ static void i596_tx_timeout (struct net_device *dev) lp->dma->scb.command = SWAP16(CUC_START | RX_START); DMA_WBACK_INV(dev, &(lp->dma->scb), sizeof(struct i596_scb)); ca (dev); - lp->last_restart = lp->stats.tx_packets; + lp->last_restart = dev->stats.tx_packets; } dev->trans_start = jiffies; @@ -999,7 +997,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev) DEB(DEB_ERRORS, printk(KERN_DEBUG "%s: xmit ring full, dropping packet.\n", dev->name)); - lp->stats.tx_dropped++; + dev->stats.tx_dropped++; dev_kfree_skb(skb); } else { @@ -1025,8 +1023,8 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev) DMA_WBACK_INV(dev, tbd, sizeof(struct i596_tbd)); i596_add_cmd(dev, &tx_cmd->cmd); - lp->stats.tx_packets++; - lp->stats.tx_bytes += length; + dev->stats.tx_packets++; + dev->stats.tx_bytes += length; } netif_start_queue(dev); @@ -1076,7 +1074,6 @@ static int __devinit i82596_probe(struct net_device *dev) dev->open = i596_open; dev->stop = i596_close; dev->hard_start_xmit = i596_start_xmit; - dev->get_stats = i596_get_stats; dev->set_multicast_list = set_multicast_list; dev->tx_timeout = i596_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; @@ -1197,17 +1194,17 @@ static irqreturn_t i596_interrupt(int irq, void *dev_id) DEB(DEB_TXADDR, print_eth(skb->data, "tx-done")); } else { - lp->stats.tx_errors++; + dev->stats.tx_errors++; if (ptr->status & SWAP16(0x0020)) - lp->stats.collisions++; + dev->stats.collisions++; if (!(ptr->status & SWAP16(0x0040))) - lp->stats.tx_heartbeat_errors++; + dev->stats.tx_heartbeat_errors++; if (ptr->status & SWAP16(0x0400)) - lp->stats.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; if (ptr->status & SWAP16(0x0800)) - lp->stats.collisions++; + dev->stats.collisions++; if (ptr->status & SWAP16(0x1000)) - lp->stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; } dma_unmap_single(dev->dev.parent, tx_cmd->dma_addr, @@ -1292,8 +1289,8 @@ static irqreturn_t i596_interrupt(int irq, void *dev_id) "%s: i596 interrupt receive unit inactive, status 0x%x\n", dev->name, status)); ack_cmd |= RX_START; - lp->stats.rx_errors++; - lp->stats.rx_fifo_errors++; + dev->stats.rx_errors++; + dev->stats.rx_fifo_errors++; rebuild_rx_bufs(dev); } } @@ -1346,13 +1343,6 @@ static int i596_close(struct net_device *dev) return 0; } -static struct net_device_stats *i596_get_stats(struct net_device *dev) -{ - struct i596_private *lp = netdev_priv(dev); - - return &lp->stats; -} - /* * Set or clear the multicast filter for this adaptor. */ diff --git a/drivers/net/lp486e.c b/drivers/net/lp486e.c index 408ae6eb6a8..c5095ecd8b1 100644 --- a/drivers/net/lp486e.c +++ b/drivers/net/lp486e.c @@ -350,7 +350,6 @@ struct i596_private { /* aligned to a 16-byte boundary */ struct i596_cmd *cmd_head; int cmd_backlog; unsigned long last_cmd; - struct net_device_stats stats; spinlock_t cmd_lock; }; @@ -381,7 +380,6 @@ static int i596_open(struct net_device *dev); static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev); static irqreturn_t i596_interrupt(int irq, void *dev_id); static int i596_close(struct net_device *dev); -static struct net_device_stats *i596_get_stats(struct net_device *dev); static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd); static void print_eth(char *); static void set_multicast_list(struct net_device *dev); @@ -670,7 +668,7 @@ i596_rx_one(struct net_device *dev, struct i596_private *lp, if (skb == NULL) { printk ("%s: i596_rx Memory squeeze, " "dropping packet.\n", dev->name); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; return 1; } @@ -679,27 +677,27 @@ i596_rx_one(struct net_device *dev, struct i596_private *lp, skb->protocol = eth_type_trans(skb,dev); netif_rx(skb); dev->last_rx = jiffies; - lp->stats.rx_packets++; + dev->stats.rx_packets++; } else { #if 0 printk("Frame reception error status %04x\n", rfd->stat); #endif - lp->stats.rx_errors++; + dev->stats.rx_errors++; if (rfd->stat & RFD_COLLISION) - lp->stats.collisions++; + dev->stats.collisions++; if (rfd->stat & RFD_SHORT_FRAME_ERR) - lp->stats.rx_length_errors++; + dev->stats.rx_length_errors++; if (rfd->stat & RFD_DMA_ERR) - lp->stats.rx_over_errors++; + dev->stats.rx_over_errors++; if (rfd->stat & RFD_NOBUFS_ERR) - lp->stats.rx_fifo_errors++; + dev->stats.rx_fifo_errors++; if (rfd->stat & RFD_ALIGN_ERR) - lp->stats.rx_frame_errors++; + dev->stats.rx_frame_errors++; if (rfd->stat & RFD_CRC_ERR) - lp->stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; if (rfd->stat & RFD_LENGTH_ERR) - lp->stats.rx_length_errors++; + dev->stats.rx_length_errors++; } rfd->stat = rfd->count = 0; return 0; @@ -755,8 +753,8 @@ i596_cleanup_cmd(struct net_device *dev) { dev_kfree_skb_any(tx_cmd_tbd->skb); - lp->stats.tx_errors++; - lp->stats.tx_aborted_errors++; + dev->stats.tx_errors++; + dev->stats.tx_aborted_errors++; cmd->pa_next = I596_NULL; kfree((unsigned char *)tx_cmd); @@ -867,7 +865,6 @@ static int i596_open(struct net_device *dev) } static int i596_start_xmit (struct sk_buff *skb, struct net_device *dev) { - struct i596_private *lp = dev->priv; struct tx_cmd *tx_cmd; short length; @@ -884,7 +881,7 @@ static int i596_start_xmit (struct sk_buff *skb, struct net_device *dev) { tx_cmd = kmalloc((sizeof (struct tx_cmd) + sizeof (struct i596_tbd)), GFP_ATOMIC); if (tx_cmd == NULL) { printk(KERN_WARNING "%s: i596_xmit Memory squeeze, dropping packet.\n", dev->name); - lp->stats.tx_dropped++; + dev->stats.tx_dropped++; dev_kfree_skb (skb); } else { struct i596_tbd *tx_cmd_tbd; @@ -907,7 +904,7 @@ static int i596_start_xmit (struct sk_buff *skb, struct net_device *dev) { i596_add_cmd (dev, (struct i596_cmd *) tx_cmd); - lp->stats.tx_packets++; + dev->stats.tx_packets++; } return 0; @@ -920,10 +917,10 @@ i596_tx_timeout (struct net_device *dev) { /* Transmitter timeout, serious problems. */ printk(KERN_WARNING "%s: transmit timed out, status resetting.\n", dev->name); - lp->stats.tx_errors++; + dev->stats.tx_errors++; /* Try to restart the adaptor */ - if (lp->last_restart == lp->stats.tx_packets) { + if (lp->last_restart == dev->stats.tx_packets) { printk ("Resetting board.\n"); /* Shutdown and restart */ @@ -933,7 +930,7 @@ i596_tx_timeout (struct net_device *dev) { printk ("Kicking board.\n"); lp->scb.command = (CUC_START | RX_START); CA(); - lp->last_restart = lp->stats.tx_packets; + lp->last_restart = dev->stats.tx_packets; } netif_wake_queue(dev); } @@ -1021,7 +1018,6 @@ static int __init lp486e_probe(struct net_device *dev) { dev->open = &i596_open; dev->stop = &i596_close; dev->hard_start_xmit = &i596_start_xmit; - dev->get_stats = &i596_get_stats; dev->set_multicast_list = &set_multicast_list; dev->watchdog_timeo = 5*HZ; dev->tx_timeout = i596_tx_timeout; @@ -1078,20 +1074,20 @@ i596_handle_CU_completion(struct net_device *dev, if (i596_debug) print_eth(pa_to_va(tx_cmd_tbd->pa_data)); } else { - lp->stats.tx_errors++; + dev->stats.tx_errors++; if (i596_debug) printk("transmission failure:%04x\n", cmd->status); if (cmd->status & 0x0020) - lp->stats.collisions++; + dev->stats.collisions++; if (!(cmd->status & 0x0040)) - lp->stats.tx_heartbeat_errors++; + dev->stats.tx_heartbeat_errors++; if (cmd->status & 0x0400) - lp->stats.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; if (cmd->status & 0x0800) - lp->stats.collisions++; + dev->stats.collisions++; if (cmd->status & 0x1000) - lp->stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; } dev_kfree_skb_irq(tx_cmd_tbd->skb); @@ -1242,12 +1238,6 @@ static int i596_close(struct net_device *dev) { return 0; } -static struct net_device_stats * i596_get_stats(struct net_device *dev) { - struct i596_private *lp = dev->priv; - - return &lp->stats; -} - /* * Set or clear the multicast filter for this adaptor. */ diff --git a/drivers/net/mace.c b/drivers/net/mace.c index de3b002e9a4..ee132b1e09b 100644 --- a/drivers/net/mace.c +++ b/drivers/net/mace.c @@ -57,7 +57,6 @@ struct mace_data { unsigned char tx_fullup; unsigned char tx_active; unsigned char tx_bad_runt; - struct net_device_stats stats; struct timer_list tx_timeout; int timeout_active; int port_aaui; @@ -78,7 +77,6 @@ struct mace_data { static int mace_open(struct net_device *dev); static int mace_close(struct net_device *dev); static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev); -static struct net_device_stats *mace_stats(struct net_device *dev); static void mace_set_multicast(struct net_device *dev); static void mace_reset(struct net_device *dev); static int mace_set_address(struct net_device *dev, void *addr); @@ -188,7 +186,6 @@ static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_i mp->tx_cmds = (volatile struct dbdma_cmd *) DBDMA_ALIGN(mp + 1); mp->rx_cmds = mp->tx_cmds + NCMDS_TX * N_TX_RING + 1; - memset(&mp->stats, 0, sizeof(mp->stats)); memset((char *) mp->tx_cmds, 0, (NCMDS_TX*N_TX_RING + N_RX_RING + 2) * sizeof(struct dbdma_cmd)); init_timer(&mp->tx_timeout); @@ -213,7 +210,6 @@ static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_i dev->open = mace_open; dev->stop = mace_close; dev->hard_start_xmit = mace_xmit_start; - dev->get_stats = mace_stats; dev->set_multicast_list = mace_set_multicast; dev->set_mac_address = mace_set_address; @@ -584,13 +580,6 @@ static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev) return 0; } -static struct net_device_stats *mace_stats(struct net_device *dev) -{ - struct mace_data *p = (struct mace_data *) dev->priv; - - return &p->stats; -} - static void mace_set_multicast(struct net_device *dev) { struct mace_data *mp = (struct mace_data *) dev->priv; @@ -644,19 +633,19 @@ static void mace_set_multicast(struct net_device *dev) spin_unlock_irqrestore(&mp->lock, flags); } -static void mace_handle_misc_intrs(struct mace_data *mp, int intr) +static void mace_handle_misc_intrs(struct mace_data *mp, int intr, struct net_device *dev) { volatile struct mace __iomem *mb = mp->mace; static int mace_babbles, mace_jabbers; if (intr & MPCO) - mp->stats.rx_missed_errors += 256; - mp->stats.rx_missed_errors += in_8(&mb->mpc); /* reading clears it */ + dev->stats.rx_missed_errors += 256; + dev->stats.rx_missed_errors += in_8(&mb->mpc); /* reading clears it */ if (intr & RNTPCO) - mp->stats.rx_length_errors += 256; - mp->stats.rx_length_errors += in_8(&mb->rntpc); /* reading clears it */ + dev->stats.rx_length_errors += 256; + dev->stats.rx_length_errors += in_8(&mb->rntpc); /* reading clears it */ if (intr & CERR) - ++mp->stats.tx_heartbeat_errors; + ++dev->stats.tx_heartbeat_errors; if (intr & BABBLE) if (mace_babbles++ < 4) printk(KERN_DEBUG "mace: babbling transmitter\n"); @@ -680,7 +669,7 @@ static irqreturn_t mace_interrupt(int irq, void *dev_id) spin_lock_irqsave(&mp->lock, flags); intr = in_8(&mb->ir); /* read interrupt register */ in_8(&mb->xmtrc); /* get retries */ - mace_handle_misc_intrs(mp, intr); + mace_handle_misc_intrs(mp, intr, dev); i = mp->tx_empty; while (in_8(&mb->pr) & XMTSV) { @@ -693,7 +682,7 @@ static irqreturn_t mace_interrupt(int irq, void *dev_id) */ intr = in_8(&mb->ir); if (intr != 0) - mace_handle_misc_intrs(mp, intr); + mace_handle_misc_intrs(mp, intr, dev); if (mp->tx_bad_runt) { fs = in_8(&mb->xmtfs); mp->tx_bad_runt = 0; @@ -767,14 +756,14 @@ static irqreturn_t mace_interrupt(int irq, void *dev_id) } /* Update stats */ if (fs & (UFLO|LCOL|LCAR|RTRY)) { - ++mp->stats.tx_errors; + ++dev->stats.tx_errors; if (fs & LCAR) - ++mp->stats.tx_carrier_errors; + ++dev->stats.tx_carrier_errors; if (fs & (UFLO|LCOL|RTRY)) - ++mp->stats.tx_aborted_errors; + ++dev->stats.tx_aborted_errors; } else { - mp->stats.tx_bytes += mp->tx_bufs[i]->len; - ++mp->stats.tx_packets; + dev->stats.tx_bytes += mp->tx_bufs[i]->len; + ++dev->stats.tx_packets; } dev_kfree_skb_irq(mp->tx_bufs[i]); --mp->tx_active; @@ -828,7 +817,7 @@ static void mace_tx_timeout(unsigned long data) goto out; /* update various counters */ - mace_handle_misc_intrs(mp, in_8(&mb->ir)); + mace_handle_misc_intrs(mp, in_8(&mb->ir), dev); cp = mp->tx_cmds + NCMDS_TX * mp->tx_empty; @@ -848,7 +837,7 @@ static void mace_tx_timeout(unsigned long data) /* fix up the transmit side */ i = mp->tx_empty; mp->tx_active = 0; - ++mp->stats.tx_errors; + ++dev->stats.tx_errors; if (mp->tx_bad_runt) { mp->tx_bad_runt = 0; } else if (i != mp->tx_fill) { @@ -916,18 +905,18 @@ static irqreturn_t mace_rxdma_intr(int irq, void *dev_id) /* got a packet, have a look at it */ skb = mp->rx_bufs[i]; if (skb == 0) { - ++mp->stats.rx_dropped; + ++dev->stats.rx_dropped; } else if (nb > 8) { data = skb->data; frame_status = (data[nb-3] << 8) + data[nb-4]; if (frame_status & (RS_OFLO|RS_CLSN|RS_FRAMERR|RS_FCSERR)) { - ++mp->stats.rx_errors; + ++dev->stats.rx_errors; if (frame_status & RS_OFLO) - ++mp->stats.rx_over_errors; + ++dev->stats.rx_over_errors; if (frame_status & RS_FRAMERR) - ++mp->stats.rx_frame_errors; + ++dev->stats.rx_frame_errors; if (frame_status & RS_FCSERR) - ++mp->stats.rx_crc_errors; + ++dev->stats.rx_crc_errors; } else { /* Mace feature AUTO_STRIP_RCV is on by default, dropping the * FCS on frames with 802.3 headers. This means that Ethernet @@ -939,15 +928,15 @@ static irqreturn_t mace_rxdma_intr(int irq, void *dev_id) nb -= 8; skb_put(skb, nb); skb->protocol = eth_type_trans(skb, dev); - mp->stats.rx_bytes += skb->len; + dev->stats.rx_bytes += skb->len; netif_rx(skb); dev->last_rx = jiffies; mp->rx_bufs[i] = NULL; - ++mp->stats.rx_packets; + ++dev->stats.rx_packets; } } else { - ++mp->stats.rx_errors; - ++mp->stats.rx_length_errors; + ++dev->stats.rx_errors; + ++dev->stats.rx_length_errors; } /* advance to next */ diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c index 5d2daa24887..57f7c1a2c1d 100644 --- a/drivers/net/macmace.c +++ b/drivers/net/macmace.c @@ -65,7 +65,6 @@ struct mace_data { unsigned char *rx_ring; dma_addr_t rx_ring_phys; int dma_intr; - struct net_device_stats stats; int rx_slot, rx_tail; int tx_slot, tx_sloti, tx_count; int chipid; @@ -92,7 +91,6 @@ struct mace_frame { static int mace_open(struct net_device *dev); static int mace_close(struct net_device *dev); static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev); -static struct net_device_stats *mace_stats(struct net_device *dev); static void mace_set_multicast(struct net_device *dev); static int mace_set_address(struct net_device *dev, void *addr); static void mace_reset(struct net_device *dev); @@ -242,14 +240,11 @@ static int __devinit mace_probe(struct platform_device *pdev) return -ENODEV; } - memset(&mp->stats, 0, sizeof(mp->stats)); - dev->open = mace_open; dev->stop = mace_close; dev->hard_start_xmit = mace_xmit_start; dev->tx_timeout = mace_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; - dev->get_stats = mace_stats; dev->set_multicast_list = mace_set_multicast; dev->set_mac_address = mace_set_address; @@ -472,8 +467,8 @@ static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev) mp->tx_count--; local_irq_restore(flags); - mp->stats.tx_packets++; - mp->stats.tx_bytes += skb->len; + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; /* We need to copy into our xmit buffer to take care of alignment and caching issues */ skb_copy_from_linear_data(skb, mp->tx_ring, skb->len); @@ -492,12 +487,6 @@ static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } -static struct net_device_stats *mace_stats(struct net_device *dev) -{ - struct mace_data *mp = netdev_priv(dev); - return &mp->stats; -} - static void mace_set_multicast(struct net_device *dev) { struct mace_data *mp = netdev_priv(dev); @@ -555,13 +544,13 @@ static void mace_handle_misc_intrs(struct mace_data *mp, int intr) static int mace_babbles, mace_jabbers; if (intr & MPCO) - mp->stats.rx_missed_errors += 256; - mp->stats.rx_missed_errors += mb->mpc; /* reading clears it */ + dev->stats.rx_missed_errors += 256; + dev->stats.rx_missed_errors += mb->mpc; /* reading clears it */ if (intr & RNTPCO) - mp->stats.rx_length_errors += 256; - mp->stats.rx_length_errors += mb->rntpc; /* reading clears it */ + dev->stats.rx_length_errors += 256; + dev->stats.rx_length_errors += mb->rntpc; /* reading clears it */ if (intr & CERR) - ++mp->stats.tx_heartbeat_errors; + ++dev->stats.tx_heartbeat_errors; if (intr & BABBLE) if (mace_babbles++ < 4) printk(KERN_DEBUG "macmace: babbling transmitter\n"); @@ -600,14 +589,14 @@ static irqreturn_t mace_interrupt(int irq, void *dev_id) } /* Update stats */ if (fs & (UFLO|LCOL|LCAR|RTRY)) { - ++mp->stats.tx_errors; + ++dev->stats.tx_errors; if (fs & LCAR) - ++mp->stats.tx_carrier_errors; + ++dev->stats.tx_carrier_errors; else if (fs & (UFLO|LCOL|RTRY)) { - ++mp->stats.tx_aborted_errors; + ++dev->stats.tx_aborted_errors; if (mb->xmtfs & UFLO) { printk(KERN_ERR "%s: DMA underrun.\n", dev->name); - mp->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; mace_txdma_reset(dev); } } @@ -661,23 +650,23 @@ static void mace_dma_rx_frame(struct net_device *dev, struct mace_frame *mf) unsigned int frame_status = mf->rcvsts; if (frame_status & (RS_OFLO | RS_CLSN | RS_FRAMERR | RS_FCSERR)) { - mp->stats.rx_errors++; + dev->stats.rx_errors++; if (frame_status & RS_OFLO) { printk(KERN_DEBUG "%s: fifo overflow.\n", dev->name); - mp->stats.rx_fifo_errors++; + dev->stats.rx_fifo_errors++; } if (frame_status & RS_CLSN) - mp->stats.collisions++; + dev->stats.collisions++; if (frame_status & RS_FRAMERR) - mp->stats.rx_frame_errors++; + dev->stats.rx_frame_errors++; if (frame_status & RS_FCSERR) - mp->stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; } else { unsigned int frame_length = mf->rcvcnt + ((frame_status & 0x0F) << 8 ); skb = dev_alloc_skb(frame_length + 2); if (!skb) { - mp->stats.rx_dropped++; + dev->stats.rx_dropped++; return; } skb_reserve(skb, 2); @@ -686,8 +675,8 @@ static void mace_dma_rx_frame(struct net_device *dev, struct mace_frame *mf) skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; - mp->stats.rx_packets++; - mp->stats.rx_bytes += frame_length; + dev->stats.rx_packets++; + dev->stats.rx_bytes += frame_length; } } diff --git a/drivers/net/meth.c b/drivers/net/meth.c index 32bed6bc6c0..fe5b6c37207 100644 --- a/drivers/net/meth.c +++ b/drivers/net/meth.c @@ -66,7 +66,6 @@ module_param(timeout, int, 0); * packets in and out, so there is place for a packet */ struct meth_private { - struct net_device_stats stats; /* in-memory copy of MAC Control register */ unsigned long mac_ctrl; /* in-memory copy of DMA Control register */ @@ -401,15 +400,15 @@ static void meth_rx(struct net_device* dev, unsigned long int_status) printk(KERN_DEBUG "%s: bogus packet size: %ld, status=%#2lx.\n", dev->name, priv->rx_write, priv->rx_ring[priv->rx_write]->status.raw); - priv->stats.rx_errors++; - priv->stats.rx_length_errors++; + dev->stats.rx_errors++; + dev->stats.rx_length_errors++; skb = priv->rx_skbs[priv->rx_write]; } else { skb = alloc_skb(METH_RX_BUFF_SIZE, GFP_ATOMIC); if (!skb) { /* Ouch! No memory! Drop packet on the floor */ DPRINTK("No mem: dropping packet\n"); - priv->stats.rx_dropped++; + dev->stats.rx_dropped++; skb = priv->rx_skbs[priv->rx_write]; } else { struct sk_buff *skb_c = priv->rx_skbs[priv->rx_write]; @@ -421,13 +420,13 @@ static void meth_rx(struct net_device* dev, unsigned long int_status) priv->rx_skbs[priv->rx_write] = skb; skb_c->protocol = eth_type_trans(skb_c, dev); dev->last_rx = jiffies; - priv->stats.rx_packets++; - priv->stats.rx_bytes += len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += len; netif_rx(skb_c); } } } else { - priv->stats.rx_errors++; + dev->stats.rx_errors++; skb=priv->rx_skbs[priv->rx_write]; #if MFE_DEBUG>0 printk(KERN_WARNING "meth: RX error: status=0x%016lx\n",status); @@ -490,10 +489,10 @@ static void meth_tx_cleanup(struct net_device* dev, unsigned long int_status) #endif if (status & METH_TX_ST_DONE) { if (status & METH_TX_ST_SUCCESS){ - priv->stats.tx_packets++; - priv->stats.tx_bytes += skb->len; + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; } else { - priv->stats.tx_errors++; + dev->stats.tx_errors++; #if MFE_DEBUG>=1 DPRINTK("TX error: status=%016lx <",status); if(status & METH_TX_ST_SUCCESS) @@ -734,7 +733,7 @@ static void meth_tx_timeout(struct net_device *dev) /* Try to reset the interface. */ meth_reset(dev); - priv->stats.tx_errors++; + dev->stats.tx_errors++; /* Clear all rings */ meth_free_tx_ring(priv); @@ -773,12 +772,6 @@ static int meth_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) /* * Return statistics to the caller */ -static struct net_device_stats *meth_stats(struct net_device *dev) -{ - struct meth_private *priv = netdev_priv(dev); - return &priv->stats; -} - /* * The init function. */ @@ -796,7 +789,6 @@ static int __init meth_probe(struct platform_device *pdev) dev->stop = meth_release; dev->hard_start_xmit = meth_tx; dev->do_ioctl = meth_ioctl; - dev->get_stats = meth_stats; #ifdef HAVE_TX_TIMEOUT dev->tx_timeout = meth_tx_timeout; dev->watchdog_timeo = timeout; diff --git a/drivers/net/mipsnet.c b/drivers/net/mipsnet.c index c0f5ad38fb1..d593175ab6f 100644 --- a/drivers/net/mipsnet.c +++ b/drivers/net/mipsnet.c @@ -21,10 +21,6 @@ #define mipsnet_reg_address(dev, field) (dev->base_addr + field_offset(field)) -struct mipsnet_priv { - struct net_device_stats stats; -}; - static char mipsnet_string[] = "mipsnet"; /* @@ -49,7 +45,6 @@ static inline ssize_t mipsnet_put_todevice(struct net_device *dev, { int count_to_go = skb->len; char *buf_ptr = skb->data; - struct mipsnet_priv *mp = netdev_priv(dev); pr_debug("%s: %s(): telling MIPSNET txDataCount(%d)\n", dev->name, __FUNCTION__, skb->len); @@ -63,8 +58,8 @@ static inline ssize_t mipsnet_put_todevice(struct net_device *dev, outb(*buf_ptr, mipsnet_reg_address(dev, txDataBuffer)); } - mp->stats.tx_packets++; - mp->stats.tx_bytes += skb->len; + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; return skb->len; } @@ -87,10 +82,9 @@ static inline ssize_t mipsnet_get_fromdev(struct net_device *dev, size_t count) { struct sk_buff *skb; size_t len = count; - struct mipsnet_priv *mp = netdev_priv(dev); if (!(skb = alloc_skb(len + 2, GFP_KERNEL))) { - mp->stats.rx_dropped++; + dev->stats.rx_dropped++; return -ENOMEM; } @@ -105,8 +99,8 @@ static inline ssize_t mipsnet_get_fromdev(struct net_device *dev, size_t count) dev->name, __FUNCTION__); netif_rx(skb); - mp->stats.rx_packets++; - mp->stats.rx_bytes += len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += len; return count; } @@ -203,13 +197,6 @@ static int mipsnet_close(struct net_device *dev) return 0; } -static struct net_device_stats *mipsnet_get_stats(struct net_device *dev) -{ - struct mipsnet_priv *mp = netdev_priv(dev); - - return &mp->stats; -} - static void mipsnet_set_mclist(struct net_device *dev) { // we don't do anything @@ -221,7 +208,7 @@ static int __init mipsnet_probe(struct device *dev) struct net_device *netdev; int err; - netdev = alloc_etherdev(sizeof(struct mipsnet_priv)); + netdev = alloc_etherdev(0); if (!netdev) { err = -ENOMEM; goto out; @@ -232,7 +219,6 @@ static int __init mipsnet_probe(struct device *dev) netdev->open = mipsnet_open; netdev->stop = mipsnet_close; netdev->hard_start_xmit = mipsnet_xmit; - netdev->get_stats = mipsnet_get_stats; netdev->set_multicast_list = mipsnet_set_mclist; /* diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 2a808e265a3..35781616eb2 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -63,7 +63,6 @@ static unsigned int mv643xx_eth_port_disable_rx(unsigned int port_num); static int mv643xx_eth_open(struct net_device *); static int mv643xx_eth_stop(struct net_device *); static int mv643xx_eth_change_mtu(struct net_device *, int); -static struct net_device_stats *mv643xx_eth_get_stats(struct net_device *); static void eth_port_init_mac_tables(unsigned int eth_port_num); #ifdef MV643XX_NAPI static int mv643xx_poll(struct napi_struct *napi, int budget); @@ -341,7 +340,7 @@ int mv643xx_eth_free_tx_descs(struct net_device *dev, int force) if (cmd_sts & ETH_ERROR_SUMMARY) { printk("%s: Error in TX\n", dev->name); - mp->stats.tx_errors++; + dev->stats.tx_errors++; } spin_unlock_irqrestore(&mp->lock, flags); @@ -388,7 +387,7 @@ static void mv643xx_eth_free_all_tx_descs(struct net_device *dev) static int mv643xx_eth_receive_queue(struct net_device *dev, int budget) { struct mv643xx_private *mp = netdev_priv(dev); - struct net_device_stats *stats = &mp->stats; + struct net_device_stats *stats = &dev->stats; unsigned int received_packets = 0; struct sk_buff *skb; struct pkt_info pkt_info; @@ -1192,7 +1191,7 @@ static void eth_tx_submit_descs_for_skb(struct mv643xx_private *mp, static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct mv643xx_private *mp = netdev_priv(dev); - struct net_device_stats *stats = &mp->stats; + struct net_device_stats *stats = &dev->stats; unsigned long flags; BUG_ON(netif_queue_stopped(dev)); @@ -1228,23 +1227,6 @@ static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev) return 0; /* success */ } -/* - * mv643xx_eth_get_stats - * - * Returns a pointer to the interface statistics. - * - * Input : dev - a pointer to the required interface - * - * Output : a pointer to the interface's statistics - */ - -static struct net_device_stats *mv643xx_eth_get_stats(struct net_device *dev) -{ - struct mv643xx_private *mp = netdev_priv(dev); - - return &mp->stats; -} - #ifdef CONFIG_NET_POLL_CONTROLLER static void mv643xx_netpoll(struct net_device *netdev) { @@ -1339,7 +1321,6 @@ static int mv643xx_eth_probe(struct platform_device *pdev) dev->open = mv643xx_eth_open; dev->stop = mv643xx_eth_stop; dev->hard_start_xmit = mv643xx_eth_start_xmit; - dev->get_stats = mv643xx_eth_get_stats; dev->set_mac_address = mv643xx_eth_set_mac_address; dev->set_multicast_list = mv643xx_eth_set_rx_mode; diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c index 331b76c4956..35c4c598c8d 100644 --- a/drivers/net/myri_sbus.c +++ b/drivers/net/myri_sbus.c @@ -353,7 +353,7 @@ static void myri_tx(struct myri_eth *mp, struct net_device *dev) sbus_unmap_single(mp->myri_sdev, dma_addr, skb->len, SBUS_DMA_TODEVICE); dev_kfree_skb(skb); mp->tx_skbs[entry] = NULL; - mp->enet_stats.tx_packets++; + dev->stats.tx_packets++; entry = NEXT_TX(entry); } mp->tx_old = entry; @@ -434,20 +434,20 @@ static void myri_rx(struct myri_eth *mp, struct net_device *dev) RX_ALLOC_SIZE, SBUS_DMA_FROMDEVICE); if (len < (ETH_HLEN + MYRI_PAD_LEN) || (skb->data[0] != MYRI_PAD_LEN)) { DRX(("ERROR[")); - mp->enet_stats.rx_errors++; + dev->stats.rx_errors++; if (len < (ETH_HLEN + MYRI_PAD_LEN)) { DRX(("BAD_LENGTH] ")); - mp->enet_stats.rx_length_errors++; + dev->stats.rx_length_errors++; } else { DRX(("NO_PADDING] ")); - mp->enet_stats.rx_frame_errors++; + dev->stats.rx_frame_errors++; } /* Return it to the LANAI. */ drop_it: drops++; DRX(("DROP ")); - mp->enet_stats.rx_dropped++; + dev->stats.rx_dropped++; sbus_dma_sync_single_for_device(mp->myri_sdev, sbus_readl(&rxd->myri_scatters[0].addr), RX_ALLOC_SIZE, @@ -527,8 +527,8 @@ static void myri_rx(struct myri_eth *mp, struct net_device *dev) netif_rx(skb); dev->last_rx = jiffies; - mp->enet_stats.rx_packets++; - mp->enet_stats.rx_bytes += len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += len; next: DRX(("NEXT\n")); entry = NEXT_RX(entry); @@ -596,7 +596,7 @@ static void myri_tx_timeout(struct net_device *dev) printk(KERN_ERR "%s: transmit timed out, resetting\n", dev->name); - mp->enet_stats.tx_errors++; + dev->stats.tx_errors++; myri_init(mp, 0); netif_wake_queue(dev); } @@ -806,9 +806,6 @@ static int myri_change_mtu(struct net_device *dev, int new_mtu) return 0; } -static struct net_device_stats *myri_get_stats(struct net_device *dev) -{ return &(((struct myri_eth *)dev->priv)->enet_stats); } - static void myri_set_multicast(struct net_device *dev) { /* Do nothing, all MyriCOM nodes transmit multicast frames @@ -1060,7 +1057,6 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev) dev->hard_start_xmit = &myri_start_xmit; dev->tx_timeout = &myri_tx_timeout; dev->watchdog_timeo = 5*HZ; - dev->get_stats = &myri_get_stats; dev->set_multicast_list = &myri_set_multicast; dev->irq = sdev->irqs[0]; diff --git a/drivers/net/myri_sbus.h b/drivers/net/myri_sbus.h index 2f69ef7cdcc..5d93fcc95d5 100644 --- a/drivers/net/myri_sbus.h +++ b/drivers/net/myri_sbus.h @@ -280,7 +280,6 @@ struct myri_eth { void __iomem *lregs; /* Quick ptr to LANAI regs. */ struct sk_buff *rx_skbs[RX_RING_SIZE+1];/* RX skb's */ struct sk_buff *tx_skbs[TX_RING_SIZE]; /* TX skb's */ - struct net_device_stats enet_stats; /* Interface stats. */ /* These are less frequently accessed. */ void __iomem *regs; /* MyriCOM register space. */ diff --git a/drivers/net/netx-eth.c b/drivers/net/netx-eth.c index 6fee405d840..eb0aff787df 100644 --- a/drivers/net/netx-eth.c +++ b/drivers/net/netx-eth.c @@ -97,7 +97,6 @@ struct netx_eth_priv { void __iomem *sram_base, *xpec_base, *xmac_base; int id; - struct net_device_stats stats; struct mii_if_info mii; u32 msg_enable; struct xc *xc; @@ -129,8 +128,8 @@ netx_eth_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev) FIFO_PTR_FRAMELEN(len)); ndev->trans_start = jiffies; - priv->stats.tx_packets++; - priv->stats.tx_bytes += skb->len; + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; netif_stop_queue(ndev); spin_unlock_irq(&priv->lock); @@ -156,7 +155,7 @@ static void netx_eth_receive(struct net_device *ndev) if (unlikely(skb == NULL)) { printk(KERN_NOTICE "%s: Low memory, packet dropped.\n", ndev->name); - priv->stats.rx_dropped++; + dev->stats.rx_dropped++; return; } @@ -170,8 +169,8 @@ static void netx_eth_receive(struct net_device *ndev) ndev->last_rx = jiffies; skb->protocol = eth_type_trans(skb, ndev); netif_rx(skb); - priv->stats.rx_packets++; - priv->stats.rx_bytes += len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += len; } static irqreturn_t @@ -210,12 +209,6 @@ netx_eth_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static struct net_device_stats *netx_eth_query_statistics(struct net_device *ndev) -{ - struct netx_eth_priv *priv = netdev_priv(ndev); - return &priv->stats; -} - static int netx_eth_open(struct net_device *ndev) { struct netx_eth_priv *priv = netdev_priv(ndev); @@ -323,7 +316,6 @@ static int netx_eth_enable(struct net_device *ndev) ndev->hard_start_xmit = netx_eth_hard_start_xmit; ndev->tx_timeout = netx_eth_timeout; ndev->watchdog_timeo = msecs_to_jiffies(5000); - ndev->get_stats = netx_eth_query_statistics; ndev->set_multicast_list = netx_eth_set_multicast_list; priv->msg_enable = NETIF_MSG_LINK; diff --git a/drivers/net/ni5010.c b/drivers/net/ni5010.c index cc1d09a21c0..1dc74a78afa 100644 --- a/drivers/net/ni5010.c +++ b/drivers/net/ni5010.c @@ -89,7 +89,6 @@ static unsigned int ports[] __initdata = /* Information that needs to be kept for each board. */ struct ni5010_local { - struct net_device_stats stats; int o_pkt_size; spinlock_t lock; }; @@ -103,7 +102,6 @@ static irqreturn_t ni5010_interrupt(int irq, void *dev_id); static void ni5010_rx(struct net_device *dev); static void ni5010_timeout(struct net_device *dev); static int ni5010_close(struct net_device *dev); -static struct net_device_stats *ni5010_get_stats(struct net_device *dev); static void ni5010_set_multicast_list(struct net_device *dev); static void reset_receiver(struct net_device *dev); @@ -334,7 +332,6 @@ static int __init ni5010_probe1(struct net_device *dev, int ioaddr) dev->open = ni5010_open; dev->stop = ni5010_close; dev->hard_start_xmit = ni5010_send_packet; - dev->get_stats = ni5010_get_stats; dev->set_multicast_list = ni5010_set_multicast_list; dev->tx_timeout = ni5010_timeout; dev->watchdog_timeo = HZ/20; @@ -532,11 +529,11 @@ static void ni5010_rx(struct net_device *dev) if ( (rcv_stat & RS_VALID_BITS) != RS_PKT_OK) { PRINTK((KERN_INFO "%s: receive error.\n", dev->name)); - lp->stats.rx_errors++; - if (rcv_stat & RS_RUNT) lp->stats.rx_length_errors++; - if (rcv_stat & RS_ALIGN) lp->stats.rx_frame_errors++; - if (rcv_stat & RS_CRC_ERR) lp->stats.rx_crc_errors++; - if (rcv_stat & RS_OFLW) lp->stats.rx_fifo_errors++; + dev->stats.rx_errors++; + if (rcv_stat & RS_RUNT) dev->stats.rx_length_errors++; + if (rcv_stat & RS_ALIGN) dev->stats.rx_frame_errors++; + if (rcv_stat & RS_CRC_ERR) dev->stats.rx_crc_errors++; + if (rcv_stat & RS_OFLW) dev->stats.rx_fifo_errors++; outb(0xff, EDLC_RCLR); /* Clear the interrupt */ return; } @@ -547,8 +544,8 @@ static void ni5010_rx(struct net_device *dev) if (i_pkt_size > ETH_FRAME_LEN || i_pkt_size < 10 ) { PRINTK((KERN_DEBUG "%s: Packet size error, packet size = %#4.4x\n", dev->name, i_pkt_size)); - lp->stats.rx_errors++; - lp->stats.rx_length_errors++; + dev->stats.rx_errors++; + dev->stats.rx_length_errors++; return; } @@ -556,7 +553,7 @@ static void ni5010_rx(struct net_device *dev) skb = dev_alloc_skb(i_pkt_size + 3); if (skb == NULL) { printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; return; } @@ -573,8 +570,8 @@ static void ni5010_rx(struct net_device *dev) skb->protocol = eth_type_trans(skb,dev); netif_rx(skb); dev->last_rx = jiffies; - lp->stats.rx_packets++; - lp->stats.rx_bytes += i_pkt_size; + dev->stats.rx_packets++; + dev->stats.rx_bytes += i_pkt_size; PRINTK2((KERN_DEBUG "%s: Received packet, size=%#4.4x\n", dev->name, i_pkt_size)); @@ -602,14 +599,14 @@ static int process_xmt_interrupt(struct net_device *dev) /* outb(0, IE_MMODE); */ /* xmt buf on sysbus FIXME: needed ? */ outb(MM_EN_XMT | MM_MUX, IE_MMODE); outb(XM_ALL, EDLC_XMASK); /* Enable xmt IRQ's */ - lp->stats.collisions++; + dev->stats.collisions++; return 1; } /* FIXME: handle other xmt error conditions */ - lp->stats.tx_packets++; - lp->stats.tx_bytes += lp->o_pkt_size; + dev->stats.tx_packets++; + dev->stats.tx_bytes += lp->o_pkt_size; netif_wake_queue(dev); PRINTK2((KERN_DEBUG "%s: sent packet, size=%#4.4x\n", @@ -638,24 +635,6 @@ static int ni5010_close(struct net_device *dev) } -/* Get the current statistics. This may be called with the card open or - closed. */ -static struct net_device_stats *ni5010_get_stats(struct net_device *dev) -{ - struct ni5010_local *lp = netdev_priv(dev); - - PRINTK2((KERN_DEBUG "%s: entering ni5010_get_stats\n", dev->name)); - - if (NI5010_DEBUG) ni5010_show_registers(dev); - - /* cli(); */ - /* Update the statistics from the device registers. */ - /* We do this in the interrupt handler */ - /* sti(); */ - - return &lp->stats; -} - /* Set or clear the multicast filter for this adaptor. num_addrs == -1 Promiscuous mode, receive all packets num_addrs == 0 Normal mode, clear multicast list diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 723685ee57a..f310d94443a 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -530,8 +530,8 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) } else skb->ip_summed = CHECKSUM_NONE; - mac->stats.rx_bytes += len; - mac->stats.rx_packets++; + mac->netdev->stats.rx_bytes += len; + mac->netdev->stats.rx_packets++; skb->protocol = eth_type_trans(skb, mac->netdev); netif_receive_skb(skb); @@ -1032,8 +1032,8 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev) info->skb = skb; txring->next_to_fill++; - mac->stats.tx_packets++; - mac->stats.tx_bytes += skb->len; + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; spin_unlock_irqrestore(&txring->lock, flags); @@ -1047,14 +1047,6 @@ out_err: return NETDEV_TX_BUSY; } -static struct net_device_stats *pasemi_mac_get_stats(struct net_device *dev) -{ - struct pasemi_mac *mac = netdev_priv(dev); - - return &mac->stats; -} - - static void pasemi_mac_set_rx_mode(struct net_device *dev) { struct pasemi_mac *mac = netdev_priv(dev); @@ -1223,7 +1215,6 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) dev->open = pasemi_mac_open; dev->stop = pasemi_mac_close; dev->hard_start_xmit = pasemi_mac_start_tx; - dev->get_stats = pasemi_mac_get_stats; dev->set_multicast_list = pasemi_mac_set_rx_mode; err = pasemi_mac_map_regs(mac); diff --git a/drivers/net/pasemi_mac.h b/drivers/net/pasemi_mac.h index c5b0adbc182..c52cfcb6c4c 100644 --- a/drivers/net/pasemi_mac.h +++ b/drivers/net/pasemi_mac.h @@ -60,7 +60,6 @@ struct pasemi_mac { struct pci_dev *iob_pdev; struct phy_device *phydev; struct napi_struct napi; - struct net_device_stats stats; /* Pointer to the cacheable per-channel status registers */ u64 *rx_status; diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c index a4b16484a5f..7dace63fb6e 100644 --- a/drivers/net/pci-skeleton.c +++ b/drivers/net/pci-skeleton.c @@ -457,7 +457,6 @@ struct netdrv_private { void *mmio_addr; int drv_flags; struct pci_dev *pci_dev; - struct net_device_stats stats; struct timer_list timer; /* Media selection timer. */ unsigned char *rx_ring; unsigned int cur_rx; /* Index into the Rx buffer of next Rx pkt. */ @@ -505,7 +504,6 @@ static int netdrv_start_xmit (struct sk_buff *skb, static irqreturn_t netdrv_interrupt (int irq, void *dev_instance); static int netdrv_close (struct net_device *dev); static int netdrv_ioctl (struct net_device *dev, struct ifreq *rq, int cmd); -static struct net_device_stats *netdrv_get_stats (struct net_device *dev); static void netdrv_set_rx_mode (struct net_device *dev); static void netdrv_hw_start (struct net_device *dev); @@ -775,7 +773,6 @@ static int __devinit netdrv_init_one (struct pci_dev *pdev, dev->open = netdrv_open; dev->hard_start_xmit = netdrv_start_xmit; dev->stop = netdrv_close; - dev->get_stats = netdrv_get_stats; dev->set_multicast_list = netdrv_set_rx_mode; dev->do_ioctl = netdrv_ioctl; dev->tx_timeout = netdrv_tx_timeout; @@ -1276,7 +1273,7 @@ static void netdrv_tx_clear (struct netdrv_private *tp) if (rp->skb) { dev_kfree_skb (rp->skb); rp->skb = NULL; - tp->stats.tx_dropped++; + dev->stats.tx_dropped++; } } } @@ -1389,25 +1386,25 @@ static void netdrv_tx_interrupt (struct net_device *dev, /* There was an major error, log it. */ DPRINTK ("%s: Transmit error, Tx status %8.8x.\n", dev->name, txstatus); - tp->stats.tx_errors++; + dev->stats.tx_errors++; if (txstatus & TxAborted) { - tp->stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; NETDRV_W32 (TxConfig, TxClearAbt | (TX_DMA_BURST << TxDMAShift)); } if (txstatus & TxCarrierLost) - tp->stats.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; if (txstatus & TxOutOfWindow) - tp->stats.tx_window_errors++; + dev->stats.tx_window_errors++; } else { if (txstatus & TxUnderrun) { /* Add 64 to the Tx FIFO threshold. */ if (tp->tx_flag < 0x00300000) tp->tx_flag += 0x00020000; - tp->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; } - tp->stats.collisions += (txstatus >> 24) & 15; - tp->stats.tx_bytes += txstatus & 0x7ff; - tp->stats.tx_packets++; + dev->stats.collisions += (txstatus >> 24) & 15; + dev->stats.tx_bytes += txstatus & 0x7ff; + dev->stats.tx_packets++; } /* Free the original skb. */ @@ -1460,13 +1457,13 @@ static void netdrv_rx_err (u32 rx_status, struct net_device *dev, dev->name, rx_status); /* A.C.: The chip hangs here. */ } - tp->stats.rx_errors++; + dev->stats.rx_errors++; if (rx_status & (RxBadSymbol | RxBadAlign)) - tp->stats.rx_frame_errors++; + dev->stats.rx_frame_errors++; if (rx_status & (RxRunt | RxTooLong)) - tp->stats.rx_length_errors++; + dev->stats.rx_length_errors++; if (rx_status & RxCRCErr) - tp->stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; /* Reset the receiver, based on RealTek recommendation. (Bug?) */ tp->cur_rx = 0; @@ -1572,13 +1569,13 @@ static void netdrv_rx_interrupt (struct net_device *dev, skb->protocol = eth_type_trans (skb, dev); netif_rx (skb); dev->last_rx = jiffies; - tp->stats.rx_bytes += pkt_size; - tp->stats.rx_packets++; + dev->stats.rx_bytes += pkt_size; + dev->stats.rx_packets++; } else { printk (KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name); - tp->stats.rx_dropped++; + dev->stats.rx_dropped++; } cur_rx = (cur_rx + rx_size + 4 + 3) & ~3; @@ -1607,7 +1604,7 @@ static void netdrv_weird_interrupt (struct net_device *dev, assert (ioaddr != NULL); /* Update the error count. */ - tp->stats.rx_missed_errors += NETDRV_R32 (RxMissed); + dev->stats.rx_missed_errors += NETDRV_R32 (RxMissed); NETDRV_W32 (RxMissed, 0); if ((status & RxUnderrun) && link_changed && @@ -1628,14 +1625,14 @@ static void netdrv_weird_interrupt (struct net_device *dev, /* XXX along with netdrv_rx_err, are we double-counting errors? */ if (status & (RxUnderrun | RxOverflow | RxErr | RxFIFOOver)) - tp->stats.rx_errors++; + dev->stats.rx_errors++; if (status & (PCSTimeout)) - tp->stats.rx_length_errors++; + dev->stats.rx_length_errors++; if (status & (RxUnderrun | RxFIFOOver)) - tp->stats.rx_fifo_errors++; + dev->stats.rx_fifo_errors++; if (status & RxOverflow) { - tp->stats.rx_over_errors++; + dev->stats.rx_over_errors++; tp->cur_rx = NETDRV_R16 (RxBufAddr) % RX_BUF_LEN; NETDRV_W16_F (RxBufPtr, tp->cur_rx - 16); } @@ -1739,7 +1736,7 @@ static int netdrv_close (struct net_device *dev) NETDRV_W16 (IntrMask, 0x0000); /* Update the error counts. */ - tp->stats.rx_missed_errors += NETDRV_R32 (RxMissed); + dev->stats.rx_missed_errors += NETDRV_R32 (RxMissed); NETDRV_W32 (RxMissed, 0); spin_unlock_irqrestore (&tp->lock, flags); @@ -1806,31 +1803,6 @@ static int netdrv_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) return rc; } - -static struct net_device_stats *netdrv_get_stats (struct net_device *dev) -{ - struct netdrv_private *tp = dev->priv; - void *ioaddr = tp->mmio_addr; - - DPRINTK ("ENTER\n"); - - assert (tp != NULL); - - if (netif_running(dev)) { - unsigned long flags; - - spin_lock_irqsave (&tp->lock, flags); - - tp->stats.rx_missed_errors += NETDRV_R32 (RxMissed); - NETDRV_W32 (RxMissed, 0); - - spin_unlock_irqrestore (&tp->lock, flags); - } - - DPRINTK ("EXIT\n"); - return &tp->stats; -} - /* Set or clear the multicast filter for this adaptor. This routine is not state sensitive and need not be SMP locked. */ @@ -1908,7 +1880,7 @@ static int netdrv_suspend (struct pci_dev *pdev, pm_message_t state) NETDRV_W8 (ChipCmd, (NETDRV_R8 (ChipCmd) & ChipCmdClear)); /* Update the error counts. */ - tp->stats.rx_missed_errors += NETDRV_R32 (RxMissed); + dev->stats.rx_missed_errors += NETDRV_R32 (RxMissed); NETDRV_W32 (RxMissed, 0); spin_unlock_irqrestore (&tp->lock, flags); diff --git a/drivers/net/plip.c b/drivers/net/plip.c index 2cfab4b3665..c17d9ac9ff3 100644 --- a/drivers/net/plip.c +++ b/drivers/net/plip.c @@ -154,7 +154,6 @@ static int plip_hard_header_cache(struct neighbour *neigh, struct hh_cache *hh); static int plip_open(struct net_device *dev); static int plip_close(struct net_device *dev); -static struct net_device_stats *plip_get_stats(struct net_device *dev); static int plip_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); static int plip_preempt(void *handle); static void plip_wakeup(void *handle); @@ -206,7 +205,6 @@ struct plip_local { }; struct net_local { - struct net_device_stats enet_stats; struct net_device *dev; struct work_struct immediate; struct delayed_work deferred; @@ -285,7 +283,6 @@ plip_init_netdev(struct net_device *dev) dev->hard_start_xmit = plip_tx_packet; dev->open = plip_open; dev->stop = plip_close; - dev->get_stats = plip_get_stats; dev->do_ioctl = plip_ioctl; dev->header_cache_update = NULL; dev->tx_queue_len = 10; @@ -430,8 +427,8 @@ plip_bh_timeout_error(struct net_device *dev, struct net_local *nl, dev->name, snd->state, c0); } else error = HS_TIMEOUT; - nl->enet_stats.tx_errors++; - nl->enet_stats.tx_aborted_errors++; + dev->stats.tx_errors++; + dev->stats.tx_aborted_errors++; } else if (nl->connection == PLIP_CN_RECEIVE) { if (rcv->state == PLIP_PK_TRIGGER) { /* Transmission was interrupted. */ @@ -448,7 +445,7 @@ plip_bh_timeout_error(struct net_device *dev, struct net_local *nl, printk(KERN_WARNING "%s: receive timeout(%d,%02x)\n", dev->name, rcv->state, c0); } - nl->enet_stats.rx_dropped++; + dev->stats.rx_dropped++; } rcv->state = PLIP_PK_DONE; if (rcv->skb) { @@ -661,7 +658,7 @@ plip_receive_packet(struct net_device *dev, struct net_local *nl, &rcv->nibble, &rcv->data)) return TIMEOUT; if (rcv->data != rcv->checksum) { - nl->enet_stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; if (net_debug) printk(KERN_DEBUG "%s: checksum error\n", dev->name); return ERROR; @@ -673,8 +670,8 @@ plip_receive_packet(struct net_device *dev, struct net_local *nl, rcv->skb->protocol=plip_type_trans(rcv->skb, dev); netif_rx(rcv->skb); dev->last_rx = jiffies; - nl->enet_stats.rx_bytes += rcv->length.h; - nl->enet_stats.rx_packets++; + dev->stats.rx_bytes += rcv->length.h; + dev->stats.rx_packets++; rcv->skb = NULL; if (net_debug > 2) printk(KERN_DEBUG "%s: receive end\n", dev->name); @@ -776,7 +773,7 @@ plip_send_packet(struct net_device *dev, struct net_local *nl, if (nl->connection == PLIP_CN_RECEIVE) { spin_unlock_irq(&nl->lock); /* Interrupted. */ - nl->enet_stats.collisions++; + dev->stats.collisions++; return OK; } c0 = read_status(dev); @@ -792,7 +789,7 @@ plip_send_packet(struct net_device *dev, struct net_local *nl, {enable,disable}_irq *counts* them. -- AV */ ENABLE(dev->irq); - nl->enet_stats.collisions++; + dev->stats.collisions++; return OK; } disable_parport_interrupts (dev); @@ -840,9 +837,9 @@ plip_send_packet(struct net_device *dev, struct net_local *nl, &snd->nibble, snd->checksum)) return TIMEOUT; - nl->enet_stats.tx_bytes += snd->skb->len; + dev->stats.tx_bytes += snd->skb->len; dev_kfree_skb(snd->skb); - nl->enet_stats.tx_packets++; + dev->stats.tx_packets++; snd->state = PLIP_PK_DONE; case PLIP_PK_DONE: @@ -1199,15 +1196,6 @@ plip_wakeup(void *handle) return; } -static struct net_device_stats * -plip_get_stats(struct net_device *dev) -{ - struct net_local *nl = netdev_priv(dev); - struct net_device_stats *r = &nl->enet_stats; - - return r; -} - static int plip_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c index 309199bb7d1..97c6ed07dd1 100755 --- a/drivers/net/qla3xxx.c +++ b/drivers/net/qla3xxx.c @@ -2053,7 +2053,7 @@ static void ql_process_mac_tx_intr(struct ql3_adapter *qdev, if(mac_rsp->flags & OB_MAC_IOCB_RSP_S) { printk(KERN_ERR "Frame too short to be legal, frame not sent.\n"); - qdev->stats.tx_errors++; + qdev->ndev->stats.tx_errors++; retval = -EIO; goto frame_not_sent; } @@ -2061,7 +2061,7 @@ static void ql_process_mac_tx_intr(struct ql3_adapter *qdev, if(tx_cb->seg_count == 0) { printk(KERN_ERR "tx_cb->seg_count == 0: %d\n", mac_rsp->transaction_id); - qdev->stats.tx_errors++; + qdev->ndev->stats.tx_errors++; retval = -EIO; goto invalid_seg_count; } @@ -2080,8 +2080,8 @@ static void ql_process_mac_tx_intr(struct ql3_adapter *qdev, PCI_DMA_TODEVICE); } } - qdev->stats.tx_packets++; - qdev->stats.tx_bytes += tx_cb->skb->len; + qdev->ndev->stats.tx_packets++; + qdev->ndev->stats.tx_bytes += tx_cb->skb->len; frame_not_sent: dev_kfree_skb_irq(tx_cb->skb); @@ -2140,8 +2140,8 @@ static void ql_process_mac_rx_intr(struct ql3_adapter *qdev, lrg_buf_cb2 = ql_get_lbuf(qdev); skb = lrg_buf_cb2->skb; - qdev->stats.rx_packets++; - qdev->stats.rx_bytes += length; + qdev->ndev->stats.rx_packets++; + qdev->ndev->stats.rx_bytes += length; skb_put(skb, length); pci_unmap_single(qdev->pdev, @@ -2225,8 +2225,8 @@ static void ql_process_macip_rx_intr(struct ql3_adapter *qdev, skb2->protocol = eth_type_trans(skb2, qdev->ndev); netif_receive_skb(skb2); - qdev->stats.rx_packets++; - qdev->stats.rx_bytes += length; + ndev->stats.rx_packets++; + ndev->stats.rx_bytes += length; ndev->last_rx = jiffies; lrg_buf_cb2->skb = NULL; @@ -3753,12 +3753,6 @@ static int ql3xxx_open(struct net_device *ndev) return (ql_adapter_up(qdev)); } -static struct net_device_stats *ql3xxx_get_stats(struct net_device *dev) -{ - struct ql3_adapter *qdev = (struct ql3_adapter *)dev->priv; - return &qdev->stats; -} - static void ql3xxx_set_multicast_list(struct net_device *ndev) { /* @@ -4048,7 +4042,6 @@ static int __devinit ql3xxx_probe(struct pci_dev *pdev, ndev->open = ql3xxx_open; ndev->hard_start_xmit = ql3xxx_send; ndev->stop = ql3xxx_close; - ndev->get_stats = ql3xxx_get_stats; ndev->set_multicast_list = ql3xxx_set_multicast_list; SET_ETHTOOL_OPS(ndev, &ql3xxx_ethtool_ops); ndev->set_mac_address = ql3xxx_set_mac_address; diff --git a/drivers/net/qla3xxx.h b/drivers/net/qla3xxx.h index aa2216f0d7b..483840f7fc1 100755 --- a/drivers/net/qla3xxx.h +++ b/drivers/net/qla3xxx.h @@ -1283,7 +1283,6 @@ struct ql3_adapter { u32 update_ob_opcode; /* Opcode to use for updating NCB */ u32 mb_bit_mask; /* MA Bits mask to use on transmission */ u32 numPorts; - struct net_device_stats stats; struct workqueue_struct *workqueue; struct delayed_work reset_work; struct delayed_work tx_timeout_work; diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c index 25a9dd821aa..d43dcf3ed5a 100644 --- a/drivers/net/rionet.c +++ b/drivers/net/rionet.c @@ -53,7 +53,6 @@ struct rionet_private { struct rio_mport *mport; struct sk_buff *rx_skb[RIONET_RX_RING_SIZE]; struct sk_buff *tx_skb[RIONET_TX_RING_SIZE]; - struct net_device_stats stats; int rx_slot; int tx_slot; int tx_cnt; @@ -91,12 +90,6 @@ static struct rio_dev *rionet_active[RIO_MAX_ROUTE_ENTRIES]; #define RIONET_MAC_MATCH(x) (*(u32 *)x == 0x00010001) #define RIONET_GET_DESTID(x) (*(u16 *)(x + 4)) -static struct net_device_stats *rionet_stats(struct net_device *ndev) -{ - struct rionet_private *rnet = ndev->priv; - return &rnet->stats; -} - static int rionet_rx_clean(struct net_device *ndev) { int i; @@ -120,15 +113,15 @@ static int rionet_rx_clean(struct net_device *ndev) error = netif_rx(rnet->rx_skb[i]); if (error == NET_RX_DROP) { - rnet->stats.rx_dropped++; + ndev->stats.rx_dropped++; } else if (error == NET_RX_BAD) { if (netif_msg_rx_err(rnet)) printk(KERN_WARNING "%s: bad rx packet\n", DRV_NAME); - rnet->stats.rx_errors++; + ndev->stats.rx_errors++; } else { - rnet->stats.rx_packets++; - rnet->stats.rx_bytes += RIO_MAX_MSG_SIZE; + ndev->stats.rx_packets++; + ndev->stats.rx_bytes += RIO_MAX_MSG_SIZE; } } while ((i = (i + 1) % RIONET_RX_RING_SIZE) != rnet->rx_slot); @@ -163,8 +156,8 @@ static int rionet_queue_tx_msg(struct sk_buff *skb, struct net_device *ndev, rio_add_outb_message(rnet->mport, rdev, 0, skb->data, skb->len); rnet->tx_skb[rnet->tx_slot] = skb; - rnet->stats.tx_packets++; - rnet->stats.tx_bytes += skb->len; + ndev->stats.tx_packets++; + ndev->stats.tx_bytes += skb->len; if (++rnet->tx_cnt == RIONET_TX_RING_SIZE) netif_stop_queue(ndev); @@ -466,7 +459,6 @@ static int rionet_setup_netdev(struct rio_mport *mport) ndev->open = &rionet_open; ndev->hard_start_xmit = &rionet_start_xmit; ndev->stop = &rionet_close; - ndev->get_stats = &rionet_stats; ndev->mtu = RIO_MAX_MSG_SIZE - 14; ndev->features = NETIF_F_LLTX; SET_ETHTOOL_OPS(ndev, &rionet_ethtool_ops); diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c index 41f877d482c..03facba0525 100644 --- a/drivers/net/rrunner.c +++ b/drivers/net/rrunner.c @@ -126,7 +126,6 @@ static int __devinit rr_init_one(struct pci_dev *pdev, dev->open = &rr_open; dev->hard_start_xmit = &rr_start_xmit; dev->stop = &rr_close; - dev->get_stats = &rr_get_stats; dev->do_ioctl = &rr_ioctl; dev->base_addr = pci_resource_start(pdev, 0); @@ -808,7 +807,7 @@ static u32 rr_handle_event(struct net_device *dev, u32 prodidx, u32 eidx) case E_CON_REJ: printk(KERN_WARNING "%s: Connection rejected\n", dev->name); - rrpriv->stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; break; case E_CON_TMOUT: printk(KERN_WARNING "%s: Connection timeout\n", @@ -817,7 +816,7 @@ static u32 rr_handle_event(struct net_device *dev, u32 prodidx, u32 eidx) case E_DISC_ERR: printk(KERN_WARNING "%s: HIPPI disconnect error\n", dev->name); - rrpriv->stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; break; case E_INT_PRTY: printk(KERN_ERR "%s: HIPPI Internal Parity error\n", @@ -833,7 +832,7 @@ static u32 rr_handle_event(struct net_device *dev, u32 prodidx, u32 eidx) case E_TX_LINK_DROP: printk(KERN_WARNING "%s: Link lost during transmit\n", dev->name); - rrpriv->stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, ®s->HostCtrl); wmb(); @@ -973,7 +972,7 @@ static void rx_int(struct net_device *dev, u32 rxlimit, u32 index) printk("len %x, mode %x\n", pkt_len, desc->mode); #endif if ( (rrpriv->rx_ring[index].mode & PACKET_BAD) == PACKET_BAD){ - rrpriv->stats.rx_dropped++; + dev->stats.rx_dropped++; goto defer; } @@ -986,7 +985,7 @@ static void rx_int(struct net_device *dev, u32 rxlimit, u32 index) skb = alloc_skb(pkt_len, GFP_ATOMIC); if (skb == NULL){ printk(KERN_WARNING "%s: Unable to allocate skb (%i bytes), deferring packet\n", dev->name, pkt_len); - rrpriv->stats.rx_dropped++; + dev->stats.rx_dropped++; goto defer; } else { pci_dma_sync_single_for_cpu(rrpriv->pci_dev, @@ -1024,7 +1023,7 @@ static void rx_int(struct net_device *dev, u32 rxlimit, u32 index) } else { printk("%s: Out of memory, deferring " "packet\n", dev->name); - rrpriv->stats.rx_dropped++; + dev->stats.rx_dropped++; goto defer; } } @@ -1033,8 +1032,8 @@ static void rx_int(struct net_device *dev, u32 rxlimit, u32 index) netif_rx(skb); /* send it up */ dev->last_rx = jiffies; - rrpriv->stats.rx_packets++; - rrpriv->stats.rx_bytes += pkt_len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; } defer: desc->mode = 0; @@ -1102,8 +1101,8 @@ static irqreturn_t rr_interrupt(int irq, void *dev_id) desc = &(rrpriv->tx_ring[txcon]); skb = rrpriv->tx_skbuff[txcon]; - rrpriv->stats.tx_packets++; - rrpriv->stats.tx_bytes += skb->len; + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; pci_unmap_single(rrpriv->pci_dev, desc->addr.addrlo, skb->len, @@ -1491,16 +1490,6 @@ static int rr_start_xmit(struct sk_buff *skb, struct net_device *dev) } -static struct net_device_stats *rr_get_stats(struct net_device *dev) -{ - struct rr_private *rrpriv; - - rrpriv = netdev_priv(dev); - - return(&rrpriv->stats); -} - - /* * Read the firmware out of the EEPROM and put it into the SRAM * (or from user space - later) diff --git a/drivers/net/rrunner.h b/drivers/net/rrunner.h index 9f3e050c4dc..6a79825bc8c 100644 --- a/drivers/net/rrunner.h +++ b/drivers/net/rrunner.h @@ -819,7 +819,6 @@ struct rr_private u32 tx_full; u32 fw_rev; volatile short fw_running; - struct net_device_stats stats; struct pci_dev *pci_dev; }; @@ -834,7 +833,6 @@ static irqreturn_t rr_interrupt(int irq, void *dev_id); static int rr_open(struct net_device *dev); static int rr_start_xmit(struct sk_buff *skb, struct net_device *dev); static int rr_close(struct net_device *dev); -static struct net_device_stats *rr_get_stats(struct net_device *dev); static int rr_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static unsigned int rr_read_eeprom(struct rr_private *rrpriv, unsigned long offset, diff --git a/drivers/net/saa9730.c b/drivers/net/saa9730.c index 7dae4d40497..14361e88541 100644 --- a/drivers/net/saa9730.c +++ b/drivers/net/saa9730.c @@ -151,30 +151,30 @@ static void __attribute_used__ show_saa9730_regs(struct lan_saa9730_private *lp) printk("lp->lan_saa9730_regs->CamData = %x\n", readl(&lp->lan_saa9730_regs->CamData)); } - printk("lp->stats.tx_packets = %lx\n", lp->stats.tx_packets); - printk("lp->stats.tx_errors = %lx\n", lp->stats.tx_errors); - printk("lp->stats.tx_aborted_errors = %lx\n", - lp->stats.tx_aborted_errors); - printk("lp->stats.tx_window_errors = %lx\n", - lp->stats.tx_window_errors); - printk("lp->stats.tx_carrier_errors = %lx\n", - lp->stats.tx_carrier_errors); - printk("lp->stats.tx_fifo_errors = %lx\n", - lp->stats.tx_fifo_errors); - printk("lp->stats.tx_heartbeat_errors = %lx\n", - lp->stats.tx_heartbeat_errors); - printk("lp->stats.collisions = %lx\n", lp->stats.collisions); - - printk("lp->stats.rx_packets = %lx\n", lp->stats.rx_packets); - printk("lp->stats.rx_errors = %lx\n", lp->stats.rx_errors); - printk("lp->stats.rx_dropped = %lx\n", lp->stats.rx_dropped); - printk("lp->stats.rx_crc_errors = %lx\n", lp->stats.rx_crc_errors); - printk("lp->stats.rx_frame_errors = %lx\n", - lp->stats.rx_frame_errors); - printk("lp->stats.rx_fifo_errors = %lx\n", - lp->stats.rx_fifo_errors); - printk("lp->stats.rx_length_errors = %lx\n", - lp->stats.rx_length_errors); + printk("dev->stats.tx_packets = %lx\n", dev->stats.tx_packets); + printk("dev->stats.tx_errors = %lx\n", dev->stats.tx_errors); + printk("dev->stats.tx_aborted_errors = %lx\n", + dev->stats.tx_aborted_errors); + printk("dev->stats.tx_window_errors = %lx\n", + dev->stats.tx_window_errors); + printk("dev->stats.tx_carrier_errors = %lx\n", + dev->stats.tx_carrier_errors); + printk("dev->stats.tx_fifo_errors = %lx\n", + dev->stats.tx_fifo_errors); + printk("dev->stats.tx_heartbeat_errors = %lx\n", + dev->stats.tx_heartbeat_errors); + printk("dev->stats.collisions = %lx\n", dev->stats.collisions); + + printk("dev->stats.rx_packets = %lx\n", dev->stats.rx_packets); + printk("dev->stats.rx_errors = %lx\n", dev->stats.rx_errors); + printk("dev->stats.rx_dropped = %lx\n", dev->stats.rx_dropped); + printk("dev->stats.rx_crc_errors = %lx\n", dev->stats.rx_crc_errors); + printk("dev->stats.rx_frame_errors = %lx\n", + dev->stats.rx_frame_errors); + printk("dev->stats.rx_fifo_errors = %lx\n", + dev->stats.rx_fifo_errors); + printk("dev->stats.rx_length_errors = %lx\n", + dev->stats.rx_length_errors); printk("lp->lan_saa9730_regs->DebugPCIMasterAddr = %x\n", readl(&lp->lan_saa9730_regs->DebugPCIMasterAddr)); @@ -605,24 +605,24 @@ static int lan_saa9730_tx(struct net_device *dev) printk("lan_saa9730_tx: tx error = %x\n", tx_status); - lp->stats.tx_errors++; + dev->stats.tx_errors++; if (tx_status & (TX_STATUS_EX_COLL << TX_STAT_CTL_STATUS_SHF)) - lp->stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; if (tx_status & (TX_STATUS_LATE_COLL << TX_STAT_CTL_STATUS_SHF)) - lp->stats.tx_window_errors++; + dev->stats.tx_window_errors++; if (tx_status & (TX_STATUS_L_CARR << TX_STAT_CTL_STATUS_SHF)) - lp->stats.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; if (tx_status & (TX_STATUS_UNDER << TX_STAT_CTL_STATUS_SHF)) - lp->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; if (tx_status & (TX_STATUS_SQ_ERR << TX_STAT_CTL_STATUS_SHF)) - lp->stats.tx_heartbeat_errors++; + dev->stats.tx_heartbeat_errors++; - lp->stats.collisions += + dev->stats.collisions += tx_status & TX_STATUS_TX_COLL_MSK; } @@ -684,10 +684,10 @@ static int lan_saa9730_rx(struct net_device *dev) printk ("%s: Memory squeeze, deferring packet.\n", dev->name); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; } else { - lp->stats.rx_bytes += len; - lp->stats.rx_packets++; + dev->stats.rx_bytes += len; + dev->stats.rx_packets++; skb_reserve(skb, 2); /* 16 byte align */ skb_put(skb, len); /* make room */ skb_copy_to_linear_data(skb, @@ -704,19 +704,19 @@ static int lan_saa9730_rx(struct net_device *dev) ("lan_saa9730_rx: We got an error packet = %x\n", rx_status); - lp->stats.rx_errors++; + dev->stats.rx_errors++; if (rx_status & (RX_STATUS_CRC_ERR << RX_STAT_CTL_STATUS_SHF)) - lp->stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; if (rx_status & (RX_STATUS_ALIGN_ERR << RX_STAT_CTL_STATUS_SHF)) - lp->stats.rx_frame_errors++; + dev->stats.rx_frame_errors++; if (rx_status & (RX_STATUS_OVERFLOW << RX_STAT_CTL_STATUS_SHF)) - lp->stats.rx_fifo_errors++; + dev->stats.rx_fifo_errors++; if (rx_status & (RX_STATUS_LONG_ERR << RX_STAT_CTL_STATUS_SHF)) - lp->stats.rx_length_errors++; + dev->stats.rx_length_errors++; } /* Indicate we have processed the buffer. */ @@ -853,7 +853,7 @@ static void lan_saa9730_tx_timeout(struct net_device *dev) struct lan_saa9730_private *lp = netdev_priv(dev); /* Transmitter timeout, serious problems */ - lp->stats.tx_errors++; + dev->stats.tx_errors++; printk("%s: transmit timed out, reset\n", dev->name); /*show_saa9730_regs(lp); */ lan_saa9730_restart(lp); @@ -886,8 +886,8 @@ static int lan_saa9730_start_xmit(struct sk_buff *skb, return -1; } - lp->stats.tx_bytes += len; - lp->stats.tx_packets++; + dev->stats.tx_bytes += len; + dev->stats.tx_packets++; dev->trans_start = jiffies; netif_wake_queue(dev); @@ -919,14 +919,6 @@ static int lan_saa9730_close(struct net_device *dev) return 0; } -static struct net_device_stats *lan_saa9730_get_stats(struct net_device - *dev) -{ - struct lan_saa9730_private *lp = netdev_priv(dev); - - return &lp->stats; -} - static void lan_saa9730_set_multicast(struct net_device *dev) { struct lan_saa9730_private *lp = netdev_priv(dev); @@ -1040,7 +1032,6 @@ static int lan_saa9730_init(struct net_device *dev, struct pci_dev *pdev, dev->open = lan_saa9730_open; dev->hard_start_xmit = lan_saa9730_start_xmit; dev->stop = lan_saa9730_close; - dev->get_stats = lan_saa9730_get_stats; dev->set_multicast_list = lan_saa9730_set_multicast; dev->tx_timeout = lan_saa9730_tx_timeout; dev->watchdog_timeo = (HZ >> 1); diff --git a/drivers/net/saa9730.h b/drivers/net/saa9730.h index f656f2f40bb..010a120ea93 100644 --- a/drivers/net/saa9730.h +++ b/drivers/net/saa9730.h @@ -378,7 +378,6 @@ struct lan_saa9730_private { unsigned char PhysicalAddress[LAN_SAA9730_CAM_ENTRIES][6]; - struct net_device_stats stats; spinlock_t lock; }; diff --git a/drivers/net/sb1000.c b/drivers/net/sb1000.c index aeaa75f549e..487f9d2ac5b 100644 --- a/drivers/net/sb1000.c +++ b/drivers/net/sb1000.c @@ -76,7 +76,6 @@ struct sb1000_private { unsigned char rx_session_id[NPIDS]; unsigned char rx_frame_id[NPIDS]; unsigned char rx_pkt_type[NPIDS]; - struct net_device_stats stats; }; /* prototypes for Linux interface */ @@ -85,7 +84,6 @@ static int sb1000_open(struct net_device *dev); static int sb1000_dev_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd); static int sb1000_start_xmit(struct sk_buff *skb, struct net_device *dev); static irqreturn_t sb1000_interrupt(int irq, void *dev_id); -static struct net_device_stats *sb1000_stats(struct net_device *dev); static int sb1000_close(struct net_device *dev); @@ -199,7 +197,6 @@ sb1000_probe_one(struct pnp_dev *pdev, const struct pnp_device_id *id) dev->do_ioctl = sb1000_dev_ioctl; dev->hard_start_xmit = sb1000_start_xmit; dev->stop = sb1000_close; - dev->get_stats = sb1000_stats; /* hardware address is 0:0:serial_number */ dev->dev_addr[2] = serial_number >> 24 & 0xff; @@ -739,7 +736,7 @@ sb1000_rx(struct net_device *dev) unsigned int skbsize; struct sk_buff *skb; struct sb1000_private *lp = netdev_priv(dev); - struct net_device_stats *stats = &lp->stats; + struct net_device_stats *stats = &dev->stats; /* SB1000 frame constants */ const int FrameSize = FRAMESIZE; @@ -1002,11 +999,11 @@ static int sb1000_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) switch (cmd) { case SIOCGCMSTATS: /* get statistics */ - stats[0] = lp->stats.rx_bytes; + stats[0] = dev->stats.rx_bytes; stats[1] = lp->rx_frames; - stats[2] = lp->stats.rx_packets; - stats[3] = lp->stats.rx_errors; - stats[4] = lp->stats.rx_dropped; + stats[2] = dev->stats.rx_packets; + stats[3] = dev->stats.rx_errors; + stats[4] = dev->stats.rx_dropped; if(copy_to_user(ifr->ifr_data, stats, sizeof(stats))) return -EFAULT; status = 0; @@ -1132,12 +1129,6 @@ static irqreturn_t sb1000_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static struct net_device_stats *sb1000_stats(struct net_device *dev) -{ - struct sb1000_private *lp = netdev_priv(dev); - return &lp->stats; -} - static int sb1000_close(struct net_device *dev) { int i; diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index b6cafac9720..76e7ee9a6cb 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -241,7 +241,6 @@ struct sbmac_softc { struct napi_struct napi; spinlock_t sbm_lock; /* spin lock */ struct timer_list sbm_timer; /* for monitoring MII */ - struct net_device_stats sbm_stats; int sbm_devflags; /* current device flags */ int sbm_phy_oldbmsr; @@ -317,7 +316,6 @@ static int sbmac_set_duplex(struct sbmac_softc *s,sbmac_duplex_t duplex,sbmac_fc static int sbmac_open(struct net_device *dev); static void sbmac_timer(unsigned long data); static void sbmac_tx_timeout (struct net_device *dev); -static struct net_device_stats *sbmac_get_stats(struct net_device *dev); static void sbmac_set_rx_mode(struct net_device *dev); static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static int sbmac_close(struct net_device *dev); @@ -1190,6 +1188,7 @@ static void sbmac_netpoll(struct net_device *netdev) static int sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d, int work_to_do, int poll) { + struct net_device *dev = sc->sbm_dev; int curidx; int hwidx; sbdmadscr_t *dsc; @@ -1202,7 +1201,7 @@ static int sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d, again: /* Check if the HW dropped any frames */ - sc->sbm_stats.rx_fifo_errors + dev->stats.rx_fifo_errors += __raw_readq(sc->sbm_rxdma.sbdma_oodpktlost) & 0xffff; __raw_writeq(0, sc->sbm_rxdma.sbdma_oodpktlost); @@ -1261,7 +1260,7 @@ again: if (unlikely (sbdma_add_rcvbuffer(d,NULL) == -ENOBUFS)) { - sc->sbm_stats.rx_dropped++; + dev->stats.rx_dropped++; sbdma_add_rcvbuffer(d,sb); /* re-add old buffer */ /* No point in continuing at the moment */ printk(KERN_ERR "dropped packet (1)\n"); @@ -1297,13 +1296,13 @@ again: dropped = netif_rx(sb); if (dropped == NET_RX_DROP) { - sc->sbm_stats.rx_dropped++; + dev->stats.rx_dropped++; d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr); goto done; } else { - sc->sbm_stats.rx_bytes += len; - sc->sbm_stats.rx_packets++; + dev->stats.rx_bytes += len; + dev->stats.rx_packets++; } } } else { @@ -1311,7 +1310,7 @@ again: * Packet was mangled somehow. Just drop it and * put it back on the receive ring. */ - sc->sbm_stats.rx_errors++; + dev->stats.rx_errors++; sbdma_add_rcvbuffer(d,sb); } @@ -1351,6 +1350,7 @@ done: static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d, int poll) { + struct net_device *dev = sc->sbm_dev; int curidx; int hwidx; sbdmadscr_t *dsc; @@ -1401,8 +1401,8 @@ static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d, int poll) * Stats */ - sc->sbm_stats.tx_bytes += sb->len; - sc->sbm_stats.tx_packets++; + dev->stats.tx_bytes += sb->len; + dev->stats.tx_packets++; /* * for transmits, we just free buffers. @@ -2457,7 +2457,6 @@ static int sbmac_init(struct net_device *dev, int idx) dev->open = sbmac_open; dev->hard_start_xmit = sbmac_start_tx; dev->stop = sbmac_close; - dev->get_stats = sbmac_get_stats; dev->set_multicast_list = sbmac_set_rx_mode; dev->do_ioctl = sbmac_mii_ioctl; dev->tx_timeout = sbmac_tx_timeout; @@ -2748,7 +2747,7 @@ static void sbmac_tx_timeout (struct net_device *dev) dev->trans_start = jiffies; - sc->sbm_stats.tx_errors++; + dev->stats.tx_errors++; spin_unlock_irq (&sc->sbm_lock); @@ -2758,22 +2757,6 @@ static void sbmac_tx_timeout (struct net_device *dev) -static struct net_device_stats *sbmac_get_stats(struct net_device *dev) -{ - struct sbmac_softc *sc = netdev_priv(dev); - unsigned long flags; - - spin_lock_irqsave(&sc->sbm_lock, flags); - - /* XXX update other stats here */ - - spin_unlock_irqrestore(&sc->sbm_lock, flags); - - return &sc->sbm_stats; -} - - - static void sbmac_set_rx_mode(struct net_device *dev) { unsigned long flags; diff --git a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c index 4bce7c4f373..8ef94028cba 100644 --- a/drivers/net/seeq8005.c +++ b/drivers/net/seeq8005.c @@ -67,7 +67,6 @@ static unsigned int net_debug = NET_DEBUG; /* Information that need to be kept for each board. */ struct net_local { - struct net_device_stats stats; unsigned short receive_ptr; /* What address in packet memory do we expect a recv_pkt_header? */ long open_time; /* Useless example local info. */ }; @@ -86,7 +85,6 @@ static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev); static irqreturn_t seeq8005_interrupt(int irq, void *dev_id); static void seeq8005_rx(struct net_device *dev); static int seeq8005_close(struct net_device *dev); -static struct net_device_stats *seeq8005_get_stats(struct net_device *dev); static void set_multicast_list(struct net_device *dev); /* Example routines you must write ;->. */ @@ -338,7 +336,6 @@ static int __init seeq8005_probe1(struct net_device *dev, int ioaddr) dev->hard_start_xmit = seeq8005_send_packet; dev->tx_timeout = seeq8005_timeout; dev->watchdog_timeo = HZ/20; - dev->get_stats = seeq8005_get_stats; dev->set_multicast_list = set_multicast_list; dev->flags &= ~IFF_MULTICAST; @@ -391,7 +388,6 @@ static void seeq8005_timeout(struct net_device *dev) static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev) { - struct net_local *lp = netdev_priv(dev); short length = skb->len; unsigned char *buf; @@ -407,7 +403,7 @@ static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev) hardware_send_packet(dev, buf, length); dev->trans_start = jiffies; - lp->stats.tx_bytes += length; + dev->stats.tx_bytes += length; dev_kfree_skb (skb); /* You might need to clean up and record Tx statistics here. */ @@ -463,7 +459,7 @@ static irqreturn_t seeq8005_interrupt(int irq, void *dev_id) if (status & SEEQSTAT_TX_INT) { handled = 1; outw( SEEQCMD_TX_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD); - lp->stats.tx_packets++; + dev->stats.tx_packets++; netif_wake_queue(dev); /* Inform upper layers. */ } if (status & SEEQSTAT_RX_INT) { @@ -531,11 +527,11 @@ static void seeq8005_rx(struct net_device *dev) } if (pkt_hdr & SEEQPKTS_ANY_ERROR) { /* There was an error. */ - lp->stats.rx_errors++; - if (pkt_hdr & SEEQPKTS_SHORT) lp->stats.rx_frame_errors++; - if (pkt_hdr & SEEQPKTS_DRIB) lp->stats.rx_frame_errors++; - if (pkt_hdr & SEEQPKTS_OVERSIZE) lp->stats.rx_over_errors++; - if (pkt_hdr & SEEQPKTS_CRC_ERR) lp->stats.rx_crc_errors++; + dev->stats.rx_errors++; + if (pkt_hdr & SEEQPKTS_SHORT) dev->stats.rx_frame_errors++; + if (pkt_hdr & SEEQPKTS_DRIB) dev->stats.rx_frame_errors++; + if (pkt_hdr & SEEQPKTS_OVERSIZE) dev->stats.rx_over_errors++; + if (pkt_hdr & SEEQPKTS_CRC_ERR) dev->stats.rx_crc_errors++; /* skip over this packet */ outw( SEEQCMD_FIFO_WRITE | SEEQCMD_DMA_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD); outw( (lp->receive_ptr & 0xff00)>>8, SEEQ_REA); @@ -547,7 +543,7 @@ static void seeq8005_rx(struct net_device *dev) skb = dev_alloc_skb(pkt_len); if (skb == NULL) { printk("%s: Memory squeeze, dropping packet.\n", dev->name); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; break; } skb_reserve(skb, 2); /* align data on 16 byte */ @@ -567,8 +563,8 @@ static void seeq8005_rx(struct net_device *dev) skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); dev->last_rx = jiffies; - lp->stats.rx_packets++; - lp->stats.rx_bytes += pkt_len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; } } while ((--boguscount) && (pkt_hdr & SEEQPKTH_CHAIN)); @@ -599,15 +595,6 @@ static int seeq8005_close(struct net_device *dev) } -/* Get the current statistics. This may be called with the card open or - closed. */ -static struct net_device_stats *seeq8005_get_stats(struct net_device *dev) -{ - struct net_local *lp = netdev_priv(dev); - - return &lp->stats; -} - /* Set or clear the multicast filter for this adaptor. num_addrs == -1 Promiscuous mode, receive all packets num_addrs == 0 Normal mode, clear multicast list diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c index eb67b024e41..5189ef06688 100644 --- a/drivers/net/sgiseeq.c +++ b/drivers/net/sgiseeq.c @@ -93,8 +93,6 @@ struct sgiseeq_private { unsigned char control; unsigned char mode; - struct net_device_stats stats; - spinlock_t tx_lock; }; @@ -267,18 +265,17 @@ static int init_seeq(struct net_device *dev, struct sgiseeq_private *sp, return 0; } -static inline void record_rx_errors(struct sgiseeq_private *sp, - unsigned char status) +static void record_rx_errors(struct net_device *dev, unsigned char status) { if (status & SEEQ_RSTAT_OVERF || status & SEEQ_RSTAT_SFRAME) - sp->stats.rx_over_errors++; + dev->stats.rx_over_errors++; if (status & SEEQ_RSTAT_CERROR) - sp->stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; if (status & SEEQ_RSTAT_DERROR) - sp->stats.rx_frame_errors++; + dev->stats.rx_frame_errors++; if (status & SEEQ_RSTAT_REOF) - sp->stats.rx_errors++; + dev->stats.rx_errors++; } static inline void rx_maybe_restart(struct sgiseeq_private *sp, @@ -328,8 +325,8 @@ static inline void sgiseeq_rx(struct net_device *dev, struct sgiseeq_private *sp if (memcmp(eth_hdr(skb)->h_source, dev->dev_addr, ETH_ALEN)) { netif_rx(skb); dev->last_rx = jiffies; - sp->stats.rx_packets++; - sp->stats.rx_bytes += len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += len; } else { /* Silently drop my own packets */ dev_kfree_skb_irq(skb); @@ -337,10 +334,10 @@ static inline void sgiseeq_rx(struct net_device *dev, struct sgiseeq_private *sp } else { printk (KERN_NOTICE "%s: Memory squeeze, deferring packet.\n", dev->name); - sp->stats.rx_dropped++; + dev->stats.rx_dropped++; } } else { - record_rx_errors(sp, pkt_status); + record_rx_errors(dev, pkt_status); } /* Return the entry to the ring pool. */ @@ -392,11 +389,11 @@ static inline void sgiseeq_tx(struct net_device *dev, struct sgiseeq_private *sp if (!(status & (HPC3_ETXCTRL_ACTIVE | SEEQ_TSTAT_PTRANS))) { /* Oops, HPC detected some sort of error. */ if (status & SEEQ_TSTAT_R16) - sp->stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; if (status & SEEQ_TSTAT_UFLOW) - sp->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; if (status & SEEQ_TSTAT_LCLS) - sp->stats.collisions++; + dev->stats.collisions++; } /* Ack 'em... */ @@ -412,7 +409,7 @@ static inline void sgiseeq_tx(struct net_device *dev, struct sgiseeq_private *sp } break; } - sp->stats.tx_packets++; + dev->stats.tx_packets++; sp->tx_old = NEXT_TX(sp->tx_old); td->tdma.cntinfo &= ~(HPCDMA_XIU | HPCDMA_XIE); td->tdma.cntinfo |= HPCDMA_EOX; @@ -516,7 +513,7 @@ static int sgiseeq_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Setup... */ skblen = skb->len; len = (skblen <= ETH_ZLEN) ? ETH_ZLEN : skblen; - sp->stats.tx_bytes += len; + dev->stats.tx_bytes += len; entry = sp->tx_new; td = &sp->tx_desc[entry]; @@ -569,13 +566,6 @@ static void timeout(struct net_device *dev) netif_wake_queue(dev); } -static struct net_device_stats *sgiseeq_get_stats(struct net_device *dev) -{ - struct sgiseeq_private *sp = netdev_priv(dev); - - return &sp->stats; -} - static void sgiseeq_set_multicast(struct net_device *dev) { struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv; @@ -694,7 +684,6 @@ static int __init sgiseeq_probe(struct platform_device *pdev) dev->hard_start_xmit = sgiseeq_start_xmit; dev->tx_timeout = timeout; dev->watchdog_timeo = (200 * HZ) / 1000; - dev->get_stats = sgiseeq_get_stats; dev->set_multicast_list = sgiseeq_set_multicast; dev->set_mac_address = sgiseeq_set_mac_address; dev->irq = irq; diff --git a/drivers/net/shaper.c b/drivers/net/shaper.c index b56721a68a8..315feba7dac 100644 --- a/drivers/net/shaper.c +++ b/drivers/net/shaper.c @@ -171,7 +171,7 @@ static int shaper_start_xmit(struct sk_buff *skb, struct net_device *dev) */ if(time_after(SHAPERCB(skb)->shapeclock,jiffies + SHAPER_LATENCY)) { dev_kfree_skb(skb); - shaper->stats.tx_dropped++; + dev->stats.tx_dropped++; } else skb_queue_tail(&shaper->sendq, skb); } @@ -182,7 +182,7 @@ static int shaper_start_xmit(struct sk_buff *skb, struct net_device *dev) { ptr=skb_dequeue(&shaper->sendq); dev_kfree_skb(ptr); - shaper->stats.collisions++; + dev->stats.collisions++; } shaper_kick(shaper); spin_unlock(&shaper->lock); @@ -207,8 +207,8 @@ static void shaper_queue_xmit(struct shaper *shaper, struct sk_buff *skb) shaper->dev->name,newskb->priority); dev_queue_xmit(newskb); - shaper->stats.tx_bytes += skb->len; - shaper->stats.tx_packets++; + shaper->dev->stats.tx_bytes += skb->len; + shaper->dev->stats.tx_packets++; if(sh_debug) printk("Kicked new frame out.\n"); @@ -330,12 +330,6 @@ static int shaper_close(struct net_device *dev) * ARP and other resolutions and not before. */ -static struct net_device_stats *shaper_get_stats(struct net_device *dev) -{ - struct shaper *sh=dev->priv; - return &sh->stats; -} - static int shaper_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned len) { @@ -538,7 +532,6 @@ static void __init shaper_setup(struct net_device *dev) dev->open = shaper_open; dev->stop = shaper_close; dev->hard_start_xmit = shaper_start_xmit; - dev->get_stats = shaper_get_stats; dev->set_multicast_list = NULL; /* diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index e810ae942cd..808141b4658 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c @@ -270,7 +270,6 @@ struct sis190_private { void __iomem *mmio_addr; struct pci_dev *pci_dev; struct net_device *dev; - struct net_device_stats stats; spinlock_t lock; u32 rx_buf_sz; u32 cur_rx; @@ -569,7 +568,7 @@ static inline int sis190_rx_pkt_err(u32 status, struct net_device_stats *stats) static int sis190_rx_interrupt(struct net_device *dev, struct sis190_private *tp, void __iomem *ioaddr) { - struct net_device_stats *stats = &tp->stats; + struct net_device_stats *stats = &dev->stats; u32 rx_left, cur_rx = tp->cur_rx; u32 delta, count; @@ -683,8 +682,8 @@ static void sis190_tx_interrupt(struct net_device *dev, skb = tp->Tx_skbuff[entry]; - tp->stats.tx_packets++; - tp->stats.tx_bytes += skb->len; + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; sis190_unmap_tx_skb(tp->pci_dev, skb, txd); tp->Tx_skbuff[entry] = NULL; @@ -1080,7 +1079,7 @@ static void sis190_tx_clear(struct sis190_private *tp) tp->Tx_skbuff[i] = NULL; dev_kfree_skb(skb); - tp->stats.tx_dropped++; + tp->dev->stats.tx_dropped++; } tp->cur_tx = tp->dirty_tx = 0; } @@ -1143,7 +1142,7 @@ static int sis190_start_xmit(struct sk_buff *skb, struct net_device *dev) if (unlikely(skb->len < ETH_ZLEN)) { if (skb_padto(skb, ETH_ZLEN)) { - tp->stats.tx_dropped++; + dev->stats.tx_dropped++; goto out; } len = ETH_ZLEN; @@ -1196,13 +1195,6 @@ out: return NETDEV_TX_OK; } -static struct net_device_stats *sis190_get_stats(struct net_device *dev) -{ - struct sis190_private *tp = netdev_priv(dev); - - return &tp->stats; -} - static void sis190_free_phy(struct list_head *first_phy) { struct sis190_phy *cur, *next; @@ -1795,7 +1787,6 @@ static int __devinit sis190_init_one(struct pci_dev *pdev, dev->open = sis190_open; dev->stop = sis190_close; dev->do_ioctl = sis190_ioctl; - dev->get_stats = sis190_get_stats; dev->tx_timeout = sis190_tx_timeout; dev->watchdog_timeo = SIS190_TX_TIMEOUT; dev->hard_start_xmit = sis190_start_xmit; diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index e1930c3ee75..5da8e671324 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -158,7 +158,6 @@ typedef struct _BufferDesc { } BufferDesc; struct sis900_private { - struct net_device_stats stats; struct pci_dev * pci_dev; spinlock_t lock; @@ -221,7 +220,6 @@ static void sis900_finish_xmit (struct net_device *net_dev); static irqreturn_t sis900_interrupt(int irq, void *dev_instance); static int sis900_close(struct net_device *net_dev); static int mii_ioctl(struct net_device *net_dev, struct ifreq *rq, int cmd); -static struct net_device_stats *sis900_get_stats(struct net_device *net_dev); static u16 sis900_mcast_bitnr(u8 *addr, u8 revision); static void set_rx_mode(struct net_device *net_dev); static void sis900_reset(struct net_device *net_dev); @@ -466,7 +464,6 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev, net_dev->open = &sis900_open; net_dev->hard_start_xmit = &sis900_start_xmit; net_dev->stop = &sis900_close; - net_dev->get_stats = &sis900_get_stats; net_dev->set_config = &sis900_set_config; net_dev->set_multicast_list = &set_rx_mode; net_dev->do_ioctl = &mii_ioctl; @@ -1542,7 +1539,7 @@ static void sis900_tx_timeout(struct net_device *net_dev) sis_priv->tx_skbuff[i] = NULL; sis_priv->tx_ring[i].cmdsts = 0; sis_priv->tx_ring[i].bufptr = 0; - sis_priv->stats.tx_dropped++; + net_dev->stats.tx_dropped++; } } sis_priv->tx_full = 0; @@ -1739,15 +1736,15 @@ static int sis900_rx(struct net_device *net_dev) printk(KERN_DEBUG "%s: Corrupted packet " "received, buffer status = 0x%8.8x/%d.\n", net_dev->name, rx_status, data_size); - sis_priv->stats.rx_errors++; + net_dev->stats.rx_errors++; if (rx_status & OVERRUN) - sis_priv->stats.rx_over_errors++; + net_dev->stats.rx_over_errors++; if (rx_status & (TOOLONG|RUNT)) - sis_priv->stats.rx_length_errors++; + net_dev->stats.rx_length_errors++; if (rx_status & (RXISERR | FAERR)) - sis_priv->stats.rx_frame_errors++; + net_dev->stats.rx_frame_errors++; if (rx_status & CRCERR) - sis_priv->stats.rx_crc_errors++; + net_dev->stats.rx_crc_errors++; /* reset buffer descriptor state */ sis_priv->rx_ring[entry].cmdsts = RX_BUF_SIZE; } else { @@ -1768,7 +1765,7 @@ static int sis900_rx(struct net_device *net_dev) * in the rx ring */ skb = sis_priv->rx_skbuff[entry]; - sis_priv->stats.rx_dropped++; + net_dev->stats.rx_dropped++; goto refill_rx_ring; } @@ -1793,10 +1790,10 @@ static int sis900_rx(struct net_device *net_dev) /* some network statistics */ if ((rx_status & BCAST) == MCAST) - sis_priv->stats.multicast++; + net_dev->stats.multicast++; net_dev->last_rx = jiffies; - sis_priv->stats.rx_bytes += rx_size; - sis_priv->stats.rx_packets++; + net_dev->stats.rx_bytes += rx_size; + net_dev->stats.rx_packets++; sis_priv->dirty_rx++; refill_rx_ring: sis_priv->rx_skbuff[entry] = skb; @@ -1827,7 +1824,7 @@ refill_rx_ring: printk(KERN_INFO "%s: Memory squeeze," "deferring packet.\n", net_dev->name); - sis_priv->stats.rx_dropped++; + net_dev->stats.rx_dropped++; break; } sis_priv->rx_skbuff[entry] = skb; @@ -1878,20 +1875,20 @@ static void sis900_finish_xmit (struct net_device *net_dev) printk(KERN_DEBUG "%s: Transmit " "error, Tx status %8.8x.\n", net_dev->name, tx_status); - sis_priv->stats.tx_errors++; + net_dev->stats.tx_errors++; if (tx_status & UNDERRUN) - sis_priv->stats.tx_fifo_errors++; + net_dev->stats.tx_fifo_errors++; if (tx_status & ABORT) - sis_priv->stats.tx_aborted_errors++; + net_dev->stats.tx_aborted_errors++; if (tx_status & NOCARRIER) - sis_priv->stats.tx_carrier_errors++; + net_dev->stats.tx_carrier_errors++; if (tx_status & OWCOLL) - sis_priv->stats.tx_window_errors++; + net_dev->stats.tx_window_errors++; } else { /* packet successfully transmitted */ - sis_priv->stats.collisions += (tx_status & COLCNT) >> 16; - sis_priv->stats.tx_bytes += tx_status & DSIZE; - sis_priv->stats.tx_packets++; + net_dev->stats.collisions += (tx_status & COLCNT) >> 16; + net_dev->stats.tx_bytes += tx_status & DSIZE; + net_dev->stats.tx_packets++; } /* Free the original skb. */ skb = sis_priv->tx_skbuff[entry]; @@ -2137,21 +2134,6 @@ static int mii_ioctl(struct net_device *net_dev, struct ifreq *rq, int cmd) } } -/** - * sis900_get_stats - Get sis900 read/write statistics - * @net_dev: the net device to get statistics for - * - * get tx/rx statistics for sis900 - */ - -static struct net_device_stats * -sis900_get_stats(struct net_device *net_dev) -{ - struct sis900_private *sis_priv = net_dev->priv; - - return &sis_priv->stats; -} - /** * sis900_set_config - Set media type by net_device.set_config * @dev: the net device for media type change diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 5f03e44ad13..c0276c04dec 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -115,13 +115,6 @@ struct smc911x_local { */ struct sk_buff *pending_tx_skb; - /* - * these are things that the kernel wants me to keep, so users - * can find out semi-useless statistics of how well the card is - * performing - */ - struct net_device_stats stats; - /* version/revision of the SMC911x chip */ u16 version; u16 revision; @@ -315,8 +308,8 @@ static void smc911x_reset(struct net_device *dev) if (lp->pending_tx_skb != NULL) { dev_kfree_skb (lp->pending_tx_skb); lp->pending_tx_skb = NULL; - lp->stats.tx_errors++; - lp->stats.tx_aborted_errors++; + dev->stats.tx_errors++; + dev->stats.tx_aborted_errors++; } } @@ -449,14 +442,14 @@ static inline void smc911x_rcv(struct net_device *dev) pkt_len = (status & RX_STS_PKT_LEN_) >> 16; if (status & RX_STS_ES_) { /* Deal with a bad packet */ - lp->stats.rx_errors++; + dev->stats.rx_errors++; if (status & RX_STS_CRC_ERR_) - lp->stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; else { if (status & RX_STS_LEN_ERR_) - lp->stats.rx_length_errors++; + dev->stats.rx_length_errors++; if (status & RX_STS_MCAST_) - lp->stats.multicast++; + dev->stats.multicast++; } /* Remove the bad packet data from the RX FIFO */ smc911x_drop_pkt(dev); @@ -467,7 +460,7 @@ static inline void smc911x_rcv(struct net_device *dev) if (unlikely(skb == NULL)) { PRINTK( "%s: Low memory, rcvd packet dropped.\n", dev->name); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; smc911x_drop_pkt(dev); return; } @@ -503,8 +496,8 @@ static inline void smc911x_rcv(struct net_device *dev) dev->last_rx = jiffies; skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - lp->stats.rx_packets++; - lp->stats.rx_bytes += pkt_len-4; + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len-4; #endif } } @@ -616,8 +609,8 @@ static int smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) printk("%s: No Tx free space %d < %d\n", dev->name, free, skb->len); lp->pending_tx_skb = NULL; - lp->stats.tx_errors++; - lp->stats.tx_dropped++; + dev->stats.tx_errors++; + dev->stats.tx_dropped++; dev_kfree_skb(skb); return 0; } @@ -667,8 +660,8 @@ static void smc911x_tx(struct net_device *dev) dev->name, (SMC_GET_TX_FIFO_INF() & TX_FIFO_INF_TSUSED_) >> 16); tx_status = SMC_GET_TX_STS_FIFO(); - lp->stats.tx_packets++; - lp->stats.tx_bytes+=tx_status>>16; + dev->stats.tx_packets++; + dev->stats.tx_bytes+=tx_status>>16; DBG(SMC_DEBUG_TX, "%s: Tx FIFO tag 0x%04x status 0x%04x\n", dev->name, (tx_status & 0xffff0000) >> 16, tx_status & 0x0000ffff); @@ -676,22 +669,22 @@ static void smc911x_tx(struct net_device *dev) * full-duplex mode */ if ((tx_status & TX_STS_ES_) && !(lp->ctl_rfduplx && !(tx_status & 0x00000306))) { - lp->stats.tx_errors++; + dev->stats.tx_errors++; } if (tx_status & TX_STS_MANY_COLL_) { - lp->stats.collisions+=16; - lp->stats.tx_aborted_errors++; + dev->stats.collisions+=16; + dev->stats.tx_aborted_errors++; } else { - lp->stats.collisions+=(tx_status & TX_STS_COLL_CNT_) >> 3; + dev->stats.collisions+=(tx_status & TX_STS_COLL_CNT_) >> 3; } /* carrier error only has meaning for half-duplex communication */ if ((tx_status & (TX_STS_LOC_ | TX_STS_NO_CARR_)) && !lp->ctl_rfduplx) { - lp->stats.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; } if (tx_status & TX_STS_LATE_COLL_) { - lp->stats.collisions++; - lp->stats.tx_aborted_errors++; + dev->stats.collisions++; + dev->stats.tx_aborted_errors++; } } } @@ -1121,11 +1114,11 @@ static irqreturn_t smc911x_interrupt(int irq, void *dev_id) /* Handle various error conditions */ if (status & INT_STS_RXE_) { SMC_ACK_INT(INT_STS_RXE_); - lp->stats.rx_errors++; + dev->stats.rx_errors++; } if (status & INT_STS_RXDFH_INT_) { SMC_ACK_INT(INT_STS_RXDFH_INT_); - lp->stats.rx_dropped+=SMC_GET_RX_DROP(); + dev->stats.rx_dropped+=SMC_GET_RX_DROP(); } /* Undocumented interrupt-what is the right thing to do here? */ if (status & INT_STS_RXDF_INT_) { @@ -1140,8 +1133,8 @@ static irqreturn_t smc911x_interrupt(int irq, void *dev_id) cr &= ~MAC_CR_RXEN_; SMC_SET_MAC_CR(cr); DBG(SMC_DEBUG_RX, "%s: RX overrun\n", dev->name); - lp->stats.rx_errors++; - lp->stats.rx_fifo_errors++; + dev->stats.rx_errors++; + dev->stats.rx_fifo_errors++; } SMC_ACK_INT(INT_STS_RDFL_); } @@ -1152,8 +1145,8 @@ static irqreturn_t smc911x_interrupt(int irq, void *dev_id) SMC_SET_MAC_CR(cr); rx_overrun=1; DBG(SMC_DEBUG_RX, "%s: RX overrun\n", dev->name); - lp->stats.rx_errors++; - lp->stats.rx_fifo_errors++; + dev->stats.rx_errors++; + dev->stats.rx_fifo_errors++; } SMC_ACK_INT(INT_STS_RDFO_); } @@ -1307,8 +1300,8 @@ smc911x_rx_dma_irq(int dma, void *data) dev->last_rx = jiffies; skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - lp->stats.rx_packets++; - lp->stats.rx_bytes += skb->len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += skb->len; spin_lock_irqsave(&lp->lock, flags); pkts = (SMC_GET_RX_FIFO_INF() & RX_FIFO_INF_RXSUSED_) >> 16; @@ -1567,19 +1560,6 @@ static int smc911x_close(struct net_device *dev) return 0; } -/* - * Get the current statistics. - * This may be called with the card open or closed. - */ -static struct net_device_stats *smc911x_query_statistics(struct net_device *dev) -{ - struct smc911x_local *lp = netdev_priv(dev); - DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__); - - - return &lp->stats; -} - /* * Ethtool support */ @@ -2056,7 +2036,6 @@ static int __init smc911x_probe(struct net_device *dev, unsigned long ioaddr) dev->hard_start_xmit = smc911x_hard_start_xmit; dev->tx_timeout = smc911x_timeout; dev->watchdog_timeo = msecs_to_jiffies(watchdog); - dev->get_stats = smc911x_query_statistics; dev->set_multicast_list = smc911x_set_multicast_list; dev->ethtool_ops = &smc911x_ethtool_ops; #ifdef CONFIG_NET_POLL_CONTROLLER diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c index 0a79516d196..5b6748e3ea0 100644 --- a/drivers/net/smc9194.c +++ b/drivers/net/smc9194.c @@ -190,13 +190,6 @@ static struct devlist smc_devlist[] __initdata = { /* store this information for the driver.. */ struct smc_local { - /* - these are things that the kernel wants me to keep, so users - can find out semi-useless statistics of how well the card is - performing - */ - struct net_device_stats stats; - /* If I have to wait until memory is available to send a packet, I will store the skbuff here, until I get the @@ -248,12 +241,6 @@ static void smc_timeout(struct net_device *dev); */ static int smc_close(struct net_device *dev); -/* - . This routine allows the proc file system to query the driver's - . statistics. -*/ -static struct net_device_stats * smc_query_statistics( struct net_device *dev); - /* . Finally, a call to set promiscuous mode ( for TCPDUMP and related . programs ) and multicast modes. @@ -514,7 +501,7 @@ static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * de if ( lp->saved_skb) { /* THIS SHOULD NEVER HAPPEN. */ - lp->stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; printk(CARDNAME": Bad Craziness - sent packet while busy.\n" ); return 1; } @@ -1065,7 +1052,6 @@ static int __init smc_probe(struct net_device *dev, int ioaddr) dev->hard_start_xmit = smc_wait_to_send_packet; dev->tx_timeout = smc_timeout; dev->watchdog_timeo = HZ/20; - dev->get_stats = smc_query_statistics; dev->set_multicast_list = smc_set_multicast_list; return 0; @@ -1199,7 +1185,6 @@ static void smc_timeout(struct net_device *dev) */ static void smc_rcv(struct net_device *dev) { - struct smc_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; int packet_number; word status; @@ -1243,13 +1228,13 @@ static void smc_rcv(struct net_device *dev) /* set multicast stats */ if ( status & RS_MULTICAST ) - lp->stats.multicast++; + dev->stats.multicast++; skb = dev_alloc_skb( packet_length + 5); if ( skb == NULL ) { printk(KERN_NOTICE CARDNAME ": Low memory, packet dropped.\n"); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; goto done; } @@ -1289,16 +1274,16 @@ static void smc_rcv(struct net_device *dev) skb->protocol = eth_type_trans(skb, dev ); netif_rx(skb); dev->last_rx = jiffies; - lp->stats.rx_packets++; - lp->stats.rx_bytes += packet_length; + dev->stats.rx_packets++; + dev->stats.rx_bytes += packet_length; } else { /* error ... */ - lp->stats.rx_errors++; + dev->stats.rx_errors++; - if ( status & RS_ALGNERR ) lp->stats.rx_frame_errors++; + if ( status & RS_ALGNERR ) dev->stats.rx_frame_errors++; if ( status & (RS_TOOSHORT | RS_TOOLONG ) ) - lp->stats.rx_length_errors++; - if ( status & RS_BADCRC) lp->stats.rx_crc_errors++; + dev->stats.rx_length_errors++; + if ( status & RS_BADCRC) dev->stats.rx_crc_errors++; } done: @@ -1346,12 +1331,12 @@ static void smc_tx( struct net_device * dev ) tx_status = inw( ioaddr + DATA_1 ); PRINTK3((CARDNAME": TX DONE STATUS: %4x \n", tx_status )); - lp->stats.tx_errors++; - if ( tx_status & TS_LOSTCAR ) lp->stats.tx_carrier_errors++; + dev->stats.tx_errors++; + if ( tx_status & TS_LOSTCAR ) dev->stats.tx_carrier_errors++; if ( tx_status & TS_LATCOL ) { printk(KERN_DEBUG CARDNAME ": Late collision occurred on last xmit.\n"); - lp->stats.tx_window_errors++; + dev->stats.tx_window_errors++; } #if 0 if ( tx_status & TS_16COL ) { ... } @@ -1446,10 +1431,10 @@ static irqreturn_t smc_interrupt(int irq, void * dev_id) SMC_SELECT_BANK( 0 ); card_stats = inw( ioaddr + COUNTER ); /* single collisions */ - lp->stats.collisions += card_stats & 0xF; + dev->stats.collisions += card_stats & 0xF; card_stats >>= 4; /* multiple collisions */ - lp->stats.collisions += card_stats & 0xF; + dev->stats.collisions += card_stats & 0xF; /* these are for when linux supports these statistics */ @@ -1458,7 +1443,7 @@ static irqreturn_t smc_interrupt(int irq, void * dev_id) ": TX_BUFFER_EMPTY handled\n")); outb( IM_TX_EMPTY_INT, ioaddr + INTERRUPT ); mask &= ~IM_TX_EMPTY_INT; - lp->stats.tx_packets += lp->packets_waiting; + dev->stats.tx_packets += lp->packets_waiting; lp->packets_waiting = 0; } else if (status & IM_ALLOC_INT ) { @@ -1477,8 +1462,8 @@ static irqreturn_t smc_interrupt(int irq, void * dev_id) PRINTK2((CARDNAME": Handoff done successfully.\n")); } else if (status & IM_RX_OVRN_INT ) { - lp->stats.rx_errors++; - lp->stats.rx_fifo_errors++; + dev->stats.rx_errors++; + dev->stats.rx_fifo_errors++; outb( IM_RX_OVRN_INT, ioaddr + INTERRUPT ); } else if (status & IM_EPH_INT ) { PRINTK((CARDNAME ": UNSUPPORTED: EPH INTERRUPT \n")); @@ -1521,16 +1506,6 @@ static int smc_close(struct net_device *dev) return 0; } -/*------------------------------------------------------------ - . Get the current statistics. - . This may be called with the card open or closed. - .-------------------------------------------------------------*/ -static struct net_device_stats* smc_query_statistics(struct net_device *dev) { - struct smc_local *lp = netdev_priv(dev); - - return &lp->stats; -} - /*----------------------------------------------------------- . smc_set_multicast_list . diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index c5837ab5c96..fe28d277f21 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -183,13 +183,6 @@ struct smc_local { struct sk_buff *pending_tx_skb; struct tasklet_struct tx_task; - /* - * these are things that the kernel wants me to keep, so users - * can find out semi-useless statistics of how well the card is - * performing - */ - struct net_device_stats stats; - /* version/revision of the SMC91x chip */ int version; @@ -332,8 +325,8 @@ static void smc_reset(struct net_device *dev) /* free any pending tx skb */ if (pending_skb) { dev_kfree_skb(pending_skb); - lp->stats.tx_errors++; - lp->stats.tx_aborted_errors++; + dev->stats.tx_errors++; + dev->stats.tx_aborted_errors++; } /* @@ -512,13 +505,13 @@ static inline void smc_rcv(struct net_device *dev) } SMC_WAIT_MMU_BUSY(); SMC_SET_MMU_CMD(MC_RELEASE); - lp->stats.rx_errors++; + dev->stats.rx_errors++; if (status & RS_ALGNERR) - lp->stats.rx_frame_errors++; + dev->stats.rx_frame_errors++; if (status & (RS_TOOSHORT | RS_TOOLONG)) - lp->stats.rx_length_errors++; + dev->stats.rx_length_errors++; if (status & RS_BADCRC) - lp->stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; } else { struct sk_buff *skb; unsigned char *data; @@ -526,7 +519,7 @@ static inline void smc_rcv(struct net_device *dev) /* set multicast stats */ if (status & RS_MULTICAST) - lp->stats.multicast++; + dev->stats.multicast++; /* * Actual payload is packet_len - 6 (or 5 if odd byte). @@ -542,7 +535,7 @@ static inline void smc_rcv(struct net_device *dev) dev->name); SMC_WAIT_MMU_BUSY(); SMC_SET_MMU_CMD(MC_RELEASE); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; return; } @@ -570,8 +563,8 @@ static inline void smc_rcv(struct net_device *dev) dev->last_rx = jiffies; skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - lp->stats.rx_packets++; - lp->stats.rx_bytes += data_len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += data_len; } } @@ -644,8 +637,8 @@ static void smc_hardware_send_pkt(unsigned long data) packet_no = SMC_GET_AR(); if (unlikely(packet_no & AR_FAILED)) { printk("%s: Memory allocation failed.\n", dev->name); - lp->stats.tx_errors++; - lp->stats.tx_fifo_errors++; + dev->stats.tx_errors++; + dev->stats.tx_fifo_errors++; smc_special_unlock(&lp->lock); goto done; } @@ -688,8 +681,8 @@ static void smc_hardware_send_pkt(unsigned long data) smc_special_unlock(&lp->lock); dev->trans_start = jiffies; - lp->stats.tx_packets++; - lp->stats.tx_bytes += len; + dev->stats.tx_packets++; + dev->stats.tx_bytes += len; SMC_ENABLE_INT(IM_TX_INT | IM_TX_EMPTY_INT); @@ -729,8 +722,8 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) numPages = ((skb->len & ~1) + (6 - 1)) >> 8; if (unlikely(numPages > 7)) { printk("%s: Far too big packet error.\n", dev->name); - lp->stats.tx_errors++; - lp->stats.tx_dropped++; + dev->stats.tx_errors++; + dev->stats.tx_dropped++; dev_kfree_skb(skb); return 0; } @@ -803,17 +796,17 @@ static void smc_tx(struct net_device *dev) dev->name, tx_status, packet_no); if (!(tx_status & ES_TX_SUC)) - lp->stats.tx_errors++; + dev->stats.tx_errors++; if (tx_status & ES_LOSTCARR) - lp->stats.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; if (tx_status & (ES_LATCOL | ES_16COL)) { PRINTK("%s: %s occurred on last xmit\n", dev->name, (tx_status & ES_LATCOL) ? "late collision" : "too many collisions"); - lp->stats.tx_window_errors++; - if (!(lp->stats.tx_window_errors & 63) && net_ratelimit()) { + dev->stats.tx_window_errors++; + if (!(dev->stats.tx_window_errors & 63) && net_ratelimit()) { printk(KERN_INFO "%s: unexpectedly large number of " "bad collisions. Please check duplex " "setting.\n", dev->name); @@ -1347,19 +1340,19 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id) SMC_SELECT_BANK(2); /* single collisions */ - lp->stats.collisions += card_stats & 0xF; + dev->stats.collisions += card_stats & 0xF; card_stats >>= 4; /* multiple collisions */ - lp->stats.collisions += card_stats & 0xF; + dev->stats.collisions += card_stats & 0xF; } else if (status & IM_RX_OVRN_INT) { DBG(1, "%s: RX overrun (EPH_ST 0x%04x)\n", dev->name, ({ int eph_st; SMC_SELECT_BANK(0); eph_st = SMC_GET_EPH_STATUS(); SMC_SELECT_BANK(2); eph_st; }) ); SMC_ACK_INT(IM_RX_OVRN_INT); - lp->stats.rx_errors++; - lp->stats.rx_fifo_errors++; + dev->stats.rx_errors++; + dev->stats.rx_fifo_errors++; } else if (status & IM_EPH_INT) { smc_eph_interrupt(dev); } else if (status & IM_MDINT) { @@ -1627,19 +1620,6 @@ static int smc_close(struct net_device *dev) return 0; } -/* - * Get the current statistics. - * This may be called with the card open or closed. - */ -static struct net_device_stats *smc_query_statistics(struct net_device *dev) -{ - struct smc_local *lp = netdev_priv(dev); - - DBG(2, "%s: %s\n", dev->name, __FUNCTION__); - - return &lp->stats; -} - /* * Ethtool support */ @@ -1965,7 +1945,6 @@ static int __init smc_probe(struct net_device *dev, void __iomem *ioaddr) dev->hard_start_xmit = smc_hard_start_xmit; dev->tx_timeout = smc_timeout; dev->watchdog_timeo = msecs_to_jiffies(watchdog); - dev->get_stats = smc_query_statistics; dev->set_multicast_list = smc_set_multicast_list; dev->ethtool_ops = &smc_ethtool_ops; #ifdef CONFIG_NET_POLL_CONTROLLER diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index edc736eb3b8..fab055ffcc9 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -795,6 +795,7 @@ spider_net_set_low_watermark(struct spider_net_card *card) static int spider_net_release_tx_chain(struct spider_net_card *card, int brutal) { + struct net_device *dev = card->netdev; struct spider_net_descr_chain *chain = &card->tx_chain; struct spider_net_descr *descr; struct spider_net_hw_descr *hwdescr; @@ -815,8 +816,8 @@ spider_net_release_tx_chain(struct spider_net_card *card, int brutal) status = spider_net_get_descr_status(hwdescr); switch (status) { case SPIDER_NET_DESCR_COMPLETE: - card->netdev_stats.tx_packets++; - card->netdev_stats.tx_bytes += descr->skb->len; + dev->stats.tx_packets++; + dev->stats.tx_bytes += descr->skb->len; break; case SPIDER_NET_DESCR_CARDOWNED: @@ -835,11 +836,11 @@ spider_net_release_tx_chain(struct spider_net_card *card, int brutal) if (netif_msg_tx_err(card)) dev_err(&card->netdev->dev, "forcing end of tx descriptor " "with status x%02x\n", status); - card->netdev_stats.tx_errors++; + dev->stats.tx_errors++; break; default: - card->netdev_stats.tx_dropped++; + dev->stats.tx_dropped++; if (!brutal) { spin_unlock_irqrestore(&chain->lock, flags); return 1; @@ -919,7 +920,7 @@ spider_net_xmit(struct sk_buff *skb, struct net_device *netdev) spider_net_release_tx_chain(card, 0); if (spider_net_prepare_tx_descr(card, skb) != 0) { - card->netdev_stats.tx_dropped++; + netdev->stats.tx_dropped++; netif_stop_queue(netdev); return NETDEV_TX_BUSY; } @@ -979,16 +980,12 @@ static void spider_net_pass_skb_up(struct spider_net_descr *descr, struct spider_net_card *card) { - struct spider_net_hw_descr *hwdescr= descr->hwdescr; - struct sk_buff *skb; - struct net_device *netdev; - u32 data_status, data_error; - - data_status = hwdescr->data_status; - data_error = hwdescr->data_error; - netdev = card->netdev; + struct spider_net_hw_descr *hwdescr = descr->hwdescr; + struct sk_buff *skb = descr->skb; + struct net_device *netdev = card->netdev; + u32 data_status = hwdescr->data_status; + u32 data_error = hwdescr->data_error; - skb = descr->skb; skb_put(skb, hwdescr->valid_size); /* the card seems to add 2 bytes of junk in front @@ -1015,8 +1012,8 @@ spider_net_pass_skb_up(struct spider_net_descr *descr, } /* update netdevice statistics */ - card->netdev_stats.rx_packets++; - card->netdev_stats.rx_bytes += skb->len; + netdev->stats.rx_packets++; + netdev->stats.rx_bytes += skb->len; /* pass skb up to stack */ netif_receive_skb(skb); @@ -1184,6 +1181,7 @@ static int spider_net_resync_tail_ptr(struct spider_net_card *card) static int spider_net_decode_one_descr(struct spider_net_card *card) { + struct net_device *dev = card->netdev; struct spider_net_descr_chain *chain = &card->rx_chain; struct spider_net_descr *descr = chain->tail; struct spider_net_hw_descr *hwdescr = descr->hwdescr; @@ -1210,9 +1208,9 @@ spider_net_decode_one_descr(struct spider_net_card *card) (status == SPIDER_NET_DESCR_PROTECTION_ERROR) || (status == SPIDER_NET_DESCR_FORCE_END) ) { if (netif_msg_rx_err(card)) - dev_err(&card->netdev->dev, + dev_err(&dev->dev, "dropping RX descriptor with state %d\n", status); - card->netdev_stats.rx_dropped++; + dev->stats.rx_dropped++; goto bad_desc; } @@ -1314,20 +1312,6 @@ static int spider_net_poll(struct napi_struct *napi, int budget) return packets_done; } -/** - * spider_net_get_stats - get interface statistics - * @netdev: interface device structure - * - * returns the interface statistics residing in the spider_net_card struct - */ -static struct net_device_stats * -spider_net_get_stats(struct net_device *netdev) -{ - struct spider_net_card *card = netdev_priv(netdev); - struct net_device_stats *stats = &card->netdev_stats; - return stats; -} - /** * spider_net_change_mtu - changes the MTU of an interface * @netdev: interface device structure @@ -2290,7 +2274,6 @@ spider_net_setup_netdev_ops(struct net_device *netdev) netdev->open = &spider_net_open; netdev->stop = &spider_net_stop; netdev->hard_start_xmit = &spider_net_xmit; - netdev->get_stats = &spider_net_get_stats; netdev->set_multicast_list = &spider_net_set_multi; netdev->set_mac_address = &spider_net_set_mac; netdev->change_mtu = &spider_net_change_mtu; diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h index a2fcdebc379..a897beee7d5 100644 --- a/drivers/net/spider_net.h +++ b/drivers/net/spider_net.h @@ -487,7 +487,6 @@ struct spider_net_card { /* for ethtool */ int msg_enable; - struct net_device_stats netdev_stats; struct spider_net_extra_stats spider_stats; struct spider_net_options options; diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c index c67632dcac4..f8fbc049270 100644 --- a/drivers/net/sun3lance.c +++ b/drivers/net/sun3lance.c @@ -152,7 +152,6 @@ struct lance_private { struct lance_memory *mem; int new_rx, new_tx; /* The next free ring entry */ int old_tx, old_rx; /* ring entry to be processed */ - struct net_device_stats stats; /* These two must be longs for set_bit() */ long tx_full; long lock; @@ -241,7 +240,6 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ); static irqreturn_t lance_interrupt( int irq, void *dev_id); static int lance_rx( struct net_device *dev ); static int lance_close( struct net_device *dev ); -static struct net_device_stats *lance_get_stats( struct net_device *dev ); static void set_multicast_list( struct net_device *dev ); /************************* End of Prototypes **************************/ @@ -401,15 +399,12 @@ static int __init lance_probe( struct net_device *dev) dev->open = &lance_open; dev->hard_start_xmit = &lance_start_xmit; dev->stop = &lance_close; - dev->get_stats = &lance_get_stats; dev->set_multicast_list = &set_multicast_list; dev->set_mac_address = NULL; // KLUDGE -- REMOVE ME set_bit(__LINK_STATE_PRESENT, &dev->state); - memset( &lp->stats, 0, sizeof(lp->stats) ); - return 1; } @@ -534,7 +529,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) * little endian mode. */ REGA(CSR3) = CSR3_BSWP; - lp->stats.tx_errors++; + dev->stats.tx_errors++; if(lance_debug >= 2) { int i; @@ -634,7 +629,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) head->flag = TMD1_OWN_CHIP | TMD1_ENP | TMD1_STP; lp->new_tx = (lp->new_tx + 1) & TX_RING_MOD_MASK; - lp->stats.tx_bytes += skb->len; + dev->stats.tx_bytes += skb->len; /* Trigger an immediate send poll. */ REGA(CSR0) = CSR0_INEA | CSR0_TDMD | CSR0_STRT; @@ -712,12 +707,12 @@ static irqreturn_t lance_interrupt( int irq, void *dev_id) if (head->flag & TMD1_ERR) { int status = head->misc; - lp->stats.tx_errors++; - if (status & TMD3_RTRY) lp->stats.tx_aborted_errors++; - if (status & TMD3_LCAR) lp->stats.tx_carrier_errors++; - if (status & TMD3_LCOL) lp->stats.tx_window_errors++; + dev->stats.tx_errors++; + if (status & TMD3_RTRY) dev->stats.tx_aborted_errors++; + if (status & TMD3_LCAR) dev->stats.tx_carrier_errors++; + if (status & TMD3_LCOL) dev->stats.tx_window_errors++; if (status & (TMD3_UFLO | TMD3_BUFF)) { - lp->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; printk("%s: Tx FIFO error\n", dev->name); REGA(CSR0) = CSR0_STOP; @@ -730,9 +725,9 @@ static irqreturn_t lance_interrupt( int irq, void *dev_id) head->flag &= ~(TMD1_ENP | TMD1_STP); if(head->flag & (TMD1_ONE | TMD1_MORE)) - lp->stats.collisions++; + dev->stats.collisions++; - lp->stats.tx_packets++; + dev->stats.tx_packets++; DPRINTK(3, ("cleared tx ring %d\n", old_tx)); } old_tx = (old_tx +1) & TX_RING_MOD_MASK; @@ -752,8 +747,8 @@ static irqreturn_t lance_interrupt( int irq, void *dev_id) lance_rx( dev ); /* Log misc errors. */ - if (csr0 & CSR0_BABL) lp->stats.tx_errors++; /* Tx babble. */ - if (csr0 & CSR0_MISS) lp->stats.rx_errors++; /* Missed a Rx frame. */ + if (csr0 & CSR0_BABL) dev->stats.tx_errors++; /* Tx babble. */ + if (csr0 & CSR0_MISS) dev->stats.rx_errors++; /* Missed a Rx frame. */ if (csr0 & CSR0_MERR) { DPRINTK( 1, ( "%s: Bus master arbitration failure (?!?), " "status %04x.\n", dev->name, csr0 )); @@ -799,11 +794,11 @@ static int lance_rx( struct net_device *dev ) full-sized buffers it's possible for a jabber packet to use two buffers, with only the last correctly noting the error. */ if (status & RMD1_ENP) /* Only count a general error at the */ - lp->stats.rx_errors++; /* end of a packet.*/ - if (status & RMD1_FRAM) lp->stats.rx_frame_errors++; - if (status & RMD1_OFLO) lp->stats.rx_over_errors++; - if (status & RMD1_CRC) lp->stats.rx_crc_errors++; - if (status & RMD1_BUFF) lp->stats.rx_fifo_errors++; + dev->stats.rx_errors++; /* end of a packet.*/ + if (status & RMD1_FRAM) dev->stats.rx_frame_errors++; + if (status & RMD1_OFLO) dev->stats.rx_over_errors++; + if (status & RMD1_CRC) dev->stats.rx_crc_errors++; + if (status & RMD1_BUFF) dev->stats.rx_fifo_errors++; head->flag &= (RMD1_ENP|RMD1_STP); } else { /* Malloc up new buffer, compatible with net-3. */ @@ -813,7 +808,7 @@ static int lance_rx( struct net_device *dev ) if (pkt_len < 60) { printk( "%s: Runt packet!\n", dev->name ); - lp->stats.rx_errors++; + dev->stats.rx_errors++; } else { skb = dev_alloc_skb( pkt_len+2 ); @@ -821,7 +816,7 @@ static int lance_rx( struct net_device *dev ) DPRINTK( 1, ( "%s: Memory squeeze, deferring packet.\n", dev->name )); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; head->msg_length = 0; head->flag |= RMD1_OWN_CHIP; lp->new_rx = (lp->new_rx+1) & @@ -859,8 +854,8 @@ static int lance_rx( struct net_device *dev ) skb->protocol = eth_type_trans( skb, dev ); netif_rx( skb ); dev->last_rx = jiffies; - lp->stats.rx_packets++; - lp->stats.rx_bytes += pkt_len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; } } @@ -897,14 +892,6 @@ static int lance_close( struct net_device *dev ) } -static struct net_device_stats *lance_get_stats( struct net_device *dev ) -{ - struct lance_private *lp = netdev_priv(dev); - - return &lp->stats; -} - - /* Set or clear the multicast filter for this adaptor. num_addrs == -1 Promiscuous mode, receive all packets num_addrs == 0 Normal mode, clear multicast list diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c index 17d66c1185c..7bf5c90b774 100644 --- a/drivers/net/sunlance.c +++ b/drivers/net/sunlance.c @@ -248,7 +248,6 @@ struct lance_private { int rx_new, tx_new; int rx_old, tx_old; - struct net_device_stats stats; struct sbus_dma *ledma; /* If set this points to ledma */ char tpe; /* cable-selection is TPE */ char auto_select; /* cable-selection by carrier */ @@ -519,17 +518,17 @@ static void lance_rx_dvma(struct net_device *dev) /* We got an incomplete frame? */ if ((bits & LE_R1_POK) != LE_R1_POK) { - lp->stats.rx_over_errors++; - lp->stats.rx_errors++; + dev->stats.rx_over_errors++; + dev->stats.rx_errors++; } else if (bits & LE_R1_ERR) { /* Count only the end frame as a rx error, * not the beginning */ - if (bits & LE_R1_BUF) lp->stats.rx_fifo_errors++; - if (bits & LE_R1_CRC) lp->stats.rx_crc_errors++; - if (bits & LE_R1_OFL) lp->stats.rx_over_errors++; - if (bits & LE_R1_FRA) lp->stats.rx_frame_errors++; - if (bits & LE_R1_EOP) lp->stats.rx_errors++; + if (bits & LE_R1_BUF) dev->stats.rx_fifo_errors++; + if (bits & LE_R1_CRC) dev->stats.rx_crc_errors++; + if (bits & LE_R1_OFL) dev->stats.rx_over_errors++; + if (bits & LE_R1_FRA) dev->stats.rx_frame_errors++; + if (bits & LE_R1_EOP) dev->stats.rx_errors++; } else { len = (rd->mblength & 0xfff) - 4; skb = dev_alloc_skb(len + 2); @@ -537,14 +536,14 @@ static void lance_rx_dvma(struct net_device *dev) if (skb == NULL) { printk(KERN_INFO "%s: Memory squeeze, deferring packet.\n", dev->name); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; rd->mblength = 0; rd->rmd1_bits = LE_R1_OWN; lp->rx_new = RX_NEXT(entry); return; } - lp->stats.rx_bytes += len; + dev->stats.rx_bytes += len; skb_reserve(skb, 2); /* 16 byte align */ skb_put(skb, len); /* make room */ @@ -554,7 +553,7 @@ static void lance_rx_dvma(struct net_device *dev) skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; - lp->stats.rx_packets++; + dev->stats.rx_packets++; } /* Return the packet to the pool */ @@ -586,12 +585,12 @@ static void lance_tx_dvma(struct net_device *dev) if (bits & LE_T1_ERR) { u16 status = td->misc; - lp->stats.tx_errors++; - if (status & LE_T3_RTY) lp->stats.tx_aborted_errors++; - if (status & LE_T3_LCOL) lp->stats.tx_window_errors++; + dev->stats.tx_errors++; + if (status & LE_T3_RTY) dev->stats.tx_aborted_errors++; + if (status & LE_T3_LCOL) dev->stats.tx_window_errors++; if (status & LE_T3_CLOS) { - lp->stats.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; if (lp->auto_select) { lp->tpe = 1 - lp->tpe; printk(KERN_NOTICE "%s: Carrier Lost, trying %s\n", @@ -608,7 +607,7 @@ static void lance_tx_dvma(struct net_device *dev) * transmitter, restart the adapter. */ if (status & (LE_T3_BUF|LE_T3_UFL)) { - lp->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; printk(KERN_ERR "%s: Tx: ERR_BUF|ERR_UFL, restarting\n", dev->name); @@ -626,13 +625,13 @@ static void lance_tx_dvma(struct net_device *dev) /* One collision before packet was sent. */ if (bits & LE_T1_EONE) - lp->stats.collisions++; + dev->stats.collisions++; /* More than one collision, be optimistic. */ if (bits & LE_T1_EMORE) - lp->stats.collisions += 2; + dev->stats.collisions += 2; - lp->stats.tx_packets++; + dev->stats.tx_packets++; } j = TX_NEXT(j); @@ -692,17 +691,17 @@ static void lance_rx_pio(struct net_device *dev) /* We got an incomplete frame? */ if ((bits & LE_R1_POK) != LE_R1_POK) { - lp->stats.rx_over_errors++; - lp->stats.rx_errors++; + dev->stats.rx_over_errors++; + dev->stats.rx_errors++; } else if (bits & LE_R1_ERR) { /* Count only the end frame as a rx error, * not the beginning */ - if (bits & LE_R1_BUF) lp->stats.rx_fifo_errors++; - if (bits & LE_R1_CRC) lp->stats.rx_crc_errors++; - if (bits & LE_R1_OFL) lp->stats.rx_over_errors++; - if (bits & LE_R1_FRA) lp->stats.rx_frame_errors++; - if (bits & LE_R1_EOP) lp->stats.rx_errors++; + if (bits & LE_R1_BUF) dev->stats.rx_fifo_errors++; + if (bits & LE_R1_CRC) dev->stats.rx_crc_errors++; + if (bits & LE_R1_OFL) dev->stats.rx_over_errors++; + if (bits & LE_R1_FRA) dev->stats.rx_frame_errors++; + if (bits & LE_R1_EOP) dev->stats.rx_errors++; } else { len = (sbus_readw(&rd->mblength) & 0xfff) - 4; skb = dev_alloc_skb(len + 2); @@ -710,14 +709,14 @@ static void lance_rx_pio(struct net_device *dev) if (skb == NULL) { printk(KERN_INFO "%s: Memory squeeze, deferring packet.\n", dev->name); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; sbus_writew(0, &rd->mblength); sbus_writeb(LE_R1_OWN, &rd->rmd1_bits); lp->rx_new = RX_NEXT(entry); return; } - lp->stats.rx_bytes += len; + dev->stats.rx_bytes += len; skb_reserve (skb, 2); /* 16 byte align */ skb_put(skb, len); /* make room */ @@ -725,7 +724,7 @@ static void lance_rx_pio(struct net_device *dev) skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; - lp->stats.rx_packets++; + dev->stats.rx_packets++; } /* Return the packet to the pool */ @@ -757,12 +756,12 @@ static void lance_tx_pio(struct net_device *dev) if (bits & LE_T1_ERR) { u16 status = sbus_readw(&td->misc); - lp->stats.tx_errors++; - if (status & LE_T3_RTY) lp->stats.tx_aborted_errors++; - if (status & LE_T3_LCOL) lp->stats.tx_window_errors++; + dev->stats.tx_errors++; + if (status & LE_T3_RTY) dev->stats.tx_aborted_errors++; + if (status & LE_T3_LCOL) dev->stats.tx_window_errors++; if (status & LE_T3_CLOS) { - lp->stats.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; if (lp->auto_select) { lp->tpe = 1 - lp->tpe; printk(KERN_NOTICE "%s: Carrier Lost, trying %s\n", @@ -779,7 +778,7 @@ static void lance_tx_pio(struct net_device *dev) * transmitter, restart the adapter. */ if (status & (LE_T3_BUF|LE_T3_UFL)) { - lp->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; printk(KERN_ERR "%s: Tx: ERR_BUF|ERR_UFL, restarting\n", dev->name); @@ -797,13 +796,13 @@ static void lance_tx_pio(struct net_device *dev) /* One collision before packet was sent. */ if (bits & LE_T1_EONE) - lp->stats.collisions++; + dev->stats.collisions++; /* More than one collision, be optimistic. */ if (bits & LE_T1_EMORE) - lp->stats.collisions += 2; + dev->stats.collisions += 2; - lp->stats.tx_packets++; + dev->stats.tx_packets++; } j = TX_NEXT(j); @@ -844,10 +843,10 @@ static irqreturn_t lance_interrupt(int irq, void *dev_id) lp->tx(dev); if (csr0 & LE_C0_BABL) - lp->stats.tx_errors++; + dev->stats.tx_errors++; if (csr0 & LE_C0_MISS) - lp->stats.rx_errors++; + dev->stats.rx_errors++; if (csr0 & LE_C0_MERR) { if (lp->dregs) { @@ -1127,7 +1126,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_lock_irq(&lp->lock); - lp->stats.tx_bytes += len; + dev->stats.tx_bytes += len; entry = lp->tx_new & TX_RING_MOD_MASK; if (lp->pio_buffer) { @@ -1170,13 +1169,6 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) return 0; } -static struct net_device_stats *lance_get_stats(struct net_device *dev) -{ - struct lance_private *lp = netdev_priv(dev); - - return &lp->stats; -} - /* taken from the depca driver */ static void lance_load_multicast(struct net_device *dev) { @@ -1463,7 +1455,6 @@ no_link_test: dev->hard_start_xmit = &lance_start_xmit; dev->tx_timeout = &lance_tx_timeout; dev->watchdog_timeo = 5*HZ; - dev->get_stats = &lance_get_stats; dev->set_multicast_list = &lance_set_multicast; dev->ethtool_ops = &sparc_lance_ethtool_ops; diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c index b5c2974fd62..ff23c6489ef 100644 --- a/drivers/net/sunqe.c +++ b/drivers/net/sunqe.c @@ -260,31 +260,31 @@ static int qe_is_bolixed(struct sunqe *qep, u32 qe_status) if (qe_status & CREG_STAT_EDEFER) { printk(KERN_ERR "%s: Excessive transmit defers.\n", dev->name); - qep->net_stats.tx_errors++; + dev->stats.tx_errors++; } if (qe_status & CREG_STAT_CLOSS) { printk(KERN_ERR "%s: Carrier lost, link down?\n", dev->name); - qep->net_stats.tx_errors++; - qep->net_stats.tx_carrier_errors++; + dev->stats.tx_errors++; + dev->stats.tx_carrier_errors++; } if (qe_status & CREG_STAT_ERETRIES) { printk(KERN_ERR "%s: Excessive transmit retries (more than 16).\n", dev->name); - qep->net_stats.tx_errors++; + dev->stats.tx_errors++; mace_hwbug_workaround = 1; } if (qe_status & CREG_STAT_LCOLL) { printk(KERN_ERR "%s: Late transmit collision.\n", dev->name); - qep->net_stats.tx_errors++; - qep->net_stats.collisions++; + dev->stats.tx_errors++; + dev->stats.collisions++; mace_hwbug_workaround = 1; } if (qe_status & CREG_STAT_FUFLOW) { printk(KERN_ERR "%s: Transmit fifo underflow, driver bug.\n", dev->name); - qep->net_stats.tx_errors++; + dev->stats.tx_errors++; mace_hwbug_workaround = 1; } @@ -297,104 +297,104 @@ static int qe_is_bolixed(struct sunqe *qep, u32 qe_status) } if (qe_status & CREG_STAT_CCOFLOW) { - qep->net_stats.tx_errors += 256; - qep->net_stats.collisions += 256; + dev->stats.tx_errors += 256; + dev->stats.collisions += 256; } if (qe_status & CREG_STAT_TXDERROR) { printk(KERN_ERR "%s: Transmit descriptor is bogus, driver bug.\n", dev->name); - qep->net_stats.tx_errors++; - qep->net_stats.tx_aborted_errors++; + dev->stats.tx_errors++; + dev->stats.tx_aborted_errors++; mace_hwbug_workaround = 1; } if (qe_status & CREG_STAT_TXLERR) { printk(KERN_ERR "%s: Transmit late error.\n", dev->name); - qep->net_stats.tx_errors++; + dev->stats.tx_errors++; mace_hwbug_workaround = 1; } if (qe_status & CREG_STAT_TXPERR) { printk(KERN_ERR "%s: Transmit DMA parity error.\n", dev->name); - qep->net_stats.tx_errors++; - qep->net_stats.tx_aborted_errors++; + dev->stats.tx_errors++; + dev->stats.tx_aborted_errors++; mace_hwbug_workaround = 1; } if (qe_status & CREG_STAT_TXSERR) { printk(KERN_ERR "%s: Transmit DMA sbus error ack.\n", dev->name); - qep->net_stats.tx_errors++; - qep->net_stats.tx_aborted_errors++; + dev->stats.tx_errors++; + dev->stats.tx_aborted_errors++; mace_hwbug_workaround = 1; } if (qe_status & CREG_STAT_RCCOFLOW) { - qep->net_stats.rx_errors += 256; - qep->net_stats.collisions += 256; + dev->stats.rx_errors += 256; + dev->stats.collisions += 256; } if (qe_status & CREG_STAT_RUOFLOW) { - qep->net_stats.rx_errors += 256; - qep->net_stats.rx_over_errors += 256; + dev->stats.rx_errors += 256; + dev->stats.rx_over_errors += 256; } if (qe_status & CREG_STAT_MCOFLOW) { - qep->net_stats.rx_errors += 256; - qep->net_stats.rx_missed_errors += 256; + dev->stats.rx_errors += 256; + dev->stats.rx_missed_errors += 256; } if (qe_status & CREG_STAT_RXFOFLOW) { printk(KERN_ERR "%s: Receive fifo overflow.\n", dev->name); - qep->net_stats.rx_errors++; - qep->net_stats.rx_over_errors++; + dev->stats.rx_errors++; + dev->stats.rx_over_errors++; } if (qe_status & CREG_STAT_RLCOLL) { printk(KERN_ERR "%s: Late receive collision.\n", dev->name); - qep->net_stats.rx_errors++; - qep->net_stats.collisions++; + dev->stats.rx_errors++; + dev->stats.collisions++; } if (qe_status & CREG_STAT_FCOFLOW) { - qep->net_stats.rx_errors += 256; - qep->net_stats.rx_frame_errors += 256; + dev->stats.rx_errors += 256; + dev->stats.rx_frame_errors += 256; } if (qe_status & CREG_STAT_CECOFLOW) { - qep->net_stats.rx_errors += 256; - qep->net_stats.rx_crc_errors += 256; + dev->stats.rx_errors += 256; + dev->stats.rx_crc_errors += 256; } if (qe_status & CREG_STAT_RXDROP) { printk(KERN_ERR "%s: Receive packet dropped.\n", dev->name); - qep->net_stats.rx_errors++; - qep->net_stats.rx_dropped++; - qep->net_stats.rx_missed_errors++; + dev->stats.rx_errors++; + dev->stats.rx_dropped++; + dev->stats.rx_missed_errors++; } if (qe_status & CREG_STAT_RXSMALL) { printk(KERN_ERR "%s: Receive buffer too small, driver bug.\n", dev->name); - qep->net_stats.rx_errors++; - qep->net_stats.rx_length_errors++; + dev->stats.rx_errors++; + dev->stats.rx_length_errors++; } if (qe_status & CREG_STAT_RXLERR) { printk(KERN_ERR "%s: Receive late error.\n", dev->name); - qep->net_stats.rx_errors++; + dev->stats.rx_errors++; mace_hwbug_workaround = 1; } if (qe_status & CREG_STAT_RXPERR) { printk(KERN_ERR "%s: Receive DMA parity error.\n", dev->name); - qep->net_stats.rx_errors++; - qep->net_stats.rx_missed_errors++; + dev->stats.rx_errors++; + dev->stats.rx_missed_errors++; mace_hwbug_workaround = 1; } if (qe_status & CREG_STAT_RXSERR) { printk(KERN_ERR "%s: Receive DMA sbus error ack.\n", dev->name); - qep->net_stats.rx_errors++; - qep->net_stats.rx_missed_errors++; + dev->stats.rx_errors++; + dev->stats.rx_missed_errors++; mace_hwbug_workaround = 1; } @@ -409,6 +409,7 @@ static int qe_is_bolixed(struct sunqe *qep, u32 qe_status) static void qe_rx(struct sunqe *qep) { struct qe_rxd *rxbase = &qep->qe_block->qe_rxd[0]; + struct net_device *dev = qep->dev; struct qe_rxd *this; struct sunqe_buffers *qbufs = qep->buffers; __u32 qbufs_dvma = qep->buffers_dvma; @@ -428,14 +429,14 @@ static void qe_rx(struct sunqe *qep) /* Check for errors. */ if (len < ETH_ZLEN) { - qep->net_stats.rx_errors++; - qep->net_stats.rx_length_errors++; - qep->net_stats.rx_dropped++; + dev->stats.rx_errors++; + dev->stats.rx_length_errors++; + dev->stats.rx_dropped++; } else { skb = dev_alloc_skb(len + 2); if (skb == NULL) { drops++; - qep->net_stats.rx_dropped++; + dev->stats.rx_dropped++; } else { skb_reserve(skb, 2); skb_put(skb, len); @@ -444,8 +445,8 @@ static void qe_rx(struct sunqe *qep) skb->protocol = eth_type_trans(skb, qep->dev); netif_rx(skb); qep->dev->last_rx = jiffies; - qep->net_stats.rx_packets++; - qep->net_stats.rx_bytes += len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += len; } } end_rxd->rx_addr = this_qbuf_dvma; @@ -603,8 +604,8 @@ static int qe_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; sbus_writel(CREG_CTRL_TWAKEUP, qep->qcregs + CREG_CTRL); - qep->net_stats.tx_packets++; - qep->net_stats.tx_bytes += len; + dev->stats.tx_packets++; + dev->stats.tx_bytes += len; if (TX_BUFFS_AVAIL(qep) <= 0) { /* Halt the net queue and enable tx interrupts. @@ -622,13 +623,6 @@ static int qe_start_xmit(struct sk_buff *skb, struct net_device *dev) return 0; } -static struct net_device_stats *qe_get_stats(struct net_device *dev) -{ - struct sunqe *qep = (struct sunqe *) dev->priv; - - return &qep->net_stats; -} - static void qe_set_multicast(struct net_device *dev) { struct sunqe *qep = (struct sunqe *) dev->priv; @@ -903,7 +897,6 @@ static int __init qec_ether_init(struct sbus_dev *sdev) dev->open = qe_open; dev->stop = qe_close; dev->hard_start_xmit = qe_start_xmit; - dev->get_stats = qe_get_stats; dev->set_multicast_list = qe_set_multicast; dev->tx_timeout = qe_tx_timeout; dev->watchdog_timeo = 5*HZ; diff --git a/drivers/net/sunqe.h b/drivers/net/sunqe.h index af34f36111e..347c8ddc159 100644 --- a/drivers/net/sunqe.h +++ b/drivers/net/sunqe.h @@ -342,7 +342,6 @@ struct sunqe { __u32 buffers_dvma; /* DVMA visible address. */ struct sunqec *parent; u8 mconfig; /* Base MACE mconfig value */ - struct net_device_stats net_stats; /* Statistical counters */ struct sbus_dev *qe_sdev; /* QE's SBUS device struct */ struct net_device *dev; /* QE's netdevice struct */ int channel; /* Who am I? */ diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 8b3ec335385..d279151f065 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -110,7 +110,7 @@ static int tun_net_xmit(struct sk_buff *skb, struct net_device *dev) /* We won't see all dropped packets individually, so overrun * error is more appropriate. */ - tun->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; } else { /* Single queue mode. * Driver handles dropping of all packets itself. */ @@ -129,7 +129,7 @@ static int tun_net_xmit(struct sk_buff *skb, struct net_device *dev) return 0; drop: - tun->stats.tx_dropped++; + dev->stats.tx_dropped++; kfree_skb(skb); return 0; } @@ -172,12 +172,6 @@ tun_net_mclist(struct net_device *dev) } } -static struct net_device_stats *tun_net_stats(struct net_device *dev) -{ - struct tun_struct *tun = netdev_priv(dev); - return &tun->stats; -} - /* Initialize net device. */ static void tun_net_init(struct net_device *dev) { @@ -250,14 +244,14 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, struct iovec *iv, align = NET_IP_ALIGN; if (!(skb = alloc_skb(len + align, GFP_KERNEL))) { - tun->stats.rx_dropped++; + tun->dev->stats.rx_dropped++; return -ENOMEM; } if (align) skb_reserve(skb, align); if (memcpy_fromiovec(skb_put(skb, len), iv, len)) { - tun->stats.rx_dropped++; + tun->dev->stats.rx_dropped++; kfree_skb(skb); return -EFAULT; } @@ -279,8 +273,8 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, struct iovec *iv, netif_rx_ni(skb); tun->dev->last_rx = jiffies; - tun->stats.rx_packets++; - tun->stats.rx_bytes += len; + tun->dev->stats.rx_packets++; + tun->dev->stats.rx_bytes += len; return count; } @@ -336,8 +330,8 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun, skb_copy_datagram_iovec(skb, 0, iv, len); total += len; - tun->stats.tx_packets++; - tun->stats.tx_bytes += len; + tun->dev->stats.tx_packets++; + tun->dev->stats.tx_bytes += len; return total; } @@ -438,7 +432,6 @@ static void tun_setup(struct net_device *dev) dev->open = tun_net_open; dev->hard_start_xmit = tun_net_xmit; dev->stop = tun_net_close; - dev->get_stats = tun_net_stats; dev->ethtool_ops = &tun_ethtool_ops; dev->destructor = free_netdev; } diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 8da41229594..9667dac383f 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -3350,14 +3350,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) return 0; } -/* returns a net_device_stats structure pointer */ -static struct net_device_stats *ucc_geth_get_stats(struct net_device *dev) -{ - struct ucc_geth_private *ugeth = netdev_priv(dev); - - return &(ugeth->stats); -} - /* ucc_geth_timeout gets called when a packet has not been * transmitted after a set amount of time. * For now, assume that clearing out all the structures, and @@ -3368,7 +3360,7 @@ static void ucc_geth_timeout(struct net_device *dev) ugeth_vdbg("%s: IN", __FUNCTION__); - ugeth->stats.tx_errors++; + dev->stats.tx_errors++; ugeth_dump_regs(ugeth); @@ -3396,7 +3388,7 @@ static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_lock_irq(&ugeth->lock); - ugeth->stats.tx_bytes += skb->len; + dev->stats.tx_bytes += skb->len; /* Start from the next BD that should be filled */ bd = ugeth->txBd[txQ]; @@ -3488,9 +3480,9 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit dev_kfree_skb_any(skb); ugeth->rx_skbuff[rxQ][ugeth->skb_currx[rxQ]] = NULL; - ugeth->stats.rx_dropped++; + dev->stats.rx_dropped++; } else { - ugeth->stats.rx_packets++; + dev->stats.rx_packets++; howmany++; /* Prep the skb for the packet */ @@ -3499,7 +3491,7 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit /* Tell the skb what kind of packet this is */ skb->protocol = eth_type_trans(skb, ugeth->dev); - ugeth->stats.rx_bytes += length; + dev->stats.rx_bytes += length; /* Send the packet up the stack */ #ifdef CONFIG_UGETH_NAPI netif_receive_skb(skb); @@ -3514,7 +3506,7 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit if (!skb) { if (netif_msg_rx_err(ugeth)) ugeth_warn("%s: No Rx Data Buffer", __FUNCTION__); - ugeth->stats.rx_dropped++; + dev->stats.rx_dropped++; break; } @@ -3556,7 +3548,7 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ) if ((bd == ugeth->txBd[txQ]) && (netif_queue_stopped(dev) == 0)) break; - ugeth->stats.tx_packets++; + dev->stats.tx_packets++; /* Free the sk buffer associated with this TxBD */ dev_kfree_skb_irq(ugeth-> @@ -3673,10 +3665,10 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info) /* Errors and other events */ if (ucce & UCCE_OTHER) { if (ucce & UCCE_BSY) { - ugeth->stats.rx_errors++; + dev->stats.rx_errors++; } if (ucce & UCCE_TXE) { - ugeth->stats.tx_errors++; + dev->stats.tx_errors++; } } @@ -3969,7 +3961,6 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma netif_napi_add(dev, &ugeth->napi, ucc_geth_poll, UCC_GETH_DEV_WEIGHT); #endif /* CONFIG_UGETH_NAPI */ dev->stop = ucc_geth_close; - dev->get_stats = ucc_geth_get_stats; // dev->change_mtu = ucc_geth_change_mtu; dev->mtu = 1500; dev->set_multicast_list = ucc_geth_set_multi; diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h index 0579ba081aa..aaeb9487798 100644 --- a/drivers/net/ucc_geth.h +++ b/drivers/net/ucc_geth.h @@ -1185,7 +1185,6 @@ struct ucc_geth_private { struct ucc_fast_private *uccf; struct net_device *dev; struct napi_struct napi; - struct net_device_stats stats; /* linux network statistics */ struct ucc_geth *ug_regs; struct ucc_geth_init_pram *p_init_enet_param_shadow; struct ucc_geth_exf_global_pram *p_exf_glbl_param; diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 8eeb068dc4a..78e344ae705 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -73,7 +73,6 @@ struct netfront_info { struct net_device *netdev; struct napi_struct napi; - struct net_device_stats stats; struct xen_netif_tx_front_ring tx; struct xen_netif_rx_front_ring rx; @@ -309,8 +308,6 @@ static int xennet_open(struct net_device *dev) { struct netfront_info *np = netdev_priv(dev); - memset(&np->stats, 0, sizeof(np->stats)); - napi_enable(&np->napi); spin_lock_bh(&np->rx_lock); @@ -537,8 +534,8 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev) if (notify) notify_remote_via_irq(np->netdev->irq); - np->stats.tx_bytes += skb->len; - np->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; + dev->stats.tx_packets++; /* Note: It is not safe to access skb after xennet_tx_buf_gc()! */ xennet_tx_buf_gc(dev); @@ -551,7 +548,7 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev) return 0; drop: - np->stats.tx_dropped++; + dev->stats.tx_dropped++; dev_kfree_skb(skb); return 0; } @@ -564,12 +561,6 @@ static int xennet_close(struct net_device *dev) return 0; } -static struct net_device_stats *xennet_get_stats(struct net_device *dev) -{ - struct netfront_info *np = netdev_priv(dev); - return &np->stats; -} - static void xennet_move_rx_slot(struct netfront_info *np, struct sk_buff *skb, grant_ref_t ref) { @@ -804,9 +795,8 @@ out: } static int handle_incoming_queue(struct net_device *dev, - struct sk_buff_head *rxq) + struct sk_buff_head *rxq) { - struct netfront_info *np = netdev_priv(dev); int packets_dropped = 0; struct sk_buff *skb; @@ -828,13 +818,13 @@ static int handle_incoming_queue(struct net_device *dev, if (skb_checksum_setup(skb)) { kfree_skb(skb); packets_dropped++; - np->stats.rx_errors++; + dev->stats.rx_errors++; continue; } } - np->stats.rx_packets++; - np->stats.rx_bytes += skb->len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += skb->len; /* Pass it up. */ netif_receive_skb(skb); @@ -887,7 +877,7 @@ static int xennet_poll(struct napi_struct *napi, int budget) err: while ((skb = __skb_dequeue(&tmpq))) __skb_queue_tail(&errq, skb); - np->stats.rx_errors++; + dev->stats.rx_errors++; i = np->rx.rsp_cons; continue; } @@ -1169,7 +1159,6 @@ static struct net_device * __devinit xennet_create_dev(struct xenbus_device *dev netdev->open = xennet_open; netdev->hard_start_xmit = xennet_start_xmit; netdev->stop = xennet_close; - netdev->get_stats = xennet_get_stats; netif_napi_add(netdev, &np->napi, xennet_poll, 64); netdev->uninit = xennet_uninit; netdev->change_mtu = xennet_change_mtu; diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c index 29e96950be6..709623e1c61 100644 --- a/drivers/net/yellowfin.c +++ b/drivers/net/yellowfin.c @@ -318,7 +318,6 @@ struct yellowfin_private { dma_addr_t tx_status_dma; struct timer_list timer; /* Media selection timer. */ - struct net_device_stats stats; /* Frequently used and paired value: keep adjacent for cache effect. */ int chip_id, drv_flags; struct pci_dev *pci_dev; @@ -353,7 +352,6 @@ static irqreturn_t yellowfin_interrupt(int irq, void *dev_instance); static int yellowfin_rx(struct net_device *dev); static void yellowfin_error(struct net_device *dev, int intr_status); static int yellowfin_close(struct net_device *dev); -static struct net_device_stats *yellowfin_get_stats(struct net_device *dev); static void set_rx_mode(struct net_device *dev); static const struct ethtool_ops ethtool_ops; @@ -469,7 +467,6 @@ static int __devinit yellowfin_init_one(struct pci_dev *pdev, dev->open = &yellowfin_open; dev->hard_start_xmit = &yellowfin_start_xmit; dev->stop = &yellowfin_close; - dev->get_stats = &yellowfin_get_stats; dev->set_multicast_list = &set_rx_mode; dev->do_ioctl = &netdev_ioctl; SET_ETHTOOL_OPS(dev, ðtool_ops); @@ -717,7 +714,7 @@ static void yellowfin_tx_timeout(struct net_device *dev) netif_wake_queue (dev); /* Typical path */ dev->trans_start = jiffies; - yp->stats.tx_errors++; + dev->stats.tx_errors++; } /* Initialize the Rx and Tx rings, along with various 'dev' bits. */ @@ -923,8 +920,8 @@ static irqreturn_t yellowfin_interrupt(int irq, void *dev_instance) if (yp->tx_ring[entry].result_status == 0) break; skb = yp->tx_skbuff[entry]; - yp->stats.tx_packets++; - yp->stats.tx_bytes += skb->len; + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; /* Free the original skb. */ pci_unmap_single(yp->pci_dev, yp->tx_ring[entry].addr, skb->len, PCI_DMA_TODEVICE); @@ -968,20 +965,20 @@ static irqreturn_t yellowfin_interrupt(int irq, void *dev_instance) printk(KERN_DEBUG "%s: Transmit error, Tx status %4.4x.\n", dev->name, tx_errs); #endif - yp->stats.tx_errors++; - if (tx_errs & 0xF800) yp->stats.tx_aborted_errors++; - if (tx_errs & 0x0800) yp->stats.tx_carrier_errors++; - if (tx_errs & 0x2000) yp->stats.tx_window_errors++; - if (tx_errs & 0x8000) yp->stats.tx_fifo_errors++; + dev->stats.tx_errors++; + if (tx_errs & 0xF800) dev->stats.tx_aborted_errors++; + if (tx_errs & 0x0800) dev->stats.tx_carrier_errors++; + if (tx_errs & 0x2000) dev->stats.tx_window_errors++; + if (tx_errs & 0x8000) dev->stats.tx_fifo_errors++; } else { #ifndef final_version if (yellowfin_debug > 4) printk(KERN_DEBUG "%s: Normal transmit, Tx status %4.4x.\n", dev->name, tx_errs); #endif - yp->stats.tx_bytes += skb->len; - yp->stats.collisions += tx_errs & 15; - yp->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; + dev->stats.collisions += tx_errs & 15; + dev->stats.tx_packets++; } /* Free the original skb. */ pci_unmap_single(yp->pci_dev, @@ -1076,26 +1073,26 @@ static int yellowfin_rx(struct net_device *dev) if (data_size != 0) printk(KERN_WARNING "%s: Oversized Ethernet frame spanned multiple buffers," " status %4.4x, data_size %d!\n", dev->name, desc_status, data_size); - yp->stats.rx_length_errors++; + dev->stats.rx_length_errors++; } else if ((yp->drv_flags & IsGigabit) && (frame_status & 0x0038)) { /* There was a error. */ if (yellowfin_debug > 3) printk(KERN_DEBUG " yellowfin_rx() Rx error was %4.4x.\n", frame_status); - yp->stats.rx_errors++; - if (frame_status & 0x0060) yp->stats.rx_length_errors++; - if (frame_status & 0x0008) yp->stats.rx_frame_errors++; - if (frame_status & 0x0010) yp->stats.rx_crc_errors++; - if (frame_status < 0) yp->stats.rx_dropped++; + dev->stats.rx_errors++; + if (frame_status & 0x0060) dev->stats.rx_length_errors++; + if (frame_status & 0x0008) dev->stats.rx_frame_errors++; + if (frame_status & 0x0010) dev->stats.rx_crc_errors++; + if (frame_status < 0) dev->stats.rx_dropped++; } else if ( !(yp->drv_flags & IsGigabit) && ((buf_addr[data_size-1] & 0x85) || buf_addr[data_size-2] & 0xC0)) { u8 status1 = buf_addr[data_size-2]; u8 status2 = buf_addr[data_size-1]; - yp->stats.rx_errors++; - if (status1 & 0xC0) yp->stats.rx_length_errors++; - if (status2 & 0x03) yp->stats.rx_frame_errors++; - if (status2 & 0x04) yp->stats.rx_crc_errors++; - if (status2 & 0x80) yp->stats.rx_dropped++; + dev->stats.rx_errors++; + if (status1 & 0xC0) dev->stats.rx_length_errors++; + if (status2 & 0x03) dev->stats.rx_frame_errors++; + if (status2 & 0x04) dev->stats.rx_crc_errors++; + if (status2 & 0x80) dev->stats.rx_dropped++; #ifdef YF_PROTOTYPE /* Support for prototype hardware errata. */ } else if ((yp->flags & HasMACAddrBug) && memcmp(le32_to_cpu(yp->rx_ring_dma + @@ -1145,8 +1142,8 @@ static int yellowfin_rx(struct net_device *dev) skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; - yp->stats.rx_packets++; - yp->stats.rx_bytes += pkt_len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; } entry = (++yp->cur_rx) % RX_RING_SIZE; } @@ -1180,15 +1177,13 @@ static int yellowfin_rx(struct net_device *dev) static void yellowfin_error(struct net_device *dev, int intr_status) { - struct yellowfin_private *yp = netdev_priv(dev); - printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n", dev->name, intr_status); /* Hmmmmm, it's not clear what to do here. */ if (intr_status & (IntrTxPCIErr | IntrTxPCIFault)) - yp->stats.tx_errors++; + dev->stats.tx_errors++; if (intr_status & (IntrRxPCIErr | IntrRxPCIFault)) - yp->stats.rx_errors++; + dev->stats.rx_errors++; } static int yellowfin_close(struct net_device *dev) @@ -1280,12 +1275,6 @@ static int yellowfin_close(struct net_device *dev) return 0; } -static struct net_device_stats *yellowfin_get_stats(struct net_device *dev) -{ - struct yellowfin_private *yp = netdev_priv(dev); - return &yp->stats; -} - /* Set or clear the multicast filter for this adaptor. */ static void set_rx_mode(struct net_device *dev) diff --git a/drivers/net/znet.c b/drivers/net/znet.c index dcd4e1b136b..43712c7b9ec 100644 --- a/drivers/net/znet.c +++ b/drivers/net/znet.c @@ -128,7 +128,6 @@ MODULE_LICENSE("GPL"); struct znet_private { int rx_dma, tx_dma; - struct net_device_stats stats; spinlock_t lock; short sia_base, sia_size, io_size; struct i82593_conf_block i593_init; @@ -161,7 +160,6 @@ static int znet_send_packet(struct sk_buff *skb, struct net_device *dev); static irqreturn_t znet_interrupt(int irq, void *dev_id); static void znet_rx(struct net_device *dev); static int znet_close(struct net_device *dev); -static struct net_device_stats *net_get_stats(struct net_device *dev); static void hardware_init(struct net_device *dev); static void update_stop_hit(short ioaddr, unsigned short rx_stop_offset); static void znet_tx_timeout (struct net_device *dev); @@ -445,7 +443,6 @@ static int __init znet_probe (void) dev->open = &znet_open; dev->hard_start_xmit = &znet_send_packet; dev->stop = &znet_close; - dev->get_stats = net_get_stats; dev->set_multicast_list = &znet_set_multicast_list; dev->tx_timeout = znet_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; @@ -564,7 +561,7 @@ static int znet_send_packet(struct sk_buff *skb, struct net_device *dev) ushort *tx_link = znet->tx_cur - 1; ushort rnd_len = (length + 1)>>1; - znet->stats.tx_bytes+=length; + dev->stats.tx_bytes+=length; if (znet->tx_cur >= znet->tx_end) znet->tx_cur = znet->tx_start; @@ -639,20 +636,20 @@ static irqreturn_t znet_interrupt(int irq, void *dev_id) tx_status = inw(ioaddr); /* It's undocumented, but tx_status seems to match the i82586. */ if (tx_status & TX_OK) { - znet->stats.tx_packets++; - znet->stats.collisions += tx_status & TX_NCOL_MASK; + dev->stats.tx_packets++; + dev->stats.collisions += tx_status & TX_NCOL_MASK; } else { if (tx_status & (TX_LOST_CTS | TX_LOST_CRS)) - znet->stats.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; if (tx_status & TX_UND_RUN) - znet->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; if (!(tx_status & TX_HRT_BEAT)) - znet->stats.tx_heartbeat_errors++; + dev->stats.tx_heartbeat_errors++; if (tx_status & TX_MAX_COL) - znet->stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; /* ...and the catch-all. */ if ((tx_status | (TX_LOST_CRS | TX_LOST_CTS | TX_UND_RUN | TX_HRT_BEAT | TX_MAX_COL)) != (TX_LOST_CRS | TX_LOST_CTS | TX_UND_RUN | TX_HRT_BEAT | TX_MAX_COL)) - znet->stats.tx_errors++; + dev->stats.tx_errors++; /* Transceiver may be stuck if cable * was removed while emiting a @@ -748,19 +745,19 @@ static void znet_rx(struct net_device *dev) this_rfp_ptr[-3]<<1); /* Once again we must assume that the i82586 docs apply. */ if ( ! (status & RX_RCV_OK)) { /* There was an error. */ - znet->stats.rx_errors++; - if (status & RX_CRC_ERR) znet->stats.rx_crc_errors++; - if (status & RX_ALG_ERR) znet->stats.rx_frame_errors++; + dev->stats.rx_errors++; + if (status & RX_CRC_ERR) dev->stats.rx_crc_errors++; + if (status & RX_ALG_ERR) dev->stats.rx_frame_errors++; #if 0 - if (status & 0x0200) znet->stats.rx_over_errors++; /* Wrong. */ - if (status & 0x0100) znet->stats.rx_fifo_errors++; + if (status & 0x0200) dev->stats.rx_over_errors++; /* Wrong. */ + if (status & 0x0100) dev->stats.rx_fifo_errors++; #else /* maz : Wild guess... */ - if (status & RX_OVRRUN) znet->stats.rx_over_errors++; + if (status & RX_OVRRUN) dev->stats.rx_over_errors++; #endif - if (status & RX_SRT_FRM) znet->stats.rx_length_errors++; + if (status & RX_SRT_FRM) dev->stats.rx_length_errors++; } else if (pkt_len > 1536) { - znet->stats.rx_length_errors++; + dev->stats.rx_length_errors++; } else { /* Malloc up new buffer. */ struct sk_buff *skb; @@ -769,7 +766,7 @@ static void znet_rx(struct net_device *dev) if (skb == NULL) { if (znet_debug) printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name); - znet->stats.rx_dropped++; + dev->stats.rx_dropped++; break; } @@ -789,8 +786,8 @@ static void znet_rx(struct net_device *dev) skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); dev->last_rx = jiffies; - znet->stats.rx_packets++; - znet->stats.rx_bytes += pkt_len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; } znet->rx_cur = this_rfp_ptr; if (znet->rx_cur >= znet->rx_end) @@ -827,15 +824,6 @@ static int znet_close(struct net_device *dev) return 0; } -/* Get the current statistics. This may be called with the card open or - closed. */ -static struct net_device_stats *net_get_stats(struct net_device *dev) -{ - struct znet_private *znet = dev->priv; - - return &znet->stats; -} - static void show_dma(struct net_device *dev) { short ioaddr = dev->base_addr; diff --git a/include/linux/if_eql.h b/include/linux/if_eql.h index b68752fdc5c..79c4f268410 100644 --- a/include/linux/if_eql.h +++ b/include/linux/if_eql.h @@ -58,7 +58,6 @@ typedef struct equalizer { slave_queue_t queue; int min_slaves; int max_slaves; - struct net_device_stats stats; struct timer_list timer; } equalizer_t; diff --git a/include/linux/if_shaper.h b/include/linux/if_shaper.h index 68c896a36a3..51574743aa1 100644 --- a/include/linux/if_shaper.h +++ b/include/linux/if_shaper.h @@ -24,7 +24,6 @@ struct shaper unsigned long recovery; /* Time we can next clock a packet out on an empty queue */ spinlock_t lock; - struct net_device_stats stats; struct net_device *dev; int (*hard_start_xmit) (struct sk_buff *skb, struct net_device *dev); diff --git a/include/linux/if_tun.h b/include/linux/if_tun.h index 42eb6945b93..33e489d5bb3 100644 --- a/include/linux/if_tun.h +++ b/include/linux/if_tun.h @@ -42,7 +42,6 @@ struct tun_struct { struct sk_buff_head readq; struct net_device *dev; - struct net_device_stats stats; struct fasync_struct *fasync; -- cgit v1.2.3-70-g09d2 From 88d3aafdae5c5e1d2dd9489a5c8a24e29d335f2e Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Sat, 15 Sep 2007 14:41:06 -0700 Subject: [ETHTOOL] Provide default behaviors for a few ethtool sub-ioctls For the operations get-tx-csum get-sg get-tso get-ufo the default ethtool_op_xxx behavior is fine for all drivers, so we permit op==NULL to imply the default behavior. This provides a more uniform behavior across all drivers, eliminating ethtool(8) "ioctl not supported" errors on older drivers that had not been updated for the latest sub-ioctls. The ethtool_op_xxx() functions are left exported, in case anyone wishes to call them directly from a driver-private implementation -- a not-uncommon case. Should an ethtool_op_xxx() helper remain unused for a while, except by net/core/ethtool.c, we can un-export it at a later date. [ Resolved conflicts with set/get value ethtool patch... -DaveM ] Signed-off-by: Jeff Garzik Signed-off-by: David S. Miller --- drivers/net/8139cp.c | 3 --- drivers/net/atl1/atl1_ethtool.c | 3 --- drivers/net/bnx2.c | 3 --- drivers/net/bonding/bond_main.c | 4 ---- drivers/net/chelsio/cxgb2.c | 3 --- drivers/net/cxgb3/cxgb3_main.c | 3 --- drivers/net/e1000/e1000_ethtool.c | 2 -- drivers/net/ehea/ehea_ethtool.c | 3 --- drivers/net/epic100.c | 2 -- drivers/net/fealnx.c | 2 -- drivers/net/fec_8xx/fec_main.c | 2 -- drivers/net/forcedeth.c | 3 --- drivers/net/fs_enet/fs_enet-main.c | 2 -- drivers/net/ibm_emac/ibm_emac_core.c | 2 -- drivers/net/ibmveth.c | 6 +----- drivers/net/ixgb/ixgb_ethtool.c | 2 -- drivers/net/loopback.c | 1 - drivers/net/macvlan.c | 4 ---- drivers/net/mv643xx_eth.c | 1 - drivers/net/myri10ge/myri10ge.c | 3 --- drivers/net/ne2k-pci.c | 2 -- drivers/net/netxen/netxen_nic_ethtool.c | 3 --- drivers/net/pcnet32.c | 3 --- drivers/net/r8169.c | 3 --- drivers/net/s2io.c | 3 --- drivers/net/sc92031.c | 4 ---- drivers/net/skge.c | 2 -- drivers/net/sky2.c | 3 --- drivers/net/spider_net_ethtool.c | 1 - drivers/net/tg3.c | 3 --- drivers/net/tulip/de2104x.c | 2 -- drivers/net/tulip/winbond-840.c | 2 -- drivers/net/typhoon.c | 3 --- drivers/net/ucc_geth_ethtool.c | 2 -- drivers/net/via-rhine.c | 2 -- drivers/net/xen-netfront.c | 3 --- net/bridge/br_device.c | 3 --- net/core/ethtool.c | 16 ++++++++++++---- 38 files changed, 13 insertions(+), 101 deletions(-) (limited to 'drivers') diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index 30310ed9f75..58fad1b2f72 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -1572,11 +1572,8 @@ static const struct ethtool_ops cp_ethtool_ops = { .set_msglevel = cp_set_msglevel, .get_rx_csum = cp_get_rx_csum, .set_rx_csum = cp_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, .set_tx_csum = ethtool_op_set_tx_csum, /* local! */ - .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, .set_tso = ethtool_op_set_tso, .get_regs = cp_get_regs, .get_wol = cp_get_wol, diff --git a/drivers/net/atl1/atl1_ethtool.c b/drivers/net/atl1/atl1_ethtool.c index 1f616c5c147..53353b60a9c 100644 --- a/drivers/net/atl1/atl1_ethtool.c +++ b/drivers/net/atl1/atl1_ethtool.c @@ -489,15 +489,12 @@ const struct ethtool_ops atl1_ethtool_ops = { .get_pauseparam = atl1_get_pauseparam, .set_pauseparam = atl1_set_pauseparam, .get_rx_csum = atl1_get_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, .set_tx_csum = ethtool_op_set_tx_hw_csum, .get_link = ethtool_op_get_link, - .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, .get_strings = atl1_get_strings, .nway_reset = atl1_nway_reset, .get_ethtool_stats = atl1_get_ethtool_stats, .get_stats_count = atl1_get_stats_count, - .get_tso = ethtool_op_get_tso, .set_tso = ethtool_op_set_tso, }; diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index f1e7204f78c..5ee805b3e0e 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -6257,11 +6257,8 @@ static const struct ethtool_ops bnx2_ethtool_ops = { .set_pauseparam = bnx2_set_pauseparam, .get_rx_csum = bnx2_get_rx_csum, .set_rx_csum = bnx2_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, .set_tx_csum = bnx2_set_tx_csum, - .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, .set_tso = bnx2_set_tso, .self_test_count = bnx2_self_test_count, .self_test = bnx2_self_test, diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 88ff72ac9b0..ea58144c220 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4202,10 +4202,6 @@ static void bond_ethtool_get_drvinfo(struct net_device *bond_dev, } static const struct ethtool_ops bond_ethtool_ops = { - .get_tx_csum = ethtool_op_get_tx_csum, - .get_tso = ethtool_op_get_tso, - .get_ufo = ethtool_op_get_ufo, - .get_sg = ethtool_op_get_sg, .get_drvinfo = bond_ethtool_get_drvinfo, }; diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c index 884aa0cd000..7029f13d008 100644 --- a/drivers/net/chelsio/cxgb2.c +++ b/drivers/net/chelsio/cxgb2.c @@ -794,9 +794,7 @@ static const struct ethtool_ops t1_ethtool_ops = { .set_pauseparam = set_pauseparam, .get_rx_csum = get_rx_csum, .set_rx_csum = set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, .set_tx_csum = ethtool_op_set_tx_csum, - .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, .get_link = ethtool_op_get_link, .get_strings = get_strings, @@ -804,7 +802,6 @@ static const struct ethtool_ops t1_ethtool_ops = { .get_ethtool_stats = get_stats, .get_regs_len = get_regs_len, .get_regs = get_regs, - .get_tso = ethtool_op_get_tso, .set_tso = set_tso, }; diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index 19937498589..04633ea5520 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -1634,9 +1634,7 @@ static const struct ethtool_ops cxgb_ethtool_ops = { .set_pauseparam = set_pauseparam, .get_rx_csum = get_rx_csum, .set_rx_csum = set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, .set_tx_csum = ethtool_op_set_tx_csum, - .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, .get_link = ethtool_op_get_link, .get_strings = get_strings, @@ -1647,7 +1645,6 @@ static const struct ethtool_ops cxgb_ethtool_ops = { .get_regs_len = get_regs_len, .get_regs = get_regs, .get_wol = get_wol, - .get_tso = ethtool_op_get_tso, .set_tso = ethtool_op_set_tso, }; diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index 76d16aaf05b..e6c4a3bb9e4 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -1965,9 +1965,7 @@ static const struct ethtool_ops e1000_ethtool_ops = { .set_rx_csum = e1000_set_rx_csum, .get_tx_csum = e1000_get_tx_csum, .set_tx_csum = e1000_set_tx_csum, - .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, .set_tso = e1000_set_tso, .self_test_count = e1000_diag_test_count, .self_test = e1000_diag_test, diff --git a/drivers/net/ehea/ehea_ethtool.c b/drivers/net/ehea/ehea_ethtool.c index 29ef7a98f8b..6498455bf97 100644 --- a/drivers/net/ehea/ehea_ethtool.c +++ b/drivers/net/ehea/ehea_ethtool.c @@ -262,9 +262,6 @@ const struct ethtool_ops ehea_ethtool_ops = { .get_msglevel = ehea_get_msglevel, .set_msglevel = ehea_set_msglevel, .get_link = ethtool_op_get_link, - .get_tx_csum = ethtool_op_get_tx_csum, - .get_sg = ethtool_op_get_sg, - .get_tso = ethtool_op_get_tso, .set_tso = ethtool_op_set_tso, .get_strings = ehea_get_strings, .get_stats_count = ehea_get_stats_count, diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index 122ffd2f082..5ac56f20003 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -1494,8 +1494,6 @@ static const struct ethtool_ops netdev_ethtool_ops = { .get_link = netdev_get_link, .get_msglevel = netdev_get_msglevel, .set_msglevel = netdev_set_msglevel, - .get_sg = ethtool_op_get_sg, - .get_tx_csum = ethtool_op_get_tx_csum, .begin = ethtool_begin, .complete = ethtool_complete }; diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c index e9353072a96..402b071d8d5 100644 --- a/drivers/net/fealnx.c +++ b/drivers/net/fealnx.c @@ -1891,8 +1891,6 @@ static const struct ethtool_ops netdev_ethtool_ops = { .get_link = netdev_get_link, .get_msglevel = netdev_get_msglevel, .set_msglevel = netdev_set_msglevel, - .get_sg = ethtool_op_get_sg, - .get_tx_csum = ethtool_op_get_tx_csum, }; static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) diff --git a/drivers/net/fec_8xx/fec_main.c b/drivers/net/fec_8xx/fec_main.c index 6f214ab12ff..8d2904fa578 100644 --- a/drivers/net/fec_8xx/fec_main.c +++ b/drivers/net/fec_8xx/fec_main.c @@ -1041,9 +1041,7 @@ static const struct ethtool_ops fec_ethtool_ops = { .get_link = ethtool_op_get_link, .get_msglevel = fec_get_msglevel, .set_msglevel = fec_set_msglevel, - .get_tx_csum = ethtool_op_get_tx_csum, .set_tx_csum = ethtool_op_set_tx_csum, /* local! */ - .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, .get_regs = fec_get_regs, }; diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 050a8f14eda..be744573b1c 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -4710,7 +4710,6 @@ static const struct ethtool_ops ops = { .get_regs_len = nv_get_regs_len, .get_regs = nv_get_regs, .nway_reset = nv_nway_reset, - .get_tso = ethtool_op_get_tso, .set_tso = nv_set_tso, .get_ringparam = nv_get_ringparam, .set_ringparam = nv_set_ringparam, @@ -4718,9 +4717,7 @@ static const struct ethtool_ops ops = { .set_pauseparam = nv_set_pauseparam, .get_rx_csum = nv_get_rx_csum, .set_rx_csum = nv_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, .set_tx_csum = nv_set_tx_csum, - .get_sg = ethtool_op_get_sg, .set_sg = nv_set_sg, .get_strings = nv_get_strings, .get_stats_count = nv_get_stats_count, diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index f6789a8db8c..f9079599dd2 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -907,9 +907,7 @@ static const struct ethtool_ops fs_ethtool_ops = { .get_link = ethtool_op_get_link, .get_msglevel = fs_get_msglevel, .set_msglevel = fs_set_msglevel, - .get_tx_csum = ethtool_op_get_tx_csum, .set_tx_csum = ethtool_op_set_tx_csum, /* local! */ - .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, .get_regs = fs_get_regs, }; diff --git a/drivers/net/ibm_emac/ibm_emac_core.c b/drivers/net/ibm_emac/ibm_emac_core.c index 354616b0b57..d7da56b105c 100644 --- a/drivers/net/ibm_emac/ibm_emac_core.c +++ b/drivers/net/ibm_emac/ibm_emac_core.c @@ -1900,8 +1900,6 @@ static const struct ethtool_ops emac_ethtool_ops = { .get_ethtool_stats = emac_ethtool_get_ethtool_stats, .get_link = ethtool_op_get_link, - .get_tx_csum = ethtool_op_get_tx_csum, - .get_sg = ethtool_op_get_sg, }; static int emac_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index bdbf3dead4e..0636883449f 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -821,15 +821,11 @@ static const struct ethtool_ops netdev_ethtool_ops = { .get_drvinfo = netdev_get_drvinfo, .get_settings = netdev_get_settings, .get_link = netdev_get_link, - .get_sg = ethtool_op_get_sg, - .get_tx_csum = ethtool_op_get_tx_csum, .set_tx_csum = ibmveth_set_tx_csum, .get_rx_csum = ibmveth_get_rx_csum, .set_rx_csum = ibmveth_set_rx_csum, - .get_tso = ethtool_op_get_tso, - .get_ufo = ethtool_op_get_ufo, .get_strings = ibmveth_get_strings, - .get_stats_count = ibmveth_get_stats_count, + .get_stats_count = ibmveth_get_stats_count, .get_ethtool_stats = ibmveth_get_ethtool_stats, }; diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c index 21d35bc5390..181b59dc1ac 100644 --- a/drivers/net/ixgb/ixgb_ethtool.c +++ b/drivers/net/ixgb/ixgb_ethtool.c @@ -713,11 +713,9 @@ static const struct ethtool_ops ixgb_ethtool_ops = { .set_rx_csum = ixgb_set_rx_csum, .get_tx_csum = ixgb_get_tx_csum, .set_tx_csum = ixgb_set_tx_csum, - .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, .get_msglevel = ixgb_get_msglevel, .set_msglevel = ixgb_set_msglevel, - .get_tso = ethtool_op_get_tso, .set_tso = ixgb_set_tso, .get_strings = ixgb_get_strings, .phys_id = ixgb_phys_id, diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index a328da72833..0e2252fd71a 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -192,7 +192,6 @@ static u32 always_on(struct net_device *dev) static const struct ethtool_ops loopback_ethtool_ops = { .get_link = always_on, - .get_tso = ethtool_op_get_tso, .set_tso = ethtool_op_set_tso, .get_tx_csum = always_on, .get_sg = always_on, diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 2de073da182..2f6cdaa8872 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -282,10 +282,6 @@ static u32 macvlan_ethtool_get_rx_csum(struct net_device *dev) static const struct ethtool_ops macvlan_ethtool_ops = { .get_link = ethtool_op_get_link, .get_rx_csum = macvlan_ethtool_get_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, - .get_tso = ethtool_op_get_tso, - .get_ufo = ethtool_op_get_ufo, - .get_sg = ethtool_op_get_sg, .get_drvinfo = macvlan_ethtool_get_drvinfo, }; diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 35781616eb2..34df02cfdbe 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -2735,7 +2735,6 @@ static const struct ethtool_ops mv643xx_ethtool_ops = { .set_settings = mv643xx_set_settings, .get_drvinfo = mv643xx_get_drvinfo, .get_link = mv643xx_eth_get_link, - .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, .get_stats_count = mv643xx_get_stats_count, .get_ethtool_stats = mv643xx_get_ethtool_stats, diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 6dc28b82493..2f8864e70ca 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -1499,11 +1499,8 @@ static const struct ethtool_ops myri10ge_ethtool_ops = { .get_ringparam = myri10ge_get_ringparam, .get_rx_csum = myri10ge_get_rx_csum, .set_rx_csum = myri10ge_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, .set_tx_csum = ethtool_op_set_tx_hw_csum, - .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, .set_tso = ethtool_op_set_tso, .get_link = ethtool_op_get_link, .get_strings = myri10ge_get_strings, diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c index 7ec362b2e3e..a5879672903 100644 --- a/drivers/net/ne2k-pci.c +++ b/drivers/net/ne2k-pci.c @@ -635,8 +635,6 @@ static void ne2k_pci_get_drvinfo(struct net_device *dev, static const struct ethtool_ops ne2k_pci_ethtool_ops = { .get_drvinfo = ne2k_pci_get_drvinfo, - .get_tx_csum = ethtool_op_get_tx_csum, - .get_sg = ethtool_op_get_sg, }; static void __devexit ne2k_pci_remove_one (struct pci_dev *pdev) diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index a6138b474b4..08c76b34366 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c @@ -744,11 +744,8 @@ struct ethtool_ops netxen_nic_ethtool_ops = { .get_ringparam = netxen_nic_get_ringparam, .get_pauseparam = netxen_nic_get_pauseparam, .set_pauseparam = netxen_nic_set_pauseparam, - .get_tx_csum = ethtool_op_get_tx_csum, .set_tx_csum = ethtool_op_set_tx_csum, - .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, .set_tso = ethtool_op_set_tso, .self_test_count = netxen_nic_diag_test_count, .self_test = netxen_nic_diag_test, diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 724d90bd1fe..4840ddea71a 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -1509,9 +1509,6 @@ static const struct ethtool_ops pcnet32_ethtool_ops = { .get_link = pcnet32_get_link, .get_ringparam = pcnet32_get_ringparam, .set_ringparam = pcnet32_set_ringparam, - .get_tx_csum = ethtool_op_get_tx_csum, - .get_sg = ethtool_op_get_sg, - .get_tso = ethtool_op_get_tso, .get_strings = pcnet32_get_strings, .self_test_count = pcnet32_self_test_count, .self_test = pcnet32_ethtool_test, diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index b8809a8ef20..06a1a6f2d17 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -1061,11 +1061,8 @@ static const struct ethtool_ops rtl8169_ethtool_ops = { .set_msglevel = rtl8169_set_msglevel, .get_rx_csum = rtl8169_get_rx_csum, .set_rx_csum = rtl8169_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, .set_tx_csum = ethtool_op_set_tx_csum, - .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, .set_tso = ethtool_op_set_tso, .get_regs = rtl8169_get_regs, .get_wol = rtl8169_get_wol, diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index f77049b34e1..a285dd734a0 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -6326,13 +6326,10 @@ static const struct ethtool_ops netdev_ethtool_ops = { .set_pauseparam = s2io_ethtool_setpause_data, .get_rx_csum = s2io_ethtool_get_rx_csum, .set_rx_csum = s2io_ethtool_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, .set_tx_csum = s2io_ethtool_op_set_tx_csum, - .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, .get_tso = s2io_ethtool_op_get_tso, .set_tso = s2io_ethtool_op_set_tso, - .get_ufo = ethtool_op_get_ufo, .set_ufo = ethtool_op_set_ufo, .self_test_count = s2io_ethtool_self_test_count, .self_test = s2io_ethtool_test, diff --git a/drivers/net/sc92031.c b/drivers/net/sc92031.c index 872cb1cc9c4..02c472ecbe5 100644 --- a/drivers/net/sc92031.c +++ b/drivers/net/sc92031.c @@ -1396,13 +1396,9 @@ static struct ethtool_ops sc92031_ethtool_ops = { .set_wol = sc92031_ethtool_set_wol, .nway_reset = sc92031_ethtool_nway_reset, .get_link = ethtool_op_get_link, - .get_tx_csum = ethtool_op_get_tx_csum, - .get_sg = ethtool_op_get_sg, - .get_tso = ethtool_op_get_tso, .get_strings = sc92031_ethtool_get_strings, .get_stats_count = sc92031_ethtool_get_stats_count, .get_ethtool_stats = sc92031_ethtool_get_ethtool_stats, - .get_ufo = ethtool_op_get_ufo, }; static int __devinit sc92031_probe(struct pci_dev *pdev, diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 47a144d000d..cac499f8413 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -811,9 +811,7 @@ static const struct ethtool_ops skge_ethtool_ops = { .set_pauseparam = skge_set_pauseparam, .get_coalesce = skge_get_coalesce, .set_coalesce = skge_set_coalesce, - .get_sg = ethtool_op_get_sg, .set_sg = skge_set_sg, - .get_tx_csum = ethtool_op_get_tx_csum, .set_tx_csum = skge_set_tx_csum, .get_rx_csum = skge_get_rx_csum, .set_rx_csum = skge_set_rx_csum, diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 1b9e5f40dde..b8c15f881eb 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -3710,11 +3710,8 @@ static const struct ethtool_ops sky2_ethtool_ops = { .get_eeprom_len = sky2_get_eeprom_len, .get_eeprom = sky2_get_eeprom, .set_eeprom = sky2_set_eeprom, - .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, - .get_tx_csum = ethtool_op_get_tx_csum, .set_tx_csum = sky2_set_tx_csum, - .get_tso = ethtool_op_get_tso, .set_tso = sky2_set_tso, .get_rx_csum = sky2_get_rx_csum, .set_rx_csum = sky2_set_rx_csum, diff --git a/drivers/net/spider_net_ethtool.c b/drivers/net/spider_net_ethtool.c index d940474e024..1460d5006d1 100644 --- a/drivers/net/spider_net_ethtool.c +++ b/drivers/net/spider_net_ethtool.c @@ -188,7 +188,6 @@ const struct ethtool_ops spider_net_ethtool_ops = { .nway_reset = spider_net_ethtool_nway_reset, .get_rx_csum = spider_net_ethtool_get_rx_csum, .set_rx_csum = spider_net_ethtool_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, .set_tx_csum = ethtool_op_set_tx_csum, .get_ringparam = spider_net_ethtool_get_ringparam, .get_strings = spider_net_get_strings, diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 369a172a04a..1b860e0817f 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -9278,11 +9278,8 @@ static const struct ethtool_ops tg3_ethtool_ops = { .set_pauseparam = tg3_set_pauseparam, .get_rx_csum = tg3_get_rx_csum, .set_rx_csum = tg3_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, .set_tx_csum = tg3_set_tx_csum, - .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, .set_tso = tg3_set_tso, .self_test_count = tg3_get_test_count, .self_test = tg3_self_test, diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index bd04e93908e..ba3d0e5574a 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -1670,8 +1670,6 @@ static void de_get_regs(struct net_device *dev, struct ethtool_regs *regs, static const struct ethtool_ops de_ethtool_ops = { .get_link = ethtool_op_get_link, - .get_tx_csum = ethtool_op_get_tx_csum, - .get_sg = ethtool_op_get_sg, .get_drvinfo = de_get_drvinfo, .get_regs_len = de_get_regs_len, .get_settings = de_get_settings, diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c index 396f8455cd3..e00833fadc0 100644 --- a/drivers/net/tulip/winbond-840.c +++ b/drivers/net/tulip/winbond-840.c @@ -1451,8 +1451,6 @@ static const struct ethtool_ops netdev_ethtool_ops = { .get_link = netdev_get_link, .get_msglevel = netdev_get_msglevel, .set_msglevel = netdev_set_msglevel, - .get_sg = ethtool_op_get_sg, - .get_tx_csum = ethtool_op_get_tx_csum, }; static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index 84d99fc7789..c6d8513ecad 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -1236,11 +1236,8 @@ static const struct ethtool_ops typhoon_ethtool_ops = { .set_wol = typhoon_set_wol, .get_link = ethtool_op_get_link, .get_rx_csum = typhoon_get_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, .set_tx_csum = ethtool_op_set_tx_csum, - .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, .set_tso = ethtool_op_set_tso, .get_ringparam = typhoon_get_ringparam, }; diff --git a/drivers/net/ucc_geth_ethtool.c b/drivers/net/ucc_geth_ethtool.c index 64bef7c1236..73aa677a4a3 100644 --- a/drivers/net/ucc_geth_ethtool.c +++ b/drivers/net/ucc_geth_ethtool.c @@ -373,9 +373,7 @@ static const struct ethtool_ops uec_ethtool_ops = { .set_ringparam = uec_set_ringparam, .get_pauseparam = uec_get_pauseparam, .set_pauseparam = uec_set_pauseparam, - .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, .get_stats_count = uec_get_stats_count, .get_strings = uec_get_strings, .get_ethtool_stats = uec_get_ethtool_stats, diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index 987f5b937e3..d55c4fdff48 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -1813,8 +1813,6 @@ static const struct ethtool_ops netdev_ethtool_ops = { .set_msglevel = netdev_set_msglevel, .get_wol = rhine_get_wol, .set_wol = rhine_set_wol, - .get_sg = ethtool_op_get_sg, - .get_tx_csum = ethtool_op_get_tx_csum, }; static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 78e344ae705..f464b82c7d5 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -1617,11 +1617,8 @@ static void backend_changed(struct xenbus_device *dev, static struct ethtool_ops xennet_ethtool_ops = { - .get_tx_csum = ethtool_op_get_tx_csum, .set_tx_csum = ethtool_op_set_tx_csum, - .get_sg = ethtool_op_get_sg, .set_sg = xennet_set_sg, - .get_tso = ethtool_op_get_tso, .set_tso = xennet_set_tso, .get_link = ethtool_op_get_link, }; diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index f803e39eee2..c07bac5e3e1 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c @@ -150,11 +150,8 @@ static int br_set_tx_csum(struct net_device *dev, u32 data) static struct ethtool_ops br_ethtool_ops = { .get_drvinfo = br_getinfo, .get_link = ethtool_op_get_link, - .get_sg = ethtool_op_get_sg, .set_sg = br_set_sg, - .get_tx_csum = ethtool_op_get_tx_csum, .set_tx_csum = br_set_tx_csum, - .get_tso = ethtool_op_get_tso, .set_tso = br_set_tso, }; diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 0d0b13cc1dd..1163eb2256d 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -893,21 +893,27 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) break; case ETHTOOL_GTXCSUM: rc = ethtool_get_value(dev, useraddr, ethcmd, - dev->ethtool_ops->get_tx_csum); + (dev->ethtool_ops->get_tx_csum ? + dev->ethtool_ops->get_tx_csum : + ethtool_op_get_tx_csum)); break; case ETHTOOL_STXCSUM: rc = ethtool_set_tx_csum(dev, useraddr); break; case ETHTOOL_GSG: rc = ethtool_get_value(dev, useraddr, ethcmd, - dev->ethtool_ops->get_sg); + (dev->ethtool_ops->get_sg ? + dev->ethtool_ops->get_sg : + ethtool_op_get_sg)); break; case ETHTOOL_SSG: rc = ethtool_set_sg(dev, useraddr); break; case ETHTOOL_GTSO: rc = ethtool_get_value(dev, useraddr, ethcmd, - dev->ethtool_ops->get_tso); + (dev->ethtool_ops->get_tso ? + dev->ethtool_ops->get_tso : + ethtool_op_get_tso)); break; case ETHTOOL_STSO: rc = ethtool_set_tso(dev, useraddr); @@ -929,7 +935,9 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) break; case ETHTOOL_GUFO: rc = ethtool_get_value(dev, useraddr, ethcmd, - dev->ethtool_ops->get_ufo); + (dev->ethtool_ops->get_ufo ? + dev->ethtool_ops->get_ufo : + ethtool_op_get_ufo)); break; case ETHTOOL_SUFO: rc = ethtool_set_ufo(dev, useraddr); -- cgit v1.2.3-70-g09d2 From 4885a50476b95fa0f4caad179a80783508c2fe86 Mon Sep 17 00:00:00 2001 From: Ed Swierk Date: Sun, 16 Sep 2007 12:21:38 -0700 Subject: [TAP]: Configurable interface MTU. Signed-off-by: David S. Miller --- drivers/net/tun.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/net/tun.c b/drivers/net/tun.c index d279151f065..d8b8e68ef70 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -172,6 +172,18 @@ tun_net_mclist(struct net_device *dev) } } +#define MIN_MTU 68 +#define MAX_MTU 65535 + +static int +tun_net_change_mtu(struct net_device *dev, int new_mtu) +{ + if (new_mtu < MIN_MTU || new_mtu + dev->hard_header_len > MAX_MTU) + return -EINVAL; + dev->mtu = new_mtu; + return 0; +} + /* Initialize net device. */ static void tun_net_init(struct net_device *dev) { @@ -183,6 +195,7 @@ static void tun_net_init(struct net_device *dev) dev->hard_header_len = 0; dev->addr_len = 0; dev->mtu = 1500; + dev->change_mtu = tun_net_change_mtu; /* Zero header length */ dev->type = ARPHRD_NONE; @@ -195,6 +208,7 @@ static void tun_net_init(struct net_device *dev) dev->set_multicast_list = tun_net_mclist; ether_setup(dev); + dev->change_mtu = tun_net_change_mtu; /* random address already created for us by tun_set_iff, use it */ memcpy(dev->dev_addr, tun->dev_addr, min(sizeof(tun->dev_addr), sizeof(dev->dev_addr)) ); -- cgit v1.2.3-70-g09d2 From 1202d6ff356cc66dc8d2b85546eb4f187f9e1f25 Mon Sep 17 00:00:00 2001 From: Francois Romieu Date: Mon, 17 Sep 2007 17:13:55 -0700 Subject: [IPG]: add IP1000A driver to kernel tree Signed-off-by: Jesse Huang Signed-off-by: Stefan Lippers-Hollmann Signed-off-by: Francois Romieu Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- MAINTAINERS | 10 + drivers/net/Kconfig | 9 + drivers/net/Makefile | 1 + drivers/net/ipg.c | 2326 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/net/ipg.h | 856 +++++++++++++++++ include/linux/pci_ids.h | 2 + 6 files changed, 3204 insertions(+) create mode 100644 drivers/net/ipg.c create mode 100644 drivers/net/ipg.h (limited to 'drivers') diff --git a/MAINTAINERS b/MAINTAINERS index c35eb125e1c..27cd503cf0e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2081,6 +2081,16 @@ P: Juanjo Ciarlante M: jjciarla@raiz.uncu.edu.ar S: Maintained +IP1000A 10/100/1000 GIGABIT ETHERNET DRIVER +P: Francois Romieu +M: romieu@fr.zoreil.com +P: Sorbica Shieh +M: sorbica@icplus.com.tw +P: Jesse Huang +M: jesse@icplus.com.tw +L: netdev@vger.kernel.org +S: Maintained + IPATH DRIVER: P: Arthur Jones M: infinipath@qlogic.com diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 76db0bc9452..63ab05b5a87 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -165,6 +165,15 @@ config NET_SB1000 If you don't have this card, of course say N. +config IP1000 + tristate "IP1000 Gigabit Ethernet support" + depends on PCI && EXPERIMENTAL + ---help--- + This driver supports IP1000 gigabit Ethernet cards. + + To compile this driver as a module, choose M here: the module + will be called ipg. This is recommended. + source "drivers/net/arcnet/Kconfig" source "drivers/net/phy/Kconfig" diff --git a/drivers/net/Makefile b/drivers/net/Makefile index c23ffdbe259..2098647080a 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_E1000E) += e1000e/ obj-$(CONFIG_IBM_EMAC) += ibm_emac/ obj-$(CONFIG_IXGBE) += ixgbe/ obj-$(CONFIG_IXGB) += ixgb/ +obj-$(CONFIG_IP1000) += ipg.o obj-$(CONFIG_CHELSIO_T1) += chelsio/ obj-$(CONFIG_CHELSIO_T3) += cxgb3/ obj-$(CONFIG_EHEA) += ehea/ diff --git a/drivers/net/ipg.c b/drivers/net/ipg.c new file mode 100644 index 00000000000..dfdc96fcade --- /dev/null +++ b/drivers/net/ipg.c @@ -0,0 +1,2326 @@ +/* + * ipg.c: Device Driver for the IP1000 Gigabit Ethernet Adapter + * + * Copyright (C) 2003, 2007 IC Plus Corp + * + * Original Author: + * + * Craig Rich + * Sundance Technology, Inc. + * www.sundanceti.com + * craig_rich@sundanceti.com + * + * Current Maintainer: + * + * Sorbica Shieh. + * http://www.icplus.com.tw + * sorbica@icplus.com.tw + * + * Jesse Huang + * http://www.icplus.com.tw + * jesse@icplus.com.tw + */ +#include +#include +#include +#include + +#define IPG_RX_RING_BYTES (sizeof(struct ipg_rx) * IPG_RFDLIST_LENGTH) +#define IPG_TX_RING_BYTES (sizeof(struct ipg_tx) * IPG_TFDLIST_LENGTH) +#define IPG_RESET_MASK \ + (IPG_AC_GLOBAL_RESET | IPG_AC_RX_RESET | IPG_AC_TX_RESET | \ + IPG_AC_DMA | IPG_AC_FIFO | IPG_AC_NETWORK | IPG_AC_HOST | \ + IPG_AC_AUTO_INIT) + +#define ipg_w32(val32,reg) iowrite32((val32), ioaddr + (reg)) +#define ipg_w16(val16,reg) iowrite16((val16), ioaddr + (reg)) +#define ipg_w8(val8,reg) iowrite8((val8), ioaddr + (reg)) + +#define ipg_r32(reg) ioread32(ioaddr + (reg)) +#define ipg_r16(reg) ioread16(ioaddr + (reg)) +#define ipg_r8(reg) ioread8(ioaddr + (reg)) + +#define JUMBO_FRAME_4k_ONLY +enum { + netdev_io_size = 128 +}; + +#include "ipg.h" +#define DRV_NAME "ipg" + +MODULE_AUTHOR("IC Plus Corp. 2003"); +MODULE_DESCRIPTION("IC Plus IP1000 Gigabit Ethernet Adapter Linux Driver " + DrvVer); +MODULE_LICENSE("GPL"); + +static const char *ipg_brand_name[] = { + "IC PLUS IP1000 1000/100/10 based NIC", + "Sundance Technology ST2021 based NIC", + "Tamarack Microelectronics TC9020/9021 based NIC", + "Tamarack Microelectronics TC9020/9021 based NIC", + "D-Link NIC", + "D-Link NIC IP1000A" +}; + +static struct pci_device_id ipg_pci_tbl[] __devinitdata = { + { PCI_VDEVICE(SUNDANCE, 0x1023), 0 }, + { PCI_VDEVICE(SUNDANCE, 0x2021), 1 }, + { PCI_VDEVICE(SUNDANCE, 0x1021), 2 }, + { PCI_VDEVICE(DLINK, 0x9021), 3 }, + { PCI_VDEVICE(DLINK, 0x4000), 4 }, + { PCI_VDEVICE(DLINK, 0x4020), 5 }, + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, ipg_pci_tbl); + +static inline void __iomem *ipg_ioaddr(struct net_device *dev) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + return sp->ioaddr; +} + +#ifdef IPG_DEBUG +static void ipg_dump_rfdlist(struct net_device *dev) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + void __iomem *ioaddr = sp->ioaddr; + unsigned int i; + u32 offset; + + IPG_DEBUG_MSG("_dump_rfdlist\n"); + + printk(KERN_INFO "rx_current = %2.2x\n", sp->rx_current); + printk(KERN_INFO "rx_dirty = %2.2x\n", sp->rx_dirty); + printk(KERN_INFO "RFDList start address = %16.16lx\n", + (unsigned long) sp->rxd_map); + printk(KERN_INFO "RFDListPtr register = %8.8x%8.8x\n", + ipg_r32(IPG_RFDLISTPTR1), ipg_r32(IPG_RFDLISTPTR0)); + + for (i = 0; i < IPG_RFDLIST_LENGTH; i++) { + offset = (u32) &sp->rxd[i].next_desc - (u32) sp->rxd; + printk(KERN_INFO "%2.2x %4.4x RFDNextPtr = %16.16lx\n", i, + offset, (unsigned long) sp->rxd[i].next_desc); + offset = (u32) &sp->rxd[i].rfs - (u32) sp->rxd; + printk(KERN_INFO "%2.2x %4.4x RFS = %16.16lx\n", i, + offset, (unsigned long) sp->rxd[i].rfs); + offset = (u32) &sp->rxd[i].frag_info - (u32) sp->rxd; + printk(KERN_INFO "%2.2x %4.4x frag_info = %16.16lx\n", i, + offset, (unsigned long) sp->rxd[i].frag_info); + } +} + +static void ipg_dump_tfdlist(struct net_device *dev) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + void __iomem *ioaddr = sp->ioaddr; + unsigned int i; + u32 offset; + + IPG_DEBUG_MSG("_dump_tfdlist\n"); + + printk(KERN_INFO "tx_current = %2.2x\n", sp->tx_current); + printk(KERN_INFO "tx_dirty = %2.2x\n", sp->tx_dirty); + printk(KERN_INFO "TFDList start address = %16.16lx\n", + (unsigned long) sp->txd_map); + printk(KERN_INFO "TFDListPtr register = %8.8x%8.8x\n", + ipg_r32(IPG_TFDLISTPTR1), ipg_r32(IPG_TFDLISTPTR0)); + + for (i = 0; i < IPG_TFDLIST_LENGTH; i++) { + offset = (u32) &sp->txd[i].next_desc - (u32) sp->txd; + printk(KERN_INFO "%2.2x %4.4x TFDNextPtr = %16.16lx\n", i, + offset, (unsigned long) sp->txd[i].next_desc); + + offset = (u32) &sp->txd[i].tfc - (u32) sp->txd; + printk(KERN_INFO "%2.2x %4.4x TFC = %16.16lx\n", i, + offset, (unsigned long) sp->txd[i].tfc); + offset = (u32) &sp->txd[i].frag_info - (u32) sp->txd; + printk(KERN_INFO "%2.2x %4.4x frag_info = %16.16lx\n", i, + offset, (unsigned long) sp->txd[i].frag_info); + } +} +#endif + +static void ipg_write_phy_ctl(void __iomem *ioaddr, u8 data) +{ + ipg_w8(IPG_PC_RSVD_MASK & data, PHY_CTRL); + ndelay(IPG_PC_PHYCTRLWAIT_NS); +} + +static void ipg_drive_phy_ctl_low_high(void __iomem *ioaddr, u8 data) +{ + ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_LO | data); + ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_HI | data); +} + +static void send_three_state(void __iomem *ioaddr, u8 phyctrlpolarity) +{ + phyctrlpolarity |= (IPG_PC_MGMTDATA & 0) | IPG_PC_MGMTDIR; + + ipg_drive_phy_ctl_low_high(ioaddr, phyctrlpolarity); +} + +static void send_end(void __iomem *ioaddr, u8 phyctrlpolarity) +{ + ipg_w8((IPG_PC_MGMTCLK_LO | (IPG_PC_MGMTDATA & 0) | IPG_PC_MGMTDIR | + phyctrlpolarity) & IPG_PC_RSVD_MASK, PHY_CTRL); +} + +static u16 read_phy_bit(void __iomem * ioaddr, u8 phyctrlpolarity) +{ + u16 bit_data; + + ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_LO | phyctrlpolarity); + + bit_data = ((ipg_r8(PHY_CTRL) & IPG_PC_MGMTDATA) >> 1) & 1; + + ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_HI | phyctrlpolarity); + + return bit_data; +} + +/* + * Read a register from the Physical Layer device located + * on the IPG NIC, using the IPG PHYCTRL register. + */ +static int mdio_read(struct net_device * dev, int phy_id, int phy_reg) +{ + void __iomem *ioaddr = ipg_ioaddr(dev); + /* + * The GMII mangement frame structure for a read is as follows: + * + * |Preamble|st|op|phyad|regad|ta| data |idle| + * |< 32 1s>|01|10|AAAAA|RRRRR|z0|DDDDDDDDDDDDDDDD|z | + * + * <32 1s> = 32 consecutive logic 1 values + * A = bit of Physical Layer device address (MSB first) + * R = bit of register address (MSB first) + * z = High impedance state + * D = bit of read data (MSB first) + * + * Transmission order is 'Preamble' field first, bits transmitted + * left to right (first to last). + */ + struct { + u32 field; + unsigned int len; + } p[] = { + { GMII_PREAMBLE, 32 }, /* Preamble */ + { GMII_ST, 2 }, /* ST */ + { GMII_READ, 2 }, /* OP */ + { phy_id, 5 }, /* PHYAD */ + { phy_reg, 5 }, /* REGAD */ + { 0x0000, 2 }, /* TA */ + { 0x0000, 16 }, /* DATA */ + { 0x0000, 1 } /* IDLE */ + }; + unsigned int i, j; + u8 polarity, data; + + polarity = ipg_r8(PHY_CTRL); + polarity &= (IPG_PC_DUPLEX_POLARITY | IPG_PC_LINK_POLARITY); + + /* Create the Preamble, ST, OP, PHYAD, and REGAD field. */ + for (j = 0; j < 5; j++) { + for (i = 0; i < p[j].len; i++) { + /* For each variable length field, the MSB must be + * transmitted first. Rotate through the field bits, + * starting with the MSB, and move each bit into the + * the 1st (2^1) bit position (this is the bit position + * corresponding to the MgmtData bit of the PhyCtrl + * register for the IPG). + * + * Example: ST = 01; + * + * First write a '0' to bit 1 of the PhyCtrl + * register, then write a '1' to bit 1 of the + * PhyCtrl register. + * + * To do this, right shift the MSB of ST by the value: + * [field length - 1 - #ST bits already written] + * then left shift this result by 1. + */ + data = (p[j].field >> (p[j].len - 1 - i)) << 1; + data &= IPG_PC_MGMTDATA; + data |= polarity | IPG_PC_MGMTDIR; + + ipg_drive_phy_ctl_low_high(ioaddr, data); + } + } + + send_three_state(ioaddr, polarity); + + read_phy_bit(ioaddr, polarity); + + /* + * For a read cycle, the bits for the next two fields (TA and + * DATA) are driven by the PHY (the IPG reads these bits). + */ + for (i = 0; i < p[6].len; i++) { + p[6].field |= + (read_phy_bit(ioaddr, polarity) << (p[6].len - 1 - i)); + } + + send_three_state(ioaddr, polarity); + send_three_state(ioaddr, polarity); + send_three_state(ioaddr, polarity); + send_end(ioaddr, polarity); + + /* Return the value of the DATA field. */ + return p[6].field; +} + +/* + * Write to a register from the Physical Layer device located + * on the IPG NIC, using the IPG PHYCTRL register. + */ +static void mdio_write(struct net_device *dev, int phy_id, int phy_reg, int val) +{ + void __iomem *ioaddr = ipg_ioaddr(dev); + /* + * The GMII mangement frame structure for a read is as follows: + * + * |Preamble|st|op|phyad|regad|ta| data |idle| + * |< 32 1s>|01|10|AAAAA|RRRRR|z0|DDDDDDDDDDDDDDDD|z | + * + * <32 1s> = 32 consecutive logic 1 values + * A = bit of Physical Layer device address (MSB first) + * R = bit of register address (MSB first) + * z = High impedance state + * D = bit of write data (MSB first) + * + * Transmission order is 'Preamble' field first, bits transmitted + * left to right (first to last). + */ + struct { + u32 field; + unsigned int len; + } p[] = { + { GMII_PREAMBLE, 32 }, /* Preamble */ + { GMII_ST, 2 }, /* ST */ + { GMII_WRITE, 2 }, /* OP */ + { phy_id, 5 }, /* PHYAD */ + { phy_reg, 5 }, /* REGAD */ + { 0x0002, 2 }, /* TA */ + { val & 0xffff, 16 }, /* DATA */ + { 0x0000, 1 } /* IDLE */ + }; + unsigned int i, j; + u8 polarity, data; + + polarity = ipg_r8(PHY_CTRL); + polarity &= (IPG_PC_DUPLEX_POLARITY | IPG_PC_LINK_POLARITY); + + /* Create the Preamble, ST, OP, PHYAD, and REGAD field. */ + for (j = 0; j < 7; j++) { + for (i = 0; i < p[j].len; i++) { + /* For each variable length field, the MSB must be + * transmitted first. Rotate through the field bits, + * starting with the MSB, and move each bit into the + * the 1st (2^1) bit position (this is the bit position + * corresponding to the MgmtData bit of the PhyCtrl + * register for the IPG). + * + * Example: ST = 01; + * + * First write a '0' to bit 1 of the PhyCtrl + * register, then write a '1' to bit 1 of the + * PhyCtrl register. + * + * To do this, right shift the MSB of ST by the value: + * [field length - 1 - #ST bits already written] + * then left shift this result by 1. + */ + data = (p[j].field >> (p[j].len - 1 - i)) << 1; + data &= IPG_PC_MGMTDATA; + data |= polarity | IPG_PC_MGMTDIR; + + ipg_drive_phy_ctl_low_high(ioaddr, data); + } + } + + /* The last cycle is a tri-state, so read from the PHY. */ + for (j = 7; j < 8; j++) { + for (i = 0; i < p[j].len; i++) { + ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_LO | polarity); + + p[j].field |= ((ipg_r8(PHY_CTRL) & + IPG_PC_MGMTDATA) >> 1) << (p[j].len - 1 - i); + + ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_HI | polarity); + } + } +} + +/* Set LED_Mode JES20040127EEPROM */ +static void ipg_set_led_mode(struct net_device *dev) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + void __iomem *ioaddr = sp->ioaddr; + u32 mode; + + mode = ipg_r32(ASIC_CTRL); + mode &= ~(IPG_AC_LED_MODE_BIT_1 | IPG_AC_LED_MODE | IPG_AC_LED_SPEED); + + if ((sp->LED_Mode & 0x03) > 1) + mode |= IPG_AC_LED_MODE_BIT_1; /* Write Asic Control Bit 29 */ + + if ((sp->LED_Mode & 0x01) == 1) + mode |= IPG_AC_LED_MODE; /* Write Asic Control Bit 14 */ + + if ((sp->LED_Mode & 0x08) == 8) + mode |= IPG_AC_LED_SPEED; /* Write Asic Control Bit 27 */ + + ipg_w32(mode, ASIC_CTRL); +} + +/* Set PHYSet JES20040127EEPROM */ +static void ipg_set_phy_set(struct net_device *dev) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + void __iomem *ioaddr = sp->ioaddr; + int physet; + + physet = ipg_r8(PHY_SET); + physet &= ~(IPG_PS_MEM_LENB9B | IPG_PS_MEM_LEN9 | IPG_PS_NON_COMPDET); + physet |= ((sp->LED_Mode & 0x70) >> 4); + ipg_w8(physet, PHY_SET); +} + +static int ipg_reset(struct net_device *dev, u32 resetflags) +{ + /* Assert functional resets via the IPG AsicCtrl + * register as specified by the 'resetflags' input + * parameter. + */ + void __iomem *ioaddr = ipg_ioaddr(dev); //JES20040127EEPROM: + unsigned int timeout_count = 0; + + IPG_DEBUG_MSG("_reset\n"); + + ipg_w32(ipg_r32(ASIC_CTRL) | resetflags, ASIC_CTRL); + + /* Delay added to account for problem with 10Mbps reset. */ + mdelay(IPG_AC_RESETWAIT); + + while (IPG_AC_RESET_BUSY & ipg_r32(ASIC_CTRL)) { + mdelay(IPG_AC_RESETWAIT); + if (++timeout_count > IPG_AC_RESET_TIMEOUT) + return -ETIME; + } + /* Set LED Mode in Asic Control JES20040127EEPROM */ + ipg_set_led_mode(dev); + + /* Set PHYSet Register Value JES20040127EEPROM */ + ipg_set_phy_set(dev); + return 0; +} + +/* Find the GMII PHY address. */ +static int ipg_find_phyaddr(struct net_device *dev) +{ + unsigned int phyaddr, i; + + for (i = 0; i < 32; i++) { + u32 status; + + /* Search for the correct PHY address among 32 possible. */ + phyaddr = (IPG_NIC_PHY_ADDRESS + i) % 32; + + /* 10/22/03 Grace change verify from GMII_PHY_STATUS to + GMII_PHY_ID1 + */ + + status = mdio_read(dev, phyaddr, MII_BMSR); + + if ((status != 0xFFFF) && (status != 0)) + return phyaddr; + } + + return 0x1f; +} + +/* + * Configure IPG based on result of IEEE 802.3 PHY + * auto-negotiation. + */ +static int ipg_config_autoneg(struct net_device *dev) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + void __iomem *ioaddr = sp->ioaddr; + unsigned int txflowcontrol; + unsigned int rxflowcontrol; + unsigned int fullduplex; + unsigned int gig; + u32 mac_ctrl_val; + u32 asicctrl; + u8 phyctrl; + + IPG_DEBUG_MSG("_config_autoneg\n"); + + asicctrl = ipg_r32(ASIC_CTRL); + phyctrl = ipg_r8(PHY_CTRL); + mac_ctrl_val = ipg_r32(MAC_CTRL); + + /* Set flags for use in resolving auto-negotation, assuming + * non-1000Mbps, half duplex, no flow control. + */ + fullduplex = 0; + txflowcontrol = 0; + rxflowcontrol = 0; + gig = 0; + + /* To accomodate a problem in 10Mbps operation, + * set a global flag if PHY running in 10Mbps mode. + */ + sp->tenmbpsmode = 0; + + printk(KERN_INFO "%s: Link speed = ", dev->name); + + /* Determine actual speed of operation. */ + switch (phyctrl & IPG_PC_LINK_SPEED) { + case IPG_PC_LINK_SPEED_10MBPS: + printk("10Mbps.\n"); + printk(KERN_INFO "%s: 10Mbps operational mode enabled.\n", + dev->name); + sp->tenmbpsmode = 1; + break; + case IPG_PC_LINK_SPEED_100MBPS: + printk("100Mbps.\n"); + break; + case IPG_PC_LINK_SPEED_1000MBPS: + printk("1000Mbps.\n"); + gig = 1; + break; + default: + printk("undefined!\n"); + return 0; + } + + if (phyctrl & IPG_PC_DUPLEX_STATUS) { + fullduplex = 1; + txflowcontrol = 1; + rxflowcontrol = 1; + } + + /* Configure full duplex, and flow control. */ + if (fullduplex == 1) { + /* Configure IPG for full duplex operation. */ + printk(KERN_INFO "%s: setting full duplex, ", dev->name); + + mac_ctrl_val |= IPG_MC_DUPLEX_SELECT_FD; + + if (txflowcontrol == 1) { + printk("TX flow control"); + mac_ctrl_val |= IPG_MC_TX_FLOW_CONTROL_ENABLE; + } else { + printk("no TX flow control"); + mac_ctrl_val &= ~IPG_MC_TX_FLOW_CONTROL_ENABLE; + } + + if (rxflowcontrol == 1) { + printk(", RX flow control."); + mac_ctrl_val |= IPG_MC_RX_FLOW_CONTROL_ENABLE; + } else { + printk(", no RX flow control."); + mac_ctrl_val &= ~IPG_MC_RX_FLOW_CONTROL_ENABLE; + } + + printk("\n"); + } else { + /* Configure IPG for half duplex operation. */ + printk(KERN_INFO "%s: setting half duplex, " + "no TX flow control, no RX flow control.\n", dev->name); + + mac_ctrl_val &= ~IPG_MC_DUPLEX_SELECT_FD & + ~IPG_MC_TX_FLOW_CONTROL_ENABLE & + ~IPG_MC_RX_FLOW_CONTROL_ENABLE; + } + ipg_w32(mac_ctrl_val, MAC_CTRL); + return 0; +} + +/* Determine and configure multicast operation and set + * receive mode for IPG. + */ +static void ipg_nic_set_multicast_list(struct net_device *dev) +{ + void __iomem *ioaddr = ipg_ioaddr(dev); + struct dev_mc_list *mc_list_ptr; + unsigned int hashindex; + u32 hashtable[2]; + u8 receivemode; + + IPG_DEBUG_MSG("_nic_set_multicast_list\n"); + + receivemode = IPG_RM_RECEIVEUNICAST | IPG_RM_RECEIVEBROADCAST; + + if (dev->flags & IFF_PROMISC) { + /* NIC to be configured in promiscuous mode. */ + receivemode = IPG_RM_RECEIVEALLFRAMES; + } else if ((dev->flags & IFF_ALLMULTI) || + (dev->flags & IFF_MULTICAST & + (dev->mc_count > IPG_MULTICAST_HASHTABLE_SIZE))) { + /* NIC to be configured to receive all multicast + * frames. */ + receivemode |= IPG_RM_RECEIVEMULTICAST; + } else if (dev->flags & IFF_MULTICAST & (dev->mc_count > 0)) { + /* NIC to be configured to receive selected + * multicast addresses. */ + receivemode |= IPG_RM_RECEIVEMULTICASTHASH; + } + + /* Calculate the bits to set for the 64 bit, IPG HASHTABLE. + * The IPG applies a cyclic-redundancy-check (the same CRC + * used to calculate the frame data FCS) to the destination + * address all incoming multicast frames whose destination + * address has the multicast bit set. The least significant + * 6 bits of the CRC result are used as an addressing index + * into the hash table. If the value of the bit addressed by + * this index is a 1, the frame is passed to the host system. + */ + + /* Clear hashtable. */ + hashtable[0] = 0x00000000; + hashtable[1] = 0x00000000; + + /* Cycle through all multicast addresses to filter. */ + for (mc_list_ptr = dev->mc_list; + mc_list_ptr != NULL; mc_list_ptr = mc_list_ptr->next) { + /* Calculate CRC result for each multicast address. */ + hashindex = crc32_le(0xffffffff, mc_list_ptr->dmi_addr, + ETH_ALEN); + + /* Use only the least significant 6 bits. */ + hashindex = hashindex & 0x3F; + + /* Within "hashtable", set bit number "hashindex" + * to a logic 1. + */ + set_bit(hashindex, (void *)hashtable); + } + + /* Write the value of the hashtable, to the 4, 16 bit + * HASHTABLE IPG registers. + */ + ipg_w32(hashtable[0], HASHTABLE_0); + ipg_w32(hashtable[1], HASHTABLE_1); + + ipg_w8(IPG_RM_RSVD_MASK & receivemode, RECEIVE_MODE); + + IPG_DEBUG_MSG("ReceiveMode = %x\n", ipg_r8(RECEIVE_MODE)); +} + +static int ipg_io_config(struct net_device *dev) +{ + void __iomem *ioaddr = ipg_ioaddr(dev); + u32 origmacctrl; + u32 restoremacctrl; + + IPG_DEBUG_MSG("_io_config\n"); + + origmacctrl = ipg_r32(MAC_CTRL); + + restoremacctrl = origmacctrl | IPG_MC_STATISTICS_ENABLE; + + /* Based on compilation option, determine if FCS is to be + * stripped on receive frames by IPG. + */ + if (!IPG_STRIP_FCS_ON_RX) + restoremacctrl |= IPG_MC_RCV_FCS; + + /* Determine if transmitter and/or receiver are + * enabled so we may restore MACCTRL correctly. + */ + if (origmacctrl & IPG_MC_TX_ENABLED) + restoremacctrl |= IPG_MC_TX_ENABLE; + + if (origmacctrl & IPG_MC_RX_ENABLED) + restoremacctrl |= IPG_MC_RX_ENABLE; + + /* Transmitter and receiver must be disabled before setting + * IFSSelect. + */ + ipg_w32((origmacctrl & (IPG_MC_RX_DISABLE | IPG_MC_TX_DISABLE)) & + IPG_MC_RSVD_MASK, MAC_CTRL); + + /* Now that transmitter and receiver are disabled, write + * to IFSSelect. + */ + ipg_w32((origmacctrl & IPG_MC_IFS_96BIT) & IPG_MC_RSVD_MASK, MAC_CTRL); + + /* Set RECEIVEMODE register. */ + ipg_nic_set_multicast_list(dev); + + ipg_w16(IPG_MAX_RXFRAME_SIZE, MAX_FRAME_SIZE); + + ipg_w8(IPG_RXDMAPOLLPERIOD_VALUE, RX_DMA_POLL_PERIOD); + ipg_w8(IPG_RXDMAURGENTTHRESH_VALUE, RX_DMA_URGENT_THRESH); + ipg_w8(IPG_RXDMABURSTTHRESH_VALUE, RX_DMA_BURST_THRESH); + ipg_w8(IPG_TXDMAPOLLPERIOD_VALUE, TX_DMA_POLL_PERIOD); + ipg_w8(IPG_TXDMAURGENTTHRESH_VALUE, TX_DMA_URGENT_THRESH); + ipg_w8(IPG_TXDMABURSTTHRESH_VALUE, TX_DMA_BURST_THRESH); + ipg_w16((IPG_IE_HOST_ERROR | IPG_IE_TX_DMA_COMPLETE | + IPG_IE_TX_COMPLETE | IPG_IE_INT_REQUESTED | + IPG_IE_UPDATE_STATS | IPG_IE_LINK_EVENT | + IPG_IE_RX_DMA_COMPLETE | IPG_IE_RX_DMA_PRIORITY), INT_ENABLE); + ipg_w16(IPG_FLOWONTHRESH_VALUE, FLOW_ON_THRESH); + ipg_w16(IPG_FLOWOFFTHRESH_VALUE, FLOW_OFF_THRESH); + + /* IPG multi-frag frame bug workaround. + * Per silicon revision B3 eratta. + */ + ipg_w16(ipg_r16(DEBUG_CTRL) | 0x0200, DEBUG_CTRL); + + /* IPG TX poll now bug workaround. + * Per silicon revision B3 eratta. + */ + ipg_w16(ipg_r16(DEBUG_CTRL) | 0x0010, DEBUG_CTRL); + + /* IPG RX poll now bug workaround. + * Per silicon revision B3 eratta. + */ + ipg_w16(ipg_r16(DEBUG_CTRL) | 0x0020, DEBUG_CTRL); + + /* Now restore MACCTRL to original setting. */ + ipg_w32(IPG_MC_RSVD_MASK & restoremacctrl, MAC_CTRL); + + /* Disable unused RMON statistics. */ + ipg_w32(IPG_RZ_ALL, RMON_STATISTICS_MASK); + + /* Disable unused MIB statistics. */ + ipg_w32(IPG_SM_MACCONTROLFRAMESXMTD | IPG_SM_MACCONTROLFRAMESRCVD | + IPG_SM_BCSTOCTETXMTOK_BCSTFRAMESXMTDOK | IPG_SM_TXJUMBOFRAMES | + IPG_SM_MCSTOCTETXMTOK_MCSTFRAMESXMTDOK | IPG_SM_RXJUMBOFRAMES | + IPG_SM_BCSTOCTETRCVDOK_BCSTFRAMESRCVDOK | + IPG_SM_UDPCHECKSUMERRORS | IPG_SM_TCPCHECKSUMERRORS | + IPG_SM_IPCHECKSUMERRORS, STATISTICS_MASK); + + return 0; +} + +/* + * Create a receive buffer within system memory and update + * NIC private structure appropriately. + */ +static int ipg_get_rxbuff(struct net_device *dev, int entry) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + struct ipg_rx *rxfd = sp->rxd + entry; + struct sk_buff *skb; + u64 rxfragsize; + + IPG_DEBUG_MSG("_get_rxbuff\n"); + + skb = netdev_alloc_skb(dev, IPG_RXSUPPORT_SIZE + NET_IP_ALIGN); + if (!skb) { + sp->RxBuff[entry] = NULL; + return -ENOMEM; + } + + /* Adjust the data start location within the buffer to + * align IP address field to a 16 byte boundary. + */ + skb_reserve(skb, NET_IP_ALIGN); + + /* Associate the receive buffer with the IPG NIC. */ + skb->dev = dev; + + /* Save the address of the sk_buff structure. */ + sp->RxBuff[entry] = skb; + + rxfd->frag_info = cpu_to_le64(pci_map_single(sp->pdev, skb->data, + sp->rx_buf_sz, PCI_DMA_FROMDEVICE)); + + /* Set the RFD fragment length. */ + rxfragsize = IPG_RXFRAG_SIZE; + rxfd->frag_info |= cpu_to_le64((rxfragsize << 48) & IPG_RFI_FRAGLEN); + + return 0; +} + +static int init_rfdlist(struct net_device *dev) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + void __iomem *ioaddr = sp->ioaddr; + unsigned int i; + + IPG_DEBUG_MSG("_init_rfdlist\n"); + + for (i = 0; i < IPG_RFDLIST_LENGTH; i++) { + struct ipg_rx *rxfd = sp->rxd + i; + + if (sp->RxBuff[i]) { + pci_unmap_single(sp->pdev, + le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN), + sp->rx_buf_sz, PCI_DMA_FROMDEVICE); + IPG_DEV_KFREE_SKB(sp->RxBuff[i]); + sp->RxBuff[i] = NULL; + } + + /* Clear out the RFS field. */ + rxfd->rfs = 0x0000000000000000; + + if (ipg_get_rxbuff(dev, i) < 0) { + /* + * A receive buffer was not ready, break the + * RFD list here. + */ + IPG_DEBUG_MSG("Cannot allocate Rx buffer.\n"); + + /* Just in case we cannot allocate a single RFD. + * Should not occur. + */ + if (i == 0) { + printk(KERN_ERR "%s: No memory available" + " for RFD list.\n", dev->name); + return -ENOMEM; + } + } + + rxfd->next_desc = cpu_to_le64(sp->rxd_map + + sizeof(struct ipg_rx)*(i + 1)); + } + sp->rxd[i - 1].next_desc = cpu_to_le64(sp->rxd_map); + + sp->rx_current = 0; + sp->rx_dirty = 0; + + /* Write the location of the RFDList to the IPG. */ + ipg_w32((u32) sp->rxd_map, RFD_LIST_PTR_0); + ipg_w32(0x00000000, RFD_LIST_PTR_1); + + return 0; +} + +static void init_tfdlist(struct net_device *dev) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + void __iomem *ioaddr = sp->ioaddr; + unsigned int i; + + IPG_DEBUG_MSG("_init_tfdlist\n"); + + for (i = 0; i < IPG_TFDLIST_LENGTH; i++) { + struct ipg_tx *txfd = sp->txd + i; + + txfd->tfc = cpu_to_le64(IPG_TFC_TFDDONE); + + if (sp->TxBuff[i]) { + IPG_DEV_KFREE_SKB(sp->TxBuff[i]); + sp->TxBuff[i] = NULL; + } + + txfd->next_desc = cpu_to_le64(sp->txd_map + + sizeof(struct ipg_tx)*(i + 1)); + } + sp->txd[i - 1].next_desc = cpu_to_le64(sp->txd_map); + + sp->tx_current = 0; + sp->tx_dirty = 0; + + /* Write the location of the TFDList to the IPG. */ + IPG_DDEBUG_MSG("Starting TFDListPtr = %8.8x\n", + (u32) sp->txd_map); + ipg_w32((u32) sp->txd_map, TFD_LIST_PTR_0); + ipg_w32(0x00000000, TFD_LIST_PTR_1); + + sp->ResetCurrentTFD = 1; +} + +/* + * Free all transmit buffers which have already been transfered + * via DMA to the IPG. + */ +static void ipg_nic_txfree(struct net_device *dev) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + void __iomem *ioaddr = sp->ioaddr; + const unsigned int curr = ipg_r32(TFD_LIST_PTR_0) - + (sp->txd_map / sizeof(struct ipg_tx)) - 1; + unsigned int released, pending; + + IPG_DEBUG_MSG("_nic_txfree\n"); + + pending = sp->tx_current - sp->tx_dirty; + + for (released = 0; released < pending; released++) { + unsigned int dirty = sp->tx_dirty % IPG_TFDLIST_LENGTH; + struct sk_buff *skb = sp->TxBuff[dirty]; + struct ipg_tx *txfd = sp->txd + dirty; + + IPG_DEBUG_MSG("TFC = %16.16lx\n", (unsigned long) txfd->tfc); + + /* Look at each TFD's TFC field beginning + * at the last freed TFD up to the current TFD. + * If the TFDDone bit is set, free the associated + * buffer. + */ + if (dirty == curr) + break; + + /* Setup TFDDONE for compatible issue. */ + txfd->tfc |= cpu_to_le64(IPG_TFC_TFDDONE); + + /* Free the transmit buffer. */ + if (skb) { + pci_unmap_single(sp->pdev, + le64_to_cpu(txfd->frag_info & ~IPG_TFI_FRAGLEN), + skb->len, PCI_DMA_TODEVICE); + + IPG_DEV_KFREE_SKB(skb); + + sp->TxBuff[dirty] = NULL; + } + } + + sp->tx_dirty += released; + + if (netif_queue_stopped(dev) && + (sp->tx_current != (sp->tx_dirty + IPG_TFDLIST_LENGTH))) { + netif_wake_queue(dev); + } +} + +static void ipg_tx_timeout(struct net_device *dev) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + void __iomem *ioaddr = sp->ioaddr; + + ipg_reset(dev, IPG_AC_TX_RESET | IPG_AC_DMA | IPG_AC_NETWORK | + IPG_AC_FIFO); + + spin_lock_irq(&sp->lock); + + /* Re-configure after DMA reset. */ + if (ipg_io_config(dev) < 0) { + printk(KERN_INFO "%s: Error during re-configuration.\n", + dev->name); + } + + init_tfdlist(dev); + + spin_unlock_irq(&sp->lock); + + ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_TX_ENABLE) & IPG_MC_RSVD_MASK, + MAC_CTRL); +} + +/* + * For TxComplete interrupts, free all transmit + * buffers which have already been transfered via DMA + * to the IPG. + */ +static void ipg_nic_txcleanup(struct net_device *dev) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + void __iomem *ioaddr = sp->ioaddr; + unsigned int i; + + IPG_DEBUG_MSG("_nic_txcleanup\n"); + + for (i = 0; i < IPG_TFDLIST_LENGTH; i++) { + /* Reading the TXSTATUS register clears the + * TX_COMPLETE interrupt. + */ + u32 txstatusdword = ipg_r32(TX_STATUS); + + IPG_DEBUG_MSG("TxStatus = %8.8x\n", txstatusdword); + + /* Check for Transmit errors. Error bits only valid if + * TX_COMPLETE bit in the TXSTATUS register is a 1. + */ + if (!(txstatusdword & IPG_TS_TX_COMPLETE)) + break; + + /* If in 10Mbps mode, indicate transmit is ready. */ + if (sp->tenmbpsmode) { + netif_wake_queue(dev); + } + + /* Transmit error, increment stat counters. */ + if (txstatusdword & IPG_TS_TX_ERROR) { + IPG_DEBUG_MSG("Transmit error.\n"); + sp->stats.tx_errors++; + } + + /* Late collision, re-enable transmitter. */ + if (txstatusdword & IPG_TS_LATE_COLLISION) { + IPG_DEBUG_MSG("Late collision on transmit.\n"); + ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_TX_ENABLE) & + IPG_MC_RSVD_MASK, MAC_CTRL); + } + + /* Maximum collisions, re-enable transmitter. */ + if (txstatusdword & IPG_TS_TX_MAX_COLL) { + IPG_DEBUG_MSG("Maximum collisions on transmit.\n"); + ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_TX_ENABLE) & + IPG_MC_RSVD_MASK, MAC_CTRL); + } + + /* Transmit underrun, reset and re-enable + * transmitter. + */ + if (txstatusdword & IPG_TS_TX_UNDERRUN) { + IPG_DEBUG_MSG("Transmitter underrun.\n"); + sp->stats.tx_fifo_errors++; + ipg_reset(dev, IPG_AC_TX_RESET | IPG_AC_DMA | + IPG_AC_NETWORK | IPG_AC_FIFO); + + /* Re-configure after DMA reset. */ + if (ipg_io_config(dev) < 0) { + printk(KERN_INFO + "%s: Error during re-configuration.\n", + dev->name); + } + init_tfdlist(dev); + + ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_TX_ENABLE) & + IPG_MC_RSVD_MASK, MAC_CTRL); + } + } + + ipg_nic_txfree(dev); +} + +/* Provides statistical information about the IPG NIC. */ +struct net_device_stats *ipg_nic_get_stats(struct net_device *dev) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + void __iomem *ioaddr = sp->ioaddr; + u16 temp1; + u16 temp2; + + IPG_DEBUG_MSG("_nic_get_stats\n"); + + /* Check to see if the NIC has been initialized via nic_open, + * before trying to read statistic registers. + */ + if (!test_bit(__LINK_STATE_START, &dev->state)) + return &sp->stats; + + sp->stats.rx_packets += ipg_r32(IPG_FRAMESRCVDOK); + sp->stats.tx_packets += ipg_r32(IPG_FRAMESXMTDOK); + sp->stats.rx_bytes += ipg_r32(IPG_OCTETRCVOK); + sp->stats.tx_bytes += ipg_r32(IPG_OCTETXMTOK); + temp1 = ipg_r16(IPG_FRAMESLOSTRXERRORS); + sp->stats.rx_errors += temp1; + sp->stats.rx_missed_errors += temp1; + temp1 = ipg_r32(IPG_SINGLECOLFRAMES) + ipg_r32(IPG_MULTICOLFRAMES) + + ipg_r32(IPG_LATECOLLISIONS); + temp2 = ipg_r16(IPG_CARRIERSENSEERRORS); + sp->stats.collisions += temp1; + sp->stats.tx_dropped += ipg_r16(IPG_FRAMESABORTXSCOLLS); + sp->stats.tx_errors += ipg_r16(IPG_FRAMESWEXDEFERRAL) + + ipg_r32(IPG_FRAMESWDEFERREDXMT) + temp1 + temp2; + sp->stats.multicast += ipg_r32(IPG_MCSTOCTETRCVDOK); + + /* detailed tx_errors */ + sp->stats.tx_carrier_errors += temp2; + + /* detailed rx_errors */ + sp->stats.rx_length_errors += ipg_r16(IPG_INRANGELENGTHERRORS) + + ipg_r16(IPG_FRAMETOOLONGERRRORS); + sp->stats.rx_crc_errors += ipg_r16(IPG_FRAMECHECKSEQERRORS); + + /* Unutilized IPG statistic registers. */ + ipg_r32(IPG_MCSTFRAMESRCVDOK); + + return &sp->stats; +} + +/* Restore used receive buffers. */ +static int ipg_nic_rxrestore(struct net_device *dev) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + const unsigned int curr = sp->rx_current; + unsigned int dirty = sp->rx_dirty; + + IPG_DEBUG_MSG("_nic_rxrestore\n"); + + for (dirty = sp->rx_dirty; curr - dirty > 0; dirty++) { + unsigned int entry = dirty % IPG_RFDLIST_LENGTH; + + /* rx_copybreak may poke hole here and there. */ + if (sp->RxBuff[entry]) + continue; + + /* Generate a new receive buffer to replace the + * current buffer (which will be released by the + * Linux system). + */ + if (ipg_get_rxbuff(dev, entry) < 0) { + IPG_DEBUG_MSG("Cannot allocate new Rx buffer.\n"); + + break; + } + + /* Reset the RFS field. */ + sp->rxd[entry].rfs = 0x0000000000000000; + } + sp->rx_dirty = dirty; + + return 0; +} + +#ifdef JUMBO_FRAME + +/* use jumboindex and jumbosize to control jumbo frame status + initial status is jumboindex=-1 and jumbosize=0 + 1. jumboindex = -1 and jumbosize=0 : previous jumbo frame has been done. + 2. jumboindex != -1 and jumbosize != 0 : jumbo frame is not over size and receiving + 3. jumboindex = -1 and jumbosize != 0 : jumbo frame is over size, already dump + previous receiving and need to continue dumping the current one +*/ +enum { + NormalPacket, + ErrorPacket +}; + +enum { + Frame_NoStart_NoEnd = 0, + Frame_WithStart = 1, + Frame_WithEnd = 10, + Frame_WithStart_WithEnd = 11 +}; + +inline void ipg_nic_rx_free_skb(struct net_device *dev) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + unsigned int entry = sp->rx_current % IPG_RFDLIST_LENGTH; + + if (sp->RxBuff[entry]) { + struct ipg_rx *rxfd = sp->rxd + entry; + + pci_unmap_single(sp->pdev, + le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN), + sp->rx_buf_sz, PCI_DMA_FROMDEVICE); + IPG_DEV_KFREE_SKB(sp->RxBuff[entry]); + sp->RxBuff[entry] = NULL; + } +} + +inline int ipg_nic_rx_check_frame_type(struct net_device *dev) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + struct ipg_rx *rxfd = sp->rxd + (sp->rx_current % IPG_RFDLIST_LENGTH); + int type = Frame_NoStart_NoEnd; + + if (le64_to_cpu(rxfd->rfs) & IPG_RFS_FRAMESTART) + type += Frame_WithStart; + if (le64_to_cpu(rxfd->rfs) & IPG_RFS_FRAMEEND) + type += Frame_WithEnd; + return type; +} + +inline int ipg_nic_rx_check_error(struct net_device *dev) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + unsigned int entry = sp->rx_current % IPG_RFDLIST_LENGTH; + struct ipg_rx *rxfd = sp->rxd + entry; + + if (IPG_DROP_ON_RX_ETH_ERRORS && (le64_to_cpu(rxfd->rfs) & + (IPG_RFS_RXFIFOOVERRUN | IPG_RFS_RXRUNTFRAME | + IPG_RFS_RXALIGNMENTERROR | IPG_RFS_RXFCSERROR | + IPG_RFS_RXOVERSIZEDFRAME | IPG_RFS_RXLENGTHERROR))) { + IPG_DEBUG_MSG("Rx error, RFS = %16.16lx\n", + (unsigned long) rxfd->rfs); + + /* Increment general receive error statistic. */ + sp->stats.rx_errors++; + + /* Increment detailed receive error statistics. */ + if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFIFOOVERRUN) { + IPG_DEBUG_MSG("RX FIFO overrun occured.\n"); + + sp->stats.rx_fifo_errors++; + } + + if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXRUNTFRAME) { + IPG_DEBUG_MSG("RX runt occured.\n"); + sp->stats.rx_length_errors++; + } + + /* Do nothing for IPG_RFS_RXOVERSIZEDFRAME, + * error count handled by a IPG statistic register. + */ + + if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXALIGNMENTERROR) { + IPG_DEBUG_MSG("RX alignment error occured.\n"); + sp->stats.rx_frame_errors++; + } + + /* Do nothing for IPG_RFS_RXFCSERROR, error count + * handled by a IPG statistic register. + */ + + /* Free the memory associated with the RX + * buffer since it is erroneous and we will + * not pass it to higher layer processes. + */ + if (sp->RxBuff[entry]) { + pci_unmap_single(sp->pdev, + le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN), + sp->rx_buf_sz, PCI_DMA_FROMDEVICE); + + IPG_DEV_KFREE_SKB(sp->RxBuff[entry]); + sp->RxBuff[entry] = NULL; + } + return ErrorPacket; + } + return NormalPacket; +} + +static void ipg_nic_rx_with_start_and_end(struct net_device *dev, + struct ipg_nic_private *sp, + struct ipg_rx *rxfd, unsigned entry) +{ + struct SJumbo *jumbo = &sp->Jumbo; + struct sk_buff *skb; + int framelen; + + if (jumbo->FoundStart) { + IPG_DEV_KFREE_SKB(jumbo->skb); + jumbo->FoundStart = 0; + jumbo->CurrentSize = 0; + jumbo->skb = NULL; + } + + // 1: found error, 0 no error + if (ipg_nic_rx_check_error(dev) != NormalPacket) + return; + + skb = sp->RxBuff[entry]; + if (!skb) + return; + + // accept this frame and send to upper layer + framelen = le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFRAMELEN; + if (framelen > IPG_RXFRAG_SIZE) + framelen = IPG_RXFRAG_SIZE; + + skb_put(skb, framelen); + skb->protocol = eth_type_trans(skb, dev); + skb->ip_summed = CHECKSUM_NONE; + netif_rx(skb); + dev->last_rx = jiffies; + sp->RxBuff[entry] = NULL; +} + +static void ipg_nic_rx_with_start(struct net_device *dev, + struct ipg_nic_private *sp, + struct ipg_rx *rxfd, unsigned entry) +{ + struct SJumbo *jumbo = &sp->Jumbo; + struct pci_dev *pdev = sp->pdev; + struct sk_buff *skb; + + // 1: found error, 0 no error + if (ipg_nic_rx_check_error(dev) != NormalPacket) + return; + + // accept this frame and send to upper layer + skb = sp->RxBuff[entry]; + if (!skb) + return; + + if (jumbo->FoundStart) + IPG_DEV_KFREE_SKB(jumbo->skb); + + pci_unmap_single(pdev, le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN), + sp->rx_buf_sz, PCI_DMA_FROMDEVICE); + + skb_put(skb, IPG_RXFRAG_SIZE); + + jumbo->FoundStart = 1; + jumbo->CurrentSize = IPG_RXFRAG_SIZE; + jumbo->skb = skb; + + sp->RxBuff[entry] = NULL; + dev->last_rx = jiffies; +} + +static void ipg_nic_rx_with_end(struct net_device *dev, + struct ipg_nic_private *sp, + struct ipg_rx *rxfd, unsigned entry) +{ + struct SJumbo *jumbo = &sp->Jumbo; + + //1: found error, 0 no error + if (ipg_nic_rx_check_error(dev) == NormalPacket) { + struct sk_buff *skb = sp->RxBuff[entry]; + + if (!skb) + return; + + if (jumbo->FoundStart) { + int framelen, endframelen; + + framelen = le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFRAMELEN; + + endframeLen = framelen - jumbo->CurrentSize; + /* + if (framelen > IPG_RXFRAG_SIZE) + framelen=IPG_RXFRAG_SIZE; + */ + if (framelen > IPG_RXSUPPORT_SIZE) + IPG_DEV_KFREE_SKB(jumbo->skb); + else { + memcpy(skb_put(jumbo->skb, endframeLen), + skb->data, endframeLen); + + jumbo->skb->protocol = + eth_type_trans(jumbo->skb, dev); + + jumbo->skb->ip_summed = CHECKSUM_NONE; + netif_rx(jumbo->skb); + } + } + + dev->last_rx = jiffies; + jumbo->FoundStart = 0; + jumbo->CurrentSize = 0; + jumbo->skb = NULL; + + ipg_nic_rx_free_skb(dev); + } else { + IPG_DEV_KFREE_SKB(jumbo->skb); + jumbo->FoundStart = 0; + jumbo->CurrentSize = 0; + jumbo->skb = NULL; + } +} + +static void ipg_nic_rx_no_start_no_end(struct net_device *dev, + struct ipg_nic_private *sp, + struct ipg_rx *rxfd, unsigned entry) +{ + struct SJumbo *jumbo = &sp->Jumbo; + + //1: found error, 0 no error + if (ipg_nic_rx_check_error(dev) == NormalPacket) { + struct sk_buff *skb = sp->RxBuff[entry]; + + if (skb) { + if (jumbo->FoundStart) { + jumbo->CurrentSize += IPG_RXFRAG_SIZE; + if (jumbo->CurrentSize <= IPG_RXSUPPORT_SIZE) { + memcpy(skb_put(jumbo->skb, + IPG_RXFRAG_SIZE), + skb->data, IPG_RXFRAG_SIZE); + } + } + dev->last_rx = jiffies; + ipg_nic_rx_free_skb(dev); + } + } else { + IPG_DEV_KFREE_SKB(jumbo->skb); + jumbo->FoundStart = 0; + jumbo->CurrentSize = 0; + jumbo->skb = NULL; + } +} + +static int ipg_nic_rx(struct net_device *dev) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + unsigned int curr = sp->rx_current; + void __iomem *ioaddr = sp->ioaddr; + unsigned int i; + + IPG_DEBUG_MSG("_nic_rx\n"); + + for (i = 0; i < IPG_MAXRFDPROCESS_COUNT; i++, curr++) { + unsigned int entry = curr % IPG_RFDLIST_LENGTH; + struct ipg_rx *rxfd = sp->rxd + entry; + + if (!(rxfd->rfs & le64_to_cpu(IPG_RFS_RFDDONE))) + break; + + switch (ipg_nic_rx_check_frame_type(dev)) { + case Frame_WithStart_WithEnd: + ipg_nic_rx_with_start_and_end(dev, tp, rxfd, entry); + break; + case Frame_WithStart: + ipg_nic_rx_with_start(dev, tp, rxfd, entry); + break; + case Frame_WithEnd: + ipg_nic_rx_with_end(dev, tp, rxfd, entry); + break; + case Frame_NoStart_NoEnd: + ipg_nic_rx_no_start_no_end(dev, tp, rxfd, entry); + break; + } + } + + sp->rx_current = curr; + + if (i == IPG_MAXRFDPROCESS_COUNT) { + /* There are more RFDs to process, however the + * allocated amount of RFD processing time has + * expired. Assert Interrupt Requested to make + * sure we come back to process the remaining RFDs. + */ + ipg_w32(ipg_r32(ASIC_CTRL) | IPG_AC_INT_REQUEST, ASIC_CTRL); + } + + ipg_nic_rxrestore(dev); + + return 0; +} + +#else +static int ipg_nic_rx(struct net_device *dev) +{ + /* Transfer received Ethernet frames to higher network layers. */ + struct ipg_nic_private *sp = netdev_priv(dev); + unsigned int curr = sp->rx_current; + void __iomem *ioaddr = sp->ioaddr; + struct ipg_rx *rxfd; + unsigned int i; + + IPG_DEBUG_MSG("_nic_rx\n"); + +#define __RFS_MASK \ + cpu_to_le64(IPG_RFS_RFDDONE | IPG_RFS_FRAMESTART | IPG_RFS_FRAMEEND) + + for (i = 0; i < IPG_MAXRFDPROCESS_COUNT; i++, curr++) { + unsigned int entry = curr % IPG_RFDLIST_LENGTH; + struct sk_buff *skb = sp->RxBuff[entry]; + unsigned int framelen; + + rxfd = sp->rxd + entry; + + if (((rxfd->rfs & __RFS_MASK) != __RFS_MASK) || !skb) + break; + + /* Get received frame length. */ + framelen = le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFRAMELEN; + + /* Check for jumbo frame arrival with too small + * RXFRAG_SIZE. + */ + if (framelen > IPG_RXFRAG_SIZE) { + IPG_DEBUG_MSG + ("RFS FrameLen > allocated fragment size.\n"); + + framelen = IPG_RXFRAG_SIZE; + } + + if ((IPG_DROP_ON_RX_ETH_ERRORS && (le64_to_cpu(rxfd->rfs & + (IPG_RFS_RXFIFOOVERRUN | IPG_RFS_RXRUNTFRAME | + IPG_RFS_RXALIGNMENTERROR | IPG_RFS_RXFCSERROR | + IPG_RFS_RXOVERSIZEDFRAME | IPG_RFS_RXLENGTHERROR))))) { + + IPG_DEBUG_MSG("Rx error, RFS = %16.16lx\n", + (unsigned long int) rxfd->rfs); + + /* Increment general receive error statistic. */ + sp->stats.rx_errors++; + + /* Increment detailed receive error statistics. */ + if (le64_to_cpu(rxfd->rfs & IPG_RFS_RXFIFOOVERRUN)) { + IPG_DEBUG_MSG("RX FIFO overrun occured.\n"); + sp->stats.rx_fifo_errors++; + } + + if (le64_to_cpu(rxfd->rfs & IPG_RFS_RXRUNTFRAME)) { + IPG_DEBUG_MSG("RX runt occured.\n"); + sp->stats.rx_length_errors++; + } + + if (le64_to_cpu(rxfd->rfs & IPG_RFS_RXOVERSIZEDFRAME)) ; + /* Do nothing, error count handled by a IPG + * statistic register. + */ + + if (le64_to_cpu(rxfd->rfs & IPG_RFS_RXALIGNMENTERROR)) { + IPG_DEBUG_MSG("RX alignment error occured.\n"); + sp->stats.rx_frame_errors++; + } + + if (le64_to_cpu(rxfd->rfs & IPG_RFS_RXFCSERROR)) ; + /* Do nothing, error count handled by a IPG + * statistic register. + */ + + /* Free the memory associated with the RX + * buffer since it is erroneous and we will + * not pass it to higher layer processes. + */ + if (skb) { + u64 info = rxfd->frag_info; + + pci_unmap_single(sp->pdev, + le64_to_cpu(info & ~IPG_RFI_FRAGLEN), + sp->rx_buf_sz, PCI_DMA_FROMDEVICE); + + IPG_DEV_KFREE_SKB(skb); + } + } else { + + /* Adjust the new buffer length to accomodate the size + * of the received frame. + */ + skb_put(skb, framelen); + + /* Set the buffer's protocol field to Ethernet. */ + skb->protocol = eth_type_trans(skb, dev); + + /* If the frame contains an IP/TCP/UDP frame, + * determine if upper layer must check IP/TCP/UDP + * checksums. + * + * NOTE: DO NOT RELY ON THE TCP/UDP CHECKSUM + * VERIFICATION FOR SILICON REVISIONS B3 + * AND EARLIER! + * + if ((le64_to_cpu(rxfd->rfs & + (IPG_RFS_TCPDETECTED | IPG_RFS_UDPDETECTED | + IPG_RFS_IPDETECTED))) && + !(le64_to_cpu(rxfd->rfs & + (IPG_RFS_TCPERROR | IPG_RFS_UDPERROR | + IPG_RFS_IPERROR)))) { + * Indicate IP checksums were performed + * by the IPG. + * + skb->ip_summed = CHECKSUM_UNNECESSARY; + } else + */ + { + /* The IPG encountered an error with (or + * there were no) IP/TCP/UDP checksums. + * This may or may not indicate an invalid + * IP/TCP/UDP frame was received. Let the + * upper layer decide. + */ + skb->ip_summed = CHECKSUM_NONE; + } + + /* Hand off frame for higher layer processing. + * The function netif_rx() releases the sk_buff + * when processing completes. + */ + netif_rx(skb); + + /* Record frame receive time (jiffies = Linux + * kernel current time stamp). + */ + dev->last_rx = jiffies; + } + + /* Assure RX buffer is not reused by IPG. */ + sp->RxBuff[entry] = NULL; + } + + /* + * If there are more RFDs to proces and the allocated amount of RFD + * processing time has expired, assert Interrupt Requested to make + * sure we come back to process the remaining RFDs. + */ + if (i == IPG_MAXRFDPROCESS_COUNT) + ipg_w32(ipg_r32(ASIC_CTRL) | IPG_AC_INT_REQUEST, ASIC_CTRL); + +#ifdef IPG_DEBUG + /* Check if the RFD list contained no receive frame data. */ + if (!i) + sp->EmptyRFDListCount++; +#endif + while ((le64_to_cpu(rxfd->rfs & IPG_RFS_RFDDONE)) && + !((le64_to_cpu(rxfd->rfs & IPG_RFS_FRAMESTART)) && + (le64_to_cpu(rxfd->rfs & IPG_RFS_FRAMEEND)))) { + unsigned int entry = curr++ % IPG_RFDLIST_LENGTH; + + rxfd = sp->rxd + entry; + + IPG_DEBUG_MSG("Frame requires multiple RFDs.\n"); + + /* An unexpected event, additional code needed to handle + * properly. So for the time being, just disregard the + * frame. + */ + + /* Free the memory associated with the RX + * buffer since it is erroneous and we will + * not pass it to higher layer processes. + */ + if (sp->RxBuff[entry]) { + pci_unmap_single(sp->pdev, + le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN), + sp->rx_buf_sz, PCI_DMA_FROMDEVICE); + IPG_DEV_KFREE_SKB(sp->RxBuff[entry]); + } + + /* Assure RX buffer is not reused by IPG. */ + sp->RxBuff[entry] = NULL; + } + + sp->rx_current = curr; + + /* Check to see if there are a minimum number of used + * RFDs before restoring any (should improve performance.) + */ + if ((curr - sp->rx_dirty) >= IPG_MINUSEDRFDSTOFREE) + ipg_nic_rxrestore(dev); + + return 0; +} +#endif + +static void ipg_reset_after_host_error(struct work_struct *work) +{ + struct ipg_nic_private *sp = + container_of(work, struct ipg_nic_private, task.work); + struct net_device *dev = sp->dev; + + IPG_DDEBUG_MSG("DMACtrl = %8.8x\n", ioread32(sp->ioaddr + IPG_DMACTRL)); + + /* + * Acknowledge HostError interrupt by resetting + * IPG DMA and HOST. + */ + ipg_reset(dev, IPG_AC_GLOBAL_RESET | IPG_AC_HOST | IPG_AC_DMA); + + init_rfdlist(dev); + init_tfdlist(dev); + + if (ipg_io_config(dev) < 0) { + printk(KERN_INFO "%s: Cannot recover from PCI error.\n", + dev->name); + schedule_delayed_work(&sp->task, HZ); + } +} + +static irqreturn_t ipg_interrupt_handler(int irq, void *dev_inst) +{ + struct net_device *dev = dev_inst; + struct ipg_nic_private *sp = netdev_priv(dev); + void __iomem *ioaddr = sp->ioaddr; + unsigned int handled = 0; + u16 status; + + IPG_DEBUG_MSG("_interrupt_handler\n"); + +#ifdef JUMBO_FRAME + ipg_nic_rxrestore(dev); +#endif + /* Get interrupt source information, and acknowledge + * some (i.e. TxDMAComplete, RxDMAComplete, RxEarly, + * IntRequested, MacControlFrame, LinkEvent) interrupts + * if issued. Also, all IPG interrupts are disabled by + * reading IntStatusAck. + */ + status = ipg_r16(INT_STATUS_ACK); + + IPG_DEBUG_MSG("IntStatusAck = %4.4x\n", status); + + /* Shared IRQ of remove event. */ + if (!(status & IPG_IS_RSVD_MASK)) + goto out_enable; + + handled = 1; + + if (unlikely(!netif_running(dev))) + goto out; + + spin_lock(&sp->lock); + + /* If RFDListEnd interrupt, restore all used RFDs. */ + if (status & IPG_IS_RFD_LIST_END) { + IPG_DEBUG_MSG("RFDListEnd Interrupt.\n"); + + /* The RFD list end indicates an RFD was encountered + * with a 0 NextPtr, or with an RFDDone bit set to 1 + * (indicating the RFD is not read for use by the + * IPG.) Try to restore all RFDs. + */ + ipg_nic_rxrestore(dev); + +#ifdef IPG_DEBUG + /* Increment the RFDlistendCount counter. */ + sp->RFDlistendCount++; +#endif + } + + /* If RFDListEnd, RxDMAPriority, RxDMAComplete, or + * IntRequested interrupt, process received frames. */ + if ((status & IPG_IS_RX_DMA_PRIORITY) || + (status & IPG_IS_RFD_LIST_END) || + (status & IPG_IS_RX_DMA_COMPLETE) || + (status & IPG_IS_INT_REQUESTED)) { +#ifdef IPG_DEBUG + /* Increment the RFD list checked counter if interrupted + * only to check the RFD list. */ + if (status & (~(IPG_IS_RX_DMA_PRIORITY | IPG_IS_RFD_LIST_END | + IPG_IS_RX_DMA_COMPLETE | IPG_IS_INT_REQUESTED) & + (IPG_IS_HOST_ERROR | IPG_IS_TX_DMA_COMPLETE | + IPG_IS_LINK_EVENT | IPG_IS_TX_COMPLETE | + IPG_IS_UPDATE_STATS))) + sp->RFDListCheckedCount++; +#endif + + ipg_nic_rx(dev); + } + + /* If TxDMAComplete interrupt, free used TFDs. */ + if (status & IPG_IS_TX_DMA_COMPLETE) + ipg_nic_txfree(dev); + + /* TxComplete interrupts indicate one of numerous actions. + * Determine what action to take based on TXSTATUS register. + */ + if (status & IPG_IS_TX_COMPLETE) + ipg_nic_txcleanup(dev); + + /* If UpdateStats interrupt, update Linux Ethernet statistics */ + if (status & IPG_IS_UPDATE_STATS) + ipg_nic_get_stats(dev); + + /* If HostError interrupt, reset IPG. */ + if (status & IPG_IS_HOST_ERROR) { + IPG_DDEBUG_MSG("HostError Interrupt\n"); + + schedule_delayed_work(&sp->task, 0); + } + + /* If LinkEvent interrupt, resolve autonegotiation. */ + if (status & IPG_IS_LINK_EVENT) { + if (ipg_config_autoneg(dev) < 0) + printk(KERN_INFO "%s: Auto-negotiation error.\n", + dev->name); + } + + /* If MACCtrlFrame interrupt, do nothing. */ + if (status & IPG_IS_MAC_CTRL_FRAME) + IPG_DEBUG_MSG("MACCtrlFrame interrupt.\n"); + + /* If RxComplete interrupt, do nothing. */ + if (status & IPG_IS_RX_COMPLETE) + IPG_DEBUG_MSG("RxComplete interrupt.\n"); + + /* If RxEarly interrupt, do nothing. */ + if (status & IPG_IS_RX_EARLY) + IPG_DEBUG_MSG("RxEarly interrupt.\n"); + +out_enable: + /* Re-enable IPG interrupts. */ + ipg_w16(IPG_IE_TX_DMA_COMPLETE | IPG_IE_RX_DMA_COMPLETE | + IPG_IE_HOST_ERROR | IPG_IE_INT_REQUESTED | IPG_IE_TX_COMPLETE | + IPG_IE_LINK_EVENT | IPG_IE_UPDATE_STATS, INT_ENABLE); + + spin_unlock(&sp->lock); +out: + return IRQ_RETVAL(handled); +} + +static void ipg_rx_clear(struct ipg_nic_private *sp) +{ + unsigned int i; + + for (i = 0; i < IPG_RFDLIST_LENGTH; i++) { + if (sp->RxBuff[i]) { + struct ipg_rx *rxfd = sp->rxd + i; + + IPG_DEV_KFREE_SKB(sp->RxBuff[i]); + sp->RxBuff[i] = NULL; + pci_unmap_single(sp->pdev, + le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN), + sp->rx_buf_sz, PCI_DMA_FROMDEVICE); + } + } +} + +static void ipg_tx_clear(struct ipg_nic_private *sp) +{ + unsigned int i; + + for (i = 0; i < IPG_TFDLIST_LENGTH; i++) { + if (sp->TxBuff[i]) { + struct ipg_tx *txfd = sp->txd + i; + + pci_unmap_single(sp->pdev, + le64_to_cpu(txfd->frag_info & ~IPG_TFI_FRAGLEN), + sp->TxBuff[i]->len, PCI_DMA_TODEVICE); + + IPG_DEV_KFREE_SKB(sp->TxBuff[i]); + + sp->TxBuff[i] = NULL; + } + } +} + +static int ipg_nic_open(struct net_device *dev) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + void __iomem *ioaddr = sp->ioaddr; + struct pci_dev *pdev = sp->pdev; + int rc; + + IPG_DEBUG_MSG("_nic_open\n"); + + sp->rx_buf_sz = IPG_RXSUPPORT_SIZE; + + /* Check for interrupt line conflicts, and request interrupt + * line for IPG. + * + * IMPORTANT: Disable IPG interrupts prior to registering + * IRQ. + */ + ipg_w16(0x0000, INT_ENABLE); + + /* Register the interrupt line to be used by the IPG within + * the Linux system. + */ + rc = request_irq(pdev->irq, &ipg_interrupt_handler, IRQF_SHARED, + dev->name, dev); + if (rc < 0) { + printk(KERN_INFO "%s: Error when requesting interrupt.\n", + dev->name); + goto out; + } + + dev->irq = pdev->irq; + + rc = -ENOMEM; + + sp->rxd = dma_alloc_coherent(&pdev->dev, IPG_RX_RING_BYTES, + &sp->rxd_map, GFP_KERNEL); + if (!sp->rxd) + goto err_free_irq_0; + + sp->txd = dma_alloc_coherent(&pdev->dev, IPG_TX_RING_BYTES, + &sp->txd_map, GFP_KERNEL); + if (!sp->txd) + goto err_free_rx_1; + + rc = init_rfdlist(dev); + if (rc < 0) { + printk(KERN_INFO "%s: Error during configuration.\n", + dev->name); + goto err_free_tx_2; + } + + init_tfdlist(dev); + + rc = ipg_io_config(dev); + if (rc < 0) { + printk(KERN_INFO "%s: Error during configuration.\n", + dev->name); + goto err_release_tfdlist_3; + } + + /* Resolve autonegotiation. */ + if (ipg_config_autoneg(dev) < 0) + printk(KERN_INFO "%s: Auto-negotiation error.\n", dev->name); + +#ifdef JUMBO_FRAME + /* initialize JUMBO Frame control variable */ + sp->Jumbo.FoundStart = 0; + sp->Jumbo.CurrentSize = 0; + sp->Jumbo.skb = 0; + dev->mtu = IPG_TXFRAG_SIZE; +#endif + + /* Enable transmit and receive operation of the IPG. */ + ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_RX_ENABLE | IPG_MC_TX_ENABLE) & + IPG_MC_RSVD_MASK, MAC_CTRL); + + netif_start_queue(dev); +out: + return rc; + +err_release_tfdlist_3: + ipg_tx_clear(sp); + ipg_rx_clear(sp); +err_free_tx_2: + dma_free_coherent(&pdev->dev, IPG_TX_RING_BYTES, sp->txd, sp->txd_map); +err_free_rx_1: + dma_free_coherent(&pdev->dev, IPG_RX_RING_BYTES, sp->rxd, sp->rxd_map); +err_free_irq_0: + free_irq(pdev->irq, dev); + goto out; +} + +static int ipg_nic_stop(struct net_device *dev) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + void __iomem *ioaddr = sp->ioaddr; + struct pci_dev *pdev = sp->pdev; + + IPG_DEBUG_MSG("_nic_stop\n"); + + netif_stop_queue(dev); + + IPG_DDEBUG_MSG("RFDlistendCount = %i\n", sp->RFDlistendCount); + IPG_DDEBUG_MSG("RFDListCheckedCount = %i\n", sp->rxdCheckedCount); + IPG_DDEBUG_MSG("EmptyRFDListCount = %i\n", sp->EmptyRFDListCount); + IPG_DUMPTFDLIST(dev); + + do { + (void) ipg_r16(INT_STATUS_ACK); + + ipg_reset(dev, IPG_AC_GLOBAL_RESET | IPG_AC_HOST | IPG_AC_DMA); + + synchronize_irq(pdev->irq); + } while (ipg_r16(INT_ENABLE) & IPG_IE_RSVD_MASK); + + ipg_rx_clear(sp); + + ipg_tx_clear(sp); + + pci_free_consistent(pdev, IPG_RX_RING_BYTES, sp->rxd, sp->rxd_map); + pci_free_consistent(pdev, IPG_TX_RING_BYTES, sp->txd, sp->txd_map); + + free_irq(pdev->irq, dev); + + return 0; +} + +static int ipg_nic_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + void __iomem *ioaddr = sp->ioaddr; + unsigned int entry = sp->tx_current % IPG_TFDLIST_LENGTH; + unsigned long flags; + struct ipg_tx *txfd; + + IPG_DDEBUG_MSG("_nic_hard_start_xmit\n"); + + /* If in 10Mbps mode, stop the transmit queue so + * no more transmit frames are accepted. + */ + if (sp->tenmbpsmode) + netif_stop_queue(dev); + + if (sp->ResetCurrentTFD) { + sp->ResetCurrentTFD = 0; + entry = 0; + } + + txfd = sp->txd + entry; + + sp->TxBuff[entry] = skb; + + /* Clear all TFC fields, except TFDDONE. */ + txfd->tfc = cpu_to_le64(IPG_TFC_TFDDONE); + + /* Specify the TFC field within the TFD. */ + txfd->tfc |= cpu_to_le64(IPG_TFC_WORDALIGNDISABLED | + (IPG_TFC_FRAMEID & cpu_to_le64(sp->tx_current)) | + (IPG_TFC_FRAGCOUNT & (1 << 24))); + + /* Request TxComplete interrupts at an interval defined + * by the constant IPG_FRAMESBETWEENTXCOMPLETES. + * Request TxComplete interrupt for every frame + * if in 10Mbps mode to accomodate problem with 10Mbps + * processing. + */ + if (sp->tenmbpsmode) + txfd->tfc |= cpu_to_le64(IPG_TFC_TXINDICATE); + else if (!((sp->tx_current - sp->tx_dirty + 1) > + IPG_FRAMESBETWEENTXDMACOMPLETES)) { + txfd->tfc |= cpu_to_le64(IPG_TFC_TXDMAINDICATE); + } + /* Based on compilation option, determine if FCS is to be + * appended to transmit frame by IPG. + */ + if (!(IPG_APPEND_FCS_ON_TX)) + txfd->tfc |= cpu_to_le64(IPG_TFC_FCSAPPENDDISABLE); + + /* Based on compilation option, determine if IP, TCP and/or + * UDP checksums are to be added to transmit frame by IPG. + */ + if (IPG_ADD_IPCHECKSUM_ON_TX) + txfd->tfc |= cpu_to_le64(IPG_TFC_IPCHECKSUMENABLE); + + if (IPG_ADD_TCPCHECKSUM_ON_TX) + txfd->tfc |= cpu_to_le64(IPG_TFC_TCPCHECKSUMENABLE); + + if (IPG_ADD_UDPCHECKSUM_ON_TX) + txfd->tfc |= cpu_to_le64(IPG_TFC_UDPCHECKSUMENABLE); + + /* Based on compilation option, determine if VLAN tag info is to be + * inserted into transmit frame by IPG. + */ + if (IPG_INSERT_MANUAL_VLAN_TAG) { + txfd->tfc |= cpu_to_le64(IPG_TFC_VLANTAGINSERT | + ((u64) IPG_MANUAL_VLAN_VID << 32) | + ((u64) IPG_MANUAL_VLAN_CFI << 44) | + ((u64) IPG_MANUAL_VLAN_USERPRIORITY << 45)); + } + + /* The fragment start location within system memory is defined + * by the sk_buff structure's data field. The physical address + * of this location within the system's virtual memory space + * is determined using the IPG_HOST2BUS_MAP function. + */ + txfd->frag_info = cpu_to_le64(pci_map_single(sp->pdev, skb->data, + skb->len, PCI_DMA_TODEVICE)); + + /* The length of the fragment within system memory is defined by + * the sk_buff structure's len field. + */ + txfd->frag_info |= cpu_to_le64(IPG_TFI_FRAGLEN & + ((u64) (skb->len & 0xffff) << 48)); + + /* Clear the TFDDone bit last to indicate the TFD is ready + * for transfer to the IPG. + */ + txfd->tfc &= cpu_to_le64(~IPG_TFC_TFDDONE); + + spin_lock_irqsave(&sp->lock, flags); + + sp->tx_current++; + + mmiowb(); + + ipg_w32(IPG_DC_TX_DMA_POLL_NOW, DMA_CTRL); + + if (sp->tx_current == (sp->tx_dirty + IPG_TFDLIST_LENGTH)) + netif_wake_queue(dev); + + spin_unlock_irqrestore(&sp->lock, flags); + + return NETDEV_TX_OK; +} + +static void ipg_set_phy_default_param(unsigned char rev, + struct net_device *dev, int phy_address) +{ + unsigned short length; + unsigned char revision; + unsigned short *phy_param; + unsigned short address, value; + + phy_param = &DefaultPhyParam[0]; + length = *phy_param & 0x00FF; + revision = (unsigned char)((*phy_param) >> 8); + phy_param++; + while (length != 0) { + if (rev == revision) { + while (length > 1) { + address = *phy_param; + value = *(phy_param + 1); + phy_param += 2; + mdio_write(dev, phy_address, address, value); + length -= 4; + } + break; + } else { + phy_param += length / 2; + length = *phy_param & 0x00FF; + revision = (unsigned char)((*phy_param) >> 8); + phy_param++; + } + } +} + +/* JES20040127EEPROM */ +static int read_eeprom(struct net_device *dev, int eep_addr) +{ + void __iomem *ioaddr = ipg_ioaddr(dev); + unsigned int i; + int ret = 0; + u16 value; + + value = IPG_EC_EEPROM_READOPCODE | (eep_addr & 0xff); + ipg_w16(value, EEPROM_CTRL); + + for (i = 0; i < 1000; i++) { + u16 data; + + mdelay(10); + data = ipg_r16(EEPROM_CTRL); + if (!(data & IPG_EC_EEPROM_BUSY)) { + ret = ipg_r16(EEPROM_DATA); + break; + } + } + return ret; +} + +static void ipg_init_mii(struct net_device *dev) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + struct mii_if_info *mii_if = &sp->mii_if; + int phyaddr; + + mii_if->dev = dev; + mii_if->mdio_read = mdio_read; + mii_if->mdio_write = mdio_write; + mii_if->phy_id_mask = 0x1f; + mii_if->reg_num_mask = 0x1f; + + mii_if->phy_id = phyaddr = ipg_find_phyaddr(dev); + + if (phyaddr != 0x1f) { + u16 mii_phyctrl, mii_1000cr; + u8 revisionid = 0; + + mii_1000cr = mdio_read(dev, phyaddr, MII_CTRL1000); + mii_1000cr |= ADVERTISE_1000FULL | ADVERTISE_1000HALF | + GMII_PHY_1000BASETCONTROL_PreferMaster; + mdio_write(dev, phyaddr, MII_CTRL1000, mii_1000cr); + + mii_phyctrl = mdio_read(dev, phyaddr, MII_BMCR); + + /* Set default phyparam */ + pci_read_config_byte(sp->pdev, PCI_REVISION_ID, &revisionid); + ipg_set_phy_default_param(revisionid, dev, phyaddr); + + /* Reset PHY */ + mii_phyctrl |= BMCR_RESET | BMCR_ANRESTART; + mdio_write(dev, phyaddr, MII_BMCR, mii_phyctrl); + + } +} + +static int ipg_hw_init(struct net_device *dev) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + void __iomem *ioaddr = sp->ioaddr; + unsigned int i; + int rc; + + /* Read/Write and Reset EEPROM Value Jesse20040128EEPROM_VALUE */ + /* Read LED Mode Configuration from EEPROM */ + sp->LED_Mode = read_eeprom(dev, 6); + + /* Reset all functions within the IPG. Do not assert + * RST_OUT as not compatible with some PHYs. + */ + rc = ipg_reset(dev, IPG_RESET_MASK); + if (rc < 0) + goto out; + + ipg_init_mii(dev); + + /* Read MAC Address from EEPROM */ + for (i = 0; i < 3; i++) + sp->station_addr[i] = read_eeprom(dev, 16 + i); + + for (i = 0; i < 3; i++) + ipg_w16(sp->station_addr[i], STATION_ADDRESS_0 + 2*i); + + /* Set station address in ethernet_device structure. */ + dev->dev_addr[0] = ipg_r16(STATION_ADDRESS_0) & 0x00ff; + dev->dev_addr[1] = (ipg_r16(STATION_ADDRESS_0) & 0xff00) >> 8; + dev->dev_addr[2] = ipg_r16(STATION_ADDRESS_1) & 0x00ff; + dev->dev_addr[3] = (ipg_r16(STATION_ADDRESS_1) & 0xff00) >> 8; + dev->dev_addr[4] = ipg_r16(STATION_ADDRESS_2) & 0x00ff; + dev->dev_addr[5] = (ipg_r16(STATION_ADDRESS_2) & 0xff00) >> 8; +out: + return rc; +} + +static int ipg_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + int rc; + + mutex_lock(&sp->mii_mutex); + rc = generic_mii_ioctl(&sp->mii_if, if_mii(ifr), cmd, NULL); + mutex_unlock(&sp->mii_mutex); + + return rc; +} + +static int ipg_nic_change_mtu(struct net_device *dev, int new_mtu) +{ + /* Function to accomodate changes to Maximum Transfer Unit + * (or MTU) of IPG NIC. Cannot use default function since + * the default will not allow for MTU > 1500 bytes. + */ + + IPG_DEBUG_MSG("_nic_change_mtu\n"); + + /* Check that the new MTU value is between 68 (14 byte header, 46 + * byte payload, 4 byte FCS) and IPG_MAX_RXFRAME_SIZE, which + * corresponds to the MAXFRAMESIZE register in the IPG. + */ + if ((new_mtu < 68) || (new_mtu > IPG_MAX_RXFRAME_SIZE)) + return -EINVAL; + + dev->mtu = new_mtu; + + return 0; +} + +static int ipg_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + int rc; + + mutex_lock(&sp->mii_mutex); + rc = mii_ethtool_gset(&sp->mii_if, cmd); + mutex_unlock(&sp->mii_mutex); + + return rc; +} + +static int ipg_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + int rc; + + mutex_lock(&sp->mii_mutex); + rc = mii_ethtool_sset(&sp->mii_if, cmd); + mutex_unlock(&sp->mii_mutex); + + return rc; +} + +static int ipg_nway_reset(struct net_device *dev) +{ + struct ipg_nic_private *sp = netdev_priv(dev); + int rc; + + mutex_lock(&sp->mii_mutex); + rc = mii_nway_restart(&sp->mii_if); + mutex_unlock(&sp->mii_mutex); + + return rc; +} + +static struct ethtool_ops ipg_ethtool_ops = { + .get_settings = ipg_get_settings, + .set_settings = ipg_set_settings, + .nway_reset = ipg_nway_reset, +}; + +static void ipg_remove(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct ipg_nic_private *sp = netdev_priv(dev); + + IPG_DEBUG_MSG("_remove\n"); + + /* Un-register Ethernet device. */ + unregister_netdev(dev); + + pci_iounmap(pdev, sp->ioaddr); + + pci_release_regions(pdev); + + free_netdev(dev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); +} + +static int __devinit ipg_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + unsigned int i = id->driver_data; + struct ipg_nic_private *sp; + struct net_device *dev; + void __iomem *ioaddr; + int rc; + + rc = pci_enable_device(pdev); + if (rc < 0) + goto out; + + printk(KERN_INFO "%s: %s\n", pci_name(pdev), ipg_brand_name[i]); + + pci_set_master(pdev); + + rc = pci_set_dma_mask(pdev, DMA_40BIT_MASK); + if (rc < 0) { + rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (rc < 0) { + printk(KERN_ERR "%s: DMA config failed.\n", + pci_name(pdev)); + goto err_disable_0; + } + } + + /* + * Initialize net device. + */ + dev = alloc_etherdev(sizeof(struct ipg_nic_private)); + if (!dev) { + printk(KERN_ERR "%s: alloc_etherdev failed\n", pci_name(pdev)); + rc = -ENOMEM; + goto err_disable_0; + } + + sp = netdev_priv(dev); + spin_lock_init(&sp->lock); + mutex_init(&sp->mii_mutex); + + /* Declare IPG NIC functions for Ethernet device methods. + */ + dev->open = &ipg_nic_open; + dev->stop = &ipg_nic_stop; + dev->hard_start_xmit = &ipg_nic_hard_start_xmit; + dev->get_stats = &ipg_nic_get_stats; + dev->set_multicast_list = &ipg_nic_set_multicast_list; + dev->do_ioctl = ipg_ioctl; + dev->tx_timeout = ipg_tx_timeout; + dev->change_mtu = &ipg_nic_change_mtu; + + SET_NETDEV_DEV(dev, &pdev->dev); + SET_ETHTOOL_OPS(dev, &ipg_ethtool_ops); + + rc = pci_request_regions(pdev, DRV_NAME); + if (rc) + goto err_free_dev_1; + + ioaddr = pci_iomap(pdev, 1, pci_resource_len(pdev, 1)); + if (!ioaddr) { + printk(KERN_ERR "%s cannot map MMIO\n", pci_name(pdev)); + rc = -EIO; + goto err_release_regions_2; + } + + /* Save the pointer to the PCI device information. */ + sp->ioaddr = ioaddr; + sp->pdev = pdev; + sp->dev = dev; + + INIT_DELAYED_WORK(&sp->task, ipg_reset_after_host_error); + + pci_set_drvdata(pdev, dev); + + rc = ipg_hw_init(dev); + if (rc < 0) + goto err_unmap_3; + + rc = register_netdev(dev); + if (rc < 0) + goto err_unmap_3; + + printk(KERN_INFO "Ethernet device registered as: %s\n", dev->name); +out: + return rc; + +err_unmap_3: + pci_iounmap(pdev, ioaddr); +err_release_regions_2: + pci_release_regions(pdev); +err_free_dev_1: + free_netdev(dev); +err_disable_0: + pci_disable_device(pdev); + goto out; +} + +static struct pci_driver ipg_pci_driver = { + .name = IPG_DRIVER_NAME, + .id_table = ipg_pci_tbl, + .probe = ipg_probe, + .remove = __devexit_p(ipg_remove), +}; + +static int __init ipg_init_module(void) +{ + return pci_register_driver(&ipg_pci_driver); +} + +static void __exit ipg_exit_module(void) +{ + pci_unregister_driver(&ipg_pci_driver); +} + +module_init(ipg_init_module); +module_exit(ipg_exit_module); diff --git a/drivers/net/ipg.h b/drivers/net/ipg.h new file mode 100644 index 00000000000..1952d0dfd31 --- /dev/null +++ b/drivers/net/ipg.h @@ -0,0 +1,856 @@ +/* + * + * ipg.h + * + * Include file for Gigabit Ethernet device driver for Network + * Interface Cards (NICs) utilizing the Tamarack Microelectronics + * Inc. IPG Gigabit or Triple Speed Ethernet Media Access + * Controller. + * + * Craig Rich + * Sundance Technology, Inc. + * 1485 Saratoga Avenue + * Suite 200 + * San Jose, CA 95129 + * 408 873 4117 + * www.sundanceti.com + * craig_rich@sundanceti.com + */ +#ifndef __LINUX_IPG_H +#define __LINUX_IPG_H + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/*#include */ + +#define DrvVer "2.09d" + +#define IPG_DEV_KFREE_SKB(skb) dev_kfree_skb_irq(skb) + +/* + * Constants + */ + +/* GMII based PHY IDs */ +#define NS 0x2000 +#define MARVELL 0x0141 +#define ICPLUS_PHY 0x243 + +/* NIC Physical Layer Device MII register fields. */ +#define MII_PHY_SELECTOR_IEEE8023 0x0001 +#define MII_PHY_TECHABILITYFIELD 0x1FE0 + +/* GMII_PHY_1000 need to set to prefer master */ +#define GMII_PHY_1000BASETCONTROL_PreferMaster 0x0400 + +/* NIC Physical Layer Device GMII constants. */ +#define GMII_PREAMBLE 0xFFFFFFFF +#define GMII_ST 0x1 +#define GMII_READ 0x2 +#define GMII_WRITE 0x1 +#define GMII_TA_READ_MASK 0x1 +#define GMII_TA_WRITE 0x2 + +/* I/O register offsets. */ +enum ipg_regs { + DMA_CTRL = 0x00, + RX_DMA_STATUS = 0x08, // Unused + reserved + TFD_LIST_PTR_0 = 0x10, + TFD_LIST_PTR_1 = 0x14, + TX_DMA_BURST_THRESH = 0x18, + TX_DMA_URGENT_THRESH = 0x19, + TX_DMA_POLL_PERIOD = 0x1a, + RFD_LIST_PTR_0 = 0x1c, + RFD_LIST_PTR_1 = 0x20, + RX_DMA_BURST_THRESH = 0x24, + RX_DMA_URGENT_THRESH = 0x25, + RX_DMA_POLL_PERIOD = 0x26, + DEBUG_CTRL = 0x2c, + ASIC_CTRL = 0x30, + FIFO_CTRL = 0x38, // Unused + FLOW_OFF_THRESH = 0x3c, + FLOW_ON_THRESH = 0x3e, + EEPROM_DATA = 0x48, + EEPROM_CTRL = 0x4a, + EXPROM_ADDR = 0x4c, // Unused + EXPROM_DATA = 0x50, // Unused + WAKE_EVENT = 0x51, // Unused + COUNTDOWN = 0x54, // Unused + INT_STATUS_ACK = 0x5a, + INT_ENABLE = 0x5c, + INT_STATUS = 0x5e, // Unused + TX_STATUS = 0x60, + MAC_CTRL = 0x6c, + VLAN_TAG = 0x70, // Unused + PHY_SET = 0x75, // JES20040127EEPROM + PHY_CTRL = 0x76, + STATION_ADDRESS_0 = 0x78, + STATION_ADDRESS_1 = 0x7a, + STATION_ADDRESS_2 = 0x7c, + MAX_FRAME_SIZE = 0x86, + RECEIVE_MODE = 0x88, + HASHTABLE_0 = 0x8c, + HASHTABLE_1 = 0x90, + RMON_STATISTICS_MASK = 0x98, + STATISTICS_MASK = 0x9c, + RX_JUMBO_FRAMES = 0xbc, // Unused + TCP_CHECKSUM_ERRORS = 0xc0, // Unused + IP_CHECKSUM_ERRORS = 0xc2, // Unused + UDP_CHECKSUM_ERRORS = 0xc4, // Unused + TX_JUMBO_FRAMES = 0xf4 // Unused +}; + +/* Ethernet MIB statistic register offsets. */ +#define IPG_OCTETRCVOK 0xA8 +#define IPG_MCSTOCTETRCVDOK 0xAC +#define IPG_BCSTOCTETRCVOK 0xB0 +#define IPG_FRAMESRCVDOK 0xB4 +#define IPG_MCSTFRAMESRCVDOK 0xB8 +#define IPG_BCSTFRAMESRCVDOK 0xBE +#define IPG_MACCONTROLFRAMESRCVD 0xC6 +#define IPG_FRAMETOOLONGERRRORS 0xC8 +#define IPG_INRANGELENGTHERRORS 0xCA +#define IPG_FRAMECHECKSEQERRORS 0xCC +#define IPG_FRAMESLOSTRXERRORS 0xCE +#define IPG_OCTETXMTOK 0xD0 +#define IPG_MCSTOCTETXMTOK 0xD4 +#define IPG_BCSTOCTETXMTOK 0xD8 +#define IPG_FRAMESXMTDOK 0xDC +#define IPG_MCSTFRAMESXMTDOK 0xE0 +#define IPG_FRAMESWDEFERREDXMT 0xE4 +#define IPG_LATECOLLISIONS 0xE8 +#define IPG_MULTICOLFRAMES 0xEC +#define IPG_SINGLECOLFRAMES 0xF0 +#define IPG_BCSTFRAMESXMTDOK 0xF6 +#define IPG_CARRIERSENSEERRORS 0xF8 +#define IPG_MACCONTROLFRAMESXMTDOK 0xFA +#define IPG_FRAMESABORTXSCOLLS 0xFC +#define IPG_FRAMESWEXDEFERRAL 0xFE + +/* RMON statistic register offsets. */ +#define IPG_ETHERSTATSCOLLISIONS 0x100 +#define IPG_ETHERSTATSOCTETSTRANSMIT 0x104 +#define IPG_ETHERSTATSPKTSTRANSMIT 0x108 +#define IPG_ETHERSTATSPKTS64OCTESTSTRANSMIT 0x10C +#define IPG_ETHERSTATSPKTS65TO127OCTESTSTRANSMIT 0x110 +#define IPG_ETHERSTATSPKTS128TO255OCTESTSTRANSMIT 0x114 +#define IPG_ETHERSTATSPKTS256TO511OCTESTSTRANSMIT 0x118 +#define IPG_ETHERSTATSPKTS512TO1023OCTESTSTRANSMIT 0x11C +#define IPG_ETHERSTATSPKTS1024TO1518OCTESTSTRANSMIT 0x120 +#define IPG_ETHERSTATSCRCALIGNERRORS 0x124 +#define IPG_ETHERSTATSUNDERSIZEPKTS 0x128 +#define IPG_ETHERSTATSFRAGMENTS 0x12C +#define IPG_ETHERSTATSJABBERS 0x130 +#define IPG_ETHERSTATSOCTETS 0x134 +#define IPG_ETHERSTATSPKTS 0x138 +#define IPG_ETHERSTATSPKTS64OCTESTS 0x13C +#define IPG_ETHERSTATSPKTS65TO127OCTESTS 0x140 +#define IPG_ETHERSTATSPKTS128TO255OCTESTS 0x144 +#define IPG_ETHERSTATSPKTS256TO511OCTESTS 0x148 +#define IPG_ETHERSTATSPKTS512TO1023OCTESTS 0x14C +#define IPG_ETHERSTATSPKTS1024TO1518OCTESTS 0x150 + +/* RMON statistic register equivalents. */ +#define IPG_ETHERSTATSMULTICASTPKTSTRANSMIT 0xE0 +#define IPG_ETHERSTATSBROADCASTPKTSTRANSMIT 0xF6 +#define IPG_ETHERSTATSMULTICASTPKTS 0xB8 +#define IPG_ETHERSTATSBROADCASTPKTS 0xBE +#define IPG_ETHERSTATSOVERSIZEPKTS 0xC8 +#define IPG_ETHERSTATSDROPEVENTS 0xCE + +/* Serial EEPROM offsets */ +#define IPG_EEPROM_CONFIGPARAM 0x00 +#define IPG_EEPROM_ASICCTRL 0x01 +#define IPG_EEPROM_SUBSYSTEMVENDORID 0x02 +#define IPG_EEPROM_SUBSYSTEMID 0x03 +#define IPG_EEPROM_STATIONADDRESS0 0x10 +#define IPG_EEPROM_STATIONADDRESS1 0x11 +#define IPG_EEPROM_STATIONADDRESS2 0x12 + +/* Register & data structure bit masks */ + +/* PCI register masks. */ + +/* IOBaseAddress */ +#define IPG_PIB_RSVD_MASK 0xFFFFFE01 +#define IPG_PIB_IOBASEADDRESS 0xFFFFFF00 +#define IPG_PIB_IOBASEADDRIND 0x00000001 + +/* MemBaseAddress */ +#define IPG_PMB_RSVD_MASK 0xFFFFFE07 +#define IPG_PMB_MEMBASEADDRIND 0x00000001 +#define IPG_PMB_MEMMAPTYPE 0x00000006 +#define IPG_PMB_MEMMAPTYPE0 0x00000002 +#define IPG_PMB_MEMMAPTYPE1 0x00000004 +#define IPG_PMB_MEMBASEADDRESS 0xFFFFFE00 + +/* ConfigStatus */ +#define IPG_CS_RSVD_MASK 0xFFB0 +#define IPG_CS_CAPABILITIES 0x0010 +#define IPG_CS_66MHZCAPABLE 0x0020 +#define IPG_CS_FASTBACK2BACK 0x0080 +#define IPG_CS_DATAPARITYREPORTED 0x0100 +#define IPG_CS_DEVSELTIMING 0x0600 +#define IPG_CS_SIGNALEDTARGETABORT 0x0800 +#define IPG_CS_RECEIVEDTARGETABORT 0x1000 +#define IPG_CS_RECEIVEDMASTERABORT 0x2000 +#define IPG_CS_SIGNALEDSYSTEMERROR 0x4000 +#define IPG_CS_DETECTEDPARITYERROR 0x8000 + +/* TFD data structure masks. */ + +/* TFDList, TFC */ +#define IPG_TFC_RSVD_MASK 0x0000FFFF9FFFFFFF +#define IPG_TFC_FRAMEID 0x000000000000FFFF +#define IPG_TFC_WORDALIGN 0x0000000000030000 +#define IPG_TFC_WORDALIGNTODWORD 0x0000000000000000 +#define IPG_TFC_WORDALIGNTOWORD 0x0000000000020000 +#define IPG_TFC_WORDALIGNDISABLED 0x0000000000030000 +#define IPG_TFC_TCPCHECKSUMENABLE 0x0000000000040000 +#define IPG_TFC_UDPCHECKSUMENABLE 0x0000000000080000 +#define IPG_TFC_IPCHECKSUMENABLE 0x0000000000100000 +#define IPG_TFC_FCSAPPENDDISABLE 0x0000000000200000 +#define IPG_TFC_TXINDICATE 0x0000000000400000 +#define IPG_TFC_TXDMAINDICATE 0x0000000000800000 +#define IPG_TFC_FRAGCOUNT 0x000000000F000000 +#define IPG_TFC_VLANTAGINSERT 0x0000000010000000 +#define IPG_TFC_TFDDONE 0x0000000080000000 +#define IPG_TFC_VID 0x00000FFF00000000 +#define IPG_TFC_CFI 0x0000100000000000 +#define IPG_TFC_USERPRIORITY 0x0000E00000000000 + +/* TFDList, FragInfo */ +#define IPG_TFI_RSVD_MASK 0xFFFF00FFFFFFFFFF +#define IPG_TFI_FRAGADDR 0x000000FFFFFFFFFF +#define IPG_TFI_FRAGLEN 0xFFFF000000000000LL + +/* RFD data structure masks. */ + +/* RFDList, RFS */ +#define IPG_RFS_RSVD_MASK 0x0000FFFFFFFFFFFF +#define IPG_RFS_RXFRAMELEN 0x000000000000FFFF +#define IPG_RFS_RXFIFOOVERRUN 0x0000000000010000 +#define IPG_RFS_RXRUNTFRAME 0x0000000000020000 +#define IPG_RFS_RXALIGNMENTERROR 0x0000000000040000 +#define IPG_RFS_RXFCSERROR 0x0000000000080000 +#define IPG_RFS_RXOVERSIZEDFRAME 0x0000000000100000 +#define IPG_RFS_RXLENGTHERROR 0x0000000000200000 +#define IPG_RFS_VLANDETECTED 0x0000000000400000 +#define IPG_RFS_TCPDETECTED 0x0000000000800000 +#define IPG_RFS_TCPERROR 0x0000000001000000 +#define IPG_RFS_UDPDETECTED 0x0000000002000000 +#define IPG_RFS_UDPERROR 0x0000000004000000 +#define IPG_RFS_IPDETECTED 0x0000000008000000 +#define IPG_RFS_IPERROR 0x0000000010000000 +#define IPG_RFS_FRAMESTART 0x0000000020000000 +#define IPG_RFS_FRAMEEND 0x0000000040000000 +#define IPG_RFS_RFDDONE 0x0000000080000000 +#define IPG_RFS_TCI 0x0000FFFF00000000 + +/* RFDList, FragInfo */ +#define IPG_RFI_RSVD_MASK 0xFFFF00FFFFFFFFFF +#define IPG_RFI_FRAGADDR 0x000000FFFFFFFFFF +#define IPG_RFI_FRAGLEN 0xFFFF000000000000LL + +/* I/O Register masks. */ + +/* RMON Statistics Mask */ +#define IPG_RZ_ALL 0x0FFFFFFF + +/* Statistics Mask */ +#define IPG_SM_ALL 0x0FFFFFFF +#define IPG_SM_OCTETRCVOK_FRAMESRCVDOK 0x00000001 +#define IPG_SM_MCSTOCTETRCVDOK_MCSTFRAMESRCVDOK 0x00000002 +#define IPG_SM_BCSTOCTETRCVDOK_BCSTFRAMESRCVDOK 0x00000004 +#define IPG_SM_RXJUMBOFRAMES 0x00000008 +#define IPG_SM_TCPCHECKSUMERRORS 0x00000010 +#define IPG_SM_IPCHECKSUMERRORS 0x00000020 +#define IPG_SM_UDPCHECKSUMERRORS 0x00000040 +#define IPG_SM_MACCONTROLFRAMESRCVD 0x00000080 +#define IPG_SM_FRAMESTOOLONGERRORS 0x00000100 +#define IPG_SM_INRANGELENGTHERRORS 0x00000200 +#define IPG_SM_FRAMECHECKSEQERRORS 0x00000400 +#define IPG_SM_FRAMESLOSTRXERRORS 0x00000800 +#define IPG_SM_OCTETXMTOK_FRAMESXMTOK 0x00001000 +#define IPG_SM_MCSTOCTETXMTOK_MCSTFRAMESXMTDOK 0x00002000 +#define IPG_SM_BCSTOCTETXMTOK_BCSTFRAMESXMTDOK 0x00004000 +#define IPG_SM_FRAMESWDEFERREDXMT 0x00008000 +#define IPG_SM_LATECOLLISIONS 0x00010000 +#define IPG_SM_MULTICOLFRAMES 0x00020000 +#define IPG_SM_SINGLECOLFRAMES 0x00040000 +#define IPG_SM_TXJUMBOFRAMES 0x00080000 +#define IPG_SM_CARRIERSENSEERRORS 0x00100000 +#define IPG_SM_MACCONTROLFRAMESXMTD 0x00200000 +#define IPG_SM_FRAMESABORTXSCOLLS 0x00400000 +#define IPG_SM_FRAMESWEXDEFERAL 0x00800000 + +/* Countdown */ +#define IPG_CD_RSVD_MASK 0x0700FFFF +#define IPG_CD_COUNT 0x0000FFFF +#define IPG_CD_COUNTDOWNSPEED 0x01000000 +#define IPG_CD_COUNTDOWNMODE 0x02000000 +#define IPG_CD_COUNTINTENABLED 0x04000000 + +/* TxDMABurstThresh */ +#define IPG_TB_RSVD_MASK 0xFF + +/* TxDMAUrgentThresh */ +#define IPG_TU_RSVD_MASK 0xFF + +/* TxDMAPollPeriod */ +#define IPG_TP_RSVD_MASK 0xFF + +/* RxDMAUrgentThresh */ +#define IPG_RU_RSVD_MASK 0xFF + +/* RxDMAPollPeriod */ +#define IPG_RP_RSVD_MASK 0xFF + +/* ReceiveMode */ +#define IPG_RM_RSVD_MASK 0x3F +#define IPG_RM_RECEIVEUNICAST 0x01 +#define IPG_RM_RECEIVEMULTICAST 0x02 +#define IPG_RM_RECEIVEBROADCAST 0x04 +#define IPG_RM_RECEIVEALLFRAMES 0x08 +#define IPG_RM_RECEIVEMULTICASTHASH 0x10 +#define IPG_RM_RECEIVEIPMULTICAST 0x20 + +/* PhySet JES20040127EEPROM*/ +#define IPG_PS_MEM_LENB9B 0x01 +#define IPG_PS_MEM_LEN9 0x02 +#define IPG_PS_NON_COMPDET 0x04 + +/* PhyCtrl */ +#define IPG_PC_RSVD_MASK 0xFF +#define IPG_PC_MGMTCLK_LO 0x00 +#define IPG_PC_MGMTCLK_HI 0x01 +#define IPG_PC_MGMTCLK 0x01 +#define IPG_PC_MGMTDATA 0x02 +#define IPG_PC_MGMTDIR 0x04 +#define IPG_PC_DUPLEX_POLARITY 0x08 +#define IPG_PC_DUPLEX_STATUS 0x10 +#define IPG_PC_LINK_POLARITY 0x20 +#define IPG_PC_LINK_SPEED 0xC0 +#define IPG_PC_LINK_SPEED_10MBPS 0x40 +#define IPG_PC_LINK_SPEED_100MBPS 0x80 +#define IPG_PC_LINK_SPEED_1000MBPS 0xC0 + +/* DMACtrl */ +#define IPG_DC_RSVD_MASK 0xC07D9818 +#define IPG_DC_RX_DMA_COMPLETE 0x00000008 +#define IPG_DC_RX_DMA_POLL_NOW 0x00000010 +#define IPG_DC_TX_DMA_COMPLETE 0x00000800 +#define IPG_DC_TX_DMA_POLL_NOW 0x00001000 +#define IPG_DC_TX_DMA_IN_PROG 0x00008000 +#define IPG_DC_RX_EARLY_DISABLE 0x00010000 +#define IPG_DC_MWI_DISABLE 0x00040000 +#define IPG_DC_TX_WRITE_BACK_DISABLE 0x00080000 +#define IPG_DC_TX_BURST_LIMIT 0x00700000 +#define IPG_DC_TARGET_ABORT 0x40000000 +#define IPG_DC_MASTER_ABORT 0x80000000 + +/* ASICCtrl */ +#define IPG_AC_RSVD_MASK 0x07FFEFF2 +#define IPG_AC_EXP_ROM_SIZE 0x00000002 +#define IPG_AC_PHY_SPEED10 0x00000010 +#define IPG_AC_PHY_SPEED100 0x00000020 +#define IPG_AC_PHY_SPEED1000 0x00000040 +#define IPG_AC_PHY_MEDIA 0x00000080 +#define IPG_AC_FORCED_CFG 0x00000700 +#define IPG_AC_D3RESETDISABLE 0x00000800 +#define IPG_AC_SPEED_UP_MODE 0x00002000 +#define IPG_AC_LED_MODE 0x00004000 +#define IPG_AC_RST_OUT_POLARITY 0x00008000 +#define IPG_AC_GLOBAL_RESET 0x00010000 +#define IPG_AC_RX_RESET 0x00020000 +#define IPG_AC_TX_RESET 0x00040000 +#define IPG_AC_DMA 0x00080000 +#define IPG_AC_FIFO 0x00100000 +#define IPG_AC_NETWORK 0x00200000 +#define IPG_AC_HOST 0x00400000 +#define IPG_AC_AUTO_INIT 0x00800000 +#define IPG_AC_RST_OUT 0x01000000 +#define IPG_AC_INT_REQUEST 0x02000000 +#define IPG_AC_RESET_BUSY 0x04000000 +#define IPG_AC_LED_SPEED 0x08000000 //JES20040127EEPROM +#define IPG_AC_LED_MODE_BIT_1 0x20000000 //JES20040127EEPROM + +/* EepromCtrl */ +#define IPG_EC_RSVD_MASK 0x83FF +#define IPG_EC_EEPROM_ADDR 0x00FF +#define IPG_EC_EEPROM_OPCODE 0x0300 +#define IPG_EC_EEPROM_SUBCOMMAD 0x0000 +#define IPG_EC_EEPROM_WRITEOPCODE 0x0100 +#define IPG_EC_EEPROM_READOPCODE 0x0200 +#define IPG_EC_EEPROM_ERASEOPCODE 0x0300 +#define IPG_EC_EEPROM_BUSY 0x8000 + +/* FIFOCtrl */ +#define IPG_FC_RSVD_MASK 0xC001 +#define IPG_FC_RAM_TEST_MODE 0x0001 +#define IPG_FC_TRANSMITTING 0x4000 +#define IPG_FC_RECEIVING 0x8000 + +/* TxStatus */ +#define IPG_TS_RSVD_MASK 0xFFFF00DD +#define IPG_TS_TX_ERROR 0x00000001 +#define IPG_TS_LATE_COLLISION 0x00000004 +#define IPG_TS_TX_MAX_COLL 0x00000008 +#define IPG_TS_TX_UNDERRUN 0x00000010 +#define IPG_TS_TX_IND_REQD 0x00000040 +#define IPG_TS_TX_COMPLETE 0x00000080 +#define IPG_TS_TX_FRAMEID 0xFFFF0000 + +/* WakeEvent */ +#define IPG_WE_WAKE_PKT_ENABLE 0x01 +#define IPG_WE_MAGIC_PKT_ENABLE 0x02 +#define IPG_WE_LINK_EVT_ENABLE 0x04 +#define IPG_WE_WAKE_POLARITY 0x08 +#define IPG_WE_WAKE_PKT_EVT 0x10 +#define IPG_WE_MAGIC_PKT_EVT 0x20 +#define IPG_WE_LINK_EVT 0x40 +#define IPG_WE_WOL_ENABLE 0x80 + +/* IntEnable */ +#define IPG_IE_RSVD_MASK 0x1FFE +#define IPG_IE_HOST_ERROR 0x0002 +#define IPG_IE_TX_COMPLETE 0x0004 +#define IPG_IE_MAC_CTRL_FRAME 0x0008 +#define IPG_IE_RX_COMPLETE 0x0010 +#define IPG_IE_RX_EARLY 0x0020 +#define IPG_IE_INT_REQUESTED 0x0040 +#define IPG_IE_UPDATE_STATS 0x0080 +#define IPG_IE_LINK_EVENT 0x0100 +#define IPG_IE_TX_DMA_COMPLETE 0x0200 +#define IPG_IE_RX_DMA_COMPLETE 0x0400 +#define IPG_IE_RFD_LIST_END 0x0800 +#define IPG_IE_RX_DMA_PRIORITY 0x1000 + +/* IntStatus */ +#define IPG_IS_RSVD_MASK 0x1FFF +#define IPG_IS_INTERRUPT_STATUS 0x0001 +#define IPG_IS_HOST_ERROR 0x0002 +#define IPG_IS_TX_COMPLETE 0x0004 +#define IPG_IS_MAC_CTRL_FRAME 0x0008 +#define IPG_IS_RX_COMPLETE 0x0010 +#define IPG_IS_RX_EARLY 0x0020 +#define IPG_IS_INT_REQUESTED 0x0040 +#define IPG_IS_UPDATE_STATS 0x0080 +#define IPG_IS_LINK_EVENT 0x0100 +#define IPG_IS_TX_DMA_COMPLETE 0x0200 +#define IPG_IS_RX_DMA_COMPLETE 0x0400 +#define IPG_IS_RFD_LIST_END 0x0800 +#define IPG_IS_RX_DMA_PRIORITY 0x1000 + +/* MACCtrl */ +#define IPG_MC_RSVD_MASK 0x7FE33FA3 +#define IPG_MC_IFS_SELECT 0x00000003 +#define IPG_MC_IFS_4352BIT 0x00000003 +#define IPG_MC_IFS_1792BIT 0x00000002 +#define IPG_MC_IFS_1024BIT 0x00000001 +#define IPG_MC_IFS_96BIT 0x00000000 +#define IPG_MC_DUPLEX_SELECT 0x00000020 +#define IPG_MC_DUPLEX_SELECT_FD 0x00000020 +#define IPG_MC_DUPLEX_SELECT_HD 0x00000000 +#define IPG_MC_TX_FLOW_CONTROL_ENABLE 0x00000080 +#define IPG_MC_RX_FLOW_CONTROL_ENABLE 0x00000100 +#define IPG_MC_RCV_FCS 0x00000200 +#define IPG_MC_FIFO_LOOPBACK 0x00000400 +#define IPG_MC_MAC_LOOPBACK 0x00000800 +#define IPG_MC_AUTO_VLAN_TAGGING 0x00001000 +#define IPG_MC_AUTO_VLAN_UNTAGGING 0x00002000 +#define IPG_MC_COLLISION_DETECT 0x00010000 +#define IPG_MC_CARRIER_SENSE 0x00020000 +#define IPG_MC_STATISTICS_ENABLE 0x00200000 +#define IPG_MC_STATISTICS_DISABLE 0x00400000 +#define IPG_MC_STATISTICS_ENABLED 0x00800000 +#define IPG_MC_TX_ENABLE 0x01000000 +#define IPG_MC_TX_DISABLE 0x02000000 +#define IPG_MC_TX_ENABLED 0x04000000 +#define IPG_MC_RX_ENABLE 0x08000000 +#define IPG_MC_RX_DISABLE 0x10000000 +#define IPG_MC_RX_ENABLED 0x20000000 +#define IPG_MC_PAUSED 0x40000000 + +/* + * Tune + */ + +/* Miscellaneous Constants. */ +#define TRUE 1 +#define FALSE 0 + +/* Assign IPG_APPEND_FCS_ON_TX > 0 for auto FCS append on TX. */ +#define IPG_APPEND_FCS_ON_TX TRUE + +/* Assign IPG_APPEND_FCS_ON_TX > 0 for auto FCS strip on RX. */ +#define IPG_STRIP_FCS_ON_RX TRUE + +/* Assign IPG_DROP_ON_RX_ETH_ERRORS > 0 to drop RX frames with + * Ethernet errors. + */ +#define IPG_DROP_ON_RX_ETH_ERRORS TRUE + +/* Assign IPG_INSERT_MANUAL_VLAN_TAG > 0 to insert VLAN tags manually + * (via TFC). + */ +#define IPG_INSERT_MANUAL_VLAN_TAG FALSE + +/* Assign IPG_ADD_IPCHECKSUM_ON_TX > 0 for auto IP checksum on TX. */ +#define IPG_ADD_IPCHECKSUM_ON_TX FALSE + +/* Assign IPG_ADD_TCPCHECKSUM_ON_TX > 0 for auto TCP checksum on TX. + * DO NOT USE FOR SILICON REVISIONS B3 AND EARLIER. + */ +#define IPG_ADD_TCPCHECKSUM_ON_TX FALSE + +/* Assign IPG_ADD_UDPCHECKSUM_ON_TX > 0 for auto UDP checksum on TX. + * DO NOT USE FOR SILICON REVISIONS B3 AND EARLIER. + */ +#define IPG_ADD_UDPCHECKSUM_ON_TX FALSE + +/* If inserting VLAN tags manually, assign the IPG_MANUAL_VLAN_xx + * constants as desired. + */ +#define IPG_MANUAL_VLAN_VID 0xABC +#define IPG_MANUAL_VLAN_CFI 0x1 +#define IPG_MANUAL_VLAN_USERPRIORITY 0x5 + +#define IPG_IO_REG_RANGE 0xFF +#define IPG_MEM_REG_RANGE 0x154 +#define IPG_DRIVER_NAME "Sundance Technology IPG Triple-Speed Ethernet" +#define IPG_NIC_PHY_ADDRESS 0x01 +#define IPG_DMALIST_ALIGN_PAD 0x07 +#define IPG_MULTICAST_HASHTABLE_SIZE 0x40 + +/* Number of miliseconds to wait after issuing a software reset. + * 0x05 <= IPG_AC_RESETWAIT to account for proper 10Mbps operation. + */ +#define IPG_AC_RESETWAIT 0x05 + +/* Number of IPG_AC_RESETWAIT timeperiods before declaring timeout. */ +#define IPG_AC_RESET_TIMEOUT 0x0A + +/* Minimum number of nanoseconds used to toggle MDC clock during + * MII/GMII register access. + */ +#define IPG_PC_PHYCTRLWAIT_NS 200 + +#define IPG_TFDLIST_LENGTH 0x100 + +/* Number of frames between TxDMAComplete interrupt. + * 0 < IPG_FRAMESBETWEENTXDMACOMPLETES <= IPG_TFDLIST_LENGTH + */ +#define IPG_FRAMESBETWEENTXDMACOMPLETES 0x1 + +#ifdef JUMBO_FRAME + +# ifdef JUMBO_FRAME_SIZE_2K +# define JUMBO_FRAME_SIZE 2048 +# define __IPG_RXFRAG_SIZE 2048 +# else +# ifdef JUMBO_FRAME_SIZE_3K +# define JUMBO_FRAME_SIZE 3072 +# define __IPG_RXFRAG_SIZE 3072 +# else +# ifdef JUMBO_FRAME_SIZE_4K +# define JUMBO_FRAME_SIZE 4096 +# define __IPG_RXFRAG_SIZE 4088 +# else +# ifdef JUMBO_FRAME_SIZE_5K +# define JUMBO_FRAME_SIZE 5120 +# define __IPG_RXFRAG_SIZE 4088 +# else +# ifdef JUMBO_FRAME_SIZE_6K +# define JUMBO_FRAME_SIZE 6144 +# define __IPG_RXFRAG_SIZE 4088 +# else +# ifdef JUMBO_FRAME_SIZE_7K +# define JUMBO_FRAME_SIZE 7168 +# define __IPG_RXFRAG_SIZE 4088 +# else +# ifdef JUMBO_FRAME_SIZE_8K +# define JUMBO_FRAME_SIZE 8192 +# define __IPG_RXFRAG_SIZE 4088 +# else +# ifdef JUMBO_FRAME_SIZE_9K +# define JUMBO_FRAME_SIZE 9216 +# define __IPG_RXFRAG_SIZE 4088 +# else +# ifdef JUMBO_FRAME_SIZE_10K +# define JUMBO_FRAME_SIZE 10240 +# define __IPG_RXFRAG_SIZE 4088 +# else +# define JUMBO_FRAME_SIZE 4096 +# endif +# endif +# endif +# endif +# endif +# endif +# endif +# endif +# endif +#endif + +/* Size of allocated received buffers. Nominally 0x0600. + * Define larger if expecting jumbo frames. + */ +#ifdef JUMBO_FRAME +//IPG_TXFRAG_SIZE must <= 0x2b00, or TX will crash +#define IPG_TXFRAG_SIZE JUMBO_FRAME_SIZE +#endif + +/* Size of allocated received buffers. Nominally 0x0600. + * Define larger if expecting jumbo frames. + */ +#ifdef JUMBO_FRAME +//4088=4096-8 +#define IPG_RXFRAG_SIZE __IPG_RXFRAG_SIZE +#define IPG_RXSUPPORT_SIZE IPG_MAX_RXFRAME_SIZE +#else +#define IPG_RXFRAG_SIZE 0x0600 +#define IPG_RXSUPPORT_SIZE IPG_RXFRAG_SIZE +#endif + +/* IPG_MAX_RXFRAME_SIZE <= IPG_RXFRAG_SIZE */ +#ifdef JUMBO_FRAME +#define IPG_MAX_RXFRAME_SIZE JUMBO_FRAME_SIZE +#else +#define IPG_MAX_RXFRAME_SIZE 0x0600 +#endif + +#define IPG_RFDLIST_LENGTH 0x100 + +/* Maximum number of RFDs to process per interrupt. + * 1 < IPG_MAXRFDPROCESS_COUNT < IPG_RFDLIST_LENGTH + */ +#define IPG_MAXRFDPROCESS_COUNT 0x80 + +/* Minimum margin between last freed RFD, and current RFD. + * 1 < IPG_MINUSEDRFDSTOFREE < IPG_RFDLIST_LENGTH + */ +#define IPG_MINUSEDRFDSTOFREE 0x80 + +/* specify the jumbo frame maximum size + * per unit is 0x600 (the RxBuffer size that one RFD can carry) + */ +#define MAX_JUMBOSIZE 0x8 // max is 12K + +/* Key register values loaded at driver start up. */ + +/* TXDMAPollPeriod is specified in 320ns increments. + * + * Value Time + * --------------------- + * 0x00-0x01 320ns + * 0x03 ~1us + * 0x1F ~10us + * 0xFF ~82us + */ +#define IPG_TXDMAPOLLPERIOD_VALUE 0x26 + +/* TxDMAUrgentThresh specifies the minimum amount of + * data in the transmit FIFO before asserting an + * urgent transmit DMA request. + * + * Value Min TxFIFO occupied space before urgent TX request + * --------------------------------------------------------------- + * 0x00-0x04 128 bytes (1024 bits) + * 0x27 1248 bytes (~10000 bits) + * 0x30 1536 bytes (12288 bits) + * 0xFF 8192 bytes (65535 bits) + */ +#define IPG_TXDMAURGENTTHRESH_VALUE 0x04 + +/* TxDMABurstThresh specifies the minimum amount of + * free space in the transmit FIFO before asserting an + * transmit DMA request. + * + * Value Min TxFIFO free space before TX request + * ---------------------------------------------------- + * 0x00-0x08 256 bytes + * 0x30 1536 bytes + * 0xFF 8192 bytes + */ +#define IPG_TXDMABURSTTHRESH_VALUE 0x30 + +/* RXDMAPollPeriod is specified in 320ns increments. + * + * Value Time + * --------------------- + * 0x00-0x01 320ns + * 0x03 ~1us + * 0x1F ~10us + * 0xFF ~82us + */ +#define IPG_RXDMAPOLLPERIOD_VALUE 0x01 + +/* RxDMAUrgentThresh specifies the minimum amount of + * free space within the receive FIFO before asserting + * a urgent receive DMA request. + * + * Value Min RxFIFO free space before urgent RX request + * --------------------------------------------------------------- + * 0x00-0x04 128 bytes (1024 bits) + * 0x27 1248 bytes (~10000 bits) + * 0x30 1536 bytes (12288 bits) + * 0xFF 8192 bytes (65535 bits) + */ +#define IPG_RXDMAURGENTTHRESH_VALUE 0x30 + +/* RxDMABurstThresh specifies the minimum amount of + * occupied space within the receive FIFO before asserting + * a receive DMA request. + * + * Value Min TxFIFO free space before TX request + * ---------------------------------------------------- + * 0x00-0x08 256 bytes + * 0x30 1536 bytes + * 0xFF 8192 bytes + */ +#define IPG_RXDMABURSTTHRESH_VALUE 0x30 + +/* FlowOnThresh specifies the maximum amount of occupied + * space in the receive FIFO before a PAUSE frame with + * maximum pause time transmitted. + * + * Value Max RxFIFO occupied space before PAUSE + * --------------------------------------------------- + * 0x0000 0 bytes + * 0x0740 29,696 bytes + * 0x07FF 32,752 bytes + */ +#define IPG_FLOWONTHRESH_VALUE 0x0740 + +/* FlowOffThresh specifies the minimum amount of occupied + * space in the receive FIFO before a PAUSE frame with + * zero pause time is transmitted. + * + * Value Max RxFIFO occupied space before PAUSE + * --------------------------------------------------- + * 0x0000 0 bytes + * 0x00BF 3056 bytes + * 0x07FF 32,752 bytes + */ +#define IPG_FLOWOFFTHRESH_VALUE 0x00BF + +/* + * Miscellaneous macros. + */ + +/* Marco for printing debug statements. +# define IPG_DDEBUG_MSG(args...) printk(KERN_DEBUG "IPG: " ## args) */ +#ifdef IPG_DEBUG +# define IPG_DEBUG_MSG(args...) +# define IPG_DDEBUG_MSG(args...) printk(KERN_DEBUG "IPG: " args) +# define IPG_DUMPRFDLIST(args) ipg_dump_rfdlist(args) +# define IPG_DUMPTFDLIST(args) ipg_dump_tfdlist(args) +#else +# define IPG_DEBUG_MSG(args...) +# define IPG_DDEBUG_MSG(args...) +# define IPG_DUMPRFDLIST(args) +# define IPG_DUMPTFDLIST(args) +#endif + +/* + * End miscellaneous macros. + */ + +/* Transmit Frame Descriptor. The IPG supports 15 fragments, + * however Linux requires only a single fragment. Note, each + * TFD field is 64 bits wide. + */ +struct ipg_tx { + u64 next_desc; + u64 tfc; + u64 frag_info; +}; + +/* Receive Frame Descriptor. Note, each RFD field is 64 bits wide. + */ +struct ipg_rx { + u64 next_desc; + u64 rfs; + u64 frag_info; +}; + +struct SJumbo { + int FoundStart; + int CurrentSize; + struct sk_buff *skb; +}; +/* Structure of IPG NIC specific data. */ +struct ipg_nic_private { + void __iomem *ioaddr; + struct ipg_tx *txd; + struct ipg_rx *rxd; + dma_addr_t txd_map; + dma_addr_t rxd_map; + struct sk_buff *TxBuff[IPG_TFDLIST_LENGTH]; + struct sk_buff *RxBuff[IPG_RFDLIST_LENGTH]; + unsigned int tx_current; + unsigned int tx_dirty; + unsigned int rx_current; + unsigned int rx_dirty; +// Add by Grace 2005/05/19 +#ifdef JUMBO_FRAME + struct SJumbo Jumbo; +#endif + unsigned int rx_buf_sz; + struct pci_dev *pdev; + struct net_device *dev; + struct net_device_stats stats; + spinlock_t lock; + int tenmbpsmode; + + /*Jesse20040128EEPROM_VALUE */ + u16 LED_Mode; + u16 station_addr[3]; /* Station Address in EEPROM Reg 0x10..0x12 */ + + struct mutex mii_mutex; + struct mii_if_info mii_if; + int ResetCurrentTFD; +#ifdef IPG_DEBUG + int RFDlistendCount; + int RFDListCheckedCount; + int EmptyRFDListCount; +#endif + struct delayed_work task; +}; + +//variable record -- index by leading revision/length +//Revision/Length(=N*4), Address1, Data1, Address2, Data2,...,AddressN,DataN +unsigned short DefaultPhyParam[] = { + // 11/12/03 IP1000A v1-3 rev=0x40 + /*-------------------------------------------------------------------------- + (0x4000|(15*4)), 31, 0x0001, 27, 0x01e0, 31, 0x0002, 22, 0x85bd, 24, 0xfff2, + 27, 0x0c10, 28, 0x0c10, 29, 0x2c10, 31, 0x0003, 23, 0x92f6, + 31, 0x0000, 23, 0x003d, 30, 0x00de, 20, 0x20e7, 9, 0x0700, + --------------------------------------------------------------------------*/ + // 12/17/03 IP1000A v1-4 rev=0x40 + (0x4000 | (07 * 4)), 31, 0x0001, 27, 0x01e0, 31, 0x0002, 27, 0xeb8e, 31, + 0x0000, + 30, 0x005e, 9, 0x0700, + // 01/09/04 IP1000A v1-5 rev=0x41 + (0x4100 | (07 * 4)), 31, 0x0001, 27, 0x01e0, 31, 0x0002, 27, 0xeb8e, 31, + 0x0000, + 30, 0x005e, 9, 0x0700, + 0x0000 +}; + +#endif /* __LINUX_IPG_H */ diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 55f307ffbf9..c9c24ddf9c7 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1841,6 +1841,8 @@ #define PCI_VENDOR_ID_ABOCOM 0x13D1 #define PCI_DEVICE_ID_ABOCOM_2BD1 0x2BD1 +#define PCI_VENDOR_ID_SUNDANCE 0x13f0 + #define PCI_VENDOR_ID_CMEDIA 0x13f6 #define PCI_DEVICE_ID_CMEDIA_CM8338A 0x0100 #define PCI_DEVICE_ID_CMEDIA_CM8338B 0x0101 -- cgit v1.2.3-70-g09d2 From 1a348ccc1047a00507e554826775a3d81f7f3437 Mon Sep 17 00:00:00 2001 From: Andy Gospodarek Date: Mon, 17 Sep 2007 18:50:36 -0700 Subject: [NET]: Add Tehuti network driver. [ Ported to napi_struct changes... -DaveM ] Signed-off-by: David S. Miller --- MAINTAINERS | 8 + drivers/net/Kconfig | 6 + drivers/net/Makefile | 1 + drivers/net/tehuti.c | 2508 +++++++++++ drivers/net/tehuti.h | 564 +++ drivers/net/tehuti_fw.h | 10712 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/pci_ids.h | 5 + 7 files changed, 13804 insertions(+) create mode 100644 drivers/net/tehuti.c create mode 100644 drivers/net/tehuti.h create mode 100644 drivers/net/tehuti_fw.h (limited to 'drivers') diff --git a/MAINTAINERS b/MAINTAINERS index 27cd503cf0e..3f07d5ff85f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3630,6 +3630,14 @@ M: hlhung3i@gmail.com W: http://tcp-lp-mod.sourceforge.net/ S: Maintained +TEHUTI ETHERNET DRIVER +P: Alexander Indenbaum +M: baum@tehutinetworks.net +P: Andy Gospodarek +M: andy@greyhouse.net +L: netdev@vger.kernel.org +S: Supported + TI FLASH MEDIA INTERFACE DRIVER P: Alex Dubov M: oakad@yahoo.com diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 63ab05b5a87..fd284a93c9d 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2661,6 +2661,12 @@ config MLX4_DEBUG debug_level module parameter (which can also be set after the driver is loaded through sysfs). +config TEHUTI + tristate "Tehuti Networks 10G Ethernet" + depends on PCI + help + Tehuti Networks 10G Ethernet NIC + endif # NETDEV_10000 source "drivers/net/tokenring/Kconfig" diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 2098647080a..2ab33e8b915 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_EHEA) += ehea/ obj-$(CONFIG_BONDING) += bonding/ obj-$(CONFIG_ATL1) += atl1/ obj-$(CONFIG_GIANFAR) += gianfar_driver.o +obj-$(CONFIG_TEHUTI) += tehuti.o gianfar_driver-objs := gianfar.o \ gianfar_ethtool.o \ diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c new file mode 100644 index 00000000000..24834317735 --- /dev/null +++ b/drivers/net/tehuti.c @@ -0,0 +1,2508 @@ +/* + * Tehuti Networks(R) Network Driver + * ethtool interface implementation + * Copyright (C) 2007 Tehuti Networks Ltd. All rights reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +/* + * RX HW/SW interaction overview + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * There are 2 types of RX communication channels betwean driver and NIC. + * 1) RX Free Fifo - RXF - holds descriptors of empty buffers to accept incoming + * traffic. This Fifo is filled by SW and is readen by HW. Each descriptor holds + * info about buffer's location, size and ID. An ID field is used to identify a + * buffer when it's returned with data via RXD Fifo (see below) + * 2) RX Data Fifo - RXD - holds descriptors of full buffers. This Fifo is + * filled by HW and is readen by SW. Each descriptor holds status and ID. + * HW pops descriptor from RXF Fifo, stores ID, fills buffer with incoming data, + * via dma moves it into host memory, builds new RXD descriptor with same ID, + * pushes it into RXD Fifo and raises interrupt to indicate new RX data. + * + * Current NIC configuration (registers + firmware) makes NIC use 2 RXF Fifos. + * One holds 1.5K packets and another - 26K packets. Depending on incoming + * packet size, HW desides on a RXF Fifo to pop buffer from. When packet is + * filled with data, HW builds new RXD descriptor for it and push it into single + * RXD Fifo. + * + * RX SW Data Structures + * ~~~~~~~~~~~~~~~~~~~~~ + * skb db - used to keep track of all skbs owned by SW and their dma addresses. + * For RX case, ownership lasts from allocating new empty skb for RXF until + * accepting full skb from RXD and passing it to OS. Each RXF Fifo has its own + * skb db. Implemented as array with bitmask. + * fifo - keeps info about fifo's size and location, relevant HW registers, + * usage and skb db. Each RXD and RXF Fifo has its own fifo structure. + * Implemented as simple struct. + * + * RX SW Execution Flow + * ~~~~~~~~~~~~~~~~~~~~ + * Upon initialization (ifconfig up) driver creates RX fifos and initializes + * relevant registers. At the end of init phase, driver enables interrupts. + * NIC sees that there is no RXF buffers and raises + * RD_INTR interrupt, isr fills skbs and Rx begins. + * Driver has two receive operation modes: + * NAPI - interrupt-driven mixed with polling + * interrupt-driven only + * + * Interrupt-driven only flow is following. When buffer is ready, HW raises + * interrupt and isr is called. isr collects all available packets + * (bdx_rx_receive), refills skbs (bdx_rx_alloc_skbs) and exit. + + * Rx buffer allocation note + * ~~~~~~~~~~~~~~~~~~~~~~~~~ + * Driver cares to feed such amount of RxF descriptors that respective amount of + * RxD descriptors can not fill entire RxD fifo. The main reason is lack of + * overflow check in Bordeaux for RxD fifo free/used size. + * FIXME: this is NOT fully implemented, more work should be done + * + */ + +#include "tehuti.h" +#include "tehuti_fw.h" + +static struct pci_device_id __devinitdata bdx_pci_tbl[] = { + {0x1FC9, 0x3009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0x1FC9, 0x3010, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0x1FC9, 0x3014, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0} +}; + +MODULE_DEVICE_TABLE(pci, bdx_pci_tbl); + +/* Definitions needed by ISR or NAPI functions */ +static void bdx_rx_alloc_skbs(struct bdx_priv *priv, struct rxf_fifo *f); +static void bdx_tx_cleanup(struct bdx_priv *priv); +static int bdx_rx_receive(struct bdx_priv *priv, struct rxd_fifo *f, int budget); + +/* Definitions needed by FW loading */ +static void bdx_tx_push_desc_safe(struct bdx_priv *priv, void *data, int size); + +/* Definitions needed by hw_start */ +static int bdx_tx_init(struct bdx_priv *priv); +static int bdx_rx_init(struct bdx_priv *priv); + +/* Definitions needed by bdx_close */ +static void bdx_rx_free(struct bdx_priv *priv); +static void bdx_tx_free(struct bdx_priv *priv); + +/* Definitions needed by bdx_probe */ +static void bdx_ethtool_ops(struct net_device *netdev); + +/************************************************************************* + * Print Info * + *************************************************************************/ + +static void print_hw_id(struct pci_dev *pdev) +{ + struct pci_nic *nic = pci_get_drvdata(pdev); + u16 pci_link_status = 0; + u16 pci_ctrl = 0; + + pci_read_config_word(pdev, PCI_LINK_STATUS_REG, &pci_link_status); + pci_read_config_word(pdev, PCI_DEV_CTRL_REG, &pci_ctrl); + + printk(KERN_INFO "tehuti: %s%s\n", BDX_NIC_NAME, + nic->port_num == 1 ? "" : ", 2-Port"); + printk(KERN_INFO + "tehuti: srom 0x%x fpga %d build %u lane# %d" + " max_pl 0x%x mrrs 0x%x\n", + readl(nic->regs + SROM_VER), readl(nic->regs + FPGA_VER) & 0xFFF, + readl(nic->regs + FPGA_SEED), + GET_LINK_STATUS_LANES(pci_link_status), + GET_DEV_CTRL_MAXPL(pci_ctrl), GET_DEV_CTRL_MRRS(pci_ctrl)); +} + +static void print_fw_id(struct pci_nic *nic) +{ + printk(KERN_INFO "tehuti: fw 0x%x\n", readl(nic->regs + FW_VER)); +} + +static void print_eth_id(struct net_device *ndev) +{ + printk(KERN_INFO "%s: %s, Port %c\n", ndev->name, BDX_NIC_NAME, + (ndev->if_port == 0) ? 'A' : 'B'); + +} + +/************************************************************************* + * Code * + *************************************************************************/ + +#define bdx_enable_interrupts(priv) \ + do { WRITE_REG(priv, regIMR, IR_RUN); } while (0) +#define bdx_disable_interrupts(priv) \ + do { WRITE_REG(priv, regIMR, 0); } while (0) + +/* bdx_fifo_init + * create TX/RX descriptor fifo for host-NIC communication. + * 1K extra space is allocated at the end of the fifo to simplify + * processing of descriptors that wraps around fifo's end + * @priv - NIC private structure + * @f - fifo to initialize + * @fsz_type - fifo size type: 0-4KB, 1-8KB, 2-16KB, 3-32KB + * @reg_XXX - offsets of registers relative to base address + * + * Returns 0 on success, negative value on failure + * + */ +static int +bdx_fifo_init(struct bdx_priv *priv, struct fifo *f, int fsz_type, + u16 reg_CFG0, u16 reg_CFG1, u16 reg_RPTR, u16 reg_WPTR) +{ + u16 memsz = FIFO_SIZE * (1 << fsz_type); + + memset(f, 0, sizeof(struct fifo)); + /* pci_alloc_consistent gives us 4k-aligned memory */ + f->va = pci_alloc_consistent(priv->pdev, + memsz + FIFO_EXTRA_SPACE, &f->da); + if (!f->va) { + ERR("pci_alloc_consistent failed\n"); + RET(-ENOMEM); + } + f->reg_CFG0 = reg_CFG0; + f->reg_CFG1 = reg_CFG1; + f->reg_RPTR = reg_RPTR; + f->reg_WPTR = reg_WPTR; + f->rptr = 0; + f->wptr = 0; + f->memsz = memsz; + f->size_mask = memsz - 1; + WRITE_REG(priv, reg_CFG0, (u32) ((f->da & TX_RX_CFG0_BASE) | fsz_type)); + WRITE_REG(priv, reg_CFG1, H32_64(f->da)); + + RET(0); +} + +/* bdx_fifo_free - free all resources used by fifo + * @priv - NIC private structure + * @f - fifo to release + */ +static void bdx_fifo_free(struct bdx_priv *priv, struct fifo *f) +{ + ENTER; + if (f->va) { + pci_free_consistent(priv->pdev, + f->memsz + FIFO_EXTRA_SPACE, f->va, f->da); + f->va = NULL; + } + RET(); +} + +/* + * bdx_link_changed - notifies OS about hw link state. + * @bdx_priv - hw adapter structure + */ +static void bdx_link_changed(struct bdx_priv *priv) +{ + u32 link = READ_REG(priv, regMAC_LNK_STAT) & MAC_LINK_STAT; + + if (!link) { + if (netif_carrier_ok(priv->ndev)) { + netif_stop_queue(priv->ndev); + netif_carrier_off(priv->ndev); + ERR("%s: Link Down\n", priv->ndev->name); + } + } else { + if (!netif_carrier_ok(priv->ndev)) { + netif_wake_queue(priv->ndev); + netif_carrier_on(priv->ndev); + ERR("%s: Link Up\n", priv->ndev->name); + } + } +} + +static void bdx_isr_extra(struct bdx_priv *priv, u32 isr) +{ + if (isr & IR_RX_FREE_0) { + bdx_rx_alloc_skbs(priv, &priv->rxf_fifo0); + DBG("RX_FREE_0\n"); + } + + if (isr & IR_LNKCHG0) + bdx_link_changed(priv); + + if (isr & IR_PCIE_LINK) + ERR("%s: PCI-E Link Fault\n", priv->ndev->name); + + if (isr & IR_PCIE_TOUT) + ERR("%s: PCI-E Time Out\n", priv->ndev->name); + +} + +/* bdx_isr - Interrupt Service Routine for Bordeaux NIC + * @irq - interrupt number + * @ndev - network device + * @regs - CPU registers + * + * Return IRQ_NONE if it was not our interrupt, IRQ_HANDLED - otherwise + * + * It reads ISR register to know interrupt reasons, and proceed them one by one. + * Reasons of interest are: + * RX_DESC - new packet has arrived and RXD fifo holds its descriptor + * RX_FREE - number of free Rx buffers in RXF fifo gets low + * TX_FREE - packet was transmited and RXF fifo holds its descriptor + */ + +static irqreturn_t bdx_isr_napi(int irq, void *dev) +{ + struct net_device *ndev = dev; + struct bdx_priv *priv = ndev->priv; + u32 isr; + + ENTER; + isr = (READ_REG(priv, regISR) & IR_RUN); + if (unlikely(!isr)) { + bdx_enable_interrupts(priv); + return IRQ_NONE; /* Not our interrupt */ + } + + if (isr & IR_EXTRA) + bdx_isr_extra(priv, isr); + + if (isr & (IR_RX_DESC_0 | IR_TX_FREE_0)) { + if (likely(netif_rx_schedule_prep(ndev, &priv->napi))) { + __netif_rx_schedule(ndev, &priv->napi); + RET(IRQ_HANDLED); + } else { + /* NOTE: we get here if intr has slipped into window + * between these lines in bdx_poll: + * bdx_enable_interrupts(priv); + * return 0; + * currently intrs are disabled (since we read ISR), + * and we have failed to register next poll. + * so we read the regs to trigger chip + * and allow further interupts. */ + READ_REG(priv, regTXF_WPTR_0); + READ_REG(priv, regRXD_WPTR_0); + } + } + + bdx_enable_interrupts(priv); + RET(IRQ_HANDLED); +} + +static int bdx_poll(struct napi_struct *napi, int budget) +{ + struct bdx_priv *priv = container_of(napi, struct bdx_priv, napi); + struct net_device *dev = priv->ndev; + int work_done; + + ENTER; + bdx_tx_cleanup(priv); + work_done = bdx_rx_receive(priv, &priv->rxd_fifo0, budget); + if ((work_done < budget) || + (priv->napi_stop++ >= 30)) { + DBG("rx poll is done. backing to isr-driven\n"); + + /* from time to time we exit to let NAPI layer release + * device lock and allow waiting tasks (eg rmmod) to advance) */ + priv->napi_stop = 0; + + netif_rx_complete(dev, napi); + bdx_enable_interrupts(priv); + } + return work_done; +} + +/* bdx_fw_load - loads firmware to NIC + * @priv - NIC private structure + * Firmware is loaded via TXD fifo, so it must be initialized first. + * Firware must be loaded once per NIC not per PCI device provided by NIC (NIC + * can have few of them). So all drivers use semaphore register to choose one + * that will actually load FW to NIC. + */ + +static int bdx_fw_load(struct bdx_priv *priv) +{ + int master, i; + + ENTER; + master = READ_REG(priv, regINIT_SEMAPHORE); + if (!READ_REG(priv, regINIT_STATUS) && master) { + bdx_tx_push_desc_safe(priv, s_firmLoad, sizeof(s_firmLoad)); + mdelay(100); + } + for (i = 0; i < 200; i++) { + if (READ_REG(priv, regINIT_STATUS)) + break; + mdelay(2); + } + if (master) + WRITE_REG(priv, regINIT_SEMAPHORE, 1); + + if (i == 200) { + ERR("%s: firmware loading failed\n", priv->ndev->name); + DBG("VPC = 0x%x VIC = 0x%x INIT_STATUS = 0x%x i=%d\n", + READ_REG(priv, regVPC), + READ_REG(priv, regVIC), READ_REG(priv, regINIT_STATUS), i); + RET(-EIO); + } else { + DBG("%s: firmware loading success\n", priv->ndev->name); + RET(0); + } +} + +static void bdx_restore_mac(struct net_device *ndev, struct bdx_priv *priv) +{ + u32 val; + + ENTER; + DBG("mac0=%x mac1=%x mac2=%x\n", + READ_REG(priv, regUNC_MAC0_A), + READ_REG(priv, regUNC_MAC1_A), READ_REG(priv, regUNC_MAC2_A)); + + val = (ndev->dev_addr[0] << 8) | (ndev->dev_addr[1]); + WRITE_REG(priv, regUNC_MAC2_A, val); + val = (ndev->dev_addr[2] << 8) | (ndev->dev_addr[3]); + WRITE_REG(priv, regUNC_MAC1_A, val); + val = (ndev->dev_addr[4] << 8) | (ndev->dev_addr[5]); + WRITE_REG(priv, regUNC_MAC0_A, val); + + DBG("mac0=%x mac1=%x mac2=%x\n", + READ_REG(priv, regUNC_MAC0_A), + READ_REG(priv, regUNC_MAC1_A), READ_REG(priv, regUNC_MAC2_A)); + RET(); +} + +/* bdx_hw_start - inits registers and starts HW's Rx and Tx engines + * @priv - NIC private structure + */ +static int bdx_hw_start(struct bdx_priv *priv) +{ + int rc = -EIO; + struct net_device *ndev = priv->ndev; + + ENTER; + bdx_link_changed(priv); + + /* 10G overall max length (vlan, eth&ip header, ip payload, crc) */ + WRITE_REG(priv, regFRM_LENGTH, 0X3FE0); + WRITE_REG(priv, regPAUSE_QUANT, 0x96); + WRITE_REG(priv, regRX_FIFO_SECTION, 0x800010); + WRITE_REG(priv, regTX_FIFO_SECTION, 0xE00010); + WRITE_REG(priv, regRX_FULLNESS, 0); + WRITE_REG(priv, regTX_FULLNESS, 0); + WRITE_REG(priv, regCTRLST, + regCTRLST_BASE | regCTRLST_RX_ENA | regCTRLST_TX_ENA); + + WRITE_REG(priv, regVGLB, 0); + WRITE_REG(priv, regMAX_FRAME_A, + priv->rxf_fifo0.m.pktsz & MAX_FRAME_AB_VAL); + + DBG("RDINTCM=%08x\n", priv->rdintcm); /*NOTE: test script uses this */ + WRITE_REG(priv, regRDINTCM0, priv->rdintcm); + WRITE_REG(priv, regRDINTCM2, 0); /*cpu_to_le32(rcm.val)); */ + + DBG("TDINTCM=%08x\n", priv->tdintcm); /*NOTE: test script uses this */ + WRITE_REG(priv, regTDINTCM0, priv->tdintcm); /* old val = 0x300064 */ + + /* Enable timer interrupt once in 2 secs. */ + /*WRITE_REG(priv, regGTMR0, ((GTMR_SEC * 2) & GTMR_DATA)); */ + bdx_restore_mac(priv->ndev, priv); + + WRITE_REG(priv, regGMAC_RXF_A, GMAC_RX_FILTER_OSEN | + GMAC_RX_FILTER_AM | GMAC_RX_FILTER_AB); + +#define BDX_IRQ_TYPE ((priv->nic->irq_type == IRQ_MSI)?0:IRQF_SHARED) + if ((rc = request_irq(priv->pdev->irq, &bdx_isr_napi, BDX_IRQ_TYPE, + ndev->name, ndev))) + goto err_irq; + bdx_enable_interrupts(priv); + + RET(0); + +err_irq: + RET(rc); +} + +static void bdx_hw_stop(struct bdx_priv *priv) +{ + ENTER; + bdx_disable_interrupts(priv); + free_irq(priv->pdev->irq, priv->ndev); + + netif_carrier_off(priv->ndev); + netif_stop_queue(priv->ndev); + + RET(); +} + +static int bdx_hw_reset_direct(void __iomem *regs) +{ + u32 val, i; + ENTER; + + /* reset sequences: read, write 1, read, write 0 */ + val = readl(regs + regCLKPLL); + writel((val | CLKPLL_SFTRST) + 0x8, regs + regCLKPLL); + udelay(50); + val = readl(regs + regCLKPLL); + writel(val & ~CLKPLL_SFTRST, regs + regCLKPLL); + + /* check that the PLLs are locked and reset ended */ + for (i = 0; i < 70; i++, mdelay(10)) + if ((readl(regs + regCLKPLL) & CLKPLL_LKD) == CLKPLL_LKD) { + /* do any PCI-E read transaction */ + readl(regs + regRXD_CFG0_0); + return 0; + } + ERR("tehuti: HW reset failed\n"); + return 1; /* failure */ +} + +static int bdx_hw_reset(struct bdx_priv *priv) +{ + u32 val, i; + ENTER; + + if (priv->port == 0) { + /* reset sequences: read, write 1, read, write 0 */ + val = READ_REG(priv, regCLKPLL); + WRITE_REG(priv, regCLKPLL, (val | CLKPLL_SFTRST) + 0x8); + udelay(50); + val = READ_REG(priv, regCLKPLL); + WRITE_REG(priv, regCLKPLL, val & ~CLKPLL_SFTRST); + } + /* check that the PLLs are locked and reset ended */ + for (i = 0; i < 70; i++, mdelay(10)) + if ((READ_REG(priv, regCLKPLL) & CLKPLL_LKD) == CLKPLL_LKD) { + /* do any PCI-E read transaction */ + READ_REG(priv, regRXD_CFG0_0); + return 0; + } + ERR("tehuti: HW reset failed\n"); + return 1; /* failure */ +} + +static int bdx_sw_reset(struct bdx_priv *priv) +{ + int i; + + ENTER; + /* 1. load MAC (obsolete) */ + /* 2. disable Rx (and Tx) */ + WRITE_REG(priv, regGMAC_RXF_A, 0); + mdelay(100); + /* 3. disable port */ + WRITE_REG(priv, regDIS_PORT, 1); + /* 4. disable queue */ + WRITE_REG(priv, regDIS_QU, 1); + /* 5. wait until hw is disabled */ + for (i = 0; i < 50; i++) { + if (READ_REG(priv, regRST_PORT) & 1) + break; + mdelay(10); + } + if (i == 50) + ERR("%s: SW reset timeout. continuing anyway\n", + priv->ndev->name); + + /* 6. disable intrs */ + WRITE_REG(priv, regRDINTCM0, 0); + WRITE_REG(priv, regTDINTCM0, 0); + WRITE_REG(priv, regIMR, 0); + READ_REG(priv, regISR); + + /* 7. reset queue */ + WRITE_REG(priv, regRST_QU, 1); + /* 8. reset port */ + WRITE_REG(priv, regRST_PORT, 1); + /* 9. zero all read and write pointers */ + for (i = regTXD_WPTR_0; i <= regTXF_RPTR_3; i += 0x10) + DBG("%x = %x\n", i, READ_REG(priv, i) & TXF_WPTR_WR_PTR); + for (i = regTXD_WPTR_0; i <= regTXF_RPTR_3; i += 0x10) + WRITE_REG(priv, i, 0); + /* 10. unseet port disable */ + WRITE_REG(priv, regDIS_PORT, 0); + /* 11. unset queue disable */ + WRITE_REG(priv, regDIS_QU, 0); + /* 12. unset queue reset */ + WRITE_REG(priv, regRST_QU, 0); + /* 13. unset port reset */ + WRITE_REG(priv, regRST_PORT, 0); + /* 14. enable Rx */ + /* skiped. will be done later */ + /* 15. save MAC (obsolete) */ + for (i = regTXD_WPTR_0; i <= regTXF_RPTR_3; i += 0x10) + DBG("%x = %x\n", i, READ_REG(priv, i) & TXF_WPTR_WR_PTR); + + RET(0); +} + +/* bdx_reset - performs right type of reset depending on hw type */ +static int bdx_reset(struct bdx_priv *priv) +{ + ENTER; + RET((priv->pdev->device == 0x3009) + ? bdx_hw_reset(priv) + : bdx_sw_reset(priv)); +} + +/** + * bdx_close - Disables a network interface + * @netdev: network interface device structure + * + * Returns 0, this is not allowed to fail + * + * The close entry point is called when an interface is de-activated + * by the OS. The hardware is still under the drivers control, but + * needs to be disabled. A global MAC reset is issued to stop the + * hardware, and all transmit and receive resources are freed. + **/ +static int bdx_close(struct net_device *ndev) +{ + struct bdx_priv *priv = NULL; + + ENTER; + priv = ndev->priv; + + napi_disable(&priv->napi); + + bdx_reset(priv); + bdx_hw_stop(priv); + bdx_rx_free(priv); + bdx_tx_free(priv); + RET(0); +} + +/** + * bdx_open - Called when a network interface is made active + * @netdev: network interface device structure + * + * Returns 0 on success, negative value on failure + * + * The open entry point is called when a network interface is made + * active by the system (IFF_UP). At this point all resources needed + * for transmit and receive operations are allocated, the interrupt + * handler is registered with the OS, the watchdog timer is started, + * and the stack is notified that the interface is ready. + **/ +static int bdx_open(struct net_device *ndev) +{ + struct bdx_priv *priv; + int rc; + + ENTER; + priv = ndev->priv; + bdx_reset(priv); + if (netif_running(ndev)) + netif_stop_queue(priv->ndev); + + if ((rc = bdx_tx_init(priv))) + goto err; + + if ((rc = bdx_rx_init(priv))) + goto err; + + if ((rc = bdx_fw_load(priv))) + goto err; + + bdx_rx_alloc_skbs(priv, &priv->rxf_fifo0); + + if ((rc = bdx_hw_start(priv))) + goto err; + + napi_enable(&priv->napi); + + print_fw_id(priv->nic); + + RET(0); + +err: + bdx_close(ndev); + RET(rc); +} + +static void __init bdx_firmware_endianess(void) +{ + int i; + for (i = 0; i < sizeof(s_firmLoad) / sizeof(u32); i++) + s_firmLoad[i] = CPU_CHIP_SWAP32(s_firmLoad[i]); +} + +static int bdx_ioctl_priv(struct net_device *ndev, struct ifreq *ifr, int cmd) +{ + struct bdx_priv *priv = ndev->priv; + u32 data[3]; + int error; + + ENTER; + + DBG("jiffies=%ld cmd=%d\n", jiffies, cmd); + if (cmd != SIOCDEVPRIVATE) { + error = copy_from_user(data, ifr->ifr_data, sizeof(data)); + if (error) { + ERR("cant copy from user\n"); + RET(error); + } + DBG("%d 0x%x 0x%x\n", data[0], data[1], data[2]); + } + + switch (data[0]) { + + case BDX_OP_READ: + data[2] = READ_REG(priv, data[1]); + DBG("read_reg(0x%x)=0x%x (dec %d)\n", data[1], data[2], + data[2]); + error = copy_to_user(ifr->ifr_data, data, sizeof(data)); + if (error) + RET(error); + break; + + case BDX_OP_WRITE: + WRITE_REG(priv, data[1], data[2]); + DBG("write_reg(0x%x, 0x%x)\n", data[1], data[2]); + break; + + default: + RET(-EOPNOTSUPP); + } + return 0; +} + +static int bdx_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd) +{ + ENTER; + if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) + RET(bdx_ioctl_priv(ndev, ifr, cmd)); + else + RET(-EOPNOTSUPP); +} + +/* + * __bdx_vlan_rx_vid - private helper for adding/killing VLAN vid + * by passing VLAN filter table to hardware + * @ndev network device + * @vid VLAN vid + * @op add or kill operation + */ +static void __bdx_vlan_rx_vid(struct net_device *ndev, uint16_t vid, int enable) +{ + struct bdx_priv *priv = ndev->priv; + u32 reg, bit, val; + + ENTER; + DBG2("vid=%d value=%d\n", (int)vid, enable); + if (unlikely(vid >= 4096)) { + ERR("tehuti: invalid VID: %u (> 4096)\n", vid); + RET(); + } + reg = regVLAN_0 + (vid / 32) * 4; + bit = 1 << vid % 32; + val = READ_REG(priv, reg); + DBG2("reg=%x, val=%x, bit=%d\n", reg, val, bit); + if (enable) + val |= bit; + else + val &= ~bit; + DBG2("new val %x\n", val); + WRITE_REG(priv, reg, val); + RET(); +} + +/* + * bdx_vlan_rx_add_vid - kernel hook for adding VLAN vid to hw filtering table + * @ndev network device + * @vid VLAN vid to add + */ +static void bdx_vlan_rx_add_vid(struct net_device *ndev, uint16_t vid) +{ + __bdx_vlan_rx_vid(ndev, vid, 1); +} + +/* + * bdx_vlan_rx_kill_vid - kernel hook for killing VLAN vid in hw filtering table + * @ndev network device + * @vid VLAN vid to kill + */ +static void bdx_vlan_rx_kill_vid(struct net_device *ndev, unsigned short vid) +{ + __bdx_vlan_rx_vid(ndev, vid, 0); +} + +/* + * bdx_vlan_rx_register - kernel hook for adding VLAN group + * @ndev network device + * @grp VLAN group + */ +static void +bdx_vlan_rx_register(struct net_device *ndev, struct vlan_group *grp) +{ + struct bdx_priv *priv = ndev->priv; + + ENTER; + DBG("device='%s', group='%p'\n", ndev->name, grp); + priv->vlgrp = grp; + RET(); +} + +/** + * bdx_change_mtu - Change the Maximum Transfer Unit + * @netdev: network interface device structure + * @new_mtu: new value for maximum frame size + * + * Returns 0 on success, negative on failure + */ +static int bdx_change_mtu(struct net_device *ndev, int new_mtu) +{ + BDX_ASSERT(ndev == 0); + ENTER; + + if (new_mtu == ndev->mtu) + RET(0); + + /* enforce minimum frame size */ + if (new_mtu < ETH_ZLEN) { + ERR("%s: %s mtu %d is less then minimal %d\n", + BDX_DRV_NAME, ndev->name, new_mtu, ETH_ZLEN); + RET(-EINVAL); + } + + ndev->mtu = new_mtu; + if (netif_running(ndev)) { + bdx_close(ndev); + bdx_open(ndev); + } + RET(0); +} + +static void bdx_setmulti(struct net_device *ndev) +{ + struct bdx_priv *priv = ndev->priv; + + u32 rxf_val = + GMAC_RX_FILTER_AM | GMAC_RX_FILTER_AB | GMAC_RX_FILTER_OSEN; + int i; + + ENTER; + /* IMF - imperfect (hash) rx multicat filter */ + /* PMF - perfect rx multicat filter */ + + /* FIXME: RXE(OFF) */ + if (ndev->flags & IFF_PROMISC) { + rxf_val |= GMAC_RX_FILTER_PRM; + } else if (ndev->flags & IFF_ALLMULTI) { + /* set IMF to accept all multicast frmaes */ + for (i = 0; i < MAC_MCST_HASH_NUM; i++) + WRITE_REG(priv, regRX_MCST_HASH0 + i * 4, ~0); + } else if (ndev->mc_count) { + u8 hash; + struct dev_mc_list *mclist; + u32 reg, val; + + /* set IMF to deny all multicast frames */ + for (i = 0; i < MAC_MCST_HASH_NUM; i++) + WRITE_REG(priv, regRX_MCST_HASH0 + i * 4, 0); + /* set PMF to deny all multicast frames */ + for (i = 0; i < MAC_MCST_NUM; i++) { + WRITE_REG(priv, regRX_MAC_MCST0 + i * 8, 0); + WRITE_REG(priv, regRX_MAC_MCST1 + i * 8, 0); + } + + /* use PMF to accept first MAC_MCST_NUM (15) addresses */ + /* TBD: sort addreses and write them in ascending order + * into RX_MAC_MCST regs. we skip this phase now and accept ALL + * multicast frames throu IMF */ + mclist = ndev->mc_list; + + /* accept the rest of addresses throu IMF */ + for (; mclist; mclist = mclist->next) { + hash = 0; + for (i = 0; i < ETH_ALEN; i++) + hash ^= mclist->dmi_addr[i]; + reg = regRX_MCST_HASH0 + ((hash >> 5) << 2); + val = READ_REG(priv, reg); + val |= (1 << (hash % 32)); + WRITE_REG(priv, reg, val); + } + + } else { + DBG("only own mac %d\n", ndev->mc_count); + rxf_val |= GMAC_RX_FILTER_AB; + } + WRITE_REG(priv, regGMAC_RXF_A, rxf_val); + /* enable RX */ + /* FIXME: RXE(ON) */ + RET(); +} + +static int bdx_set_mac(struct net_device *ndev, void *p) +{ + struct bdx_priv *priv = ndev->priv; + struct sockaddr *addr = p; + + ENTER; + /* + if (netif_running(dev)) + return -EBUSY + */ + memcpy(ndev->dev_addr, addr->sa_data, ndev->addr_len); + bdx_restore_mac(ndev, priv); + RET(0); +} + +static int bdx_read_mac(struct bdx_priv *priv) +{ + u16 macAddress[3], i; + ENTER; + + macAddress[2] = READ_REG(priv, regUNC_MAC0_A); + macAddress[2] = READ_REG(priv, regUNC_MAC0_A); + macAddress[1] = READ_REG(priv, regUNC_MAC1_A); + macAddress[1] = READ_REG(priv, regUNC_MAC1_A); + macAddress[0] = READ_REG(priv, regUNC_MAC2_A); + macAddress[0] = READ_REG(priv, regUNC_MAC2_A); + for (i = 0; i < 3; i++) { + priv->ndev->dev_addr[i * 2 + 1] = macAddress[i]; + priv->ndev->dev_addr[i * 2] = macAddress[i] >> 8; + } + RET(0); +} + +static u64 bdx_read_l2stat(struct bdx_priv *priv, int reg) +{ + u64 val; + + val = READ_REG(priv, reg); + val |= ((u64) READ_REG(priv, reg + 8)) << 32; + return val; +} + +/*Do the statistics-update work*/ +static void bdx_update_stats(struct bdx_priv *priv) +{ + struct bdx_stats *stats = &priv->hw_stats; + u64 *stats_vector = (u64 *) stats; + int i; + int addr; + + /*Fill HW structure */ + addr = 0x7200; + /*First 12 statistics - 0x7200 - 0x72B0 */ + for (i = 0; i < 12; i++) { + stats_vector[i] = bdx_read_l2stat(priv, addr); + addr += 0x10; + } + BDX_ASSERT(addr != 0x72C0); + /* 0x72C0-0x72E0 RSRV */ + addr = 0x72F0; + for (; i < 16; i++) { + stats_vector[i] = bdx_read_l2stat(priv, addr); + addr += 0x10; + } + BDX_ASSERT(addr != 0x7330); + /* 0x7330-0x7360 RSRV */ + addr = 0x7370; + for (; i < 19; i++) { + stats_vector[i] = bdx_read_l2stat(priv, addr); + addr += 0x10; + } + BDX_ASSERT(addr != 0x73A0); + /* 0x73A0-0x73B0 RSRV */ + addr = 0x73C0; + for (; i < 23; i++) { + stats_vector[i] = bdx_read_l2stat(priv, addr); + addr += 0x10; + } + BDX_ASSERT(addr != 0x7400); + BDX_ASSERT((sizeof(struct bdx_stats) / sizeof(u64)) != i); +} + +static struct net_device_stats *bdx_get_stats(struct net_device *ndev) +{ + struct bdx_priv *priv = ndev->priv; + struct net_device_stats *net_stat = &priv->net_stats; + return net_stat; +} + +static void print_rxdd(struct rxd_desc *rxdd, u32 rxd_val1, u16 len, + u16 rxd_vlan); +static void print_rxfd(struct rxf_desc *rxfd); + +/************************************************************************* + * Rx DB * + *************************************************************************/ + +static void bdx_rxdb_destroy(struct rxdb *db) +{ + if (db) + vfree(db); +} + +static struct rxdb *bdx_rxdb_create(int nelem) +{ + struct rxdb *db; + int i; + + db = vmalloc(sizeof(struct rxdb) + + (nelem * sizeof(int)) + + (nelem * sizeof(struct rx_map))); + if (likely(db != NULL)) { + db->stack = (int *)(db + 1); + db->elems = (void *)(db->stack + nelem); + db->nelem = nelem; + db->top = nelem; + for (i = 0; i < nelem; i++) + db->stack[i] = nelem - i - 1; /* to make first allocs + close to db struct*/ + } + + return db; +} + +static inline int bdx_rxdb_alloc_elem(struct rxdb *db) +{ + BDX_ASSERT(db->top <= 0); + return db->stack[--(db->top)]; +} + +static inline void *bdx_rxdb_addr_elem(struct rxdb *db, int n) +{ + BDX_ASSERT((n < 0) || (n >= db->nelem)); + return db->elems + n; +} + +static inline int bdx_rxdb_available(struct rxdb *db) +{ + return db->top; +} + +static inline void bdx_rxdb_free_elem(struct rxdb *db, int n) +{ + BDX_ASSERT((n >= db->nelem) || (n < 0)); + db->stack[(db->top)++] = n; +} + +/************************************************************************* + * Rx Init * + *************************************************************************/ + +/* bdx_rx_init - initialize RX all related HW and SW resources + * @priv - NIC private structure + * + * Returns 0 on success, negative value on failure + * + * It creates rxf and rxd fifos, update relevant HW registers, preallocate + * skb for rx. It assumes that Rx is desabled in HW + * funcs are grouped for better cache usage + * + * RxD fifo is smaller then RxF fifo by design. Upon high load, RxD will be + * filled and packets will be dropped by nic without getting into host or + * cousing interrupt. Anyway, in that condition, host has no chance to proccess + * all packets, but dropping in nic is cheaper, since it takes 0 cpu cycles + */ + +/* TBD: ensure proper packet size */ + +static int bdx_rx_init(struct bdx_priv *priv) +{ + ENTER; + BDX_ASSERT(priv == 0); + if (bdx_fifo_init(priv, &priv->rxd_fifo0.m, priv->rxd_size, + regRXD_CFG0_0, regRXD_CFG1_0, + regRXD_RPTR_0, regRXD_WPTR_0)) + goto err_mem; + if (bdx_fifo_init(priv, &priv->rxf_fifo0.m, priv->rxf_size, + regRXF_CFG0_0, regRXF_CFG1_0, + regRXF_RPTR_0, regRXF_WPTR_0)) + goto err_mem; + if (! + (priv->rxdb = + bdx_rxdb_create(priv->rxf_fifo0.m.memsz / + sizeof(struct rxf_desc)))) + goto err_mem; + + priv->rxf_fifo0.m.pktsz = priv->ndev->mtu + VLAN_ETH_HLEN; + return 0; + +err_mem: + ERR("%s: %s: Rx init failed\n", BDX_DRV_NAME, priv->ndev->name); + return -ENOMEM; +} + +/* bdx_rx_free_skbs - frees and unmaps all skbs allocated for the fifo + * @priv - NIC private structure + * @f - RXF fifo + */ +static void bdx_rx_free_skbs(struct bdx_priv *priv, struct rxf_fifo *f) +{ + struct rx_map *dm; + struct rxdb *db = priv->rxdb; + u16 i; + + ENTER; + DBG("total=%d free=%d busy=%d\n", db->nelem, bdx_rxdb_available(db), + db->nelem - bdx_rxdb_available(db)); + while (bdx_rxdb_available(db) > 0) { + i = bdx_rxdb_alloc_elem(db); + dm = bdx_rxdb_addr_elem(db, i); + dm->dma = 0; + } + for (i = 0; i < db->nelem; i++) { + dm = bdx_rxdb_addr_elem(db, i); + if (dm->dma) { + pci_unmap_single(priv->pdev, + dm->dma, f->m.pktsz, + PCI_DMA_FROMDEVICE); + dev_kfree_skb(dm->skb); + } + } +} + +/* bdx_rx_free - release all Rx resources + * @priv - NIC private structure + * It assumes that Rx is desabled in HW + */ +static void bdx_rx_free(struct bdx_priv *priv) +{ + ENTER; + if (priv->rxdb) { + bdx_rx_free_skbs(priv, &priv->rxf_fifo0); + bdx_rxdb_destroy(priv->rxdb); + priv->rxdb = NULL; + } + bdx_fifo_free(priv, &priv->rxf_fifo0.m); + bdx_fifo_free(priv, &priv->rxd_fifo0.m); + + RET(); +} + +/************************************************************************* + * Rx Engine * + *************************************************************************/ + +/* bdx_rx_alloc_skbs - fill rxf fifo with new skbs + * @priv - nic's private structure + * @f - RXF fifo that needs skbs + * It allocates skbs, build rxf descs and push it (rxf descr) into rxf fifo. + * skb's virtual and physical addresses are stored in skb db. + * To calculate free space, func uses cached values of RPTR and WPTR + * When needed, it also updates RPTR and WPTR. + */ + +/* TBD: do not update WPTR if no desc were written */ + +static void bdx_rx_alloc_skbs(struct bdx_priv *priv, struct rxf_fifo *f) +{ + struct sk_buff *skb; + struct rxf_desc *rxfd; + struct rx_map *dm; + int dno, delta, idx; + struct rxdb *db = priv->rxdb; + + ENTER; + dno = bdx_rxdb_available(db) - 1; + while (dno > 0) { + if (!(skb = dev_alloc_skb(f->m.pktsz + NET_IP_ALIGN))) { + ERR("NO MEM: dev_alloc_skb failed\n"); + break; + } + skb->dev = priv->ndev; + skb_reserve(skb, NET_IP_ALIGN); + + idx = bdx_rxdb_alloc_elem(db); + dm = bdx_rxdb_addr_elem(db, idx); + dm->dma = pci_map_single(priv->pdev, + skb->data, f->m.pktsz, + PCI_DMA_FROMDEVICE); + dm->skb = skb; + rxfd = (struct rxf_desc *)(f->m.va + f->m.wptr); + rxfd->info = CPU_CHIP_SWAP32(0x10003); /* INFO=1 BC=3 */ + rxfd->va_lo = idx; + rxfd->pa_lo = CPU_CHIP_SWAP32(L32_64(dm->dma)); + rxfd->pa_hi = CPU_CHIP_SWAP32(H32_64(dm->dma)); + rxfd->len = CPU_CHIP_SWAP32(f->m.pktsz); + print_rxfd(rxfd); + + f->m.wptr += sizeof(struct rxf_desc); + delta = f->m.wptr - f->m.memsz; + if (unlikely(delta >= 0)) { + f->m.wptr = delta; + if (delta > 0) { + memcpy(f->m.va, f->m.va + f->m.memsz, delta); + DBG("wrapped descriptor\n"); + } + } + dno--; + } + /*TBD: to do - delayed rxf wptr like in txd */ + WRITE_REG(priv, f->m.reg_WPTR, f->m.wptr & TXF_WPTR_WR_PTR); + RET(); +} + +static inline void +NETIF_RX_MUX(struct bdx_priv *priv, u32 rxd_val1, u16 rxd_vlan, + struct sk_buff *skb) +{ + ENTER; + DBG("rxdd->flags.bits.vtag=%d vlgrp=%p\n", GET_RXD_VTAG(rxd_val1), + priv->vlgrp); + if (priv->vlgrp && GET_RXD_VTAG(rxd_val1)) { + DBG("%s: vlan rcv vlan '%x' vtag '%x', device name '%s'\n", + priv->ndev->name, + GET_RXD_VLAN_ID(rxd_vlan), + GET_RXD_VTAG(rxd_val1), + vlan_group_get_device(priv->vlgrp, + GET_RXD_VLAN_ID(rxd_vlan))->name); + /* NAPI variant of receive functions */ + vlan_hwaccel_receive_skb(skb, priv->vlgrp, + GET_RXD_VLAN_ID(rxd_vlan)); + } else { + netif_receive_skb(skb); + } +} + +static void bdx_recycle_skb(struct bdx_priv *priv, struct rxd_desc *rxdd) +{ + struct rxf_desc *rxfd; + struct rx_map *dm; + struct rxf_fifo *f; + struct rxdb *db; + struct sk_buff *skb; + int delta; + + ENTER; + DBG("priv=%p rxdd=%p\n", priv, rxdd); + f = &priv->rxf_fifo0; + db = priv->rxdb; + DBG("db=%p f=%p\n", db, f); + dm = bdx_rxdb_addr_elem(db, rxdd->va_lo); + DBG("dm=%p\n", dm); + skb = dm->skb; + rxfd = (struct rxf_desc *)(f->m.va + f->m.wptr); + rxfd->info = CPU_CHIP_SWAP32(0x10003); /* INFO=1 BC=3 */ + rxfd->va_lo = rxdd->va_lo; + rxfd->pa_lo = CPU_CHIP_SWAP32(L32_64(dm->dma)); + rxfd->pa_hi = CPU_CHIP_SWAP32(H32_64(dm->dma)); + rxfd->len = CPU_CHIP_SWAP32(f->m.pktsz); + print_rxfd(rxfd); + + f->m.wptr += sizeof(struct rxf_desc); + delta = f->m.wptr - f->m.memsz; + if (unlikely(delta >= 0)) { + f->m.wptr = delta; + if (delta > 0) { + memcpy(f->m.va, f->m.va + f->m.memsz, delta); + DBG("wrapped descriptor\n"); + } + } + RET(); +} + +/* bdx_rx_receive - recieves full packets from RXD fifo and pass them to OS + * NOTE: a special treatment is given to non-continous descriptors + * that start near the end, wraps around and continue at the beginning. a second + * part is copied right after the first, and then descriptor is interpreted as + * normal. fifo has an extra space to allow such operations + * @priv - nic's private structure + * @f - RXF fifo that needs skbs + */ + +/* TBD: replace memcpy func call by explicite inline asm */ + +static int bdx_rx_receive(struct bdx_priv *priv, struct rxd_fifo *f, int budget) +{ + struct sk_buff *skb, *skb2; + struct rxd_desc *rxdd; + struct rx_map *dm; + struct rxf_fifo *rxf_fifo; + int tmp_len, size; + int done = 0; + int max_done = BDX_MAX_RX_DONE; + struct rxdb *db = NULL; + /* Unmarshalled descriptor - copy of descriptor in host order */ + u32 rxd_val1; + u16 len; + u16 rxd_vlan; + + ENTER; + max_done = budget; + + priv->ndev->last_rx = jiffies; + f->m.wptr = READ_REG(priv, f->m.reg_WPTR) & TXF_WPTR_WR_PTR; + + size = f->m.wptr - f->m.rptr; + if (size < 0) + size = f->m.memsz + size; /* size is negative :-) */ + + while (size > 0) { + + rxdd = (struct rxd_desc *)(f->m.va + f->m.rptr); + rxd_val1 = CPU_CHIP_SWAP32(rxdd->rxd_val1); + + len = CPU_CHIP_SWAP16(rxdd->len); + + rxd_vlan = CPU_CHIP_SWAP16(rxdd->rxd_vlan); + + print_rxdd(rxdd, rxd_val1, len, rxd_vlan); + + tmp_len = GET_RXD_BC(rxd_val1) << 3; + BDX_ASSERT(tmp_len <= 0); + size -= tmp_len; + if (size < 0) /* test for partially arrived descriptor */ + break; + + f->m.rptr += tmp_len; + + tmp_len = f->m.rptr - f->m.memsz; + if (unlikely(tmp_len >= 0)) { + f->m.rptr = tmp_len; + if (tmp_len > 0) { + DBG("wrapped desc rptr=%d tmp_len=%d\n", + f->m.rptr, tmp_len); + memcpy(f->m.va + f->m.memsz, f->m.va, tmp_len); + } + } + + if (unlikely(GET_RXD_ERR(rxd_val1))) { + DBG("rxd_err = 0x%x\n", GET_RXD_ERR(rxd_val1)); + priv->net_stats.rx_errors++; + bdx_recycle_skb(priv, rxdd); + continue; + } + + rxf_fifo = &priv->rxf_fifo0; + db = priv->rxdb; + dm = bdx_rxdb_addr_elem(db, rxdd->va_lo); + skb = dm->skb; + + if (len < BDX_COPYBREAK && + (skb2 = dev_alloc_skb(len + NET_IP_ALIGN))) { + skb_reserve(skb2, NET_IP_ALIGN); + /*skb_put(skb2, len); */ + pci_dma_sync_single_for_cpu(priv->pdev, + dm->dma, rxf_fifo->m.pktsz, + PCI_DMA_FROMDEVICE); + memcpy(skb2->data, skb->data, len); + bdx_recycle_skb(priv, rxdd); + skb = skb2; + } else { + pci_unmap_single(priv->pdev, + dm->dma, rxf_fifo->m.pktsz, + PCI_DMA_FROMDEVICE); + bdx_rxdb_free_elem(db, rxdd->va_lo); + } + + priv->net_stats.rx_bytes += len; + + skb_put(skb, len); + skb->dev = priv->ndev; + skb->ip_summed = CHECKSUM_UNNECESSARY; + skb->protocol = eth_type_trans(skb, priv->ndev); + + /* Non-IP packets aren't checksum-offloaded */ + if (GET_RXD_PKT_ID(rxd_val1) == 0) + skb->ip_summed = CHECKSUM_NONE; + + NETIF_RX_MUX(priv, rxd_val1, rxd_vlan, skb); + + if (++done >= max_done) + break; + } + + priv->net_stats.rx_packets += done; + + /* FIXME: do smth to minimize pci accesses */ + WRITE_REG(priv, f->m.reg_RPTR, f->m.rptr & TXF_WPTR_WR_PTR); + + bdx_rx_alloc_skbs(priv, &priv->rxf_fifo0); + + RET(done); +} + +/************************************************************************* + * Debug / Temprorary Code * + *************************************************************************/ +static void print_rxdd(struct rxd_desc *rxdd, u32 rxd_val1, u16 len, + u16 rxd_vlan) +{ + DBG("ERROR: rxdd bc %d rxfq %d to %d type %d err %d rxp %d " + "pkt_id %d vtag %d len %d vlan_id %d cfi %d prio %d " + "va_lo %d va_hi %d\n", + GET_RXD_BC(rxd_val1), GET_RXD_RXFQ(rxd_val1), GET_RXD_TO(rxd_val1), + GET_RXD_TYPE(rxd_val1), GET_RXD_ERR(rxd_val1), + GET_RXD_RXP(rxd_val1), GET_RXD_PKT_ID(rxd_val1), + GET_RXD_VTAG(rxd_val1), len, GET_RXD_VLAN_ID(rxd_vlan), + GET_RXD_CFI(rxd_vlan), GET_RXD_PRIO(rxd_vlan), rxdd->va_lo, + rxdd->va_hi); +} + +static void print_rxfd(struct rxf_desc *rxfd) +{ + DBG("=== RxF desc CHIP ORDER/ENDIANESS =============\n" + "info 0x%x va_lo %u pa_lo 0x%x pa_hi 0x%x len 0x%x\n", + rxfd->info, rxfd->va_lo, rxfd->pa_lo, rxfd->pa_hi, rxfd->len); +} + +/* + * TX HW/SW interaction overview + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * There are 2 types of TX communication channels betwean driver and NIC. + * 1) TX Free Fifo - TXF - holds ack descriptors for sent packets + * 2) TX Data Fifo - TXD - holds descriptors of full buffers. + * + * Currently NIC supports TSO, checksuming and gather DMA + * UFO and IP fragmentation is on the way + * + * RX SW Data Structures + * ~~~~~~~~~~~~~~~~~~~~~ + * txdb - used to keep track of all skbs owned by SW and their dma addresses. + * For TX case, ownership lasts from geting packet via hard_xmit and until HW + * acknowledges sent by TXF descriptors. + * Implemented as cyclic buffer. + * fifo - keeps info about fifo's size and location, relevant HW registers, + * usage and skb db. Each RXD and RXF Fifo has its own fifo structure. + * Implemented as simple struct. + * + * TX SW Execution Flow + * ~~~~~~~~~~~~~~~~~~~~ + * OS calls driver's hard_xmit method with packet to sent. + * Driver creates DMA mappings, builds TXD descriptors and kicks HW + * by updating TXD WPTR. + * When packet is sent, HW write us TXF descriptor and SW frees original skb. + * To prevent TXD fifo overflow without reading HW registers every time, + * SW deploys "tx level" technique. + * Upon strart up, tx level is initialized to TXD fifo length. + * For every sent packet, SW gets its TXD descriptor sizei + * (from precalculated array) and substructs it from tx level. + * The size is also stored in txdb. When TXF ack arrives, SW fetch size of + * original TXD descriptor from txdb and adds it to tx level. + * When Tx level drops under some predefined treshhold, the driver + * stops the TX queue. When TX level rises above that level, + * the tx queue is enabled again. + * + * This technique avoids eccessive reading of RPTR and WPTR registers. + * As our benchmarks shows, it adds 1.5 Gbit/sec to NIS's throuput. + */ + +/************************************************************************* + * Tx DB * + *************************************************************************/ +static inline int bdx_tx_db_size(struct txdb *db) +{ + int taken = db->wptr - db->rptr; + if (taken < 0) + taken = db->size + 1 + taken; /* (size + 1) equals memsz */ + + return db->size - taken; +} + +/* __bdx_tx_ptr_next - helper function, increment read/write pointer + wrap + * @d - tx data base + * @ptr - read or write pointer + */ +static inline void __bdx_tx_db_ptr_next(struct txdb *db, struct tx_map **pptr) +{ + BDX_ASSERT(db == NULL || pptr == NULL); /* sanity */ + + BDX_ASSERT(*pptr != db->rptr && /* expect either read */ + *pptr != db->wptr); /* or write pointer */ + + BDX_ASSERT(*pptr < db->start || /* pointer has to be */ + *pptr >= db->end); /* in range */ + + ++*pptr; + if (unlikely(*pptr == db->end)) + *pptr = db->start; +} + +/* bdx_tx_db_inc_rptr - increment read pointer + * @d - tx data base + */ +static inline void bdx_tx_db_inc_rptr(struct txdb *db) +{ + BDX_ASSERT(db->rptr == db->wptr); /* can't read from empty db */ + __bdx_tx_db_ptr_next(db, &db->rptr); +} + +/* bdx_tx_db_inc_rptr - increment write pointer + * @d - tx data base + */ +static inline void bdx_tx_db_inc_wptr(struct txdb *db) +{ + __bdx_tx_db_ptr_next(db, &db->wptr); + BDX_ASSERT(db->rptr == db->wptr); /* we can not get empty db as + a result of write */ +} + +/* bdx_tx_db_init - creates and initializes tx db + * @d - tx data base + * @sz_type - size of tx fifo + * Returns 0 on success, error code otherwise + */ +static int bdx_tx_db_init(struct txdb *d, int sz_type) +{ + int memsz = FIFO_SIZE * (1 << (sz_type + 1)); + + d->start = vmalloc(memsz); + if (!d->start) + return -ENOMEM; + + /* + * In order to differentiate between db is empty and db is full + * states at least one element should always be empty in order to + * avoid rptr == wptr which means db is empty + */ + d->size = memsz / sizeof(struct tx_map) - 1; + d->end = d->start + d->size + 1; /* just after last element */ + + /* all dbs are created equally empty */ + d->rptr = d->start; + d->wptr = d->start; + + return 0; +} + +/* bdx_tx_db_close - closes tx db and frees all memory + * @d - tx data base + */ +static void bdx_tx_db_close(struct txdb *d) +{ + BDX_ASSERT(d == NULL); + + if (d->start) { + vfree(d->start); + d->start = NULL; + } +} + +/************************************************************************* + * Tx Engine * + *************************************************************************/ + +/* sizes of tx desc (including padding if needed) as function + * of skb's frag number */ +static struct { + u16 bytes; + u16 qwords; /* qword = 64 bit */ +} txd_sizes[MAX_SKB_FRAGS + 1]; + +/* txdb_map_skb - creates and stores dma mappings for skb's data blocks + * @priv - NIC private structure + * @skb - socket buffer to map + * + * It makes dma mappings for skb's data blocks and writes them to PBL of + * new tx descriptor. It also stores them in the tx db, so they could be + * unmaped after data was sent. It is reponsibility of a caller to make + * sure that there is enough space in the tx db. Last element holds pointer + * to skb itself and marked with zero length + */ +static inline void +bdx_tx_map_skb(struct bdx_priv *priv, struct sk_buff *skb, + struct txd_desc *txdd) +{ + struct txdb *db = &priv->txdb; + struct pbl *pbl = &txdd->pbl[0]; + int nr_frags = skb_shinfo(skb)->nr_frags; + int i; + + db->wptr->len = skb->len - skb->data_len; + db->wptr->addr.dma = pci_map_single(priv->pdev, skb->data, + db->wptr->len, PCI_DMA_TODEVICE); + pbl->len = CPU_CHIP_SWAP32(db->wptr->len); + pbl->pa_lo = CPU_CHIP_SWAP32(L32_64(db->wptr->addr.dma)); + pbl->pa_hi = CPU_CHIP_SWAP32(H32_64(db->wptr->addr.dma)); + DBG("=== pbl len: 0x%x ================\n", pbl->len); + DBG("=== pbl pa_lo: 0x%x ================\n", pbl->pa_lo); + DBG("=== pbl pa_hi: 0x%x ================\n", pbl->pa_hi); + bdx_tx_db_inc_wptr(db); + + for (i = 0; i < nr_frags; i++) { + struct skb_frag_struct *frag; + + frag = &skb_shinfo(skb)->frags[i]; + db->wptr->len = frag->size; + db->wptr->addr.dma = + pci_map_page(priv->pdev, frag->page, frag->page_offset, + frag->size, PCI_DMA_TODEVICE); + + pbl++; + pbl->len = CPU_CHIP_SWAP32(db->wptr->len); + pbl->pa_lo = CPU_CHIP_SWAP32(L32_64(db->wptr->addr.dma)); + pbl->pa_hi = CPU_CHIP_SWAP32(H32_64(db->wptr->addr.dma)); + bdx_tx_db_inc_wptr(db); + } + + /* add skb clean up info. */ + db->wptr->len = -txd_sizes[nr_frags].bytes; + db->wptr->addr.skb = skb; + bdx_tx_db_inc_wptr(db); +} + +/* init_txd_sizes - precalculate sizes of descriptors for skbs up to 16 frags + * number of frags is used as index to fetch correct descriptors size, + * instead of calculating it each time */ +static void __init init_txd_sizes(void) +{ + int i, lwords; + + /* 7 - is number of lwords in txd with one phys buffer + * 3 - is number of lwords used for every additional phys buffer */ + for (i = 0; i < MAX_SKB_FRAGS + 1; i++) { + lwords = 7 + (i * 3); + if (lwords & 1) + lwords++; /* pad it with 1 lword */ + txd_sizes[i].qwords = lwords >> 1; + txd_sizes[i].bytes = lwords << 2; + } +} + +/* bdx_tx_init - initialize all Tx related stuff. + * Namely, TXD and TXF fifos, database etc */ +static int bdx_tx_init(struct bdx_priv *priv) +{ + if (bdx_fifo_init(priv, &priv->txd_fifo0.m, priv->txd_size, + regTXD_CFG0_0, + regTXD_CFG1_0, regTXD_RPTR_0, regTXD_WPTR_0)) + goto err_mem; + if (bdx_fifo_init(priv, &priv->txf_fifo0.m, priv->txf_size, + regTXF_CFG0_0, + regTXF_CFG1_0, regTXF_RPTR_0, regTXF_WPTR_0)) + goto err_mem; + + /* The TX db has to keep mappings for all packets sent (on TxD) + * and not yet reclaimed (on TxF) */ + if (bdx_tx_db_init(&priv->txdb, max(priv->txd_size, priv->txf_size))) + goto err_mem; + + priv->tx_level = BDX_MAX_TX_LEVEL; +#ifdef BDX_DELAY_WPTR + priv->tx_update_mark = priv->tx_level - 1024; +#endif + return 0; + +err_mem: + ERR("tehuti: %s: Tx init failed\n", priv->ndev->name); + return -ENOMEM; +} + +/* + * bdx_tx_space - calculates avalable space in TX fifo + * @priv - NIC private structure + * Returns avaliable space in TX fifo in bytes + */ +static inline int bdx_tx_space(struct bdx_priv *priv) +{ + struct txd_fifo *f = &priv->txd_fifo0; + int fsize; + + f->m.rptr = READ_REG(priv, f->m.reg_RPTR) & TXF_WPTR_WR_PTR; + fsize = f->m.rptr - f->m.wptr; + if (fsize <= 0) + fsize = f->m.memsz + fsize; + return (fsize); +} + +/* bdx_tx_transmit - send packet to NIC + * @skb - packet to send + * ndev - network device assigned to NIC + * Return codes: + * o NETDEV_TX_OK everything ok. + * o NETDEV_TX_BUSY Cannot transmit packet, try later + * Usually a bug, means queue start/stop flow control is broken in + * the driver. Note: the driver must NOT put the skb in its DMA ring. + * o NETDEV_TX_LOCKED Locking failed, please retry quickly. + */ +static int bdx_tx_transmit(struct sk_buff *skb, struct net_device *ndev) +{ + struct bdx_priv *priv = ndev->priv; + struct txd_fifo *f = &priv->txd_fifo0; + int txd_checksum = 7; /* full checksum */ + int txd_lgsnd = 0; + int txd_vlan_id = 0; + int txd_vtag = 0; + int txd_mss = 0; + + int nr_frags = skb_shinfo(skb)->nr_frags; + struct txd_desc *txdd; + int len; + unsigned long flags; + + ENTER; + local_irq_save(flags); + if (!spin_trylock(&priv->tx_lock)) { + local_irq_restore(flags); + DBG("%s[%s]: TX locked, returning NETDEV_TX_LOCKED\n", + BDX_DRV_NAME, ndev->name); + return NETDEV_TX_LOCKED; + } + + /* build tx descriptor */ + BDX_ASSERT(f->m.wptr >= f->m.memsz); /* started with valid wptr */ + txdd = (struct txd_desc *)(f->m.va + f->m.wptr); + if (unlikely(skb->ip_summed != CHECKSUM_PARTIAL)) + txd_checksum = 0; + + if (skb_shinfo(skb)->gso_size) { + txd_mss = skb_shinfo(skb)->gso_size; + txd_lgsnd = 1; + DBG("skb %p skb len %d gso size = %d\n", skb, skb->len, + txd_mss); + } + + if (vlan_tx_tag_present(skb)) { + /*Cut VLAN ID to 12 bits */ + txd_vlan_id = vlan_tx_tag_get(skb) & BITS_MASK(12); + txd_vtag = 1; + } + + txdd->length = CPU_CHIP_SWAP16(skb->len); + txdd->mss = CPU_CHIP_SWAP16(txd_mss); + txdd->txd_val1 = + CPU_CHIP_SWAP32(TXD_W1_VAL + (txd_sizes[nr_frags].qwords, txd_checksum, txd_vtag, + txd_lgsnd, txd_vlan_id)); + DBG("=== TxD desc =====================\n"); + DBG("=== w1: 0x%x ================\n", txdd->txd_val1); + DBG("=== w2: mss 0x%x len 0x%x\n", txdd->mss, txdd->length); + + bdx_tx_map_skb(priv, skb, txdd); + + /* increment TXD write pointer. In case of + fifo wrapping copy reminder of the descriptor + to the beginning */ + f->m.wptr += txd_sizes[nr_frags].bytes; + len = f->m.wptr - f->m.memsz; + if (unlikely(len >= 0)) { + f->m.wptr = len; + if (len > 0) { + BDX_ASSERT(len > f->m.memsz); + memcpy(f->m.va, f->m.va + f->m.memsz, len); + } + } + BDX_ASSERT(f->m.wptr >= f->m.memsz); /* finished with valid wptr */ + + priv->tx_level -= txd_sizes[nr_frags].bytes; + BDX_ASSERT(priv->tx_level <= 0 || priv->tx_level > BDX_MAX_TX_LEVEL); +#ifdef BDX_DELAY_WPTR + if (priv->tx_level > priv->tx_update_mark) { + /* Force memory writes to complete before letting h/w + know there are new descriptors to fetch. + (might be needed on platforms like IA64) + wmb(); */ + WRITE_REG(priv, f->m.reg_WPTR, f->m.wptr & TXF_WPTR_WR_PTR); + } else { + if (priv->tx_noupd++ > BDX_NO_UPD_PACKETS) { + priv->tx_noupd = 0; + WRITE_REG(priv, f->m.reg_WPTR, + f->m.wptr & TXF_WPTR_WR_PTR); + } + } +#else + /* Force memory writes to complete before letting h/w + know there are new descriptors to fetch. + (might be needed on platforms like IA64) + wmb(); */ + WRITE_REG(priv, f->m.reg_WPTR, f->m.wptr & TXF_WPTR_WR_PTR); + +#endif + ndev->trans_start = jiffies; + + priv->net_stats.tx_packets++; + priv->net_stats.tx_bytes += skb->len; + + if (priv->tx_level < BDX_MIN_TX_LEVEL) { + DBG("%s: %s: TX Q STOP level %d\n", + BDX_DRV_NAME, ndev->name, priv->tx_level); + netif_stop_queue(ndev); + } + + spin_unlock_irqrestore(&priv->tx_lock, flags); + return NETDEV_TX_OK; +} + +/* bdx_tx_cleanup - clean TXF fifo, run in the context of IRQ. + * @priv - bdx adapter + * It scans TXF fifo for descriptors, frees DMA mappings and reports to OS + * that those packets were sent + */ +static void bdx_tx_cleanup(struct bdx_priv *priv) +{ + struct txf_fifo *f = &priv->txf_fifo0; + struct txdb *db = &priv->txdb; + int tx_level = 0; + + ENTER; + f->m.wptr = READ_REG(priv, f->m.reg_WPTR) & TXF_WPTR_MASK; + BDX_ASSERT(f->m.rptr >= f->m.memsz); /* started with valid rptr */ + + while (f->m.wptr != f->m.rptr) { + f->m.rptr += BDX_TXF_DESC_SZ; + f->m.rptr &= f->m.size_mask; + + /* unmap all the fragments */ + /* first has to come tx_maps containing dma */ + BDX_ASSERT(db->rptr->len == 0); + do { + BDX_ASSERT(db->rptr->addr.dma == 0); + pci_unmap_page(priv->pdev, db->rptr->addr.dma, + db->rptr->len, PCI_DMA_TODEVICE); + bdx_tx_db_inc_rptr(db); + } while (db->rptr->len > 0); + tx_level -= db->rptr->len; /* '-' koz len is negative */ + + /* now should come skb pointer - free it */ + BDX_ASSERT(db->rptr->addr.skb == 0); + dev_kfree_skb_irq(db->rptr->addr.skb); + bdx_tx_db_inc_rptr(db); + } + + /* let h/w know which TXF descriptors were cleaned */ + BDX_ASSERT((f->m.wptr & TXF_WPTR_WR_PTR) >= f->m.memsz); + WRITE_REG(priv, f->m.reg_RPTR, f->m.rptr & TXF_WPTR_WR_PTR); + + /* We reclaimed resources, so in case the Q is stopped by xmit callback, + * we resume the transmition and use tx_lock to synchronize with xmit.*/ + spin_lock(&priv->tx_lock); + priv->tx_level += tx_level; + BDX_ASSERT(priv->tx_level <= 0 || priv->tx_level > BDX_MAX_TX_LEVEL); +#ifdef BDX_DELAY_WPTR + if (priv->tx_noupd) { + priv->tx_noupd = 0; + WRITE_REG(priv, priv->txd_fifo0.m.reg_WPTR, + priv->txd_fifo0.m.wptr & TXF_WPTR_WR_PTR); + } +#endif + + if (unlikely(netif_queue_stopped(priv->ndev) + && netif_carrier_ok(priv->ndev) + && (priv->tx_level >= BDX_MIN_TX_LEVEL))) { + DBG("%s: %s: TX Q WAKE level %d\n", + BDX_DRV_NAME, priv->ndev->name, priv->tx_level); + netif_wake_queue(priv->ndev); + } + spin_unlock(&priv->tx_lock); +} + +/* bdx_tx_free_skbs - frees all skbs from TXD fifo. + * It gets called when OS stops this dev, eg upon "ifconfig down" or rmmod + */ +static void bdx_tx_free_skbs(struct bdx_priv *priv) +{ + struct txdb *db = &priv->txdb; + + ENTER; + while (db->rptr != db->wptr) { + if (likely(db->rptr->len)) + pci_unmap_page(priv->pdev, db->rptr->addr.dma, + db->rptr->len, PCI_DMA_TODEVICE); + else + dev_kfree_skb(db->rptr->addr.skb); + bdx_tx_db_inc_rptr(db); + } + RET(); +} + +/* bdx_tx_free - frees all Tx resources */ +static void bdx_tx_free(struct bdx_priv *priv) +{ + ENTER; + bdx_tx_free_skbs(priv); + bdx_fifo_free(priv, &priv->txd_fifo0.m); + bdx_fifo_free(priv, &priv->txf_fifo0.m); + bdx_tx_db_close(&priv->txdb); +} + +/* bdx_tx_push_desc - push descriptor to TxD fifo + * @priv - NIC private structure + * @data - desc's data + * @size - desc's size + * + * Pushes desc to TxD fifo and overlaps it if needed. + * NOTE: this func does not check for available space. this is responsibility + * of the caller. Neither does it check that data size is smaller then + * fifo size. + */ +static void bdx_tx_push_desc(struct bdx_priv *priv, void *data, int size) +{ + struct txd_fifo *f = &priv->txd_fifo0; + int i = f->m.memsz - f->m.wptr; + + if (size == 0) + return; + + if (i > size) { + memcpy(f->m.va + f->m.wptr, data, size); + f->m.wptr += size; + } else { + memcpy(f->m.va + f->m.wptr, data, i); + f->m.wptr = size - i; + memcpy(f->m.va, data + i, f->m.wptr); + } + WRITE_REG(priv, f->m.reg_WPTR, f->m.wptr & TXF_WPTR_WR_PTR); +} + +/* bdx_tx_push_desc_safe - push descriptor to TxD fifo in a safe way + * @priv - NIC private structure + * @data - desc's data + * @size - desc's size + * + * NOTE: this func does check for available space and, if neccessary, waits for + * NIC to read existing data before writing new one. + */ +static void bdx_tx_push_desc_safe(struct bdx_priv *priv, void *data, int size) +{ + int timer = 0; + ENTER; + + while (size > 0) { + /* we substruct 8 because when fifo is full rptr == wptr + which also means that fifo is empty, we can understand + the difference, but could hw do the same ??? :) */ + int avail = bdx_tx_space(priv) - 8; + if (avail <= 0) { + if (timer++ > 300) { /* prevent endless loop */ + DBG("timeout while writing desc to TxD fifo\n"); + break; + } + udelay(50); /* give hw a chance to clean fifo */ + continue; + } + avail = MIN(avail, size); + DBG("about to push %d bytes starting %p size %d\n", avail, + data, size); + bdx_tx_push_desc(priv, data, avail); + size -= avail; + data += avail; + } + RET(); +} + +/** + * bdx_probe - Device Initialization Routine + * @pdev: PCI device information struct + * @ent: entry in bdx_pci_tbl + * + * Returns 0 on success, negative on failure + * + * bdx_probe initializes an adapter identified by a pci_dev structure. + * The OS initialization, configuring of the adapter private structure, + * and a hardware reset occur. + * + * functions and their order used as explained in + * /usr/src/linux/Documentation/DMA-{API,mapping}.txt + * + */ + +/* TBD: netif_msg should be checked and implemented. I disable it for now */ +static int __devinit +bdx_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + struct net_device *ndev; + struct bdx_priv *priv; + int err, pci_using_dac, port; + unsigned long pciaddr; + u32 regionSize; + struct pci_nic *nic; + + ENTER; + + nic = vmalloc(sizeof(*nic)); + if (!nic) + RET(-ENOMEM); + + /************** pci *****************/ + if ((err = pci_enable_device(pdev))) /* it trigers interrupt, dunno why. */ + RET(err); /* it's not a problem though */ + + if (!(err = pci_set_dma_mask(pdev, DMA_64BIT_MASK)) && + !(err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))) { + pci_using_dac = 1; + } else { + if ((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK)) || + (err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK))) { + printk(KERN_ERR "tehuti: No usable DMA configuration" + ", aborting\n"); + goto err_dma; + } + pci_using_dac = 0; + } + + if ((err = pci_request_regions(pdev, BDX_DRV_NAME))) + goto err_dma; + + pci_set_master(pdev); + + pciaddr = pci_resource_start(pdev, 0); + if (!pciaddr) { + err = -EIO; + ERR("tehuti: no MMIO resource\n"); + goto err_out_res; + } + if ((regionSize = pci_resource_len(pdev, 0)) < BDX_REGS_SIZE) { + err = -EIO; + ERR("tehuti: MMIO resource (%x) too small\n", regionSize); + goto err_out_res; + } + + nic->regs = ioremap(pciaddr, regionSize); + if (!nic->regs) { + err = -EIO; + ERR("tehuti: ioremap failed\n"); + goto err_out_res; + } + + if (pdev->irq < 2) { + err = -EIO; + ERR("tehuti: invalid irq (%d)\n", pdev->irq); + goto err_out_iomap; + } + pci_set_drvdata(pdev, nic); + + if (pdev->device == 0x3014) + nic->port_num = 2; + else + nic->port_num = 1; + + print_hw_id(pdev); + + bdx_hw_reset_direct(nic->regs); + + nic->irq_type = IRQ_INTX; +#ifdef BDX_MSI + if ((readl(nic->regs + FPGA_VER) & 0xFFF) >= 378) { + if ((err = pci_enable_msi(pdev))) + ERR("Tehuti: Can't eneble msi. error is %d\n", err); + else + nic->irq_type = IRQ_MSI; + } else + DBG("HW does not support MSI\n"); +#endif + + /************** netdev **************/ + for (port = 0; port < nic->port_num; port++) { + if (!(ndev = alloc_etherdev(sizeof(struct bdx_priv)))) { + err = -ENOMEM; + printk(KERN_ERR "tehuti: alloc_etherdev failed\n"); + goto err_out_iomap; + } + + ndev->open = bdx_open; + ndev->stop = bdx_close; + ndev->hard_start_xmit = bdx_tx_transmit; + ndev->do_ioctl = bdx_ioctl; + ndev->set_multicast_list = bdx_setmulti; + ndev->get_stats = bdx_get_stats; + ndev->change_mtu = bdx_change_mtu; + ndev->set_mac_address = bdx_set_mac; + ndev->tx_queue_len = BDX_NDEV_TXQ_LEN; + ndev->vlan_rx_register = bdx_vlan_rx_register; + ndev->vlan_rx_add_vid = bdx_vlan_rx_add_vid; + ndev->vlan_rx_kill_vid = bdx_vlan_rx_kill_vid; + + bdx_ethtool_ops(ndev); /* ethtool interface */ + + /* these fields are used for info purposes only + * so we can have them same for all ports of the board */ + ndev->if_port = port; + ndev->base_addr = pciaddr; + ndev->mem_start = pciaddr; + ndev->mem_end = pciaddr + regionSize; + ndev->irq = pdev->irq; + ndev->features = NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO + | NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | + NETIF_F_HW_VLAN_FILTER + /*| NETIF_F_FRAGLIST */ + ; + + if (pci_using_dac) + ndev->features |= NETIF_F_HIGHDMA; + + /************** priv ****************/ + priv = nic->priv[port] = ndev->priv; + + memset(priv, 0, sizeof(struct bdx_priv)); + priv->pBdxRegs = nic->regs + port * 0x8000; + priv->port = port; + priv->pdev = pdev; + priv->ndev = ndev; + priv->nic = nic; + priv->msg_enable = BDX_DEF_MSG_ENABLE; + + netif_napi_add(ndev, &priv->napi, bdx_poll, 64); + + if ((readl(nic->regs + FPGA_VER) & 0xFFF) == 308) { + DBG("HW statistics not supported\n"); + priv->stats_flag = 0; + } else { + priv->stats_flag = 1; + } + + /* Initialize fifo sizes. */ + priv->txd_size = 2; + priv->txf_size = 2; + priv->rxd_size = 2; + priv->rxf_size = 3; + + /* Initialize the initial coalescing registers. */ + priv->rdintcm = INT_REG_VAL(0x20, 1, 4, 12); + priv->tdintcm = INT_REG_VAL(0x20, 1, 0, 12); + + /* ndev->xmit_lock spinlock is not used. + * Private priv->tx_lock is used for synchronization + * between transmit and TX irq cleanup. In addition + * set multicast list callback has to use priv->tx_lock. + */ +#ifdef BDX_LLTX + ndev->features |= NETIF_F_LLTX; +#endif + spin_lock_init(&priv->tx_lock); + + /*bdx_hw_reset(priv); */ + if (bdx_read_mac(priv)) { + printk(KERN_ERR "tehuti: load MAC address failed\n"); + goto err_out_iomap; + } + SET_NETDEV_DEV(ndev, &pdev->dev); + if ((err = register_netdev(ndev))) { + printk(KERN_ERR "tehuti: register_netdev failed\n"); + goto err_out_free; + } + netif_carrier_off(ndev); + netif_stop_queue(ndev); + + print_eth_id(ndev); + } + RET(0); + +err_out_free: + free_netdev(ndev); +err_out_iomap: + iounmap(nic->regs); +err_out_res: + pci_release_regions(pdev); +err_dma: + pci_disable_device(pdev); + vfree(nic); + + RET(err); +} + +/****************** Ethtool interface *********************/ +/* get strings for tests */ +static const char + bdx_test_names[][ETH_GSTRING_LEN] = { + "No tests defined" +}; + +/* get strings for statistics counters */ +static const char + bdx_stat_names[][ETH_GSTRING_LEN] = { + "InUCast", /* 0x7200 */ + "InMCast", /* 0x7210 */ + "InBCast", /* 0x7220 */ + "InPkts", /* 0x7230 */ + "InErrors", /* 0x7240 */ + "InDropped", /* 0x7250 */ + "FrameTooLong", /* 0x7260 */ + "FrameSequenceErrors", /* 0x7270 */ + "InVLAN", /* 0x7280 */ + "InDroppedDFE", /* 0x7290 */ + "InDroppedIntFull", /* 0x72A0 */ + "InFrameAlignErrors", /* 0x72B0 */ + + /* 0x72C0-0x72E0 RSRV */ + + "OutUCast", /* 0x72F0 */ + "OutMCast", /* 0x7300 */ + "OutBCast", /* 0x7310 */ + "OutPkts", /* 0x7320 */ + + /* 0x7330-0x7360 RSRV */ + + "OutVLAN", /* 0x7370 */ + "InUCastOctects", /* 0x7380 */ + "OutUCastOctects", /* 0x7390 */ + + /* 0x73A0-0x73B0 RSRV */ + + "InBCastOctects", /* 0x73C0 */ + "OutBCastOctects", /* 0x73D0 */ + "InOctects", /* 0x73E0 */ + "OutOctects", /* 0x73F0 */ +}; + +/* + * bdx_get_settings - get device-specific settings + * @netdev + * @ecmd + */ +static int bdx_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) +{ + u32 rdintcm; + u32 tdintcm; + struct bdx_priv *priv = netdev->priv; + + rdintcm = priv->rdintcm; + tdintcm = priv->tdintcm; + + ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE); + ecmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE); + ecmd->speed = SPEED_10000; + ecmd->duplex = DUPLEX_FULL; + ecmd->port = PORT_FIBRE; + ecmd->transceiver = XCVR_EXTERNAL; /* what does it mean? */ + ecmd->autoneg = AUTONEG_DISABLE; + + /* PCK_TH measures in multiples of FIFO bytes + We translate to packets */ + ecmd->maxtxpkt = + ((GET_PCK_TH(tdintcm) * PCK_TH_MULT) / BDX_TXF_DESC_SZ); + ecmd->maxrxpkt = + ((GET_PCK_TH(rdintcm) * PCK_TH_MULT) / sizeof(struct rxf_desc)); + + return 0; +} + +/* + * bdx_get_drvinfo - report driver information + * @netdev + * @drvinfo + */ +static void +bdx_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo) +{ + struct bdx_priv *priv = netdev->priv; + + strncat(drvinfo->driver, BDX_DRV_NAME, sizeof(drvinfo->driver)); + strncat(drvinfo->version, BDX_DRV_VERSION, sizeof(drvinfo->version)); + strncat(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version)); + strncat(drvinfo->bus_info, pci_name(priv->pdev), + sizeof(drvinfo->bus_info)); + + drvinfo->n_stats = ((priv->stats_flag) ? + (sizeof(bdx_stat_names) / ETH_GSTRING_LEN) : 0); + drvinfo->testinfo_len = 0; + drvinfo->regdump_len = 0; + drvinfo->eedump_len = 0; +} + +/* + * bdx_get_rx_csum - report whether receive checksums are turned on or off + * @netdev + */ +static u32 bdx_get_rx_csum(struct net_device *netdev) +{ + return 1; /* always on */ +} + +/* + * bdx_get_tx_csum - report whether transmit checksums are turned on or off + * @netdev + */ +static u32 bdx_get_tx_csum(struct net_device *netdev) +{ + return (netdev->features & NETIF_F_IP_CSUM) != 0; +} + +/* + * bdx_get_coalesce - get interrupt coalescing parameters + * @netdev + * @ecoal + */ +static int +bdx_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *ecoal) +{ + u32 rdintcm; + u32 tdintcm; + struct bdx_priv *priv = netdev->priv; + + rdintcm = priv->rdintcm; + tdintcm = priv->tdintcm; + + /* PCK_TH measures in multiples of FIFO bytes + We translate to packets */ + ecoal->rx_coalesce_usecs = GET_INT_COAL(rdintcm) * INT_COAL_MULT; + ecoal->rx_max_coalesced_frames = + ((GET_PCK_TH(rdintcm) * PCK_TH_MULT) / sizeof(struct rxf_desc)); + + ecoal->tx_coalesce_usecs = GET_INT_COAL(tdintcm) * INT_COAL_MULT; + ecoal->tx_max_coalesced_frames = + ((GET_PCK_TH(tdintcm) * PCK_TH_MULT) / BDX_TXF_DESC_SZ); + + /* adaptive parameters ignored */ + return 0; +} + +/* + * bdx_set_coalesce - set interrupt coalescing parameters + * @netdev + * @ecoal + */ +static int +bdx_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *ecoal) +{ + u32 rdintcm; + u32 tdintcm; + struct bdx_priv *priv = netdev->priv; + int rx_coal; + int tx_coal; + int rx_max_coal; + int tx_max_coal; + + /* Check for valid input */ + rx_coal = ecoal->rx_coalesce_usecs / INT_COAL_MULT; + tx_coal = ecoal->tx_coalesce_usecs / INT_COAL_MULT; + rx_max_coal = ecoal->rx_max_coalesced_frames; + tx_max_coal = ecoal->tx_max_coalesced_frames; + + /* Translate from packets to multiples of FIFO bytes */ + rx_max_coal = + (((rx_max_coal * sizeof(struct rxf_desc)) + PCK_TH_MULT - 1) + / PCK_TH_MULT); + tx_max_coal = + (((tx_max_coal * BDX_TXF_DESC_SZ) + PCK_TH_MULT - 1) + / PCK_TH_MULT); + + if ((rx_coal > 0x7FFF) || (tx_coal > 0x7FFF) + || (rx_max_coal > 0xF) || (tx_max_coal > 0xF)) + return -EINVAL; + + rdintcm = INT_REG_VAL(rx_coal, GET_INT_COAL_RC(priv->rdintcm), + GET_RXF_TH(priv->rdintcm), rx_max_coal); + tdintcm = INT_REG_VAL(tx_coal, GET_INT_COAL_RC(priv->tdintcm), 0, + tx_max_coal); + + priv->rdintcm = rdintcm; + priv->tdintcm = tdintcm; + + WRITE_REG(priv, regRDINTCM0, rdintcm); + WRITE_REG(priv, regTDINTCM0, tdintcm); + + return 0; +} + +/* Convert RX fifo size to number of pending packets */ +static inline int bdx_rx_fifo_size_to_packets(int rx_size) +{ + return ((FIFO_SIZE * (1 << rx_size)) / sizeof(struct rxf_desc)); +} + +/* Convert TX fifo size to number of pending packets */ +static inline int bdx_tx_fifo_size_to_packets(int tx_size) +{ + return ((FIFO_SIZE * (1 << tx_size)) / BDX_TXF_DESC_SZ); +} + +/* + * bdx_get_ringparam - report ring sizes + * @netdev + * @ring + */ +static void +bdx_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) +{ + struct bdx_priv *priv = netdev->priv; + + /*max_pending - the maximum-sized FIFO we allow */ + ring->rx_max_pending = bdx_rx_fifo_size_to_packets(3); + ring->tx_max_pending = bdx_tx_fifo_size_to_packets(3); + ring->rx_pending = bdx_rx_fifo_size_to_packets(priv->rxf_size); + ring->tx_pending = bdx_tx_fifo_size_to_packets(priv->txd_size); +} + +/* + * bdx_set_ringparam - set ring sizes + * @netdev + * @ring + */ +static int +bdx_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) +{ + struct bdx_priv *priv = netdev->priv; + int rx_size = 0; + int tx_size = 0; + + for (; rx_size < 4; rx_size++) { + if (bdx_rx_fifo_size_to_packets(rx_size) >= ring->rx_pending) + break; + } + if (rx_size == 4) + rx_size = 3; + + for (; tx_size < 4; tx_size++) { + if (bdx_tx_fifo_size_to_packets(tx_size) >= ring->tx_pending) + break; + } + if (tx_size == 4) + tx_size = 3; + + /*Is there anything to do? */ + if ((rx_size == priv->rxf_size) + && (tx_size == priv->txd_size)) + return 0; + + priv->rxf_size = rx_size; + if (rx_size > 1) + priv->rxd_size = rx_size - 1; + else + priv->rxd_size = rx_size; + + priv->txf_size = priv->txd_size = tx_size; + + if (netif_running(netdev)) { + bdx_close(netdev); + bdx_open(netdev); + } + return 0; +} + +/* + * bdx_get_strings - return a set of strings that describe the requested objects + * @netdev + * @data + */ +static void bdx_get_strings(struct net_device *netdev, u32 stringset, u8 *data) +{ + switch (stringset) { + case ETH_SS_TEST: + memcpy(data, *bdx_test_names, sizeof(bdx_test_names)); + break; + case ETH_SS_STATS: + memcpy(data, *bdx_stat_names, sizeof(bdx_stat_names)); + break; + } +} + +/* + * bdx_get_stats_count - return number of 64bit statistics counters + * @netdev + */ +static int bdx_get_stats_count(struct net_device *netdev) +{ + struct bdx_priv *priv = netdev->priv; + BDX_ASSERT(sizeof(bdx_stat_names) / ETH_GSTRING_LEN + != sizeof(struct bdx_stats) / sizeof(u64)); + return ((priv->stats_flag) ? (sizeof(bdx_stat_names) / ETH_GSTRING_LEN) + : 0); +} + +/* + * bdx_get_ethtool_stats - return device's hardware L2 statistics + * @netdev + * @stats + * @data + */ +static void bdx_get_ethtool_stats(struct net_device *netdev, + struct ethtool_stats *stats, u64 *data) +{ + struct bdx_priv *priv = netdev->priv; + + if (priv->stats_flag) { + + /* Update stats from HW */ + bdx_update_stats(priv); + + /* Copy data to user buffer */ + memcpy(data, &priv->hw_stats, sizeof(priv->hw_stats)); + } +} + +/* + * bdx_ethtool_ops - ethtool interface implementation + * @netdev + */ +static void bdx_ethtool_ops(struct net_device *netdev) +{ + static struct ethtool_ops bdx_ethtool_ops = { + .get_settings = bdx_get_settings, + .get_drvinfo = bdx_get_drvinfo, + .get_link = ethtool_op_get_link, + .get_coalesce = bdx_get_coalesce, + .set_coalesce = bdx_set_coalesce, + .get_ringparam = bdx_get_ringparam, + .set_ringparam = bdx_set_ringparam, + .get_rx_csum = bdx_get_rx_csum, + .get_tx_csum = bdx_get_tx_csum, + .get_sg = ethtool_op_get_sg, + .get_tso = ethtool_op_get_tso, + .get_strings = bdx_get_strings, + .get_stats_count = bdx_get_stats_count, + .get_ethtool_stats = bdx_get_ethtool_stats, + }; + + SET_ETHTOOL_OPS(netdev, &bdx_ethtool_ops); +} + +/** + * bdx_remove - Device Removal Routine + * @pdev: PCI device information struct + * + * bdx_remove is called by the PCI subsystem to alert the driver + * that it should release a PCI device. The could be caused by a + * Hot-Plug event, or because the driver is going to be removed from + * memory. + **/ +static void __devexit bdx_remove(struct pci_dev *pdev) +{ + struct pci_nic *nic = pci_get_drvdata(pdev); + struct net_device *ndev; + int port; + + for (port = 0; port < nic->port_num; port++) { + ndev = nic->priv[port]->ndev; + unregister_netdev(ndev); + free_netdev(ndev); + } + + /*bdx_hw_reset_direct(nic->regs); */ +#ifdef BDX_MSI + if (nic->irq_type == IRQ_MSI) + pci_disable_msi(pdev); +#endif + + iounmap(nic->regs); + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + vfree(nic); + + RET(); +} + +static struct pci_driver bdx_pci_driver = { + .name = BDX_DRV_NAME, + .id_table = bdx_pci_tbl, + .probe = bdx_probe, + .remove = __devexit_p(bdx_remove), +}; + +/* + * print_driver_id - print parameters of the driver build + */ +static void __init print_driver_id(void) +{ + printk(KERN_INFO "%s: %s, %s\n", BDX_DRV_NAME, BDX_DRV_DESC, + BDX_DRV_VERSION); + printk(KERN_INFO "%s: Options: hw_csum %s\n", BDX_DRV_NAME, + BDX_MSI_STRING); +} + +static int __init bdx_module_init(void) +{ + ENTER; + bdx_firmware_endianess(); + init_txd_sizes(); + print_driver_id(); + RET(pci_register_driver(&bdx_pci_driver)); +} + +module_init(bdx_module_init); + +static void __exit bdx_module_exit(void) +{ + ENTER; + pci_unregister_driver(&bdx_pci_driver); + RET(); +} + +module_exit(bdx_module_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(BDX_DRV_DESC); diff --git a/drivers/net/tehuti.h b/drivers/net/tehuti.h new file mode 100644 index 00000000000..efd170f451b --- /dev/null +++ b/drivers/net/tehuti.h @@ -0,0 +1,564 @@ +/* + * Tehuti Networks(R) Network Driver + * Copyright (C) 2007 Tehuti Networks Ltd. All rights reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef _TEHUTI_H +#define _TEHUTI_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Compile Time Switches */ +/* start */ +#define BDX_TSO +#define BDX_LLTX +#define BDX_DELAY_WPTR +/* #define BDX_MSI */ +/* end */ + +#if !defined CONFIG_PCI_MSI +# undef BDX_MSI +#endif + +#define BDX_DEF_MSG_ENABLE (NETIF_MSG_DRV | \ + NETIF_MSG_PROBE | \ + NETIF_MSG_LINK) + +/* ioctl ops */ +#define BDX_OP_READ 1 +#define BDX_OP_WRITE 2 + +/* RX copy break size */ +#define BDX_COPYBREAK 257 + +#define DRIVER_AUTHOR "Tehuti Networks(R)" +#define BDX_DRV_DESC "Tehuti Networks(R) Network Driver" +#define BDX_DRV_NAME "tehuti" +#define BDX_NIC_NAME "Tehuti 10 Giga TOE SmartNIC" +#define BDX_NIC2PORT_NAME "Tehuti 2-Port 10 Giga TOE SmartNIC" +#define BDX_DRV_VERSION "7.29.3" + +#ifdef BDX_MSI +# define BDX_MSI_STRING "msi " +#else +# define BDX_MSI_STRING "" +#endif + +/* netdev tx queue len for Luxor. default value is, btw, 1000 + * ifcontig eth1 txqueuelen 3000 - to change it at runtime */ +#define BDX_NDEV_TXQ_LEN 3000 + +#define FIFO_SIZE 4096 +#define FIFO_EXTRA_SPACE 1024 + +#define MIN(x, y) ((x) < (y) ? (x) : (y)) + +#if BITS_PER_LONG == 64 +# define H32_64(x) (u32) ((u64)(x) >> 32) +# define L32_64(x) (u32) ((u64)(x) & 0xffffffff) +#elif BITS_PER_LONG == 32 +# define H32_64(x) 0 +# define L32_64(x) ((u32) (x)) +#else /* BITS_PER_LONG == ?? */ +# error BITS_PER_LONG is undefined. Must be 64 or 32 +#endif /* BITS_PER_LONG */ + +#ifdef __BIG_ENDIAN +# define CPU_CHIP_SWAP32(x) swab32(x) +# define CPU_CHIP_SWAP16(x) swab16(x) +#else +# define CPU_CHIP_SWAP32(x) (x) +# define CPU_CHIP_SWAP16(x) (x) +#endif + +#define READ_REG(pp, reg) readl(pp->pBdxRegs + reg) +#define WRITE_REG(pp, reg, val) writel(val, pp->pBdxRegs + reg) + +#ifndef DMA_64BIT_MASK +# define DMA_64BIT_MASK 0xffffffffffffffffULL +#endif + +#ifndef DMA_32BIT_MASK +# define DMA_32BIT_MASK 0x00000000ffffffffULL +#endif + +#ifndef NET_IP_ALIGN +# define NET_IP_ALIGN 2 +#endif + +#ifndef NETDEV_TX_OK +# define NETDEV_TX_OK 0 +#endif + +#define LUXOR_MAX_PORT 2 +#define BDX_MAX_RX_DONE 150 +#define BDX_TXF_DESC_SZ 16 +#define BDX_MAX_TX_LEVEL (priv->txd_fifo0.m.memsz - 16) +#define BDX_MIN_TX_LEVEL 256 +#define BDX_NO_UPD_PACKETS 40 + +struct pci_nic { + int port_num; + void __iomem *regs; + int irq_type; + struct bdx_priv *priv[LUXOR_MAX_PORT]; +}; + +enum { IRQ_INTX, IRQ_MSI, IRQ_MSIX }; + +#define PCK_TH_MULT 128 +#define INT_COAL_MULT 2 + +#define BITS_MASK(nbits) ((1<>nshift)&BITS_MASK(nbits)) +#define BITS_SHIFT_MASK(nbits, nshift) (BITS_MASK(nbits)< Date: Tue, 18 Sep 2007 15:12:50 -0400 Subject: [SSB]: add Sonics Silicon Backplane bus support SSB is an SoC bus used in a number of embedded devices. The most well-known of these devices is probably the Linksys WRT54G, but there are others as well. The bus is also used internally on the BCM43xx and BCM44xx devices from Broadcom. This patch also includes support for SSB ID tables in modules, so that SSB drivers can be loaded automatically. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- MAINTAINERS | 6 + drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/ssb/Kconfig | 117 +++ drivers/ssb/Makefile | 18 + drivers/ssb/b43_pci_bridge.c | 46 ++ drivers/ssb/driver_chipcommon.c | 446 +++++++++++ drivers/ssb/driver_extif.c | 129 ++++ drivers/ssb/driver_mipscore.c | 223 ++++++ drivers/ssb/driver_pcicore.c | 576 ++++++++++++++ drivers/ssb/main.c | 1162 +++++++++++++++++++++++++++++ drivers/ssb/pci.c | 740 ++++++++++++++++++ drivers/ssb/pcihost_wrapper.c | 104 +++ drivers/ssb/pcmcia.c | 271 +++++++ drivers/ssb/scan.c | 413 ++++++++++ drivers/ssb/ssb_private.h | 136 ++++ include/linux/mod_devicetable.h | 15 + include/linux/ssb/ssb.h | 424 +++++++++++ include/linux/ssb/ssb_driver_chipcommon.h | 396 ++++++++++ include/linux/ssb/ssb_driver_extif.h | 204 +++++ include/linux/ssb/ssb_driver_mips.h | 46 ++ include/linux/ssb/ssb_driver_pci.h | 106 +++ include/linux/ssb/ssb_regs.h | 292 ++++++++ scripts/mod/file2alias.c | 19 + 24 files changed, 5892 insertions(+) create mode 100644 drivers/ssb/Kconfig create mode 100644 drivers/ssb/Makefile create mode 100644 drivers/ssb/b43_pci_bridge.c create mode 100644 drivers/ssb/driver_chipcommon.c create mode 100644 drivers/ssb/driver_extif.c create mode 100644 drivers/ssb/driver_mipscore.c create mode 100644 drivers/ssb/driver_pcicore.c create mode 100644 drivers/ssb/main.c create mode 100644 drivers/ssb/pci.c create mode 100644 drivers/ssb/pcihost_wrapper.c create mode 100644 drivers/ssb/pcmcia.c create mode 100644 drivers/ssb/scan.c create mode 100644 drivers/ssb/ssb_private.h create mode 100644 include/linux/ssb/ssb.h create mode 100644 include/linux/ssb/ssb_driver_chipcommon.h create mode 100644 include/linux/ssb/ssb_driver_extif.h create mode 100644 include/linux/ssb/ssb_driver_mips.h create mode 100644 include/linux/ssb/ssb_driver_pci.h create mode 100644 include/linux/ssb/ssb_regs.h (limited to 'drivers') diff --git a/MAINTAINERS b/MAINTAINERS index 3f07d5ff85f..7524cd802da 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3446,6 +3446,12 @@ M: tsbogend@alpha.franken.de L: netdev@vger.kernel.org S: Maintained +SONICS SILICON BACKPLANE DRIVER (SSB) +P: Michael Buesch +M: mb@bu3sch.de +L: netdev@vger.kernel.org +S: Maintained + SONY VAIO CONTROL DEVICE DRIVER P: Mattia Dongili M: malattia@linux.it diff --git a/drivers/Kconfig b/drivers/Kconfig index 3e1c442deff..7bdae47d6b9 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -58,6 +58,8 @@ source "drivers/power/Kconfig" source "drivers/hwmon/Kconfig" +source "drivers/ssb/Kconfig" + source "drivers/mfd/Kconfig" source "drivers/media/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index f0878b2ec55..a168eacdcd9 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -88,3 +88,4 @@ obj-$(CONFIG_DMA_ENGINE) += dma/ obj-$(CONFIG_HID) += hid/ obj-$(CONFIG_PPC_PS3) += ps3/ obj-$(CONFIG_OF) += of/ +obj-$(CONFIG_SSB) += ssb/ diff --git a/drivers/ssb/Kconfig b/drivers/ssb/Kconfig new file mode 100644 index 00000000000..b4a5e5e9d9f --- /dev/null +++ b/drivers/ssb/Kconfig @@ -0,0 +1,117 @@ +menu "Sonics Silicon Backplane" + +config SSB_POSSIBLE + bool + depends on HAS_IOMEM + default y + +config SSB + tristate "Sonics Silicon Backplane support" + depends on SSB_POSSIBLE + help + Support for the Sonics Silicon Backplane bus. + You only need to enable this option, if you are + configuring a kernel for an embedded system with + this bus. + It will be auto-selected if needed in other + environments. + + The module will be called ssb. + + If unsure, say N. + +config SSB_PCIHOST_POSSIBLE + bool + depends on SSB && PCI + default y + +config SSB_PCIHOST + bool "Support for SSB on PCI-bus host" + depends on SSB_PCIHOST_POSSIBLE + default y + help + Support for a Sonics Silicon Backplane on top + of a PCI device. + + If unsure, say Y + +config SSB_PCMCIAHOST_POSSIBLE + bool + depends on SSB && PCMCIA && EXPERIMENTAL + default y + +config SSB_PCMCIAHOST + bool "Support for SSB on PCMCIA-bus host (EXPERIMENTAL)" + depends on SSB_PCMCIAHOST_POSSIBLE + help + Support for a Sonics Silicon Backplane on top + of a PCMCIA device. + + If unsure, say N + +config SSB_SILENT + bool "No SSB kernel messages" + depends on SSB && EMBEDDED + help + This option turns off all Sonics Silicon Backplane printks. + Note that you won't be able to identify problems, once + messages are turned off. + This might only be desired for production kernels on + embedded devices to reduce the kernel size. + + Say N + +config SSB_DEBUG + bool "SSB debugging" + depends on SSB && !SSB_SILENT + help + This turns on additional runtime checks and debugging + messages. Turn this on for SSB troubleshooting. + + If unsure, say N + +config SSB_SERIAL + bool + depends on SSB + # ChipCommon and ExtIf serial support routines. + +config SSB_DRIVER_PCICORE_POSSIBLE + bool + depends on SSB_PCIHOST + default y + +config SSB_DRIVER_PCICORE + bool "SSB PCI core driver" + depends on SSB_DRIVER_PCICORE_POSSIBLE + help + Driver for the Sonics Silicon Backplane attached + Broadcom PCI core. + + If unsure, say Y + +config SSB_PCICORE_HOSTMODE + bool "Hostmode support for SSB PCI core (EXPERIMENTAL)" + depends on SSB_DRIVER_PCICORE && SSB_DRIVER_MIPS && EXPERIMENTAL + help + PCIcore hostmode operation (external PCI bus). + +config SSB_DRIVER_MIPS + bool "SSB Broadcom MIPS core driver (EXPERIMENTAL)" + depends on SSB && MIPS && EXPERIMENTAL + select SSB_SERIAL + help + Driver for the Sonics Silicon Backplane attached + Broadcom MIPS core. + + If unsure, say N + +config SSB_DRIVER_EXTIF + bool "SSB Broadcom EXTIF core driver (EXPERIMENTAL)" + depends on SSB_DRIVER_MIPS && EXPERIMENTAL + help + Driver for the Sonics Silicon Backplane attached + Broadcom EXTIF core. + + If unsure, say N + +endmenu diff --git a/drivers/ssb/Makefile b/drivers/ssb/Makefile new file mode 100644 index 00000000000..7be39759580 --- /dev/null +++ b/drivers/ssb/Makefile @@ -0,0 +1,18 @@ +# core +ssb-y += main.o scan.o + +# host support +ssb-$(CONFIG_SSB_PCIHOST) += pci.o pcihost_wrapper.o +ssb-$(CONFIG_SSB_PCMCIAHOST) += pcmcia.o + +# built-in drivers +ssb-y += driver_chipcommon.o +ssb-$(CONFIG_SSB_DRIVER_MIPS) += driver_mipscore.o +ssb-$(CONFIG_SSB_DRIVER_EXTIF) += driver_extif.o +ssb-$(CONFIG_SSB_DRIVER_PCICORE) += driver_pcicore.o + +# b43 pci-ssb-bridge driver +# Not strictly a part of SSB, but kept here for convenience +ssb-$(CONFIG_SSB_PCIHOST) += b43_pci_bridge.o + +obj-$(CONFIG_SSB) += ssb.o diff --git a/drivers/ssb/b43_pci_bridge.c b/drivers/ssb/b43_pci_bridge.c new file mode 100644 index 00000000000..fa3bd292f5f --- /dev/null +++ b/drivers/ssb/b43_pci_bridge.c @@ -0,0 +1,46 @@ +/* + * Broadcom 43xx PCI-SSB bridge module + * + * This technically is a seperate PCI driver module, but + * because of its small size we include it in the SSB core + * instead of creating a standalone module. + * + * Copyright 2007 Michael Buesch + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include +#include + + +static const struct pci_device_id b43_pci_bridge_tbl[] = { + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4301) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4307) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4311) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4312) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4318) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4319) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4320) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4321) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4324) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4325) }, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, b43_pci_bridge_tbl); + +static struct pci_driver b43_pci_bridge_driver = { + .name = "b43-pci-bridge", + .id_table = b43_pci_bridge_tbl, +}; + + +int __init b43_pci_ssb_bridge_init(void) +{ + return ssb_pcihost_register(&b43_pci_bridge_driver); +} + +void __exit b43_pci_ssb_bridge_exit(void) +{ + ssb_pcihost_unregister(&b43_pci_bridge_driver); +} diff --git a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c new file mode 100644 index 00000000000..a890544e8fb --- /dev/null +++ b/drivers/ssb/driver_chipcommon.c @@ -0,0 +1,446 @@ +/* + * Sonics Silicon Backplane + * Broadcom ChipCommon core driver + * + * Copyright 2005, Broadcom Corporation + * Copyright 2006, 2007, Michael Buesch + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include +#include +#include + +#include "ssb_private.h" + + +/* Clock sources */ +enum ssb_clksrc { + /* PCI clock */ + SSB_CHIPCO_CLKSRC_PCI, + /* Crystal slow clock oscillator */ + SSB_CHIPCO_CLKSRC_XTALOS, + /* Low power oscillator */ + SSB_CHIPCO_CLKSRC_LOPWROS, +}; + + +static inline u32 chipco_read32(struct ssb_chipcommon *cc, + u16 offset) +{ + return ssb_read32(cc->dev, offset); +} + +static inline void chipco_write32(struct ssb_chipcommon *cc, + u16 offset, + u32 value) +{ + ssb_write32(cc->dev, offset, value); +} + +static inline void chipco_write32_masked(struct ssb_chipcommon *cc, u16 offset, + u32 mask, u32 value) +{ + value &= mask; + value |= chipco_read32(cc, offset) & ~mask; + chipco_write32(cc, offset, value); +} + +void ssb_chipco_set_clockmode(struct ssb_chipcommon *cc, + enum ssb_clkmode mode) +{ + struct ssb_device *ccdev = cc->dev; + struct ssb_bus *bus; + u32 tmp; + + if (!ccdev) + return; + bus = ccdev->bus; + /* chipcommon cores prior to rev6 don't support dynamic clock control */ + if (ccdev->id.revision < 6) + return; + /* chipcommon cores rev10 are a whole new ball game */ + if (ccdev->id.revision >= 10) + return; + if (!(cc->capabilities & SSB_CHIPCO_CAP_PCTL)) + return; + + switch (mode) { + case SSB_CLKMODE_SLOW: + tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL); + tmp |= SSB_CHIPCO_SLOWCLKCTL_FSLOW; + chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp); + break; + case SSB_CLKMODE_FAST: + ssb_pci_xtal(bus, SSB_GPIO_XTAL, 1); /* Force crystal on */ + tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL); + tmp &= ~SSB_CHIPCO_SLOWCLKCTL_FSLOW; + tmp |= SSB_CHIPCO_SLOWCLKCTL_IPLL; + chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp); + break; + case SSB_CLKMODE_DYNAMIC: + tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL); + tmp &= ~SSB_CHIPCO_SLOWCLKCTL_FSLOW; + tmp &= ~SSB_CHIPCO_SLOWCLKCTL_IPLL; + tmp &= ~SSB_CHIPCO_SLOWCLKCTL_ENXTAL; + if ((tmp & SSB_CHIPCO_SLOWCLKCTL_SRC) != SSB_CHIPCO_SLOWCLKCTL_SRC_XTAL) + tmp |= SSB_CHIPCO_SLOWCLKCTL_ENXTAL; + chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp); + + /* for dynamic control, we have to release our xtal_pu "force on" */ + if (tmp & SSB_CHIPCO_SLOWCLKCTL_ENXTAL) + ssb_pci_xtal(bus, SSB_GPIO_XTAL, 0); + break; + default: + SSB_WARN_ON(1); + } +} + +/* Get the Slow Clock Source */ +static enum ssb_clksrc chipco_pctl_get_slowclksrc(struct ssb_chipcommon *cc) +{ + struct ssb_bus *bus = cc->dev->bus; + u32 uninitialized_var(tmp); + + if (cc->dev->id.revision < 6) { + if (bus->bustype == SSB_BUSTYPE_SSB || + bus->bustype == SSB_BUSTYPE_PCMCIA) + return SSB_CHIPCO_CLKSRC_XTALOS; + if (bus->bustype == SSB_BUSTYPE_PCI) { + pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT, &tmp); + if (tmp & 0x10) + return SSB_CHIPCO_CLKSRC_PCI; + return SSB_CHIPCO_CLKSRC_XTALOS; + } + } + if (cc->dev->id.revision < 10) { + tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL); + tmp &= 0x7; + if (tmp == 0) + return SSB_CHIPCO_CLKSRC_LOPWROS; + if (tmp == 1) + return SSB_CHIPCO_CLKSRC_XTALOS; + if (tmp == 2) + return SSB_CHIPCO_CLKSRC_PCI; + } + + return SSB_CHIPCO_CLKSRC_XTALOS; +} + +/* Get maximum or minimum (depending on get_max flag) slowclock frequency. */ +static int chipco_pctl_clockfreqlimit(struct ssb_chipcommon *cc, int get_max) +{ + int uninitialized_var(limit); + enum ssb_clksrc clocksrc; + int divisor = 1; + u32 tmp; + + clocksrc = chipco_pctl_get_slowclksrc(cc); + if (cc->dev->id.revision < 6) { + switch (clocksrc) { + case SSB_CHIPCO_CLKSRC_PCI: + divisor = 64; + break; + case SSB_CHIPCO_CLKSRC_XTALOS: + divisor = 32; + break; + default: + SSB_WARN_ON(1); + } + } else if (cc->dev->id.revision < 10) { + switch (clocksrc) { + case SSB_CHIPCO_CLKSRC_LOPWROS: + break; + case SSB_CHIPCO_CLKSRC_XTALOS: + case SSB_CHIPCO_CLKSRC_PCI: + tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL); + divisor = (tmp >> 16) + 1; + divisor *= 4; + break; + } + } else { + tmp = chipco_read32(cc, SSB_CHIPCO_SYSCLKCTL); + divisor = (tmp >> 16) + 1; + divisor *= 4; + } + + switch (clocksrc) { + case SSB_CHIPCO_CLKSRC_LOPWROS: + if (get_max) + limit = 43000; + else + limit = 25000; + break; + case SSB_CHIPCO_CLKSRC_XTALOS: + if (get_max) + limit = 20200000; + else + limit = 19800000; + break; + case SSB_CHIPCO_CLKSRC_PCI: + if (get_max) + limit = 34000000; + else + limit = 25000000; + break; + } + limit /= divisor; + + return limit; +} + +static void chipco_powercontrol_init(struct ssb_chipcommon *cc) +{ + struct ssb_bus *bus = cc->dev->bus; + + if (bus->chip_id == 0x4321) { + if (bus->chip_rev == 0) + chipco_write32(cc, SSB_CHIPCO_CHIPCTL, 0x3A4); + else if (bus->chip_rev == 1) + chipco_write32(cc, SSB_CHIPCO_CHIPCTL, 0xA4); + } + + if (!(cc->capabilities & SSB_CHIPCO_CAP_PCTL)) + return; + + if (cc->dev->id.revision >= 10) { + /* Set Idle Power clock rate to 1Mhz */ + chipco_write32(cc, SSB_CHIPCO_SYSCLKCTL, + (chipco_read32(cc, SSB_CHIPCO_SYSCLKCTL) & + 0x0000FFFF) | 0x00040000); + } else { + int maxfreq; + + maxfreq = chipco_pctl_clockfreqlimit(cc, 1); + chipco_write32(cc, SSB_CHIPCO_PLLONDELAY, + (maxfreq * 150 + 999999) / 1000000); + chipco_write32(cc, SSB_CHIPCO_FREFSELDELAY, + (maxfreq * 15 + 999999) / 1000000); + } +} + +static void calc_fast_powerup_delay(struct ssb_chipcommon *cc) +{ + struct ssb_bus *bus = cc->dev->bus; + int minfreq; + unsigned int tmp; + u32 pll_on_delay; + + if (bus->bustype != SSB_BUSTYPE_PCI) + return; + if (!(cc->capabilities & SSB_CHIPCO_CAP_PCTL)) + return; + + minfreq = chipco_pctl_clockfreqlimit(cc, 0); + pll_on_delay = chipco_read32(cc, SSB_CHIPCO_PLLONDELAY); + tmp = (((pll_on_delay + 2) * 1000000) + (minfreq - 1)) / minfreq; + SSB_WARN_ON(tmp & ~0xFFFF); + + cc->fast_pwrup_delay = tmp; +} + +void ssb_chipcommon_init(struct ssb_chipcommon *cc) +{ + if (!cc->dev) + return; /* We don't have a ChipCommon */ + chipco_powercontrol_init(cc); + ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST); + calc_fast_powerup_delay(cc); +} + +void ssb_chipco_suspend(struct ssb_chipcommon *cc, pm_message_t state) +{ + if (!cc->dev) + return; + ssb_chipco_set_clockmode(cc, SSB_CLKMODE_SLOW); +} + +void ssb_chipco_resume(struct ssb_chipcommon *cc) +{ + if (!cc->dev) + return; + chipco_powercontrol_init(cc); + ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST); +} + +/* Get the processor clock */ +void ssb_chipco_get_clockcpu(struct ssb_chipcommon *cc, + u32 *plltype, u32 *n, u32 *m) +{ + *n = chipco_read32(cc, SSB_CHIPCO_CLOCK_N); + *plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT); + switch (*plltype) { + case SSB_PLLTYPE_2: + case SSB_PLLTYPE_4: + case SSB_PLLTYPE_6: + case SSB_PLLTYPE_7: + *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_MIPS); + break; + case SSB_PLLTYPE_3: + /* 5350 uses m2 to control mips */ + *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_M2); + break; + default: + *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_SB); + break; + } +} + +/* Get the bus clock */ +void ssb_chipco_get_clockcontrol(struct ssb_chipcommon *cc, + u32 *plltype, u32 *n, u32 *m) +{ + *n = chipco_read32(cc, SSB_CHIPCO_CLOCK_N); + *plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT); + switch (*plltype) { + case SSB_PLLTYPE_6: /* 100/200 or 120/240 only */ + *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_MIPS); + break; + case SSB_PLLTYPE_3: /* 25Mhz, 2 dividers */ + if (cc->dev->bus->chip_id != 0x5365) { + *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_M2); + break; + } + /* Fallthough */ + default: + *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_SB); + } +} + +void ssb_chipco_timing_init(struct ssb_chipcommon *cc, + unsigned long ns) +{ + struct ssb_device *dev = cc->dev; + struct ssb_bus *bus = dev->bus; + u32 tmp; + + /* set register for external IO to control LED. */ + chipco_write32(cc, SSB_CHIPCO_PROG_CFG, 0x11); + tmp = DIV_ROUND_UP(10, ns) << SSB_PROG_WCNT_3_SHIFT; /* Waitcount-3 = 10ns */ + tmp |= DIV_ROUND_UP(40, ns) << SSB_PROG_WCNT_1_SHIFT; /* Waitcount-1 = 40ns */ + tmp |= DIV_ROUND_UP(240, ns); /* Waitcount-0 = 240ns */ + chipco_write32(cc, SSB_CHIPCO_PROG_WAITCNT, tmp); /* 0x01020a0c for a 100Mhz clock */ + + /* Set timing for the flash */ + tmp = DIV_ROUND_UP(10, ns) << SSB_FLASH_WCNT_3_SHIFT; /* Waitcount-3 = 10nS */ + tmp |= DIV_ROUND_UP(10, ns) << SSB_FLASH_WCNT_1_SHIFT; /* Waitcount-1 = 10nS */ + tmp |= DIV_ROUND_UP(120, ns); /* Waitcount-0 = 120nS */ + if ((bus->chip_id == 0x5365) || + (dev->id.revision < 9)) + chipco_write32(cc, SSB_CHIPCO_FLASH_WAITCNT, tmp); + if ((bus->chip_id == 0x5365) || + (dev->id.revision < 9) || + ((bus->chip_id == 0x5350) && (bus->chip_rev == 0))) + chipco_write32(cc, SSB_CHIPCO_PCMCIA_MEMWAIT, tmp); + + if (bus->chip_id == 0x5350) { + /* Enable EXTIF */ + tmp = DIV_ROUND_UP(10, ns) << SSB_PROG_WCNT_3_SHIFT; /* Waitcount-3 = 10ns */ + tmp |= DIV_ROUND_UP(20, ns) << SSB_PROG_WCNT_2_SHIFT; /* Waitcount-2 = 20ns */ + tmp |= DIV_ROUND_UP(100, ns) << SSB_PROG_WCNT_1_SHIFT; /* Waitcount-1 = 100ns */ + tmp |= DIV_ROUND_UP(120, ns); /* Waitcount-0 = 120ns */ + chipco_write32(cc, SSB_CHIPCO_PROG_WAITCNT, tmp); /* 0x01020a0c for a 100Mhz clock */ + } +} + +/* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */ +void +ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc, u32 ticks) +{ + /* instant NMI */ + chipco_write32(cc, SSB_CHIPCO_WATCHDOG, ticks); +} + +u32 ssb_chipco_gpio_in(struct ssb_chipcommon *cc, u32 mask) +{ + return chipco_read32(cc, SSB_CHIPCO_GPIOIN) & mask; +} + +void ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value) +{ + return chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUT, mask, value); +} + +void ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value) +{ + return chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUTEN, mask, value); +} + +#ifdef CONFIG_SSB_SERIAL +int ssb_chipco_serial_init(struct ssb_chipcommon *cc, + struct ssb_serial_port *ports) +{ + struct ssb_bus *bus = cc->dev->bus; + int nr_ports = 0; + u32 plltype; + unsigned int irq; + u32 baud_base, div; + u32 i, n; + + plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT); + irq = ssb_mips_irq(cc->dev); + + if (plltype == SSB_PLLTYPE_1) { + /* PLL clock */ + baud_base = ssb_calc_clock_rate(plltype, + chipco_read32(cc, SSB_CHIPCO_CLOCK_N), + chipco_read32(cc, SSB_CHIPCO_CLOCK_M2)); + div = 1; + } else { + if (cc->dev->id.revision >= 11) { + /* Fixed ALP clock */ + baud_base = 20000000; + div = 1; + /* Set the override bit so we don't divide it */ + chipco_write32(cc, SSB_CHIPCO_CORECTL, + SSB_CHIPCO_CORECTL_UARTCLK0); + } else if (cc->dev->id.revision >= 3) { + /* Internal backplane clock */ + baud_base = ssb_clockspeed(bus); + div = chipco_read32(cc, SSB_CHIPCO_CLKDIV) + & SSB_CHIPCO_CLKDIV_UART; + } else { + /* Fixed internal backplane clock */ + baud_base = 88000000; + div = 48; + } + + /* Clock source depends on strapping if UartClkOverride is unset */ + if ((cc->dev->id.revision > 0) && + !(chipco_read32(cc, SSB_CHIPCO_CORECTL) & SSB_CHIPCO_CORECTL_UARTCLK0)) { + if ((cc->capabilities & SSB_CHIPCO_CAP_UARTCLK) == + SSB_CHIPCO_CAP_UARTCLK_INT) { + /* Internal divided backplane clock */ + baud_base /= div; + } else { + /* Assume external clock of 1.8432 MHz */ + baud_base = 1843200; + } + } + } + + /* Determine the registers of the UARTs */ + n = (cc->capabilities & SSB_CHIPCO_CAP_NRUART); + for (i = 0; i < n; i++) { + void __iomem *cc_mmio; + void __iomem *uart_regs; + + cc_mmio = cc->dev->bus->mmio + (cc->dev->core_index * SSB_CORE_SIZE); + uart_regs = cc_mmio + SSB_CHIPCO_UART0_DATA; + /* Offset changed at after rev 0 */ + if (cc->dev->id.revision == 0) + uart_regs += (i * 8); + else + uart_regs += (i * 256); + + nr_ports++; + ports[i].regs = uart_regs; + ports[i].irq = irq; + ports[i].baud_base = baud_base; + ports[i].reg_shift = 0; + } + + return nr_ports; +} +#endif /* CONFIG_SSB_SERIAL */ diff --git a/drivers/ssb/driver_extif.c b/drivers/ssb/driver_extif.c new file mode 100644 index 00000000000..fe55eb8b038 --- /dev/null +++ b/drivers/ssb/driver_extif.c @@ -0,0 +1,129 @@ +/* + * Sonics Silicon Backplane + * Broadcom EXTIF core driver + * + * Copyright 2005, Broadcom Corporation + * Copyright 2006, 2007, Michael Buesch + * Copyright 2006, 2007, Felix Fietkau + * Copyright 2007, Aurelien Jarno + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include +#include +#include + +#include "ssb_private.h" + + +static inline u32 extif_read32(struct ssb_extif *extif, u16 offset) +{ + return ssb_read32(extif->dev, offset); +} + +static inline void extif_write32(struct ssb_extif *extif, u16 offset, u32 value) +{ + ssb_write32(extif->dev, offset, value); +} + +static inline void extif_write32_masked(struct ssb_extif *extif, u16 offset, + u32 mask, u32 value) +{ + value &= mask; + value |= extif_read32(extif, offset) & ~mask; + extif_write32(extif, offset, value); +} + +#ifdef CONFIG_SSB_SERIAL +static bool serial_exists(u8 *regs) +{ + u8 save_mcr, msr = 0; + + if (regs) { + save_mcr = regs[UART_MCR]; + regs[UART_MCR] = (UART_MCR_LOOP | UART_MCR_OUT2 | UART_MCR_RTS); + msr = regs[UART_MSR] & (UART_MSR_DCD | UART_MSR_RI + | UART_MSR_CTS | UART_MSR_DSR); + regs[UART_MCR] = save_mcr; + } + return (msr == (UART_MSR_DCD | UART_MSR_CTS)); +} + +int ssb_extif_serial_init(struct ssb_extif *extif, struct ssb_serial_port *ports) +{ + u32 i, nr_ports = 0; + + /* Disable GPIO interrupt initially */ + extif_write32(extif, SSB_EXTIF_GPIO_INTPOL, 0); + extif_write32(extif, SSB_EXTIF_GPIO_INTMASK, 0); + + for (i = 0; i < 2; i++) { + void __iomem *uart_regs; + + uart_regs = ioremap_nocache(SSB_EUART, 16); + if (uart_regs) { + uart_regs += (i * 8); + + if (serial_exists(uart_regs) && ports) { + extif_write32(extif, SSB_EXTIF_GPIO_INTMASK, 2); + + nr_ports++; + ports[i].regs = uart_regs; + ports[i].irq = 2; + ports[i].baud_base = 13500000; + ports[i].reg_shift = 0; + } + iounmap(uart_regs); + } + } + return nr_ports; +} +#endif /* CONFIG_SSB_SERIAL */ + +void ssb_extif_timing_init(struct ssb_extif *extif, unsigned long ns) +{ + u32 tmp; + + /* Initialize extif so we can get to the LEDs and external UART */ + extif_write32(extif, SSB_EXTIF_PROG_CFG, SSB_EXTCFG_EN); + + /* Set timing for the flash */ + tmp = DIV_ROUND_UP(10, ns) << SSB_PROG_WCNT_3_SHIFT; + tmp |= DIV_ROUND_UP(40, ns) << SSB_PROG_WCNT_1_SHIFT; + tmp |= DIV_ROUND_UP(120, ns); + extif_write32(extif, SSB_EXTIF_PROG_WAITCNT, tmp); + + /* Set programmable interface timing for external uart */ + tmp = DIV_ROUND_UP(10, ns) << SSB_PROG_WCNT_3_SHIFT; + tmp |= DIV_ROUND_UP(20, ns) << SSB_PROG_WCNT_2_SHIFT; + tmp |= DIV_ROUND_UP(100, ns) << SSB_PROG_WCNT_1_SHIFT; + tmp |= DIV_ROUND_UP(120, ns); + extif_write32(extif, SSB_EXTIF_PROG_WAITCNT, tmp); +} + +void ssb_extif_get_clockcontrol(struct ssb_extif *extif, + u32 *pll_type, u32 *n, u32 *m) +{ + *pll_type = SSB_PLLTYPE_1; + *n = extif_read32(extif, SSB_EXTIF_CLOCK_N); + *m = extif_read32(extif, SSB_EXTIF_CLOCK_SB); +} + +u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask) +{ + return extif_read32(extif, SSB_EXTIF_GPIO_IN) & mask; +} + +void ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, u32 value) +{ + return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUT(0), + mask, value); +} + +void ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, u32 value) +{ + return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUTEN(0), + mask, value); +} + diff --git a/drivers/ssb/driver_mipscore.c b/drivers/ssb/driver_mipscore.c new file mode 100644 index 00000000000..ab8691a3258 --- /dev/null +++ b/drivers/ssb/driver_mipscore.c @@ -0,0 +1,223 @@ +/* + * Sonics Silicon Backplane + * Broadcom MIPS core driver + * + * Copyright 2005, Broadcom Corporation + * Copyright 2006, 2007, Michael Buesch + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include + +#include +#include +#include +#include + +#include "ssb_private.h" + + +static inline u32 mips_read32(struct ssb_mipscore *mcore, + u16 offset) +{ + return ssb_read32(mcore->dev, offset); +} + +static inline void mips_write32(struct ssb_mipscore *mcore, + u16 offset, + u32 value) +{ + ssb_write32(mcore->dev, offset, value); +} + +static const u32 ipsflag_irq_mask[] = { + 0, + SSB_IPSFLAG_IRQ1, + SSB_IPSFLAG_IRQ2, + SSB_IPSFLAG_IRQ3, + SSB_IPSFLAG_IRQ4, +}; + +static const u32 ipsflag_irq_shift[] = { + 0, + SSB_IPSFLAG_IRQ1_SHIFT, + SSB_IPSFLAG_IRQ2_SHIFT, + SSB_IPSFLAG_IRQ3_SHIFT, + SSB_IPSFLAG_IRQ4_SHIFT, +}; + +static inline u32 ssb_irqflag(struct ssb_device *dev) +{ + return ssb_read32(dev, SSB_TPSFLAG) & SSB_TPSFLAG_BPFLAG; +} + +/* Get the MIPS IRQ assignment for a specified device. + * If unassigned, 0 is returned. + */ +unsigned int ssb_mips_irq(struct ssb_device *dev) +{ + struct ssb_bus *bus = dev->bus; + u32 irqflag; + u32 ipsflag; + u32 tmp; + unsigned int irq; + + irqflag = ssb_irqflag(dev); + ipsflag = ssb_read32(bus->mipscore.dev, SSB_IPSFLAG); + for (irq = 1; irq <= 4; irq++) { + tmp = ((ipsflag & ipsflag_irq_mask[irq]) >> ipsflag_irq_shift[irq]); + if (tmp == irqflag) + break; + } + if (irq == 5) + irq = 0; + + return irq; +} + +static void clear_irq(struct ssb_bus *bus, unsigned int irq) +{ + struct ssb_device *dev = bus->mipscore.dev; + + /* Clear the IRQ in the MIPScore backplane registers */ + if (irq == 0) { + ssb_write32(dev, SSB_INTVEC, 0); + } else { + ssb_write32(dev, SSB_IPSFLAG, + ssb_read32(dev, SSB_IPSFLAG) | + ipsflag_irq_mask[irq]); + } +} + +static void set_irq(struct ssb_device *dev, unsigned int irq) +{ + unsigned int oldirq = ssb_mips_irq(dev); + struct ssb_bus *bus = dev->bus; + struct ssb_device *mdev = bus->mipscore.dev; + u32 irqflag = ssb_irqflag(dev); + + dev->irq = irq + 2; + + ssb_dprintk(KERN_INFO PFX + "set_irq: core 0x%04x, irq %d => %d\n", + dev->id.coreid, oldirq, irq); + /* clear the old irq */ + if (oldirq == 0) + ssb_write32(mdev, SSB_INTVEC, (~(1 << irqflag) & ssb_read32(mdev, SSB_INTVEC))); + else + clear_irq(bus, oldirq); + + /* assign the new one */ + if (irq == 0) + ssb_write32(mdev, SSB_INTVEC, ((1 << irqflag) & ssb_read32(mdev, SSB_INTVEC))); + + irqflag <<= ipsflag_irq_shift[irq]; + irqflag |= (ssb_read32(mdev, SSB_IPSFLAG) & ~ipsflag_irq_mask[irq]); + ssb_write32(mdev, SSB_IPSFLAG, irqflag); +} + +static void ssb_mips_serial_init(struct ssb_mipscore *mcore) +{ + struct ssb_bus *bus = mcore->dev->bus; + + if (bus->extif.dev) + mcore->nr_serial_ports = ssb_extif_serial_init(&bus->extif, mcore->serial_ports); + else if (bus->chipco.dev) + mcore->nr_serial_ports = ssb_chipco_serial_init(&bus->chipco, mcore->serial_ports); + else + mcore->nr_serial_ports = 0; +} + +static void ssb_mips_flash_detect(struct ssb_mipscore *mcore) +{ + struct ssb_bus *bus = mcore->dev->bus; + + mcore->flash_buswidth = 2; + if (bus->chipco.dev) { + mcore->flash_window = 0x1c000000; + mcore->flash_window_size = 0x02000000; + if ((ssb_read32(bus->chipco.dev, SSB_CHIPCO_FLASH_CFG) + & SSB_CHIPCO_CFG_DS16) == 0) + mcore->flash_buswidth = 1; + } else { + mcore->flash_window = 0x1fc00000; + mcore->flash_window_size = 0x00400000; + } +} + +u32 ssb_cpu_clock(struct ssb_mipscore *mcore) +{ + struct ssb_bus *bus = mcore->dev->bus; + u32 pll_type, n, m, rate = 0; + + if (bus->extif.dev) { + ssb_extif_get_clockcontrol(&bus->extif, &pll_type, &n, &m); + } else if (bus->chipco.dev) { + ssb_chipco_get_clockcpu(&bus->chipco, &pll_type, &n, &m); + } else + return 0; + + if ((pll_type == SSB_PLLTYPE_5) || (bus->chip_id == 0x5365)) { + rate = 200000000; + } else { + rate = ssb_calc_clock_rate(pll_type, n, m); + } + + if (pll_type == SSB_PLLTYPE_6) { + rate *= 2; + } + + return rate; +} + +void ssb_mipscore_init(struct ssb_mipscore *mcore) +{ + struct ssb_bus *bus = mcore->dev->bus; + struct ssb_device *dev; + unsigned long hz, ns; + unsigned int irq, i; + + if (!mcore->dev) + return; /* We don't have a MIPS core */ + + ssb_dprintk(KERN_INFO PFX "Initializing MIPS core...\n"); + + hz = ssb_clockspeed(bus); + if (!hz) + hz = 100000000; + ns = 1000000000 / hz; + + if (bus->extif.dev) + ssb_extif_timing_init(&bus->extif, ns); + else if (bus->chipco.dev) + ssb_chipco_timing_init(&bus->chipco, ns); + + /* Assign IRQs to all cores on the bus, start with irq line 2, because serial usually takes 1 */ + for (irq = 2, i = 0; i < bus->nr_devices; i++) { + dev = &(bus->devices[i]); + dev->irq = ssb_mips_irq(dev) + 2; + switch (dev->id.coreid) { + case SSB_DEV_USB11_HOST: + /* shouldn't need a separate irq line for non-4710, most of them have a proper + * external usb controller on the pci */ + if ((bus->chip_id == 0x4710) && (irq <= 4)) { + set_irq(dev, irq++); + break; + } + /* fallthrough */ + case SSB_DEV_PCI: + case SSB_DEV_ETHERNET: + case SSB_DEV_80211: + case SSB_DEV_USB20_HOST: + /* These devices get their own IRQ line if available, the rest goes on IRQ0 */ + if (irq <= 4) { + set_irq(dev, irq++); + break; + } + } + } + + ssb_mips_serial_init(mcore); + ssb_mips_flash_detect(mcore); +} diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c new file mode 100644 index 00000000000..2faaa906d5d --- /dev/null +++ b/drivers/ssb/driver_pcicore.c @@ -0,0 +1,576 @@ +/* + * Sonics Silicon Backplane + * Broadcom PCI-core driver + * + * Copyright 2005, Broadcom Corporation + * Copyright 2006, 2007, Michael Buesch + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include +#include +#include + +#include "ssb_private.h" + + +static inline +u32 pcicore_read32(struct ssb_pcicore *pc, u16 offset) +{ + return ssb_read32(pc->dev, offset); +} + +static inline +void pcicore_write32(struct ssb_pcicore *pc, u16 offset, u32 value) +{ + ssb_write32(pc->dev, offset, value); +} + +/************************************************** + * Code for hostmode operation. + **************************************************/ + +#ifdef CONFIG_SSB_PCICORE_HOSTMODE + +#include +/* Probe a 32bit value on the bus and catch bus exceptions. + * Returns nonzero on a bus exception. + * This is MIPS specific */ +#define mips_busprobe32(val, addr) get_dbe((val), ((u32 *)(addr))) + +/* Assume one-hot slot wiring */ +#define SSB_PCI_SLOT_MAX 16 + +/* Global lock is OK, as we won't have more than one extpci anyway. */ +static DEFINE_SPINLOCK(cfgspace_lock); +/* Core to access the external PCI config space. Can only have one. */ +static struct ssb_pcicore *extpci_core; + +static u32 ssb_pcicore_pcibus_iobase = 0x100; +static u32 ssb_pcicore_pcibus_membase = SSB_PCI_DMA; + +int pcibios_plat_dev_init(struct pci_dev *d) +{ + struct resource *res; + int pos, size; + u32 *base; + + ssb_printk(KERN_INFO "PCI: Fixing up device %s\n", + pci_name(d)); + + /* Fix up resource bases */ + for (pos = 0; pos < 6; pos++) { + res = &d->resource[pos]; + if (res->flags & IORESOURCE_IO) + base = &ssb_pcicore_pcibus_iobase; + else + base = &ssb_pcicore_pcibus_membase; + if (res->end) { + size = res->end - res->start + 1; + if (*base & (size - 1)) + *base = (*base + size) & ~(size - 1); + res->start = *base; + res->end = res->start + size - 1; + *base += size; + pci_write_config_dword(d, PCI_BASE_ADDRESS_0 + (pos << 2), res->start); + } + /* Fix up PCI bridge BAR0 only */ + if (d->bus->number == 0 && PCI_SLOT(d->devfn) == 0) + break; + } + /* Fix up interrupt lines */ + d->irq = ssb_mips_irq(extpci_core->dev) + 2; + pci_write_config_byte(d, PCI_INTERRUPT_LINE, d->irq); + + return 0; +} + +static void __init ssb_fixup_pcibridge(struct pci_dev *dev) +{ + if (dev->bus->number != 0 || PCI_SLOT(dev->devfn) != 0) + return; + + ssb_printk(KERN_INFO "PCI: fixing up bridge\n"); + + /* Enable PCI bridge bus mastering and memory space */ + pci_set_master(dev); + pcibios_enable_device(dev, ~0); + + /* Enable PCI bridge BAR1 prefetch and burst */ + pci_write_config_dword(dev, SSB_BAR1_CONTROL, 3); + + /* Make sure our latency is high enough to handle the devices behind us */ + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xa8); +} +DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ssb_fixup_pcibridge); + +int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +{ + return ssb_mips_irq(extpci_core->dev) + 2; +} + +static u32 get_cfgspace_addr(struct ssb_pcicore *pc, + unsigned int bus, unsigned int dev, + unsigned int func, unsigned int off) +{ + u32 addr = 0; + u32 tmp; + + if (unlikely(pc->cardbusmode && dev > 1)) + goto out; + if (bus == 0) { + /* Type 0 transaction */ + if (unlikely(dev >= SSB_PCI_SLOT_MAX)) + goto out; + /* Slide the window */ + tmp = SSB_PCICORE_SBTOPCI_CFG0; + tmp |= ((1 << (dev + 16)) & SSB_PCICORE_SBTOPCI1_MASK); + pcicore_write32(pc, SSB_PCICORE_SBTOPCI1, tmp); + /* Calculate the address */ + addr = SSB_PCI_CFG; + addr |= ((1 << (dev + 16)) & ~SSB_PCICORE_SBTOPCI1_MASK); + addr |= (func << 8); + addr |= (off & ~3); + } else { + /* Type 1 transaction */ + pcicore_write32(pc, SSB_PCICORE_SBTOPCI1, + SSB_PCICORE_SBTOPCI_CFG1); + /* Calculate the address */ + addr = SSB_PCI_CFG; + addr |= (bus << 16); + addr |= (dev << 11); + addr |= (func << 8); + addr |= (off & ~3); + } +out: + return addr; +} + +static int ssb_extpci_read_config(struct ssb_pcicore *pc, + unsigned int bus, unsigned int dev, + unsigned int func, unsigned int off, + void *buf, int len) +{ + int err = -EINVAL; + u32 addr, val; + void __iomem *mmio; + + SSB_WARN_ON(!pc->hostmode); + if (unlikely(len != 1 && len != 2 && len != 4)) + goto out; + addr = get_cfgspace_addr(pc, bus, dev, func, off); + if (unlikely(!addr)) + goto out; + err = -ENOMEM; + mmio = ioremap_nocache(addr, len); + if (!mmio) + goto out; + + if (mips_busprobe32(val, mmio)) { + val = 0xffffffff; + goto unmap; + } + + val = readl(mmio); + val >>= (8 * (off & 3)); + + switch (len) { + case 1: + *((u8 *)buf) = (u8)val; + break; + case 2: + *((u16 *)buf) = (u16)val; + break; + case 4: + *((u32 *)buf) = (u32)val; + break; + } + err = 0; +unmap: + iounmap(mmio); +out: + return err; +} + +static int ssb_extpci_write_config(struct ssb_pcicore *pc, + unsigned int bus, unsigned int dev, + unsigned int func, unsigned int off, + const void *buf, int len) +{ + int err = -EINVAL; + u32 addr, val = 0; + void __iomem *mmio; + + SSB_WARN_ON(!pc->hostmode); + if (unlikely(len != 1 && len != 2 && len != 4)) + goto out; + addr = get_cfgspace_addr(pc, bus, dev, func, off); + if (unlikely(!addr)) + goto out; + err = -ENOMEM; + mmio = ioremap_nocache(addr, len); + if (!mmio) + goto out; + + if (mips_busprobe32(val, mmio)) { + val = 0xffffffff; + goto unmap; + } + + switch (len) { + case 1: + val = readl(mmio); + val &= ~(0xFF << (8 * (off & 3))); + val |= *((const u8 *)buf) << (8 * (off & 3)); + break; + case 2: + val = readl(mmio); + val &= ~(0xFFFF << (8 * (off & 3))); + val |= *((const u16 *)buf) << (8 * (off & 3)); + break; + case 4: + val = *((const u32 *)buf); + break; + } + writel(val, mmio); + + err = 0; +unmap: + iounmap(mmio); +out: + return err; +} + +static int ssb_pcicore_read_config(struct pci_bus *bus, unsigned int devfn, + int reg, int size, u32 *val) +{ + unsigned long flags; + int err; + + spin_lock_irqsave(&cfgspace_lock, flags); + err = ssb_extpci_read_config(extpci_core, bus->number, PCI_SLOT(devfn), + PCI_FUNC(devfn), reg, val, size); + spin_unlock_irqrestore(&cfgspace_lock, flags); + + return err ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL; +} + +static int ssb_pcicore_write_config(struct pci_bus *bus, unsigned int devfn, + int reg, int size, u32 val) +{ + unsigned long flags; + int err; + + spin_lock_irqsave(&cfgspace_lock, flags); + err = ssb_extpci_write_config(extpci_core, bus->number, PCI_SLOT(devfn), + PCI_FUNC(devfn), reg, &val, size); + spin_unlock_irqrestore(&cfgspace_lock, flags); + + return err ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops ssb_pcicore_pciops = { + .read = ssb_pcicore_read_config, + .write = ssb_pcicore_write_config, +}; + +static struct resource ssb_pcicore_mem_resource = { + .name = "SSB PCIcore external memory", + .start = SSB_PCI_DMA, + .end = SSB_PCI_DMA + SSB_PCI_DMA_SZ - 1, + .flags = IORESOURCE_MEM, +}; + +static struct resource ssb_pcicore_io_resource = { + .name = "SSB PCIcore external I/O", + .start = 0x100, + .end = 0x7FF, + .flags = IORESOURCE_IO, +}; + +static struct pci_controller ssb_pcicore_controller = { + .pci_ops = &ssb_pcicore_pciops, + .io_resource = &ssb_pcicore_io_resource, + .mem_resource = &ssb_pcicore_mem_resource, + .mem_offset = 0x24000000, +}; + +static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc) +{ + u32 val; + + if (WARN_ON(extpci_core)) + return; + extpci_core = pc; + + ssb_dprintk(KERN_INFO PFX "PCIcore in host mode found\n"); + /* Reset devices on the external PCI bus */ + val = SSB_PCICORE_CTL_RST_OE; + val |= SSB_PCICORE_CTL_CLK_OE; + pcicore_write32(pc, SSB_PCICORE_CTL, val); + val |= SSB_PCICORE_CTL_CLK; /* Clock on */ + pcicore_write32(pc, SSB_PCICORE_CTL, val); + udelay(150); /* Assertion time demanded by the PCI standard */ + val |= SSB_PCICORE_CTL_RST; /* Deassert RST# */ + pcicore_write32(pc, SSB_PCICORE_CTL, val); + val = SSB_PCICORE_ARBCTL_INTERN; + pcicore_write32(pc, SSB_PCICORE_ARBCTL, val); + udelay(1); /* Assertion time demanded by the PCI standard */ + + /*TODO cardbus mode */ + + /* 64MB I/O window */ + pcicore_write32(pc, SSB_PCICORE_SBTOPCI0, + SSB_PCICORE_SBTOPCI_IO); + /* 64MB config space */ + pcicore_write32(pc, SSB_PCICORE_SBTOPCI1, + SSB_PCICORE_SBTOPCI_CFG0); + /* 1GB memory window */ + pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, + SSB_PCICORE_SBTOPCI_MEM | SSB_PCI_DMA); + + /* Enable PCI bridge BAR0 prefetch and burst */ + val = PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; + ssb_extpci_write_config(pc, 0, 0, 0, PCI_COMMAND, &val, 2); + /* Clear error conditions */ + val = 0; + ssb_extpci_write_config(pc, 0, 0, 0, PCI_STATUS, &val, 2); + + /* Enable PCI interrupts */ + pcicore_write32(pc, SSB_PCICORE_IMASK, + SSB_PCICORE_IMASK_INTA); + + /* Ok, ready to run, register it to the system. + * The following needs change, if we want to port hostmode + * to non-MIPS platform. */ + set_io_port_base((unsigned long)ioremap_nocache(SSB_PCI_MEM, 0x04000000)); + /* Give some time to the PCI controller to configure itself with the new + * values. Not waiting at this point causes crashes of the machine. */ + mdelay(10); + register_pci_controller(&ssb_pcicore_controller); +} + +static int pcicore_is_in_hostmode(struct ssb_pcicore *pc) +{ + struct ssb_bus *bus = pc->dev->bus; + u16 chipid_top; + u32 tmp; + + chipid_top = (bus->chip_id & 0xFF00); + if (chipid_top != 0x4700 && + chipid_top != 0x5300) + return 0; + + if (bus->sprom.r1.boardflags_lo & SSB_PCICORE_BFL_NOPCI) + return 0; + + /* The 200-pin BCM4712 package does not bond out PCI. Even when + * PCI is bonded out, some boards may leave the pins floating. */ + if (bus->chip_id == 0x4712) { + if (bus->chip_package == SSB_CHIPPACK_BCM4712S) + return 0; + if (bus->chip_package == SSB_CHIPPACK_BCM4712M) + return 0; + } + if (bus->chip_id == 0x5350) + return 0; + + return !mips_busprobe32(tmp, (bus->mmio + (pc->dev->core_index * SSB_CORE_SIZE))); +} +#endif /* CONFIG_SSB_PCICORE_HOSTMODE */ + + +/************************************************** + * Generic and Clientmode operation code. + **************************************************/ + +static void ssb_pcicore_init_clientmode(struct ssb_pcicore *pc) +{ + /* Disable PCI interrupts. */ + ssb_write32(pc->dev, SSB_INTVEC, 0); +} + +void ssb_pcicore_init(struct ssb_pcicore *pc) +{ + struct ssb_device *dev = pc->dev; + struct ssb_bus *bus; + + if (!dev) + return; + bus = dev->bus; + if (!ssb_device_is_enabled(dev)) + ssb_device_enable(dev, 0); + +#ifdef CONFIG_SSB_PCICORE_HOSTMODE + pc->hostmode = pcicore_is_in_hostmode(pc); + if (pc->hostmode) + ssb_pcicore_init_hostmode(pc); +#endif /* CONFIG_SSB_PCICORE_HOSTMODE */ + if (!pc->hostmode) + ssb_pcicore_init_clientmode(pc); +} + +static u32 ssb_pcie_read(struct ssb_pcicore *pc, u32 address) +{ + pcicore_write32(pc, 0x130, address); + return pcicore_read32(pc, 0x134); +} + +static void ssb_pcie_write(struct ssb_pcicore *pc, u32 address, u32 data) +{ + pcicore_write32(pc, 0x130, address); + pcicore_write32(pc, 0x134, data); +} + +static void ssb_pcie_mdio_write(struct ssb_pcicore *pc, u8 device, + u8 address, u16 data) +{ + const u16 mdio_control = 0x128; + const u16 mdio_data = 0x12C; + u32 v; + int i; + + v = 0x80; /* Enable Preamble Sequence */ + v |= 0x2; /* MDIO Clock Divisor */ + pcicore_write32(pc, mdio_control, v); + + v = (1 << 30); /* Start of Transaction */ + v |= (1 << 28); /* Write Transaction */ + v |= (1 << 17); /* Turnaround */ + v |= (u32)device << 22; + v |= (u32)address << 18; + v |= data; + pcicore_write32(pc, mdio_data, v); + /* Wait for the device to complete the transaction */ + udelay(10); + for (i = 0; i < 10; i++) { + v = pcicore_read32(pc, mdio_control); + if (v & 0x100 /* Trans complete */) + break; + msleep(1); + } + pcicore_write32(pc, mdio_control, 0); +} + +static void ssb_broadcast_value(struct ssb_device *dev, + u32 address, u32 data) +{ + /* This is used for both, PCI and ChipCommon core, so be careful. */ + BUILD_BUG_ON(SSB_PCICORE_BCAST_ADDR != SSB_CHIPCO_BCAST_ADDR); + BUILD_BUG_ON(SSB_PCICORE_BCAST_DATA != SSB_CHIPCO_BCAST_DATA); + + ssb_write32(dev, SSB_PCICORE_BCAST_ADDR, address); + ssb_read32(dev, SSB_PCICORE_BCAST_ADDR); /* flush */ + ssb_write32(dev, SSB_PCICORE_BCAST_DATA, data); + ssb_read32(dev, SSB_PCICORE_BCAST_DATA); /* flush */ +} + +static void ssb_commit_settings(struct ssb_bus *bus) +{ + struct ssb_device *dev; + + dev = bus->chipco.dev ? bus->chipco.dev : bus->pcicore.dev; + if (WARN_ON(!dev)) + return; + /* This forces an update of the cached registers. */ + ssb_broadcast_value(dev, 0xFD8, 0); +} + +int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc, + struct ssb_device *dev) +{ + struct ssb_device *pdev = pc->dev; + struct ssb_bus *bus; + int err = 0; + u32 tmp; + + might_sleep(); + + if (!pdev) + goto out; + bus = pdev->bus; + + /* Enable interrupts for this device. */ + if (bus->host_pci && + ((pdev->id.revision >= 6) || (pdev->id.coreid == SSB_DEV_PCIE))) { + u32 coremask; + + /* Calculate the "coremask" for the device. */ + coremask = (1 << dev->core_index); + + err = pci_read_config_dword(bus->host_pci, SSB_PCI_IRQMASK, &tmp); + if (err) + goto out; + tmp |= coremask << 8; + err = pci_write_config_dword(bus->host_pci, SSB_PCI_IRQMASK, tmp); + if (err) + goto out; + } else { + u32 intvec; + + intvec = ssb_read32(pdev, SSB_INTVEC); + if ((bus->chip_id & 0xFF00) == 0x4400) { + /* Workaround: On the BCM44XX the BPFLAG routing + * bit is wrong. Use a hardcoded constant. */ + intvec |= 0x00000002; + } else { + tmp = ssb_read32(dev, SSB_TPSFLAG); + tmp &= SSB_TPSFLAG_BPFLAG; + intvec |= tmp; + } + ssb_write32(pdev, SSB_INTVEC, intvec); + } + + /* Setup PCIcore operation. */ + if (pc->setup_done) + goto out; + if (pdev->id.coreid == SSB_DEV_PCI) { + tmp = pcicore_read32(pc, SSB_PCICORE_SBTOPCI2); + tmp |= SSB_PCICORE_SBTOPCI_PREF; + tmp |= SSB_PCICORE_SBTOPCI_BURST; + pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp); + + if (pdev->id.revision < 5) { + tmp = ssb_read32(pdev, SSB_IMCFGLO); + tmp &= ~SSB_IMCFGLO_SERTO; + tmp |= 2; + tmp &= ~SSB_IMCFGLO_REQTO; + tmp |= 3 << SSB_IMCFGLO_REQTO_SHIFT; + ssb_write32(pdev, SSB_IMCFGLO, tmp); + ssb_commit_settings(bus); + } else if (pdev->id.revision >= 11) { + tmp = pcicore_read32(pc, SSB_PCICORE_SBTOPCI2); + tmp |= SSB_PCICORE_SBTOPCI_MRM; + pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp); + } + } else { + WARN_ON(pdev->id.coreid != SSB_DEV_PCIE); + //TODO: Better make defines for all these magic PCIE values. + if ((pdev->id.revision == 0) || (pdev->id.revision == 1)) { + /* TLP Workaround register. */ + tmp = ssb_pcie_read(pc, 0x4); + tmp |= 0x8; + ssb_pcie_write(pc, 0x4, tmp); + } + if (pdev->id.revision == 0) { + const u8 serdes_rx_device = 0x1F; + + ssb_pcie_mdio_write(pc, serdes_rx_device, + 2 /* Timer */, 0x8128); + ssb_pcie_mdio_write(pc, serdes_rx_device, + 6 /* CDR */, 0x0100); + ssb_pcie_mdio_write(pc, serdes_rx_device, + 7 /* CDR BW */, 0x1466); + } else if (pdev->id.revision == 1) { + /* DLLP Link Control register. */ + tmp = ssb_pcie_read(pc, 0x100); + tmp |= 0x40; + ssb_pcie_write(pc, 0x100, tmp); + } + } + pc->setup_done = 1; +out: + return err; +} +EXPORT_SYMBOL(ssb_pcicore_dev_irqvecs_enable); diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c new file mode 100644 index 00000000000..74d5182db4b --- /dev/null +++ b/drivers/ssb/main.c @@ -0,0 +1,1162 @@ +/* + * Sonics Silicon Backplane + * Subsystem core + * + * Copyright 2005, Broadcom Corporation + * Copyright 2006, 2007, Michael Buesch + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include "ssb_private.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +MODULE_DESCRIPTION("Sonics Silicon Backplane driver"); +MODULE_LICENSE("GPL"); + + +/* Temporary list of yet-to-be-attached buses */ +static LIST_HEAD(attach_queue); +/* List if running buses */ +static LIST_HEAD(buses); +/* Software ID counter */ +static unsigned int next_busnumber; +/* buses_mutes locks the two buslists and the next_busnumber. + * Don't lock this directly, but use ssb_buses_[un]lock() below. */ +static DEFINE_MUTEX(buses_mutex); + +/* There are differences in the codeflow, if the bus is + * initialized from early boot, as various needed services + * are not available early. This is a mechanism to delay + * these initializations to after early boot has finished. + * It's also used to avoid mutex locking, as that's not + * available and needed early. */ +static bool ssb_is_early_boot = 1; + +static void ssb_buses_lock(void); +static void ssb_buses_unlock(void); + + +#ifdef CONFIG_SSB_PCIHOST +struct ssb_bus *ssb_pci_dev_to_bus(struct pci_dev *pdev) +{ + struct ssb_bus *bus; + + ssb_buses_lock(); + list_for_each_entry(bus, &buses, list) { + if (bus->bustype == SSB_BUSTYPE_PCI && + bus->host_pci == pdev) + goto found; + } + bus = NULL; +found: + ssb_buses_unlock(); + + return bus; +} +#endif /* CONFIG_SSB_PCIHOST */ + +static struct ssb_device *ssb_device_get(struct ssb_device *dev) +{ + if (dev) + get_device(dev->dev); + return dev; +} + +static void ssb_device_put(struct ssb_device *dev) +{ + if (dev) + put_device(dev->dev); +} + +static int ssb_bus_resume(struct ssb_bus *bus) +{ + int err; + + ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1); + err = ssb_pcmcia_init(bus); + if (err) { + /* No need to disable XTAL, as we don't have one on PCMCIA. */ + return err; + } + ssb_chipco_resume(&bus->chipco); + + return 0; +} + +static int ssb_device_resume(struct device *dev) +{ + struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); + struct ssb_driver *ssb_drv; + struct ssb_bus *bus; + int err = 0; + + bus = ssb_dev->bus; + if (bus->suspend_cnt == bus->nr_devices) { + err = ssb_bus_resume(bus); + if (err) + return err; + } + bus->suspend_cnt--; + if (dev->driver) { + ssb_drv = drv_to_ssb_drv(dev->driver); + if (ssb_drv && ssb_drv->resume) + err = ssb_drv->resume(ssb_dev); + if (err) + goto out; + } +out: + return err; +} + +static void ssb_bus_suspend(struct ssb_bus *bus, pm_message_t state) +{ + ssb_chipco_suspend(&bus->chipco, state); + ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0); + + /* Reset HW state information in memory, so that HW is + * completely reinitialized on resume. */ + bus->mapped_device = NULL; +#ifdef CONFIG_SSB_DRIVER_PCICORE + bus->pcicore.setup_done = 0; +#endif +#ifdef CONFIG_SSB_DEBUG + bus->powered_up = 0; +#endif +} + +static int ssb_device_suspend(struct device *dev, pm_message_t state) +{ + struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); + struct ssb_driver *ssb_drv; + struct ssb_bus *bus; + int err = 0; + + if (dev->driver) { + ssb_drv = drv_to_ssb_drv(dev->driver); + if (ssb_drv && ssb_drv->suspend) + err = ssb_drv->suspend(ssb_dev, state); + if (err) + goto out; + } + + bus = ssb_dev->bus; + bus->suspend_cnt++; + if (bus->suspend_cnt == bus->nr_devices) { + /* All devices suspended. Shutdown the bus. */ + ssb_bus_suspend(bus, state); + } + +out: + return err; +} + +#ifdef CONFIG_SSB_PCIHOST +int ssb_devices_freeze(struct ssb_bus *bus) +{ + struct ssb_device *dev; + struct ssb_driver *drv; + int err = 0; + int i; + pm_message_t state = PMSG_FREEZE; + + /* First check that we are capable to freeze all devices. */ + for (i = 0; i < bus->nr_devices; i++) { + dev = &(bus->devices[i]); + if (!dev->dev || + !dev->dev->driver || + !device_is_registered(dev->dev)) + continue; + drv = drv_to_ssb_drv(dev->dev->driver); + if (!drv) + continue; + if (!drv->suspend) { + /* Nope, can't suspend this one. */ + return -EOPNOTSUPP; + } + } + /* Now suspend all devices */ + for (i = 0; i < bus->nr_devices; i++) { + dev = &(bus->devices[i]); + if (!dev->dev || + !dev->dev->driver || + !device_is_registered(dev->dev)) + continue; + drv = drv_to_ssb_drv(dev->dev->driver); + if (!drv) + continue; + err = drv->suspend(dev, state); + if (err) { + ssb_printk(KERN_ERR PFX "Failed to freeze device %s\n", + dev->dev->bus_id); + goto err_unwind; + } + } + + return 0; +err_unwind: + for (i--; i >= 0; i--) { + dev = &(bus->devices[i]); + if (!dev->dev || + !dev->dev->driver || + !device_is_registered(dev->dev)) + continue; + drv = drv_to_ssb_drv(dev->dev->driver); + if (!drv) + continue; + if (drv->resume) + drv->resume(dev); + } + return err; +} + +int ssb_devices_thaw(struct ssb_bus *bus) +{ + struct ssb_device *dev; + struct ssb_driver *drv; + int err; + int i; + + for (i = 0; i < bus->nr_devices; i++) { + dev = &(bus->devices[i]); + if (!dev->dev || + !dev->dev->driver || + !device_is_registered(dev->dev)) + continue; + drv = drv_to_ssb_drv(dev->dev->driver); + if (!drv) + continue; + if (SSB_WARN_ON(!drv->resume)) + continue; + err = drv->resume(dev); + if (err) { + ssb_printk(KERN_ERR PFX "Failed to thaw device %s\n", + dev->dev->bus_id); + } + } + + return 0; +} +#endif /* CONFIG_SSB_PCIHOST */ + +static void ssb_device_shutdown(struct device *dev) +{ + struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); + struct ssb_driver *ssb_drv; + + if (!dev->driver) + return; + ssb_drv = drv_to_ssb_drv(dev->driver); + if (ssb_drv && ssb_drv->shutdown) + ssb_drv->shutdown(ssb_dev); +} + +static int ssb_device_remove(struct device *dev) +{ + struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); + struct ssb_driver *ssb_drv = drv_to_ssb_drv(dev->driver); + + if (ssb_drv && ssb_drv->remove) + ssb_drv->remove(ssb_dev); + ssb_device_put(ssb_dev); + + return 0; +} + +static int ssb_device_probe(struct device *dev) +{ + struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); + struct ssb_driver *ssb_drv = drv_to_ssb_drv(dev->driver); + int err = 0; + + ssb_device_get(ssb_dev); + if (ssb_drv && ssb_drv->probe) + err = ssb_drv->probe(ssb_dev, &ssb_dev->id); + if (err) + ssb_device_put(ssb_dev); + + return err; +} + +static int ssb_match_devid(const struct ssb_device_id *tabid, + const struct ssb_device_id *devid) +{ + if ((tabid->vendor != devid->vendor) && + tabid->vendor != SSB_ANY_VENDOR) + return 0; + if ((tabid->coreid != devid->coreid) && + tabid->coreid != SSB_ANY_ID) + return 0; + if ((tabid->revision != devid->revision) && + tabid->revision != SSB_ANY_REV) + return 0; + return 1; +} + +static int ssb_bus_match(struct device *dev, struct device_driver *drv) +{ + struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); + struct ssb_driver *ssb_drv = drv_to_ssb_drv(drv); + const struct ssb_device_id *id; + + for (id = ssb_drv->id_table; + id->vendor || id->coreid || id->revision; + id++) { + if (ssb_match_devid(id, &ssb_dev->id)) + return 1; /* found */ + } + + return 0; +} + +static int ssb_device_uevent(struct device *dev, char **envp, int num_envp, + char *buffer, int buffer_size) +{ + struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); + int ret, i = 0, length = 0; + + if (!dev) + return -ENODEV; + + ret = add_uevent_var(envp, num_envp, &i, + buffer, buffer_size, &length, + "MODALIAS=ssb:v%04Xid%04Xrev%02X", + ssb_dev->id.vendor, ssb_dev->id.coreid, + ssb_dev->id.revision); + envp[i] = NULL; + + return ret; +} + +static struct bus_type ssb_bustype = { + .name = "ssb", + .match = ssb_bus_match, + .probe = ssb_device_probe, + .remove = ssb_device_remove, + .shutdown = ssb_device_shutdown, + .suspend = ssb_device_suspend, + .resume = ssb_device_resume, + .uevent = ssb_device_uevent, +}; + +static void ssb_buses_lock(void) +{ + /* See the comment at the ssb_is_early_boot definition */ + if (!ssb_is_early_boot) + mutex_lock(&buses_mutex); +} + +static void ssb_buses_unlock(void) +{ + /* See the comment at the ssb_is_early_boot definition */ + if (!ssb_is_early_boot) + mutex_unlock(&buses_mutex); +} + +static void ssb_devices_unregister(struct ssb_bus *bus) +{ + struct ssb_device *sdev; + int i; + + for (i = bus->nr_devices - 1; i >= 0; i--) { + sdev = &(bus->devices[i]); + if (sdev->dev) + device_unregister(sdev->dev); + } +} + +void ssb_bus_unregister(struct ssb_bus *bus) +{ + ssb_buses_lock(); + ssb_devices_unregister(bus); + list_del(&bus->list); + ssb_buses_unlock(); + + /* ssb_pcmcia_exit(bus); */ + ssb_pci_exit(bus); + ssb_iounmap(bus); +} +EXPORT_SYMBOL(ssb_bus_unregister); + +static void ssb_release_dev(struct device *dev) +{ + struct __ssb_dev_wrapper *devwrap; + + devwrap = container_of(dev, struct __ssb_dev_wrapper, dev); + kfree(devwrap); +} + +static int ssb_devices_register(struct ssb_bus *bus) +{ + struct ssb_device *sdev; + struct device *dev; + struct __ssb_dev_wrapper *devwrap; + int i, err = 0; + int dev_idx = 0; + + for (i = 0; i < bus->nr_devices; i++) { + sdev = &(bus->devices[i]); + + /* We don't register SSB-system devices to the kernel, + * as the drivers for them are built into SSB. */ + switch (sdev->id.coreid) { + case SSB_DEV_CHIPCOMMON: + case SSB_DEV_PCI: + case SSB_DEV_PCIE: + case SSB_DEV_PCMCIA: + case SSB_DEV_MIPS: + case SSB_DEV_MIPS_3302: + case SSB_DEV_EXTIF: + continue; + } + + devwrap = kzalloc(sizeof(*devwrap), GFP_KERNEL); + if (!devwrap) { + ssb_printk(KERN_ERR PFX + "Could not allocate device\n"); + err = -ENOMEM; + goto error; + } + dev = &devwrap->dev; + devwrap->sdev = sdev; + + dev->release = ssb_release_dev; + dev->bus = &ssb_bustype; + snprintf(dev->bus_id, sizeof(dev->bus_id), + "ssb%u:%d", bus->busnumber, dev_idx); + + switch (bus->bustype) { + case SSB_BUSTYPE_PCI: +#ifdef CONFIG_SSB_PCIHOST + sdev->irq = bus->host_pci->irq; + dev->parent = &bus->host_pci->dev; +#endif + break; + case SSB_BUSTYPE_PCMCIA: +#ifdef CONFIG_SSB_PCMCIAHOST + dev->parent = &bus->host_pcmcia->dev; +#endif + break; + case SSB_BUSTYPE_SSB: + break; + } + + sdev->dev = dev; + err = device_register(dev); + if (err) { + ssb_printk(KERN_ERR PFX + "Could not register %s\n", + dev->bus_id); + /* Set dev to NULL to not unregister + * dev on error unwinding. */ + sdev->dev = NULL; + kfree(devwrap); + goto error; + } + dev_idx++; + } + + return 0; +error: + /* Unwind the already registered devices. */ + ssb_devices_unregister(bus); + return err; +} + +/* Needs ssb_buses_lock() */ +static int ssb_attach_queued_buses(void) +{ + struct ssb_bus *bus, *n; + int err = 0; + int drop_them_all = 0; + + list_for_each_entry_safe(bus, n, &attach_queue, list) { + if (drop_them_all) { + list_del(&bus->list); + continue; + } + /* Can't init the PCIcore in ssb_bus_register(), as that + * is too early in boot for embedded systems + * (no udelay() available). So do it here in attach stage. + */ + err = ssb_bus_powerup(bus, 0); + if (err) + goto error; + ssb_pcicore_init(&bus->pcicore); + ssb_bus_may_powerdown(bus); + + err = ssb_devices_register(bus); +error: + if (err) { + drop_them_all = 1; + list_del(&bus->list); + continue; + } + list_move_tail(&bus->list, &buses); + } + + return err; +} + +static u16 ssb_ssb_read16(struct ssb_device *dev, u16 offset) +{ + struct ssb_bus *bus = dev->bus; + + offset += dev->core_index * SSB_CORE_SIZE; + return readw(bus->mmio + offset); +} + +static u32 ssb_ssb_read32(struct ssb_device *dev, u16 offset) +{ + struct ssb_bus *bus = dev->bus; + + offset += dev->core_index * SSB_CORE_SIZE; + return readl(bus->mmio + offset); +} + +static void ssb_ssb_write16(struct ssb_device *dev, u16 offset, u16 value) +{ + struct ssb_bus *bus = dev->bus; + + offset += dev->core_index * SSB_CORE_SIZE; + writew(value, bus->mmio + offset); +} + +static void ssb_ssb_write32(struct ssb_device *dev, u16 offset, u32 value) +{ + struct ssb_bus *bus = dev->bus; + + offset += dev->core_index * SSB_CORE_SIZE; + writel(value, bus->mmio + offset); +} + +/* Ops for the plain SSB bus without a host-device (no PCI or PCMCIA). */ +static const struct ssb_bus_ops ssb_ssb_ops = { + .read16 = ssb_ssb_read16, + .read32 = ssb_ssb_read32, + .write16 = ssb_ssb_write16, + .write32 = ssb_ssb_write32, +}; + +static int ssb_fetch_invariants(struct ssb_bus *bus, + ssb_invariants_func_t get_invariants) +{ + struct ssb_init_invariants iv; + int err; + + memset(&iv, 0, sizeof(iv)); + err = get_invariants(bus, &iv); + if (err) + goto out; + memcpy(&bus->boardinfo, &iv.boardinfo, sizeof(iv.boardinfo)); + memcpy(&bus->sprom, &iv.sprom, sizeof(iv.sprom)); +out: + return err; +} + +static int ssb_bus_register(struct ssb_bus *bus, + ssb_invariants_func_t get_invariants, + unsigned long baseaddr) +{ + int err; + + spin_lock_init(&bus->bar_lock); + INIT_LIST_HEAD(&bus->list); + + /* Powerup the bus */ + err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1); + if (err) + goto out; + ssb_buses_lock(); + bus->busnumber = next_busnumber; + /* Scan for devices (cores) */ + err = ssb_bus_scan(bus, baseaddr); + if (err) + goto err_disable_xtal; + + /* Init PCI-host device (if any) */ + err = ssb_pci_init(bus); + if (err) + goto err_unmap; + /* Init PCMCIA-host device (if any) */ + err = ssb_pcmcia_init(bus); + if (err) + goto err_pci_exit; + + /* Initialize basic system devices (if available) */ + err = ssb_bus_powerup(bus, 0); + if (err) + goto err_pcmcia_exit; + ssb_chipcommon_init(&bus->chipco); + ssb_mipscore_init(&bus->mipscore); + err = ssb_fetch_invariants(bus, get_invariants); + if (err) { + ssb_bus_may_powerdown(bus); + goto err_pcmcia_exit; + } + ssb_bus_may_powerdown(bus); + + /* Queue it for attach. + * See the comment at the ssb_is_early_boot definition. */ + list_add_tail(&bus->list, &attach_queue); + if (!ssb_is_early_boot) { + /* This is not early boot, so we must attach the bus now */ + err = ssb_attach_queued_buses(); + if (err) + goto err_dequeue; + } + next_busnumber++; + ssb_buses_unlock(); + +out: + return err; + +err_dequeue: + list_del(&bus->list); +err_pcmcia_exit: +/* ssb_pcmcia_exit(bus); */ +err_pci_exit: + ssb_pci_exit(bus); +err_unmap: + ssb_iounmap(bus); +err_disable_xtal: + ssb_buses_unlock(); + ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0); + return err; +} + +#ifdef CONFIG_SSB_PCIHOST +int ssb_bus_pcibus_register(struct ssb_bus *bus, + struct pci_dev *host_pci) +{ + int err; + + bus->bustype = SSB_BUSTYPE_PCI; + bus->host_pci = host_pci; + bus->ops = &ssb_pci_ops; + + err = ssb_bus_register(bus, ssb_pci_get_invariants, 0); + if (!err) { + ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found on " + "PCI device %s\n", host_pci->dev.bus_id); + } + + return err; +} +EXPORT_SYMBOL(ssb_bus_pcibus_register); +#endif /* CONFIG_SSB_PCIHOST */ + +#ifdef CONFIG_SSB_PCMCIAHOST +int ssb_bus_pcmciabus_register(struct ssb_bus *bus, + struct pcmcia_device *pcmcia_dev, + unsigned long baseaddr) +{ + int err; + + bus->bustype = SSB_BUSTYPE_PCMCIA; + bus->host_pcmcia = pcmcia_dev; + bus->ops = &ssb_pcmcia_ops; + + err = ssb_bus_register(bus, ssb_pcmcia_get_invariants, baseaddr); + if (!err) { + ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found on " + "PCMCIA device %s\n", pcmcia_dev->devname); + } + + return err; +} +EXPORT_SYMBOL(ssb_bus_pcmciabus_register); +#endif /* CONFIG_SSB_PCMCIAHOST */ + +int ssb_bus_ssbbus_register(struct ssb_bus *bus, + unsigned long baseaddr, + ssb_invariants_func_t get_invariants) +{ + int err; + + bus->bustype = SSB_BUSTYPE_SSB; + bus->ops = &ssb_ssb_ops; + + err = ssb_bus_register(bus, get_invariants, baseaddr); + if (!err) { + ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found at " + "address 0x%08lX\n", baseaddr); + } + + return err; +} + +int __ssb_driver_register(struct ssb_driver *drv, struct module *owner) +{ + drv->drv.name = drv->name; + drv->drv.bus = &ssb_bustype; + drv->drv.owner = owner; + + return driver_register(&drv->drv); +} +EXPORT_SYMBOL(__ssb_driver_register); + +void ssb_driver_unregister(struct ssb_driver *drv) +{ + driver_unregister(&drv->drv); +} +EXPORT_SYMBOL(ssb_driver_unregister); + +void ssb_set_devtypedata(struct ssb_device *dev, void *data) +{ + struct ssb_bus *bus = dev->bus; + struct ssb_device *ent; + int i; + + for (i = 0; i < bus->nr_devices; i++) { + ent = &(bus->devices[i]); + if (ent->id.vendor != dev->id.vendor) + continue; + if (ent->id.coreid != dev->id.coreid) + continue; + + ent->devtypedata = data; + } +} +EXPORT_SYMBOL(ssb_set_devtypedata); + +static u32 clkfactor_f6_resolve(u32 v) +{ + /* map the magic values */ + switch (v) { + case SSB_CHIPCO_CLK_F6_2: + return 2; + case SSB_CHIPCO_CLK_F6_3: + return 3; + case SSB_CHIPCO_CLK_F6_4: + return 4; + case SSB_CHIPCO_CLK_F6_5: + return 5; + case SSB_CHIPCO_CLK_F6_6: + return 6; + case SSB_CHIPCO_CLK_F6_7: + return 7; + } + return 0; +} + +/* Calculate the speed the backplane would run at a given set of clockcontrol values */ +u32 ssb_calc_clock_rate(u32 plltype, u32 n, u32 m) +{ + u32 n1, n2, clock, m1, m2, m3, mc; + + n1 = (n & SSB_CHIPCO_CLK_N1); + n2 = ((n & SSB_CHIPCO_CLK_N2) >> SSB_CHIPCO_CLK_N2_SHIFT); + + switch (plltype) { + case SSB_PLLTYPE_6: /* 100/200 or 120/240 only */ + if (m & SSB_CHIPCO_CLK_T6_MMASK) + return SSB_CHIPCO_CLK_T6_M0; + return SSB_CHIPCO_CLK_T6_M1; + case SSB_PLLTYPE_1: /* 48Mhz base, 3 dividers */ + case SSB_PLLTYPE_3: /* 25Mhz, 2 dividers */ + case SSB_PLLTYPE_4: /* 48Mhz, 4 dividers */ + case SSB_PLLTYPE_7: /* 25Mhz, 4 dividers */ + n1 = clkfactor_f6_resolve(n1); + n2 += SSB_CHIPCO_CLK_F5_BIAS; + break; + case SSB_PLLTYPE_2: /* 48Mhz, 4 dividers */ + n1 += SSB_CHIPCO_CLK_T2_BIAS; + n2 += SSB_CHIPCO_CLK_T2_BIAS; + SSB_WARN_ON(!((n1 >= 2) && (n1 <= 7))); + SSB_WARN_ON(!((n2 >= 5) && (n2 <= 23))); + break; + case SSB_PLLTYPE_5: /* 25Mhz, 4 dividers */ + return 100000000; + default: + SSB_WARN_ON(1); + } + + switch (plltype) { + case SSB_PLLTYPE_3: /* 25Mhz, 2 dividers */ + case SSB_PLLTYPE_7: /* 25Mhz, 4 dividers */ + clock = SSB_CHIPCO_CLK_BASE2 * n1 * n2; + break; + default: + clock = SSB_CHIPCO_CLK_BASE1 * n1 * n2; + } + if (!clock) + return 0; + + m1 = (m & SSB_CHIPCO_CLK_M1); + m2 = ((m & SSB_CHIPCO_CLK_M2) >> SSB_CHIPCO_CLK_M2_SHIFT); + m3 = ((m & SSB_CHIPCO_CLK_M3) >> SSB_CHIPCO_CLK_M3_SHIFT); + mc = ((m & SSB_CHIPCO_CLK_MC) >> SSB_CHIPCO_CLK_MC_SHIFT); + + switch (plltype) { + case SSB_PLLTYPE_1: /* 48Mhz base, 3 dividers */ + case SSB_PLLTYPE_3: /* 25Mhz, 2 dividers */ + case SSB_PLLTYPE_4: /* 48Mhz, 4 dividers */ + case SSB_PLLTYPE_7: /* 25Mhz, 4 dividers */ + m1 = clkfactor_f6_resolve(m1); + if ((plltype == SSB_PLLTYPE_1) || + (plltype == SSB_PLLTYPE_3)) + m2 += SSB_CHIPCO_CLK_F5_BIAS; + else + m2 = clkfactor_f6_resolve(m2); + m3 = clkfactor_f6_resolve(m3); + + switch (mc) { + case SSB_CHIPCO_CLK_MC_BYPASS: + return clock; + case SSB_CHIPCO_CLK_MC_M1: + return (clock / m1); + case SSB_CHIPCO_CLK_MC_M1M2: + return (clock / (m1 * m2)); + case SSB_CHIPCO_CLK_MC_M1M2M3: + return (clock / (m1 * m2 * m3)); + case SSB_CHIPCO_CLK_MC_M1M3: + return (clock / (m1 * m3)); + } + return 0; + case SSB_PLLTYPE_2: + m1 += SSB_CHIPCO_CLK_T2_BIAS; + m2 += SSB_CHIPCO_CLK_T2M2_BIAS; + m3 += SSB_CHIPCO_CLK_T2_BIAS; + SSB_WARN_ON(!((m1 >= 2) && (m1 <= 7))); + SSB_WARN_ON(!((m2 >= 3) && (m2 <= 10))); + SSB_WARN_ON(!((m3 >= 2) && (m3 <= 7))); + + if (!(mc & SSB_CHIPCO_CLK_T2MC_M1BYP)) + clock /= m1; + if (!(mc & SSB_CHIPCO_CLK_T2MC_M2BYP)) + clock /= m2; + if (!(mc & SSB_CHIPCO_CLK_T2MC_M3BYP)) + clock /= m3; + return clock; + default: + SSB_WARN_ON(1); + } + return 0; +} + +/* Get the current speed the backplane is running at */ +u32 ssb_clockspeed(struct ssb_bus *bus) +{ + u32 rate; + u32 plltype; + u32 clkctl_n, clkctl_m; + + if (ssb_extif_available(&bus->extif)) + ssb_extif_get_clockcontrol(&bus->extif, &plltype, + &clkctl_n, &clkctl_m); + else if (bus->chipco.dev) + ssb_chipco_get_clockcontrol(&bus->chipco, &plltype, + &clkctl_n, &clkctl_m); + else + return 0; + + if (bus->chip_id == 0x5365) { + rate = 100000000; + } else { + rate = ssb_calc_clock_rate(plltype, clkctl_n, clkctl_m); + if (plltype == SSB_PLLTYPE_3) /* 25Mhz, 2 dividers */ + rate /= 2; + } + + return rate; +} +EXPORT_SYMBOL(ssb_clockspeed); + +static u32 ssb_tmslow_reject_bitmask(struct ssb_device *dev) +{ + /* The REJECT bit changed position in TMSLOW between + * Backplane revisions. */ + switch (ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_SSBREV) { + case SSB_IDLOW_SSBREV_22: + return SSB_TMSLOW_REJECT_22; + case SSB_IDLOW_SSBREV_23: + return SSB_TMSLOW_REJECT_23; + default: + WARN_ON(1); + } + return (SSB_TMSLOW_REJECT_22 | SSB_TMSLOW_REJECT_23); +} + +int ssb_device_is_enabled(struct ssb_device *dev) +{ + u32 val; + u32 reject; + + reject = ssb_tmslow_reject_bitmask(dev); + val = ssb_read32(dev, SSB_TMSLOW); + val &= SSB_TMSLOW_CLOCK | SSB_TMSLOW_RESET | reject; + + return (val == SSB_TMSLOW_CLOCK); +} +EXPORT_SYMBOL(ssb_device_is_enabled); + +static void ssb_flush_tmslow(struct ssb_device *dev) +{ + /* Make _really_ sure the device has finished the TMSLOW + * register write transaction, as we risk running into + * a machine check exception otherwise. + * Do this by reading the register back to commit the + * PCI write and delay an additional usec for the device + * to react to the change. */ + ssb_read32(dev, SSB_TMSLOW); + udelay(1); +} + +void ssb_device_enable(struct ssb_device *dev, u32 core_specific_flags) +{ + u32 val; + + ssb_device_disable(dev, core_specific_flags); + ssb_write32(dev, SSB_TMSLOW, + SSB_TMSLOW_RESET | SSB_TMSLOW_CLOCK | + SSB_TMSLOW_FGC | core_specific_flags); + ssb_flush_tmslow(dev); + + /* Clear SERR if set. This is a hw bug workaround. */ + if (ssb_read32(dev, SSB_TMSHIGH) & SSB_TMSHIGH_SERR) + ssb_write32(dev, SSB_TMSHIGH, 0); + + val = ssb_read32(dev, SSB_IMSTATE); + if (val & (SSB_IMSTATE_IBE | SSB_IMSTATE_TO)) { + val &= ~(SSB_IMSTATE_IBE | SSB_IMSTATE_TO); + ssb_write32(dev, SSB_IMSTATE, val); + } + + ssb_write32(dev, SSB_TMSLOW, + SSB_TMSLOW_CLOCK | SSB_TMSLOW_FGC | + core_specific_flags); + ssb_flush_tmslow(dev); + + ssb_write32(dev, SSB_TMSLOW, SSB_TMSLOW_CLOCK | + core_specific_flags); + ssb_flush_tmslow(dev); +} +EXPORT_SYMBOL(ssb_device_enable); + +/* Wait for a bit in a register to get set or unset. + * timeout is in units of ten-microseconds */ +static int ssb_wait_bit(struct ssb_device *dev, u16 reg, u32 bitmask, + int timeout, int set) +{ + int i; + u32 val; + + for (i = 0; i < timeout; i++) { + val = ssb_read32(dev, reg); + if (set) { + if (val & bitmask) + return 0; + } else { + if (!(val & bitmask)) + return 0; + } + udelay(10); + } + printk(KERN_ERR PFX "Timeout waiting for bitmask %08X on " + "register %04X to %s.\n", + bitmask, reg, (set ? "set" : "clear")); + + return -ETIMEDOUT; +} + +void ssb_device_disable(struct ssb_device *dev, u32 core_specific_flags) +{ + u32 reject; + + if (ssb_read32(dev, SSB_TMSLOW) & SSB_TMSLOW_RESET) + return; + + reject = ssb_tmslow_reject_bitmask(dev); + ssb_write32(dev, SSB_TMSLOW, reject | SSB_TMSLOW_CLOCK); + ssb_wait_bit(dev, SSB_TMSLOW, reject, 1000, 1); + ssb_wait_bit(dev, SSB_TMSHIGH, SSB_TMSHIGH_BUSY, 1000, 0); + ssb_write32(dev, SSB_TMSLOW, + SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | + reject | SSB_TMSLOW_RESET | + core_specific_flags); + ssb_flush_tmslow(dev); + + ssb_write32(dev, SSB_TMSLOW, + reject | SSB_TMSLOW_RESET | + core_specific_flags); + ssb_flush_tmslow(dev); +} +EXPORT_SYMBOL(ssb_device_disable); + +u32 ssb_dma_translation(struct ssb_device *dev) +{ + switch (dev->bus->bustype) { + case SSB_BUSTYPE_SSB: + return 0; + case SSB_BUSTYPE_PCI: + case SSB_BUSTYPE_PCMCIA: + return SSB_PCI_DMA; + } + return 0; +} +EXPORT_SYMBOL(ssb_dma_translation); + +int ssb_dma_set_mask(struct ssb_device *ssb_dev, u64 mask) +{ + struct device *dev = ssb_dev->dev; + +#ifdef CONFIG_SSB_PCIHOST + if (ssb_dev->bus->bustype == SSB_BUSTYPE_PCI && + !dma_supported(dev, mask)) + return -EIO; +#endif + dev->coherent_dma_mask = mask; + dev->dma_mask = &dev->coherent_dma_mask; + + return 0; +} +EXPORT_SYMBOL(ssb_dma_set_mask); + +int ssb_bus_may_powerdown(struct ssb_bus *bus) +{ + struct ssb_chipcommon *cc; + int err = 0; + + /* On buses where more than one core may be working + * at a time, we must not powerdown stuff if there are + * still cores that may want to run. */ + if (bus->bustype == SSB_BUSTYPE_SSB) + goto out; + + cc = &bus->chipco; + ssb_chipco_set_clockmode(cc, SSB_CLKMODE_SLOW); + err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0); + if (err) + goto error; +out: +#ifdef CONFIG_SSB_DEBUG + bus->powered_up = 0; +#endif + return err; +error: + ssb_printk(KERN_ERR PFX "Bus powerdown failed\n"); + goto out; +} +EXPORT_SYMBOL(ssb_bus_may_powerdown); + +int ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl) +{ + struct ssb_chipcommon *cc; + int err; + enum ssb_clkmode mode; + + err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1); + if (err) + goto error; + cc = &bus->chipco; + mode = dynamic_pctl ? SSB_CLKMODE_DYNAMIC : SSB_CLKMODE_FAST; + ssb_chipco_set_clockmode(cc, mode); + +#ifdef CONFIG_SSB_DEBUG + bus->powered_up = 1; +#endif + return 0; +error: + ssb_printk(KERN_ERR PFX "Bus powerup failed\n"); + return err; +} +EXPORT_SYMBOL(ssb_bus_powerup); + +u32 ssb_admatch_base(u32 adm) +{ + u32 base = 0; + + switch (adm & SSB_ADM_TYPE) { + case SSB_ADM_TYPE0: + base = (adm & SSB_ADM_BASE0); + break; + case SSB_ADM_TYPE1: + SSB_WARN_ON(adm & SSB_ADM_NEG); /* unsupported */ + base = (adm & SSB_ADM_BASE1); + break; + case SSB_ADM_TYPE2: + SSB_WARN_ON(adm & SSB_ADM_NEG); /* unsupported */ + base = (adm & SSB_ADM_BASE2); + break; + default: + SSB_WARN_ON(1); + } + + return base; +} +EXPORT_SYMBOL(ssb_admatch_base); + +u32 ssb_admatch_size(u32 adm) +{ + u32 size = 0; + + switch (adm & SSB_ADM_TYPE) { + case SSB_ADM_TYPE0: + size = ((adm & SSB_ADM_SZ0) >> SSB_ADM_SZ0_SHIFT); + break; + case SSB_ADM_TYPE1: + SSB_WARN_ON(adm & SSB_ADM_NEG); /* unsupported */ + size = ((adm & SSB_ADM_SZ1) >> SSB_ADM_SZ1_SHIFT); + break; + case SSB_ADM_TYPE2: + SSB_WARN_ON(adm & SSB_ADM_NEG); /* unsupported */ + size = ((adm & SSB_ADM_SZ2) >> SSB_ADM_SZ2_SHIFT); + break; + default: + SSB_WARN_ON(1); + } + size = (1 << (size + 1)); + + return size; +} +EXPORT_SYMBOL(ssb_admatch_size); + +static int __init ssb_modinit(void) +{ + int err; + + /* See the comment at the ssb_is_early_boot definition */ + ssb_is_early_boot = 0; + err = bus_register(&ssb_bustype); + if (err) + return err; + + /* Maybe we already registered some buses at early boot. + * Check for this and attach them + */ + ssb_buses_lock(); + err = ssb_attach_queued_buses(); + ssb_buses_unlock(); + if (err) + bus_unregister(&ssb_bustype); + + err = b43_pci_ssb_bridge_init(); + if (err) { + ssb_printk(KERN_ERR "Broadcom 43xx PCI-SSB-bridge " + "initialization failed"); + /* don't fail SSB init because of this */ + err = 0; + } + + return err; +} +subsys_initcall(ssb_modinit); + +static void __exit ssb_modexit(void) +{ + b43_pci_ssb_bridge_exit(); + bus_unregister(&ssb_bustype); +} +module_exit(ssb_modexit) diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c new file mode 100644 index 00000000000..3d23ca4befe --- /dev/null +++ b/drivers/ssb/pci.c @@ -0,0 +1,740 @@ +/* + * Sonics Silicon Backplane PCI-Hostbus related functions. + * + * Copyright (C) 2005-2006 Michael Buesch + * Copyright (C) 2005 Martin Langer + * Copyright (C) 2005 Stefano Brivio + * Copyright (C) 2005 Danny van Dyk + * Copyright (C) 2005 Andreas Jaggi + * + * Derived from the Broadcom 4400 device driver. + * Copyright (C) 2002 David S. Miller (davem@redhat.com) + * Fixed by Pekka Pietikainen (pp@ee.oulu.fi) + * Copyright (C) 2006 Broadcom Corporation. + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include +#include +#include +#include + +#include "ssb_private.h" + + +/* Define the following to 1 to enable a printk on each coreswitch. */ +#define SSB_VERBOSE_PCICORESWITCH_DEBUG 0 + + +/* Lowlevel coreswitching */ +int ssb_pci_switch_coreidx(struct ssb_bus *bus, u8 coreidx) +{ + int err; + int attempts = 0; + u32 cur_core; + + while (1) { + err = pci_write_config_dword(bus->host_pci, SSB_BAR0_WIN, + (coreidx * SSB_CORE_SIZE) + + SSB_ENUM_BASE); + if (err) + goto error; + err = pci_read_config_dword(bus->host_pci, SSB_BAR0_WIN, + &cur_core); + if (err) + goto error; + cur_core = (cur_core - SSB_ENUM_BASE) + / SSB_CORE_SIZE; + if (cur_core == coreidx) + break; + + if (attempts++ > SSB_BAR0_MAX_RETRIES) + goto error; + udelay(10); + } + return 0; +error: + ssb_printk(KERN_ERR PFX "Failed to switch to core %u\n", coreidx); + return -ENODEV; +} + +int ssb_pci_switch_core(struct ssb_bus *bus, + struct ssb_device *dev) +{ + int err; + unsigned long flags; + +#if SSB_VERBOSE_PCICORESWITCH_DEBUG + ssb_printk(KERN_INFO PFX + "Switching to %s core, index %d\n", + ssb_core_name(dev->id.coreid), + dev->core_index); +#endif + + spin_lock_irqsave(&bus->bar_lock, flags); + err = ssb_pci_switch_coreidx(bus, dev->core_index); + if (!err) + bus->mapped_device = dev; + spin_unlock_irqrestore(&bus->bar_lock, flags); + + return err; +} + +/* Enable/disable the on board crystal oscillator and/or PLL. */ +int ssb_pci_xtal(struct ssb_bus *bus, u32 what, int turn_on) +{ + int err; + u32 in, out, outenable; + u16 pci_status; + + if (bus->bustype != SSB_BUSTYPE_PCI) + return 0; + + err = pci_read_config_dword(bus->host_pci, SSB_GPIO_IN, &in); + if (err) + goto err_pci; + err = pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT, &out); + if (err) + goto err_pci; + err = pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE, &outenable); + if (err) + goto err_pci; + + outenable |= what; + + if (turn_on) { + /* Avoid glitching the clock if GPRS is already using it. + * We can't actually read the state of the PLLPD so we infer it + * by the value of XTAL_PU which *is* readable via gpioin. + */ + if (!(in & SSB_GPIO_XTAL)) { + if (what & SSB_GPIO_XTAL) { + /* Turn the crystal on */ + out |= SSB_GPIO_XTAL; + if (what & SSB_GPIO_PLL) + out |= SSB_GPIO_PLL; + err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out); + if (err) + goto err_pci; + err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE, + outenable); + if (err) + goto err_pci; + msleep(1); + } + if (what & SSB_GPIO_PLL) { + /* Turn the PLL on */ + out &= ~SSB_GPIO_PLL; + err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out); + if (err) + goto err_pci; + msleep(5); + } + } + + err = pci_read_config_word(bus->host_pci, PCI_STATUS, &pci_status); + if (err) + goto err_pci; + pci_status &= ~PCI_STATUS_SIG_TARGET_ABORT; + err = pci_write_config_word(bus->host_pci, PCI_STATUS, pci_status); + if (err) + goto err_pci; + } else { + if (what & SSB_GPIO_XTAL) { + /* Turn the crystal off */ + out &= ~SSB_GPIO_XTAL; + } + if (what & SSB_GPIO_PLL) { + /* Turn the PLL off */ + out |= SSB_GPIO_PLL; + } + err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out); + if (err) + goto err_pci; + err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE, outenable); + if (err) + goto err_pci; + } + +out: + return err; + +err_pci: + printk(KERN_ERR PFX "Error: ssb_pci_xtal() could not access PCI config space!\n"); + err = -EBUSY; + goto out; +} + +/* Get the word-offset for a SSB_SPROM_XXX define. */ +#define SPOFF(offset) (((offset) - SSB_SPROM_BASE) / sizeof(u16)) +/* Helper to extract some _offset, which is one of the SSB_SPROM_XXX defines. */ +#define SPEX(_outvar, _offset, _mask, _shift) \ + out->_outvar = ((in[SPOFF(_offset)] & (_mask)) >> (_shift)) + +static inline u8 ssb_crc8(u8 crc, u8 data) +{ + /* Polynomial: x^8 + x^7 + x^6 + x^4 + x^2 + 1 */ + static const u8 t[] = { + 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B, + 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21, + 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF, + 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5, + 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14, + 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E, + 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80, + 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA, + 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95, + 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF, + 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01, + 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B, + 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA, + 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0, + 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E, + 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34, + 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0, + 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A, + 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54, + 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E, + 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF, + 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5, + 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B, + 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61, + 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E, + 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74, + 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA, + 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0, + 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41, + 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B, + 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5, + 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F, + }; + return t[crc ^ data]; +} + +static u8 ssb_sprom_crc(const u16 *sprom) +{ + int word; + u8 crc = 0xFF; + + for (word = 0; word < SSB_SPROMSIZE_WORDS - 1; word++) { + crc = ssb_crc8(crc, sprom[word] & 0x00FF); + crc = ssb_crc8(crc, (sprom[word] & 0xFF00) >> 8); + } + crc = ssb_crc8(crc, sprom[SPOFF(SSB_SPROM_REVISION)] & 0x00FF); + crc ^= 0xFF; + + return crc; +} + +static int sprom_check_crc(const u16 *sprom) +{ + u8 crc; + u8 expected_crc; + u16 tmp; + + crc = ssb_sprom_crc(sprom); + tmp = sprom[SPOFF(SSB_SPROM_REVISION)] & SSB_SPROM_REVISION_CRC; + expected_crc = tmp >> SSB_SPROM_REVISION_CRC_SHIFT; + if (crc != expected_crc) + return -EPROTO; + + return 0; +} + +static void sprom_do_read(struct ssb_bus *bus, u16 *sprom) +{ + int i; + + for (i = 0; i < SSB_SPROMSIZE_WORDS; i++) + sprom[i] = readw(bus->mmio + SSB_SPROM_BASE + (i * 2)); +} + +static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom) +{ + struct pci_dev *pdev = bus->host_pci; + int i, err; + u32 spromctl; + + ssb_printk(KERN_NOTICE PFX "Writing SPROM. Do NOT turn off the power! Please stand by...\n"); + err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl); + if (err) + goto err_ctlreg; + spromctl |= SSB_SPROMCTL_WE; + err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl); + if (err) + goto err_ctlreg; + ssb_printk(KERN_NOTICE PFX "[ 0%%"); + msleep(500); + for (i = 0; i < SSB_SPROMSIZE_WORDS; i++) { + if (i == SSB_SPROMSIZE_WORDS / 4) + ssb_printk("25%%"); + else if (i == SSB_SPROMSIZE_WORDS / 2) + ssb_printk("50%%"); + else if (i == (SSB_SPROMSIZE_WORDS / 4) * 3) + ssb_printk("75%%"); + else if (i % 2) + ssb_printk("."); + writew(sprom[i], bus->mmio + SSB_SPROM_BASE + (i * 2)); + mmiowb(); + msleep(20); + } + err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl); + if (err) + goto err_ctlreg; + spromctl &= ~SSB_SPROMCTL_WE; + err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl); + if (err) + goto err_ctlreg; + msleep(500); + ssb_printk("100%% ]\n"); + ssb_printk(KERN_NOTICE PFX "SPROM written.\n"); + + return 0; +err_ctlreg: + ssb_printk(KERN_ERR PFX "Could not access SPROM control register.\n"); + return err; +} + +static void sprom_extract_r1(struct ssb_sprom_r1 *out, const u16 *in) +{ + int i; + u16 v; + + SPEX(pci_spid, SSB_SPROM1_SPID, 0xFFFF, 0); + SPEX(pci_svid, SSB_SPROM1_SVID, 0xFFFF, 0); + SPEX(pci_pid, SSB_SPROM1_PID, 0xFFFF, 0); + for (i = 0; i < 3; i++) { + v = in[SPOFF(SSB_SPROM1_IL0MAC) + i]; + *(((u16 *)out->il0mac) + i) = cpu_to_be16(v); + } + for (i = 0; i < 3; i++) { + v = in[SPOFF(SSB_SPROM1_ET0MAC) + i]; + *(((u16 *)out->et0mac) + i) = cpu_to_be16(v); + } + for (i = 0; i < 3; i++) { + v = in[SPOFF(SSB_SPROM1_ET1MAC) + i]; + *(((u16 *)out->et1mac) + i) = cpu_to_be16(v); + } + SPEX(et0phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0A, 0); + SPEX(et1phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1A, + SSB_SPROM1_ETHPHY_ET1A_SHIFT); + SPEX(et0mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0M, 14); + SPEX(et1mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1M, 15); + SPEX(board_rev, SSB_SPROM1_BINF, SSB_SPROM1_BINF_BREV, 0); + SPEX(country_code, SSB_SPROM1_BINF, SSB_SPROM1_BINF_CCODE, + SSB_SPROM1_BINF_CCODE_SHIFT); + SPEX(antenna_a, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTA, + SSB_SPROM1_BINF_ANTA_SHIFT); + SPEX(antenna_bg, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTBG, + SSB_SPROM1_BINF_ANTBG_SHIFT); + SPEX(pa0b0, SSB_SPROM1_PA0B0, 0xFFFF, 0); + SPEX(pa0b1, SSB_SPROM1_PA0B1, 0xFFFF, 0); + SPEX(pa0b2, SSB_SPROM1_PA0B2, 0xFFFF, 0); + SPEX(pa1b0, SSB_SPROM1_PA1B0, 0xFFFF, 0); + SPEX(pa1b1, SSB_SPROM1_PA1B1, 0xFFFF, 0); + SPEX(pa1b2, SSB_SPROM1_PA1B2, 0xFFFF, 0); + SPEX(gpio0, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P0, 0); + SPEX(gpio1, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P1, + SSB_SPROM1_GPIOA_P1_SHIFT); + SPEX(gpio2, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P2, 0); + SPEX(gpio3, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P3, + SSB_SPROM1_GPIOB_P3_SHIFT); + SPEX(maxpwr_a, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_A, + SSB_SPROM1_MAXPWR_A_SHIFT); + SPEX(maxpwr_bg, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_BG, 0); + SPEX(itssi_a, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_A, + SSB_SPROM1_ITSSI_A_SHIFT); + SPEX(itssi_bg, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_BG, 0); + SPEX(boardflags_lo, SSB_SPROM1_BFLLO, 0xFFFF, 0); + SPEX(antenna_gain_a, SSB_SPROM1_AGAIN, SSB_SPROM1_AGAIN_A, 0); + SPEX(antenna_gain_bg, SSB_SPROM1_AGAIN, SSB_SPROM1_AGAIN_BG, + SSB_SPROM1_AGAIN_BG_SHIFT); + for (i = 0; i < 4; i++) { + v = in[SPOFF(SSB_SPROM1_OEM) + i]; + *(((u16 *)out->oem) + i) = cpu_to_le16(v); + } +} + +static void sprom_extract_r2(struct ssb_sprom_r2 *out, const u16 *in) +{ + int i; + u16 v; + + SPEX(boardflags_hi, SSB_SPROM2_BFLHI, 0xFFFF, 0); + SPEX(maxpwr_a_hi, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_HI, 0); + SPEX(maxpwr_a_lo, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_LO, + SSB_SPROM2_MAXP_A_LO_SHIFT); + SPEX(pa1lob0, SSB_SPROM2_PA1LOB0, 0xFFFF, 0); + SPEX(pa1lob1, SSB_SPROM2_PA1LOB1, 0xFFFF, 0); + SPEX(pa1lob2, SSB_SPROM2_PA1LOB2, 0xFFFF, 0); + SPEX(pa1hib0, SSB_SPROM2_PA1HIB0, 0xFFFF, 0); + SPEX(pa1hib1, SSB_SPROM2_PA1HIB1, 0xFFFF, 0); + SPEX(pa1hib2, SSB_SPROM2_PA1HIB2, 0xFFFF, 0); + SPEX(ofdm_pwr_off, SSB_SPROM2_OPO, SSB_SPROM2_OPO_VALUE, 0); + for (i = 0; i < 4; i++) { + v = in[SPOFF(SSB_SPROM2_CCODE) + i]; + *(((u16 *)out->country_str) + i) = cpu_to_le16(v); + } +} + +static void sprom_extract_r3(struct ssb_sprom_r3 *out, const u16 *in) +{ + out->ofdmapo = (in[SPOFF(SSB_SPROM3_OFDMAPO) + 0] & 0xFF00) >> 8; + out->ofdmapo |= (in[SPOFF(SSB_SPROM3_OFDMAPO) + 0] & 0x00FF) << 8; + out->ofdmapo <<= 16; + out->ofdmapo |= (in[SPOFF(SSB_SPROM3_OFDMAPO) + 1] & 0xFF00) >> 8; + out->ofdmapo |= (in[SPOFF(SSB_SPROM3_OFDMAPO) + 1] & 0x00FF) << 8; + + out->ofdmalpo = (in[SPOFF(SSB_SPROM3_OFDMALPO) + 0] & 0xFF00) >> 8; + out->ofdmalpo |= (in[SPOFF(SSB_SPROM3_OFDMALPO) + 0] & 0x00FF) << 8; + out->ofdmalpo <<= 16; + out->ofdmalpo |= (in[SPOFF(SSB_SPROM3_OFDMALPO) + 1] & 0xFF00) >> 8; + out->ofdmalpo |= (in[SPOFF(SSB_SPROM3_OFDMALPO) + 1] & 0x00FF) << 8; + + out->ofdmahpo = (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 0] & 0xFF00) >> 8; + out->ofdmahpo |= (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 0] & 0x00FF) << 8; + out->ofdmahpo <<= 16; + out->ofdmahpo |= (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 1] & 0xFF00) >> 8; + out->ofdmahpo |= (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 1] & 0x00FF) << 8; + + SPEX(gpioldc_on_cnt, SSB_SPROM3_GPIOLDC, SSB_SPROM3_GPIOLDC_ON, + SSB_SPROM3_GPIOLDC_ON_SHIFT); + SPEX(gpioldc_off_cnt, SSB_SPROM3_GPIOLDC, SSB_SPROM3_GPIOLDC_OFF, + SSB_SPROM3_GPIOLDC_OFF_SHIFT); + SPEX(cckpo_1M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_1M, 0); + SPEX(cckpo_2M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_2M, + SSB_SPROM3_CCKPO_2M_SHIFT); + SPEX(cckpo_55M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_55M, + SSB_SPROM3_CCKPO_55M_SHIFT); + SPEX(cckpo_11M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_11M, + SSB_SPROM3_CCKPO_11M_SHIFT); + + out->ofdmgpo = (in[SPOFF(SSB_SPROM3_OFDMGPO) + 0] & 0xFF00) >> 8; + out->ofdmgpo |= (in[SPOFF(SSB_SPROM3_OFDMGPO) + 0] & 0x00FF) << 8; + out->ofdmgpo <<= 16; + out->ofdmgpo |= (in[SPOFF(SSB_SPROM3_OFDMGPO) + 1] & 0xFF00) >> 8; + out->ofdmgpo |= (in[SPOFF(SSB_SPROM3_OFDMGPO) + 1] & 0x00FF) << 8; +} + +static int sprom_extract(struct ssb_bus *bus, + struct ssb_sprom *out, const u16 *in) +{ + memset(out, 0, sizeof(*out)); + + SPEX(revision, SSB_SPROM_REVISION, SSB_SPROM_REVISION_REV, 0); + SPEX(crc, SSB_SPROM_REVISION, SSB_SPROM_REVISION_CRC, + SSB_SPROM_REVISION_CRC_SHIFT); + + if ((bus->chip_id & 0xFF00) == 0x4400) { + /* Workaround: The BCM44XX chip has a stupid revision + * number stored in the SPROM. + * Always extract r1. */ + sprom_extract_r1(&out->r1, in); + } else { + if (out->revision == 0) + goto unsupported; + if (out->revision >= 1 && out->revision <= 3) + sprom_extract_r1(&out->r1, in); + if (out->revision >= 2 && out->revision <= 3) + sprom_extract_r2(&out->r2, in); + if (out->revision == 3) + sprom_extract_r3(&out->r3, in); + if (out->revision >= 4) + goto unsupported; + } + + return 0; +unsupported: + ssb_printk(KERN_WARNING PFX "Unsupported SPROM revision %d " + "detected. Will extract v1\n", out->revision); + sprom_extract_r1(&out->r1, in); + return 0; +} + +static int ssb_pci_sprom_get(struct ssb_bus *bus, + struct ssb_sprom *sprom) +{ + int err = -ENOMEM; + u16 *buf; + + buf = kcalloc(SSB_SPROMSIZE_WORDS, sizeof(u16), GFP_KERNEL); + if (!buf) + goto out; + sprom_do_read(bus, buf); + err = sprom_check_crc(buf); + if (err) { + ssb_printk(KERN_WARNING PFX + "WARNING: Invalid SPROM CRC (corrupt SPROM)\n"); + } + err = sprom_extract(bus, sprom, buf); + + kfree(buf); +out: + return err; +} + +static void ssb_pci_get_boardinfo(struct ssb_bus *bus, + struct ssb_boardinfo *bi) +{ + pci_read_config_word(bus->host_pci, PCI_SUBSYSTEM_VENDOR_ID, + &bi->vendor); + pci_read_config_word(bus->host_pci, PCI_SUBSYSTEM_ID, + &bi->type); + pci_read_config_word(bus->host_pci, PCI_REVISION_ID, + &bi->rev); +} + +int ssb_pci_get_invariants(struct ssb_bus *bus, + struct ssb_init_invariants *iv) +{ + int err; + + err = ssb_pci_sprom_get(bus, &iv->sprom); + if (err) + goto out; + ssb_pci_get_boardinfo(bus, &iv->boardinfo); + +out: + return err; +} + +#ifdef CONFIG_SSB_DEBUG +static int ssb_pci_assert_buspower(struct ssb_bus *bus) +{ + if (likely(bus->powered_up)) + return 0; + + printk(KERN_ERR PFX "FATAL ERROR: Bus powered down " + "while accessing PCI MMIO space\n"); + if (bus->power_warn_count <= 10) { + bus->power_warn_count++; + dump_stack(); + } + + return -ENODEV; +} +#else /* DEBUG */ +static inline int ssb_pci_assert_buspower(struct ssb_bus *bus) +{ + return 0; +} +#endif /* DEBUG */ + +static u16 ssb_pci_read16(struct ssb_device *dev, u16 offset) +{ + struct ssb_bus *bus = dev->bus; + + if (unlikely(ssb_pci_assert_buspower(bus))) + return 0xFFFF; + if (unlikely(bus->mapped_device != dev)) { + if (unlikely(ssb_pci_switch_core(bus, dev))) + return 0xFFFF; + } + return readw(bus->mmio + offset); +} + +static u32 ssb_pci_read32(struct ssb_device *dev, u16 offset) +{ + struct ssb_bus *bus = dev->bus; + + if (unlikely(ssb_pci_assert_buspower(bus))) + return 0xFFFFFFFF; + if (unlikely(bus->mapped_device != dev)) { + if (unlikely(ssb_pci_switch_core(bus, dev))) + return 0xFFFFFFFF; + } + return readl(bus->mmio + offset); +} + +static void ssb_pci_write16(struct ssb_device *dev, u16 offset, u16 value) +{ + struct ssb_bus *bus = dev->bus; + + if (unlikely(ssb_pci_assert_buspower(bus))) + return; + if (unlikely(bus->mapped_device != dev)) { + if (unlikely(ssb_pci_switch_core(bus, dev))) + return; + } + writew(value, bus->mmio + offset); +} + +static void ssb_pci_write32(struct ssb_device *dev, u16 offset, u32 value) +{ + struct ssb_bus *bus = dev->bus; + + if (unlikely(ssb_pci_assert_buspower(bus))) + return; + if (unlikely(bus->mapped_device != dev)) { + if (unlikely(ssb_pci_switch_core(bus, dev))) + return; + } + writel(value, bus->mmio + offset); +} + +/* Not "static", as it's used in main.c */ +const struct ssb_bus_ops ssb_pci_ops = { + .read16 = ssb_pci_read16, + .read32 = ssb_pci_read32, + .write16 = ssb_pci_write16, + .write32 = ssb_pci_write32, +}; + +static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len) +{ + int i, pos = 0; + + for (i = 0; i < SSB_SPROMSIZE_WORDS; i++) { + pos += snprintf(buf + pos, buf_len - pos - 1, + "%04X", swab16(sprom[i]) & 0xFFFF); + } + pos += snprintf(buf + pos, buf_len - pos - 1, "\n"); + + return pos + 1; +} + +static int hex2sprom(u16 *sprom, const char *dump, size_t len) +{ + char tmp[5] = { 0 }; + int cnt = 0; + unsigned long parsed; + + if (len < SSB_SPROMSIZE_BYTES * 2) + return -EINVAL; + + while (cnt < SSB_SPROMSIZE_WORDS) { + memcpy(tmp, dump, 4); + dump += 4; + parsed = simple_strtoul(tmp, NULL, 16); + sprom[cnt++] = swab16((u16)parsed); + } + + return 0; +} + +static ssize_t ssb_pci_attr_sprom_show(struct device *pcidev, + struct device_attribute *attr, + char *buf) +{ + struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev); + struct ssb_bus *bus; + u16 *sprom; + int err = -ENODEV; + ssize_t count = 0; + + bus = ssb_pci_dev_to_bus(pdev); + if (!bus) + goto out; + err = -ENOMEM; + sprom = kcalloc(SSB_SPROMSIZE_WORDS, sizeof(u16), GFP_KERNEL); + if (!sprom) + goto out; + + /* Use interruptible locking, as the SPROM write might + * be holding the lock for several seconds. So allow userspace + * to cancel operation. */ + err = -ERESTARTSYS; + if (mutex_lock_interruptible(&bus->pci_sprom_mutex)) + goto out_kfree; + sprom_do_read(bus, sprom); + mutex_unlock(&bus->pci_sprom_mutex); + + count = sprom2hex(sprom, buf, PAGE_SIZE); + err = 0; + +out_kfree: + kfree(sprom); +out: + return err ? err : count; +} + +static ssize_t ssb_pci_attr_sprom_store(struct device *pcidev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev); + struct ssb_bus *bus; + u16 *sprom; + int res = 0, err = -ENODEV; + + bus = ssb_pci_dev_to_bus(pdev); + if (!bus) + goto out; + err = -ENOMEM; + sprom = kcalloc(SSB_SPROMSIZE_WORDS, sizeof(u16), GFP_KERNEL); + if (!sprom) + goto out; + err = hex2sprom(sprom, buf, count); + if (err) { + err = -EINVAL; + goto out_kfree; + } + err = sprom_check_crc(sprom); + if (err) { + err = -EINVAL; + goto out_kfree; + } + + /* Use interruptible locking, as the SPROM write might + * be holding the lock for several seconds. So allow userspace + * to cancel operation. */ + err = -ERESTARTSYS; + if (mutex_lock_interruptible(&bus->pci_sprom_mutex)) + goto out_kfree; + err = ssb_devices_freeze(bus); + if (err == -EOPNOTSUPP) { + ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze devices. " + "No suspend support. Is CONFIG_PM enabled?\n"); + goto out_unlock; + } + if (err) { + ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze all devices\n"); + goto out_unlock; + } + res = sprom_do_write(bus, sprom); + err = ssb_devices_thaw(bus); + if (err) + ssb_printk(KERN_ERR PFX "SPROM write: Could not thaw all devices\n"); +out_unlock: + mutex_unlock(&bus->pci_sprom_mutex); +out_kfree: + kfree(sprom); +out: + if (res) + return res; + return err ? err : count; +} + +static DEVICE_ATTR(ssb_sprom, 0600, + ssb_pci_attr_sprom_show, + ssb_pci_attr_sprom_store); + +void ssb_pci_exit(struct ssb_bus *bus) +{ + struct pci_dev *pdev; + + if (bus->bustype != SSB_BUSTYPE_PCI) + return; + + pdev = bus->host_pci; + device_remove_file(&pdev->dev, &dev_attr_ssb_sprom); +} + +int ssb_pci_init(struct ssb_bus *bus) +{ + struct pci_dev *pdev; + int err; + + if (bus->bustype != SSB_BUSTYPE_PCI) + return 0; + + pdev = bus->host_pci; + mutex_init(&bus->pci_sprom_mutex); + err = device_create_file(&pdev->dev, &dev_attr_ssb_sprom); + if (err) + goto out; + +out: + return err; +} diff --git a/drivers/ssb/pcihost_wrapper.c b/drivers/ssb/pcihost_wrapper.c new file mode 100644 index 00000000000..82a10abef64 --- /dev/null +++ b/drivers/ssb/pcihost_wrapper.c @@ -0,0 +1,104 @@ +/* + * Sonics Silicon Backplane + * PCI Hostdevice wrapper + * + * Copyright (c) 2005 Martin Langer + * Copyright (c) 2005 Stefano Brivio + * Copyright (c) 2005 Danny van Dyk + * Copyright (c) 2005 Andreas Jaggi + * Copyright (c) 2005-2007 Michael Buesch + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include +#include + + +#ifdef CONFIG_PM +static int ssb_pcihost_suspend(struct pci_dev *dev, pm_message_t state) +{ + pci_save_state(dev); + pci_disable_device(dev); + pci_set_power_state(dev, pci_choose_state(dev, state)); + + return 0; +} + +static int ssb_pcihost_resume(struct pci_dev *dev) +{ + int err; + + pci_set_power_state(dev, 0); + err = pci_enable_device(dev); + if (err) + return err; + pci_restore_state(dev); + + return 0; +} +#else /* CONFIG_PM */ +# define ssb_pcihost_suspend NULL +# define ssb_pcihost_resume NULL +#endif /* CONFIG_PM */ + +static int ssb_pcihost_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + struct ssb_bus *ssb; + int err = -ENOMEM; + const char *name; + + ssb = kzalloc(sizeof(*ssb), GFP_KERNEL); + if (!ssb) + goto out; + err = pci_enable_device(dev); + if (err) + goto err_kfree_ssb; + name = dev->dev.bus_id; + if (dev->driver && dev->driver->name) + name = dev->driver->name; + err = pci_request_regions(dev, name); + if (err) + goto err_pci_disable; + pci_set_master(dev); + + err = ssb_bus_pcibus_register(ssb, dev); + if (err) + goto err_pci_release_regions; + + pci_set_drvdata(dev, ssb); + +out: + return err; + +err_pci_release_regions: + pci_release_regions(dev); +err_pci_disable: + pci_disable_device(dev); +err_kfree_ssb: + kfree(ssb); + return err; +} + +static void ssb_pcihost_remove(struct pci_dev *dev) +{ + struct ssb_bus *ssb = pci_get_drvdata(dev); + + ssb_bus_unregister(ssb); + pci_release_regions(dev); + pci_disable_device(dev); + kfree(ssb); + pci_set_drvdata(dev, NULL); +} + +int ssb_pcihost_register(struct pci_driver *driver) +{ + driver->probe = ssb_pcihost_probe; + driver->remove = ssb_pcihost_remove; + driver->suspend = ssb_pcihost_suspend; + driver->resume = ssb_pcihost_resume; + + return pci_register_driver(driver); +} +EXPORT_SYMBOL(ssb_pcihost_register); diff --git a/drivers/ssb/pcmcia.c b/drivers/ssb/pcmcia.c new file mode 100644 index 00000000000..7c773603b40 --- /dev/null +++ b/drivers/ssb/pcmcia.c @@ -0,0 +1,271 @@ +/* + * Sonics Silicon Backplane + * PCMCIA-Hostbus related functions + * + * Copyright 2006 Johannes Berg + * Copyright 2007 Michael Buesch + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "ssb_private.h" + + +/* Define the following to 1 to enable a printk on each coreswitch. */ +#define SSB_VERBOSE_PCMCIACORESWITCH_DEBUG 0 + + +int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus, + u8 coreidx) +{ + struct pcmcia_device *pdev = bus->host_pcmcia; + int err; + int attempts = 0; + u32 cur_core; + conf_reg_t reg; + u32 addr; + u32 read_addr; + + addr = (coreidx * SSB_CORE_SIZE) + SSB_ENUM_BASE; + while (1) { + reg.Action = CS_WRITE; + reg.Offset = 0x2E; + reg.Value = (addr & 0x0000F000) >> 12; + err = pcmcia_access_configuration_register(pdev, ®); + if (err != CS_SUCCESS) + goto error; + reg.Offset = 0x30; + reg.Value = (addr & 0x00FF0000) >> 16; + err = pcmcia_access_configuration_register(pdev, ®); + if (err != CS_SUCCESS) + goto error; + reg.Offset = 0x32; + reg.Value = (addr & 0xFF000000) >> 24; + err = pcmcia_access_configuration_register(pdev, ®); + if (err != CS_SUCCESS) + goto error; + + read_addr = 0; + + reg.Action = CS_READ; + reg.Offset = 0x2E; + err = pcmcia_access_configuration_register(pdev, ®); + if (err != CS_SUCCESS) + goto error; + read_addr |= (reg.Value & 0xF) << 12; + reg.Offset = 0x30; + err = pcmcia_access_configuration_register(pdev, ®); + if (err != CS_SUCCESS) + goto error; + read_addr |= reg.Value << 16; + reg.Offset = 0x32; + err = pcmcia_access_configuration_register(pdev, ®); + if (err != CS_SUCCESS) + goto error; + read_addr |= reg.Value << 24; + + cur_core = (read_addr - SSB_ENUM_BASE) / SSB_CORE_SIZE; + if (cur_core == coreidx) + break; + + if (attempts++ > SSB_BAR0_MAX_RETRIES) + goto error; + udelay(10); + } + + return 0; +error: + ssb_printk(KERN_ERR PFX "Failed to switch to core %u\n", coreidx); + return -ENODEV; +} + +int ssb_pcmcia_switch_core(struct ssb_bus *bus, + struct ssb_device *dev) +{ + int err; + unsigned long flags; + +#if SSB_VERBOSE_PCMCIACORESWITCH_DEBUG + ssb_printk(KERN_INFO PFX + "Switching to %s core, index %d\n", + ssb_core_name(dev->id.coreid), + dev->core_index); +#endif + + spin_lock_irqsave(&bus->bar_lock, flags); + err = ssb_pcmcia_switch_coreidx(bus, dev->core_index); + if (!err) + bus->mapped_device = dev; + spin_unlock_irqrestore(&bus->bar_lock, flags); + + return err; +} + +int ssb_pcmcia_switch_segment(struct ssb_bus *bus, u8 seg) +{ + int attempts = 0; + unsigned long flags; + conf_reg_t reg; + int res, err = 0; + + SSB_WARN_ON((seg != 0) && (seg != 1)); + reg.Offset = 0x34; + reg.Function = 0; + spin_lock_irqsave(&bus->bar_lock, flags); + while (1) { + reg.Action = CS_WRITE; + reg.Value = seg; + res = pcmcia_access_configuration_register(bus->host_pcmcia, ®); + if (unlikely(res != CS_SUCCESS)) + goto error; + reg.Value = 0xFF; + reg.Action = CS_READ; + res = pcmcia_access_configuration_register(bus->host_pcmcia, ®); + if (unlikely(res != CS_SUCCESS)) + goto error; + + if (reg.Value == seg) + break; + + if (unlikely(attempts++ > SSB_BAR0_MAX_RETRIES)) + goto error; + udelay(10); + } + bus->mapped_pcmcia_seg = seg; +out_unlock: + spin_unlock_irqrestore(&bus->bar_lock, flags); + return err; +error: + ssb_printk(KERN_ERR PFX "Failed to switch pcmcia segment\n"); + err = -ENODEV; + goto out_unlock; +} + +/* These are the main device register access functions. + * do_select_core is inline to have the likely hotpath inline. + * All unlikely codepaths are out-of-line. */ +static inline int do_select_core(struct ssb_bus *bus, + struct ssb_device *dev, + u16 *offset) +{ + int err; + u8 need_seg = (*offset >= 0x800) ? 1 : 0; + + if (unlikely(dev != bus->mapped_device)) { + err = ssb_pcmcia_switch_core(bus, dev); + if (unlikely(err)) + return err; + } + if (unlikely(need_seg != bus->mapped_pcmcia_seg)) { + err = ssb_pcmcia_switch_segment(bus, need_seg); + if (unlikely(err)) + return err; + } + if (need_seg == 1) + *offset -= 0x800; + + return 0; +} + +static u16 ssb_pcmcia_read16(struct ssb_device *dev, u16 offset) +{ + struct ssb_bus *bus = dev->bus; + u16 x; + + if (unlikely(do_select_core(bus, dev, &offset))) + return 0xFFFF; + x = readw(bus->mmio + offset); + + return x; +} + +static u32 ssb_pcmcia_read32(struct ssb_device *dev, u16 offset) +{ + struct ssb_bus *bus = dev->bus; + u32 x; + + if (unlikely(do_select_core(bus, dev, &offset))) + return 0xFFFFFFFF; + x = readl(bus->mmio + offset); + + return x; +} + +static void ssb_pcmcia_write16(struct ssb_device *dev, u16 offset, u16 value) +{ + struct ssb_bus *bus = dev->bus; + + if (unlikely(do_select_core(bus, dev, &offset))) + return; + writew(value, bus->mmio + offset); +} + +static void ssb_pcmcia_write32(struct ssb_device *dev, u16 offset, u32 value) +{ + struct ssb_bus *bus = dev->bus; + + if (unlikely(do_select_core(bus, dev, &offset))) + return; + readw(bus->mmio + offset); + writew(value >> 16, bus->mmio + offset + 2); + readw(bus->mmio + offset); + writew(value, bus->mmio + offset); +} + +/* Not "static", as it's used in main.c */ +const struct ssb_bus_ops ssb_pcmcia_ops = { + .read16 = ssb_pcmcia_read16, + .read32 = ssb_pcmcia_read32, + .write16 = ssb_pcmcia_write16, + .write32 = ssb_pcmcia_write32, +}; + +int ssb_pcmcia_get_invariants(struct ssb_bus *bus, + struct ssb_init_invariants *iv) +{ + //TODO + return 0; +} + +int ssb_pcmcia_init(struct ssb_bus *bus) +{ + conf_reg_t reg; + int err; + + if (bus->bustype != SSB_BUSTYPE_PCMCIA) + return 0; + + /* Switch segment to a known state and sync + * bus->mapped_pcmcia_seg with hardware state. */ + ssb_pcmcia_switch_segment(bus, 0); + + /* Init IRQ routing */ + reg.Action = CS_READ; + reg.Function = 0; + if (bus->chip_id == 0x4306) + reg.Offset = 0x00; + else + reg.Offset = 0x80; + err = pcmcia_access_configuration_register(bus->host_pcmcia, ®); + if (err != CS_SUCCESS) + goto error; + reg.Action = CS_WRITE; + reg.Value |= 0x04 | 0x01; + err = pcmcia_access_configuration_register(bus->host_pcmcia, ®); + if (err != CS_SUCCESS) + goto error; + + return 0; +error: + return -ENODEV; +} diff --git a/drivers/ssb/scan.c b/drivers/ssb/scan.c new file mode 100644 index 00000000000..96258c60919 --- /dev/null +++ b/drivers/ssb/scan.c @@ -0,0 +1,413 @@ +/* + * Sonics Silicon Backplane + * Bus scanning + * + * Copyright (C) 2005-2007 Michael Buesch + * Copyright (C) 2005 Martin Langer + * Copyright (C) 2005 Stefano Brivio + * Copyright (C) 2005 Danny van Dyk + * Copyright (C) 2005 Andreas Jaggi + * Copyright (C) 2006 Broadcom Corporation. + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "ssb_private.h" + + +const char *ssb_core_name(u16 coreid) +{ + switch (coreid) { + case SSB_DEV_CHIPCOMMON: + return "ChipCommon"; + case SSB_DEV_ILINE20: + return "ILine 20"; + case SSB_DEV_SDRAM: + return "SDRAM"; + case SSB_DEV_PCI: + return "PCI"; + case SSB_DEV_MIPS: + return "MIPS"; + case SSB_DEV_ETHERNET: + return "Fast Ethernet"; + case SSB_DEV_V90: + return "V90"; + case SSB_DEV_USB11_HOSTDEV: + return "USB 1.1 Hostdev"; + case SSB_DEV_ADSL: + return "ADSL"; + case SSB_DEV_ILINE100: + return "ILine 100"; + case SSB_DEV_IPSEC: + return "IPSEC"; + case SSB_DEV_PCMCIA: + return "PCMCIA"; + case SSB_DEV_INTERNAL_MEM: + return "Internal Memory"; + case SSB_DEV_MEMC_SDRAM: + return "MEMC SDRAM"; + case SSB_DEV_EXTIF: + return "EXTIF"; + case SSB_DEV_80211: + return "IEEE 802.11"; + case SSB_DEV_MIPS_3302: + return "MIPS 3302"; + case SSB_DEV_USB11_HOST: + return "USB 1.1 Host"; + case SSB_DEV_USB11_DEV: + return "USB 1.1 Device"; + case SSB_DEV_USB20_HOST: + return "USB 2.0 Host"; + case SSB_DEV_USB20_DEV: + return "USB 2.0 Device"; + case SSB_DEV_SDIO_HOST: + return "SDIO Host"; + case SSB_DEV_ROBOSWITCH: + return "Roboswitch"; + case SSB_DEV_PARA_ATA: + return "PATA"; + case SSB_DEV_SATA_XORDMA: + return "SATA XOR-DMA"; + case SSB_DEV_ETHERNET_GBIT: + return "GBit Ethernet"; + case SSB_DEV_PCIE: + return "PCI-E"; + case SSB_DEV_MIMO_PHY: + return "MIMO PHY"; + case SSB_DEV_SRAM_CTRLR: + return "SRAM Controller"; + case SSB_DEV_MINI_MACPHY: + return "Mini MACPHY"; + case SSB_DEV_ARM_1176: + return "ARM 1176"; + case SSB_DEV_ARM_7TDMI: + return "ARM 7TDMI"; + } + return "UNKNOWN"; +} + +static u16 pcidev_to_chipid(struct pci_dev *pci_dev) +{ + u16 chipid_fallback = 0; + + switch (pci_dev->device) { + case 0x4301: + chipid_fallback = 0x4301; + break; + case 0x4305 ... 0x4307: + chipid_fallback = 0x4307; + break; + case 0x4403: + chipid_fallback = 0x4402; + break; + case 0x4610 ... 0x4615: + chipid_fallback = 0x4610; + break; + case 0x4710 ... 0x4715: + chipid_fallback = 0x4710; + break; + case 0x4320 ... 0x4325: + chipid_fallback = 0x4309; + break; + case PCI_DEVICE_ID_BCM4401: + case PCI_DEVICE_ID_BCM4401B0: + case PCI_DEVICE_ID_BCM4401B1: + chipid_fallback = 0x4401; + break; + default: + ssb_printk(KERN_ERR PFX + "PCI-ID not in fallback list\n"); + } + + return chipid_fallback; +} + +static u8 chipid_to_nrcores(u16 chipid) +{ + switch (chipid) { + case 0x5365: + return 7; + case 0x4306: + return 6; + case 0x4310: + return 8; + case 0x4307: + case 0x4301: + return 5; + case 0x4401: + case 0x4402: + return 3; + case 0x4710: + case 0x4610: + case 0x4704: + return 9; + default: + ssb_printk(KERN_ERR PFX + "CHIPID not in nrcores fallback list\n"); + } + + return 1; +} + +static u32 scan_read32(struct ssb_bus *bus, u8 current_coreidx, + u16 offset) +{ + switch (bus->bustype) { + case SSB_BUSTYPE_SSB: + offset += current_coreidx * SSB_CORE_SIZE; + break; + case SSB_BUSTYPE_PCI: + break; + case SSB_BUSTYPE_PCMCIA: + if (offset >= 0x800) { + ssb_pcmcia_switch_segment(bus, 1); + offset -= 0x800; + } else + ssb_pcmcia_switch_segment(bus, 0); + break; + } + return readl(bus->mmio + offset); +} + +static int scan_switchcore(struct ssb_bus *bus, u8 coreidx) +{ + switch (bus->bustype) { + case SSB_BUSTYPE_SSB: + break; + case SSB_BUSTYPE_PCI: + return ssb_pci_switch_coreidx(bus, coreidx); + case SSB_BUSTYPE_PCMCIA: + return ssb_pcmcia_switch_coreidx(bus, coreidx); + } + return 0; +} + +void ssb_iounmap(struct ssb_bus *bus) +{ + switch (bus->bustype) { + case SSB_BUSTYPE_SSB: + case SSB_BUSTYPE_PCMCIA: + iounmap(bus->mmio); + break; + case SSB_BUSTYPE_PCI: +#ifdef CONFIG_SSB_PCIHOST + pci_iounmap(bus->host_pci, bus->mmio); +#else + SSB_BUG_ON(1); /* Can't reach this code. */ +#endif + break; + } + bus->mmio = NULL; + bus->mapped_device = NULL; +} + +static void __iomem *ssb_ioremap(struct ssb_bus *bus, + unsigned long baseaddr) +{ + void __iomem *mmio = NULL; + + switch (bus->bustype) { + case SSB_BUSTYPE_SSB: + /* Only map the first core for now. */ + /* fallthrough... */ + case SSB_BUSTYPE_PCMCIA: + mmio = ioremap(baseaddr, SSB_CORE_SIZE); + break; + case SSB_BUSTYPE_PCI: +#ifdef CONFIG_SSB_PCIHOST + mmio = pci_iomap(bus->host_pci, 0, ~0UL); +#else + SSB_BUG_ON(1); /* Can't reach this code. */ +#endif + break; + } + + return mmio; +} + +static int we_support_multiple_80211_cores(struct ssb_bus *bus) +{ + /* More than one 802.11 core is only supported by special chips. + * There are chips with two 802.11 cores, but with dangling + * pins on the second core. Be careful and reject them here. + */ + +#ifdef CONFIG_SSB_PCIHOST + if (bus->bustype == SSB_BUSTYPE_PCI) { + if (bus->host_pci->vendor == PCI_VENDOR_ID_BROADCOM && + bus->host_pci->device == 0x4324) + return 1; + } +#endif /* CONFIG_SSB_PCIHOST */ + return 0; +} + +int ssb_bus_scan(struct ssb_bus *bus, + unsigned long baseaddr) +{ + int err = -ENOMEM; + void __iomem *mmio; + u32 idhi, cc, rev, tmp; + int dev_i, i; + struct ssb_device *dev; + int nr_80211_cores = 0; + + mmio = ssb_ioremap(bus, baseaddr); + if (!mmio) + goto out; + bus->mmio = mmio; + + err = scan_switchcore(bus, 0); /* Switch to first core */ + if (err) + goto err_unmap; + + idhi = scan_read32(bus, 0, SSB_IDHIGH); + cc = (idhi & SSB_IDHIGH_CC) >> SSB_IDHIGH_CC_SHIFT; + rev = (idhi & SSB_IDHIGH_RCLO); + rev |= (idhi & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT; + + bus->nr_devices = 0; + if (cc == SSB_DEV_CHIPCOMMON) { + tmp = scan_read32(bus, 0, SSB_CHIPCO_CHIPID); + + bus->chip_id = (tmp & SSB_CHIPCO_IDMASK); + bus->chip_rev = (tmp & SSB_CHIPCO_REVMASK) >> + SSB_CHIPCO_REVSHIFT; + bus->chip_package = (tmp & SSB_CHIPCO_PACKMASK) >> + SSB_CHIPCO_PACKSHIFT; + if (rev >= 4) { + bus->nr_devices = (tmp & SSB_CHIPCO_NRCORESMASK) >> + SSB_CHIPCO_NRCORESSHIFT; + } + tmp = scan_read32(bus, 0, SSB_CHIPCO_CAP); + bus->chipco.capabilities = tmp; + } else { + if (bus->bustype == SSB_BUSTYPE_PCI) { + bus->chip_id = pcidev_to_chipid(bus->host_pci); + pci_read_config_word(bus->host_pci, PCI_REVISION_ID, + &bus->chip_rev); + bus->chip_package = 0; + } else { + bus->chip_id = 0x4710; + bus->chip_rev = 0; + bus->chip_package = 0; + } + } + if (!bus->nr_devices) + bus->nr_devices = chipid_to_nrcores(bus->chip_id); + if (bus->nr_devices > ARRAY_SIZE(bus->devices)) { + ssb_printk(KERN_ERR PFX + "More than %d ssb cores found (%d)\n", + SSB_MAX_NR_CORES, bus->nr_devices); + goto err_unmap; + } + if (bus->bustype == SSB_BUSTYPE_SSB) { + /* Now that we know the number of cores, + * remap the whole IO space for all cores. + */ + err = -ENOMEM; + iounmap(mmio); + mmio = ioremap(baseaddr, SSB_CORE_SIZE * bus->nr_devices); + if (!mmio) + goto out; + bus->mmio = mmio; + } + + /* Fetch basic information about each core/device */ + for (i = 0, dev_i = 0; i < bus->nr_devices; i++) { + err = scan_switchcore(bus, i); + if (err) + goto err_unmap; + dev = &(bus->devices[dev_i]); + + idhi = scan_read32(bus, i, SSB_IDHIGH); + dev->id.coreid = (idhi & SSB_IDHIGH_CC) >> SSB_IDHIGH_CC_SHIFT; + dev->id.revision = (idhi & SSB_IDHIGH_RCLO); + dev->id.revision |= (idhi & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT; + dev->id.vendor = (idhi & SSB_IDHIGH_VC) >> SSB_IDHIGH_VC_SHIFT; + dev->core_index = i; + dev->bus = bus; + dev->ops = bus->ops; + + ssb_dprintk(KERN_INFO PFX + "Core %d found: %s " + "(cc 0x%03X, rev 0x%02X, vendor 0x%04X)\n", + i, ssb_core_name(dev->id.coreid), + dev->id.coreid, dev->id.revision, dev->id.vendor); + + switch (dev->id.coreid) { + case SSB_DEV_80211: + nr_80211_cores++; + if (nr_80211_cores > 1) { + if (!we_support_multiple_80211_cores(bus)) { + ssb_dprintk(KERN_INFO PFX "Ignoring additional " + "802.11 core\n"); + continue; + } + } + break; + case SSB_DEV_EXTIF: +#ifdef CONFIG_SSB_DRIVER_EXTIF + if (bus->extif.dev) { + ssb_printk(KERN_WARNING PFX + "WARNING: Multiple EXTIFs found\n"); + break; + } + bus->extif.dev = dev; +#endif /* CONFIG_SSB_DRIVER_EXTIF */ + break; + case SSB_DEV_CHIPCOMMON: + if (bus->chipco.dev) { + ssb_printk(KERN_WARNING PFX + "WARNING: Multiple ChipCommon found\n"); + break; + } + bus->chipco.dev = dev; + break; + case SSB_DEV_MIPS: + case SSB_DEV_MIPS_3302: +#ifdef CONFIG_SSB_DRIVER_MIPS + if (bus->mipscore.dev) { + ssb_printk(KERN_WARNING PFX + "WARNING: Multiple MIPS cores found\n"); + break; + } + bus->mipscore.dev = dev; +#endif /* CONFIG_SSB_DRIVER_MIPS */ + break; + case SSB_DEV_PCI: + case SSB_DEV_PCIE: +#ifdef CONFIG_SSB_DRIVER_PCICORE + if (bus->pcicore.dev) { + ssb_printk(KERN_WARNING PFX + "WARNING: Multiple PCI(E) cores found\n"); + break; + } + bus->pcicore.dev = dev; +#endif /* CONFIG_SSB_DRIVER_PCICORE */ + break; + default: + break; + } + + dev_i++; + } + bus->nr_devices = dev_i; + + err = 0; +out: + return err; +err_unmap: + ssb_iounmap(bus); + goto out; +} diff --git a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h new file mode 100644 index 00000000000..a789364264a --- /dev/null +++ b/drivers/ssb/ssb_private.h @@ -0,0 +1,136 @@ +#ifndef LINUX_SSB_PRIVATE_H_ +#define LINUX_SSB_PRIVATE_H_ + +#include +#include + + +#define PFX "ssb: " + +#ifdef CONFIG_SSB_SILENT +# define ssb_printk(fmt, x...) do { /* nothing */ } while (0) +#else +# define ssb_printk printk +#endif /* CONFIG_SSB_SILENT */ + +/* dprintk: Debugging printk; vanishes for non-debug compilation */ +#ifdef CONFIG_SSB_DEBUG +# define ssb_dprintk(fmt, x...) ssb_printk(fmt , ##x) +#else +# define ssb_dprintk(fmt, x...) do { /* nothing */ } while (0) +#endif + +#ifdef CONFIG_SSB_DEBUG +# define SSB_WARN_ON(x) WARN_ON(x) +# define SSB_BUG_ON(x) BUG_ON(x) +#else +static inline int __ssb_do_nothing(int x) { return x; } +# define SSB_WARN_ON(x) __ssb_do_nothing(unlikely(!!(x))) +# define SSB_BUG_ON(x) __ssb_do_nothing(unlikely(!!(x))) +#endif + + +/* pci.c */ +#ifdef CONFIG_SSB_PCIHOST +extern int ssb_pci_switch_core(struct ssb_bus *bus, + struct ssb_device *dev); +extern int ssb_pci_switch_coreidx(struct ssb_bus *bus, + u8 coreidx); +extern int ssb_pci_xtal(struct ssb_bus *bus, u32 what, + int turn_on); +extern int ssb_pci_get_invariants(struct ssb_bus *bus, + struct ssb_init_invariants *iv); +extern void ssb_pci_exit(struct ssb_bus *bus); +extern int ssb_pci_init(struct ssb_bus *bus); +extern const struct ssb_bus_ops ssb_pci_ops; + +#else /* CONFIG_SSB_PCIHOST */ + +static inline int ssb_pci_switch_core(struct ssb_bus *bus, + struct ssb_device *dev) +{ + return 0; +} +static inline int ssb_pci_switch_coreidx(struct ssb_bus *bus, + u8 coreidx) +{ + return 0; +} +static inline int ssb_pci_xtal(struct ssb_bus *bus, u32 what, + int turn_on) +{ + return 0; +} +static inline void ssb_pci_exit(struct ssb_bus *bus) +{ +} +static inline int ssb_pci_init(struct ssb_bus *bus) +{ + return 0; +} +#endif /* CONFIG_SSB_PCIHOST */ + + +/* pcmcia.c */ +#ifdef CONFIG_SSB_PCMCIAHOST +extern int ssb_pcmcia_switch_core(struct ssb_bus *bus, + struct ssb_device *dev); +extern int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus, + u8 coreidx); +extern int ssb_pcmcia_switch_segment(struct ssb_bus *bus, + u8 seg); +extern int ssb_pcmcia_get_invariants(struct ssb_bus *bus, + struct ssb_init_invariants *iv); +extern int ssb_pcmcia_init(struct ssb_bus *bus); +extern const struct ssb_bus_ops ssb_pcmcia_ops; +#else /* CONFIG_SSB_PCMCIAHOST */ +static inline int ssb_pcmcia_switch_core(struct ssb_bus *bus, + struct ssb_device *dev) +{ + return 0; +} +static inline int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus, + u8 coreidx) +{ + return 0; +} +static inline int ssb_pcmcia_switch_segment(struct ssb_bus *bus, + u8 seg) +{ + return 0; +} +static inline int ssb_pcmcia_init(struct ssb_bus *bus) +{ + return 0; +} +#endif /* CONFIG_SSB_PCMCIAHOST */ + + +/* scan.c */ +extern const char *ssb_core_name(u16 coreid); +extern int ssb_bus_scan(struct ssb_bus *bus, + unsigned long baseaddr); +extern void ssb_iounmap(struct ssb_bus *ssb); + + +/* core.c */ +extern u32 ssb_calc_clock_rate(u32 plltype, u32 n, u32 m); +extern int ssb_devices_freeze(struct ssb_bus *bus); +extern int ssb_devices_thaw(struct ssb_bus *bus); +extern struct ssb_bus *ssb_pci_dev_to_bus(struct pci_dev *pdev); + +/* b43_pci_bridge.c */ +#ifdef CONFIG_SSB_PCIHOST +extern int __init b43_pci_ssb_bridge_init(void); +extern void __exit b43_pci_ssb_bridge_exit(void); +#else /* CONFIG_SSB_PCIHOST */ +static inline int b43_pci_ssb_bridge_init(void) +{ + return 0; +} +static inline void b43_pci_ssb_bridge_exit(void) +{ +} +#endif /* CONFIG_SSB_PCIHOST */ + +#endif /* LINUX_SSB_PRIVATE_H_ */ diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index 4dc5fa8be78..0c522e6b091 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -340,4 +340,19 @@ struct parisc_device_id { #define PA_HVERSION_ANY_ID 0xffff #define PA_SVERSION_ANY_ID 0xffffffff +/* SSB core, see drivers/ssb/ */ +struct ssb_device_id { + __u16 vendor; + __u16 coreid; + __u8 revision; +}; +#define SSB_DEVICE(_vendor, _coreid, _revision) \ + { .vendor = _vendor, .coreid = _coreid, .revision = _revision, } +#define SSB_DEVTABLE_END \ + { 0, }, + +#define SSB_ANY_VENDOR 0xFFFF +#define SSB_ANY_ID 0xFFFF +#define SSB_ANY_REV 0xFF + #endif /* LINUX_MOD_DEVICETABLE_H */ diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h new file mode 100644 index 00000000000..2b5c312c496 --- /dev/null +++ b/include/linux/ssb/ssb.h @@ -0,0 +1,424 @@ +#ifndef LINUX_SSB_H_ +#define LINUX_SSB_H_ + +#include +#include +#include +#include +#include +#include + +#include + + +struct pcmcia_device; +struct ssb_bus; +struct ssb_driver; + + +struct ssb_sprom_r1 { + u16 pci_spid; /* Subsystem Product ID for PCI */ + u16 pci_svid; /* Subsystem Vendor ID for PCI */ + u16 pci_pid; /* Product ID for PCI */ + u8 il0mac[6]; /* MAC address for 802.11b/g */ + u8 et0mac[6]; /* MAC address for Ethernet */ + u8 et1mac[6]; /* MAC address for 802.11a */ + u8 et0phyaddr:5; /* MII address for enet0 */ + u8 et1phyaddr:5; /* MII address for enet1 */ + u8 et0mdcport:1; /* MDIO for enet0 */ + u8 et1mdcport:1; /* MDIO for enet1 */ + u8 board_rev; /* Board revision */ + u8 country_code:4; /* Country Code */ + u8 antenna_a:2; /* Antenna 0/1 available for A-PHY */ + u8 antenna_bg:2; /* Antenna 0/1 available for B-PHY and G-PHY */ + u16 pa0b0; + u16 pa0b1; + u16 pa0b2; + u16 pa1b0; + u16 pa1b1; + u16 pa1b2; + u8 gpio0; /* GPIO pin 0 */ + u8 gpio1; /* GPIO pin 1 */ + u8 gpio2; /* GPIO pin 2 */ + u8 gpio3; /* GPIO pin 3 */ + u16 maxpwr_a; /* A-PHY Power Amplifier Max Power (in dBm Q5.2) */ + u16 maxpwr_bg; /* B/G-PHY Power Amplifier Max Power (in dBm Q5.2) */ + u8 itssi_a; /* Idle TSSI Target for A-PHY */ + u8 itssi_bg; /* Idle TSSI Target for B/G-PHY */ + u16 boardflags_lo; /* Boardflags (low 16 bits) */ + u8 antenna_gain_a; /* A-PHY Antenna gain (in dBm Q5.2) */ + u8 antenna_gain_bg; /* B/G-PHY Antenna gain (in dBm Q5.2) */ + u8 oem[8]; /* OEM string (rev 1 only) */ +}; + +struct ssb_sprom_r2 { + u16 boardflags_hi; /* Boardflags (high 16 bits) */ + u8 maxpwr_a_lo; /* A-PHY Max Power Low */ + u8 maxpwr_a_hi; /* A-PHY Max Power High */ + u16 pa1lob0; /* A-PHY PA Low Settings */ + u16 pa1lob1; /* A-PHY PA Low Settings */ + u16 pa1lob2; /* A-PHY PA Low Settings */ + u16 pa1hib0; /* A-PHY PA High Settings */ + u16 pa1hib1; /* A-PHY PA High Settings */ + u16 pa1hib2; /* A-PHY PA High Settings */ + u8 ofdm_pwr_off; /* OFDM Power Offset from CCK Level */ + u8 country_str[2]; /* Two char Country Code */ +}; + +struct ssb_sprom_r3 { + u32 ofdmapo; /* A-PHY OFDM Mid Power Offset */ + u32 ofdmalpo; /* A-PHY OFDM Low Power Offset */ + u32 ofdmahpo; /* A-PHY OFDM High Power Offset */ + u8 gpioldc_on_cnt; /* GPIO LED Powersave Duty Cycle ON count */ + u8 gpioldc_off_cnt; /* GPIO LED Powersave Duty Cycle OFF count */ + u8 cckpo_1M:4; /* CCK Power Offset for Rate 1M */ + u8 cckpo_2M:4; /* CCK Power Offset for Rate 2M */ + u8 cckpo_55M:4; /* CCK Power Offset for Rate 5.5M */ + u8 cckpo_11M:4; /* CCK Power Offset for Rate 11M */ + u32 ofdmgpo; /* G-PHY OFDM Power Offset */ +}; + +struct ssb_sprom_r4 { + /* TODO */ +}; + +struct ssb_sprom { + u8 revision; + u8 crc; + /* The valid r# fields are selected by the "revision". + * Revision 3 and lower inherit from lower revisions. + */ + union { + struct { + struct ssb_sprom_r1 r1; + struct ssb_sprom_r2 r2; + struct ssb_sprom_r3 r3; + }; + struct ssb_sprom_r4 r4; + }; +}; + +/* Information about the PCB the circuitry is soldered on. */ +struct ssb_boardinfo { + u16 vendor; + u16 type; + u16 rev; +}; + + +struct ssb_device; +/* Lowlevel read/write operations on the device MMIO. + * Internal, don't use that outside of ssb. */ +struct ssb_bus_ops { + u16 (*read16)(struct ssb_device *dev, u16 offset); + u32 (*read32)(struct ssb_device *dev, u16 offset); + void (*write16)(struct ssb_device *dev, u16 offset, u16 value); + void (*write32)(struct ssb_device *dev, u16 offset, u32 value); +}; + + +/* Core-ID values. */ +#define SSB_DEV_CHIPCOMMON 0x800 +#define SSB_DEV_ILINE20 0x801 +#define SSB_DEV_SDRAM 0x803 +#define SSB_DEV_PCI 0x804 +#define SSB_DEV_MIPS 0x805 +#define SSB_DEV_ETHERNET 0x806 +#define SSB_DEV_V90 0x807 +#define SSB_DEV_USB11_HOSTDEV 0x808 +#define SSB_DEV_ADSL 0x809 +#define SSB_DEV_ILINE100 0x80A +#define SSB_DEV_IPSEC 0x80B +#define SSB_DEV_PCMCIA 0x80D +#define SSB_DEV_INTERNAL_MEM 0x80E +#define SSB_DEV_MEMC_SDRAM 0x80F +#define SSB_DEV_EXTIF 0x811 +#define SSB_DEV_80211 0x812 +#define SSB_DEV_MIPS_3302 0x816 +#define SSB_DEV_USB11_HOST 0x817 +#define SSB_DEV_USB11_DEV 0x818 +#define SSB_DEV_USB20_HOST 0x819 +#define SSB_DEV_USB20_DEV 0x81A +#define SSB_DEV_SDIO_HOST 0x81B +#define SSB_DEV_ROBOSWITCH 0x81C +#define SSB_DEV_PARA_ATA 0x81D +#define SSB_DEV_SATA_XORDMA 0x81E +#define SSB_DEV_ETHERNET_GBIT 0x81F +#define SSB_DEV_PCIE 0x820 +#define SSB_DEV_MIMO_PHY 0x821 +#define SSB_DEV_SRAM_CTRLR 0x822 +#define SSB_DEV_MINI_MACPHY 0x823 +#define SSB_DEV_ARM_1176 0x824 +#define SSB_DEV_ARM_7TDMI 0x825 + +/* Vendor-ID values */ +#define SSB_VENDOR_BROADCOM 0x4243 + +/* Some kernel subsystems poke with dev->drvdata, so we must use the + * following ugly workaround to get from struct device to struct ssb_device */ +struct __ssb_dev_wrapper { + struct device dev; + struct ssb_device *sdev; +}; + +struct ssb_device { + /* Having a copy of the ops pointer in each dev struct + * is an optimization. */ + const struct ssb_bus_ops *ops; + + struct device *dev; + struct ssb_bus *bus; + struct ssb_device_id id; + + u8 core_index; + unsigned int irq; + + /* Internal-only stuff follows. */ + void *drvdata; /* Per-device data */ + void *devtypedata; /* Per-devicetype (eg 802.11) data */ +}; + +/* Go from struct device to struct ssb_device. */ +static inline +struct ssb_device * dev_to_ssb_dev(struct device *dev) +{ + struct __ssb_dev_wrapper *wrap; + wrap = container_of(dev, struct __ssb_dev_wrapper, dev); + return wrap->sdev; +} + +/* Device specific user data */ +static inline +void ssb_set_drvdata(struct ssb_device *dev, void *data) +{ + dev->drvdata = data; +} +static inline +void * ssb_get_drvdata(struct ssb_device *dev) +{ + return dev->drvdata; +} + +/* Devicetype specific user data. This is per device-type (not per device) */ +void ssb_set_devtypedata(struct ssb_device *dev, void *data); +static inline +void * ssb_get_devtypedata(struct ssb_device *dev) +{ + return dev->devtypedata; +} + + +struct ssb_driver { + const char *name; + const struct ssb_device_id *id_table; + + int (*probe)(struct ssb_device *dev, const struct ssb_device_id *id); + void (*remove)(struct ssb_device *dev); + int (*suspend)(struct ssb_device *dev, pm_message_t state); + int (*resume)(struct ssb_device *dev); + void (*shutdown)(struct ssb_device *dev); + + struct device_driver drv; +}; +#define drv_to_ssb_drv(_drv) container_of(_drv, struct ssb_driver, drv) + +extern int __ssb_driver_register(struct ssb_driver *drv, struct module *owner); +static inline int ssb_driver_register(struct ssb_driver *drv) +{ + return __ssb_driver_register(drv, THIS_MODULE); +} +extern void ssb_driver_unregister(struct ssb_driver *drv); + + + + +enum ssb_bustype { + SSB_BUSTYPE_SSB, /* This SSB bus is the system bus */ + SSB_BUSTYPE_PCI, /* SSB is connected to PCI bus */ + SSB_BUSTYPE_PCMCIA, /* SSB is connected to PCMCIA bus */ +}; + +/* board_vendor */ +#define SSB_BOARDVENDOR_BCM 0x14E4 /* Broadcom */ +#define SSB_BOARDVENDOR_DELL 0x1028 /* Dell */ +#define SSB_BOARDVENDOR_HP 0x0E11 /* HP */ +/* board_type */ +#define SSB_BOARD_BCM94306MP 0x0418 +#define SSB_BOARD_BCM4309G 0x0421 +#define SSB_BOARD_BCM4306CB 0x0417 +#define SSB_BOARD_BCM4309MP 0x040C +#define SSB_BOARD_MP4318 0x044A +#define SSB_BOARD_BU4306 0x0416 +#define SSB_BOARD_BU4309 0x040A +/* chip_package */ +#define SSB_CHIPPACK_BCM4712S 1 /* Small 200pin 4712 */ +#define SSB_CHIPPACK_BCM4712M 2 /* Medium 225pin 4712 */ +#define SSB_CHIPPACK_BCM4712L 0 /* Large 340pin 4712 */ + +#include +#include +#include +#include + +struct ssb_bus { + /* The MMIO area. */ + void __iomem *mmio; + + const struct ssb_bus_ops *ops; + + /* The core in the basic address register window. (PCI bus only) */ + struct ssb_device *mapped_device; + /* Currently mapped PCMCIA segment. (bustype == SSB_BUSTYPE_PCMCIA only) */ + u8 mapped_pcmcia_seg; + /* Lock for core and segment switching. */ + spinlock_t bar_lock; + + /* The bus this backplane is running on. */ + enum ssb_bustype bustype; + /* Pointer to the PCI bus (only valid if bustype == SSB_BUSTYPE_PCI). */ + struct pci_dev *host_pci; + /* Pointer to the PCMCIA device (only if bustype == SSB_BUSTYPE_PCMCIA). */ + struct pcmcia_device *host_pcmcia; + +#ifdef CONFIG_SSB_PCIHOST + /* Mutex to protect the SPROM writing. */ + struct mutex pci_sprom_mutex; +#endif + + /* ID information about the Chip. */ + u16 chip_id; + u16 chip_rev; + u8 chip_package; + + /* List of devices (cores) on the backplane. */ + struct ssb_device devices[SSB_MAX_NR_CORES]; + u8 nr_devices; + + /* Reference count. Number of suspended devices. */ + u8 suspend_cnt; + + /* Software ID number for this bus. */ + unsigned int busnumber; + + /* The ChipCommon device (if available). */ + struct ssb_chipcommon chipco; + /* The PCI-core device (if available). */ + struct ssb_pcicore pcicore; + /* The MIPS-core device (if available). */ + struct ssb_mipscore mipscore; + /* The EXTif-core device (if available). */ + struct ssb_extif extif; + + /* The following structure elements are not available in early + * SSB initialization. Though, they are available for regular + * registered drivers at any stage. So be careful when + * using them in the ssb core code. */ + + /* ID information about the PCB. */ + struct ssb_boardinfo boardinfo; + /* Contents of the SPROM. */ + struct ssb_sprom sprom; + + /* Internal-only stuff follows. Do not touch. */ + struct list_head list; +#ifdef CONFIG_SSB_DEBUG + /* Is the bus already powered up? */ + bool powered_up; + int power_warn_count; +#endif /* DEBUG */ +}; + +/* The initialization-invariants. */ +struct ssb_init_invariants { + struct ssb_boardinfo boardinfo; + struct ssb_sprom sprom; +}; +/* Type of function to fetch the invariants. */ +typedef int (*ssb_invariants_func_t)(struct ssb_bus *bus, + struct ssb_init_invariants *iv); + +/* Register a SSB system bus. get_invariants() is called after the + * basic system devices are initialized. + * The invariants are usually fetched from some NVRAM. + * Put the invariants into the struct pointed to by iv. */ +extern int ssb_bus_ssbbus_register(struct ssb_bus *bus, + unsigned long baseaddr, + ssb_invariants_func_t get_invariants); +#ifdef CONFIG_SSB_PCIHOST +extern int ssb_bus_pcibus_register(struct ssb_bus *bus, + struct pci_dev *host_pci); +#endif /* CONFIG_SSB_PCIHOST */ +#ifdef CONFIG_SSB_PCMCIAHOST +extern int ssb_bus_pcmciabus_register(struct ssb_bus *bus, + struct pcmcia_device *pcmcia_dev, + unsigned long baseaddr); +#endif /* CONFIG_SSB_PCMCIAHOST */ + +extern void ssb_bus_unregister(struct ssb_bus *bus); + +extern u32 ssb_clockspeed(struct ssb_bus *bus); + +/* Is the device enabled in hardware? */ +int ssb_device_is_enabled(struct ssb_device *dev); +/* Enable a device and pass device-specific SSB_TMSLOW flags. + * If no device-specific flags are available, use 0. */ +void ssb_device_enable(struct ssb_device *dev, u32 core_specific_flags); +/* Disable a device in hardware and pass SSB_TMSLOW flags (if any). */ +void ssb_device_disable(struct ssb_device *dev, u32 core_specific_flags); + + +/* Device MMIO register read/write functions. */ +static inline u16 ssb_read16(struct ssb_device *dev, u16 offset) +{ + return dev->ops->read16(dev, offset); +} +static inline u32 ssb_read32(struct ssb_device *dev, u16 offset) +{ + return dev->ops->read32(dev, offset); +} +static inline void ssb_write16(struct ssb_device *dev, u16 offset, u16 value) +{ + dev->ops->write16(dev, offset, value); +} +static inline void ssb_write32(struct ssb_device *dev, u16 offset, u32 value) +{ + dev->ops->write32(dev, offset, value); +} + + +/* Translation (routing) bits that need to be ORed to DMA + * addresses before they are given to a device. */ +extern u32 ssb_dma_translation(struct ssb_device *dev); +#define SSB_DMA_TRANSLATION_MASK 0xC0000000 +#define SSB_DMA_TRANSLATION_SHIFT 30 + +extern int ssb_dma_set_mask(struct ssb_device *ssb_dev, u64 mask); + + +#ifdef CONFIG_SSB_PCIHOST +/* PCI-host wrapper driver */ +extern int ssb_pcihost_register(struct pci_driver *driver); +static inline void ssb_pcihost_unregister(struct pci_driver *driver) +{ + pci_unregister_driver(driver); +} +#endif /* CONFIG_SSB_PCIHOST */ + + +/* If a driver is shutdown or suspended, call this to signal + * that the bus may be completely powered down. SSB will decide, + * if it's really time to power down the bus, based on if there + * are other devices that want to run. */ +extern int ssb_bus_may_powerdown(struct ssb_bus *bus); +/* Before initializing and enabling a device, call this to power-up the bus. + * If you want to allow use of dynamic-power-control, pass the flag. + * Otherwise static always-on powercontrol will be used. */ +extern int ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl); + + +/* Various helper functions */ +extern u32 ssb_admatch_base(u32 adm); +extern u32 ssb_admatch_size(u32 adm); + + +#endif /* LINUX_SSB_H_ */ diff --git a/include/linux/ssb/ssb_driver_chipcommon.h b/include/linux/ssb/ssb_driver_chipcommon.h new file mode 100644 index 00000000000..4cb99549466 --- /dev/null +++ b/include/linux/ssb/ssb_driver_chipcommon.h @@ -0,0 +1,396 @@ +#ifndef LINUX_SSB_CHIPCO_H_ +#define LINUX_SSB_CHIPCO_H_ + +/* SonicsSiliconBackplane CHIPCOMMON core hardware definitions + * + * The chipcommon core provides chip identification, SB control, + * jtag, 0/1/2 uarts, clock frequency control, a watchdog interrupt timer, + * gpio interface, extbus, and support for serial and parallel flashes. + * + * Copyright 2005, Broadcom Corporation + * Copyright 2006, Michael Buesch + * + * Licensed under the GPL version 2. See COPYING for details. + */ + +/** ChipCommon core registers. **/ + +#define SSB_CHIPCO_CHIPID 0x0000 +#define SSB_CHIPCO_IDMASK 0x0000FFFF +#define SSB_CHIPCO_REVMASK 0x000F0000 +#define SSB_CHIPCO_REVSHIFT 16 +#define SSB_CHIPCO_PACKMASK 0x00F00000 +#define SSB_CHIPCO_PACKSHIFT 20 +#define SSB_CHIPCO_NRCORESMASK 0x0F000000 +#define SSB_CHIPCO_NRCORESSHIFT 24 +#define SSB_CHIPCO_CAP 0x0004 /* Capabilities */ +#define SSB_CHIPCO_CAP_NRUART 0x00000003 /* # of UARTs */ +#define SSB_CHIPCO_CAP_MIPSEB 0x00000004 /* MIPS in BigEndian Mode */ +#define SSB_CHIPCO_CAP_UARTCLK 0x00000018 /* UART clock select */ +#define SSB_CHIPCO_CAP_UARTCLK_INT 0x00000008 /* UARTs are driven by internal divided clock */ +#define SSB_CHIPCO_CAP_UARTGPIO 0x00000020 /* UARTs on GPIO 15-12 */ +#define SSB_CHIPCO_CAP_EXTBUS 0x000000C0 /* External buses present */ +#define SSB_CHIPCO_CAP_FLASHT 0x00000700 /* Flash Type */ +#define SSB_CHIPCO_FLASHT_NONE 0x00000000 /* No flash */ +#define SSB_CHIPCO_FLASHT_STSER 0x00000100 /* ST serial flash */ +#define SSB_CHIPCO_FLASHT_ATSER 0x00000200 /* Atmel serial flash */ +#define SSB_CHIPCO_FLASHT_PARA 0x00000700 /* Parallel flash */ +#define SSB_CHIPCO_CAP_PLLT 0x00038000 /* PLL Type */ +#define SSB_PLLTYPE_NONE 0x00000000 +#define SSB_PLLTYPE_1 0x00010000 /* 48Mhz base, 3 dividers */ +#define SSB_PLLTYPE_2 0x00020000 /* 48Mhz, 4 dividers */ +#define SSB_PLLTYPE_3 0x00030000 /* 25Mhz, 2 dividers */ +#define SSB_PLLTYPE_4 0x00008000 /* 48Mhz, 4 dividers */ +#define SSB_PLLTYPE_5 0x00018000 /* 25Mhz, 4 dividers */ +#define SSB_PLLTYPE_6 0x00028000 /* 100/200 or 120/240 only */ +#define SSB_PLLTYPE_7 0x00038000 /* 25Mhz, 4 dividers */ +#define SSB_CHIPCO_CAP_PCTL 0x00040000 /* Power Control */ +#define SSB_CHIPCO_CAP_OTPS 0x00380000 /* OTP size */ +#define SSB_CHIPCO_CAP_OTPS_SHIFT 19 +#define SSB_CHIPCO_CAP_OTPS_BASE 5 +#define SSB_CHIPCO_CAP_JTAGM 0x00400000 /* JTAG master present */ +#define SSB_CHIPCO_CAP_BROM 0x00800000 /* Internal boot ROM active */ +#define SSB_CHIPCO_CAP_64BIT 0x08000000 /* 64-bit Backplane */ +#define SSB_CHIPCO_CORECTL 0x0008 +#define SSB_CHIPCO_CORECTL_UARTCLK0 0x00000001 /* Drive UART with internal clock */ +#define SSB_CHIPCO_CORECTL_SE 0x00000002 /* sync clk out enable (corerev >= 3) */ +#define SSB_CHIPCO_BIST 0x000C +#define SSB_CHIPCO_OTPS 0x0010 /* OTP status */ +#define SSB_CHIPCO_OTPS_PROGFAIL 0x80000000 +#define SSB_CHIPCO_OTPS_PROTECT 0x00000007 +#define SSB_CHIPCO_OTPS_HW_PROTECT 0x00000001 +#define SSB_CHIPCO_OTPS_SW_PROTECT 0x00000002 +#define SSB_CHIPCO_OTPS_CID_PROTECT 0x00000004 +#define SSB_CHIPCO_OTPC 0x0014 /* OTP control */ +#define SSB_CHIPCO_OTPC_RECWAIT 0xFF000000 +#define SSB_CHIPCO_OTPC_PROGWAIT 0x00FFFF00 +#define SSB_CHIPCO_OTPC_PRW_SHIFT 8 +#define SSB_CHIPCO_OTPC_MAXFAIL 0x00000038 +#define SSB_CHIPCO_OTPC_VSEL 0x00000006 +#define SSB_CHIPCO_OTPC_SELVL 0x00000001 +#define SSB_CHIPCO_OTPP 0x0018 /* OTP prog */ +#define SSB_CHIPCO_OTPP_COL 0x000000FF +#define SSB_CHIPCO_OTPP_ROW 0x0000FF00 +#define SSB_CHIPCO_OTPP_ROW_SHIFT 8 +#define SSB_CHIPCO_OTPP_READERR 0x10000000 +#define SSB_CHIPCO_OTPP_VALUE 0x20000000 +#define SSB_CHIPCO_OTPP_READ 0x40000000 +#define SSB_CHIPCO_OTPP_START 0x80000000 +#define SSB_CHIPCO_OTPP_BUSY 0x80000000 +#define SSB_CHIPCO_IRQSTAT 0x0020 +#define SSB_CHIPCO_IRQMASK 0x0024 +#define SSB_CHIPCO_IRQ_GPIO 0x00000001 /* gpio intr */ +#define SSB_CHIPCO_IRQ_EXT 0x00000002 /* ro: ext intr pin (corerev >= 3) */ +#define SSB_CHIPCO_IRQ_WDRESET 0x80000000 /* watchdog reset occurred */ +#define SSB_CHIPCO_CHIPCTL 0x0028 /* Rev >= 11 only */ +#define SSB_CHIPCO_CHIPSTAT 0x002C /* Rev >= 11 only */ +#define SSB_CHIPCO_JCMD 0x0030 /* Rev >= 10 only */ +#define SSB_CHIPCO_JCMD_START 0x80000000 +#define SSB_CHIPCO_JCMD_BUSY 0x80000000 +#define SSB_CHIPCO_JCMD_PAUSE 0x40000000 +#define SSB_CHIPCO_JCMD0_ACC_MASK 0x0000F000 +#define SSB_CHIPCO_JCMD0_ACC_IRDR 0x00000000 +#define SSB_CHIPCO_JCMD0_ACC_DR 0x00001000 +#define SSB_CHIPCO_JCMD0_ACC_IR 0x00002000 +#define SSB_CHIPCO_JCMD0_ACC_RESET 0x00003000 +#define SSB_CHIPCO_JCMD0_ACC_IRPDR 0x00004000 +#define SSB_CHIPCO_JCMD0_ACC_PDR 0x00005000 +#define SSB_CHIPCO_JCMD0_IRW_MASK 0x00000F00 +#define SSB_CHIPCO_JCMD_ACC_MASK 0x000F0000 /* Changes for corerev 11 */ +#define SSB_CHIPCO_JCMD_ACC_IRDR 0x00000000 +#define SSB_CHIPCO_JCMD_ACC_DR 0x00010000 +#define SSB_CHIPCO_JCMD_ACC_IR 0x00020000 +#define SSB_CHIPCO_JCMD_ACC_RESET 0x00030000 +#define SSB_CHIPCO_JCMD_ACC_IRPDR 0x00040000 +#define SSB_CHIPCO_JCMD_ACC_PDR 0x00050000 +#define SSB_CHIPCO_JCMD_IRW_MASK 0x00001F00 +#define SSB_CHIPCO_JCMD_IRW_SHIFT 8 +#define SSB_CHIPCO_JCMD_DRW_MASK 0x0000003F +#define SSB_CHIPCO_JIR 0x0034 /* Rev >= 10 only */ +#define SSB_CHIPCO_JDR 0x0038 /* Rev >= 10 only */ +#define SSB_CHIPCO_JCTL 0x003C /* Rev >= 10 only */ +#define SSB_CHIPCO_JCTL_FORCE_CLK 4 /* Force clock */ +#define SSB_CHIPCO_JCTL_EXT_EN 2 /* Enable external targets */ +#define SSB_CHIPCO_JCTL_EN 1 /* Enable Jtag master */ +#define SSB_CHIPCO_FLASHCTL 0x0040 +#define SSB_CHIPCO_FLASHCTL_START 0x80000000 +#define SSB_CHIPCO_FLASHCTL_BUSY SSB_CHIPCO_FLASHCTL_START +#define SSB_CHIPCO_FLASHADDR 0x0044 +#define SSB_CHIPCO_FLASHDATA 0x0048 +#define SSB_CHIPCO_BCAST_ADDR 0x0050 +#define SSB_CHIPCO_BCAST_DATA 0x0054 +#define SSB_CHIPCO_GPIOIN 0x0060 +#define SSB_CHIPCO_GPIOOUT 0x0064 +#define SSB_CHIPCO_GPIOOUTEN 0x0068 +#define SSB_CHIPCO_GPIOCTL 0x006C +#define SSB_CHIPCO_GPIOPOL 0x0070 +#define SSB_CHIPCO_GPIOIRQ 0x0074 +#define SSB_CHIPCO_WATCHDOG 0x0080 +#define SSB_CHIPCO_GPIOTIMER 0x0088 /* LED powersave (corerev >= 16) */ +#define SSB_CHIPCO_GPIOTIMER_ONTIME_SHIFT 16 +#define SSB_CHIPCO_GPIOTOUTM 0x008C /* LED powersave (corerev >= 16) */ +#define SSB_CHIPCO_CLOCK_N 0x0090 +#define SSB_CHIPCO_CLOCK_SB 0x0094 +#define SSB_CHIPCO_CLOCK_PCI 0x0098 +#define SSB_CHIPCO_CLOCK_M2 0x009C +#define SSB_CHIPCO_CLOCK_MIPS 0x00A0 +#define SSB_CHIPCO_CLKDIV 0x00A4 /* Rev >= 3 only */ +#define SSB_CHIPCO_CLKDIV_SFLASH 0x0F000000 +#define SSB_CHIPCO_CLKDIV_SFLASH_SHIFT 24 +#define SSB_CHIPCO_CLKDIV_OTP 0x000F0000 +#define SSB_CHIPCO_CLKDIV_OTP_SHIFT 16 +#define SSB_CHIPCO_CLKDIV_JTAG 0x00000F00 +#define SSB_CHIPCO_CLKDIV_JTAG_SHIFT 8 +#define SSB_CHIPCO_CLKDIV_UART 0x000000FF +#define SSB_CHIPCO_PLLONDELAY 0x00B0 /* Rev >= 4 only */ +#define SSB_CHIPCO_FREFSELDELAY 0x00B4 /* Rev >= 4 only */ +#define SSB_CHIPCO_SLOWCLKCTL 0x00B8 /* 6 <= Rev <= 9 only */ +#define SSB_CHIPCO_SLOWCLKCTL_SRC 0x00000007 /* slow clock source mask */ +#define SSB_CHIPCO_SLOWCLKCTL_SRC_LPO 0x00000000 /* source of slow clock is LPO */ +#define SSB_CHIPCO_SLOWCLKCTL_SRC_XTAL 0x00000001 /* source of slow clock is crystal */ +#define SSB_CHIPCO_SLOECLKCTL_SRC_PCI 0x00000002 /* source of slow clock is PCI */ +#define SSB_CHIPCO_SLOWCLKCTL_LPOFREQ 0x00000200 /* LPOFreqSel, 1: 160Khz, 0: 32KHz */ +#define SSB_CHIPCO_SLOWCLKCTL_LPOPD 0x00000400 /* LPOPowerDown, 1: LPO is disabled, 0: LPO is enabled */ +#define SSB_CHIPCO_SLOWCLKCTL_FSLOW 0x00000800 /* ForceSlowClk, 1: sb/cores running on slow clock, 0: power logic control */ +#define SSB_CHIPCO_SLOWCLKCTL_IPLL 0x00001000 /* IgnorePllOffReq, 1/0: power logic ignores/honors PLL clock disable requests from core */ +#define SSB_CHIPCO_SLOWCLKCTL_ENXTAL 0x00002000 /* XtalControlEn, 1/0: power logic does/doesn't disable crystal when appropriate */ +#define SSB_CHIPCO_SLOWCLKCTL_XTALPU 0x00004000 /* XtalPU (RO), 1/0: crystal running/disabled */ +#define SSB_CHIPCO_SLOWCLKCTL_CLKDIV 0xFFFF0000 /* ClockDivider (SlowClk = 1/(4+divisor)) */ +#define SSB_CHIPCO_SLOWCLKCTL_CLKDIV_SHIFT 16 +#define SSB_CHIPCO_SYSCLKCTL 0x00C0 /* Rev >= 3 only */ +#define SSB_CHIPCO_SYSCLKCTL_IDLPEN 0x00000001 /* ILPen: Enable Idle Low Power */ +#define SSB_CHIPCO_SYSCLKCTL_ALPEN 0x00000002 /* ALPen: Enable Active Low Power */ +#define SSB_CHIPCO_SYSCLKCTL_PLLEN 0x00000004 /* ForcePLLOn */ +#define SSB_CHIPCO_SYSCLKCTL_FORCEALP 0x00000008 /* Force ALP (or HT if ALPen is not set */ +#define SSB_CHIPCO_SYSCLKCTL_FORCEHT 0x00000010 /* Force HT */ +#define SSB_CHIPCO_SYSCLKCTL_CLKDIV 0xFFFF0000 /* ClkDiv (ILP = 1/(4+divisor)) */ +#define SSB_CHIPCO_SYSCLKCTL_CLKDIV_SHIFT 16 +#define SSB_CHIPCO_CLKSTSTR 0x00C4 /* Rev >= 3 only */ +#define SSB_CHIPCO_PCMCIA_CFG 0x0100 +#define SSB_CHIPCO_PCMCIA_MEMWAIT 0x0104 +#define SSB_CHIPCO_PCMCIA_ATTRWAIT 0x0108 +#define SSB_CHIPCO_PCMCIA_IOWAIT 0x010C +#define SSB_CHIPCO_IDE_CFG 0x0110 +#define SSB_CHIPCO_IDE_MEMWAIT 0x0114 +#define SSB_CHIPCO_IDE_ATTRWAIT 0x0118 +#define SSB_CHIPCO_IDE_IOWAIT 0x011C +#define SSB_CHIPCO_PROG_CFG 0x0120 +#define SSB_CHIPCO_PROG_WAITCNT 0x0124 +#define SSB_CHIPCO_FLASH_CFG 0x0128 +#define SSB_CHIPCO_FLASH_WAITCNT 0x012C +#define SSB_CHIPCO_UART0_DATA 0x0300 +#define SSB_CHIPCO_UART0_IMR 0x0304 +#define SSB_CHIPCO_UART0_FCR 0x0308 +#define SSB_CHIPCO_UART0_LCR 0x030C +#define SSB_CHIPCO_UART0_MCR 0x0310 +#define SSB_CHIPCO_UART0_LSR 0x0314 +#define SSB_CHIPCO_UART0_MSR 0x0318 +#define SSB_CHIPCO_UART0_SCRATCH 0x031C +#define SSB_CHIPCO_UART1_DATA 0x0400 +#define SSB_CHIPCO_UART1_IMR 0x0404 +#define SSB_CHIPCO_UART1_FCR 0x0408 +#define SSB_CHIPCO_UART1_LCR 0x040C +#define SSB_CHIPCO_UART1_MCR 0x0410 +#define SSB_CHIPCO_UART1_LSR 0x0414 +#define SSB_CHIPCO_UART1_MSR 0x0418 +#define SSB_CHIPCO_UART1_SCRATCH 0x041C + + + +/** Clockcontrol masks and values **/ + +/* SSB_CHIPCO_CLOCK_N */ +#define SSB_CHIPCO_CLK_N1 0x0000003F /* n1 control */ +#define SSB_CHIPCO_CLK_N2 0x00003F00 /* n2 control */ +#define SSB_CHIPCO_CLK_N2_SHIFT 8 +#define SSB_CHIPCO_CLK_PLLC 0x000F0000 /* pll control */ +#define SSB_CHIPCO_CLK_PLLC_SHIFT 16 + +/* SSB_CHIPCO_CLOCK_SB/PCI/UART */ +#define SSB_CHIPCO_CLK_M1 0x0000003F /* m1 control */ +#define SSB_CHIPCO_CLK_M2 0x00003F00 /* m2 control */ +#define SSB_CHIPCO_CLK_M2_SHIFT 8 +#define SSB_CHIPCO_CLK_M3 0x003F0000 /* m3 control */ +#define SSB_CHIPCO_CLK_M3_SHIFT 16 +#define SSB_CHIPCO_CLK_MC 0x1F000000 /* mux control */ +#define SSB_CHIPCO_CLK_MC_SHIFT 24 + +/* N3M Clock control magic field values */ +#define SSB_CHIPCO_CLK_F6_2 0x02 /* A factor of 2 in */ +#define SSB_CHIPCO_CLK_F6_3 0x03 /* 6-bit fields like */ +#define SSB_CHIPCO_CLK_F6_4 0x05 /* N1, M1 or M3 */ +#define SSB_CHIPCO_CLK_F6_5 0x09 +#define SSB_CHIPCO_CLK_F6_6 0x11 +#define SSB_CHIPCO_CLK_F6_7 0x21 + +#define SSB_CHIPCO_CLK_F5_BIAS 5 /* 5-bit fields get this added */ + +#define SSB_CHIPCO_CLK_MC_BYPASS 0x08 +#define SSB_CHIPCO_CLK_MC_M1 0x04 +#define SSB_CHIPCO_CLK_MC_M1M2 0x02 +#define SSB_CHIPCO_CLK_MC_M1M2M3 0x01 +#define SSB_CHIPCO_CLK_MC_M1M3 0x11 + +/* Type 2 Clock control magic field values */ +#define SSB_CHIPCO_CLK_T2_BIAS 2 /* n1, n2, m1 & m3 bias */ +#define SSB_CHIPCO_CLK_T2M2_BIAS 3 /* m2 bias */ + +#define SSB_CHIPCO_CLK_T2MC_M1BYP 1 +#define SSB_CHIPCO_CLK_T2MC_M2BYP 2 +#define SSB_CHIPCO_CLK_T2MC_M3BYP 4 + +/* Type 6 Clock control magic field values */ +#define SSB_CHIPCO_CLK_T6_MMASK 1 /* bits of interest in m */ +#define SSB_CHIPCO_CLK_T6_M0 120000000 /* sb clock for m = 0 */ +#define SSB_CHIPCO_CLK_T6_M1 100000000 /* sb clock for m = 1 */ +#define SSB_CHIPCO_CLK_SB2MIPS_T6(sb) (2 * (sb)) + +/* Common clock base */ +#define SSB_CHIPCO_CLK_BASE1 24000000 /* Half the clock freq */ +#define SSB_CHIPCO_CLK_BASE2 12500000 /* Alternate crystal on some PLL's */ + +/* Clock control values for 200Mhz in 5350 */ +#define SSB_CHIPCO_CLK_5350_N 0x0311 +#define SSB_CHIPCO_CLK_5350_M 0x04020009 + + +/** Bits in the config registers **/ + +#define SSB_CHIPCO_CFG_EN 0x0001 /* Enable */ +#define SSB_CHIPCO_CFG_EXTM 0x000E /* Extif Mode */ +#define SSB_CHIPCO_CFG_EXTM_ASYNC 0x0002 /* Async/Parallel flash */ +#define SSB_CHIPCO_CFG_EXTM_SYNC 0x0004 /* Synchronous */ +#define SSB_CHIPCO_CFG_EXTM_PCMCIA 0x0008 /* PCMCIA */ +#define SSB_CHIPCO_CFG_EXTM_IDE 0x000A /* IDE */ +#define SSB_CHIPCO_CFG_DS16 0x0010 /* Data size, 0=8bit, 1=16bit */ +#define SSB_CHIPCO_CFG_CLKDIV 0x0060 /* Sync: Clock divisor */ +#define SSB_CHIPCO_CFG_CLKEN 0x0080 /* Sync: Clock enable */ +#define SSB_CHIPCO_CFG_BSTRO 0x0100 /* Sync: Size/Bytestrobe */ + + +/** Flash-specific control/status values */ + +/* flashcontrol opcodes for ST flashes */ +#define SSB_CHIPCO_FLASHCTL_ST_WREN 0x0006 /* Write Enable */ +#define SSB_CHIPCO_FLASHCTL_ST_WRDIS 0x0004 /* Write Disable */ +#define SSB_CHIPCO_FLASHCTL_ST_RDSR 0x0105 /* Read Status Register */ +#define SSB_CHIPCO_FLASHCTL_ST_WRSR 0x0101 /* Write Status Register */ +#define SSB_CHIPCO_FLASHCTL_ST_READ 0x0303 /* Read Data Bytes */ +#define SSB_CHIPCO_FLASHCTL_ST_PP 0x0302 /* Page Program */ +#define SSB_CHIPCO_FLASHCTL_ST_SE 0x02D8 /* Sector Erase */ +#define SSB_CHIPCO_FLASHCTL_ST_BE 0x00C7 /* Bulk Erase */ +#define SSB_CHIPCO_FLASHCTL_ST_DP 0x00B9 /* Deep Power-down */ +#define SSB_CHIPCO_FLASHCTL_ST_RSIG 0x03AB /* Read Electronic Signature */ + +/* Status register bits for ST flashes */ +#define SSB_CHIPCO_FLASHSTA_ST_WIP 0x01 /* Write In Progress */ +#define SSB_CHIPCO_FLASHSTA_ST_WEL 0x02 /* Write Enable Latch */ +#define SSB_CHIPCO_FLASHSTA_ST_BP 0x1C /* Block Protect */ +#define SSB_CHIPCO_FLASHSTA_ST_BP_SHIFT 2 +#define SSB_CHIPCO_FLASHSTA_ST_SRWD 0x80 /* Status Register Write Disable */ + +/* flashcontrol opcodes for Atmel flashes */ +#define SSB_CHIPCO_FLASHCTL_AT_READ 0x07E8 +#define SSB_CHIPCO_FLASHCTL_AT_PAGE_READ 0x07D2 +#define SSB_CHIPCO_FLASHCTL_AT_BUF1_READ /* FIXME */ +#define SSB_CHIPCO_FLASHCTL_AT_BUF2_READ /* FIXME */ +#define SSB_CHIPCO_FLASHCTL_AT_STATUS 0x01D7 +#define SSB_CHIPCO_FLASHCTL_AT_BUF1_WRITE 0x0384 +#define SSB_CHIPCO_FLASHCTL_AT_BUF2_WRITE 0x0387 +#define SSB_CHIPCO_FLASHCTL_AT_BUF1_ERASE_PRGM 0x0283 /* Erase program */ +#define SSB_CHIPCO_FLASHCTL_AT_BUF2_ERASE_PRGM 0x0286 /* Erase program */ +#define SSB_CHIPCO_FLASHCTL_AT_BUF1_PROGRAM 0x0288 +#define SSB_CHIPCO_FLASHCTL_AT_BUF2_PROGRAM 0x0289 +#define SSB_CHIPCO_FLASHCTL_AT_PAGE_ERASE 0x0281 +#define SSB_CHIPCO_FLASHCTL_AT_BLOCK_ERASE 0x0250 +#define SSB_CHIPCO_FLASHCTL_AT_BUF1_WRER_PRGM 0x0382 /* Write erase program */ +#define SSB_CHIPCO_FLASHCTL_AT_BUF2_WRER_PRGM 0x0385 /* Write erase program */ +#define SSB_CHIPCO_FLASHCTL_AT_BUF1_LOAD 0x0253 +#define SSB_CHIPCO_FLASHCTL_AT_BUF2_LOAD 0x0255 +#define SSB_CHIPCO_FLASHCTL_AT_BUF1_COMPARE 0x0260 +#define SSB_CHIPCO_FLASHCTL_AT_BUF2_COMPARE 0x0261 +#define SSB_CHIPCO_FLASHCTL_AT_BUF1_REPROGRAM 0x0258 +#define SSB_CHIPCO_FLASHCTL_AT_BUF2_REPROGRAM 0x0259 + +/* Status register bits for Atmel flashes */ +#define SSB_CHIPCO_FLASHSTA_AT_READY 0x80 +#define SSB_CHIPCO_FLASHSTA_AT_MISMATCH 0x40 +#define SSB_CHIPCO_FLASHSTA_AT_ID 0x38 +#define SSB_CHIPCO_FLASHSTA_AT_ID_SHIFT 3 + + +/** OTP **/ + +/* OTP regions */ +#define SSB_CHIPCO_OTP_HW_REGION SSB_CHIPCO_OTPS_HW_PROTECT +#define SSB_CHIPCO_OTP_SW_REGION SSB_CHIPCO_OTPS_SW_PROTECT +#define SSB_CHIPCO_OTP_CID_REGION SSB_CHIPCO_OTPS_CID_PROTECT + +/* OTP regions (Byte offsets from otp size) */ +#define SSB_CHIPCO_OTP_SWLIM_OFF (-8) +#define SSB_CHIPCO_OTP_CIDBASE_OFF 0 +#define SSB_CHIPCO_OTP_CIDLIM_OFF 8 + +/* Predefined OTP words (Word offset from otp size) */ +#define SSB_CHIPCO_OTP_BOUNDARY_OFF (-4) +#define SSB_CHIPCO_OTP_HWSIGN_OFF (-3) +#define SSB_CHIPCO_OTP_SWSIGN_OFF (-2) +#define SSB_CHIPCO_OTP_CIDSIGN_OFF (-1) + +#define SSB_CHIPCO_OTP_CID_OFF 0 +#define SSB_CHIPCO_OTP_PKG_OFF 1 +#define SSB_CHIPCO_OTP_FID_OFF 2 +#define SSB_CHIPCO_OTP_RSV_OFF 3 +#define SSB_CHIPCO_OTP_LIM_OFF 4 + +#define SSB_CHIPCO_OTP_SIGNATURE 0x578A +#define SSB_CHIPCO_OTP_MAGIC 0x4E56 + + +struct ssb_device; +struct ssb_serial_port; + +struct ssb_chipcommon { + struct ssb_device *dev; + u32 capabilities; + /* Fast Powerup Delay constant */ + u16 fast_pwrup_delay; +}; + +extern void ssb_chipcommon_init(struct ssb_chipcommon *cc); + +#include +extern void ssb_chipco_suspend(struct ssb_chipcommon *cc, pm_message_t state); +extern void ssb_chipco_resume(struct ssb_chipcommon *cc); + +extern void ssb_chipco_get_clockcpu(struct ssb_chipcommon *cc, + u32 *plltype, u32 *n, u32 *m); +extern void ssb_chipco_get_clockcontrol(struct ssb_chipcommon *cc, + u32 *plltype, u32 *n, u32 *m); +extern void ssb_chipco_timing_init(struct ssb_chipcommon *cc, + unsigned long ns_per_cycle); + +enum ssb_clkmode { + SSB_CLKMODE_SLOW, + SSB_CLKMODE_FAST, + SSB_CLKMODE_DYNAMIC, +}; + +extern void ssb_chipco_set_clockmode(struct ssb_chipcommon *cc, + enum ssb_clkmode mode); + +extern void ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc, + u32 ticks); + +u32 ssb_chipco_gpio_in(struct ssb_chipcommon *cc, u32 mask); + +void ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value); + +void ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value); + +#ifdef CONFIG_SSB_SERIAL +extern int ssb_chipco_serial_init(struct ssb_chipcommon *cc, + struct ssb_serial_port *ports); +#endif /* CONFIG_SSB_SERIAL */ + +#endif /* LINUX_SSB_CHIPCO_H_ */ diff --git a/include/linux/ssb/ssb_driver_extif.h b/include/linux/ssb/ssb_driver_extif.h new file mode 100644 index 00000000000..a9164357b5a --- /dev/null +++ b/include/linux/ssb/ssb_driver_extif.h @@ -0,0 +1,204 @@ +/* + * Hardware-specific External Interface I/O core definitions + * for the BCM47xx family of SiliconBackplane-based chips. + * + * The External Interface core supports a total of three external chip selects + * supporting external interfaces. One of the external chip selects is + * used for Flash, one is used for PCMCIA, and the other may be + * programmed to support either a synchronous interface or an + * asynchronous interface. The asynchronous interface can be used to + * support external devices such as UARTs and the BCM2019 Bluetooth + * baseband processor. + * The external interface core also contains 2 on-chip 16550 UARTs, clock + * frequency control, a watchdog interrupt timer, and a GPIO interface. + * + * Copyright 2005, Broadcom Corporation + * Copyright 2006, Michael Buesch + * + * Licensed under the GPL version 2. See COPYING for details. + */ +#ifndef LINUX_SSB_EXTIFCORE_H_ +#define LINUX_SSB_EXTIFCORE_H_ + +/* external interface address space */ +#define SSB_EXTIF_PCMCIA_MEMBASE(x) (x) +#define SSB_EXTIF_PCMCIA_IOBASE(x) ((x) + 0x100000) +#define SSB_EXTIF_PCMCIA_CFGBASE(x) ((x) + 0x200000) +#define SSB_EXTIF_CFGIF_BASE(x) ((x) + 0x800000) +#define SSB_EXTIF_FLASH_BASE(x) ((x) + 0xc00000) + +#define SSB_EXTIF_NR_GPIOOUT 5 +/* GPIO NOTE: + * The multiple instances of output and output enable registers + * are present to allow driver software for multiple cores to control + * gpio outputs without needing to share a single register pair. + * Use the following helper macro to get a register offset value. + */ +#define SSB_EXTIF_GPIO_OUT(index) ({ \ + BUILD_BUG_ON(index >= SSB_EXTIF_NR_GPIOOUT); \ + SSB_EXTIF_GPIO_OUT_BASE + ((index) * 8); \ + }) +#define SSB_EXTIF_GPIO_OUTEN(index) ({ \ + BUILD_BUG_ON(index >= SSB_EXTIF_NR_GPIOOUT); \ + SSB_EXTIF_GPIO_OUTEN_BASE + ((index) * 8); \ + }) + +/** EXTIF core registers **/ + +#define SSB_EXTIF_CTL 0x0000 +#define SSB_EXTIF_CTL_UARTEN (1 << 0) /* UART enable */ +#define SSB_EXTIF_EXTSTAT 0x0004 +#define SSB_EXTIF_EXTSTAT_EMODE (1 << 0) /* Endian mode (ro) */ +#define SSB_EXTIF_EXTSTAT_EIRQPIN (1 << 1) /* External interrupt pin (ro) */ +#define SSB_EXTIF_EXTSTAT_GPIOIRQPIN (1 << 2) /* GPIO interrupt pin (ro) */ +#define SSB_EXTIF_PCMCIA_CFG 0x0010 +#define SSB_EXTIF_PCMCIA_MEMWAIT 0x0014 +#define SSB_EXTIF_PCMCIA_ATTRWAIT 0x0018 +#define SSB_EXTIF_PCMCIA_IOWAIT 0x001C +#define SSB_EXTIF_PROG_CFG 0x0020 +#define SSB_EXTIF_PROG_WAITCNT 0x0024 +#define SSB_EXTIF_FLASH_CFG 0x0028 +#define SSB_EXTIF_FLASH_WAITCNT 0x002C +#define SSB_EXTIF_WATCHDOG 0x0040 +#define SSB_EXTIF_CLOCK_N 0x0044 +#define SSB_EXTIF_CLOCK_SB 0x0048 +#define SSB_EXTIF_CLOCK_PCI 0x004C +#define SSB_EXTIF_CLOCK_MII 0x0050 +#define SSB_EXTIF_GPIO_IN 0x0060 +#define SSB_EXTIF_GPIO_OUT_BASE 0x0064 +#define SSB_EXTIF_GPIO_OUTEN_BASE 0x0068 +#define SSB_EXTIF_EJTAG_OUTEN 0x0090 +#define SSB_EXTIF_GPIO_INTPOL 0x0094 +#define SSB_EXTIF_GPIO_INTMASK 0x0098 +#define SSB_EXTIF_UART_DATA 0x0300 +#define SSB_EXTIF_UART_TIMER 0x0310 +#define SSB_EXTIF_UART_FCR 0x0320 +#define SSB_EXTIF_UART_LCR 0x0330 +#define SSB_EXTIF_UART_MCR 0x0340 +#define SSB_EXTIF_UART_LSR 0x0350 +#define SSB_EXTIF_UART_MSR 0x0360 +#define SSB_EXTIF_UART_SCRATCH 0x0370 + + + + +/* pcmcia/prog/flash_config */ +#define SSB_EXTCFG_EN (1 << 0) /* enable */ +#define SSB_EXTCFG_MODE 0xE /* mode */ +#define SSB_EXTCFG_MODE_SHIFT 1 +#define SSB_EXTCFG_MODE_FLASH 0x0 /* flash/asynchronous mode */ +#define SSB_EXTCFG_MODE_SYNC 0x2 /* synchronous mode */ +#define SSB_EXTCFG_MODE_PCMCIA 0x4 /* pcmcia mode */ +#define SSB_EXTCFG_DS16 (1 << 4) /* destsize: 0=8bit, 1=16bit */ +#define SSB_EXTCFG_BSWAP (1 << 5) /* byteswap */ +#define SSB_EXTCFG_CLKDIV 0xC0 /* clock divider */ +#define SSB_EXTCFG_CLKDIV_SHIFT 6 +#define SSB_EXTCFG_CLKDIV_2 0x0 /* backplane/2 */ +#define SSB_EXTCFG_CLKDIV_3 0x40 /* backplane/3 */ +#define SSB_EXTCFG_CLKDIV_4 0x80 /* backplane/4 */ +#define SSB_EXTCFG_CLKEN (1 << 8) /* clock enable */ +#define SSB_EXTCFG_STROBE (1 << 9) /* size/bytestrobe (synch only) */ + +/* pcmcia_memwait */ +#define SSB_PCMCIA_MEMW_0 0x0000003F /* waitcount0 */ +#define SSB_PCMCIA_MEMW_1 0x00001F00 /* waitcount1 */ +#define SSB_PCMCIA_MEMW_1_SHIFT 8 +#define SSB_PCMCIA_MEMW_2 0x001F0000 /* waitcount2 */ +#define SSB_PCMCIA_MEMW_2_SHIFT 16 +#define SSB_PCMCIA_MEMW_3 0x1F000000 /* waitcount3 */ +#define SSB_PCMCIA_MEMW_3_SHIFT 24 + +/* pcmcia_attrwait */ +#define SSB_PCMCIA_ATTW_0 0x0000003F /* waitcount0 */ +#define SSB_PCMCIA_ATTW_1 0x00001F00 /* waitcount1 */ +#define SSB_PCMCIA_ATTW_1_SHIFT 8 +#define SSB_PCMCIA_ATTW_2 0x001F0000 /* waitcount2 */ +#define SSB_PCMCIA_ATTW_2_SHIFT 16 +#define SSB_PCMCIA_ATTW_3 0x1F000000 /* waitcount3 */ +#define SSB_PCMCIA_ATTW_3_SHIFT 24 + +/* pcmcia_iowait */ +#define SSB_PCMCIA_IOW_0 0x0000003F /* waitcount0 */ +#define SSB_PCMCIA_IOW_1 0x00001F00 /* waitcount1 */ +#define SSB_PCMCIA_IOW_1_SHIFT 8 +#define SSB_PCMCIA_IOW_2 0x001F0000 /* waitcount2 */ +#define SSB_PCMCIA_IOW_2_SHIFT 16 +#define SSB_PCMCIA_IOW_3 0x1F000000 /* waitcount3 */ +#define SSB_PCMCIA_IOW_3_SHIFT 24 + +/* prog_waitcount */ +#define SSB_PROG_WCNT_0 0x0000001F /* waitcount0 */ +#define SSB_PROG_WCNT_1 0x00001F00 /* waitcount1 */ +#define SSB_PROG_WCNT_1_SHIFT 8 +#define SSB_PROG_WCNT_2 0x001F0000 /* waitcount2 */ +#define SSB_PROG_WCNT_2_SHIFT 16 +#define SSB_PROG_WCNT_3 0x1F000000 /* waitcount3 */ +#define SSB_PROG_WCNT_3_SHIFT 24 + +#define SSB_PROG_W0 0x0000000C +#define SSB_PROG_W1 0x00000A00 +#define SSB_PROG_W2 0x00020000 +#define SSB_PROG_W3 0x01000000 + +/* flash_waitcount */ +#define SSB_FLASH_WCNT_0 0x0000001F /* waitcount0 */ +#define SSB_FLASH_WCNT_1 0x00001F00 /* waitcount1 */ +#define SSB_FLASH_WCNT_1_SHIFT 8 +#define SSB_FLASH_WCNT_2 0x001F0000 /* waitcount2 */ +#define SSB_FLASH_WCNT_2_SHIFT 16 +#define SSB_FLASH_WCNT_3 0x1F000000 /* waitcount3 */ +#define SSB_FLASH_WCNT_3_SHIFT 24 + +/* watchdog */ +#define SSB_EXTIF_WATCHDOG_CLK 48000000 /* Hz */ + + + +#ifdef CONFIG_SSB_DRIVER_EXTIF + +struct ssb_extif { + struct ssb_device *dev; +}; + +static inline bool ssb_extif_available(struct ssb_extif *extif) +{ + return (extif->dev != NULL); +} + +extern void ssb_extif_get_clockcontrol(struct ssb_extif *extif, + u32 *plltype, u32 *n, u32 *m); + +extern void ssb_extif_timing_init(struct ssb_extif *extif, + unsigned long ns); + +u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask); + +void ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, u32 value); + +void ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, u32 value); + +#ifdef CONFIG_SSB_SERIAL +extern int ssb_extif_serial_init(struct ssb_extif *extif, + struct ssb_serial_port *ports); +#endif /* CONFIG_SSB_SERIAL */ + + +#else /* CONFIG_SSB_DRIVER_EXTIF */ +/* extif disabled */ + +struct ssb_extif { +}; + +static inline bool ssb_extif_available(struct ssb_extif *extif) +{ + return 0; +} + +static inline +void ssb_extif_get_clockcontrol(struct ssb_extif *extif, + u32 *plltype, u32 *n, u32 *m) +{ +} + +#endif /* CONFIG_SSB_DRIVER_EXTIF */ +#endif /* LINUX_SSB_EXTIFCORE_H_ */ diff --git a/include/linux/ssb/ssb_driver_mips.h b/include/linux/ssb/ssb_driver_mips.h new file mode 100644 index 00000000000..5f44e9740cd --- /dev/null +++ b/include/linux/ssb/ssb_driver_mips.h @@ -0,0 +1,46 @@ +#ifndef LINUX_SSB_MIPSCORE_H_ +#define LINUX_SSB_MIPSCORE_H_ + +#ifdef CONFIG_SSB_DRIVER_MIPS + +struct ssb_device; + +struct ssb_serial_port { + void *regs; + unsigned long clockspeed; + unsigned int irq; + unsigned int baud_base; + unsigned int reg_shift; +}; + + +struct ssb_mipscore { + struct ssb_device *dev; + + int nr_serial_ports; + struct ssb_serial_port serial_ports[4]; + + u8 flash_buswidth; + u32 flash_window; + u32 flash_window_size; +}; + +extern void ssb_mipscore_init(struct ssb_mipscore *mcore); +extern u32 ssb_cpu_clock(struct ssb_mipscore *mcore); + +extern unsigned int ssb_mips_irq(struct ssb_device *dev); + + +#else /* CONFIG_SSB_DRIVER_MIPS */ + +struct ssb_mipscore { +}; + +static inline +void ssb_mipscore_init(struct ssb_mipscore *mcore) +{ +} + +#endif /* CONFIG_SSB_DRIVER_MIPS */ + +#endif /* LINUX_SSB_MIPSCORE_H_ */ diff --git a/include/linux/ssb/ssb_driver_pci.h b/include/linux/ssb/ssb_driver_pci.h new file mode 100644 index 00000000000..9cfffb7b1a2 --- /dev/null +++ b/include/linux/ssb/ssb_driver_pci.h @@ -0,0 +1,106 @@ +#ifndef LINUX_SSB_PCICORE_H_ +#define LINUX_SSB_PCICORE_H_ + +#ifdef CONFIG_SSB_DRIVER_PCICORE + +/* PCI core registers. */ +#define SSB_PCICORE_CTL 0x0000 /* PCI Control */ +#define SSB_PCICORE_CTL_RST_OE 0x00000001 /* PCI_RESET Output Enable */ +#define SSB_PCICORE_CTL_RST 0x00000002 /* PCI_RESET driven out to pin */ +#define SSB_PCICORE_CTL_CLK_OE 0x00000004 /* Clock gate Output Enable */ +#define SSB_PCICORE_CTL_CLK 0x00000008 /* Gate for clock driven out to pin */ +#define SSB_PCICORE_ARBCTL 0x0010 /* PCI Arbiter Control */ +#define SSB_PCICORE_ARBCTL_INTERN 0x00000001 /* Use internal arbiter */ +#define SSB_PCICORE_ARBCTL_EXTERN 0x00000002 /* Use external arbiter */ +#define SSB_PCICORE_ARBCTL_PARKID 0x00000006 /* Mask, selects which agent is parked on an idle bus */ +#define SSB_PCICORE_ARBCTL_PARKID_LAST 0x00000000 /* Last requestor */ +#define SSB_PCICORE_ARBCTL_PARKID_4710 0x00000002 /* 4710 */ +#define SSB_PCICORE_ARBCTL_PARKID_EXT0 0x00000004 /* External requestor 0 */ +#define SSB_PCICORE_ARBCTL_PARKID_EXT1 0x00000006 /* External requestor 1 */ +#define SSB_PCICORE_ISTAT 0x0020 /* Interrupt status */ +#define SSB_PCICORE_ISTAT_INTA 0x00000001 /* PCI INTA# */ +#define SSB_PCICORE_ISTAT_INTB 0x00000002 /* PCI INTB# */ +#define SSB_PCICORE_ISTAT_SERR 0x00000004 /* PCI SERR# (write to clear) */ +#define SSB_PCICORE_ISTAT_PERR 0x00000008 /* PCI PERR# (write to clear) */ +#define SSB_PCICORE_ISTAT_PME 0x00000010 /* PCI PME# */ +#define SSB_PCICORE_IMASK 0x0024 /* Interrupt mask */ +#define SSB_PCICORE_IMASK_INTA 0x00000001 /* PCI INTA# */ +#define SSB_PCICORE_IMASK_INTB 0x00000002 /* PCI INTB# */ +#define SSB_PCICORE_IMASK_SERR 0x00000004 /* PCI SERR# */ +#define SSB_PCICORE_IMASK_PERR 0x00000008 /* PCI PERR# */ +#define SSB_PCICORE_IMASK_PME 0x00000010 /* PCI PME# */ +#define SSB_PCICORE_MBOX 0x0028 /* Backplane to PCI Mailbox */ +#define SSB_PCICORE_MBOX_F0_0 0x00000100 /* PCI function 0, INT 0 */ +#define SSB_PCICORE_MBOX_F0_1 0x00000200 /* PCI function 0, INT 1 */ +#define SSB_PCICORE_MBOX_F1_0 0x00000400 /* PCI function 1, INT 0 */ +#define SSB_PCICORE_MBOX_F1_1 0x00000800 /* PCI function 1, INT 1 */ +#define SSB_PCICORE_MBOX_F2_0 0x00001000 /* PCI function 2, INT 0 */ +#define SSB_PCICORE_MBOX_F2_1 0x00002000 /* PCI function 2, INT 1 */ +#define SSB_PCICORE_MBOX_F3_0 0x00004000 /* PCI function 3, INT 0 */ +#define SSB_PCICORE_MBOX_F3_1 0x00008000 /* PCI function 3, INT 1 */ +#define SSB_PCICORE_BCAST_ADDR 0x0050 /* Backplane Broadcast Address */ +#define SSB_PCICORE_BCAST_ADDR_MASK 0x000000FF +#define SSB_PCICORE_BCAST_DATA 0x0054 /* Backplane Broadcast Data */ +#define SSB_PCICORE_GPIO_IN 0x0060 /* rev >= 2 only */ +#define SSB_PCICORE_GPIO_OUT 0x0064 /* rev >= 2 only */ +#define SSB_PCICORE_GPIO_ENABLE 0x0068 /* rev >= 2 only */ +#define SSB_PCICORE_GPIO_CTL 0x006C /* rev >= 2 only */ +#define SSB_PCICORE_SBTOPCI0 0x0100 /* Backplane to PCI translation 0 (sbtopci0) */ +#define SSB_PCICORE_SBTOPCI0_MASK 0xFC000000 +#define SSB_PCICORE_SBTOPCI1 0x0104 /* Backplane to PCI translation 1 (sbtopci1) */ +#define SSB_PCICORE_SBTOPCI1_MASK 0xFC000000 +#define SSB_PCICORE_SBTOPCI2 0x0108 /* Backplane to PCI translation 2 (sbtopci2) */ +#define SSB_PCICORE_SBTOPCI2_MASK 0xC0000000 + +/* SBtoPCIx */ +#define SSB_PCICORE_SBTOPCI_MEM 0x00000000 +#define SSB_PCICORE_SBTOPCI_IO 0x00000001 +#define SSB_PCICORE_SBTOPCI_CFG0 0x00000002 +#define SSB_PCICORE_SBTOPCI_CFG1 0x00000003 +#define SSB_PCICORE_SBTOPCI_PREF 0x00000004 /* Prefetch enable */ +#define SSB_PCICORE_SBTOPCI_BURST 0x00000008 /* Burst enable */ +#define SSB_PCICORE_SBTOPCI_MRM 0x00000020 /* Memory Read Multiple */ +#define SSB_PCICORE_SBTOPCI_RC 0x00000030 /* Read Command mask (rev >= 11) */ +#define SSB_PCICORE_SBTOPCI_RC_READ 0x00000000 /* Memory read */ +#define SSB_PCICORE_SBTOPCI_RC_READL 0x00000010 /* Memory read line */ +#define SSB_PCICORE_SBTOPCI_RC_READM 0x00000020 /* Memory read multiple */ + + +/* PCIcore specific boardflags */ +#define SSB_PCICORE_BFL_NOPCI 0x00000400 /* Board leaves PCI floating */ + + +struct ssb_pcicore { + struct ssb_device *dev; + u8 setup_done:1; + u8 hostmode:1; + u8 cardbusmode:1; +}; + +extern void ssb_pcicore_init(struct ssb_pcicore *pc); + +/* Enable IRQ routing for a specific device */ +extern int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc, + struct ssb_device *dev); + + +#else /* CONFIG_SSB_DRIVER_PCICORE */ + + +struct ssb_pcicore { +}; + +static inline +void ssb_pcicore_init(struct ssb_pcicore *pc) +{ +} + +static inline +int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc, + struct ssb_device *dev) +{ + return 0; +} + +#endif /* CONFIG_SSB_DRIVER_PCICORE */ +#endif /* LINUX_SSB_PCICORE_H_ */ diff --git a/include/linux/ssb/ssb_regs.h b/include/linux/ssb/ssb_regs.h new file mode 100644 index 00000000000..47c7c71a5ac --- /dev/null +++ b/include/linux/ssb/ssb_regs.h @@ -0,0 +1,292 @@ +#ifndef LINUX_SSB_REGS_H_ +#define LINUX_SSB_REGS_H_ + + +/* SiliconBackplane Address Map. + * All regions may not exist on all chips. + */ +#define SSB_SDRAM_BASE 0x00000000U /* Physical SDRAM */ +#define SSB_PCI_MEM 0x08000000U /* Host Mode sb2pcitranslation0 (64 MB) */ +#define SSB_PCI_CFG 0x0c000000U /* Host Mode sb2pcitranslation1 (64 MB) */ +#define SSB_SDRAM_SWAPPED 0x10000000U /* Byteswapped Physical SDRAM */ +#define SSB_ENUM_BASE 0x18000000U /* Enumeration space base */ +#define SSB_ENUM_LIMIT 0x18010000U /* Enumeration space limit */ + +#define SSB_FLASH2 0x1c000000U /* Flash Region 2 (region 1 shadowed here) */ +#define SSB_FLASH2_SZ 0x02000000U /* Size of Flash Region 2 */ + +#define SSB_EXTIF_BASE 0x1f000000U /* External Interface region base address */ +#define SSB_FLASH1 0x1fc00000U /* Flash Region 1 */ +#define SSB_FLASH1_SZ 0x00400000U /* Size of Flash Region 1 */ + +#define SSB_PCI_DMA 0x40000000U /* Client Mode sb2pcitranslation2 (1 GB) */ +#define SSB_PCI_DMA_SZ 0x40000000U /* Client Mode sb2pcitranslation2 size in bytes */ +#define SSB_PCIE_DMA_L32 0x00000000U /* PCIE Client Mode sb2pcitranslation2 (2 ZettaBytes), low 32 bits */ +#define SSB_PCIE_DMA_H32 0x80000000U /* PCIE Client Mode sb2pcitranslation2 (2 ZettaBytes), high 32 bits */ +#define SSB_EUART (SSB_EXTIF_BASE + 0x00800000) +#define SSB_LED (SSB_EXTIF_BASE + 0x00900000) + + +/* Enumeration space constants */ +#define SSB_CORE_SIZE 0x1000 /* Size of a core MMIO area */ +#define SSB_MAX_NR_CORES ((SSB_ENUM_LIMIT - SSB_ENUM_BASE) / SSB_CORE_SIZE) + + +/* mips address */ +#define SSB_EJTAG 0xff200000 /* MIPS EJTAG space (2M) */ + + +/* SSB PCI config space registers. */ +#define SSB_PMCSR 0x44 +#define SSB_PE 0x100 +#define SSB_BAR0_WIN 0x80 /* Backplane address space 0 */ +#define SSB_BAR1_WIN 0x84 /* Backplane address space 1 */ +#define SSB_SPROMCTL 0x88 /* SPROM control */ +#define SSB_SPROMCTL_WE 0x10 /* SPROM write enable */ +#define SSB_BAR1_CONTROL 0x8c /* Address space 1 burst control */ +#define SSB_PCI_IRQS 0x90 /* PCI interrupts */ +#define SSB_PCI_IRQMASK 0x94 /* PCI IRQ control and mask (pcirev >= 6 only) */ +#define SSB_BACKPLANE_IRQS 0x98 /* Backplane Interrupts */ +#define SSB_GPIO_IN 0xB0 /* GPIO Input (pcirev >= 3 only) */ +#define SSB_GPIO_OUT 0xB4 /* GPIO Output (pcirev >= 3 only) */ +#define SSB_GPIO_OUT_ENABLE 0xB8 /* GPIO Output Enable/Disable (pcirev >= 3 only) */ +#define SSB_GPIO_SCS 0x10 /* PCI config space bit 4 for 4306c0 slow clock source */ +#define SSB_GPIO_HWRAD 0x20 /* PCI config space GPIO 13 for hw radio disable */ +#define SSB_GPIO_XTAL 0x40 /* PCI config space GPIO 14 for Xtal powerup */ +#define SSB_GPIO_PLL 0x80 /* PCI config space GPIO 15 for PLL powerdown */ + + +#define SSB_BAR0_MAX_RETRIES 50 + +/* Silicon backplane configuration register definitions */ +#define SSB_IPSFLAG 0x0F08 +#define SSB_IPSFLAG_IRQ1 0x0000003F /* which sbflags get routed to mips interrupt 1 */ +#define SSB_IPSFLAG_IRQ1_SHIFT 0 +#define SSB_IPSFLAG_IRQ2 0x00003F00 /* which sbflags get routed to mips interrupt 2 */ +#define SSB_IPSFLAG_IRQ2_SHIFT 8 +#define SSB_IPSFLAG_IRQ3 0x003F0000 /* which sbflags get routed to mips interrupt 3 */ +#define SSB_IPSFLAG_IRQ3_SHIFT 16 +#define SSB_IPSFLAG_IRQ4 0x3F000000 /* which sbflags get routed to mips interrupt 4 */ +#define SSB_IPSFLAG_IRQ4_SHIFT 24 +#define SSB_TPSFLAG 0x0F18 +#define SSB_TPSFLAG_BPFLAG 0x0000003F /* Backplane flag # */ +#define SSB_TPSFLAG_ALWAYSIRQ 0x00000040 /* IRQ is always sent on the Backplane */ +#define SSB_TMERRLOGA 0x0F48 +#define SSB_TMERRLOG 0x0F50 +#define SSB_ADMATCH3 0x0F60 +#define SSB_ADMATCH2 0x0F68 +#define SSB_ADMATCH1 0x0F70 +#define SSB_IMSTATE 0x0F90 /* SB Initiator Agent State */ +#define SSB_IMSTATE_PC 0x0000000f /* Pipe Count */ +#define SSB_IMSTATE_AP_MASK 0x00000030 /* Arbitration Priority */ +#define SSB_IMSTATE_AP_BOTH 0x00000000 /* Use both timeslices and token */ +#define SSB_IMSTATE_AP_TS 0x00000010 /* Use timeslices only */ +#define SSB_IMSTATE_AP_TK 0x00000020 /* Use token only */ +#define SSB_IMSTATE_AP_RSV 0x00000030 /* Reserved */ +#define SSB_IMSTATE_IBE 0x00020000 /* In Band Error */ +#define SSB_IMSTATE_TO 0x00040000 /* Timeout */ +#define SSB_INTVEC 0x0F94 /* SB Interrupt Mask */ +#define SSB_INTVEC_PCI 0x00000001 /* Enable interrupts for PCI */ +#define SSB_INTVEC_ENET0 0x00000002 /* Enable interrupts for enet 0 */ +#define SSB_INTVEC_ILINE20 0x00000004 /* Enable interrupts for iline20 */ +#define SSB_INTVEC_CODEC 0x00000008 /* Enable interrupts for v90 codec */ +#define SSB_INTVEC_USB 0x00000010 /* Enable interrupts for usb */ +#define SSB_INTVEC_EXTIF 0x00000020 /* Enable interrupts for external i/f */ +#define SSB_INTVEC_ENET1 0x00000040 /* Enable interrupts for enet 1 */ +#define SSB_TMSLOW 0x0F98 /* SB Target State Low */ +#define SSB_TMSLOW_RESET 0x00000001 /* Reset */ +#define SSB_TMSLOW_REJECT_22 0x00000002 /* Reject (Backplane rev 2.2) */ +#define SSB_TMSLOW_REJECT_23 0x00000004 /* Reject (Backplane rev 2.3) */ +#define SSB_TMSLOW_CLOCK 0x00010000 /* Clock Enable */ +#define SSB_TMSLOW_FGC 0x00020000 /* Force Gated Clocks On */ +#define SSB_TMSLOW_PE 0x40000000 /* Power Management Enable */ +#define SSB_TMSLOW_BE 0x80000000 /* BIST Enable */ +#define SSB_TMSHIGH 0x0F9C /* SB Target State High */ +#define SSB_TMSHIGH_SERR 0x00000001 /* S-error */ +#define SSB_TMSHIGH_INT 0x00000002 /* Interrupt */ +#define SSB_TMSHIGH_BUSY 0x00000004 /* Busy */ +#define SSB_TMSHIGH_TO 0x00000020 /* Timeout. Backplane rev >= 2.3 only */ +#define SSB_TMSHIGH_COREFL 0x1FFF0000 /* Core specific flags */ +#define SSB_TMSHIGH_COREFL_SHIFT 16 +#define SSB_TMSHIGH_DMA64 0x10000000 /* 64bit DMA supported */ +#define SSB_TMSHIGH_GCR 0x20000000 /* Gated Clock Request */ +#define SSB_TMSHIGH_BISTF 0x40000000 /* BIST Failed */ +#define SSB_TMSHIGH_BISTD 0x80000000 /* BIST Done */ +#define SSB_BWA0 0x0FA0 +#define SSB_IMCFGLO 0x0FA8 +#define SSB_IMCFGLO_SERTO 0x00000007 /* Service timeout */ +#define SSB_IMCFGLO_REQTO 0x00000070 /* Request timeout */ +#define SSB_IMCFGLO_REQTO_SHIFT 4 +#define SSB_IMCFGLO_CONNID 0x00FF0000 /* Connection ID */ +#define SSB_IMCFGLO_CONNID_SHIFT 16 +#define SSB_IMCFGHI 0x0FAC +#define SSB_ADMATCH0 0x0FB0 +#define SSB_TMCFGLO 0x0FB8 +#define SSB_TMCFGHI 0x0FBC +#define SSB_BCONFIG 0x0FC0 +#define SSB_BSTATE 0x0FC8 +#define SSB_ACTCFG 0x0FD8 +#define SSB_FLAGST 0x0FE8 +#define SSB_IDLOW 0x0FF8 +#define SSB_IDLOW_CFGSP 0x00000003 /* Config Space */ +#define SSB_IDLOW_ADDRNGE 0x00000038 /* Address Ranges supported */ +#define SSB_IDLOW_ADDRNGE_SHIFT 3 +#define SSB_IDLOW_SYNC 0x00000040 +#define SSB_IDLOW_INITIATOR 0x00000080 +#define SSB_IDLOW_MIBL 0x00000F00 /* Minimum Backplane latency */ +#define SSB_IDLOW_MIBL_SHIFT 8 +#define SSB_IDLOW_MABL 0x0000F000 /* Maximum Backplane latency */ +#define SSB_IDLOW_MABL_SHIFT 12 +#define SSB_IDLOW_TIF 0x00010000 /* This Initiator is first */ +#define SSB_IDLOW_CCW 0x000C0000 /* Cycle counter width */ +#define SSB_IDLOW_CCW_SHIFT 18 +#define SSB_IDLOW_TPT 0x00F00000 /* Target ports */ +#define SSB_IDLOW_TPT_SHIFT 20 +#define SSB_IDLOW_INITP 0x0F000000 /* Initiator ports */ +#define SSB_IDLOW_INITP_SHIFT 24 +#define SSB_IDLOW_SSBREV 0xF0000000 /* Sonics Backplane Revision code */ +#define SSB_IDLOW_SSBREV_22 0x00000000 /* <= 2.2 */ +#define SSB_IDLOW_SSBREV_23 0x10000000 /* 2.3 */ +#define SSB_IDHIGH 0x0FFC /* SB Identification High */ +#define SSB_IDHIGH_RCLO 0x0000000F /* Revision Code (low part) */ +#define SSB_IDHIGH_CC 0x00008FF0 /* Core Code */ +#define SSB_IDHIGH_CC_SHIFT 4 +#define SSB_IDHIGH_RCHI 0x00007000 /* Revision Code (high part) */ +#define SSB_IDHIGH_RCHI_SHIFT 8 /* yes, shift 8 is right */ +#define SSB_IDHIGH_VC 0xFFFF0000 /* Vendor Code */ +#define SSB_IDHIGH_VC_SHIFT 16 + +/* SPROM shadow area. If not otherwise noted, fields are + * two bytes wide. Note that the SPROM can _only_ be read + * in two-byte quantinies. + */ +#define SSB_SPROMSIZE_WORDS 64 +#define SSB_SPROMSIZE_BYTES (SSB_SPROMSIZE_WORDS * sizeof(u16)) +#define SSB_SPROM_BASE 0x1000 +#define SSB_SPROM_REVISION 0x107E +#define SSB_SPROM_REVISION_REV 0x00FF /* SPROM Revision number */ +#define SSB_SPROM_REVISION_CRC 0xFF00 /* SPROM CRC8 value */ +#define SSB_SPROM_REVISION_CRC_SHIFT 8 +/* SPROM Revision 1 */ +#define SSB_SPROM1_SPID 0x1004 /* Subsystem Product ID for PCI */ +#define SSB_SPROM1_SVID 0x1006 /* Subsystem Vendor ID for PCI */ +#define SSB_SPROM1_PID 0x1008 /* Product ID for PCI */ +#define SSB_SPROM1_IL0MAC 0x1048 /* 6 bytes MAC address for 802.11b/g */ +#define SSB_SPROM1_ET0MAC 0x104E /* 6 bytes MAC address for Ethernet */ +#define SSB_SPROM1_ET1MAC 0x1054 /* 6 bytes MAC address for 802.11a */ +#define SSB_SPROM1_ETHPHY 0x105A /* Ethernet PHY settings */ +#define SSB_SPROM1_ETHPHY_ET0A 0x001F /* MII Address for enet0 */ +#define SSB_SPROM1_ETHPHY_ET1A 0x03E0 /* MII Address for enet1 */ +#define SSB_SPROM1_ETHPHY_ET1A_SHIFT 5 +#define SSB_SPROM1_ETHPHY_ET0M (1<<14) /* MDIO for enet0 */ +#define SSB_SPROM1_ETHPHY_ET1M (1<<15) /* MDIO for enet1 */ +#define SSB_SPROM1_BINF 0x105C /* Board info */ +#define SSB_SPROM1_BINF_BREV 0x00FF /* Board Revision */ +#define SSB_SPROM1_BINF_CCODE 0x0F00 /* Country Code */ +#define SSB_SPROM1_BINF_CCODE_SHIFT 8 +#define SSB_SPROM1_BINF_ANTA 0x3000 /* Available A-PHY antennas */ +#define SSB_SPROM1_BINF_ANTA_SHIFT 12 +#define SSB_SPROM1_BINF_ANTBG 0xC000 /* Available B-PHY antennas */ +#define SSB_SPROM1_BINF_ANTBG_SHIFT 14 +#define SSB_SPROM1_PA0B0 0x105E +#define SSB_SPROM1_PA0B1 0x1060 +#define SSB_SPROM1_PA0B2 0x1062 +#define SSB_SPROM1_GPIOA 0x1064 /* General Purpose IO pins 0 and 1 */ +#define SSB_SPROM1_GPIOA_P0 0x00FF /* Pin 0 */ +#define SSB_SPROM1_GPIOA_P1 0xFF00 /* Pin 1 */ +#define SSB_SPROM1_GPIOA_P1_SHIFT 8 +#define SSB_SPROM1_GPIOB 0x1066 /* General Purpuse IO pins 2 and 3 */ +#define SSB_SPROM1_GPIOB_P2 0x00FF /* Pin 2 */ +#define SSB_SPROM1_GPIOB_P3 0xFF00 /* Pin 3 */ +#define SSB_SPROM1_GPIOB_P3_SHIFT 8 +#define SSB_SPROM1_MAXPWR 0x1068 /* Power Amplifier Max Power */ +#define SSB_SPROM1_MAXPWR_BG 0x00FF /* B-PHY and G-PHY (in dBm Q5.2) */ +#define SSB_SPROM1_MAXPWR_A 0xFF00 /* A-PHY (in dBm Q5.2) */ +#define SSB_SPROM1_MAXPWR_A_SHIFT 8 +#define SSB_SPROM1_PA1B0 0x106A +#define SSB_SPROM1_PA1B1 0x106C +#define SSB_SPROM1_PA1B2 0x106E +#define SSB_SPROM1_ITSSI 0x1070 /* Idle TSSI Target */ +#define SSB_SPROM1_ITSSI_BG 0x00FF /* B-PHY and G-PHY*/ +#define SSB_SPROM1_ITSSI_A 0xFF00 /* A-PHY */ +#define SSB_SPROM1_ITSSI_A_SHIFT 8 +#define SSB_SPROM1_BFLLO 0x1072 /* Boardflags (low 16 bits) */ +#define SSB_SPROM1_AGAIN 0x1074 /* Antenna Gain (in dBm Q5.2) */ +#define SSB_SPROM1_AGAIN_A 0x00FF /* A-PHY */ +#define SSB_SPROM1_AGAIN_BG 0xFF00 /* B-PHY and G-PHY */ +#define SSB_SPROM1_AGAIN_BG_SHIFT 8 +#define SSB_SPROM1_OEM 0x1076 /* 8 bytes OEM string (rev 1 only) */ +/* SPROM Revision 2 (inherits from rev 1) */ +#define SSB_SPROM2_BFLHI 0x1038 /* Boardflags (high 16 bits) */ +#define SSB_SPROM2_MAXP_A 0x103A /* A-PHY Max Power */ +#define SSB_SPROM2_MAXP_A_HI 0x00FF /* Max Power High */ +#define SSB_SPROM2_MAXP_A_LO 0xFF00 /* Max Power Low */ +#define SSB_SPROM2_MAXP_A_LO_SHIFT 8 +#define SSB_SPROM2_PA1LOB0 0x103C /* A-PHY PowerAmplifier Low Settings */ +#define SSB_SPROM2_PA1LOB1 0x103E /* A-PHY PowerAmplifier Low Settings */ +#define SSB_SPROM2_PA1LOB2 0x1040 /* A-PHY PowerAmplifier Low Settings */ +#define SSB_SPROM2_PA1HIB0 0x1042 /* A-PHY PowerAmplifier High Settings */ +#define SSB_SPROM2_PA1HIB1 0x1044 /* A-PHY PowerAmplifier High Settings */ +#define SSB_SPROM2_PA1HIB2 0x1046 /* A-PHY PowerAmplifier High Settings */ +#define SSB_SPROM2_OPO 0x1078 /* OFDM Power Offset from CCK Level */ +#define SSB_SPROM2_OPO_VALUE 0x00FF +#define SSB_SPROM2_OPO_UNUSED 0xFF00 +#define SSB_SPROM2_CCODE 0x107C /* Two char Country Code */ +/* SPROM Revision 3 (inherits from rev 2) */ +#define SSB_SPROM3_OFDMAPO 0x102C /* A-PHY OFDM Mid Power Offset (4 bytes, BigEndian) */ +#define SSB_SPROM3_OFDMALPO 0x1030 /* A-PHY OFDM Low Power Offset (4 bytes, BigEndian) */ +#define SSB_SPROM3_OFDMAHPO 0x1034 /* A-PHY OFDM High Power Offset (4 bytes, BigEndian) */ +#define SSB_SPROM3_GPIOLDC 0x1042 /* GPIO LED Powersave Duty Cycle (4 bytes, BigEndian) */ +#define SSB_SPROM3_GPIOLDC_OFF 0x0000FF00 /* Off Count */ +#define SSB_SPROM3_GPIOLDC_OFF_SHIFT 8 +#define SSB_SPROM3_GPIOLDC_ON 0x00FF0000 /* On Count */ +#define SSB_SPROM3_GPIOLDC_ON_SHIFT 16 +#define SSB_SPROM3_CCKPO 0x1078 /* CCK Power Offset */ +#define SSB_SPROM3_CCKPO_1M 0x000F /* 1M Rate PO */ +#define SSB_SPROM3_CCKPO_2M 0x00F0 /* 2M Rate PO */ +#define SSB_SPROM3_CCKPO_2M_SHIFT 4 +#define SSB_SPROM3_CCKPO_55M 0x0F00 /* 5.5M Rate PO */ +#define SSB_SPROM3_CCKPO_55M_SHIFT 8 +#define SSB_SPROM3_CCKPO_11M 0xF000 /* 11M Rate PO */ +#define SSB_SPROM3_CCKPO_11M_SHIFT 12 +#define SSB_SPROM3_OFDMGPO 0x107A /* G-PHY OFDM Power Offset (4 bytes, BigEndian) */ + +/* Values for SSB_SPROM1_BINF_CCODE */ +enum { + SSB_SPROM1CCODE_WORLD = 0, + SSB_SPROM1CCODE_THAILAND, + SSB_SPROM1CCODE_ISRAEL, + SSB_SPROM1CCODE_JORDAN, + SSB_SPROM1CCODE_CHINA, + SSB_SPROM1CCODE_JAPAN, + SSB_SPROM1CCODE_USA_CANADA_ANZ, + SSB_SPROM1CCODE_EUROPE, + SSB_SPROM1CCODE_USA_LOW, + SSB_SPROM1CCODE_JAPAN_HIGH, + SSB_SPROM1CCODE_ALL, + SSB_SPROM1CCODE_NONE, +}; + +/* Address-Match values and masks (SSB_ADMATCHxxx) */ +#define SSB_ADM_TYPE 0x00000003 /* Address type */ +#define SSB_ADM_TYPE0 0 +#define SSB_ADM_TYPE1 1 +#define SSB_ADM_TYPE2 2 +#define SSB_ADM_AD64 0x00000004 +#define SSB_ADM_SZ0 0x000000F8 /* Type0 size */ +#define SSB_ADM_SZ0_SHIFT 3 +#define SSB_ADM_SZ1 0x000001F8 /* Type1 size */ +#define SSB_ADM_SZ1_SHIFT 3 +#define SSB_ADM_SZ2 0x000001F8 /* Type2 size */ +#define SSB_ADM_SZ2_SHIFT 3 +#define SSB_ADM_EN 0x00000400 /* Enable */ +#define SSB_ADM_NEG 0x00000800 /* Negative decode */ +#define SSB_ADM_BASE0 0xFFFFFF00 /* Type0 base address */ +#define SSB_ADM_BASE0_SHIFT 8 +#define SSB_ADM_BASE1 0xFFFFF000 /* Type1 base address for the core */ +#define SSB_ADM_BASE1_SHIFT 12 +#define SSB_ADM_BASE2 0xFFFF0000 /* Type2 base address for the core */ +#define SSB_ADM_BASE2_SHIFT 16 + + +#endif /* LINUX_SSB_REGS_H_ */ diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 8a09021d8c5..895ba3ac620 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -484,6 +484,21 @@ static int do_parisc_entry(const char *filename, struct parisc_device_id *id, return 1; } +/* Looks like: ssb:vNidNrevN. */ +static int do_ssb_entry(const char *filename, + struct ssb_device_id *id, char *alias) +{ + id->vendor = TO_NATIVE(id->vendor); + id->coreid = TO_NATIVE(id->coreid); + id->revision = TO_NATIVE(id->revision); + + strcpy(alias, "ssb:"); + ADD(alias, "v", id->vendor != SSB_ANY_VENDOR, id->vendor); + ADD(alias, "id", id->coreid != SSB_ANY_ID, id->coreid); + ADD(alias, "rev", id->revision != SSB_ANY_REV, id->revision); + return 1; +} + /* Ignore any prefix, eg. v850 prepends _ */ static inline int sym_is(const char *symbol, const char *name) { @@ -599,6 +614,10 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, do_table(symval, sym->st_size, sizeof(struct parisc_device_id), "parisc", do_parisc_entry, mod); + else if (sym_is(symname, "__mod_ssb_device_table")) + do_table(symval, sym->st_size, + sizeof(struct ssb_device_id), "ssb", + do_ssb_entry, mod); } /* Now add out buffered information to the generated C source */ -- cgit v1.2.3-70-g09d2 From e4d6b7951812d98417feb10784e400e253caf633 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Tue, 18 Sep 2007 15:39:42 -0400 Subject: [B43]: add mac80211-based driver for modern BCM43xx devices Signed-off-by: Michael Buesch Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- MAINTAINERS | 9 + drivers/net/wireless/Kconfig | 1 + drivers/net/wireless/Makefile | 1 + drivers/net/wireless/b43/Kconfig | 119 + drivers/net/wireless/b43/Makefile | 17 + drivers/net/wireless/b43/b43.h | 845 +++++++ drivers/net/wireless/b43/debugfs.c | 654 ++++++ drivers/net/wireless/b43/debugfs.h | 89 + drivers/net/wireless/b43/dma.c | 1494 +++++++++++++ drivers/net/wireless/b43/dma.h | 337 +++ drivers/net/wireless/b43/leds.c | 299 +++ drivers/net/wireless/b43/leds.h | 55 + drivers/net/wireless/b43/lo.c | 1261 +++++++++++ drivers/net/wireless/b43/lo.h | 112 + drivers/net/wireless/b43/main.c | 4091 +++++++++++++++++++++++++++++++++ drivers/net/wireless/b43/main.h | 142 ++ drivers/net/wireless/b43/pcmcia.c | 157 ++ drivers/net/wireless/b43/pcmcia.h | 20 + drivers/net/wireless/b43/phy.c | 4351 ++++++++++++++++++++++++++++++++++++ drivers/net/wireless/b43/phy.h | 297 +++ drivers/net/wireless/b43/pio.c | 650 ++++++ drivers/net/wireless/b43/pio.h | 153 ++ drivers/net/wireless/b43/sysfs.c | 235 ++ drivers/net/wireless/b43/sysfs.h | 9 + drivers/net/wireless/b43/tables.c | 375 ++++ drivers/net/wireless/b43/tables.h | 28 + drivers/net/wireless/b43/xmit.c | 648 ++++++ drivers/net/wireless/b43/xmit.h | 250 +++ 28 files changed, 16699 insertions(+) create mode 100644 drivers/net/wireless/b43/Kconfig create mode 100644 drivers/net/wireless/b43/Makefile create mode 100644 drivers/net/wireless/b43/b43.h create mode 100644 drivers/net/wireless/b43/debugfs.c create mode 100644 drivers/net/wireless/b43/debugfs.h create mode 100644 drivers/net/wireless/b43/dma.c create mode 100644 drivers/net/wireless/b43/dma.h create mode 100644 drivers/net/wireless/b43/leds.c create mode 100644 drivers/net/wireless/b43/leds.h create mode 100644 drivers/net/wireless/b43/lo.c create mode 100644 drivers/net/wireless/b43/lo.h create mode 100644 drivers/net/wireless/b43/main.c create mode 100644 drivers/net/wireless/b43/main.h create mode 100644 drivers/net/wireless/b43/pcmcia.c create mode 100644 drivers/net/wireless/b43/pcmcia.h create mode 100644 drivers/net/wireless/b43/phy.c create mode 100644 drivers/net/wireless/b43/phy.h create mode 100644 drivers/net/wireless/b43/pio.c create mode 100644 drivers/net/wireless/b43/pio.h create mode 100644 drivers/net/wireless/b43/sysfs.c create mode 100644 drivers/net/wireless/b43/sysfs.h create mode 100644 drivers/net/wireless/b43/tables.c create mode 100644 drivers/net/wireless/b43/tables.h create mode 100644 drivers/net/wireless/b43/xmit.c create mode 100644 drivers/net/wireless/b43/xmit.h (limited to 'drivers') diff --git a/MAINTAINERS b/MAINTAINERS index 7524cd802da..e6589c3b69c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -795,6 +795,15 @@ L: linux-hams@vger.kernel.org W: http://www.baycom.org/~tom/ham/ham.html S: Maintained +B43 WIRELESS DRIVER +P: Michael Buesch +M: mb@bu3sch.de +P: Stefano Brivio +M: st3@riseup.net +L: linux-wireless@vger.kernel.org +W: http://bcm43xx.berlios.de/ +S: Maintained + BCM43XX WIRELESS DRIVER (SOFTMAC BASED VERSION) P: Larry Finger M: Larry.Finger@lwfinger.net diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 8d1541bbe25..7bed87e63da 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -579,6 +579,7 @@ config ADM8211 source "drivers/net/wireless/hostap/Kconfig" source "drivers/net/wireless/bcm43xx/Kconfig" +source "drivers/net/wireless/b43/Kconfig" source "drivers/net/wireless/zd1211rw/Kconfig" endmenu diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index e9bffdae0a0..765dbbcf54b 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -36,6 +36,7 @@ obj-$(CONFIG_PRISM54) += prism54/ obj-$(CONFIG_HOSTAP) += hostap/ obj-$(CONFIG_BCM43XX) += bcm43xx/ +obj-$(CONFIG_B43) += b43/ obj-$(CONFIG_ZD1211RW) += zd1211rw/ # 16-bit wireless PCMCIA client drivers diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig new file mode 100644 index 00000000000..4620119891f --- /dev/null +++ b/drivers/net/wireless/b43/Kconfig @@ -0,0 +1,119 @@ +config B43 + tristate "Broadcom 43xx wireless support (mac80211 stack)" + depends on SSB_POSSIBLE && MAC80211 && WLAN_80211 + select SSB + select FW_LOADER + select HW_RANDOM + ---help--- + b43 is a driver for the Broadcom 43xx series wireless devices. + + Check "lspci" for something like + "Broadcom Corporation BCM43XX 802.11 Wireless LAN Controller" + to determine whether you own such a device. + + This driver supports the new BCM43xx IEEE 802.11G devices, but not + the old IEEE 802.11B devices. Old devices are supported by + the b43legacy driver. + Note that this has nothing to do with the standard that your AccessPoint + supports (A, B, G or a combination). + IEEE 802.11G devices can talk to IEEE 802.11B AccessPoints. + + It is safe to include both b43 and b43legacy as the underlying glue + layer will automatically load the correct version for your device. + + This driver uses V4 firmware, which must be installed separately using + b43-fwcutter. + + This driver can be built as a module (recommended) that will be called "b43". + If unsure, say M. + +# Auto-select SSB PCI-HOST support, if possible +config B43_PCI_AUTOSELECT + bool + depends on B43 && SSB_PCIHOST_POSSIBLE + select SSB_PCIHOST + default y + +# Auto-select SSB PCICORE driver, if possible +config B43_PCICORE_AUTOSELECT + bool + depends on B43 && SSB_DRIVER_PCICORE_POSSIBLE + select SSB_DRIVER_PCICORE + default y + +config B43_PCMCIA + bool "Broadcom 43xx PCMCIA device support (EXPERIMENTAL)" + depends on B43 && SSB_PCMCIAHOST_POSSIBLE && EXPERIMENTAL + select SSB_PCMCIAHOST + ---help--- + Broadcom 43xx PCMCIA device support. + + Support for 16bit PCMCIA devices. + Please note that most PC-CARD devices are _NOT_ 16bit PCMCIA + devices, but 32bit CardBUS devices. CardBUS devices are supported + out of the box by b43. + + With this config option you can drive b43 cards in + CompactFlash formfactor in a PCMCIA adaptor. + CF b43 cards can sometimes be found in handheld PCs. + + It's safe to select Y here, even if you don't have a B43 PCMCIA device. + + If unsure, say N. + +config B43_DEBUG + bool "Broadcom 43xx debugging" + depends on B43 + ---help--- + Broadcom 43xx debugging messages. + + Say Y, if you want to find out why the driver does not + work for you. + +config B43_DMA + bool + depends on B43 +config B43_PIO + bool + depends on B43 + +choice + prompt "Broadcom 43xx data transfer mode" + depends on B43 + default B43_DMA_AND_PIO_MODE + +config B43_DMA_AND_PIO_MODE + bool "DMA + PIO" + select B43_DMA + select B43_PIO + ---help--- + Include both, Direct Memory Access (DMA) and Programmed I/O (PIO) + data transfer modes. + The actually used mode is selectable through the module + parameter "pio". If the module parameter is pio=0, DMA is used. + Otherwise PIO is used. DMA is default. + + If unsure, choose this option. + +config B43_DMA_MODE + bool "DMA (Direct Memory Access) only" + select B43_DMA + ---help--- + Only include Direct Memory Access (DMA). + This reduces the size of the driver module, by omitting the PIO code. + +config B43_PIO_MODE + bool "PIO (Programmed I/O) only" + select B43_PIO + ---help--- + Only include Programmed I/O (PIO). + This reduces the size of the driver module, by omitting the DMA code. + Please note that PIO transfers are slow (compared to DMA). + + Also note that not all devices of the 43xx series support PIO. + The 4306 (Apple Airport Extreme and others) supports PIO, while + the 4318 is known to _not_ support PIO. + + Only use PIO, if DMA does not work for you. + +endchoice diff --git a/drivers/net/wireless/b43/Makefile b/drivers/net/wireless/b43/Makefile new file mode 100644 index 00000000000..370935b84c5 --- /dev/null +++ b/drivers/net/wireless/b43/Makefile @@ -0,0 +1,17 @@ +# b43 core +b43-y += main.o +b43-y += tables.o +b43-y += phy.o +b43-y += sysfs.o +b43-y += leds.o +b43-y += xmit.o +b43-y += lo.o +# b43 PCMCIA support +b43-$(CONFIG_B43_PCMCIA) += pcmcia.o +# b43 debugging +b43-$(CONFIG_B43_DEBUG) += debugfs.o +# b43 DMA and PIO +b43-$(CONFIG_B43_DMA) += dma.o +b43-$(CONFIG_B43_PIO) += pio.o + +obj-$(CONFIG_B43) += b43.o diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h new file mode 100644 index 00000000000..270a2112de2 --- /dev/null +++ b/drivers/net/wireless/b43/b43.h @@ -0,0 +1,845 @@ +#ifndef B43_H_ +#define B43_H_ + +#include +#include +#include +#include +#include +#include + +#include "debugfs.h" +#include "leds.h" +#include "lo.h" +#include "phy.h" + +#ifdef CONFIG_B43_DEBUG +# define B43_DEBUG 1 +#else +# define B43_DEBUG 0 +#endif + +#define B43_RX_MAX_SSI 60 + +/* MMIO offsets */ +#define B43_MMIO_DMA0_REASON 0x20 +#define B43_MMIO_DMA0_IRQ_MASK 0x24 +#define B43_MMIO_DMA1_REASON 0x28 +#define B43_MMIO_DMA1_IRQ_MASK 0x2C +#define B43_MMIO_DMA2_REASON 0x30 +#define B43_MMIO_DMA2_IRQ_MASK 0x34 +#define B43_MMIO_DMA3_REASON 0x38 +#define B43_MMIO_DMA3_IRQ_MASK 0x3C +#define B43_MMIO_DMA4_REASON 0x40 +#define B43_MMIO_DMA4_IRQ_MASK 0x44 +#define B43_MMIO_DMA5_REASON 0x48 +#define B43_MMIO_DMA5_IRQ_MASK 0x4C +#define B43_MMIO_MACCTL 0x120 +#define B43_MMIO_STATUS2_BITFIELD 0x124 +#define B43_MMIO_GEN_IRQ_REASON 0x128 +#define B43_MMIO_GEN_IRQ_MASK 0x12C +#define B43_MMIO_RAM_CONTROL 0x130 +#define B43_MMIO_RAM_DATA 0x134 +#define B43_MMIO_PS_STATUS 0x140 +#define B43_MMIO_RADIO_HWENABLED_HI 0x158 +#define B43_MMIO_SHM_CONTROL 0x160 +#define B43_MMIO_SHM_DATA 0x164 +#define B43_MMIO_SHM_DATA_UNALIGNED 0x166 +#define B43_MMIO_XMITSTAT_0 0x170 +#define B43_MMIO_XMITSTAT_1 0x174 +#define B43_MMIO_REV3PLUS_TSF_LOW 0x180 /* core rev >= 3 only */ +#define B43_MMIO_REV3PLUS_TSF_HIGH 0x184 /* core rev >= 3 only */ + +/* 32-bit DMA */ +#define B43_MMIO_DMA32_BASE0 0x200 +#define B43_MMIO_DMA32_BASE1 0x220 +#define B43_MMIO_DMA32_BASE2 0x240 +#define B43_MMIO_DMA32_BASE3 0x260 +#define B43_MMIO_DMA32_BASE4 0x280 +#define B43_MMIO_DMA32_BASE5 0x2A0 +/* 64-bit DMA */ +#define B43_MMIO_DMA64_BASE0 0x200 +#define B43_MMIO_DMA64_BASE1 0x240 +#define B43_MMIO_DMA64_BASE2 0x280 +#define B43_MMIO_DMA64_BASE3 0x2C0 +#define B43_MMIO_DMA64_BASE4 0x300 +#define B43_MMIO_DMA64_BASE5 0x340 +/* PIO */ +#define B43_MMIO_PIO1_BASE 0x300 +#define B43_MMIO_PIO2_BASE 0x310 +#define B43_MMIO_PIO3_BASE 0x320 +#define B43_MMIO_PIO4_BASE 0x330 + +#define B43_MMIO_PHY_VER 0x3E0 +#define B43_MMIO_PHY_RADIO 0x3E2 +#define B43_MMIO_PHY0 0x3E6 +#define B43_MMIO_ANTENNA 0x3E8 +#define B43_MMIO_CHANNEL 0x3F0 +#define B43_MMIO_CHANNEL_EXT 0x3F4 +#define B43_MMIO_RADIO_CONTROL 0x3F6 +#define B43_MMIO_RADIO_DATA_HIGH 0x3F8 +#define B43_MMIO_RADIO_DATA_LOW 0x3FA +#define B43_MMIO_PHY_CONTROL 0x3FC +#define B43_MMIO_PHY_DATA 0x3FE +#define B43_MMIO_MACFILTER_CONTROL 0x420 +#define B43_MMIO_MACFILTER_DATA 0x422 +#define B43_MMIO_RCMTA_COUNT 0x43C +#define B43_MMIO_RADIO_HWENABLED_LO 0x49A +#define B43_MMIO_GPIO_CONTROL 0x49C +#define B43_MMIO_GPIO_MASK 0x49E +#define B43_MMIO_TSF_0 0x632 /* core rev < 3 only */ +#define B43_MMIO_TSF_1 0x634 /* core rev < 3 only */ +#define B43_MMIO_TSF_2 0x636 /* core rev < 3 only */ +#define B43_MMIO_TSF_3 0x638 /* core rev < 3 only */ +#define B43_MMIO_RNG 0x65A +#define B43_MMIO_POWERUP_DELAY 0x6A8 + +/* SPROM boardflags_lo values */ +#define B43_BFL_BTCOEXIST 0x0001 /* implements Bluetooth coexistance */ +#define B43_BFL_PACTRL 0x0002 /* GPIO 9 controlling the PA */ +#define B43_BFL_AIRLINEMODE 0x0004 /* implements GPIO 13 radio disable indication */ +#define B43_BFL_RSSI 0x0008 /* software calculates nrssi slope. */ +#define B43_BFL_ENETSPI 0x0010 /* has ephy roboswitch spi */ +#define B43_BFL_XTAL_NOSLOW 0x0020 /* no slow clock available */ +#define B43_BFL_CCKHIPWR 0x0040 /* can do high power CCK transmission */ +#define B43_BFL_ENETADM 0x0080 /* has ADMtek switch */ +#define B43_BFL_ENETVLAN 0x0100 /* can do vlan */ +#define B43_BFL_AFTERBURNER 0x0200 /* supports Afterburner mode */ +#define B43_BFL_NOPCI 0x0400 /* leaves PCI floating */ +#define B43_BFL_FEM 0x0800 /* supports the Front End Module */ +#define B43_BFL_EXTLNA 0x1000 /* has an external LNA */ +#define B43_BFL_HGPA 0x2000 /* had high gain PA */ +#define B43_BFL_BTCMOD 0x4000 /* BFL_BTCOEXIST is given in alternate GPIOs */ +#define B43_BFL_ALTIQ 0x8000 /* alternate I/Q settings */ + +/* GPIO register offset, in both ChipCommon and PCI core. */ +#define B43_GPIO_CONTROL 0x6c + +/* SHM Routing */ +enum { + B43_SHM_UCODE, /* Microcode memory */ + B43_SHM_SHARED, /* Shared memory */ + B43_SHM_SCRATCH, /* Scratch memory */ + B43_SHM_HW, /* Internal hardware register */ + B43_SHM_RCMTA, /* Receive match transmitter address (rev >= 5 only) */ +}; +/* SHM Routing modifiers */ +#define B43_SHM_AUTOINC_R 0x0200 /* Auto-increment address on read */ +#define B43_SHM_AUTOINC_W 0x0100 /* Auto-increment address on write */ +#define B43_SHM_AUTOINC_RW (B43_SHM_AUTOINC_R | \ + B43_SHM_AUTOINC_W) + +/* Misc SHM_SHARED offsets */ +#define B43_SHM_SH_WLCOREREV 0x0016 /* 802.11 core revision */ +#define B43_SHM_SH_PCTLWDPOS 0x0008 +#define B43_SHM_SH_RXPADOFF 0x0034 /* RX Padding data offset (PIO only) */ +#define B43_SHM_SH_PHYVER 0x0050 /* PHY version */ +#define B43_SHM_SH_PHYTYPE 0x0052 /* PHY type */ +#define B43_SHM_SH_ANTSWAP 0x005C /* Antenna swap threshold */ +#define B43_SHM_SH_HOSTFLO 0x005E /* Hostflags for ucode options (low) */ +#define B43_SHM_SH_HOSTFHI 0x0060 /* Hostflags for ucode options (high) */ +#define B43_SHM_SH_RFATT 0x0064 /* Current radio attenuation value */ +#define B43_SHM_SH_RADAR 0x0066 /* Radar register */ +#define B43_SHM_SH_PHYTXNOI 0x006E /* PHY noise directly after TX (lower 8bit only) */ +#define B43_SHM_SH_RFRXSP1 0x0072 /* RF RX SP Register 1 */ +#define B43_SHM_SH_CHAN 0x00A0 /* Current channel (low 8bit only) */ +#define B43_SHM_SH_CHAN_5GHZ 0x0100 /* Bit set, if 5Ghz channel */ +#define B43_SHM_SH_BCMCFIFOID 0x0108 /* Last posted cookie to the bcast/mcast FIFO */ +/* SHM_SHARED TX FIFO variables */ +#define B43_SHM_SH_SIZE01 0x0098 /* TX FIFO size for FIFO 0 (low) and 1 (high) */ +#define B43_SHM_SH_SIZE23 0x009A /* TX FIFO size for FIFO 2 and 3 */ +#define B43_SHM_SH_SIZE45 0x009C /* TX FIFO size for FIFO 4 and 5 */ +#define B43_SHM_SH_SIZE67 0x009E /* TX FIFO size for FIFO 6 and 7 */ +/* SHM_SHARED background noise */ +#define B43_SHM_SH_JSSI0 0x0088 /* Measure JSSI 0 */ +#define B43_SHM_SH_JSSI1 0x008A /* Measure JSSI 1 */ +#define B43_SHM_SH_JSSIAUX 0x008C /* Measure JSSI AUX */ +/* SHM_SHARED crypto engine */ +#define B43_SHM_SH_DEFAULTIV 0x003C /* Default IV location */ +#define B43_SHM_SH_NRRXTRANS 0x003E /* # of soft RX transmitter addresses (max 8) */ +#define B43_SHM_SH_KTP 0x0056 /* Key table pointer */ +#define B43_SHM_SH_TKIPTSCTTAK 0x0318 +#define B43_SHM_SH_KEYIDXBLOCK 0x05D4 /* Key index/algorithm block (v4 firmware) */ +#define B43_SHM_SH_PSM 0x05F4 /* PSM transmitter address match block (rev < 5) */ +/* SHM_SHARED WME variables */ +#define B43_SHM_SH_EDCFSTAT 0x000E /* EDCF status */ +#define B43_SHM_SH_TXFCUR 0x0030 /* TXF current index */ +#define B43_SHM_SH_EDCFQ 0x0240 /* EDCF Q info */ +/* SHM_SHARED powersave mode related */ +#define B43_SHM_SH_SLOTT 0x0010 /* Slot time */ +#define B43_SHM_SH_DTIMPER 0x0012 /* DTIM period */ +#define B43_SHM_SH_NOSLPZNATDTIM 0x004C /* NOSLPZNAT DTIM */ +/* SHM_SHARED beacon variables */ +#define B43_SHM_SH_BTL0 0x0018 /* Beacon template length 0 */ +#define B43_SHM_SH_BTL1 0x001A /* Beacon template length 1 */ +#define B43_SHM_SH_BTSFOFF 0x001C /* Beacon TSF offset */ +#define B43_SHM_SH_TIMBPOS 0x001E /* TIM B position in beacon */ +#define B43_SHM_SH_SFFBLIM 0x0044 /* Short frame fallback retry limit */ +#define B43_SHM_SH_LFFBLIM 0x0046 /* Long frame fallback retry limit */ +#define B43_SHM_SH_BEACPHYCTL 0x0054 /* Beacon PHY TX control word (see PHY TX control) */ +/* SHM_SHARED ACK/CTS control */ +#define B43_SHM_SH_ACKCTSPHYCTL 0x0022 /* ACK/CTS PHY control word (see PHY TX control) */ +/* SHM_SHARED probe response variables */ +#define B43_SHM_SH_PRSSID 0x0160 /* Probe Response SSID */ +#define B43_SHM_SH_PRSSIDLEN 0x0048 /* Probe Response SSID length */ +#define B43_SHM_SH_PRTLEN 0x004A /* Probe Response template length */ +#define B43_SHM_SH_PRMAXTIME 0x0074 /* Probe Response max time */ +#define B43_SHM_SH_PRPHYCTL 0x0188 /* Probe Response PHY TX control word */ +/* SHM_SHARED rate tables */ +#define B43_SHM_SH_OFDMDIRECT 0x01C0 /* Pointer to OFDM direct map */ +#define B43_SHM_SH_OFDMBASIC 0x01E0 /* Pointer to OFDM basic rate map */ +#define B43_SHM_SH_CCKDIRECT 0x0200 /* Pointer to CCK direct map */ +#define B43_SHM_SH_CCKBASIC 0x0220 /* Pointer to CCK basic rate map */ +/* SHM_SHARED microcode soft registers */ +#define B43_SHM_SH_UCODEREV 0x0000 /* Microcode revision */ +#define B43_SHM_SH_UCODEPATCH 0x0002 /* Microcode patchlevel */ +#define B43_SHM_SH_UCODEDATE 0x0004 /* Microcode date */ +#define B43_SHM_SH_UCODETIME 0x0006 /* Microcode time */ +#define B43_SHM_SH_UCODESTAT 0x0040 /* Microcode debug status code */ +#define B43_SHM_SH_UCODESTAT_INVALID 0 +#define B43_SHM_SH_UCODESTAT_INIT 1 +#define B43_SHM_SH_UCODESTAT_ACTIVE 2 +#define B43_SHM_SH_UCODESTAT_SUSP 3 /* suspended */ +#define B43_SHM_SH_UCODESTAT_SLEEP 4 /* asleep (PS) */ +#define B43_SHM_SH_MAXBFRAMES 0x0080 /* Maximum number of frames in a burst */ +#define B43_SHM_SH_SPUWKUP 0x0094 /* pre-wakeup for synth PU in us */ +#define B43_SHM_SH_PRETBTT 0x0096 /* pre-TBTT in us */ + +/* SHM_SCRATCH offsets */ +#define B43_SHM_SC_MINCONT 0x0003 /* Minimum contention window */ +#define B43_SHM_SC_MAXCONT 0x0004 /* Maximum contention window */ +#define B43_SHM_SC_CURCONT 0x0005 /* Current contention window */ +#define B43_SHM_SC_SRLIMIT 0x0006 /* Short retry count limit */ +#define B43_SHM_SC_LRLIMIT 0x0007 /* Long retry count limit */ +#define B43_SHM_SC_DTIMC 0x0008 /* Current DTIM count */ +#define B43_SHM_SC_BTL0LEN 0x0015 /* Beacon 0 template length */ +#define B43_SHM_SC_BTL1LEN 0x0016 /* Beacon 1 template length */ +#define B43_SHM_SC_SCFB 0x0017 /* Short frame transmit count threshold for rate fallback */ +#define B43_SHM_SC_LCFB 0x0018 /* Long frame transmit count threshold for rate fallback */ + +/* Hardware Radio Enable masks */ +#define B43_MMIO_RADIO_HWENABLED_HI_MASK (1 << 16) +#define B43_MMIO_RADIO_HWENABLED_LO_MASK (1 << 4) + +/* HostFlags. See b43_hf_read/write() */ +#define B43_HF_ANTDIVHELP 0x00000001 /* ucode antenna div helper */ +#define B43_HF_SYMW 0x00000002 /* G-PHY SYM workaround */ +#define B43_HF_RXPULLW 0x00000004 /* RX pullup workaround */ +#define B43_HF_CCKBOOST 0x00000008 /* 4dB CCK power boost (exclusive with OFDM boost) */ +#define B43_HF_BTCOEX 0x00000010 /* Bluetooth coexistance */ +#define B43_HF_GDCW 0x00000020 /* G-PHY DV canceller filter bw workaround */ +#define B43_HF_OFDMPABOOST 0x00000040 /* Enable PA gain boost for OFDM */ +#define B43_HF_ACPR 0x00000080 /* Disable for Japan, channel 14 */ +#define B43_HF_EDCF 0x00000100 /* on if WME and MAC suspended */ +#define B43_HF_TSSIRPSMW 0x00000200 /* TSSI reset PSM ucode workaround */ +#define B43_HF_DSCRQ 0x00000400 /* Disable slow clock request in ucode */ +#define B43_HF_ACIW 0x00000800 /* ACI workaround: shift bits by 2 on PHY CRS */ +#define B43_HF_2060W 0x00001000 /* 2060 radio workaround */ +#define B43_HF_RADARW 0x00002000 /* Radar workaround */ +#define B43_HF_USEDEFKEYS 0x00004000 /* Enable use of default keys */ +#define B43_HF_BT4PRIOCOEX 0x00010000 /* Bluetooth 2-priority coexistance */ +#define B43_HF_FWKUP 0x00020000 /* Fast wake-up ucode */ +#define B43_HF_VCORECALC 0x00040000 /* Force VCO recalculation when powering up synthpu */ +#define B43_HF_PCISCW 0x00080000 /* PCI slow clock workaround */ +#define B43_HF_4318TSSI 0x00200000 /* 4318 TSSI */ +#define B43_HF_FBCMCFIFO 0x00400000 /* Flush bcast/mcast FIFO immediately */ +#define B43_HF_HWPCTL 0x00800000 /* Enable hardwarre power control */ +#define B43_HF_BTCOEXALT 0x01000000 /* Bluetooth coexistance in alternate pins */ +#define B43_HF_TXBTCHECK 0x02000000 /* Bluetooth check during transmission */ +#define B43_HF_SKCFPUP 0x04000000 /* Skip CFP update */ + +/* MacFilter offsets. */ +#define B43_MACFILTER_SELF 0x0000 +#define B43_MACFILTER_BSSID 0x0003 + +/* PowerControl */ +#define B43_PCTL_IN 0xB0 +#define B43_PCTL_OUT 0xB4 +#define B43_PCTL_OUTENABLE 0xB8 +#define B43_PCTL_XTAL_POWERUP 0x40 +#define B43_PCTL_PLL_POWERDOWN 0x80 + +/* PowerControl Clock Modes */ +#define B43_PCTL_CLK_FAST 0x00 +#define B43_PCTL_CLK_SLOW 0x01 +#define B43_PCTL_CLK_DYNAMIC 0x02 + +#define B43_PCTL_FORCE_SLOW 0x0800 +#define B43_PCTL_FORCE_PLL 0x1000 +#define B43_PCTL_DYN_XTAL 0x2000 + +/* PHYVersioning */ +#define B43_PHYTYPE_A 0x00 +#define B43_PHYTYPE_B 0x01 +#define B43_PHYTYPE_G 0x02 + +/* PHYRegisters */ +#define B43_PHY_ILT_A_CTRL 0x0072 +#define B43_PHY_ILT_A_DATA1 0x0073 +#define B43_PHY_ILT_A_DATA2 0x0074 +#define B43_PHY_G_LO_CONTROL 0x0810 +#define B43_PHY_ILT_G_CTRL 0x0472 +#define B43_PHY_ILT_G_DATA1 0x0473 +#define B43_PHY_ILT_G_DATA2 0x0474 +#define B43_PHY_A_PCTL 0x007B +#define B43_PHY_G_PCTL 0x0029 +#define B43_PHY_A_CRS 0x0029 +#define B43_PHY_RADIO_BITFIELD 0x0401 +#define B43_PHY_G_CRS 0x0429 +#define B43_PHY_NRSSILT_CTRL 0x0803 +#define B43_PHY_NRSSILT_DATA 0x0804 + +/* RadioRegisters */ +#define B43_RADIOCTL_ID 0x01 + +/* MAC Control bitfield */ +#define B43_MACCTL_ENABLED 0x00000001 /* MAC Enabled */ +#define B43_MACCTL_PSM_RUN 0x00000002 /* Run Microcode */ +#define B43_MACCTL_PSM_JMP0 0x00000004 /* Microcode jump to 0 */ +#define B43_MACCTL_SHM_ENABLED 0x00000100 /* SHM Enabled */ +#define B43_MACCTL_SHM_UPPER 0x00000200 /* SHM Upper */ +#define B43_MACCTL_IHR_ENABLED 0x00000400 /* IHR Region Enabled */ +#define B43_MACCTL_PSM_DBG 0x00002000 /* Microcode debugging enabled */ +#define B43_MACCTL_GPOUTSMSK 0x0000C000 /* GPOUT Select Mask */ +#define B43_MACCTL_BE 0x00010000 /* Big Endian mode */ +#define B43_MACCTL_INFRA 0x00020000 /* Infrastructure mode */ +#define B43_MACCTL_AP 0x00040000 /* AccessPoint mode */ +#define B43_MACCTL_RADIOLOCK 0x00080000 /* Radio lock */ +#define B43_MACCTL_BEACPROMISC 0x00100000 /* Beacon Promiscuous */ +#define B43_MACCTL_KEEP_BADPLCP 0x00200000 /* Keep frames with bad PLCP */ +#define B43_MACCTL_KEEP_CTL 0x00400000 /* Keep control frames */ +#define B43_MACCTL_KEEP_BAD 0x00800000 /* Keep bad frames (FCS) */ +#define B43_MACCTL_PROMISC 0x01000000 /* Promiscuous mode */ +#define B43_MACCTL_HWPS 0x02000000 /* Hardware Power Saving */ +#define B43_MACCTL_AWAKE 0x04000000 /* Device is awake */ +#define B43_MACCTL_CLOSEDNET 0x08000000 /* Closed net (no SSID bcast) */ +#define B43_MACCTL_TBTTHOLD 0x10000000 /* TBTT Hold */ +#define B43_MACCTL_DISCTXSTAT 0x20000000 /* Discard TX status */ +#define B43_MACCTL_DISCPMQ 0x40000000 /* Discard Power Management Queue */ +#define B43_MACCTL_GMODE 0x80000000 /* G Mode */ + +/* 802.11 core specific TM State Low flags */ +#define B43_TMSLOW_GMODE 0x20000000 /* G Mode Enable */ +#define B43_TMSLOW_PLLREFSEL 0x00200000 /* PLL Frequency Reference Select */ +#define B43_TMSLOW_MACPHYCLKEN 0x00100000 /* MAC PHY Clock Control Enable (rev >= 5) */ +#define B43_TMSLOW_PHYRESET 0x00080000 /* PHY Reset */ +#define B43_TMSLOW_PHYCLKEN 0x00040000 /* PHY Clock Enable */ + +/* 802.11 core specific TM State High flags */ +#define B43_TMSHIGH_FCLOCK 0x00040000 /* Fast Clock Available (rev >= 5) */ +#define B43_TMSHIGH_APHY 0x00020000 /* A-PHY available (rev >= 5) */ +#define B43_TMSHIGH_GPHY 0x00010000 /* G-PHY available (rev >= 5) */ + +/* Generic-Interrupt reasons. */ +#define B43_IRQ_MAC_SUSPENDED 0x00000001 +#define B43_IRQ_BEACON 0x00000002 +#define B43_IRQ_TBTT_INDI 0x00000004 +#define B43_IRQ_BEACON_TX_OK 0x00000008 +#define B43_IRQ_BEACON_CANCEL 0x00000010 +#define B43_IRQ_ATIM_END 0x00000020 +#define B43_IRQ_PMQ 0x00000040 +#define B43_IRQ_PIO_WORKAROUND 0x00000100 +#define B43_IRQ_MAC_TXERR 0x00000200 +#define B43_IRQ_PHY_TXERR 0x00000800 +#define B43_IRQ_PMEVENT 0x00001000 +#define B43_IRQ_TIMER0 0x00002000 +#define B43_IRQ_TIMER1 0x00004000 +#define B43_IRQ_DMA 0x00008000 +#define B43_IRQ_TXFIFO_FLUSH_OK 0x00010000 +#define B43_IRQ_CCA_MEASURE_OK 0x00020000 +#define B43_IRQ_NOISESAMPLE_OK 0x00040000 +#define B43_IRQ_UCODE_DEBUG 0x08000000 +#define B43_IRQ_RFKILL 0x10000000 +#define B43_IRQ_TX_OK 0x20000000 +#define B43_IRQ_PHY_G_CHANGED 0x40000000 +#define B43_IRQ_TIMEOUT 0x80000000 + +#define B43_IRQ_ALL 0xFFFFFFFF +#define B43_IRQ_MASKTEMPLATE (B43_IRQ_MAC_SUSPENDED | \ + B43_IRQ_BEACON | \ + B43_IRQ_TBTT_INDI | \ + B43_IRQ_ATIM_END | \ + B43_IRQ_PMQ | \ + B43_IRQ_MAC_TXERR | \ + B43_IRQ_PHY_TXERR | \ + B43_IRQ_DMA | \ + B43_IRQ_TXFIFO_FLUSH_OK | \ + B43_IRQ_NOISESAMPLE_OK | \ + B43_IRQ_UCODE_DEBUG | \ + B43_IRQ_RFKILL | \ + B43_IRQ_TX_OK) + +/* Device specific rate values. + * The actual values defined here are (rate_in_mbps * 2). + * Some code depends on this. Don't change it. */ +#define B43_CCK_RATE_1MB 0x02 +#define B43_CCK_RATE_2MB 0x04 +#define B43_CCK_RATE_5MB 0x0B +#define B43_CCK_RATE_11MB 0x16 +#define B43_OFDM_RATE_6MB 0x0C +#define B43_OFDM_RATE_9MB 0x12 +#define B43_OFDM_RATE_12MB 0x18 +#define B43_OFDM_RATE_18MB 0x24 +#define B43_OFDM_RATE_24MB 0x30 +#define B43_OFDM_RATE_36MB 0x48 +#define B43_OFDM_RATE_48MB 0x60 +#define B43_OFDM_RATE_54MB 0x6C +/* Convert a b43 rate value to a rate in 100kbps */ +#define B43_RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2) + +#define B43_DEFAULT_SHORT_RETRY_LIMIT 7 +#define B43_DEFAULT_LONG_RETRY_LIMIT 4 + +/* Max size of a security key */ +#define B43_SEC_KEYSIZE 16 +/* Security algorithms. */ +enum { + B43_SEC_ALGO_NONE = 0, /* unencrypted, as of TX header. */ + B43_SEC_ALGO_WEP40, + B43_SEC_ALGO_TKIP, + B43_SEC_ALGO_AES, + B43_SEC_ALGO_WEP104, + B43_SEC_ALGO_AES_LEGACY, +}; + +struct b43_dmaring; +struct b43_pioqueue; + +/* The firmware file header */ +#define B43_FW_TYPE_UCODE 'u' +#define B43_FW_TYPE_PCM 'p' +#define B43_FW_TYPE_IV 'i' +struct b43_fw_header { + /* File type */ + u8 type; + /* File format version */ + u8 ver; + u8 __padding[2]; + /* Size of the data. For ucode and PCM this is in bytes. + * For IV this is number-of-ivs. */ + __be32 size; +} __attribute__((__packed__)); + +/* Initial Value file format */ +#define B43_IV_OFFSET_MASK 0x7FFF +#define B43_IV_32BIT 0x8000 +struct b43_iv { + __be16 offset_size; + union { + __be16 d16; + __be32 d32; + } data __attribute__((__packed__)); +} __attribute__((__packed__)); + + +#define B43_PHYMODE(phytype) (1 << (phytype)) +#define B43_PHYMODE_A B43_PHYMODE(B43_PHYTYPE_A) +#define B43_PHYMODE_B B43_PHYMODE(B43_PHYTYPE_B) +#define B43_PHYMODE_G B43_PHYMODE(B43_PHYTYPE_G) + +struct b43_phy { + /* Possible PHYMODEs on this PHY */ + u8 possible_phymodes; + /* GMODE bit enabled? */ + bool gmode; + /* Possible ieee80211 subsystem hwmodes for this PHY. + * Which mode is selected, depends on thr GMODE enabled bit */ +#define B43_MAX_PHYHWMODES 2 + struct ieee80211_hw_mode hwmodes[B43_MAX_PHYHWMODES]; + + /* Analog Type */ + u8 analog; + /* B43_PHYTYPE_ */ + u8 type; + /* PHY revision number. */ + u8 rev; + + /* Radio versioning */ + u16 radio_manuf; /* Radio manufacturer */ + u16 radio_ver; /* Radio version */ + u8 radio_rev; /* Radio revision */ + + bool radio_on; /* Radio switched on/off */ + bool locked; /* Only used in b43_phy_{un}lock() */ + bool dyn_tssi_tbl; /* tssi2dbm is kmalloc()ed. */ + + /* ACI (adjacent channel interference) flags. */ + bool aci_enable; + bool aci_wlan_automatic; + bool aci_hw_rssi; + + u16 minlowsig[2]; + u16 minlowsigpos[2]; + + /* TSSI to dBm table in use */ + const s8 *tssi2dbm; + /* Target idle TSSI */ + int tgt_idle_tssi; + /* Current idle TSSI */ + int cur_idle_tssi; + + /* LocalOscillator control values. */ + struct b43_txpower_lo_control *lo_control; + /* Values from b43_calc_loopback_gain() */ + s16 max_lb_gain; /* Maximum Loopback gain in hdB */ + s16 trsw_rx_gain; /* TRSW RX gain in hdB */ + s16 lna_lod_gain; /* LNA lod */ + s16 lna_gain; /* LNA */ + s16 pga_gain; /* PGA */ + + /* PHY lock for core.rev < 3 + * This lock is only used by b43_phy_{un}lock() + */ + spinlock_t lock; + + /* Desired TX power level (in dBm). + * This is set by the user and adjusted in b43_phy_xmitpower(). */ + u8 power_level; + /* A-PHY TX Power control value. */ + u16 txpwr_offset; + + /* Current TX power level attenuation control values */ + struct b43_bbatt bbatt; + struct b43_rfatt rfatt; + u8 tx_control; /* B43_TXCTL_XXX */ +#ifdef CONFIG_B43_DEBUG + bool manual_txpower_control; /* Manual TX-power control enabled? */ +#endif + /* Hardware Power Control enabled? */ + bool hardware_power_control; + + /* Current Interference Mitigation mode */ + int interfmode; + /* Stack of saved values from the Interference Mitigation code. + * Each value in the stack is layed out as follows: + * bit 0-11: offset + * bit 12-15: register ID + * bit 16-32: value + * register ID is: 0x1 PHY, 0x2 Radio, 0x3 ILT + */ +#define B43_INTERFSTACK_SIZE 26 + u32 interfstack[B43_INTERFSTACK_SIZE]; //FIXME: use a data structure + + /* Saved values from the NRSSI Slope calculation */ + s16 nrssi[2]; + s32 nrssislope; + /* In memory nrssi lookup table. */ + s8 nrssi_lt[64]; + + /* current channel */ + u8 channel; + + u16 lofcal; + + u16 initval; //FIXME rename? +}; + +/* Data structures for DMA transmission, per 80211 core. */ +struct b43_dma { + struct b43_dmaring *tx_ring0; + struct b43_dmaring *tx_ring1; + struct b43_dmaring *tx_ring2; + struct b43_dmaring *tx_ring3; + struct b43_dmaring *tx_ring4; + struct b43_dmaring *tx_ring5; + + struct b43_dmaring *rx_ring0; + struct b43_dmaring *rx_ring3; /* only available on core.rev < 5 */ +}; + +/* Data structures for PIO transmission, per 80211 core. */ +struct b43_pio { + struct b43_pioqueue *queue0; + struct b43_pioqueue *queue1; + struct b43_pioqueue *queue2; + struct b43_pioqueue *queue3; +}; + +/* Context information for a noise calculation (Link Quality). */ +struct b43_noise_calculation { + u8 channel_at_start; + bool calculation_running; + u8 nr_samples; + s8 samples[8][4]; +}; + +struct b43_stats { + u8 link_noise; + /* Store the last TX/RX times here for updating the leds. */ + unsigned long last_tx; + unsigned long last_rx; +}; + +struct b43_key { + /* If keyconf is NULL, this key is disabled. + * keyconf is a cookie. Don't derefenrence it outside of the set_key + * path, because b43 doesn't own it. */ + struct ieee80211_key_conf *keyconf; + u8 algorithm; +}; + +struct b43_wldev; + +/* Data structure for the WLAN parts (802.11 cores) of the b43 chip. */ +struct b43_wl { + /* Pointer to the active wireless device on this chip */ + struct b43_wldev *current_dev; + /* Pointer to the ieee80211 hardware data structure */ + struct ieee80211_hw *hw; + + spinlock_t irq_lock; + struct mutex mutex; + spinlock_t leds_lock; + + /* We can only have one operating interface (802.11 core) + * at a time. General information about this interface follows. + */ + + /* Opaque ID of the operating interface (!= monitor + * interface) from the ieee80211 subsystem. + * Do not modify. + */ + int if_id; + /* The MAC address of the operating interface. */ + u8 mac_addr[ETH_ALEN]; + /* Current BSSID */ + u8 bssid[ETH_ALEN]; + /* Interface type. (IEEE80211_IF_TYPE_XXX) */ + int if_type; + /* Counter of active monitor interfaces. */ + int monitor; + /* Is the card operating in AP, STA or IBSS mode? */ + bool operating; + /* Promisc mode active? + * Note that (monitor != 0) implies promisc. + */ + bool promisc; + /* Stats about the wireless interface */ + struct ieee80211_low_level_stats ieee_stats; + + struct hwrng rng; + u8 rng_initialized; + char rng_name[30 + 1]; + + /* List of all wireless devices on this chip */ + struct list_head devlist; + u8 nr_devs; +}; + +/* Pointers to the firmware data and meta information about it. */ +struct b43_firmware { + /* Microcode */ + const struct firmware *ucode; + /* PCM code */ + const struct firmware *pcm; + /* Initial MMIO values for the firmware */ + const struct firmware *initvals; + /* Initial MMIO values for the firmware, band-specific */ + const struct firmware *initvals_band; + /* Firmware revision */ + u16 rev; + /* Firmware patchlevel */ + u16 patch; +}; + +/* Device (802.11 core) initialization status. */ +enum { + B43_STAT_UNINIT = 0, /* Uninitialized. */ + B43_STAT_INITIALIZED = 1, /* Initialized, but not started, yet. */ + B43_STAT_STARTED = 2, /* Up and running. */ +}; +#define b43_status(wldev) atomic_read(&(wldev)->__init_status) +#define b43_set_status(wldev, stat) do { \ + atomic_set(&(wldev)->__init_status, (stat)); \ + smp_wmb(); \ + } while (0) + +/* XXX--- HOW LOCKING WORKS IN B43 ---XXX + * + * You should always acquire both, wl->mutex and wl->irq_lock unless: + * - You don't need to acquire wl->irq_lock, if the interface is stopped. + * - You don't need to acquire wl->mutex in the IRQ handler, IRQ tasklet + * and packet TX path (and _ONLY_ there.) + */ + +/* Data structure for one wireless device (802.11 core) */ +struct b43_wldev { + struct ssb_device *dev; + struct b43_wl *wl; + + /* The device initialization status. + * Use b43_status() to query. */ + atomic_t __init_status; + /* Saved init status for handling suspend. */ + int suspend_init_status; + + bool __using_pio; /* Internal, use b43_using_pio(). */ + bool bad_frames_preempt; /* Use "Bad Frames Preemption" (default off) */ + bool reg124_set_0x4; /* Some variable to keep track of IRQ stuff. */ + bool short_preamble; /* TRUE, if short preamble is enabled. */ + bool short_slot; /* TRUE, if short slot timing is enabled. */ + bool radio_hw_enable; /* saved state of radio hardware enabled state */ + + /* PHY/Radio device. */ + struct b43_phy phy; + union { + /* DMA engines. */ + struct b43_dma dma; + /* PIO engines. */ + struct b43_pio pio; + }; + + /* Various statistics about the physical device. */ + struct b43_stats stats; + +#define B43_NR_LEDS 4 + struct b43_led leds[B43_NR_LEDS]; + + /* Reason code of the last interrupt. */ + u32 irq_reason; + u32 dma_reason[6]; + /* saved irq enable/disable state bitfield. */ + u32 irq_savedstate; + /* Link Quality calculation context. */ + struct b43_noise_calculation noisecalc; + /* if > 0 MAC is suspended. if == 0 MAC is enabled. */ + int mac_suspended; + + /* Interrupt Service Routine tasklet (bottom-half) */ + struct tasklet_struct isr_tasklet; + + /* Periodic tasks */ + struct delayed_work periodic_work; + unsigned int periodic_state; + + struct work_struct restart_work; + + /* encryption/decryption */ + u16 ktp; /* Key table pointer */ + u8 max_nr_keys; + struct b43_key key[58]; + + /* Cached beacon template while uploading the template. */ + struct sk_buff *cached_beacon; + + /* Firmware data */ + struct b43_firmware fw; + + /* Devicelist in struct b43_wl (all 802.11 cores) */ + struct list_head list; + + /* Debugging stuff follows. */ +#ifdef CONFIG_B43_DEBUG + struct b43_dfsentry *dfsentry; +#endif +}; + +static inline struct b43_wl *hw_to_b43_wl(struct ieee80211_hw *hw) +{ + return hw->priv; +} + +/* Helper function, which returns a boolean. + * TRUE, if PIO is used; FALSE, if DMA is used. + */ +#if defined(CONFIG_B43_DMA) && defined(CONFIG_B43_PIO) +static inline int b43_using_pio(struct b43_wldev *dev) +{ + return dev->__using_pio; +} +#elif defined(CONFIG_B43_DMA) +static inline int b43_using_pio(struct b43_wldev *dev) +{ + return 0; +} +#elif defined(CONFIG_B43_PIO) +static inline int b43_using_pio(struct b43_wldev *dev) +{ + return 1; +} +#else +# error "Using neither DMA nor PIO? Confused..." +#endif + +static inline struct b43_wldev *dev_to_b43_wldev(struct device *dev) +{ + struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); + return ssb_get_drvdata(ssb_dev); +} + +/* Is the device operating in a specified mode (IEEE80211_IF_TYPE_XXX). */ +static inline int b43_is_mode(struct b43_wl *wl, int type) +{ + if (type == IEEE80211_IF_TYPE_MNTR) + return !!(wl->monitor); + return (wl->operating && wl->if_type == type); +} + +static inline u16 b43_read16(struct b43_wldev *dev, u16 offset) +{ + return ssb_read16(dev->dev, offset); +} + +static inline void b43_write16(struct b43_wldev *dev, u16 offset, u16 value) +{ + ssb_write16(dev->dev, offset, value); +} + +static inline u32 b43_read32(struct b43_wldev *dev, u16 offset) +{ + return ssb_read32(dev->dev, offset); +} + +static inline void b43_write32(struct b43_wldev *dev, u16 offset, u32 value) +{ + ssb_write32(dev->dev, offset, value); +} + +/* Message printing */ +void b43info(struct b43_wl *wl, const char *fmt, ...) + __attribute__ ((format(printf, 2, 3))); +void b43err(struct b43_wl *wl, const char *fmt, ...) + __attribute__ ((format(printf, 2, 3))); +void b43warn(struct b43_wl *wl, const char *fmt, ...) + __attribute__ ((format(printf, 2, 3))); +#if B43_DEBUG +void b43dbg(struct b43_wl *wl, const char *fmt, ...) + __attribute__ ((format(printf, 2, 3))); +#else /* DEBUG */ +# define b43dbg(wl, fmt...) do { /* nothing */ } while (0) +#endif /* DEBUG */ + +/* A WARN_ON variant that vanishes when b43 debugging is disabled. + * This _also_ evaluates the arg with debugging disabled. */ +#if B43_DEBUG +# define B43_WARN_ON(x) WARN_ON(x) +#else +static inline bool __b43_warn_on_dummy(bool x) { return x; } +# define B43_WARN_ON(x) __b43_warn_on_dummy(unlikely(!!(x))) +#endif + +/** Limit a value between two limits */ +#ifdef limit_value +# undef limit_value +#endif +#define limit_value(value, min, max) \ + ({ \ + typeof(value) __value = (value); \ + typeof(value) __min = (min); \ + typeof(value) __max = (max); \ + if (__value < __min) \ + __value = __min; \ + else if (__value > __max) \ + __value = __max; \ + __value; \ + }) + +/* Convert an integer to a Q5.2 value */ +#define INT_TO_Q52(i) ((i) << 2) +/* Convert a Q5.2 value to an integer (precision loss!) */ +#define Q52_TO_INT(q52) ((q52) >> 2) +/* Macros for printing a value in Q5.2 format */ +#define Q52_FMT "%u.%u" +#define Q52_ARG(q52) Q52_TO_INT(q52), ((((q52) & 0x3) * 100) / 4) + +#endif /* B43_H_ */ diff --git a/drivers/net/wireless/b43/debugfs.c b/drivers/net/wireless/b43/debugfs.c new file mode 100644 index 00000000000..f82e3ef9bd7 --- /dev/null +++ b/drivers/net/wireless/b43/debugfs.c @@ -0,0 +1,654 @@ +/* + + Broadcom B43 wireless driver + + debugfs driver debugging code + + Copyright (c) 2005-2007 Michael Buesch + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include +#include +#include +#include +#include +#include + +#include "b43.h" +#include "main.h" +#include "debugfs.h" +#include "dma.h" +#include "pio.h" +#include "xmit.h" + + +/* The root directory. */ +struct dentry *rootdir; + +struct b43_debugfs_fops { + ssize_t (*read)(struct b43_wldev *dev, char *buf, size_t bufsize); + int (*write)(struct b43_wldev *dev, const char *buf, size_t count); + struct file_operations fops; + /* Offset of struct b43_dfs_file in struct b43_dfsentry */ + size_t file_struct_offset; + /* Take wl->irq_lock before calling read/write? */ + bool take_irqlock; +}; + +static inline +struct b43_dfs_file * fops_to_dfs_file(struct b43_wldev *dev, + const struct b43_debugfs_fops *dfops) +{ + void *p; + + p = dev->dfsentry; + p += dfops->file_struct_offset; + + return p; +} + + +#define fappend(fmt, x...) \ + do { \ + if (bufsize - count) \ + count += snprintf(buf + count, \ + bufsize - count, \ + fmt , ##x); \ + else \ + printk(KERN_ERR "b43: fappend overflow\n"); \ + } while (0) + + +/* wl->irq_lock is locked */ +ssize_t tsf_read_file(struct b43_wldev *dev, char *buf, size_t bufsize) +{ + ssize_t count = 0; + u64 tsf; + + b43_tsf_read(dev, &tsf); + fappend("0x%08x%08x\n", + (unsigned int)((tsf & 0xFFFFFFFF00000000ULL) >> 32), + (unsigned int)(tsf & 0xFFFFFFFFULL)); + + return count; +} + +/* wl->irq_lock is locked */ +int tsf_write_file(struct b43_wldev *dev, const char *buf, size_t count) +{ + u64 tsf; + + if (sscanf(buf, "%llu", (unsigned long long *)(&tsf)) != 1) + return -EINVAL; + b43_tsf_write(dev, tsf); + + return 0; +} + +/* wl->irq_lock is locked */ +ssize_t ucode_regs_read_file(struct b43_wldev *dev, char *buf, size_t bufsize) +{ + ssize_t count = 0; + int i; + + for (i = 0; i < 64; i++) { + fappend("r%d = 0x%04x\n", i, + b43_shm_read16(dev, B43_SHM_SCRATCH, i)); + } + + return count; +} + +/* wl->irq_lock is locked */ +ssize_t shm_read_file(struct b43_wldev *dev, char *buf, size_t bufsize) +{ + ssize_t count = 0; + int i; + u16 tmp; + __le16 *le16buf = (__le16 *)buf; + + for (i = 0; i < 0x1000; i++) { + if (bufsize <= 0) + break; + tmp = b43_shm_read16(dev, B43_SHM_SHARED, 2 * i); + le16buf[i] = cpu_to_le16(tmp); + count += sizeof(tmp); + bufsize -= sizeof(tmp); + } + + return count; +} + +ssize_t txstat_read_file(struct b43_wldev *dev, char *buf, size_t bufsize) +{ + struct b43_txstatus_log *log = &dev->dfsentry->txstatlog; + ssize_t count = 0; + unsigned long flags; + int i, idx; + struct b43_txstatus *stat; + + spin_lock_irqsave(&log->lock, flags); + if (log->end < 0) { + fappend("Nothing transmitted, yet\n"); + goto out_unlock; + } + fappend("b43 TX status reports:\n\n" + "index | cookie | seq | phy_stat | frame_count | " + "rts_count | supp_reason | pm_indicated | " + "intermediate | for_ampdu | acked\n" "---\n"); + i = log->end + 1; + idx = 0; + while (1) { + if (i == B43_NR_LOGGED_TXSTATUS) + i = 0; + stat = &(log->log[i]); + if (stat->cookie) { + fappend("%03d | " + "0x%04X | 0x%04X | 0x%02X | " + "0x%X | 0x%X | " + "%u | %u | " + "%u | %u | %u\n", + idx, + stat->cookie, stat->seq, stat->phy_stat, + stat->frame_count, stat->rts_count, + stat->supp_reason, stat->pm_indicated, + stat->intermediate, stat->for_ampdu, + stat->acked); + idx++; + } + if (i == log->end) + break; + i++; + } +out_unlock: + spin_unlock_irqrestore(&log->lock, flags); + + return count; +} + +ssize_t txpower_g_read_file(struct b43_wldev *dev, char *buf, size_t bufsize) +{ + ssize_t count = 0; + + if (dev->phy.type != B43_PHYTYPE_G) { + fappend("Device is not a G-PHY\n"); + goto out; + } + fappend("Control: %s\n", dev->phy.manual_txpower_control ? + "MANUAL" : "AUTOMATIC"); + fappend("Baseband attenuation: %u\n", dev->phy.bbatt.att); + fappend("Radio attenuation: %u\n", dev->phy.rfatt.att); + fappend("TX Mixer Gain: %s\n", + (dev->phy.tx_control & B43_TXCTL_TXMIX) ? "ON" : "OFF"); + fappend("PA Gain 2dB: %s\n", + (dev->phy.tx_control & B43_TXCTL_PA2DB) ? "ON" : "OFF"); + fappend("PA Gain 3dB: %s\n", + (dev->phy.tx_control & B43_TXCTL_PA3DB) ? "ON" : "OFF"); + fappend("\n\n"); + fappend("You can write to this file:\n"); + fappend("Writing \"auto\" enables automatic txpower control.\n"); + fappend + ("Writing the attenuation values as \"bbatt rfatt txmix pa2db pa3db\" " + "enables manual txpower control.\n"); + fappend("Example: 5 4 0 0 1\n"); + fappend("Enables manual control with Baseband attenuation 5, " + "Radio attenuation 4, No TX Mixer Gain, " + "No PA Gain 2dB, With PA Gain 3dB.\n"); +out: + return count; +} + +int txpower_g_write_file(struct b43_wldev *dev, const char *buf, size_t count) +{ + unsigned long flags; + unsigned long phy_flags; + int err = 0; + + spin_lock_irqsave(&dev->wl->irq_lock, flags); + if (dev->phy.type != B43_PHYTYPE_G) { + err = -ENODEV; + goto out_unlock; + } + if ((count >= 4) && (memcmp(buf, "auto", 4) == 0)) { + /* Automatic control */ + dev->phy.manual_txpower_control = 0; + b43_phy_xmitpower(dev); + } else { + int bbatt = 0, rfatt = 0, txmix = 0, pa2db = 0, pa3db = 0; + /* Manual control */ + if (sscanf(buf, "%d %d %d %d %d", &bbatt, &rfatt, + &txmix, &pa2db, &pa3db) != 5) { + err = -EINVAL; + goto out_unlock; + } + b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt); + dev->phy.manual_txpower_control = 1; + dev->phy.bbatt.att = bbatt; + dev->phy.rfatt.att = rfatt; + dev->phy.tx_control = 0; + if (txmix) + dev->phy.tx_control |= B43_TXCTL_TXMIX; + if (pa2db) + dev->phy.tx_control |= B43_TXCTL_PA2DB; + if (pa3db) + dev->phy.tx_control |= B43_TXCTL_PA3DB; + b43_phy_lock(dev, phy_flags); + b43_radio_lock(dev); + b43_set_txpower_g(dev, &dev->phy.bbatt, + &dev->phy.rfatt, dev->phy.tx_control); + b43_radio_unlock(dev); + b43_phy_unlock(dev, phy_flags); + } +out_unlock: + spin_unlock_irqrestore(&dev->wl->irq_lock, flags); + + return err; +} + +/* wl->irq_lock is locked */ +int restart_write_file(struct b43_wldev *dev, const char *buf, size_t count) +{ + int err = 0; + + if (count > 0 && buf[0] == '1') { + b43_controller_restart(dev, "manually restarted"); + } else + err = -EINVAL; + + return err; +} + +static ssize_t append_lo_table(ssize_t count, char *buf, const size_t bufsize, + struct b43_loctl table[B43_NR_BB][B43_NR_RF]) +{ + unsigned int i, j; + struct b43_loctl *ctl; + + for (i = 0; i < B43_NR_BB; i++) { + for (j = 0; j < B43_NR_RF; j++) { + ctl = &(table[i][j]); + fappend("(bbatt %2u, rfatt %2u) -> " + "(I %+3d, Q %+3d, Used: %d, Calibrated: %d)\n", + i, j, ctl->i, ctl->q, + ctl->used, + b43_loctl_is_calibrated(ctl)); + } + } + + return count; +} + +ssize_t loctls_read_file(struct b43_wldev *dev, char *buf, size_t bufsize) +{ + ssize_t count = 0; + struct b43_txpower_lo_control *lo; + int i, err = 0; + + if (dev->phy.type != B43_PHYTYPE_G) { + fappend("Device is not a G-PHY\n"); + err = -ENODEV; + goto out; + } + lo = dev->phy.lo_control; + fappend("-- Local Oscillator calibration data --\n\n"); + fappend("Measured: %d, Rebuild: %d, HW-power-control: %d\n", + lo->lo_measured, + lo->rebuild, + dev->phy.hardware_power_control); + fappend("TX Bias: 0x%02X, TX Magn: 0x%02X\n", + lo->tx_bias, lo->tx_magn); + fappend("Power Vector: 0x%08X%08X\n", + (unsigned int)((lo->power_vector & 0xFFFFFFFF00000000ULL) >> 32), + (unsigned int)(lo->power_vector & 0x00000000FFFFFFFFULL)); + fappend("\nControl table WITH PADMIX:\n"); + count = append_lo_table(count, buf, bufsize, lo->with_padmix); + fappend("\nControl table WITHOUT PADMIX:\n"); + count = append_lo_table(count, buf, bufsize, lo->no_padmix); + fappend("\nUsed RF attenuation values: Value(WithPadmix flag)\n"); + for (i = 0; i < lo->rfatt_list.len; i++) { + fappend("%u(%d), ", + lo->rfatt_list.list[i].att, + lo->rfatt_list.list[i].with_padmix); + } + fappend("\n"); + fappend("\nUsed Baseband attenuation values:\n"); + for (i = 0; i < lo->bbatt_list.len; i++) { + fappend("%u, ", + lo->bbatt_list.list[i].att); + } + fappend("\n"); + +out: + return err ? err : count; +} + +#undef fappend + +static int b43_debugfs_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t b43_debugfs_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct b43_wldev *dev; + struct b43_debugfs_fops *dfops; + struct b43_dfs_file *dfile; + ssize_t ret; + char *buf; + const size_t bufsize = 1024 * 128; + const size_t buforder = get_order(bufsize); + int err = 0; + + if (!count) + return 0; + dev = file->private_data; + if (!dev) + return -ENODEV; + + mutex_lock(&dev->wl->mutex); + if (b43_status(dev) < B43_STAT_INITIALIZED) { + err = -ENODEV; + goto out_unlock; + } + + dfops = container_of(file->f_op, struct b43_debugfs_fops, fops); + if (!dfops->read) { + err = -ENOSYS; + goto out_unlock; + } + dfile = fops_to_dfs_file(dev, dfops); + + if (!dfile->buffer) { + buf = (char *)__get_free_pages(GFP_KERNEL, buforder); + if (!buf) { + err = -ENOMEM; + goto out_unlock; + } + memset(buf, 0, bufsize); + if (dfops->take_irqlock) { + spin_lock_irq(&dev->wl->irq_lock); + ret = dfops->read(dev, buf, bufsize); + spin_unlock_irq(&dev->wl->irq_lock); + } else + ret = dfops->read(dev, buf, bufsize); + if (ret <= 0) { + free_pages((unsigned long)buf, buforder); + err = ret; + goto out_unlock; + } + dfile->data_len = ret; + dfile->buffer = buf; + } + + ret = simple_read_from_buffer(userbuf, count, ppos, + dfile->buffer, + dfile->data_len); + if (*ppos >= dfile->data_len) { + free_pages((unsigned long)dfile->buffer, buforder); + dfile->buffer = NULL; + dfile->data_len = 0; + } +out_unlock: + mutex_unlock(&dev->wl->mutex); + + return err ? err : ret; +} + +static ssize_t b43_debugfs_write(struct file *file, + const char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct b43_wldev *dev; + struct b43_debugfs_fops *dfops; + char *buf; + int err = 0; + + if (!count) + return 0; + if (count > PAGE_SIZE) + return -E2BIG; + dev = file->private_data; + if (!dev) + return -ENODEV; + + mutex_lock(&dev->wl->mutex); + if (b43_status(dev) < B43_STAT_INITIALIZED) { + err = -ENODEV; + goto out_unlock; + } + + dfops = container_of(file->f_op, struct b43_debugfs_fops, fops); + if (!dfops->write) { + err = -ENOSYS; + goto out_unlock; + } + + buf = (char *)get_zeroed_page(GFP_KERNEL); + if (!buf) { + err = -ENOMEM; + goto out_unlock; + } + if (copy_from_user(buf, userbuf, count)) { + err = -EFAULT; + goto out_freepage; + } + if (dfops->take_irqlock) { + spin_lock_irq(&dev->wl->irq_lock); + err = dfops->write(dev, buf, count); + spin_unlock_irq(&dev->wl->irq_lock); + } else + err = dfops->write(dev, buf, count); + if (err) + goto out_freepage; + +out_freepage: + free_page((unsigned long)buf); +out_unlock: + mutex_unlock(&dev->wl->mutex); + + return err ? err : count; +} + + +#define B43_DEBUGFS_FOPS(name, _read, _write, _take_irqlock) \ + static struct b43_debugfs_fops fops_##name = { \ + .read = _read, \ + .write = _write, \ + .fops = { \ + .open = b43_debugfs_open, \ + .read = b43_debugfs_read, \ + .write = b43_debugfs_write, \ + }, \ + .file_struct_offset = offsetof(struct b43_dfsentry, \ + file_##name), \ + .take_irqlock = _take_irqlock, \ + } + +B43_DEBUGFS_FOPS(tsf, tsf_read_file, tsf_write_file, 1); +B43_DEBUGFS_FOPS(ucode_regs, ucode_regs_read_file, NULL, 1); +B43_DEBUGFS_FOPS(shm, shm_read_file, NULL, 1); +B43_DEBUGFS_FOPS(txstat, txstat_read_file, NULL, 0); +B43_DEBUGFS_FOPS(txpower_g, txpower_g_read_file, txpower_g_write_file, 0); +B43_DEBUGFS_FOPS(restart, NULL, restart_write_file, 1); +B43_DEBUGFS_FOPS(loctls, loctls_read_file, NULL, 0); + + +int b43_debug(struct b43_wldev *dev, enum b43_dyndbg feature) +{ + return !!(dev->dfsentry && dev->dfsentry->dyn_debug[feature]); +} + +static void b43_remove_dynamic_debug(struct b43_wldev *dev) +{ + struct b43_dfsentry *e = dev->dfsentry; + int i; + + for (i = 0; i < __B43_NR_DYNDBG; i++) + debugfs_remove(e->dyn_debug_dentries[i]); +} + +static void b43_add_dynamic_debug(struct b43_wldev *dev) +{ + struct b43_dfsentry *e = dev->dfsentry; + struct dentry *d; + +#define add_dyn_dbg(name, id, initstate) do { \ + e->dyn_debug[id] = (initstate); \ + d = debugfs_create_bool(name, 0600, e->subdir, \ + &(e->dyn_debug[id])); \ + if (!IS_ERR(d)) \ + e->dyn_debug_dentries[id] = d; \ + } while (0) + + add_dyn_dbg("debug_xmitpower", B43_DBG_XMITPOWER, 0); + add_dyn_dbg("debug_dmaoverflow", B43_DBG_DMAOVERFLOW, 0); + add_dyn_dbg("debug_dmaverbose", B43_DBG_DMAVERBOSE, 0); + add_dyn_dbg("debug_pwork_fast", B43_DBG_PWORK_FAST, 0); + add_dyn_dbg("debug_pwork_stop", B43_DBG_PWORK_STOP, 0); + +#undef add_dyn_dbg +} + +void b43_debugfs_add_device(struct b43_wldev *dev) +{ + struct b43_dfsentry *e; + struct b43_txstatus_log *log; + char devdir[16]; + + B43_WARN_ON(!dev); + e = kzalloc(sizeof(*e), GFP_KERNEL); + if (!e) { + b43err(dev->wl, "debugfs: add device OOM\n"); + return; + } + e->dev = dev; + log = &e->txstatlog; + log->log = kcalloc(B43_NR_LOGGED_TXSTATUS, + sizeof(struct b43_txstatus), GFP_KERNEL); + if (!log->log) { + b43err(dev->wl, "debugfs: add device txstatus OOM\n"); + kfree(e); + return; + } + log->end = -1; + spin_lock_init(&log->lock); + + dev->dfsentry = e; + + snprintf(devdir, sizeof(devdir), "%s", wiphy_name(dev->wl->hw->wiphy)); + e->subdir = debugfs_create_dir(devdir, rootdir); + if (!e->subdir || IS_ERR(e->subdir)) { + if (e->subdir == ERR_PTR(-ENODEV)) { + b43dbg(dev->wl, "DebugFS (CONFIG_DEBUG_FS) not " + "enabled in kernel config\n"); + } else { + b43err(dev->wl, "debugfs: cannot create %s directory\n", + devdir); + } + dev->dfsentry = NULL; + kfree(log->log); + kfree(e); + return; + } + +#define ADD_FILE(name, mode) \ + do { \ + struct dentry *d; \ + d = debugfs_create_file(__stringify(name), \ + mode, e->subdir, dev, \ + &fops_##name.fops); \ + e->file_##name.dentry = NULL; \ + if (!IS_ERR(d)) \ + e->file_##name.dentry = d; \ + } while (0) + + + ADD_FILE(tsf, 0600); + ADD_FILE(ucode_regs, 0400); + ADD_FILE(shm, 0400); + ADD_FILE(txstat, 0400); + ADD_FILE(txpower_g, 0600); + ADD_FILE(restart, 0200); + ADD_FILE(loctls, 0400); + +#undef ADD_FILE + + b43_add_dynamic_debug(dev); +} + +void b43_debugfs_remove_device(struct b43_wldev *dev) +{ + struct b43_dfsentry *e; + + if (!dev) + return; + e = dev->dfsentry; + if (!e) + return; + b43_remove_dynamic_debug(dev); + + debugfs_remove(e->file_tsf.dentry); + debugfs_remove(e->file_ucode_regs.dentry); + debugfs_remove(e->file_shm.dentry); + debugfs_remove(e->file_txstat.dentry); + debugfs_remove(e->file_txpower_g.dentry); + debugfs_remove(e->file_restart.dentry); + debugfs_remove(e->file_loctls.dentry); + + debugfs_remove(e->subdir); + kfree(e->txstatlog.log); + kfree(e); +} + +void b43_debugfs_log_txstat(struct b43_wldev *dev, + const struct b43_txstatus *status) +{ + struct b43_dfsentry *e = dev->dfsentry; + struct b43_txstatus_log *log; + struct b43_txstatus *cur; + int i; + + if (!e) + return; + log = &e->txstatlog; + B43_WARN_ON(!irqs_disabled()); + spin_lock(&log->lock); + i = log->end + 1; + if (i == B43_NR_LOGGED_TXSTATUS) + i = 0; + log->end = i; + cur = &(log->log[i]); + memcpy(cur, status, sizeof(*cur)); + spin_unlock(&log->lock); +} + +void b43_debugfs_init(void) +{ + rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL); + if (IS_ERR(rootdir)) + rootdir = NULL; +} + +void b43_debugfs_exit(void) +{ + debugfs_remove(rootdir); +} diff --git a/drivers/net/wireless/b43/debugfs.h b/drivers/net/wireless/b43/debugfs.h new file mode 100644 index 00000000000..6eebe858db5 --- /dev/null +++ b/drivers/net/wireless/b43/debugfs.h @@ -0,0 +1,89 @@ +#ifndef B43_DEBUGFS_H_ +#define B43_DEBUGFS_H_ + +struct b43_wldev; +struct b43_txstatus; + +enum b43_dyndbg { /* Dynamic debugging features */ + B43_DBG_XMITPOWER, + B43_DBG_DMAOVERFLOW, + B43_DBG_DMAVERBOSE, + B43_DBG_PWORK_FAST, + B43_DBG_PWORK_STOP, + __B43_NR_DYNDBG, +}; + +#ifdef CONFIG_B43_DEBUG + +struct dentry; + +#define B43_NR_LOGGED_TXSTATUS 100 + +struct b43_txstatus_log { + struct b43_txstatus *log; + int end; + spinlock_t lock; +}; + +struct b43_dfs_file { + struct dentry *dentry; + char *buffer; + size_t data_len; +}; + +struct b43_dfsentry { + struct b43_wldev *dev; + struct dentry *subdir; + + struct b43_dfs_file file_tsf; + struct b43_dfs_file file_ucode_regs; + struct b43_dfs_file file_shm; + struct b43_dfs_file file_txstat; + struct b43_dfs_file file_txpower_g; + struct b43_dfs_file file_restart; + struct b43_dfs_file file_loctls; + + struct b43_txstatus_log txstatlog; + + /* Enabled/Disabled list for the dynamic debugging features. */ + u32 dyn_debug[__B43_NR_DYNDBG]; + /* Dentries for the dynamic debugging entries. */ + struct dentry *dyn_debug_dentries[__B43_NR_DYNDBG]; +}; + +int b43_debug(struct b43_wldev *dev, enum b43_dyndbg feature); + +void b43_debugfs_init(void); +void b43_debugfs_exit(void); +void b43_debugfs_add_device(struct b43_wldev *dev); +void b43_debugfs_remove_device(struct b43_wldev *dev); +void b43_debugfs_log_txstat(struct b43_wldev *dev, + const struct b43_txstatus *status); + +#else /* CONFIG_B43_DEBUG */ + +static inline int b43_debug(struct b43_wldev *dev, enum b43_dyndbg feature) +{ + return 0; +} + +static inline void b43_debugfs_init(void) +{ +} +static inline void b43_debugfs_exit(void) +{ +} +static inline void b43_debugfs_add_device(struct b43_wldev *dev) +{ +} +static inline void b43_debugfs_remove_device(struct b43_wldev *dev) +{ +} +static inline void b43_debugfs_log_txstat(struct b43_wldev *dev, + const struct b43_txstatus *status) +{ +} + +#endif /* CONFIG_B43_DEBUG */ + +#endif /* B43_DEBUGFS_H_ */ diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c new file mode 100644 index 00000000000..5e8f8ac0f1d --- /dev/null +++ b/drivers/net/wireless/b43/dma.c @@ -0,0 +1,1494 @@ +/* + + Broadcom B43 wireless driver + + DMA ringbuffer and descriptor allocation/management + + Copyright (c) 2005, 2006 Michael Buesch + + Some code in this file is derived from the b44.c driver + Copyright (C) 2002 David S. Miller + Copyright (C) Pekka Pietikainen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "b43.h" +#include "dma.h" +#include "main.h" +#include "debugfs.h" +#include "xmit.h" + +#include +#include +#include +#include + +/* 32bit DMA ops. */ +static +struct b43_dmadesc_generic *op32_idx2desc(struct b43_dmaring *ring, + int slot, + struct b43_dmadesc_meta **meta) +{ + struct b43_dmadesc32 *desc; + + *meta = &(ring->meta[slot]); + desc = ring->descbase; + desc = &(desc[slot]); + + return (struct b43_dmadesc_generic *)desc; +} + +static void op32_fill_descriptor(struct b43_dmaring *ring, + struct b43_dmadesc_generic *desc, + dma_addr_t dmaaddr, u16 bufsize, + int start, int end, int irq) +{ + struct b43_dmadesc32 *descbase = ring->descbase; + int slot; + u32 ctl; + u32 addr; + u32 addrext; + + slot = (int)(&(desc->dma32) - descbase); + B43_WARN_ON(!(slot >= 0 && slot < ring->nr_slots)); + + addr = (u32) (dmaaddr & ~SSB_DMA_TRANSLATION_MASK); + addrext = (u32) (dmaaddr & SSB_DMA_TRANSLATION_MASK) + >> SSB_DMA_TRANSLATION_SHIFT; + addr |= ssb_dma_translation(ring->dev->dev); + ctl = (bufsize - ring->frameoffset) + & B43_DMA32_DCTL_BYTECNT; + if (slot == ring->nr_slots - 1) + ctl |= B43_DMA32_DCTL_DTABLEEND; + if (start) + ctl |= B43_DMA32_DCTL_FRAMESTART; + if (end) + ctl |= B43_DMA32_DCTL_FRAMEEND; + if (irq) + ctl |= B43_DMA32_DCTL_IRQ; + ctl |= (addrext << B43_DMA32_DCTL_ADDREXT_SHIFT) + & B43_DMA32_DCTL_ADDREXT_MASK; + + desc->dma32.control = cpu_to_le32(ctl); + desc->dma32.address = cpu_to_le32(addr); +} + +static void op32_poke_tx(struct b43_dmaring *ring, int slot) +{ + b43_dma_write(ring, B43_DMA32_TXINDEX, + (u32) (slot * sizeof(struct b43_dmadesc32))); +} + +static void op32_tx_suspend(struct b43_dmaring *ring) +{ + b43_dma_write(ring, B43_DMA32_TXCTL, b43_dma_read(ring, B43_DMA32_TXCTL) + | B43_DMA32_TXSUSPEND); +} + +static void op32_tx_resume(struct b43_dmaring *ring) +{ + b43_dma_write(ring, B43_DMA32_TXCTL, b43_dma_read(ring, B43_DMA32_TXCTL) + & ~B43_DMA32_TXSUSPEND); +} + +static int op32_get_current_rxslot(struct b43_dmaring *ring) +{ + u32 val; + + val = b43_dma_read(ring, B43_DMA32_RXSTATUS); + val &= B43_DMA32_RXDPTR; + + return (val / sizeof(struct b43_dmadesc32)); +} + +static void op32_set_current_rxslot(struct b43_dmaring *ring, int slot) +{ + b43_dma_write(ring, B43_DMA32_RXINDEX, + (u32) (slot * sizeof(struct b43_dmadesc32))); +} + +static const struct b43_dma_ops dma32_ops = { + .idx2desc = op32_idx2desc, + .fill_descriptor = op32_fill_descriptor, + .poke_tx = op32_poke_tx, + .tx_suspend = op32_tx_suspend, + .tx_resume = op32_tx_resume, + .get_current_rxslot = op32_get_current_rxslot, + .set_current_rxslot = op32_set_current_rxslot, +}; + +/* 64bit DMA ops. */ +static +struct b43_dmadesc_generic *op64_idx2desc(struct b43_dmaring *ring, + int slot, + struct b43_dmadesc_meta **meta) +{ + struct b43_dmadesc64 *desc; + + *meta = &(ring->meta[slot]); + desc = ring->descbase; + desc = &(desc[slot]); + + return (struct b43_dmadesc_generic *)desc; +} + +static void op64_fill_descriptor(struct b43_dmaring *ring, + struct b43_dmadesc_generic *desc, + dma_addr_t dmaaddr, u16 bufsize, + int start, int end, int irq) +{ + struct b43_dmadesc64 *descbase = ring->descbase; + int slot; + u32 ctl0 = 0, ctl1 = 0; + u32 addrlo, addrhi; + u32 addrext; + + slot = (int)(&(desc->dma64) - descbase); + B43_WARN_ON(!(slot >= 0 && slot < ring->nr_slots)); + + addrlo = (u32) (dmaaddr & 0xFFFFFFFF); + addrhi = (((u64) dmaaddr >> 32) & ~SSB_DMA_TRANSLATION_MASK); + addrext = (((u64) dmaaddr >> 32) & SSB_DMA_TRANSLATION_MASK) + >> SSB_DMA_TRANSLATION_SHIFT; + addrhi |= ssb_dma_translation(ring->dev->dev); + if (slot == ring->nr_slots - 1) + ctl0 |= B43_DMA64_DCTL0_DTABLEEND; + if (start) + ctl0 |= B43_DMA64_DCTL0_FRAMESTART; + if (end) + ctl0 |= B43_DMA64_DCTL0_FRAMEEND; + if (irq) + ctl0 |= B43_DMA64_DCTL0_IRQ; + ctl1 |= (bufsize - ring->frameoffset) + & B43_DMA64_DCTL1_BYTECNT; + ctl1 |= (addrext << B43_DMA64_DCTL1_ADDREXT_SHIFT) + & B43_DMA64_DCTL1_ADDREXT_MASK; + + desc->dma64.control0 = cpu_to_le32(ctl0); + desc->dma64.control1 = cpu_to_le32(ctl1); + desc->dma64.address_low = cpu_to_le32(addrlo); + desc->dma64.address_high = cpu_to_le32(addrhi); +} + +static void op64_poke_tx(struct b43_dmaring *ring, int slot) +{ + b43_dma_write(ring, B43_DMA64_TXINDEX, + (u32) (slot * sizeof(struct b43_dmadesc64))); +} + +static void op64_tx_suspend(struct b43_dmaring *ring) +{ + b43_dma_write(ring, B43_DMA64_TXCTL, b43_dma_read(ring, B43_DMA64_TXCTL) + | B43_DMA64_TXSUSPEND); +} + +static void op64_tx_resume(struct b43_dmaring *ring) +{ + b43_dma_write(ring, B43_DMA64_TXCTL, b43_dma_read(ring, B43_DMA64_TXCTL) + & ~B43_DMA64_TXSUSPEND); +} + +static int op64_get_current_rxslot(struct b43_dmaring *ring) +{ + u32 val; + + val = b43_dma_read(ring, B43_DMA64_RXSTATUS); + val &= B43_DMA64_RXSTATDPTR; + + return (val / sizeof(struct b43_dmadesc64)); +} + +static void op64_set_current_rxslot(struct b43_dmaring *ring, int slot) +{ + b43_dma_write(ring, B43_DMA64_RXINDEX, + (u32) (slot * sizeof(struct b43_dmadesc64))); +} + +static const struct b43_dma_ops dma64_ops = { + .idx2desc = op64_idx2desc, + .fill_descriptor = op64_fill_descriptor, + .poke_tx = op64_poke_tx, + .tx_suspend = op64_tx_suspend, + .tx_resume = op64_tx_resume, + .get_current_rxslot = op64_get_current_rxslot, + .set_current_rxslot = op64_set_current_rxslot, +}; + +static inline int free_slots(struct b43_dmaring *ring) +{ + return (ring->nr_slots - ring->used_slots); +} + +static inline int next_slot(struct b43_dmaring *ring, int slot) +{ + B43_WARN_ON(!(slot >= -1 && slot <= ring->nr_slots - 1)); + if (slot == ring->nr_slots - 1) + return 0; + return slot + 1; +} + +static inline int prev_slot(struct b43_dmaring *ring, int slot) +{ + B43_WARN_ON(!(slot >= 0 && slot <= ring->nr_slots - 1)); + if (slot == 0) + return ring->nr_slots - 1; + return slot - 1; +} + +#ifdef CONFIG_B43_DEBUG +static void update_max_used_slots(struct b43_dmaring *ring, + int current_used_slots) +{ + if (current_used_slots <= ring->max_used_slots) + return; + ring->max_used_slots = current_used_slots; + if (b43_debug(ring->dev, B43_DBG_DMAVERBOSE)) { + b43dbg(ring->dev->wl, + "max_used_slots increased to %d on %s ring %d\n", + ring->max_used_slots, + ring->tx ? "TX" : "RX", ring->index); + } +} +#else +static inline + void update_max_used_slots(struct b43_dmaring *ring, int current_used_slots) +{ +} +#endif /* DEBUG */ + +/* Request a slot for usage. */ +static inline int request_slot(struct b43_dmaring *ring) +{ + int slot; + + B43_WARN_ON(!ring->tx); + B43_WARN_ON(ring->stopped); + B43_WARN_ON(free_slots(ring) == 0); + + slot = next_slot(ring, ring->current_slot); + ring->current_slot = slot; + ring->used_slots++; + + update_max_used_slots(ring, ring->used_slots); + + return slot; +} + +/* Mac80211-queue to b43-ring mapping */ +static struct b43_dmaring *priority_to_txring(struct b43_wldev *dev, + int queue_priority) +{ + struct b43_dmaring *ring; + +/*FIXME: For now we always run on TX-ring-1 */ + return dev->dma.tx_ring1; + + /* 0 = highest priority */ + switch (queue_priority) { + default: + B43_WARN_ON(1); + /* fallthrough */ + case 0: + ring = dev->dma.tx_ring3; + break; + case 1: + ring = dev->dma.tx_ring2; + break; + case 2: + ring = dev->dma.tx_ring1; + break; + case 3: + ring = dev->dma.tx_ring0; + break; + case 4: + ring = dev->dma.tx_ring4; + break; + case 5: + ring = dev->dma.tx_ring5; + break; + } + + return ring; +} + +/* Bcm43xx-ring to mac80211-queue mapping */ +static inline int txring_to_priority(struct b43_dmaring *ring) +{ + static const u8 idx_to_prio[] = { 3, 2, 1, 0, 4, 5, }; + +/*FIXME: have only one queue, for now */ + return 0; + + return idx_to_prio[ring->index]; +} + +u16 b43_dmacontroller_base(int dma64bit, int controller_idx) +{ + static const u16 map64[] = { + B43_MMIO_DMA64_BASE0, + B43_MMIO_DMA64_BASE1, + B43_MMIO_DMA64_BASE2, + B43_MMIO_DMA64_BASE3, + B43_MMIO_DMA64_BASE4, + B43_MMIO_DMA64_BASE5, + }; + static const u16 map32[] = { + B43_MMIO_DMA32_BASE0, + B43_MMIO_DMA32_BASE1, + B43_MMIO_DMA32_BASE2, + B43_MMIO_DMA32_BASE3, + B43_MMIO_DMA32_BASE4, + B43_MMIO_DMA32_BASE5, + }; + + if (dma64bit) { + B43_WARN_ON(!(controller_idx >= 0 && + controller_idx < ARRAY_SIZE(map64))); + return map64[controller_idx]; + } + B43_WARN_ON(!(controller_idx >= 0 && + controller_idx < ARRAY_SIZE(map32))); + return map32[controller_idx]; +} + +static inline + dma_addr_t map_descbuffer(struct b43_dmaring *ring, + unsigned char *buf, size_t len, int tx) +{ + dma_addr_t dmaaddr; + + if (tx) { + dmaaddr = dma_map_single(ring->dev->dev->dev, + buf, len, DMA_TO_DEVICE); + } else { + dmaaddr = dma_map_single(ring->dev->dev->dev, + buf, len, DMA_FROM_DEVICE); + } + + return dmaaddr; +} + +static inline + void unmap_descbuffer(struct b43_dmaring *ring, + dma_addr_t addr, size_t len, int tx) +{ + if (tx) { + dma_unmap_single(ring->dev->dev->dev, addr, len, DMA_TO_DEVICE); + } else { + dma_unmap_single(ring->dev->dev->dev, + addr, len, DMA_FROM_DEVICE); + } +} + +static inline + void sync_descbuffer_for_cpu(struct b43_dmaring *ring, + dma_addr_t addr, size_t len) +{ + B43_WARN_ON(ring->tx); + dma_sync_single_for_cpu(ring->dev->dev->dev, + addr, len, DMA_FROM_DEVICE); +} + +static inline + void sync_descbuffer_for_device(struct b43_dmaring *ring, + dma_addr_t addr, size_t len) +{ + B43_WARN_ON(ring->tx); + dma_sync_single_for_device(ring->dev->dev->dev, + addr, len, DMA_FROM_DEVICE); +} + +static inline + void free_descriptor_buffer(struct b43_dmaring *ring, + struct b43_dmadesc_meta *meta) +{ + if (meta->skb) { + dev_kfree_skb_any(meta->skb); + meta->skb = NULL; + } +} + +static int alloc_ringmemory(struct b43_dmaring *ring) +{ + struct device *dev = ring->dev->dev->dev; + + ring->descbase = dma_alloc_coherent(dev, B43_DMA_RINGMEMSIZE, + &(ring->dmabase), GFP_KERNEL); + if (!ring->descbase) { + b43err(ring->dev->wl, "DMA ringmemory allocation failed\n"); + return -ENOMEM; + } + memset(ring->descbase, 0, B43_DMA_RINGMEMSIZE); + + return 0; +} + +static void free_ringmemory(struct b43_dmaring *ring) +{ + struct device *dev = ring->dev->dev->dev; + + dma_free_coherent(dev, B43_DMA_RINGMEMSIZE, + ring->descbase, ring->dmabase); +} + +/* Reset the RX DMA channel */ +int b43_dmacontroller_rx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64) +{ + int i; + u32 value; + u16 offset; + + might_sleep(); + + offset = dma64 ? B43_DMA64_RXCTL : B43_DMA32_RXCTL; + b43_write32(dev, mmio_base + offset, 0); + for (i = 0; i < 10; i++) { + offset = dma64 ? B43_DMA64_RXSTATUS : B43_DMA32_RXSTATUS; + value = b43_read32(dev, mmio_base + offset); + if (dma64) { + value &= B43_DMA64_RXSTAT; + if (value == B43_DMA64_RXSTAT_DISABLED) { + i = -1; + break; + } + } else { + value &= B43_DMA32_RXSTATE; + if (value == B43_DMA32_RXSTAT_DISABLED) { + i = -1; + break; + } + } + msleep(1); + } + if (i != -1) { + b43err(dev->wl, "DMA RX reset timed out\n"); + return -ENODEV; + } + + return 0; +} + +/* Reset the RX DMA channel */ +int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64) +{ + int i; + u32 value; + u16 offset; + + might_sleep(); + + for (i = 0; i < 10; i++) { + offset = dma64 ? B43_DMA64_TXSTATUS : B43_DMA32_TXSTATUS; + value = b43_read32(dev, mmio_base + offset); + if (dma64) { + value &= B43_DMA64_TXSTAT; + if (value == B43_DMA64_TXSTAT_DISABLED || + value == B43_DMA64_TXSTAT_IDLEWAIT || + value == B43_DMA64_TXSTAT_STOPPED) + break; + } else { + value &= B43_DMA32_TXSTATE; + if (value == B43_DMA32_TXSTAT_DISABLED || + value == B43_DMA32_TXSTAT_IDLEWAIT || + value == B43_DMA32_TXSTAT_STOPPED) + break; + } + msleep(1); + } + offset = dma64 ? B43_DMA64_TXCTL : B43_DMA32_TXCTL; + b43_write32(dev, mmio_base + offset, 0); + for (i = 0; i < 10; i++) { + offset = dma64 ? B43_DMA64_TXSTATUS : B43_DMA32_TXSTATUS; + value = b43_read32(dev, mmio_base + offset); + if (dma64) { + value &= B43_DMA64_TXSTAT; + if (value == B43_DMA64_TXSTAT_DISABLED) { + i = -1; + break; + } + } else { + value &= B43_DMA32_TXSTATE; + if (value == B43_DMA32_TXSTAT_DISABLED) { + i = -1; + break; + } + } + msleep(1); + } + if (i != -1) { + b43err(dev->wl, "DMA TX reset timed out\n"); + return -ENODEV; + } + /* ensure the reset is completed. */ + msleep(1); + + return 0; +} + +static int setup_rx_descbuffer(struct b43_dmaring *ring, + struct b43_dmadesc_generic *desc, + struct b43_dmadesc_meta *meta, gfp_t gfp_flags) +{ + struct b43_rxhdr_fw4 *rxhdr; + struct b43_hwtxstatus *txstat; + dma_addr_t dmaaddr; + struct sk_buff *skb; + + B43_WARN_ON(ring->tx); + + skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags); + if (unlikely(!skb)) + return -ENOMEM; + dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0); + if (dma_mapping_error(dmaaddr)) { + /* ugh. try to realloc in zone_dma */ + gfp_flags |= GFP_DMA; + + dev_kfree_skb_any(skb); + + skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags); + if (unlikely(!skb)) + return -ENOMEM; + dmaaddr = map_descbuffer(ring, skb->data, + ring->rx_buffersize, 0); + } + + if (dma_mapping_error(dmaaddr)) { + dev_kfree_skb_any(skb); + return -EIO; + } + + meta->skb = skb; + meta->dmaaddr = dmaaddr; + ring->ops->fill_descriptor(ring, desc, dmaaddr, + ring->rx_buffersize, 0, 0, 0); + + rxhdr = (struct b43_rxhdr_fw4 *)(skb->data); + rxhdr->frame_len = 0; + txstat = (struct b43_hwtxstatus *)(skb->data); + txstat->cookie = 0; + + return 0; +} + +/* Allocate the initial descbuffers. + * This is used for an RX ring only. + */ +static int alloc_initial_descbuffers(struct b43_dmaring *ring) +{ + int i, err = -ENOMEM; + struct b43_dmadesc_generic *desc; + struct b43_dmadesc_meta *meta; + + for (i = 0; i < ring->nr_slots; i++) { + desc = ring->ops->idx2desc(ring, i, &meta); + + err = setup_rx_descbuffer(ring, desc, meta, GFP_KERNEL); + if (err) { + b43err(ring->dev->wl, + "Failed to allocate initial descbuffers\n"); + goto err_unwind; + } + } + mb(); + ring->used_slots = ring->nr_slots; + err = 0; + out: + return err; + + err_unwind: + for (i--; i >= 0; i--) { + desc = ring->ops->idx2desc(ring, i, &meta); + + unmap_descbuffer(ring, meta->dmaaddr, ring->rx_buffersize, 0); + dev_kfree_skb(meta->skb); + } + goto out; +} + +/* Do initial setup of the DMA controller. + * Reset the controller, write the ring busaddress + * and switch the "enable" bit on. + */ +static int dmacontroller_setup(struct b43_dmaring *ring) +{ + int err = 0; + u32 value; + u32 addrext; + u32 trans = ssb_dma_translation(ring->dev->dev); + + if (ring->tx) { + if (ring->dma64) { + u64 ringbase = (u64) (ring->dmabase); + + addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK) + >> SSB_DMA_TRANSLATION_SHIFT; + value = B43_DMA64_TXENABLE; + value |= (addrext << B43_DMA64_TXADDREXT_SHIFT) + & B43_DMA64_TXADDREXT_MASK; + b43_dma_write(ring, B43_DMA64_TXCTL, value); + b43_dma_write(ring, B43_DMA64_TXRINGLO, + (ringbase & 0xFFFFFFFF)); + b43_dma_write(ring, B43_DMA64_TXRINGHI, + ((ringbase >> 32) & + ~SSB_DMA_TRANSLATION_MASK) + | trans); + } else { + u32 ringbase = (u32) (ring->dmabase); + + addrext = (ringbase & SSB_DMA_TRANSLATION_MASK) + >> SSB_DMA_TRANSLATION_SHIFT; + value = B43_DMA32_TXENABLE; + value |= (addrext << B43_DMA32_TXADDREXT_SHIFT) + & B43_DMA32_TXADDREXT_MASK; + b43_dma_write(ring, B43_DMA32_TXCTL, value); + b43_dma_write(ring, B43_DMA32_TXRING, + (ringbase & ~SSB_DMA_TRANSLATION_MASK) + | trans); + } + } else { + err = alloc_initial_descbuffers(ring); + if (err) + goto out; + if (ring->dma64) { + u64 ringbase = (u64) (ring->dmabase); + + addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK) + >> SSB_DMA_TRANSLATION_SHIFT; + value = (ring->frameoffset << B43_DMA64_RXFROFF_SHIFT); + value |= B43_DMA64_RXENABLE; + value |= (addrext << B43_DMA64_RXADDREXT_SHIFT) + & B43_DMA64_RXADDREXT_MASK; + b43_dma_write(ring, B43_DMA64_RXCTL, value); + b43_dma_write(ring, B43_DMA64_RXRINGLO, + (ringbase & 0xFFFFFFFF)); + b43_dma_write(ring, B43_DMA64_RXRINGHI, + ((ringbase >> 32) & + ~SSB_DMA_TRANSLATION_MASK) + | trans); + b43_dma_write(ring, B43_DMA64_RXINDEX, 200); + } else { + u32 ringbase = (u32) (ring->dmabase); + + addrext = (ringbase & SSB_DMA_TRANSLATION_MASK) + >> SSB_DMA_TRANSLATION_SHIFT; + value = (ring->frameoffset << B43_DMA32_RXFROFF_SHIFT); + value |= B43_DMA32_RXENABLE; + value |= (addrext << B43_DMA32_RXADDREXT_SHIFT) + & B43_DMA32_RXADDREXT_MASK; + b43_dma_write(ring, B43_DMA32_RXCTL, value); + b43_dma_write(ring, B43_DMA32_RXRING, + (ringbase & ~SSB_DMA_TRANSLATION_MASK) + | trans); + b43_dma_write(ring, B43_DMA32_RXINDEX, 200); + } + } + + out: + return err; +} + +/* Shutdown the DMA controller. */ +static void dmacontroller_cleanup(struct b43_dmaring *ring) +{ + if (ring->tx) { + b43_dmacontroller_tx_reset(ring->dev, ring->mmio_base, + ring->dma64); + if (ring->dma64) { + b43_dma_write(ring, B43_DMA64_TXRINGLO, 0); + b43_dma_write(ring, B43_DMA64_TXRINGHI, 0); + } else + b43_dma_write(ring, B43_DMA32_TXRING, 0); + } else { + b43_dmacontroller_rx_reset(ring->dev, ring->mmio_base, + ring->dma64); + if (ring->dma64) { + b43_dma_write(ring, B43_DMA64_RXRINGLO, 0); + b43_dma_write(ring, B43_DMA64_RXRINGHI, 0); + } else + b43_dma_write(ring, B43_DMA32_RXRING, 0); + } +} + +static void free_all_descbuffers(struct b43_dmaring *ring) +{ + struct b43_dmadesc_generic *desc; + struct b43_dmadesc_meta *meta; + int i; + + if (!ring->used_slots) + return; + for (i = 0; i < ring->nr_slots; i++) { + desc = ring->ops->idx2desc(ring, i, &meta); + + if (!meta->skb) { + B43_WARN_ON(!ring->tx); + continue; + } + if (ring->tx) { + unmap_descbuffer(ring, meta->dmaaddr, + meta->skb->len, 1); + } else { + unmap_descbuffer(ring, meta->dmaaddr, + ring->rx_buffersize, 0); + } + free_descriptor_buffer(ring, meta); + } +} + +static u64 supported_dma_mask(struct b43_wldev *dev) +{ + u32 tmp; + u16 mmio_base; + + tmp = b43_read32(dev, SSB_TMSHIGH); + if (tmp & SSB_TMSHIGH_DMA64) + return DMA_64BIT_MASK; + mmio_base = b43_dmacontroller_base(0, 0); + b43_write32(dev, mmio_base + B43_DMA32_TXCTL, B43_DMA32_TXADDREXT_MASK); + tmp = b43_read32(dev, mmio_base + B43_DMA32_TXCTL); + if (tmp & B43_DMA32_TXADDREXT_MASK) + return DMA_32BIT_MASK; + + return DMA_30BIT_MASK; +} + +/* Main initialization function. */ +static +struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, + int controller_index, + int for_tx, int dma64) +{ + struct b43_dmaring *ring; + int err; + int nr_slots; + dma_addr_t dma_test; + + ring = kzalloc(sizeof(*ring), GFP_KERNEL); + if (!ring) + goto out; + + nr_slots = B43_RXRING_SLOTS; + if (for_tx) + nr_slots = B43_TXRING_SLOTS; + + ring->meta = kcalloc(nr_slots, sizeof(struct b43_dmadesc_meta), + GFP_KERNEL); + if (!ring->meta) + goto err_kfree_ring; + if (for_tx) { + ring->txhdr_cache = kcalloc(nr_slots, + sizeof(struct b43_txhdr_fw4), + GFP_KERNEL); + if (!ring->txhdr_cache) + goto err_kfree_meta; + + /* test for ability to dma to txhdr_cache */ + dma_test = dma_map_single(dev->dev->dev, + ring->txhdr_cache, + sizeof(struct b43_txhdr_fw4), + DMA_TO_DEVICE); + + if (dma_mapping_error(dma_test)) { + /* ugh realloc */ + kfree(ring->txhdr_cache); + ring->txhdr_cache = kcalloc(nr_slots, + sizeof(struct + b43_txhdr_fw4), + GFP_KERNEL | GFP_DMA); + if (!ring->txhdr_cache) + goto err_kfree_meta; + + dma_test = dma_map_single(dev->dev->dev, + ring->txhdr_cache, + sizeof(struct b43_txhdr_fw4), + DMA_TO_DEVICE); + + if (dma_mapping_error(dma_test)) + goto err_kfree_txhdr_cache; + } + + dma_unmap_single(dev->dev->dev, + dma_test, sizeof(struct b43_txhdr_fw4), + DMA_TO_DEVICE); + } + + ring->dev = dev; + ring->nr_slots = nr_slots; + ring->mmio_base = b43_dmacontroller_base(dma64, controller_index); + ring->index = controller_index; + ring->dma64 = !!dma64; + if (dma64) + ring->ops = &dma64_ops; + else + ring->ops = &dma32_ops; + if (for_tx) { + ring->tx = 1; + ring->current_slot = -1; + } else { + if (ring->index == 0) { + ring->rx_buffersize = B43_DMA0_RX_BUFFERSIZE; + ring->frameoffset = B43_DMA0_RX_FRAMEOFFSET; + } else if (ring->index == 3) { + ring->rx_buffersize = B43_DMA3_RX_BUFFERSIZE; + ring->frameoffset = B43_DMA3_RX_FRAMEOFFSET; + } else + B43_WARN_ON(1); + } + spin_lock_init(&ring->lock); +#ifdef CONFIG_B43_DEBUG + ring->last_injected_overflow = jiffies; +#endif + + err = alloc_ringmemory(ring); + if (err) + goto err_kfree_txhdr_cache; + err = dmacontroller_setup(ring); + if (err) + goto err_free_ringmemory; + + out: + return ring; + + err_free_ringmemory: + free_ringmemory(ring); + err_kfree_txhdr_cache: + kfree(ring->txhdr_cache); + err_kfree_meta: + kfree(ring->meta); + err_kfree_ring: + kfree(ring); + ring = NULL; + goto out; +} + +/* Main cleanup function. */ +static void b43_destroy_dmaring(struct b43_dmaring *ring) +{ + if (!ring) + return; + + b43dbg(ring->dev->wl, "DMA-%s 0x%04X (%s) max used slots: %d/%d\n", + (ring->dma64) ? "64" : "32", + ring->mmio_base, + (ring->tx) ? "TX" : "RX", ring->max_used_slots, ring->nr_slots); + /* Device IRQs are disabled prior entering this function, + * so no need to take care of concurrency with rx handler stuff. + */ + dmacontroller_cleanup(ring); + free_all_descbuffers(ring); + free_ringmemory(ring); + + kfree(ring->txhdr_cache); + kfree(ring->meta); + kfree(ring); +} + +void b43_dma_free(struct b43_wldev *dev) +{ + struct b43_dma *dma; + + if (b43_using_pio(dev)) + return; + dma = &dev->dma; + + b43_destroy_dmaring(dma->rx_ring3); + dma->rx_ring3 = NULL; + b43_destroy_dmaring(dma->rx_ring0); + dma->rx_ring0 = NULL; + + b43_destroy_dmaring(dma->tx_ring5); + dma->tx_ring5 = NULL; + b43_destroy_dmaring(dma->tx_ring4); + dma->tx_ring4 = NULL; + b43_destroy_dmaring(dma->tx_ring3); + dma->tx_ring3 = NULL; + b43_destroy_dmaring(dma->tx_ring2); + dma->tx_ring2 = NULL; + b43_destroy_dmaring(dma->tx_ring1); + dma->tx_ring1 = NULL; + b43_destroy_dmaring(dma->tx_ring0); + dma->tx_ring0 = NULL; +} + +int b43_dma_init(struct b43_wldev *dev) +{ + struct b43_dma *dma = &dev->dma; + struct b43_dmaring *ring; + int err; + u64 dmamask; + int dma64 = 0; + + dmamask = supported_dma_mask(dev); + if (dmamask == DMA_64BIT_MASK) + dma64 = 1; + + err = ssb_dma_set_mask(dev->dev, dmamask); + if (err) { +#ifdef B43_PIO + b43warn(dev->wl, "DMA for this device not supported. " + "Falling back to PIO\n"); + dev->__using_pio = 1; + return -EAGAIN; +#else + b43err(dev->wl, "DMA for this device not supported and " + "no PIO support compiled in\n"); + return -EOPNOTSUPP; +#endif + } + + err = -ENOMEM; + /* setup TX DMA channels. */ + ring = b43_setup_dmaring(dev, 0, 1, dma64); + if (!ring) + goto out; + dma->tx_ring0 = ring; + + ring = b43_setup_dmaring(dev, 1, 1, dma64); + if (!ring) + goto err_destroy_tx0; + dma->tx_ring1 = ring; + + ring = b43_setup_dmaring(dev, 2, 1, dma64); + if (!ring) + goto err_destroy_tx1; + dma->tx_ring2 = ring; + + ring = b43_setup_dmaring(dev, 3, 1, dma64); + if (!ring) + goto err_destroy_tx2; + dma->tx_ring3 = ring; + + ring = b43_setup_dmaring(dev, 4, 1, dma64); + if (!ring) + goto err_destroy_tx3; + dma->tx_ring4 = ring; + + ring = b43_setup_dmaring(dev, 5, 1, dma64); + if (!ring) + goto err_destroy_tx4; + dma->tx_ring5 = ring; + + /* setup RX DMA channels. */ + ring = b43_setup_dmaring(dev, 0, 0, dma64); + if (!ring) + goto err_destroy_tx5; + dma->rx_ring0 = ring; + + if (dev->dev->id.revision < 5) { + ring = b43_setup_dmaring(dev, 3, 0, dma64); + if (!ring) + goto err_destroy_rx0; + dma->rx_ring3 = ring; + } + + b43dbg(dev->wl, "%d-bit DMA initialized\n", + (dmamask == DMA_64BIT_MASK) ? 64 : + (dmamask == DMA_32BIT_MASK) ? 32 : 30); + err = 0; + out: + return err; + + err_destroy_rx0: + b43_destroy_dmaring(dma->rx_ring0); + dma->rx_ring0 = NULL; + err_destroy_tx5: + b43_destroy_dmaring(dma->tx_ring5); + dma->tx_ring5 = NULL; + err_destroy_tx4: + b43_destroy_dmaring(dma->tx_ring4); + dma->tx_ring4 = NULL; + err_destroy_tx3: + b43_destroy_dmaring(dma->tx_ring3); + dma->tx_ring3 = NULL; + err_destroy_tx2: + b43_destroy_dmaring(dma->tx_ring2); + dma->tx_ring2 = NULL; + err_destroy_tx1: + b43_destroy_dmaring(dma->tx_ring1); + dma->tx_ring1 = NULL; + err_destroy_tx0: + b43_destroy_dmaring(dma->tx_ring0); + dma->tx_ring0 = NULL; + goto out; +} + +/* Generate a cookie for the TX header. */ +static u16 generate_cookie(struct b43_dmaring *ring, int slot) +{ + u16 cookie = 0x1000; + + /* Use the upper 4 bits of the cookie as + * DMA controller ID and store the slot number + * in the lower 12 bits. + * Note that the cookie must never be 0, as this + * is a special value used in RX path. + */ + switch (ring->index) { + case 0: + cookie = 0xA000; + break; + case 1: + cookie = 0xB000; + break; + case 2: + cookie = 0xC000; + break; + case 3: + cookie = 0xD000; + break; + case 4: + cookie = 0xE000; + break; + case 5: + cookie = 0xF000; + break; + } + B43_WARN_ON(slot & ~0x0FFF); + cookie |= (u16) slot; + + return cookie; +} + +/* Inspect a cookie and find out to which controller/slot it belongs. */ +static +struct b43_dmaring *parse_cookie(struct b43_wldev *dev, u16 cookie, int *slot) +{ + struct b43_dma *dma = &dev->dma; + struct b43_dmaring *ring = NULL; + + switch (cookie & 0xF000) { + case 0xA000: + ring = dma->tx_ring0; + break; + case 0xB000: + ring = dma->tx_ring1; + break; + case 0xC000: + ring = dma->tx_ring2; + break; + case 0xD000: + ring = dma->tx_ring3; + break; + case 0xE000: + ring = dma->tx_ring4; + break; + case 0xF000: + ring = dma->tx_ring5; + break; + default: + B43_WARN_ON(1); + } + *slot = (cookie & 0x0FFF); + B43_WARN_ON(!(ring && *slot >= 0 && *slot < ring->nr_slots)); + + return ring; +} + +static int dma_tx_fragment(struct b43_dmaring *ring, + struct sk_buff *skb, + struct ieee80211_tx_control *ctl) +{ + const struct b43_dma_ops *ops = ring->ops; + u8 *header; + int slot; + int err; + struct b43_dmadesc_generic *desc; + struct b43_dmadesc_meta *meta; + struct b43_dmadesc_meta *meta_hdr; + struct sk_buff *bounce_skb; + +#define SLOTS_PER_PACKET 2 + B43_WARN_ON(skb_shinfo(skb)->nr_frags); + + /* Get a slot for the header. */ + slot = request_slot(ring); + desc = ops->idx2desc(ring, slot, &meta_hdr); + memset(meta_hdr, 0, sizeof(*meta_hdr)); + + header = &(ring->txhdr_cache[slot * sizeof(struct b43_txhdr_fw4)]); + b43_generate_txhdr(ring->dev, header, + skb->data, skb->len, ctl, + generate_cookie(ring, slot)); + + meta_hdr->dmaaddr = map_descbuffer(ring, (unsigned char *)header, + sizeof(struct b43_txhdr_fw4), 1); + if (dma_mapping_error(meta_hdr->dmaaddr)) + return -EIO; + ops->fill_descriptor(ring, desc, meta_hdr->dmaaddr, + sizeof(struct b43_txhdr_fw4), 1, 0, 0); + + /* Get a slot for the payload. */ + slot = request_slot(ring); + desc = ops->idx2desc(ring, slot, &meta); + memset(meta, 0, sizeof(*meta)); + + memcpy(&meta->txstat.control, ctl, sizeof(*ctl)); + meta->skb = skb; + meta->is_last_fragment = 1; + + meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); + /* create a bounce buffer in zone_dma on mapping failure. */ + if (dma_mapping_error(meta->dmaaddr)) { + bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA); + if (!bounce_skb) { + err = -ENOMEM; + goto out_unmap_hdr; + } + + memcpy(skb_put(bounce_skb, skb->len), skb->data, skb->len); + dev_kfree_skb_any(skb); + skb = bounce_skb; + meta->skb = skb; + meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); + if (dma_mapping_error(meta->dmaaddr)) { + err = -EIO; + goto out_free_bounce; + } + } + + ops->fill_descriptor(ring, desc, meta->dmaaddr, skb->len, 0, 1, 1); + + /* Now transfer the whole frame. */ + wmb(); + ops->poke_tx(ring, next_slot(ring, slot)); + return 0; + + out_free_bounce: + dev_kfree_skb_any(skb); + out_unmap_hdr: + unmap_descbuffer(ring, meta_hdr->dmaaddr, + sizeof(struct b43_txhdr_fw4), 1); + return err; +} + +static inline int should_inject_overflow(struct b43_dmaring *ring) +{ +#ifdef CONFIG_B43_DEBUG + if (unlikely(b43_debug(ring->dev, B43_DBG_DMAOVERFLOW))) { + /* Check if we should inject another ringbuffer overflow + * to test handling of this situation in the stack. */ + unsigned long next_overflow; + + next_overflow = ring->last_injected_overflow + HZ; + if (time_after(jiffies, next_overflow)) { + ring->last_injected_overflow = jiffies; + b43dbg(ring->dev->wl, + "Injecting TX ring overflow on " + "DMA controller %d\n", ring->index); + return 1; + } + } +#endif /* CONFIG_B43_DEBUG */ + return 0; +} + +int b43_dma_tx(struct b43_wldev *dev, + struct sk_buff *skb, struct ieee80211_tx_control *ctl) +{ + struct b43_dmaring *ring; + int err = 0; + unsigned long flags; + + ring = priority_to_txring(dev, ctl->queue); + spin_lock_irqsave(&ring->lock, flags); + B43_WARN_ON(!ring->tx); + if (unlikely(free_slots(ring) < SLOTS_PER_PACKET)) { + b43warn(dev->wl, "DMA queue overflow\n"); + err = -ENOSPC; + goto out_unlock; + } + /* Check if the queue was stopped in mac80211, + * but we got called nevertheless. + * That would be a mac80211 bug. */ + B43_WARN_ON(ring->stopped); + + err = dma_tx_fragment(ring, skb, ctl); + if (unlikely(err)) { + b43err(dev->wl, "DMA tx mapping failure\n"); + goto out_unlock; + } + ring->nr_tx_packets++; + if ((free_slots(ring) < SLOTS_PER_PACKET) || + should_inject_overflow(ring)) { + /* This TX ring is full. */ + ieee80211_stop_queue(dev->wl->hw, txring_to_priority(ring)); + ring->stopped = 1; + if (b43_debug(dev, B43_DBG_DMAVERBOSE)) { + b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index); + } + } + out_unlock: + spin_unlock_irqrestore(&ring->lock, flags); + + return err; +} + +void b43_dma_handle_txstatus(struct b43_wldev *dev, + const struct b43_txstatus *status) +{ + const struct b43_dma_ops *ops; + struct b43_dmaring *ring; + struct b43_dmadesc_generic *desc; + struct b43_dmadesc_meta *meta; + int slot; + + ring = parse_cookie(dev, status->cookie, &slot); + if (unlikely(!ring)) + return; + B43_WARN_ON(!irqs_disabled()); + spin_lock(&ring->lock); + + B43_WARN_ON(!ring->tx); + ops = ring->ops; + while (1) { + B43_WARN_ON(!(slot >= 0 && slot < ring->nr_slots)); + desc = ops->idx2desc(ring, slot, &meta); + + if (meta->skb) + unmap_descbuffer(ring, meta->dmaaddr, meta->skb->len, + 1); + else + unmap_descbuffer(ring, meta->dmaaddr, + sizeof(struct b43_txhdr_fw4), 1); + + if (meta->is_last_fragment) { + B43_WARN_ON(!meta->skb); + /* Call back to inform the ieee80211 subsystem about the + * status of the transmission. + * Some fields of txstat are already filled in dma_tx(). + */ + if (status->acked) { + meta->txstat.flags |= IEEE80211_TX_STATUS_ACK; + } else { + if (!(meta->txstat.control.flags + & IEEE80211_TXCTL_NO_ACK)) + meta->txstat.excessive_retries = 1; + } + if (status->frame_count == 0) { + /* The frame was not transmitted at all. */ + meta->txstat.retry_count = 0; + } else + meta->txstat.retry_count = status->frame_count - 1; + ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb, + &(meta->txstat)); + /* skb is freed by ieee80211_tx_status_irqsafe() */ + meta->skb = NULL; + } else { + /* No need to call free_descriptor_buffer here, as + * this is only the txhdr, which is not allocated. + */ + B43_WARN_ON(meta->skb); + } + + /* Everything unmapped and free'd. So it's not used anymore. */ + ring->used_slots--; + + if (meta->is_last_fragment) + break; + slot = next_slot(ring, slot); + } + dev->stats.last_tx = jiffies; + if (ring->stopped) { + B43_WARN_ON(free_slots(ring) < SLOTS_PER_PACKET); + ieee80211_wake_queue(dev->wl->hw, txring_to_priority(ring)); + ring->stopped = 0; + if (b43_debug(dev, B43_DBG_DMAVERBOSE)) { + b43dbg(dev->wl, "Woke up TX ring %d\n", ring->index); + } + } + + spin_unlock(&ring->lock); +} + +void b43_dma_get_tx_stats(struct b43_wldev *dev, + struct ieee80211_tx_queue_stats *stats) +{ + const int nr_queues = dev->wl->hw->queues; + struct b43_dmaring *ring; + struct ieee80211_tx_queue_stats_data *data; + unsigned long flags; + int i; + + for (i = 0; i < nr_queues; i++) { + data = &(stats->data[i]); + ring = priority_to_txring(dev, i); + + spin_lock_irqsave(&ring->lock, flags); + data->len = ring->used_slots / SLOTS_PER_PACKET; + data->limit = ring->nr_slots / SLOTS_PER_PACKET; + data->count = ring->nr_tx_packets; + spin_unlock_irqrestore(&ring->lock, flags); + } +} + +static void dma_rx(struct b43_dmaring *ring, int *slot) +{ + const struct b43_dma_ops *ops = ring->ops; + struct b43_dmadesc_generic *desc; + struct b43_dmadesc_meta *meta; + struct b43_rxhdr_fw4 *rxhdr; + struct sk_buff *skb; + u16 len; + int err; + dma_addr_t dmaaddr; + + desc = ops->idx2desc(ring, *slot, &meta); + + sync_descbuffer_for_cpu(ring, meta->dmaaddr, ring->rx_buffersize); + skb = meta->skb; + + if (ring->index == 3) { + /* We received an xmit status. */ + struct b43_hwtxstatus *hw = (struct b43_hwtxstatus *)skb->data; + int i = 0; + + while (hw->cookie == 0) { + if (i > 100) + break; + i++; + udelay(2); + barrier(); + } + b43_handle_hwtxstatus(ring->dev, hw); + /* recycle the descriptor buffer. */ + sync_descbuffer_for_device(ring, meta->dmaaddr, + ring->rx_buffersize); + + return; + } + rxhdr = (struct b43_rxhdr_fw4 *)skb->data; + len = le16_to_cpu(rxhdr->frame_len); + if (len == 0) { + int i = 0; + + do { + udelay(2); + barrier(); + len = le16_to_cpu(rxhdr->frame_len); + } while (len == 0 && i++ < 5); + if (unlikely(len == 0)) { + /* recycle the descriptor buffer. */ + sync_descbuffer_for_device(ring, meta->dmaaddr, + ring->rx_buffersize); + goto drop; + } + } + if (unlikely(len > ring->rx_buffersize)) { + /* The data did not fit into one descriptor buffer + * and is split over multiple buffers. + * This should never happen, as we try to allocate buffers + * big enough. So simply ignore this packet. + */ + int cnt = 0; + s32 tmp = len; + + while (1) { + desc = ops->idx2desc(ring, *slot, &meta); + /* recycle the descriptor buffer. */ + sync_descbuffer_for_device(ring, meta->dmaaddr, + ring->rx_buffersize); + *slot = next_slot(ring, *slot); + cnt++; + tmp -= ring->rx_buffersize; + if (tmp <= 0) + break; + } + b43err(ring->dev->wl, "DMA RX buffer too small " + "(len: %u, buffer: %u, nr-dropped: %d)\n", + len, ring->rx_buffersize, cnt); + goto drop; + } + + dmaaddr = meta->dmaaddr; + err = setup_rx_descbuffer(ring, desc, meta, GFP_ATOMIC); + if (unlikely(err)) { + b43dbg(ring->dev->wl, "DMA RX: setup_rx_descbuffer() failed\n"); + sync_descbuffer_for_device(ring, dmaaddr, ring->rx_buffersize); + goto drop; + } + + unmap_descbuffer(ring, dmaaddr, ring->rx_buffersize, 0); + skb_put(skb, len + ring->frameoffset); + skb_pull(skb, ring->frameoffset); + + b43_rx(ring->dev, skb, rxhdr); + drop: + return; +} + +void b43_dma_rx(struct b43_dmaring *ring) +{ + const struct b43_dma_ops *ops = ring->ops; + int slot, current_slot; + int used_slots = 0; + + B43_WARN_ON(ring->tx); + current_slot = ops->get_current_rxslot(ring); + B43_WARN_ON(!(current_slot >= 0 && current_slot < ring->nr_slots)); + + slot = ring->current_slot; + for (; slot != current_slot; slot = next_slot(ring, slot)) { + dma_rx(ring, &slot); + update_max_used_slots(ring, ++used_slots); + } + ops->set_current_rxslot(ring, slot); + ring->current_slot = slot; +} + +static void b43_dma_tx_suspend_ring(struct b43_dmaring *ring) +{ + unsigned long flags; + + spin_lock_irqsave(&ring->lock, flags); + B43_WARN_ON(!ring->tx); + ring->ops->tx_suspend(ring); + spin_unlock_irqrestore(&ring->lock, flags); +} + +static void b43_dma_tx_resume_ring(struct b43_dmaring *ring) +{ + unsigned long flags; + + spin_lock_irqsave(&ring->lock, flags); + B43_WARN_ON(!ring->tx); + ring->ops->tx_resume(ring); + spin_unlock_irqrestore(&ring->lock, flags); +} + +void b43_dma_tx_suspend(struct b43_wldev *dev) +{ + b43_power_saving_ctl_bits(dev, B43_PS_AWAKE); + b43_dma_tx_suspend_ring(dev->dma.tx_ring0); + b43_dma_tx_suspend_ring(dev->dma.tx_ring1); + b43_dma_tx_suspend_ring(dev->dma.tx_ring2); + b43_dma_tx_suspend_ring(dev->dma.tx_ring3); + b43_dma_tx_suspend_ring(dev->dma.tx_ring4); + b43_dma_tx_suspend_ring(dev->dma.tx_ring5); +} + +void b43_dma_tx_resume(struct b43_wldev *dev) +{ + b43_dma_tx_resume_ring(dev->dma.tx_ring5); + b43_dma_tx_resume_ring(dev->dma.tx_ring4); + b43_dma_tx_resume_ring(dev->dma.tx_ring3); + b43_dma_tx_resume_ring(dev->dma.tx_ring2); + b43_dma_tx_resume_ring(dev->dma.tx_ring1); + b43_dma_tx_resume_ring(dev->dma.tx_ring0); + b43_power_saving_ctl_bits(dev, 0); +} diff --git a/drivers/net/wireless/b43/dma.h b/drivers/net/wireless/b43/dma.h new file mode 100644 index 00000000000..3eed185be72 --- /dev/null +++ b/drivers/net/wireless/b43/dma.h @@ -0,0 +1,337 @@ +#ifndef B43_DMA_H_ +#define B43_DMA_H_ + +#include +#include +#include +#include +#include + +#include "b43.h" + +/* DMA-Interrupt reasons. */ +#define B43_DMAIRQ_FATALMASK ((1 << 10) | (1 << 11) | (1 << 12) \ + | (1 << 14) | (1 << 15)) +#define B43_DMAIRQ_NONFATALMASK (1 << 13) +#define B43_DMAIRQ_RX_DONE (1 << 16) + +/*** 32-bit DMA Engine. ***/ + +/* 32-bit DMA controller registers. */ +#define B43_DMA32_TXCTL 0x00 +#define B43_DMA32_TXENABLE 0x00000001 +#define B43_DMA32_TXSUSPEND 0x00000002 +#define B43_DMA32_TXLOOPBACK 0x00000004 +#define B43_DMA32_TXFLUSH 0x00000010 +#define B43_DMA32_TXADDREXT_MASK 0x00030000 +#define B43_DMA32_TXADDREXT_SHIFT 16 +#define B43_DMA32_TXRING 0x04 +#define B43_DMA32_TXINDEX 0x08 +#define B43_DMA32_TXSTATUS 0x0C +#define B43_DMA32_TXDPTR 0x00000FFF +#define B43_DMA32_TXSTATE 0x0000F000 +#define B43_DMA32_TXSTAT_DISABLED 0x00000000 +#define B43_DMA32_TXSTAT_ACTIVE 0x00001000 +#define B43_DMA32_TXSTAT_IDLEWAIT 0x00002000 +#define B43_DMA32_TXSTAT_STOPPED 0x00003000 +#define B43_DMA32_TXSTAT_SUSP 0x00004000 +#define B43_DMA32_TXERROR 0x000F0000 +#define B43_DMA32_TXERR_NOERR 0x00000000 +#define B43_DMA32_TXERR_PROT 0x00010000 +#define B43_DMA32_TXERR_UNDERRUN 0x00020000 +#define B43_DMA32_TXERR_BUFREAD 0x00030000 +#define B43_DMA32_TXERR_DESCREAD 0x00040000 +#define B43_DMA32_TXACTIVE 0xFFF00000 +#define B43_DMA32_RXCTL 0x10 +#define B43_DMA32_RXENABLE 0x00000001 +#define B43_DMA32_RXFROFF_MASK 0x000000FE +#define B43_DMA32_RXFROFF_SHIFT 1 +#define B43_DMA32_RXDIRECTFIFO 0x00000100 +#define B43_DMA32_RXADDREXT_MASK 0x00030000 +#define B43_DMA32_RXADDREXT_SHIFT 16 +#define B43_DMA32_RXRING 0x14 +#define B43_DMA32_RXINDEX 0x18 +#define B43_DMA32_RXSTATUS 0x1C +#define B43_DMA32_RXDPTR 0x00000FFF +#define B43_DMA32_RXSTATE 0x0000F000 +#define B43_DMA32_RXSTAT_DISABLED 0x00000000 +#define B43_DMA32_RXSTAT_ACTIVE 0x00001000 +#define B43_DMA32_RXSTAT_IDLEWAIT 0x00002000 +#define B43_DMA32_RXSTAT_STOPPED 0x00003000 +#define B43_DMA32_RXERROR 0x000F0000 +#define B43_DMA32_RXERR_NOERR 0x00000000 +#define B43_DMA32_RXERR_PROT 0x00010000 +#define B43_DMA32_RXERR_OVERFLOW 0x00020000 +#define B43_DMA32_RXERR_BUFWRITE 0x00030000 +#define B43_DMA32_RXERR_DESCREAD 0x00040000 +#define B43_DMA32_RXACTIVE 0xFFF00000 + +/* 32-bit DMA descriptor. */ +struct b43_dmadesc32 { + __le32 control; + __le32 address; +} __attribute__ ((__packed__)); +#define B43_DMA32_DCTL_BYTECNT 0x00001FFF +#define B43_DMA32_DCTL_ADDREXT_MASK 0x00030000 +#define B43_DMA32_DCTL_ADDREXT_SHIFT 16 +#define B43_DMA32_DCTL_DTABLEEND 0x10000000 +#define B43_DMA32_DCTL_IRQ 0x20000000 +#define B43_DMA32_DCTL_FRAMEEND 0x40000000 +#define B43_DMA32_DCTL_FRAMESTART 0x80000000 + +/*** 64-bit DMA Engine. ***/ + +/* 64-bit DMA controller registers. */ +#define B43_DMA64_TXCTL 0x00 +#define B43_DMA64_TXENABLE 0x00000001 +#define B43_DMA64_TXSUSPEND 0x00000002 +#define B43_DMA64_TXLOOPBACK 0x00000004 +#define B43_DMA64_TXFLUSH 0x00000010 +#define B43_DMA64_TXADDREXT_MASK 0x00030000 +#define B43_DMA64_TXADDREXT_SHIFT 16 +#define B43_DMA64_TXINDEX 0x04 +#define B43_DMA64_TXRINGLO 0x08 +#define B43_DMA64_TXRINGHI 0x0C +#define B43_DMA64_TXSTATUS 0x10 +#define B43_DMA64_TXSTATDPTR 0x00001FFF +#define B43_DMA64_TXSTAT 0xF0000000 +#define B43_DMA64_TXSTAT_DISABLED 0x00000000 +#define B43_DMA64_TXSTAT_ACTIVE 0x10000000 +#define B43_DMA64_TXSTAT_IDLEWAIT 0x20000000 +#define B43_DMA64_TXSTAT_STOPPED 0x30000000 +#define B43_DMA64_TXSTAT_SUSP 0x40000000 +#define B43_DMA64_TXERROR 0x14 +#define B43_DMA64_TXERRDPTR 0x0001FFFF +#define B43_DMA64_TXERR 0xF0000000 +#define B43_DMA64_TXERR_NOERR 0x00000000 +#define B43_DMA64_TXERR_PROT 0x10000000 +#define B43_DMA64_TXERR_UNDERRUN 0x20000000 +#define B43_DMA64_TXERR_TRANSFER 0x30000000 +#define B43_DMA64_TXERR_DESCREAD 0x40000000 +#define B43_DMA64_TXERR_CORE 0x50000000 +#define B43_DMA64_RXCTL 0x20 +#define B43_DMA64_RXENABLE 0x00000001 +#define B43_DMA64_RXFROFF_MASK 0x000000FE +#define B43_DMA64_RXFROFF_SHIFT 1 +#define B43_DMA64_RXDIRECTFIFO 0x00000100 +#define B43_DMA64_RXADDREXT_MASK 0x00030000 +#define B43_DMA64_RXADDREXT_SHIFT 16 +#define B43_DMA64_RXINDEX 0x24 +#define B43_DMA64_RXRINGLO 0x28 +#define B43_DMA64_RXRINGHI 0x2C +#define B43_DMA64_RXSTATUS 0x30 +#define B43_DMA64_RXSTATDPTR 0x00001FFF +#define B43_DMA64_RXSTAT 0xF0000000 +#define B43_DMA64_RXSTAT_DISABLED 0x00000000 +#define B43_DMA64_RXSTAT_ACTIVE 0x10000000 +#define B43_DMA64_RXSTAT_IDLEWAIT 0x20000000 +#define B43_DMA64_RXSTAT_STOPPED 0x30000000 +#define B43_DMA64_RXSTAT_SUSP 0x40000000 +#define B43_DMA64_RXERROR 0x34 +#define B43_DMA64_RXERRDPTR 0x0001FFFF +#define B43_DMA64_RXERR 0xF0000000 +#define B43_DMA64_RXERR_NOERR 0x00000000 +#define B43_DMA64_RXERR_PROT 0x10000000 +#define B43_DMA64_RXERR_UNDERRUN 0x20000000 +#define B43_DMA64_RXERR_TRANSFER 0x30000000 +#define B43_DMA64_RXERR_DESCREAD 0x40000000 +#define B43_DMA64_RXERR_CORE 0x50000000 + +/* 64-bit DMA descriptor. */ +struct b43_dmadesc64 { + __le32 control0; + __le32 control1; + __le32 address_low; + __le32 address_high; +} __attribute__ ((__packed__)); +#define B43_DMA64_DCTL0_DTABLEEND 0x10000000 +#define B43_DMA64_DCTL0_IRQ 0x20000000 +#define B43_DMA64_DCTL0_FRAMEEND 0x40000000 +#define B43_DMA64_DCTL0_FRAMESTART 0x80000000 +#define B43_DMA64_DCTL1_BYTECNT 0x00001FFF +#define B43_DMA64_DCTL1_ADDREXT_MASK 0x00030000 +#define B43_DMA64_DCTL1_ADDREXT_SHIFT 16 + +struct b43_dmadesc_generic { + union { + struct b43_dmadesc32 dma32; + struct b43_dmadesc64 dma64; + } __attribute__ ((__packed__)); +} __attribute__ ((__packed__)); + +/* Misc DMA constants */ +#define B43_DMA_RINGMEMSIZE PAGE_SIZE +#define B43_DMA0_RX_FRAMEOFFSET 30 +#define B43_DMA3_RX_FRAMEOFFSET 0 + +/* DMA engine tuning knobs */ +#define B43_TXRING_SLOTS 128 +#define B43_RXRING_SLOTS 64 +#define B43_DMA0_RX_BUFFERSIZE (2304 + 100) +#define B43_DMA3_RX_BUFFERSIZE 16 + +#ifdef CONFIG_B43_DMA + +struct sk_buff; +struct b43_private; +struct b43_txstatus; + +struct b43_dmadesc_meta { + /* The kernel DMA-able buffer. */ + struct sk_buff *skb; + /* DMA base bus-address of the descriptor buffer. */ + dma_addr_t dmaaddr; + /* ieee80211 TX status. Only used once per 802.11 frag. */ + bool is_last_fragment; + struct ieee80211_tx_status txstat; +}; + +struct b43_dmaring; + +/* Lowlevel DMA operations that differ between 32bit and 64bit DMA. */ +struct b43_dma_ops { + struct b43_dmadesc_generic *(*idx2desc) (struct b43_dmaring * ring, + int slot, + struct b43_dmadesc_meta ** + meta); + void (*fill_descriptor) (struct b43_dmaring * ring, + struct b43_dmadesc_generic * desc, + dma_addr_t dmaaddr, u16 bufsize, int start, + int end, int irq); + void (*poke_tx) (struct b43_dmaring * ring, int slot); + void (*tx_suspend) (struct b43_dmaring * ring); + void (*tx_resume) (struct b43_dmaring * ring); + int (*get_current_rxslot) (struct b43_dmaring * ring); + void (*set_current_rxslot) (struct b43_dmaring * ring, int slot); +}; + +struct b43_dmaring { + /* Lowlevel DMA ops. */ + const struct b43_dma_ops *ops; + /* Kernel virtual base address of the ring memory. */ + void *descbase; + /* Meta data about all descriptors. */ + struct b43_dmadesc_meta *meta; + /* Cache of TX headers for each slot. + * This is to avoid an allocation on each TX. + * This is NULL for an RX ring. + */ + u8 *txhdr_cache; + /* (Unadjusted) DMA base bus-address of the ring memory. */ + dma_addr_t dmabase; + /* Number of descriptor slots in the ring. */ + int nr_slots; + /* Number of used descriptor slots. */ + int used_slots; + /* Currently used slot in the ring. */ + int current_slot; + /* Total number of packets sent. Statistics only. */ + unsigned int nr_tx_packets; + /* Frameoffset in octets. */ + u32 frameoffset; + /* Descriptor buffer size. */ + u16 rx_buffersize; + /* The MMIO base register of the DMA controller. */ + u16 mmio_base; + /* DMA controller index number (0-5). */ + int index; + /* Boolean. Is this a TX ring? */ + bool tx; + /* Boolean. 64bit DMA if true, 32bit DMA otherwise. */ + bool dma64; + /* Boolean. Is this ring stopped at ieee80211 level? */ + bool stopped; + /* Lock, only used for TX. */ + spinlock_t lock; + struct b43_wldev *dev; +#ifdef CONFIG_B43_DEBUG + /* Maximum number of used slots. */ + int max_used_slots; + /* Last time we injected a ring overflow. */ + unsigned long last_injected_overflow; +#endif /* CONFIG_B43_DEBUG */ +}; + +static inline u32 b43_dma_read(struct b43_dmaring *ring, u16 offset) +{ + return b43_read32(ring->dev, ring->mmio_base + offset); +} + +static inline + void b43_dma_write(struct b43_dmaring *ring, u16 offset, u32 value) +{ + b43_write32(ring->dev, ring->mmio_base + offset, value); +} + +int b43_dma_init(struct b43_wldev *dev); +void b43_dma_free(struct b43_wldev *dev); + +int b43_dmacontroller_rx_reset(struct b43_wldev *dev, + u16 dmacontroller_mmio_base, int dma64); +int b43_dmacontroller_tx_reset(struct b43_wldev *dev, + u16 dmacontroller_mmio_base, int dma64); + +u16 b43_dmacontroller_base(int dma64bit, int dmacontroller_idx); + +void b43_dma_tx_suspend(struct b43_wldev *dev); +void b43_dma_tx_resume(struct b43_wldev *dev); + +void b43_dma_get_tx_stats(struct b43_wldev *dev, + struct ieee80211_tx_queue_stats *stats); + +int b43_dma_tx(struct b43_wldev *dev, + struct sk_buff *skb, struct ieee80211_tx_control *ctl); +void b43_dma_handle_txstatus(struct b43_wldev *dev, + const struct b43_txstatus *status); + +void b43_dma_rx(struct b43_dmaring *ring); + +#else /* CONFIG_B43_DMA */ + +static inline int b43_dma_init(struct b43_wldev *dev) +{ + return 0; +} +static inline void b43_dma_free(struct b43_wldev *dev) +{ +} +static inline + int b43_dmacontroller_rx_reset(struct b43_wldev *dev, + u16 dmacontroller_mmio_base, int dma64) +{ + return 0; +} +static inline + int b43_dmacontroller_tx_reset(struct b43_wldev *dev, + u16 dmacontroller_mmio_base, int dma64) +{ + return 0; +} +static inline + void b43_dma_get_tx_stats(struct b43_wldev *dev, + struct ieee80211_tx_queue_stats *stats) +{ +} +static inline + int b43_dma_tx(struct b43_wldev *dev, + struct sk_buff *skb, struct ieee80211_tx_control *ctl) +{ + return 0; +} +static inline + void b43_dma_handle_txstatus(struct b43_wldev *dev, + const struct b43_txstatus *status) +{ +} +static inline void b43_dma_rx(struct b43_dmaring *ring) +{ +} +static inline void b43_dma_tx_suspend(struct b43_wldev *dev) +{ +} +static inline void b43_dma_tx_resume(struct b43_wldev *dev) +{ +} + +#endif /* CONFIG_B43_DMA */ +#endif /* B43_DMA_H_ */ diff --git a/drivers/net/wireless/b43/leds.c b/drivers/net/wireless/b43/leds.c new file mode 100644 index 00000000000..535f960412d --- /dev/null +++ b/drivers/net/wireless/b43/leds.c @@ -0,0 +1,299 @@ +/* + + Broadcom B43 wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "b43.h" +#include "leds.h" +#include "main.h" + +static void b43_led_changestate(struct b43_led *led) +{ + struct b43_wldev *dev = led->dev; + const int index = b43_led_index(led); + const u16 mask = (1 << index); + u16 ledctl; + + B43_WARN_ON(!(index >= 0 && index < B43_NR_LEDS)); + B43_WARN_ON(!led->blink_interval); + ledctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL); + ledctl = (ledctl & mask) ? (ledctl & ~mask) : (ledctl | mask); + b43_write16(dev, B43_MMIO_GPIO_CONTROL, ledctl); +} + +static void b43_led_blink(unsigned long d) +{ + struct b43_led *led = (struct b43_led *)d; + struct b43_wldev *dev = led->dev; + unsigned long flags; + + spin_lock_irqsave(&dev->wl->leds_lock, flags); + if (led->blink_interval) { + b43_led_changestate(led); + mod_timer(&led->blink_timer, jiffies + led->blink_interval); + } + spin_unlock_irqrestore(&dev->wl->leds_lock, flags); +} + +static void b43_led_blink_start(struct b43_led *led, unsigned long interval) +{ + if (led->blink_interval) + return; + led->blink_interval = interval; + b43_led_changestate(led); + led->blink_timer.expires = jiffies + interval; + add_timer(&led->blink_timer); +} + +static void b43_led_blink_stop(struct b43_led *led, int sync) +{ + struct b43_wldev *dev = led->dev; + const int index = b43_led_index(led); + u16 ledctl; + + if (!led->blink_interval) + return; + if (unlikely(sync)) + del_timer_sync(&led->blink_timer); + else + del_timer(&led->blink_timer); + led->blink_interval = 0; + + /* Make sure the LED is turned off. */ + B43_WARN_ON(!(index >= 0 && index < B43_NR_LEDS)); + ledctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL); + if (led->activelow) + ledctl |= (1 << index); + else + ledctl &= ~(1 << index); + b43_write16(dev, B43_MMIO_GPIO_CONTROL, ledctl); +} + +static void b43_led_init_hardcoded(struct b43_wldev *dev, + struct b43_led *led, int led_index) +{ + struct ssb_bus *bus = dev->dev->bus; + + /* This function is called, if the behaviour (and activelow) + * information for a LED is missing in the SPROM. + * We hardcode the behaviour values for various devices here. + * Note that the B43_LED_TEST_XXX behaviour values can + * be used to figure out which led is mapped to which index. + */ + + switch (led_index) { + case 0: + led->behaviour = B43_LED_ACTIVITY; + led->activelow = 1; + if (bus->boardinfo.vendor == PCI_VENDOR_ID_COMPAQ) + led->behaviour = B43_LED_RADIO_ALL; + break; + case 1: + led->behaviour = B43_LED_RADIO_B; + if (bus->boardinfo.vendor == PCI_VENDOR_ID_ASUSTEK) + led->behaviour = B43_LED_ASSOC; + break; + case 2: + led->behaviour = B43_LED_RADIO_A; + break; + case 3: + led->behaviour = B43_LED_OFF; + break; + default: + B43_WARN_ON(1); + } +} + +int b43_leds_init(struct b43_wldev *dev) +{ + struct b43_led *led; + u8 sprom[4]; + int i; + + sprom[0] = dev->dev->bus->sprom.r1.gpio0; + sprom[1] = dev->dev->bus->sprom.r1.gpio1; + sprom[2] = dev->dev->bus->sprom.r1.gpio2; + sprom[3] = dev->dev->bus->sprom.r1.gpio3; + + for (i = 0; i < B43_NR_LEDS; i++) { + led = &(dev->leds[i]); + led->dev = dev; + setup_timer(&led->blink_timer, + b43_led_blink, (unsigned long)led); + + if (sprom[i] == 0xFF) { + b43_led_init_hardcoded(dev, led, i); + } else { + led->behaviour = sprom[i] & B43_LED_BEHAVIOUR; + led->activelow = !!(sprom[i] & B43_LED_ACTIVELOW); + } + } + + return 0; +} + +void b43_leds_exit(struct b43_wldev *dev) +{ + struct b43_led *led; + int i; + + for (i = 0; i < B43_NR_LEDS; i++) { + led = &(dev->leds[i]); + b43_led_blink_stop(led, 1); + } + b43_leds_switch_all(dev, 0); +} + +void b43_leds_update(struct b43_wldev *dev, int activity) +{ + struct b43_led *led; + struct b43_phy *phy = &dev->phy; + const int transferring = + (jiffies - dev->stats.last_tx) < B43_LED_XFER_THRES; + int i, turn_on; + unsigned long interval = 0; + u16 ledctl; + unsigned long flags; + + spin_lock_irqsave(&dev->wl->leds_lock, flags); + ledctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL); + for (i = 0; i < B43_NR_LEDS; i++) { + led = &(dev->leds[i]); + + turn_on = 0; + switch (led->behaviour) { + case B43_LED_INACTIVE: + continue; + case B43_LED_OFF: + break; + case B43_LED_ON: + turn_on = 1; + break; + case B43_LED_ACTIVITY: + turn_on = activity; + break; + case B43_LED_RADIO_ALL: + turn_on = phy->radio_on && b43_is_hw_radio_enabled(dev); + break; + case B43_LED_RADIO_A: + turn_on = (phy->radio_on && b43_is_hw_radio_enabled(dev) + && phy->type == B43_PHYTYPE_A); + break; + case B43_LED_RADIO_B: + turn_on = (phy->radio_on && b43_is_hw_radio_enabled(dev) + && (phy->type == B43_PHYTYPE_B + || phy->type == B43_PHYTYPE_G)); + break; + case B43_LED_MODE_BG: + if (phy->type == B43_PHYTYPE_G + && b43_is_hw_radio_enabled(dev) + && 1 /*FIXME: using G rates. */ ) + turn_on = 1; + break; + case B43_LED_TRANSFER: + if (transferring) + b43_led_blink_start(led, B43_LEDBLINK_MEDIUM); + else + b43_led_blink_stop(led, 0); + continue; + case B43_LED_APTRANSFER: + if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) { + if (transferring) { + interval = B43_LEDBLINK_FAST; + turn_on = 1; + } + } else { + turn_on = 1; + if (0 /*TODO: not assoc */ ) + interval = B43_LEDBLINK_SLOW; + else if (transferring) + interval = B43_LEDBLINK_FAST; + else + turn_on = 0; + } + if (turn_on) + b43_led_blink_start(led, interval); + else + b43_led_blink_stop(led, 0); + continue; + case B43_LED_WEIRD: + //TODO + break; + case B43_LED_ASSOC: + if (1 /*dev->softmac->associated */ ) + turn_on = 1; + break; +#ifdef CONFIG_B43_DEBUG + case B43_LED_TEST_BLINKSLOW: + b43_led_blink_start(led, B43_LEDBLINK_SLOW); + continue; + case B43_LED_TEST_BLINKMEDIUM: + b43_led_blink_start(led, B43_LEDBLINK_MEDIUM); + continue; + case B43_LED_TEST_BLINKFAST: + b43_led_blink_start(led, B43_LEDBLINK_FAST); + continue; +#endif /* CONFIG_B43_DEBUG */ + default: + B43_WARN_ON(1); + }; + + if (led->activelow) + turn_on = !turn_on; + if (turn_on) + ledctl |= (1 << i); + else + ledctl &= ~(1 << i); + } + b43_write16(dev, B43_MMIO_GPIO_CONTROL, ledctl); + spin_unlock_irqrestore(&dev->wl->leds_lock, flags); +} + +void b43_leds_switch_all(struct b43_wldev *dev, int on) +{ + struct b43_led *led; + u16 ledctl; + int i; + int bit_on; + unsigned long flags; + + spin_lock_irqsave(&dev->wl->leds_lock, flags); + ledctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL); + for (i = 0; i < B43_NR_LEDS; i++) { + led = &(dev->leds[i]); + if (led->behaviour == B43_LED_INACTIVE) + continue; + if (on) + bit_on = led->activelow ? 0 : 1; + else + bit_on = led->activelow ? 1 : 0; + if (bit_on) + ledctl |= (1 << i); + else + ledctl &= ~(1 << i); + } + b43_write16(dev, B43_MMIO_GPIO_CONTROL, ledctl); + spin_unlock_irqrestore(&dev->wl->leds_lock, flags); +} diff --git a/drivers/net/wireless/b43/leds.h b/drivers/net/wireless/b43/leds.h new file mode 100644 index 00000000000..36b46cfda22 --- /dev/null +++ b/drivers/net/wireless/b43/leds.h @@ -0,0 +1,55 @@ +#ifndef B43_LEDS_H_ +#define B43_LEDS_H_ + +#include +#include + +struct b43_led { + u8 behaviour:7; + u8 activelow:1; + + struct b43_wldev *dev; + struct timer_list blink_timer; + unsigned long blink_interval; +}; +#define b43_led_index(led) ((int)((led) - (led)->dev->leds)) + +/* Delay between state changes when blinking in jiffies */ +#define B43_LEDBLINK_SLOW (HZ / 1) +#define B43_LEDBLINK_MEDIUM (HZ / 4) +#define B43_LEDBLINK_FAST (HZ / 8) + +#define B43_LED_XFER_THRES (HZ / 100) + +#define B43_LED_BEHAVIOUR 0x7F +#define B43_LED_ACTIVELOW 0x80 +enum { /* LED behaviour values */ + B43_LED_OFF, + B43_LED_ON, + B43_LED_ACTIVITY, + B43_LED_RADIO_ALL, + B43_LED_RADIO_A, + B43_LED_RADIO_B, + B43_LED_MODE_BG, + B43_LED_TRANSFER, + B43_LED_APTRANSFER, + B43_LED_WEIRD, //FIXME + B43_LED_ASSOC, + B43_LED_INACTIVE, + + /* Behaviour values for testing. + * With these values it is easier to figure out + * the real behaviour of leds, in case the SPROM + * is missing information. + */ + B43_LED_TEST_BLINKSLOW, + B43_LED_TEST_BLINKMEDIUM, + B43_LED_TEST_BLINKFAST, +}; + +int b43_leds_init(struct b43_wldev *dev); +void b43_leds_exit(struct b43_wldev *dev); +void b43_leds_update(struct b43_wldev *dev, int activity); +void b43_leds_switch_all(struct b43_wldev *dev, int on); + +#endif /* B43_LEDS_H_ */ diff --git a/drivers/net/wireless/b43/lo.c b/drivers/net/wireless/b43/lo.c new file mode 100644 index 00000000000..b14a1753a0d --- /dev/null +++ b/drivers/net/wireless/b43/lo.c @@ -0,0 +1,1261 @@ +/* + + Broadcom B43 wireless driver + + G PHY LO (LocalOscillator) Measuring and Control routines + + Copyright (c) 2005 Martin Langer , + Copyright (c) 2005, 2006 Stefano Brivio + Copyright (c) 2005-2007 Michael Buesch + Copyright (c) 2005, 2006 Danny van Dyk + Copyright (c) 2005, 2006 Andreas Jaggi + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "b43.h" +#include "lo.h" +#include "phy.h" +#include "main.h" + +#include +#include + + +/* Define to 1 to always calibrate all possible LO control pairs. + * This is a workaround until we fix the partial LO calibration optimization. */ +#define B43_CALIB_ALL_LOCTLS 1 + + +/* Write the LocalOscillator Control (adjust) value-pair. */ +static void b43_lo_write(struct b43_wldev *dev, struct b43_loctl *control) +{ + struct b43_phy *phy = &dev->phy; + u16 value; + u16 reg; + + if (B43_DEBUG) { + if (unlikely(abs(control->i) > 16 || abs(control->q) > 16)) { + b43dbg(dev->wl, "Invalid LO control pair " + "(I: %d, Q: %d)\n", control->i, control->q); + dump_stack(); + return; + } + } + + value = (u8) (control->q); + value |= ((u8) (control->i)) << 8; + + reg = (phy->type == B43_PHYTYPE_B) ? 0x002F : B43_PHY_LO_CTL; + b43_phy_write(dev, reg, value); +} + +static int assert_rfatt_and_bbatt(const struct b43_rfatt *rfatt, + const struct b43_bbatt *bbatt, + struct b43_wldev *dev) +{ + int err = 0; + + /* Check the attenuation values against the LO control array sizes. */ + if (unlikely(rfatt->att >= B43_NR_RF)) { + b43err(dev->wl, "rfatt(%u) >= size of LO array\n", rfatt->att); + err = -EINVAL; + } + if (unlikely(bbatt->att >= B43_NR_BB)) { + b43err(dev->wl, "bbatt(%u) >= size of LO array\n", bbatt->att); + err = -EINVAL; + } + + return err; +} + +#if !B43_CALIB_ALL_LOCTLS +static +struct b43_loctl *b43_get_lo_g_ctl_nopadmix(struct b43_wldev *dev, + const struct b43_rfatt *rfatt, + const struct b43_bbatt *bbatt) +{ + struct b43_phy *phy = &dev->phy; + struct b43_txpower_lo_control *lo = phy->lo_control; + + if (assert_rfatt_and_bbatt(rfatt, bbatt, dev)) + return &(lo->no_padmix[0][0]); /* Just prevent a crash */ + return &(lo->no_padmix[bbatt->att][rfatt->att]); +} +#endif /* !B43_CALIB_ALL_LOCTLS */ + +struct b43_loctl *b43_get_lo_g_ctl(struct b43_wldev *dev, + const struct b43_rfatt *rfatt, + const struct b43_bbatt *bbatt) +{ + struct b43_phy *phy = &dev->phy; + struct b43_txpower_lo_control *lo = phy->lo_control; + + if (assert_rfatt_and_bbatt(rfatt, bbatt, dev)) + return &(lo->no_padmix[0][0]); /* Just prevent a crash */ + if (rfatt->with_padmix) + return &(lo->with_padmix[bbatt->att][rfatt->att]); + return &(lo->no_padmix[bbatt->att][rfatt->att]); +} + +/* Call a function for every possible LO control value-pair. */ +static void b43_call_for_each_loctl(struct b43_wldev *dev, + void (*func) (struct b43_wldev *, + struct b43_loctl *)) +{ + struct b43_phy *phy = &dev->phy; + struct b43_txpower_lo_control *ctl = phy->lo_control; + int i, j; + + for (i = 0; i < B43_NR_BB; i++) { + for (j = 0; j < B43_NR_RF; j++) + func(dev, &(ctl->with_padmix[i][j])); + } + for (i = 0; i < B43_NR_BB; i++) { + for (j = 0; j < B43_NR_RF; j++) + func(dev, &(ctl->no_padmix[i][j])); + } +} + +static u16 lo_b_r15_loop(struct b43_wldev *dev) +{ + int i; + u16 ret = 0; + + for (i = 0; i < 10; i++) { + b43_phy_write(dev, 0x0015, 0xAFA0); + udelay(1); + b43_phy_write(dev, 0x0015, 0xEFA0); + udelay(10); + b43_phy_write(dev, 0x0015, 0xFFA0); + udelay(40); + ret += b43_phy_read(dev, 0x002C); + } + + return ret; +} + +void b43_lo_b_measure(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + u16 regstack[12] = { 0 }; + u16 mls; + u16 fval; + int i, j; + + regstack[0] = b43_phy_read(dev, 0x0015); + regstack[1] = b43_radio_read16(dev, 0x0052) & 0xFFF0; + + if (phy->radio_ver == 0x2053) { + regstack[2] = b43_phy_read(dev, 0x000A); + regstack[3] = b43_phy_read(dev, 0x002A); + regstack[4] = b43_phy_read(dev, 0x0035); + regstack[5] = b43_phy_read(dev, 0x0003); + regstack[6] = b43_phy_read(dev, 0x0001); + regstack[7] = b43_phy_read(dev, 0x0030); + + regstack[8] = b43_radio_read16(dev, 0x0043); + regstack[9] = b43_radio_read16(dev, 0x007A); + regstack[10] = b43_read16(dev, 0x03EC); + regstack[11] = b43_radio_read16(dev, 0x0052) & 0x00F0; + + b43_phy_write(dev, 0x0030, 0x00FF); + b43_write16(dev, 0x03EC, 0x3F3F); + b43_phy_write(dev, 0x0035, regstack[4] & 0xFF7F); + b43_radio_write16(dev, 0x007A, regstack[9] & 0xFFF0); + } + b43_phy_write(dev, 0x0015, 0xB000); + b43_phy_write(dev, 0x002B, 0x0004); + + if (phy->radio_ver == 0x2053) { + b43_phy_write(dev, 0x002B, 0x0203); + b43_phy_write(dev, 0x002A, 0x08A3); + } + + phy->minlowsig[0] = 0xFFFF; + + for (i = 0; i < 4; i++) { + b43_radio_write16(dev, 0x0052, regstack[1] | i); + lo_b_r15_loop(dev); + } + for (i = 0; i < 10; i++) { + b43_radio_write16(dev, 0x0052, regstack[1] | i); + mls = lo_b_r15_loop(dev) / 10; + if (mls < phy->minlowsig[0]) { + phy->minlowsig[0] = mls; + phy->minlowsigpos[0] = i; + } + } + b43_radio_write16(dev, 0x0052, regstack[1] | phy->minlowsigpos[0]); + + phy->minlowsig[1] = 0xFFFF; + + for (i = -4; i < 5; i += 2) { + for (j = -4; j < 5; j += 2) { + if (j < 0) + fval = (0x0100 * i) + j + 0x0100; + else + fval = (0x0100 * i) + j; + b43_phy_write(dev, 0x002F, fval); + mls = lo_b_r15_loop(dev) / 10; + if (mls < phy->minlowsig[1]) { + phy->minlowsig[1] = mls; + phy->minlowsigpos[1] = fval; + } + } + } + phy->minlowsigpos[1] += 0x0101; + + b43_phy_write(dev, 0x002F, phy->minlowsigpos[1]); + if (phy->radio_ver == 0x2053) { + b43_phy_write(dev, 0x000A, regstack[2]); + b43_phy_write(dev, 0x002A, regstack[3]); + b43_phy_write(dev, 0x0035, regstack[4]); + b43_phy_write(dev, 0x0003, regstack[5]); + b43_phy_write(dev, 0x0001, regstack[6]); + b43_phy_write(dev, 0x0030, regstack[7]); + + b43_radio_write16(dev, 0x0043, regstack[8]); + b43_radio_write16(dev, 0x007A, regstack[9]); + + b43_radio_write16(dev, 0x0052, + (b43_radio_read16(dev, 0x0052) & 0x000F) + | regstack[11]); + + b43_write16(dev, 0x03EC, regstack[10]); + } + b43_phy_write(dev, 0x0015, regstack[0]); +} + +static u16 lo_measure_feedthrough(struct b43_wldev *dev, + u16 lna, u16 pga, u16 trsw_rx) +{ + struct b43_phy *phy = &dev->phy; + u16 rfover; + u16 feedthrough; + + if (phy->gmode) { + lna <<= B43_PHY_RFOVERVAL_LNA_SHIFT; + pga <<= B43_PHY_RFOVERVAL_PGA_SHIFT; + + B43_WARN_ON(lna & ~B43_PHY_RFOVERVAL_LNA); + B43_WARN_ON(pga & ~B43_PHY_RFOVERVAL_PGA); +/*FIXME This assertion fails B43_WARN_ON(trsw_rx & ~(B43_PHY_RFOVERVAL_TRSWRX | + B43_PHY_RFOVERVAL_BW)); +*/ + trsw_rx &= (B43_PHY_RFOVERVAL_TRSWRX | B43_PHY_RFOVERVAL_BW); + + /* Construct the RF Override Value */ + rfover = B43_PHY_RFOVERVAL_UNK; + rfover |= pga; + rfover |= lna; + rfover |= trsw_rx; + if ((dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_EXTLNA) && + phy->rev > 6) + rfover |= B43_PHY_RFOVERVAL_EXTLNA; + + b43_phy_write(dev, B43_PHY_PGACTL, 0xE300); + b43_phy_write(dev, B43_PHY_RFOVERVAL, rfover); + udelay(10); + rfover |= B43_PHY_RFOVERVAL_BW_LBW; + b43_phy_write(dev, B43_PHY_RFOVERVAL, rfover); + udelay(10); + rfover |= B43_PHY_RFOVERVAL_BW_LPF; + b43_phy_write(dev, B43_PHY_RFOVERVAL, rfover); + udelay(10); + b43_phy_write(dev, B43_PHY_PGACTL, 0xF300); + } else { + pga |= B43_PHY_PGACTL_UNKNOWN; + b43_phy_write(dev, B43_PHY_PGACTL, pga); + udelay(10); + pga |= B43_PHY_PGACTL_LOWBANDW; + b43_phy_write(dev, B43_PHY_PGACTL, pga); + udelay(10); + pga |= B43_PHY_PGACTL_LPF; + b43_phy_write(dev, B43_PHY_PGACTL, pga); + } + udelay(21); + feedthrough = b43_phy_read(dev, B43_PHY_LO_LEAKAGE); + + /* This is a good place to check if we need to relax a bit, + * as this is the main function called regularly + * in the LO calibration. */ + cond_resched(); + + return feedthrough; +} + +/* TXCTL Register and Value Table. + * Returns the "TXCTL Register". + * "value" is the "TXCTL Value". + * "pad_mix_gain" is the PAD Mixer Gain. + */ +static u16 lo_txctl_register_table(struct b43_wldev *dev, + u16 * value, u16 * pad_mix_gain) +{ + struct b43_phy *phy = &dev->phy; + u16 reg, v, padmix; + + if (phy->type == B43_PHYTYPE_B) { + v = 0x30; + if (phy->radio_rev <= 5) { + reg = 0x43; + padmix = 0; + } else { + reg = 0x52; + padmix = 5; + } + } else { + if (phy->rev >= 2 && phy->radio_rev == 8) { + reg = 0x43; + v = 0x10; + padmix = 2; + } else { + reg = 0x52; + v = 0x30; + padmix = 5; + } + } + if (value) + *value = v; + if (pad_mix_gain) + *pad_mix_gain = padmix; + + return reg; +} + +static void lo_measure_txctl_values(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_txpower_lo_control *lo = phy->lo_control; + u16 reg, mask; + u16 trsw_rx, pga; + u16 radio_pctl_reg; + + static const u8 tx_bias_values[] = { + 0x09, 0x08, 0x0A, 0x01, 0x00, + 0x02, 0x05, 0x04, 0x06, + }; + static const u8 tx_magn_values[] = { + 0x70, 0x40, + }; + + if (!has_loopback_gain(phy)) { + radio_pctl_reg = 6; + trsw_rx = 2; + pga = 0; + } else { + int lb_gain; /* Loopback gain (in dB) */ + + trsw_rx = 0; + lb_gain = phy->max_lb_gain / 2; + if (lb_gain > 10) { + radio_pctl_reg = 0; + pga = abs(10 - lb_gain) / 6; + pga = limit_value(pga, 0, 15); + } else { + int cmp_val; + int tmp; + + pga = 0; + cmp_val = 0x24; + if ((phy->rev >= 2) && + (phy->radio_ver == 0x2050) && (phy->radio_rev == 8)) + cmp_val = 0x3C; + tmp = lb_gain; + if ((10 - lb_gain) < cmp_val) + tmp = (10 - lb_gain); + if (tmp < 0) + tmp += 6; + else + tmp += 3; + cmp_val /= 4; + tmp /= 4; + if (tmp >= cmp_val) + radio_pctl_reg = cmp_val; + else + radio_pctl_reg = tmp; + } + } + b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43) + & 0xFFF0) | radio_pctl_reg); + b43_phy_set_baseband_attenuation(dev, 2); + + reg = lo_txctl_register_table(dev, &mask, NULL); + mask = ~mask; + b43_radio_write16(dev, reg, b43_radio_read16(dev, reg) + & mask); + + if (has_tx_magnification(phy)) { + int i, j; + int feedthrough; + int min_feedth = 0xFFFF; + u8 tx_magn, tx_bias; + + for (i = 0; i < ARRAY_SIZE(tx_magn_values); i++) { + tx_magn = tx_magn_values[i]; + b43_radio_write16(dev, 0x52, + (b43_radio_read16(dev, 0x52) + & 0xFF0F) | tx_magn); + for (j = 0; j < ARRAY_SIZE(tx_bias_values); j++) { + tx_bias = tx_bias_values[j]; + b43_radio_write16(dev, 0x52, + (b43_radio_read16(dev, 0x52) + & 0xFFF0) | tx_bias); + feedthrough = + lo_measure_feedthrough(dev, 0, pga, + trsw_rx); + if (feedthrough < min_feedth) { + lo->tx_bias = tx_bias; + lo->tx_magn = tx_magn; + min_feedth = feedthrough; + } + if (lo->tx_bias == 0) + break; + } + b43_radio_write16(dev, 0x52, + (b43_radio_read16(dev, 0x52) + & 0xFF00) | lo->tx_bias | lo-> + tx_magn); + } + } else { + lo->tx_magn = 0; + lo->tx_bias = 0; + b43_radio_write16(dev, 0x52, b43_radio_read16(dev, 0x52) + & 0xFFF0); /* TX bias == 0 */ + } +} + +static void lo_read_power_vector(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_txpower_lo_control *lo = phy->lo_control; + u16 i; + u64 tmp; + u64 power_vector = 0; + int rf_offset, bb_offset; + struct b43_loctl *loctl; + + for (i = 0; i < 8; i += 2) { + tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x310 + i); + /* Clear the top byte. We get holes in the bitmap... */ + tmp &= 0xFF; + power_vector |= (tmp << (i * 8)); + /* Clear the vector on the device. */ + b43_shm_write16(dev, B43_SHM_SHARED, 0x310 + i, 0); + } + + if (power_vector) + lo->power_vector = power_vector; + power_vector = lo->power_vector; + + for (i = 0; i < 64; i++) { + if (power_vector & ((u64) 1ULL << i)) { + /* Now figure out which b43_loctl corresponds + * to this bit. + */ + rf_offset = i / lo->rfatt_list.len; + bb_offset = i % lo->rfatt_list.len; //FIXME? + loctl = + b43_get_lo_g_ctl(dev, + &lo->rfatt_list.list[rf_offset], + &lo->bbatt_list.list[bb_offset]); + /* And mark it as "used", as the device told us + * through the bitmap it is using it. + */ + loctl->used = 1; + } + } +} + +/* 802.11/LO/GPHY/MeasuringGains */ +static void lo_measure_gain_values(struct b43_wldev *dev, + s16 max_rx_gain, int use_trsw_rx) +{ + struct b43_phy *phy = &dev->phy; + u16 tmp; + + if (max_rx_gain < 0) + max_rx_gain = 0; + + if (has_loopback_gain(phy)) { + int trsw_rx = 0; + int trsw_rx_gain; + + if (use_trsw_rx) { + trsw_rx_gain = phy->trsw_rx_gain / 2; + if (max_rx_gain >= trsw_rx_gain) { + trsw_rx_gain = max_rx_gain - trsw_rx_gain; + trsw_rx = 0x20; + } + } else + trsw_rx_gain = max_rx_gain; + if (trsw_rx_gain < 9) { + phy->lna_lod_gain = 0; + } else { + phy->lna_lod_gain = 1; + trsw_rx_gain -= 8; + } + trsw_rx_gain = limit_value(trsw_rx_gain, 0, 0x2D); + phy->pga_gain = trsw_rx_gain / 3; + if (phy->pga_gain >= 5) { + phy->pga_gain -= 5; + phy->lna_gain = 2; + } else + phy->lna_gain = 0; + } else { + phy->lna_gain = 0; + phy->trsw_rx_gain = 0x20; + if (max_rx_gain >= 0x14) { + phy->lna_lod_gain = 1; + phy->pga_gain = 2; + } else if (max_rx_gain >= 0x12) { + phy->lna_lod_gain = 1; + phy->pga_gain = 1; + } else if (max_rx_gain >= 0xF) { + phy->lna_lod_gain = 1; + phy->pga_gain = 0; + } else { + phy->lna_lod_gain = 0; + phy->pga_gain = 0; + } + } + + tmp = b43_radio_read16(dev, 0x7A); + if (phy->lna_lod_gain == 0) + tmp &= ~0x0008; + else + tmp |= 0x0008; + b43_radio_write16(dev, 0x7A, tmp); +} + +struct lo_g_saved_values { + u8 old_channel; + + /* Core registers */ + u16 reg_3F4; + u16 reg_3E2; + + /* PHY registers */ + u16 phy_lo_mask; + u16 phy_extg_01; + u16 phy_dacctl_hwpctl; + u16 phy_dacctl; + u16 phy_base_14; + u16 phy_hpwr_tssictl; + u16 phy_analogover; + u16 phy_analogoverval; + u16 phy_rfover; + u16 phy_rfoverval; + u16 phy_classctl; + u16 phy_base_3E; + u16 phy_crs0; + u16 phy_pgactl; + u16 phy_base_2A; + u16 phy_syncctl; + u16 phy_base_30; + u16 phy_base_06; + + /* Radio registers */ + u16 radio_43; + u16 radio_7A; + u16 radio_52; +}; + +static void lo_measure_setup(struct b43_wldev *dev, + struct lo_g_saved_values *sav) +{ + struct ssb_sprom *sprom = &dev->dev->bus->sprom; + struct b43_phy *phy = &dev->phy; + struct b43_txpower_lo_control *lo = phy->lo_control; + u16 tmp; + + if (b43_has_hardware_pctl(phy)) { + sav->phy_lo_mask = b43_phy_read(dev, B43_PHY_LO_MASK); + sav->phy_extg_01 = b43_phy_read(dev, B43_PHY_EXTG(0x01)); + sav->phy_dacctl_hwpctl = b43_phy_read(dev, B43_PHY_DACCTL); + sav->phy_base_14 = b43_phy_read(dev, B43_PHY_BASE(0x14)); + sav->phy_hpwr_tssictl = b43_phy_read(dev, B43_PHY_HPWR_TSSICTL); + + b43_phy_write(dev, B43_PHY_HPWR_TSSICTL, + b43_phy_read(dev, B43_PHY_HPWR_TSSICTL) + | 0x100); + b43_phy_write(dev, B43_PHY_EXTG(0x01), + b43_phy_read(dev, B43_PHY_EXTG(0x01)) + | 0x40); + b43_phy_write(dev, B43_PHY_DACCTL, + b43_phy_read(dev, B43_PHY_DACCTL) + | 0x40); + b43_phy_write(dev, B43_PHY_BASE(0x14), + b43_phy_read(dev, B43_PHY_BASE(0x14)) + | 0x200); + } + if (phy->type == B43_PHYTYPE_B && + phy->radio_ver == 0x2050 && phy->radio_rev < 6) { + b43_phy_write(dev, B43_PHY_BASE(0x16), 0x410); + b43_phy_write(dev, B43_PHY_BASE(0x17), 0x820); + } + if (!lo->rebuild && b43_has_hardware_pctl(phy)) + lo_read_power_vector(dev); + if (phy->rev >= 2) { + sav->phy_analogover = b43_phy_read(dev, B43_PHY_ANALOGOVER); + sav->phy_analogoverval = + b43_phy_read(dev, B43_PHY_ANALOGOVERVAL); + sav->phy_rfover = b43_phy_read(dev, B43_PHY_RFOVER); + sav->phy_rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL); + sav->phy_classctl = b43_phy_read(dev, B43_PHY_CLASSCTL); + sav->phy_base_3E = b43_phy_read(dev, B43_PHY_BASE(0x3E)); + sav->phy_crs0 = b43_phy_read(dev, B43_PHY_CRS0); + + b43_phy_write(dev, B43_PHY_CLASSCTL, + b43_phy_read(dev, B43_PHY_CLASSCTL) + & 0xFFFC); + b43_phy_write(dev, B43_PHY_CRS0, b43_phy_read(dev, B43_PHY_CRS0) + & 0x7FFF); + b43_phy_write(dev, B43_PHY_ANALOGOVER, + b43_phy_read(dev, B43_PHY_ANALOGOVER) + | 0x0003); + b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, + b43_phy_read(dev, B43_PHY_ANALOGOVERVAL) + & 0xFFFC); + if (phy->type == B43_PHYTYPE_G) { + if ((phy->rev >= 7) && + (sprom->r1.boardflags_lo & B43_BFL_EXTLNA)) { + b43_phy_write(dev, B43_PHY_RFOVER, 0x933); + } else { + b43_phy_write(dev, B43_PHY_RFOVER, 0x133); + } + } else { + b43_phy_write(dev, B43_PHY_RFOVER, 0); + } + b43_phy_write(dev, B43_PHY_BASE(0x3E), 0); + } + sav->reg_3F4 = b43_read16(dev, 0x3F4); + sav->reg_3E2 = b43_read16(dev, 0x3E2); + sav->radio_43 = b43_radio_read16(dev, 0x43); + sav->radio_7A = b43_radio_read16(dev, 0x7A); + sav->phy_pgactl = b43_phy_read(dev, B43_PHY_PGACTL); + sav->phy_base_2A = b43_phy_read(dev, B43_PHY_BASE(0x2A)); + sav->phy_syncctl = b43_phy_read(dev, B43_PHY_SYNCCTL); + sav->phy_dacctl = b43_phy_read(dev, B43_PHY_DACCTL); + + if (!has_tx_magnification(phy)) { + sav->radio_52 = b43_radio_read16(dev, 0x52); + sav->radio_52 &= 0x00F0; + } + if (phy->type == B43_PHYTYPE_B) { + sav->phy_base_30 = b43_phy_read(dev, B43_PHY_BASE(0x30)); + sav->phy_base_06 = b43_phy_read(dev, B43_PHY_BASE(0x06)); + b43_phy_write(dev, B43_PHY_BASE(0x30), 0x00FF); + b43_phy_write(dev, B43_PHY_BASE(0x06), 0x3F3F); + } else { + b43_write16(dev, 0x3E2, b43_read16(dev, 0x3E2) + | 0x8000); + } + b43_write16(dev, 0x3F4, b43_read16(dev, 0x3F4) + & 0xF000); + + tmp = + (phy->type == B43_PHYTYPE_G) ? B43_PHY_LO_MASK : B43_PHY_BASE(0x2E); + b43_phy_write(dev, tmp, 0x007F); + + tmp = sav->phy_syncctl; + b43_phy_write(dev, B43_PHY_SYNCCTL, tmp & 0xFF7F); + tmp = sav->radio_7A; + b43_radio_write16(dev, 0x007A, tmp & 0xFFF0); + + b43_phy_write(dev, B43_PHY_BASE(0x2A), 0x8A3); + if (phy->type == B43_PHYTYPE_G || + (phy->type == B43_PHYTYPE_B && + phy->radio_ver == 0x2050 && phy->radio_rev >= 6)) { + b43_phy_write(dev, B43_PHY_BASE(0x2B), 0x1003); + } else + b43_phy_write(dev, B43_PHY_BASE(0x2B), 0x0802); + if (phy->rev >= 2) + b43_dummy_transmission(dev); + b43_radio_selectchannel(dev, 6, 0); + b43_radio_read16(dev, 0x51); /* dummy read */ + if (phy->type == B43_PHYTYPE_G) + b43_phy_write(dev, B43_PHY_BASE(0x2F), 0); + if (lo->rebuild) + lo_measure_txctl_values(dev); + if (phy->type == B43_PHYTYPE_G && phy->rev >= 3) { + b43_phy_write(dev, B43_PHY_LO_MASK, 0xC078); + } else { + if (phy->type == B43_PHYTYPE_B) + b43_phy_write(dev, B43_PHY_BASE(0x2E), 0x8078); + else + b43_phy_write(dev, B43_PHY_LO_MASK, 0x8078); + } +} + +static void lo_measure_restore(struct b43_wldev *dev, + struct lo_g_saved_values *sav) +{ + struct b43_phy *phy = &dev->phy; + struct b43_txpower_lo_control *lo = phy->lo_control; + u16 tmp; + + if (phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_PGACTL, 0xE300); + tmp = (phy->pga_gain << 8); + b43_phy_write(dev, B43_PHY_RFOVERVAL, tmp | 0xA0); + udelay(5); + b43_phy_write(dev, B43_PHY_RFOVERVAL, tmp | 0xA2); + udelay(2); + b43_phy_write(dev, B43_PHY_RFOVERVAL, tmp | 0xA3); + } else { + tmp = (phy->pga_gain | 0xEFA0); + b43_phy_write(dev, B43_PHY_PGACTL, tmp); + } + if (b43_has_hardware_pctl(phy)) { + b43_gphy_dc_lt_init(dev); + } else { + if (lo->rebuild) + b43_lo_g_adjust_to(dev, 3, 2, 0); + else + b43_lo_g_adjust(dev); + } + if (phy->type == B43_PHYTYPE_G) { + if (phy->rev >= 3) + b43_phy_write(dev, B43_PHY_BASE(0x2E), 0xC078); + else + b43_phy_write(dev, B43_PHY_BASE(0x2E), 0x8078); + if (phy->rev >= 2) + b43_phy_write(dev, B43_PHY_BASE(0x2F), 0x0202); + else + b43_phy_write(dev, B43_PHY_BASE(0x2F), 0x0101); + } + b43_write16(dev, 0x3F4, sav->reg_3F4); + b43_phy_write(dev, B43_PHY_PGACTL, sav->phy_pgactl); + b43_phy_write(dev, B43_PHY_BASE(0x2A), sav->phy_base_2A); + b43_phy_write(dev, B43_PHY_SYNCCTL, sav->phy_syncctl); + b43_phy_write(dev, B43_PHY_DACCTL, sav->phy_dacctl); + b43_radio_write16(dev, 0x43, sav->radio_43); + b43_radio_write16(dev, 0x7A, sav->radio_7A); + if (!has_tx_magnification(phy)) { + tmp = sav->radio_52; + b43_radio_write16(dev, 0x52, (b43_radio_read16(dev, 0x52) + & 0xFF0F) | tmp); + } + b43_write16(dev, 0x3E2, sav->reg_3E2); + if (phy->type == B43_PHYTYPE_B && + phy->radio_ver == 0x2050 && phy->radio_rev <= 5) { + b43_phy_write(dev, B43_PHY_BASE(0x30), sav->phy_base_30); + b43_phy_write(dev, B43_PHY_BASE(0x06), sav->phy_base_06); + } + if (phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_ANALOGOVER, sav->phy_analogover); + b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, + sav->phy_analogoverval); + b43_phy_write(dev, B43_PHY_CLASSCTL, sav->phy_classctl); + b43_phy_write(dev, B43_PHY_RFOVER, sav->phy_rfover); + b43_phy_write(dev, B43_PHY_RFOVERVAL, sav->phy_rfoverval); + b43_phy_write(dev, B43_PHY_BASE(0x3E), sav->phy_base_3E); + b43_phy_write(dev, B43_PHY_CRS0, sav->phy_crs0); + } + if (b43_has_hardware_pctl(phy)) { + tmp = (sav->phy_lo_mask & 0xBFFF); + b43_phy_write(dev, B43_PHY_LO_MASK, tmp); + b43_phy_write(dev, B43_PHY_EXTG(0x01), sav->phy_extg_01); + b43_phy_write(dev, B43_PHY_DACCTL, sav->phy_dacctl_hwpctl); + b43_phy_write(dev, B43_PHY_BASE(0x14), sav->phy_base_14); + b43_phy_write(dev, B43_PHY_HPWR_TSSICTL, sav->phy_hpwr_tssictl); + } + b43_radio_selectchannel(dev, sav->old_channel, 1); +} + +struct b43_lo_g_statemachine { + int current_state; + int nr_measured; + int state_val_multiplier; + u16 lowest_feedth; + struct b43_loctl min_loctl; +}; + +/* Loop over each possible value in this state. */ +static int lo_probe_possible_loctls(struct b43_wldev *dev, + struct b43_loctl *probe_loctl, + struct b43_lo_g_statemachine *d) +{ + struct b43_phy *phy = &dev->phy; + struct b43_txpower_lo_control *lo = phy->lo_control; + struct b43_loctl test_loctl; + struct b43_loctl orig_loctl; + struct b43_loctl prev_loctl = { + .i = -100, + .q = -100, + }; + int i; + int begin, end; + int found_lower = 0; + u16 feedth; + + static const struct b43_loctl modifiers[] = { + {.i = 1,.q = 1,}, + {.i = 1,.q = 0,}, + {.i = 1,.q = -1,}, + {.i = 0,.q = -1,}, + {.i = -1,.q = -1,}, + {.i = -1,.q = 0,}, + {.i = -1,.q = 1,}, + {.i = 0,.q = 1,}, + }; + + if (d->current_state == 0) { + begin = 1; + end = 8; + } else if (d->current_state % 2 == 0) { + begin = d->current_state - 1; + end = d->current_state + 1; + } else { + begin = d->current_state - 2; + end = d->current_state + 2; + } + if (begin < 1) + begin += 8; + if (end > 8) + end -= 8; + + memcpy(&orig_loctl, probe_loctl, sizeof(struct b43_loctl)); + i = begin; + d->current_state = i; + while (1) { + B43_WARN_ON(!(i >= 1 && i <= 8)); + memcpy(&test_loctl, &orig_loctl, sizeof(struct b43_loctl)); + test_loctl.i += modifiers[i - 1].i * d->state_val_multiplier; + test_loctl.q += modifiers[i - 1].q * d->state_val_multiplier; + if ((test_loctl.i != prev_loctl.i || + test_loctl.q != prev_loctl.q) && + (abs(test_loctl.i) <= 16 && abs(test_loctl.q) <= 16)) { + b43_lo_write(dev, &test_loctl); + feedth = lo_measure_feedthrough(dev, phy->lna_gain, + phy->pga_gain, + phy->trsw_rx_gain); + if (feedth < d->lowest_feedth) { + memcpy(probe_loctl, &test_loctl, + sizeof(struct b43_loctl)); + found_lower = 1; + d->lowest_feedth = feedth; + if ((d->nr_measured < 2) && + (!has_loopback_gain(phy) || lo->rebuild)) + break; + } + } + memcpy(&prev_loctl, &test_loctl, sizeof(prev_loctl)); + if (i == end) + break; + if (i == 8) + i = 1; + else + i++; + d->current_state = i; + } + + return found_lower; +} + +static void lo_probe_loctls_statemachine(struct b43_wldev *dev, + struct b43_loctl *loctl, + int *max_rx_gain) +{ + struct b43_phy *phy = &dev->phy; + struct b43_txpower_lo_control *lo = phy->lo_control; + struct b43_lo_g_statemachine d; + u16 feedth; + int found_lower; + struct b43_loctl probe_loctl; + int max_repeat = 1, repeat_cnt = 0; + + d.nr_measured = 0; + d.state_val_multiplier = 1; + if (has_loopback_gain(phy) && !lo->rebuild) + d.state_val_multiplier = 3; + + memcpy(&d.min_loctl, loctl, sizeof(struct b43_loctl)); + if (has_loopback_gain(phy) && lo->rebuild) + max_repeat = 4; + do { + b43_lo_write(dev, &d.min_loctl); + feedth = lo_measure_feedthrough(dev, phy->lna_gain, + phy->pga_gain, + phy->trsw_rx_gain); + if (!lo->rebuild && feedth < 0x258) { + if (feedth >= 0x12C) + *max_rx_gain += 6; + else + *max_rx_gain += 3; + feedth = lo_measure_feedthrough(dev, phy->lna_gain, + phy->pga_gain, + phy->trsw_rx_gain); + } + d.lowest_feedth = feedth; + + d.current_state = 0; + do { + B43_WARN_ON(! + (d.current_state >= 0 + && d.current_state <= 8)); + memcpy(&probe_loctl, &d.min_loctl, + sizeof(struct b43_loctl)); + found_lower = + lo_probe_possible_loctls(dev, &probe_loctl, &d); + if (!found_lower) + break; + if ((probe_loctl.i == d.min_loctl.i) && + (probe_loctl.q == d.min_loctl.q)) + break; + memcpy(&d.min_loctl, &probe_loctl, + sizeof(struct b43_loctl)); + d.nr_measured++; + } while (d.nr_measured < 24); + memcpy(loctl, &d.min_loctl, sizeof(struct b43_loctl)); + + if (has_loopback_gain(phy)) { + if (d.lowest_feedth > 0x1194) + *max_rx_gain -= 6; + else if (d.lowest_feedth < 0x5DC) + *max_rx_gain += 3; + if (repeat_cnt == 0) { + if (d.lowest_feedth <= 0x5DC) { + d.state_val_multiplier = 1; + repeat_cnt++; + } else + d.state_val_multiplier = 2; + } else if (repeat_cnt == 2) + d.state_val_multiplier = 1; + } + lo_measure_gain_values(dev, *max_rx_gain, + has_loopback_gain(phy)); + } while (++repeat_cnt < max_repeat); +} + +#if B43_CALIB_ALL_LOCTLS +static const struct b43_rfatt b43_full_rfatt_list_items[] = { + { .att = 0, .with_padmix = 0, }, + { .att = 1, .with_padmix = 0, }, + { .att = 2, .with_padmix = 0, }, + { .att = 3, .with_padmix = 0, }, + { .att = 4, .with_padmix = 0, }, + { .att = 5, .with_padmix = 0, }, + { .att = 6, .with_padmix = 0, }, + { .att = 7, .with_padmix = 0, }, + { .att = 8, .with_padmix = 0, }, + { .att = 9, .with_padmix = 0, }, + { .att = 10, .with_padmix = 0, }, + { .att = 11, .with_padmix = 0, }, + { .att = 12, .with_padmix = 0, }, + { .att = 13, .with_padmix = 0, }, + { .att = 14, .with_padmix = 0, }, + { .att = 15, .with_padmix = 0, }, + { .att = 0, .with_padmix = 1, }, + { .att = 1, .with_padmix = 1, }, + { .att = 2, .with_padmix = 1, }, + { .att = 3, .with_padmix = 1, }, + { .att = 4, .with_padmix = 1, }, + { .att = 5, .with_padmix = 1, }, + { .att = 6, .with_padmix = 1, }, + { .att = 7, .with_padmix = 1, }, + { .att = 8, .with_padmix = 1, }, + { .att = 9, .with_padmix = 1, }, + { .att = 10, .with_padmix = 1, }, + { .att = 11, .with_padmix = 1, }, + { .att = 12, .with_padmix = 1, }, + { .att = 13, .with_padmix = 1, }, + { .att = 14, .with_padmix = 1, }, + { .att = 15, .with_padmix = 1, }, +}; +static const struct b43_rfatt_list b43_full_rfatt_list = { + .list = b43_full_rfatt_list_items, + .len = ARRAY_SIZE(b43_full_rfatt_list_items), +}; + +static const struct b43_bbatt b43_full_bbatt_list_items[] = { + { .att = 0, }, + { .att = 1, }, + { .att = 2, }, + { .att = 3, }, + { .att = 4, }, + { .att = 5, }, + { .att = 6, }, + { .att = 7, }, + { .att = 8, }, + { .att = 9, }, + { .att = 10, }, + { .att = 11, }, +}; +static const struct b43_bbatt_list b43_full_bbatt_list = { + .list = b43_full_bbatt_list_items, + .len = ARRAY_SIZE(b43_full_bbatt_list_items), +}; +#endif /* B43_CALIB_ALL_LOCTLS */ + +static void lo_measure(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_txpower_lo_control *lo = phy->lo_control; + struct b43_loctl loctl = { + .i = 0, + .q = 0, + }; + struct b43_loctl *ploctl; + int max_rx_gain; + int rfidx, bbidx; + const struct b43_bbatt_list *bbatt_list; + const struct b43_rfatt_list *rfatt_list; + + /* Values from the "TXCTL Register and Value Table" */ + u16 txctl_reg; + u16 txctl_value; + u16 pad_mix_gain; + + bbatt_list = &lo->bbatt_list; + rfatt_list = &lo->rfatt_list; +#if B43_CALIB_ALL_LOCTLS + bbatt_list = &b43_full_bbatt_list; + rfatt_list = &b43_full_rfatt_list; +#endif + + txctl_reg = lo_txctl_register_table(dev, &txctl_value, &pad_mix_gain); + + for (rfidx = 0; rfidx < rfatt_list->len; rfidx++) { + + b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43) + & 0xFFF0) | + rfatt_list->list[rfidx].att); + b43_radio_write16(dev, txctl_reg, + (b43_radio_read16(dev, txctl_reg) + & ~txctl_value) + | (rfatt_list->list[rfidx].with_padmix ? + txctl_value : 0)); + + for (bbidx = 0; bbidx < bbatt_list->len; bbidx++) { + if (lo->rebuild) { +#if B43_CALIB_ALL_LOCTLS + ploctl = b43_get_lo_g_ctl(dev, + &rfatt_list->list[rfidx], + &bbatt_list->list[bbidx]); +#else + ploctl = b43_get_lo_g_ctl_nopadmix(dev, + &rfatt_list-> + list[rfidx], + &bbatt_list-> + list[bbidx]); +#endif + } else { + ploctl = b43_get_lo_g_ctl(dev, + &rfatt_list->list[rfidx], + &bbatt_list->list[bbidx]); + if (!ploctl->used) + continue; + } + memcpy(&loctl, ploctl, sizeof(loctl)); + loctl.i = 0; + loctl.q = 0; + + max_rx_gain = rfatt_list->list[rfidx].att * 2; + max_rx_gain += bbatt_list->list[bbidx].att / 2; + if (rfatt_list->list[rfidx].with_padmix) + max_rx_gain -= pad_mix_gain; + if (has_loopback_gain(phy)) + max_rx_gain += phy->max_lb_gain; + lo_measure_gain_values(dev, max_rx_gain, + has_loopback_gain(phy)); + + b43_phy_set_baseband_attenuation(dev, + bbatt_list->list[bbidx].att); + lo_probe_loctls_statemachine(dev, &loctl, &max_rx_gain); + if (phy->type == B43_PHYTYPE_B) { + loctl.i++; + loctl.q++; + } + b43_loctl_set_calibrated(&loctl, 1); + memcpy(ploctl, &loctl, sizeof(loctl)); + } + } +} + +#if B43_DEBUG +static void do_validate_loctl(struct b43_wldev *dev, struct b43_loctl *control) +{ + const int is_initializing = (b43_status(dev) == B43_STAT_UNINIT); + int i = control->i; + int q = control->q; + + if (b43_loctl_is_calibrated(control)) { + if ((abs(i) > 16) || (abs(q) > 16)) + goto error; + } else { + if (control->used) + goto error; + if (dev->phy.lo_control->rebuild) { + control->i = 0; + control->q = 0; + if ((i != B43_LOCTL_POISON) || + (q != B43_LOCTL_POISON)) + goto error; + } + } + if (is_initializing && control->used) + goto error; + + return; +error: + b43err(dev->wl, "LO control pair validation failed " + "(I: %d, Q: %d, used %u, calib: %u, initing: %d)\n", + i, q, control->used, + b43_loctl_is_calibrated(control), + is_initializing); +} + +static void validate_all_loctls(struct b43_wldev *dev) +{ + b43_call_for_each_loctl(dev, do_validate_loctl); +} + +static void do_reset_calib(struct b43_wldev *dev, struct b43_loctl *control) +{ + if (dev->phy.lo_control->rebuild || + control->used) { + b43_loctl_set_calibrated(control, 0); + control->i = B43_LOCTL_POISON; + control->q = B43_LOCTL_POISON; + } +} + +static void reset_all_loctl_calibration_states(struct b43_wldev *dev) +{ + b43_call_for_each_loctl(dev, do_reset_calib); +} + +#else /* B43_DEBUG */ +static inline void validate_all_loctls(struct b43_wldev *dev) { } +static inline void reset_all_loctl_calibration_states(struct b43_wldev *dev) { } +#endif /* B43_DEBUG */ + +void b43_lo_g_measure(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct lo_g_saved_values uninitialized_var(sav); + + B43_WARN_ON((phy->type != B43_PHYTYPE_B) && + (phy->type != B43_PHYTYPE_G)); + + sav.old_channel = phy->channel; + lo_measure_setup(dev, &sav); + reset_all_loctl_calibration_states(dev); + lo_measure(dev); + lo_measure_restore(dev, &sav); + + validate_all_loctls(dev); + + phy->lo_control->lo_measured = 1; + phy->lo_control->rebuild = 0; +} + +#if B43_DEBUG +static void validate_loctl_calibration(struct b43_wldev *dev, + struct b43_loctl *loctl, + struct b43_rfatt *rfatt, + struct b43_bbatt *bbatt) +{ + if (b43_loctl_is_calibrated(loctl)) + return; + if (!dev->phy.lo_control->lo_measured) { + /* On init we set the attenuation values before we + * calibrated the LO. I guess that's OK. */ + return; + } + b43err(dev->wl, "Adjusting Local Oscillator to an uncalibrated " + "control pair: rfatt=%u,%spadmix bbatt=%u\n", + rfatt->att, + (rfatt->with_padmix) ? "" : "no-", + bbatt->att); +} +#else +static inline void validate_loctl_calibration(struct b43_wldev *dev, + struct b43_loctl *loctl, + struct b43_rfatt *rfatt, + struct b43_bbatt *bbatt) +{ +} +#endif + +static inline void fixup_rfatt_for_txcontrol(struct b43_rfatt *rf, + u8 tx_control) +{ + if (tx_control & B43_TXCTL_TXMIX) { + if (rf->att < 5) + rf->att = 4; + } +} + +void b43_lo_g_adjust(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_rfatt rf; + struct b43_loctl *loctl; + + memcpy(&rf, &phy->rfatt, sizeof(rf)); + fixup_rfatt_for_txcontrol(&rf, phy->tx_control); + + loctl = b43_get_lo_g_ctl(dev, &rf, &phy->bbatt); + validate_loctl_calibration(dev, loctl, &rf, &phy->bbatt); + b43_lo_write(dev, loctl); +} + +void b43_lo_g_adjust_to(struct b43_wldev *dev, + u16 rfatt, u16 bbatt, u16 tx_control) +{ + struct b43_rfatt rf; + struct b43_bbatt bb; + struct b43_loctl *loctl; + + memset(&rf, 0, sizeof(rf)); + memset(&bb, 0, sizeof(bb)); + rf.att = rfatt; + bb.att = bbatt; + fixup_rfatt_for_txcontrol(&rf, tx_control); + loctl = b43_get_lo_g_ctl(dev, &rf, &bb); + validate_loctl_calibration(dev, loctl, &rf, &bb); + b43_lo_write(dev, loctl); +} + +static void do_mark_unused(struct b43_wldev *dev, struct b43_loctl *control) +{ + control->used = 0; +} + +void b43_lo_g_ctl_mark_all_unused(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_txpower_lo_control *lo = phy->lo_control; + + b43_call_for_each_loctl(dev, do_mark_unused); + lo->rebuild = 1; +} + +void b43_lo_g_ctl_mark_cur_used(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_rfatt rf; + + memcpy(&rf, &phy->rfatt, sizeof(rf)); + fixup_rfatt_for_txcontrol(&rf, phy->tx_control); + + b43_get_lo_g_ctl(dev, &rf, &phy->bbatt)->used = 1; +} diff --git a/drivers/net/wireless/b43/lo.h b/drivers/net/wireless/b43/lo.h new file mode 100644 index 00000000000..455615d1f8c --- /dev/null +++ b/drivers/net/wireless/b43/lo.h @@ -0,0 +1,112 @@ +#ifndef B43_LO_H_ +#define B43_LO_H_ + +#include "phy.h" + +struct b43_wldev; + +/* Local Oscillator control value-pair. */ +struct b43_loctl { + /* Control values. */ + s8 i; + s8 q; + /* "Used by hardware" flag. */ + bool used; +#ifdef CONFIG_B43_DEBUG + /* Is this lo-control-array entry calibrated? */ + bool calibrated; +#endif +}; + +/* Debugging: Poison value for i and q values. */ +#define B43_LOCTL_POISON 111 + +/* loctl->calibrated debugging mechanism */ +#ifdef CONFIG_B43_DEBUG +static inline void b43_loctl_set_calibrated(struct b43_loctl *loctl, + bool calibrated) +{ + loctl->calibrated = calibrated; +} +static inline bool b43_loctl_is_calibrated(struct b43_loctl *loctl) +{ + return loctl->calibrated; +} +#else +static inline void b43_loctl_set_calibrated(struct b43_loctl *loctl, + bool calibrated) +{ +} +static inline bool b43_loctl_is_calibrated(struct b43_loctl *loctl) +{ + return 1; +} +#endif + +/* TX Power LO Control Array. + * Value-pairs to adjust the LocalOscillator are stored + * in this structure. + * There are two different set of values. One for "Flag is Set" + * and one for "Flag is Unset". + * By "Flag" the flag in struct b43_rfatt is meant. + * The Value arrays are two-dimensional. The first index + * is the baseband attenuation and the second index + * is the radio attenuation. + * Use b43_get_lo_g_ctl() to retrieve a value from the lists. + */ +struct b43_txpower_lo_control { +#define B43_NR_BB 12 +#define B43_NR_RF 16 + /* LO Control values, with PAD Mixer */ + struct b43_loctl with_padmix[B43_NR_BB][B43_NR_RF]; + /* LO Control values, without PAD Mixer */ + struct b43_loctl no_padmix[B43_NR_BB][B43_NR_RF]; + + /* Flag to indicate a complete rebuild of the two tables above + * to the LO measuring code. */ + bool rebuild; + + /* Lists of valid RF and BB attenuation values for this device. */ + struct b43_rfatt_list rfatt_list; + struct b43_bbatt_list bbatt_list; + + /* Current TX Bias value */ + u8 tx_bias; + /* Current TX Magnification Value (if used by the device) */ + u8 tx_magn; + + /* GPHY LO is measured. */ + bool lo_measured; + + /* Saved device PowerVector */ + u64 power_vector; +}; + +/* Measure the BPHY Local Oscillator. */ +void b43_lo_b_measure(struct b43_wldev *dev); +/* Measure the BPHY/GPHY Local Oscillator. */ +void b43_lo_g_measure(struct b43_wldev *dev); + +/* Adjust the Local Oscillator to the saved attenuation + * and txctl values. + */ +void b43_lo_g_adjust(struct b43_wldev *dev); +/* Adjust to specific values. */ +void b43_lo_g_adjust_to(struct b43_wldev *dev, + u16 rfatt, u16 bbatt, u16 tx_control); + +/* Mark all possible b43_lo_g_ctl as "unused" */ +void b43_lo_g_ctl_mark_all_unused(struct b43_wldev *dev); +/* Mark the b43_lo_g_ctl corresponding to the current + * attenuation values as used. + */ +void b43_lo_g_ctl_mark_cur_used(struct b43_wldev *dev); + +/* Get a reference to a LO Control value pair in the + * TX Power LO Control Array. + */ +struct b43_loctl *b43_get_lo_g_ctl(struct b43_wldev *dev, + const struct b43_rfatt *rfatt, + const struct b43_bbatt *bbatt); + +#endif /* B43_LO_H_ */ diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c new file mode 100644 index 00000000000..184ebe3ed73 --- /dev/null +++ b/drivers/net/wireless/b43/main.c @@ -0,0 +1,4091 @@ +/* + + Broadcom B43 wireless driver + + Copyright (c) 2005 Martin Langer + Copyright (c) 2005 Stefano Brivio + Copyright (c) 2005, 2006 Michael Buesch + Copyright (c) 2005 Danny van Dyk + Copyright (c) 2005 Andreas Jaggi + + Some parts of the code in this file are derived from the ipw2200 + driver Copyright(c) 2003 - 2004 Intel Corporation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "b43.h" +#include "main.h" +#include "debugfs.h" +#include "phy.h" +#include "dma.h" +#include "pio.h" +#include "sysfs.h" +#include "xmit.h" +#include "sysfs.h" +#include "lo.h" +#include "pcmcia.h" + +MODULE_DESCRIPTION("Broadcom B43 wireless driver"); +MODULE_AUTHOR("Martin Langer"); +MODULE_AUTHOR("Stefano Brivio"); +MODULE_AUTHOR("Michael Buesch"); +MODULE_LICENSE("GPL"); + +extern char *nvram_get(char *name); + +#if defined(CONFIG_B43_DMA) && defined(CONFIG_B43_PIO) +static int modparam_pio; +module_param_named(pio, modparam_pio, int, 0444); +MODULE_PARM_DESC(pio, "enable(1) / disable(0) PIO mode"); +#elif defined(CONFIG_B43_DMA) +# define modparam_pio 0 +#elif defined(CONFIG_B43_PIO) +# define modparam_pio 1 +#endif + +static int modparam_bad_frames_preempt; +module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444); +MODULE_PARM_DESC(bad_frames_preempt, + "enable(1) / disable(0) Bad Frames Preemption"); + +static int modparam_short_retry = B43_DEFAULT_SHORT_RETRY_LIMIT; +module_param_named(short_retry, modparam_short_retry, int, 0444); +MODULE_PARM_DESC(short_retry, "Short-Retry-Limit (0 - 15)"); + +static int modparam_long_retry = B43_DEFAULT_LONG_RETRY_LIMIT; +module_param_named(long_retry, modparam_long_retry, int, 0444); +MODULE_PARM_DESC(long_retry, "Long-Retry-Limit (0 - 15)"); + +static int modparam_noleds; +module_param_named(noleds, modparam_noleds, int, 0444); +MODULE_PARM_DESC(noleds, "Turn off all LED activity"); + +static char modparam_fwpostfix[16]; +module_param_string(fwpostfix, modparam_fwpostfix, 16, 0444); +MODULE_PARM_DESC(fwpostfix, "Postfix for the .fw files to load."); + +static int modparam_mon_keep_bad; +module_param_named(mon_keep_bad, modparam_mon_keep_bad, int, 0444); +MODULE_PARM_DESC(mon_keep_bad, "Keep bad frames in monitor mode"); + +static int modparam_mon_keep_badplcp; +module_param_named(mon_keep_badplcp, modparam_mon_keep_bad, int, 0444); +MODULE_PARM_DESC(mon_keep_badplcp, "Keep frames with bad PLCP in monitor mode"); + +static int modparam_hwpctl; +module_param_named(hwpctl, modparam_hwpctl, int, 0444); +MODULE_PARM_DESC(hwpctl, "Enable hardware-side power control (default off)"); + +static int modparam_nohwcrypt; +module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444); +MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); + +static const struct ssb_device_id b43_ssb_tbl[] = { + SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 5), + SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 6), + SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 7), + SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 9), + SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 10), + SSB_DEVTABLE_END +}; + +MODULE_DEVICE_TABLE(ssb, b43_ssb_tbl); + +/* Channel and ratetables are shared for all devices. + * They can't be const, because ieee80211 puts some precalculated + * data in there. This data is the same for all devices, so we don't + * get concurrency issues */ +#define RATETAB_ENT(_rateid, _flags) \ + { \ + .rate = B43_RATE_TO_BASE100KBPS(_rateid), \ + .val = (_rateid), \ + .val2 = (_rateid), \ + .flags = (_flags), \ + } +static struct ieee80211_rate __b43_ratetable[] = { + RATETAB_ENT(B43_CCK_RATE_1MB, IEEE80211_RATE_CCK), + RATETAB_ENT(B43_CCK_RATE_2MB, IEEE80211_RATE_CCK_2), + RATETAB_ENT(B43_CCK_RATE_5MB, IEEE80211_RATE_CCK_2), + RATETAB_ENT(B43_CCK_RATE_11MB, IEEE80211_RATE_CCK_2), + RATETAB_ENT(B43_OFDM_RATE_6MB, IEEE80211_RATE_OFDM), + RATETAB_ENT(B43_OFDM_RATE_9MB, IEEE80211_RATE_OFDM), + RATETAB_ENT(B43_OFDM_RATE_12MB, IEEE80211_RATE_OFDM), + RATETAB_ENT(B43_OFDM_RATE_18MB, IEEE80211_RATE_OFDM), + RATETAB_ENT(B43_OFDM_RATE_24MB, IEEE80211_RATE_OFDM), + RATETAB_ENT(B43_OFDM_RATE_36MB, IEEE80211_RATE_OFDM), + RATETAB_ENT(B43_OFDM_RATE_48MB, IEEE80211_RATE_OFDM), + RATETAB_ENT(B43_OFDM_RATE_54MB, IEEE80211_RATE_OFDM), +}; + +#define b43_a_ratetable (__b43_ratetable + 4) +#define b43_a_ratetable_size 8 +#define b43_b_ratetable (__b43_ratetable + 0) +#define b43_b_ratetable_size 4 +#define b43_g_ratetable (__b43_ratetable + 0) +#define b43_g_ratetable_size 12 + +#define CHANTAB_ENT(_chanid, _freq) \ + { \ + .chan = (_chanid), \ + .freq = (_freq), \ + .val = (_chanid), \ + .flag = IEEE80211_CHAN_W_SCAN | \ + IEEE80211_CHAN_W_ACTIVE_SCAN | \ + IEEE80211_CHAN_W_IBSS, \ + .power_level = 0xFF, \ + .antenna_max = 0xFF, \ + } +static struct ieee80211_channel b43_bg_chantable[] = { + CHANTAB_ENT(1, 2412), + CHANTAB_ENT(2, 2417), + CHANTAB_ENT(3, 2422), + CHANTAB_ENT(4, 2427), + CHANTAB_ENT(5, 2432), + CHANTAB_ENT(6, 2437), + CHANTAB_ENT(7, 2442), + CHANTAB_ENT(8, 2447), + CHANTAB_ENT(9, 2452), + CHANTAB_ENT(10, 2457), + CHANTAB_ENT(11, 2462), + CHANTAB_ENT(12, 2467), + CHANTAB_ENT(13, 2472), + CHANTAB_ENT(14, 2484), +}; + +#define b43_bg_chantable_size ARRAY_SIZE(b43_bg_chantable) +static struct ieee80211_channel b43_a_chantable[] = { + CHANTAB_ENT(36, 5180), + CHANTAB_ENT(40, 5200), + CHANTAB_ENT(44, 5220), + CHANTAB_ENT(48, 5240), + CHANTAB_ENT(52, 5260), + CHANTAB_ENT(56, 5280), + CHANTAB_ENT(60, 5300), + CHANTAB_ENT(64, 5320), + CHANTAB_ENT(149, 5745), + CHANTAB_ENT(153, 5765), + CHANTAB_ENT(157, 5785), + CHANTAB_ENT(161, 5805), + CHANTAB_ENT(165, 5825), +}; + +#define b43_a_chantable_size ARRAY_SIZE(b43_a_chantable) + +static void b43_wireless_core_exit(struct b43_wldev *dev); +static int b43_wireless_core_init(struct b43_wldev *dev); +static void b43_wireless_core_stop(struct b43_wldev *dev); +static int b43_wireless_core_start(struct b43_wldev *dev); + +static int b43_ratelimit(struct b43_wl *wl) +{ + if (!wl || !wl->current_dev) + return 1; + if (b43_status(wl->current_dev) < B43_STAT_STARTED) + return 1; + /* We are up and running. + * Ratelimit the messages to avoid DoS over the net. */ + return net_ratelimit(); +} + +void b43info(struct b43_wl *wl, const char *fmt, ...) +{ + va_list args; + + if (!b43_ratelimit(wl)) + return; + va_start(args, fmt); + printk(KERN_INFO "b43-%s: ", + (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan"); + vprintk(fmt, args); + va_end(args); +} + +void b43err(struct b43_wl *wl, const char *fmt, ...) +{ + va_list args; + + if (!b43_ratelimit(wl)) + return; + va_start(args, fmt); + printk(KERN_ERR "b43-%s ERROR: ", + (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan"); + vprintk(fmt, args); + va_end(args); +} + +void b43warn(struct b43_wl *wl, const char *fmt, ...) +{ + va_list args; + + if (!b43_ratelimit(wl)) + return; + va_start(args, fmt); + printk(KERN_WARNING "b43-%s warning: ", + (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan"); + vprintk(fmt, args); + va_end(args); +} + +#if B43_DEBUG +void b43dbg(struct b43_wl *wl, const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + printk(KERN_DEBUG "b43-%s debug: ", + (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan"); + vprintk(fmt, args); + va_end(args); +} +#endif /* DEBUG */ + +static void b43_ram_write(struct b43_wldev *dev, u16 offset, u32 val) +{ + u32 macctl; + + B43_WARN_ON(offset % 4 != 0); + + macctl = b43_read32(dev, B43_MMIO_MACCTL); + if (macctl & B43_MACCTL_BE) + val = swab32(val); + + b43_write32(dev, B43_MMIO_RAM_CONTROL, offset); + mmiowb(); + b43_write32(dev, B43_MMIO_RAM_DATA, val); +} + +static inline + void b43_shm_control_word(struct b43_wldev *dev, u16 routing, u16 offset) +{ + u32 control; + + /* "offset" is the WORD offset. */ + + control = routing; + control <<= 16; + control |= offset; + b43_write32(dev, B43_MMIO_SHM_CONTROL, control); +} + +u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset) +{ + u32 ret; + + if (routing == B43_SHM_SHARED) { + B43_WARN_ON(offset & 0x0001); + if (offset & 0x0003) { + /* Unaligned access */ + b43_shm_control_word(dev, routing, offset >> 2); + ret = b43_read16(dev, B43_MMIO_SHM_DATA_UNALIGNED); + ret <<= 16; + b43_shm_control_word(dev, routing, (offset >> 2) + 1); + ret |= b43_read16(dev, B43_MMIO_SHM_DATA); + + return ret; + } + offset >>= 2; + } + b43_shm_control_word(dev, routing, offset); + ret = b43_read32(dev, B43_MMIO_SHM_DATA); + + return ret; +} + +u16 b43_shm_read16(struct b43_wldev * dev, u16 routing, u16 offset) +{ + u16 ret; + + if (routing == B43_SHM_SHARED) { + B43_WARN_ON(offset & 0x0001); + if (offset & 0x0003) { + /* Unaligned access */ + b43_shm_control_word(dev, routing, offset >> 2); + ret = b43_read16(dev, B43_MMIO_SHM_DATA_UNALIGNED); + + return ret; + } + offset >>= 2; + } + b43_shm_control_word(dev, routing, offset); + ret = b43_read16(dev, B43_MMIO_SHM_DATA); + + return ret; +} + +void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value) +{ + if (routing == B43_SHM_SHARED) { + B43_WARN_ON(offset & 0x0001); + if (offset & 0x0003) { + /* Unaligned access */ + b43_shm_control_word(dev, routing, offset >> 2); + mmiowb(); + b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED, + (value >> 16) & 0xffff); + mmiowb(); + b43_shm_control_word(dev, routing, (offset >> 2) + 1); + mmiowb(); + b43_write16(dev, B43_MMIO_SHM_DATA, value & 0xffff); + return; + } + offset >>= 2; + } + b43_shm_control_word(dev, routing, offset); + mmiowb(); + b43_write32(dev, B43_MMIO_SHM_DATA, value); +} + +void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value) +{ + if (routing == B43_SHM_SHARED) { + B43_WARN_ON(offset & 0x0001); + if (offset & 0x0003) { + /* Unaligned access */ + b43_shm_control_word(dev, routing, offset >> 2); + mmiowb(); + b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED, value); + return; + } + offset >>= 2; + } + b43_shm_control_word(dev, routing, offset); + mmiowb(); + b43_write16(dev, B43_MMIO_SHM_DATA, value); +} + +/* Read HostFlags */ +u32 b43_hf_read(struct b43_wldev * dev) +{ + u32 ret; + + ret = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFHI); + ret <<= 16; + ret |= b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFLO); + + return ret; +} + +/* Write HostFlags */ +void b43_hf_write(struct b43_wldev *dev, u32 value) +{ + b43_shm_write16(dev, B43_SHM_SHARED, + B43_SHM_SH_HOSTFLO, (value & 0x0000FFFF)); + b43_shm_write16(dev, B43_SHM_SHARED, + B43_SHM_SH_HOSTFHI, ((value & 0xFFFF0000) >> 16)); +} + +void b43_tsf_read(struct b43_wldev *dev, u64 * tsf) +{ + /* We need to be careful. As we read the TSF from multiple + * registers, we should take care of register overflows. + * In theory, the whole tsf read process should be atomic. + * We try to be atomic here, by restaring the read process, + * if any of the high registers changed (overflew). + */ + if (dev->dev->id.revision >= 3) { + u32 low, high, high2; + + do { + high = b43_read32(dev, B43_MMIO_REV3PLUS_TSF_HIGH); + low = b43_read32(dev, B43_MMIO_REV3PLUS_TSF_LOW); + high2 = b43_read32(dev, B43_MMIO_REV3PLUS_TSF_HIGH); + } while (unlikely(high != high2)); + + *tsf = high; + *tsf <<= 32; + *tsf |= low; + } else { + u64 tmp; + u16 v0, v1, v2, v3; + u16 test1, test2, test3; + + do { + v3 = b43_read16(dev, B43_MMIO_TSF_3); + v2 = b43_read16(dev, B43_MMIO_TSF_2); + v1 = b43_read16(dev, B43_MMIO_TSF_1); + v0 = b43_read16(dev, B43_MMIO_TSF_0); + + test3 = b43_read16(dev, B43_MMIO_TSF_3); + test2 = b43_read16(dev, B43_MMIO_TSF_2); + test1 = b43_read16(dev, B43_MMIO_TSF_1); + } while (v3 != test3 || v2 != test2 || v1 != test1); + + *tsf = v3; + *tsf <<= 48; + tmp = v2; + tmp <<= 32; + *tsf |= tmp; + tmp = v1; + tmp <<= 16; + *tsf |= tmp; + *tsf |= v0; + } +} + +static void b43_time_lock(struct b43_wldev *dev) +{ + u32 macctl; + + macctl = b43_read32(dev, B43_MMIO_MACCTL); + macctl |= B43_MACCTL_TBTTHOLD; + b43_write32(dev, B43_MMIO_MACCTL, macctl); + /* Commit the write */ + b43_read32(dev, B43_MMIO_MACCTL); +} + +static void b43_time_unlock(struct b43_wldev *dev) +{ + u32 macctl; + + macctl = b43_read32(dev, B43_MMIO_MACCTL); + macctl &= ~B43_MACCTL_TBTTHOLD; + b43_write32(dev, B43_MMIO_MACCTL, macctl); + /* Commit the write */ + b43_read32(dev, B43_MMIO_MACCTL); +} + +static void b43_tsf_write_locked(struct b43_wldev *dev, u64 tsf) +{ + /* Be careful with the in-progress timer. + * First zero out the low register, so we have a full + * register-overflow duration to complete the operation. + */ + if (dev->dev->id.revision >= 3) { + u32 lo = (tsf & 0x00000000FFFFFFFFULL); + u32 hi = (tsf & 0xFFFFFFFF00000000ULL) >> 32; + + b43_write32(dev, B43_MMIO_REV3PLUS_TSF_LOW, 0); + mmiowb(); + b43_write32(dev, B43_MMIO_REV3PLUS_TSF_HIGH, hi); + mmiowb(); + b43_write32(dev, B43_MMIO_REV3PLUS_TSF_LOW, lo); + } else { + u16 v0 = (tsf & 0x000000000000FFFFULL); + u16 v1 = (tsf & 0x00000000FFFF0000ULL) >> 16; + u16 v2 = (tsf & 0x0000FFFF00000000ULL) >> 32; + u16 v3 = (tsf & 0xFFFF000000000000ULL) >> 48; + + b43_write16(dev, B43_MMIO_TSF_0, 0); + mmiowb(); + b43_write16(dev, B43_MMIO_TSF_3, v3); + mmiowb(); + b43_write16(dev, B43_MMIO_TSF_2, v2); + mmiowb(); + b43_write16(dev, B43_MMIO_TSF_1, v1); + mmiowb(); + b43_write16(dev, B43_MMIO_TSF_0, v0); + } +} + +void b43_tsf_write(struct b43_wldev *dev, u64 tsf) +{ + b43_time_lock(dev); + b43_tsf_write_locked(dev, tsf); + b43_time_unlock(dev); +} + +static +void b43_macfilter_set(struct b43_wldev *dev, u16 offset, const u8 * mac) +{ + static const u8 zero_addr[ETH_ALEN] = { 0 }; + u16 data; + + if (!mac) + mac = zero_addr; + + offset |= 0x0020; + b43_write16(dev, B43_MMIO_MACFILTER_CONTROL, offset); + + data = mac[0]; + data |= mac[1] << 8; + b43_write16(dev, B43_MMIO_MACFILTER_DATA, data); + data = mac[2]; + data |= mac[3] << 8; + b43_write16(dev, B43_MMIO_MACFILTER_DATA, data); + data = mac[4]; + data |= mac[5] << 8; + b43_write16(dev, B43_MMIO_MACFILTER_DATA, data); +} + +static void b43_write_mac_bssid_templates(struct b43_wldev *dev) +{ + const u8 *mac; + const u8 *bssid; + u8 mac_bssid[ETH_ALEN * 2]; + int i; + u32 tmp; + + bssid = dev->wl->bssid; + mac = dev->wl->mac_addr; + + b43_macfilter_set(dev, B43_MACFILTER_BSSID, bssid); + + memcpy(mac_bssid, mac, ETH_ALEN); + memcpy(mac_bssid + ETH_ALEN, bssid, ETH_ALEN); + + /* Write our MAC address and BSSID to template ram */ + for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32)) { + tmp = (u32) (mac_bssid[i + 0]); + tmp |= (u32) (mac_bssid[i + 1]) << 8; + tmp |= (u32) (mac_bssid[i + 2]) << 16; + tmp |= (u32) (mac_bssid[i + 3]) << 24; + b43_ram_write(dev, 0x20 + i, tmp); + } +} + +static void b43_upload_card_macaddress(struct b43_wldev *dev, + const u8 * mac_addr) +{ + if (mac_addr) + memcpy(dev->wl->mac_addr, mac_addr, ETH_ALEN); + else + memset(dev->wl->mac_addr, 0, ETH_ALEN); + b43_write_mac_bssid_templates(dev); + b43_macfilter_set(dev, B43_MACFILTER_SELF, mac_addr); +} + +static void b43_set_slot_time(struct b43_wldev *dev, u16 slot_time) +{ + /* slot_time is in usec. */ + if (dev->phy.type != B43_PHYTYPE_G) + return; + b43_write16(dev, 0x684, 510 + slot_time); + b43_shm_write16(dev, B43_SHM_SHARED, 0x0010, slot_time); +} + +static void b43_short_slot_timing_enable(struct b43_wldev *dev) +{ + b43_set_slot_time(dev, 9); + dev->short_slot = 1; +} + +static void b43_short_slot_timing_disable(struct b43_wldev *dev) +{ + b43_set_slot_time(dev, 20); + dev->short_slot = 0; +} + +/* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable. + * Returns the _previously_ enabled IRQ mask. + */ +static inline u32 b43_interrupt_enable(struct b43_wldev *dev, u32 mask) +{ + u32 old_mask; + + old_mask = b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); + b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, old_mask | mask); + + return old_mask; +} + +/* Disable a Generic IRQ. "mask" is the mask of which IRQs to disable. + * Returns the _previously_ enabled IRQ mask. + */ +static inline u32 b43_interrupt_disable(struct b43_wldev *dev, u32 mask) +{ + u32 old_mask; + + old_mask = b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); + b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, old_mask & ~mask); + + return old_mask; +} + +/* Synchronize IRQ top- and bottom-half. + * IRQs must be masked before calling this. + * This must not be called with the irq_lock held. + */ +static void b43_synchronize_irq(struct b43_wldev *dev) +{ + synchronize_irq(dev->dev->irq); + tasklet_kill(&dev->isr_tasklet); +} + +/* DummyTransmission function, as documented on + * http://bcm-specs.sipsolutions.net/DummyTransmission + */ +void b43_dummy_transmission(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + unsigned int i, max_loop; + u16 value; + u32 buffer[5] = { + 0x00000000, + 0x00D40000, + 0x00000000, + 0x01000000, + 0x00000000, + }; + + switch (phy->type) { + case B43_PHYTYPE_A: + max_loop = 0x1E; + buffer[0] = 0x000201CC; + break; + case B43_PHYTYPE_B: + case B43_PHYTYPE_G: + max_loop = 0xFA; + buffer[0] = 0x000B846E; + break; + default: + B43_WARN_ON(1); + return; + } + + for (i = 0; i < 5; i++) + b43_ram_write(dev, i * 4, buffer[i]); + + /* Commit writes */ + b43_read32(dev, B43_MMIO_MACCTL); + + b43_write16(dev, 0x0568, 0x0000); + b43_write16(dev, 0x07C0, 0x0000); + value = ((phy->type == B43_PHYTYPE_A) ? 1 : 0); + b43_write16(dev, 0x050C, value); + b43_write16(dev, 0x0508, 0x0000); + b43_write16(dev, 0x050A, 0x0000); + b43_write16(dev, 0x054C, 0x0000); + b43_write16(dev, 0x056A, 0x0014); + b43_write16(dev, 0x0568, 0x0826); + b43_write16(dev, 0x0500, 0x0000); + b43_write16(dev, 0x0502, 0x0030); + + if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5) + b43_radio_write16(dev, 0x0051, 0x0017); + for (i = 0x00; i < max_loop; i++) { + value = b43_read16(dev, 0x050E); + if (value & 0x0080) + break; + udelay(10); + } + for (i = 0x00; i < 0x0A; i++) { + value = b43_read16(dev, 0x050E); + if (value & 0x0400) + break; + udelay(10); + } + for (i = 0x00; i < 0x0A; i++) { + value = b43_read16(dev, 0x0690); + if (!(value & 0x0100)) + break; + udelay(10); + } + if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5) + b43_radio_write16(dev, 0x0051, 0x0037); +} + +static void key_write(struct b43_wldev *dev, + u8 index, u8 algorithm, const u8 * key) +{ + unsigned int i; + u32 offset; + u16 value; + u16 kidx; + + /* Key index/algo block */ + kidx = b43_kidx_to_fw(dev, index); + value = ((kidx << 4) | algorithm); + b43_shm_write16(dev, B43_SHM_SHARED, + B43_SHM_SH_KEYIDXBLOCK + (kidx * 2), value); + + /* Write the key to the Key Table Pointer offset */ + offset = dev->ktp + (index * B43_SEC_KEYSIZE); + for (i = 0; i < B43_SEC_KEYSIZE; i += 2) { + value = key[i]; + value |= (u16) (key[i + 1]) << 8; + b43_shm_write16(dev, B43_SHM_SHARED, offset + i, value); + } +} + +static void keymac_write(struct b43_wldev *dev, u8 index, const u8 * addr) +{ + u32 addrtmp[2] = { 0, 0, }; + u8 per_sta_keys_start = 8; + + if (b43_new_kidx_api(dev)) + per_sta_keys_start = 4; + + B43_WARN_ON(index < per_sta_keys_start); + /* We have two default TX keys and possibly two default RX keys. + * Physical mac 0 is mapped to physical key 4 or 8, depending + * on the firmware version. + * So we must adjust the index here. + */ + index -= per_sta_keys_start; + + if (addr) { + addrtmp[0] = addr[0]; + addrtmp[0] |= ((u32) (addr[1]) << 8); + addrtmp[0] |= ((u32) (addr[2]) << 16); + addrtmp[0] |= ((u32) (addr[3]) << 24); + addrtmp[1] = addr[4]; + addrtmp[1] |= ((u32) (addr[5]) << 8); + } + + if (dev->dev->id.revision >= 5) { + /* Receive match transmitter address mechanism */ + b43_shm_write32(dev, B43_SHM_RCMTA, + (index * 2) + 0, addrtmp[0]); + b43_shm_write16(dev, B43_SHM_RCMTA, + (index * 2) + 1, addrtmp[1]); + } else { + /* RXE (Receive Engine) and + * PSM (Programmable State Machine) mechanism + */ + if (index < 8) { + /* TODO write to RCM 16, 19, 22 and 25 */ + } else { + b43_shm_write32(dev, B43_SHM_SHARED, + B43_SHM_SH_PSM + (index * 6) + 0, + addrtmp[0]); + b43_shm_write16(dev, B43_SHM_SHARED, + B43_SHM_SH_PSM + (index * 6) + 4, + addrtmp[1]); + } + } +} + +static void do_key_write(struct b43_wldev *dev, + u8 index, u8 algorithm, + const u8 * key, size_t key_len, const u8 * mac_addr) +{ + u8 buf[B43_SEC_KEYSIZE] = { 0, }; + u8 per_sta_keys_start = 8; + + if (b43_new_kidx_api(dev)) + per_sta_keys_start = 4; + + B43_WARN_ON(index >= dev->max_nr_keys); + B43_WARN_ON(key_len > B43_SEC_KEYSIZE); + + if (index >= per_sta_keys_start) + keymac_write(dev, index, NULL); /* First zero out mac. */ + if (key) + memcpy(buf, key, key_len); + key_write(dev, index, algorithm, buf); + if (index >= per_sta_keys_start) + keymac_write(dev, index, mac_addr); + + dev->key[index].algorithm = algorithm; +} + +static int b43_key_write(struct b43_wldev *dev, + int index, u8 algorithm, + const u8 * key, size_t key_len, + const u8 * mac_addr, + struct ieee80211_key_conf *keyconf) +{ + int i; + int sta_keys_start; + + if (key_len > B43_SEC_KEYSIZE) + return -EINVAL; + for (i = 0; i < dev->max_nr_keys; i++) { + /* Check that we don't already have this key. */ + B43_WARN_ON(dev->key[i].keyconf == keyconf); + } + if (index < 0) { + /* Either pairwise key or address is 00:00:00:00:00:00 + * for transmit-only keys. Search the index. */ + if (b43_new_kidx_api(dev)) + sta_keys_start = 4; + else + sta_keys_start = 8; + for (i = sta_keys_start; i < dev->max_nr_keys; i++) { + if (!dev->key[i].keyconf) { + /* found empty */ + index = i; + break; + } + } + if (index < 0) { + b43err(dev->wl, "Out of hardware key memory\n"); + return -ENOSPC; + } + } else + B43_WARN_ON(index > 3); + + do_key_write(dev, index, algorithm, key, key_len, mac_addr); + if ((index <= 3) && !b43_new_kidx_api(dev)) { + /* Default RX key */ + B43_WARN_ON(mac_addr); + do_key_write(dev, index + 4, algorithm, key, key_len, NULL); + } + keyconf->hw_key_idx = index; + dev->key[index].keyconf = keyconf; + + return 0; +} + +static int b43_key_clear(struct b43_wldev *dev, int index) +{ + if (B43_WARN_ON((index < 0) || (index >= dev->max_nr_keys))) + return -EINVAL; + do_key_write(dev, index, B43_SEC_ALGO_NONE, + NULL, B43_SEC_KEYSIZE, NULL); + if ((index <= 3) && !b43_new_kidx_api(dev)) { + do_key_write(dev, index + 4, B43_SEC_ALGO_NONE, + NULL, B43_SEC_KEYSIZE, NULL); + } + dev->key[index].keyconf = NULL; + + return 0; +} + +static void b43_clear_keys(struct b43_wldev *dev) +{ + int i; + + for (i = 0; i < dev->max_nr_keys; i++) + b43_key_clear(dev, i); +} + +void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags) +{ + u32 macctl; + u16 ucstat; + bool hwps; + bool awake; + int i; + + B43_WARN_ON((ps_flags & B43_PS_ENABLED) && + (ps_flags & B43_PS_DISABLED)); + B43_WARN_ON((ps_flags & B43_PS_AWAKE) && (ps_flags & B43_PS_ASLEEP)); + + if (ps_flags & B43_PS_ENABLED) { + hwps = 1; + } else if (ps_flags & B43_PS_DISABLED) { + hwps = 0; + } else { + //TODO: If powersave is not off and FIXME is not set and we are not in adhoc + // and thus is not an AP and we are associated, set bit 25 + } + if (ps_flags & B43_PS_AWAKE) { + awake = 1; + } else if (ps_flags & B43_PS_ASLEEP) { + awake = 0; + } else { + //TODO: If the device is awake or this is an AP, or we are scanning, or FIXME, + // or we are associated, or FIXME, or the latest PS-Poll packet sent was + // successful, set bit26 + } + +/* FIXME: For now we force awake-on and hwps-off */ + hwps = 0; + awake = 1; + + macctl = b43_read32(dev, B43_MMIO_MACCTL); + if (hwps) + macctl |= B43_MACCTL_HWPS; + else + macctl &= ~B43_MACCTL_HWPS; + if (awake) + macctl |= B43_MACCTL_AWAKE; + else + macctl &= ~B43_MACCTL_AWAKE; + b43_write32(dev, B43_MMIO_MACCTL, macctl); + /* Commit write */ + b43_read32(dev, B43_MMIO_MACCTL); + if (awake && dev->dev->id.revision >= 5) { + /* Wait for the microcode to wake up. */ + for (i = 0; i < 100; i++) { + ucstat = b43_shm_read16(dev, B43_SHM_SHARED, + B43_SHM_SH_UCODESTAT); + if (ucstat != B43_SHM_SH_UCODESTAT_SLEEP) + break; + udelay(10); + } + } +} + +/* Turn the Analog ON/OFF */ +static void b43_switch_analog(struct b43_wldev *dev, int on) +{ + b43_write16(dev, B43_MMIO_PHY0, on ? 0 : 0xF4); +} + +void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags) +{ + u32 tmslow; + u32 macctl; + + flags |= B43_TMSLOW_PHYCLKEN; + flags |= B43_TMSLOW_PHYRESET; + ssb_device_enable(dev->dev, flags); + msleep(2); /* Wait for the PLL to turn on. */ + + /* Now take the PHY out of Reset again */ + tmslow = ssb_read32(dev->dev, SSB_TMSLOW); + tmslow |= SSB_TMSLOW_FGC; + tmslow &= ~B43_TMSLOW_PHYRESET; + ssb_write32(dev->dev, SSB_TMSLOW, tmslow); + ssb_read32(dev->dev, SSB_TMSLOW); /* flush */ + msleep(1); + tmslow &= ~SSB_TMSLOW_FGC; + ssb_write32(dev->dev, SSB_TMSLOW, tmslow); + ssb_read32(dev->dev, SSB_TMSLOW); /* flush */ + msleep(1); + + /* Turn Analog ON */ + b43_switch_analog(dev, 1); + + macctl = b43_read32(dev, B43_MMIO_MACCTL); + macctl &= ~B43_MACCTL_GMODE; + if (flags & B43_TMSLOW_GMODE) + macctl |= B43_MACCTL_GMODE; + macctl |= B43_MACCTL_IHR_ENABLED; + b43_write32(dev, B43_MMIO_MACCTL, macctl); +} + +static void handle_irq_transmit_status(struct b43_wldev *dev) +{ + u32 v0, v1; + u16 tmp; + struct b43_txstatus stat; + + while (1) { + v0 = b43_read32(dev, B43_MMIO_XMITSTAT_0); + if (!(v0 & 0x00000001)) + break; + v1 = b43_read32(dev, B43_MMIO_XMITSTAT_1); + + stat.cookie = (v0 >> 16); + stat.seq = (v1 & 0x0000FFFF); + stat.phy_stat = ((v1 & 0x00FF0000) >> 16); + tmp = (v0 & 0x0000FFFF); + stat.frame_count = ((tmp & 0xF000) >> 12); + stat.rts_count = ((tmp & 0x0F00) >> 8); + stat.supp_reason = ((tmp & 0x001C) >> 2); + stat.pm_indicated = !!(tmp & 0x0080); + stat.intermediate = !!(tmp & 0x0040); + stat.for_ampdu = !!(tmp & 0x0020); + stat.acked = !!(tmp & 0x0002); + + b43_handle_txstatus(dev, &stat); + } +} + +static void drain_txstatus_queue(struct b43_wldev *dev) +{ + u32 dummy; + + if (dev->dev->id.revision < 5) + return; + /* Read all entries from the microcode TXstatus FIFO + * and throw them away. + */ + while (1) { + dummy = b43_read32(dev, B43_MMIO_XMITSTAT_0); + if (!(dummy & 0x00000001)) + break; + dummy = b43_read32(dev, B43_MMIO_XMITSTAT_1); + } +} + +static u32 b43_jssi_read(struct b43_wldev *dev) +{ + u32 val = 0; + + val = b43_shm_read16(dev, B43_SHM_SHARED, 0x08A); + val <<= 16; + val |= b43_shm_read16(dev, B43_SHM_SHARED, 0x088); + + return val; +} + +static void b43_jssi_write(struct b43_wldev *dev, u32 jssi) +{ + b43_shm_write16(dev, B43_SHM_SHARED, 0x088, (jssi & 0x0000FFFF)); + b43_shm_write16(dev, B43_SHM_SHARED, 0x08A, (jssi & 0xFFFF0000) >> 16); +} + +static void b43_generate_noise_sample(struct b43_wldev *dev) +{ + b43_jssi_write(dev, 0x7F7F7F7F); + b43_write32(dev, B43_MMIO_STATUS2_BITFIELD, + b43_read32(dev, B43_MMIO_STATUS2_BITFIELD) + | (1 << 4)); + B43_WARN_ON(dev->noisecalc.channel_at_start != dev->phy.channel); +} + +static void b43_calculate_link_quality(struct b43_wldev *dev) +{ + /* Top half of Link Quality calculation. */ + + if (dev->noisecalc.calculation_running) + return; + dev->noisecalc.channel_at_start = dev->phy.channel; + dev->noisecalc.calculation_running = 1; + dev->noisecalc.nr_samples = 0; + + b43_generate_noise_sample(dev); +} + +static void handle_irq_noise(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + u16 tmp; + u8 noise[4]; + u8 i, j; + s32 average; + + /* Bottom half of Link Quality calculation. */ + + B43_WARN_ON(!dev->noisecalc.calculation_running); + if (dev->noisecalc.channel_at_start != phy->channel) + goto drop_calculation; + *((u32 *) noise) = cpu_to_le32(b43_jssi_read(dev)); + if (noise[0] == 0x7F || noise[1] == 0x7F || + noise[2] == 0x7F || noise[3] == 0x7F) + goto generate_new; + + /* Get the noise samples. */ + B43_WARN_ON(dev->noisecalc.nr_samples >= 8); + i = dev->noisecalc.nr_samples; + noise[0] = limit_value(noise[0], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); + noise[1] = limit_value(noise[1], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); + noise[2] = limit_value(noise[2], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); + noise[3] = limit_value(noise[3], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); + dev->noisecalc.samples[i][0] = phy->nrssi_lt[noise[0]]; + dev->noisecalc.samples[i][1] = phy->nrssi_lt[noise[1]]; + dev->noisecalc.samples[i][2] = phy->nrssi_lt[noise[2]]; + dev->noisecalc.samples[i][3] = phy->nrssi_lt[noise[3]]; + dev->noisecalc.nr_samples++; + if (dev->noisecalc.nr_samples == 8) { + /* Calculate the Link Quality by the noise samples. */ + average = 0; + for (i = 0; i < 8; i++) { + for (j = 0; j < 4; j++) + average += dev->noisecalc.samples[i][j]; + } + average /= (8 * 4); + average *= 125; + average += 64; + average /= 128; + tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x40C); + tmp = (tmp / 128) & 0x1F; + if (tmp >= 8) + average += 2; + else + average -= 25; + if (tmp == 8) + average -= 72; + else + average -= 48; + + dev->stats.link_noise = average; + drop_calculation: + dev->noisecalc.calculation_running = 0; + return; + } + generate_new: + b43_generate_noise_sample(dev); +} + +static void handle_irq_tbtt_indication(struct b43_wldev *dev) +{ + if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) { + ///TODO: PS TBTT + } else { + if (1 /*FIXME: the last PSpoll frame was sent successfully */ ) + b43_power_saving_ctl_bits(dev, 0); + } + dev->reg124_set_0x4 = 0; + if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS)) + dev->reg124_set_0x4 = 1; +} + +static void handle_irq_atim_end(struct b43_wldev *dev) +{ + if (!dev->reg124_set_0x4 /*FIXME rename this variable */ ) + return; + b43_write32(dev, B43_MMIO_STATUS2_BITFIELD, + b43_read32(dev, B43_MMIO_STATUS2_BITFIELD) + | 0x4); +} + +static void handle_irq_pmq(struct b43_wldev *dev) +{ + u32 tmp; + + //TODO: AP mode. + + while (1) { + tmp = b43_read32(dev, B43_MMIO_PS_STATUS); + if (!(tmp & 0x00000008)) + break; + } + /* 16bit write is odd, but correct. */ + b43_write16(dev, B43_MMIO_PS_STATUS, 0x0002); +} + +static void b43_write_template_common(struct b43_wldev *dev, + const u8 * data, u16 size, + u16 ram_offset, + u16 shm_size_offset, u8 rate) +{ + u32 i, tmp; + struct b43_plcp_hdr4 plcp; + + plcp.data = 0; + b43_generate_plcp_hdr(&plcp, size + FCS_LEN, rate); + b43_ram_write(dev, ram_offset, le32_to_cpu(plcp.data)); + ram_offset += sizeof(u32); + /* The PLCP is 6 bytes long, but we only wrote 4 bytes, yet. + * So leave the first two bytes of the next write blank. + */ + tmp = (u32) (data[0]) << 16; + tmp |= (u32) (data[1]) << 24; + b43_ram_write(dev, ram_offset, tmp); + ram_offset += sizeof(u32); + for (i = 2; i < size; i += sizeof(u32)) { + tmp = (u32) (data[i + 0]); + if (i + 1 < size) + tmp |= (u32) (data[i + 1]) << 8; + if (i + 2 < size) + tmp |= (u32) (data[i + 2]) << 16; + if (i + 3 < size) + tmp |= (u32) (data[i + 3]) << 24; + b43_ram_write(dev, ram_offset + i - 2, tmp); + } + b43_shm_write16(dev, B43_SHM_SHARED, shm_size_offset, + size + sizeof(struct b43_plcp_hdr6)); +} + +static void b43_write_beacon_template(struct b43_wldev *dev, + u16 ram_offset, + u16 shm_size_offset, u8 rate) +{ + int len; + const u8 *data; + + B43_WARN_ON(!dev->cached_beacon); + len = min((size_t) dev->cached_beacon->len, + 0x200 - sizeof(struct b43_plcp_hdr6)); + data = (const u8 *)(dev->cached_beacon->data); + b43_write_template_common(dev, data, + len, ram_offset, shm_size_offset, rate); +} + +static void b43_write_probe_resp_plcp(struct b43_wldev *dev, + u16 shm_offset, u16 size, u8 rate) +{ + struct b43_plcp_hdr4 plcp; + u32 tmp; + __le16 dur; + + plcp.data = 0; + b43_generate_plcp_hdr(&plcp, size + FCS_LEN, rate); + dur = ieee80211_generic_frame_duration(dev->wl->hw, + dev->wl->if_id, size, + B43_RATE_TO_BASE100KBPS(rate)); + /* Write PLCP in two parts and timing for packet transfer */ + tmp = le32_to_cpu(plcp.data); + b43_shm_write16(dev, B43_SHM_SHARED, shm_offset, tmp & 0xFFFF); + b43_shm_write16(dev, B43_SHM_SHARED, shm_offset + 2, tmp >> 16); + b43_shm_write16(dev, B43_SHM_SHARED, shm_offset + 6, le16_to_cpu(dur)); +} + +/* Instead of using custom probe response template, this function + * just patches custom beacon template by: + * 1) Changing packet type + * 2) Patching duration field + * 3) Stripping TIM + */ +static u8 *b43_generate_probe_resp(struct b43_wldev *dev, + u16 * dest_size, u8 rate) +{ + const u8 *src_data; + u8 *dest_data; + u16 src_size, elem_size, src_pos, dest_pos; + __le16 dur; + struct ieee80211_hdr *hdr; + + B43_WARN_ON(!dev->cached_beacon); + src_size = dev->cached_beacon->len; + src_data = (const u8 *)dev->cached_beacon->data; + + if (unlikely(src_size < 0x24)) { + b43dbg(dev->wl, "b43_generate_probe_resp: " "invalid beacon\n"); + return NULL; + } + + dest_data = kmalloc(src_size, GFP_ATOMIC); + if (unlikely(!dest_data)) + return NULL; + + /* 0x24 is offset of first variable-len Information-Element + * in beacon frame. + */ + memcpy(dest_data, src_data, 0x24); + src_pos = dest_pos = 0x24; + for (; src_pos < src_size - 2; src_pos += elem_size) { + elem_size = src_data[src_pos + 1] + 2; + if (src_data[src_pos] != 0x05) { /* TIM */ + memcpy(dest_data + dest_pos, src_data + src_pos, + elem_size); + dest_pos += elem_size; + } + } + *dest_size = dest_pos; + hdr = (struct ieee80211_hdr *)dest_data; + + /* Set the frame control. */ + hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | + IEEE80211_STYPE_PROBE_RESP); + dur = ieee80211_generic_frame_duration(dev->wl->hw, + dev->wl->if_id, *dest_size, + B43_RATE_TO_BASE100KBPS(rate)); + hdr->duration_id = dur; + + return dest_data; +} + +static void b43_write_probe_resp_template(struct b43_wldev *dev, + u16 ram_offset, + u16 shm_size_offset, u8 rate) +{ + u8 *probe_resp_data; + u16 size; + + B43_WARN_ON(!dev->cached_beacon); + size = dev->cached_beacon->len; + probe_resp_data = b43_generate_probe_resp(dev, &size, rate); + if (unlikely(!probe_resp_data)) + return; + + /* Looks like PLCP headers plus packet timings are stored for + * all possible basic rates + */ + b43_write_probe_resp_plcp(dev, 0x31A, size, B43_CCK_RATE_1MB); + b43_write_probe_resp_plcp(dev, 0x32C, size, B43_CCK_RATE_2MB); + b43_write_probe_resp_plcp(dev, 0x33E, size, B43_CCK_RATE_5MB); + b43_write_probe_resp_plcp(dev, 0x350, size, B43_CCK_RATE_11MB); + + size = min((size_t) size, 0x200 - sizeof(struct b43_plcp_hdr6)); + b43_write_template_common(dev, probe_resp_data, + size, ram_offset, shm_size_offset, rate); + kfree(probe_resp_data); +} + +static int b43_refresh_cached_beacon(struct b43_wldev *dev, + struct sk_buff *beacon) +{ + if (dev->cached_beacon) + kfree_skb(dev->cached_beacon); + dev->cached_beacon = beacon; + + return 0; +} + +static void b43_update_templates(struct b43_wldev *dev) +{ + u32 status; + + B43_WARN_ON(!dev->cached_beacon); + + b43_write_beacon_template(dev, 0x68, 0x18, B43_CCK_RATE_1MB); + b43_write_beacon_template(dev, 0x468, 0x1A, B43_CCK_RATE_1MB); + b43_write_probe_resp_template(dev, 0x268, 0x4A, B43_CCK_RATE_11MB); + + status = b43_read32(dev, B43_MMIO_STATUS2_BITFIELD); + status |= 0x03; + b43_write32(dev, B43_MMIO_STATUS2_BITFIELD, status); +} + +static void b43_refresh_templates(struct b43_wldev *dev, struct sk_buff *beacon) +{ + int err; + + err = b43_refresh_cached_beacon(dev, beacon); + if (unlikely(err)) + return; + b43_update_templates(dev); +} + +static void b43_set_ssid(struct b43_wldev *dev, const u8 * ssid, u8 ssid_len) +{ + u32 tmp; + u16 i, len; + + len = min((u16) ssid_len, (u16) 0x100); + for (i = 0; i < len; i += sizeof(u32)) { + tmp = (u32) (ssid[i + 0]); + if (i + 1 < len) + tmp |= (u32) (ssid[i + 1]) << 8; + if (i + 2 < len) + tmp |= (u32) (ssid[i + 2]) << 16; + if (i + 3 < len) + tmp |= (u32) (ssid[i + 3]) << 24; + b43_shm_write32(dev, B43_SHM_SHARED, 0x380 + i, tmp); + } + b43_shm_write16(dev, B43_SHM_SHARED, 0x48, len); +} + +static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int) +{ + b43_time_lock(dev); + if (dev->dev->id.revision >= 3) { + b43_write32(dev, 0x188, (beacon_int << 16)); + } else { + b43_write16(dev, 0x606, (beacon_int >> 6)); + b43_write16(dev, 0x610, beacon_int); + } + b43_time_unlock(dev); +} + +static void handle_irq_beacon(struct b43_wldev *dev) +{ + u32 status; + + if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) + return; + + dev->irq_savedstate &= ~B43_IRQ_BEACON; + status = b43_read32(dev, B43_MMIO_STATUS2_BITFIELD); + + if (!dev->cached_beacon || ((status & 0x1) && (status & 0x2))) { + /* ACK beacon IRQ. */ + b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, B43_IRQ_BEACON); + dev->irq_savedstate |= B43_IRQ_BEACON; + if (dev->cached_beacon) + kfree_skb(dev->cached_beacon); + dev->cached_beacon = NULL; + return; + } + if (!(status & 0x1)) { + b43_write_beacon_template(dev, 0x68, 0x18, B43_CCK_RATE_1MB); + status |= 0x1; + b43_write32(dev, B43_MMIO_STATUS2_BITFIELD, status); + } + if (!(status & 0x2)) { + b43_write_beacon_template(dev, 0x468, 0x1A, B43_CCK_RATE_1MB); + status |= 0x2; + b43_write32(dev, B43_MMIO_STATUS2_BITFIELD, status); + } +} + +static void handle_irq_ucode_debug(struct b43_wldev *dev) +{ + //TODO +} + +/* Interrupt handler bottom-half */ +static void b43_interrupt_tasklet(struct b43_wldev *dev) +{ + u32 reason; + u32 dma_reason[ARRAY_SIZE(dev->dma_reason)]; + u32 merged_dma_reason = 0; + int i, activity = 0; + unsigned long flags; + + spin_lock_irqsave(&dev->wl->irq_lock, flags); + + B43_WARN_ON(b43_status(dev) != B43_STAT_STARTED); + + reason = dev->irq_reason; + for (i = 0; i < ARRAY_SIZE(dma_reason); i++) { + dma_reason[i] = dev->dma_reason[i]; + merged_dma_reason |= dma_reason[i]; + } + + if (unlikely(reason & B43_IRQ_MAC_TXERR)) + b43err(dev->wl, "MAC transmission error\n"); + + if (unlikely(reason & B43_IRQ_PHY_TXERR)) + b43err(dev->wl, "PHY transmission error\n"); + + if (unlikely(merged_dma_reason & (B43_DMAIRQ_FATALMASK | + B43_DMAIRQ_NONFATALMASK))) { + if (merged_dma_reason & B43_DMAIRQ_FATALMASK) { + b43err(dev->wl, "Fatal DMA error: " + "0x%08X, 0x%08X, 0x%08X, " + "0x%08X, 0x%08X, 0x%08X\n", + dma_reason[0], dma_reason[1], + dma_reason[2], dma_reason[3], + dma_reason[4], dma_reason[5]); + b43_controller_restart(dev, "DMA error"); + mmiowb(); + spin_unlock_irqrestore(&dev->wl->irq_lock, flags); + return; + } + if (merged_dma_reason & B43_DMAIRQ_NONFATALMASK) { + b43err(dev->wl, "DMA error: " + "0x%08X, 0x%08X, 0x%08X, " + "0x%08X, 0x%08X, 0x%08X\n", + dma_reason[0], dma_reason[1], + dma_reason[2], dma_reason[3], + dma_reason[4], dma_reason[5]); + } + } + + if (unlikely(reason & B43_IRQ_UCODE_DEBUG)) + handle_irq_ucode_debug(dev); + if (reason & B43_IRQ_TBTT_INDI) + handle_irq_tbtt_indication(dev); + if (reason & B43_IRQ_ATIM_END) + handle_irq_atim_end(dev); + if (reason & B43_IRQ_BEACON) + handle_irq_beacon(dev); + if (reason & B43_IRQ_PMQ) + handle_irq_pmq(dev); + if (reason & B43_IRQ_TXFIFO_FLUSH_OK) ; + /*TODO*/ if (reason & B43_IRQ_NOISESAMPLE_OK) + handle_irq_noise(dev); + + /* Check the DMA reason registers for received data. */ + if (dma_reason[0] & B43_DMAIRQ_RX_DONE) { + if (b43_using_pio(dev)) + b43_pio_rx(dev->pio.queue0); + else + b43_dma_rx(dev->dma.rx_ring0); + /* We intentionally don't set "activity" to 1, here. */ + } + B43_WARN_ON(dma_reason[1] & B43_DMAIRQ_RX_DONE); + B43_WARN_ON(dma_reason[2] & B43_DMAIRQ_RX_DONE); + if (dma_reason[3] & B43_DMAIRQ_RX_DONE) { + if (b43_using_pio(dev)) + b43_pio_rx(dev->pio.queue3); + else + b43_dma_rx(dev->dma.rx_ring3); + activity = 1; + } + B43_WARN_ON(dma_reason[4] & B43_DMAIRQ_RX_DONE); + B43_WARN_ON(dma_reason[5] & B43_DMAIRQ_RX_DONE); + + if (reason & B43_IRQ_TX_OK) { + handle_irq_transmit_status(dev); + activity = 1; + //TODO: In AP mode, this also causes sending of powersave responses. + } + + if (!modparam_noleds) + b43_leds_update(dev, activity); + b43_interrupt_enable(dev, dev->irq_savedstate); + mmiowb(); + spin_unlock_irqrestore(&dev->wl->irq_lock, flags); +} + +static void pio_irq_workaround(struct b43_wldev *dev, u16 base, int queueidx) +{ + u16 rxctl; + + rxctl = b43_read16(dev, base + B43_PIO_RXCTL); + if (rxctl & B43_PIO_RXCTL_DATAAVAILABLE) + dev->dma_reason[queueidx] |= B43_DMAIRQ_RX_DONE; + else + dev->dma_reason[queueidx] &= ~B43_DMAIRQ_RX_DONE; +} + +static void b43_interrupt_ack(struct b43_wldev *dev, u32 reason) +{ + if (b43_using_pio(dev) && + (dev->dev->id.revision < 3) && + (!(reason & B43_IRQ_PIO_WORKAROUND))) { + /* Apply a PIO specific workaround to the dma_reasons */ + pio_irq_workaround(dev, B43_MMIO_PIO1_BASE, 0); + pio_irq_workaround(dev, B43_MMIO_PIO2_BASE, 1); + pio_irq_workaround(dev, B43_MMIO_PIO3_BASE, 2); + pio_irq_workaround(dev, B43_MMIO_PIO4_BASE, 3); + } + + b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, reason); + + b43_write32(dev, B43_MMIO_DMA0_REASON, dev->dma_reason[0]); + b43_write32(dev, B43_MMIO_DMA1_REASON, dev->dma_reason[1]); + b43_write32(dev, B43_MMIO_DMA2_REASON, dev->dma_reason[2]); + b43_write32(dev, B43_MMIO_DMA3_REASON, dev->dma_reason[3]); + b43_write32(dev, B43_MMIO_DMA4_REASON, dev->dma_reason[4]); + b43_write32(dev, B43_MMIO_DMA5_REASON, dev->dma_reason[5]); +} + +/* Interrupt handler top-half */ +static irqreturn_t b43_interrupt_handler(int irq, void *dev_id) +{ + irqreturn_t ret = IRQ_NONE; + struct b43_wldev *dev = dev_id; + u32 reason; + + if (!dev) + return IRQ_NONE; + + spin_lock(&dev->wl->irq_lock); + + if (b43_status(dev) < B43_STAT_STARTED) + goto out; + reason = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON); + if (reason == 0xffffffff) /* shared IRQ */ + goto out; + ret = IRQ_HANDLED; + reason &= b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); + if (!reason) + goto out; + + dev->dma_reason[0] = b43_read32(dev, B43_MMIO_DMA0_REASON) + & 0x0001DC00; + dev->dma_reason[1] = b43_read32(dev, B43_MMIO_DMA1_REASON) + & 0x0000DC00; + dev->dma_reason[2] = b43_read32(dev, B43_MMIO_DMA2_REASON) + & 0x0000DC00; + dev->dma_reason[3] = b43_read32(dev, B43_MMIO_DMA3_REASON) + & 0x0001DC00; + dev->dma_reason[4] = b43_read32(dev, B43_MMIO_DMA4_REASON) + & 0x0000DC00; + dev->dma_reason[5] = b43_read32(dev, B43_MMIO_DMA5_REASON) + & 0x0000DC00; + + b43_interrupt_ack(dev, reason); + /* disable all IRQs. They are enabled again in the bottom half. */ + dev->irq_savedstate = b43_interrupt_disable(dev, B43_IRQ_ALL); + /* save the reason code and call our bottom half. */ + dev->irq_reason = reason; + tasklet_schedule(&dev->isr_tasklet); + out: + mmiowb(); + spin_unlock(&dev->wl->irq_lock); + + return ret; +} + +static void b43_release_firmware(struct b43_wldev *dev) +{ + release_firmware(dev->fw.ucode); + dev->fw.ucode = NULL; + release_firmware(dev->fw.pcm); + dev->fw.pcm = NULL; + release_firmware(dev->fw.initvals); + dev->fw.initvals = NULL; + release_firmware(dev->fw.initvals_band); + dev->fw.initvals_band = NULL; +} + +static void b43_print_fw_helptext(struct b43_wl *wl) +{ + b43err(wl, "You must go to " + "http://linuxwireless.org/en/users/Drivers/bcm43xx#devicefirmware " + "and download the correct firmware (version 4).\n"); +} + +static int do_request_fw(struct b43_wldev *dev, + const char *name, + const struct firmware **fw) +{ + const size_t plen = sizeof(modparam_fwpostfix) + 32; + char path[plen]; + struct b43_fw_header *hdr; + u32 size; + int err; + + if (!name) + return 0; + + snprintf(path, ARRAY_SIZE(path), + "b43%s/%s.fw", + modparam_fwpostfix, name); + err = request_firmware(fw, path, dev->dev->dev); + if (err) { + b43err(dev->wl, "Firmware file \"%s\" not found " + "or load failed.\n", path); + return err; + } + if ((*fw)->size < sizeof(struct b43_fw_header)) + goto err_format; + hdr = (struct b43_fw_header *)((*fw)->data); + switch (hdr->type) { + case B43_FW_TYPE_UCODE: + case B43_FW_TYPE_PCM: + size = be32_to_cpu(hdr->size); + if (size != (*fw)->size - sizeof(struct b43_fw_header)) + goto err_format; + /* fallthrough */ + case B43_FW_TYPE_IV: + if (hdr->ver != 1) + goto err_format; + break; + default: + goto err_format; + } + + return err; + +err_format: + b43err(dev->wl, "Firmware file \"%s\" format error.\n", path); + return -EPROTO; +} + +static int b43_request_firmware(struct b43_wldev *dev) +{ + struct b43_firmware *fw = &dev->fw; + const u8 rev = dev->dev->id.revision; + const char *filename; + u32 tmshigh; + int err; + + tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH); + if (!fw->ucode) { + if ((rev >= 5) && (rev <= 10)) + filename = "ucode5"; + else if ((rev >= 11) && (rev <= 12)) + filename = "ucode11"; + else if (rev >= 13) + filename = "ucode13"; + else + goto err_no_ucode; + err = do_request_fw(dev, filename, &fw->ucode); + if (err) + goto err_load; + } + if (!fw->pcm) { + if ((rev >= 5) && (rev <= 10)) + filename = "pcm5"; + else if (rev >= 11) + filename = NULL; + else + goto err_no_pcm; + err = do_request_fw(dev, filename, &fw->pcm); + if (err) + goto err_load; + } + if (!fw->initvals) { + switch (dev->phy.type) { + case B43_PHYTYPE_A: + if ((rev >= 5) && (rev <= 10)) { + if (tmshigh & B43_TMSHIGH_GPHY) + filename = "a0g1initvals5"; + else + filename = "a0g0initvals5"; + } else + goto err_no_initvals; + break; + case B43_PHYTYPE_G: + if ((rev >= 5) && (rev <= 10)) + filename = "b0g0initvals5"; + else if (rev >= 13) + filename = "lp0initvals13"; + else + goto err_no_initvals; + break; + default: + goto err_no_initvals; + } + err = do_request_fw(dev, filename, &fw->initvals); + if (err) + goto err_load; + } + if (!fw->initvals_band) { + switch (dev->phy.type) { + case B43_PHYTYPE_A: + if ((rev >= 5) && (rev <= 10)) { + if (tmshigh & B43_TMSHIGH_GPHY) + filename = "a0g1bsinitvals5"; + else + filename = "a0g0bsinitvals5"; + } else if (rev >= 11) + filename = NULL; + else + goto err_no_initvals; + break; + case B43_PHYTYPE_G: + if ((rev >= 5) && (rev <= 10)) + filename = "b0g0bsinitvals5"; + else if (rev >= 11) + filename = NULL; + else + goto err_no_initvals; + break; + default: + goto err_no_initvals; + } + err = do_request_fw(dev, filename, &fw->initvals_band); + if (err) + goto err_load; + } + + return 0; + +err_load: + b43_print_fw_helptext(dev->wl); + goto error; + +err_no_ucode: + err = -ENODEV; + b43err(dev->wl, "No microcode available for core rev %u\n", rev); + goto error; + +err_no_pcm: + err = -ENODEV; + b43err(dev->wl, "No PCM available for core rev %u\n", rev); + goto error; + +err_no_initvals: + err = -ENODEV; + b43err(dev->wl, "No Initial Values firmware file for PHY %u, " + "core rev %u\n", dev->phy.type, rev); + goto error; + +error: + b43_release_firmware(dev); + return err; +} + +static int b43_upload_microcode(struct b43_wldev *dev) +{ + const size_t hdr_len = sizeof(struct b43_fw_header); + const __be32 *data; + unsigned int i, len; + u16 fwrev, fwpatch, fwdate, fwtime; + u32 tmp; + int err = 0; + + /* Upload Microcode. */ + data = (__be32 *) (dev->fw.ucode->data + hdr_len); + len = (dev->fw.ucode->size - hdr_len) / sizeof(__be32); + b43_shm_control_word(dev, B43_SHM_UCODE | B43_SHM_AUTOINC_W, 0x0000); + for (i = 0; i < len; i++) { + b43_write32(dev, B43_MMIO_SHM_DATA, be32_to_cpu(data[i])); + udelay(10); + } + + if (dev->fw.pcm) { + /* Upload PCM data. */ + data = (__be32 *) (dev->fw.pcm->data + hdr_len); + len = (dev->fw.pcm->size - hdr_len) / sizeof(__be32); + b43_shm_control_word(dev, B43_SHM_HW, 0x01EA); + b43_write32(dev, B43_MMIO_SHM_DATA, 0x00004000); + /* No need for autoinc bit in SHM_HW */ + b43_shm_control_word(dev, B43_SHM_HW, 0x01EB); + for (i = 0; i < len; i++) { + b43_write32(dev, B43_MMIO_SHM_DATA, be32_to_cpu(data[i])); + udelay(10); + } + } + + b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, B43_IRQ_ALL); + b43_write32(dev, B43_MMIO_MACCTL, + B43_MACCTL_PSM_RUN | + B43_MACCTL_IHR_ENABLED | B43_MACCTL_INFRA); + + /* Wait for the microcode to load and respond */ + i = 0; + while (1) { + tmp = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON); + if (tmp == B43_IRQ_MAC_SUSPENDED) + break; + i++; + if (i >= 50) { + b43err(dev->wl, "Microcode not responding\n"); + b43_print_fw_helptext(dev->wl); + err = -ENODEV; + goto out; + } + udelay(10); + } + b43_read32(dev, B43_MMIO_GEN_IRQ_REASON); /* dummy read */ + + /* Get and check the revisions. */ + fwrev = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_UCODEREV); + fwpatch = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_UCODEPATCH); + fwdate = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_UCODEDATE); + fwtime = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_UCODETIME); + + if (fwrev <= 0x128) { + b43err(dev->wl, "YOUR FIRMWARE IS TOO OLD. Firmware from " + "binary drivers older than version 4.x is unsupported. " + "You must upgrade your firmware files.\n"); + b43_print_fw_helptext(dev->wl); + b43_write32(dev, B43_MMIO_MACCTL, 0); + err = -EOPNOTSUPP; + goto out; + } + b43dbg(dev->wl, "Loading firmware version %u.%u " + "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n", + fwrev, fwpatch, + (fwdate >> 12) & 0xF, (fwdate >> 8) & 0xF, fwdate & 0xFF, + (fwtime >> 11) & 0x1F, (fwtime >> 5) & 0x3F, fwtime & 0x1F); + + dev->fw.rev = fwrev; + dev->fw.patch = fwpatch; + + out: + return err; +} + +static int b43_write_initvals(struct b43_wldev *dev, + const struct b43_iv *ivals, + size_t count, + size_t array_size) +{ + const struct b43_iv *iv; + u16 offset; + size_t i; + bool bit32; + + BUILD_BUG_ON(sizeof(struct b43_iv) != 6); + iv = ivals; + for (i = 0; i < count; i++) { + if (array_size < sizeof(iv->offset_size)) + goto err_format; + array_size -= sizeof(iv->offset_size); + offset = be16_to_cpu(iv->offset_size); + bit32 = !!(offset & B43_IV_32BIT); + offset &= B43_IV_OFFSET_MASK; + if (offset >= 0x1000) + goto err_format; + if (bit32) { + u32 value; + + if (array_size < sizeof(iv->data.d32)) + goto err_format; + array_size -= sizeof(iv->data.d32); + + value = be32_to_cpu(get_unaligned(&iv->data.d32)); + b43_write32(dev, offset, value); + + iv = (const struct b43_iv *)((const uint8_t *)iv + + sizeof(__be16) + + sizeof(__be32)); + } else { + u16 value; + + if (array_size < sizeof(iv->data.d16)) + goto err_format; + array_size -= sizeof(iv->data.d16); + + value = be16_to_cpu(iv->data.d16); + b43_write16(dev, offset, value); + + iv = (const struct b43_iv *)((const uint8_t *)iv + + sizeof(__be16) + + sizeof(__be16)); + } + } + if (array_size) + goto err_format; + + return 0; + +err_format: + b43err(dev->wl, "Initial Values Firmware file-format error.\n"); + b43_print_fw_helptext(dev->wl); + + return -EPROTO; +} + +static int b43_upload_initvals(struct b43_wldev *dev) +{ + const size_t hdr_len = sizeof(struct b43_fw_header); + const struct b43_fw_header *hdr; + struct b43_firmware *fw = &dev->fw; + const struct b43_iv *ivals; + size_t count; + int err; + + hdr = (const struct b43_fw_header *)(fw->initvals->data); + ivals = (const struct b43_iv *)(fw->initvals->data + hdr_len); + count = be32_to_cpu(hdr->size); + err = b43_write_initvals(dev, ivals, count, + fw->initvals->size - hdr_len); + if (err) + goto out; + if (fw->initvals_band) { + hdr = (const struct b43_fw_header *)(fw->initvals_band->data); + ivals = (const struct b43_iv *)(fw->initvals_band->data + hdr_len); + count = be32_to_cpu(hdr->size); + err = b43_write_initvals(dev, ivals, count, + fw->initvals_band->size - hdr_len); + if (err) + goto out; + } +out: + + return err; +} + +/* Initialize the GPIOs + * http://bcm-specs.sipsolutions.net/GPIO + */ +static int b43_gpio_init(struct b43_wldev *dev) +{ + struct ssb_bus *bus = dev->dev->bus; + struct ssb_device *gpiodev, *pcidev = NULL; + u32 mask, set; + + b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL) + & ~B43_MACCTL_GPOUTSMSK); + + b43_leds_switch_all(dev, 0); + b43_write16(dev, B43_MMIO_GPIO_MASK, b43_read16(dev, B43_MMIO_GPIO_MASK) + | 0x000F); + + mask = 0x0000001F; + set = 0x0000000F; + if (dev->dev->bus->chip_id == 0x4301) { + mask |= 0x0060; + set |= 0x0060; + } + if (0 /* FIXME: conditional unknown */ ) { + b43_write16(dev, B43_MMIO_GPIO_MASK, + b43_read16(dev, B43_MMIO_GPIO_MASK) + | 0x0100); + mask |= 0x0180; + set |= 0x0180; + } + if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_PACTRL) { + b43_write16(dev, B43_MMIO_GPIO_MASK, + b43_read16(dev, B43_MMIO_GPIO_MASK) + | 0x0200); + mask |= 0x0200; + set |= 0x0200; + } + if (dev->dev->id.revision >= 2) + mask |= 0x0010; /* FIXME: This is redundant. */ + +#ifdef CONFIG_SSB_DRIVER_PCICORE + pcidev = bus->pcicore.dev; +#endif + gpiodev = bus->chipco.dev ? : pcidev; + if (!gpiodev) + return 0; + ssb_write32(gpiodev, B43_GPIO_CONTROL, + (ssb_read32(gpiodev, B43_GPIO_CONTROL) + & mask) | set); + + return 0; +} + +/* Turn off all GPIO stuff. Call this on module unload, for example. */ +static void b43_gpio_cleanup(struct b43_wldev *dev) +{ + struct ssb_bus *bus = dev->dev->bus; + struct ssb_device *gpiodev, *pcidev = NULL; + +#ifdef CONFIG_SSB_DRIVER_PCICORE + pcidev = bus->pcicore.dev; +#endif + gpiodev = bus->chipco.dev ? : pcidev; + if (!gpiodev) + return; + ssb_write32(gpiodev, B43_GPIO_CONTROL, 0); +} + +/* http://bcm-specs.sipsolutions.net/EnableMac */ +void b43_mac_enable(struct b43_wldev *dev) +{ + dev->mac_suspended--; + B43_WARN_ON(dev->mac_suspended < 0); + if (dev->mac_suspended == 0) { + b43_write32(dev, B43_MMIO_MACCTL, + b43_read32(dev, B43_MMIO_MACCTL) + | B43_MACCTL_ENABLED); + b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, + B43_IRQ_MAC_SUSPENDED); + /* Commit writes */ + b43_read32(dev, B43_MMIO_MACCTL); + b43_read32(dev, B43_MMIO_GEN_IRQ_REASON); + b43_power_saving_ctl_bits(dev, 0); + } +} + +/* http://bcm-specs.sipsolutions.net/SuspendMAC */ +void b43_mac_suspend(struct b43_wldev *dev) +{ + int i; + u32 tmp; + + B43_WARN_ON(dev->mac_suspended < 0); + if (dev->mac_suspended == 0) { + b43_power_saving_ctl_bits(dev, B43_PS_AWAKE); + b43_write32(dev, B43_MMIO_MACCTL, + b43_read32(dev, B43_MMIO_MACCTL) + & ~B43_MACCTL_ENABLED); + /* force pci to flush the write */ + b43_read32(dev, B43_MMIO_MACCTL); + for (i = 10000; i; i--) { + tmp = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON); + if (tmp & B43_IRQ_MAC_SUSPENDED) + goto out; + udelay(1); + } + b43err(dev->wl, "MAC suspend failed\n"); + } + out: + dev->mac_suspended++; +} + +static void b43_adjust_opmode(struct b43_wldev *dev) +{ + struct b43_wl *wl = dev->wl; + u32 ctl; + u16 cfp_pretbtt; + + ctl = b43_read32(dev, B43_MMIO_MACCTL); + /* Reset status to STA infrastructure mode. */ + ctl &= ~B43_MACCTL_AP; + ctl &= ~B43_MACCTL_KEEP_CTL; + ctl &= ~B43_MACCTL_KEEP_BADPLCP; + ctl &= ~B43_MACCTL_KEEP_BAD; + ctl &= ~B43_MACCTL_PROMISC; + ctl |= B43_MACCTL_INFRA; + + if (wl->operating) { + switch (wl->if_type) { + case IEEE80211_IF_TYPE_AP: + ctl |= B43_MACCTL_AP; + break; + case IEEE80211_IF_TYPE_IBSS: + ctl &= ~B43_MACCTL_INFRA; + break; + case IEEE80211_IF_TYPE_STA: + case IEEE80211_IF_TYPE_MNTR: + case IEEE80211_IF_TYPE_WDS: + break; + default: + B43_WARN_ON(1); + } + } + if (wl->monitor) { + ctl |= B43_MACCTL_KEEP_CTL; + if (modparam_mon_keep_bad) + ctl |= B43_MACCTL_KEEP_BAD; + if (modparam_mon_keep_badplcp) + ctl |= B43_MACCTL_KEEP_BADPLCP; + } + if (wl->promisc) + ctl |= B43_MACCTL_PROMISC; + /* Workaround: On old hardware the HW-MAC-address-filter + * doesn't work properly, so always run promisc in filter + * it in software. */ + if (dev->dev->id.revision <= 4) + ctl |= B43_MACCTL_PROMISC; + + b43_write32(dev, B43_MMIO_MACCTL, ctl); + + cfp_pretbtt = 2; + if ((ctl & B43_MACCTL_INFRA) && !(ctl & B43_MACCTL_AP)) { + if (dev->dev->bus->chip_id == 0x4306 && + dev->dev->bus->chip_rev == 3) + cfp_pretbtt = 100; + else + cfp_pretbtt = 50; + } + b43_write16(dev, 0x612, cfp_pretbtt); +} + +static void b43_rate_memory_write(struct b43_wldev *dev, u16 rate, int is_ofdm) +{ + u16 offset; + + if (is_ofdm) { + offset = 0x480; + offset += (b43_plcp_get_ratecode_ofdm(rate) & 0x000F) * 2; + } else { + offset = 0x4C0; + offset += (b43_plcp_get_ratecode_cck(rate) & 0x000F) * 2; + } + b43_shm_write16(dev, B43_SHM_SHARED, offset + 0x20, + b43_shm_read16(dev, B43_SHM_SHARED, offset)); +} + +static void b43_rate_memory_init(struct b43_wldev *dev) +{ + switch (dev->phy.type) { + case B43_PHYTYPE_A: + case B43_PHYTYPE_G: + b43_rate_memory_write(dev, B43_OFDM_RATE_6MB, 1); + b43_rate_memory_write(dev, B43_OFDM_RATE_12MB, 1); + b43_rate_memory_write(dev, B43_OFDM_RATE_18MB, 1); + b43_rate_memory_write(dev, B43_OFDM_RATE_24MB, 1); + b43_rate_memory_write(dev, B43_OFDM_RATE_36MB, 1); + b43_rate_memory_write(dev, B43_OFDM_RATE_48MB, 1); + b43_rate_memory_write(dev, B43_OFDM_RATE_54MB, 1); + if (dev->phy.type == B43_PHYTYPE_A) + break; + /* fallthrough */ + case B43_PHYTYPE_B: + b43_rate_memory_write(dev, B43_CCK_RATE_1MB, 0); + b43_rate_memory_write(dev, B43_CCK_RATE_2MB, 0); + b43_rate_memory_write(dev, B43_CCK_RATE_5MB, 0); + b43_rate_memory_write(dev, B43_CCK_RATE_11MB, 0); + break; + default: + B43_WARN_ON(1); + } +} + +/* Set the TX-Antenna for management frames sent by firmware. */ +static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna) +{ + u16 ant = 0; + u16 tmp; + + switch (antenna) { + case B43_ANTENNA0: + ant |= B43_TX4_PHY_ANT0; + break; + case B43_ANTENNA1: + ant |= B43_TX4_PHY_ANT1; + break; + case B43_ANTENNA_AUTO: + ant |= B43_TX4_PHY_ANTLAST; + break; + default: + B43_WARN_ON(1); + } + + /* FIXME We also need to set the other flags of the PHY control field somewhere. */ + + /* For Beacons */ + tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL); + tmp = (tmp & ~B43_TX4_PHY_ANT) | ant; + b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL, tmp); + /* For ACK/CTS */ + tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_ACKCTSPHYCTL); + tmp = (tmp & ~B43_TX4_PHY_ANT) | ant; + b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_ACKCTSPHYCTL, tmp); + /* For Probe Resposes */ + tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_PRPHYCTL); + tmp = (tmp & ~B43_TX4_PHY_ANT) | ant; + b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRPHYCTL, tmp); +} + +/* This is the opposite of b43_chip_init() */ +static void b43_chip_exit(struct b43_wldev *dev) +{ + b43_radio_turn_off(dev); + if (!modparam_noleds) + b43_leds_exit(dev); + b43_gpio_cleanup(dev); + /* firmware is released later */ +} + +/* Initialize the chip + * http://bcm-specs.sipsolutions.net/ChipInit + */ +static int b43_chip_init(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + int err, tmp; + u32 value32; + u16 value16; + + b43_write32(dev, B43_MMIO_MACCTL, + B43_MACCTL_PSM_JMP0 | B43_MACCTL_IHR_ENABLED); + + err = b43_request_firmware(dev); + if (err) + goto out; + err = b43_upload_microcode(dev); + if (err) + goto out; /* firmware is released later */ + + err = b43_gpio_init(dev); + if (err) + goto out; /* firmware is released later */ + err = b43_upload_initvals(dev); + if (err) + goto err_gpio_cleanup; + b43_radio_turn_on(dev); + dev->radio_hw_enable = b43_is_hw_radio_enabled(dev); + b43dbg(dev->wl, "Radio %s by hardware\n", + (dev->radio_hw_enable == 0) ? "disabled" : "enabled"); + + b43_write16(dev, 0x03E6, 0x0000); + err = b43_phy_init(dev); + if (err) + goto err_radio_off; + + /* Select initial Interference Mitigation. */ + tmp = phy->interfmode; + phy->interfmode = B43_INTERFMODE_NONE; + b43_radio_set_interference_mitigation(dev, tmp); + + b43_set_rx_antenna(dev, B43_ANTENNA_DEFAULT); + b43_mgmtframe_txantenna(dev, B43_ANTENNA_DEFAULT); + + if (phy->type == B43_PHYTYPE_B) { + value16 = b43_read16(dev, 0x005E); + value16 |= 0x0004; + b43_write16(dev, 0x005E, value16); + } + b43_write32(dev, 0x0100, 0x01000000); + if (dev->dev->id.revision < 5) + b43_write32(dev, 0x010C, 0x01000000); + + b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL) + & ~B43_MACCTL_INFRA); + b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL) + | B43_MACCTL_INFRA); + /* Let beacons come through */ + b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL) + | B43_MACCTL_BEACPROMISC); + + if (b43_using_pio(dev)) { + b43_write32(dev, 0x0210, 0x00000100); + b43_write32(dev, 0x0230, 0x00000100); + b43_write32(dev, 0x0250, 0x00000100); + b43_write32(dev, 0x0270, 0x00000100); + b43_shm_write16(dev, B43_SHM_SHARED, 0x0034, 0x0000); + } + + /* Probe Response Timeout value */ + /* FIXME: Default to 0, has to be set by ioctl probably... :-/ */ + b43_shm_write16(dev, B43_SHM_SHARED, 0x0074, 0x0000); + + /* Initially set the wireless operation mode. */ + b43_adjust_opmode(dev); + + if (dev->dev->id.revision < 3) { + b43_write16(dev, 0x060E, 0x0000); + b43_write16(dev, 0x0610, 0x8000); + b43_write16(dev, 0x0604, 0x0000); + b43_write16(dev, 0x0606, 0x0200); + } else { + b43_write32(dev, 0x0188, 0x80000000); + b43_write32(dev, 0x018C, 0x02000000); + } + b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, 0x00004000); + b43_write32(dev, B43_MMIO_DMA0_IRQ_MASK, 0x0001DC00); + b43_write32(dev, B43_MMIO_DMA1_IRQ_MASK, 0x0000DC00); + b43_write32(dev, B43_MMIO_DMA2_IRQ_MASK, 0x0000DC00); + b43_write32(dev, B43_MMIO_DMA3_IRQ_MASK, 0x0001DC00); + b43_write32(dev, B43_MMIO_DMA4_IRQ_MASK, 0x0000DC00); + b43_write32(dev, B43_MMIO_DMA5_IRQ_MASK, 0x0000DC00); + + value32 = ssb_read32(dev->dev, SSB_TMSLOW); + value32 |= 0x00100000; + ssb_write32(dev->dev, SSB_TMSLOW, value32); + + b43_write16(dev, B43_MMIO_POWERUP_DELAY, + dev->dev->bus->chipco.fast_pwrup_delay); + + err = 0; + b43dbg(dev->wl, "Chip initialized\n"); + out: + return err; + + err_radio_off: + b43_radio_turn_off(dev); + err_gpio_cleanup: + b43_gpio_cleanup(dev); + goto out; +} + +static void b43_periodic_every120sec(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + + if (phy->type != B43_PHYTYPE_G || phy->rev < 2) + return; + + b43_mac_suspend(dev); + b43_lo_g_measure(dev); + b43_mac_enable(dev); + if (b43_has_hardware_pctl(phy)) + b43_lo_g_ctl_mark_all_unused(dev); +} + +static void b43_periodic_every60sec(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + + if (!b43_has_hardware_pctl(phy)) + b43_lo_g_ctl_mark_all_unused(dev); + if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI) { + b43_mac_suspend(dev); + b43_calc_nrssi_slope(dev); + if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 8)) { + u8 old_chan = phy->channel; + + /* VCO Calibration */ + if (old_chan >= 8) + b43_radio_selectchannel(dev, 1, 0); + else + b43_radio_selectchannel(dev, 13, 0); + b43_radio_selectchannel(dev, old_chan, 0); + } + b43_mac_enable(dev); + } +} + +static void b43_periodic_every30sec(struct b43_wldev *dev) +{ + /* Update device statistics. */ + b43_calculate_link_quality(dev); +} + +static void b43_periodic_every15sec(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + + if (phy->type == B43_PHYTYPE_G) { + //TODO: update_aci_moving_average + if (phy->aci_enable && phy->aci_wlan_automatic) { + b43_mac_suspend(dev); + if (!phy->aci_enable && 1 /*TODO: not scanning? */ ) { + if (0 /*TODO: bunch of conditions */ ) { + b43_radio_set_interference_mitigation + (dev, B43_INTERFMODE_MANUALWLAN); + } + } else if (1 /*TODO*/) { + /* + if ((aci_average > 1000) && !(b43_radio_aci_scan(dev))) { + b43_radio_set_interference_mitigation(dev, + B43_INTERFMODE_NONE); + } + */ + } + b43_mac_enable(dev); + } else if (phy->interfmode == B43_INTERFMODE_NONWLAN && + phy->rev == 1) { + //TODO: implement rev1 workaround + } + } + b43_phy_xmitpower(dev); //FIXME: unless scanning? + //TODO for APHY (temperature?) +} + +static void b43_periodic_every1sec(struct b43_wldev *dev) +{ + int radio_hw_enable; + + /* check if radio hardware enabled status changed */ + radio_hw_enable = b43_is_hw_radio_enabled(dev); + if (unlikely(dev->radio_hw_enable != radio_hw_enable)) { + dev->radio_hw_enable = radio_hw_enable; + b43dbg(dev->wl, "Radio hardware status changed to %s\n", + (radio_hw_enable == 0) ? "disabled" : "enabled"); + b43_leds_update(dev, 0); + } +} + +static void do_periodic_work(struct b43_wldev *dev) +{ + unsigned int state; + + state = dev->periodic_state; + if (state % 120 == 0) + b43_periodic_every120sec(dev); + if (state % 60 == 0) + b43_periodic_every60sec(dev); + if (state % 30 == 0) + b43_periodic_every30sec(dev); + if (state % 15 == 0) + b43_periodic_every15sec(dev); + b43_periodic_every1sec(dev); +} + +/* Estimate a "Badness" value based on the periodic work + * state-machine state. "Badness" is worse (bigger), if the + * periodic work will take longer. + */ +static int estimate_periodic_work_badness(unsigned int state) +{ + int badness = 0; + + if (state % 120 == 0) /* every 120 sec */ + badness += 10; + if (state % 60 == 0) /* every 60 sec */ + badness += 5; + if (state % 30 == 0) /* every 30 sec */ + badness += 1; + if (state % 15 == 0) /* every 15 sec */ + badness += 1; + +#define BADNESS_LIMIT 4 + return badness; +} + +static void b43_periodic_work_handler(struct work_struct *work) +{ + struct b43_wldev *dev = + container_of(work, struct b43_wldev, periodic_work.work); + unsigned long flags, delay; + u32 savedirqs = 0; + int badness; + + mutex_lock(&dev->wl->mutex); + + if (unlikely(b43_status(dev) != B43_STAT_STARTED)) + goto out; + if (b43_debug(dev, B43_DBG_PWORK_STOP)) + goto out_requeue; + + badness = estimate_periodic_work_badness(dev->periodic_state); + if (badness > BADNESS_LIMIT) { + spin_lock_irqsave(&dev->wl->irq_lock, flags); + /* Suspend TX as we don't want to transmit packets while + * we recalibrate the hardware. */ + b43_tx_suspend(dev); + savedirqs = b43_interrupt_disable(dev, B43_IRQ_ALL); + /* Periodic work will take a long time, so we want it to + * be preemtible and release the spinlock. */ + spin_unlock_irqrestore(&dev->wl->irq_lock, flags); + b43_synchronize_irq(dev); + + do_periodic_work(dev); + + spin_lock_irqsave(&dev->wl->irq_lock, flags); + b43_interrupt_enable(dev, savedirqs); + b43_tx_resume(dev); + mmiowb(); + spin_unlock_irqrestore(&dev->wl->irq_lock, flags); + } else { + /* Take the global driver lock. This will lock any operation. */ + spin_lock_irqsave(&dev->wl->irq_lock, flags); + + do_periodic_work(dev); + + mmiowb(); + spin_unlock_irqrestore(&dev->wl->irq_lock, flags); + } + dev->periodic_state++; + out_requeue: + if (b43_debug(dev, B43_DBG_PWORK_FAST)) + delay = msecs_to_jiffies(50); + else + delay = round_jiffies(HZ); + queue_delayed_work(dev->wl->hw->workqueue, &dev->periodic_work, delay); + out: + mutex_unlock(&dev->wl->mutex); +} + +static void b43_periodic_tasks_setup(struct b43_wldev *dev) +{ + struct delayed_work *work = &dev->periodic_work; + + dev->periodic_state = 0; + INIT_DELAYED_WORK(work, b43_periodic_work_handler); + queue_delayed_work(dev->wl->hw->workqueue, work, 0); +} + +/* Validate access to the chip (SHM) */ +static int b43_validate_chipaccess(struct b43_wldev *dev) +{ + u32 value; + u32 shm_backup; + + shm_backup = b43_shm_read32(dev, B43_SHM_SHARED, 0); + b43_shm_write32(dev, B43_SHM_SHARED, 0, 0xAA5555AA); + if (b43_shm_read32(dev, B43_SHM_SHARED, 0) != 0xAA5555AA) + goto error; + b43_shm_write32(dev, B43_SHM_SHARED, 0, 0x55AAAA55); + if (b43_shm_read32(dev, B43_SHM_SHARED, 0) != 0x55AAAA55) + goto error; + b43_shm_write32(dev, B43_SHM_SHARED, 0, shm_backup); + + value = b43_read32(dev, B43_MMIO_MACCTL); + if ((value | B43_MACCTL_GMODE) != + (B43_MACCTL_GMODE | B43_MACCTL_IHR_ENABLED)) + goto error; + + value = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON); + if (value) + goto error; + + return 0; + error: + b43err(dev->wl, "Failed to validate the chipaccess\n"); + return -ENODEV; +} + +static void b43_security_init(struct b43_wldev *dev) +{ + dev->max_nr_keys = (dev->dev->id.revision >= 5) ? 58 : 20; + B43_WARN_ON(dev->max_nr_keys > ARRAY_SIZE(dev->key)); + dev->ktp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_KTP); + /* KTP is a word address, but we address SHM bytewise. + * So multiply by two. + */ + dev->ktp *= 2; + if (dev->dev->id.revision >= 5) { + /* Number of RCMTA address slots */ + b43_write16(dev, B43_MMIO_RCMTA_COUNT, dev->max_nr_keys - 8); + } + b43_clear_keys(dev); +} + +static int b43_rng_read(struct hwrng *rng, u32 * data) +{ + struct b43_wl *wl = (struct b43_wl *)rng->priv; + unsigned long flags; + + /* Don't take wl->mutex here, as it could deadlock with + * hwrng internal locking. It's not needed to take + * wl->mutex here, anyway. */ + + spin_lock_irqsave(&wl->irq_lock, flags); + *data = b43_read16(wl->current_dev, B43_MMIO_RNG); + spin_unlock_irqrestore(&wl->irq_lock, flags); + + return (sizeof(u16)); +} + +static void b43_rng_exit(struct b43_wl *wl) +{ + if (wl->rng_initialized) + hwrng_unregister(&wl->rng); +} + +static int b43_rng_init(struct b43_wl *wl) +{ + int err; + + snprintf(wl->rng_name, ARRAY_SIZE(wl->rng_name), + "%s_%s", KBUILD_MODNAME, wiphy_name(wl->hw->wiphy)); + wl->rng.name = wl->rng_name; + wl->rng.data_read = b43_rng_read; + wl->rng.priv = (unsigned long)wl; + wl->rng_initialized = 1; + err = hwrng_register(&wl->rng); + if (err) { + wl->rng_initialized = 0; + b43err(wl, "Failed to register the random " + "number generator (%d)\n", err); + } + + return err; +} + +static int b43_tx(struct ieee80211_hw *hw, + struct sk_buff *skb, struct ieee80211_tx_control *ctl) +{ + struct b43_wl *wl = hw_to_b43_wl(hw); + struct b43_wldev *dev = wl->current_dev; + int err = -ENODEV; + unsigned long flags; + + if (unlikely(!dev)) + goto out; + if (unlikely(b43_status(dev) < B43_STAT_STARTED)) + goto out; + /* DMA-TX is done without a global lock. */ + if (b43_using_pio(dev)) { + spin_lock_irqsave(&wl->irq_lock, flags); + err = b43_pio_tx(dev, skb, ctl); + spin_unlock_irqrestore(&wl->irq_lock, flags); + } else + err = b43_dma_tx(dev, skb, ctl); + out: + if (unlikely(err)) + return NETDEV_TX_BUSY; + return NETDEV_TX_OK; +} + +static int b43_conf_tx(struct ieee80211_hw *hw, + int queue, + const struct ieee80211_tx_queue_params *params) +{ + return 0; +} + +static int b43_get_tx_stats(struct ieee80211_hw *hw, + struct ieee80211_tx_queue_stats *stats) +{ + struct b43_wl *wl = hw_to_b43_wl(hw); + struct b43_wldev *dev = wl->current_dev; + unsigned long flags; + int err = -ENODEV; + + if (!dev) + goto out; + spin_lock_irqsave(&wl->irq_lock, flags); + if (likely(b43_status(dev) >= B43_STAT_STARTED)) { + if (b43_using_pio(dev)) + b43_pio_get_tx_stats(dev, stats); + else + b43_dma_get_tx_stats(dev, stats); + err = 0; + } + spin_unlock_irqrestore(&wl->irq_lock, flags); + out: + return err; +} + +static int b43_get_stats(struct ieee80211_hw *hw, + struct ieee80211_low_level_stats *stats) +{ + struct b43_wl *wl = hw_to_b43_wl(hw); + unsigned long flags; + + spin_lock_irqsave(&wl->irq_lock, flags); + memcpy(stats, &wl->ieee_stats, sizeof(*stats)); + spin_unlock_irqrestore(&wl->irq_lock, flags); + + return 0; +} + +static const char *phymode_to_string(unsigned int phymode) +{ + switch (phymode) { + case B43_PHYMODE_A: + return "A"; + case B43_PHYMODE_B: + return "B"; + case B43_PHYMODE_G: + return "G"; + default: + B43_WARN_ON(1); + } + return ""; +} + +static int find_wldev_for_phymode(struct b43_wl *wl, + unsigned int phymode, + struct b43_wldev **dev, bool * gmode) +{ + struct b43_wldev *d; + + list_for_each_entry(d, &wl->devlist, list) { + if (d->phy.possible_phymodes & phymode) { + /* Ok, this device supports the PHY-mode. + * Now figure out how the gmode bit has to be + * set to support it. */ + if (phymode == B43_PHYMODE_A) + *gmode = 0; + else + *gmode = 1; + *dev = d; + + return 0; + } + } + + return -ESRCH; +} + +static void b43_put_phy_into_reset(struct b43_wldev *dev) +{ + struct ssb_device *sdev = dev->dev; + u32 tmslow; + + tmslow = ssb_read32(sdev, SSB_TMSLOW); + tmslow &= ~B43_TMSLOW_GMODE; + tmslow |= B43_TMSLOW_PHYRESET; + tmslow |= SSB_TMSLOW_FGC; + ssb_write32(sdev, SSB_TMSLOW, tmslow); + msleep(1); + + tmslow = ssb_read32(sdev, SSB_TMSLOW); + tmslow &= ~SSB_TMSLOW_FGC; + tmslow |= B43_TMSLOW_PHYRESET; + ssb_write32(sdev, SSB_TMSLOW, tmslow); + msleep(1); +} + +/* Expects wl->mutex locked */ +static int b43_switch_phymode(struct b43_wl *wl, unsigned int new_mode) +{ + struct b43_wldev *up_dev; + struct b43_wldev *down_dev; + int err; + bool gmode = 0; + int prev_status; + + err = find_wldev_for_phymode(wl, new_mode, &up_dev, &gmode); + if (err) { + b43err(wl, "Could not find a device for %s-PHY mode\n", + phymode_to_string(new_mode)); + return err; + } + if ((up_dev == wl->current_dev) && + (!!wl->current_dev->phy.gmode == !!gmode)) { + /* This device is already running. */ + return 0; + } + b43dbg(wl, "Reconfiguring PHYmode to %s-PHY\n", + phymode_to_string(new_mode)); + down_dev = wl->current_dev; + + prev_status = b43_status(down_dev); + /* Shutdown the currently running core. */ + if (prev_status >= B43_STAT_STARTED) + b43_wireless_core_stop(down_dev); + if (prev_status >= B43_STAT_INITIALIZED) + b43_wireless_core_exit(down_dev); + + if (down_dev != up_dev) { + /* We switch to a different core, so we put PHY into + * RESET on the old core. */ + b43_put_phy_into_reset(down_dev); + } + + /* Now start the new core. */ + up_dev->phy.gmode = gmode; + if (prev_status >= B43_STAT_INITIALIZED) { + err = b43_wireless_core_init(up_dev); + if (err) { + b43err(wl, "Fatal: Could not initialize device for " + "newly selected %s-PHY mode\n", + phymode_to_string(new_mode)); + goto init_failure; + } + } + if (prev_status >= B43_STAT_STARTED) { + err = b43_wireless_core_start(up_dev); + if (err) { + b43err(wl, "Fatal: Coult not start device for " + "newly selected %s-PHY mode\n", + phymode_to_string(new_mode)); + b43_wireless_core_exit(up_dev); + goto init_failure; + } + } + B43_WARN_ON(b43_status(up_dev) != prev_status); + + wl->current_dev = up_dev; + + return 0; + init_failure: + /* Whoops, failed to init the new core. No core is operating now. */ + wl->current_dev = NULL; + return err; +} + +static int b43_antenna_from_ieee80211(u8 antenna) +{ + switch (antenna) { + case 0: /* default/diversity */ + return B43_ANTENNA_DEFAULT; + case 1: /* Antenna 0 */ + return B43_ANTENNA0; + case 2: /* Antenna 1 */ + return B43_ANTENNA1; + default: + return B43_ANTENNA_DEFAULT; + } +} + +static int b43_dev_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) +{ + struct b43_wl *wl = hw_to_b43_wl(hw); + struct b43_wldev *dev; + struct b43_phy *phy; + unsigned long flags; + unsigned int new_phymode = 0xFFFF; + int antenna_tx; + int antenna_rx; + int err = 0; + u32 savedirqs; + + antenna_tx = b43_antenna_from_ieee80211(conf->antenna_sel_tx); + antenna_rx = b43_antenna_from_ieee80211(conf->antenna_sel_rx); + + mutex_lock(&wl->mutex); + + /* Switch the PHY mode (if necessary). */ + switch (conf->phymode) { + case MODE_IEEE80211A: + new_phymode = B43_PHYMODE_A; + break; + case MODE_IEEE80211B: + new_phymode = B43_PHYMODE_B; + break; + case MODE_IEEE80211G: + new_phymode = B43_PHYMODE_G; + break; + default: + B43_WARN_ON(1); + } + err = b43_switch_phymode(wl, new_phymode); + if (err) + goto out_unlock_mutex; + dev = wl->current_dev; + phy = &dev->phy; + + /* Disable IRQs while reconfiguring the device. + * This makes it possible to drop the spinlock throughout + * the reconfiguration process. */ + spin_lock_irqsave(&wl->irq_lock, flags); + if (b43_status(dev) < B43_STAT_STARTED) { + spin_unlock_irqrestore(&wl->irq_lock, flags); + goto out_unlock_mutex; + } + savedirqs = b43_interrupt_disable(dev, B43_IRQ_ALL); + spin_unlock_irqrestore(&wl->irq_lock, flags); + b43_synchronize_irq(dev); + + /* Switch to the requested channel. + * The firmware takes care of races with the TX handler. */ + if (conf->channel_val != phy->channel) + b43_radio_selectchannel(dev, conf->channel_val, 0); + + /* Enable/Disable ShortSlot timing. */ + if ((!!(conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)) != + dev->short_slot) { + B43_WARN_ON(phy->type != B43_PHYTYPE_G); + if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) + b43_short_slot_timing_enable(dev); + else + b43_short_slot_timing_disable(dev); + } + + /* Adjust the desired TX power level. */ + if (conf->power_level != 0) { + if (conf->power_level != phy->power_level) { + phy->power_level = conf->power_level; + b43_phy_xmitpower(dev); + } + } + + /* Antennas for RX and management frame TX. */ + b43_mgmtframe_txantenna(dev, antenna_tx); + b43_set_rx_antenna(dev, antenna_rx); + + /* Update templates for AP mode. */ + if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) + b43_set_beacon_int(dev, conf->beacon_int); + + spin_lock_irqsave(&wl->irq_lock, flags); + b43_interrupt_enable(dev, savedirqs); + mmiowb(); + spin_unlock_irqrestore(&wl->irq_lock, flags); + out_unlock_mutex: + mutex_unlock(&wl->mutex); + + return err; +} + +static int b43_dev_set_key(struct ieee80211_hw *hw, + set_key_cmd cmd, const u8 *local_addr, + const u8 *addr, struct ieee80211_key_conf *key) +{ + struct b43_wl *wl = hw_to_b43_wl(hw); + struct b43_wldev *dev = wl->current_dev; + unsigned long flags; + u8 algorithm; + u8 index; + int err = -EINVAL; + + if (modparam_nohwcrypt) + return -ENOSPC; /* User disabled HW-crypto */ + + if (!dev) + return -ENODEV; + switch (key->alg) { + case ALG_NONE: + algorithm = B43_SEC_ALGO_NONE; + break; + case ALG_WEP: + if (key->keylen == 5) + algorithm = B43_SEC_ALGO_WEP40; + else + algorithm = B43_SEC_ALGO_WEP104; + break; + case ALG_TKIP: + algorithm = B43_SEC_ALGO_TKIP; + break; + case ALG_CCMP: + algorithm = B43_SEC_ALGO_AES; + break; + default: + B43_WARN_ON(1); + goto out; + } + + index = (u8) (key->keyidx); + if (index > 3) + goto out; + + mutex_lock(&wl->mutex); + spin_lock_irqsave(&wl->irq_lock, flags); + + if (b43_status(dev) < B43_STAT_INITIALIZED) { + err = -ENODEV; + goto out_unlock; + } + + switch (cmd) { + case SET_KEY: + if (algorithm == B43_SEC_ALGO_TKIP) { + /* FIXME: No TKIP hardware encryption for now. */ + err = -EOPNOTSUPP; + goto out_unlock; + } + + if (is_broadcast_ether_addr(addr)) { + /* addr is FF:FF:FF:FF:FF:FF for default keys */ + err = b43_key_write(dev, index, algorithm, + key->key, key->keylen, NULL, key); + } else { + /* + * either pairwise key or address is 00:00:00:00:00:00 + * for transmit-only keys + */ + err = b43_key_write(dev, -1, algorithm, + key->key, key->keylen, addr, key); + } + if (err) + goto out_unlock; + + if (algorithm == B43_SEC_ALGO_WEP40 || + algorithm == B43_SEC_ALGO_WEP104) { + b43_hf_write(dev, b43_hf_read(dev) | B43_HF_USEDEFKEYS); + } else { + b43_hf_write(dev, + b43_hf_read(dev) & ~B43_HF_USEDEFKEYS); + } + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + break; + case DISABLE_KEY: { + err = b43_key_clear(dev, key->hw_key_idx); + if (err) + goto out_unlock; + break; + } + default: + B43_WARN_ON(1); + } +out_unlock: + spin_unlock_irqrestore(&wl->irq_lock, flags); + mutex_unlock(&wl->mutex); +out: + if (!err) { + b43dbg(wl, "%s hardware based encryption for keyidx: %d, " + "mac: " MAC_FMT "\n", + cmd == SET_KEY ? "Using" : "Disabling", key->keyidx, + MAC_ARG(addr)); + } + return err; +} + +static void b43_set_multicast_list(struct ieee80211_hw *hw, + unsigned short netflags, int mc_count) +{ + struct b43_wl *wl = hw_to_b43_wl(hw); + struct b43_wldev *dev = wl->current_dev; + unsigned long flags; + + if (!dev) + return; + spin_lock_irqsave(&wl->irq_lock, flags); + if (wl->promisc != !!(netflags & IFF_PROMISC)) { + wl->promisc = !!(netflags & IFF_PROMISC); + if (b43_status(dev) >= B43_STAT_INITIALIZED) + b43_adjust_opmode(dev); + } + spin_unlock_irqrestore(&wl->irq_lock, flags); +} + +static int b43_config_interface(struct ieee80211_hw *hw, + int if_id, struct ieee80211_if_conf *conf) +{ + struct b43_wl *wl = hw_to_b43_wl(hw); + struct b43_wldev *dev = wl->current_dev; + unsigned long flags; + + if (!dev) + return -ENODEV; + mutex_lock(&wl->mutex); + spin_lock_irqsave(&wl->irq_lock, flags); + if (conf->type != IEEE80211_IF_TYPE_MNTR) { + B43_WARN_ON(wl->if_id != if_id); + if (conf->bssid) + memcpy(wl->bssid, conf->bssid, ETH_ALEN); + else + memset(wl->bssid, 0, ETH_ALEN); + if (b43_status(dev) >= B43_STAT_INITIALIZED) { + if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) { + B43_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP); + b43_set_ssid(dev, conf->ssid, conf->ssid_len); + if (conf->beacon) + b43_refresh_templates(dev, conf->beacon); + } + b43_write_mac_bssid_templates(dev); + } + } + spin_unlock_irqrestore(&wl->irq_lock, flags); + mutex_unlock(&wl->mutex); + + return 0; +} + +/* Locking: wl->mutex */ +static void b43_wireless_core_stop(struct b43_wldev *dev) +{ + struct b43_wl *wl = dev->wl; + unsigned long flags; + + if (b43_status(dev) < B43_STAT_STARTED) + return; + b43_set_status(dev, B43_STAT_INITIALIZED); + + mutex_unlock(&wl->mutex); + /* Must unlock as it would otherwise deadlock. No races here. + * Cancel the possibly running self-rearming periodic work. */ + cancel_delayed_work_sync(&dev->periodic_work); + mutex_lock(&wl->mutex); + + ieee80211_stop_queues(wl->hw); //FIXME this could cause a deadlock, as mac80211 seems buggy. + + /* Disable and sync interrupts. */ + spin_lock_irqsave(&wl->irq_lock, flags); + dev->irq_savedstate = b43_interrupt_disable(dev, B43_IRQ_ALL); + b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* flush */ + spin_unlock_irqrestore(&wl->irq_lock, flags); + b43_synchronize_irq(dev); + + b43_mac_suspend(dev); + free_irq(dev->dev->irq, dev); + b43dbg(wl, "Wireless interface stopped\n"); +} + +/* Locking: wl->mutex */ +static int b43_wireless_core_start(struct b43_wldev *dev) +{ + int err; + + B43_WARN_ON(b43_status(dev) != B43_STAT_INITIALIZED); + + drain_txstatus_queue(dev); + err = request_irq(dev->dev->irq, b43_interrupt_handler, + IRQF_SHARED, KBUILD_MODNAME, dev); + if (err) { + b43err(dev->wl, "Cannot request IRQ-%d\n", dev->dev->irq); + goto out; + } + + /* We are ready to run. */ + b43_set_status(dev, B43_STAT_STARTED); + + /* Start data flow (TX/RX). */ + b43_mac_enable(dev); + b43_interrupt_enable(dev, dev->irq_savedstate); + ieee80211_start_queues(dev->wl->hw); + + /* Start maintainance work */ + b43_periodic_tasks_setup(dev); + + b43dbg(dev->wl, "Wireless interface started\n"); + out: + return err; +} + +/* Get PHY and RADIO versioning numbers */ +static int b43_phy_versioning(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + u32 tmp; + u8 analog_type; + u8 phy_type; + u8 phy_rev; + u16 radio_manuf; + u16 radio_ver; + u16 radio_rev; + int unsupported = 0; + + /* Get PHY versioning */ + tmp = b43_read16(dev, B43_MMIO_PHY_VER); + analog_type = (tmp & B43_PHYVER_ANALOG) >> B43_PHYVER_ANALOG_SHIFT; + phy_type = (tmp & B43_PHYVER_TYPE) >> B43_PHYVER_TYPE_SHIFT; + phy_rev = (tmp & B43_PHYVER_VERSION); + switch (phy_type) { + case B43_PHYTYPE_A: + if (phy_rev >= 4) + unsupported = 1; + break; + case B43_PHYTYPE_B: + if (phy_rev != 2 && phy_rev != 4 && phy_rev != 6 + && phy_rev != 7) + unsupported = 1; + break; + case B43_PHYTYPE_G: + if (phy_rev > 8) + unsupported = 1; + break; + default: + unsupported = 1; + }; + if (unsupported) { + b43err(dev->wl, "FOUND UNSUPPORTED PHY " + "(Analog %u, Type %u, Revision %u)\n", + analog_type, phy_type, phy_rev); + return -EOPNOTSUPP; + } + b43dbg(dev->wl, "Found PHY: Analog %u, Type %u, Revision %u\n", + analog_type, phy_type, phy_rev); + + /* Get RADIO versioning */ + if (dev->dev->bus->chip_id == 0x4317) { + if (dev->dev->bus->chip_rev == 0) + tmp = 0x3205017F; + else if (dev->dev->bus->chip_rev == 1) + tmp = 0x4205017F; + else + tmp = 0x5205017F; + } else { + b43_write16(dev, B43_MMIO_RADIO_CONTROL, B43_RADIOCTL_ID); + tmp = b43_read16(dev, B43_MMIO_RADIO_DATA_HIGH); + tmp <<= 16; + b43_write16(dev, B43_MMIO_RADIO_CONTROL, B43_RADIOCTL_ID); + tmp |= b43_read16(dev, B43_MMIO_RADIO_DATA_LOW); + } + radio_manuf = (tmp & 0x00000FFF); + radio_ver = (tmp & 0x0FFFF000) >> 12; + radio_rev = (tmp & 0xF0000000) >> 28; + switch (phy_type) { + case B43_PHYTYPE_A: + if (radio_ver != 0x2060) + unsupported = 1; + if (radio_rev != 1) + unsupported = 1; + if (radio_manuf != 0x17F) + unsupported = 1; + break; + case B43_PHYTYPE_B: + if ((radio_ver & 0xFFF0) != 0x2050) + unsupported = 1; + break; + case B43_PHYTYPE_G: + if (radio_ver != 0x2050) + unsupported = 1; + break; + default: + B43_WARN_ON(1); + } + if (unsupported) { + b43err(dev->wl, "FOUND UNSUPPORTED RADIO " + "(Manuf 0x%X, Version 0x%X, Revision %u)\n", + radio_manuf, radio_ver, radio_rev); + return -EOPNOTSUPP; + } + b43dbg(dev->wl, "Found Radio: Manuf 0x%X, Version 0x%X, Revision %u\n", + radio_manuf, radio_ver, radio_rev); + + phy->radio_manuf = radio_manuf; + phy->radio_ver = radio_ver; + phy->radio_rev = radio_rev; + + phy->analog = analog_type; + phy->type = phy_type; + phy->rev = phy_rev; + + return 0; +} + +static void setup_struct_phy_for_init(struct b43_wldev *dev, + struct b43_phy *phy) +{ + struct b43_txpower_lo_control *lo; + int i; + + memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig)); + memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos)); + + /* Flags */ + phy->locked = 0; + + phy->aci_enable = 0; + phy->aci_wlan_automatic = 0; + phy->aci_hw_rssi = 0; + + lo = phy->lo_control; + if (lo) { + memset(lo, 0, sizeof(*(phy->lo_control))); + lo->rebuild = 1; + lo->tx_bias = 0xFF; + } + phy->max_lb_gain = 0; + phy->trsw_rx_gain = 0; + phy->txpwr_offset = 0; + + /* NRSSI */ + phy->nrssislope = 0; + for (i = 0; i < ARRAY_SIZE(phy->nrssi); i++) + phy->nrssi[i] = -1000; + for (i = 0; i < ARRAY_SIZE(phy->nrssi_lt); i++) + phy->nrssi_lt[i] = i; + + phy->lofcal = 0xFFFF; + phy->initval = 0xFFFF; + + spin_lock_init(&phy->lock); + phy->interfmode = B43_INTERFMODE_NONE; + phy->channel = 0xFF; + + phy->hardware_power_control = !!modparam_hwpctl; +} + +static void setup_struct_wldev_for_init(struct b43_wldev *dev) +{ + /* Flags */ + dev->reg124_set_0x4 = 0; + + /* Stats */ + memset(&dev->stats, 0, sizeof(dev->stats)); + + setup_struct_phy_for_init(dev, &dev->phy); + + /* IRQ related flags */ + dev->irq_reason = 0; + memset(dev->dma_reason, 0, sizeof(dev->dma_reason)); + dev->irq_savedstate = B43_IRQ_MASKTEMPLATE; + + dev->mac_suspended = 1; + + /* Noise calculation context */ + memset(&dev->noisecalc, 0, sizeof(dev->noisecalc)); +} + +static void b43_bluetooth_coext_enable(struct b43_wldev *dev) +{ + struct ssb_sprom *sprom = &dev->dev->bus->sprom; + u32 hf; + + if (!(sprom->r1.boardflags_lo & B43_BFL_BTCOEXIST)) + return; + if (dev->phy.type != B43_PHYTYPE_B && !dev->phy.gmode) + return; + + hf = b43_hf_read(dev); + if (sprom->r1.boardflags_lo & B43_BFL_BTCMOD) + hf |= B43_HF_BTCOEXALT; + else + hf |= B43_HF_BTCOEX; + b43_hf_write(dev, hf); + //TODO +} + +static void b43_bluetooth_coext_disable(struct b43_wldev *dev) +{ //TODO +} + +static void b43_imcfglo_timeouts_workaround(struct b43_wldev *dev) +{ +#ifdef CONFIG_SSB_DRIVER_PCICORE + struct ssb_bus *bus = dev->dev->bus; + u32 tmp; + + if (bus->pcicore.dev && + bus->pcicore.dev->id.coreid == SSB_DEV_PCI && + bus->pcicore.dev->id.revision <= 5) { + /* IMCFGLO timeouts workaround. */ + tmp = ssb_read32(dev->dev, SSB_IMCFGLO); + tmp &= ~SSB_IMCFGLO_REQTO; + tmp &= ~SSB_IMCFGLO_SERTO; + switch (bus->bustype) { + case SSB_BUSTYPE_PCI: + case SSB_BUSTYPE_PCMCIA: + tmp |= 0x32; + break; + case SSB_BUSTYPE_SSB: + tmp |= 0x53; + break; + } + ssb_write32(dev->dev, SSB_IMCFGLO, tmp); + } +#endif /* CONFIG_SSB_DRIVER_PCICORE */ +} + +/* Shutdown a wireless core */ +/* Locking: wl->mutex */ +static void b43_wireless_core_exit(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + + B43_WARN_ON(b43_status(dev) > B43_STAT_INITIALIZED); + if (b43_status(dev) != B43_STAT_INITIALIZED) + return; + b43_set_status(dev, B43_STAT_UNINIT); + + b43_rng_exit(dev->wl); + b43_pio_free(dev); + b43_dma_free(dev); + b43_chip_exit(dev); + b43_radio_turn_off(dev); + b43_switch_analog(dev, 0); + if (phy->dyn_tssi_tbl) + kfree(phy->tssi2dbm); + kfree(phy->lo_control); + phy->lo_control = NULL; + ssb_device_disable(dev->dev, 0); + ssb_bus_may_powerdown(dev->dev->bus); +} + +/* Initialize a wireless core */ +static int b43_wireless_core_init(struct b43_wldev *dev) +{ + struct b43_wl *wl = dev->wl; + struct ssb_bus *bus = dev->dev->bus; + struct ssb_sprom *sprom = &bus->sprom; + struct b43_phy *phy = &dev->phy; + int err; + u32 hf, tmp; + + B43_WARN_ON(b43_status(dev) != B43_STAT_UNINIT); + + err = ssb_bus_powerup(bus, 0); + if (err) + goto out; + if (!ssb_device_is_enabled(dev->dev)) { + tmp = phy->gmode ? B43_TMSLOW_GMODE : 0; + b43_wireless_core_reset(dev, tmp); + } + + if ((phy->type == B43_PHYTYPE_B) || (phy->type == B43_PHYTYPE_G)) { + phy->lo_control = + kzalloc(sizeof(*(phy->lo_control)), GFP_KERNEL); + if (!phy->lo_control) { + err = -ENOMEM; + goto err_busdown; + } + } + setup_struct_wldev_for_init(dev); + + err = b43_phy_init_tssi2dbm_table(dev); + if (err) + goto err_kfree_lo_control; + + /* Enable IRQ routing to this device. */ + ssb_pcicore_dev_irqvecs_enable(&bus->pcicore, dev->dev); + + b43_imcfglo_timeouts_workaround(dev); + b43_bluetooth_coext_disable(dev); + b43_phy_early_init(dev); + err = b43_chip_init(dev); + if (err) + goto err_kfree_tssitbl; + b43_shm_write16(dev, B43_SHM_SHARED, + B43_SHM_SH_WLCOREREV, dev->dev->id.revision); + hf = b43_hf_read(dev); + if (phy->type == B43_PHYTYPE_G) { + hf |= B43_HF_SYMW; + if (phy->rev == 1) + hf |= B43_HF_GDCW; + if (sprom->r1.boardflags_lo & B43_BFL_PACTRL) + hf |= B43_HF_OFDMPABOOST; + } else if (phy->type == B43_PHYTYPE_B) { + hf |= B43_HF_SYMW; + if (phy->rev >= 2 && phy->radio_ver == 0x2050) + hf &= ~B43_HF_GDCW; + } + b43_hf_write(dev, hf); + + /* Short/Long Retry Limit. + * The retry-limit is a 4-bit counter. Enforce this to avoid overflowing + * the chip-internal counter. + */ + tmp = limit_value(modparam_short_retry, 0, 0xF); + b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_SRLIMIT, tmp); + tmp = limit_value(modparam_long_retry, 0, 0xF); + b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_LRLIMIT, tmp); + + b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_SFFBLIM, 3); + b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_LFFBLIM, 2); + + /* Disable sending probe responses from firmware. + * Setting the MaxTime to one usec will always trigger + * a timeout, so we never send any probe resp. + * A timeout of zero is infinite. */ + b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRMAXTIME, 1); + + b43_rate_memory_init(dev); + + /* Minimum Contention Window */ + if (phy->type == B43_PHYTYPE_B) { + b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MINCONT, 0x1F); + } else { + b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MINCONT, 0xF); + } + /* Maximum Contention Window */ + b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MAXCONT, 0x3FF); + + do { + if (b43_using_pio(dev)) { + err = b43_pio_init(dev); + } else { + err = b43_dma_init(dev); + if (!err) + b43_qos_init(dev); + } + } while (err == -EAGAIN); + if (err) + goto err_chip_exit; + +//FIXME +#if 1 + b43_write16(dev, 0x0612, 0x0050); + b43_shm_write16(dev, B43_SHM_SHARED, 0x0416, 0x0050); + b43_shm_write16(dev, B43_SHM_SHARED, 0x0414, 0x01F4); +#endif + + b43_bluetooth_coext_enable(dev); + + ssb_bus_powerup(bus, 1); /* Enable dynamic PCTL */ + memset(wl->bssid, 0, ETH_ALEN); + b43_upload_card_macaddress(dev, NULL); + b43_security_init(dev); + b43_rng_init(wl); + + b43_set_status(dev, B43_STAT_INITIALIZED); + + out: + return err; + + err_chip_exit: + b43_chip_exit(dev); + err_kfree_tssitbl: + if (phy->dyn_tssi_tbl) + kfree(phy->tssi2dbm); + err_kfree_lo_control: + kfree(phy->lo_control); + phy->lo_control = NULL; + err_busdown: + ssb_bus_may_powerdown(bus); + B43_WARN_ON(b43_status(dev) != B43_STAT_UNINIT); + return err; +} + +static int b43_add_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct b43_wl *wl = hw_to_b43_wl(hw); + struct b43_wldev *dev; + unsigned long flags; + int err = -EOPNOTSUPP; + int did_init = 0; + + mutex_lock(&wl->mutex); + if ((conf->type != IEEE80211_IF_TYPE_MNTR) && wl->operating) + goto out_mutex_unlock; + + b43dbg(wl, "Adding Interface type %d\n", conf->type); + + dev = wl->current_dev; + if (b43_status(dev) < B43_STAT_INITIALIZED) { + err = b43_wireless_core_init(dev); + if (err) + goto out_mutex_unlock; + did_init = 1; + } + if (b43_status(dev) < B43_STAT_STARTED) { + err = b43_wireless_core_start(dev); + if (err) { + if (did_init) + b43_wireless_core_exit(dev); + goto out_mutex_unlock; + } + } + + spin_lock_irqsave(&wl->irq_lock, flags); + switch (conf->type) { + case IEEE80211_IF_TYPE_MNTR: + wl->monitor++; + break; + default: + wl->operating = 1; + wl->if_id = conf->if_id; + wl->if_type = conf->type; + b43_upload_card_macaddress(dev, conf->mac_addr); + } + b43_adjust_opmode(dev); + spin_unlock_irqrestore(&wl->irq_lock, flags); + + err = 0; + out_mutex_unlock: + mutex_unlock(&wl->mutex); + + return err; +} + +static void b43_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct b43_wl *wl = hw_to_b43_wl(hw); + struct b43_wldev *dev; + unsigned long flags; + + b43dbg(wl, "Removing Interface type %d\n", conf->type); + + mutex_lock(&wl->mutex); + if (conf->type == IEEE80211_IF_TYPE_MNTR) { + wl->monitor--; + B43_WARN_ON(wl->monitor < 0); + } else { + B43_WARN_ON(!wl->operating); + wl->operating = 0; + } + + dev = wl->current_dev; + if (!wl->operating && wl->monitor == 0) { + /* No interface left. */ + if (b43_status(dev) >= B43_STAT_STARTED) + b43_wireless_core_stop(dev); + b43_wireless_core_exit(dev); + } else { + /* Just monitor interfaces left. */ + spin_lock_irqsave(&wl->irq_lock, flags); + b43_adjust_opmode(dev); + if (!wl->operating) + b43_upload_card_macaddress(dev, NULL); + spin_unlock_irqrestore(&wl->irq_lock, flags); + } + mutex_unlock(&wl->mutex); +} + +static const struct ieee80211_ops b43_hw_ops = { + .tx = b43_tx, + .conf_tx = b43_conf_tx, + .add_interface = b43_add_interface, + .remove_interface = b43_remove_interface, + .config = b43_dev_config, + .config_interface = b43_config_interface, + .set_multicast_list = b43_set_multicast_list, + .set_key = b43_dev_set_key, + .get_stats = b43_get_stats, + .get_tx_stats = b43_get_tx_stats, +}; + +/* Hard-reset the chip. Do not call this directly. + * Use b43_controller_restart() + */ +static void b43_chip_reset(struct work_struct *work) +{ + struct b43_wldev *dev = + container_of(work, struct b43_wldev, restart_work); + struct b43_wl *wl = dev->wl; + int err = 0; + int prev_status; + + mutex_lock(&wl->mutex); + + prev_status = b43_status(dev); + /* Bring the device down... */ + if (prev_status >= B43_STAT_STARTED) + b43_wireless_core_stop(dev); + if (prev_status >= B43_STAT_INITIALIZED) + b43_wireless_core_exit(dev); + + /* ...and up again. */ + if (prev_status >= B43_STAT_INITIALIZED) { + err = b43_wireless_core_init(dev); + if (err) + goto out; + } + if (prev_status >= B43_STAT_STARTED) { + err = b43_wireless_core_start(dev); + if (err) { + b43_wireless_core_exit(dev); + goto out; + } + } + out: + mutex_unlock(&wl->mutex); + if (err) + b43err(wl, "Controller restart FAILED\n"); + else + b43info(wl, "Controller restarted\n"); +} + +static int b43_setup_modes(struct b43_wldev *dev, + int have_aphy, int have_bphy, int have_gphy) +{ + struct ieee80211_hw *hw = dev->wl->hw; + struct ieee80211_hw_mode *mode; + struct b43_phy *phy = &dev->phy; + int cnt = 0; + int err; + +/*FIXME: Don't tell ieee80211 about an A-PHY, because we currently don't support A-PHY. */ + have_aphy = 0; + + phy->possible_phymodes = 0; + for (; 1; cnt++) { + if (have_aphy) { + B43_WARN_ON(cnt >= B43_MAX_PHYHWMODES); + mode = &phy->hwmodes[cnt]; + + mode->mode = MODE_IEEE80211A; + mode->num_channels = b43_a_chantable_size; + mode->channels = b43_a_chantable; + mode->num_rates = b43_a_ratetable_size; + mode->rates = b43_a_ratetable; + err = ieee80211_register_hwmode(hw, mode); + if (err) + return err; + + phy->possible_phymodes |= B43_PHYMODE_A; + have_aphy = 0; + continue; + } + if (have_bphy) { + B43_WARN_ON(cnt >= B43_MAX_PHYHWMODES); + mode = &phy->hwmodes[cnt]; + + mode->mode = MODE_IEEE80211B; + mode->num_channels = b43_bg_chantable_size; + mode->channels = b43_bg_chantable; + mode->num_rates = b43_b_ratetable_size; + mode->rates = b43_b_ratetable; + err = ieee80211_register_hwmode(hw, mode); + if (err) + return err; + + phy->possible_phymodes |= B43_PHYMODE_B; + have_bphy = 0; + continue; + } + if (have_gphy) { + B43_WARN_ON(cnt >= B43_MAX_PHYHWMODES); + mode = &phy->hwmodes[cnt]; + + mode->mode = MODE_IEEE80211G; + mode->num_channels = b43_bg_chantable_size; + mode->channels = b43_bg_chantable; + mode->num_rates = b43_g_ratetable_size; + mode->rates = b43_g_ratetable; + err = ieee80211_register_hwmode(hw, mode); + if (err) + return err; + + phy->possible_phymodes |= B43_PHYMODE_G; + have_gphy = 0; + continue; + } + break; + } + + return 0; +} + +static void b43_wireless_core_detach(struct b43_wldev *dev) +{ + /* We release firmware that late to not be required to re-request + * is all the time when we reinit the core. */ + b43_release_firmware(dev); +} + +static int b43_wireless_core_attach(struct b43_wldev *dev) +{ + struct b43_wl *wl = dev->wl; + struct ssb_bus *bus = dev->dev->bus; + struct pci_dev *pdev = bus->host_pci; + int err; + int have_aphy = 0, have_bphy = 0, have_gphy = 0; + u32 tmp; + + /* Do NOT do any device initialization here. + * Do it in wireless_core_init() instead. + * This function is for gathering basic information about the HW, only. + * Also some structs may be set up here. But most likely you want to have + * that in core_init(), too. + */ + + err = ssb_bus_powerup(bus, 0); + if (err) { + b43err(wl, "Bus powerup failed\n"); + goto out; + } + /* Get the PHY type. */ + if (dev->dev->id.revision >= 5) { + u32 tmshigh; + + tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH); + have_aphy = !!(tmshigh & B43_TMSHIGH_APHY); + have_gphy = !!(tmshigh & B43_TMSHIGH_GPHY); + if (!have_aphy && !have_gphy) + have_bphy = 1; + } else if (dev->dev->id.revision == 4) { + have_gphy = 1; + have_aphy = 1; + } else + have_bphy = 1; + + /* Initialize LEDs structs. */ + err = b43_leds_init(dev); + if (err) + goto err_powerdown; + + dev->phy.gmode = (have_gphy || have_bphy); + tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0; + b43_wireless_core_reset(dev, tmp); + + err = b43_phy_versioning(dev); + if (err) + goto err_leds_exit; + /* Check if this device supports multiband. */ + if (!pdev || + (pdev->device != 0x4312 && + pdev->device != 0x4319 && pdev->device != 0x4324)) { + /* No multiband support. */ + have_aphy = 0; + have_bphy = 0; + have_gphy = 0; + switch (dev->phy.type) { + case B43_PHYTYPE_A: + have_aphy = 1; + break; + case B43_PHYTYPE_B: + have_bphy = 1; + break; + case B43_PHYTYPE_G: + have_gphy = 1; + break; + default: + B43_WARN_ON(1); + } + } + dev->phy.gmode = (have_gphy || have_bphy); + tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0; + b43_wireless_core_reset(dev, tmp); + + err = b43_validate_chipaccess(dev); + if (err) + goto err_leds_exit; + err = b43_setup_modes(dev, have_aphy, have_bphy, have_gphy); + if (err) + goto err_leds_exit; + + /* Now set some default "current_dev" */ + if (!wl->current_dev) + wl->current_dev = dev; + INIT_WORK(&dev->restart_work, b43_chip_reset); + + b43_radio_turn_off(dev); + b43_switch_analog(dev, 0); + ssb_device_disable(dev->dev, 0); + ssb_bus_may_powerdown(bus); + +out: + return err; + +err_leds_exit: + b43_leds_exit(dev); +err_powerdown: + ssb_bus_may_powerdown(bus); + return err; +} + +static void b43_one_core_detach(struct ssb_device *dev) +{ + struct b43_wldev *wldev; + struct b43_wl *wl; + + wldev = ssb_get_drvdata(dev); + wl = wldev->wl; + cancel_work_sync(&wldev->restart_work); + b43_debugfs_remove_device(wldev); + b43_wireless_core_detach(wldev); + list_del(&wldev->list); + wl->nr_devs--; + ssb_set_drvdata(dev, NULL); + kfree(wldev); +} + +static int b43_one_core_attach(struct ssb_device *dev, struct b43_wl *wl) +{ + struct b43_wldev *wldev; + struct pci_dev *pdev; + int err = -ENOMEM; + + if (!list_empty(&wl->devlist)) { + /* We are not the first core on this chip. */ + pdev = dev->bus->host_pci; + /* Only special chips support more than one wireless + * core, although some of the other chips have more than + * one wireless core as well. Check for this and + * bail out early. + */ + if (!pdev || + ((pdev->device != 0x4321) && + (pdev->device != 0x4313) && (pdev->device != 0x431A))) { + b43dbg(wl, "Ignoring unconnected 802.11 core\n"); + return -ENODEV; + } + } + + wldev = kzalloc(sizeof(*wldev), GFP_KERNEL); + if (!wldev) + goto out; + + wldev->dev = dev; + wldev->wl = wl; + b43_set_status(wldev, B43_STAT_UNINIT); + wldev->bad_frames_preempt = modparam_bad_frames_preempt; + tasklet_init(&wldev->isr_tasklet, + (void (*)(unsigned long))b43_interrupt_tasklet, + (unsigned long)wldev); + if (modparam_pio) + wldev->__using_pio = 1; + INIT_LIST_HEAD(&wldev->list); + + err = b43_wireless_core_attach(wldev); + if (err) + goto err_kfree_wldev; + + list_add(&wldev->list, &wl->devlist); + wl->nr_devs++; + ssb_set_drvdata(dev, wldev); + b43_debugfs_add_device(wldev); + + out: + return err; + + err_kfree_wldev: + kfree(wldev); + return err; +} + +static void b43_sprom_fixup(struct ssb_bus *bus) +{ + /* boardflags workarounds */ + if (bus->boardinfo.vendor == SSB_BOARDVENDOR_DELL && + bus->chip_id == 0x4301 && bus->boardinfo.rev == 0x74) + bus->sprom.r1.boardflags_lo |= B43_BFL_BTCOEXIST; + if (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE && + bus->boardinfo.type == 0x4E && bus->boardinfo.rev > 0x40) + bus->sprom.r1.boardflags_lo |= B43_BFL_PACTRL; + + /* Handle case when gain is not set in sprom */ + if (bus->sprom.r1.antenna_gain_a == 0xFF) + bus->sprom.r1.antenna_gain_a = 2; + if (bus->sprom.r1.antenna_gain_bg == 0xFF) + bus->sprom.r1.antenna_gain_bg = 2; + + /* Convert Antennagain values to Q5.2 */ + bus->sprom.r1.antenna_gain_a <<= 2; + bus->sprom.r1.antenna_gain_bg <<= 2; +} + +static void b43_wireless_exit(struct ssb_device *dev, struct b43_wl *wl) +{ + struct ieee80211_hw *hw = wl->hw; + + ssb_set_devtypedata(dev, NULL); + ieee80211_free_hw(hw); +} + +static int b43_wireless_init(struct ssb_device *dev) +{ + struct ssb_sprom *sprom = &dev->bus->sprom; + struct ieee80211_hw *hw; + struct b43_wl *wl; + int err = -ENOMEM; + + b43_sprom_fixup(dev->bus); + + hw = ieee80211_alloc_hw(sizeof(*wl), &b43_hw_ops); + if (!hw) { + b43err(NULL, "Could not allocate ieee80211 device\n"); + goto out; + } + + /* fill hw info */ + hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | + IEEE80211_HW_MONITOR_DURING_OPER; + hw->max_signal = 100; + hw->max_rssi = -110; + hw->max_noise = -110; + hw->queues = 1; /* FIXME: hardware has more queues */ + SET_IEEE80211_DEV(hw, dev->dev); + if (is_valid_ether_addr(sprom->r1.et1mac)) + SET_IEEE80211_PERM_ADDR(hw, sprom->r1.et1mac); + else + SET_IEEE80211_PERM_ADDR(hw, sprom->r1.il0mac); + + /* Get and initialize struct b43_wl */ + wl = hw_to_b43_wl(hw); + memset(wl, 0, sizeof(*wl)); + wl->hw = hw; + spin_lock_init(&wl->irq_lock); + spin_lock_init(&wl->leds_lock); + mutex_init(&wl->mutex); + INIT_LIST_HEAD(&wl->devlist); + + ssb_set_devtypedata(dev, wl); + b43info(wl, "Broadcom %04X WLAN found\n", dev->bus->chip_id); + err = 0; + out: + return err; +} + +static int b43_probe(struct ssb_device *dev, const struct ssb_device_id *id) +{ + struct b43_wl *wl; + int err; + int first = 0; + + wl = ssb_get_devtypedata(dev); + if (!wl) { + /* Probing the first core. Must setup common struct b43_wl */ + first = 1; + err = b43_wireless_init(dev); + if (err) + goto out; + wl = ssb_get_devtypedata(dev); + B43_WARN_ON(!wl); + } + err = b43_one_core_attach(dev, wl); + if (err) + goto err_wireless_exit; + + if (first) { + err = ieee80211_register_hw(wl->hw); + if (err) + goto err_one_core_detach; + } + + out: + return err; + + err_one_core_detach: + b43_one_core_detach(dev); + err_wireless_exit: + if (first) + b43_wireless_exit(dev, wl); + return err; +} + +static void b43_remove(struct ssb_device *dev) +{ + struct b43_wl *wl = ssb_get_devtypedata(dev); + struct b43_wldev *wldev = ssb_get_drvdata(dev); + + B43_WARN_ON(!wl); + if (wl->current_dev == wldev) + ieee80211_unregister_hw(wl->hw); + + b43_one_core_detach(dev); + + if (list_empty(&wl->devlist)) { + /* Last core on the chip unregistered. + * We can destroy common struct b43_wl. + */ + b43_wireless_exit(dev, wl); + } +} + +/* Perform a hardware reset. This can be called from any context. */ +void b43_controller_restart(struct b43_wldev *dev, const char *reason) +{ + /* Must avoid requeueing, if we are in shutdown. */ + if (b43_status(dev) < B43_STAT_INITIALIZED) + return; + b43info(dev->wl, "Controller RESET (%s) ...\n", reason); + queue_work(dev->wl->hw->workqueue, &dev->restart_work); +} + +#ifdef CONFIG_PM + +static int b43_suspend(struct ssb_device *dev, pm_message_t state) +{ + struct b43_wldev *wldev = ssb_get_drvdata(dev); + struct b43_wl *wl = wldev->wl; + + b43dbg(wl, "Suspending...\n"); + + mutex_lock(&wl->mutex); + wldev->suspend_init_status = b43_status(wldev); + if (wldev->suspend_init_status >= B43_STAT_STARTED) + b43_wireless_core_stop(wldev); + if (wldev->suspend_init_status >= B43_STAT_INITIALIZED) + b43_wireless_core_exit(wldev); + mutex_unlock(&wl->mutex); + + b43dbg(wl, "Device suspended.\n"); + + return 0; +} + +static int b43_resume(struct ssb_device *dev) +{ + struct b43_wldev *wldev = ssb_get_drvdata(dev); + struct b43_wl *wl = wldev->wl; + int err = 0; + + b43dbg(wl, "Resuming...\n"); + + mutex_lock(&wl->mutex); + if (wldev->suspend_init_status >= B43_STAT_INITIALIZED) { + err = b43_wireless_core_init(wldev); + if (err) { + b43err(wl, "Resume failed at core init\n"); + goto out; + } + } + if (wldev->suspend_init_status >= B43_STAT_STARTED) { + err = b43_wireless_core_start(wldev); + if (err) { + b43_wireless_core_exit(wldev); + b43err(wl, "Resume failed at core start\n"); + goto out; + } + } + mutex_unlock(&wl->mutex); + + b43dbg(wl, "Device resumed.\n"); + out: + return err; +} + +#else /* CONFIG_PM */ +# define b43_suspend NULL +# define b43_resume NULL +#endif /* CONFIG_PM */ + +static struct ssb_driver b43_ssb_driver = { + .name = KBUILD_MODNAME, + .id_table = b43_ssb_tbl, + .probe = b43_probe, + .remove = b43_remove, + .suspend = b43_suspend, + .resume = b43_resume, +}; + +static int __init b43_init(void) +{ + int err; + + b43_debugfs_init(); + err = b43_pcmcia_init(); + if (err) + goto err_dfs_exit; + err = ssb_driver_register(&b43_ssb_driver); + if (err) + goto err_pcmcia_exit; + + return err; + +err_pcmcia_exit: + b43_pcmcia_exit(); +err_dfs_exit: + b43_debugfs_exit(); + return err; +} + +static void __exit b43_exit(void) +{ + ssb_driver_unregister(&b43_ssb_driver); + b43_pcmcia_exit(); + b43_debugfs_exit(); +} + +module_init(b43_init) +module_exit(b43_exit) diff --git a/drivers/net/wireless/b43/main.h b/drivers/net/wireless/b43/main.h new file mode 100644 index 00000000000..bd8fcf72dc5 --- /dev/null +++ b/drivers/net/wireless/b43/main.h @@ -0,0 +1,142 @@ +/* + + Broadcom B43 wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + + Some parts of the code in this file are derived from the ipw2200 + driver Copyright(c) 2003 - 2004 Intel Corporation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#ifndef B43_MAIN_H_ +#define B43_MAIN_H_ + +#include "b43.h" + +#define P4D_BYT3S(magic, nr_bytes) u8 __p4dding##magic[nr_bytes] +#define P4D_BYTES(line, nr_bytes) P4D_BYT3S(line, nr_bytes) +/* Magic helper macro to pad structures. Ignore those above. It's magic. */ +#define PAD_BYTES(nr_bytes) P4D_BYTES( __LINE__ , (nr_bytes)) + +/* Lightweight function to convert a frequency (in Mhz) to a channel number. */ +static inline u8 b43_freq_to_channel_a(int freq) +{ + return ((freq - 5000) / 5); +} +static inline u8 b43_freq_to_channel_bg(int freq) +{ + u8 channel; + + if (freq == 2484) + channel = 14; + else + channel = (freq - 2407) / 5; + + return channel; +} +static inline u8 b43_freq_to_channel(struct b43_wldev *dev, int freq) +{ + if (dev->phy.type == B43_PHYTYPE_A) + return b43_freq_to_channel_a(freq); + return b43_freq_to_channel_bg(freq); +} + +/* Lightweight function to convert a channel number to a frequency (in Mhz). */ +static inline int b43_channel_to_freq_a(u8 channel) +{ + return (5000 + (5 * channel)); +} +static inline int b43_channel_to_freq_bg(u8 channel) +{ + int freq; + + if (channel == 14) + freq = 2484; + else + freq = 2407 + (5 * channel); + + return freq; +} +static inline int b43_channel_to_freq(struct b43_wldev *dev, u8 channel) +{ + if (dev->phy.type == B43_PHYTYPE_A) + return b43_channel_to_freq_a(channel); + return b43_channel_to_freq_bg(channel); +} + +static inline int b43_is_cck_rate(int rate) +{ + return (rate == B43_CCK_RATE_1MB || + rate == B43_CCK_RATE_2MB || + rate == B43_CCK_RATE_5MB || rate == B43_CCK_RATE_11MB); +} + +static inline int b43_is_ofdm_rate(int rate) +{ + return !b43_is_cck_rate(rate); +} + +static inline int b43_is_hw_radio_enabled(struct b43_wldev *dev) +{ + /* function to return state of hardware enable of radio + * returns 0 if radio disabled, 1 if radio enabled + */ + struct b43_phy *phy = &dev->phy; + + if (phy->rev >= 3) + return ((b43_read32(dev, B43_MMIO_RADIO_HWENABLED_HI) + & B43_MMIO_RADIO_HWENABLED_HI_MASK) + == 0) ? 1 : 0; + else + return ((b43_read16(dev, B43_MMIO_RADIO_HWENABLED_LO) + & B43_MMIO_RADIO_HWENABLED_LO_MASK) + == 0) ? 0 : 1; +} + +void b43_tsf_read(struct b43_wldev *dev, u64 * tsf); +void b43_tsf_write(struct b43_wldev *dev, u64 tsf); + +u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset); +u16 b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset); +void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value); +void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value); + +u32 b43_hf_read(struct b43_wldev *dev); +void b43_hf_write(struct b43_wldev *dev, u32 value); + +void b43_dummy_transmission(struct b43_wldev *dev); + +void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags); + +void b43_mac_suspend(struct b43_wldev *dev); +void b43_mac_enable(struct b43_wldev *dev); + +void b43_controller_restart(struct b43_wldev *dev, const char *reason); + +#define B43_PS_ENABLED (1 << 0) /* Force enable hardware power saving */ +#define B43_PS_DISABLED (1 << 1) /* Force disable hardware power saving */ +#define B43_PS_AWAKE (1 << 2) /* Force device awake */ +#define B43_PS_ASLEEP (1 << 3) /* Force device asleep */ +void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags); + +#endif /* B43_MAIN_H_ */ diff --git a/drivers/net/wireless/b43/pcmcia.c b/drivers/net/wireless/b43/pcmcia.c new file mode 100644 index 00000000000..3e75a8a12c9 --- /dev/null +++ b/drivers/net/wireless/b43/pcmcia.c @@ -0,0 +1,157 @@ +/* + + Broadcom B43 wireless driver + + Copyright (c) 2007 Michael Buesch + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include + +#include +#include +#include +#include +#include +#include + +static /*const */ struct pcmcia_device_id b43_pcmcia_tbl[] = { + PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x448), + PCMCIA_DEVICE_NULL, +}; + +MODULE_DEVICE_TABLE(pcmcia, b43_pcmcia_tbl); + +#ifdef CONFIG_PM +static int b43_pcmcia_suspend(struct pcmcia_device *dev) +{ + //TODO + return 0; +} + +static int b43_pcmcia_resume(struct pcmcia_device *dev) +{ + //TODO + return 0; +} +#else /* CONFIG_PM */ +# define b43_pcmcia_suspend NULL +# define b43_pcmcia_resume NULL +#endif /* CONFIG_PM */ + +static int __devinit b43_pcmcia_probe(struct pcmcia_device *dev) +{ + struct ssb_bus *ssb; + win_req_t win; + memreq_t mem; + tuple_t tuple; + cisparse_t parse; + int err = -ENOMEM; + int res; + unsigned char buf[64]; + + ssb = kzalloc(sizeof(*ssb), GFP_KERNEL); + if (!ssb) + goto out; + + err = -ENODEV; + tuple.DesiredTuple = CISTPL_CONFIG; + tuple.Attributes = 0; + tuple.TupleData = buf; + tuple.TupleDataMax = sizeof(buf); + tuple.TupleOffset = 0; + + res = pcmcia_get_first_tuple(dev, &tuple); + if (res != CS_SUCCESS) + goto err_kfree_ssb; + res = pcmcia_get_tuple_data(dev, &tuple); + if (res != CS_SUCCESS) + goto err_kfree_ssb; + res = pcmcia_parse_tuple(dev, &tuple, &parse); + if (res != CS_SUCCESS) + goto err_kfree_ssb; + + dev->conf.ConfigBase = parse.config.base; + dev->conf.Present = parse.config.rmask[0]; + + dev->io.BasePort2 = 0; + dev->io.NumPorts2 = 0; + dev->io.Attributes2 = 0; + + win.Attributes = WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT; + win.Base = 0; + win.Size = SSB_CORE_SIZE; + win.AccessSpeed = 1000; + res = pcmcia_request_window(&dev, &win, &dev->win); + if (res != CS_SUCCESS) + goto err_kfree_ssb; + + mem.CardOffset = 0; + mem.Page = 0; + res = pcmcia_map_mem_page(dev->win, &mem); + if (res != CS_SUCCESS) + goto err_kfree_ssb; + + res = pcmcia_request_configuration(dev, &dev->conf); + if (res != CS_SUCCESS) + goto err_disable; + + err = ssb_bus_pcmciabus_register(ssb, dev, win.Base); + dev->priv = ssb; + + out: + return err; + err_disable: + pcmcia_disable_device(dev); + err_kfree_ssb: + kfree(ssb); + return err; +} + +static void __devexit b43_pcmcia_remove(struct pcmcia_device *dev) +{ + struct ssb_bus *ssb = dev->priv; + + ssb_bus_unregister(ssb); + pcmcia_release_window(dev->win); + pcmcia_disable_device(dev); + kfree(ssb); + dev->priv = NULL; +} + +static struct pcmcia_driver b43_pcmcia_driver = { + .owner = THIS_MODULE, + .drv = { + .name = "b43-pcmcia", + }, + .id_table = b43_pcmcia_tbl, + .probe = b43_pcmcia_probe, + .remove = b43_pcmcia_remove, + .suspend = b43_pcmcia_suspend, + .resume = b43_pcmcia_resume, +}; + +int b43_pcmcia_init(void) +{ + return pcmcia_register_driver(&b43_pcmcia_driver); +} + +void b43_pcmcia_exit(void) +{ + pcmcia_unregister_driver(&b43_pcmcia_driver); +} diff --git a/drivers/net/wireless/b43/pcmcia.h b/drivers/net/wireless/b43/pcmcia.h new file mode 100644 index 00000000000..85f120a67cb --- /dev/null +++ b/drivers/net/wireless/b43/pcmcia.h @@ -0,0 +1,20 @@ +#ifndef B43_PCMCIA_H_ +#define B43_PCMCIA_H_ + +#ifdef CONFIG_B43_PCMCIA + +int b43_pcmcia_init(void); +void b43_pcmcia_exit(void); + +#else /* CONFIG_B43_PCMCIA */ + +static inline int b43_pcmcia_init(void) +{ + return 0; +} +static inline void b43_pcmcia_exit(void) +{ +} + +#endif /* CONFIG_B43_PCMCIA */ +#endif /* B43_PCMCIA_H_ */ diff --git a/drivers/net/wireless/b43/phy.c b/drivers/net/wireless/b43/phy.c new file mode 100644 index 00000000000..3282893021b --- /dev/null +++ b/drivers/net/wireless/b43/phy.c @@ -0,0 +1,4351 @@ +/* + + Broadcom B43 wireless driver + + Copyright (c) 2005 Martin Langer , + Copyright (c) 2005, 2006 Stefano Brivio + Copyright (c) 2005, 2006 Michael Buesch + Copyright (c) 2005, 2006 Danny van Dyk + Copyright (c) 2005, 2006 Andreas Jaggi + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include +#include + +#include "b43.h" +#include "phy.h" +#include "main.h" +#include "tables.h" +#include "lo.h" + +static const s8 b43_tssi2dbm_b_table[] = { + 0x4D, 0x4C, 0x4B, 0x4A, + 0x4A, 0x49, 0x48, 0x47, + 0x47, 0x46, 0x45, 0x45, + 0x44, 0x43, 0x42, 0x42, + 0x41, 0x40, 0x3F, 0x3E, + 0x3D, 0x3C, 0x3B, 0x3A, + 0x39, 0x38, 0x37, 0x36, + 0x35, 0x34, 0x32, 0x31, + 0x30, 0x2F, 0x2D, 0x2C, + 0x2B, 0x29, 0x28, 0x26, + 0x25, 0x23, 0x21, 0x1F, + 0x1D, 0x1A, 0x17, 0x14, + 0x10, 0x0C, 0x06, 0x00, + -7, -7, -7, -7, + -7, -7, -7, -7, + -7, -7, -7, -7, +}; + +static const s8 b43_tssi2dbm_g_table[] = { + 77, 77, 77, 76, + 76, 76, 75, 75, + 74, 74, 73, 73, + 73, 72, 72, 71, + 71, 70, 70, 69, + 68, 68, 67, 67, + 66, 65, 65, 64, + 63, 63, 62, 61, + 60, 59, 58, 57, + 56, 55, 54, 53, + 52, 50, 49, 47, + 45, 43, 40, 37, + 33, 28, 22, 14, + 5, -7, -20, -20, + -20, -20, -20, -20, + -20, -20, -20, -20, +}; + +const u8 b43_radio_channel_codes_bg[] = { + 12, 17, 22, 27, + 32, 37, 42, 47, + 52, 57, 62, 67, + 72, 84, +}; + +static void b43_phy_initg(struct b43_wldev *dev); + +/* Reverse the bits of a 4bit value. + * Example: 1101 is flipped 1011 + */ +static u16 flip_4bit(u16 value) +{ + u16 flipped = 0x0000; + + B43_WARN_ON(value & ~0x000F); + + flipped |= (value & 0x0001) << 3; + flipped |= (value & 0x0002) << 1; + flipped |= (value & 0x0004) >> 1; + flipped |= (value & 0x0008) >> 3; + + return flipped; +} + +static void generate_rfatt_list(struct b43_wldev *dev, + struct b43_rfatt_list *list) +{ + struct b43_phy *phy = &dev->phy; + + /* APHY.rev < 5 || GPHY.rev < 6 */ + static const struct b43_rfatt rfatt_0[] = { + {.att = 3,.with_padmix = 0,}, + {.att = 1,.with_padmix = 0,}, + {.att = 5,.with_padmix = 0,}, + {.att = 7,.with_padmix = 0,}, + {.att = 9,.with_padmix = 0,}, + {.att = 2,.with_padmix = 0,}, + {.att = 0,.with_padmix = 0,}, + {.att = 4,.with_padmix = 0,}, + {.att = 6,.with_padmix = 0,}, + {.att = 8,.with_padmix = 0,}, + {.att = 1,.with_padmix = 1,}, + {.att = 2,.with_padmix = 1,}, + {.att = 3,.with_padmix = 1,}, + {.att = 4,.with_padmix = 1,}, + }; + /* Radio.rev == 8 && Radio.version == 0x2050 */ + static const struct b43_rfatt rfatt_1[] = { + {.att = 2,.with_padmix = 1,}, + {.att = 4,.with_padmix = 1,}, + {.att = 6,.with_padmix = 1,}, + {.att = 8,.with_padmix = 1,}, + {.att = 10,.with_padmix = 1,}, + {.att = 12,.with_padmix = 1,}, + {.att = 14,.with_padmix = 1,}, + }; + /* Otherwise */ + static const struct b43_rfatt rfatt_2[] = { + {.att = 0,.with_padmix = 1,}, + {.att = 2,.with_padmix = 1,}, + {.att = 4,.with_padmix = 1,}, + {.att = 6,.with_padmix = 1,}, + {.att = 8,.with_padmix = 1,}, + {.att = 9,.with_padmix = 1,}, + {.att = 9,.with_padmix = 1,}, + }; + + if ((phy->type == B43_PHYTYPE_A && phy->rev < 5) || + (phy->type == B43_PHYTYPE_G && phy->rev < 6)) { + /* Software pctl */ + list->list = rfatt_0; + list->len = ARRAY_SIZE(rfatt_0); + list->min_val = 0; + list->max_val = 9; + return; + } + if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) { + /* Hardware pctl */ + list->list = rfatt_1; + list->len = ARRAY_SIZE(rfatt_1); + list->min_val = 2; + list->max_val = 14; + return; + } + /* Hardware pctl */ + list->list = rfatt_2; + list->len = ARRAY_SIZE(rfatt_2); + list->min_val = 0; + list->max_val = 9; +} + +static void generate_bbatt_list(struct b43_wldev *dev, + struct b43_bbatt_list *list) +{ + static const struct b43_bbatt bbatt_0[] = { + {.att = 0,}, + {.att = 1,}, + {.att = 2,}, + {.att = 3,}, + {.att = 4,}, + {.att = 5,}, + {.att = 6,}, + {.att = 7,}, + {.att = 8,}, + }; + + list->list = bbatt_0; + list->len = ARRAY_SIZE(bbatt_0); + list->min_val = 0; + list->max_val = 8; +} + +bool b43_has_hardware_pctl(struct b43_phy *phy) +{ + if (!phy->hardware_power_control) + return 0; + switch (phy->type) { + case B43_PHYTYPE_A: + if (phy->rev >= 5) + return 1; + break; + case B43_PHYTYPE_G: + if (phy->rev >= 6) + return 1; + break; + default: + B43_WARN_ON(1); + } + return 0; +} + +static void b43_shm_clear_tssi(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + + switch (phy->type) { + case B43_PHYTYPE_A: + b43_shm_write16(dev, B43_SHM_SHARED, 0x0068, 0x7F7F); + b43_shm_write16(dev, B43_SHM_SHARED, 0x006a, 0x7F7F); + break; + case B43_PHYTYPE_B: + case B43_PHYTYPE_G: + b43_shm_write16(dev, B43_SHM_SHARED, 0x0058, 0x7F7F); + b43_shm_write16(dev, B43_SHM_SHARED, 0x005a, 0x7F7F); + b43_shm_write16(dev, B43_SHM_SHARED, 0x0070, 0x7F7F); + b43_shm_write16(dev, B43_SHM_SHARED, 0x0072, 0x7F7F); + break; + } +} + +void b43_raw_phy_lock(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + + B43_WARN_ON(!irqs_disabled()); + + /* We had a check for MACCTL==0 here, but I think that doesn't + * make sense, as MACCTL is never 0 when this is called. + * --mb */ + B43_WARN_ON(b43_read32(dev, B43_MMIO_MACCTL) == 0); + + if (dev->dev->id.revision < 3) { + b43_mac_suspend(dev); + spin_lock(&phy->lock); + } else { + if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) + b43_power_saving_ctl_bits(dev, B43_PS_AWAKE); + } + phy->locked = 1; +} + +void b43_raw_phy_unlock(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + + B43_WARN_ON(!irqs_disabled()); + if (dev->dev->id.revision < 3) { + if (phy->locked) { + spin_unlock(&phy->lock); + b43_mac_enable(dev); + } + } else { + if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) + b43_power_saving_ctl_bits(dev, 0); + } + phy->locked = 0; +} + +/* Different PHYs require different register routing flags. + * This adjusts (and does sanity checks on) the routing flags. + */ +static inline u16 adjust_phyreg_for_phytype(struct b43_phy *phy, + u16 offset, struct b43_wldev *dev) +{ + if (phy->type == B43_PHYTYPE_A) { + /* OFDM registers are base-registers for the A-PHY. */ + offset &= ~B43_PHYROUTE_OFDM_GPHY; + } + if (offset & B43_PHYROUTE_EXT_GPHY) { + /* Ext-G registers are only available on G-PHYs */ + if (phy->type != B43_PHYTYPE_G) { + b43dbg(dev->wl, "EXT-G PHY access at " + "0x%04X on %u type PHY\n", offset, phy->type); + } + } + + return offset; +} + +u16 b43_phy_read(struct b43_wldev * dev, u16 offset) +{ + struct b43_phy *phy = &dev->phy; + + offset = adjust_phyreg_for_phytype(phy, offset, dev); + b43_write16(dev, B43_MMIO_PHY_CONTROL, offset); + return b43_read16(dev, B43_MMIO_PHY_DATA); +} + +void b43_phy_write(struct b43_wldev *dev, u16 offset, u16 val) +{ + struct b43_phy *phy = &dev->phy; + + offset = adjust_phyreg_for_phytype(phy, offset, dev); + b43_write16(dev, B43_MMIO_PHY_CONTROL, offset); + mmiowb(); + b43_write16(dev, B43_MMIO_PHY_DATA, val); +} + +static void b43_radio_set_txpower_a(struct b43_wldev *dev, u16 txpower); + +/* Adjust the transmission power output (G-PHY) */ +void b43_set_txpower_g(struct b43_wldev *dev, + const struct b43_bbatt *bbatt, + const struct b43_rfatt *rfatt, u8 tx_control) +{ + struct b43_phy *phy = &dev->phy; + struct b43_txpower_lo_control *lo = phy->lo_control; + u16 bb, rf; + u16 tx_bias, tx_magn; + + bb = bbatt->att; + rf = rfatt->att; + tx_bias = lo->tx_bias; + tx_magn = lo->tx_magn; + if (unlikely(tx_bias == 0xFF)) + tx_bias = 0; + + /* Save the values for later */ + phy->tx_control = tx_control; + memcpy(&phy->rfatt, rfatt, sizeof(*rfatt)); + memcpy(&phy->bbatt, bbatt, sizeof(*bbatt)); + + if (b43_debug(dev, B43_DBG_XMITPOWER)) { + b43dbg(dev->wl, "Tuning TX-power to bbatt(%u), " + "rfatt(%u), tx_control(0x%02X), " + "tx_bias(0x%02X), tx_magn(0x%02X)\n", + bb, rf, tx_control, tx_bias, tx_magn); + } + + b43_phy_set_baseband_attenuation(dev, bb); + b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_RFATT, rf); + if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) { + b43_radio_write16(dev, 0x43, + (rf & 0x000F) | (tx_control & 0x0070)); + } else { + b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43) + & 0xFFF0) | (rf & 0x000F)); + b43_radio_write16(dev, 0x52, (b43_radio_read16(dev, 0x52) + & ~0x0070) | (tx_control & + 0x0070)); + } + if (has_tx_magnification(phy)) { + b43_radio_write16(dev, 0x52, tx_magn | tx_bias); + } else { + b43_radio_write16(dev, 0x52, (b43_radio_read16(dev, 0x52) + & 0xFFF0) | (tx_bias & 0x000F)); + } + if (phy->type == B43_PHYTYPE_G) + b43_lo_g_adjust(dev); +} + +static void default_baseband_attenuation(struct b43_wldev *dev, + struct b43_bbatt *bb) +{ + struct b43_phy *phy = &dev->phy; + + if (phy->radio_ver == 0x2050 && phy->radio_rev < 6) + bb->att = 0; + else + bb->att = 2; +} + +static void default_radio_attenuation(struct b43_wldev *dev, + struct b43_rfatt *rf) +{ + struct ssb_bus *bus = dev->dev->bus; + struct b43_phy *phy = &dev->phy; + + rf->with_padmix = 0; + + if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM && + bus->boardinfo.type == SSB_BOARD_BCM4309G) { + if (bus->boardinfo.rev < 0x43) { + rf->att = 2; + return; + } else if (bus->boardinfo.rev < 0x51) { + rf->att = 3; + return; + } + } + + if (phy->type == B43_PHYTYPE_A) { + rf->att = 0x60; + return; + } + + switch (phy->radio_ver) { + case 0x2053: + switch (phy->radio_rev) { + case 1: + rf->att = 6; + return; + } + break; + case 0x2050: + switch (phy->radio_rev) { + case 0: + rf->att = 5; + return; + case 1: + if (phy->type == B43_PHYTYPE_G) { + if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM + && bus->boardinfo.type == SSB_BOARD_BCM4309G + && bus->boardinfo.rev >= 30) + rf->att = 3; + else if (bus->boardinfo.vendor == + SSB_BOARDVENDOR_BCM + && bus->boardinfo.type == + SSB_BOARD_BU4306) + rf->att = 3; + else + rf->att = 1; + } else { + if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM + && bus->boardinfo.type == SSB_BOARD_BCM4309G + && bus->boardinfo.rev >= 30) + rf->att = 7; + else + rf->att = 6; + } + return; + case 2: + if (phy->type == B43_PHYTYPE_G) { + if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM + && bus->boardinfo.type == SSB_BOARD_BCM4309G + && bus->boardinfo.rev >= 30) + rf->att = 3; + else if (bus->boardinfo.vendor == + SSB_BOARDVENDOR_BCM + && bus->boardinfo.type == + SSB_BOARD_BU4306) + rf->att = 5; + else if (bus->chip_id == 0x4320) + rf->att = 4; + else + rf->att = 3; + } else + rf->att = 6; + return; + case 3: + rf->att = 5; + return; + case 4: + case 5: + rf->att = 1; + return; + case 6: + case 7: + rf->att = 5; + return; + case 8: + rf->att = 0xA; + rf->with_padmix = 1; + return; + case 9: + default: + rf->att = 5; + return; + } + } + rf->att = 5; +} + +static u16 default_tx_control(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + + if (phy->radio_ver != 0x2050) + return 0; + if (phy->radio_rev == 1) + return B43_TXCTL_PA2DB | B43_TXCTL_TXMIX; + if (phy->radio_rev < 6) + return B43_TXCTL_PA2DB; + if (phy->radio_rev == 8) + return B43_TXCTL_TXMIX; + return 0; +} + +/* This func is called "PHY calibrate" in the specs... */ +void b43_phy_early_init(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_txpower_lo_control *lo = phy->lo_control; + + default_baseband_attenuation(dev, &phy->bbatt); + default_radio_attenuation(dev, &phy->rfatt); + phy->tx_control = (default_tx_control(dev) << 4); + + /* Commit previous writes */ + b43_read32(dev, B43_MMIO_MACCTL); + + if (phy->type == B43_PHYTYPE_B || phy->type == B43_PHYTYPE_G) { + generate_rfatt_list(dev, &lo->rfatt_list); + generate_bbatt_list(dev, &lo->bbatt_list); + } + if (phy->type == B43_PHYTYPE_G && phy->rev == 1) { + /* Workaround: Temporarly disable gmode through the early init + * phase, as the gmode stuff is not needed for phy rev 1 */ + phy->gmode = 0; + b43_wireless_core_reset(dev, 0); + b43_phy_initg(dev); + phy->gmode = 1; + b43_wireless_core_reset(dev, B43_TMSLOW_GMODE); + } +} + +/* GPHY_TSSI_Power_Lookup_Table_Init */ +static void b43_gphy_tssi_power_lt_init(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + int i; + u16 value; + + for (i = 0; i < 32; i++) + b43_ofdmtab_write16(dev, 0x3C20, i, phy->tssi2dbm[i]); + for (i = 32; i < 64; i++) + b43_ofdmtab_write16(dev, 0x3C00, i - 32, phy->tssi2dbm[i]); + for (i = 0; i < 64; i += 2) { + value = (u16) phy->tssi2dbm[i]; + value |= ((u16) phy->tssi2dbm[i + 1]) << 8; + b43_phy_write(dev, 0x380 + (i / 2), value); + } +} + +/* GPHY_Gain_Lookup_Table_Init */ +static void b43_gphy_gain_lt_init(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_txpower_lo_control *lo = phy->lo_control; + u16 nr_written = 0; + u16 tmp; + u8 rf, bb; + + if (!lo->lo_measured) { + b43_phy_write(dev, 0x3FF, 0); + return; + } + + for (rf = 0; rf < lo->rfatt_list.len; rf++) { + for (bb = 0; bb < lo->bbatt_list.len; bb++) { + if (nr_written >= 0x40) + return; + tmp = lo->bbatt_list.list[bb].att; + tmp <<= 8; + if (phy->radio_rev == 8) + tmp |= 0x50; + else + tmp |= 0x40; + tmp |= lo->rfatt_list.list[rf].att; + b43_phy_write(dev, 0x3C0 + nr_written, tmp); + nr_written++; + } + } +} + +/* GPHY_DC_Lookup_Table */ +void b43_gphy_dc_lt_init(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_txpower_lo_control *lo = phy->lo_control; + struct b43_loctl *loctl0; + struct b43_loctl *loctl1; + int i; + int rf_offset, bb_offset; + u16 tmp; + + for (i = 0; i < lo->rfatt_list.len + lo->bbatt_list.len; i += 2) { + rf_offset = i / lo->rfatt_list.len; + bb_offset = i % lo->rfatt_list.len; + + loctl0 = b43_get_lo_g_ctl(dev, &lo->rfatt_list.list[rf_offset], + &lo->bbatt_list.list[bb_offset]); + if (i + 1 < lo->rfatt_list.len * lo->bbatt_list.len) { + rf_offset = (i + 1) / lo->rfatt_list.len; + bb_offset = (i + 1) % lo->rfatt_list.len; + + loctl1 = + b43_get_lo_g_ctl(dev, + &lo->rfatt_list.list[rf_offset], + &lo->bbatt_list.list[bb_offset]); + } else + loctl1 = loctl0; + + tmp = ((u16) loctl0->q & 0xF); + tmp |= ((u16) loctl0->i & 0xF) << 4; + tmp |= ((u16) loctl1->q & 0xF) << 8; + tmp |= ((u16) loctl1->i & 0xF) << 12; //FIXME? + b43_phy_write(dev, 0x3A0 + (i / 2), tmp); + } +} + +static void hardware_pctl_init_aphy(struct b43_wldev *dev) +{ + //TODO +} + +static void hardware_pctl_init_gphy(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + + b43_phy_write(dev, 0x0036, (b43_phy_read(dev, 0x0036) & 0xFFC0) + | (phy->tgt_idle_tssi - phy->cur_idle_tssi)); + b43_phy_write(dev, 0x0478, (b43_phy_read(dev, 0x0478) & 0xFF00) + | (phy->tgt_idle_tssi - phy->cur_idle_tssi)); + b43_gphy_tssi_power_lt_init(dev); + b43_gphy_gain_lt_init(dev); + b43_phy_write(dev, 0x0060, b43_phy_read(dev, 0x0060) & 0xFFBF); + b43_phy_write(dev, 0x0014, 0x0000); + + B43_WARN_ON(phy->rev < 6); + b43_phy_write(dev, 0x0478, b43_phy_read(dev, 0x0478) + | 0x0800); + b43_phy_write(dev, 0x0478, b43_phy_read(dev, 0x0478) + & 0xFEFF); + b43_phy_write(dev, 0x0801, b43_phy_read(dev, 0x0801) + & 0xFFBF); + + b43_gphy_dc_lt_init(dev); +} + +/* HardwarePowerControl init for A and G PHY */ +static void b43_hardware_pctl_init(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + + if (!b43_has_hardware_pctl(phy)) { + /* No hardware power control */ + b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_HWPCTL); + return; + } + /* Init the hwpctl related hardware */ + switch (phy->type) { + case B43_PHYTYPE_A: + hardware_pctl_init_aphy(dev); + break; + case B43_PHYTYPE_G: + hardware_pctl_init_gphy(dev); + break; + default: + B43_WARN_ON(1); + } + /* Enable hardware pctl in firmware. */ + b43_hf_write(dev, b43_hf_read(dev) | B43_HF_HWPCTL); +} + +static void b43_hardware_pctl_early_init(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + + if (!b43_has_hardware_pctl(phy)) { + b43_phy_write(dev, 0x047A, 0xC111); + return; + } + + b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036) & 0xFEFF); + b43_phy_write(dev, 0x002F, 0x0202); + b43_phy_write(dev, 0x047C, b43_phy_read(dev, 0x047C) | 0x0002); + b43_phy_write(dev, 0x047A, b43_phy_read(dev, 0x047A) | 0xF000); + if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) { + b43_phy_write(dev, 0x047A, (b43_phy_read(dev, 0x047A) + & 0xFF0F) | 0x0010); + b43_phy_write(dev, 0x005D, b43_phy_read(dev, 0x005D) + | 0x8000); + b43_phy_write(dev, 0x004E, (b43_phy_read(dev, 0x004E) + & 0xFFC0) | 0x0010); + b43_phy_write(dev, 0x002E, 0xC07F); + b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036) + | 0x0400); + } else { + b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036) + | 0x0200); + b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036) + | 0x0400); + b43_phy_write(dev, 0x005D, b43_phy_read(dev, 0x005D) + & 0x7FFF); + b43_phy_write(dev, 0x004F, b43_phy_read(dev, 0x004F) + & 0xFFFE); + b43_phy_write(dev, 0x004E, (b43_phy_read(dev, 0x004E) + & 0xFFC0) | 0x0010); + b43_phy_write(dev, 0x002E, 0xC07F); + b43_phy_write(dev, 0x047A, (b43_phy_read(dev, 0x047A) + & 0xFF0F) | 0x0010); + } +} + +/* Intialize B/G PHY power control + * as described in http://bcm-specs.sipsolutions.net/InitPowerControl + */ +static void b43_phy_init_pctl(struct b43_wldev *dev) +{ + struct ssb_bus *bus = dev->dev->bus; + struct b43_phy *phy = &dev->phy; + struct b43_rfatt old_rfatt; + struct b43_bbatt old_bbatt; + u8 old_tx_control = 0; + + if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && + (bus->boardinfo.type == SSB_BOARD_BU4306)) + return; + + b43_phy_write(dev, 0x0028, 0x8018); + + /* This does something with the Analog... */ + b43_write16(dev, B43_MMIO_PHY0, b43_read16(dev, B43_MMIO_PHY0) + & 0xFFDF); + + if (phy->type == B43_PHYTYPE_G && !phy->gmode) + return; + b43_hardware_pctl_early_init(dev); + if (phy->cur_idle_tssi == 0) { + if (phy->radio_ver == 0x2050 && phy->analog == 0) { + b43_radio_write16(dev, 0x0076, + (b43_radio_read16(dev, 0x0076) + & 0x00F7) | 0x0084); + } else { + struct b43_rfatt rfatt; + struct b43_bbatt bbatt; + + memcpy(&old_rfatt, &phy->rfatt, sizeof(old_rfatt)); + memcpy(&old_bbatt, &phy->bbatt, sizeof(old_bbatt)); + old_tx_control = phy->tx_control; + + bbatt.att = 11; + if (phy->radio_rev == 8) { + rfatt.att = 15; + rfatt.with_padmix = 1; + } else { + rfatt.att = 9; + rfatt.with_padmix = 0; + } + b43_set_txpower_g(dev, &bbatt, &rfatt, 0); + } + b43_dummy_transmission(dev); + phy->cur_idle_tssi = b43_phy_read(dev, B43_PHY_ITSSI); + if (B43_DEBUG) { + /* Current-Idle-TSSI sanity check. */ + if (abs(phy->cur_idle_tssi - phy->tgt_idle_tssi) >= 20) { + b43dbg(dev->wl, + "!WARNING! Idle-TSSI phy->cur_idle_tssi " + "measuring failed. (cur=%d, tgt=%d). Disabling TX power " + "adjustment.\n", phy->cur_idle_tssi, + phy->tgt_idle_tssi); + phy->cur_idle_tssi = 0; + } + } + if (phy->radio_ver == 0x2050 && phy->analog == 0) { + b43_radio_write16(dev, 0x0076, + b43_radio_read16(dev, 0x0076) + & 0xFF7B); + } else { + b43_set_txpower_g(dev, &old_bbatt, + &old_rfatt, old_tx_control); + } + } + b43_hardware_pctl_init(dev); + b43_shm_clear_tssi(dev); +} + +static void b43_phy_agcsetup(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + u16 offset = 0x0000; + + if (phy->rev == 1) + offset = 0x4C00; + + b43_ofdmtab_write16(dev, offset, 0, 0x00FE); + b43_ofdmtab_write16(dev, offset, 1, 0x000D); + b43_ofdmtab_write16(dev, offset, 2, 0x0013); + b43_ofdmtab_write16(dev, offset, 3, 0x0019); + + if (phy->rev == 1) { + b43_ofdmtab_write16(dev, 0x1800, 0, 0x2710); + b43_ofdmtab_write16(dev, 0x1801, 0, 0x9B83); + b43_ofdmtab_write16(dev, 0x1802, 0, 0x9B83); + b43_ofdmtab_write16(dev, 0x1803, 0, 0x0F8D); + b43_phy_write(dev, 0x0455, 0x0004); + } + + b43_phy_write(dev, 0x04A5, (b43_phy_read(dev, 0x04A5) + & 0x00FF) | 0x5700); + b43_phy_write(dev, 0x041A, (b43_phy_read(dev, 0x041A) + & 0xFF80) | 0x000F); + b43_phy_write(dev, 0x041A, (b43_phy_read(dev, 0x041A) + & 0xC07F) | 0x2B80); + b43_phy_write(dev, 0x048C, (b43_phy_read(dev, 0x048C) + & 0xF0FF) | 0x0300); + + b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) + | 0x0008); + + b43_phy_write(dev, 0x04A0, (b43_phy_read(dev, 0x04A0) + & 0xFFF0) | 0x0008); + b43_phy_write(dev, 0x04A1, (b43_phy_read(dev, 0x04A1) + & 0xF0FF) | 0x0600); + b43_phy_write(dev, 0x04A2, (b43_phy_read(dev, 0x04A2) + & 0xF0FF) | 0x0700); + b43_phy_write(dev, 0x04A0, (b43_phy_read(dev, 0x04A0) + & 0xF0FF) | 0x0100); + + if (phy->rev == 1) { + b43_phy_write(dev, 0x04A2, (b43_phy_read(dev, 0x04A2) + & 0xFFF0) | 0x0007); + } + + b43_phy_write(dev, 0x0488, (b43_phy_read(dev, 0x0488) + & 0xFF00) | 0x001C); + b43_phy_write(dev, 0x0488, (b43_phy_read(dev, 0x0488) + & 0xC0FF) | 0x0200); + b43_phy_write(dev, 0x0496, (b43_phy_read(dev, 0x0496) + & 0xFF00) | 0x001C); + b43_phy_write(dev, 0x0489, (b43_phy_read(dev, 0x0489) + & 0xFF00) | 0x0020); + b43_phy_write(dev, 0x0489, (b43_phy_read(dev, 0x0489) + & 0xC0FF) | 0x0200); + b43_phy_write(dev, 0x0482, (b43_phy_read(dev, 0x0482) + & 0xFF00) | 0x002E); + b43_phy_write(dev, 0x0496, (b43_phy_read(dev, 0x0496) + & 0x00FF) | 0x1A00); + b43_phy_write(dev, 0x0481, (b43_phy_read(dev, 0x0481) + & 0xFF00) | 0x0028); + b43_phy_write(dev, 0x0481, (b43_phy_read(dev, 0x0481) + & 0x00FF) | 0x2C00); + + if (phy->rev == 1) { + b43_phy_write(dev, 0x0430, 0x092B); + b43_phy_write(dev, 0x041B, (b43_phy_read(dev, 0x041B) + & 0xFFE1) | 0x0002); + } else { + b43_phy_write(dev, 0x041B, b43_phy_read(dev, 0x041B) + & 0xFFE1); + b43_phy_write(dev, 0x041F, 0x287A); + b43_phy_write(dev, 0x0420, (b43_phy_read(dev, 0x0420) + & 0xFFF0) | 0x0004); + } + + if (phy->rev >= 6) { + b43_phy_write(dev, 0x0422, 0x287A); + b43_phy_write(dev, 0x0420, (b43_phy_read(dev, 0x0420) + & 0x0FFF) | 0x3000); + } + + b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8) + & 0x8080) | 0x7874); + b43_phy_write(dev, 0x048E, 0x1C00); + + offset = 0x0800; + if (phy->rev == 1) { + offset = 0x5400; + b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB) + & 0xF0FF) | 0x0600); + b43_phy_write(dev, 0x048B, 0x005E); + b43_phy_write(dev, 0x048C, (b43_phy_read(dev, 0x048C) + & 0xFF00) | 0x001E); + b43_phy_write(dev, 0x048D, 0x0002); + } + b43_ofdmtab_write16(dev, offset, 0, 0x00); + b43_ofdmtab_write16(dev, offset, 1, 0x07); + b43_ofdmtab_write16(dev, offset, 2, 0x10); + b43_ofdmtab_write16(dev, offset, 3, 0x1C); + + if (phy->rev >= 6) { + b43_phy_write(dev, 0x0426, b43_phy_read(dev, 0x0426) + & 0xFFFC); + b43_phy_write(dev, 0x0426, b43_phy_read(dev, 0x0426) + & 0xEFFF); + } +} + +static void b43_phy_setupg(struct b43_wldev *dev) +{ + struct ssb_bus *bus = dev->dev->bus; + struct b43_phy *phy = &dev->phy; + u16 i; + + B43_WARN_ON(phy->type != B43_PHYTYPE_G); + if (phy->rev == 1) { + b43_phy_write(dev, 0x0406, 0x4F19); + b43_phy_write(dev, B43_PHY_G_CRS, + (b43_phy_read(dev, B43_PHY_G_CRS) & 0xFC3F) | + 0x0340); + b43_phy_write(dev, 0x042C, 0x005A); + b43_phy_write(dev, 0x0427, 0x001A); + + for (i = 0; i < B43_TAB_FINEFREQG_SIZE; i++) + b43_ofdmtab_write16(dev, 0x5800, i, + b43_tab_finefreqg[i]); + for (i = 0; i < B43_TAB_NOISEG1_SIZE; i++) + b43_ofdmtab_write16(dev, 0x1800, i, b43_tab_noiseg1[i]); + for (i = 0; i < B43_TAB_ROTOR_SIZE; i++) + b43_ofdmtab_write16(dev, 0x2000, i, b43_tab_rotor[i]); + } else { + /* nrssi values are signed 6-bit values. Not sure why we write 0x7654 here... */ + b43_nrssi_hw_write(dev, 0xBA98, (s16) 0x7654); + + if (phy->rev == 2) { + b43_phy_write(dev, 0x04C0, 0x1861); + b43_phy_write(dev, 0x04C1, 0x0271); + } else if (phy->rev > 2) { + b43_phy_write(dev, 0x04C0, 0x0098); + b43_phy_write(dev, 0x04C1, 0x0070); + b43_phy_write(dev, 0x04C9, 0x0080); + } + b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x800); + + for (i = 0; i < 64; i++) + b43_ofdmtab_write16(dev, 0x4000, i, i); + for (i = 0; i < B43_TAB_NOISEG2_SIZE; i++) + b43_ofdmtab_write16(dev, 0x1800, i, b43_tab_noiseg2[i]); + } + + if (phy->rev <= 2) + for (i = 0; i < B43_TAB_NOISESCALEG_SIZE; i++) + b43_ofdmtab_write16(dev, 0x1400, i, + b43_tab_noisescaleg1[i]); + else if ((phy->rev >= 7) && (b43_phy_read(dev, 0x0449) & 0x0200)) + for (i = 0; i < B43_TAB_NOISESCALEG_SIZE; i++) + b43_ofdmtab_write16(dev, 0x1400, i, + b43_tab_noisescaleg3[i]); + else + for (i = 0; i < B43_TAB_NOISESCALEG_SIZE; i++) + b43_ofdmtab_write16(dev, 0x1400, i, + b43_tab_noisescaleg2[i]); + + if (phy->rev == 2) + for (i = 0; i < B43_TAB_SIGMASQR_SIZE; i++) + b43_ofdmtab_write16(dev, 0x5000, i, + b43_tab_sigmasqr1[i]); + else if ((phy->rev > 2) && (phy->rev <= 8)) + for (i = 0; i < B43_TAB_SIGMASQR_SIZE; i++) + b43_ofdmtab_write16(dev, 0x5000, i, + b43_tab_sigmasqr2[i]); + + if (phy->rev == 1) { + for (i = 0; i < B43_TAB_RETARD_SIZE; i++) + b43_ofdmtab_write32(dev, 0x2400, i, b43_tab_retard[i]); + for (i = 4; i < 20; i++) + b43_ofdmtab_write16(dev, 0x5400, i, 0x0020); + b43_phy_agcsetup(dev); + + if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && + (bus->boardinfo.type == SSB_BOARD_BU4306) && + (bus->boardinfo.rev == 0x17)) + return; + + b43_ofdmtab_write16(dev, 0x5001, 0, 0x0002); + b43_ofdmtab_write16(dev, 0x5002, 0, 0x0001); + } else { + for (i = 0; i < 0x20; i++) + b43_ofdmtab_write16(dev, 0x1000, i, 0x0820); + b43_phy_agcsetup(dev); + b43_phy_read(dev, 0x0400); /* dummy read */ + b43_phy_write(dev, 0x0403, 0x1000); + b43_ofdmtab_write16(dev, 0x3C02, 0, 0x000F); + b43_ofdmtab_write16(dev, 0x3C03, 0, 0x0014); + + if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && + (bus->boardinfo.type == SSB_BOARD_BU4306) && + (bus->boardinfo.rev == 0x17)) + return; + + b43_ofdmtab_write16(dev, 0x0401, 0, 0x0002); + b43_ofdmtab_write16(dev, 0x0402, 0, 0x0001); + } +} + +/* Initialize the noisescaletable for APHY */ +static void b43_phy_init_noisescaletbl(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + int i; + + for (i = 0; i < 12; i++) { + if (phy->rev == 2) + b43_ofdmtab_write16(dev, 0x1400, i, 0x6767); + else + b43_ofdmtab_write16(dev, 0x1400, i, 0x2323); + } + if (phy->rev == 2) + b43_ofdmtab_write16(dev, 0x1400, i, 0x6700); + else + b43_ofdmtab_write16(dev, 0x1400, i, 0x2300); + for (i = 0; i < 11; i++) { + if (phy->rev == 2) + b43_ofdmtab_write16(dev, 0x1400, i, 0x6767); + else + b43_ofdmtab_write16(dev, 0x1400, i, 0x2323); + } + if (phy->rev == 2) + b43_ofdmtab_write16(dev, 0x1400, i, 0x0067); + else + b43_ofdmtab_write16(dev, 0x1400, i, 0x0023); +} + +static void b43_phy_setupa(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + u16 i; + + B43_WARN_ON(phy->type != B43_PHYTYPE_A); + switch (phy->rev) { + case 2: + b43_phy_write(dev, 0x008E, 0x3800); + b43_phy_write(dev, 0x0035, 0x03FF); + b43_phy_write(dev, 0x0036, 0x0400); + + b43_ofdmtab_write16(dev, 0x3807, 0, 0x0051); + + b43_phy_write(dev, 0x001C, 0x0FF9); + b43_phy_write(dev, 0x0020, b43_phy_read(dev, 0x0020) & 0xFF0F); + b43_ofdmtab_write16(dev, 0x3C0C, 0, 0x07BF); + b43_radio_write16(dev, 0x0002, 0x07BF); + + b43_phy_write(dev, 0x0024, 0x4680); + b43_phy_write(dev, 0x0020, 0x0003); + b43_phy_write(dev, 0x001D, 0x0F40); + b43_phy_write(dev, 0x001F, 0x1C00); + + b43_phy_write(dev, 0x002A, (b43_phy_read(dev, 0x002A) + & 0x00FF) | 0x0400); + b43_phy_write(dev, 0x002B, b43_phy_read(dev, 0x002B) + & 0xFBFF); + b43_phy_write(dev, 0x008E, 0x58C1); + + b43_ofdmtab_write16(dev, 0x0803, 0, 0x000F); + b43_ofdmtab_write16(dev, 0x0804, 0, 0x001F); + b43_ofdmtab_write16(dev, 0x0805, 0, 0x002A); + b43_ofdmtab_write16(dev, 0x0805, 0, 0x0030); + b43_ofdmtab_write16(dev, 0x0807, 0, 0x003A); + + b43_ofdmtab_write16(dev, 0x0000, 0, 0x0013); + b43_ofdmtab_write16(dev, 0x0000, 1, 0x0013); + b43_ofdmtab_write16(dev, 0x0000, 2, 0x0013); + b43_ofdmtab_write16(dev, 0x0000, 3, 0x0013); + b43_ofdmtab_write16(dev, 0x0000, 4, 0x0015); + b43_ofdmtab_write16(dev, 0x0000, 5, 0x0015); + b43_ofdmtab_write16(dev, 0x0000, 6, 0x0019); + + b43_ofdmtab_write16(dev, 0x0404, 0, 0x0003); + b43_ofdmtab_write16(dev, 0x0405, 0, 0x0003); + b43_ofdmtab_write16(dev, 0x0406, 0, 0x0007); + + for (i = 0; i < 16; i++) + b43_ofdmtab_write16(dev, 0x4000, i, (0x8 + i) & 0x000F); + + b43_ofdmtab_write16(dev, 0x3003, 0, 0x1044); + b43_ofdmtab_write16(dev, 0x3004, 0, 0x7201); + b43_ofdmtab_write16(dev, 0x3006, 0, 0x0040); + b43_ofdmtab_write16(dev, 0x3001, 0, + (b43_ofdmtab_read16(dev, 0x3001, 0) & + 0x0010) | 0x0008); + + for (i = 0; i < B43_TAB_FINEFREQA_SIZE; i++) + b43_ofdmtab_write16(dev, 0x5800, i, + b43_tab_finefreqa[i]); + for (i = 0; i < B43_TAB_NOISEA2_SIZE; i++) + b43_ofdmtab_write16(dev, 0x1800, i, b43_tab_noisea2[i]); + for (i = 0; i < B43_TAB_ROTOR_SIZE; i++) + b43_ofdmtab_write32(dev, 0x2000, i, b43_tab_rotor[i]); + b43_phy_init_noisescaletbl(dev); + for (i = 0; i < B43_TAB_RETARD_SIZE; i++) + b43_ofdmtab_write32(dev, 0x2400, i, b43_tab_retard[i]); + break; + case 3: + for (i = 0; i < 64; i++) + b43_ofdmtab_write16(dev, 0x4000, i, i); + + b43_ofdmtab_write16(dev, 0x3807, 0, 0x0051); + + b43_phy_write(dev, 0x001C, 0x0FF9); + b43_phy_write(dev, 0x0020, b43_phy_read(dev, 0x0020) & 0xFF0F); + b43_radio_write16(dev, 0x0002, 0x07BF); + + b43_phy_write(dev, 0x0024, 0x4680); + b43_phy_write(dev, 0x0020, 0x0003); + b43_phy_write(dev, 0x001D, 0x0F40); + b43_phy_write(dev, 0x001F, 0x1C00); + b43_phy_write(dev, 0x002A, (b43_phy_read(dev, 0x002A) + & 0x00FF) | 0x0400); + + b43_ofdmtab_write16(dev, 0x3000, 1, + (b43_ofdmtab_read16(dev, 0x3000, 1) + & 0x0010) | 0x0008); + for (i = 0; i < B43_TAB_NOISEA3_SIZE; i++) { + b43_ofdmtab_write16(dev, 0x1800, i, b43_tab_noisea3[i]); + } + b43_phy_init_noisescaletbl(dev); + for (i = 0; i < B43_TAB_SIGMASQR_SIZE; i++) { + b43_ofdmtab_write16(dev, 0x5000, i, + b43_tab_sigmasqr1[i]); + } + + b43_phy_write(dev, 0x0003, 0x1808); + + b43_ofdmtab_write16(dev, 0x0803, 0, 0x000F); + b43_ofdmtab_write16(dev, 0x0804, 0, 0x001F); + b43_ofdmtab_write16(dev, 0x0805, 0, 0x002A); + b43_ofdmtab_write16(dev, 0x0805, 0, 0x0030); + b43_ofdmtab_write16(dev, 0x0807, 0, 0x003A); + + b43_ofdmtab_write16(dev, 0x0000, 0, 0x0013); + b43_ofdmtab_write16(dev, 0x0001, 0, 0x0013); + b43_ofdmtab_write16(dev, 0x0002, 0, 0x0013); + b43_ofdmtab_write16(dev, 0x0003, 0, 0x0013); + b43_ofdmtab_write16(dev, 0x0004, 0, 0x0015); + b43_ofdmtab_write16(dev, 0x0005, 0, 0x0015); + b43_ofdmtab_write16(dev, 0x0006, 0, 0x0019); + + b43_ofdmtab_write16(dev, 0x0404, 0, 0x0003); + b43_ofdmtab_write16(dev, 0x0405, 0, 0x0003); + b43_ofdmtab_write16(dev, 0x0406, 0, 0x0007); + + b43_ofdmtab_write16(dev, 0x3C02, 0, 0x000F); + b43_ofdmtab_write16(dev, 0x3C03, 0, 0x0014); + break; + default: + B43_WARN_ON(1); + } +} + +/* Initialize APHY. This is also called for the GPHY in some cases. */ +static void b43_phy_inita(struct b43_wldev *dev) +{ + struct ssb_bus *bus = dev->dev->bus; + struct b43_phy *phy = &dev->phy; + u16 tval; + + might_sleep(); + + if (phy->type == B43_PHYTYPE_A) { + b43_phy_setupa(dev); + } else { + b43_phy_setupg(dev); + if (phy->gmode && + (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_PACTRL)) + b43_phy_write(dev, 0x046E, 0x03CF); + return; + } + + b43_phy_write(dev, B43_PHY_A_CRS, + (b43_phy_read(dev, B43_PHY_A_CRS) & 0xF83C) | 0x0340); + b43_phy_write(dev, 0x0034, 0x0001); + + //TODO: RSSI AGC + b43_phy_write(dev, B43_PHY_A_CRS, + b43_phy_read(dev, B43_PHY_A_CRS) | (1 << 14)); + b43_radio_init2060(dev); + + if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && + ((bus->boardinfo.type == SSB_BOARD_BU4306) || + (bus->boardinfo.type == SSB_BOARD_BU4309))) { + if (phy->lofcal == 0xFFFF) { + //TODO: LOF Cal + b43_radio_set_tx_iq(dev); + } else + b43_radio_write16(dev, 0x001E, phy->lofcal); + } + + b43_phy_write(dev, 0x007A, 0xF111); + + if (phy->cur_idle_tssi == 0) { + b43_radio_write16(dev, 0x0019, 0x0000); + b43_radio_write16(dev, 0x0017, 0x0020); + + tval = b43_ofdmtab_read16(dev, 0x3001, 0); + if (phy->rev == 1) { + b43_ofdmtab_write16(dev, 0x3001, 0, + (b43_ofdmtab_read16(dev, 0x3001, 0) + & 0xFF87) + | 0x0058); + } else { + b43_ofdmtab_write16(dev, 0x3001, 0, + (b43_ofdmtab_read16(dev, 0x3001, 0) + & 0xFFC3) + | 0x002C); + } + b43_dummy_transmission(dev); + phy->cur_idle_tssi = b43_phy_read(dev, B43_PHY_A_PCTL); + b43_ofdmtab_write16(dev, 0x3001, 0, tval); + + b43_radio_set_txpower_a(dev, 0x0018); + } + b43_shm_clear_tssi(dev); +} + +static void b43_phy_initb2(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + u16 offset, val; + + b43_write16(dev, 0x03EC, 0x3F22); + b43_phy_write(dev, 0x0020, 0x301C); + b43_phy_write(dev, 0x0026, 0x0000); + b43_phy_write(dev, 0x0030, 0x00C6); + b43_phy_write(dev, 0x0088, 0x3E00); + val = 0x3C3D; + for (offset = 0x0089; offset < 0x00A7; offset++) { + b43_phy_write(dev, offset, val); + val -= 0x0202; + } + b43_phy_write(dev, 0x03E4, 0x3000); + if (phy->channel == 0xFF) + b43_radio_selectchannel(dev, B43_DEFAULT_CHANNEL_BG, 0); + else + b43_radio_selectchannel(dev, phy->channel, 0); + if (phy->radio_ver != 0x2050) { + b43_radio_write16(dev, 0x0075, 0x0080); + b43_radio_write16(dev, 0x0079, 0x0081); + } + b43_radio_write16(dev, 0x0050, 0x0020); + b43_radio_write16(dev, 0x0050, 0x0023); + if (phy->radio_ver == 0x2050) { + b43_radio_write16(dev, 0x0050, 0x0020); + b43_radio_write16(dev, 0x005A, 0x0070); + b43_radio_write16(dev, 0x005B, 0x007B); + b43_radio_write16(dev, 0x005C, 0x00B0); + b43_radio_write16(dev, 0x007A, 0x000F); + b43_phy_write(dev, 0x0038, 0x0677); + b43_radio_init2050(dev); + } + b43_phy_write(dev, 0x0014, 0x0080); + b43_phy_write(dev, 0x0032, 0x00CA); + b43_phy_write(dev, 0x0032, 0x00CC); + b43_phy_write(dev, 0x0035, 0x07C2); + b43_lo_b_measure(dev); + b43_phy_write(dev, 0x0026, 0xCC00); + if (phy->radio_ver != 0x2050) + b43_phy_write(dev, 0x0026, 0xCE00); + b43_write16(dev, B43_MMIO_CHANNEL_EXT, 0x1000); + b43_phy_write(dev, 0x002A, 0x88A3); + if (phy->radio_ver != 0x2050) + b43_phy_write(dev, 0x002A, 0x88C2); + b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control); + b43_phy_init_pctl(dev); +} + +static void b43_phy_initb4(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + u16 offset, val; + + b43_write16(dev, 0x03EC, 0x3F22); + b43_phy_write(dev, 0x0020, 0x301C); + b43_phy_write(dev, 0x0026, 0x0000); + b43_phy_write(dev, 0x0030, 0x00C6); + b43_phy_write(dev, 0x0088, 0x3E00); + val = 0x3C3D; + for (offset = 0x0089; offset < 0x00A7; offset++) { + b43_phy_write(dev, offset, val); + val -= 0x0202; + } + b43_phy_write(dev, 0x03E4, 0x3000); + if (phy->channel == 0xFF) + b43_radio_selectchannel(dev, B43_DEFAULT_CHANNEL_BG, 0); + else + b43_radio_selectchannel(dev, phy->channel, 0); + if (phy->radio_ver != 0x2050) { + b43_radio_write16(dev, 0x0075, 0x0080); + b43_radio_write16(dev, 0x0079, 0x0081); + } + b43_radio_write16(dev, 0x0050, 0x0020); + b43_radio_write16(dev, 0x0050, 0x0023); + if (phy->radio_ver == 0x2050) { + b43_radio_write16(dev, 0x0050, 0x0020); + b43_radio_write16(dev, 0x005A, 0x0070); + b43_radio_write16(dev, 0x005B, 0x007B); + b43_radio_write16(dev, 0x005C, 0x00B0); + b43_radio_write16(dev, 0x007A, 0x000F); + b43_phy_write(dev, 0x0038, 0x0677); + b43_radio_init2050(dev); + } + b43_phy_write(dev, 0x0014, 0x0080); + b43_phy_write(dev, 0x0032, 0x00CA); + if (phy->radio_ver == 0x2050) + b43_phy_write(dev, 0x0032, 0x00E0); + b43_phy_write(dev, 0x0035, 0x07C2); + + b43_lo_b_measure(dev); + + b43_phy_write(dev, 0x0026, 0xCC00); + if (phy->radio_ver == 0x2050) + b43_phy_write(dev, 0x0026, 0xCE00); + b43_write16(dev, B43_MMIO_CHANNEL_EXT, 0x1100); + b43_phy_write(dev, 0x002A, 0x88A3); + if (phy->radio_ver == 0x2050) + b43_phy_write(dev, 0x002A, 0x88C2); + b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control); + if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI) { + b43_calc_nrssi_slope(dev); + b43_calc_nrssi_threshold(dev); + } + b43_phy_init_pctl(dev); +} + +static void b43_phy_initb5(struct b43_wldev *dev) +{ + struct ssb_bus *bus = dev->dev->bus; + struct b43_phy *phy = &dev->phy; + u16 offset, value; + u8 old_channel; + + if (phy->analog == 1) { + b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) + | 0x0050); + } + if ((bus->boardinfo.vendor != SSB_BOARDVENDOR_BCM) && + (bus->boardinfo.type != SSB_BOARD_BU4306)) { + value = 0x2120; + for (offset = 0x00A8; offset < 0x00C7; offset++) { + b43_phy_write(dev, offset, value); + value += 0x202; + } + } + b43_phy_write(dev, 0x0035, (b43_phy_read(dev, 0x0035) & 0xF0FF) + | 0x0700); + if (phy->radio_ver == 0x2050) + b43_phy_write(dev, 0x0038, 0x0667); + + if (phy->gmode || phy->rev >= 2) { + if (phy->radio_ver == 0x2050) { + b43_radio_write16(dev, 0x007A, + b43_radio_read16(dev, 0x007A) + | 0x0020); + b43_radio_write16(dev, 0x0051, + b43_radio_read16(dev, 0x0051) + | 0x0004); + } + b43_write16(dev, B43_MMIO_PHY_RADIO, 0x0000); + + b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x0100); + b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x2000); + + b43_phy_write(dev, 0x001C, 0x186A); + + b43_phy_write(dev, 0x0013, + (b43_phy_read(dev, 0x0013) & 0x00FF) | 0x1900); + b43_phy_write(dev, 0x0035, + (b43_phy_read(dev, 0x0035) & 0xFFC0) | 0x0064); + b43_phy_write(dev, 0x005D, + (b43_phy_read(dev, 0x005D) & 0xFF80) | 0x000A); + } + + if (dev->bad_frames_preempt) { + b43_phy_write(dev, B43_PHY_RADIO_BITFIELD, + b43_phy_read(dev, + B43_PHY_RADIO_BITFIELD) | (1 << 11)); + } + + if (phy->analog == 1) { + b43_phy_write(dev, 0x0026, 0xCE00); + b43_phy_write(dev, 0x0021, 0x3763); + b43_phy_write(dev, 0x0022, 0x1BC3); + b43_phy_write(dev, 0x0023, 0x06F9); + b43_phy_write(dev, 0x0024, 0x037E); + } else + b43_phy_write(dev, 0x0026, 0xCC00); + b43_phy_write(dev, 0x0030, 0x00C6); + b43_write16(dev, 0x03EC, 0x3F22); + + if (phy->analog == 1) + b43_phy_write(dev, 0x0020, 0x3E1C); + else + b43_phy_write(dev, 0x0020, 0x301C); + + if (phy->analog == 0) + b43_write16(dev, 0x03E4, 0x3000); + + old_channel = phy->channel; + /* Force to channel 7, even if not supported. */ + b43_radio_selectchannel(dev, 7, 0); + + if (phy->radio_ver != 0x2050) { + b43_radio_write16(dev, 0x0075, 0x0080); + b43_radio_write16(dev, 0x0079, 0x0081); + } + + b43_radio_write16(dev, 0x0050, 0x0020); + b43_radio_write16(dev, 0x0050, 0x0023); + + if (phy->radio_ver == 0x2050) { + b43_radio_write16(dev, 0x0050, 0x0020); + b43_radio_write16(dev, 0x005A, 0x0070); + } + + b43_radio_write16(dev, 0x005B, 0x007B); + b43_radio_write16(dev, 0x005C, 0x00B0); + + b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) | 0x0007); + + b43_radio_selectchannel(dev, old_channel, 0); + + b43_phy_write(dev, 0x0014, 0x0080); + b43_phy_write(dev, 0x0032, 0x00CA); + b43_phy_write(dev, 0x002A, 0x88A3); + + b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control); + + if (phy->radio_ver == 0x2050) + b43_radio_write16(dev, 0x005D, 0x000D); + + b43_write16(dev, 0x03E4, (b43_read16(dev, 0x03E4) & 0xFFC0) | 0x0004); +} + +static void b43_phy_initb6(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + u16 offset, val; + u8 old_channel; + + b43_phy_write(dev, 0x003E, 0x817A); + b43_radio_write16(dev, 0x007A, + (b43_radio_read16(dev, 0x007A) | 0x0058)); + if (phy->radio_rev == 4 || phy->radio_rev == 5) { + b43_radio_write16(dev, 0x51, 0x37); + b43_radio_write16(dev, 0x52, 0x70); + b43_radio_write16(dev, 0x53, 0xB3); + b43_radio_write16(dev, 0x54, 0x9B); + b43_radio_write16(dev, 0x5A, 0x88); + b43_radio_write16(dev, 0x5B, 0x88); + b43_radio_write16(dev, 0x5D, 0x88); + b43_radio_write16(dev, 0x5E, 0x88); + b43_radio_write16(dev, 0x7D, 0x88); + b43_hf_write(dev, b43_hf_read(dev) + | B43_HF_TSSIRPSMW); + } + B43_WARN_ON(phy->radio_rev == 6 || phy->radio_rev == 7); /* We had code for these revs here... */ + if (phy->radio_rev == 8) { + b43_radio_write16(dev, 0x51, 0); + b43_radio_write16(dev, 0x52, 0x40); + b43_radio_write16(dev, 0x53, 0xB7); + b43_radio_write16(dev, 0x54, 0x98); + b43_radio_write16(dev, 0x5A, 0x88); + b43_radio_write16(dev, 0x5B, 0x6B); + b43_radio_write16(dev, 0x5C, 0x0F); + if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_ALTIQ) { + b43_radio_write16(dev, 0x5D, 0xFA); + b43_radio_write16(dev, 0x5E, 0xD8); + } else { + b43_radio_write16(dev, 0x5D, 0xF5); + b43_radio_write16(dev, 0x5E, 0xB8); + } + b43_radio_write16(dev, 0x0073, 0x0003); + b43_radio_write16(dev, 0x007D, 0x00A8); + b43_radio_write16(dev, 0x007C, 0x0001); + b43_radio_write16(dev, 0x007E, 0x0008); + } + val = 0x1E1F; + for (offset = 0x0088; offset < 0x0098; offset++) { + b43_phy_write(dev, offset, val); + val -= 0x0202; + } + val = 0x3E3F; + for (offset = 0x0098; offset < 0x00A8; offset++) { + b43_phy_write(dev, offset, val); + val -= 0x0202; + } + val = 0x2120; + for (offset = 0x00A8; offset < 0x00C8; offset++) { + b43_phy_write(dev, offset, (val & 0x3F3F)); + val += 0x0202; + } + if (phy->type == B43_PHYTYPE_G) { + b43_radio_write16(dev, 0x007A, + b43_radio_read16(dev, 0x007A) | 0x0020); + b43_radio_write16(dev, 0x0051, + b43_radio_read16(dev, 0x0051) | 0x0004); + b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x0100); + b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x2000); + b43_phy_write(dev, 0x5B, 0); + b43_phy_write(dev, 0x5C, 0); + } + + old_channel = phy->channel; + if (old_channel >= 8) + b43_radio_selectchannel(dev, 1, 0); + else + b43_radio_selectchannel(dev, 13, 0); + + b43_radio_write16(dev, 0x0050, 0x0020); + b43_radio_write16(dev, 0x0050, 0x0023); + udelay(40); + if (phy->radio_rev < 6 || phy->radio_rev == 8) { + b43_radio_write16(dev, 0x7C, (b43_radio_read16(dev, 0x7C) + | 0x0002)); + b43_radio_write16(dev, 0x50, 0x20); + } + if (phy->radio_rev <= 2) { + b43_radio_write16(dev, 0x7C, 0x20); + b43_radio_write16(dev, 0x5A, 0x70); + b43_radio_write16(dev, 0x5B, 0x7B); + b43_radio_write16(dev, 0x5C, 0xB0); + } + b43_radio_write16(dev, 0x007A, + (b43_radio_read16(dev, 0x007A) & 0x00F8) | 0x0007); + + b43_radio_selectchannel(dev, old_channel, 0); + + b43_phy_write(dev, 0x0014, 0x0200); + if (phy->radio_rev >= 6) + b43_phy_write(dev, 0x2A, 0x88C2); + else + b43_phy_write(dev, 0x2A, 0x8AC0); + b43_phy_write(dev, 0x0038, 0x0668); + b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control); + if (phy->radio_rev <= 5) { + b43_phy_write(dev, 0x5D, (b43_phy_read(dev, 0x5D) + & 0xFF80) | 0x0003); + } + if (phy->radio_rev <= 2) + b43_radio_write16(dev, 0x005D, 0x000D); + + if (phy->analog == 4) { + b43_write16(dev, 0x3E4, 9); + b43_phy_write(dev, 0x61, b43_phy_read(dev, 0x61) + & 0x0FFF); + } else { + b43_phy_write(dev, 0x0002, (b43_phy_read(dev, 0x0002) & 0xFFC0) + | 0x0004); + } + if (phy->type == B43_PHYTYPE_B) { + b43_write16(dev, 0x03E6, 0x8140); + b43_phy_write(dev, 0x0016, 0x0410); + b43_phy_write(dev, 0x0017, 0x0820); + b43_phy_write(dev, 0x0062, 0x0007); + b43_radio_init2050(dev); + b43_lo_g_measure(dev); + if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI) { + b43_calc_nrssi_slope(dev); + b43_calc_nrssi_threshold(dev); + } + b43_phy_init_pctl(dev); + } else if (phy->type == B43_PHYTYPE_G) + b43_write16(dev, 0x03E6, 0x0); +} + +static void b43_calc_loopback_gain(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + u16 backup_phy[16] = { 0 }; + u16 backup_radio[3]; + u16 backup_bband; + u16 i, j, loop_i_max; + u16 trsw_rx; + u16 loop1_outer_done, loop1_inner_done; + + backup_phy[0] = b43_phy_read(dev, B43_PHY_CRS0); + backup_phy[1] = b43_phy_read(dev, B43_PHY_CCKBBANDCFG); + backup_phy[2] = b43_phy_read(dev, B43_PHY_RFOVER); + backup_phy[3] = b43_phy_read(dev, B43_PHY_RFOVERVAL); + if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ + backup_phy[4] = b43_phy_read(dev, B43_PHY_ANALOGOVER); + backup_phy[5] = b43_phy_read(dev, B43_PHY_ANALOGOVERVAL); + } + backup_phy[6] = b43_phy_read(dev, B43_PHY_BASE(0x5A)); + backup_phy[7] = b43_phy_read(dev, B43_PHY_BASE(0x59)); + backup_phy[8] = b43_phy_read(dev, B43_PHY_BASE(0x58)); + backup_phy[9] = b43_phy_read(dev, B43_PHY_BASE(0x0A)); + backup_phy[10] = b43_phy_read(dev, B43_PHY_BASE(0x03)); + backup_phy[11] = b43_phy_read(dev, B43_PHY_LO_MASK); + backup_phy[12] = b43_phy_read(dev, B43_PHY_LO_CTL); + backup_phy[13] = b43_phy_read(dev, B43_PHY_BASE(0x2B)); + backup_phy[14] = b43_phy_read(dev, B43_PHY_PGACTL); + backup_phy[15] = b43_phy_read(dev, B43_PHY_LO_LEAKAGE); + backup_bband = phy->bbatt.att; + backup_radio[0] = b43_radio_read16(dev, 0x52); + backup_radio[1] = b43_radio_read16(dev, 0x43); + backup_radio[2] = b43_radio_read16(dev, 0x7A); + + b43_phy_write(dev, B43_PHY_CRS0, + b43_phy_read(dev, B43_PHY_CRS0) & 0x3FFF); + b43_phy_write(dev, B43_PHY_CCKBBANDCFG, + b43_phy_read(dev, B43_PHY_CCKBBANDCFG) | 0x8000); + b43_phy_write(dev, B43_PHY_RFOVER, + b43_phy_read(dev, B43_PHY_RFOVER) | 0x0002); + b43_phy_write(dev, B43_PHY_RFOVERVAL, + b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xFFFD); + b43_phy_write(dev, B43_PHY_RFOVER, + b43_phy_read(dev, B43_PHY_RFOVER) | 0x0001); + b43_phy_write(dev, B43_PHY_RFOVERVAL, + b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xFFFE); + if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ + b43_phy_write(dev, B43_PHY_ANALOGOVER, + b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0001); + b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, + b43_phy_read(dev, + B43_PHY_ANALOGOVERVAL) & 0xFFFE); + b43_phy_write(dev, B43_PHY_ANALOGOVER, + b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0002); + b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, + b43_phy_read(dev, + B43_PHY_ANALOGOVERVAL) & 0xFFFD); + } + b43_phy_write(dev, B43_PHY_RFOVER, + b43_phy_read(dev, B43_PHY_RFOVER) | 0x000C); + b43_phy_write(dev, B43_PHY_RFOVERVAL, + b43_phy_read(dev, B43_PHY_RFOVERVAL) | 0x000C); + b43_phy_write(dev, B43_PHY_RFOVER, + b43_phy_read(dev, B43_PHY_RFOVER) | 0x0030); + b43_phy_write(dev, B43_PHY_RFOVERVAL, + (b43_phy_read(dev, B43_PHY_RFOVERVAL) + & 0xFFCF) | 0x10); + + b43_phy_write(dev, B43_PHY_BASE(0x5A), 0x0780); + b43_phy_write(dev, B43_PHY_BASE(0x59), 0xC810); + b43_phy_write(dev, B43_PHY_BASE(0x58), 0x000D); + + b43_phy_write(dev, B43_PHY_BASE(0x0A), + b43_phy_read(dev, B43_PHY_BASE(0x0A)) | 0x2000); + if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ + b43_phy_write(dev, B43_PHY_ANALOGOVER, + b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0004); + b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, + b43_phy_read(dev, + B43_PHY_ANALOGOVERVAL) & 0xFFFB); + } + b43_phy_write(dev, B43_PHY_BASE(0x03), + (b43_phy_read(dev, B43_PHY_BASE(0x03)) + & 0xFF9F) | 0x40); + + if (phy->radio_rev == 8) { + b43_radio_write16(dev, 0x43, 0x000F); + } else { + b43_radio_write16(dev, 0x52, 0); + b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43) + & 0xFFF0) | 0x9); + } + b43_phy_set_baseband_attenuation(dev, 11); + + if (phy->rev >= 3) + b43_phy_write(dev, B43_PHY_LO_MASK, 0xC020); + else + b43_phy_write(dev, B43_PHY_LO_MASK, 0x8020); + b43_phy_write(dev, B43_PHY_LO_CTL, 0); + + b43_phy_write(dev, B43_PHY_BASE(0x2B), + (b43_phy_read(dev, B43_PHY_BASE(0x2B)) + & 0xFFC0) | 0x01); + b43_phy_write(dev, B43_PHY_BASE(0x2B), + (b43_phy_read(dev, B43_PHY_BASE(0x2B)) + & 0xC0FF) | 0x800); + + b43_phy_write(dev, B43_PHY_RFOVER, + b43_phy_read(dev, B43_PHY_RFOVER) | 0x0100); + b43_phy_write(dev, B43_PHY_RFOVERVAL, + b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xCFFF); + + if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_EXTLNA) { + if (phy->rev >= 7) { + b43_phy_write(dev, B43_PHY_RFOVER, + b43_phy_read(dev, B43_PHY_RFOVER) + | 0x0800); + b43_phy_write(dev, B43_PHY_RFOVERVAL, + b43_phy_read(dev, B43_PHY_RFOVERVAL) + | 0x8000); + } + } + b43_radio_write16(dev, 0x7A, b43_radio_read16(dev, 0x7A) + & 0x00F7); + + j = 0; + loop_i_max = (phy->radio_rev == 8) ? 15 : 9; + for (i = 0; i < loop_i_max; i++) { + for (j = 0; j < 16; j++) { + b43_radio_write16(dev, 0x43, i); + b43_phy_write(dev, B43_PHY_RFOVERVAL, + (b43_phy_read(dev, B43_PHY_RFOVERVAL) + & 0xF0FF) | (j << 8)); + b43_phy_write(dev, B43_PHY_PGACTL, + (b43_phy_read(dev, B43_PHY_PGACTL) + & 0x0FFF) | 0xA000); + b43_phy_write(dev, B43_PHY_PGACTL, + b43_phy_read(dev, B43_PHY_PGACTL) + | 0xF000); + udelay(20); + if (b43_phy_read(dev, B43_PHY_LO_LEAKAGE) >= 0xDFC) + goto exit_loop1; + } + } + exit_loop1: + loop1_outer_done = i; + loop1_inner_done = j; + if (j >= 8) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + b43_phy_read(dev, B43_PHY_RFOVERVAL) + | 0x30); + trsw_rx = 0x1B; + for (j = j - 8; j < 16; j++) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + (b43_phy_read(dev, B43_PHY_RFOVERVAL) + & 0xF0FF) | (j << 8)); + b43_phy_write(dev, B43_PHY_PGACTL, + (b43_phy_read(dev, B43_PHY_PGACTL) + & 0x0FFF) | 0xA000); + b43_phy_write(dev, B43_PHY_PGACTL, + b43_phy_read(dev, B43_PHY_PGACTL) + | 0xF000); + udelay(20); + trsw_rx -= 3; + if (b43_phy_read(dev, B43_PHY_LO_LEAKAGE) >= 0xDFC) + goto exit_loop2; + } + } else + trsw_rx = 0x18; + exit_loop2: + + if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ + b43_phy_write(dev, B43_PHY_ANALOGOVER, backup_phy[4]); + b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, backup_phy[5]); + } + b43_phy_write(dev, B43_PHY_BASE(0x5A), backup_phy[6]); + b43_phy_write(dev, B43_PHY_BASE(0x59), backup_phy[7]); + b43_phy_write(dev, B43_PHY_BASE(0x58), backup_phy[8]); + b43_phy_write(dev, B43_PHY_BASE(0x0A), backup_phy[9]); + b43_phy_write(dev, B43_PHY_BASE(0x03), backup_phy[10]); + b43_phy_write(dev, B43_PHY_LO_MASK, backup_phy[11]); + b43_phy_write(dev, B43_PHY_LO_CTL, backup_phy[12]); + b43_phy_write(dev, B43_PHY_BASE(0x2B), backup_phy[13]); + b43_phy_write(dev, B43_PHY_PGACTL, backup_phy[14]); + + b43_phy_set_baseband_attenuation(dev, backup_bband); + + b43_radio_write16(dev, 0x52, backup_radio[0]); + b43_radio_write16(dev, 0x43, backup_radio[1]); + b43_radio_write16(dev, 0x7A, backup_radio[2]); + + b43_phy_write(dev, B43_PHY_RFOVER, backup_phy[2] | 0x0003); + udelay(10); + b43_phy_write(dev, B43_PHY_RFOVER, backup_phy[2]); + b43_phy_write(dev, B43_PHY_RFOVERVAL, backup_phy[3]); + b43_phy_write(dev, B43_PHY_CRS0, backup_phy[0]); + b43_phy_write(dev, B43_PHY_CCKBBANDCFG, backup_phy[1]); + + phy->max_lb_gain = + ((loop1_inner_done * 6) - (loop1_outer_done * 4)) - 11; + phy->trsw_rx_gain = trsw_rx * 2; +} + +static void b43_phy_initg(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + u16 tmp; + + if (phy->rev == 1) + b43_phy_initb5(dev); + else + b43_phy_initb6(dev); + + if (phy->rev >= 2 || phy->gmode) + b43_phy_inita(dev); + + if (phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_ANALOGOVER, 0); + b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, 0); + } + if (phy->rev == 2) { + b43_phy_write(dev, B43_PHY_RFOVER, 0); + b43_phy_write(dev, B43_PHY_PGACTL, 0xC0); + } + if (phy->rev > 5) { + b43_phy_write(dev, B43_PHY_RFOVER, 0x400); + b43_phy_write(dev, B43_PHY_PGACTL, 0xC0); + } + if (phy->gmode || phy->rev >= 2) { + tmp = b43_phy_read(dev, B43_PHY_VERSION_OFDM); + tmp &= B43_PHYVER_VERSION; + if (tmp == 3 || tmp == 5) { + b43_phy_write(dev, B43_PHY_OFDM(0xC2), 0x1816); + b43_phy_write(dev, B43_PHY_OFDM(0xC3), 0x8006); + } + if (tmp == 5) { + b43_phy_write(dev, B43_PHY_OFDM(0xCC), + (b43_phy_read(dev, B43_PHY_OFDM(0xCC)) + & 0x00FF) | 0x1F00); + } + } + if ((phy->rev <= 2 && phy->gmode) || phy->rev >= 2) + b43_phy_write(dev, B43_PHY_OFDM(0x7E), 0x78); + if (phy->radio_rev == 8) { + b43_phy_write(dev, B43_PHY_EXTG(0x01), + b43_phy_read(dev, B43_PHY_EXTG(0x01)) + | 0x80); + b43_phy_write(dev, B43_PHY_OFDM(0x3E), + b43_phy_read(dev, B43_PHY_OFDM(0x3E)) + | 0x4); + } + if (has_loopback_gain(phy)) + b43_calc_loopback_gain(dev); + + if (phy->radio_rev != 8) { + if (phy->initval == 0xFFFF) + phy->initval = b43_radio_init2050(dev); + else + b43_radio_write16(dev, 0x0078, phy->initval); + } + if (phy->lo_control->tx_bias == 0xFF) { + b43_lo_g_measure(dev); + } else { + if (has_tx_magnification(phy)) { + b43_radio_write16(dev, 0x52, + (b43_radio_read16(dev, 0x52) & 0xFF00) + | phy->lo_control->tx_bias | phy-> + lo_control->tx_magn); + } else { + b43_radio_write16(dev, 0x52, + (b43_radio_read16(dev, 0x52) & 0xFFF0) + | phy->lo_control->tx_bias); + } + if (phy->rev >= 6) { + b43_phy_write(dev, B43_PHY_BASE(0x36), + (b43_phy_read(dev, B43_PHY_BASE(0x36)) + & 0x0FFF) | (phy->lo_control-> + tx_bias << 12)); + } + if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_PACTRL) + b43_phy_write(dev, B43_PHY_BASE(0x2E), 0x8075); + else + b43_phy_write(dev, B43_PHY_BASE(0x2E), 0x807F); + if (phy->rev < 2) + b43_phy_write(dev, B43_PHY_BASE(0x2F), 0x101); + else + b43_phy_write(dev, B43_PHY_BASE(0x2F), 0x202); + } + if (phy->gmode || phy->rev >= 2) { + b43_lo_g_adjust(dev); + b43_phy_write(dev, B43_PHY_LO_MASK, 0x8078); + } + + if (!(dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI)) { + /* The specs state to update the NRSSI LT with + * the value 0x7FFFFFFF here. I think that is some weird + * compiler optimization in the original driver. + * Essentially, what we do here is resetting all NRSSI LT + * entries to -32 (see the limit_value() in nrssi_hw_update()) + */ + b43_nrssi_hw_update(dev, 0xFFFF); //FIXME? + b43_calc_nrssi_threshold(dev); + } else if (phy->gmode || phy->rev >= 2) { + if (phy->nrssi[0] == -1000) { + B43_WARN_ON(phy->nrssi[1] != -1000); + b43_calc_nrssi_slope(dev); + } else + b43_calc_nrssi_threshold(dev); + } + if (phy->radio_rev == 8) + b43_phy_write(dev, B43_PHY_EXTG(0x05), 0x3230); + b43_phy_init_pctl(dev); + /* FIXME: The spec says in the following if, the 0 should be replaced + 'if OFDM may not be used in the current locale' + but OFDM is legal everywhere */ + if ((dev->dev->bus->chip_id == 0x4306 + && dev->dev->bus->chip_package == 2) || 0) { + b43_phy_write(dev, B43_PHY_CRS0, b43_phy_read(dev, B43_PHY_CRS0) + & 0xBFFF); + b43_phy_write(dev, B43_PHY_OFDM(0xC3), + b43_phy_read(dev, B43_PHY_OFDM(0xC3)) + & 0x7FFF); + } +} + +/* Set the baseband attenuation value on chip. */ +void b43_phy_set_baseband_attenuation(struct b43_wldev *dev, + u16 baseband_attenuation) +{ + struct b43_phy *phy = &dev->phy; + + if (phy->analog == 0) { + b43_write16(dev, B43_MMIO_PHY0, (b43_read16(dev, B43_MMIO_PHY0) + & 0xFFF0) | + baseband_attenuation); + } else if (phy->analog > 1) { + b43_phy_write(dev, B43_PHY_DACCTL, + (b43_phy_read(dev, B43_PHY_DACCTL) + & 0xFFC3) | (baseband_attenuation << 2)); + } else { + b43_phy_write(dev, B43_PHY_DACCTL, + (b43_phy_read(dev, B43_PHY_DACCTL) + & 0xFF87) | (baseband_attenuation << 3)); + } +} + +/* http://bcm-specs.sipsolutions.net/EstimatePowerOut + * This function converts a TSSI value to dBm in Q5.2 + */ +static s8 b43_phy_estimate_power_out(struct b43_wldev *dev, s8 tssi) +{ + struct b43_phy *phy = &dev->phy; + s8 dbm = 0; + s32 tmp; + + tmp = (phy->tgt_idle_tssi - phy->cur_idle_tssi + tssi); + + switch (phy->type) { + case B43_PHYTYPE_A: + tmp += 0x80; + tmp = limit_value(tmp, 0x00, 0xFF); + dbm = phy->tssi2dbm[tmp]; + //TODO: There's a FIXME on the specs + break; + case B43_PHYTYPE_B: + case B43_PHYTYPE_G: + tmp = limit_value(tmp, 0x00, 0x3F); + dbm = phy->tssi2dbm[tmp]; + break; + default: + B43_WARN_ON(1); + } + + return dbm; +} + +void b43_put_attenuation_into_ranges(struct b43_wldev *dev, + int *_bbatt, int *_rfatt) +{ + int rfatt = *_rfatt; + int bbatt = *_bbatt; + struct b43_txpower_lo_control *lo = dev->phy.lo_control; + + /* Get baseband and radio attenuation values into their permitted ranges. + * Radio attenuation affects power level 4 times as much as baseband. */ + + /* Range constants */ + const int rf_min = lo->rfatt_list.min_val; + const int rf_max = lo->rfatt_list.max_val; + const int bb_min = lo->bbatt_list.min_val; + const int bb_max = lo->bbatt_list.max_val; + + while (1) { + if (rfatt > rf_max && bbatt > bb_max - 4) + break; /* Can not get it into ranges */ + if (rfatt < rf_min && bbatt < bb_min + 4) + break; /* Can not get it into ranges */ + if (bbatt > bb_max && rfatt > rf_max - 1) + break; /* Can not get it into ranges */ + if (bbatt < bb_min && rfatt < rf_min + 1) + break; /* Can not get it into ranges */ + + if (bbatt > bb_max) { + bbatt -= 4; + rfatt += 1; + continue; + } + if (bbatt < bb_min) { + bbatt += 4; + rfatt -= 1; + continue; + } + if (rfatt > rf_max) { + rfatt -= 1; + bbatt += 4; + continue; + } + if (rfatt < rf_min) { + rfatt += 1; + bbatt -= 4; + continue; + } + break; + } + + *_rfatt = limit_value(rfatt, rf_min, rf_max); + *_bbatt = limit_value(bbatt, bb_min, bb_max); +} + +/* http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */ +void b43_phy_xmitpower(struct b43_wldev *dev) +{ + struct ssb_bus *bus = dev->dev->bus; + struct b43_phy *phy = &dev->phy; + + if (phy->cur_idle_tssi == 0) + return; + if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && + (bus->boardinfo.type == SSB_BOARD_BU4306)) + return; +#ifdef CONFIG_B43_DEBUG + if (phy->manual_txpower_control) + return; +#endif + + switch (phy->type) { + case B43_PHYTYPE_A:{ + + //TODO: Nothing for A PHYs yet :-/ + + break; + } + case B43_PHYTYPE_B: + case B43_PHYTYPE_G:{ + u16 tmp; + s8 v0, v1, v2, v3; + s8 average; + int max_pwr; + int desired_pwr, estimated_pwr, pwr_adjust; + int rfatt_delta, bbatt_delta; + int rfatt, bbatt; + u8 tx_control; + unsigned long phylock_flags; + + tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x0058); + v0 = (s8) (tmp & 0x00FF); + v1 = (s8) ((tmp & 0xFF00) >> 8); + tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x005A); + v2 = (s8) (tmp & 0x00FF); + v3 = (s8) ((tmp & 0xFF00) >> 8); + tmp = 0; + + if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F + || v3 == 0x7F) { + tmp = + b43_shm_read16(dev, B43_SHM_SHARED, 0x0070); + v0 = (s8) (tmp & 0x00FF); + v1 = (s8) ((tmp & 0xFF00) >> 8); + tmp = + b43_shm_read16(dev, B43_SHM_SHARED, 0x0072); + v2 = (s8) (tmp & 0x00FF); + v3 = (s8) ((tmp & 0xFF00) >> 8); + if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F + || v3 == 0x7F) + return; + v0 = (v0 + 0x20) & 0x3F; + v1 = (v1 + 0x20) & 0x3F; + v2 = (v2 + 0x20) & 0x3F; + v3 = (v3 + 0x20) & 0x3F; + tmp = 1; + } + b43_shm_clear_tssi(dev); + + average = (v0 + v1 + v2 + v3 + 2) / 4; + + if (tmp + && (b43_shm_read16(dev, B43_SHM_SHARED, 0x005E) & + 0x8)) + average -= 13; + + estimated_pwr = + b43_phy_estimate_power_out(dev, average); + + max_pwr = dev->dev->bus->sprom.r1.maxpwr_bg; + if ((dev->dev->bus->sprom.r1. + boardflags_lo & B43_BFL_PACTRL) + && (phy->type == B43_PHYTYPE_G)) + max_pwr -= 0x3; + if (unlikely(max_pwr <= 0)) { + b43warn(dev->wl, + "Invalid max-TX-power value in SPROM.\n"); + max_pwr = 60; /* fake it */ + dev->dev->bus->sprom.r1.maxpwr_bg = max_pwr; + } + + /*TODO: + max_pwr = min(REG - dev->dev->bus->sprom.antennagain_bgphy - 0x6, max_pwr) + where REG is the max power as per the regulatory domain + */ + + /* Get desired power (in Q5.2) */ + desired_pwr = INT_TO_Q52(phy->power_level); + /* And limit it. max_pwr already is Q5.2 */ + desired_pwr = limit_value(desired_pwr, 0, max_pwr); + if (b43_debug(dev, B43_DBG_XMITPOWER)) { + b43dbg(dev->wl, + "Current TX power output: " Q52_FMT + " dBm, " "Desired TX power output: " + Q52_FMT " dBm\n", Q52_ARG(estimated_pwr), + Q52_ARG(desired_pwr)); + } + + /* Calculate the adjustment delta. */ + pwr_adjust = desired_pwr - estimated_pwr; + + /* RF attenuation delta. */ + rfatt_delta = ((pwr_adjust + 7) / 8); + /* Lower attenuation => Bigger power output. Negate it. */ + rfatt_delta = -rfatt_delta; + + /* Baseband attenuation delta. */ + bbatt_delta = pwr_adjust / 2; + /* Lower attenuation => Bigger power output. Negate it. */ + bbatt_delta = -bbatt_delta; + /* RF att affects power level 4 times as much as + * Baseband attennuation. Subtract it. */ + bbatt_delta -= 4 * rfatt_delta; + + /* So do we finally need to adjust something? */ + if ((rfatt_delta == 0) && (bbatt_delta == 0)) { + b43_lo_g_ctl_mark_cur_used(dev); + return; + } + + /* Calculate the new attenuation values. */ + bbatt = phy->bbatt.att; + bbatt += bbatt_delta; + rfatt = phy->rfatt.att; + rfatt += rfatt_delta; + + b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt); + tx_control = phy->tx_control; + if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 2)) { + if (rfatt <= 1) { + if (tx_control == 0) { + tx_control = + B43_TXCTL_PA2DB | + B43_TXCTL_TXMIX; + rfatt += 2; + bbatt += 2; + } else if (dev->dev->bus->sprom.r1. + boardflags_lo & + B43_BFL_PACTRL) { + bbatt += 4 * (rfatt - 2); + rfatt = 2; + } + } else if (rfatt > 4 && tx_control) { + tx_control = 0; + if (bbatt < 3) { + rfatt -= 3; + bbatt += 2; + } else { + rfatt -= 2; + bbatt -= 2; + } + } + } + /* Save the control values */ + phy->tx_control = tx_control; + b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt); + phy->rfatt.att = rfatt; + phy->bbatt.att = bbatt; + + /* Adjust the hardware */ + b43_phy_lock(dev, phylock_flags); + b43_radio_lock(dev); + b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, + phy->tx_control); + b43_lo_g_ctl_mark_cur_used(dev); + b43_radio_unlock(dev); + b43_phy_unlock(dev, phylock_flags); + break; + } + default: + B43_WARN_ON(1); + } +} + +static inline s32 b43_tssi2dbm_ad(s32 num, s32 den) +{ + if (num < 0) + return num / den; + else + return (num + den / 2) / den; +} + +static inline + s8 b43_tssi2dbm_entry(s8 entry[], u8 index, s16 pab0, s16 pab1, s16 pab2) +{ + s32 m1, m2, f = 256, q, delta; + s8 i = 0; + + m1 = b43_tssi2dbm_ad(16 * pab0 + index * pab1, 32); + m2 = max(b43_tssi2dbm_ad(32768 + index * pab2, 256), 1); + do { + if (i > 15) + return -EINVAL; + q = b43_tssi2dbm_ad(f * 4096 - + b43_tssi2dbm_ad(m2 * f, 16) * f, 2048); + delta = abs(q - f); + f = q; + i++; + } while (delta >= 2); + entry[index] = limit_value(b43_tssi2dbm_ad(m1 * f, 8192), -127, 128); + return 0; +} + +/* http://bcm-specs.sipsolutions.net/TSSI_to_DBM_Table */ +int b43_phy_init_tssi2dbm_table(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + s16 pab0, pab1, pab2; + u8 idx; + s8 *dyn_tssi2dbm; + + if (phy->type == B43_PHYTYPE_A) { + pab0 = (s16) (dev->dev->bus->sprom.r1.pa1b0); + pab1 = (s16) (dev->dev->bus->sprom.r1.pa1b1); + pab2 = (s16) (dev->dev->bus->sprom.r1.pa1b2); + } else { + pab0 = (s16) (dev->dev->bus->sprom.r1.pa0b0); + pab1 = (s16) (dev->dev->bus->sprom.r1.pa0b1); + pab2 = (s16) (dev->dev->bus->sprom.r1.pa0b2); + } + + if ((dev->dev->bus->chip_id == 0x4301) && (phy->radio_ver != 0x2050)) { + phy->tgt_idle_tssi = 0x34; + phy->tssi2dbm = b43_tssi2dbm_b_table; + return 0; + } + + if (pab0 != 0 && pab1 != 0 && pab2 != 0 && + pab0 != -1 && pab1 != -1 && pab2 != -1) { + /* The pabX values are set in SPROM. Use them. */ + if (phy->type == B43_PHYTYPE_A) { + if ((s8) dev->dev->bus->sprom.r1.itssi_a != 0 && + (s8) dev->dev->bus->sprom.r1.itssi_a != -1) + phy->tgt_idle_tssi = + (s8) (dev->dev->bus->sprom.r1.itssi_a); + else + phy->tgt_idle_tssi = 62; + } else { + if ((s8) dev->dev->bus->sprom.r1.itssi_bg != 0 && + (s8) dev->dev->bus->sprom.r1.itssi_bg != -1) + phy->tgt_idle_tssi = + (s8) (dev->dev->bus->sprom.r1.itssi_bg); + else + phy->tgt_idle_tssi = 62; + } + dyn_tssi2dbm = kmalloc(64, GFP_KERNEL); + if (dyn_tssi2dbm == NULL) { + b43err(dev->wl, "Could not allocate memory" + "for tssi2dbm table\n"); + return -ENOMEM; + } + for (idx = 0; idx < 64; idx++) + if (b43_tssi2dbm_entry + (dyn_tssi2dbm, idx, pab0, pab1, pab2)) { + phy->tssi2dbm = NULL; + b43err(dev->wl, "Could not generate " + "tssi2dBm table\n"); + kfree(dyn_tssi2dbm); + return -ENODEV; + } + phy->tssi2dbm = dyn_tssi2dbm; + phy->dyn_tssi_tbl = 1; + } else { + /* pabX values not set in SPROM. */ + switch (phy->type) { + case B43_PHYTYPE_A: + /* APHY needs a generated table. */ + phy->tssi2dbm = NULL; + b43err(dev->wl, "Could not generate tssi2dBm " + "table (wrong SPROM info)!\n"); + return -ENODEV; + case B43_PHYTYPE_B: + phy->tgt_idle_tssi = 0x34; + phy->tssi2dbm = b43_tssi2dbm_b_table; + break; + case B43_PHYTYPE_G: + phy->tgt_idle_tssi = 0x34; + phy->tssi2dbm = b43_tssi2dbm_g_table; + break; + } + } + + return 0; +} + +int b43_phy_init(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + int err = -ENODEV; + + switch (phy->type) { + case B43_PHYTYPE_A: + if (phy->rev == 2 || phy->rev == 3) { + b43_phy_inita(dev); + err = 0; + } + break; + case B43_PHYTYPE_B: + switch (phy->rev) { + case 2: + b43_phy_initb2(dev); + err = 0; + break; + case 4: + b43_phy_initb4(dev); + err = 0; + break; + case 5: + b43_phy_initb5(dev); + err = 0; + break; + case 6: + b43_phy_initb6(dev); + err = 0; + break; + } + break; + case B43_PHYTYPE_G: + b43_phy_initg(dev); + err = 0; + break; + } + if (err) + b43err(dev->wl, "Unknown PHYTYPE found\n"); + + return err; +} + +void b43_set_rx_antenna(struct b43_wldev *dev, int antenna) +{ + struct b43_phy *phy = &dev->phy; + u32 hf; + u16 tmp; + int autodiv = 0; + + if (antenna == B43_ANTENNA_AUTO0 || antenna == B43_ANTENNA_AUTO1) + autodiv = 1; + + hf = b43_hf_read(dev); + hf &= ~B43_HF_ANTDIVHELP; + b43_hf_write(dev, hf); + + switch (phy->type) { + case B43_PHYTYPE_A: + case B43_PHYTYPE_G: + tmp = b43_phy_read(dev, B43_PHY_BBANDCFG); + tmp &= ~B43_PHY_BBANDCFG_RXANT; + tmp |= (autodiv ? B43_ANTENNA_AUTO0 : antenna) + << B43_PHY_BBANDCFG_RXANT_SHIFT; + b43_phy_write(dev, B43_PHY_BBANDCFG, tmp); + + if (autodiv) { + tmp = b43_phy_read(dev, B43_PHY_ANTDWELL); + if (antenna == B43_ANTENNA_AUTO0) + tmp &= ~B43_PHY_ANTDWELL_AUTODIV1; + else + tmp |= B43_PHY_ANTDWELL_AUTODIV1; + b43_phy_write(dev, B43_PHY_ANTDWELL, tmp); + } + if (phy->type == B43_PHYTYPE_G) { + tmp = b43_phy_read(dev, B43_PHY_ANTWRSETT); + if (autodiv) + tmp |= B43_PHY_ANTWRSETT_ARXDIV; + else + tmp &= ~B43_PHY_ANTWRSETT_ARXDIV; + b43_phy_write(dev, B43_PHY_ANTWRSETT, tmp); + if (phy->rev >= 2) { + tmp = b43_phy_read(dev, B43_PHY_OFDM61); + tmp |= B43_PHY_OFDM61_10; + b43_phy_write(dev, B43_PHY_OFDM61, tmp); + + tmp = + b43_phy_read(dev, B43_PHY_DIVSRCHGAINBACK); + tmp = (tmp & 0xFF00) | 0x15; + b43_phy_write(dev, B43_PHY_DIVSRCHGAINBACK, + tmp); + + if (phy->rev == 2) { + b43_phy_write(dev, B43_PHY_ADIVRELATED, + 8); + } else { + tmp = + b43_phy_read(dev, + B43_PHY_ADIVRELATED); + tmp = (tmp & 0xFF00) | 8; + b43_phy_write(dev, B43_PHY_ADIVRELATED, + tmp); + } + } + if (phy->rev >= 6) + b43_phy_write(dev, B43_PHY_OFDM9B, 0xDC); + } else { + if (phy->rev < 3) { + tmp = b43_phy_read(dev, B43_PHY_ANTDWELL); + tmp = (tmp & 0xFF00) | 0x24; + b43_phy_write(dev, B43_PHY_ANTDWELL, tmp); + } else { + tmp = b43_phy_read(dev, B43_PHY_OFDM61); + tmp |= 0x10; + b43_phy_write(dev, B43_PHY_OFDM61, tmp); + if (phy->analog == 3) { + b43_phy_write(dev, B43_PHY_CLIPPWRDOWNT, + 0x1D); + b43_phy_write(dev, B43_PHY_ADIVRELATED, + 8); + } else { + b43_phy_write(dev, B43_PHY_CLIPPWRDOWNT, + 0x3A); + tmp = + b43_phy_read(dev, + B43_PHY_ADIVRELATED); + tmp = (tmp & 0xFF00) | 8; + b43_phy_write(dev, B43_PHY_ADIVRELATED, + tmp); + } + } + } + break; + case B43_PHYTYPE_B: + tmp = b43_phy_read(dev, B43_PHY_CCKBBANDCFG); + tmp &= ~B43_PHY_BBANDCFG_RXANT; + tmp |= (autodiv ? B43_ANTENNA_AUTO0 : antenna) + << B43_PHY_BBANDCFG_RXANT_SHIFT; + b43_phy_write(dev, B43_PHY_CCKBBANDCFG, tmp); + break; + default: + B43_WARN_ON(1); + } + + hf |= B43_HF_ANTDIVHELP; + b43_hf_write(dev, hf); +} + +/* Get the freq, as it has to be written to the device. */ +static inline u16 channel2freq_bg(u8 channel) +{ + B43_WARN_ON(!(channel >= 1 && channel <= 14)); + + return b43_radio_channel_codes_bg[channel - 1]; +} + +/* Get the freq, as it has to be written to the device. */ +static inline u16 channel2freq_a(u8 channel) +{ + B43_WARN_ON(channel > 200); + + return (5000 + 5 * channel); +} + +void b43_radio_lock(struct b43_wldev *dev) +{ + u32 macctl; + + macctl = b43_read32(dev, B43_MMIO_MACCTL); + macctl |= B43_MACCTL_RADIOLOCK; + b43_write32(dev, B43_MMIO_MACCTL, macctl); + /* Commit the write and wait for the device + * to exit any radio register access. */ + b43_read32(dev, B43_MMIO_MACCTL); + udelay(10); +} + +void b43_radio_unlock(struct b43_wldev *dev) +{ + u32 macctl; + + /* Commit any write */ + b43_read16(dev, B43_MMIO_PHY_VER); + /* unlock */ + macctl = b43_read32(dev, B43_MMIO_MACCTL); + macctl &= ~B43_MACCTL_RADIOLOCK; + b43_write32(dev, B43_MMIO_MACCTL, macctl); +} + +u16 b43_radio_read16(struct b43_wldev *dev, u16 offset) +{ + struct b43_phy *phy = &dev->phy; + + switch (phy->type) { + case B43_PHYTYPE_A: + offset |= 0x0040; + break; + case B43_PHYTYPE_B: + if (phy->radio_ver == 0x2053) { + if (offset < 0x70) + offset += 0x80; + else if (offset < 0x80) + offset += 0x70; + } else if (phy->radio_ver == 0x2050) { + offset |= 0x80; + } else + B43_WARN_ON(1); + break; + case B43_PHYTYPE_G: + offset |= 0x80; + break; + } + + b43_write16(dev, B43_MMIO_RADIO_CONTROL, offset); + return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW); +} + +void b43_radio_write16(struct b43_wldev *dev, u16 offset, u16 val) +{ + b43_write16(dev, B43_MMIO_RADIO_CONTROL, offset); + mmiowb(); + b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, val); +} + +static void b43_set_all_gains(struct b43_wldev *dev, + s16 first, s16 second, s16 third) +{ + struct b43_phy *phy = &dev->phy; + u16 i; + u16 start = 0x08, end = 0x18; + u16 tmp; + u16 table; + + if (phy->rev <= 1) { + start = 0x10; + end = 0x20; + } + + table = B43_OFDMTAB_GAINX; + if (phy->rev <= 1) + table = B43_OFDMTAB_GAINX_R1; + for (i = 0; i < 4; i++) + b43_ofdmtab_write16(dev, table, i, first); + + for (i = start; i < end; i++) + b43_ofdmtab_write16(dev, table, i, second); + + if (third != -1) { + tmp = ((u16) third << 14) | ((u16) third << 6); + b43_phy_write(dev, 0x04A0, + (b43_phy_read(dev, 0x04A0) & 0xBFBF) | tmp); + b43_phy_write(dev, 0x04A1, + (b43_phy_read(dev, 0x04A1) & 0xBFBF) | tmp); + b43_phy_write(dev, 0x04A2, + (b43_phy_read(dev, 0x04A2) & 0xBFBF) | tmp); + } + b43_dummy_transmission(dev); +} + +static void b43_set_original_gains(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + u16 i, tmp; + u16 table; + u16 start = 0x0008, end = 0x0018; + + if (phy->rev <= 1) { + start = 0x0010; + end = 0x0020; + } + + table = B43_OFDMTAB_GAINX; + if (phy->rev <= 1) + table = B43_OFDMTAB_GAINX_R1; + for (i = 0; i < 4; i++) { + tmp = (i & 0xFFFC); + tmp |= (i & 0x0001) << 1; + tmp |= (i & 0x0002) >> 1; + + b43_ofdmtab_write16(dev, table, i, tmp); + } + + for (i = start; i < end; i++) + b43_ofdmtab_write16(dev, table, i, i - start); + + b43_phy_write(dev, 0x04A0, + (b43_phy_read(dev, 0x04A0) & 0xBFBF) | 0x4040); + b43_phy_write(dev, 0x04A1, + (b43_phy_read(dev, 0x04A1) & 0xBFBF) | 0x4040); + b43_phy_write(dev, 0x04A2, + (b43_phy_read(dev, 0x04A2) & 0xBFBF) | 0x4000); + b43_dummy_transmission(dev); +} + +/* Synthetic PU workaround */ +static void b43_synth_pu_workaround(struct b43_wldev *dev, u8 channel) +{ + struct b43_phy *phy = &dev->phy; + + might_sleep(); + + if (phy->radio_ver != 0x2050 || phy->radio_rev >= 6) { + /* We do not need the workaround. */ + return; + } + + if (channel <= 10) { + b43_write16(dev, B43_MMIO_CHANNEL, + channel2freq_bg(channel + 4)); + } else { + b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(1)); + } + msleep(1); + b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(channel)); +} + +u8 b43_radio_aci_detect(struct b43_wldev *dev, u8 channel) +{ + struct b43_phy *phy = &dev->phy; + u8 ret = 0; + u16 saved, rssi, temp; + int i, j = 0; + + saved = b43_phy_read(dev, 0x0403); + b43_radio_selectchannel(dev, channel, 0); + b43_phy_write(dev, 0x0403, (saved & 0xFFF8) | 5); + if (phy->aci_hw_rssi) + rssi = b43_phy_read(dev, 0x048A) & 0x3F; + else + rssi = saved & 0x3F; + /* clamp temp to signed 5bit */ + if (rssi > 32) + rssi -= 64; + for (i = 0; i < 100; i++) { + temp = (b43_phy_read(dev, 0x047F) >> 8) & 0x3F; + if (temp > 32) + temp -= 64; + if (temp < rssi) + j++; + if (j >= 20) + ret = 1; + } + b43_phy_write(dev, 0x0403, saved); + + return ret; +} + +u8 b43_radio_aci_scan(struct b43_wldev * dev) +{ + struct b43_phy *phy = &dev->phy; + u8 ret[13]; + unsigned int channel = phy->channel; + unsigned int i, j, start, end; + unsigned long phylock_flags; + + if (!((phy->type == B43_PHYTYPE_G) && (phy->rev > 0))) + return 0; + + b43_phy_lock(dev, phylock_flags); + b43_radio_lock(dev); + b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & 0xFFFC); + b43_phy_write(dev, B43_PHY_G_CRS, + b43_phy_read(dev, B43_PHY_G_CRS) & 0x7FFF); + b43_set_all_gains(dev, 3, 8, 1); + + start = (channel - 5 > 0) ? channel - 5 : 1; + end = (channel + 5 < 14) ? channel + 5 : 13; + + for (i = start; i <= end; i++) { + if (abs(channel - i) > 2) + ret[i - 1] = b43_radio_aci_detect(dev, i); + } + b43_radio_selectchannel(dev, channel, 0); + b43_phy_write(dev, 0x0802, + (b43_phy_read(dev, 0x0802) & 0xFFFC) | 0x0003); + b43_phy_write(dev, 0x0403, b43_phy_read(dev, 0x0403) & 0xFFF8); + b43_phy_write(dev, B43_PHY_G_CRS, + b43_phy_read(dev, B43_PHY_G_CRS) | 0x8000); + b43_set_original_gains(dev); + for (i = 0; i < 13; i++) { + if (!ret[i]) + continue; + end = (i + 5 < 13) ? i + 5 : 13; + for (j = i; j < end; j++) + ret[j] = 1; + } + b43_radio_unlock(dev); + b43_phy_unlock(dev, phylock_flags); + + return ret[channel - 1]; +} + +/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +void b43_nrssi_hw_write(struct b43_wldev *dev, u16 offset, s16 val) +{ + b43_phy_write(dev, B43_PHY_NRSSILT_CTRL, offset); + mmiowb(); + b43_phy_write(dev, B43_PHY_NRSSILT_DATA, (u16) val); +} + +/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +s16 b43_nrssi_hw_read(struct b43_wldev *dev, u16 offset) +{ + u16 val; + + b43_phy_write(dev, B43_PHY_NRSSILT_CTRL, offset); + val = b43_phy_read(dev, B43_PHY_NRSSILT_DATA); + + return (s16) val; +} + +/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val) +{ + u16 i; + s16 tmp; + + for (i = 0; i < 64; i++) { + tmp = b43_nrssi_hw_read(dev, i); + tmp -= val; + tmp = limit_value(tmp, -32, 31); + b43_nrssi_hw_write(dev, i, tmp); + } +} + +/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +void b43_nrssi_mem_update(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + s16 i, delta; + s32 tmp; + + delta = 0x1F - phy->nrssi[0]; + for (i = 0; i < 64; i++) { + tmp = (i - delta) * phy->nrssislope; + tmp /= 0x10000; + tmp += 0x3A; + tmp = limit_value(tmp, 0, 0x3F); + phy->nrssi_lt[i] = tmp; + } +} + +static void b43_calc_nrssi_offset(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + u16 backup[20] = { 0 }; + s16 v47F; + u16 i; + u16 saved = 0xFFFF; + + backup[0] = b43_phy_read(dev, 0x0001); + backup[1] = b43_phy_read(dev, 0x0811); + backup[2] = b43_phy_read(dev, 0x0812); + if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ + backup[3] = b43_phy_read(dev, 0x0814); + backup[4] = b43_phy_read(dev, 0x0815); + } + backup[5] = b43_phy_read(dev, 0x005A); + backup[6] = b43_phy_read(dev, 0x0059); + backup[7] = b43_phy_read(dev, 0x0058); + backup[8] = b43_phy_read(dev, 0x000A); + backup[9] = b43_phy_read(dev, 0x0003); + backup[10] = b43_radio_read16(dev, 0x007A); + backup[11] = b43_radio_read16(dev, 0x0043); + + b43_phy_write(dev, 0x0429, b43_phy_read(dev, 0x0429) & 0x7FFF); + b43_phy_write(dev, 0x0001, + (b43_phy_read(dev, 0x0001) & 0x3FFF) | 0x4000); + b43_phy_write(dev, 0x0811, b43_phy_read(dev, 0x0811) | 0x000C); + b43_phy_write(dev, 0x0812, + (b43_phy_read(dev, 0x0812) & 0xFFF3) | 0x0004); + b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & ~(0x1 | 0x2)); + if (phy->rev >= 6) { + backup[12] = b43_phy_read(dev, 0x002E); + backup[13] = b43_phy_read(dev, 0x002F); + backup[14] = b43_phy_read(dev, 0x080F); + backup[15] = b43_phy_read(dev, 0x0810); + backup[16] = b43_phy_read(dev, 0x0801); + backup[17] = b43_phy_read(dev, 0x0060); + backup[18] = b43_phy_read(dev, 0x0014); + backup[19] = b43_phy_read(dev, 0x0478); + + b43_phy_write(dev, 0x002E, 0); + b43_phy_write(dev, 0x002F, 0); + b43_phy_write(dev, 0x080F, 0); + b43_phy_write(dev, 0x0810, 0); + b43_phy_write(dev, 0x0478, b43_phy_read(dev, 0x0478) | 0x0100); + b43_phy_write(dev, 0x0801, b43_phy_read(dev, 0x0801) | 0x0040); + b43_phy_write(dev, 0x0060, b43_phy_read(dev, 0x0060) | 0x0040); + b43_phy_write(dev, 0x0014, b43_phy_read(dev, 0x0014) | 0x0200); + } + b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) | 0x0070); + b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) | 0x0080); + udelay(30); + + v47F = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F); + if (v47F >= 0x20) + v47F -= 0x40; + if (v47F == 31) { + for (i = 7; i >= 4; i--) { + b43_radio_write16(dev, 0x007B, i); + udelay(20); + v47F = + (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F); + if (v47F >= 0x20) + v47F -= 0x40; + if (v47F < 31 && saved == 0xFFFF) + saved = i; + } + if (saved == 0xFFFF) + saved = 4; + } else { + b43_radio_write16(dev, 0x007A, + b43_radio_read16(dev, 0x007A) & 0x007F); + if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ + b43_phy_write(dev, 0x0814, + b43_phy_read(dev, 0x0814) | 0x0001); + b43_phy_write(dev, 0x0815, + b43_phy_read(dev, 0x0815) & 0xFFFE); + } + b43_phy_write(dev, 0x0811, b43_phy_read(dev, 0x0811) | 0x000C); + b43_phy_write(dev, 0x0812, b43_phy_read(dev, 0x0812) | 0x000C); + b43_phy_write(dev, 0x0811, b43_phy_read(dev, 0x0811) | 0x0030); + b43_phy_write(dev, 0x0812, b43_phy_read(dev, 0x0812) | 0x0030); + b43_phy_write(dev, 0x005A, 0x0480); + b43_phy_write(dev, 0x0059, 0x0810); + b43_phy_write(dev, 0x0058, 0x000D); + if (phy->rev == 0) { + b43_phy_write(dev, 0x0003, 0x0122); + } else { + b43_phy_write(dev, 0x000A, b43_phy_read(dev, 0x000A) + | 0x2000); + } + if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ + b43_phy_write(dev, 0x0814, + b43_phy_read(dev, 0x0814) | 0x0004); + b43_phy_write(dev, 0x0815, + b43_phy_read(dev, 0x0815) & 0xFFFB); + } + b43_phy_write(dev, 0x0003, (b43_phy_read(dev, 0x0003) & 0xFF9F) + | 0x0040); + b43_radio_write16(dev, 0x007A, + b43_radio_read16(dev, 0x007A) | 0x000F); + b43_set_all_gains(dev, 3, 0, 1); + b43_radio_write16(dev, 0x0043, (b43_radio_read16(dev, 0x0043) + & 0x00F0) | 0x000F); + udelay(30); + v47F = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F); + if (v47F >= 0x20) + v47F -= 0x40; + if (v47F == -32) { + for (i = 0; i < 4; i++) { + b43_radio_write16(dev, 0x007B, i); + udelay(20); + v47F = + (s16) ((b43_phy_read(dev, 0x047F) >> 8) & + 0x003F); + if (v47F >= 0x20) + v47F -= 0x40; + if (v47F > -31 && saved == 0xFFFF) + saved = i; + } + if (saved == 0xFFFF) + saved = 3; + } else + saved = 0; + } + b43_radio_write16(dev, 0x007B, saved); + + if (phy->rev >= 6) { + b43_phy_write(dev, 0x002E, backup[12]); + b43_phy_write(dev, 0x002F, backup[13]); + b43_phy_write(dev, 0x080F, backup[14]); + b43_phy_write(dev, 0x0810, backup[15]); + } + if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ + b43_phy_write(dev, 0x0814, backup[3]); + b43_phy_write(dev, 0x0815, backup[4]); + } + b43_phy_write(dev, 0x005A, backup[5]); + b43_phy_write(dev, 0x0059, backup[6]); + b43_phy_write(dev, 0x0058, backup[7]); + b43_phy_write(dev, 0x000A, backup[8]); + b43_phy_write(dev, 0x0003, backup[9]); + b43_radio_write16(dev, 0x0043, backup[11]); + b43_radio_write16(dev, 0x007A, backup[10]); + b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x1 | 0x2); + b43_phy_write(dev, 0x0429, b43_phy_read(dev, 0x0429) | 0x8000); + b43_set_original_gains(dev); + if (phy->rev >= 6) { + b43_phy_write(dev, 0x0801, backup[16]); + b43_phy_write(dev, 0x0060, backup[17]); + b43_phy_write(dev, 0x0014, backup[18]); + b43_phy_write(dev, 0x0478, backup[19]); + } + b43_phy_write(dev, 0x0001, backup[0]); + b43_phy_write(dev, 0x0812, backup[2]); + b43_phy_write(dev, 0x0811, backup[1]); +} + +void b43_calc_nrssi_slope(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + u16 backup[18] = { 0 }; + u16 tmp; + s16 nrssi0, nrssi1; + + switch (phy->type) { + case B43_PHYTYPE_B: + backup[0] = b43_radio_read16(dev, 0x007A); + backup[1] = b43_radio_read16(dev, 0x0052); + backup[2] = b43_radio_read16(dev, 0x0043); + backup[3] = b43_phy_read(dev, 0x0030); + backup[4] = b43_phy_read(dev, 0x0026); + backup[5] = b43_phy_read(dev, 0x0015); + backup[6] = b43_phy_read(dev, 0x002A); + backup[7] = b43_phy_read(dev, 0x0020); + backup[8] = b43_phy_read(dev, 0x005A); + backup[9] = b43_phy_read(dev, 0x0059); + backup[10] = b43_phy_read(dev, 0x0058); + backup[11] = b43_read16(dev, 0x03E2); + backup[12] = b43_read16(dev, 0x03E6); + backup[13] = b43_read16(dev, B43_MMIO_CHANNEL_EXT); + + tmp = b43_radio_read16(dev, 0x007A); + tmp &= (phy->rev >= 5) ? 0x007F : 0x000F; + b43_radio_write16(dev, 0x007A, tmp); + b43_phy_write(dev, 0x0030, 0x00FF); + b43_write16(dev, 0x03EC, 0x7F7F); + b43_phy_write(dev, 0x0026, 0x0000); + b43_phy_write(dev, 0x0015, b43_phy_read(dev, 0x0015) | 0x0020); + b43_phy_write(dev, 0x002A, 0x08A3); + b43_radio_write16(dev, 0x007A, + b43_radio_read16(dev, 0x007A) | 0x0080); + + nrssi0 = (s16) b43_phy_read(dev, 0x0027); + b43_radio_write16(dev, 0x007A, + b43_radio_read16(dev, 0x007A) & 0x007F); + if (phy->rev >= 2) { + b43_write16(dev, 0x03E6, 0x0040); + } else if (phy->rev == 0) { + b43_write16(dev, 0x03E6, 0x0122); + } else { + b43_write16(dev, B43_MMIO_CHANNEL_EXT, + b43_read16(dev, + B43_MMIO_CHANNEL_EXT) & 0x2000); + } + b43_phy_write(dev, 0x0020, 0x3F3F); + b43_phy_write(dev, 0x0015, 0xF330); + b43_radio_write16(dev, 0x005A, 0x0060); + b43_radio_write16(dev, 0x0043, + b43_radio_read16(dev, 0x0043) & 0x00F0); + b43_phy_write(dev, 0x005A, 0x0480); + b43_phy_write(dev, 0x0059, 0x0810); + b43_phy_write(dev, 0x0058, 0x000D); + udelay(20); + + nrssi1 = (s16) b43_phy_read(dev, 0x0027); + b43_phy_write(dev, 0x0030, backup[3]); + b43_radio_write16(dev, 0x007A, backup[0]); + b43_write16(dev, 0x03E2, backup[11]); + b43_phy_write(dev, 0x0026, backup[4]); + b43_phy_write(dev, 0x0015, backup[5]); + b43_phy_write(dev, 0x002A, backup[6]); + b43_synth_pu_workaround(dev, phy->channel); + if (phy->rev != 0) + b43_write16(dev, 0x03F4, backup[13]); + + b43_phy_write(dev, 0x0020, backup[7]); + b43_phy_write(dev, 0x005A, backup[8]); + b43_phy_write(dev, 0x0059, backup[9]); + b43_phy_write(dev, 0x0058, backup[10]); + b43_radio_write16(dev, 0x0052, backup[1]); + b43_radio_write16(dev, 0x0043, backup[2]); + + if (nrssi0 == nrssi1) + phy->nrssislope = 0x00010000; + else + phy->nrssislope = 0x00400000 / (nrssi0 - nrssi1); + + if (nrssi0 <= -4) { + phy->nrssi[0] = nrssi0; + phy->nrssi[1] = nrssi1; + } + break; + case B43_PHYTYPE_G: + if (phy->radio_rev >= 9) + return; + if (phy->radio_rev == 8) + b43_calc_nrssi_offset(dev); + + b43_phy_write(dev, B43_PHY_G_CRS, + b43_phy_read(dev, B43_PHY_G_CRS) & 0x7FFF); + b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & 0xFFFC); + backup[7] = b43_read16(dev, 0x03E2); + b43_write16(dev, 0x03E2, b43_read16(dev, 0x03E2) | 0x8000); + backup[0] = b43_radio_read16(dev, 0x007A); + backup[1] = b43_radio_read16(dev, 0x0052); + backup[2] = b43_radio_read16(dev, 0x0043); + backup[3] = b43_phy_read(dev, 0x0015); + backup[4] = b43_phy_read(dev, 0x005A); + backup[5] = b43_phy_read(dev, 0x0059); + backup[6] = b43_phy_read(dev, 0x0058); + backup[8] = b43_read16(dev, 0x03E6); + backup[9] = b43_read16(dev, B43_MMIO_CHANNEL_EXT); + if (phy->rev >= 3) { + backup[10] = b43_phy_read(dev, 0x002E); + backup[11] = b43_phy_read(dev, 0x002F); + backup[12] = b43_phy_read(dev, 0x080F); + backup[13] = b43_phy_read(dev, B43_PHY_G_LO_CONTROL); + backup[14] = b43_phy_read(dev, 0x0801); + backup[15] = b43_phy_read(dev, 0x0060); + backup[16] = b43_phy_read(dev, 0x0014); + backup[17] = b43_phy_read(dev, 0x0478); + b43_phy_write(dev, 0x002E, 0); + b43_phy_write(dev, B43_PHY_G_LO_CONTROL, 0); + switch (phy->rev) { + case 4: + case 6: + case 7: + b43_phy_write(dev, 0x0478, + b43_phy_read(dev, 0x0478) + | 0x0100); + b43_phy_write(dev, 0x0801, + b43_phy_read(dev, 0x0801) + | 0x0040); + break; + case 3: + case 5: + b43_phy_write(dev, 0x0801, + b43_phy_read(dev, 0x0801) + & 0xFFBF); + break; + } + b43_phy_write(dev, 0x0060, b43_phy_read(dev, 0x0060) + | 0x0040); + b43_phy_write(dev, 0x0014, b43_phy_read(dev, 0x0014) + | 0x0200); + } + b43_radio_write16(dev, 0x007A, + b43_radio_read16(dev, 0x007A) | 0x0070); + b43_set_all_gains(dev, 0, 8, 0); + b43_radio_write16(dev, 0x007A, + b43_radio_read16(dev, 0x007A) & 0x00F7); + if (phy->rev >= 2) { + b43_phy_write(dev, 0x0811, + (b43_phy_read(dev, 0x0811) & 0xFFCF) | + 0x0030); + b43_phy_write(dev, 0x0812, + (b43_phy_read(dev, 0x0812) & 0xFFCF) | + 0x0010); + } + b43_radio_write16(dev, 0x007A, + b43_radio_read16(dev, 0x007A) | 0x0080); + udelay(20); + + nrssi0 = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F); + if (nrssi0 >= 0x0020) + nrssi0 -= 0x0040; + + b43_radio_write16(dev, 0x007A, + b43_radio_read16(dev, 0x007A) & 0x007F); + if (phy->rev >= 2) { + b43_phy_write(dev, 0x0003, (b43_phy_read(dev, 0x0003) + & 0xFF9F) | 0x0040); + } + + b43_write16(dev, B43_MMIO_CHANNEL_EXT, + b43_read16(dev, B43_MMIO_CHANNEL_EXT) + | 0x2000); + b43_radio_write16(dev, 0x007A, + b43_radio_read16(dev, 0x007A) | 0x000F); + b43_phy_write(dev, 0x0015, 0xF330); + if (phy->rev >= 2) { + b43_phy_write(dev, 0x0812, + (b43_phy_read(dev, 0x0812) & 0xFFCF) | + 0x0020); + b43_phy_write(dev, 0x0811, + (b43_phy_read(dev, 0x0811) & 0xFFCF) | + 0x0020); + } + + b43_set_all_gains(dev, 3, 0, 1); + if (phy->radio_rev == 8) { + b43_radio_write16(dev, 0x0043, 0x001F); + } else { + tmp = b43_radio_read16(dev, 0x0052) & 0xFF0F; + b43_radio_write16(dev, 0x0052, tmp | 0x0060); + tmp = b43_radio_read16(dev, 0x0043) & 0xFFF0; + b43_radio_write16(dev, 0x0043, tmp | 0x0009); + } + b43_phy_write(dev, 0x005A, 0x0480); + b43_phy_write(dev, 0x0059, 0x0810); + b43_phy_write(dev, 0x0058, 0x000D); + udelay(20); + nrssi1 = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F); + if (nrssi1 >= 0x0020) + nrssi1 -= 0x0040; + if (nrssi0 == nrssi1) + phy->nrssislope = 0x00010000; + else + phy->nrssislope = 0x00400000 / (nrssi0 - nrssi1); + if (nrssi0 >= -4) { + phy->nrssi[0] = nrssi1; + phy->nrssi[1] = nrssi0; + } + if (phy->rev >= 3) { + b43_phy_write(dev, 0x002E, backup[10]); + b43_phy_write(dev, 0x002F, backup[11]); + b43_phy_write(dev, 0x080F, backup[12]); + b43_phy_write(dev, B43_PHY_G_LO_CONTROL, backup[13]); + } + if (phy->rev >= 2) { + b43_phy_write(dev, 0x0812, + b43_phy_read(dev, 0x0812) & 0xFFCF); + b43_phy_write(dev, 0x0811, + b43_phy_read(dev, 0x0811) & 0xFFCF); + } + + b43_radio_write16(dev, 0x007A, backup[0]); + b43_radio_write16(dev, 0x0052, backup[1]); + b43_radio_write16(dev, 0x0043, backup[2]); + b43_write16(dev, 0x03E2, backup[7]); + b43_write16(dev, 0x03E6, backup[8]); + b43_write16(dev, B43_MMIO_CHANNEL_EXT, backup[9]); + b43_phy_write(dev, 0x0015, backup[3]); + b43_phy_write(dev, 0x005A, backup[4]); + b43_phy_write(dev, 0x0059, backup[5]); + b43_phy_write(dev, 0x0058, backup[6]); + b43_synth_pu_workaround(dev, phy->channel); + b43_phy_write(dev, 0x0802, + b43_phy_read(dev, 0x0802) | (0x0001 | 0x0002)); + b43_set_original_gains(dev); + b43_phy_write(dev, B43_PHY_G_CRS, + b43_phy_read(dev, B43_PHY_G_CRS) | 0x8000); + if (phy->rev >= 3) { + b43_phy_write(dev, 0x0801, backup[14]); + b43_phy_write(dev, 0x0060, backup[15]); + b43_phy_write(dev, 0x0014, backup[16]); + b43_phy_write(dev, 0x0478, backup[17]); + } + b43_nrssi_mem_update(dev); + b43_calc_nrssi_threshold(dev); + break; + default: + B43_WARN_ON(1); + } +} + +void b43_calc_nrssi_threshold(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + s32 threshold; + s32 a, b; + s16 tmp16; + u16 tmp_u16; + + switch (phy->type) { + case B43_PHYTYPE_B:{ + if (phy->radio_ver != 0x2050) + return; + if (! + (dev->dev->bus->sprom.r1. + boardflags_lo & B43_BFL_RSSI)) + return; + + if (phy->radio_rev >= 6) { + threshold = + (phy->nrssi[1] - phy->nrssi[0]) * 32; + threshold += 20 * (phy->nrssi[0] + 1); + threshold /= 40; + } else + threshold = phy->nrssi[1] - 5; + + threshold = limit_value(threshold, 0, 0x3E); + b43_phy_read(dev, 0x0020); /* dummy read */ + b43_phy_write(dev, 0x0020, + (((u16) threshold) << 8) | 0x001C); + + if (phy->radio_rev >= 6) { + b43_phy_write(dev, 0x0087, 0x0E0D); + b43_phy_write(dev, 0x0086, 0x0C0B); + b43_phy_write(dev, 0x0085, 0x0A09); + b43_phy_write(dev, 0x0084, 0x0808); + b43_phy_write(dev, 0x0083, 0x0808); + b43_phy_write(dev, 0x0082, 0x0604); + b43_phy_write(dev, 0x0081, 0x0302); + b43_phy_write(dev, 0x0080, 0x0100); + } + break; + } + case B43_PHYTYPE_G: + if (!phy->gmode || + !(dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI)) { + tmp16 = b43_nrssi_hw_read(dev, 0x20); + if (tmp16 >= 0x20) + tmp16 -= 0x40; + if (tmp16 < 3) { + b43_phy_write(dev, 0x048A, + (b43_phy_read(dev, 0x048A) + & 0xF000) | 0x09EB); + } else { + b43_phy_write(dev, 0x048A, + (b43_phy_read(dev, 0x048A) + & 0xF000) | 0x0AED); + } + } else { + if (phy->interfmode == B43_INTERFMODE_NONWLAN) { + a = 0xE; + b = 0xA; + } else if (!phy->aci_wlan_automatic && phy->aci_enable) { + a = 0x13; + b = 0x12; + } else { + a = 0xE; + b = 0x11; + } + + a = a * (phy->nrssi[1] - phy->nrssi[0]); + a += (phy->nrssi[0] << 6); + if (a < 32) + a += 31; + else + a += 32; + a = a >> 6; + a = limit_value(a, -31, 31); + + b = b * (phy->nrssi[1] - phy->nrssi[0]); + b += (phy->nrssi[0] << 6); + if (b < 32) + b += 31; + else + b += 32; + b = b >> 6; + b = limit_value(b, -31, 31); + + tmp_u16 = b43_phy_read(dev, 0x048A) & 0xF000; + tmp_u16 |= ((u32) b & 0x0000003F); + tmp_u16 |= (((u32) a & 0x0000003F) << 6); + b43_phy_write(dev, 0x048A, tmp_u16); + } + break; + default: + B43_WARN_ON(1); + } +} + +/* Stack implementation to save/restore values from the + * interference mitigation code. + * It is save to restore values in random order. + */ +static void _stack_save(u32 * _stackptr, size_t * stackidx, + u8 id, u16 offset, u16 value) +{ + u32 *stackptr = &(_stackptr[*stackidx]); + + B43_WARN_ON(offset & 0xF000); + B43_WARN_ON(id & 0xF0); + *stackptr = offset; + *stackptr |= ((u32) id) << 12; + *stackptr |= ((u32) value) << 16; + (*stackidx)++; + B43_WARN_ON(*stackidx >= B43_INTERFSTACK_SIZE); +} + +static u16 _stack_restore(u32 * stackptr, u8 id, u16 offset) +{ + size_t i; + + B43_WARN_ON(offset & 0xF000); + B43_WARN_ON(id & 0xF0); + for (i = 0; i < B43_INTERFSTACK_SIZE; i++, stackptr++) { + if ((*stackptr & 0x00000FFF) != offset) + continue; + if (((*stackptr & 0x0000F000) >> 12) != id) + continue; + return ((*stackptr & 0xFFFF0000) >> 16); + } + B43_WARN_ON(1); + + return 0; +} + +#define phy_stacksave(offset) \ + do { \ + _stack_save(stack, &stackidx, 0x1, (offset), \ + b43_phy_read(dev, (offset))); \ + } while (0) +#define phy_stackrestore(offset) \ + do { \ + b43_phy_write(dev, (offset), \ + _stack_restore(stack, 0x1, \ + (offset))); \ + } while (0) +#define radio_stacksave(offset) \ + do { \ + _stack_save(stack, &stackidx, 0x2, (offset), \ + b43_radio_read16(dev, (offset))); \ + } while (0) +#define radio_stackrestore(offset) \ + do { \ + b43_radio_write16(dev, (offset), \ + _stack_restore(stack, 0x2, \ + (offset))); \ + } while (0) +#define ofdmtab_stacksave(table, offset) \ + do { \ + _stack_save(stack, &stackidx, 0x3, (offset)|(table), \ + b43_ofdmtab_read16(dev, (table), (offset))); \ + } while (0) +#define ofdmtab_stackrestore(table, offset) \ + do { \ + b43_ofdmtab_write16(dev, (table), (offset), \ + _stack_restore(stack, 0x3, \ + (offset)|(table))); \ + } while (0) + +static void +b43_radio_interference_mitigation_enable(struct b43_wldev *dev, int mode) +{ + struct b43_phy *phy = &dev->phy; + u16 tmp, flipped; + size_t stackidx = 0; + u32 *stack = phy->interfstack; + + switch (mode) { + case B43_INTERFMODE_NONWLAN: + if (phy->rev != 1) { + b43_phy_write(dev, 0x042B, + b43_phy_read(dev, 0x042B) | 0x0800); + b43_phy_write(dev, B43_PHY_G_CRS, + b43_phy_read(dev, + B43_PHY_G_CRS) & ~0x4000); + break; + } + radio_stacksave(0x0078); + tmp = (b43_radio_read16(dev, 0x0078) & 0x001E); + flipped = flip_4bit(tmp); + if (flipped < 10 && flipped >= 8) + flipped = 7; + else if (flipped >= 10) + flipped -= 3; + flipped = flip_4bit(flipped); + flipped = (flipped << 1) | 0x0020; + b43_radio_write16(dev, 0x0078, flipped); + + b43_calc_nrssi_threshold(dev); + + phy_stacksave(0x0406); + b43_phy_write(dev, 0x0406, 0x7E28); + + b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x0800); + b43_phy_write(dev, B43_PHY_RADIO_BITFIELD, + b43_phy_read(dev, + B43_PHY_RADIO_BITFIELD) | 0x1000); + + phy_stacksave(0x04A0); + b43_phy_write(dev, 0x04A0, + (b43_phy_read(dev, 0x04A0) & 0xC0C0) | 0x0008); + phy_stacksave(0x04A1); + b43_phy_write(dev, 0x04A1, + (b43_phy_read(dev, 0x04A1) & 0xC0C0) | 0x0605); + phy_stacksave(0x04A2); + b43_phy_write(dev, 0x04A2, + (b43_phy_read(dev, 0x04A2) & 0xC0C0) | 0x0204); + phy_stacksave(0x04A8); + b43_phy_write(dev, 0x04A8, + (b43_phy_read(dev, 0x04A8) & 0xC0C0) | 0x0803); + phy_stacksave(0x04AB); + b43_phy_write(dev, 0x04AB, + (b43_phy_read(dev, 0x04AB) & 0xC0C0) | 0x0605); + + phy_stacksave(0x04A7); + b43_phy_write(dev, 0x04A7, 0x0002); + phy_stacksave(0x04A3); + b43_phy_write(dev, 0x04A3, 0x287A); + phy_stacksave(0x04A9); + b43_phy_write(dev, 0x04A9, 0x2027); + phy_stacksave(0x0493); + b43_phy_write(dev, 0x0493, 0x32F5); + phy_stacksave(0x04AA); + b43_phy_write(dev, 0x04AA, 0x2027); + phy_stacksave(0x04AC); + b43_phy_write(dev, 0x04AC, 0x32F5); + break; + case B43_INTERFMODE_MANUALWLAN: + if (b43_phy_read(dev, 0x0033) & 0x0800) + break; + + phy->aci_enable = 1; + + phy_stacksave(B43_PHY_RADIO_BITFIELD); + phy_stacksave(B43_PHY_G_CRS); + if (phy->rev < 2) { + phy_stacksave(0x0406); + } else { + phy_stacksave(0x04C0); + phy_stacksave(0x04C1); + } + phy_stacksave(0x0033); + phy_stacksave(0x04A7); + phy_stacksave(0x04A3); + phy_stacksave(0x04A9); + phy_stacksave(0x04AA); + phy_stacksave(0x04AC); + phy_stacksave(0x0493); + phy_stacksave(0x04A1); + phy_stacksave(0x04A0); + phy_stacksave(0x04A2); + phy_stacksave(0x048A); + phy_stacksave(0x04A8); + phy_stacksave(0x04AB); + if (phy->rev == 2) { + phy_stacksave(0x04AD); + phy_stacksave(0x04AE); + } else if (phy->rev >= 3) { + phy_stacksave(0x04AD); + phy_stacksave(0x0415); + phy_stacksave(0x0416); + phy_stacksave(0x0417); + ofdmtab_stacksave(0x1A00, 0x2); + ofdmtab_stacksave(0x1A00, 0x3); + } + phy_stacksave(0x042B); + phy_stacksave(0x048C); + + b43_phy_write(dev, B43_PHY_RADIO_BITFIELD, + b43_phy_read(dev, B43_PHY_RADIO_BITFIELD) + & ~0x1000); + b43_phy_write(dev, B43_PHY_G_CRS, + (b43_phy_read(dev, B43_PHY_G_CRS) + & 0xFFFC) | 0x0002); + + b43_phy_write(dev, 0x0033, 0x0800); + b43_phy_write(dev, 0x04A3, 0x2027); + b43_phy_write(dev, 0x04A9, 0x1CA8); + b43_phy_write(dev, 0x0493, 0x287A); + b43_phy_write(dev, 0x04AA, 0x1CA8); + b43_phy_write(dev, 0x04AC, 0x287A); + + b43_phy_write(dev, 0x04A0, (b43_phy_read(dev, 0x04A0) + & 0xFFC0) | 0x001A); + b43_phy_write(dev, 0x04A7, 0x000D); + + if (phy->rev < 2) { + b43_phy_write(dev, 0x0406, 0xFF0D); + } else if (phy->rev == 2) { + b43_phy_write(dev, 0x04C0, 0xFFFF); + b43_phy_write(dev, 0x04C1, 0x00A9); + } else { + b43_phy_write(dev, 0x04C0, 0x00C1); + b43_phy_write(dev, 0x04C1, 0x0059); + } + + b43_phy_write(dev, 0x04A1, (b43_phy_read(dev, 0x04A1) + & 0xC0FF) | 0x1800); + b43_phy_write(dev, 0x04A1, (b43_phy_read(dev, 0x04A1) + & 0xFFC0) | 0x0015); + b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8) + & 0xCFFF) | 0x1000); + b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8) + & 0xF0FF) | 0x0A00); + b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB) + & 0xCFFF) | 0x1000); + b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB) + & 0xF0FF) | 0x0800); + b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB) + & 0xFFCF) | 0x0010); + b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB) + & 0xFFF0) | 0x0005); + b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8) + & 0xFFCF) | 0x0010); + b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8) + & 0xFFF0) | 0x0006); + b43_phy_write(dev, 0x04A2, (b43_phy_read(dev, 0x04A2) + & 0xF0FF) | 0x0800); + b43_phy_write(dev, 0x04A0, (b43_phy_read(dev, 0x04A0) + & 0xF0FF) | 0x0500); + b43_phy_write(dev, 0x04A2, (b43_phy_read(dev, 0x04A2) + & 0xFFF0) | 0x000B); + + if (phy->rev >= 3) { + b43_phy_write(dev, 0x048A, b43_phy_read(dev, 0x048A) + & ~0x8000); + b43_phy_write(dev, 0x0415, (b43_phy_read(dev, 0x0415) + & 0x8000) | 0x36D8); + b43_phy_write(dev, 0x0416, (b43_phy_read(dev, 0x0416) + & 0x8000) | 0x36D8); + b43_phy_write(dev, 0x0417, (b43_phy_read(dev, 0x0417) + & 0xFE00) | 0x016D); + } else { + b43_phy_write(dev, 0x048A, b43_phy_read(dev, 0x048A) + | 0x1000); + b43_phy_write(dev, 0x048A, (b43_phy_read(dev, 0x048A) + & 0x9FFF) | 0x2000); + b43_hf_write(dev, b43_hf_read(dev) | B43_HF_ACIW); + } + if (phy->rev >= 2) { + b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) + | 0x0800); + } + b43_phy_write(dev, 0x048C, (b43_phy_read(dev, 0x048C) + & 0xF0FF) | 0x0200); + if (phy->rev == 2) { + b43_phy_write(dev, 0x04AE, (b43_phy_read(dev, 0x04AE) + & 0xFF00) | 0x007F); + b43_phy_write(dev, 0x04AD, (b43_phy_read(dev, 0x04AD) + & 0x00FF) | 0x1300); + } else if (phy->rev >= 6) { + b43_ofdmtab_write16(dev, 0x1A00, 0x3, 0x007F); + b43_ofdmtab_write16(dev, 0x1A00, 0x2, 0x007F); + b43_phy_write(dev, 0x04AD, b43_phy_read(dev, 0x04AD) + & 0x00FF); + } + b43_calc_nrssi_slope(dev); + break; + default: + B43_WARN_ON(1); + } +} + +static void +b43_radio_interference_mitigation_disable(struct b43_wldev *dev, int mode) +{ + struct b43_phy *phy = &dev->phy; + u32 *stack = phy->interfstack; + + switch (mode) { + case B43_INTERFMODE_NONWLAN: + if (phy->rev != 1) { + b43_phy_write(dev, 0x042B, + b43_phy_read(dev, 0x042B) & ~0x0800); + b43_phy_write(dev, B43_PHY_G_CRS, + b43_phy_read(dev, + B43_PHY_G_CRS) | 0x4000); + break; + } + radio_stackrestore(0x0078); + b43_calc_nrssi_threshold(dev); + phy_stackrestore(0x0406); + b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) & ~0x0800); + if (!dev->bad_frames_preempt) { + b43_phy_write(dev, B43_PHY_RADIO_BITFIELD, + b43_phy_read(dev, B43_PHY_RADIO_BITFIELD) + & ~(1 << 11)); + } + b43_phy_write(dev, B43_PHY_G_CRS, + b43_phy_read(dev, B43_PHY_G_CRS) | 0x4000); + phy_stackrestore(0x04A0); + phy_stackrestore(0x04A1); + phy_stackrestore(0x04A2); + phy_stackrestore(0x04A8); + phy_stackrestore(0x04AB); + phy_stackrestore(0x04A7); + phy_stackrestore(0x04A3); + phy_stackrestore(0x04A9); + phy_stackrestore(0x0493); + phy_stackrestore(0x04AA); + phy_stackrestore(0x04AC); + break; + case B43_INTERFMODE_MANUALWLAN: + if (!(b43_phy_read(dev, 0x0033) & 0x0800)) + break; + + phy->aci_enable = 0; + + phy_stackrestore(B43_PHY_RADIO_BITFIELD); + phy_stackrestore(B43_PHY_G_CRS); + phy_stackrestore(0x0033); + phy_stackrestore(0x04A3); + phy_stackrestore(0x04A9); + phy_stackrestore(0x0493); + phy_stackrestore(0x04AA); + phy_stackrestore(0x04AC); + phy_stackrestore(0x04A0); + phy_stackrestore(0x04A7); + if (phy->rev >= 2) { + phy_stackrestore(0x04C0); + phy_stackrestore(0x04C1); + } else + phy_stackrestore(0x0406); + phy_stackrestore(0x04A1); + phy_stackrestore(0x04AB); + phy_stackrestore(0x04A8); + if (phy->rev == 2) { + phy_stackrestore(0x04AD); + phy_stackrestore(0x04AE); + } else if (phy->rev >= 3) { + phy_stackrestore(0x04AD); + phy_stackrestore(0x0415); + phy_stackrestore(0x0416); + phy_stackrestore(0x0417); + ofdmtab_stackrestore(0x1A00, 0x2); + ofdmtab_stackrestore(0x1A00, 0x3); + } + phy_stackrestore(0x04A2); + phy_stackrestore(0x048A); + phy_stackrestore(0x042B); + phy_stackrestore(0x048C); + b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_ACIW); + b43_calc_nrssi_slope(dev); + break; + default: + B43_WARN_ON(1); + } +} + +#undef phy_stacksave +#undef phy_stackrestore +#undef radio_stacksave +#undef radio_stackrestore +#undef ofdmtab_stacksave +#undef ofdmtab_stackrestore + +int b43_radio_set_interference_mitigation(struct b43_wldev *dev, int mode) +{ + struct b43_phy *phy = &dev->phy; + int currentmode; + + if ((phy->type != B43_PHYTYPE_G) || (phy->rev == 0) || (!phy->gmode)) + return -ENODEV; + + phy->aci_wlan_automatic = 0; + switch (mode) { + case B43_INTERFMODE_AUTOWLAN: + phy->aci_wlan_automatic = 1; + if (phy->aci_enable) + mode = B43_INTERFMODE_MANUALWLAN; + else + mode = B43_INTERFMODE_NONE; + break; + case B43_INTERFMODE_NONE: + case B43_INTERFMODE_NONWLAN: + case B43_INTERFMODE_MANUALWLAN: + break; + default: + return -EINVAL; + } + + currentmode = phy->interfmode; + if (currentmode == mode) + return 0; + if (currentmode != B43_INTERFMODE_NONE) + b43_radio_interference_mitigation_disable(dev, currentmode); + + if (mode == B43_INTERFMODE_NONE) { + phy->aci_enable = 0; + phy->aci_hw_rssi = 0; + } else + b43_radio_interference_mitigation_enable(dev, mode); + phy->interfmode = mode; + + return 0; +} + +static u16 b43_radio_core_calibration_value(struct b43_wldev *dev) +{ + u16 reg, index, ret; + + static const u8 rcc_table[] = { + 0x02, 0x03, 0x01, 0x0F, + 0x06, 0x07, 0x05, 0x0F, + 0x0A, 0x0B, 0x09, 0x0F, + 0x0E, 0x0F, 0x0D, 0x0F, + }; + + reg = b43_radio_read16(dev, 0x60); + index = (reg & 0x001E) >> 1; + ret = rcc_table[index] << 1; + ret |= (reg & 0x0001); + ret |= 0x0020; + + return ret; +} + +#define LPD(L, P, D) (((L) << 2) | ((P) << 1) | ((D) << 0)) +static u16 radio2050_rfover_val(struct b43_wldev *dev, + u16 phy_register, unsigned int lpd) +{ + struct b43_phy *phy = &dev->phy; + struct ssb_sprom *sprom = &(dev->dev->bus->sprom); + + if (!phy->gmode) + return 0; + + if (has_loopback_gain(phy)) { + int max_lb_gain = phy->max_lb_gain; + u16 extlna; + u16 i; + + if (phy->radio_rev == 8) + max_lb_gain += 0x3E; + else + max_lb_gain += 0x26; + if (max_lb_gain >= 0x46) { + extlna = 0x3000; + max_lb_gain -= 0x46; + } else if (max_lb_gain >= 0x3A) { + extlna = 0x1000; + max_lb_gain -= 0x3A; + } else if (max_lb_gain >= 0x2E) { + extlna = 0x2000; + max_lb_gain -= 0x2E; + } else { + extlna = 0; + max_lb_gain -= 0x10; + } + + for (i = 0; i < 16; i++) { + max_lb_gain -= (i * 6); + if (max_lb_gain < 6) + break; + } + + if ((phy->rev < 7) || + !(sprom->r1.boardflags_lo & B43_BFL_EXTLNA)) { + if (phy_register == B43_PHY_RFOVER) { + return 0x1B3; + } else if (phy_register == B43_PHY_RFOVERVAL) { + extlna |= (i << 8); + switch (lpd) { + case LPD(0, 1, 1): + return 0x0F92; + case LPD(0, 0, 1): + case LPD(1, 0, 1): + return (0x0092 | extlna); + case LPD(1, 0, 0): + return (0x0093 | extlna); + } + B43_WARN_ON(1); + } + B43_WARN_ON(1); + } else { + if (phy_register == B43_PHY_RFOVER) { + return 0x9B3; + } else if (phy_register == B43_PHY_RFOVERVAL) { + if (extlna) + extlna |= 0x8000; + extlna |= (i << 8); + switch (lpd) { + case LPD(0, 1, 1): + return 0x8F92; + case LPD(0, 0, 1): + return (0x8092 | extlna); + case LPD(1, 0, 1): + return (0x2092 | extlna); + case LPD(1, 0, 0): + return (0x2093 | extlna); + } + B43_WARN_ON(1); + } + B43_WARN_ON(1); + } + } else { + if ((phy->rev < 7) || + !(sprom->r1.boardflags_lo & B43_BFL_EXTLNA)) { + if (phy_register == B43_PHY_RFOVER) { + return 0x1B3; + } else if (phy_register == B43_PHY_RFOVERVAL) { + switch (lpd) { + case LPD(0, 1, 1): + return 0x0FB2; + case LPD(0, 0, 1): + return 0x00B2; + case LPD(1, 0, 1): + return 0x30B2; + case LPD(1, 0, 0): + return 0x30B3; + } + B43_WARN_ON(1); + } + B43_WARN_ON(1); + } else { + if (phy_register == B43_PHY_RFOVER) { + return 0x9B3; + } else if (phy_register == B43_PHY_RFOVERVAL) { + switch (lpd) { + case LPD(0, 1, 1): + return 0x8FB2; + case LPD(0, 0, 1): + return 0x80B2; + case LPD(1, 0, 1): + return 0x20B2; + case LPD(1, 0, 0): + return 0x20B3; + } + B43_WARN_ON(1); + } + B43_WARN_ON(1); + } + } + return 0; +} + +struct init2050_saved_values { + /* Core registers */ + u16 reg_3EC; + u16 reg_3E6; + u16 reg_3F4; + /* Radio registers */ + u16 radio_43; + u16 radio_51; + u16 radio_52; + /* PHY registers */ + u16 phy_pgactl; + u16 phy_base_5A; + u16 phy_base_59; + u16 phy_base_58; + u16 phy_base_30; + u16 phy_rfover; + u16 phy_rfoverval; + u16 phy_analogover; + u16 phy_analogoverval; + u16 phy_crs0; + u16 phy_classctl; + u16 phy_lo_mask; + u16 phy_lo_ctl; + u16 phy_syncctl; +}; + +u16 b43_radio_init2050(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct init2050_saved_values sav; + u16 rcc; + u16 radio78; + u16 ret; + u16 i, j; + u32 tmp1 = 0, tmp2 = 0; + + memset(&sav, 0, sizeof(sav)); /* get rid of "may be used uninitialized..." */ + + sav.radio_43 = b43_radio_read16(dev, 0x43); + sav.radio_51 = b43_radio_read16(dev, 0x51); + sav.radio_52 = b43_radio_read16(dev, 0x52); + sav.phy_pgactl = b43_phy_read(dev, B43_PHY_PGACTL); + sav.phy_base_5A = b43_phy_read(dev, B43_PHY_BASE(0x5A)); + sav.phy_base_59 = b43_phy_read(dev, B43_PHY_BASE(0x59)); + sav.phy_base_58 = b43_phy_read(dev, B43_PHY_BASE(0x58)); + + if (phy->type == B43_PHYTYPE_B) { + sav.phy_base_30 = b43_phy_read(dev, B43_PHY_BASE(0x30)); + sav.reg_3EC = b43_read16(dev, 0x3EC); + + b43_phy_write(dev, B43_PHY_BASE(0x30), 0xFF); + b43_write16(dev, 0x3EC, 0x3F3F); + } else if (phy->gmode || phy->rev >= 2) { + sav.phy_rfover = b43_phy_read(dev, B43_PHY_RFOVER); + sav.phy_rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL); + sav.phy_analogover = b43_phy_read(dev, B43_PHY_ANALOGOVER); + sav.phy_analogoverval = + b43_phy_read(dev, B43_PHY_ANALOGOVERVAL); + sav.phy_crs0 = b43_phy_read(dev, B43_PHY_CRS0); + sav.phy_classctl = b43_phy_read(dev, B43_PHY_CLASSCTL); + + b43_phy_write(dev, B43_PHY_ANALOGOVER, + b43_phy_read(dev, B43_PHY_ANALOGOVER) + | 0x0003); + b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, + b43_phy_read(dev, B43_PHY_ANALOGOVERVAL) + & 0xFFFC); + b43_phy_write(dev, B43_PHY_CRS0, b43_phy_read(dev, B43_PHY_CRS0) + & 0x7FFF); + b43_phy_write(dev, B43_PHY_CLASSCTL, + b43_phy_read(dev, B43_PHY_CLASSCTL) + & 0xFFFC); + if (has_loopback_gain(phy)) { + sav.phy_lo_mask = b43_phy_read(dev, B43_PHY_LO_MASK); + sav.phy_lo_ctl = b43_phy_read(dev, B43_PHY_LO_CTL); + + if (phy->rev >= 3) + b43_phy_write(dev, B43_PHY_LO_MASK, 0xC020); + else + b43_phy_write(dev, B43_PHY_LO_MASK, 0x8020); + b43_phy_write(dev, B43_PHY_LO_CTL, 0); + } + + b43_phy_write(dev, B43_PHY_RFOVERVAL, + radio2050_rfover_val(dev, B43_PHY_RFOVERVAL, + LPD(0, 1, 1))); + b43_phy_write(dev, B43_PHY_RFOVER, + radio2050_rfover_val(dev, B43_PHY_RFOVER, 0)); + } + b43_write16(dev, 0x3E2, b43_read16(dev, 0x3E2) | 0x8000); + + sav.phy_syncctl = b43_phy_read(dev, B43_PHY_SYNCCTL); + b43_phy_write(dev, B43_PHY_SYNCCTL, b43_phy_read(dev, B43_PHY_SYNCCTL) + & 0xFF7F); + sav.reg_3E6 = b43_read16(dev, 0x3E6); + sav.reg_3F4 = b43_read16(dev, 0x3F4); + + if (phy->analog == 0) { + b43_write16(dev, 0x03E6, 0x0122); + } else { + if (phy->analog >= 2) { + b43_phy_write(dev, B43_PHY_BASE(0x03), + (b43_phy_read(dev, B43_PHY_BASE(0x03)) + & 0xFFBF) | 0x40); + } + b43_write16(dev, B43_MMIO_CHANNEL_EXT, + (b43_read16(dev, B43_MMIO_CHANNEL_EXT) | 0x2000)); + } + + rcc = b43_radio_core_calibration_value(dev); + + if (phy->type == B43_PHYTYPE_B) + b43_radio_write16(dev, 0x78, 0x26); + if (phy->gmode || phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + radio2050_rfover_val(dev, B43_PHY_RFOVERVAL, + LPD(0, 1, 1))); + } + b43_phy_write(dev, B43_PHY_PGACTL, 0xBFAF); + b43_phy_write(dev, B43_PHY_BASE(0x2B), 0x1403); + if (phy->gmode || phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + radio2050_rfover_val(dev, B43_PHY_RFOVERVAL, + LPD(0, 0, 1))); + } + b43_phy_write(dev, B43_PHY_PGACTL, 0xBFA0); + b43_radio_write16(dev, 0x51, b43_radio_read16(dev, 0x51) + | 0x0004); + if (phy->radio_rev == 8) { + b43_radio_write16(dev, 0x43, 0x1F); + } else { + b43_radio_write16(dev, 0x52, 0); + b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43) + & 0xFFF0) | 0x0009); + } + b43_phy_write(dev, B43_PHY_BASE(0x58), 0); + + for (i = 0; i < 16; i++) { + b43_phy_write(dev, B43_PHY_BASE(0x5A), 0x0480); + b43_phy_write(dev, B43_PHY_BASE(0x59), 0xC810); + b43_phy_write(dev, B43_PHY_BASE(0x58), 0x000D); + if (phy->gmode || phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + radio2050_rfover_val(dev, + B43_PHY_RFOVERVAL, + LPD(1, 0, 1))); + } + b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0); + udelay(10); + if (phy->gmode || phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + radio2050_rfover_val(dev, + B43_PHY_RFOVERVAL, + LPD(1, 0, 1))); + } + b43_phy_write(dev, B43_PHY_PGACTL, 0xEFB0); + udelay(10); + if (phy->gmode || phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + radio2050_rfover_val(dev, + B43_PHY_RFOVERVAL, + LPD(1, 0, 0))); + } + b43_phy_write(dev, B43_PHY_PGACTL, 0xFFF0); + udelay(20); + tmp1 += b43_phy_read(dev, B43_PHY_LO_LEAKAGE); + b43_phy_write(dev, B43_PHY_BASE(0x58), 0); + if (phy->gmode || phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + radio2050_rfover_val(dev, + B43_PHY_RFOVERVAL, + LPD(1, 0, 1))); + } + b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0); + } + udelay(10); + + b43_phy_write(dev, B43_PHY_BASE(0x58), 0); + tmp1++; + tmp1 >>= 9; + + for (i = 0; i < 16; i++) { + radio78 = ((flip_4bit(i) << 1) | 0x20); + b43_radio_write16(dev, 0x78, radio78); + udelay(10); + for (j = 0; j < 16; j++) { + b43_phy_write(dev, B43_PHY_BASE(0x5A), 0x0D80); + b43_phy_write(dev, B43_PHY_BASE(0x59), 0xC810); + b43_phy_write(dev, B43_PHY_BASE(0x58), 0x000D); + if (phy->gmode || phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + radio2050_rfover_val(dev, + B43_PHY_RFOVERVAL, + LPD(1, 0, + 1))); + } + b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0); + udelay(10); + if (phy->gmode || phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + radio2050_rfover_val(dev, + B43_PHY_RFOVERVAL, + LPD(1, 0, + 1))); + } + b43_phy_write(dev, B43_PHY_PGACTL, 0xEFB0); + udelay(10); + if (phy->gmode || phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + radio2050_rfover_val(dev, + B43_PHY_RFOVERVAL, + LPD(1, 0, + 0))); + } + b43_phy_write(dev, B43_PHY_PGACTL, 0xFFF0); + udelay(10); + tmp2 += b43_phy_read(dev, B43_PHY_LO_LEAKAGE); + b43_phy_write(dev, B43_PHY_BASE(0x58), 0); + if (phy->gmode || phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + radio2050_rfover_val(dev, + B43_PHY_RFOVERVAL, + LPD(1, 0, + 1))); + } + b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0); + } + tmp2++; + tmp2 >>= 8; + if (tmp1 < tmp2) + break; + } + + /* Restore the registers */ + b43_phy_write(dev, B43_PHY_PGACTL, sav.phy_pgactl); + b43_radio_write16(dev, 0x51, sav.radio_51); + b43_radio_write16(dev, 0x52, sav.radio_52); + b43_radio_write16(dev, 0x43, sav.radio_43); + b43_phy_write(dev, B43_PHY_BASE(0x5A), sav.phy_base_5A); + b43_phy_write(dev, B43_PHY_BASE(0x59), sav.phy_base_59); + b43_phy_write(dev, B43_PHY_BASE(0x58), sav.phy_base_58); + b43_write16(dev, 0x3E6, sav.reg_3E6); + if (phy->analog != 0) + b43_write16(dev, 0x3F4, sav.reg_3F4); + b43_phy_write(dev, B43_PHY_SYNCCTL, sav.phy_syncctl); + b43_synth_pu_workaround(dev, phy->channel); + if (phy->type == B43_PHYTYPE_B) { + b43_phy_write(dev, B43_PHY_BASE(0x30), sav.phy_base_30); + b43_write16(dev, 0x3EC, sav.reg_3EC); + } else if (phy->gmode) { + b43_write16(dev, B43_MMIO_PHY_RADIO, + b43_read16(dev, B43_MMIO_PHY_RADIO) + & 0x7FFF); + b43_phy_write(dev, B43_PHY_RFOVER, sav.phy_rfover); + b43_phy_write(dev, B43_PHY_RFOVERVAL, sav.phy_rfoverval); + b43_phy_write(dev, B43_PHY_ANALOGOVER, sav.phy_analogover); + b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, + sav.phy_analogoverval); + b43_phy_write(dev, B43_PHY_CRS0, sav.phy_crs0); + b43_phy_write(dev, B43_PHY_CLASSCTL, sav.phy_classctl); + if (has_loopback_gain(phy)) { + b43_phy_write(dev, B43_PHY_LO_MASK, sav.phy_lo_mask); + b43_phy_write(dev, B43_PHY_LO_CTL, sav.phy_lo_ctl); + } + } + if (i > 15) + ret = radio78; + else + ret = rcc; + + return ret; +} + +void b43_radio_init2060(struct b43_wldev *dev) +{ + int err; + + b43_radio_write16(dev, 0x0004, 0x00C0); + b43_radio_write16(dev, 0x0005, 0x0008); + b43_radio_write16(dev, 0x0009, 0x0040); + b43_radio_write16(dev, 0x0005, 0x00AA); + b43_radio_write16(dev, 0x0032, 0x008F); + b43_radio_write16(dev, 0x0006, 0x008F); + b43_radio_write16(dev, 0x0034, 0x008F); + b43_radio_write16(dev, 0x002C, 0x0007); + b43_radio_write16(dev, 0x0082, 0x0080); + b43_radio_write16(dev, 0x0080, 0x0000); + b43_radio_write16(dev, 0x003F, 0x00DA); + b43_radio_write16(dev, 0x0005, b43_radio_read16(dev, 0x0005) & ~0x0008); + b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0010); + b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0020); + b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0020); + msleep(1); /* delay 400usec */ + + b43_radio_write16(dev, 0x0081, + (b43_radio_read16(dev, 0x0081) & ~0x0020) | 0x0010); + msleep(1); /* delay 400usec */ + + b43_radio_write16(dev, 0x0005, + (b43_radio_read16(dev, 0x0005) & ~0x0008) | 0x0008); + b43_radio_write16(dev, 0x0085, b43_radio_read16(dev, 0x0085) & ~0x0010); + b43_radio_write16(dev, 0x0005, b43_radio_read16(dev, 0x0005) & ~0x0008); + b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0040); + b43_radio_write16(dev, 0x0081, + (b43_radio_read16(dev, 0x0081) & ~0x0040) | 0x0040); + b43_radio_write16(dev, 0x0005, + (b43_radio_read16(dev, 0x0081) & ~0x0008) | 0x0008); + b43_phy_write(dev, 0x0063, 0xDDC6); + b43_phy_write(dev, 0x0069, 0x07BE); + b43_phy_write(dev, 0x006A, 0x0000); + + err = b43_radio_selectchannel(dev, B43_DEFAULT_CHANNEL_A, 0); + B43_WARN_ON(err); + + msleep(1); +} + +static inline u16 freq_r3A_value(u16 frequency) +{ + u16 value; + + if (frequency < 5091) + value = 0x0040; + else if (frequency < 5321) + value = 0x0000; + else if (frequency < 5806) + value = 0x0080; + else + value = 0x0040; + + return value; +} + +void b43_radio_set_tx_iq(struct b43_wldev *dev) +{ + static const u8 data_high[5] = { 0x00, 0x40, 0x80, 0x90, 0xD0 }; + static const u8 data_low[5] = { 0x00, 0x01, 0x05, 0x06, 0x0A }; + u16 tmp = b43_radio_read16(dev, 0x001E); + int i, j; + + for (i = 0; i < 5; i++) { + for (j = 0; j < 5; j++) { + if (tmp == (data_high[i] << 4 | data_low[j])) { + b43_phy_write(dev, 0x0069, + (i - j) << 8 | 0x00C0); + return; + } + } + } +} + +int b43_radio_selectchannel(struct b43_wldev *dev, + u8 channel, int synthetic_pu_workaround) +{ + struct b43_phy *phy = &dev->phy; + u16 r8, tmp; + u16 freq; + u16 channelcookie; + + /* First we set the channel radio code to prevent the + * firmware from sending ghost packets. + */ + channelcookie = channel; + if (phy->type == B43_PHYTYPE_A) + channelcookie |= 0x100; + b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN, channelcookie); + + if (phy->type == B43_PHYTYPE_A) { + if (channel > 200) + return -EINVAL; + freq = channel2freq_a(channel); + + r8 = b43_radio_read16(dev, 0x0008); + b43_write16(dev, 0x03F0, freq); + b43_radio_write16(dev, 0x0008, r8); + + //TODO: write max channel TX power? to Radio 0x2D + tmp = b43_radio_read16(dev, 0x002E); + tmp &= 0x0080; + //TODO: OR tmp with the Power out estimation for this channel? + b43_radio_write16(dev, 0x002E, tmp); + + if (freq >= 4920 && freq <= 5500) { + /* + * r8 = (((freq * 15 * 0xE1FC780F) >> 32) / 29) & 0x0F; + * = (freq * 0.025862069 + */ + r8 = 3 * freq / 116; /* is equal to r8 = freq * 0.025862 */ + } + b43_radio_write16(dev, 0x0007, (r8 << 4) | r8); + b43_radio_write16(dev, 0x0020, (r8 << 4) | r8); + b43_radio_write16(dev, 0x0021, (r8 << 4) | r8); + b43_radio_write16(dev, 0x0022, (b43_radio_read16(dev, 0x0022) + & 0x000F) | (r8 << 4)); + b43_radio_write16(dev, 0x002A, (r8 << 4)); + b43_radio_write16(dev, 0x002B, (r8 << 4)); + b43_radio_write16(dev, 0x0008, (b43_radio_read16(dev, 0x0008) + & 0x00F0) | (r8 << 4)); + b43_radio_write16(dev, 0x0029, (b43_radio_read16(dev, 0x0029) + & 0xFF0F) | 0x00B0); + b43_radio_write16(dev, 0x0035, 0x00AA); + b43_radio_write16(dev, 0x0036, 0x0085); + b43_radio_write16(dev, 0x003A, (b43_radio_read16(dev, 0x003A) + & 0xFF20) | + freq_r3A_value(freq)); + b43_radio_write16(dev, 0x003D, + b43_radio_read16(dev, 0x003D) & 0x00FF); + b43_radio_write16(dev, 0x0081, (b43_radio_read16(dev, 0x0081) + & 0xFF7F) | 0x0080); + b43_radio_write16(dev, 0x0035, + b43_radio_read16(dev, 0x0035) & 0xFFEF); + b43_radio_write16(dev, 0x0035, (b43_radio_read16(dev, 0x0035) + & 0xFFEF) | 0x0010); + b43_radio_set_tx_iq(dev); + //TODO: TSSI2dbm workaround + b43_phy_xmitpower(dev); //FIXME correct? + } else { + if ((channel < 1) || (channel > 14)) + return -EINVAL; + + if (synthetic_pu_workaround) + b43_synth_pu_workaround(dev, channel); + + b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(channel)); + + if (channel == 14) { + if (dev->dev->bus->sprom.r1.country_code == + SSB_SPROM1CCODE_JAPAN) + b43_hf_write(dev, + b43_hf_read(dev) & ~B43_HF_ACPR); + else + b43_hf_write(dev, + b43_hf_read(dev) | B43_HF_ACPR); + b43_write16(dev, B43_MMIO_CHANNEL_EXT, + b43_read16(dev, B43_MMIO_CHANNEL_EXT) + | (1 << 11)); + } else { + b43_write16(dev, B43_MMIO_CHANNEL_EXT, + b43_read16(dev, B43_MMIO_CHANNEL_EXT) + & 0xF7BF); + } + } + + phy->channel = channel; + /* Wait for the radio to tune to the channel and stabilize. */ + msleep(8); + + return 0; +} + +/* http://bcm-specs.sipsolutions.net/TX_Gain_Base_Band */ +static u16 b43_get_txgain_base_band(u16 txpower) +{ + u16 ret; + + B43_WARN_ON(txpower > 63); + + if (txpower >= 54) + ret = 2; + else if (txpower >= 49) + ret = 4; + else if (txpower >= 44) + ret = 5; + else + ret = 6; + + return ret; +} + +/* http://bcm-specs.sipsolutions.net/TX_Gain_Radio_Frequency_Power_Amplifier */ +static u16 b43_get_txgain_freq_power_amp(u16 txpower) +{ + u16 ret; + + B43_WARN_ON(txpower > 63); + + if (txpower >= 32) + ret = 0; + else if (txpower >= 25) + ret = 1; + else if (txpower >= 20) + ret = 2; + else if (txpower >= 12) + ret = 3; + else + ret = 4; + + return ret; +} + +/* http://bcm-specs.sipsolutions.net/TX_Gain_Digital_Analog_Converter */ +static u16 b43_get_txgain_dac(u16 txpower) +{ + u16 ret; + + B43_WARN_ON(txpower > 63); + + if (txpower >= 54) + ret = txpower - 53; + else if (txpower >= 49) + ret = txpower - 42; + else if (txpower >= 44) + ret = txpower - 37; + else if (txpower >= 32) + ret = txpower - 32; + else if (txpower >= 25) + ret = txpower - 20; + else if (txpower >= 20) + ret = txpower - 13; + else if (txpower >= 12) + ret = txpower - 8; + else + ret = txpower; + + return ret; +} + +static void b43_radio_set_txpower_a(struct b43_wldev *dev, u16 txpower) +{ + struct b43_phy *phy = &dev->phy; + u16 pamp, base, dac, t; + + txpower = limit_value(txpower, 0, 63); + + pamp = b43_get_txgain_freq_power_amp(txpower); + pamp <<= 5; + pamp &= 0x00E0; + b43_phy_write(dev, 0x0019, pamp); + + base = b43_get_txgain_base_band(txpower); + base &= 0x000F; + b43_phy_write(dev, 0x0017, base | 0x0020); + + t = b43_ofdmtab_read16(dev, 0x3000, 1); + t &= 0x0007; + + dac = b43_get_txgain_dac(txpower); + dac <<= 3; + dac |= t; + + b43_ofdmtab_write16(dev, 0x3000, 1, dac); + + phy->txpwr_offset = txpower; + + //TODO: FuncPlaceholder (Adjust BB loft cancel) +} + +void b43_radio_turn_on(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + int err; + + might_sleep(); + + if (phy->radio_on) + return; + + switch (phy->type) { + case B43_PHYTYPE_A: + b43_radio_write16(dev, 0x0004, 0x00C0); + b43_radio_write16(dev, 0x0005, 0x0008); + b43_phy_write(dev, 0x0010, b43_phy_read(dev, 0x0010) & 0xFFF7); + b43_phy_write(dev, 0x0011, b43_phy_read(dev, 0x0011) & 0xFFF7); + b43_radio_init2060(dev); + break; + case B43_PHYTYPE_B: + case B43_PHYTYPE_G: + b43_phy_write(dev, 0x0015, 0x8000); + b43_phy_write(dev, 0x0015, 0xCC00); + b43_phy_write(dev, 0x0015, (phy->gmode ? 0x00C0 : 0x0000)); + err = b43_radio_selectchannel(dev, B43_DEFAULT_CHANNEL_BG, 1); + B43_WARN_ON(err); + break; + default: + B43_WARN_ON(1); + } + phy->radio_on = 1; + b43dbg(dev->wl, "Radio turned on\n"); +} + +void b43_radio_turn_off(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + + if (phy->type == B43_PHYTYPE_A) { + b43_radio_write16(dev, 0x0004, 0x00FF); + b43_radio_write16(dev, 0x0005, 0x00FB); + b43_phy_write(dev, 0x0010, b43_phy_read(dev, 0x0010) | 0x0008); + b43_phy_write(dev, 0x0011, b43_phy_read(dev, 0x0011) | 0x0008); + } + if (phy->type == B43_PHYTYPE_G && dev->dev->id.revision >= 5) { + b43_phy_write(dev, 0x0811, b43_phy_read(dev, 0x0811) | 0x008C); + b43_phy_write(dev, 0x0812, b43_phy_read(dev, 0x0812) & 0xFF73); + } else + b43_phy_write(dev, 0x0015, 0xAA00); + phy->radio_on = 0; + b43dbg(dev->wl, "Radio turned off\n"); +} diff --git a/drivers/net/wireless/b43/phy.h b/drivers/net/wireless/b43/phy.h new file mode 100644 index 00000000000..d1f623cb9b3 --- /dev/null +++ b/drivers/net/wireless/b43/phy.h @@ -0,0 +1,297 @@ +#ifndef B43_PHY_H_ +#define B43_PHY_H_ + +#include + +struct b43_wldev; +struct b43_phy; + +/*** PHY Registers ***/ + +/* Routing */ +#define B43_PHYROUTE_OFDM_GPHY 0x400 +#define B43_PHYROUTE_EXT_GPHY 0x800 + +/* Base registers. */ +#define B43_PHY_BASE(reg) (reg) +/* OFDM (A) registers of a G-PHY */ +#define B43_PHY_OFDM(reg) ((reg) | B43_PHYROUTE_OFDM_GPHY) +/* Extended G-PHY registers */ +#define B43_PHY_EXTG(reg) ((reg) | B43_PHYROUTE_EXT_GPHY) + +/* OFDM (A) PHY Registers */ +#define B43_PHY_VERSION_OFDM B43_PHY_OFDM(0x00) /* Versioning register for A-PHY */ +#define B43_PHY_BBANDCFG B43_PHY_OFDM(0x01) /* Baseband config */ +#define B43_PHY_BBANDCFG_RXANT 0x180 /* RX Antenna selection */ +#define B43_PHY_BBANDCFG_RXANT_SHIFT 7 +#define B43_PHY_PWRDOWN B43_PHY_OFDM(0x03) /* Powerdown */ +#define B43_PHY_CRSTHRES1 B43_PHY_OFDM(0x06) /* CRS Threshold 1 */ +#define B43_PHY_LNAHPFCTL B43_PHY_OFDM(0x1C) /* LNA/HPF control */ +#define B43_PHY_ADIVRELATED B43_PHY_OFDM(0x27) /* FIXME rename */ +#define B43_PHY_CRS0 B43_PHY_OFDM(0x29) +#define B43_PHY_ANTDWELL B43_PHY_OFDM(0x2B) /* Antenna dwell */ +#define B43_PHY_ANTDWELL_AUTODIV1 0x0100 /* Automatic RX diversity start antenna */ +#define B43_PHY_ENCORE B43_PHY_OFDM(0x49) /* "Encore" (RangeMax / BroadRange) */ +#define B43_PHY_ENCORE_EN 0x0200 /* Encore enable */ +#define B43_PHY_LMS B43_PHY_OFDM(0x55) +#define B43_PHY_OFDM61 B43_PHY_OFDM(0x61) /* FIXME rename */ +#define B43_PHY_OFDM61_10 0x0010 /* FIXME rename */ +#define B43_PHY_IQBAL B43_PHY_OFDM(0x69) /* I/Q balance */ +#define B43_PHY_OTABLECTL B43_PHY_OFDM(0x72) /* OFDM table control (see below) */ +#define B43_PHY_OTABLEOFF 0x03FF /* OFDM table offset (see below) */ +#define B43_PHY_OTABLENR 0xFC00 /* OFDM table number (see below) */ +#define B43_PHY_OTABLENR_SHIFT 10 +#define B43_PHY_OTABLEI B43_PHY_OFDM(0x73) /* OFDM table data I */ +#define B43_PHY_OTABLEQ B43_PHY_OFDM(0x74) /* OFDM table data Q */ +#define B43_PHY_HPWR_TSSICTL B43_PHY_OFDM(0x78) /* Hardware power TSSI control */ +#define B43_PHY_NRSSITHRES B43_PHY_OFDM(0x8A) /* NRSSI threshold */ +#define B43_PHY_ANTWRSETT B43_PHY_OFDM(0x8C) /* Antenna WR settle */ +#define B43_PHY_ANTWRSETT_ARXDIV 0x2000 /* Automatic RX diversity enabled */ +#define B43_PHY_CLIPPWRDOWNT B43_PHY_OFDM(0x93) /* Clip powerdown threshold */ +#define B43_PHY_OFDM9B B43_PHY_OFDM(0x9B) /* FIXME rename */ +#define B43_PHY_N1P1GAIN B43_PHY_OFDM(0xA0) +#define B43_PHY_P1P2GAIN B43_PHY_OFDM(0xA1) +#define B43_PHY_N1N2GAIN B43_PHY_OFDM(0xA2) +#define B43_PHY_CLIPTHRES B43_PHY_OFDM(0xA3) +#define B43_PHY_CLIPN1P2THRES B43_PHY_OFDM(0xA4) +#define B43_PHY_DIVSRCHIDX B43_PHY_OFDM(0xA8) /* Divider search gain/index */ +#define B43_PHY_CLIPP2THRES B43_PHY_OFDM(0xA9) +#define B43_PHY_CLIPP3THRES B43_PHY_OFDM(0xAA) +#define B43_PHY_DIVP1P2GAIN B43_PHY_OFDM(0xAB) +#define B43_PHY_DIVSRCHGAINBACK B43_PHY_OFDM(0xAD) /* Divider search gain back */ +#define B43_PHY_DIVSRCHGAINCHNG B43_PHY_OFDM(0xAE) /* Divider search gain change */ +#define B43_PHY_CRSTHRES1_R1 B43_PHY_OFDM(0xC0) /* CRS Threshold 1 (rev 1 only) */ +#define B43_PHY_CRSTHRES2_R1 B43_PHY_OFDM(0xC1) /* CRS Threshold 2 (rev 1 only) */ +#define B43_PHY_TSSIP_LTBASE B43_PHY_OFDM(0x380) /* TSSI power lookup table base */ +#define B43_PHY_DC_LTBASE B43_PHY_OFDM(0x3A0) /* DC lookup table base */ +#define B43_PHY_GAIN_LTBASE B43_PHY_OFDM(0x3C0) /* Gain lookup table base */ + +/* CCK (B) PHY Registers */ +#define B43_PHY_VERSION_CCK B43_PHY_BASE(0x00) /* Versioning register for B-PHY */ +#define B43_PHY_CCKBBANDCFG B43_PHY_BASE(0x01) /* Contains antenna 0/1 control bit */ +#define B43_PHY_PGACTL B43_PHY_BASE(0x15) /* PGA control */ +#define B43_PHY_PGACTL_LPF 0x1000 /* Low pass filter (?) */ +#define B43_PHY_PGACTL_LOWBANDW 0x0040 /* Low bandwidth flag */ +#define B43_PHY_PGACTL_UNKNOWN 0xEFA0 +#define B43_PHY_FBCTL1 B43_PHY_BASE(0x18) /* Frequency bandwidth control 1 */ +#define B43_PHY_ITSSI B43_PHY_BASE(0x29) /* Idle TSSI */ +#define B43_PHY_LO_LEAKAGE B43_PHY_BASE(0x2D) /* Measured LO leakage */ +#define B43_PHY_ENERGY B43_PHY_BASE(0x33) /* Energy */ +#define B43_PHY_SYNCCTL B43_PHY_BASE(0x35) +#define B43_PHY_FBCTL2 B43_PHY_BASE(0x38) /* Frequency bandwidth control 2 */ +#define B43_PHY_DACCTL B43_PHY_BASE(0x60) /* DAC control */ +#define B43_PHY_RCCALOVER B43_PHY_BASE(0x78) /* RC calibration override */ + +/* Extended G-PHY Registers */ +#define B43_PHY_CLASSCTL B43_PHY_EXTG(0x02) /* Classify control */ +#define B43_PHY_GTABCTL B43_PHY_EXTG(0x03) /* G-PHY table control (see below) */ +#define B43_PHY_GTABOFF 0x03FF /* G-PHY table offset (see below) */ +#define B43_PHY_GTABNR 0xFC00 /* G-PHY table number (see below) */ +#define B43_PHY_GTABNR_SHIFT 10 +#define B43_PHY_GTABDATA B43_PHY_EXTG(0x04) /* G-PHY table data */ +#define B43_PHY_LO_MASK B43_PHY_EXTG(0x0F) /* Local Oscillator control mask */ +#define B43_PHY_LO_CTL B43_PHY_EXTG(0x10) /* Local Oscillator control */ +#define B43_PHY_RFOVER B43_PHY_EXTG(0x11) /* RF override */ +#define B43_PHY_RFOVERVAL B43_PHY_EXTG(0x12) /* RF override value */ +#define B43_PHY_RFOVERVAL_EXTLNA 0x8000 +#define B43_PHY_RFOVERVAL_LNA 0x7000 +#define B43_PHY_RFOVERVAL_LNA_SHIFT 12 +#define B43_PHY_RFOVERVAL_PGA 0x0F00 +#define B43_PHY_RFOVERVAL_PGA_SHIFT 8 +#define B43_PHY_RFOVERVAL_UNK 0x0010 /* Unknown, always set. */ +#define B43_PHY_RFOVERVAL_TRSWRX 0x00E0 +#define B43_PHY_RFOVERVAL_BW 0x0003 /* Bandwidth flags */ +#define B43_PHY_RFOVERVAL_BW_LPF 0x0001 /* Low Pass Filter */ +#define B43_PHY_RFOVERVAL_BW_LBW 0x0002 /* Low Bandwidth (when set), high when unset */ +#define B43_PHY_ANALOGOVER B43_PHY_EXTG(0x14) /* Analog override */ +#define B43_PHY_ANALOGOVERVAL B43_PHY_EXTG(0x15) /* Analog override value */ + +/*** OFDM table numbers ***/ +#define B43_OFDMTAB(number, offset) (((number) << B43_PHY_OTABLENR_SHIFT) | (offset)) +#define B43_OFDMTAB_AGC1 B43_OFDMTAB(0x00, 0) +#define B43_OFDMTAB_GAIN0 B43_OFDMTAB(0x00, 0) +#define B43_OFDMTAB_GAINX B43_OFDMTAB(0x01, 0) //TODO rename +#define B43_OFDMTAB_GAIN1 B43_OFDMTAB(0x01, 4) +#define B43_OFDMTAB_AGC3 B43_OFDMTAB(0x02, 0) +#define B43_OFDMTAB_GAIN2 B43_OFDMTAB(0x02, 3) +#define B43_OFDMTAB_LNAHPFGAIN1 B43_OFDMTAB(0x03, 0) +#define B43_OFDMTAB_WRSSI B43_OFDMTAB(0x04, 0) +#define B43_OFDMTAB_LNAHPFGAIN2 B43_OFDMTAB(0x04, 0) +#define B43_OFDMTAB_NOISESCALE B43_OFDMTAB(0x05, 0) +#define B43_OFDMTAB_AGC2 B43_OFDMTAB(0x06, 0) +#define B43_OFDMTAB_ROTOR B43_OFDMTAB(0x08, 0) +#define B43_OFDMTAB_ADVRETARD B43_OFDMTAB(0x09, 0) +#define B43_OFDMTAB_DAC B43_OFDMTAB(0x0C, 0) +#define B43_OFDMTAB_DC B43_OFDMTAB(0x0E, 7) +#define B43_OFDMTAB_PWRDYN2 B43_OFDMTAB(0x0E, 12) +#define B43_OFDMTAB_LNAGAIN B43_OFDMTAB(0x0E, 13) +//TODO +#define B43_OFDMTAB_LPFGAIN B43_OFDMTAB(0x0F, 12) +#define B43_OFDMTAB_RSSI B43_OFDMTAB(0x10, 0) +//TODO +#define B43_OFDMTAB_AGC1_R1 B43_OFDMTAB(0x13, 0) +#define B43_OFDMTAB_GAINX_R1 B43_OFDMTAB(0x14, 0) //TODO rename +#define B43_OFDMTAB_MINSIGSQ B43_OFDMTAB(0x14, 1) +#define B43_OFDMTAB_AGC3_R1 B43_OFDMTAB(0x15, 0) +#define B43_OFDMTAB_WRSSI_R1 B43_OFDMTAB(0x15, 4) +#define B43_OFDMTAB_TSSI B43_OFDMTAB(0x15, 0) +#define B43_OFDMTAB_DACRFPABB B43_OFDMTAB(0x16, 0) +#define B43_OFDMTAB_DACOFF B43_OFDMTAB(0x17, 0) +#define B43_OFDMTAB_DCBIAS B43_OFDMTAB(0x18, 0) + +u16 b43_ofdmtab_read16(struct b43_wldev *dev, u16 table, u16 offset); +void b43_ofdmtab_write16(struct b43_wldev *dev, u16 table, + u16 offset, u16 value); +u32 b43_ofdmtab_read32(struct b43_wldev *dev, u16 table, u16 offset); +void b43_ofdmtab_write32(struct b43_wldev *dev, u16 table, + u16 offset, u32 value); + +/*** G-PHY table numbers */ +#define B43_GTAB(number, offset) (((number) << B43_PHY_GTABNR_SHIFT) | (offset)) +#define B43_GTAB_NRSSI B43_GTAB(0x00, 0) +#define B43_GTAB_TRFEMW B43_GTAB(0x0C, 0x120) +#define B43_GTAB_ORIGTR B43_GTAB(0x2E, 0x298) + +u16 b43_gtab_read(struct b43_wldev *dev, u16 table, u16 offset); //TODO implement +void b43_gtab_write(struct b43_wldev *dev, u16 table, u16 offset, u16 value); //TODO implement + +#define B43_DEFAULT_CHANNEL_A 36 +#define B43_DEFAULT_CHANNEL_BG 6 + +enum { + B43_ANTENNA0, /* Antenna 0 */ + B43_ANTENNA1, /* Antenna 0 */ + B43_ANTENNA_AUTO1, /* Automatic, starting with antenna 1 */ + B43_ANTENNA_AUTO0, /* Automatic, starting with antenna 0 */ + + B43_ANTENNA_AUTO = B43_ANTENNA_AUTO0, + B43_ANTENNA_DEFAULT = B43_ANTENNA_AUTO, +}; + +enum { + B43_INTERFMODE_NONE, + B43_INTERFMODE_NONWLAN, + B43_INTERFMODE_MANUALWLAN, + B43_INTERFMODE_AUTOWLAN, +}; + +/* Masks for the different PHY versioning registers. */ +#define B43_PHYVER_ANALOG 0xF000 +#define B43_PHYVER_ANALOG_SHIFT 12 +#define B43_PHYVER_TYPE 0x0F00 +#define B43_PHYVER_TYPE_SHIFT 8 +#define B43_PHYVER_VERSION 0x00FF + +void b43_raw_phy_lock(struct b43_wldev *dev); +#define b43_phy_lock(dev, flags) \ + do { \ + local_irq_save(flags); \ + b43_raw_phy_lock(dev); \ + } while (0) +void b43_raw_phy_unlock(struct b43_wldev *dev); +#define b43_phy_unlock(dev, flags) \ + do { \ + b43_raw_phy_unlock(dev); \ + local_irq_restore(flags); \ + } while (0) + +u16 b43_phy_read(struct b43_wldev *dev, u16 offset); +void b43_phy_write(struct b43_wldev *dev, u16 offset, u16 val); + +int b43_phy_init_tssi2dbm_table(struct b43_wldev *dev); + +void b43_phy_early_init(struct b43_wldev *dev); +int b43_phy_init(struct b43_wldev *dev); + +void b43_set_rx_antenna(struct b43_wldev *dev, int antenna); + +void b43_phy_xmitpower(struct b43_wldev *dev); +void b43_gphy_dc_lt_init(struct b43_wldev *dev); + +/* Returns the boolean whether the board has HardwarePowerControl */ +bool b43_has_hardware_pctl(struct b43_phy *phy); +/* Returns the boolean whether "TX Magnification" is enabled. */ +#define has_tx_magnification(phy) \ + (((phy)->rev >= 2) && \ + ((phy)->radio_ver == 0x2050) && \ + ((phy)->radio_rev == 8)) +/* Card uses the loopback gain stuff */ +#define has_loopback_gain(phy) \ + (((phy)->rev > 1) || ((phy)->gmode)) + +/* Radio Attenuation (RF Attenuation) */ +struct b43_rfatt { + u8 att; /* Attenuation value */ + bool with_padmix; /* Flag, PAD Mixer enabled. */ +}; +struct b43_rfatt_list { + /* Attenuation values list */ + const struct b43_rfatt *list; + u8 len; + /* Minimum/Maximum attenuation values */ + u8 min_val; + u8 max_val; +}; + +/* Baseband Attenuation */ +struct b43_bbatt { + u8 att; /* Attenuation value */ +}; +struct b43_bbatt_list { + /* Attenuation values list */ + const struct b43_bbatt *list; + u8 len; + /* Minimum/Maximum attenuation values */ + u8 min_val; + u8 max_val; +}; + +/* tx_control bits. */ +#define B43_TXCTL_PA3DB 0x40 /* PA Gain 3dB */ +#define B43_TXCTL_PA2DB 0x20 /* PA Gain 2dB */ +#define B43_TXCTL_TXMIX 0x10 /* TX Mixer Gain */ + +/* Write BasebandAttenuation value to the device. */ +void b43_phy_set_baseband_attenuation(struct b43_wldev *dev, + u16 baseband_attenuation); + +extern const u8 b43_radio_channel_codes_bg[]; + +void b43_radio_lock(struct b43_wldev *dev); +void b43_radio_unlock(struct b43_wldev *dev); + +u16 b43_radio_read16(struct b43_wldev *dev, u16 offset); +void b43_radio_write16(struct b43_wldev *dev, u16 offset, u16 val); + +u16 b43_radio_init2050(struct b43_wldev *dev); +void b43_radio_init2060(struct b43_wldev *dev); + +void b43_radio_turn_on(struct b43_wldev *dev); +void b43_radio_turn_off(struct b43_wldev *dev); + +int b43_radio_selectchannel(struct b43_wldev *dev, u8 channel, + int synthetic_pu_workaround); + +u8 b43_radio_aci_detect(struct b43_wldev *dev, u8 channel); +u8 b43_radio_aci_scan(struct b43_wldev *dev); + +int b43_radio_set_interference_mitigation(struct b43_wldev *dev, int mode); + +void b43_calc_nrssi_slope(struct b43_wldev *dev); +void b43_calc_nrssi_threshold(struct b43_wldev *dev); +s16 b43_nrssi_hw_read(struct b43_wldev *dev, u16 offset); +void b43_nrssi_hw_write(struct b43_wldev *dev, u16 offset, s16 val); +void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val); +void b43_nrssi_mem_update(struct b43_wldev *dev); + +void b43_radio_set_tx_iq(struct b43_wldev *dev); +u16 b43_radio_calibrationvalue(struct b43_wldev *dev); + +void b43_put_attenuation_into_ranges(struct b43_wldev *dev, + int *_bbatt, int *_rfatt); + +void b43_set_txpower_g(struct b43_wldev *dev, + const struct b43_bbatt *bbatt, + const struct b43_rfatt *rfatt, u8 tx_control); + +#endif /* B43_PHY_H_ */ diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c new file mode 100644 index 00000000000..4ac91fdd356 --- /dev/null +++ b/drivers/net/wireless/b43/pio.c @@ -0,0 +1,650 @@ +/* + + Broadcom B43 wireless driver + + PIO Transmission + + Copyright (c) 2005 Michael Buesch + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "b43.h" +#include "pio.h" +#include "main.h" +#include "xmit.h" + +#include + +static void tx_start(struct b43_pioqueue *queue) +{ + b43_pio_write(queue, B43_PIO_TXCTL, B43_PIO_TXCTL_INIT); +} + +static void tx_octet(struct b43_pioqueue *queue, u8 octet) +{ + if (queue->need_workarounds) { + b43_pio_write(queue, B43_PIO_TXDATA, octet); + b43_pio_write(queue, B43_PIO_TXCTL, B43_PIO_TXCTL_WRITELO); + } else { + b43_pio_write(queue, B43_PIO_TXCTL, B43_PIO_TXCTL_WRITELO); + b43_pio_write(queue, B43_PIO_TXDATA, octet); + } +} + +static u16 tx_get_next_word(const u8 * txhdr, + const u8 * packet, + size_t txhdr_size, unsigned int *pos) +{ + const u8 *source; + unsigned int i = *pos; + u16 ret; + + if (i < txhdr_size) { + source = txhdr; + } else { + source = packet; + i -= txhdr_size; + } + ret = le16_to_cpu(*((u16 *) (source + i))); + *pos += 2; + + return ret; +} + +static void tx_data(struct b43_pioqueue *queue, + u8 * txhdr, const u8 * packet, unsigned int octets) +{ + u16 data; + unsigned int i = 0; + + if (queue->need_workarounds) { + data = tx_get_next_word(txhdr, packet, + sizeof(struct b43_txhdr_fw4), &i); + b43_pio_write(queue, B43_PIO_TXDATA, data); + } + b43_pio_write(queue, B43_PIO_TXCTL, + B43_PIO_TXCTL_WRITELO | B43_PIO_TXCTL_WRITEHI); + while (i < octets - 1) { + data = tx_get_next_word(txhdr, packet, + sizeof(struct b43_txhdr_fw4), &i); + b43_pio_write(queue, B43_PIO_TXDATA, data); + } + if (octets % 2) + tx_octet(queue, + packet[octets - sizeof(struct b43_txhdr_fw4) - 1]); +} + +static void tx_complete(struct b43_pioqueue *queue, struct sk_buff *skb) +{ + if (queue->need_workarounds) { + b43_pio_write(queue, B43_PIO_TXDATA, skb->data[skb->len - 1]); + b43_pio_write(queue, B43_PIO_TXCTL, + B43_PIO_TXCTL_WRITELO | B43_PIO_TXCTL_COMPLETE); + } else { + b43_pio_write(queue, B43_PIO_TXCTL, B43_PIO_TXCTL_COMPLETE); + } +} + +static u16 generate_cookie(struct b43_pioqueue *queue, + struct b43_pio_txpacket *packet) +{ + u16 cookie = 0x0000; + int packetindex; + + /* We use the upper 4 bits for the PIO + * controller ID and the lower 12 bits + * for the packet index (in the cache). + */ + switch (queue->mmio_base) { + case B43_MMIO_PIO1_BASE: + break; + case B43_MMIO_PIO2_BASE: + cookie = 0x1000; + break; + case B43_MMIO_PIO3_BASE: + cookie = 0x2000; + break; + case B43_MMIO_PIO4_BASE: + cookie = 0x3000; + break; + default: + B43_WARN_ON(1); + } + packetindex = pio_txpacket_getindex(packet); + B43_WARN_ON(packetindex & ~0x0FFF); + cookie |= (u16) packetindex; + + return cookie; +} + +static +struct b43_pioqueue *parse_cookie(struct b43_wldev *dev, + u16 cookie, struct b43_pio_txpacket **packet) +{ + struct b43_pio *pio = &dev->pio; + struct b43_pioqueue *queue = NULL; + int packetindex; + + switch (cookie & 0xF000) { + case 0x0000: + queue = pio->queue0; + break; + case 0x1000: + queue = pio->queue1; + break; + case 0x2000: + queue = pio->queue2; + break; + case 0x3000: + queue = pio->queue3; + break; + default: + B43_WARN_ON(1); + } + packetindex = (cookie & 0x0FFF); + B43_WARN_ON(!(packetindex >= 0 && packetindex < B43_PIO_MAXTXPACKETS)); + *packet = &(queue->tx_packets_cache[packetindex]); + + return queue; +} + +union txhdr_union { + struct b43_txhdr_fw4 txhdr_fw4; +}; + +static void pio_tx_write_fragment(struct b43_pioqueue *queue, + struct sk_buff *skb, + struct b43_pio_txpacket *packet, + size_t txhdr_size) +{ + union txhdr_union txhdr_data; + u8 *txhdr = NULL; + unsigned int octets; + + txhdr = (u8 *) (&txhdr_data.txhdr_fw4); + + B43_WARN_ON(skb_shinfo(skb)->nr_frags); + b43_generate_txhdr(queue->dev, + txhdr, skb->data, skb->len, + &packet->txstat.control, + generate_cookie(queue, packet)); + + tx_start(queue); + octets = skb->len + txhdr_size; + if (queue->need_workarounds) + octets--; + tx_data(queue, txhdr, (u8 *) skb->data, octets); + tx_complete(queue, skb); +} + +static void free_txpacket(struct b43_pio_txpacket *packet) +{ + struct b43_pioqueue *queue = packet->queue; + + if (packet->skb) + dev_kfree_skb_any(packet->skb); + list_move(&packet->list, &queue->txfree); + queue->nr_txfree++; +} + +static int pio_tx_packet(struct b43_pio_txpacket *packet) +{ + struct b43_pioqueue *queue = packet->queue; + struct sk_buff *skb = packet->skb; + u16 octets; + + octets = (u16) skb->len + sizeof(struct b43_txhdr_fw4); + if (queue->tx_devq_size < octets) { + b43warn(queue->dev->wl, "PIO queue too small. " + "Dropping packet.\n"); + /* Drop it silently (return success) */ + free_txpacket(packet); + return 0; + } + B43_WARN_ON(queue->tx_devq_packets > B43_PIO_MAXTXDEVQPACKETS); + B43_WARN_ON(queue->tx_devq_used > queue->tx_devq_size); + /* Check if there is sufficient free space on the device + * TX queue. If not, return and let the TX tasklet + * retry later. + */ + if (queue->tx_devq_packets == B43_PIO_MAXTXDEVQPACKETS) + return -EBUSY; + if (queue->tx_devq_used + octets > queue->tx_devq_size) + return -EBUSY; + /* Now poke the device. */ + pio_tx_write_fragment(queue, skb, packet, sizeof(struct b43_txhdr_fw4)); + + /* Account for the packet size. + * (We must not overflow the device TX queue) + */ + queue->tx_devq_packets++; + queue->tx_devq_used += octets; + + /* Transmission started, everything ok, move the + * packet to the txrunning list. + */ + list_move_tail(&packet->list, &queue->txrunning); + + return 0; +} + +static void tx_tasklet(unsigned long d) +{ + struct b43_pioqueue *queue = (struct b43_pioqueue *)d; + struct b43_wldev *dev = queue->dev; + unsigned long flags; + struct b43_pio_txpacket *packet, *tmp_packet; + int err; + u16 txctl; + + spin_lock_irqsave(&dev->wl->irq_lock, flags); + if (queue->tx_frozen) + goto out_unlock; + txctl = b43_pio_read(queue, B43_PIO_TXCTL); + if (txctl & B43_PIO_TXCTL_SUSPEND) + goto out_unlock; + + list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) { + /* Try to transmit the packet. This can fail, if + * the device queue is full. In case of failure, the + * packet is left in the txqueue. + * If transmission succeed, the packet is moved to txrunning. + * If it is impossible to transmit the packet, it + * is dropped. + */ + err = pio_tx_packet(packet); + if (err) + break; + } + out_unlock: + spin_unlock_irqrestore(&dev->wl->irq_lock, flags); +} + +static void setup_txqueues(struct b43_pioqueue *queue) +{ + struct b43_pio_txpacket *packet; + int i; + + queue->nr_txfree = B43_PIO_MAXTXPACKETS; + for (i = 0; i < B43_PIO_MAXTXPACKETS; i++) { + packet = &(queue->tx_packets_cache[i]); + + packet->queue = queue; + INIT_LIST_HEAD(&packet->list); + + list_add(&packet->list, &queue->txfree); + } +} + +static +struct b43_pioqueue *b43_setup_pioqueue(struct b43_wldev *dev, + u16 pio_mmio_base) +{ + struct b43_pioqueue *queue; + u16 qsize; + + queue = kzalloc(sizeof(*queue), GFP_KERNEL); + if (!queue) + goto out; + + queue->dev = dev; + queue->mmio_base = pio_mmio_base; + queue->need_workarounds = (dev->dev->id.revision < 3); + + INIT_LIST_HEAD(&queue->txfree); + INIT_LIST_HEAD(&queue->txqueue); + INIT_LIST_HEAD(&queue->txrunning); + tasklet_init(&queue->txtask, tx_tasklet, (unsigned long)queue); + + b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL) + & ~B43_MACCTL_BE); + + qsize = b43_read16(dev, queue->mmio_base + B43_PIO_TXQBUFSIZE); + if (qsize == 0) { + b43err(dev->wl, "This card does not support PIO " + "operation mode. Please use DMA mode " + "(module parameter pio=0).\n"); + goto err_freequeue; + } + if (qsize <= B43_PIO_TXQADJUST) { + b43err(dev->wl, "PIO tx device-queue too small (%u)\n", qsize); + goto err_freequeue; + } + qsize -= B43_PIO_TXQADJUST; + queue->tx_devq_size = qsize; + + setup_txqueues(queue); + + out: + return queue; + + err_freequeue: + kfree(queue); + queue = NULL; + goto out; +} + +static void cancel_transfers(struct b43_pioqueue *queue) +{ + struct b43_pio_txpacket *packet, *tmp_packet; + + tasklet_disable(&queue->txtask); + + list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list) + free_txpacket(packet); + list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) + free_txpacket(packet); +} + +static void b43_destroy_pioqueue(struct b43_pioqueue *queue) +{ + if (!queue) + return; + + cancel_transfers(queue); + kfree(queue); +} + +void b43_pio_free(struct b43_wldev *dev) +{ + struct b43_pio *pio; + + if (!b43_using_pio(dev)) + return; + pio = &dev->pio; + + b43_destroy_pioqueue(pio->queue3); + pio->queue3 = NULL; + b43_destroy_pioqueue(pio->queue2); + pio->queue2 = NULL; + b43_destroy_pioqueue(pio->queue1); + pio->queue1 = NULL; + b43_destroy_pioqueue(pio->queue0); + pio->queue0 = NULL; +} + +int b43_pio_init(struct b43_wldev *dev) +{ + struct b43_pio *pio = &dev->pio; + struct b43_pioqueue *queue; + int err = -ENOMEM; + + queue = b43_setup_pioqueue(dev, B43_MMIO_PIO1_BASE); + if (!queue) + goto out; + pio->queue0 = queue; + + queue = b43_setup_pioqueue(dev, B43_MMIO_PIO2_BASE); + if (!queue) + goto err_destroy0; + pio->queue1 = queue; + + queue = b43_setup_pioqueue(dev, B43_MMIO_PIO3_BASE); + if (!queue) + goto err_destroy1; + pio->queue2 = queue; + + queue = b43_setup_pioqueue(dev, B43_MMIO_PIO4_BASE); + if (!queue) + goto err_destroy2; + pio->queue3 = queue; + + if (dev->dev->id.revision < 3) + dev->irq_savedstate |= B43_IRQ_PIO_WORKAROUND; + + b43dbg(dev->wl, "PIO initialized\n"); + err = 0; + out: + return err; + + err_destroy2: + b43_destroy_pioqueue(pio->queue2); + pio->queue2 = NULL; + err_destroy1: + b43_destroy_pioqueue(pio->queue1); + pio->queue1 = NULL; + err_destroy0: + b43_destroy_pioqueue(pio->queue0); + pio->queue0 = NULL; + goto out; +} + +int b43_pio_tx(struct b43_wldev *dev, + struct sk_buff *skb, struct ieee80211_tx_control *ctl) +{ + struct b43_pioqueue *queue = dev->pio.queue1; + struct b43_pio_txpacket *packet; + + B43_WARN_ON(queue->tx_suspended); + B43_WARN_ON(list_empty(&queue->txfree)); + + packet = list_entry(queue->txfree.next, struct b43_pio_txpacket, list); + packet->skb = skb; + + memset(&packet->txstat, 0, sizeof(packet->txstat)); + memcpy(&packet->txstat.control, ctl, sizeof(*ctl)); + + list_move_tail(&packet->list, &queue->txqueue); + queue->nr_txfree--; + queue->nr_tx_packets++; + B43_WARN_ON(queue->nr_txfree >= B43_PIO_MAXTXPACKETS); + + tasklet_schedule(&queue->txtask); + + return 0; +} + +void b43_pio_handle_txstatus(struct b43_wldev *dev, + const struct b43_txstatus *status) +{ + struct b43_pioqueue *queue; + struct b43_pio_txpacket *packet; + + queue = parse_cookie(dev, status->cookie, &packet); + if (B43_WARN_ON(!queue)) + return; + + queue->tx_devq_packets--; + queue->tx_devq_used -= + (packet->skb->len + sizeof(struct b43_txhdr_fw4)); + + if (status->acked) { + packet->txstat.flags |= IEEE80211_TX_STATUS_ACK; + } else { + if (!(packet->txstat.control.flags & IEEE80211_TXCTL_NO_ACK)) + packet->txstat.excessive_retries = 1; + } + if (status->frame_count == 0) { + /* The frame was not transmitted at all. */ + packet->txstat.retry_count = 0; + } else + packet->txstat.retry_count = status->frame_count - 1; + ieee80211_tx_status_irqsafe(dev->wl->hw, packet->skb, + &(packet->txstat)); + packet->skb = NULL; + + free_txpacket(packet); + /* If there are packets on the txqueue, poke the tasklet + * to transmit them. + */ + if (!list_empty(&queue->txqueue)) + tasklet_schedule(&queue->txtask); +} + +void b43_pio_get_tx_stats(struct b43_wldev *dev, + struct ieee80211_tx_queue_stats *stats) +{ + struct b43_pio *pio = &dev->pio; + struct b43_pioqueue *queue; + struct ieee80211_tx_queue_stats_data *data; + + queue = pio->queue1; + data = &(stats->data[0]); + data->len = B43_PIO_MAXTXPACKETS - queue->nr_txfree; + data->limit = B43_PIO_MAXTXPACKETS; + data->count = queue->nr_tx_packets; +} + +static void pio_rx_error(struct b43_pioqueue *queue, + int clear_buffers, const char *error) +{ + int i; + + b43err(queue->dev->wl, "PIO RX error: %s\n", error); + b43_pio_write(queue, B43_PIO_RXCTL, B43_PIO_RXCTL_READY); + if (clear_buffers) { + B43_WARN_ON(queue->mmio_base != B43_MMIO_PIO1_BASE); + for (i = 0; i < 15; i++) { + /* Dummy read. */ + b43_pio_read(queue, B43_PIO_RXDATA); + } + } +} + +void b43_pio_rx(struct b43_pioqueue *queue) +{ + u16 preamble[21] = { 0 }; + struct b43_rxhdr_fw4 *rxhdr; + u16 tmp, len, macstat; + int i, preamble_readwords; + struct sk_buff *skb; + + tmp = b43_pio_read(queue, B43_PIO_RXCTL); + if (!(tmp & B43_PIO_RXCTL_DATAAVAILABLE)) + return; + b43_pio_write(queue, B43_PIO_RXCTL, B43_PIO_RXCTL_DATAAVAILABLE); + + for (i = 0; i < 10; i++) { + tmp = b43_pio_read(queue, B43_PIO_RXCTL); + if (tmp & B43_PIO_RXCTL_READY) + goto data_ready; + udelay(10); + } + b43dbg(queue->dev->wl, "PIO RX timed out\n"); + return; + data_ready: + + len = b43_pio_read(queue, B43_PIO_RXDATA); + if (unlikely(len > 0x700)) { + pio_rx_error(queue, 0, "len > 0x700"); + return; + } + if (unlikely(len == 0 && queue->mmio_base != B43_MMIO_PIO4_BASE)) { + pio_rx_error(queue, 0, "len == 0"); + return; + } + preamble[0] = cpu_to_le16(len); + if (queue->mmio_base == B43_MMIO_PIO4_BASE) + preamble_readwords = 14 / sizeof(u16); + else + preamble_readwords = 18 / sizeof(u16); + for (i = 0; i < preamble_readwords; i++) { + tmp = b43_pio_read(queue, B43_PIO_RXDATA); + preamble[i + 1] = cpu_to_le16(tmp); + } + rxhdr = (struct b43_rxhdr_fw4 *)preamble; + macstat = le16_to_cpu(rxhdr->mac_status); + if (macstat & B43_RX_MAC_FCSERR) { + pio_rx_error(queue, + (queue->mmio_base == B43_MMIO_PIO1_BASE), + "Frame FCS error"); + return; + } + if (queue->mmio_base == B43_MMIO_PIO4_BASE) { + /* We received an xmit status. */ + struct b43_hwtxstatus *hw; + + hw = (struct b43_hwtxstatus *)(preamble + 1); + b43_handle_hwtxstatus(queue->dev, hw); + + return; + } + + skb = dev_alloc_skb(len); + if (unlikely(!skb)) { + pio_rx_error(queue, 1, "OOM"); + return; + } + skb_put(skb, len); + for (i = 0; i < len - 1; i += 2) { + tmp = b43_pio_read(queue, B43_PIO_RXDATA); + *((u16 *) (skb->data + i)) = cpu_to_le16(tmp); + } + if (len % 2) { + tmp = b43_pio_read(queue, B43_PIO_RXDATA); + skb->data[len - 1] = (tmp & 0x00FF); +/* The specs say the following is required, but + * it is wrong and corrupts the PLCP. If we don't do + * this, the PLCP seems to be correct. So ifdef it out for now. + */ +#if 0 + if (rxflags2 & B43_RXHDR_FLAGS2_TYPE2FRAME) + skb->data[2] = (tmp & 0xFF00) >> 8; + else + skb->data[0] = (tmp & 0xFF00) >> 8; +#endif + } + b43_rx(queue->dev, skb, rxhdr); +} + +void b43_pio_tx_suspend(struct b43_pioqueue *queue) +{ + b43_power_saving_ctl_bits(queue->dev, B43_PS_AWAKE); + b43_pio_write(queue, B43_PIO_TXCTL, b43_pio_read(queue, B43_PIO_TXCTL) + | B43_PIO_TXCTL_SUSPEND); +} + +void b43_pio_tx_resume(struct b43_pioqueue *queue) +{ + b43_pio_write(queue, B43_PIO_TXCTL, b43_pio_read(queue, B43_PIO_TXCTL) + & ~B43_PIO_TXCTL_SUSPEND); + b43_power_saving_ctl_bits(queue->dev, 0); + tasklet_schedule(&queue->txtask); +} + +void b43_pio_freeze_txqueues(struct b43_wldev *dev) +{ + struct b43_pio *pio; + + B43_WARN_ON(!b43_using_pio(dev)); + pio = &dev->pio; + pio->queue0->tx_frozen = 1; + pio->queue1->tx_frozen = 1; + pio->queue2->tx_frozen = 1; + pio->queue3->tx_frozen = 1; +} + +void b43_pio_thaw_txqueues(struct b43_wldev *dev) +{ + struct b43_pio *pio; + + B43_WARN_ON(!b43_using_pio(dev)); + pio = &dev->pio; + pio->queue0->tx_frozen = 0; + pio->queue1->tx_frozen = 0; + pio->queue2->tx_frozen = 0; + pio->queue3->tx_frozen = 0; + if (!list_empty(&pio->queue0->txqueue)) + tasklet_schedule(&pio->queue0->txtask); + if (!list_empty(&pio->queue1->txqueue)) + tasklet_schedule(&pio->queue1->txtask); + if (!list_empty(&pio->queue2->txqueue)) + tasklet_schedule(&pio->queue2->txtask); + if (!list_empty(&pio->queue3->txqueue)) + tasklet_schedule(&pio->queue3->txtask); +} diff --git a/drivers/net/wireless/b43/pio.h b/drivers/net/wireless/b43/pio.h new file mode 100644 index 00000000000..46d6d2ea9b5 --- /dev/null +++ b/drivers/net/wireless/b43/pio.h @@ -0,0 +1,153 @@ +#ifndef B43_PIO_H_ +#define B43_PIO_H_ + +#include "b43.h" + +#include +#include +#include + +#define B43_PIO_TXCTL 0x00 +#define B43_PIO_TXDATA 0x02 +#define B43_PIO_TXQBUFSIZE 0x04 +#define B43_PIO_RXCTL 0x08 +#define B43_PIO_RXDATA 0x0A + +#define B43_PIO_TXCTL_WRITELO (1 << 0) +#define B43_PIO_TXCTL_WRITEHI (1 << 1) +#define B43_PIO_TXCTL_COMPLETE (1 << 2) +#define B43_PIO_TXCTL_INIT (1 << 3) +#define B43_PIO_TXCTL_SUSPEND (1 << 7) + +#define B43_PIO_RXCTL_DATAAVAILABLE (1 << 0) +#define B43_PIO_RXCTL_READY (1 << 1) + +/* PIO constants */ +#define B43_PIO_MAXTXDEVQPACKETS 31 +#define B43_PIO_TXQADJUST 80 + +/* PIO tuning knobs */ +#define B43_PIO_MAXTXPACKETS 256 + +#ifdef CONFIG_B43_PIO + +struct b43_pioqueue; +struct b43_xmitstatus; + +struct b43_pio_txpacket { + struct b43_pioqueue *queue; + struct sk_buff *skb; + struct ieee80211_tx_status txstat; + struct list_head list; +}; + +#define pio_txpacket_getindex(packet) ((int)((packet) - (packet)->queue->tx_packets_cache)) + +struct b43_pioqueue { + struct b43_wldev *dev; + u16 mmio_base; + + bool tx_suspended; + bool tx_frozen; + bool need_workarounds; /* Workarounds needed for core.rev < 3 */ + + /* Adjusted size of the device internal TX buffer. */ + u16 tx_devq_size; + /* Used octets of the device internal TX buffer. */ + u16 tx_devq_used; + /* Used packet slots in the device internal TX buffer. */ + u8 tx_devq_packets; + /* Packets from the txfree list can + * be taken on incoming TX requests. + */ + struct list_head txfree; + unsigned int nr_txfree; + /* Packets on the txqueue are queued, + * but not completely written to the chip, yet. + */ + struct list_head txqueue; + /* Packets on the txrunning queue are completely + * posted to the device. We are waiting for the txstatus. + */ + struct list_head txrunning; + /* Total number or packets sent. + * (This counter can obviously wrap). + */ + unsigned int nr_tx_packets; + struct tasklet_struct txtask; + struct b43_pio_txpacket tx_packets_cache[B43_PIO_MAXTXPACKETS]; +}; + +static inline u16 b43_pio_read(struct b43_pioqueue *queue, u16 offset) +{ + return b43_read16(queue->dev, queue->mmio_base + offset); +} + +static inline + void b43_pio_write(struct b43_pioqueue *queue, u16 offset, u16 value) +{ + b43_write16(queue->dev, queue->mmio_base + offset, value); + mmiowb(); +} + +int b43_pio_init(struct b43_wldev *dev); +void b43_pio_free(struct b43_wldev *dev); + +int b43_pio_tx(struct b43_wldev *dev, + struct sk_buff *skb, struct ieee80211_tx_control *ctl); +void b43_pio_handle_txstatus(struct b43_wldev *dev, + const struct b43_txstatus *status); +void b43_pio_get_tx_stats(struct b43_wldev *dev, + struct ieee80211_tx_queue_stats *stats); +void b43_pio_rx(struct b43_pioqueue *queue); + +/* Suspend TX queue in hardware. */ +void b43_pio_tx_suspend(struct b43_pioqueue *queue); +void b43_pio_tx_resume(struct b43_pioqueue *queue); +/* Suspend (freeze) the TX tasklet (software level). */ +void b43_pio_freeze_txqueues(struct b43_wldev *dev); +void b43_pio_thaw_txqueues(struct b43_wldev *dev); + +#else /* CONFIG_B43_PIO */ + +static inline int b43_pio_init(struct b43_wldev *dev) +{ + return 0; +} +static inline void b43_pio_free(struct b43_wldev *dev) +{ +} +static inline + int b43_pio_tx(struct b43_wldev *dev, + struct sk_buff *skb, struct ieee80211_tx_control *ctl) +{ + return 0; +} +static inline + void b43_pio_handle_txstatus(struct b43_wldev *dev, + const struct b43_txstatus *status) +{ +} +static inline + void b43_pio_get_tx_stats(struct b43_wldev *dev, + struct ieee80211_tx_queue_stats *stats) +{ +} +static inline void b43_pio_rx(struct b43_pioqueue *queue) +{ +} +static inline void b43_pio_tx_suspend(struct b43_pioqueue *queue) +{ +} +static inline void b43_pio_tx_resume(struct b43_pioqueue *queue) +{ +} +static inline void b43_pio_freeze_txqueues(struct b43_wldev *dev) +{ +} +static inline void b43_pio_thaw_txqueues(struct b43_wldev *dev) +{ +} + +#endif /* CONFIG_B43_PIO */ +#endif /* B43_PIO_H_ */ diff --git a/drivers/net/wireless/b43/sysfs.c b/drivers/net/wireless/b43/sysfs.c new file mode 100644 index 00000000000..fcb777383e7 --- /dev/null +++ b/drivers/net/wireless/b43/sysfs.c @@ -0,0 +1,235 @@ +/* + + Broadcom B43 wireless driver + + SYSFS support routines + + Copyright (c) 2006 Michael Buesch + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "b43.h" +#include "sysfs.h" +#include "main.h" +#include "phy.h" + +#include + +#define GENERIC_FILESIZE 64 + +static int get_integer(const char *buf, size_t count) +{ + char tmp[10 + 1] = { 0 }; + int ret = -EINVAL; + + if (count == 0) + goto out; + count = min(count, (size_t) 10); + memcpy(tmp, buf, count); + ret = simple_strtol(tmp, NULL, 10); + out: + return ret; +} + +static int get_boolean(const char *buf, size_t count) +{ + if (count != 0) { + if (buf[0] == '1') + return 1; + if (buf[0] == '0') + return 0; + if (count >= 4 && memcmp(buf, "true", 4) == 0) + return 1; + if (count >= 5 && memcmp(buf, "false", 5) == 0) + return 0; + if (count >= 3 && memcmp(buf, "yes", 3) == 0) + return 1; + if (count >= 2 && memcmp(buf, "no", 2) == 0) + return 0; + if (count >= 2 && memcmp(buf, "on", 2) == 0) + return 1; + if (count >= 3 && memcmp(buf, "off", 3) == 0) + return 0; + } + return -EINVAL; +} + +static ssize_t b43_attr_interfmode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct b43_wldev *wldev = dev_to_b43_wldev(dev); + ssize_t count = 0; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + mutex_lock(&wldev->wl->mutex); + + switch (wldev->phy.interfmode) { + case B43_INTERFMODE_NONE: + count = + snprintf(buf, PAGE_SIZE, + "0 (No Interference Mitigation)\n"); + break; + case B43_INTERFMODE_NONWLAN: + count = + snprintf(buf, PAGE_SIZE, + "1 (Non-WLAN Interference Mitigation)\n"); + break; + case B43_INTERFMODE_MANUALWLAN: + count = + snprintf(buf, PAGE_SIZE, + "2 (WLAN Interference Mitigation)\n"); + break; + default: + B43_WARN_ON(1); + } + + mutex_unlock(&wldev->wl->mutex); + + return count; +} + +static ssize_t b43_attr_interfmode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct b43_wldev *wldev = dev_to_b43_wldev(dev); + unsigned long flags; + int err; + int mode; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + mode = get_integer(buf, count); + switch (mode) { + case 0: + mode = B43_INTERFMODE_NONE; + break; + case 1: + mode = B43_INTERFMODE_NONWLAN; + break; + case 2: + mode = B43_INTERFMODE_MANUALWLAN; + break; + case 3: + mode = B43_INTERFMODE_AUTOWLAN; + break; + default: + return -EINVAL; + } + + mutex_lock(&wldev->wl->mutex); + spin_lock_irqsave(&wldev->wl->irq_lock, flags); + + err = b43_radio_set_interference_mitigation(wldev, mode); + if (err) { + b43err(wldev->wl, "Interference Mitigation not " + "supported by device\n"); + } + mmiowb(); + spin_unlock_irqrestore(&wldev->wl->irq_lock, flags); + mutex_unlock(&wldev->wl->mutex); + + return err ? err : count; +} + +static DEVICE_ATTR(interference, 0644, + b43_attr_interfmode_show, b43_attr_interfmode_store); + +static ssize_t b43_attr_preamble_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct b43_wldev *wldev = dev_to_b43_wldev(dev); + ssize_t count; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + mutex_lock(&wldev->wl->mutex); + + if (wldev->short_preamble) + count = + snprintf(buf, PAGE_SIZE, "1 (Short Preamble enabled)\n"); + else + count = + snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n"); + + mutex_unlock(&wldev->wl->mutex); + + return count; +} + +static ssize_t b43_attr_preamble_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct b43_wldev *wldev = dev_to_b43_wldev(dev); + unsigned long flags; + int value; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + value = get_boolean(buf, count); + if (value < 0) + return value; + mutex_lock(&wldev->wl->mutex); + spin_lock_irqsave(&wldev->wl->irq_lock, flags); + + wldev->short_preamble = !!value; + + spin_unlock_irqrestore(&wldev->wl->irq_lock, flags); + mutex_unlock(&wldev->wl->mutex); + + return count; +} + +static DEVICE_ATTR(shortpreamble, 0644, + b43_attr_preamble_show, b43_attr_preamble_store); + +int b43_sysfs_register(struct b43_wldev *wldev) +{ + struct device *dev = wldev->dev->dev; + int err; + + B43_WARN_ON(b43_status(wldev) != B43_STAT_INITIALIZED); + + err = device_create_file(dev, &dev_attr_interference); + if (err) + goto out; + err = device_create_file(dev, &dev_attr_shortpreamble); + if (err) + goto err_remove_interfmode; + + out: + return err; + err_remove_interfmode: + device_remove_file(dev, &dev_attr_interference); + goto out; +} + +void b43_sysfs_unregister(struct b43_wldev *wldev) +{ + struct device *dev = wldev->dev->dev; + + device_remove_file(dev, &dev_attr_shortpreamble); + device_remove_file(dev, &dev_attr_interference); +} diff --git a/drivers/net/wireless/b43/sysfs.h b/drivers/net/wireless/b43/sysfs.h new file mode 100644 index 00000000000..12bda9ef1a8 --- /dev/null +++ b/drivers/net/wireless/b43/sysfs.h @@ -0,0 +1,9 @@ +#ifndef B43_SYSFS_H_ +#define B43_SYSFS_H_ + +struct b43_wldev; + +int b43_sysfs_register(struct b43_wldev *dev); +void b43_sysfs_unregister(struct b43_wldev *dev); + +#endif /* B43_SYSFS_H_ */ diff --git a/drivers/net/wireless/b43/tables.c b/drivers/net/wireless/b43/tables.c new file mode 100644 index 00000000000..15a87183a57 --- /dev/null +++ b/drivers/net/wireless/b43/tables.c @@ -0,0 +1,375 @@ +/* + + Broadcom B43 wireless driver + + Copyright (c) 2005 Martin Langer , + Copyright (c) 2005 Stefano Brivio + Copyright (c) 2006, 2006 Michael Buesch + Copyright (c) 2005 Danny van Dyk + Copyright (c) 2005 Andreas Jaggi + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "b43.h" +#include "tables.h" +#include "phy.h" + +const u32 b43_tab_rotor[] = { + 0xFEB93FFD, 0xFEC63FFD, /* 0 */ + 0xFED23FFD, 0xFEDF3FFD, + 0xFEEC3FFE, 0xFEF83FFE, + 0xFF053FFE, 0xFF113FFE, + 0xFF1E3FFE, 0xFF2A3FFF, /* 8 */ + 0xFF373FFF, 0xFF443FFF, + 0xFF503FFF, 0xFF5D3FFF, + 0xFF693FFF, 0xFF763FFF, + 0xFF824000, 0xFF8F4000, /* 16 */ + 0xFF9B4000, 0xFFA84000, + 0xFFB54000, 0xFFC14000, + 0xFFCE4000, 0xFFDA4000, + 0xFFE74000, 0xFFF34000, /* 24 */ + 0x00004000, 0x000D4000, + 0x00194000, 0x00264000, + 0x00324000, 0x003F4000, + 0x004B4000, 0x00584000, /* 32 */ + 0x00654000, 0x00714000, + 0x007E4000, 0x008A3FFF, + 0x00973FFF, 0x00A33FFF, + 0x00B03FFF, 0x00BC3FFF, /* 40 */ + 0x00C93FFF, 0x00D63FFF, + 0x00E23FFE, 0x00EF3FFE, + 0x00FB3FFE, 0x01083FFE, + 0x01143FFE, 0x01213FFD, /* 48 */ + 0x012E3FFD, 0x013A3FFD, + 0x01473FFD, +}; + +const u32 b43_tab_retard[] = { + 0xDB93CB87, 0xD666CF64, /* 0 */ + 0xD1FDD358, 0xCDA6D826, + 0xCA38DD9F, 0xC729E2B4, + 0xC469E88E, 0xC26AEE2B, + 0xC0DEF46C, 0xC073FA62, /* 8 */ + 0xC01D00D5, 0xC0760743, + 0xC1560D1E, 0xC2E51369, + 0xC4ED18FF, 0xC7AC1ED7, + 0xCB2823B2, 0xCEFA28D9, /* 16 */ + 0xD2F62D3F, 0xD7BB3197, + 0xDCE53568, 0xE1FE3875, + 0xE7D13B35, 0xED663D35, + 0xF39B3EC4, 0xF98E3FA7, /* 24 */ + 0x00004000, 0x06723FA7, + 0x0C653EC4, 0x129A3D35, + 0x182F3B35, 0x1E023875, + 0x231B3568, 0x28453197, /* 32 */ + 0x2D0A2D3F, 0x310628D9, + 0x34D823B2, 0x38541ED7, + 0x3B1318FF, 0x3D1B1369, + 0x3EAA0D1E, 0x3F8A0743, /* 40 */ + 0x3FE300D5, 0x3F8DFA62, + 0x3F22F46C, 0x3D96EE2B, + 0x3B97E88E, 0x38D7E2B4, + 0x35C8DD9F, 0x325AD826, /* 48 */ + 0x2E03D358, 0x299ACF64, + 0x246DCB87, +}; + +const u16 b43_tab_finefreqa[] = { + 0x0082, 0x0082, 0x0102, 0x0182, /* 0 */ + 0x0202, 0x0282, 0x0302, 0x0382, + 0x0402, 0x0482, 0x0502, 0x0582, + 0x05E2, 0x0662, 0x06E2, 0x0762, + 0x07E2, 0x0842, 0x08C2, 0x0942, /* 16 */ + 0x09C2, 0x0A22, 0x0AA2, 0x0B02, + 0x0B82, 0x0BE2, 0x0C62, 0x0CC2, + 0x0D42, 0x0DA2, 0x0E02, 0x0E62, + 0x0EE2, 0x0F42, 0x0FA2, 0x1002, /* 32 */ + 0x1062, 0x10C2, 0x1122, 0x1182, + 0x11E2, 0x1242, 0x12A2, 0x12E2, + 0x1342, 0x13A2, 0x1402, 0x1442, + 0x14A2, 0x14E2, 0x1542, 0x1582, /* 48 */ + 0x15E2, 0x1622, 0x1662, 0x16C1, + 0x1701, 0x1741, 0x1781, 0x17E1, + 0x1821, 0x1861, 0x18A1, 0x18E1, + 0x1921, 0x1961, 0x19A1, 0x19E1, /* 64 */ + 0x1A21, 0x1A61, 0x1AA1, 0x1AC1, + 0x1B01, 0x1B41, 0x1B81, 0x1BA1, + 0x1BE1, 0x1C21, 0x1C41, 0x1C81, + 0x1CA1, 0x1CE1, 0x1D01, 0x1D41, /* 80 */ + 0x1D61, 0x1DA1, 0x1DC1, 0x1E01, + 0x1E21, 0x1E61, 0x1E81, 0x1EA1, + 0x1EE1, 0x1F01, 0x1F21, 0x1F41, + 0x1F81, 0x1FA1, 0x1FC1, 0x1FE1, /* 96 */ + 0x2001, 0x2041, 0x2061, 0x2081, + 0x20A1, 0x20C1, 0x20E1, 0x2101, + 0x2121, 0x2141, 0x2161, 0x2181, + 0x21A1, 0x21C1, 0x21E1, 0x2201, /* 112 */ + 0x2221, 0x2241, 0x2261, 0x2281, + 0x22A1, 0x22C1, 0x22C1, 0x22E1, + 0x2301, 0x2321, 0x2341, 0x2361, + 0x2361, 0x2381, 0x23A1, 0x23C1, /* 128 */ + 0x23E1, 0x23E1, 0x2401, 0x2421, + 0x2441, 0x2441, 0x2461, 0x2481, + 0x2481, 0x24A1, 0x24C1, 0x24C1, + 0x24E1, 0x2501, 0x2501, 0x2521, /* 144 */ + 0x2541, 0x2541, 0x2561, 0x2561, + 0x2581, 0x25A1, 0x25A1, 0x25C1, + 0x25C1, 0x25E1, 0x2601, 0x2601, + 0x2621, 0x2621, 0x2641, 0x2641, /* 160 */ + 0x2661, 0x2661, 0x2681, 0x2681, + 0x26A1, 0x26A1, 0x26C1, 0x26C1, + 0x26E1, 0x26E1, 0x2701, 0x2701, + 0x2721, 0x2721, 0x2740, 0x2740, /* 176 */ + 0x2760, 0x2760, 0x2780, 0x2780, + 0x2780, 0x27A0, 0x27A0, 0x27C0, + 0x27C0, 0x27E0, 0x27E0, 0x27E0, + 0x2800, 0x2800, 0x2820, 0x2820, /* 192 */ + 0x2820, 0x2840, 0x2840, 0x2840, + 0x2860, 0x2860, 0x2880, 0x2880, + 0x2880, 0x28A0, 0x28A0, 0x28A0, + 0x28C0, 0x28C0, 0x28C0, 0x28E0, /* 208 */ + 0x28E0, 0x28E0, 0x2900, 0x2900, + 0x2900, 0x2920, 0x2920, 0x2920, + 0x2940, 0x2940, 0x2940, 0x2960, + 0x2960, 0x2960, 0x2960, 0x2980, /* 224 */ + 0x2980, 0x2980, 0x29A0, 0x29A0, + 0x29A0, 0x29A0, 0x29C0, 0x29C0, + 0x29C0, 0x29E0, 0x29E0, 0x29E0, + 0x29E0, 0x2A00, 0x2A00, 0x2A00, /* 240 */ + 0x2A00, 0x2A20, 0x2A20, 0x2A20, + 0x2A20, 0x2A40, 0x2A40, 0x2A40, + 0x2A40, 0x2A60, 0x2A60, 0x2A60, +}; + +const u16 b43_tab_finefreqg[] = { + 0x0089, 0x02E9, 0x0409, 0x04E9, /* 0 */ + 0x05A9, 0x0669, 0x0709, 0x0789, + 0x0829, 0x08A9, 0x0929, 0x0989, + 0x0A09, 0x0A69, 0x0AC9, 0x0B29, + 0x0BA9, 0x0BE9, 0x0C49, 0x0CA9, /* 16 */ + 0x0D09, 0x0D69, 0x0DA9, 0x0E09, + 0x0E69, 0x0EA9, 0x0F09, 0x0F49, + 0x0FA9, 0x0FE9, 0x1029, 0x1089, + 0x10C9, 0x1109, 0x1169, 0x11A9, /* 32 */ + 0x11E9, 0x1229, 0x1289, 0x12C9, + 0x1309, 0x1349, 0x1389, 0x13C9, + 0x1409, 0x1449, 0x14A9, 0x14E9, + 0x1529, 0x1569, 0x15A9, 0x15E9, /* 48 */ + 0x1629, 0x1669, 0x16A9, 0x16E8, + 0x1728, 0x1768, 0x17A8, 0x17E8, + 0x1828, 0x1868, 0x18A8, 0x18E8, + 0x1928, 0x1968, 0x19A8, 0x19E8, /* 64 */ + 0x1A28, 0x1A68, 0x1AA8, 0x1AE8, + 0x1B28, 0x1B68, 0x1BA8, 0x1BE8, + 0x1C28, 0x1C68, 0x1CA8, 0x1CE8, + 0x1D28, 0x1D68, 0x1DC8, 0x1E08, /* 80 */ + 0x1E48, 0x1E88, 0x1EC8, 0x1F08, + 0x1F48, 0x1F88, 0x1FE8, 0x2028, + 0x2068, 0x20A8, 0x2108, 0x2148, + 0x2188, 0x21C8, 0x2228, 0x2268, /* 96 */ + 0x22C8, 0x2308, 0x2348, 0x23A8, + 0x23E8, 0x2448, 0x24A8, 0x24E8, + 0x2548, 0x25A8, 0x2608, 0x2668, + 0x26C8, 0x2728, 0x2787, 0x27E7, /* 112 */ + 0x2847, 0x28C7, 0x2947, 0x29A7, + 0x2A27, 0x2AC7, 0x2B47, 0x2BE7, + 0x2CA7, 0x2D67, 0x2E47, 0x2F67, + 0x3247, 0x3526, 0x3646, 0x3726, /* 128 */ + 0x3806, 0x38A6, 0x3946, 0x39E6, + 0x3A66, 0x3AE6, 0x3B66, 0x3BC6, + 0x3C45, 0x3CA5, 0x3D05, 0x3D85, + 0x3DE5, 0x3E45, 0x3EA5, 0x3EE5, /* 144 */ + 0x3F45, 0x3FA5, 0x4005, 0x4045, + 0x40A5, 0x40E5, 0x4145, 0x4185, + 0x41E5, 0x4225, 0x4265, 0x42C5, + 0x4305, 0x4345, 0x43A5, 0x43E5, /* 160 */ + 0x4424, 0x4464, 0x44C4, 0x4504, + 0x4544, 0x4584, 0x45C4, 0x4604, + 0x4644, 0x46A4, 0x46E4, 0x4724, + 0x4764, 0x47A4, 0x47E4, 0x4824, /* 176 */ + 0x4864, 0x48A4, 0x48E4, 0x4924, + 0x4964, 0x49A4, 0x49E4, 0x4A24, + 0x4A64, 0x4AA4, 0x4AE4, 0x4B23, + 0x4B63, 0x4BA3, 0x4BE3, 0x4C23, /* 192 */ + 0x4C63, 0x4CA3, 0x4CE3, 0x4D23, + 0x4D63, 0x4DA3, 0x4DE3, 0x4E23, + 0x4E63, 0x4EA3, 0x4EE3, 0x4F23, + 0x4F63, 0x4FC3, 0x5003, 0x5043, /* 208 */ + 0x5083, 0x50C3, 0x5103, 0x5143, + 0x5183, 0x51E2, 0x5222, 0x5262, + 0x52A2, 0x52E2, 0x5342, 0x5382, + 0x53C2, 0x5402, 0x5462, 0x54A2, /* 224 */ + 0x5502, 0x5542, 0x55A2, 0x55E2, + 0x5642, 0x5682, 0x56E2, 0x5722, + 0x5782, 0x57E1, 0x5841, 0x58A1, + 0x5901, 0x5961, 0x59C1, 0x5A21, /* 240 */ + 0x5AA1, 0x5B01, 0x5B81, 0x5BE1, + 0x5C61, 0x5D01, 0x5D80, 0x5E20, + 0x5EE0, 0x5FA0, 0x6080, 0x61C0, +}; + +const u16 b43_tab_noisea2[] = { + 0x0001, 0x0001, 0x0001, 0xFFFE, + 0xFFFE, 0x3FFF, 0x1000, 0x0393, +}; + +const u16 b43_tab_noisea3[] = { + 0x4C4C, 0x4C4C, 0x4C4C, 0x2D36, + 0x4C4C, 0x4C4C, 0x4C4C, 0x2D36, +}; + +const u16 b43_tab_noiseg1[] = { + 0x013C, 0x01F5, 0x031A, 0x0631, + 0x0001, 0x0001, 0x0001, 0x0001, +}; + +const u16 b43_tab_noiseg2[] = { + 0x5484, 0x3C40, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, +}; + +const u16 b43_tab_noisescaleg1[] = { + 0x6C77, 0x5162, 0x3B40, 0x3335, /* 0 */ + 0x2F2D, 0x2A2A, 0x2527, 0x1F21, + 0x1A1D, 0x1719, 0x1616, 0x1414, + 0x1414, 0x1400, 0x1414, 0x1614, + 0x1716, 0x1A19, 0x1F1D, 0x2521, /* 16 */ + 0x2A27, 0x2F2A, 0x332D, 0x3B35, + 0x5140, 0x6C62, 0x0077, +}; + +const u16 b43_tab_noisescaleg2[] = { + 0xD8DD, 0xCBD4, 0xBCC0, 0XB6B7, /* 0 */ + 0xB2B0, 0xADAD, 0xA7A9, 0x9FA1, + 0x969B, 0x9195, 0x8F8F, 0x8A8A, + 0x8A8A, 0x8A00, 0x8A8A, 0x8F8A, + 0x918F, 0x9695, 0x9F9B, 0xA7A1, /* 16 */ + 0xADA9, 0xB2AD, 0xB6B0, 0xBCB7, + 0xCBC0, 0xD8D4, 0x00DD, +}; + +const u16 b43_tab_noisescaleg3[] = { + 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, /* 0 */ + 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, + 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, + 0xA4A4, 0xA400, 0xA4A4, 0xA4A4, + 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, /* 16 */ + 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, + 0xA4A4, 0xA4A4, 0x00A4, +}; + +const u16 b43_tab_sigmasqr1[] = { + 0x007A, 0x0075, 0x0071, 0x006C, /* 0 */ + 0x0067, 0x0063, 0x005E, 0x0059, + 0x0054, 0x0050, 0x004B, 0x0046, + 0x0042, 0x003D, 0x003D, 0x003D, + 0x003D, 0x003D, 0x003D, 0x003D, /* 16 */ + 0x003D, 0x003D, 0x003D, 0x003D, + 0x003D, 0x003D, 0x0000, 0x003D, + 0x003D, 0x003D, 0x003D, 0x003D, + 0x003D, 0x003D, 0x003D, 0x003D, /* 32 */ + 0x003D, 0x003D, 0x003D, 0x003D, + 0x0042, 0x0046, 0x004B, 0x0050, + 0x0054, 0x0059, 0x005E, 0x0063, + 0x0067, 0x006C, 0x0071, 0x0075, /* 48 */ + 0x007A, +}; + +const u16 b43_tab_sigmasqr2[] = { + 0x00DE, 0x00DC, 0x00DA, 0x00D8, /* 0 */ + 0x00D6, 0x00D4, 0x00D2, 0x00CF, + 0x00CD, 0x00CA, 0x00C7, 0x00C4, + 0x00C1, 0x00BE, 0x00BE, 0x00BE, + 0x00BE, 0x00BE, 0x00BE, 0x00BE, /* 16 */ + 0x00BE, 0x00BE, 0x00BE, 0x00BE, + 0x00BE, 0x00BE, 0x0000, 0x00BE, + 0x00BE, 0x00BE, 0x00BE, 0x00BE, + 0x00BE, 0x00BE, 0x00BE, 0x00BE, /* 32 */ + 0x00BE, 0x00BE, 0x00BE, 0x00BE, + 0x00C1, 0x00C4, 0x00C7, 0x00CA, + 0x00CD, 0x00CF, 0x00D2, 0x00D4, + 0x00D6, 0x00D8, 0x00DA, 0x00DC, /* 48 */ + 0x00DE, +}; + +static inline void assert_sizes(void) +{ + BUILD_BUG_ON(B43_TAB_ROTOR_SIZE != ARRAY_SIZE(b43_tab_rotor)); + BUILD_BUG_ON(B43_TAB_RETARD_SIZE != ARRAY_SIZE(b43_tab_retard)); + BUILD_BUG_ON(B43_TAB_FINEFREQA_SIZE != ARRAY_SIZE(b43_tab_finefreqa)); + BUILD_BUG_ON(B43_TAB_FINEFREQG_SIZE != ARRAY_SIZE(b43_tab_finefreqg)); + BUILD_BUG_ON(B43_TAB_NOISEA2_SIZE != ARRAY_SIZE(b43_tab_noisea2)); + BUILD_BUG_ON(B43_TAB_NOISEA3_SIZE != ARRAY_SIZE(b43_tab_noisea3)); + BUILD_BUG_ON(B43_TAB_NOISEG1_SIZE != ARRAY_SIZE(b43_tab_noiseg1)); + BUILD_BUG_ON(B43_TAB_NOISEG2_SIZE != ARRAY_SIZE(b43_tab_noiseg2)); + BUILD_BUG_ON(B43_TAB_NOISESCALEG_SIZE != + ARRAY_SIZE(b43_tab_noisescaleg1)); + BUILD_BUG_ON(B43_TAB_NOISESCALEG_SIZE != + ARRAY_SIZE(b43_tab_noisescaleg2)); + BUILD_BUG_ON(B43_TAB_NOISESCALEG_SIZE != + ARRAY_SIZE(b43_tab_noisescaleg3)); + BUILD_BUG_ON(B43_TAB_SIGMASQR_SIZE != ARRAY_SIZE(b43_tab_sigmasqr1)); + BUILD_BUG_ON(B43_TAB_SIGMASQR_SIZE != ARRAY_SIZE(b43_tab_sigmasqr2)); +} + +u16 b43_ofdmtab_read16(struct b43_wldev *dev, u16 table, u16 offset) +{ + assert_sizes(); + + b43_phy_write(dev, B43_PHY_OTABLECTL, table + offset); + return b43_phy_read(dev, B43_PHY_OTABLEI); +} + +void b43_ofdmtab_write16(struct b43_wldev *dev, u16 table, + u16 offset, u16 value) +{ + b43_phy_write(dev, B43_PHY_OTABLECTL, table + offset); + b43_phy_write(dev, B43_PHY_OTABLEI, value); +} + +u32 b43_ofdmtab_read32(struct b43_wldev *dev, u16 table, u16 offset) +{ + u32 ret; + + b43_phy_write(dev, B43_PHY_OTABLECTL, table + offset); + ret = b43_phy_read(dev, B43_PHY_OTABLEQ); + ret <<= 16; + ret |= b43_phy_read(dev, B43_PHY_OTABLEI); + + return ret; +} + +void b43_ofdmtab_write32(struct b43_wldev *dev, u16 table, + u16 offset, u32 value) +{ + b43_phy_write(dev, B43_PHY_OTABLECTL, table + offset); + b43_phy_write(dev, B43_PHY_OTABLEI, value); + b43_phy_write(dev, B43_PHY_OTABLEQ, (value >> 16)); +} + +u16 b43_gtab_read(struct b43_wldev *dev, u16 table, u16 offset) +{ + b43_phy_write(dev, B43_PHY_GTABCTL, table + offset); + return b43_phy_read(dev, B43_PHY_GTABDATA); +} + +void b43_gtab_write(struct b43_wldev *dev, u16 table, u16 offset, u16 value) +{ + b43_phy_write(dev, B43_PHY_GTABCTL, table + offset); + b43_phy_write(dev, B43_PHY_GTABDATA, value); +} diff --git a/drivers/net/wireless/b43/tables.h b/drivers/net/wireless/b43/tables.h new file mode 100644 index 00000000000..64635d7b518 --- /dev/null +++ b/drivers/net/wireless/b43/tables.h @@ -0,0 +1,28 @@ +#ifndef B43_TABLES_H_ +#define B43_TABLES_H_ + +#define B43_TAB_ROTOR_SIZE 53 +extern const u32 b43_tab_rotor[]; +#define B43_TAB_RETARD_SIZE 53 +extern const u32 b43_tab_retard[]; +#define B43_TAB_FINEFREQA_SIZE 256 +extern const u16 b43_tab_finefreqa[]; +#define B43_TAB_FINEFREQG_SIZE 256 +extern const u16 b43_tab_finefreqg[]; +#define B43_TAB_NOISEA2_SIZE 8 +extern const u16 b43_tab_noisea2[]; +#define B43_TAB_NOISEA3_SIZE 8 +extern const u16 b43_tab_noisea3[]; +#define B43_TAB_NOISEG1_SIZE 8 +extern const u16 b43_tab_noiseg1[]; +#define B43_TAB_NOISEG2_SIZE 8 +extern const u16 b43_tab_noiseg2[]; +#define B43_TAB_NOISESCALEG_SIZE 27 +extern const u16 b43_tab_noisescaleg1[]; +extern const u16 b43_tab_noisescaleg2[]; +extern const u16 b43_tab_noisescaleg3[]; +#define B43_TAB_SIGMASQR_SIZE 53 +extern const u16 b43_tab_sigmasqr1[]; +extern const u16 b43_tab_sigmasqr2[]; + +#endif /* B43_TABLES_H_ */ diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c new file mode 100644 index 00000000000..e6174b6f11f --- /dev/null +++ b/drivers/net/wireless/b43/xmit.c @@ -0,0 +1,648 @@ +/* + + Broadcom B43 wireless driver + + Transmission (TX/RX) related functions. + + Copyright (C) 2005 Martin Langer + Copyright (C) 2005 Stefano Brivio + Copyright (C) 2005, 2006 Michael Buesch + Copyright (C) 2005 Danny van Dyk + Copyright (C) 2005 Andreas Jaggi + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "xmit.h" +#include "phy.h" +#include "dma.h" +#include "pio.h" + +/* Extract the bitrate out of a CCK PLCP header. */ +static u8 b43_plcp_get_bitrate_cck(struct b43_plcp_hdr6 *plcp) +{ + switch (plcp->raw[0]) { + case 0x0A: + return B43_CCK_RATE_1MB; + case 0x14: + return B43_CCK_RATE_2MB; + case 0x37: + return B43_CCK_RATE_5MB; + case 0x6E: + return B43_CCK_RATE_11MB; + } + B43_WARN_ON(1); + return 0; +} + +/* Extract the bitrate out of an OFDM PLCP header. */ +static u8 b43_plcp_get_bitrate_ofdm(struct b43_plcp_hdr6 *plcp) +{ + switch (plcp->raw[0] & 0xF) { + case 0xB: + return B43_OFDM_RATE_6MB; + case 0xF: + return B43_OFDM_RATE_9MB; + case 0xA: + return B43_OFDM_RATE_12MB; + case 0xE: + return B43_OFDM_RATE_18MB; + case 0x9: + return B43_OFDM_RATE_24MB; + case 0xD: + return B43_OFDM_RATE_36MB; + case 0x8: + return B43_OFDM_RATE_48MB; + case 0xC: + return B43_OFDM_RATE_54MB; + } + B43_WARN_ON(1); + return 0; +} + +u8 b43_plcp_get_ratecode_cck(const u8 bitrate) +{ + switch (bitrate) { + case B43_CCK_RATE_1MB: + return 0x0A; + case B43_CCK_RATE_2MB: + return 0x14; + case B43_CCK_RATE_5MB: + return 0x37; + case B43_CCK_RATE_11MB: + return 0x6E; + } + B43_WARN_ON(1); + return 0; +} + +u8 b43_plcp_get_ratecode_ofdm(const u8 bitrate) +{ + switch (bitrate) { + case B43_OFDM_RATE_6MB: + return 0xB; + case B43_OFDM_RATE_9MB: + return 0xF; + case B43_OFDM_RATE_12MB: + return 0xA; + case B43_OFDM_RATE_18MB: + return 0xE; + case B43_OFDM_RATE_24MB: + return 0x9; + case B43_OFDM_RATE_36MB: + return 0xD; + case B43_OFDM_RATE_48MB: + return 0x8; + case B43_OFDM_RATE_54MB: + return 0xC; + } + B43_WARN_ON(1); + return 0; +} + +void b43_generate_plcp_hdr(struct b43_plcp_hdr4 *plcp, + const u16 octets, const u8 bitrate) +{ + __le32 *data = &(plcp->data); + __u8 *raw = plcp->raw; + + if (b43_is_ofdm_rate(bitrate)) { + *data = b43_plcp_get_ratecode_ofdm(bitrate); + B43_WARN_ON(octets & 0xF000); + *data |= (octets << 5); + *data = cpu_to_le32(*data); + } else { + u32 plen; + + plen = octets * 16 / bitrate; + if ((octets * 16 % bitrate) > 0) { + plen++; + if ((bitrate == B43_CCK_RATE_11MB) + && ((octets * 8 % 11) < 4)) { + raw[1] = 0x84; + } else + raw[1] = 0x04; + } else + raw[1] = 0x04; + *data |= cpu_to_le32(plen << 16); + raw[0] = b43_plcp_get_ratecode_cck(bitrate); + } +} + +static u8 b43_calc_fallback_rate(u8 bitrate) +{ + switch (bitrate) { + case B43_CCK_RATE_1MB: + return B43_CCK_RATE_1MB; + case B43_CCK_RATE_2MB: + return B43_CCK_RATE_1MB; + case B43_CCK_RATE_5MB: + return B43_CCK_RATE_2MB; + case B43_CCK_RATE_11MB: + return B43_CCK_RATE_5MB; + case B43_OFDM_RATE_6MB: + return B43_CCK_RATE_5MB; + case B43_OFDM_RATE_9MB: + return B43_OFDM_RATE_6MB; + case B43_OFDM_RATE_12MB: + return B43_OFDM_RATE_9MB; + case B43_OFDM_RATE_18MB: + return B43_OFDM_RATE_12MB; + case B43_OFDM_RATE_24MB: + return B43_OFDM_RATE_18MB; + case B43_OFDM_RATE_36MB: + return B43_OFDM_RATE_24MB; + case B43_OFDM_RATE_48MB: + return B43_OFDM_RATE_36MB; + case B43_OFDM_RATE_54MB: + return B43_OFDM_RATE_48MB; + } + B43_WARN_ON(1); + return 0; +} + +static void generate_txhdr_fw4(struct b43_wldev *dev, + struct b43_txhdr_fw4 *txhdr, + const unsigned char *fragment_data, + unsigned int fragment_len, + const struct ieee80211_tx_control *txctl, + u16 cookie) +{ + const struct b43_phy *phy = &dev->phy; + const struct ieee80211_hdr *wlhdr = + (const struct ieee80211_hdr *)fragment_data; + int use_encryption = (!(txctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)); + u16 fctl = le16_to_cpu(wlhdr->frame_control); + u8 rate, rate_fb; + int rate_ofdm, rate_fb_ofdm; + unsigned int plcp_fragment_len; + u32 mac_ctl = 0; + u16 phy_ctl = 0; + u8 extra_ft = 0; + + memset(txhdr, 0, sizeof(*txhdr)); + + rate = txctl->tx_rate; + rate_ofdm = b43_is_ofdm_rate(rate); + rate_fb = (txctl->alt_retry_rate == -1) ? rate : txctl->alt_retry_rate; + rate_fb_ofdm = b43_is_ofdm_rate(rate_fb); + + if (rate_ofdm) + txhdr->phy_rate = b43_plcp_get_ratecode_ofdm(rate); + else + txhdr->phy_rate = b43_plcp_get_ratecode_cck(rate); + txhdr->mac_frame_ctl = wlhdr->frame_control; + memcpy(txhdr->tx_receiver, wlhdr->addr1, 6); + + /* Calculate duration for fallback rate */ + if ((rate_fb == rate) || + (wlhdr->duration_id & cpu_to_le16(0x8000)) || + (wlhdr->duration_id == cpu_to_le16(0))) { + /* If the fallback rate equals the normal rate or the + * dur_id field contains an AID, CFP magic or 0, + * use the original dur_id field. */ + txhdr->dur_fb = wlhdr->duration_id; + } else { + int fbrate_base100kbps = B43_RATE_TO_BASE100KBPS(rate_fb); + txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw, + dev->wl->if_id, + fragment_len, + fbrate_base100kbps); + } + + plcp_fragment_len = fragment_len + FCS_LEN; + if (use_encryption) { + u8 key_idx = (u16) (txctl->key_idx); + struct b43_key *key; + int wlhdr_len; + size_t iv_len; + + B43_WARN_ON(key_idx >= dev->max_nr_keys); + key = &(dev->key[key_idx]); + B43_WARN_ON(!key->keyconf); + + /* Hardware appends ICV. */ + plcp_fragment_len += txctl->icv_len; + + key_idx = b43_kidx_to_fw(dev, key_idx); + mac_ctl |= (key_idx << B43_TX4_MAC_KEYIDX_SHIFT) & + B43_TX4_MAC_KEYIDX; + mac_ctl |= (key->algorithm << B43_TX4_MAC_KEYALG_SHIFT) & + B43_TX4_MAC_KEYALG; + wlhdr_len = ieee80211_get_hdrlen(fctl); + iv_len = min((size_t) txctl->iv_len, + ARRAY_SIZE(txhdr->iv)); + memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len); + } + b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->plcp), + plcp_fragment_len, rate); + b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->plcp_fb), + plcp_fragment_len, rate_fb); + + /* Extra Frame Types */ + if (rate_fb_ofdm) + extra_ft |= B43_TX4_EFT_FBOFDM; + + /* Set channel radio code. Note that the micrcode ORs 0x100 to + * this value before comparing it to the value in SHM, if this + * is a 5Ghz packet. + */ + txhdr->chan_radio_code = phy->channel; + + /* PHY TX Control word */ + if (rate_ofdm) + phy_ctl |= B43_TX4_PHY_OFDM; + if (dev->short_preamble) + phy_ctl |= B43_TX4_PHY_SHORTPRMBL; + switch (txctl->antenna_sel_tx) { + case 0: + phy_ctl |= B43_TX4_PHY_ANTLAST; + break; + case 1: + phy_ctl |= B43_TX4_PHY_ANT0; + break; + case 2: + phy_ctl |= B43_TX4_PHY_ANT1; + break; + default: + B43_WARN_ON(1); + } + + /* MAC control */ + if (!(txctl->flags & IEEE80211_TXCTL_NO_ACK)) + mac_ctl |= B43_TX4_MAC_ACK; + if (!(((fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) && + ((fctl & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL))) + mac_ctl |= B43_TX4_MAC_HWSEQ; + if (txctl->flags & IEEE80211_TXCTL_FIRST_FRAGMENT) + mac_ctl |= B43_TX4_MAC_STMSDU; + if (phy->type == B43_PHYTYPE_A) + mac_ctl |= B43_TX4_MAC_5GHZ; + + /* Generate the RTS or CTS-to-self frame */ + if ((txctl->flags & IEEE80211_TXCTL_USE_RTS_CTS) || + (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) { + unsigned int len; + struct ieee80211_hdr *hdr; + int rts_rate, rts_rate_fb; + int rts_rate_ofdm, rts_rate_fb_ofdm; + + rts_rate = txctl->rts_cts_rate; + rts_rate_ofdm = b43_is_ofdm_rate(rts_rate); + rts_rate_fb = b43_calc_fallback_rate(rts_rate); + rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb); + + if (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { + ieee80211_ctstoself_get(dev->wl->hw, dev->wl->if_id, + fragment_data, fragment_len, + txctl, + (struct ieee80211_cts *)(txhdr-> + rts_frame)); + mac_ctl |= B43_TX4_MAC_SENDCTS; + len = sizeof(struct ieee80211_cts); + } else { + ieee80211_rts_get(dev->wl->hw, dev->wl->if_id, + fragment_data, fragment_len, txctl, + (struct ieee80211_rts *)(txhdr-> + rts_frame)); + mac_ctl |= B43_TX4_MAC_SENDRTS; + len = sizeof(struct ieee80211_rts); + } + len += FCS_LEN; + b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr-> + rts_plcp), len, + rts_rate); + b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr-> + rts_plcp_fb), + len, rts_rate_fb); + hdr = (struct ieee80211_hdr *)(&txhdr->rts_frame); + txhdr->rts_dur_fb = hdr->duration_id; + if (rts_rate_ofdm) { + extra_ft |= B43_TX4_EFT_RTSOFDM; + txhdr->phy_rate_rts = + b43_plcp_get_ratecode_ofdm(rts_rate); + } else + txhdr->phy_rate_rts = + b43_plcp_get_ratecode_cck(rts_rate); + if (rts_rate_fb_ofdm) + extra_ft |= B43_TX4_EFT_RTSFBOFDM; + mac_ctl |= B43_TX4_MAC_LONGFRAME; + } + + /* Magic cookie */ + txhdr->cookie = cpu_to_le16(cookie); + + /* Apply the bitfields */ + txhdr->mac_ctl = cpu_to_le32(mac_ctl); + txhdr->phy_ctl = cpu_to_le16(phy_ctl); + txhdr->extra_ft = extra_ft; +} + +void b43_generate_txhdr(struct b43_wldev *dev, + u8 * txhdr, + const unsigned char *fragment_data, + unsigned int fragment_len, + const struct ieee80211_tx_control *txctl, u16 cookie) +{ + generate_txhdr_fw4(dev, (struct b43_txhdr_fw4 *)txhdr, + fragment_data, fragment_len, txctl, cookie); +} + +static s8 b43_rssi_postprocess(struct b43_wldev *dev, + u8 in_rssi, int ofdm, + int adjust_2053, int adjust_2050) +{ + struct b43_phy *phy = &dev->phy; + s32 tmp; + + switch (phy->radio_ver) { + case 0x2050: + if (ofdm) { + tmp = in_rssi; + if (tmp > 127) + tmp -= 256; + tmp *= 73; + tmp /= 64; + if (adjust_2050) + tmp += 25; + else + tmp -= 3; + } else { + if (dev->dev->bus->sprom.r1. + boardflags_lo & B43_BFL_RSSI) { + if (in_rssi > 63) + in_rssi = 63; + tmp = phy->nrssi_lt[in_rssi]; + tmp = 31 - tmp; + tmp *= -131; + tmp /= 128; + tmp -= 57; + } else { + tmp = in_rssi; + tmp = 31 - tmp; + tmp *= -149; + tmp /= 128; + tmp -= 68; + } + if (phy->type == B43_PHYTYPE_G && adjust_2050) + tmp += 25; + } + break; + case 0x2060: + if (in_rssi > 127) + tmp = in_rssi - 256; + else + tmp = in_rssi; + break; + default: + tmp = in_rssi; + tmp -= 11; + tmp *= 103; + tmp /= 64; + if (adjust_2053) + tmp -= 109; + else + tmp -= 83; + } + + return (s8) tmp; +} + +//TODO +#if 0 +static s8 b43_rssinoise_postprocess(struct b43_wldev *dev, u8 in_rssi) +{ + struct b43_phy *phy = &dev->phy; + s8 ret; + + if (phy->type == B43_PHYTYPE_A) { + //TODO: Incomplete specs. + ret = 0; + } else + ret = b43_rssi_postprocess(dev, in_rssi, 0, 1, 1); + + return ret; +} +#endif + +void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) +{ + struct ieee80211_rx_status status; + struct b43_plcp_hdr6 *plcp; + struct ieee80211_hdr *wlhdr; + const struct b43_rxhdr_fw4 *rxhdr = _rxhdr; + u16 fctl; + u16 phystat0, phystat3, chanstat, mactime; + u32 macstat; + u16 chanid; + u8 jssi; + int padding; + + memset(&status, 0, sizeof(status)); + + /* Get metadata about the frame from the header. */ + phystat0 = le16_to_cpu(rxhdr->phy_status0); + phystat3 = le16_to_cpu(rxhdr->phy_status3); + jssi = rxhdr->jssi; + macstat = le32_to_cpu(rxhdr->mac_status); + mactime = le16_to_cpu(rxhdr->mac_time); + chanstat = le16_to_cpu(rxhdr->channel); + + if (macstat & B43_RX_MAC_FCSERR) + dev->wl->ieee_stats.dot11FCSErrorCount++; + if (macstat & B43_RX_MAC_DECERR) { + /* Decryption with the given key failed. + * Drop the packet. We also won't be able to decrypt it with + * the key in software. */ + goto drop; + } + + /* Skip PLCP and padding */ + padding = (macstat & B43_RX_MAC_PADDING) ? 2 : 0; + if (unlikely(skb->len < (sizeof(struct b43_plcp_hdr6) + padding))) { + b43dbg(dev->wl, "RX: Packet size underrun (1)\n"); + goto drop; + } + plcp = (struct b43_plcp_hdr6 *)(skb->data + padding); + skb_pull(skb, sizeof(struct b43_plcp_hdr6) + padding); + /* The skb contains the Wireless Header + payload data now */ + if (unlikely(skb->len < (2 + 2 + 6 /*minimum hdr */ + FCS_LEN))) { + b43dbg(dev->wl, "RX: Packet size underrun (2)\n"); + goto drop; + } + wlhdr = (struct ieee80211_hdr *)(skb->data); + fctl = le16_to_cpu(wlhdr->frame_control); + skb_trim(skb, skb->len - FCS_LEN); + + if (macstat & B43_RX_MAC_DEC) { + unsigned int keyidx; + int wlhdr_len; + + keyidx = ((macstat & B43_RX_MAC_KEYIDX) + >> B43_RX_MAC_KEYIDX_SHIFT); + /* We must adjust the key index here. We want the "physical" + * key index, but the ucode passed it slightly different. + */ + keyidx = b43_kidx_to_raw(dev, keyidx); + B43_WARN_ON(keyidx >= dev->max_nr_keys); + + if (dev->key[keyidx].algorithm != B43_SEC_ALGO_NONE) { + wlhdr_len = ieee80211_get_hdrlen(fctl); + if (unlikely(skb->len < (wlhdr_len + 3))) { + b43dbg(dev->wl, + "RX: Packet size underrun (3)\n"); + goto drop; + } + status.flag |= RX_FLAG_DECRYPTED; + } + } + + status.ssi = b43_rssi_postprocess(dev, jssi, + (phystat0 & B43_RX_PHYST0_OFDM), + (phystat0 & B43_RX_PHYST0_GAINCTL), + (phystat3 & B43_RX_PHYST3_TRSTATE)); + status.noise = dev->stats.link_noise; + /* the next line looks wrong, but is what mac80211 wants */ + status.signal = (jssi * 100) / B43_RX_MAX_SSI; + if (phystat0 & B43_RX_PHYST0_OFDM) + status.rate = b43_plcp_get_bitrate_ofdm(plcp); + else + status.rate = b43_plcp_get_bitrate_cck(plcp); + status.antenna = !!(phystat0 & B43_RX_PHYST0_ANT); + status.mactime = mactime; + + chanid = (chanstat & B43_RX_CHAN_ID) >> B43_RX_CHAN_ID_SHIFT; + switch (chanstat & B43_RX_CHAN_PHYTYPE) { + case B43_PHYTYPE_A: + status.phymode = MODE_IEEE80211A; + status.freq = chanid; + status.channel = b43_freq_to_channel_a(chanid); + break; + case B43_PHYTYPE_B: + status.phymode = MODE_IEEE80211B; + status.freq = chanid + 2400; + status.channel = b43_freq_to_channel_bg(chanid + 2400); + break; + case B43_PHYTYPE_G: + status.phymode = MODE_IEEE80211G; + status.freq = chanid + 2400; + status.channel = b43_freq_to_channel_bg(chanid + 2400); + break; + default: + B43_WARN_ON(1); + } + + dev->stats.last_rx = jiffies; + ieee80211_rx_irqsafe(dev->wl->hw, skb, &status); + + return; +drop: + b43dbg(dev->wl, "RX: Packet dropped\n"); + dev_kfree_skb_any(skb); +} + +void b43_handle_txstatus(struct b43_wldev *dev, + const struct b43_txstatus *status) +{ + b43_debugfs_log_txstat(dev, status); + + if (status->intermediate) + return; + if (status->for_ampdu) + return; + if (!status->acked) + dev->wl->ieee_stats.dot11ACKFailureCount++; + if (status->rts_count) { + if (status->rts_count == 0xF) //FIXME + dev->wl->ieee_stats.dot11RTSFailureCount++; + else + dev->wl->ieee_stats.dot11RTSSuccessCount++; + } + + if (b43_using_pio(dev)) + b43_pio_handle_txstatus(dev, status); + else + b43_dma_handle_txstatus(dev, status); +} + +/* Handle TX status report as received through DMA/PIO queues */ +void b43_handle_hwtxstatus(struct b43_wldev *dev, + const struct b43_hwtxstatus *hw) +{ + struct b43_txstatus status; + u8 tmp; + + status.cookie = le16_to_cpu(hw->cookie); + status.seq = le16_to_cpu(hw->seq); + status.phy_stat = hw->phy_stat; + tmp = hw->count; + status.frame_count = (tmp >> 4); + status.rts_count = (tmp & 0x0F); + tmp = hw->flags; + status.supp_reason = ((tmp & 0x1C) >> 2); + status.pm_indicated = !!(tmp & 0x80); + status.intermediate = !!(tmp & 0x40); + status.for_ampdu = !!(tmp & 0x20); + status.acked = !!(tmp & 0x02); + + b43_handle_txstatus(dev, &status); +} + +/* Stop any TX operation on the device (suspend the hardware queues) */ +void b43_tx_suspend(struct b43_wldev *dev) +{ + if (b43_using_pio(dev)) + b43_pio_freeze_txqueues(dev); + else + b43_dma_tx_suspend(dev); +} + +/* Resume any TX operation on the device (resume the hardware queues) */ +void b43_tx_resume(struct b43_wldev *dev) +{ + if (b43_using_pio(dev)) + b43_pio_thaw_txqueues(dev); + else + b43_dma_tx_resume(dev); +} + +#if 0 +static void upload_qos_parms(struct b43_wldev *dev, + const u16 * parms, u16 offset) +{ + int i; + + for (i = 0; i < B43_NR_QOSPARMS; i++) { + b43_shm_write16(dev, B43_SHM_SHARED, + offset + (i * 2), parms[i]); + } +} +#endif + +/* Initialize the QoS parameters */ +void b43_qos_init(struct b43_wldev *dev) +{ + /* FIXME: This function must probably be called from the mac80211 + * config callback. */ + return; + + b43_hf_write(dev, b43_hf_read(dev) | B43_HF_EDCF); + //FIXME kill magic + b43_write16(dev, 0x688, b43_read16(dev, 0x688) | 0x4); + + /*TODO: We might need some stack support here to get the values. */ +} diff --git a/drivers/net/wireless/b43/xmit.h b/drivers/net/wireless/b43/xmit.h new file mode 100644 index 00000000000..03bddd25161 --- /dev/null +++ b/drivers/net/wireless/b43/xmit.h @@ -0,0 +1,250 @@ +#ifndef B43_XMIT_H_ +#define B43_XMIT_H_ + +#include "main.h" + +#define _b43_declare_plcp_hdr(size) \ + struct b43_plcp_hdr##size { \ + union { \ + __le32 data; \ + __u8 raw[size]; \ + } __attribute__((__packed__)); \ + } __attribute__((__packed__)) + +/* struct b43_plcp_hdr4 */ +_b43_declare_plcp_hdr(4); +/* struct b43_plcp_hdr6 */ +_b43_declare_plcp_hdr(6); + +#undef _b43_declare_plcp_hdr + +/* TX header for v4 firmware */ +struct b43_txhdr_fw4 { + __le32 mac_ctl; /* MAC TX control */ + __le16 mac_frame_ctl; /* Copy of the FrameControl field */ + __le16 tx_fes_time_norm; /* TX FES Time Normal */ + __le16 phy_ctl; /* PHY TX control */ + __le16 phy_ctl_0; /* Unused */ + __le16 phy_ctl_1; /* Unused */ + __le16 phy_ctl_rts_0; /* Unused */ + __le16 phy_ctl_rts_1; /* Unused */ + __u8 phy_rate; /* PHY rate */ + __u8 phy_rate_rts; /* PHY rate for RTS/CTS */ + __u8 extra_ft; /* Extra Frame Types */ + __u8 chan_radio_code; /* Channel Radio Code */ + __u8 iv[16]; /* Encryption IV */ + __u8 tx_receiver[6]; /* TX Frame Receiver address */ + __le16 tx_fes_time_fb; /* TX FES Time Fallback */ + struct b43_plcp_hdr6 rts_plcp_fb; /* RTS fallback PLCP */ + __le16 rts_dur_fb; /* RTS fallback duration */ + struct b43_plcp_hdr6 plcp_fb; /* Fallback PLCP */ + __le16 dur_fb; /* Fallback duration */ + __le16 mm_dur_time; /* Unused */ + __le16 mm_dur_time_fb; /* Unused */ + __le32 time_stamp; /* Timestamp */ + PAD_BYTES(2); + __le16 cookie; /* TX frame cookie */ + __le16 tx_status; /* TX status */ + struct b43_plcp_hdr6 rts_plcp; /* RTS PLCP */ + __u8 rts_frame[16]; /* The RTS frame (if used) */ + PAD_BYTES(2); + struct b43_plcp_hdr6 plcp; /* Main PLCP */ +} __attribute__ ((__packed__)); + +/* MAC TX control */ +#define B43_TX4_MAC_KEYIDX 0x0FF00000 /* Security key index */ +#define B43_TX4_MAC_KEYIDX_SHIFT 20 +#define B43_TX4_MAC_KEYALG 0x00070000 /* Security key algorithm */ +#define B43_TX4_MAC_KEYALG_SHIFT 16 +#define B43_TX4_MAC_LIFETIME 0x00001000 +#define B43_TX4_MAC_FRAMEBURST 0x00000800 +#define B43_TX4_MAC_SENDCTS 0x00000400 +#define B43_TX4_MAC_AMPDU 0x00000300 +#define B43_TX4_MAC_AMPDU_SHIFT 8 +#define B43_TX4_MAC_5GHZ 0x00000080 +#define B43_TX4_MAC_IGNPMQ 0x00000020 +#define B43_TX4_MAC_HWSEQ 0x00000010 /* Use Hardware Sequence Number */ +#define B43_TX4_MAC_STMSDU 0x00000008 /* Start MSDU */ +#define B43_TX4_MAC_SENDRTS 0x00000004 +#define B43_TX4_MAC_LONGFRAME 0x00000002 +#define B43_TX4_MAC_ACK 0x00000001 + +/* Extra Frame Types */ +#define B43_TX4_EFT_FBOFDM 0x0001 /* Data frame fallback rate type */ +#define B43_TX4_EFT_RTSOFDM 0x0004 /* RTS/CTS rate type */ +#define B43_TX4_EFT_RTSFBOFDM 0x0010 /* RTS/CTS fallback rate type */ + +/* PHY TX control word */ +#define B43_TX4_PHY_OFDM 0x0001 /* Data frame rate type */ +#define B43_TX4_PHY_SHORTPRMBL 0x0010 /* Use short preamble */ +#define B43_TX4_PHY_ANT 0x03C0 /* Antenna selection */ +#define B43_TX4_PHY_ANT0 0x0000 /* Use antenna 0 */ +#define B43_TX4_PHY_ANT1 0x0100 /* Use antenna 1 */ +#define B43_TX4_PHY_ANTLAST 0x0300 /* Use last used antenna */ + +void b43_generate_txhdr(struct b43_wldev *dev, + u8 * txhdr, + const unsigned char *fragment_data, + unsigned int fragment_len, + const struct ieee80211_tx_control *txctl, u16 cookie); + +/* Transmit Status */ +struct b43_txstatus { + u16 cookie; /* The cookie from the txhdr */ + u16 seq; /* Sequence number */ + u8 phy_stat; /* PHY TX status */ + u8 frame_count; /* Frame transmit count */ + u8 rts_count; /* RTS transmit count */ + u8 supp_reason; /* Suppression reason */ + /* flags */ + u8 pm_indicated; /* PM mode indicated to AP */ + u8 intermediate; /* Intermediate status notification (not final) */ + u8 for_ampdu; /* Status is for an AMPDU (afterburner) */ + u8 acked; /* Wireless ACK received */ +}; + +/* txstatus supp_reason values */ +enum { + B43_TXST_SUPP_NONE, /* Not suppressed */ + B43_TXST_SUPP_PMQ, /* Suppressed due to PMQ entry */ + B43_TXST_SUPP_FLUSH, /* Suppressed due to flush request */ + B43_TXST_SUPP_PREV, /* Previous fragment failed */ + B43_TXST_SUPP_CHAN, /* Channel mismatch */ + B43_TXST_SUPP_LIFE, /* Lifetime expired */ + B43_TXST_SUPP_UNDER, /* Buffer underflow */ + B43_TXST_SUPP_ABNACK, /* Afterburner NACK */ +}; + +/* Transmit Status as received through DMA/PIO on old chips */ +struct b43_hwtxstatus { + PAD_BYTES(4); + __le16 cookie; + u8 flags; + u8 count; + PAD_BYTES(2); + __le16 seq; + u8 phy_stat; + PAD_BYTES(1); +} __attribute__ ((__packed__)); + +/* Receive header for v4 firmware. */ +struct b43_rxhdr_fw4 { + __le16 frame_len; /* Frame length */ + PAD_BYTES(2); + __le16 phy_status0; /* PHY RX Status 0 */ + __u8 jssi; /* PHY RX Status 1: JSSI */ + __u8 sig_qual; /* PHY RX Status 1: Signal Quality */ + __le16 phy_status2; /* PHY RX Status 2 */ + __le16 phy_status3; /* PHY RX Status 3 */ + __le32 mac_status; /* MAC RX status */ + __le16 mac_time; + __le16 channel; +} __attribute__ ((__packed__)); + +/* PHY RX Status 0 */ +#define B43_RX_PHYST0_GAINCTL 0x4000 /* Gain Control */ +#define B43_RX_PHYST0_PLCPHCF 0x0200 +#define B43_RX_PHYST0_PLCPFV 0x0100 +#define B43_RX_PHYST0_SHORTPRMBL 0x0080 /* Received with Short Preamble */ +#define B43_RX_PHYST0_LCRS 0x0040 +#define B43_RX_PHYST0_ANT 0x0020 /* Antenna */ +#define B43_RX_PHYST0_UNSRATE 0x0010 +#define B43_RX_PHYST0_CLIP 0x000C +#define B43_RX_PHYST0_CLIP_SHIFT 2 +#define B43_RX_PHYST0_FTYPE 0x0003 /* Frame type */ +#define B43_RX_PHYST0_CCK 0x0000 /* Frame type: CCK */ +#define B43_RX_PHYST0_OFDM 0x0001 /* Frame type: OFDM */ +#define B43_RX_PHYST0_PRE_N 0x0002 /* Pre-standard N-PHY frame */ +#define B43_RX_PHYST0_STD_N 0x0003 /* Standard N-PHY frame */ + +/* PHY RX Status 2 */ +#define B43_RX_PHYST2_LNAG 0xC000 /* LNA Gain */ +#define B43_RX_PHYST2_LNAG_SHIFT 14 +#define B43_RX_PHYST2_PNAG 0x3C00 /* PNA Gain */ +#define B43_RX_PHYST2_PNAG_SHIFT 10 +#define B43_RX_PHYST2_FOFF 0x03FF /* F offset */ + +/* PHY RX Status 3 */ +#define B43_RX_PHYST3_DIGG 0x1800 /* DIG Gain */ +#define B43_RX_PHYST3_DIGG_SHIFT 11 +#define B43_RX_PHYST3_TRSTATE 0x0400 /* TR state */ + +/* MAC RX Status */ +#define B43_RX_MAC_BEACONSENT 0x00008000 /* Beacon send flag */ +#define B43_RX_MAC_KEYIDX 0x000007E0 /* Key index */ +#define B43_RX_MAC_KEYIDX_SHIFT 5 +#define B43_RX_MAC_DECERR 0x00000010 /* Decrypt error */ +#define B43_RX_MAC_DEC 0x00000008 /* Decryption attempted */ +#define B43_RX_MAC_PADDING 0x00000004 /* Pad bytes present */ +#define B43_RX_MAC_RESP 0x00000002 /* Response frame transmitted */ +#define B43_RX_MAC_FCSERR 0x00000001 /* FCS error */ + +/* RX channel */ +#define B43_RX_CHAN_GAIN 0xFC00 /* Gain */ +#define B43_RX_CHAN_GAIN_SHIFT 10 +#define B43_RX_CHAN_ID 0x03FC /* Channel ID */ +#define B43_RX_CHAN_ID_SHIFT 2 +#define B43_RX_CHAN_PHYTYPE 0x0003 /* PHY type */ + +u8 b43_plcp_get_ratecode_cck(const u8 bitrate); +u8 b43_plcp_get_ratecode_ofdm(const u8 bitrate); + +void b43_generate_plcp_hdr(struct b43_plcp_hdr4 *plcp, + const u16 octets, const u8 bitrate); + +void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr); + +void b43_handle_txstatus(struct b43_wldev *dev, + const struct b43_txstatus *status); + +void b43_handle_hwtxstatus(struct b43_wldev *dev, + const struct b43_hwtxstatus *hw); + +void b43_tx_suspend(struct b43_wldev *dev); +void b43_tx_resume(struct b43_wldev *dev); + +#define B43_NR_QOSPARMS 22 +enum { + B43_QOSPARM_TXOP = 0, + B43_QOSPARM_CWMIN, + B43_QOSPARM_CWMAX, + B43_QOSPARM_CWCUR, + B43_QOSPARM_AIFS, + B43_QOSPARM_BSLOTS, + B43_QOSPARM_REGGAP, + B43_QOSPARM_STATUS, +}; +void b43_qos_init(struct b43_wldev *dev); + +/* Helper functions for converting the key-table index from "firmware-format" + * to "raw-format" and back. The firmware API changed for this at some revision. + * We need to account for that here. */ +static inline int b43_new_kidx_api(struct b43_wldev *dev) +{ + /* FIXME: Not sure the change was at rev 351 */ + return (dev->fw.rev >= 351); +} +static inline u8 b43_kidx_to_fw(struct b43_wldev *dev, u8 raw_kidx) +{ + u8 firmware_kidx; + if (b43_new_kidx_api(dev)) { + firmware_kidx = raw_kidx; + } else { + if (raw_kidx >= 4) /* Is per STA key? */ + firmware_kidx = raw_kidx - 4; + else + firmware_kidx = raw_kidx; /* TX default key */ + } + return firmware_kidx; +} +static inline u8 b43_kidx_to_raw(struct b43_wldev *dev, u8 firmware_kidx) +{ + u8 raw_kidx; + if (b43_new_kidx_api(dev)) + raw_kidx = firmware_kidx; + else + raw_kidx = firmware_kidx + 4; /* RX default keys or per STA keys */ + return raw_kidx; +} + +#endif /* B43_XMIT_H_ */ -- cgit v1.2.3-70-g09d2 From 75388acd0cd827dc1498043daa7d1c760902cd67 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Tue, 25 Sep 2007 16:46:54 -0700 Subject: [B43LEGACY]: add mac80211-based driver for legacy BCM43xx devices Signed-off-by: Larry Finger Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- MAINTAINERS | 7 + drivers/net/wireless/Kconfig | 1 + drivers/net/wireless/Makefile | 1 + drivers/net/wireless/b43legacy/Kconfig | 89 + drivers/net/wireless/b43legacy/Makefile | 14 + drivers/net/wireless/b43legacy/b43legacy.h | 829 ++++++ drivers/net/wireless/b43legacy/debugfs.c | 505 ++++ drivers/net/wireless/b43legacy/debugfs.h | 89 + drivers/net/wireless/b43legacy/dma.c | 1565 ++++++++++++ drivers/net/wireless/b43legacy/dma.h | 367 +++ drivers/net/wireless/b43legacy/ilt.c | 336 +++ drivers/net/wireless/b43legacy/ilt.h | 34 + drivers/net/wireless/b43legacy/leds.c | 302 +++ drivers/net/wireless/b43legacy/leds.h | 56 + drivers/net/wireless/b43legacy/main.c | 3805 ++++++++++++++++++++++++++++ drivers/net/wireless/b43legacy/main.h | 147 ++ drivers/net/wireless/b43legacy/phy.c | 2265 +++++++++++++++++ drivers/net/wireless/b43legacy/phy.h | 219 ++ drivers/net/wireless/b43legacy/pio.c | 668 +++++ drivers/net/wireless/b43legacy/pio.h | 172 ++ drivers/net/wireless/b43legacy/radio.c | 2131 ++++++++++++++++ drivers/net/wireless/b43legacy/radio.h | 98 + drivers/net/wireless/b43legacy/sysfs.c | 238 ++ drivers/net/wireless/b43legacy/sysfs.h | 9 + drivers/net/wireless/b43legacy/xmit.c | 642 +++++ drivers/net/wireless/b43legacy/xmit.h | 259 ++ 26 files changed, 14848 insertions(+) create mode 100644 drivers/net/wireless/b43legacy/Kconfig create mode 100644 drivers/net/wireless/b43legacy/Makefile create mode 100644 drivers/net/wireless/b43legacy/b43legacy.h create mode 100644 drivers/net/wireless/b43legacy/debugfs.c create mode 100644 drivers/net/wireless/b43legacy/debugfs.h create mode 100644 drivers/net/wireless/b43legacy/dma.c create mode 100644 drivers/net/wireless/b43legacy/dma.h create mode 100644 drivers/net/wireless/b43legacy/ilt.c create mode 100644 drivers/net/wireless/b43legacy/ilt.h create mode 100644 drivers/net/wireless/b43legacy/leds.c create mode 100644 drivers/net/wireless/b43legacy/leds.h create mode 100644 drivers/net/wireless/b43legacy/main.c create mode 100644 drivers/net/wireless/b43legacy/main.h create mode 100644 drivers/net/wireless/b43legacy/phy.c create mode 100644 drivers/net/wireless/b43legacy/phy.h create mode 100644 drivers/net/wireless/b43legacy/pio.c create mode 100644 drivers/net/wireless/b43legacy/pio.h create mode 100644 drivers/net/wireless/b43legacy/radio.c create mode 100644 drivers/net/wireless/b43legacy/radio.h create mode 100644 drivers/net/wireless/b43legacy/sysfs.c create mode 100644 drivers/net/wireless/b43legacy/sysfs.h create mode 100644 drivers/net/wireless/b43legacy/xmit.c create mode 100644 drivers/net/wireless/b43legacy/xmit.h (limited to 'drivers') diff --git a/MAINTAINERS b/MAINTAINERS index e6589c3b69c..ef9402807de 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -804,6 +804,13 @@ L: linux-wireless@vger.kernel.org W: http://bcm43xx.berlios.de/ S: Maintained +B43LEGACY WIRELESS DRIVER +P: Larry Finger +M: Larry.Finger@lwfinger.net +L: linux-wireless@vger.kernel.org +W: http://bcm43xx.berlios.de/ +S: Maintained + BCM43XX WIRELESS DRIVER (SOFTMAC BASED VERSION) P: Larry Finger M: Larry.Finger@lwfinger.net diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 7bed87e63da..c2102653b2a 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -580,6 +580,7 @@ config ADM8211 source "drivers/net/wireless/hostap/Kconfig" source "drivers/net/wireless/bcm43xx/Kconfig" source "drivers/net/wireless/b43/Kconfig" +source "drivers/net/wireless/b43legacy/Kconfig" source "drivers/net/wireless/zd1211rw/Kconfig" endmenu diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 765dbbcf54b..d8dd907e499 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -37,6 +37,7 @@ obj-$(CONFIG_PRISM54) += prism54/ obj-$(CONFIG_HOSTAP) += hostap/ obj-$(CONFIG_BCM43XX) += bcm43xx/ obj-$(CONFIG_B43) += b43/ +obj-$(CONFIG_B43LEGACY) += b43legacy/ obj-$(CONFIG_ZD1211RW) += zd1211rw/ # 16-bit wireless PCMCIA client drivers diff --git a/drivers/net/wireless/b43legacy/Kconfig b/drivers/net/wireless/b43legacy/Kconfig new file mode 100644 index 00000000000..7e23ec23fc9 --- /dev/null +++ b/drivers/net/wireless/b43legacy/Kconfig @@ -0,0 +1,89 @@ +config B43LEGACY + tristate "Broadcom 43xx-legacy wireless support (mac80211 stack)" + depends on SSB_POSSIBLE && MAC80211 && WLAN_80211 + select SSB + select FW_LOADER + select HW_RANDOM + ---help--- + b43legacy is a driver for 802.11b devices from Broadcom (BCM4301 and + BCM4303) and early model 802.11g chips (BCM4306 Ver. 2) used in the + Linksys WPC54G V1 PCMCIA devices. + + Newer 802.11g and 802.11a devices need b43. + + It is safe to include both b43 and b43legacy as the underlying glue + layer will automatically load the correct version for your device. + + This driver uses V3 firmware, which must be installed separately using + b43-fwcutter. + + This driver can be built as a module (recommended) that will be + called "b43legacy". If unsure, say M. + +# Auto-select SSB PCI-HOST support, if possible +config B43LEGACY_PCI_AUTOSELECT + bool + depends on B43LEGACY && SSB_PCIHOST_POSSIBLE + select SSB_PCIHOST + default y + +# Auto-select SSB PCICORE driver, if possible +config B43LEGACY_PCICORE_AUTOSELECT + bool + depends on B43LEGACY && SSB_DRIVER_PCICORE_POSSIBLE + select SSB_DRIVER_PCICORE + default y + +config B43LEGACY_DEBUG + bool "Broadcom 43xx-legacy debugging" + depends on B43LEGACY + default y + ---help--- + Say Y, because this information will help you get the driver running. + This option generates a minimum of log output. + +config B43LEGACY_DMA + bool + depends on B43LEGACY + +config B43LEGACY_PIO + bool + depends on B43LEGACY + +choice + prompt "Broadcom 43xx-legacy data transfer mode" + depends on B43LEGACY + default B43LEGACY_DMA_AND_PIO_MODE + +config B43LEGACY_DMA_AND_PIO_MODE + bool "DMA + PIO" + select B43LEGACY_DMA + select B43LEGACY_PIO + ---help--- + Include both, Direct Memory Access (DMA) and Programmed I/O (PIO) + data transfer modes. The mode actually used is selectable through + the module parameter "pio". With pio=0 as a module parameter, the + default DMA is used, otherwise PIO is used. + + If unsure, choose this option. + +config B43LEGACY_DMA_MODE + bool "DMA (Direct Memory Access) only" + select B43LEGACY_DMA + ---help--- + Only include Direct Memory Access (DMA). + This reduces the size of the driver module, by omitting the PIO code. + +config B43LEGACY_PIO_MODE + bool "PIO (Programmed I/O) only" + select B43LEGACY_PIO + ---help--- + Only include Programmed I/O (PIO). + This reduces the size of the driver module, by omitting the DMA code. + Please note that PIO transfers are slow (compared to DMA). + + Also note that not all devices of the b43legacy series support PIO. + + You should use PIO only if DMA does not work for you. + +endchoice diff --git a/drivers/net/wireless/b43legacy/Makefile b/drivers/net/wireless/b43legacy/Makefile new file mode 100644 index 00000000000..ec3a2482bba --- /dev/null +++ b/drivers/net/wireless/b43legacy/Makefile @@ -0,0 +1,14 @@ +obj-$(CONFIG_B43LEGACY) += b43legacy.o +b43legacy-obj-$(CONFIG_B43LEGACY_DEBUG) += debugfs.o + +b43legacy-obj-$(CONFIG_B43LEGACY_DMA) += dma.o +b43legacy-obj-$(CONFIG_B43LEGACY_PIO) += pio.o + +b43legacy-objs := main.o \ + ilt.o \ + leds.o \ + phy.o \ + radio.o \ + sysfs.o \ + xmit.o \ + $(b43legacy-obj-y) diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h new file mode 100644 index 00000000000..34a6277051a --- /dev/null +++ b/drivers/net/wireless/b43legacy/b43legacy.h @@ -0,0 +1,829 @@ +#ifndef B43legacy_H_ +#define B43legacy_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "debugfs.h" +#include "leds.h" +#include "phy.h" + + +#define B43legacy_IRQWAIT_MAX_RETRIES 100 + +#define B43legacy_RX_MAX_SSI 60 /* best guess at max ssi */ + +/* MMIO offsets */ +#define B43legacy_MMIO_DMA0_REASON 0x20 +#define B43legacy_MMIO_DMA0_IRQ_MASK 0x24 +#define B43legacy_MMIO_DMA1_REASON 0x28 +#define B43legacy_MMIO_DMA1_IRQ_MASK 0x2C +#define B43legacy_MMIO_DMA2_REASON 0x30 +#define B43legacy_MMIO_DMA2_IRQ_MASK 0x34 +#define B43legacy_MMIO_DMA3_REASON 0x38 +#define B43legacy_MMIO_DMA3_IRQ_MASK 0x3C +#define B43legacy_MMIO_DMA4_REASON 0x40 +#define B43legacy_MMIO_DMA4_IRQ_MASK 0x44 +#define B43legacy_MMIO_DMA5_REASON 0x48 +#define B43legacy_MMIO_DMA5_IRQ_MASK 0x4C +#define B43legacy_MMIO_MACCTL 0x120 +#define B43legacy_MMIO_STATUS_BITFIELD 0x120 +#define B43legacy_MMIO_STATUS2_BITFIELD 0x124 +#define B43legacy_MMIO_GEN_IRQ_REASON 0x128 +#define B43legacy_MMIO_GEN_IRQ_MASK 0x12C +#define B43legacy_MMIO_RAM_CONTROL 0x130 +#define B43legacy_MMIO_RAM_DATA 0x134 +#define B43legacy_MMIO_PS_STATUS 0x140 +#define B43legacy_MMIO_RADIO_HWENABLED_HI 0x158 +#define B43legacy_MMIO_SHM_CONTROL 0x160 +#define B43legacy_MMIO_SHM_DATA 0x164 +#define B43legacy_MMIO_SHM_DATA_UNALIGNED 0x166 +#define B43legacy_MMIO_XMITSTAT_0 0x170 +#define B43legacy_MMIO_XMITSTAT_1 0x174 +#define B43legacy_MMIO_REV3PLUS_TSF_LOW 0x180 /* core rev >= 3 only */ +#define B43legacy_MMIO_REV3PLUS_TSF_HIGH 0x184 /* core rev >= 3 only */ + +/* 32-bit DMA */ +#define B43legacy_MMIO_DMA32_BASE0 0x200 +#define B43legacy_MMIO_DMA32_BASE1 0x220 +#define B43legacy_MMIO_DMA32_BASE2 0x240 +#define B43legacy_MMIO_DMA32_BASE3 0x260 +#define B43legacy_MMIO_DMA32_BASE4 0x280 +#define B43legacy_MMIO_DMA32_BASE5 0x2A0 +/* 64-bit DMA */ +#define B43legacy_MMIO_DMA64_BASE0 0x200 +#define B43legacy_MMIO_DMA64_BASE1 0x240 +#define B43legacy_MMIO_DMA64_BASE2 0x280 +#define B43legacy_MMIO_DMA64_BASE3 0x2C0 +#define B43legacy_MMIO_DMA64_BASE4 0x300 +#define B43legacy_MMIO_DMA64_BASE5 0x340 +/* PIO */ +#define B43legacy_MMIO_PIO1_BASE 0x300 +#define B43legacy_MMIO_PIO2_BASE 0x310 +#define B43legacy_MMIO_PIO3_BASE 0x320 +#define B43legacy_MMIO_PIO4_BASE 0x330 + +#define B43legacy_MMIO_PHY_VER 0x3E0 +#define B43legacy_MMIO_PHY_RADIO 0x3E2 +#define B43legacy_MMIO_PHY0 0x3E6 +#define B43legacy_MMIO_ANTENNA 0x3E8 +#define B43legacy_MMIO_CHANNEL 0x3F0 +#define B43legacy_MMIO_CHANNEL_EXT 0x3F4 +#define B43legacy_MMIO_RADIO_CONTROL 0x3F6 +#define B43legacy_MMIO_RADIO_DATA_HIGH 0x3F8 +#define B43legacy_MMIO_RADIO_DATA_LOW 0x3FA +#define B43legacy_MMIO_PHY_CONTROL 0x3FC +#define B43legacy_MMIO_PHY_DATA 0x3FE +#define B43legacy_MMIO_MACFILTER_CONTROL 0x420 +#define B43legacy_MMIO_MACFILTER_DATA 0x422 +#define B43legacy_MMIO_RCMTA_COUNT 0x43C /* Receive Match Transmitter Addr */ +#define B43legacy_MMIO_RADIO_HWENABLED_LO 0x49A +#define B43legacy_MMIO_GPIO_CONTROL 0x49C +#define B43legacy_MMIO_GPIO_MASK 0x49E +#define B43legacy_MMIO_TSF_0 0x632 /* core rev < 3 only */ +#define B43legacy_MMIO_TSF_1 0x634 /* core rev < 3 only */ +#define B43legacy_MMIO_TSF_2 0x636 /* core rev < 3 only */ +#define B43legacy_MMIO_TSF_3 0x638 /* core rev < 3 only */ +#define B43legacy_MMIO_RNG 0x65A +#define B43legacy_MMIO_POWERUP_DELAY 0x6A8 + +/* SPROM boardflags_lo values */ +#define B43legacy_BFL_PACTRL 0x0002 +#define B43legacy_BFL_RSSI 0x0008 +#define B43legacy_BFL_EXTLNA 0x1000 + +/* GPIO register offset, in both ChipCommon and PCI core. */ +#define B43legacy_GPIO_CONTROL 0x6c + +/* SHM Routing */ +#define B43legacy_SHM_SHARED 0x0001 +#define B43legacy_SHM_WIRELESS 0x0002 +#define B43legacy_SHM_HW 0x0004 +#define B43legacy_SHM_UCODE 0x0300 + +/* SHM Routing modifiers */ +#define B43legacy_SHM_AUTOINC_R 0x0200 /* Read Auto-increment */ +#define B43legacy_SHM_AUTOINC_W 0x0100 /* Write Auto-increment */ +#define B43legacy_SHM_AUTOINC_RW (B43legacy_SHM_AUTOINC_R | \ + B43legacy_SHM_AUTOINC_W) + +/* Misc SHM_SHARED offsets */ +#define B43legacy_SHM_SH_WLCOREREV 0x0016 /* 802.11 core revision */ +#define B43legacy_SHM_SH_HOSTFLO 0x005E /* Hostflags ucode opts (low) */ +#define B43legacy_SHM_SH_HOSTFHI 0x0060 /* Hostflags ucode opts (high) */ +/* SHM_SHARED crypto engine */ +#define B43legacy_SHM_SH_KEYIDXBLOCK 0x05D4 /* Key index/algorithm block */ +/* SHM_SHARED beacon variables */ +#define B43legacy_SHM_SH_BEACPHYCTL 0x0054 /* Beacon PHY TX control word */ +/* SHM_SHARED ACK/CTS control */ +#define B43legacy_SHM_SH_ACKCTSPHYCTL 0x0022 /* ACK/CTS PHY control word */ +/* SHM_SHARED probe response variables */ +#define B43legacy_SHM_SH_PRPHYCTL 0x0188 /* Probe Resp PHY TX control */ +#define B43legacy_SHM_SH_PRMAXTIME 0x0074 /* Probe Response max time */ +/* SHM_SHARED rate tables */ +/* SHM_SHARED microcode soft registers */ +#define B43legacy_SHM_SH_UCODEREV 0x0000 /* Microcode revision */ +#define B43legacy_SHM_SH_UCODEPATCH 0x0002 /* Microcode patchlevel */ +#define B43legacy_SHM_SH_UCODEDATE 0x0004 /* Microcode date */ +#define B43legacy_SHM_SH_UCODETIME 0x0006 /* Microcode time */ + +#define B43legacy_UCODEFLAGS_OFFSET 0x005E + +/* Hardware Radio Enable masks */ +#define B43legacy_MMIO_RADIO_HWENABLED_HI_MASK (1 << 16) +#define B43legacy_MMIO_RADIO_HWENABLED_LO_MASK (1 << 4) + +/* HostFlags. See b43legacy_hf_read/write() */ +#define B43legacy_HF_SYMW 0x00000002 /* G-PHY SYM workaround */ +#define B43legacy_HF_GDCW 0x00000020 /* G-PHY DV cancel filter */ +#define B43legacy_HF_OFDMPABOOST 0x00000040 /* Enable PA boost OFDM */ +#define B43legacy_HF_EDCF 0x00000100 /* on if WME/MAC suspended */ + +/* MacFilter offsets. */ +#define B43legacy_MACFILTER_SELF 0x0000 +#define B43legacy_MACFILTER_BSSID 0x0003 +#define B43legacy_MACFILTER_MAC 0x0010 + +/* PHYVersioning */ +#define B43legacy_PHYTYPE_B 0x01 +#define B43legacy_PHYTYPE_G 0x02 + +/* PHYRegisters */ +#define B43legacy_PHY_G_LO_CONTROL 0x0810 +#define B43legacy_PHY_ILT_G_CTRL 0x0472 +#define B43legacy_PHY_ILT_G_DATA1 0x0473 +#define B43legacy_PHY_ILT_G_DATA2 0x0474 +#define B43legacy_PHY_G_PCTL 0x0029 +#define B43legacy_PHY_RADIO_BITFIELD 0x0401 +#define B43legacy_PHY_G_CRS 0x0429 +#define B43legacy_PHY_NRSSILT_CTRL 0x0803 +#define B43legacy_PHY_NRSSILT_DATA 0x0804 + +/* RadioRegisters */ +#define B43legacy_RADIOCTL_ID 0x01 + +/* MAC Control bitfield */ +#define B43legacy_MACCTL_IHR_ENABLED 0x00000400 /* IHR Region Enabled */ +#define B43legacy_MACCTL_INFRA 0x00020000 /* Infrastructure mode */ +#define B43legacy_MACCTL_AP 0x00040000 /* AccessPoint mode */ +#define B43legacy_MACCTL_KEEP_BADPLCP 0x00200000 /* Keep bad PLCP frames */ +#define B43legacy_MACCTL_KEEP_CTL 0x00400000 /* Keep control frames */ +#define B43legacy_MACCTL_KEEP_BAD 0x00800000 /* Keep bad frames (FCS) */ +#define B43legacy_MACCTL_PROMISC 0x01000000 /* Promiscuous mode */ +#define B43legacy_MACCTL_GMODE 0x80000000 /* G Mode */ + +/* StatusBitField */ +#define B43legacy_SBF_MAC_ENABLED 0x00000001 +#define B43legacy_SBF_CORE_READY 0x00000004 +#define B43legacy_SBF_400 0x00000400 /*FIXME: fix name*/ +#define B43legacy_SBF_XFER_REG_BYTESWAP 0x00010000 +#define B43legacy_SBF_MODE_NOTADHOC 0x00020000 +#define B43legacy_SBF_MODE_AP 0x00040000 +#define B43legacy_SBF_RADIOREG_LOCK 0x00080000 +#define B43legacy_SBF_MODE_MONITOR 0x00400000 +#define B43legacy_SBF_MODE_PROMISC 0x01000000 +#define B43legacy_SBF_PS1 0x02000000 +#define B43legacy_SBF_PS2 0x04000000 +#define B43legacy_SBF_NO_SSID_BCAST 0x08000000 +#define B43legacy_SBF_TIME_UPDATE 0x10000000 + +/* 802.11 core specific TM State Low flags */ +#define B43legacy_TMSLOW_GMODE 0x20000000 /* G Mode Enable */ +#define B43legacy_TMSLOW_PLLREFSEL 0x00200000 /* PLL Freq Ref Select */ +#define B43legacy_TMSLOW_MACPHYCLKEN 0x00100000 /* MAC PHY Clock Ctrl Enbl */ +#define B43legacy_TMSLOW_PHYRESET 0x00080000 /* PHY Reset */ +#define B43legacy_TMSLOW_PHYCLKEN 0x00040000 /* PHY Clock Enable */ + +/* 802.11 core specific TM State High flags */ +#define B43legacy_TMSHIGH_FCLOCK 0x00040000 /* Fast Clock Available */ +#define B43legacy_TMSHIGH_GPHY 0x00010000 /* G-PHY avail (rev >= 5) */ + +#define B43legacy_UCODEFLAG_AUTODIV 0x0001 + +/* Generic-Interrupt reasons. */ +#define B43legacy_IRQ_MAC_SUSPENDED 0x00000001 +#define B43legacy_IRQ_BEACON 0x00000002 +#define B43legacy_IRQ_TBTT_INDI 0x00000004 /* Target Beacon Transmit Time */ +#define B43legacy_IRQ_BEACON_TX_OK 0x00000008 +#define B43legacy_IRQ_BEACON_CANCEL 0x00000010 +#define B43legacy_IRQ_ATIM_END 0x00000020 +#define B43legacy_IRQ_PMQ 0x00000040 +#define B43legacy_IRQ_PIO_WORKAROUND 0x00000100 +#define B43legacy_IRQ_MAC_TXERR 0x00000200 +#define B43legacy_IRQ_PHY_TXERR 0x00000800 +#define B43legacy_IRQ_PMEVENT 0x00001000 +#define B43legacy_IRQ_TIMER0 0x00002000 +#define B43legacy_IRQ_TIMER1 0x00004000 +#define B43legacy_IRQ_DMA 0x00008000 +#define B43legacy_IRQ_TXFIFO_FLUSH_OK 0x00010000 +#define B43legacy_IRQ_CCA_MEASURE_OK 0x00020000 +#define B43legacy_IRQ_NOISESAMPLE_OK 0x00040000 +#define B43legacy_IRQ_UCODE_DEBUG 0x08000000 +#define B43legacy_IRQ_RFKILL 0x10000000 +#define B43legacy_IRQ_TX_OK 0x20000000 +#define B43legacy_IRQ_PHY_G_CHANGED 0x40000000 +#define B43legacy_IRQ_TIMEOUT 0x80000000 + +#define B43legacy_IRQ_ALL 0xFFFFFFFF +#define B43legacy_IRQ_MASKTEMPLATE (B43legacy_IRQ_MAC_SUSPENDED | \ + B43legacy_IRQ_BEACON | \ + B43legacy_IRQ_TBTT_INDI | \ + B43legacy_IRQ_ATIM_END | \ + B43legacy_IRQ_PMQ | \ + B43legacy_IRQ_MAC_TXERR | \ + B43legacy_IRQ_PHY_TXERR | \ + B43legacy_IRQ_DMA | \ + B43legacy_IRQ_TXFIFO_FLUSH_OK | \ + B43legacy_IRQ_NOISESAMPLE_OK | \ + B43legacy_IRQ_UCODE_DEBUG | \ + B43legacy_IRQ_RFKILL | \ + B43legacy_IRQ_TX_OK) + +/* Device specific rate values. + * The actual values defined here are (rate_in_mbps * 2). + * Some code depends on this. Don't change it. */ +#define B43legacy_CCK_RATE_1MB 2 +#define B43legacy_CCK_RATE_2MB 4 +#define B43legacy_CCK_RATE_5MB 11 +#define B43legacy_CCK_RATE_11MB 22 +#define B43legacy_OFDM_RATE_6MB 12 +#define B43legacy_OFDM_RATE_9MB 18 +#define B43legacy_OFDM_RATE_12MB 24 +#define B43legacy_OFDM_RATE_18MB 36 +#define B43legacy_OFDM_RATE_24MB 48 +#define B43legacy_OFDM_RATE_36MB 72 +#define B43legacy_OFDM_RATE_48MB 96 +#define B43legacy_OFDM_RATE_54MB 108 +/* Convert a b43legacy rate value to a rate in 100kbps */ +#define B43legacy_RATE_TO_100KBPS(rate) (((rate) * 10) / 2) + + +#define B43legacy_DEFAULT_SHORT_RETRY_LIMIT 7 +#define B43legacy_DEFAULT_LONG_RETRY_LIMIT 4 + +/* Max size of a security key */ +#define B43legacy_SEC_KEYSIZE 16 +/* Security algorithms. */ +enum { + B43legacy_SEC_ALGO_NONE = 0, /* unencrypted, as of TX header. */ + B43legacy_SEC_ALGO_WEP40, + B43legacy_SEC_ALGO_TKIP, + B43legacy_SEC_ALGO_AES, + B43legacy_SEC_ALGO_WEP104, + B43legacy_SEC_ALGO_AES_LEGACY, +}; + +/* Core Information Registers */ +#define B43legacy_CIR_BASE 0xf00 +#define B43legacy_CIR_SBTPSFLAG (B43legacy_CIR_BASE + 0x18) +#define B43legacy_CIR_SBIMSTATE (B43legacy_CIR_BASE + 0x90) +#define B43legacy_CIR_SBINTVEC (B43legacy_CIR_BASE + 0x94) +#define B43legacy_CIR_SBTMSTATELOW (B43legacy_CIR_BASE + 0x98) +#define B43legacy_CIR_SBTMSTATEHIGH (B43legacy_CIR_BASE + 0x9c) +#define B43legacy_CIR_SBIMCONFIGLOW (B43legacy_CIR_BASE + 0xa8) +#define B43legacy_CIR_SB_ID_HI (B43legacy_CIR_BASE + 0xfc) + +/* sbtmstatehigh state flags */ +#define B43legacy_SBTMSTATEHIGH_SERROR 0x00000001 +#define B43legacy_SBTMSTATEHIGH_BUSY 0x00000004 +#define B43legacy_SBTMSTATEHIGH_TIMEOUT 0x00000020 +#define B43legacy_SBTMSTATEHIGH_G_PHY_AVAIL 0x00010000 +#define B43legacy_SBTMSTATEHIGH_COREFLAGS 0x1FFF0000 +#define B43legacy_SBTMSTATEHIGH_DMA64BIT 0x10000000 +#define B43legacy_SBTMSTATEHIGH_GATEDCLK 0x20000000 +#define B43legacy_SBTMSTATEHIGH_BISTFAILED 0x40000000 +#define B43legacy_SBTMSTATEHIGH_BISTCOMPLETE 0x80000000 + +/* sbimstate flags */ +#define B43legacy_SBIMSTATE_IB_ERROR 0x20000 +#define B43legacy_SBIMSTATE_TIMEOUT 0x40000 + +#define PFX KBUILD_MODNAME ": " +#ifdef assert +# undef assert +#endif +#ifdef CONFIG_B43LEGACY_DEBUG +# define B43legacy_WARN_ON(expr) \ + do { \ + if (unlikely((expr))) { \ + printk(KERN_INFO PFX "Test (%s) failed at:" \ + " %s:%d:%s()\n", \ + #expr, __FILE__, \ + __LINE__, __FUNCTION__); \ + } \ + } while (0) +# define B43legacy_BUG_ON(expr) \ + do { \ + if (unlikely((expr))) { \ + printk(KERN_INFO PFX "Test (%s) failed\n", \ + #expr); \ + BUG_ON(expr); \ + } \ + } while (0) +# define B43legacy_DEBUG 1 +#else +# define B43legacy_WARN_ON(x) do { /* nothing */ } while (0) +# define B43legacy_BUG_ON(x) do { /* nothing */ } while (0) +# define B43legacy_DEBUG 0 +#endif + + +struct net_device; +struct pci_dev; +struct b43legacy_dmaring; +struct b43legacy_pioqueue; + +/* The firmware file header */ +#define B43legacy_FW_TYPE_UCODE 'u' +#define B43legacy_FW_TYPE_PCM 'p' +#define B43legacy_FW_TYPE_IV 'i' +struct b43legacy_fw_header { + /* File type */ + u8 type; + /* File format version */ + u8 ver; + u8 __padding[2]; + /* Size of the data. For ucode and PCM this is in bytes. + * For IV this is number-of-ivs. */ + __be32 size; +} __attribute__((__packed__)); + +/* Initial Value file format */ +#define B43legacy_IV_OFFSET_MASK 0x7FFF +#define B43legacy_IV_32BIT 0x8000 +struct b43legacy_iv { + __be16 offset_size; + union { + __be16 d16; + __be32 d32; + } data __attribute__((__packed__)); +} __attribute__((__packed__)); + +#define B43legacy_PHYMODE(phytype) (1 << (phytype)) +#define B43legacy_PHYMODE_B B43legacy_PHYMODE \ + ((B43legacy_PHYTYPE_B)) +#define B43legacy_PHYMODE_G B43legacy_PHYMODE \ + ((B43legacy_PHYTYPE_G)) + +/* Value pair to measure the LocalOscillator. */ +struct b43legacy_lopair { + s8 low; + s8 high; + u8 used:1; +}; +#define B43legacy_LO_COUNT (14*4) + +struct b43legacy_phy { + /* Possible PHYMODEs on this PHY */ + u8 possible_phymodes; + /* GMODE bit enabled in MACCTL? */ + bool gmode; + /* Possible ieee80211 subsystem hwmodes for this PHY. + * Which mode is selected, depends on thr GMODE enabled bit */ +#define B43legacy_MAX_PHYHWMODES 2 + struct ieee80211_hw_mode hwmodes[B43legacy_MAX_PHYHWMODES]; + + /* Analog Type */ + u8 analog; + /* B43legacy_PHYTYPE_ */ + u8 type; + /* PHY revision number. */ + u8 rev; + + u16 antenna_diversity; + u16 savedpctlreg; + /* Radio versioning */ + u16 radio_manuf; /* Radio manufacturer */ + u16 radio_ver; /* Radio version */ + u8 calibrated:1; + u8 radio_rev; /* Radio revision */ + + bool radio_on; /* Radio switched on/off */ + bool locked; /* Only used in b43legacy_phy_{un}lock() */ + bool dyn_tssi_tbl; /* tssi2dbm is kmalloc()ed. */ + + /* ACI (adjacent channel interference) flags. */ + bool aci_enable; + bool aci_wlan_automatic; + bool aci_hw_rssi; + + u16 minlowsig[2]; + u16 minlowsigpos[2]; + + /* LO Measurement Data. + * Use b43legacy_get_lopair() to get a value. + */ + struct b43legacy_lopair *_lo_pairs; + /* TSSI to dBm table in use */ + const s8 *tssi2dbm; + /* idle TSSI value */ + s8 idle_tssi; + /* Target idle TSSI */ + int tgt_idle_tssi; + /* Current idle TSSI */ + int cur_idle_tssi; + + /* LocalOscillator control values. */ + struct b43legacy_txpower_lo_control *lo_control; + /* Values from b43legacy_calc_loopback_gain() */ + s16 max_lb_gain; /* Maximum Loopback gain in hdB */ + s16 trsw_rx_gain; /* TRSW RX gain in hdB */ + s16 lna_lod_gain; /* LNA lod */ + s16 lna_gain; /* LNA */ + s16 pga_gain; /* PGA */ + + /* PHY lock for core.rev < 3 + * This lock is only used by b43legacy_phy_{un}lock() + */ + spinlock_t lock; + + /* Desired TX power level (in dBm). This is set by the user and + * adjusted in b43legacy_phy_xmitpower(). */ + u8 power_level; + + /* Values from b43legacy_calc_loopback_gain() */ + u16 loopback_gain[2]; + + /* TX Power control values. */ + /* B/G PHY */ + struct { + /* Current Radio Attenuation for TXpower recalculation. */ + u16 rfatt; + /* Current Baseband Attenuation for TXpower recalculation. */ + u16 bbatt; + /* Current TXpower control value for TXpower recalculation. */ + u16 txctl1; + u16 txctl2; + }; + /* A PHY */ + struct { + u16 txpwr_offset; + }; + +#ifdef CONFIG_B43LEGACY_DEBUG + bool manual_txpower_control; /* Manual TX-power control enabled? */ +#endif + /* Current Interference Mitigation mode */ + int interfmode; + /* Stack of saved values from the Interference Mitigation code. + * Each value in the stack is layed out as follows: + * bit 0-11: offset + * bit 12-15: register ID + * bit 16-32: value + * register ID is: 0x1 PHY, 0x2 Radio, 0x3 ILT + */ +#define B43legacy_INTERFSTACK_SIZE 26 + u32 interfstack[B43legacy_INTERFSTACK_SIZE]; + + /* Saved values from the NRSSI Slope calculation */ + s16 nrssi[2]; + s32 nrssislope; + /* In memory nrssi lookup table. */ + s8 nrssi_lt[64]; + + /* current channel */ + u8 channel; + + u16 lofcal; + + u16 initval; +}; + +/* Data structures for DMA transmission, per 80211 core. */ +struct b43legacy_dma { + struct b43legacy_dmaring *tx_ring0; + struct b43legacy_dmaring *tx_ring1; + struct b43legacy_dmaring *tx_ring2; + struct b43legacy_dmaring *tx_ring3; + struct b43legacy_dmaring *tx_ring4; + struct b43legacy_dmaring *tx_ring5; + + struct b43legacy_dmaring *rx_ring0; + struct b43legacy_dmaring *rx_ring3; /* only on core.rev < 5 */ +}; + +/* Data structures for PIO transmission, per 80211 core. */ +struct b43legacy_pio { + struct b43legacy_pioqueue *queue0; + struct b43legacy_pioqueue *queue1; + struct b43legacy_pioqueue *queue2; + struct b43legacy_pioqueue *queue3; +}; + +/* Context information for a noise calculation (Link Quality). */ +struct b43legacy_noise_calculation { + u8 channel_at_start; + bool calculation_running; + u8 nr_samples; + s8 samples[8][4]; +}; + +struct b43legacy_stats { + u8 link_noise; + /* Store the last TX/RX times here for updating the leds. */ + unsigned long last_tx; + unsigned long last_rx; +}; + +struct b43legacy_key { + void *keyconf; + bool enabled; + u8 algorithm; +}; + +struct b43legacy_wldev; + +/* Data structure for the WLAN parts (802.11 cores) of the b43legacy chip. */ +struct b43legacy_wl { + /* Pointer to the active wireless device on this chip */ + struct b43legacy_wldev *current_dev; + /* Pointer to the ieee80211 hardware data structure */ + struct ieee80211_hw *hw; + + spinlock_t irq_lock; /* locks IRQ */ + struct mutex mutex; /* locks wireless core state */ + spinlock_t leds_lock; /* lock for leds */ + + /* We can only have one operating interface (802.11 core) + * at a time. General information about this interface follows. + */ + + /* Opaque ID of the operating interface (!= monitor + * interface) from the ieee80211 subsystem. + * Do not modify. + */ + int if_id; + /* MAC address (can be NULL). */ + const u8 *mac_addr; + /* Current BSSID (can be NULL). */ + const u8 *bssid; + /* Interface type. (IEEE80211_IF_TYPE_XXX) */ + int if_type; + /* Counter of active monitor interfaces. */ + int monitor; + /* Is the card operating in AP, STA or IBSS mode? */ + bool operating; + /* Promisc mode active? + * Note that (monitor != 0) implies promisc. + */ + bool promisc; + /* Stats about the wireless interface */ + struct ieee80211_low_level_stats ieee_stats; + + struct hwrng rng; + u8 rng_initialized; + char rng_name[30 + 1]; + + /* List of all wireless devices on this chip */ + struct list_head devlist; + u8 nr_devs; +}; + +/* Pointers to the firmware data and meta information about it. */ +struct b43legacy_firmware { + /* Microcode */ + const struct firmware *ucode; + /* PCM code */ + const struct firmware *pcm; + /* Initial MMIO values for the firmware */ + const struct firmware *initvals; + /* Initial MMIO values for the firmware, band-specific */ + const struct firmware *initvals_band; + /* Firmware revision */ + u16 rev; + /* Firmware patchlevel */ + u16 patch; +}; + +/* Device (802.11 core) initialization status. */ +enum { + B43legacy_STAT_UNINIT = 0, /* Uninitialized. */ + B43legacy_STAT_INITIALIZED = 1, /* Initialized, not yet started. */ + B43legacy_STAT_STARTED = 2, /* Up and running. */ +}; +#define b43legacy_status(wldev) atomic_read(&(wldev)->__init_status) +#define b43legacy_set_status(wldev, stat) do { \ + atomic_set(&(wldev)->__init_status, (stat)); \ + smp_wmb(); \ + } while (0) + +/* *** --- HOW LOCKING WORKS IN B43legacy --- *** + * + * You should always acquire both, wl->mutex and wl->irq_lock unless: + * - You don't need to acquire wl->irq_lock, if the interface is stopped. + * - You don't need to acquire wl->mutex in the IRQ handler, IRQ tasklet + * and packet TX path (and _ONLY_ there.) + */ + +/* Data structure for one wireless device (802.11 core) */ +struct b43legacy_wldev { + struct ssb_device *dev; + struct b43legacy_wl *wl; + + /* The device initialization status. + * Use b43legacy_status() to query. */ + atomic_t __init_status; + /* Saved init status for handling suspend. */ + int suspend_init_status; + + bool __using_pio; /* Using pio rather than dma. */ + bool bad_frames_preempt;/* Use "Bad Frames Preemption". */ + bool reg124_set_0x4; /* Variable to keep track of IRQ. */ + bool short_preamble; /* TRUE if using short preamble. */ + bool short_slot; /* TRUE if using short slot timing. */ + bool radio_hw_enable; /* State of radio hardware enable bit. */ + + /* PHY/Radio device. */ + struct b43legacy_phy phy; + union { + /* DMA engines. */ + struct b43legacy_dma dma; + /* PIO engines. */ + struct b43legacy_pio pio; + }; + + /* Various statistics about the physical device. */ + struct b43legacy_stats stats; + +#define B43legacy_NR_LEDS 4 + struct b43legacy_led leds[B43legacy_NR_LEDS]; + + /* Reason code of the last interrupt. */ + u32 irq_reason; + u32 dma_reason[6]; + /* saved irq enable/disable state bitfield. */ + u32 irq_savedstate; + /* Link Quality calculation context. */ + struct b43legacy_noise_calculation noisecalc; + /* if > 0 MAC is suspended. if == 0 MAC is enabled. */ + int mac_suspended; + + /* Interrupt Service Routine tasklet (bottom-half) */ + struct tasklet_struct isr_tasklet; + + /* Periodic tasks */ + struct delayed_work periodic_work; + unsigned int periodic_state; + + struct work_struct restart_work; + + /* encryption/decryption */ + u16 ktp; /* Key table pointer */ + u8 max_nr_keys; + struct b43legacy_key key[58]; + + /* Cached beacon template while uploading the template. */ + struct sk_buff *cached_beacon; + + /* Firmware data */ + struct b43legacy_firmware fw; + + /* Devicelist in struct b43legacy_wl (all 802.11 cores) */ + struct list_head list; + + /* Debugging stuff follows. */ +#ifdef CONFIG_B43LEGACY_DEBUG + struct b43legacy_dfsentry *dfsentry; +#endif +}; + + +static inline +struct b43legacy_wl *hw_to_b43legacy_wl(struct ieee80211_hw *hw) +{ + return hw->priv; +} + +/* Helper function, which returns a boolean. + * TRUE, if PIO is used; FALSE, if DMA is used. + */ +#if defined(CONFIG_B43LEGACY_DMA) && defined(CONFIG_B43LEGACY_PIO) +static inline +int b43legacy_using_pio(struct b43legacy_wldev *dev) +{ + return dev->__using_pio; +} +#elif defined(CONFIG_B43LEGACY_DMA) +static inline +int b43legacy_using_pio(struct b43legacy_wldev *dev) +{ + return 0; +} +#elif defined(CONFIG_B43LEGACY_PIO) +static inline +int b43legacy_using_pio(struct b43legacy_wldev *dev) +{ + return 1; +} +#else +# error "Using neither DMA nor PIO? Confused..." +#endif + + +static inline +struct b43legacy_wldev *dev_to_b43legacy_wldev(struct device *dev) +{ + struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); + return ssb_get_drvdata(ssb_dev); +} + +/* Is the device operating in a specified mode (IEEE80211_IF_TYPE_XXX). */ +static inline +int b43legacy_is_mode(struct b43legacy_wl *wl, int type) +{ + if (type == IEEE80211_IF_TYPE_MNTR) + return !!(wl->monitor); + return (wl->operating && + wl->if_type == type); +} + +static inline +bool is_bcm_board_vendor(struct b43legacy_wldev *dev) +{ + return (dev->dev->bus->boardinfo.vendor == PCI_VENDOR_ID_BROADCOM); +} + +static inline +u16 b43legacy_read16(struct b43legacy_wldev *dev, u16 offset) +{ + return ssb_read16(dev->dev, offset); +} + +static inline +void b43legacy_write16(struct b43legacy_wldev *dev, u16 offset, u16 value) +{ + ssb_write16(dev->dev, offset, value); +} + +static inline +u32 b43legacy_read32(struct b43legacy_wldev *dev, u16 offset) +{ + return ssb_read32(dev->dev, offset); +} + +static inline +void b43legacy_write32(struct b43legacy_wldev *dev, u16 offset, u32 value) +{ + ssb_write32(dev->dev, offset, value); +} + +static inline +struct b43legacy_lopair *b43legacy_get_lopair(struct b43legacy_phy *phy, + u16 radio_attenuation, + u16 baseband_attenuation) +{ + return phy->_lo_pairs + (radio_attenuation + + 14 * (baseband_attenuation / 2)); +} + + + +/* Message printing */ +void b43legacyinfo(struct b43legacy_wl *wl, const char *fmt, ...) + __attribute__((format(printf, 2, 3))); +void b43legacyerr(struct b43legacy_wl *wl, const char *fmt, ...) + __attribute__((format(printf, 2, 3))); +void b43legacywarn(struct b43legacy_wl *wl, const char *fmt, ...) + __attribute__((format(printf, 2, 3))); +#if B43legacy_DEBUG +void b43legacydbg(struct b43legacy_wl *wl, const char *fmt, ...) + __attribute__((format(printf, 2, 3))); +#else /* DEBUG */ +# define b43legacydbg(wl, fmt...) do { /* nothing */ } while (0) +#endif /* DEBUG */ + + +/** Limit a value between two limits */ +#ifdef limit_value +# undef limit_value +#endif +#define limit_value(value, min, max) \ + ({ \ + typeof(value) __value = (value); \ + typeof(value) __min = (min); \ + typeof(value) __max = (max); \ + if (__value < __min) \ + __value = __min; \ + else if (__value > __max) \ + __value = __max; \ + __value; \ + }) + +/* Macros for printing a value in Q5.2 format */ +#define Q52_FMT "%u.%u" +#define Q52_ARG(q52) ((q52) / 4), (((q52) & 3) * 100 / 4) + +#endif /* B43legacy_H_ */ diff --git a/drivers/net/wireless/b43legacy/debugfs.c b/drivers/net/wireless/b43legacy/debugfs.c new file mode 100644 index 00000000000..eefa6fb7968 --- /dev/null +++ b/drivers/net/wireless/b43legacy/debugfs.c @@ -0,0 +1,505 @@ +/* + + Broadcom B43legacy wireless driver + + debugfs driver debugging code + + Copyright (c) 2005-2007 Michael Buesch + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include +#include +#include +#include +#include +#include + +#include "b43legacy.h" +#include "main.h" +#include "debugfs.h" +#include "dma.h" +#include "pio.h" +#include "xmit.h" + + +/* The root directory. */ +static struct dentry *rootdir; + +struct b43legacy_debugfs_fops { + ssize_t (*read)(struct b43legacy_wldev *dev, char *buf, size_t bufsize); + int (*write)(struct b43legacy_wldev *dev, const char *buf, size_t count); + struct file_operations fops; + /* Offset of struct b43legacy_dfs_file in struct b43legacy_dfsentry */ + size_t file_struct_offset; + /* Take wl->irq_lock before calling read/write? */ + bool take_irqlock; +}; + +static inline +struct b43legacy_dfs_file * fops_to_dfs_file(struct b43legacy_wldev *dev, + const struct b43legacy_debugfs_fops *dfops) +{ + void *p; + + p = dev->dfsentry; + p += dfops->file_struct_offset; + + return p; +} + + +#define fappend(fmt, x...) \ + do { \ + if (bufsize - count) \ + count += snprintf(buf + count, \ + bufsize - count, \ + fmt , ##x); \ + else \ + printk(KERN_ERR "b43legacy: fappend overflow\n"); \ + } while (0) + + +/* wl->irq_lock is locked */ +static ssize_t tsf_read_file(struct b43legacy_wldev *dev, char *buf, size_t bufsize) +{ + ssize_t count = 0; + u64 tsf; + + b43legacy_tsf_read(dev, &tsf); + fappend("0x%08x%08x\n", + (unsigned int)((tsf & 0xFFFFFFFF00000000ULL) >> 32), + (unsigned int)(tsf & 0xFFFFFFFFULL)); + + return count; +} + +/* wl->irq_lock is locked */ +static int tsf_write_file(struct b43legacy_wldev *dev, const char *buf, size_t count) +{ + u64 tsf; + + if (sscanf(buf, "%llu", (unsigned long long *)(&tsf)) != 1) + return -EINVAL; + b43legacy_tsf_write(dev, tsf); + + return 0; +} + +/* wl->irq_lock is locked */ +static ssize_t ucode_regs_read_file(struct b43legacy_wldev *dev, char *buf, size_t bufsize) +{ + ssize_t count = 0; + int i; + + for (i = 0; i < 64; i++) { + fappend("r%d = 0x%04x\n", i, + b43legacy_shm_read16(dev, B43legacy_SHM_WIRELESS, i)); + } + + return count; +} + +/* wl->irq_lock is locked */ +static ssize_t shm_read_file(struct b43legacy_wldev *dev, char *buf, size_t bufsize) +{ + ssize_t count = 0; + int i; + u16 tmp; + __le16 *le16buf = (__le16 *)buf; + + for (i = 0; i < 0x1000; i++) { + if (bufsize <= 0) + break; + tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 2 * i); + le16buf[i] = cpu_to_le16(tmp); + count += sizeof(tmp); + bufsize -= sizeof(tmp); + } + + return count; +} + +static ssize_t txstat_read_file(struct b43legacy_wldev *dev, char *buf, size_t bufsize) +{ + struct b43legacy_txstatus_log *log = &dev->dfsentry->txstatlog; + ssize_t count = 0; + unsigned long flags; + int i, idx; + struct b43legacy_txstatus *stat; + + spin_lock_irqsave(&log->lock, flags); + if (log->end < 0) { + fappend("Nothing transmitted, yet\n"); + goto out_unlock; + } + fappend("b43legacy TX status reports:\n\n" + "index | cookie | seq | phy_stat | frame_count | " + "rts_count | supp_reason | pm_indicated | " + "intermediate | for_ampdu | acked\n" "---\n"); + i = log->end + 1; + idx = 0; + while (1) { + if (i == B43legacy_NR_LOGGED_TXSTATUS) + i = 0; + stat = &(log->log[i]); + if (stat->cookie) { + fappend("%03d | " + "0x%04X | 0x%04X | 0x%02X | " + "0x%X | 0x%X | " + "%u | %u | " + "%u | %u | %u\n", + idx, + stat->cookie, stat->seq, stat->phy_stat, + stat->frame_count, stat->rts_count, + stat->supp_reason, stat->pm_indicated, + stat->intermediate, stat->for_ampdu, + stat->acked); + idx++; + } + if (i == log->end) + break; + i++; + } +out_unlock: + spin_unlock_irqrestore(&log->lock, flags); + + return count; +} + +/* wl->irq_lock is locked */ +static int restart_write_file(struct b43legacy_wldev *dev, const char *buf, size_t count) +{ + int err = 0; + + if (count > 0 && buf[0] == '1') { + b43legacy_controller_restart(dev, "manually restarted"); + } else + err = -EINVAL; + + return err; +} + +#undef fappend + +static int b43legacy_debugfs_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t b43legacy_debugfs_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct b43legacy_wldev *dev; + struct b43legacy_debugfs_fops *dfops; + struct b43legacy_dfs_file *dfile; + ssize_t ret = 0; + char *buf; + const size_t bufsize = 1024 * 128; + const size_t buforder = get_order(bufsize); + int err = 0; + + if (!count) + return 0; + dev = file->private_data; + if (!dev) + return -ENODEV; + + mutex_lock(&dev->wl->mutex); + if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) { + err = -ENODEV; + goto out_unlock; + } + + dfops = container_of(file->f_op, struct b43legacy_debugfs_fops, fops); + if (!dfops->read) { + err = -ENOSYS; + goto out_unlock; + } + dfile = fops_to_dfs_file(dev, dfops); + + if (!dfile->buffer) { + buf = (char *)__get_free_pages(GFP_KERNEL, buforder); + if (!buf) { + err = -ENOMEM; + goto out_unlock; + } + memset(buf, 0, bufsize); + if (dfops->take_irqlock) { + spin_lock_irq(&dev->wl->irq_lock); + ret = dfops->read(dev, buf, bufsize); + spin_unlock_irq(&dev->wl->irq_lock); + } else + ret = dfops->read(dev, buf, bufsize); + if (ret <= 0) { + free_pages((unsigned long)buf, buforder); + err = ret; + goto out_unlock; + } + dfile->data_len = ret; + dfile->buffer = buf; + } + + ret = simple_read_from_buffer(userbuf, count, ppos, + dfile->buffer, + dfile->data_len); + if (*ppos >= dfile->data_len) { + free_pages((unsigned long)dfile->buffer, buforder); + dfile->buffer = NULL; + dfile->data_len = 0; + } +out_unlock: + mutex_unlock(&dev->wl->mutex); + + return err ? err : ret; +} + +static ssize_t b43legacy_debugfs_write(struct file *file, + const char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct b43legacy_wldev *dev; + struct b43legacy_debugfs_fops *dfops; + char *buf; + int err = 0; + + if (!count) + return 0; + if (count > PAGE_SIZE) + return -E2BIG; + dev = file->private_data; + if (!dev) + return -ENODEV; + + mutex_lock(&dev->wl->mutex); + if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) { + err = -ENODEV; + goto out_unlock; + } + + dfops = container_of(file->f_op, struct b43legacy_debugfs_fops, fops); + if (!dfops->write) { + err = -ENOSYS; + goto out_unlock; + } + + buf = (char *)get_zeroed_page(GFP_KERNEL); + if (!buf) { + err = -ENOMEM; + goto out_unlock; + } + if (copy_from_user(buf, userbuf, count)) { + err = -EFAULT; + goto out_freepage; + } + if (dfops->take_irqlock) { + spin_lock_irq(&dev->wl->irq_lock); + err = dfops->write(dev, buf, count); + spin_unlock_irq(&dev->wl->irq_lock); + } else + err = dfops->write(dev, buf, count); + if (err) + goto out_freepage; + +out_freepage: + free_page((unsigned long)buf); +out_unlock: + mutex_unlock(&dev->wl->mutex); + + return err ? err : count; +} + + +#define B43legacy_DEBUGFS_FOPS(name, _read, _write, _take_irqlock) \ + static struct b43legacy_debugfs_fops fops_##name = { \ + .read = _read, \ + .write = _write, \ + .fops = { \ + .open = b43legacy_debugfs_open, \ + .read = b43legacy_debugfs_read, \ + .write = b43legacy_debugfs_write, \ + }, \ + .file_struct_offset = offsetof(struct b43legacy_dfsentry, \ + file_##name), \ + .take_irqlock = _take_irqlock, \ + } + +B43legacy_DEBUGFS_FOPS(tsf, tsf_read_file, tsf_write_file, 1); +B43legacy_DEBUGFS_FOPS(ucode_regs, ucode_regs_read_file, NULL, 1); +B43legacy_DEBUGFS_FOPS(shm, shm_read_file, NULL, 1); +B43legacy_DEBUGFS_FOPS(txstat, txstat_read_file, NULL, 0); +B43legacy_DEBUGFS_FOPS(restart, NULL, restart_write_file, 1); + + +int b43legacy_debug(struct b43legacy_wldev *dev, enum b43legacy_dyndbg feature) +{ + return !!(dev->dfsentry && dev->dfsentry->dyn_debug[feature]); +} + +static void b43legacy_remove_dynamic_debug(struct b43legacy_wldev *dev) +{ + struct b43legacy_dfsentry *e = dev->dfsentry; + int i; + + for (i = 0; i < __B43legacy_NR_DYNDBG; i++) + debugfs_remove(e->dyn_debug_dentries[i]); +} + +static void b43legacy_add_dynamic_debug(struct b43legacy_wldev *dev) +{ + struct b43legacy_dfsentry *e = dev->dfsentry; + struct dentry *d; + +#define add_dyn_dbg(name, id, initstate) do { \ + e->dyn_debug[id] = (initstate); \ + d = debugfs_create_bool(name, 0600, e->subdir, \ + &(e->dyn_debug[id])); \ + if (!IS_ERR(d)) \ + e->dyn_debug_dentries[id] = d; \ + } while (0) + + add_dyn_dbg("debug_xmitpower", B43legacy_DBG_XMITPOWER, 0); + add_dyn_dbg("debug_dmaoverflow", B43legacy_DBG_DMAOVERFLOW, 0); + add_dyn_dbg("debug_dmaverbose", B43legacy_DBG_DMAVERBOSE, 0); + add_dyn_dbg("debug_pwork_fast", B43legacy_DBG_PWORK_FAST, 0); + add_dyn_dbg("debug_pwork_stop", B43legacy_DBG_PWORK_STOP, 0); + +#undef add_dyn_dbg +} + +void b43legacy_debugfs_add_device(struct b43legacy_wldev *dev) +{ + struct b43legacy_dfsentry *e; + struct b43legacy_txstatus_log *log; + char devdir[16]; + + B43legacy_WARN_ON(!dev); + e = kzalloc(sizeof(*e), GFP_KERNEL); + if (!e) { + b43legacyerr(dev->wl, "debugfs: add device OOM\n"); + return; + } + e->dev = dev; + log = &e->txstatlog; + log->log = kcalloc(B43legacy_NR_LOGGED_TXSTATUS, + sizeof(struct b43legacy_txstatus), GFP_KERNEL); + if (!log->log) { + b43legacyerr(dev->wl, "debugfs: add device txstatus OOM\n"); + kfree(e); + return; + } + log->end = -1; + spin_lock_init(&log->lock); + + dev->dfsentry = e; + + snprintf(devdir, sizeof(devdir), "%s", wiphy_name(dev->wl->hw->wiphy)); + e->subdir = debugfs_create_dir(devdir, rootdir); + if (!e->subdir || IS_ERR(e->subdir)) { + if (e->subdir == ERR_PTR(-ENODEV)) { + b43legacydbg(dev->wl, "DebugFS (CONFIG_DEBUG_FS) not " + "enabled in kernel config\n"); + } else { + b43legacyerr(dev->wl, "debugfs: cannot create %s directory\n", + devdir); + } + dev->dfsentry = NULL; + kfree(log->log); + kfree(e); + return; + } + +#define ADD_FILE(name, mode) \ + do { \ + struct dentry *d; \ + d = debugfs_create_file(__stringify(name), \ + mode, e->subdir, dev, \ + &fops_##name.fops); \ + e->file_##name.dentry = NULL; \ + if (!IS_ERR(d)) \ + e->file_##name.dentry = d; \ + } while (0) + + + ADD_FILE(tsf, 0600); + ADD_FILE(ucode_regs, 0400); + ADD_FILE(shm, 0400); + ADD_FILE(txstat, 0400); + ADD_FILE(restart, 0200); + +#undef ADD_FILE + + b43legacy_add_dynamic_debug(dev); +} + +void b43legacy_debugfs_remove_device(struct b43legacy_wldev *dev) +{ + struct b43legacy_dfsentry *e; + + if (!dev) + return; + e = dev->dfsentry; + if (!e) + return; + b43legacy_remove_dynamic_debug(dev); + + debugfs_remove(e->file_tsf.dentry); + debugfs_remove(e->file_ucode_regs.dentry); + debugfs_remove(e->file_shm.dentry); + debugfs_remove(e->file_txstat.dentry); + debugfs_remove(e->file_restart.dentry); + + debugfs_remove(e->subdir); + kfree(e->txstatlog.log); + kfree(e); +} + +void b43legacy_debugfs_log_txstat(struct b43legacy_wldev *dev, + const struct b43legacy_txstatus *status) +{ + struct b43legacy_dfsentry *e = dev->dfsentry; + struct b43legacy_txstatus_log *log; + struct b43legacy_txstatus *cur; + int i; + + if (!e) + return; + log = &e->txstatlog; + B43legacy_WARN_ON(!irqs_disabled()); + spin_lock(&log->lock); + i = log->end + 1; + if (i == B43legacy_NR_LOGGED_TXSTATUS) + i = 0; + log->end = i; + cur = &(log->log[i]); + memcpy(cur, status, sizeof(*cur)); + spin_unlock(&log->lock); +} + +void b43legacy_debugfs_init(void) +{ + rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL); + if (IS_ERR(rootdir)) + rootdir = NULL; +} + +void b43legacy_debugfs_exit(void) +{ + debugfs_remove(rootdir); +} diff --git a/drivers/net/wireless/b43legacy/debugfs.h b/drivers/net/wireless/b43legacy/debugfs.h new file mode 100644 index 00000000000..ae3b0d0fa84 --- /dev/null +++ b/drivers/net/wireless/b43legacy/debugfs.h @@ -0,0 +1,89 @@ +#ifndef B43legacy_DEBUGFS_H_ +#define B43legacy_DEBUGFS_H_ + +struct b43legacy_wldev; +struct b43legacy_txstatus; + +enum b43legacy_dyndbg { /* Dynamic debugging features */ + B43legacy_DBG_XMITPOWER, + B43legacy_DBG_DMAOVERFLOW, + B43legacy_DBG_DMAVERBOSE, + B43legacy_DBG_PWORK_FAST, + B43legacy_DBG_PWORK_STOP, + __B43legacy_NR_DYNDBG, +}; + + +#ifdef CONFIG_B43LEGACY_DEBUG + +struct dentry; + +#define B43legacy_NR_LOGGED_TXSTATUS 100 + +struct b43legacy_txstatus_log { + struct b43legacy_txstatus *log; + int end; + spinlock_t lock; /* lock for debugging */ +}; + +struct b43legacy_dfs_file { + struct dentry *dentry; + char *buffer; + size_t data_len; +}; + +struct b43legacy_dfsentry { + struct b43legacy_wldev *dev; + struct dentry *subdir; + + struct b43legacy_dfs_file file_tsf; + struct b43legacy_dfs_file file_ucode_regs; + struct b43legacy_dfs_file file_shm; + struct b43legacy_dfs_file file_txstat; + struct b43legacy_dfs_file file_txpower_g; + struct b43legacy_dfs_file file_restart; + struct b43legacy_dfs_file file_loctls; + + struct b43legacy_txstatus_log txstatlog; + + /* Enabled/Disabled list for the dynamic debugging features. */ + u32 dyn_debug[__B43legacy_NR_DYNDBG]; + /* Dentries for the dynamic debugging entries. */ + struct dentry *dyn_debug_dentries[__B43legacy_NR_DYNDBG]; +}; + +int b43legacy_debug(struct b43legacy_wldev *dev, + enum b43legacy_dyndbg feature); + +void b43legacy_debugfs_init(void); +void b43legacy_debugfs_exit(void); +void b43legacy_debugfs_add_device(struct b43legacy_wldev *dev); +void b43legacy_debugfs_remove_device(struct b43legacy_wldev *dev); +void b43legacy_debugfs_log_txstat(struct b43legacy_wldev *dev, + const struct b43legacy_txstatus *status); + +#else /* CONFIG_B43LEGACY_DEBUG*/ + +static inline +int b43legacy_debug(struct b43legacy_wldev *dev, + enum b43legacy_dyndbg feature) +{ + return 0; +} + +static inline +void b43legacy_debugfs_init(void) { } +static inline +void b43legacy_debugfs_exit(void) { } +static inline +void b43legacy_debugfs_add_device(struct b43legacy_wldev *dev) { } +static inline +void b43legacy_debugfs_remove_device(struct b43legacy_wldev *dev) { } +static inline +void b43legacy_debugfs_log_txstat(struct b43legacy_wldev *dev, + const struct b43legacy_txstatus *status) + { } + +#endif /* CONFIG_B43LEGACY_DEBUG*/ + +#endif /* B43legacy_DEBUGFS_H_ */ diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c new file mode 100644 index 00000000000..8cb3dc4c474 --- /dev/null +++ b/drivers/net/wireless/b43legacy/dma.c @@ -0,0 +1,1565 @@ +/* + + Broadcom B43legacy wireless driver + + DMA ringbuffer and descriptor allocation/management + + Copyright (c) 2005, 2006 Michael Buesch + + Some code in this file is derived from the b44.c driver + Copyright (C) 2002 David S. Miller + Copyright (C) Pekka Pietikainen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "b43legacy.h" +#include "dma.h" +#include "main.h" +#include "debugfs.h" +#include "xmit.h" + +#include +#include +#include +#include +#include + +/* 32bit DMA ops. */ +static +struct b43legacy_dmadesc_generic *op32_idx2desc( + struct b43legacy_dmaring *ring, + int slot, + struct b43legacy_dmadesc_meta **meta) +{ + struct b43legacy_dmadesc32 *desc; + + *meta = &(ring->meta[slot]); + desc = ring->descbase; + desc = &(desc[slot]); + + return (struct b43legacy_dmadesc_generic *)desc; +} + +static void op32_fill_descriptor(struct b43legacy_dmaring *ring, + struct b43legacy_dmadesc_generic *desc, + dma_addr_t dmaaddr, u16 bufsize, + int start, int end, int irq) +{ + struct b43legacy_dmadesc32 *descbase = ring->descbase; + int slot; + u32 ctl; + u32 addr; + u32 addrext; + + slot = (int)(&(desc->dma32) - descbase); + B43legacy_WARN_ON(!(slot >= 0 && slot < ring->nr_slots)); + + addr = (u32)(dmaaddr & ~SSB_DMA_TRANSLATION_MASK); + addrext = (u32)(dmaaddr & SSB_DMA_TRANSLATION_MASK) + >> SSB_DMA_TRANSLATION_SHIFT; + addr |= ssb_dma_translation(ring->dev->dev); + ctl = (bufsize - ring->frameoffset) + & B43legacy_DMA32_DCTL_BYTECNT; + if (slot == ring->nr_slots - 1) + ctl |= B43legacy_DMA32_DCTL_DTABLEEND; + if (start) + ctl |= B43legacy_DMA32_DCTL_FRAMESTART; + if (end) + ctl |= B43legacy_DMA32_DCTL_FRAMEEND; + if (irq) + ctl |= B43legacy_DMA32_DCTL_IRQ; + ctl |= (addrext << B43legacy_DMA32_DCTL_ADDREXT_SHIFT) + & B43legacy_DMA32_DCTL_ADDREXT_MASK; + + desc->dma32.control = cpu_to_le32(ctl); + desc->dma32.address = cpu_to_le32(addr); +} + +static void op32_poke_tx(struct b43legacy_dmaring *ring, int slot) +{ + b43legacy_dma_write(ring, B43legacy_DMA32_TXINDEX, + (u32)(slot * sizeof(struct b43legacy_dmadesc32))); +} + +static void op32_tx_suspend(struct b43legacy_dmaring *ring) +{ + b43legacy_dma_write(ring, B43legacy_DMA32_TXCTL, + b43legacy_dma_read(ring, B43legacy_DMA32_TXCTL) + | B43legacy_DMA32_TXSUSPEND); +} + +static void op32_tx_resume(struct b43legacy_dmaring *ring) +{ + b43legacy_dma_write(ring, B43legacy_DMA32_TXCTL, + b43legacy_dma_read(ring, B43legacy_DMA32_TXCTL) + & ~B43legacy_DMA32_TXSUSPEND); +} + +static int op32_get_current_rxslot(struct b43legacy_dmaring *ring) +{ + u32 val; + + val = b43legacy_dma_read(ring, B43legacy_DMA32_RXSTATUS); + val &= B43legacy_DMA32_RXDPTR; + + return (val / sizeof(struct b43legacy_dmadesc32)); +} + +static void op32_set_current_rxslot(struct b43legacy_dmaring *ring, + int slot) +{ + b43legacy_dma_write(ring, B43legacy_DMA32_RXINDEX, + (u32)(slot * sizeof(struct b43legacy_dmadesc32))); +} + +static const struct b43legacy_dma_ops dma32_ops = { + .idx2desc = op32_idx2desc, + .fill_descriptor = op32_fill_descriptor, + .poke_tx = op32_poke_tx, + .tx_suspend = op32_tx_suspend, + .tx_resume = op32_tx_resume, + .get_current_rxslot = op32_get_current_rxslot, + .set_current_rxslot = op32_set_current_rxslot, +}; + +/* 64bit DMA ops. */ +static +struct b43legacy_dmadesc_generic *op64_idx2desc( + struct b43legacy_dmaring *ring, + int slot, + struct b43legacy_dmadesc_meta + **meta) +{ + struct b43legacy_dmadesc64 *desc; + + *meta = &(ring->meta[slot]); + desc = ring->descbase; + desc = &(desc[slot]); + + return (struct b43legacy_dmadesc_generic *)desc; +} + +static void op64_fill_descriptor(struct b43legacy_dmaring *ring, + struct b43legacy_dmadesc_generic *desc, + dma_addr_t dmaaddr, u16 bufsize, + int start, int end, int irq) +{ + struct b43legacy_dmadesc64 *descbase = ring->descbase; + int slot; + u32 ctl0 = 0; + u32 ctl1 = 0; + u32 addrlo; + u32 addrhi; + u32 addrext; + + slot = (int)(&(desc->dma64) - descbase); + B43legacy_WARN_ON(!(slot >= 0 && slot < ring->nr_slots)); + + addrlo = (u32)(dmaaddr & 0xFFFFFFFF); + addrhi = (((u64)dmaaddr >> 32) & ~SSB_DMA_TRANSLATION_MASK); + addrext = (((u64)dmaaddr >> 32) & SSB_DMA_TRANSLATION_MASK) + >> SSB_DMA_TRANSLATION_SHIFT; + addrhi |= ssb_dma_translation(ring->dev->dev); + if (slot == ring->nr_slots - 1) + ctl0 |= B43legacy_DMA64_DCTL0_DTABLEEND; + if (start) + ctl0 |= B43legacy_DMA64_DCTL0_FRAMESTART; + if (end) + ctl0 |= B43legacy_DMA64_DCTL0_FRAMEEND; + if (irq) + ctl0 |= B43legacy_DMA64_DCTL0_IRQ; + ctl1 |= (bufsize - ring->frameoffset) + & B43legacy_DMA64_DCTL1_BYTECNT; + ctl1 |= (addrext << B43legacy_DMA64_DCTL1_ADDREXT_SHIFT) + & B43legacy_DMA64_DCTL1_ADDREXT_MASK; + + desc->dma64.control0 = cpu_to_le32(ctl0); + desc->dma64.control1 = cpu_to_le32(ctl1); + desc->dma64.address_low = cpu_to_le32(addrlo); + desc->dma64.address_high = cpu_to_le32(addrhi); +} + +static void op64_poke_tx(struct b43legacy_dmaring *ring, int slot) +{ + b43legacy_dma_write(ring, B43legacy_DMA64_TXINDEX, + (u32)(slot * sizeof(struct b43legacy_dmadesc64))); +} + +static void op64_tx_suspend(struct b43legacy_dmaring *ring) +{ + b43legacy_dma_write(ring, B43legacy_DMA64_TXCTL, + b43legacy_dma_read(ring, B43legacy_DMA64_TXCTL) + | B43legacy_DMA64_TXSUSPEND); +} + +static void op64_tx_resume(struct b43legacy_dmaring *ring) +{ + b43legacy_dma_write(ring, B43legacy_DMA64_TXCTL, + b43legacy_dma_read(ring, B43legacy_DMA64_TXCTL) + & ~B43legacy_DMA64_TXSUSPEND); +} + +static int op64_get_current_rxslot(struct b43legacy_dmaring *ring) +{ + u32 val; + + val = b43legacy_dma_read(ring, B43legacy_DMA64_RXSTATUS); + val &= B43legacy_DMA64_RXSTATDPTR; + + return (val / sizeof(struct b43legacy_dmadesc64)); +} + +static void op64_set_current_rxslot(struct b43legacy_dmaring *ring, + int slot) +{ + b43legacy_dma_write(ring, B43legacy_DMA64_RXINDEX, + (u32)(slot * sizeof(struct b43legacy_dmadesc64))); +} + +static const struct b43legacy_dma_ops dma64_ops = { + .idx2desc = op64_idx2desc, + .fill_descriptor = op64_fill_descriptor, + .poke_tx = op64_poke_tx, + .tx_suspend = op64_tx_suspend, + .tx_resume = op64_tx_resume, + .get_current_rxslot = op64_get_current_rxslot, + .set_current_rxslot = op64_set_current_rxslot, +}; + + +static inline int free_slots(struct b43legacy_dmaring *ring) +{ + return (ring->nr_slots - ring->used_slots); +} + +static inline int next_slot(struct b43legacy_dmaring *ring, int slot) +{ + B43legacy_WARN_ON(!(slot >= -1 && slot <= ring->nr_slots - 1)); + if (slot == ring->nr_slots - 1) + return 0; + return slot + 1; +} + +static inline int prev_slot(struct b43legacy_dmaring *ring, int slot) +{ + B43legacy_WARN_ON(!(slot >= 0 && slot <= ring->nr_slots - 1)); + if (slot == 0) + return ring->nr_slots - 1; + return slot - 1; +} + +#ifdef CONFIG_B43LEGACY_DEBUG +static void update_max_used_slots(struct b43legacy_dmaring *ring, + int current_used_slots) +{ + if (current_used_slots <= ring->max_used_slots) + return; + ring->max_used_slots = current_used_slots; + if (b43legacy_debug(ring->dev, B43legacy_DBG_DMAVERBOSE)) + b43legacydbg(ring->dev->wl, + "max_used_slots increased to %d on %s ring %d\n", + ring->max_used_slots, + ring->tx ? "TX" : "RX", + ring->index); +} +#else +static inline +void update_max_used_slots(struct b43legacy_dmaring *ring, + int current_used_slots) +{ } +#endif /* DEBUG */ + +/* Request a slot for usage. */ +static inline +int request_slot(struct b43legacy_dmaring *ring) +{ + int slot; + + B43legacy_WARN_ON(!ring->tx); + B43legacy_WARN_ON(ring->stopped); + B43legacy_WARN_ON(free_slots(ring) == 0); + + slot = next_slot(ring, ring->current_slot); + ring->current_slot = slot; + ring->used_slots++; + + update_max_used_slots(ring, ring->used_slots); + + return slot; +} + +/* Mac80211-queue to b43legacy-ring mapping */ +static struct b43legacy_dmaring *priority_to_txring( + struct b43legacy_wldev *dev, + int queue_priority) +{ + struct b43legacy_dmaring *ring; + +/*FIXME: For now we always run on TX-ring-1 */ +return dev->dma.tx_ring1; + + /* 0 = highest priority */ + switch (queue_priority) { + default: + B43legacy_WARN_ON(1); + /* fallthrough */ + case 0: + ring = dev->dma.tx_ring3; + break; + case 1: + ring = dev->dma.tx_ring2; + break; + case 2: + ring = dev->dma.tx_ring1; + break; + case 3: + ring = dev->dma.tx_ring0; + break; + case 4: + ring = dev->dma.tx_ring4; + break; + case 5: + ring = dev->dma.tx_ring5; + break; + } + + return ring; +} + +/* Bcm4301-ring to mac80211-queue mapping */ +static inline int txring_to_priority(struct b43legacy_dmaring *ring) +{ + static const u8 idx_to_prio[] = + { 3, 2, 1, 0, 4, 5, }; + +/*FIXME: have only one queue, for now */ +return 0; + + return idx_to_prio[ring->index]; +} + + +u16 b43legacy_dmacontroller_base(int dma64bit, int controller_idx) +{ + static const u16 map64[] = { + B43legacy_MMIO_DMA64_BASE0, + B43legacy_MMIO_DMA64_BASE1, + B43legacy_MMIO_DMA64_BASE2, + B43legacy_MMIO_DMA64_BASE3, + B43legacy_MMIO_DMA64_BASE4, + B43legacy_MMIO_DMA64_BASE5, + }; + static const u16 map32[] = { + B43legacy_MMIO_DMA32_BASE0, + B43legacy_MMIO_DMA32_BASE1, + B43legacy_MMIO_DMA32_BASE2, + B43legacy_MMIO_DMA32_BASE3, + B43legacy_MMIO_DMA32_BASE4, + B43legacy_MMIO_DMA32_BASE5, + }; + + if (dma64bit) { + B43legacy_WARN_ON(!(controller_idx >= 0 && + controller_idx < ARRAY_SIZE(map64))); + return map64[controller_idx]; + } + B43legacy_WARN_ON(!(controller_idx >= 0 && + controller_idx < ARRAY_SIZE(map32))); + return map32[controller_idx]; +} + +static inline +dma_addr_t map_descbuffer(struct b43legacy_dmaring *ring, + unsigned char *buf, + size_t len, + int tx) +{ + dma_addr_t dmaaddr; + + if (tx) + dmaaddr = dma_map_single(ring->dev->dev->dev, + buf, len, + DMA_TO_DEVICE); + else + dmaaddr = dma_map_single(ring->dev->dev->dev, + buf, len, + DMA_FROM_DEVICE); + + return dmaaddr; +} + +static inline +void unmap_descbuffer(struct b43legacy_dmaring *ring, + dma_addr_t addr, + size_t len, + int tx) +{ + if (tx) + dma_unmap_single(ring->dev->dev->dev, + addr, len, + DMA_TO_DEVICE); + else + dma_unmap_single(ring->dev->dev->dev, + addr, len, + DMA_FROM_DEVICE); +} + +static inline +void sync_descbuffer_for_cpu(struct b43legacy_dmaring *ring, + dma_addr_t addr, + size_t len) +{ + B43legacy_WARN_ON(ring->tx); + + dma_sync_single_for_cpu(ring->dev->dev->dev, + addr, len, DMA_FROM_DEVICE); +} + +static inline +void sync_descbuffer_for_device(struct b43legacy_dmaring *ring, + dma_addr_t addr, + size_t len) +{ + B43legacy_WARN_ON(ring->tx); + + dma_sync_single_for_device(ring->dev->dev->dev, + addr, len, DMA_FROM_DEVICE); +} + +static inline +void free_descriptor_buffer(struct b43legacy_dmaring *ring, + struct b43legacy_dmadesc_meta *meta, + int irq_context) +{ + if (meta->skb) { + if (irq_context) + dev_kfree_skb_irq(meta->skb); + else + dev_kfree_skb(meta->skb); + meta->skb = NULL; + } +} + +static int alloc_ringmemory(struct b43legacy_dmaring *ring) +{ + struct device *dev = ring->dev->dev->dev; + + ring->descbase = dma_alloc_coherent(dev, B43legacy_DMA_RINGMEMSIZE, + &(ring->dmabase), GFP_KERNEL); + if (!ring->descbase) { + b43legacyerr(ring->dev->wl, "DMA ringmemory allocation" + " failed\n"); + return -ENOMEM; + } + memset(ring->descbase, 0, B43legacy_DMA_RINGMEMSIZE); + + return 0; +} + +static void free_ringmemory(struct b43legacy_dmaring *ring) +{ + struct device *dev = ring->dev->dev->dev; + + dma_free_coherent(dev, B43legacy_DMA_RINGMEMSIZE, + ring->descbase, ring->dmabase); +} + +/* Reset the RX DMA channel */ +int b43legacy_dmacontroller_rx_reset(struct b43legacy_wldev *dev, + u16 mmio_base, int dma64) +{ + int i; + u32 value; + u16 offset; + + might_sleep(); + + offset = dma64 ? B43legacy_DMA64_RXCTL : B43legacy_DMA32_RXCTL; + b43legacy_write32(dev, mmio_base + offset, 0); + for (i = 0; i < 10; i++) { + offset = dma64 ? B43legacy_DMA64_RXSTATUS : + B43legacy_DMA32_RXSTATUS; + value = b43legacy_read32(dev, mmio_base + offset); + if (dma64) { + value &= B43legacy_DMA64_RXSTAT; + if (value == B43legacy_DMA64_RXSTAT_DISABLED) { + i = -1; + break; + } + } else { + value &= B43legacy_DMA32_RXSTATE; + if (value == B43legacy_DMA32_RXSTAT_DISABLED) { + i = -1; + break; + } + } + msleep(1); + } + if (i != -1) { + b43legacyerr(dev->wl, "DMA RX reset timed out\n"); + return -ENODEV; + } + + return 0; +} + +/* Reset the RX DMA channel */ +int b43legacy_dmacontroller_tx_reset(struct b43legacy_wldev *dev, + u16 mmio_base, int dma64) +{ + int i; + u32 value; + u16 offset; + + might_sleep(); + + for (i = 0; i < 10; i++) { + offset = dma64 ? B43legacy_DMA64_TXSTATUS : + B43legacy_DMA32_TXSTATUS; + value = b43legacy_read32(dev, mmio_base + offset); + if (dma64) { + value &= B43legacy_DMA64_TXSTAT; + if (value == B43legacy_DMA64_TXSTAT_DISABLED || + value == B43legacy_DMA64_TXSTAT_IDLEWAIT || + value == B43legacy_DMA64_TXSTAT_STOPPED) + break; + } else { + value &= B43legacy_DMA32_TXSTATE; + if (value == B43legacy_DMA32_TXSTAT_DISABLED || + value == B43legacy_DMA32_TXSTAT_IDLEWAIT || + value == B43legacy_DMA32_TXSTAT_STOPPED) + break; + } + msleep(1); + } + offset = dma64 ? B43legacy_DMA64_TXCTL : B43legacy_DMA32_TXCTL; + b43legacy_write32(dev, mmio_base + offset, 0); + for (i = 0; i < 10; i++) { + offset = dma64 ? B43legacy_DMA64_TXSTATUS : + B43legacy_DMA32_TXSTATUS; + value = b43legacy_read32(dev, mmio_base + offset); + if (dma64) { + value &= B43legacy_DMA64_TXSTAT; + if (value == B43legacy_DMA64_TXSTAT_DISABLED) { + i = -1; + break; + } + } else { + value &= B43legacy_DMA32_TXSTATE; + if (value == B43legacy_DMA32_TXSTAT_DISABLED) { + i = -1; + break; + } + } + msleep(1); + } + if (i != -1) { + b43legacyerr(dev->wl, "DMA TX reset timed out\n"); + return -ENODEV; + } + /* ensure the reset is completed. */ + msleep(1); + + return 0; +} + +static int setup_rx_descbuffer(struct b43legacy_dmaring *ring, + struct b43legacy_dmadesc_generic *desc, + struct b43legacy_dmadesc_meta *meta, + gfp_t gfp_flags) +{ + struct b43legacy_rxhdr_fw3 *rxhdr; + struct b43legacy_hwtxstatus *txstat; + dma_addr_t dmaaddr; + struct sk_buff *skb; + + B43legacy_WARN_ON(ring->tx); + + skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags); + if (unlikely(!skb)) + return -ENOMEM; + dmaaddr = map_descbuffer(ring, skb->data, + ring->rx_buffersize, 0); + if (dma_mapping_error(dmaaddr)) { + /* ugh. try to realloc in zone_dma */ + gfp_flags |= GFP_DMA; + + dev_kfree_skb_any(skb); + + skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags); + if (unlikely(!skb)) + return -ENOMEM; + dmaaddr = map_descbuffer(ring, skb->data, + ring->rx_buffersize, 0); + } + + if (dma_mapping_error(dmaaddr)) { + dev_kfree_skb_any(skb); + return -EIO; + } + + meta->skb = skb; + meta->dmaaddr = dmaaddr; + ring->ops->fill_descriptor(ring, desc, dmaaddr, + ring->rx_buffersize, 0, 0, 0); + + rxhdr = (struct b43legacy_rxhdr_fw3 *)(skb->data); + rxhdr->frame_len = 0; + txstat = (struct b43legacy_hwtxstatus *)(skb->data); + txstat->cookie = 0; + + return 0; +} + +/* Allocate the initial descbuffers. + * This is used for an RX ring only. + */ +static int alloc_initial_descbuffers(struct b43legacy_dmaring *ring) +{ + int i; + int err = -ENOMEM; + struct b43legacy_dmadesc_generic *desc; + struct b43legacy_dmadesc_meta *meta; + + for (i = 0; i < ring->nr_slots; i++) { + desc = ring->ops->idx2desc(ring, i, &meta); + + err = setup_rx_descbuffer(ring, desc, meta, GFP_KERNEL); + if (err) { + b43legacyerr(ring->dev->wl, + "Failed to allocate initial descbuffers\n"); + goto err_unwind; + } + } + mb(); /* all descbuffer setup before next line */ + ring->used_slots = ring->nr_slots; + err = 0; +out: + return err; + +err_unwind: + for (i--; i >= 0; i--) { + desc = ring->ops->idx2desc(ring, i, &meta); + + unmap_descbuffer(ring, meta->dmaaddr, ring->rx_buffersize, 0); + dev_kfree_skb(meta->skb); + } + goto out; +} + +/* Do initial setup of the DMA controller. + * Reset the controller, write the ring busaddress + * and switch the "enable" bit on. + */ +static int dmacontroller_setup(struct b43legacy_dmaring *ring) +{ + int err = 0; + u32 value; + u32 addrext; + u32 trans = ssb_dma_translation(ring->dev->dev); + + if (ring->tx) { + if (ring->dma64) { + u64 ringbase = (u64)(ring->dmabase); + + addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK) + >> SSB_DMA_TRANSLATION_SHIFT; + value = B43legacy_DMA64_TXENABLE; + value |= (addrext << B43legacy_DMA64_TXADDREXT_SHIFT) + & B43legacy_DMA64_TXADDREXT_MASK; + b43legacy_dma_write(ring, B43legacy_DMA64_TXCTL, + value); + b43legacy_dma_write(ring, B43legacy_DMA64_TXRINGLO, + (ringbase & 0xFFFFFFFF)); + b43legacy_dma_write(ring, B43legacy_DMA64_TXRINGHI, + ((ringbase >> 32) + & ~SSB_DMA_TRANSLATION_MASK) + | trans); + } else { + u32 ringbase = (u32)(ring->dmabase); + + addrext = (ringbase & SSB_DMA_TRANSLATION_MASK) + >> SSB_DMA_TRANSLATION_SHIFT; + value = B43legacy_DMA32_TXENABLE; + value |= (addrext << B43legacy_DMA32_TXADDREXT_SHIFT) + & B43legacy_DMA32_TXADDREXT_MASK; + b43legacy_dma_write(ring, B43legacy_DMA32_TXCTL, + value); + b43legacy_dma_write(ring, B43legacy_DMA32_TXRING, + (ringbase & + ~SSB_DMA_TRANSLATION_MASK) + | trans); + } + } else { + err = alloc_initial_descbuffers(ring); + if (err) + goto out; + if (ring->dma64) { + u64 ringbase = (u64)(ring->dmabase); + + addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK) + >> SSB_DMA_TRANSLATION_SHIFT; + value = (ring->frameoffset << + B43legacy_DMA64_RXFROFF_SHIFT); + value |= B43legacy_DMA64_RXENABLE; + value |= (addrext << B43legacy_DMA64_RXADDREXT_SHIFT) + & B43legacy_DMA64_RXADDREXT_MASK; + b43legacy_dma_write(ring, B43legacy_DMA64_RXCTL, + value); + b43legacy_dma_write(ring, B43legacy_DMA64_RXRINGLO, + (ringbase & 0xFFFFFFFF)); + b43legacy_dma_write(ring, B43legacy_DMA64_RXRINGHI, + ((ringbase >> 32) & + ~SSB_DMA_TRANSLATION_MASK) | + trans); + b43legacy_dma_write(ring, B43legacy_DMA64_RXINDEX, + 200); + } else { + u32 ringbase = (u32)(ring->dmabase); + + addrext = (ringbase & SSB_DMA_TRANSLATION_MASK) + >> SSB_DMA_TRANSLATION_SHIFT; + value = (ring->frameoffset << + B43legacy_DMA32_RXFROFF_SHIFT); + value |= B43legacy_DMA32_RXENABLE; + value |= (addrext << + B43legacy_DMA32_RXADDREXT_SHIFT) + & B43legacy_DMA32_RXADDREXT_MASK; + b43legacy_dma_write(ring, B43legacy_DMA32_RXCTL, + value); + b43legacy_dma_write(ring, B43legacy_DMA32_RXRING, + (ringbase & + ~SSB_DMA_TRANSLATION_MASK) + | trans); + b43legacy_dma_write(ring, B43legacy_DMA32_RXINDEX, + 200); + } + } + +out: + return err; +} + +/* Shutdown the DMA controller. */ +static void dmacontroller_cleanup(struct b43legacy_dmaring *ring) +{ + if (ring->tx) { + b43legacy_dmacontroller_tx_reset(ring->dev, ring->mmio_base, + ring->dma64); + if (ring->dma64) { + b43legacy_dma_write(ring, B43legacy_DMA64_TXRINGLO, 0); + b43legacy_dma_write(ring, B43legacy_DMA64_TXRINGHI, 0); + } else + b43legacy_dma_write(ring, B43legacy_DMA32_TXRING, 0); + } else { + b43legacy_dmacontroller_rx_reset(ring->dev, ring->mmio_base, + ring->dma64); + if (ring->dma64) { + b43legacy_dma_write(ring, B43legacy_DMA64_RXRINGLO, 0); + b43legacy_dma_write(ring, B43legacy_DMA64_RXRINGHI, 0); + } else + b43legacy_dma_write(ring, B43legacy_DMA32_RXRING, 0); + } +} + +static void free_all_descbuffers(struct b43legacy_dmaring *ring) +{ + struct b43legacy_dmadesc_generic *desc; + struct b43legacy_dmadesc_meta *meta; + int i; + + if (!ring->used_slots) + return; + for (i = 0; i < ring->nr_slots; i++) { + desc = ring->ops->idx2desc(ring, i, &meta); + + if (!meta->skb) { + B43legacy_WARN_ON(!ring->tx); + continue; + } + if (ring->tx) + unmap_descbuffer(ring, meta->dmaaddr, + meta->skb->len, 1); + else + unmap_descbuffer(ring, meta->dmaaddr, + ring->rx_buffersize, 0); + free_descriptor_buffer(ring, meta, 0); + } +} + +static u64 supported_dma_mask(struct b43legacy_wldev *dev) +{ + u32 tmp; + u16 mmio_base; + + tmp = b43legacy_read32(dev, SSB_TMSHIGH); + if (tmp & SSB_TMSHIGH_DMA64) + return DMA_64BIT_MASK; + mmio_base = b43legacy_dmacontroller_base(0, 0); + b43legacy_write32(dev, + mmio_base + B43legacy_DMA32_TXCTL, + B43legacy_DMA32_TXADDREXT_MASK); + tmp = b43legacy_read32(dev, mmio_base + + B43legacy_DMA32_TXCTL); + if (tmp & B43legacy_DMA32_TXADDREXT_MASK) + return DMA_32BIT_MASK; + + return DMA_30BIT_MASK; +} + +/* Main initialization function. */ +static +struct b43legacy_dmaring *b43legacy_setup_dmaring( + struct b43legacy_wldev *dev, + int controller_index, + int for_tx, + int dma64) +{ + struct b43legacy_dmaring *ring; + int err; + int nr_slots; + dma_addr_t dma_test; + + ring = kzalloc(sizeof(*ring), GFP_KERNEL); + if (!ring) + goto out; + + nr_slots = B43legacy_RXRING_SLOTS; + if (for_tx) + nr_slots = B43legacy_TXRING_SLOTS; + + ring->meta = kcalloc(nr_slots, sizeof(struct b43legacy_dmadesc_meta), + GFP_KERNEL); + if (!ring->meta) + goto err_kfree_ring; + if (for_tx) { + ring->txhdr_cache = kcalloc(nr_slots, + sizeof(struct b43legacy_txhdr_fw3), + GFP_KERNEL); + if (!ring->txhdr_cache) + goto err_kfree_meta; + + /* test for ability to dma to txhdr_cache */ + dma_test = dma_map_single(dev->dev->dev, + ring->txhdr_cache, + sizeof(struct b43legacy_txhdr_fw3), + DMA_TO_DEVICE); + + if (dma_mapping_error(dma_test)) { + /* ugh realloc */ + kfree(ring->txhdr_cache); + ring->txhdr_cache = kcalloc(nr_slots, + sizeof(struct b43legacy_txhdr_fw3), + GFP_KERNEL | GFP_DMA); + if (!ring->txhdr_cache) + goto err_kfree_meta; + + dma_test = dma_map_single(dev->dev->dev, + ring->txhdr_cache, + sizeof(struct b43legacy_txhdr_fw3), + DMA_TO_DEVICE); + + if (dma_mapping_error(dma_test)) + goto err_kfree_txhdr_cache; + } + + dma_unmap_single(dev->dev->dev, + dma_test, sizeof(struct b43legacy_txhdr_fw3), + DMA_TO_DEVICE); + } + + ring->dev = dev; + ring->nr_slots = nr_slots; + ring->mmio_base = b43legacy_dmacontroller_base(dma64, + controller_index); + ring->index = controller_index; + ring->dma64 = !!dma64; + if (dma64) + ring->ops = &dma64_ops; + else + ring->ops = &dma32_ops; + if (for_tx) { + ring->tx = 1; + ring->current_slot = -1; + } else { + if (ring->index == 0) { + ring->rx_buffersize = B43legacy_DMA0_RX_BUFFERSIZE; + ring->frameoffset = B43legacy_DMA0_RX_FRAMEOFFSET; + } else if (ring->index == 3) { + ring->rx_buffersize = B43legacy_DMA3_RX_BUFFERSIZE; + ring->frameoffset = B43legacy_DMA3_RX_FRAMEOFFSET; + } else + B43legacy_WARN_ON(1); + } + spin_lock_init(&ring->lock); +#ifdef CONFIG_B43LEGACY_DEBUG + ring->last_injected_overflow = jiffies; +#endif + + err = alloc_ringmemory(ring); + if (err) + goto err_kfree_txhdr_cache; + err = dmacontroller_setup(ring); + if (err) + goto err_free_ringmemory; + +out: + return ring; + +err_free_ringmemory: + free_ringmemory(ring); +err_kfree_txhdr_cache: + kfree(ring->txhdr_cache); +err_kfree_meta: + kfree(ring->meta); +err_kfree_ring: + kfree(ring); + ring = NULL; + goto out; +} + +/* Main cleanup function. */ +static void b43legacy_destroy_dmaring(struct b43legacy_dmaring *ring) +{ + if (!ring) + return; + + b43legacydbg(ring->dev->wl, "DMA-%s 0x%04X (%s) max used slots:" + " %d/%d\n", (ring->dma64) ? "64" : "32", ring->mmio_base, + (ring->tx) ? "TX" : "RX", + ring->max_used_slots, ring->nr_slots); + /* Device IRQs are disabled prior entering this function, + * so no need to take care of concurrency with rx handler stuff. + */ + dmacontroller_cleanup(ring); + free_all_descbuffers(ring); + free_ringmemory(ring); + + kfree(ring->txhdr_cache); + kfree(ring->meta); + kfree(ring); +} + +void b43legacy_dma_free(struct b43legacy_wldev *dev) +{ + struct b43legacy_dma *dma; + + if (b43legacy_using_pio(dev)) + return; + dma = &dev->dma; + + b43legacy_destroy_dmaring(dma->rx_ring3); + dma->rx_ring3 = NULL; + b43legacy_destroy_dmaring(dma->rx_ring0); + dma->rx_ring0 = NULL; + + b43legacy_destroy_dmaring(dma->tx_ring5); + dma->tx_ring5 = NULL; + b43legacy_destroy_dmaring(dma->tx_ring4); + dma->tx_ring4 = NULL; + b43legacy_destroy_dmaring(dma->tx_ring3); + dma->tx_ring3 = NULL; + b43legacy_destroy_dmaring(dma->tx_ring2); + dma->tx_ring2 = NULL; + b43legacy_destroy_dmaring(dma->tx_ring1); + dma->tx_ring1 = NULL; + b43legacy_destroy_dmaring(dma->tx_ring0); + dma->tx_ring0 = NULL; +} + +int b43legacy_dma_init(struct b43legacy_wldev *dev) +{ + struct b43legacy_dma *dma = &dev->dma; + struct b43legacy_dmaring *ring; + int err; + u64 dmamask; + int dma64 = 0; + + dmamask = supported_dma_mask(dev); + if (dmamask == DMA_64BIT_MASK) + dma64 = 1; + + err = ssb_dma_set_mask(dev->dev, dmamask); + if (err) { +#ifdef BCM43XX_PIO + b43legacywarn(dev->wl, "DMA for this device not supported. " + "Falling back to PIO\n"); + dev->__using_pio = 1; + return -EAGAIN; +#else + b43legacyerr(dev->wl, "DMA for this device not supported and " + "no PIO support compiled in\n"); + return -EOPNOTSUPP; +#endif + } + + err = -ENOMEM; + /* setup TX DMA channels. */ + ring = b43legacy_setup_dmaring(dev, 0, 1, dma64); + if (!ring) + goto out; + dma->tx_ring0 = ring; + + ring = b43legacy_setup_dmaring(dev, 1, 1, dma64); + if (!ring) + goto err_destroy_tx0; + dma->tx_ring1 = ring; + + ring = b43legacy_setup_dmaring(dev, 2, 1, dma64); + if (!ring) + goto err_destroy_tx1; + dma->tx_ring2 = ring; + + ring = b43legacy_setup_dmaring(dev, 3, 1, dma64); + if (!ring) + goto err_destroy_tx2; + dma->tx_ring3 = ring; + + ring = b43legacy_setup_dmaring(dev, 4, 1, dma64); + if (!ring) + goto err_destroy_tx3; + dma->tx_ring4 = ring; + + ring = b43legacy_setup_dmaring(dev, 5, 1, dma64); + if (!ring) + goto err_destroy_tx4; + dma->tx_ring5 = ring; + + /* setup RX DMA channels. */ + ring = b43legacy_setup_dmaring(dev, 0, 0, dma64); + if (!ring) + goto err_destroy_tx5; + dma->rx_ring0 = ring; + + if (dev->dev->id.revision < 5) { + ring = b43legacy_setup_dmaring(dev, 3, 0, dma64); + if (!ring) + goto err_destroy_rx0; + dma->rx_ring3 = ring; + } + + b43legacydbg(dev->wl, "%d-bit DMA initialized\n", + (dmamask == DMA_64BIT_MASK) ? 64 : + (dmamask == DMA_32BIT_MASK) ? 32 : 30); + err = 0; +out: + return err; + +err_destroy_rx0: + b43legacy_destroy_dmaring(dma->rx_ring0); + dma->rx_ring0 = NULL; +err_destroy_tx5: + b43legacy_destroy_dmaring(dma->tx_ring5); + dma->tx_ring5 = NULL; +err_destroy_tx4: + b43legacy_destroy_dmaring(dma->tx_ring4); + dma->tx_ring4 = NULL; +err_destroy_tx3: + b43legacy_destroy_dmaring(dma->tx_ring3); + dma->tx_ring3 = NULL; +err_destroy_tx2: + b43legacy_destroy_dmaring(dma->tx_ring2); + dma->tx_ring2 = NULL; +err_destroy_tx1: + b43legacy_destroy_dmaring(dma->tx_ring1); + dma->tx_ring1 = NULL; +err_destroy_tx0: + b43legacy_destroy_dmaring(dma->tx_ring0); + dma->tx_ring0 = NULL; + goto out; +} + +/* Generate a cookie for the TX header. */ +static u16 generate_cookie(struct b43legacy_dmaring *ring, + int slot) +{ + u16 cookie = 0x1000; + + /* Use the upper 4 bits of the cookie as + * DMA controller ID and store the slot number + * in the lower 12 bits. + * Note that the cookie must never be 0, as this + * is a special value used in RX path. + */ + switch (ring->index) { + case 0: + cookie = 0xA000; + break; + case 1: + cookie = 0xB000; + break; + case 2: + cookie = 0xC000; + break; + case 3: + cookie = 0xD000; + break; + case 4: + cookie = 0xE000; + break; + case 5: + cookie = 0xF000; + break; + } + B43legacy_WARN_ON(!(((u16)slot & 0xF000) == 0x0000)); + cookie |= (u16)slot; + + return cookie; +} + +/* Inspect a cookie and find out to which controller/slot it belongs. */ +static +struct b43legacy_dmaring *parse_cookie(struct b43legacy_wldev *dev, + u16 cookie, int *slot) +{ + struct b43legacy_dma *dma = &dev->dma; + struct b43legacy_dmaring *ring = NULL; + + switch (cookie & 0xF000) { + case 0xA000: + ring = dma->tx_ring0; + break; + case 0xB000: + ring = dma->tx_ring1; + break; + case 0xC000: + ring = dma->tx_ring2; + break; + case 0xD000: + ring = dma->tx_ring3; + break; + case 0xE000: + ring = dma->tx_ring4; + break; + case 0xF000: + ring = dma->tx_ring5; + break; + default: + B43legacy_WARN_ON(1); + } + *slot = (cookie & 0x0FFF); + B43legacy_WARN_ON(!(ring && *slot >= 0 && *slot < ring->nr_slots)); + + return ring; +} + +static int dma_tx_fragment(struct b43legacy_dmaring *ring, + struct sk_buff *skb, + struct ieee80211_tx_control *ctl) +{ + const struct b43legacy_dma_ops *ops = ring->ops; + u8 *header; + int slot; + int err; + struct b43legacy_dmadesc_generic *desc; + struct b43legacy_dmadesc_meta *meta; + struct b43legacy_dmadesc_meta *meta_hdr; + struct sk_buff *bounce_skb; + +#define SLOTS_PER_PACKET 2 + B43legacy_WARN_ON(skb_shinfo(skb)->nr_frags != 0); + + /* Get a slot for the header. */ + slot = request_slot(ring); + desc = ops->idx2desc(ring, slot, &meta_hdr); + memset(meta_hdr, 0, sizeof(*meta_hdr)); + + header = &(ring->txhdr_cache[slot * sizeof( + struct b43legacy_txhdr_fw3)]); + b43legacy_generate_txhdr(ring->dev, header, + skb->data, skb->len, ctl, + generate_cookie(ring, slot)); + + meta_hdr->dmaaddr = map_descbuffer(ring, (unsigned char *)header, + sizeof(struct b43legacy_txhdr_fw3), 1); + if (dma_mapping_error(meta_hdr->dmaaddr)) + return -EIO; + ops->fill_descriptor(ring, desc, meta_hdr->dmaaddr, + sizeof(struct b43legacy_txhdr_fw3), 1, 0, 0); + + /* Get a slot for the payload. */ + slot = request_slot(ring); + desc = ops->idx2desc(ring, slot, &meta); + memset(meta, 0, sizeof(*meta)); + + memcpy(&meta->txstat.control, ctl, sizeof(*ctl)); + meta->skb = skb; + meta->is_last_fragment = 1; + + meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); + /* create a bounce buffer in zone_dma on mapping failure. */ + if (dma_mapping_error(meta->dmaaddr)) { + bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA); + if (!bounce_skb) { + err = -ENOMEM; + goto out_unmap_hdr; + } + + memcpy(skb_put(bounce_skb, skb->len), skb->data, skb->len); + dev_kfree_skb_any(skb); + skb = bounce_skb; + meta->skb = skb; + meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); + if (dma_mapping_error(meta->dmaaddr)) { + err = -EIO; + goto out_free_bounce; + } + } + + ops->fill_descriptor(ring, desc, meta->dmaaddr, + skb->len, 0, 1, 1); + + wmb(); /* previous stuff MUST be done */ + /* Now transfer the whole frame. */ + ops->poke_tx(ring, next_slot(ring, slot)); + return 0; + +out_free_bounce: + dev_kfree_skb_any(skb); +out_unmap_hdr: + unmap_descbuffer(ring, meta_hdr->dmaaddr, + sizeof(struct b43legacy_txhdr_fw3), 1); + return err; +} + +static inline +int should_inject_overflow(struct b43legacy_dmaring *ring) +{ +#ifdef CONFIG_B43LEGACY_DEBUG + if (unlikely(b43legacy_debug(ring->dev, + B43legacy_DBG_DMAOVERFLOW))) { + /* Check if we should inject another ringbuffer overflow + * to test handling of this situation in the stack. */ + unsigned long next_overflow; + + next_overflow = ring->last_injected_overflow + HZ; + if (time_after(jiffies, next_overflow)) { + ring->last_injected_overflow = jiffies; + b43legacydbg(ring->dev->wl, + "Injecting TX ring overflow on " + "DMA controller %d\n", ring->index); + return 1; + } + } +#endif /* CONFIG_B43LEGACY_DEBUG */ + return 0; +} + +int b43legacy_dma_tx(struct b43legacy_wldev *dev, + struct sk_buff *skb, + struct ieee80211_tx_control *ctl) +{ + struct b43legacy_dmaring *ring; + int err = 0; + unsigned long flags; + + ring = priority_to_txring(dev, ctl->queue); + spin_lock_irqsave(&ring->lock, flags); + B43legacy_WARN_ON(!ring->tx); + if (unlikely(free_slots(ring) < SLOTS_PER_PACKET)) { + b43legacywarn(dev->wl, "DMA queue overflow\n"); + err = -ENOSPC; + goto out_unlock; + } + /* Check if the queue was stopped in mac80211, + * but we got called nevertheless. + * That would be a mac80211 bug. */ + B43legacy_BUG_ON(ring->stopped); + + err = dma_tx_fragment(ring, skb, ctl); + if (unlikely(err)) { + b43legacyerr(dev->wl, "DMA tx mapping failure\n"); + goto out_unlock; + } + ring->nr_tx_packets++; + if ((free_slots(ring) < SLOTS_PER_PACKET) || + should_inject_overflow(ring)) { + /* This TX ring is full. */ + ieee80211_stop_queue(dev->wl->hw, txring_to_priority(ring)); + ring->stopped = 1; + if (b43legacy_debug(dev, B43legacy_DBG_DMAVERBOSE)) + b43legacydbg(dev->wl, "Stopped TX ring %d\n", + ring->index); + } +out_unlock: + spin_unlock_irqrestore(&ring->lock, flags); + + return err; +} + +void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev, + const struct b43legacy_txstatus *status) +{ + const struct b43legacy_dma_ops *ops; + struct b43legacy_dmaring *ring; + struct b43legacy_dmadesc_generic *desc; + struct b43legacy_dmadesc_meta *meta; + int slot; + + ring = parse_cookie(dev, status->cookie, &slot); + if (unlikely(!ring)) + return; + B43legacy_WARN_ON(!irqs_disabled()); + spin_lock(&ring->lock); + + B43legacy_WARN_ON(!ring->tx); + ops = ring->ops; + while (1) { + B43legacy_WARN_ON(!(slot >= 0 && slot < ring->nr_slots)); + desc = ops->idx2desc(ring, slot, &meta); + + if (meta->skb) + unmap_descbuffer(ring, meta->dmaaddr, + meta->skb->len, 1); + else + unmap_descbuffer(ring, meta->dmaaddr, + sizeof(struct b43legacy_txhdr_fw3), + 1); + + if (meta->is_last_fragment) { + B43legacy_WARN_ON(!meta->skb); + /* Call back to inform the ieee80211 subsystem about the + * status of the transmission. + * Some fields of txstat are already filled in dma_tx(). + */ + if (status->acked) { + meta->txstat.flags |= IEEE80211_TX_STATUS_ACK; + } else { + if (!(meta->txstat.control.flags + & IEEE80211_TXCTL_NO_ACK)) + meta->txstat.excessive_retries = 1; + } + if (status->frame_count == 0) { + /* The frame was not transmitted at all. */ + meta->txstat.retry_count = 0; + } else + meta->txstat.retry_count = status->frame_count + - 1; + ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb, + &(meta->txstat)); + /* skb is freed by ieee80211_tx_status_irqsafe() */ + meta->skb = NULL; + } else { + /* No need to call free_descriptor_buffer here, as + * this is only the txhdr, which is not allocated. + */ + B43legacy_WARN_ON(meta->skb != NULL); + } + + /* Everything unmapped and free'd. So it's not used anymore. */ + ring->used_slots--; + + if (meta->is_last_fragment) + break; + slot = next_slot(ring, slot); + } + dev->stats.last_tx = jiffies; + if (ring->stopped) { + B43legacy_WARN_ON(free_slots(ring) < SLOTS_PER_PACKET); + ieee80211_wake_queue(dev->wl->hw, txring_to_priority(ring)); + ring->stopped = 0; + if (b43legacy_debug(dev, B43legacy_DBG_DMAVERBOSE)) + b43legacydbg(dev->wl, "Woke up TX ring %d\n", + ring->index); + } + + spin_unlock(&ring->lock); +} + +void b43legacy_dma_get_tx_stats(struct b43legacy_wldev *dev, + struct ieee80211_tx_queue_stats *stats) +{ + const int nr_queues = dev->wl->hw->queues; + struct b43legacy_dmaring *ring; + struct ieee80211_tx_queue_stats_data *data; + unsigned long flags; + int i; + + for (i = 0; i < nr_queues; i++) { + data = &(stats->data[i]); + ring = priority_to_txring(dev, i); + + spin_lock_irqsave(&ring->lock, flags); + data->len = ring->used_slots / SLOTS_PER_PACKET; + data->limit = ring->nr_slots / SLOTS_PER_PACKET; + data->count = ring->nr_tx_packets; + spin_unlock_irqrestore(&ring->lock, flags); + } +} + +static void dma_rx(struct b43legacy_dmaring *ring, + int *slot) +{ + const struct b43legacy_dma_ops *ops = ring->ops; + struct b43legacy_dmadesc_generic *desc; + struct b43legacy_dmadesc_meta *meta; + struct b43legacy_rxhdr_fw3 *rxhdr; + struct sk_buff *skb; + u16 len; + int err; + dma_addr_t dmaaddr; + + desc = ops->idx2desc(ring, *slot, &meta); + + sync_descbuffer_for_cpu(ring, meta->dmaaddr, ring->rx_buffersize); + skb = meta->skb; + + if (ring->index == 3) { + /* We received an xmit status. */ + struct b43legacy_hwtxstatus *hw = + (struct b43legacy_hwtxstatus *)skb->data; + int i = 0; + + while (hw->cookie == 0) { + if (i > 100) + break; + i++; + udelay(2); + barrier(); + } + b43legacy_handle_hwtxstatus(ring->dev, hw); + /* recycle the descriptor buffer. */ + sync_descbuffer_for_device(ring, meta->dmaaddr, + ring->rx_buffersize); + + return; + } + rxhdr = (struct b43legacy_rxhdr_fw3 *)skb->data; + len = le16_to_cpu(rxhdr->frame_len); + if (len == 0) { + int i = 0; + + do { + udelay(2); + barrier(); + len = le16_to_cpu(rxhdr->frame_len); + } while (len == 0 && i++ < 5); + if (unlikely(len == 0)) { + /* recycle the descriptor buffer. */ + sync_descbuffer_for_device(ring, meta->dmaaddr, + ring->rx_buffersize); + goto drop; + } + } + if (unlikely(len > ring->rx_buffersize)) { + /* The data did not fit into one descriptor buffer + * and is split over multiple buffers. + * This should never happen, as we try to allocate buffers + * big enough. So simply ignore this packet. + */ + int cnt = 0; + s32 tmp = len; + + while (1) { + desc = ops->idx2desc(ring, *slot, &meta); + /* recycle the descriptor buffer. */ + sync_descbuffer_for_device(ring, meta->dmaaddr, + ring->rx_buffersize); + *slot = next_slot(ring, *slot); + cnt++; + tmp -= ring->rx_buffersize; + if (tmp <= 0) + break; + } + b43legacyerr(ring->dev->wl, "DMA RX buffer too small " + "(len: %u, buffer: %u, nr-dropped: %d)\n", + len, ring->rx_buffersize, cnt); + goto drop; + } + + dmaaddr = meta->dmaaddr; + err = setup_rx_descbuffer(ring, desc, meta, GFP_ATOMIC); + if (unlikely(err)) { + b43legacydbg(ring->dev->wl, "DMA RX: setup_rx_descbuffer()" + " failed\n"); + sync_descbuffer_for_device(ring, dmaaddr, + ring->rx_buffersize); + goto drop; + } + + unmap_descbuffer(ring, dmaaddr, ring->rx_buffersize, 0); + skb_put(skb, len + ring->frameoffset); + skb_pull(skb, ring->frameoffset); + + b43legacy_rx(ring->dev, skb, rxhdr); +drop: + return; +} + +void b43legacy_dma_rx(struct b43legacy_dmaring *ring) +{ + const struct b43legacy_dma_ops *ops = ring->ops; + int slot; + int current_slot; + int used_slots = 0; + + B43legacy_WARN_ON(ring->tx); + current_slot = ops->get_current_rxslot(ring); + B43legacy_WARN_ON(!(current_slot >= 0 && current_slot < + ring->nr_slots)); + + slot = ring->current_slot; + for (; slot != current_slot; slot = next_slot(ring, slot)) { + dma_rx(ring, &slot); + update_max_used_slots(ring, ++used_slots); + } + ops->set_current_rxslot(ring, slot); + ring->current_slot = slot; +} + +static void b43legacy_dma_tx_suspend_ring(struct b43legacy_dmaring *ring) +{ + unsigned long flags; + + spin_lock_irqsave(&ring->lock, flags); + B43legacy_WARN_ON(!ring->tx); + ring->ops->tx_suspend(ring); + spin_unlock_irqrestore(&ring->lock, flags); +} + +static void b43legacy_dma_tx_resume_ring(struct b43legacy_dmaring *ring) +{ + unsigned long flags; + + spin_lock_irqsave(&ring->lock, flags); + B43legacy_WARN_ON(!ring->tx); + ring->ops->tx_resume(ring); + spin_unlock_irqrestore(&ring->lock, flags); +} + +void b43legacy_dma_tx_suspend(struct b43legacy_wldev *dev) +{ + b43legacy_power_saving_ctl_bits(dev, -1, 1); + b43legacy_dma_tx_suspend_ring(dev->dma.tx_ring0); + b43legacy_dma_tx_suspend_ring(dev->dma.tx_ring1); + b43legacy_dma_tx_suspend_ring(dev->dma.tx_ring2); + b43legacy_dma_tx_suspend_ring(dev->dma.tx_ring3); + b43legacy_dma_tx_suspend_ring(dev->dma.tx_ring4); + b43legacy_dma_tx_suspend_ring(dev->dma.tx_ring5); +} + +void b43legacy_dma_tx_resume(struct b43legacy_wldev *dev) +{ + b43legacy_dma_tx_resume_ring(dev->dma.tx_ring5); + b43legacy_dma_tx_resume_ring(dev->dma.tx_ring4); + b43legacy_dma_tx_resume_ring(dev->dma.tx_ring3); + b43legacy_dma_tx_resume_ring(dev->dma.tx_ring2); + b43legacy_dma_tx_resume_ring(dev->dma.tx_ring1); + b43legacy_dma_tx_resume_ring(dev->dma.tx_ring0); + b43legacy_power_saving_ctl_bits(dev, -1, -1); +} diff --git a/drivers/net/wireless/b43legacy/dma.h b/drivers/net/wireless/b43legacy/dma.h new file mode 100644 index 00000000000..26f6ab08de7 --- /dev/null +++ b/drivers/net/wireless/b43legacy/dma.h @@ -0,0 +1,367 @@ +#ifndef B43legacy_DMA_H_ +#define B43legacy_DMA_H_ + +#include +#include +#include +#include +#include + +#include "b43legacy.h" + + +/* DMA-Interrupt reasons. */ +#define B43legacy_DMAIRQ_FATALMASK ((1 << 10) | (1 << 11) | (1 << 12) \ + | (1 << 14) | (1 << 15)) +#define B43legacy_DMAIRQ_NONFATALMASK (1 << 13) +#define B43legacy_DMAIRQ_RX_DONE (1 << 16) + + +/*** 32-bit DMA Engine. ***/ + +/* 32-bit DMA controller registers. */ +#define B43legacy_DMA32_TXCTL 0x00 +#define B43legacy_DMA32_TXENABLE 0x00000001 +#define B43legacy_DMA32_TXSUSPEND 0x00000002 +#define B43legacy_DMA32_TXLOOPBACK 0x00000004 +#define B43legacy_DMA32_TXFLUSH 0x00000010 +#define B43legacy_DMA32_TXADDREXT_MASK 0x00030000 +#define B43legacy_DMA32_TXADDREXT_SHIFT 16 +#define B43legacy_DMA32_TXRING 0x04 +#define B43legacy_DMA32_TXINDEX 0x08 +#define B43legacy_DMA32_TXSTATUS 0x0C +#define B43legacy_DMA32_TXDPTR 0x00000FFF +#define B43legacy_DMA32_TXSTATE 0x0000F000 +#define B43legacy_DMA32_TXSTAT_DISABLED 0x00000000 +#define B43legacy_DMA32_TXSTAT_ACTIVE 0x00001000 +#define B43legacy_DMA32_TXSTAT_IDLEWAIT 0x00002000 +#define B43legacy_DMA32_TXSTAT_STOPPED 0x00003000 +#define B43legacy_DMA32_TXSTAT_SUSP 0x00004000 +#define B43legacy_DMA32_TXERROR 0x000F0000 +#define B43legacy_DMA32_TXERR_NOERR 0x00000000 +#define B43legacy_DMA32_TXERR_PROT 0x00010000 +#define B43legacy_DMA32_TXERR_UNDERRUN 0x00020000 +#define B43legacy_DMA32_TXERR_BUFREAD 0x00030000 +#define B43legacy_DMA32_TXERR_DESCREAD 0x00040000 +#define B43legacy_DMA32_TXACTIVE 0xFFF00000 +#define B43legacy_DMA32_RXCTL 0x10 +#define B43legacy_DMA32_RXENABLE 0x00000001 +#define B43legacy_DMA32_RXFROFF_MASK 0x000000FE +#define B43legacy_DMA32_RXFROFF_SHIFT 1 +#define B43legacy_DMA32_RXDIRECTFIFO 0x00000100 +#define B43legacy_DMA32_RXADDREXT_MASK 0x00030000 +#define B43legacy_DMA32_RXADDREXT_SHIFT 16 +#define B43legacy_DMA32_RXRING 0x14 +#define B43legacy_DMA32_RXINDEX 0x18 +#define B43legacy_DMA32_RXSTATUS 0x1C +#define B43legacy_DMA32_RXDPTR 0x00000FFF +#define B43legacy_DMA32_RXSTATE 0x0000F000 +#define B43legacy_DMA32_RXSTAT_DISABLED 0x00000000 +#define B43legacy_DMA32_RXSTAT_ACTIVE 0x00001000 +#define B43legacy_DMA32_RXSTAT_IDLEWAIT 0x00002000 +#define B43legacy_DMA32_RXSTAT_STOPPED 0x00003000 +#define B43legacy_DMA32_RXERROR 0x000F0000 +#define B43legacy_DMA32_RXERR_NOERR 0x00000000 +#define B43legacy_DMA32_RXERR_PROT 0x00010000 +#define B43legacy_DMA32_RXERR_OVERFLOW 0x00020000 +#define B43legacy_DMA32_RXERR_BUFWRITE 0x00030000 +#define B43legacy_DMA32_RXERR_DESCREAD 0x00040000 +#define B43legacy_DMA32_RXACTIVE 0xFFF00000 + +/* 32-bit DMA descriptor. */ +struct b43legacy_dmadesc32 { + __le32 control; + __le32 address; +} __attribute__((__packed__)); +#define B43legacy_DMA32_DCTL_BYTECNT 0x00001FFF +#define B43legacy_DMA32_DCTL_ADDREXT_MASK 0x00030000 +#define B43legacy_DMA32_DCTL_ADDREXT_SHIFT 16 +#define B43legacy_DMA32_DCTL_DTABLEEND 0x10000000 +#define B43legacy_DMA32_DCTL_IRQ 0x20000000 +#define B43legacy_DMA32_DCTL_FRAMEEND 0x40000000 +#define B43legacy_DMA32_DCTL_FRAMESTART 0x80000000 + + + +/*** 64-bit DMA Engine. ***/ + +/* 64-bit DMA controller registers. */ +#define B43legacy_DMA64_TXCTL 0x00 +#define B43legacy_DMA64_TXENABLE 0x00000001 +#define B43legacy_DMA64_TXSUSPEND 0x00000002 +#define B43legacy_DMA64_TXLOOPBACK 0x00000004 +#define B43legacy_DMA64_TXFLUSH 0x00000010 +#define B43legacy_DMA64_TXADDREXT_MASK 0x00030000 +#define B43legacy_DMA64_TXADDREXT_SHIFT 16 +#define B43legacy_DMA64_TXINDEX 0x04 +#define B43legacy_DMA64_TXRINGLO 0x08 +#define B43legacy_DMA64_TXRINGHI 0x0C +#define B43legacy_DMA64_TXSTATUS 0x10 +#define B43legacy_DMA64_TXSTATDPTR 0x00001FFF +#define B43legacy_DMA64_TXSTAT 0xF0000000 +#define B43legacy_DMA64_TXSTAT_DISABLED 0x00000000 +#define B43legacy_DMA64_TXSTAT_ACTIVE 0x10000000 +#define B43legacy_DMA64_TXSTAT_IDLEWAIT 0x20000000 +#define B43legacy_DMA64_TXSTAT_STOPPED 0x30000000 +#define B43legacy_DMA64_TXSTAT_SUSP 0x40000000 +#define B43legacy_DMA64_TXERROR 0x14 +#define B43legacy_DMA64_TXERRDPTR 0x0001FFFF +#define B43legacy_DMA64_TXERR 0xF0000000 +#define B43legacy_DMA64_TXERR_NOERR 0x00000000 +#define B43legacy_DMA64_TXERR_PROT 0x10000000 +#define B43legacy_DMA64_TXERR_UNDERRUN 0x20000000 +#define B43legacy_DMA64_TXERR_TRANSFER 0x30000000 +#define B43legacy_DMA64_TXERR_DESCREAD 0x40000000 +#define B43legacy_DMA64_TXERR_CORE 0x50000000 +#define B43legacy_DMA64_RXCTL 0x20 +#define B43legacy_DMA64_RXENABLE 0x00000001 +#define B43legacy_DMA64_RXFROFF_MASK 0x000000FE +#define B43legacy_DMA64_RXFROFF_SHIFT 1 +#define B43legacy_DMA64_RXDIRECTFIFO 0x00000100 +#define B43legacy_DMA64_RXADDREXT_MASK 0x00030000 +#define B43legacy_DMA64_RXADDREXT_SHIFT 16 +#define B43legacy_DMA64_RXINDEX 0x24 +#define B43legacy_DMA64_RXRINGLO 0x28 +#define B43legacy_DMA64_RXRINGHI 0x2C +#define B43legacy_DMA64_RXSTATUS 0x30 +#define B43legacy_DMA64_RXSTATDPTR 0x00001FFF +#define B43legacy_DMA64_RXSTAT 0xF0000000 +#define B43legacy_DMA64_RXSTAT_DISABLED 0x00000000 +#define B43legacy_DMA64_RXSTAT_ACTIVE 0x10000000 +#define B43legacy_DMA64_RXSTAT_IDLEWAIT 0x20000000 +#define B43legacy_DMA64_RXSTAT_STOPPED 0x30000000 +#define B43legacy_DMA64_RXSTAT_SUSP 0x40000000 +#define B43legacy_DMA64_RXERROR 0x34 +#define B43legacy_DMA64_RXERRDPTR 0x0001FFFF +#define B43legacy_DMA64_RXERR 0xF0000000 +#define B43legacy_DMA64_RXERR_NOERR 0x00000000 +#define B43legacy_DMA64_RXERR_PROT 0x10000000 +#define B43legacy_DMA64_RXERR_UNDERRUN 0x20000000 +#define B43legacy_DMA64_RXERR_TRANSFER 0x30000000 +#define B43legacy_DMA64_RXERR_DESCREAD 0x40000000 +#define B43legacy_DMA64_RXERR_CORE 0x50000000 + +/* 64-bit DMA descriptor. */ +struct b43legacy_dmadesc64 { + __le32 control0; + __le32 control1; + __le32 address_low; + __le32 address_high; +} __attribute__((__packed__)); +#define B43legacy_DMA64_DCTL0_DTABLEEND 0x10000000 +#define B43legacy_DMA64_DCTL0_IRQ 0x20000000 +#define B43legacy_DMA64_DCTL0_FRAMEEND 0x40000000 +#define B43legacy_DMA64_DCTL0_FRAMESTART 0x80000000 +#define B43legacy_DMA64_DCTL1_BYTECNT 0x00001FFF +#define B43legacy_DMA64_DCTL1_ADDREXT_MASK 0x00030000 +#define B43legacy_DMA64_DCTL1_ADDREXT_SHIFT 16 + + + +struct b43legacy_dmadesc_generic { + union { + struct b43legacy_dmadesc32 dma32; + struct b43legacy_dmadesc64 dma64; + } __attribute__((__packed__)); +} __attribute__((__packed__)); + + +/* Misc DMA constants */ +#define B43legacy_DMA_RINGMEMSIZE PAGE_SIZE +#define B43legacy_DMA0_RX_FRAMEOFFSET 30 +#define B43legacy_DMA3_RX_FRAMEOFFSET 0 + + +/* DMA engine tuning knobs */ +#define B43legacy_TXRING_SLOTS 128 +#define B43legacy_RXRING_SLOTS 64 +#define B43legacy_DMA0_RX_BUFFERSIZE (2304 + 100) +#define B43legacy_DMA3_RX_BUFFERSIZE 16 + + + +#ifdef CONFIG_B43LEGACY_DMA + + +struct sk_buff; +struct b43legacy_private; +struct b43legacy_txstatus; + + +struct b43legacy_dmadesc_meta { + /* The kernel DMA-able buffer. */ + struct sk_buff *skb; + /* DMA base bus-address of the descriptor buffer. */ + dma_addr_t dmaaddr; + /* ieee80211 TX status. Only used once per 802.11 frag. */ + bool is_last_fragment; + struct ieee80211_tx_status txstat; +}; + +struct b43legacy_dmaring; + +/* Lowlevel DMA operations that differ between 32bit and 64bit DMA. */ +struct b43legacy_dma_ops { + struct b43legacy_dmadesc_generic * (*idx2desc) + (struct b43legacy_dmaring *ring, + int slot, + struct b43legacy_dmadesc_meta + **meta); + void (*fill_descriptor)(struct b43legacy_dmaring *ring, + struct b43legacy_dmadesc_generic *desc, + dma_addr_t dmaaddr, u16 bufsize, + int start, int end, int irq); + void (*poke_tx)(struct b43legacy_dmaring *ring, int slot); + void (*tx_suspend)(struct b43legacy_dmaring *ring); + void (*tx_resume)(struct b43legacy_dmaring *ring); + int (*get_current_rxslot)(struct b43legacy_dmaring *ring); + void (*set_current_rxslot)(struct b43legacy_dmaring *ring, int slot); +}; + +struct b43legacy_dmaring { + /* Lowlevel DMA ops. */ + const struct b43legacy_dma_ops *ops; + /* Kernel virtual base address of the ring memory. */ + void *descbase; + /* Meta data about all descriptors. */ + struct b43legacy_dmadesc_meta *meta; + /* Cache of TX headers for each slot. + * This is to avoid an allocation on each TX. + * This is NULL for an RX ring. + */ + u8 *txhdr_cache; + /* (Unadjusted) DMA base bus-address of the ring memory. */ + dma_addr_t dmabase; + /* Number of descriptor slots in the ring. */ + int nr_slots; + /* Number of used descriptor slots. */ + int used_slots; + /* Currently used slot in the ring. */ + int current_slot; + /* Total number of packets sent. Statistics only. */ + unsigned int nr_tx_packets; + /* Frameoffset in octets. */ + u32 frameoffset; + /* Descriptor buffer size. */ + u16 rx_buffersize; + /* The MMIO base register of the DMA controller. */ + u16 mmio_base; + /* DMA controller index number (0-5). */ + int index; + /* Boolean. Is this a TX ring? */ + bool tx; + /* Boolean. 64bit DMA if true, 32bit DMA otherwise. */ + bool dma64; + /* Boolean. Is this ring stopped at ieee80211 level? */ + bool stopped; + /* Lock, only used for TX. */ + spinlock_t lock; + struct b43legacy_wldev *dev; +#ifdef CONFIG_B43LEGACY_DEBUG + /* Maximum number of used slots. */ + int max_used_slots; + /* Last time we injected a ring overflow. */ + unsigned long last_injected_overflow; +#endif /* CONFIG_B43LEGACY_DEBUG*/ +}; + + +static inline +u32 b43legacy_dma_read(struct b43legacy_dmaring *ring, + u16 offset) +{ + return b43legacy_read32(ring->dev, ring->mmio_base + offset); +} + +static inline +void b43legacy_dma_write(struct b43legacy_dmaring *ring, + u16 offset, u32 value) +{ + b43legacy_write32(ring->dev, ring->mmio_base + offset, value); +} + + +int b43legacy_dma_init(struct b43legacy_wldev *dev); +void b43legacy_dma_free(struct b43legacy_wldev *dev); + +int b43legacy_dmacontroller_rx_reset(struct b43legacy_wldev *dev, + u16 dmacontroller_mmio_base, + int dma64); +int b43legacy_dmacontroller_tx_reset(struct b43legacy_wldev *dev, + u16 dmacontroller_mmio_base, + int dma64); + +u16 b43legacy_dmacontroller_base(int dma64bit, int dmacontroller_idx); + +void b43legacy_dma_tx_suspend(struct b43legacy_wldev *dev); +void b43legacy_dma_tx_resume(struct b43legacy_wldev *dev); + +void b43legacy_dma_get_tx_stats(struct b43legacy_wldev *dev, + struct ieee80211_tx_queue_stats *stats); + +int b43legacy_dma_tx(struct b43legacy_wldev *dev, + struct sk_buff *skb, + struct ieee80211_tx_control *ctl); +void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev, + const struct b43legacy_txstatus *status); + +void b43legacy_dma_rx(struct b43legacy_dmaring *ring); + +#else /* CONFIG_B43LEGACY_DMA */ + + +static inline +int b43legacy_dma_init(struct b43legacy_wldev *dev) +{ + return 0; +} +static inline +void b43legacy_dma_free(struct b43legacy_wldev *dev) +{ +} +static inline +int b43legacy_dmacontroller_rx_reset(struct b43legacy_wldev *dev, + u16 dmacontroller_mmio_base, + int dma64) +{ + return 0; +} +static inline +int b43legacy_dmacontroller_tx_reset(struct b43legacy_wldev *dev, + u16 dmacontroller_mmio_base, + int dma64) +{ + return 0; +} +static inline +void b43legacy_dma_get_tx_stats(struct b43legacy_wldev *dev, + struct ieee80211_tx_queue_stats *stats) +{ +} +static inline +int b43legacy_dma_tx(struct b43legacy_wldev *dev, + struct sk_buff *skb, + struct ieee80211_tx_control *ctl) +{ + return 0; +} +static inline +void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev, + const struct b43legacy_txstatus *status) +{ +} +static inline +void b43legacy_dma_rx(struct b43legacy_dmaring *ring) +{ +} +static inline +void b43legacy_dma_tx_suspend(struct b43legacy_wldev *dev) +{ +} +static inline +void b43legacy_dma_tx_resume(struct b43legacy_wldev *dev) +{ +} + +#endif /* CONFIG_B43LEGACY_DMA */ +#endif /* B43legacy_DMA_H_ */ diff --git a/drivers/net/wireless/b43legacy/ilt.c b/drivers/net/wireless/b43legacy/ilt.c new file mode 100644 index 00000000000..247fc780ffd --- /dev/null +++ b/drivers/net/wireless/b43legacy/ilt.c @@ -0,0 +1,336 @@ +/* + + Broadcom B43legacy wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "b43legacy.h" +#include "ilt.h" +#include "phy.h" + + +/**** Initial Internal Lookup Tables ****/ + +const u32 b43legacy_ilt_rotor[B43legacy_ILT_ROTOR_SIZE] = { + 0xFEB93FFD, 0xFEC63FFD, /* 0 */ + 0xFED23FFD, 0xFEDF3FFD, + 0xFEEC3FFE, 0xFEF83FFE, + 0xFF053FFE, 0xFF113FFE, + 0xFF1E3FFE, 0xFF2A3FFF, /* 8 */ + 0xFF373FFF, 0xFF443FFF, + 0xFF503FFF, 0xFF5D3FFF, + 0xFF693FFF, 0xFF763FFF, + 0xFF824000, 0xFF8F4000, /* 16 */ + 0xFF9B4000, 0xFFA84000, + 0xFFB54000, 0xFFC14000, + 0xFFCE4000, 0xFFDA4000, + 0xFFE74000, 0xFFF34000, /* 24 */ + 0x00004000, 0x000D4000, + 0x00194000, 0x00264000, + 0x00324000, 0x003F4000, + 0x004B4000, 0x00584000, /* 32 */ + 0x00654000, 0x00714000, + 0x007E4000, 0x008A3FFF, + 0x00973FFF, 0x00A33FFF, + 0x00B03FFF, 0x00BC3FFF, /* 40 */ + 0x00C93FFF, 0x00D63FFF, + 0x00E23FFE, 0x00EF3FFE, + 0x00FB3FFE, 0x01083FFE, + 0x01143FFE, 0x01213FFD, /* 48 */ + 0x012E3FFD, 0x013A3FFD, + 0x01473FFD, +}; + +const u32 b43legacy_ilt_retard[B43legacy_ILT_RETARD_SIZE] = { + 0xDB93CB87, 0xD666CF64, /* 0 */ + 0xD1FDD358, 0xCDA6D826, + 0xCA38DD9F, 0xC729E2B4, + 0xC469E88E, 0xC26AEE2B, + 0xC0DEF46C, 0xC073FA62, /* 8 */ + 0xC01D00D5, 0xC0760743, + 0xC1560D1E, 0xC2E51369, + 0xC4ED18FF, 0xC7AC1ED7, + 0xCB2823B2, 0xCEFA28D9, /* 16 */ + 0xD2F62D3F, 0xD7BB3197, + 0xDCE53568, 0xE1FE3875, + 0xE7D13B35, 0xED663D35, + 0xF39B3EC4, 0xF98E3FA7, /* 24 */ + 0x00004000, 0x06723FA7, + 0x0C653EC4, 0x129A3D35, + 0x182F3B35, 0x1E023875, + 0x231B3568, 0x28453197, /* 32 */ + 0x2D0A2D3F, 0x310628D9, + 0x34D823B2, 0x38541ED7, + 0x3B1318FF, 0x3D1B1369, + 0x3EAA0D1E, 0x3F8A0743, /* 40 */ + 0x3FE300D5, 0x3F8DFA62, + 0x3F22F46C, 0x3D96EE2B, + 0x3B97E88E, 0x38D7E2B4, + 0x35C8DD9F, 0x325AD826, /* 48 */ + 0x2E03D358, 0x299ACF64, + 0x246DCB87, +}; + +const u16 b43legacy_ilt_finefreqa[B43legacy_ILT_FINEFREQA_SIZE] = { + 0x0082, 0x0082, 0x0102, 0x0182, /* 0 */ + 0x0202, 0x0282, 0x0302, 0x0382, + 0x0402, 0x0482, 0x0502, 0x0582, + 0x05E2, 0x0662, 0x06E2, 0x0762, + 0x07E2, 0x0842, 0x08C2, 0x0942, /* 16 */ + 0x09C2, 0x0A22, 0x0AA2, 0x0B02, + 0x0B82, 0x0BE2, 0x0C62, 0x0CC2, + 0x0D42, 0x0DA2, 0x0E02, 0x0E62, + 0x0EE2, 0x0F42, 0x0FA2, 0x1002, /* 32 */ + 0x1062, 0x10C2, 0x1122, 0x1182, + 0x11E2, 0x1242, 0x12A2, 0x12E2, + 0x1342, 0x13A2, 0x1402, 0x1442, + 0x14A2, 0x14E2, 0x1542, 0x1582, /* 48 */ + 0x15E2, 0x1622, 0x1662, 0x16C1, + 0x1701, 0x1741, 0x1781, 0x17E1, + 0x1821, 0x1861, 0x18A1, 0x18E1, + 0x1921, 0x1961, 0x19A1, 0x19E1, /* 64 */ + 0x1A21, 0x1A61, 0x1AA1, 0x1AC1, + 0x1B01, 0x1B41, 0x1B81, 0x1BA1, + 0x1BE1, 0x1C21, 0x1C41, 0x1C81, + 0x1CA1, 0x1CE1, 0x1D01, 0x1D41, /* 80 */ + 0x1D61, 0x1DA1, 0x1DC1, 0x1E01, + 0x1E21, 0x1E61, 0x1E81, 0x1EA1, + 0x1EE1, 0x1F01, 0x1F21, 0x1F41, + 0x1F81, 0x1FA1, 0x1FC1, 0x1FE1, /* 96 */ + 0x2001, 0x2041, 0x2061, 0x2081, + 0x20A1, 0x20C1, 0x20E1, 0x2101, + 0x2121, 0x2141, 0x2161, 0x2181, + 0x21A1, 0x21C1, 0x21E1, 0x2201, /* 112 */ + 0x2221, 0x2241, 0x2261, 0x2281, + 0x22A1, 0x22C1, 0x22C1, 0x22E1, + 0x2301, 0x2321, 0x2341, 0x2361, + 0x2361, 0x2381, 0x23A1, 0x23C1, /* 128 */ + 0x23E1, 0x23E1, 0x2401, 0x2421, + 0x2441, 0x2441, 0x2461, 0x2481, + 0x2481, 0x24A1, 0x24C1, 0x24C1, + 0x24E1, 0x2501, 0x2501, 0x2521, /* 144 */ + 0x2541, 0x2541, 0x2561, 0x2561, + 0x2581, 0x25A1, 0x25A1, 0x25C1, + 0x25C1, 0x25E1, 0x2601, 0x2601, + 0x2621, 0x2621, 0x2641, 0x2641, /* 160 */ + 0x2661, 0x2661, 0x2681, 0x2681, + 0x26A1, 0x26A1, 0x26C1, 0x26C1, + 0x26E1, 0x26E1, 0x2701, 0x2701, + 0x2721, 0x2721, 0x2740, 0x2740, /* 176 */ + 0x2760, 0x2760, 0x2780, 0x2780, + 0x2780, 0x27A0, 0x27A0, 0x27C0, + 0x27C0, 0x27E0, 0x27E0, 0x27E0, + 0x2800, 0x2800, 0x2820, 0x2820, /* 192 */ + 0x2820, 0x2840, 0x2840, 0x2840, + 0x2860, 0x2860, 0x2880, 0x2880, + 0x2880, 0x28A0, 0x28A0, 0x28A0, + 0x28C0, 0x28C0, 0x28C0, 0x28E0, /* 208 */ + 0x28E0, 0x28E0, 0x2900, 0x2900, + 0x2900, 0x2920, 0x2920, 0x2920, + 0x2940, 0x2940, 0x2940, 0x2960, + 0x2960, 0x2960, 0x2960, 0x2980, /* 224 */ + 0x2980, 0x2980, 0x29A0, 0x29A0, + 0x29A0, 0x29A0, 0x29C0, 0x29C0, + 0x29C0, 0x29E0, 0x29E0, 0x29E0, + 0x29E0, 0x2A00, 0x2A00, 0x2A00, /* 240 */ + 0x2A00, 0x2A20, 0x2A20, 0x2A20, + 0x2A20, 0x2A40, 0x2A40, 0x2A40, + 0x2A40, 0x2A60, 0x2A60, 0x2A60, +}; + +const u16 b43legacy_ilt_finefreqg[B43legacy_ILT_FINEFREQG_SIZE] = { + 0x0089, 0x02E9, 0x0409, 0x04E9, /* 0 */ + 0x05A9, 0x0669, 0x0709, 0x0789, + 0x0829, 0x08A9, 0x0929, 0x0989, + 0x0A09, 0x0A69, 0x0AC9, 0x0B29, + 0x0BA9, 0x0BE9, 0x0C49, 0x0CA9, /* 16 */ + 0x0D09, 0x0D69, 0x0DA9, 0x0E09, + 0x0E69, 0x0EA9, 0x0F09, 0x0F49, + 0x0FA9, 0x0FE9, 0x1029, 0x1089, + 0x10C9, 0x1109, 0x1169, 0x11A9, /* 32 */ + 0x11E9, 0x1229, 0x1289, 0x12C9, + 0x1309, 0x1349, 0x1389, 0x13C9, + 0x1409, 0x1449, 0x14A9, 0x14E9, + 0x1529, 0x1569, 0x15A9, 0x15E9, /* 48 */ + 0x1629, 0x1669, 0x16A9, 0x16E8, + 0x1728, 0x1768, 0x17A8, 0x17E8, + 0x1828, 0x1868, 0x18A8, 0x18E8, + 0x1928, 0x1968, 0x19A8, 0x19E8, /* 64 */ + 0x1A28, 0x1A68, 0x1AA8, 0x1AE8, + 0x1B28, 0x1B68, 0x1BA8, 0x1BE8, + 0x1C28, 0x1C68, 0x1CA8, 0x1CE8, + 0x1D28, 0x1D68, 0x1DC8, 0x1E08, /* 80 */ + 0x1E48, 0x1E88, 0x1EC8, 0x1F08, + 0x1F48, 0x1F88, 0x1FE8, 0x2028, + 0x2068, 0x20A8, 0x2108, 0x2148, + 0x2188, 0x21C8, 0x2228, 0x2268, /* 96 */ + 0x22C8, 0x2308, 0x2348, 0x23A8, + 0x23E8, 0x2448, 0x24A8, 0x24E8, + 0x2548, 0x25A8, 0x2608, 0x2668, + 0x26C8, 0x2728, 0x2787, 0x27E7, /* 112 */ + 0x2847, 0x28C7, 0x2947, 0x29A7, + 0x2A27, 0x2AC7, 0x2B47, 0x2BE7, + 0x2CA7, 0x2D67, 0x2E47, 0x2F67, + 0x3247, 0x3526, 0x3646, 0x3726, /* 128 */ + 0x3806, 0x38A6, 0x3946, 0x39E6, + 0x3A66, 0x3AE6, 0x3B66, 0x3BC6, + 0x3C45, 0x3CA5, 0x3D05, 0x3D85, + 0x3DE5, 0x3E45, 0x3EA5, 0x3EE5, /* 144 */ + 0x3F45, 0x3FA5, 0x4005, 0x4045, + 0x40A5, 0x40E5, 0x4145, 0x4185, + 0x41E5, 0x4225, 0x4265, 0x42C5, + 0x4305, 0x4345, 0x43A5, 0x43E5, /* 160 */ + 0x4424, 0x4464, 0x44C4, 0x4504, + 0x4544, 0x4584, 0x45C4, 0x4604, + 0x4644, 0x46A4, 0x46E4, 0x4724, + 0x4764, 0x47A4, 0x47E4, 0x4824, /* 176 */ + 0x4864, 0x48A4, 0x48E4, 0x4924, + 0x4964, 0x49A4, 0x49E4, 0x4A24, + 0x4A64, 0x4AA4, 0x4AE4, 0x4B23, + 0x4B63, 0x4BA3, 0x4BE3, 0x4C23, /* 192 */ + 0x4C63, 0x4CA3, 0x4CE3, 0x4D23, + 0x4D63, 0x4DA3, 0x4DE3, 0x4E23, + 0x4E63, 0x4EA3, 0x4EE3, 0x4F23, + 0x4F63, 0x4FC3, 0x5003, 0x5043, /* 208 */ + 0x5083, 0x50C3, 0x5103, 0x5143, + 0x5183, 0x51E2, 0x5222, 0x5262, + 0x52A2, 0x52E2, 0x5342, 0x5382, + 0x53C2, 0x5402, 0x5462, 0x54A2, /* 224 */ + 0x5502, 0x5542, 0x55A2, 0x55E2, + 0x5642, 0x5682, 0x56E2, 0x5722, + 0x5782, 0x57E1, 0x5841, 0x58A1, + 0x5901, 0x5961, 0x59C1, 0x5A21, /* 240 */ + 0x5AA1, 0x5B01, 0x5B81, 0x5BE1, + 0x5C61, 0x5D01, 0x5D80, 0x5E20, + 0x5EE0, 0x5FA0, 0x6080, 0x61C0, +}; + +const u16 b43legacy_ilt_noisea2[B43legacy_ILT_NOISEA2_SIZE] = { + 0x0001, 0x0001, 0x0001, 0xFFFE, + 0xFFFE, 0x3FFF, 0x1000, 0x0393, +}; + +const u16 b43legacy_ilt_noisea3[B43legacy_ILT_NOISEA3_SIZE] = { + 0x4C4C, 0x4C4C, 0x4C4C, 0x2D36, + 0x4C4C, 0x4C4C, 0x4C4C, 0x2D36, +}; + +const u16 b43legacy_ilt_noiseg1[B43legacy_ILT_NOISEG1_SIZE] = { + 0x013C, 0x01F5, 0x031A, 0x0631, + 0x0001, 0x0001, 0x0001, 0x0001, +}; + +const u16 b43legacy_ilt_noiseg2[B43legacy_ILT_NOISEG2_SIZE] = { + 0x5484, 0x3C40, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, +}; + +const u16 b43legacy_ilt_noisescaleg1[B43legacy_ILT_NOISESCALEG_SIZE] = { + 0x6C77, 0x5162, 0x3B40, 0x3335, /* 0 */ + 0x2F2D, 0x2A2A, 0x2527, 0x1F21, + 0x1A1D, 0x1719, 0x1616, 0x1414, + 0x1414, 0x1400, 0x1414, 0x1614, + 0x1716, 0x1A19, 0x1F1D, 0x2521, /* 16 */ + 0x2A27, 0x2F2A, 0x332D, 0x3B35, + 0x5140, 0x6C62, 0x0077, +}; + +const u16 b43legacy_ilt_noisescaleg2[B43legacy_ILT_NOISESCALEG_SIZE] = { + 0xD8DD, 0xCBD4, 0xBCC0, 0XB6B7, /* 0 */ + 0xB2B0, 0xADAD, 0xA7A9, 0x9FA1, + 0x969B, 0x9195, 0x8F8F, 0x8A8A, + 0x8A8A, 0x8A00, 0x8A8A, 0x8F8A, + 0x918F, 0x9695, 0x9F9B, 0xA7A1, /* 16 */ + 0xADA9, 0xB2AD, 0xB6B0, 0xBCB7, + 0xCBC0, 0xD8D4, 0x00DD, +}; + +const u16 b43legacy_ilt_noisescaleg3[B43legacy_ILT_NOISESCALEG_SIZE] = { + 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, /* 0 */ + 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, + 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, + 0xA4A4, 0xA400, 0xA4A4, 0xA4A4, + 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, /* 16 */ + 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, + 0xA4A4, 0xA4A4, 0x00A4, +}; + +const u16 b43legacy_ilt_sigmasqr1[B43legacy_ILT_SIGMASQR_SIZE] = { + 0x007A, 0x0075, 0x0071, 0x006C, /* 0 */ + 0x0067, 0x0063, 0x005E, 0x0059, + 0x0054, 0x0050, 0x004B, 0x0046, + 0x0042, 0x003D, 0x003D, 0x003D, + 0x003D, 0x003D, 0x003D, 0x003D, /* 16 */ + 0x003D, 0x003D, 0x003D, 0x003D, + 0x003D, 0x003D, 0x0000, 0x003D, + 0x003D, 0x003D, 0x003D, 0x003D, + 0x003D, 0x003D, 0x003D, 0x003D, /* 32 */ + 0x003D, 0x003D, 0x003D, 0x003D, + 0x0042, 0x0046, 0x004B, 0x0050, + 0x0054, 0x0059, 0x005E, 0x0063, + 0x0067, 0x006C, 0x0071, 0x0075, /* 48 */ + 0x007A, +}; + +const u16 b43legacy_ilt_sigmasqr2[B43legacy_ILT_SIGMASQR_SIZE] = { + 0x00DE, 0x00DC, 0x00DA, 0x00D8, /* 0 */ + 0x00D6, 0x00D4, 0x00D2, 0x00CF, + 0x00CD, 0x00CA, 0x00C7, 0x00C4, + 0x00C1, 0x00BE, 0x00BE, 0x00BE, + 0x00BE, 0x00BE, 0x00BE, 0x00BE, /* 16 */ + 0x00BE, 0x00BE, 0x00BE, 0x00BE, + 0x00BE, 0x00BE, 0x0000, 0x00BE, + 0x00BE, 0x00BE, 0x00BE, 0x00BE, + 0x00BE, 0x00BE, 0x00BE, 0x00BE, /* 32 */ + 0x00BE, 0x00BE, 0x00BE, 0x00BE, + 0x00C1, 0x00C4, 0x00C7, 0x00CA, + 0x00CD, 0x00CF, 0x00D2, 0x00D4, + 0x00D6, 0x00D8, 0x00DA, 0x00DC, /* 48 */ + 0x00DE, +}; + +/**** Helper functions to access the device Internal Lookup Tables ****/ + +void b43legacy_ilt_write(struct b43legacy_wldev *dev, u16 offset, u16 val) +{ + b43legacy_phy_write(dev, B43legacy_PHY_ILT_G_CTRL, offset); + mmiowb(); + b43legacy_phy_write(dev, B43legacy_PHY_ILT_G_DATA1, val); +} + +void b43legacy_ilt_write32(struct b43legacy_wldev *dev, u16 offset, u32 val) +{ + b43legacy_phy_write(dev, B43legacy_PHY_ILT_G_CTRL, offset); + mmiowb(); + b43legacy_phy_write(dev, B43legacy_PHY_ILT_G_DATA2, + (val & 0xFFFF0000) >> 16); + b43legacy_phy_write(dev, B43legacy_PHY_ILT_G_DATA1, + val & 0x0000FFFF); +} + +u16 b43legacy_ilt_read(struct b43legacy_wldev *dev, u16 offset) +{ + b43legacy_phy_write(dev, B43legacy_PHY_ILT_G_CTRL, offset); + return b43legacy_phy_read(dev, B43legacy_PHY_ILT_G_DATA1); +} diff --git a/drivers/net/wireless/b43legacy/ilt.h b/drivers/net/wireless/b43legacy/ilt.h new file mode 100644 index 00000000000..48bcf37eccb --- /dev/null +++ b/drivers/net/wireless/b43legacy/ilt.h @@ -0,0 +1,34 @@ +#ifndef B43legacy_ILT_H_ +#define B43legacy_ILT_H_ + +#define B43legacy_ILT_ROTOR_SIZE 53 +extern const u32 b43legacy_ilt_rotor[B43legacy_ILT_ROTOR_SIZE]; +#define B43legacy_ILT_RETARD_SIZE 53 +extern const u32 b43legacy_ilt_retard[B43legacy_ILT_RETARD_SIZE]; +#define B43legacy_ILT_FINEFREQA_SIZE 256 +extern const u16 b43legacy_ilt_finefreqa[B43legacy_ILT_FINEFREQA_SIZE]; +#define B43legacy_ILT_FINEFREQG_SIZE 256 +extern const u16 b43legacy_ilt_finefreqg[B43legacy_ILT_FINEFREQG_SIZE]; +#define B43legacy_ILT_NOISEA2_SIZE 8 +extern const u16 b43legacy_ilt_noisea2[B43legacy_ILT_NOISEA2_SIZE]; +#define B43legacy_ILT_NOISEA3_SIZE 8 +extern const u16 b43legacy_ilt_noisea3[B43legacy_ILT_NOISEA3_SIZE]; +#define B43legacy_ILT_NOISEG1_SIZE 8 +extern const u16 b43legacy_ilt_noiseg1[B43legacy_ILT_NOISEG1_SIZE]; +#define B43legacy_ILT_NOISEG2_SIZE 8 +extern const u16 b43legacy_ilt_noiseg2[B43legacy_ILT_NOISEG2_SIZE]; +#define B43legacy_ILT_NOISESCALEG_SIZE 27 +extern const u16 b43legacy_ilt_noisescaleg1[B43legacy_ILT_NOISESCALEG_SIZE]; +extern const u16 b43legacy_ilt_noisescaleg2[B43legacy_ILT_NOISESCALEG_SIZE]; +extern const u16 b43legacy_ilt_noisescaleg3[B43legacy_ILT_NOISESCALEG_SIZE]; +#define B43legacy_ILT_SIGMASQR_SIZE 53 +extern const u16 b43legacy_ilt_sigmasqr1[B43legacy_ILT_SIGMASQR_SIZE]; +extern const u16 b43legacy_ilt_sigmasqr2[B43legacy_ILT_SIGMASQR_SIZE]; + + +void b43legacy_ilt_write(struct b43legacy_wldev *dev, u16 offset, u16 val); +void b43legacy_ilt_write32(struct b43legacy_wldev *dev, u16 offset, + u32 val); +u16 b43legacy_ilt_read(struct b43legacy_wldev *dev, u16 offset); + +#endif /* B43legacy_ILT_H_ */ diff --git a/drivers/net/wireless/b43legacy/leds.c b/drivers/net/wireless/b43legacy/leds.c new file mode 100644 index 00000000000..498912ddedd --- /dev/null +++ b/drivers/net/wireless/b43legacy/leds.c @@ -0,0 +1,302 @@ +/* + + Broadcom B43legacy wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + Copyright (c) 2007 Larry Finger + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "leds.h" +#include "b43legacy.h" +#include "main.h" + +static void b43legacy_led_changestate(struct b43legacy_led *led) +{ + struct b43legacy_wldev *dev = led->dev; + const int index = led->index; + u16 ledctl; + + B43legacy_WARN_ON(!(index >= 0 && index < B43legacy_NR_LEDS)); + B43legacy_WARN_ON(!led->blink_interval); + ledctl = b43legacy_read16(dev, B43legacy_MMIO_GPIO_CONTROL); + ledctl ^= (1 << index); + b43legacy_write16(dev, B43legacy_MMIO_GPIO_CONTROL, ledctl); +} + +static void b43legacy_led_blink(unsigned long d) +{ + struct b43legacy_led *led = (struct b43legacy_led *)d; + struct b43legacy_wldev *dev = led->dev; + unsigned long flags; + + spin_lock_irqsave(&dev->wl->leds_lock, flags); + if (led->blink_interval) { + b43legacy_led_changestate(led); + mod_timer(&led->blink_timer, jiffies + led->blink_interval); + } + spin_unlock_irqrestore(&dev->wl->leds_lock, flags); +} + +static void b43legacy_led_blink_start(struct b43legacy_led *led, + unsigned long interval) +{ + if (led->blink_interval) + return; + led->blink_interval = interval; + b43legacy_led_changestate(led); + led->blink_timer.expires = jiffies + interval; + add_timer(&led->blink_timer); +} + +static void b43legacy_led_blink_stop(struct b43legacy_led *led, int sync) +{ + struct b43legacy_wldev *dev = led->dev; + const int index = led->index; + u16 ledctl; + + if (!led->blink_interval) + return; + if (unlikely(sync)) + del_timer_sync(&led->blink_timer); + else + del_timer(&led->blink_timer); + led->blink_interval = 0; + + /* Make sure the LED is turned off. */ + B43legacy_WARN_ON(!(index >= 0 && index < B43legacy_NR_LEDS)); + ledctl = b43legacy_read16(dev, B43legacy_MMIO_GPIO_CONTROL); + if (led->activelow) + ledctl |= (1 << index); + else + ledctl &= ~(1 << index); + b43legacy_write16(dev, B43legacy_MMIO_GPIO_CONTROL, ledctl); +} + +static void b43legacy_led_init_hardcoded(struct b43legacy_wldev *dev, + struct b43legacy_led *led, + int led_index) +{ + struct ssb_bus *bus = dev->dev->bus; + + /* This function is called, if the behaviour (and activelow) + * information for a LED is missing in the SPROM. + * We hardcode the behaviour values for various devices here. + * Note that the B43legacy_LED_TEST_XXX behaviour values can + * be used to figure out which led is mapped to which index. + */ + + switch (led_index) { + case 0: + led->behaviour = B43legacy_LED_ACTIVITY; + led->activelow = 1; + if (bus->boardinfo.vendor == PCI_VENDOR_ID_COMPAQ) + led->behaviour = B43legacy_LED_RADIO_ALL; + break; + case 1: + led->behaviour = B43legacy_LED_RADIO_B; + if (bus->boardinfo.vendor == PCI_VENDOR_ID_ASUSTEK) + led->behaviour = B43legacy_LED_ASSOC; + break; + case 2: + led->behaviour = B43legacy_LED_RADIO_A; + break; + case 3: + led->behaviour = B43legacy_LED_OFF; + break; + default: + B43legacy_BUG_ON(1); + } +} + +int b43legacy_leds_init(struct b43legacy_wldev *dev) +{ + struct b43legacy_led *led; + u8 sprom[4]; + int i; + + sprom[0] = dev->dev->bus->sprom.r1.gpio0; + sprom[1] = dev->dev->bus->sprom.r1.gpio1; + sprom[2] = dev->dev->bus->sprom.r1.gpio2; + sprom[3] = dev->dev->bus->sprom.r1.gpio3; + + for (i = 0; i < B43legacy_NR_LEDS; i++) { + led = &(dev->leds[i]); + led->index = i; + led->dev = dev; + setup_timer(&led->blink_timer, + b43legacy_led_blink, + (unsigned long)led); + + if (sprom[i] == 0xFF) + b43legacy_led_init_hardcoded(dev, led, i); + else { + led->behaviour = sprom[i] & B43legacy_LED_BEHAVIOUR; + led->activelow = !!(sprom[i] & + B43legacy_LED_ACTIVELOW); + } + } + + return 0; +} + +void b43legacy_leds_exit(struct b43legacy_wldev *dev) +{ + struct b43legacy_led *led; + int i; + + for (i = 0; i < B43legacy_NR_LEDS; i++) { + led = &(dev->leds[i]); + b43legacy_led_blink_stop(led, 1); + } + b43legacy_leds_switch_all(dev, 0); +} + +void b43legacy_leds_update(struct b43legacy_wldev *dev, int activity) +{ + struct b43legacy_led *led; + struct b43legacy_phy *phy = &dev->phy; + const int transferring = (jiffies - dev->stats.last_tx) + < B43legacy_LED_XFER_THRES; + int i; + int turn_on; + unsigned long interval = 0; + u16 ledctl; + unsigned long flags; + + spin_lock_irqsave(&dev->wl->leds_lock, flags); + ledctl = b43legacy_read16(dev, B43legacy_MMIO_GPIO_CONTROL); + for (i = 0; i < B43legacy_NR_LEDS; i++) { + led = &(dev->leds[i]); + + turn_on = 0; + switch (led->behaviour) { + case B43legacy_LED_INACTIVE: + continue; + case B43legacy_LED_OFF: + break; + case B43legacy_LED_ON: + turn_on = 1; + break; + case B43legacy_LED_ACTIVITY: + turn_on = activity; + break; + case B43legacy_LED_RADIO_ALL: + turn_on = phy->radio_on && + b43legacy_is_hw_radio_enabled(dev); + break; + case B43legacy_LED_RADIO_A: + break; + case B43legacy_LED_RADIO_B: + turn_on = (phy->radio_on && + b43legacy_is_hw_radio_enabled(dev) && + (phy->type == B43legacy_PHYTYPE_B || + phy->type == B43legacy_PHYTYPE_G)); + break; + case B43legacy_LED_MODE_BG: + if (phy->type == B43legacy_PHYTYPE_G && + b43legacy_is_hw_radio_enabled(dev)) + turn_on = 1; + break; + case B43legacy_LED_TRANSFER: + if (transferring) + b43legacy_led_blink_start(led, + B43legacy_LEDBLINK_MEDIUM); + else + b43legacy_led_blink_stop(led, 0); + continue; + case B43legacy_LED_APTRANSFER: + if (b43legacy_is_mode(dev->wl, + IEEE80211_IF_TYPE_AP)) { + if (transferring) { + interval = B43legacy_LEDBLINK_FAST; + turn_on = 1; + } + } else { + turn_on = 1; + if (transferring) + interval = B43legacy_LEDBLINK_FAST; + else + turn_on = 0; + } + if (turn_on) + b43legacy_led_blink_start(led, interval); + else + b43legacy_led_blink_stop(led, 0); + continue; + case B43legacy_LED_WEIRD: + break; + case B43legacy_LED_ASSOC: + turn_on = 1; +#ifdef CONFIG_B43LEGACY_DEBUG + case B43legacy_LED_TEST_BLINKSLOW: + b43legacy_led_blink_start(led, B43legacy_LEDBLINK_SLOW); + continue; + case B43legacy_LED_TEST_BLINKMEDIUM: + b43legacy_led_blink_start(led, + B43legacy_LEDBLINK_MEDIUM); + continue; + case B43legacy_LED_TEST_BLINKFAST: + b43legacy_led_blink_start(led, B43legacy_LEDBLINK_FAST); + continue; +#endif /* CONFIG_B43LEGACY_DEBUG */ + default: + B43legacy_BUG_ON(1); + }; + + if (led->activelow) + turn_on = !turn_on; + if (turn_on) + ledctl |= (1 << i); + else + ledctl &= ~(1 << i); + } + b43legacy_write16(dev, B43legacy_MMIO_GPIO_CONTROL, ledctl); + spin_unlock_irqrestore(&dev->wl->leds_lock, flags); +} + +void b43legacy_leds_switch_all(struct b43legacy_wldev *dev, int on) +{ + struct b43legacy_led *led; + u16 ledctl; + int i; + int bit_on; + unsigned long flags; + + spin_lock_irqsave(&dev->wl->leds_lock, flags); + ledctl = b43legacy_read16(dev, B43legacy_MMIO_GPIO_CONTROL); + for (i = 0; i < B43legacy_NR_LEDS; i++) { + led = &(dev->leds[i]); + if (led->behaviour == B43legacy_LED_INACTIVE) + continue; + if (on) + bit_on = led->activelow ? 0 : 1; + else + bit_on = led->activelow ? 1 : 0; + if (bit_on) + ledctl |= (1 << i); + else + ledctl &= ~(1 << i); + } + b43legacy_write16(dev, B43legacy_MMIO_GPIO_CONTROL, ledctl); + spin_unlock_irqrestore(&dev->wl->leds_lock, flags); +} diff --git a/drivers/net/wireless/b43legacy/leds.h b/drivers/net/wireless/b43legacy/leds.h new file mode 100644 index 00000000000..b989f503e68 --- /dev/null +++ b/drivers/net/wireless/b43legacy/leds.h @@ -0,0 +1,56 @@ +#ifndef B43legacy_LEDS_H_ +#define B43legacy_LEDS_H_ + +#include +#include + + +struct b43legacy_led { + u8 behaviour; + bool activelow; + /* Index in the "leds" array in b43legacy_wldev */ + u8 index; + struct b43legacy_wldev *dev; + struct timer_list blink_timer; + unsigned long blink_interval; +}; + +/* Delay between state changes when blinking in jiffies */ +#define B43legacy_LEDBLINK_SLOW (HZ / 1) +#define B43legacy_LEDBLINK_MEDIUM (HZ / 4) +#define B43legacy_LEDBLINK_FAST (HZ / 8) + +#define B43legacy_LED_XFER_THRES (HZ / 100) + +#define B43legacy_LED_BEHAVIOUR 0x7F +#define B43legacy_LED_ACTIVELOW 0x80 +enum { /* LED behaviour values */ + B43legacy_LED_OFF, + B43legacy_LED_ON, + B43legacy_LED_ACTIVITY, + B43legacy_LED_RADIO_ALL, + B43legacy_LED_RADIO_A, + B43legacy_LED_RADIO_B, + B43legacy_LED_MODE_BG, + B43legacy_LED_TRANSFER, + B43legacy_LED_APTRANSFER, + B43legacy_LED_WEIRD, + B43legacy_LED_ASSOC, + B43legacy_LED_INACTIVE, + + /* Behaviour values for testing. + * With these values it is easier to figure out + * the real behaviour of leds, in case the SPROM + * is missing information. + */ + B43legacy_LED_TEST_BLINKSLOW, + B43legacy_LED_TEST_BLINKMEDIUM, + B43legacy_LED_TEST_BLINKFAST, +}; + +int b43legacy_leds_init(struct b43legacy_wldev *dev); +void b43legacy_leds_exit(struct b43legacy_wldev *dev); +void b43legacy_leds_update(struct b43legacy_wldev *dev, int activity); +void b43legacy_leds_switch_all(struct b43legacy_wldev *dev, int on); + +#endif /* B43legacy_LEDS_H_ */ diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c new file mode 100644 index 00000000000..ac4831adb57 --- /dev/null +++ b/drivers/net/wireless/b43legacy/main.c @@ -0,0 +1,3805 @@ +/* + * + * Broadcom B43legacy wireless driver + * + * Copyright (c) 2005 Martin Langer + * Copyright (c) 2005 Stefano Brivio + * Copyright (c) 2005, 2006 Michael Buesch + * Copyright (c) 2005 Danny van Dyk + * Copyright (c) 2005 Andreas Jaggi + * Copyright (c) 2007 Larry Finger + * + * Some parts of the code in this file are derived from the ipw2200 + * driver Copyright(c) 2003 - 2004 Intel Corporation. + + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "b43legacy.h" +#include "main.h" +#include "debugfs.h" +#include "phy.h" +#include "dma.h" +#include "pio.h" +#include "sysfs.h" +#include "xmit.h" +#include "radio.h" + + +MODULE_DESCRIPTION("Broadcom B43legacy wireless driver"); +MODULE_AUTHOR("Martin Langer"); +MODULE_AUTHOR("Stefano Brivio"); +MODULE_AUTHOR("Michael Buesch"); +MODULE_LICENSE("GPL"); + +#if defined(CONFIG_B43LEGACY_DMA) && defined(CONFIG_B43LEGACY_PIO) +static int modparam_pio; +module_param_named(pio, modparam_pio, int, 0444); +MODULE_PARM_DESC(pio, "enable(1) / disable(0) PIO mode"); +#elif defined(CONFIG_B43LEGACY_DMA) +# define modparam_pio 0 +#elif defined(CONFIG_B43LEGACY_PIO) +# define modparam_pio 1 +#endif + +static int modparam_bad_frames_preempt; +module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444); +MODULE_PARM_DESC(bad_frames_preempt, "enable(1) / disable(0) Bad Frames" + " Preemption"); + +static int modparam_short_retry = B43legacy_DEFAULT_SHORT_RETRY_LIMIT; +module_param_named(short_retry, modparam_short_retry, int, 0444); +MODULE_PARM_DESC(short_retry, "Short-Retry-Limit (0 - 15)"); + +static int modparam_long_retry = B43legacy_DEFAULT_LONG_RETRY_LIMIT; +module_param_named(long_retry, modparam_long_retry, int, 0444); +MODULE_PARM_DESC(long_retry, "Long-Retry-Limit (0 - 15)"); + +static int modparam_noleds; +module_param_named(noleds, modparam_noleds, int, 0444); +MODULE_PARM_DESC(noleds, "Turn off all LED activity"); + +static char modparam_fwpostfix[16]; +module_param_string(fwpostfix, modparam_fwpostfix, 16, 0444); +MODULE_PARM_DESC(fwpostfix, "Postfix for the firmware files to load."); + +static int modparam_mon_keep_bad; +module_param_named(mon_keep_bad, modparam_mon_keep_bad, int, 0444); +MODULE_PARM_DESC(mon_keep_bad, "Keep bad frames in monitor mode"); + +static int modparam_mon_keep_badplcp; +module_param_named(mon_keep_badplcp, modparam_mon_keep_bad, int, 0444); +MODULE_PARM_DESC(mon_keep_badplcp, "Keep frames with bad PLCP in monitor mode"); + +/* The following table supports BCM4301, BCM4303 and BCM4306/2 devices. */ +static const struct ssb_device_id b43legacy_ssb_tbl[] = { + SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 2), + SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 4), + SSB_DEVTABLE_END +}; +MODULE_DEVICE_TABLE(ssb, b43legacy_ssb_tbl); + + +/* Channel and ratetables are shared for all devices. + * They can't be const, because ieee80211 puts some precalculated + * data in there. This data is the same for all devices, so we don't + * get concurrency issues */ +#define RATETAB_ENT(_rateid, _flags) \ + { \ + .rate = B43legacy_RATE_TO_100KBPS(_rateid), \ + .val = (_rateid), \ + .val2 = (_rateid), \ + .flags = (_flags), \ + } +static struct ieee80211_rate __b43legacy_ratetable[] = { + RATETAB_ENT(B43legacy_CCK_RATE_1MB, IEEE80211_RATE_CCK), + RATETAB_ENT(B43legacy_CCK_RATE_2MB, IEEE80211_RATE_CCK_2), + RATETAB_ENT(B43legacy_CCK_RATE_5MB, IEEE80211_RATE_CCK_2), + RATETAB_ENT(B43legacy_CCK_RATE_11MB, IEEE80211_RATE_CCK_2), + RATETAB_ENT(B43legacy_OFDM_RATE_6MB, IEEE80211_RATE_OFDM), + RATETAB_ENT(B43legacy_OFDM_RATE_9MB, IEEE80211_RATE_OFDM), + RATETAB_ENT(B43legacy_OFDM_RATE_12MB, IEEE80211_RATE_OFDM), + RATETAB_ENT(B43legacy_OFDM_RATE_18MB, IEEE80211_RATE_OFDM), + RATETAB_ENT(B43legacy_OFDM_RATE_24MB, IEEE80211_RATE_OFDM), + RATETAB_ENT(B43legacy_OFDM_RATE_36MB, IEEE80211_RATE_OFDM), + RATETAB_ENT(B43legacy_OFDM_RATE_48MB, IEEE80211_RATE_OFDM), + RATETAB_ENT(B43legacy_OFDM_RATE_54MB, IEEE80211_RATE_OFDM), +}; +#define b43legacy_a_ratetable (__b43legacy_ratetable + 4) +#define b43legacy_a_ratetable_size 8 +#define b43legacy_b_ratetable (__b43legacy_ratetable + 0) +#define b43legacy_b_ratetable_size 4 +#define b43legacy_g_ratetable (__b43legacy_ratetable + 0) +#define b43legacy_g_ratetable_size 12 + +#define CHANTAB_ENT(_chanid, _freq) \ + { \ + .chan = (_chanid), \ + .freq = (_freq), \ + .val = (_chanid), \ + .flag = IEEE80211_CHAN_W_SCAN | \ + IEEE80211_CHAN_W_ACTIVE_SCAN | \ + IEEE80211_CHAN_W_IBSS, \ + .power_level = 0x0A, \ + .antenna_max = 0xFF, \ + } +static struct ieee80211_channel b43legacy_bg_chantable[] = { + CHANTAB_ENT(1, 2412), + CHANTAB_ENT(2, 2417), + CHANTAB_ENT(3, 2422), + CHANTAB_ENT(4, 2427), + CHANTAB_ENT(5, 2432), + CHANTAB_ENT(6, 2437), + CHANTAB_ENT(7, 2442), + CHANTAB_ENT(8, 2447), + CHANTAB_ENT(9, 2452), + CHANTAB_ENT(10, 2457), + CHANTAB_ENT(11, 2462), + CHANTAB_ENT(12, 2467), + CHANTAB_ENT(13, 2472), + CHANTAB_ENT(14, 2484), +}; +#define b43legacy_bg_chantable_size ARRAY_SIZE(b43legacy_bg_chantable) + +static void b43legacy_wireless_core_exit(struct b43legacy_wldev *dev); +static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev); +static void b43legacy_wireless_core_stop(struct b43legacy_wldev *dev); +static int b43legacy_wireless_core_start(struct b43legacy_wldev *dev); + + +static int b43legacy_ratelimit(struct b43legacy_wl *wl) +{ + if (!wl || !wl->current_dev) + return 1; + if (b43legacy_status(wl->current_dev) < B43legacy_STAT_STARTED) + return 1; + /* We are up and running. + * Ratelimit the messages to avoid DoS over the net. */ + return net_ratelimit(); +} + +void b43legacyinfo(struct b43legacy_wl *wl, const char *fmt, ...) +{ + va_list args; + + if (!b43legacy_ratelimit(wl)) + return; + va_start(args, fmt); + printk(KERN_INFO "b43legacy-%s: ", + (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan"); + vprintk(fmt, args); + va_end(args); +} + +void b43legacyerr(struct b43legacy_wl *wl, const char *fmt, ...) +{ + va_list args; + + if (!b43legacy_ratelimit(wl)) + return; + va_start(args, fmt); + printk(KERN_ERR "b43legacy-%s ERROR: ", + (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan"); + vprintk(fmt, args); + va_end(args); +} + +void b43legacywarn(struct b43legacy_wl *wl, const char *fmt, ...) +{ + va_list args; + + if (!b43legacy_ratelimit(wl)) + return; + va_start(args, fmt); + printk(KERN_WARNING "b43legacy-%s warning: ", + (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan"); + vprintk(fmt, args); + va_end(args); +} + +#if B43legacy_DEBUG +void b43legacydbg(struct b43legacy_wl *wl, const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + printk(KERN_DEBUG "b43legacy-%s debug: ", + (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan"); + vprintk(fmt, args); + va_end(args); +} +#endif /* DEBUG */ + +static void b43legacy_ram_write(struct b43legacy_wldev *dev, u16 offset, + u32 val) +{ + u32 status; + + B43legacy_WARN_ON(offset % 4 != 0); + + status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD); + if (status & B43legacy_SBF_XFER_REG_BYTESWAP) + val = swab32(val); + + b43legacy_write32(dev, B43legacy_MMIO_RAM_CONTROL, offset); + mmiowb(); + b43legacy_write32(dev, B43legacy_MMIO_RAM_DATA, val); +} + +static inline +void b43legacy_shm_control_word(struct b43legacy_wldev *dev, + u16 routing, u16 offset) +{ + u32 control; + + /* "offset" is the WORD offset. */ + + control = routing; + control <<= 16; + control |= offset; + b43legacy_write32(dev, B43legacy_MMIO_SHM_CONTROL, control); +} + +u32 b43legacy_shm_read32(struct b43legacy_wldev *dev, + u16 routing, u16 offset) +{ + u32 ret; + + if (routing == B43legacy_SHM_SHARED) { + B43legacy_WARN_ON((offset & 0x0001) != 0); + if (offset & 0x0003) { + /* Unaligned access */ + b43legacy_shm_control_word(dev, routing, offset >> 2); + ret = b43legacy_read16(dev, + B43legacy_MMIO_SHM_DATA_UNALIGNED); + ret <<= 16; + b43legacy_shm_control_word(dev, routing, + (offset >> 2) + 1); + ret |= b43legacy_read16(dev, B43legacy_MMIO_SHM_DATA); + + return ret; + } + offset >>= 2; + } + b43legacy_shm_control_word(dev, routing, offset); + ret = b43legacy_read32(dev, B43legacy_MMIO_SHM_DATA); + + return ret; +} + +u16 b43legacy_shm_read16(struct b43legacy_wldev *dev, + u16 routing, u16 offset) +{ + u16 ret; + + if (routing == B43legacy_SHM_SHARED) { + B43legacy_WARN_ON((offset & 0x0001) != 0); + if (offset & 0x0003) { + /* Unaligned access */ + b43legacy_shm_control_word(dev, routing, offset >> 2); + ret = b43legacy_read16(dev, + B43legacy_MMIO_SHM_DATA_UNALIGNED); + + return ret; + } + offset >>= 2; + } + b43legacy_shm_control_word(dev, routing, offset); + ret = b43legacy_read16(dev, B43legacy_MMIO_SHM_DATA); + + return ret; +} + +void b43legacy_shm_write32(struct b43legacy_wldev *dev, + u16 routing, u16 offset, + u32 value) +{ + if (routing == B43legacy_SHM_SHARED) { + B43legacy_WARN_ON((offset & 0x0001) != 0); + if (offset & 0x0003) { + /* Unaligned access */ + b43legacy_shm_control_word(dev, routing, offset >> 2); + mmiowb(); + b43legacy_write16(dev, + B43legacy_MMIO_SHM_DATA_UNALIGNED, + (value >> 16) & 0xffff); + mmiowb(); + b43legacy_shm_control_word(dev, routing, + (offset >> 2) + 1); + mmiowb(); + b43legacy_write16(dev, B43legacy_MMIO_SHM_DATA, + value & 0xffff); + return; + } + offset >>= 2; + } + b43legacy_shm_control_word(dev, routing, offset); + mmiowb(); + b43legacy_write32(dev, B43legacy_MMIO_SHM_DATA, value); +} + +void b43legacy_shm_write16(struct b43legacy_wldev *dev, u16 routing, u16 offset, + u16 value) +{ + if (routing == B43legacy_SHM_SHARED) { + B43legacy_WARN_ON((offset & 0x0001) != 0); + if (offset & 0x0003) { + /* Unaligned access */ + b43legacy_shm_control_word(dev, routing, offset >> 2); + mmiowb(); + b43legacy_write16(dev, + B43legacy_MMIO_SHM_DATA_UNALIGNED, + value); + return; + } + offset >>= 2; + } + b43legacy_shm_control_word(dev, routing, offset); + mmiowb(); + b43legacy_write16(dev, B43legacy_MMIO_SHM_DATA, value); +} + +/* Read HostFlags */ +u32 b43legacy_hf_read(struct b43legacy_wldev *dev) +{ + u32 ret; + + ret = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, + B43legacy_SHM_SH_HOSTFHI); + ret <<= 16; + ret |= b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, + B43legacy_SHM_SH_HOSTFLO); + + return ret; +} + +/* Write HostFlags */ +void b43legacy_hf_write(struct b43legacy_wldev *dev, u32 value) +{ + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, + B43legacy_SHM_SH_HOSTFLO, + (value & 0x0000FFFF)); + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, + B43legacy_SHM_SH_HOSTFHI, + ((value & 0xFFFF0000) >> 16)); +} + +void b43legacy_tsf_read(struct b43legacy_wldev *dev, u64 *tsf) +{ + /* We need to be careful. As we read the TSF from multiple + * registers, we should take care of register overflows. + * In theory, the whole tsf read process should be atomic. + * We try to be atomic here, by restaring the read process, + * if any of the high registers changed (overflew). + */ + if (dev->dev->id.revision >= 3) { + u32 low; + u32 high; + u32 high2; + + do { + high = b43legacy_read32(dev, + B43legacy_MMIO_REV3PLUS_TSF_HIGH); + low = b43legacy_read32(dev, + B43legacy_MMIO_REV3PLUS_TSF_LOW); + high2 = b43legacy_read32(dev, + B43legacy_MMIO_REV3PLUS_TSF_HIGH); + } while (unlikely(high != high2)); + + *tsf = high; + *tsf <<= 32; + *tsf |= low; + } else { + u64 tmp; + u16 v0; + u16 v1; + u16 v2; + u16 v3; + u16 test1; + u16 test2; + u16 test3; + + do { + v3 = b43legacy_read16(dev, B43legacy_MMIO_TSF_3); + v2 = b43legacy_read16(dev, B43legacy_MMIO_TSF_2); + v1 = b43legacy_read16(dev, B43legacy_MMIO_TSF_1); + v0 = b43legacy_read16(dev, B43legacy_MMIO_TSF_0); + + test3 = b43legacy_read16(dev, B43legacy_MMIO_TSF_3); + test2 = b43legacy_read16(dev, B43legacy_MMIO_TSF_2); + test1 = b43legacy_read16(dev, B43legacy_MMIO_TSF_1); + } while (v3 != test3 || v2 != test2 || v1 != test1); + + *tsf = v3; + *tsf <<= 48; + tmp = v2; + tmp <<= 32; + *tsf |= tmp; + tmp = v1; + tmp <<= 16; + *tsf |= tmp; + *tsf |= v0; + } +} + +static void b43legacy_time_lock(struct b43legacy_wldev *dev) +{ + u32 status; + + status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD); + status |= B43legacy_SBF_TIME_UPDATE; + b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status); + mmiowb(); +} + +static void b43legacy_time_unlock(struct b43legacy_wldev *dev) +{ + u32 status; + + status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD); + status &= ~B43legacy_SBF_TIME_UPDATE; + b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status); +} + +static void b43legacy_tsf_write_locked(struct b43legacy_wldev *dev, u64 tsf) +{ + /* Be careful with the in-progress timer. + * First zero out the low register, so we have a full + * register-overflow duration to complete the operation. + */ + if (dev->dev->id.revision >= 3) { + u32 lo = (tsf & 0x00000000FFFFFFFFULL); + u32 hi = (tsf & 0xFFFFFFFF00000000ULL) >> 32; + + b43legacy_write32(dev, B43legacy_MMIO_REV3PLUS_TSF_LOW, 0); + mmiowb(); + b43legacy_write32(dev, B43legacy_MMIO_REV3PLUS_TSF_HIGH, + hi); + mmiowb(); + b43legacy_write32(dev, B43legacy_MMIO_REV3PLUS_TSF_LOW, + lo); + } else { + u16 v0 = (tsf & 0x000000000000FFFFULL); + u16 v1 = (tsf & 0x00000000FFFF0000ULL) >> 16; + u16 v2 = (tsf & 0x0000FFFF00000000ULL) >> 32; + u16 v3 = (tsf & 0xFFFF000000000000ULL) >> 48; + + b43legacy_write16(dev, B43legacy_MMIO_TSF_0, 0); + mmiowb(); + b43legacy_write16(dev, B43legacy_MMIO_TSF_3, v3); + mmiowb(); + b43legacy_write16(dev, B43legacy_MMIO_TSF_2, v2); + mmiowb(); + b43legacy_write16(dev, B43legacy_MMIO_TSF_1, v1); + mmiowb(); + b43legacy_write16(dev, B43legacy_MMIO_TSF_0, v0); + } +} + +void b43legacy_tsf_write(struct b43legacy_wldev *dev, u64 tsf) +{ + b43legacy_time_lock(dev); + b43legacy_tsf_write_locked(dev, tsf); + b43legacy_time_unlock(dev); +} + +static +void b43legacy_macfilter_set(struct b43legacy_wldev *dev, + u16 offset, const u8 *mac) +{ + static const u8 zero_addr[ETH_ALEN] = { 0 }; + u16 data; + + if (!mac) + mac = zero_addr; + + offset |= 0x0020; + b43legacy_write16(dev, B43legacy_MMIO_MACFILTER_CONTROL, offset); + + data = mac[0]; + data |= mac[1] << 8; + b43legacy_write16(dev, B43legacy_MMIO_MACFILTER_DATA, data); + data = mac[2]; + data |= mac[3] << 8; + b43legacy_write16(dev, B43legacy_MMIO_MACFILTER_DATA, data); + data = mac[4]; + data |= mac[5] << 8; + b43legacy_write16(dev, B43legacy_MMIO_MACFILTER_DATA, data); +} + +static void b43legacy_write_mac_bssid_templates(struct b43legacy_wldev *dev) +{ + static const u8 zero_addr[ETH_ALEN] = { 0 }; + const u8 *mac = dev->wl->mac_addr; + const u8 *bssid = dev->wl->bssid; + u8 mac_bssid[ETH_ALEN * 2]; + int i; + u32 tmp; + + if (!bssid) + bssid = zero_addr; + if (!mac) + mac = zero_addr; + + b43legacy_macfilter_set(dev, B43legacy_MACFILTER_BSSID, bssid); + + memcpy(mac_bssid, mac, ETH_ALEN); + memcpy(mac_bssid + ETH_ALEN, bssid, ETH_ALEN); + + /* Write our MAC address and BSSID to template ram */ + for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32)) { + tmp = (u32)(mac_bssid[i + 0]); + tmp |= (u32)(mac_bssid[i + 1]) << 8; + tmp |= (u32)(mac_bssid[i + 2]) << 16; + tmp |= (u32)(mac_bssid[i + 3]) << 24; + b43legacy_ram_write(dev, 0x20 + i, tmp); + b43legacy_ram_write(dev, 0x78 + i, tmp); + b43legacy_ram_write(dev, 0x478 + i, tmp); + } +} + +static void b43legacy_upload_card_macaddress(struct b43legacy_wldev *dev, + const u8 *mac_addr) +{ + dev->wl->mac_addr = mac_addr; + b43legacy_write_mac_bssid_templates(dev); + b43legacy_macfilter_set(dev, B43legacy_MACFILTER_SELF, mac_addr); +} + +static void b43legacy_set_slot_time(struct b43legacy_wldev *dev, + u16 slot_time) +{ + /* slot_time is in usec. */ + if (dev->phy.type != B43legacy_PHYTYPE_G) + return; + b43legacy_write16(dev, 0x684, 510 + slot_time); + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0010, + slot_time); +} + +static void b43legacy_short_slot_timing_enable(struct b43legacy_wldev *dev) +{ + b43legacy_set_slot_time(dev, 9); + dev->short_slot = 1; +} + +static void b43legacy_short_slot_timing_disable(struct b43legacy_wldev *dev) +{ + b43legacy_set_slot_time(dev, 20); + dev->short_slot = 0; +} + +/* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable. + * Returns the _previously_ enabled IRQ mask. + */ +static inline u32 b43legacy_interrupt_enable(struct b43legacy_wldev *dev, + u32 mask) +{ + u32 old_mask; + + old_mask = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK); + b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, old_mask | + mask); + + return old_mask; +} + +/* Disable a Generic IRQ. "mask" is the mask of which IRQs to disable. + * Returns the _previously_ enabled IRQ mask. + */ +static inline u32 b43legacy_interrupt_disable(struct b43legacy_wldev *dev, + u32 mask) +{ + u32 old_mask; + + old_mask = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK); + b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, old_mask & ~mask); + + return old_mask; +} + +/* Synchronize IRQ top- and bottom-half. + * IRQs must be masked before calling this. + * This must not be called with the irq_lock held. + */ +static void b43legacy_synchronize_irq(struct b43legacy_wldev *dev) +{ + synchronize_irq(dev->dev->irq); + tasklet_kill(&dev->isr_tasklet); +} + +/* DummyTransmission function, as documented on + * http://bcm-specs.sipsolutions.net/DummyTransmission + */ +void b43legacy_dummy_transmission(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + unsigned int i; + unsigned int max_loop; + u16 value; + u32 buffer[5] = { + 0x00000000, + 0x00D40000, + 0x00000000, + 0x01000000, + 0x00000000, + }; + + switch (phy->type) { + case B43legacy_PHYTYPE_B: + case B43legacy_PHYTYPE_G: + max_loop = 0xFA; + buffer[0] = 0x000B846E; + break; + default: + B43legacy_BUG_ON(1); + return; + } + + for (i = 0; i < 5; i++) + b43legacy_ram_write(dev, i * 4, buffer[i]); + + /* dummy read follows */ + b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD); + + b43legacy_write16(dev, 0x0568, 0x0000); + b43legacy_write16(dev, 0x07C0, 0x0000); + b43legacy_write16(dev, 0x050C, 0x0000); + b43legacy_write16(dev, 0x0508, 0x0000); + b43legacy_write16(dev, 0x050A, 0x0000); + b43legacy_write16(dev, 0x054C, 0x0000); + b43legacy_write16(dev, 0x056A, 0x0014); + b43legacy_write16(dev, 0x0568, 0x0826); + b43legacy_write16(dev, 0x0500, 0x0000); + b43legacy_write16(dev, 0x0502, 0x0030); + + if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5) + b43legacy_radio_write16(dev, 0x0051, 0x0017); + for (i = 0x00; i < max_loop; i++) { + value = b43legacy_read16(dev, 0x050E); + if (value & 0x0080) + break; + udelay(10); + } + for (i = 0x00; i < 0x0A; i++) { + value = b43legacy_read16(dev, 0x050E); + if (value & 0x0400) + break; + udelay(10); + } + for (i = 0x00; i < 0x0A; i++) { + value = b43legacy_read16(dev, 0x0690); + if (!(value & 0x0100)) + break; + udelay(10); + } + if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5) + b43legacy_radio_write16(dev, 0x0051, 0x0037); +} + +/* Turn the Analog ON/OFF */ +static void b43legacy_switch_analog(struct b43legacy_wldev *dev, int on) +{ + b43legacy_write16(dev, B43legacy_MMIO_PHY0, on ? 0 : 0xF4); +} + +void b43legacy_wireless_core_reset(struct b43legacy_wldev *dev, u32 flags) +{ + u32 tmslow; + u32 macctl; + + flags |= B43legacy_TMSLOW_PHYCLKEN; + flags |= B43legacy_TMSLOW_PHYRESET; + ssb_device_enable(dev->dev, flags); + msleep(2); /* Wait for the PLL to turn on. */ + + /* Now take the PHY out of Reset again */ + tmslow = ssb_read32(dev->dev, SSB_TMSLOW); + tmslow |= SSB_TMSLOW_FGC; + tmslow &= ~B43legacy_TMSLOW_PHYRESET; + ssb_write32(dev->dev, SSB_TMSLOW, tmslow); + ssb_read32(dev->dev, SSB_TMSLOW); /* flush */ + msleep(1); + tmslow &= ~SSB_TMSLOW_FGC; + ssb_write32(dev->dev, SSB_TMSLOW, tmslow); + ssb_read32(dev->dev, SSB_TMSLOW); /* flush */ + msleep(1); + + /* Turn Analog ON */ + b43legacy_switch_analog(dev, 1); + + macctl = b43legacy_read32(dev, B43legacy_MMIO_MACCTL); + macctl &= ~B43legacy_MACCTL_GMODE; + if (flags & B43legacy_TMSLOW_GMODE) { + macctl |= B43legacy_MACCTL_GMODE; + dev->phy.gmode = 1; + } else + dev->phy.gmode = 0; + macctl |= B43legacy_MACCTL_IHR_ENABLED; + b43legacy_write32(dev, B43legacy_MMIO_MACCTL, macctl); +} + +static void handle_irq_transmit_status(struct b43legacy_wldev *dev) +{ + u32 v0; + u32 v1; + u16 tmp; + struct b43legacy_txstatus stat; + + while (1) { + v0 = b43legacy_read32(dev, B43legacy_MMIO_XMITSTAT_0); + if (!(v0 & 0x00000001)) + break; + v1 = b43legacy_read32(dev, B43legacy_MMIO_XMITSTAT_1); + + stat.cookie = (v0 >> 16); + stat.seq = (v1 & 0x0000FFFF); + stat.phy_stat = ((v1 & 0x00FF0000) >> 16); + tmp = (v0 & 0x0000FFFF); + stat.frame_count = ((tmp & 0xF000) >> 12); + stat.rts_count = ((tmp & 0x0F00) >> 8); + stat.supp_reason = ((tmp & 0x001C) >> 2); + stat.pm_indicated = !!(tmp & 0x0080); + stat.intermediate = !!(tmp & 0x0040); + stat.for_ampdu = !!(tmp & 0x0020); + stat.acked = !!(tmp & 0x0002); + + b43legacy_handle_txstatus(dev, &stat); + } +} + +static void drain_txstatus_queue(struct b43legacy_wldev *dev) +{ + u32 dummy; + + if (dev->dev->id.revision < 5) + return; + /* Read all entries from the microcode TXstatus FIFO + * and throw them away. + */ + while (1) { + dummy = b43legacy_read32(dev, B43legacy_MMIO_XMITSTAT_0); + if (!(dummy & 0x00000001)) + break; + dummy = b43legacy_read32(dev, B43legacy_MMIO_XMITSTAT_1); + } +} + +static u32 b43legacy_jssi_read(struct b43legacy_wldev *dev) +{ + u32 val = 0; + + val = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x40A); + val <<= 16; + val |= b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x408); + + return val; +} + +static void b43legacy_jssi_write(struct b43legacy_wldev *dev, u32 jssi) +{ + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x408, + (jssi & 0x0000FFFF)); + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x40A, + (jssi & 0xFFFF0000) >> 16); +} + +static void b43legacy_generate_noise_sample(struct b43legacy_wldev *dev) +{ + b43legacy_jssi_write(dev, 0x7F7F7F7F); + b43legacy_write32(dev, B43legacy_MMIO_STATUS2_BITFIELD, + b43legacy_read32(dev, + B43legacy_MMIO_STATUS2_BITFIELD) + | (1 << 4)); + B43legacy_WARN_ON(dev->noisecalc.channel_at_start != + dev->phy.channel); +} + +static void b43legacy_calculate_link_quality(struct b43legacy_wldev *dev) +{ + /* Top half of Link Quality calculation. */ + + if (dev->noisecalc.calculation_running) + return; + dev->noisecalc.channel_at_start = dev->phy.channel; + dev->noisecalc.calculation_running = 1; + dev->noisecalc.nr_samples = 0; + + b43legacy_generate_noise_sample(dev); +} + +static void handle_irq_noise(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 tmp; + u8 noise[4]; + u8 i; + u8 j; + s32 average; + + /* Bottom half of Link Quality calculation. */ + + B43legacy_WARN_ON(!dev->noisecalc.calculation_running); + if (dev->noisecalc.channel_at_start != phy->channel) + goto drop_calculation; + *((__le32 *)noise) = cpu_to_le32(b43legacy_jssi_read(dev)); + if (noise[0] == 0x7F || noise[1] == 0x7F || + noise[2] == 0x7F || noise[3] == 0x7F) + goto generate_new; + + /* Get the noise samples. */ + B43legacy_WARN_ON(dev->noisecalc.nr_samples >= 8); + i = dev->noisecalc.nr_samples; + noise[0] = limit_value(noise[0], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); + noise[1] = limit_value(noise[1], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); + noise[2] = limit_value(noise[2], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); + noise[3] = limit_value(noise[3], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); + dev->noisecalc.samples[i][0] = phy->nrssi_lt[noise[0]]; + dev->noisecalc.samples[i][1] = phy->nrssi_lt[noise[1]]; + dev->noisecalc.samples[i][2] = phy->nrssi_lt[noise[2]]; + dev->noisecalc.samples[i][3] = phy->nrssi_lt[noise[3]]; + dev->noisecalc.nr_samples++; + if (dev->noisecalc.nr_samples == 8) { + /* Calculate the Link Quality by the noise samples. */ + average = 0; + for (i = 0; i < 8; i++) { + for (j = 0; j < 4; j++) + average += dev->noisecalc.samples[i][j]; + } + average /= (8 * 4); + average *= 125; + average += 64; + average /= 128; + tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, + 0x40C); + tmp = (tmp / 128) & 0x1F; + if (tmp >= 8) + average += 2; + else + average -= 25; + if (tmp == 8) + average -= 72; + else + average -= 48; + + dev->stats.link_noise = average; +drop_calculation: + dev->noisecalc.calculation_running = 0; + return; + } +generate_new: + b43legacy_generate_noise_sample(dev); +} + +static void handle_irq_tbtt_indication(struct b43legacy_wldev *dev) +{ + if (b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) { + /* TODO: PS TBTT */ + } else { + if (1/*FIXME: the last PSpoll frame was sent successfully */) + b43legacy_power_saving_ctl_bits(dev, -1, -1); + } + dev->reg124_set_0x4 = 0; + if (b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS)) + dev->reg124_set_0x4 = 1; +} + +static void handle_irq_atim_end(struct b43legacy_wldev *dev) +{ + if (!dev->reg124_set_0x4) /*FIXME rename this variable*/ + return; + b43legacy_write32(dev, B43legacy_MMIO_STATUS2_BITFIELD, + b43legacy_read32(dev, B43legacy_MMIO_STATUS2_BITFIELD) + | 0x4); +} + +static void handle_irq_pmq(struct b43legacy_wldev *dev) +{ + u32 tmp; + + /* TODO: AP mode. */ + + while (1) { + tmp = b43legacy_read32(dev, B43legacy_MMIO_PS_STATUS); + if (!(tmp & 0x00000008)) + break; + } + /* 16bit write is odd, but correct. */ + b43legacy_write16(dev, B43legacy_MMIO_PS_STATUS, 0x0002); +} + +static void b43legacy_write_template_common(struct b43legacy_wldev *dev, + const u8 *data, u16 size, + u16 ram_offset, + u16 shm_size_offset, u8 rate) +{ + u32 i; + u32 tmp; + struct b43legacy_plcp_hdr4 plcp; + + plcp.data = 0; + b43legacy_generate_plcp_hdr(&plcp, size + FCS_LEN, rate); + b43legacy_ram_write(dev, ram_offset, le32_to_cpu(plcp.data)); + ram_offset += sizeof(u32); + /* The PLCP is 6 bytes long, but we only wrote 4 bytes, yet. + * So leave the first two bytes of the next write blank. + */ + tmp = (u32)(data[0]) << 16; + tmp |= (u32)(data[1]) << 24; + b43legacy_ram_write(dev, ram_offset, tmp); + ram_offset += sizeof(u32); + for (i = 2; i < size; i += sizeof(u32)) { + tmp = (u32)(data[i + 0]); + if (i + 1 < size) + tmp |= (u32)(data[i + 1]) << 8; + if (i + 2 < size) + tmp |= (u32)(data[i + 2]) << 16; + if (i + 3 < size) + tmp |= (u32)(data[i + 3]) << 24; + b43legacy_ram_write(dev, ram_offset + i - 2, tmp); + } + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, shm_size_offset, + size + sizeof(struct b43legacy_plcp_hdr6)); +} + +static void b43legacy_write_beacon_template(struct b43legacy_wldev *dev, + u16 ram_offset, + u16 shm_size_offset, u8 rate) +{ + int len; + const u8 *data; + + B43legacy_WARN_ON(!dev->cached_beacon); + len = min((size_t)dev->cached_beacon->len, + 0x200 - sizeof(struct b43legacy_plcp_hdr6)); + data = (const u8 *)(dev->cached_beacon->data); + b43legacy_write_template_common(dev, data, + len, ram_offset, + shm_size_offset, rate); +} + +static void b43legacy_write_probe_resp_plcp(struct b43legacy_wldev *dev, + u16 shm_offset, u16 size, + u8 rate) +{ + struct b43legacy_plcp_hdr4 plcp; + u32 tmp; + __le16 dur; + + plcp.data = 0; + b43legacy_generate_plcp_hdr(&plcp, size + FCS_LEN, rate); + dur = ieee80211_generic_frame_duration(dev->wl->hw, + dev->wl->if_id, + size, + B43legacy_RATE_TO_100KBPS(rate)); + /* Write PLCP in two parts and timing for packet transfer */ + tmp = le32_to_cpu(plcp.data); + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, shm_offset, + tmp & 0xFFFF); + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, shm_offset + 2, + tmp >> 16); + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, shm_offset + 6, + le16_to_cpu(dur)); +} + +/* Instead of using custom probe response template, this function + * just patches custom beacon template by: + * 1) Changing packet type + * 2) Patching duration field + * 3) Stripping TIM + */ +static u8 *b43legacy_generate_probe_resp(struct b43legacy_wldev *dev, + u16 *dest_size, u8 rate) +{ + const u8 *src_data; + u8 *dest_data; + u16 src_size; + u16 elem_size; + u16 src_pos; + u16 dest_pos; + __le16 dur; + struct ieee80211_hdr *hdr; + + B43legacy_WARN_ON(!dev->cached_beacon); + src_size = dev->cached_beacon->len; + src_data = (const u8 *)dev->cached_beacon->data; + + if (unlikely(src_size < 0x24)) { + b43legacydbg(dev->wl, "b43legacy_generate_probe_resp: " + "invalid beacon\n"); + return NULL; + } + + dest_data = kmalloc(src_size, GFP_ATOMIC); + if (unlikely(!dest_data)) + return NULL; + + /* 0x24 is offset of first variable-len Information-Element + * in beacon frame. + */ + memcpy(dest_data, src_data, 0x24); + src_pos = 0x24; + dest_pos = 0x24; + for (; src_pos < src_size - 2; src_pos += elem_size) { + elem_size = src_data[src_pos + 1] + 2; + if (src_data[src_pos] != 0x05) { /* TIM */ + memcpy(dest_data + dest_pos, src_data + src_pos, + elem_size); + dest_pos += elem_size; + } + } + *dest_size = dest_pos; + hdr = (struct ieee80211_hdr *)dest_data; + + /* Set the frame control. */ + hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | + IEEE80211_STYPE_PROBE_RESP); + dur = ieee80211_generic_frame_duration(dev->wl->hw, + dev->wl->if_id, + *dest_size, + B43legacy_RATE_TO_100KBPS(rate)); + hdr->duration_id = dur; + + return dest_data; +} + +static void b43legacy_write_probe_resp_template(struct b43legacy_wldev *dev, + u16 ram_offset, + u16 shm_size_offset, u8 rate) +{ + u8 *probe_resp_data; + u16 size; + + B43legacy_WARN_ON(!dev->cached_beacon); + size = dev->cached_beacon->len; + probe_resp_data = b43legacy_generate_probe_resp(dev, &size, rate); + if (unlikely(!probe_resp_data)) + return; + + /* Looks like PLCP headers plus packet timings are stored for + * all possible basic rates + */ + b43legacy_write_probe_resp_plcp(dev, 0x31A, size, + B43legacy_CCK_RATE_1MB); + b43legacy_write_probe_resp_plcp(dev, 0x32C, size, + B43legacy_CCK_RATE_2MB); + b43legacy_write_probe_resp_plcp(dev, 0x33E, size, + B43legacy_CCK_RATE_5MB); + b43legacy_write_probe_resp_plcp(dev, 0x350, size, + B43legacy_CCK_RATE_11MB); + + size = min((size_t)size, + 0x200 - sizeof(struct b43legacy_plcp_hdr6)); + b43legacy_write_template_common(dev, probe_resp_data, + size, ram_offset, + shm_size_offset, rate); + kfree(probe_resp_data); +} + +static int b43legacy_refresh_cached_beacon(struct b43legacy_wldev *dev, + struct sk_buff *beacon) +{ + if (dev->cached_beacon) + kfree_skb(dev->cached_beacon); + dev->cached_beacon = beacon; + + return 0; +} + +static void b43legacy_update_templates(struct b43legacy_wldev *dev) +{ + u32 status; + + B43legacy_WARN_ON(!dev->cached_beacon); + + b43legacy_write_beacon_template(dev, 0x68, 0x18, + B43legacy_CCK_RATE_1MB); + b43legacy_write_beacon_template(dev, 0x468, 0x1A, + B43legacy_CCK_RATE_1MB); + b43legacy_write_probe_resp_template(dev, 0x268, 0x4A, + B43legacy_CCK_RATE_11MB); + + status = b43legacy_read32(dev, B43legacy_MMIO_STATUS2_BITFIELD); + status |= 0x03; + b43legacy_write32(dev, B43legacy_MMIO_STATUS2_BITFIELD, status); +} + +static void b43legacy_refresh_templates(struct b43legacy_wldev *dev, + struct sk_buff *beacon) +{ + int err; + + err = b43legacy_refresh_cached_beacon(dev, beacon); + if (unlikely(err)) + return; + b43legacy_update_templates(dev); +} + +static void b43legacy_set_ssid(struct b43legacy_wldev *dev, + const u8 *ssid, u8 ssid_len) +{ + u32 tmp; + u16 i; + u16 len; + + len = min((u16)ssid_len, (u16)0x100); + for (i = 0; i < len; i += sizeof(u32)) { + tmp = (u32)(ssid[i + 0]); + if (i + 1 < len) + tmp |= (u32)(ssid[i + 1]) << 8; + if (i + 2 < len) + tmp |= (u32)(ssid[i + 2]) << 16; + if (i + 3 < len) + tmp |= (u32)(ssid[i + 3]) << 24; + b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, + 0x380 + i, tmp); + } + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, + 0x48, len); +} + +static void b43legacy_set_beacon_int(struct b43legacy_wldev *dev, + u16 beacon_int) +{ + b43legacy_time_lock(dev); + if (dev->dev->id.revision >= 3) + b43legacy_write32(dev, 0x188, (beacon_int << 16)); + else { + b43legacy_write16(dev, 0x606, (beacon_int >> 6)); + b43legacy_write16(dev, 0x610, beacon_int); + } + b43legacy_time_unlock(dev); +} + +static void handle_irq_beacon(struct b43legacy_wldev *dev) +{ + u32 status; + + if (!b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) + return; + + dev->irq_savedstate &= ~B43legacy_IRQ_BEACON; + status = b43legacy_read32(dev, B43legacy_MMIO_STATUS2_BITFIELD); + + if (!dev->cached_beacon || ((status & 0x1) && (status & 0x2))) { + /* ACK beacon IRQ. */ + b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON, + B43legacy_IRQ_BEACON); + dev->irq_savedstate |= B43legacy_IRQ_BEACON; + if (dev->cached_beacon) + kfree_skb(dev->cached_beacon); + dev->cached_beacon = NULL; + return; + } + if (!(status & 0x1)) { + b43legacy_write_beacon_template(dev, 0x68, 0x18, + B43legacy_CCK_RATE_1MB); + status |= 0x1; + b43legacy_write32(dev, B43legacy_MMIO_STATUS2_BITFIELD, + status); + } + if (!(status & 0x2)) { + b43legacy_write_beacon_template(dev, 0x468, 0x1A, + B43legacy_CCK_RATE_1MB); + status |= 0x2; + b43legacy_write32(dev, B43legacy_MMIO_STATUS2_BITFIELD, + status); + } +} + +static void handle_irq_ucode_debug(struct b43legacy_wldev *dev) +{ +} + +/* Interrupt handler bottom-half */ +static void b43legacy_interrupt_tasklet(struct b43legacy_wldev *dev) +{ + u32 reason; + u32 dma_reason[ARRAY_SIZE(dev->dma_reason)]; + u32 merged_dma_reason = 0; + int i; + int activity = 0; + unsigned long flags; + + spin_lock_irqsave(&dev->wl->irq_lock, flags); + + B43legacy_WARN_ON(b43legacy_status(dev) < + B43legacy_STAT_INITIALIZED); + + reason = dev->irq_reason; + for (i = 0; i < ARRAY_SIZE(dma_reason); i++) { + dma_reason[i] = dev->dma_reason[i]; + merged_dma_reason |= dma_reason[i]; + } + + if (unlikely(reason & B43legacy_IRQ_MAC_TXERR)) + b43legacyerr(dev->wl, "MAC transmission error\n"); + + if (unlikely(reason & B43legacy_IRQ_PHY_TXERR)) + b43legacyerr(dev->wl, "PHY transmission error\n"); + + if (unlikely(merged_dma_reason & (B43legacy_DMAIRQ_FATALMASK | + B43legacy_DMAIRQ_NONFATALMASK))) { + if (merged_dma_reason & B43legacy_DMAIRQ_FATALMASK) { + b43legacyerr(dev->wl, "Fatal DMA error: " + "0x%08X, 0x%08X, 0x%08X, " + "0x%08X, 0x%08X, 0x%08X\n", + dma_reason[0], dma_reason[1], + dma_reason[2], dma_reason[3], + dma_reason[4], dma_reason[5]); + b43legacy_controller_restart(dev, "DMA error"); + mmiowb(); + spin_unlock_irqrestore(&dev->wl->irq_lock, flags); + return; + } + if (merged_dma_reason & B43legacy_DMAIRQ_NONFATALMASK) + b43legacyerr(dev->wl, "DMA error: " + "0x%08X, 0x%08X, 0x%08X, " + "0x%08X, 0x%08X, 0x%08X\n", + dma_reason[0], dma_reason[1], + dma_reason[2], dma_reason[3], + dma_reason[4], dma_reason[5]); + } + + if (unlikely(reason & B43legacy_IRQ_UCODE_DEBUG)) + handle_irq_ucode_debug(dev); + if (reason & B43legacy_IRQ_TBTT_INDI) + handle_irq_tbtt_indication(dev); + if (reason & B43legacy_IRQ_ATIM_END) + handle_irq_atim_end(dev); + if (reason & B43legacy_IRQ_BEACON) + handle_irq_beacon(dev); + if (reason & B43legacy_IRQ_PMQ) + handle_irq_pmq(dev); + if (reason & B43legacy_IRQ_TXFIFO_FLUSH_OK) + ;/*TODO*/ + if (reason & B43legacy_IRQ_NOISESAMPLE_OK) + handle_irq_noise(dev); + + /* Check the DMA reason registers for received data. */ + if (dma_reason[0] & B43legacy_DMAIRQ_RX_DONE) { + if (b43legacy_using_pio(dev)) + b43legacy_pio_rx(dev->pio.queue0); + else + b43legacy_dma_rx(dev->dma.rx_ring0); + /* We intentionally don't set "activity" to 1, here. */ + } + B43legacy_WARN_ON(dma_reason[1] & B43legacy_DMAIRQ_RX_DONE); + B43legacy_WARN_ON(dma_reason[2] & B43legacy_DMAIRQ_RX_DONE); + if (dma_reason[3] & B43legacy_DMAIRQ_RX_DONE) { + if (b43legacy_using_pio(dev)) + b43legacy_pio_rx(dev->pio.queue3); + else + b43legacy_dma_rx(dev->dma.rx_ring3); + activity = 1; + } + B43legacy_WARN_ON(dma_reason[4] & B43legacy_DMAIRQ_RX_DONE); + B43legacy_WARN_ON(dma_reason[5] & B43legacy_DMAIRQ_RX_DONE); + + if (reason & B43legacy_IRQ_TX_OK) { + handle_irq_transmit_status(dev); + activity = 1; + /* TODO: In AP mode, this also causes sending of powersave + responses. */ + } + + if (!modparam_noleds) + b43legacy_leds_update(dev, activity); + b43legacy_interrupt_enable(dev, dev->irq_savedstate); + mmiowb(); + spin_unlock_irqrestore(&dev->wl->irq_lock, flags); +} + +static void pio_irq_workaround(struct b43legacy_wldev *dev, + u16 base, int queueidx) +{ + u16 rxctl; + + rxctl = b43legacy_read16(dev, base + B43legacy_PIO_RXCTL); + if (rxctl & B43legacy_PIO_RXCTL_DATAAVAILABLE) + dev->dma_reason[queueidx] |= B43legacy_DMAIRQ_RX_DONE; + else + dev->dma_reason[queueidx] &= ~B43legacy_DMAIRQ_RX_DONE; +} + +static void b43legacy_interrupt_ack(struct b43legacy_wldev *dev, u32 reason) +{ + if (b43legacy_using_pio(dev) && + (dev->dev->id.revision < 3) && + (!(reason & B43legacy_IRQ_PIO_WORKAROUND))) { + /* Apply a PIO specific workaround to the dma_reasons */ + pio_irq_workaround(dev, B43legacy_MMIO_PIO1_BASE, 0); + pio_irq_workaround(dev, B43legacy_MMIO_PIO2_BASE, 1); + pio_irq_workaround(dev, B43legacy_MMIO_PIO3_BASE, 2); + pio_irq_workaround(dev, B43legacy_MMIO_PIO4_BASE, 3); + } + + b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON, reason); + + b43legacy_write32(dev, B43legacy_MMIO_DMA0_REASON, + dev->dma_reason[0]); + b43legacy_write32(dev, B43legacy_MMIO_DMA1_REASON, + dev->dma_reason[1]); + b43legacy_write32(dev, B43legacy_MMIO_DMA2_REASON, + dev->dma_reason[2]); + b43legacy_write32(dev, B43legacy_MMIO_DMA3_REASON, + dev->dma_reason[3]); + b43legacy_write32(dev, B43legacy_MMIO_DMA4_REASON, + dev->dma_reason[4]); + b43legacy_write32(dev, B43legacy_MMIO_DMA5_REASON, + dev->dma_reason[5]); +} + +/* Interrupt handler top-half */ +static irqreturn_t b43legacy_interrupt_handler(int irq, void *dev_id) +{ + irqreturn_t ret = IRQ_NONE; + struct b43legacy_wldev *dev = dev_id; + u32 reason; + + if (!dev) + return IRQ_NONE; + + spin_lock(&dev->wl->irq_lock); + + if (b43legacy_status(dev) < B43legacy_STAT_STARTED) + goto out; + reason = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON); + if (reason == 0xffffffff) /* shared IRQ */ + goto out; + ret = IRQ_HANDLED; + reason &= b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK); + if (!reason) + goto out; + + dev->dma_reason[0] = b43legacy_read32(dev, + B43legacy_MMIO_DMA0_REASON) + & 0x0001DC00; + dev->dma_reason[1] = b43legacy_read32(dev, + B43legacy_MMIO_DMA1_REASON) + & 0x0000DC00; + dev->dma_reason[2] = b43legacy_read32(dev, + B43legacy_MMIO_DMA2_REASON) + & 0x0000DC00; + dev->dma_reason[3] = b43legacy_read32(dev, + B43legacy_MMIO_DMA3_REASON) + & 0x0001DC00; + dev->dma_reason[4] = b43legacy_read32(dev, + B43legacy_MMIO_DMA4_REASON) + & 0x0000DC00; + dev->dma_reason[5] = b43legacy_read32(dev, + B43legacy_MMIO_DMA5_REASON) + & 0x0000DC00; + + b43legacy_interrupt_ack(dev, reason); + /* disable all IRQs. They are enabled again in the bottom half. */ + dev->irq_savedstate = b43legacy_interrupt_disable(dev, + B43legacy_IRQ_ALL); + /* save the reason code and call our bottom half. */ + dev->irq_reason = reason; + tasklet_schedule(&dev->isr_tasklet); +out: + mmiowb(); + spin_unlock(&dev->wl->irq_lock); + + return ret; +} + +static void b43legacy_release_firmware(struct b43legacy_wldev *dev) +{ + release_firmware(dev->fw.ucode); + dev->fw.ucode = NULL; + release_firmware(dev->fw.pcm); + dev->fw.pcm = NULL; + release_firmware(dev->fw.initvals); + dev->fw.initvals = NULL; + release_firmware(dev->fw.initvals_band); + dev->fw.initvals_band = NULL; +} + +static void b43legacy_print_fw_helptext(struct b43legacy_wl *wl) +{ + b43legacyerr(wl, "You must go to http://linuxwireless.org/en/users/" + "Drivers/bcm43xx#devicefirmware " + "and download the correct firmware (version 3).\n"); +} + +static int do_request_fw(struct b43legacy_wldev *dev, + const char *name, + const struct firmware **fw) +{ + char path[sizeof(modparam_fwpostfix) + 32]; + struct b43legacy_fw_header *hdr; + u32 size; + int err; + + if (!name) + return 0; + + snprintf(path, ARRAY_SIZE(path), + "b43legacy%s/%s.fw", + modparam_fwpostfix, name); + err = request_firmware(fw, path, dev->dev->dev); + if (err) { + b43legacyerr(dev->wl, "Firmware file \"%s\" not found " + "or load failed.\n", path); + return err; + } + if ((*fw)->size < sizeof(struct b43legacy_fw_header)) + goto err_format; + hdr = (struct b43legacy_fw_header *)((*fw)->data); + switch (hdr->type) { + case B43legacy_FW_TYPE_UCODE: + case B43legacy_FW_TYPE_PCM: + size = be32_to_cpu(hdr->size); + if (size != (*fw)->size - sizeof(struct b43legacy_fw_header)) + goto err_format; + /* fallthrough */ + case B43legacy_FW_TYPE_IV: + if (hdr->ver != 1) + goto err_format; + break; + default: + goto err_format; + } + + return err; + +err_format: + b43legacyerr(dev->wl, "Firmware file \"%s\" format error.\n", path); + return -EPROTO; +} + +static int b43legacy_request_firmware(struct b43legacy_wldev *dev) +{ + struct b43legacy_firmware *fw = &dev->fw; + const u8 rev = dev->dev->id.revision; + const char *filename; + u32 tmshigh; + int err; + + tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH); + if (!fw->ucode) { + if (rev == 2) + filename = "ucode2"; + else if (rev == 4) + filename = "ucode4"; + else + filename = "ucode5"; + err = do_request_fw(dev, filename, &fw->ucode); + if (err) + goto err_load; + } + if (!fw->pcm) { + if (rev < 5) + filename = "pcm4"; + else + filename = "pcm5"; + err = do_request_fw(dev, filename, &fw->pcm); + if (err) + goto err_load; + } + if (!fw->initvals) { + switch (dev->phy.type) { + case B43legacy_PHYTYPE_G: + if ((rev >= 5) && (rev <= 10)) + filename = "b0g0initvals5"; + else if (rev == 2 || rev == 4) + filename = "b0g0initvals2"; + else + goto err_no_initvals; + break; + default: + goto err_no_initvals; + } + err = do_request_fw(dev, filename, &fw->initvals); + if (err) + goto err_load; + } + if (!fw->initvals_band) { + switch (dev->phy.type) { + case B43legacy_PHYTYPE_G: + if ((rev >= 5) && (rev <= 10)) + filename = "b0g0bsinitvals5"; + else if (rev >= 11) + filename = NULL; + else if (rev == 2 || rev == 4) + filename = NULL; + else + goto err_no_initvals; + break; + default: + goto err_no_initvals; + } + err = do_request_fw(dev, filename, &fw->initvals_band); + if (err) + goto err_load; + } + + return 0; + +err_load: + b43legacy_print_fw_helptext(dev->wl); + goto error; + +err_no_initvals: + err = -ENODEV; + b43legacyerr(dev->wl, "No Initial Values firmware file for PHY %u, " + "core rev %u\n", dev->phy.type, rev); + goto error; + +error: + b43legacy_release_firmware(dev); + return err; +} + +static int b43legacy_upload_microcode(struct b43legacy_wldev *dev) +{ + const size_t hdr_len = sizeof(struct b43legacy_fw_header); + const __be32 *data; + unsigned int i; + unsigned int len; + u16 fwrev; + u16 fwpatch; + u16 fwdate; + u16 fwtime; + u32 tmp; + int err = 0; + + /* Upload Microcode. */ + data = (__be32 *) (dev->fw.ucode->data + hdr_len); + len = (dev->fw.ucode->size - hdr_len) / sizeof(__be32); + b43legacy_shm_control_word(dev, + B43legacy_SHM_UCODE | + B43legacy_SHM_AUTOINC_W, + 0x0000); + for (i = 0; i < len; i++) { + b43legacy_write32(dev, B43legacy_MMIO_SHM_DATA, + be32_to_cpu(data[i])); + udelay(10); + } + + if (dev->fw.pcm) { + /* Upload PCM data. */ + data = (__be32 *) (dev->fw.pcm->data + hdr_len); + len = (dev->fw.pcm->size - hdr_len) / sizeof(__be32); + b43legacy_shm_control_word(dev, B43legacy_SHM_HW, 0x01EA); + b43legacy_write32(dev, B43legacy_MMIO_SHM_DATA, 0x00004000); + /* No need for autoinc bit in SHM_HW */ + b43legacy_shm_control_word(dev, B43legacy_SHM_HW, 0x01EB); + for (i = 0; i < len; i++) { + b43legacy_write32(dev, B43legacy_MMIO_SHM_DATA, + be32_to_cpu(data[i])); + udelay(10); + } + } + + b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON, + B43legacy_IRQ_ALL); + b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, 0x00020402); + + /* Wait for the microcode to load and respond */ + i = 0; + while (1) { + tmp = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON); + if (tmp == B43legacy_IRQ_MAC_SUSPENDED) + break; + i++; + if (i >= B43legacy_IRQWAIT_MAX_RETRIES) { + b43legacyerr(dev->wl, "Microcode not responding\n"); + b43legacy_print_fw_helptext(dev->wl); + err = -ENODEV; + goto out; + } + udelay(10); + } + /* dummy read follows */ + b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON); + + /* Get and check the revisions. */ + fwrev = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, + B43legacy_SHM_SH_UCODEREV); + fwpatch = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, + B43legacy_SHM_SH_UCODEPATCH); + fwdate = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, + B43legacy_SHM_SH_UCODEDATE); + fwtime = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, + B43legacy_SHM_SH_UCODETIME); + + if (fwrev > 0x128) { + b43legacyerr(dev->wl, "YOU ARE TRYING TO LOAD V4 FIRMWARE." + " Only firmware from binary drivers version 3.x" + " is supported. You must change your firmware" + " files.\n"); + b43legacy_print_fw_helptext(dev->wl); + b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, 0); + err = -EOPNOTSUPP; + goto out; + } + b43legacydbg(dev->wl, "Loading firmware version 0x%X, patch level %u " + "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n", fwrev, fwpatch, + (fwdate >> 12) & 0xF, (fwdate >> 8) & 0xF, fwdate & 0xFF, + (fwtime >> 11) & 0x1F, (fwtime >> 5) & 0x3F, fwtime & 0x1F); + + dev->fw.rev = fwrev; + dev->fw.patch = fwpatch; + +out: + return err; +} + +static int b43legacy_write_initvals(struct b43legacy_wldev *dev, + const struct b43legacy_iv *ivals, + size_t count, + size_t array_size) +{ + const struct b43legacy_iv *iv; + u16 offset; + size_t i; + bool bit32; + + BUILD_BUG_ON(sizeof(struct b43legacy_iv) != 6); + iv = ivals; + for (i = 0; i < count; i++) { + if (array_size < sizeof(iv->offset_size)) + goto err_format; + array_size -= sizeof(iv->offset_size); + offset = be16_to_cpu(iv->offset_size); + bit32 = !!(offset & B43legacy_IV_32BIT); + offset &= B43legacy_IV_OFFSET_MASK; + if (offset >= 0x1000) + goto err_format; + if (bit32) { + u32 value; + + if (array_size < sizeof(iv->data.d32)) + goto err_format; + array_size -= sizeof(iv->data.d32); + + value = be32_to_cpu(get_unaligned(&iv->data.d32)); + b43legacy_write32(dev, offset, value); + + iv = (const struct b43legacy_iv *)((const uint8_t *)iv + + sizeof(__be16) + + sizeof(__be32)); + } else { + u16 value; + + if (array_size < sizeof(iv->data.d16)) + goto err_format; + array_size -= sizeof(iv->data.d16); + + value = be16_to_cpu(iv->data.d16); + b43legacy_write16(dev, offset, value); + + iv = (const struct b43legacy_iv *)((const uint8_t *)iv + + sizeof(__be16) + + sizeof(__be16)); + } + } + if (array_size) + goto err_format; + + return 0; + +err_format: + b43legacyerr(dev->wl, "Initial Values Firmware file-format error.\n"); + b43legacy_print_fw_helptext(dev->wl); + + return -EPROTO; +} + +static int b43legacy_upload_initvals(struct b43legacy_wldev *dev) +{ + const size_t hdr_len = sizeof(struct b43legacy_fw_header); + const struct b43legacy_fw_header *hdr; + struct b43legacy_firmware *fw = &dev->fw; + const struct b43legacy_iv *ivals; + size_t count; + int err; + + hdr = (const struct b43legacy_fw_header *)(fw->initvals->data); + ivals = (const struct b43legacy_iv *)(fw->initvals->data + hdr_len); + count = be32_to_cpu(hdr->size); + err = b43legacy_write_initvals(dev, ivals, count, + fw->initvals->size - hdr_len); + if (err) + goto out; + if (fw->initvals_band) { + hdr = (const struct b43legacy_fw_header *) + (fw->initvals_band->data); + ivals = (const struct b43legacy_iv *)(fw->initvals_band->data + + hdr_len); + count = be32_to_cpu(hdr->size); + err = b43legacy_write_initvals(dev, ivals, count, + fw->initvals_band->size - hdr_len); + if (err) + goto out; + } +out: + + return err; +} + +/* Initialize the GPIOs + * http://bcm-specs.sipsolutions.net/GPIO + */ +static int b43legacy_gpio_init(struct b43legacy_wldev *dev) +{ + struct ssb_bus *bus = dev->dev->bus; + struct ssb_device *gpiodev, *pcidev = NULL; + u32 mask; + u32 set; + + b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, + b43legacy_read32(dev, + B43legacy_MMIO_STATUS_BITFIELD) + & 0xFFFF3FFF); + + b43legacy_leds_switch_all(dev, 0); + b43legacy_write16(dev, B43legacy_MMIO_GPIO_MASK, + b43legacy_read16(dev, + B43legacy_MMIO_GPIO_MASK) + | 0x000F); + + mask = 0x0000001F; + set = 0x0000000F; + if (dev->dev->bus->chip_id == 0x4301) { + mask |= 0x0060; + set |= 0x0060; + } + if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_PACTRL) { + b43legacy_write16(dev, B43legacy_MMIO_GPIO_MASK, + b43legacy_read16(dev, + B43legacy_MMIO_GPIO_MASK) + | 0x0200); + mask |= 0x0200; + set |= 0x0200; + } + if (dev->dev->id.revision >= 2) + mask |= 0x0010; /* FIXME: This is redundant. */ + +#ifdef CONFIG_SSB_DRIVER_PCICORE + pcidev = bus->pcicore.dev; +#endif + gpiodev = bus->chipco.dev ? : pcidev; + if (!gpiodev) + return 0; + ssb_write32(gpiodev, B43legacy_GPIO_CONTROL, + (ssb_read32(gpiodev, B43legacy_GPIO_CONTROL) + & mask) | set); + + return 0; +} + +/* Turn off all GPIO stuff. Call this on module unload, for example. */ +static void b43legacy_gpio_cleanup(struct b43legacy_wldev *dev) +{ + struct ssb_bus *bus = dev->dev->bus; + struct ssb_device *gpiodev, *pcidev = NULL; + +#ifdef CONFIG_SSB_DRIVER_PCICORE + pcidev = bus->pcicore.dev; +#endif + gpiodev = bus->chipco.dev ? : pcidev; + if (!gpiodev) + return; + ssb_write32(gpiodev, B43legacy_GPIO_CONTROL, 0); +} + +/* http://bcm-specs.sipsolutions.net/EnableMac */ +void b43legacy_mac_enable(struct b43legacy_wldev *dev) +{ + dev->mac_suspended--; + B43legacy_WARN_ON(dev->mac_suspended < 0); + if (dev->mac_suspended == 0) { + b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, + b43legacy_read32(dev, + B43legacy_MMIO_STATUS_BITFIELD) + | B43legacy_SBF_MAC_ENABLED); + b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON, + B43legacy_IRQ_MAC_SUSPENDED); + /* the next two are dummy reads */ + b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD); + b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON); + b43legacy_power_saving_ctl_bits(dev, -1, -1); + } +} + +/* http://bcm-specs.sipsolutions.net/SuspendMAC */ +void b43legacy_mac_suspend(struct b43legacy_wldev *dev) +{ + int i; + u32 tmp; + + B43legacy_WARN_ON(dev->mac_suspended < 0); + if (dev->mac_suspended == 0) { + b43legacy_power_saving_ctl_bits(dev, -1, 1); + b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, + b43legacy_read32(dev, + B43legacy_MMIO_STATUS_BITFIELD) + & ~B43legacy_SBF_MAC_ENABLED); + b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON); + for (i = 10000; i; i--) { + tmp = b43legacy_read32(dev, + B43legacy_MMIO_GEN_IRQ_REASON); + if (tmp & B43legacy_IRQ_MAC_SUSPENDED) + goto out; + udelay(1); + } + b43legacyerr(dev->wl, "MAC suspend failed\n"); + } +out: + dev->mac_suspended++; +} + +static void b43legacy_adjust_opmode(struct b43legacy_wldev *dev) +{ + struct b43legacy_wl *wl = dev->wl; + u32 ctl; + u16 cfp_pretbtt; + + ctl = b43legacy_read32(dev, B43legacy_MMIO_MACCTL); + /* Reset status to STA infrastructure mode. */ + ctl &= ~B43legacy_MACCTL_AP; + ctl &= ~B43legacy_MACCTL_KEEP_CTL; + ctl &= ~B43legacy_MACCTL_KEEP_BADPLCP; + ctl &= ~B43legacy_MACCTL_KEEP_BAD; + ctl &= ~B43legacy_MACCTL_PROMISC; + ctl |= B43legacy_MACCTL_INFRA; + + if (wl->operating) { + switch (wl->if_type) { + case IEEE80211_IF_TYPE_AP: + ctl |= B43legacy_MACCTL_AP; + break; + case IEEE80211_IF_TYPE_IBSS: + ctl &= ~B43legacy_MACCTL_INFRA; + break; + case IEEE80211_IF_TYPE_STA: + case IEEE80211_IF_TYPE_MNTR: + case IEEE80211_IF_TYPE_WDS: + break; + default: + b43legacyerr(wl, "Improper value of %d for" + " wl->if_type\n", wl->if_type); + } + } + if (wl->monitor) { + ctl |= B43legacy_MACCTL_KEEP_CTL; + if (modparam_mon_keep_bad) + ctl |= B43legacy_MACCTL_KEEP_BAD; + if (modparam_mon_keep_badplcp) + ctl |= B43legacy_MACCTL_KEEP_BADPLCP; + } + if (wl->promisc) + ctl |= B43legacy_MACCTL_PROMISC; + /* Workaround: On old hardware the HW-MAC-address-filter + * doesn't work properly, so always run promisc in filter + * it in software. */ + if (dev->dev->id.revision <= 4) + ctl |= B43legacy_MACCTL_PROMISC; + + b43legacy_write32(dev, B43legacy_MMIO_MACCTL, ctl); + + cfp_pretbtt = 2; + if ((ctl & B43legacy_MACCTL_INFRA) && + !(ctl & B43legacy_MACCTL_AP)) { + if (dev->dev->bus->chip_id == 0x4306 && + dev->dev->bus->chip_rev == 3) + cfp_pretbtt = 100; + else + cfp_pretbtt = 50; + } + b43legacy_write16(dev, 0x612, cfp_pretbtt); +} + +static void b43legacy_rate_memory_write(struct b43legacy_wldev *dev, + u16 rate, + int is_ofdm) +{ + u16 offset; + + if (is_ofdm) { + offset = 0x480; + offset += (b43legacy_plcp_get_ratecode_ofdm(rate) & 0x000F) * 2; + } else { + offset = 0x4C0; + offset += (b43legacy_plcp_get_ratecode_cck(rate) & 0x000F) * 2; + } + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, offset + 0x20, + b43legacy_shm_read16(dev, + B43legacy_SHM_SHARED, offset)); +} + +static void b43legacy_rate_memory_init(struct b43legacy_wldev *dev) +{ + switch (dev->phy.type) { + case B43legacy_PHYTYPE_G: + b43legacy_rate_memory_write(dev, B43legacy_OFDM_RATE_6MB, 1); + b43legacy_rate_memory_write(dev, B43legacy_OFDM_RATE_12MB, 1); + b43legacy_rate_memory_write(dev, B43legacy_OFDM_RATE_18MB, 1); + b43legacy_rate_memory_write(dev, B43legacy_OFDM_RATE_24MB, 1); + b43legacy_rate_memory_write(dev, B43legacy_OFDM_RATE_36MB, 1); + b43legacy_rate_memory_write(dev, B43legacy_OFDM_RATE_48MB, 1); + b43legacy_rate_memory_write(dev, B43legacy_OFDM_RATE_54MB, 1); + /* fallthrough */ + case B43legacy_PHYTYPE_B: + b43legacy_rate_memory_write(dev, B43legacy_CCK_RATE_1MB, 0); + b43legacy_rate_memory_write(dev, B43legacy_CCK_RATE_2MB, 0); + b43legacy_rate_memory_write(dev, B43legacy_CCK_RATE_5MB, 0); + b43legacy_rate_memory_write(dev, B43legacy_CCK_RATE_11MB, 0); + break; + default: + B43legacy_BUG_ON(1); + } +} + +/* Set the TX-Antenna for management frames sent by firmware. */ +static void b43legacy_mgmtframe_txantenna(struct b43legacy_wldev *dev, + int antenna) +{ + u16 ant = 0; + u16 tmp; + + switch (antenna) { + case B43legacy_ANTENNA0: + ant |= B43legacy_TX4_PHY_ANT0; + break; + case B43legacy_ANTENNA1: + ant |= B43legacy_TX4_PHY_ANT1; + break; + case B43legacy_ANTENNA_AUTO: + ant |= B43legacy_TX4_PHY_ANTLAST; + break; + default: + B43legacy_BUG_ON(1); + } + + /* FIXME We also need to set the other flags of the PHY control + * field somewhere. */ + + /* For Beacons */ + tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, + B43legacy_SHM_SH_BEACPHYCTL); + tmp = (tmp & ~B43legacy_TX4_PHY_ANT) | ant; + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, + B43legacy_SHM_SH_BEACPHYCTL, tmp); + /* For ACK/CTS */ + tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, + B43legacy_SHM_SH_ACKCTSPHYCTL); + tmp = (tmp & ~B43legacy_TX4_PHY_ANT) | ant; + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, + B43legacy_SHM_SH_ACKCTSPHYCTL, tmp); + /* For Probe Resposes */ + tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, + B43legacy_SHM_SH_PRPHYCTL); + tmp = (tmp & ~B43legacy_TX4_PHY_ANT) | ant; + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, + B43legacy_SHM_SH_PRPHYCTL, tmp); +} + +/* This is the opposite of b43legacy_chip_init() */ +static void b43legacy_chip_exit(struct b43legacy_wldev *dev) +{ + b43legacy_radio_turn_off(dev); + if (!modparam_noleds) + b43legacy_leds_exit(dev); + b43legacy_gpio_cleanup(dev); + /* firmware is released later */ +} + +/* Initialize the chip + * http://bcm-specs.sipsolutions.net/ChipInit + */ +static int b43legacy_chip_init(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + int err; + int tmp; + u32 value32; + u16 value16; + + b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, + B43legacy_SBF_CORE_READY + | B43legacy_SBF_400); + + err = b43legacy_request_firmware(dev); + if (err) + goto out; + err = b43legacy_upload_microcode(dev); + if (err) + goto out; /* firmware is released later */ + + err = b43legacy_gpio_init(dev); + if (err) + goto out; /* firmware is released later */ + err = b43legacy_upload_initvals(dev); + if (err) + goto err_gpio_cleanup; + b43legacy_radio_turn_on(dev); + dev->radio_hw_enable = b43legacy_is_hw_radio_enabled(dev); + b43legacyinfo(dev->wl, "Radio %s by hardware\n", + (dev->radio_hw_enable == 0) ? "disabled" : "enabled"); + + b43legacy_write16(dev, 0x03E6, 0x0000); + err = b43legacy_phy_init(dev); + if (err) + goto err_radio_off; + + /* Select initial Interference Mitigation. */ + tmp = phy->interfmode; + phy->interfmode = B43legacy_INTERFMODE_NONE; + b43legacy_radio_set_interference_mitigation(dev, tmp); + + b43legacy_phy_set_antenna_diversity(dev); + b43legacy_mgmtframe_txantenna(dev, B43legacy_ANTENNA_DEFAULT); + + if (phy->type == B43legacy_PHYTYPE_B) { + value16 = b43legacy_read16(dev, 0x005E); + value16 |= 0x0004; + b43legacy_write16(dev, 0x005E, value16); + } + b43legacy_write32(dev, 0x0100, 0x01000000); + if (dev->dev->id.revision < 5) + b43legacy_write32(dev, 0x010C, 0x01000000); + + value32 = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD); + value32 &= ~B43legacy_SBF_MODE_NOTADHOC; + b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, value32); + value32 = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD); + value32 |= B43legacy_SBF_MODE_NOTADHOC; + b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, value32); + + value32 = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD); + value32 |= 0x100000; + b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, value32); + + if (b43legacy_using_pio(dev)) { + b43legacy_write32(dev, 0x0210, 0x00000100); + b43legacy_write32(dev, 0x0230, 0x00000100); + b43legacy_write32(dev, 0x0250, 0x00000100); + b43legacy_write32(dev, 0x0270, 0x00000100); + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0034, + 0x0000); + } + + /* Probe Response Timeout value */ + /* FIXME: Default to 0, has to be set by ioctl probably... :-/ */ + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0074, 0x0000); + + /* Initially set the wireless operation mode. */ + b43legacy_adjust_opmode(dev); + + if (dev->dev->id.revision < 3) { + b43legacy_write16(dev, 0x060E, 0x0000); + b43legacy_write16(dev, 0x0610, 0x8000); + b43legacy_write16(dev, 0x0604, 0x0000); + b43legacy_write16(dev, 0x0606, 0x0200); + } else { + b43legacy_write32(dev, 0x0188, 0x80000000); + b43legacy_write32(dev, 0x018C, 0x02000000); + } + b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON, 0x00004000); + b43legacy_write32(dev, B43legacy_MMIO_DMA0_IRQ_MASK, 0x0001DC00); + b43legacy_write32(dev, B43legacy_MMIO_DMA1_IRQ_MASK, 0x0000DC00); + b43legacy_write32(dev, B43legacy_MMIO_DMA2_IRQ_MASK, 0x0000DC00); + b43legacy_write32(dev, B43legacy_MMIO_DMA3_IRQ_MASK, 0x0001DC00); + b43legacy_write32(dev, B43legacy_MMIO_DMA4_IRQ_MASK, 0x0000DC00); + b43legacy_write32(dev, B43legacy_MMIO_DMA5_IRQ_MASK, 0x0000DC00); + + value32 = ssb_read32(dev->dev, SSB_TMSLOW); + value32 |= 0x00100000; + ssb_write32(dev->dev, SSB_TMSLOW, value32); + + b43legacy_write16(dev, B43legacy_MMIO_POWERUP_DELAY, + dev->dev->bus->chipco.fast_pwrup_delay); + + B43legacy_WARN_ON(err != 0); + b43legacydbg(dev->wl, "Chip initialized\n"); +out: + return err; + +err_radio_off: + b43legacy_radio_turn_off(dev); +err_gpio_cleanup: + b43legacy_gpio_cleanup(dev); + goto out; +} + +static void b43legacy_periodic_every120sec(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + + if (phy->type != B43legacy_PHYTYPE_G || phy->rev < 2) + return; + + b43legacy_mac_suspend(dev); + b43legacy_phy_lo_g_measure(dev); + b43legacy_mac_enable(dev); +} + +static void b43legacy_periodic_every60sec(struct b43legacy_wldev *dev) +{ + b43legacy_phy_lo_mark_all_unused(dev); + if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_RSSI) { + b43legacy_mac_suspend(dev); + b43legacy_calc_nrssi_slope(dev); + b43legacy_mac_enable(dev); + } +} + +static void b43legacy_periodic_every30sec(struct b43legacy_wldev *dev) +{ + /* Update device statistics. */ + b43legacy_calculate_link_quality(dev); +} + +static void b43legacy_periodic_every15sec(struct b43legacy_wldev *dev) +{ + b43legacy_phy_xmitpower(dev); /* FIXME: unless scanning? */ +} + +static void b43legacy_periodic_every1sec(struct b43legacy_wldev *dev) +{ + int radio_hw_enable; + + /* check if radio hardware enabled status changed */ + radio_hw_enable = b43legacy_is_hw_radio_enabled(dev); + if (unlikely(dev->radio_hw_enable != radio_hw_enable)) { + dev->radio_hw_enable = radio_hw_enable; + b43legacyinfo(dev->wl, "Radio hardware status changed to %s\n", + (radio_hw_enable == 0) ? "disabled" : "enabled"); + b43legacy_leds_update(dev, 0); + } +} + +static void do_periodic_work(struct b43legacy_wldev *dev) +{ + unsigned int state; + + state = dev->periodic_state; + if (state % 120 == 0) + b43legacy_periodic_every120sec(dev); + if (state % 60 == 0) + b43legacy_periodic_every60sec(dev); + if (state % 30 == 0) + b43legacy_periodic_every30sec(dev); + if (state % 15 == 0) + b43legacy_periodic_every15sec(dev); + b43legacy_periodic_every1sec(dev); +} + +/* Estimate a "Badness" value based on the periodic work + * state-machine state. "Badness" is worse (bigger), if the + * periodic work will take longer. + */ +static int estimate_periodic_work_badness(unsigned int state) +{ + int badness = 0; + + if (state % 120 == 0) /* every 120 sec */ + badness += 10; + if (state % 60 == 0) /* every 60 sec */ + badness += 5; + if (state % 30 == 0) /* every 30 sec */ + badness += 1; + if (state % 15 == 0) /* every 15 sec */ + badness += 1; + +#define BADNESS_LIMIT 4 + return badness; +} + +static void b43legacy_periodic_work_handler(struct work_struct *work) +{ + struct b43legacy_wldev *dev = + container_of(work, struct b43legacy_wldev, + periodic_work.work); + unsigned long flags; + unsigned long delay; + u32 savedirqs = 0; + int badness; + + mutex_lock(&dev->wl->mutex); + + if (unlikely(b43legacy_status(dev) != B43legacy_STAT_STARTED)) + goto out; + if (b43legacy_debug(dev, B43legacy_DBG_PWORK_STOP)) + goto out_requeue; + + badness = estimate_periodic_work_badness(dev->periodic_state); + if (badness > BADNESS_LIMIT) { + spin_lock_irqsave(&dev->wl->irq_lock, flags); + /* Suspend TX as we don't want to transmit packets while + * we recalibrate the hardware. */ + b43legacy_tx_suspend(dev); + savedirqs = b43legacy_interrupt_disable(dev, + B43legacy_IRQ_ALL); + /* Periodic work will take a long time, so we want it to + * be preemtible and release the spinlock. */ + spin_unlock_irqrestore(&dev->wl->irq_lock, flags); + b43legacy_synchronize_irq(dev); + + do_periodic_work(dev); + + spin_lock_irqsave(&dev->wl->irq_lock, flags); + b43legacy_interrupt_enable(dev, savedirqs); + b43legacy_tx_resume(dev); + mmiowb(); + spin_unlock_irqrestore(&dev->wl->irq_lock, flags); + } else { + /* Take the global driver lock. This will lock any operation. */ + spin_lock_irqsave(&dev->wl->irq_lock, flags); + + do_periodic_work(dev); + + mmiowb(); + spin_unlock_irqrestore(&dev->wl->irq_lock, flags); + } + dev->periodic_state++; +out_requeue: + if (b43legacy_debug(dev, B43legacy_DBG_PWORK_FAST)) + delay = msecs_to_jiffies(50); + else + delay = round_jiffies(HZ); + queue_delayed_work(dev->wl->hw->workqueue, + &dev->periodic_work, delay); +out: + mutex_unlock(&dev->wl->mutex); +} + +static void b43legacy_periodic_tasks_setup(struct b43legacy_wldev *dev) +{ + struct delayed_work *work = &dev->periodic_work; + + dev->periodic_state = 0; + INIT_DELAYED_WORK(work, b43legacy_periodic_work_handler); + queue_delayed_work(dev->wl->hw->workqueue, work, 0); +} + +/* Validate access to the chip (SHM) */ +static int b43legacy_validate_chipaccess(struct b43legacy_wldev *dev) +{ + u32 value; + u32 shm_backup; + + shm_backup = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED, 0); + b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, 0, 0xAA5555AA); + if (b43legacy_shm_read32(dev, B43legacy_SHM_SHARED, 0) != + 0xAA5555AA) + goto error; + b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, 0, 0x55AAAA55); + if (b43legacy_shm_read32(dev, B43legacy_SHM_SHARED, 0) != + 0x55AAAA55) + goto error; + b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, 0, shm_backup); + + value = b43legacy_read32(dev, B43legacy_MMIO_MACCTL); + if ((value | B43legacy_MACCTL_GMODE) != + (B43legacy_MACCTL_GMODE | B43legacy_MACCTL_IHR_ENABLED)) + goto error; + + value = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON); + if (value) + goto error; + + return 0; +error: + b43legacyerr(dev->wl, "Failed to validate the chipaccess\n"); + return -ENODEV; +} + +static void b43legacy_security_init(struct b43legacy_wldev *dev) +{ + dev->max_nr_keys = (dev->dev->id.revision >= 5) ? 58 : 20; + B43legacy_WARN_ON(dev->max_nr_keys > ARRAY_SIZE(dev->key)); + dev->ktp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, + 0x0056); + /* KTP is a word address, but we address SHM bytewise. + * So multiply by two. + */ + dev->ktp *= 2; + if (dev->dev->id.revision >= 5) + /* Number of RCMTA address slots */ + b43legacy_write16(dev, B43legacy_MMIO_RCMTA_COUNT, + dev->max_nr_keys - 8); +} + +static int b43legacy_rng_read(struct hwrng *rng, u32 *data) +{ + struct b43legacy_wl *wl = (struct b43legacy_wl *)rng->priv; + unsigned long flags; + + /* Don't take wl->mutex here, as it could deadlock with + * hwrng internal locking. It's not needed to take + * wl->mutex here, anyway. */ + + spin_lock_irqsave(&wl->irq_lock, flags); + *data = b43legacy_read16(wl->current_dev, B43legacy_MMIO_RNG); + spin_unlock_irqrestore(&wl->irq_lock, flags); + + return (sizeof(u16)); +} + +static void b43legacy_rng_exit(struct b43legacy_wl *wl) +{ + if (wl->rng_initialized) + hwrng_unregister(&wl->rng); +} + +static int b43legacy_rng_init(struct b43legacy_wl *wl) +{ + int err; + + snprintf(wl->rng_name, ARRAY_SIZE(wl->rng_name), + "%s_%s", KBUILD_MODNAME, wiphy_name(wl->hw->wiphy)); + wl->rng.name = wl->rng_name; + wl->rng.data_read = b43legacy_rng_read; + wl->rng.priv = (unsigned long)wl; + wl->rng_initialized = 1; + err = hwrng_register(&wl->rng); + if (err) { + wl->rng_initialized = 0; + b43legacyerr(wl, "Failed to register the random " + "number generator (%d)\n", err); + } + + return err; +} + +static int b43legacy_tx(struct ieee80211_hw *hw, + struct sk_buff *skb, + struct ieee80211_tx_control *ctl) +{ + struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); + struct b43legacy_wldev *dev = wl->current_dev; + int err = -ENODEV; + unsigned long flags; + + if (unlikely(!dev)) + goto out; + if (unlikely(b43legacy_status(dev) < B43legacy_STAT_STARTED)) + goto out; + /* DMA-TX is done without a global lock. */ + if (b43legacy_using_pio(dev)) { + spin_lock_irqsave(&wl->irq_lock, flags); + err = b43legacy_pio_tx(dev, skb, ctl); + spin_unlock_irqrestore(&wl->irq_lock, flags); + } else + err = b43legacy_dma_tx(dev, skb, ctl); +out: + if (unlikely(err)) + return NETDEV_TX_BUSY; + return NETDEV_TX_OK; +} + +static int b43legacy_conf_tx(struct ieee80211_hw *hw, + int queue, + const struct ieee80211_tx_queue_params *params) +{ + return 0; +} + +static int b43legacy_get_tx_stats(struct ieee80211_hw *hw, + struct ieee80211_tx_queue_stats *stats) +{ + struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); + struct b43legacy_wldev *dev = wl->current_dev; + unsigned long flags; + int err = -ENODEV; + + if (!dev) + goto out; + spin_lock_irqsave(&wl->irq_lock, flags); + if (likely(b43legacy_status(dev) >= B43legacy_STAT_STARTED)) { + if (b43legacy_using_pio(dev)) + b43legacy_pio_get_tx_stats(dev, stats); + else + b43legacy_dma_get_tx_stats(dev, stats); + err = 0; + } + spin_unlock_irqrestore(&wl->irq_lock, flags); +out: + return err; +} + +static int b43legacy_get_stats(struct ieee80211_hw *hw, + struct ieee80211_low_level_stats *stats) +{ + struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); + unsigned long flags; + + spin_lock_irqsave(&wl->irq_lock, flags); + memcpy(stats, &wl->ieee_stats, sizeof(*stats)); + spin_unlock_irqrestore(&wl->irq_lock, flags); + + return 0; +} + +static const char *phymode_to_string(unsigned int phymode) +{ + switch (phymode) { + case B43legacy_PHYMODE_B: + return "B"; + case B43legacy_PHYMODE_G: + return "G"; + default: + B43legacy_BUG_ON(1); + } + return ""; +} + +static int find_wldev_for_phymode(struct b43legacy_wl *wl, + unsigned int phymode, + struct b43legacy_wldev **dev, + bool *gmode) +{ + struct b43legacy_wldev *d; + + list_for_each_entry(d, &wl->devlist, list) { + if (d->phy.possible_phymodes & phymode) { + /* Ok, this device supports the PHY-mode. + * Set the gmode bit. */ + *gmode = 1; + *dev = d; + + return 0; + } + } + + return -ESRCH; +} + +static void b43legacy_put_phy_into_reset(struct b43legacy_wldev *dev) +{ + struct ssb_device *sdev = dev->dev; + u32 tmslow; + + tmslow = ssb_read32(sdev, SSB_TMSLOW); + tmslow &= ~B43legacy_TMSLOW_GMODE; + tmslow |= B43legacy_TMSLOW_PHYRESET; + tmslow |= SSB_TMSLOW_FGC; + ssb_write32(sdev, SSB_TMSLOW, tmslow); + msleep(1); + + tmslow = ssb_read32(sdev, SSB_TMSLOW); + tmslow &= ~SSB_TMSLOW_FGC; + tmslow |= B43legacy_TMSLOW_PHYRESET; + ssb_write32(sdev, SSB_TMSLOW, tmslow); + msleep(1); +} + +/* Expects wl->mutex locked */ +static int b43legacy_switch_phymode(struct b43legacy_wl *wl, + unsigned int new_mode) +{ + struct b43legacy_wldev *up_dev; + struct b43legacy_wldev *down_dev; + int err; + bool gmode = 0; + int prev_status; + + err = find_wldev_for_phymode(wl, new_mode, &up_dev, &gmode); + if (err) { + b43legacyerr(wl, "Could not find a device for %s-PHY mode\n", + phymode_to_string(new_mode)); + return err; + } + if ((up_dev == wl->current_dev) && + (!!wl->current_dev->phy.gmode == !!gmode)) + /* This device is already running. */ + return 0; + b43legacydbg(wl, "Reconfiguring PHYmode to %s-PHY\n", + phymode_to_string(new_mode)); + down_dev = wl->current_dev; + + prev_status = b43legacy_status(down_dev); + /* Shutdown the currently running core. */ + if (prev_status >= B43legacy_STAT_STARTED) + b43legacy_wireless_core_stop(down_dev); + if (prev_status >= B43legacy_STAT_INITIALIZED) + b43legacy_wireless_core_exit(down_dev); + + if (down_dev != up_dev) + /* We switch to a different core, so we put PHY into + * RESET on the old core. */ + b43legacy_put_phy_into_reset(down_dev); + + /* Now start the new core. */ + up_dev->phy.gmode = gmode; + if (prev_status >= B43legacy_STAT_INITIALIZED) { + err = b43legacy_wireless_core_init(up_dev); + if (err) { + b43legacyerr(wl, "Fatal: Could not initialize device" + " for newly selected %s-PHY mode\n", + phymode_to_string(new_mode)); + goto init_failure; + } + } + if (prev_status >= B43legacy_STAT_STARTED) { + err = b43legacy_wireless_core_start(up_dev); + if (err) { + b43legacyerr(wl, "Fatal: Coult not start device for " + "newly selected %s-PHY mode\n", + phymode_to_string(new_mode)); + b43legacy_wireless_core_exit(up_dev); + goto init_failure; + } + } + B43legacy_WARN_ON(b43legacy_status(up_dev) != prev_status); + + b43legacy_shm_write32(up_dev, B43legacy_SHM_SHARED, 0x003E, 0); + + wl->current_dev = up_dev; + + return 0; +init_failure: + /* Whoops, failed to init the new core. No core is operating now. */ + wl->current_dev = NULL; + return err; +} + +static int b43legacy_antenna_from_ieee80211(u8 antenna) +{ + switch (antenna) { + case 0: /* default/diversity */ + return B43legacy_ANTENNA_DEFAULT; + case 1: /* Antenna 0 */ + return B43legacy_ANTENNA0; + case 2: /* Antenna 1 */ + return B43legacy_ANTENNA1; + default: + return B43legacy_ANTENNA_DEFAULT; + } +} + +static int b43legacy_dev_config(struct ieee80211_hw *hw, + struct ieee80211_conf *conf) +{ + struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); + struct b43legacy_wldev *dev; + struct b43legacy_phy *phy; + unsigned long flags; + unsigned int new_phymode = 0xFFFF; + int antenna_tx; + int antenna_rx; + int err = 0; + u32 savedirqs; + + antenna_tx = b43legacy_antenna_from_ieee80211(conf->antenna_sel_tx); + antenna_rx = b43legacy_antenna_from_ieee80211(conf->antenna_sel_rx); + + mutex_lock(&wl->mutex); + + /* Switch the PHY mode (if necessary). */ + switch (conf->phymode) { + case MODE_IEEE80211B: + new_phymode = B43legacy_PHYMODE_B; + break; + case MODE_IEEE80211G: + new_phymode = B43legacy_PHYMODE_G; + break; + default: + B43legacy_WARN_ON(1); + } + err = b43legacy_switch_phymode(wl, new_phymode); + if (err) + goto out_unlock_mutex; + dev = wl->current_dev; + phy = &dev->phy; + + /* Disable IRQs while reconfiguring the device. + * This makes it possible to drop the spinlock throughout + * the reconfiguration process. */ + spin_lock_irqsave(&wl->irq_lock, flags); + if (b43legacy_status(dev) < B43legacy_STAT_STARTED) { + spin_unlock_irqrestore(&wl->irq_lock, flags); + goto out_unlock_mutex; + } + savedirqs = b43legacy_interrupt_disable(dev, B43legacy_IRQ_ALL); + spin_unlock_irqrestore(&wl->irq_lock, flags); + b43legacy_synchronize_irq(dev); + + /* Switch to the requested channel. + * The firmware takes care of races with the TX handler. */ + if (conf->channel_val != phy->channel) + b43legacy_radio_selectchannel(dev, conf->channel_val, 0); + + /* Enable/Disable ShortSlot timing. */ + if ((!!(conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)) + != dev->short_slot) { + B43legacy_WARN_ON(phy->type != B43legacy_PHYTYPE_G); + if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) + b43legacy_short_slot_timing_enable(dev); + else + b43legacy_short_slot_timing_disable(dev); + } + + /* Adjust the desired TX power level. */ + if (conf->power_level != 0) { + if (conf->power_level != phy->power_level) { + phy->power_level = conf->power_level; + b43legacy_phy_xmitpower(dev); + } + } + + /* Antennas for RX and management frame TX. */ + b43legacy_mgmtframe_txantenna(dev, antenna_tx); + + /* Update templates for AP mode. */ + if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP)) + b43legacy_set_beacon_int(dev, conf->beacon_int); + + + spin_lock_irqsave(&wl->irq_lock, flags); + b43legacy_interrupt_enable(dev, savedirqs); + mmiowb(); + spin_unlock_irqrestore(&wl->irq_lock, flags); +out_unlock_mutex: + mutex_unlock(&wl->mutex); + + return err; +} + +static int b43legacy_dev_set_key(struct ieee80211_hw *hw, + set_key_cmd cmd, + const u8 *local_addr, const u8 *addr, + struct ieee80211_key_conf *key) +{ + struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); + struct b43legacy_wldev *dev = wl->current_dev; + unsigned long flags; + int err = -EOPNOTSUPP; + + if (!dev) + return -ENODEV; + mutex_lock(&wl->mutex); + spin_lock_irqsave(&wl->irq_lock, flags); + + if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) { + err = -ENODEV; + } + spin_unlock_irqrestore(&wl->irq_lock, flags); + mutex_unlock(&wl->mutex); + b43legacydbg(wl, "Using software based encryption for " + "mac: " MAC_FMT "\n", MAC_ARG(addr)); + return err; +} + +static void b43legacy_set_multicast_list(struct ieee80211_hw *hw, + unsigned short netflags, + int mc_count) +{ + struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); + struct b43legacy_wldev *dev = wl->current_dev; + unsigned long flags; + + if (!dev) + return; + spin_lock_irqsave(&wl->irq_lock, flags); + if (wl->promisc != !!(netflags & IFF_PROMISC)) { + wl->promisc = !!(netflags & IFF_PROMISC); + if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) + b43legacy_adjust_opmode(dev); + } + spin_unlock_irqrestore(&wl->irq_lock, flags); +} + +static int b43legacy_config_interface(struct ieee80211_hw *hw, + int if_id, + struct ieee80211_if_conf *conf) +{ + struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); + struct b43legacy_wldev *dev = wl->current_dev; + unsigned long flags; + + if (!dev) + return -ENODEV; + mutex_lock(&wl->mutex); + spin_lock_irqsave(&wl->irq_lock, flags); + if (conf->type != IEEE80211_IF_TYPE_MNTR) { + B43legacy_WARN_ON(wl->if_id != if_id); + wl->bssid = conf->bssid; + if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) { + if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP)) { + B43legacy_WARN_ON(conf->type != + IEEE80211_IF_TYPE_AP); + b43legacy_set_ssid(dev, conf->ssid, + conf->ssid_len); + if (conf->beacon) + b43legacy_refresh_templates(dev, + conf->beacon); + } + b43legacy_write_mac_bssid_templates(dev); + } + } + spin_unlock_irqrestore(&wl->irq_lock, flags); + mutex_unlock(&wl->mutex); + + return 0; +} + +/* Locking: wl->mutex */ +static void b43legacy_wireless_core_stop(struct b43legacy_wldev *dev) +{ + struct b43legacy_wl *wl = dev->wl; + unsigned long flags; + + if (b43legacy_status(dev) < B43legacy_STAT_STARTED) + return; + b43legacy_set_status(dev, B43legacy_STAT_INITIALIZED); + + mutex_unlock(&wl->mutex); + /* Must unlock as it would otherwise deadlock. No races here. + * Cancel the possibly running self-rearming periodic work. */ + cancel_delayed_work_sync(&dev->periodic_work); + mutex_lock(&wl->mutex); + + ieee80211_stop_queues(wl->hw); /* FIXME this could cause a deadlock */ + + /* Disable and sync interrupts. */ + spin_lock_irqsave(&wl->irq_lock, flags); + dev->irq_savedstate = b43legacy_interrupt_disable(dev, + B43legacy_IRQ_ALL); + b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK); /* flush */ + spin_unlock_irqrestore(&wl->irq_lock, flags); + b43legacy_synchronize_irq(dev); + + b43legacy_mac_suspend(dev); + free_irq(dev->dev->irq, dev); + b43legacydbg(wl, "Wireless interface stopped\n"); +} + +/* Locking: wl->mutex */ +static int b43legacy_wireless_core_start(struct b43legacy_wldev *dev) +{ + int err; + + B43legacy_WARN_ON(b43legacy_status(dev) != B43legacy_STAT_INITIALIZED); + + drain_txstatus_queue(dev); + err = request_irq(dev->dev->irq, b43legacy_interrupt_handler, + IRQF_SHARED, KBUILD_MODNAME, dev); + if (err) { + b43legacyerr(dev->wl, "Cannot request IRQ-%d\n", + dev->dev->irq); + goto out; + } + /* We are ready to run. */ + b43legacy_set_status(dev, B43legacy_STAT_STARTED); + + /* Start data flow (TX/RX) */ + b43legacy_mac_enable(dev); + b43legacy_interrupt_enable(dev, dev->irq_savedstate); + ieee80211_start_queues(dev->wl->hw); + + /* Start maintenance work */ + b43legacy_periodic_tasks_setup(dev); + + b43legacydbg(dev->wl, "Wireless interface started\n"); +out: + return err; +} + +/* Get PHY and RADIO versioning numbers */ +static int b43legacy_phy_versioning(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + u32 tmp; + u8 analog_type; + u8 phy_type; + u8 phy_rev; + u16 radio_manuf; + u16 radio_ver; + u16 radio_rev; + int unsupported = 0; + + /* Get PHY versioning */ + tmp = b43legacy_read16(dev, B43legacy_MMIO_PHY_VER); + analog_type = (tmp & B43legacy_PHYVER_ANALOG) + >> B43legacy_PHYVER_ANALOG_SHIFT; + phy_type = (tmp & B43legacy_PHYVER_TYPE) >> B43legacy_PHYVER_TYPE_SHIFT; + phy_rev = (tmp & B43legacy_PHYVER_VERSION); + switch (phy_type) { + case B43legacy_PHYTYPE_B: + if (phy_rev != 2 && phy_rev != 4 + && phy_rev != 6 && phy_rev != 7) + unsupported = 1; + break; + case B43legacy_PHYTYPE_G: + if (phy_rev > 8) + unsupported = 1; + break; + default: + unsupported = 1; + }; + if (unsupported) { + b43legacyerr(dev->wl, "FOUND UNSUPPORTED PHY " + "(Analog %u, Type %u, Revision %u)\n", + analog_type, phy_type, phy_rev); + return -EOPNOTSUPP; + } + b43legacydbg(dev->wl, "Found PHY: Analog %u, Type %u, Revision %u\n", + analog_type, phy_type, phy_rev); + + + /* Get RADIO versioning */ + if (dev->dev->bus->chip_id == 0x4317) { + if (dev->dev->bus->chip_rev == 0) + tmp = 0x3205017F; + else if (dev->dev->bus->chip_rev == 1) + tmp = 0x4205017F; + else + tmp = 0x5205017F; + } else { + b43legacy_write16(dev, B43legacy_MMIO_RADIO_CONTROL, + B43legacy_RADIOCTL_ID); + tmp = b43legacy_read16(dev, B43legacy_MMIO_RADIO_DATA_HIGH); + tmp <<= 16; + b43legacy_write16(dev, B43legacy_MMIO_RADIO_CONTROL, + B43legacy_RADIOCTL_ID); + tmp |= b43legacy_read16(dev, B43legacy_MMIO_RADIO_DATA_LOW); + } + radio_manuf = (tmp & 0x00000FFF); + radio_ver = (tmp & 0x0FFFF000) >> 12; + radio_rev = (tmp & 0xF0000000) >> 28; + switch (phy_type) { + case B43legacy_PHYTYPE_B: + if ((radio_ver & 0xFFF0) != 0x2050) + unsupported = 1; + break; + case B43legacy_PHYTYPE_G: + if (radio_ver != 0x2050) + unsupported = 1; + break; + default: + B43legacy_BUG_ON(1); + } + if (unsupported) { + b43legacyerr(dev->wl, "FOUND UNSUPPORTED RADIO " + "(Manuf 0x%X, Version 0x%X, Revision %u)\n", + radio_manuf, radio_ver, radio_rev); + return -EOPNOTSUPP; + } + b43legacydbg(dev->wl, "Found Radio: Manuf 0x%X, Version 0x%X," + " Revision %u\n", radio_manuf, radio_ver, radio_rev); + + + phy->radio_manuf = radio_manuf; + phy->radio_ver = radio_ver; + phy->radio_rev = radio_rev; + + phy->analog = analog_type; + phy->type = phy_type; + phy->rev = phy_rev; + + return 0; +} + +static void setup_struct_phy_for_init(struct b43legacy_wldev *dev, + struct b43legacy_phy *phy) +{ + struct b43legacy_lopair *lo; + int i; + + memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig)); + memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos)); + + /* Flags */ + phy->locked = 0; + + phy->savedpctlreg = 0xFFFF; + phy->aci_enable = 0; + phy->aci_wlan_automatic = 0; + phy->aci_hw_rssi = 0; + + lo = phy->_lo_pairs; + if (lo) + memset(lo, 0, sizeof(struct b43legacy_lopair) * + B43legacy_LO_COUNT); + phy->max_lb_gain = 0; + phy->trsw_rx_gain = 0; + + /* Set default attenuation values. */ + phy->bbatt = b43legacy_default_baseband_attenuation(dev); + phy->rfatt = b43legacy_default_radio_attenuation(dev); + phy->txctl1 = b43legacy_default_txctl1(dev); + phy->txpwr_offset = 0; + + /* NRSSI */ + phy->nrssislope = 0; + for (i = 0; i < ARRAY_SIZE(phy->nrssi); i++) + phy->nrssi[i] = -1000; + for (i = 0; i < ARRAY_SIZE(phy->nrssi_lt); i++) + phy->nrssi_lt[i] = i; + + phy->lofcal = 0xFFFF; + phy->initval = 0xFFFF; + + spin_lock_init(&phy->lock); + phy->interfmode = B43legacy_INTERFMODE_NONE; + phy->channel = 0xFF; +} + +static void setup_struct_wldev_for_init(struct b43legacy_wldev *dev) +{ + /* Flags */ + dev->reg124_set_0x4 = 0; + + /* Stats */ + memset(&dev->stats, 0, sizeof(dev->stats)); + + setup_struct_phy_for_init(dev, &dev->phy); + + /* IRQ related flags */ + dev->irq_reason = 0; + memset(dev->dma_reason, 0, sizeof(dev->dma_reason)); + dev->irq_savedstate = B43legacy_IRQ_MASKTEMPLATE; + + dev->mac_suspended = 1; + + /* Noise calculation context */ + memset(&dev->noisecalc, 0, sizeof(dev->noisecalc)); +} + +static void b43legacy_imcfglo_timeouts_workaround(struct b43legacy_wldev *dev) +{ +#ifdef CONFIG_SSB_DRIVER_PCICORE + struct ssb_bus *bus = dev->dev->bus; + u32 tmp; + + if (bus->pcicore.dev && + bus->pcicore.dev->id.coreid == SSB_DEV_PCI && + bus->pcicore.dev->id.revision <= 5) { + /* IMCFGLO timeouts workaround. */ + tmp = ssb_read32(dev->dev, SSB_IMCFGLO); + tmp &= ~SSB_IMCFGLO_REQTO; + tmp &= ~SSB_IMCFGLO_SERTO; + switch (bus->bustype) { + case SSB_BUSTYPE_PCI: + case SSB_BUSTYPE_PCMCIA: + tmp |= 0x32; + break; + case SSB_BUSTYPE_SSB: + tmp |= 0x53; + break; + } + ssb_write32(dev->dev, SSB_IMCFGLO, tmp); + } +#endif /* CONFIG_SSB_DRIVER_PCICORE */ +} + +/* Shutdown a wireless core */ +/* Locking: wl->mutex */ +static void b43legacy_wireless_core_exit(struct b43legacy_wldev *dev) +{ + struct b43legacy_wl *wl = dev->wl; + struct b43legacy_phy *phy = &dev->phy; + + B43legacy_WARN_ON(b43legacy_status(dev) > B43legacy_STAT_INITIALIZED); + if (b43legacy_status(dev) != B43legacy_STAT_INITIALIZED) + return; + b43legacy_set_status(dev, B43legacy_STAT_UNINIT); + + mutex_unlock(&wl->mutex); + /* Must unlock as it would otherwise deadlock. No races here. + * Cancel possibly pending workqueues. */ + cancel_work_sync(&dev->restart_work); + mutex_lock(&wl->mutex); + + b43legacy_rng_exit(dev->wl); + b43legacy_pio_free(dev); + b43legacy_dma_free(dev); + b43legacy_chip_exit(dev); + b43legacy_radio_turn_off(dev); + b43legacy_switch_analog(dev, 0); + if (phy->dyn_tssi_tbl) + kfree(phy->tssi2dbm); + kfree(phy->lo_control); + phy->lo_control = NULL; + ssb_device_disable(dev->dev, 0); + ssb_bus_may_powerdown(dev->dev->bus); +} + +static void prepare_phy_data_for_init(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + int i; + + /* Set default attenuation values. */ + phy->bbatt = b43legacy_default_baseband_attenuation(dev); + phy->rfatt = b43legacy_default_radio_attenuation(dev); + phy->txctl1 = b43legacy_default_txctl1(dev); + phy->txctl2 = 0xFFFF; + phy->txpwr_offset = 0; + + /* NRSSI */ + phy->nrssislope = 0; + for (i = 0; i < ARRAY_SIZE(phy->nrssi); i++) + phy->nrssi[i] = -1000; + for (i = 0; i < ARRAY_SIZE(phy->nrssi_lt); i++) + phy->nrssi_lt[i] = i; + + phy->lofcal = 0xFFFF; + phy->initval = 0xFFFF; + + phy->aci_enable = 0; + phy->aci_wlan_automatic = 0; + phy->aci_hw_rssi = 0; + + phy->antenna_diversity = 0xFFFF; + memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig)); + memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos)); + + /* Flags */ + phy->calibrated = 0; + phy->locked = 0; + + if (phy->_lo_pairs) + memset(phy->_lo_pairs, 0, + sizeof(struct b43legacy_lopair) * B43legacy_LO_COUNT); + memset(phy->loopback_gain, 0, sizeof(phy->loopback_gain)); +} + +/* Initialize a wireless core */ +static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev) +{ + struct b43legacy_wl *wl = dev->wl; + struct ssb_bus *bus = dev->dev->bus; + struct b43legacy_phy *phy = &dev->phy; + struct ssb_sprom *sprom = &dev->dev->bus->sprom; + int err; + u32 hf; + u32 tmp; + + B43legacy_WARN_ON(b43legacy_status(dev) != B43legacy_STAT_UNINIT); + + err = ssb_bus_powerup(bus, 0); + if (err) + goto out; + if (!ssb_device_is_enabled(dev->dev)) { + tmp = phy->gmode ? B43legacy_TMSLOW_GMODE : 0; + b43legacy_wireless_core_reset(dev, tmp); + } + + if ((phy->type == B43legacy_PHYTYPE_B) || + (phy->type == B43legacy_PHYTYPE_G)) { + phy->_lo_pairs = kzalloc(sizeof(struct b43legacy_lopair) + * B43legacy_LO_COUNT, + GFP_KERNEL); + if (!phy->_lo_pairs) + return -ENOMEM; + } + setup_struct_wldev_for_init(dev); + + err = b43legacy_phy_init_tssi2dbm_table(dev); + if (err) + goto err_kfree_lo_control; + + /* Enable IRQ routing to this device. */ + ssb_pcicore_dev_irqvecs_enable(&bus->pcicore, dev->dev); + + b43legacy_imcfglo_timeouts_workaround(dev); + prepare_phy_data_for_init(dev); + b43legacy_phy_calibrate(dev); + err = b43legacy_chip_init(dev); + if (err) + goto err_kfree_tssitbl; + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, + B43legacy_SHM_SH_WLCOREREV, + dev->dev->id.revision); + hf = b43legacy_hf_read(dev); + if (phy->type == B43legacy_PHYTYPE_G) { + hf |= B43legacy_HF_SYMW; + if (phy->rev == 1) + hf |= B43legacy_HF_GDCW; + if (sprom->r1.boardflags_lo & B43legacy_BFL_PACTRL) + hf |= B43legacy_HF_OFDMPABOOST; + } else if (phy->type == B43legacy_PHYTYPE_B) { + hf |= B43legacy_HF_SYMW; + if (phy->rev >= 2 && phy->radio_ver == 0x2050) + hf &= ~B43legacy_HF_GDCW; + } + b43legacy_hf_write(dev, hf); + + /* Short/Long Retry Limit. + * The retry-limit is a 4-bit counter. Enforce this to avoid overflowing + * the chip-internal counter. + */ + tmp = limit_value(modparam_short_retry, 0, 0xF); + b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, + 0x0006, tmp); + tmp = limit_value(modparam_long_retry, 0, 0xF); + b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, + 0x0007, tmp); + + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, + 0x0044, 3); + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, + 0x0046, 2); + + /* Disable sending probe responses from firmware. + * Setting the MaxTime to one usec will always trigger + * a timeout, so we never send any probe resp. + * A timeout of zero is infinite. */ + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, + B43legacy_SHM_SH_PRMAXTIME, 1); + + b43legacy_rate_memory_init(dev); + + /* Minimum Contention Window */ + if (phy->type == B43legacy_PHYTYPE_B) + b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, + 0x0003, 31); + else + b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, + 0x0003, 15); + /* Maximum Contention Window */ + b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, + 0x0004, 1023); + + do { + if (b43legacy_using_pio(dev)) + err = b43legacy_pio_init(dev); + else { + err = b43legacy_dma_init(dev); + if (!err) + b43legacy_qos_init(dev); + } + } while (err == -EAGAIN); + if (err) + goto err_chip_exit; + + b43legacy_write16(dev, 0x0612, 0x0050); + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0416, 0x0050); + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0414, 0x01F4); + + ssb_bus_powerup(bus, 1); /* Enable dynamic PCTL */ + wl->bssid = NULL; + b43legacy_upload_card_macaddress(dev, NULL); + b43legacy_security_init(dev); + b43legacy_rng_init(wl); + + b43legacy_set_status(dev, B43legacy_STAT_INITIALIZED); + +out: + return err; + +err_chip_exit: + b43legacy_chip_exit(dev); +err_kfree_tssitbl: + if (phy->dyn_tssi_tbl) + kfree(phy->tssi2dbm); +err_kfree_lo_control: + kfree(phy->lo_control); + phy->lo_control = NULL; + ssb_bus_may_powerdown(bus); + B43legacy_WARN_ON(b43legacy_status(dev) != B43legacy_STAT_UNINIT); + return err; +} + +static int b43legacy_add_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); + struct b43legacy_wldev *dev; + unsigned long flags; + int err = -EOPNOTSUPP; + int did_init = 0; + + mutex_lock(&wl->mutex); + if ((conf->type != IEEE80211_IF_TYPE_MNTR) && + wl->operating) + goto out_mutex_unlock; + + b43legacydbg(wl, "Adding Interface type %d\n", conf->type); + + dev = wl->current_dev; + if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) { + err = b43legacy_wireless_core_init(dev); + if (err) + goto out_mutex_unlock; + did_init = 1; + } + if (b43legacy_status(dev) < B43legacy_STAT_STARTED) { + err = b43legacy_wireless_core_start(dev); + if (err) { + if (did_init) + b43legacy_wireless_core_exit(dev); + goto out_mutex_unlock; + } + } + + spin_lock_irqsave(&wl->irq_lock, flags); + switch (conf->type) { + case IEEE80211_IF_TYPE_MNTR: + wl->monitor++; + break; + default: + wl->operating = 1; + wl->if_id = conf->if_id; + wl->if_type = conf->type; + b43legacy_upload_card_macaddress(dev, conf->mac_addr); + } + b43legacy_adjust_opmode(dev); + spin_unlock_irqrestore(&wl->irq_lock, flags); + + err = 0; +out_mutex_unlock: + mutex_unlock(&wl->mutex); + + return err; +} + +static void b43legacy_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); + struct b43legacy_wldev *dev; + unsigned long flags; + + b43legacydbg(wl, "Removing Interface type %d\n", conf->type); + + mutex_lock(&wl->mutex); + if (conf->type == IEEE80211_IF_TYPE_MNTR) { + wl->monitor--; + B43legacy_WARN_ON(wl->monitor < 0); + } else { + B43legacy_WARN_ON(!wl->operating); + wl->operating = 0; + } + + dev = wl->current_dev; + if (!wl->operating && wl->monitor == 0) { + /* No interface left. */ + if (b43legacy_status(dev) >= B43legacy_STAT_STARTED) + b43legacy_wireless_core_stop(dev); + b43legacy_wireless_core_exit(dev); + } else { + /* Just monitor interfaces left. */ + spin_lock_irqsave(&wl->irq_lock, flags); + b43legacy_adjust_opmode(dev); + if (!wl->operating) + b43legacy_upload_card_macaddress(dev, NULL); + spin_unlock_irqrestore(&wl->irq_lock, flags); + } + mutex_unlock(&wl->mutex); +} + + +static const struct ieee80211_ops b43legacy_hw_ops = { + .tx = b43legacy_tx, + .conf_tx = b43legacy_conf_tx, + .add_interface = b43legacy_add_interface, + .remove_interface = b43legacy_remove_interface, + .config = b43legacy_dev_config, + .config_interface = b43legacy_config_interface, + .set_key = b43legacy_dev_set_key, + .set_multicast_list = b43legacy_set_multicast_list, + .get_stats = b43legacy_get_stats, + .get_tx_stats = b43legacy_get_tx_stats, +}; + +/* Hard-reset the chip. Do not call this directly. + * Use b43legacy_controller_restart() + */ +static void b43legacy_chip_reset(struct work_struct *work) +{ + struct b43legacy_wldev *dev = + container_of(work, struct b43legacy_wldev, restart_work); + struct b43legacy_wl *wl = dev->wl; + int err = 0; + int prev_status; + + mutex_lock(&wl->mutex); + + prev_status = b43legacy_status(dev); + /* Bring the device down... */ + if (prev_status >= B43legacy_STAT_STARTED) + b43legacy_wireless_core_stop(dev); + if (prev_status >= B43legacy_STAT_INITIALIZED) + b43legacy_wireless_core_exit(dev); + + /* ...and up again. */ + if (prev_status >= B43legacy_STAT_INITIALIZED) { + err = b43legacy_wireless_core_init(dev); + if (err) + goto out; + } + if (prev_status >= B43legacy_STAT_STARTED) { + err = b43legacy_wireless_core_start(dev); + if (err) { + b43legacy_wireless_core_exit(dev); + goto out; + } + } +out: + mutex_unlock(&wl->mutex); + if (err) + b43legacyerr(wl, "Controller restart FAILED\n"); + else + b43legacyinfo(wl, "Controller restarted\n"); +} + +static int b43legacy_setup_modes(struct b43legacy_wldev *dev, + int have_bphy, + int have_gphy) +{ + struct ieee80211_hw *hw = dev->wl->hw; + struct ieee80211_hw_mode *mode; + struct b43legacy_phy *phy = &dev->phy; + int cnt = 0; + int err; + + phy->possible_phymodes = 0; + for (; 1; cnt++) { + if (have_bphy) { + B43legacy_WARN_ON(cnt >= B43legacy_MAX_PHYHWMODES); + mode = &phy->hwmodes[cnt]; + + mode->mode = MODE_IEEE80211B; + mode->num_channels = b43legacy_bg_chantable_size; + mode->channels = b43legacy_bg_chantable; + mode->num_rates = b43legacy_b_ratetable_size; + mode->rates = b43legacy_b_ratetable; + err = ieee80211_register_hwmode(hw, mode); + if (err) + return err; + + phy->possible_phymodes |= B43legacy_PHYMODE_B; + have_bphy = 0; + continue; + } + if (have_gphy) { + B43legacy_WARN_ON(cnt >= B43legacy_MAX_PHYHWMODES); + mode = &phy->hwmodes[cnt]; + + mode->mode = MODE_IEEE80211G; + mode->num_channels = b43legacy_bg_chantable_size; + mode->channels = b43legacy_bg_chantable; + mode->num_rates = b43legacy_g_ratetable_size; + mode->rates = b43legacy_g_ratetable; + err = ieee80211_register_hwmode(hw, mode); + if (err) + return err; + + phy->possible_phymodes |= B43legacy_PHYMODE_G; + have_gphy = 0; + continue; + } + break; + } + + return 0; +} + +static void b43legacy_wireless_core_detach(struct b43legacy_wldev *dev) +{ + /* We release firmware that late to not be required to re-request + * is all the time when we reinit the core. */ + b43legacy_release_firmware(dev); +} + +static int b43legacy_wireless_core_attach(struct b43legacy_wldev *dev) +{ + struct b43legacy_wl *wl = dev->wl; + struct ssb_bus *bus = dev->dev->bus; + struct pci_dev *pdev = bus->host_pci; + int err; + int have_bphy = 0; + int have_gphy = 0; + u32 tmp; + + /* Do NOT do any device initialization here. + * Do it in wireless_core_init() instead. + * This function is for gathering basic information about the HW, only. + * Also some structs may be set up here. But most likely you want to + * have that in core_init(), too. + */ + + err = ssb_bus_powerup(bus, 0); + if (err) { + b43legacyerr(wl, "Bus powerup failed\n"); + goto out; + } + /* Get the PHY type. */ + if (dev->dev->id.revision >= 5) { + u32 tmshigh; + + tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH); + have_gphy = !!(tmshigh & B43legacy_TMSHIGH_GPHY); + if (!have_gphy) + have_bphy = 1; + } else if (dev->dev->id.revision == 4) + have_gphy = 1; + else + have_bphy = 1; + + /* Initialize LEDs structs. */ + err = b43legacy_leds_init(dev); + if (err) + goto err_powerdown; + + dev->phy.gmode = (have_gphy || have_bphy); + tmp = dev->phy.gmode ? B43legacy_TMSLOW_GMODE : 0; + b43legacy_wireless_core_reset(dev, tmp); + + err = b43legacy_phy_versioning(dev); + if (err) + goto err_leds_exit; + /* Check if this device supports multiband. */ + if (!pdev || + (pdev->device != 0x4312 && + pdev->device != 0x4319 && + pdev->device != 0x4324)) { + /* No multiband support. */ + have_bphy = 0; + have_gphy = 0; + switch (dev->phy.type) { + case B43legacy_PHYTYPE_B: + have_bphy = 1; + break; + case B43legacy_PHYTYPE_G: + have_gphy = 1; + break; + default: + B43legacy_BUG_ON(1); + } + } + dev->phy.gmode = (have_gphy || have_bphy); + tmp = dev->phy.gmode ? B43legacy_TMSLOW_GMODE : 0; + b43legacy_wireless_core_reset(dev, tmp); + + err = b43legacy_validate_chipaccess(dev); + if (err) + goto err_leds_exit; + err = b43legacy_setup_modes(dev, have_bphy, have_gphy); + if (err) + goto err_leds_exit; + + /* Now set some default "current_dev" */ + if (!wl->current_dev) + wl->current_dev = dev; + INIT_WORK(&dev->restart_work, b43legacy_chip_reset); + + b43legacy_radio_turn_off(dev); + b43legacy_switch_analog(dev, 0); + ssb_device_disable(dev->dev, 0); + ssb_bus_may_powerdown(bus); + +out: + return err; + +err_leds_exit: + b43legacy_leds_exit(dev); +err_powerdown: + ssb_bus_may_powerdown(bus); + return err; +} + +static void b43legacy_one_core_detach(struct ssb_device *dev) +{ + struct b43legacy_wldev *wldev; + struct b43legacy_wl *wl; + + wldev = ssb_get_drvdata(dev); + wl = wldev->wl; + cancel_work_sync(&wldev->restart_work); + b43legacy_debugfs_remove_device(wldev); + b43legacy_wireless_core_detach(wldev); + list_del(&wldev->list); + wl->nr_devs--; + ssb_set_drvdata(dev, NULL); + kfree(wldev); +} + +static int b43legacy_one_core_attach(struct ssb_device *dev, + struct b43legacy_wl *wl) +{ + struct b43legacy_wldev *wldev; + struct pci_dev *pdev; + int err = -ENOMEM; + + if (!list_empty(&wl->devlist)) { + /* We are not the first core on this chip. */ + pdev = dev->bus->host_pci; + /* Only special chips support more than one wireless + * core, although some of the other chips have more than + * one wireless core as well. Check for this and + * bail out early. + */ + if (!pdev || + ((pdev->device != 0x4321) && + (pdev->device != 0x4313) && + (pdev->device != 0x431A))) { + b43legacydbg(wl, "Ignoring unconnected 802.11 core\n"); + return -ENODEV; + } + } + + wldev = kzalloc(sizeof(*wldev), GFP_KERNEL); + if (!wldev) + goto out; + + wldev->dev = dev; + wldev->wl = wl; + b43legacy_set_status(wldev, B43legacy_STAT_UNINIT); + wldev->bad_frames_preempt = modparam_bad_frames_preempt; + tasklet_init(&wldev->isr_tasklet, + (void (*)(unsigned long))b43legacy_interrupt_tasklet, + (unsigned long)wldev); + if (modparam_pio) + wldev->__using_pio = 1; + INIT_LIST_HEAD(&wldev->list); + + err = b43legacy_wireless_core_attach(wldev); + if (err) + goto err_kfree_wldev; + + list_add(&wldev->list, &wl->devlist); + wl->nr_devs++; + ssb_set_drvdata(dev, wldev); + b43legacy_debugfs_add_device(wldev); +out: + return err; + +err_kfree_wldev: + kfree(wldev); + return err; +} + +static void b43legacy_sprom_fixup(struct ssb_bus *bus) +{ + /* boardflags workarounds */ + if (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE && + bus->boardinfo.type == 0x4E && + bus->boardinfo.rev > 0x40) + bus->sprom.r1.boardflags_lo |= B43legacy_BFL_PACTRL; + + /* Convert Antennagain values to Q5.2 */ + if (bus->sprom.r1.antenna_gain_bg == 0xFF) + bus->sprom.r1.antenna_gain_bg = 2; /* if unset, use 2 dBm */ + bus->sprom.r1.antenna_gain_bg <<= 2; +} + +static void b43legacy_wireless_exit(struct ssb_device *dev, + struct b43legacy_wl *wl) +{ + struct ieee80211_hw *hw = wl->hw; + + ssb_set_devtypedata(dev, NULL); + ieee80211_free_hw(hw); +} + +static int b43legacy_wireless_init(struct ssb_device *dev) +{ + struct ssb_sprom *sprom = &dev->bus->sprom; + struct ieee80211_hw *hw; + struct b43legacy_wl *wl; + int err = -ENOMEM; + + b43legacy_sprom_fixup(dev->bus); + + hw = ieee80211_alloc_hw(sizeof(*wl), &b43legacy_hw_ops); + if (!hw) { + b43legacyerr(NULL, "Could not allocate ieee80211 device\n"); + goto out; + } + + /* fill hw info */ + hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | + IEEE80211_HW_RX_INCLUDES_FCS; + hw->max_signal = 100; + hw->max_rssi = -110; + hw->max_noise = -110; + hw->queues = 1; /* FIXME: hardware has more queues */ + SET_IEEE80211_DEV(hw, dev->dev); + if (is_valid_ether_addr(sprom->r1.et1mac)) + SET_IEEE80211_PERM_ADDR(hw, sprom->r1.et1mac); + else + SET_IEEE80211_PERM_ADDR(hw, sprom->r1.il0mac); + + /* Get and initialize struct b43legacy_wl */ + wl = hw_to_b43legacy_wl(hw); + memset(wl, 0, sizeof(*wl)); + wl->hw = hw; + spin_lock_init(&wl->irq_lock); + spin_lock_init(&wl->leds_lock); + mutex_init(&wl->mutex); + INIT_LIST_HEAD(&wl->devlist); + + ssb_set_devtypedata(dev, wl); + b43legacyinfo(wl, "Broadcom %04X WLAN found\n", dev->bus->chip_id); + err = 0; +out: + return err; +} + +static int b43legacy_probe(struct ssb_device *dev, + const struct ssb_device_id *id) +{ + struct b43legacy_wl *wl; + int err; + int first = 0; + + wl = ssb_get_devtypedata(dev); + if (!wl) { + /* Probing the first core - setup common struct b43legacy_wl */ + first = 1; + err = b43legacy_wireless_init(dev); + if (err) + goto out; + wl = ssb_get_devtypedata(dev); + B43legacy_WARN_ON(!wl); + } + err = b43legacy_one_core_attach(dev, wl); + if (err) + goto err_wireless_exit; + + if (first) { + err = ieee80211_register_hw(wl->hw); + if (err) + goto err_one_core_detach; + } + +out: + return err; + +err_one_core_detach: + b43legacy_one_core_detach(dev); +err_wireless_exit: + if (first) + b43legacy_wireless_exit(dev, wl); + return err; +} + +static void b43legacy_remove(struct ssb_device *dev) +{ + struct b43legacy_wl *wl = ssb_get_devtypedata(dev); + struct b43legacy_wldev *wldev = ssb_get_drvdata(dev); + + B43legacy_WARN_ON(!wl); + if (wl->current_dev == wldev) + ieee80211_unregister_hw(wl->hw); + + b43legacy_one_core_detach(dev); + + if (list_empty(&wl->devlist)) + /* Last core on the chip unregistered. + * We can destroy common struct b43legacy_wl. + */ + b43legacy_wireless_exit(dev, wl); +} + +/* Perform a hardware reset. This can be called from any context. */ +void b43legacy_controller_restart(struct b43legacy_wldev *dev, + const char *reason) +{ + /* Must avoid requeueing, if we are in shutdown. */ + if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) + return; + b43legacyinfo(dev->wl, "Controller RESET (%s) ...\n", reason); + queue_work(dev->wl->hw->workqueue, &dev->restart_work); +} + +#ifdef CONFIG_PM + +static int b43legacy_suspend(struct ssb_device *dev, pm_message_t state) +{ + struct b43legacy_wldev *wldev = ssb_get_drvdata(dev); + struct b43legacy_wl *wl = wldev->wl; + + b43legacydbg(wl, "Suspending...\n"); + + mutex_lock(&wl->mutex); + wldev->suspend_init_status = b43legacy_status(wldev); + if (wldev->suspend_init_status >= B43legacy_STAT_STARTED) + b43legacy_wireless_core_stop(wldev); + if (wldev->suspend_init_status >= B43legacy_STAT_INITIALIZED) + b43legacy_wireless_core_exit(wldev); + mutex_unlock(&wl->mutex); + + b43legacydbg(wl, "Device suspended.\n"); + + return 0; +} + +static int b43legacy_resume(struct ssb_device *dev) +{ + struct b43legacy_wldev *wldev = ssb_get_drvdata(dev); + struct b43legacy_wl *wl = wldev->wl; + int err = 0; + + b43legacydbg(wl, "Resuming...\n"); + + mutex_lock(&wl->mutex); + if (wldev->suspend_init_status >= B43legacy_STAT_INITIALIZED) { + err = b43legacy_wireless_core_init(wldev); + if (err) { + b43legacyerr(wl, "Resume failed at core init\n"); + goto out; + } + } + if (wldev->suspend_init_status >= B43legacy_STAT_STARTED) { + err = b43legacy_wireless_core_start(wldev); + if (err) { + b43legacy_wireless_core_exit(wldev); + b43legacyerr(wl, "Resume failed at core start\n"); + goto out; + } + } + mutex_unlock(&wl->mutex); + + b43legacydbg(wl, "Device resumed.\n"); +out: + return err; +} + +#else /* CONFIG_PM */ +# define b43legacy_suspend NULL +# define b43legacy_resume NULL +#endif /* CONFIG_PM */ + +static struct ssb_driver b43legacy_ssb_driver = { + .name = KBUILD_MODNAME, + .id_table = b43legacy_ssb_tbl, + .probe = b43legacy_probe, + .remove = b43legacy_remove, + .suspend = b43legacy_suspend, + .resume = b43legacy_resume, +}; + +static int __init b43legacy_init(void) +{ + int err; + + b43legacy_debugfs_init(); + + err = ssb_driver_register(&b43legacy_ssb_driver); + if (err) + goto err_dfs_exit; + + return err; + +err_dfs_exit: + b43legacy_debugfs_exit(); + return err; +} + +static void __exit b43legacy_exit(void) +{ + ssb_driver_unregister(&b43legacy_ssb_driver); + b43legacy_debugfs_exit(); +} + +module_init(b43legacy_init) +module_exit(b43legacy_exit) diff --git a/drivers/net/wireless/b43legacy/main.h b/drivers/net/wireless/b43legacy/main.h new file mode 100644 index 00000000000..673935e67e6 --- /dev/null +++ b/drivers/net/wireless/b43legacy/main.h @@ -0,0 +1,147 @@ +/* + + Broadcom B43legacy wireless driver + + Copyright (c) 2005 Martin Langer , + Copyright (c) 2005 Stefano Brivio + Copyright (c) 2005, 2006 Michael Buesch + Copyright (c) 2005 Danny van Dyk + Copyright (c) 2005 Andreas Jaggi + Copyright (c) 2007 Larry Finger + + Some parts of the code in this file are derived from the ipw2200 + driver Copyright(c) 2003 - 2004 Intel Corporation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#ifndef B43legacy_MAIN_H_ +#define B43legacy_MAIN_H_ + +#include "b43legacy.h" + + +#define P4D_BYT3S(magic, nr_bytes) u8 __p4dding##magic[nr_bytes] +#define P4D_BYTES(line, nr_bytes) P4D_BYT3S(line, nr_bytes) +/* Magic helper macro to pad structures. Ignore those above. It's magic. */ +#define PAD_BYTES(nr_bytes) P4D_BYTES(__LINE__ , (nr_bytes)) + + +/* Lightweight function to convert a frequency (in Mhz) to a channel number. */ +static inline +u8 b43legacy_freq_to_channel_bg(int freq) +{ + u8 channel; + + if (freq == 2484) + channel = 14; + else + channel = (freq - 2407) / 5; + + return channel; +} +static inline +u8 b43legacy_freq_to_channel(struct b43legacy_wldev *dev, + int freq) +{ + return b43legacy_freq_to_channel_bg(freq); +} + +/* Lightweight function to convert a channel number to a frequency (in Mhz). */ +static inline +int b43legacy_channel_to_freq_bg(u8 channel) +{ + int freq; + + if (channel == 14) + freq = 2484; + else + freq = 2407 + (5 * channel); + + return freq; +} + +static inline +int b43legacy_channel_to_freq(struct b43legacy_wldev *dev, + u8 channel) +{ + return b43legacy_channel_to_freq_bg(channel); +} + +static inline +int b43legacy_is_cck_rate(int rate) +{ + return (rate == B43legacy_CCK_RATE_1MB || + rate == B43legacy_CCK_RATE_2MB || + rate == B43legacy_CCK_RATE_5MB || + rate == B43legacy_CCK_RATE_11MB); +} + +static inline +int b43legacy_is_ofdm_rate(int rate) +{ + return !b43legacy_is_cck_rate(rate); +} + +static inline +int b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev) +{ + /* function to return state of hardware enable of radio + * returns 0 if radio disabled, 1 if radio enabled + */ + struct b43legacy_phy *phy = &dev->phy; + + if (phy->rev >= 3) + return ((b43legacy_read32(dev, + B43legacy_MMIO_RADIO_HWENABLED_HI) + & B43legacy_MMIO_RADIO_HWENABLED_HI_MASK) + == 0) ? 1 : 0; + else + return ((b43legacy_read16(dev, + B43legacy_MMIO_RADIO_HWENABLED_LO) + & B43legacy_MMIO_RADIO_HWENABLED_LO_MASK) + == 0) ? 0 : 1; +} + +void b43legacy_tsf_read(struct b43legacy_wldev *dev, u64 *tsf); +void b43legacy_tsf_write(struct b43legacy_wldev *dev, u64 tsf); + +u32 b43legacy_shm_read32(struct b43legacy_wldev *dev, + u16 routing, u16 offset); +u16 b43legacy_shm_read16(struct b43legacy_wldev *dev, + u16 routing, u16 offset); +void b43legacy_shm_write32(struct b43legacy_wldev *dev, + u16 routing, u16 offset, + u32 value); +void b43legacy_shm_write16(struct b43legacy_wldev *dev, + u16 routing, u16 offset, + u16 value); + +u32 b43legacy_hf_read(struct b43legacy_wldev *dev); +void b43legacy_hf_write(struct b43legacy_wldev *dev, u32 value); + +void b43legacy_dummy_transmission(struct b43legacy_wldev *dev); + +void b43legacy_wireless_core_reset(struct b43legacy_wldev *dev, u32 flags); + +void b43legacy_mac_suspend(struct b43legacy_wldev *dev); +void b43legacy_mac_enable(struct b43legacy_wldev *dev); + +void b43legacy_controller_restart(struct b43legacy_wldev *dev, + const char *reason); + +#endif /* B43legacy_MAIN_H_ */ diff --git a/drivers/net/wireless/b43legacy/phy.c b/drivers/net/wireless/b43legacy/phy.c new file mode 100644 index 00000000000..f9edbd5f300 --- /dev/null +++ b/drivers/net/wireless/b43legacy/phy.c @@ -0,0 +1,2265 @@ +/* + + Broadcom B43legacy wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + Copyright (c) 2007 Larry Finger + + Some parts of the code in this file are derived from the ipw2200 + driver Copyright(c) 2003 - 2004 Intel Corporation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include +#include +#include + +#include "b43legacy.h" +#include "phy.h" +#include "main.h" +#include "radio.h" +#include "ilt.h" + + +static const s8 b43legacy_tssi2dbm_b_table[] = { + 0x4D, 0x4C, 0x4B, 0x4A, + 0x4A, 0x49, 0x48, 0x47, + 0x47, 0x46, 0x45, 0x45, + 0x44, 0x43, 0x42, 0x42, + 0x41, 0x40, 0x3F, 0x3E, + 0x3D, 0x3C, 0x3B, 0x3A, + 0x39, 0x38, 0x37, 0x36, + 0x35, 0x34, 0x32, 0x31, + 0x30, 0x2F, 0x2D, 0x2C, + 0x2B, 0x29, 0x28, 0x26, + 0x25, 0x23, 0x21, 0x1F, + 0x1D, 0x1A, 0x17, 0x14, + 0x10, 0x0C, 0x06, 0x00, + -7, -7, -7, -7, + -7, -7, -7, -7, + -7, -7, -7, -7, +}; + +static const s8 b43legacy_tssi2dbm_g_table[] = { + 77, 77, 77, 76, + 76, 76, 75, 75, + 74, 74, 73, 73, + 73, 72, 72, 71, + 71, 70, 70, 69, + 68, 68, 67, 67, + 66, 65, 65, 64, + 63, 63, 62, 61, + 60, 59, 58, 57, + 56, 55, 54, 53, + 52, 50, 49, 47, + 45, 43, 40, 37, + 33, 28, 22, 14, + 5, -7, -20, -20, + -20, -20, -20, -20, + -20, -20, -20, -20, +}; + +static void b43legacy_phy_initg(struct b43legacy_wldev *dev); + + +static inline +void b43legacy_voluntary_preempt(void) +{ + B43legacy_BUG_ON(!(!in_atomic() && !in_irq() && + !in_interrupt() && !irqs_disabled())); +#ifndef CONFIG_PREEMPT + cond_resched(); +#endif /* CONFIG_PREEMPT */ +} + +void b43legacy_raw_phy_lock(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + + B43legacy_WARN_ON(!irqs_disabled()); + if (b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD) == 0) { + phy->locked = 0; + return; + } + if (dev->dev->id.revision < 3) { + b43legacy_mac_suspend(dev); + spin_lock(&phy->lock); + } else { + if (!b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) + b43legacy_power_saving_ctl_bits(dev, -1, 1); + } + phy->locked = 1; +} + +void b43legacy_raw_phy_unlock(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + + B43legacy_WARN_ON(!irqs_disabled()); + if (dev->dev->id.revision < 3) { + if (phy->locked) { + spin_unlock(&phy->lock); + b43legacy_mac_enable(dev); + } + } else { + if (!b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) + b43legacy_power_saving_ctl_bits(dev, -1, -1); + } + phy->locked = 0; +} + +u16 b43legacy_phy_read(struct b43legacy_wldev *dev, u16 offset) +{ + b43legacy_write16(dev, B43legacy_MMIO_PHY_CONTROL, offset); + return b43legacy_read16(dev, B43legacy_MMIO_PHY_DATA); +} + +void b43legacy_phy_write(struct b43legacy_wldev *dev, u16 offset, u16 val) +{ + b43legacy_write16(dev, B43legacy_MMIO_PHY_CONTROL, offset); + mmiowb(); + b43legacy_write16(dev, B43legacy_MMIO_PHY_DATA, val); +} + +void b43legacy_phy_calibrate(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + + b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD); /* Dummy read. */ + if (phy->calibrated) + return; + if (phy->type == B43legacy_PHYTYPE_G && phy->rev == 1) { + b43legacy_wireless_core_reset(dev, 0); + b43legacy_phy_initg(dev); + b43legacy_wireless_core_reset(dev, B43legacy_TMSLOW_GMODE); + } + phy->calibrated = 1; +} + +/* intialize B PHY power control + * as described in http://bcm-specs.sipsolutions.net/InitPowerControl + */ +static void b43legacy_phy_init_pctl(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 saved_batt = 0; + u16 saved_ratt = 0; + u16 saved_txctl1 = 0; + int must_reset_txpower = 0; + + B43legacy_BUG_ON(!(phy->type == B43legacy_PHYTYPE_B || + phy->type == B43legacy_PHYTYPE_G)); + if (is_bcm_board_vendor(dev) && + (dev->dev->bus->boardinfo.type == 0x0416)) + return; + + b43legacy_phy_write(dev, 0x0028, 0x8018); + b43legacy_write16(dev, 0x03E6, b43legacy_read16(dev, 0x03E6) & 0xFFDF); + + if (phy->type == B43legacy_PHYTYPE_G) { + if (!phy->gmode) + return; + b43legacy_phy_write(dev, 0x047A, 0xC111); + } + if (phy->savedpctlreg != 0xFFFF) + return; +#ifdef CONFIG_B43LEGACY_DEBUG + if (phy->manual_txpower_control) + return; +#endif + + if (phy->type == B43legacy_PHYTYPE_B && + phy->rev >= 2 && + phy->radio_ver == 0x2050) + b43legacy_radio_write16(dev, 0x0076, + b43legacy_radio_read16(dev, 0x0076) + | 0x0084); + else { + saved_batt = phy->bbatt; + saved_ratt = phy->rfatt; + saved_txctl1 = phy->txctl1; + if ((phy->radio_rev >= 6) && (phy->radio_rev <= 8) + && /*FIXME: incomplete specs for 5 < revision < 9 */ 0) + b43legacy_radio_set_txpower_bg(dev, 0xB, 0x1F, 0); + else + b43legacy_radio_set_txpower_bg(dev, 0xB, 9, 0); + must_reset_txpower = 1; + } + b43legacy_dummy_transmission(dev); + + phy->savedpctlreg = b43legacy_phy_read(dev, B43legacy_PHY_G_PCTL); + + if (must_reset_txpower) + b43legacy_radio_set_txpower_bg(dev, saved_batt, saved_ratt, + saved_txctl1); + else + b43legacy_radio_write16(dev, 0x0076, b43legacy_radio_read16(dev, + 0x0076) & 0xFF7B); + b43legacy_radio_clear_tssi(dev); +} + +static void b43legacy_phy_agcsetup(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 offset = 0x0000; + + if (phy->rev == 1) + offset = 0x4C00; + + b43legacy_ilt_write(dev, offset, 0x00FE); + b43legacy_ilt_write(dev, offset + 1, 0x000D); + b43legacy_ilt_write(dev, offset + 2, 0x0013); + b43legacy_ilt_write(dev, offset + 3, 0x0019); + + if (phy->rev == 1) { + b43legacy_ilt_write(dev, 0x1800, 0x2710); + b43legacy_ilt_write(dev, 0x1801, 0x9B83); + b43legacy_ilt_write(dev, 0x1802, 0x9B83); + b43legacy_ilt_write(dev, 0x1803, 0x0F8D); + b43legacy_phy_write(dev, 0x0455, 0x0004); + } + + b43legacy_phy_write(dev, 0x04A5, (b43legacy_phy_read(dev, 0x04A5) + & 0x00FF) | 0x5700); + b43legacy_phy_write(dev, 0x041A, (b43legacy_phy_read(dev, 0x041A) + & 0xFF80) | 0x000F); + b43legacy_phy_write(dev, 0x041A, (b43legacy_phy_read(dev, 0x041A) + & 0xC07F) | 0x2B80); + b43legacy_phy_write(dev, 0x048C, (b43legacy_phy_read(dev, 0x048C) + & 0xF0FF) | 0x0300); + + b43legacy_radio_write16(dev, 0x007A, + b43legacy_radio_read16(dev, 0x007A) + | 0x0008); + + b43legacy_phy_write(dev, 0x04A0, (b43legacy_phy_read(dev, 0x04A0) + & 0xFFF0) | 0x0008); + b43legacy_phy_write(dev, 0x04A1, (b43legacy_phy_read(dev, 0x04A1) + & 0xF0FF) | 0x0600); + b43legacy_phy_write(dev, 0x04A2, (b43legacy_phy_read(dev, 0x04A2) + & 0xF0FF) | 0x0700); + b43legacy_phy_write(dev, 0x04A0, (b43legacy_phy_read(dev, 0x04A0) + & 0xF0FF) | 0x0100); + + if (phy->rev == 1) + b43legacy_phy_write(dev, 0x04A2, + (b43legacy_phy_read(dev, 0x04A2) + & 0xFFF0) | 0x0007); + + b43legacy_phy_write(dev, 0x0488, (b43legacy_phy_read(dev, 0x0488) + & 0xFF00) | 0x001C); + b43legacy_phy_write(dev, 0x0488, (b43legacy_phy_read(dev, 0x0488) + & 0xC0FF) | 0x0200); + b43legacy_phy_write(dev, 0x0496, (b43legacy_phy_read(dev, 0x0496) + & 0xFF00) | 0x001C); + b43legacy_phy_write(dev, 0x0489, (b43legacy_phy_read(dev, 0x0489) + & 0xFF00) | 0x0020); + b43legacy_phy_write(dev, 0x0489, (b43legacy_phy_read(dev, 0x0489) + & 0xC0FF) | 0x0200); + b43legacy_phy_write(dev, 0x0482, (b43legacy_phy_read(dev, 0x0482) + & 0xFF00) | 0x002E); + b43legacy_phy_write(dev, 0x0496, (b43legacy_phy_read(dev, 0x0496) + & 0x00FF) | 0x1A00); + b43legacy_phy_write(dev, 0x0481, (b43legacy_phy_read(dev, 0x0481) + & 0xFF00) | 0x0028); + b43legacy_phy_write(dev, 0x0481, (b43legacy_phy_read(dev, 0x0481) + & 0x00FF) | 0x2C00); + + if (phy->rev == 1) { + b43legacy_phy_write(dev, 0x0430, 0x092B); + b43legacy_phy_write(dev, 0x041B, + (b43legacy_phy_read(dev, 0x041B) + & 0xFFE1) | 0x0002); + } else { + b43legacy_phy_write(dev, 0x041B, + b43legacy_phy_read(dev, 0x041B) & 0xFFE1); + b43legacy_phy_write(dev, 0x041F, 0x287A); + b43legacy_phy_write(dev, 0x0420, + (b43legacy_phy_read(dev, 0x0420) + & 0xFFF0) | 0x0004); + } + + if (phy->rev > 2) { + b43legacy_phy_write(dev, 0x0422, 0x287A); + b43legacy_phy_write(dev, 0x0420, + (b43legacy_phy_read(dev, 0x0420) + & 0x0FFF) | 0x3000); + } + + b43legacy_phy_write(dev, 0x04A8, (b43legacy_phy_read(dev, 0x04A8) + & 0x8080) | 0x7874); + b43legacy_phy_write(dev, 0x048E, 0x1C00); + + if (phy->rev == 1) { + b43legacy_phy_write(dev, 0x04AB, + (b43legacy_phy_read(dev, 0x04AB) + & 0xF0FF) | 0x0600); + b43legacy_phy_write(dev, 0x048B, 0x005E); + b43legacy_phy_write(dev, 0x048C, + (b43legacy_phy_read(dev, 0x048C) & 0xFF00) + | 0x001E); + b43legacy_phy_write(dev, 0x048D, 0x0002); + } + + b43legacy_ilt_write(dev, offset + 0x0800, 0); + b43legacy_ilt_write(dev, offset + 0x0801, 7); + b43legacy_ilt_write(dev, offset + 0x0802, 16); + b43legacy_ilt_write(dev, offset + 0x0803, 28); + + if (phy->rev >= 6) { + b43legacy_phy_write(dev, 0x0426, + (b43legacy_phy_read(dev, 0x0426) & 0xFFFC)); + b43legacy_phy_write(dev, 0x0426, + (b43legacy_phy_read(dev, 0x0426) & 0xEFFF)); + } +} + +static void b43legacy_phy_setupg(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 i; + + B43legacy_BUG_ON(phy->type != B43legacy_PHYTYPE_G); + if (phy->rev == 1) { + b43legacy_phy_write(dev, 0x0406, 0x4F19); + b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, + (b43legacy_phy_read(dev, + B43legacy_PHY_G_CRS) & 0xFC3F) | 0x0340); + b43legacy_phy_write(dev, 0x042C, 0x005A); + b43legacy_phy_write(dev, 0x0427, 0x001A); + + for (i = 0; i < B43legacy_ILT_FINEFREQG_SIZE; i++) + b43legacy_ilt_write(dev, 0x5800 + i, + b43legacy_ilt_finefreqg[i]); + for (i = 0; i < B43legacy_ILT_NOISEG1_SIZE; i++) + b43legacy_ilt_write(dev, 0x1800 + i, + b43legacy_ilt_noiseg1[i]); + for (i = 0; i < B43legacy_ILT_ROTOR_SIZE; i++) + b43legacy_ilt_write32(dev, 0x2000 + i, + b43legacy_ilt_rotor[i]); + } else { + /* nrssi values are signed 6-bit values. Why 0x7654 here? */ + b43legacy_nrssi_hw_write(dev, 0xBA98, (s16)0x7654); + + if (phy->rev == 2) { + b43legacy_phy_write(dev, 0x04C0, 0x1861); + b43legacy_phy_write(dev, 0x04C1, 0x0271); + } else if (phy->rev > 2) { + b43legacy_phy_write(dev, 0x04C0, 0x0098); + b43legacy_phy_write(dev, 0x04C1, 0x0070); + b43legacy_phy_write(dev, 0x04C9, 0x0080); + } + b43legacy_phy_write(dev, 0x042B, b43legacy_phy_read(dev, + 0x042B) | 0x800); + + for (i = 0; i < 64; i++) + b43legacy_ilt_write(dev, 0x4000 + i, i); + for (i = 0; i < B43legacy_ILT_NOISEG2_SIZE; i++) + b43legacy_ilt_write(dev, 0x1800 + i, + b43legacy_ilt_noiseg2[i]); + } + + if (phy->rev <= 2) + for (i = 0; i < B43legacy_ILT_NOISESCALEG_SIZE; i++) + b43legacy_ilt_write(dev, 0x1400 + i, + b43legacy_ilt_noisescaleg1[i]); + else if ((phy->rev >= 7) && (b43legacy_phy_read(dev, 0x0449) & 0x0200)) + for (i = 0; i < B43legacy_ILT_NOISESCALEG_SIZE; i++) + b43legacy_ilt_write(dev, 0x1400 + i, + b43legacy_ilt_noisescaleg3[i]); + else + for (i = 0; i < B43legacy_ILT_NOISESCALEG_SIZE; i++) + b43legacy_ilt_write(dev, 0x1400 + i, + b43legacy_ilt_noisescaleg2[i]); + + if (phy->rev == 2) + for (i = 0; i < B43legacy_ILT_SIGMASQR_SIZE; i++) + b43legacy_ilt_write(dev, 0x5000 + i, + b43legacy_ilt_sigmasqr1[i]); + else if ((phy->rev > 2) && (phy->rev <= 8)) + for (i = 0; i < B43legacy_ILT_SIGMASQR_SIZE; i++) + b43legacy_ilt_write(dev, 0x5000 + i, + b43legacy_ilt_sigmasqr2[i]); + + if (phy->rev == 1) { + for (i = 0; i < B43legacy_ILT_RETARD_SIZE; i++) + b43legacy_ilt_write32(dev, 0x2400 + i, + b43legacy_ilt_retard[i]); + for (i = 4; i < 20; i++) + b43legacy_ilt_write(dev, 0x5400 + i, 0x0020); + b43legacy_phy_agcsetup(dev); + + if (is_bcm_board_vendor(dev) && + (dev->dev->bus->boardinfo.type == 0x0416) && + (dev->dev->bus->boardinfo.rev == 0x0017)) + return; + + b43legacy_ilt_write(dev, 0x5001, 0x0002); + b43legacy_ilt_write(dev, 0x5002, 0x0001); + } else { + for (i = 0; i <= 0x20; i++) + b43legacy_ilt_write(dev, 0x1000 + i, 0x0820); + b43legacy_phy_agcsetup(dev); + b43legacy_phy_read(dev, 0x0400); /* dummy read */ + b43legacy_phy_write(dev, 0x0403, 0x1000); + b43legacy_ilt_write(dev, 0x3C02, 0x000F); + b43legacy_ilt_write(dev, 0x3C03, 0x0014); + + if (is_bcm_board_vendor(dev) && + (dev->dev->bus->boardinfo.type == 0x0416) && + (dev->dev->bus->boardinfo.rev == 0x0017)) + return; + + b43legacy_ilt_write(dev, 0x0401, 0x0002); + b43legacy_ilt_write(dev, 0x0402, 0x0001); + } +} + +/* Initialize the APHY portion of a GPHY. */ +static void b43legacy_phy_inita(struct b43legacy_wldev *dev) +{ + + might_sleep(); + + b43legacy_phy_setupg(dev); + if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_PACTRL) + b43legacy_phy_write(dev, 0x046E, 0x03CF); +} + +static void b43legacy_phy_initb2(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 offset; + int val; + + b43legacy_write16(dev, 0x03EC, 0x3F22); + b43legacy_phy_write(dev, 0x0020, 0x301C); + b43legacy_phy_write(dev, 0x0026, 0x0000); + b43legacy_phy_write(dev, 0x0030, 0x00C6); + b43legacy_phy_write(dev, 0x0088, 0x3E00); + val = 0x3C3D; + for (offset = 0x0089; offset < 0x00A7; offset++) { + b43legacy_phy_write(dev, offset, val); + val -= 0x0202; + } + b43legacy_phy_write(dev, 0x03E4, 0x3000); + if (phy->channel == 0xFF) + b43legacy_radio_selectchannel(dev, + B43legacy_RADIO_DEFAULT_CHANNEL_BG, + 0); + else + b43legacy_radio_selectchannel(dev, phy->channel, 0); + if (phy->radio_ver != 0x2050) { + b43legacy_radio_write16(dev, 0x0075, 0x0080); + b43legacy_radio_write16(dev, 0x0079, 0x0081); + } + b43legacy_radio_write16(dev, 0x0050, 0x0020); + b43legacy_radio_write16(dev, 0x0050, 0x0023); + if (phy->radio_ver == 0x2050) { + b43legacy_radio_write16(dev, 0x0050, 0x0020); + b43legacy_radio_write16(dev, 0x005A, 0x0070); + b43legacy_radio_write16(dev, 0x005B, 0x007B); + b43legacy_radio_write16(dev, 0x005C, 0x00B0); + b43legacy_radio_write16(dev, 0x007A, 0x000F); + b43legacy_phy_write(dev, 0x0038, 0x0677); + b43legacy_radio_init2050(dev); + } + b43legacy_phy_write(dev, 0x0014, 0x0080); + b43legacy_phy_write(dev, 0x0032, 0x00CA); + b43legacy_phy_write(dev, 0x0032, 0x00CC); + b43legacy_phy_write(dev, 0x0035, 0x07C2); + b43legacy_phy_lo_b_measure(dev); + b43legacy_phy_write(dev, 0x0026, 0xCC00); + if (phy->radio_ver != 0x2050) + b43legacy_phy_write(dev, 0x0026, 0xCE00); + b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, 0x1000); + b43legacy_phy_write(dev, 0x002A, 0x88A3); + if (phy->radio_ver != 0x2050) + b43legacy_phy_write(dev, 0x002A, 0x88C2); + b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF); + b43legacy_phy_init_pctl(dev); +} + +static void b43legacy_phy_initb4(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 offset; + u16 val; + + b43legacy_write16(dev, 0x03EC, 0x3F22); + b43legacy_phy_write(dev, 0x0020, 0x301C); + b43legacy_phy_write(dev, 0x0026, 0x0000); + b43legacy_phy_write(dev, 0x0030, 0x00C6); + b43legacy_phy_write(dev, 0x0088, 0x3E00); + val = 0x3C3D; + for (offset = 0x0089; offset < 0x00A7; offset++) { + b43legacy_phy_write(dev, offset, val); + val -= 0x0202; + } + b43legacy_phy_write(dev, 0x03E4, 0x3000); + if (phy->channel == 0xFF) + b43legacy_radio_selectchannel(dev, + B43legacy_RADIO_DEFAULT_CHANNEL_BG, + 0); + else + b43legacy_radio_selectchannel(dev, phy->channel, 0); + if (phy->radio_ver != 0x2050) { + b43legacy_radio_write16(dev, 0x0075, 0x0080); + b43legacy_radio_write16(dev, 0x0079, 0x0081); + } + b43legacy_radio_write16(dev, 0x0050, 0x0020); + b43legacy_radio_write16(dev, 0x0050, 0x0023); + if (phy->radio_ver == 0x2050) { + b43legacy_radio_write16(dev, 0x0050, 0x0020); + b43legacy_radio_write16(dev, 0x005A, 0x0070); + b43legacy_radio_write16(dev, 0x005B, 0x007B); + b43legacy_radio_write16(dev, 0x005C, 0x00B0); + b43legacy_radio_write16(dev, 0x007A, 0x000F); + b43legacy_phy_write(dev, 0x0038, 0x0677); + b43legacy_radio_init2050(dev); + } + b43legacy_phy_write(dev, 0x0014, 0x0080); + b43legacy_phy_write(dev, 0x0032, 0x00CA); + if (phy->radio_ver == 0x2050) + b43legacy_phy_write(dev, 0x0032, 0x00E0); + b43legacy_phy_write(dev, 0x0035, 0x07C2); + + b43legacy_phy_lo_b_measure(dev); + + b43legacy_phy_write(dev, 0x0026, 0xCC00); + if (phy->radio_ver == 0x2050) + b43legacy_phy_write(dev, 0x0026, 0xCE00); + b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, 0x1100); + b43legacy_phy_write(dev, 0x002A, 0x88A3); + if (phy->radio_ver == 0x2050) + b43legacy_phy_write(dev, 0x002A, 0x88C2); + b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF); + if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_RSSI) { + b43legacy_calc_nrssi_slope(dev); + b43legacy_calc_nrssi_threshold(dev); + } + b43legacy_phy_init_pctl(dev); +} + +static void b43legacy_phy_initb5(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 offset; + u16 value; + u8 old_channel; + + if (phy->analog == 1) + b43legacy_radio_write16(dev, 0x007A, + b43legacy_radio_read16(dev, 0x007A) + | 0x0050); + if (!is_bcm_board_vendor(dev) && + (dev->dev->bus->boardinfo.type != 0x0416)) { + value = 0x2120; + for (offset = 0x00A8 ; offset < 0x00C7; offset++) { + b43legacy_phy_write(dev, offset, value); + value += 0x0202; + } + } + b43legacy_phy_write(dev, 0x0035, + (b43legacy_phy_read(dev, 0x0035) & 0xF0FF) + | 0x0700); + if (phy->radio_ver == 0x2050) + b43legacy_phy_write(dev, 0x0038, 0x0667); + + if (phy->gmode) { + if (phy->radio_ver == 0x2050) { + b43legacy_radio_write16(dev, 0x007A, + b43legacy_radio_read16(dev, 0x007A) + | 0x0020); + b43legacy_radio_write16(dev, 0x0051, + b43legacy_radio_read16(dev, 0x0051) + | 0x0004); + } + b43legacy_write16(dev, B43legacy_MMIO_PHY_RADIO, 0x0000); + + b43legacy_phy_write(dev, 0x0802, b43legacy_phy_read(dev, 0x0802) + | 0x0100); + b43legacy_phy_write(dev, 0x042B, b43legacy_phy_read(dev, 0x042B) + | 0x2000); + + b43legacy_phy_write(dev, 0x001C, 0x186A); + + b43legacy_phy_write(dev, 0x0013, (b43legacy_phy_read(dev, + 0x0013) & 0x00FF) | 0x1900); + b43legacy_phy_write(dev, 0x0035, (b43legacy_phy_read(dev, + 0x0035) & 0xFFC0) | 0x0064); + b43legacy_phy_write(dev, 0x005D, (b43legacy_phy_read(dev, + 0x005D) & 0xFF80) | 0x000A); + } + + if (dev->bad_frames_preempt) + b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD, + b43legacy_phy_read(dev, + B43legacy_PHY_RADIO_BITFIELD) | (1 << 11)); + + if (phy->analog == 1) { + b43legacy_phy_write(dev, 0x0026, 0xCE00); + b43legacy_phy_write(dev, 0x0021, 0x3763); + b43legacy_phy_write(dev, 0x0022, 0x1BC3); + b43legacy_phy_write(dev, 0x0023, 0x06F9); + b43legacy_phy_write(dev, 0x0024, 0x037E); + } else + b43legacy_phy_write(dev, 0x0026, 0xCC00); + b43legacy_phy_write(dev, 0x0030, 0x00C6); + b43legacy_write16(dev, 0x03EC, 0x3F22); + + if (phy->analog == 1) + b43legacy_phy_write(dev, 0x0020, 0x3E1C); + else + b43legacy_phy_write(dev, 0x0020, 0x301C); + + if (phy->analog == 0) + b43legacy_write16(dev, 0x03E4, 0x3000); + + old_channel = (phy->channel == 0xFF) ? 1 : phy->channel; + /* Force to channel 7, even if not supported. */ + b43legacy_radio_selectchannel(dev, 7, 0); + + if (phy->radio_ver != 0x2050) { + b43legacy_radio_write16(dev, 0x0075, 0x0080); + b43legacy_radio_write16(dev, 0x0079, 0x0081); + } + + b43legacy_radio_write16(dev, 0x0050, 0x0020); + b43legacy_radio_write16(dev, 0x0050, 0x0023); + + if (phy->radio_ver == 0x2050) { + b43legacy_radio_write16(dev, 0x0050, 0x0020); + b43legacy_radio_write16(dev, 0x005A, 0x0070); + } + + b43legacy_radio_write16(dev, 0x005B, 0x007B); + b43legacy_radio_write16(dev, 0x005C, 0x00B0); + + b43legacy_radio_write16(dev, 0x007A, b43legacy_radio_read16(dev, + 0x007A) | 0x0007); + + b43legacy_radio_selectchannel(dev, old_channel, 0); + + b43legacy_phy_write(dev, 0x0014, 0x0080); + b43legacy_phy_write(dev, 0x0032, 0x00CA); + b43legacy_phy_write(dev, 0x002A, 0x88A3); + + b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF); + + if (phy->radio_ver == 0x2050) + b43legacy_radio_write16(dev, 0x005D, 0x000D); + + b43legacy_write16(dev, 0x03E4, (b43legacy_read16(dev, 0x03E4) & + 0xFFC0) | 0x0004); +} + +static void b43legacy_phy_initb6(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 offset; + u16 val; + u8 old_channel; + + b43legacy_phy_write(dev, 0x003E, 0x817A); + b43legacy_radio_write16(dev, 0x007A, + (b43legacy_radio_read16(dev, 0x007A) | 0x0058)); + if (phy->radio_rev == 4 || + phy->radio_rev == 5) { + b43legacy_radio_write16(dev, 0x0051, 0x0037); + b43legacy_radio_write16(dev, 0x0052, 0x0070); + b43legacy_radio_write16(dev, 0x0053, 0x00B3); + b43legacy_radio_write16(dev, 0x0054, 0x009B); + b43legacy_radio_write16(dev, 0x005A, 0x0088); + b43legacy_radio_write16(dev, 0x005B, 0x0088); + b43legacy_radio_write16(dev, 0x005D, 0x0088); + b43legacy_radio_write16(dev, 0x005E, 0x0088); + b43legacy_radio_write16(dev, 0x007D, 0x0088); + b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, + B43legacy_UCODEFLAGS_OFFSET, + (b43legacy_shm_read32(dev, + B43legacy_SHM_SHARED, + B43legacy_UCODEFLAGS_OFFSET) + | 0x00000200)); + } + if (phy->radio_rev == 8) { + b43legacy_radio_write16(dev, 0x0051, 0x0000); + b43legacy_radio_write16(dev, 0x0052, 0x0040); + b43legacy_radio_write16(dev, 0x0053, 0x00B7); + b43legacy_radio_write16(dev, 0x0054, 0x0098); + b43legacy_radio_write16(dev, 0x005A, 0x0088); + b43legacy_radio_write16(dev, 0x005B, 0x006B); + b43legacy_radio_write16(dev, 0x005C, 0x000F); + if (dev->dev->bus->sprom.r1.boardflags_lo & 0x8000) { + b43legacy_radio_write16(dev, 0x005D, 0x00FA); + b43legacy_radio_write16(dev, 0x005E, 0x00D8); + } else { + b43legacy_radio_write16(dev, 0x005D, 0x00F5); + b43legacy_radio_write16(dev, 0x005E, 0x00B8); + } + b43legacy_radio_write16(dev, 0x0073, 0x0003); + b43legacy_radio_write16(dev, 0x007D, 0x00A8); + b43legacy_radio_write16(dev, 0x007C, 0x0001); + b43legacy_radio_write16(dev, 0x007E, 0x0008); + } + val = 0x1E1F; + for (offset = 0x0088; offset < 0x0098; offset++) { + b43legacy_phy_write(dev, offset, val); + val -= 0x0202; + } + val = 0x3E3F; + for (offset = 0x0098; offset < 0x00A8; offset++) { + b43legacy_phy_write(dev, offset, val); + val -= 0x0202; + } + val = 0x2120; + for (offset = 0x00A8; offset < 0x00C8; offset++) { + b43legacy_phy_write(dev, offset, (val & 0x3F3F)); + val += 0x0202; + } + if (phy->type == B43legacy_PHYTYPE_G) { + b43legacy_radio_write16(dev, 0x007A, + b43legacy_radio_read16(dev, 0x007A) | + 0x0020); + b43legacy_radio_write16(dev, 0x0051, + b43legacy_radio_read16(dev, 0x0051) | + 0x0004); + b43legacy_phy_write(dev, 0x0802, + b43legacy_phy_read(dev, 0x0802) | 0x0100); + b43legacy_phy_write(dev, 0x042B, + b43legacy_phy_read(dev, 0x042B) | 0x2000); + b43legacy_phy_write(dev, 0x5B, 0x0000); + b43legacy_phy_write(dev, 0x5C, 0x0000); + } + + old_channel = phy->channel; + if (old_channel >= 8) + b43legacy_radio_selectchannel(dev, 1, 0); + else + b43legacy_radio_selectchannel(dev, 13, 0); + + b43legacy_radio_write16(dev, 0x0050, 0x0020); + b43legacy_radio_write16(dev, 0x0050, 0x0023); + udelay(40); + if (phy->radio_rev < 6 || phy->radio_rev == 8) { + b43legacy_radio_write16(dev, 0x007C, + (b43legacy_radio_read16(dev, 0x007C) + | 0x0002)); + b43legacy_radio_write16(dev, 0x0050, 0x0020); + } + if (phy->radio_rev <= 2) { + b43legacy_radio_write16(dev, 0x007C, 0x0020); + b43legacy_radio_write16(dev, 0x005A, 0x0070); + b43legacy_radio_write16(dev, 0x005B, 0x007B); + b43legacy_radio_write16(dev, 0x005C, 0x00B0); + } + b43legacy_radio_write16(dev, 0x007A, + (b43legacy_radio_read16(dev, + 0x007A) & 0x00F8) | 0x0007); + + b43legacy_radio_selectchannel(dev, old_channel, 0); + + b43legacy_phy_write(dev, 0x0014, 0x0200); + if (phy->radio_rev >= 6) + b43legacy_phy_write(dev, 0x002A, 0x88C2); + else + b43legacy_phy_write(dev, 0x002A, 0x8AC0); + b43legacy_phy_write(dev, 0x0038, 0x0668); + b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF); + if (phy->radio_rev <= 5) + b43legacy_phy_write(dev, 0x005D, (b43legacy_phy_read(dev, + 0x005D) & 0xFF80) | 0x0003); + if (phy->radio_rev <= 2) + b43legacy_radio_write16(dev, 0x005D, 0x000D); + + if (phy->analog == 4) { + b43legacy_write16(dev, 0x03E4, 0x0009); + b43legacy_phy_write(dev, 0x61, b43legacy_phy_read(dev, 0x61) + & 0xFFF); + } else + b43legacy_phy_write(dev, 0x0002, (b43legacy_phy_read(dev, + 0x0002) & 0xFFC0) | 0x0004); + if (phy->type == B43legacy_PHYTYPE_G) + b43legacy_write16(dev, 0x03E6, 0x0); + if (phy->type == B43legacy_PHYTYPE_B) { + b43legacy_write16(dev, 0x03E6, 0x8140); + b43legacy_phy_write(dev, 0x0016, 0x0410); + b43legacy_phy_write(dev, 0x0017, 0x0820); + b43legacy_phy_write(dev, 0x0062, 0x0007); + b43legacy_radio_init2050(dev); + b43legacy_phy_lo_g_measure(dev); + if (dev->dev->bus->sprom.r1.boardflags_lo & + B43legacy_BFL_RSSI) { + b43legacy_calc_nrssi_slope(dev); + b43legacy_calc_nrssi_threshold(dev); + } + b43legacy_phy_init_pctl(dev); + } +} + +static void b43legacy_calc_loopback_gain(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 backup_phy[15] = {0}; + u16 backup_radio[3]; + u16 backup_bband; + u16 i; + u16 loop1_cnt; + u16 loop1_done; + u16 loop1_omitted; + u16 loop2_done; + + backup_phy[0] = b43legacy_phy_read(dev, 0x0429); + backup_phy[1] = b43legacy_phy_read(dev, 0x0001); + backup_phy[2] = b43legacy_phy_read(dev, 0x0811); + backup_phy[3] = b43legacy_phy_read(dev, 0x0812); + if (phy->rev != 1) { + backup_phy[4] = b43legacy_phy_read(dev, 0x0814); + backup_phy[5] = b43legacy_phy_read(dev, 0x0815); + } + backup_phy[6] = b43legacy_phy_read(dev, 0x005A); + backup_phy[7] = b43legacy_phy_read(dev, 0x0059); + backup_phy[8] = b43legacy_phy_read(dev, 0x0058); + backup_phy[9] = b43legacy_phy_read(dev, 0x000A); + backup_phy[10] = b43legacy_phy_read(dev, 0x0003); + backup_phy[11] = b43legacy_phy_read(dev, 0x080F); + backup_phy[12] = b43legacy_phy_read(dev, 0x0810); + backup_phy[13] = b43legacy_phy_read(dev, 0x002B); + backup_phy[14] = b43legacy_phy_read(dev, 0x0015); + b43legacy_phy_read(dev, 0x002D); /* dummy read */ + backup_bband = phy->bbatt; + backup_radio[0] = b43legacy_radio_read16(dev, 0x0052); + backup_radio[1] = b43legacy_radio_read16(dev, 0x0043); + backup_radio[2] = b43legacy_radio_read16(dev, 0x007A); + + b43legacy_phy_write(dev, 0x0429, + b43legacy_phy_read(dev, 0x0429) & 0x3FFF); + b43legacy_phy_write(dev, 0x0001, + b43legacy_phy_read(dev, 0x0001) & 0x8000); + b43legacy_phy_write(dev, 0x0811, + b43legacy_phy_read(dev, 0x0811) | 0x0002); + b43legacy_phy_write(dev, 0x0812, + b43legacy_phy_read(dev, 0x0812) & 0xFFFD); + b43legacy_phy_write(dev, 0x0811, + b43legacy_phy_read(dev, 0x0811) | 0x0001); + b43legacy_phy_write(dev, 0x0812, + b43legacy_phy_read(dev, 0x0812) & 0xFFFE); + if (phy->rev != 1) { + b43legacy_phy_write(dev, 0x0814, + b43legacy_phy_read(dev, 0x0814) | 0x0001); + b43legacy_phy_write(dev, 0x0815, + b43legacy_phy_read(dev, 0x0815) & 0xFFFE); + b43legacy_phy_write(dev, 0x0814, + b43legacy_phy_read(dev, 0x0814) | 0x0002); + b43legacy_phy_write(dev, 0x0815, + b43legacy_phy_read(dev, 0x0815) & 0xFFFD); + } + b43legacy_phy_write(dev, 0x0811, b43legacy_phy_read(dev, 0x0811) | + 0x000C); + b43legacy_phy_write(dev, 0x0812, b43legacy_phy_read(dev, 0x0812) | + 0x000C); + + b43legacy_phy_write(dev, 0x0811, (b43legacy_phy_read(dev, 0x0811) + & 0xFFCF) | 0x0030); + b43legacy_phy_write(dev, 0x0812, (b43legacy_phy_read(dev, 0x0812) + & 0xFFCF) | 0x0010); + + b43legacy_phy_write(dev, 0x005A, 0x0780); + b43legacy_phy_write(dev, 0x0059, 0xC810); + b43legacy_phy_write(dev, 0x0058, 0x000D); + if (phy->analog == 0) + b43legacy_phy_write(dev, 0x0003, 0x0122); + else + b43legacy_phy_write(dev, 0x000A, + b43legacy_phy_read(dev, 0x000A) + | 0x2000); + if (phy->rev != 1) { + b43legacy_phy_write(dev, 0x0814, + b43legacy_phy_read(dev, 0x0814) | 0x0004); + b43legacy_phy_write(dev, 0x0815, + b43legacy_phy_read(dev, 0x0815) & 0xFFFB); + } + b43legacy_phy_write(dev, 0x0003, + (b43legacy_phy_read(dev, 0x0003) + & 0xFF9F) | 0x0040); + if (phy->radio_ver == 0x2050 && phy->radio_rev == 2) { + b43legacy_radio_write16(dev, 0x0052, 0x0000); + b43legacy_radio_write16(dev, 0x0043, + (b43legacy_radio_read16(dev, 0x0043) + & 0xFFF0) | 0x0009); + loop1_cnt = 9; + } else if (phy->radio_rev == 8) { + b43legacy_radio_write16(dev, 0x0043, 0x000F); + loop1_cnt = 15; + } else + loop1_cnt = 0; + + b43legacy_phy_set_baseband_attenuation(dev, 11); + + if (phy->rev >= 3) + b43legacy_phy_write(dev, 0x080F, 0xC020); + else + b43legacy_phy_write(dev, 0x080F, 0x8020); + b43legacy_phy_write(dev, 0x0810, 0x0000); + + b43legacy_phy_write(dev, 0x002B, + (b43legacy_phy_read(dev, 0x002B) + & 0xFFC0) | 0x0001); + b43legacy_phy_write(dev, 0x002B, + (b43legacy_phy_read(dev, 0x002B) + & 0xC0FF) | 0x0800); + b43legacy_phy_write(dev, 0x0811, + b43legacy_phy_read(dev, 0x0811) | 0x0100); + b43legacy_phy_write(dev, 0x0812, + b43legacy_phy_read(dev, 0x0812) & 0xCFFF); + if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_EXTLNA) { + if (phy->rev >= 7) { + b43legacy_phy_write(dev, 0x0811, + b43legacy_phy_read(dev, 0x0811) + | 0x0800); + b43legacy_phy_write(dev, 0x0812, + b43legacy_phy_read(dev, 0x0812) + | 0x8000); + } + } + b43legacy_radio_write16(dev, 0x007A, + b43legacy_radio_read16(dev, 0x007A) + & 0x00F7); + + for (i = 0; i < loop1_cnt; i++) { + b43legacy_radio_write16(dev, 0x0043, loop1_cnt); + b43legacy_phy_write(dev, 0x0812, + (b43legacy_phy_read(dev, 0x0812) + & 0xF0FF) | (i << 8)); + b43legacy_phy_write(dev, 0x0015, + (b43legacy_phy_read(dev, 0x0015) + & 0x0FFF) | 0xA000); + b43legacy_phy_write(dev, 0x0015, + (b43legacy_phy_read(dev, 0x0015) + & 0x0FFF) | 0xF000); + udelay(20); + if (b43legacy_phy_read(dev, 0x002D) >= 0x0DFC) + break; + } + loop1_done = i; + loop1_omitted = loop1_cnt - loop1_done; + + loop2_done = 0; + if (loop1_done >= 8) { + b43legacy_phy_write(dev, 0x0812, + b43legacy_phy_read(dev, 0x0812) + | 0x0030); + for (i = loop1_done - 8; i < 16; i++) { + b43legacy_phy_write(dev, 0x0812, + (b43legacy_phy_read(dev, 0x0812) + & 0xF0FF) | (i << 8)); + b43legacy_phy_write(dev, 0x0015, + (b43legacy_phy_read(dev, 0x0015) + & 0x0FFF) | 0xA000); + b43legacy_phy_write(dev, 0x0015, + (b43legacy_phy_read(dev, 0x0015) + & 0x0FFF) | 0xF000); + udelay(20); + if (b43legacy_phy_read(dev, 0x002D) >= 0x0DFC) + break; + } + } + + if (phy->rev != 1) { + b43legacy_phy_write(dev, 0x0814, backup_phy[4]); + b43legacy_phy_write(dev, 0x0815, backup_phy[5]); + } + b43legacy_phy_write(dev, 0x005A, backup_phy[6]); + b43legacy_phy_write(dev, 0x0059, backup_phy[7]); + b43legacy_phy_write(dev, 0x0058, backup_phy[8]); + b43legacy_phy_write(dev, 0x000A, backup_phy[9]); + b43legacy_phy_write(dev, 0x0003, backup_phy[10]); + b43legacy_phy_write(dev, 0x080F, backup_phy[11]); + b43legacy_phy_write(dev, 0x0810, backup_phy[12]); + b43legacy_phy_write(dev, 0x002B, backup_phy[13]); + b43legacy_phy_write(dev, 0x0015, backup_phy[14]); + + b43legacy_phy_set_baseband_attenuation(dev, backup_bband); + + b43legacy_radio_write16(dev, 0x0052, backup_radio[0]); + b43legacy_radio_write16(dev, 0x0043, backup_radio[1]); + b43legacy_radio_write16(dev, 0x007A, backup_radio[2]); + + b43legacy_phy_write(dev, 0x0811, backup_phy[2] | 0x0003); + udelay(10); + b43legacy_phy_write(dev, 0x0811, backup_phy[2]); + b43legacy_phy_write(dev, 0x0812, backup_phy[3]); + b43legacy_phy_write(dev, 0x0429, backup_phy[0]); + b43legacy_phy_write(dev, 0x0001, backup_phy[1]); + + phy->loopback_gain[0] = ((loop1_done * 6) - (loop1_omitted * 4)) - 11; + phy->loopback_gain[1] = (24 - (3 * loop2_done)) * 2; +} + +static void b43legacy_phy_initg(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 tmp; + + if (phy->rev == 1) + b43legacy_phy_initb5(dev); + else + b43legacy_phy_initb6(dev); + if (phy->rev >= 2 || phy->gmode) + b43legacy_phy_inita(dev); + + if (phy->rev >= 2) { + b43legacy_phy_write(dev, 0x0814, 0x0000); + b43legacy_phy_write(dev, 0x0815, 0x0000); + } + if (phy->rev == 2) { + b43legacy_phy_write(dev, 0x0811, 0x0000); + b43legacy_phy_write(dev, 0x0015, 0x00C0); + } + if (phy->rev > 5) { + b43legacy_phy_write(dev, 0x0811, 0x0400); + b43legacy_phy_write(dev, 0x0015, 0x00C0); + } + if (phy->rev >= 2 || phy->gmode) { + tmp = b43legacy_phy_read(dev, 0x0400) & 0xFF; + if (tmp == 3 || tmp == 5) { + b43legacy_phy_write(dev, 0x04C2, 0x1816); + b43legacy_phy_write(dev, 0x04C3, 0x8006); + if (tmp == 5) + b43legacy_phy_write(dev, 0x04CC, + (b43legacy_phy_read(dev, + 0x04CC) & 0x00FF) | + 0x1F00); + } + b43legacy_phy_write(dev, 0x047E, 0x0078); + } + if (phy->radio_rev == 8) { + b43legacy_phy_write(dev, 0x0801, b43legacy_phy_read(dev, 0x0801) + | 0x0080); + b43legacy_phy_write(dev, 0x043E, b43legacy_phy_read(dev, 0x043E) + | 0x0004); + } + if (phy->rev >= 2 && phy->gmode) + b43legacy_calc_loopback_gain(dev); + if (phy->radio_rev != 8) { + if (phy->initval == 0xFFFF) + phy->initval = b43legacy_radio_init2050(dev); + else + b43legacy_radio_write16(dev, 0x0078, phy->initval); + } + if (phy->txctl2 == 0xFFFF) + b43legacy_phy_lo_g_measure(dev); + else { + if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) + b43legacy_radio_write16(dev, 0x0052, + (phy->txctl1 << 4) | + phy->txctl2); + else + b43legacy_radio_write16(dev, 0x0052, + (b43legacy_radio_read16(dev, + 0x0052) & 0xFFF0) | + phy->txctl1); + if (phy->rev >= 6) + b43legacy_phy_write(dev, 0x0036, + (b43legacy_phy_read(dev, 0x0036) + & 0x0FFF) | (phy->txctl2 << 12)); + if (dev->dev->bus->sprom.r1.boardflags_lo & + B43legacy_BFL_PACTRL) + b43legacy_phy_write(dev, 0x002E, 0x8075); + else + b43legacy_phy_write(dev, 0x002E, 0x807F); + if (phy->rev < 2) + b43legacy_phy_write(dev, 0x002F, 0x0101); + else + b43legacy_phy_write(dev, 0x002F, 0x0202); + } + if (phy->gmode || phy->rev >= 2) { + b43legacy_phy_lo_adjust(dev, 0); + b43legacy_phy_write(dev, 0x080F, 0x8078); + } + + if (!(dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_RSSI)) { + /* The specs state to update the NRSSI LT with + * the value 0x7FFFFFFF here. I think that is some weird + * compiler optimization in the original driver. + * Essentially, what we do here is resetting all NRSSI LT + * entries to -32 (see the limit_value() in nrssi_hw_update()) + */ + b43legacy_nrssi_hw_update(dev, 0xFFFF); + b43legacy_calc_nrssi_threshold(dev); + } else if (phy->gmode || phy->rev >= 2) { + if (phy->nrssi[0] == -1000) { + B43legacy_WARN_ON(phy->nrssi[1] != -1000); + b43legacy_calc_nrssi_slope(dev); + } else { + B43legacy_WARN_ON(phy->nrssi[1] == -1000); + b43legacy_calc_nrssi_threshold(dev); + } + } + if (phy->radio_rev == 8) + b43legacy_phy_write(dev, 0x0805, 0x3230); + b43legacy_phy_init_pctl(dev); + if (dev->dev->bus->chip_id == 0x4306 + && dev->dev->bus->chip_package == 2) { + b43legacy_phy_write(dev, 0x0429, + b43legacy_phy_read(dev, 0x0429) & 0xBFFF); + b43legacy_phy_write(dev, 0x04C3, + b43legacy_phy_read(dev, 0x04C3) & 0x7FFF); + } +} + +static u16 b43legacy_phy_lo_b_r15_loop(struct b43legacy_wldev *dev) +{ + int i; + u16 ret = 0; + unsigned long flags; + + local_irq_save(flags); + for (i = 0; i < 10; i++) { + b43legacy_phy_write(dev, 0x0015, 0xAFA0); + udelay(1); + b43legacy_phy_write(dev, 0x0015, 0xEFA0); + udelay(10); + b43legacy_phy_write(dev, 0x0015, 0xFFA0); + udelay(40); + ret += b43legacy_phy_read(dev, 0x002C); + } + local_irq_restore(flags); + b43legacy_voluntary_preempt(); + + return ret; +} + +void b43legacy_phy_lo_b_measure(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 regstack[12] = { 0 }; + u16 mls; + u16 fval; + int i; + int j; + + regstack[0] = b43legacy_phy_read(dev, 0x0015); + regstack[1] = b43legacy_radio_read16(dev, 0x0052) & 0xFFF0; + + if (phy->radio_ver == 0x2053) { + regstack[2] = b43legacy_phy_read(dev, 0x000A); + regstack[3] = b43legacy_phy_read(dev, 0x002A); + regstack[4] = b43legacy_phy_read(dev, 0x0035); + regstack[5] = b43legacy_phy_read(dev, 0x0003); + regstack[6] = b43legacy_phy_read(dev, 0x0001); + regstack[7] = b43legacy_phy_read(dev, 0x0030); + + regstack[8] = b43legacy_radio_read16(dev, 0x0043); + regstack[9] = b43legacy_radio_read16(dev, 0x007A); + regstack[10] = b43legacy_read16(dev, 0x03EC); + regstack[11] = b43legacy_radio_read16(dev, 0x0052) & 0x00F0; + + b43legacy_phy_write(dev, 0x0030, 0x00FF); + b43legacy_write16(dev, 0x03EC, 0x3F3F); + b43legacy_phy_write(dev, 0x0035, regstack[4] & 0xFF7F); + b43legacy_radio_write16(dev, 0x007A, regstack[9] & 0xFFF0); + } + b43legacy_phy_write(dev, 0x0015, 0xB000); + b43legacy_phy_write(dev, 0x002B, 0x0004); + + if (phy->radio_ver == 0x2053) { + b43legacy_phy_write(dev, 0x002B, 0x0203); + b43legacy_phy_write(dev, 0x002A, 0x08A3); + } + + phy->minlowsig[0] = 0xFFFF; + + for (i = 0; i < 4; i++) { + b43legacy_radio_write16(dev, 0x0052, regstack[1] | i); + b43legacy_phy_lo_b_r15_loop(dev); + } + for (i = 0; i < 10; i++) { + b43legacy_radio_write16(dev, 0x0052, regstack[1] | i); + mls = b43legacy_phy_lo_b_r15_loop(dev) / 10; + if (mls < phy->minlowsig[0]) { + phy->minlowsig[0] = mls; + phy->minlowsigpos[0] = i; + } + } + b43legacy_radio_write16(dev, 0x0052, regstack[1] + | phy->minlowsigpos[0]); + + phy->minlowsig[1] = 0xFFFF; + + for (i = -4; i < 5; i += 2) { + for (j = -4; j < 5; j += 2) { + if (j < 0) + fval = (0x0100 * i) + j + 0x0100; + else + fval = (0x0100 * i) + j; + b43legacy_phy_write(dev, 0x002F, fval); + mls = b43legacy_phy_lo_b_r15_loop(dev) / 10; + if (mls < phy->minlowsig[1]) { + phy->minlowsig[1] = mls; + phy->minlowsigpos[1] = fval; + } + } + } + phy->minlowsigpos[1] += 0x0101; + + b43legacy_phy_write(dev, 0x002F, phy->minlowsigpos[1]); + if (phy->radio_ver == 0x2053) { + b43legacy_phy_write(dev, 0x000A, regstack[2]); + b43legacy_phy_write(dev, 0x002A, regstack[3]); + b43legacy_phy_write(dev, 0x0035, regstack[4]); + b43legacy_phy_write(dev, 0x0003, regstack[5]); + b43legacy_phy_write(dev, 0x0001, regstack[6]); + b43legacy_phy_write(dev, 0x0030, regstack[7]); + + b43legacy_radio_write16(dev, 0x0043, regstack[8]); + b43legacy_radio_write16(dev, 0x007A, regstack[9]); + + b43legacy_radio_write16(dev, 0x0052, + (b43legacy_radio_read16(dev, 0x0052) + & 0x000F) | regstack[11]); + + b43legacy_write16(dev, 0x03EC, regstack[10]); + } + b43legacy_phy_write(dev, 0x0015, regstack[0]); +} + +static inline +u16 b43legacy_phy_lo_g_deviation_subval(struct b43legacy_wldev *dev, + u16 control) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 ret; + unsigned long flags; + + local_irq_save(flags); + if (phy->gmode) { + b43legacy_phy_write(dev, 0x15, 0xE300); + control <<= 8; + b43legacy_phy_write(dev, 0x0812, control | 0x00B0); + udelay(5); + b43legacy_phy_write(dev, 0x0812, control | 0x00B2); + udelay(2); + b43legacy_phy_write(dev, 0x0812, control | 0x00B3); + udelay(4); + b43legacy_phy_write(dev, 0x0015, 0xF300); + udelay(8); + } else { + b43legacy_phy_write(dev, 0x0015, control | 0xEFA0); + udelay(2); + b43legacy_phy_write(dev, 0x0015, control | 0xEFE0); + udelay(4); + b43legacy_phy_write(dev, 0x0015, control | 0xFFE0); + udelay(8); + } + ret = b43legacy_phy_read(dev, 0x002D); + local_irq_restore(flags); + b43legacy_voluntary_preempt(); + + return ret; +} + +static u32 b43legacy_phy_lo_g_singledeviation(struct b43legacy_wldev *dev, + u16 control) +{ + int i; + u32 ret = 0; + + for (i = 0; i < 8; i++) + ret += b43legacy_phy_lo_g_deviation_subval(dev, control); + + return ret; +} + +/* Write the LocalOscillator CONTROL */ +static inline +void b43legacy_lo_write(struct b43legacy_wldev *dev, + struct b43legacy_lopair *pair) +{ + u16 value; + + value = (u8)(pair->low); + value |= ((u8)(pair->high)) << 8; + +#ifdef CONFIG_B43LEGACY_DEBUG + /* Sanity check. */ + if (pair->low < -8 || pair->low > 8 || + pair->high < -8 || pair->high > 8) { + struct b43legacy_phy *phy = &dev->phy; + b43legacydbg(dev->wl, + "WARNING: Writing invalid LOpair " + "(low: %d, high: %d, index: %lu)\n", + pair->low, pair->high, + (unsigned long)(pair - phy->_lo_pairs)); + dump_stack(); + } +#endif + + b43legacy_phy_write(dev, B43legacy_PHY_G_LO_CONTROL, value); +} + +static inline +struct b43legacy_lopair *b43legacy_find_lopair(struct b43legacy_wldev *dev, + u16 bbatt, + u16 rfatt, + u16 tx) +{ + static const u8 dict[10] = { 11, 10, 11, 12, 13, 12, 13, 12, 13, 12 }; + struct b43legacy_phy *phy = &dev->phy; + + if (bbatt > 6) + bbatt = 6; + B43legacy_WARN_ON(rfatt >= 10); + + if (tx == 3) + return b43legacy_get_lopair(phy, rfatt, bbatt); + return b43legacy_get_lopair(phy, dict[rfatt], bbatt); +} + +static inline +struct b43legacy_lopair *b43legacy_current_lopair(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + + return b43legacy_find_lopair(dev, phy->bbatt, + phy->rfatt, phy->txctl1); +} + +/* Adjust B/G LO */ +void b43legacy_phy_lo_adjust(struct b43legacy_wldev *dev, int fixed) +{ + struct b43legacy_lopair *pair; + + if (fixed) { + /* Use fixed values. Only for initialization. */ + pair = b43legacy_find_lopair(dev, 2, 3, 0); + } else + pair = b43legacy_current_lopair(dev); + b43legacy_lo_write(dev, pair); +} + +static void b43legacy_phy_lo_g_measure_txctl2(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 txctl2 = 0; + u16 i; + u32 smallest; + u32 tmp; + + b43legacy_radio_write16(dev, 0x0052, 0x0000); + udelay(10); + smallest = b43legacy_phy_lo_g_singledeviation(dev, 0); + for (i = 0; i < 16; i++) { + b43legacy_radio_write16(dev, 0x0052, i); + udelay(10); + tmp = b43legacy_phy_lo_g_singledeviation(dev, 0); + if (tmp < smallest) { + smallest = tmp; + txctl2 = i; + } + } + phy->txctl2 = txctl2; +} + +static +void b43legacy_phy_lo_g_state(struct b43legacy_wldev *dev, + const struct b43legacy_lopair *in_pair, + struct b43legacy_lopair *out_pair, + u16 r27) +{ + static const struct b43legacy_lopair transitions[8] = { + { .high = 1, .low = 1, }, + { .high = 1, .low = 0, }, + { .high = 1, .low = -1, }, + { .high = 0, .low = -1, }, + { .high = -1, .low = -1, }, + { .high = -1, .low = 0, }, + { .high = -1, .low = 1, }, + { .high = 0, .low = 1, }, + }; + struct b43legacy_lopair lowest_transition = { + .high = in_pair->high, + .low = in_pair->low, + }; + struct b43legacy_lopair tmp_pair; + struct b43legacy_lopair transition; + int i = 12; + int state = 0; + int found_lower; + int j; + int begin; + int end; + u32 lowest_deviation; + u32 tmp; + + /* Note that in_pair and out_pair can point to the same pair. + * Be careful. */ + + b43legacy_lo_write(dev, &lowest_transition); + lowest_deviation = b43legacy_phy_lo_g_singledeviation(dev, r27); + do { + found_lower = 0; + B43legacy_WARN_ON(!(state >= 0 && state <= 8)); + if (state == 0) { + begin = 1; + end = 8; + } else if (state % 2 == 0) { + begin = state - 1; + end = state + 1; + } else { + begin = state - 2; + end = state + 2; + } + if (begin < 1) + begin += 8; + if (end > 8) + end -= 8; + + j = begin; + tmp_pair.high = lowest_transition.high; + tmp_pair.low = lowest_transition.low; + while (1) { + B43legacy_WARN_ON(!(j >= 1 && j <= 8)); + transition.high = tmp_pair.high + + transitions[j - 1].high; + transition.low = tmp_pair.low + transitions[j - 1].low; + if ((abs(transition.low) < 9) + && (abs(transition.high) < 9)) { + b43legacy_lo_write(dev, &transition); + tmp = b43legacy_phy_lo_g_singledeviation(dev, + r27); + if (tmp < lowest_deviation) { + lowest_deviation = tmp; + state = j; + found_lower = 1; + + lowest_transition.high = + transition.high; + lowest_transition.low = transition.low; + } + } + if (j == end) + break; + if (j == 8) + j = 1; + else + j++; + } + } while (i-- && found_lower); + + out_pair->high = lowest_transition.high; + out_pair->low = lowest_transition.low; +} + +/* Set the baseband attenuation value on chip. */ +void b43legacy_phy_set_baseband_attenuation(struct b43legacy_wldev *dev, + u16 bbatt) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 value; + + if (phy->analog == 0) { + value = (b43legacy_read16(dev, 0x03E6) & 0xFFF0); + value |= (bbatt & 0x000F); + b43legacy_write16(dev, 0x03E6, value); + return; + } + + if (phy->analog > 1) { + value = b43legacy_phy_read(dev, 0x0060) & 0xFFC3; + value |= (bbatt << 2) & 0x003C; + } else { + value = b43legacy_phy_read(dev, 0x0060) & 0xFF87; + value |= (bbatt << 3) & 0x0078; + } + b43legacy_phy_write(dev, 0x0060, value); +} + +/* http://bcm-specs.sipsolutions.net/LocalOscillator/Measure */ +void b43legacy_phy_lo_g_measure(struct b43legacy_wldev *dev) +{ + static const u8 pairorder[10] = { 3, 1, 5, 7, 9, 2, 0, 4, 6, 8 }; + const int is_initializing = (b43legacy_status(dev) + < B43legacy_STAT_STARTED); + struct b43legacy_phy *phy = &dev->phy; + u16 h; + u16 i; + u16 oldi = 0; + u16 j; + struct b43legacy_lopair control; + struct b43legacy_lopair *tmp_control; + u16 tmp; + u16 regstack[16] = { 0 }; + u8 oldchannel; + + /* XXX: What are these? */ + u8 r27 = 0; + u16 r31; + + oldchannel = phy->channel; + /* Setup */ + if (phy->gmode) { + regstack[0] = b43legacy_phy_read(dev, B43legacy_PHY_G_CRS); + regstack[1] = b43legacy_phy_read(dev, 0x0802); + b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, regstack[0] + & 0x7FFF); + b43legacy_phy_write(dev, 0x0802, regstack[1] & 0xFFFC); + } + regstack[3] = b43legacy_read16(dev, 0x03E2); + b43legacy_write16(dev, 0x03E2, regstack[3] | 0x8000); + regstack[4] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT); + regstack[5] = b43legacy_phy_read(dev, 0x15); + regstack[6] = b43legacy_phy_read(dev, 0x2A); + regstack[7] = b43legacy_phy_read(dev, 0x35); + regstack[8] = b43legacy_phy_read(dev, 0x60); + regstack[9] = b43legacy_radio_read16(dev, 0x43); + regstack[10] = b43legacy_radio_read16(dev, 0x7A); + regstack[11] = b43legacy_radio_read16(dev, 0x52); + if (phy->gmode) { + regstack[12] = b43legacy_phy_read(dev, 0x0811); + regstack[13] = b43legacy_phy_read(dev, 0x0812); + regstack[14] = b43legacy_phy_read(dev, 0x0814); + regstack[15] = b43legacy_phy_read(dev, 0x0815); + } + b43legacy_radio_selectchannel(dev, 6, 0); + if (phy->gmode) { + b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, regstack[0] + & 0x7FFF); + b43legacy_phy_write(dev, 0x0802, regstack[1] & 0xFFFC); + b43legacy_dummy_transmission(dev); + } + b43legacy_radio_write16(dev, 0x0043, 0x0006); + + b43legacy_phy_set_baseband_attenuation(dev, 2); + + b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, 0x0000); + b43legacy_phy_write(dev, 0x002E, 0x007F); + b43legacy_phy_write(dev, 0x080F, 0x0078); + b43legacy_phy_write(dev, 0x0035, regstack[7] & ~(1 << 7)); + b43legacy_radio_write16(dev, 0x007A, regstack[10] & 0xFFF0); + b43legacy_phy_write(dev, 0x002B, 0x0203); + b43legacy_phy_write(dev, 0x002A, 0x08A3); + if (phy->gmode) { + b43legacy_phy_write(dev, 0x0814, regstack[14] | 0x0003); + b43legacy_phy_write(dev, 0x0815, regstack[15] & 0xFFFC); + b43legacy_phy_write(dev, 0x0811, 0x01B3); + b43legacy_phy_write(dev, 0x0812, 0x00B2); + } + if (is_initializing) + b43legacy_phy_lo_g_measure_txctl2(dev); + b43legacy_phy_write(dev, 0x080F, 0x8078); + + /* Measure */ + control.low = 0; + control.high = 0; + for (h = 0; h < 10; h++) { + /* Loop over each possible RadioAttenuation (0-9) */ + i = pairorder[h]; + if (is_initializing) { + if (i == 3) { + control.low = 0; + control.high = 0; + } else if (((i % 2 == 1) && (oldi % 2 == 1)) || + ((i % 2 == 0) && (oldi % 2 == 0))) { + tmp_control = b43legacy_get_lopair(phy, oldi, + 0); + memcpy(&control, tmp_control, sizeof(control)); + } else { + tmp_control = b43legacy_get_lopair(phy, 3, 0); + memcpy(&control, tmp_control, sizeof(control)); + } + } + /* Loop over each possible BasebandAttenuation/2 */ + for (j = 0; j < 4; j++) { + if (is_initializing) { + tmp = i * 2 + j; + r27 = 0; + r31 = 0; + if (tmp > 14) { + r31 = 1; + if (tmp > 17) + r27 = 1; + if (tmp > 19) + r27 = 2; + } + } else { + tmp_control = b43legacy_get_lopair(phy, i, + j * 2); + if (!tmp_control->used) + continue; + memcpy(&control, tmp_control, sizeof(control)); + r27 = 3; + r31 = 0; + } + b43legacy_radio_write16(dev, 0x43, i); + b43legacy_radio_write16(dev, 0x52, phy->txctl2); + udelay(10); + b43legacy_voluntary_preempt(); + + b43legacy_phy_set_baseband_attenuation(dev, j * 2); + + tmp = (regstack[10] & 0xFFF0); + if (r31) + tmp |= 0x0008; + b43legacy_radio_write16(dev, 0x007A, tmp); + + tmp_control = b43legacy_get_lopair(phy, i, j * 2); + b43legacy_phy_lo_g_state(dev, &control, tmp_control, + r27); + } + oldi = i; + } + /* Loop over each possible RadioAttenuation (10-13) */ + for (i = 10; i < 14; i++) { + /* Loop over each possible BasebandAttenuation/2 */ + for (j = 0; j < 4; j++) { + if (is_initializing) { + tmp_control = b43legacy_get_lopair(phy, i - 9, + j * 2); + memcpy(&control, tmp_control, sizeof(control)); + /* FIXME: The next line is wrong, as the + * following if statement can never trigger. */ + tmp = (i - 9) * 2 + j - 5; + r27 = 0; + r31 = 0; + if (tmp > 14) { + r31 = 1; + if (tmp > 17) + r27 = 1; + if (tmp > 19) + r27 = 2; + } + } else { + tmp_control = b43legacy_get_lopair(phy, i - 9, + j * 2); + if (!tmp_control->used) + continue; + memcpy(&control, tmp_control, sizeof(control)); + r27 = 3; + r31 = 0; + } + b43legacy_radio_write16(dev, 0x43, i - 9); + /* FIXME: shouldn't txctl1 be zero in the next line + * and 3 in the loop above? */ + b43legacy_radio_write16(dev, 0x52, + phy->txctl2 + | (3/*txctl1*/ << 4)); + udelay(10); + b43legacy_voluntary_preempt(); + + b43legacy_phy_set_baseband_attenuation(dev, j * 2); + + tmp = (regstack[10] & 0xFFF0); + if (r31) + tmp |= 0x0008; + b43legacy_radio_write16(dev, 0x7A, tmp); + + tmp_control = b43legacy_get_lopair(phy, i, j * 2); + b43legacy_phy_lo_g_state(dev, &control, tmp_control, + r27); + } + } + + /* Restoration */ + if (phy->gmode) { + b43legacy_phy_write(dev, 0x0015, 0xE300); + b43legacy_phy_write(dev, 0x0812, (r27 << 8) | 0xA0); + udelay(5); + b43legacy_phy_write(dev, 0x0812, (r27 << 8) | 0xA2); + udelay(2); + b43legacy_phy_write(dev, 0x0812, (r27 << 8) | 0xA3); + b43legacy_voluntary_preempt(); + } else + b43legacy_phy_write(dev, 0x0015, r27 | 0xEFA0); + b43legacy_phy_lo_adjust(dev, is_initializing); + b43legacy_phy_write(dev, 0x002E, 0x807F); + if (phy->gmode) + b43legacy_phy_write(dev, 0x002F, 0x0202); + else + b43legacy_phy_write(dev, 0x002F, 0x0101); + b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, regstack[4]); + b43legacy_phy_write(dev, 0x0015, regstack[5]); + b43legacy_phy_write(dev, 0x002A, regstack[6]); + b43legacy_phy_write(dev, 0x0035, regstack[7]); + b43legacy_phy_write(dev, 0x0060, regstack[8]); + b43legacy_radio_write16(dev, 0x0043, regstack[9]); + b43legacy_radio_write16(dev, 0x007A, regstack[10]); + regstack[11] &= 0x00F0; + regstack[11] |= (b43legacy_radio_read16(dev, 0x52) & 0x000F); + b43legacy_radio_write16(dev, 0x52, regstack[11]); + b43legacy_write16(dev, 0x03E2, regstack[3]); + if (phy->gmode) { + b43legacy_phy_write(dev, 0x0811, regstack[12]); + b43legacy_phy_write(dev, 0x0812, regstack[13]); + b43legacy_phy_write(dev, 0x0814, regstack[14]); + b43legacy_phy_write(dev, 0x0815, regstack[15]); + b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, regstack[0]); + b43legacy_phy_write(dev, 0x0802, regstack[1]); + } + b43legacy_radio_selectchannel(dev, oldchannel, 1); + +#ifdef CONFIG_B43LEGACY_DEBUG + { + /* Sanity check for all lopairs. */ + for (i = 0; i < B43legacy_LO_COUNT; i++) { + tmp_control = phy->_lo_pairs + i; + if (tmp_control->low < -8 || tmp_control->low > 8 || + tmp_control->high < -8 || tmp_control->high > 8) + b43legacywarn(dev->wl, + "WARNING: Invalid LOpair (low: %d, high:" + " %d, index: %d)\n", + tmp_control->low, tmp_control->high, i); + } + } +#endif /* CONFIG_B43LEGACY_DEBUG */ +} + +static +void b43legacy_phy_lo_mark_current_used(struct b43legacy_wldev *dev) +{ + struct b43legacy_lopair *pair; + + pair = b43legacy_current_lopair(dev); + pair->used = 1; +} + +void b43legacy_phy_lo_mark_all_unused(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + struct b43legacy_lopair *pair; + int i; + + for (i = 0; i < B43legacy_LO_COUNT; i++) { + pair = phy->_lo_pairs + i; + pair->used = 0; + } +} + +/* http://bcm-specs.sipsolutions.net/EstimatePowerOut + * This function converts a TSSI value to dBm in Q5.2 + */ +static s8 b43legacy_phy_estimate_power_out(struct b43legacy_wldev *dev, s8 tssi) +{ + struct b43legacy_phy *phy = &dev->phy; + s8 dbm = 0; + s32 tmp; + + tmp = phy->idle_tssi; + tmp += tssi; + tmp -= phy->savedpctlreg; + + switch (phy->type) { + case B43legacy_PHYTYPE_B: + case B43legacy_PHYTYPE_G: + tmp = limit_value(tmp, 0x00, 0x3F); + dbm = phy->tssi2dbm[tmp]; + break; + default: + B43legacy_BUG_ON(1); + } + + return dbm; +} + +/* http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */ +void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 tmp; + u16 txpower; + s8 v0; + s8 v1; + s8 v2; + s8 v3; + s8 average; + int max_pwr; + s16 desired_pwr; + s16 estimated_pwr; + s16 pwr_adjust; + s16 radio_att_delta; + s16 baseband_att_delta; + s16 radio_attenuation; + s16 baseband_attenuation; + unsigned long phylock_flags; + + if (phy->savedpctlreg == 0xFFFF) + return; + if ((dev->dev->bus->boardinfo.type == 0x0416) && + is_bcm_board_vendor(dev)) + return; +#ifdef CONFIG_B43LEGACY_DEBUG + if (phy->manual_txpower_control) + return; +#endif + + B43legacy_BUG_ON(!(phy->type == B43legacy_PHYTYPE_B || + phy->type == B43legacy_PHYTYPE_G)); + tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x0058); + v0 = (s8)(tmp & 0x00FF); + v1 = (s8)((tmp & 0xFF00) >> 8); + tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x005A); + v2 = (s8)(tmp & 0x00FF); + v3 = (s8)((tmp & 0xFF00) >> 8); + tmp = 0; + + if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F || v3 == 0x7F) { + tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, + 0x0070); + v0 = (s8)(tmp & 0x00FF); + v1 = (s8)((tmp & 0xFF00) >> 8); + tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, + 0x0072); + v2 = (s8)(tmp & 0x00FF); + v3 = (s8)((tmp & 0xFF00) >> 8); + if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F || v3 == 0x7F) + return; + v0 = (v0 + 0x20) & 0x3F; + v1 = (v1 + 0x20) & 0x3F; + v2 = (v2 + 0x20) & 0x3F; + v3 = (v3 + 0x20) & 0x3F; + tmp = 1; + } + b43legacy_radio_clear_tssi(dev); + + average = (v0 + v1 + v2 + v3 + 2) / 4; + + if (tmp && (b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x005E) + & 0x8)) + average -= 13; + + estimated_pwr = b43legacy_phy_estimate_power_out(dev, average); + + max_pwr = dev->dev->bus->sprom.r1.maxpwr_bg; + + if ((dev->dev->bus->sprom.r1.boardflags_lo + & B43legacy_BFL_PACTRL) && + (phy->type == B43legacy_PHYTYPE_G)) + max_pwr -= 0x3; + if (unlikely(max_pwr <= 0)) { + b43legacywarn(dev->wl, "Invalid max-TX-power value in SPROM." + "\n"); + max_pwr = 74; /* fake it */ + dev->dev->bus->sprom.r1.maxpwr_bg = max_pwr; + } + + /* Use regulatory information to get the maximum power. + * In the absence of such data from mac80211, we will use 20 dBm, which + * is the value for the EU, US, Canada, and most of the world. + * The regulatory maximum is reduced by the antenna gain (from sprom) + * and 1.5 dBm (a safety factor??). The result is in Q5.2 format + * which accounts for the factor of 4 */ +#define REG_MAX_PWR 20 + max_pwr = min(REG_MAX_PWR * 4 - dev->dev->bus->sprom.r1.antenna_gain_bg + - 0x6, max_pwr); + + /* find the desired power in Q5.2 - power_level is in dBm + * and limit it - max_pwr is already in Q5.2 */ + desired_pwr = limit_value(phy->power_level << 2, 0, max_pwr); + if (b43legacy_debug(dev, B43legacy_DBG_XMITPOWER)) + b43legacydbg(dev->wl, "Current TX power output: " Q52_FMT + " dBm, Desired TX power output: " Q52_FMT + " dBm\n", Q52_ARG(estimated_pwr), + Q52_ARG(desired_pwr)); + /* Check if we need to adjust the current power. The factor of 2 is + * for damping */ + pwr_adjust = (desired_pwr - estimated_pwr) / 2; + /* RF attenuation delta + * The minus sign is because lower attenuation => more power */ + radio_att_delta = -(pwr_adjust + 7) >> 3; + /* Baseband attenuation delta */ + baseband_att_delta = -(pwr_adjust >> 1) - (4 * radio_att_delta); + /* Do we need to adjust anything? */ + if ((radio_att_delta == 0) && (baseband_att_delta == 0)) { + b43legacy_phy_lo_mark_current_used(dev); + return; + } + + /* Calculate the new attenuation values. */ + baseband_attenuation = phy->bbatt; + baseband_attenuation += baseband_att_delta; + radio_attenuation = phy->rfatt; + radio_attenuation += radio_att_delta; + + /* Get baseband and radio attenuation values into permitted ranges. + * baseband 0-11, radio 0-9. + * Radio attenuation affects power level 4 times as much as baseband. + */ + if (radio_attenuation < 0) { + baseband_attenuation -= (4 * -radio_attenuation); + radio_attenuation = 0; + } else if (radio_attenuation > 9) { + baseband_attenuation += (4 * (radio_attenuation - 9)); + radio_attenuation = 9; + } else { + while (baseband_attenuation < 0 && radio_attenuation > 0) { + baseband_attenuation += 4; + radio_attenuation--; + } + while (baseband_attenuation > 11 && radio_attenuation < 9) { + baseband_attenuation -= 4; + radio_attenuation++; + } + } + baseband_attenuation = limit_value(baseband_attenuation, 0, 11); + + txpower = phy->txctl1; + if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 2)) { + if (radio_attenuation <= 1) { + if (txpower == 0) { + txpower = 3; + radio_attenuation += 2; + baseband_attenuation += 2; + } else if (dev->dev->bus->sprom.r1.boardflags_lo + & B43legacy_BFL_PACTRL) { + baseband_attenuation += 4 * + (radio_attenuation - 2); + radio_attenuation = 2; + } + } else if (radio_attenuation > 4 && txpower != 0) { + txpower = 0; + if (baseband_attenuation < 3) { + radio_attenuation -= 3; + baseband_attenuation += 2; + } else { + radio_attenuation -= 2; + baseband_attenuation -= 2; + } + } + } + /* Save the control values */ + phy->txctl1 = txpower; + baseband_attenuation = limit_value(baseband_attenuation, 0, 11); + radio_attenuation = limit_value(radio_attenuation, 0, 9); + phy->rfatt = radio_attenuation; + phy->bbatt = baseband_attenuation; + + /* Adjust the hardware */ + b43legacy_phy_lock(dev, phylock_flags); + b43legacy_radio_lock(dev); + b43legacy_radio_set_txpower_bg(dev, baseband_attenuation, + radio_attenuation, txpower); + b43legacy_phy_lo_mark_current_used(dev); + b43legacy_radio_unlock(dev); + b43legacy_phy_unlock(dev, phylock_flags); +} + +static inline +s32 b43legacy_tssi2dbm_ad(s32 num, s32 den) +{ + if (num < 0) + return num/den; + else + return (num+den/2)/den; +} + +static inline +s8 b43legacy_tssi2dbm_entry(s8 entry [], u8 index, s16 pab0, s16 pab1, s16 pab2) +{ + s32 m1; + s32 m2; + s32 f = 256; + s32 q; + s32 delta; + s8 i = 0; + + m1 = b43legacy_tssi2dbm_ad(16 * pab0 + index * pab1, 32); + m2 = max(b43legacy_tssi2dbm_ad(32768 + index * pab2, 256), 1); + do { + if (i > 15) + return -EINVAL; + q = b43legacy_tssi2dbm_ad(f * 4096 - + b43legacy_tssi2dbm_ad(m2 * f, 16) * + f, 2048); + delta = abs(q - f); + f = q; + i++; + } while (delta >= 2); + entry[index] = limit_value(b43legacy_tssi2dbm_ad(m1 * f, 8192), + -127, 128); + return 0; +} + +/* http://bcm-specs.sipsolutions.net/TSSI_to_DBM_Table */ +int b43legacy_phy_init_tssi2dbm_table(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + s16 pab0; + s16 pab1; + s16 pab2; + u8 idx; + s8 *dyn_tssi2dbm; + + B43legacy_WARN_ON(!(phy->type == B43legacy_PHYTYPE_B || + phy->type == B43legacy_PHYTYPE_G)); + pab0 = (s16)(dev->dev->bus->sprom.r1.pa0b0); + pab1 = (s16)(dev->dev->bus->sprom.r1.pa0b1); + pab2 = (s16)(dev->dev->bus->sprom.r1.pa0b2); + + if ((dev->dev->bus->chip_id == 0x4301) && (phy->radio_ver != 0x2050)) { + phy->idle_tssi = 0x34; + phy->tssi2dbm = b43legacy_tssi2dbm_b_table; + return 0; + } + + if (pab0 != 0 && pab1 != 0 && pab2 != 0 && + pab0 != -1 && pab1 != -1 && pab2 != -1) { + /* The pabX values are set in SPROM. Use them. */ + if ((s8)dev->dev->bus->sprom.r1.itssi_bg != 0 && + (s8)dev->dev->bus->sprom.r1.itssi_bg != -1) + phy->idle_tssi = (s8)(dev->dev->bus->sprom.r1.itssi_bg); + else + phy->idle_tssi = 62; + dyn_tssi2dbm = kmalloc(64, GFP_KERNEL); + if (dyn_tssi2dbm == NULL) { + b43legacyerr(dev->wl, "Could not allocate memory" + "for tssi2dbm table\n"); + return -ENOMEM; + } + for (idx = 0; idx < 64; idx++) + if (b43legacy_tssi2dbm_entry(dyn_tssi2dbm, idx, pab0, + pab1, pab2)) { + phy->tssi2dbm = NULL; + b43legacyerr(dev->wl, "Could not generate " + "tssi2dBm table\n"); + kfree(dyn_tssi2dbm); + return -ENODEV; + } + phy->tssi2dbm = dyn_tssi2dbm; + phy->dyn_tssi_tbl = 1; + } else { + /* pabX values not set in SPROM. */ + switch (phy->type) { + case B43legacy_PHYTYPE_B: + phy->idle_tssi = 0x34; + phy->tssi2dbm = b43legacy_tssi2dbm_b_table; + break; + case B43legacy_PHYTYPE_G: + phy->idle_tssi = 0x34; + phy->tssi2dbm = b43legacy_tssi2dbm_g_table; + break; + } + } + + return 0; +} + +int b43legacy_phy_init(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + int err = -ENODEV; + + switch (phy->type) { + case B43legacy_PHYTYPE_B: + switch (phy->rev) { + case 2: + b43legacy_phy_initb2(dev); + err = 0; + break; + case 4: + b43legacy_phy_initb4(dev); + err = 0; + break; + case 5: + b43legacy_phy_initb5(dev); + err = 0; + break; + case 6: + b43legacy_phy_initb6(dev); + err = 0; + break; + } + break; + case B43legacy_PHYTYPE_G: + b43legacy_phy_initg(dev); + err = 0; + break; + } + if (err) + b43legacyerr(dev->wl, "Unknown PHYTYPE found\n"); + + return err; +} + +void b43legacy_phy_set_antenna_diversity(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 antennadiv; + u16 offset; + u16 value; + u32 ucodeflags; + + antennadiv = phy->antenna_diversity; + + if (antennadiv == 0xFFFF) + antennadiv = 3; + B43legacy_WARN_ON(antennadiv > 3); + + ucodeflags = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED, + B43legacy_UCODEFLAGS_OFFSET); + b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, + B43legacy_UCODEFLAGS_OFFSET, + ucodeflags & ~B43legacy_UCODEFLAG_AUTODIV); + + switch (phy->type) { + case B43legacy_PHYTYPE_G: + offset = 0x0400; + + if (antennadiv == 2) + value = (3/*automatic*/ << 7); + else + value = (antennadiv << 7); + b43legacy_phy_write(dev, offset + 1, + (b43legacy_phy_read(dev, offset + 1) + & 0x7E7F) | value); + + if (antennadiv >= 2) { + if (antennadiv == 2) + value = (antennadiv << 7); + else + value = (0/*force0*/ << 7); + b43legacy_phy_write(dev, offset + 0x2B, + (b43legacy_phy_read(dev, + offset + 0x2B) + & 0xFEFF) | value); + } + + if (phy->type == B43legacy_PHYTYPE_G) { + if (antennadiv >= 2) + b43legacy_phy_write(dev, 0x048C, + b43legacy_phy_read(dev, + 0x048C) | 0x2000); + else + b43legacy_phy_write(dev, 0x048C, + b43legacy_phy_read(dev, + 0x048C) & ~0x2000); + if (phy->rev >= 2) { + b43legacy_phy_write(dev, 0x0461, + b43legacy_phy_read(dev, + 0x0461) | 0x0010); + b43legacy_phy_write(dev, 0x04AD, + (b43legacy_phy_read(dev, + 0x04AD) + & 0x00FF) | 0x0015); + if (phy->rev == 2) + b43legacy_phy_write(dev, 0x0427, + 0x0008); + else + b43legacy_phy_write(dev, 0x0427, + (b43legacy_phy_read(dev, 0x0427) + & 0x00FF) | 0x0008); + } else if (phy->rev >= 6) + b43legacy_phy_write(dev, 0x049B, 0x00DC); + } else { + if (phy->rev < 3) + b43legacy_phy_write(dev, 0x002B, + (b43legacy_phy_read(dev, + 0x002B) & 0x00FF) + | 0x0024); + else { + b43legacy_phy_write(dev, 0x0061, + b43legacy_phy_read(dev, + 0x0061) | 0x0010); + if (phy->rev == 3) { + b43legacy_phy_write(dev, 0x0093, + 0x001D); + b43legacy_phy_write(dev, 0x0027, + 0x0008); + } else { + b43legacy_phy_write(dev, 0x0093, + 0x003A); + b43legacy_phy_write(dev, 0x0027, + (b43legacy_phy_read(dev, 0x0027) + & 0x00FF) | 0x0008); + } + } + } + break; + case B43legacy_PHYTYPE_B: + if (dev->dev->id.revision == 2) + value = (3/*automatic*/ << 7); + else + value = (antennadiv << 7); + b43legacy_phy_write(dev, 0x03E2, + (b43legacy_phy_read(dev, 0x03E2) + & 0xFE7F) | value); + break; + default: + B43legacy_WARN_ON(1); + } + + if (antennadiv >= 2) { + ucodeflags = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED, + B43legacy_UCODEFLAGS_OFFSET); + b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, + B43legacy_UCODEFLAGS_OFFSET, + ucodeflags | B43legacy_UCODEFLAG_AUTODIV); + } + + phy->antenna_diversity = antennadiv; +} + +/* Set the PowerSavingControlBits. + * Bitvalues: + * 0 => unset the bit + * 1 => set the bit + * -1 => calculate the bit + */ +void b43legacy_power_saving_ctl_bits(struct b43legacy_wldev *dev, + int bit25, int bit26) +{ + int i; + u32 status; + +/* FIXME: Force 25 to off and 26 to on for now: */ +bit25 = 0; +bit26 = 1; + + if (bit25 == -1) { + /* TODO: If powersave is not off and FIXME is not set and we + * are not in adhoc and thus is not an AP and we arei + * associated, set bit 25 */ + } + if (bit26 == -1) { + /* TODO: If the device is awake or this is an AP, or we are + * scanning, or FIXME, or we are associated, or FIXME, + * or the latest PS-Poll packet sent was successful, + * set bit26 */ + } + status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD); + if (bit25) + status |= B43legacy_SBF_PS1; + else + status &= ~B43legacy_SBF_PS1; + if (bit26) + status |= B43legacy_SBF_PS2; + else + status &= ~B43legacy_SBF_PS2; + b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status); + if (bit26 && dev->dev->id.revision >= 5) { + for (i = 0; i < 100; i++) { + if (b43legacy_shm_read32(dev, B43legacy_SHM_SHARED, + 0x0040) != 4) + break; + udelay(10); + } + } +} diff --git a/drivers/net/wireless/b43legacy/phy.h b/drivers/net/wireless/b43legacy/phy.h new file mode 100644 index 00000000000..f11b4271714 --- /dev/null +++ b/drivers/net/wireless/b43legacy/phy.h @@ -0,0 +1,219 @@ +/* + + Broadcom B43legacy wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + Copyright (c) 2007 Larry Finger + + Some parts of the code in this file are derived from the ipw2200 + driver Copyright(c) 2003 - 2004 Intel Corporation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#ifndef B43legacy_PHY_H_ +#define B43legacy_PHY_H_ + +#include + +enum { + B43legacy_ANTENNA0, /* Antenna 0 */ + B43legacy_ANTENNA1, /* Antenna 0 */ + B43legacy_ANTENNA_AUTO1, /* Automatic, starting with antenna 1 */ + B43legacy_ANTENNA_AUTO0, /* Automatic, starting with antenna 0 */ + + B43legacy_ANTENNA_AUTO = B43legacy_ANTENNA_AUTO0, + B43legacy_ANTENNA_DEFAULT = B43legacy_ANTENNA_AUTO, +}; + +enum { + B43legacy_INTERFMODE_NONE, + B43legacy_INTERFMODE_NONWLAN, + B43legacy_INTERFMODE_MANUALWLAN, + B43legacy_INTERFMODE_AUTOWLAN, +}; + +/*** PHY Registers ***/ + +/* Routing */ +#define B43legacy_PHYROUTE_OFDM_GPHY 0x400 +#define B43legacy_PHYROUTE_EXT_GPHY 0x800 + +/* Base registers. */ +#define B43legacy_PHY_BASE(reg) (reg) +/* OFDM (A) registers of a G-PHY */ +#define B43legacy_PHY_OFDM(reg) ((reg) | B43legacy_PHYROUTE_OFDM_GPHY) +/* Extended G-PHY registers */ +#define B43legacy_PHY_EXTG(reg) ((reg) | B43legacy_PHYROUTE_EXT_GPHY) + + +/* Extended G-PHY Registers */ +#define B43legacy_PHY_CLASSCTL B43legacy_PHY_EXTG(0x02) /* Classify control */ +#define B43legacy_PHY_GTABCTL B43legacy_PHY_EXTG(0x03) /* G-PHY table control (see below) */ +#define B43legacy_PHY_GTABOFF 0x03FF /* G-PHY table offset (see below) */ +#define B43legacy_PHY_GTABNR 0xFC00 /* G-PHY table number (see below) */ +#define B43legacy_PHY_GTABNR_SHIFT 10 +#define B43legacy_PHY_GTABDATA B43legacy_PHY_EXTG(0x04) /* G-PHY table data */ +#define B43legacy_PHY_LO_MASK B43legacy_PHY_EXTG(0x0F) /* Local Oscillator control mask */ +#define B43legacy_PHY_LO_CTL B43legacy_PHY_EXTG(0x10) /* Local Oscillator control */ +#define B43legacy_PHY_RFOVER B43legacy_PHY_EXTG(0x11) /* RF override */ +#define B43legacy_PHY_RFOVERVAL B43legacy_PHY_EXTG(0x12) /* RF override value */ +/*** OFDM table numbers ***/ +#define B43legacy_OFDMTAB(number, offset) \ + (((number) << B43legacy_PHY_OTABLENR_SHIFT) \ + | (offset)) +#define B43legacy_OFDMTAB_AGC1 B43legacy_OFDMTAB(0x00, 0) +#define B43legacy_OFDMTAB_GAIN0 B43legacy_OFDMTAB(0x00, 0) +#define B43legacy_OFDMTAB_GAINX B43legacy_OFDMTAB(0x01, 0) +#define B43legacy_OFDMTAB_GAIN1 B43legacy_OFDMTAB(0x01, 4) +#define B43legacy_OFDMTAB_AGC3 B43legacy_OFDMTAB(0x02, 0) +#define B43legacy_OFDMTAB_GAIN2 B43legacy_OFDMTAB(0x02, 3) +#define B43legacy_OFDMTAB_LNAHPFGAIN1 B43legacy_OFDMTAB(0x03, 0) +#define B43legacy_OFDMTAB_WRSSI B43legacy_OFDMTAB(0x04, 0) +#define B43legacy_OFDMTAB_LNAHPFGAIN2 B43legacy_OFDMTAB(0x04, 0) +#define B43legacy_OFDMTAB_NOISESCALE B43legacy_OFDMTAB(0x05, 0) +#define B43legacy_OFDMTAB_AGC2 B43legacy_OFDMTAB(0x06, 0) +#define B43legacy_OFDMTAB_ROTOR B43legacy_OFDMTAB(0x08, 0) +#define B43legacy_OFDMTAB_ADVRETARD B43legacy_OFDMTAB(0x09, 0) +#define B43legacy_OFDMTAB_DAC B43legacy_OFDMTAB(0x0C, 0) +#define B43legacy_OFDMTAB_DC B43legacy_OFDMTAB(0x0E, 7) +#define B43legacy_OFDMTAB_PWRDYN2 B43legacy_OFDMTAB(0x0E, 12) +#define B43legacy_OFDMTAB_LNAGAIN B43legacy_OFDMTAB(0x0E, 13) + +#define B43legacy_OFDMTAB_LPFGAIN B43legacy_OFDMTAB(0x0F, 12) +#define B43legacy_OFDMTAB_RSSI B43legacy_OFDMTAB(0x10, 0) + +#define B43legacy_OFDMTAB_AGC1_R1 B43legacy_OFDMTAB(0x13, 0) +#define B43legacy_OFDMTAB_GAINX_R1 B43legacy_OFDMTAB(0x14, 0) +#define B43legacy_OFDMTAB_MINSIGSQ B43legacy_OFDMTAB(0x14, 1) +#define B43legacy_OFDMTAB_AGC3_R1 B43legacy_OFDMTAB(0x15, 0) +#define B43legacy_OFDMTAB_WRSSI_R1 B43legacy_OFDMTAB(0x15, 4) +#define B43legacy_OFDMTAB_TSSI B43legacy_OFDMTAB(0x15, 0) +#define B43legacy_OFDMTAB_DACRFPABB B43legacy_OFDMTAB(0x16, 0) +#define B43legacy_OFDMTAB_DACOFF B43legacy_OFDMTAB(0x17, 0) +#define B43legacy_OFDMTAB_DCBIAS B43legacy_OFDMTAB(0x18, 0) + +void b43legacy_put_attenuation_into_ranges(int *_bbatt, int *_rfatt); + +/* OFDM (A) PHY Registers */ +#define B43legacy_PHY_VERSION_OFDM B43legacy_PHY_OFDM(0x00) /* Versioning register for A-PHY */ +#define B43legacy_PHY_BBANDCFG B43legacy_PHY_OFDM(0x01) /* Baseband config */ +#define B43legacy_PHY_BBANDCFG_RXANT 0x180 /* RX Antenna selection */ +#define B43legacy_PHY_BBANDCFG_RXANT_SHIFT 7 +#define B43legacy_PHY_PWRDOWN B43legacy_PHY_OFDM(0x03) /* Powerdown */ +#define B43legacy_PHY_CRSTHRES1 B43legacy_PHY_OFDM(0x06) /* CRS Threshold 1 */ +#define B43legacy_PHY_LNAHPFCTL B43legacy_PHY_OFDM(0x1C) /* LNA/HPF control */ +#define B43legacy_PHY_ADIVRELATED B43legacy_PHY_OFDM(0x27) /* FIXME rename */ +#define B43legacy_PHY_CRS0 B43legacy_PHY_OFDM(0x29) +#define B43legacy_PHY_ANTDWELL B43legacy_PHY_OFDM(0x2B) /* Antenna dwell */ +#define B43legacy_PHY_ANTDWELL_AUTODIV1 0x0100 /* Automatic RX diversity start antenna */ +#define B43legacy_PHY_ENCORE B43legacy_PHY_OFDM(0x49) /* "Encore" (RangeMax / BroadRange) */ +#define B43legacy_PHY_ENCORE_EN 0x0200 /* Encore enable */ +#define B43legacy_PHY_LMS B43legacy_PHY_OFDM(0x55) +#define B43legacy_PHY_OFDM61 B43legacy_PHY_OFDM(0x61) /* FIXME rename */ +#define B43legacy_PHY_OFDM61_10 0x0010 /* FIXME rename */ +#define B43legacy_PHY_IQBAL B43legacy_PHY_OFDM(0x69) /* I/Q balance */ +#define B43legacy_PHY_OTABLECTL B43legacy_PHY_OFDM(0x72) /* OFDM table control (see below) */ +#define B43legacy_PHY_OTABLEOFF 0x03FF /* OFDM table offset (see below) */ +#define B43legacy_PHY_OTABLENR 0xFC00 /* OFDM table number (see below) */ +#define B43legacy_PHY_OTABLENR_SHIFT 10 +#define B43legacy_PHY_OTABLEI B43legacy_PHY_OFDM(0x73) /* OFDM table data I */ +#define B43legacy_PHY_OTABLEQ B43legacy_PHY_OFDM(0x74) /* OFDM table data Q */ +#define B43legacy_PHY_HPWR_TSSICTL B43legacy_PHY_OFDM(0x78) /* Hardware power TSSI control */ +#define B43legacy_PHY_NRSSITHRES B43legacy_PHY_OFDM(0x8A) /* NRSSI threshold */ +#define B43legacy_PHY_ANTWRSETT B43legacy_PHY_OFDM(0x8C) /* Antenna WR settle */ +#define B43legacy_PHY_ANTWRSETT_ARXDIV 0x2000 /* Automatic RX diversity enabled */ +#define B43legacy_PHY_CLIPPWRDOWNT B43legacy_PHY_OFDM(0x93) /* Clip powerdown threshold */ +#define B43legacy_PHY_OFDM9B B43legacy_PHY_OFDM(0x9B) /* FIXME rename */ +#define B43legacy_PHY_N1P1GAIN B43legacy_PHY_OFDM(0xA0) +#define B43legacy_PHY_P1P2GAIN B43legacy_PHY_OFDM(0xA1) +#define B43legacy_PHY_N1N2GAIN B43legacy_PHY_OFDM(0xA2) +#define B43legacy_PHY_CLIPTHRES B43legacy_PHY_OFDM(0xA3) +#define B43legacy_PHY_CLIPN1P2THRES B43legacy_PHY_OFDM(0xA4) +#define B43legacy_PHY_DIVSRCHIDX B43legacy_PHY_OFDM(0xA8) /* Divider search gain/index */ +#define B43legacy_PHY_CLIPP2THRES B43legacy_PHY_OFDM(0xA9) +#define B43legacy_PHY_CLIPP3THRES B43legacy_PHY_OFDM(0xAA) +#define B43legacy_PHY_DIVP1P2GAIN B43legacy_PHY_OFDM(0xAB) +#define B43legacy_PHY_DIVSRCHGAINBACK B43legacy_PHY_OFDM(0xAD) /* Divider search gain back */ +#define B43legacy_PHY_DIVSRCHGAINCHNG B43legacy_PHY_OFDM(0xAE) /* Divider search gain change */ +#define B43legacy_PHY_CRSTHRES1_R1 B43legacy_PHY_OFDM(0xC0) /* CRS Threshold 1 (rev 1 only) */ +#define B43legacy_PHY_CRSTHRES2_R1 B43legacy_PHY_OFDM(0xC1) /* CRS Threshold 2 (rev 1 only) */ +#define B43legacy_PHY_TSSIP_LTBASE B43legacy_PHY_OFDM(0x380) /* TSSI power lookup table base */ +#define B43legacy_PHY_DC_LTBASE B43legacy_PHY_OFDM(0x3A0) /* DC lookup table base */ +#define B43legacy_PHY_GAIN_LTBASE B43legacy_PHY_OFDM(0x3C0) /* Gain lookup table base */ + +void b43legacy_put_attenuation_into_ranges(int *_bbatt, int *_rfatt); + +/* Masks for the different PHY versioning registers. */ +#define B43legacy_PHYVER_ANALOG 0xF000 +#define B43legacy_PHYVER_ANALOG_SHIFT 12 +#define B43legacy_PHYVER_TYPE 0x0F00 +#define B43legacy_PHYVER_TYPE_SHIFT 8 +#define B43legacy_PHYVER_VERSION 0x00FF + +struct b43legacy_wldev; + +void b43legacy_raw_phy_lock(struct b43legacy_wldev *dev); +#define b43legacy_phy_lock(bcm, flags) \ + do { \ + local_irq_save(flags); \ + b43legacy_raw_phy_lock(bcm); \ + } while (0) +void b43legacy_raw_phy_unlock(struct b43legacy_wldev *dev); +#define b43legacy_phy_unlock(bcm, flags) \ + do { \ + b43legacy_raw_phy_unlock(bcm); \ + local_irq_restore(flags); \ + } while (0) + +/* Card uses the loopback gain stuff */ +#define has_loopback_gain(phy) \ + (((phy)->rev > 1) || ((phy)->gmode)) + +u16 b43legacy_phy_read(struct b43legacy_wldev *dev, u16 offset); +void b43legacy_phy_write(struct b43legacy_wldev *dev, u16 offset, u16 val); + +int b43legacy_phy_init_tssi2dbm_table(struct b43legacy_wldev *dev); +int b43legacy_phy_init(struct b43legacy_wldev *dev); + +void b43legacy_set_rx_antenna(struct b43legacy_wldev *dev, int antenna); + +void b43legacy_phy_set_antenna_diversity(struct b43legacy_wldev *dev); +void b43legacy_phy_calibrate(struct b43legacy_wldev *dev); +int b43legacy_phy_connect(struct b43legacy_wldev *dev, int connect); + +void b43legacy_phy_lo_b_measure(struct b43legacy_wldev *dev); +void b43legacy_phy_lo_g_measure(struct b43legacy_wldev *dev); +void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev); + +/* Adjust the LocalOscillator to the saved values. + * "fixed" is only set to 1 once in initialization. Set to 0 otherwise. + */ +void b43legacy_phy_lo_adjust(struct b43legacy_wldev *dev, int fixed); +void b43legacy_phy_lo_mark_all_unused(struct b43legacy_wldev *dev); + +void b43legacy_phy_set_baseband_attenuation(struct b43legacy_wldev *dev, + u16 baseband_attenuation); + +void b43legacy_power_saving_ctl_bits(struct b43legacy_wldev *dev, + int bit25, int bit26); + +#endif /* B43legacy_PHY_H_ */ diff --git a/drivers/net/wireless/b43legacy/pio.c b/drivers/net/wireless/b43legacy/pio.c new file mode 100644 index 00000000000..de843ac147a --- /dev/null +++ b/drivers/net/wireless/b43legacy/pio.c @@ -0,0 +1,668 @@ +/* + + Broadcom B43legacy wireless driver + + PIO Transmission + + Copyright (c) 2005 Michael Buesch + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "b43legacy.h" +#include "pio.h" +#include "main.h" +#include "xmit.h" + +#include + + +static void tx_start(struct b43legacy_pioqueue *queue) +{ + b43legacy_pio_write(queue, B43legacy_PIO_TXCTL, + B43legacy_PIO_TXCTL_INIT); +} + +static void tx_octet(struct b43legacy_pioqueue *queue, + u8 octet) +{ + if (queue->need_workarounds) { + b43legacy_pio_write(queue, B43legacy_PIO_TXDATA, octet); + b43legacy_pio_write(queue, B43legacy_PIO_TXCTL, + B43legacy_PIO_TXCTL_WRITELO); + } else { + b43legacy_pio_write(queue, B43legacy_PIO_TXCTL, + B43legacy_PIO_TXCTL_WRITELO); + b43legacy_pio_write(queue, B43legacy_PIO_TXDATA, octet); + } +} + +static u16 tx_get_next_word(const u8 *txhdr, + const u8 *packet, + size_t txhdr_size, + unsigned int *pos) +{ + const u8 *source; + unsigned int i = *pos; + u16 ret; + + if (i < txhdr_size) + source = txhdr; + else { + source = packet; + i -= txhdr_size; + } + ret = le16_to_cpu(*((__le16 *)(source + i))); + *pos += 2; + + return ret; +} + +static void tx_data(struct b43legacy_pioqueue *queue, + u8 *txhdr, + const u8 *packet, + unsigned int octets) +{ + u16 data; + unsigned int i = 0; + + if (queue->need_workarounds) { + data = tx_get_next_word(txhdr, packet, + sizeof(struct b43legacy_txhdr_fw3), &i); + b43legacy_pio_write(queue, B43legacy_PIO_TXDATA, data); + } + b43legacy_pio_write(queue, B43legacy_PIO_TXCTL, + B43legacy_PIO_TXCTL_WRITELO | + B43legacy_PIO_TXCTL_WRITEHI); + while (i < octets - 1) { + data = tx_get_next_word(txhdr, packet, + sizeof(struct b43legacy_txhdr_fw3), &i); + b43legacy_pio_write(queue, B43legacy_PIO_TXDATA, data); + } + if (octets % 2) + tx_octet(queue, packet[octets - + sizeof(struct b43legacy_txhdr_fw3) - 1]); +} + +static void tx_complete(struct b43legacy_pioqueue *queue, + struct sk_buff *skb) +{ + if (queue->need_workarounds) { + b43legacy_pio_write(queue, B43legacy_PIO_TXDATA, + skb->data[skb->len - 1]); + b43legacy_pio_write(queue, B43legacy_PIO_TXCTL, + B43legacy_PIO_TXCTL_WRITELO | + B43legacy_PIO_TXCTL_COMPLETE); + } else + b43legacy_pio_write(queue, B43legacy_PIO_TXCTL, + B43legacy_PIO_TXCTL_COMPLETE); +} + +static u16 generate_cookie(struct b43legacy_pioqueue *queue, + struct b43legacy_pio_txpacket *packet) +{ + u16 cookie = 0x0000; + int packetindex; + + /* We use the upper 4 bits for the PIO + * controller ID and the lower 12 bits + * for the packet index (in the cache). + */ + switch (queue->mmio_base) { + case B43legacy_MMIO_PIO1_BASE: + break; + case B43legacy_MMIO_PIO2_BASE: + cookie = 0x1000; + break; + case B43legacy_MMIO_PIO3_BASE: + cookie = 0x2000; + break; + case B43legacy_MMIO_PIO4_BASE: + cookie = 0x3000; + break; + default: + B43legacy_WARN_ON(1); + } + packetindex = pio_txpacket_getindex(packet); + B43legacy_WARN_ON(!(((u16)packetindex & 0xF000) == 0x0000)); + cookie |= (u16)packetindex; + + return cookie; +} + +static +struct b43legacy_pioqueue *parse_cookie(struct b43legacy_wldev *dev, + u16 cookie, + struct b43legacy_pio_txpacket **packet) +{ + struct b43legacy_pio *pio = &dev->pio; + struct b43legacy_pioqueue *queue = NULL; + int packetindex; + + switch (cookie & 0xF000) { + case 0x0000: + queue = pio->queue0; + break; + case 0x1000: + queue = pio->queue1; + break; + case 0x2000: + queue = pio->queue2; + break; + case 0x3000: + queue = pio->queue3; + break; + default: + B43legacy_WARN_ON(1); + } + packetindex = (cookie & 0x0FFF); + B43legacy_WARN_ON(!(packetindex >= 0 && packetindex + < B43legacy_PIO_MAXTXPACKETS)); + *packet = &(queue->tx_packets_cache[packetindex]); + + return queue; +} + +union txhdr_union { + struct b43legacy_txhdr_fw3 txhdr_fw3; +}; + +static void pio_tx_write_fragment(struct b43legacy_pioqueue *queue, + struct sk_buff *skb, + struct b43legacy_pio_txpacket *packet, + size_t txhdr_size) +{ + union txhdr_union txhdr_data; + u8 *txhdr = NULL; + unsigned int octets; + + txhdr = (u8 *)(&txhdr_data.txhdr_fw3); + + B43legacy_WARN_ON(skb_shinfo(skb)->nr_frags != 0); + b43legacy_generate_txhdr(queue->dev, + txhdr, skb->data, skb->len, + &packet->txstat.control, + generate_cookie(queue, packet)); + + tx_start(queue); + octets = skb->len + txhdr_size; + if (queue->need_workarounds) + octets--; + tx_data(queue, txhdr, (u8 *)skb->data, octets); + tx_complete(queue, skb); +} + +static void free_txpacket(struct b43legacy_pio_txpacket *packet, + int irq_context) +{ + struct b43legacy_pioqueue *queue = packet->queue; + + if (packet->skb) { + if (irq_context) + dev_kfree_skb_irq(packet->skb); + else + dev_kfree_skb(packet->skb); + } + list_move(&packet->list, &queue->txfree); + queue->nr_txfree++; +} + +static int pio_tx_packet(struct b43legacy_pio_txpacket *packet) +{ + struct b43legacy_pioqueue *queue = packet->queue; + struct sk_buff *skb = packet->skb; + u16 octets; + + octets = (u16)skb->len + sizeof(struct b43legacy_txhdr_fw3); + if (queue->tx_devq_size < octets) { + b43legacywarn(queue->dev->wl, "PIO queue too small. " + "Dropping packet.\n"); + /* Drop it silently (return success) */ + free_txpacket(packet, 1); + return 0; + } + B43legacy_WARN_ON(queue->tx_devq_packets > + B43legacy_PIO_MAXTXDEVQPACKETS); + B43legacy_WARN_ON(queue->tx_devq_used > queue->tx_devq_size); + /* Check if there is sufficient free space on the device + * TX queue. If not, return and let the TX tasklet + * retry later. + */ + if (queue->tx_devq_packets == B43legacy_PIO_MAXTXDEVQPACKETS) + return -EBUSY; + if (queue->tx_devq_used + octets > queue->tx_devq_size) + return -EBUSY; + /* Now poke the device. */ + pio_tx_write_fragment(queue, skb, packet, + sizeof(struct b43legacy_txhdr_fw3)); + + /* Account for the packet size. + * (We must not overflow the device TX queue) + */ + queue->tx_devq_packets++; + queue->tx_devq_used += octets; + + /* Transmission started, everything ok, move the + * packet to the txrunning list. + */ + list_move_tail(&packet->list, &queue->txrunning); + + return 0; +} + +static void tx_tasklet(unsigned long d) +{ + struct b43legacy_pioqueue *queue = (struct b43legacy_pioqueue *)d; + struct b43legacy_wldev *dev = queue->dev; + unsigned long flags; + struct b43legacy_pio_txpacket *packet, *tmp_packet; + int err; + u16 txctl; + + spin_lock_irqsave(&dev->wl->irq_lock, flags); + if (queue->tx_frozen) + goto out_unlock; + txctl = b43legacy_pio_read(queue, B43legacy_PIO_TXCTL); + if (txctl & B43legacy_PIO_TXCTL_SUSPEND) + goto out_unlock; + + list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) { + /* Try to transmit the packet. This can fail, if + * the device queue is full. In case of failure, the + * packet is left in the txqueue. + * If transmission succeed, the packet is moved to txrunning. + * If it is impossible to transmit the packet, it + * is dropped. + */ + err = pio_tx_packet(packet); + if (err) + break; + } +out_unlock: + spin_unlock_irqrestore(&dev->wl->irq_lock, flags); +} + +static void setup_txqueues(struct b43legacy_pioqueue *queue) +{ + struct b43legacy_pio_txpacket *packet; + int i; + + queue->nr_txfree = B43legacy_PIO_MAXTXPACKETS; + for (i = 0; i < B43legacy_PIO_MAXTXPACKETS; i++) { + packet = &(queue->tx_packets_cache[i]); + + packet->queue = queue; + INIT_LIST_HEAD(&packet->list); + + list_add(&packet->list, &queue->txfree); + } +} + +static +struct b43legacy_pioqueue *b43legacy_setup_pioqueue(struct b43legacy_wldev *dev, + u16 pio_mmio_base) +{ + struct b43legacy_pioqueue *queue; + u32 value; + u16 qsize; + + queue = kzalloc(sizeof(*queue), GFP_KERNEL); + if (!queue) + goto out; + + queue->dev = dev; + queue->mmio_base = pio_mmio_base; + queue->need_workarounds = (dev->dev->id.revision < 3); + + INIT_LIST_HEAD(&queue->txfree); + INIT_LIST_HEAD(&queue->txqueue); + INIT_LIST_HEAD(&queue->txrunning); + tasklet_init(&queue->txtask, tx_tasklet, + (unsigned long)queue); + + value = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD); + value &= ~B43legacy_SBF_XFER_REG_BYTESWAP; + b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, value); + + qsize = b43legacy_read16(dev, queue->mmio_base + + B43legacy_PIO_TXQBUFSIZE); + if (qsize == 0) { + b43legacyerr(dev->wl, "This card does not support PIO " + "operation mode. Please use DMA mode " + "(module parameter pio=0).\n"); + goto err_freequeue; + } + if (qsize <= B43legacy_PIO_TXQADJUST) { + b43legacyerr(dev->wl, "PIO tx device-queue too small (%u)\n", + qsize); + goto err_freequeue; + } + qsize -= B43legacy_PIO_TXQADJUST; + queue->tx_devq_size = qsize; + + setup_txqueues(queue); + +out: + return queue; + +err_freequeue: + kfree(queue); + queue = NULL; + goto out; +} + +static void cancel_transfers(struct b43legacy_pioqueue *queue) +{ + struct b43legacy_pio_txpacket *packet, *tmp_packet; + + tasklet_disable(&queue->txtask); + + list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list) + free_txpacket(packet, 0); + list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) + free_txpacket(packet, 0); +} + +static void b43legacy_destroy_pioqueue(struct b43legacy_pioqueue *queue) +{ + if (!queue) + return; + + cancel_transfers(queue); + kfree(queue); +} + +void b43legacy_pio_free(struct b43legacy_wldev *dev) +{ + struct b43legacy_pio *pio; + + if (!b43legacy_using_pio(dev)) + return; + pio = &dev->pio; + + b43legacy_destroy_pioqueue(pio->queue3); + pio->queue3 = NULL; + b43legacy_destroy_pioqueue(pio->queue2); + pio->queue2 = NULL; + b43legacy_destroy_pioqueue(pio->queue1); + pio->queue1 = NULL; + b43legacy_destroy_pioqueue(pio->queue0); + pio->queue0 = NULL; +} + +int b43legacy_pio_init(struct b43legacy_wldev *dev) +{ + struct b43legacy_pio *pio = &dev->pio; + struct b43legacy_pioqueue *queue; + int err = -ENOMEM; + + queue = b43legacy_setup_pioqueue(dev, B43legacy_MMIO_PIO1_BASE); + if (!queue) + goto out; + pio->queue0 = queue; + + queue = b43legacy_setup_pioqueue(dev, B43legacy_MMIO_PIO2_BASE); + if (!queue) + goto err_destroy0; + pio->queue1 = queue; + + queue = b43legacy_setup_pioqueue(dev, B43legacy_MMIO_PIO3_BASE); + if (!queue) + goto err_destroy1; + pio->queue2 = queue; + + queue = b43legacy_setup_pioqueue(dev, B43legacy_MMIO_PIO4_BASE); + if (!queue) + goto err_destroy2; + pio->queue3 = queue; + + if (dev->dev->id.revision < 3) + dev->irq_savedstate |= B43legacy_IRQ_PIO_WORKAROUND; + + b43legacydbg(dev->wl, "PIO initialized\n"); + err = 0; +out: + return err; + +err_destroy2: + b43legacy_destroy_pioqueue(pio->queue2); + pio->queue2 = NULL; +err_destroy1: + b43legacy_destroy_pioqueue(pio->queue1); + pio->queue1 = NULL; +err_destroy0: + b43legacy_destroy_pioqueue(pio->queue0); + pio->queue0 = NULL; + goto out; +} + +int b43legacy_pio_tx(struct b43legacy_wldev *dev, + struct sk_buff *skb, + struct ieee80211_tx_control *ctl) +{ + struct b43legacy_pioqueue *queue = dev->pio.queue1; + struct b43legacy_pio_txpacket *packet; + + B43legacy_WARN_ON(queue->tx_suspended); + B43legacy_WARN_ON(list_empty(&queue->txfree)); + + packet = list_entry(queue->txfree.next, struct b43legacy_pio_txpacket, + list); + packet->skb = skb; + + memset(&packet->txstat, 0, sizeof(packet->txstat)); + memcpy(&packet->txstat.control, ctl, sizeof(*ctl)); + + list_move_tail(&packet->list, &queue->txqueue); + queue->nr_txfree--; + queue->nr_tx_packets++; + B43legacy_WARN_ON(queue->nr_txfree >= B43legacy_PIO_MAXTXPACKETS); + + tasklet_schedule(&queue->txtask); + + return 0; +} + +void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev, + const struct b43legacy_txstatus *status) +{ + struct b43legacy_pioqueue *queue; + struct b43legacy_pio_txpacket *packet; + + queue = parse_cookie(dev, status->cookie, &packet); + B43legacy_WARN_ON(!queue); + + queue->tx_devq_packets--; + queue->tx_devq_used -= (packet->skb->len + + sizeof(struct b43legacy_txhdr_fw3)); + + if (status->acked) + packet->txstat.flags |= IEEE80211_TX_STATUS_ACK; + packet->txstat.retry_count = status->frame_count - 1; + ieee80211_tx_status_irqsafe(dev->wl->hw, packet->skb, + &(packet->txstat)); + packet->skb = NULL; + + free_txpacket(packet, 1); + /* If there are packets on the txqueue, poke the tasklet + * to transmit them. + */ + if (!list_empty(&queue->txqueue)) + tasklet_schedule(&queue->txtask); +} + +void b43legacy_pio_get_tx_stats(struct b43legacy_wldev *dev, + struct ieee80211_tx_queue_stats *stats) +{ + struct b43legacy_pio *pio = &dev->pio; + struct b43legacy_pioqueue *queue; + struct ieee80211_tx_queue_stats_data *data; + + queue = pio->queue1; + data = &(stats->data[0]); + data->len = B43legacy_PIO_MAXTXPACKETS - queue->nr_txfree; + data->limit = B43legacy_PIO_MAXTXPACKETS; + data->count = queue->nr_tx_packets; +} + +static void pio_rx_error(struct b43legacy_pioqueue *queue, + int clear_buffers, + const char *error) +{ + int i; + + b43legacyerr(queue->dev->wl, "PIO RX error: %s\n", error); + b43legacy_pio_write(queue, B43legacy_PIO_RXCTL, + B43legacy_PIO_RXCTL_READY); + if (clear_buffers) { + B43legacy_WARN_ON(queue->mmio_base != B43legacy_MMIO_PIO1_BASE); + for (i = 0; i < 15; i++) { + /* Dummy read. */ + b43legacy_pio_read(queue, B43legacy_PIO_RXDATA); + } + } +} + +void b43legacy_pio_rx(struct b43legacy_pioqueue *queue) +{ + __le16 preamble[21] = { 0 }; + struct b43legacy_rxhdr_fw3 *rxhdr; + u16 tmp; + u16 len; + u16 macstat; + int i; + int preamble_readwords; + struct sk_buff *skb; + + tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXCTL); + if (!(tmp & B43legacy_PIO_RXCTL_DATAAVAILABLE)) + return; + b43legacy_pio_write(queue, B43legacy_PIO_RXCTL, + B43legacy_PIO_RXCTL_DATAAVAILABLE); + + for (i = 0; i < 10; i++) { + tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXCTL); + if (tmp & B43legacy_PIO_RXCTL_READY) + goto data_ready; + udelay(10); + } + b43legacydbg(queue->dev->wl, "PIO RX timed out\n"); + return; +data_ready: + + len = b43legacy_pio_read(queue, B43legacy_PIO_RXDATA); + if (unlikely(len > 0x700)) { + pio_rx_error(queue, 0, "len > 0x700"); + return; + } + if (unlikely(len == 0 && queue->mmio_base != + B43legacy_MMIO_PIO4_BASE)) { + pio_rx_error(queue, 0, "len == 0"); + return; + } + preamble[0] = cpu_to_le16(len); + if (queue->mmio_base == B43legacy_MMIO_PIO4_BASE) + preamble_readwords = 14 / sizeof(u16); + else + preamble_readwords = 18 / sizeof(u16); + for (i = 0; i < preamble_readwords; i++) { + tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXDATA); + preamble[i + 1] = cpu_to_le16(tmp); + } + rxhdr = (struct b43legacy_rxhdr_fw3 *)preamble; + macstat = le16_to_cpu(rxhdr->mac_status); + if (macstat & B43legacy_RX_MAC_FCSERR) { + pio_rx_error(queue, + (queue->mmio_base == B43legacy_MMIO_PIO1_BASE), + "Frame FCS error"); + return; + } + if (queue->mmio_base == B43legacy_MMIO_PIO4_BASE) { + /* We received an xmit status. */ + struct b43legacy_hwtxstatus *hw; + + hw = (struct b43legacy_hwtxstatus *)(preamble + 1); + b43legacy_handle_hwtxstatus(queue->dev, hw); + + return; + } + + skb = dev_alloc_skb(len); + if (unlikely(!skb)) { + pio_rx_error(queue, 1, "OOM"); + return; + } + skb_put(skb, len); + for (i = 0; i < len - 1; i += 2) { + tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXDATA); + *((__le16 *)(skb->data + i)) = cpu_to_le16(tmp); + } + if (len % 2) { + tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXDATA); + skb->data[len - 1] = (tmp & 0x00FF); + } + b43legacy_rx(queue->dev, skb, rxhdr); +} + +void b43legacy_pio_tx_suspend(struct b43legacy_pioqueue *queue) +{ + b43legacy_power_saving_ctl_bits(queue->dev, -1, 1); + b43legacy_pio_write(queue, B43legacy_PIO_TXCTL, + b43legacy_pio_read(queue, B43legacy_PIO_TXCTL) + | B43legacy_PIO_TXCTL_SUSPEND); +} + +void b43legacy_pio_tx_resume(struct b43legacy_pioqueue *queue) +{ + b43legacy_pio_write(queue, B43legacy_PIO_TXCTL, + b43legacy_pio_read(queue, B43legacy_PIO_TXCTL) + & ~B43legacy_PIO_TXCTL_SUSPEND); + b43legacy_power_saving_ctl_bits(queue->dev, -1, -1); + tasklet_schedule(&queue->txtask); +} + +void b43legacy_pio_freeze_txqueues(struct b43legacy_wldev *dev) +{ + struct b43legacy_pio *pio; + + B43legacy_WARN_ON(!b43legacy_using_pio(dev)); + pio = &dev->pio; + pio->queue0->tx_frozen = 1; + pio->queue1->tx_frozen = 1; + pio->queue2->tx_frozen = 1; + pio->queue3->tx_frozen = 1; +} + +void b43legacy_pio_thaw_txqueues(struct b43legacy_wldev *dev) +{ + struct b43legacy_pio *pio; + + B43legacy_WARN_ON(!b43legacy_using_pio(dev)); + pio = &dev->pio; + pio->queue0->tx_frozen = 0; + pio->queue1->tx_frozen = 0; + pio->queue2->tx_frozen = 0; + pio->queue3->tx_frozen = 0; + if (!list_empty(&pio->queue0->txqueue)) + tasklet_schedule(&pio->queue0->txtask); + if (!list_empty(&pio->queue1->txqueue)) + tasklet_schedule(&pio->queue1->txtask); + if (!list_empty(&pio->queue2->txqueue)) + tasklet_schedule(&pio->queue2->txtask); + if (!list_empty(&pio->queue3->txqueue)) + tasklet_schedule(&pio->queue3->txtask); +} diff --git a/drivers/net/wireless/b43legacy/pio.h b/drivers/net/wireless/b43legacy/pio.h new file mode 100644 index 00000000000..5bfed0c4003 --- /dev/null +++ b/drivers/net/wireless/b43legacy/pio.h @@ -0,0 +1,172 @@ +#ifndef B43legacy_PIO_H_ +#define B43legacy_PIO_H_ + +#include "b43legacy.h" + +#include +#include +#include + + +#define B43legacy_PIO_TXCTL 0x00 +#define B43legacy_PIO_TXDATA 0x02 +#define B43legacy_PIO_TXQBUFSIZE 0x04 +#define B43legacy_PIO_RXCTL 0x08 +#define B43legacy_PIO_RXDATA 0x0A + +#define B43legacy_PIO_TXCTL_WRITELO (1 << 0) +#define B43legacy_PIO_TXCTL_WRITEHI (1 << 1) +#define B43legacy_PIO_TXCTL_COMPLETE (1 << 2) +#define B43legacy_PIO_TXCTL_INIT (1 << 3) +#define B43legacy_PIO_TXCTL_SUSPEND (1 << 7) + +#define B43legacy_PIO_RXCTL_DATAAVAILABLE (1 << 0) +#define B43legacy_PIO_RXCTL_READY (1 << 1) + +/* PIO constants */ +#define B43legacy_PIO_MAXTXDEVQPACKETS 31 +#define B43legacy_PIO_TXQADJUST 80 + +/* PIO tuning knobs */ +#define B43legacy_PIO_MAXTXPACKETS 256 + + + +#ifdef CONFIG_B43LEGACY_PIO + + +struct b43legacy_pioqueue; +struct b43legacy_xmitstatus; + +struct b43legacy_pio_txpacket { + struct b43legacy_pioqueue *queue; + struct sk_buff *skb; + struct ieee80211_tx_status txstat; + struct list_head list; +}; + +#define pio_txpacket_getindex(packet) ((int)((packet) - \ + (packet)->queue->tx_packets_cache)) + +struct b43legacy_pioqueue { + struct b43legacy_wldev *dev; + u16 mmio_base; + + bool tx_suspended; + bool tx_frozen; + bool need_workarounds; /* Workarounds needed for core.rev < 3 */ + + /* Adjusted size of the device internal TX buffer. */ + u16 tx_devq_size; + /* Used octets of the device internal TX buffer. */ + u16 tx_devq_used; + /* Used packet slots in the device internal TX buffer. */ + u8 tx_devq_packets; + /* Packets from the txfree list can + * be taken on incoming TX requests. + */ + struct list_head txfree; + unsigned int nr_txfree; + /* Packets on the txqueue are queued, + * but not completely written to the chip, yet. + */ + struct list_head txqueue; + /* Packets on the txrunning queue are completely + * posted to the device. We are waiting for the txstatus. + */ + struct list_head txrunning; + /* Total number or packets sent. + * (This counter can obviously wrap). + */ + unsigned int nr_tx_packets; + struct tasklet_struct txtask; + struct b43legacy_pio_txpacket + tx_packets_cache[B43legacy_PIO_MAXTXPACKETS]; +}; + +static inline +u16 b43legacy_pio_read(struct b43legacy_pioqueue *queue, + u16 offset) +{ + return b43legacy_read16(queue->dev, queue->mmio_base + offset); +} + +static inline +void b43legacy_pio_write(struct b43legacy_pioqueue *queue, + u16 offset, u16 value) +{ + b43legacy_write16(queue->dev, queue->mmio_base + offset, value); + mmiowb(); +} + + +int b43legacy_pio_init(struct b43legacy_wldev *dev); +void b43legacy_pio_free(struct b43legacy_wldev *dev); + +int b43legacy_pio_tx(struct b43legacy_wldev *dev, + struct sk_buff *skb, + struct ieee80211_tx_control *ctl); +void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev, + const struct b43legacy_txstatus *status); +void b43legacy_pio_get_tx_stats(struct b43legacy_wldev *dev, + struct ieee80211_tx_queue_stats *stats); +void b43legacy_pio_rx(struct b43legacy_pioqueue *queue); + +/* Suspend TX queue in hardware. */ +void b43legacy_pio_tx_suspend(struct b43legacy_pioqueue *queue); +void b43legacy_pio_tx_resume(struct b43legacy_pioqueue *queue); +/* Suspend (freeze) the TX tasklet (software level). */ +void b43legacy_pio_freeze_txqueues(struct b43legacy_wldev *dev); +void b43legacy_pio_thaw_txqueues(struct b43legacy_wldev *dev); + +#else /* CONFIG_B43LEGACY_PIO */ + +static inline +int b43legacy_pio_init(struct b43legacy_wldev *dev) +{ + return 0; +} +static inline +void b43legacy_pio_free(struct b43legacy_wldev *dev) +{ +} +static inline +int b43legacy_pio_tx(struct b43legacy_wldev *dev, + struct sk_buff *skb, + struct ieee80211_tx_control *ctl) +{ + return 0; +} +static inline +void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev, + const struct b43legacy_txstatus *status) +{ +} +static inline +void b43legacy_pio_get_tx_stats(struct b43legacy_wldev *dev, + struct ieee80211_tx_queue_stats *stats) +{ +} +static inline +void b43legacy_pio_rx(struct b43legacy_pioqueue *queue) +{ +} +static inline +void b43legacy_pio_tx_suspend(struct b43legacy_pioqueue *queue) +{ +} +static inline +void b43legacy_pio_tx_resume(struct b43legacy_pioqueue *queue) +{ +} +static inline +void b43legacy_pio_freeze_txqueues(struct b43legacy_wldev *dev) +{ +} +static inline +void b43legacy_pio_thaw_txqueues(struct b43legacy_wldev *dev) +{ +} + +#endif /* CONFIG_B43LEGACY_PIO */ +#endif /* B43legacy_PIO_H_ */ diff --git a/drivers/net/wireless/b43legacy/radio.c b/drivers/net/wireless/b43legacy/radio.c new file mode 100644 index 00000000000..2a11ee63f40 --- /dev/null +++ b/drivers/net/wireless/b43legacy/radio.c @@ -0,0 +1,2131 @@ +/* + + Broadcom B43legacy wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + Copyright (c) 2007 Larry Finger + + Some parts of the code in this file are derived from the ipw2200 + driver Copyright(c) 2003 - 2004 Intel Corporation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include + +#include "b43legacy.h" +#include "main.h" +#include "phy.h" +#include "radio.h" +#include "ilt.h" + + +/* Table for b43legacy_radio_calibrationvalue() */ +static const u16 rcc_table[16] = { + 0x0002, 0x0003, 0x0001, 0x000F, + 0x0006, 0x0007, 0x0005, 0x000F, + 0x000A, 0x000B, 0x0009, 0x000F, + 0x000E, 0x000F, 0x000D, 0x000F, +}; + +/* Reverse the bits of a 4bit value. + * Example: 1101 is flipped 1011 + */ +static u16 flip_4bit(u16 value) +{ + u16 flipped = 0x0000; + + B43legacy_BUG_ON(!((value & ~0x000F) == 0x0000)); + + flipped |= (value & 0x0001) << 3; + flipped |= (value & 0x0002) << 1; + flipped |= (value & 0x0004) >> 1; + flipped |= (value & 0x0008) >> 3; + + return flipped; +} + +/* Get the freq, as it has to be written to the device. */ +static inline +u16 channel2freq_bg(u8 channel) +{ + /* Frequencies are given as frequencies_bg[index] + 2.4GHz + * Starting with channel 1 + */ + static const u16 frequencies_bg[14] = { + 12, 17, 22, 27, + 32, 37, 42, 47, + 52, 57, 62, 67, + 72, 84, + }; + + if (unlikely(channel < 1 || channel > 14)) { + printk(KERN_INFO "b43legacy: Channel %d is out of range\n", + channel); + dump_stack(); + return 2412; + } + + return frequencies_bg[channel - 1]; +} + +void b43legacy_radio_lock(struct b43legacy_wldev *dev) +{ + u32 status; + + status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD); + status |= B43legacy_SBF_RADIOREG_LOCK; + b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status); + mmiowb(); + udelay(10); +} + +void b43legacy_radio_unlock(struct b43legacy_wldev *dev) +{ + u32 status; + + b43legacy_read16(dev, B43legacy_MMIO_PHY_VER); /* dummy read */ + status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD); + status &= ~B43legacy_SBF_RADIOREG_LOCK; + b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status); + mmiowb(); +} + +u16 b43legacy_radio_read16(struct b43legacy_wldev *dev, u16 offset) +{ + struct b43legacy_phy *phy = &dev->phy; + + switch (phy->type) { + case B43legacy_PHYTYPE_B: + if (phy->radio_ver == 0x2053) { + if (offset < 0x70) + offset += 0x80; + else if (offset < 0x80) + offset += 0x70; + } else if (phy->radio_ver == 0x2050) + offset |= 0x80; + else + B43legacy_WARN_ON(1); + break; + case B43legacy_PHYTYPE_G: + offset |= 0x80; + break; + default: + B43legacy_BUG_ON(1); + } + + b43legacy_write16(dev, B43legacy_MMIO_RADIO_CONTROL, offset); + return b43legacy_read16(dev, B43legacy_MMIO_RADIO_DATA_LOW); +} + +void b43legacy_radio_write16(struct b43legacy_wldev *dev, u16 offset, u16 val) +{ + b43legacy_write16(dev, B43legacy_MMIO_RADIO_CONTROL, offset); + mmiowb(); + b43legacy_write16(dev, B43legacy_MMIO_RADIO_DATA_LOW, val); +} + +static void b43legacy_set_all_gains(struct b43legacy_wldev *dev, + s16 first, s16 second, s16 third) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 i; + u16 start = 0x08; + u16 end = 0x18; + u16 offset = 0x0400; + u16 tmp; + + if (phy->rev <= 1) { + offset = 0x5000; + start = 0x10; + end = 0x20; + } + + for (i = 0; i < 4; i++) + b43legacy_ilt_write(dev, offset + i, first); + + for (i = start; i < end; i++) + b43legacy_ilt_write(dev, offset + i, second); + + if (third != -1) { + tmp = ((u16)third << 14) | ((u16)third << 6); + b43legacy_phy_write(dev, 0x04A0, + (b43legacy_phy_read(dev, 0x04A0) & 0xBFBF) + | tmp); + b43legacy_phy_write(dev, 0x04A1, + (b43legacy_phy_read(dev, 0x04A1) & 0xBFBF) + | tmp); + b43legacy_phy_write(dev, 0x04A2, + (b43legacy_phy_read(dev, 0x04A2) & 0xBFBF) + | tmp); + } + b43legacy_dummy_transmission(dev); +} + +static void b43legacy_set_original_gains(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 i; + u16 tmp; + u16 offset = 0x0400; + u16 start = 0x0008; + u16 end = 0x0018; + + if (phy->rev <= 1) { + offset = 0x5000; + start = 0x0010; + end = 0x0020; + } + + for (i = 0; i < 4; i++) { + tmp = (i & 0xFFFC); + tmp |= (i & 0x0001) << 1; + tmp |= (i & 0x0002) >> 1; + + b43legacy_ilt_write(dev, offset + i, tmp); + } + + for (i = start; i < end; i++) + b43legacy_ilt_write(dev, offset + i, i - start); + + b43legacy_phy_write(dev, 0x04A0, + (b43legacy_phy_read(dev, 0x04A0) & 0xBFBF) + | 0x4040); + b43legacy_phy_write(dev, 0x04A1, + (b43legacy_phy_read(dev, 0x04A1) & 0xBFBF) + | 0x4040); + b43legacy_phy_write(dev, 0x04A2, + (b43legacy_phy_read(dev, 0x04A2) & 0xBFBF) + | 0x4000); + b43legacy_dummy_transmission(dev); +} + +/* Synthetic PU workaround */ +static void b43legacy_synth_pu_workaround(struct b43legacy_wldev *dev, + u8 channel) +{ + struct b43legacy_phy *phy = &dev->phy; + + might_sleep(); + + if (phy->radio_ver != 0x2050 || phy->radio_rev >= 6) + /* We do not need the workaround. */ + return; + + if (channel <= 10) + b43legacy_write16(dev, B43legacy_MMIO_CHANNEL, + channel2freq_bg(channel + 4)); + else + b43legacy_write16(dev, B43legacy_MMIO_CHANNEL, + channel2freq_bg(channel)); + msleep(1); + b43legacy_write16(dev, B43legacy_MMIO_CHANNEL, + channel2freq_bg(channel)); +} + +u8 b43legacy_radio_aci_detect(struct b43legacy_wldev *dev, u8 channel) +{ + struct b43legacy_phy *phy = &dev->phy; + u8 ret = 0; + u16 saved; + u16 rssi; + u16 temp; + int i; + int j = 0; + + saved = b43legacy_phy_read(dev, 0x0403); + b43legacy_radio_selectchannel(dev, channel, 0); + b43legacy_phy_write(dev, 0x0403, (saved & 0xFFF8) | 5); + if (phy->aci_hw_rssi) + rssi = b43legacy_phy_read(dev, 0x048A) & 0x3F; + else + rssi = saved & 0x3F; + /* clamp temp to signed 5bit */ + if (rssi > 32) + rssi -= 64; + for (i = 0; i < 100; i++) { + temp = (b43legacy_phy_read(dev, 0x047F) >> 8) & 0x3F; + if (temp > 32) + temp -= 64; + if (temp < rssi) + j++; + if (j >= 20) + ret = 1; + } + b43legacy_phy_write(dev, 0x0403, saved); + + return ret; +} + +u8 b43legacy_radio_aci_scan(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + u8 ret[13]; + unsigned int channel = phy->channel; + unsigned int i; + unsigned int j; + unsigned int start; + unsigned int end; + unsigned long phylock_flags; + + if (!((phy->type == B43legacy_PHYTYPE_G) && (phy->rev > 0))) + return 0; + + b43legacy_phy_lock(dev, phylock_flags); + b43legacy_radio_lock(dev); + b43legacy_phy_write(dev, 0x0802, + b43legacy_phy_read(dev, 0x0802) & 0xFFFC); + b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, + b43legacy_phy_read(dev, B43legacy_PHY_G_CRS) + & 0x7FFF); + b43legacy_set_all_gains(dev, 3, 8, 1); + + start = (channel - 5 > 0) ? channel - 5 : 1; + end = (channel + 5 < 14) ? channel + 5 : 13; + + for (i = start; i <= end; i++) { + if (abs(channel - i) > 2) + ret[i-1] = b43legacy_radio_aci_detect(dev, i); + } + b43legacy_radio_selectchannel(dev, channel, 0); + b43legacy_phy_write(dev, 0x0802, + (b43legacy_phy_read(dev, 0x0802) & 0xFFFC) + | 0x0003); + b43legacy_phy_write(dev, 0x0403, + b43legacy_phy_read(dev, 0x0403) & 0xFFF8); + b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, + b43legacy_phy_read(dev, B43legacy_PHY_G_CRS) + | 0x8000); + b43legacy_set_original_gains(dev); + for (i = 0; i < 13; i++) { + if (!ret[i]) + continue; + end = (i + 5 < 13) ? i + 5 : 13; + for (j = i; j < end; j++) + ret[j] = 1; + } + b43legacy_radio_unlock(dev); + b43legacy_phy_unlock(dev, phylock_flags); + + return ret[channel - 1]; +} + +/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +void b43legacy_nrssi_hw_write(struct b43legacy_wldev *dev, u16 offset, s16 val) +{ + b43legacy_phy_write(dev, B43legacy_PHY_NRSSILT_CTRL, offset); + mmiowb(); + b43legacy_phy_write(dev, B43legacy_PHY_NRSSILT_DATA, (u16)val); +} + +/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +s16 b43legacy_nrssi_hw_read(struct b43legacy_wldev *dev, u16 offset) +{ + u16 val; + + b43legacy_phy_write(dev, B43legacy_PHY_NRSSILT_CTRL, offset); + val = b43legacy_phy_read(dev, B43legacy_PHY_NRSSILT_DATA); + + return (s16)val; +} + +/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +void b43legacy_nrssi_hw_update(struct b43legacy_wldev *dev, u16 val) +{ + u16 i; + s16 tmp; + + for (i = 0; i < 64; i++) { + tmp = b43legacy_nrssi_hw_read(dev, i); + tmp -= val; + tmp = limit_value(tmp, -32, 31); + b43legacy_nrssi_hw_write(dev, i, tmp); + } +} + +/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +void b43legacy_nrssi_mem_update(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + s16 i; + s16 delta; + s32 tmp; + + delta = 0x1F - phy->nrssi[0]; + for (i = 0; i < 64; i++) { + tmp = (i - delta) * phy->nrssislope; + tmp /= 0x10000; + tmp += 0x3A; + tmp = limit_value(tmp, 0, 0x3F); + phy->nrssi_lt[i] = tmp; + } +} + +static void b43legacy_calc_nrssi_offset(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 backup[20] = { 0 }; + s16 v47F; + u16 i; + u16 saved = 0xFFFF; + + backup[0] = b43legacy_phy_read(dev, 0x0001); + backup[1] = b43legacy_phy_read(dev, 0x0811); + backup[2] = b43legacy_phy_read(dev, 0x0812); + backup[3] = b43legacy_phy_read(dev, 0x0814); + backup[4] = b43legacy_phy_read(dev, 0x0815); + backup[5] = b43legacy_phy_read(dev, 0x005A); + backup[6] = b43legacy_phy_read(dev, 0x0059); + backup[7] = b43legacy_phy_read(dev, 0x0058); + backup[8] = b43legacy_phy_read(dev, 0x000A); + backup[9] = b43legacy_phy_read(dev, 0x0003); + backup[10] = b43legacy_radio_read16(dev, 0x007A); + backup[11] = b43legacy_radio_read16(dev, 0x0043); + + b43legacy_phy_write(dev, 0x0429, + b43legacy_phy_read(dev, 0x0429) & 0x7FFF); + b43legacy_phy_write(dev, 0x0001, + (b43legacy_phy_read(dev, 0x0001) & 0x3FFF) + | 0x4000); + b43legacy_phy_write(dev, 0x0811, + b43legacy_phy_read(dev, 0x0811) | 0x000C); + b43legacy_phy_write(dev, 0x0812, + (b43legacy_phy_read(dev, 0x0812) & 0xFFF3) + | 0x0004); + b43legacy_phy_write(dev, 0x0802, + b43legacy_phy_read(dev, 0x0802) & ~(0x1 | 0x2)); + if (phy->rev >= 6) { + backup[12] = b43legacy_phy_read(dev, 0x002E); + backup[13] = b43legacy_phy_read(dev, 0x002F); + backup[14] = b43legacy_phy_read(dev, 0x080F); + backup[15] = b43legacy_phy_read(dev, 0x0810); + backup[16] = b43legacy_phy_read(dev, 0x0801); + backup[17] = b43legacy_phy_read(dev, 0x0060); + backup[18] = b43legacy_phy_read(dev, 0x0014); + backup[19] = b43legacy_phy_read(dev, 0x0478); + + b43legacy_phy_write(dev, 0x002E, 0); + b43legacy_phy_write(dev, 0x002F, 0); + b43legacy_phy_write(dev, 0x080F, 0); + b43legacy_phy_write(dev, 0x0810, 0); + b43legacy_phy_write(dev, 0x0478, + b43legacy_phy_read(dev, 0x0478) | 0x0100); + b43legacy_phy_write(dev, 0x0801, + b43legacy_phy_read(dev, 0x0801) | 0x0040); + b43legacy_phy_write(dev, 0x0060, + b43legacy_phy_read(dev, 0x0060) | 0x0040); + b43legacy_phy_write(dev, 0x0014, + b43legacy_phy_read(dev, 0x0014) | 0x0200); + } + b43legacy_radio_write16(dev, 0x007A, + b43legacy_radio_read16(dev, 0x007A) | 0x0070); + b43legacy_radio_write16(dev, 0x007A, + b43legacy_radio_read16(dev, 0x007A) | 0x0080); + udelay(30); + + v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F); + if (v47F >= 0x20) + v47F -= 0x40; + if (v47F == 31) { + for (i = 7; i >= 4; i--) { + b43legacy_radio_write16(dev, 0x007B, i); + udelay(20); + v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) + & 0x003F); + if (v47F >= 0x20) + v47F -= 0x40; + if (v47F < 31 && saved == 0xFFFF) + saved = i; + } + if (saved == 0xFFFF) + saved = 4; + } else { + b43legacy_radio_write16(dev, 0x007A, + b43legacy_radio_read16(dev, 0x007A) + & 0x007F); + b43legacy_phy_write(dev, 0x0814, + b43legacy_phy_read(dev, 0x0814) | 0x0001); + b43legacy_phy_write(dev, 0x0815, + b43legacy_phy_read(dev, 0x0815) & 0xFFFE); + b43legacy_phy_write(dev, 0x0811, + b43legacy_phy_read(dev, 0x0811) | 0x000C); + b43legacy_phy_write(dev, 0x0812, + b43legacy_phy_read(dev, 0x0812) | 0x000C); + b43legacy_phy_write(dev, 0x0811, + b43legacy_phy_read(dev, 0x0811) | 0x0030); + b43legacy_phy_write(dev, 0x0812, + b43legacy_phy_read(dev, 0x0812) | 0x0030); + b43legacy_phy_write(dev, 0x005A, 0x0480); + b43legacy_phy_write(dev, 0x0059, 0x0810); + b43legacy_phy_write(dev, 0x0058, 0x000D); + if (phy->analog == 0) + b43legacy_phy_write(dev, 0x0003, 0x0122); + else + b43legacy_phy_write(dev, 0x000A, + b43legacy_phy_read(dev, 0x000A) + | 0x2000); + b43legacy_phy_write(dev, 0x0814, + b43legacy_phy_read(dev, 0x0814) | 0x0004); + b43legacy_phy_write(dev, 0x0815, + b43legacy_phy_read(dev, 0x0815) & 0xFFFB); + b43legacy_phy_write(dev, 0x0003, + (b43legacy_phy_read(dev, 0x0003) & 0xFF9F) + | 0x0040); + b43legacy_radio_write16(dev, 0x007A, + b43legacy_radio_read16(dev, 0x007A) + | 0x000F); + b43legacy_set_all_gains(dev, 3, 0, 1); + b43legacy_radio_write16(dev, 0x0043, + (b43legacy_radio_read16(dev, 0x0043) + & 0x00F0) | 0x000F); + udelay(30); + v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F); + if (v47F >= 0x20) + v47F -= 0x40; + if (v47F == -32) { + for (i = 0; i < 4; i++) { + b43legacy_radio_write16(dev, 0x007B, i); + udelay(20); + v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >> + 8) & 0x003F); + if (v47F >= 0x20) + v47F -= 0x40; + if (v47F > -31 && saved == 0xFFFF) + saved = i; + } + if (saved == 0xFFFF) + saved = 3; + } else + saved = 0; + } + b43legacy_radio_write16(dev, 0x007B, saved); + + if (phy->rev >= 6) { + b43legacy_phy_write(dev, 0x002E, backup[12]); + b43legacy_phy_write(dev, 0x002F, backup[13]); + b43legacy_phy_write(dev, 0x080F, backup[14]); + b43legacy_phy_write(dev, 0x0810, backup[15]); + } + b43legacy_phy_write(dev, 0x0814, backup[3]); + b43legacy_phy_write(dev, 0x0815, backup[4]); + b43legacy_phy_write(dev, 0x005A, backup[5]); + b43legacy_phy_write(dev, 0x0059, backup[6]); + b43legacy_phy_write(dev, 0x0058, backup[7]); + b43legacy_phy_write(dev, 0x000A, backup[8]); + b43legacy_phy_write(dev, 0x0003, backup[9]); + b43legacy_radio_write16(dev, 0x0043, backup[11]); + b43legacy_radio_write16(dev, 0x007A, backup[10]); + b43legacy_phy_write(dev, 0x0802, + b43legacy_phy_read(dev, 0x0802) | 0x1 | 0x2); + b43legacy_phy_write(dev, 0x0429, + b43legacy_phy_read(dev, 0x0429) | 0x8000); + b43legacy_set_original_gains(dev); + if (phy->rev >= 6) { + b43legacy_phy_write(dev, 0x0801, backup[16]); + b43legacy_phy_write(dev, 0x0060, backup[17]); + b43legacy_phy_write(dev, 0x0014, backup[18]); + b43legacy_phy_write(dev, 0x0478, backup[19]); + } + b43legacy_phy_write(dev, 0x0001, backup[0]); + b43legacy_phy_write(dev, 0x0812, backup[2]); + b43legacy_phy_write(dev, 0x0811, backup[1]); +} + +void b43legacy_calc_nrssi_slope(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 backup[18] = { 0 }; + u16 tmp; + s16 nrssi0; + s16 nrssi1; + + switch (phy->type) { + case B43legacy_PHYTYPE_B: + backup[0] = b43legacy_radio_read16(dev, 0x007A); + backup[1] = b43legacy_radio_read16(dev, 0x0052); + backup[2] = b43legacy_radio_read16(dev, 0x0043); + backup[3] = b43legacy_phy_read(dev, 0x0030); + backup[4] = b43legacy_phy_read(dev, 0x0026); + backup[5] = b43legacy_phy_read(dev, 0x0015); + backup[6] = b43legacy_phy_read(dev, 0x002A); + backup[7] = b43legacy_phy_read(dev, 0x0020); + backup[8] = b43legacy_phy_read(dev, 0x005A); + backup[9] = b43legacy_phy_read(dev, 0x0059); + backup[10] = b43legacy_phy_read(dev, 0x0058); + backup[11] = b43legacy_read16(dev, 0x03E2); + backup[12] = b43legacy_read16(dev, 0x03E6); + backup[13] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT); + + tmp = b43legacy_radio_read16(dev, 0x007A); + tmp &= (phy->rev >= 5) ? 0x007F : 0x000F; + b43legacy_radio_write16(dev, 0x007A, tmp); + b43legacy_phy_write(dev, 0x0030, 0x00FF); + b43legacy_write16(dev, 0x03EC, 0x7F7F); + b43legacy_phy_write(dev, 0x0026, 0x0000); + b43legacy_phy_write(dev, 0x0015, + b43legacy_phy_read(dev, 0x0015) | 0x0020); + b43legacy_phy_write(dev, 0x002A, 0x08A3); + b43legacy_radio_write16(dev, 0x007A, + b43legacy_radio_read16(dev, 0x007A) + | 0x0080); + + nrssi0 = (s16)b43legacy_phy_read(dev, 0x0027); + b43legacy_radio_write16(dev, 0x007A, + b43legacy_radio_read16(dev, 0x007A) + & 0x007F); + if (phy->analog >= 2) + b43legacy_write16(dev, 0x03E6, 0x0040); + else if (phy->analog == 0) + b43legacy_write16(dev, 0x03E6, 0x0122); + else + b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, + b43legacy_read16(dev, + B43legacy_MMIO_CHANNEL_EXT) & 0x2000); + b43legacy_phy_write(dev, 0x0020, 0x3F3F); + b43legacy_phy_write(dev, 0x0015, 0xF330); + b43legacy_radio_write16(dev, 0x005A, 0x0060); + b43legacy_radio_write16(dev, 0x0043, + b43legacy_radio_read16(dev, 0x0043) + & 0x00F0); + b43legacy_phy_write(dev, 0x005A, 0x0480); + b43legacy_phy_write(dev, 0x0059, 0x0810); + b43legacy_phy_write(dev, 0x0058, 0x000D); + udelay(20); + + nrssi1 = (s16)b43legacy_phy_read(dev, 0x0027); + b43legacy_phy_write(dev, 0x0030, backup[3]); + b43legacy_radio_write16(dev, 0x007A, backup[0]); + b43legacy_write16(dev, 0x03E2, backup[11]); + b43legacy_phy_write(dev, 0x0026, backup[4]); + b43legacy_phy_write(dev, 0x0015, backup[5]); + b43legacy_phy_write(dev, 0x002A, backup[6]); + b43legacy_synth_pu_workaround(dev, phy->channel); + if (phy->analog != 0) + b43legacy_write16(dev, 0x03F4, backup[13]); + + b43legacy_phy_write(dev, 0x0020, backup[7]); + b43legacy_phy_write(dev, 0x005A, backup[8]); + b43legacy_phy_write(dev, 0x0059, backup[9]); + b43legacy_phy_write(dev, 0x0058, backup[10]); + b43legacy_radio_write16(dev, 0x0052, backup[1]); + b43legacy_radio_write16(dev, 0x0043, backup[2]); + + if (nrssi0 == nrssi1) + phy->nrssislope = 0x00010000; + else + phy->nrssislope = 0x00400000 / (nrssi0 - nrssi1); + + if (nrssi0 <= -4) { + phy->nrssi[0] = nrssi0; + phy->nrssi[1] = nrssi1; + } + break; + case B43legacy_PHYTYPE_G: + if (phy->radio_rev >= 9) + return; + if (phy->radio_rev == 8) + b43legacy_calc_nrssi_offset(dev); + + b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, + b43legacy_phy_read(dev, B43legacy_PHY_G_CRS) + & 0x7FFF); + b43legacy_phy_write(dev, 0x0802, + b43legacy_phy_read(dev, 0x0802) & 0xFFFC); + backup[7] = b43legacy_read16(dev, 0x03E2); + b43legacy_write16(dev, 0x03E2, + b43legacy_read16(dev, 0x03E2) | 0x8000); + backup[0] = b43legacy_radio_read16(dev, 0x007A); + backup[1] = b43legacy_radio_read16(dev, 0x0052); + backup[2] = b43legacy_radio_read16(dev, 0x0043); + backup[3] = b43legacy_phy_read(dev, 0x0015); + backup[4] = b43legacy_phy_read(dev, 0x005A); + backup[5] = b43legacy_phy_read(dev, 0x0059); + backup[6] = b43legacy_phy_read(dev, 0x0058); + backup[8] = b43legacy_read16(dev, 0x03E6); + backup[9] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT); + if (phy->rev >= 3) { + backup[10] = b43legacy_phy_read(dev, 0x002E); + backup[11] = b43legacy_phy_read(dev, 0x002F); + backup[12] = b43legacy_phy_read(dev, 0x080F); + backup[13] = b43legacy_phy_read(dev, + B43legacy_PHY_G_LO_CONTROL); + backup[14] = b43legacy_phy_read(dev, 0x0801); + backup[15] = b43legacy_phy_read(dev, 0x0060); + backup[16] = b43legacy_phy_read(dev, 0x0014); + backup[17] = b43legacy_phy_read(dev, 0x0478); + b43legacy_phy_write(dev, 0x002E, 0); + b43legacy_phy_write(dev, B43legacy_PHY_G_LO_CONTROL, 0); + switch (phy->rev) { + case 4: case 6: case 7: + b43legacy_phy_write(dev, 0x0478, + b43legacy_phy_read(dev, + 0x0478) | 0x0100); + b43legacy_phy_write(dev, 0x0801, + b43legacy_phy_read(dev, + 0x0801) | 0x0040); + break; + case 3: case 5: + b43legacy_phy_write(dev, 0x0801, + b43legacy_phy_read(dev, + 0x0801) & 0xFFBF); + break; + } + b43legacy_phy_write(dev, 0x0060, + b43legacy_phy_read(dev, 0x0060) + | 0x0040); + b43legacy_phy_write(dev, 0x0014, + b43legacy_phy_read(dev, 0x0014) + | 0x0200); + } + b43legacy_radio_write16(dev, 0x007A, + b43legacy_radio_read16(dev, 0x007A) + | 0x0070); + b43legacy_set_all_gains(dev, 0, 8, 0); + b43legacy_radio_write16(dev, 0x007A, + b43legacy_radio_read16(dev, 0x007A) + & 0x00F7); + if (phy->rev >= 2) { + b43legacy_phy_write(dev, 0x0811, + (b43legacy_phy_read(dev, 0x0811) + & 0xFFCF) | 0x0030); + b43legacy_phy_write(dev, 0x0812, + (b43legacy_phy_read(dev, 0x0812) + & 0xFFCF) | 0x0010); + } + b43legacy_radio_write16(dev, 0x007A, + b43legacy_radio_read16(dev, 0x007A) + | 0x0080); + udelay(20); + + nrssi0 = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F); + if (nrssi0 >= 0x0020) + nrssi0 -= 0x0040; + + b43legacy_radio_write16(dev, 0x007A, + b43legacy_radio_read16(dev, 0x007A) + & 0x007F); + if (phy->analog >= 2) + b43legacy_phy_write(dev, 0x0003, + (b43legacy_phy_read(dev, 0x0003) + & 0xFF9F) | 0x0040); + + b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, + b43legacy_read16(dev, + B43legacy_MMIO_CHANNEL_EXT) | 0x2000); + b43legacy_radio_write16(dev, 0x007A, + b43legacy_radio_read16(dev, 0x007A) + | 0x000F); + b43legacy_phy_write(dev, 0x0015, 0xF330); + if (phy->rev >= 2) { + b43legacy_phy_write(dev, 0x0812, + (b43legacy_phy_read(dev, 0x0812) + & 0xFFCF) | 0x0020); + b43legacy_phy_write(dev, 0x0811, + (b43legacy_phy_read(dev, 0x0811) + & 0xFFCF) | 0x0020); + } + + b43legacy_set_all_gains(dev, 3, 0, 1); + if (phy->radio_rev == 8) + b43legacy_radio_write16(dev, 0x0043, 0x001F); + else { + tmp = b43legacy_radio_read16(dev, 0x0052) & 0xFF0F; + b43legacy_radio_write16(dev, 0x0052, tmp | 0x0060); + tmp = b43legacy_radio_read16(dev, 0x0043) & 0xFFF0; + b43legacy_radio_write16(dev, 0x0043, tmp | 0x0009); + } + b43legacy_phy_write(dev, 0x005A, 0x0480); + b43legacy_phy_write(dev, 0x0059, 0x0810); + b43legacy_phy_write(dev, 0x0058, 0x000D); + udelay(20); + nrssi1 = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F); + if (nrssi1 >= 0x0020) + nrssi1 -= 0x0040; + if (nrssi0 == nrssi1) + phy->nrssislope = 0x00010000; + else + phy->nrssislope = 0x00400000 / (nrssi0 - nrssi1); + if (nrssi0 >= -4) { + phy->nrssi[0] = nrssi1; + phy->nrssi[1] = nrssi0; + } + if (phy->rev >= 3) { + b43legacy_phy_write(dev, 0x002E, backup[10]); + b43legacy_phy_write(dev, 0x002F, backup[11]); + b43legacy_phy_write(dev, 0x080F, backup[12]); + b43legacy_phy_write(dev, B43legacy_PHY_G_LO_CONTROL, + backup[13]); + } + if (phy->rev >= 2) { + b43legacy_phy_write(dev, 0x0812, + b43legacy_phy_read(dev, 0x0812) + & 0xFFCF); + b43legacy_phy_write(dev, 0x0811, + b43legacy_phy_read(dev, 0x0811) + & 0xFFCF); + } + + b43legacy_radio_write16(dev, 0x007A, backup[0]); + b43legacy_radio_write16(dev, 0x0052, backup[1]); + b43legacy_radio_write16(dev, 0x0043, backup[2]); + b43legacy_write16(dev, 0x03E2, backup[7]); + b43legacy_write16(dev, 0x03E6, backup[8]); + b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, backup[9]); + b43legacy_phy_write(dev, 0x0015, backup[3]); + b43legacy_phy_write(dev, 0x005A, backup[4]); + b43legacy_phy_write(dev, 0x0059, backup[5]); + b43legacy_phy_write(dev, 0x0058, backup[6]); + b43legacy_synth_pu_workaround(dev, phy->channel); + b43legacy_phy_write(dev, 0x0802, + b43legacy_phy_read(dev, 0x0802) | 0x0003); + b43legacy_set_original_gains(dev); + b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, + b43legacy_phy_read(dev, B43legacy_PHY_G_CRS) + | 0x8000); + if (phy->rev >= 3) { + b43legacy_phy_write(dev, 0x0801, backup[14]); + b43legacy_phy_write(dev, 0x0060, backup[15]); + b43legacy_phy_write(dev, 0x0014, backup[16]); + b43legacy_phy_write(dev, 0x0478, backup[17]); + } + b43legacy_nrssi_mem_update(dev); + b43legacy_calc_nrssi_threshold(dev); + break; + default: + B43legacy_BUG_ON(1); + } +} + +void b43legacy_calc_nrssi_threshold(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + s32 threshold; + s32 a; + s32 b; + s16 tmp16; + u16 tmp_u16; + + switch (phy->type) { + case B43legacy_PHYTYPE_B: { + if (phy->radio_ver != 0x2050) + return; + if (!(dev->dev->bus->sprom.r1.boardflags_lo & + B43legacy_BFL_RSSI)) + return; + + if (phy->radio_rev >= 6) { + threshold = (phy->nrssi[1] - phy->nrssi[0]) * 32; + threshold += 20 * (phy->nrssi[0] + 1); + threshold /= 40; + } else + threshold = phy->nrssi[1] - 5; + + threshold = limit_value(threshold, 0, 0x3E); + b43legacy_phy_read(dev, 0x0020); /* dummy read */ + b43legacy_phy_write(dev, 0x0020, (((u16)threshold) << 8) + | 0x001C); + + if (phy->radio_rev >= 6) { + b43legacy_phy_write(dev, 0x0087, 0x0E0D); + b43legacy_phy_write(dev, 0x0086, 0x0C0B); + b43legacy_phy_write(dev, 0x0085, 0x0A09); + b43legacy_phy_write(dev, 0x0084, 0x0808); + b43legacy_phy_write(dev, 0x0083, 0x0808); + b43legacy_phy_write(dev, 0x0082, 0x0604); + b43legacy_phy_write(dev, 0x0081, 0x0302); + b43legacy_phy_write(dev, 0x0080, 0x0100); + } + break; + } + case B43legacy_PHYTYPE_G: + if (!phy->gmode || + !(dev->dev->bus->sprom.r1.boardflags_lo & + B43legacy_BFL_RSSI)) { + tmp16 = b43legacy_nrssi_hw_read(dev, 0x20); + if (tmp16 >= 0x20) + tmp16 -= 0x40; + if (tmp16 < 3) + b43legacy_phy_write(dev, 0x048A, + (b43legacy_phy_read(dev, + 0x048A) & 0xF000) | 0x09EB); + else + b43legacy_phy_write(dev, 0x048A, + (b43legacy_phy_read(dev, + 0x048A) & 0xF000) | 0x0AED); + } else { + if (phy->interfmode == + B43legacy_RADIO_INTERFMODE_NONWLAN) { + a = 0xE; + b = 0xA; + } else if (!phy->aci_wlan_automatic && + phy->aci_enable) { + a = 0x13; + b = 0x12; + } else { + a = 0xE; + b = 0x11; + } + + a = a * (phy->nrssi[1] - phy->nrssi[0]); + a += (phy->nrssi[0] << 6); + if (a < 32) + a += 31; + else + a += 32; + a = a >> 6; + a = limit_value(a, -31, 31); + + b = b * (phy->nrssi[1] - phy->nrssi[0]); + b += (phy->nrssi[0] << 6); + if (b < 32) + b += 31; + else + b += 32; + b = b >> 6; + b = limit_value(b, -31, 31); + + tmp_u16 = b43legacy_phy_read(dev, 0x048A) & 0xF000; + tmp_u16 |= ((u32)b & 0x0000003F); + tmp_u16 |= (((u32)a & 0x0000003F) << 6); + b43legacy_phy_write(dev, 0x048A, tmp_u16); + } + break; + default: + B43legacy_BUG_ON(1); + } +} + +/* Stack implementation to save/restore values from the + * interference mitigation code. + * It is save to restore values in random order. + */ +static void _stack_save(u32 *_stackptr, size_t *stackidx, + u8 id, u16 offset, u16 value) +{ + u32 *stackptr = &(_stackptr[*stackidx]); + + B43legacy_WARN_ON(!((offset & 0xE000) == 0x0000)); + B43legacy_WARN_ON(!((id & 0xF8) == 0x00)); + *stackptr = offset; + *stackptr |= ((u32)id) << 13; + *stackptr |= ((u32)value) << 16; + (*stackidx)++; + B43legacy_WARN_ON(!(*stackidx < B43legacy_INTERFSTACK_SIZE)); +} + +static u16 _stack_restore(u32 *stackptr, + u8 id, u16 offset) +{ + size_t i; + + B43legacy_WARN_ON(!((offset & 0xE000) == 0x0000)); + B43legacy_WARN_ON(!((id & 0xF8) == 0x00)); + for (i = 0; i < B43legacy_INTERFSTACK_SIZE; i++, stackptr++) { + if ((*stackptr & 0x00001FFF) != offset) + continue; + if (((*stackptr & 0x00007000) >> 13) != id) + continue; + return ((*stackptr & 0xFFFF0000) >> 16); + } + B43legacy_BUG_ON(1); + + return 0; +} + +#define phy_stacksave(offset) \ + do { \ + _stack_save(stack, &stackidx, 0x1, (offset), \ + b43legacy_phy_read(dev, (offset))); \ + } while (0) +#define phy_stackrestore(offset) \ + do { \ + b43legacy_phy_write(dev, (offset), \ + _stack_restore(stack, 0x1, \ + (offset))); \ + } while (0) +#define radio_stacksave(offset) \ + do { \ + _stack_save(stack, &stackidx, 0x2, (offset), \ + b43legacy_radio_read16(dev, (offset))); \ + } while (0) +#define radio_stackrestore(offset) \ + do { \ + b43legacy_radio_write16(dev, (offset), \ + _stack_restore(stack, 0x2, \ + (offset))); \ + } while (0) +#define ilt_stacksave(offset) \ + do { \ + _stack_save(stack, &stackidx, 0x3, (offset), \ + b43legacy_ilt_read(dev, (offset))); \ + } while (0) +#define ilt_stackrestore(offset) \ + do { \ + b43legacy_ilt_write(dev, (offset), \ + _stack_restore(stack, 0x3, \ + (offset))); \ + } while (0) + +static void +b43legacy_radio_interference_mitigation_enable(struct b43legacy_wldev *dev, + int mode) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 tmp; + u16 flipped; + u32 tmp32; + size_t stackidx = 0; + u32 *stack = phy->interfstack; + + switch (mode) { + case B43legacy_RADIO_INTERFMODE_NONWLAN: + if (phy->rev != 1) { + b43legacy_phy_write(dev, 0x042B, + b43legacy_phy_read(dev, 0x042B) + | 0x0800); + b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, + b43legacy_phy_read(dev, + B43legacy_PHY_G_CRS) & ~0x4000); + break; + } + radio_stacksave(0x0078); + tmp = (b43legacy_radio_read16(dev, 0x0078) & 0x001E); + flipped = flip_4bit(tmp); + if (flipped < 10 && flipped >= 8) + flipped = 7; + else if (flipped >= 10) + flipped -= 3; + flipped = flip_4bit(flipped); + flipped = (flipped << 1) | 0x0020; + b43legacy_radio_write16(dev, 0x0078, flipped); + + b43legacy_calc_nrssi_threshold(dev); + + phy_stacksave(0x0406); + b43legacy_phy_write(dev, 0x0406, 0x7E28); + + b43legacy_phy_write(dev, 0x042B, + b43legacy_phy_read(dev, 0x042B) | 0x0800); + b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD, + b43legacy_phy_read(dev, + B43legacy_PHY_RADIO_BITFIELD) | 0x1000); + + phy_stacksave(0x04A0); + b43legacy_phy_write(dev, 0x04A0, + (b43legacy_phy_read(dev, 0x04A0) & 0xC0C0) + | 0x0008); + phy_stacksave(0x04A1); + b43legacy_phy_write(dev, 0x04A1, + (b43legacy_phy_read(dev, 0x04A1) & 0xC0C0) + | 0x0605); + phy_stacksave(0x04A2); + b43legacy_phy_write(dev, 0x04A2, + (b43legacy_phy_read(dev, 0x04A2) & 0xC0C0) + | 0x0204); + phy_stacksave(0x04A8); + b43legacy_phy_write(dev, 0x04A8, + (b43legacy_phy_read(dev, 0x04A8) & 0xC0C0) + | 0x0803); + phy_stacksave(0x04AB); + b43legacy_phy_write(dev, 0x04AB, + (b43legacy_phy_read(dev, 0x04AB) & 0xC0C0) + | 0x0605); + + phy_stacksave(0x04A7); + b43legacy_phy_write(dev, 0x04A7, 0x0002); + phy_stacksave(0x04A3); + b43legacy_phy_write(dev, 0x04A3, 0x287A); + phy_stacksave(0x04A9); + b43legacy_phy_write(dev, 0x04A9, 0x2027); + phy_stacksave(0x0493); + b43legacy_phy_write(dev, 0x0493, 0x32F5); + phy_stacksave(0x04AA); + b43legacy_phy_write(dev, 0x04AA, 0x2027); + phy_stacksave(0x04AC); + b43legacy_phy_write(dev, 0x04AC, 0x32F5); + break; + case B43legacy_RADIO_INTERFMODE_MANUALWLAN: + if (b43legacy_phy_read(dev, 0x0033) & 0x0800) + break; + + phy->aci_enable = 1; + + phy_stacksave(B43legacy_PHY_RADIO_BITFIELD); + phy_stacksave(B43legacy_PHY_G_CRS); + if (phy->rev < 2) + phy_stacksave(0x0406); + else { + phy_stacksave(0x04C0); + phy_stacksave(0x04C1); + } + phy_stacksave(0x0033); + phy_stacksave(0x04A7); + phy_stacksave(0x04A3); + phy_stacksave(0x04A9); + phy_stacksave(0x04AA); + phy_stacksave(0x04AC); + phy_stacksave(0x0493); + phy_stacksave(0x04A1); + phy_stacksave(0x04A0); + phy_stacksave(0x04A2); + phy_stacksave(0x048A); + phy_stacksave(0x04A8); + phy_stacksave(0x04AB); + if (phy->rev == 2) { + phy_stacksave(0x04AD); + phy_stacksave(0x04AE); + } else if (phy->rev >= 3) { + phy_stacksave(0x04AD); + phy_stacksave(0x0415); + phy_stacksave(0x0416); + phy_stacksave(0x0417); + ilt_stacksave(0x1A00 + 0x2); + ilt_stacksave(0x1A00 + 0x3); + } + phy_stacksave(0x042B); + phy_stacksave(0x048C); + + b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD, + b43legacy_phy_read(dev, + B43legacy_PHY_RADIO_BITFIELD) & ~0x1000); + b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, + (b43legacy_phy_read(dev, + B43legacy_PHY_G_CRS) + & 0xFFFC) | 0x0002); + + b43legacy_phy_write(dev, 0x0033, 0x0800); + b43legacy_phy_write(dev, 0x04A3, 0x2027); + b43legacy_phy_write(dev, 0x04A9, 0x1CA8); + b43legacy_phy_write(dev, 0x0493, 0x287A); + b43legacy_phy_write(dev, 0x04AA, 0x1CA8); + b43legacy_phy_write(dev, 0x04AC, 0x287A); + + b43legacy_phy_write(dev, 0x04A0, + (b43legacy_phy_read(dev, 0x04A0) + & 0xFFC0) | 0x001A); + b43legacy_phy_write(dev, 0x04A7, 0x000D); + + if (phy->rev < 2) + b43legacy_phy_write(dev, 0x0406, 0xFF0D); + else if (phy->rev == 2) { + b43legacy_phy_write(dev, 0x04C0, 0xFFFF); + b43legacy_phy_write(dev, 0x04C1, 0x00A9); + } else { + b43legacy_phy_write(dev, 0x04C0, 0x00C1); + b43legacy_phy_write(dev, 0x04C1, 0x0059); + } + + b43legacy_phy_write(dev, 0x04A1, + (b43legacy_phy_read(dev, 0x04A1) + & 0xC0FF) | 0x1800); + b43legacy_phy_write(dev, 0x04A1, + (b43legacy_phy_read(dev, 0x04A1) + & 0xFFC0) | 0x0015); + b43legacy_phy_write(dev, 0x04A8, + (b43legacy_phy_read(dev, 0x04A8) + & 0xCFFF) | 0x1000); + b43legacy_phy_write(dev, 0x04A8, + (b43legacy_phy_read(dev, 0x04A8) + & 0xF0FF) | 0x0A00); + b43legacy_phy_write(dev, 0x04AB, + (b43legacy_phy_read(dev, 0x04AB) + & 0xCFFF) | 0x1000); + b43legacy_phy_write(dev, 0x04AB, + (b43legacy_phy_read(dev, 0x04AB) + & 0xF0FF) | 0x0800); + b43legacy_phy_write(dev, 0x04AB, + (b43legacy_phy_read(dev, 0x04AB) + & 0xFFCF) | 0x0010); + b43legacy_phy_write(dev, 0x04AB, + (b43legacy_phy_read(dev, 0x04AB) + & 0xFFF0) | 0x0005); + b43legacy_phy_write(dev, 0x04A8, + (b43legacy_phy_read(dev, 0x04A8) + & 0xFFCF) | 0x0010); + b43legacy_phy_write(dev, 0x04A8, + (b43legacy_phy_read(dev, 0x04A8) + & 0xFFF0) | 0x0006); + b43legacy_phy_write(dev, 0x04A2, + (b43legacy_phy_read(dev, 0x04A2) + & 0xF0FF) | 0x0800); + b43legacy_phy_write(dev, 0x04A0, + (b43legacy_phy_read(dev, 0x04A0) + & 0xF0FF) | 0x0500); + b43legacy_phy_write(dev, 0x04A2, + (b43legacy_phy_read(dev, 0x04A2) + & 0xFFF0) | 0x000B); + + if (phy->rev >= 3) { + b43legacy_phy_write(dev, 0x048A, + b43legacy_phy_read(dev, 0x048A) + & ~0x8000); + b43legacy_phy_write(dev, 0x0415, + (b43legacy_phy_read(dev, 0x0415) + & 0x8000) | 0x36D8); + b43legacy_phy_write(dev, 0x0416, + (b43legacy_phy_read(dev, 0x0416) + & 0x8000) | 0x36D8); + b43legacy_phy_write(dev, 0x0417, + (b43legacy_phy_read(dev, 0x0417) + & 0xFE00) | 0x016D); + } else { + b43legacy_phy_write(dev, 0x048A, + b43legacy_phy_read(dev, 0x048A) + | 0x1000); + b43legacy_phy_write(dev, 0x048A, + (b43legacy_phy_read(dev, 0x048A) + & 0x9FFF) | 0x2000); + tmp32 = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED, + B43legacy_UCODEFLAGS_OFFSET); + if (!(tmp32 & 0x800)) { + tmp32 |= 0x800; + b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, + B43legacy_UCODEFLAGS_OFFSET, + tmp32); + } + } + if (phy->rev >= 2) + b43legacy_phy_write(dev, 0x042B, + b43legacy_phy_read(dev, 0x042B) + | 0x0800); + b43legacy_phy_write(dev, 0x048C, + (b43legacy_phy_read(dev, 0x048C) + & 0xF0FF) | 0x0200); + if (phy->rev == 2) { + b43legacy_phy_write(dev, 0x04AE, + (b43legacy_phy_read(dev, 0x04AE) + & 0xFF00) | 0x007F); + b43legacy_phy_write(dev, 0x04AD, + (b43legacy_phy_read(dev, 0x04AD) + & 0x00FF) | 0x1300); + } else if (phy->rev >= 6) { + b43legacy_ilt_write(dev, 0x1A00 + 0x3, 0x007F); + b43legacy_ilt_write(dev, 0x1A00 + 0x2, 0x007F); + b43legacy_phy_write(dev, 0x04AD, + b43legacy_phy_read(dev, 0x04AD) + & 0x00FF); + } + b43legacy_calc_nrssi_slope(dev); + break; + default: + B43legacy_BUG_ON(1); + } +} + +static void +b43legacy_radio_interference_mitigation_disable(struct b43legacy_wldev *dev, + int mode) +{ + struct b43legacy_phy *phy = &dev->phy; + u32 tmp32; + u32 *stack = phy->interfstack; + + switch (mode) { + case B43legacy_RADIO_INTERFMODE_NONWLAN: + if (phy->rev != 1) { + b43legacy_phy_write(dev, 0x042B, + b43legacy_phy_read(dev, 0x042B) + & ~0x0800); + b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, + b43legacy_phy_read(dev, + B43legacy_PHY_G_CRS) | 0x4000); + break; + } + phy_stackrestore(0x0078); + b43legacy_calc_nrssi_threshold(dev); + phy_stackrestore(0x0406); + b43legacy_phy_write(dev, 0x042B, + b43legacy_phy_read(dev, 0x042B) & ~0x0800); + if (!dev->bad_frames_preempt) + b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD, + b43legacy_phy_read(dev, + B43legacy_PHY_RADIO_BITFIELD) + & ~(1 << 11)); + b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, + b43legacy_phy_read(dev, B43legacy_PHY_G_CRS) + | 0x4000); + phy_stackrestore(0x04A0); + phy_stackrestore(0x04A1); + phy_stackrestore(0x04A2); + phy_stackrestore(0x04A8); + phy_stackrestore(0x04AB); + phy_stackrestore(0x04A7); + phy_stackrestore(0x04A3); + phy_stackrestore(0x04A9); + phy_stackrestore(0x0493); + phy_stackrestore(0x04AA); + phy_stackrestore(0x04AC); + break; + case B43legacy_RADIO_INTERFMODE_MANUALWLAN: + if (!(b43legacy_phy_read(dev, 0x0033) & 0x0800)) + break; + + phy->aci_enable = 0; + + phy_stackrestore(B43legacy_PHY_RADIO_BITFIELD); + phy_stackrestore(B43legacy_PHY_G_CRS); + phy_stackrestore(0x0033); + phy_stackrestore(0x04A3); + phy_stackrestore(0x04A9); + phy_stackrestore(0x0493); + phy_stackrestore(0x04AA); + phy_stackrestore(0x04AC); + phy_stackrestore(0x04A0); + phy_stackrestore(0x04A7); + if (phy->rev >= 2) { + phy_stackrestore(0x04C0); + phy_stackrestore(0x04C1); + } else + phy_stackrestore(0x0406); + phy_stackrestore(0x04A1); + phy_stackrestore(0x04AB); + phy_stackrestore(0x04A8); + if (phy->rev == 2) { + phy_stackrestore(0x04AD); + phy_stackrestore(0x04AE); + } else if (phy->rev >= 3) { + phy_stackrestore(0x04AD); + phy_stackrestore(0x0415); + phy_stackrestore(0x0416); + phy_stackrestore(0x0417); + ilt_stackrestore(0x1A00 + 0x2); + ilt_stackrestore(0x1A00 + 0x3); + } + phy_stackrestore(0x04A2); + phy_stackrestore(0x04A8); + phy_stackrestore(0x042B); + phy_stackrestore(0x048C); + tmp32 = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED, + B43legacy_UCODEFLAGS_OFFSET); + if (tmp32 & 0x800) { + tmp32 &= ~0x800; + b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, + B43legacy_UCODEFLAGS_OFFSET, + tmp32); + } + b43legacy_calc_nrssi_slope(dev); + break; + default: + B43legacy_BUG_ON(1); + } +} + +#undef phy_stacksave +#undef phy_stackrestore +#undef radio_stacksave +#undef radio_stackrestore +#undef ilt_stacksave +#undef ilt_stackrestore + +int b43legacy_radio_set_interference_mitigation(struct b43legacy_wldev *dev, + int mode) +{ + struct b43legacy_phy *phy = &dev->phy; + int currentmode; + + if ((phy->type != B43legacy_PHYTYPE_G) || + (phy->rev == 0) || (!phy->gmode)) + return -ENODEV; + + phy->aci_wlan_automatic = 0; + switch (mode) { + case B43legacy_RADIO_INTERFMODE_AUTOWLAN: + phy->aci_wlan_automatic = 1; + if (phy->aci_enable) + mode = B43legacy_RADIO_INTERFMODE_MANUALWLAN; + else + mode = B43legacy_RADIO_INTERFMODE_NONE; + break; + case B43legacy_RADIO_INTERFMODE_NONE: + case B43legacy_RADIO_INTERFMODE_NONWLAN: + case B43legacy_RADIO_INTERFMODE_MANUALWLAN: + break; + default: + return -EINVAL; + } + + currentmode = phy->interfmode; + if (currentmode == mode) + return 0; + if (currentmode != B43legacy_RADIO_INTERFMODE_NONE) + b43legacy_radio_interference_mitigation_disable(dev, + currentmode); + + if (mode == B43legacy_RADIO_INTERFMODE_NONE) { + phy->aci_enable = 0; + phy->aci_hw_rssi = 0; + } else + b43legacy_radio_interference_mitigation_enable(dev, mode); + phy->interfmode = mode; + + return 0; +} + +u16 b43legacy_radio_calibrationvalue(struct b43legacy_wldev *dev) +{ + u16 reg; + u16 index; + u16 ret; + + reg = b43legacy_radio_read16(dev, 0x0060); + index = (reg & 0x001E) >> 1; + ret = rcc_table[index] << 1; + ret |= (reg & 0x0001); + ret |= 0x0020; + + return ret; +} + +#define LPD(L, P, D) (((L) << 2) | ((P) << 1) | ((D) << 0)) +static u16 b43legacy_get_812_value(struct b43legacy_wldev *dev, u8 lpd) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 loop_or = 0; + u16 adj_loopback_gain = phy->loopback_gain[0]; + u8 loop; + u16 extern_lna_control; + + if (!phy->gmode) + return 0; + if (!has_loopback_gain(phy)) { + if (phy->rev < 7 || !(dev->dev->bus->sprom.r1.boardflags_lo + & B43legacy_BFL_EXTLNA)) { + switch (lpd) { + case LPD(0, 1, 1): + return 0x0FB2; + case LPD(0, 0, 1): + return 0x00B2; + case LPD(1, 0, 1): + return 0x30B2; + case LPD(1, 0, 0): + return 0x30B3; + default: + B43legacy_BUG_ON(1); + } + } else { + switch (lpd) { + case LPD(0, 1, 1): + return 0x8FB2; + case LPD(0, 0, 1): + return 0x80B2; + case LPD(1, 0, 1): + return 0x20B2; + case LPD(1, 0, 0): + return 0x20B3; + default: + B43legacy_BUG_ON(1); + } + } + } else { + if (phy->radio_rev == 8) + adj_loopback_gain += 0x003E; + else + adj_loopback_gain += 0x0026; + if (adj_loopback_gain >= 0x46) { + adj_loopback_gain -= 0x46; + extern_lna_control = 0x3000; + } else if (adj_loopback_gain >= 0x3A) { + adj_loopback_gain -= 0x3A; + extern_lna_control = 0x2000; + } else if (adj_loopback_gain >= 0x2E) { + adj_loopback_gain -= 0x2E; + extern_lna_control = 0x1000; + } else { + adj_loopback_gain -= 0x10; + extern_lna_control = 0x0000; + } + for (loop = 0; loop < 16; loop++) { + u16 tmp = adj_loopback_gain - 6 * loop; + if (tmp < 6) + break; + } + + loop_or = (loop << 8) | extern_lna_control; + if (phy->rev >= 7 && dev->dev->bus->sprom.r1.boardflags_lo + & B43legacy_BFL_EXTLNA) { + if (extern_lna_control) + loop_or |= 0x8000; + switch (lpd) { + case LPD(0, 1, 1): + return 0x8F92; + case LPD(0, 0, 1): + return (0x8092 | loop_or); + case LPD(1, 0, 1): + return (0x2092 | loop_or); + case LPD(1, 0, 0): + return (0x2093 | loop_or); + default: + B43legacy_BUG_ON(1); + } + } else { + switch (lpd) { + case LPD(0, 1, 1): + return 0x0F92; + case LPD(0, 0, 1): + case LPD(1, 0, 1): + return (0x0092 | loop_or); + case LPD(1, 0, 0): + return (0x0093 | loop_or); + default: + B43legacy_BUG_ON(1); + } + } + } + return 0; +} + +u16 b43legacy_radio_init2050(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 backup[21] = { 0 }; + u16 ret; + u16 i; + u16 j; + u32 tmp1 = 0; + u32 tmp2 = 0; + + backup[0] = b43legacy_radio_read16(dev, 0x0043); + backup[14] = b43legacy_radio_read16(dev, 0x0051); + backup[15] = b43legacy_radio_read16(dev, 0x0052); + backup[1] = b43legacy_phy_read(dev, 0x0015); + backup[16] = b43legacy_phy_read(dev, 0x005A); + backup[17] = b43legacy_phy_read(dev, 0x0059); + backup[18] = b43legacy_phy_read(dev, 0x0058); + if (phy->type == B43legacy_PHYTYPE_B) { + backup[2] = b43legacy_phy_read(dev, 0x0030); + backup[3] = b43legacy_read16(dev, 0x03EC); + b43legacy_phy_write(dev, 0x0030, 0x00FF); + b43legacy_write16(dev, 0x03EC, 0x3F3F); + } else { + if (phy->gmode) { + backup[4] = b43legacy_phy_read(dev, 0x0811); + backup[5] = b43legacy_phy_read(dev, 0x0812); + backup[6] = b43legacy_phy_read(dev, 0x0814); + backup[7] = b43legacy_phy_read(dev, 0x0815); + backup[8] = b43legacy_phy_read(dev, + B43legacy_PHY_G_CRS); + backup[9] = b43legacy_phy_read(dev, 0x0802); + b43legacy_phy_write(dev, 0x0814, + (b43legacy_phy_read(dev, 0x0814) + | 0x0003)); + b43legacy_phy_write(dev, 0x0815, + (b43legacy_phy_read(dev, 0x0815) + & 0xFFFC)); + b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, + (b43legacy_phy_read(dev, + B43legacy_PHY_G_CRS) & 0x7FFF)); + b43legacy_phy_write(dev, 0x0802, + (b43legacy_phy_read(dev, 0x0802) + & 0xFFFC)); + if (phy->rev > 1) { /* loopback gain enabled */ + backup[19] = b43legacy_phy_read(dev, 0x080F); + backup[20] = b43legacy_phy_read(dev, 0x0810); + if (phy->rev >= 3) + b43legacy_phy_write(dev, 0x080F, + 0xC020); + else + b43legacy_phy_write(dev, 0x080F, + 0x8020); + b43legacy_phy_write(dev, 0x0810, 0x0000); + } + b43legacy_phy_write(dev, 0x0812, + b43legacy_get_812_value(dev, + LPD(0, 1, 1))); + if (phy->rev < 7 || + !(dev->dev->bus->sprom.r1.boardflags_lo + & B43legacy_BFL_EXTLNA)) + b43legacy_phy_write(dev, 0x0811, 0x01B3); + else + b43legacy_phy_write(dev, 0x0811, 0x09B3); + } + } + b43legacy_write16(dev, B43legacy_MMIO_PHY_RADIO, + (b43legacy_read16(dev, B43legacy_MMIO_PHY_RADIO) + | 0x8000)); + backup[10] = b43legacy_phy_read(dev, 0x0035); + b43legacy_phy_write(dev, 0x0035, + (b43legacy_phy_read(dev, 0x0035) & 0xFF7F)); + backup[11] = b43legacy_read16(dev, 0x03E6); + backup[12] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT); + + /* Initialization */ + if (phy->analog == 0) + b43legacy_write16(dev, 0x03E6, 0x0122); + else { + if (phy->analog >= 2) + b43legacy_phy_write(dev, 0x0003, + (b43legacy_phy_read(dev, 0x0003) + & 0xFFBF) | 0x0040); + b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, + (b43legacy_read16(dev, + B43legacy_MMIO_CHANNEL_EXT) | 0x2000)); + } + + ret = b43legacy_radio_calibrationvalue(dev); + + if (phy->type == B43legacy_PHYTYPE_B) + b43legacy_radio_write16(dev, 0x0078, 0x0026); + + if (phy->gmode) + b43legacy_phy_write(dev, 0x0812, + b43legacy_get_812_value(dev, + LPD(0, 1, 1))); + b43legacy_phy_write(dev, 0x0015, 0xBFAF); + b43legacy_phy_write(dev, 0x002B, 0x1403); + if (phy->gmode) + b43legacy_phy_write(dev, 0x0812, + b43legacy_get_812_value(dev, + LPD(0, 0, 1))); + b43legacy_phy_write(dev, 0x0015, 0xBFA0); + b43legacy_radio_write16(dev, 0x0051, + (b43legacy_radio_read16(dev, 0x0051) + | 0x0004)); + if (phy->radio_rev == 8) + b43legacy_radio_write16(dev, 0x0043, 0x001F); + else { + b43legacy_radio_write16(dev, 0x0052, 0x0000); + b43legacy_radio_write16(dev, 0x0043, + (b43legacy_radio_read16(dev, 0x0043) + & 0xFFF0) | 0x0009); + } + b43legacy_phy_write(dev, 0x0058, 0x0000); + + for (i = 0; i < 16; i++) { + b43legacy_phy_write(dev, 0x005A, 0x0480); + b43legacy_phy_write(dev, 0x0059, 0xC810); + b43legacy_phy_write(dev, 0x0058, 0x000D); + if (phy->gmode) + b43legacy_phy_write(dev, 0x0812, + b43legacy_get_812_value(dev, + LPD(1, 0, 1))); + b43legacy_phy_write(dev, 0x0015, 0xAFB0); + udelay(10); + if (phy->gmode) + b43legacy_phy_write(dev, 0x0812, + b43legacy_get_812_value(dev, + LPD(1, 0, 1))); + b43legacy_phy_write(dev, 0x0015, 0xEFB0); + udelay(10); + if (phy->gmode) + b43legacy_phy_write(dev, 0x0812, + b43legacy_get_812_value(dev, + LPD(1, 0, 0))); + b43legacy_phy_write(dev, 0x0015, 0xFFF0); + udelay(20); + tmp1 += b43legacy_phy_read(dev, 0x002D); + b43legacy_phy_write(dev, 0x0058, 0x0000); + if (phy->gmode) + b43legacy_phy_write(dev, 0x0812, + b43legacy_get_812_value(dev, + LPD(1, 0, 1))); + b43legacy_phy_write(dev, 0x0015, 0xAFB0); + } + + tmp1++; + tmp1 >>= 9; + udelay(10); + b43legacy_phy_write(dev, 0x0058, 0x0000); + + for (i = 0; i < 16; i++) { + b43legacy_radio_write16(dev, 0x0078, (flip_4bit(i) << 1) + | 0x0020); + backup[13] = b43legacy_radio_read16(dev, 0x0078); + udelay(10); + for (j = 0; j < 16; j++) { + b43legacy_phy_write(dev, 0x005A, 0x0D80); + b43legacy_phy_write(dev, 0x0059, 0xC810); + b43legacy_phy_write(dev, 0x0058, 0x000D); + if (phy->gmode) + b43legacy_phy_write(dev, 0x0812, + b43legacy_get_812_value(dev, + LPD(1, 0, 1))); + b43legacy_phy_write(dev, 0x0015, 0xAFB0); + udelay(10); + if (phy->gmode) + b43legacy_phy_write(dev, 0x0812, + b43legacy_get_812_value(dev, + LPD(1, 0, 1))); + b43legacy_phy_write(dev, 0x0015, 0xEFB0); + udelay(10); + if (phy->gmode) + b43legacy_phy_write(dev, 0x0812, + b43legacy_get_812_value(dev, + LPD(1, 0, 0))); + b43legacy_phy_write(dev, 0x0015, 0xFFF0); + udelay(10); + tmp2 += b43legacy_phy_read(dev, 0x002D); + b43legacy_phy_write(dev, 0x0058, 0x0000); + if (phy->gmode) + b43legacy_phy_write(dev, 0x0812, + b43legacy_get_812_value(dev, + LPD(1, 0, 1))); + b43legacy_phy_write(dev, 0x0015, 0xAFB0); + } + tmp2++; + tmp2 >>= 8; + if (tmp1 < tmp2) + break; + } + + /* Restore the registers */ + b43legacy_phy_write(dev, 0x0015, backup[1]); + b43legacy_radio_write16(dev, 0x0051, backup[14]); + b43legacy_radio_write16(dev, 0x0052, backup[15]); + b43legacy_radio_write16(dev, 0x0043, backup[0]); + b43legacy_phy_write(dev, 0x005A, backup[16]); + b43legacy_phy_write(dev, 0x0059, backup[17]); + b43legacy_phy_write(dev, 0x0058, backup[18]); + b43legacy_write16(dev, 0x03E6, backup[11]); + if (phy->analog != 0) + b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, backup[12]); + b43legacy_phy_write(dev, 0x0035, backup[10]); + b43legacy_radio_selectchannel(dev, phy->channel, 1); + if (phy->type == B43legacy_PHYTYPE_B) { + b43legacy_phy_write(dev, 0x0030, backup[2]); + b43legacy_write16(dev, 0x03EC, backup[3]); + } else { + if (phy->gmode) { + b43legacy_write16(dev, B43legacy_MMIO_PHY_RADIO, + (b43legacy_read16(dev, + B43legacy_MMIO_PHY_RADIO) & 0x7FFF)); + b43legacy_phy_write(dev, 0x0811, backup[4]); + b43legacy_phy_write(dev, 0x0812, backup[5]); + b43legacy_phy_write(dev, 0x0814, backup[6]); + b43legacy_phy_write(dev, 0x0815, backup[7]); + b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, + backup[8]); + b43legacy_phy_write(dev, 0x0802, backup[9]); + if (phy->rev > 1) { + b43legacy_phy_write(dev, 0x080F, backup[19]); + b43legacy_phy_write(dev, 0x0810, backup[20]); + } + } + } + if (i >= 15) + ret = backup[13]; + + return ret; +} + +static inline +u16 freq_r3A_value(u16 frequency) +{ + u16 value; + + if (frequency < 5091) + value = 0x0040; + else if (frequency < 5321) + value = 0x0000; + else if (frequency < 5806) + value = 0x0080; + else + value = 0x0040; + + return value; +} + +void b43legacy_radio_set_tx_iq(struct b43legacy_wldev *dev) +{ + static const u8 data_high[5] = { 0x00, 0x40, 0x80, 0x90, 0xD0 }; + static const u8 data_low[5] = { 0x00, 0x01, 0x05, 0x06, 0x0A }; + u16 tmp = b43legacy_radio_read16(dev, 0x001E); + int i; + int j; + + for (i = 0; i < 5; i++) { + for (j = 0; j < 5; j++) { + if (tmp == (data_high[i] | data_low[j])) { + b43legacy_phy_write(dev, 0x0069, (i - j) << 8 | + 0x00C0); + return; + } + } + } +} + +int b43legacy_radio_selectchannel(struct b43legacy_wldev *dev, + u8 channel, + int synthetic_pu_workaround) +{ + struct b43legacy_phy *phy = &dev->phy; + +/* TODO: Check if channel is valid - return -EINVAL if not */ + if (synthetic_pu_workaround) + b43legacy_synth_pu_workaround(dev, channel); + + b43legacy_write16(dev, B43legacy_MMIO_CHANNEL, + channel2freq_bg(channel)); + + if (channel == 14) { + if (dev->dev->bus->sprom.r1.country_code == 5) /* JAPAN) */ + b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, + B43legacy_UCODEFLAGS_OFFSET, + b43legacy_shm_read32(dev, + B43legacy_SHM_SHARED, + B43legacy_UCODEFLAGS_OFFSET) + & ~(1 << 7)); + else + b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, + B43legacy_UCODEFLAGS_OFFSET, + b43legacy_shm_read32(dev, + B43legacy_SHM_SHARED, + B43legacy_UCODEFLAGS_OFFSET) + | (1 << 7)); + b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, + b43legacy_read16(dev, + B43legacy_MMIO_CHANNEL_EXT) | (1 << 11)); + } else + b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, + b43legacy_read16(dev, + B43legacy_MMIO_CHANNEL_EXT) & 0xF7BF); + + phy->channel = channel; + /*XXX: Using the longer of 2 timeouts (8000 vs 2000 usecs). Specs states + * that 2000 usecs might suffice. */ + msleep(8); + + return 0; +} + +void b43legacy_radio_set_txantenna(struct b43legacy_wldev *dev, u32 val) +{ + u16 tmp; + + val <<= 8; + tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x0022) & 0xFCFF; + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0022, tmp | val); + tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x03A8) & 0xFCFF; + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x03A8, tmp | val); + tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x0054) & 0xFCFF; + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0054, tmp | val); +} + +/* http://bcm-specs.sipsolutions.net/TX_Gain_Base_Band */ +static u16 b43legacy_get_txgain_base_band(u16 txpower) +{ + u16 ret; + + B43legacy_WARN_ON(txpower > 63); + + if (txpower >= 54) + ret = 2; + else if (txpower >= 49) + ret = 4; + else if (txpower >= 44) + ret = 5; + else + ret = 6; + + return ret; +} + +/* http://bcm-specs.sipsolutions.net/TX_Gain_Radio_Frequency_Power_Amplifier */ +static u16 b43legacy_get_txgain_freq_power_amp(u16 txpower) +{ + u16 ret; + + B43legacy_WARN_ON(txpower > 63); + + if (txpower >= 32) + ret = 0; + else if (txpower >= 25) + ret = 1; + else if (txpower >= 20) + ret = 2; + else if (txpower >= 12) + ret = 3; + else + ret = 4; + + return ret; +} + +/* http://bcm-specs.sipsolutions.net/TX_Gain_Digital_Analog_Converter */ +static u16 b43legacy_get_txgain_dac(u16 txpower) +{ + u16 ret; + + B43legacy_WARN_ON(txpower > 63); + + if (txpower >= 54) + ret = txpower - 53; + else if (txpower >= 49) + ret = txpower - 42; + else if (txpower >= 44) + ret = txpower - 37; + else if (txpower >= 32) + ret = txpower - 32; + else if (txpower >= 25) + ret = txpower - 20; + else if (txpower >= 20) + ret = txpower - 13; + else if (txpower >= 12) + ret = txpower - 8; + else + ret = txpower; + + return ret; +} + +void b43legacy_radio_set_txpower_a(struct b43legacy_wldev *dev, u16 txpower) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 pamp; + u16 base; + u16 dac; + u16 ilt; + + txpower = limit_value(txpower, 0, 63); + + pamp = b43legacy_get_txgain_freq_power_amp(txpower); + pamp <<= 5; + pamp &= 0x00E0; + b43legacy_phy_write(dev, 0x0019, pamp); + + base = b43legacy_get_txgain_base_band(txpower); + base &= 0x000F; + b43legacy_phy_write(dev, 0x0017, base | 0x0020); + + ilt = b43legacy_ilt_read(dev, 0x3001); + ilt &= 0x0007; + + dac = b43legacy_get_txgain_dac(txpower); + dac <<= 3; + dac |= ilt; + + b43legacy_ilt_write(dev, 0x3001, dac); + + phy->txpwr_offset = txpower; + + /* TODO: FuncPlaceholder (Adjust BB loft cancel) */ +} + +void b43legacy_radio_set_txpower_bg(struct b43legacy_wldev *dev, + u16 baseband_attenuation, + u16 radio_attenuation, + u16 txpower) +{ + struct b43legacy_phy *phy = &dev->phy; + + if (baseband_attenuation == 0xFFFF) + baseband_attenuation = phy->bbatt; + if (radio_attenuation == 0xFFFF) + radio_attenuation = phy->rfatt; + if (txpower == 0xFFFF) + txpower = phy->txctl1; + phy->bbatt = baseband_attenuation; + phy->rfatt = radio_attenuation; + phy->txctl1 = txpower; + + B43legacy_WARN_ON(baseband_attenuation > 11); + if (phy->radio_rev < 6) + B43legacy_WARN_ON(radio_attenuation > 9); + else + B43legacy_WARN_ON(radio_attenuation > 31); + B43legacy_WARN_ON(txpower > 7); + + b43legacy_phy_set_baseband_attenuation(dev, baseband_attenuation); + b43legacy_radio_write16(dev, 0x0043, radio_attenuation); + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0064, + radio_attenuation); + if (phy->radio_ver == 0x2050) + b43legacy_radio_write16(dev, 0x0052, + (b43legacy_radio_read16(dev, 0x0052) + & ~0x0070) | ((txpower << 4) & 0x0070)); + /* FIXME: The spec is very weird and unclear here. */ + if (phy->type == B43legacy_PHYTYPE_G) + b43legacy_phy_lo_adjust(dev, 0); +} + +u16 b43legacy_default_baseband_attenuation(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + + if (phy->radio_ver == 0x2050 && phy->radio_rev < 6) + return 0; + return 2; +} + +u16 b43legacy_default_radio_attenuation(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + u16 att = 0xFFFF; + + switch (phy->radio_ver) { + case 0x2053: + switch (phy->radio_rev) { + case 1: + att = 6; + break; + } + break; + case 0x2050: + switch (phy->radio_rev) { + case 0: + att = 5; + break; + case 1: + if (phy->type == B43legacy_PHYTYPE_G) { + if (is_bcm_board_vendor(dev) && + dev->dev->bus->boardinfo.type == 0x421 && + dev->dev->bus->boardinfo.rev >= 30) + att = 3; + else if (is_bcm_board_vendor(dev) && + dev->dev->bus->boardinfo.type == 0x416) + att = 3; + else + att = 1; + } else { + if (is_bcm_board_vendor(dev) && + dev->dev->bus->boardinfo.type == 0x421 && + dev->dev->bus->boardinfo.rev >= 30) + att = 7; + else + att = 6; + } + break; + case 2: + if (phy->type == B43legacy_PHYTYPE_G) { + if (is_bcm_board_vendor(dev) && + dev->dev->bus->boardinfo.type == 0x421 && + dev->dev->bus->boardinfo.rev >= 30) + att = 3; + else if (is_bcm_board_vendor(dev) && + dev->dev->bus->boardinfo.type == + 0x416) + att = 5; + else if (dev->dev->bus->chip_id == 0x4320) + att = 4; + else + att = 3; + } else + att = 6; + break; + case 3: + att = 5; + break; + case 4: + case 5: + att = 1; + break; + case 6: + case 7: + att = 5; + break; + case 8: + att = 0x1A; + break; + case 9: + default: + att = 5; + } + } + if (is_bcm_board_vendor(dev) && + dev->dev->bus->boardinfo.type == 0x421) { + if (dev->dev->bus->boardinfo.rev < 0x43) + att = 2; + else if (dev->dev->bus->boardinfo.rev < 0x51) + att = 3; + } + if (att == 0xFFFF) + att = 5; + + return att; +} + +u16 b43legacy_default_txctl1(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + + if (phy->radio_ver != 0x2050) + return 0; + if (phy->radio_rev == 1) + return 3; + if (phy->radio_rev < 6) + return 2; + if (phy->radio_rev == 8) + return 1; + return 0; +} + +void b43legacy_radio_turn_on(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + int err; + + might_sleep(); + + if (phy->radio_on) + return; + + switch (phy->type) { + case B43legacy_PHYTYPE_B: + case B43legacy_PHYTYPE_G: + b43legacy_phy_write(dev, 0x0015, 0x8000); + b43legacy_phy_write(dev, 0x0015, 0xCC00); + b43legacy_phy_write(dev, 0x0015, + (phy->gmode ? 0x00C0 : 0x0000)); + err = b43legacy_radio_selectchannel(dev, + B43legacy_RADIO_DEFAULT_CHANNEL_BG, 1); + B43legacy_WARN_ON(err != 0); + break; + default: + B43legacy_BUG_ON(1); + } + phy->radio_on = 1; + b43legacydbg(dev->wl, "Radio turned on\n"); + b43legacy_leds_update(dev, 0); +} + +void b43legacy_radio_turn_off(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + + if (phy->type == B43legacy_PHYTYPE_G && dev->dev->id.revision >= 5) { + b43legacy_phy_write(dev, 0x0811, b43legacy_phy_read(dev, 0x0811) + | 0x008C); + b43legacy_phy_write(dev, 0x0812, b43legacy_phy_read(dev, 0x0812) + & 0xFF73); + } else + b43legacy_phy_write(dev, 0x0015, 0xAA00); + phy->radio_on = 0; + b43legacydbg(dev->wl, "Radio turned off\n"); + b43legacy_leds_update(dev, 0); +} + +void b43legacy_radio_clear_tssi(struct b43legacy_wldev *dev) +{ + struct b43legacy_phy *phy = &dev->phy; + + switch (phy->type) { + case B43legacy_PHYTYPE_B: + case B43legacy_PHYTYPE_G: + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0058, + 0x7F7F); + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x005a, + 0x7F7F); + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0070, + 0x7F7F); + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0072, + 0x7F7F); + break; + } +} diff --git a/drivers/net/wireless/b43legacy/radio.h b/drivers/net/wireless/b43legacy/radio.h new file mode 100644 index 00000000000..6c6a203439e --- /dev/null +++ b/drivers/net/wireless/b43legacy/radio.h @@ -0,0 +1,98 @@ +/* + + Broadcom B43legacy wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + + Some parts of the code in this file are derived from the ipw2200 + driver Copyright(c) 2003 - 2004 Intel Corporation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#ifndef B43legacy_RADIO_H_ +#define B43legacy_RADIO_H_ + +#include "b43legacy.h" + + +#define B43legacy_RADIO_DEFAULT_CHANNEL_BG 6 + +/* Force antenna 0. */ +#define B43legacy_RADIO_TXANTENNA_0 0 +/* Force antenna 1. */ +#define B43legacy_RADIO_TXANTENNA_1 1 +/* Use the RX antenna, that was selected for the most recently + * received good PLCP header. + */ +#define B43legacy_RADIO_TXANTENNA_LASTPLCP 3 +#define B43legacy_RADIO_TXANTENNA_DEFAULT B43legacy_RADIO_TXANTENNA_LASTPLCP + +#define B43legacy_RADIO_INTERFMODE_NONE 0 +#define B43legacy_RADIO_INTERFMODE_NONWLAN 1 +#define B43legacy_RADIO_INTERFMODE_MANUALWLAN 2 +#define B43legacy_RADIO_INTERFMODE_AUTOWLAN 3 + + +void b43legacy_radio_lock(struct b43legacy_wldev *dev); +void b43legacy_radio_unlock(struct b43legacy_wldev *dev); + +u16 b43legacy_radio_read16(struct b43legacy_wldev *dev, u16 offset); +void b43legacy_radio_write16(struct b43legacy_wldev *dev, u16 offset, u16 val); + +u16 b43legacy_radio_init2050(struct b43legacy_wldev *dev); + +void b43legacy_radio_turn_on(struct b43legacy_wldev *dev); +void b43legacy_radio_turn_off(struct b43legacy_wldev *dev); + +int b43legacy_radio_selectchannel(struct b43legacy_wldev *dev, u8 channel, + int synthetic_pu_workaround); + +void b43legacy_radio_set_txpower_a(struct b43legacy_wldev *dev, u16 txpower); +void b43legacy_radio_set_txpower_bg(struct b43legacy_wldev *dev, + u16 baseband_attenuation, u16 attenuation, + u16 txpower); + +u16 b43legacy_default_baseband_attenuation(struct b43legacy_wldev *dev); +u16 b43legacy_default_radio_attenuation(struct b43legacy_wldev *dev); +u16 b43legacy_default_txctl1(struct b43legacy_wldev *dev); + +void b43legacy_radio_set_txantenna(struct b43legacy_wldev *dev, u32 val); + +void b43legacy_radio_clear_tssi(struct b43legacy_wldev *dev); + +u8 b43legacy_radio_aci_detect(struct b43legacy_wldev *dev, u8 channel); +u8 b43legacy_radio_aci_scan(struct b43legacy_wldev *dev); + +int b43legacy_radio_set_interference_mitigation(struct b43legacy_wldev *dev, + int mode); + +void b43legacy_calc_nrssi_slope(struct b43legacy_wldev *dev); +void b43legacy_calc_nrssi_threshold(struct b43legacy_wldev *dev); +s16 b43legacy_nrssi_hw_read(struct b43legacy_wldev *dev, u16 offset); +void b43legacy_nrssi_hw_write(struct b43legacy_wldev *dev, u16 offset, s16 val); +void b43legacy_nrssi_hw_update(struct b43legacy_wldev *dev, u16 val); +void b43legacy_nrssi_mem_update(struct b43legacy_wldev *dev); + +void b43legacy_radio_set_tx_iq(struct b43legacy_wldev *dev); +u16 b43legacy_radio_calibrationvalue(struct b43legacy_wldev *dev); + +#endif /* B43legacy_RADIO_H_ */ diff --git a/drivers/net/wireless/b43legacy/sysfs.c b/drivers/net/wireless/b43legacy/sysfs.c new file mode 100644 index 00000000000..56c384fa9b1 --- /dev/null +++ b/drivers/net/wireless/b43legacy/sysfs.c @@ -0,0 +1,238 @@ +/* + + Broadcom B43legacy wireless driver + + SYSFS support routines + + Copyright (c) 2006 Michael Buesch + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "sysfs.h" +#include "b43legacy.h" +#include "main.h" +#include "phy.h" +#include "radio.h" + +#include + + +#define GENERIC_FILESIZE 64 + + +static int get_integer(const char *buf, size_t count) +{ + char tmp[10 + 1] = { 0 }; + int ret = -EINVAL; + + if (count == 0) + goto out; + count = min(count, (size_t)10); + memcpy(tmp, buf, count); + ret = simple_strtol(tmp, NULL, 10); +out: + return ret; +} + +static int get_boolean(const char *buf, size_t count) +{ + if (count != 0) { + if (buf[0] == '1') + return 1; + if (buf[0] == '0') + return 0; + if (count >= 4 && memcmp(buf, "true", 4) == 0) + return 1; + if (count >= 5 && memcmp(buf, "false", 5) == 0) + return 0; + if (count >= 3 && memcmp(buf, "yes", 3) == 0) + return 1; + if (count >= 2 && memcmp(buf, "no", 2) == 0) + return 0; + if (count >= 2 && memcmp(buf, "on", 2) == 0) + return 1; + if (count >= 3 && memcmp(buf, "off", 3) == 0) + return 0; + } + return -EINVAL; +} + +static ssize_t b43legacy_attr_interfmode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct b43legacy_wldev *wldev = dev_to_b43legacy_wldev(dev); + ssize_t count = 0; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + mutex_lock(&wldev->wl->mutex); + + switch (wldev->phy.interfmode) { + case B43legacy_INTERFMODE_NONE: + count = snprintf(buf, PAGE_SIZE, "0 (No Interference" + " Mitigation)\n"); + break; + case B43legacy_INTERFMODE_NONWLAN: + count = snprintf(buf, PAGE_SIZE, "1 (Non-WLAN Interference" + " Mitigation)\n"); + break; + case B43legacy_INTERFMODE_MANUALWLAN: + count = snprintf(buf, PAGE_SIZE, "2 (WLAN Interference" + " Mitigation)\n"); + break; + default: + B43legacy_WARN_ON(1); + } + + mutex_unlock(&wldev->wl->mutex); + + return count; +} + +static ssize_t b43legacy_attr_interfmode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct b43legacy_wldev *wldev = dev_to_b43legacy_wldev(dev); + unsigned long flags; + int err; + int mode; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + mode = get_integer(buf, count); + switch (mode) { + case 0: + mode = B43legacy_INTERFMODE_NONE; + break; + case 1: + mode = B43legacy_INTERFMODE_NONWLAN; + break; + case 2: + mode = B43legacy_INTERFMODE_MANUALWLAN; + break; + case 3: + mode = B43legacy_INTERFMODE_AUTOWLAN; + break; + default: + return -EINVAL; + } + + mutex_lock(&wldev->wl->mutex); + spin_lock_irqsave(&wldev->wl->irq_lock, flags); + + err = b43legacy_radio_set_interference_mitigation(wldev, mode); + if (err) + b43legacyerr(wldev->wl, "Interference Mitigation not " + "supported by device\n"); + mmiowb(); + spin_unlock_irqrestore(&wldev->wl->irq_lock, flags); + mutex_unlock(&wldev->wl->mutex); + + return err ? err : count; +} + +static DEVICE_ATTR(interference, 0644, + b43legacy_attr_interfmode_show, + b43legacy_attr_interfmode_store); + +static ssize_t b43legacy_attr_preamble_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct b43legacy_wldev *wldev = dev_to_b43legacy_wldev(dev); + ssize_t count; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + mutex_lock(&wldev->wl->mutex); + + if (wldev->short_preamble) + count = snprintf(buf, PAGE_SIZE, "1 (Short Preamble" + " enabled)\n"); + else + count = snprintf(buf, PAGE_SIZE, "0 (Short Preamble" + " disabled)\n"); + + mutex_unlock(&wldev->wl->mutex); + + return count; +} + +static ssize_t b43legacy_attr_preamble_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct b43legacy_wldev *wldev = dev_to_b43legacy_wldev(dev); + unsigned long flags; + int value; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + value = get_boolean(buf, count); + if (value < 0) + return value; + mutex_lock(&wldev->wl->mutex); + spin_lock_irqsave(&wldev->wl->irq_lock, flags); + + wldev->short_preamble = !!value; + + spin_unlock_irqrestore(&wldev->wl->irq_lock, flags); + mutex_unlock(&wldev->wl->mutex); + + return count; +} + +static DEVICE_ATTR(shortpreamble, 0644, + b43legacy_attr_preamble_show, + b43legacy_attr_preamble_store); + +int b43legacy_sysfs_register(struct b43legacy_wldev *wldev) +{ + struct device *dev = wldev->dev->dev; + int err; + + B43legacy_WARN_ON(b43legacy_status(wldev) != + B43legacy_STAT_INITIALIZED); + + err = device_create_file(dev, &dev_attr_interference); + if (err) + goto out; + err = device_create_file(dev, &dev_attr_shortpreamble); + if (err) + goto err_remove_interfmode; + +out: + return err; +err_remove_interfmode: + device_remove_file(dev, &dev_attr_interference); + goto out; +} + +void b43legacy_sysfs_unregister(struct b43legacy_wldev *wldev) +{ + struct device *dev = wldev->dev->dev; + + device_remove_file(dev, &dev_attr_shortpreamble); + device_remove_file(dev, &dev_attr_interference); +} diff --git a/drivers/net/wireless/b43legacy/sysfs.h b/drivers/net/wireless/b43legacy/sysfs.h new file mode 100644 index 00000000000..417d509803c --- /dev/null +++ b/drivers/net/wireless/b43legacy/sysfs.h @@ -0,0 +1,9 @@ +#ifndef B43legacy_SYSFS_H_ +#define B43legacy_SYSFS_H_ + +struct b43legacy_wldev; + +int b43legacy_sysfs_register(struct b43legacy_wldev *dev); +void b43legacy_sysfs_unregister(struct b43legacy_wldev *dev); + +#endif /* B43legacy_SYSFS_H_ */ diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c new file mode 100644 index 00000000000..fa1e65687a6 --- /dev/null +++ b/drivers/net/wireless/b43legacy/xmit.c @@ -0,0 +1,642 @@ +/* + + Broadcom B43legacy wireless driver + + Transmission (TX/RX) related functions. + + Copyright (C) 2005 Martin Langer + Copyright (C) 2005 Stefano Brivio + Copyright (C) 2005, 2006 Michael Buesch + Copyright (C) 2005 Danny van Dyk + Copyright (C) 2005 Andreas Jaggi + Copyright (C) 2007 Larry Finger + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include + +#include "xmit.h" +#include "phy.h" +#include "dma.h" +#include "pio.h" + + +/* Extract the bitrate out of a CCK PLCP header. */ +static u8 b43legacy_plcp_get_bitrate_cck(struct b43legacy_plcp_hdr6 *plcp) +{ + switch (plcp->raw[0]) { + case 0x0A: + return B43legacy_CCK_RATE_1MB; + case 0x14: + return B43legacy_CCK_RATE_2MB; + case 0x37: + return B43legacy_CCK_RATE_5MB; + case 0x6E: + return B43legacy_CCK_RATE_11MB; + } + B43legacy_BUG_ON(1); + return 0; +} + +/* Extract the bitrate out of an OFDM PLCP header. */ +static u8 b43legacy_plcp_get_bitrate_ofdm(struct b43legacy_plcp_hdr6 *plcp) +{ + switch (plcp->raw[0] & 0xF) { + case 0xB: + return B43legacy_OFDM_RATE_6MB; + case 0xF: + return B43legacy_OFDM_RATE_9MB; + case 0xA: + return B43legacy_OFDM_RATE_12MB; + case 0xE: + return B43legacy_OFDM_RATE_18MB; + case 0x9: + return B43legacy_OFDM_RATE_24MB; + case 0xD: + return B43legacy_OFDM_RATE_36MB; + case 0x8: + return B43legacy_OFDM_RATE_48MB; + case 0xC: + return B43legacy_OFDM_RATE_54MB; + } + B43legacy_BUG_ON(1); + return 0; +} + +u8 b43legacy_plcp_get_ratecode_cck(const u8 bitrate) +{ + switch (bitrate) { + case B43legacy_CCK_RATE_1MB: + return 0x0A; + case B43legacy_CCK_RATE_2MB: + return 0x14; + case B43legacy_CCK_RATE_5MB: + return 0x37; + case B43legacy_CCK_RATE_11MB: + return 0x6E; + } + B43legacy_BUG_ON(1); + return 0; +} + +u8 b43legacy_plcp_get_ratecode_ofdm(const u8 bitrate) +{ + switch (bitrate) { + case B43legacy_OFDM_RATE_6MB: + return 0xB; + case B43legacy_OFDM_RATE_9MB: + return 0xF; + case B43legacy_OFDM_RATE_12MB: + return 0xA; + case B43legacy_OFDM_RATE_18MB: + return 0xE; + case B43legacy_OFDM_RATE_24MB: + return 0x9; + case B43legacy_OFDM_RATE_36MB: + return 0xD; + case B43legacy_OFDM_RATE_48MB: + return 0x8; + case B43legacy_OFDM_RATE_54MB: + return 0xC; + } + B43legacy_BUG_ON(1); + return 0; +} + +void b43legacy_generate_plcp_hdr(struct b43legacy_plcp_hdr4 *plcp, + const u16 octets, const u8 bitrate) +{ + __le32 *data = &(plcp->data); + __u8 *raw = plcp->raw; + + if (b43legacy_is_ofdm_rate(bitrate)) { + u16 d; + + d = b43legacy_plcp_get_ratecode_ofdm(bitrate); + B43legacy_WARN_ON(octets & 0xF000); + d |= (octets << 5); + *data = cpu_to_le32(d); + } else { + u32 plen; + + plen = octets * 16 / bitrate; + if ((octets * 16 % bitrate) > 0) { + plen++; + if ((bitrate == B43legacy_CCK_RATE_11MB) + && ((octets * 8 % 11) < 4)) + raw[1] = 0x84; + else + raw[1] = 0x04; + } else + raw[1] = 0x04; + *data |= cpu_to_le32(plen << 16); + raw[0] = b43legacy_plcp_get_ratecode_cck(bitrate); + } +} + +static u8 b43legacy_calc_fallback_rate(u8 bitrate) +{ + switch (bitrate) { + case B43legacy_CCK_RATE_1MB: + return B43legacy_CCK_RATE_1MB; + case B43legacy_CCK_RATE_2MB: + return B43legacy_CCK_RATE_1MB; + case B43legacy_CCK_RATE_5MB: + return B43legacy_CCK_RATE_2MB; + case B43legacy_CCK_RATE_11MB: + return B43legacy_CCK_RATE_5MB; + case B43legacy_OFDM_RATE_6MB: + return B43legacy_CCK_RATE_5MB; + case B43legacy_OFDM_RATE_9MB: + return B43legacy_OFDM_RATE_6MB; + case B43legacy_OFDM_RATE_12MB: + return B43legacy_OFDM_RATE_9MB; + case B43legacy_OFDM_RATE_18MB: + return B43legacy_OFDM_RATE_12MB; + case B43legacy_OFDM_RATE_24MB: + return B43legacy_OFDM_RATE_18MB; + case B43legacy_OFDM_RATE_36MB: + return B43legacy_OFDM_RATE_24MB; + case B43legacy_OFDM_RATE_48MB: + return B43legacy_OFDM_RATE_36MB; + case B43legacy_OFDM_RATE_54MB: + return B43legacy_OFDM_RATE_48MB; + } + B43legacy_BUG_ON(1); + return 0; +} + +static void generate_txhdr_fw3(struct b43legacy_wldev *dev, + struct b43legacy_txhdr_fw3 *txhdr, + const unsigned char *fragment_data, + unsigned int fragment_len, + const struct ieee80211_tx_control *txctl, + u16 cookie) +{ + const struct ieee80211_hdr *wlhdr; + int use_encryption = (!(txctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)); + u16 fctl; + u8 rate; + u8 rate_fb; + int rate_ofdm; + int rate_fb_ofdm; + unsigned int plcp_fragment_len; + u32 mac_ctl = 0; + u16 phy_ctl = 0; + + wlhdr = (const struct ieee80211_hdr *)fragment_data; + fctl = le16_to_cpu(wlhdr->frame_control); + + memset(txhdr, 0, sizeof(*txhdr)); + + rate = txctl->tx_rate; + rate_ofdm = b43legacy_is_ofdm_rate(rate); + rate_fb = (txctl->alt_retry_rate == -1) ? rate : txctl->alt_retry_rate; + rate_fb_ofdm = b43legacy_is_ofdm_rate(rate_fb); + + txhdr->mac_frame_ctl = wlhdr->frame_control; + memcpy(txhdr->tx_receiver, wlhdr->addr1, 6); + + /* Calculate duration for fallback rate */ + if ((rate_fb == rate) || + (wlhdr->duration_id & cpu_to_le16(0x8000)) || + (wlhdr->duration_id == cpu_to_le16(0))) { + /* If the fallback rate equals the normal rate or the + * dur_id field contains an AID, CFP magic or 0, + * use the original dur_id field. */ + txhdr->dur_fb = wlhdr->duration_id; + } else { + int fbrate_base100kbps = B43legacy_RATE_TO_100KBPS(rate_fb); + txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw, + dev->wl->if_id, + fragment_len, + fbrate_base100kbps); + } + + plcp_fragment_len = fragment_len + FCS_LEN; + if (use_encryption) { + u8 key_idx = (u16)(txctl->key_idx); + struct b43legacy_key *key; + int wlhdr_len; + size_t iv_len; + + B43legacy_WARN_ON(key_idx >= dev->max_nr_keys); + key = &(dev->key[key_idx]); + + if (key->enabled) { + /* Hardware appends ICV. */ + plcp_fragment_len += txctl->icv_len; + + key_idx = b43legacy_kidx_to_fw(dev, key_idx); + mac_ctl |= (key_idx << B43legacy_TX4_MAC_KEYIDX_SHIFT) & + B43legacy_TX4_MAC_KEYIDX; + mac_ctl |= (key->algorithm << + B43legacy_TX4_MAC_KEYALG_SHIFT) & + B43legacy_TX4_MAC_KEYALG; + wlhdr_len = ieee80211_get_hdrlen(fctl); + iv_len = min((size_t)txctl->iv_len, + ARRAY_SIZE(txhdr->iv)); + memcpy(txhdr->iv, ((u8 *)wlhdr) + wlhdr_len, iv_len); + } + } + b43legacy_generate_plcp_hdr((struct b43legacy_plcp_hdr4 *) + (&txhdr->plcp), plcp_fragment_len, + rate); + b43legacy_generate_plcp_hdr((struct b43legacy_plcp_hdr4 *) + (&txhdr->plcp_fb), plcp_fragment_len, + rate_fb); + + /* PHY TX Control word */ + if (rate_ofdm) + phy_ctl |= B43legacy_TX4_PHY_OFDM; + if (dev->short_preamble) + phy_ctl |= B43legacy_TX4_PHY_SHORTPRMBL; + switch (txctl->antenna_sel_tx) { + case 0: + phy_ctl |= B43legacy_TX4_PHY_ANTLAST; + break; + case 1: + phy_ctl |= B43legacy_TX4_PHY_ANT0; + break; + case 2: + phy_ctl |= B43legacy_TX4_PHY_ANT1; + break; + default: + B43legacy_BUG_ON(1); + } + + /* MAC control */ + if (!(txctl->flags & IEEE80211_TXCTL_NO_ACK)) + mac_ctl |= B43legacy_TX4_MAC_ACK; + if (!(((fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) && + ((fctl & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL))) + mac_ctl |= B43legacy_TX4_MAC_HWSEQ; + if (txctl->flags & IEEE80211_TXCTL_FIRST_FRAGMENT) + mac_ctl |= B43legacy_TX4_MAC_STMSDU; + if (rate_fb_ofdm) + mac_ctl |= B43legacy_TX4_MAC_FALLBACKOFDM; + + /* Generate the RTS or CTS-to-self frame */ + if ((txctl->flags & IEEE80211_TXCTL_USE_RTS_CTS) || + (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) { + unsigned int len; + struct ieee80211_hdr *hdr; + int rts_rate; + int rts_rate_fb; + int rts_rate_ofdm; + int rts_rate_fb_ofdm; + + rts_rate = txctl->rts_cts_rate; + rts_rate_ofdm = b43legacy_is_ofdm_rate(rts_rate); + rts_rate_fb = b43legacy_calc_fallback_rate(rts_rate); + rts_rate_fb_ofdm = b43legacy_is_ofdm_rate(rts_rate_fb); + if (rts_rate_fb_ofdm) + mac_ctl |= B43legacy_TX4_MAC_CTSFALLBACKOFDM; + + if (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { + ieee80211_ctstoself_get(dev->wl->hw, + dev->wl->if_id, + fragment_data, + fragment_len, txctl, + (struct ieee80211_cts *) + (txhdr->rts_frame)); + mac_ctl |= B43legacy_TX4_MAC_SENDCTS; + len = sizeof(struct ieee80211_cts); + } else { + ieee80211_rts_get(dev->wl->hw, + dev->wl->if_id, + fragment_data, fragment_len, txctl, + (struct ieee80211_rts *) + (txhdr->rts_frame)); + mac_ctl |= B43legacy_TX4_MAC_SENDRTS; + len = sizeof(struct ieee80211_rts); + } + len += FCS_LEN; + b43legacy_generate_plcp_hdr((struct b43legacy_plcp_hdr4 *) + (&txhdr->rts_plcp), + len, rts_rate); + b43legacy_generate_plcp_hdr((struct b43legacy_plcp_hdr4 *) + (&txhdr->rts_plcp_fb), + len, rts_rate_fb); + hdr = (struct ieee80211_hdr *)(&txhdr->rts_frame); + txhdr->rts_dur_fb = hdr->duration_id; + mac_ctl |= B43legacy_TX4_MAC_LONGFRAME; + } + + /* Magic cookie */ + txhdr->cookie = cpu_to_le16(cookie); + + /* Apply the bitfields */ + txhdr->mac_ctl = cpu_to_le32(mac_ctl); + txhdr->phy_ctl = cpu_to_le16(phy_ctl); +} + +void b43legacy_generate_txhdr(struct b43legacy_wldev *dev, + u8 *txhdr, + const unsigned char *fragment_data, + unsigned int fragment_len, + const struct ieee80211_tx_control *txctl, + u16 cookie) +{ + generate_txhdr_fw3(dev, (struct b43legacy_txhdr_fw3 *)txhdr, + fragment_data, fragment_len, + txctl, cookie); +} + +static s8 b43legacy_rssi_postprocess(struct b43legacy_wldev *dev, + u8 in_rssi, int ofdm, + int adjust_2053, int adjust_2050) +{ + struct b43legacy_phy *phy = &dev->phy; + s32 tmp; + + switch (phy->radio_ver) { + case 0x2050: + if (ofdm) { + tmp = in_rssi; + if (tmp > 127) + tmp -= 256; + tmp *= 73; + tmp /= 64; + if (adjust_2050) + tmp += 25; + else + tmp -= 3; + } else { + if (dev->dev->bus->sprom.r1.boardflags_lo + & B43legacy_BFL_RSSI) { + if (in_rssi > 63) + in_rssi = 63; + tmp = phy->nrssi_lt[in_rssi]; + tmp = 31 - tmp; + tmp *= -131; + tmp /= 128; + tmp -= 57; + } else { + tmp = in_rssi; + tmp = 31 - tmp; + tmp *= -149; + tmp /= 128; + tmp -= 68; + } + if (phy->type == B43legacy_PHYTYPE_G && + adjust_2050) + tmp += 25; + } + break; + case 0x2060: + if (in_rssi > 127) + tmp = in_rssi - 256; + else + tmp = in_rssi; + break; + default: + tmp = in_rssi; + tmp -= 11; + tmp *= 103; + tmp /= 64; + if (adjust_2053) + tmp -= 109; + else + tmp -= 83; + } + + return (s8)tmp; +} + +void b43legacy_rx(struct b43legacy_wldev *dev, + struct sk_buff *skb, + const void *_rxhdr) +{ + struct ieee80211_rx_status status; + struct b43legacy_plcp_hdr6 *plcp; + struct ieee80211_hdr *wlhdr; + const struct b43legacy_rxhdr_fw3 *rxhdr = _rxhdr; + u16 fctl; + u16 phystat0; + u16 phystat3; + u16 chanstat; + u16 mactime; + u32 macstat; + u16 chanid; + u8 jssi; + int padding; + + memset(&status, 0, sizeof(status)); + + /* Get metadata about the frame from the header. */ + phystat0 = le16_to_cpu(rxhdr->phy_status0); + phystat3 = le16_to_cpu(rxhdr->phy_status3); + jssi = rxhdr->jssi; + macstat = le16_to_cpu(rxhdr->mac_status); + mactime = le16_to_cpu(rxhdr->mac_time); + chanstat = le16_to_cpu(rxhdr->channel); + + if (macstat & B43legacy_RX_MAC_FCSERR) + dev->wl->ieee_stats.dot11FCSErrorCount++; + + /* Skip PLCP and padding */ + padding = (macstat & B43legacy_RX_MAC_PADDING) ? 2 : 0; + if (unlikely(skb->len < (sizeof(struct b43legacy_plcp_hdr6) + + padding))) { + b43legacydbg(dev->wl, "RX: Packet size underrun (1)\n"); + goto drop; + } + plcp = (struct b43legacy_plcp_hdr6 *)(skb->data + padding); + skb_pull(skb, sizeof(struct b43legacy_plcp_hdr6) + padding); + /* The skb contains the Wireless Header + payload data now */ + if (unlikely(skb->len < (2+2+6/*minimum hdr*/ + FCS_LEN))) { + b43legacydbg(dev->wl, "RX: Packet size underrun (2)\n"); + goto drop; + } + wlhdr = (struct ieee80211_hdr *)(skb->data); + fctl = le16_to_cpu(wlhdr->frame_control); + + if ((macstat & B43legacy_RX_MAC_DEC) && + !(macstat & B43legacy_RX_MAC_DECERR)) { + unsigned int keyidx; + int wlhdr_len; + int iv_len; + int icv_len; + + keyidx = ((macstat & B43legacy_RX_MAC_KEYIDX) + >> B43legacy_RX_MAC_KEYIDX_SHIFT); + /* We must adjust the key index here. We want the "physical" + * key index, but the ucode passed it slightly different. + */ + keyidx = b43legacy_kidx_to_raw(dev, keyidx); + B43legacy_WARN_ON(keyidx >= dev->max_nr_keys); + + if (dev->key[keyidx].algorithm != B43legacy_SEC_ALGO_NONE) { + /* Remove PROTECTED flag to mark it as decrypted. */ + B43legacy_WARN_ON(!(fctl & IEEE80211_FCTL_PROTECTED)); + fctl &= ~IEEE80211_FCTL_PROTECTED; + wlhdr->frame_control = cpu_to_le16(fctl); + + wlhdr_len = ieee80211_get_hdrlen(fctl); + if (unlikely(skb->len < (wlhdr_len + 3))) { + b43legacydbg(dev->wl, "RX: Packet size" + " underrun3\n"); + goto drop; + } + if (skb->data[wlhdr_len + 3] & (1 << 5)) { + /* The Ext-IV Bit is set in the "KeyID" + * octet of the IV. + */ + iv_len = 8; + icv_len = 8; + } else { + iv_len = 4; + icv_len = 4; + } + if (unlikely(skb->len < (wlhdr_len + iv_len + + icv_len))) { + b43legacydbg(dev->wl, "RX: Packet size" + " underrun4\n"); + goto drop; + } + /* Remove the IV */ + memmove(skb->data + iv_len, skb->data, wlhdr_len); + skb_pull(skb, iv_len); + /* Remove the ICV */ + skb_trim(skb, skb->len - icv_len); + + status.flag |= RX_FLAG_DECRYPTED; + } + } + + status.ssi = b43legacy_rssi_postprocess(dev, jssi, + (phystat0 & B43legacy_RX_PHYST0_OFDM), + (phystat0 & B43legacy_RX_PHYST0_GAINCTL), + (phystat3 & B43legacy_RX_PHYST3_TRSTATE)); + status.noise = dev->stats.link_noise; + status.signal = (jssi * 100) / B43legacy_RX_MAX_SSI; + if (phystat0 & B43legacy_RX_PHYST0_OFDM) + status.rate = b43legacy_plcp_get_bitrate_ofdm(plcp); + else + status.rate = b43legacy_plcp_get_bitrate_cck(plcp); + status.antenna = !!(phystat0 & B43legacy_RX_PHYST0_ANT); + status.mactime = mactime; + + chanid = (chanstat & B43legacy_RX_CHAN_ID) >> + B43legacy_RX_CHAN_ID_SHIFT; + switch (chanstat & B43legacy_RX_CHAN_PHYTYPE) { + case B43legacy_PHYTYPE_B: + status.phymode = MODE_IEEE80211B; + status.freq = chanid + 2400; + status.channel = b43legacy_freq_to_channel_bg(chanid + 2400); + break; + case B43legacy_PHYTYPE_G: + status.phymode = MODE_IEEE80211G; + status.freq = chanid + 2400; + status.channel = b43legacy_freq_to_channel_bg(chanid + 2400); + break; + default: + b43legacywarn(dev->wl, "Unexpected value for chanstat (0x%X)\n", + chanstat); + } + + dev->stats.last_rx = jiffies; + ieee80211_rx_irqsafe(dev->wl->hw, skb, &status); + + return; +drop: + b43legacydbg(dev->wl, "RX: Packet dropped\n"); + dev_kfree_skb_any(skb); +} + +void b43legacy_handle_txstatus(struct b43legacy_wldev *dev, + const struct b43legacy_txstatus *status) +{ + b43legacy_debugfs_log_txstat(dev, status); + + if (status->intermediate) + return; + if (status->for_ampdu) + return; + if (!status->acked) + dev->wl->ieee_stats.dot11ACKFailureCount++; + if (status->rts_count) { + if (status->rts_count == 0xF) /* FIXME */ + dev->wl->ieee_stats.dot11RTSFailureCount++; + else + dev->wl->ieee_stats.dot11RTSSuccessCount++; + } + + if (b43legacy_using_pio(dev)) + b43legacy_pio_handle_txstatus(dev, status); + else + b43legacy_dma_handle_txstatus(dev, status); +} + +/* Handle TX status report as received through DMA/PIO queues */ +void b43legacy_handle_hwtxstatus(struct b43legacy_wldev *dev, + const struct b43legacy_hwtxstatus *hw) +{ + struct b43legacy_txstatus status; + u8 tmp; + + status.cookie = le16_to_cpu(hw->cookie); + status.seq = le16_to_cpu(hw->seq); + status.phy_stat = hw->phy_stat; + tmp = hw->count; + status.frame_count = (tmp >> 4); + status.rts_count = (tmp & 0x0F); + tmp = hw->flags; + status.supp_reason = ((tmp & 0x1C) >> 2); + status.pm_indicated = !!(tmp & 0x80); + status.intermediate = !!(tmp & 0x40); + status.for_ampdu = !!(tmp & 0x20); + status.acked = !!(tmp & 0x02); + + b43legacy_handle_txstatus(dev, &status); +} + +/* Stop any TX operation on the device (suspend the hardware queues) */ +void b43legacy_tx_suspend(struct b43legacy_wldev *dev) +{ + if (b43legacy_using_pio(dev)) + b43legacy_pio_freeze_txqueues(dev); + else + b43legacy_dma_tx_suspend(dev); +} + +/* Resume any TX operation on the device (resume the hardware queues) */ +void b43legacy_tx_resume(struct b43legacy_wldev *dev) +{ + if (b43legacy_using_pio(dev)) + b43legacy_pio_thaw_txqueues(dev); + else + b43legacy_dma_tx_resume(dev); +} + +/* Initialize the QoS parameters */ +void b43legacy_qos_init(struct b43legacy_wldev *dev) +{ + /* FIXME: This function must probably be called from the mac80211 + * config callback. */ +return; + + b43legacy_hf_write(dev, b43legacy_hf_read(dev) | B43legacy_HF_EDCF); + /* FIXME kill magic */ + b43legacy_write16(dev, 0x688, + b43legacy_read16(dev, 0x688) | 0x4); + + + /*TODO: We might need some stack support here to get the values. */ +} diff --git a/drivers/net/wireless/b43legacy/xmit.h b/drivers/net/wireless/b43legacy/xmit.h new file mode 100644 index 00000000000..8a155d0a5d1 --- /dev/null +++ b/drivers/net/wireless/b43legacy/xmit.h @@ -0,0 +1,259 @@ +#ifndef B43legacy_XMIT_H_ +#define B43legacy_XMIT_H_ + +#include "main.h" + + +#define _b43legacy_declare_plcp_hdr(size) \ + struct b43legacy_plcp_hdr##size { \ + union { \ + __le32 data; \ + __u8 raw[size]; \ + } __attribute__((__packed__)); \ + } __attribute__((__packed__)) + +/* struct b43legacy_plcp_hdr4 */ +_b43legacy_declare_plcp_hdr(4); +/* struct b43legacy_plcp_hdr6 */ +_b43legacy_declare_plcp_hdr(6); + +#undef _b43legacy_declare_plcp_hdr + + +/* TX header for v3 firmware */ +struct b43legacy_txhdr_fw3 { + __le32 mac_ctl; /* MAC TX control */ + __le16 mac_frame_ctl; /* Copy of the FrameControl */ + __le16 tx_fes_time_norm; /* TX FES Time Normal */ + __le16 phy_ctl; /* PHY TX control */ + __u8 iv[16]; /* Encryption IV */ + __u8 tx_receiver[6]; /* TX Frame Receiver address */ + __le16 tx_fes_time_fb; /* TX FES Time Fallback */ + struct b43legacy_plcp_hdr4 rts_plcp_fb; /* RTS fallback PLCP */ + __le16 rts_dur_fb; /* RTS fallback duration */ + struct b43legacy_plcp_hdr4 plcp_fb; /* Fallback PLCP */ + __le16 dur_fb; /* Fallback duration */ + PAD_BYTES(2); + __le16 cookie; + __le16 unknown_scb_stuff; + struct b43legacy_plcp_hdr6 rts_plcp; /* RTS PLCP */ + __u8 rts_frame[18]; /* The RTS frame (if used) */ + struct b43legacy_plcp_hdr6 plcp; +} __attribute__((__packed__)); + +/* MAC TX control */ +#define B43legacy_TX4_MAC_KEYIDX 0x0FF00000 /* Security key index */ +#define B43legacy_TX4_MAC_KEYIDX_SHIFT 20 +#define B43legacy_TX4_MAC_KEYALG 0x00070000 /* Security key algorithm */ +#define B43legacy_TX4_MAC_KEYALG_SHIFT 16 +#define B43legacy_TX4_MAC_LIFETIME 0x00001000 +#define B43legacy_TX4_MAC_FRAMEBURST 0x00000800 +#define B43legacy_TX4_MAC_SENDCTS 0x00000400 +#define B43legacy_TX4_MAC_AMPDU 0x00000300 +#define B43legacy_TX4_MAC_AMPDU_SHIFT 8 +#define B43legacy_TX4_MAC_CTSFALLBACKOFDM 0x00000200 +#define B43legacy_TX4_MAC_FALLBACKOFDM 0x00000100 +#define B43legacy_TX4_MAC_5GHZ 0x00000080 +#define B43legacy_TX4_MAC_IGNPMQ 0x00000020 +#define B43legacy_TX4_MAC_HWSEQ 0x00000010 /* Use Hardware Seq No */ +#define B43legacy_TX4_MAC_STMSDU 0x00000008 /* Start MSDU */ +#define B43legacy_TX4_MAC_SENDRTS 0x00000004 +#define B43legacy_TX4_MAC_LONGFRAME 0x00000002 +#define B43legacy_TX4_MAC_ACK 0x00000001 + +/* Extra Frame Types */ +#define B43legacy_TX4_EFT_FBOFDM 0x0001 /* Data frame fb rate type */ +#define B43legacy_TX4_EFT_RTSOFDM 0x0004 /* RTS/CTS rate type */ +#define B43legacy_TX4_EFT_RTSFBOFDM 0x0010 /* RTS/CTS fallback rate type */ + +/* PHY TX control word */ +#define B43legacy_TX4_PHY_OFDM 0x0001 /* Data frame rate type */ +#define B43legacy_TX4_PHY_SHORTPRMBL 0x0010 /* Use short preamble */ +#define B43legacy_TX4_PHY_ANT 0x03C0 /* Antenna selection */ +#define B43legacy_TX4_PHY_ANT0 0x0000 /* Use antenna 0 */ +#define B43legacy_TX4_PHY_ANT1 0x0100 /* Use antenna 1 */ +#define B43legacy_TX4_PHY_ANTLAST 0x0300 /* Use last used antenna */ + + + +void b43legacy_generate_txhdr(struct b43legacy_wldev *dev, + u8 *txhdr, + const unsigned char *fragment_data, + unsigned int fragment_len, + const struct ieee80211_tx_control *txctl, + u16 cookie); + + +/* Transmit Status */ +struct b43legacy_txstatus { + u16 cookie; /* The cookie from the txhdr */ + u16 seq; /* Sequence number */ + u8 phy_stat; /* PHY TX status */ + u8 frame_count; /* Frame transmit count */ + u8 rts_count; /* RTS transmit count */ + u8 supp_reason; /* Suppression reason */ + /* flags */ + u8 pm_indicated;/* PM mode indicated to AP */ + u8 intermediate;/* Intermediate status notification */ + u8 for_ampdu; /* Status is for an AMPDU (afterburner) */ + u8 acked; /* Wireless ACK received */ +}; + +/* txstatus supp_reason values */ +enum { + B43legacy_TXST_SUPP_NONE, /* Not suppressed */ + B43legacy_TXST_SUPP_PMQ, /* Suppressed due to PMQ entry */ + B43legacy_TXST_SUPP_FLUSH, /* Suppressed due to flush request */ + B43legacy_TXST_SUPP_PREV, /* Previous fragment failed */ + B43legacy_TXST_SUPP_CHAN, /* Channel mismatch */ + B43legacy_TXST_SUPP_LIFE, /* Lifetime expired */ + B43legacy_TXST_SUPP_UNDER, /* Buffer underflow */ + B43legacy_TXST_SUPP_ABNACK, /* Afterburner NACK */ +}; + +/* Transmit Status as received through DMA/PIO on old chips */ +struct b43legacy_hwtxstatus { + PAD_BYTES(4); + __le16 cookie; + u8 flags; + u8 count; + PAD_BYTES(2); + __le16 seq; + u8 phy_stat; + PAD_BYTES(1); +} __attribute__((__packed__)); + + +/* Receive header for v3 firmware. */ +struct b43legacy_rxhdr_fw3 { + __le16 frame_len; /* Frame length */ + PAD_BYTES(2); + __le16 phy_status0; /* PHY RX Status 0 */ + __u8 jssi; /* PHY RX Status 1: JSSI */ + __u8 sig_qual; /* PHY RX Status 1: Signal Quality */ + PAD_BYTES(2); /* PHY RX Status 2 */ + __le16 phy_status3; /* PHY RX Status 3 */ + __le16 mac_status; /* MAC RX status */ + __le16 mac_time; + __le16 channel; +} __attribute__((__packed__)); + + +/* PHY RX Status 0 */ +#define B43legacy_RX_PHYST0_GAINCTL 0x4000 /* Gain Control */ +#define B43legacy_RX_PHYST0_PLCPHCF 0x0200 +#define B43legacy_RX_PHYST0_PLCPFV 0x0100 +#define B43legacy_RX_PHYST0_SHORTPRMBL 0x0080 /* Recvd with Short Preamble */ +#define B43legacy_RX_PHYST0_LCRS 0x0040 +#define B43legacy_RX_PHYST0_ANT 0x0020 /* Antenna */ +#define B43legacy_RX_PHYST0_UNSRATE 0x0010 +#define B43legacy_RX_PHYST0_CLIP 0x000C +#define B43legacy_RX_PHYST0_CLIP_SHIFT 2 +#define B43legacy_RX_PHYST0_FTYPE 0x0003 /* Frame type */ +#define B43legacy_RX_PHYST0_CCK 0x0000 /* Frame type: CCK */ +#define B43legacy_RX_PHYST0_OFDM 0x0001 /* Frame type: OFDM */ +#define B43legacy_RX_PHYST0_PRE_N 0x0002 /* Pre-standard N-PHY frame */ +#define B43legacy_RX_PHYST0_STD_N 0x0003 /* Standard N-PHY frame */ + +/* PHY RX Status 2 */ +#define B43legacy_RX_PHYST2_LNAG 0xC000 /* LNA Gain */ +#define B43legacy_RX_PHYST2_LNAG_SHIFT 14 +#define B43legacy_RX_PHYST2_PNAG 0x3C00 /* PNA Gain */ +#define B43legacy_RX_PHYST2_PNAG_SHIFT 10 +#define B43legacy_RX_PHYST2_FOFF 0x03FF /* F offset */ + +/* PHY RX Status 3 */ +#define B43legacy_RX_PHYST3_DIGG 0x1800 /* DIG Gain */ +#define B43legacy_RX_PHYST3_DIGG_SHIFT 11 +#define B43legacy_RX_PHYST3_TRSTATE 0x0400 /* TR state */ + +/* MAC RX Status */ +#define B43legacy_RX_MAC_BEACONSENT 0x00008000 /* Beacon send flag */ +#define B43legacy_RX_MAC_KEYIDX 0x000007E0 /* Key index */ +#define B43legacy_RX_MAC_KEYIDX_SHIFT 5 +#define B43legacy_RX_MAC_DECERR 0x00000010 /* Decrypt error */ +#define B43legacy_RX_MAC_DEC 0x00000008 /* Decryption attempted */ +#define B43legacy_RX_MAC_PADDING 0x00000004 /* Pad bytes present */ +#define B43legacy_RX_MAC_RESP 0x00000002 /* Response frame xmitted */ +#define B43legacy_RX_MAC_FCSERR 0x00000001 /* FCS error */ + +/* RX channel */ +#define B43legacy_RX_CHAN_GAIN 0xFC00 /* Gain */ +#define B43legacy_RX_CHAN_GAIN_SHIFT 10 +#define B43legacy_RX_CHAN_ID 0x03FC /* Channel ID */ +#define B43legacy_RX_CHAN_ID_SHIFT 2 +#define B43legacy_RX_CHAN_PHYTYPE 0x0003 /* PHY type */ + + + +u8 b43legacy_plcp_get_ratecode_cck(const u8 bitrate); +u8 b43legacy_plcp_get_ratecode_ofdm(const u8 bitrate); + +void b43legacy_generate_plcp_hdr(struct b43legacy_plcp_hdr4 *plcp, + const u16 octets, const u8 bitrate); + +void b43legacy_rx(struct b43legacy_wldev *dev, + struct sk_buff *skb, + const void *_rxhdr); + +void b43legacy_handle_txstatus(struct b43legacy_wldev *dev, + const struct b43legacy_txstatus *status); + +void b43legacy_handle_hwtxstatus(struct b43legacy_wldev *dev, + const struct b43legacy_hwtxstatus *hw); + +void b43legacy_tx_suspend(struct b43legacy_wldev *dev); +void b43legacy_tx_resume(struct b43legacy_wldev *dev); + + +#define B43legacy_NR_QOSPARMS 22 +enum { + B43legacy_QOSPARM_TXOP = 0, + B43legacy_QOSPARM_CWMIN, + B43legacy_QOSPARM_CWMAX, + B43legacy_QOSPARM_CWCUR, + B43legacy_QOSPARM_AIFS, + B43legacy_QOSPARM_BSLOTS, + B43legacy_QOSPARM_REGGAP, + B43legacy_QOSPARM_STATUS, +}; + +void b43legacy_qos_init(struct b43legacy_wldev *dev); + + +/* Helper functions for converting the key-table index from "firmware-format" + * to "raw-format" and back. The firmware API changed for this at some revision. + * We need to account for that here. */ +static inline +int b43legacy_new_kidx_api(struct b43legacy_wldev *dev) +{ + /* FIXME: Not sure the change was at rev 351 */ + return (dev->fw.rev >= 351); +} +static inline +u8 b43legacy_kidx_to_fw(struct b43legacy_wldev *dev, u8 raw_kidx) +{ + u8 firmware_kidx; + if (b43legacy_new_kidx_api(dev)) + firmware_kidx = raw_kidx; + else { + if (raw_kidx >= 4) /* Is per STA key? */ + firmware_kidx = raw_kidx - 4; + else + firmware_kidx = raw_kidx; /* TX default key */ + } + return firmware_kidx; +} +static inline +u8 b43legacy_kidx_to_raw(struct b43legacy_wldev *dev, u8 firmware_kidx) +{ + u8 raw_kidx; + if (b43legacy_new_kidx_api(dev)) + raw_kidx = firmware_kidx; + else + /* RX default keys or per STA keys */ + raw_kidx = firmware_kidx + 4; + return raw_kidx; +} + +#endif /* B43legacy_XMIT_H_ */ -- cgit v1.2.3-70-g09d2 From b481de9ca074528fe8c429604e2777db8b89806a Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Tue, 25 Sep 2007 17:54:57 -0700 Subject: [IWLWIFI]: add iwlwifi wireless drivers This patch adds the mac80211 based wireless drivers for the Intel PRO/Wireless 3945ABG/BG Network Connection and Intel Wireless WiFi Link AGN (4965) adapters. [ Move driver into it's own directory -DaveM ] Signed-off-by: Zhu Yi Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- MAINTAINERS | 9 + drivers/net/wireless/Kconfig | 1 + drivers/net/wireless/Makefile | 2 + drivers/net/wireless/iwlwifi/Kconfig | 128 + drivers/net/wireless/iwlwifi/Makefile | 11 + drivers/net/wireless/iwlwifi/iwl-3945-hw.h | 118 + drivers/net/wireless/iwlwifi/iwl-3945-rs.c | 979 +++ drivers/net/wireless/iwlwifi/iwl-3945-rs.h | 191 + drivers/net/wireless/iwlwifi/iwl-3945.c | 2290 +++++++ drivers/net/wireless/iwlwifi/iwl-3945.h | 41 + drivers/net/wireless/iwlwifi/iwl-4965-hw.h | 581 ++ drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 2118 ++++++ drivers/net/wireless/iwlwifi/iwl-4965-rs.h | 266 + drivers/net/wireless/iwlwifi/iwl-4965.c | 4719 ++++++++++++++ drivers/net/wireless/iwlwifi/iwl-4965.h | 341 + drivers/net/wireless/iwlwifi/iwl-channel.h | 161 + drivers/net/wireless/iwlwifi/iwl-commands.h | 1734 +++++ drivers/net/wireless/iwlwifi/iwl-debug.h | 149 + drivers/net/wireless/iwlwifi/iwl-eeprom.h | 336 + drivers/net/wireless/iwlwifi/iwl-helpers.h | 255 + drivers/net/wireless/iwlwifi/iwl-hw.h | 537 ++ drivers/net/wireless/iwlwifi/iwl-io.h | 470 ++ drivers/net/wireless/iwlwifi/iwl-priv.h | 308 + drivers/net/wireless/iwlwifi/iwl-prph.h | 229 + drivers/net/wireless/iwlwifi/iwl-spectrum.h | 91 + drivers/net/wireless/iwlwifi/iwl3945-base.c | 8732 +++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl4965-base.c | 9323 +++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwlwifi.h | 713 ++ 28 files changed, 34833 insertions(+) create mode 100644 drivers/net/wireless/iwlwifi/Kconfig create mode 100644 drivers/net/wireless/iwlwifi/Makefile create mode 100644 drivers/net/wireless/iwlwifi/iwl-3945-hw.h create mode 100644 drivers/net/wireless/iwlwifi/iwl-3945-rs.c create mode 100644 drivers/net/wireless/iwlwifi/iwl-3945-rs.h create mode 100644 drivers/net/wireless/iwlwifi/iwl-3945.c create mode 100644 drivers/net/wireless/iwlwifi/iwl-3945.h create mode 100644 drivers/net/wireless/iwlwifi/iwl-4965-hw.h create mode 100644 drivers/net/wireless/iwlwifi/iwl-4965-rs.c create mode 100644 drivers/net/wireless/iwlwifi/iwl-4965-rs.h create mode 100644 drivers/net/wireless/iwlwifi/iwl-4965.c create mode 100644 drivers/net/wireless/iwlwifi/iwl-4965.h create mode 100644 drivers/net/wireless/iwlwifi/iwl-channel.h create mode 100644 drivers/net/wireless/iwlwifi/iwl-commands.h create mode 100644 drivers/net/wireless/iwlwifi/iwl-debug.h create mode 100644 drivers/net/wireless/iwlwifi/iwl-eeprom.h create mode 100644 drivers/net/wireless/iwlwifi/iwl-helpers.h create mode 100644 drivers/net/wireless/iwlwifi/iwl-hw.h create mode 100644 drivers/net/wireless/iwlwifi/iwl-io.h create mode 100644 drivers/net/wireless/iwlwifi/iwl-priv.h create mode 100644 drivers/net/wireless/iwlwifi/iwl-prph.h create mode 100644 drivers/net/wireless/iwlwifi/iwl-spectrum.h create mode 100644 drivers/net/wireless/iwlwifi/iwl3945-base.c create mode 100644 drivers/net/wireless/iwlwifi/iwl4965-base.c create mode 100644 drivers/net/wireless/iwlwifi/iwlwifi.h (limited to 'drivers') diff --git a/MAINTAINERS b/MAINTAINERS index ef9402807de..934afd3dfa4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2080,6 +2080,15 @@ L: http://lists.sourceforge.net/mailman/listinfo/ipw2100-devel W: http://ipw2200.sourceforge.net S: Supported +INTEL WIRELESS WIFI LINK (iwlwifi) +P: Zhu Yi +M: yi.zhu@intel.com +L: linux-wireless@vger.kernel.org +L: ipw3945-devel@lists.sourceforge.net +W: http://intellinuxwireless.org +T: git git://intellinuxwireless.org/repos/iwlwifi +S: Supported + IOC3 ETHERNET DRIVER P: Ralf Baechle M: ralf@linux-mips.org diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index c2102653b2a..085ba132835 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -577,6 +577,7 @@ config ADM8211 Thanks to Infineon-ADMtek for their support of this driver. +source "drivers/net/wireless/iwlwifi/Kconfig" source "drivers/net/wireless/hostap/Kconfig" source "drivers/net/wireless/bcm43xx/Kconfig" source "drivers/net/wireless/b43/Kconfig" diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index d8dd907e499..351024f2fe7 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -51,3 +51,5 @@ rtl8187-objs := rtl8187_dev.o rtl8187_rtl8225.o obj-$(CONFIG_RTL8187) += rtl8187.o obj-$(CONFIG_ADM8211) += adm8211.o + +obj-$(CONFIG_IWLWIFI) += iwlwifi/ diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig new file mode 100644 index 00000000000..25cfc6c3250 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -0,0 +1,128 @@ +config IWLWIFI + bool "Intel Wireless WiFi Link Drivers" + depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL + select FW_LOADER + default n + ---help--- + Select to enable drivers based on the iwlwifi project. This + project provides a common foundation for Intel's wireless + drivers designed to use the mac80211 subsystem. + + See for + information on the capabilities currently enabled in this + driver and for tips for debugging issues and problems. + +config IWLWIFI_DEBUG + bool "Enable full debugging output in iwlwifi drivers" + depends on IWLWIFI + default y + ---help--- + This option will enable debug tracing output for the iwlwifi + drivers. + + This will result in the kernel module being ~100k larger. You can + control which debug output is sent to the kernel log by setting the + value in + + /sys/bus/pci/drivers/${DRIVER}/debug_level + + This entry will only exist if this option is enabled. + + To set a value, simply echo an 8-byte hex value to the same file: + + % echo 0x43fff > /sys/bus/pci/drivers/${DRIVER}/debug_level + + You can find the list of debug mask values in: + drivers/net/wireless/mac80211/iwlwifi/iwl-debug.h + + If this is your first time using this driver, you should say Y here + as the debug information can assist others in helping you resolve + any problems you may encounter. + +config IWLWIFI_SENSITIVITY + bool "Enable Sensitivity Calibration in iwlwifi drivers" + depends on IWLWIFI + default y + ---help--- + This option will enable sensitivity calibration for the iwlwifi + drivers. + +config IWLWIFI_SPECTRUM_MEASUREMENT + bool "Enable Spectrum Measurement in iwlwifi drivers" + depends on IWLWIFI + default y + ---help--- + This option will enable spectrum measurement for the iwlwifi drivers. + +config IWLWIFI_QOS + bool "Enable Wireless QoS in iwlwifi drivers" + depends on IWLWIFI + default y + ---help--- + This option will enable wireless quality of service (QoS) for the + iwlwifi drivers. + +config IWLWIFI_HT + bool "Enable 802.11n HT features in iwlwifi drivers" + depends on EXPERIMENTAL + depends on IWLWIFI && MAC80211_HT + default n + ---help--- + This option enables IEEE 802.11n High Throughput features + for the iwlwifi drivers. + +config IWL4965 + tristate "Intel Wireless WiFi 4965AGN" + depends on m && IWLWIFI && EXPERIMENTAL + default m + ---help--- + Select to build the driver supporting the: + + Intel Wireless WiFi Link 4965AGN + + This driver uses the kernel's mac80211 subsystem. + + See for + information on the capabilities currently enabled in this + driver and for tips for debugging any issues or problems. + + In order to use this driver, you will need a microcode (uCode) + image for it. You can obtain the microcode from: + + . + + See the above referenced README.iwlwifi for information on where + to install the microcode images. + + If you want to compile the driver as a module ( = code which can be + inserted in and remvoed from the running kernel whenever you want), + say M here and read . The module + will be called iwl4965.ko. + +config IWL3945 + tristate "Intel PRO/Wireless 3945ABG/BG Network Connection" + depends on m && IWLWIFI && EXPERIMENTAL + default m + ---help--- + Select to build the driver supporting the: + + Intel PRO/Wireless 3945ABG/BG Network Connection + + This driver uses the kernel's mac80211 subsystem. + + See for + information on the capabilities currently enabled in this + driver and for tips for debugging any issues or problems. + + In order to use this driver, you will need a microcode (uCode) + image for it. You can obtain the microcode from: + + . + + See the above referenced README.iwlwifi for information on where + to install the microcode images. + + If you want to compile the driver as a module ( = code which can be + inserted in and remvoed from the running kernel whenever you want), + say M here and read . The module + will be called iwl3945.ko. diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile new file mode 100644 index 00000000000..03837ff5431 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -0,0 +1,11 @@ +obj-$(CONFIG_IWL3945) += iwl3945.o +iwl3945-objs = iwl3945-base.o iwl-3945.o iwl-3945-rs.o +CFLAGS_iwl3945-base.o = -DIWL=3945 +CFLAGS_iwl-3945.o = -DIWL=3945 +CFLAGS_iwl-3945-rs.o = -DIWL=3945 + +obj-$(CONFIG_IWL4965) += iwl4965.o +iwl4965-objs = iwl4965-base.o iwl-4965.o iwl-4965-rs.o +CFLAGS_iwl4965-base.o = -DIWL=4965 +CFLAGS_iwl-4965.o = -DIWL=4965 +CFLAGS_iwl-4965-rs.o = -DIWL=4965 diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h new file mode 100644 index 00000000000..fb5f0649f4f --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h @@ -0,0 +1,118 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU Geeral Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +#ifndef __iwl_3945_hw__ +#define __iwl_3945_hw__ + +#define IWL_RX_BUF_SIZE 3000 +/* card static random access memory (SRAM) for processor data and instructs */ +#define ALM_RTC_INST_UPPER_BOUND (0x014000) +#define ALM_RTC_DATA_UPPER_BOUND (0x808000) + +#define ALM_RTC_INST_SIZE (ALM_RTC_INST_UPPER_BOUND - RTC_INST_LOWER_BOUND) +#define ALM_RTC_DATA_SIZE (ALM_RTC_DATA_UPPER_BOUND - RTC_DATA_LOWER_BOUND) + +#define IWL_MAX_BSM_SIZE ALM_RTC_INST_SIZE +#define IWL_MAX_INST_SIZE ALM_RTC_INST_SIZE +#define IWL_MAX_DATA_SIZE ALM_RTC_DATA_SIZE +#define IWL_MAX_NUM_QUEUES 8 + +static inline int iwl_hw_valid_rtc_data_addr(u32 addr) +{ + return (addr >= RTC_DATA_LOWER_BOUND) && + (addr < ALM_RTC_DATA_UPPER_BOUND); +} + +/* Base physical address of iwl_shared is provided to FH_TSSR_CBB_BASE + * and &iwl_shared.rx_read_ptr[0] is provided to FH_RCSR_RPTR_ADDR(0) */ +struct iwl_shared { + __le32 tx_base_ptr[8]; + __le32 rx_read_ptr[3]; +} __attribute__ ((packed)); + +struct iwl_tfd_frame_data { + __le32 addr; + __le32 len; +} __attribute__ ((packed)); + +struct iwl_tfd_frame { + __le32 control_flags; + struct iwl_tfd_frame_data pa[4]; + u8 reserved[28]; +} __attribute__ ((packed)); + +static inline u8 iwl_hw_get_rate(__le16 rate_n_flags) +{ + return le16_to_cpu(rate_n_flags) & 0xFF; +} + +static inline u16 iwl_hw_get_rate_n_flags(__le16 rate_n_flags) +{ + return le16_to_cpu(rate_n_flags); +} + +static inline __le16 iwl_hw_set_rate_n_flags(u8 rate, u16 flags) +{ + return cpu_to_le16((u16)rate|flags); +} +#endif diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c new file mode 100644 index 00000000000..a4f4c8798a8 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -0,0 +1,979 @@ +/****************************************************************************** + * + * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#include "../net/mac80211/ieee80211_rate.h" + +#include "iwlwifi.h" + +#define RS_NAME "iwl-3945-rs" + +struct iwl_rate_scale_data { + u64 data; + s32 success_counter; + s32 success_ratio; + s32 counter; + s32 average_tpt; + unsigned long stamp; +}; + +struct iwl_rate_scale_priv { + spinlock_t lock; + s32 *expected_tpt; + unsigned long last_partial_flush; + unsigned long last_flush; + u32 flush_time; + u32 last_tx_packets; + u32 tx_packets; + u8 tgg; + u8 flush_pending; + u8 start_rate; + u8 ibss_sta_added; + struct timer_list rate_scale_flush; + struct iwl_rate_scale_data win[IWL_RATE_COUNT]; +}; + +static s32 iwl_expected_tpt_g[IWL_RATE_COUNT] = { + 0, 0, 76, 104, 130, 168, 191, 202, 7, 13, 35, 58 +}; + +static s32 iwl_expected_tpt_g_prot[IWL_RATE_COUNT] = { + 0, 0, 0, 80, 93, 113, 123, 125, 7, 13, 35, 58 +}; + +static s32 iwl_expected_tpt_a[IWL_RATE_COUNT] = { + 40, 57, 72, 98, 121, 154, 177, 186, 0, 0, 0, 0 +}; + +static s32 iwl_expected_tpt_b[IWL_RATE_COUNT] = { + 0, 0, 0, 0, 0, 0, 0, 0, 7, 13, 35, 58 +}; + +struct iwl_tpt_entry { + s8 min_rssi; + u8 index; +}; + +static struct iwl_tpt_entry iwl_tpt_table_a[] = { + {-60, IWL_RATE_54M_INDEX}, + {-64, IWL_RATE_48M_INDEX}, + {-72, IWL_RATE_36M_INDEX}, + {-80, IWL_RATE_24M_INDEX}, + {-84, IWL_RATE_18M_INDEX}, + {-85, IWL_RATE_12M_INDEX}, + {-87, IWL_RATE_9M_INDEX}, + {-89, IWL_RATE_6M_INDEX} +}; + +static struct iwl_tpt_entry iwl_tpt_table_b[] = { + {-86, IWL_RATE_11M_INDEX}, + {-88, IWL_RATE_5M_INDEX}, + {-90, IWL_RATE_2M_INDEX}, + {-92, IWL_RATE_1M_INDEX} + +}; + +static struct iwl_tpt_entry iwl_tpt_table_g[] = { + {-60, IWL_RATE_54M_INDEX}, + {-64, IWL_RATE_48M_INDEX}, + {-68, IWL_RATE_36M_INDEX}, + {-80, IWL_RATE_24M_INDEX}, + {-84, IWL_RATE_18M_INDEX}, + {-85, IWL_RATE_12M_INDEX}, + {-86, IWL_RATE_11M_INDEX}, + {-88, IWL_RATE_5M_INDEX}, + {-90, IWL_RATE_2M_INDEX}, + {-92, IWL_RATE_1M_INDEX} +}; + +#define IWL_RATE_MAX_WINDOW 62 +#define IWL_RATE_FLUSH (3*HZ/10) +#define IWL_RATE_WIN_FLUSH (HZ/2) +#define IWL_RATE_HIGH_TH 11520 +#define IWL_RATE_MIN_FAILURE_TH 8 +#define IWL_RATE_MIN_SUCCESS_TH 8 +#define IWL_RATE_DECREASE_TH 1920 + +static u8 iwl_get_rate_index_by_rssi(s32 rssi, u8 mode) +{ + u32 index = 0; + u32 table_size = 0; + struct iwl_tpt_entry *tpt_table = NULL; + + if ((rssi < IWL_MIN_RSSI_VAL) || (rssi > IWL_MAX_RSSI_VAL)) + rssi = IWL_MIN_RSSI_VAL; + + switch (mode) { + case MODE_IEEE80211G: + tpt_table = iwl_tpt_table_g; + table_size = ARRAY_SIZE(iwl_tpt_table_g); + break; + + case MODE_IEEE80211A: + tpt_table = iwl_tpt_table_a; + table_size = ARRAY_SIZE(iwl_tpt_table_a); + break; + + default: + case MODE_IEEE80211B: + tpt_table = iwl_tpt_table_b; + table_size = ARRAY_SIZE(iwl_tpt_table_b); + break; + } + + while ((index < table_size) && (rssi < tpt_table[index].min_rssi)) + index++; + + index = min(index, (table_size - 1)); + + return tpt_table[index].index; +} + +static void iwl_clear_window(struct iwl_rate_scale_data *window) +{ + window->data = 0; + window->success_counter = 0; + window->success_ratio = IWL_INVALID_VALUE; + window->counter = 0; + window->average_tpt = IWL_INVALID_VALUE; + window->stamp = 0; +} + +/** + * iwl_rate_scale_flush_windows - flush out the rate scale windows + * + * Returns the number of windows that have gathered data but were + * not flushed. If there were any that were not flushed, then + * reschedule the rate flushing routine. + */ +static int iwl_rate_scale_flush_windows(struct iwl_rate_scale_priv *rs_priv) +{ + int unflushed = 0; + int i; + unsigned long flags; + + /* + * For each rate, if we have collected data on that rate + * and it has been more than IWL_RATE_WIN_FLUSH + * since we flushed, clear out the gathered statistics + */ + for (i = 0; i < IWL_RATE_COUNT; i++) { + if (!rs_priv->win[i].counter) + continue; + + spin_lock_irqsave(&rs_priv->lock, flags); + if (time_after(jiffies, rs_priv->win[i].stamp + + IWL_RATE_WIN_FLUSH)) { + IWL_DEBUG_RATE("flushing %d samples of rate " + "index %d\n", + rs_priv->win[i].counter, i); + iwl_clear_window(&rs_priv->win[i]); + } else + unflushed++; + spin_unlock_irqrestore(&rs_priv->lock, flags); + } + + return unflushed; +} + +#define IWL_RATE_FLUSH_MAX 5000 /* msec */ +#define IWL_RATE_FLUSH_MIN 50 /* msec */ + +static void iwl_bg_rate_scale_flush(unsigned long data) +{ + struct iwl_rate_scale_priv *rs_priv = (void *)data; + int unflushed = 0; + unsigned long flags; + u32 packet_count, duration, pps; + + IWL_DEBUG_RATE("enter\n"); + + unflushed = iwl_rate_scale_flush_windows(rs_priv); + + spin_lock_irqsave(&rs_priv->lock, flags); + + rs_priv->flush_pending = 0; + + /* Number of packets Rx'd since last time this timer ran */ + packet_count = (rs_priv->tx_packets - rs_priv->last_tx_packets) + 1; + + rs_priv->last_tx_packets = rs_priv->tx_packets + 1; + + if (unflushed) { + duration = + jiffies_to_msecs(jiffies - rs_priv->last_partial_flush); +/* duration = jiffies_to_msecs(rs_priv->flush_time); */ + + IWL_DEBUG_RATE("Tx'd %d packets in %dms\n", + packet_count, duration); + + /* Determine packets per second */ + if (duration) + pps = (packet_count * 1000) / duration; + else + pps = 0; + + if (pps) { + duration = IWL_RATE_FLUSH_MAX / pps; + if (duration < IWL_RATE_FLUSH_MIN) + duration = IWL_RATE_FLUSH_MIN; + } else + duration = IWL_RATE_FLUSH_MAX; + + rs_priv->flush_time = msecs_to_jiffies(duration); + + IWL_DEBUG_RATE("new flush period: %d msec ave %d\n", + duration, packet_count); + + mod_timer(&rs_priv->rate_scale_flush, jiffies + + rs_priv->flush_time); + + rs_priv->last_partial_flush = jiffies; + } + + /* If there weren't any unflushed entries, we don't schedule the timer + * to run again */ + + rs_priv->last_flush = jiffies; + + spin_unlock_irqrestore(&rs_priv->lock, flags); + + IWL_DEBUG_RATE("leave\n"); +} + +/** + * iwl_collect_tx_data - Update the success/failure sliding window + * + * We keep a sliding window of the last 64 packets transmitted + * at this rate. window->data contains the bitmask of successful + * packets. + */ +static void iwl_collect_tx_data(struct iwl_rate_scale_priv *rs_priv, + struct iwl_rate_scale_data *window, + int success, int retries) +{ + unsigned long flags; + + if (!retries) { + IWL_DEBUG_RATE("leave: retries == 0 -- should be at least 1\n"); + return; + } + + while (retries--) { + spin_lock_irqsave(&rs_priv->lock, flags); + + /* If we have filled up the window then subtract one from the + * success counter if the high-bit is counting toward + * success */ + if (window->counter == IWL_RATE_MAX_WINDOW) { + if (window->data & (1ULL << (IWL_RATE_MAX_WINDOW - 1))) + window->success_counter--; + } else + window->counter++; + + /* Slide the window to the left one bit */ + window->data = (window->data << 1); + + /* If this packet was a success then set the low bit high */ + if (success) { + window->success_counter++; + window->data |= 1; + } + + /* window->counter can't be 0 -- it is either >0 or + * IWL_RATE_MAX_WINDOW */ + window->success_ratio = 12800 * window->success_counter / + window->counter; + + /* Tag this window as having been updated */ + window->stamp = jiffies; + + spin_unlock_irqrestore(&rs_priv->lock, flags); + } +} + +static void rs_rate_init(void *priv_rate, void *priv_sta, + struct ieee80211_local *local, struct sta_info *sta) +{ + int i; + + IWL_DEBUG_RATE("enter\n"); + + /* TODO: what is a good starting rate for STA? About middle? Maybe not + * the lowest or the highest rate.. Could consider using RSSI from + * previous packets? Need to have IEEE 802.1X auth succeed immediately + * after assoc.. */ + + for (i = IWL_RATE_COUNT - 1; i >= 0; i--) { + if (sta->supp_rates & (1 << i)) { + sta->txrate = i; + break; + } + } + + sta->last_txrate = sta->txrate; + + IWL_DEBUG_RATE("leave\n"); +} + +static void *rs_alloc(struct ieee80211_local *local) +{ + return local->hw.priv; +} + +/* rate scale requires free function to be implmented */ +static void rs_free(void *priv) +{ + return; +} +static void rs_clear(void *priv) +{ + return; +} + + +static void *rs_alloc_sta(void *priv, gfp_t gfp) +{ + struct iwl_rate_scale_priv *rs_priv; + int i; + + IWL_DEBUG_RATE("enter\n"); + + rs_priv = kzalloc(sizeof(struct iwl_rate_scale_priv), gfp); + if (!rs_priv) { + IWL_DEBUG_RATE("leave: ENOMEM\n"); + return NULL; + } + + spin_lock_init(&rs_priv->lock); + + rs_priv->start_rate = IWL_RATE_INVALID; + + /* default to just 802.11b */ + rs_priv->expected_tpt = iwl_expected_tpt_b; + + rs_priv->last_partial_flush = jiffies; + rs_priv->last_flush = jiffies; + rs_priv->flush_time = IWL_RATE_FLUSH; + rs_priv->last_tx_packets = 0; + rs_priv->ibss_sta_added = 0; + + init_timer(&rs_priv->rate_scale_flush); + rs_priv->rate_scale_flush.data = (unsigned long)rs_priv; + rs_priv->rate_scale_flush.function = &iwl_bg_rate_scale_flush; + + for (i = 0; i < IWL_RATE_COUNT; i++) + iwl_clear_window(&rs_priv->win[i]); + + IWL_DEBUG_RATE("leave\n"); + + return rs_priv; +} + +static void rs_free_sta(void *priv, void *priv_sta) +{ + struct iwl_rate_scale_priv *rs_priv = priv_sta; + + IWL_DEBUG_RATE("enter\n"); + del_timer_sync(&rs_priv->rate_scale_flush); + kfree(rs_priv); + IWL_DEBUG_RATE("leave\n"); +} + +/** + * rs_tx_status - Update rate control values based on Tx results + * + * NOTE: Uses iwl_priv->retry_rate for the # of retries attempted by + * the hardware for each rate. + */ +static void rs_tx_status(void *priv_rate, + struct net_device *dev, + struct sk_buff *skb, + struct ieee80211_tx_status *tx_resp) +{ + u8 retries, current_count; + int scale_rate_index, first_index, last_index; + unsigned long flags; + struct sta_info *sta; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct iwl_priv *priv = (struct iwl_priv *)priv_rate; + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct iwl_rate_scale_priv *rs_priv; + + IWL_DEBUG_RATE("enter\n"); + + retries = tx_resp->retry_count; + + first_index = tx_resp->control.tx_rate; + if ((first_index < 0) || (first_index >= IWL_RATE_COUNT)) { + IWL_DEBUG_RATE("leave: Rate out of bounds: %0x for %d\n", + tx_resp->control.tx_rate, first_index); + return; + } + + sta = sta_info_get(local, hdr->addr1); + if (!sta || !sta->rate_ctrl_priv) { + if (sta) + sta_info_put(sta); + IWL_DEBUG_RATE("leave: No STA priv data to update!\n"); + return; + } + + rs_priv = (void *)sta->rate_ctrl_priv; + + rs_priv->tx_packets++; + + scale_rate_index = first_index; + last_index = first_index; + + /* + * Update the window for each rate. We determine which rates + * were Tx'd based on the total number of retries vs. the number + * of retries configured for each rate -- currently set to the + * priv value 'retry_rate' vs. rate specific + * + * On exit from this while loop last_index indicates the rate + * at which the frame was finally transmitted (or failed if no + * ACK) + */ + while (retries > 0) { + if (retries < priv->retry_rate) { + current_count = retries; + last_index = scale_rate_index; + } else { + current_count = priv->retry_rate; + last_index = iwl_get_prev_ieee_rate(scale_rate_index); + } + + /* Update this rate accounting for as many retries + * as was used for it (per current_count) */ + iwl_collect_tx_data(rs_priv, + &rs_priv->win[scale_rate_index], + 0, current_count); + IWL_DEBUG_RATE("Update rate %d for %d retries.\n", + scale_rate_index, current_count); + + retries -= current_count; + + if (retries) + scale_rate_index = + iwl_get_prev_ieee_rate(scale_rate_index); + } + + /* Update the last index window with success/failure based on ACK */ + IWL_DEBUG_RATE("Update rate %d with %s.\n", + last_index, + (tx_resp->flags & IEEE80211_TX_STATUS_ACK) ? + "success" : "failure"); + iwl_collect_tx_data(rs_priv, + &rs_priv->win[last_index], + tx_resp->flags & IEEE80211_TX_STATUS_ACK, 1); + + /* We updated the rate scale window -- if its been more than + * flush_time since the last run, schedule the flush + * again */ + spin_lock_irqsave(&rs_priv->lock, flags); + + if (!rs_priv->flush_pending && + time_after(jiffies, rs_priv->last_partial_flush + + rs_priv->flush_time)) { + + rs_priv->flush_pending = 1; + mod_timer(&rs_priv->rate_scale_flush, + jiffies + rs_priv->flush_time); + } + + spin_unlock_irqrestore(&rs_priv->lock, flags); + + sta_info_put(sta); + + IWL_DEBUG_RATE("leave\n"); + + return; +} + +static struct ieee80211_rate *iwl_get_lowest_rate(struct ieee80211_local + *local) +{ + struct ieee80211_hw_mode *mode = local->oper_hw_mode; + int i; + + for (i = 0; i < mode->num_rates; i++) { + struct ieee80211_rate *rate = &mode->rates[i]; + + if (rate->flags & IEEE80211_RATE_SUPPORTED) + return rate; + } + + return &mode->rates[0]; +} + +static u16 iwl_get_adjacent_rate(struct iwl_rate_scale_priv *rs_priv, + u8 index, u16 rate_mask, int phymode) +{ + u8 high = IWL_RATE_INVALID; + u8 low = IWL_RATE_INVALID; + + /* 802.11A walks to the next literal adjascent rate in + * the rate table */ + if (unlikely(phymode == MODE_IEEE80211A)) { + int i; + u32 mask; + + /* Find the previous rate that is in the rate mask */ + i = index - 1; + for (mask = (1 << i); i >= 0; i--, mask >>= 1) { + if (rate_mask & mask) { + low = i; + break; + } + } + + /* Find the next rate that is in the rate mask */ + i = index + 1; + for (mask = (1 << i); i < IWL_RATE_COUNT; i++, mask <<= 1) { + if (rate_mask & mask) { + high = i; + break; + } + } + + return (high << 8) | low; + } + + low = index; + while (low != IWL_RATE_INVALID) { + if (rs_priv->tgg) + low = iwl_rates[low].prev_rs_tgg; + else + low = iwl_rates[low].prev_rs; + if (low == IWL_RATE_INVALID) + break; + if (rate_mask & (1 << low)) + break; + IWL_DEBUG_RATE("Skipping masked lower rate: %d\n", low); + } + + high = index; + while (high != IWL_RATE_INVALID) { + if (rs_priv->tgg) + high = iwl_rates[high].next_rs_tgg; + else + high = iwl_rates[high].next_rs; + if (high == IWL_RATE_INVALID) + break; + if (rate_mask & (1 << high)) + break; + IWL_DEBUG_RATE("Skipping masked higher rate: %d\n", high); + } + + return (high << 8) | low; +} + +/** + * rs_get_rate - find the rate for the requested packet + * + * Returns the ieee80211_rate structure allocated by the driver. + * + * The rate control algorithm has no internal mapping between hw_mode's + * rate ordering and the rate ordering used by the rate control algorithm. + * + * The rate control algorithm uses a single table of rates that goes across + * the entire A/B/G spectrum vs. being limited to just one particular + * hw_mode. + * + * As such, we can't convert the index obtained below into the hw_mode's + * rate table and must reference the driver allocated rate table + * + */ +static struct ieee80211_rate *rs_get_rate(void *priv_rate, + struct net_device *dev, + struct sk_buff *skb, + struct rate_control_extra *extra) +{ + u8 low = IWL_RATE_INVALID; + u8 high = IWL_RATE_INVALID; + u16 high_low; + int index; + struct iwl_rate_scale_priv *rs_priv; + struct iwl_rate_scale_data *window = NULL; + int current_tpt = IWL_INVALID_VALUE; + int low_tpt = IWL_INVALID_VALUE; + int high_tpt = IWL_INVALID_VALUE; + u32 fail_count; + s8 scale_action = 0; + unsigned long flags; + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct sta_info *sta; + u16 fc, rate_mask; + struct iwl_priv *priv = (struct iwl_priv *)priv_rate; + + IWL_DEBUG_RATE("enter\n"); + + memset(extra, 0, sizeof(*extra)); + + fc = le16_to_cpu(hdr->frame_control); + if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) || + (is_multicast_ether_addr(hdr->addr1))) { + /* Send management frames and broadcast/multicast data using + * lowest rate. */ + /* TODO: this could probably be improved.. */ + IWL_DEBUG_RATE("leave: lowest rate (not data or is " + "multicast)\n"); + + return iwl_get_lowest_rate(local); + } + + sta = sta_info_get(local, hdr->addr1); + if (!sta || !sta->rate_ctrl_priv) { + IWL_DEBUG_RATE("leave: No STA priv data to update!\n"); + if (sta) + sta_info_put(sta); + return NULL; + } + + rate_mask = sta->supp_rates; + index = min(sta->txrate & 0xffff, IWL_RATE_COUNT - 1); + + rs_priv = (void *)sta->rate_ctrl_priv; + + if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && + !rs_priv->ibss_sta_added) { + u8 sta_id = iwl_hw_find_station(priv, hdr->addr1); + + if (sta_id == IWL_INVALID_STATION) { + IWL_DEBUG_RATE("LQ: ADD station " MAC_FMT "\n", + MAC_ARG(hdr->addr1)); + sta_id = iwl_add_station(priv, + hdr->addr1, 0, CMD_ASYNC); + } + if (sta_id != IWL_INVALID_STATION) + rs_priv->ibss_sta_added = 1; + } + + spin_lock_irqsave(&rs_priv->lock, flags); + + if (rs_priv->start_rate != IWL_RATE_INVALID) { + index = rs_priv->start_rate; + rs_priv->start_rate = IWL_RATE_INVALID; + } + + window = &(rs_priv->win[index]); + + fail_count = window->counter - window->success_counter; + + if (((fail_count <= IWL_RATE_MIN_FAILURE_TH) && + (window->success_counter < IWL_RATE_MIN_SUCCESS_TH))) { + window->average_tpt = IWL_INVALID_VALUE; + spin_unlock_irqrestore(&rs_priv->lock, flags); + + IWL_DEBUG_RATE("Invalid average_tpt on rate %d: " + "counter: %d, success_counter: %d, " + "expected_tpt is %sNULL\n", + index, + window->counter, + window->success_counter, + rs_priv->expected_tpt ? "not " : ""); + goto out; + + } + + window->average_tpt = ((window->success_ratio * + rs_priv->expected_tpt[index] + 64) / 128); + current_tpt = window->average_tpt; + + high_low = iwl_get_adjacent_rate(rs_priv, index, rate_mask, + local->hw.conf.phymode); + low = high_low & 0xff; + high = (high_low >> 8) & 0xff; + + if (low != IWL_RATE_INVALID) + low_tpt = rs_priv->win[low].average_tpt; + + if (high != IWL_RATE_INVALID) + high_tpt = rs_priv->win[high].average_tpt; + + spin_unlock_irqrestore(&rs_priv->lock, flags); + + scale_action = 1; + + if ((window->success_ratio < IWL_RATE_DECREASE_TH) || !current_tpt) { + IWL_DEBUG_RATE("decrease rate because of low success_ratio\n"); + scale_action = -1; + } else if ((low_tpt == IWL_INVALID_VALUE) && + (high_tpt == IWL_INVALID_VALUE)) + scale_action = 1; + else if ((low_tpt != IWL_INVALID_VALUE) && + (high_tpt != IWL_INVALID_VALUE) + && (low_tpt < current_tpt) + && (high_tpt < current_tpt)) { + IWL_DEBUG_RATE("No action -- low [%d] & high [%d] < " + "current_tpt [%d]\n", + low_tpt, high_tpt, current_tpt); + scale_action = 0; + } else { + if (high_tpt != IWL_INVALID_VALUE) { + if (high_tpt > current_tpt) + scale_action = 1; + else { + IWL_DEBUG_RATE + ("decrease rate because of high tpt\n"); + scale_action = -1; + } + } else if (low_tpt != IWL_INVALID_VALUE) { + if (low_tpt > current_tpt) { + IWL_DEBUG_RATE + ("decrease rate because of low tpt\n"); + scale_action = -1; + } else + scale_action = 1; + } + } + + if ((window->success_ratio > IWL_RATE_HIGH_TH) || + (current_tpt > window->average_tpt)) { + IWL_DEBUG_RATE("No action -- success_ratio [%d] > HIGH_TH or " + "current_tpt [%d] > average_tpt [%d]\n", + window->success_ratio, + current_tpt, window->average_tpt); + scale_action = 0; + } + + switch (scale_action) { + case -1: + if (low != IWL_RATE_INVALID) + index = low; + break; + + case 1: + if (high != IWL_RATE_INVALID) + index = high; + + break; + + case 0: + default: + break; + } + + IWL_DEBUG_RATE("Selected %d (action %d) - low %d high %d\n", + index, scale_action, low, high); + + out: + + sta->last_txrate = index; + sta->txrate = sta->last_txrate; + sta_info_put(sta); + + IWL_DEBUG_RATE("leave: %d\n", index); + + return &priv->ieee_rates[index]; +} + +static struct rate_control_ops rs_ops = { + .module = NULL, + .name = RS_NAME, + .tx_status = rs_tx_status, + .get_rate = rs_get_rate, + .rate_init = rs_rate_init, + .clear = rs_clear, + .alloc = rs_alloc, + .free = rs_free, + .alloc_sta = rs_alloc_sta, + .free_sta = rs_free_sta, +}; + +int iwl_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct iwl_priv *priv = hw->priv; + struct iwl_rate_scale_priv *rs_priv; + struct sta_info *sta; + unsigned long flags; + int count = 0, i; + u32 samples = 0, success = 0, good = 0; + unsigned long now = jiffies; + u32 max_time = 0; + + sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr); + if (!sta || !sta->rate_ctrl_priv) { + if (sta) { + sta_info_put(sta); + IWL_DEBUG_RATE("leave - no private rate data!\n"); + } else + IWL_DEBUG_RATE("leave - no station!\n"); + return sprintf(buf, "station %d not found\n", sta_id); + } + + rs_priv = (void *)sta->rate_ctrl_priv; + spin_lock_irqsave(&rs_priv->lock, flags); + i = IWL_RATE_54M_INDEX; + while (1) { + u64 mask; + int j; + + count += + sprintf(&buf[count], " %2dMbs: ", iwl_rates[i].ieee / 2); + + mask = (1ULL << (IWL_RATE_MAX_WINDOW - 1)); + for (j = 0; j < IWL_RATE_MAX_WINDOW; j++, mask >>= 1) + buf[count++] = + (rs_priv->win[i].data & mask) ? '1' : '0'; + + samples += rs_priv->win[i].counter; + good += rs_priv->win[i].success_counter; + success += rs_priv->win[i].success_counter * iwl_rates[i].ieee; + + if (rs_priv->win[i].stamp) { + int delta = + jiffies_to_msecs(now - rs_priv->win[i].stamp); + + if (delta > max_time) + max_time = delta; + + count += sprintf(&buf[count], "%5dms\n", delta); + } else + buf[count++] = '\n'; + + j = iwl_get_prev_ieee_rate(i); + if (j == i) + break; + i = j; + } + spin_unlock_irqrestore(&rs_priv->lock, flags); + sta_info_put(sta); + + /* Display the average rate of all samples taken. + * + * NOTE: We multiple # of samples by 2 since the IEEE measurement + * added from iwl_rates is actually 2X the rate */ + if (samples) + count += sprintf( + &buf[count], + "\nAverage rate is %3d.%02dMbs over last %4dms\n" + "%3d%% success (%d good packets over %d tries)\n", + success / (2 * samples), (success * 5 / samples) % 10, + max_time, good * 100 / samples, good, samples); + else + count += sprintf(&buf[count], "\nAverage rate: 0Mbs\n"); + + return count; +} + +void iwl_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) +{ + struct iwl_priv *priv = hw->priv; + s32 rssi = 0; + unsigned long flags; + struct ieee80211_local *local = hw_to_local(hw); + struct iwl_rate_scale_priv *rs_priv; + struct sta_info *sta; + + IWL_DEBUG_RATE("enter\n"); + + if (!local->rate_ctrl->ops->name || + strcmp(local->rate_ctrl->ops->name, RS_NAME)) { + IWL_WARNING("iwl-3945-rs not selected as rate control algo!\n"); + IWL_DEBUG_RATE("leave - mac80211 picked the wrong RC algo.\n"); + return; + } + + sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr); + if (!sta || !sta->rate_ctrl_priv) { + if (sta) + sta_info_put(sta); + IWL_DEBUG_RATE("leave - no private rate data!\n"); + return; + } + + rs_priv = (void *)sta->rate_ctrl_priv; + + spin_lock_irqsave(&rs_priv->lock, flags); + + rs_priv->tgg = 0; + switch (priv->phymode) { + case MODE_IEEE80211G: + if (priv->active_rxon.flags & RXON_FLG_TGG_PROTECT_MSK) { + rs_priv->tgg = 1; + rs_priv->expected_tpt = iwl_expected_tpt_g_prot; + } else + rs_priv->expected_tpt = iwl_expected_tpt_g; + break; + + case MODE_IEEE80211A: + rs_priv->expected_tpt = iwl_expected_tpt_a; + break; + + default: + IWL_WARNING("Invalid phymode. Defaulting to 802.11b\n"); + case MODE_IEEE80211B: + rs_priv->expected_tpt = iwl_expected_tpt_b; + break; + } + + sta_info_put(sta); + spin_unlock_irqrestore(&rs_priv->lock, flags); + + rssi = priv->last_rx_rssi; + if (rssi == 0) + rssi = IWL_MIN_RSSI_VAL; + + IWL_DEBUG(IWL_DL_INFO | IWL_DL_RATE, "Network RSSI: %d\n", rssi); + + rs_priv->start_rate = iwl_get_rate_index_by_rssi(rssi, priv->phymode); + + IWL_DEBUG_RATE("leave: rssi %d assign rate index: " + "%d (plcp 0x%x)\n", rssi, rs_priv->start_rate, + iwl_rates[rs_priv->start_rate].plcp); +} + +void iwl_rate_control_register(struct ieee80211_hw *hw) +{ + ieee80211_rate_control_register(&rs_ops); +} + +void iwl_rate_control_unregister(struct ieee80211_hw *hw) +{ + ieee80211_rate_control_unregister(&rs_ops); +} + + diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.h b/drivers/net/wireless/iwlwifi/iwl-3945-rs.h new file mode 100644 index 00000000000..b926738e0ea --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.h @@ -0,0 +1,191 @@ +/****************************************************************************** + * + * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#ifndef __iwl_3945_rs_h__ +#define __iwl_3945_rs_h__ + +struct iwl_rate_info { + u8 plcp; + u8 ieee; + u8 prev_ieee; /* previous rate in IEEE speeds */ + u8 next_ieee; /* next rate in IEEE speeds */ + u8 prev_rs; /* previous rate used in rs algo */ + u8 next_rs; /* next rate used in rs algo */ + u8 prev_rs_tgg; /* previous rate used in TGG rs algo */ + u8 next_rs_tgg; /* next rate used in TGG rs algo */ +}; + +enum { + IWL_RATE_6M_INDEX = 0, + IWL_RATE_9M_INDEX, + IWL_RATE_12M_INDEX, + IWL_RATE_18M_INDEX, + IWL_RATE_24M_INDEX, + IWL_RATE_36M_INDEX, + IWL_RATE_48M_INDEX, + IWL_RATE_54M_INDEX, + IWL_RATE_1M_INDEX, + IWL_RATE_2M_INDEX, + IWL_RATE_5M_INDEX, + IWL_RATE_11M_INDEX, + IWL_RATE_COUNT, + IWL_RATE_INVM_INDEX, + IWL_RATE_INVALID = IWL_RATE_INVM_INDEX +}; + +enum { + IWL_FIRST_OFDM_RATE = IWL_RATE_6M_INDEX, + IWL_LAST_OFDM_RATE = IWL_RATE_54M_INDEX, + IWL_FIRST_CCK_RATE = IWL_RATE_1M_INDEX, + IWL_LAST_CCK_RATE = IWL_RATE_11M_INDEX, +}; + +/* #define vs. enum to keep from defaulting to 'large integer' */ +#define IWL_RATE_6M_MASK (1< + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "iwlwifi.h" +#include "iwl-helpers.h" +#include "iwl-3945.h" +#include "iwl-3945-rs.h" + +#define IWL_DECLARE_RATE_INFO(r, ip, in, rp, rn, pp, np) \ + [IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP, \ + IWL_RATE_##r##M_IEEE, \ + IWL_RATE_##ip##M_INDEX, \ + IWL_RATE_##in##M_INDEX, \ + IWL_RATE_##rp##M_INDEX, \ + IWL_RATE_##rn##M_INDEX, \ + IWL_RATE_##pp##M_INDEX, \ + IWL_RATE_##np##M_INDEX } + +/* + * Parameter order: + * rate, prev rate, next rate, prev tgg rate, next tgg rate + * + * If there isn't a valid next or previous rate then INV is used which + * maps to IWL_RATE_INVALID + * + */ +const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] = { + IWL_DECLARE_RATE_INFO(6, 5, 9, 5, 11, 5, 11), /* 6mbps */ + IWL_DECLARE_RATE_INFO(9, 6, 11, 5, 11, 5, 11), /* 9mbps */ + IWL_DECLARE_RATE_INFO(12, 11, 18, 11, 18, 11, 18), /* 12mbps */ + IWL_DECLARE_RATE_INFO(18, 12, 24, 12, 24, 11, 24), /* 18mbps */ + IWL_DECLARE_RATE_INFO(24, 18, 36, 18, 36, 18, 36), /* 24mbps */ + IWL_DECLARE_RATE_INFO(36, 24, 48, 24, 48, 24, 48), /* 36mbps */ + IWL_DECLARE_RATE_INFO(48, 36, 54, 36, 54, 36, 54), /* 48mbps */ + IWL_DECLARE_RATE_INFO(54, 48, INV, 48, INV, 48, INV),/* 54mbps */ + IWL_DECLARE_RATE_INFO(1, INV, 2, INV, 2, INV, 2), /* 1mbps */ + IWL_DECLARE_RATE_INFO(2, 1, 5, 1, 5, 1, 5), /* 2mbps */ + IWL_DECLARE_RATE_INFO(5, 2, 6, 2, 11, 2, 11), /*5.5mbps */ + IWL_DECLARE_RATE_INFO(11, 9, 12, 5, 12, 5, 18), /* 11mbps */ +}; + +/* 1 = enable the iwl_disable_events() function */ +#define IWL_EVT_DISABLE (0) +#define IWL_EVT_DISABLE_SIZE (1532/32) + +/** + * iwl_disable_events - Disable selected events in uCode event log + * + * Disable an event by writing "1"s into "disable" + * bitmap in SRAM. Bit position corresponds to Event # (id/type). + * Default values of 0 enable uCode events to be logged. + * Use for only special debugging. This function is just a placeholder as-is, + * you'll need to provide the special bits! ... + * ... and set IWL_EVT_DISABLE to 1. */ +void iwl_disable_events(struct iwl_priv *priv) +{ + int rc; + int i; + u32 base; /* SRAM address of event log header */ + u32 disable_ptr; /* SRAM address of event-disable bitmap array */ + u32 array_size; /* # of u32 entries in array */ + u32 evt_disable[IWL_EVT_DISABLE_SIZE] = { + 0x00000000, /* 31 - 0 Event id numbers */ + 0x00000000, /* 63 - 32 */ + 0x00000000, /* 95 - 64 */ + 0x00000000, /* 127 - 96 */ + 0x00000000, /* 159 - 128 */ + 0x00000000, /* 191 - 160 */ + 0x00000000, /* 223 - 192 */ + 0x00000000, /* 255 - 224 */ + 0x00000000, /* 287 - 256 */ + 0x00000000, /* 319 - 288 */ + 0x00000000, /* 351 - 320 */ + 0x00000000, /* 383 - 352 */ + 0x00000000, /* 415 - 384 */ + 0x00000000, /* 447 - 416 */ + 0x00000000, /* 479 - 448 */ + 0x00000000, /* 511 - 480 */ + 0x00000000, /* 543 - 512 */ + 0x00000000, /* 575 - 544 */ + 0x00000000, /* 607 - 576 */ + 0x00000000, /* 639 - 608 */ + 0x00000000, /* 671 - 640 */ + 0x00000000, /* 703 - 672 */ + 0x00000000, /* 735 - 704 */ + 0x00000000, /* 767 - 736 */ + 0x00000000, /* 799 - 768 */ + 0x00000000, /* 831 - 800 */ + 0x00000000, /* 863 - 832 */ + 0x00000000, /* 895 - 864 */ + 0x00000000, /* 927 - 896 */ + 0x00000000, /* 959 - 928 */ + 0x00000000, /* 991 - 960 */ + 0x00000000, /* 1023 - 992 */ + 0x00000000, /* 1055 - 1024 */ + 0x00000000, /* 1087 - 1056 */ + 0x00000000, /* 1119 - 1088 */ + 0x00000000, /* 1151 - 1120 */ + 0x00000000, /* 1183 - 1152 */ + 0x00000000, /* 1215 - 1184 */ + 0x00000000, /* 1247 - 1216 */ + 0x00000000, /* 1279 - 1248 */ + 0x00000000, /* 1311 - 1280 */ + 0x00000000, /* 1343 - 1312 */ + 0x00000000, /* 1375 - 1344 */ + 0x00000000, /* 1407 - 1376 */ + 0x00000000, /* 1439 - 1408 */ + 0x00000000, /* 1471 - 1440 */ + 0x00000000, /* 1503 - 1472 */ + }; + + base = le32_to_cpu(priv->card_alive.log_event_table_ptr); + if (!iwl_hw_valid_rtc_data_addr(base)) { + IWL_ERROR("Invalid event log pointer 0x%08X\n", base); + return; + } + + rc = iwl_grab_restricted_access(priv); + if (rc) { + IWL_WARNING("Can not read from adapter at this time.\n"); + return; + } + + disable_ptr = iwl_read_restricted_mem(priv, base + (4 * sizeof(u32))); + array_size = iwl_read_restricted_mem(priv, base + (5 * sizeof(u32))); + iwl_release_restricted_access(priv); + + if (IWL_EVT_DISABLE && (array_size == IWL_EVT_DISABLE_SIZE)) { + IWL_DEBUG_INFO("Disabling selected uCode log events at 0x%x\n", + disable_ptr); + rc = iwl_grab_restricted_access(priv); + for (i = 0; i < IWL_EVT_DISABLE_SIZE; i++) + iwl_write_restricted_mem(priv, + disable_ptr + + (i * sizeof(u32)), + evt_disable[i]); + + iwl_release_restricted_access(priv); + } else { + IWL_DEBUG_INFO("Selected uCode log events may be disabled\n"); + IWL_DEBUG_INFO(" by writing \"1\"s into disable bitmap\n"); + IWL_DEBUG_INFO(" in SRAM at 0x%x, size %d u32s\n", + disable_ptr, array_size); + } + +} + +/** + * iwl3945_get_antenna_flags - Get antenna flags for RXON command + * @priv: eeprom and antenna fields are used to determine antenna flags + * + * priv->eeprom is used to determine if antenna AUX/MAIN are reversed + * priv->antenna specifies the antenna diversity mode: + * + * IWL_ANTENNA_DIVERISTY - NIC selects best antenna by itself + * IWL_ANTENNA_MAIN - Force MAIN antenna + * IWL_ANTENNA_AUX - Force AUX antenna + */ +__le32 iwl3945_get_antenna_flags(const struct iwl_priv *priv) +{ + switch (priv->antenna) { + case IWL_ANTENNA_DIVERSITY: + return 0; + + case IWL_ANTENNA_MAIN: + if (priv->eeprom.antenna_switch_type) + return RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_B_MSK; + return RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_A_MSK; + + case IWL_ANTENNA_AUX: + if (priv->eeprom.antenna_switch_type) + return RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_A_MSK; + return RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_B_MSK; + } + + /* bad antenna selector value */ + IWL_ERROR("Bad antenna selector value (0x%x)\n", priv->antenna); + return 0; /* "diversity" is default if error */ +} + +/***************************************************************************** + * + * Intel PRO/Wireless 3945ABG/BG Network Connection + * + * RX handler implementations + * + * Used by iwl-base.c + * + *****************************************************************************/ + +void iwl_hw_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + IWL_DEBUG_RX("Statistics notification received (%d vs %d).\n", + (int)sizeof(struct iwl_notif_statistics), + le32_to_cpu(pkt->len)); + + memcpy(&priv->statistics, pkt->u.raw, sizeof(priv->statistics)); + + priv->last_statistics_time = jiffies; +} + +static void iwl3945_handle_data_packet(struct iwl_priv *priv, int is_data, + struct iwl_rx_mem_buffer *rxb, + struct ieee80211_rx_status *stats, + u16 phy_flags) +{ + struct ieee80211_hdr *hdr; + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); + struct iwl_rx_frame_end *rx_end = IWL_RX_END(pkt); + short len = le16_to_cpu(rx_hdr->len); + + /* We received data from the HW, so stop the watchdog */ + if (unlikely((len + IWL_RX_FRAME_SIZE) > skb_tailroom(rxb->skb))) { + IWL_DEBUG_DROP("Corruption detected!\n"); + return; + } + + /* We only process data packets if the interface is open */ + if (unlikely(!priv->is_open)) { + IWL_DEBUG_DROP_LIMIT + ("Dropping packet while interface is not open.\n"); + return; + } + if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) { + if (iwl_param_hwcrypto) + iwl_set_decrypted_flag(priv, rxb->skb, + le32_to_cpu(rx_end->status), + stats); + iwl_handle_data_packet_monitor(priv, rxb, IWL_RX_DATA(pkt), + len, stats, phy_flags); + return; + } + + skb_reserve(rxb->skb, (void *)rx_hdr->payload - (void *)pkt); + /* Set the size of the skb to the size of the frame */ + skb_put(rxb->skb, le16_to_cpu(rx_hdr->len)); + + hdr = (void *)rxb->skb->data; + + if (iwl_param_hwcrypto) + iwl_set_decrypted_flag(priv, rxb->skb, + le32_to_cpu(rx_end->status), stats); + + ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats); + rxb->skb = NULL; +} + +static void iwl3945_rx_reply_rx(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt); + struct iwl_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); + struct iwl_rx_frame_end *rx_end = IWL_RX_END(pkt); + struct ieee80211_hdr *header; + u16 phy_flags = le16_to_cpu(rx_hdr->phy_flags); + u16 rx_stats_sig_avg = le16_to_cpu(rx_stats->sig_avg); + u16 rx_stats_noise_diff = le16_to_cpu(rx_stats->noise_diff); + struct ieee80211_rx_status stats = { + .mactime = le64_to_cpu(rx_end->timestamp), + .freq = ieee80211chan2mhz(le16_to_cpu(rx_hdr->channel)), + .channel = le16_to_cpu(rx_hdr->channel), + .phymode = (rx_hdr->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? + MODE_IEEE80211G : MODE_IEEE80211A, + .antenna = 0, + .rate = rx_hdr->rate, + .flag = 0, + }; + u8 network_packet; + int snr; + + if ((unlikely(rx_stats->phy_count > 20))) { + IWL_DEBUG_DROP + ("dsp size out of range [0,20]: " + "%d/n", rx_stats->phy_count); + return; + } + + if (!(rx_end->status & RX_RES_STATUS_NO_CRC32_ERROR) + || !(rx_end->status & RX_RES_STATUS_NO_RXE_OVERFLOW)) { + IWL_DEBUG_RX("Bad CRC or FIFO: 0x%08X.\n", rx_end->status); + return; + } + + if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) { + iwl3945_handle_data_packet(priv, 1, rxb, &stats, phy_flags); + return; + } + + /* Convert 3945's rssi indicator to dBm */ + stats.ssi = rx_stats->rssi - IWL_RSSI_OFFSET; + + /* Set default noise value to -127 */ + if (priv->last_rx_noise == 0) + priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE; + + /* 3945 provides noise info for OFDM frames only. + * sig_avg and noise_diff are measured by the 3945's digital signal + * processor (DSP), and indicate linear levels of signal level and + * distortion/noise within the packet preamble after + * automatic gain control (AGC). sig_avg should stay fairly + * constant if the radio's AGC is working well. + * Since these values are linear (not dB or dBm), linear + * signal-to-noise ratio (SNR) is (sig_avg / noise_diff). + * Convert linear SNR to dB SNR, then subtract that from rssi dBm + * to obtain noise level in dBm. + * Calculate stats.signal (quality indicator in %) based on SNR. */ + if (rx_stats_noise_diff) { + snr = rx_stats_sig_avg / rx_stats_noise_diff; + stats.noise = stats.ssi - iwl_calc_db_from_ratio(snr); + stats.signal = iwl_calc_sig_qual(stats.ssi, stats.noise); + + /* If noise info not available, calculate signal quality indicator (%) + * using just the dBm signal level. */ + } else { + stats.noise = priv->last_rx_noise; + stats.signal = iwl_calc_sig_qual(stats.ssi, 0); + } + + + IWL_DEBUG_STATS("Rssi %d noise %d qual %d sig_avg %d noise_diff %d\n", + stats.ssi, stats.noise, stats.signal, + rx_stats_sig_avg, rx_stats_noise_diff); + + stats.freq = ieee80211chan2mhz(stats.channel); + + /* can be covered by iwl_report_frame() in most cases */ +/* IWL_DEBUG_RX("RX status: 0x%08X\n", rx_end->status); */ + + header = (struct ieee80211_hdr *)IWL_RX_DATA(pkt); + + network_packet = iwl_is_network_packet(priv, header); + +#ifdef CONFIG_IWLWIFI_DEBUG + if (iwl_debug_level & IWL_DL_STATS && net_ratelimit()) + IWL_DEBUG_STATS + ("[%c] %d RSSI: %d Signal: %u, Noise: %u, Rate: %u\n", + network_packet ? '*' : ' ', + stats.channel, stats.ssi, stats.ssi, + stats.ssi, stats.rate); + + if (iwl_debug_level & (IWL_DL_RX)) + /* Set "1" to report good data frames in groups of 100 */ + iwl_report_frame(priv, pkt, header, 1); +#endif + + if (network_packet) { + priv->last_beacon_time = le32_to_cpu(rx_end->beacon_timestamp); + priv->last_tsf = le64_to_cpu(rx_end->timestamp); + priv->last_rx_rssi = stats.ssi; + priv->last_rx_noise = stats.noise; + } + + switch (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FTYPE) { + case IEEE80211_FTYPE_MGMT: + switch (le16_to_cpu(header->frame_control) & + IEEE80211_FCTL_STYPE) { + case IEEE80211_STYPE_PROBE_RESP: + case IEEE80211_STYPE_BEACON:{ + /* If this is a beacon or probe response for + * our network then cache the beacon + * timestamp */ + if ((((priv->iw_mode == IEEE80211_IF_TYPE_STA) + && !compare_ether_addr(header->addr2, + priv->bssid)) || + ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) + && !compare_ether_addr(header->addr3, + priv->bssid)))) { + struct ieee80211_mgmt *mgmt = + (struct ieee80211_mgmt *)header; + __le32 *pos; + pos = + (__le32 *) & mgmt->u.beacon. + timestamp; + priv->timestamp0 = le32_to_cpu(pos[0]); + priv->timestamp1 = le32_to_cpu(pos[1]); + priv->beacon_int = le16_to_cpu( + mgmt->u.beacon.beacon_int); + if (priv->call_post_assoc_from_beacon && + (priv->iw_mode == + IEEE80211_IF_TYPE_STA)) + queue_work(priv->workqueue, + &priv->post_associate.work); + + priv->call_post_assoc_from_beacon = 0; + } + + break; + } + + case IEEE80211_STYPE_ACTION: + /* TODO: Parse 802.11h frames for CSA... */ + break; + + /* + * TODO: There is no callback function from upper + * stack to inform us when associated status. this + * work around to sniff assoc_resp management frame + * and finish the association process. + */ + case IEEE80211_STYPE_ASSOC_RESP: + case IEEE80211_STYPE_REASSOC_RESP:{ + struct ieee80211_mgmt *mgnt = + (struct ieee80211_mgmt *)header; + priv->assoc_id = (~((1 << 15) | (1 << 14)) & + le16_to_cpu(mgnt->u. + assoc_resp.aid)); + priv->assoc_capability = + le16_to_cpu(mgnt->u.assoc_resp.capab_info); + if (priv->beacon_int) + queue_work(priv->workqueue, + &priv->post_associate.work); + else + priv->call_post_assoc_from_beacon = 1; + break; + } + + case IEEE80211_STYPE_PROBE_REQ:{ + if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) + IWL_DEBUG_DROP + ("Dropping (non network): " MAC_FMT + ", " MAC_FMT ", " MAC_FMT "\n", + MAC_ARG(header->addr1), + MAC_ARG(header->addr2), + MAC_ARG(header->addr3)); + return; + } + } + + iwl3945_handle_data_packet(priv, 0, rxb, &stats, phy_flags); + break; + + case IEEE80211_FTYPE_CTL: + break; + + case IEEE80211_FTYPE_DATA: + if (unlikely(is_duplicate_packet(priv, header))) + IWL_DEBUG_DROP("Dropping (dup): " MAC_FMT ", " + MAC_FMT ", " MAC_FMT "\n", + MAC_ARG(header->addr1), + MAC_ARG(header->addr2), + MAC_ARG(header->addr3)); + else + iwl3945_handle_data_packet(priv, 1, rxb, &stats, + phy_flags); + break; + } +} + +int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr, + dma_addr_t addr, u16 len) +{ + int count; + u32 pad; + struct iwl_tfd_frame *tfd = (struct iwl_tfd_frame *)ptr; + + count = TFD_CTL_COUNT_GET(le32_to_cpu(tfd->control_flags)); + pad = TFD_CTL_PAD_GET(le32_to_cpu(tfd->control_flags)); + + if ((count >= NUM_TFD_CHUNKS) || (count < 0)) { + IWL_ERROR("Error can not send more than %d chunks\n", + NUM_TFD_CHUNKS); + return -EINVAL; + } + + tfd->pa[count].addr = cpu_to_le32(addr); + tfd->pa[count].len = cpu_to_le32(len); + + count++; + + tfd->control_flags = cpu_to_le32(TFD_CTL_COUNT_SET(count) | + TFD_CTL_PAD_SET(pad)); + + return 0; +} + +/** + * iwl_hw_txq_free_tfd - Free one TFD, those at index [txq->q.last_used] + * + * Does NOT advance any indexes + */ +int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) +{ + struct iwl_tfd_frame *bd_tmp = (struct iwl_tfd_frame *)&txq->bd[0]; + struct iwl_tfd_frame *bd = &bd_tmp[txq->q.last_used]; + struct pci_dev *dev = priv->pci_dev; + int i; + int counter; + + /* classify bd */ + if (txq->q.id == IWL_CMD_QUEUE_NUM) + /* nothing to cleanup after for host commands */ + return 0; + + /* sanity check */ + counter = TFD_CTL_COUNT_GET(le32_to_cpu(bd->control_flags)); + if (counter > NUM_TFD_CHUNKS) { + IWL_ERROR("Too many chunks: %i\n", counter); + /* @todo issue fatal error, it is quite serious situation */ + return 0; + } + + /* unmap chunks if any */ + + for (i = 1; i < counter; i++) { + pci_unmap_single(dev, le32_to_cpu(bd->pa[i].addr), + le32_to_cpu(bd->pa[i].len), PCI_DMA_TODEVICE); + if (txq->txb[txq->q.last_used].skb[0]) { + struct sk_buff *skb = txq->txb[txq->q.last_used].skb[0]; + if (txq->txb[txq->q.last_used].skb[0]) { + /* Can be called from interrupt context */ + dev_kfree_skb_any(skb); + txq->txb[txq->q.last_used].skb[0] = NULL; + } + } + } + return 0; +} + +u8 iwl_hw_find_station(struct iwl_priv *priv, const u8 *addr) +{ + int i; + int ret = IWL_INVALID_STATION; + unsigned long flags; + + spin_lock_irqsave(&priv->sta_lock, flags); + for (i = IWL_STA_ID; i < priv->hw_setting.max_stations; i++) + if ((priv->stations[i].used) && + (!compare_ether_addr + (priv->stations[i].sta.sta.addr, addr))) { + ret = i; + goto out; + } + + IWL_DEBUG_INFO("can not find STA " MAC_FMT " (total %d)\n", + MAC_ARG(addr), priv->num_stations); + out: + spin_unlock_irqrestore(&priv->sta_lock, flags); + return ret; +} + +/** + * iwl_hw_build_tx_cmd_rate - Add rate portion to TX_CMD: + * +*/ +void iwl_hw_build_tx_cmd_rate(struct iwl_priv *priv, + struct iwl_cmd *cmd, + struct ieee80211_tx_control *ctrl, + struct ieee80211_hdr *hdr, int sta_id, int tx_id) +{ + unsigned long flags; + u16 rate_index = min(ctrl->tx_rate & 0xffff, IWL_RATE_COUNT - 1); + u16 rate_mask; + int rate; + u8 rts_retry_limit; + u8 data_retry_limit; + __le32 tx_flags; + u16 fc = le16_to_cpu(hdr->frame_control); + + rate = iwl_rates[rate_index].plcp; + tx_flags = cmd->cmd.tx.tx_flags; + + /* We need to figure out how to get the sta->supp_rates while + * in this running context; perhaps encoding into ctrl->tx_rate? */ + rate_mask = IWL_RATES_MASK; + + spin_lock_irqsave(&priv->sta_lock, flags); + + priv->stations[sta_id].current_rate.rate_n_flags = rate; + + if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && + (sta_id != IWL3945_BROADCAST_ID) && + (sta_id != IWL_MULTICAST_ID)) + priv->stations[IWL_STA_ID].current_rate.rate_n_flags = rate; + + spin_unlock_irqrestore(&priv->sta_lock, flags); + + if (tx_id >= IWL_CMD_QUEUE_NUM) + rts_retry_limit = 3; + else + rts_retry_limit = 7; + + if (ieee80211_is_probe_response(fc)) { + data_retry_limit = 3; + if (data_retry_limit < rts_retry_limit) + rts_retry_limit = data_retry_limit; + } else + data_retry_limit = IWL_DEFAULT_TX_RETRY; + + if (priv->data_retry_limit != -1) + data_retry_limit = priv->data_retry_limit; + + if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) { + switch (fc & IEEE80211_FCTL_STYPE) { + case IEEE80211_STYPE_AUTH: + case IEEE80211_STYPE_DEAUTH: + case IEEE80211_STYPE_ASSOC_REQ: + case IEEE80211_STYPE_REASSOC_REQ: + if (tx_flags & TX_CMD_FLG_RTS_MSK) { + tx_flags &= ~TX_CMD_FLG_RTS_MSK; + tx_flags |= TX_CMD_FLG_CTS_MSK; + } + break; + default: + break; + } + } + + cmd->cmd.tx.rts_retry_limit = rts_retry_limit; + cmd->cmd.tx.data_retry_limit = data_retry_limit; + cmd->cmd.tx.rate = rate; + cmd->cmd.tx.tx_flags = tx_flags; + + /* OFDM */ + cmd->cmd.tx.supp_rates[0] = rate_mask & IWL_OFDM_RATES_MASK; + + /* CCK */ + cmd->cmd.tx.supp_rates[1] = (rate_mask >> 8) & 0xF; + + IWL_DEBUG_RATE("Tx sta id: %d, rate: %d (plcp), flags: 0x%4X " + "cck/ofdm mask: 0x%x/0x%x\n", sta_id, + cmd->cmd.tx.rate, le32_to_cpu(cmd->cmd.tx.tx_flags), + cmd->cmd.tx.supp_rates[1], cmd->cmd.tx.supp_rates[0]); +} + +u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, u16 tx_rate, u8 flags) +{ + unsigned long flags_spin; + struct iwl_station_entry *station; + + if (sta_id == IWL_INVALID_STATION) + return IWL_INVALID_STATION; + + spin_lock_irqsave(&priv->sta_lock, flags_spin); + station = &priv->stations[sta_id]; + + station->sta.sta.modify_mask = STA_MODIFY_TX_RATE_MSK; + station->sta.rate_n_flags = cpu_to_le16(tx_rate); + station->current_rate.rate_n_flags = tx_rate; + station->sta.mode = STA_CONTROL_MODIFY_MSK; + + spin_unlock_irqrestore(&priv->sta_lock, flags_spin); + + iwl_send_add_station(priv, &station->sta, flags); + IWL_DEBUG_RATE("SCALE sync station %d to rate %d\n", + sta_id, tx_rate); + return sta_id; +} + +void iwl_hw_card_show_info(struct iwl_priv *priv) +{ + IWL_DEBUG_INFO("3945ABG HW Version %u.%u.%u\n", + ((priv->eeprom.board_revision >> 8) & 0x0F), + ((priv->eeprom.board_revision >> 8) >> 4), + (priv->eeprom.board_revision & 0x00FF)); + + IWL_DEBUG_INFO("3945ABG PBA Number %.*s\n", + (int)sizeof(priv->eeprom.board_pba_number), + priv->eeprom.board_pba_number); + + IWL_DEBUG_INFO("EEPROM_ANTENNA_SWITCH_TYPE is 0x%02X\n", + priv->eeprom.antenna_switch_type); +} + +static int iwl3945_nic_set_pwr_src(struct iwl_priv *priv, int pwr_max) +{ + int rc; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + rc = iwl_grab_restricted_access(priv); + if (rc) { + spin_unlock_irqrestore(&priv->lock, flags); + return rc; + } + + if (!pwr_max) { + u32 val; + + rc = pci_read_config_dword(priv->pci_dev, + PCI_POWER_SOURCE, &val); + if (val & PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT) { + iwl_set_bits_mask_restricted_reg(priv, APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_PWR_SRC_VAUX, + ~APMG_PS_CTRL_MSK_PWR_SRC); + iwl_release_restricted_access(priv); + + iwl_poll_bit(priv, CSR_GPIO_IN, + CSR_GPIO_IN_VAL_VAUX_PWR_SRC, + CSR_GPIO_IN_BIT_AUX_POWER, 5000); + } else + iwl_release_restricted_access(priv); + } else { + iwl_set_bits_mask_restricted_reg(priv, APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_PWR_SRC_VMAIN, + ~APMG_PS_CTRL_MSK_PWR_SRC); + + iwl_release_restricted_access(priv); + iwl_poll_bit(priv, CSR_GPIO_IN, CSR_GPIO_IN_VAL_VMAIN_PWR_SRC, + CSR_GPIO_IN_BIT_AUX_POWER, 5000); /* uS */ + } + spin_unlock_irqrestore(&priv->lock, flags); + + return rc; +} + +static int iwl3945_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) +{ + int rc; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + rc = iwl_grab_restricted_access(priv); + if (rc) { + spin_unlock_irqrestore(&priv->lock, flags); + return rc; + } + + iwl_write_restricted(priv, FH_RCSR_RBD_BASE(0), rxq->dma_addr); + iwl_write_restricted(priv, FH_RCSR_RPTR_ADDR(0), + priv->hw_setting.shared_phys + + offsetof(struct iwl_shared, rx_read_ptr[0])); + iwl_write_restricted(priv, FH_RCSR_WPTR(0), 0); + iwl_write_restricted(priv, FH_RCSR_CONFIG(0), + ALM_FH_RCSR_RX_CONFIG_REG_VAL_DMA_CHNL_EN_ENABLE | + ALM_FH_RCSR_RX_CONFIG_REG_VAL_RDRBD_EN_ENABLE | + ALM_FH_RCSR_RX_CONFIG_REG_BIT_WR_STTS_EN | + ALM_FH_RCSR_RX_CONFIG_REG_VAL_MAX_FRAG_SIZE_128 | + (RX_QUEUE_SIZE_LOG << ALM_FH_RCSR_RX_CONFIG_REG_POS_RBDC_SIZE) | + ALM_FH_RCSR_RX_CONFIG_REG_VAL_IRQ_DEST_INT_HOST | + (1 << ALM_FH_RCSR_RX_CONFIG_REG_POS_IRQ_RBTH) | + ALM_FH_RCSR_RX_CONFIG_REG_VAL_MSG_MODE_FH); + + /* fake read to flush all prev I/O */ + iwl_read_restricted(priv, FH_RSSR_CTRL); + + iwl_release_restricted_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +static int iwl3945_tx_reset(struct iwl_priv *priv) +{ + int rc; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + rc = iwl_grab_restricted_access(priv); + if (rc) { + spin_unlock_irqrestore(&priv->lock, flags); + return rc; + } + + /* bypass mode */ + iwl_write_restricted_reg(priv, SCD_MODE_REG, 0x2); + + /* RA 0 is active */ + iwl_write_restricted_reg(priv, SCD_ARASTAT_REG, 0x01); + + /* all 6 fifo are active */ + iwl_write_restricted_reg(priv, SCD_TXFACT_REG, 0x3f); + + iwl_write_restricted_reg(priv, SCD_SBYP_MODE_1_REG, 0x010000); + iwl_write_restricted_reg(priv, SCD_SBYP_MODE_2_REG, 0x030002); + iwl_write_restricted_reg(priv, SCD_TXF4MF_REG, 0x000004); + iwl_write_restricted_reg(priv, SCD_TXF5MF_REG, 0x000005); + + iwl_write_restricted(priv, FH_TSSR_CBB_BASE, + priv->hw_setting.shared_phys); + + iwl_write_restricted(priv, FH_TSSR_MSG_CONFIG, + ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TXPD_ON | + ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_TXPD_ON | + ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_128B | + ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TFD_ON | + ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_CBB_ON | + ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RSP_WAIT_TH | + ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_RSP_WAIT_TH); + + iwl_release_restricted_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +/** + * iwl3945_txq_ctx_reset - Reset TX queue context + * + * Destroys all DMA structures and initialize them again + */ +static int iwl3945_txq_ctx_reset(struct iwl_priv *priv) +{ + int rc; + int txq_id, slots_num; + + iwl_hw_txq_ctx_free(priv); + + /* Tx CMD queue */ + rc = iwl3945_tx_reset(priv); + if (rc) + goto error; + + /* Tx queue(s) */ + for (txq_id = 0; txq_id < TFD_QUEUE_MAX; txq_id++) { + slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ? + TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; + rc = iwl_tx_queue_init(priv, &priv->txq[txq_id], slots_num, + txq_id); + if (rc) { + IWL_ERROR("Tx %d queue init failed\n", txq_id); + goto error; + } + } + + return rc; + + error: + iwl_hw_txq_ctx_free(priv); + return rc; +} + +int iwl_hw_nic_init(struct iwl_priv *priv) +{ + u8 rev_id; + int rc; + unsigned long flags; + struct iwl_rx_queue *rxq = &priv->rxq; + + iwl_power_init_handle(priv); + + spin_lock_irqsave(&priv->lock, flags); + iwl_set_bit(priv, CSR_ANA_PLL_CFG, (1 << 24)); + iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, + CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX); + + iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + rc = iwl_poll_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + if (rc < 0) { + spin_unlock_irqrestore(&priv->lock, flags); + IWL_DEBUG_INFO("Failed to init the card\n"); + return rc; + } + + rc = iwl_grab_restricted_access(priv); + if (rc) { + spin_unlock_irqrestore(&priv->lock, flags); + return rc; + } + iwl_write_restricted_reg(priv, APMG_CLK_EN_REG, + APMG_CLK_VAL_DMA_CLK_RQT | + APMG_CLK_VAL_BSM_CLK_RQT); + udelay(20); + iwl_set_bits_restricted_reg(priv, APMG_PCIDEV_STT_REG, + APMG_PCIDEV_STT_VAL_L1_ACT_DIS); + iwl_release_restricted_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + /* Determine HW type */ + rc = pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &rev_id); + if (rc) + return rc; + IWL_DEBUG_INFO("HW Revision ID = 0x%X\n", rev_id); + + iwl3945_nic_set_pwr_src(priv, 1); + spin_lock_irqsave(&priv->lock, flags); + + if (rev_id & PCI_CFG_REV_ID_BIT_RTP) + IWL_DEBUG_INFO("RTP type \n"); + else if (rev_id & PCI_CFG_REV_ID_BIT_BASIC_SKU) { + IWL_DEBUG_INFO("ALM-MB type\n"); + iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MB); + } else { + IWL_DEBUG_INFO("ALM-MM type\n"); + iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MM); + } + + spin_unlock_irqrestore(&priv->lock, flags); + + /* Initialize the EEPROM */ + rc = iwl_eeprom_init(priv); + if (rc) + return rc; + + spin_lock_irqsave(&priv->lock, flags); + if (EEPROM_SKU_CAP_OP_MODE_MRC == priv->eeprom.sku_cap) { + IWL_DEBUG_INFO("SKU OP mode is mrc\n"); + iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_SKU_MRC); + } else + IWL_DEBUG_INFO("SKU OP mode is basic\n"); + + if ((priv->eeprom.board_revision & 0xF0) == 0xD0) { + IWL_DEBUG_INFO("3945ABG revision is 0x%X\n", + priv->eeprom.board_revision); + iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_BOARD_TYPE); + } else { + IWL_DEBUG_INFO("3945ABG revision is 0x%X\n", + priv->eeprom.board_revision); + iwl_clear_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_BOARD_TYPE); + } + + if (priv->eeprom.almgor_m_version <= 1) { + iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A); + IWL_DEBUG_INFO("Card M type A version is 0x%X\n", + priv->eeprom.almgor_m_version); + } else { + IWL_DEBUG_INFO("Card M type B version is 0x%X\n", + priv->eeprom.almgor_m_version); + iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B); + } + spin_unlock_irqrestore(&priv->lock, flags); + + if (priv->eeprom.sku_cap & EEPROM_SKU_CAP_SW_RF_KILL_ENABLE) + IWL_DEBUG_RF_KILL("SW RF KILL supported in EEPROM.\n"); + + if (priv->eeprom.sku_cap & EEPROM_SKU_CAP_HW_RF_KILL_ENABLE) + IWL_DEBUG_RF_KILL("HW RF KILL supported in EEPROM.\n"); + + /* Allocate the RX queue, or reset if it is already allocated */ + if (!rxq->bd) { + rc = iwl_rx_queue_alloc(priv); + if (rc) { + IWL_ERROR("Unable to initialize Rx queue\n"); + return -ENOMEM; + } + } else + iwl_rx_queue_reset(priv, rxq); + + iwl_rx_replenish(priv); + + iwl3945_rx_init(priv, rxq); + + spin_lock_irqsave(&priv->lock, flags); + + /* Look at using this instead: + rxq->need_update = 1; + iwl_rx_queue_update_write_ptr(priv, rxq); + */ + + rc = iwl_grab_restricted_access(priv); + if (rc) { + spin_unlock_irqrestore(&priv->lock, flags); + return rc; + } + iwl_write_restricted(priv, FH_RCSR_WPTR(0), rxq->write & ~7); + iwl_release_restricted_access(priv); + + spin_unlock_irqrestore(&priv->lock, flags); + + rc = iwl3945_txq_ctx_reset(priv); + if (rc) + return rc; + + set_bit(STATUS_INIT, &priv->status); + + return 0; +} + +/** + * iwl_hw_txq_ctx_free - Free TXQ Context + * + * Destroy all TX DMA queues and structures + */ +void iwl_hw_txq_ctx_free(struct iwl_priv *priv) +{ + int txq_id; + + /* Tx queues */ + for (txq_id = 0; txq_id < TFD_QUEUE_MAX; txq_id++) + iwl_tx_queue_free(priv, &priv->txq[txq_id]); +} + +void iwl_hw_txq_ctx_stop(struct iwl_priv *priv) +{ + int queue; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + if (iwl_grab_restricted_access(priv)) { + spin_unlock_irqrestore(&priv->lock, flags); + iwl_hw_txq_ctx_free(priv); + return; + } + + /* stop SCD */ + iwl_write_restricted_reg(priv, SCD_MODE_REG, 0); + + /* reset TFD queues */ + for (queue = TFD_QUEUE_MIN; queue < TFD_QUEUE_MAX; queue++) { + iwl_write_restricted(priv, FH_TCSR_CONFIG(queue), 0x0); + iwl_poll_restricted_bit(priv, FH_TSSR_TX_STATUS, + ALM_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(queue), + 1000); + } + + iwl_release_restricted_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + iwl_hw_txq_ctx_free(priv); +} + +int iwl_hw_nic_stop_master(struct iwl_priv *priv) +{ + int rc = 0; + u32 reg_val; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + + /* set stop master bit */ + iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); + + reg_val = iwl_read32(priv, CSR_GP_CNTRL); + + if (CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE == + (reg_val & CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE)) + IWL_DEBUG_INFO("Card in power save, master is already " + "stopped\n"); + else { + rc = iwl_poll_bit(priv, CSR_RESET, + CSR_RESET_REG_FLAG_MASTER_DISABLED, + CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); + if (rc < 0) { + spin_unlock_irqrestore(&priv->lock, flags); + return rc; + } + } + + spin_unlock_irqrestore(&priv->lock, flags); + IWL_DEBUG_INFO("stop master\n"); + + return rc; +} + +int iwl_hw_nic_reset(struct iwl_priv *priv) +{ + int rc; + unsigned long flags; + + iwl_hw_nic_stop_master(priv); + + spin_lock_irqsave(&priv->lock, flags); + + iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); + + rc = iwl_poll_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + + rc = iwl_grab_restricted_access(priv); + if (!rc) { + iwl_write_restricted_reg(priv, APMG_CLK_CTRL_REG, + APMG_CLK_VAL_BSM_CLK_RQT); + + udelay(10); + + iwl_set_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + + iwl_write_restricted_reg(priv, APMG_RTC_INT_MSK_REG, 0x0); + iwl_write_restricted_reg(priv, APMG_RTC_INT_STT_REG, + 0xFFFFFFFF); + + /* enable DMA */ + iwl_write_restricted_reg(priv, APMG_CLK_EN_REG, + APMG_CLK_VAL_DMA_CLK_RQT | + APMG_CLK_VAL_BSM_CLK_RQT); + udelay(10); + + iwl_set_bits_restricted_reg(priv, APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_RESET_REQ); + udelay(5); + iwl_clear_bits_restricted_reg(priv, APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_RESET_REQ); + iwl_release_restricted_access(priv); + } + + /* Clear the 'host command active' bit... */ + clear_bit(STATUS_HCMD_ACTIVE, &priv->status); + + wake_up_interruptible(&priv->wait_command_queue); + spin_unlock_irqrestore(&priv->lock, flags); + + return rc; +} + +/** + * iwl_hw_reg_adjust_power_by_temp - return index delta into power gain settings table + */ +static int iwl_hw_reg_adjust_power_by_temp(int new_reading, int old_reading) +{ + return (new_reading - old_reading) * (-11) / 100; +} + +/** + * iwl_hw_reg_temp_out_of_range - Keep temperature in sane range + */ +static inline int iwl_hw_reg_temp_out_of_range(int temperature) +{ + return (((temperature < -260) || (temperature > 25)) ? 1 : 0); +} + +int iwl_hw_get_temperature(struct iwl_priv *priv) +{ + return iwl_read32(priv, CSR_UCODE_DRV_GP2); +} + +/** + * iwl_hw_reg_txpower_get_temperature - get current temperature by reading from NIC + */ +static int iwl_hw_reg_txpower_get_temperature(struct iwl_priv *priv) +{ + int temperature; + + temperature = iwl_hw_get_temperature(priv); + + /* driver's okay range is -260 to +25. + * human readable okay range is 0 to +285 */ + IWL_DEBUG_INFO("Temperature: %d\n", temperature + IWL_TEMP_CONVERT); + + /* handle insane temp reading */ + if (iwl_hw_reg_temp_out_of_range(temperature)) { + IWL_ERROR("Error bad temperature value %d\n", temperature); + + /* if really really hot(?), + * substitute the 3rd band/group's temp measured at factory */ + if (priv->last_temperature > 100) + temperature = priv->eeprom.groups[2].temperature; + else /* else use most recent "sane" value from driver */ + temperature = priv->last_temperature; + } + + return temperature; /* raw, not "human readable" */ +} + +/* Adjust Txpower only if temperature variance is greater than threshold. + * + * Both are lower than older versions' 9 degrees */ +#define IWL_TEMPERATURE_LIMIT_TIMER 6 + +/** + * is_temp_calib_needed - determines if new calibration is needed + * + * records new temperature in tx_mgr->temperature. + * replaces tx_mgr->last_temperature *only* if calib needed + * (assumes caller will actually do the calibration!). */ +static int is_temp_calib_needed(struct iwl_priv *priv) +{ + int temp_diff; + + priv->temperature = iwl_hw_reg_txpower_get_temperature(priv); + temp_diff = priv->temperature - priv->last_temperature; + + /* get absolute value */ + if (temp_diff < 0) { + IWL_DEBUG_POWER("Getting cooler, delta %d,\n", temp_diff); + temp_diff = -temp_diff; + } else if (temp_diff == 0) + IWL_DEBUG_POWER("Same temp,\n"); + else + IWL_DEBUG_POWER("Getting warmer, delta %d,\n", temp_diff); + + /* if we don't need calibration, *don't* update last_temperature */ + if (temp_diff < IWL_TEMPERATURE_LIMIT_TIMER) { + IWL_DEBUG_POWER("Timed thermal calib not needed\n"); + return 0; + } + + IWL_DEBUG_POWER("Timed thermal calib needed\n"); + + /* assume that caller will actually do calib ... + * update the "last temperature" value */ + priv->last_temperature = priv->temperature; + return 1; +} + +#define IWL_MAX_GAIN_ENTRIES 78 +#define IWL_CCK_FROM_OFDM_POWER_DIFF -5 +#define IWL_CCK_FROM_OFDM_INDEX_DIFF (10) + +/* radio and DSP power table, each step is 1/2 dB. + * 1st number is for RF analog gain, 2nd number is for DSP pre-DAC gain. */ +static struct iwl_tx_power power_gain_table[2][IWL_MAX_GAIN_ENTRIES] = { + { + {251, 127}, /* 2.4 GHz, highest power */ + {251, 127}, + {251, 127}, + {251, 127}, + {251, 125}, + {251, 110}, + {251, 105}, + {251, 98}, + {187, 125}, + {187, 115}, + {187, 108}, + {187, 99}, + {243, 119}, + {243, 111}, + {243, 105}, + {243, 97}, + {243, 92}, + {211, 106}, + {211, 100}, + {179, 120}, + {179, 113}, + {179, 107}, + {147, 125}, + {147, 119}, + {147, 112}, + {147, 106}, + {147, 101}, + {147, 97}, + {147, 91}, + {115, 107}, + {235, 121}, + {235, 115}, + {235, 109}, + {203, 127}, + {203, 121}, + {203, 115}, + {203, 108}, + {203, 102}, + {203, 96}, + {203, 92}, + {171, 110}, + {171, 104}, + {171, 98}, + {139, 116}, + {227, 125}, + {227, 119}, + {227, 113}, + {227, 107}, + {227, 101}, + {227, 96}, + {195, 113}, + {195, 106}, + {195, 102}, + {195, 95}, + {163, 113}, + {163, 106}, + {163, 102}, + {163, 95}, + {131, 113}, + {131, 106}, + {131, 102}, + {131, 95}, + {99, 113}, + {99, 106}, + {99, 102}, + {99, 95}, + {67, 113}, + {67, 106}, + {67, 102}, + {67, 95}, + {35, 113}, + {35, 106}, + {35, 102}, + {35, 95}, + {3, 113}, + {3, 106}, + {3, 102}, + {3, 95} }, /* 2.4 GHz, lowest power */ + { + {251, 127}, /* 5.x GHz, highest power */ + {251, 120}, + {251, 114}, + {219, 119}, + {219, 101}, + {187, 113}, + {187, 102}, + {155, 114}, + {155, 103}, + {123, 117}, + {123, 107}, + {123, 99}, + {123, 92}, + {91, 108}, + {59, 125}, + {59, 118}, + {59, 109}, + {59, 102}, + {59, 96}, + {59, 90}, + {27, 104}, + {27, 98}, + {27, 92}, + {115, 118}, + {115, 111}, + {115, 104}, + {83, 126}, + {83, 121}, + {83, 113}, + {83, 105}, + {83, 99}, + {51, 118}, + {51, 111}, + {51, 104}, + {51, 98}, + {19, 116}, + {19, 109}, + {19, 102}, + {19, 98}, + {19, 93}, + {171, 113}, + {171, 107}, + {171, 99}, + {139, 120}, + {139, 113}, + {139, 107}, + {139, 99}, + {107, 120}, + {107, 113}, + {107, 107}, + {107, 99}, + {75, 120}, + {75, 113}, + {75, 107}, + {75, 99}, + {43, 120}, + {43, 113}, + {43, 107}, + {43, 99}, + {11, 120}, + {11, 113}, + {11, 107}, + {11, 99}, + {131, 107}, + {131, 99}, + {99, 120}, + {99, 113}, + {99, 107}, + {99, 99}, + {67, 120}, + {67, 113}, + {67, 107}, + {67, 99}, + {35, 120}, + {35, 113}, + {35, 107}, + {35, 99}, + {3, 120} } /* 5.x GHz, lowest power */ +}; + +static inline u8 iwl_hw_reg_fix_power_index(int index) +{ + if (index < 0) + return 0; + if (index >= IWL_MAX_GAIN_ENTRIES) + return IWL_MAX_GAIN_ENTRIES - 1; + return (u8) index; +} + +/* Kick off thermal recalibration check every 60 seconds */ +#define REG_RECALIB_PERIOD (60) + +/** + * iwl_hw_reg_set_scan_power - Set Tx power for scan probe requests + * + * Set (in our channel info database) the direct scan Tx power for 1 Mbit (CCK) + * or 6 Mbit (OFDM) rates. + */ +static void iwl_hw_reg_set_scan_power(struct iwl_priv *priv, u32 scan_tbl_index, + s32 rate_index, const s8 *clip_pwrs, + struct iwl_channel_info *ch_info, + int band_index) +{ + struct iwl_scan_power_info *scan_power_info; + s8 power; + u8 power_index; + + scan_power_info = &ch_info->scan_pwr_info[scan_tbl_index]; + + /* use this channel group's 6Mbit clipping/saturation pwr, + * but cap at regulatory scan power restriction (set during init + * based on eeprom channel data) for this channel. */ + power = min(ch_info->scan_power, clip_pwrs[IWL_RATE_6M_INDEX]); + + /* further limit to user's max power preference. + * FIXME: Other spectrum management power limitations do not + * seem to apply?? */ + power = min(power, priv->user_txpower_limit); + scan_power_info->requested_power = power; + + /* find difference between new scan *power* and current "normal" + * Tx *power* for 6Mb. Use this difference (x2) to adjust the + * current "normal" temperature-compensated Tx power *index* for + * this rate (1Mb or 6Mb) to yield new temp-compensated scan power + * *index*. */ + power_index = ch_info->power_info[rate_index].power_table_index + - (power - ch_info->power_info + [IWL_RATE_6M_INDEX].requested_power) * 2; + + /* store reference index that we use when adjusting *all* scan + * powers. So we can accommodate user (all channel) or spectrum + * management (single channel) power changes "between" temperature + * feedback compensation procedures. + * don't force fit this reference index into gain table; it may be a + * negative number. This will help avoid errors when we're at + * the lower bounds (highest gains, for warmest temperatures) + * of the table. */ + + /* don't exceed table bounds for "real" setting */ + power_index = iwl_hw_reg_fix_power_index(power_index); + + scan_power_info->power_table_index = power_index; + scan_power_info->tpc.tx_gain = + power_gain_table[band_index][power_index].tx_gain; + scan_power_info->tpc.dsp_atten = + power_gain_table[band_index][power_index].dsp_atten; +} + +/** + * iwl_hw_reg_send_txpower - fill in Tx Power command with gain settings + * + * Configures power settings for all rates for the current channel, + * using values from channel info struct, and send to NIC + */ +int iwl_hw_reg_send_txpower(struct iwl_priv *priv) +{ + int rate_idx; + const struct iwl_channel_info *ch_info = NULL; + struct iwl_txpowertable_cmd txpower = { + .channel = priv->active_rxon.channel, + }; + + txpower.band = (priv->phymode == MODE_IEEE80211A) ? 0 : 1; + ch_info = iwl_get_channel_info(priv, + priv->phymode, + le16_to_cpu(priv->active_rxon.channel)); + if (!ch_info) { + IWL_ERROR + ("Failed to get channel info for channel %d [%d]\n", + le16_to_cpu(priv->active_rxon.channel), priv->phymode); + return -EINVAL; + } + + if (!is_channel_valid(ch_info)) { + IWL_DEBUG_POWER("Not calling TX_PWR_TABLE_CMD on " + "non-Tx channel.\n"); + return 0; + } + + /* fill cmd with power settings for all rates for current channel */ + for (rate_idx = 0; rate_idx < IWL_RATE_COUNT; rate_idx++) { + txpower.power[rate_idx].tpc = ch_info->power_info[rate_idx].tpc; + txpower.power[rate_idx].rate = iwl_rates[rate_idx].plcp; + + IWL_DEBUG_POWER("ch %d:%d rf %d dsp %3d rate code 0x%02x\n", + le16_to_cpu(txpower.channel), + txpower.band, + txpower.power[rate_idx].tpc.tx_gain, + txpower.power[rate_idx].tpc.dsp_atten, + txpower.power[rate_idx].rate); + } + + return iwl_send_cmd_pdu(priv, REPLY_TX_PWR_TABLE_CMD, + sizeof(struct iwl_txpowertable_cmd), &txpower); + +} + +/** + * iwl_hw_reg_set_new_power - Configures power tables at new levels + * @ch_info: Channel to update. Uses power_info.requested_power. + * + * Replace requested_power and base_power_index ch_info fields for + * one channel. + * + * Called if user or spectrum management changes power preferences. + * Takes into account h/w and modulation limitations (clip power). + * + * This does *not* send anything to NIC, just sets up ch_info for one channel. + * + * NOTE: reg_compensate_for_temperature_dif() *must* be run after this to + * properly fill out the scan powers, and actual h/w gain settings, + * and send changes to NIC + */ +static int iwl_hw_reg_set_new_power(struct iwl_priv *priv, + struct iwl_channel_info *ch_info) +{ + struct iwl_channel_power_info *power_info; + int power_changed = 0; + int i; + const s8 *clip_pwrs; + int power; + + /* Get this chnlgrp's rate-to-max/clip-powers table */ + clip_pwrs = priv->clip_groups[ch_info->group_index].clip_powers; + + /* Get this channel's rate-to-current-power settings table */ + power_info = ch_info->power_info; + + /* update OFDM Txpower settings */ + for (i = IWL_FIRST_OFDM_RATE; i <= IWL_LAST_OFDM_RATE; + i++, ++power_info) { + int delta_idx; + + /* limit new power to be no more than h/w capability */ + power = min(ch_info->curr_txpow, clip_pwrs[i]); + if (power == power_info->requested_power) + continue; + + /* find difference between old and new requested powers, + * update base (non-temp-compensated) power index */ + delta_idx = (power - power_info->requested_power) * 2; + power_info->base_power_index -= delta_idx; + + /* save new requested power value */ + power_info->requested_power = power; + + power_changed = 1; + } + + /* update CCK Txpower settings, based on OFDM 12M setting ... + * ... all CCK power settings for a given channel are the *same*. */ + if (power_changed) { + power = + ch_info->power_info[IWL_RATE_12M_INDEX]. + requested_power + IWL_CCK_FROM_OFDM_POWER_DIFF; + + /* do all CCK rates' iwl_channel_power_info structures */ + for (i = IWL_FIRST_CCK_RATE; i <= IWL_LAST_CCK_RATE; i++) { + power_info->requested_power = power; + power_info->base_power_index = + ch_info->power_info[IWL_RATE_12M_INDEX]. + base_power_index + IWL_CCK_FROM_OFDM_INDEX_DIFF; + ++power_info; + } + } + + return 0; +} + +/** + * iwl_hw_reg_get_ch_txpower_limit - returns new power limit for channel + * + * NOTE: Returned power limit may be less (but not more) than requested, + * based strictly on regulatory (eeprom and spectrum mgt) limitations + * (no consideration for h/w clipping limitations). + */ +static int iwl_hw_reg_get_ch_txpower_limit(struct iwl_channel_info *ch_info) +{ + s8 max_power; + +#if 0 + /* if we're using TGd limits, use lower of TGd or EEPROM */ + if (ch_info->tgd_data.max_power != 0) + max_power = min(ch_info->tgd_data.max_power, + ch_info->eeprom.max_power_avg); + + /* else just use EEPROM limits */ + else +#endif + max_power = ch_info->eeprom.max_power_avg; + + return min(max_power, ch_info->max_power_avg); +} + +/** + * iwl_hw_reg_comp_txpower_temp - Compensate for temperature + * + * Compensate txpower settings of *all* channels for temperature. + * This only accounts for the difference between current temperature + * and the factory calibration temperatures, and bases the new settings + * on the channel's base_power_index. + * + * If RxOn is "associated", this sends the new Txpower to NIC! + */ +static int iwl_hw_reg_comp_txpower_temp(struct iwl_priv *priv) +{ + struct iwl_channel_info *ch_info = NULL; + int delta_index; + const s8 *clip_pwrs; /* array of h/w max power levels for each rate */ + u8 a_band; + u8 rate_index; + u8 scan_tbl_index; + u8 i; + int ref_temp; + int temperature = priv->temperature; + + /* set up new Tx power info for each and every channel, 2.4 and 5.x */ + for (i = 0; i < priv->channel_count; i++) { + ch_info = &priv->channel_info[i]; + a_band = is_channel_a_band(ch_info); + + /* Get this chnlgrp's factory calibration temperature */ + ref_temp = (s16)priv->eeprom.groups[ch_info->group_index]. + temperature; + + /* get power index adjustment based on curr and factory + * temps */ + delta_index = iwl_hw_reg_adjust_power_by_temp(temperature, + ref_temp); + + /* set tx power value for all rates, OFDM and CCK */ + for (rate_index = 0; rate_index < IWL_RATE_COUNT; + rate_index++) { + int power_idx = + ch_info->power_info[rate_index].base_power_index; + + /* temperature compensate */ + power_idx += delta_index; + + /* stay within table range */ + power_idx = iwl_hw_reg_fix_power_index(power_idx); + ch_info->power_info[rate_index]. + power_table_index = (u8) power_idx; + ch_info->power_info[rate_index].tpc = + power_gain_table[a_band][power_idx]; + } + + /* Get this chnlgrp's rate-to-max/clip-powers table */ + clip_pwrs = priv->clip_groups[ch_info->group_index].clip_powers; + + /* set scan tx power, 1Mbit for CCK, 6Mbit for OFDM */ + for (scan_tbl_index = 0; + scan_tbl_index < IWL_NUM_SCAN_RATES; scan_tbl_index++) { + s32 actual_index = (scan_tbl_index == 0) ? + IWL_RATE_1M_INDEX : IWL_RATE_6M_INDEX; + iwl_hw_reg_set_scan_power(priv, scan_tbl_index, + actual_index, clip_pwrs, + ch_info, a_band); + } + } + + /* send Txpower command for current channel to ucode */ + return iwl_hw_reg_send_txpower(priv); +} + +int iwl_hw_reg_set_txpower(struct iwl_priv *priv, s8 power) +{ + struct iwl_channel_info *ch_info; + s8 max_power; + u8 a_band; + u8 i; + + if (priv->user_txpower_limit == power) { + IWL_DEBUG_POWER("Requested Tx power same as current " + "limit: %ddBm.\n", power); + return 0; + } + + IWL_DEBUG_POWER("Setting upper limit clamp to %ddBm.\n", power); + priv->user_txpower_limit = power; + + /* set up new Tx powers for each and every channel, 2.4 and 5.x */ + + for (i = 0; i < priv->channel_count; i++) { + ch_info = &priv->channel_info[i]; + a_band = is_channel_a_band(ch_info); + + /* find minimum power of all user and regulatory constraints + * (does not consider h/w clipping limitations) */ + max_power = iwl_hw_reg_get_ch_txpower_limit(ch_info); + max_power = min(power, max_power); + if (max_power != ch_info->curr_txpow) { + ch_info->curr_txpow = max_power; + + /* this considers the h/w clipping limitations */ + iwl_hw_reg_set_new_power(priv, ch_info); + } + } + + /* update txpower settings for all channels, + * send to NIC if associated. */ + is_temp_calib_needed(priv); + iwl_hw_reg_comp_txpower_temp(priv); + + return 0; +} + +/* will add 3945 channel switch cmd handling later */ +int iwl_hw_channel_switch(struct iwl_priv *priv, u16 channel) +{ + return 0; +} + +/** + * iwl3945_reg_txpower_periodic - called when time to check our temperature. + * + * -- reset periodic timer + * -- see if temp has changed enough to warrant re-calibration ... if so: + * -- correct coeffs for temp (can reset temp timer) + * -- save this temp as "last", + * -- send new set of gain settings to NIC + * NOTE: This should continue working, even when we're not associated, + * so we can keep our internal table of scan powers current. */ +void iwl3945_reg_txpower_periodic(struct iwl_priv *priv) +{ + /* This will kick in the "brute force" + * iwl_hw_reg_comp_txpower_temp() below */ + if (!is_temp_calib_needed(priv)) + goto reschedule; + + /* Set up a new set of temp-adjusted TxPowers, send to NIC. + * This is based *only* on current temperature, + * ignoring any previous power measurements */ + iwl_hw_reg_comp_txpower_temp(priv); + + reschedule: + queue_delayed_work(priv->workqueue, + &priv->thermal_periodic, REG_RECALIB_PERIOD * HZ); +} + +void iwl3945_bg_reg_txpower_periodic(struct work_struct *work) +{ + struct iwl_priv *priv = container_of(work, struct iwl_priv, + thermal_periodic.work); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + mutex_lock(&priv->mutex); + iwl3945_reg_txpower_periodic(priv); + mutex_unlock(&priv->mutex); +} + +/** + * iwl_hw_reg_get_ch_grp_index - find the channel-group index (0-4) + * for the channel. + * + * This function is used when initializing channel-info structs. + * + * NOTE: These channel groups do *NOT* match the bands above! + * These channel groups are based on factory-tested channels; + * on A-band, EEPROM's "group frequency" entries represent the top + * channel in each group 1-4. Group 5 All B/G channels are in group 0. + */ +static u16 iwl_hw_reg_get_ch_grp_index(struct iwl_priv *priv, + const struct iwl_channel_info *ch_info) +{ + struct iwl_eeprom_txpower_group *ch_grp = &priv->eeprom.groups[0]; + u8 group; + u16 group_index = 0; /* based on factory calib frequencies */ + u8 grp_channel; + + /* Find the group index for the channel ... don't use index 1(?) */ + if (is_channel_a_band(ch_info)) { + for (group = 1; group < 5; group++) { + grp_channel = ch_grp[group].group_channel; + if (ch_info->channel <= grp_channel) { + group_index = group; + break; + } + } + /* group 4 has a few channels *above* its factory cal freq */ + if (group == 5) + group_index = 4; + } else + group_index = 0; /* 2.4 GHz, group 0 */ + + IWL_DEBUG_POWER("Chnl %d mapped to grp %d\n", ch_info->channel, + group_index); + return group_index; +} + +/** + * iwl_hw_reg_get_matched_power_index - Interpolate to get nominal index + * + * Interpolate to get nominal (i.e. at factory calibration temperature) index + * into radio/DSP gain settings table for requested power. + */ +static int iwl_hw_reg_get_matched_power_index(struct iwl_priv *priv, + s8 requested_power, + s32 setting_index, s32 *new_index) +{ + const struct iwl_eeprom_txpower_group *chnl_grp = NULL; + s32 index0, index1; + s32 power = 2 * requested_power; + s32 i; + const struct iwl_eeprom_txpower_sample *samples; + s32 gains0, gains1; + s32 res; + s32 denominator; + + chnl_grp = &priv->eeprom.groups[setting_index]; + samples = chnl_grp->samples; + for (i = 0; i < 5; i++) { + if (power == samples[i].power) { + *new_index = samples[i].gain_index; + return 0; + } + } + + if (power > samples[1].power) { + index0 = 0; + index1 = 1; + } else if (power > samples[2].power) { + index0 = 1; + index1 = 2; + } else if (power > samples[3].power) { + index0 = 2; + index1 = 3; + } else { + index0 = 3; + index1 = 4; + } + + denominator = (s32) samples[index1].power - (s32) samples[index0].power; + if (denominator == 0) + return -EINVAL; + gains0 = (s32) samples[index0].gain_index * (1 << 19); + gains1 = (s32) samples[index1].gain_index * (1 << 19); + res = gains0 + (gains1 - gains0) * + ((s32) power - (s32) samples[index0].power) / denominator + + (1 << 18); + *new_index = res >> 19; + return 0; +} + +static void iwl_hw_reg_init_channel_groups(struct iwl_priv *priv) +{ + u32 i; + s32 rate_index; + const struct iwl_eeprom_txpower_group *group; + + IWL_DEBUG_POWER("Initializing factory calib info from EEPROM\n"); + + for (i = 0; i < IWL_NUM_TX_CALIB_GROUPS; i++) { + s8 *clip_pwrs; /* table of power levels for each rate */ + s8 satur_pwr; /* saturation power for each chnl group */ + group = &priv->eeprom.groups[i]; + + /* sanity check on factory saturation power value */ + if (group->saturation_power < 40) { + IWL_WARNING("Error: saturation power is %d, " + "less than minimum expected 40\n", + group->saturation_power); + return; + } + + /* + * Derive requested power levels for each rate, based on + * hardware capabilities (saturation power for band). + * Basic value is 3dB down from saturation, with further + * power reductions for highest 3 data rates. These + * backoffs provide headroom for high rate modulation + * power peaks, without too much distortion (clipping). + */ + /* we'll fill in this array with h/w max power levels */ + clip_pwrs = (s8 *) priv->clip_groups[i].clip_powers; + + /* divide factory saturation power by 2 to find -3dB level */ + satur_pwr = (s8) (group->saturation_power >> 1); + + /* fill in channel group's nominal powers for each rate */ + for (rate_index = 0; + rate_index < IWL_RATE_COUNT; rate_index++, clip_pwrs++) { + switch (rate_index) { + case IWL_RATE_36M_INDEX: + if (i == 0) /* B/G */ + *clip_pwrs = satur_pwr; + else /* A */ + *clip_pwrs = satur_pwr - 5; + break; + case IWL_RATE_48M_INDEX: + if (i == 0) + *clip_pwrs = satur_pwr - 7; + else + *clip_pwrs = satur_pwr - 10; + break; + case IWL_RATE_54M_INDEX: + if (i == 0) + *clip_pwrs = satur_pwr - 9; + else + *clip_pwrs = satur_pwr - 12; + break; + default: + *clip_pwrs = satur_pwr; + break; + } + } + } +} + +/** + * iwl3945_txpower_set_from_eeprom - Set channel power info based on EEPROM + * + * Second pass (during init) to set up priv->channel_info + * + * Set up Tx-power settings in our channel info database for each VALID + * (for this geo/SKU) channel, at all Tx data rates, based on eeprom values + * and current temperature. + * + * Since this is based on current temperature (at init time), these values may + * not be valid for very long, but it gives us a starting/default point, + * and allows us to active (i.e. using Tx) scan. + * + * This does *not* write values to NIC, just sets up our internal table. + */ +int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv) +{ + struct iwl_channel_info *ch_info = NULL; + struct iwl_channel_power_info *pwr_info; + int delta_index; + u8 rate_index; + u8 scan_tbl_index; + const s8 *clip_pwrs; /* array of power levels for each rate */ + u8 gain, dsp_atten; + s8 power; + u8 pwr_index, base_pwr_index, a_band; + u8 i; + int temperature; + + /* save temperature reference, + * so we can determine next time to calibrate */ + temperature = iwl_hw_reg_txpower_get_temperature(priv); + priv->last_temperature = temperature; + + iwl_hw_reg_init_channel_groups(priv); + + /* initialize Tx power info for each and every channel, 2.4 and 5.x */ + for (i = 0, ch_info = priv->channel_info; i < priv->channel_count; + i++, ch_info++) { + a_band = is_channel_a_band(ch_info); + if (!is_channel_valid(ch_info)) + continue; + + /* find this channel's channel group (*not* "band") index */ + ch_info->group_index = + iwl_hw_reg_get_ch_grp_index(priv, ch_info); + + /* Get this chnlgrp's rate->max/clip-powers table */ + clip_pwrs = priv->clip_groups[ch_info->group_index].clip_powers; + + /* calculate power index *adjustment* value according to + * diff between current temperature and factory temperature */ + delta_index = iwl_hw_reg_adjust_power_by_temp(temperature, + priv->eeprom.groups[ch_info->group_index]. + temperature); + + IWL_DEBUG_POWER("Delta index for channel %d: %d [%d]\n", + ch_info->channel, delta_index, temperature + + IWL_TEMP_CONVERT); + + /* set tx power value for all OFDM rates */ + for (rate_index = 0; rate_index < IWL_OFDM_RATES; + rate_index++) { + s32 power_idx; + int rc; + + /* use channel group's clip-power table, + * but don't exceed channel's max power */ + s8 pwr = min(ch_info->max_power_avg, + clip_pwrs[rate_index]); + + pwr_info = &ch_info->power_info[rate_index]; + + /* get base (i.e. at factory-measured temperature) + * power table index for this rate's power */ + rc = iwl_hw_reg_get_matched_power_index(priv, pwr, + ch_info->group_index, + &power_idx); + if (rc) { + IWL_ERROR("Invalid power index\n"); + return rc; + } + pwr_info->base_power_index = (u8) power_idx; + + /* temperature compensate */ + power_idx += delta_index; + + /* stay within range of gain table */ + power_idx = iwl_hw_reg_fix_power_index(power_idx); + + /* fill 1 OFDM rate's iwl_channel_power_info struct */ + pwr_info->requested_power = pwr; + pwr_info->power_table_index = (u8) power_idx; + pwr_info->tpc.tx_gain = + power_gain_table[a_band][power_idx].tx_gain; + pwr_info->tpc.dsp_atten = + power_gain_table[a_band][power_idx].dsp_atten; + } + + /* set tx power for CCK rates, based on OFDM 12 Mbit settings*/ + pwr_info = &ch_info->power_info[IWL_RATE_12M_INDEX]; + power = pwr_info->requested_power + + IWL_CCK_FROM_OFDM_POWER_DIFF; + pwr_index = pwr_info->power_table_index + + IWL_CCK_FROM_OFDM_INDEX_DIFF; + base_pwr_index = pwr_info->base_power_index + + IWL_CCK_FROM_OFDM_INDEX_DIFF; + + /* stay within table range */ + pwr_index = iwl_hw_reg_fix_power_index(pwr_index); + gain = power_gain_table[a_band][pwr_index].tx_gain; + dsp_atten = power_gain_table[a_band][pwr_index].dsp_atten; + + /* fill each CCK rate's iwl_channel_power_info structure + * NOTE: All CCK-rate Txpwrs are the same for a given chnl! + * NOTE: CCK rates start at end of OFDM rates! */ + for (rate_index = IWL_OFDM_RATES; + rate_index < IWL_RATE_COUNT; rate_index++) { + pwr_info = &ch_info->power_info[rate_index]; + pwr_info->requested_power = power; + pwr_info->power_table_index = pwr_index; + pwr_info->base_power_index = base_pwr_index; + pwr_info->tpc.tx_gain = gain; + pwr_info->tpc.dsp_atten = dsp_atten; + } + + /* set scan tx power, 1Mbit for CCK, 6Mbit for OFDM */ + for (scan_tbl_index = 0; + scan_tbl_index < IWL_NUM_SCAN_RATES; scan_tbl_index++) { + s32 actual_index = (scan_tbl_index == 0) ? + IWL_RATE_1M_INDEX : IWL_RATE_6M_INDEX; + iwl_hw_reg_set_scan_power(priv, scan_tbl_index, + actual_index, clip_pwrs, ch_info, a_band); + } + } + + return 0; +} + +int iwl_hw_rxq_stop(struct iwl_priv *priv) +{ + int rc; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + rc = iwl_grab_restricted_access(priv); + if (rc) { + spin_unlock_irqrestore(&priv->lock, flags); + return rc; + } + + iwl_write_restricted(priv, FH_RCSR_CONFIG(0), 0); + rc = iwl_poll_restricted_bit(priv, FH_RSSR_STATUS, (1 << 24), 1000); + if (rc < 0) + IWL_ERROR("Can't stop Rx DMA.\n"); + + iwl_release_restricted_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +int iwl_hw_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq) +{ + int rc; + unsigned long flags; + int txq_id = txq->q.id; + + struct iwl_shared *shared_data = priv->hw_setting.shared_virt; + + shared_data->tx_base_ptr[txq_id] = cpu_to_le32((u32)txq->q.dma_addr); + + spin_lock_irqsave(&priv->lock, flags); + rc = iwl_grab_restricted_access(priv); + if (rc) { + spin_unlock_irqrestore(&priv->lock, flags); + return rc; + } + iwl_write_restricted(priv, FH_CBCC_CTRL(txq_id), 0); + iwl_write_restricted(priv, FH_CBCC_BASE(txq_id), 0); + + iwl_write_restricted(priv, FH_TCSR_CONFIG(txq_id), + ALM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_NOINT | + ALM_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_TXF | + ALM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD | + ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL | + ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE); + iwl_release_restricted_access(priv); + + /* fake read to flush all prev. writes */ + iwl_read32(priv, FH_TSSR_CBB_BASE); + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +int iwl_hw_get_rx_read(struct iwl_priv *priv) +{ + struct iwl_shared *shared_data = priv->hw_setting.shared_virt; + + return le32_to_cpu(shared_data->rx_read_ptr[0]); +} + +/** + * iwl3945_init_hw_rate_table - Initialize the hardware rate fallback table + */ +int iwl3945_init_hw_rate_table(struct iwl_priv *priv) +{ + int rc, i; + struct iwl_rate_scaling_cmd rate_cmd = { + .reserved = {0, 0, 0}, + }; + struct iwl_rate_scaling_info *table = rate_cmd.table; + + for (i = 0; i < ARRAY_SIZE(iwl_rates); i++) { + table[i].rate_n_flags = + iwl_hw_set_rate_n_flags(iwl_rates[i].plcp, 0); + table[i].try_cnt = priv->retry_rate; + table[i].next_rate_index = iwl_get_prev_ieee_rate(i); + } + + switch (priv->phymode) { + case MODE_IEEE80211A: + IWL_DEBUG_RATE("Select A mode rate scale\n"); + /* If one of the following CCK rates is used, + * have it fall back to the 6M OFDM rate */ + for (i = IWL_FIRST_CCK_RATE; i <= IWL_LAST_CCK_RATE; i++) + table[i].next_rate_index = IWL_FIRST_OFDM_RATE; + + /* Don't fall back to CCK rates */ + table[IWL_RATE_12M_INDEX].next_rate_index = IWL_RATE_9M_INDEX; + + /* Don't drop out of OFDM rates */ + table[IWL_FIRST_OFDM_RATE].next_rate_index = + IWL_FIRST_OFDM_RATE; + break; + + case MODE_IEEE80211B: + IWL_DEBUG_RATE("Select B mode rate scale\n"); + /* If an OFDM rate is used, have it fall back to the + * 1M CCK rates */ + for (i = IWL_FIRST_OFDM_RATE; i <= IWL_LAST_OFDM_RATE; i++) + table[i].next_rate_index = IWL_FIRST_CCK_RATE; + + /* CCK shouldn't fall back to OFDM... */ + table[IWL_RATE_11M_INDEX].next_rate_index = IWL_RATE_5M_INDEX; + break; + + default: + IWL_DEBUG_RATE("Select G mode rate scale\n"); + break; + } + + /* Update the rate scaling for control frame Tx */ + rate_cmd.table_id = 0; + rc = iwl_send_cmd_pdu(priv, REPLY_RATE_SCALE, sizeof(rate_cmd), + &rate_cmd); + if (rc) + return rc; + + /* Update the rate scaling for data frame Tx */ + rate_cmd.table_id = 1; + return iwl_send_cmd_pdu(priv, REPLY_RATE_SCALE, sizeof(rate_cmd), + &rate_cmd); +} + +int iwl_hw_set_hw_setting(struct iwl_priv *priv) +{ + memset((void *)&priv->hw_setting, 0, + sizeof(struct iwl_driver_hw_info)); + + priv->hw_setting.shared_virt = + pci_alloc_consistent(priv->pci_dev, + sizeof(struct iwl_shared), + &priv->hw_setting.shared_phys); + + if (!priv->hw_setting.shared_virt) { + IWL_ERROR("failed to allocate pci memory\n"); + mutex_unlock(&priv->mutex); + return -ENOMEM; + } + + priv->hw_setting.ac_queue_count = AC_NUM; + priv->hw_setting.rx_buffer_size = IWL_RX_BUF_SIZE; + priv->hw_setting.tx_cmd_len = sizeof(struct iwl_tx_cmd); + priv->hw_setting.max_rxq_size = RX_QUEUE_SIZE; + priv->hw_setting.max_rxq_log = RX_QUEUE_SIZE_LOG; + priv->hw_setting.cck_flag = 0; + priv->hw_setting.max_stations = IWL3945_STATION_COUNT; + priv->hw_setting.bcast_sta_id = IWL3945_BROADCAST_ID; + return 0; +} + +unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv, + struct iwl_frame *frame, u8 rate) +{ + struct iwl_tx_beacon_cmd *tx_beacon_cmd; + unsigned int frame_size; + + tx_beacon_cmd = (struct iwl_tx_beacon_cmd *)&frame->u; + memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd)); + + tx_beacon_cmd->tx.sta_id = IWL3945_BROADCAST_ID; + tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; + + frame_size = iwl_fill_beacon_frame(priv, + tx_beacon_cmd->frame, + BROADCAST_ADDR, + sizeof(frame->u) - sizeof(*tx_beacon_cmd)); + + BUG_ON(frame_size > MAX_MPDU_SIZE); + tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size); + + tx_beacon_cmd->tx.rate = rate; + tx_beacon_cmd->tx.tx_flags = (TX_CMD_FLG_SEQ_CTL_MSK | + TX_CMD_FLG_TSF_MSK); + + /* supp_rates[0] == OFDM */ + tx_beacon_cmd->tx.supp_rates[0] = IWL_OFDM_BASIC_RATES_MASK; + + /* supp_rates[1] == CCK + * + * NOTE: IWL_*_RATES_MASK are not in the order that supp_rates + * expects so we have to shift them around. + * + * supp_rates expects: + * CCK rates are bit0..3 + * + * However IWL_*_RATES_MASK has: + * CCK rates are bit8..11 + */ + tx_beacon_cmd->tx.supp_rates[1] = + (IWL_CCK_BASIC_RATES_MASK >> 8) & 0xF; + + return (sizeof(struct iwl_tx_beacon_cmd) + frame_size); +} + +void iwl_hw_rx_handler_setup(struct iwl_priv *priv) +{ + priv->rx_handlers[REPLY_3945_RX] = iwl3945_rx_reply_rx; +} + +void iwl_hw_setup_deferred_work(struct iwl_priv *priv) +{ + INIT_DELAYED_WORK(&priv->thermal_periodic, + iwl3945_bg_reg_txpower_periodic); +} + +void iwl_hw_cancel_deferred_work(struct iwl_priv *priv) +{ + cancel_delayed_work(&priv->thermal_periodic); +} + +struct pci_device_id iwl_hw_card_ids[] = { + {0x8086, 0x4222, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0x8086, 0x4227, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0} +}; + +inline int iwl_eeprom_aqcuire_semaphore(struct iwl_priv *priv) +{ + _iwl_clear_bit(priv, CSR_EEPROM_GP, CSR_EEPROM_GP_IF_OWNER_MSK); + return 0; +} + +MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids); diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h new file mode 100644 index 00000000000..813902e9f8c --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -0,0 +1,41 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#ifndef __iwl_3945_h__ +#define __iwl_3945_h__ + +/* + * Forward declare iwl-3945.c functions for iwl-base.c + */ +extern int iwl_eeprom_aqcuire_semaphore(struct iwl_priv *priv); +extern __le32 iwl3945_get_antenna_flags(const struct iwl_priv *priv); +extern int iwl3945_init_hw_rate_table(struct iwl_priv *priv); +extern void iwl3945_reg_txpower_periodic(struct iwl_priv *priv); +extern void iwl3945_bg_reg_txpower_periodic(struct work_struct *work); +extern int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv); +extern u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, + u16 tx_rate, u8 flags); +#endif diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h new file mode 100644 index 00000000000..99a19ef4c74 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h @@ -0,0 +1,581 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU Geeral Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +#ifndef __iwl_4965_hw_h__ +#define __iwl_4965_hw_h__ + +#define IWL_RX_BUF_SIZE (4 * 1024) +#define IWL_MAX_BSM_SIZE BSM_SRAM_SIZE +#define KDR_RTC_INST_UPPER_BOUND (0x018000) +#define KDR_RTC_DATA_UPPER_BOUND (0x80A000) +#define KDR_RTC_INST_SIZE (KDR_RTC_INST_UPPER_BOUND - RTC_INST_LOWER_BOUND) +#define KDR_RTC_DATA_SIZE (KDR_RTC_DATA_UPPER_BOUND - RTC_DATA_LOWER_BOUND) + +#define IWL_MAX_INST_SIZE KDR_RTC_INST_SIZE +#define IWL_MAX_DATA_SIZE KDR_RTC_DATA_SIZE + +static inline int iwl_hw_valid_rtc_data_addr(u32 addr) +{ + return (addr >= RTC_DATA_LOWER_BOUND) && + (addr < KDR_RTC_DATA_UPPER_BOUND); +} + +/********************* START TXPOWER *****************************************/ +enum { + HT_IE_EXT_CHANNEL_NONE = 0, + HT_IE_EXT_CHANNEL_ABOVE, + HT_IE_EXT_CHANNEL_INVALID, + HT_IE_EXT_CHANNEL_BELOW, + HT_IE_EXT_CHANNEL_MAX +}; + +enum { + CALIB_CH_GROUP_1 = 0, + CALIB_CH_GROUP_2 = 1, + CALIB_CH_GROUP_3 = 2, + CALIB_CH_GROUP_4 = 3, + CALIB_CH_GROUP_5 = 4, + CALIB_CH_GROUP_MAX +}; + +/* Temperature calibration offset is 3% 0C in Kelvin */ +#define TEMPERATURE_CALIB_KELVIN_OFFSET 8 +#define TEMPERATURE_CALIB_A_VAL 259 + +#define IWL_TX_POWER_TEMPERATURE_MIN (263) +#define IWL_TX_POWER_TEMPERATURE_MAX (410) + +#define IWL_TX_POWER_TEMPERATURE_OUT_OF_RANGE(t) \ + (((t) < IWL_TX_POWER_TEMPERATURE_MIN) || \ + ((t) > IWL_TX_POWER_TEMPERATURE_MAX)) + +#define IWL_TX_POWER_ILLEGAL_TEMPERATURE (300) + +#define IWL_TX_POWER_TEMPERATURE_DIFFERENCE (2) + +#define IWL_TX_POWER_MIMO_REGULATORY_COMPENSATION (6) + +#define IWL_TX_POWER_TARGET_POWER_MIN (0) /* 0 dBm = 1 milliwatt */ +#define IWL_TX_POWER_TARGET_POWER_MAX (16) /* 16 dBm */ + +/* timeout equivalent to 3 minutes */ +#define IWL_TX_POWER_TIMELIMIT_NOCALIB 1800000000 + +#define IWL_TX_POWER_CCK_COMPENSATION (9) + +#define MIN_TX_GAIN_INDEX (0) +#define MIN_TX_GAIN_INDEX_52GHZ_EXT (-9) +#define MAX_TX_GAIN_INDEX_52GHZ (98) +#define MIN_TX_GAIN_52GHZ (98) +#define MAX_TX_GAIN_INDEX_24GHZ (98) +#define MIN_TX_GAIN_24GHZ (98) +#define MAX_TX_GAIN (0) +#define MAX_TX_GAIN_52GHZ_EXT (-9) + +#define IWL_TX_POWER_DEFAULT_REGULATORY_24 (34) +#define IWL_TX_POWER_DEFAULT_REGULATORY_52 (34) +#define IWL_TX_POWER_REGULATORY_MIN (0) +#define IWL_TX_POWER_REGULATORY_MAX (34) +#define IWL_TX_POWER_DEFAULT_SATURATION_24 (38) +#define IWL_TX_POWER_DEFAULT_SATURATION_52 (38) +#define IWL_TX_POWER_SATURATION_MIN (20) +#define IWL_TX_POWER_SATURATION_MAX (50) + +/* dv *0.4 = dt; so that 5 degrees temperature diff equals + * 12.5 in voltage diff */ +#define IWL_TX_TEMPERATURE_UPDATE_LIMIT 9 + +#define IWL_INVALID_CHANNEL (0xffffffff) +#define IWL_TX_POWER_REGITRY_BIT (2) + +#define MIN_IWL_TX_POWER_CALIB_DUR (100) +#define IWL_CCK_FROM_OFDM_POWER_DIFF (-5) +#define IWL_CCK_FROM_OFDM_INDEX_DIFF (9) + +/* Number of entries in the gain table */ +#define POWER_GAIN_NUM_ENTRIES 78 +#define TX_POW_MAX_SESSION_NUM 5 +/* timeout equivalent to 3 minutes */ +#define TX_IWL_TIMELIMIT_NOCALIB 1800000000 + +/* Kedron TX_CALIB_STATES */ +#define IWL_TX_CALIB_STATE_SEND_TX 0x00000001 +#define IWL_TX_CALIB_WAIT_TX_RESPONSE 0x00000002 +#define IWL_TX_CALIB_ENABLED 0x00000004 +#define IWL_TX_CALIB_XVT_ON 0x00000008 +#define IWL_TX_CALIB_TEMPERATURE_CORRECT 0x00000010 +#define IWL_TX_CALIB_WORKING_WITH_XVT 0x00000020 +#define IWL_TX_CALIB_XVT_PERIODICAL 0x00000040 + +#define NUM_IWL_TX_CALIB_SETTINS 5 /* Number of tx correction groups */ + +#define IWL_MIN_POWER_IN_VP_TABLE 1 /* 0.5dBm multiplied by 2 */ +#define IWL_MAX_POWER_IN_VP_TABLE 40 /* 20dBm - multiplied by 2 (because + * entries are for each 0.5dBm) */ +#define IWL_STEP_IN_VP_TABLE 1 /* 0.5dB - multiplied by 2 */ +#define IWL_NUM_POINTS_IN_VPTABLE \ + (1 + IWL_MAX_POWER_IN_VP_TABLE - IWL_MIN_POWER_IN_VP_TABLE) + +#define MIN_TX_GAIN_INDEX (0) +#define MAX_TX_GAIN_INDEX_52GHZ (98) +#define MIN_TX_GAIN_52GHZ (98) +#define MAX_TX_GAIN_INDEX_24GHZ (98) +#define MIN_TX_GAIN_24GHZ (98) +#define MAX_TX_GAIN (0) + +/* First and last channels of all groups */ +#define CALIB_IWL_TX_ATTEN_GR1_FCH 34 +#define CALIB_IWL_TX_ATTEN_GR1_LCH 43 +#define CALIB_IWL_TX_ATTEN_GR2_FCH 44 +#define CALIB_IWL_TX_ATTEN_GR2_LCH 70 +#define CALIB_IWL_TX_ATTEN_GR3_FCH 71 +#define CALIB_IWL_TX_ATTEN_GR3_LCH 124 +#define CALIB_IWL_TX_ATTEN_GR4_FCH 125 +#define CALIB_IWL_TX_ATTEN_GR4_LCH 200 +#define CALIB_IWL_TX_ATTEN_GR5_FCH 1 +#define CALIB_IWL_TX_ATTEN_GR5_LCH 20 + + +union iwl_tx_power_dual_stream { + struct { + u8 radio_tx_gain[2]; + u8 dsp_predis_atten[2]; + } s; + u32 dw; +}; + +/********************* END TXPOWER *****************************************/ + +/* HT flags */ +#define RXON_FLG_CTRL_CHANNEL_LOC_POS (22) +#define RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK __constant_cpu_to_le32(0x1<<22) + +#define RXON_FLG_HT_OPERATING_MODE_POS (23) + +#define RXON_FLG_HT_PROT_MSK __constant_cpu_to_le32(0x1<<23) +#define RXON_FLG_FAT_PROT_MSK __constant_cpu_to_le32(0x2<<23) + +#define RXON_FLG_CHANNEL_MODE_POS (25) +#define RXON_FLG_CHANNEL_MODE_MSK __constant_cpu_to_le32(0x3<<25) +#define RXON_FLG_CHANNEL_MODE_PURE_40_MSK __constant_cpu_to_le32(0x1<<25) +#define RXON_FLG_CHANNEL_MODE_MIXED_MSK __constant_cpu_to_le32(0x2<<25) + +#define RXON_RX_CHAIN_DRIVER_FORCE_MSK __constant_cpu_to_le16(0x1<<0) +#define RXON_RX_CHAIN_VALID_MSK __constant_cpu_to_le16(0x7<<1) +#define RXON_RX_CHAIN_VALID_POS (1) +#define RXON_RX_CHAIN_FORCE_SEL_MSK __constant_cpu_to_le16(0x7<<4) +#define RXON_RX_CHAIN_FORCE_SEL_POS (4) +#define RXON_RX_CHAIN_FORCE_MIMO_SEL_MSK __constant_cpu_to_le16(0x7<<7) +#define RXON_RX_CHAIN_FORCE_MIMO_SEL_POS (7) +#define RXON_RX_CHAIN_CNT_MSK __constant_cpu_to_le16(0x3<<10) +#define RXON_RX_CHAIN_CNT_POS (10) +#define RXON_RX_CHAIN_MIMO_CNT_MSK __constant_cpu_to_le16(0x3<<12) +#define RXON_RX_CHAIN_MIMO_CNT_POS (12) +#define RXON_RX_CHAIN_MIMO_FORCE_MSK __constant_cpu_to_le16(0x1<<14) +#define RXON_RX_CHAIN_MIMO_FORCE_POS (14) + + +#define MCS_DUP_6M_PLCP 0x20 + +/* OFDM HT rate masks */ +/* ***************************************** */ +#define R_MCS_6M_MSK 0x1 +#define R_MCS_12M_MSK 0x2 +#define R_MCS_18M_MSK 0x4 +#define R_MCS_24M_MSK 0x8 +#define R_MCS_36M_MSK 0x10 +#define R_MCS_48M_MSK 0x20 +#define R_MCS_54M_MSK 0x40 +#define R_MCS_60M_MSK 0x80 +#define R_MCS_12M_DUAL_MSK 0x100 +#define R_MCS_24M_DUAL_MSK 0x200 +#define R_MCS_36M_DUAL_MSK 0x400 +#define R_MCS_48M_DUAL_MSK 0x800 + +#define is_legacy(tbl) (((tbl) == LQ_G) || ((tbl) == LQ_A)) +#define is_siso(tbl) (((tbl) == LQ_SISO)) +#define is_mimo(tbl) (((tbl) == LQ_MIMO)) +#define is_Ht(tbl) (is_siso(tbl) || is_mimo(tbl)) +#define is_a_band(tbl) (((tbl) == LQ_A)) +#define is_g_and(tbl) (((tbl) == LQ_G)) + +/* Flow Handler Definitions */ + +/**********************/ +/* Addresses */ +/**********************/ + +#define FH_MEM_LOWER_BOUND (0x1000) +#define FH_MEM_UPPER_BOUND (0x1EF0) + +#define IWL_FH_REGS_LOWER_BOUND (0x1000) +#define IWL_FH_REGS_UPPER_BOUND (0x2000) + +#define IWL_FH_KW_MEM_ADDR_REG (FH_MEM_LOWER_BOUND + 0x97C) + +/* CBBC Area - Circular buffers base address cache pointers table */ +#define FH_MEM_CBBC_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0x9D0) +#define FH_MEM_CBBC_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xA10) +/* queues 0 - 15 */ +#define FH_MEM_CBBC_QUEUE(x) (FH_MEM_CBBC_LOWER_BOUND + (x) * 0x4) + +/* RSCSR Area */ +#define FH_MEM_RSCSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xBC0) +#define FH_MEM_RSCSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xC00) +#define FH_MEM_RSCSR_CHNL0 (FH_MEM_RSCSR_LOWER_BOUND) + +#define FH_RSCSR_CHNL0_STTS_WPTR_REG (FH_MEM_RSCSR_CHNL0) +#define FH_RSCSR_CHNL0_RBDCB_BASE_REG (FH_MEM_RSCSR_CHNL0 + 0x004) +#define FH_RSCSR_CHNL0_RBDCB_WPTR_REG (FH_MEM_RSCSR_CHNL0 + 0x008) + +/* RCSR Area - Registers address map */ +#define FH_MEM_RCSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xC00) +#define FH_MEM_RCSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xCC0) +#define FH_MEM_RCSR_CHNL0 (FH_MEM_RCSR_LOWER_BOUND) + +#define FH_MEM_RCSR_CHNL0_CONFIG_REG (FH_MEM_RCSR_CHNL0) + +/* RSSR Area - Rx shared ctrl & status registers */ +#define FH_MEM_RSSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xC40) +#define FH_MEM_RSSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xD00) +#define FH_MEM_RSSR_SHARED_CTRL_REG (FH_MEM_RSSR_LOWER_BOUND) +#define FH_MEM_RSSR_RX_STATUS_REG (FH_MEM_RSSR_LOWER_BOUND + 0x004) +#define FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV (FH_MEM_RSSR_LOWER_BOUND + 0x008) + +/* TCSR */ +#define IWL_FH_TCSR_LOWER_BOUND (IWL_FH_REGS_LOWER_BOUND + 0xD00) +#define IWL_FH_TCSR_UPPER_BOUND (IWL_FH_REGS_LOWER_BOUND + 0xE60) + +#define IWL_FH_TCSR_CHNL_NUM (7) +#define IWL_FH_TCSR_CHNL_TX_CONFIG_REG(_chnl) \ + (IWL_FH_TCSR_LOWER_BOUND + 0x20 * _chnl) + +/* TSSR Area - Tx shared status registers */ +/* TSSR */ +#define IWL_FH_TSSR_LOWER_BOUND (IWL_FH_REGS_LOWER_BOUND + 0xEA0) +#define IWL_FH_TSSR_UPPER_BOUND (IWL_FH_REGS_LOWER_BOUND + 0xEC0) + +#define IWL_FH_TSSR_TX_MSG_CONFIG_REG (IWL_FH_TSSR_LOWER_BOUND + 0x008) +#define IWL_FH_TSSR_TX_STATUS_REG (IWL_FH_TSSR_LOWER_BOUND + 0x010) + +#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TXPD_ON (0xFF000000) +#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_TXPD_ON (0x00FF0000) + +#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_64B (0x00000000) +#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_128B (0x00000400) +#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_256B (0x00000800) +#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_512B (0x00000C00) + +#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TFD_ON (0x00000100) +#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_CBB_ON (0x00000080) + +#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RSP_WAIT_TH (0x00000020) +#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_RSP_WAIT_TH (0x00000005) + +#define IWL_FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) \ + ((1 << (_chnl)) << 24) +#define IWL_FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl) \ + ((1 << (_chnl)) << 16) + +#define IWL_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(_chnl) \ + (IWL_FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) | \ + IWL_FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl)) + +/* TCSR: tx_config register values */ +#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_TXF (0x00000000) +#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_DRIVER (0x00000001) +#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_ARC (0x00000002) + +#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL (0x00000000) +#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL (0x00000008) + +#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_NOINT (0x00000000) +#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD (0x00100000) +#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD (0x00200000) + +#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_NOINT (0x00000000) +#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_ENDTFD (0x00400000) +#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_IFTFD (0x00800000) + +#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE (0x00000000) +#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE_EOF (0x40000000) +#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE (0x80000000) + +#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_EMPTY (0x00000000) +#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_WAIT (0x00002000) +#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID (0x00000003) + +#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_BIT_TFDB_WPTR (0x00000001) + +#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM (20) +#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX (12) + +/* RCSR: channel 0 rx_config register defines */ +#define FH_RCSR_CHNL0_RX_CONFIG_DMA_CHNL_EN_MASK (0xC0000000) /* bits 30-31 */ +#define FH_RCSR_CHNL0_RX_CONFIG_RBDBC_SIZE_MASK (0x00F00000) /* bits 20-23 */ +#define FH_RCSR_CHNL0_RX_CONFIG_RB_SIZE_MASK (0x00030000) /* bits 16-17 */ +#define FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME_MASK (0x00008000) /* bit 15 */ +#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_MASK (0x00001000) /* bit 12 */ +#define FH_RCSR_CHNL0_RX_CONFIG_RB_TIMEOUT_MASK (0x00000FF0) /* bit 4-11 */ + +#define FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT (20) +#define FH_RCSR_RX_CONFIG_RB_SIZE_BITSHIFT (16) + +/* RCSR: rx_config register values */ +#define FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_VAL (0x00000000) +#define FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_EOF_VAL (0x40000000) +#define FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL (0x80000000) + +#define IWL_FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K (0x00000000) + +/* RCSR channel 0 config register values */ +#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_NO_INT_VAL (0x00000000) +#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL (0x00001000) + +/* RSCSR: defs used in normal mode */ +#define FH_RSCSR_CHNL0_RBDCB_WPTR_MASK (0x00000FFF) /* bits 0-11 */ + +#define SCD_WIN_SIZE 64 +#define SCD_FRAME_LIMIT 64 + +/* memory mapped registers */ +#define SCD_START_OFFSET 0xa02c00 + +#define SCD_SRAM_BASE_ADDR (SCD_START_OFFSET + 0x0) +#define SCD_EMPTY_BITS (SCD_START_OFFSET + 0x4) +#define SCD_DRAM_BASE_ADDR (SCD_START_OFFSET + 0x10) +#define SCD_AIT (SCD_START_OFFSET + 0x18) +#define SCD_TXFACT (SCD_START_OFFSET + 0x1c) +#define SCD_QUEUE_WRPTR(x) (SCD_START_OFFSET + 0x24 + (x) * 4) +#define SCD_QUEUE_RDPTR(x) (SCD_START_OFFSET + 0x64 + (x) * 4) +#define SCD_SETQUEUENUM (SCD_START_OFFSET + 0xa4) +#define SCD_SET_TXSTAT_TXED (SCD_START_OFFSET + 0xa8) +#define SCD_SET_TXSTAT_DONE (SCD_START_OFFSET + 0xac) +#define SCD_SET_TXSTAT_NOT_SCHD (SCD_START_OFFSET + 0xb0) +#define SCD_DECREASE_CREDIT (SCD_START_OFFSET + 0xb4) +#define SCD_DECREASE_SCREDIT (SCD_START_OFFSET + 0xb8) +#define SCD_LOAD_CREDIT (SCD_START_OFFSET + 0xbc) +#define SCD_LOAD_SCREDIT (SCD_START_OFFSET + 0xc0) +#define SCD_BAR (SCD_START_OFFSET + 0xc4) +#define SCD_BAR_DW0 (SCD_START_OFFSET + 0xc8) +#define SCD_BAR_DW1 (SCD_START_OFFSET + 0xcc) +#define SCD_QUEUECHAIN_SEL (SCD_START_OFFSET + 0xd0) +#define SCD_QUERY_REQ (SCD_START_OFFSET + 0xd8) +#define SCD_QUERY_RES (SCD_START_OFFSET + 0xdc) +#define SCD_PENDING_FRAMES (SCD_START_OFFSET + 0xe0) +#define SCD_INTERRUPT_MASK (SCD_START_OFFSET + 0xe4) +#define SCD_INTERRUPT_THRESHOLD (SCD_START_OFFSET + 0xe8) +#define SCD_QUERY_MIN_FRAME_SIZE (SCD_START_OFFSET + 0x100) +#define SCD_QUEUE_STATUS_BITS(x) (SCD_START_OFFSET + 0x104 + (x) * 4) + +/* SRAM structures */ +#define SCD_CONTEXT_DATA_OFFSET 0x380 +#define SCD_TX_STTS_BITMAP_OFFSET 0x400 +#define SCD_TRANSLATE_TBL_OFFSET 0x500 +#define SCD_CONTEXT_QUEUE_OFFSET(x) (SCD_CONTEXT_DATA_OFFSET + ((x) * 8)) +#define SCD_TRANSLATE_TBL_OFFSET_QUEUE(x) \ + ((SCD_TRANSLATE_TBL_OFFSET + ((x) * 2)) & 0xfffffffc) + +#define SCD_TXFACT_REG_TXFIFO_MASK(lo, hi) \ + ((1<<(hi))|((1<<(hi))-(1<<(lo)))) + + +#define SCD_MODE_REG_BIT_SEARCH_MODE (1<<0) +#define SCD_MODE_REG_BIT_SBYP_MODE (1<<1) + +#define SCD_TXFIFO_POS_TID (0) +#define SCD_TXFIFO_POS_RA (4) +#define SCD_QUEUE_STTS_REG_POS_ACTIVE (0) +#define SCD_QUEUE_STTS_REG_POS_TXF (1) +#define SCD_QUEUE_STTS_REG_POS_WSL (5) +#define SCD_QUEUE_STTS_REG_POS_SCD_ACK (8) +#define SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN (10) +#define SCD_QUEUE_STTS_REG_MSK (0x0007FC00) + +#define SCD_QUEUE_RA_TID_MAP_RATID_MSK (0x01FF) + +#define SCD_QUEUE_CTX_REG1_WIN_SIZE_POS (0) +#define SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK (0x0000007F) +#define SCD_QUEUE_CTX_REG1_CREDIT_POS (8) +#define SCD_QUEUE_CTX_REG1_CREDIT_MSK (0x00FFFF00) +#define SCD_QUEUE_CTX_REG1_SUPER_CREDIT_POS (24) +#define SCD_QUEUE_CTX_REG1_SUPER_CREDIT_MSK (0xFF000000) +#define SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS (16) +#define SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK (0x007F0000) + +#define CSR_HW_IF_CONFIG_REG_BIT_KEDRON_R (0x00000010) +#define CSR_HW_IF_CONFIG_REG_MSK_BOARD_VER (0x00000C00) +#define CSR_HW_IF_CONFIG_REG_BIT_MAC_SI (0x00000100) +#define CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI (0x00000200) + +static inline u8 iwl_hw_get_rate(__le32 rate_n_flags) +{ + return le32_to_cpu(rate_n_flags) & 0xFF; +} +static inline u16 iwl_hw_get_rate_n_flags(__le32 rate_n_flags) +{ + return le32_to_cpu(rate_n_flags) & 0xFFFF; +} +static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u16 flags) +{ + return cpu_to_le32(flags|(u16)rate); +} + +struct iwl_tfd_frame_data { + __le32 tb1_addr; + + __le32 val1; + /* __le32 ptb1_32_35:4; */ +#define IWL_tb1_addr_hi_POS 0 +#define IWL_tb1_addr_hi_LEN 4 +#define IWL_tb1_addr_hi_SYM val1 + /* __le32 tb_len1:12; */ +#define IWL_tb1_len_POS 4 +#define IWL_tb1_len_LEN 12 +#define IWL_tb1_len_SYM val1 + /* __le32 ptb2_0_15:16; */ +#define IWL_tb2_addr_lo16_POS 16 +#define IWL_tb2_addr_lo16_LEN 16 +#define IWL_tb2_addr_lo16_SYM val1 + + __le32 val2; + /* __le32 ptb2_16_35:20; */ +#define IWL_tb2_addr_hi20_POS 0 +#define IWL_tb2_addr_hi20_LEN 20 +#define IWL_tb2_addr_hi20_SYM val2 + /* __le32 tb_len2:12; */ +#define IWL_tb2_len_POS 20 +#define IWL_tb2_len_LEN 12 +#define IWL_tb2_len_SYM val2 +} __attribute__ ((packed)); + +struct iwl_tfd_frame { + __le32 val0; + /* __le32 rsvd1:24; */ + /* __le32 num_tbs:5; */ +#define IWL_num_tbs_POS 24 +#define IWL_num_tbs_LEN 5 +#define IWL_num_tbs_SYM val0 + /* __le32 rsvd2:1; */ + /* __le32 padding:2; */ + struct iwl_tfd_frame_data pa[10]; + __le32 reserved; +} __attribute__ ((packed)); + +#define IWL4965_MAX_WIN_SIZE 64 +#define IWL4965_QUEUE_SIZE 256 +#define IWL4965_NUM_FIFOS 7 +#define IWL_MAX_NUM_QUEUES 16 + +struct iwl4965_queue_byte_cnt_entry { + __le16 val; + /* __le16 byte_cnt:12; */ +#define IWL_byte_cnt_POS 0 +#define IWL_byte_cnt_LEN 12 +#define IWL_byte_cnt_SYM val + /* __le16 rsvd:4; */ +} __attribute__ ((packed)); + +struct iwl4965_sched_queue_byte_cnt_tbl { + struct iwl4965_queue_byte_cnt_entry tfd_offset[IWL4965_QUEUE_SIZE + + IWL4965_MAX_WIN_SIZE]; + u8 dont_care[1024 - + (IWL4965_QUEUE_SIZE + IWL4965_MAX_WIN_SIZE) * + sizeof(__le16)]; +} __attribute__ ((packed)); + +/* Base physical address of iwl_shared is provided to SCD_DRAM_BASE_ADDR + * and &iwl_shared.val0 is provided to FH_RSCSR_CHNL0_STTS_WPTR_REG */ +struct iwl_shared { + struct iwl4965_sched_queue_byte_cnt_tbl + queues_byte_cnt_tbls[IWL_MAX_NUM_QUEUES]; + __le32 val0; + + /* __le32 rb_closed_stts_rb_num:12; */ +#define IWL_rb_closed_stts_rb_num_POS 0 +#define IWL_rb_closed_stts_rb_num_LEN 12 +#define IWL_rb_closed_stts_rb_num_SYM val0 + /* __le32 rsrv1:4; */ + /* __le32 rb_closed_stts_rx_frame_num:12; */ +#define IWL_rb_closed_stts_rx_frame_num_POS 16 +#define IWL_rb_closed_stts_rx_frame_num_LEN 12 +#define IWL_rb_closed_stts_rx_frame_num_SYM val0 + /* __le32 rsrv2:4; */ + + __le32 val1; + /* __le32 frame_finished_stts_rb_num:12; */ +#define IWL_frame_finished_stts_rb_num_POS 0 +#define IWL_frame_finished_stts_rb_num_LEN 12 +#define IWL_frame_finished_stts_rb_num_SYM val1 + /* __le32 rsrv3:4; */ + /* __le32 frame_finished_stts_rx_frame_num:12; */ +#define IWL_frame_finished_stts_rx_frame_num_POS 16 +#define IWL_frame_finished_stts_rx_frame_num_LEN 12 +#define IWL_frame_finished_stts_rx_frame_num_SYM val1 + /* __le32 rsrv4:4; */ + + __le32 padding1; /* so that allocation will be aligned to 16B */ + __le32 padding2; +} __attribute__ ((packed)); + +#endif /* __iwl_4965_hw_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c new file mode 100644 index 00000000000..f3638607d64 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -0,0 +1,2118 @@ +/****************************************************************************** + * + * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#include "../net/mac80211/ieee80211_rate.h" + +#include "iwlwifi.h" +#include "iwl-helpers.h" + +#define RS_NAME "iwl-4965-rs" + +#define NUM_TRY_BEFORE_ANTENNA_TOGGLE 1 +#define IWL_NUMBER_TRY 1 +#define IWL_HT_NUMBER_TRY 3 + +#define IWL_RATE_MAX_WINDOW 62 +#define IWL_RATE_HIGH_TH 10880 +#define IWL_RATE_MIN_FAILURE_TH 6 +#define IWL_RATE_MIN_SUCCESS_TH 8 +#define IWL_RATE_DECREASE_TH 1920 +#define IWL_RATE_INCREASE_TH 8960 +#define IWL_RATE_SCALE_FLUSH_INTVL (2*HZ) /*2 seconds */ + +static u8 rs_ht_to_legacy[] = { + IWL_RATE_6M_INDEX, IWL_RATE_6M_INDEX, + IWL_RATE_6M_INDEX, IWL_RATE_6M_INDEX, + IWL_RATE_6M_INDEX, + IWL_RATE_6M_INDEX, IWL_RATE_9M_INDEX, + IWL_RATE_12M_INDEX, IWL_RATE_18M_INDEX, + IWL_RATE_24M_INDEX, IWL_RATE_36M_INDEX, + IWL_RATE_48M_INDEX, IWL_RATE_54M_INDEX +}; + +struct iwl_rate { + u32 rate_n_flags; +} __attribute__ ((packed)); + +struct iwl_rate_scale_data { + u64 data; + s32 success_counter; + s32 success_ratio; + s32 counter; + s32 average_tpt; + unsigned long stamp; +}; + +struct iwl_scale_tbl_info { + enum iwl_table_type lq_type; + enum iwl_antenna_type antenna_type; + u8 is_SGI; + u8 is_fat; + u8 is_dup; + u8 action; + s32 *expected_tpt; + struct iwl_rate current_rate; + struct iwl_rate_scale_data win[IWL_RATE_COUNT]; +}; + +struct iwl_rate_scale_priv { + u8 active_tbl; + u8 enable_counter; + u8 stay_in_tbl; + u8 search_better_tbl; + s32 last_tpt; + u32 table_count_limit; + u32 max_failure_limit; + u32 max_success_limit; + u32 table_count; + u32 total_failed; + u32 total_success; + u32 flush_timer; + u8 action_counter; + u8 antenna; + u8 valid_antenna; + u8 is_green; + u8 is_dup; + u8 phymode; + u8 ibss_sta_added; + u16 active_rate; + u16 active_siso_rate; + u16 active_mimo_rate; + u16 active_rate_basic; + struct iwl_link_quality_cmd lq; + struct iwl_scale_tbl_info lq_info[LQ_SIZE]; +}; + +static void rs_rate_scale_perform(struct iwl_priv *priv, + struct net_device *dev, + struct ieee80211_hdr *hdr, + struct sta_info *sta); +static int rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data, + struct iwl_rate *tx_mcs, + struct iwl_link_quality_cmd *tbl, + struct sta_info *sta); + + +static s32 expected_tpt_A[IWL_RATE_COUNT] = { + 0, 0, 0, 0, 40, 57, 72, 98, 121, 154, 177, 186, 186 +}; + +static s32 expected_tpt_G[IWL_RATE_COUNT] = { + 7, 13, 35, 58, 40, 57, 72, 98, 121, 154, 177, 186, 186 +}; + +static s32 expected_tpt_siso20MHz[IWL_RATE_COUNT] = { + 0, 0, 0, 0, 42, 42, 76, 102, 124, 159, 183, 193, 202 +}; + +static s32 expected_tpt_siso20MHzSGI[IWL_RATE_COUNT] = { + 0, 0, 0, 0, 46, 46, 82, 110, 132, 168, 192, 202, 211 +}; + +static s32 expected_tpt_mimo20MHz[IWL_RATE_COUNT] = { + 0, 0, 0, 0, 74, 74, 123, 155, 179, 214, 236, 244, 251 +}; + +static s32 expected_tpt_mimo20MHzSGI[IWL_RATE_COUNT] = { + 0, 0, 0, 0, 81, 81, 131, 164, 188, 222, 243, 251, 257 +}; + +static s32 expected_tpt_siso40MHz[IWL_RATE_COUNT] = { + 0, 0, 0, 0, 77, 77, 127, 160, 184, 220, 242, 250, 257 +}; + +static s32 expected_tpt_siso40MHzSGI[IWL_RATE_COUNT] = { + 0, 0, 0, 0, 83, 83, 135, 169, 193, 229, 250, 257, 264 +}; + +static s32 expected_tpt_mimo40MHz[IWL_RATE_COUNT] = { + 0, 0, 0, 0, 123, 123, 182, 214, 235, 264, 279, 285, 289 +}; + +static s32 expected_tpt_mimo40MHzSGI[IWL_RATE_COUNT] = { + 0, 0, 0, 0, 131, 131, 191, 222, 242, 270, 284, 289, 293 +}; + +static int iwl_lq_sync_callback(struct iwl_priv *priv, + struct iwl_cmd *cmd, struct sk_buff *skb) +{ + /*We didn't cache the SKB; let the caller free it */ + return 1; +} + +static inline u8 iwl_rate_get_rate(u32 rate_n_flags) +{ + return (u8)(rate_n_flags & 0xFF); +} + +static int rs_send_lq_cmd(struct iwl_priv *priv, + struct iwl_link_quality_cmd *lq, u8 flags) +{ +#ifdef CONFIG_IWLWIFI_DEBUG + int i; +#endif + int rc = -1; + + struct iwl_host_cmd cmd = { + .id = REPLY_TX_LINK_QUALITY_CMD, + .len = sizeof(struct iwl_link_quality_cmd), + .meta.flags = flags, + .data = lq, + }; + + if ((lq->sta_id == 0xFF) && + (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)) + return rc; + + if (lq->sta_id == 0xFF) + lq->sta_id = IWL_AP_ID; + + IWL_DEBUG_RATE("lq station id 0x%x\n", lq->sta_id); + IWL_DEBUG_RATE("lq dta 0x%X 0x%X\n", + lq->general_params.single_stream_ant_msk, + lq->general_params.dual_stream_ant_msk); +#ifdef CONFIG_IWLWIFI_DEBUG + for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) + IWL_DEBUG_RATE("lq index %d 0x%X\n", + i, lq->rs_table[i].rate_n_flags); +#endif + + if (flags & CMD_ASYNC) + cmd.meta.u.callback = iwl_lq_sync_callback; + + if (iwl_is_associated(priv) && priv->assoc_station_added && + priv->lq_mngr.lq_ready) + rc = iwl_send_cmd(priv, &cmd); + + return rc; +} + +static int rs_rate_scale_clear_window(struct iwl_rate_scale_data *window) +{ + window->data = 0; + window->success_counter = 0; + window->success_ratio = IWL_INVALID_VALUE; + window->counter = 0; + window->average_tpt = IWL_INVALID_VALUE; + window->stamp = 0; + + return 0; +} + +static int rs_collect_tx_data(struct iwl_rate_scale_data *windows, + int scale_index, s32 tpt, u32 status) +{ + int rc = 0; + struct iwl_rate_scale_data *window = NULL; + u64 mask; + u8 win_size = IWL_RATE_MAX_WINDOW; + s32 fail_count; + + if (scale_index < 0) + return -1; + + if (scale_index >= IWL_RATE_COUNT) + return -1; + + window = &(windows[scale_index]); + + if (window->counter >= win_size) { + + window->counter = win_size - 1; + mask = 1; + mask = (mask << (win_size - 1)); + if ((window->data & mask)) { + window->data &= ~mask; + window->success_counter = window->success_counter - 1; + } + } + + window->counter = window->counter + 1; + mask = window->data; + window->data = (mask << 1); + if (status != 0) { + window->success_counter = window->success_counter + 1; + window->data |= 0x1; + } + + if (window->counter > 0) + window->success_ratio = 128 * (100 * window->success_counter) + / window->counter; + else + window->success_ratio = IWL_INVALID_VALUE; + + fail_count = window->counter - window->success_counter; + + if ((fail_count >= IWL_RATE_MIN_FAILURE_TH) || + (window->success_counter >= IWL_RATE_MIN_SUCCESS_TH)) + window->average_tpt = (window->success_ratio * tpt + 64) / 128; + else + window->average_tpt = IWL_INVALID_VALUE; + + window->stamp = jiffies; + + return rc; +} + +int static rs_mcs_from_tbl(struct iwl_rate *mcs_rate, + struct iwl_scale_tbl_info *tbl, + int index, u8 use_green) +{ + int rc = 0; + + if (is_legacy(tbl->lq_type)) { + mcs_rate->rate_n_flags = iwl_rates[index].plcp; + if (index >= IWL_FIRST_CCK_RATE && index <= IWL_LAST_CCK_RATE) + mcs_rate->rate_n_flags |= RATE_MCS_CCK_MSK; + + } else if (is_siso(tbl->lq_type)) { + if (index > IWL_LAST_OFDM_RATE) + index = IWL_LAST_OFDM_RATE; + mcs_rate->rate_n_flags = iwl_rates[index].plcp_siso | + RATE_MCS_HT_MSK; + } else { + if (index > IWL_LAST_OFDM_RATE) + index = IWL_LAST_OFDM_RATE; + mcs_rate->rate_n_flags = iwl_rates[index].plcp_mimo | + RATE_MCS_HT_MSK; + } + + switch (tbl->antenna_type) { + case ANT_BOTH: + mcs_rate->rate_n_flags |= RATE_MCS_ANT_AB_MSK; + break; + case ANT_MAIN: + mcs_rate->rate_n_flags |= RATE_MCS_ANT_A_MSK; + break; + case ANT_AUX: + mcs_rate->rate_n_flags |= RATE_MCS_ANT_B_MSK; + break; + case ANT_NONE: + break; + } + + if (is_legacy(tbl->lq_type)) + return rc; + + if (tbl->is_fat) { + if (tbl->is_dup) + mcs_rate->rate_n_flags |= RATE_MCS_DUP_MSK; + else + mcs_rate->rate_n_flags |= RATE_MCS_FAT_MSK; + } + if (tbl->is_SGI) + mcs_rate->rate_n_flags |= RATE_MCS_SGI_MSK; + + if (use_green) { + mcs_rate->rate_n_flags |= RATE_MCS_GF_MSK; + if (is_siso(tbl->lq_type)) + mcs_rate->rate_n_flags &= ~RATE_MCS_SGI_MSK; + } + return rc; +} + +static int rs_get_tbl_info_from_mcs(const struct iwl_rate *mcs_rate, + int phymode, struct iwl_scale_tbl_info *tbl, + int *rate_idx) +{ + int index; + u32 ant_msk; + + index = iwl_rate_index_from_plcp(mcs_rate->rate_n_flags); + + if (index == IWL_RATE_INVALID) { + *rate_idx = -1; + return -1; + } + tbl->is_SGI = 0; + tbl->is_fat = 0; + tbl->is_dup = 0; + tbl->antenna_type = ANT_BOTH; + + if (!(mcs_rate->rate_n_flags & RATE_MCS_HT_MSK)) { + ant_msk = (mcs_rate->rate_n_flags & RATE_MCS_ANT_AB_MSK); + + if (ant_msk == RATE_MCS_ANT_AB_MSK) + tbl->lq_type = LQ_NONE; + else { + + if (phymode == MODE_IEEE80211A) + tbl->lq_type = LQ_A; + else + tbl->lq_type = LQ_G; + + if (mcs_rate->rate_n_flags & RATE_MCS_ANT_A_MSK) + tbl->antenna_type = ANT_MAIN; + else + tbl->antenna_type = ANT_AUX; + } + *rate_idx = index; + + } else if (iwl_rate_get_rate(mcs_rate->rate_n_flags) + <= IWL_RATE_SISO_60M_PLCP) { + tbl->lq_type = LQ_SISO; + + ant_msk = (mcs_rate->rate_n_flags & RATE_MCS_ANT_AB_MSK); + if (ant_msk == RATE_MCS_ANT_AB_MSK) + tbl->lq_type = LQ_NONE; + else { + if (mcs_rate->rate_n_flags & RATE_MCS_ANT_A_MSK) + tbl->antenna_type = ANT_MAIN; + else + tbl->antenna_type = ANT_AUX; + } + if (mcs_rate->rate_n_flags & RATE_MCS_SGI_MSK) + tbl->is_SGI = 1; + + if ((mcs_rate->rate_n_flags & RATE_MCS_FAT_MSK) || + (mcs_rate->rate_n_flags & RATE_MCS_DUP_MSK)) + tbl->is_fat = 1; + + if (mcs_rate->rate_n_flags & RATE_MCS_DUP_MSK) + tbl->is_dup = 1; + + *rate_idx = index; + } else { + tbl->lq_type = LQ_MIMO; + if (mcs_rate->rate_n_flags & RATE_MCS_SGI_MSK) + tbl->is_SGI = 1; + + if ((mcs_rate->rate_n_flags & RATE_MCS_FAT_MSK) || + (mcs_rate->rate_n_flags & RATE_MCS_DUP_MSK)) + tbl->is_fat = 1; + + if (mcs_rate->rate_n_flags & RATE_MCS_DUP_MSK) + tbl->is_dup = 1; + *rate_idx = index; + } + return 0; +} + +static inline void rs_toggle_antenna(struct iwl_rate *new_rate, + struct iwl_scale_tbl_info *tbl) +{ + if (tbl->antenna_type == ANT_AUX) { + tbl->antenna_type = ANT_MAIN; + new_rate->rate_n_flags &= ~RATE_MCS_ANT_B_MSK; + new_rate->rate_n_flags |= RATE_MCS_ANT_A_MSK; + } else { + tbl->antenna_type = ANT_AUX; + new_rate->rate_n_flags &= ~RATE_MCS_ANT_A_MSK; + new_rate->rate_n_flags |= RATE_MCS_ANT_B_MSK; + } +} + +static inline s8 rs_use_green(struct iwl_priv *priv) +{ + s8 rc = 0; +#ifdef CONFIG_IWLWIFI_HT + if (!priv->is_ht_enabled || !priv->current_assoc_ht.is_ht) + return 0; + + if ((priv->current_assoc_ht.is_green_field) && + !(priv->current_assoc_ht.operating_mode & 0x4)) + rc = 1; +#endif /*CONFIG_IWLWIFI_HT */ + return rc; +} + +/** + * rs_get_supported_rates - get the available rates + * + * if management frame or broadcast frame only return + * basic available rates. + * + */ +static void rs_get_supported_rates(struct iwl_rate_scale_priv *lq_data, + struct ieee80211_hdr *hdr, + enum iwl_table_type rate_type, + u16 *data_rate) +{ + if (is_legacy(rate_type)) + *data_rate = lq_data->active_rate; + else { + if (is_siso(rate_type)) + *data_rate = lq_data->active_siso_rate; + else + *data_rate = lq_data->active_mimo_rate; + } + + if (hdr && is_multicast_ether_addr(hdr->addr1) && + lq_data->active_rate_basic) + *data_rate = lq_data->active_rate_basic; +} + +static u16 rs_get_adjacent_rate(u8 index, u16 rate_mask, int rate_type) +{ + u8 high = IWL_RATE_INVALID; + u8 low = IWL_RATE_INVALID; + + /* 802.11A or ht walks to the next literal adjascent rate in + * the rate table */ + if (is_a_band(rate_type) || !is_legacy(rate_type)) { + int i; + u32 mask; + + /* Find the previous rate that is in the rate mask */ + i = index - 1; + for (mask = (1 << i); i >= 0; i--, mask >>= 1) { + if (rate_mask & mask) { + low = i; + break; + } + } + + /* Find the next rate that is in the rate mask */ + i = index + 1; + for (mask = (1 << i); i < IWL_RATE_COUNT; i++, mask <<= 1) { + if (rate_mask & mask) { + high = i; + break; + } + } + + return (high << 8) | low; + } + + low = index; + while (low != IWL_RATE_INVALID) { + low = iwl_rates[low].prev_rs; + if (low == IWL_RATE_INVALID) + break; + if (rate_mask & (1 << low)) + break; + IWL_DEBUG_RATE("Skipping masked lower rate: %d\n", low); + } + + high = index; + while (high != IWL_RATE_INVALID) { + high = iwl_rates[high].next_rs; + if (high == IWL_RATE_INVALID) + break; + if (rate_mask & (1 << high)) + break; + IWL_DEBUG_RATE("Skipping masked higher rate: %d\n", high); + } + + return (high << 8) | low; +} + +static int rs_get_lower_rate(struct iwl_rate_scale_priv *lq_data, + struct iwl_scale_tbl_info *tbl, u8 scale_index, + u8 ht_possible, struct iwl_rate *mcs_rate, + struct sta_info *sta) +{ + u8 is_green = lq_data->is_green; + s32 low; + u16 rate_mask; + u16 high_low; + u8 switch_to_legacy = 0; + + /* check if we need to switch from HT to legacy rates. + * assumption is that mandatory rates (1Mbps or 6Mbps) + * are always supported (spec demand) */ + if (!is_legacy(tbl->lq_type) && (!ht_possible || !scale_index)) { + switch_to_legacy = 1; + scale_index = rs_ht_to_legacy[scale_index]; + if (lq_data->phymode == MODE_IEEE80211A) + tbl->lq_type = LQ_A; + else + tbl->lq_type = LQ_G; + + if ((tbl->antenna_type == ANT_BOTH) || + (tbl->antenna_type == ANT_NONE)) + tbl->antenna_type = ANT_MAIN; + + tbl->is_fat = 0; + tbl->is_SGI = 0; + } + + rs_get_supported_rates(lq_data, NULL, tbl->lq_type, &rate_mask); + + /* mask with station rate restriction */ + if (is_legacy(tbl->lq_type)) { + if (lq_data->phymode == (u8) MODE_IEEE80211A) + rate_mask = (u16)(rate_mask & + (sta->supp_rates << IWL_FIRST_OFDM_RATE)); + else + rate_mask = (u16)(rate_mask & sta->supp_rates); + } + + /* if we did switched from HT to legacy check current rate */ + if ((switch_to_legacy) && + (rate_mask & (1 << scale_index))) { + rs_mcs_from_tbl(mcs_rate, tbl, scale_index, is_green); + return 0; + } + + high_low = rs_get_adjacent_rate(scale_index, rate_mask, tbl->lq_type); + low = high_low & 0xff; + + if (low != IWL_RATE_INVALID) + rs_mcs_from_tbl(mcs_rate, tbl, low, is_green); + else + rs_mcs_from_tbl(mcs_rate, tbl, scale_index, is_green); + + return 0; +} + +static void rs_tx_status(void *priv_rate, + struct net_device *dev, + struct sk_buff *skb, + struct ieee80211_tx_status *tx_resp) +{ + int status; + u8 retries; + int rs_index, index = 0; + struct iwl_rate_scale_priv *lq; + struct iwl_link_quality_cmd *table; + struct sta_info *sta; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct iwl_priv *priv = (struct iwl_priv *)priv_rate; + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct iwl_rate_scale_data *window = NULL; + struct iwl_rate_scale_data *search_win = NULL; + struct iwl_rate tx_mcs; + struct iwl_scale_tbl_info tbl_type; + struct iwl_scale_tbl_info *curr_tbl, *search_tbl; + u8 active_index = 0; + u16 fc = le16_to_cpu(hdr->frame_control); + s32 tpt = 0; + + IWL_DEBUG_RATE("get frame ack response, update rate scale window\n"); + + if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1)) + return; + + retries = tx_resp->retry_count; + + if (retries > 15) + retries = 15; + + + sta = sta_info_get(local, hdr->addr1); + + if (!sta || !sta->rate_ctrl_priv) { + if (sta) + sta_info_put(sta); + return; + } + + lq = (struct iwl_rate_scale_priv *)sta->rate_ctrl_priv; + + if (!priv->lq_mngr.lq_ready) + return; + + if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && !lq->ibss_sta_added) + return; + + table = &lq->lq; + active_index = lq->active_tbl; + + lq->antenna = (lq->valid_antenna & local->hw.conf.antenna_sel_tx); + if (!lq->antenna) + lq->antenna = lq->valid_antenna; + + lq->antenna = lq->valid_antenna; + curr_tbl = &(lq->lq_info[active_index]); + search_tbl = &(lq->lq_info[(1 - active_index)]); + window = (struct iwl_rate_scale_data *) + &(curr_tbl->win[0]); + search_win = (struct iwl_rate_scale_data *) + &(search_tbl->win[0]); + + tx_mcs.rate_n_flags = tx_resp->control.tx_rate; + + rs_get_tbl_info_from_mcs(&tx_mcs, priv->phymode, + &tbl_type, &rs_index); + if ((rs_index < 0) || (rs_index >= IWL_RATE_COUNT)) { + IWL_DEBUG_RATE("bad rate index at: %d rate 0x%X\n", + rs_index, tx_mcs.rate_n_flags); + sta_info_put(sta); + return; + } + + if (retries && + (tx_mcs.rate_n_flags != + le32_to_cpu(table->rs_table[0].rate_n_flags))) { + IWL_DEBUG_RATE("initial rate does not match 0x%x 0x%x\n", + tx_mcs.rate_n_flags, + le32_to_cpu(table->rs_table[0].rate_n_flags)); + sta_info_put(sta); + return; + } + + while (retries) { + tx_mcs.rate_n_flags = + le32_to_cpu(table->rs_table[index].rate_n_flags); + rs_get_tbl_info_from_mcs(&tx_mcs, priv->phymode, + &tbl_type, &rs_index); + + if ((tbl_type.lq_type == search_tbl->lq_type) && + (tbl_type.antenna_type == search_tbl->antenna_type) && + (tbl_type.is_SGI == search_tbl->is_SGI)) { + if (search_tbl->expected_tpt) + tpt = search_tbl->expected_tpt[rs_index]; + else + tpt = 0; + rs_collect_tx_data(search_win, + rs_index, tpt, 0); + } else if ((tbl_type.lq_type == curr_tbl->lq_type) && + (tbl_type.antenna_type == curr_tbl->antenna_type) && + (tbl_type.is_SGI == curr_tbl->is_SGI)) { + if (curr_tbl->expected_tpt) + tpt = curr_tbl->expected_tpt[rs_index]; + else + tpt = 0; + rs_collect_tx_data(window, rs_index, tpt, 0); + } + if (lq->stay_in_tbl) + lq->total_failed++; + --retries; + index++; + + } + + if (!tx_resp->retry_count) + tx_mcs.rate_n_flags = tx_resp->control.tx_rate; + else + tx_mcs.rate_n_flags = + le32_to_cpu(table->rs_table[index].rate_n_flags); + + rs_get_tbl_info_from_mcs(&tx_mcs, priv->phymode, + &tbl_type, &rs_index); + + if (tx_resp->flags & IEEE80211_TX_STATUS_ACK) + status = 1; + else + status = 0; + + if ((tbl_type.lq_type == search_tbl->lq_type) && + (tbl_type.antenna_type == search_tbl->antenna_type) && + (tbl_type.is_SGI == search_tbl->is_SGI)) { + if (search_tbl->expected_tpt) + tpt = search_tbl->expected_tpt[rs_index]; + else + tpt = 0; + rs_collect_tx_data(search_win, + rs_index, tpt, status); + } else if ((tbl_type.lq_type == curr_tbl->lq_type) && + (tbl_type.antenna_type == curr_tbl->antenna_type) && + (tbl_type.is_SGI == curr_tbl->is_SGI)) { + if (curr_tbl->expected_tpt) + tpt = curr_tbl->expected_tpt[rs_index]; + else + tpt = 0; + rs_collect_tx_data(window, rs_index, tpt, status); + } + + if (lq->stay_in_tbl) { + if (status) + lq->total_success++; + else + lq->total_failed++; + } + + rs_rate_scale_perform(priv, dev, hdr, sta); + sta_info_put(sta); + return; +} + +static u8 rs_is_ant_connected(u8 valid_antenna, + enum iwl_antenna_type antenna_type) +{ + if (antenna_type == ANT_AUX) + return ((valid_antenna & 0x2) ? 1:0); + else if (antenna_type == ANT_MAIN) + return ((valid_antenna & 0x1) ? 1:0); + else if (antenna_type == ANT_BOTH) { + if ((valid_antenna & 0x3) == 0x3) + return 1; + else + return 0; + } + + return 1; +} + +static u8 rs_is_other_ant_connected(u8 valid_antenna, + enum iwl_antenna_type antenna_type) +{ + if (antenna_type == ANT_AUX) + return (rs_is_ant_connected(valid_antenna, ANT_MAIN)); + else + return (rs_is_ant_connected(valid_antenna, ANT_AUX)); + + return 0; +} + +static void rs_set_stay_in_table(u8 is_legacy, + struct iwl_rate_scale_priv *lq_data) +{ + IWL_DEBUG_HT("we are staying in the same table\n"); + lq_data->stay_in_tbl = 1; + if (is_legacy) { + lq_data->table_count_limit = IWL_LEGACY_TABLE_COUNT; + lq_data->max_failure_limit = IWL_LEGACY_FAILURE_LIMIT; + lq_data->max_success_limit = IWL_LEGACY_TABLE_COUNT; + } else { + lq_data->table_count_limit = IWL_NONE_LEGACY_TABLE_COUNT; + lq_data->max_failure_limit = IWL_NONE_LEGACY_FAILURE_LIMIT; + lq_data->max_success_limit = IWL_NONE_LEGACY_SUCCESS_LIMIT; + } + lq_data->table_count = 0; + lq_data->total_failed = 0; + lq_data->total_success = 0; +} + +static void rs_get_expected_tpt_table(struct iwl_rate_scale_priv *lq_data, + struct iwl_scale_tbl_info *tbl) +{ + if (is_legacy(tbl->lq_type)) { + if (!is_a_band(tbl->lq_type)) + tbl->expected_tpt = expected_tpt_G; + else + tbl->expected_tpt = expected_tpt_A; + } else if (is_siso(tbl->lq_type)) { + if (tbl->is_fat && !lq_data->is_dup) + if (tbl->is_SGI) + tbl->expected_tpt = expected_tpt_siso40MHzSGI; + else + tbl->expected_tpt = expected_tpt_siso40MHz; + else if (tbl->is_SGI) + tbl->expected_tpt = expected_tpt_siso20MHzSGI; + else + tbl->expected_tpt = expected_tpt_siso20MHz; + + } else if (is_mimo(tbl->lq_type)) { + if (tbl->is_fat && !lq_data->is_dup) + if (tbl->is_SGI) + tbl->expected_tpt = expected_tpt_mimo40MHzSGI; + else + tbl->expected_tpt = expected_tpt_mimo40MHz; + else if (tbl->is_SGI) + tbl->expected_tpt = expected_tpt_mimo20MHzSGI; + else + tbl->expected_tpt = expected_tpt_mimo20MHz; + } else + tbl->expected_tpt = expected_tpt_G; +} + +#ifdef CONFIG_IWLWIFI_HT +static s32 rs_get_best_rate(struct iwl_priv *priv, + struct iwl_rate_scale_priv *lq_data, + struct iwl_scale_tbl_info *tbl, + u16 rate_mask, s8 index, s8 rate) +{ + struct iwl_scale_tbl_info *active_tbl = + &(lq_data->lq_info[lq_data->active_tbl]); + s32 new_rate, high, low, start_hi; + s32 active_sr = active_tbl->win[index].success_ratio; + s32 *tpt_tbl = tbl->expected_tpt; + s32 active_tpt = active_tbl->expected_tpt[index]; + u16 high_low; + + new_rate = high = low = start_hi = IWL_RATE_INVALID; + + for (; ;) { + high_low = rs_get_adjacent_rate(rate, rate_mask, tbl->lq_type); + + low = high_low & 0xff; + high = (high_low >> 8) & 0xff; + + if ((((100 * tpt_tbl[rate]) > lq_data->last_tpt) && + ((active_sr > IWL_RATE_DECREASE_TH) && + (active_sr <= IWL_RATE_HIGH_TH) && + (tpt_tbl[rate] <= active_tpt))) || + ((active_sr >= IWL_RATE_SCALE_SWITCH) && + (tpt_tbl[rate] > active_tpt))) { + + if (start_hi != IWL_RATE_INVALID) { + new_rate = start_hi; + break; + } + new_rate = rate; + if (low != IWL_RATE_INVALID) + rate = low; + else + break; + } else { + if (new_rate != IWL_RATE_INVALID) + break; + else if (high != IWL_RATE_INVALID) { + start_hi = high; + rate = high; + } else { + new_rate = rate; + break; + } + } + } + + return new_rate; +} +#endif /* CONFIG_IWLWIFI_HT */ + +static inline u8 rs_is_both_ant_supp(u8 valid_antenna) +{ + return (rs_is_ant_connected(valid_antenna, ANT_BOTH)); +} + +static int rs_switch_to_mimo(struct iwl_priv *priv, + struct iwl_rate_scale_priv *lq_data, + struct iwl_scale_tbl_info *tbl, int index) +{ + int rc = -1; +#ifdef CONFIG_IWLWIFI_HT + u16 rate_mask; + s32 rate; + s8 is_green = lq_data->is_green; + + if (!priv->is_ht_enabled || !priv->current_assoc_ht.is_ht) + return -1; + + IWL_DEBUG_HT("LQ: try to switch to MIMO\n"); + tbl->lq_type = LQ_MIMO; + rs_get_supported_rates(lq_data, NULL, tbl->lq_type, + &rate_mask); + + if (priv->current_assoc_ht.tx_mimo_ps_mode == IWL_MIMO_PS_STATIC) + return -1; + + if (!rs_is_both_ant_supp(lq_data->antenna)) + return -1; + + rc = 0; + tbl->is_dup = lq_data->is_dup; + tbl->action = 0; + if (priv->current_channel_width == IWL_CHANNEL_WIDTH_40MHZ) + tbl->is_fat = 1; + else + tbl->is_fat = 0; + + if (tbl->is_fat) { + if (priv->current_assoc_ht.sgf & HT_SHORT_GI_40MHZ_ONLY) + tbl->is_SGI = 1; + else + tbl->is_SGI = 0; + } else if (priv->current_assoc_ht.sgf & HT_SHORT_GI_20MHZ_ONLY) + tbl->is_SGI = 1; + else + tbl->is_SGI = 0; + + rs_get_expected_tpt_table(lq_data, tbl); + + rate = rs_get_best_rate(priv, lq_data, tbl, rate_mask, index, index); + + IWL_DEBUG_HT("LQ: MIMO best rate %d mask %X\n", rate, rate_mask); + if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) + return -1; + rs_mcs_from_tbl(&tbl->current_rate, tbl, rate, is_green); + + IWL_DEBUG_HT("LQ: Switch to new mcs %X index is green %X\n", + tbl->current_rate.rate_n_flags, is_green); + +#endif /*CONFIG_IWLWIFI_HT */ + return rc; +} + +static int rs_switch_to_siso(struct iwl_priv *priv, + struct iwl_rate_scale_priv *lq_data, + struct iwl_scale_tbl_info *tbl, int index) +{ + int rc = -1; +#ifdef CONFIG_IWLWIFI_HT + u16 rate_mask; + u8 is_green = lq_data->is_green; + s32 rate; + + IWL_DEBUG_HT("LQ: try to switch to SISO\n"); + if (!priv->is_ht_enabled || !priv->current_assoc_ht.is_ht) + return -1; + + rc = 0; + tbl->is_dup = lq_data->is_dup; + tbl->lq_type = LQ_SISO; + tbl->action = 0; + rs_get_supported_rates(lq_data, NULL, tbl->lq_type, + &rate_mask); + + if (priv->current_channel_width == IWL_CHANNEL_WIDTH_40MHZ) + tbl->is_fat = 1; + else + tbl->is_fat = 0; + + if (tbl->is_fat) { + if (priv->current_assoc_ht.sgf & HT_SHORT_GI_40MHZ_ONLY) + tbl->is_SGI = 1; + else + tbl->is_SGI = 0; + } else if (priv->current_assoc_ht.sgf & HT_SHORT_GI_20MHZ_ONLY) + tbl->is_SGI = 1; + else + tbl->is_SGI = 0; + + if (is_green) + tbl->is_SGI = 0; + + rs_get_expected_tpt_table(lq_data, tbl); + rate = rs_get_best_rate(priv, lq_data, tbl, rate_mask, index, index); + + IWL_DEBUG_HT("LQ: get best rate %d mask %X\n", rate, rate_mask); + if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) { + IWL_DEBUG_HT("can not switch with index %d rate mask %x\n", + rate, rate_mask); + return -1; + } + rs_mcs_from_tbl(&tbl->current_rate, tbl, rate, is_green); + IWL_DEBUG_HT("LQ: Switch to new mcs %X index is green %X\n", + tbl->current_rate.rate_n_flags, is_green); + +#endif /*CONFIG_IWLWIFI_HT */ + return rc; +} + +static int rs_move_legacy_other(struct iwl_priv *priv, + struct iwl_rate_scale_priv *lq_data, + int index) +{ + int rc = 0; + struct iwl_scale_tbl_info *tbl = + &(lq_data->lq_info[lq_data->active_tbl]); + struct iwl_scale_tbl_info *search_tbl = + &(lq_data->lq_info[(1 - lq_data->active_tbl)]); + struct iwl_rate_scale_data *window = &(tbl->win[index]); + u32 sz = (sizeof(struct iwl_scale_tbl_info) - + (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); + u8 start_action = tbl->action; + + for (; ;) { + switch (tbl->action) { + case IWL_LEGACY_SWITCH_ANTENNA: + IWL_DEBUG_HT("LQ Legacy switch Antenna\n"); + + search_tbl->lq_type = LQ_NONE; + lq_data->action_counter++; + if (window->success_ratio >= IWL_RS_GOOD_RATIO) + break; + if (!rs_is_other_ant_connected(lq_data->antenna, + tbl->antenna_type)) + break; + + memcpy(search_tbl, tbl, sz); + + rs_toggle_antenna(&(search_tbl->current_rate), + search_tbl); + rs_get_expected_tpt_table(lq_data, search_tbl); + lq_data->search_better_tbl = 1; + goto out; + + case IWL_LEGACY_SWITCH_SISO: + IWL_DEBUG_HT("LQ: Legacy switch to SISO\n"); + memcpy(search_tbl, tbl, sz); + search_tbl->lq_type = LQ_SISO; + search_tbl->is_SGI = 0; + search_tbl->is_fat = 0; + rc = rs_switch_to_siso(priv, lq_data, search_tbl, + index); + if (!rc) { + lq_data->search_better_tbl = 1; + lq_data->action_counter = 0; + } + if (!rc) + goto out; + + break; + case IWL_LEGACY_SWITCH_MIMO: + IWL_DEBUG_HT("LQ: Legacy switch MIMO\n"); + memcpy(search_tbl, tbl, sz); + search_tbl->lq_type = LQ_MIMO; + search_tbl->is_SGI = 0; + search_tbl->is_fat = 0; + search_tbl->antenna_type = ANT_BOTH; + rc = rs_switch_to_mimo(priv, lq_data, search_tbl, + index); + if (!rc) { + lq_data->search_better_tbl = 1; + lq_data->action_counter = 0; + } + if (!rc) + goto out; + break; + } + tbl->action++; + if (tbl->action > IWL_LEGACY_SWITCH_MIMO) + tbl->action = IWL_LEGACY_SWITCH_ANTENNA; + + if (tbl->action == start_action) + break; + + } + return 0; + + out: + tbl->action++; + if (tbl->action > IWL_LEGACY_SWITCH_MIMO) + tbl->action = IWL_LEGACY_SWITCH_ANTENNA; + return 0; + +} + +static int rs_move_siso_to_other(struct iwl_priv *priv, + struct iwl_rate_scale_priv *lq_data, + int index) +{ + int rc = -1; + u8 is_green = lq_data->is_green; + struct iwl_scale_tbl_info *tbl = + &(lq_data->lq_info[lq_data->active_tbl]); + struct iwl_scale_tbl_info *search_tbl = + &(lq_data->lq_info[(1 - lq_data->active_tbl)]); + struct iwl_rate_scale_data *window = &(tbl->win[index]); + u32 sz = (sizeof(struct iwl_scale_tbl_info) - + (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); + u8 start_action = tbl->action; + + for (;;) { + lq_data->action_counter++; + switch (tbl->action) { + case IWL_SISO_SWITCH_ANTENNA: + IWL_DEBUG_HT("LQ: SISO SWITCH ANTENNA SISO\n"); + search_tbl->lq_type = LQ_NONE; + if (window->success_ratio >= IWL_RS_GOOD_RATIO) + break; + if (!rs_is_other_ant_connected(lq_data->antenna, + tbl->antenna_type)) + break; + + memcpy(search_tbl, tbl, sz); + search_tbl->action = IWL_SISO_SWITCH_MIMO; + rs_toggle_antenna(&(search_tbl->current_rate), + search_tbl); + lq_data->search_better_tbl = 1; + + goto out; + + case IWL_SISO_SWITCH_MIMO: + IWL_DEBUG_HT("LQ: SISO SWITCH TO MIMO FROM SISO\n"); + memcpy(search_tbl, tbl, sz); + search_tbl->lq_type = LQ_MIMO; + search_tbl->is_SGI = 0; + search_tbl->is_fat = 0; + search_tbl->antenna_type = ANT_BOTH; + rc = rs_switch_to_mimo(priv, lq_data, search_tbl, + index); + if (!rc) + lq_data->search_better_tbl = 1; + + if (!rc) + goto out; + break; + case IWL_SISO_SWITCH_GI: + IWL_DEBUG_HT("LQ: SISO SWITCH TO GI\n"); + memcpy(search_tbl, tbl, sz); + search_tbl->action = 0; + if (search_tbl->is_SGI) + search_tbl->is_SGI = 0; + else if (!is_green) + search_tbl->is_SGI = 1; + else + break; + lq_data->search_better_tbl = 1; + if ((tbl->lq_type == LQ_SISO) && + (tbl->is_SGI)) { + s32 tpt = lq_data->last_tpt / 100; + if (((!tbl->is_fat) && + (tpt >= expected_tpt_siso20MHz[index])) || + ((tbl->is_fat) && + (tpt >= expected_tpt_siso40MHz[index]))) + lq_data->search_better_tbl = 0; + } + rs_get_expected_tpt_table(lq_data, search_tbl); + rs_mcs_from_tbl(&search_tbl->current_rate, + search_tbl, index, is_green); + goto out; + } + tbl->action++; + if (tbl->action > IWL_SISO_SWITCH_GI) + tbl->action = IWL_SISO_SWITCH_ANTENNA; + + if (tbl->action == start_action) + break; + } + return 0; + + out: + tbl->action++; + if (tbl->action > IWL_SISO_SWITCH_GI) + tbl->action = IWL_SISO_SWITCH_ANTENNA; + return 0; +} + +static int rs_move_mimo_to_other(struct iwl_priv *priv, + struct iwl_rate_scale_priv *lq_data, + int index) +{ + int rc = -1; + s8 is_green = lq_data->is_green; + struct iwl_scale_tbl_info *tbl = + &(lq_data->lq_info[lq_data->active_tbl]); + struct iwl_scale_tbl_info *search_tbl = + &(lq_data->lq_info[(1 - lq_data->active_tbl)]); + u32 sz = (sizeof(struct iwl_scale_tbl_info) - + (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); + u8 start_action = tbl->action; + + for (;;) { + lq_data->action_counter++; + switch (tbl->action) { + case IWL_MIMO_SWITCH_ANTENNA_A: + case IWL_MIMO_SWITCH_ANTENNA_B: + IWL_DEBUG_HT("LQ: MIMO SWITCH TO SISO\n"); + memcpy(search_tbl, tbl, sz); + search_tbl->lq_type = LQ_SISO; + search_tbl->is_SGI = 0; + search_tbl->is_fat = 0; + if (tbl->action == IWL_MIMO_SWITCH_ANTENNA_A) + search_tbl->antenna_type = ANT_MAIN; + else + search_tbl->antenna_type = ANT_AUX; + + rc = rs_switch_to_siso(priv, lq_data, search_tbl, + index); + if (!rc) { + lq_data->search_better_tbl = 1; + goto out; + } + break; + + case IWL_MIMO_SWITCH_GI: + IWL_DEBUG_HT("LQ: MIMO SWITCH TO GI\n"); + memcpy(search_tbl, tbl, sz); + search_tbl->lq_type = LQ_MIMO; + search_tbl->antenna_type = ANT_BOTH; + search_tbl->action = 0; + if (search_tbl->is_SGI) + search_tbl->is_SGI = 0; + else + search_tbl->is_SGI = 1; + lq_data->search_better_tbl = 1; + if ((tbl->lq_type == LQ_MIMO) && + (tbl->is_SGI)) { + s32 tpt = lq_data->last_tpt / 100; + if (((!tbl->is_fat) && + (tpt >= expected_tpt_mimo20MHz[index])) || + ((tbl->is_fat) && + (tpt >= expected_tpt_mimo40MHz[index]))) + lq_data->search_better_tbl = 0; + } + rs_get_expected_tpt_table(lq_data, search_tbl); + rs_mcs_from_tbl(&search_tbl->current_rate, + search_tbl, index, is_green); + goto out; + + } + tbl->action++; + if (tbl->action > IWL_MIMO_SWITCH_GI) + tbl->action = IWL_MIMO_SWITCH_ANTENNA_A; + + if (tbl->action == start_action) + break; + } + + return 0; + out: + tbl->action++; + if (tbl->action > IWL_MIMO_SWITCH_GI) + tbl->action = IWL_MIMO_SWITCH_ANTENNA_A; + return 0; + +} + +static void rs_stay_in_table(struct iwl_rate_scale_priv *lq_data) +{ + struct iwl_scale_tbl_info *tbl; + int i; + int active_tbl; + int flush_interval_passed = 0; + + active_tbl = lq_data->active_tbl; + + tbl = &(lq_data->lq_info[active_tbl]); + + if (lq_data->stay_in_tbl) { + + if (lq_data->flush_timer) + flush_interval_passed = + time_after(jiffies, + (unsigned long)(lq_data->flush_timer + + IWL_RATE_SCALE_FLUSH_INTVL)); + + flush_interval_passed = 0; + if ((lq_data->total_failed > lq_data->max_failure_limit) || + (lq_data->total_success > lq_data->max_success_limit) || + ((!lq_data->search_better_tbl) && (lq_data->flush_timer) + && (flush_interval_passed))) { + IWL_DEBUG_HT("LQ: stay is expired %d %d %d\n:", + lq_data->total_failed, + lq_data->total_success, + flush_interval_passed); + lq_data->stay_in_tbl = 0; + lq_data->total_failed = 0; + lq_data->total_success = 0; + lq_data->flush_timer = 0; + } else if (lq_data->table_count > 0) { + lq_data->table_count++; + if (lq_data->table_count >= + lq_data->table_count_limit) { + lq_data->table_count = 0; + + IWL_DEBUG_HT("LQ: stay in table clear win\n"); + for (i = 0; i < IWL_RATE_COUNT; i++) + rs_rate_scale_clear_window( + &(tbl->win[i])); + } + } + + if (!lq_data->stay_in_tbl) { + for (i = 0; i < IWL_RATE_COUNT; i++) + rs_rate_scale_clear_window(&(tbl->win[i])); + } + } +} + +static void rs_rate_scale_perform(struct iwl_priv *priv, + struct net_device *dev, + struct ieee80211_hdr *hdr, + struct sta_info *sta) +{ + int low = IWL_RATE_INVALID; + int high = IWL_RATE_INVALID; + int index; + int i; + struct iwl_rate_scale_data *window = NULL; + int current_tpt = IWL_INVALID_VALUE; + int low_tpt = IWL_INVALID_VALUE; + int high_tpt = IWL_INVALID_VALUE; + u32 fail_count; + s8 scale_action = 0; + u16 fc, rate_mask; + u8 update_lq = 0; + struct iwl_rate_scale_priv *lq_data; + struct iwl_scale_tbl_info *tbl, *tbl1; + u16 rate_scale_index_msk = 0; + struct iwl_rate mcs_rate; + u8 is_green = 0; + u8 active_tbl = 0; + u8 done_search = 0; + u16 high_low; + + IWL_DEBUG_RATE("rate scale calculate new rate for skb\n"); + + fc = le16_to_cpu(hdr->frame_control); + if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1)) { + /* Send management frames and broadcast/multicast data using + * lowest rate. */ + /* TODO: this could probably be improved.. */ + return; + } + + if (!sta || !sta->rate_ctrl_priv) + return; + + if (!priv->lq_mngr.lq_ready) { + IWL_DEBUG_RATE("still rate scaling not ready\n"); + return; + } + lq_data = (struct iwl_rate_scale_priv *)sta->rate_ctrl_priv; + + if (!lq_data->search_better_tbl) + active_tbl = lq_data->active_tbl; + else + active_tbl = 1 - lq_data->active_tbl; + + tbl = &(lq_data->lq_info[active_tbl]); + is_green = lq_data->is_green; + + index = sta->last_txrate; + + IWL_DEBUG_RATE("Rate scale index %d for type %d\n", index, + tbl->lq_type); + + rs_get_supported_rates(lq_data, hdr, tbl->lq_type, + &rate_mask); + + IWL_DEBUG_RATE("mask 0x%04X \n", rate_mask); + + /* mask with station rate restriction */ + if (is_legacy(tbl->lq_type)) { + if (lq_data->phymode == (u8) MODE_IEEE80211A) + rate_scale_index_msk = (u16) (rate_mask & + (sta->supp_rates << IWL_FIRST_OFDM_RATE)); + else + rate_scale_index_msk = (u16) (rate_mask & + sta->supp_rates); + + } else + rate_scale_index_msk = rate_mask; + + if (!rate_scale_index_msk) + rate_scale_index_msk = rate_mask; + + if (index < 0 || !((1 << index) & rate_scale_index_msk)) { + index = IWL_INVALID_VALUE; + update_lq = 1; + + /* get the lowest availabe rate */ + for (i = 0; i <= IWL_RATE_COUNT; i++) { + if ((1 << i) & rate_scale_index_msk) + index = i; + } + + if (index == IWL_INVALID_VALUE) { + IWL_WARNING("Can not find a suitable rate\n"); + return; + } + } + + if (!tbl->expected_tpt) + rs_get_expected_tpt_table(lq_data, tbl); + + window = &(tbl->win[index]); + + fail_count = window->counter - window->success_counter; + if (((fail_count < IWL_RATE_MIN_FAILURE_TH) && + (window->success_counter < IWL_RATE_MIN_SUCCESS_TH)) + || (tbl->expected_tpt == NULL)) { + IWL_DEBUG_RATE("LQ: still below TH succ %d total %d " + "for index %d\n", + window->success_counter, window->counter, index); + window->average_tpt = IWL_INVALID_VALUE; + rs_stay_in_table(lq_data); + if (update_lq) { + rs_mcs_from_tbl(&mcs_rate, tbl, index, is_green); + rs_fill_link_cmd(lq_data, &mcs_rate, &lq_data->lq, sta); + rs_send_lq_cmd(priv, &lq_data->lq, CMD_ASYNC); + } + goto out; + + } else + window->average_tpt = ((window->success_ratio * + tbl->expected_tpt[index] + 64) / 128); + + if (lq_data->search_better_tbl) { + int success_limit = IWL_RATE_SCALE_SWITCH; + + if ((window->success_ratio > success_limit) || + (window->average_tpt > lq_data->last_tpt)) { + if (!is_legacy(tbl->lq_type)) { + IWL_DEBUG_HT("LQ: we are switching to HT" + " rate suc %d current tpt %d" + " old tpt %d\n", + window->success_ratio, + window->average_tpt, + lq_data->last_tpt); + lq_data->enable_counter = 1; + } + lq_data->active_tbl = active_tbl; + current_tpt = window->average_tpt; + } else { + tbl->lq_type = LQ_NONE; + active_tbl = lq_data->active_tbl; + tbl = &(lq_data->lq_info[active_tbl]); + + index = iwl_rate_index_from_plcp( + tbl->current_rate.rate_n_flags); + + update_lq = 1; + current_tpt = lq_data->last_tpt; + IWL_DEBUG_HT("XXY GO BACK TO OLD TABLE\n"); + } + lq_data->search_better_tbl = 0; + done_search = 1; + goto lq_update; + } + + high_low = rs_get_adjacent_rate(index, rate_scale_index_msk, + tbl->lq_type); + low = high_low & 0xff; + high = (high_low >> 8) & 0xff; + + current_tpt = window->average_tpt; + + if (low != IWL_RATE_INVALID) + low_tpt = tbl->win[low].average_tpt; + + if (high != IWL_RATE_INVALID) + high_tpt = tbl->win[high].average_tpt; + + + scale_action = 1; + + if ((window->success_ratio <= IWL_RATE_DECREASE_TH) || + (current_tpt == 0)) { + IWL_DEBUG_RATE("decrease rate because of low success_ratio\n"); + scale_action = -1; + } else if ((low_tpt == IWL_INVALID_VALUE) && + (high_tpt == IWL_INVALID_VALUE)) + scale_action = 1; + else if ((low_tpt != IWL_INVALID_VALUE) && + (high_tpt != IWL_INVALID_VALUE) && + (low_tpt < current_tpt) && + (high_tpt < current_tpt)) + scale_action = 0; + else { + if (high_tpt != IWL_INVALID_VALUE) { + if (high_tpt > current_tpt) + scale_action = 1; + else { + IWL_DEBUG_RATE + ("decrease rate because of high tpt\n"); + scale_action = -1; + } + } else if (low_tpt != IWL_INVALID_VALUE) { + if (low_tpt > current_tpt) { + IWL_DEBUG_RATE + ("decrease rate because of low tpt\n"); + scale_action = -1; + } else + scale_action = 1; + } + } + + if (scale_action == -1) { + if ((low != IWL_RATE_INVALID) && + ((window->success_ratio > IWL_RATE_HIGH_TH) || + (current_tpt > (100 * tbl->expected_tpt[low])))) + scale_action = 0; + } else if ((scale_action == 1) && + (window->success_ratio < IWL_RATE_INCREASE_TH)) + scale_action = 0; + + switch (scale_action) { + case -1: + if (low != IWL_RATE_INVALID) { + update_lq = 1; + index = low; + } + break; + case 1: + if (high != IWL_RATE_INVALID) { + update_lq = 1; + index = high; + } + + break; + case 0: + default: + break; + } + + IWL_DEBUG_HT("choose rate scale index %d action %d low %d " + "high %d type %d\n", + index, scale_action, low, high, tbl->lq_type); + + lq_update: + if (update_lq) { + rs_mcs_from_tbl(&mcs_rate, tbl, index, is_green); + rs_fill_link_cmd(lq_data, &mcs_rate, &lq_data->lq, sta); + rs_send_lq_cmd(priv, &lq_data->lq, CMD_ASYNC); + } + rs_stay_in_table(lq_data); + + if (!update_lq && !done_search && !lq_data->stay_in_tbl) { + lq_data->last_tpt = current_tpt; + + if (is_legacy(tbl->lq_type)) + rs_move_legacy_other(priv, lq_data, index); + else if (is_siso(tbl->lq_type)) + rs_move_siso_to_other(priv, lq_data, index); + else + rs_move_mimo_to_other(priv, lq_data, index); + + if (lq_data->search_better_tbl) { + tbl = &(lq_data->lq_info[(1 - lq_data->active_tbl)]); + for (i = 0; i < IWL_RATE_COUNT; i++) + rs_rate_scale_clear_window(&(tbl->win[i])); + + index = iwl_rate_index_from_plcp( + tbl->current_rate.rate_n_flags); + + IWL_DEBUG_HT("Switch current mcs: %X index: %d\n", + tbl->current_rate.rate_n_flags, index); + rs_fill_link_cmd(lq_data, &tbl->current_rate, + &(lq_data->lq), sta); + rs_send_lq_cmd(priv, &lq_data->lq, CMD_ASYNC); + } + tbl1 = &(lq_data->lq_info[lq_data->active_tbl]); + + if (is_legacy(tbl1->lq_type) && +#ifdef CONFIG_IWLWIFI_HT + !priv->current_assoc_ht.is_ht && +#endif + (lq_data->action_counter >= 1)) { + lq_data->action_counter = 0; + IWL_DEBUG_HT("LQ: STAY in legacy table\n"); + rs_set_stay_in_table(1, lq_data); + } + + if (lq_data->enable_counter && + (lq_data->action_counter >= IWL_ACTION_LIMIT)) { +#ifdef CONFIG_IWLWIFI_HT_AGG + if ((lq_data->last_tpt > TID_AGG_TPT_THREHOLD) && + (priv->lq_mngr.agg_ctrl.auto_agg)) { + priv->lq_mngr.agg_ctrl.tid_retry = + TID_ALL_SPECIFIED; + schedule_work(&priv->agg_work); + } +#endif /*CONFIG_IWLWIFI_HT_AGG */ + lq_data->action_counter = 0; + rs_set_stay_in_table(0, lq_data); + } + } else { + if ((!update_lq) && (!done_search) && (!lq_data->flush_timer)) + lq_data->flush_timer = jiffies; + } + +out: + rs_mcs_from_tbl(&tbl->current_rate, tbl, index, is_green); + i = index; + sta->last_txrate = i; + + /* sta->txrate is an index to A mode rates which start + * at IWL_FIRST_OFDM_RATE + */ + if (lq_data->phymode == (u8) MODE_IEEE80211A) + sta->txrate = i - IWL_FIRST_OFDM_RATE; + else + sta->txrate = i; + + return; +} + + +static void rs_initialize_lq(struct iwl_priv *priv, + struct sta_info *sta) +{ + int i; + struct iwl_rate_scale_priv *lq; + struct iwl_scale_tbl_info *tbl; + u8 active_tbl = 0; + int rate_idx; + u8 use_green = rs_use_green(priv); + struct iwl_rate mcs_rate; + + if (!sta || !sta->rate_ctrl_priv) + goto out; + + lq = (struct iwl_rate_scale_priv *)sta->rate_ctrl_priv; + i = sta->last_txrate; + + if ((lq->lq.sta_id == 0xff) && + (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)) + goto out; + + if (!lq->search_better_tbl) + active_tbl = lq->active_tbl; + else + active_tbl = 1 - lq->active_tbl; + + tbl = &(lq->lq_info[active_tbl]); + + if ((i < 0) || (i >= IWL_RATE_COUNT)) + i = 0; + + mcs_rate.rate_n_flags = iwl_rates[i].plcp ; + mcs_rate.rate_n_flags |= RATE_MCS_ANT_B_MSK; + mcs_rate.rate_n_flags &= ~RATE_MCS_ANT_A_MSK; + + if (i >= IWL_FIRST_CCK_RATE && i <= IWL_LAST_CCK_RATE) + mcs_rate.rate_n_flags |= RATE_MCS_CCK_MSK; + + tbl->antenna_type = ANT_AUX; + rs_get_tbl_info_from_mcs(&mcs_rate, priv->phymode, tbl, &rate_idx); + if (!rs_is_ant_connected(priv->valid_antenna, tbl->antenna_type)) + rs_toggle_antenna(&mcs_rate, tbl), + + rs_mcs_from_tbl(&mcs_rate, tbl, rate_idx, use_green); + tbl->current_rate.rate_n_flags = mcs_rate.rate_n_flags; + rs_get_expected_tpt_table(lq, tbl); + rs_fill_link_cmd(lq, &mcs_rate, &(lq->lq), sta); + rs_send_lq_cmd(priv, &lq->lq, CMD_ASYNC); + out: + return; +} + +static struct ieee80211_rate *rs_get_lowest_rate(struct ieee80211_local + *local) +{ + struct ieee80211_hw_mode *mode = local->oper_hw_mode; + int i; + + for (i = 0; i < mode->num_rates; i++) { + struct ieee80211_rate *rate = &mode->rates[i]; + + if (rate->flags & IEEE80211_RATE_SUPPORTED) + return rate; + } + + return &mode->rates[0]; +} + +static struct ieee80211_rate *rs_get_rate(void *priv_rate, + struct net_device *dev, + struct sk_buff *skb, + struct rate_control_extra + *extra) +{ + + int i; + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct sta_info *sta; + u16 fc; + struct iwl_priv *priv = (struct iwl_priv *)priv_rate; + struct iwl_rate_scale_priv *lq; + + IWL_DEBUG_RATE("rate scale calculate new rate for skb\n"); + + memset(extra, 0, sizeof(*extra)); + + fc = le16_to_cpu(hdr->frame_control); + if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1)) { + /* Send management frames and broadcast/multicast data using + * lowest rate. */ + /* TODO: this could probably be improved.. */ + return rs_get_lowest_rate(local); + } + + sta = sta_info_get(local, hdr->addr1); + + if (!sta || !sta->rate_ctrl_priv) { + if (sta) + sta_info_put(sta); + return rs_get_lowest_rate(local); + } + + lq = (struct iwl_rate_scale_priv *)sta->rate_ctrl_priv; + i = sta->last_txrate; + + if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && !lq->ibss_sta_added) { + u8 sta_id = iwl_hw_find_station(priv, hdr->addr1); + + if (sta_id == IWL_INVALID_STATION) { + IWL_DEBUG_RATE("LQ: ADD station " MAC_FMT "\n", + MAC_ARG(hdr->addr1)); + sta_id = iwl_add_station(priv, + hdr->addr1, 0, CMD_ASYNC); + } + if ((sta_id != IWL_INVALID_STATION)) { + lq->lq.sta_id = sta_id; + lq->lq.rs_table[0].rate_n_flags = 0; + lq->ibss_sta_added = 1; + rs_initialize_lq(priv, sta); + } + if (!lq->ibss_sta_added) + goto done; + } + + done: + sta_info_put(sta); + if ((i < 0) || (i > IWL_RATE_COUNT)) + return rs_get_lowest_rate(local); + + return &priv->ieee_rates[i]; +} + +static void *rs_alloc_sta(void *priv, gfp_t gfp) +{ + struct iwl_rate_scale_priv *crl; + int i, j; + + IWL_DEBUG_RATE("create station rate scale window\n"); + + crl = kzalloc(sizeof(struct iwl_rate_scale_priv), gfp); + + if (crl == NULL) + return NULL; + + memset(crl, 0, sizeof(struct iwl_rate_scale_priv)); + crl->lq.sta_id = 0xff; + + for (j = 0; j < LQ_SIZE; j++) + for (i = 0; i < IWL_RATE_COUNT; i++) + rs_rate_scale_clear_window(&(crl->lq_info[j].win[i])); + + return crl; +} + +static void rs_rate_init(void *priv_rate, void *priv_sta, + struct ieee80211_local *local, + struct sta_info *sta) +{ + int i, j; + struct ieee80211_hw_mode *mode = local->oper_hw_mode; + struct iwl_priv *priv = (struct iwl_priv *)priv_rate; + struct iwl_rate_scale_priv *crl = priv_sta; + + memset(crl, 0, sizeof(struct iwl_rate_scale_priv)); + + crl->lq.sta_id = 0xff; + crl->flush_timer = 0; + sta->txrate = 3; + for (j = 0; j < LQ_SIZE; j++) + for (i = 0; i < IWL_RATE_COUNT; i++) + rs_rate_scale_clear_window(&(crl->lq_info[j].win[i])); + + IWL_DEBUG_RATE("rate scale global init\n"); + /* TODO: what is a good starting rate for STA? About middle? Maybe not + * the lowest or the highest rate.. Could consider using RSSI from + * previous packets? Need to have IEEE 802.1X auth succeed immediately + * after assoc.. */ + + crl->ibss_sta_added = 0; + if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { + u8 sta_id = iwl_hw_find_station(priv, sta->addr); + /* for IBSS the call are from tasklet */ + IWL_DEBUG_HT("LQ: ADD station " MAC_FMT " \n", + MAC_ARG(sta->addr)); + + if (sta_id == IWL_INVALID_STATION) { + IWL_DEBUG_RATE("LQ: ADD station " MAC_FMT "\n", + MAC_ARG(sta->addr)); + sta_id = iwl_add_station(priv, + sta->addr, 0, CMD_ASYNC); + } + if ((sta_id != IWL_INVALID_STATION)) { + crl->lq.sta_id = sta_id; + crl->lq.rs_table[0].rate_n_flags = 0; + } + /* FIXME: this is w/a remove it later */ + priv->assoc_station_added = 1; + } + + for (i = 0; i < mode->num_rates; i++) { + if ((sta->supp_rates & BIT(i)) && + (mode->rates[i].flags & IEEE80211_RATE_SUPPORTED)) + sta->txrate = i; + } + sta->last_txrate = sta->txrate; + /* For MODE_IEEE80211A mode cck rate are at end + * rate table + */ + if (local->hw.conf.phymode == MODE_IEEE80211A) + sta->last_txrate += IWL_FIRST_OFDM_RATE; + + crl->is_dup = priv->is_dup; + crl->valid_antenna = priv->valid_antenna; + crl->antenna = priv->antenna; + crl->is_green = rs_use_green(priv); + crl->active_rate = priv->active_rate; + crl->active_rate &= ~(0x1000); + crl->active_rate_basic = priv->active_rate_basic; + crl->phymode = priv->phymode; +#ifdef CONFIG_IWLWIFI_HT + crl->active_siso_rate = (priv->current_assoc_ht.supp_rates[0] << 1); + crl->active_siso_rate |= (priv->current_assoc_ht.supp_rates[0] & 0x1); + crl->active_siso_rate &= ~((u16)0x2); + crl->active_siso_rate = crl->active_siso_rate << IWL_FIRST_OFDM_RATE; + + crl->active_mimo_rate = (priv->current_assoc_ht.supp_rates[1] << 1); + crl->active_mimo_rate |= (priv->current_assoc_ht.supp_rates[1] & 0x1); + crl->active_mimo_rate &= ~((u16)0x2); + crl->active_mimo_rate = crl->active_mimo_rate << IWL_FIRST_OFDM_RATE; + IWL_DEBUG_HT("MIMO RATE 0x%X SISO MASK 0x%X\n", crl->active_siso_rate, + crl->active_mimo_rate); +#endif /*CONFIG_IWLWIFI_HT*/ + + if (priv->assoc_station_added) + priv->lq_mngr.lq_ready = 1; + + rs_initialize_lq(priv, sta); +} + +static int rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data, + struct iwl_rate *tx_mcs, + struct iwl_link_quality_cmd *lq_cmd, + struct sta_info *sta) +{ + int index = 0; + int rc = 0; + int rate_idx; + u8 ant_toggle_count = 0; + u8 use_ht_possible = 1; + u8 repeat_cur_rate = 0; + struct iwl_rate new_rate; + struct iwl_scale_tbl_info tbl_type = { 0 }; + + rs_get_tbl_info_from_mcs(tx_mcs, lq_data->phymode, + &tbl_type, &rate_idx); + + if (is_legacy(tbl_type.lq_type)) { + ant_toggle_count = 1; + repeat_cur_rate = IWL_NUMBER_TRY; + } else + repeat_cur_rate = IWL_HT_NUMBER_TRY; + + lq_cmd->general_params.mimo_delimiter = + is_mimo(tbl_type.lq_type) ? 1 : 0; + lq_cmd->rs_table[index].rate_n_flags = + cpu_to_le32(tx_mcs->rate_n_flags); + new_rate.rate_n_flags = tx_mcs->rate_n_flags; + + if (is_mimo(tbl_type.lq_type) || (tbl_type.antenna_type == ANT_MAIN)) + lq_cmd->general_params.single_stream_ant_msk = 1; + else + lq_cmd->general_params.single_stream_ant_msk = 2; + + index++; + repeat_cur_rate--; + + while (index < LINK_QUAL_MAX_RETRY_NUM) { + while (repeat_cur_rate && (index < LINK_QUAL_MAX_RETRY_NUM)) { + if (is_legacy(tbl_type.lq_type)) { + if (ant_toggle_count < + NUM_TRY_BEFORE_ANTENNA_TOGGLE) + ant_toggle_count++; + else { + rs_toggle_antenna(&new_rate, &tbl_type); + ant_toggle_count = 1; + } + } + lq_cmd->rs_table[index].rate_n_flags = + cpu_to_le32(new_rate.rate_n_flags); + repeat_cur_rate--; + index++; + } + + rs_get_tbl_info_from_mcs(&new_rate, lq_data->phymode, &tbl_type, + &rate_idx); + + if (is_mimo(tbl_type.lq_type)) + lq_cmd->general_params.mimo_delimiter = index; + + rs_get_lower_rate(lq_data, &tbl_type, rate_idx, + use_ht_possible, &new_rate, sta); + + if (is_legacy(tbl_type.lq_type)) { + if (ant_toggle_count < NUM_TRY_BEFORE_ANTENNA_TOGGLE) + ant_toggle_count++; + else { + rs_toggle_antenna(&new_rate, &tbl_type); + ant_toggle_count = 1; + } + repeat_cur_rate = IWL_NUMBER_TRY; + } else + repeat_cur_rate = IWL_HT_NUMBER_TRY; + + use_ht_possible = 0; + + lq_cmd->rs_table[index].rate_n_flags = + cpu_to_le32(new_rate.rate_n_flags); + /* lq_cmd->rs_table[index].rate_n_flags = 0x800d; */ + + index++; + repeat_cur_rate--; + } + + /* lq_cmd->rs_table[0].rate_n_flags = 0x800d; */ + + lq_cmd->general_params.dual_stream_ant_msk = 3; + lq_cmd->agg_params.agg_dis_start_th = 3; + lq_cmd->agg_params.agg_time_limit = cpu_to_le16(4000); + return rc; +} + +static void *rs_alloc(struct ieee80211_local *local) +{ + return local->hw.priv; +} +/* rate scale requires free function to be implemented */ +static void rs_free(void *priv_rate) +{ + return; +} + +static void rs_clear(void *priv_rate) +{ + struct iwl_priv *priv = (struct iwl_priv *) priv_rate; + + IWL_DEBUG_RATE("enter\n"); + + priv->lq_mngr.lq_ready = 0; +#ifdef CONFIG_IWLWIFI_HT +#ifdef CONFIG_IWLWIFI_HT_AGG + if (priv->lq_mngr.agg_ctrl.granted_ba) + iwl4965_turn_off_agg(priv, TID_ALL_SPECIFIED); +#endif /*CONFIG_IWLWIFI_HT_AGG */ +#endif /* CONFIG_IWLWIFI_HT */ + + IWL_DEBUG_RATE("leave\n"); +} + +static void rs_free_sta(void *priv, void *priv_sta) +{ + struct iwl_rate_scale_priv *rs_priv = priv_sta; + + IWL_DEBUG_RATE("enter\n"); + kfree(rs_priv); + IWL_DEBUG_RATE("leave\n"); +} + + +static struct rate_control_ops rs_ops = { + .module = NULL, + .name = RS_NAME, + .tx_status = rs_tx_status, + .get_rate = rs_get_rate, + .rate_init = rs_rate_init, + .clear = rs_clear, + .alloc = rs_alloc, + .free = rs_free, + .alloc_sta = rs_alloc_sta, + .free_sta = rs_free_sta, +}; + +int iwl_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct iwl_priv *priv = hw->priv; + struct iwl_rate_scale_priv *rs_priv; + struct sta_info *sta; + int count = 0, i; + u32 samples = 0, success = 0, good = 0; + unsigned long now = jiffies; + u32 max_time = 0; + u8 lq_type, antenna; + + sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr); + if (!sta || !sta->rate_ctrl_priv) { + if (sta) { + sta_info_put(sta); + IWL_DEBUG_RATE("leave - no private rate data!\n"); + } else + IWL_DEBUG_RATE("leave - no station!\n"); + return sprintf(buf, "station %d not found\n", sta_id); + } + + rs_priv = (void *)sta->rate_ctrl_priv; + + lq_type = rs_priv->lq_info[rs_priv->active_tbl].lq_type; + antenna = rs_priv->lq_info[rs_priv->active_tbl].antenna_type; + + if (is_legacy(lq_type)) + i = IWL_RATE_54M_INDEX; + else + i = IWL_RATE_60M_INDEX; + while (1) { + u64 mask; + int j; + int active = rs_priv->active_tbl; + + count += + sprintf(&buf[count], " %2dMbs: ", iwl_rates[i].ieee / 2); + + mask = (1ULL << (IWL_RATE_MAX_WINDOW - 1)); + for (j = 0; j < IWL_RATE_MAX_WINDOW; j++, mask >>= 1) + buf[count++] = + (rs_priv->lq_info[active].win[i].data & mask) + ? '1' : '0'; + + samples += rs_priv->lq_info[active].win[i].counter; + good += rs_priv->lq_info[active].win[i].success_counter; + success += rs_priv->lq_info[active].win[i].success_counter * + iwl_rates[i].ieee; + + if (rs_priv->lq_info[active].win[i].stamp) { + int delta = + jiffies_to_msecs(now - + rs_priv->lq_info[active].win[i].stamp); + + if (delta > max_time) + max_time = delta; + + count += sprintf(&buf[count], "%5dms\n", delta); + } else + buf[count++] = '\n'; + + j = iwl_get_prev_ieee_rate(i); + if (j == i) + break; + i = j; + } + + /* Display the average rate of all samples taken. + * + * NOTE: We multiple # of samples by 2 since the IEEE measurement + * added from iwl_rates is actually 2X the rate */ + if (samples) + count += sprintf(&buf[count], + "\nAverage rate is %3d.%02dMbs over last %4dms\n" + "%3d%% success (%d good packets over %d tries)\n", + success / (2 * samples), (success * 5 / samples) % 10, + max_time, good * 100 / samples, good, samples); + else + count += sprintf(&buf[count], "\nAverage rate: 0Mbs\n"); + count += sprintf(&buf[count], "\nrate scale type %d anntena %d " + "active_search %d rate index %d\n", lq_type, antenna, + rs_priv->search_better_tbl, sta->last_txrate); + + sta_info_put(sta); + return count; +} + +void iwl_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) +{ + struct iwl_priv *priv = hw->priv; + + priv->lq_mngr.lq_ready = 1; +} + +void iwl_rate_control_register(struct ieee80211_hw *hw) +{ + ieee80211_rate_control_register(&rs_ops); +} + +void iwl_rate_control_unregister(struct ieee80211_hw *hw) +{ + ieee80211_rate_control_unregister(&rs_ops); +} + diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.h b/drivers/net/wireless/iwlwifi/iwl-4965-rs.h new file mode 100644 index 00000000000..c6325f72df6 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.h @@ -0,0 +1,266 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#ifndef __iwl_4965_rs_h__ +#define __iwl_4965_rs_h__ + +#include "iwl-4965.h" + +struct iwl_rate_info { + u8 plcp; + u8 plcp_siso; + u8 plcp_mimo; + u8 ieee; + u8 prev_ieee; /* previous rate in IEEE speeds */ + u8 next_ieee; /* next rate in IEEE speeds */ + u8 prev_rs; /* previous rate used in rs algo */ + u8 next_rs; /* next rate used in rs algo */ + u8 prev_rs_tgg; /* previous rate used in TGG rs algo */ + u8 next_rs_tgg; /* next rate used in TGG rs algo */ +}; + +enum { + IWL_RATE_1M_INDEX = 0, + IWL_RATE_2M_INDEX, + IWL_RATE_5M_INDEX, + IWL_RATE_11M_INDEX, + IWL_RATE_6M_INDEX, + IWL_RATE_9M_INDEX, + IWL_RATE_12M_INDEX, + IWL_RATE_18M_INDEX, + IWL_RATE_24M_INDEX, + IWL_RATE_36M_INDEX, + IWL_RATE_48M_INDEX, + IWL_RATE_54M_INDEX, + IWL_RATE_60M_INDEX, + IWL_RATE_COUNT, + IWL_RATE_INVM_INDEX = IWL_RATE_COUNT, + IWL_RATE_INVALID = IWL_RATE_INVM_INDEX +}; + +enum { + IWL_FIRST_OFDM_RATE = IWL_RATE_6M_INDEX, + IWL_LAST_OFDM_RATE = IWL_RATE_60M_INDEX, + IWL_FIRST_CCK_RATE = IWL_RATE_1M_INDEX, + IWL_LAST_CCK_RATE = IWL_RATE_11M_INDEX, +}; + +/* #define vs. enum to keep from defaulting to 'large integer' */ +#define IWL_RATE_6M_MASK (1< + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "iwlwifi.h" +#include "iwl-4965.h" +#include "iwl-helpers.h" + +#define IWL_DECLARE_RATE_INFO(r, s, ip, in, rp, rn, pp, np) \ + [IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP, \ + IWL_RATE_SISO_##s##M_PLCP, \ + IWL_RATE_MIMO_##s##M_PLCP, \ + IWL_RATE_##r##M_IEEE, \ + IWL_RATE_##ip##M_INDEX, \ + IWL_RATE_##in##M_INDEX, \ + IWL_RATE_##rp##M_INDEX, \ + IWL_RATE_##rn##M_INDEX, \ + IWL_RATE_##pp##M_INDEX, \ + IWL_RATE_##np##M_INDEX } + +/* + * Parameter order: + * rate, ht rate, prev rate, next rate, prev tgg rate, next tgg rate + * + * If there isn't a valid next or previous rate then INV is used which + * maps to IWL_RATE_INVALID + * + */ +const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] = { + IWL_DECLARE_RATE_INFO(1, INV, INV, 2, INV, 2, INV, 2), /* 1mbps */ + IWL_DECLARE_RATE_INFO(2, INV, 1, 5, 1, 5, 1, 5), /* 2mbps */ + IWL_DECLARE_RATE_INFO(5, INV, 2, 6, 2, 11, 2, 11), /*5.5mbps */ + IWL_DECLARE_RATE_INFO(11, INV, 9, 12, 9, 12, 5, 18), /* 11mbps */ + IWL_DECLARE_RATE_INFO(6, 6, 5, 9, 5, 11, 5, 11), /* 6mbps */ + IWL_DECLARE_RATE_INFO(9, 6, 6, 11, 6, 11, 5, 11), /* 9mbps */ + IWL_DECLARE_RATE_INFO(12, 12, 11, 18, 11, 18, 11, 18), /* 12mbps */ + IWL_DECLARE_RATE_INFO(18, 18, 12, 24, 12, 24, 11, 24), /* 18mbps */ + IWL_DECLARE_RATE_INFO(24, 24, 18, 36, 18, 36, 18, 36), /* 24mbps */ + IWL_DECLARE_RATE_INFO(36, 36, 24, 48, 24, 48, 24, 48), /* 36mbps */ + IWL_DECLARE_RATE_INFO(48, 48, 36, 54, 36, 54, 36, 54), /* 48mbps */ + IWL_DECLARE_RATE_INFO(54, 54, 48, INV, 48, INV, 48, INV),/* 54mbps */ + IWL_DECLARE_RATE_INFO(60, 60, 48, INV, 48, INV, 48, INV),/* 60mbps */ +}; + +static int is_fat_channel(__le32 rxon_flags) +{ + return (rxon_flags & RXON_FLG_CHANNEL_MODE_PURE_40_MSK) || + (rxon_flags & RXON_FLG_CHANNEL_MODE_MIXED_MSK); +} + +static u8 is_single_stream(struct iwl_priv *priv) +{ +#ifdef CONFIG_IWLWIFI_HT + if (!priv->is_ht_enabled || !priv->current_assoc_ht.is_ht || + (priv->active_rate_ht[1] == 0) || + (priv->ps_mode == IWL_MIMO_PS_STATIC)) + return 1; +#else + return 1; +#endif /*CONFIG_IWLWIFI_HT */ + return 0; +} + +/* + * Determine how many receiver/antenna chains to use. + * More provides better reception via diversity. Fewer saves power. + * MIMO (dual stream) requires at least 2, but works better with 3. + * This does not determine *which* chains to use, just how many. + */ +static int iwl4965_get_rx_chain_counter(struct iwl_priv *priv, + u8 *idle_state, u8 *rx_state) +{ + u8 is_single = is_single_stream(priv); + u8 is_cam = test_bit(STATUS_POWER_PMI, &priv->status) ? 0 : 1; + + /* # of Rx chains to use when expecting MIMO. */ + if (is_single || (!is_cam && (priv->ps_mode == IWL_MIMO_PS_STATIC))) + *rx_state = 2; + else + *rx_state = 3; + + /* # Rx chains when idling and maybe trying to save power */ + switch (priv->ps_mode) { + case IWL_MIMO_PS_STATIC: + case IWL_MIMO_PS_DYNAMIC: + *idle_state = (is_cam) ? 2 : 1; + break; + case IWL_MIMO_PS_NONE: + *idle_state = (is_cam) ? *rx_state : 1; + break; + default: + *idle_state = 1; + break; + } + + return 0; +} + +int iwl_hw_rxq_stop(struct iwl_priv *priv) +{ + int rc; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + rc = iwl_grab_restricted_access(priv); + if (rc) { + spin_unlock_irqrestore(&priv->lock, flags); + return rc; + } + + /* stop HW */ + iwl_write_restricted(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); + rc = iwl_poll_restricted_bit(priv, FH_MEM_RSSR_RX_STATUS_REG, + (1 << 24), 1000); + if (rc < 0) + IWL_ERROR("Can't stop Rx DMA.\n"); + + iwl_release_restricted_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +u8 iwl_hw_find_station(struct iwl_priv *priv, const u8 *addr) +{ + int i; + int start = 0; + int ret = IWL_INVALID_STATION; + unsigned long flags; + + if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) || + (priv->iw_mode == IEEE80211_IF_TYPE_AP)) + start = IWL_STA_ID; + + if (is_broadcast_ether_addr(addr)) + return IWL4965_BROADCAST_ID; + + spin_lock_irqsave(&priv->sta_lock, flags); + for (i = start; i < priv->hw_setting.max_stations; i++) + if ((priv->stations[i].used) && + (!compare_ether_addr + (priv->stations[i].sta.sta.addr, addr))) { + ret = i; + goto out; + } + + IWL_DEBUG_ASSOC("can not find STA " MAC_FMT " total %d\n", + MAC_ARG(addr), priv->num_stations); + + out: + spin_unlock_irqrestore(&priv->sta_lock, flags); + return ret; +} + +static int iwl4965_nic_set_pwr_src(struct iwl_priv *priv, int pwr_max) +{ + int rc = 0; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + rc = iwl_grab_restricted_access(priv); + if (rc) { + spin_unlock_irqrestore(&priv->lock, flags); + return rc; + } + + if (!pwr_max) { + u32 val; + + rc = pci_read_config_dword(priv->pci_dev, PCI_POWER_SOURCE, + &val); + + if (val & PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT) + iwl_set_bits_mask_restricted_reg( + priv, APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_PWR_SRC_VAUX, + ~APMG_PS_CTRL_MSK_PWR_SRC); + } else + iwl_set_bits_mask_restricted_reg( + priv, APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_PWR_SRC_VMAIN, + ~APMG_PS_CTRL_MSK_PWR_SRC); + + iwl_release_restricted_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + return rc; +} + +static int iwl4965_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) +{ + int rc; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + rc = iwl_grab_restricted_access(priv); + if (rc) { + spin_unlock_irqrestore(&priv->lock, flags); + return rc; + } + + /* stop HW */ + iwl_write_restricted(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); + + iwl_write_restricted(priv, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0); + iwl_write_restricted(priv, FH_RSCSR_CHNL0_RBDCB_BASE_REG, + rxq->dma_addr >> 8); + + iwl_write_restricted(priv, FH_RSCSR_CHNL0_STTS_WPTR_REG, + (priv->hw_setting.shared_phys + + offsetof(struct iwl_shared, val0)) >> 4); + + iwl_write_restricted(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, + FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL | + FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL | + IWL_FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K | + /*0x10 << 4 | */ + (RX_QUEUE_SIZE_LOG << + FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT)); + + /* + * iwl_write32(priv,CSR_INT_COAL_REG,0); + */ + + iwl_release_restricted_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +static int iwl4965_kw_init(struct iwl_priv *priv) +{ + unsigned long flags; + int rc; + + spin_lock_irqsave(&priv->lock, flags); + rc = iwl_grab_restricted_access(priv); + if (rc) + goto out; + + iwl_write_restricted(priv, IWL_FH_KW_MEM_ADDR_REG, + priv->kw.dma_addr >> 4); + iwl_release_restricted_access(priv); +out: + spin_unlock_irqrestore(&priv->lock, flags); + return rc; +} + +static int iwl4965_kw_alloc(struct iwl_priv *priv) +{ + struct pci_dev *dev = priv->pci_dev; + struct iwl_kw *kw = &priv->kw; + + kw->size = IWL4965_KW_SIZE; /* TBW need set somewhere else */ + kw->v_addr = pci_alloc_consistent(dev, kw->size, &kw->dma_addr); + if (!kw->v_addr) + return -ENOMEM; + + return 0; +} + +#define CHECK_AND_PRINT(x) ((eeprom_ch->flags & EEPROM_CHANNEL_##x) \ + ? # x " " : "") + +int iwl4965_set_fat_chan_info(struct iwl_priv *priv, int phymode, u16 channel, + const struct iwl_eeprom_channel *eeprom_ch, + u8 fat_extension_channel) +{ + struct iwl_channel_info *ch_info; + + ch_info = (struct iwl_channel_info *) + iwl_get_channel_info(priv, phymode, channel); + + if (!is_channel_valid(ch_info)) + return -1; + + IWL_DEBUG_INFO("FAT Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x" + " %ddBm): Ad-Hoc %ssupported\n", + ch_info->channel, + is_channel_a_band(ch_info) ? + "5.2" : "2.4", + CHECK_AND_PRINT(IBSS), + CHECK_AND_PRINT(ACTIVE), + CHECK_AND_PRINT(RADAR), + CHECK_AND_PRINT(WIDE), + CHECK_AND_PRINT(NARROW), + CHECK_AND_PRINT(DFS), + eeprom_ch->flags, + eeprom_ch->max_power_avg, + ((eeprom_ch->flags & EEPROM_CHANNEL_IBSS) + && !(eeprom_ch->flags & EEPROM_CHANNEL_RADAR)) ? + "" : "not "); + + ch_info->fat_eeprom = *eeprom_ch; + ch_info->fat_max_power_avg = eeprom_ch->max_power_avg; + ch_info->fat_curr_txpow = eeprom_ch->max_power_avg; + ch_info->fat_min_power = 0; + ch_info->fat_scan_power = eeprom_ch->max_power_avg; + ch_info->fat_flags = eeprom_ch->flags; + ch_info->fat_extension_channel = fat_extension_channel; + + return 0; +} + +static void iwl4965_kw_free(struct iwl_priv *priv) +{ + struct pci_dev *dev = priv->pci_dev; + struct iwl_kw *kw = &priv->kw; + + if (kw->v_addr) { + pci_free_consistent(dev, kw->size, kw->v_addr, kw->dma_addr); + memset(kw, 0, sizeof(*kw)); + } +} + +/** + * iwl4965_txq_ctx_reset - Reset TX queue context + * Destroys all DMA structures and initialise them again + * + * @param priv + * @return error code + */ +static int iwl4965_txq_ctx_reset(struct iwl_priv *priv) +{ + int rc = 0; + int txq_id, slots_num; + unsigned long flags; + + iwl4965_kw_free(priv); + + iwl_hw_txq_ctx_free(priv); + + /* Tx CMD queue */ + rc = iwl4965_kw_alloc(priv); + if (rc) { + IWL_ERROR("Keep Warm allocation failed"); + goto error_kw; + } + + spin_lock_irqsave(&priv->lock, flags); + + rc = iwl_grab_restricted_access(priv); + if (unlikely(rc)) { + IWL_ERROR("TX reset failed"); + spin_unlock_irqrestore(&priv->lock, flags); + goto error_reset; + } + + iwl_write_restricted_reg(priv, SCD_TXFACT, 0); + iwl_release_restricted_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + rc = iwl4965_kw_init(priv); + if (rc) { + IWL_ERROR("kw_init failed\n"); + goto error_reset; + } + + /* Tx queue(s) */ + for (txq_id = 0; txq_id < priv->hw_setting.max_txq_num; txq_id++) { + slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ? + TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; + rc = iwl_tx_queue_init(priv, &priv->txq[txq_id], slots_num, + txq_id); + if (rc) { + IWL_ERROR("Tx %d queue init failed\n", txq_id); + goto error; + } + } + + return rc; + + error: + iwl_hw_txq_ctx_free(priv); + error_reset: + iwl4965_kw_free(priv); + error_kw: + return rc; +} + +int iwl_hw_nic_init(struct iwl_priv *priv) +{ + int rc; + unsigned long flags; + struct iwl_rx_queue *rxq = &priv->rxq; + u8 rev_id; + u32 val; + u8 val_link; + + iwl_power_init_handle(priv); + + /* nic_init */ + spin_lock_irqsave(&priv->lock, flags); + + iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, + CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); + + iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + rc = iwl_poll_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + if (rc < 0) { + spin_unlock_irqrestore(&priv->lock, flags); + IWL_DEBUG_INFO("Failed to init the card\n"); + return rc; + } + + rc = iwl_grab_restricted_access(priv); + if (rc) { + spin_unlock_irqrestore(&priv->lock, flags); + return rc; + } + + iwl_read_restricted_reg(priv, APMG_CLK_CTRL_REG); + + iwl_write_restricted_reg(priv, APMG_CLK_CTRL_REG, + APMG_CLK_VAL_DMA_CLK_RQT | + APMG_CLK_VAL_BSM_CLK_RQT); + iwl_read_restricted_reg(priv, APMG_CLK_CTRL_REG); + + udelay(20); + + iwl_set_bits_restricted_reg(priv, APMG_PCIDEV_STT_REG, + APMG_PCIDEV_STT_VAL_L1_ACT_DIS); + + iwl_release_restricted_access(priv); + iwl_write32(priv, CSR_INT_COALESCING, 512 / 32); + spin_unlock_irqrestore(&priv->lock, flags); + + /* Determine HW type */ + rc = pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &rev_id); + if (rc) + return rc; + + IWL_DEBUG_INFO("HW Revision ID = 0x%X\n", rev_id); + + iwl4965_nic_set_pwr_src(priv, 1); + spin_lock_irqsave(&priv->lock, flags); + + if ((rev_id & 0x80) == 0x80 && (rev_id & 0x7f) < 8) { + pci_read_config_dword(priv->pci_dev, PCI_REG_WUM8, &val); + /* Enable No Snoop field */ + pci_write_config_dword(priv->pci_dev, PCI_REG_WUM8, + val & ~(1 << 11)); + } + + spin_unlock_irqrestore(&priv->lock, flags); + + /* Read the EEPROM */ + rc = iwl_eeprom_init(priv); + if (rc) + return rc; + + if (priv->eeprom.calib_version < EEPROM_TX_POWER_VERSION_NEW) { + IWL_ERROR("Older EEPROM detected! Aborting.\n"); + return -EINVAL; + } + + pci_read_config_byte(priv->pci_dev, PCI_LINK_CTRL, &val_link); + + /* disable L1 entry -- workaround for pre-B1 */ + pci_write_config_byte(priv->pci_dev, PCI_LINK_CTRL, val_link & ~0x02); + + spin_lock_irqsave(&priv->lock, flags); + + /* set CSR_HW_CONFIG_REG for uCode use */ + + iwl_set_bit(priv, CSR_SW_VER, CSR_HW_IF_CONFIG_REG_BIT_KEDRON_R | + CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI | + CSR_HW_IF_CONFIG_REG_BIT_MAC_SI); + + rc = iwl_grab_restricted_access(priv); + if (rc < 0) { + spin_unlock_irqrestore(&priv->lock, flags); + IWL_DEBUG_INFO("Failed to init the card\n"); + return rc; + } + + iwl_read_restricted_reg(priv, APMG_PS_CTRL_REG); + iwl_set_bits_restricted_reg(priv, APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_RESET_REQ); + udelay(5); + iwl_clear_bits_restricted_reg(priv, APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_RESET_REQ); + + iwl_release_restricted_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + iwl_hw_card_show_info(priv); + + /* end nic_init */ + + /* Allocate the RX queue, or reset if it is already allocated */ + if (!rxq->bd) { + rc = iwl_rx_queue_alloc(priv); + if (rc) { + IWL_ERROR("Unable to initialize Rx queue\n"); + return -ENOMEM; + } + } else + iwl_rx_queue_reset(priv, rxq); + + iwl_rx_replenish(priv); + + iwl4965_rx_init(priv, rxq); + + spin_lock_irqsave(&priv->lock, flags); + + rxq->need_update = 1; + iwl_rx_queue_update_write_ptr(priv, rxq); + + spin_unlock_irqrestore(&priv->lock, flags); + rc = iwl4965_txq_ctx_reset(priv); + if (rc) + return rc; + + if (priv->eeprom.sku_cap & EEPROM_SKU_CAP_SW_RF_KILL_ENABLE) + IWL_DEBUG_RF_KILL("SW RF KILL supported in EEPROM.\n"); + + if (priv->eeprom.sku_cap & EEPROM_SKU_CAP_HW_RF_KILL_ENABLE) + IWL_DEBUG_RF_KILL("HW RF KILL supported in EEPROM.\n"); + + set_bit(STATUS_INIT, &priv->status); + + return 0; +} + +int iwl_hw_nic_stop_master(struct iwl_priv *priv) +{ + int rc = 0; + u32 reg_val; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + + /* set stop master bit */ + iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); + + reg_val = iwl_read32(priv, CSR_GP_CNTRL); + + if (CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE == + (reg_val & CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE)) + IWL_DEBUG_INFO("Card in power save, master is already " + "stopped\n"); + else { + rc = iwl_poll_bit(priv, CSR_RESET, + CSR_RESET_REG_FLAG_MASTER_DISABLED, + CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); + if (rc < 0) { + spin_unlock_irqrestore(&priv->lock, flags); + return rc; + } + } + + spin_unlock_irqrestore(&priv->lock, flags); + IWL_DEBUG_INFO("stop master\n"); + + return rc; +} + +void iwl_hw_txq_ctx_stop(struct iwl_priv *priv) +{ + + int txq_id; + unsigned long flags; + + /* reset TFD queues */ + for (txq_id = 0; txq_id < priv->hw_setting.max_txq_num; txq_id++) { + spin_lock_irqsave(&priv->lock, flags); + if (iwl_grab_restricted_access(priv)) { + spin_unlock_irqrestore(&priv->lock, flags); + continue; + } + + iwl_write_restricted(priv, + IWL_FH_TCSR_CHNL_TX_CONFIG_REG(txq_id), + 0x0); + iwl_poll_restricted_bit(priv, IWL_FH_TSSR_TX_STATUS_REG, + IWL_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE + (txq_id), 200); + iwl_release_restricted_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + } + + iwl_hw_txq_ctx_free(priv); +} + +int iwl_hw_nic_reset(struct iwl_priv *priv) +{ + int rc = 0; + unsigned long flags; + + iwl_hw_nic_stop_master(priv); + + spin_lock_irqsave(&priv->lock, flags); + + iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); + + udelay(10); + + iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + rc = iwl_poll_bit(priv, CSR_RESET, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25); + + udelay(10); + + rc = iwl_grab_restricted_access(priv); + if (!rc) { + iwl_write_restricted_reg(priv, APMG_CLK_EN_REG, + APMG_CLK_VAL_DMA_CLK_RQT | + APMG_CLK_VAL_BSM_CLK_RQT); + + udelay(10); + + iwl_set_bits_restricted_reg(priv, APMG_PCIDEV_STT_REG, + APMG_PCIDEV_STT_VAL_L1_ACT_DIS); + + iwl_release_restricted_access(priv); + } + + clear_bit(STATUS_HCMD_ACTIVE, &priv->status); + wake_up_interruptible(&priv->wait_command_queue); + + spin_unlock_irqrestore(&priv->lock, flags); + + return rc; + +} + +#define REG_RECALIB_PERIOD (60) + +/** + * iwl4965_bg_statistics_periodic - Timer callback to queue statistics + * + * This callback is provided in order to queue the statistics_work + * in work_queue context (v. softirq) + * + * This timer function is continually reset to execute within + * REG_RECALIB_PERIOD seconds since the last STATISTICS_NOTIFICATION + * was received. We need to ensure we receive the statistics in order + * to update the temperature used for calibrating the TXPOWER. However, + * we can't send the statistics command from softirq context (which + * is the context which timers run at) so we have to queue off the + * statistics_work to actually send the command to the hardware. + */ +static void iwl4965_bg_statistics_periodic(unsigned long data) +{ + struct iwl_priv *priv = (struct iwl_priv *)data; + + queue_work(priv->workqueue, &priv->statistics_work); +} + +/** + * iwl4965_bg_statistics_work - Send the statistics request to the hardware. + * + * This is queued by iwl_bg_statistics_periodic. + */ +static void iwl4965_bg_statistics_work(struct work_struct *work) +{ + struct iwl_priv *priv = container_of(work, struct iwl_priv, + statistics_work); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + mutex_lock(&priv->mutex); + iwl_send_statistics_request(priv); + mutex_unlock(&priv->mutex); +} + +#define CT_LIMIT_CONST 259 +#define TM_CT_KILL_THRESHOLD 110 + +void iwl4965_rf_kill_ct_config(struct iwl_priv *priv) +{ + struct iwl_ct_kill_config cmd; + u32 R1, R2, R3; + u32 temp_th; + u32 crit_temperature; + unsigned long flags; + int rc = 0; + + spin_lock_irqsave(&priv->lock, flags); + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, + CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); + spin_unlock_irqrestore(&priv->lock, flags); + + if (priv->statistics.flag & STATISTICS_REPLY_FLG_FAT_MODE_MSK) { + R1 = (s32)le32_to_cpu(priv->card_alive_init.therm_r1[1]); + R2 = (s32)le32_to_cpu(priv->card_alive_init.therm_r2[1]); + R3 = (s32)le32_to_cpu(priv->card_alive_init.therm_r3[1]); + } else { + R1 = (s32)le32_to_cpu(priv->card_alive_init.therm_r1[0]); + R2 = (s32)le32_to_cpu(priv->card_alive_init.therm_r2[0]); + R3 = (s32)le32_to_cpu(priv->card_alive_init.therm_r3[0]); + } + + temp_th = CELSIUS_TO_KELVIN(TM_CT_KILL_THRESHOLD); + + crit_temperature = ((temp_th * (R3-R1))/CT_LIMIT_CONST) + R2; + cmd.critical_temperature_R = cpu_to_le32(crit_temperature); + rc = iwl_send_cmd_pdu(priv, + REPLY_CT_KILL_CONFIG_CMD, sizeof(cmd), &cmd); + if (rc) + IWL_ERROR("REPLY_CT_KILL_CONFIG_CMD failed\n"); + else + IWL_DEBUG_INFO("REPLY_CT_KILL_CONFIG_CMD succeeded\n"); +} + +#ifdef CONFIG_IWLWIFI_SENSITIVITY + +/* "false alarms" are signals that our DSP tries to lock onto, + * but then determines that they are either noise, or transmissions + * from a distant wireless network (also "noise", really) that get + * "stepped on" by stronger transmissions within our own network. + * This algorithm attempts to set a sensitivity level that is high + * enough to receive all of our own network traffic, but not so + * high that our DSP gets too busy trying to lock onto non-network + * activity/noise. */ +static int iwl4965_sens_energy_cck(struct iwl_priv *priv, + u32 norm_fa, + u32 rx_enable_time, + struct statistics_general_data *rx_info) +{ + u32 max_nrg_cck = 0; + int i = 0; + u8 max_silence_rssi = 0; + u32 silence_ref = 0; + u8 silence_rssi_a = 0; + u8 silence_rssi_b = 0; + u8 silence_rssi_c = 0; + u32 val; + + /* "false_alarms" values below are cross-multiplications to assess the + * numbers of false alarms within the measured period of actual Rx + * (Rx is off when we're txing), vs the min/max expected false alarms + * (some should be expected if rx is sensitive enough) in a + * hypothetical listening period of 200 time units (TU), 204.8 msec: + * + * MIN_FA/fixed-time < false_alarms/actual-rx-time < MAX_FA/beacon-time + * + * */ + u32 false_alarms = norm_fa * 200 * 1024; + u32 max_false_alarms = MAX_FA_CCK * rx_enable_time; + u32 min_false_alarms = MIN_FA_CCK * rx_enable_time; + struct iwl_sensitivity_data *data = NULL; + + data = &(priv->sensitivity_data); + + data->nrg_auto_corr_silence_diff = 0; + + /* Find max silence rssi among all 3 receivers. + * This is background noise, which may include transmissions from other + * networks, measured during silence before our network's beacon */ + silence_rssi_a = (u8)((rx_info->beacon_silence_rssi_a & + ALL_BAND_FILTER)>>8); + silence_rssi_b = (u8)((rx_info->beacon_silence_rssi_b & + ALL_BAND_FILTER)>>8); + silence_rssi_c = (u8)((rx_info->beacon_silence_rssi_c & + ALL_BAND_FILTER)>>8); + + val = max(silence_rssi_b, silence_rssi_c); + max_silence_rssi = max(silence_rssi_a, (u8) val); + + /* Store silence rssi in 20-beacon history table */ + data->nrg_silence_rssi[data->nrg_silence_idx] = max_silence_rssi; + data->nrg_silence_idx++; + if (data->nrg_silence_idx >= NRG_NUM_PREV_STAT_L) + data->nrg_silence_idx = 0; + + /* Find max silence rssi across 20 beacon history */ + for (i = 0; i < NRG_NUM_PREV_STAT_L; i++) { + val = data->nrg_silence_rssi[i]; + silence_ref = max(silence_ref, val); + } + IWL_DEBUG_CALIB("silence a %u, b %u, c %u, 20-bcn max %u\n", + silence_rssi_a, silence_rssi_b, silence_rssi_c, + silence_ref); + + /* Find max rx energy (min value!) among all 3 receivers, + * measured during beacon frame. + * Save it in 10-beacon history table. */ + i = data->nrg_energy_idx; + val = min(rx_info->beacon_energy_b, rx_info->beacon_energy_c); + data->nrg_value[i] = min(rx_info->beacon_energy_a, val); + + data->nrg_energy_idx++; + if (data->nrg_energy_idx >= 10) + data->nrg_energy_idx = 0; + + /* Find min rx energy (max value) across 10 beacon history. + * This is the minimum signal level that we want to receive well. + * Add backoff (margin so we don't miss slightly lower energy frames). + * This establishes an upper bound (min value) for energy threshold. */ + max_nrg_cck = data->nrg_value[0]; + for (i = 1; i < 10; i++) + max_nrg_cck = (u32) max(max_nrg_cck, (data->nrg_value[i])); + max_nrg_cck += 6; + + IWL_DEBUG_CALIB("rx energy a %u, b %u, c %u, 10-bcn max/min %u\n", + rx_info->beacon_energy_a, rx_info->beacon_energy_b, + rx_info->beacon_energy_c, max_nrg_cck - 6); + + /* Count number of consecutive beacons with fewer-than-desired + * false alarms. */ + if (false_alarms < min_false_alarms) + data->num_in_cck_no_fa++; + else + data->num_in_cck_no_fa = 0; + IWL_DEBUG_CALIB("consecutive bcns with few false alarms = %u\n", + data->num_in_cck_no_fa); + + /* If we got too many false alarms this time, reduce sensitivity */ + if (false_alarms > max_false_alarms) { + IWL_DEBUG_CALIB("norm FA %u > max FA %u\n", + false_alarms, max_false_alarms); + IWL_DEBUG_CALIB("... reducing sensitivity\n"); + data->nrg_curr_state = IWL_FA_TOO_MANY; + + if (data->auto_corr_cck > AUTO_CORR_MAX_TH_CCK) { + /* Store for "fewer than desired" on later beacon */ + data->nrg_silence_ref = silence_ref; + + /* increase energy threshold (reduce nrg value) + * to decrease sensitivity */ + if (data->nrg_th_cck > (NRG_MAX_CCK + NRG_STEP_CCK)) + data->nrg_th_cck = data->nrg_th_cck + - NRG_STEP_CCK; + } + + /* increase auto_corr values to decrease sensitivity */ + if (data->auto_corr_cck < AUTO_CORR_MAX_TH_CCK) + data->auto_corr_cck = AUTO_CORR_MAX_TH_CCK + 1; + else { + val = data->auto_corr_cck + AUTO_CORR_STEP_CCK; + data->auto_corr_cck = min((u32)AUTO_CORR_MAX_CCK, val); + } + val = data->auto_corr_cck_mrc + AUTO_CORR_STEP_CCK; + data->auto_corr_cck_mrc = min((u32)AUTO_CORR_MAX_CCK_MRC, val); + + /* Else if we got fewer than desired, increase sensitivity */ + } else if (false_alarms < min_false_alarms) { + data->nrg_curr_state = IWL_FA_TOO_FEW; + + /* Compare silence level with silence level for most recent + * healthy number or too many false alarms */ + data->nrg_auto_corr_silence_diff = (s32)data->nrg_silence_ref - + (s32)silence_ref; + + IWL_DEBUG_CALIB("norm FA %u < min FA %u, silence diff %d\n", + false_alarms, min_false_alarms, + data->nrg_auto_corr_silence_diff); + + /* Increase value to increase sensitivity, but only if: + * 1a) previous beacon did *not* have *too many* false alarms + * 1b) AND there's a significant difference in Rx levels + * from a previous beacon with too many, or healthy # FAs + * OR 2) We've seen a lot of beacons (100) with too few + * false alarms */ + if ((data->nrg_prev_state != IWL_FA_TOO_MANY) && + ((data->nrg_auto_corr_silence_diff > NRG_DIFF) || + (data->num_in_cck_no_fa > MAX_NUMBER_CCK_NO_FA))) { + + IWL_DEBUG_CALIB("... increasing sensitivity\n"); + /* Increase nrg value to increase sensitivity */ + val = data->nrg_th_cck + NRG_STEP_CCK; + data->nrg_th_cck = min((u32)NRG_MIN_CCK, val); + + /* Decrease auto_corr values to increase sensitivity */ + val = data->auto_corr_cck - AUTO_CORR_STEP_CCK; + data->auto_corr_cck = max((u32)AUTO_CORR_MIN_CCK, val); + + val = data->auto_corr_cck_mrc - AUTO_CORR_STEP_CCK; + data->auto_corr_cck_mrc = + max((u32)AUTO_CORR_MIN_CCK_MRC, val); + + } else + IWL_DEBUG_CALIB("... but not changing sensitivity\n"); + + /* Else we got a healthy number of false alarms, keep status quo */ + } else { + IWL_DEBUG_CALIB(" FA in safe zone\n"); + data->nrg_curr_state = IWL_FA_GOOD_RANGE; + + /* Store for use in "fewer than desired" with later beacon */ + data->nrg_silence_ref = silence_ref; + + /* If previous beacon had too many false alarms, + * give it some extra margin by reducing sensitivity again + * (but don't go below measured energy of desired Rx) */ + if (IWL_FA_TOO_MANY == data->nrg_prev_state) { + IWL_DEBUG_CALIB("... increasing margin\n"); + data->nrg_th_cck -= NRG_MARGIN; + } + } + + /* Make sure the energy threshold does not go above the measured + * energy of the desired Rx signals (reduced by backoff margin), + * or else we might start missing Rx frames. + * Lower value is higher energy, so we use max()! + */ + data->nrg_th_cck = max(max_nrg_cck, data->nrg_th_cck); + IWL_DEBUG_CALIB("new nrg_th_cck %u\n", data->nrg_th_cck); + + data->nrg_prev_state = data->nrg_curr_state; + + return 0; +} + + +static int iwl4965_sens_auto_corr_ofdm(struct iwl_priv *priv, + u32 norm_fa, + u32 rx_enable_time) +{ + u32 val; + u32 false_alarms = norm_fa * 200 * 1024; + u32 max_false_alarms = MAX_FA_OFDM * rx_enable_time; + u32 min_false_alarms = MIN_FA_OFDM * rx_enable_time; + struct iwl_sensitivity_data *data = NULL; + + data = &(priv->sensitivity_data); + + /* If we got too many false alarms this time, reduce sensitivity */ + if (false_alarms > max_false_alarms) { + + IWL_DEBUG_CALIB("norm FA %u > max FA %u)\n", + false_alarms, max_false_alarms); + + val = data->auto_corr_ofdm + AUTO_CORR_STEP_OFDM; + data->auto_corr_ofdm = + min((u32)AUTO_CORR_MAX_OFDM, val); + + val = data->auto_corr_ofdm_mrc + AUTO_CORR_STEP_OFDM; + data->auto_corr_ofdm_mrc = + min((u32)AUTO_CORR_MAX_OFDM_MRC, val); + + val = data->auto_corr_ofdm_x1 + AUTO_CORR_STEP_OFDM; + data->auto_corr_ofdm_x1 = + min((u32)AUTO_CORR_MAX_OFDM_X1, val); + + val = data->auto_corr_ofdm_mrc_x1 + AUTO_CORR_STEP_OFDM; + data->auto_corr_ofdm_mrc_x1 = + min((u32)AUTO_CORR_MAX_OFDM_MRC_X1, val); + } + + /* Else if we got fewer than desired, increase sensitivity */ + else if (false_alarms < min_false_alarms) { + + IWL_DEBUG_CALIB("norm FA %u < min FA %u\n", + false_alarms, min_false_alarms); + + val = data->auto_corr_ofdm - AUTO_CORR_STEP_OFDM; + data->auto_corr_ofdm = + max((u32)AUTO_CORR_MIN_OFDM, val); + + val = data->auto_corr_ofdm_mrc - AUTO_CORR_STEP_OFDM; + data->auto_corr_ofdm_mrc = + max((u32)AUTO_CORR_MIN_OFDM_MRC, val); + + val = data->auto_corr_ofdm_x1 - AUTO_CORR_STEP_OFDM; + data->auto_corr_ofdm_x1 = + max((u32)AUTO_CORR_MIN_OFDM_X1, val); + + val = data->auto_corr_ofdm_mrc_x1 - AUTO_CORR_STEP_OFDM; + data->auto_corr_ofdm_mrc_x1 = + max((u32)AUTO_CORR_MIN_OFDM_MRC_X1, val); + } + + else + IWL_DEBUG_CALIB("min FA %u < norm FA %u < max FA %u OK\n", + min_false_alarms, false_alarms, max_false_alarms); + + return 0; +} + +static int iwl_sensitivity_callback(struct iwl_priv *priv, + struct iwl_cmd *cmd, struct sk_buff *skb) +{ + /* We didn't cache the SKB; let the caller free it */ + return 1; +} + +/* Prepare a SENSITIVITY_CMD, send to uCode if values have changed */ +static int iwl4965_sensitivity_write(struct iwl_priv *priv, u8 flags) +{ + int rc = 0; + struct iwl_sensitivity_cmd cmd ; + struct iwl_sensitivity_data *data = NULL; + struct iwl_host_cmd cmd_out = { + .id = SENSITIVITY_CMD, + .len = sizeof(struct iwl_sensitivity_cmd), + .meta.flags = flags, + .data = &cmd, + }; + + data = &(priv->sensitivity_data); + + memset(&cmd, 0, sizeof(cmd)); + + cmd.table[HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX] = + cpu_to_le16((u16)data->auto_corr_ofdm); + cmd.table[HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX] = + cpu_to_le16((u16)data->auto_corr_ofdm_mrc); + cmd.table[HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX] = + cpu_to_le16((u16)data->auto_corr_ofdm_x1); + cmd.table[HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX] = + cpu_to_le16((u16)data->auto_corr_ofdm_mrc_x1); + + cmd.table[HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX] = + cpu_to_le16((u16)data->auto_corr_cck); + cmd.table[HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX] = + cpu_to_le16((u16)data->auto_corr_cck_mrc); + + cmd.table[HD_MIN_ENERGY_CCK_DET_INDEX] = + cpu_to_le16((u16)data->nrg_th_cck); + cmd.table[HD_MIN_ENERGY_OFDM_DET_INDEX] = + cpu_to_le16((u16)data->nrg_th_ofdm); + + cmd.table[HD_BARKER_CORR_TH_ADD_MIN_INDEX] = + __constant_cpu_to_le16(190); + cmd.table[HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX] = + __constant_cpu_to_le16(390); + cmd.table[HD_OFDM_ENERGY_TH_IN_INDEX] = + __constant_cpu_to_le16(62); + + IWL_DEBUG_CALIB("ofdm: ac %u mrc %u x1 %u mrc_x1 %u thresh %u\n", + data->auto_corr_ofdm, data->auto_corr_ofdm_mrc, + data->auto_corr_ofdm_x1, data->auto_corr_ofdm_mrc_x1, + data->nrg_th_ofdm); + + IWL_DEBUG_CALIB("cck: ac %u mrc %u thresh %u\n", + data->auto_corr_cck, data->auto_corr_cck_mrc, + data->nrg_th_cck); + + cmd.control = SENSITIVITY_CMD_CONTROL_WORK_TABLE; + + if (flags & CMD_ASYNC) + cmd_out.meta.u.callback = iwl_sensitivity_callback; + + /* Don't send command to uCode if nothing has changed */ + if (!memcmp(&cmd.table[0], &(priv->sensitivity_tbl[0]), + sizeof(u16)*HD_TABLE_SIZE)) { + IWL_DEBUG_CALIB("No change in SENSITIVITY_CMD\n"); + return 0; + } + + /* Copy table for comparison next time */ + memcpy(&(priv->sensitivity_tbl[0]), &(cmd.table[0]), + sizeof(u16)*HD_TABLE_SIZE); + + rc = iwl_send_cmd(priv, &cmd_out); + if (!rc) { + IWL_DEBUG_CALIB("SENSITIVITY_CMD succeeded\n"); + return rc; + } + + return 0; +} + +void iwl4965_init_sensitivity(struct iwl_priv *priv, u8 flags, u8 force) +{ + int rc = 0; + int i; + struct iwl_sensitivity_data *data = NULL; + + IWL_DEBUG_CALIB("Start iwl4965_init_sensitivity\n"); + + if (force) + memset(&(priv->sensitivity_tbl[0]), 0, + sizeof(u16)*HD_TABLE_SIZE); + + /* Clear driver's sensitivity algo data */ + data = &(priv->sensitivity_data); + memset(data, 0, sizeof(struct iwl_sensitivity_data)); + + data->num_in_cck_no_fa = 0; + data->nrg_curr_state = IWL_FA_TOO_MANY; + data->nrg_prev_state = IWL_FA_TOO_MANY; + data->nrg_silence_ref = 0; + data->nrg_silence_idx = 0; + data->nrg_energy_idx = 0; + + for (i = 0; i < 10; i++) + data->nrg_value[i] = 0; + + for (i = 0; i < NRG_NUM_PREV_STAT_L; i++) + data->nrg_silence_rssi[i] = 0; + + data->auto_corr_ofdm = 90; + data->auto_corr_ofdm_mrc = 170; + data->auto_corr_ofdm_x1 = 105; + data->auto_corr_ofdm_mrc_x1 = 220; + data->auto_corr_cck = AUTO_CORR_CCK_MIN_VAL_DEF; + data->auto_corr_cck_mrc = 200; + data->nrg_th_cck = 100; + data->nrg_th_ofdm = 100; + + data->last_bad_plcp_cnt_ofdm = 0; + data->last_fa_cnt_ofdm = 0; + data->last_bad_plcp_cnt_cck = 0; + data->last_fa_cnt_cck = 0; + + /* Clear prior Sensitivity command data to force send to uCode */ + if (force) + memset(&(priv->sensitivity_tbl[0]), 0, + sizeof(u16)*HD_TABLE_SIZE); + + rc |= iwl4965_sensitivity_write(priv, flags); + IWL_DEBUG_CALIB("<chain_noise_data); + if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl_is_associated(priv)) { + struct iwl_calibration_cmd cmd; + + memset(&cmd, 0, sizeof(cmd)); + cmd.opCode = PHY_CALIBRATE_DIFF_GAIN_CMD; + cmd.diff_gain_a = 0; + cmd.diff_gain_b = 0; + cmd.diff_gain_c = 0; + rc = iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, + sizeof(cmd), &cmd); + msleep(4); + data->state = IWL_CHAIN_NOISE_ACCUMULATE; + IWL_DEBUG_CALIB("Run chain_noise_calibrate\n"); + } + return; +} + +/* + * Accumulate 20 beacons of signal and noise statistics for each of + * 3 receivers/antennas/rx-chains, then figure out: + * 1) Which antennas are connected. + * 2) Differential rx gain settings to balance the 3 receivers. + */ +static void iwl4965_noise_calibration(struct iwl_priv *priv, + struct iwl_notif_statistics *stat_resp) +{ + struct iwl_chain_noise_data *data = NULL; + int rc = 0; + + u32 chain_noise_a; + u32 chain_noise_b; + u32 chain_noise_c; + u32 chain_sig_a; + u32 chain_sig_b; + u32 chain_sig_c; + u32 average_sig[NUM_RX_CHAINS] = {INITIALIZATION_VALUE}; + u32 average_noise[NUM_RX_CHAINS] = {INITIALIZATION_VALUE}; + u32 max_average_sig; + u16 max_average_sig_antenna_i; + u32 min_average_noise = MIN_AVERAGE_NOISE_MAX_VALUE; + u16 min_average_noise_antenna_i = INITIALIZATION_VALUE; + u16 i = 0; + u16 chan_num = INITIALIZATION_VALUE; + u32 band = INITIALIZATION_VALUE; + u32 active_chains = 0; + unsigned long flags; + struct statistics_rx_non_phy *rx_info = &(stat_resp->rx.general); + + data = &(priv->chain_noise_data); + + /* Accumulate just the first 20 beacons after the first association, + * then we're done forever. */ + if (data->state != IWL_CHAIN_NOISE_ACCUMULATE) { + if (data->state == IWL_CHAIN_NOISE_ALIVE) + IWL_DEBUG_CALIB("Wait for noise calib reset\n"); + return; + } + + spin_lock_irqsave(&priv->lock, flags); + if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) { + IWL_DEBUG_CALIB(" << Interference data unavailable\n"); + spin_unlock_irqrestore(&priv->lock, flags); + return; + } + + band = (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) ? 0 : 1; + chan_num = le16_to_cpu(priv->staging_rxon.channel); + + /* Make sure we accumulate data for just the associated channel + * (even if scanning). */ + if ((chan_num != (le32_to_cpu(stat_resp->flag) >> 16)) || + ((STATISTICS_REPLY_FLG_BAND_24G_MSK == + (stat_resp->flag & STATISTICS_REPLY_FLG_BAND_24G_MSK)) && band)) { + IWL_DEBUG_CALIB("Stats not from chan=%d, band=%d\n", + chan_num, band); + spin_unlock_irqrestore(&priv->lock, flags); + return; + } + + /* Accumulate beacon statistics values across 20 beacons */ + chain_noise_a = le32_to_cpu(rx_info->beacon_silence_rssi_a) & + IN_BAND_FILTER; + chain_noise_b = le32_to_cpu(rx_info->beacon_silence_rssi_b) & + IN_BAND_FILTER; + chain_noise_c = le32_to_cpu(rx_info->beacon_silence_rssi_c) & + IN_BAND_FILTER; + + chain_sig_a = le32_to_cpu(rx_info->beacon_rssi_a) & IN_BAND_FILTER; + chain_sig_b = le32_to_cpu(rx_info->beacon_rssi_b) & IN_BAND_FILTER; + chain_sig_c = le32_to_cpu(rx_info->beacon_rssi_c) & IN_BAND_FILTER; + + spin_unlock_irqrestore(&priv->lock, flags); + + data->beacon_count++; + + data->chain_noise_a = (chain_noise_a + data->chain_noise_a); + data->chain_noise_b = (chain_noise_b + data->chain_noise_b); + data->chain_noise_c = (chain_noise_c + data->chain_noise_c); + + data->chain_signal_a = (chain_sig_a + data->chain_signal_a); + data->chain_signal_b = (chain_sig_b + data->chain_signal_b); + data->chain_signal_c = (chain_sig_c + data->chain_signal_c); + + IWL_DEBUG_CALIB("chan=%d, band=%d, beacon=%d\n", chan_num, band, + data->beacon_count); + IWL_DEBUG_CALIB("chain_sig: a %d b %d c %d\n", + chain_sig_a, chain_sig_b, chain_sig_c); + IWL_DEBUG_CALIB("chain_noise: a %d b %d c %d\n", + chain_noise_a, chain_noise_b, chain_noise_c); + + /* If this is the 20th beacon, determine: + * 1) Disconnected antennas (using signal strengths) + * 2) Differential gain (using silence noise) to balance receivers */ + if (data->beacon_count == CAL_NUM_OF_BEACONS) { + + /* Analyze signal for disconnected antenna */ + average_sig[0] = (data->chain_signal_a) / CAL_NUM_OF_BEACONS; + average_sig[1] = (data->chain_signal_b) / CAL_NUM_OF_BEACONS; + average_sig[2] = (data->chain_signal_c) / CAL_NUM_OF_BEACONS; + + if (average_sig[0] >= average_sig[1]) { + max_average_sig = average_sig[0]; + max_average_sig_antenna_i = 0; + active_chains = (1 << max_average_sig_antenna_i); + } else { + max_average_sig = average_sig[1]; + max_average_sig_antenna_i = 1; + active_chains = (1 << max_average_sig_antenna_i); + } + + if (average_sig[2] >= max_average_sig) { + max_average_sig = average_sig[2]; + max_average_sig_antenna_i = 2; + active_chains = (1 << max_average_sig_antenna_i); + } + + IWL_DEBUG_CALIB("average_sig: a %d b %d c %d\n", + average_sig[0], average_sig[1], average_sig[2]); + IWL_DEBUG_CALIB("max_average_sig = %d, antenna %d\n", + max_average_sig, max_average_sig_antenna_i); + + /* Compare signal strengths for all 3 receivers. */ + for (i = 0; i < NUM_RX_CHAINS; i++) { + if (i != max_average_sig_antenna_i) { + s32 rssi_delta = (max_average_sig - + average_sig[i]); + + /* If signal is very weak, compared with + * strongest, mark it as disconnected. */ + if (rssi_delta > MAXIMUM_ALLOWED_PATHLOSS) + data->disconn_array[i] = 1; + else + active_chains |= (1 << i); + IWL_DEBUG_CALIB("i = %d rssiDelta = %d " + "disconn_array[i] = %d\n", + i, rssi_delta, data->disconn_array[i]); + } + } + + /*If both chains A & B are disconnected - + * connect B and leave A as is */ + if (data->disconn_array[CHAIN_A] && + data->disconn_array[CHAIN_B]) { + data->disconn_array[CHAIN_B] = 0; + active_chains |= (1 << CHAIN_B); + IWL_DEBUG_CALIB("both A & B chains are disconnected! " + "W/A - declare B as connected\n"); + } + + IWL_DEBUG_CALIB("active_chains (bitwise) = 0x%x\n", + active_chains); + + /* Save for use within RXON, TX, SCAN commands, etc. */ + priv->valid_antenna = active_chains; + + /* Analyze noise for rx balance */ + average_noise[0] = ((data->chain_noise_a)/CAL_NUM_OF_BEACONS); + average_noise[1] = ((data->chain_noise_b)/CAL_NUM_OF_BEACONS); + average_noise[2] = ((data->chain_noise_c)/CAL_NUM_OF_BEACONS); + + for (i = 0; i < NUM_RX_CHAINS; i++) { + if (!(data->disconn_array[i]) && + (average_noise[i] <= min_average_noise)) { + /* This means that chain i is active and has + * lower noise values so far: */ + min_average_noise = average_noise[i]; + min_average_noise_antenna_i = i; + } + } + + data->delta_gain_code[min_average_noise_antenna_i] = 0; + + IWL_DEBUG_CALIB("average_noise: a %d b %d c %d\n", + average_noise[0], average_noise[1], + average_noise[2]); + + IWL_DEBUG_CALIB("min_average_noise = %d, antenna %d\n", + min_average_noise, min_average_noise_antenna_i); + + for (i = 0; i < NUM_RX_CHAINS; i++) { + s32 delta_g = 0; + + if (!(data->disconn_array[i]) && + (data->delta_gain_code[i] == + CHAIN_NOISE_DELTA_GAIN_INIT_VAL)) { + delta_g = average_noise[i] - min_average_noise; + data->delta_gain_code[i] = (u8)((delta_g * + 10) / 15); + if (CHAIN_NOISE_MAX_DELTA_GAIN_CODE < + data->delta_gain_code[i]) + data->delta_gain_code[i] = + CHAIN_NOISE_MAX_DELTA_GAIN_CODE; + + data->delta_gain_code[i] = + (data->delta_gain_code[i] | (1 << 2)); + } else + data->delta_gain_code[i] = 0; + } + IWL_DEBUG_CALIB("delta_gain_codes: a %d b %d c %d\n", + data->delta_gain_code[0], + data->delta_gain_code[1], + data->delta_gain_code[2]); + + /* Differential gain gets sent to uCode only once */ + if (!data->radio_write) { + struct iwl_calibration_cmd cmd; + data->radio_write = 1; + + memset(&cmd, 0, sizeof(cmd)); + cmd.opCode = PHY_CALIBRATE_DIFF_GAIN_CMD; + cmd.diff_gain_a = data->delta_gain_code[0]; + cmd.diff_gain_b = data->delta_gain_code[1]; + cmd.diff_gain_c = data->delta_gain_code[2]; + rc = iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, + sizeof(cmd), &cmd); + if (rc) + IWL_DEBUG_CALIB("fail sending cmd " + "REPLY_PHY_CALIBRATION_CMD \n"); + + /* TODO we might want recalculate + * rx_chain in rxon cmd */ + + /* Mark so we run this algo only once! */ + data->state = IWL_CHAIN_NOISE_CALIBRATED; + } + data->chain_noise_a = 0; + data->chain_noise_b = 0; + data->chain_noise_c = 0; + data->chain_signal_a = 0; + data->chain_signal_b = 0; + data->chain_signal_c = 0; + data->beacon_count = 0; + } + return; +} + +static void iwl4965_sensitivity_calibration(struct iwl_priv *priv, + struct iwl_notif_statistics *resp) +{ + int rc = 0; + u32 rx_enable_time; + u32 fa_cck; + u32 fa_ofdm; + u32 bad_plcp_cck; + u32 bad_plcp_ofdm; + u32 norm_fa_ofdm; + u32 norm_fa_cck; + struct iwl_sensitivity_data *data = NULL; + struct statistics_rx_non_phy *rx_info = &(resp->rx.general); + struct statistics_rx *statistics = &(resp->rx); + unsigned long flags; + struct statistics_general_data statis; + + data = &(priv->sensitivity_data); + + if (!iwl_is_associated(priv)) { + IWL_DEBUG_CALIB("<< - not associated\n"); + return; + } + + spin_lock_irqsave(&priv->lock, flags); + if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) { + IWL_DEBUG_CALIB("<< invalid data.\n"); + spin_unlock_irqrestore(&priv->lock, flags); + return; + } + + /* Extract Statistics: */ + rx_enable_time = le32_to_cpu(rx_info->channel_load); + fa_cck = le32_to_cpu(statistics->cck.false_alarm_cnt); + fa_ofdm = le32_to_cpu(statistics->ofdm.false_alarm_cnt); + bad_plcp_cck = le32_to_cpu(statistics->cck.plcp_err); + bad_plcp_ofdm = le32_to_cpu(statistics->ofdm.plcp_err); + + statis.beacon_silence_rssi_a = + le32_to_cpu(statistics->general.beacon_silence_rssi_a); + statis.beacon_silence_rssi_b = + le32_to_cpu(statistics->general.beacon_silence_rssi_b); + statis.beacon_silence_rssi_c = + le32_to_cpu(statistics->general.beacon_silence_rssi_c); + statis.beacon_energy_a = + le32_to_cpu(statistics->general.beacon_energy_a); + statis.beacon_energy_b = + le32_to_cpu(statistics->general.beacon_energy_b); + statis.beacon_energy_c = + le32_to_cpu(statistics->general.beacon_energy_c); + + spin_unlock_irqrestore(&priv->lock, flags); + + IWL_DEBUG_CALIB("rx_enable_time = %u usecs\n", rx_enable_time); + + if (!rx_enable_time) { + IWL_DEBUG_CALIB("<< RX Enable Time == 0! \n"); + return; + } + + /* These statistics increase monotonically, and do not reset + * at each beacon. Calculate difference from last value, or just + * use the new statistics value if it has reset or wrapped around. */ + if (data->last_bad_plcp_cnt_cck > bad_plcp_cck) + data->last_bad_plcp_cnt_cck = bad_plcp_cck; + else { + bad_plcp_cck -= data->last_bad_plcp_cnt_cck; + data->last_bad_plcp_cnt_cck += bad_plcp_cck; + } + + if (data->last_bad_plcp_cnt_ofdm > bad_plcp_ofdm) + data->last_bad_plcp_cnt_ofdm = bad_plcp_ofdm; + else { + bad_plcp_ofdm -= data->last_bad_plcp_cnt_ofdm; + data->last_bad_plcp_cnt_ofdm += bad_plcp_ofdm; + } + + if (data->last_fa_cnt_ofdm > fa_ofdm) + data->last_fa_cnt_ofdm = fa_ofdm; + else { + fa_ofdm -= data->last_fa_cnt_ofdm; + data->last_fa_cnt_ofdm += fa_ofdm; + } + + if (data->last_fa_cnt_cck > fa_cck) + data->last_fa_cnt_cck = fa_cck; + else { + fa_cck -= data->last_fa_cnt_cck; + data->last_fa_cnt_cck += fa_cck; + } + + /* Total aborted signal locks */ + norm_fa_ofdm = fa_ofdm + bad_plcp_ofdm; + norm_fa_cck = fa_cck + bad_plcp_cck; + + IWL_DEBUG_CALIB("cck: fa %u badp %u ofdm: fa %u badp %u\n", fa_cck, + bad_plcp_cck, fa_ofdm, bad_plcp_ofdm); + + iwl4965_sens_auto_corr_ofdm(priv, norm_fa_ofdm, rx_enable_time); + iwl4965_sens_energy_cck(priv, norm_fa_cck, rx_enable_time, &statis); + rc |= iwl4965_sensitivity_write(priv, CMD_ASYNC); + + return; +} + +static void iwl4965_bg_sensitivity_work(struct work_struct *work) +{ + struct iwl_priv *priv = container_of(work, struct iwl_priv, + sensitivity_work); + + mutex_lock(&priv->mutex); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status) || + test_bit(STATUS_SCANNING, &priv->status)) { + mutex_unlock(&priv->mutex); + return; + } + + if (priv->start_calib) { + iwl4965_noise_calibration(priv, &priv->statistics); + + if (priv->sensitivity_data.state == + IWL_SENS_CALIB_NEED_REINIT) { + iwl4965_init_sensitivity(priv, CMD_ASYNC, 0); + priv->sensitivity_data.state = IWL_SENS_CALIB_ALLOWED; + } else + iwl4965_sensitivity_calibration(priv, + &priv->statistics); + } + + mutex_unlock(&priv->mutex); + return; +} +#endif /*CONFIG_IWLWIFI_SENSITIVITY*/ + +static void iwl4965_bg_txpower_work(struct work_struct *work) +{ + struct iwl_priv *priv = container_of(work, struct iwl_priv, + txpower_work); + + /* If a scan happened to start before we got here + * then just return; the statistics notification will + * kick off another scheduled work to compensate for + * any temperature delta we missed here. */ + if (test_bit(STATUS_EXIT_PENDING, &priv->status) || + test_bit(STATUS_SCANNING, &priv->status)) + return; + + mutex_lock(&priv->mutex); + + /* Regardless of if we are assocaited, we must reconfigure the + * TX power since frames can be sent on non-radar channels while + * not associated */ + iwl_hw_reg_send_txpower(priv); + + /* Update last_temperature to keep is_calib_needed from running + * when it isn't needed... */ + priv->last_temperature = priv->temperature; + + mutex_unlock(&priv->mutex); +} + +/* + * Acquire priv->lock before calling this function ! + */ +static void iwl4965_set_wr_ptrs(struct iwl_priv *priv, int txq_id, u32 index) +{ + iwl_write_restricted(priv, HBUS_TARG_WRPTR, + (index & 0xff) | (txq_id << 8)); + iwl_write_restricted_reg(priv, SCD_QUEUE_RDPTR(txq_id), index); +} + +/* + * Acquire priv->lock before calling this function ! + */ +static void iwl4965_tx_queue_set_status(struct iwl_priv *priv, + struct iwl_tx_queue *txq, + int tx_fifo_id, int scd_retry) +{ + int txq_id = txq->q.id; + int active = test_bit(txq_id, &priv->txq_ctx_active_msk)?1:0; + + iwl_write_restricted_reg(priv, SCD_QUEUE_STATUS_BITS(txq_id), + (active << SCD_QUEUE_STTS_REG_POS_ACTIVE) | + (tx_fifo_id << SCD_QUEUE_STTS_REG_POS_TXF) | + (scd_retry << SCD_QUEUE_STTS_REG_POS_WSL) | + (scd_retry << SCD_QUEUE_STTS_REG_POS_SCD_ACK) | + SCD_QUEUE_STTS_REG_MSK); + + txq->sched_retry = scd_retry; + + IWL_DEBUG_INFO("%s %s Queue %d on AC %d\n", + active ? "Activete" : "Deactivate", + scd_retry ? "BA" : "AC", txq_id, tx_fifo_id); +} + +static const u16 default_queue_to_tx_fifo[] = { + IWL_TX_FIFO_AC3, + IWL_TX_FIFO_AC2, + IWL_TX_FIFO_AC1, + IWL_TX_FIFO_AC0, + IWL_CMD_FIFO_NUM, + IWL_TX_FIFO_HCCA_1, + IWL_TX_FIFO_HCCA_2 +}; + +static inline void iwl4965_txq_ctx_activate(struct iwl_priv *priv, int txq_id) +{ + set_bit(txq_id, &priv->txq_ctx_active_msk); +} + +static inline void iwl4965_txq_ctx_deactivate(struct iwl_priv *priv, int txq_id) +{ + clear_bit(txq_id, &priv->txq_ctx_active_msk); +} + +int iwl4965_alive_notify(struct iwl_priv *priv) +{ + u32 a; + int i = 0; + unsigned long flags; + int rc; + + spin_lock_irqsave(&priv->lock, flags); + +#ifdef CONFIG_IWLWIFI_SENSITIVITY + memset(&(priv->sensitivity_data), 0, + sizeof(struct iwl_sensitivity_data)); + memset(&(priv->chain_noise_data), 0, + sizeof(struct iwl_chain_noise_data)); + for (i = 0; i < NUM_RX_CHAINS; i++) + priv->chain_noise_data.delta_gain_code[i] = + CHAIN_NOISE_DELTA_GAIN_INIT_VAL; +#endif /* CONFIG_IWLWIFI_SENSITIVITY*/ + rc = iwl_grab_restricted_access(priv); + if (rc) { + spin_unlock_irqrestore(&priv->lock, flags); + return rc; + } + + priv->scd_base_addr = iwl_read_restricted_reg(priv, SCD_SRAM_BASE_ADDR); + a = priv->scd_base_addr + SCD_CONTEXT_DATA_OFFSET; + for (; a < priv->scd_base_addr + SCD_TX_STTS_BITMAP_OFFSET; a += 4) + iwl_write_restricted_mem(priv, a, 0); + for (; a < priv->scd_base_addr + SCD_TRANSLATE_TBL_OFFSET; a += 4) + iwl_write_restricted_mem(priv, a, 0); + for (; a < sizeof(u16) * priv->hw_setting.max_txq_num; a += 4) + iwl_write_restricted_mem(priv, a, 0); + + iwl_write_restricted_reg(priv, SCD_DRAM_BASE_ADDR, + (priv->hw_setting.shared_phys + + offsetof(struct iwl_shared, queues_byte_cnt_tbls)) >> 10); + iwl_write_restricted_reg(priv, SCD_QUEUECHAIN_SEL, 0); + + /* initiate the queues */ + for (i = 0; i < priv->hw_setting.max_txq_num; i++) { + iwl_write_restricted_reg(priv, SCD_QUEUE_RDPTR(i), 0); + iwl_write_restricted(priv, HBUS_TARG_WRPTR, 0 | (i << 8)); + iwl_write_restricted_mem(priv, priv->scd_base_addr + + SCD_CONTEXT_QUEUE_OFFSET(i), + (SCD_WIN_SIZE << + SCD_QUEUE_CTX_REG1_WIN_SIZE_POS) & + SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK); + iwl_write_restricted_mem(priv, priv->scd_base_addr + + SCD_CONTEXT_QUEUE_OFFSET(i) + + sizeof(u32), + (SCD_FRAME_LIMIT << + SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) & + SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK); + + } + iwl_write_restricted_reg(priv, SCD_INTERRUPT_MASK, + (1 << priv->hw_setting.max_txq_num) - 1); + + iwl_write_restricted_reg(priv, SCD_TXFACT, + SCD_TXFACT_REG_TXFIFO_MASK(0, 7)); + + iwl4965_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0); + /* map qos queues to fifos one-to-one */ + for (i = 0; i < ARRAY_SIZE(default_queue_to_tx_fifo); i++) { + int ac = default_queue_to_tx_fifo[i]; + iwl4965_txq_ctx_activate(priv, i); + iwl4965_tx_queue_set_status(priv, &priv->txq[i], ac, 0); + } + + iwl_release_restricted_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +int iwl_hw_set_hw_setting(struct iwl_priv *priv) +{ + priv->hw_setting.shared_virt = + pci_alloc_consistent(priv->pci_dev, + sizeof(struct iwl_shared), + &priv->hw_setting.shared_phys); + + if (!priv->hw_setting.shared_virt) + return -1; + + memset(priv->hw_setting.shared_virt, 0, sizeof(struct iwl_shared)); + + priv->hw_setting.max_txq_num = iwl_param_queues_num; + priv->hw_setting.ac_queue_count = AC_NUM; + + priv->hw_setting.cck_flag = RATE_MCS_CCK_MSK; + priv->hw_setting.tx_cmd_len = sizeof(struct iwl_tx_cmd); + priv->hw_setting.max_rxq_size = RX_QUEUE_SIZE; + priv->hw_setting.max_rxq_log = RX_QUEUE_SIZE_LOG; + + priv->hw_setting.max_stations = IWL4965_STATION_COUNT; + priv->hw_setting.bcast_sta_id = IWL4965_BROADCAST_ID; + return 0; +} + +/** + * iwl_hw_txq_ctx_free - Free TXQ Context + * + * Destroy all TX DMA queues and structures + */ +void iwl_hw_txq_ctx_free(struct iwl_priv *priv) +{ + int txq_id; + + /* Tx queues */ + for (txq_id = 0; txq_id < priv->hw_setting.max_txq_num; txq_id++) + iwl_tx_queue_free(priv, &priv->txq[txq_id]); + + iwl4965_kw_free(priv); +} + +/** + * iwl_hw_txq_free_tfd - Free one TFD, those at index [txq->q.last_used] + * + * Does NOT advance any indexes + */ +int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) +{ + struct iwl_tfd_frame *bd_tmp = (struct iwl_tfd_frame *)&txq->bd[0]; + struct iwl_tfd_frame *bd = &bd_tmp[txq->q.last_used]; + struct pci_dev *dev = priv->pci_dev; + int i; + int counter = 0; + int index, is_odd; + + /* classify bd */ + if (txq->q.id == IWL_CMD_QUEUE_NUM) + /* nothing to cleanup after for host commands */ + return 0; + + /* sanity check */ + counter = IWL_GET_BITS(*bd, num_tbs); + if (counter > MAX_NUM_OF_TBS) { + IWL_ERROR("Too many chunks: %i\n", counter); + /* @todo issue fatal error, it is quite serious situation */ + return 0; + } + + /* unmap chunks if any */ + + for (i = 0; i < counter; i++) { + index = i / 2; + is_odd = i & 0x1; + + if (is_odd) + pci_unmap_single( + dev, + IWL_GET_BITS(bd->pa[index], tb2_addr_lo16) | + (IWL_GET_BITS(bd->pa[index], + tb2_addr_hi20) << 16), + IWL_GET_BITS(bd->pa[index], tb2_len), + PCI_DMA_TODEVICE); + + else if (i > 0) + pci_unmap_single(dev, + le32_to_cpu(bd->pa[index].tb1_addr), + IWL_GET_BITS(bd->pa[index], tb1_len), + PCI_DMA_TODEVICE); + + if (txq->txb[txq->q.last_used].skb[i]) { + struct sk_buff *skb = txq->txb[txq->q.last_used].skb[i]; + + dev_kfree_skb(skb); + txq->txb[txq->q.last_used].skb[i] = NULL; + } + } + return 0; +} + +int iwl_hw_reg_set_txpower(struct iwl_priv *priv, s8 power) +{ + IWL_ERROR("TODO: Implement iwl_hw_reg_set_txpower!\n"); + return -EINVAL; +} + +static s32 iwl4965_math_div_round(s32 num, s32 denom, s32 *res) +{ + s32 sign = 1; + + if (num < 0) { + sign = -sign; + num = -num; + } + if (denom < 0) { + sign = -sign; + denom = -denom; + } + *res = 1; + *res = ((num * 2 + denom) / (denom * 2)) * sign; + + return 1; +} + +static s32 iwl4965_get_voltage_compensation(s32 eeprom_voltage, + s32 current_voltage) +{ + s32 comp = 0; + + if ((TX_POWER_IWL_ILLEGAL_VOLTAGE == eeprom_voltage) || + (TX_POWER_IWL_ILLEGAL_VOLTAGE == current_voltage)) + return 0; + + iwl4965_math_div_round(current_voltage - eeprom_voltage, + TX_POWER_IWL_VOLTAGE_CODES_PER_03V, &comp); + + if (current_voltage > eeprom_voltage) + comp *= 2; + if ((comp < -2) || (comp > 2)) + comp = 0; + + return comp; +} + +static const struct iwl_channel_info * +iwl4965_get_channel_txpower_info(struct iwl_priv *priv, u8 phymode, u16 channel) +{ + const struct iwl_channel_info *ch_info; + + ch_info = iwl_get_channel_info(priv, phymode, channel); + + if (!is_channel_valid(ch_info)) + return NULL; + + return ch_info; +} + +static s32 iwl4965_get_tx_atten_grp(u16 channel) +{ + if (channel >= CALIB_IWL_TX_ATTEN_GR5_FCH && + channel <= CALIB_IWL_TX_ATTEN_GR5_LCH) + return CALIB_CH_GROUP_5; + + if (channel >= CALIB_IWL_TX_ATTEN_GR1_FCH && + channel <= CALIB_IWL_TX_ATTEN_GR1_LCH) + return CALIB_CH_GROUP_1; + + if (channel >= CALIB_IWL_TX_ATTEN_GR2_FCH && + channel <= CALIB_IWL_TX_ATTEN_GR2_LCH) + return CALIB_CH_GROUP_2; + + if (channel >= CALIB_IWL_TX_ATTEN_GR3_FCH && + channel <= CALIB_IWL_TX_ATTEN_GR3_LCH) + return CALIB_CH_GROUP_3; + + if (channel >= CALIB_IWL_TX_ATTEN_GR4_FCH && + channel <= CALIB_IWL_TX_ATTEN_GR4_LCH) + return CALIB_CH_GROUP_4; + + IWL_ERROR("Can't find txatten group for channel %d.\n", channel); + return -1; +} + +static u32 iwl4965_get_sub_band(const struct iwl_priv *priv, u32 channel) +{ + s32 b = -1; + + for (b = 0; b < EEPROM_TX_POWER_BANDS; b++) { + if (priv->eeprom.calib_info.band_info[b].ch_from == 0) + continue; + + if ((channel >= priv->eeprom.calib_info.band_info[b].ch_from) + && (channel <= priv->eeprom.calib_info.band_info[b].ch_to)) + break; + } + + return b; +} + +static s32 iwl4965_interpolate_value(s32 x, s32 x1, s32 y1, s32 x2, s32 y2) +{ + s32 val; + + if (x2 == x1) + return y1; + else { + iwl4965_math_div_round((x2 - x) * (y1 - y2), (x2 - x1), &val); + return val + y2; + } +} + +static int iwl4965_interpolate_chan(struct iwl_priv *priv, u32 channel, + struct iwl_eeprom_calib_ch_info *chan_info) +{ + s32 s = -1; + u32 c; + u32 m; + const struct iwl_eeprom_calib_measure *m1; + const struct iwl_eeprom_calib_measure *m2; + struct iwl_eeprom_calib_measure *omeas; + u32 ch_i1; + u32 ch_i2; + + s = iwl4965_get_sub_band(priv, channel); + if (s >= EEPROM_TX_POWER_BANDS) { + IWL_ERROR("Tx Power can not find channel %d ", channel); + return -1; + } + + ch_i1 = priv->eeprom.calib_info.band_info[s].ch1.ch_num; + ch_i2 = priv->eeprom.calib_info.band_info[s].ch2.ch_num; + chan_info->ch_num = (u8) channel; + + IWL_DEBUG_TXPOWER("channel %d subband %d factory cal ch %d & %d\n", + channel, s, ch_i1, ch_i2); + + for (c = 0; c < EEPROM_TX_POWER_TX_CHAINS; c++) { + for (m = 0; m < EEPROM_TX_POWER_MEASUREMENTS; m++) { + m1 = &(priv->eeprom.calib_info.band_info[s].ch1. + measurements[c][m]); + m2 = &(priv->eeprom.calib_info.band_info[s].ch2. + measurements[c][m]); + omeas = &(chan_info->measurements[c][m]); + + omeas->actual_pow = + (u8) iwl4965_interpolate_value(channel, ch_i1, + m1->actual_pow, + ch_i2, + m2->actual_pow); + omeas->gain_idx = + (u8) iwl4965_interpolate_value(channel, ch_i1, + m1->gain_idx, ch_i2, + m2->gain_idx); + omeas->temperature = + (u8) iwl4965_interpolate_value(channel, ch_i1, + m1->temperature, + ch_i2, + m2->temperature); + omeas->pa_det = + (s8) iwl4965_interpolate_value(channel, ch_i1, + m1->pa_det, ch_i2, + m2->pa_det); + + IWL_DEBUG_TXPOWER + ("chain %d meas %d AP1=%d AP2=%d AP=%d\n", c, m, + m1->actual_pow, m2->actual_pow, omeas->actual_pow); + IWL_DEBUG_TXPOWER + ("chain %d meas %d NI1=%d NI2=%d NI=%d\n", c, m, + m1->gain_idx, m2->gain_idx, omeas->gain_idx); + IWL_DEBUG_TXPOWER + ("chain %d meas %d PA1=%d PA2=%d PA=%d\n", c, m, + m1->pa_det, m2->pa_det, omeas->pa_det); + IWL_DEBUG_TXPOWER + ("chain %d meas %d T1=%d T2=%d T=%d\n", c, m, + m1->temperature, m2->temperature, + omeas->temperature); + } + } + + return 0; +} + +/* bit-rate-dependent table to prevent Tx distortion, in half-dB units, + * for OFDM 6, 12, 18, 24, 36, 48, 54, 60 MBit, and CCK all rates. */ +static s32 back_off_table[] = { + 10, 10, 10, 10, 10, 15, 17, 20, /* OFDM SISO 20 MHz */ + 10, 10, 10, 10, 10, 15, 17, 20, /* OFDM MIMO 20 MHz */ + 10, 10, 10, 10, 10, 15, 17, 20, /* OFDM SISO 40 MHz */ + 10, 10, 10, 10, 10, 15, 17, 20, /* OFDM MIMO 40 MHz */ + 10 /* CCK */ +}; + +/* Thermal compensation values for txpower for various frequency ranges ... + * ratios from 3:1 to 4.5:1 of degrees (Celsius) per half-dB gain adjust */ +static struct iwl_txpower_comp_entry { + s32 degrees_per_05db_a; + s32 degrees_per_05db_a_denom; +} tx_power_cmp_tble[CALIB_CH_GROUP_MAX] = { + {9, 2}, /* group 0 5.2, ch 34-43 */ + {4, 1}, /* group 1 5.2, ch 44-70 */ + {4, 1}, /* group 2 5.2, ch 71-124 */ + {4, 1}, /* group 3 5.2, ch 125-200 */ + {3, 1} /* group 4 2.4, ch all */ +}; + +static s32 get_min_power_index(s32 rate_power_index, u32 band) +{ + if (!band) { + if ((rate_power_index & 7) <= 4) + return MIN_TX_GAIN_INDEX_52GHZ_EXT; + } + return MIN_TX_GAIN_INDEX; +} + +struct gain_entry { + u8 dsp; + u8 radio; +}; + +static const struct gain_entry gain_table[2][108] = { + /* 5.2GHz power gain index table */ + { + {123, 0x3F}, /* highest txpower */ + {117, 0x3F}, + {110, 0x3F}, + {104, 0x3F}, + {98, 0x3F}, + {110, 0x3E}, + {104, 0x3E}, + {98, 0x3E}, + {110, 0x3D}, + {104, 0x3D}, + {98, 0x3D}, + {110, 0x3C}, + {104, 0x3C}, + {98, 0x3C}, + {110, 0x3B}, + {104, 0x3B}, + {98, 0x3B}, + {110, 0x3A}, + {104, 0x3A}, + {98, 0x3A}, + {110, 0x39}, + {104, 0x39}, + {98, 0x39}, + {110, 0x38}, + {104, 0x38}, + {98, 0x38}, + {110, 0x37}, + {104, 0x37}, + {98, 0x37}, + {110, 0x36}, + {104, 0x36}, + {98, 0x36}, + {110, 0x35}, + {104, 0x35}, + {98, 0x35}, + {110, 0x34}, + {104, 0x34}, + {98, 0x34}, + {110, 0x33}, + {104, 0x33}, + {98, 0x33}, + {110, 0x32}, + {104, 0x32}, + {98, 0x32}, + {110, 0x31}, + {104, 0x31}, + {98, 0x31}, + {110, 0x30}, + {104, 0x30}, + {98, 0x30}, + {110, 0x25}, + {104, 0x25}, + {98, 0x25}, + {110, 0x24}, + {104, 0x24}, + {98, 0x24}, + {110, 0x23}, + {104, 0x23}, + {98, 0x23}, + {110, 0x22}, + {104, 0x18}, + {98, 0x18}, + {110, 0x17}, + {104, 0x17}, + {98, 0x17}, + {110, 0x16}, + {104, 0x16}, + {98, 0x16}, + {110, 0x15}, + {104, 0x15}, + {98, 0x15}, + {110, 0x14}, + {104, 0x14}, + {98, 0x14}, + {110, 0x13}, + {104, 0x13}, + {98, 0x13}, + {110, 0x12}, + {104, 0x08}, + {98, 0x08}, + {110, 0x07}, + {104, 0x07}, + {98, 0x07}, + {110, 0x06}, + {104, 0x06}, + {98, 0x06}, + {110, 0x05}, + {104, 0x05}, + {98, 0x05}, + {110, 0x04}, + {104, 0x04}, + {98, 0x04}, + {110, 0x03}, + {104, 0x03}, + {98, 0x03}, + {110, 0x02}, + {104, 0x02}, + {98, 0x02}, + {110, 0x01}, + {104, 0x01}, + {98, 0x01}, + {110, 0x00}, + {104, 0x00}, + {98, 0x00}, + {93, 0x00}, + {88, 0x00}, + {83, 0x00}, + {78, 0x00}, + }, + /* 2.4GHz power gain index table */ + { + {110, 0x3f}, /* highest txpower */ + {104, 0x3f}, + {98, 0x3f}, + {110, 0x3e}, + {104, 0x3e}, + {98, 0x3e}, + {110, 0x3d}, + {104, 0x3d}, + {98, 0x3d}, + {110, 0x3c}, + {104, 0x3c}, + {98, 0x3c}, + {110, 0x3b}, + {104, 0x3b}, + {98, 0x3b}, + {110, 0x3a}, + {104, 0x3a}, + {98, 0x3a}, + {110, 0x39}, + {104, 0x39}, + {98, 0x39}, + {110, 0x38}, + {104, 0x38}, + {98, 0x38}, + {110, 0x37}, + {104, 0x37}, + {98, 0x37}, + {110, 0x36}, + {104, 0x36}, + {98, 0x36}, + {110, 0x35}, + {104, 0x35}, + {98, 0x35}, + {110, 0x34}, + {104, 0x34}, + {98, 0x34}, + {110, 0x33}, + {104, 0x33}, + {98, 0x33}, + {110, 0x32}, + {104, 0x32}, + {98, 0x32}, + {110, 0x31}, + {104, 0x31}, + {98, 0x31}, + {110, 0x30}, + {104, 0x30}, + {98, 0x30}, + {110, 0x6}, + {104, 0x6}, + {98, 0x6}, + {110, 0x5}, + {104, 0x5}, + {98, 0x5}, + {110, 0x4}, + {104, 0x4}, + {98, 0x4}, + {110, 0x3}, + {104, 0x3}, + {98, 0x3}, + {110, 0x2}, + {104, 0x2}, + {98, 0x2}, + {110, 0x1}, + {104, 0x1}, + {98, 0x1}, + {110, 0x0}, + {104, 0x0}, + {98, 0x0}, + {97, 0}, + {96, 0}, + {95, 0}, + {94, 0}, + {93, 0}, + {92, 0}, + {91, 0}, + {90, 0}, + {89, 0}, + {88, 0}, + {87, 0}, + {86, 0}, + {85, 0}, + {84, 0}, + {83, 0}, + {82, 0}, + {81, 0}, + {80, 0}, + {79, 0}, + {78, 0}, + {77, 0}, + {76, 0}, + {75, 0}, + {74, 0}, + {73, 0}, + {72, 0}, + {71, 0}, + {70, 0}, + {69, 0}, + {68, 0}, + {67, 0}, + {66, 0}, + {65, 0}, + {64, 0}, + {63, 0}, + {62, 0}, + {61, 0}, + {60, 0}, + {59, 0}, + } +}; + +static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel, + u8 is_fat, u8 ctrl_chan_high, + struct iwl_tx_power_db *tx_power_tbl) +{ + u8 saturation_power; + s32 target_power; + s32 user_target_power; + s32 power_limit; + s32 current_temp; + s32 reg_limit; + s32 current_regulatory; + s32 txatten_grp = CALIB_CH_GROUP_MAX; + int i; + int c; + const struct iwl_channel_info *ch_info = NULL; + struct iwl_eeprom_calib_ch_info ch_eeprom_info; + const struct iwl_eeprom_calib_measure *measurement; + s16 voltage; + s32 init_voltage; + s32 voltage_compensation; + s32 degrees_per_05db_num; + s32 degrees_per_05db_denom; + s32 factory_temp; + s32 temperature_comp[2]; + s32 factory_gain_index[2]; + s32 factory_actual_pwr[2]; + s32 power_index; + + /* Sanity check requested level (dBm) */ + if (priv->user_txpower_limit < IWL_TX_POWER_TARGET_POWER_MIN) { + IWL_WARNING("Requested user TXPOWER %d below limit.\n", + priv->user_txpower_limit); + return -EINVAL; + } + if (priv->user_txpower_limit > IWL_TX_POWER_TARGET_POWER_MAX) { + IWL_WARNING("Requested user TXPOWER %d above limit.\n", + priv->user_txpower_limit); + return -EINVAL; + } + + /* user_txpower_limit is in dBm, convert to half-dBm (half-dB units + * are used for indexing into txpower table) */ + user_target_power = 2 * priv->user_txpower_limit; + + /* Get current (RXON) channel, band, width */ + ch_info = + iwl4965_get_channel_txpower_info(priv, priv->phymode, channel); + + IWL_DEBUG_TXPOWER("chan %d band %d is_fat %d\n", channel, band, + is_fat); + + if (!ch_info) + return -EINVAL; + + /* get txatten group, used to select 1) thermal txpower adjustment + * and 2) mimo txpower balance between Tx chains. */ + txatten_grp = iwl4965_get_tx_atten_grp(channel); + if (txatten_grp < 0) + return -EINVAL; + + IWL_DEBUG_TXPOWER("channel %d belongs to txatten group %d\n", + channel, txatten_grp); + + if (is_fat) { + if (ctrl_chan_high) + channel -= 2; + else + channel += 2; + } + + /* hardware txpower limits ... + * saturation (clipping distortion) txpowers are in half-dBm */ + if (band) + saturation_power = priv->eeprom.calib_info.saturation_power24; + else + saturation_power = priv->eeprom.calib_info.saturation_power52; + + if (saturation_power < IWL_TX_POWER_SATURATION_MIN || + saturation_power > IWL_TX_POWER_SATURATION_MAX) { + if (band) + saturation_power = IWL_TX_POWER_DEFAULT_SATURATION_24; + else + saturation_power = IWL_TX_POWER_DEFAULT_SATURATION_52; + } + + /* regulatory txpower limits ... reg_limit values are in half-dBm, + * max_power_avg values are in dBm, convert * 2 */ + if (is_fat) + reg_limit = ch_info->fat_max_power_avg * 2; + else + reg_limit = ch_info->max_power_avg * 2; + + if ((reg_limit < IWL_TX_POWER_REGULATORY_MIN) || + (reg_limit > IWL_TX_POWER_REGULATORY_MAX)) { + if (band) + reg_limit = IWL_TX_POWER_DEFAULT_REGULATORY_24; + else + reg_limit = IWL_TX_POWER_DEFAULT_REGULATORY_52; + } + + /* Interpolate txpower calibration values for this channel, + * based on factory calibration tests on spaced channels. */ + iwl4965_interpolate_chan(priv, channel, &ch_eeprom_info); + + /* calculate tx gain adjustment based on power supply voltage */ + voltage = priv->eeprom.calib_info.voltage; + init_voltage = (s32)le32_to_cpu(priv->card_alive_init.voltage); + voltage_compensation = + iwl4965_get_voltage_compensation(voltage, init_voltage); + + IWL_DEBUG_TXPOWER("curr volt %d eeprom volt %d volt comp %d\n", + init_voltage, + voltage, voltage_compensation); + + /* get current temperature (Celsius) */ + current_temp = max(priv->temperature, IWL_TX_POWER_TEMPERATURE_MIN); + current_temp = min(priv->temperature, IWL_TX_POWER_TEMPERATURE_MAX); + current_temp = KELVIN_TO_CELSIUS(current_temp); + + /* select thermal txpower adjustment params, based on channel group + * (same frequency group used for mimo txatten adjustment) */ + degrees_per_05db_num = + tx_power_cmp_tble[txatten_grp].degrees_per_05db_a; + degrees_per_05db_denom = + tx_power_cmp_tble[txatten_grp].degrees_per_05db_a_denom; + + /* get per-chain txpower values from factory measurements */ + for (c = 0; c < 2; c++) { + measurement = &ch_eeprom_info.measurements[c][1]; + + /* txgain adjustment (in half-dB steps) based on difference + * between factory and current temperature */ + factory_temp = measurement->temperature; + iwl4965_math_div_round((current_temp - factory_temp) * + degrees_per_05db_denom, + degrees_per_05db_num, + &temperature_comp[c]); + + factory_gain_index[c] = measurement->gain_idx; + factory_actual_pwr[c] = measurement->actual_pow; + + IWL_DEBUG_TXPOWER("chain = %d\n", c); + IWL_DEBUG_TXPOWER("fctry tmp %d, " + "curr tmp %d, comp %d steps\n", + factory_temp, current_temp, + temperature_comp[c]); + + IWL_DEBUG_TXPOWER("fctry idx %d, fctry pwr %d\n", + factory_gain_index[c], + factory_actual_pwr[c]); + } + + /* for each of 33 bit-rates (including 1 for CCK) */ + for (i = 0; i < POWER_TABLE_NUM_ENTRIES; i++) { + u8 is_mimo_rate; + union iwl_tx_power_dual_stream tx_power; + + /* for mimo, reduce each chain's txpower by half + * (3dB, 6 steps), so total output power is regulatory + * compliant. */ + if (i & 0x8) { + current_regulatory = reg_limit - + IWL_TX_POWER_MIMO_REGULATORY_COMPENSATION; + is_mimo_rate = 1; + } else { + current_regulatory = reg_limit; + is_mimo_rate = 0; + } + + /* find txpower limit, either hardware or regulatory */ + power_limit = saturation_power - back_off_table[i]; + if (power_limit > current_regulatory) + power_limit = current_regulatory; + + /* reduce user's txpower request if necessary + * for this rate on this channel */ + target_power = user_target_power; + if (target_power > power_limit) + target_power = power_limit; + + IWL_DEBUG_TXPOWER("rate %d sat %d reg %d usr %d tgt %d\n", + i, saturation_power - back_off_table[i], + current_regulatory, user_target_power, + target_power); + + /* for each of 2 Tx chains (radio transmitters) */ + for (c = 0; c < 2; c++) { + s32 atten_value; + + if (is_mimo_rate) + atten_value = + (s32)le32_to_cpu(priv->card_alive_init. + tx_atten[txatten_grp][c]); + else + atten_value = 0; + + /* calculate index; higher index means lower txpower */ + power_index = (u8) (factory_gain_index[c] - + (target_power - + factory_actual_pwr[c]) - + temperature_comp[c] - + voltage_compensation + + atten_value); + +/* IWL_DEBUG_TXPOWER("calculated txpower index %d\n", + power_index); */ + + if (power_index < get_min_power_index(i, band)) + power_index = get_min_power_index(i, band); + + /* adjust 5 GHz index to support negative indexes */ + if (!band) + power_index += 9; + + /* CCK, rate 32, reduce txpower for CCK */ + if (i == POWER_TABLE_CCK_ENTRY) + power_index += + IWL_TX_POWER_CCK_COMPENSATION_C_STEP; + + /* stay within the table! */ + if (power_index > 107) { + IWL_WARNING("txpower index %d > 107\n", + power_index); + power_index = 107; + } + if (power_index < 0) { + IWL_WARNING("txpower index %d < 0\n", + power_index); + power_index = 0; + } + + /* fill txpower command for this rate/chain */ + tx_power.s.radio_tx_gain[c] = + gain_table[band][power_index].radio; + tx_power.s.dsp_predis_atten[c] = + gain_table[band][power_index].dsp; + + IWL_DEBUG_TXPOWER("chain %d mimo %d index %d " + "gain 0x%02x dsp %d\n", + c, atten_value, power_index, + tx_power.s.radio_tx_gain[c], + tx_power.s.dsp_predis_atten[c]); + }/* for each chain */ + + tx_power_tbl->power_tbl[i].dw = cpu_to_le32(tx_power.dw); + + }/* for each rate */ + + return 0; +} + +/** + * iwl_hw_reg_send_txpower - Configure the TXPOWER level user limit + * + * Uses the active RXON for channel, band, and characteristics (fat, high) + * The power limit is taken from priv->user_txpower_limit. + */ +int iwl_hw_reg_send_txpower(struct iwl_priv *priv) +{ + struct iwl_txpowertable_cmd cmd = { 0 }; + int rc = 0; + u8 band = 0; + u8 is_fat = 0; + u8 ctrl_chan_high = 0; + + if (test_bit(STATUS_SCANNING, &priv->status)) { + /* If this gets hit a lot, switch it to a BUG() and catch + * the stack trace to find out who is calling this during + * a scan. */ + IWL_WARNING("TX Power requested while scanning!\n"); + return -EAGAIN; + } + + band = ((priv->phymode == MODE_IEEE80211B) || + (priv->phymode == MODE_IEEE80211G)); + + is_fat = is_fat_channel(priv->active_rxon.flags); + + if (is_fat && + (priv->active_rxon.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK)) + ctrl_chan_high = 1; + + cmd.band = band; + cmd.channel = priv->active_rxon.channel; + + rc = iwl4965_fill_txpower_tbl(priv, band, + le16_to_cpu(priv->active_rxon.channel), + is_fat, ctrl_chan_high, &cmd.tx_power); + if (rc) + return rc; + + rc = iwl_send_cmd_pdu(priv, REPLY_TX_PWR_TABLE_CMD, sizeof(cmd), &cmd); + return rc; +} + +int iwl_hw_channel_switch(struct iwl_priv *priv, u16 channel) +{ + int rc; + u8 band = 0; + u8 is_fat = 0; + u8 ctrl_chan_high = 0; + struct iwl_channel_switch_cmd cmd = { 0 }; + const struct iwl_channel_info *ch_info; + + band = ((priv->phymode == MODE_IEEE80211B) || + (priv->phymode == MODE_IEEE80211G)); + + ch_info = iwl_get_channel_info(priv, priv->phymode, channel); + + is_fat = is_fat_channel(priv->staging_rxon.flags); + + if (is_fat && + (priv->active_rxon.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK)) + ctrl_chan_high = 1; + + cmd.band = band; + cmd.expect_beacon = 0; + cmd.channel = cpu_to_le16(channel); + cmd.rxon_flags = priv->active_rxon.flags; + cmd.rxon_filter_flags = priv->active_rxon.filter_flags; + cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time); + if (ch_info) + cmd.expect_beacon = is_channel_radar(ch_info); + else + cmd.expect_beacon = 1; + + rc = iwl4965_fill_txpower_tbl(priv, band, channel, is_fat, + ctrl_chan_high, &cmd.tx_power); + if (rc) { + IWL_DEBUG_11H("error:%d fill txpower_tbl\n", rc); + return rc; + } + + rc = iwl_send_cmd_pdu(priv, REPLY_CHANNEL_SWITCH, sizeof(cmd), &cmd); + return rc; +} + +#define RTS_HCCA_RETRY_LIMIT 3 +#define RTS_DFAULT_RETRY_LIMIT 60 + +void iwl_hw_build_tx_cmd_rate(struct iwl_priv *priv, + struct iwl_cmd *cmd, + struct ieee80211_tx_control *ctrl, + struct ieee80211_hdr *hdr, int sta_id, + int is_hcca) +{ + u8 rate; + u8 rts_retry_limit = 0; + u8 data_retry_limit = 0; + __le32 tx_flags; + u16 fc = le16_to_cpu(hdr->frame_control); + + tx_flags = cmd->cmd.tx.tx_flags; + + rate = iwl_rates[ctrl->tx_rate].plcp; + + rts_retry_limit = (is_hcca) ? + RTS_HCCA_RETRY_LIMIT : RTS_DFAULT_RETRY_LIMIT; + + if (ieee80211_is_probe_response(fc)) { + data_retry_limit = 3; + if (data_retry_limit < rts_retry_limit) + rts_retry_limit = data_retry_limit; + } else + data_retry_limit = IWL_DEFAULT_TX_RETRY; + + if (priv->data_retry_limit != -1) + data_retry_limit = priv->data_retry_limit; + + if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) { + switch (fc & IEEE80211_FCTL_STYPE) { + case IEEE80211_STYPE_AUTH: + case IEEE80211_STYPE_DEAUTH: + case IEEE80211_STYPE_ASSOC_REQ: + case IEEE80211_STYPE_REASSOC_REQ: + if (tx_flags & TX_CMD_FLG_RTS_MSK) { + tx_flags &= ~TX_CMD_FLG_RTS_MSK; + tx_flags |= TX_CMD_FLG_CTS_MSK; + } + break; + default: + break; + } + } + + cmd->cmd.tx.rts_retry_limit = rts_retry_limit; + cmd->cmd.tx.data_retry_limit = data_retry_limit; + cmd->cmd.tx.rate_n_flags = iwl_hw_set_rate_n_flags(rate, 0); + cmd->cmd.tx.tx_flags = tx_flags; +} + +int iwl_hw_get_rx_read(struct iwl_priv *priv) +{ + struct iwl_shared *shared_data = priv->hw_setting.shared_virt; + + return IWL_GET_BITS(*shared_data, rb_closed_stts_rb_num); +} + +int iwl_hw_get_temperature(struct iwl_priv *priv) +{ + return priv->temperature; +} + +unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv, + struct iwl_frame *frame, u8 rate) +{ + struct iwl_tx_beacon_cmd *tx_beacon_cmd; + unsigned int frame_size; + + tx_beacon_cmd = &frame->u.beacon; + memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd)); + + tx_beacon_cmd->tx.sta_id = IWL4965_BROADCAST_ID; + tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; + + frame_size = iwl_fill_beacon_frame(priv, + tx_beacon_cmd->frame, + BROADCAST_ADDR, + sizeof(frame->u) - sizeof(*tx_beacon_cmd)); + + BUG_ON(frame_size > MAX_MPDU_SIZE); + tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size); + + if ((rate == IWL_RATE_1M_PLCP) || (rate >= IWL_RATE_2M_PLCP)) + tx_beacon_cmd->tx.rate_n_flags = + iwl_hw_set_rate_n_flags(rate, RATE_MCS_CCK_MSK); + else + tx_beacon_cmd->tx.rate_n_flags = + iwl_hw_set_rate_n_flags(rate, 0); + + tx_beacon_cmd->tx.tx_flags = (TX_CMD_FLG_SEQ_CTL_MSK | + TX_CMD_FLG_TSF_MSK | TX_CMD_FLG_STA_RATE_MSK); + return (sizeof(*tx_beacon_cmd) + frame_size); +} + +int iwl_hw_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq) +{ + int rc; + unsigned long flags; + int txq_id = txq->q.id; + + spin_lock_irqsave(&priv->lock, flags); + rc = iwl_grab_restricted_access(priv); + if (rc) { + spin_unlock_irqrestore(&priv->lock, flags); + return rc; + } + + iwl_write_restricted(priv, FH_MEM_CBBC_QUEUE(txq_id), + txq->q.dma_addr >> 8); + iwl_write_restricted( + priv, IWL_FH_TCSR_CHNL_TX_CONFIG_REG(txq_id), + IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | + IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL); + iwl_release_restricted_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +static inline u8 iwl4965_get_dma_hi_address(dma_addr_t addr) +{ + return sizeof(addr) > sizeof(u32) ? (addr >> 16) >> 16 : 0; +} + +int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr, + dma_addr_t addr, u16 len) +{ + int index, is_odd; + struct iwl_tfd_frame *tfd = ptr; + u32 num_tbs = IWL_GET_BITS(*tfd, num_tbs); + + if ((num_tbs >= MAX_NUM_OF_TBS) || (num_tbs < 0)) { + IWL_ERROR("Error can not send more than %d chunks\n", + MAX_NUM_OF_TBS); + return -EINVAL; + } + + index = num_tbs / 2; + is_odd = num_tbs & 0x1; + + if (!is_odd) { + tfd->pa[index].tb1_addr = cpu_to_le32(addr); + IWL_SET_BITS(tfd->pa[index], tb1_addr_hi, + iwl4965_get_dma_hi_address(addr)); + IWL_SET_BITS(tfd->pa[index], tb1_len, len); + } else { + IWL_SET_BITS(tfd->pa[index], tb2_addr_lo16, + (u32) (addr & 0xffff)); + IWL_SET_BITS(tfd->pa[index], tb2_addr_hi20, addr >> 16); + IWL_SET_BITS(tfd->pa[index], tb2_len, len); + } + + IWL_SET_BITS(*tfd, num_tbs, num_tbs + 1); + + return 0; +} + +void iwl_hw_card_show_info(struct iwl_priv *priv) +{ + u16 hw_version = priv->eeprom.board_revision_4965; + + IWL_DEBUG_INFO("4965ABGN HW Version %u.%u.%u\n", + ((hw_version >> 8) & 0x0F), + ((hw_version >> 8) >> 4), (hw_version & 0x00FF)); + + IWL_DEBUG_INFO("4965ABGN PBA Number %.16s\n", + priv->eeprom.board_pba_number_4965); +} + +#define IWL_TX_CRC_SIZE 4 +#define IWL_TX_DELIMITER_SIZE 4 + +int iwl4965_tx_queue_update_wr_ptr(struct iwl_priv *priv, + struct iwl_tx_queue *txq, u16 byte_cnt) +{ + int len; + int txq_id = txq->q.id; + struct iwl_shared *shared_data = priv->hw_setting.shared_virt; + + if (txq->need_update == 0) + return 0; + + len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE; + + IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id]. + tfd_offset[txq->q.first_empty], byte_cnt, len); + + if (txq->q.first_empty < IWL4965_MAX_WIN_SIZE) + IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id]. + tfd_offset[IWL4965_QUEUE_SIZE + txq->q.first_empty], + byte_cnt, len); + + return 0; +} + +/* Set up Rx receiver/antenna/chain usage in "staging" RXON image. + * This should not be used for scan command ... it puts data in wrong place. */ +void iwl4965_set_rxon_chain(struct iwl_priv *priv) +{ + u8 is_single = is_single_stream(priv); + u8 idle_state, rx_state; + + priv->staging_rxon.rx_chain = 0; + rx_state = idle_state = 3; + + /* Tell uCode which antennas are actually connected. + * Before first association, we assume all antennas are connected. + * Just after first association, iwl4965_noise_calibration() + * checks which antennas actually *are* connected. */ + priv->staging_rxon.rx_chain |= + cpu_to_le16(priv->valid_antenna << RXON_RX_CHAIN_VALID_POS); + + /* How many receivers should we use? */ + iwl4965_get_rx_chain_counter(priv, &idle_state, &rx_state); + priv->staging_rxon.rx_chain |= + cpu_to_le16(rx_state << RXON_RX_CHAIN_MIMO_CNT_POS); + priv->staging_rxon.rx_chain |= + cpu_to_le16(idle_state << RXON_RX_CHAIN_CNT_POS); + + if (!is_single && (rx_state >= 2) && + !test_bit(STATUS_POWER_PMI, &priv->status)) + priv->staging_rxon.rx_chain |= RXON_RX_CHAIN_MIMO_FORCE_MSK; + else + priv->staging_rxon.rx_chain &= ~RXON_RX_CHAIN_MIMO_FORCE_MSK; + + IWL_DEBUG_ASSOC("rx chain %X\n", priv->staging_rxon.rx_chain); +} + +#ifdef CONFIG_IWLWIFI_HT +#ifdef CONFIG_IWLWIFI_HT_AGG +/* + get the traffic load value for tid +*/ +static u32 iwl4965_tl_get_load(struct iwl_priv *priv, u8 tid) +{ + u32 load = 0; + u32 current_time = jiffies_to_msecs(jiffies); + u32 time_diff; + s32 index; + unsigned long flags; + struct iwl_traffic_load *tid_ptr = NULL; + + if (tid >= TID_MAX_LOAD_COUNT) + return 0; + + tid_ptr = &(priv->lq_mngr.agg_ctrl.traffic_load[tid]); + + current_time -= current_time % TID_ROUND_VALUE; + + spin_lock_irqsave(&priv->lq_mngr.lock, flags); + if (!(tid_ptr->queue_count)) + goto out; + + time_diff = TIME_WRAP_AROUND(tid_ptr->time_stamp, current_time); + index = time_diff / TID_QUEUE_CELL_SPACING; + + if (index >= TID_QUEUE_MAX_SIZE) { + u32 oldest_time = current_time - TID_MAX_TIME_DIFF; + + while (tid_ptr->queue_count && + (tid_ptr->time_stamp < oldest_time)) { + tid_ptr->total -= tid_ptr->packet_count[tid_ptr->head]; + tid_ptr->packet_count[tid_ptr->head] = 0; + tid_ptr->time_stamp += TID_QUEUE_CELL_SPACING; + tid_ptr->queue_count--; + tid_ptr->head++; + if (tid_ptr->head >= TID_QUEUE_MAX_SIZE) + tid_ptr->head = 0; + } + } + load = tid_ptr->total; + + out: + spin_unlock_irqrestore(&priv->lq_mngr.lock, flags); + return load; +} + +/* + increment traffic load value for tid and also remove + any old values if passed the certian time period +*/ +static void iwl4965_tl_add_packet(struct iwl_priv *priv, u8 tid) +{ + u32 current_time = jiffies_to_msecs(jiffies); + u32 time_diff; + s32 index; + unsigned long flags; + struct iwl_traffic_load *tid_ptr = NULL; + + if (tid >= TID_MAX_LOAD_COUNT) + return; + + tid_ptr = &(priv->lq_mngr.agg_ctrl.traffic_load[tid]); + + current_time -= current_time % TID_ROUND_VALUE; + + spin_lock_irqsave(&priv->lq_mngr.lock, flags); + if (!(tid_ptr->queue_count)) { + tid_ptr->total = 1; + tid_ptr->time_stamp = current_time; + tid_ptr->queue_count = 1; + tid_ptr->head = 0; + tid_ptr->packet_count[0] = 1; + goto out; + } + + time_diff = TIME_WRAP_AROUND(tid_ptr->time_stamp, current_time); + index = time_diff / TID_QUEUE_CELL_SPACING; + + if (index >= TID_QUEUE_MAX_SIZE) { + u32 oldest_time = current_time - TID_MAX_TIME_DIFF; + + while (tid_ptr->queue_count && + (tid_ptr->time_stamp < oldest_time)) { + tid_ptr->total -= tid_ptr->packet_count[tid_ptr->head]; + tid_ptr->packet_count[tid_ptr->head] = 0; + tid_ptr->time_stamp += TID_QUEUE_CELL_SPACING; + tid_ptr->queue_count--; + tid_ptr->head++; + if (tid_ptr->head >= TID_QUEUE_MAX_SIZE) + tid_ptr->head = 0; + } + } + + index = (tid_ptr->head + index) % TID_QUEUE_MAX_SIZE; + tid_ptr->packet_count[index] = tid_ptr->packet_count[index] + 1; + tid_ptr->total = tid_ptr->total + 1; + + if ((index + 1) > tid_ptr->queue_count) + tid_ptr->queue_count = index + 1; + out: + spin_unlock_irqrestore(&priv->lq_mngr.lock, flags); + +} + +#define MMAC_SCHED_MAX_NUMBER_OF_HT_BACK_FLOWS 7 +enum HT_STATUS { + BA_STATUS_FAILURE = 0, + BA_STATUS_INITIATOR_DELBA, + BA_STATUS_RECIPIENT_DELBA, + BA_STATUS_RENEW_ADDBA_REQUEST, + BA_STATUS_ACTIVE, +}; + +static u8 iwl4964_tl_ba_avail(struct iwl_priv *priv) +{ + int i; + struct iwl_lq_mngr *lq; + u8 count = 0; + u16 msk; + + lq = (struct iwl_lq_mngr *)&(priv->lq_mngr); + for (i = 0; i < TID_MAX_LOAD_COUNT ; i++) { + msk = 1 << i; + if ((lq->agg_ctrl.granted_ba & msk) || + (lq->agg_ctrl.wait_for_agg_status & msk)) + count++; + } + + if (count < MMAC_SCHED_MAX_NUMBER_OF_HT_BACK_FLOWS) + return 1; + + return 0; +} + +static void iwl4965_ba_status(struct iwl_priv *priv, + u8 tid, enum HT_STATUS status); + +static int iwl4965_perform_addba(struct iwl_priv *priv, u8 tid, u32 length, + u32 ba_timeout) +{ + int rc; + + rc = ieee80211_start_BA_session(priv->hw, priv->bssid, tid); + if (rc) + iwl4965_ba_status(priv, tid, BA_STATUS_FAILURE); + + return rc; +} + +static int iwl4965_perform_delba(struct iwl_priv *priv, u8 tid) +{ + int rc; + + rc = ieee80211_stop_BA_session(priv->hw, priv->bssid, tid); + if (rc) + iwl4965_ba_status(priv, tid, BA_STATUS_FAILURE); + + return rc; +} + +static void iwl4965_turn_on_agg_for_tid(struct iwl_priv *priv, + struct iwl_lq_mngr *lq, + u8 auto_agg, u8 tid) +{ + u32 tid_msk = (1 << tid); + unsigned long flags; + + spin_lock_irqsave(&priv->lq_mngr.lock, flags); +/* + if ((auto_agg) && (!lq->enable_counter)){ + lq->agg_ctrl.next_retry = 0; + lq->agg_ctrl.tid_retry = 0; + spin_unlock_irqrestore(&priv->lq_mngr.lock, flags); + return; + } +*/ + if (!(lq->agg_ctrl.granted_ba & tid_msk) && + (lq->agg_ctrl.requested_ba & tid_msk)) { + u8 available_queues; + u32 load; + + spin_unlock_irqrestore(&priv->lq_mngr.lock, flags); + available_queues = iwl4964_tl_ba_avail(priv); + load = iwl4965_tl_get_load(priv, tid); + + spin_lock_irqsave(&priv->lq_mngr.lock, flags); + if (!available_queues) { + if (auto_agg) + lq->agg_ctrl.tid_retry |= tid_msk; + else { + lq->agg_ctrl.requested_ba &= ~tid_msk; + lq->agg_ctrl.wait_for_agg_status &= ~tid_msk; + } + } else if ((auto_agg) && + ((load <= lq->agg_ctrl.tid_traffic_load_threshold) || + ((lq->agg_ctrl.wait_for_agg_status & tid_msk)))) + lq->agg_ctrl.tid_retry |= tid_msk; + else { + lq->agg_ctrl.wait_for_agg_status |= tid_msk; + spin_unlock_irqrestore(&priv->lq_mngr.lock, flags); + iwl4965_perform_addba(priv, tid, 0x40, + lq->agg_ctrl.ba_timeout); + spin_lock_irqsave(&priv->lq_mngr.lock, flags); + } + } + spin_unlock_irqrestore(&priv->lq_mngr.lock, flags); +} + +static void iwl4965_turn_on_agg(struct iwl_priv *priv, u8 tid) +{ + struct iwl_lq_mngr *lq; + unsigned long flags; + + lq = (struct iwl_lq_mngr *)&(priv->lq_mngr); + + if ((tid < TID_MAX_LOAD_COUNT)) + iwl4965_turn_on_agg_for_tid(priv, lq, lq->agg_ctrl.auto_agg, + tid); + else if (tid == TID_ALL_SPECIFIED) { + if (lq->agg_ctrl.requested_ba) { + for (tid = 0; tid < TID_MAX_LOAD_COUNT; tid++) + iwl4965_turn_on_agg_for_tid(priv, lq, + lq->agg_ctrl.auto_agg, tid); + } else { + spin_lock_irqsave(&priv->lq_mngr.lock, flags); + lq->agg_ctrl.tid_retry = 0; + lq->agg_ctrl.next_retry = 0; + spin_unlock_irqrestore(&priv->lq_mngr.lock, flags); + } + } + +} + +void iwl4965_turn_off_agg(struct iwl_priv *priv, u8 tid) +{ + u32 tid_msk; + struct iwl_lq_mngr *lq; + unsigned long flags; + + lq = (struct iwl_lq_mngr *)&(priv->lq_mngr); + + if ((tid < TID_MAX_LOAD_COUNT)) { + tid_msk = 1 << tid; + spin_lock_irqsave(&priv->lq_mngr.lock, flags); + lq->agg_ctrl.wait_for_agg_status |= tid_msk; + lq->agg_ctrl.requested_ba &= ~tid_msk; + spin_unlock_irqrestore(&priv->lq_mngr.lock, flags); + iwl4965_perform_delba(priv, tid); + } else if (tid == TID_ALL_SPECIFIED) { + spin_lock_irqsave(&priv->lq_mngr.lock, flags); + for (tid = 0; tid < TID_MAX_LOAD_COUNT; tid++) { + tid_msk = 1 << tid; + lq->agg_ctrl.wait_for_agg_status |= tid_msk; + spin_unlock_irqrestore(&priv->lq_mngr.lock, flags); + iwl4965_perform_delba(priv, tid); + spin_lock_irqsave(&priv->lq_mngr.lock, flags); + } + lq->agg_ctrl.requested_ba = 0; + spin_unlock_irqrestore(&priv->lq_mngr.lock, flags); + } +} + +static void iwl4965_ba_status(struct iwl_priv *priv, + u8 tid, enum HT_STATUS status) +{ + struct iwl_lq_mngr *lq; + u32 tid_msk = (1 << tid); + unsigned long flags; + + lq = (struct iwl_lq_mngr *)&(priv->lq_mngr); + + if ((tid >= TID_MAX_LOAD_COUNT)) + goto out; + + spin_lock_irqsave(&priv->lq_mngr.lock, flags); + switch (status) { + case BA_STATUS_ACTIVE: + if (!(lq->agg_ctrl.granted_ba & tid_msk)) + lq->agg_ctrl.granted_ba |= tid_msk; + break; + default: + if ((lq->agg_ctrl.granted_ba & tid_msk)) + lq->agg_ctrl.granted_ba &= ~tid_msk; + break; + } + + lq->agg_ctrl.wait_for_agg_status &= ~tid_msk; + if (status != BA_STATUS_ACTIVE) { + if (lq->agg_ctrl.auto_agg) { + lq->agg_ctrl.tid_retry |= tid_msk; + lq->agg_ctrl.next_retry = + jiffies + msecs_to_jiffies(500); + } else + lq->agg_ctrl.requested_ba &= ~tid_msk; + } + spin_unlock_irqrestore(&priv->lq_mngr.lock, flags); + out: + return; +} + +static void iwl4965_bg_agg_work(struct work_struct *work) +{ + struct iwl_priv *priv = container_of(work, struct iwl_priv, + agg_work); + + u32 tid; + u32 retry_tid; + u32 tid_msk; + unsigned long flags; + struct iwl_lq_mngr *lq = (struct iwl_lq_mngr *)&(priv->lq_mngr); + + spin_lock_irqsave(&priv->lq_mngr.lock, flags); + retry_tid = lq->agg_ctrl.tid_retry; + lq->agg_ctrl.tid_retry = 0; + spin_unlock_irqrestore(&priv->lq_mngr.lock, flags); + + if (retry_tid == TID_ALL_SPECIFIED) + iwl4965_turn_on_agg(priv, TID_ALL_SPECIFIED); + else { + for (tid = 0; tid < TID_MAX_LOAD_COUNT; tid++) { + tid_msk = (1 << tid); + if (retry_tid & tid_msk) + iwl4965_turn_on_agg(priv, tid); + } + } + + spin_lock_irqsave(&priv->lq_mngr.lock, flags); + if (lq->agg_ctrl.tid_retry) + lq->agg_ctrl.next_retry = jiffies + msecs_to_jiffies(500); + spin_unlock_irqrestore(&priv->lq_mngr.lock, flags); + return; +} +#endif /*CONFIG_IWLWIFI_HT_AGG */ +#endif /* CONFIG_IWLWIFI_HT */ + +int iwl4965_tx_cmd(struct iwl_priv *priv, struct iwl_cmd *out_cmd, + u8 sta_id, dma_addr_t txcmd_phys, + struct ieee80211_hdr *hdr, u8 hdr_len, + struct ieee80211_tx_control *ctrl, void *sta_in) +{ + struct iwl_tx_cmd cmd; + struct iwl_tx_cmd *tx = (struct iwl_tx_cmd *)&out_cmd->cmd.payload[0]; + dma_addr_t scratch_phys; + u8 unicast = 0; + u8 is_data = 1; + u16 fc; + u16 rate_flags; + int rate_index = min(ctrl->tx_rate & 0xffff, IWL_RATE_COUNT - 1); +#ifdef CONFIG_IWLWIFI_HT +#ifdef CONFIG_IWLWIFI_HT_AGG + __le16 *qc; +#endif /*CONFIG_IWLWIFI_HT_AGG */ +#endif /* CONFIG_IWLWIFI_HT */ + + unicast = !is_multicast_ether_addr(hdr->addr1); + + fc = le16_to_cpu(hdr->frame_control); + if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) + is_data = 0; + + memcpy(&cmd, &(out_cmd->cmd.tx), sizeof(struct iwl_tx_cmd)); + memset(tx, 0, sizeof(struct iwl_tx_cmd)); + memcpy(tx->hdr, hdr, hdr_len); + + tx->len = cmd.len; + tx->driver_txop = cmd.driver_txop; + tx->stop_time.life_time = cmd.stop_time.life_time; + tx->tx_flags = cmd.tx_flags; + tx->sta_id = cmd.sta_id; + tx->tid_tspec = cmd.tid_tspec; + tx->timeout.pm_frame_timeout = cmd.timeout.pm_frame_timeout; + tx->next_frame_len = cmd.next_frame_len; + + tx->sec_ctl = cmd.sec_ctl; + memcpy(&(tx->key[0]), &(cmd.key[0]), 16); + tx->tx_flags = cmd.tx_flags; + + tx->rts_retry_limit = cmd.rts_retry_limit; + tx->data_retry_limit = cmd.data_retry_limit; + + scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) + + offsetof(struct iwl_tx_cmd, scratch); + tx->dram_lsb_ptr = cpu_to_le32(scratch_phys); + tx->dram_msb_ptr = iwl4965_get_dma_hi_address(scratch_phys); + + /* Hard coded to start at the highest retry fallback position + * until the 4965 specific rate control algorithm is tied in */ + tx->initial_rate_index = LINK_QUAL_MAX_RETRY_NUM - 1; + + /* Alternate between antenna A and B for successive frames */ + if (priv->use_ant_b_for_management_frame) { + priv->use_ant_b_for_management_frame = 0; + rate_flags = RATE_MCS_ANT_B_MSK; + } else { + priv->use_ant_b_for_management_frame = 1; + rate_flags = RATE_MCS_ANT_A_MSK; + } + + if (!unicast || !is_data) { + if ((rate_index >= IWL_FIRST_CCK_RATE) && + (rate_index <= IWL_LAST_CCK_RATE)) + rate_flags |= RATE_MCS_CCK_MSK; + } else { + tx->initial_rate_index = 0; + tx->tx_flags |= TX_CMD_FLG_STA_RATE_MSK; + } + + tx->rate_n_flags = iwl_hw_set_rate_n_flags(iwl_rates[rate_index].plcp, + rate_flags); + + if (ieee80211_is_probe_request(fc)) + tx->tx_flags |= TX_CMD_FLG_TSF_MSK; + else if (ieee80211_is_back_request(fc)) + tx->tx_flags |= TX_CMD_FLG_ACK_MSK | + TX_CMD_FLG_IMM_BA_RSP_MASK; +#ifdef CONFIG_IWLWIFI_HT +#ifdef CONFIG_IWLWIFI_HT_AGG + qc = ieee80211_get_qos_ctrl(hdr); + if (qc && + (priv->iw_mode != IEEE80211_IF_TYPE_IBSS)) { + u8 tid = 0; + tid = (u8) (le16_to_cpu(*qc) & 0xF); + if (tid < TID_MAX_LOAD_COUNT) + iwl4965_tl_add_packet(priv, tid); + } + + if (priv->lq_mngr.agg_ctrl.next_retry && + (time_after(priv->lq_mngr.agg_ctrl.next_retry, jiffies))) { + unsigned long flags; + + spin_lock_irqsave(&priv->lq_mngr.lock, flags); + priv->lq_mngr.agg_ctrl.next_retry = 0; + spin_unlock_irqrestore(&priv->lq_mngr.lock, flags); + schedule_work(&priv->agg_work); + } +#endif +#endif + return 0; +} + +/** + * sign_extend - Sign extend a value using specified bit as sign-bit + * + * Example: sign_extend(9, 3) would return -7 as bit3 of 1001b is 1 + * and bit0..2 is 001b which when sign extended to 1111111111111001b is -7. + * + * @param oper value to sign extend + * @param index 0 based bit index (0<=index<32) to sign bit + */ +static s32 sign_extend(u32 oper, int index) +{ + u8 shift = 31 - index; + + return (s32)(oper << shift) >> shift; +} + +/** + * iwl4965_get_temperature - return the calibrated temperature (in Kelvin) + * @statistics: Provides the temperature reading from the uCode + * + * A return of <0 indicates bogus data in the statistics + */ +int iwl4965_get_temperature(const struct iwl_priv *priv) +{ + s32 temperature; + s32 vt; + s32 R1, R2, R3; + u32 R4; + + if (test_bit(STATUS_TEMPERATURE, &priv->status) && + (priv->statistics.flag & STATISTICS_REPLY_FLG_FAT_MODE_MSK)) { + IWL_DEBUG_TEMP("Running FAT temperature calibration\n"); + R1 = (s32)le32_to_cpu(priv->card_alive_init.therm_r1[1]); + R2 = (s32)le32_to_cpu(priv->card_alive_init.therm_r2[1]); + R3 = (s32)le32_to_cpu(priv->card_alive_init.therm_r3[1]); + R4 = le32_to_cpu(priv->card_alive_init.therm_r4[1]); + } else { + IWL_DEBUG_TEMP("Running temperature calibration\n"); + R1 = (s32)le32_to_cpu(priv->card_alive_init.therm_r1[0]); + R2 = (s32)le32_to_cpu(priv->card_alive_init.therm_r2[0]); + R3 = (s32)le32_to_cpu(priv->card_alive_init.therm_r3[0]); + R4 = le32_to_cpu(priv->card_alive_init.therm_r4[0]); + } + + /* + * Temperature is only 23 bits so sign extend out to 32 + * + * NOTE If we haven't received a statistics notification yet + * with an updated temperature, use R4 provided to us in the + * ALIVE response. */ + if (!test_bit(STATUS_TEMPERATURE, &priv->status)) + vt = sign_extend(R4, 23); + else + vt = sign_extend( + le32_to_cpu(priv->statistics.general.temperature), 23); + + IWL_DEBUG_TEMP("Calib values R[1-3]: %d %d %d R4: %d\n", + R1, R2, R3, vt); + + if (R3 == R1) { + IWL_ERROR("Calibration conflict R1 == R3\n"); + return -1; + } + + /* Calculate temperature in degrees Kelvin, adjust by 97%. + * Add offset to center the adjustment around 0 degrees Centigrade. */ + temperature = TEMPERATURE_CALIB_A_VAL * (vt - R2); + temperature /= (R3 - R1); + temperature = (temperature * 97) / 100 + + TEMPERATURE_CALIB_KELVIN_OFFSET; + + IWL_DEBUG_TEMP("Calibrated temperature: %dK, %dC\n", temperature, + KELVIN_TO_CELSIUS(temperature)); + + return temperature; +} + +/* Adjust Txpower only if temperature variance is greater than threshold. */ +#define IWL_TEMPERATURE_THRESHOLD 3 + +/** + * iwl4965_is_temp_calib_needed - determines if new calibration is needed + * + * If the temperature changed has changed sufficiently, then a recalibration + * is needed. + * + * Assumes caller will replace priv->last_temperature once calibration + * executed. + */ +static int iwl4965_is_temp_calib_needed(struct iwl_priv *priv) +{ + int temp_diff; + + if (!test_bit(STATUS_STATISTICS, &priv->status)) { + IWL_DEBUG_TEMP("Temperature not updated -- no statistics.\n"); + return 0; + } + + temp_diff = priv->temperature - priv->last_temperature; + + /* get absolute value */ + if (temp_diff < 0) { + IWL_DEBUG_POWER("Getting cooler, delta %d, \n", temp_diff); + temp_diff = -temp_diff; + } else if (temp_diff == 0) + IWL_DEBUG_POWER("Same temp, \n"); + else + IWL_DEBUG_POWER("Getting warmer, delta %d, \n", temp_diff); + + if (temp_diff < IWL_TEMPERATURE_THRESHOLD) { + IWL_DEBUG_POWER("Thermal txpower calib not needed\n"); + return 0; + } + + IWL_DEBUG_POWER("Thermal txpower calib needed\n"); + + return 1; +} + +/* Calculate noise level, based on measurements during network silence just + * before arriving beacon. This measurement can be done only if we know + * exactly when to expect beacons, therefore only when we're associated. */ +static void iwl4965_rx_calc_noise(struct iwl_priv *priv) +{ + struct statistics_rx_non_phy *rx_info + = &(priv->statistics.rx.general); + int num_active_rx = 0; + int total_silence = 0; + int bcn_silence_a = + le32_to_cpu(rx_info->beacon_silence_rssi_a) & IN_BAND_FILTER; + int bcn_silence_b = + le32_to_cpu(rx_info->beacon_silence_rssi_b) & IN_BAND_FILTER; + int bcn_silence_c = + le32_to_cpu(rx_info->beacon_silence_rssi_c) & IN_BAND_FILTER; + + if (bcn_silence_a) { + total_silence += bcn_silence_a; + num_active_rx++; + } + if (bcn_silence_b) { + total_silence += bcn_silence_b; + num_active_rx++; + } + if (bcn_silence_c) { + total_silence += bcn_silence_c; + num_active_rx++; + } + + /* Average among active antennas */ + if (num_active_rx) + priv->last_rx_noise = (total_silence / num_active_rx) - 107; + else + priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE; + + IWL_DEBUG_CALIB("inband silence a %u, b %u, c %u, dBm %d\n", + bcn_silence_a, bcn_silence_b, bcn_silence_c, + priv->last_rx_noise); +} + +void iwl_hw_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + int change; + s32 temp; + + IWL_DEBUG_RX("Statistics notification received (%d vs %d).\n", + (int)sizeof(priv->statistics), pkt->len); + + change = ((priv->statistics.general.temperature != + pkt->u.stats.general.temperature) || + ((priv->statistics.flag & + STATISTICS_REPLY_FLG_FAT_MODE_MSK) != + (pkt->u.stats.flag & STATISTICS_REPLY_FLG_FAT_MODE_MSK))); + + memcpy(&priv->statistics, &pkt->u.stats, sizeof(priv->statistics)); + + set_bit(STATUS_STATISTICS, &priv->status); + + /* Reschedule the statistics timer to occur in + * REG_RECALIB_PERIOD seconds to ensure we get a + * thermal update even if the uCode doesn't give + * us one */ + mod_timer(&priv->statistics_periodic, jiffies + + msecs_to_jiffies(REG_RECALIB_PERIOD * 1000)); + + if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)) && + (pkt->hdr.cmd == STATISTICS_NOTIFICATION)) { + iwl4965_rx_calc_noise(priv); +#ifdef CONFIG_IWLWIFI_SENSITIVITY + queue_work(priv->workqueue, &priv->sensitivity_work); +#endif + } + + /* If the hardware hasn't reported a change in + * temperature then don't bother computing a + * calibrated temperature value */ + if (!change) + return; + + temp = iwl4965_get_temperature(priv); + if (temp < 0) + return; + + if (priv->temperature != temp) { + if (priv->temperature) + IWL_DEBUG_TEMP("Temperature changed " + "from %dC to %dC\n", + KELVIN_TO_CELSIUS(priv->temperature), + KELVIN_TO_CELSIUS(temp)); + else + IWL_DEBUG_TEMP("Temperature " + "initialized to %dC\n", + KELVIN_TO_CELSIUS(temp)); + } + + priv->temperature = temp; + set_bit(STATUS_TEMPERATURE, &priv->status); + + if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)) && + iwl4965_is_temp_calib_needed(priv)) + queue_work(priv->workqueue, &priv->txpower_work); +} + +static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data, + int include_phy, + struct iwl_rx_mem_buffer *rxb, + struct ieee80211_rx_status *stats) +{ + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl4965_rx_phy_res *rx_start = (include_phy) ? + (struct iwl4965_rx_phy_res *)&(pkt->u.raw[0]) : NULL; + struct ieee80211_hdr *hdr; + u16 len; + __le32 *rx_end; + unsigned int skblen; + u32 ampdu_status; + + if (!include_phy && priv->last_phy_res[0]) + rx_start = (struct iwl4965_rx_phy_res *)&priv->last_phy_res[1]; + + if (!rx_start) { + IWL_ERROR("MPDU frame without a PHY data\n"); + return; + } + if (include_phy) { + hdr = (struct ieee80211_hdr *)((u8 *) & rx_start[1] + + rx_start->cfg_phy_cnt); + + len = le16_to_cpu(rx_start->byte_count); + + rx_end = (__le32 *) ((u8 *) & pkt->u.raw[0] + + sizeof(struct iwl4965_rx_phy_res) + + rx_start->cfg_phy_cnt + len); + + } else { + struct iwl4965_rx_mpdu_res_start *amsdu = + (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw; + + hdr = (struct ieee80211_hdr *)(pkt->u.raw + + sizeof(struct iwl4965_rx_mpdu_res_start)); + len = le16_to_cpu(amsdu->byte_count); + rx_start->byte_count = amsdu->byte_count; + rx_end = (__le32 *) (((u8 *) hdr) + len); + } + if (len > 2342 || len < 16) { + IWL_DEBUG_DROP("byte count out of range [16,2342]" + " : %d\n", len); + return; + } + + ampdu_status = le32_to_cpu(*rx_end); + skblen = ((u8 *) rx_end - (u8 *) & pkt->u.raw[0]) + sizeof(u32); + + /* start from MAC */ + skb_reserve(rxb->skb, (void *)hdr - (void *)pkt); + skb_put(rxb->skb, len); /* end where data ends */ + + /* We only process data packets if the interface is open */ + if (unlikely(!priv->is_open)) { + IWL_DEBUG_DROP_LIMIT + ("Dropping packet while interface is not open.\n"); + return; + } + + if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) { + if (iwl_param_hwcrypto) + iwl_set_decrypted_flag(priv, rxb->skb, + ampdu_status, stats); + iwl_handle_data_packet_monitor(priv, rxb, hdr, len, stats, 0); + return; + } + + stats->flag = 0; + hdr = (struct ieee80211_hdr *)rxb->skb->data; + + if (iwl_param_hwcrypto) + iwl_set_decrypted_flag(priv, rxb->skb, ampdu_status, stats); + + ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats); + priv->alloc_rxb_skb--; + rxb->skb = NULL; +#ifdef LED + priv->led_packets += len; + iwl_setup_activity_timer(priv); +#endif +} + +/* Calc max signal level (dBm) among 3 possible receivers */ +static int iwl4965_calc_rssi(struct iwl4965_rx_phy_res *rx_resp) +{ + /* data from PHY/DSP regarding signal strength, etc., + * contents are always there, not configurable by host. */ + struct iwl4965_rx_non_cfg_phy *ncphy = + (struct iwl4965_rx_non_cfg_phy *)rx_resp->non_cfg_phy; + u32 agc = (le16_to_cpu(ncphy->agc_info) & IWL_AGC_DB_MASK) + >> IWL_AGC_DB_POS; + + u32 valid_antennae = + (le16_to_cpu(rx_resp->phy_flags) & RX_PHY_FLAGS_ANTENNAE_MASK) + >> RX_PHY_FLAGS_ANTENNAE_OFFSET; + u8 max_rssi = 0; + u32 i; + + /* Find max rssi among 3 possible receivers. + * These values are measured by the digital signal processor (DSP). + * They should stay fairly constant even as the signal strength varies, + * if the radio's automatic gain control (AGC) is working right. + * AGC value (see below) will provide the "interesting" info. */ + for (i = 0; i < 3; i++) + if (valid_antennae & (1 << i)) + max_rssi = max(ncphy->rssi_info[i << 1], max_rssi); + + IWL_DEBUG_STATS("Rssi In A %d B %d C %d Max %d AGC dB %d\n", + ncphy->rssi_info[0], ncphy->rssi_info[2], ncphy->rssi_info[4], + max_rssi, agc); + + /* dBm = max_rssi dB - agc dB - constant. + * Higher AGC (higher radio gain) means lower signal. */ + return (max_rssi - agc - IWL_RSSI_OFFSET); +} + +#ifdef CONFIG_IWLWIFI_HT + +/* Parsed Information Elements */ +struct ieee802_11_elems { + u8 *ds_params; + u8 ds_params_len; + u8 *tim; + u8 tim_len; + u8 *ibss_params; + u8 ibss_params_len; + u8 *erp_info; + u8 erp_info_len; + u8 *ht_cap_param; + u8 ht_cap_param_len; + u8 *ht_extra_param; + u8 ht_extra_param_len; +}; + +static int parse_elems(u8 *start, size_t len, struct ieee802_11_elems *elems) +{ + size_t left = len; + u8 *pos = start; + int unknown = 0; + + memset(elems, 0, sizeof(*elems)); + + while (left >= 2) { + u8 id, elen; + + id = *pos++; + elen = *pos++; + left -= 2; + + if (elen > left) + return -1; + + switch (id) { + case WLAN_EID_DS_PARAMS: + elems->ds_params = pos; + elems->ds_params_len = elen; + break; + case WLAN_EID_TIM: + elems->tim = pos; + elems->tim_len = elen; + break; + case WLAN_EID_IBSS_PARAMS: + elems->ibss_params = pos; + elems->ibss_params_len = elen; + break; + case WLAN_EID_ERP_INFO: + elems->erp_info = pos; + elems->erp_info_len = elen; + break; + case WLAN_EID_HT_CAPABILITY: + elems->ht_cap_param = pos; + elems->ht_cap_param_len = elen; + break; + case WLAN_EID_HT_EXTRA_INFO: + elems->ht_extra_param = pos; + elems->ht_extra_param_len = elen; + break; + default: + unknown++; + break; + } + + left -= elen; + pos += elen; + } + + return 0; +} +#endif /* CONFIG_IWLWIFI_HT */ + +static void iwl4965_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->sta_lock, flags); + priv->stations[sta_id].sta.station_flags &= ~STA_FLG_PWR_SAVE_MSK; + priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK; + priv->stations[sta_id].sta.sta.modify_mask = 0; + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + spin_unlock_irqrestore(&priv->sta_lock, flags); + + iwl_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC); +} + +static void iwl4965_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr) +{ + /* FIXME: need locking over ps_status ??? */ + u8 sta_id = iwl_hw_find_station(priv, addr); + + if (sta_id != IWL_INVALID_STATION) { + u8 sta_awake = priv->stations[sta_id]. + ps_status == STA_PS_STATUS_WAKE; + + if (sta_awake && ps_bit) + priv->stations[sta_id].ps_status = STA_PS_STATUS_SLEEP; + else if (!sta_awake && !ps_bit) { + iwl4965_sta_modify_ps_wake(priv, sta_id); + priv->stations[sta_id].ps_status = STA_PS_STATUS_WAKE; + } + } +} + +/* Called for REPLY_4965_RX (legacy ABG frames), or + * REPLY_RX_MPDU_CMD (HT high-throughput N frames). */ +static void iwl4965_rx_reply_rx(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + /* Use phy data (Rx signal strength, etc.) contained within + * this rx packet for legacy frames, + * or phy data cached from REPLY_RX_PHY_CMD for HT frames. */ + int include_phy = (pkt->hdr.cmd == REPLY_4965_RX); + struct iwl4965_rx_phy_res *rx_start = (include_phy) ? + (struct iwl4965_rx_phy_res *)&(pkt->u.raw[0]) : + (struct iwl4965_rx_phy_res *)&priv->last_phy_res[1]; + __le32 *rx_end; + unsigned int len = 0; + struct ieee80211_hdr *header; + u16 fc; + struct ieee80211_rx_status stats = { + .mactime = le64_to_cpu(rx_start->timestamp), + .channel = le16_to_cpu(rx_start->channel), + .phymode = + (rx_start->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? + MODE_IEEE80211G : MODE_IEEE80211A, + .antenna = 0, + .rate = iwl_hw_get_rate(rx_start->rate_n_flags), + .flag = 0, +#ifdef CONFIG_IWLWIFI_HT_AGG + .ordered = 0 +#endif /* CONFIG_IWLWIFI_HT_AGG */ + }; + u8 network_packet; + + if ((unlikely(rx_start->cfg_phy_cnt > 20))) { + IWL_DEBUG_DROP + ("dsp size out of range [0,20]: " + "%d/n", rx_start->cfg_phy_cnt); + return; + } + if (!include_phy) { + if (priv->last_phy_res[0]) + rx_start = (struct iwl4965_rx_phy_res *) + &priv->last_phy_res[1]; + else + rx_start = NULL; + } + + if (!rx_start) { + IWL_ERROR("MPDU frame without a PHY data\n"); + return; + } + + if (include_phy) { + header = (struct ieee80211_hdr *)((u8 *) & rx_start[1] + + rx_start->cfg_phy_cnt); + + len = le16_to_cpu(rx_start->byte_count); + rx_end = (__le32 *) (pkt->u.raw + rx_start->cfg_phy_cnt + + sizeof(struct iwl4965_rx_phy_res) + len); + } else { + struct iwl4965_rx_mpdu_res_start *amsdu = + (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw; + + header = (void *)(pkt->u.raw + + sizeof(struct iwl4965_rx_mpdu_res_start)); + len = le16_to_cpu(amsdu->byte_count); + rx_end = (__le32 *) (pkt->u.raw + + sizeof(struct iwl4965_rx_mpdu_res_start) + len); + } + + if (!(*rx_end & RX_RES_STATUS_NO_CRC32_ERROR) || + !(*rx_end & RX_RES_STATUS_NO_RXE_OVERFLOW)) { + IWL_DEBUG_RX("Bad CRC or FIFO: 0x%08X.\n", + le32_to_cpu(*rx_end)); + return; + } + + priv->ucode_beacon_time = le32_to_cpu(rx_start->beacon_time_stamp); + + stats.freq = ieee80211chan2mhz(stats.channel); + + /* Find max signal strength (dBm) among 3 antenna/receiver chains */ + stats.ssi = iwl4965_calc_rssi(rx_start); + + /* Meaningful noise values are available only from beacon statistics, + * which are gathered only when associated, and indicate noise + * only for the associated network channel ... + * Ignore these noise values while scanning (other channels) */ + if (iwl_is_associated(priv) && + !test_bit(STATUS_SCANNING, &priv->status)) { + stats.noise = priv->last_rx_noise; + stats.signal = iwl_calc_sig_qual(stats.ssi, stats.noise); + } else { + stats.noise = IWL_NOISE_MEAS_NOT_AVAILABLE; + stats.signal = iwl_calc_sig_qual(stats.ssi, 0); + } + + /* Reset beacon noise level if not associated. */ + if (!iwl_is_associated(priv)) + priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE; + +#ifdef CONFIG_IWLWIFI_DEBUG + /* TODO: Parts of iwl_report_frame are broken for 4965 */ + if (iwl_debug_level & (IWL_DL_RX)) + /* Set "1" to report good data frames in groups of 100 */ + iwl_report_frame(priv, pkt, header, 1); + + if (iwl_debug_level & (IWL_DL_RX | IWL_DL_STATS)) + IWL_DEBUG_RX("Rssi %d, noise %d, qual %d, TSF %lu\n", + stats.ssi, stats.noise, stats.signal, + (long unsigned int)le64_to_cpu(rx_start->timestamp)); +#endif + + network_packet = iwl_is_network_packet(priv, header); + if (network_packet) { + priv->last_rx_rssi = stats.ssi; + priv->last_beacon_time = priv->ucode_beacon_time; + priv->last_tsf = le64_to_cpu(rx_start->timestamp); + } + + fc = le16_to_cpu(header->frame_control); + switch (fc & IEEE80211_FCTL_FTYPE) { + case IEEE80211_FTYPE_MGMT: + + if (priv->iw_mode == IEEE80211_IF_TYPE_AP) + iwl4965_update_ps_mode(priv, fc & IEEE80211_FCTL_PM, + header->addr2); + switch (fc & IEEE80211_FCTL_STYPE) { + case IEEE80211_STYPE_PROBE_RESP: + case IEEE80211_STYPE_BEACON: + if ((priv->iw_mode == IEEE80211_IF_TYPE_STA && + !compare_ether_addr(header->addr2, priv->bssid)) || + (priv->iw_mode == IEEE80211_IF_TYPE_IBSS && + !compare_ether_addr(header->addr3, priv->bssid))) { + struct ieee80211_mgmt *mgmt = + (struct ieee80211_mgmt *)header; + u64 timestamp = + le64_to_cpu(mgmt->u.beacon.timestamp); + + priv->timestamp0 = timestamp & 0xFFFFFFFF; + priv->timestamp1 = + (timestamp >> 32) & 0xFFFFFFFF; + priv->beacon_int = le16_to_cpu( + mgmt->u.beacon.beacon_int); + if (priv->call_post_assoc_from_beacon && + (priv->iw_mode == IEEE80211_IF_TYPE_STA)) { + priv->call_post_assoc_from_beacon = 0; + queue_work(priv->workqueue, + &priv->post_associate.work); + } + } + break; + + case IEEE80211_STYPE_ACTION: + break; + + /* + * TODO: There is no callback function from upper + * stack to inform us when associated status. this + * work around to sniff assoc_resp management frame + * and finish the association process. + */ + case IEEE80211_STYPE_ASSOC_RESP: + case IEEE80211_STYPE_REASSOC_RESP: + if (network_packet && iwl_is_associated(priv)) { +#ifdef CONFIG_IWLWIFI_HT + u8 *pos = NULL; + struct ieee802_11_elems elems; +#endif /*CONFIG_IWLWIFI_HT */ + struct ieee80211_mgmt *mgnt = + (struct ieee80211_mgmt *)header; + + priv->assoc_id = (~((1 << 15) | (1 << 14)) + & le16_to_cpu(mgnt->u.assoc_resp.aid)); + priv->assoc_capability = + le16_to_cpu( + mgnt->u.assoc_resp.capab_info); +#ifdef CONFIG_IWLWIFI_HT + pos = mgnt->u.assoc_resp.variable; + if (!parse_elems(pos, + len - (pos - (u8 *) mgnt), + &elems)) { + if (elems.ht_extra_param && + elems.ht_cap_param) + break; + } +#endif /*CONFIG_IWLWIFI_HT */ + /* assoc_id is 0 no association */ + if (!priv->assoc_id) + break; + if (priv->beacon_int) + queue_work(priv->workqueue, + &priv->post_associate.work); + else + priv->call_post_assoc_from_beacon = 1; + } + + break; + + case IEEE80211_STYPE_PROBE_REQ: + if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && + !iwl_is_associated(priv)) { + IWL_DEBUG_DROP("Dropping (non network): " + MAC_FMT ", " MAC_FMT ", " + MAC_FMT "\n", + MAC_ARG(header->addr1), + MAC_ARG(header->addr2), + MAC_ARG(header->addr3)); + return; + } + } + iwl4965_handle_data_packet(priv, 0, include_phy, rxb, &stats); + break; + + case IEEE80211_FTYPE_CTL: +#ifdef CONFIG_IWLWIFI_HT_AGG + switch (fc & IEEE80211_FCTL_STYPE) { + case IEEE80211_STYPE_BACK_REQ: + IWL_DEBUG_HT("IEEE80211_STYPE_BACK_REQ arrived\n"); + iwl4965_handle_data_packet(priv, 0, include_phy, + rxb, &stats); + break; + default: + break; + } +#endif + + break; + + case IEEE80211_FTYPE_DATA: + if (priv->iw_mode == IEEE80211_IF_TYPE_AP) + iwl4965_update_ps_mode(priv, fc & IEEE80211_FCTL_PM, + header->addr2); + + if (unlikely(!network_packet)) + IWL_DEBUG_DROP("Dropping (non network): " + MAC_FMT ", " MAC_FMT ", " + MAC_FMT "\n", + MAC_ARG(header->addr1), + MAC_ARG(header->addr2), + MAC_ARG(header->addr3)); + else if (unlikely(is_duplicate_packet(priv, header))) + IWL_DEBUG_DROP("Dropping (dup): " MAC_FMT ", " + MAC_FMT ", " MAC_FMT "\n", + MAC_ARG(header->addr1), + MAC_ARG(header->addr2), + MAC_ARG(header->addr3)); + else + iwl4965_handle_data_packet(priv, 1, include_phy, rxb, + &stats); + break; + default: + break; + + } +} + +/* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD). + * This will be used later in iwl4965_rx_reply_rx() for REPLY_RX_MPDU_CMD. */ +static void iwl4965_rx_reply_rx_phy(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + priv->last_phy_res[0] = 1; + memcpy(&priv->last_phy_res[1], &(pkt->u.raw[0]), + sizeof(struct iwl4965_rx_phy_res)); +} + +static void iwl4965_rx_missed_beacon_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) + +{ +#ifdef CONFIG_IWLWIFI_SENSITIVITY + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_missed_beacon_notif *missed_beacon; + + missed_beacon = &pkt->u.missed_beacon; + if (le32_to_cpu(missed_beacon->consequtive_missed_beacons) > 5) { + IWL_DEBUG_CALIB("missed bcn cnsq %d totl %d rcd %d expctd %d\n", + le32_to_cpu(missed_beacon->consequtive_missed_beacons), + le32_to_cpu(missed_beacon->total_missed_becons), + le32_to_cpu(missed_beacon->num_recvd_beacons), + le32_to_cpu(missed_beacon->num_expected_beacons)); + priv->sensitivity_data.state = IWL_SENS_CALIB_NEED_REINIT; + if (unlikely(!test_bit(STATUS_SCANNING, &priv->status))) + queue_work(priv->workqueue, &priv->sensitivity_work); + } +#endif /*CONFIG_IWLWIFI_SENSITIVITY*/ +} + +#ifdef CONFIG_IWLWIFI_HT +#ifdef CONFIG_IWLWIFI_HT_AGG + +static void iwl4965_set_tx_status(struct iwl_priv *priv, int txq_id, int idx, + u32 status, u32 retry_count, u32 rate) +{ + struct ieee80211_tx_status *tx_status = + &(priv->txq[txq_id].txb[idx].status); + + tx_status->flags = status ? IEEE80211_TX_STATUS_ACK : 0; + tx_status->retry_count += retry_count; + tx_status->control.tx_rate = rate; +} + + +static void iwl_sta_modify_enable_tid_tx(struct iwl_priv *priv, + int sta_id, int tid) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->sta_lock, flags); + priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_TID_DISABLE_TX; + priv->stations[sta_id].sta.tid_disable_tx &= cpu_to_le16(~(1 << tid)); + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + spin_unlock_irqrestore(&priv->sta_lock, flags); + + iwl_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC); +} + + +static int iwl4965_tx_status_reply_compressed_ba(struct iwl_priv *priv, + struct iwl_ht_agg *agg, + struct iwl_compressed_ba_resp* + ba_resp) + +{ + int i, sh, ack; + u16 ba_seq_ctl = le16_to_cpu(ba_resp->ba_seq_ctl); + u32 bitmap0, bitmap1; + u32 resp_bitmap0 = le32_to_cpu(ba_resp->ba_bitmap0); + u32 resp_bitmap1 = le32_to_cpu(ba_resp->ba_bitmap1); + + if (unlikely(!agg->wait_for_ba)) { + IWL_ERROR("Received BA when not expected\n"); + return -EINVAL; + } + agg->wait_for_ba = 0; + IWL_DEBUG_TX_REPLY("BA %d %d\n", agg->start_idx, ba_resp->ba_seq_ctl); + sh = agg->start_idx - SEQ_TO_INDEX(ba_seq_ctl>>4); + if (sh < 0) /* tbw something is wrong with indeces */ + sh += 0x100; + + /* don't use 64 bits for now */ + bitmap0 = resp_bitmap0 >> sh; + bitmap1 = resp_bitmap1 >> sh; + bitmap0 |= (resp_bitmap1 & ((1<frame_count > (64 - sh)) { + IWL_DEBUG_TX_REPLY("more frames than bitmap size"); + return -1; + } + + /* check for success or failure according to the + * transmitted bitmap and back bitmap */ + bitmap0 &= agg->bitmap0; + bitmap1 &= agg->bitmap1; + + for (i = 0; i < agg->frame_count ; i++) { + int idx = (agg->start_idx + i) & 0xff; + ack = bitmap0 & (1 << i); + IWL_DEBUG_TX_REPLY("%s ON i=%d idx=%d raw=%d\n", + ack? "ACK":"NACK", i, idx, agg->start_idx + i); + iwl4965_set_tx_status(priv, agg->txq_id, idx, ack, 0, + agg->rate_n_flags); + + } + + IWL_DEBUG_TX_REPLY("Bitmap %x%x\n", bitmap0, bitmap1); + + return 0; +} + +static inline int iwl_queue_dec_wrap(int index, int n_bd) +{ + return (index == 0) ? n_bd - 1 : index - 1; +} + +static void iwl4965_rx_reply_compressed_ba(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_compressed_ba_resp *ba_resp = &pkt->u.compressed_ba; + int index; + struct iwl_tx_queue *txq = NULL; + struct iwl_ht_agg *agg; + u16 ba_resp_scd_flow = le16_to_cpu(ba_resp->scd_flow); + u16 ba_resp_scd_ssn = le16_to_cpu(ba_resp->scd_ssn); + + if (ba_resp_scd_flow >= ARRAY_SIZE(priv->txq)) { + IWL_ERROR("BUG_ON scd_flow is bigger than number of queues"); + return; + } + + txq = &priv->txq[ba_resp_scd_flow]; + agg = &priv->stations[ba_resp->sta_id].tid[ba_resp->tid].agg; + index = iwl_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd); + + /* TODO: Need to get this copy more sefely - now good for debug */ +/* + IWL_DEBUG_TX_REPLY("REPLY_COMPRESSED_BA [%d]Received from " MAC_FMT ", + sta_id = %d\n", + agg->wait_for_ba, + MAC_ARG((u8*) &ba_resp->sta_addr_lo32), + ba_resp->sta_id); + IWL_DEBUG_TX_REPLY("TID = %d, SeqCtl = %d, bitmap = 0x%X%X, scd_flow = " + "%d, scd_ssn = %d\n", + ba_resp->tid, + ba_resp->ba_seq_ctl, + ba_resp->ba_bitmap1, + ba_resp->ba_bitmap0, + ba_resp->scd_flow, + ba_resp->scd_ssn); + IWL_DEBUG_TX_REPLY("DAT start_idx = %d, bitmap = 0x%X%X \n", + agg->start_idx, + agg->bitmap1, + agg->bitmap0); +*/ + iwl4965_tx_status_reply_compressed_ba(priv, agg, ba_resp); + /* releases all the TFDs until the SSN */ + if (txq->q.last_used != (ba_resp_scd_ssn & 0xff)) + iwl_tx_queue_reclaim(priv, ba_resp_scd_flow, index); + +} + + +static void iwl4965_tx_queue_stop_scheduler(struct iwl_priv *priv, u16 txq_id) +{ + iwl_write_restricted_reg(priv, + SCD_QUEUE_STATUS_BITS(txq_id), + (0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)| + (1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN)); +} + +static int iwl4965_tx_queue_set_q2ratid(struct iwl_priv *priv, u16 ra_tid, + u16 txq_id) +{ + u32 tbl_dw_addr; + u32 tbl_dw; + u16 scd_q2ratid; + + scd_q2ratid = ra_tid & SCD_QUEUE_RA_TID_MAP_RATID_MSK; + + tbl_dw_addr = priv->scd_base_addr + + SCD_TRANSLATE_TBL_OFFSET_QUEUE(txq_id); + + tbl_dw = iwl_read_restricted_mem(priv, tbl_dw_addr); + + if (txq_id & 0x1) + tbl_dw = (scd_q2ratid << 16) | (tbl_dw & 0x0000FFFF); + else + tbl_dw = scd_q2ratid | (tbl_dw & 0xFFFF0000); + + iwl_write_restricted_mem(priv, tbl_dw_addr, tbl_dw); + + return 0; +} + +/** + * txq_id must be greater than IWL_BACK_QUEUE_FIRST_ID + */ +static int iwl4965_tx_queue_agg_enable(struct iwl_priv *priv, int txq_id, + int tx_fifo, int sta_id, int tid, + u16 ssn_idx) +{ + unsigned long flags; + int rc; + u16 ra_tid; + + if (IWL_BACK_QUEUE_FIRST_ID > txq_id) + IWL_WARNING("queue number too small: %d, must be > %d\n", + txq_id, IWL_BACK_QUEUE_FIRST_ID); + + ra_tid = BUILD_RAxTID(sta_id, tid); + + iwl_sta_modify_enable_tid_tx(priv, sta_id, tid); + + spin_lock_irqsave(&priv->lock, flags); + rc = iwl_grab_restricted_access(priv); + if (rc) { + spin_unlock_irqrestore(&priv->lock, flags); + return rc; + } + + iwl4965_tx_queue_stop_scheduler(priv, txq_id); + + iwl4965_tx_queue_set_q2ratid(priv, ra_tid, txq_id); + + + iwl_set_bits_restricted_reg(priv, SCD_QUEUECHAIN_SEL, (1<txq[txq_id].q.last_used = (ssn_idx & 0xff); + priv->txq[txq_id].q.first_empty = (ssn_idx & 0xff); + + /* supposes that ssn_idx is valid (!= 0xFFF) */ + iwl4965_set_wr_ptrs(priv, txq_id, ssn_idx); + + iwl_write_restricted_mem(priv, + priv->scd_base_addr + SCD_CONTEXT_QUEUE_OFFSET(txq_id), + (SCD_WIN_SIZE << SCD_QUEUE_CTX_REG1_WIN_SIZE_POS) & + SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK); + + iwl_write_restricted_mem(priv, priv->scd_base_addr + + SCD_CONTEXT_QUEUE_OFFSET(txq_id) + sizeof(u32), + (SCD_FRAME_LIMIT << SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) + & SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK); + + iwl_set_bits_restricted_reg(priv, SCD_INTERRUPT_MASK, (1 << txq_id)); + + iwl4965_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1); + + iwl_release_restricted_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +/** + * txq_id must be greater than IWL_BACK_QUEUE_FIRST_ID + */ +static int iwl4965_tx_queue_agg_disable(struct iwl_priv *priv, u16 txq_id, + u16 ssn_idx, u8 tx_fifo) +{ + unsigned long flags; + int rc; + + if (IWL_BACK_QUEUE_FIRST_ID > txq_id) { + IWL_WARNING("queue number too small: %d, must be > %d\n", + txq_id, IWL_BACK_QUEUE_FIRST_ID); + return -EINVAL; + } + + spin_lock_irqsave(&priv->lock, flags); + rc = iwl_grab_restricted_access(priv); + if (rc) { + spin_unlock_irqrestore(&priv->lock, flags); + return rc; + } + + iwl4965_tx_queue_stop_scheduler(priv, txq_id); + + iwl_clear_bits_restricted_reg(priv, SCD_QUEUECHAIN_SEL, (1 << txq_id)); + + priv->txq[txq_id].q.last_used = (ssn_idx & 0xff); + priv->txq[txq_id].q.first_empty = (ssn_idx & 0xff); + /* supposes that ssn_idx is valid (!= 0xFFF) */ + iwl4965_set_wr_ptrs(priv, txq_id, ssn_idx); + + iwl_clear_bits_restricted_reg(priv, SCD_INTERRUPT_MASK, (1 << txq_id)); + iwl4965_txq_ctx_deactivate(priv, txq_id); + iwl4965_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 0); + + iwl_release_restricted_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +#endif/* CONFIG_IWLWIFI_HT_AGG */ +#endif /* CONFIG_IWLWIFI_HT */ +/* + * RATE SCALE CODE + */ +int iwl4965_init_hw_rates(struct iwl_priv *priv, struct ieee80211_rate *rates) +{ + return 0; +} + + +/** + * iwl4965_add_station - Initialize a station's hardware rate table + * + * The uCode contains a table of fallback rates and retries per rate + * for automatic fallback during transmission. + * + * NOTE: This initializes the table for a single retry per data rate + * which is not optimal. Setting up an intelligent retry per rate + * requires feedback from transmission, which isn't exposed through + * rc80211_simple which is what this driver is currently using. + * + */ +void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap) +{ + int i, r; + struct iwl_link_quality_cmd link_cmd = { + .reserved1 = 0, + }; + u16 rate_flags; + + /* Set up the rate scaling to start at 54M and fallback + * all the way to 1M in IEEE order and then spin on IEEE */ + if (is_ap) + r = IWL_RATE_54M_INDEX; + else if (priv->phymode == MODE_IEEE80211A) + r = IWL_RATE_6M_INDEX; + else + r = IWL_RATE_1M_INDEX; + + for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) { + rate_flags = 0; + if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE) + rate_flags |= RATE_MCS_CCK_MSK; + + rate_flags |= RATE_MCS_ANT_B_MSK; + rate_flags &= ~RATE_MCS_ANT_A_MSK; + link_cmd.rs_table[i].rate_n_flags = + iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags); + r = iwl_get_prev_ieee_rate(r); + } + + link_cmd.general_params.single_stream_ant_msk = 2; + link_cmd.general_params.dual_stream_ant_msk = 3; + link_cmd.agg_params.agg_dis_start_th = 3; + link_cmd.agg_params.agg_time_limit = cpu_to_le16(4000); + + /* Update the rate scaling for control frame Tx to AP */ + link_cmd.sta_id = is_ap ? IWL_AP_ID : IWL4965_BROADCAST_ID; + + iwl_send_cmd_pdu(priv, REPLY_TX_LINK_QUALITY_CMD, sizeof(link_cmd), + &link_cmd); +} + +#ifdef CONFIG_IWLWIFI_HT + +static u8 iwl_is_channel_extension(struct iwl_priv *priv, int phymode, + u16 channel, u8 extension_chan_offset) +{ + const struct iwl_channel_info *ch_info; + + ch_info = iwl_get_channel_info(priv, phymode, channel); + if (!is_channel_valid(ch_info)) + return 0; + + if (extension_chan_offset == IWL_EXT_CHANNEL_OFFSET_AUTO) + return 0; + + if ((ch_info->fat_extension_channel == extension_chan_offset) || + (ch_info->fat_extension_channel == HT_IE_EXT_CHANNEL_MAX)) + return 1; + + return 0; +} + +static u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv, + const struct sta_ht_info *ht_info) +{ + + if (priv->channel_width != IWL_CHANNEL_WIDTH_40MHZ) + return 0; + + if (ht_info->supported_chan_width != IWL_CHANNEL_WIDTH_40MHZ) + return 0; + + if (ht_info->extension_chan_offset == IWL_EXT_CHANNEL_OFFSET_AUTO) + return 0; + + /* no fat tx allowed on 2.4GHZ */ + if (priv->phymode != MODE_IEEE80211A) + return 0; + return (iwl_is_channel_extension(priv, priv->phymode, + ht_info->control_channel, + ht_info->extension_chan_offset)); +} + +void iwl4965_set_rxon_ht(struct iwl_priv *priv, struct sta_ht_info *ht_info) +{ + struct iwl_rxon_cmd *rxon = &priv->staging_rxon; + u32 val; + + if (!ht_info->is_ht) + return; + + if (iwl_is_fat_tx_allowed(priv, ht_info)) + rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED_MSK; + else + rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK | + RXON_FLG_CHANNEL_MODE_PURE_40_MSK); + + if (le16_to_cpu(rxon->channel) != ht_info->control_channel) { + IWL_DEBUG_ASSOC("control diff than current %d %d\n", + le16_to_cpu(rxon->channel), + ht_info->control_channel); + rxon->channel = cpu_to_le16(ht_info->control_channel); + return; + } + + /* Note: control channel is oposit to extension channel */ + switch (ht_info->extension_chan_offset) { + case IWL_EXT_CHANNEL_OFFSET_ABOVE: + rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK); + break; + case IWL_EXT_CHANNEL_OFFSET_BELOW: + rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK; + break; + case IWL_EXT_CHANNEL_OFFSET_AUTO: + rxon->flags &= ~RXON_FLG_CHANNEL_MODE_MIXED_MSK; + break; + default: + rxon->flags &= ~RXON_FLG_CHANNEL_MODE_MIXED_MSK; + break; + } + + val = ht_info->operating_mode; + + rxon->flags |= cpu_to_le32(val << RXON_FLG_HT_OPERATING_MODE_POS); + + priv->active_rate_ht[0] = ht_info->supp_rates[0]; + priv->active_rate_ht[1] = ht_info->supp_rates[1]; + iwl4965_set_rxon_chain(priv); + + IWL_DEBUG_ASSOC("supported HT rate 0x%X %X " + "rxon flags 0x%X operation mode :0x%X " + "extension channel offset 0x%x " + "control chan %d\n", + priv->active_rate_ht[0], priv->active_rate_ht[1], + le32_to_cpu(rxon->flags), ht_info->operating_mode, + ht_info->extension_chan_offset, + ht_info->control_channel); + return; +} + +void iwl4965_set_ht_add_station(struct iwl_priv *priv, u8 index) +{ + __le32 sta_flags; + struct sta_ht_info *ht_info = &priv->current_assoc_ht; + + priv->current_channel_width = IWL_CHANNEL_WIDTH_20MHZ; + if (!ht_info->is_ht) + goto done; + + sta_flags = priv->stations[index].sta.station_flags; + + if (ht_info->tx_mimo_ps_mode == IWL_MIMO_PS_DYNAMIC) + sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK; + else + sta_flags &= ~STA_FLG_RTS_MIMO_PROT_MSK; + + sta_flags |= cpu_to_le32( + (u32)ht_info->ampdu_factor << STA_FLG_MAX_AGG_SIZE_POS); + + sta_flags |= cpu_to_le32( + (u32)ht_info->mpdu_density << STA_FLG_AGG_MPDU_DENSITY_POS); + + sta_flags &= (~STA_FLG_FAT_EN_MSK); + ht_info->tx_chan_width = IWL_CHANNEL_WIDTH_20MHZ; + ht_info->chan_width_cap = IWL_CHANNEL_WIDTH_20MHZ; + + if (iwl_is_fat_tx_allowed(priv, ht_info)) { + sta_flags |= STA_FLG_FAT_EN_MSK; + ht_info->chan_width_cap = IWL_CHANNEL_WIDTH_40MHZ; + if (ht_info->supported_chan_width == IWL_CHANNEL_WIDTH_40MHZ) + ht_info->tx_chan_width = IWL_CHANNEL_WIDTH_40MHZ; + } + priv->current_channel_width = ht_info->tx_chan_width; + priv->stations[index].sta.station_flags = sta_flags; + done: + return; +} + +#ifdef CONFIG_IWLWIFI_HT_AGG + +static void iwl4965_sta_modify_add_ba_tid(struct iwl_priv *priv, + int sta_id, int tid, u16 ssn) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->sta_lock, flags); + priv->stations[sta_id].sta.station_flags_msk = 0; + priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_ADDBA_TID_MSK; + priv->stations[sta_id].sta.add_immediate_ba_tid = (u8)tid; + priv->stations[sta_id].sta.add_immediate_ba_ssn = cpu_to_le16(ssn); + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + spin_unlock_irqrestore(&priv->sta_lock, flags); + + iwl_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC); +} + +static void iwl4965_sta_modify_del_ba_tid(struct iwl_priv *priv, + int sta_id, int tid) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->sta_lock, flags); + priv->stations[sta_id].sta.station_flags_msk = 0; + priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK; + priv->stations[sta_id].sta.remove_immediate_ba_tid = (u8)tid; + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + spin_unlock_irqrestore(&priv->sta_lock, flags); + + iwl_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC); +} + +static const u16 default_tid_to_tx_fifo[] = { + IWL_TX_FIFO_AC1, + IWL_TX_FIFO_AC0, + IWL_TX_FIFO_AC0, + IWL_TX_FIFO_AC1, + IWL_TX_FIFO_AC2, + IWL_TX_FIFO_AC2, + IWL_TX_FIFO_AC3, + IWL_TX_FIFO_AC3, + IWL_TX_FIFO_NONE, + IWL_TX_FIFO_NONE, + IWL_TX_FIFO_NONE, + IWL_TX_FIFO_NONE, + IWL_TX_FIFO_NONE, + IWL_TX_FIFO_NONE, + IWL_TX_FIFO_NONE, + IWL_TX_FIFO_NONE, + IWL_TX_FIFO_AC3 +}; + +static int iwl_txq_ctx_activate_free(struct iwl_priv *priv) +{ + int txq_id; + + for (txq_id = 0; txq_id < priv->hw_setting.max_txq_num; txq_id++) + if (!test_and_set_bit(txq_id, &priv->txq_ctx_active_msk)) + return txq_id; + return -1; +} + +int iwl_mac_ht_tx_agg_start(struct ieee80211_hw *hw, u8 *da, u16 tid, + u16 *start_seq_num) +{ + + struct iwl_priv *priv = hw->priv; + int sta_id; + int tx_fifo; + int txq_id; + int ssn = -1; + unsigned long flags; + struct iwl_tid_data *tid_data; + + if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo))) + tx_fifo = default_tid_to_tx_fifo[tid]; + else + return -EINVAL; + + IWL_WARNING("iwl-AGG iwl_mac_ht_tx_agg_start on da=" MAC_FMT + " tid=%d\n", MAC_ARG(da), tid); + + sta_id = iwl_hw_find_station(priv, da); + if (sta_id == IWL_INVALID_STATION) + return -ENXIO; + + txq_id = iwl_txq_ctx_activate_free(priv); + if (txq_id == -1) + return -ENXIO; + + spin_lock_irqsave(&priv->sta_lock, flags); + tid_data = &priv->stations[sta_id].tid[tid]; + ssn = SEQ_TO_SN(tid_data->seq_number); + tid_data->agg.txq_id = txq_id; + spin_unlock_irqrestore(&priv->sta_lock, flags); + + *start_seq_num = ssn; + iwl4965_ba_status(priv, tid, BA_STATUS_ACTIVE); + return iwl4965_tx_queue_agg_enable(priv, txq_id, tx_fifo, + sta_id, tid, ssn); +} + + +int iwl_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, u8 *da, u16 tid, + int generator) +{ + + struct iwl_priv *priv = hw->priv; + int tx_fifo_id, txq_id, sta_id, ssn = -1; + struct iwl_tid_data *tid_data; + int rc; + if (!da) { + IWL_ERROR("%s: da = NULL\n", __func__); + return -EINVAL; + } + + if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo))) + tx_fifo_id = default_tid_to_tx_fifo[tid]; + else + return -EINVAL; + + sta_id = iwl_hw_find_station(priv, da); + + if (sta_id == IWL_INVALID_STATION) + return -ENXIO; + + tid_data = &priv->stations[sta_id].tid[tid]; + ssn = (tid_data->seq_number & IEEE80211_SCTL_SEQ) >> 4; + txq_id = tid_data->agg.txq_id; + + rc = iwl4965_tx_queue_agg_disable(priv, txq_id, ssn, tx_fifo_id); + /* FIXME: need more safe way to handle error condition */ + if (rc) + return rc; + + iwl4965_ba_status(priv, tid, BA_STATUS_INITIATOR_DELBA); + IWL_DEBUG_INFO("iwl_mac_ht_tx_agg_stop on da=" MAC_FMT " tid=%d\n", + MAC_ARG(da), tid); + + return 0; +} + +int iwl_mac_ht_rx_agg_start(struct ieee80211_hw *hw, u8 *da, + u16 tid, u16 start_seq_num) +{ + struct iwl_priv *priv = hw->priv; + int sta_id; + + IWL_WARNING("iwl-AGG iwl_mac_ht_rx_agg_start on da=" MAC_FMT + " tid=%d\n", MAC_ARG(da), tid); + sta_id = iwl_hw_find_station(priv, da); + iwl4965_sta_modify_add_ba_tid(priv, sta_id, tid, start_seq_num); + return 0; +} + +int iwl_mac_ht_rx_agg_stop(struct ieee80211_hw *hw, u8 *da, + u16 tid, int generator) +{ + struct iwl_priv *priv = hw->priv; + int sta_id; + + IWL_WARNING("iwl-AGG iwl_mac_ht_rx_agg_stop on da=" MAC_FMT " tid=%d\n", + MAC_ARG(da), tid); + sta_id = iwl_hw_find_station(priv, da); + iwl4965_sta_modify_del_ba_tid(priv, sta_id, tid); + return 0; +} + +#endif /* CONFIG_IWLWIFI_HT_AGG */ +#endif /* CONFIG_IWLWIFI_HT */ + +/* Set up 4965-specific Rx frame reply handlers */ +void iwl_hw_rx_handler_setup(struct iwl_priv *priv) +{ + /* Legacy Rx frames */ + priv->rx_handlers[REPLY_4965_RX] = iwl4965_rx_reply_rx; + + /* High-throughput (HT) Rx frames */ + priv->rx_handlers[REPLY_RX_PHY_CMD] = iwl4965_rx_reply_rx_phy; + priv->rx_handlers[REPLY_RX_MPDU_CMD] = iwl4965_rx_reply_rx; + + priv->rx_handlers[MISSED_BEACONS_NOTIFICATION] = + iwl4965_rx_missed_beacon_notif; + +#ifdef CONFIG_IWLWIFI_HT +#ifdef CONFIG_IWLWIFI_HT_AGG + priv->rx_handlers[REPLY_COMPRESSED_BA] = iwl4965_rx_reply_compressed_ba; +#endif /* CONFIG_IWLWIFI_AGG */ +#endif /* CONFIG_IWLWIFI */ +} + +void iwl_hw_setup_deferred_work(struct iwl_priv *priv) +{ + INIT_WORK(&priv->txpower_work, iwl4965_bg_txpower_work); + INIT_WORK(&priv->statistics_work, iwl4965_bg_statistics_work); +#ifdef CONFIG_IWLWIFI_SENSITIVITY + INIT_WORK(&priv->sensitivity_work, iwl4965_bg_sensitivity_work); +#endif +#ifdef CONFIG_IWLWIFI_HT +#ifdef CONFIG_IWLWIFI_HT_AGG + INIT_WORK(&priv->agg_work, iwl4965_bg_agg_work); +#endif /* CONFIG_IWLWIFI_AGG */ +#endif /* CONFIG_IWLWIFI_HT */ + init_timer(&priv->statistics_periodic); + priv->statistics_periodic.data = (unsigned long)priv; + priv->statistics_periodic.function = iwl4965_bg_statistics_periodic; +} + +void iwl_hw_cancel_deferred_work(struct iwl_priv *priv) +{ + del_timer_sync(&priv->statistics_periodic); + + cancel_delayed_work(&priv->init_alive_start); +} + +struct pci_device_id iwl_hw_card_ids[] = { + {0x8086, 0x4229, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0x8086, 0x4230, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0} +}; + +int iwl_eeprom_aqcuire_semaphore(struct iwl_priv *priv) +{ + u16 count; + int rc; + + for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) { + iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); + rc = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, + CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, + EEPROM_SEM_TIMEOUT); + if (rc >= 0) { + IWL_DEBUG_IO("Aqcuired semaphore after %d tries.\n", + count+1); + return rc; + } + } + + return rc; +} + +inline void iwl_eeprom_release_semaphore(struct iwl_priv *priv) +{ + iwl_clear_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); +} + + +MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids); diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-4965.h new file mode 100644 index 00000000000..4c700812b45 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-4965.h @@ -0,0 +1,341 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ +#ifndef __iwl_4965_h__ +#define __iwl_4965_h__ + +struct iwl_priv; +struct sta_ht_info; + +/* + * Forward declare iwl-4965.c functions for iwl-base.c + */ +extern int iwl_eeprom_aqcuire_semaphore(struct iwl_priv *priv); +extern void iwl_eeprom_release_semaphore(struct iwl_priv *priv); + +extern int iwl4965_tx_queue_update_wr_ptr(struct iwl_priv *priv, + struct iwl_tx_queue *txq, + u16 byte_cnt); +extern void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr, + int is_ap); +extern void iwl4965_set_rxon_ht(struct iwl_priv *priv, + struct sta_ht_info *ht_info); + +extern void iwl4965_set_rxon_chain(struct iwl_priv *priv); +extern int iwl4965_tx_cmd(struct iwl_priv *priv, struct iwl_cmd *out_cmd, + u8 sta_id, dma_addr_t txcmd_phys, + struct ieee80211_hdr *hdr, u8 hdr_len, + struct ieee80211_tx_control *ctrl, void *sta_in); +extern int iwl4965_init_hw_rates(struct iwl_priv *priv, + struct ieee80211_rate *rates); +extern int iwl4965_alive_notify(struct iwl_priv *priv); +extern void iwl4965_update_rate_scaling(struct iwl_priv *priv, u8 mode); +extern void iwl4965_set_ht_add_station(struct iwl_priv *priv, u8 index); + +extern void iwl4965_chain_noise_reset(struct iwl_priv *priv); +extern void iwl4965_init_sensitivity(struct iwl_priv *priv, u8 flags, + u8 force); +extern int iwl4965_set_fat_chan_info(struct iwl_priv *priv, int phymode, + u16 channel, + const struct iwl_eeprom_channel *eeprom_ch, + u8 fat_extension_channel); +extern void iwl4965_rf_kill_ct_config(struct iwl_priv *priv); + +#ifdef CONFIG_IWLWIFI_HT +#ifdef CONFIG_IWLWIFI_HT_AGG +extern int iwl_mac_ht_tx_agg_start(struct ieee80211_hw *hw, u8 *da, + u16 tid, u16 *start_seq_num); +extern int iwl_mac_ht_rx_agg_start(struct ieee80211_hw *hw, u8 *da, + u16 tid, u16 start_seq_num); +extern int iwl_mac_ht_rx_agg_stop(struct ieee80211_hw *hw, u8 *da, + u16 tid, int generator); +extern int iwl_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, u8 *da, + u16 tid, int generator); +extern void iwl4965_turn_off_agg(struct iwl_priv *priv, u8 tid); +#endif /* CONFIG_IWLWIFI_HT_AGG */ +#endif /*CONFIG_IWLWIFI_HT */ +/* Structures, enum, and defines specific to the 4965 */ + +#define IWL4965_KW_SIZE 0x1000 /*4k */ + +struct iwl_kw { + dma_addr_t dma_addr; + void *v_addr; + size_t size; +}; + +#define TID_QUEUE_CELL_SPACING 50 /*mS */ +#define TID_QUEUE_MAX_SIZE 20 +#define TID_ROUND_VALUE 5 /* mS */ +#define TID_MAX_LOAD_COUNT 8 + +#define TID_MAX_TIME_DIFF ((TID_QUEUE_MAX_SIZE - 1) * TID_QUEUE_CELL_SPACING) +#define TIME_WRAP_AROUND(x, y) (((y) > (x)) ? (y) - (x) : (0-(x)) + (y)) + +#define TID_ALL_ENABLED 0x7f +#define TID_ALL_SPECIFIED 0xff +#define TID_AGG_TPT_THREHOLD 0x0 + +#define IWL_CHANNEL_WIDTH_20MHZ 0 +#define IWL_CHANNEL_WIDTH_40MHZ 1 + +#define IWL_MIMO_PS_STATIC 0 +#define IWL_MIMO_PS_NONE 3 +#define IWL_MIMO_PS_DYNAMIC 1 +#define IWL_MIMO_PS_INVALID 2 + +#define IWL_OPERATION_MODE_AUTO 0 +#define IWL_OPERATION_MODE_HT_ONLY 1 +#define IWL_OPERATION_MODE_MIXED 2 +#define IWL_OPERATION_MODE_20MHZ 3 + +#define IWL_EXT_CHANNEL_OFFSET_AUTO 0 +#define IWL_EXT_CHANNEL_OFFSET_ABOVE 1 +#define IWL_EXT_CHANNEL_OFFSET_ 2 +#define IWL_EXT_CHANNEL_OFFSET_BELOW 3 +#define IWL_EXT_CHANNEL_OFFSET_MAX 4 + +#define NRG_NUM_PREV_STAT_L 20 +#define NUM_RX_CHAINS (3) + +#define TX_POWER_IWL_ILLEGAL_VDET -100000 +#define TX_POWER_IWL_ILLEGAL_VOLTAGE -10000 +#define TX_POWER_IWL_CLOSED_LOOP_MIN_POWER 18 +#define TX_POWER_IWL_CLOSED_LOOP_MAX_POWER 34 +#define TX_POWER_IWL_VDET_SLOPE_BELOW_NOMINAL 17 +#define TX_POWER_IWL_VDET_SLOPE_ABOVE_NOMINAL 20 +#define TX_POWER_IWL_NOMINAL_POWER 26 +#define TX_POWER_IWL_CLOSED_LOOP_ITERATION_LIMIT 1 +#define TX_POWER_IWL_VOLTAGE_CODES_PER_03V 7 +#define TX_POWER_IWL_DEGREES_PER_VDET_CODE 11 +#define IWL_TX_POWER_MAX_NUM_PA_MEASUREMENTS 1 +#define IWL_TX_POWER_CCK_COMPENSATION_B_STEP (9) +#define IWL_TX_POWER_CCK_COMPENSATION_C_STEP (5) + +struct iwl_traffic_load { + unsigned long time_stamp; + u32 packet_count[TID_QUEUE_MAX_SIZE]; + u8 queue_count; + u8 head; + u32 total; +}; + +#ifdef CONFIG_IWLWIFI_HT_AGG +struct iwl_agg_control { + unsigned long next_retry; + u32 wait_for_agg_status; + u32 tid_retry; + u32 requested_ba; + u32 granted_ba; + u8 auto_agg; + u32 tid_traffic_load_threshold; + u32 ba_timeout; + struct iwl_traffic_load traffic_load[TID_MAX_LOAD_COUNT]; +}; +#endif /*CONFIG_IWLWIFI_HT_AGG */ + +struct iwl_lq_mngr { +#ifdef CONFIG_IWLWIFI_HT_AGG + struct iwl_agg_control agg_ctrl; +#endif + spinlock_t lock; + s32 max_window_size; + s32 *expected_tpt; + u8 *next_higher_rate; + u8 *next_lower_rate; + unsigned long stamp; + unsigned long stamp_last; + u32 flush_time; + u32 tx_packets; + u8 lq_ready; +}; + + +/* Sensitivity and chain noise calibration */ +#define INTERFERENCE_DATA_AVAILABLE __constant_cpu_to_le32(1) +#define INITIALIZATION_VALUE 0xFFFF +#define CAL_NUM_OF_BEACONS 20 +#define MAXIMUM_ALLOWED_PATHLOSS 15 + +/* Param table within SENSITIVITY_CMD */ +#define HD_MIN_ENERGY_CCK_DET_INDEX (0) +#define HD_MIN_ENERGY_OFDM_DET_INDEX (1) +#define HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX (2) +#define HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX (3) +#define HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX (4) +#define HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX (5) +#define HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX (6) +#define HD_BARKER_CORR_TH_ADD_MIN_INDEX (7) +#define HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX (8) +#define HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX (9) +#define HD_OFDM_ENERGY_TH_IN_INDEX (10) + +#define SENSITIVITY_CMD_CONTROL_DEFAULT_TABLE __constant_cpu_to_le16(0) +#define SENSITIVITY_CMD_CONTROL_WORK_TABLE __constant_cpu_to_le16(1) + +#define CHAIN_NOISE_MAX_DELTA_GAIN_CODE 3 + +#define MAX_FA_OFDM 50 +#define MIN_FA_OFDM 5 +#define MAX_FA_CCK 50 +#define MIN_FA_CCK 5 + +#define NRG_MIN_CCK 97 +#define NRG_MAX_CCK 0 + +#define AUTO_CORR_MIN_OFDM 85 +#define AUTO_CORR_MIN_OFDM_MRC 170 +#define AUTO_CORR_MIN_OFDM_X1 105 +#define AUTO_CORR_MIN_OFDM_MRC_X1 220 +#define AUTO_CORR_MAX_OFDM 120 +#define AUTO_CORR_MAX_OFDM_MRC 210 +#define AUTO_CORR_MAX_OFDM_X1 140 +#define AUTO_CORR_MAX_OFDM_MRC_X1 270 +#define AUTO_CORR_STEP_OFDM 1 + +#define AUTO_CORR_MIN_CCK (125) +#define AUTO_CORR_MAX_CCK (200) +#define AUTO_CORR_MIN_CCK_MRC 200 +#define AUTO_CORR_MAX_CCK_MRC 400 +#define AUTO_CORR_STEP_CCK 3 +#define AUTO_CORR_MAX_TH_CCK 160 + +#define NRG_ALG 0 +#define AUTO_CORR_ALG 1 +#define NRG_DIFF 2 +#define NRG_STEP_CCK 2 +#define NRG_MARGIN 8 +#define MAX_NUMBER_CCK_NO_FA 100 + +#define AUTO_CORR_CCK_MIN_VAL_DEF (125) + +#define CHAIN_A 0 +#define CHAIN_B 1 +#define CHAIN_C 2 +#define CHAIN_NOISE_DELTA_GAIN_INIT_VAL 4 +#define ALL_BAND_FILTER 0xFF00 +#define IN_BAND_FILTER 0xFF +#define MIN_AVERAGE_NOISE_MAX_VALUE 0xFFFFFFFF + +enum iwl_false_alarm_state { + IWL_FA_TOO_MANY = 0, + IWL_FA_TOO_FEW = 1, + IWL_FA_GOOD_RANGE = 2, +}; + +enum iwl_chain_noise_state { + IWL_CHAIN_NOISE_ALIVE = 0, /* must be 0 */ + IWL_CHAIN_NOISE_ACCUMULATE = 1, + IWL_CHAIN_NOISE_CALIBRATED = 2, +}; + +enum iwl_sensitivity_state { + IWL_SENS_CALIB_ALLOWED = 0, + IWL_SENS_CALIB_NEED_REINIT = 1, +}; + +enum iwl_calib_enabled_state { + IWL_CALIB_DISABLED = 0, /* must be 0 */ + IWL_CALIB_ENABLED = 1, +}; + +struct statistics_general_data { + u32 beacon_silence_rssi_a; + u32 beacon_silence_rssi_b; + u32 beacon_silence_rssi_c; + u32 beacon_energy_a; + u32 beacon_energy_b; + u32 beacon_energy_c; +}; + +/* Sensitivity calib data */ +struct iwl_sensitivity_data { + u32 auto_corr_ofdm; + u32 auto_corr_ofdm_mrc; + u32 auto_corr_ofdm_x1; + u32 auto_corr_ofdm_mrc_x1; + u32 auto_corr_cck; + u32 auto_corr_cck_mrc; + + u32 last_bad_plcp_cnt_ofdm; + u32 last_fa_cnt_ofdm; + u32 last_bad_plcp_cnt_cck; + u32 last_fa_cnt_cck; + + u32 nrg_curr_state; + u32 nrg_prev_state; + u32 nrg_value[10]; + u8 nrg_silence_rssi[NRG_NUM_PREV_STAT_L]; + u32 nrg_silence_ref; + u32 nrg_energy_idx; + u32 nrg_silence_idx; + u32 nrg_th_cck; + s32 nrg_auto_corr_silence_diff; + u32 num_in_cck_no_fa; + u32 nrg_th_ofdm; + + u8 state; +}; + +/* Chain noise (differential Rx gain) calib data */ +struct iwl_chain_noise_data { + u8 state; + u16 beacon_count; + u32 chain_noise_a; + u32 chain_noise_b; + u32 chain_noise_c; + u32 chain_signal_a; + u32 chain_signal_b; + u32 chain_signal_c; + u8 disconn_array[NUM_RX_CHAINS]; + u8 delta_gain_code[NUM_RX_CHAINS]; + u8 radio_write; +}; + +/* IWL4965 */ +#define RATE_MCS_CODE_MSK 0x7 +#define RATE_MCS_MIMO_POS 3 +#define RATE_MCS_MIMO_MSK 0x8 +#define RATE_MCS_HT_DUP_POS 5 +#define RATE_MCS_HT_DUP_MSK 0x20 +#define RATE_MCS_FLAGS_POS 8 +#define RATE_MCS_HT_POS 8 +#define RATE_MCS_HT_MSK 0x100 +#define RATE_MCS_CCK_POS 9 +#define RATE_MCS_CCK_MSK 0x200 +#define RATE_MCS_GF_POS 10 +#define RATE_MCS_GF_MSK 0x400 + +#define RATE_MCS_FAT_POS 11 +#define RATE_MCS_FAT_MSK 0x800 +#define RATE_MCS_DUP_POS 12 +#define RATE_MCS_DUP_MSK 0x1000 +#define RATE_MCS_SGI_POS 13 +#define RATE_MCS_SGI_MSK 0x2000 + +#define EEPROM_SEM_TIMEOUT 10 +#define EEPROM_SEM_RETRY_LIMIT 1000 + +#endif /* __iwl_4965_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-channel.h b/drivers/net/wireless/iwlwifi/iwl-channel.h new file mode 100644 index 00000000000..023c3f240ce --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-channel.h @@ -0,0 +1,161 @@ +/****************************************************************************** + * + * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ +#ifndef __iwl_channel_h__ +#define __iwl_channel_h__ + +#define IWL_NUM_SCAN_RATES (2) + +struct iwl_channel_tgd_info { + u8 type; + s8 max_power; +}; + +struct iwl_channel_tgh_info { + s64 last_radar_time; +}; + +/* current Tx power values to use, one for each rate for each channel. + * requested power is limited by: + * -- regulatory EEPROM limits for this channel + * -- hardware capabilities (clip-powers) + * -- spectrum management + * -- user preference (e.g. iwconfig) + * when requested power is set, base power index must also be set. */ +struct iwl_channel_power_info { + struct iwl_tx_power tpc; /* actual radio and DSP gain settings */ + s8 power_table_index; /* actual (compenst'd) index into gain table */ + s8 base_power_index; /* gain index for power at factory temp. */ + s8 requested_power; /* power (dBm) requested for this chnl/rate */ +}; + +/* current scan Tx power values to use, one for each scan rate for each + * channel. */ +struct iwl_scan_power_info { + struct iwl_tx_power tpc; /* actual radio and DSP gain settings */ + s8 power_table_index; /* actual (compenst'd) index into gain table */ + s8 requested_power; /* scan pwr (dBm) requested for chnl/rate */ +}; + +/* Channel unlock period is 15 seconds. If no beacon or probe response + * has been received within 15 seconds on a locked channel then the channel + * remains locked. */ +#define TX_UNLOCK_PERIOD 15 + +/* CSA lock period is 15 seconds. If a CSA has been received on a channel in + * the last 15 seconds, the channel is locked */ +#define CSA_LOCK_PERIOD 15 +/* + * One for each channel, holds all channel setup data + * Some of the fields (e.g. eeprom and flags/max_power_avg) are redundant + * with one another! + */ +#define IWL4965_MAX_RATE (33) + +struct iwl_channel_info { + struct iwl_channel_tgd_info tgd; + struct iwl_channel_tgh_info tgh; + struct iwl_eeprom_channel eeprom; /* EEPROM regulatory limit */ + struct iwl_eeprom_channel fat_eeprom; /* EEPROM regulatory limit for + * FAT channel */ + + u8 channel; /* channel number */ + u8 flags; /* flags copied from EEPROM */ + s8 max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */ + s8 curr_txpow; /* (dBm) regulatory/spectrum/user (not h/w) */ + s8 min_power; /* always 0 */ + s8 scan_power; /* (dBm) regul. eeprom, direct scans, any rate */ + + u8 group_index; /* 0-4, maps channel to group1/2/3/4/5 */ + u8 band_index; /* 0-4, maps channel to band1/2/3/4/5 */ + u8 phymode; /* MODE_IEEE80211{A,B,G} */ + + /* Radio/DSP gain settings for each "normal" data Tx rate. + * These include, in addition to RF and DSP gain, a few fields for + * remembering/modifying gain settings (indexes). */ + struct iwl_channel_power_info power_info[IWL4965_MAX_RATE]; + +#if IWL == 4965 + /* FAT channel info */ + s8 fat_max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */ + s8 fat_curr_txpow; /* (dBm) regulatory/spectrum/user (not h/w) */ + s8 fat_min_power; /* always 0 */ + s8 fat_scan_power; /* (dBm) eeprom, direct scans, any rate */ + u8 fat_flags; /* flags copied from EEPROM */ + u8 fat_extension_channel; +#endif + + /* Radio/DSP gain settings for each scan rate, for directed scans. */ + struct iwl_scan_power_info scan_pwr_info[IWL_NUM_SCAN_RATES]; +}; + +struct iwl_clip_group { + /* maximum power level to prevent clipping for each rate, derived by + * us from this band's saturation power in EEPROM */ + const s8 clip_powers[IWL_MAX_RATES]; +}; + +static inline int is_channel_valid(const struct iwl_channel_info *ch_info) +{ + if (ch_info == NULL) + return 0; + return (ch_info->flags & EEPROM_CHANNEL_VALID) ? 1 : 0; +} + +static inline int is_channel_narrow(const struct iwl_channel_info *ch_info) +{ + return (ch_info->flags & EEPROM_CHANNEL_NARROW) ? 1 : 0; +} + +static inline int is_channel_radar(const struct iwl_channel_info *ch_info) +{ + return (ch_info->flags & EEPROM_CHANNEL_RADAR) ? 1 : 0; +} + +static inline u8 is_channel_a_band(const struct iwl_channel_info *ch_info) +{ + return ch_info->phymode == MODE_IEEE80211A; +} + +static inline u8 is_channel_bg_band(const struct iwl_channel_info *ch_info) +{ + return ((ch_info->phymode == MODE_IEEE80211B) || + (ch_info->phymode == MODE_IEEE80211G)); +} + +static inline int is_channel_passive(const struct iwl_channel_info *ch) +{ + return (!(ch->flags & EEPROM_CHANNEL_ACTIVE)) ? 1 : 0; +} + +static inline int is_channel_ibss(const struct iwl_channel_info *ch) +{ + return ((ch->flags & EEPROM_CHANNEL_IBSS)) ? 1 : 0; +} + +extern const struct iwl_channel_info *iwl_get_channel_info( + const struct iwl_priv *priv, int phymode, u16 channel); + +#endif diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h new file mode 100644 index 00000000000..9de8d7f6efa --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -0,0 +1,1734 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU Geeral Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +#ifndef __iwl_commands_h__ +#define __iwl_commands_h__ + +enum { + REPLY_ALIVE = 0x1, + REPLY_ERROR = 0x2, + + /* RXON and QOS commands */ + REPLY_RXON = 0x10, + REPLY_RXON_ASSOC = 0x11, + REPLY_QOS_PARAM = 0x13, + REPLY_RXON_TIMING = 0x14, + + /* Multi-Station support */ + REPLY_ADD_STA = 0x18, + REPLY_REMOVE_STA = 0x19, /* not used */ + REPLY_REMOVE_ALL_STA = 0x1a, /* not used */ + + /* RX, TX, LEDs */ +#if IWL == 3945 + REPLY_3945_RX = 0x1b, /* 3945 only */ +#endif + REPLY_TX = 0x1c, + REPLY_RATE_SCALE = 0x47, /* 3945 only */ + REPLY_LEDS_CMD = 0x48, + REPLY_TX_LINK_QUALITY_CMD = 0x4e, /* 4965 only */ + + /* 802.11h related */ + RADAR_NOTIFICATION = 0x70, /* not used */ + REPLY_QUIET_CMD = 0x71, /* not used */ + REPLY_CHANNEL_SWITCH = 0x72, + CHANNEL_SWITCH_NOTIFICATION = 0x73, + REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74, + SPECTRUM_MEASURE_NOTIFICATION = 0x75, + + /* Power Management */ + POWER_TABLE_CMD = 0x77, + PM_SLEEP_NOTIFICATION = 0x7A, + PM_DEBUG_STATISTIC_NOTIFIC = 0x7B, + + /* Scan commands and notifications */ + REPLY_SCAN_CMD = 0x80, + REPLY_SCAN_ABORT_CMD = 0x81, + SCAN_START_NOTIFICATION = 0x82, + SCAN_RESULTS_NOTIFICATION = 0x83, + SCAN_COMPLETE_NOTIFICATION = 0x84, + + /* IBSS/AP commands */ + BEACON_NOTIFICATION = 0x90, + REPLY_TX_BEACON = 0x91, + WHO_IS_AWAKE_NOTIFICATION = 0x94, /* not used */ + + /* Miscellaneous commands */ + QUIET_NOTIFICATION = 0x96, /* not used */ + REPLY_TX_PWR_TABLE_CMD = 0x97, + MEASURE_ABORT_NOTIFICATION = 0x99, /* not used */ + + /* BT config command */ + REPLY_BT_CONFIG = 0x9b, + + /* 4965 Statistics */ + REPLY_STATISTICS_CMD = 0x9c, + STATISTICS_NOTIFICATION = 0x9d, + + /* RF-KILL commands and notifications */ + REPLY_CARD_STATE_CMD = 0xa0, + CARD_STATE_NOTIFICATION = 0xa1, + + /* Missed beacons notification */ + MISSED_BEACONS_NOTIFICATION = 0xa2, + +#if IWL == 4965 + REPLY_CT_KILL_CONFIG_CMD = 0xa4, + SENSITIVITY_CMD = 0xa8, + REPLY_PHY_CALIBRATION_CMD = 0xb0, + REPLY_RX_PHY_CMD = 0xc0, + REPLY_RX_MPDU_CMD = 0xc1, + REPLY_4965_RX = 0xc3, + REPLY_COMPRESSED_BA = 0xc5, +#endif + REPLY_MAX = 0xff +}; + +/****************************************************************************** + * (0) + * Header + * + *****************************************************************************/ + +#define IWL_CMD_FAILED_MSK 0x40 + +struct iwl_cmd_header { + u8 cmd; + u8 flags; + /* We have 15 LSB to use as we please (MSB indicates + * a frame Rx'd from the HW). We encode the following + * information into the sequence field: + * + * 0:7 index in fifo + * 8:13 fifo selection + * 14:14 bit indicating if this packet references the 'extra' + * storage at the end of the memory queue + * 15:15 (Rx indication) + * + */ + __le16 sequence; + + /* command data follows immediately */ + u8 data[0]; +} __attribute__ ((packed)); + +/****************************************************************************** + * (0a) + * Alive and Error Commands & Responses: + * + *****************************************************************************/ + +#define UCODE_VALID_OK __constant_cpu_to_le32(0x1) +#define INITIALIZE_SUBTYPE (9) + +/* + * REPLY_ALIVE = 0x1 (response only, not a command) + */ +struct iwl_alive_resp { + u8 ucode_minor; + u8 ucode_major; + __le16 reserved1; + u8 sw_rev[8]; + u8 ver_type; + u8 ver_subtype; + __le16 reserved2; + __le32 log_event_table_ptr; + __le32 error_event_table_ptr; + __le32 timestamp; + __le32 is_valid; +} __attribute__ ((packed)); + +struct iwl_init_alive_resp { + u8 ucode_minor; + u8 ucode_major; + __le16 reserved1; + u8 sw_rev[8]; + u8 ver_type; + u8 ver_subtype; + __le16 reserved2; + __le32 log_event_table_ptr; + __le32 error_event_table_ptr; + __le32 timestamp; + __le32 is_valid; + +#if IWL == 4965 + /* calibration values from "initialize" uCode */ + __le32 voltage; /* signed */ + __le32 therm_r1[2]; /* signed 1st for normal, 2nd for FAT channel */ + __le32 therm_r2[2]; /* signed */ + __le32 therm_r3[2]; /* signed */ + __le32 therm_r4[2]; /* signed */ + __le32 tx_atten[5][2]; /* signed MIMO gain comp, 5 freq groups, + * 2 Tx chains */ +#endif +} __attribute__ ((packed)); + +union tsf { + u8 byte[8]; + __le16 word[4]; + __le32 dw[2]; +}; + +/* + * REPLY_ERROR = 0x2 (response only, not a command) + */ +struct iwl_error_resp { + __le32 error_type; + u8 cmd_id; + u8 reserved1; + __le16 bad_cmd_seq_num; +#if IWL == 3945 + __le16 reserved2; +#endif + __le32 error_info; + union tsf timestamp; +} __attribute__ ((packed)); + +/****************************************************************************** + * (1) + * RXON Commands & Responses: + * + *****************************************************************************/ + +/* + * Rx config defines & structure + */ +/* rx_config device types */ +enum { + RXON_DEV_TYPE_AP = 1, + RXON_DEV_TYPE_ESS = 3, + RXON_DEV_TYPE_IBSS = 4, + RXON_DEV_TYPE_SNIFFER = 6, +}; + +/* rx_config flags */ +/* band & modulation selection */ +#define RXON_FLG_BAND_24G_MSK __constant_cpu_to_le32(1 << 0) +#define RXON_FLG_CCK_MSK __constant_cpu_to_le32(1 << 1) +/* auto detection enable */ +#define RXON_FLG_AUTO_DETECT_MSK __constant_cpu_to_le32(1 << 2) +/* TGg protection when tx */ +#define RXON_FLG_TGG_PROTECT_MSK __constant_cpu_to_le32(1 << 3) +/* cck short slot & preamble */ +#define RXON_FLG_SHORT_SLOT_MSK __constant_cpu_to_le32(1 << 4) +#define RXON_FLG_SHORT_PREAMBLE_MSK __constant_cpu_to_le32(1 << 5) +/* antenna selection */ +#define RXON_FLG_DIS_DIV_MSK __constant_cpu_to_le32(1 << 7) +#define RXON_FLG_ANT_SEL_MSK __constant_cpu_to_le32(0x0f00) +#define RXON_FLG_ANT_A_MSK __constant_cpu_to_le32(1 << 8) +#define RXON_FLG_ANT_B_MSK __constant_cpu_to_le32(1 << 9) +/* radar detection enable */ +#define RXON_FLG_RADAR_DETECT_MSK __constant_cpu_to_le32(1 << 12) +#define RXON_FLG_TGJ_NARROW_BAND_MSK __constant_cpu_to_le32(1 << 13) +/* rx response to host with 8-byte TSF +* (according to ON_AIR deassertion) */ +#define RXON_FLG_TSF2HOST_MSK __constant_cpu_to_le32(1 << 15) + +/* rx_config filter flags */ +/* accept all data frames */ +#define RXON_FILTER_PROMISC_MSK __constant_cpu_to_le32(1 << 0) +/* pass control & management to host */ +#define RXON_FILTER_CTL2HOST_MSK __constant_cpu_to_le32(1 << 1) +/* accept multi-cast */ +#define RXON_FILTER_ACCEPT_GRP_MSK __constant_cpu_to_le32(1 << 2) +/* don't decrypt uni-cast frames */ +#define RXON_FILTER_DIS_DECRYPT_MSK __constant_cpu_to_le32(1 << 3) +/* don't decrypt multi-cast frames */ +#define RXON_FILTER_DIS_GRP_DECRYPT_MSK __constant_cpu_to_le32(1 << 4) +/* STA is associated */ +#define RXON_FILTER_ASSOC_MSK __constant_cpu_to_le32(1 << 5) +/* transfer to host non bssid beacons in associated state */ +#define RXON_FILTER_BCON_AWARE_MSK __constant_cpu_to_le32(1 << 6) + +/* + * REPLY_RXON = 0x10 (command, has simple generic response) + */ +struct iwl_rxon_cmd { + u8 node_addr[6]; + __le16 reserved1; + u8 bssid_addr[6]; + __le16 reserved2; + u8 wlap_bssid_addr[6]; + __le16 reserved3; + u8 dev_type; + u8 air_propagation; +#if IWL == 3945 + __le16 reserved4; +#elif IWL == 4965 + __le16 rx_chain; +#endif + u8 ofdm_basic_rates; + u8 cck_basic_rates; + __le16 assoc_id; + __le32 flags; + __le32 filter_flags; + __le16 channel; +#if IWL == 3945 + __le16 reserved5; +#elif IWL == 4965 + u8 ofdm_ht_single_stream_basic_rates; + u8 ofdm_ht_dual_stream_basic_rates; +#endif +} __attribute__ ((packed)); + +/* + * REPLY_RXON_ASSOC = 0x11 (command, has simple generic response) + */ +struct iwl_rxon_assoc_cmd { + __le32 flags; + __le32 filter_flags; + u8 ofdm_basic_rates; + u8 cck_basic_rates; +#if IWL == 4965 + u8 ofdm_ht_single_stream_basic_rates; + u8 ofdm_ht_dual_stream_basic_rates; + __le16 rx_chain_select_flags; +#endif + __le16 reserved; +} __attribute__ ((packed)); + +/* + * REPLY_RXON_TIMING = 0x14 (command, has simple generic response) + */ +struct iwl_rxon_time_cmd { + union tsf timestamp; + __le16 beacon_interval; + __le16 atim_window; + __le32 beacon_init_val; + __le16 listen_interval; + __le16 reserved; +} __attribute__ ((packed)); + +struct iwl_tx_power { + u8 tx_gain; /* gain for analog radio */ + u8 dsp_atten; /* gain for DSP */ +} __attribute__ ((packed)); + +#if IWL == 3945 +struct iwl_power_per_rate { + u8 rate; /* plcp */ + struct iwl_tx_power tpc; + u8 reserved; +} __attribute__ ((packed)); + +#elif IWL == 4965 +#define POWER_TABLE_NUM_ENTRIES 33 +#define POWER_TABLE_NUM_HT_OFDM_ENTRIES 32 +#define POWER_TABLE_CCK_ENTRY 32 +struct tx_power_dual_stream { + __le32 dw; +} __attribute__ ((packed)); + +struct iwl_tx_power_db { + struct tx_power_dual_stream power_tbl[POWER_TABLE_NUM_ENTRIES]; +} __attribute__ ((packed)); +#endif + +/* + * REPLY_CHANNEL_SWITCH = 0x72 (command, has simple generic response) + */ +struct iwl_channel_switch_cmd { + u8 band; + u8 expect_beacon; + __le16 channel; + __le32 rxon_flags; + __le32 rxon_filter_flags; + __le32 switch_time; +#if IWL == 3945 + struct iwl_power_per_rate power[IWL_MAX_RATES]; +#elif IWL == 4965 + struct iwl_tx_power_db tx_power; +#endif +} __attribute__ ((packed)); + +/* + * CHANNEL_SWITCH_NOTIFICATION = 0x73 (notification only, not a command) + */ +struct iwl_csa_notification { + __le16 band; + __le16 channel; + __le32 status; /* 0 - OK, 1 - fail */ +} __attribute__ ((packed)); + +/****************************************************************************** + * (2) + * Quality-of-Service (QOS) Commands & Responses: + * + *****************************************************************************/ +struct iwl_ac_qos { + __le16 cw_min; + __le16 cw_max; + u8 aifsn; + u8 reserved1; + __le16 edca_txop; +} __attribute__ ((packed)); + +/* QoS flags defines */ +#define QOS_PARAM_FLG_UPDATE_EDCA_MSK __constant_cpu_to_le32(0x01) +#define QOS_PARAM_FLG_TGN_MSK __constant_cpu_to_le32(0x02) +#define QOS_PARAM_FLG_TXOP_TYPE_MSK __constant_cpu_to_le32(0x10) + +/* + * TXFIFO Queue number defines + */ +/* number of Access categories (AC) (EDCA), queues 0..3 */ +#define AC_NUM 4 + +/* + * REPLY_QOS_PARAM = 0x13 (command, has simple generic response) + */ +struct iwl_qosparam_cmd { + __le32 qos_flags; + struct iwl_ac_qos ac[AC_NUM]; +} __attribute__ ((packed)); + +/****************************************************************************** + * (3) + * Add/Modify Stations Commands & Responses: + * + *****************************************************************************/ +/* + * Multi station support + */ +#define IWL_AP_ID 0 +#define IWL_MULTICAST_ID 1 +#define IWL_STA_ID 2 + +#define IWL3945_BROADCAST_ID 24 +#define IWL3945_STATION_COUNT 25 + +#define IWL4965_BROADCAST_ID 31 +#define IWL4965_STATION_COUNT 32 + +#define IWL_STATION_COUNT 32 /* MAX(3945,4965)*/ +#define IWL_INVALID_STATION 255 + +#if IWL == 3945 +#define STA_FLG_TX_RATE_MSK __constant_cpu_to_le32(1<<2); +#endif +#define STA_FLG_PWR_SAVE_MSK __constant_cpu_to_le32(1<<8); + +#define STA_CONTROL_MODIFY_MSK 0x01 + +/* key flags __le16*/ +#define STA_KEY_FLG_ENCRYPT_MSK __constant_cpu_to_le16(0x7) +#define STA_KEY_FLG_NO_ENC __constant_cpu_to_le16(0x0) +#define STA_KEY_FLG_WEP __constant_cpu_to_le16(0x1) +#define STA_KEY_FLG_CCMP __constant_cpu_to_le16(0x2) +#define STA_KEY_FLG_TKIP __constant_cpu_to_le16(0x3) + +#define STA_KEY_FLG_KEYID_POS 8 +#define STA_KEY_FLG_INVALID __constant_cpu_to_le16(0x0800) + +/* modify flags */ +#define STA_MODIFY_KEY_MASK 0x01 +#define STA_MODIFY_TID_DISABLE_TX 0x02 +#define STA_MODIFY_TX_RATE_MSK 0x04 +#define STA_MODIFY_ADDBA_TID_MSK 0x08 +#define STA_MODIFY_DELBA_TID_MSK 0x10 +#define BUILD_RAxTID(sta_id, tid) (((sta_id) << 4) + (tid)) + +/* + * Antenna masks: + * bit14:15 01 B inactive, A active + * 10 B active, A inactive + * 11 Both active + */ +#define RATE_MCS_ANT_A_POS 14 +#define RATE_MCS_ANT_B_POS 15 +#define RATE_MCS_ANT_A_MSK 0x4000 +#define RATE_MCS_ANT_B_MSK 0x8000 +#define RATE_MCS_ANT_AB_MSK 0xc000 + +struct iwl_keyinfo { + __le16 key_flags; + u8 tkip_rx_tsc_byte2; /* TSC[2] for key mix ph1 detection */ + u8 reserved1; + __le16 tkip_rx_ttak[5]; /* 10-byte unicast TKIP TTAK */ + __le16 reserved2; + u8 key[16]; /* 16-byte unicast decryption key */ +} __attribute__ ((packed)); + +struct sta_id_modify { + u8 addr[ETH_ALEN]; + __le16 reserved1; + u8 sta_id; + u8 modify_mask; + __le16 reserved2; +} __attribute__ ((packed)); + +/* + * REPLY_ADD_STA = 0x18 (command) + */ +struct iwl_addsta_cmd { + u8 mode; + u8 reserved[3]; + struct sta_id_modify sta; + struct iwl_keyinfo key; + __le32 station_flags; + __le32 station_flags_msk; + __le16 tid_disable_tx; +#if IWL == 3945 + __le16 rate_n_flags; +#else + __le16 reserved1; +#endif + u8 add_immediate_ba_tid; + u8 remove_immediate_ba_tid; + __le16 add_immediate_ba_ssn; +#if IWL == 4965 + __le32 reserved2; +#endif +} __attribute__ ((packed)); + +/* + * REPLY_ADD_STA = 0x18 (response) + */ +struct iwl_add_sta_resp { + u8 status; +} __attribute__ ((packed)); + +#define ADD_STA_SUCCESS_MSK 0x1 + +/****************************************************************************** + * (4) + * Rx Responses: + * + *****************************************************************************/ + +struct iwl_rx_frame_stats { + u8 phy_count; + u8 id; + u8 rssi; + u8 agc; + __le16 sig_avg; + __le16 noise_diff; + u8 payload[0]; +} __attribute__ ((packed)); + +struct iwl_rx_frame_hdr { + __le16 channel; + __le16 phy_flags; + u8 reserved1; + u8 rate; + __le16 len; + u8 payload[0]; +} __attribute__ ((packed)); + +#define RX_RES_STATUS_NO_CRC32_ERROR __constant_cpu_to_le32(1 << 0) +#define RX_RES_STATUS_NO_RXE_OVERFLOW __constant_cpu_to_le32(1 << 1) + +#define RX_RES_PHY_FLAGS_BAND_24_MSK __constant_cpu_to_le16(1 << 0) +#define RX_RES_PHY_FLAGS_MOD_CCK_MSK __constant_cpu_to_le16(1 << 1) +#define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK __constant_cpu_to_le16(1 << 2) +#define RX_RES_PHY_FLAGS_NARROW_BAND_MSK __constant_cpu_to_le16(1 << 3) +#define RX_RES_PHY_FLAGS_ANTENNA_MSK __constant_cpu_to_le16(0xf0) + +#define RX_RES_STATUS_SEC_TYPE_MSK (0x7 << 8) +#define RX_RES_STATUS_SEC_TYPE_NONE (0x0 << 8) +#define RX_RES_STATUS_SEC_TYPE_WEP (0x1 << 8) +#define RX_RES_STATUS_SEC_TYPE_CCMP (0x2 << 8) +#define RX_RES_STATUS_SEC_TYPE_TKIP (0x3 << 8) + +#define RX_RES_STATUS_DECRYPT_TYPE_MSK (0x3 << 11) +#define RX_RES_STATUS_NOT_DECRYPT (0x0 << 11) +#define RX_RES_STATUS_DECRYPT_OK (0x3 << 11) +#define RX_RES_STATUS_BAD_ICV_MIC (0x1 << 11) +#define RX_RES_STATUS_BAD_KEY_TTAK (0x2 << 11) + +struct iwl_rx_frame_end { + __le32 status; + __le64 timestamp; + __le32 beacon_timestamp; +} __attribute__ ((packed)); + +/* + * REPLY_3945_RX = 0x1b (response only, not a command) + * + * NOTE: DO NOT dereference from casts to this structure + * It is provided only for calculating minimum data set size. + * The actual offsets of the hdr and end are dynamic based on + * stats.phy_count + */ +struct iwl_rx_frame { + struct iwl_rx_frame_stats stats; + struct iwl_rx_frame_hdr hdr; + struct iwl_rx_frame_end end; +} __attribute__ ((packed)); + +/* Fixed (non-configurable) rx data from phy */ +#define RX_PHY_FLAGS_ANTENNAE_OFFSET (4) +#define RX_PHY_FLAGS_ANTENNAE_MASK (0x70) +#define IWL_AGC_DB_MASK (0x3f80) /* MASK(7,13) */ +#define IWL_AGC_DB_POS (7) +struct iwl4965_rx_non_cfg_phy { + __le16 ant_selection; /* ant A bit 4, ant B bit 5, ant C bit 6 */ + __le16 agc_info; /* agc code 0:6, agc dB 7:13, reserved 14:15 */ + u8 rssi_info[6]; /* we use even entries, 0/2/4 for A/B/C rssi */ + u8 pad[0]; +} __attribute__ ((packed)); + +/* + * REPLY_4965_RX = 0xc3 (response only, not a command) + * Used only for legacy (non 11n) frames. + */ +#define RX_RES_PHY_CNT 14 +struct iwl4965_rx_phy_res { + u8 non_cfg_phy_cnt; /* non configurable DSP phy data byte count */ + u8 cfg_phy_cnt; /* configurable DSP phy data byte count */ + u8 stat_id; /* configurable DSP phy data set ID */ + u8 reserved1; + __le64 timestamp; /* TSF at on air rise */ + __le32 beacon_time_stamp; /* beacon at on-air rise */ + __le16 phy_flags; /* general phy flags: band, modulation, ... */ + __le16 channel; /* channel number */ + __le16 non_cfg_phy[RX_RES_PHY_CNT]; /* upto 14 phy entries */ + __le32 reserved2; + __le32 rate_n_flags; + __le16 byte_count; /* frame's byte-count */ + __le16 reserved3; +} __attribute__ ((packed)); + +struct iwl4965_rx_mpdu_res_start { + __le16 byte_count; + __le16 reserved; +} __attribute__ ((packed)); + + +/****************************************************************************** + * (5) + * Tx Commands & Responses: + * + *****************************************************************************/ + +/* Tx flags */ +#define TX_CMD_FLG_RTS_MSK __constant_cpu_to_le32(1 << 1) +#define TX_CMD_FLG_CTS_MSK __constant_cpu_to_le32(1 << 2) +#define TX_CMD_FLG_ACK_MSK __constant_cpu_to_le32(1 << 3) +#define TX_CMD_FLG_STA_RATE_MSK __constant_cpu_to_le32(1 << 4) +#define TX_CMD_FLG_IMM_BA_RSP_MASK __constant_cpu_to_le32(1 << 6) +#define TX_CMD_FLG_FULL_TXOP_PROT_MSK __constant_cpu_to_le32(1 << 7) +#define TX_CMD_FLG_ANT_SEL_MSK __constant_cpu_to_le32(0xf00) +#define TX_CMD_FLG_ANT_A_MSK __constant_cpu_to_le32(1 << 8) +#define TX_CMD_FLG_ANT_B_MSK __constant_cpu_to_le32(1 << 9) + +/* ucode ignores BT priority for this frame */ +#define TX_CMD_FLG_BT_DIS_MSK __constant_cpu_to_le32(1 << 12) + +/* ucode overrides sequence control */ +#define TX_CMD_FLG_SEQ_CTL_MSK __constant_cpu_to_le32(1 << 13) + +/* signal that this frame is non-last MPDU */ +#define TX_CMD_FLG_MORE_FRAG_MSK __constant_cpu_to_le32(1 << 14) + +/* calculate TSF in outgoing frame */ +#define TX_CMD_FLG_TSF_MSK __constant_cpu_to_le32(1 << 16) + +/* activate TX calibration. */ +#define TX_CMD_FLG_CALIB_MSK __constant_cpu_to_le32(1 << 17) + +/* signals that 2 bytes pad was inserted + after the MAC header */ +#define TX_CMD_FLG_MH_PAD_MSK __constant_cpu_to_le32(1 << 20) + +/* HCCA-AP - disable duration overwriting. */ +#define TX_CMD_FLG_DUR_MSK __constant_cpu_to_le32(1 << 25) + +/* + * TX command security control + */ +#define TX_CMD_SEC_WEP 0x01 +#define TX_CMD_SEC_CCM 0x02 +#define TX_CMD_SEC_TKIP 0x03 +#define TX_CMD_SEC_MSK 0x03 +#define TX_CMD_SEC_SHIFT 6 +#define TX_CMD_SEC_KEY128 0x08 + +/* + * TX command Frame life time + */ + +struct iwl_dram_scratch { + u8 try_cnt; + u8 bt_kill_cnt; + __le16 reserved; +} __attribute__ ((packed)); + +/* + * REPLY_TX = 0x1c (command) + */ +struct iwl_tx_cmd { + __le16 len; + __le16 next_frame_len; + __le32 tx_flags; +#if IWL == 3945 + u8 rate; + u8 sta_id; + u8 tid_tspec; +#elif IWL == 4965 + struct iwl_dram_scratch scratch; + __le32 rate_n_flags; + u8 sta_id; +#endif + u8 sec_ctl; +#if IWL == 4965 + u8 initial_rate_index; + u8 reserved; +#endif + u8 key[16]; +#if IWL == 3945 + union { + u8 byte[8]; + __le16 word[4]; + __le32 dw[2]; + } tkip_mic; + __le32 next_frame_info; +#elif IWL == 4965 + __le16 next_frame_flags; + __le16 reserved2; +#endif + union { + __le32 life_time; + __le32 attempt; + } stop_time; +#if IWL == 3945 + u8 supp_rates[2]; +#elif IWL == 4965 + __le32 dram_lsb_ptr; + u8 dram_msb_ptr; +#endif + u8 rts_retry_limit; /*byte 50 */ + u8 data_retry_limit; /*byte 51 */ +#if IWL == 4965 + u8 tid_tspec; +#endif + union { + __le16 pm_frame_timeout; + __le16 attempt_duration; + } timeout; + __le16 driver_txop; + u8 payload[0]; + struct ieee80211_hdr hdr[0]; +} __attribute__ ((packed)); + +/* TX command response is sent after *all* transmission attempts. + * + * NOTES: + * + * TX_STATUS_FAIL_NEXT_FRAG + * + * If the fragment flag in the MAC header for the frame being transmitted + * is set and there is insufficient time to transmit the next frame, the + * TX status will be returned with 'TX_STATUS_FAIL_NEXT_FRAG'. + * + * TX_STATUS_FIFO_UNDERRUN + * + * Indicates the host did not provide bytes to the FIFO fast enough while + * a TX was in progress. + * + * TX_STATUS_FAIL_MGMNT_ABORT + * + * This status is only possible if the ABORT ON MGMT RX parameter was + * set to true with the TX command. + * + * If the MSB of the status parameter is set then an abort sequence is + * required. This sequence consists of the host activating the TX Abort + * control line, and then waiting for the TX Abort command response. This + * indicates that a the device is no longer in a transmit state, and that the + * command FIFO has been cleared. The host must then deactivate the TX Abort + * control line. Receiving is still allowed in this case. + */ +enum { + TX_STATUS_SUCCESS = 0x01, + TX_STATUS_DIRECT_DONE = 0x02, + TX_STATUS_FAIL_SHORT_LIMIT = 0x82, + TX_STATUS_FAIL_LONG_LIMIT = 0x83, + TX_STATUS_FAIL_FIFO_UNDERRUN = 0x84, + TX_STATUS_FAIL_MGMNT_ABORT = 0x85, + TX_STATUS_FAIL_NEXT_FRAG = 0x86, + TX_STATUS_FAIL_LIFE_EXPIRE = 0x87, + TX_STATUS_FAIL_DEST_PS = 0x88, + TX_STATUS_FAIL_ABORTED = 0x89, + TX_STATUS_FAIL_BT_RETRY = 0x8a, + TX_STATUS_FAIL_STA_INVALID = 0x8b, + TX_STATUS_FAIL_FRAG_DROPPED = 0x8c, + TX_STATUS_FAIL_TID_DISABLE = 0x8d, + TX_STATUS_FAIL_FRAME_FLUSHED = 0x8e, + TX_STATUS_FAIL_INSUFFICIENT_CF_POLL = 0x8f, + TX_STATUS_FAIL_TX_LOCKED = 0x90, + TX_STATUS_FAIL_NO_BEACON_ON_RADAR = 0x91, +}; + +#define TX_PACKET_MODE_REGULAR 0x0000 +#define TX_PACKET_MODE_BURST_SEQ 0x0100 +#define TX_PACKET_MODE_BURST_FIRST 0x0200 + +enum { + TX_POWER_PA_NOT_ACTIVE = 0x0, +}; + +enum { + TX_STATUS_MSK = 0x000000ff, /* bits 0:7 */ + TX_STATUS_DELAY_MSK = 0x00000040, + TX_STATUS_ABORT_MSK = 0x00000080, + TX_PACKET_MODE_MSK = 0x0000ff00, /* bits 8:15 */ + TX_FIFO_NUMBER_MSK = 0x00070000, /* bits 16:18 */ + TX_RESERVED = 0x00780000, /* bits 19:22 */ + TX_POWER_PA_DETECT_MSK = 0x7f800000, /* bits 23:30 */ + TX_ABORT_REQUIRED_MSK = 0x80000000, /* bits 31:31 */ +}; + +/* ******************************* + * TX aggregation state + ******************************* */ + +enum { + AGG_TX_STATE_TRANSMITTED = 0x00, + AGG_TX_STATE_UNDERRUN_MSK = 0x01, + AGG_TX_STATE_BT_PRIO_MSK = 0x02, + AGG_TX_STATE_FEW_BYTES_MSK = 0x04, + AGG_TX_STATE_ABORT_MSK = 0x08, + AGG_TX_STATE_LAST_SENT_TTL_MSK = 0x10, + AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK = 0x20, + AGG_TX_STATE_LAST_SENT_BT_KILL_MSK = 0x40, + AGG_TX_STATE_SCD_QUERY_MSK = 0x80, + AGG_TX_STATE_TEST_BAD_CRC32_MSK = 0x100, + AGG_TX_STATE_RESPONSE_MSK = 0x1ff, + AGG_TX_STATE_DUMP_TX_MSK = 0x200, + AGG_TX_STATE_DELAY_TX_MSK = 0x400 +}; + +#define AGG_TX_STATE_LAST_SENT_MSK \ +(AGG_TX_STATE_LAST_SENT_TTL_MSK | \ + AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK | \ + AGG_TX_STATE_LAST_SENT_BT_KILL_MSK) + +#define AGG_TX_STATE_TRY_CNT_POS 12 +#define AGG_TX_STATE_TRY_CNT_MSK 0xf000 + +#define AGG_TX_STATE_SEQ_NUM_POS 16 +#define AGG_TX_STATE_SEQ_NUM_MSK 0xffff0000 + +/* + * REPLY_TX = 0x1c (response) + */ +#if IWL == 4965 +struct iwl_tx_resp { + u8 frame_count; /* 1 no aggregation, >1 aggregation */ + u8 bt_kill_count; + u8 failure_rts; + u8 failure_frame; + __le32 rate_n_flags; + __le16 wireless_media_time; + __le16 reserved; + __le32 pa_power1; + __le32 pa_power2; + __le32 status; /* TX status (for aggregation status of 1st frame) */ +} __attribute__ ((packed)); + +#elif IWL == 3945 +struct iwl_tx_resp { + u8 failure_rts; + u8 failure_frame; + u8 bt_kill_count; + u8 rate; + __le32 wireless_media_time; + __le32 status; /* TX status (for aggregation status of 1st frame) */ +} __attribute__ ((packed)); +#endif + +/* + * REPLY_COMPRESSED_BA = 0xc5 (response only, not a command) + */ +struct iwl_compressed_ba_resp { + __le32 sta_addr_lo32; + __le16 sta_addr_hi16; + __le16 reserved; + u8 sta_id; + u8 tid; + __le16 ba_seq_ctl; + __le32 ba_bitmap0; + __le32 ba_bitmap1; + __le16 scd_flow; + __le16 scd_ssn; +} __attribute__ ((packed)); + +/* + * REPLY_TX_PWR_TABLE_CMD = 0x97 (command, has simple generic response) + */ +struct iwl_txpowertable_cmd { + u8 band; /* 0: 5 GHz, 1: 2.4 GHz */ + u8 reserved; + __le16 channel; +#if IWL == 3945 + struct iwl_power_per_rate power[IWL_MAX_RATES]; +#elif IWL == 4965 + struct iwl_tx_power_db tx_power; +#endif +} __attribute__ ((packed)); + +#if IWL == 3945 +struct iwl_rate_scaling_info { + __le16 rate_n_flags; + u8 try_cnt; + u8 next_rate_index; +} __attribute__ ((packed)); + +/** + * struct iwl_rate_scaling_cmd - Rate Scaling Command & Response + * + * REPLY_RATE_SCALE = 0x47 (command, has simple generic response) + * + * NOTE: The table of rates passed to the uCode via the + * RATE_SCALE command sets up the corresponding order of + * rates used for all related commands, including rate + * masks, etc. + * + * For example, if you set 9MB (PLCP 0x0f) as the first + * rate in the rate table, the bit mask for that rate + * when passed through ofdm_basic_rates on the REPLY_RXON + * command would be bit 0 (1<<0) + */ +struct iwl_rate_scaling_cmd { + u8 table_id; + u8 reserved[3]; + struct iwl_rate_scaling_info table[IWL_MAX_RATES]; +} __attribute__ ((packed)); + +#elif IWL == 4965 + +/*RS_NEW_API: only TLC_RTS remains and moved to bit 0 */ +#define LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK (1<<0) + +#define LINK_QUAL_AC_NUM AC_NUM +#define LINK_QUAL_MAX_RETRY_NUM 16 + +#define LINK_QUAL_ANT_A_MSK (1<<0) +#define LINK_QUAL_ANT_B_MSK (1<<1) +#define LINK_QUAL_ANT_MSK (LINK_QUAL_ANT_A_MSK|LINK_QUAL_ANT_B_MSK) + +struct iwl_link_qual_general_params { + u8 flags; + u8 mimo_delimiter; + u8 single_stream_ant_msk; + u8 dual_stream_ant_msk; + u8 start_rate_index[LINK_QUAL_AC_NUM]; +} __attribute__ ((packed)); + +struct iwl_link_qual_agg_params { + __le16 agg_time_limit; + u8 agg_dis_start_th; + u8 agg_frame_cnt_limit; + __le32 reserved; +} __attribute__ ((packed)); + +/* + * REPLY_TX_LINK_QUALITY_CMD = 0x4e (command, has simple generic response) + */ +struct iwl_link_quality_cmd { + u8 sta_id; + u8 reserved1; + __le16 control; + struct iwl_link_qual_general_params general_params; + struct iwl_link_qual_agg_params agg_params; + struct { + __le32 rate_n_flags; + } rs_table[LINK_QUAL_MAX_RETRY_NUM]; + __le32 reserved2; +} __attribute__ ((packed)); +#endif + +/* + * REPLY_BT_CONFIG = 0x9b (command, has simple generic response) + */ +struct iwl_bt_cmd { + u8 flags; + u8 lead_time; + u8 max_kill; + u8 reserved; + __le32 kill_ack_mask; + __le32 kill_cts_mask; +} __attribute__ ((packed)); + +/****************************************************************************** + * (6) + * Spectrum Management (802.11h) Commands, Responses, Notifications: + * + *****************************************************************************/ + +/* + * Spectrum Management + */ +#define MEASUREMENT_FILTER_FLAG (RXON_FILTER_PROMISC_MSK | \ + RXON_FILTER_CTL2HOST_MSK | \ + RXON_FILTER_ACCEPT_GRP_MSK | \ + RXON_FILTER_DIS_DECRYPT_MSK | \ + RXON_FILTER_DIS_GRP_DECRYPT_MSK | \ + RXON_FILTER_ASSOC_MSK | \ + RXON_FILTER_BCON_AWARE_MSK) + +struct iwl_measure_channel { + __le32 duration; /* measurement duration in extended beacon + * format */ + u8 channel; /* channel to measure */ + u8 type; /* see enum iwl_measure_type */ + __le16 reserved; +} __attribute__ ((packed)); + +/* + * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (command) + */ +struct iwl_spectrum_cmd { + __le16 len; /* number of bytes starting from token */ + u8 token; /* token id */ + u8 id; /* measurement id -- 0 or 1 */ + u8 origin; /* 0 = TGh, 1 = other, 2 = TGk */ + u8 periodic; /* 1 = periodic */ + __le16 path_loss_timeout; + __le32 start_time; /* start time in extended beacon format */ + __le32 reserved2; + __le32 flags; /* rxon flags */ + __le32 filter_flags; /* rxon filter flags */ + __le16 channel_count; /* minimum 1, maximum 10 */ + __le16 reserved3; + struct iwl_measure_channel channels[10]; +} __attribute__ ((packed)); + +/* + * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (response) + */ +struct iwl_spectrum_resp { + u8 token; + u8 id; /* id of the prior command replaced, or 0xff */ + __le16 status; /* 0 - command will be handled + * 1 - cannot handle (conflicts with another + * measurement) */ +} __attribute__ ((packed)); + +enum iwl_measurement_state { + IWL_MEASUREMENT_START = 0, + IWL_MEASUREMENT_STOP = 1, +}; + +enum iwl_measurement_status { + IWL_MEASUREMENT_OK = 0, + IWL_MEASUREMENT_CONCURRENT = 1, + IWL_MEASUREMENT_CSA_CONFLICT = 2, + IWL_MEASUREMENT_TGH_CONFLICT = 3, + /* 4-5 reserved */ + IWL_MEASUREMENT_STOPPED = 6, + IWL_MEASUREMENT_TIMEOUT = 7, + IWL_MEASUREMENT_PERIODIC_FAILED = 8, +}; + +#define NUM_ELEMENTS_IN_HISTOGRAM 8 + +struct iwl_measurement_histogram { + __le32 ofdm[NUM_ELEMENTS_IN_HISTOGRAM]; /* in 0.8usec counts */ + __le32 cck[NUM_ELEMENTS_IN_HISTOGRAM]; /* in 1usec counts */ +} __attribute__ ((packed)); + +/* clear channel availability counters */ +struct iwl_measurement_cca_counters { + __le32 ofdm; + __le32 cck; +} __attribute__ ((packed)); + +enum iwl_measure_type { + IWL_MEASURE_BASIC = (1 << 0), + IWL_MEASURE_CHANNEL_LOAD = (1 << 1), + IWL_MEASURE_HISTOGRAM_RPI = (1 << 2), + IWL_MEASURE_HISTOGRAM_NOISE = (1 << 3), + IWL_MEASURE_FRAME = (1 << 4), + /* bits 5:6 are reserved */ + IWL_MEASURE_IDLE = (1 << 7), +}; + +/* + * SPECTRUM_MEASURE_NOTIFICATION = 0x75 (notification only, not a command) + */ +struct iwl_spectrum_notification { + u8 id; /* measurement id -- 0 or 1 */ + u8 token; + u8 channel_index; /* index in measurement channel list */ + u8 state; /* 0 - start, 1 - stop */ + __le32 start_time; /* lower 32-bits of TSF */ + u8 band; /* 0 - 5.2GHz, 1 - 2.4GHz */ + u8 channel; + u8 type; /* see enum iwl_measurement_type */ + u8 reserved1; + /* NOTE: cca_ofdm, cca_cck, basic_type, and histogram are only only + * valid if applicable for measurement type requested. */ + __le32 cca_ofdm; /* cca fraction time in 40Mhz clock periods */ + __le32 cca_cck; /* cca fraction time in 44Mhz clock periods */ + __le32 cca_time; /* channel load time in usecs */ + u8 basic_type; /* 0 - bss, 1 - ofdm preamble, 2 - + * unidentified */ + u8 reserved2[3]; + struct iwl_measurement_histogram histogram; + __le32 stop_time; /* lower 32-bits of TSF */ + __le32 status; /* see iwl_measurement_status */ +} __attribute__ ((packed)); + +/****************************************************************************** + * (7) + * Power Management Commands, Responses, Notifications: + * + *****************************************************************************/ + +/** + * struct iwl_powertable_cmd - Power Table Command + * @flags: See below: + * + * POWER_TABLE_CMD = 0x77 (command, has simple generic response) + * + * PM allow: + * bit 0 - '0' Driver not allow power management + * '1' Driver allow PM (use rest of parameters) + * uCode send sleep notifications: + * bit 1 - '0' Don't send sleep notification + * '1' send sleep notification (SEND_PM_NOTIFICATION) + * Sleep over DTIM + * bit 2 - '0' PM have to walk up every DTIM + * '1' PM could sleep over DTIM till listen Interval. + * PCI power managed + * bit 3 - '0' (PCI_LINK_CTRL & 0x1) + * '1' !(PCI_LINK_CTRL & 0x1) + * Force sleep Modes + * bit 31/30- '00' use both mac/xtal sleeps + * '01' force Mac sleep + * '10' force xtal sleep + * '11' Illegal set + * + * NOTE: if sleep_interval[SLEEP_INTRVL_TABLE_SIZE-1] > DTIM period then + * ucode assume sleep over DTIM is allowed and we don't need to wakeup + * for every DTIM. + */ +#define IWL_POWER_VEC_SIZE 5 + + +#if IWL == 3945 + +#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK __constant_cpu_to_le32(1<<0) +#define IWL_POWER_SLEEP_OVER_DTIM_MSK __constant_cpu_to_le32(1<<2) +#define IWL_POWER_PCI_PM_MSK __constant_cpu_to_le32(1<<3) +struct iwl_powertable_cmd { + __le32 flags; + __le32 rx_data_timeout; + __le32 tx_data_timeout; + __le32 sleep_interval[IWL_POWER_VEC_SIZE]; +} __attribute__((packed)); + +#elif IWL == 4965 + +#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK __constant_cpu_to_le16(1<<0) +#define IWL_POWER_SLEEP_OVER_DTIM_MSK __constant_cpu_to_le16(1<<2) +#define IWL_POWER_PCI_PM_MSK __constant_cpu_to_le16(1<<3) + +struct iwl_powertable_cmd { + __le16 flags; + u8 keep_alive_seconds; + u8 debug_flags; + __le32 rx_data_timeout; + __le32 tx_data_timeout; + __le32 sleep_interval[IWL_POWER_VEC_SIZE]; + __le32 keep_alive_beacons; +} __attribute__ ((packed)); +#endif + +/* + * PM_SLEEP_NOTIFICATION = 0x7A (notification only, not a command) + * 3945 and 4965 identical. + */ +struct iwl_sleep_notification { + u8 pm_sleep_mode; + u8 pm_wakeup_src; + __le16 reserved; + __le32 sleep_time; + __le32 tsf_low; + __le32 bcon_timer; +} __attribute__ ((packed)); + +/* Sleep states. 3945 and 4965 identical. */ +enum { + IWL_PM_NO_SLEEP = 0, + IWL_PM_SLP_MAC = 1, + IWL_PM_SLP_FULL_MAC_UNASSOCIATE = 2, + IWL_PM_SLP_FULL_MAC_CARD_STATE = 3, + IWL_PM_SLP_PHY = 4, + IWL_PM_SLP_REPENT = 5, + IWL_PM_WAKEUP_BY_TIMER = 6, + IWL_PM_WAKEUP_BY_DRIVER = 7, + IWL_PM_WAKEUP_BY_RFKILL = 8, + /* 3 reserved */ + IWL_PM_NUM_OF_MODES = 12, +}; + +/* + * REPLY_CARD_STATE_CMD = 0xa0 (command, has simple generic response) + */ +#define CARD_STATE_CMD_DISABLE 0x00 /* Put card to sleep */ +#define CARD_STATE_CMD_ENABLE 0x01 /* Wake up card */ +#define CARD_STATE_CMD_HALT 0x02 /* Power down permanently */ +struct iwl_card_state_cmd { + __le32 status; /* CARD_STATE_CMD_* request new power state */ +} __attribute__ ((packed)); + +/* + * CARD_STATE_NOTIFICATION = 0xa1 (notification only, not a command) + */ +struct iwl_card_state_notif { + __le32 flags; +} __attribute__ ((packed)); + +#define HW_CARD_DISABLED 0x01 +#define SW_CARD_DISABLED 0x02 +#define RF_CARD_DISABLED 0x04 +#define RXON_CARD_DISABLED 0x10 + +struct iwl_ct_kill_config { + __le32 reserved; + __le32 critical_temperature_M; + __le32 critical_temperature_R; +} __attribute__ ((packed)); + +/****************************************************************************** + * (8) + * Scan Commands, Responses, Notifications: + * + *****************************************************************************/ + +struct iwl_scan_channel { + /* type is defined as: + * 0:0 active (0 - passive) + * 1:4 SSID direct + * If 1 is set then corresponding SSID IE is transmitted in probe + * 5:7 reserved + */ + u8 type; + u8 channel; + struct iwl_tx_power tpc; + __le16 active_dwell; + __le16 passive_dwell; +} __attribute__ ((packed)); + +struct iwl_ssid_ie { + u8 id; + u8 len; + u8 ssid[32]; +} __attribute__ ((packed)); + +#define PROBE_OPTION_MAX 0x4 +#define TX_CMD_LIFE_TIME_INFINITE __constant_cpu_to_le32(0xFFFFFFFF) +#define IWL_GOOD_CRC_TH __constant_cpu_to_le16(1) +#define IWL_MAX_SCAN_SIZE 1024 + +/* + * REPLY_SCAN_CMD = 0x80 (command) + */ +struct iwl_scan_cmd { + __le16 len; + u8 reserved0; + u8 channel_count; + __le16 quiet_time; /* dwell only this long on quiet chnl + * (active scan) */ + __le16 quiet_plcp_th; /* quiet chnl is < this # pkts (typ. 1) */ + __le16 good_CRC_th; /* passive -> active promotion threshold */ +#if IWL == 3945 + __le16 reserved1; +#elif IWL == 4965 + __le16 rx_chain; +#endif + __le32 max_out_time; /* max usec to be out of associated (service) + * chnl */ + __le32 suspend_time; /* pause scan this long when returning to svc + * chnl. + * 3945 -- 31:24 # beacons, 19:0 additional usec, + * 4965 -- 31:22 # beacons, 21:0 additional usec. + */ + __le32 flags; + __le32 filter_flags; + + struct iwl_tx_cmd tx_cmd; + struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX]; + + u8 data[0]; + /* + * The channels start after the probe request payload and are of type: + * + * struct iwl_scan_channel channels[0]; + * + * NOTE: Only one band of channels can be scanned per pass. You + * can not mix 2.4GHz channels and 5.2GHz channels and must + * request a scan multiple times (not concurrently) + * + */ +} __attribute__ ((packed)); + +/* Can abort will notify by complete notification with abort status. */ +#define CAN_ABORT_STATUS __constant_cpu_to_le32(0x1) +/* complete notification statuses */ +#define ABORT_STATUS 0x2 + +/* + * REPLY_SCAN_CMD = 0x80 (response) + */ +struct iwl_scanreq_notification { + __le32 status; /* 1: okay, 2: cannot fulfill request */ +} __attribute__ ((packed)); + +/* + * SCAN_START_NOTIFICATION = 0x82 (notification only, not a command) + */ +struct iwl_scanstart_notification { + __le32 tsf_low; + __le32 tsf_high; + __le32 beacon_timer; + u8 channel; + u8 band; + u8 reserved[2]; + __le32 status; +} __attribute__ ((packed)); + +#define SCAN_OWNER_STATUS 0x1; +#define MEASURE_OWNER_STATUS 0x2; + +#define NUMBER_OF_STATISTICS 1 /* first __le32 is good CRC */ +/* + * SCAN_RESULTS_NOTIFICATION = 0x83 (notification only, not a command) + */ +struct iwl_scanresults_notification { + u8 channel; + u8 band; + u8 reserved[2]; + __le32 tsf_low; + __le32 tsf_high; + __le32 statistics[NUMBER_OF_STATISTICS]; +} __attribute__ ((packed)); + +/* + * SCAN_COMPLETE_NOTIFICATION = 0x84 (notification only, not a command) + */ +struct iwl_scancomplete_notification { + u8 scanned_channels; + u8 status; + u8 reserved; + u8 last_channel; + __le32 tsf_low; + __le32 tsf_high; +} __attribute__ ((packed)); + + +/****************************************************************************** + * (9) + * IBSS/AP Commands and Notifications: + * + *****************************************************************************/ + +/* + * BEACON_NOTIFICATION = 0x90 (notification only, not a command) + */ +struct iwl_beacon_notif { + struct iwl_tx_resp beacon_notify_hdr; + __le32 low_tsf; + __le32 high_tsf; + __le32 ibss_mgr_status; +} __attribute__ ((packed)); + +/* + * REPLY_TX_BEACON = 0x91 (command, has simple generic response) + */ +struct iwl_tx_beacon_cmd { + struct iwl_tx_cmd tx; + __le16 tim_idx; + u8 tim_size; + u8 reserved1; + struct ieee80211_hdr frame[0]; /* beacon frame */ +} __attribute__ ((packed)); + +/****************************************************************************** + * (10) + * Statistics Commands and Notifications: + * + *****************************************************************************/ + +#define IWL_TEMP_CONVERT 260 + +#define SUP_RATE_11A_MAX_NUM_CHANNELS 8 +#define SUP_RATE_11B_MAX_NUM_CHANNELS 4 +#define SUP_RATE_11G_MAX_NUM_CHANNELS 12 + +/* Used for passing to driver number of successes and failures per rate */ +struct rate_histogram { + union { + __le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS]; + __le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS]; + __le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS]; + } success; + union { + __le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS]; + __le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS]; + __le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS]; + } failed; +} __attribute__ ((packed)); + +/* statistics command response */ + +struct statistics_rx_phy { + __le32 ina_cnt; + __le32 fina_cnt; + __le32 plcp_err; + __le32 crc32_err; + __le32 overrun_err; + __le32 early_overrun_err; + __le32 crc32_good; + __le32 false_alarm_cnt; + __le32 fina_sync_err_cnt; + __le32 sfd_timeout; + __le32 fina_timeout; + __le32 unresponded_rts; + __le32 rxe_frame_limit_overrun; + __le32 sent_ack_cnt; + __le32 sent_cts_cnt; +#if IWL == 4965 + __le32 sent_ba_rsp_cnt; + __le32 dsp_self_kill; + __le32 mh_format_err; + __le32 re_acq_main_rssi_sum; + __le32 reserved3; +#endif +} __attribute__ ((packed)); + +#if IWL == 4965 +struct statistics_rx_ht_phy { + __le32 plcp_err; + __le32 overrun_err; + __le32 early_overrun_err; + __le32 crc32_good; + __le32 crc32_err; + __le32 mh_format_err; + __le32 agg_crc32_good; + __le32 agg_mpdu_cnt; + __le32 agg_cnt; + __le32 reserved2; +} __attribute__ ((packed)); +#endif + +struct statistics_rx_non_phy { + __le32 bogus_cts; /* CTS received when not expecting CTS */ + __le32 bogus_ack; /* ACK received when not expecting ACK */ + __le32 non_bssid_frames; /* number of frames with BSSID that + * doesn't belong to the STA BSSID */ + __le32 filtered_frames; /* count frames that were dumped in the + * filtering process */ + __le32 non_channel_beacons; /* beacons with our bss id but not on + * our serving channel */ +#if IWL == 4965 + __le32 channel_beacons; /* beacons with our bss id and in our + * serving channel */ + __le32 num_missed_bcon; /* number of missed beacons */ + __le32 adc_rx_saturation_time; /* count in 0.8us units the time the + * ADC was in saturation */ + __le32 ina_detection_search_time;/* total time (in 0.8us) searched + * for INA */ + __le32 beacon_silence_rssi_a; /* RSSI silence after beacon frame */ + __le32 beacon_silence_rssi_b; /* RSSI silence after beacon frame */ + __le32 beacon_silence_rssi_c; /* RSSI silence after beacon frame */ + __le32 interference_data_flag; /* flag for interference data + * availability. 1 when data is + * available. */ + __le32 channel_load; /* counts RX Enable time */ + __le32 dsp_false_alarms; /* DSP false alarm (both OFDM + * and CCK) counter */ + __le32 beacon_rssi_a; + __le32 beacon_rssi_b; + __le32 beacon_rssi_c; + __le32 beacon_energy_a; + __le32 beacon_energy_b; + __le32 beacon_energy_c; +#endif +} __attribute__ ((packed)); + +struct statistics_rx { + struct statistics_rx_phy ofdm; + struct statistics_rx_phy cck; + struct statistics_rx_non_phy general; +#if IWL == 4965 + struct statistics_rx_ht_phy ofdm_ht; +#endif +} __attribute__ ((packed)); + +#if IWL == 4965 +struct statistics_tx_non_phy_agg { + __le32 ba_timeout; + __le32 ba_reschedule_frames; + __le32 scd_query_agg_frame_cnt; + __le32 scd_query_no_agg; + __le32 scd_query_agg; + __le32 scd_query_mismatch; + __le32 frame_not_ready; + __le32 underrun; + __le32 bt_prio_kill; + __le32 rx_ba_rsp_cnt; + __le32 reserved2; + __le32 reserved3; +} __attribute__ ((packed)); +#endif + +struct statistics_tx { + __le32 preamble_cnt; + __le32 rx_detected_cnt; + __le32 bt_prio_defer_cnt; + __le32 bt_prio_kill_cnt; + __le32 few_bytes_cnt; + __le32 cts_timeout; + __le32 ack_timeout; + __le32 expected_ack_cnt; + __le32 actual_ack_cnt; +#if IWL == 4965 + __le32 dump_msdu_cnt; + __le32 burst_abort_next_frame_mismatch_cnt; + __le32 burst_abort_missing_next_frame_cnt; + __le32 cts_timeout_collision; + __le32 ack_or_ba_timeout_collision; + struct statistics_tx_non_phy_agg agg; +#endif +} __attribute__ ((packed)); + +struct statistics_dbg { + __le32 burst_check; + __le32 burst_count; + __le32 reserved[4]; +} __attribute__ ((packed)); + +struct statistics_div { + __le32 tx_on_a; + __le32 tx_on_b; + __le32 exec_time; + __le32 probe_time; +#if IWL == 4965 + __le32 reserved1; + __le32 reserved2; +#endif +} __attribute__ ((packed)); + +struct statistics_general { + __le32 temperature; +#if IWL == 4965 + __le32 temperature_m; +#endif + struct statistics_dbg dbg; + __le32 sleep_time; + __le32 slots_out; + __le32 slots_idle; + __le32 ttl_timestamp; + struct statistics_div div; +#if IWL == 4965 + __le32 rx_enable_counter; + __le32 reserved1; + __le32 reserved2; + __le32 reserved3; +#endif +} __attribute__ ((packed)); + +/* + * REPLY_STATISTICS_CMD = 0x9c, + * 3945 and 4965 identical. + * + * This command triggers an immediate response containing uCode statistics. + * The response is in the same format as STATISTICS_NOTIFICATION 0x9d, below. + * + * If the CLEAR_STATS configuration flag is set, uCode will clear its + * internal copy of the statistics (counters) after issuing the response. + * This flag does not affect STATISTICS_NOTIFICATIONs after beacons (see below). + * + * If the DISABLE_NOTIF configuration flag is set, uCode will not issue + * STATISTICS_NOTIFICATIONs after received beacons (see below). This flag + * does not affect the response to the REPLY_STATISTICS_CMD 0x9c itself. + */ +#define IWL_STATS_CONF_CLEAR_STATS __constant_cpu_to_le32(0x1) /* see above */ +#define IWL_STATS_CONF_DISABLE_NOTIF __constant_cpu_to_le32(0x2)/* see above */ +struct iwl_statistics_cmd { + __le32 configuration_flags; /* IWL_STATS_CONF_* */ +} __attribute__ ((packed)); + +/* + * STATISTICS_NOTIFICATION = 0x9d (notification only, not a command) + * + * By default, uCode issues this notification after receiving a beacon + * while associated. To disable this behavior, set DISABLE_NOTIF flag in the + * REPLY_STATISTICS_CMD 0x9c, above. + * + * Statistics counters continue to increment beacon after beacon, but are + * cleared when changing channels or when driver issues REPLY_STATISTICS_CMD + * 0x9c with CLEAR_STATS bit set (see above). + * + * uCode also issues this notification during scans. uCode clears statistics + * appropriately so that each notification contains statistics for only the + * one channel that has just been scanned. + */ +#define STATISTICS_REPLY_FLG_BAND_24G_MSK __constant_cpu_to_le32(0x2) +#define STATISTICS_REPLY_FLG_FAT_MODE_MSK __constant_cpu_to_le32(0x8) +struct iwl_notif_statistics { + __le32 flag; + struct statistics_rx rx; + struct statistics_tx tx; + struct statistics_general general; +} __attribute__ ((packed)); + + +/* + * MISSED_BEACONS_NOTIFICATION = 0xa2 (notification only, not a command) + */ +/* if ucode missed CONSECUTIVE_MISSED_BCONS_TH beacons in a row, + * then this notification will be sent. */ +#define CONSECUTIVE_MISSED_BCONS_TH 20 + +struct iwl_missed_beacon_notif { + __le32 consequtive_missed_beacons; + __le32 total_missed_becons; + __le32 num_expected_beacons; + __le32 num_recvd_beacons; +} __attribute__ ((packed)); + +/****************************************************************************** + * (11) + * Rx Calibration Commands: + * + *****************************************************************************/ + +#define PHY_CALIBRATE_DIFF_GAIN_CMD (7) +#define HD_TABLE_SIZE (11) + +struct iwl_sensitivity_cmd { + __le16 control; + __le16 table[HD_TABLE_SIZE]; +} __attribute__ ((packed)); + +struct iwl_calibration_cmd { + u8 opCode; + u8 flags; + __le16 reserved; + s8 diff_gain_a; + s8 diff_gain_b; + s8 diff_gain_c; + u8 reserved1; +} __attribute__ ((packed)); + +/****************************************************************************** + * (12) + * Miscellaneous Commands: + * + *****************************************************************************/ + +/* + * LEDs Command & Response + * REPLY_LEDS_CMD = 0x48 (command, has simple generic response) + * + * For each of 3 possible LEDs (Activity/Link/Tech, selected by "id" field), + * this command turns it on or off, or sets up a periodic blinking cycle. + */ +struct iwl_led_cmd { + __le32 interval; /* "interval" in uSec */ + u8 id; /* 1: Activity, 2: Link, 3: Tech */ + u8 off; /* # intervals off while blinking; + * "0", with >0 "on" value, turns LED on */ + u8 on; /* # intervals on while blinking; + * "0", regardless of "off", turns LED off */ + u8 reserved; +} __attribute__ ((packed)); + +/****************************************************************************** + * (13) + * Union of all expected notifications/responses: + * + *****************************************************************************/ + +struct iwl_rx_packet { + __le32 len; + struct iwl_cmd_header hdr; + union { + struct iwl_alive_resp alive_frame; + struct iwl_rx_frame rx_frame; + struct iwl_tx_resp tx_resp; + struct iwl_spectrum_notification spectrum_notif; + struct iwl_csa_notification csa_notif; + struct iwl_error_resp err_resp; + struct iwl_card_state_notif card_state_notif; + struct iwl_beacon_notif beacon_status; + struct iwl_add_sta_resp add_sta; + struct iwl_sleep_notification sleep_notif; + struct iwl_spectrum_resp spectrum; + struct iwl_notif_statistics stats; +#if IWL == 4965 + struct iwl_compressed_ba_resp compressed_ba; + struct iwl_missed_beacon_notif missed_beacon; +#endif + __le32 status; + u8 raw[0]; + } u; +} __attribute__ ((packed)); + +#define IWL_RX_FRAME_SIZE (4 + sizeof(struct iwl_rx_frame)) + +#endif /* __iwl_commands_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h new file mode 100644 index 00000000000..abd344c549a --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -0,0 +1,149 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#ifndef __iwl_debug_h__ +#define __iwl_debug_h__ + +#ifdef CONFIG_IWLWIFI_DEBUG +extern u32 iwl_debug_level; +#define IWL_DEBUG(level, fmt, args...) \ +do { if (iwl_debug_level & (level)) \ + printk(KERN_ERR DRV_NAME": %c %s " fmt, \ + in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0) + +#define IWL_DEBUG_LIMIT(level, fmt, args...) \ +do { if ((iwl_debug_level & (level)) && net_ratelimit()) \ + printk(KERN_ERR DRV_NAME": %c %s " fmt, \ + in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0) +#else +static inline void IWL_DEBUG(int level, const char *fmt, ...) +{ +} +static inline void IWL_DEBUG_LIMIT(int level, const char *fmt, ...) +{ +} +#endif /* CONFIG_IWLWIFI_DEBUG */ + +/* + * To use the debug system; + * + * If you are defining a new debug classification, simply add it to the #define + * list here in the form of: + * + * #define IWL_DL_xxxx VALUE + * + * shifting value to the left one bit from the previous entry. xxxx should be + * the name of the classification (for example, WEP) + * + * You then need to either add a IWL_xxxx_DEBUG() macro definition for your + * classification, or use IWL_DEBUG(IWL_DL_xxxx, ...) whenever you want + * to send output to that classification. + * + * To add your debug level to the list of levels seen when you perform + * + * % cat /proc/net/iwl/debug_level + * + * you simply need to add your entry to the iwl_debug_levels array. + * + * If you do not see debug_level in /proc/net/iwl then you do not have + * CONFIG_IWLWIFI_DEBUG defined in your kernel configuration + * + */ + +#define IWL_DL_INFO (1<<0) +#define IWL_DL_MAC80211 (1<<1) +#define IWL_DL_HOST_COMMAND (1<<2) +#define IWL_DL_STATE (1<<3) + +#define IWL_DL_RADIO (1<<7) +#define IWL_DL_POWER (1<<8) +#define IWL_DL_TEMP (1<<9) + +#define IWL_DL_NOTIF (1<<10) +#define IWL_DL_SCAN (1<<11) +#define IWL_DL_ASSOC (1<<12) +#define IWL_DL_DROP (1<<13) + +#define IWL_DL_TXPOWER (1<<14) + +#define IWL_DL_AP (1<<15) + +#define IWL_DL_FW (1<<16) +#define IWL_DL_RF_KILL (1<<17) +#define IWL_DL_FW_ERRORS (1<<18) + +#define IWL_DL_LED (1<<19) + +#define IWL_DL_RATE (1<<20) + +#define IWL_DL_CALIB (1<<21) +#define IWL_DL_WEP (1<<22) +#define IWL_DL_TX (1<<23) +#define IWL_DL_RX (1<<24) +#define IWL_DL_ISR (1<<25) +#define IWL_DL_HT (1<<26) +#define IWL_DL_IO (1<<27) +#define IWL_DL_11H (1<<28) + +#define IWL_DL_STATS (1<<29) +#define IWL_DL_TX_REPLY (1<<30) +#define IWL_DL_QOS (1<<31) + +#define IWL_ERROR(f, a...) printk(KERN_ERR DRV_NAME ": " f, ## a) +#define IWL_WARNING(f, a...) printk(KERN_WARNING DRV_NAME ": " f, ## a) +#define IWL_DEBUG_INFO(f, a...) IWL_DEBUG(IWL_DL_INFO, f, ## a) + +#define IWL_DEBUG_MAC80211(f, a...) IWL_DEBUG(IWL_DL_MAC80211, f, ## a) +#define IWL_DEBUG_TEMP(f, a...) IWL_DEBUG(IWL_DL_TEMP, f, ## a) +#define IWL_DEBUG_SCAN(f, a...) IWL_DEBUG(IWL_DL_SCAN, f, ## a) +#define IWL_DEBUG_RX(f, a...) IWL_DEBUG(IWL_DL_RX, f, ## a) +#define IWL_DEBUG_TX(f, a...) IWL_DEBUG(IWL_DL_TX, f, ## a) +#define IWL_DEBUG_ISR(f, a...) IWL_DEBUG(IWL_DL_ISR, f, ## a) +#define IWL_DEBUG_LED(f, a...) IWL_DEBUG(IWL_DL_LED, f, ## a) +#define IWL_DEBUG_WEP(f, a...) IWL_DEBUG(IWL_DL_WEP, f, ## a) +#define IWL_DEBUG_HC(f, a...) IWL_DEBUG(IWL_DL_HOST_COMMAND, f, ## a) +#define IWL_DEBUG_CALIB(f, a...) IWL_DEBUG(IWL_DL_CALIB, f, ## a) +#define IWL_DEBUG_FW(f, a...) IWL_DEBUG(IWL_DL_FW, f, ## a) +#define IWL_DEBUG_RF_KILL(f, a...) IWL_DEBUG(IWL_DL_RF_KILL, f, ## a) +#define IWL_DEBUG_DROP(f, a...) IWL_DEBUG(IWL_DL_DROP, f, ## a) +#define IWL_DEBUG_DROP_LIMIT(f, a...) IWL_DEBUG_LIMIT(IWL_DL_DROP, f, ## a) +#define IWL_DEBUG_AP(f, a...) IWL_DEBUG(IWL_DL_AP, f, ## a) +#define IWL_DEBUG_TXPOWER(f, a...) IWL_DEBUG(IWL_DL_TXPOWER, f, ## a) +#define IWL_DEBUG_IO(f, a...) IWL_DEBUG(IWL_DL_IO, f, ## a) +#define IWL_DEBUG_RATE(f, a...) IWL_DEBUG(IWL_DL_RATE, f, ## a) +#define IWL_DEBUG_NOTIF(f, a...) IWL_DEBUG(IWL_DL_NOTIF, f, ## a) +#define IWL_DEBUG_ASSOC(f, a...) IWL_DEBUG(IWL_DL_ASSOC | IWL_DL_INFO, f, ## a) +#define IWL_DEBUG_HT(f, a...) IWL_DEBUG(IWL_DL_HT, f, ## a) +#define IWL_DEBUG_STATS(f, a...) IWL_DEBUG(IWL_DL_STATS, f, ## a) +#define IWL_DEBUG_TX_REPLY(f, a...) IWL_DEBUG(IWL_DL_TX_REPLY, f, ## a) +#define IWL_DEBUG_QOS(f, a...) IWL_DEBUG(IWL_DL_QOS, f, ## a) +#define IWL_DEBUG_RADIO(f, a...) IWL_DEBUG(IWL_DL_RADIO, f, ## a) +#define IWL_DEBUG_POWER(f, a...) IWL_DEBUG(IWL_DL_POWER, f, ## a) +#define IWL_DEBUG_11H(f, a...) IWL_DEBUG(IWL_DL_11H, f, ## a) + +#endif diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h new file mode 100644 index 00000000000..e473c97e3f4 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -0,0 +1,336 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU Geeral Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +#ifndef __iwl_eeprom_h__ +#define __iwl_eeprom_h__ + +/* + * This file defines EEPROM related constants, enums, and inline functions. + * + */ + +#define IWL_EEPROM_ACCESS_TIMEOUT 5000 /* uSec */ +#define IWL_EEPROM_ACCESS_DELAY 10 /* uSec */ +/* EEPROM field values */ +#define ANTENNA_SWITCH_NORMAL 0 +#define ANTENNA_SWITCH_INVERSE 1 + +enum { + EEPROM_CHANNEL_VALID = (1 << 0), /* usable for this SKU/geo */ + EEPROM_CHANNEL_IBSS = (1 << 1), /* usable as an IBSS channel */ + /* Bit 2 Reserved */ + EEPROM_CHANNEL_ACTIVE = (1 << 3), /* active scanning allowed */ + EEPROM_CHANNEL_RADAR = (1 << 4), /* radar detection required */ + EEPROM_CHANNEL_WIDE = (1 << 5), + EEPROM_CHANNEL_NARROW = (1 << 6), + EEPROM_CHANNEL_DFS = (1 << 7), /* dynamic freq selection candidate */ +}; + +/* EEPROM field lengths */ +#define EEPROM_BOARD_PBA_NUMBER_LENGTH 11 + +/* EEPROM field lengths */ +#define EEPROM_BOARD_PBA_NUMBER_LENGTH 11 +#define EEPROM_REGULATORY_SKU_ID_LENGTH 4 +#define EEPROM_REGULATORY_BAND1_CHANNELS_LENGTH 14 +#define EEPROM_REGULATORY_BAND2_CHANNELS_LENGTH 13 +#define EEPROM_REGULATORY_BAND3_CHANNELS_LENGTH 12 +#define EEPROM_REGULATORY_BAND4_CHANNELS_LENGTH 11 +#define EEPROM_REGULATORY_BAND5_CHANNELS_LENGTH 6 + +#if IWL == 3945 +#define EEPROM_REGULATORY_CHANNELS_LENGTH ( \ + EEPROM_REGULATORY_BAND1_CHANNELS_LENGTH + \ + EEPROM_REGULATORY_BAND2_CHANNELS_LENGTH + \ + EEPROM_REGULATORY_BAND3_CHANNELS_LENGTH + \ + EEPROM_REGULATORY_BAND4_CHANNELS_LENGTH + \ + EEPROM_REGULATORY_BAND5_CHANNELS_LENGTH) +#elif IWL == 4965 +#define EEPROM_REGULATORY_BAND_24_FAT_CHANNELS_LENGTH 7 +#define EEPROM_REGULATORY_BAND_52_FAT_CHANNELS_LENGTH 11 +#define EEPROM_REGULATORY_CHANNELS_LENGTH ( \ + EEPROM_REGULATORY_BAND1_CHANNELS_LENGTH + \ + EEPROM_REGULATORY_BAND2_CHANNELS_LENGTH + \ + EEPROM_REGULATORY_BAND3_CHANNELS_LENGTH + \ + EEPROM_REGULATORY_BAND4_CHANNELS_LENGTH + \ + EEPROM_REGULATORY_BAND5_CHANNELS_LENGTH + \ + EEPROM_REGULATORY_BAND_24_FAT_CHANNELS_LENGTH + \ + EEPROM_REGULATORY_BAND_52_FAT_CHANNELS_LENGTH) +#endif + +#define EEPROM_REGULATORY_NUMBER_OF_BANDS 5 + +/* SKU Capabilities */ +#define EEPROM_SKU_CAP_SW_RF_KILL_ENABLE (1 << 0) +#define EEPROM_SKU_CAP_HW_RF_KILL_ENABLE (1 << 1) +#define EEPROM_SKU_CAP_OP_MODE_MRC (1 << 7) + +/* *regulatory* channel data from eeprom, one for each channel */ +struct iwl_eeprom_channel { + u8 flags; /* flags copied from EEPROM */ + s8 max_power_avg; /* max power (dBm) on this chnl, limit 31 */ +} __attribute__ ((packed)); + +/* + * Mapping of a Tx power level, at factory calibration temperature, + * to a radio/DSP gain table index. + * One for each of 5 "sample" power levels in each band. + * v_det is measured at the factory, using the 3945's built-in power amplifier + * (PA) output voltage detector. This same detector is used during Tx of + * long packets in normal operation to provide feedback as to proper output + * level. + * Data copied from EEPROM. + */ +struct iwl_eeprom_txpower_sample { + u8 gain_index; /* index into power (gain) setup table ... */ + s8 power; /* ... for this pwr level for this chnl group */ + u16 v_det; /* PA output voltage */ +} __attribute__ ((packed)); + +/* + * Mappings of Tx power levels -> nominal radio/DSP gain table indexes. + * One for each channel group (a.k.a. "band") (1 for BG, 4 for A). + * Tx power setup code interpolates between the 5 "sample" power levels + * to determine the nominal setup for a requested power level. + * Data copied from EEPROM. + * DO NOT ALTER THIS STRUCTURE!!! + */ +struct iwl_eeprom_txpower_group { + struct iwl_eeprom_txpower_sample samples[5]; /* 5 power levels */ + s32 a, b, c, d, e; /* coefficients for voltage->power + * formula (signed) */ + s32 Fa, Fb, Fc, Fd, Fe; /* these modify coeffs based on + * frequency (signed) */ + s8 saturation_power; /* highest power possible by h/w in this + * band */ + u8 group_channel; /* "representative" channel # in this band */ + s16 temperature; /* h/w temperature at factory calib this band + * (signed) */ +} __attribute__ ((packed)); + +/* + * Temperature-based Tx-power compensation data, not band-specific. + * These coefficients are use to modify a/b/c/d/e coeffs based on + * difference between current temperature and factory calib temperature. + * Data copied from EEPROM. + */ +struct iwl_eeprom_temperature_corr { + u32 Ta; + u32 Tb; + u32 Tc; + u32 Td; + u32 Te; +} __attribute__ ((packed)); + +#if IWL == 4965 +#define EEPROM_TX_POWER_TX_CHAINS (2) +#define EEPROM_TX_POWER_BANDS (8) +#define EEPROM_TX_POWER_MEASUREMENTS (3) +#define EEPROM_TX_POWER_VERSION (2) +#define EEPROM_TX_POWER_VERSION_NEW (5) + +struct iwl_eeprom_calib_measure { + u8 temperature; + u8 gain_idx; + u8 actual_pow; + s8 pa_det; +} __attribute__ ((packed)); + +struct iwl_eeprom_calib_ch_info { + u8 ch_num; + struct iwl_eeprom_calib_measure measurements[EEPROM_TX_POWER_TX_CHAINS] + [EEPROM_TX_POWER_MEASUREMENTS]; +} __attribute__ ((packed)); + +struct iwl_eeprom_calib_subband_info { + u8 ch_from; + u8 ch_to; + struct iwl_eeprom_calib_ch_info ch1; + struct iwl_eeprom_calib_ch_info ch2; +} __attribute__ ((packed)); + +struct iwl_eeprom_calib_info { + u8 saturation_power24; + u8 saturation_power52; + s16 voltage; /* signed */ + struct iwl_eeprom_calib_subband_info band_info[EEPROM_TX_POWER_BANDS]; +} __attribute__ ((packed)); + +#endif + +struct iwl_eeprom { + u8 reserved0[16]; +#define EEPROM_DEVICE_ID (2*0x08) /* 2 bytes */ + u16 device_id; /* abs.ofs: 16 */ + u8 reserved1[2]; +#define EEPROM_PMC (2*0x0A) /* 2 bytes */ + u16 pmc; /* abs.ofs: 20 */ + u8 reserved2[20]; +#define EEPROM_MAC_ADDRESS (2*0x15) /* 6 bytes */ + u8 mac_address[6]; /* abs.ofs: 42 */ + u8 reserved3[58]; +#define EEPROM_BOARD_REVISION (2*0x35) /* 2 bytes */ + u16 board_revision; /* abs.ofs: 106 */ + u8 reserved4[11]; +#define EEPROM_BOARD_PBA_NUMBER (2*0x3B+1) /* 9 bytes */ + u8 board_pba_number[9]; /* abs.ofs: 119 */ + u8 reserved5[8]; +#define EEPROM_VERSION (2*0x44) /* 2 bytes */ + u16 version; /* abs.ofs: 136 */ +#define EEPROM_SKU_CAP (2*0x45) /* 1 bytes */ + u8 sku_cap; /* abs.ofs: 138 */ +#define EEPROM_LEDS_MODE (2*0x45+1) /* 1 bytes */ + u8 leds_mode; /* abs.ofs: 139 */ +#define EEPROM_OEM_MODE (2*0x46) /* 2 bytes */ + u16 oem_mode; +#define EEPROM_WOWLAN_MODE (2*0x47) /* 2 bytes */ + u16 wowlan_mode; /* abs.ofs: 142 */ +#define EEPROM_LEDS_TIME_INTERVAL (2*0x48) /* 2 bytes */ + u16 leds_time_interval; /* abs.ofs: 144 */ +#define EEPROM_LEDS_OFF_TIME (2*0x49) /* 1 bytes */ + u8 leds_off_time; /* abs.ofs: 146 */ +#define EEPROM_LEDS_ON_TIME (2*0x49+1) /* 1 bytes */ + u8 leds_on_time; /* abs.ofs: 147 */ +#define EEPROM_ALMGOR_M_VERSION (2*0x4A) /* 1 bytes */ + u8 almgor_m_version; /* abs.ofs: 148 */ +#define EEPROM_ANTENNA_SWITCH_TYPE (2*0x4A+1) /* 1 bytes */ + u8 antenna_switch_type; /* abs.ofs: 149 */ +#if IWL == 3945 + u8 reserved6[42]; +#else + u8 reserved6[8]; +#define EEPROM_4965_BOARD_REVISION (2*0x4F) /* 2 bytes */ + u16 board_revision_4965; /* abs.ofs: 158 */ + u8 reserved7[13]; +#define EEPROM_4965_BOARD_PBA (2*0x56+1) /* 9 bytes */ + u8 board_pba_number_4965[9]; /* abs.ofs: 173 */ + u8 reserved8[10]; +#endif +#define EEPROM_REGULATORY_SKU_ID (2*0x60) /* 4 bytes */ + u8 sku_id[4]; /* abs.ofs: 192 */ +#define EEPROM_REGULATORY_BAND_1 (2*0x62) /* 2 bytes */ + u16 band_1_count; /* abs.ofs: 196 */ +#define EEPROM_REGULATORY_BAND_1_CHANNELS (2*0x63) /* 28 bytes */ + struct iwl_eeprom_channel band_1_channels[14]; /* abs.ofs: 196 */ +#define EEPROM_REGULATORY_BAND_2 (2*0x71) /* 2 bytes */ + u16 band_2_count; /* abs.ofs: 226 */ +#define EEPROM_REGULATORY_BAND_2_CHANNELS (2*0x72) /* 26 bytes */ + struct iwl_eeprom_channel band_2_channels[13]; /* abs.ofs: 228 */ +#define EEPROM_REGULATORY_BAND_3 (2*0x7F) /* 2 bytes */ + u16 band_3_count; /* abs.ofs: 254 */ +#define EEPROM_REGULATORY_BAND_3_CHANNELS (2*0x80) /* 24 bytes */ + struct iwl_eeprom_channel band_3_channels[12]; /* abs.ofs: 256 */ +#define EEPROM_REGULATORY_BAND_4 (2*0x8C) /* 2 bytes */ + u16 band_4_count; /* abs.ofs: 280 */ +#define EEPROM_REGULATORY_BAND_4_CHANNELS (2*0x8D) /* 22 bytes */ + struct iwl_eeprom_channel band_4_channels[11]; /* abs.ofs: 282 */ +#define EEPROM_REGULATORY_BAND_5 (2*0x98) /* 2 bytes */ + u16 band_5_count; /* abs.ofs: 304 */ +#define EEPROM_REGULATORY_BAND_5_CHANNELS (2*0x99) /* 12 bytes */ + struct iwl_eeprom_channel band_5_channels[6]; /* abs.ofs: 306 */ + +/* From here on out the EEPROM diverges between the 4965 and the 3945 */ +#if IWL == 3945 + + u8 reserved9[194]; + +#define EEPROM_TXPOWER_CALIB_GROUP0 0x200 +#define EEPROM_TXPOWER_CALIB_GROUP1 0x240 +#define EEPROM_TXPOWER_CALIB_GROUP2 0x280 +#define EEPROM_TXPOWER_CALIB_GROUP3 0x2c0 +#define EEPROM_TXPOWER_CALIB_GROUP4 0x300 +#define IWL_NUM_TX_CALIB_GROUPS 5 + struct iwl_eeprom_txpower_group groups[IWL_NUM_TX_CALIB_GROUPS]; +/* abs.ofs: 512 */ +#define EEPROM_CALIB_TEMPERATURE_CORRECT 0x340 + struct iwl_eeprom_temperature_corr corrections; /* abs.ofs: 832 */ + u8 reserved16[172]; /* fill out to full 1024 byte block */ + +/* 4965AGN adds fat channel support */ +#elif IWL == 4965 + + u8 reserved10[2]; +#define EEPROM_REGULATORY_BAND_24_FAT_CHANNELS (2*0xA0) /* 14 bytes */ + struct iwl_eeprom_channel band_24_channels[7]; /* abs.ofs: 320 */ + u8 reserved11[2]; +#define EEPROM_REGULATORY_BAND_52_FAT_CHANNELS (2*0xA8) /* 22 bytes */ + struct iwl_eeprom_channel band_52_channels[11]; /* abs.ofs: 336 */ + u8 reserved12[6]; +#define EEPROM_CALIB_VERSION_OFFSET (2*0xB6) /* 2 bytes */ + u16 calib_version; /* abs.ofs: 364 */ + u8 reserved13[2]; +#define EEPROM_SATURATION_POWER_OFFSET (2*0xB8) /* 2 bytes */ + u16 satruation_power; /* abs.ofs: 368 */ + u8 reserved14[94]; +#define EEPROM_IWL_CALIB_TXPOWER_OFFSET (2*0xE8) /* 48 bytes */ + struct iwl_eeprom_calib_info calib_info; /* abs.ofs: 464 */ + + u8 reserved16[140]; /* fill out to full 1024 byte block */ + +#endif + +} __attribute__ ((packed)); + +#define IWL_EEPROM_IMAGE_SIZE 1024 + +#endif diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h new file mode 100644 index 00000000000..e2a8d95ad9c --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h @@ -0,0 +1,255 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project, as well + * as portions of the ieee80211 subsystem header files. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#ifndef __iwl_helpers_h__ +#define __iwl_helpers_h__ + +#include + +/* + * The structures defined by the hardware/uCode interface + * have bit-wise operations. For each bit-field there is + * a data symbol in the structure, the start bit position + * and the length of the bit-field. + * + * iwl_get_bits and iwl_set_bits will return or set the + * appropriate bits on a 32-bit value. + * + * IWL_GET_BITS and IWL_SET_BITS use symbol expansion to + * expand out to the appropriate call to iwl_get_bits + * and iwl_set_bits without having to reference all of the + * numerical constants and defines provided in the hardware + * definition + */ + +/** + * iwl_get_bits - Extract a hardware bit-field value + * @src: source hardware value (__le32) + * @pos: bit-position (0-based) of first bit of value + * @len: length of bit-field + * + * iwl_get_bits will return the bit-field in cpu endian ordering. + * + * NOTE: If used from IWL_GET_BITS then pos and len are compile-constants and + * will collapse to minimal code by the compiler. + */ +static inline u32 iwl_get_bits(__le32 src, u8 pos, u8 len) +{ + u32 tmp = le32_to_cpu(src); + + tmp >>= pos; + tmp &= (1UL << len) - 1; + return tmp; +} + +/** + * iwl_set_bits - Set a hardware bit-field value + * @dst: Address of __le32 hardware value + * @pos: bit-position (0-based) of first bit of value + * @len: length of bit-field + * @val: cpu endian value to encode into the bit-field + * + * iwl_set_bits will encode val into dst, masked to be len bits long at bit + * position pos. + * + * NOTE: If used IWL_SET_BITS pos and len will be compile-constants and + * will collapse to minimal code by the compiler. + */ +static inline void iwl_set_bits(__le32 *dst, u8 pos, u8 len, int val) +{ + u32 tmp = le32_to_cpu(*dst); + + tmp &= ~(((1UL << len) - 1) << pos); + tmp |= (val & ((1UL << len) - 1)) << pos; + *dst = cpu_to_le32(tmp); +} + +static inline void iwl_set_bits16(__le16 *dst, u8 pos, u8 len, int val) +{ + u16 tmp = le16_to_cpu(*dst); + + tmp &= ~((1UL << (pos + len)) - (1UL << pos)); + tmp |= (val & ((1UL << len) - 1)) << pos; + *dst = cpu_to_le16(tmp); +} + +/* + * The bit-field definitions in iwl-xxxx-hw.h are in the form of: + * + * struct example { + * __le32 val1; + * #define IWL_name_POS 8 + * #define IWL_name_LEN 4 + * #define IWL_name_SYM val1 + * }; + * + * The IWL_SET_BITS and IWL_GET_BITS macros are provided to allow the driver + * to call: + * + * struct example bar; + * u32 val = IWL_GET_BITS(bar, name); + * val = val * 2; + * IWL_SET_BITS(bar, name, val); + * + * All cpu / host ordering, masking, and shifts are performed by the macros + * and iwl_{get,set}_bits. + * + */ +#define IWL_SET_BITS(s, sym, v) \ + iwl_set_bits(&(s).IWL_ ## sym ## _SYM, IWL_ ## sym ## _POS, \ + IWL_ ## sym ## _LEN, (v)) + +#define IWL_SET_BITS16(s, sym, v) \ + iwl_set_bits16(&(s).IWL_ ## sym ## _SYM, IWL_ ## sym ## _POS, \ + IWL_ ## sym ## _LEN, (v)) + +#define IWL_GET_BITS(s, sym) \ + iwl_get_bits((s).IWL_ ## sym ## _SYM, IWL_ ## sym ## _POS, \ + IWL_ ## sym ## _LEN) + + +#define KELVIN_TO_CELSIUS(x) ((x)-273) +#define CELSIUS_TO_KELVIN(x) ((x)+273) + +#define IEEE80211_CHAN_W_RADAR_DETECT 0x00000010 + +static inline struct ieee80211_conf *ieee80211_get_hw_conf( + struct ieee80211_hw *hw) +{ + return &hw->conf; +} + +#define QOS_CONTROL_LEN 2 + +#define IEEE80211_STYPE_BACK_REQ 0x0080 +#define IEEE80211_STYPE_BACK 0x0090 + + +static inline int ieee80211_is_management(u16 fc) +{ + return (fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT; +} + +static inline int ieee80211_is_control(u16 fc) +{ + return (fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL; +} + +static inline int ieee80211_is_data(u16 fc) +{ + return (fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA; +} + +static inline int ieee80211_is_back_request(u16 fc) +{ + return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) && + ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BACK_REQ); +} + +static inline int ieee80211_is_probe_response(u16 fc) +{ + return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) && + ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP); +} + +static inline int ieee80211_is_probe_request(u16 fc) +{ + return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) && + ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_REQ); +} + +static inline int ieee80211_is_beacon(u16 fc) +{ + return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) && + ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON); +} + +static inline int ieee80211_is_atim(u16 fc) +{ + return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) && + ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ATIM); +} + +static inline int ieee80211_is_assoc_request(u16 fc) +{ + return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) && + ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ); +} + +static inline int ieee80211_is_assoc_response(u16 fc) +{ + return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) && + ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_RESP); +} + +static inline int ieee80211_is_auth(u16 fc) +{ + return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) && + ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ); +} + +static inline int ieee80211_is_deauth(u16 fc) +{ + return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) && + ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ); +} + +static inline int ieee80211_is_disassoc(u16 fc) +{ + return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) && + ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ); +} + +static inline int ieee80211_is_reassoc_request(u16 fc) +{ + return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) && + ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ); +} + +static inline int ieee80211_is_reassoc_response(u16 fc) +{ + return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) && + ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_RESP); +} + +static inline int iwl_check_bits(unsigned long field, unsigned long mask) +{ + return ((field & mask) == mask) ? 1 : 0; +} + +static inline unsigned long elapsed_jiffies(unsigned long start, + unsigned long end) +{ + if (end > start) + return end - start; + + return end + (MAX_JIFFY_OFFSET - start); +} + +#endif /* __iwl_helpers_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-hw.h b/drivers/net/wireless/iwlwifi/iwl-hw.h new file mode 100644 index 00000000000..1aa6fcd39a5 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-hw.h @@ -0,0 +1,537 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU Geeral Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +#ifndef __iwlwifi_hw_h__ +#define __iwlwifi_hw_h__ + +/* + * This file defines hardware constants common to 3945 and 4965. + * + * Device-specific constants are defined in iwl-3945-hw.h and iwl-4965-hw.h, + * although this file contains a few definitions for which the .c + * implementation is the same for 3945 and 4965, except for the value of + * a constant. + * + * uCode API constants are defined in iwl-commands.h. + * + * NOTE: DO NOT PUT OS IMPLEMENTATION-SPECIFIC DECLARATIONS HERE + * + * The iwl-*hw.h (and files they include) files should remain OS/driver + * implementation independent, declaring only the hardware interface. + */ + +/* uCode queue management definitions */ +#define IWL_CMD_QUEUE_NUM 4 +#define IWL_CMD_FIFO_NUM 4 +#define IWL_BACK_QUEUE_FIRST_ID 7 + +/* Tx rates */ +#define IWL_CCK_RATES 4 +#define IWL_OFDM_RATES 8 + +#if IWL == 3945 +#define IWL_HT_RATES 0 +#elif IWL == 4965 +#define IWL_HT_RATES 16 +#endif + +#define IWL_MAX_RATES (IWL_CCK_RATES+IWL_OFDM_RATES+IWL_HT_RATES) + +/* Time constants */ +#define SHORT_SLOT_TIME 9 +#define LONG_SLOT_TIME 20 + +/* RSSI to dBm */ +#if IWL == 3945 +#define IWL_RSSI_OFFSET 95 +#elif IWL == 4965 +#define IWL_RSSI_OFFSET 44 +#endif + +#include "iwl-eeprom.h" +#include "iwl-commands.h" + +#define PCI_LINK_CTRL 0x0F0 +#define PCI_POWER_SOURCE 0x0C8 +#define PCI_REG_WUM8 0x0E8 +#define PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT (0x80000000) + +/*=== CSR (control and status registers) ===*/ +#define CSR_BASE (0x000) + +#define CSR_SW_VER (CSR_BASE+0x000) +#define CSR_HW_IF_CONFIG_REG (CSR_BASE+0x000) /* hardware interface config */ +#define CSR_INT_COALESCING (CSR_BASE+0x004) /* accum ints, 32-usec units */ +#define CSR_INT (CSR_BASE+0x008) /* host interrupt status/ack */ +#define CSR_INT_MASK (CSR_BASE+0x00c) /* host interrupt enable */ +#define CSR_FH_INT_STATUS (CSR_BASE+0x010) /* busmaster int status/ack*/ +#define CSR_GPIO_IN (CSR_BASE+0x018) /* read external chip pins */ +#define CSR_RESET (CSR_BASE+0x020) /* busmaster enable, NMI, etc*/ +#define CSR_GP_CNTRL (CSR_BASE+0x024) +#define CSR_HW_REV (CSR_BASE+0x028) +#define CSR_EEPROM_REG (CSR_BASE+0x02c) +#define CSR_EEPROM_GP (CSR_BASE+0x030) +#define CSR_GP_UCODE (CSR_BASE+0x044) +#define CSR_UCODE_DRV_GP1 (CSR_BASE+0x054) +#define CSR_UCODE_DRV_GP1_SET (CSR_BASE+0x058) +#define CSR_UCODE_DRV_GP1_CLR (CSR_BASE+0x05c) +#define CSR_UCODE_DRV_GP2 (CSR_BASE+0x060) +#define CSR_LED_REG (CSR_BASE+0x094) +#define CSR_DRAM_INT_TBL_CTL (CSR_BASE+0x0A0) +#define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100) +#define CSR_ANA_PLL_CFG (CSR_BASE+0x20c) +#define CSR_HW_REV_WA_REG (CSR_BASE+0x22C) + +/* HW I/F configuration */ +#define CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MB (0x00000100) +#define CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MM (0x00000200) +#define CSR_HW_IF_CONFIG_REG_BIT_SKU_MRC (0x00000400) +#define CSR_HW_IF_CONFIG_REG_BIT_BOARD_TYPE (0x00000800) +#define CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A (0x00000000) +#define CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B (0x00001000) +#define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM (0x00200000) + +/* interrupt flags in INTA, set by uCode or hardware (e.g. dma), + * acknowledged (reset) by host writing "1" to flagged bits. */ +#define CSR_INT_BIT_FH_RX (1<<31) /* Rx DMA, cmd responses, FH_INT[17:16] */ +#define CSR_INT_BIT_HW_ERR (1<<29) /* DMA hardware error FH_INT[31] */ +#define CSR_INT_BIT_DNLD (1<<28) /* uCode Download */ +#define CSR_INT_BIT_FH_TX (1<<27) /* Tx DMA FH_INT[1:0] */ +#define CSR_INT_BIT_MAC_CLK_ACTV (1<<26) /* NIC controller's clock toggled on/off */ +#define CSR_INT_BIT_SW_ERR (1<<25) /* uCode error */ +#define CSR_INT_BIT_RF_KILL (1<<7) /* HW RFKILL switch GP_CNTRL[27] toggled */ +#define CSR_INT_BIT_CT_KILL (1<<6) /* Critical temp (chip too hot) rfkill */ +#define CSR_INT_BIT_SW_RX (1<<3) /* Rx, command responses, 3945 */ +#define CSR_INT_BIT_WAKEUP (1<<1) /* NIC controller waking up (pwr mgmt) */ +#define CSR_INT_BIT_ALIVE (1<<0) /* uCode interrupts once it initializes */ + +#define CSR_INI_SET_MASK (CSR_INT_BIT_FH_RX | \ + CSR_INT_BIT_HW_ERR | \ + CSR_INT_BIT_FH_TX | \ + CSR_INT_BIT_SW_ERR | \ + CSR_INT_BIT_RF_KILL | \ + CSR_INT_BIT_SW_RX | \ + CSR_INT_BIT_WAKEUP | \ + CSR_INT_BIT_ALIVE) + +/* interrupt flags in FH (flow handler) (PCI busmaster DMA) */ +#define CSR_FH_INT_BIT_ERR (1<<31) /* Error */ +#define CSR_FH_INT_BIT_HI_PRIOR (1<<30) /* High priority Rx, bypass coalescing */ +#define CSR_FH_INT_BIT_RX_CHNL2 (1<<18) /* Rx channel 2 (3945 only) */ +#define CSR_FH_INT_BIT_RX_CHNL1 (1<<17) /* Rx channel 1 */ +#define CSR_FH_INT_BIT_RX_CHNL0 (1<<16) /* Rx channel 0 */ +#define CSR_FH_INT_BIT_TX_CHNL6 (1<<6) /* Tx channel 6 (3945 only) */ +#define CSR_FH_INT_BIT_TX_CHNL1 (1<<1) /* Tx channel 1 */ +#define CSR_FH_INT_BIT_TX_CHNL0 (1<<0) /* Tx channel 0 */ + +#define CSR_FH_INT_RX_MASK (CSR_FH_INT_BIT_HI_PRIOR | \ + CSR_FH_INT_BIT_RX_CHNL2 | \ + CSR_FH_INT_BIT_RX_CHNL1 | \ + CSR_FH_INT_BIT_RX_CHNL0) + +#define CSR_FH_INT_TX_MASK (CSR_FH_INT_BIT_TX_CHNL6 | \ + CSR_FH_INT_BIT_TX_CHNL1 | \ + CSR_FH_INT_BIT_TX_CHNL0 ) + + +/* RESET */ +#define CSR_RESET_REG_FLAG_NEVO_RESET (0x00000001) +#define CSR_RESET_REG_FLAG_FORCE_NMI (0x00000002) +#define CSR_RESET_REG_FLAG_SW_RESET (0x00000080) +#define CSR_RESET_REG_FLAG_MASTER_DISABLED (0x00000100) +#define CSR_RESET_REG_FLAG_STOP_MASTER (0x00000200) + +/* GP (general purpose) CONTROL */ +#define CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY (0x00000001) +#define CSR_GP_CNTRL_REG_FLAG_INIT_DONE (0x00000004) +#define CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ (0x00000008) +#define CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP (0x00000010) + +#define CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN (0x00000001) + +#define CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE (0x07000000) +#define CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE (0x04000000) +#define CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW (0x08000000) + + +/* EEPROM REG */ +#define CSR_EEPROM_REG_READ_VALID_MSK (0x00000001) +#define CSR_EEPROM_REG_BIT_CMD (0x00000002) + +/* EEPROM GP */ +#define CSR_EEPROM_GP_VALID_MSK (0x00000006) +#define CSR_EEPROM_GP_BAD_SIGNATURE (0x00000000) +#define CSR_EEPROM_GP_IF_OWNER_MSK (0x00000180) + +/* UCODE DRV GP */ +#define CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP (0x00000001) +#define CSR_UCODE_SW_BIT_RFKILL (0x00000002) +#define CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED (0x00000004) +#define CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT (0x00000008) + +/* GPIO */ +#define CSR_GPIO_IN_BIT_AUX_POWER (0x00000200) +#define CSR_GPIO_IN_VAL_VAUX_PWR_SRC (0x00000000) +#define CSR_GPIO_IN_VAL_VMAIN_PWR_SRC CSR_GPIO_IN_BIT_AUX_POWER + +/* GI Chicken Bits */ +#define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX (0x00800000) +#define CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER (0x20000000) + +/* CSR_ANA_PLL_CFG */ +#define CSR_ANA_PLL_CFG_SH (0x00880300) + +#define CSR_LED_REG_TRUN_ON (0x00000078) +#define CSR_LED_REG_TRUN_OFF (0x00000038) +#define CSR_LED_BSM_CTRL_MSK (0xFFFFFFDF) + +/* DRAM_INT_TBL_CTRL */ +#define CSR_DRAM_INT_TBL_CTRL_EN (1<<31) +#define CSR_DRAM_INT_TBL_CTRL_WRAP_CHK (1<<27) + +/*=== HBUS (Host-side Bus) ===*/ +#define HBUS_BASE (0x400) + +#define HBUS_TARG_MEM_RADDR (HBUS_BASE+0x00c) +#define HBUS_TARG_MEM_WADDR (HBUS_BASE+0x010) +#define HBUS_TARG_MEM_WDAT (HBUS_BASE+0x018) +#define HBUS_TARG_MEM_RDAT (HBUS_BASE+0x01c) +#define HBUS_TARG_PRPH_WADDR (HBUS_BASE+0x044) +#define HBUS_TARG_PRPH_RADDR (HBUS_BASE+0x048) +#define HBUS_TARG_PRPH_WDAT (HBUS_BASE+0x04c) +#define HBUS_TARG_PRPH_RDAT (HBUS_BASE+0x050) +#define HBUS_TARG_WRPTR (HBUS_BASE+0x060) + +#define HBUS_TARG_MBX_C (HBUS_BASE+0x030) + + +/* SCD (Scheduler) */ +#define SCD_BASE (CSR_BASE + 0x2E00) + +#define SCD_MODE_REG (SCD_BASE + 0x000) +#define SCD_ARASTAT_REG (SCD_BASE + 0x004) +#define SCD_TXFACT_REG (SCD_BASE + 0x010) +#define SCD_TXF4MF_REG (SCD_BASE + 0x014) +#define SCD_TXF5MF_REG (SCD_BASE + 0x020) +#define SCD_SBYP_MODE_1_REG (SCD_BASE + 0x02C) +#define SCD_SBYP_MODE_2_REG (SCD_BASE + 0x030) + +/*=== FH (data Flow Handler) ===*/ +#define FH_BASE (0x800) + +#define FH_CBCC_TABLE (FH_BASE+0x140) +#define FH_TFDB_TABLE (FH_BASE+0x180) +#define FH_RCSR_TABLE (FH_BASE+0x400) +#define FH_RSSR_TABLE (FH_BASE+0x4c0) +#define FH_TCSR_TABLE (FH_BASE+0x500) +#define FH_TSSR_TABLE (FH_BASE+0x680) + +/* TFDB (Transmit Frame Buffer Descriptor) */ +#define FH_TFDB(_channel, buf) \ + (FH_TFDB_TABLE+((_channel)*2+(buf))*0x28) +#define ALM_FH_TFDB_CHNL_BUF_CTRL_REG(_channel) \ + (FH_TFDB_TABLE + 0x50 * _channel) +/* CBCC _channel is [0,2] */ +#define FH_CBCC(_channel) (FH_CBCC_TABLE+(_channel)*0x8) +#define FH_CBCC_CTRL(_channel) (FH_CBCC(_channel)+0x00) +#define FH_CBCC_BASE(_channel) (FH_CBCC(_channel)+0x04) + +/* RCSR _channel is [0,2] */ +#define FH_RCSR(_channel) (FH_RCSR_TABLE+(_channel)*0x40) +#define FH_RCSR_CONFIG(_channel) (FH_RCSR(_channel)+0x00) +#define FH_RCSR_RBD_BASE(_channel) (FH_RCSR(_channel)+0x04) +#define FH_RCSR_WPTR(_channel) (FH_RCSR(_channel)+0x20) +#define FH_RCSR_RPTR_ADDR(_channel) (FH_RCSR(_channel)+0x24) + +#if IWL == 3945 +#define FH_RSCSR_CHNL0_WPTR (FH_RCSR_WPTR(0)) +#elif IWL == 4965 +#define FH_RSCSR_CHNL0_WPTR (FH_RSCSR_CHNL0_RBDCB_WPTR_REG) +#endif + +/* RSSR */ +#define FH_RSSR_CTRL (FH_RSSR_TABLE+0x000) +#define FH_RSSR_STATUS (FH_RSSR_TABLE+0x004) +/* TCSR */ +#define FH_TCSR(_channel) (FH_TCSR_TABLE+(_channel)*0x20) +#define FH_TCSR_CONFIG(_channel) (FH_TCSR(_channel)+0x00) +#define FH_TCSR_CREDIT(_channel) (FH_TCSR(_channel)+0x04) +#define FH_TCSR_BUFF_STTS(_channel) (FH_TCSR(_channel)+0x08) +/* TSSR */ +#define FH_TSSR_CBB_BASE (FH_TSSR_TABLE+0x000) +#define FH_TSSR_MSG_CONFIG (FH_TSSR_TABLE+0x008) +#define FH_TSSR_TX_STATUS (FH_TSSR_TABLE+0x010) +/* 18 - reserved */ + +/* card static random access memory (SRAM) for processor data and instructs */ +#define RTC_INST_LOWER_BOUND (0x000000) +#define RTC_DATA_LOWER_BOUND (0x800000) + + +/* DBM */ + +#define ALM_FH_SRVC_CHNL (6) + +#define ALM_FH_RCSR_RX_CONFIG_REG_POS_RBDC_SIZE (20) +#define ALM_FH_RCSR_RX_CONFIG_REG_POS_IRQ_RBTH (4) + +#define ALM_FH_RCSR_RX_CONFIG_REG_BIT_WR_STTS_EN (0x08000000) + +#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_DMA_CHNL_EN_ENABLE (0x80000000) + +#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_RDRBD_EN_ENABLE (0x20000000) + +#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_MAX_FRAG_SIZE_128 (0x01000000) + +#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_IRQ_DEST_INT_HOST (0x00001000) + +#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_MSG_MODE_FH (0x00000000) + +#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_TXF (0x00000000) +#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_DRIVER (0x00000001) + +#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL (0x00000000) +#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL (0x00000008) + +#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD (0x00200000) + +#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_NOINT (0x00000000) + +#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE (0x00000000) +#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE (0x80000000) + +#define ALM_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID (0x00004000) + +#define ALM_FH_TCSR_CHNL_TX_BUF_STS_REG_BIT_TFDB_WPTR (0x00000001) + +#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TXPD_ON (0xFF000000) +#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_TXPD_ON (0x00FF0000) + +#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_128B (0x00000400) + +#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TFD_ON (0x00000100) +#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_CBB_ON (0x00000080) + +#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RSP_WAIT_TH (0x00000020) +#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_RSP_WAIT_TH (0x00000005) + +#define ALM_TB_MAX_BYTES_COUNT (0xFFF0) + +#define ALM_FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_channel) \ + ((1LU << _channel) << 24) +#define ALM_FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_channel) \ + ((1LU << _channel) << 16) + +#define ALM_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(_channel) \ + (ALM_FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_channel) | \ + ALM_FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_channel)) +#define PCI_CFG_REV_ID_BIT_BASIC_SKU (0x40) /* bit 6 */ +#define PCI_CFG_REV_ID_BIT_RTP (0x80) /* bit 7 */ + +#define HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED (0x00000004) + +#define TFD_QUEUE_MIN 0 +#define TFD_QUEUE_MAX 6 +#define TFD_QUEUE_SIZE_MAX (256) + +/* spectrum and channel data structures */ +#define IWL_NUM_SCAN_RATES (2) + +#define IWL_SCAN_FLAG_24GHZ (1<<0) +#define IWL_SCAN_FLAG_52GHZ (1<<1) +#define IWL_SCAN_FLAG_ACTIVE (1<<2) +#define IWL_SCAN_FLAG_DIRECT (1<<3) + +#define IWL_MAX_CMD_SIZE 1024 + +#define IWL_DEFAULT_TX_RETRY 15 +#define IWL_MAX_TX_RETRY 16 + +/*********************************************/ + +#define RFD_SIZE 4 +#define NUM_TFD_CHUNKS 4 + +#define RX_QUEUE_SIZE 256 +#define RX_QUEUE_MASK 255 +#define RX_QUEUE_SIZE_LOG 8 + +/* QoS definitions */ + +#define CW_MIN_OFDM 15 +#define CW_MAX_OFDM 1023 +#define CW_MIN_CCK 31 +#define CW_MAX_CCK 1023 + +#define QOS_TX0_CW_MIN_OFDM CW_MIN_OFDM +#define QOS_TX1_CW_MIN_OFDM CW_MIN_OFDM +#define QOS_TX2_CW_MIN_OFDM ((CW_MIN_OFDM + 1) / 2 - 1) +#define QOS_TX3_CW_MIN_OFDM ((CW_MIN_OFDM + 1) / 4 - 1) + +#define QOS_TX0_CW_MIN_CCK CW_MIN_CCK +#define QOS_TX1_CW_MIN_CCK CW_MIN_CCK +#define QOS_TX2_CW_MIN_CCK ((CW_MIN_CCK + 1) / 2 - 1) +#define QOS_TX3_CW_MIN_CCK ((CW_MIN_CCK + 1) / 4 - 1) + +#define QOS_TX0_CW_MAX_OFDM CW_MAX_OFDM +#define QOS_TX1_CW_MAX_OFDM CW_MAX_OFDM +#define QOS_TX2_CW_MAX_OFDM CW_MIN_OFDM +#define QOS_TX3_CW_MAX_OFDM ((CW_MIN_OFDM + 1) / 2 - 1) + +#define QOS_TX0_CW_MAX_CCK CW_MAX_CCK +#define QOS_TX1_CW_MAX_CCK CW_MAX_CCK +#define QOS_TX2_CW_MAX_CCK CW_MIN_CCK +#define QOS_TX3_CW_MAX_CCK ((CW_MIN_CCK + 1) / 2 - 1) + +#define QOS_TX0_AIFS 3 +#define QOS_TX1_AIFS 7 +#define QOS_TX2_AIFS 2 +#define QOS_TX3_AIFS 2 + +#define QOS_TX0_ACM 0 +#define QOS_TX1_ACM 0 +#define QOS_TX2_ACM 0 +#define QOS_TX3_ACM 0 + +#define QOS_TX0_TXOP_LIMIT_CCK 0 +#define QOS_TX1_TXOP_LIMIT_CCK 0 +#define QOS_TX2_TXOP_LIMIT_CCK 6016 +#define QOS_TX3_TXOP_LIMIT_CCK 3264 + +#define QOS_TX0_TXOP_LIMIT_OFDM 0 +#define QOS_TX1_TXOP_LIMIT_OFDM 0 +#define QOS_TX2_TXOP_LIMIT_OFDM 3008 +#define QOS_TX3_TXOP_LIMIT_OFDM 1504 + +#define DEF_TX0_CW_MIN_OFDM CW_MIN_OFDM +#define DEF_TX1_CW_MIN_OFDM CW_MIN_OFDM +#define DEF_TX2_CW_MIN_OFDM CW_MIN_OFDM +#define DEF_TX3_CW_MIN_OFDM CW_MIN_OFDM + +#define DEF_TX0_CW_MIN_CCK CW_MIN_CCK +#define DEF_TX1_CW_MIN_CCK CW_MIN_CCK +#define DEF_TX2_CW_MIN_CCK CW_MIN_CCK +#define DEF_TX3_CW_MIN_CCK CW_MIN_CCK + +#define DEF_TX0_CW_MAX_OFDM CW_MAX_OFDM +#define DEF_TX1_CW_MAX_OFDM CW_MAX_OFDM +#define DEF_TX2_CW_MAX_OFDM CW_MAX_OFDM +#define DEF_TX3_CW_MAX_OFDM CW_MAX_OFDM + +#define DEF_TX0_CW_MAX_CCK CW_MAX_CCK +#define DEF_TX1_CW_MAX_CCK CW_MAX_CCK +#define DEF_TX2_CW_MAX_CCK CW_MAX_CCK +#define DEF_TX3_CW_MAX_CCK CW_MAX_CCK + +#define DEF_TX0_AIFS (2) +#define DEF_TX1_AIFS (2) +#define DEF_TX2_AIFS (2) +#define DEF_TX3_AIFS (2) + +#define DEF_TX0_ACM 0 +#define DEF_TX1_ACM 0 +#define DEF_TX2_ACM 0 +#define DEF_TX3_ACM 0 + +#define DEF_TX0_TXOP_LIMIT_CCK 0 +#define DEF_TX1_TXOP_LIMIT_CCK 0 +#define DEF_TX2_TXOP_LIMIT_CCK 0 +#define DEF_TX3_TXOP_LIMIT_CCK 0 + +#define DEF_TX0_TXOP_LIMIT_OFDM 0 +#define DEF_TX1_TXOP_LIMIT_OFDM 0 +#define DEF_TX2_TXOP_LIMIT_OFDM 0 +#define DEF_TX3_TXOP_LIMIT_OFDM 0 + +#define QOS_QOS_SETS 3 +#define QOS_PARAM_SET_ACTIVE 0 +#define QOS_PARAM_SET_DEF_CCK 1 +#define QOS_PARAM_SET_DEF_OFDM 2 + +#define CTRL_QOS_NO_ACK (0x0020) +#define DCT_FLAG_EXT_QOS_ENABLED (0x10) + +#define U32_PAD(n) ((4-(n))&0x3) + +/* + * Generic queue structure + * + * Contains common data for Rx and Tx queues + */ +#define TFD_CTL_COUNT_SET(n) (n<<24) +#define TFD_CTL_COUNT_GET(ctl) ((ctl>>24) & 7) +#define TFD_CTL_PAD_SET(n) (n<<28) +#define TFD_CTL_PAD_GET(ctl) (ctl>>28) + +#define TFD_TX_CMD_SLOTS 256 +#define TFD_CMD_SLOTS 32 + +#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_cmd) - \ + sizeof(struct iwl_cmd_meta)) + +/* + * RX related structures and functions + */ +#define RX_FREE_BUFFERS 64 +#define RX_LOW_WATERMARK 8 + +#endif /* __iwlwifi_hw_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h new file mode 100644 index 00000000000..8a8b96fcf48 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-io.h @@ -0,0 +1,470 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#ifndef __iwl_io_h__ +#define __iwl_io_h__ + +#include + +#include "iwl-debug.h" + +/* + * IO, register, and NIC memory access functions + * + * NOTE on naming convention and macro usage for these + * + * A single _ prefix before a an access function means that no state + * check or debug information is printed when that function is called. + * + * A double __ prefix before an access function means that state is checked + * (in the case of *restricted calls) and the current line number is printed + * in addition to any other debug output. + * + * The non-prefixed name is the #define that maps the caller into a + * #define that provides the caller's __LINE__ to the double prefix version. + * + * If you wish to call the function without any debug or state checking, + * you should use the single _ prefix version (as is used by dependent IO + * routines, for example _iwl_read_restricted calls the non-check version of + * _iwl_read32.) + * + * These declarations are *extremely* useful in quickly isolating code deltas + * which result in misconfiguring of the hardware I/O. In combination with + * git-bisect and the IO debug level you can quickly determine the specific + * commit which breaks the IO sequence to the hardware. + * + */ + +#define _iwl_write32(iwl, ofs, val) writel((val), (iwl)->hw_base + (ofs)) +#ifdef CONFIG_IWLWIFI_DEBUG +static inline void __iwl_write32(const char *f, u32 l, struct iwl_priv *iwl, + u32 ofs, u32 val) +{ + IWL_DEBUG_IO("write_direct32(0x%08X, 0x%08X) - %s %d\n", + (u32) (ofs), (u32) (val), f, l); + _iwl_write32(iwl, ofs, val); +} +#define iwl_write32(iwl, ofs, val) \ + __iwl_write32(__FILE__, __LINE__, iwl, ofs, val) +#else +#define iwl_write32(iwl, ofs, val) _iwl_write32(iwl, ofs, val) +#endif + +#define _iwl_read32(iwl, ofs) readl((iwl)->hw_base + (ofs)) +#ifdef CONFIG_IWLWIFI_DEBUG +static inline u32 __iwl_read32(char *f, u32 l, struct iwl_priv *iwl, u32 ofs) +{ + IWL_DEBUG_IO("read_direct32(0x%08X) - %s %d\n", ofs, f, l); + return _iwl_read32(iwl, ofs); +} +#define iwl_read32(iwl, ofs) __iwl_read32(__FILE__, __LINE__, iwl, ofs) +#else +#define iwl_read32(p, o) _iwl_read32(p, o) +#endif + +static inline int _iwl_poll_bit(struct iwl_priv *priv, u32 addr, + u32 bits, u32 mask, int timeout) +{ + int i = 0; + + do { + if ((_iwl_read32(priv, addr) & mask) == (bits & mask)) + return i; + mdelay(10); + i += 10; + } while (i < timeout); + + return -ETIMEDOUT; +} +#ifdef CONFIG_IWLWIFI_DEBUG +static inline int __iwl_poll_bit(const char *f, u32 l, + struct iwl_priv *priv, u32 addr, + u32 bits, u32 mask, int timeout) +{ + int rc = _iwl_poll_bit(priv, addr, bits, mask, timeout); + if (unlikely(rc == -ETIMEDOUT)) + IWL_DEBUG_IO + ("poll_bit(0x%08X, 0x%08X, 0x%08X) - timedout - %s %d\n", + addr, bits, mask, f, l); + else + IWL_DEBUG_IO + ("poll_bit(0x%08X, 0x%08X, 0x%08X) = 0x%08X - %s %d\n", + addr, bits, mask, rc, f, l); + return rc; +} +#define iwl_poll_bit(iwl, addr, bits, mask, timeout) \ + __iwl_poll_bit(__FILE__, __LINE__, iwl, addr, bits, mask, timeout) +#else +#define iwl_poll_bit(p, a, b, m, t) _iwl_poll_bit(p, a, b, m, t) +#endif + +static inline void _iwl_set_bit(struct iwl_priv *priv, u32 reg, u32 mask) +{ + _iwl_write32(priv, reg, _iwl_read32(priv, reg) | mask); +} +#ifdef CONFIG_IWLWIFI_DEBUG +static inline void __iwl_set_bit(const char *f, u32 l, + struct iwl_priv *priv, u32 reg, u32 mask) +{ + u32 val = _iwl_read32(priv, reg) | mask; + IWL_DEBUG_IO("set_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val); + _iwl_write32(priv, reg, val); +} +#define iwl_set_bit(p, r, m) __iwl_set_bit(__FILE__, __LINE__, p, r, m) +#else +#define iwl_set_bit(p, r, m) _iwl_set_bit(p, r, m) +#endif + +static inline void _iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask) +{ + _iwl_write32(priv, reg, _iwl_read32(priv, reg) & ~mask); +} +#ifdef CONFIG_IWLWIFI_DEBUG +static inline void __iwl_clear_bit(const char *f, u32 l, + struct iwl_priv *priv, u32 reg, u32 mask) +{ + u32 val = _iwl_read32(priv, reg) & ~mask; + IWL_DEBUG_IO("clear_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val); + _iwl_write32(priv, reg, val); +} +#define iwl_clear_bit(p, r, m) __iwl_clear_bit(__FILE__, __LINE__, p, r, m) +#else +#define iwl_clear_bit(p, r, m) _iwl_clear_bit(p, r, m) +#endif + +static inline int _iwl_grab_restricted_access(struct iwl_priv *priv) +{ + int rc; + u32 gp_ctl; + +#ifdef CONFIG_IWLWIFI_DEBUG + if (atomic_read(&priv->restrict_refcnt)) + return 0; +#endif + if (test_bit(STATUS_RF_KILL_HW, &priv->status) || + test_bit(STATUS_RF_KILL_SW, &priv->status)) { + IWL_WARNING("WARNING: Requesting MAC access during RFKILL " + "wakes up NIC\n"); + + /* 10 msec allows time for NIC to complete its data save */ + gp_ctl = _iwl_read32(priv, CSR_GP_CNTRL); + if (gp_ctl & CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY) { + IWL_DEBUG_RF_KILL("Wait for complete power-down, " + "gpctl = 0x%08x\n", gp_ctl); + mdelay(10); + } else + IWL_DEBUG_RF_KILL("power-down complete, " + "gpctl = 0x%08x\n", gp_ctl); + } + + /* this bit wakes up the NIC */ + _iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + rc = _iwl_poll_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN, + (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | + CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 50); + if (rc < 0) { + IWL_ERROR("MAC is in deep sleep!\n"); + return -EIO; + } + +#ifdef CONFIG_IWLWIFI_DEBUG + atomic_inc(&priv->restrict_refcnt); +#endif + return 0; +} + +#ifdef CONFIG_IWLWIFI_DEBUG +static inline int __iwl_grab_restricted_access(const char *f, u32 l, + struct iwl_priv *priv) +{ + if (atomic_read(&priv->restrict_refcnt)) + IWL_DEBUG_INFO("Grabbing access while already held at " + "line %d.\n", l); + + IWL_DEBUG_IO("grabbing restricted access - %s %d\n", f, l); + + return _iwl_grab_restricted_access(priv); +} +#define iwl_grab_restricted_access(priv) \ + __iwl_grab_restricted_access(__FILE__, __LINE__, priv) +#else +#define iwl_grab_restricted_access(priv) \ + _iwl_grab_restricted_access(priv) +#endif + +static inline void _iwl_release_restricted_access(struct iwl_priv *priv) +{ +#ifdef CONFIG_IWLWIFI_DEBUG + if (atomic_dec_and_test(&priv->restrict_refcnt)) +#endif + _iwl_clear_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); +} +#ifdef CONFIG_IWLWIFI_DEBUG +static inline void __iwl_release_restricted_access(const char *f, u32 l, + struct iwl_priv *priv) +{ + if (atomic_read(&priv->restrict_refcnt) <= 0) + IWL_ERROR("Release unheld restricted access at line %d.\n", l); + + IWL_DEBUG_IO("releasing restricted access - %s %d\n", f, l); + _iwl_release_restricted_access(priv); +} +#define iwl_release_restricted_access(priv) \ + __iwl_release_restricted_access(__FILE__, __LINE__, priv) +#else +#define iwl_release_restricted_access(priv) \ + _iwl_release_restricted_access(priv) +#endif + +static inline u32 _iwl_read_restricted(struct iwl_priv *priv, u32 reg) +{ + return _iwl_read32(priv, reg); +} +#ifdef CONFIG_IWLWIFI_DEBUG +static inline u32 __iwl_read_restricted(const char *f, u32 l, + struct iwl_priv *priv, u32 reg) +{ + u32 value = _iwl_read_restricted(priv, reg); + if (!atomic_read(&priv->restrict_refcnt)) + IWL_ERROR("Unrestricted access from %s %d\n", f, l); + IWL_DEBUG_IO("read_restricted(0x%4X) = 0x%08x - %s %d \n", reg, value, + f, l); + return value; +} +#define iwl_read_restricted(priv, reg) \ + __iwl_read_restricted(__FILE__, __LINE__, priv, reg) +#else +#define iwl_read_restricted _iwl_read_restricted +#endif + +static inline void _iwl_write_restricted(struct iwl_priv *priv, + u32 reg, u32 value) +{ + _iwl_write32(priv, reg, value); +} +#ifdef CONFIG_IWLWIFI_DEBUG +static void __iwl_write_restricted(u32 line, + struct iwl_priv *priv, u32 reg, u32 value) +{ + if (!atomic_read(&priv->restrict_refcnt)) + IWL_ERROR("Unrestricted access from line %d\n", line); + _iwl_write_restricted(priv, reg, value); +} +#define iwl_write_restricted(priv, reg, value) \ + __iwl_write_restricted(__LINE__, priv, reg, value) +#else +#define iwl_write_restricted _iwl_write_restricted +#endif + +static inline void iwl_write_buffer_restricted(struct iwl_priv *priv, + u32 reg, u32 len, u32 *values) +{ + u32 count = sizeof(u32); + + if ((priv != NULL) && (values != NULL)) { + for (; 0 < len; len -= count, reg += count, values++) + _iwl_write_restricted(priv, reg, *values); + } +} + +static inline int _iwl_poll_restricted_bit(struct iwl_priv *priv, + u32 addr, u32 mask, int timeout) +{ + int i = 0; + + do { + if ((_iwl_read_restricted(priv, addr) & mask) == mask) + return i; + mdelay(10); + i += 10; + } while (i < timeout); + + return -ETIMEDOUT; +} + +#ifdef CONFIG_IWLWIFI_DEBUG +static inline int __iwl_poll_restricted_bit(const char *f, u32 l, + struct iwl_priv *priv, + u32 addr, u32 mask, int timeout) +{ + int rc = _iwl_poll_restricted_bit(priv, addr, mask, timeout); + + if (unlikely(rc == -ETIMEDOUT)) + IWL_DEBUG_IO("poll_restricted_bit(0x%08X, 0x%08X) - " + "timedout - %s %d\n", addr, mask, f, l); + else + IWL_DEBUG_IO("poll_restricted_bit(0x%08X, 0x%08X) = 0x%08X " + "- %s %d\n", addr, mask, rc, f, l); + return rc; +} +#define iwl_poll_restricted_bit(iwl, addr, mask, timeout) \ + __iwl_poll_restricted_bit(__FILE__, __LINE__, iwl, addr, mask, timeout) +#else +#define iwl_poll_restricted_bit _iwl_poll_restricted_bit +#endif + +static inline u32 _iwl_read_restricted_reg(struct iwl_priv *priv, u32 reg) +{ + _iwl_write_restricted(priv, HBUS_TARG_PRPH_RADDR, reg | (3 << 24)); + return _iwl_read_restricted(priv, HBUS_TARG_PRPH_RDAT); +} +#ifdef CONFIG_IWLWIFI_DEBUG +static inline u32 __iwl_read_restricted_reg(u32 line, + struct iwl_priv *priv, u32 reg) +{ + if (!atomic_read(&priv->restrict_refcnt)) + IWL_ERROR("Unrestricted access from line %d\n", line); + return _iwl_read_restricted_reg(priv, reg); +} + +#define iwl_read_restricted_reg(priv, reg) \ + __iwl_read_restricted_reg(__LINE__, priv, reg) +#else +#define iwl_read_restricted_reg _iwl_read_restricted_reg +#endif + +static inline void _iwl_write_restricted_reg(struct iwl_priv *priv, + u32 addr, u32 val) +{ + _iwl_write_restricted(priv, HBUS_TARG_PRPH_WADDR, + ((addr & 0x0000FFFF) | (3 << 24))); + _iwl_write_restricted(priv, HBUS_TARG_PRPH_WDAT, val); +} +#ifdef CONFIG_IWLWIFI_DEBUG +static inline void __iwl_write_restricted_reg(u32 line, + struct iwl_priv *priv, + u32 addr, u32 val) +{ + if (!atomic_read(&priv->restrict_refcnt)) + IWL_ERROR("Unrestricted access from line %d\n", line); + _iwl_write_restricted_reg(priv, addr, val); +} + +#define iwl_write_restricted_reg(priv, addr, val) \ + __iwl_write_restricted_reg(__LINE__, priv, addr, val); +#else +#define iwl_write_restricted_reg _iwl_write_restricted_reg +#endif + +#define _iwl_set_bits_restricted_reg(priv, reg, mask) \ + _iwl_write_restricted_reg(priv, reg, \ + (_iwl_read_restricted_reg(priv, reg) | mask)) +#ifdef CONFIG_IWLWIFI_DEBUG +static inline void __iwl_set_bits_restricted_reg(u32 line, struct iwl_priv + *priv, u32 reg, u32 mask) +{ + if (!atomic_read(&priv->restrict_refcnt)) + IWL_ERROR("Unrestricted access from line %d\n", line); + _iwl_set_bits_restricted_reg(priv, reg, mask); +} +#define iwl_set_bits_restricted_reg(priv, reg, mask) \ + __iwl_set_bits_restricted_reg(__LINE__, priv, reg, mask) +#else +#define iwl_set_bits_restricted_reg _iwl_set_bits_restricted_reg +#endif + +#define _iwl_set_bits_mask_restricted_reg(priv, reg, bits, mask) \ + _iwl_write_restricted_reg( \ + priv, reg, ((_iwl_read_restricted_reg(priv, reg) & mask) | bits)) +#ifdef CONFIG_IWLWIFI_DEBUG +static inline void __iwl_set_bits_mask_restricted_reg(u32 line, + struct iwl_priv *priv, u32 reg, u32 bits, u32 mask) +{ + if (!atomic_read(&priv->restrict_refcnt)) + IWL_ERROR("Unrestricted access from line %d\n", line); + _iwl_set_bits_mask_restricted_reg(priv, reg, bits, mask); +} + +#define iwl_set_bits_mask_restricted_reg(priv, reg, bits, mask) \ + __iwl_set_bits_mask_restricted_reg(__LINE__, priv, reg, bits, mask) +#else +#define iwl_set_bits_mask_restricted_reg _iwl_set_bits_mask_restricted_reg +#endif + +static inline void iwl_clear_bits_restricted_reg(struct iwl_priv + *priv, u32 reg, u32 mask) +{ + u32 val = _iwl_read_restricted_reg(priv, reg); + _iwl_write_restricted_reg(priv, reg, (val & ~mask)); +} + +static inline u32 iwl_read_restricted_mem(struct iwl_priv *priv, u32 addr) +{ + iwl_write_restricted(priv, HBUS_TARG_MEM_RADDR, addr); + return iwl_read_restricted(priv, HBUS_TARG_MEM_RDAT); +} + +static inline void iwl_write_restricted_mem(struct iwl_priv *priv, u32 addr, + u32 val) +{ + iwl_write_restricted(priv, HBUS_TARG_MEM_WADDR, addr); + iwl_write_restricted(priv, HBUS_TARG_MEM_WDAT, val); +} + +static inline void iwl_write_restricted_mems(struct iwl_priv *priv, u32 addr, + u32 len, u32 *values) +{ + iwl_write_restricted(priv, HBUS_TARG_MEM_WADDR, addr); + for (; 0 < len; len -= sizeof(u32), values++) + iwl_write_restricted(priv, HBUS_TARG_MEM_WDAT, *values); +} + +static inline void iwl_write_restricted_regs(struct iwl_priv *priv, u32 reg, + u32 len, u8 *values) +{ + u32 reg_offset = reg; + u32 aligment = reg & 0x3; + + /* write any non-dword-aligned stuff at the beginning */ + if (len < sizeof(u32)) { + if ((aligment + len) <= sizeof(u32)) { + u8 size; + u32 value = 0; + size = len - 1; + memcpy(&value, values, len); + reg_offset = (reg_offset & 0x0000FFFF); + + _iwl_write_restricted(priv, + HBUS_TARG_PRPH_WADDR, + (reg_offset | (size << 24))); + _iwl_write_restricted(priv, HBUS_TARG_PRPH_WDAT, + value); + } + + return; + } + + /* now write all the dword-aligned stuff */ + for (; reg_offset < (reg + len); + reg_offset += sizeof(u32), values += sizeof(u32)) + _iwl_write_restricted_reg(priv, reg_offset, *((u32 *) values)); +} + +#endif diff --git a/drivers/net/wireless/iwlwifi/iwl-priv.h b/drivers/net/wireless/iwlwifi/iwl-priv.h new file mode 100644 index 00000000000..6b490d08fea --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-priv.h @@ -0,0 +1,308 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#ifndef __iwl_priv_h__ +#define __iwl_priv_h__ + +#include + +#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT + +enum { + MEASUREMENT_READY = (1 << 0), + MEASUREMENT_ACTIVE = (1 << 1), +}; + +#endif + +struct iwl_priv { + + /* ieee device used by generic ieee processing code */ + struct ieee80211_hw *hw; + struct ieee80211_channel *ieee_channels; + struct ieee80211_rate *ieee_rates; + + /* temporary frame storage list */ + struct list_head free_frames; + int frames_count; + + u8 phymode; + int alloc_rxb_skb; + + void (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb); + + const struct ieee80211_hw_mode *modes; + +#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT + /* spectrum measurement report caching */ + struct iwl_spectrum_notification measure_report; + u8 measurement_status; +#endif + /* ucode beacon time */ + u32 ucode_beacon_time; + + /* we allocate array of iwl_channel_info for NIC's valid channels. + * Access via channel # using indirect index array */ + struct iwl_channel_info *channel_info; /* channel info array */ + u8 channel_count; /* # of channels */ + + /* each calibration channel group in the EEPROM has a derived + * clip setting for each rate. */ + const struct iwl_clip_group clip_groups[5]; + + /* thermal calibration */ + s32 temperature; /* degrees Kelvin */ + s32 last_temperature; + + /* Scan related variables */ + unsigned long last_scan_jiffies; + unsigned long scan_start; + unsigned long scan_pass_start; + unsigned long scan_start_tsf; + int scan_bands; + int one_direct_scan; + u8 direct_ssid_len; + u8 direct_ssid[IW_ESSID_MAX_SIZE]; + struct iwl_scan_cmd *scan; + u8 only_active_channel; + + /* spinlock */ + spinlock_t lock; /* protect general shared data */ + spinlock_t hcmd_lock; /* protect hcmd */ + struct mutex mutex; + + /* basic pci-network driver stuff */ + struct pci_dev *pci_dev; + + /* pci hardware address support */ + void __iomem *hw_base; + + /* uCode images, save to reload in case of failure */ + struct fw_image_desc ucode_code; /* runtime inst */ + struct fw_image_desc ucode_data; /* runtime data original */ + struct fw_image_desc ucode_data_backup; /* runtime data save/restore */ + struct fw_image_desc ucode_init; /* initialization inst */ + struct fw_image_desc ucode_init_data; /* initialization data */ + struct fw_image_desc ucode_boot; /* bootstrap inst */ + + + struct iwl_rxon_time_cmd rxon_timing; + + /* We declare this const so it can only be + * changed via explicit cast within the + * routines that actually update the physical + * hardware */ + const struct iwl_rxon_cmd active_rxon; + struct iwl_rxon_cmd staging_rxon; + + int error_recovering; + struct iwl_rxon_cmd recovery_rxon; + + /* 1st responses from initialize and runtime uCode images. + * 4965's initialize alive response contains some calibration data. */ + struct iwl_init_alive_resp card_alive_init; + struct iwl_alive_resp card_alive; + +#ifdef LED + /* LED related variables */ + struct iwl_activity_blink activity; + unsigned long led_packets; + int led_state; +#endif + + u16 active_rate; + u16 active_rate_basic; + + u8 call_post_assoc_from_beacon; + u8 assoc_station_added; +#if IWL == 4965 + u8 use_ant_b_for_management_frame; /* Tx antenna selection */ + /* HT variables */ + u8 is_dup; + u8 is_ht_enabled; + u8 channel_width; /* 0=20MHZ, 1=40MHZ */ + u8 current_channel_width; + u8 valid_antenna; /* Bit mask of antennas actually connected */ +#ifdef CONFIG_IWLWIFI_SENSITIVITY + struct iwl_sensitivity_data sensitivity_data; + struct iwl_chain_noise_data chain_noise_data; + u8 start_calib; + __le16 sensitivity_tbl[HD_TABLE_SIZE]; +#endif /*CONFIG_IWLWIFI_SENSITIVITY*/ + +#ifdef CONFIG_IWLWIFI_HT + struct sta_ht_info current_assoc_ht; +#endif + u8 active_rate_ht[2]; + u8 last_phy_res[100]; + + /* Rate scaling data */ + struct iwl_lq_mngr lq_mngr; +#endif + + /* Rate scaling data */ + s8 data_retry_limit; + u8 retry_rate; + + wait_queue_head_t wait_command_queue; + + int activity_timer_active; + + /* Rx and Tx DMA processing queues */ + struct iwl_rx_queue rxq; + struct iwl_tx_queue txq[IWL_MAX_NUM_QUEUES]; +#if IWL == 4965 + unsigned long txq_ctx_active_msk; + struct iwl_kw kw; /* keep warm address */ + u32 scd_base_addr; /* scheduler sram base address */ +#endif + + unsigned long status; + u32 config; + + int last_rx_rssi; /* From Rx packet statisitics */ + int last_rx_noise; /* From beacon statistics */ + + struct iwl_power_mgr power_data; + + struct iwl_notif_statistics statistics; + unsigned long last_statistics_time; + + /* context information */ + u8 essid[IW_ESSID_MAX_SIZE]; + u8 essid_len; + u16 rates_mask; + + u32 power_mode; + u32 antenna; + u8 bssid[ETH_ALEN]; + u16 rts_threshold; + u8 mac_addr[ETH_ALEN]; + + /*station table variables */ + spinlock_t sta_lock; + int num_stations; + struct iwl_station_entry stations[IWL_STATION_COUNT]; + + /* Indication if ieee80211_ops->open has been called */ + int is_open; + + u8 mac80211_registered; + int is_abg; + + u32 notif_missed_beacons; + + /* Rx'd packet timing information */ + u32 last_beacon_time; + u64 last_tsf; + + /* Duplicate packet detection */ + u16 last_seq_num; + u16 last_frag_num; + unsigned long last_packet_time; + struct list_head ibss_mac_hash[IWL_IBSS_MAC_HASH_SIZE]; + + /* eeprom */ + struct iwl_eeprom eeprom; + + int iw_mode; + + struct sk_buff *ibss_beacon; + + /* Last Rx'd beacon timestamp */ + u32 timestamp0; + u32 timestamp1; + u16 beacon_int; + struct iwl_driver_hw_info hw_setting; + int interface_id; + + /* Current association information needed to configure the + * hardware */ + u16 assoc_id; + u16 assoc_capability; + u8 ps_mode; + +#ifdef CONFIG_IWLWIFI_QOS + struct iwl_qos_info qos_data; +#endif /*CONFIG_IWLWIFI_QOS */ + + struct workqueue_struct *workqueue; + + struct work_struct up; + struct work_struct restart; + struct work_struct calibrated_work; + struct work_struct scan_completed; + struct work_struct rx_replenish; + struct work_struct rf_kill; + struct work_struct abort_scan; + struct work_struct update_link_led; + struct work_struct auth_work; + struct work_struct report_work; + struct work_struct request_scan; + struct work_struct beacon_update; + + struct tasklet_struct irq_tasklet; + + struct delayed_work init_alive_start; + struct delayed_work alive_start; + struct delayed_work activity_timer; + struct delayed_work thermal_periodic; + struct delayed_work gather_stats; + struct delayed_work scan_check; + struct delayed_work post_associate; + +#define IWL_DEFAULT_TX_POWER 0x0F + s8 user_txpower_limit; + s8 max_channel_txpower_limit; + u32 cck_power_index_compensation; + +#ifdef CONFIG_PM + u32 pm_state[16]; +#endif + +#ifdef CONFIG_IWLWIFI_DEBUG + /* debugging info */ + u32 framecnt_to_us; + atomic_t restrict_refcnt; +#endif + +#if IWL == 4965 + struct work_struct txpower_work; +#ifdef CONFIG_IWLWIFI_SENSITIVITY + struct work_struct sensitivity_work; +#endif + struct work_struct statistics_work; + struct timer_list statistics_periodic; + +#ifdef CONFIG_IWLWIFI_HT_AGG + struct work_struct agg_work; +#endif + +#endif /* 4965 */ +}; /*iwl_priv */ + +#endif /* __iwl_priv_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h new file mode 100644 index 00000000000..0df41148ead --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -0,0 +1,229 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU Geeral Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +#ifndef __iwl_prph_h__ +#define __iwl_prph_h__ + + +#define PRPH_BASE (0x00000) +#define PRPH_END (0xFFFFF) + +/* APMG (power management) constants */ +#define APMG_BASE (PRPH_BASE + 0x3000) +#define APMG_CLK_CTRL_REG (APMG_BASE + 0x0000) +#define APMG_CLK_EN_REG (APMG_BASE + 0x0004) +#define APMG_CLK_DIS_REG (APMG_BASE + 0x0008) +#define APMG_PS_CTRL_REG (APMG_BASE + 0x000c) +#define APMG_PCIDEV_STT_REG (APMG_BASE + 0x0010) +#define APMG_RFKILL_REG (APMG_BASE + 0x0014) +#define APMG_RTC_INT_STT_REG (APMG_BASE + 0x001c) +#define APMG_RTC_INT_MSK_REG (APMG_BASE + 0x0020) + +#define APMG_CLK_VAL_DMA_CLK_RQT (0x00000200) +#define APMG_CLK_VAL_BSM_CLK_RQT (0x00000800) + +#define APMG_PS_CTRL_VAL_RESET_REQ (0x04000000) + +#define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800) + +#define APMG_PS_CTRL_MSK_PWR_SRC (0x03000000) +#define APMG_PS_CTRL_VAL_PWR_SRC_VMAIN (0x00000000) +#define APMG_PS_CTRL_VAL_PWR_SRC_VAUX (0x01000000) + + +/** + * BSM (Bootstrap State Machine) + * + * The Bootstrap State Machine (BSM) stores a short bootstrap uCode program + * in special SRAM that does not power down when the embedded control + * processor is sleeping (e.g. for periodic power-saving shutdowns of radio). + * + * When powering back up after sleeps (or during initial uCode load), the BSM + * internally loads the short bootstrap program from the special SRAM into the + * embedded processor's instruction SRAM, and starts the processor so it runs + * the bootstrap program. + * + * This bootstrap program loads (via PCI busmaster DMA) instructions and data + * images for a uCode program from host DRAM locations. The host driver + * indicates DRAM locations and sizes for instruction and data images via the + * four BSM_DRAM_* registers. Once the bootstrap program loads the new program, + * the new program starts automatically. + * + * The uCode used for open-source drivers includes two programs: + * + * 1) Initialization -- performs hardware calibration and sets up some + * internal data, then notifies host via "initialize alive" notification + * (struct iwl_init_alive_resp) that it has completed all of its work. + * After signal from host, it then loads and starts the runtime program. + * The initialization program must be used when initially setting up the + * NIC after loading the driver. + * + * 2) Runtime/Protocol -- performs all normal runtime operations. This + * notifies host via "alive" notification (struct iwl_alive_resp) that it + * is ready to be used. + * + * When initializing the NIC, the host driver does the following procedure: + * + * 1) Load bootstrap program (instructions only, no data image for bootstrap) + * into bootstrap memory. Use dword writes starting at BSM_SRAM_LOWER_BOUND + * + * 2) Point (via BSM_DRAM_*) to the "initialize" uCode data and instruction + * images in host DRAM. + * + * 3) Set up BSM to copy from BSM SRAM into uCode instruction SRAM when asked: + * BSM_WR_MEM_SRC_REG = 0 + * BSM_WR_MEM_DST_REG = RTC_INST_LOWER_BOUND + * BSM_WR_MEM_DWCOUNT_REG = # dwords in bootstrap instruction image + * + * 4) Load bootstrap into instruction SRAM: + * BSM_WR_CTRL_REG = BSM_WR_CTRL_REG_BIT_START + * + * 5) Wait for load completion: + * Poll BSM_WR_CTRL_REG for BSM_WR_CTRL_REG_BIT_START = 0 + * + * 6) Enable future boot loads whenever NIC's power management triggers it: + * BSM_WR_CTRL_REG = BSM_WR_CTRL_REG_BIT_START_EN + * + * 7) Start the NIC by removing all reset bits: + * CSR_RESET = 0 + * + * The bootstrap uCode (already in instruction SRAM) loads initialization + * uCode. Initialization uCode performs data initialization, sends + * "initialize alive" notification to host, and waits for a signal from + * host to load runtime code. + * + * 4) Point (via BSM_DRAM_*) to the "runtime" uCode data and instruction + * images in host DRAM. The last register loaded must be the instruction + * bytecount register ("1" in MSbit tells initialization uCode to load + * the runtime uCode): + * BSM_DRAM_INST_BYTECOUNT_REG = bytecount | BSM_DRAM_INST_LOAD + * + * 5) Wait for "alive" notification, then issue normal runtime commands. + * + * Data caching during power-downs: + * + * Just before the embedded controller powers down (e.g for automatic + * power-saving modes, or for RFKILL), uCode stores (via PCI busmaster DMA) + * a current snapshot of the embedded processor's data SRAM into host DRAM. + * This caches the data while the embedded processor's memory is powered down. + * Location and size are controlled by BSM_DRAM_DATA_* registers. + * + * NOTE: Instruction SRAM does not need to be saved, since that doesn't + * change during operation; the original image (from uCode distribution + * file) can be used for reload. + * + * When powering back up, the BSM loads the bootstrap program. Bootstrap looks + * at the BSM_DRAM_* registers, which now point to the runtime instruction + * image and the cached (modified) runtime data (*not* the initialization + * uCode). Bootstrap reloads these runtime images into SRAM, and restarts the + * uCode from where it left off before the power-down. + * + * NOTE: Initialization uCode does *not* run as part of the save/restore + * procedure. + * + * This save/restore method is mostly for autonomous power management during + * normal operation (result of POWER_TABLE_CMD). Platform suspend/resume and + * RFKILL should use complete restarts (with total re-initialization) of uCode, + * allowing total shutdown (including BSM memory). + * + * Note that, during normal operation, the host DRAM that held the initial + * startup data for the runtime code is now being used as a backup data cache + * for modified data! If you need to completely re-initialize the NIC, make + * sure that you use the runtime data image from the uCode distribution file, + * not the modified/saved runtime data. You may want to store a separate + * "clean" runtime data image in DRAM to avoid disk reads of distribution file. + */ + +/* BSM bit fields */ +#define BSM_WR_CTRL_REG_BIT_START (0x80000000) /* start boot load now */ +#define BSM_WR_CTRL_REG_BIT_START_EN (0x40000000) /* enable boot after pwrup*/ +#define BSM_DRAM_INST_LOAD (0x80000000) /* start program load now */ + +/* BSM addresses */ +#define BSM_BASE (PRPH_BASE + 0x3400) +#define BSM_END (PRPH_BASE + 0x3800) + +#define BSM_WR_CTRL_REG (BSM_BASE + 0x000) /* ctl and status */ +#define BSM_WR_MEM_SRC_REG (BSM_BASE + 0x004) /* source in BSM mem */ +#define BSM_WR_MEM_DST_REG (BSM_BASE + 0x008) /* dest in SRAM mem */ +#define BSM_WR_DWCOUNT_REG (BSM_BASE + 0x00C) /* bytes */ +#define BSM_WR_STATUS_REG (BSM_BASE + 0x010) /* bit 0: 1 == done */ + +/* + * Pointers and size regs for bootstrap load and data SRAM save/restore. + * NOTE: 3945 pointers use bits 31:0 of DRAM address. + * 4965 pointers use bits 35:4 of DRAM address. + */ +#define BSM_DRAM_INST_PTR_REG (BSM_BASE + 0x090) +#define BSM_DRAM_INST_BYTECOUNT_REG (BSM_BASE + 0x094) +#define BSM_DRAM_DATA_PTR_REG (BSM_BASE + 0x098) +#define BSM_DRAM_DATA_BYTECOUNT_REG (BSM_BASE + 0x09C) + +/* + * BSM special memory, stays powered on during power-save sleeps. + * Read/write, address range from LOWER_BOUND to (LOWER_BOUND + SIZE -1) + */ +#define BSM_SRAM_LOWER_BOUND (PRPH_BASE + 0x3800) +#define BSM_SRAM_SIZE (1024) /* bytes */ + + +#endif /* __iwl_prph_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-spectrum.h b/drivers/net/wireless/iwlwifi/iwl-spectrum.h new file mode 100644 index 00000000000..b576ff24eb4 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-spectrum.h @@ -0,0 +1,91 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ieee80211 subsystem header files. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#ifndef __iwl_spectrum_h__ +#define __iwl_spectrum_h__ +enum { /* ieee80211_basic_report.map */ + IEEE80211_BASIC_MAP_BSS = (1 << 0), + IEEE80211_BASIC_MAP_OFDM = (1 << 1), + IEEE80211_BASIC_MAP_UNIDENTIFIED = (1 << 2), + IEEE80211_BASIC_MAP_RADAR = (1 << 3), + IEEE80211_BASIC_MAP_UNMEASURED = (1 << 4), + /* Bits 5-7 are reserved */ + +}; +struct ieee80211_basic_report { + u8 channel; + __le64 start_time; + __le16 duration; + u8 map; +} __attribute__ ((packed)); + +enum { /* ieee80211_measurement_request.mode */ + /* Bit 0 is reserved */ + IEEE80211_MEASUREMENT_ENABLE = (1 << 1), + IEEE80211_MEASUREMENT_REQUEST = (1 << 2), + IEEE80211_MEASUREMENT_REPORT = (1 << 3), + /* Bits 4-7 are reserved */ +}; + +enum { + IEEE80211_REPORT_BASIC = 0, /* required */ + IEEE80211_REPORT_CCA = 1, /* optional */ + IEEE80211_REPORT_RPI = 2, /* optional */ + /* 3-255 reserved */ +}; + +struct ieee80211_measurement_params { + u8 channel; + __le64 start_time; + __le16 duration; +} __attribute__ ((packed)); + +struct ieee80211_info_element { + u8 id; + u8 len; + u8 data[0]; +} __attribute__ ((packed)); + +struct ieee80211_measurement_request { + struct ieee80211_info_element ie; + u8 token; + u8 mode; + u8 type; + struct ieee80211_measurement_params params[0]; +} __attribute__ ((packed)); + +struct ieee80211_measurement_report { + struct ieee80211_info_element ie; + u8 token; + u8 mode; + u8 type; + union { + struct ieee80211_basic_report basic[0]; + } u; +} __attribute__ ((packed)); +#endif diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c new file mode 100644 index 00000000000..474b6402040 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -0,0 +1,8732 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project, as well + * as portions of the ieee80211 subsystem header files. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +/* + * NOTE: This file (iwl-base.c) is used to build to multiple hardware targets + * by defining IWL to either 3945 or 4965. The Makefile used when building + * the base targets will create base-3945.o and base-4965.o + * + * The eventual goal is to move as many of the #if IWL / #endif blocks out of + * this file and into the hardware specific implementation files (iwl-XXXX.c) + * and leave only the common (non #ifdef sprinkled) code in this file + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "iwlwifi.h" +#include "iwl-3945.h" +#include "iwl-helpers.h" + +#ifdef CONFIG_IWLWIFI_DEBUG +u32 iwl_debug_level; +#endif + +/****************************************************************************** + * + * module boiler plate + * + ******************************************************************************/ + +/* module parameters */ +int iwl_param_disable_hw_scan; +int iwl_param_debug; +int iwl_param_disable; /* def: enable radio */ +int iwl_param_antenna; /* def: 0 = both antennas (use diversity) */ +int iwl_param_hwcrypto; /* def: using software encryption */ +int iwl_param_qos_enable = 1; +int iwl_param_queues_num = IWL_MAX_NUM_QUEUES; + +/* + * module name, copyright, version, etc. + * NOTE: DRV_NAME is defined in iwlwifi.h for use by iwl-debug.h and printk + */ + +#define DRV_DESCRIPTION \ +"Intel(R) PRO/Wireless 3945ABG/BG Network Connection driver for Linux" + +#ifdef CONFIG_IWLWIFI_DEBUG +#define VD "d" +#else +#define VD +#endif + +#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT +#define VS "s" +#else +#define VS +#endif + +#define IWLWIFI_VERSION "0.1.15k" VD VS +#define DRV_COPYRIGHT "Copyright(c) 2003-2007 Intel Corporation" +#define DRV_VERSION IWLWIFI_VERSION + +/* Change firmware file name, using "-" and incrementing number, + * *only* when uCode interface or architecture changes so that it + * is not compatible with earlier drivers. + * This number will also appear in << 8 position of 1st dword of uCode file */ +#define IWL3945_UCODE_API "-1" + +MODULE_DESCRIPTION(DRV_DESCRIPTION); +MODULE_VERSION(DRV_VERSION); +MODULE_AUTHOR(DRV_COPYRIGHT); +MODULE_LICENSE("GPL"); + +__le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr) +{ + u16 fc = le16_to_cpu(hdr->frame_control); + int hdr_len = ieee80211_get_hdrlen(fc); + + if ((fc & 0x00cc) == (IEEE80211_STYPE_QOS_DATA | IEEE80211_FTYPE_DATA)) + return (__le16 *) ((u8 *) hdr + hdr_len - QOS_CONTROL_LEN); + return NULL; +} + +static const struct ieee80211_hw_mode *iwl_get_hw_mode( + struct iwl_priv *priv, int mode) +{ + int i; + + for (i = 0; i < 3; i++) + if (priv->modes[i].mode == mode) + return &priv->modes[i]; + + return NULL; +} + +static int iwl_is_empty_essid(const char *essid, int essid_len) +{ + /* Single white space is for Linksys APs */ + if (essid_len == 1 && essid[0] == ' ') + return 1; + + /* Otherwise, if the entire essid is 0, we assume it is hidden */ + while (essid_len) { + essid_len--; + if (essid[essid_len] != '\0') + return 0; + } + + return 1; +} + +static const char *iwl_escape_essid(const char *essid, u8 essid_len) +{ + static char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; + const char *s = essid; + char *d = escaped; + + if (iwl_is_empty_essid(essid, essid_len)) { + memcpy(escaped, "", sizeof("")); + return escaped; + } + + essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE); + while (essid_len--) { + if (*s == '\0') { + *d++ = '\\'; + *d++ = '0'; + s++; + } else + *d++ = *s++; + } + *d = '\0'; + return escaped; +} + +static void iwl_print_hex_dump(int level, void *p, u32 len) +{ +#ifdef CONFIG_IWLWIFI_DEBUG + if (!(iwl_debug_level & level)) + return; + + print_hex_dump(KERN_DEBUG, "iwl data: ", DUMP_PREFIX_OFFSET, 16, 1, + p, len, 1); +#endif +} + +/*************** DMA-QUEUE-GENERAL-FUNCTIONS ***** + * DMA services + * + * Theory of operation + * + * A queue is a circular buffers with 'Read' and 'Write' pointers. + * 2 empty entries always kept in the buffer to protect from overflow. + * + * For Tx queue, there are low mark and high mark limits. If, after queuing + * the packet for Tx, free space become < low mark, Tx queue stopped. When + * reclaiming packets (on 'tx done IRQ), if free space become > high mark, + * Tx queue resumed. + * + * The IPW operates with six queues, one receive queue in the device's + * sram, one transmit queue for sending commands to the device firmware, + * and four transmit queues for data. + ***************************************************/ + +static int iwl_queue_space(const struct iwl_queue *q) +{ + int s = q->last_used - q->first_empty; + + if (q->last_used > q->first_empty) + s -= q->n_bd; + + if (s <= 0) + s += q->n_window; + /* keep some reserve to not confuse empty and full situations */ + s -= 2; + if (s < 0) + s = 0; + return s; +} + +/* XXX: n_bd must be power-of-two size */ +static inline int iwl_queue_inc_wrap(int index, int n_bd) +{ + return ++index & (n_bd - 1); +} + +/* XXX: n_bd must be power-of-two size */ +static inline int iwl_queue_dec_wrap(int index, int n_bd) +{ + return --index & (n_bd - 1); +} + +static inline int x2_queue_used(const struct iwl_queue *q, int i) +{ + return q->first_empty > q->last_used ? + (i >= q->last_used && i < q->first_empty) : + !(i < q->last_used && i >= q->first_empty); +} + +static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge) +{ + if (is_huge) + return q->n_window; + + return index & (q->n_window - 1); +} + +static int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q, + int count, int slots_num, u32 id) +{ + q->n_bd = count; + q->n_window = slots_num; + q->id = id; + + /* count must be power-of-two size, otherwise iwl_queue_inc_wrap + * and iwl_queue_dec_wrap are broken. */ + BUG_ON(!is_power_of_2(count)); + + /* slots_num must be power-of-two size, otherwise + * get_cmd_index is broken. */ + BUG_ON(!is_power_of_2(slots_num)); + + q->low_mark = q->n_window / 4; + if (q->low_mark < 4) + q->low_mark = 4; + + q->high_mark = q->n_window / 8; + if (q->high_mark < 2) + q->high_mark = 2; + + q->first_empty = q->last_used = 0; + + return 0; +} + +static int iwl_tx_queue_alloc(struct iwl_priv *priv, + struct iwl_tx_queue *txq, u32 id) +{ + struct pci_dev *dev = priv->pci_dev; + + if (id != IWL_CMD_QUEUE_NUM) { + txq->txb = kmalloc(sizeof(txq->txb[0]) * + TFD_QUEUE_SIZE_MAX, GFP_KERNEL); + if (!txq->txb) { + IWL_ERROR("kmalloc for auxilary BD " + "structures failed\n"); + goto error; + } + } else + txq->txb = NULL; + + txq->bd = pci_alloc_consistent(dev, + sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX, + &txq->q.dma_addr); + + if (!txq->bd) { + IWL_ERROR("pci_alloc_consistent(%zd) failed\n", + sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX); + goto error; + } + txq->q.id = id; + + return 0; + + error: + if (txq->txb) { + kfree(txq->txb); + txq->txb = NULL; + } + + return -ENOMEM; +} + +int iwl_tx_queue_init(struct iwl_priv *priv, + struct iwl_tx_queue *txq, int slots_num, u32 txq_id) +{ + struct pci_dev *dev = priv->pci_dev; + int len; + int rc = 0; + + /* alocate command space + one big command for scan since scan + * command is very huge the system will not have two scan at the + * same time */ + len = sizeof(struct iwl_cmd) * slots_num; + if (txq_id == IWL_CMD_QUEUE_NUM) + len += IWL_MAX_SCAN_SIZE; + txq->cmd = pci_alloc_consistent(dev, len, &txq->dma_addr_cmd); + if (!txq->cmd) + return -ENOMEM; + + rc = iwl_tx_queue_alloc(priv, txq, txq_id); + if (rc) { + pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd); + + return -ENOMEM; + } + txq->need_update = 0; + + /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise + * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */ + BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1)); + iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id); + + iwl_hw_tx_queue_init(priv, txq); + + return 0; +} + +/** + * iwl_tx_queue_free - Deallocate DMA queue. + * @txq: Transmit queue to deallocate. + * + * Empty queue by removing and destroying all BD's. + * Free all buffers. txq itself is not freed. + * + */ +void iwl_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq) +{ + struct iwl_queue *q = &txq->q; + struct pci_dev *dev = priv->pci_dev; + int len; + + if (q->n_bd == 0) + return; + + /* first, empty all BD's */ + for (; q->first_empty != q->last_used; + q->last_used = iwl_queue_inc_wrap(q->last_used, q->n_bd)) + iwl_hw_txq_free_tfd(priv, txq); + + len = sizeof(struct iwl_cmd) * q->n_window; + if (q->id == IWL_CMD_QUEUE_NUM) + len += IWL_MAX_SCAN_SIZE; + + pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd); + + /* free buffers belonging to queue itself */ + if (txq->q.n_bd) + pci_free_consistent(dev, sizeof(struct iwl_tfd_frame) * + txq->q.n_bd, txq->bd, txq->q.dma_addr); + + if (txq->txb) { + kfree(txq->txb); + txq->txb = NULL; + } + + /* 0 fill whole structure */ + memset(txq, 0, sizeof(*txq)); +} + +const u8 BROADCAST_ADDR[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + +/*************** STATION TABLE MANAGEMENT **** + * + * NOTE: This needs to be overhauled to better synchronize between + * how the iwl-4965.c is using iwl_hw_find_station vs. iwl-3945.c + * + * mac80211 should also be examined to determine if sta_info is duplicating + * the functionality provided here + */ + +/**************************************************************/ +static u8 iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap) +{ + int index = IWL_INVALID_STATION; + int i; + unsigned long flags; + + spin_lock_irqsave(&priv->sta_lock, flags); + + if (is_ap) + index = IWL_AP_ID; + else if (is_broadcast_ether_addr(addr)) + index = priv->hw_setting.bcast_sta_id; + else + for (i = IWL_STA_ID; i < priv->hw_setting.max_stations; i++) + if (priv->stations[i].used && + !compare_ether_addr(priv->stations[i].sta.sta.addr, + addr)) { + index = i; + break; + } + + if (unlikely(index == IWL_INVALID_STATION)) + goto out; + + if (priv->stations[index].used) { + priv->stations[index].used = 0; + priv->num_stations--; + } + + BUG_ON(priv->num_stations < 0); + +out: + spin_unlock_irqrestore(&priv->sta_lock, flags); + return 0; +} + +static void iwl_clear_stations_table(struct iwl_priv *priv) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->sta_lock, flags); + + priv->num_stations = 0; + memset(priv->stations, 0, sizeof(priv->stations)); + + spin_unlock_irqrestore(&priv->sta_lock, flags); +} + + +u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags) +{ + int i; + int index = IWL_INVALID_STATION; + struct iwl_station_entry *station; + unsigned long flags_spin; + + spin_lock_irqsave(&priv->sta_lock, flags_spin); + if (is_ap) + index = IWL_AP_ID; + else if (is_broadcast_ether_addr(addr)) + index = priv->hw_setting.bcast_sta_id; + else + for (i = IWL_STA_ID; i < priv->hw_setting.max_stations; i++) { + if (!compare_ether_addr(priv->stations[i].sta.sta.addr, + addr)) { + index = i; + break; + } + + if (!priv->stations[i].used && + index == IWL_INVALID_STATION) + index = i; + } + + /* These twh conditions has the same outcome but keep them separate + since they have different meaning */ + if (unlikely(index == IWL_INVALID_STATION)) { + spin_unlock_irqrestore(&priv->sta_lock, flags_spin); + return index; + } + + if (priv->stations[index].used && + !compare_ether_addr(priv->stations[index].sta.sta.addr, addr)) { + spin_unlock_irqrestore(&priv->sta_lock, flags_spin); + return index; + } + + IWL_DEBUG_ASSOC("Add STA ID %d: " MAC_FMT "\n", index, MAC_ARG(addr)); + station = &priv->stations[index]; + station->used = 1; + priv->num_stations++; + + memset(&station->sta, 0, sizeof(struct iwl_addsta_cmd)); + memcpy(station->sta.sta.addr, addr, ETH_ALEN); + station->sta.mode = 0; + station->sta.sta.sta_id = index; + station->sta.station_flags = 0; + + spin_unlock_irqrestore(&priv->sta_lock, flags_spin); + iwl_send_add_station(priv, &station->sta, flags); + return index; + +} + +/*************** DRIVER STATUS FUNCTIONS *****/ + +static inline int iwl_is_ready(struct iwl_priv *priv) +{ + /* The adapter is 'ready' if READY and GEO_CONFIGURED bits are + * set but EXIT_PENDING is not */ + return test_bit(STATUS_READY, &priv->status) && + test_bit(STATUS_GEO_CONFIGURED, &priv->status) && + !test_bit(STATUS_EXIT_PENDING, &priv->status); +} + +static inline int iwl_is_alive(struct iwl_priv *priv) +{ + return test_bit(STATUS_ALIVE, &priv->status); +} + +static inline int iwl_is_init(struct iwl_priv *priv) +{ + return test_bit(STATUS_INIT, &priv->status); +} + +static inline int iwl_is_rfkill(struct iwl_priv *priv) +{ + return test_bit(STATUS_RF_KILL_HW, &priv->status) || + test_bit(STATUS_RF_KILL_SW, &priv->status); +} + +static inline int iwl_is_ready_rf(struct iwl_priv *priv) +{ + + if (iwl_is_rfkill(priv)) + return 0; + + return iwl_is_ready(priv); +} + +/*************** HOST COMMAND QUEUE FUNCTIONS *****/ + +#define IWL_CMD(x) case x : return #x + +static const char *get_cmd_string(u8 cmd) +{ + switch (cmd) { + IWL_CMD(REPLY_ALIVE); + IWL_CMD(REPLY_ERROR); + IWL_CMD(REPLY_RXON); + IWL_CMD(REPLY_RXON_ASSOC); + IWL_CMD(REPLY_QOS_PARAM); + IWL_CMD(REPLY_RXON_TIMING); + IWL_CMD(REPLY_ADD_STA); + IWL_CMD(REPLY_REMOVE_STA); + IWL_CMD(REPLY_REMOVE_ALL_STA); + IWL_CMD(REPLY_3945_RX); + IWL_CMD(REPLY_TX); + IWL_CMD(REPLY_RATE_SCALE); + IWL_CMD(REPLY_LEDS_CMD); + IWL_CMD(REPLY_TX_LINK_QUALITY_CMD); + IWL_CMD(RADAR_NOTIFICATION); + IWL_CMD(REPLY_QUIET_CMD); + IWL_CMD(REPLY_CHANNEL_SWITCH); + IWL_CMD(CHANNEL_SWITCH_NOTIFICATION); + IWL_CMD(REPLY_SPECTRUM_MEASUREMENT_CMD); + IWL_CMD(SPECTRUM_MEASURE_NOTIFICATION); + IWL_CMD(POWER_TABLE_CMD); + IWL_CMD(PM_SLEEP_NOTIFICATION); + IWL_CMD(PM_DEBUG_STATISTIC_NOTIFIC); + IWL_CMD(REPLY_SCAN_CMD); + IWL_CMD(REPLY_SCAN_ABORT_CMD); + IWL_CMD(SCAN_START_NOTIFICATION); + IWL_CMD(SCAN_RESULTS_NOTIFICATION); + IWL_CMD(SCAN_COMPLETE_NOTIFICATION); + IWL_CMD(BEACON_NOTIFICATION); + IWL_CMD(REPLY_TX_BEACON); + IWL_CMD(WHO_IS_AWAKE_NOTIFICATION); + IWL_CMD(QUIET_NOTIFICATION); + IWL_CMD(REPLY_TX_PWR_TABLE_CMD); + IWL_CMD(MEASURE_ABORT_NOTIFICATION); + IWL_CMD(REPLY_BT_CONFIG); + IWL_CMD(REPLY_STATISTICS_CMD); + IWL_CMD(STATISTICS_NOTIFICATION); + IWL_CMD(REPLY_CARD_STATE_CMD); + IWL_CMD(CARD_STATE_NOTIFICATION); + IWL_CMD(MISSED_BEACONS_NOTIFICATION); + default: + return "UNKNOWN"; + + } +} + +#define HOST_COMPLETE_TIMEOUT (HZ / 2) + +/** + * iwl_enqueue_hcmd - enqueue a uCode command + * @priv: device private data point + * @cmd: a point to the ucode command structure + * + * The function returns < 0 values to indicate the operation is + * failed. On success, it turns the index (> 0) of command in the + * command queue. + */ +static int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) +{ + struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM]; + struct iwl_queue *q = &txq->q; + struct iwl_tfd_frame *tfd; + u32 *control_flags; + struct iwl_cmd *out_cmd; + u32 idx; + u16 fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr)); + dma_addr_t phys_addr; + int pad; + u16 count; + int ret; + unsigned long flags; + + /* If any of the command structures end up being larger than + * the TFD_MAX_PAYLOAD_SIZE, and it sent as a 'small' command then + * we will need to increase the size of the TFD entries */ + BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) && + !(cmd->meta.flags & CMD_SIZE_HUGE)); + + if (iwl_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) { + IWL_ERROR("No space for Tx\n"); + return -ENOSPC; + } + + spin_lock_irqsave(&priv->hcmd_lock, flags); + + tfd = &txq->bd[q->first_empty]; + memset(tfd, 0, sizeof(*tfd)); + + control_flags = (u32 *) tfd; + + idx = get_cmd_index(q, q->first_empty, cmd->meta.flags & CMD_SIZE_HUGE); + out_cmd = &txq->cmd[idx]; + + out_cmd->hdr.cmd = cmd->id; + memcpy(&out_cmd->meta, &cmd->meta, sizeof(cmd->meta)); + memcpy(&out_cmd->cmd.payload, cmd->data, cmd->len); + + /* At this point, the out_cmd now has all of the incoming cmd + * information */ + + out_cmd->hdr.flags = 0; + out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(IWL_CMD_QUEUE_NUM) | + INDEX_TO_SEQ(q->first_empty)); + if (out_cmd->meta.flags & CMD_SIZE_HUGE) + out_cmd->hdr.sequence |= cpu_to_le16(SEQ_HUGE_FRAME); + + phys_addr = txq->dma_addr_cmd + sizeof(txq->cmd[0]) * idx + + offsetof(struct iwl_cmd, hdr); + iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size); + + pad = U32_PAD(cmd->len); + count = TFD_CTL_COUNT_GET(*control_flags); + *control_flags = TFD_CTL_COUNT_SET(count) | TFD_CTL_PAD_SET(pad); + + IWL_DEBUG_HC("Sending command %s (#%x), seq: 0x%04X, " + "%d bytes at %d[%d]:%d\n", + get_cmd_string(out_cmd->hdr.cmd), + out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence), + fix_size, q->first_empty, idx, IWL_CMD_QUEUE_NUM); + + txq->need_update = 1; + q->first_empty = iwl_queue_inc_wrap(q->first_empty, q->n_bd); + ret = iwl_tx_queue_update_write_ptr(priv, txq); + + spin_unlock_irqrestore(&priv->hcmd_lock, flags); + return ret ? ret : idx; +} + +int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd) +{ + int ret; + + BUG_ON(!(cmd->meta.flags & CMD_ASYNC)); + + /* An asynchronous command can not expect an SKB to be set. */ + BUG_ON(cmd->meta.flags & CMD_WANT_SKB); + + /* An asynchronous command MUST have a callback. */ + BUG_ON(!cmd->meta.u.callback); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return -EBUSY; + + ret = iwl_enqueue_hcmd(priv, cmd); + if (ret < 0) { + IWL_ERROR("Error sending %s: iwl_enqueue_hcmd failed: %d\n", + get_cmd_string(cmd->id), ret); + return ret; + } + return 0; +} + +int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) +{ + int cmd_idx; + int ret; + static atomic_t entry = ATOMIC_INIT(0); /* reentrance protection */ + + BUG_ON(cmd->meta.flags & CMD_ASYNC); + + /* A synchronous command can not have a callback set. */ + BUG_ON(cmd->meta.u.callback != NULL); + + if (atomic_xchg(&entry, 1)) { + IWL_ERROR("Error sending %s: Already sending a host command\n", + get_cmd_string(cmd->id)); + return -EBUSY; + } + + set_bit(STATUS_HCMD_ACTIVE, &priv->status); + + if (cmd->meta.flags & CMD_WANT_SKB) + cmd->meta.source = &cmd->meta; + + cmd_idx = iwl_enqueue_hcmd(priv, cmd); + if (cmd_idx < 0) { + ret = cmd_idx; + IWL_ERROR("Error sending %s: iwl_enqueue_hcmd failed: %d\n", + get_cmd_string(cmd->id), ret); + goto out; + } + + ret = wait_event_interruptible_timeout(priv->wait_command_queue, + !test_bit(STATUS_HCMD_ACTIVE, &priv->status), + HOST_COMPLETE_TIMEOUT); + if (!ret) { + if (test_bit(STATUS_HCMD_ACTIVE, &priv->status)) { + IWL_ERROR("Error sending %s: time out after %dms.\n", + get_cmd_string(cmd->id), + jiffies_to_msecs(HOST_COMPLETE_TIMEOUT)); + + clear_bit(STATUS_HCMD_ACTIVE, &priv->status); + ret = -ETIMEDOUT; + goto cancel; + } + } + + if (test_bit(STATUS_RF_KILL_HW, &priv->status)) { + IWL_DEBUG_INFO("Command %s aborted: RF KILL Switch\n", + get_cmd_string(cmd->id)); + ret = -ECANCELED; + goto fail; + } + if (test_bit(STATUS_FW_ERROR, &priv->status)) { + IWL_DEBUG_INFO("Command %s failed: FW Error\n", + get_cmd_string(cmd->id)); + ret = -EIO; + goto fail; + } + if ((cmd->meta.flags & CMD_WANT_SKB) && !cmd->meta.u.skb) { + IWL_ERROR("Error: Response NULL in '%s'\n", + get_cmd_string(cmd->id)); + ret = -EIO; + goto out; + } + + ret = 0; + goto out; + +cancel: + if (cmd->meta.flags & CMD_WANT_SKB) { + struct iwl_cmd *qcmd; + + /* Cancel the CMD_WANT_SKB flag for the cmd in the + * TX cmd queue. Otherwise in case the cmd comes + * in later, it will possibly set an invalid + * address (cmd->meta.source). */ + qcmd = &priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_idx]; + qcmd->meta.flags &= ~CMD_WANT_SKB; + } +fail: + if (cmd->meta.u.skb) { + dev_kfree_skb_any(cmd->meta.u.skb); + cmd->meta.u.skb = NULL; + } +out: + atomic_set(&entry, 0); + return ret; +} + +int iwl_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) +{ + /* A command can not be asynchronous AND expect an SKB to be set. */ + BUG_ON((cmd->meta.flags & CMD_ASYNC) && + (cmd->meta.flags & CMD_WANT_SKB)); + + if (cmd->meta.flags & CMD_ASYNC) + return iwl_send_cmd_async(priv, cmd); + + return iwl_send_cmd_sync(priv, cmd); +} + +int iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u16 len, const void *data) +{ + struct iwl_host_cmd cmd = { + .id = id, + .len = len, + .data = data, + }; + + return iwl_send_cmd_sync(priv, &cmd); +} + +static int __must_check iwl_send_cmd_u32(struct iwl_priv *priv, u8 id, u32 val) +{ + struct iwl_host_cmd cmd = { + .id = id, + .len = sizeof(val), + .data = &val, + }; + + return iwl_send_cmd_sync(priv, &cmd); +} + +int iwl_send_statistics_request(struct iwl_priv *priv) +{ + return iwl_send_cmd_u32(priv, REPLY_STATISTICS_CMD, 0); +} + +/** + * iwl_rxon_add_station - add station into station table. + * + * there is only one AP station with id= IWL_AP_ID + * NOTE: mutex must be held before calling the this fnction +*/ +static int iwl_rxon_add_station(struct iwl_priv *priv, + const u8 *addr, int is_ap) +{ + u8 rc; + + /* Remove this station if it happens to already exist */ + iwl_remove_station(priv, addr, is_ap); + + rc = iwl_add_station(priv, addr, is_ap, 0); + + return rc; +} + +/** + * iwl_set_rxon_channel - Set the phymode and channel values in staging RXON + * @phymode: MODE_IEEE80211A sets to 5.2GHz; all else set to 2.4GHz + * @channel: Any channel valid for the requested phymode + + * In addition to setting the staging RXON, priv->phymode is also set. + * + * NOTE: Does not commit to the hardware; it sets appropriate bit fields + * in the staging RXON flag structure based on the phymode + */ +static int iwl_set_rxon_channel(struct iwl_priv *priv, u8 phymode, u16 channel) +{ + if (!iwl_get_channel_info(priv, phymode, channel)) { + IWL_DEBUG_INFO("Could not set channel to %d [%d]\n", + channel, phymode); + return -EINVAL; + } + + if ((le16_to_cpu(priv->staging_rxon.channel) == channel) && + (priv->phymode == phymode)) + return 0; + + priv->staging_rxon.channel = cpu_to_le16(channel); + if (phymode == MODE_IEEE80211A) + priv->staging_rxon.flags &= ~RXON_FLG_BAND_24G_MSK; + else + priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK; + + priv->phymode = phymode; + + IWL_DEBUG_INFO("Staging channel set to %d [%d]\n", channel, phymode); + + return 0; +} + +/** + * iwl_check_rxon_cmd - validate RXON structure is valid + * + * NOTE: This is really only useful during development and can eventually + * be #ifdef'd out once the driver is stable and folks aren't actively + * making changes + */ +static int iwl_check_rxon_cmd(struct iwl_rxon_cmd *rxon) +{ + int error = 0; + int counter = 1; + + if (rxon->flags & RXON_FLG_BAND_24G_MSK) { + error |= le32_to_cpu(rxon->flags & + (RXON_FLG_TGJ_NARROW_BAND_MSK | + RXON_FLG_RADAR_DETECT_MSK)); + if (error) + IWL_WARNING("check 24G fields %d | %d\n", + counter++, error); + } else { + error |= (rxon->flags & RXON_FLG_SHORT_SLOT_MSK) ? + 0 : le32_to_cpu(RXON_FLG_SHORT_SLOT_MSK); + if (error) + IWL_WARNING("check 52 fields %d | %d\n", + counter++, error); + error |= le32_to_cpu(rxon->flags & RXON_FLG_CCK_MSK); + if (error) + IWL_WARNING("check 52 CCK %d | %d\n", + counter++, error); + } + error |= (rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1; + if (error) + IWL_WARNING("check mac addr %d | %d\n", counter++, error); + + /* make sure basic rates 6Mbps and 1Mbps are supported */ + error |= (((rxon->ofdm_basic_rates & IWL_RATE_6M_MASK) == 0) && + ((rxon->cck_basic_rates & IWL_RATE_1M_MASK) == 0)); + if (error) + IWL_WARNING("check basic rate %d | %d\n", counter++, error); + + error |= (le16_to_cpu(rxon->assoc_id) > 2007); + if (error) + IWL_WARNING("check assoc id %d | %d\n", counter++, error); + + error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)) + == (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)); + if (error) + IWL_WARNING("check CCK and short slot %d | %d\n", + counter++, error); + + error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)) + == (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)); + if (error) + IWL_WARNING("check CCK & auto detect %d | %d\n", + counter++, error); + + error |= ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK | + RXON_FLG_TGG_PROTECT_MSK)) == RXON_FLG_TGG_PROTECT_MSK); + if (error) + IWL_WARNING("check TGG and auto detect %d | %d\n", + counter++, error); + + if ((rxon->flags & RXON_FLG_DIS_DIV_MSK)) + error |= ((rxon->flags & (RXON_FLG_ANT_B_MSK | + RXON_FLG_ANT_A_MSK)) == 0); + if (error) + IWL_WARNING("check antenna %d %d\n", counter++, error); + + if (error) + IWL_WARNING("Tuning to channel %d\n", + le16_to_cpu(rxon->channel)); + + if (error) { + IWL_ERROR("Not a valid iwl_rxon_assoc_cmd field values\n"); + return -1; + } + return 0; +} + +/** + * iwl_full_rxon_required - determine if RXON_ASSOC can be used in RXON commit + * @priv: staging_rxon is comapred to active_rxon + * + * If the RXON structure is changing sufficient to require a new + * tune or to clear and reset the RXON_FILTER_ASSOC_MSK then return 1 + * to indicate a new tune is required. + */ +static int iwl_full_rxon_required(struct iwl_priv *priv) +{ + + /* These items are only settable from the full RXON command */ + if (!(priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) || + compare_ether_addr(priv->staging_rxon.bssid_addr, + priv->active_rxon.bssid_addr) || + compare_ether_addr(priv->staging_rxon.node_addr, + priv->active_rxon.node_addr) || + compare_ether_addr(priv->staging_rxon.wlap_bssid_addr, + priv->active_rxon.wlap_bssid_addr) || + (priv->staging_rxon.dev_type != priv->active_rxon.dev_type) || + (priv->staging_rxon.channel != priv->active_rxon.channel) || + (priv->staging_rxon.air_propagation != + priv->active_rxon.air_propagation) || + (priv->staging_rxon.assoc_id != priv->active_rxon.assoc_id)) + return 1; + + /* flags, filter_flags, ofdm_basic_rates, and cck_basic_rates can + * be updated with the RXON_ASSOC command -- however only some + * flag transitions are allowed using RXON_ASSOC */ + + /* Check if we are not switching bands */ + if ((priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) != + (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK)) + return 1; + + /* Check if we are switching association toggle */ + if ((priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) != + (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK)) + return 1; + + return 0; +} + +static int iwl_send_rxon_assoc(struct iwl_priv *priv) +{ + int rc = 0; + struct iwl_rx_packet *res = NULL; + struct iwl_rxon_assoc_cmd rxon_assoc; + struct iwl_host_cmd cmd = { + .id = REPLY_RXON_ASSOC, + .len = sizeof(rxon_assoc), + .meta.flags = CMD_WANT_SKB, + .data = &rxon_assoc, + }; + const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon; + const struct iwl_rxon_cmd *rxon2 = &priv->active_rxon; + + if ((rxon1->flags == rxon2->flags) && + (rxon1->filter_flags == rxon2->filter_flags) && + (rxon1->cck_basic_rates == rxon2->cck_basic_rates) && + (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) { + IWL_DEBUG_INFO("Using current RXON_ASSOC. Not resending.\n"); + return 0; + } + + rxon_assoc.flags = priv->staging_rxon.flags; + rxon_assoc.filter_flags = priv->staging_rxon.filter_flags; + rxon_assoc.ofdm_basic_rates = priv->staging_rxon.ofdm_basic_rates; + rxon_assoc.cck_basic_rates = priv->staging_rxon.cck_basic_rates; + rxon_assoc.reserved = 0; + + rc = iwl_send_cmd_sync(priv, &cmd); + if (rc) + return rc; + + res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; + if (res->hdr.flags & IWL_CMD_FAILED_MSK) { + IWL_ERROR("Bad return from REPLY_RXON_ASSOC command\n"); + rc = -EIO; + } + + priv->alloc_rxb_skb--; + dev_kfree_skb_any(cmd.meta.u.skb); + + return rc; +} + +/** + * iwl_commit_rxon - commit staging_rxon to hardware + * + * The RXON command in staging_rxon is commited to the hardware and + * the active_rxon structure is updated with the new data. This + * function correctly transitions out of the RXON_ASSOC_MSK state if + * a HW tune is required based on the RXON structure changes. + */ +static int iwl_commit_rxon(struct iwl_priv *priv) +{ + /* cast away the const for active_rxon in this function */ + struct iwl_rxon_cmd *active_rxon = (void *)&priv->active_rxon; + int rc = 0; + + if (!iwl_is_alive(priv)) + return -1; + + /* always get timestamp with Rx frame */ + priv->staging_rxon.flags |= RXON_FLG_TSF2HOST_MSK; + + /* select antenna */ + priv->staging_rxon.flags &= + ~(RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_SEL_MSK); + priv->staging_rxon.flags |= iwl3945_get_antenna_flags(priv); + + rc = iwl_check_rxon_cmd(&priv->staging_rxon); + if (rc) { + IWL_ERROR("Invalid RXON configuration. Not committing.\n"); + return -EINVAL; + } + + /* If we don't need to send a full RXON, we can use + * iwl_rxon_assoc_cmd which is used to reconfigure filter + * and other flags for the current radio configuration. */ + if (!iwl_full_rxon_required(priv)) { + rc = iwl_send_rxon_assoc(priv); + if (rc) { + IWL_ERROR("Error setting RXON_ASSOC " + "configuration (%d).\n", rc); + return rc; + } + + memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); + + return 0; + } + + /* If we are currently associated and the new config requires + * an RXON_ASSOC and the new config wants the associated mask enabled, + * we must clear the associated from the active configuration + * before we apply the new config */ + if (iwl_is_associated(priv) && + (priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK)) { + IWL_DEBUG_INFO("Toggling associated bit on current RXON\n"); + active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; + + rc = iwl_send_cmd_pdu(priv, REPLY_RXON, + sizeof(struct iwl_rxon_cmd), + &priv->active_rxon); + + /* If the mask clearing failed then we set + * active_rxon back to what it was previously */ + if (rc) { + active_rxon->filter_flags |= RXON_FILTER_ASSOC_MSK; + IWL_ERROR("Error clearing ASSOC_MSK on current " + "configuration (%d).\n", rc); + return rc; + } + + /* The RXON bit toggling will have cleared out the + * station table in the uCode, so blank it in the driver + * as well */ + iwl_clear_stations_table(priv); + } else if (priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) { + /* When switching from non-associated to associated, the + * uCode clears out the station table; so clear it in the + * driver as well */ + iwl_clear_stations_table(priv); + } + + IWL_DEBUG_INFO("Sending RXON\n" + "* with%s RXON_FILTER_ASSOC_MSK\n" + "* channel = %d\n" + "* bssid = " MAC_FMT "\n", + ((priv->staging_rxon.filter_flags & + RXON_FILTER_ASSOC_MSK) ? "" : "out"), + le16_to_cpu(priv->staging_rxon.channel), + MAC_ARG(priv->staging_rxon.bssid_addr)); + + /* Apply the new configuration */ + rc = iwl_send_cmd_pdu(priv, REPLY_RXON, + sizeof(struct iwl_rxon_cmd), &priv->staging_rxon); + if (rc) { + IWL_ERROR("Error setting new configuration (%d).\n", rc); + return rc; + } + + memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); + + /* If we issue a new RXON command which required a tune then we must + * send a new TXPOWER command or we won't be able to Tx any frames */ + rc = iwl_hw_reg_send_txpower(priv); + if (rc) { + IWL_ERROR("Error setting Tx power (%d).\n", rc); + return rc; + } + + /* Add the broadcast address so we can send broadcast frames */ + if (iwl_rxon_add_station(priv, BROADCAST_ADDR, 0) == + IWL_INVALID_STATION) { + IWL_ERROR("Error adding BROADCAST address for transmit.\n"); + return -EIO; + } + + /* If we have set the ASSOC_MSK and we are in BSS mode then + * add the IWL_AP_ID to the station rate table */ + if (iwl_is_associated(priv) && + (priv->iw_mode == IEEE80211_IF_TYPE_STA)) + if (iwl_rxon_add_station(priv, priv->active_rxon.bssid_addr, 1) + == IWL_INVALID_STATION) { + IWL_ERROR("Error adding AP address for transmit.\n"); + return -EIO; + } + + /* Init the hardware's rate fallback order based on the + * phymode */ + rc = iwl3945_init_hw_rate_table(priv); + if (rc) { + IWL_ERROR("Error setting HW rate table: %02X\n", rc); + return -EIO; + } + + return 0; +} + +static int iwl_send_bt_config(struct iwl_priv *priv) +{ + struct iwl_bt_cmd bt_cmd = { + .flags = 3, + .lead_time = 0xAA, + .max_kill = 1, + .kill_ack_mask = 0, + .kill_cts_mask = 0, + }; + + return iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG, + sizeof(struct iwl_bt_cmd), &bt_cmd); +} + +static int iwl_send_scan_abort(struct iwl_priv *priv) +{ + int rc = 0; + struct iwl_rx_packet *res; + struct iwl_host_cmd cmd = { + .id = REPLY_SCAN_ABORT_CMD, + .meta.flags = CMD_WANT_SKB, + }; + + /* If there isn't a scan actively going on in the hardware + * then we are in between scan bands and not actually + * actively scanning, so don't send the abort command */ + if (!test_bit(STATUS_SCAN_HW, &priv->status)) { + clear_bit(STATUS_SCAN_ABORTING, &priv->status); + return 0; + } + + rc = iwl_send_cmd_sync(priv, &cmd); + if (rc) { + clear_bit(STATUS_SCAN_ABORTING, &priv->status); + return rc; + } + + res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; + if (res->u.status != CAN_ABORT_STATUS) { + /* The scan abort will return 1 for success or + * 2 for "failure". A failure condition can be + * due to simply not being in an active scan which + * can occur if we send the scan abort before we + * the microcode has notified us that a scan is + * completed. */ + IWL_DEBUG_INFO("SCAN_ABORT returned %d.\n", res->u.status); + clear_bit(STATUS_SCAN_ABORTING, &priv->status); + clear_bit(STATUS_SCAN_HW, &priv->status); + } + + dev_kfree_skb_any(cmd.meta.u.skb); + + return rc; +} + +static int iwl_card_state_sync_callback(struct iwl_priv *priv, + struct iwl_cmd *cmd, + struct sk_buff *skb) +{ + return 1; +} + +/* + * CARD_STATE_CMD + * + * Use: Sets the internal card state to enable, disable, or halt + * + * When in the 'enable' state the card operates as normal. + * When in the 'disable' state, the card enters into a low power mode. + * When in the 'halt' state, the card is shut down and must be fully + * restarted to come back on. + */ +static int iwl_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag) +{ + struct iwl_host_cmd cmd = { + .id = REPLY_CARD_STATE_CMD, + .len = sizeof(u32), + .data = &flags, + .meta.flags = meta_flag, + }; + + if (meta_flag & CMD_ASYNC) + cmd.meta.u.callback = iwl_card_state_sync_callback; + + return iwl_send_cmd(priv, &cmd); +} + +static int iwl_add_sta_sync_callback(struct iwl_priv *priv, + struct iwl_cmd *cmd, struct sk_buff *skb) +{ + struct iwl_rx_packet *res = NULL; + + if (!skb) { + IWL_ERROR("Error: Response NULL in REPLY_ADD_STA.\n"); + return 1; + } + + res = (struct iwl_rx_packet *)skb->data; + if (res->hdr.flags & IWL_CMD_FAILED_MSK) { + IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n", + res->hdr.flags); + return 1; + } + + switch (res->u.add_sta.status) { + case ADD_STA_SUCCESS_MSK: + break; + default: + break; + } + + /* We didn't cache the SKB; let the caller free it */ + return 1; +} + +int iwl_send_add_station(struct iwl_priv *priv, + struct iwl_addsta_cmd *sta, u8 flags) +{ + struct iwl_rx_packet *res = NULL; + int rc = 0; + struct iwl_host_cmd cmd = { + .id = REPLY_ADD_STA, + .len = sizeof(struct iwl_addsta_cmd), + .meta.flags = flags, + .data = sta, + }; + + if (flags & CMD_ASYNC) + cmd.meta.u.callback = iwl_add_sta_sync_callback; + else + cmd.meta.flags |= CMD_WANT_SKB; + + rc = iwl_send_cmd(priv, &cmd); + + if (rc || (flags & CMD_ASYNC)) + return rc; + + res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; + if (res->hdr.flags & IWL_CMD_FAILED_MSK) { + IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n", + res->hdr.flags); + rc = -EIO; + } + + if (rc == 0) { + switch (res->u.add_sta.status) { + case ADD_STA_SUCCESS_MSK: + IWL_DEBUG_INFO("REPLY_ADD_STA PASSED\n"); + break; + default: + rc = -EIO; + IWL_WARNING("REPLY_ADD_STA failed\n"); + break; + } + } + + priv->alloc_rxb_skb--; + dev_kfree_skb_any(cmd.meta.u.skb); + + return rc; +} + +static int iwl_update_sta_key_info(struct iwl_priv *priv, + struct ieee80211_key_conf *keyconf, + u8 sta_id) +{ + unsigned long flags; + __le16 key_flags = 0; + + switch (keyconf->alg) { + case ALG_CCMP: + key_flags |= STA_KEY_FLG_CCMP; + key_flags |= cpu_to_le16( + keyconf->keyidx << STA_KEY_FLG_KEYID_POS); + key_flags &= ~STA_KEY_FLG_INVALID; + break; + case ALG_TKIP: + case ALG_WEP: + return -EINVAL; + default: + return -EINVAL; + } + spin_lock_irqsave(&priv->sta_lock, flags); + priv->stations[sta_id].keyinfo.alg = keyconf->alg; + priv->stations[sta_id].keyinfo.keylen = keyconf->keylen; + memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key, + keyconf->keylen); + + memcpy(priv->stations[sta_id].sta.key.key, keyconf->key, + keyconf->keylen); + priv->stations[sta_id].sta.key.key_flags = key_flags; + priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + + spin_unlock_irqrestore(&priv->sta_lock, flags); + + IWL_DEBUG_INFO("hwcrypto: modify ucode station key info\n"); + iwl_send_add_station(priv, &priv->stations[sta_id].sta, 0); + return 0; +} + +static int iwl_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->sta_lock, flags); + memset(&priv->stations[sta_id].keyinfo, 0, sizeof(struct iwl_hw_key)); + memset(&priv->stations[sta_id].sta.key, 0, sizeof(struct iwl_keyinfo)); + priv->stations[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC; + priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + spin_unlock_irqrestore(&priv->sta_lock, flags); + + IWL_DEBUG_INFO("hwcrypto: clear ucode station key info\n"); + iwl_send_add_station(priv, &priv->stations[sta_id].sta, 0); + return 0; +} + +static void iwl_clear_free_frames(struct iwl_priv *priv) +{ + struct list_head *element; + + IWL_DEBUG_INFO("%d frames on pre-allocated heap on clear.\n", + priv->frames_count); + + while (!list_empty(&priv->free_frames)) { + element = priv->free_frames.next; + list_del(element); + kfree(list_entry(element, struct iwl_frame, list)); + priv->frames_count--; + } + + if (priv->frames_count) { + IWL_WARNING("%d frames still in use. Did we lose one?\n", + priv->frames_count); + priv->frames_count = 0; + } +} + +static struct iwl_frame *iwl_get_free_frame(struct iwl_priv *priv) +{ + struct iwl_frame *frame; + struct list_head *element; + if (list_empty(&priv->free_frames)) { + frame = kzalloc(sizeof(*frame), GFP_KERNEL); + if (!frame) { + IWL_ERROR("Could not allocate frame!\n"); + return NULL; + } + + priv->frames_count++; + return frame; + } + + element = priv->free_frames.next; + list_del(element); + return list_entry(element, struct iwl_frame, list); +} + +static void iwl_free_frame(struct iwl_priv *priv, struct iwl_frame *frame) +{ + memset(frame, 0, sizeof(*frame)); + list_add(&frame->list, &priv->free_frames); +} + +unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv, + struct ieee80211_hdr *hdr, + const u8 *dest, int left) +{ + + if (!iwl_is_associated(priv) || !priv->ibss_beacon || + ((priv->iw_mode != IEEE80211_IF_TYPE_IBSS) && + (priv->iw_mode != IEEE80211_IF_TYPE_AP))) + return 0; + + if (priv->ibss_beacon->len > left) + return 0; + + memcpy(hdr, priv->ibss_beacon->data, priv->ibss_beacon->len); + + return priv->ibss_beacon->len; +} + +static int iwl_rate_index_from_plcp(int plcp) +{ + int i = 0; + + for (i = 0; i < IWL_RATE_COUNT; i++) + if (iwl_rates[i].plcp == plcp) + return i; + return -1; +} + +static u8 iwl_rate_get_lowest_plcp(int rate_mask) +{ + u8 i; + + for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID; + i = iwl_rates[i].next_ieee) { + if (rate_mask & (1 << i)) + return iwl_rates[i].plcp; + } + + return IWL_RATE_INVALID; +} + +static int iwl_send_beacon_cmd(struct iwl_priv *priv) +{ + struct iwl_frame *frame; + unsigned int frame_size; + int rc; + u8 rate; + + frame = iwl_get_free_frame(priv); + + if (!frame) { + IWL_ERROR("Could not obtain free frame buffer for beacon " + "command.\n"); + return -ENOMEM; + } + + if (!(priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK)) { + rate = iwl_rate_get_lowest_plcp(priv->active_rate_basic & + 0xFF0); + if (rate == IWL_INVALID_RATE) + rate = IWL_RATE_6M_PLCP; + } else { + rate = iwl_rate_get_lowest_plcp(priv->active_rate_basic & 0xF); + if (rate == IWL_INVALID_RATE) + rate = IWL_RATE_1M_PLCP; + } + + frame_size = iwl_hw_get_beacon_cmd(priv, frame, rate); + + rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size, + &frame->u.cmd[0]); + + iwl_free_frame(priv, frame); + + return rc; +} + +/****************************************************************************** + * + * EEPROM related functions + * + ******************************************************************************/ + +static void get_eeprom_mac(struct iwl_priv *priv, u8 *mac) +{ + memcpy(mac, priv->eeprom.mac_address, 6); +} + +/** + * iwl_eeprom_init - read EEPROM contents + * + * Load the EEPROM from adapter into priv->eeprom + * + * NOTE: This routine uses the non-debug IO access functions. + */ +int iwl_eeprom_init(struct iwl_priv *priv) +{ + u16 *e = (u16 *)&priv->eeprom; + u32 gp = iwl_read32(priv, CSR_EEPROM_GP); + u32 r; + int sz = sizeof(priv->eeprom); + int rc; + int i; + u16 addr; + + /* The EEPROM structure has several padding buffers within it + * and when adding new EEPROM maps is subject to programmer errors + * which may be very difficult to identify without explicitly + * checking the resulting size of the eeprom map. */ + BUILD_BUG_ON(sizeof(priv->eeprom) != IWL_EEPROM_IMAGE_SIZE); + + if ((gp & CSR_EEPROM_GP_VALID_MSK) == CSR_EEPROM_GP_BAD_SIGNATURE) { + IWL_ERROR("EEPROM not found, EEPROM_GP=0x%08x", gp); + return -ENOENT; + } + + rc = iwl_eeprom_aqcuire_semaphore(priv); + if (rc < 0) { + IWL_ERROR("Failed to aqcuire EEPROM semaphore.\n"); + return -ENOENT; + } + + /* eeprom is an array of 16bit values */ + for (addr = 0; addr < sz; addr += sizeof(u16)) { + _iwl_write32(priv, CSR_EEPROM_REG, addr << 1); + _iwl_clear_bit(priv, CSR_EEPROM_REG, CSR_EEPROM_REG_BIT_CMD); + + for (i = 0; i < IWL_EEPROM_ACCESS_TIMEOUT; + i += IWL_EEPROM_ACCESS_DELAY) { + r = _iwl_read_restricted(priv, CSR_EEPROM_REG); + if (r & CSR_EEPROM_REG_READ_VALID_MSK) + break; + udelay(IWL_EEPROM_ACCESS_DELAY); + } + + if (!(r & CSR_EEPROM_REG_READ_VALID_MSK)) { + IWL_ERROR("Time out reading EEPROM[%d]", addr); + return -ETIMEDOUT; + } + e[addr / 2] = le16_to_cpu(r >> 16); + } + + return 0; +} + +/****************************************************************************** + * + * Misc. internal state and helper functions + * + ******************************************************************************/ +#ifdef CONFIG_IWLWIFI_DEBUG + +/** + * iwl_report_frame - dump frame to syslog during debug sessions + * + * hack this function to show different aspects of received frames, + * including selective frame dumps. + * group100 parameter selects whether to show 1 out of 100 good frames. + * + * TODO: ieee80211_hdr stuff is common to 3945 and 4965, so frame type + * info output is okay, but some of this stuff (e.g. iwl_rx_frame_stats) + * is 3945-specific and gives bad output for 4965. Need to split the + * functionality, keep common stuff here. + */ +void iwl_report_frame(struct iwl_priv *priv, + struct iwl_rx_packet *pkt, + struct ieee80211_hdr *header, int group100) +{ + u32 to_us; + u32 print_summary = 0; + u32 print_dump = 0; /* set to 1 to dump all frames' contents */ + u32 hundred = 0; + u32 dataframe = 0; + u16 fc; + u16 seq_ctl; + u16 channel; + u16 phy_flags; + int rate_sym; + u16 length; + u16 status; + u16 bcn_tmr; + u32 tsf_low; + u64 tsf; + u8 rssi; + u8 agc; + u16 sig_avg; + u16 noise_diff; + struct iwl_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt); + struct iwl_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); + struct iwl_rx_frame_end *rx_end = IWL_RX_END(pkt); + u8 *data = IWL_RX_DATA(pkt); + + /* MAC header */ + fc = le16_to_cpu(header->frame_control); + seq_ctl = le16_to_cpu(header->seq_ctrl); + + /* metadata */ + channel = le16_to_cpu(rx_hdr->channel); + phy_flags = le16_to_cpu(rx_hdr->phy_flags); + rate_sym = rx_hdr->rate; + length = le16_to_cpu(rx_hdr->len); + + /* end-of-frame status and timestamp */ + status = le32_to_cpu(rx_end->status); + bcn_tmr = le32_to_cpu(rx_end->beacon_timestamp); + tsf_low = le64_to_cpu(rx_end->timestamp) & 0x0ffffffff; + tsf = le64_to_cpu(rx_end->timestamp); + + /* signal statistics */ + rssi = rx_stats->rssi; + agc = rx_stats->agc; + sig_avg = le16_to_cpu(rx_stats->sig_avg); + noise_diff = le16_to_cpu(rx_stats->noise_diff); + + to_us = !compare_ether_addr(header->addr1, priv->mac_addr); + + /* if data frame is to us and all is good, + * (optionally) print summary for only 1 out of every 100 */ + if (to_us && (fc & ~IEEE80211_FCTL_PROTECTED) == + (IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) { + dataframe = 1; + if (!group100) + print_summary = 1; /* print each frame */ + else if (priv->framecnt_to_us < 100) { + priv->framecnt_to_us++; + print_summary = 0; + } else { + priv->framecnt_to_us = 0; + print_summary = 1; + hundred = 1; + } + } else { + /* print summary for all other frames */ + print_summary = 1; + } + + if (print_summary) { + char *title; + u32 rate; + + if (hundred) + title = "100Frames"; + else if (fc & IEEE80211_FCTL_RETRY) + title = "Retry"; + else if (ieee80211_is_assoc_response(fc)) + title = "AscRsp"; + else if (ieee80211_is_reassoc_response(fc)) + title = "RasRsp"; + else if (ieee80211_is_probe_response(fc)) { + title = "PrbRsp"; + print_dump = 1; /* dump frame contents */ + } else if (ieee80211_is_beacon(fc)) { + title = "Beacon"; + print_dump = 1; /* dump frame contents */ + } else if (ieee80211_is_atim(fc)) + title = "ATIM"; + else if (ieee80211_is_auth(fc)) + title = "Auth"; + else if (ieee80211_is_deauth(fc)) + title = "DeAuth"; + else if (ieee80211_is_disassoc(fc)) + title = "DisAssoc"; + else + title = "Frame"; + + rate = iwl_rate_index_from_plcp(rate_sym); + if (rate == -1) + rate = 0; + else + rate = iwl_rates[rate].ieee / 2; + + /* print frame summary. + * MAC addresses show just the last byte (for brevity), + * but you can hack it to show more, if you'd like to. */ + if (dataframe) + IWL_DEBUG_RX("%s: mhd=0x%04x, dst=0x%02x, " + "len=%u, rssi=%d, chnl=%d, rate=%u, \n", + title, fc, header->addr1[5], + length, rssi, channel, rate); + else { + /* src/dst addresses assume managed mode */ + IWL_DEBUG_RX("%s: 0x%04x, dst=0x%02x, " + "src=0x%02x, rssi=%u, tim=%lu usec, " + "phy=0x%02x, chnl=%d\n", + title, fc, header->addr1[5], + header->addr3[5], rssi, + tsf_low - priv->scan_start_tsf, + phy_flags, channel); + } + } + if (print_dump) + iwl_print_hex_dump(IWL_DL_RX, data, length); +} +#endif + +static void iwl_unset_hw_setting(struct iwl_priv *priv) +{ + if (priv->hw_setting.shared_virt) + pci_free_consistent(priv->pci_dev, + sizeof(struct iwl_shared), + priv->hw_setting.shared_virt, + priv->hw_setting.shared_phys); +} + +/** + * iwl_supported_rate_to_ie - fill in the supported rate in IE field + * + * return : set the bit for each supported rate insert in ie + */ +static u16 iwl_supported_rate_to_ie(u8 *ie, u16 supported_rate, + u16 basic_rate, int max_count) +{ + u16 ret_rates = 0, bit; + int i; + u8 *rates; + + rates = &(ie[1]); + + for (bit = 1, i = 0; i < IWL_RATE_COUNT; i++, bit <<= 1) { + if (bit & supported_rate) { + ret_rates |= bit; + rates[*ie] = iwl_rates[i].ieee | + ((bit & basic_rate) ? 0x80 : 0x00); + *ie = *ie + 1; + if (*ie >= max_count) + break; + } + } + + return ret_rates; +} + +/** + * iwl_fill_probe_req - fill in all required fields and IE for probe request + */ +static u16 iwl_fill_probe_req(struct iwl_priv *priv, + struct ieee80211_mgmt *frame, + int left, int is_direct) +{ + int len = 0; + u8 *pos = NULL; + u16 ret_rates; + + /* Make sure there is enough space for the probe request, + * two mandatory IEs and the data */ + left -= 24; + if (left < 0) + return 0; + len += 24; + + frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); + memcpy(frame->da, BROADCAST_ADDR, ETH_ALEN); + memcpy(frame->sa, priv->mac_addr, ETH_ALEN); + memcpy(frame->bssid, BROADCAST_ADDR, ETH_ALEN); + frame->seq_ctrl = 0; + + /* fill in our indirect SSID IE */ + /* ...next IE... */ + + left -= 2; + if (left < 0) + return 0; + len += 2; + pos = &(frame->u.probe_req.variable[0]); + *pos++ = WLAN_EID_SSID; + *pos++ = 0; + + /* fill in our direct SSID IE... */ + if (is_direct) { + /* ...next IE... */ + left -= 2 + priv->essid_len; + if (left < 0) + return 0; + /* ... fill it in... */ + *pos++ = WLAN_EID_SSID; + *pos++ = priv->essid_len; + memcpy(pos, priv->essid, priv->essid_len); + pos += priv->essid_len; + len += 2 + priv->essid_len; + } + + /* fill in supported rate */ + /* ...next IE... */ + left -= 2; + if (left < 0) + return 0; + /* ... fill it in... */ + *pos++ = WLAN_EID_SUPP_RATES; + *pos = 0; + ret_rates = priv->active_rate = priv->rates_mask; + priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK; + + iwl_supported_rate_to_ie(pos, priv->active_rate, + priv->active_rate_basic, left); + len += 2 + *pos; + pos += (*pos) + 1; + ret_rates = ~ret_rates & priv->active_rate; + + if (ret_rates == 0) + goto fill_end; + + /* fill in supported extended rate */ + /* ...next IE... */ + left -= 2; + if (left < 0) + return 0; + /* ... fill it in... */ + *pos++ = WLAN_EID_EXT_SUPP_RATES; + *pos = 0; + iwl_supported_rate_to_ie(pos, ret_rates, priv->active_rate_basic, left); + if (*pos > 0) + len += 2 + *pos; + + fill_end: + return (u16)len; +} + +/* + * QoS support +*/ +#ifdef CONFIG_IWLWIFI_QOS +static int iwl_send_qos_params_command(struct iwl_priv *priv, + struct iwl_qosparam_cmd *qos) +{ + + return iwl_send_cmd_pdu(priv, REPLY_QOS_PARAM, + sizeof(struct iwl_qosparam_cmd), qos); +} + +static void iwl_reset_qos(struct iwl_priv *priv) +{ + u16 cw_min = 15; + u16 cw_max = 1023; + u8 aifs = 2; + u8 is_legacy = 0; + unsigned long flags; + int i; + + spin_lock_irqsave(&priv->lock, flags); + priv->qos_data.qos_active = 0; + + if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) { + if (priv->qos_data.qos_enable) + priv->qos_data.qos_active = 1; + if (!(priv->active_rate & 0xfff0)) { + cw_min = 31; + is_legacy = 1; + } + } else if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { + if (priv->qos_data.qos_enable) + priv->qos_data.qos_active = 1; + } else if (!(priv->staging_rxon.flags & RXON_FLG_SHORT_SLOT_MSK)) { + cw_min = 31; + is_legacy = 1; + } + + if (priv->qos_data.qos_active) + aifs = 3; + + priv->qos_data.def_qos_parm.ac[0].cw_min = cpu_to_le16(cw_min); + priv->qos_data.def_qos_parm.ac[0].cw_max = cpu_to_le16(cw_max); + priv->qos_data.def_qos_parm.ac[0].aifsn = aifs; + priv->qos_data.def_qos_parm.ac[0].edca_txop = 0; + priv->qos_data.def_qos_parm.ac[0].reserved1 = 0; + + if (priv->qos_data.qos_active) { + i = 1; + priv->qos_data.def_qos_parm.ac[i].cw_min = cpu_to_le16(cw_min); + priv->qos_data.def_qos_parm.ac[i].cw_max = cpu_to_le16(cw_max); + priv->qos_data.def_qos_parm.ac[i].aifsn = 7; + priv->qos_data.def_qos_parm.ac[i].edca_txop = 0; + priv->qos_data.def_qos_parm.ac[i].reserved1 = 0; + + i = 2; + priv->qos_data.def_qos_parm.ac[i].cw_min = + cpu_to_le16((cw_min + 1) / 2 - 1); + priv->qos_data.def_qos_parm.ac[i].cw_max = + cpu_to_le16(cw_max); + priv->qos_data.def_qos_parm.ac[i].aifsn = 2; + if (is_legacy) + priv->qos_data.def_qos_parm.ac[i].edca_txop = + cpu_to_le16(6016); + else + priv->qos_data.def_qos_parm.ac[i].edca_txop = + cpu_to_le16(3008); + priv->qos_data.def_qos_parm.ac[i].reserved1 = 0; + + i = 3; + priv->qos_data.def_qos_parm.ac[i].cw_min = + cpu_to_le16((cw_min + 1) / 4 - 1); + priv->qos_data.def_qos_parm.ac[i].cw_max = + cpu_to_le16((cw_max + 1) / 2 - 1); + priv->qos_data.def_qos_parm.ac[i].aifsn = 2; + priv->qos_data.def_qos_parm.ac[i].reserved1 = 0; + if (is_legacy) + priv->qos_data.def_qos_parm.ac[i].edca_txop = + cpu_to_le16(3264); + else + priv->qos_data.def_qos_parm.ac[i].edca_txop = + cpu_to_le16(1504); + } else { + for (i = 1; i < 4; i++) { + priv->qos_data.def_qos_parm.ac[i].cw_min = + cpu_to_le16(cw_min); + priv->qos_data.def_qos_parm.ac[i].cw_max = + cpu_to_le16(cw_max); + priv->qos_data.def_qos_parm.ac[i].aifsn = aifs; + priv->qos_data.def_qos_parm.ac[i].edca_txop = 0; + priv->qos_data.def_qos_parm.ac[i].reserved1 = 0; + } + } + IWL_DEBUG_QOS("set QoS to default \n"); + + spin_unlock_irqrestore(&priv->lock, flags); +} + +static void iwl_activate_qos(struct iwl_priv *priv, u8 force) +{ + unsigned long flags; + + if (priv == NULL) + return; + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + if (!priv->qos_data.qos_enable) + return; + + spin_lock_irqsave(&priv->lock, flags); + priv->qos_data.def_qos_parm.qos_flags = 0; + + if (priv->qos_data.qos_cap.q_AP.queue_request && + !priv->qos_data.qos_cap.q_AP.txop_request) + priv->qos_data.def_qos_parm.qos_flags |= + QOS_PARAM_FLG_TXOP_TYPE_MSK; + + if (priv->qos_data.qos_active) + priv->qos_data.def_qos_parm.qos_flags |= + QOS_PARAM_FLG_UPDATE_EDCA_MSK; + + spin_unlock_irqrestore(&priv->lock, flags); + + if (force || iwl_is_associated(priv)) { + IWL_DEBUG_QOS("send QoS cmd with Qos active %d \n", + priv->qos_data.qos_active); + + iwl_send_qos_params_command(priv, + &(priv->qos_data.def_qos_parm)); + } +} + +#endif /* CONFIG_IWLWIFI_QOS */ +/* + * Power management (not Tx power!) functions + */ +#define MSEC_TO_USEC 1024 + +#define NOSLP __constant_cpu_to_le32(0) +#define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK +#define SLP_TIMEOUT(T) __constant_cpu_to_le32((T) * MSEC_TO_USEC) +#define SLP_VEC(X0, X1, X2, X3, X4) {__constant_cpu_to_le32(X0), \ + __constant_cpu_to_le32(X1), \ + __constant_cpu_to_le32(X2), \ + __constant_cpu_to_le32(X3), \ + __constant_cpu_to_le32(X4)} + + +/* default power management (not Tx power) table values */ +/* for tim 0-10 */ +static struct iwl_power_vec_entry range_0[IWL_POWER_AC] = { + {{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, + {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0}, + {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(300), SLP_VEC(2, 4, 6, 7, 7)}, 0}, + {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(100), SLP_VEC(2, 6, 9, 9, 10)}, 0}, + {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(25), SLP_VEC(2, 7, 9, 9, 10)}, 1}, + {{SLP, SLP_TIMEOUT(25), SLP_TIMEOUT(25), SLP_VEC(4, 7, 10, 10, 10)}, 1} +}; + +/* for tim > 10 */ +static struct iwl_power_vec_entry range_1[IWL_POWER_AC] = { + {{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, + {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500), + SLP_VEC(1, 2, 3, 4, 0xFF)}, 0}, + {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(300), + SLP_VEC(2, 4, 6, 7, 0xFF)}, 0}, + {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(100), + SLP_VEC(2, 6, 9, 9, 0xFF)}, 0}, + {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(25), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0}, + {{SLP, SLP_TIMEOUT(25), SLP_TIMEOUT(25), + SLP_VEC(4, 7, 10, 10, 0xFF)}, 0} +}; + +int iwl_power_init_handle(struct iwl_priv *priv) +{ + int rc = 0, i; + struct iwl_power_mgr *pow_data; + int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_AC; + u16 pci_pm; + + IWL_DEBUG_POWER("Initialize power \n"); + + pow_data = &(priv->power_data); + + memset(pow_data, 0, sizeof(*pow_data)); + + pow_data->active_index = IWL_POWER_RANGE_0; + pow_data->dtim_val = 0xffff; + + memcpy(&pow_data->pwr_range_0[0], &range_0[0], size); + memcpy(&pow_data->pwr_range_1[0], &range_1[0], size); + + rc = pci_read_config_word(priv->pci_dev, PCI_LINK_CTRL, &pci_pm); + if (rc != 0) + return 0; + else { + struct iwl_powertable_cmd *cmd; + + IWL_DEBUG_POWER("adjust power command flags\n"); + + for (i = 0; i < IWL_POWER_AC; i++) { + cmd = &pow_data->pwr_range_0[i].cmd; + + if (pci_pm & 0x1) + cmd->flags &= ~IWL_POWER_PCI_PM_MSK; + else + cmd->flags |= IWL_POWER_PCI_PM_MSK; + } + } + return rc; +} + +static int iwl_update_power_cmd(struct iwl_priv *priv, + struct iwl_powertable_cmd *cmd, u32 mode) +{ + int rc = 0, i; + u8 skip; + u32 max_sleep = 0; + struct iwl_power_vec_entry *range; + u8 period = 0; + struct iwl_power_mgr *pow_data; + + if (mode > IWL_POWER_INDEX_5) { + IWL_DEBUG_POWER("Error invalid power mode \n"); + return -1; + } + pow_data = &(priv->power_data); + + if (pow_data->active_index == IWL_POWER_RANGE_0) + range = &pow_data->pwr_range_0[0]; + else + range = &pow_data->pwr_range_1[1]; + + memcpy(cmd, &range[mode].cmd, sizeof(struct iwl_powertable_cmd)); + +#ifdef IWL_MAC80211_DISABLE + if (priv->assoc_network != NULL) { + unsigned long flags; + + period = priv->assoc_network->tim.tim_period; + } +#endif /*IWL_MAC80211_DISABLE */ + skip = range[mode].no_dtim; + + if (period == 0) { + period = 1; + skip = 0; + } + + if (skip == 0) { + max_sleep = period; + cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK; + } else { + __le32 slp_itrvl = cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]; + max_sleep = (le32_to_cpu(slp_itrvl) / period) * period; + cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK; + } + + for (i = 0; i < IWL_POWER_VEC_SIZE; i++) { + if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep) + cmd->sleep_interval[i] = cpu_to_le32(max_sleep); + } + + IWL_DEBUG_POWER("Flags value = 0x%08X\n", cmd->flags); + IWL_DEBUG_POWER("Tx timeout = %u\n", le32_to_cpu(cmd->tx_data_timeout)); + IWL_DEBUG_POWER("Rx timeout = %u\n", le32_to_cpu(cmd->rx_data_timeout)); + IWL_DEBUG_POWER("Sleep interval vector = { %d , %d , %d , %d , %d }\n", + le32_to_cpu(cmd->sleep_interval[0]), + le32_to_cpu(cmd->sleep_interval[1]), + le32_to_cpu(cmd->sleep_interval[2]), + le32_to_cpu(cmd->sleep_interval[3]), + le32_to_cpu(cmd->sleep_interval[4])); + + return rc; +} + +static int iwl_send_power_mode(struct iwl_priv *priv, u32 mode) +{ + u32 final_mode = mode; + int rc; + struct iwl_powertable_cmd cmd; + + /* If on battery, set to 3, + * if plugged into AC power, set to CAM ("continuosly aware mode"), + * else user level */ + switch (mode) { + case IWL_POWER_BATTERY: + final_mode = IWL_POWER_INDEX_3; + break; + case IWL_POWER_AC: + final_mode = IWL_POWER_MODE_CAM; + break; + default: + final_mode = mode; + break; + } + + iwl_update_power_cmd(priv, &cmd, final_mode); + + rc = iwl_send_cmd_pdu(priv, POWER_TABLE_CMD, sizeof(cmd), &cmd); + + if (final_mode == IWL_POWER_MODE_CAM) + clear_bit(STATUS_POWER_PMI, &priv->status); + else + set_bit(STATUS_POWER_PMI, &priv->status); + + return rc; +} + +int iwl_is_network_packet(struct iwl_priv *priv, struct ieee80211_hdr *header) +{ + /* Filter incoming packets to determine if they are targeted toward + * this network, discarding packets coming from ourselves */ + switch (priv->iw_mode) { + case IEEE80211_IF_TYPE_IBSS: /* Header: Dest. | Source | BSSID */ + /* packets from our adapter are dropped (echo) */ + if (!compare_ether_addr(header->addr2, priv->mac_addr)) + return 0; + /* {broad,multi}cast packets to our IBSS go through */ + if (is_multicast_ether_addr(header->addr1)) + return !compare_ether_addr(header->addr3, priv->bssid); + /* packets to our adapter go through */ + return !compare_ether_addr(header->addr1, priv->mac_addr); + case IEEE80211_IF_TYPE_STA: /* Header: Dest. | AP{BSSID} | Source */ + /* packets from our adapter are dropped (echo) */ + if (!compare_ether_addr(header->addr3, priv->mac_addr)) + return 0; + /* {broad,multi}cast packets to our BSS go through */ + if (is_multicast_ether_addr(header->addr1)) + return !compare_ether_addr(header->addr2, priv->bssid); + /* packets to our adapter go through */ + return !compare_ether_addr(header->addr1, priv->mac_addr); + } + + return 1; +} + +#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x + +const char *iwl_get_tx_fail_reason(u32 status) +{ + switch (status & TX_STATUS_MSK) { + case TX_STATUS_SUCCESS: + return "SUCCESS"; + TX_STATUS_ENTRY(SHORT_LIMIT); + TX_STATUS_ENTRY(LONG_LIMIT); + TX_STATUS_ENTRY(FIFO_UNDERRUN); + TX_STATUS_ENTRY(MGMNT_ABORT); + TX_STATUS_ENTRY(NEXT_FRAG); + TX_STATUS_ENTRY(LIFE_EXPIRE); + TX_STATUS_ENTRY(DEST_PS); + TX_STATUS_ENTRY(ABORTED); + TX_STATUS_ENTRY(BT_RETRY); + TX_STATUS_ENTRY(STA_INVALID); + TX_STATUS_ENTRY(FRAG_DROPPED); + TX_STATUS_ENTRY(TID_DISABLE); + TX_STATUS_ENTRY(FRAME_FLUSHED); + TX_STATUS_ENTRY(INSUFFICIENT_CF_POLL); + TX_STATUS_ENTRY(TX_LOCKED); + TX_STATUS_ENTRY(NO_BEACON_ON_RADAR); + } + + return "UNKNOWN"; +} + +/** + * iwl_scan_cancel - Cancel any currently executing HW scan + * + * NOTE: priv->mutex is not required before calling this function + */ +static int iwl_scan_cancel(struct iwl_priv *priv) +{ + if (!test_bit(STATUS_SCAN_HW, &priv->status)) { + clear_bit(STATUS_SCANNING, &priv->status); + return 0; + } + + if (test_bit(STATUS_SCANNING, &priv->status)) { + if (!test_bit(STATUS_SCAN_ABORTING, &priv->status)) { + IWL_DEBUG_SCAN("Queuing scan abort.\n"); + set_bit(STATUS_SCAN_ABORTING, &priv->status); + queue_work(priv->workqueue, &priv->abort_scan); + + } else + IWL_DEBUG_SCAN("Scan abort already in progress.\n"); + + return test_bit(STATUS_SCANNING, &priv->status); + } + + return 0; +} + +/** + * iwl_scan_cancel_timeout - Cancel any currently executing HW scan + * @ms: amount of time to wait (in milliseconds) for scan to abort + * + * NOTE: priv->mutex must be held before calling this function + */ +static int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms) +{ + unsigned long now = jiffies; + int ret; + + ret = iwl_scan_cancel(priv); + if (ret && ms) { + mutex_unlock(&priv->mutex); + while (!time_after(jiffies, now + msecs_to_jiffies(ms)) && + test_bit(STATUS_SCANNING, &priv->status)) + msleep(1); + mutex_lock(&priv->mutex); + + return test_bit(STATUS_SCANNING, &priv->status); + } + + return ret; +} + +static void iwl_sequence_reset(struct iwl_priv *priv) +{ + /* Reset ieee stats */ + + /* We don't reset the net_device_stats (ieee->stats) on + * re-association */ + + priv->last_seq_num = -1; + priv->last_frag_num = -1; + priv->last_packet_time = 0; + + iwl_scan_cancel(priv); +} + +#define MAX_UCODE_BEACON_INTERVAL 1024 +#define INTEL_CONN_LISTEN_INTERVAL __constant_cpu_to_le16(0xA) + +static __le16 iwl_adjust_beacon_interval(u16 beacon_val) +{ + u16 new_val = 0; + u16 beacon_factor = 0; + + beacon_factor = + (beacon_val + MAX_UCODE_BEACON_INTERVAL) + / MAX_UCODE_BEACON_INTERVAL; + new_val = beacon_val / beacon_factor; + + return cpu_to_le16(new_val); +} + +static void iwl_setup_rxon_timing(struct iwl_priv *priv) +{ + u64 interval_tm_unit; + u64 tsf, result; + unsigned long flags; + struct ieee80211_conf *conf = NULL; + u16 beacon_int = 0; + + conf = ieee80211_get_hw_conf(priv->hw); + + spin_lock_irqsave(&priv->lock, flags); + priv->rxon_timing.timestamp.dw[1] = cpu_to_le32(priv->timestamp1); + priv->rxon_timing.timestamp.dw[0] = cpu_to_le32(priv->timestamp0); + + priv->rxon_timing.listen_interval = INTEL_CONN_LISTEN_INTERVAL; + + tsf = priv->timestamp1; + tsf = ((tsf << 32) | priv->timestamp0); + + beacon_int = priv->beacon_int; + spin_unlock_irqrestore(&priv->lock, flags); + + if (priv->iw_mode == IEEE80211_IF_TYPE_STA) { + if (beacon_int == 0) { + priv->rxon_timing.beacon_interval = cpu_to_le16(100); + priv->rxon_timing.beacon_init_val = cpu_to_le32(102400); + } else { + priv->rxon_timing.beacon_interval = + cpu_to_le16(beacon_int); + priv->rxon_timing.beacon_interval = + iwl_adjust_beacon_interval( + le16_to_cpu(priv->rxon_timing.beacon_interval)); + } + + priv->rxon_timing.atim_window = 0; + } else { + priv->rxon_timing.beacon_interval = + iwl_adjust_beacon_interval(conf->beacon_int); + /* TODO: we need to get atim_window from upper stack + * for now we set to 0 */ + priv->rxon_timing.atim_window = 0; + } + + interval_tm_unit = + (le16_to_cpu(priv->rxon_timing.beacon_interval) * 1024); + result = do_div(tsf, interval_tm_unit); + priv->rxon_timing.beacon_init_val = + cpu_to_le32((u32) ((u64) interval_tm_unit - result)); + + IWL_DEBUG_ASSOC + ("beacon interval %d beacon timer %d beacon tim %d\n", + le16_to_cpu(priv->rxon_timing.beacon_interval), + le32_to_cpu(priv->rxon_timing.beacon_init_val), + le16_to_cpu(priv->rxon_timing.atim_window)); +} + +static int iwl_scan_initiate(struct iwl_priv *priv) +{ + if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { + IWL_ERROR("APs don't scan.\n"); + return 0; + } + + if (!iwl_is_ready_rf(priv)) { + IWL_DEBUG_SCAN("Aborting scan due to not ready.\n"); + return -EIO; + } + + if (test_bit(STATUS_SCANNING, &priv->status)) { + IWL_DEBUG_SCAN("Scan already in progress.\n"); + return -EAGAIN; + } + + if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { + IWL_DEBUG_SCAN("Scan request while abort pending. " + "Queuing.\n"); + return -EAGAIN; + } + + IWL_DEBUG_INFO("Starting scan...\n"); + priv->scan_bands = 2; + set_bit(STATUS_SCANNING, &priv->status); + priv->scan_start = jiffies; + priv->scan_pass_start = priv->scan_start; + + queue_work(priv->workqueue, &priv->request_scan); + + return 0; +} + +static int iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt) +{ + struct iwl_rxon_cmd *rxon = &priv->staging_rxon; + + if (hw_decrypt) + rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK; + else + rxon->filter_flags |= RXON_FILTER_DIS_DECRYPT_MSK; + + return 0; +} + +static void iwl_set_flags_for_phymode(struct iwl_priv *priv, u8 phymode) +{ + if (phymode == MODE_IEEE80211A) { + priv->staging_rxon.flags &= + ~(RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK + | RXON_FLG_CCK_MSK); + priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK; + } else { + /* Copied from iwl_bg_post_associate() */ + if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME) + priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK; + else + priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; + + if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) + priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; + + priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK; + priv->staging_rxon.flags |= RXON_FLG_AUTO_DETECT_MSK; + priv->staging_rxon.flags &= ~RXON_FLG_CCK_MSK; + } +} + +/* + * initilize rxon structure with default values fromm eeprom + */ +static void iwl_connection_init_rx_config(struct iwl_priv *priv) +{ + const struct iwl_channel_info *ch_info; + + memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon)); + + switch (priv->iw_mode) { + case IEEE80211_IF_TYPE_AP: + priv->staging_rxon.dev_type = RXON_DEV_TYPE_AP; + break; + + case IEEE80211_IF_TYPE_STA: + priv->staging_rxon.dev_type = RXON_DEV_TYPE_ESS; + priv->staging_rxon.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK; + break; + + case IEEE80211_IF_TYPE_IBSS: + priv->staging_rxon.dev_type = RXON_DEV_TYPE_IBSS; + priv->staging_rxon.flags = RXON_FLG_SHORT_PREAMBLE_MSK; + priv->staging_rxon.filter_flags = RXON_FILTER_BCON_AWARE_MSK | + RXON_FILTER_ACCEPT_GRP_MSK; + break; + + case IEEE80211_IF_TYPE_MNTR: + priv->staging_rxon.dev_type = RXON_DEV_TYPE_SNIFFER; + priv->staging_rxon.filter_flags = RXON_FILTER_PROMISC_MSK | + RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_ACCEPT_GRP_MSK; + break; + } + +#if 0 + /* TODO: Figure out when short_preamble would be set and cache from + * that */ + if (!hw_to_local(priv->hw)->short_preamble) + priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK; + else + priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; +#endif + + ch_info = iwl_get_channel_info(priv, priv->phymode, + le16_to_cpu(priv->staging_rxon.channel)); + + if (!ch_info) + ch_info = &priv->channel_info[0]; + + /* + * in some case A channels are all non IBSS + * in this case force B/G channel + */ + if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && + !(is_channel_ibss(ch_info))) + ch_info = &priv->channel_info[0]; + + priv->staging_rxon.channel = cpu_to_le16(ch_info->channel); + if (is_channel_a_band(ch_info)) + priv->phymode = MODE_IEEE80211A; + else + priv->phymode = MODE_IEEE80211G; + + iwl_set_flags_for_phymode(priv, priv->phymode); + + priv->staging_rxon.ofdm_basic_rates = + (IWL_OFDM_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF; + priv->staging_rxon.cck_basic_rates = + (IWL_CCK_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF; +} + +static int iwl_set_mode(struct iwl_priv *priv, int mode) +{ + if (!iwl_is_ready_rf(priv)) + return -EAGAIN; + + if (mode == IEEE80211_IF_TYPE_IBSS) { + const struct iwl_channel_info *ch_info; + + ch_info = iwl_get_channel_info(priv, + priv->phymode, + le16_to_cpu(priv->staging_rxon.channel)); + + if (!ch_info || !is_channel_ibss(ch_info)) { + IWL_ERROR("channel %d not IBSS channel\n", + le16_to_cpu(priv->staging_rxon.channel)); + return -EINVAL; + } + } + + cancel_delayed_work(&priv->scan_check); + if (iwl_scan_cancel_timeout(priv, 100)) { + IWL_WARNING("Aborted scan still in progress after 100ms\n"); + IWL_DEBUG_MAC80211("leaving - scan abort failed.\n"); + return -EAGAIN; + } + + priv->iw_mode = mode; + + iwl_connection_init_rx_config(priv); + memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); + + iwl_clear_stations_table(priv); + + iwl_commit_rxon(priv); + + return 0; +} + +static void iwl_build_tx_cmd_hwcrypto(struct iwl_priv *priv, + struct ieee80211_tx_control *ctl, + struct iwl_cmd *cmd, + struct sk_buff *skb_frag, + int last_frag) +{ + struct iwl_hw_key *keyinfo = &priv->stations[ctl->key_idx].keyinfo; + + switch (keyinfo->alg) { + case ALG_CCMP: + cmd->cmd.tx.sec_ctl = TX_CMD_SEC_CCM; + memcpy(cmd->cmd.tx.key, keyinfo->key, keyinfo->keylen); + IWL_DEBUG_TX("tx_cmd with aes hwcrypto\n"); + break; + + case ALG_TKIP: +#if 0 + cmd->cmd.tx.sec_ctl = TX_CMD_SEC_TKIP; + + if (last_frag) + memcpy(cmd->cmd.tx.tkip_mic.byte, skb_frag->tail - 8, + 8); + else + memset(cmd->cmd.tx.tkip_mic.byte, 0, 8); +#endif + break; + + case ALG_WEP: + cmd->cmd.tx.sec_ctl = TX_CMD_SEC_WEP | + (ctl->key_idx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT; + + if (keyinfo->keylen == 13) + cmd->cmd.tx.sec_ctl |= TX_CMD_SEC_KEY128; + + memcpy(&cmd->cmd.tx.key[3], keyinfo->key, keyinfo->keylen); + + IWL_DEBUG_TX("Configuring packet for WEP encryption " + "with key %d\n", ctl->key_idx); + break; + + case ALG_NONE: + IWL_DEBUG_TX("Tx packet in the clear (encrypt requested).\n"); + break; + + default: + printk(KERN_ERR "Unknown encode alg %d\n", keyinfo->alg); + break; + } +} + +/* + * handle build REPLY_TX command notification. + */ +static void iwl_build_tx_cmd_basic(struct iwl_priv *priv, + struct iwl_cmd *cmd, + struct ieee80211_tx_control *ctrl, + struct ieee80211_hdr *hdr, + int is_unicast, u8 std_id) +{ + __le16 *qc; + u16 fc = le16_to_cpu(hdr->frame_control); + __le32 tx_flags = cmd->cmd.tx.tx_flags; + + cmd->cmd.tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; + if (!(ctrl->flags & IEEE80211_TXCTL_NO_ACK)) { + tx_flags |= TX_CMD_FLG_ACK_MSK; + if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) + tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; + if (ieee80211_is_probe_response(fc) && + !(le16_to_cpu(hdr->seq_ctrl) & 0xf)) + tx_flags |= TX_CMD_FLG_TSF_MSK; + } else { + tx_flags &= (~TX_CMD_FLG_ACK_MSK); + tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; + } + + cmd->cmd.tx.sta_id = std_id; + if (ieee80211_get_morefrag(hdr)) + tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK; + + qc = ieee80211_get_qos_ctrl(hdr); + if (qc) { + cmd->cmd.tx.tid_tspec = (u8) (le16_to_cpu(*qc) & 0xf); + tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK; + } else + tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; + + if (ctrl->flags & IEEE80211_TXCTL_USE_RTS_CTS) { + tx_flags |= TX_CMD_FLG_RTS_MSK; + tx_flags &= ~TX_CMD_FLG_CTS_MSK; + } else if (ctrl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { + tx_flags &= ~TX_CMD_FLG_RTS_MSK; + tx_flags |= TX_CMD_FLG_CTS_MSK; + } + + if ((tx_flags & TX_CMD_FLG_RTS_MSK) || (tx_flags & TX_CMD_FLG_CTS_MSK)) + tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK; + + tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK); + if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) { + if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ || + (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ) + cmd->cmd.tx.timeout.pm_frame_timeout = + cpu_to_le16(3); + else + cmd->cmd.tx.timeout.pm_frame_timeout = + cpu_to_le16(2); + } else + cmd->cmd.tx.timeout.pm_frame_timeout = 0; + + cmd->cmd.tx.driver_txop = 0; + cmd->cmd.tx.tx_flags = tx_flags; + cmd->cmd.tx.next_frame_len = 0; +} + +static int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) +{ + int sta_id; + u16 fc = le16_to_cpu(hdr->frame_control); + + /* If this frame is broadcast or not data then use the broadcast + * station id */ + if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) || + is_multicast_ether_addr(hdr->addr1)) + return priv->hw_setting.bcast_sta_id; + + switch (priv->iw_mode) { + + /* If this frame is part of a BSS network (we're a station), then + * we use the AP's station id */ + case IEEE80211_IF_TYPE_STA: + return IWL_AP_ID; + + /* If we are an AP, then find the station, or use BCAST */ + case IEEE80211_IF_TYPE_AP: + sta_id = iwl_hw_find_station(priv, hdr->addr1); + if (sta_id != IWL_INVALID_STATION) + return sta_id; + return priv->hw_setting.bcast_sta_id; + + /* If this frame is part of a IBSS network, then we use the + * target specific station id */ + case IEEE80211_IF_TYPE_IBSS: + sta_id = iwl_hw_find_station(priv, hdr->addr1); + if (sta_id != IWL_INVALID_STATION) + return sta_id; + + sta_id = iwl_add_station(priv, hdr->addr1, 0, CMD_ASYNC); + + if (sta_id != IWL_INVALID_STATION) + return sta_id; + + IWL_DEBUG_DROP("Station " MAC_FMT " not in station map. " + "Defaulting to broadcast...\n", + MAC_ARG(hdr->addr1)); + iwl_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); + return priv->hw_setting.bcast_sta_id; + + default: + IWL_WARNING("Unkown mode of operation: %d", priv->iw_mode); + return priv->hw_setting.bcast_sta_id; + } +} + +/* + * start REPLY_TX command process + */ +static int iwl_tx_skb(struct iwl_priv *priv, + struct sk_buff *skb, struct ieee80211_tx_control *ctl) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct iwl_tfd_frame *tfd; + u32 *control_flags; + int txq_id = ctl->queue; + struct iwl_tx_queue *txq = NULL; + struct iwl_queue *q = NULL; + dma_addr_t phys_addr; + dma_addr_t txcmd_phys; + struct iwl_cmd *out_cmd = NULL; + u16 len, idx, len_org; + u8 id, hdr_len, unicast; + u8 sta_id; + u16 seq_number = 0; + u16 fc; + __le16 *qc; + u8 wait_write_ptr = 0; + unsigned long flags; + int rc; + + spin_lock_irqsave(&priv->lock, flags); + if (iwl_is_rfkill(priv)) { + IWL_DEBUG_DROP("Dropping - RF KILL\n"); + goto drop_unlock; + } + + if (!priv->interface_id) { + IWL_DEBUG_DROP("Dropping - !priv->interface_id\n"); + goto drop_unlock; + } + + if ((ctl->tx_rate & 0xFF) == IWL_INVALID_RATE) { + IWL_ERROR("ERROR: No TX rate available.\n"); + goto drop_unlock; + } + + unicast = !is_multicast_ether_addr(hdr->addr1); + id = 0; + + fc = le16_to_cpu(hdr->frame_control); + +#ifdef CONFIG_IWLWIFI_DEBUG + if (ieee80211_is_auth(fc)) + IWL_DEBUG_TX("Sending AUTH frame\n"); + else if (ieee80211_is_assoc_request(fc)) + IWL_DEBUG_TX("Sending ASSOC frame\n"); + else if (ieee80211_is_reassoc_request(fc)) + IWL_DEBUG_TX("Sending REASSOC frame\n"); +#endif + + if (!iwl_is_associated(priv) && + ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) { + IWL_DEBUG_DROP("Dropping - !iwl_is_associated\n"); + goto drop_unlock; + } + + spin_unlock_irqrestore(&priv->lock, flags); + + hdr_len = ieee80211_get_hdrlen(fc); + sta_id = iwl_get_sta_id(priv, hdr); + if (sta_id == IWL_INVALID_STATION) { + IWL_DEBUG_DROP("Dropping - INVALID STATION: " MAC_FMT "\n", + MAC_ARG(hdr->addr1)); + goto drop; + } + + IWL_DEBUG_RATE("station Id %d\n", sta_id); + + qc = ieee80211_get_qos_ctrl(hdr); + if (qc) { + u8 tid = (u8)(le16_to_cpu(*qc) & 0xf); + seq_number = priv->stations[sta_id].tid[tid].seq_number & + IEEE80211_SCTL_SEQ; + hdr->seq_ctrl = cpu_to_le16(seq_number) | + (hdr->seq_ctrl & + __constant_cpu_to_le16(IEEE80211_SCTL_FRAG)); + seq_number += 0x10; + } + txq = &priv->txq[txq_id]; + q = &txq->q; + + spin_lock_irqsave(&priv->lock, flags); + + tfd = &txq->bd[q->first_empty]; + memset(tfd, 0, sizeof(*tfd)); + control_flags = (u32 *) tfd; + idx = get_cmd_index(q, q->first_empty, 0); + + memset(&(txq->txb[q->first_empty]), 0, sizeof(struct iwl_tx_info)); + txq->txb[q->first_empty].skb[0] = skb; + memcpy(&(txq->txb[q->first_empty].status.control), + ctl, sizeof(struct ieee80211_tx_control)); + out_cmd = &txq->cmd[idx]; + memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr)); + memset(&out_cmd->cmd.tx, 0, sizeof(out_cmd->cmd.tx)); + out_cmd->hdr.cmd = REPLY_TX; + out_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) | + INDEX_TO_SEQ(q->first_empty))); + /* copy frags header */ + memcpy(out_cmd->cmd.tx.hdr, hdr, hdr_len); + + /* hdr = (struct ieee80211_hdr *)out_cmd->cmd.tx.hdr; */ + len = priv->hw_setting.tx_cmd_len + + sizeof(struct iwl_cmd_header) + hdr_len; + + len_org = len; + len = (len + 3) & ~3; + + if (len_org != len) + len_org = 1; + else + len_org = 0; + + txcmd_phys = txq->dma_addr_cmd + sizeof(struct iwl_cmd) * idx + + offsetof(struct iwl_cmd, hdr); + + iwl_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len); + + if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) + iwl_build_tx_cmd_hwcrypto(priv, ctl, out_cmd, skb, 0); + + /* 802.11 null functions have no payload... */ + len = skb->len - hdr_len; + if (len) { + phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len, + len, PCI_DMA_TODEVICE); + iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, len); + } + + /* If there is no payload, then only one TFD is used */ + if (!len) + *control_flags = TFD_CTL_COUNT_SET(1); + else + *control_flags = TFD_CTL_COUNT_SET(2) | + TFD_CTL_PAD_SET(U32_PAD(len)); + + len = (u16)skb->len; + out_cmd->cmd.tx.len = cpu_to_le16(len); + + /* TODO need this for burst mode later on */ + iwl_build_tx_cmd_basic(priv, out_cmd, ctl, hdr, unicast, sta_id); + + /* set is_hcca to 0; it probably will never be implemented */ + iwl_hw_build_tx_cmd_rate(priv, out_cmd, ctl, hdr, sta_id, 0); + + out_cmd->cmd.tx.tx_flags &= ~TX_CMD_FLG_ANT_A_MSK; + out_cmd->cmd.tx.tx_flags &= ~TX_CMD_FLG_ANT_B_MSK; + + if (!ieee80211_get_morefrag(hdr)) { + txq->need_update = 1; + if (qc) { + u8 tid = (u8)(le16_to_cpu(*qc) & 0xf); + priv->stations[sta_id].tid[tid].seq_number = seq_number; + } + } else { + wait_write_ptr = 1; + txq->need_update = 0; + } + + iwl_print_hex_dump(IWL_DL_TX, out_cmd->cmd.payload, + sizeof(out_cmd->cmd.tx)); + + iwl_print_hex_dump(IWL_DL_TX, (u8 *)out_cmd->cmd.tx.hdr, + ieee80211_get_hdrlen(fc)); + + q->first_empty = iwl_queue_inc_wrap(q->first_empty, q->n_bd); + rc = iwl_tx_queue_update_write_ptr(priv, txq); + spin_unlock_irqrestore(&priv->lock, flags); + + if (rc) + return rc; + + if ((iwl_queue_space(q) < q->high_mark) + && priv->mac80211_registered) { + if (wait_write_ptr) { + spin_lock_irqsave(&priv->lock, flags); + txq->need_update = 1; + iwl_tx_queue_update_write_ptr(priv, txq); + spin_unlock_irqrestore(&priv->lock, flags); + } + + ieee80211_stop_queue(priv->hw, ctl->queue); + } + + return 0; + +drop_unlock: + spin_unlock_irqrestore(&priv->lock, flags); +drop: + return -1; +} + +static void iwl_set_rate(struct iwl_priv *priv) +{ + const struct ieee80211_hw_mode *hw = NULL; + struct ieee80211_rate *rate; + int i; + + hw = iwl_get_hw_mode(priv, priv->phymode); + + priv->active_rate = 0; + priv->active_rate_basic = 0; + + IWL_DEBUG_RATE("Setting rates for 802.11%c\n", + hw->mode == MODE_IEEE80211A ? + 'a' : ((hw->mode == MODE_IEEE80211B) ? 'b' : 'g')); + + for (i = 0; i < hw->num_rates; i++) { + rate = &(hw->rates[i]); + if ((rate->val < IWL_RATE_COUNT) && + (rate->flags & IEEE80211_RATE_SUPPORTED)) { + IWL_DEBUG_RATE("Adding rate index %d (plcp %d)%s\n", + rate->val, iwl_rates[rate->val].plcp, + (rate->flags & IEEE80211_RATE_BASIC) ? + "*" : ""); + priv->active_rate |= (1 << rate->val); + if (rate->flags & IEEE80211_RATE_BASIC) + priv->active_rate_basic |= (1 << rate->val); + } else + IWL_DEBUG_RATE("Not adding rate %d (plcp %d)\n", + rate->val, iwl_rates[rate->val].plcp); + } + + IWL_DEBUG_RATE("Set active_rate = %0x, active_rate_basic = %0x\n", + priv->active_rate, priv->active_rate_basic); + + /* + * If a basic rate is configured, then use it (adding IWL_RATE_1M_MASK) + * otherwise set it to the default of all CCK rates and 6, 12, 24 for + * OFDM + */ + if (priv->active_rate_basic & IWL_CCK_BASIC_RATES_MASK) + priv->staging_rxon.cck_basic_rates = + ((priv->active_rate_basic & + IWL_CCK_RATES_MASK) >> IWL_FIRST_CCK_RATE) & 0xF; + else + priv->staging_rxon.cck_basic_rates = + (IWL_CCK_BASIC_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF; + + if (priv->active_rate_basic & IWL_OFDM_BASIC_RATES_MASK) + priv->staging_rxon.ofdm_basic_rates = + ((priv->active_rate_basic & + (IWL_OFDM_BASIC_RATES_MASK | IWL_RATE_6M_MASK)) >> + IWL_FIRST_OFDM_RATE) & 0xFF; + else + priv->staging_rxon.ofdm_basic_rates = + (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF; +} + +static void iwl_radio_kill_sw(struct iwl_priv *priv, int disable_radio) +{ + unsigned long flags; + + if (!!disable_radio == test_bit(STATUS_RF_KILL_SW, &priv->status)) + return; + + IWL_DEBUG_RF_KILL("Manual SW RF KILL set to: RADIO %s\n", + disable_radio ? "OFF" : "ON"); + + if (disable_radio) { + iwl_scan_cancel(priv); + /* FIXME: This is a workaround for AP */ + if (priv->iw_mode != IEEE80211_IF_TYPE_AP) { + spin_lock_irqsave(&priv->lock, flags); + iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, + CSR_UCODE_SW_BIT_RFKILL); + spin_unlock_irqrestore(&priv->lock, flags); + iwl_send_card_state(priv, CARD_STATE_CMD_DISABLE, 0); + set_bit(STATUS_RF_KILL_SW, &priv->status); + } + return; + } + + spin_lock_irqsave(&priv->lock, flags); + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + + clear_bit(STATUS_RF_KILL_SW, &priv->status); + spin_unlock_irqrestore(&priv->lock, flags); + + /* wake up ucode */ + msleep(10); + + spin_lock_irqsave(&priv->lock, flags); + iwl_read32(priv, CSR_UCODE_DRV_GP1); + if (!iwl_grab_restricted_access(priv)) + iwl_release_restricted_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + if (test_bit(STATUS_RF_KILL_HW, &priv->status)) { + IWL_DEBUG_RF_KILL("Can not turn radio back on - " + "disabled by HW switch\n"); + return; + } + + queue_work(priv->workqueue, &priv->restart); + return; +} + +void iwl_set_decrypted_flag(struct iwl_priv *priv, struct sk_buff *skb, + u32 decrypt_res, struct ieee80211_rx_status *stats) +{ + u16 fc = + le16_to_cpu(((struct ieee80211_hdr *)skb->data)->frame_control); + + if (priv->active_rxon.filter_flags & RXON_FILTER_DIS_DECRYPT_MSK) + return; + + if (!(fc & IEEE80211_FCTL_PROTECTED)) + return; + + IWL_DEBUG_RX("decrypt_res:0x%x\n", decrypt_res); + switch (decrypt_res & RX_RES_STATUS_SEC_TYPE_MSK) { + case RX_RES_STATUS_SEC_TYPE_TKIP: + if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == + RX_RES_STATUS_BAD_ICV_MIC) + stats->flag |= RX_FLAG_MMIC_ERROR; + case RX_RES_STATUS_SEC_TYPE_WEP: + case RX_RES_STATUS_SEC_TYPE_CCMP: + if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == + RX_RES_STATUS_DECRYPT_OK) { + IWL_DEBUG_RX("hw decrypt successfully!!!\n"); + stats->flag |= RX_FLAG_DECRYPTED; + } + break; + + default: + break; + } +} + +void iwl_handle_data_packet_monitor(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb, + void *data, short len, + struct ieee80211_rx_status *stats, + u16 phy_flags) +{ + struct iwl_rt_rx_hdr *iwl_rt; + + /* First cache any information we need before we overwrite + * the information provided in the skb from the hardware */ + s8 signal = stats->ssi; + s8 noise = 0; + int rate = stats->rate; + u64 tsf = stats->mactime; + __le16 phy_flags_hw = cpu_to_le16(phy_flags); + + /* We received data from the HW, so stop the watchdog */ + if (len > IWL_RX_BUF_SIZE - sizeof(*iwl_rt)) { + IWL_DEBUG_DROP("Dropping too large packet in monitor\n"); + return; + } + + /* copy the frame data to write after where the radiotap header goes */ + iwl_rt = (void *)rxb->skb->data; + memmove(iwl_rt->payload, data, len); + + iwl_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; + iwl_rt->rt_hdr.it_pad = 0; /* always good to zero */ + + /* total header + data */ + iwl_rt->rt_hdr.it_len = cpu_to_le16(sizeof(*iwl_rt)); + + /* Set the size of the skb to the size of the frame */ + skb_put(rxb->skb, sizeof(*iwl_rt) + len); + + /* Big bitfield of all the fields we provide in radiotap */ + iwl_rt->rt_hdr.it_present = + cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) | + (1 << IEEE80211_RADIOTAP_FLAGS) | + (1 << IEEE80211_RADIOTAP_RATE) | + (1 << IEEE80211_RADIOTAP_CHANNEL) | + (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | + (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | + (1 << IEEE80211_RADIOTAP_ANTENNA)); + + /* Zero the flags, we'll add to them as we go */ + iwl_rt->rt_flags = 0; + + iwl_rt->rt_tsf = cpu_to_le64(tsf); + + /* Convert to dBm */ + iwl_rt->rt_dbmsignal = signal; + iwl_rt->rt_dbmnoise = noise; + + /* Convert the channel frequency and set the flags */ + iwl_rt->rt_channelMHz = cpu_to_le16(stats->freq); + if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK)) + iwl_rt->rt_chbitmask = + cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ)); + else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK) + iwl_rt->rt_chbitmask = + cpu_to_le16((IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ)); + else /* 802.11g */ + iwl_rt->rt_chbitmask = + cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ)); + + rate = iwl_rate_index_from_plcp(rate); + if (rate == -1) + iwl_rt->rt_rate = 0; + else + iwl_rt->rt_rate = iwl_rates[rate].ieee; + + /* antenna number */ + iwl_rt->rt_antenna = + le16_to_cpu(phy_flags_hw & RX_RES_PHY_FLAGS_ANTENNA_MSK) >> 4; + + /* set the preamble flag if we have it */ + if (phy_flags_hw & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) + iwl_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; + + IWL_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len); + + stats->flag |= RX_FLAG_RADIOTAP; + ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats); + rxb->skb = NULL; +} + + +#define IWL_PACKET_RETRY_TIME HZ + +int is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header) +{ + u16 sc = le16_to_cpu(header->seq_ctrl); + u16 seq = (sc & IEEE80211_SCTL_SEQ) >> 4; + u16 frag = sc & IEEE80211_SCTL_FRAG; + u16 *last_seq, *last_frag; + unsigned long *last_time; + + switch (priv->iw_mode) { + case IEEE80211_IF_TYPE_IBSS:{ + struct list_head *p; + struct iwl_ibss_seq *entry = NULL; + u8 *mac = header->addr2; + int index = mac[5] & (IWL_IBSS_MAC_HASH_SIZE - 1); + + __list_for_each(p, &priv->ibss_mac_hash[index]) { + entry = + list_entry(p, struct iwl_ibss_seq, list); + if (!compare_ether_addr(entry->mac, mac)) + break; + } + if (p == &priv->ibss_mac_hash[index]) { + entry = kzalloc(sizeof(*entry), GFP_ATOMIC); + if (!entry) { + IWL_ERROR + ("Cannot malloc new mac entry\n"); + return 0; + } + memcpy(entry->mac, mac, ETH_ALEN); + entry->seq_num = seq; + entry->frag_num = frag; + entry->packet_time = jiffies; + list_add(&entry->list, + &priv->ibss_mac_hash[index]); + return 0; + } + last_seq = &entry->seq_num; + last_frag = &entry->frag_num; + last_time = &entry->packet_time; + break; + } + case IEEE80211_IF_TYPE_STA: + last_seq = &priv->last_seq_num; + last_frag = &priv->last_frag_num; + last_time = &priv->last_packet_time; + break; + default: + return 0; + } + if ((*last_seq == seq) && + time_after(*last_time + IWL_PACKET_RETRY_TIME, jiffies)) { + if (*last_frag == frag) + goto drop; + if (*last_frag + 1 != frag) + /* out-of-order fragment */ + goto drop; + } else + *last_seq = seq; + + *last_frag = frag; + *last_time = jiffies; + return 0; + + drop: + return 1; +} + +#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT + +#include "iwl-spectrum.h" + +#define BEACON_TIME_MASK_LOW 0x00FFFFFF +#define BEACON_TIME_MASK_HIGH 0xFF000000 +#define TIME_UNIT 1024 + +/* + * extended beacon time format + * time in usec will be changed into a 32-bit value in 8:24 format + * the high 1 byte is the beacon counts + * the lower 3 bytes is the time in usec within one beacon interval + */ + +static u32 iwl_usecs_to_beacons(u32 usec, u32 beacon_interval) +{ + u32 quot; + u32 rem; + u32 interval = beacon_interval * 1024; + + if (!interval || !usec) + return 0; + + quot = (usec / interval) & (BEACON_TIME_MASK_HIGH >> 24); + rem = (usec % interval) & BEACON_TIME_MASK_LOW; + + return (quot << 24) + rem; +} + +/* base is usually what we get from ucode with each received frame, + * the same as HW timer counter counting down + */ + +static __le32 iwl_add_beacon_time(u32 base, u32 addon, u32 beacon_interval) +{ + u32 base_low = base & BEACON_TIME_MASK_LOW; + u32 addon_low = addon & BEACON_TIME_MASK_LOW; + u32 interval = beacon_interval * TIME_UNIT; + u32 res = (base & BEACON_TIME_MASK_HIGH) + + (addon & BEACON_TIME_MASK_HIGH); + + if (base_low > addon_low) + res += base_low - addon_low; + else if (base_low < addon_low) { + res += interval + base_low - addon_low; + res += (1 << 24); + } else + res += (1 << 24); + + return cpu_to_le32(res); +} + +static int iwl_get_measurement(struct iwl_priv *priv, + struct ieee80211_measurement_params *params, + u8 type) +{ + struct iwl_spectrum_cmd spectrum; + struct iwl_rx_packet *res; + struct iwl_host_cmd cmd = { + .id = REPLY_SPECTRUM_MEASUREMENT_CMD, + .data = (void *)&spectrum, + .meta.flags = CMD_WANT_SKB, + }; + u32 add_time = le64_to_cpu(params->start_time); + int rc; + int spectrum_resp_status; + int duration = le16_to_cpu(params->duration); + + if (iwl_is_associated(priv)) + add_time = + iwl_usecs_to_beacons( + le64_to_cpu(params->start_time) - priv->last_tsf, + le16_to_cpu(priv->rxon_timing.beacon_interval)); + + memset(&spectrum, 0, sizeof(spectrum)); + + spectrum.channel_count = cpu_to_le16(1); + spectrum.flags = + RXON_FLG_TSF2HOST_MSK | RXON_FLG_ANT_A_MSK | RXON_FLG_DIS_DIV_MSK; + spectrum.filter_flags = MEASUREMENT_FILTER_FLAG; + cmd.len = sizeof(spectrum); + spectrum.len = cpu_to_le16(cmd.len - sizeof(spectrum.len)); + + if (iwl_is_associated(priv)) + spectrum.start_time = + iwl_add_beacon_time(priv->last_beacon_time, + add_time, + le16_to_cpu(priv->rxon_timing.beacon_interval)); + else + spectrum.start_time = 0; + + spectrum.channels[0].duration = cpu_to_le32(duration * TIME_UNIT); + spectrum.channels[0].channel = params->channel; + spectrum.channels[0].type = type; + if (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK) + spectrum.flags |= RXON_FLG_BAND_24G_MSK | + RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK; + + rc = iwl_send_cmd_sync(priv, &cmd); + if (rc) + return rc; + + res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; + if (res->hdr.flags & IWL_CMD_FAILED_MSK) { + IWL_ERROR("Bad return from REPLY_RX_ON_ASSOC command\n"); + rc = -EIO; + } + + spectrum_resp_status = le16_to_cpu(res->u.spectrum.status); + switch (spectrum_resp_status) { + case 0: /* Command will be handled */ + if (res->u.spectrum.id != 0xff) { + IWL_DEBUG_INFO + ("Replaced existing measurement: %d\n", + res->u.spectrum.id); + priv->measurement_status &= ~MEASUREMENT_READY; + } + priv->measurement_status |= MEASUREMENT_ACTIVE; + rc = 0; + break; + + case 1: /* Command will not be handled */ + rc = -EAGAIN; + break; + } + + dev_kfree_skb_any(cmd.meta.u.skb); + + return rc; +} +#endif + +static void iwl_txstatus_to_ieee(struct iwl_priv *priv, + struct iwl_tx_info *tx_sta) +{ + + tx_sta->status.ack_signal = 0; + tx_sta->status.excessive_retries = 0; + tx_sta->status.queue_length = 0; + tx_sta->status.queue_number = 0; + + if (in_interrupt()) + ieee80211_tx_status_irqsafe(priv->hw, + tx_sta->skb[0], &(tx_sta->status)); + else + ieee80211_tx_status(priv->hw, + tx_sta->skb[0], &(tx_sta->status)); + + tx_sta->skb[0] = NULL; +} + +/** + * iwl_tx_queue_reclaim - Reclaim Tx queue entries no more used by NIC. + * + * When FW advances 'R' index, all entries between old and + * new 'R' index need to be reclaimed. As result, some free space + * forms. If there is enough free space (> low mark), wake Tx queue. + */ +int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) +{ + struct iwl_tx_queue *txq = &priv->txq[txq_id]; + struct iwl_queue *q = &txq->q; + int nfreed = 0; + + if ((index >= q->n_bd) || (x2_queue_used(q, index) == 0)) { + IWL_ERROR("Read index for DMA queue txq id (%d), index %d, " + "is out of range [0-%d] %d %d.\n", txq_id, + index, q->n_bd, q->first_empty, q->last_used); + return 0; + } + + for (index = iwl_queue_inc_wrap(index, q->n_bd); + q->last_used != index; + q->last_used = iwl_queue_inc_wrap(q->last_used, q->n_bd)) { + if (txq_id != IWL_CMD_QUEUE_NUM) { + iwl_txstatus_to_ieee(priv, + &(txq->txb[txq->q.last_used])); + iwl_hw_txq_free_tfd(priv, txq); + } else if (nfreed > 1) { + IWL_ERROR("HCMD skipped: index (%d) %d %d\n", index, + q->first_empty, q->last_used); + queue_work(priv->workqueue, &priv->restart); + } + nfreed++; + } + + if (iwl_queue_space(q) > q->low_mark && (txq_id >= 0) && + (txq_id != IWL_CMD_QUEUE_NUM) && + priv->mac80211_registered) + ieee80211_wake_queue(priv->hw, txq_id); + + + return nfreed; +} + +static int iwl_is_tx_success(u32 status) +{ + return (status & 0xFF) == 0x1; +} + +/****************************************************************************** + * + * Generic RX handler implementations + * + ******************************************************************************/ +static void iwl_rx_reply_tx(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + u16 sequence = le16_to_cpu(pkt->hdr.sequence); + int txq_id = SEQ_TO_QUEUE(sequence); + int index = SEQ_TO_INDEX(sequence); + struct iwl_tx_queue *txq = &priv->txq[txq_id]; + struct ieee80211_tx_status *tx_status; + struct iwl_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; + u32 status = le32_to_cpu(tx_resp->status); + + if ((index >= txq->q.n_bd) || (x2_queue_used(&txq->q, index) == 0)) { + IWL_ERROR("Read index for DMA queue txq_id (%d) index %d " + "is out of range [0-%d] %d %d\n", txq_id, + index, txq->q.n_bd, txq->q.first_empty, + txq->q.last_used); + return; + } + + tx_status = &(txq->txb[txq->q.last_used].status); + + tx_status->retry_count = tx_resp->failure_frame; + tx_status->queue_number = status; + tx_status->queue_length = tx_resp->bt_kill_count; + tx_status->queue_length |= tx_resp->failure_rts; + + tx_status->flags = + iwl_is_tx_success(status) ? IEEE80211_TX_STATUS_ACK : 0; + + tx_status->control.tx_rate = iwl_rate_index_from_plcp(tx_resp->rate); + + IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) plcp rate %d retries %d\n", + txq_id, iwl_get_tx_fail_reason(status), status, + tx_resp->rate, tx_resp->failure_frame); + + IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index); + if (index != -1) + iwl_tx_queue_reclaim(priv, txq_id, index); + + if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK)) + IWL_ERROR("TODO: Implement Tx ABORT REQUIRED!!!\n"); +} + + +static void iwl_rx_reply_alive(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_alive_resp *palive; + struct delayed_work *pwork; + + palive = &pkt->u.alive_frame; + + IWL_DEBUG_INFO("Alive ucode status 0x%08X revision " + "0x%01X 0x%01X\n", + palive->is_valid, palive->ver_type, + palive->ver_subtype); + + if (palive->ver_subtype == INITIALIZE_SUBTYPE) { + IWL_DEBUG_INFO("Initialization Alive received.\n"); + memcpy(&priv->card_alive_init, + &pkt->u.alive_frame, + sizeof(struct iwl_init_alive_resp)); + pwork = &priv->init_alive_start; + } else { + IWL_DEBUG_INFO("Runtime Alive received.\n"); + memcpy(&priv->card_alive, &pkt->u.alive_frame, + sizeof(struct iwl_alive_resp)); + pwork = &priv->alive_start; + iwl_disable_events(priv); + } + + /* We delay the ALIVE response by 5ms to + * give the HW RF Kill time to activate... */ + if (palive->is_valid == UCODE_VALID_OK) + queue_delayed_work(priv->workqueue, pwork, + msecs_to_jiffies(5)); + else + IWL_WARNING("uCode did not respond OK.\n"); +} + +static void iwl_rx_reply_add_sta(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + + IWL_DEBUG_RX("Received REPLY_ADD_STA: 0x%02X\n", pkt->u.status); + return; +} + +static void iwl_rx_reply_error(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + + IWL_ERROR("Error Reply type 0x%08X cmd %s (0x%02X) " + "seq 0x%04X ser 0x%08X\n", + le32_to_cpu(pkt->u.err_resp.error_type), + get_cmd_string(pkt->u.err_resp.cmd_id), + pkt->u.err_resp.cmd_id, + le16_to_cpu(pkt->u.err_resp.bad_cmd_seq_num), + le32_to_cpu(pkt->u.err_resp.error_info)); +} + +#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x + +static void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon; + struct iwl_csa_notification *csa = &(pkt->u.csa_notif); + IWL_DEBUG_11H("CSA notif: channel %d, status %d\n", + le16_to_cpu(csa->channel), le32_to_cpu(csa->status)); + rxon->channel = csa->channel; + priv->staging_rxon.channel = csa->channel; +} + +static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ +#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_spectrum_notification *report = &(pkt->u.spectrum_notif); + + if (!report->state) { + IWL_DEBUG(IWL_DL_11H | IWL_DL_INFO, + "Spectrum Measure Notification: Start\n"); + return; + } + + memcpy(&priv->measure_report, report, sizeof(*report)); + priv->measurement_status |= MEASUREMENT_READY; +#endif +} + +static void iwl_rx_pm_sleep_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ +#ifdef CONFIG_IWLWIFI_DEBUG + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_sleep_notification *sleep = &(pkt->u.sleep_notif); + IWL_DEBUG_RX("sleep mode: %d, src: %d\n", + sleep->pm_sleep_mode, sleep->pm_wakeup_src); +#endif +} + +static void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + IWL_DEBUG_RADIO("Dumping %d bytes of unhandled " + "notification for %s:\n", + le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd)); + iwl_print_hex_dump(IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len)); +} + +static void iwl_bg_beacon_update(struct work_struct *work) +{ + struct iwl_priv *priv = + container_of(work, struct iwl_priv, beacon_update); + struct sk_buff *beacon; + + /* Pull updated AP beacon from mac80211. will fail if not in AP mode */ + beacon = ieee80211_beacon_get(priv->hw, priv->interface_id, NULL); + + if (!beacon) { + IWL_ERROR("update beacon failed\n"); + return; + } + + mutex_lock(&priv->mutex); + /* new beacon skb is allocated every time; dispose previous.*/ + if (priv->ibss_beacon) + dev_kfree_skb(priv->ibss_beacon); + + priv->ibss_beacon = beacon; + mutex_unlock(&priv->mutex); + + iwl_send_beacon_cmd(priv); +} + +static void iwl_rx_beacon_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ +#ifdef CONFIG_IWLWIFI_DEBUG + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_beacon_notif *beacon = &(pkt->u.beacon_status); + u8 rate = beacon->beacon_notify_hdr.rate; + + IWL_DEBUG_RX("beacon status %x retries %d iss %d " + "tsf %d %d rate %d\n", + le32_to_cpu(beacon->beacon_notify_hdr.status) & TX_STATUS_MSK, + beacon->beacon_notify_hdr.failure_frame, + le32_to_cpu(beacon->ibss_mgr_status), + le32_to_cpu(beacon->high_tsf), + le32_to_cpu(beacon->low_tsf), rate); +#endif + + if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) && + (!test_bit(STATUS_EXIT_PENDING, &priv->status))) + queue_work(priv->workqueue, &priv->beacon_update); +} + +/* Service response to REPLY_SCAN_CMD (0x80) */ +static void iwl_rx_reply_scan(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ +#ifdef CONFIG_IWLWIFI_DEBUG + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_scanreq_notification *notif = + (struct iwl_scanreq_notification *)pkt->u.raw; + + IWL_DEBUG_RX("Scan request status = 0x%x\n", notif->status); +#endif +} + +/* Service SCAN_START_NOTIFICATION (0x82) */ +static void iwl_rx_scan_start_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_scanstart_notification *notif = + (struct iwl_scanstart_notification *)pkt->u.raw; + priv->scan_start_tsf = le32_to_cpu(notif->tsf_low); + IWL_DEBUG_SCAN("Scan start: " + "%d [802.11%s] " + "(TSF: 0x%08X:%08X) - %d (beacon timer %u)\n", + notif->channel, + notif->band ? "bg" : "a", + notif->tsf_high, + notif->tsf_low, notif->status, notif->beacon_timer); +} + +/* Service SCAN_RESULTS_NOTIFICATION (0x83) */ +static void iwl_rx_scan_results_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_scanresults_notification *notif = + (struct iwl_scanresults_notification *)pkt->u.raw; + + IWL_DEBUG_SCAN("Scan ch.res: " + "%d [802.11%s] " + "(TSF: 0x%08X:%08X) - %d " + "elapsed=%lu usec (%dms since last)\n", + notif->channel, + notif->band ? "bg" : "a", + le32_to_cpu(notif->tsf_high), + le32_to_cpu(notif->tsf_low), + le32_to_cpu(notif->statistics[0]), + le32_to_cpu(notif->tsf_low) - priv->scan_start_tsf, + jiffies_to_msecs(elapsed_jiffies + (priv->last_scan_jiffies, jiffies))); + + priv->last_scan_jiffies = jiffies; +} + +/* Service SCAN_COMPLETE_NOTIFICATION (0x84) */ +static void iwl_rx_scan_complete_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_scancomplete_notification *scan_notif = (void *)pkt->u.raw; + + IWL_DEBUG_SCAN("Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n", + scan_notif->scanned_channels, + scan_notif->tsf_low, + scan_notif->tsf_high, scan_notif->status); + + /* The HW is no longer scanning */ + clear_bit(STATUS_SCAN_HW, &priv->status); + + /* The scan completion notification came in, so kill that timer... */ + cancel_delayed_work(&priv->scan_check); + + IWL_DEBUG_INFO("Scan pass on %sGHz took %dms\n", + (priv->scan_bands == 2) ? "2.4" : "5.2", + jiffies_to_msecs(elapsed_jiffies + (priv->scan_pass_start, jiffies))); + + /* Remove this scanned band from the list + * of pending bands to scan */ + priv->scan_bands--; + + /* If a request to abort was given, or the scan did not succeed + * then we reset the scan state machine and terminate, + * re-queuing another scan if one has been requested */ + if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { + IWL_DEBUG_INFO("Aborted scan completed.\n"); + clear_bit(STATUS_SCAN_ABORTING, &priv->status); + } else { + /* If there are more bands on this scan pass reschedule */ + if (priv->scan_bands > 0) + goto reschedule; + } + + priv->last_scan_jiffies = jiffies; + IWL_DEBUG_INFO("Setting scan to off\n"); + + clear_bit(STATUS_SCANNING, &priv->status); + + IWL_DEBUG_INFO("Scan took %dms\n", + jiffies_to_msecs(elapsed_jiffies(priv->scan_start, jiffies))); + + queue_work(priv->workqueue, &priv->scan_completed); + + return; + +reschedule: + priv->scan_pass_start = jiffies; + queue_work(priv->workqueue, &priv->request_scan); +} + +/* Handle notification from uCode that card's power state is changing + * due to software, hardware, or critical temperature RFKILL */ +static void iwl_rx_card_state_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags); + unsigned long status = priv->status; + + IWL_DEBUG_RF_KILL("Card state received: HW:%s SW:%s\n", + (flags & HW_CARD_DISABLED) ? "Kill" : "On", + (flags & SW_CARD_DISABLED) ? "Kill" : "On"); + + iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, + CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); + + if (flags & HW_CARD_DISABLED) + set_bit(STATUS_RF_KILL_HW, &priv->status); + else + clear_bit(STATUS_RF_KILL_HW, &priv->status); + + + if (flags & SW_CARD_DISABLED) + set_bit(STATUS_RF_KILL_SW, &priv->status); + else + clear_bit(STATUS_RF_KILL_SW, &priv->status); + + iwl_scan_cancel(priv); + + if ((test_bit(STATUS_RF_KILL_HW, &status) != + test_bit(STATUS_RF_KILL_HW, &priv->status)) || + (test_bit(STATUS_RF_KILL_SW, &status) != + test_bit(STATUS_RF_KILL_SW, &priv->status))) + queue_work(priv->workqueue, &priv->rf_kill); + else + wake_up_interruptible(&priv->wait_command_queue); +} + +/** + * iwl_setup_rx_handlers - Initialize Rx handler callbacks + * + * Setup the RX handlers for each of the reply types sent from the uCode + * to the host. + * + * This function chains into the hardware specific files for them to setup + * any hardware specific handlers as well. + */ +static void iwl_setup_rx_handlers(struct iwl_priv *priv) +{ + priv->rx_handlers[REPLY_ALIVE] = iwl_rx_reply_alive; + priv->rx_handlers[REPLY_ADD_STA] = iwl_rx_reply_add_sta; + priv->rx_handlers[REPLY_ERROR] = iwl_rx_reply_error; + priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa; + priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] = + iwl_rx_spectrum_measure_notif; + priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl_rx_pm_sleep_notif; + priv->rx_handlers[PM_DEBUG_STATISTIC_NOTIFIC] = + iwl_rx_pm_debug_statistics_notif; + priv->rx_handlers[BEACON_NOTIFICATION] = iwl_rx_beacon_notif; + + /* NOTE: iwl_rx_statistics is different based on whether + * the build is for the 3945 or the 4965. See the + * corresponding implementation in iwl-XXXX.c + * + * The same handler is used for both the REPLY to a + * discrete statistics request from the host as well as + * for the periodic statistics notification from the uCode + */ + priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl_hw_rx_statistics; + priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl_hw_rx_statistics; + + priv->rx_handlers[REPLY_SCAN_CMD] = iwl_rx_reply_scan; + priv->rx_handlers[SCAN_START_NOTIFICATION] = iwl_rx_scan_start_notif; + priv->rx_handlers[SCAN_RESULTS_NOTIFICATION] = + iwl_rx_scan_results_notif; + priv->rx_handlers[SCAN_COMPLETE_NOTIFICATION] = + iwl_rx_scan_complete_notif; + priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl_rx_card_state_notif; + priv->rx_handlers[REPLY_TX] = iwl_rx_reply_tx; + + /* Setup hardware specific Rx handlers */ + iwl_hw_rx_handler_setup(priv); +} + +/** + * iwl_tx_cmd_complete - Pull unused buffers off the queue and reclaim them + * @rxb: Rx buffer to reclaim + * + * If an Rx buffer has an async callback associated with it the callback + * will be executed. The attached skb (if present) will only be freed + * if the callback returns 1 + */ +static void iwl_tx_cmd_complete(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + u16 sequence = le16_to_cpu(pkt->hdr.sequence); + int txq_id = SEQ_TO_QUEUE(sequence); + int index = SEQ_TO_INDEX(sequence); + int huge = sequence & SEQ_HUGE_FRAME; + int cmd_index; + struct iwl_cmd *cmd; + + /* If a Tx command is being handled and it isn't in the actual + * command queue then there a command routing bug has been introduced + * in the queue management code. */ + if (txq_id != IWL_CMD_QUEUE_NUM) + IWL_ERROR("Error wrong command queue %d command id 0x%X\n", + txq_id, pkt->hdr.cmd); + BUG_ON(txq_id != IWL_CMD_QUEUE_NUM); + + cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge); + cmd = &priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index]; + + /* Input error checking is done when commands are added to queue. */ + if (cmd->meta.flags & CMD_WANT_SKB) { + cmd->meta.source->u.skb = rxb->skb; + rxb->skb = NULL; + } else if (cmd->meta.u.callback && + !cmd->meta.u.callback(priv, cmd, rxb->skb)) + rxb->skb = NULL; + + iwl_tx_queue_reclaim(priv, txq_id, index); + + if (!(cmd->meta.flags & CMD_ASYNC)) { + clear_bit(STATUS_HCMD_ACTIVE, &priv->status); + wake_up_interruptible(&priv->wait_command_queue); + } +} + +/************************** RX-FUNCTIONS ****************************/ +/* + * Rx theory of operation + * + * The host allocates 32 DMA target addresses and passes the host address + * to the firmware at register IWL_RFDS_TABLE_LOWER + N * RFD_SIZE where N is + * 0 to 31 + * + * Rx Queue Indexes + * The host/firmware share two index registers for managing the Rx buffers. + * + * The READ index maps to the first position that the firmware may be writing + * to -- the driver can read up to (but not including) this position and get + * good data. + * The READ index is managed by the firmware once the card is enabled. + * + * The WRITE index maps to the last position the driver has read from -- the + * position preceding WRITE is the last slot the firmware can place a packet. + * + * The queue is empty (no good data) if WRITE = READ - 1, and is full if + * WRITE = READ. + * + * During initialization the host sets up the READ queue position to the first + * INDEX position, and WRITE to the last (READ - 1 wrapped) + * + * When the firmware places a packet in a buffer it will advance the READ index + * and fire the RX interrupt. The driver can then query the READ index and + * process as many packets as possible, moving the WRITE index forward as it + * resets the Rx queue buffers with new memory. + * + * The management in the driver is as follows: + * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free. When + * iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled + * to replensish the iwl->rxq->rx_free. + * + In iwl_rx_replenish (scheduled) if 'processed' != 'read' then the + * iwl->rxq is replenished and the READ INDEX is updated (updating the + * 'processed' and 'read' driver indexes as well) + * + A received packet is processed and handed to the kernel network stack, + * detached from the iwl->rxq. The driver 'processed' index is updated. + * + The Host/Firmware iwl->rxq is replenished at tasklet time from the rx_free + * list. If there are no allocated buffers in iwl->rxq->rx_free, the READ + * INDEX is not incremented and iwl->status(RX_STALLED) is set. If there + * were enough free buffers and RX_STALLED is set it is cleared. + * + * + * Driver sequence: + * + * iwl_rx_queue_alloc() Allocates rx_free + * iwl_rx_replenish() Replenishes rx_free list from rx_used, and calls + * iwl_rx_queue_restock + * iwl_rx_queue_restock() Moves available buffers from rx_free into Rx + * queue, updates firmware pointers, and updates + * the WRITE index. If insufficient rx_free buffers + * are available, schedules iwl_rx_replenish + * + * -- enable interrupts -- + * ISR - iwl_rx() Detach iwl_rx_mem_buffers from pool up to the + * READ INDEX, detaching the SKB from the pool. + * Moves the packet buffer from queue to rx_used. + * Calls iwl_rx_queue_restock to refill any empty + * slots. + * ... + * + */ + +/** + * iwl_rx_queue_space - Return number of free slots available in queue. + */ +static int iwl_rx_queue_space(const struct iwl_rx_queue *q) +{ + int s = q->read - q->write; + if (s <= 0) + s += RX_QUEUE_SIZE; + /* keep some buffer to not confuse full and empty queue */ + s -= 2; + if (s < 0) + s = 0; + return s; +} + +/** + * iwl_rx_queue_update_write_ptr - Update the write pointer for the RX queue + * + * NOTE: This function has 3945 and 4965 specific code sections + * but is declared in base due to the majority of the + * implementation being the same (only a numeric constant is + * different) + * + */ +int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q) +{ + u32 reg = 0; + int rc = 0; + unsigned long flags; + + spin_lock_irqsave(&q->lock, flags); + + if (q->need_update == 0) + goto exit_unlock; + + if (test_bit(STATUS_POWER_PMI, &priv->status)) { + reg = iwl_read32(priv, CSR_UCODE_DRV_GP1); + + if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { + iwl_set_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + goto exit_unlock; + } + + rc = iwl_grab_restricted_access(priv); + if (rc) + goto exit_unlock; + + iwl_write_restricted(priv, FH_RSCSR_CHNL0_WPTR, + q->write & ~0x7); + iwl_release_restricted_access(priv); + } else + iwl_write32(priv, FH_RSCSR_CHNL0_WPTR, q->write & ~0x7); + + + q->need_update = 0; + + exit_unlock: + spin_unlock_irqrestore(&q->lock, flags); + return rc; +} + +/** + * iwl_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer pointer. + * + * NOTE: This function has 3945 and 4965 specific code paths in it. + */ +static inline __le32 iwl_dma_addr2rbd_ptr(struct iwl_priv *priv, + dma_addr_t dma_addr) +{ + return cpu_to_le32((u32)dma_addr); +} + +/** + * iwl_rx_queue_restock - refill RX queue from pre-allocated pool + * + * If there are slots in the RX queue that need to be restocked, + * and we have free pre-allocated buffers, fill the ranks as much + * as we can pulling from rx_free. + * + * This moves the 'write' index forward to catch up with 'processed', and + * also updates the memory address in the firmware to reference the new + * target buffer. + */ +int iwl_rx_queue_restock(struct iwl_priv *priv) +{ + struct iwl_rx_queue *rxq = &priv->rxq; + struct list_head *element; + struct iwl_rx_mem_buffer *rxb; + unsigned long flags; + int write, rc; + + spin_lock_irqsave(&rxq->lock, flags); + write = rxq->write & ~0x7; + while ((iwl_rx_queue_space(rxq) > 0) && (rxq->free_count)) { + element = rxq->rx_free.next; + rxb = list_entry(element, struct iwl_rx_mem_buffer, list); + list_del(element); + rxq->bd[rxq->write] = iwl_dma_addr2rbd_ptr(priv, rxb->dma_addr); + rxq->queue[rxq->write] = rxb; + rxq->write = (rxq->write + 1) & RX_QUEUE_MASK; + rxq->free_count--; + } + spin_unlock_irqrestore(&rxq->lock, flags); + /* If the pre-allocated buffer pool is dropping low, schedule to + * refill it */ + if (rxq->free_count <= RX_LOW_WATERMARK) + queue_work(priv->workqueue, &priv->rx_replenish); + + + /* If we've added more space for the firmware to place data, tell it */ + if ((write != (rxq->write & ~0x7)) + || (abs(rxq->write - rxq->read) > 7)) { + spin_lock_irqsave(&rxq->lock, flags); + rxq->need_update = 1; + spin_unlock_irqrestore(&rxq->lock, flags); + rc = iwl_rx_queue_update_write_ptr(priv, rxq); + if (rc) + return rc; + } + + return 0; +} + +/** + * iwl_rx_replensih - Move all used packet from rx_used to rx_free + * + * When moving to rx_free an SKB is allocated for the slot. + * + * Also restock the Rx queue via iwl_rx_queue_restock. + * This is called as a scheduled work item (except for during intialization) + */ +void iwl_rx_replenish(void *data) +{ + struct iwl_priv *priv = data; + struct iwl_rx_queue *rxq = &priv->rxq; + struct list_head *element; + struct iwl_rx_mem_buffer *rxb; + unsigned long flags; + spin_lock_irqsave(&rxq->lock, flags); + while (!list_empty(&rxq->rx_used)) { + element = rxq->rx_used.next; + rxb = list_entry(element, struct iwl_rx_mem_buffer, list); + rxb->skb = + alloc_skb(IWL_RX_BUF_SIZE, __GFP_NOWARN | GFP_ATOMIC); + if (!rxb->skb) { + if (net_ratelimit()) + printk(KERN_CRIT DRV_NAME + ": Can not allocate SKB buffers\n"); + /* We don't reschedule replenish work here -- we will + * call the restock method and if it still needs + * more buffers it will schedule replenish */ + break; + } + priv->alloc_rxb_skb++; + list_del(element); + rxb->dma_addr = + pci_map_single(priv->pci_dev, rxb->skb->data, + IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + list_add_tail(&rxb->list, &rxq->rx_free); + rxq->free_count++; + } + spin_unlock_irqrestore(&rxq->lock, flags); + + spin_lock_irqsave(&priv->lock, flags); + iwl_rx_queue_restock(priv); + spin_unlock_irqrestore(&priv->lock, flags); +} + +/* Assumes that the skb field of the buffers in 'pool' is kept accurate. + * If an SKB has been detached, the POOL needs to have it's SKB set to NULL + * This free routine walks the list of POOL entries and if SKB is set to + * non NULL it is unmapped and freed + */ +void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq) +{ + int i; + for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) { + if (rxq->pool[i].skb != NULL) { + pci_unmap_single(priv->pci_dev, + rxq->pool[i].dma_addr, + IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + dev_kfree_skb(rxq->pool[i].skb); + } + } + + pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd, + rxq->dma_addr); + rxq->bd = NULL; +} + +int iwl_rx_queue_alloc(struct iwl_priv *priv) +{ + struct iwl_rx_queue *rxq = &priv->rxq; + struct pci_dev *dev = priv->pci_dev; + int i; + + spin_lock_init(&rxq->lock); + INIT_LIST_HEAD(&rxq->rx_free); + INIT_LIST_HEAD(&rxq->rx_used); + rxq->bd = pci_alloc_consistent(dev, 4 * RX_QUEUE_SIZE, &rxq->dma_addr); + if (!rxq->bd) + return -ENOMEM; + /* Fill the rx_used queue with _all_ of the Rx buffers */ + for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) + list_add_tail(&rxq->pool[i].list, &rxq->rx_used); + /* Set us so that we have processed and used all buffers, but have + * not restocked the Rx queue with fresh buffers */ + rxq->read = rxq->write = 0; + rxq->free_count = 0; + rxq->need_update = 0; + return 0; +} + +void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq) +{ + unsigned long flags; + int i; + spin_lock_irqsave(&rxq->lock, flags); + INIT_LIST_HEAD(&rxq->rx_free); + INIT_LIST_HEAD(&rxq->rx_used); + /* Fill the rx_used queue with _all_ of the Rx buffers */ + for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) { + /* In the reset function, these buffers may have been allocated + * to an SKB, so we need to unmap and free potential storage */ + if (rxq->pool[i].skb != NULL) { + pci_unmap_single(priv->pci_dev, + rxq->pool[i].dma_addr, + IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + priv->alloc_rxb_skb--; + dev_kfree_skb(rxq->pool[i].skb); + rxq->pool[i].skb = NULL; + } + list_add_tail(&rxq->pool[i].list, &rxq->rx_used); + } + + /* Set us so that we have processed and used all buffers, but have + * not restocked the Rx queue with fresh buffers */ + rxq->read = rxq->write = 0; + rxq->free_count = 0; + spin_unlock_irqrestore(&rxq->lock, flags); +} + +/* Convert linear signal-to-noise ratio into dB */ +static u8 ratio2dB[100] = { +/* 0 1 2 3 4 5 6 7 8 9 */ + 0, 0, 6, 10, 12, 14, 16, 17, 18, 19, /* 00 - 09 */ + 20, 21, 22, 22, 23, 23, 24, 25, 26, 26, /* 10 - 19 */ + 26, 26, 26, 27, 27, 28, 28, 28, 29, 29, /* 20 - 29 */ + 29, 30, 30, 30, 31, 31, 31, 31, 32, 32, /* 30 - 39 */ + 32, 32, 32, 33, 33, 33, 33, 33, 34, 34, /* 40 - 49 */ + 34, 34, 34, 34, 35, 35, 35, 35, 35, 35, /* 50 - 59 */ + 36, 36, 36, 36, 36, 36, 36, 37, 37, 37, /* 60 - 69 */ + 37, 37, 37, 37, 37, 38, 38, 38, 38, 38, /* 70 - 79 */ + 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, /* 80 - 89 */ + 39, 39, 39, 39, 39, 40, 40, 40, 40, 40 /* 90 - 99 */ +}; + +/* Calculates a relative dB value from a ratio of linear + * (i.e. not dB) signal levels. + * Conversion assumes that levels are voltages (20*log), not powers (10*log). */ +int iwl_calc_db_from_ratio(int sig_ratio) +{ + /* Anything above 1000:1 just report as 60 dB */ + if (sig_ratio > 1000) + return 60; + + /* Above 100:1, divide by 10 and use table, + * add 20 dB to make up for divide by 10 */ + if (sig_ratio > 100) + return (20 + (int)ratio2dB[sig_ratio/10]); + + /* We shouldn't see this */ + if (sig_ratio < 1) + return 0; + + /* Use table for ratios 1:1 - 99:1 */ + return (int)ratio2dB[sig_ratio]; +} + +#define PERFECT_RSSI (-20) /* dBm */ +#define WORST_RSSI (-95) /* dBm */ +#define RSSI_RANGE (PERFECT_RSSI - WORST_RSSI) + +/* Calculate an indication of rx signal quality (a percentage, not dBm!). + * See http://www.ces.clemson.edu/linux/signal_quality.shtml for info + * about formulas used below. */ +int iwl_calc_sig_qual(int rssi_dbm, int noise_dbm) +{ + int sig_qual; + int degradation = PERFECT_RSSI - rssi_dbm; + + /* If we get a noise measurement, use signal-to-noise ratio (SNR) + * as indicator; formula is (signal dbm - noise dbm). + * SNR at or above 40 is a great signal (100%). + * Below that, scale to fit SNR of 0 - 40 dB within 0 - 100% indicator. + * Weakest usable signal is usually 10 - 15 dB SNR. */ + if (noise_dbm) { + if (rssi_dbm - noise_dbm >= 40) + return 100; + else if (rssi_dbm < noise_dbm) + return 0; + sig_qual = ((rssi_dbm - noise_dbm) * 5) / 2; + + /* Else use just the signal level. + * This formula is a least squares fit of data points collected and + * compared with a reference system that had a percentage (%) display + * for signal quality. */ + } else + sig_qual = (100 * (RSSI_RANGE * RSSI_RANGE) - degradation * + (15 * RSSI_RANGE + 62 * degradation)) / + (RSSI_RANGE * RSSI_RANGE); + + if (sig_qual > 100) + sig_qual = 100; + else if (sig_qual < 1) + sig_qual = 0; + + return sig_qual; +} + +/** + * iwl_rx_handle - Main entry function for receiving responses from the uCode + * + * Uses the priv->rx_handlers callback function array to invoke + * the appropriate handlers, including command responses, + * frame-received notifications, and other notifications. + */ +static void iwl_rx_handle(struct iwl_priv *priv) +{ + struct iwl_rx_mem_buffer *rxb; + struct iwl_rx_packet *pkt; + struct iwl_rx_queue *rxq = &priv->rxq; + u32 r, i; + int reclaim; + unsigned long flags; + + r = iwl_hw_get_rx_read(priv); + i = rxq->read; + + /* Rx interrupt, but nothing sent from uCode */ + if (i == r) + IWL_DEBUG(IWL_DL_RX | IWL_DL_ISR, "r = %d, i = %d\n", r, i); + + while (i != r) { + rxb = rxq->queue[i]; + + /* If an RXB doesn't have a queue slot associated with it + * then a bug has been introduced in the queue refilling + * routines -- catch it here */ + BUG_ON(rxb == NULL); + + rxq->queue[i] = NULL; + + pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr, + IWL_RX_BUF_SIZE, + PCI_DMA_FROMDEVICE); + pkt = (struct iwl_rx_packet *)rxb->skb->data; + + /* Reclaim a command buffer only if this packet is a response + * to a (driver-originated) command. + * If the packet (e.g. Rx frame) originated from uCode, + * there is no command buffer to reclaim. + * Ucode should set SEQ_RX_FRAME bit if ucode-originated, + * but apparently a few don't get set; catch them here. */ + reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) && + (pkt->hdr.cmd != STATISTICS_NOTIFICATION) && + (pkt->hdr.cmd != REPLY_TX); + + /* Based on type of command response or notification, + * handle those that need handling via function in + * rx_handlers table. See iwl_setup_rx_handlers() */ + if (priv->rx_handlers[pkt->hdr.cmd]) { + IWL_DEBUG(IWL_DL_HOST_COMMAND | IWL_DL_RX | IWL_DL_ISR, + "r = %d, i = %d, %s, 0x%02x\n", r, i, + get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); + priv->rx_handlers[pkt->hdr.cmd] (priv, rxb); + } else { + /* No handling needed */ + IWL_DEBUG(IWL_DL_HOST_COMMAND | IWL_DL_RX | IWL_DL_ISR, + "r %d i %d No handler needed for %s, 0x%02x\n", + r, i, get_cmd_string(pkt->hdr.cmd), + pkt->hdr.cmd); + } + + if (reclaim) { + /* Invoke any callbacks, transfer the skb to caller, + * and fire off the (possibly) blocking iwl_send_cmd() + * as we reclaim the driver command queue */ + if (rxb && rxb->skb) + iwl_tx_cmd_complete(priv, rxb); + else + IWL_WARNING("Claim null rxb?\n"); + } + + /* For now we just don't re-use anything. We can tweak this + * later to try and re-use notification packets and SKBs that + * fail to Rx correctly */ + if (rxb->skb != NULL) { + priv->alloc_rxb_skb--; + dev_kfree_skb_any(rxb->skb); + rxb->skb = NULL; + } + + pci_unmap_single(priv->pci_dev, rxb->dma_addr, + IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + spin_lock_irqsave(&rxq->lock, flags); + list_add_tail(&rxb->list, &priv->rxq.rx_used); + spin_unlock_irqrestore(&rxq->lock, flags); + i = (i + 1) & RX_QUEUE_MASK; + } + + /* Backtrack one entry */ + priv->rxq.read = i; + iwl_rx_queue_restock(priv); +} + +int iwl_tx_queue_update_write_ptr(struct iwl_priv *priv, + struct iwl_tx_queue *txq) +{ + u32 reg = 0; + int rc = 0; + int txq_id = txq->q.id; + + if (txq->need_update == 0) + return rc; + + /* if we're trying to save power */ + if (test_bit(STATUS_POWER_PMI, &priv->status)) { + /* wake up nic if it's powered down ... + * uCode will wake up, and interrupt us again, so next + * time we'll skip this part. */ + reg = iwl_read32(priv, CSR_UCODE_DRV_GP1); + + if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { + IWL_DEBUG_INFO("Requesting wakeup, GP1 = 0x%x\n", reg); + iwl_set_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + return rc; + } + + /* restore this queue's parameters in nic hardware. */ + rc = iwl_grab_restricted_access(priv); + if (rc) + return rc; + iwl_write_restricted(priv, HBUS_TARG_WRPTR, + txq->q.first_empty | (txq_id << 8)); + iwl_release_restricted_access(priv); + + /* else not in power-save mode, uCode will never sleep when we're + * trying to tx (during RFKILL, we're not trying to tx). */ + } else + iwl_write32(priv, HBUS_TARG_WRPTR, + txq->q.first_empty | (txq_id << 8)); + + txq->need_update = 0; + + return rc; +} + +#ifdef CONFIG_IWLWIFI_DEBUG +static void iwl_print_rx_config_cmd(struct iwl_rxon_cmd *rxon) +{ + IWL_DEBUG_RADIO("RX CONFIG:\n"); + iwl_print_hex_dump(IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon)); + IWL_DEBUG_RADIO("u16 channel: 0x%x\n", le16_to_cpu(rxon->channel)); + IWL_DEBUG_RADIO("u32 flags: 0x%08X\n", le32_to_cpu(rxon->flags)); + IWL_DEBUG_RADIO("u32 filter_flags: 0x%08x\n", + le32_to_cpu(rxon->filter_flags)); + IWL_DEBUG_RADIO("u8 dev_type: 0x%x\n", rxon->dev_type); + IWL_DEBUG_RADIO("u8 ofdm_basic_rates: 0x%02x\n", + rxon->ofdm_basic_rates); + IWL_DEBUG_RADIO("u8 cck_basic_rates: 0x%02x\n", rxon->cck_basic_rates); + IWL_DEBUG_RADIO("u8[6] node_addr: " MAC_FMT "\n", + MAC_ARG(rxon->node_addr)); + IWL_DEBUG_RADIO("u8[6] bssid_addr: " MAC_FMT "\n", + MAC_ARG(rxon->bssid_addr)); + IWL_DEBUG_RADIO("u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id)); +} +#endif + +static void iwl_enable_interrupts(struct iwl_priv *priv) +{ + IWL_DEBUG_ISR("Enabling interrupts\n"); + set_bit(STATUS_INT_ENABLED, &priv->status); + iwl_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK); +} + +static inline void iwl_disable_interrupts(struct iwl_priv *priv) +{ + clear_bit(STATUS_INT_ENABLED, &priv->status); + + /* disable interrupts from uCode/NIC to host */ + iwl_write32(priv, CSR_INT_MASK, 0x00000000); + + /* acknowledge/clear/reset any interrupts still pending + * from uCode or flow handler (Rx/Tx DMA) */ + iwl_write32(priv, CSR_INT, 0xffffffff); + iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff); + IWL_DEBUG_ISR("Disabled interrupts\n"); +} + +static const char *desc_lookup(int i) +{ + switch (i) { + case 1: + return "FAIL"; + case 2: + return "BAD_PARAM"; + case 3: + return "BAD_CHECKSUM"; + case 4: + return "NMI_INTERRUPT"; + case 5: + return "SYSASSERT"; + case 6: + return "FATAL_ERROR"; + } + + return "UNKNOWN"; +} + +#define ERROR_START_OFFSET (1 * sizeof(u32)) +#define ERROR_ELEM_SIZE (7 * sizeof(u32)) + +static void iwl_dump_nic_error_log(struct iwl_priv *priv) +{ + u32 i; + u32 desc, time, count, base, data1; + u32 blink1, blink2, ilink1, ilink2; + int rc; + + base = le32_to_cpu(priv->card_alive.error_event_table_ptr); + + if (!iwl_hw_valid_rtc_data_addr(base)) { + IWL_ERROR("Not valid error log pointer 0x%08X\n", base); + return; + } + + rc = iwl_grab_restricted_access(priv); + if (rc) { + IWL_WARNING("Can not read from adapter at this time.\n"); + return; + } + + count = iwl_read_restricted_mem(priv, base); + + if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) { + IWL_ERROR("Start IWL Error Log Dump:\n"); + IWL_ERROR("Status: 0x%08lX, Config: %08X count: %d\n", + priv->status, priv->config, count); + } + + IWL_ERROR("Desc Time asrtPC blink2 " + "ilink1 nmiPC Line\n"); + for (i = ERROR_START_OFFSET; + i < (count * ERROR_ELEM_SIZE) + ERROR_START_OFFSET; + i += ERROR_ELEM_SIZE) { + desc = iwl_read_restricted_mem(priv, base + i); + time = + iwl_read_restricted_mem(priv, base + i + 1 * sizeof(u32)); + blink1 = + iwl_read_restricted_mem(priv, base + i + 2 * sizeof(u32)); + blink2 = + iwl_read_restricted_mem(priv, base + i + 3 * sizeof(u32)); + ilink1 = + iwl_read_restricted_mem(priv, base + i + 4 * sizeof(u32)); + ilink2 = + iwl_read_restricted_mem(priv, base + i + 5 * sizeof(u32)); + data1 = + iwl_read_restricted_mem(priv, base + i + 6 * sizeof(u32)); + + IWL_ERROR + ("%-13s (#%d) %010u 0x%05X 0x%05X 0x%05X 0x%05X %u\n\n", + desc_lookup(desc), desc, time, blink1, blink2, + ilink1, ilink2, data1); + } + + iwl_release_restricted_access(priv); + +} + +#define EVENT_START_OFFSET (4 * sizeof(u32)) + +/** + * iwl_print_event_log - Dump error event log to syslog + * + * NOTE: Must be called with iwl_grab_restricted_access() already obtained! + */ +static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, + u32 num_events, u32 mode) +{ + u32 i; + u32 base; /* SRAM byte address of event log header */ + u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */ + u32 ptr; /* SRAM byte address of log data */ + u32 ev, time, data; /* event log data */ + + if (num_events == 0) + return; + + base = le32_to_cpu(priv->card_alive.log_event_table_ptr); + + if (mode == 0) + event_size = 2 * sizeof(u32); + else + event_size = 3 * sizeof(u32); + + ptr = base + EVENT_START_OFFSET + (start_idx * event_size); + + /* "time" is actually "data" for mode 0 (no timestamp). + * place event id # at far right for easier visual parsing. */ + for (i = 0; i < num_events; i++) { + ev = iwl_read_restricted_mem(priv, ptr); + ptr += sizeof(u32); + time = iwl_read_restricted_mem(priv, ptr); + ptr += sizeof(u32); + if (mode == 0) + IWL_ERROR("0x%08x\t%04u\n", time, ev); /* data, ev */ + else { + data = iwl_read_restricted_mem(priv, ptr); + ptr += sizeof(u32); + IWL_ERROR("%010u\t0x%08x\t%04u\n", time, data, ev); + } + } +} + +static void iwl_dump_nic_event_log(struct iwl_priv *priv) +{ + int rc; + u32 base; /* SRAM byte address of event log header */ + u32 capacity; /* event log capacity in # entries */ + u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */ + u32 num_wraps; /* # times uCode wrapped to top of log */ + u32 next_entry; /* index of next entry to be written by uCode */ + u32 size; /* # entries that we'll print */ + + base = le32_to_cpu(priv->card_alive.log_event_table_ptr); + if (!iwl_hw_valid_rtc_data_addr(base)) { + IWL_ERROR("Invalid event log pointer 0x%08X\n", base); + return; + } + + rc = iwl_grab_restricted_access(priv); + if (rc) { + IWL_WARNING("Can not read from adapter at this time.\n"); + return; + } + + /* event log header */ + capacity = iwl_read_restricted_mem(priv, base); + mode = iwl_read_restricted_mem(priv, base + (1 * sizeof(u32))); + num_wraps = iwl_read_restricted_mem(priv, base + (2 * sizeof(u32))); + next_entry = iwl_read_restricted_mem(priv, base + (3 * sizeof(u32))); + + size = num_wraps ? capacity : next_entry; + + /* bail out if nothing in log */ + if (size == 0) { + IWL_ERROR("Start IPW Event Log Dump: nothing in log\n"); + iwl_release_restricted_access(priv); + return; + } + + IWL_ERROR("Start IPW Event Log Dump: display count %d, wraps %d\n", + size, num_wraps); + + /* if uCode has wrapped back to top of log, start at the oldest entry, + * i.e the next one that uCode would fill. */ + if (num_wraps) + iwl_print_event_log(priv, next_entry, + capacity - next_entry, mode); + + /* (then/else) start at top of log */ + iwl_print_event_log(priv, 0, next_entry, mode); + + iwl_release_restricted_access(priv); +} + +/** + * iwl_irq_handle_error - called for HW or SW error interrupt from card + */ +static void iwl_irq_handle_error(struct iwl_priv *priv) +{ + /* Set the FW error flag -- cleared on iwl_down */ + set_bit(STATUS_FW_ERROR, &priv->status); + + /* Cancel currently queued command. */ + clear_bit(STATUS_HCMD_ACTIVE, &priv->status); + +#ifdef CONFIG_IWLWIFI_DEBUG + if (iwl_debug_level & IWL_DL_FW_ERRORS) { + iwl_dump_nic_error_log(priv); + iwl_dump_nic_event_log(priv); + iwl_print_rx_config_cmd(&priv->staging_rxon); + } +#endif + + wake_up_interruptible(&priv->wait_command_queue); + + /* Keep the restart process from trying to send host + * commands by clearing the INIT status bit */ + clear_bit(STATUS_READY, &priv->status); + + if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) { + IWL_DEBUG(IWL_DL_INFO | IWL_DL_FW_ERRORS, + "Restarting adapter due to uCode error.\n"); + + if (iwl_is_associated(priv)) { + memcpy(&priv->recovery_rxon, &priv->active_rxon, + sizeof(priv->recovery_rxon)); + priv->error_recovering = 1; + } + queue_work(priv->workqueue, &priv->restart); + } +} + +static void iwl_error_recovery(struct iwl_priv *priv) +{ + unsigned long flags; + + memcpy(&priv->staging_rxon, &priv->recovery_rxon, + sizeof(priv->staging_rxon)); + priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; + iwl_commit_rxon(priv); + + iwl_rxon_add_station(priv, priv->bssid, 1); + + spin_lock_irqsave(&priv->lock, flags); + priv->assoc_id = le16_to_cpu(priv->staging_rxon.assoc_id); + priv->error_recovering = 0; + spin_unlock_irqrestore(&priv->lock, flags); +} + +static void iwl_irq_tasklet(struct iwl_priv *priv) +{ + u32 inta, handled = 0; + u32 inta_fh; + unsigned long flags; +#ifdef CONFIG_IWLWIFI_DEBUG + u32 inta_mask; +#endif + + spin_lock_irqsave(&priv->lock, flags); + + /* Ack/clear/reset pending uCode interrupts. + * Note: Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS, + * and will clear only when CSR_FH_INT_STATUS gets cleared. */ + inta = iwl_read32(priv, CSR_INT); + iwl_write32(priv, CSR_INT, inta); + + /* Ack/clear/reset pending flow-handler (DMA) interrupts. + * Any new interrupts that happen after this, either while we're + * in this tasklet, or later, will show up in next ISR/tasklet. */ + inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); + iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh); + +#ifdef CONFIG_IWLWIFI_DEBUG + if (iwl_debug_level & IWL_DL_ISR) { + inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */ + IWL_DEBUG_ISR("inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", + inta, inta_mask, inta_fh); + } +#endif + + /* Since CSR_INT and CSR_FH_INT_STATUS reads and clears are not + * atomic, make sure that inta covers all the interrupts that + * we've discovered, even if FH interrupt came in just after + * reading CSR_INT. */ + if (inta_fh & CSR_FH_INT_RX_MASK) + inta |= CSR_INT_BIT_FH_RX; + if (inta_fh & CSR_FH_INT_TX_MASK) + inta |= CSR_INT_BIT_FH_TX; + + /* Now service all interrupt bits discovered above. */ + if (inta & CSR_INT_BIT_HW_ERR) { + IWL_ERROR("Microcode HW error detected. Restarting.\n"); + + /* Tell the device to stop sending interrupts */ + iwl_disable_interrupts(priv); + + iwl_irq_handle_error(priv); + + handled |= CSR_INT_BIT_HW_ERR; + + spin_unlock_irqrestore(&priv->lock, flags); + + return; + } + +#ifdef CONFIG_IWLWIFI_DEBUG + if (iwl_debug_level & (IWL_DL_ISR)) { + /* NIC fires this, but we don't use it, redundant with WAKEUP */ + if (inta & CSR_INT_BIT_MAC_CLK_ACTV) + IWL_DEBUG_ISR("Microcode started or stopped.\n"); + + /* Alive notification via Rx interrupt will do the real work */ + if (inta & CSR_INT_BIT_ALIVE) + IWL_DEBUG_ISR("Alive interrupt\n"); + } +#endif + /* Safely ignore these bits for debug checks below */ + inta &= ~(CSR_INT_BIT_MAC_CLK_ACTV | CSR_INT_BIT_ALIVE); + + /* HW RF KILL switch toggled (4965 only) */ + if (inta & CSR_INT_BIT_RF_KILL) { + int hw_rf_kill = 0; + if (!(iwl_read32(priv, CSR_GP_CNTRL) & + CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) + hw_rf_kill = 1; + + IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL | IWL_DL_ISR, + "RF_KILL bit toggled to %s.\n", + hw_rf_kill ? "disable radio":"enable radio"); + + /* Queue restart only if RF_KILL switch was set to "kill" + * when we loaded driver, and is now set to "enable". + * After we're Alive, RF_KILL gets handled by + * iwl_rx_card_state_notif() */ + if (!hw_rf_kill && !test_bit(STATUS_ALIVE, &priv->status)) + queue_work(priv->workqueue, &priv->restart); + + handled |= CSR_INT_BIT_RF_KILL; + } + + /* Chip got too hot and stopped itself (4965 only) */ + if (inta & CSR_INT_BIT_CT_KILL) { + IWL_ERROR("Microcode CT kill error detected.\n"); + handled |= CSR_INT_BIT_CT_KILL; + } + + /* Error detected by uCode */ + if (inta & CSR_INT_BIT_SW_ERR) { + IWL_ERROR("Microcode SW error detected. Restarting 0x%X.\n", + inta); + iwl_irq_handle_error(priv); + handled |= CSR_INT_BIT_SW_ERR; + } + + /* uCode wakes up after power-down sleep */ + if (inta & CSR_INT_BIT_WAKEUP) { + IWL_DEBUG_ISR("Wakeup interrupt\n"); + iwl_rx_queue_update_write_ptr(priv, &priv->rxq); + iwl_tx_queue_update_write_ptr(priv, &priv->txq[0]); + iwl_tx_queue_update_write_ptr(priv, &priv->txq[1]); + iwl_tx_queue_update_write_ptr(priv, &priv->txq[2]); + iwl_tx_queue_update_write_ptr(priv, &priv->txq[3]); + iwl_tx_queue_update_write_ptr(priv, &priv->txq[4]); + iwl_tx_queue_update_write_ptr(priv, &priv->txq[5]); + + handled |= CSR_INT_BIT_WAKEUP; + } + + /* All uCode command responses, including Tx command responses, + * Rx "responses" (frame-received notification), and other + * notifications from uCode come through here*/ + if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) { + iwl_rx_handle(priv); + handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX); + } + + if (inta & CSR_INT_BIT_FH_TX) { + IWL_DEBUG_ISR("Tx interrupt\n"); + + iwl_write32(priv, CSR_FH_INT_STATUS, (1 << 6)); + if (!iwl_grab_restricted_access(priv)) { + iwl_write_restricted(priv, + FH_TCSR_CREDIT + (ALM_FH_SRVC_CHNL), 0x0); + iwl_release_restricted_access(priv); + } + handled |= CSR_INT_BIT_FH_TX; + } + + if (inta & ~handled) + IWL_ERROR("Unhandled INTA bits 0x%08x\n", inta & ~handled); + + if (inta & ~CSR_INI_SET_MASK) { + IWL_WARNING("Disabled INTA bits 0x%08x were pending\n", + inta & ~CSR_INI_SET_MASK); + IWL_WARNING(" with FH_INT = 0x%08x\n", inta_fh); + } + + /* Re-enable all interrupts */ + iwl_enable_interrupts(priv); + +#ifdef CONFIG_IWLWIFI_DEBUG + if (iwl_debug_level & (IWL_DL_ISR)) { + inta = iwl_read32(priv, CSR_INT); + inta_mask = iwl_read32(priv, CSR_INT_MASK); + inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); + IWL_DEBUG_ISR("End inta 0x%08x, enabled 0x%08x, fh 0x%08x, " + "flags 0x%08lx\n", inta, inta_mask, inta_fh, flags); + } +#endif + spin_unlock_irqrestore(&priv->lock, flags); +} + +static irqreturn_t iwl_isr(int irq, void *data) +{ + struct iwl_priv *priv = data; + u32 inta, inta_mask; + u32 inta_fh; + if (!priv) + return IRQ_NONE; + + spin_lock(&priv->lock); + + /* Disable (but don't clear!) interrupts here to avoid + * back-to-back ISRs and sporadic interrupts from our NIC. + * If we have something to service, the tasklet will re-enable ints. + * If we *don't* have something, we'll re-enable before leaving here. */ + inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */ + iwl_write32(priv, CSR_INT_MASK, 0x00000000); + + /* Discover which interrupts are active/pending */ + inta = iwl_read32(priv, CSR_INT); + inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); + + /* Ignore interrupt if there's nothing in NIC to service. + * This may be due to IRQ shared with another device, + * or due to sporadic interrupts thrown from our NIC. */ + if (!inta && !inta_fh) { + IWL_DEBUG_ISR("Ignore interrupt, inta == 0, inta_fh == 0\n"); + goto none; + } + + if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) { + /* Hardware disappeared */ + IWL_WARNING("HARDWARE GONE?? INTA == 0x%080x\n", inta); + goto none; + } + + IWL_DEBUG_ISR("ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", + inta, inta_mask, inta_fh); + + /* iwl_irq_tasklet() will service interrupts and re-enable them */ + tasklet_schedule(&priv->irq_tasklet); + spin_unlock(&priv->lock); + + return IRQ_HANDLED; + + none: + /* re-enable interrupts here since we don't have anything to service. */ + iwl_enable_interrupts(priv); + spin_unlock(&priv->lock); + return IRQ_NONE; +} + +/************************** EEPROM BANDS **************************** + * + * The iwl_eeprom_band definitions below provide the mapping from the + * EEPROM contents to the specific channel number supported for each + * band. + * + * For example, iwl_priv->eeprom.band_3_channels[4] from the band_3 + * definition below maps to physical channel 42 in the 5.2GHz spectrum. + * The specific geography and calibration information for that channel + * is contained in the eeprom map itself. + * + * During init, we copy the eeprom information and channel map + * information into priv->channel_info_24/52 and priv->channel_map_24/52 + * + * channel_map_24/52 provides the index in the channel_info array for a + * given channel. We have to have two separate maps as there is channel + * overlap with the 2.4GHz and 5.2GHz spectrum as seen in band_1 and + * band_2 + * + * A value of 0xff stored in the channel_map indicates that the channel + * is not supported by the hardware at all. + * + * A value of 0xfe in the channel_map indicates that the channel is not + * valid for Tx with the current hardware. This means that + * while the system can tune and receive on a given channel, it may not + * be able to associate or transmit any frames on that + * channel. There is no corresponding channel information for that + * entry. + * + *********************************************************************/ + +/* 2.4 GHz */ +static const u8 iwl_eeprom_band_1[14] = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 +}; + +/* 5.2 GHz bands */ +static const u8 iwl_eeprom_band_2[] = { + 183, 184, 185, 187, 188, 189, 192, 196, 7, 8, 11, 12, 16 +}; + +static const u8 iwl_eeprom_band_3[] = { /* 5205-5320MHz */ + 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64 +}; + +static const u8 iwl_eeprom_band_4[] = { /* 5500-5700MHz */ + 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140 +}; + +static const u8 iwl_eeprom_band_5[] = { /* 5725-5825MHz */ + 145, 149, 153, 157, 161, 165 +}; + +static void iwl_init_band_reference(const struct iwl_priv *priv, int band, + int *eeprom_ch_count, + const struct iwl_eeprom_channel + **eeprom_ch_info, + const u8 **eeprom_ch_index) +{ + switch (band) { + case 1: /* 2.4GHz band */ + *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_1); + *eeprom_ch_info = priv->eeprom.band_1_channels; + *eeprom_ch_index = iwl_eeprom_band_1; + break; + case 2: /* 5.2GHz band */ + *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_2); + *eeprom_ch_info = priv->eeprom.band_2_channels; + *eeprom_ch_index = iwl_eeprom_band_2; + break; + case 3: /* 5.2GHz band */ + *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_3); + *eeprom_ch_info = priv->eeprom.band_3_channels; + *eeprom_ch_index = iwl_eeprom_band_3; + break; + case 4: /* 5.2GHz band */ + *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_4); + *eeprom_ch_info = priv->eeprom.band_4_channels; + *eeprom_ch_index = iwl_eeprom_band_4; + break; + case 5: /* 5.2GHz band */ + *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_5); + *eeprom_ch_info = priv->eeprom.band_5_channels; + *eeprom_ch_index = iwl_eeprom_band_5; + break; + default: + BUG(); + return; + } +} + +const struct iwl_channel_info *iwl_get_channel_info(const struct iwl_priv *priv, + int phymode, u16 channel) +{ + int i; + + switch (phymode) { + case MODE_IEEE80211A: + for (i = 14; i < priv->channel_count; i++) { + if (priv->channel_info[i].channel == channel) + return &priv->channel_info[i]; + } + break; + + case MODE_IEEE80211B: + case MODE_IEEE80211G: + if (channel >= 1 && channel <= 14) + return &priv->channel_info[channel - 1]; + break; + + } + + return NULL; +} + +#define CHECK_AND_PRINT(x) ((eeprom_ch_info[ch].flags & EEPROM_CHANNEL_##x) \ + ? # x " " : "") + +static int iwl_init_channel_map(struct iwl_priv *priv) +{ + int eeprom_ch_count = 0; + const u8 *eeprom_ch_index = NULL; + const struct iwl_eeprom_channel *eeprom_ch_info = NULL; + int band, ch; + struct iwl_channel_info *ch_info; + + if (priv->channel_count) { + IWL_DEBUG_INFO("Channel map already initialized.\n"); + return 0; + } + + if (priv->eeprom.version < 0x2f) { + IWL_WARNING("Unsupported EEPROM version: 0x%04X\n", + priv->eeprom.version); + return -EINVAL; + } + + IWL_DEBUG_INFO("Initializing regulatory info from EEPROM\n"); + + priv->channel_count = + ARRAY_SIZE(iwl_eeprom_band_1) + + ARRAY_SIZE(iwl_eeprom_band_2) + + ARRAY_SIZE(iwl_eeprom_band_3) + + ARRAY_SIZE(iwl_eeprom_band_4) + + ARRAY_SIZE(iwl_eeprom_band_5); + + IWL_DEBUG_INFO("Parsing data for %d channels.\n", priv->channel_count); + + priv->channel_info = kzalloc(sizeof(struct iwl_channel_info) * + priv->channel_count, GFP_KERNEL); + if (!priv->channel_info) { + IWL_ERROR("Could not allocate channel_info\n"); + priv->channel_count = 0; + return -ENOMEM; + } + + ch_info = priv->channel_info; + + /* Loop through the 5 EEPROM bands adding them in order to the + * channel map we maintain (that contains additional information than + * what just in the EEPROM) */ + for (band = 1; band <= 5; band++) { + + iwl_init_band_reference(priv, band, &eeprom_ch_count, + &eeprom_ch_info, &eeprom_ch_index); + + /* Loop through each band adding each of the channels */ + for (ch = 0; ch < eeprom_ch_count; ch++) { + ch_info->channel = eeprom_ch_index[ch]; + ch_info->phymode = (band == 1) ? MODE_IEEE80211B : + MODE_IEEE80211A; + + /* permanently store EEPROM's channel regulatory flags + * and max power in channel info database. */ + ch_info->eeprom = eeprom_ch_info[ch]; + + /* Copy the run-time flags so they are there even on + * invalid channels */ + ch_info->flags = eeprom_ch_info[ch].flags; + + if (!(is_channel_valid(ch_info))) { + IWL_DEBUG_INFO("Ch. %d Flags %x [%sGHz] - " + "No traffic\n", + ch_info->channel, + ch_info->flags, + is_channel_a_band(ch_info) ? + "5.2" : "2.4"); + ch_info++; + continue; + } + + /* Initialize regulatory-based run-time data */ + ch_info->max_power_avg = ch_info->curr_txpow = + eeprom_ch_info[ch].max_power_avg; + ch_info->scan_power = eeprom_ch_info[ch].max_power_avg; + ch_info->min_power = 0; + + IWL_DEBUG_INFO("Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x" + " %ddBm): Ad-Hoc %ssupported\n", + ch_info->channel, + is_channel_a_band(ch_info) ? + "5.2" : "2.4", + CHECK_AND_PRINT(IBSS), + CHECK_AND_PRINT(ACTIVE), + CHECK_AND_PRINT(RADAR), + CHECK_AND_PRINT(WIDE), + CHECK_AND_PRINT(NARROW), + CHECK_AND_PRINT(DFS), + eeprom_ch_info[ch].flags, + eeprom_ch_info[ch].max_power_avg, + ((eeprom_ch_info[ch]. + flags & EEPROM_CHANNEL_IBSS) + && !(eeprom_ch_info[ch]. + flags & EEPROM_CHANNEL_RADAR)) + ? "" : "not "); + + /* Set the user_txpower_limit to the highest power + * supported by any channel */ + if (eeprom_ch_info[ch].max_power_avg > + priv->user_txpower_limit) + priv->user_txpower_limit = + eeprom_ch_info[ch].max_power_avg; + + ch_info++; + } + } + + if (iwl3945_txpower_set_from_eeprom(priv)) + return -EIO; + + return 0; +} + +/* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after + * sending probe req. This should be set long enough to hear probe responses + * from more than one AP. */ +#define IWL_ACTIVE_DWELL_TIME_24 (20) /* all times in msec */ +#define IWL_ACTIVE_DWELL_TIME_52 (10) + +/* For faster active scanning, scan will move to the next channel if fewer than + * PLCP_QUIET_THRESH packets are heard on this channel within + * ACTIVE_QUIET_TIME after sending probe request. This shortens the dwell + * time if it's a quiet channel (nothing responded to our probe, and there's + * no other traffic). + * Disable "quiet" feature by setting PLCP_QUIET_THRESH to 0. */ +#define IWL_PLCP_QUIET_THRESH __constant_cpu_to_le16(1) /* packets */ +#define IWL_ACTIVE_QUIET_TIME __constant_cpu_to_le16(5) /* msec */ + +/* For passive scan, listen PASSIVE_DWELL_TIME (msec) on each channel. + * Must be set longer than active dwell time. + * For the most reliable scan, set > AP beacon interval (typically 100msec). */ +#define IWL_PASSIVE_DWELL_TIME_24 (20) /* all times in msec */ +#define IWL_PASSIVE_DWELL_TIME_52 (10) +#define IWL_PASSIVE_DWELL_BASE (100) +#define IWL_CHANNEL_TUNE_TIME 5 + +static inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv, int phymode) +{ + if (phymode == MODE_IEEE80211A) + return IWL_ACTIVE_DWELL_TIME_52; + else + return IWL_ACTIVE_DWELL_TIME_24; +} + +static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, int phymode) +{ + u16 active = iwl_get_active_dwell_time(priv, phymode); + u16 passive = (phymode != MODE_IEEE80211A) ? + IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 : + IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52; + + if (iwl_is_associated(priv)) { + /* If we're associated, we clamp the maximum passive + * dwell time to be 98% of the beacon interval (minus + * 2 * channel tune time) */ + passive = priv->beacon_int; + if ((passive > IWL_PASSIVE_DWELL_BASE) || !passive) + passive = IWL_PASSIVE_DWELL_BASE; + passive = (passive * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2; + } + + if (passive <= active) + passive = active + 1; + + return passive; +} + +static int iwl_get_channels_for_scan(struct iwl_priv *priv, int phymode, + u8 is_active, u8 direct_mask, + struct iwl_scan_channel *scan_ch) +{ + const struct ieee80211_channel *channels = NULL; + const struct ieee80211_hw_mode *hw_mode; + const struct iwl_channel_info *ch_info; + u16 passive_dwell = 0; + u16 active_dwell = 0; + int added, i; + + hw_mode = iwl_get_hw_mode(priv, phymode); + if (!hw_mode) + return 0; + + channels = hw_mode->channels; + + active_dwell = iwl_get_active_dwell_time(priv, phymode); + passive_dwell = iwl_get_passive_dwell_time(priv, phymode); + + for (i = 0, added = 0; i < hw_mode->num_channels; i++) { + if (channels[i].chan == + le16_to_cpu(priv->active_rxon.channel)) { + if (iwl_is_associated(priv)) { + IWL_DEBUG_SCAN + ("Skipping current channel %d\n", + le16_to_cpu(priv->active_rxon.channel)); + continue; + } + } else if (priv->only_active_channel) + continue; + + scan_ch->channel = channels[i].chan; + + ch_info = iwl_get_channel_info(priv, phymode, scan_ch->channel); + if (!is_channel_valid(ch_info)) { + IWL_DEBUG_SCAN("Channel %d is INVALID for this SKU.\n", + scan_ch->channel); + continue; + } + + if (!is_active || is_channel_passive(ch_info) || + !(channels[i].flag & IEEE80211_CHAN_W_ACTIVE_SCAN)) + scan_ch->type = 0; /* passive */ + else + scan_ch->type = 1; /* active */ + + if (scan_ch->type & 1) + scan_ch->type |= (direct_mask << 1); + + if (is_channel_narrow(ch_info)) + scan_ch->type |= (1 << 7); + + scan_ch->active_dwell = cpu_to_le16(active_dwell); + scan_ch->passive_dwell = cpu_to_le16(passive_dwell); + + /* Set power levels to defaults */ + scan_ch->tpc.dsp_atten = 110; + /* scan_pwr_info->tpc.dsp_atten; */ + + /*scan_pwr_info->tpc.tx_gain; */ + if (phymode == MODE_IEEE80211A) + scan_ch->tpc.tx_gain = ((1 << 5) | (3 << 3)) | 3; + else { + scan_ch->tpc.tx_gain = ((1 << 5) | (5 << 3)); + /* NOTE: if we were doing 6Mb OFDM for scans we'd use + * power level + scan_ch->tpc.tx_gain = ((1<<5) | (2 << 3)) | 3; + */ + } + + IWL_DEBUG_SCAN("Scanning %d [%s %d]\n", + scan_ch->channel, + (scan_ch->type & 1) ? "ACTIVE" : "PASSIVE", + (scan_ch->type & 1) ? + active_dwell : passive_dwell); + + scan_ch++; + added++; + } + + IWL_DEBUG_SCAN("total channels to scan %d \n", added); + return added; +} + +static void iwl_reset_channel_flag(struct iwl_priv *priv) +{ + int i, j; + for (i = 0; i < 3; i++) { + struct ieee80211_hw_mode *hw_mode = (void *)&priv->modes[i]; + for (j = 0; j < hw_mode->num_channels; j++) + hw_mode->channels[j].flag = hw_mode->channels[j].val; + } +} + +static void iwl_init_hw_rates(struct iwl_priv *priv, + struct ieee80211_rate *rates) +{ + int i; + + for (i = 0; i < IWL_RATE_COUNT; i++) { + rates[i].rate = iwl_rates[i].ieee * 5; + rates[i].val = i; /* Rate scaling will work on indexes */ + rates[i].val2 = i; + rates[i].flags = IEEE80211_RATE_SUPPORTED; + /* Only OFDM have the bits-per-symbol set */ + if ((i <= IWL_LAST_OFDM_RATE) && (i >= IWL_FIRST_OFDM_RATE)) + rates[i].flags |= IEEE80211_RATE_OFDM; + else { + /* + * If CCK 1M then set rate flag to CCK else CCK_2 + * which is CCK | PREAMBLE2 + */ + rates[i].flags |= (iwl_rates[i].plcp == 10) ? + IEEE80211_RATE_CCK : IEEE80211_RATE_CCK_2; + } + + /* Set up which ones are basic rates... */ + if (IWL_BASIC_RATES_MASK & (1 << i)) + rates[i].flags |= IEEE80211_RATE_BASIC; + } +} + +/** + * iwl_init_geos - Initialize mac80211's geo/channel info based from eeprom + */ +static int iwl_init_geos(struct iwl_priv *priv) +{ + struct iwl_channel_info *ch; + struct ieee80211_hw_mode *modes; + struct ieee80211_channel *channels; + struct ieee80211_channel *geo_ch; + struct ieee80211_rate *rates; + int i = 0; + enum { + A = 0, + B = 1, + G = 2, + }; + int mode_count = 3; + + if (priv->modes) { + IWL_DEBUG_INFO("Geography modes already initialized.\n"); + set_bit(STATUS_GEO_CONFIGURED, &priv->status); + return 0; + } + + modes = kzalloc(sizeof(struct ieee80211_hw_mode) * mode_count, + GFP_KERNEL); + if (!modes) + return -ENOMEM; + + channels = kzalloc(sizeof(struct ieee80211_channel) * + priv->channel_count, GFP_KERNEL); + if (!channels) { + kfree(modes); + return -ENOMEM; + } + + rates = kzalloc((sizeof(struct ieee80211_rate) * (IWL_MAX_RATES + 1)), + GFP_KERNEL); + if (!rates) { + kfree(modes); + kfree(channels); + return -ENOMEM; + } + + /* 0 = 802.11a + * 1 = 802.11b + * 2 = 802.11g + */ + + /* 5.2GHz channels start after the 2.4GHz channels */ + modes[A].mode = MODE_IEEE80211A; + modes[A].channels = &channels[ARRAY_SIZE(iwl_eeprom_band_1)]; + modes[A].rates = rates; + modes[A].num_rates = 8; /* just OFDM */ + modes[A].num_channels = 0; + + modes[B].mode = MODE_IEEE80211B; + modes[B].channels = channels; + modes[B].rates = &rates[8]; + modes[B].num_rates = 4; /* just CCK */ + modes[B].num_channels = 0; + + modes[G].mode = MODE_IEEE80211G; + modes[G].channels = channels; + modes[G].rates = rates; + modes[G].num_rates = 12; /* OFDM & CCK */ + modes[G].num_channels = 0; + + priv->ieee_channels = channels; + priv->ieee_rates = rates; + + iwl_init_hw_rates(priv, rates); + + for (i = 0, geo_ch = channels; i < priv->channel_count; i++) { + ch = &priv->channel_info[i]; + + if (!is_channel_valid(ch)) { + IWL_DEBUG_INFO("Channel %d [%sGHz] is restricted -- " + "skipping.\n", + ch->channel, is_channel_a_band(ch) ? + "5.2" : "2.4"); + continue; + } + + if (is_channel_a_band(ch)) + geo_ch = &modes[A].channels[modes[A].num_channels++]; + else { + geo_ch = &modes[B].channels[modes[B].num_channels++]; + modes[G].num_channels++; + } + + geo_ch->freq = ieee80211chan2mhz(ch->channel); + geo_ch->chan = ch->channel; + geo_ch->power_level = ch->max_power_avg; + geo_ch->antenna_max = 0xff; + + if (is_channel_valid(ch)) { + geo_ch->flag = IEEE80211_CHAN_W_SCAN; + if (ch->flags & EEPROM_CHANNEL_IBSS) + geo_ch->flag |= IEEE80211_CHAN_W_IBSS; + + if (ch->flags & EEPROM_CHANNEL_ACTIVE) + geo_ch->flag |= IEEE80211_CHAN_W_ACTIVE_SCAN; + + if (ch->flags & EEPROM_CHANNEL_RADAR) + geo_ch->flag |= IEEE80211_CHAN_W_RADAR_DETECT; + + if (ch->max_power_avg > priv->max_channel_txpower_limit) + priv->max_channel_txpower_limit = + ch->max_power_avg; + } + + geo_ch->val = geo_ch->flag; + } + + if ((modes[A].num_channels == 0) && priv->is_abg) { + printk(KERN_INFO DRV_NAME + ": Incorrectly detected BG card as ABG. Please send " + "your PCI ID 0x%04X:0x%04X to maintainer.\n", + priv->pci_dev->device, priv->pci_dev->subsystem_device); + priv->is_abg = 0; + } + + printk(KERN_INFO DRV_NAME + ": Tunable channels: %d 802.11bg, %d 802.11a channels\n", + modes[G].num_channels, modes[A].num_channels); + + /* + * NOTE: We register these in preference of order -- the + * stack doesn't currently (as of 7.0.6 / Apr 24 '07) pick + * a phymode based on rates or AP capabilities but seems to + * configure it purely on if the channel being configured + * is supported by a mode -- and the first match is taken + */ + + if (modes[G].num_channels) + ieee80211_register_hwmode(priv->hw, &modes[G]); + if (modes[B].num_channels) + ieee80211_register_hwmode(priv->hw, &modes[B]); + if (modes[A].num_channels) + ieee80211_register_hwmode(priv->hw, &modes[A]); + + priv->modes = modes; + set_bit(STATUS_GEO_CONFIGURED, &priv->status); + + return 0; +} + +/****************************************************************************** + * + * uCode download functions + * + ******************************************************************************/ + +static void iwl_dealloc_ucode_pci(struct iwl_priv *priv) +{ + if (priv->ucode_code.v_addr != NULL) { + pci_free_consistent(priv->pci_dev, + priv->ucode_code.len, + priv->ucode_code.v_addr, + priv->ucode_code.p_addr); + priv->ucode_code.v_addr = NULL; + } + if (priv->ucode_data.v_addr != NULL) { + pci_free_consistent(priv->pci_dev, + priv->ucode_data.len, + priv->ucode_data.v_addr, + priv->ucode_data.p_addr); + priv->ucode_data.v_addr = NULL; + } + if (priv->ucode_data_backup.v_addr != NULL) { + pci_free_consistent(priv->pci_dev, + priv->ucode_data_backup.len, + priv->ucode_data_backup.v_addr, + priv->ucode_data_backup.p_addr); + priv->ucode_data_backup.v_addr = NULL; + } + if (priv->ucode_init.v_addr != NULL) { + pci_free_consistent(priv->pci_dev, + priv->ucode_init.len, + priv->ucode_init.v_addr, + priv->ucode_init.p_addr); + priv->ucode_init.v_addr = NULL; + } + if (priv->ucode_init_data.v_addr != NULL) { + pci_free_consistent(priv->pci_dev, + priv->ucode_init_data.len, + priv->ucode_init_data.v_addr, + priv->ucode_init_data.p_addr); + priv->ucode_init_data.v_addr = NULL; + } + if (priv->ucode_boot.v_addr != NULL) { + pci_free_consistent(priv->pci_dev, + priv->ucode_boot.len, + priv->ucode_boot.v_addr, + priv->ucode_boot.p_addr); + priv->ucode_boot.v_addr = NULL; + } +} + +/** + * iwl_verify_inst_full - verify runtime uCode image in card vs. host, + * looking at all data. + */ +static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 * image, u32 len) +{ + u32 val; + u32 save_len = len; + int rc = 0; + u32 errcnt; + + IWL_DEBUG_INFO("ucode inst image size is %u\n", len); + + rc = iwl_grab_restricted_access(priv); + if (rc) + return rc; + + iwl_write_restricted(priv, HBUS_TARG_MEM_RADDR, RTC_INST_LOWER_BOUND); + + errcnt = 0; + for (; len > 0; len -= sizeof(u32), image++) { + /* read data comes through single port, auto-incr addr */ + /* NOTE: Use the debugless read so we don't flood kernel log + * if IWL_DL_IO is set */ + val = _iwl_read_restricted(priv, HBUS_TARG_MEM_RDAT); + if (val != le32_to_cpu(*image)) { + IWL_ERROR("uCode INST section is invalid at " + "offset 0x%x, is 0x%x, s/b 0x%x\n", + save_len - len, val, le32_to_cpu(*image)); + rc = -EIO; + errcnt++; + if (errcnt >= 20) + break; + } + } + + iwl_release_restricted_access(priv); + + if (!errcnt) + IWL_DEBUG_INFO + ("ucode image in INSTRUCTION memory is good\n"); + + return rc; +} + + +/** + * iwl_verify_inst_sparse - verify runtime uCode image in card vs. host, + * using sample data 100 bytes apart. If these sample points are good, + * it's a pretty good bet that everything between them is good, too. + */ +static int iwl_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len) +{ + u32 val; + int rc = 0; + u32 errcnt = 0; + u32 i; + + IWL_DEBUG_INFO("ucode inst image size is %u\n", len); + + rc = iwl_grab_restricted_access(priv); + if (rc) + return rc; + + for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) { + /* read data comes through single port, auto-incr addr */ + /* NOTE: Use the debugless read so we don't flood kernel log + * if IWL_DL_IO is set */ + iwl_write_restricted(priv, HBUS_TARG_MEM_RADDR, + i + RTC_INST_LOWER_BOUND); + val = _iwl_read_restricted(priv, HBUS_TARG_MEM_RDAT); + if (val != le32_to_cpu(*image)) { +#if 0 /* Enable this if you want to see details */ + IWL_ERROR("uCode INST section is invalid at " + "offset 0x%x, is 0x%x, s/b 0x%x\n", + i, val, *image); +#endif + rc = -EIO; + errcnt++; + if (errcnt >= 3) + break; + } + } + + iwl_release_restricted_access(priv); + + return rc; +} + + +/** + * iwl_verify_ucode - determine which instruction image is in SRAM, + * and verify its contents + */ +static int iwl_verify_ucode(struct iwl_priv *priv) +{ + __le32 *image; + u32 len; + int rc = 0; + + /* Try bootstrap */ + image = (__le32 *)priv->ucode_boot.v_addr; + len = priv->ucode_boot.len; + rc = iwl_verify_inst_sparse(priv, image, len); + if (rc == 0) { + IWL_DEBUG_INFO("Bootstrap uCode is good in inst SRAM\n"); + return 0; + } + + /* Try initialize */ + image = (__le32 *)priv->ucode_init.v_addr; + len = priv->ucode_init.len; + rc = iwl_verify_inst_sparse(priv, image, len); + if (rc == 0) { + IWL_DEBUG_INFO("Initialize uCode is good in inst SRAM\n"); + return 0; + } + + /* Try runtime/protocol */ + image = (__le32 *)priv->ucode_code.v_addr; + len = priv->ucode_code.len; + rc = iwl_verify_inst_sparse(priv, image, len); + if (rc == 0) { + IWL_DEBUG_INFO("Runtime uCode is good in inst SRAM\n"); + return 0; + } + + IWL_ERROR("NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n"); + + /* Show first several data entries in instruction SRAM. + * Selection of bootstrap image is arbitrary. */ + image = (__le32 *)priv->ucode_boot.v_addr; + len = priv->ucode_boot.len; + rc = iwl_verify_inst_full(priv, image, len); + + return rc; +} + + +/* check contents of special bootstrap uCode SRAM */ +static int iwl_verify_bsm(struct iwl_priv *priv) +{ + __le32 *image = priv->ucode_boot.v_addr; + u32 len = priv->ucode_boot.len; + u32 reg; + u32 val; + + IWL_DEBUG_INFO("Begin verify bsm\n"); + + /* verify BSM SRAM contents */ + val = iwl_read_restricted_reg(priv, BSM_WR_DWCOUNT_REG); + for (reg = BSM_SRAM_LOWER_BOUND; + reg < BSM_SRAM_LOWER_BOUND + len; + reg += sizeof(u32), image ++) { + val = iwl_read_restricted_reg(priv, reg); + if (val != le32_to_cpu(*image)) { + IWL_ERROR("BSM uCode verification failed at " + "addr 0x%08X+%u (of %u), is 0x%x, s/b 0x%x\n", + BSM_SRAM_LOWER_BOUND, + reg - BSM_SRAM_LOWER_BOUND, len, + val, le32_to_cpu(*image)); + return -EIO; + } + } + + IWL_DEBUG_INFO("BSM bootstrap uCode image OK\n"); + + return 0; +} + +/** + * iwl_load_bsm - Load bootstrap instructions + * + * BSM operation: + * + * The Bootstrap State Machine (BSM) stores a short bootstrap uCode program + * in special SRAM that does not power down during RFKILL. When powering back + * up after power-saving sleeps (or during initial uCode load), the BSM loads + * the bootstrap program into the on-board processor, and starts it. + * + * The bootstrap program loads (via DMA) instructions and data for a new + * program from host DRAM locations indicated by the host driver in the + * BSM_DRAM_* registers. Once the new program is loaded, it starts + * automatically. + * + * When initializing the NIC, the host driver points the BSM to the + * "initialize" uCode image. This uCode sets up some internal data, then + * notifies host via "initialize alive" that it is complete. + * + * The host then replaces the BSM_DRAM_* pointer values to point to the + * normal runtime uCode instructions and a backup uCode data cache buffer + * (filled initially with starting data values for the on-board processor), + * then triggers the "initialize" uCode to load and launch the runtime uCode, + * which begins normal operation. + * + * When doing a power-save shutdown, runtime uCode saves data SRAM into + * the backup data cache in DRAM before SRAM is powered down. + * + * When powering back up, the BSM loads the bootstrap program. This reloads + * the runtime uCode instructions and the backup data cache into SRAM, + * and re-launches the runtime uCode from where it left off. + */ +static int iwl_load_bsm(struct iwl_priv *priv) +{ + __le32 *image = priv->ucode_boot.v_addr; + u32 len = priv->ucode_boot.len; + dma_addr_t pinst; + dma_addr_t pdata; + u32 inst_len; + u32 data_len; + int rc; + int i; + u32 done; + u32 reg_offset; + + IWL_DEBUG_INFO("Begin load bsm\n"); + + /* make sure bootstrap program is no larger than BSM's SRAM size */ + if (len > IWL_MAX_BSM_SIZE) + return -EINVAL; + + /* Tell bootstrap uCode where to find the "Initialize" uCode + * in host DRAM ... bits 31:0 for 3945, bits 35:4 for 4965. + * NOTE: iwl_initialize_alive_start() will replace these values, + * after the "initialize" uCode has run, to point to + * runtime/protocol instructions and backup data cache. */ + pinst = priv->ucode_init.p_addr; + pdata = priv->ucode_init_data.p_addr; + inst_len = priv->ucode_init.len; + data_len = priv->ucode_init_data.len; + + rc = iwl_grab_restricted_access(priv); + if (rc) + return rc; + + iwl_write_restricted_reg(priv, BSM_DRAM_INST_PTR_REG, pinst); + iwl_write_restricted_reg(priv, BSM_DRAM_DATA_PTR_REG, pdata); + iwl_write_restricted_reg(priv, BSM_DRAM_INST_BYTECOUNT_REG, inst_len); + iwl_write_restricted_reg(priv, BSM_DRAM_DATA_BYTECOUNT_REG, data_len); + + /* Fill BSM memory with bootstrap instructions */ + for (reg_offset = BSM_SRAM_LOWER_BOUND; + reg_offset < BSM_SRAM_LOWER_BOUND + len; + reg_offset += sizeof(u32), image++) + _iwl_write_restricted_reg(priv, reg_offset, + le32_to_cpu(*image)); + + rc = iwl_verify_bsm(priv); + if (rc) { + iwl_release_restricted_access(priv); + return rc; + } + + /* Tell BSM to copy from BSM SRAM into instruction SRAM, when asked */ + iwl_write_restricted_reg(priv, BSM_WR_MEM_SRC_REG, 0x0); + iwl_write_restricted_reg(priv, BSM_WR_MEM_DST_REG, + RTC_INST_LOWER_BOUND); + iwl_write_restricted_reg(priv, BSM_WR_DWCOUNT_REG, len / sizeof(u32)); + + /* Load bootstrap code into instruction SRAM now, + * to prepare to load "initialize" uCode */ + iwl_write_restricted_reg(priv, BSM_WR_CTRL_REG, + BSM_WR_CTRL_REG_BIT_START); + + /* Wait for load of bootstrap uCode to finish */ + for (i = 0; i < 100; i++) { + done = iwl_read_restricted_reg(priv, BSM_WR_CTRL_REG); + if (!(done & BSM_WR_CTRL_REG_BIT_START)) + break; + udelay(10); + } + if (i < 100) + IWL_DEBUG_INFO("BSM write complete, poll %d iterations\n", i); + else { + IWL_ERROR("BSM write did not complete!\n"); + return -EIO; + } + + /* Enable future boot loads whenever power management unit triggers it + * (e.g. when powering back up after power-save shutdown) */ + iwl_write_restricted_reg(priv, BSM_WR_CTRL_REG, + BSM_WR_CTRL_REG_BIT_START_EN); + + iwl_release_restricted_access(priv); + + return 0; +} + +static void iwl_nic_start(struct iwl_priv *priv) +{ + /* Remove all resets to allow NIC to operate */ + iwl_write32(priv, CSR_RESET, 0); +} + +/** + * iwl_read_ucode - Read uCode images from disk file. + * + * Copy into buffers for card to fetch via bus-mastering + */ +static int iwl_read_ucode(struct iwl_priv *priv) +{ + struct iwl_ucode *ucode; + int rc = 0; + const struct firmware *ucode_raw; + /* firmware file name contains uCode/driver compatibility version */ + const char *name = "iwlwifi-3945" IWL3945_UCODE_API ".ucode"; + u8 *src; + size_t len; + u32 ver, inst_size, data_size, init_size, init_data_size, boot_size; + + /* Ask kernel firmware_class module to get the boot firmware off disk. + * request_firmware() is synchronous, file is in memory on return. */ + rc = request_firmware(&ucode_raw, name, &priv->pci_dev->dev); + if (rc < 0) { + IWL_ERROR("%s firmware file req failed: Reason %d\n", name, rc); + goto error; + } + + IWL_DEBUG_INFO("Got firmware '%s' file (%zd bytes) from disk\n", + name, ucode_raw->size); + + /* Make sure that we got at least our header! */ + if (ucode_raw->size < sizeof(*ucode)) { + IWL_ERROR("File size way too small!\n"); + rc = -EINVAL; + goto err_release; + } + + /* Data from ucode file: header followed by uCode images */ + ucode = (void *)ucode_raw->data; + + ver = le32_to_cpu(ucode->ver); + inst_size = le32_to_cpu(ucode->inst_size); + data_size = le32_to_cpu(ucode->data_size); + init_size = le32_to_cpu(ucode->init_size); + init_data_size = le32_to_cpu(ucode->init_data_size); + boot_size = le32_to_cpu(ucode->boot_size); + + IWL_DEBUG_INFO("f/w package hdr ucode version = 0x%x\n", ver); + IWL_DEBUG_INFO("f/w package hdr runtime inst size = %u\n", + inst_size); + IWL_DEBUG_INFO("f/w package hdr runtime data size = %u\n", + data_size); + IWL_DEBUG_INFO("f/w package hdr init inst size = %u\n", + init_size); + IWL_DEBUG_INFO("f/w package hdr init data size = %u\n", + init_data_size); + IWL_DEBUG_INFO("f/w package hdr boot inst size = %u\n", + boot_size); + + /* Verify size of file vs. image size info in file's header */ + if (ucode_raw->size < sizeof(*ucode) + + inst_size + data_size + init_size + + init_data_size + boot_size) { + + IWL_DEBUG_INFO("uCode file size %d too small\n", + (int)ucode_raw->size); + rc = -EINVAL; + goto err_release; + } + + /* Verify that uCode images will fit in card's SRAM */ + if (inst_size > IWL_MAX_INST_SIZE) { + IWL_DEBUG_INFO("uCode instr len %d too large to fit in card\n", + (int)inst_size); + rc = -EINVAL; + goto err_release; + } + + if (data_size > IWL_MAX_DATA_SIZE) { + IWL_DEBUG_INFO("uCode data len %d too large to fit in card\n", + (int)data_size); + rc = -EINVAL; + goto err_release; + } + if (init_size > IWL_MAX_INST_SIZE) { + IWL_DEBUG_INFO + ("uCode init instr len %d too large to fit in card\n", + (int)init_size); + rc = -EINVAL; + goto err_release; + } + if (init_data_size > IWL_MAX_DATA_SIZE) { + IWL_DEBUG_INFO + ("uCode init data len %d too large to fit in card\n", + (int)init_data_size); + rc = -EINVAL; + goto err_release; + } + if (boot_size > IWL_MAX_BSM_SIZE) { + IWL_DEBUG_INFO + ("uCode boot instr len %d too large to fit in bsm\n", + (int)boot_size); + rc = -EINVAL; + goto err_release; + } + + /* Allocate ucode buffers for card's bus-master loading ... */ + + /* Runtime instructions and 2 copies of data: + * 1) unmodified from disk + * 2) backup cache for save/restore during power-downs */ + priv->ucode_code.len = inst_size; + priv->ucode_code.v_addr = + pci_alloc_consistent(priv->pci_dev, + priv->ucode_code.len, + &(priv->ucode_code.p_addr)); + + priv->ucode_data.len = data_size; + priv->ucode_data.v_addr = + pci_alloc_consistent(priv->pci_dev, + priv->ucode_data.len, + &(priv->ucode_data.p_addr)); + + priv->ucode_data_backup.len = data_size; + priv->ucode_data_backup.v_addr = + pci_alloc_consistent(priv->pci_dev, + priv->ucode_data_backup.len, + &(priv->ucode_data_backup.p_addr)); + + + /* Initialization instructions and data */ + priv->ucode_init.len = init_size; + priv->ucode_init.v_addr = + pci_alloc_consistent(priv->pci_dev, + priv->ucode_init.len, + &(priv->ucode_init.p_addr)); + + priv->ucode_init_data.len = init_data_size; + priv->ucode_init_data.v_addr = + pci_alloc_consistent(priv->pci_dev, + priv->ucode_init_data.len, + &(priv->ucode_init_data.p_addr)); + + /* Bootstrap (instructions only, no data) */ + priv->ucode_boot.len = boot_size; + priv->ucode_boot.v_addr = + pci_alloc_consistent(priv->pci_dev, + priv->ucode_boot.len, + &(priv->ucode_boot.p_addr)); + + if (!priv->ucode_code.v_addr || !priv->ucode_data.v_addr || + !priv->ucode_init.v_addr || !priv->ucode_init_data.v_addr || + !priv->ucode_boot.v_addr || !priv->ucode_data_backup.v_addr) + goto err_pci_alloc; + + /* Copy images into buffers for card's bus-master reads ... */ + + /* Runtime instructions (first block of data in file) */ + src = &ucode->data[0]; + len = priv->ucode_code.len; + IWL_DEBUG_INFO("Copying (but not loading) uCode instr len %d\n", + (int)len); + memcpy(priv->ucode_code.v_addr, src, len); + IWL_DEBUG_INFO("uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n", + priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr); + + /* Runtime data (2nd block) + * NOTE: Copy into backup buffer will be done in iwl_up() */ + src = &ucode->data[inst_size]; + len = priv->ucode_data.len; + IWL_DEBUG_INFO("Copying (but not loading) uCode data len %d\n", + (int)len); + memcpy(priv->ucode_data.v_addr, src, len); + memcpy(priv->ucode_data_backup.v_addr, src, len); + + /* Initialization instructions (3rd block) */ + if (init_size) { + src = &ucode->data[inst_size + data_size]; + len = priv->ucode_init.len; + IWL_DEBUG_INFO("Copying (but not loading) init instr len %d\n", + (int)len); + memcpy(priv->ucode_init.v_addr, src, len); + } + + /* Initialization data (4th block) */ + if (init_data_size) { + src = &ucode->data[inst_size + data_size + init_size]; + len = priv->ucode_init_data.len; + IWL_DEBUG_INFO("Copying (but not loading) init data len %d\n", + (int)len); + memcpy(priv->ucode_init_data.v_addr, src, len); + } + + /* Bootstrap instructions (5th block) */ + src = &ucode->data[inst_size + data_size + init_size + init_data_size]; + len = priv->ucode_boot.len; + IWL_DEBUG_INFO("Copying (but not loading) boot instr len %d\n", + (int)len); + memcpy(priv->ucode_boot.v_addr, src, len); + + /* We have our copies now, allow OS release its copies */ + release_firmware(ucode_raw); + return 0; + + err_pci_alloc: + IWL_ERROR("failed to allocate pci memory\n"); + rc = -ENOMEM; + iwl_dealloc_ucode_pci(priv); + + err_release: + release_firmware(ucode_raw); + + error: + return rc; +} + + +/** + * iwl_set_ucode_ptrs - Set uCode address location + * + * Tell initialization uCode where to find runtime uCode. + * + * BSM registers initially contain pointers to initialization uCode. + * We need to replace them to load runtime uCode inst and data, + * and to save runtime data when powering down. + */ +static int iwl_set_ucode_ptrs(struct iwl_priv *priv) +{ + dma_addr_t pinst; + dma_addr_t pdata; + int rc = 0; + unsigned long flags; + + /* bits 31:0 for 3945 */ + pinst = priv->ucode_code.p_addr; + pdata = priv->ucode_data_backup.p_addr; + + spin_lock_irqsave(&priv->lock, flags); + rc = iwl_grab_restricted_access(priv); + if (rc) { + spin_unlock_irqrestore(&priv->lock, flags); + return rc; + } + + /* Tell bootstrap uCode where to find image to load */ + iwl_write_restricted_reg(priv, BSM_DRAM_INST_PTR_REG, pinst); + iwl_write_restricted_reg(priv, BSM_DRAM_DATA_PTR_REG, pdata); + iwl_write_restricted_reg(priv, BSM_DRAM_DATA_BYTECOUNT_REG, + priv->ucode_data.len); + + /* Inst bytecount must be last to set up, bit 31 signals uCode + * that all new ptr/size info is in place */ + iwl_write_restricted_reg(priv, BSM_DRAM_INST_BYTECOUNT_REG, + priv->ucode_code.len | BSM_DRAM_INST_LOAD); + + iwl_release_restricted_access(priv); + + spin_unlock_irqrestore(&priv->lock, flags); + + IWL_DEBUG_INFO("Runtime uCode pointers are set.\n"); + + return rc; +} + +/** + * iwl_init_alive_start - Called after REPLY_ALIVE notification receieved + * + * Called after REPLY_ALIVE notification received from "initialize" uCode. + * + * The 4965 "initialize" ALIVE reply contains calibration data for: + * Voltage, temperature, and MIMO tx gain correction, now stored in priv + * (3945 does not contain this data). + * + * Tell "initialize" uCode to go ahead and load the runtime uCode. +*/ +static void iwl_init_alive_start(struct iwl_priv *priv) +{ + /* Check alive response for "valid" sign from uCode */ + if (priv->card_alive_init.is_valid != UCODE_VALID_OK) { + /* We had an error bringing up the hardware, so take it + * all the way back down so we can try again */ + IWL_DEBUG_INFO("Initialize Alive failed.\n"); + goto restart; + } + + /* Bootstrap uCode has loaded initialize uCode ... verify inst image. + * This is a paranoid check, because we would not have gotten the + * "initialize" alive if code weren't properly loaded. */ + if (iwl_verify_ucode(priv)) { + /* Runtime instruction load was bad; + * take it all the way back down so we can try again */ + IWL_DEBUG_INFO("Bad \"initialize\" uCode load.\n"); + goto restart; + } + + /* Send pointers to protocol/runtime uCode image ... init code will + * load and launch runtime uCode, which will send us another "Alive" + * notification. */ + IWL_DEBUG_INFO("Initialization Alive received.\n"); + if (iwl_set_ucode_ptrs(priv)) { + /* Runtime instruction load won't happen; + * take it all the way back down so we can try again */ + IWL_DEBUG_INFO("Couldn't set up uCode pointers.\n"); + goto restart; + } + return; + + restart: + queue_work(priv->workqueue, &priv->restart); +} + + +/** + * iwl_alive_start - called after REPLY_ALIVE notification received + * from protocol/runtime uCode (initialization uCode's + * Alive gets handled by iwl_init_alive_start()). + */ +static void iwl_alive_start(struct iwl_priv *priv) +{ + int rc = 0; + int thermal_spin = 0; + u32 rfkill; + + IWL_DEBUG_INFO("Runtime Alive received.\n"); + + if (priv->card_alive.is_valid != UCODE_VALID_OK) { + /* We had an error bringing up the hardware, so take it + * all the way back down so we can try again */ + IWL_DEBUG_INFO("Alive failed.\n"); + goto restart; + } + + /* Initialize uCode has loaded Runtime uCode ... verify inst image. + * This is a paranoid check, because we would not have gotten the + * "runtime" alive if code weren't properly loaded. */ + if (iwl_verify_ucode(priv)) { + /* Runtime instruction load was bad; + * take it all the way back down so we can try again */ + IWL_DEBUG_INFO("Bad runtime uCode load.\n"); + goto restart; + } + + iwl_clear_stations_table(priv); + + rc = iwl_grab_restricted_access(priv); + if (rc) { + IWL_WARNING("Can not read rfkill status from adapter\n"); + return; + } + + rfkill = iwl_read_restricted_reg(priv, APMG_RFKILL_REG); + IWL_DEBUG_INFO("RFKILL status: 0x%x\n", rfkill); + iwl_release_restricted_access(priv); + + if (rfkill & 0x1) { + clear_bit(STATUS_RF_KILL_HW, &priv->status); + /* if rfkill is not on, then wait for thermal + * sensor in adapter to kick in */ + while (iwl_hw_get_temperature(priv) == 0) { + thermal_spin++; + udelay(10); + } + + if (thermal_spin) + IWL_DEBUG_INFO("Thermal calibration took %dus\n", + thermal_spin * 10); + } else + set_bit(STATUS_RF_KILL_HW, &priv->status); + + /* After the ALIVE response, we can process host commands */ + set_bit(STATUS_ALIVE, &priv->status); + + /* Clear out the uCode error bit if it is set */ + clear_bit(STATUS_FW_ERROR, &priv->status); + + rc = iwl_init_channel_map(priv); + if (rc) { + IWL_ERROR("initializing regulatory failed: %d\n", rc); + return; + } + + iwl_init_geos(priv); + + if (iwl_is_rfkill(priv)) + return; + + if (!priv->mac80211_registered) { + /* Unlock so any user space entry points can call back into + * the driver without a deadlock... */ + mutex_unlock(&priv->mutex); + iwl_rate_control_register(priv->hw); + rc = ieee80211_register_hw(priv->hw); + priv->hw->conf.beacon_int = 100; + mutex_lock(&priv->mutex); + + if (rc) { + IWL_ERROR("Failed to register network " + "device (error %d)\n", rc); + return; + } + + priv->mac80211_registered = 1; + + iwl_reset_channel_flag(priv); + } else + ieee80211_start_queues(priv->hw); + + priv->active_rate = priv->rates_mask; + priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK; + + iwl_send_power_mode(priv, IWL_POWER_LEVEL(priv->power_mode)); + + if (iwl_is_associated(priv)) { + struct iwl_rxon_cmd *active_rxon = + (struct iwl_rxon_cmd *)(&priv->active_rxon); + + memcpy(&priv->staging_rxon, &priv->active_rxon, + sizeof(priv->staging_rxon)); + active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; + } else { + /* Initialize our rx_config data */ + iwl_connection_init_rx_config(priv); + memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); + } + + /* Configure BT coexistence */ + iwl_send_bt_config(priv); + + /* Configure the adapter for unassociated operation */ + iwl_commit_rxon(priv); + + /* At this point, the NIC is initialized and operational */ + priv->notif_missed_beacons = 0; + set_bit(STATUS_READY, &priv->status); + + iwl3945_reg_txpower_periodic(priv); + + IWL_DEBUG_INFO("ALIVE processing complete.\n"); + + if (priv->error_recovering) + iwl_error_recovery(priv); + + return; + + restart: + queue_work(priv->workqueue, &priv->restart); +} + +static void iwl_cancel_deferred_work(struct iwl_priv *priv); + +static void __iwl_down(struct iwl_priv *priv) +{ + unsigned long flags; + int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status); + struct ieee80211_conf *conf = NULL; + + IWL_DEBUG_INFO(DRV_NAME " is going down\n"); + + conf = ieee80211_get_hw_conf(priv->hw); + + if (!exit_pending) + set_bit(STATUS_EXIT_PENDING, &priv->status); + + iwl_clear_stations_table(priv); + + /* Unblock any waiting calls */ + wake_up_interruptible_all(&priv->wait_command_queue); + + iwl_cancel_deferred_work(priv); + + /* Wipe out the EXIT_PENDING status bit if we are not actually + * exiting the module */ + if (!exit_pending) + clear_bit(STATUS_EXIT_PENDING, &priv->status); + + /* stop and reset the on-board processor */ + iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); + + /* tell the device to stop sending interrupts */ + iwl_disable_interrupts(priv); + + if (priv->mac80211_registered) + ieee80211_stop_queues(priv->hw); + + /* If we have not previously called iwl_init() then + * clear all bits but the RF Kill and SUSPEND bits and return */ + if (!iwl_is_init(priv)) { + priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) << + STATUS_RF_KILL_HW | + test_bit(STATUS_RF_KILL_SW, &priv->status) << + STATUS_RF_KILL_SW | + test_bit(STATUS_IN_SUSPEND, &priv->status) << + STATUS_IN_SUSPEND; + goto exit; + } + + /* ...otherwise clear out all the status bits but the RF Kill and + * SUSPEND bits and continue taking the NIC down. */ + priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) << + STATUS_RF_KILL_HW | + test_bit(STATUS_RF_KILL_SW, &priv->status) << + STATUS_RF_KILL_SW | + test_bit(STATUS_IN_SUSPEND, &priv->status) << + STATUS_IN_SUSPEND | + test_bit(STATUS_FW_ERROR, &priv->status) << + STATUS_FW_ERROR; + + spin_lock_irqsave(&priv->lock, flags); + iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + spin_unlock_irqrestore(&priv->lock, flags); + + iwl_hw_txq_ctx_stop(priv); + iwl_hw_rxq_stop(priv); + + spin_lock_irqsave(&priv->lock, flags); + if (!iwl_grab_restricted_access(priv)) { + iwl_write_restricted_reg(priv, APMG_CLK_DIS_REG, + APMG_CLK_VAL_DMA_CLK_RQT); + iwl_release_restricted_access(priv); + } + spin_unlock_irqrestore(&priv->lock, flags); + + udelay(5); + + iwl_hw_nic_stop_master(priv); + iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); + iwl_hw_nic_reset(priv); + + exit: + memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp)); + + if (priv->ibss_beacon) + dev_kfree_skb(priv->ibss_beacon); + priv->ibss_beacon = NULL; + + /* clear out any free frames */ + iwl_clear_free_frames(priv); +} + +static void iwl_down(struct iwl_priv *priv) +{ + mutex_lock(&priv->mutex); + __iwl_down(priv); + mutex_unlock(&priv->mutex); +} + +#define MAX_HW_RESTARTS 5 + +static int __iwl_up(struct iwl_priv *priv) +{ + int rc, i; + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { + IWL_WARNING("Exit pending; will not bring the NIC up\n"); + return -EIO; + } + + if (test_bit(STATUS_RF_KILL_SW, &priv->status)) { + IWL_WARNING("Radio disabled by SW RF kill (module " + "parameter)\n"); + return 0; + } + + iwl_write32(priv, CSR_INT, 0xFFFFFFFF); + + rc = iwl_hw_nic_init(priv); + if (rc) { + IWL_ERROR("Unable to int nic\n"); + return rc; + } + + /* make sure rfkill handshake bits are cleared */ + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, + CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); + + /* clear (again), then enable host interrupts */ + iwl_write32(priv, CSR_INT, 0xFFFFFFFF); + iwl_enable_interrupts(priv); + + /* really make sure rfkill handshake bits are cleared */ + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + + /* Copy original ucode data image from disk into backup cache. + * This will be used to initialize the on-board processor's + * data SRAM for a clean start when the runtime program first loads. */ + memcpy(priv->ucode_data_backup.v_addr, priv->ucode_data.v_addr, + priv->ucode_data.len); + + for (i = 0; i < MAX_HW_RESTARTS; i++) { + + iwl_clear_stations_table(priv); + + /* load bootstrap state machine, + * load bootstrap program into processor's memory, + * prepare to load the "initialize" uCode */ + rc = iwl_load_bsm(priv); + + if (rc) { + IWL_ERROR("Unable to set up bootstrap uCode: %d\n", rc); + continue; + } + + /* start card; "initialize" will load runtime ucode */ + iwl_nic_start(priv); + + /* MAC Address location in EEPROM same for 3945/4965 */ + get_eeprom_mac(priv, priv->mac_addr); + IWL_DEBUG_INFO("MAC address: " MAC_FMT "\n", + MAC_ARG(priv->mac_addr)); + + SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr); + + IWL_DEBUG_INFO(DRV_NAME " is coming up\n"); + + return 0; + } + + set_bit(STATUS_EXIT_PENDING, &priv->status); + __iwl_down(priv); + + /* tried to restart and config the device for as long as our + * patience could withstand */ + IWL_ERROR("Unable to initialize device after %d attempts.\n", i); + return -EIO; +} + + +/***************************************************************************** + * + * Workqueue callbacks + * + *****************************************************************************/ + +static void iwl_bg_init_alive_start(struct work_struct *data) +{ + struct iwl_priv *priv = + container_of(data, struct iwl_priv, init_alive_start.work); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + mutex_lock(&priv->mutex); + iwl_init_alive_start(priv); + mutex_unlock(&priv->mutex); +} + +static void iwl_bg_alive_start(struct work_struct *data) +{ + struct iwl_priv *priv = + container_of(data, struct iwl_priv, alive_start.work); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + mutex_lock(&priv->mutex); + iwl_alive_start(priv); + mutex_unlock(&priv->mutex); +} + +static void iwl_bg_rf_kill(struct work_struct *work) +{ + struct iwl_priv *priv = container_of(work, struct iwl_priv, rf_kill); + + wake_up_interruptible(&priv->wait_command_queue); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + mutex_lock(&priv->mutex); + + if (!iwl_is_rfkill(priv)) { + IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL, + "HW and/or SW RF Kill no longer active, restarting " + "device\n"); + if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) + queue_work(priv->workqueue, &priv->restart); + } else { + + if (!test_bit(STATUS_RF_KILL_HW, &priv->status)) + IWL_DEBUG_RF_KILL("Can not turn radio back on - " + "disabled by SW switch\n"); + else + IWL_WARNING("Radio Frequency Kill Switch is On:\n" + "Kill switch must be turned off for " + "wireless networking to work.\n"); + } + mutex_unlock(&priv->mutex); +} + +#define IWL_SCAN_CHECK_WATCHDOG (7 * HZ) + +static void iwl_bg_scan_check(struct work_struct *data) +{ + struct iwl_priv *priv = + container_of(data, struct iwl_priv, scan_check.work); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + mutex_lock(&priv->mutex); + if (test_bit(STATUS_SCANNING, &priv->status) || + test_bit(STATUS_SCAN_ABORTING, &priv->status)) { + IWL_DEBUG(IWL_DL_INFO | IWL_DL_SCAN, + "Scan completion watchdog resetting adapter (%dms)\n", + jiffies_to_msecs(IWL_SCAN_CHECK_WATCHDOG)); + if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) + queue_work(priv->workqueue, &priv->restart); + } + mutex_unlock(&priv->mutex); +} + +static void iwl_bg_request_scan(struct work_struct *data) +{ + struct iwl_priv *priv = + container_of(data, struct iwl_priv, request_scan); + struct iwl_host_cmd cmd = { + .id = REPLY_SCAN_CMD, + .len = sizeof(struct iwl_scan_cmd), + .meta.flags = CMD_SIZE_HUGE, + }; + int rc = 0; + struct iwl_scan_cmd *scan; + struct ieee80211_conf *conf = NULL; + u8 direct_mask; + int phymode; + + conf = ieee80211_get_hw_conf(priv->hw); + + mutex_lock(&priv->mutex); + + if (!iwl_is_ready(priv)) { + IWL_WARNING("request scan called when driver not ready.\n"); + goto done; + } + + /* Make sure the scan wasn't cancelled before this queued work + * was given the chance to run... */ + if (!test_bit(STATUS_SCANNING, &priv->status)) + goto done; + + /* This should never be called or scheduled if there is currently + * a scan active in the hardware. */ + if (test_bit(STATUS_SCAN_HW, &priv->status)) { + IWL_DEBUG_INFO("Multiple concurrent scan requests in parallel. " + "Ignoring second request.\n"); + rc = -EIO; + goto done; + } + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { + IWL_DEBUG_SCAN("Aborting scan due to device shutdown\n"); + goto done; + } + + if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { + IWL_DEBUG_HC("Scan request while abort pending. Queuing.\n"); + goto done; + } + + if (iwl_is_rfkill(priv)) { + IWL_DEBUG_HC("Aborting scan due to RF Kill activation\n"); + goto done; + } + + if (!test_bit(STATUS_READY, &priv->status)) { + IWL_DEBUG_HC("Scan request while uninitialized. Queuing.\n"); + goto done; + } + + if (!priv->scan_bands) { + IWL_DEBUG_HC("Aborting scan due to no requested bands\n"); + goto done; + } + + if (!priv->scan) { + priv->scan = kmalloc(sizeof(struct iwl_scan_cmd) + + IWL_MAX_SCAN_SIZE, GFP_KERNEL); + if (!priv->scan) { + rc = -ENOMEM; + goto done; + } + } + scan = priv->scan; + memset(scan, 0, sizeof(struct iwl_scan_cmd) + IWL_MAX_SCAN_SIZE); + + scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH; + scan->quiet_time = IWL_ACTIVE_QUIET_TIME; + + if (iwl_is_associated(priv)) { + u16 interval = 0; + u32 extra; + u32 suspend_time = 100; + u32 scan_suspend_time = 100; + unsigned long flags; + + IWL_DEBUG_INFO("Scanning while associated...\n"); + + spin_lock_irqsave(&priv->lock, flags); + interval = priv->beacon_int; + spin_unlock_irqrestore(&priv->lock, flags); + + scan->suspend_time = 0; + scan->max_out_time = cpu_to_le32(600 * 1024); + if (!interval) + interval = suspend_time; + /* + * suspend time format: + * 0-19: beacon interval in usec (time before exec.) + * 20-23: 0 + * 24-31: number of beacons (suspend between channels) + */ + + extra = (suspend_time / interval) << 24; + scan_suspend_time = 0xFF0FFFFF & + (extra | ((suspend_time % interval) * 1024)); + + scan->suspend_time = cpu_to_le32(scan_suspend_time); + IWL_DEBUG_SCAN("suspend_time 0x%X beacon interval %d\n", + scan_suspend_time, interval); + } + + /* We should add the ability for user to lock to PASSIVE ONLY */ + if (priv->one_direct_scan) { + IWL_DEBUG_SCAN + ("Kicking off one direct scan for '%s'\n", + iwl_escape_essid(priv->direct_ssid, + priv->direct_ssid_len)); + scan->direct_scan[0].id = WLAN_EID_SSID; + scan->direct_scan[0].len = priv->direct_ssid_len; + memcpy(scan->direct_scan[0].ssid, + priv->direct_ssid, priv->direct_ssid_len); + direct_mask = 1; + } else if (!iwl_is_associated(priv)) { + scan->direct_scan[0].id = WLAN_EID_SSID; + scan->direct_scan[0].len = priv->essid_len; + memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len); + direct_mask = 1; + } else + direct_mask = 0; + + /* We don't build a direct scan probe request; the uCode will do + * that based on the direct_mask added to each channel entry */ + scan->tx_cmd.len = cpu_to_le16( + iwl_fill_probe_req(priv, (struct ieee80211_mgmt *)scan->data, + IWL_MAX_SCAN_SIZE - sizeof(scan), 0)); + scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK; + scan->tx_cmd.sta_id = priv->hw_setting.bcast_sta_id; + scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; + + /* flags + rate selection */ + + switch (priv->scan_bands) { + case 2: + scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK; + scan->tx_cmd.rate = IWL_RATE_1M_PLCP; + scan->good_CRC_th = 0; + phymode = MODE_IEEE80211G; + break; + + case 1: + scan->tx_cmd.rate = IWL_RATE_6M_PLCP; + scan->good_CRC_th = IWL_GOOD_CRC_TH; + phymode = MODE_IEEE80211A; + break; + + default: + IWL_WARNING("Invalid scan band count\n"); + goto done; + } + + /* select Rx antennas */ + scan->flags |= iwl3945_get_antenna_flags(priv); + + if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) + scan->filter_flags = RXON_FILTER_PROMISC_MSK; + + if (direct_mask) + IWL_DEBUG_SCAN + ("Initiating direct scan for %s.\n", + iwl_escape_essid(priv->essid, priv->essid_len)); + else + IWL_DEBUG_SCAN("Initiating indirect scan.\n"); + + scan->channel_count = + iwl_get_channels_for_scan( + priv, phymode, 1, /* active */ + direct_mask, + (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); + + cmd.len += le16_to_cpu(scan->tx_cmd.len) + + scan->channel_count * sizeof(struct iwl_scan_channel); + cmd.data = scan; + scan->len = cpu_to_le16(cmd.len); + + set_bit(STATUS_SCAN_HW, &priv->status); + rc = iwl_send_cmd_sync(priv, &cmd); + if (rc) + goto done; + + queue_delayed_work(priv->workqueue, &priv->scan_check, + IWL_SCAN_CHECK_WATCHDOG); + + mutex_unlock(&priv->mutex); + return; + + done: + /* inform mac80211 sacn aborted */ + queue_work(priv->workqueue, &priv->scan_completed); + mutex_unlock(&priv->mutex); +} + +static void iwl_bg_up(struct work_struct *data) +{ + struct iwl_priv *priv = container_of(data, struct iwl_priv, up); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + mutex_lock(&priv->mutex); + __iwl_up(priv); + mutex_unlock(&priv->mutex); +} + +static void iwl_bg_restart(struct work_struct *data) +{ + struct iwl_priv *priv = container_of(data, struct iwl_priv, restart); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + iwl_down(priv); + queue_work(priv->workqueue, &priv->up); +} + +static void iwl_bg_rx_replenish(struct work_struct *data) +{ + struct iwl_priv *priv = + container_of(data, struct iwl_priv, rx_replenish); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + mutex_lock(&priv->mutex); + iwl_rx_replenish(priv); + mutex_unlock(&priv->mutex); +} + +static void iwl_bg_post_associate(struct work_struct *data) +{ + struct iwl_priv *priv = container_of(data, struct iwl_priv, + post_associate.work); + + int rc = 0; + struct ieee80211_conf *conf = NULL; + + if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { + IWL_ERROR("%s Should not be called in AP mode\n", __FUNCTION__); + return; + } + + + IWL_DEBUG_ASSOC("Associated as %d to: " MAC_FMT "\n", + priv->assoc_id, MAC_ARG(priv->active_rxon.bssid_addr)); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + mutex_lock(&priv->mutex); + + conf = ieee80211_get_hw_conf(priv->hw); + + priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; + iwl_commit_rxon(priv); + + memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd)); + iwl_setup_rxon_timing(priv); + rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING, + sizeof(priv->rxon_timing), &priv->rxon_timing); + if (rc) + IWL_WARNING("REPLY_RXON_TIMING failed - " + "Attempting to continue.\n"); + + priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; + + priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id); + + IWL_DEBUG_ASSOC("assoc id %d beacon interval %d\n", + priv->assoc_id, priv->beacon_int); + + if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE) + priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; + else + priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK; + + if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) { + if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME) + priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK; + else + priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; + + if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) + priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; + + } + + iwl_commit_rxon(priv); + + switch (priv->iw_mode) { + case IEEE80211_IF_TYPE_STA: + iwl_rate_scale_init(priv->hw, IWL_AP_ID); + break; + + case IEEE80211_IF_TYPE_IBSS: + + /* clear out the station table */ + iwl_clear_stations_table(priv); + + iwl_rxon_add_station(priv, BROADCAST_ADDR, 0); + iwl_rxon_add_station(priv, priv->bssid, 0); + iwl3945_sync_sta(priv, IWL_STA_ID, + (priv->phymode == MODE_IEEE80211A)? + IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP, + CMD_ASYNC); + iwl_rate_scale_init(priv->hw, IWL_STA_ID); + iwl_send_beacon_cmd(priv); + + break; + + default: + IWL_ERROR("%s Should not be called in %d mode\n", + __FUNCTION__, priv->iw_mode); + break; + } + + iwl_sequence_reset(priv); + +#ifdef CONFIG_IWLWIFI_QOS + iwl_activate_qos(priv, 0); +#endif /* CONFIG_IWLWIFI_QOS */ + mutex_unlock(&priv->mutex); +} + +static void iwl_bg_abort_scan(struct work_struct *work) +{ + struct iwl_priv *priv = container_of(work, struct iwl_priv, + abort_scan); + + if (!iwl_is_ready(priv)) + return; + + mutex_lock(&priv->mutex); + + set_bit(STATUS_SCAN_ABORTING, &priv->status); + iwl_send_scan_abort(priv); + + mutex_unlock(&priv->mutex); +} + +static void iwl_bg_scan_completed(struct work_struct *work) +{ + struct iwl_priv *priv = + container_of(work, struct iwl_priv, scan_completed); + + IWL_DEBUG(IWL_DL_INFO | IWL_DL_SCAN, "SCAN complete scan\n"); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + ieee80211_scan_completed(priv->hw); + + /* Since setting the TXPOWER may have been deferred while + * performing the scan, fire one off */ + mutex_lock(&priv->mutex); + iwl_hw_reg_send_txpower(priv); + mutex_unlock(&priv->mutex); +} + +/***************************************************************************** + * + * mac80211 entry point functions + * + *****************************************************************************/ + +static int iwl_mac_open(struct ieee80211_hw *hw) +{ + struct iwl_priv *priv = hw->priv; + + IWL_DEBUG_MAC80211("enter\n"); + + /* we should be verifying the device is ready to be opened */ + mutex_lock(&priv->mutex); + + priv->is_open = 1; + + if (!iwl_is_rfkill(priv)) + ieee80211_start_queues(priv->hw); + + mutex_unlock(&priv->mutex); + IWL_DEBUG_MAC80211("leave\n"); + return 0; +} + +static int iwl_mac_stop(struct ieee80211_hw *hw) +{ + struct iwl_priv *priv = hw->priv; + + IWL_DEBUG_MAC80211("enter\n"); + priv->is_open = 0; + /*netif_stop_queue(dev); */ + flush_workqueue(priv->workqueue); + IWL_DEBUG_MAC80211("leave\n"); + + return 0; +} + +static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ieee80211_tx_control *ctl) +{ + struct iwl_priv *priv = hw->priv; + + IWL_DEBUG_MAC80211("enter\n"); + + if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) { + IWL_DEBUG_MAC80211("leave - monitor\n"); + return -1; + } + + IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len, + ctl->tx_rate); + + if (iwl_tx_skb(priv, skb, ctl)) + dev_kfree_skb_any(skb); + + IWL_DEBUG_MAC80211("leave\n"); + return 0; +} + +static int iwl_mac_add_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct iwl_priv *priv = hw->priv; + unsigned long flags; + + IWL_DEBUG_MAC80211("enter: id %d, type %d\n", conf->if_id, conf->type); + if (conf->mac_addr) + IWL_DEBUG_MAC80211("enter: MAC " MAC_FMT "\n", + MAC_ARG(conf->mac_addr)); + + if (priv->interface_id) { + IWL_DEBUG_MAC80211("leave - interface_id != 0\n"); + return 0; + } + + spin_lock_irqsave(&priv->lock, flags); + priv->interface_id = conf->if_id; + + spin_unlock_irqrestore(&priv->lock, flags); + + mutex_lock(&priv->mutex); + iwl_set_mode(priv, conf->type); + + IWL_DEBUG_MAC80211("leave\n"); + mutex_unlock(&priv->mutex); + + return 0; +} + +/** + * iwl_mac_config - mac80211 config callback + * + * We ignore conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME since it seems to + * be set inappropriately and the driver currently sets the hardware up to + * use it whenever needed. + */ +static int iwl_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) +{ + struct iwl_priv *priv = hw->priv; + const struct iwl_channel_info *ch_info; + unsigned long flags; + + mutex_lock(&priv->mutex); + IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel); + + if (!iwl_is_ready(priv)) { + IWL_DEBUG_MAC80211("leave - not ready\n"); + mutex_unlock(&priv->mutex); + return -EIO; + } + + /* TODO: Figure out how to get ieee80211_local->sta_scanning w/ only + * what is exposed through include/ declrations */ + if (unlikely(!iwl_param_disable_hw_scan && + test_bit(STATUS_SCANNING, &priv->status))) { + IWL_DEBUG_MAC80211("leave - scanning\n"); + mutex_unlock(&priv->mutex); + return 0; + } + + spin_lock_irqsave(&priv->lock, flags); + + ch_info = iwl_get_channel_info(priv, conf->phymode, conf->channel); + if (!is_channel_valid(ch_info)) { + IWL_DEBUG_SCAN("Channel %d [%d] is INVALID for this SKU.\n", + conf->channel, conf->phymode); + IWL_DEBUG_MAC80211("leave - invalid channel\n"); + spin_unlock_irqrestore(&priv->lock, flags); + mutex_unlock(&priv->mutex); + return -EINVAL; + } + + iwl_set_rxon_channel(priv, conf->phymode, conf->channel); + + iwl_set_flags_for_phymode(priv, conf->phymode); + + /* The list of supported rates and rate mask can be different + * for each phymode; since the phymode may have changed, reset + * the rate mask to what mac80211 lists */ + iwl_set_rate(priv); + + spin_unlock_irqrestore(&priv->lock, flags); + +#ifdef IEEE80211_CONF_CHANNEL_SWITCH + if (conf->flags & IEEE80211_CONF_CHANNEL_SWITCH) { + iwl_hw_channel_switch(priv, conf->channel); + mutex_unlock(&priv->mutex); + return 0; + } +#endif + + iwl_radio_kill_sw(priv, !conf->radio_enabled); + + if (!conf->radio_enabled) { + IWL_DEBUG_MAC80211("leave - radio disabled\n"); + mutex_unlock(&priv->mutex); + return 0; + } + + if (iwl_is_rfkill(priv)) { + IWL_DEBUG_MAC80211("leave - RF kill\n"); + mutex_unlock(&priv->mutex); + return -EIO; + } + + iwl_set_rate(priv); + + if (memcmp(&priv->active_rxon, + &priv->staging_rxon, sizeof(priv->staging_rxon))) + iwl_commit_rxon(priv); + else + IWL_DEBUG_INFO("No re-sending same RXON configuration.\n"); + + IWL_DEBUG_MAC80211("leave\n"); + + mutex_unlock(&priv->mutex); + + return 0; +} + +static void iwl_config_ap(struct iwl_priv *priv) +{ + int rc = 0; + + if (priv->status & STATUS_EXIT_PENDING) + return; + + /* The following should be done only at AP bring up */ + if ((priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) == 0) { + + /* RXON - unassoc (to set timing command) */ + priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; + iwl_commit_rxon(priv); + + /* RXON Timing */ + memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd)); + iwl_setup_rxon_timing(priv); + rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING, + sizeof(priv->rxon_timing), &priv->rxon_timing); + if (rc) + IWL_WARNING("REPLY_RXON_TIMING failed - " + "Attempting to continue.\n"); + + /* FIXME: what should be the assoc_id for AP? */ + priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id); + if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE) + priv->staging_rxon.flags |= + RXON_FLG_SHORT_PREAMBLE_MSK; + else + priv->staging_rxon.flags &= + ~RXON_FLG_SHORT_PREAMBLE_MSK; + + if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) { + if (priv->assoc_capability & + WLAN_CAPABILITY_SHORT_SLOT_TIME) + priv->staging_rxon.flags |= + RXON_FLG_SHORT_SLOT_MSK; + else + priv->staging_rxon.flags &= + ~RXON_FLG_SHORT_SLOT_MSK; + + if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) + priv->staging_rxon.flags &= + ~RXON_FLG_SHORT_SLOT_MSK; + } + /* restore RXON assoc */ + priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; + iwl_commit_rxon(priv); + iwl_rxon_add_station(priv, BROADCAST_ADDR, 0); + iwl_send_beacon_cmd(priv); + } else + iwl_send_beacon_cmd(priv); + + /* FIXME - we need to add code here to detect a totally new + * configuration, reset the AP, unassoc, rxon timing, assoc, + * clear sta table, add BCAST sta... */ +} + +static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id, + struct ieee80211_if_conf *conf) +{ + struct iwl_priv *priv = hw->priv; + unsigned long flags; + int rc; + + if (conf == NULL) + return -EIO; + + if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) && + (!conf->beacon || !conf->ssid_len)) { + IWL_DEBUG_MAC80211 + ("Leaving in AP mode because HostAPD is not ready.\n"); + return 0; + } + + mutex_lock(&priv->mutex); + + IWL_DEBUG_MAC80211("enter: interface id %d\n", if_id); + if (conf->bssid) + IWL_DEBUG_MAC80211("bssid: " MAC_FMT "\n", + MAC_ARG(conf->bssid)); + + if (unlikely(test_bit(STATUS_SCANNING, &priv->status)) && + !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) { + IWL_DEBUG_MAC80211("leave - scanning\n"); + mutex_unlock(&priv->mutex); + return 0; + } + + if (priv->interface_id != if_id) { + IWL_DEBUG_MAC80211("leave - interface_id != if_id\n"); + mutex_unlock(&priv->mutex); + return 0; + } + + if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { + if (!conf->bssid) { + conf->bssid = priv->mac_addr; + memcpy(priv->bssid, priv->mac_addr, ETH_ALEN); + IWL_DEBUG_MAC80211("bssid was set to: " MAC_FMT "\n", + MAC_ARG(conf->bssid)); + } + if (priv->ibss_beacon) + dev_kfree_skb(priv->ibss_beacon); + + priv->ibss_beacon = conf->beacon; + } + + if (conf->bssid && !is_zero_ether_addr(conf->bssid) && + !is_multicast_ether_addr(conf->bssid)) { + /* If there is currently a HW scan going on in the background + * then we need to cancel it else the RXON below will fail. */ + if (iwl_scan_cancel_timeout(priv, 100)) { + IWL_WARNING("Aborted scan still in progress " + "after 100ms\n"); + IWL_DEBUG_MAC80211("leaving - scan abort failed.\n"); + mutex_unlock(&priv->mutex); + return -EAGAIN; + } + memcpy(priv->staging_rxon.bssid_addr, conf->bssid, ETH_ALEN); + + /* TODO: Audit driver for usage of these members and see + * if mac80211 deprecates them (priv->bssid looks like it + * shouldn't be there, but I haven't scanned the IBSS code + * to verify) - jpk */ + memcpy(priv->bssid, conf->bssid, ETH_ALEN); + + if (priv->iw_mode == IEEE80211_IF_TYPE_AP) + iwl_config_ap(priv); + else { + priv->staging_rxon.filter_flags |= + RXON_FILTER_ASSOC_MSK; + rc = iwl_commit_rxon(priv); + if ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && rc) + iwl_rxon_add_station( + priv, priv->active_rxon.bssid_addr, 1); + } + + } else { + priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; + iwl_commit_rxon(priv); + } + + spin_lock_irqsave(&priv->lock, flags); + if (!conf->ssid_len) + memset(priv->essid, 0, IW_ESSID_MAX_SIZE); + else + memcpy(priv->essid, conf->ssid, conf->ssid_len); + + priv->essid_len = conf->ssid_len; + spin_unlock_irqrestore(&priv->lock, flags); + + IWL_DEBUG_MAC80211("leave\n"); + mutex_unlock(&priv->mutex); + + return 0; +} + +static void iwl_mac_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct iwl_priv *priv = hw->priv; + + IWL_DEBUG_MAC80211("enter\n"); + + mutex_lock(&priv->mutex); + if (priv->interface_id == conf->if_id) { + priv->interface_id = 0; + memset(priv->bssid, 0, ETH_ALEN); + memset(priv->essid, 0, IW_ESSID_MAX_SIZE); + priv->essid_len = 0; + } + mutex_unlock(&priv->mutex); + + IWL_DEBUG_MAC80211("leave\n"); + +} + +#define IWL_DELAY_NEXT_SCAN (HZ*2) +static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len) +{ + int rc = 0; + unsigned long flags; + struct iwl_priv *priv = hw->priv; + + IWL_DEBUG_MAC80211("enter\n"); + + spin_lock_irqsave(&priv->lock, flags); + + if (!iwl_is_ready_rf(priv)) { + rc = -EIO; + IWL_DEBUG_MAC80211("leave - not ready or exit pending\n"); + goto out_unlock; + } + + if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { /* APs don't scan */ + rc = -EIO; + IWL_ERROR("ERROR: APs don't scan\n"); + goto out_unlock; + } + + /* if we just finished scan ask for delay */ + if (priv->last_scan_jiffies && + time_after(priv->last_scan_jiffies + IWL_DELAY_NEXT_SCAN, + jiffies)) { + rc = -EAGAIN; + goto out_unlock; + } + if (len) { + IWL_DEBUG_SCAN("direct scan for " + "%s [%d]\n ", + iwl_escape_essid(ssid, len), (int)len); + + priv->one_direct_scan = 1; + priv->direct_ssid_len = (u8) + min((u8) len, (u8) IW_ESSID_MAX_SIZE); + memcpy(priv->direct_ssid, ssid, priv->direct_ssid_len); + } + + rc = iwl_scan_initiate(priv); + + IWL_DEBUG_MAC80211("leave\n"); + +out_unlock: + spin_unlock_irqrestore(&priv->lock, flags); + + return rc; +} + +static int iwl_mac_set_key(struct ieee80211_hw *hw, set_key_cmd cmd, + const u8 *local_addr, const u8 *addr, + struct ieee80211_key_conf *key) +{ + struct iwl_priv *priv = hw->priv; + int rc = 0; + u8 sta_id; + + IWL_DEBUG_MAC80211("enter\n"); + + if (!iwl_param_hwcrypto) { + IWL_DEBUG_MAC80211("leave - hwcrypto disabled\n"); + return -EOPNOTSUPP; + } + + if (is_zero_ether_addr(addr)) + /* only support pairwise keys */ + return -EOPNOTSUPP; + + sta_id = iwl_hw_find_station(priv, addr); + if (sta_id == IWL_INVALID_STATION) { + IWL_DEBUG_MAC80211("leave - " MAC_FMT " not in station map.\n", + MAC_ARG(addr)); + return -EINVAL; + } + + mutex_lock(&priv->mutex); + + switch (cmd) { + case SET_KEY: + rc = iwl_update_sta_key_info(priv, key, sta_id); + if (!rc) { + iwl_set_rxon_hwcrypto(priv, 1); + iwl_commit_rxon(priv); + key->hw_key_idx = sta_id; + IWL_DEBUG_MAC80211("set_key success, using hwcrypto\n"); + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + } + break; + case DISABLE_KEY: + rc = iwl_clear_sta_key_info(priv, sta_id); + if (!rc) { + iwl_set_rxon_hwcrypto(priv, 0); + iwl_commit_rxon(priv); + IWL_DEBUG_MAC80211("disable hwcrypto key\n"); + } + break; + default: + rc = -EINVAL; + } + + IWL_DEBUG_MAC80211("leave\n"); + mutex_unlock(&priv->mutex); + + return rc; +} + +static int iwl_mac_conf_tx(struct ieee80211_hw *hw, int queue, + const struct ieee80211_tx_queue_params *params) +{ + struct iwl_priv *priv = hw->priv; +#ifdef CONFIG_IWLWIFI_QOS + unsigned long flags; + int q; +#endif /* CONFIG_IWL_QOS */ + + IWL_DEBUG_MAC80211("enter\n"); + + if (!iwl_is_ready_rf(priv)) { + IWL_DEBUG_MAC80211("leave - RF not ready\n"); + return -EIO; + } + + if (queue >= AC_NUM) { + IWL_DEBUG_MAC80211("leave - queue >= AC_NUM %d\n", queue); + return 0; + } + +#ifdef CONFIG_IWLWIFI_QOS + if (!priv->qos_data.qos_enable) { + priv->qos_data.qos_active = 0; + IWL_DEBUG_MAC80211("leave - qos not enabled\n"); + return 0; + } + q = AC_NUM - 1 - queue; + + spin_lock_irqsave(&priv->lock, flags); + + priv->qos_data.def_qos_parm.ac[q].cw_min = cpu_to_le16(params->cw_min); + priv->qos_data.def_qos_parm.ac[q].cw_max = cpu_to_le16(params->cw_max); + priv->qos_data.def_qos_parm.ac[q].aifsn = params->aifs; + priv->qos_data.def_qos_parm.ac[q].edca_txop = + cpu_to_le16((params->burst_time * 100)); + + priv->qos_data.def_qos_parm.ac[q].reserved1 = 0; + priv->qos_data.qos_active = 1; + + spin_unlock_irqrestore(&priv->lock, flags); + + mutex_lock(&priv->mutex); + if (priv->iw_mode == IEEE80211_IF_TYPE_AP) + iwl_activate_qos(priv, 1); + else if (priv->assoc_id && iwl_is_associated(priv)) + iwl_activate_qos(priv, 0); + + mutex_unlock(&priv->mutex); + +#endif /*CONFIG_IWLWIFI_QOS */ + + IWL_DEBUG_MAC80211("leave\n"); + return 0; +} + +static int iwl_mac_get_tx_stats(struct ieee80211_hw *hw, + struct ieee80211_tx_queue_stats *stats) +{ + struct iwl_priv *priv = hw->priv; + int i, avail; + struct iwl_tx_queue *txq; + struct iwl_queue *q; + unsigned long flags; + + IWL_DEBUG_MAC80211("enter\n"); + + if (!iwl_is_ready_rf(priv)) { + IWL_DEBUG_MAC80211("leave - RF not ready\n"); + return -EIO; + } + + spin_lock_irqsave(&priv->lock, flags); + + for (i = 0; i < AC_NUM; i++) { + txq = &priv->txq[i]; + q = &txq->q; + avail = iwl_queue_space(q); + + stats->data[i].len = q->n_window - avail; + stats->data[i].limit = q->n_window - q->high_mark; + stats->data[i].count = q->n_window; + + } + spin_unlock_irqrestore(&priv->lock, flags); + + IWL_DEBUG_MAC80211("leave\n"); + + return 0; +} + +static int iwl_mac_get_stats(struct ieee80211_hw *hw, + struct ieee80211_low_level_stats *stats) +{ + IWL_DEBUG_MAC80211("enter\n"); + IWL_DEBUG_MAC80211("leave\n"); + + return 0; +} + +static u64 iwl_mac_get_tsf(struct ieee80211_hw *hw) +{ + IWL_DEBUG_MAC80211("enter\n"); + IWL_DEBUG_MAC80211("leave\n"); + + return 0; +} + +static void iwl_mac_reset_tsf(struct ieee80211_hw *hw) +{ + struct iwl_priv *priv = hw->priv; + unsigned long flags; + + mutex_lock(&priv->mutex); + IWL_DEBUG_MAC80211("enter\n"); + +#ifdef CONFIG_IWLWIFI_QOS + iwl_reset_qos(priv); +#endif + cancel_delayed_work(&priv->post_associate); + + spin_lock_irqsave(&priv->lock, flags); + priv->assoc_id = 0; + priv->assoc_capability = 0; + priv->call_post_assoc_from_beacon = 0; + + /* new association get rid of ibss beacon skb */ + if (priv->ibss_beacon) + dev_kfree_skb(priv->ibss_beacon); + + priv->ibss_beacon = NULL; + + priv->beacon_int = priv->hw->conf.beacon_int; + priv->timestamp1 = 0; + priv->timestamp0 = 0; + if ((priv->iw_mode == IEEE80211_IF_TYPE_STA)) + priv->beacon_int = 0; + + spin_unlock_irqrestore(&priv->lock, flags); + + /* Per mac80211.h: This is only used in IBSS mode... */ + if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) { + IWL_DEBUG_MAC80211("leave - not in IBSS\n"); + mutex_unlock(&priv->mutex); + return; + } + + if (!iwl_is_ready_rf(priv)) { + IWL_DEBUG_MAC80211("leave - not ready\n"); + mutex_unlock(&priv->mutex); + return; + } + + priv->only_active_channel = 0; + + iwl_set_rate(priv); + + mutex_unlock(&priv->mutex); + + IWL_DEBUG_MAC80211("leave\n"); + +} + +static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ieee80211_tx_control *control) +{ + struct iwl_priv *priv = hw->priv; + unsigned long flags; + + mutex_lock(&priv->mutex); + IWL_DEBUG_MAC80211("enter\n"); + + if (!iwl_is_ready_rf(priv)) { + IWL_DEBUG_MAC80211("leave - RF not ready\n"); + mutex_unlock(&priv->mutex); + return -EIO; + } + + if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) { + IWL_DEBUG_MAC80211("leave - not IBSS\n"); + mutex_unlock(&priv->mutex); + return -EIO; + } + + spin_lock_irqsave(&priv->lock, flags); + + if (priv->ibss_beacon) + dev_kfree_skb(priv->ibss_beacon); + + priv->ibss_beacon = skb; + + priv->assoc_id = 0; + + IWL_DEBUG_MAC80211("leave\n"); + spin_unlock_irqrestore(&priv->lock, flags); + +#ifdef CONFIG_IWLWIFI_QOS + iwl_reset_qos(priv); +#endif + + queue_work(priv->workqueue, &priv->post_associate.work); + + mutex_unlock(&priv->mutex); + + return 0; +} + +/***************************************************************************** + * + * sysfs attributes + * + *****************************************************************************/ + +#ifdef CONFIG_IWLWIFI_DEBUG + +/* + * The following adds a new attribute to the sysfs representation + * of this device driver (i.e. a new file in /sys/bus/pci/drivers/iwl/) + * used for controlling the debug level. + * + * See the level definitions in iwl for details. + */ + +static ssize_t show_debug_level(struct device_driver *d, char *buf) +{ + return sprintf(buf, "0x%08X\n", iwl_debug_level); +} +static ssize_t store_debug_level(struct device_driver *d, + const char *buf, size_t count) +{ + char *p = (char *)buf; + u32 val; + + val = simple_strtoul(p, &p, 0); + if (p == buf) + printk(KERN_INFO DRV_NAME + ": %s is not in hex or decimal form.\n", buf); + else + iwl_debug_level = val; + + return strnlen(buf, count); +} + +static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO, + show_debug_level, store_debug_level); + +#endif /* CONFIG_IWLWIFI_DEBUG */ + +static ssize_t show_rf_kill(struct device *d, + struct device_attribute *attr, char *buf) +{ + /* + * 0 - RF kill not enabled + * 1 - SW based RF kill active (sysfs) + * 2 - HW based RF kill active + * 3 - Both HW and SW based RF kill active + */ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + int val = (test_bit(STATUS_RF_KILL_SW, &priv->status) ? 0x1 : 0x0) | + (test_bit(STATUS_RF_KILL_HW, &priv->status) ? 0x2 : 0x0); + + return sprintf(buf, "%i\n", val); +} + +static ssize_t store_rf_kill(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + + mutex_lock(&priv->mutex); + iwl_radio_kill_sw(priv, buf[0] == '1'); + mutex_unlock(&priv->mutex); + + return count; +} + +static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill); + +static ssize_t show_temperature(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + + if (!iwl_is_alive(priv)) + return -EAGAIN; + + return sprintf(buf, "%d\n", iwl_hw_get_temperature(priv)); +} + +static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL); + +static ssize_t show_rs_window(struct device *d, + struct device_attribute *attr, + char *buf) +{ + struct iwl_priv *priv = d->driver_data; + return iwl_fill_rs_info(priv->hw, buf, IWL_AP_ID); +} +static DEVICE_ATTR(rs_window, S_IRUGO, show_rs_window, NULL); + +static ssize_t show_tx_power(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + return sprintf(buf, "%d\n", priv->user_txpower_limit); +} + +static ssize_t store_tx_power(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + char *p = (char *)buf; + u32 val; + + val = simple_strtoul(p, &p, 10); + if (p == buf) + printk(KERN_INFO DRV_NAME + ": %s is not in decimal form.\n", buf); + else + iwl_hw_reg_set_txpower(priv, val); + + return count; +} + +static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power); + +static ssize_t show_flags(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + + return sprintf(buf, "0x%04X\n", priv->active_rxon.flags); +} + +static ssize_t store_flags(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + u32 flags = simple_strtoul(buf, NULL, 0); + + mutex_lock(&priv->mutex); + if (le32_to_cpu(priv->staging_rxon.flags) != flags) { + /* Cancel any currently running scans... */ + if (iwl_scan_cancel_timeout(priv, 100)) + IWL_WARNING("Could not cancel scan.\n"); + else { + IWL_DEBUG_INFO("Committing rxon.flags = 0x%04X\n", + flags); + priv->staging_rxon.flags = cpu_to_le32(flags); + iwl_commit_rxon(priv); + } + } + mutex_unlock(&priv->mutex); + + return count; +} + +static DEVICE_ATTR(flags, S_IWUSR | S_IRUGO, show_flags, store_flags); + +static ssize_t show_filter_flags(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + + return sprintf(buf, "0x%04X\n", + le32_to_cpu(priv->active_rxon.filter_flags)); +} + +static ssize_t store_filter_flags(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + u32 filter_flags = simple_strtoul(buf, NULL, 0); + + mutex_lock(&priv->mutex); + if (le32_to_cpu(priv->staging_rxon.filter_flags) != filter_flags) { + /* Cancel any currently running scans... */ + if (iwl_scan_cancel_timeout(priv, 100)) + IWL_WARNING("Could not cancel scan.\n"); + else { + IWL_DEBUG_INFO("Committing rxon.filter_flags = " + "0x%04X\n", filter_flags); + priv->staging_rxon.filter_flags = + cpu_to_le32(filter_flags); + iwl_commit_rxon(priv); + } + } + mutex_unlock(&priv->mutex); + + return count; +} + +static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags, + store_filter_flags); + +static ssize_t show_tune(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + + return sprintf(buf, "0x%04X\n", + (priv->phymode << 8) | + le16_to_cpu(priv->active_rxon.channel)); +} + +static void iwl_set_flags_for_phymode(struct iwl_priv *priv, u8 phymode); + +static ssize_t store_tune(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + char *p = (char *)buf; + u16 tune = simple_strtoul(p, &p, 0); + u8 phymode = (tune >> 8) & 0xff; + u16 channel = tune & 0xff; + + IWL_DEBUG_INFO("Tune request to:%d channel:%d\n", phymode, channel); + + mutex_lock(&priv->mutex); + if ((le16_to_cpu(priv->staging_rxon.channel) != channel) || + (priv->phymode != phymode)) { + const struct iwl_channel_info *ch_info; + + ch_info = iwl_get_channel_info(priv, phymode, channel); + if (!ch_info) { + IWL_WARNING("Requested invalid phymode/channel " + "combination: %d %d\n", phymode, channel); + mutex_unlock(&priv->mutex); + return -EINVAL; + } + + /* Cancel any currently running scans... */ + if (iwl_scan_cancel_timeout(priv, 100)) + IWL_WARNING("Could not cancel scan.\n"); + else { + IWL_DEBUG_INFO("Committing phymode and " + "rxon.channel = %d %d\n", + phymode, channel); + + iwl_set_rxon_channel(priv, phymode, channel); + iwl_set_flags_for_phymode(priv, phymode); + + iwl_set_rate(priv); + iwl_commit_rxon(priv); + } + } + mutex_unlock(&priv->mutex); + + return count; +} + +static DEVICE_ATTR(tune, S_IWUSR | S_IRUGO, show_tune, store_tune); + +#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT + +static ssize_t show_measurement(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + struct iwl_spectrum_notification measure_report; + u32 size = sizeof(measure_report), len = 0, ofs = 0; + u8 *data = (u8 *) & measure_report; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + if (!(priv->measurement_status & MEASUREMENT_READY)) { + spin_unlock_irqrestore(&priv->lock, flags); + return 0; + } + memcpy(&measure_report, &priv->measure_report, size); + priv->measurement_status = 0; + spin_unlock_irqrestore(&priv->lock, flags); + + while (size && (PAGE_SIZE - len)) { + hex_dump_to_buffer(data + ofs, size, 16, 1, buf + len, + PAGE_SIZE - len, 1); + len = strlen(buf); + if (PAGE_SIZE - len) + buf[len++] = '\n'; + + ofs += 16; + size -= min(size, 16U); + } + + return len; +} + +static ssize_t store_measurement(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + struct ieee80211_measurement_params params = { + .channel = le16_to_cpu(priv->active_rxon.channel), + .start_time = cpu_to_le64(priv->last_tsf), + .duration = cpu_to_le16(1), + }; + u8 type = IWL_MEASURE_BASIC; + u8 buffer[32]; + u8 channel; + + if (count) { + char *p = buffer; + strncpy(buffer, buf, min(sizeof(buffer), count)); + channel = simple_strtoul(p, NULL, 0); + if (channel) + params.channel = channel; + + p = buffer; + while (*p && *p != ' ') + p++; + if (*p) + type = simple_strtoul(p + 1, NULL, 0); + } + + IWL_DEBUG_INFO("Invoking measurement of type %d on " + "channel %d (for '%s')\n", type, params.channel, buf); + iwl_get_measurement(priv, ¶ms, type); + + return count; +} + +static DEVICE_ATTR(measurement, S_IRUSR | S_IWUSR, + show_measurement, store_measurement); +#endif /* CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT */ + +static ssize_t show_rate(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + unsigned long flags; + int i; + + spin_lock_irqsave(&priv->sta_lock, flags); + if (priv->iw_mode == IEEE80211_IF_TYPE_STA) + i = priv->stations[IWL_AP_ID].current_rate.s.rate; + else + i = priv->stations[IWL_STA_ID].current_rate.s.rate; + spin_unlock_irqrestore(&priv->sta_lock, flags); + + i = iwl_rate_index_from_plcp(i); + if (i == -1) + return sprintf(buf, "0\n"); + + return sprintf(buf, "%d%s\n", + (iwl_rates[i].ieee >> 1), + (iwl_rates[i].ieee & 0x1) ? ".5" : ""); +} + +static DEVICE_ATTR(rate, S_IRUSR, show_rate, NULL); + +static ssize_t store_retry_rate(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + + priv->retry_rate = simple_strtoul(buf, NULL, 0); + if (priv->retry_rate <= 0) + priv->retry_rate = 1; + + return count; +} + +static ssize_t show_retry_rate(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + return sprintf(buf, "%d", priv->retry_rate); +} + +static DEVICE_ATTR(retry_rate, S_IWUSR | S_IRUSR, show_retry_rate, + store_retry_rate); + +static ssize_t store_power_level(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + int rc; + int mode; + + mode = simple_strtoul(buf, NULL, 0); + mutex_lock(&priv->mutex); + + if (!iwl_is_ready(priv)) { + rc = -EAGAIN; + goto out; + } + + if ((mode < 1) || (mode > IWL_POWER_LIMIT) || (mode == IWL_POWER_AC)) + mode = IWL_POWER_AC; + else + mode |= IWL_POWER_ENABLED; + + if (mode != priv->power_mode) { + rc = iwl_send_power_mode(priv, IWL_POWER_LEVEL(mode)); + if (rc) { + IWL_DEBUG_MAC80211("failed setting power mode.\n"); + goto out; + } + priv->power_mode = mode; + } + + rc = count; + + out: + mutex_unlock(&priv->mutex); + return rc; +} + +#define MAX_WX_STRING 80 + +/* Values are in microsecond */ +static const s32 timeout_duration[] = { + 350000, + 250000, + 75000, + 37000, + 25000, +}; +static const s32 period_duration[] = { + 400000, + 700000, + 1000000, + 1000000, + 1000000 +}; + +static ssize_t show_power_level(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + int level = IWL_POWER_LEVEL(priv->power_mode); + char *p = buf; + + p += sprintf(p, "%d ", level); + switch (level) { + case IWL_POWER_MODE_CAM: + case IWL_POWER_AC: + p += sprintf(p, "(AC)"); + break; + case IWL_POWER_BATTERY: + p += sprintf(p, "(BATTERY)"); + break; + default: + p += sprintf(p, + "(Timeout %dms, Period %dms)", + timeout_duration[level - 1] / 1000, + period_duration[level - 1] / 1000); + } + + if (!(priv->power_mode & IWL_POWER_ENABLED)) + p += sprintf(p, " OFF\n"); + else + p += sprintf(p, " \n"); + + return (p - buf + 1); + +} + +static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level, + store_power_level); + +static ssize_t show_channels(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + int len = 0, i; + struct ieee80211_channel *channels = NULL; + const struct ieee80211_hw_mode *hw_mode = NULL; + int count = 0; + + if (!iwl_is_ready(priv)) + return -EAGAIN; + + hw_mode = iwl_get_hw_mode(priv, MODE_IEEE80211G); + if (!hw_mode) + hw_mode = iwl_get_hw_mode(priv, MODE_IEEE80211B); + if (hw_mode) { + channels = hw_mode->channels; + count = hw_mode->num_channels; + } + + len += + sprintf(&buf[len], + "Displaying %d channels in 2.4GHz band " + "(802.11bg):\n", count); + + for (i = 0; i < count; i++) + len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n", + channels[i].chan, + channels[i].power_level, + channels[i]. + flag & IEEE80211_CHAN_W_RADAR_DETECT ? + " (IEEE 802.11h required)" : "", + (!(channels[i].flag & IEEE80211_CHAN_W_IBSS) + || (channels[i]. + flag & + IEEE80211_CHAN_W_RADAR_DETECT)) ? "" : + ", IBSS", + channels[i]. + flag & IEEE80211_CHAN_W_ACTIVE_SCAN ? + "active/passive" : "passive only"); + + hw_mode = iwl_get_hw_mode(priv, MODE_IEEE80211A); + if (hw_mode) { + channels = hw_mode->channels; + count = hw_mode->num_channels; + } else { + channels = NULL; + count = 0; + } + + len += sprintf(&buf[len], "Displaying %d channels in 5.2GHz band " + "(802.11a):\n", count); + + for (i = 0; i < count; i++) + len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n", + channels[i].chan, + channels[i].power_level, + channels[i]. + flag & IEEE80211_CHAN_W_RADAR_DETECT ? + " (IEEE 802.11h required)" : "", + (!(channels[i].flag & IEEE80211_CHAN_W_IBSS) + || (channels[i]. + flag & + IEEE80211_CHAN_W_RADAR_DETECT)) ? "" : + ", IBSS", + channels[i]. + flag & IEEE80211_CHAN_W_ACTIVE_SCAN ? + "active/passive" : "passive only"); + + return len; +} + +static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL); + +static ssize_t show_statistics(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + u32 size = sizeof(struct iwl_notif_statistics); + u32 len = 0, ofs = 0; + u8 *data = (u8 *) & priv->statistics; + int rc = 0; + + if (!iwl_is_alive(priv)) + return -EAGAIN; + + mutex_lock(&priv->mutex); + rc = iwl_send_statistics_request(priv); + mutex_unlock(&priv->mutex); + + if (rc) { + len = sprintf(buf, + "Error sending statistics request: 0x%08X\n", rc); + return len; + } + + while (size && (PAGE_SIZE - len)) { + hex_dump_to_buffer(data + ofs, size, 16, 1, buf + len, + PAGE_SIZE - len, 1); + len = strlen(buf); + if (PAGE_SIZE - len) + buf[len++] = '\n'; + + ofs += 16; + size -= min(size, 16U); + } + + return len; +} + +static DEVICE_ATTR(statistics, S_IRUGO, show_statistics, NULL); + +static ssize_t show_antenna(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + + if (!iwl_is_alive(priv)) + return -EAGAIN; + + return sprintf(buf, "%d\n", priv->antenna); +} + +static ssize_t store_antenna(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int ant; + struct iwl_priv *priv = dev_get_drvdata(d); + + if (count == 0) + return 0; + + if (sscanf(buf, "%1i", &ant) != 1) { + IWL_DEBUG_INFO("not in hex or decimal form.\n"); + return count; + } + + if ((ant >= 0) && (ant <= 2)) { + IWL_DEBUG_INFO("Setting antenna select to %d.\n", ant); + priv->antenna = (enum iwl_antenna)ant; + } else + IWL_DEBUG_INFO("Bad antenna select value %d.\n", ant); + + + return count; +} + +static DEVICE_ATTR(antenna, S_IWUSR | S_IRUGO, show_antenna, store_antenna); + +static ssize_t show_status(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + if (!iwl_is_alive(priv)) + return -EAGAIN; + return sprintf(buf, "0x%08x\n", (int)priv->status); +} + +static DEVICE_ATTR(status, S_IRUGO, show_status, NULL); + +static ssize_t dump_error_log(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + char *p = (char *)buf; + + if (p[0] == '1') + iwl_dump_nic_error_log((struct iwl_priv *)d->driver_data); + + return strnlen(buf, count); +} + +static DEVICE_ATTR(dump_errors, S_IWUSR, NULL, dump_error_log); + +static ssize_t dump_event_log(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + char *p = (char *)buf; + + if (p[0] == '1') + iwl_dump_nic_event_log((struct iwl_priv *)d->driver_data); + + return strnlen(buf, count); +} + +static DEVICE_ATTR(dump_events, S_IWUSR, NULL, dump_event_log); + +/***************************************************************************** + * + * driver setup and teardown + * + *****************************************************************************/ + +static void iwl_setup_deferred_work(struct iwl_priv *priv) +{ + priv->workqueue = create_workqueue(DRV_NAME); + + init_waitqueue_head(&priv->wait_command_queue); + + INIT_WORK(&priv->up, iwl_bg_up); + INIT_WORK(&priv->restart, iwl_bg_restart); + INIT_WORK(&priv->rx_replenish, iwl_bg_rx_replenish); + INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed); + INIT_WORK(&priv->request_scan, iwl_bg_request_scan); + INIT_WORK(&priv->abort_scan, iwl_bg_abort_scan); + INIT_WORK(&priv->rf_kill, iwl_bg_rf_kill); + INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update); + INIT_DELAYED_WORK(&priv->post_associate, iwl_bg_post_associate); + INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start); + INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start); + INIT_DELAYED_WORK(&priv->scan_check, iwl_bg_scan_check); + + iwl_hw_setup_deferred_work(priv); + + tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) + iwl_irq_tasklet, (unsigned long)priv); +} + +static void iwl_cancel_deferred_work(struct iwl_priv *priv) +{ + iwl_hw_cancel_deferred_work(priv); + + cancel_delayed_work(&priv->scan_check); + cancel_delayed_work(&priv->alive_start); + cancel_delayed_work(&priv->post_associate); + cancel_work_sync(&priv->beacon_update); +} + +static struct attribute *iwl_sysfs_entries[] = { + &dev_attr_antenna.attr, + &dev_attr_channels.attr, + &dev_attr_dump_errors.attr, + &dev_attr_dump_events.attr, + &dev_attr_flags.attr, + &dev_attr_filter_flags.attr, +#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT + &dev_attr_measurement.attr, +#endif + &dev_attr_power_level.attr, + &dev_attr_rate.attr, + &dev_attr_retry_rate.attr, + &dev_attr_rf_kill.attr, + &dev_attr_rs_window.attr, + &dev_attr_statistics.attr, + &dev_attr_status.attr, + &dev_attr_temperature.attr, + &dev_attr_tune.attr, + &dev_attr_tx_power.attr, + + NULL +}; + +static struct attribute_group iwl_attribute_group = { + .name = NULL, /* put in device directory */ + .attrs = iwl_sysfs_entries, +}; + +static struct ieee80211_ops iwl_hw_ops = { + .tx = iwl_mac_tx, + .open = iwl_mac_open, + .stop = iwl_mac_stop, + .add_interface = iwl_mac_add_interface, + .remove_interface = iwl_mac_remove_interface, + .config = iwl_mac_config, + .config_interface = iwl_mac_config_interface, + .set_key = iwl_mac_set_key, + .get_stats = iwl_mac_get_stats, + .get_tx_stats = iwl_mac_get_tx_stats, + .conf_tx = iwl_mac_conf_tx, + .get_tsf = iwl_mac_get_tsf, + .reset_tsf = iwl_mac_reset_tsf, + .beacon_update = iwl_mac_beacon_update, + .hw_scan = iwl_mac_hw_scan +}; + +static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + int err = 0; + u32 pci_id; + struct iwl_priv *priv; + struct ieee80211_hw *hw; + int i; + + if (iwl_param_disable_hw_scan) { + IWL_DEBUG_INFO("Disabling hw_scan\n"); + iwl_hw_ops.hw_scan = NULL; + } + + if ((iwl_param_queues_num > IWL_MAX_NUM_QUEUES) || + (iwl_param_queues_num < IWL_MIN_NUM_QUEUES)) { + IWL_ERROR("invalid queues_num, should be between %d and %d\n", + IWL_MIN_NUM_QUEUES, IWL_MAX_NUM_QUEUES); + err = -EINVAL; + goto out; + } + + /* mac80211 allocates memory for this device instance, including + * space for this driver's private structure */ + hw = ieee80211_alloc_hw(sizeof(struct iwl_priv), &iwl_hw_ops); + if (hw == NULL) { + IWL_ERROR("Can not allocate network device\n"); + err = -ENOMEM; + goto out; + } + SET_IEEE80211_DEV(hw, &pdev->dev); + + IWL_DEBUG_INFO("*** LOAD DRIVER ***\n"); + priv = hw->priv; + priv->hw = hw; + + priv->pci_dev = pdev; + priv->antenna = (enum iwl_antenna)iwl_param_antenna; +#ifdef CONFIG_IWLWIFI_DEBUG + iwl_debug_level = iwl_param_debug; + atomic_set(&priv->restrict_refcnt, 0); +#endif + priv->retry_rate = 1; + + priv->ibss_beacon = NULL; + + /* Tell mac80211 and its clients (e.g. Wireless Extensions) + * the range of signal quality values that we'll provide. + * Negative values for level/noise indicate that we'll provide dBm. + * For WE, at least, non-0 values here *enable* display of values + * in app (iwconfig). */ + hw->max_rssi = -20; /* signal level, negative indicates dBm */ + hw->max_noise = -20; /* noise level, negative indicates dBm */ + hw->max_signal = 100; /* link quality indication (%) */ + + /* Tell mac80211 our Tx characteristics */ + hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE; + + hw->queues = 4; + + spin_lock_init(&priv->lock); + spin_lock_init(&priv->power_data.lock); + spin_lock_init(&priv->sta_lock); + spin_lock_init(&priv->hcmd_lock); + + for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++) + INIT_LIST_HEAD(&priv->ibss_mac_hash[i]); + + INIT_LIST_HEAD(&priv->free_frames); + + mutex_init(&priv->mutex); + if (pci_enable_device(pdev)) { + err = -ENODEV; + goto out_ieee80211_free_hw; + } + + pci_set_master(pdev); + + iwl_clear_stations_table(priv); + + priv->data_retry_limit = -1; + priv->ieee_channels = NULL; + priv->ieee_rates = NULL; + priv->phymode = -1; + + err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (!err) + err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); + if (err) { + printk(KERN_WARNING DRV_NAME ": No suitable DMA available.\n"); + goto out_pci_disable_device; + } + + pci_set_drvdata(pdev, priv); + err = pci_request_regions(pdev, DRV_NAME); + if (err) + goto out_pci_disable_device; + /* We disable the RETRY_TIMEOUT register (0x41) to keep + * PCI Tx retries from interfering with C3 CPU state */ + pci_write_config_byte(pdev, 0x41, 0x00); + priv->hw_base = pci_iomap(pdev, 0, 0); + if (!priv->hw_base) { + err = -ENODEV; + goto out_pci_release_regions; + } + + IWL_DEBUG_INFO("pci_resource_len = 0x%08llx\n", + (unsigned long long) pci_resource_len(pdev, 0)); + IWL_DEBUG_INFO("pci_resource_base = %p\n", priv->hw_base); + + /* Initialize module parameter values here */ + + if (iwl_param_disable) { + set_bit(STATUS_RF_KILL_SW, &priv->status); + IWL_DEBUG_INFO("Radio disabled.\n"); + } + + priv->iw_mode = IEEE80211_IF_TYPE_STA; + + pci_id = + (priv->pci_dev->device << 16) | priv->pci_dev->subsystem_device; + + switch (pci_id) { + case 0x42221005: /* 0x4222 0x8086 0x1005 is BG SKU */ + case 0x42221034: /* 0x4222 0x8086 0x1034 is BG SKU */ + case 0x42271014: /* 0x4227 0x8086 0x1014 is BG SKU */ + case 0x42221044: /* 0x4222 0x8086 0x1044 is BG SKU */ + priv->is_abg = 0; + break; + + /* + * Rest are assumed ABG SKU -- if this is not the + * case then the card will get the wrong 'Detected' + * line in the kernel log however the code that + * initializes the GEO table will detect no A-band + * channels and remove the is_abg mask. + */ + default: + priv->is_abg = 1; + break; + } + + printk(KERN_INFO DRV_NAME + ": Detected Intel PRO/Wireless 3945%sBG Network Connection\n", + priv->is_abg ? "A" : ""); + + /* Device-specific setup */ + if (iwl_hw_set_hw_setting(priv)) { + IWL_ERROR("failed to set hw settings\n"); + mutex_unlock(&priv->mutex); + goto out_iounmap; + } + +#ifdef CONFIG_IWLWIFI_QOS + if (iwl_param_qos_enable) + priv->qos_data.qos_enable = 1; + + iwl_reset_qos(priv); + + priv->qos_data.qos_active = 0; + priv->qos_data.qos_cap.val = 0; +#endif /* CONFIG_IWLWIFI_QOS */ + + iwl_set_rxon_channel(priv, MODE_IEEE80211G, 6); + iwl_setup_deferred_work(priv); + iwl_setup_rx_handlers(priv); + + priv->rates_mask = IWL_RATES_MASK; + /* If power management is turned on, default to AC mode */ + priv->power_mode = IWL_POWER_AC; + priv->user_txpower_limit = IWL_DEFAULT_TX_POWER; + + pci_enable_msi(pdev); + + err = request_irq(pdev->irq, iwl_isr, IRQF_SHARED, DRV_NAME, priv); + if (err) { + IWL_ERROR("Error allocating IRQ %d\n", pdev->irq); + goto out_disable_msi; + } + + mutex_lock(&priv->mutex); + + err = sysfs_create_group(&pdev->dev.kobj, &iwl_attribute_group); + if (err) { + IWL_ERROR("failed to create sysfs device attributes\n"); + mutex_unlock(&priv->mutex); + goto out_release_irq; + } + + /* fetch ucode file from disk, alloc and copy to bus-master buffers ... + * ucode filename and max sizes are card-specific. */ + err = iwl_read_ucode(priv); + if (err) { + IWL_ERROR("Could not read microcode: %d\n", err); + mutex_unlock(&priv->mutex); + goto out_pci_alloc; + } + + mutex_unlock(&priv->mutex); + + IWL_DEBUG_INFO("Queing UP work.\n"); + + queue_work(priv->workqueue, &priv->up); + + return 0; + + out_pci_alloc: + iwl_dealloc_ucode_pci(priv); + + sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group); + + out_release_irq: + free_irq(pdev->irq, priv); + + out_disable_msi: + pci_disable_msi(pdev); + destroy_workqueue(priv->workqueue); + priv->workqueue = NULL; + iwl_unset_hw_setting(priv); + + out_iounmap: + pci_iounmap(pdev, priv->hw_base); + out_pci_release_regions: + pci_release_regions(pdev); + out_pci_disable_device: + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + out_ieee80211_free_hw: + ieee80211_free_hw(priv->hw); + out: + return err; +} + +static void iwl_pci_remove(struct pci_dev *pdev) +{ + struct iwl_priv *priv = pci_get_drvdata(pdev); + struct list_head *p, *q; + int i; + + if (!priv) + return; + + IWL_DEBUG_INFO("*** UNLOAD DRIVER ***\n"); + + mutex_lock(&priv->mutex); + set_bit(STATUS_EXIT_PENDING, &priv->status); + __iwl_down(priv); + mutex_unlock(&priv->mutex); + + /* Free MAC hash list for ADHOC */ + for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++) { + list_for_each_safe(p, q, &priv->ibss_mac_hash[i]) { + list_del(p); + kfree(list_entry(p, struct iwl_ibss_seq, list)); + } + } + + sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group); + + iwl_dealloc_ucode_pci(priv); + + if (priv->rxq.bd) + iwl_rx_queue_free(priv, &priv->rxq); + iwl_hw_txq_ctx_free(priv); + + iwl_unset_hw_setting(priv); + iwl_clear_stations_table(priv); + + if (priv->mac80211_registered) { + ieee80211_unregister_hw(priv->hw); + iwl_rate_control_unregister(priv->hw); + } + + /* ieee80211_unregister_hw calls iwl_mac_stop, which flushes + * priv->workqueue... so we can't take down the workqueue + * until now... */ + destroy_workqueue(priv->workqueue); + priv->workqueue = NULL; + + free_irq(pdev->irq, priv); + pci_disable_msi(pdev); + pci_iounmap(pdev, priv->hw_base); + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + + kfree(priv->channel_info); + + kfree(priv->ieee_channels); + kfree(priv->ieee_rates); + + if (priv->ibss_beacon) + dev_kfree_skb(priv->ibss_beacon); + + ieee80211_free_hw(priv->hw); +} + +#ifdef CONFIG_PM + +static int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct iwl_priv *priv = pci_get_drvdata(pdev); + + mutex_lock(&priv->mutex); + + set_bit(STATUS_IN_SUSPEND, &priv->status); + + /* Take down the device; powers it off, etc. */ + __iwl_down(priv); + + if (priv->mac80211_registered) + ieee80211_stop_queues(priv->hw); + + pci_save_state(pdev); + pci_disable_device(pdev); + pci_set_power_state(pdev, PCI_D3hot); + + mutex_unlock(&priv->mutex); + + return 0; +} + +static void iwl_resume(struct iwl_priv *priv) +{ + unsigned long flags; + + /* The following it a temporary work around due to the + * suspend / resume not fully initializing the NIC correctly. + * Without all of the following, resume will not attempt to take + * down the NIC (it shouldn't really need to) and will just try + * and bring the NIC back up. However that fails during the + * ucode verification process. This then causes iwl_down to be + * called *after* iwl_hw_nic_init() has succeeded -- which + * then lets the next init sequence succeed. So, we've + * replicated all of that NIC init code here... */ + + iwl_write32(priv, CSR_INT, 0xFFFFFFFF); + + iwl_hw_nic_init(priv); + + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, + CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); + iwl_write32(priv, CSR_INT, 0xFFFFFFFF); + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + + /* tell the device to stop sending interrupts */ + iwl_disable_interrupts(priv); + + spin_lock_irqsave(&priv->lock, flags); + iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + + if (!iwl_grab_restricted_access(priv)) { + iwl_write_restricted_reg(priv, APMG_CLK_DIS_REG, + APMG_CLK_VAL_DMA_CLK_RQT); + iwl_release_restricted_access(priv); + } + spin_unlock_irqrestore(&priv->lock, flags); + + udelay(5); + + iwl_hw_nic_reset(priv); + + /* Bring the device back up */ + clear_bit(STATUS_IN_SUSPEND, &priv->status); + queue_work(priv->workqueue, &priv->up); +} + +static int iwl_pci_resume(struct pci_dev *pdev) +{ + struct iwl_priv *priv = pci_get_drvdata(pdev); + int err; + + printk(KERN_INFO "Coming out of suspend...\n"); + + mutex_lock(&priv->mutex); + + pci_set_power_state(pdev, PCI_D0); + err = pci_enable_device(pdev); + pci_restore_state(pdev); + + /* + * Suspend/Resume resets the PCI configuration space, so we have to + * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries + * from interfering with C3 CPU state. pci_restore_state won't help + * here since it only restores the first 64 bytes pci config header. + */ + pci_write_config_byte(pdev, 0x41, 0x00); + + iwl_resume(priv); + mutex_unlock(&priv->mutex); + + return 0; +} + +#endif /* CONFIG_PM */ + +/***************************************************************************** + * + * driver and module entry point + * + *****************************************************************************/ + +static struct pci_driver iwl_driver = { + .name = DRV_NAME, + .id_table = iwl_hw_card_ids, + .probe = iwl_pci_probe, + .remove = __devexit_p(iwl_pci_remove), +#ifdef CONFIG_PM + .suspend = iwl_pci_suspend, + .resume = iwl_pci_resume, +#endif +}; + +static int __init iwl_init(void) +{ + + int ret; + printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n"); + printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n"); + ret = pci_register_driver(&iwl_driver); + if (ret) { + IWL_ERROR("Unable to initialize PCI module\n"); + return ret; + } +#ifdef CONFIG_IWLWIFI_DEBUG + ret = driver_create_file(&iwl_driver.driver, &driver_attr_debug_level); + if (ret) { + IWL_ERROR("Unable to create driver sysfs file\n"); + pci_unregister_driver(&iwl_driver); + return ret; + } +#endif + + return ret; +} + +static void __exit iwl_exit(void) +{ +#ifdef CONFIG_IWLWIFI_DEBUG + driver_remove_file(&iwl_driver.driver, &driver_attr_debug_level); +#endif + pci_unregister_driver(&iwl_driver); +} + +module_param_named(antenna, iwl_param_antenna, int, 0444); +MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])"); +module_param_named(disable, iwl_param_disable, int, 0444); +MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])"); +module_param_named(hwcrypto, iwl_param_hwcrypto, int, 0444); +MODULE_PARM_DESC(hwcrypto, + "using hardware crypto engine (default 0 [software])\n"); +module_param_named(debug, iwl_param_debug, int, 0444); +MODULE_PARM_DESC(debug, "debug output mask"); +module_param_named(disable_hw_scan, iwl_param_disable_hw_scan, int, 0444); +MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)"); + +module_param_named(queues_num, iwl_param_queues_num, int, 0444); +MODULE_PARM_DESC(queues_num, "number of hw queues."); + +/* QoS */ +module_param_named(qos_enable, iwl_param_qos_enable, int, 0444); +MODULE_PARM_DESC(qos_enable, "enable all QoS functionality"); + +module_exit(iwl_exit); +module_init(iwl_init); diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c new file mode 100644 index 00000000000..b79dabc8c01 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -0,0 +1,9323 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project, as well + * as portions of the ieee80211 subsystem header files. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +/* + * NOTE: This file (iwl-base.c) is used to build to multiple hardware targets + * by defining IWL to either 3945 or 4965. The Makefile used when building + * the base targets will create base-3945.o and base-4965.o + * + * The eventual goal is to move as many of the #if IWL / #endif blocks out of + * this file and into the hardware specific implementation files (iwl-XXXX.c) + * and leave only the common (non #ifdef sprinkled) code in this file + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "iwlwifi.h" +#include "iwl-4965.h" +#include "iwl-helpers.h" + +#ifdef CONFIG_IWLWIFI_DEBUG +u32 iwl_debug_level; +#endif + +/****************************************************************************** + * + * module boiler plate + * + ******************************************************************************/ + +/* module parameters */ +int iwl_param_disable_hw_scan; +int iwl_param_debug; +int iwl_param_disable; /* def: enable radio */ +int iwl_param_antenna; /* def: 0 = both antennas (use diversity) */ +int iwl_param_hwcrypto; /* def: using software encryption */ +int iwl_param_qos_enable = 1; +int iwl_param_queues_num = IWL_MAX_NUM_QUEUES; + +/* + * module name, copyright, version, etc. + * NOTE: DRV_NAME is defined in iwlwifi.h for use by iwl-debug.h and printk + */ + +#define DRV_DESCRIPTION "Intel(R) Wireless WiFi Link 4965AGN driver for Linux" + +#ifdef CONFIG_IWLWIFI_DEBUG +#define VD "d" +#else +#define VD +#endif + +#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT +#define VS "s" +#else +#define VS +#endif + +#define IWLWIFI_VERSION "0.1.15k" VD VS +#define DRV_COPYRIGHT "Copyright(c) 2003-2007 Intel Corporation" +#define DRV_VERSION IWLWIFI_VERSION + +/* Change firmware file name, using "-" and incrementing number, + * *only* when uCode interface or architecture changes so that it + * is not compatible with earlier drivers. + * This number will also appear in << 8 position of 1st dword of uCode file */ +#define IWL4965_UCODE_API "-1" + +MODULE_DESCRIPTION(DRV_DESCRIPTION); +MODULE_VERSION(DRV_VERSION); +MODULE_AUTHOR(DRV_COPYRIGHT); +MODULE_LICENSE("GPL"); + +__le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr) +{ + u16 fc = le16_to_cpu(hdr->frame_control); + int hdr_len = ieee80211_get_hdrlen(fc); + + if ((fc & 0x00cc) == (IEEE80211_STYPE_QOS_DATA | IEEE80211_FTYPE_DATA)) + return (__le16 *) ((u8 *) hdr + hdr_len - QOS_CONTROL_LEN); + return NULL; +} + +static const struct ieee80211_hw_mode *iwl_get_hw_mode( + struct iwl_priv *priv, int mode) +{ + int i; + + for (i = 0; i < 3; i++) + if (priv->modes[i].mode == mode) + return &priv->modes[i]; + + return NULL; +} + +static int iwl_is_empty_essid(const char *essid, int essid_len) +{ + /* Single white space is for Linksys APs */ + if (essid_len == 1 && essid[0] == ' ') + return 1; + + /* Otherwise, if the entire essid is 0, we assume it is hidden */ + while (essid_len) { + essid_len--; + if (essid[essid_len] != '\0') + return 0; + } + + return 1; +} + +static const char *iwl_escape_essid(const char *essid, u8 essid_len) +{ + static char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; + const char *s = essid; + char *d = escaped; + + if (iwl_is_empty_essid(essid, essid_len)) { + memcpy(escaped, "", sizeof("")); + return escaped; + } + + essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE); + while (essid_len--) { + if (*s == '\0') { + *d++ = '\\'; + *d++ = '0'; + s++; + } else + *d++ = *s++; + } + *d = '\0'; + return escaped; +} + +static void iwl_print_hex_dump(int level, void *p, u32 len) +{ +#ifdef CONFIG_IWLWIFI_DEBUG + if (!(iwl_debug_level & level)) + return; + + print_hex_dump(KERN_DEBUG, "iwl data: ", DUMP_PREFIX_OFFSET, 16, 1, + p, len, 1); +#endif +} + +/*************** DMA-QUEUE-GENERAL-FUNCTIONS ***** + * DMA services + * + * Theory of operation + * + * A queue is a circular buffers with 'Read' and 'Write' pointers. + * 2 empty entries always kept in the buffer to protect from overflow. + * + * For Tx queue, there are low mark and high mark limits. If, after queuing + * the packet for Tx, free space become < low mark, Tx queue stopped. When + * reclaiming packets (on 'tx done IRQ), if free space become > high mark, + * Tx queue resumed. + * + * The IPW operates with six queues, one receive queue in the device's + * sram, one transmit queue for sending commands to the device firmware, + * and four transmit queues for data. + ***************************************************/ + +static int iwl_queue_space(const struct iwl_queue *q) +{ + int s = q->last_used - q->first_empty; + + if (q->last_used > q->first_empty) + s -= q->n_bd; + + if (s <= 0) + s += q->n_window; + /* keep some reserve to not confuse empty and full situations */ + s -= 2; + if (s < 0) + s = 0; + return s; +} + +/* XXX: n_bd must be power-of-two size */ +static inline int iwl_queue_inc_wrap(int index, int n_bd) +{ + return ++index & (n_bd - 1); +} + +/* XXX: n_bd must be power-of-two size */ +static inline int iwl_queue_dec_wrap(int index, int n_bd) +{ + return --index & (n_bd - 1); +} + +static inline int x2_queue_used(const struct iwl_queue *q, int i) +{ + return q->first_empty > q->last_used ? + (i >= q->last_used && i < q->first_empty) : + !(i < q->last_used && i >= q->first_empty); +} + +static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge) +{ + if (is_huge) + return q->n_window; + + return index & (q->n_window - 1); +} + +static int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q, + int count, int slots_num, u32 id) +{ + q->n_bd = count; + q->n_window = slots_num; + q->id = id; + + /* count must be power-of-two size, otherwise iwl_queue_inc_wrap + * and iwl_queue_dec_wrap are broken. */ + BUG_ON(!is_power_of_2(count)); + + /* slots_num must be power-of-two size, otherwise + * get_cmd_index is broken. */ + BUG_ON(!is_power_of_2(slots_num)); + + q->low_mark = q->n_window / 4; + if (q->low_mark < 4) + q->low_mark = 4; + + q->high_mark = q->n_window / 8; + if (q->high_mark < 2) + q->high_mark = 2; + + q->first_empty = q->last_used = 0; + + return 0; +} + +static int iwl_tx_queue_alloc(struct iwl_priv *priv, + struct iwl_tx_queue *txq, u32 id) +{ + struct pci_dev *dev = priv->pci_dev; + + if (id != IWL_CMD_QUEUE_NUM) { + txq->txb = kmalloc(sizeof(txq->txb[0]) * + TFD_QUEUE_SIZE_MAX, GFP_KERNEL); + if (!txq->txb) { + IWL_ERROR("kmalloc for auxilary BD " + "structures failed\n"); + goto error; + } + } else + txq->txb = NULL; + + txq->bd = pci_alloc_consistent(dev, + sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX, + &txq->q.dma_addr); + + if (!txq->bd) { + IWL_ERROR("pci_alloc_consistent(%zd) failed\n", + sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX); + goto error; + } + txq->q.id = id; + + return 0; + + error: + if (txq->txb) { + kfree(txq->txb); + txq->txb = NULL; + } + + return -ENOMEM; +} + +int iwl_tx_queue_init(struct iwl_priv *priv, + struct iwl_tx_queue *txq, int slots_num, u32 txq_id) +{ + struct pci_dev *dev = priv->pci_dev; + int len; + int rc = 0; + + /* alocate command space + one big command for scan since scan + * command is very huge the system will not have two scan at the + * same time */ + len = sizeof(struct iwl_cmd) * slots_num; + if (txq_id == IWL_CMD_QUEUE_NUM) + len += IWL_MAX_SCAN_SIZE; + txq->cmd = pci_alloc_consistent(dev, len, &txq->dma_addr_cmd); + if (!txq->cmd) + return -ENOMEM; + + rc = iwl_tx_queue_alloc(priv, txq, txq_id); + if (rc) { + pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd); + + return -ENOMEM; + } + txq->need_update = 0; + + /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise + * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */ + BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1)); + iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id); + + iwl_hw_tx_queue_init(priv, txq); + + return 0; +} + +/** + * iwl_tx_queue_free - Deallocate DMA queue. + * @txq: Transmit queue to deallocate. + * + * Empty queue by removing and destroying all BD's. + * Free all buffers. txq itself is not freed. + * + */ +void iwl_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq) +{ + struct iwl_queue *q = &txq->q; + struct pci_dev *dev = priv->pci_dev; + int len; + + if (q->n_bd == 0) + return; + + /* first, empty all BD's */ + for (; q->first_empty != q->last_used; + q->last_used = iwl_queue_inc_wrap(q->last_used, q->n_bd)) + iwl_hw_txq_free_tfd(priv, txq); + + len = sizeof(struct iwl_cmd) * q->n_window; + if (q->id == IWL_CMD_QUEUE_NUM) + len += IWL_MAX_SCAN_SIZE; + + pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd); + + /* free buffers belonging to queue itself */ + if (txq->q.n_bd) + pci_free_consistent(dev, sizeof(struct iwl_tfd_frame) * + txq->q.n_bd, txq->bd, txq->q.dma_addr); + + if (txq->txb) { + kfree(txq->txb); + txq->txb = NULL; + } + + /* 0 fill whole structure */ + memset(txq, 0, sizeof(*txq)); +} + +const u8 BROADCAST_ADDR[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + +/*************** STATION TABLE MANAGEMENT **** + * + * NOTE: This needs to be overhauled to better synchronize between + * how the iwl-4965.c is using iwl_hw_find_station vs. iwl-3945.c + * + * mac80211 should also be examined to determine if sta_info is duplicating + * the functionality provided here + */ + +/**************************************************************/ + +static u8 iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap) +{ + int index = IWL_INVALID_STATION; + int i; + unsigned long flags; + + spin_lock_irqsave(&priv->sta_lock, flags); + + if (is_ap) + index = IWL_AP_ID; + else if (is_broadcast_ether_addr(addr)) + index = priv->hw_setting.bcast_sta_id; + else + for (i = IWL_STA_ID; i < priv->hw_setting.max_stations; i++) + if (priv->stations[i].used && + !compare_ether_addr(priv->stations[i].sta.sta.addr, + addr)) { + index = i; + break; + } + + if (unlikely(index == IWL_INVALID_STATION)) + goto out; + + if (priv->stations[index].used) { + priv->stations[index].used = 0; + priv->num_stations--; + } + + BUG_ON(priv->num_stations < 0); + +out: + spin_unlock_irqrestore(&priv->sta_lock, flags); + return 0; +} + +static void iwl_clear_stations_table(struct iwl_priv *priv) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->sta_lock, flags); + + priv->num_stations = 0; + memset(priv->stations, 0, sizeof(priv->stations)); + + spin_unlock_irqrestore(&priv->sta_lock, flags); +} + +u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags) +{ + int i; + int index = IWL_INVALID_STATION; + struct iwl_station_entry *station; + unsigned long flags_spin; + + spin_lock_irqsave(&priv->sta_lock, flags_spin); + if (is_ap) + index = IWL_AP_ID; + else if (is_broadcast_ether_addr(addr)) + index = priv->hw_setting.bcast_sta_id; + else + for (i = IWL_STA_ID; i < priv->hw_setting.max_stations; i++) { + if (!compare_ether_addr(priv->stations[i].sta.sta.addr, + addr)) { + index = i; + break; + } + + if (!priv->stations[i].used && + index == IWL_INVALID_STATION) + index = i; + } + + + /* These twh conditions has the same outcome but keep them separate + since they have different meaning */ + if (unlikely(index == IWL_INVALID_STATION)) { + spin_unlock_irqrestore(&priv->sta_lock, flags_spin); + return index; + } + + if (priv->stations[index].used && + !compare_ether_addr(priv->stations[index].sta.sta.addr, addr)) { + spin_unlock_irqrestore(&priv->sta_lock, flags_spin); + return index; + } + + + IWL_DEBUG_ASSOC("Add STA ID %d: " MAC_FMT "\n", index, MAC_ARG(addr)); + station = &priv->stations[index]; + station->used = 1; + priv->num_stations++; + + memset(&station->sta, 0, sizeof(struct iwl_addsta_cmd)); + memcpy(station->sta.sta.addr, addr, ETH_ALEN); + station->sta.mode = 0; + station->sta.sta.sta_id = index; + station->sta.station_flags = 0; + +#ifdef CONFIG_IWLWIFI_HT + /* BCAST station and IBSS stations do not work in HT mode */ + if (index != priv->hw_setting.bcast_sta_id && + priv->iw_mode != IEEE80211_IF_TYPE_IBSS) + iwl4965_set_ht_add_station(priv, index); +#endif /*CONFIG_IWLWIFI_HT*/ + + spin_unlock_irqrestore(&priv->sta_lock, flags_spin); + iwl_send_add_station(priv, &station->sta, flags); + return index; + +} + +/*************** DRIVER STATUS FUNCTIONS *****/ + +static inline int iwl_is_ready(struct iwl_priv *priv) +{ + /* The adapter is 'ready' if READY and GEO_CONFIGURED bits are + * set but EXIT_PENDING is not */ + return test_bit(STATUS_READY, &priv->status) && + test_bit(STATUS_GEO_CONFIGURED, &priv->status) && + !test_bit(STATUS_EXIT_PENDING, &priv->status); +} + +static inline int iwl_is_alive(struct iwl_priv *priv) +{ + return test_bit(STATUS_ALIVE, &priv->status); +} + +static inline int iwl_is_init(struct iwl_priv *priv) +{ + return test_bit(STATUS_INIT, &priv->status); +} + +static inline int iwl_is_rfkill(struct iwl_priv *priv) +{ + return test_bit(STATUS_RF_KILL_HW, &priv->status) || + test_bit(STATUS_RF_KILL_SW, &priv->status); +} + +static inline int iwl_is_ready_rf(struct iwl_priv *priv) +{ + + if (iwl_is_rfkill(priv)) + return 0; + + return iwl_is_ready(priv); +} + +/*************** HOST COMMAND QUEUE FUNCTIONS *****/ + +#define IWL_CMD(x) case x : return #x + +static const char *get_cmd_string(u8 cmd) +{ + switch (cmd) { + IWL_CMD(REPLY_ALIVE); + IWL_CMD(REPLY_ERROR); + IWL_CMD(REPLY_RXON); + IWL_CMD(REPLY_RXON_ASSOC); + IWL_CMD(REPLY_QOS_PARAM); + IWL_CMD(REPLY_RXON_TIMING); + IWL_CMD(REPLY_ADD_STA); + IWL_CMD(REPLY_REMOVE_STA); + IWL_CMD(REPLY_REMOVE_ALL_STA); + IWL_CMD(REPLY_TX); + IWL_CMD(REPLY_RATE_SCALE); + IWL_CMD(REPLY_LEDS_CMD); + IWL_CMD(REPLY_TX_LINK_QUALITY_CMD); + IWL_CMD(RADAR_NOTIFICATION); + IWL_CMD(REPLY_QUIET_CMD); + IWL_CMD(REPLY_CHANNEL_SWITCH); + IWL_CMD(CHANNEL_SWITCH_NOTIFICATION); + IWL_CMD(REPLY_SPECTRUM_MEASUREMENT_CMD); + IWL_CMD(SPECTRUM_MEASURE_NOTIFICATION); + IWL_CMD(POWER_TABLE_CMD); + IWL_CMD(PM_SLEEP_NOTIFICATION); + IWL_CMD(PM_DEBUG_STATISTIC_NOTIFIC); + IWL_CMD(REPLY_SCAN_CMD); + IWL_CMD(REPLY_SCAN_ABORT_CMD); + IWL_CMD(SCAN_START_NOTIFICATION); + IWL_CMD(SCAN_RESULTS_NOTIFICATION); + IWL_CMD(SCAN_COMPLETE_NOTIFICATION); + IWL_CMD(BEACON_NOTIFICATION); + IWL_CMD(REPLY_TX_BEACON); + IWL_CMD(WHO_IS_AWAKE_NOTIFICATION); + IWL_CMD(QUIET_NOTIFICATION); + IWL_CMD(REPLY_TX_PWR_TABLE_CMD); + IWL_CMD(MEASURE_ABORT_NOTIFICATION); + IWL_CMD(REPLY_BT_CONFIG); + IWL_CMD(REPLY_STATISTICS_CMD); + IWL_CMD(STATISTICS_NOTIFICATION); + IWL_CMD(REPLY_CARD_STATE_CMD); + IWL_CMD(CARD_STATE_NOTIFICATION); + IWL_CMD(MISSED_BEACONS_NOTIFICATION); + IWL_CMD(REPLY_CT_KILL_CONFIG_CMD); + IWL_CMD(SENSITIVITY_CMD); + IWL_CMD(REPLY_PHY_CALIBRATION_CMD); + IWL_CMD(REPLY_RX_PHY_CMD); + IWL_CMD(REPLY_RX_MPDU_CMD); + IWL_CMD(REPLY_4965_RX); + IWL_CMD(REPLY_COMPRESSED_BA); + default: + return "UNKNOWN"; + + } +} + +#define HOST_COMPLETE_TIMEOUT (HZ / 2) + +/** + * iwl_enqueue_hcmd - enqueue a uCode command + * @priv: device private data point + * @cmd: a point to the ucode command structure + * + * The function returns < 0 values to indicate the operation is + * failed. On success, it turns the index (> 0) of command in the + * command queue. + */ +static int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) +{ + struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM]; + struct iwl_queue *q = &txq->q; + struct iwl_tfd_frame *tfd; + u32 *control_flags; + struct iwl_cmd *out_cmd; + u32 idx; + u16 fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr)); + dma_addr_t phys_addr; + int ret; + unsigned long flags; + + /* If any of the command structures end up being larger than + * the TFD_MAX_PAYLOAD_SIZE, and it sent as a 'small' command then + * we will need to increase the size of the TFD entries */ + BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) && + !(cmd->meta.flags & CMD_SIZE_HUGE)); + + if (iwl_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) { + IWL_ERROR("No space for Tx\n"); + return -ENOSPC; + } + + spin_lock_irqsave(&priv->hcmd_lock, flags); + + tfd = &txq->bd[q->first_empty]; + memset(tfd, 0, sizeof(*tfd)); + + control_flags = (u32 *) tfd; + + idx = get_cmd_index(q, q->first_empty, cmd->meta.flags & CMD_SIZE_HUGE); + out_cmd = &txq->cmd[idx]; + + out_cmd->hdr.cmd = cmd->id; + memcpy(&out_cmd->meta, &cmd->meta, sizeof(cmd->meta)); + memcpy(&out_cmd->cmd.payload, cmd->data, cmd->len); + + /* At this point, the out_cmd now has all of the incoming cmd + * information */ + + out_cmd->hdr.flags = 0; + out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(IWL_CMD_QUEUE_NUM) | + INDEX_TO_SEQ(q->first_empty)); + if (out_cmd->meta.flags & CMD_SIZE_HUGE) + out_cmd->hdr.sequence |= cpu_to_le16(SEQ_HUGE_FRAME); + + phys_addr = txq->dma_addr_cmd + sizeof(txq->cmd[0]) * idx + + offsetof(struct iwl_cmd, hdr); + iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size); + + IWL_DEBUG_HC("Sending command %s (#%x), seq: 0x%04X, " + "%d bytes at %d[%d]:%d\n", + get_cmd_string(out_cmd->hdr.cmd), + out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence), + fix_size, q->first_empty, idx, IWL_CMD_QUEUE_NUM); + + txq->need_update = 1; + ret = iwl4965_tx_queue_update_wr_ptr(priv, txq, 0); + q->first_empty = iwl_queue_inc_wrap(q->first_empty, q->n_bd); + iwl_tx_queue_update_write_ptr(priv, txq); + + spin_unlock_irqrestore(&priv->hcmd_lock, flags); + return ret ? ret : idx; +} + +int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd) +{ + int ret; + + BUG_ON(!(cmd->meta.flags & CMD_ASYNC)); + + /* An asynchronous command can not expect an SKB to be set. */ + BUG_ON(cmd->meta.flags & CMD_WANT_SKB); + + /* An asynchronous command MUST have a callback. */ + BUG_ON(!cmd->meta.u.callback); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return -EBUSY; + + ret = iwl_enqueue_hcmd(priv, cmd); + if (ret < 0) { + IWL_ERROR("Error sending %s: iwl_enqueue_hcmd failed: %d\n", + get_cmd_string(cmd->id), ret); + return ret; + } + return 0; +} + +int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) +{ + int cmd_idx; + int ret; + static atomic_t entry = ATOMIC_INIT(0); /* reentrance protection */ + + BUG_ON(cmd->meta.flags & CMD_ASYNC); + + /* A synchronous command can not have a callback set. */ + BUG_ON(cmd->meta.u.callback != NULL); + + if (atomic_xchg(&entry, 1)) { + IWL_ERROR("Error sending %s: Already sending a host command\n", + get_cmd_string(cmd->id)); + return -EBUSY; + } + + set_bit(STATUS_HCMD_ACTIVE, &priv->status); + + if (cmd->meta.flags & CMD_WANT_SKB) + cmd->meta.source = &cmd->meta; + + cmd_idx = iwl_enqueue_hcmd(priv, cmd); + if (cmd_idx < 0) { + ret = cmd_idx; + IWL_ERROR("Error sending %s: iwl_enqueue_hcmd failed: %d\n", + get_cmd_string(cmd->id), ret); + goto out; + } + + ret = wait_event_interruptible_timeout(priv->wait_command_queue, + !test_bit(STATUS_HCMD_ACTIVE, &priv->status), + HOST_COMPLETE_TIMEOUT); + if (!ret) { + if (test_bit(STATUS_HCMD_ACTIVE, &priv->status)) { + IWL_ERROR("Error sending %s: time out after %dms.\n", + get_cmd_string(cmd->id), + jiffies_to_msecs(HOST_COMPLETE_TIMEOUT)); + + clear_bit(STATUS_HCMD_ACTIVE, &priv->status); + ret = -ETIMEDOUT; + goto cancel; + } + } + + if (test_bit(STATUS_RF_KILL_HW, &priv->status)) { + IWL_DEBUG_INFO("Command %s aborted: RF KILL Switch\n", + get_cmd_string(cmd->id)); + ret = -ECANCELED; + goto fail; + } + if (test_bit(STATUS_FW_ERROR, &priv->status)) { + IWL_DEBUG_INFO("Command %s failed: FW Error\n", + get_cmd_string(cmd->id)); + ret = -EIO; + goto fail; + } + if ((cmd->meta.flags & CMD_WANT_SKB) && !cmd->meta.u.skb) { + IWL_ERROR("Error: Response NULL in '%s'\n", + get_cmd_string(cmd->id)); + ret = -EIO; + goto out; + } + + ret = 0; + goto out; + +cancel: + if (cmd->meta.flags & CMD_WANT_SKB) { + struct iwl_cmd *qcmd; + + /* Cancel the CMD_WANT_SKB flag for the cmd in the + * TX cmd queue. Otherwise in case the cmd comes + * in later, it will possibly set an invalid + * address (cmd->meta.source). */ + qcmd = &priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_idx]; + qcmd->meta.flags &= ~CMD_WANT_SKB; + } +fail: + if (cmd->meta.u.skb) { + dev_kfree_skb_any(cmd->meta.u.skb); + cmd->meta.u.skb = NULL; + } +out: + atomic_set(&entry, 0); + return ret; +} + +int iwl_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) +{ + /* A command can not be asynchronous AND expect an SKB to be set. */ + BUG_ON((cmd->meta.flags & CMD_ASYNC) && + (cmd->meta.flags & CMD_WANT_SKB)); + + if (cmd->meta.flags & CMD_ASYNC) + return iwl_send_cmd_async(priv, cmd); + + return iwl_send_cmd_sync(priv, cmd); +} + +int iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u16 len, const void *data) +{ + struct iwl_host_cmd cmd = { + .id = id, + .len = len, + .data = data, + }; + + return iwl_send_cmd_sync(priv, &cmd); +} + +static int __must_check iwl_send_cmd_u32(struct iwl_priv *priv, u8 id, u32 val) +{ + struct iwl_host_cmd cmd = { + .id = id, + .len = sizeof(val), + .data = &val, + }; + + return iwl_send_cmd_sync(priv, &cmd); +} + +int iwl_send_statistics_request(struct iwl_priv *priv) +{ + return iwl_send_cmd_u32(priv, REPLY_STATISTICS_CMD, 0); +} + +/** + * iwl_rxon_add_station - add station into station table. + * + * there is only one AP station with id= IWL_AP_ID + * NOTE: mutex must be held before calling the this fnction +*/ +static int iwl_rxon_add_station(struct iwl_priv *priv, + const u8 *addr, int is_ap) +{ + u8 rc; + + /* Remove this station if it happens to already exist */ + iwl_remove_station(priv, addr, is_ap); + + rc = iwl_add_station(priv, addr, is_ap, 0); + + iwl4965_add_station(priv, addr, is_ap); + + return rc; +} + +/** + * iwl_set_rxon_channel - Set the phymode and channel values in staging RXON + * @phymode: MODE_IEEE80211A sets to 5.2GHz; all else set to 2.4GHz + * @channel: Any channel valid for the requested phymode + + * In addition to setting the staging RXON, priv->phymode is also set. + * + * NOTE: Does not commit to the hardware; it sets appropriate bit fields + * in the staging RXON flag structure based on the phymode + */ +static int iwl_set_rxon_channel(struct iwl_priv *priv, u8 phymode, u16 channel) +{ + if (!iwl_get_channel_info(priv, phymode, channel)) { + IWL_DEBUG_INFO("Could not set channel to %d [%d]\n", + channel, phymode); + return -EINVAL; + } + + if ((le16_to_cpu(priv->staging_rxon.channel) == channel) && + (priv->phymode == phymode)) + return 0; + + priv->staging_rxon.channel = cpu_to_le16(channel); + if (phymode == MODE_IEEE80211A) + priv->staging_rxon.flags &= ~RXON_FLG_BAND_24G_MSK; + else + priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK; + + priv->phymode = phymode; + + IWL_DEBUG_INFO("Staging channel set to %d [%d]\n", channel, phymode); + + return 0; +} + +/** + * iwl_check_rxon_cmd - validate RXON structure is valid + * + * NOTE: This is really only useful during development and can eventually + * be #ifdef'd out once the driver is stable and folks aren't actively + * making changes + */ +static int iwl_check_rxon_cmd(struct iwl_rxon_cmd *rxon) +{ + int error = 0; + int counter = 1; + + if (rxon->flags & RXON_FLG_BAND_24G_MSK) { + error |= le32_to_cpu(rxon->flags & + (RXON_FLG_TGJ_NARROW_BAND_MSK | + RXON_FLG_RADAR_DETECT_MSK)); + if (error) + IWL_WARNING("check 24G fields %d | %d\n", + counter++, error); + } else { + error |= (rxon->flags & RXON_FLG_SHORT_SLOT_MSK) ? + 0 : le32_to_cpu(RXON_FLG_SHORT_SLOT_MSK); + if (error) + IWL_WARNING("check 52 fields %d | %d\n", + counter++, error); + error |= le32_to_cpu(rxon->flags & RXON_FLG_CCK_MSK); + if (error) + IWL_WARNING("check 52 CCK %d | %d\n", + counter++, error); + } + error |= (rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1; + if (error) + IWL_WARNING("check mac addr %d | %d\n", counter++, error); + + /* make sure basic rates 6Mbps and 1Mbps are supported */ + error |= (((rxon->ofdm_basic_rates & IWL_RATE_6M_MASK) == 0) && + ((rxon->cck_basic_rates & IWL_RATE_1M_MASK) == 0)); + if (error) + IWL_WARNING("check basic rate %d | %d\n", counter++, error); + + error |= (le16_to_cpu(rxon->assoc_id) > 2007); + if (error) + IWL_WARNING("check assoc id %d | %d\n", counter++, error); + + error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)) + == (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)); + if (error) + IWL_WARNING("check CCK and short slot %d | %d\n", + counter++, error); + + error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)) + == (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)); + if (error) + IWL_WARNING("check CCK & auto detect %d | %d\n", + counter++, error); + + error |= ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK | + RXON_FLG_TGG_PROTECT_MSK)) == RXON_FLG_TGG_PROTECT_MSK); + if (error) + IWL_WARNING("check TGG and auto detect %d | %d\n", + counter++, error); + + if (error) + IWL_WARNING("Tuning to channel %d\n", + le16_to_cpu(rxon->channel)); + + if (error) { + IWL_ERROR("Not a valid iwl_rxon_assoc_cmd field values\n"); + return -1; + } + return 0; +} + +/** + * iwl_full_rxon_required - determine if RXON_ASSOC can be used in RXON commit + * @priv: staging_rxon is comapred to active_rxon + * + * If the RXON structure is changing sufficient to require a new + * tune or to clear and reset the RXON_FILTER_ASSOC_MSK then return 1 + * to indicate a new tune is required. + */ +static int iwl_full_rxon_required(struct iwl_priv *priv) +{ + + /* These items are only settable from the full RXON command */ + if (!(priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) || + compare_ether_addr(priv->staging_rxon.bssid_addr, + priv->active_rxon.bssid_addr) || + compare_ether_addr(priv->staging_rxon.node_addr, + priv->active_rxon.node_addr) || + compare_ether_addr(priv->staging_rxon.wlap_bssid_addr, + priv->active_rxon.wlap_bssid_addr) || + (priv->staging_rxon.dev_type != priv->active_rxon.dev_type) || + (priv->staging_rxon.channel != priv->active_rxon.channel) || + (priv->staging_rxon.air_propagation != + priv->active_rxon.air_propagation) || + (priv->staging_rxon.ofdm_ht_single_stream_basic_rates != + priv->active_rxon.ofdm_ht_single_stream_basic_rates) || + (priv->staging_rxon.ofdm_ht_dual_stream_basic_rates != + priv->active_rxon.ofdm_ht_dual_stream_basic_rates) || + (priv->staging_rxon.rx_chain != priv->active_rxon.rx_chain) || + (priv->staging_rxon.assoc_id != priv->active_rxon.assoc_id)) + return 1; + + /* flags, filter_flags, ofdm_basic_rates, and cck_basic_rates can + * be updated with the RXON_ASSOC command -- however only some + * flag transitions are allowed using RXON_ASSOC */ + + /* Check if we are not switching bands */ + if ((priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) != + (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK)) + return 1; + + /* Check if we are switching association toggle */ + if ((priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) != + (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK)) + return 1; + + return 0; +} + +static int iwl_send_rxon_assoc(struct iwl_priv *priv) +{ + int rc = 0; + struct iwl_rx_packet *res = NULL; + struct iwl_rxon_assoc_cmd rxon_assoc; + struct iwl_host_cmd cmd = { + .id = REPLY_RXON_ASSOC, + .len = sizeof(rxon_assoc), + .meta.flags = CMD_WANT_SKB, + .data = &rxon_assoc, + }; + const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon; + const struct iwl_rxon_cmd *rxon2 = &priv->active_rxon; + + if ((rxon1->flags == rxon2->flags) && + (rxon1->filter_flags == rxon2->filter_flags) && + (rxon1->cck_basic_rates == rxon2->cck_basic_rates) && + (rxon1->ofdm_ht_single_stream_basic_rates == + rxon2->ofdm_ht_single_stream_basic_rates) && + (rxon1->ofdm_ht_dual_stream_basic_rates == + rxon2->ofdm_ht_dual_stream_basic_rates) && + (rxon1->rx_chain == rxon2->rx_chain) && + (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) { + IWL_DEBUG_INFO("Using current RXON_ASSOC. Not resending.\n"); + return 0; + } + + rxon_assoc.flags = priv->staging_rxon.flags; + rxon_assoc.filter_flags = priv->staging_rxon.filter_flags; + rxon_assoc.ofdm_basic_rates = priv->staging_rxon.ofdm_basic_rates; + rxon_assoc.cck_basic_rates = priv->staging_rxon.cck_basic_rates; + rxon_assoc.reserved = 0; + rxon_assoc.ofdm_ht_single_stream_basic_rates = + priv->staging_rxon.ofdm_ht_single_stream_basic_rates; + rxon_assoc.ofdm_ht_dual_stream_basic_rates = + priv->staging_rxon.ofdm_ht_dual_stream_basic_rates; + rxon_assoc.rx_chain_select_flags = priv->staging_rxon.rx_chain; + + rc = iwl_send_cmd_sync(priv, &cmd); + if (rc) + return rc; + + res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; + if (res->hdr.flags & IWL_CMD_FAILED_MSK) { + IWL_ERROR("Bad return from REPLY_RXON_ASSOC command\n"); + rc = -EIO; + } + + priv->alloc_rxb_skb--; + dev_kfree_skb_any(cmd.meta.u.skb); + + return rc; +} + +/** + * iwl_commit_rxon - commit staging_rxon to hardware + * + * The RXON command in staging_rxon is commited to the hardware and + * the active_rxon structure is updated with the new data. This + * function correctly transitions out of the RXON_ASSOC_MSK state if + * a HW tune is required based on the RXON structure changes. + */ +static int iwl_commit_rxon(struct iwl_priv *priv) +{ + /* cast away the const for active_rxon in this function */ + struct iwl_rxon_cmd *active_rxon = (void *)&priv->active_rxon; + int rc = 0; + + if (!iwl_is_alive(priv)) + return -1; + + /* always get timestamp with Rx frame */ + priv->staging_rxon.flags |= RXON_FLG_TSF2HOST_MSK; + + rc = iwl_check_rxon_cmd(&priv->staging_rxon); + if (rc) { + IWL_ERROR("Invalid RXON configuration. Not committing.\n"); + return -EINVAL; + } + + /* If we don't need to send a full RXON, we can use + * iwl_rxon_assoc_cmd which is used to reconfigure filter + * and other flags for the current radio configuration. */ + if (!iwl_full_rxon_required(priv)) { + rc = iwl_send_rxon_assoc(priv); + if (rc) { + IWL_ERROR("Error setting RXON_ASSOC " + "configuration (%d).\n", rc); + return rc; + } + + memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); + + return 0; + } + + /* station table will be cleared */ + priv->assoc_station_added = 0; + +#ifdef CONFIG_IWLWIFI_SENSITIVITY + priv->sensitivity_data.state = IWL_SENS_CALIB_NEED_REINIT; + if (!priv->error_recovering) + priv->start_calib = 0; + + iwl4965_init_sensitivity(priv, CMD_ASYNC, 1); +#endif /* CONFIG_IWLWIFI_SENSITIVITY */ + + /* If we are currently associated and the new config requires + * an RXON_ASSOC and the new config wants the associated mask enabled, + * we must clear the associated from the active configuration + * before we apply the new config */ + if (iwl_is_associated(priv) && + (priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK)) { + IWL_DEBUG_INFO("Toggling associated bit on current RXON\n"); + active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; + + rc = iwl_send_cmd_pdu(priv, REPLY_RXON, + sizeof(struct iwl_rxon_cmd), + &priv->active_rxon); + + /* If the mask clearing failed then we set + * active_rxon back to what it was previously */ + if (rc) { + active_rxon->filter_flags |= RXON_FILTER_ASSOC_MSK; + IWL_ERROR("Error clearing ASSOC_MSK on current " + "configuration (%d).\n", rc); + return rc; + } + + /* The RXON bit toggling will have cleared out the + * station table in the uCode, so blank it in the driver + * as well */ + iwl_clear_stations_table(priv); + } else if (priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) { + /* When switching from non-associated to associated, the + * uCode clears out the station table; so clear it in the + * driver as well */ + iwl_clear_stations_table(priv); + } + + IWL_DEBUG_INFO("Sending RXON\n" + "* with%s RXON_FILTER_ASSOC_MSK\n" + "* channel = %d\n" + "* bssid = " MAC_FMT "\n", + ((priv->staging_rxon.filter_flags & + RXON_FILTER_ASSOC_MSK) ? "" : "out"), + le16_to_cpu(priv->staging_rxon.channel), + MAC_ARG(priv->staging_rxon.bssid_addr)); + + /* Apply the new configuration */ + rc = iwl_send_cmd_pdu(priv, REPLY_RXON, + sizeof(struct iwl_rxon_cmd), &priv->staging_rxon); + if (rc) { + IWL_ERROR("Error setting new configuration (%d).\n", rc); + return rc; + } + +#ifdef CONFIG_IWLWIFI_SENSITIVITY + if (!priv->error_recovering) + priv->start_calib = 0; + + priv->sensitivity_data.state = IWL_SENS_CALIB_NEED_REINIT; + iwl4965_init_sensitivity(priv, CMD_ASYNC, 1); +#endif /* CONFIG_IWLWIFI_SENSITIVITY */ + + memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); + + /* If we issue a new RXON command which required a tune then we must + * send a new TXPOWER command or we won't be able to Tx any frames */ + rc = iwl_hw_reg_send_txpower(priv); + if (rc) { + IWL_ERROR("Error setting Tx power (%d).\n", rc); + return rc; + } + + /* Add the broadcast address so we can send broadcast frames */ + if (iwl_rxon_add_station(priv, BROADCAST_ADDR, 0) == + IWL_INVALID_STATION) { + IWL_ERROR("Error adding BROADCAST address for transmit.\n"); + return -EIO; + } + + /* If we have set the ASSOC_MSK and we are in BSS mode then + * add the IWL_AP_ID to the station rate table */ + if (iwl_is_associated(priv) && + (priv->iw_mode == IEEE80211_IF_TYPE_STA)) { + if (iwl_rxon_add_station(priv, priv->active_rxon.bssid_addr, 1) + == IWL_INVALID_STATION) { + IWL_ERROR("Error adding AP address for transmit.\n"); + return -EIO; + } + priv->assoc_station_added = 1; + } + + return 0; +} + +static int iwl_send_bt_config(struct iwl_priv *priv) +{ + struct iwl_bt_cmd bt_cmd = { + .flags = 3, + .lead_time = 0xAA, + .max_kill = 1, + .kill_ack_mask = 0, + .kill_cts_mask = 0, + }; + + return iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG, + sizeof(struct iwl_bt_cmd), &bt_cmd); +} + +static int iwl_send_scan_abort(struct iwl_priv *priv) +{ + int rc = 0; + struct iwl_rx_packet *res; + struct iwl_host_cmd cmd = { + .id = REPLY_SCAN_ABORT_CMD, + .meta.flags = CMD_WANT_SKB, + }; + + /* If there isn't a scan actively going on in the hardware + * then we are in between scan bands and not actually + * actively scanning, so don't send the abort command */ + if (!test_bit(STATUS_SCAN_HW, &priv->status)) { + clear_bit(STATUS_SCAN_ABORTING, &priv->status); + return 0; + } + + rc = iwl_send_cmd_sync(priv, &cmd); + if (rc) { + clear_bit(STATUS_SCAN_ABORTING, &priv->status); + return rc; + } + + res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; + if (res->u.status != CAN_ABORT_STATUS) { + /* The scan abort will return 1 for success or + * 2 for "failure". A failure condition can be + * due to simply not being in an active scan which + * can occur if we send the scan abort before we + * the microcode has notified us that a scan is + * completed. */ + IWL_DEBUG_INFO("SCAN_ABORT returned %d.\n", res->u.status); + clear_bit(STATUS_SCAN_ABORTING, &priv->status); + clear_bit(STATUS_SCAN_HW, &priv->status); + } + + dev_kfree_skb_any(cmd.meta.u.skb); + + return rc; +} + +static int iwl_card_state_sync_callback(struct iwl_priv *priv, + struct iwl_cmd *cmd, + struct sk_buff *skb) +{ + return 1; +} + +/* + * CARD_STATE_CMD + * + * Use: Sets the internal card state to enable, disable, or halt + * + * When in the 'enable' state the card operates as normal. + * When in the 'disable' state, the card enters into a low power mode. + * When in the 'halt' state, the card is shut down and must be fully + * restarted to come back on. + */ +static int iwl_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag) +{ + struct iwl_host_cmd cmd = { + .id = REPLY_CARD_STATE_CMD, + .len = sizeof(u32), + .data = &flags, + .meta.flags = meta_flag, + }; + + if (meta_flag & CMD_ASYNC) + cmd.meta.u.callback = iwl_card_state_sync_callback; + + return iwl_send_cmd(priv, &cmd); +} + +static int iwl_add_sta_sync_callback(struct iwl_priv *priv, + struct iwl_cmd *cmd, struct sk_buff *skb) +{ + struct iwl_rx_packet *res = NULL; + + if (!skb) { + IWL_ERROR("Error: Response NULL in REPLY_ADD_STA.\n"); + return 1; + } + + res = (struct iwl_rx_packet *)skb->data; + if (res->hdr.flags & IWL_CMD_FAILED_MSK) { + IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n", + res->hdr.flags); + return 1; + } + + switch (res->u.add_sta.status) { + case ADD_STA_SUCCESS_MSK: + break; + default: + break; + } + + /* We didn't cache the SKB; let the caller free it */ + return 1; +} + +int iwl_send_add_station(struct iwl_priv *priv, + struct iwl_addsta_cmd *sta, u8 flags) +{ + struct iwl_rx_packet *res = NULL; + int rc = 0; + struct iwl_host_cmd cmd = { + .id = REPLY_ADD_STA, + .len = sizeof(struct iwl_addsta_cmd), + .meta.flags = flags, + .data = sta, + }; + + if (flags & CMD_ASYNC) + cmd.meta.u.callback = iwl_add_sta_sync_callback; + else + cmd.meta.flags |= CMD_WANT_SKB; + + rc = iwl_send_cmd(priv, &cmd); + + if (rc || (flags & CMD_ASYNC)) + return rc; + + res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; + if (res->hdr.flags & IWL_CMD_FAILED_MSK) { + IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n", + res->hdr.flags); + rc = -EIO; + } + + if (rc == 0) { + switch (res->u.add_sta.status) { + case ADD_STA_SUCCESS_MSK: + IWL_DEBUG_INFO("REPLY_ADD_STA PASSED\n"); + break; + default: + rc = -EIO; + IWL_WARNING("REPLY_ADD_STA failed\n"); + break; + } + } + + priv->alloc_rxb_skb--; + dev_kfree_skb_any(cmd.meta.u.skb); + + return rc; +} + +static int iwl_update_sta_key_info(struct iwl_priv *priv, + struct ieee80211_key_conf *keyconf, + u8 sta_id) +{ + unsigned long flags; + __le16 key_flags = 0; + + switch (keyconf->alg) { + case ALG_CCMP: + key_flags |= STA_KEY_FLG_CCMP; + key_flags |= cpu_to_le16( + keyconf->keyidx << STA_KEY_FLG_KEYID_POS); + key_flags &= ~STA_KEY_FLG_INVALID; + break; + case ALG_TKIP: + case ALG_WEP: + return -EINVAL; + default: + return -EINVAL; + } + spin_lock_irqsave(&priv->sta_lock, flags); + priv->stations[sta_id].keyinfo.alg = keyconf->alg; + priv->stations[sta_id].keyinfo.keylen = keyconf->keylen; + memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key, + keyconf->keylen); + + memcpy(priv->stations[sta_id].sta.key.key, keyconf->key, + keyconf->keylen); + priv->stations[sta_id].sta.key.key_flags = key_flags; + priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + + spin_unlock_irqrestore(&priv->sta_lock, flags); + + IWL_DEBUG_INFO("hwcrypto: modify ucode station key info\n"); + iwl_send_add_station(priv, &priv->stations[sta_id].sta, 0); + return 0; +} + +static int iwl_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->sta_lock, flags); + memset(&priv->stations[sta_id].keyinfo, 0, sizeof(struct iwl_hw_key)); + memset(&priv->stations[sta_id].sta.key, 0, sizeof(struct iwl_keyinfo)); + priv->stations[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC; + priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + spin_unlock_irqrestore(&priv->sta_lock, flags); + + IWL_DEBUG_INFO("hwcrypto: clear ucode station key info\n"); + iwl_send_add_station(priv, &priv->stations[sta_id].sta, 0); + return 0; +} + +static void iwl_clear_free_frames(struct iwl_priv *priv) +{ + struct list_head *element; + + IWL_DEBUG_INFO("%d frames on pre-allocated heap on clear.\n", + priv->frames_count); + + while (!list_empty(&priv->free_frames)) { + element = priv->free_frames.next; + list_del(element); + kfree(list_entry(element, struct iwl_frame, list)); + priv->frames_count--; + } + + if (priv->frames_count) { + IWL_WARNING("%d frames still in use. Did we lose one?\n", + priv->frames_count); + priv->frames_count = 0; + } +} + +static struct iwl_frame *iwl_get_free_frame(struct iwl_priv *priv) +{ + struct iwl_frame *frame; + struct list_head *element; + if (list_empty(&priv->free_frames)) { + frame = kzalloc(sizeof(*frame), GFP_KERNEL); + if (!frame) { + IWL_ERROR("Could not allocate frame!\n"); + return NULL; + } + + priv->frames_count++; + return frame; + } + + element = priv->free_frames.next; + list_del(element); + return list_entry(element, struct iwl_frame, list); +} + +static void iwl_free_frame(struct iwl_priv *priv, struct iwl_frame *frame) +{ + memset(frame, 0, sizeof(*frame)); + list_add(&frame->list, &priv->free_frames); +} + +unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv, + struct ieee80211_hdr *hdr, + const u8 *dest, int left) +{ + + if (!iwl_is_associated(priv) || !priv->ibss_beacon || + ((priv->iw_mode != IEEE80211_IF_TYPE_IBSS) && + (priv->iw_mode != IEEE80211_IF_TYPE_AP))) + return 0; + + if (priv->ibss_beacon->len > left) + return 0; + + memcpy(hdr, priv->ibss_beacon->data, priv->ibss_beacon->len); + + return priv->ibss_beacon->len; +} + +int iwl_rate_index_from_plcp(int plcp) +{ + int i = 0; + + if (plcp & RATE_MCS_HT_MSK) { + i = (plcp & 0xff); + + if (i >= IWL_RATE_MIMO_6M_PLCP) + i = i - IWL_RATE_MIMO_6M_PLCP; + + i += IWL_FIRST_OFDM_RATE; + /* skip 9M not supported in ht*/ + if (i >= IWL_RATE_9M_INDEX) + i += 1; + if ((i >= IWL_FIRST_OFDM_RATE) && + (i <= IWL_LAST_OFDM_RATE)) + return i; + } else { + for (i = 0; i < ARRAY_SIZE(iwl_rates); i++) + if (iwl_rates[i].plcp == (plcp &0xFF)) + return i; + } + return -1; +} + +static u8 iwl_rate_get_lowest_plcp(int rate_mask) +{ + u8 i; + + for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID; + i = iwl_rates[i].next_ieee) { + if (rate_mask & (1 << i)) + return iwl_rates[i].plcp; + } + + return IWL_RATE_INVALID; +} + +static int iwl_send_beacon_cmd(struct iwl_priv *priv) +{ + struct iwl_frame *frame; + unsigned int frame_size; + int rc; + u8 rate; + + frame = iwl_get_free_frame(priv); + + if (!frame) { + IWL_ERROR("Could not obtain free frame buffer for beacon " + "command.\n"); + return -ENOMEM; + } + + if (!(priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK)) { + rate = iwl_rate_get_lowest_plcp(priv->active_rate_basic & + 0xFF0); + if (rate == IWL_INVALID_RATE) + rate = IWL_RATE_6M_PLCP; + } else { + rate = iwl_rate_get_lowest_plcp(priv->active_rate_basic & 0xF); + if (rate == IWL_INVALID_RATE) + rate = IWL_RATE_1M_PLCP; + } + + frame_size = iwl_hw_get_beacon_cmd(priv, frame, rate); + + rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size, + &frame->u.cmd[0]); + + iwl_free_frame(priv, frame); + + return rc; +} + +/****************************************************************************** + * + * EEPROM related functions + * + ******************************************************************************/ + +static void get_eeprom_mac(struct iwl_priv *priv, u8 *mac) +{ + memcpy(mac, priv->eeprom.mac_address, 6); +} + +/** + * iwl_eeprom_init - read EEPROM contents + * + * Load the EEPROM from adapter into priv->eeprom + * + * NOTE: This routine uses the non-debug IO access functions. + */ +int iwl_eeprom_init(struct iwl_priv *priv) +{ + u16 *e = (u16 *)&priv->eeprom; + u32 gp = iwl_read32(priv, CSR_EEPROM_GP); + u32 r; + int sz = sizeof(priv->eeprom); + int rc; + int i; + u16 addr; + + /* The EEPROM structure has several padding buffers within it + * and when adding new EEPROM maps is subject to programmer errors + * which may be very difficult to identify without explicitly + * checking the resulting size of the eeprom map. */ + BUILD_BUG_ON(sizeof(priv->eeprom) != IWL_EEPROM_IMAGE_SIZE); + + if ((gp & CSR_EEPROM_GP_VALID_MSK) == CSR_EEPROM_GP_BAD_SIGNATURE) { + IWL_ERROR("EEPROM not found, EEPROM_GP=0x%08x", gp); + return -ENOENT; + } + + rc = iwl_eeprom_aqcuire_semaphore(priv); + if (rc < 0) { + IWL_ERROR("Failed to aqcuire EEPROM semaphore.\n"); + return -ENOENT; + } + + /* eeprom is an array of 16bit values */ + for (addr = 0; addr < sz; addr += sizeof(u16)) { + _iwl_write32(priv, CSR_EEPROM_REG, addr << 1); + _iwl_clear_bit(priv, CSR_EEPROM_REG, CSR_EEPROM_REG_BIT_CMD); + + for (i = 0; i < IWL_EEPROM_ACCESS_TIMEOUT; + i += IWL_EEPROM_ACCESS_DELAY) { + r = _iwl_read_restricted(priv, CSR_EEPROM_REG); + if (r & CSR_EEPROM_REG_READ_VALID_MSK) + break; + udelay(IWL_EEPROM_ACCESS_DELAY); + } + + if (!(r & CSR_EEPROM_REG_READ_VALID_MSK)) { + IWL_ERROR("Time out reading EEPROM[%d]", addr); + rc = -ETIMEDOUT; + goto done; + } + e[addr / 2] = le16_to_cpu(r >> 16); + } + rc = 0; + +done: + iwl_eeprom_release_semaphore(priv); + return rc; +} + +/****************************************************************************** + * + * Misc. internal state and helper functions + * + ******************************************************************************/ +#ifdef CONFIG_IWLWIFI_DEBUG + +/** + * iwl_report_frame - dump frame to syslog during debug sessions + * + * hack this function to show different aspects of received frames, + * including selective frame dumps. + * group100 parameter selects whether to show 1 out of 100 good frames. + * + * TODO: ieee80211_hdr stuff is common to 3945 and 4965, so frame type + * info output is okay, but some of this stuff (e.g. iwl_rx_frame_stats) + * is 3945-specific and gives bad output for 4965. Need to split the + * functionality, keep common stuff here. + */ +void iwl_report_frame(struct iwl_priv *priv, + struct iwl_rx_packet *pkt, + struct ieee80211_hdr *header, int group100) +{ + u32 to_us; + u32 print_summary = 0; + u32 print_dump = 0; /* set to 1 to dump all frames' contents */ + u32 hundred = 0; + u32 dataframe = 0; + u16 fc; + u16 seq_ctl; + u16 channel; + u16 phy_flags; + int rate_sym; + u16 length; + u16 status; + u16 bcn_tmr; + u32 tsf_low; + u64 tsf; + u8 rssi; + u8 agc; + u16 sig_avg; + u16 noise_diff; + struct iwl_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt); + struct iwl_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); + struct iwl_rx_frame_end *rx_end = IWL_RX_END(pkt); + u8 *data = IWL_RX_DATA(pkt); + + /* MAC header */ + fc = le16_to_cpu(header->frame_control); + seq_ctl = le16_to_cpu(header->seq_ctrl); + + /* metadata */ + channel = le16_to_cpu(rx_hdr->channel); + phy_flags = le16_to_cpu(rx_hdr->phy_flags); + rate_sym = rx_hdr->rate; + length = le16_to_cpu(rx_hdr->len); + + /* end-of-frame status and timestamp */ + status = le32_to_cpu(rx_end->status); + bcn_tmr = le32_to_cpu(rx_end->beacon_timestamp); + tsf_low = le64_to_cpu(rx_end->timestamp) & 0x0ffffffff; + tsf = le64_to_cpu(rx_end->timestamp); + + /* signal statistics */ + rssi = rx_stats->rssi; + agc = rx_stats->agc; + sig_avg = le16_to_cpu(rx_stats->sig_avg); + noise_diff = le16_to_cpu(rx_stats->noise_diff); + + to_us = !compare_ether_addr(header->addr1, priv->mac_addr); + + /* if data frame is to us and all is good, + * (optionally) print summary for only 1 out of every 100 */ + if (to_us && (fc & ~IEEE80211_FCTL_PROTECTED) == + (IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) { + dataframe = 1; + if (!group100) + print_summary = 1; /* print each frame */ + else if (priv->framecnt_to_us < 100) { + priv->framecnt_to_us++; + print_summary = 0; + } else { + priv->framecnt_to_us = 0; + print_summary = 1; + hundred = 1; + } + } else { + /* print summary for all other frames */ + print_summary = 1; + } + + if (print_summary) { + char *title; + u32 rate; + + if (hundred) + title = "100Frames"; + else if (fc & IEEE80211_FCTL_RETRY) + title = "Retry"; + else if (ieee80211_is_assoc_response(fc)) + title = "AscRsp"; + else if (ieee80211_is_reassoc_response(fc)) + title = "RasRsp"; + else if (ieee80211_is_probe_response(fc)) { + title = "PrbRsp"; + print_dump = 1; /* dump frame contents */ + } else if (ieee80211_is_beacon(fc)) { + title = "Beacon"; + print_dump = 1; /* dump frame contents */ + } else if (ieee80211_is_atim(fc)) + title = "ATIM"; + else if (ieee80211_is_auth(fc)) + title = "Auth"; + else if (ieee80211_is_deauth(fc)) + title = "DeAuth"; + else if (ieee80211_is_disassoc(fc)) + title = "DisAssoc"; + else + title = "Frame"; + + rate = iwl_rate_index_from_plcp(rate_sym); + if (rate == -1) + rate = 0; + else + rate = iwl_rates[rate].ieee / 2; + + /* print frame summary. + * MAC addresses show just the last byte (for brevity), + * but you can hack it to show more, if you'd like to. */ + if (dataframe) + IWL_DEBUG_RX("%s: mhd=0x%04x, dst=0x%02x, " + "len=%u, rssi=%d, chnl=%d, rate=%u, \n", + title, fc, header->addr1[5], + length, rssi, channel, rate); + else { + /* src/dst addresses assume managed mode */ + IWL_DEBUG_RX("%s: 0x%04x, dst=0x%02x, " + "src=0x%02x, rssi=%u, tim=%lu usec, " + "phy=0x%02x, chnl=%d\n", + title, fc, header->addr1[5], + header->addr3[5], rssi, + tsf_low - priv->scan_start_tsf, + phy_flags, channel); + } + } + if (print_dump) + iwl_print_hex_dump(IWL_DL_RX, data, length); +} +#endif + +static void iwl_unset_hw_setting(struct iwl_priv *priv) +{ + if (priv->hw_setting.shared_virt) + pci_free_consistent(priv->pci_dev, + sizeof(struct iwl_shared), + priv->hw_setting.shared_virt, + priv->hw_setting.shared_phys); +} + +/** + * iwl_supported_rate_to_ie - fill in the supported rate in IE field + * + * return : set the bit for each supported rate insert in ie + */ +static u16 iwl_supported_rate_to_ie(u8 *ie, u16 supported_rate, + u16 basic_rate, int max_count) +{ + u16 ret_rates = 0, bit; + int i; + u8 *rates; + + rates = &(ie[1]); + + for (bit = 1, i = 0; i < IWL_RATE_COUNT; i++, bit <<= 1) { + if (bit & supported_rate) { + ret_rates |= bit; + rates[*ie] = iwl_rates[i].ieee | + ((bit & basic_rate) ? 0x80 : 0x00); + *ie = *ie + 1; + if (*ie >= max_count) + break; + } + } + + return ret_rates; +} + +#ifdef CONFIG_IWLWIFI_HT +void static iwl_set_ht_capab(struct ieee80211_hw *hw, + struct ieee80211_ht_capability *ht_cap, + u8 use_wide_chan); +#endif + +/** + * iwl_fill_probe_req - fill in all required fields and IE for probe request + */ +static u16 iwl_fill_probe_req(struct iwl_priv *priv, + struct ieee80211_mgmt *frame, + int left, int is_direct) +{ + int len = 0; + u8 *pos = NULL; + u16 ret_rates; + + /* Make sure there is enough space for the probe request, + * two mandatory IEs and the data */ + left -= 24; + if (left < 0) + return 0; + len += 24; + + frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); + memcpy(frame->da, BROADCAST_ADDR, ETH_ALEN); + memcpy(frame->sa, priv->mac_addr, ETH_ALEN); + memcpy(frame->bssid, BROADCAST_ADDR, ETH_ALEN); + frame->seq_ctrl = 0; + + /* fill in our indirect SSID IE */ + /* ...next IE... */ + + left -= 2; + if (left < 0) + return 0; + len += 2; + pos = &(frame->u.probe_req.variable[0]); + *pos++ = WLAN_EID_SSID; + *pos++ = 0; + + /* fill in our direct SSID IE... */ + if (is_direct) { + /* ...next IE... */ + left -= 2 + priv->essid_len; + if (left < 0) + return 0; + /* ... fill it in... */ + *pos++ = WLAN_EID_SSID; + *pos++ = priv->essid_len; + memcpy(pos, priv->essid, priv->essid_len); + pos += priv->essid_len; + len += 2 + priv->essid_len; + } + + /* fill in supported rate */ + /* ...next IE... */ + left -= 2; + if (left < 0) + return 0; + /* ... fill it in... */ + *pos++ = WLAN_EID_SUPP_RATES; + *pos = 0; + ret_rates = priv->active_rate = priv->rates_mask; + priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK; + + iwl_supported_rate_to_ie(pos, priv->active_rate, + priv->active_rate_basic, left); + len += 2 + *pos; + pos += (*pos) + 1; + ret_rates = ~ret_rates & priv->active_rate; + + if (ret_rates == 0) + goto fill_end; + + /* fill in supported extended rate */ + /* ...next IE... */ + left -= 2; + if (left < 0) + return 0; + /* ... fill it in... */ + *pos++ = WLAN_EID_EXT_SUPP_RATES; + *pos = 0; + iwl_supported_rate_to_ie(pos, ret_rates, priv->active_rate_basic, left); + if (*pos > 0) + len += 2 + *pos; + +#ifdef CONFIG_IWLWIFI_HT + if (is_direct && priv->is_ht_enabled) { + u8 use_wide_chan = 1; + + if (priv->channel_width != IWL_CHANNEL_WIDTH_40MHZ) + use_wide_chan = 0; + pos += (*pos) + 1; + *pos++ = WLAN_EID_HT_CAPABILITY; + *pos++ = sizeof(struct ieee80211_ht_capability); + iwl_set_ht_capab(NULL, (struct ieee80211_ht_capability *)pos, + use_wide_chan); + len += 2 + sizeof(struct ieee80211_ht_capability); + } +#endif /*CONFIG_IWLWIFI_HT */ + + fill_end: + return (u16)len; +} + +/* + * QoS support +*/ +#ifdef CONFIG_IWLWIFI_QOS +static int iwl_send_qos_params_command(struct iwl_priv *priv, + struct iwl_qosparam_cmd *qos) +{ + + return iwl_send_cmd_pdu(priv, REPLY_QOS_PARAM, + sizeof(struct iwl_qosparam_cmd), qos); +} + +static void iwl_reset_qos(struct iwl_priv *priv) +{ + u16 cw_min = 15; + u16 cw_max = 1023; + u8 aifs = 2; + u8 is_legacy = 0; + unsigned long flags; + int i; + + spin_lock_irqsave(&priv->lock, flags); + priv->qos_data.qos_active = 0; + + if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) { + if (priv->qos_data.qos_enable) + priv->qos_data.qos_active = 1; + if (!(priv->active_rate & 0xfff0)) { + cw_min = 31; + is_legacy = 1; + } + } else if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { + if (priv->qos_data.qos_enable) + priv->qos_data.qos_active = 1; + } else if (!(priv->staging_rxon.flags & RXON_FLG_SHORT_SLOT_MSK)) { + cw_min = 31; + is_legacy = 1; + } + + if (priv->qos_data.qos_active) + aifs = 3; + + priv->qos_data.def_qos_parm.ac[0].cw_min = cpu_to_le16(cw_min); + priv->qos_data.def_qos_parm.ac[0].cw_max = cpu_to_le16(cw_max); + priv->qos_data.def_qos_parm.ac[0].aifsn = aifs; + priv->qos_data.def_qos_parm.ac[0].edca_txop = 0; + priv->qos_data.def_qos_parm.ac[0].reserved1 = 0; + + if (priv->qos_data.qos_active) { + i = 1; + priv->qos_data.def_qos_parm.ac[i].cw_min = cpu_to_le16(cw_min); + priv->qos_data.def_qos_parm.ac[i].cw_max = cpu_to_le16(cw_max); + priv->qos_data.def_qos_parm.ac[i].aifsn = 7; + priv->qos_data.def_qos_parm.ac[i].edca_txop = 0; + priv->qos_data.def_qos_parm.ac[i].reserved1 = 0; + + i = 2; + priv->qos_data.def_qos_parm.ac[i].cw_min = + cpu_to_le16((cw_min + 1) / 2 - 1); + priv->qos_data.def_qos_parm.ac[i].cw_max = + cpu_to_le16(cw_max); + priv->qos_data.def_qos_parm.ac[i].aifsn = 2; + if (is_legacy) + priv->qos_data.def_qos_parm.ac[i].edca_txop = + cpu_to_le16(6016); + else + priv->qos_data.def_qos_parm.ac[i].edca_txop = + cpu_to_le16(3008); + priv->qos_data.def_qos_parm.ac[i].reserved1 = 0; + + i = 3; + priv->qos_data.def_qos_parm.ac[i].cw_min = + cpu_to_le16((cw_min + 1) / 4 - 1); + priv->qos_data.def_qos_parm.ac[i].cw_max = + cpu_to_le16((cw_max + 1) / 2 - 1); + priv->qos_data.def_qos_parm.ac[i].aifsn = 2; + priv->qos_data.def_qos_parm.ac[i].reserved1 = 0; + if (is_legacy) + priv->qos_data.def_qos_parm.ac[i].edca_txop = + cpu_to_le16(3264); + else + priv->qos_data.def_qos_parm.ac[i].edca_txop = + cpu_to_le16(1504); + } else { + for (i = 1; i < 4; i++) { + priv->qos_data.def_qos_parm.ac[i].cw_min = + cpu_to_le16(cw_min); + priv->qos_data.def_qos_parm.ac[i].cw_max = + cpu_to_le16(cw_max); + priv->qos_data.def_qos_parm.ac[i].aifsn = aifs; + priv->qos_data.def_qos_parm.ac[i].edca_txop = 0; + priv->qos_data.def_qos_parm.ac[i].reserved1 = 0; + } + } + IWL_DEBUG_QOS("set QoS to default \n"); + + spin_unlock_irqrestore(&priv->lock, flags); +} + +static void iwl_activate_qos(struct iwl_priv *priv, u8 force) +{ + unsigned long flags; + + if (priv == NULL) + return; + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + if (!priv->qos_data.qos_enable) + return; + + spin_lock_irqsave(&priv->lock, flags); + priv->qos_data.def_qos_parm.qos_flags = 0; + + if (priv->qos_data.qos_cap.q_AP.queue_request && + !priv->qos_data.qos_cap.q_AP.txop_request) + priv->qos_data.def_qos_parm.qos_flags |= + QOS_PARAM_FLG_TXOP_TYPE_MSK; + + if (priv->qos_data.qos_active) + priv->qos_data.def_qos_parm.qos_flags |= + QOS_PARAM_FLG_UPDATE_EDCA_MSK; + + spin_unlock_irqrestore(&priv->lock, flags); + + if (force || iwl_is_associated(priv)) { + IWL_DEBUG_QOS("send QoS cmd with Qos active %d \n", + priv->qos_data.qos_active); + + iwl_send_qos_params_command(priv, + &(priv->qos_data.def_qos_parm)); + } +} + +#endif /* CONFIG_IWLWIFI_QOS */ +/* + * Power management (not Tx power!) functions + */ +#define MSEC_TO_USEC 1024 + +#define NOSLP __constant_cpu_to_le16(0), 0, 0 +#define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK, 0, 0 +#define SLP_TIMEOUT(T) __constant_cpu_to_le32((T) * MSEC_TO_USEC) +#define SLP_VEC(X0, X1, X2, X3, X4) {__constant_cpu_to_le32(X0), \ + __constant_cpu_to_le32(X1), \ + __constant_cpu_to_le32(X2), \ + __constant_cpu_to_le32(X3), \ + __constant_cpu_to_le32(X4)} + + +/* default power management (not Tx power) table values */ +/* for tim 0-10 */ +static struct iwl_power_vec_entry range_0[IWL_POWER_AC] = { + {{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, + {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0}, + {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(300), SLP_VEC(2, 4, 6, 7, 7)}, 0}, + {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(100), SLP_VEC(2, 6, 9, 9, 10)}, 0}, + {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(25), SLP_VEC(2, 7, 9, 9, 10)}, 1}, + {{SLP, SLP_TIMEOUT(25), SLP_TIMEOUT(25), SLP_VEC(4, 7, 10, 10, 10)}, 1} +}; + +/* for tim > 10 */ +static struct iwl_power_vec_entry range_1[IWL_POWER_AC] = { + {{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, + {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500), + SLP_VEC(1, 2, 3, 4, 0xFF)}, 0}, + {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(300), + SLP_VEC(2, 4, 6, 7, 0xFF)}, 0}, + {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(100), + SLP_VEC(2, 6, 9, 9, 0xFF)}, 0}, + {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(25), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0}, + {{SLP, SLP_TIMEOUT(25), SLP_TIMEOUT(25), + SLP_VEC(4, 7, 10, 10, 0xFF)}, 0} +}; + +int iwl_power_init_handle(struct iwl_priv *priv) +{ + int rc = 0, i; + struct iwl_power_mgr *pow_data; + int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_AC; + u16 pci_pm; + + IWL_DEBUG_POWER("Initialize power \n"); + + pow_data = &(priv->power_data); + + memset(pow_data, 0, sizeof(*pow_data)); + + pow_data->active_index = IWL_POWER_RANGE_0; + pow_data->dtim_val = 0xffff; + + memcpy(&pow_data->pwr_range_0[0], &range_0[0], size); + memcpy(&pow_data->pwr_range_1[0], &range_1[0], size); + + rc = pci_read_config_word(priv->pci_dev, PCI_LINK_CTRL, &pci_pm); + if (rc != 0) + return 0; + else { + struct iwl_powertable_cmd *cmd; + + IWL_DEBUG_POWER("adjust power command flags\n"); + + for (i = 0; i < IWL_POWER_AC; i++) { + cmd = &pow_data->pwr_range_0[i].cmd; + + if (pci_pm & 0x1) + cmd->flags &= ~IWL_POWER_PCI_PM_MSK; + else + cmd->flags |= IWL_POWER_PCI_PM_MSK; + } + } + return rc; +} + +static int iwl_update_power_cmd(struct iwl_priv *priv, + struct iwl_powertable_cmd *cmd, u32 mode) +{ + int rc = 0, i; + u8 skip; + u32 max_sleep = 0; + struct iwl_power_vec_entry *range; + u8 period = 0; + struct iwl_power_mgr *pow_data; + + if (mode > IWL_POWER_INDEX_5) { + IWL_DEBUG_POWER("Error invalid power mode \n"); + return -1; + } + pow_data = &(priv->power_data); + + if (pow_data->active_index == IWL_POWER_RANGE_0) + range = &pow_data->pwr_range_0[0]; + else + range = &pow_data->pwr_range_1[1]; + + memcpy(cmd, &range[mode].cmd, sizeof(struct iwl_powertable_cmd)); + +#ifdef IWL_MAC80211_DISABLE + if (priv->assoc_network != NULL) { + unsigned long flags; + + period = priv->assoc_network->tim.tim_period; + } +#endif /*IWL_MAC80211_DISABLE */ + skip = range[mode].no_dtim; + + if (period == 0) { + period = 1; + skip = 0; + } + + if (skip == 0) { + max_sleep = period; + cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK; + } else { + __le32 slp_itrvl = cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]; + max_sleep = (le32_to_cpu(slp_itrvl) / period) * period; + cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK; + } + + for (i = 0; i < IWL_POWER_VEC_SIZE; i++) { + if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep) + cmd->sleep_interval[i] = cpu_to_le32(max_sleep); + } + + IWL_DEBUG_POWER("Flags value = 0x%08X\n", cmd->flags); + IWL_DEBUG_POWER("Tx timeout = %u\n", le32_to_cpu(cmd->tx_data_timeout)); + IWL_DEBUG_POWER("Rx timeout = %u\n", le32_to_cpu(cmd->rx_data_timeout)); + IWL_DEBUG_POWER("Sleep interval vector = { %d , %d , %d , %d , %d }\n", + le32_to_cpu(cmd->sleep_interval[0]), + le32_to_cpu(cmd->sleep_interval[1]), + le32_to_cpu(cmd->sleep_interval[2]), + le32_to_cpu(cmd->sleep_interval[3]), + le32_to_cpu(cmd->sleep_interval[4])); + + return rc; +} + +static int iwl_send_power_mode(struct iwl_priv *priv, u32 mode) +{ + u32 final_mode = mode; + int rc; + struct iwl_powertable_cmd cmd; + + /* If on battery, set to 3, + * if plugged into AC power, set to CAM ("continuosly aware mode"), + * else user level */ + switch (mode) { + case IWL_POWER_BATTERY: + final_mode = IWL_POWER_INDEX_3; + break; + case IWL_POWER_AC: + final_mode = IWL_POWER_MODE_CAM; + break; + default: + final_mode = mode; + break; + } + + cmd.keep_alive_beacons = 0; + + iwl_update_power_cmd(priv, &cmd, final_mode); + + rc = iwl_send_cmd_pdu(priv, POWER_TABLE_CMD, sizeof(cmd), &cmd); + + if (final_mode == IWL_POWER_MODE_CAM) + clear_bit(STATUS_POWER_PMI, &priv->status); + else + set_bit(STATUS_POWER_PMI, &priv->status); + + return rc; +} + +int iwl_is_network_packet(struct iwl_priv *priv, struct ieee80211_hdr *header) +{ + /* Filter incoming packets to determine if they are targeted toward + * this network, discarding packets coming from ourselves */ + switch (priv->iw_mode) { + case IEEE80211_IF_TYPE_IBSS: /* Header: Dest. | Source | BSSID */ + /* packets from our adapter are dropped (echo) */ + if (!compare_ether_addr(header->addr2, priv->mac_addr)) + return 0; + /* {broad,multi}cast packets to our IBSS go through */ + if (is_multicast_ether_addr(header->addr1)) + return !compare_ether_addr(header->addr3, priv->bssid); + /* packets to our adapter go through */ + return !compare_ether_addr(header->addr1, priv->mac_addr); + case IEEE80211_IF_TYPE_STA: /* Header: Dest. | AP{BSSID} | Source */ + /* packets from our adapter are dropped (echo) */ + if (!compare_ether_addr(header->addr3, priv->mac_addr)) + return 0; + /* {broad,multi}cast packets to our BSS go through */ + if (is_multicast_ether_addr(header->addr1)) + return !compare_ether_addr(header->addr2, priv->bssid); + /* packets to our adapter go through */ + return !compare_ether_addr(header->addr1, priv->mac_addr); + } + + return 1; +} + +#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x + +const char *iwl_get_tx_fail_reason(u32 status) +{ + switch (status & TX_STATUS_MSK) { + case TX_STATUS_SUCCESS: + return "SUCCESS"; + TX_STATUS_ENTRY(SHORT_LIMIT); + TX_STATUS_ENTRY(LONG_LIMIT); + TX_STATUS_ENTRY(FIFO_UNDERRUN); + TX_STATUS_ENTRY(MGMNT_ABORT); + TX_STATUS_ENTRY(NEXT_FRAG); + TX_STATUS_ENTRY(LIFE_EXPIRE); + TX_STATUS_ENTRY(DEST_PS); + TX_STATUS_ENTRY(ABORTED); + TX_STATUS_ENTRY(BT_RETRY); + TX_STATUS_ENTRY(STA_INVALID); + TX_STATUS_ENTRY(FRAG_DROPPED); + TX_STATUS_ENTRY(TID_DISABLE); + TX_STATUS_ENTRY(FRAME_FLUSHED); + TX_STATUS_ENTRY(INSUFFICIENT_CF_POLL); + TX_STATUS_ENTRY(TX_LOCKED); + TX_STATUS_ENTRY(NO_BEACON_ON_RADAR); + } + + return "UNKNOWN"; +} + +/** + * iwl_scan_cancel - Cancel any currently executing HW scan + * + * NOTE: priv->mutex is not required before calling this function + */ +static int iwl_scan_cancel(struct iwl_priv *priv) +{ + if (!test_bit(STATUS_SCAN_HW, &priv->status)) { + clear_bit(STATUS_SCANNING, &priv->status); + return 0; + } + + if (test_bit(STATUS_SCANNING, &priv->status)) { + if (!test_bit(STATUS_SCAN_ABORTING, &priv->status)) { + IWL_DEBUG_SCAN("Queuing scan abort.\n"); + set_bit(STATUS_SCAN_ABORTING, &priv->status); + queue_work(priv->workqueue, &priv->abort_scan); + + } else + IWL_DEBUG_SCAN("Scan abort already in progress.\n"); + + return test_bit(STATUS_SCANNING, &priv->status); + } + + return 0; +} + +/** + * iwl_scan_cancel_timeout - Cancel any currently executing HW scan + * @ms: amount of time to wait (in milliseconds) for scan to abort + * + * NOTE: priv->mutex must be held before calling this function + */ +static int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms) +{ + unsigned long now = jiffies; + int ret; + + ret = iwl_scan_cancel(priv); + if (ret && ms) { + mutex_unlock(&priv->mutex); + while (!time_after(jiffies, now + msecs_to_jiffies(ms)) && + test_bit(STATUS_SCANNING, &priv->status)) + msleep(1); + mutex_lock(&priv->mutex); + + return test_bit(STATUS_SCANNING, &priv->status); + } + + return ret; +} + +static void iwl_sequence_reset(struct iwl_priv *priv) +{ + /* Reset ieee stats */ + + /* We don't reset the net_device_stats (ieee->stats) on + * re-association */ + + priv->last_seq_num = -1; + priv->last_frag_num = -1; + priv->last_packet_time = 0; + + iwl_scan_cancel(priv); +} + +#define MAX_UCODE_BEACON_INTERVAL 4096 +#define INTEL_CONN_LISTEN_INTERVAL __constant_cpu_to_le16(0xA) + +static __le16 iwl_adjust_beacon_interval(u16 beacon_val) +{ + u16 new_val = 0; + u16 beacon_factor = 0; + + beacon_factor = + (beacon_val + MAX_UCODE_BEACON_INTERVAL) + / MAX_UCODE_BEACON_INTERVAL; + new_val = beacon_val / beacon_factor; + + return cpu_to_le16(new_val); +} + +static void iwl_setup_rxon_timing(struct iwl_priv *priv) +{ + u64 interval_tm_unit; + u64 tsf, result; + unsigned long flags; + struct ieee80211_conf *conf = NULL; + u16 beacon_int = 0; + + conf = ieee80211_get_hw_conf(priv->hw); + + spin_lock_irqsave(&priv->lock, flags); + priv->rxon_timing.timestamp.dw[1] = cpu_to_le32(priv->timestamp1); + priv->rxon_timing.timestamp.dw[0] = cpu_to_le32(priv->timestamp0); + + priv->rxon_timing.listen_interval = INTEL_CONN_LISTEN_INTERVAL; + + tsf = priv->timestamp1; + tsf = ((tsf << 32) | priv->timestamp0); + + beacon_int = priv->beacon_int; + spin_unlock_irqrestore(&priv->lock, flags); + + if (priv->iw_mode == IEEE80211_IF_TYPE_STA) { + if (beacon_int == 0) { + priv->rxon_timing.beacon_interval = cpu_to_le16(100); + priv->rxon_timing.beacon_init_val = cpu_to_le32(102400); + } else { + priv->rxon_timing.beacon_interval = + cpu_to_le16(beacon_int); + priv->rxon_timing.beacon_interval = + iwl_adjust_beacon_interval( + le16_to_cpu(priv->rxon_timing.beacon_interval)); + } + + priv->rxon_timing.atim_window = 0; + } else { + priv->rxon_timing.beacon_interval = + iwl_adjust_beacon_interval(conf->beacon_int); + /* TODO: we need to get atim_window from upper stack + * for now we set to 0 */ + priv->rxon_timing.atim_window = 0; + } + + interval_tm_unit = + (le16_to_cpu(priv->rxon_timing.beacon_interval) * 1024); + result = do_div(tsf, interval_tm_unit); + priv->rxon_timing.beacon_init_val = + cpu_to_le32((u32) ((u64) interval_tm_unit - result)); + + IWL_DEBUG_ASSOC + ("beacon interval %d beacon timer %d beacon tim %d\n", + le16_to_cpu(priv->rxon_timing.beacon_interval), + le32_to_cpu(priv->rxon_timing.beacon_init_val), + le16_to_cpu(priv->rxon_timing.atim_window)); +} + +static int iwl_scan_initiate(struct iwl_priv *priv) +{ + if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { + IWL_ERROR("APs don't scan.\n"); + return 0; + } + + if (!iwl_is_ready_rf(priv)) { + IWL_DEBUG_SCAN("Aborting scan due to not ready.\n"); + return -EIO; + } + + if (test_bit(STATUS_SCANNING, &priv->status)) { + IWL_DEBUG_SCAN("Scan already in progress.\n"); + return -EAGAIN; + } + + if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { + IWL_DEBUG_SCAN("Scan request while abort pending. " + "Queuing.\n"); + return -EAGAIN; + } + + IWL_DEBUG_INFO("Starting scan...\n"); + priv->scan_bands = 2; + set_bit(STATUS_SCANNING, &priv->status); + priv->scan_start = jiffies; + priv->scan_pass_start = priv->scan_start; + + queue_work(priv->workqueue, &priv->request_scan); + + return 0; +} + +static int iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt) +{ + struct iwl_rxon_cmd *rxon = &priv->staging_rxon; + + if (hw_decrypt) + rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK; + else + rxon->filter_flags |= RXON_FILTER_DIS_DECRYPT_MSK; + + return 0; +} + +static void iwl_set_flags_for_phymode(struct iwl_priv *priv, u8 phymode) +{ + if (phymode == MODE_IEEE80211A) { + priv->staging_rxon.flags &= + ~(RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK + | RXON_FLG_CCK_MSK); + priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK; + } else { + /* Copied from iwl_bg_post_associate() */ + if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME) + priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK; + else + priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; + + if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) + priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; + + priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK; + priv->staging_rxon.flags |= RXON_FLG_AUTO_DETECT_MSK; + priv->staging_rxon.flags &= ~RXON_FLG_CCK_MSK; + } +} + +/* + * initilize rxon structure with default values fromm eeprom + */ +static void iwl_connection_init_rx_config(struct iwl_priv *priv) +{ + const struct iwl_channel_info *ch_info; + + memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon)); + + switch (priv->iw_mode) { + case IEEE80211_IF_TYPE_AP: + priv->staging_rxon.dev_type = RXON_DEV_TYPE_AP; + break; + + case IEEE80211_IF_TYPE_STA: + priv->staging_rxon.dev_type = RXON_DEV_TYPE_ESS; + priv->staging_rxon.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK; + break; + + case IEEE80211_IF_TYPE_IBSS: + priv->staging_rxon.dev_type = RXON_DEV_TYPE_IBSS; + priv->staging_rxon.flags = RXON_FLG_SHORT_PREAMBLE_MSK; + priv->staging_rxon.filter_flags = RXON_FILTER_BCON_AWARE_MSK | + RXON_FILTER_ACCEPT_GRP_MSK; + break; + + case IEEE80211_IF_TYPE_MNTR: + priv->staging_rxon.dev_type = RXON_DEV_TYPE_SNIFFER; + priv->staging_rxon.filter_flags = RXON_FILTER_PROMISC_MSK | + RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_ACCEPT_GRP_MSK; + break; + } + +#if 0 + /* TODO: Figure out when short_preamble would be set and cache from + * that */ + if (!hw_to_local(priv->hw)->short_preamble) + priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK; + else + priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; +#endif + + ch_info = iwl_get_channel_info(priv, priv->phymode, + le16_to_cpu(priv->staging_rxon.channel)); + + if (!ch_info) + ch_info = &priv->channel_info[0]; + + /* + * in some case A channels are all non IBSS + * in this case force B/G channel + */ + if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && + !(is_channel_ibss(ch_info))) + ch_info = &priv->channel_info[0]; + + priv->staging_rxon.channel = cpu_to_le16(ch_info->channel); + if (is_channel_a_band(ch_info)) + priv->phymode = MODE_IEEE80211A; + else + priv->phymode = MODE_IEEE80211G; + + iwl_set_flags_for_phymode(priv, priv->phymode); + + priv->staging_rxon.ofdm_basic_rates = + (IWL_OFDM_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF; + priv->staging_rxon.cck_basic_rates = + (IWL_CCK_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF; + + priv->staging_rxon.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK | + RXON_FLG_CHANNEL_MODE_PURE_40_MSK); + memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); + memcpy(priv->staging_rxon.wlap_bssid_addr, priv->mac_addr, ETH_ALEN); + priv->staging_rxon.ofdm_ht_single_stream_basic_rates = 0xff; + priv->staging_rxon.ofdm_ht_dual_stream_basic_rates = 0xff; + iwl4965_set_rxon_chain(priv); +} + +static int iwl_set_mode(struct iwl_priv *priv, int mode) +{ + if (!iwl_is_ready_rf(priv)) + return -EAGAIN; + + if (mode == IEEE80211_IF_TYPE_IBSS) { + const struct iwl_channel_info *ch_info; + + ch_info = iwl_get_channel_info(priv, + priv->phymode, + le16_to_cpu(priv->staging_rxon.channel)); + + if (!ch_info || !is_channel_ibss(ch_info)) { + IWL_ERROR("channel %d not IBSS channel\n", + le16_to_cpu(priv->staging_rxon.channel)); + return -EINVAL; + } + } + + cancel_delayed_work(&priv->scan_check); + if (iwl_scan_cancel_timeout(priv, 100)) { + IWL_WARNING("Aborted scan still in progress after 100ms\n"); + IWL_DEBUG_MAC80211("leaving - scan abort failed.\n"); + return -EAGAIN; + } + + priv->iw_mode = mode; + + iwl_connection_init_rx_config(priv); + memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); + + iwl_clear_stations_table(priv); + + iwl_commit_rxon(priv); + + return 0; +} + +static void iwl_build_tx_cmd_hwcrypto(struct iwl_priv *priv, + struct ieee80211_tx_control *ctl, + struct iwl_cmd *cmd, + struct sk_buff *skb_frag, + int last_frag) +{ + struct iwl_hw_key *keyinfo = &priv->stations[ctl->key_idx].keyinfo; + + switch (keyinfo->alg) { + case ALG_CCMP: + cmd->cmd.tx.sec_ctl = TX_CMD_SEC_CCM; + memcpy(cmd->cmd.tx.key, keyinfo->key, keyinfo->keylen); + IWL_DEBUG_TX("tx_cmd with aes hwcrypto\n"); + break; + + case ALG_TKIP: +#if 0 + cmd->cmd.tx.sec_ctl = TX_CMD_SEC_TKIP; + + if (last_frag) + memcpy(cmd->cmd.tx.tkip_mic.byte, skb_frag->tail - 8, + 8); + else + memset(cmd->cmd.tx.tkip_mic.byte, 0, 8); +#endif + break; + + case ALG_WEP: + cmd->cmd.tx.sec_ctl = TX_CMD_SEC_WEP | + (ctl->key_idx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT; + + if (keyinfo->keylen == 13) + cmd->cmd.tx.sec_ctl |= TX_CMD_SEC_KEY128; + + memcpy(&cmd->cmd.tx.key[3], keyinfo->key, keyinfo->keylen); + + IWL_DEBUG_TX("Configuring packet for WEP encryption " + "with key %d\n", ctl->key_idx); + break; + + case ALG_NONE: + IWL_DEBUG_TX("Tx packet in the clear (encrypt requested).\n"); + break; + + default: + printk(KERN_ERR "Unknown encode alg %d\n", keyinfo->alg); + break; + } +} + +/* + * handle build REPLY_TX command notification. + */ +static void iwl_build_tx_cmd_basic(struct iwl_priv *priv, + struct iwl_cmd *cmd, + struct ieee80211_tx_control *ctrl, + struct ieee80211_hdr *hdr, + int is_unicast, u8 std_id) +{ + __le16 *qc; + u16 fc = le16_to_cpu(hdr->frame_control); + __le32 tx_flags = cmd->cmd.tx.tx_flags; + + cmd->cmd.tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; + if (!(ctrl->flags & IEEE80211_TXCTL_NO_ACK)) { + tx_flags |= TX_CMD_FLG_ACK_MSK; + if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) + tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; + if (ieee80211_is_probe_response(fc) && + !(le16_to_cpu(hdr->seq_ctrl) & 0xf)) + tx_flags |= TX_CMD_FLG_TSF_MSK; + } else { + tx_flags &= (~TX_CMD_FLG_ACK_MSK); + tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; + } + + cmd->cmd.tx.sta_id = std_id; + if (ieee80211_get_morefrag(hdr)) + tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK; + + qc = ieee80211_get_qos_ctrl(hdr); + if (qc) { + cmd->cmd.tx.tid_tspec = (u8) (le16_to_cpu(*qc) & 0xf); + tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK; + } else + tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; + + if (ctrl->flags & IEEE80211_TXCTL_USE_RTS_CTS) { + tx_flags |= TX_CMD_FLG_RTS_MSK; + tx_flags &= ~TX_CMD_FLG_CTS_MSK; + } else if (ctrl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { + tx_flags &= ~TX_CMD_FLG_RTS_MSK; + tx_flags |= TX_CMD_FLG_CTS_MSK; + } + + if ((tx_flags & TX_CMD_FLG_RTS_MSK) || (tx_flags & TX_CMD_FLG_CTS_MSK)) + tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK; + + tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK); + if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) { + if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ || + (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ) + cmd->cmd.tx.timeout.pm_frame_timeout = + cpu_to_le16(3); + else + cmd->cmd.tx.timeout.pm_frame_timeout = + cpu_to_le16(2); + } else + cmd->cmd.tx.timeout.pm_frame_timeout = 0; + + cmd->cmd.tx.driver_txop = 0; + cmd->cmd.tx.tx_flags = tx_flags; + cmd->cmd.tx.next_frame_len = 0; +} + +static int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) +{ + int sta_id; + u16 fc = le16_to_cpu(hdr->frame_control); + + /* If this frame is broadcast or not data then use the broadcast + * station id */ + if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) || + is_multicast_ether_addr(hdr->addr1)) + return priv->hw_setting.bcast_sta_id; + + switch (priv->iw_mode) { + + /* If this frame is part of a BSS network (we're a station), then + * we use the AP's station id */ + case IEEE80211_IF_TYPE_STA: + return IWL_AP_ID; + + /* If we are an AP, then find the station, or use BCAST */ + case IEEE80211_IF_TYPE_AP: + sta_id = iwl_hw_find_station(priv, hdr->addr1); + if (sta_id != IWL_INVALID_STATION) + return sta_id; + return priv->hw_setting.bcast_sta_id; + + /* If this frame is part of a IBSS network, then we use the + * target specific station id */ + case IEEE80211_IF_TYPE_IBSS: + sta_id = iwl_hw_find_station(priv, hdr->addr1); + if (sta_id != IWL_INVALID_STATION) + return sta_id; + + sta_id = iwl_add_station(priv, hdr->addr1, 0, CMD_ASYNC); + + if (sta_id != IWL_INVALID_STATION) + return sta_id; + + IWL_DEBUG_DROP("Station " MAC_FMT " not in station map. " + "Defaulting to broadcast...\n", + MAC_ARG(hdr->addr1)); + iwl_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); + return priv->hw_setting.bcast_sta_id; + + default: + IWL_WARNING("Unkown mode of operation: %d", priv->iw_mode); + return priv->hw_setting.bcast_sta_id; + } +} + +/* + * start REPLY_TX command process + */ +static int iwl_tx_skb(struct iwl_priv *priv, + struct sk_buff *skb, struct ieee80211_tx_control *ctl) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct iwl_tfd_frame *tfd; + u32 *control_flags; + int txq_id = ctl->queue; + struct iwl_tx_queue *txq = NULL; + struct iwl_queue *q = NULL; + dma_addr_t phys_addr; + dma_addr_t txcmd_phys; + struct iwl_cmd *out_cmd = NULL; + u16 len, idx, len_org; + u8 id, hdr_len, unicast; + u8 sta_id; + u16 seq_number = 0; + u16 fc; + __le16 *qc; + u8 wait_write_ptr = 0; + unsigned long flags; + int rc; + + spin_lock_irqsave(&priv->lock, flags); + if (iwl_is_rfkill(priv)) { + IWL_DEBUG_DROP("Dropping - RF KILL\n"); + goto drop_unlock; + } + + if (!priv->interface_id) { + IWL_DEBUG_DROP("Dropping - !priv->interface_id\n"); + goto drop_unlock; + } + + if ((ctl->tx_rate & 0xFF) == IWL_INVALID_RATE) { + IWL_ERROR("ERROR: No TX rate available.\n"); + goto drop_unlock; + } + + unicast = !is_multicast_ether_addr(hdr->addr1); + id = 0; + + fc = le16_to_cpu(hdr->frame_control); + +#ifdef CONFIG_IWLWIFI_DEBUG + if (ieee80211_is_auth(fc)) + IWL_DEBUG_TX("Sending AUTH frame\n"); + else if (ieee80211_is_assoc_request(fc)) + IWL_DEBUG_TX("Sending ASSOC frame\n"); + else if (ieee80211_is_reassoc_request(fc)) + IWL_DEBUG_TX("Sending REASSOC frame\n"); +#endif + + if (!iwl_is_associated(priv) && + ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) { + IWL_DEBUG_DROP("Dropping - !iwl_is_associated\n"); + goto drop_unlock; + } + + spin_unlock_irqrestore(&priv->lock, flags); + + hdr_len = ieee80211_get_hdrlen(fc); + sta_id = iwl_get_sta_id(priv, hdr); + if (sta_id == IWL_INVALID_STATION) { + IWL_DEBUG_DROP("Dropping - INVALID STATION: " MAC_FMT "\n", + MAC_ARG(hdr->addr1)); + goto drop; + } + + IWL_DEBUG_RATE("station Id %d\n", sta_id); + + qc = ieee80211_get_qos_ctrl(hdr); + if (qc) { + u8 tid = (u8)(le16_to_cpu(*qc) & 0xf); + seq_number = priv->stations[sta_id].tid[tid].seq_number & + IEEE80211_SCTL_SEQ; + hdr->seq_ctrl = cpu_to_le16(seq_number) | + (hdr->seq_ctrl & + __constant_cpu_to_le16(IEEE80211_SCTL_FRAG)); + seq_number += 0x10; +#ifdef CONFIG_IWLWIFI_HT +#ifdef CONFIG_IWLWIFI_HT_AGG + /* aggregation is on for this */ + if (ctl->flags & IEEE80211_TXCTL_HT_MPDU_AGG) + txq_id = priv->stations[sta_id].tid[tid].agg.txq_id; +#endif /* CONFIG_IWLWIFI_HT_AGG */ +#endif /* CONFIG_IWLWIFI_HT */ + } + txq = &priv->txq[txq_id]; + q = &txq->q; + + spin_lock_irqsave(&priv->lock, flags); + + tfd = &txq->bd[q->first_empty]; + memset(tfd, 0, sizeof(*tfd)); + control_flags = (u32 *) tfd; + idx = get_cmd_index(q, q->first_empty, 0); + + memset(&(txq->txb[q->first_empty]), 0, sizeof(struct iwl_tx_info)); + txq->txb[q->first_empty].skb[0] = skb; + memcpy(&(txq->txb[q->first_empty].status.control), + ctl, sizeof(struct ieee80211_tx_control)); + out_cmd = &txq->cmd[idx]; + memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr)); + memset(&out_cmd->cmd.tx, 0, sizeof(out_cmd->cmd.tx)); + out_cmd->hdr.cmd = REPLY_TX; + out_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) | + INDEX_TO_SEQ(q->first_empty))); + /* copy frags header */ + memcpy(out_cmd->cmd.tx.hdr, hdr, hdr_len); + + /* hdr = (struct ieee80211_hdr *)out_cmd->cmd.tx.hdr; */ + len = priv->hw_setting.tx_cmd_len + + sizeof(struct iwl_cmd_header) + hdr_len; + + len_org = len; + len = (len + 3) & ~3; + + if (len_org != len) + len_org = 1; + else + len_org = 0; + + txcmd_phys = txq->dma_addr_cmd + sizeof(struct iwl_cmd) * idx + + offsetof(struct iwl_cmd, hdr); + + iwl_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len); + + if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) + iwl_build_tx_cmd_hwcrypto(priv, ctl, out_cmd, skb, 0); + + /* 802.11 null functions have no payload... */ + len = skb->len - hdr_len; + if (len) { + phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len, + len, PCI_DMA_TODEVICE); + iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, len); + } + + if (len_org) + out_cmd->cmd.tx.tx_flags |= TX_CMD_FLG_MH_PAD_MSK; + + len = (u16)skb->len; + out_cmd->cmd.tx.len = cpu_to_le16(len); + + /* TODO need this for burst mode later on */ + iwl_build_tx_cmd_basic(priv, out_cmd, ctl, hdr, unicast, sta_id); + + /* set is_hcca to 0; it probably will never be implemented */ + iwl_hw_build_tx_cmd_rate(priv, out_cmd, ctl, hdr, sta_id, 0); + + iwl4965_tx_cmd(priv, out_cmd, sta_id, txcmd_phys, + hdr, hdr_len, ctl, NULL); + + if (!ieee80211_get_morefrag(hdr)) { + txq->need_update = 1; + if (qc) { + u8 tid = (u8)(le16_to_cpu(*qc) & 0xf); + priv->stations[sta_id].tid[tid].seq_number = seq_number; + } + } else { + wait_write_ptr = 1; + txq->need_update = 0; + } + + iwl_print_hex_dump(IWL_DL_TX, out_cmd->cmd.payload, + sizeof(out_cmd->cmd.tx)); + + iwl_print_hex_dump(IWL_DL_TX, (u8 *)out_cmd->cmd.tx.hdr, + ieee80211_get_hdrlen(fc)); + + iwl4965_tx_queue_update_wr_ptr(priv, txq, len); + + q->first_empty = iwl_queue_inc_wrap(q->first_empty, q->n_bd); + rc = iwl_tx_queue_update_write_ptr(priv, txq); + spin_unlock_irqrestore(&priv->lock, flags); + + if (rc) + return rc; + + if ((iwl_queue_space(q) < q->high_mark) + && priv->mac80211_registered) { + if (wait_write_ptr) { + spin_lock_irqsave(&priv->lock, flags); + txq->need_update = 1; + iwl_tx_queue_update_write_ptr(priv, txq); + spin_unlock_irqrestore(&priv->lock, flags); + } + + ieee80211_stop_queue(priv->hw, ctl->queue); + } + + return 0; + +drop_unlock: + spin_unlock_irqrestore(&priv->lock, flags); +drop: + return -1; +} + +static void iwl_set_rate(struct iwl_priv *priv) +{ + const struct ieee80211_hw_mode *hw = NULL; + struct ieee80211_rate *rate; + int i; + + hw = iwl_get_hw_mode(priv, priv->phymode); + + priv->active_rate = 0; + priv->active_rate_basic = 0; + + IWL_DEBUG_RATE("Setting rates for 802.11%c\n", + hw->mode == MODE_IEEE80211A ? + 'a' : ((hw->mode == MODE_IEEE80211B) ? 'b' : 'g')); + + for (i = 0; i < hw->num_rates; i++) { + rate = &(hw->rates[i]); + if ((rate->val < IWL_RATE_COUNT) && + (rate->flags & IEEE80211_RATE_SUPPORTED)) { + IWL_DEBUG_RATE("Adding rate index %d (plcp %d)%s\n", + rate->val, iwl_rates[rate->val].plcp, + (rate->flags & IEEE80211_RATE_BASIC) ? + "*" : ""); + priv->active_rate |= (1 << rate->val); + if (rate->flags & IEEE80211_RATE_BASIC) + priv->active_rate_basic |= (1 << rate->val); + } else + IWL_DEBUG_RATE("Not adding rate %d (plcp %d)\n", + rate->val, iwl_rates[rate->val].plcp); + } + + IWL_DEBUG_RATE("Set active_rate = %0x, active_rate_basic = %0x\n", + priv->active_rate, priv->active_rate_basic); + + /* + * If a basic rate is configured, then use it (adding IWL_RATE_1M_MASK) + * otherwise set it to the default of all CCK rates and 6, 12, 24 for + * OFDM + */ + if (priv->active_rate_basic & IWL_CCK_BASIC_RATES_MASK) + priv->staging_rxon.cck_basic_rates = + ((priv->active_rate_basic & + IWL_CCK_RATES_MASK) >> IWL_FIRST_CCK_RATE) & 0xF; + else + priv->staging_rxon.cck_basic_rates = + (IWL_CCK_BASIC_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF; + + if (priv->active_rate_basic & IWL_OFDM_BASIC_RATES_MASK) + priv->staging_rxon.ofdm_basic_rates = + ((priv->active_rate_basic & + (IWL_OFDM_BASIC_RATES_MASK | IWL_RATE_6M_MASK)) >> + IWL_FIRST_OFDM_RATE) & 0xFF; + else + priv->staging_rxon.ofdm_basic_rates = + (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF; +} + +static void iwl_radio_kill_sw(struct iwl_priv *priv, int disable_radio) +{ + unsigned long flags; + + if (!!disable_radio == test_bit(STATUS_RF_KILL_SW, &priv->status)) + return; + + IWL_DEBUG_RF_KILL("Manual SW RF KILL set to: RADIO %s\n", + disable_radio ? "OFF" : "ON"); + + if (disable_radio) { + iwl_scan_cancel(priv); + /* FIXME: This is a workaround for AP */ + if (priv->iw_mode != IEEE80211_IF_TYPE_AP) { + spin_lock_irqsave(&priv->lock, flags); + iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, + CSR_UCODE_SW_BIT_RFKILL); + spin_unlock_irqrestore(&priv->lock, flags); + iwl_send_card_state(priv, CARD_STATE_CMD_DISABLE, 0); + set_bit(STATUS_RF_KILL_SW, &priv->status); + } + return; + } + + spin_lock_irqsave(&priv->lock, flags); + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + + clear_bit(STATUS_RF_KILL_SW, &priv->status); + spin_unlock_irqrestore(&priv->lock, flags); + + /* wake up ucode */ + msleep(10); + + spin_lock_irqsave(&priv->lock, flags); + iwl_read32(priv, CSR_UCODE_DRV_GP1); + if (!iwl_grab_restricted_access(priv)) + iwl_release_restricted_access(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + if (test_bit(STATUS_RF_KILL_HW, &priv->status)) { + IWL_DEBUG_RF_KILL("Can not turn radio back on - " + "disabled by HW switch\n"); + return; + } + + queue_work(priv->workqueue, &priv->restart); + return; +} + +void iwl_set_decrypted_flag(struct iwl_priv *priv, struct sk_buff *skb, + u32 decrypt_res, struct ieee80211_rx_status *stats) +{ + u16 fc = + le16_to_cpu(((struct ieee80211_hdr *)skb->data)->frame_control); + + if (priv->active_rxon.filter_flags & RXON_FILTER_DIS_DECRYPT_MSK) + return; + + if (!(fc & IEEE80211_FCTL_PROTECTED)) + return; + + IWL_DEBUG_RX("decrypt_res:0x%x\n", decrypt_res); + switch (decrypt_res & RX_RES_STATUS_SEC_TYPE_MSK) { + case RX_RES_STATUS_SEC_TYPE_TKIP: + if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == + RX_RES_STATUS_BAD_ICV_MIC) + stats->flag |= RX_FLAG_MMIC_ERROR; + case RX_RES_STATUS_SEC_TYPE_WEP: + case RX_RES_STATUS_SEC_TYPE_CCMP: + if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == + RX_RES_STATUS_DECRYPT_OK) { + IWL_DEBUG_RX("hw decrypt successfully!!!\n"); + stats->flag |= RX_FLAG_DECRYPTED; + } + break; + + default: + break; + } +} + +void iwl_handle_data_packet_monitor(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb, + void *data, short len, + struct ieee80211_rx_status *stats, + u16 phy_flags) +{ + struct iwl_rt_rx_hdr *iwl_rt; + + /* First cache any information we need before we overwrite + * the information provided in the skb from the hardware */ + s8 signal = stats->ssi; + s8 noise = 0; + int rate = stats->rate; + u64 tsf = stats->mactime; + __le16 phy_flags_hw = cpu_to_le16(phy_flags); + + /* We received data from the HW, so stop the watchdog */ + if (len > IWL_RX_BUF_SIZE - sizeof(*iwl_rt)) { + IWL_DEBUG_DROP("Dropping too large packet in monitor\n"); + return; + } + + /* copy the frame data to write after where the radiotap header goes */ + iwl_rt = (void *)rxb->skb->data; + memmove(iwl_rt->payload, data, len); + + iwl_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; + iwl_rt->rt_hdr.it_pad = 0; /* always good to zero */ + + /* total header + data */ + iwl_rt->rt_hdr.it_len = cpu_to_le16(sizeof(*iwl_rt)); + + /* Set the size of the skb to the size of the frame */ + skb_put(rxb->skb, sizeof(*iwl_rt) + len); + + /* Big bitfield of all the fields we provide in radiotap */ + iwl_rt->rt_hdr.it_present = + cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) | + (1 << IEEE80211_RADIOTAP_FLAGS) | + (1 << IEEE80211_RADIOTAP_RATE) | + (1 << IEEE80211_RADIOTAP_CHANNEL) | + (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | + (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | + (1 << IEEE80211_RADIOTAP_ANTENNA)); + + /* Zero the flags, we'll add to them as we go */ + iwl_rt->rt_flags = 0; + + iwl_rt->rt_tsf = cpu_to_le64(tsf); + + /* Convert to dBm */ + iwl_rt->rt_dbmsignal = signal; + iwl_rt->rt_dbmnoise = noise; + + /* Convert the channel frequency and set the flags */ + iwl_rt->rt_channelMHz = cpu_to_le16(stats->freq); + if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK)) + iwl_rt->rt_chbitmask = + cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ)); + else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK) + iwl_rt->rt_chbitmask = + cpu_to_le16((IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ)); + else /* 802.11g */ + iwl_rt->rt_chbitmask = + cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ)); + + rate = iwl_rate_index_from_plcp(rate); + if (rate == -1) + iwl_rt->rt_rate = 0; + else + iwl_rt->rt_rate = iwl_rates[rate].ieee; + + /* antenna number */ + iwl_rt->rt_antenna = + le16_to_cpu(phy_flags_hw & RX_RES_PHY_FLAGS_ANTENNA_MSK) >> 4; + + /* set the preamble flag if we have it */ + if (phy_flags_hw & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) + iwl_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; + + IWL_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len); + + stats->flag |= RX_FLAG_RADIOTAP; + ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats); + rxb->skb = NULL; +} + + +#define IWL_PACKET_RETRY_TIME HZ + +int is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header) +{ + u16 sc = le16_to_cpu(header->seq_ctrl); + u16 seq = (sc & IEEE80211_SCTL_SEQ) >> 4; + u16 frag = sc & IEEE80211_SCTL_FRAG; + u16 *last_seq, *last_frag; + unsigned long *last_time; + + switch (priv->iw_mode) { + case IEEE80211_IF_TYPE_IBSS:{ + struct list_head *p; + struct iwl_ibss_seq *entry = NULL; + u8 *mac = header->addr2; + int index = mac[5] & (IWL_IBSS_MAC_HASH_SIZE - 1); + + __list_for_each(p, &priv->ibss_mac_hash[index]) { + entry = + list_entry(p, struct iwl_ibss_seq, list); + if (!compare_ether_addr(entry->mac, mac)) + break; + } + if (p == &priv->ibss_mac_hash[index]) { + entry = kzalloc(sizeof(*entry), GFP_ATOMIC); + if (!entry) { + IWL_ERROR + ("Cannot malloc new mac entry\n"); + return 0; + } + memcpy(entry->mac, mac, ETH_ALEN); + entry->seq_num = seq; + entry->frag_num = frag; + entry->packet_time = jiffies; + list_add(&entry->list, + &priv->ibss_mac_hash[index]); + return 0; + } + last_seq = &entry->seq_num; + last_frag = &entry->frag_num; + last_time = &entry->packet_time; + break; + } + case IEEE80211_IF_TYPE_STA: + last_seq = &priv->last_seq_num; + last_frag = &priv->last_frag_num; + last_time = &priv->last_packet_time; + break; + default: + return 0; + } + if ((*last_seq == seq) && + time_after(*last_time + IWL_PACKET_RETRY_TIME, jiffies)) { + if (*last_frag == frag) + goto drop; + if (*last_frag + 1 != frag) + /* out-of-order fragment */ + goto drop; + } else + *last_seq = seq; + + *last_frag = frag; + *last_time = jiffies; + return 0; + + drop: + return 1; +} + +#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT + +#include "iwl-spectrum.h" + +#define BEACON_TIME_MASK_LOW 0x00FFFFFF +#define BEACON_TIME_MASK_HIGH 0xFF000000 +#define TIME_UNIT 1024 + +/* + * extended beacon time format + * time in usec will be changed into a 32-bit value in 8:24 format + * the high 1 byte is the beacon counts + * the lower 3 bytes is the time in usec within one beacon interval + */ + +static u32 iwl_usecs_to_beacons(u32 usec, u32 beacon_interval) +{ + u32 quot; + u32 rem; + u32 interval = beacon_interval * 1024; + + if (!interval || !usec) + return 0; + + quot = (usec / interval) & (BEACON_TIME_MASK_HIGH >> 24); + rem = (usec % interval) & BEACON_TIME_MASK_LOW; + + return (quot << 24) + rem; +} + +/* base is usually what we get from ucode with each received frame, + * the same as HW timer counter counting down + */ + +static __le32 iwl_add_beacon_time(u32 base, u32 addon, u32 beacon_interval) +{ + u32 base_low = base & BEACON_TIME_MASK_LOW; + u32 addon_low = addon & BEACON_TIME_MASK_LOW; + u32 interval = beacon_interval * TIME_UNIT; + u32 res = (base & BEACON_TIME_MASK_HIGH) + + (addon & BEACON_TIME_MASK_HIGH); + + if (base_low > addon_low) + res += base_low - addon_low; + else if (base_low < addon_low) { + res += interval + base_low - addon_low; + res += (1 << 24); + } else + res += (1 << 24); + + return cpu_to_le32(res); +} + +static int iwl_get_measurement(struct iwl_priv *priv, + struct ieee80211_measurement_params *params, + u8 type) +{ + struct iwl_spectrum_cmd spectrum; + struct iwl_rx_packet *res; + struct iwl_host_cmd cmd = { + .id = REPLY_SPECTRUM_MEASUREMENT_CMD, + .data = (void *)&spectrum, + .meta.flags = CMD_WANT_SKB, + }; + u32 add_time = le64_to_cpu(params->start_time); + int rc; + int spectrum_resp_status; + int duration = le16_to_cpu(params->duration); + + if (iwl_is_associated(priv)) + add_time = + iwl_usecs_to_beacons( + le64_to_cpu(params->start_time) - priv->last_tsf, + le16_to_cpu(priv->rxon_timing.beacon_interval)); + + memset(&spectrum, 0, sizeof(spectrum)); + + spectrum.channel_count = cpu_to_le16(1); + spectrum.flags = + RXON_FLG_TSF2HOST_MSK | RXON_FLG_ANT_A_MSK | RXON_FLG_DIS_DIV_MSK; + spectrum.filter_flags = MEASUREMENT_FILTER_FLAG; + cmd.len = sizeof(spectrum); + spectrum.len = cpu_to_le16(cmd.len - sizeof(spectrum.len)); + + if (iwl_is_associated(priv)) + spectrum.start_time = + iwl_add_beacon_time(priv->last_beacon_time, + add_time, + le16_to_cpu(priv->rxon_timing.beacon_interval)); + else + spectrum.start_time = 0; + + spectrum.channels[0].duration = cpu_to_le32(duration * TIME_UNIT); + spectrum.channels[0].channel = params->channel; + spectrum.channels[0].type = type; + if (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK) + spectrum.flags |= RXON_FLG_BAND_24G_MSK | + RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK; + + rc = iwl_send_cmd_sync(priv, &cmd); + if (rc) + return rc; + + res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; + if (res->hdr.flags & IWL_CMD_FAILED_MSK) { + IWL_ERROR("Bad return from REPLY_RX_ON_ASSOC command\n"); + rc = -EIO; + } + + spectrum_resp_status = le16_to_cpu(res->u.spectrum.status); + switch (spectrum_resp_status) { + case 0: /* Command will be handled */ + if (res->u.spectrum.id != 0xff) { + IWL_DEBUG_INFO + ("Replaced existing measurement: %d\n", + res->u.spectrum.id); + priv->measurement_status &= ~MEASUREMENT_READY; + } + priv->measurement_status |= MEASUREMENT_ACTIVE; + rc = 0; + break; + + case 1: /* Command will not be handled */ + rc = -EAGAIN; + break; + } + + dev_kfree_skb_any(cmd.meta.u.skb); + + return rc; +} +#endif + +static void iwl_txstatus_to_ieee(struct iwl_priv *priv, + struct iwl_tx_info *tx_sta) +{ + + tx_sta->status.ack_signal = 0; + tx_sta->status.excessive_retries = 0; + tx_sta->status.queue_length = 0; + tx_sta->status.queue_number = 0; + + if (in_interrupt()) + ieee80211_tx_status_irqsafe(priv->hw, + tx_sta->skb[0], &(tx_sta->status)); + else + ieee80211_tx_status(priv->hw, + tx_sta->skb[0], &(tx_sta->status)); + + tx_sta->skb[0] = NULL; +} + +/** + * iwl_tx_queue_reclaim - Reclaim Tx queue entries no more used by NIC. + * + * When FW advances 'R' index, all entries between old and + * new 'R' index need to be reclaimed. As result, some free space + * forms. If there is enough free space (> low mark), wake Tx queue. + */ +int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) +{ + struct iwl_tx_queue *txq = &priv->txq[txq_id]; + struct iwl_queue *q = &txq->q; + int nfreed = 0; + + if ((index >= q->n_bd) || (x2_queue_used(q, index) == 0)) { + IWL_ERROR("Read index for DMA queue txq id (%d), index %d, " + "is out of range [0-%d] %d %d.\n", txq_id, + index, q->n_bd, q->first_empty, q->last_used); + return 0; + } + + for (index = iwl_queue_inc_wrap(index, q->n_bd); + q->last_used != index; + q->last_used = iwl_queue_inc_wrap(q->last_used, q->n_bd)) { + if (txq_id != IWL_CMD_QUEUE_NUM) { + iwl_txstatus_to_ieee(priv, + &(txq->txb[txq->q.last_used])); + iwl_hw_txq_free_tfd(priv, txq); + } else if (nfreed > 1) { + IWL_ERROR("HCMD skipped: index (%d) %d %d\n", index, + q->first_empty, q->last_used); + queue_work(priv->workqueue, &priv->restart); + } + nfreed++; + } + + if (iwl_queue_space(q) > q->low_mark && (txq_id >= 0) && + (txq_id != IWL_CMD_QUEUE_NUM) && + priv->mac80211_registered) + ieee80211_wake_queue(priv->hw, txq_id); + + + return nfreed; +} + +static int iwl_is_tx_success(u32 status) +{ + status &= TX_STATUS_MSK; + return (status == TX_STATUS_SUCCESS) + || (status == TX_STATUS_DIRECT_DONE); +} + +/****************************************************************************** + * + * Generic RX handler implementations + * + ******************************************************************************/ +#ifdef CONFIG_IWLWIFI_HT +#ifdef CONFIG_IWLWIFI_HT_AGG + +static inline int iwl_get_ra_sta_id(struct iwl_priv *priv, + struct ieee80211_hdr *hdr) +{ + if (priv->iw_mode == IEEE80211_IF_TYPE_STA) + return IWL_AP_ID; + else { + u8 *da = ieee80211_get_DA(hdr); + return iwl_hw_find_station(priv, da); + } +} + +static struct ieee80211_hdr *iwl_tx_queue_get_hdr( + struct iwl_priv *priv, int txq_id, int idx) +{ + if (priv->txq[txq_id].txb[idx].skb[0]) + return (struct ieee80211_hdr *)priv->txq[txq_id]. + txb[idx].skb[0]->data; + return NULL; +} + +static inline u32 iwl_get_scd_ssn(struct iwl_tx_resp *tx_resp) +{ + __le32 *scd_ssn = (__le32 *)((u32 *)&tx_resp->status + + tx_resp->frame_count); + return le32_to_cpu(*scd_ssn) & MAX_SN; + +} +static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv, + struct iwl_ht_agg *agg, + struct iwl_tx_resp *tx_resp, + u16 start_idx) +{ + u32 status; + __le32 *frame_status = &tx_resp->status; + struct ieee80211_tx_status *tx_status = NULL; + struct ieee80211_hdr *hdr = NULL; + int i, sh; + int txq_id, idx; + u16 seq; + + if (agg->wait_for_ba) + IWL_DEBUG_TX_REPLY("got tx repsons w/o back\n"); + + agg->frame_count = tx_resp->frame_count; + agg->start_idx = start_idx; + agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags); + agg->bitmap0 = agg->bitmap1 = 0; + + if (agg->frame_count == 1) { + struct iwl_tx_queue *txq ; + status = le32_to_cpu(frame_status[0]); + + txq_id = agg->txq_id; + txq = &priv->txq[txq_id]; + /* FIXME: code repetition */ + IWL_DEBUG_TX_REPLY("FrameCnt = %d, StartIdx=%d \n", + agg->frame_count, agg->start_idx); + + tx_status = &(priv->txq[txq_id].txb[txq->q.last_used].status); + tx_status->retry_count = tx_resp->failure_frame; + tx_status->queue_number = status & 0xff; + tx_status->queue_length = tx_resp->bt_kill_count; + tx_status->queue_length |= tx_resp->failure_rts; + + tx_status->flags = iwl_is_tx_success(status)? + IEEE80211_TX_STATUS_ACK : 0; + tx_status->control.tx_rate = + iwl_hw_get_rate_n_flags(tx_resp->rate_n_flags); + /* FIXME: code repetition end */ + + IWL_DEBUG_TX_REPLY("1 Frame 0x%x failure :%d\n", + status & 0xff, tx_resp->failure_frame); + IWL_DEBUG_TX_REPLY("Rate Info rate_n_flags=%x\n", + iwl_hw_get_rate_n_flags(tx_resp->rate_n_flags)); + + agg->wait_for_ba = 0; + } else { + u64 bitmap = 0; + int start = agg->start_idx; + + for (i = 0; i < agg->frame_count; i++) { + u16 sc; + status = le32_to_cpu(frame_status[i]); + seq = status >> 16; + idx = SEQ_TO_INDEX(seq); + txq_id = SEQ_TO_QUEUE(seq); + + if (status & (AGG_TX_STATE_FEW_BYTES_MSK | + AGG_TX_STATE_ABORT_MSK)) + continue; + + IWL_DEBUG_TX_REPLY("FrameCnt = %d, txq_id=%d idx=%d\n", + agg->frame_count, txq_id, idx); + + hdr = iwl_tx_queue_get_hdr(priv, txq_id, idx); + + sc = le16_to_cpu(hdr->seq_ctrl); + if (idx != (SEQ_TO_SN(sc) & 0xff)) { + IWL_ERROR("BUG_ON idx doesn't match seq control" + " idx=%d, seq_idx=%d, seq=%d\n", + idx, SEQ_TO_SN(sc), + hdr->seq_ctrl); + return -1; + } + + IWL_DEBUG_TX_REPLY("AGG Frame i=%d idx %d seq=%d\n", + i, idx, SEQ_TO_SN(sc)); + + sh = idx - start; + if (sh > 64) { + sh = (start - idx) + 0xff; + bitmap = bitmap << sh; + sh = 0; + start = idx; + } else if (sh < -64) + sh = 0xff - (start - idx); + else if (sh < 0) { + sh = start - idx; + start = idx; + bitmap = bitmap << sh; + sh = 0; + } + bitmap |= (1 << sh); + IWL_DEBUG_TX_REPLY("start=%d bitmap=0x%x\n", + start, (u32)(bitmap & 0xFFFFFFFF)); + } + + agg->bitmap0 = bitmap & 0xFFFFFFFF; + agg->bitmap1 = bitmap >> 32; + agg->start_idx = start; + agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags); + IWL_DEBUG_TX_REPLY("Frames %d start_idx=%d bitmap=0x%x\n", + agg->frame_count, agg->start_idx, + agg->bitmap0); + + if (bitmap) + agg->wait_for_ba = 1; + } + return 0; +} +#endif +#endif + +static void iwl_rx_reply_tx(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + u16 sequence = le16_to_cpu(pkt->hdr.sequence); + int txq_id = SEQ_TO_QUEUE(sequence); + int index = SEQ_TO_INDEX(sequence); + struct iwl_tx_queue *txq = &priv->txq[txq_id]; + struct ieee80211_tx_status *tx_status; + struct iwl_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; + u32 status = le32_to_cpu(tx_resp->status); +#ifdef CONFIG_IWLWIFI_HT +#ifdef CONFIG_IWLWIFI_HT_AGG + int tid, sta_id; +#endif +#endif + + if ((index >= txq->q.n_bd) || (x2_queue_used(&txq->q, index) == 0)) { + IWL_ERROR("Read index for DMA queue txq_id (%d) index %d " + "is out of range [0-%d] %d %d\n", txq_id, + index, txq->q.n_bd, txq->q.first_empty, + txq->q.last_used); + return; + } + +#ifdef CONFIG_IWLWIFI_HT +#ifdef CONFIG_IWLWIFI_HT_AGG + if (txq->sched_retry) { + const u32 scd_ssn = iwl_get_scd_ssn(tx_resp); + struct ieee80211_hdr *hdr = + iwl_tx_queue_get_hdr(priv, txq_id, index); + struct iwl_ht_agg *agg = NULL; + __le16 *qc = ieee80211_get_qos_ctrl(hdr); + + if (qc == NULL) { + IWL_ERROR("BUG_ON qc is null!!!!\n"); + return; + } + + tid = le16_to_cpu(*qc) & 0xf; + + sta_id = iwl_get_ra_sta_id(priv, hdr); + if (unlikely(sta_id == IWL_INVALID_STATION)) { + IWL_ERROR("Station not known for\n"); + return; + } + + agg = &priv->stations[sta_id].tid[tid].agg; + + iwl4965_tx_status_reply_tx(priv, agg, tx_resp, index); + + if ((tx_resp->frame_count == 1) && + !iwl_is_tx_success(status)) { + /* TODO: send BAR */ + } + + if ((txq->q.last_used != (scd_ssn & 0xff))) { + index = iwl_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd); + IWL_DEBUG_TX_REPLY("Retry scheduler reclaim scd_ssn " + "%d index %d\n", scd_ssn , index); + iwl_tx_queue_reclaim(priv, txq_id, index); + } + } else { +#endif /* CONFIG_IWLWIFI_HT_AGG */ +#endif /* CONFIG_IWLWIFI_HT */ + tx_status = &(txq->txb[txq->q.last_used].status); + + tx_status->retry_count = tx_resp->failure_frame; + tx_status->queue_number = status; + tx_status->queue_length = tx_resp->bt_kill_count; + tx_status->queue_length |= tx_resp->failure_rts; + + tx_status->flags = + iwl_is_tx_success(status) ? IEEE80211_TX_STATUS_ACK : 0; + + tx_status->control.tx_rate = + iwl_hw_get_rate_n_flags(tx_resp->rate_n_flags); + + IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) rate_n_flags 0x%x " + "retries %d\n", txq_id, iwl_get_tx_fail_reason(status), + status, le32_to_cpu(tx_resp->rate_n_flags), + tx_resp->failure_frame); + + IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index); + if (index != -1) + iwl_tx_queue_reclaim(priv, txq_id, index); +#ifdef CONFIG_IWLWIFI_HT +#ifdef CONFIG_IWLWIFI_HT_AGG + } +#endif /* CONFIG_IWLWIFI_HT_AGG */ +#endif /* CONFIG_IWLWIFI_HT */ + + if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK)) + IWL_ERROR("TODO: Implement Tx ABORT REQUIRED!!!\n"); +} + + +static void iwl_rx_reply_alive(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_alive_resp *palive; + struct delayed_work *pwork; + + palive = &pkt->u.alive_frame; + + IWL_DEBUG_INFO("Alive ucode status 0x%08X revision " + "0x%01X 0x%01X\n", + palive->is_valid, palive->ver_type, + palive->ver_subtype); + + if (palive->ver_subtype == INITIALIZE_SUBTYPE) { + IWL_DEBUG_INFO("Initialization Alive received.\n"); + memcpy(&priv->card_alive_init, + &pkt->u.alive_frame, + sizeof(struct iwl_init_alive_resp)); + pwork = &priv->init_alive_start; + } else { + IWL_DEBUG_INFO("Runtime Alive received.\n"); + memcpy(&priv->card_alive, &pkt->u.alive_frame, + sizeof(struct iwl_alive_resp)); + pwork = &priv->alive_start; + } + + /* We delay the ALIVE response by 5ms to + * give the HW RF Kill time to activate... */ + if (palive->is_valid == UCODE_VALID_OK) + queue_delayed_work(priv->workqueue, pwork, + msecs_to_jiffies(5)); + else + IWL_WARNING("uCode did not respond OK.\n"); +} + +static void iwl_rx_reply_add_sta(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + + IWL_DEBUG_RX("Received REPLY_ADD_STA: 0x%02X\n", pkt->u.status); + return; +} + +static void iwl_rx_reply_error(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + + IWL_ERROR("Error Reply type 0x%08X cmd %s (0x%02X) " + "seq 0x%04X ser 0x%08X\n", + le32_to_cpu(pkt->u.err_resp.error_type), + get_cmd_string(pkt->u.err_resp.cmd_id), + pkt->u.err_resp.cmd_id, + le16_to_cpu(pkt->u.err_resp.bad_cmd_seq_num), + le32_to_cpu(pkt->u.err_resp.error_info)); +} + +#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x + +static void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon; + struct iwl_csa_notification *csa = &(pkt->u.csa_notif); + IWL_DEBUG_11H("CSA notif: channel %d, status %d\n", + le16_to_cpu(csa->channel), le32_to_cpu(csa->status)); + rxon->channel = csa->channel; + priv->staging_rxon.channel = csa->channel; +} + +static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ +#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_spectrum_notification *report = &(pkt->u.spectrum_notif); + + if (!report->state) { + IWL_DEBUG(IWL_DL_11H | IWL_DL_INFO, + "Spectrum Measure Notification: Start\n"); + return; + } + + memcpy(&priv->measure_report, report, sizeof(*report)); + priv->measurement_status |= MEASUREMENT_READY; +#endif +} + +static void iwl_rx_pm_sleep_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ +#ifdef CONFIG_IWLWIFI_DEBUG + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_sleep_notification *sleep = &(pkt->u.sleep_notif); + IWL_DEBUG_RX("sleep mode: %d, src: %d\n", + sleep->pm_sleep_mode, sleep->pm_wakeup_src); +#endif +} + +static void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + IWL_DEBUG_RADIO("Dumping %d bytes of unhandled " + "notification for %s:\n", + le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd)); + iwl_print_hex_dump(IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len)); +} + +static void iwl_bg_beacon_update(struct work_struct *work) +{ + struct iwl_priv *priv = + container_of(work, struct iwl_priv, beacon_update); + struct sk_buff *beacon; + + /* Pull updated AP beacon from mac80211. will fail if not in AP mode */ + beacon = ieee80211_beacon_get(priv->hw, priv->interface_id, NULL); + + if (!beacon) { + IWL_ERROR("update beacon failed\n"); + return; + } + + mutex_lock(&priv->mutex); + /* new beacon skb is allocated every time; dispose previous.*/ + if (priv->ibss_beacon) + dev_kfree_skb(priv->ibss_beacon); + + priv->ibss_beacon = beacon; + mutex_unlock(&priv->mutex); + + iwl_send_beacon_cmd(priv); +} + +static void iwl_rx_beacon_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ +#ifdef CONFIG_IWLWIFI_DEBUG + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_beacon_notif *beacon = &(pkt->u.beacon_status); + u8 rate = iwl_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags); + + IWL_DEBUG_RX("beacon status %x retries %d iss %d " + "tsf %d %d rate %d\n", + le32_to_cpu(beacon->beacon_notify_hdr.status) & TX_STATUS_MSK, + beacon->beacon_notify_hdr.failure_frame, + le32_to_cpu(beacon->ibss_mgr_status), + le32_to_cpu(beacon->high_tsf), + le32_to_cpu(beacon->low_tsf), rate); +#endif + + if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) && + (!test_bit(STATUS_EXIT_PENDING, &priv->status))) + queue_work(priv->workqueue, &priv->beacon_update); +} + +/* Service response to REPLY_SCAN_CMD (0x80) */ +static void iwl_rx_reply_scan(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ +#ifdef CONFIG_IWLWIFI_DEBUG + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_scanreq_notification *notif = + (struct iwl_scanreq_notification *)pkt->u.raw; + + IWL_DEBUG_RX("Scan request status = 0x%x\n", notif->status); +#endif +} + +/* Service SCAN_START_NOTIFICATION (0x82) */ +static void iwl_rx_scan_start_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_scanstart_notification *notif = + (struct iwl_scanstart_notification *)pkt->u.raw; + priv->scan_start_tsf = le32_to_cpu(notif->tsf_low); + IWL_DEBUG_SCAN("Scan start: " + "%d [802.11%s] " + "(TSF: 0x%08X:%08X) - %d (beacon timer %u)\n", + notif->channel, + notif->band ? "bg" : "a", + notif->tsf_high, + notif->tsf_low, notif->status, notif->beacon_timer); +} + +/* Service SCAN_RESULTS_NOTIFICATION (0x83) */ +static void iwl_rx_scan_results_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_scanresults_notification *notif = + (struct iwl_scanresults_notification *)pkt->u.raw; + + IWL_DEBUG_SCAN("Scan ch.res: " + "%d [802.11%s] " + "(TSF: 0x%08X:%08X) - %d " + "elapsed=%lu usec (%dms since last)\n", + notif->channel, + notif->band ? "bg" : "a", + le32_to_cpu(notif->tsf_high), + le32_to_cpu(notif->tsf_low), + le32_to_cpu(notif->statistics[0]), + le32_to_cpu(notif->tsf_low) - priv->scan_start_tsf, + jiffies_to_msecs(elapsed_jiffies + (priv->last_scan_jiffies, jiffies))); + + priv->last_scan_jiffies = jiffies; +} + +/* Service SCAN_COMPLETE_NOTIFICATION (0x84) */ +static void iwl_rx_scan_complete_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_scancomplete_notification *scan_notif = (void *)pkt->u.raw; + + IWL_DEBUG_SCAN("Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n", + scan_notif->scanned_channels, + scan_notif->tsf_low, + scan_notif->tsf_high, scan_notif->status); + + /* The HW is no longer scanning */ + clear_bit(STATUS_SCAN_HW, &priv->status); + + /* The scan completion notification came in, so kill that timer... */ + cancel_delayed_work(&priv->scan_check); + + IWL_DEBUG_INFO("Scan pass on %sGHz took %dms\n", + (priv->scan_bands == 2) ? "2.4" : "5.2", + jiffies_to_msecs(elapsed_jiffies + (priv->scan_pass_start, jiffies))); + + /* Remove this scanned band from the list + * of pending bands to scan */ + priv->scan_bands--; + + /* If a request to abort was given, or the scan did not succeed + * then we reset the scan state machine and terminate, + * re-queuing another scan if one has been requested */ + if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { + IWL_DEBUG_INFO("Aborted scan completed.\n"); + clear_bit(STATUS_SCAN_ABORTING, &priv->status); + } else { + /* If there are more bands on this scan pass reschedule */ + if (priv->scan_bands > 0) + goto reschedule; + } + + priv->last_scan_jiffies = jiffies; + IWL_DEBUG_INFO("Setting scan to off\n"); + + clear_bit(STATUS_SCANNING, &priv->status); + + IWL_DEBUG_INFO("Scan took %dms\n", + jiffies_to_msecs(elapsed_jiffies(priv->scan_start, jiffies))); + + queue_work(priv->workqueue, &priv->scan_completed); + + return; + +reschedule: + priv->scan_pass_start = jiffies; + queue_work(priv->workqueue, &priv->request_scan); +} + +/* Handle notification from uCode that card's power state is changing + * due to software, hardware, or critical temperature RFKILL */ +static void iwl_rx_card_state_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags); + unsigned long status = priv->status; + + IWL_DEBUG_RF_KILL("Card state received: HW:%s SW:%s\n", + (flags & HW_CARD_DISABLED) ? "Kill" : "On", + (flags & SW_CARD_DISABLED) ? "Kill" : "On"); + + if (flags & (SW_CARD_DISABLED | HW_CARD_DISABLED | + RF_CARD_DISABLED)) { + + iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, + CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); + + if (!iwl_grab_restricted_access(priv)) { + iwl_write_restricted( + priv, HBUS_TARG_MBX_C, + HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); + + iwl_release_restricted_access(priv); + } + + if (!(flags & RXON_CARD_DISABLED)) { + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, + CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); + if (!iwl_grab_restricted_access(priv)) { + iwl_write_restricted( + priv, HBUS_TARG_MBX_C, + HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); + + iwl_release_restricted_access(priv); + } + } + + if (flags & RF_CARD_DISABLED) { + iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, + CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); + iwl_read32(priv, CSR_UCODE_DRV_GP1); + if (!iwl_grab_restricted_access(priv)) + iwl_release_restricted_access(priv); + } + } + + if (flags & HW_CARD_DISABLED) + set_bit(STATUS_RF_KILL_HW, &priv->status); + else + clear_bit(STATUS_RF_KILL_HW, &priv->status); + + + if (flags & SW_CARD_DISABLED) + set_bit(STATUS_RF_KILL_SW, &priv->status); + else + clear_bit(STATUS_RF_KILL_SW, &priv->status); + + if (!(flags & RXON_CARD_DISABLED)) + iwl_scan_cancel(priv); + + if ((test_bit(STATUS_RF_KILL_HW, &status) != + test_bit(STATUS_RF_KILL_HW, &priv->status)) || + (test_bit(STATUS_RF_KILL_SW, &status) != + test_bit(STATUS_RF_KILL_SW, &priv->status))) + queue_work(priv->workqueue, &priv->rf_kill); + else + wake_up_interruptible(&priv->wait_command_queue); +} + +/** + * iwl_setup_rx_handlers - Initialize Rx handler callbacks + * + * Setup the RX handlers for each of the reply types sent from the uCode + * to the host. + * + * This function chains into the hardware specific files for them to setup + * any hardware specific handlers as well. + */ +static void iwl_setup_rx_handlers(struct iwl_priv *priv) +{ + priv->rx_handlers[REPLY_ALIVE] = iwl_rx_reply_alive; + priv->rx_handlers[REPLY_ADD_STA] = iwl_rx_reply_add_sta; + priv->rx_handlers[REPLY_ERROR] = iwl_rx_reply_error; + priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa; + priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] = + iwl_rx_spectrum_measure_notif; + priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl_rx_pm_sleep_notif; + priv->rx_handlers[PM_DEBUG_STATISTIC_NOTIFIC] = + iwl_rx_pm_debug_statistics_notif; + priv->rx_handlers[BEACON_NOTIFICATION] = iwl_rx_beacon_notif; + + /* NOTE: iwl_rx_statistics is different based on whether + * the build is for the 3945 or the 4965. See the + * corresponding implementation in iwl-XXXX.c + * + * The same handler is used for both the REPLY to a + * discrete statistics request from the host as well as + * for the periodic statistics notification from the uCode + */ + priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl_hw_rx_statistics; + priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl_hw_rx_statistics; + + priv->rx_handlers[REPLY_SCAN_CMD] = iwl_rx_reply_scan; + priv->rx_handlers[SCAN_START_NOTIFICATION] = iwl_rx_scan_start_notif; + priv->rx_handlers[SCAN_RESULTS_NOTIFICATION] = + iwl_rx_scan_results_notif; + priv->rx_handlers[SCAN_COMPLETE_NOTIFICATION] = + iwl_rx_scan_complete_notif; + priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl_rx_card_state_notif; + priv->rx_handlers[REPLY_TX] = iwl_rx_reply_tx; + + /* Setup hardware specific Rx handlers */ + iwl_hw_rx_handler_setup(priv); +} + +/** + * iwl_tx_cmd_complete - Pull unused buffers off the queue and reclaim them + * @rxb: Rx buffer to reclaim + * + * If an Rx buffer has an async callback associated with it the callback + * will be executed. The attached skb (if present) will only be freed + * if the callback returns 1 + */ +static void iwl_tx_cmd_complete(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + u16 sequence = le16_to_cpu(pkt->hdr.sequence); + int txq_id = SEQ_TO_QUEUE(sequence); + int index = SEQ_TO_INDEX(sequence); + int huge = sequence & SEQ_HUGE_FRAME; + int cmd_index; + struct iwl_cmd *cmd; + + /* If a Tx command is being handled and it isn't in the actual + * command queue then there a command routing bug has been introduced + * in the queue management code. */ + if (txq_id != IWL_CMD_QUEUE_NUM) + IWL_ERROR("Error wrong command queue %d command id 0x%X\n", + txq_id, pkt->hdr.cmd); + BUG_ON(txq_id != IWL_CMD_QUEUE_NUM); + + cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge); + cmd = &priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index]; + + /* Input error checking is done when commands are added to queue. */ + if (cmd->meta.flags & CMD_WANT_SKB) { + cmd->meta.source->u.skb = rxb->skb; + rxb->skb = NULL; + } else if (cmd->meta.u.callback && + !cmd->meta.u.callback(priv, cmd, rxb->skb)) + rxb->skb = NULL; + + iwl_tx_queue_reclaim(priv, txq_id, index); + + if (!(cmd->meta.flags & CMD_ASYNC)) { + clear_bit(STATUS_HCMD_ACTIVE, &priv->status); + wake_up_interruptible(&priv->wait_command_queue); + } +} + +/************************** RX-FUNCTIONS ****************************/ +/* + * Rx theory of operation + * + * The host allocates 32 DMA target addresses and passes the host address + * to the firmware at register IWL_RFDS_TABLE_LOWER + N * RFD_SIZE where N is + * 0 to 31 + * + * Rx Queue Indexes + * The host/firmware share two index registers for managing the Rx buffers. + * + * The READ index maps to the first position that the firmware may be writing + * to -- the driver can read up to (but not including) this position and get + * good data. + * The READ index is managed by the firmware once the card is enabled. + * + * The WRITE index maps to the last position the driver has read from -- the + * position preceding WRITE is the last slot the firmware can place a packet. + * + * The queue is empty (no good data) if WRITE = READ - 1, and is full if + * WRITE = READ. + * + * During initialization the host sets up the READ queue position to the first + * INDEX position, and WRITE to the last (READ - 1 wrapped) + * + * When the firmware places a packet in a buffer it will advance the READ index + * and fire the RX interrupt. The driver can then query the READ index and + * process as many packets as possible, moving the WRITE index forward as it + * resets the Rx queue buffers with new memory. + * + * The management in the driver is as follows: + * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free. When + * iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled + * to replensish the iwl->rxq->rx_free. + * + In iwl_rx_replenish (scheduled) if 'processed' != 'read' then the + * iwl->rxq is replenished and the READ INDEX is updated (updating the + * 'processed' and 'read' driver indexes as well) + * + A received packet is processed and handed to the kernel network stack, + * detached from the iwl->rxq. The driver 'processed' index is updated. + * + The Host/Firmware iwl->rxq is replenished at tasklet time from the rx_free + * list. If there are no allocated buffers in iwl->rxq->rx_free, the READ + * INDEX is not incremented and iwl->status(RX_STALLED) is set. If there + * were enough free buffers and RX_STALLED is set it is cleared. + * + * + * Driver sequence: + * + * iwl_rx_queue_alloc() Allocates rx_free + * iwl_rx_replenish() Replenishes rx_free list from rx_used, and calls + * iwl_rx_queue_restock + * iwl_rx_queue_restock() Moves available buffers from rx_free into Rx + * queue, updates firmware pointers, and updates + * the WRITE index. If insufficient rx_free buffers + * are available, schedules iwl_rx_replenish + * + * -- enable interrupts -- + * ISR - iwl_rx() Detach iwl_rx_mem_buffers from pool up to the + * READ INDEX, detaching the SKB from the pool. + * Moves the packet buffer from queue to rx_used. + * Calls iwl_rx_queue_restock to refill any empty + * slots. + * ... + * + */ + +/** + * iwl_rx_queue_space - Return number of free slots available in queue. + */ +static int iwl_rx_queue_space(const struct iwl_rx_queue *q) +{ + int s = q->read - q->write; + if (s <= 0) + s += RX_QUEUE_SIZE; + /* keep some buffer to not confuse full and empty queue */ + s -= 2; + if (s < 0) + s = 0; + return s; +} + +/** + * iwl_rx_queue_update_write_ptr - Update the write pointer for the RX queue + * + * NOTE: This function has 3945 and 4965 specific code sections + * but is declared in base due to the majority of the + * implementation being the same (only a numeric constant is + * different) + * + */ +int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q) +{ + u32 reg = 0; + int rc = 0; + unsigned long flags; + + spin_lock_irqsave(&q->lock, flags); + + if (q->need_update == 0) + goto exit_unlock; + + if (test_bit(STATUS_POWER_PMI, &priv->status)) { + reg = iwl_read32(priv, CSR_UCODE_DRV_GP1); + + if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { + iwl_set_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + goto exit_unlock; + } + + rc = iwl_grab_restricted_access(priv); + if (rc) + goto exit_unlock; + + iwl_write_restricted(priv, FH_RSCSR_CHNL0_WPTR, + q->write & ~0x7); + iwl_release_restricted_access(priv); + } else + iwl_write32(priv, FH_RSCSR_CHNL0_WPTR, q->write & ~0x7); + + + q->need_update = 0; + + exit_unlock: + spin_unlock_irqrestore(&q->lock, flags); + return rc; +} + +/** + * iwl_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer pointer. + * + * NOTE: This function has 3945 and 4965 specific code paths in it. + */ +static inline __le32 iwl_dma_addr2rbd_ptr(struct iwl_priv *priv, + dma_addr_t dma_addr) +{ + return cpu_to_le32((u32)(dma_addr >> 8)); +} + + +/** + * iwl_rx_queue_restock - refill RX queue from pre-allocated pool + * + * If there are slots in the RX queue that need to be restocked, + * and we have free pre-allocated buffers, fill the ranks as much + * as we can pulling from rx_free. + * + * This moves the 'write' index forward to catch up with 'processed', and + * also updates the memory address in the firmware to reference the new + * target buffer. + */ +int iwl_rx_queue_restock(struct iwl_priv *priv) +{ + struct iwl_rx_queue *rxq = &priv->rxq; + struct list_head *element; + struct iwl_rx_mem_buffer *rxb; + unsigned long flags; + int write, rc; + + spin_lock_irqsave(&rxq->lock, flags); + write = rxq->write & ~0x7; + while ((iwl_rx_queue_space(rxq) > 0) && (rxq->free_count)) { + element = rxq->rx_free.next; + rxb = list_entry(element, struct iwl_rx_mem_buffer, list); + list_del(element); + rxq->bd[rxq->write] = iwl_dma_addr2rbd_ptr(priv, rxb->dma_addr); + rxq->queue[rxq->write] = rxb; + rxq->write = (rxq->write + 1) & RX_QUEUE_MASK; + rxq->free_count--; + } + spin_unlock_irqrestore(&rxq->lock, flags); + /* If the pre-allocated buffer pool is dropping low, schedule to + * refill it */ + if (rxq->free_count <= RX_LOW_WATERMARK) + queue_work(priv->workqueue, &priv->rx_replenish); + + + /* If we've added more space for the firmware to place data, tell it */ + if ((write != (rxq->write & ~0x7)) + || (abs(rxq->write - rxq->read) > 7)) { + spin_lock_irqsave(&rxq->lock, flags); + rxq->need_update = 1; + spin_unlock_irqrestore(&rxq->lock, flags); + rc = iwl_rx_queue_update_write_ptr(priv, rxq); + if (rc) + return rc; + } + + return 0; +} + +/** + * iwl_rx_replensih - Move all used packet from rx_used to rx_free + * + * When moving to rx_free an SKB is allocated for the slot. + * + * Also restock the Rx queue via iwl_rx_queue_restock. + * This is called as a scheduled work item (except for during intialization) + */ +void iwl_rx_replenish(void *data) +{ + struct iwl_priv *priv = data; + struct iwl_rx_queue *rxq = &priv->rxq; + struct list_head *element; + struct iwl_rx_mem_buffer *rxb; + unsigned long flags; + spin_lock_irqsave(&rxq->lock, flags); + while (!list_empty(&rxq->rx_used)) { + element = rxq->rx_used.next; + rxb = list_entry(element, struct iwl_rx_mem_buffer, list); + rxb->skb = + alloc_skb(IWL_RX_BUF_SIZE, __GFP_NOWARN | GFP_ATOMIC); + if (!rxb->skb) { + if (net_ratelimit()) + printk(KERN_CRIT DRV_NAME + ": Can not allocate SKB buffers\n"); + /* We don't reschedule replenish work here -- we will + * call the restock method and if it still needs + * more buffers it will schedule replenish */ + break; + } + priv->alloc_rxb_skb++; + list_del(element); + rxb->dma_addr = + pci_map_single(priv->pci_dev, rxb->skb->data, + IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + list_add_tail(&rxb->list, &rxq->rx_free); + rxq->free_count++; + } + spin_unlock_irqrestore(&rxq->lock, flags); + + spin_lock_irqsave(&priv->lock, flags); + iwl_rx_queue_restock(priv); + spin_unlock_irqrestore(&priv->lock, flags); +} + +/* Assumes that the skb field of the buffers in 'pool' is kept accurate. + * If an SKB has been detached, the POOL needs to have it's SKB set to NULL + * This free routine walks the list of POOL entries and if SKB is set to + * non NULL it is unmapped and freed + */ +void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq) +{ + int i; + for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) { + if (rxq->pool[i].skb != NULL) { + pci_unmap_single(priv->pci_dev, + rxq->pool[i].dma_addr, + IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + dev_kfree_skb(rxq->pool[i].skb); + } + } + + pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd, + rxq->dma_addr); + rxq->bd = NULL; +} + +int iwl_rx_queue_alloc(struct iwl_priv *priv) +{ + struct iwl_rx_queue *rxq = &priv->rxq; + struct pci_dev *dev = priv->pci_dev; + int i; + + spin_lock_init(&rxq->lock); + INIT_LIST_HEAD(&rxq->rx_free); + INIT_LIST_HEAD(&rxq->rx_used); + rxq->bd = pci_alloc_consistent(dev, 4 * RX_QUEUE_SIZE, &rxq->dma_addr); + if (!rxq->bd) + return -ENOMEM; + /* Fill the rx_used queue with _all_ of the Rx buffers */ + for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) + list_add_tail(&rxq->pool[i].list, &rxq->rx_used); + /* Set us so that we have processed and used all buffers, but have + * not restocked the Rx queue with fresh buffers */ + rxq->read = rxq->write = 0; + rxq->free_count = 0; + rxq->need_update = 0; + return 0; +} + +void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq) +{ + unsigned long flags; + int i; + spin_lock_irqsave(&rxq->lock, flags); + INIT_LIST_HEAD(&rxq->rx_free); + INIT_LIST_HEAD(&rxq->rx_used); + /* Fill the rx_used queue with _all_ of the Rx buffers */ + for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) { + /* In the reset function, these buffers may have been allocated + * to an SKB, so we need to unmap and free potential storage */ + if (rxq->pool[i].skb != NULL) { + pci_unmap_single(priv->pci_dev, + rxq->pool[i].dma_addr, + IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + priv->alloc_rxb_skb--; + dev_kfree_skb(rxq->pool[i].skb); + rxq->pool[i].skb = NULL; + } + list_add_tail(&rxq->pool[i].list, &rxq->rx_used); + } + + /* Set us so that we have processed and used all buffers, but have + * not restocked the Rx queue with fresh buffers */ + rxq->read = rxq->write = 0; + rxq->free_count = 0; + spin_unlock_irqrestore(&rxq->lock, flags); +} + +/* Convert linear signal-to-noise ratio into dB */ +static u8 ratio2dB[100] = { +/* 0 1 2 3 4 5 6 7 8 9 */ + 0, 0, 6, 10, 12, 14, 16, 17, 18, 19, /* 00 - 09 */ + 20, 21, 22, 22, 23, 23, 24, 25, 26, 26, /* 10 - 19 */ + 26, 26, 26, 27, 27, 28, 28, 28, 29, 29, /* 20 - 29 */ + 29, 30, 30, 30, 31, 31, 31, 31, 32, 32, /* 30 - 39 */ + 32, 32, 32, 33, 33, 33, 33, 33, 34, 34, /* 40 - 49 */ + 34, 34, 34, 34, 35, 35, 35, 35, 35, 35, /* 50 - 59 */ + 36, 36, 36, 36, 36, 36, 36, 37, 37, 37, /* 60 - 69 */ + 37, 37, 37, 37, 37, 38, 38, 38, 38, 38, /* 70 - 79 */ + 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, /* 80 - 89 */ + 39, 39, 39, 39, 39, 40, 40, 40, 40, 40 /* 90 - 99 */ +}; + +/* Calculates a relative dB value from a ratio of linear + * (i.e. not dB) signal levels. + * Conversion assumes that levels are voltages (20*log), not powers (10*log). */ +int iwl_calc_db_from_ratio(int sig_ratio) +{ + /* Anything above 1000:1 just report as 60 dB */ + if (sig_ratio > 1000) + return 60; + + /* Above 100:1, divide by 10 and use table, + * add 20 dB to make up for divide by 10 */ + if (sig_ratio > 100) + return (20 + (int)ratio2dB[sig_ratio/10]); + + /* We shouldn't see this */ + if (sig_ratio < 1) + return 0; + + /* Use table for ratios 1:1 - 99:1 */ + return (int)ratio2dB[sig_ratio]; +} + +#define PERFECT_RSSI (-20) /* dBm */ +#define WORST_RSSI (-95) /* dBm */ +#define RSSI_RANGE (PERFECT_RSSI - WORST_RSSI) + +/* Calculate an indication of rx signal quality (a percentage, not dBm!). + * See http://www.ces.clemson.edu/linux/signal_quality.shtml for info + * about formulas used below. */ +int iwl_calc_sig_qual(int rssi_dbm, int noise_dbm) +{ + int sig_qual; + int degradation = PERFECT_RSSI - rssi_dbm; + + /* If we get a noise measurement, use signal-to-noise ratio (SNR) + * as indicator; formula is (signal dbm - noise dbm). + * SNR at or above 40 is a great signal (100%). + * Below that, scale to fit SNR of 0 - 40 dB within 0 - 100% indicator. + * Weakest usable signal is usually 10 - 15 dB SNR. */ + if (noise_dbm) { + if (rssi_dbm - noise_dbm >= 40) + return 100; + else if (rssi_dbm < noise_dbm) + return 0; + sig_qual = ((rssi_dbm - noise_dbm) * 5) / 2; + + /* Else use just the signal level. + * This formula is a least squares fit of data points collected and + * compared with a reference system that had a percentage (%) display + * for signal quality. */ + } else + sig_qual = (100 * (RSSI_RANGE * RSSI_RANGE) - degradation * + (15 * RSSI_RANGE + 62 * degradation)) / + (RSSI_RANGE * RSSI_RANGE); + + if (sig_qual > 100) + sig_qual = 100; + else if (sig_qual < 1) + sig_qual = 0; + + return sig_qual; +} + +/** + * iwl_rx_handle - Main entry function for receiving responses from the uCode + * + * Uses the priv->rx_handlers callback function array to invoke + * the appropriate handlers, including command responses, + * frame-received notifications, and other notifications. + */ +static void iwl_rx_handle(struct iwl_priv *priv) +{ + struct iwl_rx_mem_buffer *rxb; + struct iwl_rx_packet *pkt; + struct iwl_rx_queue *rxq = &priv->rxq; + u32 r, i; + int reclaim; + unsigned long flags; + + r = iwl_hw_get_rx_read(priv); + i = rxq->read; + + /* Rx interrupt, but nothing sent from uCode */ + if (i == r) + IWL_DEBUG(IWL_DL_RX | IWL_DL_ISR, "r = %d, i = %d\n", r, i); + + while (i != r) { + rxb = rxq->queue[i]; + + /* If an RXB doesn't have a queue slot associated with it + * then a bug has been introduced in the queue refilling + * routines -- catch it here */ + BUG_ON(rxb == NULL); + + rxq->queue[i] = NULL; + + pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr, + IWL_RX_BUF_SIZE, + PCI_DMA_FROMDEVICE); + pkt = (struct iwl_rx_packet *)rxb->skb->data; + + /* Reclaim a command buffer only if this packet is a response + * to a (driver-originated) command. + * If the packet (e.g. Rx frame) originated from uCode, + * there is no command buffer to reclaim. + * Ucode should set SEQ_RX_FRAME bit if ucode-originated, + * but apparently a few don't get set; catch them here. */ + reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) && + (pkt->hdr.cmd != REPLY_RX_PHY_CMD) && + (pkt->hdr.cmd != REPLY_4965_RX) && + (pkt->hdr.cmd != STATISTICS_NOTIFICATION) && + (pkt->hdr.cmd != REPLY_TX); + + /* Based on type of command response or notification, + * handle those that need handling via function in + * rx_handlers table. See iwl_setup_rx_handlers() */ + if (priv->rx_handlers[pkt->hdr.cmd]) { + IWL_DEBUG(IWL_DL_HOST_COMMAND | IWL_DL_RX | IWL_DL_ISR, + "r = %d, i = %d, %s, 0x%02x\n", r, i, + get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); + priv->rx_handlers[pkt->hdr.cmd] (priv, rxb); + } else { + /* No handling needed */ + IWL_DEBUG(IWL_DL_HOST_COMMAND | IWL_DL_RX | IWL_DL_ISR, + "r %d i %d No handler needed for %s, 0x%02x\n", + r, i, get_cmd_string(pkt->hdr.cmd), + pkt->hdr.cmd); + } + + if (reclaim) { + /* Invoke any callbacks, transfer the skb to caller, + * and fire off the (possibly) blocking iwl_send_cmd() + * as we reclaim the driver command queue */ + if (rxb && rxb->skb) + iwl_tx_cmd_complete(priv, rxb); + else + IWL_WARNING("Claim null rxb?\n"); + } + + /* For now we just don't re-use anything. We can tweak this + * later to try and re-use notification packets and SKBs that + * fail to Rx correctly */ + if (rxb->skb != NULL) { + priv->alloc_rxb_skb--; + dev_kfree_skb_any(rxb->skb); + rxb->skb = NULL; + } + + pci_unmap_single(priv->pci_dev, rxb->dma_addr, + IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + spin_lock_irqsave(&rxq->lock, flags); + list_add_tail(&rxb->list, &priv->rxq.rx_used); + spin_unlock_irqrestore(&rxq->lock, flags); + i = (i + 1) & RX_QUEUE_MASK; + } + + /* Backtrack one entry */ + priv->rxq.read = i; + iwl_rx_queue_restock(priv); +} + +int iwl_tx_queue_update_write_ptr(struct iwl_priv *priv, + struct iwl_tx_queue *txq) +{ + u32 reg = 0; + int rc = 0; + int txq_id = txq->q.id; + + if (txq->need_update == 0) + return rc; + + /* if we're trying to save power */ + if (test_bit(STATUS_POWER_PMI, &priv->status)) { + /* wake up nic if it's powered down ... + * uCode will wake up, and interrupt us again, so next + * time we'll skip this part. */ + reg = iwl_read32(priv, CSR_UCODE_DRV_GP1); + + if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { + IWL_DEBUG_INFO("Requesting wakeup, GP1 = 0x%x\n", reg); + iwl_set_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + return rc; + } + + /* restore this queue's parameters in nic hardware. */ + rc = iwl_grab_restricted_access(priv); + if (rc) + return rc; + iwl_write_restricted(priv, HBUS_TARG_WRPTR, + txq->q.first_empty | (txq_id << 8)); + iwl_release_restricted_access(priv); + + /* else not in power-save mode, uCode will never sleep when we're + * trying to tx (during RFKILL, we're not trying to tx). */ + } else + iwl_write32(priv, HBUS_TARG_WRPTR, + txq->q.first_empty | (txq_id << 8)); + + txq->need_update = 0; + + return rc; +} + +#ifdef CONFIG_IWLWIFI_DEBUG +static void iwl_print_rx_config_cmd(struct iwl_rxon_cmd *rxon) +{ + IWL_DEBUG_RADIO("RX CONFIG:\n"); + iwl_print_hex_dump(IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon)); + IWL_DEBUG_RADIO("u16 channel: 0x%x\n", le16_to_cpu(rxon->channel)); + IWL_DEBUG_RADIO("u32 flags: 0x%08X\n", le32_to_cpu(rxon->flags)); + IWL_DEBUG_RADIO("u32 filter_flags: 0x%08x\n", + le32_to_cpu(rxon->filter_flags)); + IWL_DEBUG_RADIO("u8 dev_type: 0x%x\n", rxon->dev_type); + IWL_DEBUG_RADIO("u8 ofdm_basic_rates: 0x%02x\n", + rxon->ofdm_basic_rates); + IWL_DEBUG_RADIO("u8 cck_basic_rates: 0x%02x\n", rxon->cck_basic_rates); + IWL_DEBUG_RADIO("u8[6] node_addr: " MAC_FMT "\n", + MAC_ARG(rxon->node_addr)); + IWL_DEBUG_RADIO("u8[6] bssid_addr: " MAC_FMT "\n", + MAC_ARG(rxon->bssid_addr)); + IWL_DEBUG_RADIO("u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id)); +} +#endif + +static void iwl_enable_interrupts(struct iwl_priv *priv) +{ + IWL_DEBUG_ISR("Enabling interrupts\n"); + set_bit(STATUS_INT_ENABLED, &priv->status); + iwl_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK); +} + +static inline void iwl_disable_interrupts(struct iwl_priv *priv) +{ + clear_bit(STATUS_INT_ENABLED, &priv->status); + + /* disable interrupts from uCode/NIC to host */ + iwl_write32(priv, CSR_INT_MASK, 0x00000000); + + /* acknowledge/clear/reset any interrupts still pending + * from uCode or flow handler (Rx/Tx DMA) */ + iwl_write32(priv, CSR_INT, 0xffffffff); + iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff); + IWL_DEBUG_ISR("Disabled interrupts\n"); +} + +static const char *desc_lookup(int i) +{ + switch (i) { + case 1: + return "FAIL"; + case 2: + return "BAD_PARAM"; + case 3: + return "BAD_CHECKSUM"; + case 4: + return "NMI_INTERRUPT"; + case 5: + return "SYSASSERT"; + case 6: + return "FATAL_ERROR"; + } + + return "UNKNOWN"; +} + +#define ERROR_START_OFFSET (1 * sizeof(u32)) +#define ERROR_ELEM_SIZE (7 * sizeof(u32)) + +static void iwl_dump_nic_error_log(struct iwl_priv *priv) +{ + u32 data2, line; + u32 desc, time, count, base, data1; + u32 blink1, blink2, ilink1, ilink2; + int rc; + + base = le32_to_cpu(priv->card_alive.error_event_table_ptr); + + if (!iwl_hw_valid_rtc_data_addr(base)) { + IWL_ERROR("Not valid error log pointer 0x%08X\n", base); + return; + } + + rc = iwl_grab_restricted_access(priv); + if (rc) { + IWL_WARNING("Can not read from adapter at this time.\n"); + return; + } + + count = iwl_read_restricted_mem(priv, base); + + if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) { + IWL_ERROR("Start IWL Error Log Dump:\n"); + IWL_ERROR("Status: 0x%08lX, Config: %08X count: %d\n", + priv->status, priv->config, count); + } + + desc = iwl_read_restricted_mem(priv, base + 1 * sizeof(u32)); + blink1 = iwl_read_restricted_mem(priv, base + 3 * sizeof(u32)); + blink2 = iwl_read_restricted_mem(priv, base + 4 * sizeof(u32)); + ilink1 = iwl_read_restricted_mem(priv, base + 5 * sizeof(u32)); + ilink2 = iwl_read_restricted_mem(priv, base + 6 * sizeof(u32)); + data1 = iwl_read_restricted_mem(priv, base + 7 * sizeof(u32)); + data2 = iwl_read_restricted_mem(priv, base + 8 * sizeof(u32)); + line = iwl_read_restricted_mem(priv, base + 9 * sizeof(u32)); + time = iwl_read_restricted_mem(priv, base + 11 * sizeof(u32)); + + IWL_ERROR("Desc Time " + "data1 data2 line\n"); + IWL_ERROR("%-13s (#%d) %010u 0x%08X 0x%08X %u\n", + desc_lookup(desc), desc, time, data1, data2, line); + IWL_ERROR("blink1 blink2 ilink1 ilink2\n"); + IWL_ERROR("0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2, + ilink1, ilink2); + + iwl_release_restricted_access(priv); +} + +#define EVENT_START_OFFSET (4 * sizeof(u32)) + +/** + * iwl_print_event_log - Dump error event log to syslog + * + * NOTE: Must be called with iwl_grab_restricted_access() already obtained! + */ +static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, + u32 num_events, u32 mode) +{ + u32 i; + u32 base; /* SRAM byte address of event log header */ + u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */ + u32 ptr; /* SRAM byte address of log data */ + u32 ev, time, data; /* event log data */ + + if (num_events == 0) + return; + + base = le32_to_cpu(priv->card_alive.log_event_table_ptr); + + if (mode == 0) + event_size = 2 * sizeof(u32); + else + event_size = 3 * sizeof(u32); + + ptr = base + EVENT_START_OFFSET + (start_idx * event_size); + + /* "time" is actually "data" for mode 0 (no timestamp). + * place event id # at far right for easier visual parsing. */ + for (i = 0; i < num_events; i++) { + ev = iwl_read_restricted_mem(priv, ptr); + ptr += sizeof(u32); + time = iwl_read_restricted_mem(priv, ptr); + ptr += sizeof(u32); + if (mode == 0) + IWL_ERROR("0x%08x\t%04u\n", time, ev); /* data, ev */ + else { + data = iwl_read_restricted_mem(priv, ptr); + ptr += sizeof(u32); + IWL_ERROR("%010u\t0x%08x\t%04u\n", time, data, ev); + } + } +} + +static void iwl_dump_nic_event_log(struct iwl_priv *priv) +{ + int rc; + u32 base; /* SRAM byte address of event log header */ + u32 capacity; /* event log capacity in # entries */ + u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */ + u32 num_wraps; /* # times uCode wrapped to top of log */ + u32 next_entry; /* index of next entry to be written by uCode */ + u32 size; /* # entries that we'll print */ + + base = le32_to_cpu(priv->card_alive.log_event_table_ptr); + if (!iwl_hw_valid_rtc_data_addr(base)) { + IWL_ERROR("Invalid event log pointer 0x%08X\n", base); + return; + } + + rc = iwl_grab_restricted_access(priv); + if (rc) { + IWL_WARNING("Can not read from adapter at this time.\n"); + return; + } + + /* event log header */ + capacity = iwl_read_restricted_mem(priv, base); + mode = iwl_read_restricted_mem(priv, base + (1 * sizeof(u32))); + num_wraps = iwl_read_restricted_mem(priv, base + (2 * sizeof(u32))); + next_entry = iwl_read_restricted_mem(priv, base + (3 * sizeof(u32))); + + size = num_wraps ? capacity : next_entry; + + /* bail out if nothing in log */ + if (size == 0) { + IWL_ERROR("Start IPW Event Log Dump: nothing in log\n"); + iwl_release_restricted_access(priv); + return; + } + + IWL_ERROR("Start IPW Event Log Dump: display count %d, wraps %d\n", + size, num_wraps); + + /* if uCode has wrapped back to top of log, start at the oldest entry, + * i.e the next one that uCode would fill. */ + if (num_wraps) + iwl_print_event_log(priv, next_entry, + capacity - next_entry, mode); + + /* (then/else) start at top of log */ + iwl_print_event_log(priv, 0, next_entry, mode); + + iwl_release_restricted_access(priv); +} + +/** + * iwl_irq_handle_error - called for HW or SW error interrupt from card + */ +static void iwl_irq_handle_error(struct iwl_priv *priv) +{ + /* Set the FW error flag -- cleared on iwl_down */ + set_bit(STATUS_FW_ERROR, &priv->status); + + /* Cancel currently queued command. */ + clear_bit(STATUS_HCMD_ACTIVE, &priv->status); + +#ifdef CONFIG_IWLWIFI_DEBUG + if (iwl_debug_level & IWL_DL_FW_ERRORS) { + iwl_dump_nic_error_log(priv); + iwl_dump_nic_event_log(priv); + iwl_print_rx_config_cmd(&priv->staging_rxon); + } +#endif + + wake_up_interruptible(&priv->wait_command_queue); + + /* Keep the restart process from trying to send host + * commands by clearing the INIT status bit */ + clear_bit(STATUS_READY, &priv->status); + + if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) { + IWL_DEBUG(IWL_DL_INFO | IWL_DL_FW_ERRORS, + "Restarting adapter due to uCode error.\n"); + + if (iwl_is_associated(priv)) { + memcpy(&priv->recovery_rxon, &priv->active_rxon, + sizeof(priv->recovery_rxon)); + priv->error_recovering = 1; + } + queue_work(priv->workqueue, &priv->restart); + } +} + +static void iwl_error_recovery(struct iwl_priv *priv) +{ + unsigned long flags; + + memcpy(&priv->staging_rxon, &priv->recovery_rxon, + sizeof(priv->staging_rxon)); + priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; + iwl_commit_rxon(priv); + + iwl_rxon_add_station(priv, priv->bssid, 1); + + spin_lock_irqsave(&priv->lock, flags); + priv->assoc_id = le16_to_cpu(priv->staging_rxon.assoc_id); + priv->error_recovering = 0; + spin_unlock_irqrestore(&priv->lock, flags); +} + +static void iwl_irq_tasklet(struct iwl_priv *priv) +{ + u32 inta, handled = 0; + u32 inta_fh; + unsigned long flags; +#ifdef CONFIG_IWLWIFI_DEBUG + u32 inta_mask; +#endif + + spin_lock_irqsave(&priv->lock, flags); + + /* Ack/clear/reset pending uCode interrupts. + * Note: Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS, + * and will clear only when CSR_FH_INT_STATUS gets cleared. */ + inta = iwl_read32(priv, CSR_INT); + iwl_write32(priv, CSR_INT, inta); + + /* Ack/clear/reset pending flow-handler (DMA) interrupts. + * Any new interrupts that happen after this, either while we're + * in this tasklet, or later, will show up in next ISR/tasklet. */ + inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); + iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh); + +#ifdef CONFIG_IWLWIFI_DEBUG + if (iwl_debug_level & IWL_DL_ISR) { + inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */ + IWL_DEBUG_ISR("inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", + inta, inta_mask, inta_fh); + } +#endif + + /* Since CSR_INT and CSR_FH_INT_STATUS reads and clears are not + * atomic, make sure that inta covers all the interrupts that + * we've discovered, even if FH interrupt came in just after + * reading CSR_INT. */ + if (inta_fh & CSR_FH_INT_RX_MASK) + inta |= CSR_INT_BIT_FH_RX; + if (inta_fh & CSR_FH_INT_TX_MASK) + inta |= CSR_INT_BIT_FH_TX; + + /* Now service all interrupt bits discovered above. */ + if (inta & CSR_INT_BIT_HW_ERR) { + IWL_ERROR("Microcode HW error detected. Restarting.\n"); + + /* Tell the device to stop sending interrupts */ + iwl_disable_interrupts(priv); + + iwl_irq_handle_error(priv); + + handled |= CSR_INT_BIT_HW_ERR; + + spin_unlock_irqrestore(&priv->lock, flags); + + return; + } + +#ifdef CONFIG_IWLWIFI_DEBUG + if (iwl_debug_level & (IWL_DL_ISR)) { + /* NIC fires this, but we don't use it, redundant with WAKEUP */ + if (inta & CSR_INT_BIT_MAC_CLK_ACTV) + IWL_DEBUG_ISR("Microcode started or stopped.\n"); + + /* Alive notification via Rx interrupt will do the real work */ + if (inta & CSR_INT_BIT_ALIVE) + IWL_DEBUG_ISR("Alive interrupt\n"); + } +#endif + /* Safely ignore these bits for debug checks below */ + inta &= ~(CSR_INT_BIT_MAC_CLK_ACTV | CSR_INT_BIT_ALIVE); + + /* HW RF KILL switch toggled (4965 only) */ + if (inta & CSR_INT_BIT_RF_KILL) { + int hw_rf_kill = 0; + if (!(iwl_read32(priv, CSR_GP_CNTRL) & + CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) + hw_rf_kill = 1; + + IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL | IWL_DL_ISR, + "RF_KILL bit toggled to %s.\n", + hw_rf_kill ? "disable radio":"enable radio"); + + /* Queue restart only if RF_KILL switch was set to "kill" + * when we loaded driver, and is now set to "enable". + * After we're Alive, RF_KILL gets handled by + * iwl_rx_card_state_notif() */ + if (!hw_rf_kill && !test_bit(STATUS_ALIVE, &priv->status)) + queue_work(priv->workqueue, &priv->restart); + + handled |= CSR_INT_BIT_RF_KILL; + } + + /* Chip got too hot and stopped itself (4965 only) */ + if (inta & CSR_INT_BIT_CT_KILL) { + IWL_ERROR("Microcode CT kill error detected.\n"); + handled |= CSR_INT_BIT_CT_KILL; + } + + /* Error detected by uCode */ + if (inta & CSR_INT_BIT_SW_ERR) { + IWL_ERROR("Microcode SW error detected. Restarting 0x%X.\n", + inta); + iwl_irq_handle_error(priv); + handled |= CSR_INT_BIT_SW_ERR; + } + + /* uCode wakes up after power-down sleep */ + if (inta & CSR_INT_BIT_WAKEUP) { + IWL_DEBUG_ISR("Wakeup interrupt\n"); + iwl_rx_queue_update_write_ptr(priv, &priv->rxq); + iwl_tx_queue_update_write_ptr(priv, &priv->txq[0]); + iwl_tx_queue_update_write_ptr(priv, &priv->txq[1]); + iwl_tx_queue_update_write_ptr(priv, &priv->txq[2]); + iwl_tx_queue_update_write_ptr(priv, &priv->txq[3]); + iwl_tx_queue_update_write_ptr(priv, &priv->txq[4]); + iwl_tx_queue_update_write_ptr(priv, &priv->txq[5]); + + handled |= CSR_INT_BIT_WAKEUP; + } + + /* All uCode command responses, including Tx command responses, + * Rx "responses" (frame-received notification), and other + * notifications from uCode come through here*/ + if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) { + iwl_rx_handle(priv); + handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX); + } + + if (inta & CSR_INT_BIT_FH_TX) { + IWL_DEBUG_ISR("Tx interrupt\n"); + handled |= CSR_INT_BIT_FH_TX; + } + + if (inta & ~handled) + IWL_ERROR("Unhandled INTA bits 0x%08x\n", inta & ~handled); + + if (inta & ~CSR_INI_SET_MASK) { + IWL_WARNING("Disabled INTA bits 0x%08x were pending\n", + inta & ~CSR_INI_SET_MASK); + IWL_WARNING(" with FH_INT = 0x%08x\n", inta_fh); + } + + /* Re-enable all interrupts */ + iwl_enable_interrupts(priv); + +#ifdef CONFIG_IWLWIFI_DEBUG + if (iwl_debug_level & (IWL_DL_ISR)) { + inta = iwl_read32(priv, CSR_INT); + inta_mask = iwl_read32(priv, CSR_INT_MASK); + inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); + IWL_DEBUG_ISR("End inta 0x%08x, enabled 0x%08x, fh 0x%08x, " + "flags 0x%08lx\n", inta, inta_mask, inta_fh, flags); + } +#endif + spin_unlock_irqrestore(&priv->lock, flags); +} + +static irqreturn_t iwl_isr(int irq, void *data) +{ + struct iwl_priv *priv = data; + u32 inta, inta_mask; + u32 inta_fh; + if (!priv) + return IRQ_NONE; + + spin_lock(&priv->lock); + + /* Disable (but don't clear!) interrupts here to avoid + * back-to-back ISRs and sporadic interrupts from our NIC. + * If we have something to service, the tasklet will re-enable ints. + * If we *don't* have something, we'll re-enable before leaving here. */ + inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */ + iwl_write32(priv, CSR_INT_MASK, 0x00000000); + + /* Discover which interrupts are active/pending */ + inta = iwl_read32(priv, CSR_INT); + inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); + + /* Ignore interrupt if there's nothing in NIC to service. + * This may be due to IRQ shared with another device, + * or due to sporadic interrupts thrown from our NIC. */ + if (!inta && !inta_fh) { + IWL_DEBUG_ISR("Ignore interrupt, inta == 0, inta_fh == 0\n"); + goto none; + } + + if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) { + /* Hardware disappeared */ + IWL_WARNING("HARDWARE GONE?? INTA == 0x%080x\n", inta); + goto none; + } + + IWL_DEBUG_ISR("ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", + inta, inta_mask, inta_fh); + + /* iwl_irq_tasklet() will service interrupts and re-enable them */ + tasklet_schedule(&priv->irq_tasklet); + spin_unlock(&priv->lock); + + return IRQ_HANDLED; + + none: + /* re-enable interrupts here since we don't have anything to service. */ + iwl_enable_interrupts(priv); + spin_unlock(&priv->lock); + return IRQ_NONE; +} + +/************************** EEPROM BANDS **************************** + * + * The iwl_eeprom_band definitions below provide the mapping from the + * EEPROM contents to the specific channel number supported for each + * band. + * + * For example, iwl_priv->eeprom.band_3_channels[4] from the band_3 + * definition below maps to physical channel 42 in the 5.2GHz spectrum. + * The specific geography and calibration information for that channel + * is contained in the eeprom map itself. + * + * During init, we copy the eeprom information and channel map + * information into priv->channel_info_24/52 and priv->channel_map_24/52 + * + * channel_map_24/52 provides the index in the channel_info array for a + * given channel. We have to have two separate maps as there is channel + * overlap with the 2.4GHz and 5.2GHz spectrum as seen in band_1 and + * band_2 + * + * A value of 0xff stored in the channel_map indicates that the channel + * is not supported by the hardware at all. + * + * A value of 0xfe in the channel_map indicates that the channel is not + * valid for Tx with the current hardware. This means that + * while the system can tune and receive on a given channel, it may not + * be able to associate or transmit any frames on that + * channel. There is no corresponding channel information for that + * entry. + * + *********************************************************************/ + +/* 2.4 GHz */ +static const u8 iwl_eeprom_band_1[14] = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 +}; + +/* 5.2 GHz bands */ +static const u8 iwl_eeprom_band_2[] = { + 183, 184, 185, 187, 188, 189, 192, 196, 7, 8, 11, 12, 16 +}; + +static const u8 iwl_eeprom_band_3[] = { /* 5205-5320MHz */ + 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64 +}; + +static const u8 iwl_eeprom_band_4[] = { /* 5500-5700MHz */ + 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140 +}; + +static const u8 iwl_eeprom_band_5[] = { /* 5725-5825MHz */ + 145, 149, 153, 157, 161, 165 +}; + +static u8 iwl_eeprom_band_6[] = { /* 2.4 FAT channel */ + 1, 2, 3, 4, 5, 6, 7 +}; + +static u8 iwl_eeprom_band_7[] = { /* 5.2 FAT channel */ + 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157 +}; + +static void iwl_init_band_reference(const struct iwl_priv *priv, int band, + int *eeprom_ch_count, + const struct iwl_eeprom_channel + **eeprom_ch_info, + const u8 **eeprom_ch_index) +{ + switch (band) { + case 1: /* 2.4GHz band */ + *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_1); + *eeprom_ch_info = priv->eeprom.band_1_channels; + *eeprom_ch_index = iwl_eeprom_band_1; + break; + case 2: /* 5.2GHz band */ + *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_2); + *eeprom_ch_info = priv->eeprom.band_2_channels; + *eeprom_ch_index = iwl_eeprom_band_2; + break; + case 3: /* 5.2GHz band */ + *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_3); + *eeprom_ch_info = priv->eeprom.band_3_channels; + *eeprom_ch_index = iwl_eeprom_band_3; + break; + case 4: /* 5.2GHz band */ + *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_4); + *eeprom_ch_info = priv->eeprom.band_4_channels; + *eeprom_ch_index = iwl_eeprom_band_4; + break; + case 5: /* 5.2GHz band */ + *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_5); + *eeprom_ch_info = priv->eeprom.band_5_channels; + *eeprom_ch_index = iwl_eeprom_band_5; + break; + case 6: + *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_6); + *eeprom_ch_info = priv->eeprom.band_24_channels; + *eeprom_ch_index = iwl_eeprom_band_6; + break; + case 7: + *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_7); + *eeprom_ch_info = priv->eeprom.band_52_channels; + *eeprom_ch_index = iwl_eeprom_band_7; + break; + default: + BUG(); + return; + } +} + +const struct iwl_channel_info *iwl_get_channel_info(const struct iwl_priv *priv, + int phymode, u16 channel) +{ + int i; + + switch (phymode) { + case MODE_IEEE80211A: + for (i = 14; i < priv->channel_count; i++) { + if (priv->channel_info[i].channel == channel) + return &priv->channel_info[i]; + } + break; + + case MODE_IEEE80211B: + case MODE_IEEE80211G: + if (channel >= 1 && channel <= 14) + return &priv->channel_info[channel - 1]; + break; + + } + + return NULL; +} + +#define CHECK_AND_PRINT(x) ((eeprom_ch_info[ch].flags & EEPROM_CHANNEL_##x) \ + ? # x " " : "") + +static int iwl_init_channel_map(struct iwl_priv *priv) +{ + int eeprom_ch_count = 0; + const u8 *eeprom_ch_index = NULL; + const struct iwl_eeprom_channel *eeprom_ch_info = NULL; + int band, ch; + struct iwl_channel_info *ch_info; + + if (priv->channel_count) { + IWL_DEBUG_INFO("Channel map already initialized.\n"); + return 0; + } + + if (priv->eeprom.version < 0x2f) { + IWL_WARNING("Unsupported EEPROM version: 0x%04X\n", + priv->eeprom.version); + return -EINVAL; + } + + IWL_DEBUG_INFO("Initializing regulatory info from EEPROM\n"); + + priv->channel_count = + ARRAY_SIZE(iwl_eeprom_band_1) + + ARRAY_SIZE(iwl_eeprom_band_2) + + ARRAY_SIZE(iwl_eeprom_band_3) + + ARRAY_SIZE(iwl_eeprom_band_4) + + ARRAY_SIZE(iwl_eeprom_band_5); + + IWL_DEBUG_INFO("Parsing data for %d channels.\n", priv->channel_count); + + priv->channel_info = kzalloc(sizeof(struct iwl_channel_info) * + priv->channel_count, GFP_KERNEL); + if (!priv->channel_info) { + IWL_ERROR("Could not allocate channel_info\n"); + priv->channel_count = 0; + return -ENOMEM; + } + + ch_info = priv->channel_info; + + /* Loop through the 5 EEPROM bands adding them in order to the + * channel map we maintain (that contains additional information than + * what just in the EEPROM) */ + for (band = 1; band <= 5; band++) { + + iwl_init_band_reference(priv, band, &eeprom_ch_count, + &eeprom_ch_info, &eeprom_ch_index); + + /* Loop through each band adding each of the channels */ + for (ch = 0; ch < eeprom_ch_count; ch++) { + ch_info->channel = eeprom_ch_index[ch]; + ch_info->phymode = (band == 1) ? MODE_IEEE80211B : + MODE_IEEE80211A; + + /* permanently store EEPROM's channel regulatory flags + * and max power in channel info database. */ + ch_info->eeprom = eeprom_ch_info[ch]; + + /* Copy the run-time flags so they are there even on + * invalid channels */ + ch_info->flags = eeprom_ch_info[ch].flags; + + if (!(is_channel_valid(ch_info))) { + IWL_DEBUG_INFO("Ch. %d Flags %x [%sGHz] - " + "No traffic\n", + ch_info->channel, + ch_info->flags, + is_channel_a_band(ch_info) ? + "5.2" : "2.4"); + ch_info++; + continue; + } + + /* Initialize regulatory-based run-time data */ + ch_info->max_power_avg = ch_info->curr_txpow = + eeprom_ch_info[ch].max_power_avg; + ch_info->scan_power = eeprom_ch_info[ch].max_power_avg; + ch_info->min_power = 0; + + IWL_DEBUG_INFO("Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x" + " %ddBm): Ad-Hoc %ssupported\n", + ch_info->channel, + is_channel_a_band(ch_info) ? + "5.2" : "2.4", + CHECK_AND_PRINT(IBSS), + CHECK_AND_PRINT(ACTIVE), + CHECK_AND_PRINT(RADAR), + CHECK_AND_PRINT(WIDE), + CHECK_AND_PRINT(NARROW), + CHECK_AND_PRINT(DFS), + eeprom_ch_info[ch].flags, + eeprom_ch_info[ch].max_power_avg, + ((eeprom_ch_info[ch]. + flags & EEPROM_CHANNEL_IBSS) + && !(eeprom_ch_info[ch]. + flags & EEPROM_CHANNEL_RADAR)) + ? "" : "not "); + + /* Set the user_txpower_limit to the highest power + * supported by any channel */ + if (eeprom_ch_info[ch].max_power_avg > + priv->user_txpower_limit) + priv->user_txpower_limit = + eeprom_ch_info[ch].max_power_avg; + + ch_info++; + } + } + + for (band = 6; band <= 7; band++) { + int phymode; + u8 fat_extension_chan; + + iwl_init_band_reference(priv, band, &eeprom_ch_count, + &eeprom_ch_info, &eeprom_ch_index); + + phymode = (band == 6) ? MODE_IEEE80211B : MODE_IEEE80211A; + /* Loop through each band adding each of the channels */ + for (ch = 0; ch < eeprom_ch_count; ch++) { + + if ((band == 6) && + ((eeprom_ch_index[ch] == 5) || + (eeprom_ch_index[ch] == 6) || + (eeprom_ch_index[ch] == 7))) + fat_extension_chan = HT_IE_EXT_CHANNEL_MAX; + else + fat_extension_chan = HT_IE_EXT_CHANNEL_ABOVE; + + iwl4965_set_fat_chan_info(priv, phymode, + eeprom_ch_index[ch], + &(eeprom_ch_info[ch]), + fat_extension_chan); + + iwl4965_set_fat_chan_info(priv, phymode, + (eeprom_ch_index[ch] + 4), + &(eeprom_ch_info[ch]), + HT_IE_EXT_CHANNEL_BELOW); + } + } + + return 0; +} + +/* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after + * sending probe req. This should be set long enough to hear probe responses + * from more than one AP. */ +#define IWL_ACTIVE_DWELL_TIME_24 (20) /* all times in msec */ +#define IWL_ACTIVE_DWELL_TIME_52 (10) + +/* For faster active scanning, scan will move to the next channel if fewer than + * PLCP_QUIET_THRESH packets are heard on this channel within + * ACTIVE_QUIET_TIME after sending probe request. This shortens the dwell + * time if it's a quiet channel (nothing responded to our probe, and there's + * no other traffic). + * Disable "quiet" feature by setting PLCP_QUIET_THRESH to 0. */ +#define IWL_PLCP_QUIET_THRESH __constant_cpu_to_le16(1) /* packets */ +#define IWL_ACTIVE_QUIET_TIME __constant_cpu_to_le16(5) /* msec */ + +/* For passive scan, listen PASSIVE_DWELL_TIME (msec) on each channel. + * Must be set longer than active dwell time. + * For the most reliable scan, set > AP beacon interval (typically 100msec). */ +#define IWL_PASSIVE_DWELL_TIME_24 (20) /* all times in msec */ +#define IWL_PASSIVE_DWELL_TIME_52 (10) +#define IWL_PASSIVE_DWELL_BASE (100) +#define IWL_CHANNEL_TUNE_TIME 5 + +static inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv, int phymode) +{ + if (phymode == MODE_IEEE80211A) + return IWL_ACTIVE_DWELL_TIME_52; + else + return IWL_ACTIVE_DWELL_TIME_24; +} + +static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, int phymode) +{ + u16 active = iwl_get_active_dwell_time(priv, phymode); + u16 passive = (phymode != MODE_IEEE80211A) ? + IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 : + IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52; + + if (iwl_is_associated(priv)) { + /* If we're associated, we clamp the maximum passive + * dwell time to be 98% of the beacon interval (minus + * 2 * channel tune time) */ + passive = priv->beacon_int; + if ((passive > IWL_PASSIVE_DWELL_BASE) || !passive) + passive = IWL_PASSIVE_DWELL_BASE; + passive = (passive * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2; + } + + if (passive <= active) + passive = active + 1; + + return passive; +} + +static int iwl_get_channels_for_scan(struct iwl_priv *priv, int phymode, + u8 is_active, u8 direct_mask, + struct iwl_scan_channel *scan_ch) +{ + const struct ieee80211_channel *channels = NULL; + const struct ieee80211_hw_mode *hw_mode; + const struct iwl_channel_info *ch_info; + u16 passive_dwell = 0; + u16 active_dwell = 0; + int added, i; + + hw_mode = iwl_get_hw_mode(priv, phymode); + if (!hw_mode) + return 0; + + channels = hw_mode->channels; + + active_dwell = iwl_get_active_dwell_time(priv, phymode); + passive_dwell = iwl_get_passive_dwell_time(priv, phymode); + + for (i = 0, added = 0; i < hw_mode->num_channels; i++) { + if (channels[i].chan == + le16_to_cpu(priv->active_rxon.channel)) { + if (iwl_is_associated(priv)) { + IWL_DEBUG_SCAN + ("Skipping current channel %d\n", + le16_to_cpu(priv->active_rxon.channel)); + continue; + } + } else if (priv->only_active_channel) + continue; + + scan_ch->channel = channels[i].chan; + + ch_info = iwl_get_channel_info(priv, phymode, scan_ch->channel); + if (!is_channel_valid(ch_info)) { + IWL_DEBUG_SCAN("Channel %d is INVALID for this SKU.\n", + scan_ch->channel); + continue; + } + + if (!is_active || is_channel_passive(ch_info) || + !(channels[i].flag & IEEE80211_CHAN_W_ACTIVE_SCAN)) + scan_ch->type = 0; /* passive */ + else + scan_ch->type = 1; /* active */ + + if (scan_ch->type & 1) + scan_ch->type |= (direct_mask << 1); + + if (is_channel_narrow(ch_info)) + scan_ch->type |= (1 << 7); + + scan_ch->active_dwell = cpu_to_le16(active_dwell); + scan_ch->passive_dwell = cpu_to_le16(passive_dwell); + + /* Set power levels to defaults */ + scan_ch->tpc.dsp_atten = 110; + /* scan_pwr_info->tpc.dsp_atten; */ + + /*scan_pwr_info->tpc.tx_gain; */ + if (phymode == MODE_IEEE80211A) + scan_ch->tpc.tx_gain = ((1 << 5) | (3 << 3)) | 3; + else { + scan_ch->tpc.tx_gain = ((1 << 5) | (5 << 3)); + /* NOTE: if we were doing 6Mb OFDM for scans we'd use + * power level + scan_ch->tpc.tx_gain = ((1<<5) | (2 << 3)) | 3; + */ + } + + IWL_DEBUG_SCAN("Scanning %d [%s %d]\n", + scan_ch->channel, + (scan_ch->type & 1) ? "ACTIVE" : "PASSIVE", + (scan_ch->type & 1) ? + active_dwell : passive_dwell); + + scan_ch++; + added++; + } + + IWL_DEBUG_SCAN("total channels to scan %d \n", added); + return added; +} + +static void iwl_reset_channel_flag(struct iwl_priv *priv) +{ + int i, j; + for (i = 0; i < 3; i++) { + struct ieee80211_hw_mode *hw_mode = (void *)&priv->modes[i]; + for (j = 0; j < hw_mode->num_channels; j++) + hw_mode->channels[j].flag = hw_mode->channels[j].val; + } +} + +static void iwl_init_hw_rates(struct iwl_priv *priv, + struct ieee80211_rate *rates) +{ + int i; + + for (i = 0; i < IWL_RATE_COUNT; i++) { + rates[i].rate = iwl_rates[i].ieee * 5; + rates[i].val = i; /* Rate scaling will work on indexes */ + rates[i].val2 = i; + rates[i].flags = IEEE80211_RATE_SUPPORTED; + /* Only OFDM have the bits-per-symbol set */ + if ((i <= IWL_LAST_OFDM_RATE) && (i >= IWL_FIRST_OFDM_RATE)) + rates[i].flags |= IEEE80211_RATE_OFDM; + else { + /* + * If CCK 1M then set rate flag to CCK else CCK_2 + * which is CCK | PREAMBLE2 + */ + rates[i].flags |= (iwl_rates[i].plcp == 10) ? + IEEE80211_RATE_CCK : IEEE80211_RATE_CCK_2; + } + + /* Set up which ones are basic rates... */ + if (IWL_BASIC_RATES_MASK & (1 << i)) + rates[i].flags |= IEEE80211_RATE_BASIC; + } + + iwl4965_init_hw_rates(priv, rates); +} + +/** + * iwl_init_geos - Initialize mac80211's geo/channel info based from eeprom + */ +static int iwl_init_geos(struct iwl_priv *priv) +{ + struct iwl_channel_info *ch; + struct ieee80211_hw_mode *modes; + struct ieee80211_channel *channels; + struct ieee80211_channel *geo_ch; + struct ieee80211_rate *rates; + int i = 0; + enum { + A = 0, + B = 1, + G = 2, + A_11N = 3, + G_11N = 4, + }; + int mode_count = 5; + + if (priv->modes) { + IWL_DEBUG_INFO("Geography modes already initialized.\n"); + set_bit(STATUS_GEO_CONFIGURED, &priv->status); + return 0; + } + + modes = kzalloc(sizeof(struct ieee80211_hw_mode) * mode_count, + GFP_KERNEL); + if (!modes) + return -ENOMEM; + + channels = kzalloc(sizeof(struct ieee80211_channel) * + priv->channel_count, GFP_KERNEL); + if (!channels) { + kfree(modes); + return -ENOMEM; + } + + rates = kzalloc((sizeof(struct ieee80211_rate) * (IWL_MAX_RATES + 1)), + GFP_KERNEL); + if (!rates) { + kfree(modes); + kfree(channels); + return -ENOMEM; + } + + /* 0 = 802.11a + * 1 = 802.11b + * 2 = 802.11g + */ + + /* 5.2GHz channels start after the 2.4GHz channels */ + modes[A].mode = MODE_IEEE80211A; + modes[A].channels = &channels[ARRAY_SIZE(iwl_eeprom_band_1)]; + modes[A].rates = rates; + modes[A].num_rates = 8; /* just OFDM */ + modes[A].rates = &rates[4]; + modes[A].num_channels = 0; + + modes[B].mode = MODE_IEEE80211B; + modes[B].channels = channels; + modes[B].rates = rates; + modes[B].num_rates = 4; /* just CCK */ + modes[B].num_channels = 0; + + modes[G].mode = MODE_IEEE80211G; + modes[G].channels = channels; + modes[G].rates = rates; + modes[G].num_rates = 12; /* OFDM & CCK */ + modes[G].num_channels = 0; + + modes[G_11N].mode = MODE_IEEE80211G; + modes[G_11N].channels = channels; + modes[G_11N].num_rates = 13; /* OFDM & CCK */ + modes[G_11N].rates = rates; + modes[G_11N].num_channels = 0; + + modes[A_11N].mode = MODE_IEEE80211A; + modes[A_11N].channels = &channels[ARRAY_SIZE(iwl_eeprom_band_1)]; + modes[A_11N].rates = &rates[4]; + modes[A_11N].num_rates = 9; /* just OFDM */ + modes[A_11N].num_channels = 0; + + priv->ieee_channels = channels; + priv->ieee_rates = rates; + + iwl_init_hw_rates(priv, rates); + + for (i = 0, geo_ch = channels; i < priv->channel_count; i++) { + ch = &priv->channel_info[i]; + + if (!is_channel_valid(ch)) { + IWL_DEBUG_INFO("Channel %d [%sGHz] is restricted -- " + "skipping.\n", + ch->channel, is_channel_a_band(ch) ? + "5.2" : "2.4"); + continue; + } + + if (is_channel_a_band(ch)) { + geo_ch = &modes[A].channels[modes[A].num_channels++]; + modes[A_11N].num_channels++; + } else { + geo_ch = &modes[B].channels[modes[B].num_channels++]; + modes[G].num_channels++; + modes[G_11N].num_channels++; + } + + geo_ch->freq = ieee80211chan2mhz(ch->channel); + geo_ch->chan = ch->channel; + geo_ch->power_level = ch->max_power_avg; + geo_ch->antenna_max = 0xff; + + if (is_channel_valid(ch)) { + geo_ch->flag = IEEE80211_CHAN_W_SCAN; + if (ch->flags & EEPROM_CHANNEL_IBSS) + geo_ch->flag |= IEEE80211_CHAN_W_IBSS; + + if (ch->flags & EEPROM_CHANNEL_ACTIVE) + geo_ch->flag |= IEEE80211_CHAN_W_ACTIVE_SCAN; + + if (ch->flags & EEPROM_CHANNEL_RADAR) + geo_ch->flag |= IEEE80211_CHAN_W_RADAR_DETECT; + + if (ch->max_power_avg > priv->max_channel_txpower_limit) + priv->max_channel_txpower_limit = + ch->max_power_avg; + } + + geo_ch->val = geo_ch->flag; + } + + if ((modes[A].num_channels == 0) && priv->is_abg) { + printk(KERN_INFO DRV_NAME + ": Incorrectly detected BG card as ABG. Please send " + "your PCI ID 0x%04X:0x%04X to maintainer.\n", + priv->pci_dev->device, priv->pci_dev->subsystem_device); + priv->is_abg = 0; + } + + printk(KERN_INFO DRV_NAME + ": Tunable channels: %d 802.11bg, %d 802.11a channels\n", + modes[G].num_channels, modes[A].num_channels); + + /* + * NOTE: We register these in preference of order -- the + * stack doesn't currently (as of 7.0.6 / Apr 24 '07) pick + * a phymode based on rates or AP capabilities but seems to + * configure it purely on if the channel being configured + * is supported by a mode -- and the first match is taken + */ + + if (modes[G].num_channels) + ieee80211_register_hwmode(priv->hw, &modes[G]); + if (modes[B].num_channels) + ieee80211_register_hwmode(priv->hw, &modes[B]); + if (modes[A].num_channels) + ieee80211_register_hwmode(priv->hw, &modes[A]); + + priv->modes = modes; + set_bit(STATUS_GEO_CONFIGURED, &priv->status); + + return 0; +} + +/****************************************************************************** + * + * uCode download functions + * + ******************************************************************************/ + +static void iwl_dealloc_ucode_pci(struct iwl_priv *priv) +{ + if (priv->ucode_code.v_addr != NULL) { + pci_free_consistent(priv->pci_dev, + priv->ucode_code.len, + priv->ucode_code.v_addr, + priv->ucode_code.p_addr); + priv->ucode_code.v_addr = NULL; + } + if (priv->ucode_data.v_addr != NULL) { + pci_free_consistent(priv->pci_dev, + priv->ucode_data.len, + priv->ucode_data.v_addr, + priv->ucode_data.p_addr); + priv->ucode_data.v_addr = NULL; + } + if (priv->ucode_data_backup.v_addr != NULL) { + pci_free_consistent(priv->pci_dev, + priv->ucode_data_backup.len, + priv->ucode_data_backup.v_addr, + priv->ucode_data_backup.p_addr); + priv->ucode_data_backup.v_addr = NULL; + } + if (priv->ucode_init.v_addr != NULL) { + pci_free_consistent(priv->pci_dev, + priv->ucode_init.len, + priv->ucode_init.v_addr, + priv->ucode_init.p_addr); + priv->ucode_init.v_addr = NULL; + } + if (priv->ucode_init_data.v_addr != NULL) { + pci_free_consistent(priv->pci_dev, + priv->ucode_init_data.len, + priv->ucode_init_data.v_addr, + priv->ucode_init_data.p_addr); + priv->ucode_init_data.v_addr = NULL; + } + if (priv->ucode_boot.v_addr != NULL) { + pci_free_consistent(priv->pci_dev, + priv->ucode_boot.len, + priv->ucode_boot.v_addr, + priv->ucode_boot.p_addr); + priv->ucode_boot.v_addr = NULL; + } +} + +/** + * iwl_verify_inst_full - verify runtime uCode image in card vs. host, + * looking at all data. + */ +static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 * image, u32 len) +{ + u32 val; + u32 save_len = len; + int rc = 0; + u32 errcnt; + + IWL_DEBUG_INFO("ucode inst image size is %u\n", len); + + rc = iwl_grab_restricted_access(priv); + if (rc) + return rc; + + iwl_write_restricted(priv, HBUS_TARG_MEM_RADDR, RTC_INST_LOWER_BOUND); + + errcnt = 0; + for (; len > 0; len -= sizeof(u32), image++) { + /* read data comes through single port, auto-incr addr */ + /* NOTE: Use the debugless read so we don't flood kernel log + * if IWL_DL_IO is set */ + val = _iwl_read_restricted(priv, HBUS_TARG_MEM_RDAT); + if (val != le32_to_cpu(*image)) { + IWL_ERROR("uCode INST section is invalid at " + "offset 0x%x, is 0x%x, s/b 0x%x\n", + save_len - len, val, le32_to_cpu(*image)); + rc = -EIO; + errcnt++; + if (errcnt >= 20) + break; + } + } + + iwl_release_restricted_access(priv); + + if (!errcnt) + IWL_DEBUG_INFO + ("ucode image in INSTRUCTION memory is good\n"); + + return rc; +} + + +/** + * iwl_verify_inst_sparse - verify runtime uCode image in card vs. host, + * using sample data 100 bytes apart. If these sample points are good, + * it's a pretty good bet that everything between them is good, too. + */ +static int iwl_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len) +{ + u32 val; + int rc = 0; + u32 errcnt = 0; + u32 i; + + IWL_DEBUG_INFO("ucode inst image size is %u\n", len); + + rc = iwl_grab_restricted_access(priv); + if (rc) + return rc; + + for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) { + /* read data comes through single port, auto-incr addr */ + /* NOTE: Use the debugless read so we don't flood kernel log + * if IWL_DL_IO is set */ + iwl_write_restricted(priv, HBUS_TARG_MEM_RADDR, + i + RTC_INST_LOWER_BOUND); + val = _iwl_read_restricted(priv, HBUS_TARG_MEM_RDAT); + if (val != le32_to_cpu(*image)) { +#if 0 /* Enable this if you want to see details */ + IWL_ERROR("uCode INST section is invalid at " + "offset 0x%x, is 0x%x, s/b 0x%x\n", + i, val, *image); +#endif + rc = -EIO; + errcnt++; + if (errcnt >= 3) + break; + } + } + + iwl_release_restricted_access(priv); + + return rc; +} + + +/** + * iwl_verify_ucode - determine which instruction image is in SRAM, + * and verify its contents + */ +static int iwl_verify_ucode(struct iwl_priv *priv) +{ + __le32 *image; + u32 len; + int rc = 0; + + /* Try bootstrap */ + image = (__le32 *)priv->ucode_boot.v_addr; + len = priv->ucode_boot.len; + rc = iwl_verify_inst_sparse(priv, image, len); + if (rc == 0) { + IWL_DEBUG_INFO("Bootstrap uCode is good in inst SRAM\n"); + return 0; + } + + /* Try initialize */ + image = (__le32 *)priv->ucode_init.v_addr; + len = priv->ucode_init.len; + rc = iwl_verify_inst_sparse(priv, image, len); + if (rc == 0) { + IWL_DEBUG_INFO("Initialize uCode is good in inst SRAM\n"); + return 0; + } + + /* Try runtime/protocol */ + image = (__le32 *)priv->ucode_code.v_addr; + len = priv->ucode_code.len; + rc = iwl_verify_inst_sparse(priv, image, len); + if (rc == 0) { + IWL_DEBUG_INFO("Runtime uCode is good in inst SRAM\n"); + return 0; + } + + IWL_ERROR("NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n"); + + /* Show first several data entries in instruction SRAM. + * Selection of bootstrap image is arbitrary. */ + image = (__le32 *)priv->ucode_boot.v_addr; + len = priv->ucode_boot.len; + rc = iwl_verify_inst_full(priv, image, len); + + return rc; +} + + +/* check contents of special bootstrap uCode SRAM */ +static int iwl_verify_bsm(struct iwl_priv *priv) +{ + __le32 *image = priv->ucode_boot.v_addr; + u32 len = priv->ucode_boot.len; + u32 reg; + u32 val; + + IWL_DEBUG_INFO("Begin verify bsm\n"); + + /* verify BSM SRAM contents */ + val = iwl_read_restricted_reg(priv, BSM_WR_DWCOUNT_REG); + for (reg = BSM_SRAM_LOWER_BOUND; + reg < BSM_SRAM_LOWER_BOUND + len; + reg += sizeof(u32), image ++) { + val = iwl_read_restricted_reg(priv, reg); + if (val != le32_to_cpu(*image)) { + IWL_ERROR("BSM uCode verification failed at " + "addr 0x%08X+%u (of %u), is 0x%x, s/b 0x%x\n", + BSM_SRAM_LOWER_BOUND, + reg - BSM_SRAM_LOWER_BOUND, len, + val, le32_to_cpu(*image)); + return -EIO; + } + } + + IWL_DEBUG_INFO("BSM bootstrap uCode image OK\n"); + + return 0; +} + +/** + * iwl_load_bsm - Load bootstrap instructions + * + * BSM operation: + * + * The Bootstrap State Machine (BSM) stores a short bootstrap uCode program + * in special SRAM that does not power down during RFKILL. When powering back + * up after power-saving sleeps (or during initial uCode load), the BSM loads + * the bootstrap program into the on-board processor, and starts it. + * + * The bootstrap program loads (via DMA) instructions and data for a new + * program from host DRAM locations indicated by the host driver in the + * BSM_DRAM_* registers. Once the new program is loaded, it starts + * automatically. + * + * When initializing the NIC, the host driver points the BSM to the + * "initialize" uCode image. This uCode sets up some internal data, then + * notifies host via "initialize alive" that it is complete. + * + * The host then replaces the BSM_DRAM_* pointer values to point to the + * normal runtime uCode instructions and a backup uCode data cache buffer + * (filled initially with starting data values for the on-board processor), + * then triggers the "initialize" uCode to load and launch the runtime uCode, + * which begins normal operation. + * + * When doing a power-save shutdown, runtime uCode saves data SRAM into + * the backup data cache in DRAM before SRAM is powered down. + * + * When powering back up, the BSM loads the bootstrap program. This reloads + * the runtime uCode instructions and the backup data cache into SRAM, + * and re-launches the runtime uCode from where it left off. + */ +static int iwl_load_bsm(struct iwl_priv *priv) +{ + __le32 *image = priv->ucode_boot.v_addr; + u32 len = priv->ucode_boot.len; + dma_addr_t pinst; + dma_addr_t pdata; + u32 inst_len; + u32 data_len; + int rc; + int i; + u32 done; + u32 reg_offset; + + IWL_DEBUG_INFO("Begin load bsm\n"); + + /* make sure bootstrap program is no larger than BSM's SRAM size */ + if (len > IWL_MAX_BSM_SIZE) + return -EINVAL; + + /* Tell bootstrap uCode where to find the "Initialize" uCode + * in host DRAM ... bits 31:0 for 3945, bits 35:4 for 4965. + * NOTE: iwl_initialize_alive_start() will replace these values, + * after the "initialize" uCode has run, to point to + * runtime/protocol instructions and backup data cache. */ + pinst = priv->ucode_init.p_addr >> 4; + pdata = priv->ucode_init_data.p_addr >> 4; + inst_len = priv->ucode_init.len; + data_len = priv->ucode_init_data.len; + + rc = iwl_grab_restricted_access(priv); + if (rc) + return rc; + + iwl_write_restricted_reg(priv, BSM_DRAM_INST_PTR_REG, pinst); + iwl_write_restricted_reg(priv, BSM_DRAM_DATA_PTR_REG, pdata); + iwl_write_restricted_reg(priv, BSM_DRAM_INST_BYTECOUNT_REG, inst_len); + iwl_write_restricted_reg(priv, BSM_DRAM_DATA_BYTECOUNT_REG, data_len); + + /* Fill BSM memory with bootstrap instructions */ + for (reg_offset = BSM_SRAM_LOWER_BOUND; + reg_offset < BSM_SRAM_LOWER_BOUND + len; + reg_offset += sizeof(u32), image++) + _iwl_write_restricted_reg(priv, reg_offset, + le32_to_cpu(*image)); + + rc = iwl_verify_bsm(priv); + if (rc) { + iwl_release_restricted_access(priv); + return rc; + } + + /* Tell BSM to copy from BSM SRAM into instruction SRAM, when asked */ + iwl_write_restricted_reg(priv, BSM_WR_MEM_SRC_REG, 0x0); + iwl_write_restricted_reg(priv, BSM_WR_MEM_DST_REG, + RTC_INST_LOWER_BOUND); + iwl_write_restricted_reg(priv, BSM_WR_DWCOUNT_REG, len / sizeof(u32)); + + /* Load bootstrap code into instruction SRAM now, + * to prepare to load "initialize" uCode */ + iwl_write_restricted_reg(priv, BSM_WR_CTRL_REG, + BSM_WR_CTRL_REG_BIT_START); + + /* Wait for load of bootstrap uCode to finish */ + for (i = 0; i < 100; i++) { + done = iwl_read_restricted_reg(priv, BSM_WR_CTRL_REG); + if (!(done & BSM_WR_CTRL_REG_BIT_START)) + break; + udelay(10); + } + if (i < 100) + IWL_DEBUG_INFO("BSM write complete, poll %d iterations\n", i); + else { + IWL_ERROR("BSM write did not complete!\n"); + return -EIO; + } + + /* Enable future boot loads whenever power management unit triggers it + * (e.g. when powering back up after power-save shutdown) */ + iwl_write_restricted_reg(priv, BSM_WR_CTRL_REG, + BSM_WR_CTRL_REG_BIT_START_EN); + + iwl_release_restricted_access(priv); + + return 0; +} + +static void iwl_nic_start(struct iwl_priv *priv) +{ + /* Remove all resets to allow NIC to operate */ + iwl_write32(priv, CSR_RESET, 0); +} + +/** + * iwl_read_ucode - Read uCode images from disk file. + * + * Copy into buffers for card to fetch via bus-mastering + */ +static int iwl_read_ucode(struct iwl_priv *priv) +{ + struct iwl_ucode *ucode; + int rc = 0; + const struct firmware *ucode_raw; + const char *name = "iwlwifi-4965" IWL4965_UCODE_API ".ucode"; + u8 *src; + size_t len; + u32 ver, inst_size, data_size, init_size, init_data_size, boot_size; + + /* Ask kernel firmware_class module to get the boot firmware off disk. + * request_firmware() is synchronous, file is in memory on return. */ + rc = request_firmware(&ucode_raw, name, &priv->pci_dev->dev); + if (rc < 0) { + IWL_ERROR("%s firmware file req failed: Reason %d\n", name, rc); + goto error; + } + + IWL_DEBUG_INFO("Got firmware '%s' file (%zd bytes) from disk\n", + name, ucode_raw->size); + + /* Make sure that we got at least our header! */ + if (ucode_raw->size < sizeof(*ucode)) { + IWL_ERROR("File size way too small!\n"); + rc = -EINVAL; + goto err_release; + } + + /* Data from ucode file: header followed by uCode images */ + ucode = (void *)ucode_raw->data; + + ver = le32_to_cpu(ucode->ver); + inst_size = le32_to_cpu(ucode->inst_size); + data_size = le32_to_cpu(ucode->data_size); + init_size = le32_to_cpu(ucode->init_size); + init_data_size = le32_to_cpu(ucode->init_data_size); + boot_size = le32_to_cpu(ucode->boot_size); + + IWL_DEBUG_INFO("f/w package hdr ucode version = 0x%x\n", ver); + IWL_DEBUG_INFO("f/w package hdr runtime inst size = %u\n", + inst_size); + IWL_DEBUG_INFO("f/w package hdr runtime data size = %u\n", + data_size); + IWL_DEBUG_INFO("f/w package hdr init inst size = %u\n", + init_size); + IWL_DEBUG_INFO("f/w package hdr init data size = %u\n", + init_data_size); + IWL_DEBUG_INFO("f/w package hdr boot inst size = %u\n", + boot_size); + + /* Verify size of file vs. image size info in file's header */ + if (ucode_raw->size < sizeof(*ucode) + + inst_size + data_size + init_size + + init_data_size + boot_size) { + + IWL_DEBUG_INFO("uCode file size %d too small\n", + (int)ucode_raw->size); + rc = -EINVAL; + goto err_release; + } + + /* Verify that uCode images will fit in card's SRAM */ + if (inst_size > IWL_MAX_INST_SIZE) { + IWL_DEBUG_INFO("uCode instr len %d too large to fit in card\n", + (int)inst_size); + rc = -EINVAL; + goto err_release; + } + + if (data_size > IWL_MAX_DATA_SIZE) { + IWL_DEBUG_INFO("uCode data len %d too large to fit in card\n", + (int)data_size); + rc = -EINVAL; + goto err_release; + } + if (init_size > IWL_MAX_INST_SIZE) { + IWL_DEBUG_INFO + ("uCode init instr len %d too large to fit in card\n", + (int)init_size); + rc = -EINVAL; + goto err_release; + } + if (init_data_size > IWL_MAX_DATA_SIZE) { + IWL_DEBUG_INFO + ("uCode init data len %d too large to fit in card\n", + (int)init_data_size); + rc = -EINVAL; + goto err_release; + } + if (boot_size > IWL_MAX_BSM_SIZE) { + IWL_DEBUG_INFO + ("uCode boot instr len %d too large to fit in bsm\n", + (int)boot_size); + rc = -EINVAL; + goto err_release; + } + + /* Allocate ucode buffers for card's bus-master loading ... */ + + /* Runtime instructions and 2 copies of data: + * 1) unmodified from disk + * 2) backup cache for save/restore during power-downs */ + priv->ucode_code.len = inst_size; + priv->ucode_code.v_addr = + pci_alloc_consistent(priv->pci_dev, + priv->ucode_code.len, + &(priv->ucode_code.p_addr)); + + priv->ucode_data.len = data_size; + priv->ucode_data.v_addr = + pci_alloc_consistent(priv->pci_dev, + priv->ucode_data.len, + &(priv->ucode_data.p_addr)); + + priv->ucode_data_backup.len = data_size; + priv->ucode_data_backup.v_addr = + pci_alloc_consistent(priv->pci_dev, + priv->ucode_data_backup.len, + &(priv->ucode_data_backup.p_addr)); + + + /* Initialization instructions and data */ + priv->ucode_init.len = init_size; + priv->ucode_init.v_addr = + pci_alloc_consistent(priv->pci_dev, + priv->ucode_init.len, + &(priv->ucode_init.p_addr)); + + priv->ucode_init_data.len = init_data_size; + priv->ucode_init_data.v_addr = + pci_alloc_consistent(priv->pci_dev, + priv->ucode_init_data.len, + &(priv->ucode_init_data.p_addr)); + + /* Bootstrap (instructions only, no data) */ + priv->ucode_boot.len = boot_size; + priv->ucode_boot.v_addr = + pci_alloc_consistent(priv->pci_dev, + priv->ucode_boot.len, + &(priv->ucode_boot.p_addr)); + + if (!priv->ucode_code.v_addr || !priv->ucode_data.v_addr || + !priv->ucode_init.v_addr || !priv->ucode_init_data.v_addr || + !priv->ucode_boot.v_addr || !priv->ucode_data_backup.v_addr) + goto err_pci_alloc; + + /* Copy images into buffers for card's bus-master reads ... */ + + /* Runtime instructions (first block of data in file) */ + src = &ucode->data[0]; + len = priv->ucode_code.len; + IWL_DEBUG_INFO("Copying (but not loading) uCode instr len %d\n", + (int)len); + memcpy(priv->ucode_code.v_addr, src, len); + IWL_DEBUG_INFO("uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n", + priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr); + + /* Runtime data (2nd block) + * NOTE: Copy into backup buffer will be done in iwl_up() */ + src = &ucode->data[inst_size]; + len = priv->ucode_data.len; + IWL_DEBUG_INFO("Copying (but not loading) uCode data len %d\n", + (int)len); + memcpy(priv->ucode_data.v_addr, src, len); + memcpy(priv->ucode_data_backup.v_addr, src, len); + + /* Initialization instructions (3rd block) */ + if (init_size) { + src = &ucode->data[inst_size + data_size]; + len = priv->ucode_init.len; + IWL_DEBUG_INFO("Copying (but not loading) init instr len %d\n", + (int)len); + memcpy(priv->ucode_init.v_addr, src, len); + } + + /* Initialization data (4th block) */ + if (init_data_size) { + src = &ucode->data[inst_size + data_size + init_size]; + len = priv->ucode_init_data.len; + IWL_DEBUG_INFO("Copying (but not loading) init data len %d\n", + (int)len); + memcpy(priv->ucode_init_data.v_addr, src, len); + } + + /* Bootstrap instructions (5th block) */ + src = &ucode->data[inst_size + data_size + init_size + init_data_size]; + len = priv->ucode_boot.len; + IWL_DEBUG_INFO("Copying (but not loading) boot instr len %d\n", + (int)len); + memcpy(priv->ucode_boot.v_addr, src, len); + + /* We have our copies now, allow OS release its copies */ + release_firmware(ucode_raw); + return 0; + + err_pci_alloc: + IWL_ERROR("failed to allocate pci memory\n"); + rc = -ENOMEM; + iwl_dealloc_ucode_pci(priv); + + err_release: + release_firmware(ucode_raw); + + error: + return rc; +} + + +/** + * iwl_set_ucode_ptrs - Set uCode address location + * + * Tell initialization uCode where to find runtime uCode. + * + * BSM registers initially contain pointers to initialization uCode. + * We need to replace them to load runtime uCode inst and data, + * and to save runtime data when powering down. + */ +static int iwl_set_ucode_ptrs(struct iwl_priv *priv) +{ + dma_addr_t pinst; + dma_addr_t pdata; + int rc = 0; + unsigned long flags; + + /* bits 35:4 for 4965 */ + pinst = priv->ucode_code.p_addr >> 4; + pdata = priv->ucode_data_backup.p_addr >> 4; + + spin_lock_irqsave(&priv->lock, flags); + rc = iwl_grab_restricted_access(priv); + if (rc) { + spin_unlock_irqrestore(&priv->lock, flags); + return rc; + } + + /* Tell bootstrap uCode where to find image to load */ + iwl_write_restricted_reg(priv, BSM_DRAM_INST_PTR_REG, pinst); + iwl_write_restricted_reg(priv, BSM_DRAM_DATA_PTR_REG, pdata); + iwl_write_restricted_reg(priv, BSM_DRAM_DATA_BYTECOUNT_REG, + priv->ucode_data.len); + + /* Inst bytecount must be last to set up, bit 31 signals uCode + * that all new ptr/size info is in place */ + iwl_write_restricted_reg(priv, BSM_DRAM_INST_BYTECOUNT_REG, + priv->ucode_code.len | BSM_DRAM_INST_LOAD); + + iwl_release_restricted_access(priv); + + spin_unlock_irqrestore(&priv->lock, flags); + + IWL_DEBUG_INFO("Runtime uCode pointers are set.\n"); + + return rc; +} + +/** + * iwl_init_alive_start - Called after REPLY_ALIVE notification receieved + * + * Called after REPLY_ALIVE notification received from "initialize" uCode. + * + * The 4965 "initialize" ALIVE reply contains calibration data for: + * Voltage, temperature, and MIMO tx gain correction, now stored in priv + * (3945 does not contain this data). + * + * Tell "initialize" uCode to go ahead and load the runtime uCode. +*/ +static void iwl_init_alive_start(struct iwl_priv *priv) +{ + /* Check alive response for "valid" sign from uCode */ + if (priv->card_alive_init.is_valid != UCODE_VALID_OK) { + /* We had an error bringing up the hardware, so take it + * all the way back down so we can try again */ + IWL_DEBUG_INFO("Initialize Alive failed.\n"); + goto restart; + } + + /* Bootstrap uCode has loaded initialize uCode ... verify inst image. + * This is a paranoid check, because we would not have gotten the + * "initialize" alive if code weren't properly loaded. */ + if (iwl_verify_ucode(priv)) { + /* Runtime instruction load was bad; + * take it all the way back down so we can try again */ + IWL_DEBUG_INFO("Bad \"initialize\" uCode load.\n"); + goto restart; + } + + /* Calculate temperature */ + priv->temperature = iwl4965_get_temperature(priv); + + /* Send pointers to protocol/runtime uCode image ... init code will + * load and launch runtime uCode, which will send us another "Alive" + * notification. */ + IWL_DEBUG_INFO("Initialization Alive received.\n"); + if (iwl_set_ucode_ptrs(priv)) { + /* Runtime instruction load won't happen; + * take it all the way back down so we can try again */ + IWL_DEBUG_INFO("Couldn't set up uCode pointers.\n"); + goto restart; + } + return; + + restart: + queue_work(priv->workqueue, &priv->restart); +} + + +/** + * iwl_alive_start - called after REPLY_ALIVE notification received + * from protocol/runtime uCode (initialization uCode's + * Alive gets handled by iwl_init_alive_start()). + */ +static void iwl_alive_start(struct iwl_priv *priv) +{ + int rc = 0; + + IWL_DEBUG_INFO("Runtime Alive received.\n"); + + if (priv->card_alive.is_valid != UCODE_VALID_OK) { + /* We had an error bringing up the hardware, so take it + * all the way back down so we can try again */ + IWL_DEBUG_INFO("Alive failed.\n"); + goto restart; + } + + /* Initialize uCode has loaded Runtime uCode ... verify inst image. + * This is a paranoid check, because we would not have gotten the + * "runtime" alive if code weren't properly loaded. */ + if (iwl_verify_ucode(priv)) { + /* Runtime instruction load was bad; + * take it all the way back down so we can try again */ + IWL_DEBUG_INFO("Bad runtime uCode load.\n"); + goto restart; + } + + iwl_clear_stations_table(priv); + + rc = iwl4965_alive_notify(priv); + if (rc) { + IWL_WARNING("Could not complete ALIVE transition [ntf]: %d\n", + rc); + goto restart; + } + + /* After the ALIVE response, we can process host commands */ + set_bit(STATUS_ALIVE, &priv->status); + + /* Clear out the uCode error bit if it is set */ + clear_bit(STATUS_FW_ERROR, &priv->status); + + rc = iwl_init_channel_map(priv); + if (rc) { + IWL_ERROR("initializing regulatory failed: %d\n", rc); + return; + } + + iwl_init_geos(priv); + + if (iwl_is_rfkill(priv)) + return; + + if (!priv->mac80211_registered) { + /* Unlock so any user space entry points can call back into + * the driver without a deadlock... */ + mutex_unlock(&priv->mutex); + iwl_rate_control_register(priv->hw); + rc = ieee80211_register_hw(priv->hw); + priv->hw->conf.beacon_int = 100; + mutex_lock(&priv->mutex); + + if (rc) { + IWL_ERROR("Failed to register network " + "device (error %d)\n", rc); + return; + } + + priv->mac80211_registered = 1; + + iwl_reset_channel_flag(priv); + } else + ieee80211_start_queues(priv->hw); + + priv->active_rate = priv->rates_mask; + priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK; + + iwl_send_power_mode(priv, IWL_POWER_LEVEL(priv->power_mode)); + + if (iwl_is_associated(priv)) { + struct iwl_rxon_cmd *active_rxon = + (struct iwl_rxon_cmd *)(&priv->active_rxon); + + memcpy(&priv->staging_rxon, &priv->active_rxon, + sizeof(priv->staging_rxon)); + active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; + } else { + /* Initialize our rx_config data */ + iwl_connection_init_rx_config(priv); + memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); + } + + /* Configure BT coexistence */ + iwl_send_bt_config(priv); + + /* Configure the adapter for unassociated operation */ + iwl_commit_rxon(priv); + + /* At this point, the NIC is initialized and operational */ + priv->notif_missed_beacons = 0; + set_bit(STATUS_READY, &priv->status); + + iwl4965_rf_kill_ct_config(priv); + IWL_DEBUG_INFO("ALIVE processing complete.\n"); + + if (priv->error_recovering) + iwl_error_recovery(priv); + + return; + + restart: + queue_work(priv->workqueue, &priv->restart); +} + +static void iwl_cancel_deferred_work(struct iwl_priv *priv); + +static void __iwl_down(struct iwl_priv *priv) +{ + unsigned long flags; + int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status); + struct ieee80211_conf *conf = NULL; + + IWL_DEBUG_INFO(DRV_NAME " is going down\n"); + + conf = ieee80211_get_hw_conf(priv->hw); + + if (!exit_pending) + set_bit(STATUS_EXIT_PENDING, &priv->status); + + iwl_clear_stations_table(priv); + + /* Unblock any waiting calls */ + wake_up_interruptible_all(&priv->wait_command_queue); + + iwl_cancel_deferred_work(priv); + + /* Wipe out the EXIT_PENDING status bit if we are not actually + * exiting the module */ + if (!exit_pending) + clear_bit(STATUS_EXIT_PENDING, &priv->status); + + /* stop and reset the on-board processor */ + iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); + + /* tell the device to stop sending interrupts */ + iwl_disable_interrupts(priv); + + if (priv->mac80211_registered) + ieee80211_stop_queues(priv->hw); + + /* If we have not previously called iwl_init() then + * clear all bits but the RF Kill and SUSPEND bits and return */ + if (!iwl_is_init(priv)) { + priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) << + STATUS_RF_KILL_HW | + test_bit(STATUS_RF_KILL_SW, &priv->status) << + STATUS_RF_KILL_SW | + test_bit(STATUS_IN_SUSPEND, &priv->status) << + STATUS_IN_SUSPEND; + goto exit; + } + + /* ...otherwise clear out all the status bits but the RF Kill and + * SUSPEND bits and continue taking the NIC down. */ + priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) << + STATUS_RF_KILL_HW | + test_bit(STATUS_RF_KILL_SW, &priv->status) << + STATUS_RF_KILL_SW | + test_bit(STATUS_IN_SUSPEND, &priv->status) << + STATUS_IN_SUSPEND | + test_bit(STATUS_FW_ERROR, &priv->status) << + STATUS_FW_ERROR; + + spin_lock_irqsave(&priv->lock, flags); + iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + spin_unlock_irqrestore(&priv->lock, flags); + + iwl_hw_txq_ctx_stop(priv); + iwl_hw_rxq_stop(priv); + + spin_lock_irqsave(&priv->lock, flags); + if (!iwl_grab_restricted_access(priv)) { + iwl_write_restricted_reg(priv, APMG_CLK_DIS_REG, + APMG_CLK_VAL_DMA_CLK_RQT); + iwl_release_restricted_access(priv); + } + spin_unlock_irqrestore(&priv->lock, flags); + + udelay(5); + + iwl_hw_nic_stop_master(priv); + iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); + iwl_hw_nic_reset(priv); + + exit: + memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp)); + + if (priv->ibss_beacon) + dev_kfree_skb(priv->ibss_beacon); + priv->ibss_beacon = NULL; + + /* clear out any free frames */ + iwl_clear_free_frames(priv); +} + +static void iwl_down(struct iwl_priv *priv) +{ + mutex_lock(&priv->mutex); + __iwl_down(priv); + mutex_unlock(&priv->mutex); +} + +#define MAX_HW_RESTARTS 5 + +static int __iwl_up(struct iwl_priv *priv) +{ + int rc, i; + u32 hw_rf_kill = 0; + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { + IWL_WARNING("Exit pending; will not bring the NIC up\n"); + return -EIO; + } + + if (test_bit(STATUS_RF_KILL_SW, &priv->status)) { + IWL_WARNING("Radio disabled by SW RF kill (module " + "parameter)\n"); + return 0; + } + + iwl_write32(priv, CSR_INT, 0xFFFFFFFF); + + rc = iwl_hw_nic_init(priv); + if (rc) { + IWL_ERROR("Unable to int nic\n"); + return rc; + } + + /* make sure rfkill handshake bits are cleared */ + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, + CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); + + /* clear (again), then enable host interrupts */ + iwl_write32(priv, CSR_INT, 0xFFFFFFFF); + iwl_enable_interrupts(priv); + + /* really make sure rfkill handshake bits are cleared */ + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + + /* Copy original ucode data image from disk into backup cache. + * This will be used to initialize the on-board processor's + * data SRAM for a clean start when the runtime program first loads. */ + memcpy(priv->ucode_data_backup.v_addr, priv->ucode_data.v_addr, + priv->ucode_data.len); + + /* If platform's RF_KILL switch is set to KILL, + * wait for BIT_INT_RF_KILL interrupt before loading uCode + * and getting things started */ + if (!(iwl_read32(priv, CSR_GP_CNTRL) & + CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) + hw_rf_kill = 1; + + if (test_bit(STATUS_RF_KILL_HW, &priv->status) || hw_rf_kill) { + IWL_WARNING("Radio disabled by HW RF Kill switch\n"); + return 0; + } + + for (i = 0; i < MAX_HW_RESTARTS; i++) { + + iwl_clear_stations_table(priv); + + /* load bootstrap state machine, + * load bootstrap program into processor's memory, + * prepare to load the "initialize" uCode */ + rc = iwl_load_bsm(priv); + + if (rc) { + IWL_ERROR("Unable to set up bootstrap uCode: %d\n", rc); + continue; + } + + /* start card; "initialize" will load runtime ucode */ + iwl_nic_start(priv); + + /* MAC Address location in EEPROM same for 3945/4965 */ + get_eeprom_mac(priv, priv->mac_addr); + IWL_DEBUG_INFO("MAC address: " MAC_FMT "\n", + MAC_ARG(priv->mac_addr)); + + SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr); + + IWL_DEBUG_INFO(DRV_NAME " is coming up\n"); + + return 0; + } + + set_bit(STATUS_EXIT_PENDING, &priv->status); + __iwl_down(priv); + + /* tried to restart and config the device for as long as our + * patience could withstand */ + IWL_ERROR("Unable to initialize device after %d attempts.\n", i); + return -EIO; +} + + +/***************************************************************************** + * + * Workqueue callbacks + * + *****************************************************************************/ + +static void iwl_bg_init_alive_start(struct work_struct *data) +{ + struct iwl_priv *priv = + container_of(data, struct iwl_priv, init_alive_start.work); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + mutex_lock(&priv->mutex); + iwl_init_alive_start(priv); + mutex_unlock(&priv->mutex); +} + +static void iwl_bg_alive_start(struct work_struct *data) +{ + struct iwl_priv *priv = + container_of(data, struct iwl_priv, alive_start.work); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + mutex_lock(&priv->mutex); + iwl_alive_start(priv); + mutex_unlock(&priv->mutex); +} + +static void iwl_bg_rf_kill(struct work_struct *work) +{ + struct iwl_priv *priv = container_of(work, struct iwl_priv, rf_kill); + + wake_up_interruptible(&priv->wait_command_queue); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + mutex_lock(&priv->mutex); + + if (!iwl_is_rfkill(priv)) { + IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL, + "HW and/or SW RF Kill no longer active, restarting " + "device\n"); + if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) + queue_work(priv->workqueue, &priv->restart); + } else { + + if (!test_bit(STATUS_RF_KILL_HW, &priv->status)) + IWL_DEBUG_RF_KILL("Can not turn radio back on - " + "disabled by SW switch\n"); + else + IWL_WARNING("Radio Frequency Kill Switch is On:\n" + "Kill switch must be turned off for " + "wireless networking to work.\n"); + } + mutex_unlock(&priv->mutex); +} + +#define IWL_SCAN_CHECK_WATCHDOG (7 * HZ) + +static void iwl_bg_scan_check(struct work_struct *data) +{ + struct iwl_priv *priv = + container_of(data, struct iwl_priv, scan_check.work); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + mutex_lock(&priv->mutex); + if (test_bit(STATUS_SCANNING, &priv->status) || + test_bit(STATUS_SCAN_ABORTING, &priv->status)) { + IWL_DEBUG(IWL_DL_INFO | IWL_DL_SCAN, + "Scan completion watchdog resetting adapter (%dms)\n", + jiffies_to_msecs(IWL_SCAN_CHECK_WATCHDOG)); + if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) + queue_work(priv->workqueue, &priv->restart); + } + mutex_unlock(&priv->mutex); +} + +static void iwl_bg_request_scan(struct work_struct *data) +{ + struct iwl_priv *priv = + container_of(data, struct iwl_priv, request_scan); + struct iwl_host_cmd cmd = { + .id = REPLY_SCAN_CMD, + .len = sizeof(struct iwl_scan_cmd), + .meta.flags = CMD_SIZE_HUGE, + }; + int rc = 0; + struct iwl_scan_cmd *scan; + struct ieee80211_conf *conf = NULL; + u8 direct_mask; + int phymode; + + conf = ieee80211_get_hw_conf(priv->hw); + + mutex_lock(&priv->mutex); + + if (!iwl_is_ready(priv)) { + IWL_WARNING("request scan called when driver not ready.\n"); + goto done; + } + + /* Make sure the scan wasn't cancelled before this queued work + * was given the chance to run... */ + if (!test_bit(STATUS_SCANNING, &priv->status)) + goto done; + + /* This should never be called or scheduled if there is currently + * a scan active in the hardware. */ + if (test_bit(STATUS_SCAN_HW, &priv->status)) { + IWL_DEBUG_INFO("Multiple concurrent scan requests in parallel. " + "Ignoring second request.\n"); + rc = -EIO; + goto done; + } + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { + IWL_DEBUG_SCAN("Aborting scan due to device shutdown\n"); + goto done; + } + + if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { + IWL_DEBUG_HC("Scan request while abort pending. Queuing.\n"); + goto done; + } + + if (iwl_is_rfkill(priv)) { + IWL_DEBUG_HC("Aborting scan due to RF Kill activation\n"); + goto done; + } + + if (!test_bit(STATUS_READY, &priv->status)) { + IWL_DEBUG_HC("Scan request while uninitialized. Queuing.\n"); + goto done; + } + + if (!priv->scan_bands) { + IWL_DEBUG_HC("Aborting scan due to no requested bands\n"); + goto done; + } + + if (!priv->scan) { + priv->scan = kmalloc(sizeof(struct iwl_scan_cmd) + + IWL_MAX_SCAN_SIZE, GFP_KERNEL); + if (!priv->scan) { + rc = -ENOMEM; + goto done; + } + } + scan = priv->scan; + memset(scan, 0, sizeof(struct iwl_scan_cmd) + IWL_MAX_SCAN_SIZE); + + scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH; + scan->quiet_time = IWL_ACTIVE_QUIET_TIME; + + if (iwl_is_associated(priv)) { + u16 interval = 0; + u32 extra; + u32 suspend_time = 100; + u32 scan_suspend_time = 100; + unsigned long flags; + + IWL_DEBUG_INFO("Scanning while associated...\n"); + + spin_lock_irqsave(&priv->lock, flags); + interval = priv->beacon_int; + spin_unlock_irqrestore(&priv->lock, flags); + + scan->suspend_time = 0; + scan->max_out_time = cpu_to_le32(600 * 1024); + if (!interval) + interval = suspend_time; + + extra = (suspend_time / interval) << 22; + scan_suspend_time = (extra | + ((suspend_time % interval) * 1024)); + scan->suspend_time = cpu_to_le32(scan_suspend_time); + IWL_DEBUG_SCAN("suspend_time 0x%X beacon interval %d\n", + scan_suspend_time, interval); + } + + /* We should add the ability for user to lock to PASSIVE ONLY */ + if (priv->one_direct_scan) { + IWL_DEBUG_SCAN + ("Kicking off one direct scan for '%s'\n", + iwl_escape_essid(priv->direct_ssid, + priv->direct_ssid_len)); + scan->direct_scan[0].id = WLAN_EID_SSID; + scan->direct_scan[0].len = priv->direct_ssid_len; + memcpy(scan->direct_scan[0].ssid, + priv->direct_ssid, priv->direct_ssid_len); + direct_mask = 1; + } else if (!iwl_is_associated(priv)) { + scan->direct_scan[0].id = WLAN_EID_SSID; + scan->direct_scan[0].len = priv->essid_len; + memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len); + direct_mask = 1; + } else + direct_mask = 0; + + /* We don't build a direct scan probe request; the uCode will do + * that based on the direct_mask added to each channel entry */ + scan->tx_cmd.len = cpu_to_le16( + iwl_fill_probe_req(priv, (struct ieee80211_mgmt *)scan->data, + IWL_MAX_SCAN_SIZE - sizeof(scan), 0)); + scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK; + scan->tx_cmd.sta_id = priv->hw_setting.bcast_sta_id; + scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; + + /* flags + rate selection */ + + scan->tx_cmd.tx_flags |= cpu_to_le32(0x200); + + switch (priv->scan_bands) { + case 2: + scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK; + scan->tx_cmd.rate_n_flags = + iwl_hw_set_rate_n_flags(IWL_RATE_1M_PLCP, + RATE_MCS_ANT_B_MSK|RATE_MCS_CCK_MSK); + + scan->good_CRC_th = 0; + phymode = MODE_IEEE80211G; + break; + + case 1: + scan->tx_cmd.rate_n_flags = + iwl_hw_set_rate_n_flags(IWL_RATE_6M_PLCP, + RATE_MCS_ANT_B_MSK); + scan->good_CRC_th = IWL_GOOD_CRC_TH; + phymode = MODE_IEEE80211A; + break; + + default: + IWL_WARNING("Invalid scan band count\n"); + goto done; + } + + /* select Rx chains */ + + /* Force use of chains B and C (0x6) for scan Rx. + * Avoid A (0x1) because of its off-channel reception on A-band. + * MIMO is not used here, but value is required to make uCode happy. */ + scan->rx_chain = RXON_RX_CHAIN_DRIVER_FORCE_MSK | + cpu_to_le16((0x7 << RXON_RX_CHAIN_VALID_POS) | + (0x6 << RXON_RX_CHAIN_FORCE_SEL_POS) | + (0x7 << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS)); + + if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) + scan->filter_flags = RXON_FILTER_PROMISC_MSK; + + if (direct_mask) + IWL_DEBUG_SCAN + ("Initiating direct scan for %s.\n", + iwl_escape_essid(priv->essid, priv->essid_len)); + else + IWL_DEBUG_SCAN("Initiating indirect scan.\n"); + + scan->channel_count = + iwl_get_channels_for_scan( + priv, phymode, 1, /* active */ + direct_mask, + (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); + + cmd.len += le16_to_cpu(scan->tx_cmd.len) + + scan->channel_count * sizeof(struct iwl_scan_channel); + cmd.data = scan; + scan->len = cpu_to_le16(cmd.len); + + set_bit(STATUS_SCAN_HW, &priv->status); + rc = iwl_send_cmd_sync(priv, &cmd); + if (rc) + goto done; + + queue_delayed_work(priv->workqueue, &priv->scan_check, + IWL_SCAN_CHECK_WATCHDOG); + + mutex_unlock(&priv->mutex); + return; + + done: + /* inform mac80211 sacn aborted */ + queue_work(priv->workqueue, &priv->scan_completed); + mutex_unlock(&priv->mutex); +} + +static void iwl_bg_up(struct work_struct *data) +{ + struct iwl_priv *priv = container_of(data, struct iwl_priv, up); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + mutex_lock(&priv->mutex); + __iwl_up(priv); + mutex_unlock(&priv->mutex); +} + +static void iwl_bg_restart(struct work_struct *data) +{ + struct iwl_priv *priv = container_of(data, struct iwl_priv, restart); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + iwl_down(priv); + queue_work(priv->workqueue, &priv->up); +} + +static void iwl_bg_rx_replenish(struct work_struct *data) +{ + struct iwl_priv *priv = + container_of(data, struct iwl_priv, rx_replenish); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + mutex_lock(&priv->mutex); + iwl_rx_replenish(priv); + mutex_unlock(&priv->mutex); +} + +static void iwl_bg_post_associate(struct work_struct *data) +{ + struct iwl_priv *priv = container_of(data, struct iwl_priv, + post_associate.work); + + int rc = 0; + struct ieee80211_conf *conf = NULL; + + if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { + IWL_ERROR("%s Should not be called in AP mode\n", __FUNCTION__); + return; + } + + IWL_DEBUG_ASSOC("Associated as %d to: " MAC_FMT "\n", + priv->assoc_id, MAC_ARG(priv->active_rxon.bssid_addr)); + + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + mutex_lock(&priv->mutex); + + conf = ieee80211_get_hw_conf(priv->hw); + + priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; + iwl_commit_rxon(priv); + + memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd)); + iwl_setup_rxon_timing(priv); + rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING, + sizeof(priv->rxon_timing), &priv->rxon_timing); + if (rc) + IWL_WARNING("REPLY_RXON_TIMING failed - " + "Attempting to continue.\n"); + + priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; + +#ifdef CONFIG_IWLWIFI_HT + if (priv->is_ht_enabled && priv->current_assoc_ht.is_ht) + iwl4965_set_rxon_ht(priv, &priv->current_assoc_ht); + else { + priv->active_rate_ht[0] = 0; + priv->active_rate_ht[1] = 0; + priv->current_channel_width = IWL_CHANNEL_WIDTH_20MHZ; + } +#endif /* CONFIG_IWLWIFI_HT*/ + iwl4965_set_rxon_chain(priv); + priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id); + + IWL_DEBUG_ASSOC("assoc id %d beacon interval %d\n", + priv->assoc_id, priv->beacon_int); + + if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE) + priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; + else + priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK; + + if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) { + if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME) + priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK; + else + priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; + + if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) + priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK; + + } + + iwl_commit_rxon(priv); + + switch (priv->iw_mode) { + case IEEE80211_IF_TYPE_STA: + iwl_rate_scale_init(priv->hw, IWL_AP_ID); + break; + + case IEEE80211_IF_TYPE_IBSS: + + /* clear out the station table */ + iwl_clear_stations_table(priv); + + iwl_rxon_add_station(priv, BROADCAST_ADDR, 0); + iwl_rxon_add_station(priv, priv->bssid, 0); + iwl_rate_scale_init(priv->hw, IWL_STA_ID); + iwl_send_beacon_cmd(priv); + + break; + + default: + IWL_ERROR("%s Should not be called in %d mode\n", + __FUNCTION__, priv->iw_mode); + break; + } + + iwl_sequence_reset(priv); + +#ifdef CONFIG_IWLWIFI_SENSITIVITY + /* Enable Rx differential gain and sensitivity calibrations */ + iwl4965_chain_noise_reset(priv); + priv->start_calib = 1; +#endif /* CONFIG_IWLWIFI_SENSITIVITY */ + + if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) + priv->assoc_station_added = 1; + +#ifdef CONFIG_IWLWIFI_QOS + iwl_activate_qos(priv, 0); +#endif /* CONFIG_IWLWIFI_QOS */ + mutex_unlock(&priv->mutex); +} + +static void iwl_bg_abort_scan(struct work_struct *work) +{ + struct iwl_priv *priv = container_of(work, struct iwl_priv, + abort_scan); + + if (!iwl_is_ready(priv)) + return; + + mutex_lock(&priv->mutex); + + set_bit(STATUS_SCAN_ABORTING, &priv->status); + iwl_send_scan_abort(priv); + + mutex_unlock(&priv->mutex); +} + +static void iwl_bg_scan_completed(struct work_struct *work) +{ + struct iwl_priv *priv = + container_of(work, struct iwl_priv, scan_completed); + + IWL_DEBUG(IWL_DL_INFO | IWL_DL_SCAN, "SCAN complete scan\n"); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + ieee80211_scan_completed(priv->hw); + + /* Since setting the TXPOWER may have been deferred while + * performing the scan, fire one off */ + mutex_lock(&priv->mutex); + iwl_hw_reg_send_txpower(priv); + mutex_unlock(&priv->mutex); +} + +/***************************************************************************** + * + * mac80211 entry point functions + * + *****************************************************************************/ + +static int iwl_mac_open(struct ieee80211_hw *hw) +{ + struct iwl_priv *priv = hw->priv; + + IWL_DEBUG_MAC80211("enter\n"); + + /* we should be verifying the device is ready to be opened */ + mutex_lock(&priv->mutex); + + priv->is_open = 1; + + if (!iwl_is_rfkill(priv)) + ieee80211_start_queues(priv->hw); + + mutex_unlock(&priv->mutex); + IWL_DEBUG_MAC80211("leave\n"); + return 0; +} + +static int iwl_mac_stop(struct ieee80211_hw *hw) +{ + struct iwl_priv *priv = hw->priv; + + IWL_DEBUG_MAC80211("enter\n"); + priv->is_open = 0; + /*netif_stop_queue(dev); */ + flush_workqueue(priv->workqueue); + IWL_DEBUG_MAC80211("leave\n"); + + return 0; +} + +static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ieee80211_tx_control *ctl) +{ + struct iwl_priv *priv = hw->priv; + + IWL_DEBUG_MAC80211("enter\n"); + + if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) { + IWL_DEBUG_MAC80211("leave - monitor\n"); + return -1; + } + + IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len, + ctl->tx_rate); + + if (iwl_tx_skb(priv, skb, ctl)) + dev_kfree_skb_any(skb); + + IWL_DEBUG_MAC80211("leave\n"); + return 0; +} + +static int iwl_mac_add_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct iwl_priv *priv = hw->priv; + unsigned long flags; + + IWL_DEBUG_MAC80211("enter: id %d, type %d\n", conf->if_id, conf->type); + if (conf->mac_addr) + IWL_DEBUG_MAC80211("enter: MAC " MAC_FMT "\n", + MAC_ARG(conf->mac_addr)); + + if (priv->interface_id) { + IWL_DEBUG_MAC80211("leave - interface_id != 0\n"); + return 0; + } + + spin_lock_irqsave(&priv->lock, flags); + priv->interface_id = conf->if_id; + + spin_unlock_irqrestore(&priv->lock, flags); + + mutex_lock(&priv->mutex); + iwl_set_mode(priv, conf->type); + + IWL_DEBUG_MAC80211("leave\n"); + mutex_unlock(&priv->mutex); + + return 0; +} + +/** + * iwl_mac_config - mac80211 config callback + * + * We ignore conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME since it seems to + * be set inappropriately and the driver currently sets the hardware up to + * use it whenever needed. + */ +static int iwl_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) +{ + struct iwl_priv *priv = hw->priv; + const struct iwl_channel_info *ch_info; + unsigned long flags; + + mutex_lock(&priv->mutex); + IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel); + + if (!iwl_is_ready(priv)) { + IWL_DEBUG_MAC80211("leave - not ready\n"); + mutex_unlock(&priv->mutex); + return -EIO; + } + + /* TODO: Figure out how to get ieee80211_local->sta_scanning w/ only + * what is exposed through include/ declrations */ + if (unlikely(!iwl_param_disable_hw_scan && + test_bit(STATUS_SCANNING, &priv->status))) { + IWL_DEBUG_MAC80211("leave - scanning\n"); + mutex_unlock(&priv->mutex); + return 0; + } + + spin_lock_irqsave(&priv->lock, flags); + + ch_info = iwl_get_channel_info(priv, conf->phymode, conf->channel); + if (!is_channel_valid(ch_info)) { + IWL_DEBUG_SCAN("Channel %d [%d] is INVALID for this SKU.\n", + conf->channel, conf->phymode); + IWL_DEBUG_MAC80211("leave - invalid channel\n"); + spin_unlock_irqrestore(&priv->lock, flags); + mutex_unlock(&priv->mutex); + return -EINVAL; + } + +#ifdef CONFIG_IWLWIFI_HT + /* if we are switching fron ht to 2.4 clear flags + * from any ht related info since 2.4 does not + * support ht */ + if ((le16_to_cpu(priv->staging_rxon.channel) != conf->channel) +#ifdef IEEE80211_CONF_CHANNEL_SWITCH + && !(conf->flags & IEEE80211_CONF_CHANNEL_SWITCH) +#endif + ) + priv->staging_rxon.flags = 0; +#endif /* CONFIG_IWLWIFI_HT */ + + iwl_set_rxon_channel(priv, conf->phymode, conf->channel); + + iwl_set_flags_for_phymode(priv, conf->phymode); + + /* The list of supported rates and rate mask can be different + * for each phymode; since the phymode may have changed, reset + * the rate mask to what mac80211 lists */ + iwl_set_rate(priv); + + spin_unlock_irqrestore(&priv->lock, flags); + +#ifdef IEEE80211_CONF_CHANNEL_SWITCH + if (conf->flags & IEEE80211_CONF_CHANNEL_SWITCH) { + iwl_hw_channel_switch(priv, conf->channel); + mutex_unlock(&priv->mutex); + return 0; + } +#endif + + iwl_radio_kill_sw(priv, !conf->radio_enabled); + + if (!conf->radio_enabled) { + IWL_DEBUG_MAC80211("leave - radio disabled\n"); + mutex_unlock(&priv->mutex); + return 0; + } + + if (iwl_is_rfkill(priv)) { + IWL_DEBUG_MAC80211("leave - RF kill\n"); + mutex_unlock(&priv->mutex); + return -EIO; + } + + iwl_set_rate(priv); + + if (memcmp(&priv->active_rxon, + &priv->staging_rxon, sizeof(priv->staging_rxon))) + iwl_commit_rxon(priv); + else + IWL_DEBUG_INFO("No re-sending same RXON configuration.\n"); + + IWL_DEBUG_MAC80211("leave\n"); + + mutex_unlock(&priv->mutex); + + return 0; +} + +static void iwl_config_ap(struct iwl_priv *priv) +{ + int rc = 0; + + if (priv->status & STATUS_EXIT_PENDING) + return; + + /* The following should be done only at AP bring up */ + if ((priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) == 0) { + + /* RXON - unassoc (to set timing command) */ + priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; + iwl_commit_rxon(priv); + + /* RXON Timing */ + memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd)); + iwl_setup_rxon_timing(priv); + rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING, + sizeof(priv->rxon_timing), &priv->rxon_timing); + if (rc) + IWL_WARNING("REPLY_RXON_TIMING failed - " + "Attempting to continue.\n"); + + iwl4965_set_rxon_chain(priv); + + /* FIXME: what should be the assoc_id for AP? */ + priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id); + if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE) + priv->staging_rxon.flags |= + RXON_FLG_SHORT_PREAMBLE_MSK; + else + priv->staging_rxon.flags &= + ~RXON_FLG_SHORT_PREAMBLE_MSK; + + if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) { + if (priv->assoc_capability & + WLAN_CAPABILITY_SHORT_SLOT_TIME) + priv->staging_rxon.flags |= + RXON_FLG_SHORT_SLOT_MSK; + else + priv->staging_rxon.flags &= + ~RXON_FLG_SHORT_SLOT_MSK; + + if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) + priv->staging_rxon.flags &= + ~RXON_FLG_SHORT_SLOT_MSK; + } + /* restore RXON assoc */ + priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; + iwl_commit_rxon(priv); +#ifdef CONFIG_IWLWIFI_QOS + iwl_activate_qos(priv, 1); +#endif + iwl_rxon_add_station(priv, BROADCAST_ADDR, 0); + iwl_send_beacon_cmd(priv); + } else + iwl_send_beacon_cmd(priv); + + /* FIXME - we need to add code here to detect a totally new + * configuration, reset the AP, unassoc, rxon timing, assoc, + * clear sta table, add BCAST sta... */ +} + +static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id, + struct ieee80211_if_conf *conf) +{ + struct iwl_priv *priv = hw->priv; + unsigned long flags; + int rc; + + if (conf == NULL) + return -EIO; + + if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) && + (!conf->beacon || !conf->ssid_len)) { + IWL_DEBUG_MAC80211 + ("Leaving in AP mode because HostAPD is not ready.\n"); + return 0; + } + + mutex_lock(&priv->mutex); + + IWL_DEBUG_MAC80211("enter: interface id %d\n", if_id); + if (conf->bssid) + IWL_DEBUG_MAC80211("bssid: " MAC_FMT "\n", + MAC_ARG(conf->bssid)); + + if (unlikely(test_bit(STATUS_SCANNING, &priv->status)) && + !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) { + IWL_DEBUG_MAC80211("leave - scanning\n"); + mutex_unlock(&priv->mutex); + return 0; + } + + if (priv->interface_id != if_id) { + IWL_DEBUG_MAC80211("leave - interface_id != if_id\n"); + mutex_unlock(&priv->mutex); + return 0; + } + + if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { + if (!conf->bssid) { + conf->bssid = priv->mac_addr; + memcpy(priv->bssid, priv->mac_addr, ETH_ALEN); + IWL_DEBUG_MAC80211("bssid was set to: " MAC_FMT "\n", + MAC_ARG(conf->bssid)); + } + if (priv->ibss_beacon) + dev_kfree_skb(priv->ibss_beacon); + + priv->ibss_beacon = conf->beacon; + } + + if (conf->bssid && !is_zero_ether_addr(conf->bssid) && + !is_multicast_ether_addr(conf->bssid)) { + /* If there is currently a HW scan going on in the background + * then we need to cancel it else the RXON below will fail. */ + if (iwl_scan_cancel_timeout(priv, 100)) { + IWL_WARNING("Aborted scan still in progress " + "after 100ms\n"); + IWL_DEBUG_MAC80211("leaving - scan abort failed.\n"); + mutex_unlock(&priv->mutex); + return -EAGAIN; + } + memcpy(priv->staging_rxon.bssid_addr, conf->bssid, ETH_ALEN); + + /* TODO: Audit driver for usage of these members and see + * if mac80211 deprecates them (priv->bssid looks like it + * shouldn't be there, but I haven't scanned the IBSS code + * to verify) - jpk */ + memcpy(priv->bssid, conf->bssid, ETH_ALEN); + + if (priv->iw_mode == IEEE80211_IF_TYPE_AP) + iwl_config_ap(priv); + else { + priv->staging_rxon.filter_flags |= + RXON_FILTER_ASSOC_MSK; + rc = iwl_commit_rxon(priv); + if ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && rc) + iwl_rxon_add_station( + priv, priv->active_rxon.bssid_addr, 1); + } + + } else { + priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; + iwl_commit_rxon(priv); + } + + spin_lock_irqsave(&priv->lock, flags); + if (!conf->ssid_len) + memset(priv->essid, 0, IW_ESSID_MAX_SIZE); + else + memcpy(priv->essid, conf->ssid, conf->ssid_len); + + priv->essid_len = conf->ssid_len; + spin_unlock_irqrestore(&priv->lock, flags); + + IWL_DEBUG_MAC80211("leave\n"); + mutex_unlock(&priv->mutex); + + return 0; +} + +static void iwl_mac_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct iwl_priv *priv = hw->priv; + + IWL_DEBUG_MAC80211("enter\n"); + + mutex_lock(&priv->mutex); + if (priv->interface_id == conf->if_id) { + priv->interface_id = 0; + memset(priv->bssid, 0, ETH_ALEN); + memset(priv->essid, 0, IW_ESSID_MAX_SIZE); + priv->essid_len = 0; + } + mutex_unlock(&priv->mutex); + + IWL_DEBUG_MAC80211("leave\n"); + +} + +#define IWL_DELAY_NEXT_SCAN (HZ*2) +static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len) +{ + int rc = 0; + unsigned long flags; + struct iwl_priv *priv = hw->priv; + + IWL_DEBUG_MAC80211("enter\n"); + + spin_lock_irqsave(&priv->lock, flags); + + if (!iwl_is_ready_rf(priv)) { + rc = -EIO; + IWL_DEBUG_MAC80211("leave - not ready or exit pending\n"); + goto out_unlock; + } + + if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { /* APs don't scan */ + rc = -EIO; + IWL_ERROR("ERROR: APs don't scan\n"); + goto out_unlock; + } + + /* if we just finished scan ask for delay */ + if (priv->last_scan_jiffies && + time_after(priv->last_scan_jiffies + IWL_DELAY_NEXT_SCAN, + jiffies)) { + rc = -EAGAIN; + goto out_unlock; + } + if (len) { + IWL_DEBUG_SCAN("direct scan for " + "%s [%d]\n ", + iwl_escape_essid(ssid, len), (int)len); + + priv->one_direct_scan = 1; + priv->direct_ssid_len = (u8) + min((u8) len, (u8) IW_ESSID_MAX_SIZE); + memcpy(priv->direct_ssid, ssid, priv->direct_ssid_len); + } + + rc = iwl_scan_initiate(priv); + + IWL_DEBUG_MAC80211("leave\n"); + +out_unlock: + spin_unlock_irqrestore(&priv->lock, flags); + + return rc; +} + +static int iwl_mac_set_key(struct ieee80211_hw *hw, set_key_cmd cmd, + const u8 *local_addr, const u8 *addr, + struct ieee80211_key_conf *key) +{ + struct iwl_priv *priv = hw->priv; + int rc = 0; + u8 sta_id; + + IWL_DEBUG_MAC80211("enter\n"); + + if (!iwl_param_hwcrypto) { + IWL_DEBUG_MAC80211("leave - hwcrypto disabled\n"); + return -EOPNOTSUPP; + } + + if (is_zero_ether_addr(addr)) + /* only support pairwise keys */ + return -EOPNOTSUPP; + + sta_id = iwl_hw_find_station(priv, addr); + if (sta_id == IWL_INVALID_STATION) { + IWL_DEBUG_MAC80211("leave - " MAC_FMT " not in station map.\n", + MAC_ARG(addr)); + return -EINVAL; + } + + mutex_lock(&priv->mutex); + + switch (cmd) { + case SET_KEY: + rc = iwl_update_sta_key_info(priv, key, sta_id); + if (!rc) { + iwl_set_rxon_hwcrypto(priv, 1); + iwl_commit_rxon(priv); + key->hw_key_idx = sta_id; + IWL_DEBUG_MAC80211("set_key success, using hwcrypto\n"); + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + } + break; + case DISABLE_KEY: + rc = iwl_clear_sta_key_info(priv, sta_id); + if (!rc) { + iwl_set_rxon_hwcrypto(priv, 0); + iwl_commit_rxon(priv); + IWL_DEBUG_MAC80211("disable hwcrypto key\n"); + } + break; + default: + rc = -EINVAL; + } + + IWL_DEBUG_MAC80211("leave\n"); + mutex_unlock(&priv->mutex); + + return rc; +} + +static int iwl_mac_conf_tx(struct ieee80211_hw *hw, int queue, + const struct ieee80211_tx_queue_params *params) +{ + struct iwl_priv *priv = hw->priv; +#ifdef CONFIG_IWLWIFI_QOS + unsigned long flags; + int q; +#endif /* CONFIG_IWL_QOS */ + + IWL_DEBUG_MAC80211("enter\n"); + + if (!iwl_is_ready_rf(priv)) { + IWL_DEBUG_MAC80211("leave - RF not ready\n"); + return -EIO; + } + + if (queue >= AC_NUM) { + IWL_DEBUG_MAC80211("leave - queue >= AC_NUM %d\n", queue); + return 0; + } + +#ifdef CONFIG_IWLWIFI_QOS + if (!priv->qos_data.qos_enable) { + priv->qos_data.qos_active = 0; + IWL_DEBUG_MAC80211("leave - qos not enabled\n"); + return 0; + } + q = AC_NUM - 1 - queue; + + spin_lock_irqsave(&priv->lock, flags); + + priv->qos_data.def_qos_parm.ac[q].cw_min = cpu_to_le16(params->cw_min); + priv->qos_data.def_qos_parm.ac[q].cw_max = cpu_to_le16(params->cw_max); + priv->qos_data.def_qos_parm.ac[q].aifsn = params->aifs; + priv->qos_data.def_qos_parm.ac[q].edca_txop = + cpu_to_le16((params->burst_time * 100)); + + priv->qos_data.def_qos_parm.ac[q].reserved1 = 0; + priv->qos_data.qos_active = 1; + + spin_unlock_irqrestore(&priv->lock, flags); + + mutex_lock(&priv->mutex); + if (priv->iw_mode == IEEE80211_IF_TYPE_AP) + iwl_activate_qos(priv, 1); + else if (priv->assoc_id && iwl_is_associated(priv)) + iwl_activate_qos(priv, 0); + + mutex_unlock(&priv->mutex); + +#endif /*CONFIG_IWLWIFI_QOS */ + + IWL_DEBUG_MAC80211("leave\n"); + return 0; +} + +static int iwl_mac_get_tx_stats(struct ieee80211_hw *hw, + struct ieee80211_tx_queue_stats *stats) +{ + struct iwl_priv *priv = hw->priv; + int i, avail; + struct iwl_tx_queue *txq; + struct iwl_queue *q; + unsigned long flags; + + IWL_DEBUG_MAC80211("enter\n"); + + if (!iwl_is_ready_rf(priv)) { + IWL_DEBUG_MAC80211("leave - RF not ready\n"); + return -EIO; + } + + spin_lock_irqsave(&priv->lock, flags); + + for (i = 0; i < AC_NUM; i++) { + txq = &priv->txq[i]; + q = &txq->q; + avail = iwl_queue_space(q); + + stats->data[i].len = q->n_window - avail; + stats->data[i].limit = q->n_window - q->high_mark; + stats->data[i].count = q->n_window; + + } + spin_unlock_irqrestore(&priv->lock, flags); + + IWL_DEBUG_MAC80211("leave\n"); + + return 0; +} + +static int iwl_mac_get_stats(struct ieee80211_hw *hw, + struct ieee80211_low_level_stats *stats) +{ + IWL_DEBUG_MAC80211("enter\n"); + IWL_DEBUG_MAC80211("leave\n"); + + return 0; +} + +static u64 iwl_mac_get_tsf(struct ieee80211_hw *hw) +{ + IWL_DEBUG_MAC80211("enter\n"); + IWL_DEBUG_MAC80211("leave\n"); + + return 0; +} + +static void iwl_mac_reset_tsf(struct ieee80211_hw *hw) +{ + struct iwl_priv *priv = hw->priv; + unsigned long flags; + + mutex_lock(&priv->mutex); + IWL_DEBUG_MAC80211("enter\n"); + + priv->lq_mngr.lq_ready = 0; +#ifdef CONFIG_IWLWIFI_HT + spin_lock_irqsave(&priv->lock, flags); + memset(&priv->current_assoc_ht, 0, sizeof(struct sta_ht_info)); + spin_unlock_irqrestore(&priv->lock, flags); +#ifdef CONFIG_IWLWIFI_HT_AGG +/* if (priv->lq_mngr.agg_ctrl.granted_ba) + iwl4965_turn_off_agg(priv, TID_ALL_SPECIFIED);*/ + + memset(&(priv->lq_mngr.agg_ctrl), 0, sizeof(struct iwl_agg_control)); + priv->lq_mngr.agg_ctrl.tid_traffic_load_threshold = 10; + priv->lq_mngr.agg_ctrl.ba_timeout = 5000; + priv->lq_mngr.agg_ctrl.auto_agg = 1; + + if (priv->lq_mngr.agg_ctrl.auto_agg) + priv->lq_mngr.agg_ctrl.requested_ba = TID_ALL_ENABLED; +#endif /*CONFIG_IWLWIFI_HT_AGG */ +#endif /* CONFIG_IWLWIFI_HT */ + +#ifdef CONFIG_IWLWIFI_QOS + iwl_reset_qos(priv); +#endif + + cancel_delayed_work(&priv->post_associate); + + spin_lock_irqsave(&priv->lock, flags); + priv->assoc_id = 0; + priv->assoc_capability = 0; + priv->call_post_assoc_from_beacon = 0; + priv->assoc_station_added = 0; + + /* new association get rid of ibss beacon skb */ + if (priv->ibss_beacon) + dev_kfree_skb(priv->ibss_beacon); + + priv->ibss_beacon = NULL; + + priv->beacon_int = priv->hw->conf.beacon_int; + priv->timestamp1 = 0; + priv->timestamp0 = 0; + if ((priv->iw_mode == IEEE80211_IF_TYPE_STA)) + priv->beacon_int = 0; + + spin_unlock_irqrestore(&priv->lock, flags); + + /* Per mac80211.h: This is only used in IBSS mode... */ + if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) { + IWL_DEBUG_MAC80211("leave - not in IBSS\n"); + mutex_unlock(&priv->mutex); + return; + } + + if (!iwl_is_ready_rf(priv)) { + IWL_DEBUG_MAC80211("leave - not ready\n"); + mutex_unlock(&priv->mutex); + return; + } + + priv->only_active_channel = 0; + + iwl_set_rate(priv); + + mutex_unlock(&priv->mutex); + + IWL_DEBUG_MAC80211("leave\n"); + +} + +static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ieee80211_tx_control *control) +{ + struct iwl_priv *priv = hw->priv; + unsigned long flags; + + mutex_lock(&priv->mutex); + IWL_DEBUG_MAC80211("enter\n"); + + if (!iwl_is_ready_rf(priv)) { + IWL_DEBUG_MAC80211("leave - RF not ready\n"); + mutex_unlock(&priv->mutex); + return -EIO; + } + + if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) { + IWL_DEBUG_MAC80211("leave - not IBSS\n"); + mutex_unlock(&priv->mutex); + return -EIO; + } + + spin_lock_irqsave(&priv->lock, flags); + + if (priv->ibss_beacon) + dev_kfree_skb(priv->ibss_beacon); + + priv->ibss_beacon = skb; + + priv->assoc_id = 0; + + IWL_DEBUG_MAC80211("leave\n"); + spin_unlock_irqrestore(&priv->lock, flags); + +#ifdef CONFIG_IWLWIFI_QOS + iwl_reset_qos(priv); +#endif + + queue_work(priv->workqueue, &priv->post_associate.work); + + mutex_unlock(&priv->mutex); + + return 0; +} + +#ifdef CONFIG_IWLWIFI_HT +union ht_cap_info { + struct { + u16 advanced_coding_cap :1; + u16 supported_chan_width_set :1; + u16 mimo_power_save_mode :2; + u16 green_field :1; + u16 short_GI20 :1; + u16 short_GI40 :1; + u16 tx_stbc :1; + u16 rx_stbc :1; + u16 beam_forming :1; + u16 delayed_ba :1; + u16 maximal_amsdu_size :1; + u16 cck_mode_at_40MHz :1; + u16 psmp_support :1; + u16 stbc_ctrl_frame_support :1; + u16 sig_txop_protection_support :1; + }; + u16 val; +} __attribute__ ((packed)); + +union ht_param_info{ + struct { + u8 max_rx_ampdu_factor :2; + u8 mpdu_density :3; + u8 reserved :3; + }; + u8 val; +} __attribute__ ((packed)); + +union ht_exra_param_info { + struct { + u8 ext_chan_offset :2; + u8 tx_chan_width :1; + u8 rifs_mode :1; + u8 controlled_access_only :1; + u8 service_interval_granularity :3; + }; + u8 val; +} __attribute__ ((packed)); + +union ht_operation_mode{ + struct { + u16 op_mode :2; + u16 non_GF :1; + u16 reserved :13; + }; + u16 val; +} __attribute__ ((packed)); + + +static int sta_ht_info_init(struct ieee80211_ht_capability *ht_cap, + struct ieee80211_ht_additional_info *ht_extra, + struct sta_ht_info *ht_info_ap, + struct sta_ht_info *ht_info) +{ + union ht_cap_info cap; + union ht_operation_mode op_mode; + union ht_param_info param_info; + union ht_exra_param_info extra_param_info; + + IWL_DEBUG_MAC80211("enter: \n"); + + if (!ht_info) { + IWL_DEBUG_MAC80211("leave: ht_info is NULL\n"); + return -1; + } + + if (ht_cap) { + cap.val = (u16) le16_to_cpu(ht_cap->capabilities_info); + param_info.val = ht_cap->mac_ht_params_info; + ht_info->is_ht = 1; + if (cap.short_GI20) + ht_info->sgf |= 0x1; + if (cap.short_GI40) + ht_info->sgf |= 0x2; + ht_info->is_green_field = cap.green_field; + ht_info->max_amsdu_size = cap.maximal_amsdu_size; + ht_info->supported_chan_width = cap.supported_chan_width_set; + ht_info->tx_mimo_ps_mode = cap.mimo_power_save_mode; + memcpy(ht_info->supp_rates, ht_cap->supported_mcs_set, 16); + + ht_info->ampdu_factor = param_info.max_rx_ampdu_factor; + ht_info->mpdu_density = param_info.mpdu_density; + + IWL_DEBUG_MAC80211("SISO mask 0x%X MIMO mask 0x%X \n", + ht_cap->supported_mcs_set[0], + ht_cap->supported_mcs_set[1]); + + if (ht_info_ap) { + ht_info->control_channel = ht_info_ap->control_channel; + ht_info->extension_chan_offset = + ht_info_ap->extension_chan_offset; + ht_info->tx_chan_width = ht_info_ap->tx_chan_width; + ht_info->operating_mode = ht_info_ap->operating_mode; + } + + if (ht_extra) { + extra_param_info.val = ht_extra->ht_param; + ht_info->control_channel = ht_extra->control_chan; + ht_info->extension_chan_offset = + extra_param_info.ext_chan_offset; + ht_info->tx_chan_width = extra_param_info.tx_chan_width; + op_mode.val = (u16) + le16_to_cpu(ht_extra->operation_mode); + ht_info->operating_mode = op_mode.op_mode; + IWL_DEBUG_MAC80211("control channel %d\n", + ht_extra->control_chan); + } + } else + ht_info->is_ht = 0; + + IWL_DEBUG_MAC80211("leave\n"); + return 0; +} + +static int iwl_mac_conf_ht(struct ieee80211_hw *hw, + struct ieee80211_ht_capability *ht_cap, + struct ieee80211_ht_additional_info *ht_extra) +{ + struct iwl_priv *priv = hw->priv; + int rs; + + IWL_DEBUG_MAC80211("enter: \n"); + + rs = sta_ht_info_init(ht_cap, ht_extra, NULL, &priv->current_assoc_ht); + iwl4965_set_rxon_chain(priv); + + if (priv && priv->assoc_id && + (priv->iw_mode == IEEE80211_IF_TYPE_STA)) { + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + if (priv->beacon_int) + queue_work(priv->workqueue, &priv->post_associate.work); + else + priv->call_post_assoc_from_beacon = 1; + spin_unlock_irqrestore(&priv->lock, flags); + } + + IWL_DEBUG_MAC80211("leave: control channel %d\n", + ht_extra->control_chan); + return rs; + +} + +static void iwl_set_ht_capab(struct ieee80211_hw *hw, + struct ieee80211_ht_capability *ht_cap, + u8 use_wide_chan) +{ + union ht_cap_info cap; + union ht_param_info param_info; + + memset(&cap, 0, sizeof(union ht_cap_info)); + memset(¶m_info, 0, sizeof(union ht_param_info)); + + cap.maximal_amsdu_size = HT_IE_MAX_AMSDU_SIZE_4K; + cap.green_field = 1; + cap.short_GI20 = 1; + cap.short_GI40 = 1; + cap.supported_chan_width_set = use_wide_chan; + cap.mimo_power_save_mode = 0x3; + + param_info.max_rx_ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF; + param_info.mpdu_density = CFG_HT_MPDU_DENSITY_DEF; + ht_cap->capabilities_info = (__le16) cpu_to_le16(cap.val); + ht_cap->mac_ht_params_info = (u8) param_info.val; + + ht_cap->supported_mcs_set[0] = 0xff; + ht_cap->supported_mcs_set[1] = 0xff; + ht_cap->supported_mcs_set[4] = + (cap.supported_chan_width_set) ? 0x1: 0x0; +} + +static void iwl_mac_get_ht_capab(struct ieee80211_hw *hw, + struct ieee80211_ht_capability *ht_cap) +{ + u8 use_wide_channel = 1; + struct iwl_priv *priv = hw->priv; + + IWL_DEBUG_MAC80211("enter: \n"); + if (priv->channel_width != IWL_CHANNEL_WIDTH_40MHZ) + use_wide_channel = 0; + + /* no fat tx allowed on 2.4GHZ */ + if (priv->phymode != MODE_IEEE80211A) + use_wide_channel = 0; + + iwl_set_ht_capab(hw, ht_cap, use_wide_channel); + IWL_DEBUG_MAC80211("leave: \n"); +} +#endif /*CONFIG_IWLWIFI_HT*/ + +/***************************************************************************** + * + * sysfs attributes + * + *****************************************************************************/ + +#ifdef CONFIG_IWLWIFI_DEBUG + +/* + * The following adds a new attribute to the sysfs representation + * of this device driver (i.e. a new file in /sys/bus/pci/drivers/iwl/) + * used for controlling the debug level. + * + * See the level definitions in iwl for details. + */ + +static ssize_t show_debug_level(struct device_driver *d, char *buf) +{ + return sprintf(buf, "0x%08X\n", iwl_debug_level); +} +static ssize_t store_debug_level(struct device_driver *d, + const char *buf, size_t count) +{ + char *p = (char *)buf; + u32 val; + + val = simple_strtoul(p, &p, 0); + if (p == buf) + printk(KERN_INFO DRV_NAME + ": %s is not in hex or decimal form.\n", buf); + else + iwl_debug_level = val; + + return strnlen(buf, count); +} + +static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO, + show_debug_level, store_debug_level); + +#endif /* CONFIG_IWLWIFI_DEBUG */ + +static ssize_t show_rf_kill(struct device *d, + struct device_attribute *attr, char *buf) +{ + /* + * 0 - RF kill not enabled + * 1 - SW based RF kill active (sysfs) + * 2 - HW based RF kill active + * 3 - Both HW and SW based RF kill active + */ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + int val = (test_bit(STATUS_RF_KILL_SW, &priv->status) ? 0x1 : 0x0) | + (test_bit(STATUS_RF_KILL_HW, &priv->status) ? 0x2 : 0x0); + + return sprintf(buf, "%i\n", val); +} + +static ssize_t store_rf_kill(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + + mutex_lock(&priv->mutex); + iwl_radio_kill_sw(priv, buf[0] == '1'); + mutex_unlock(&priv->mutex); + + return count; +} + +static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill); + +static ssize_t show_temperature(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + + if (!iwl_is_alive(priv)) + return -EAGAIN; + + return sprintf(buf, "%d\n", iwl_hw_get_temperature(priv)); +} + +static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL); + +static ssize_t show_rs_window(struct device *d, + struct device_attribute *attr, + char *buf) +{ + struct iwl_priv *priv = d->driver_data; + return iwl_fill_rs_info(priv->hw, buf, IWL_AP_ID); +} +static DEVICE_ATTR(rs_window, S_IRUGO, show_rs_window, NULL); + +static ssize_t show_tx_power(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + return sprintf(buf, "%d\n", priv->user_txpower_limit); +} + +static ssize_t store_tx_power(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + char *p = (char *)buf; + u32 val; + + val = simple_strtoul(p, &p, 10); + if (p == buf) + printk(KERN_INFO DRV_NAME + ": %s is not in decimal form.\n", buf); + else + iwl_hw_reg_set_txpower(priv, val); + + return count; +} + +static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power); + +static ssize_t show_flags(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + + return sprintf(buf, "0x%04X\n", priv->active_rxon.flags); +} + +static ssize_t store_flags(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + u32 flags = simple_strtoul(buf, NULL, 0); + + mutex_lock(&priv->mutex); + if (le32_to_cpu(priv->staging_rxon.flags) != flags) { + /* Cancel any currently running scans... */ + if (iwl_scan_cancel_timeout(priv, 100)) + IWL_WARNING("Could not cancel scan.\n"); + else { + IWL_DEBUG_INFO("Committing rxon.flags = 0x%04X\n", + flags); + priv->staging_rxon.flags = cpu_to_le32(flags); + iwl_commit_rxon(priv); + } + } + mutex_unlock(&priv->mutex); + + return count; +} + +static DEVICE_ATTR(flags, S_IWUSR | S_IRUGO, show_flags, store_flags); + +static ssize_t show_filter_flags(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + + return sprintf(buf, "0x%04X\n", + le32_to_cpu(priv->active_rxon.filter_flags)); +} + +static ssize_t store_filter_flags(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + u32 filter_flags = simple_strtoul(buf, NULL, 0); + + mutex_lock(&priv->mutex); + if (le32_to_cpu(priv->staging_rxon.filter_flags) != filter_flags) { + /* Cancel any currently running scans... */ + if (iwl_scan_cancel_timeout(priv, 100)) + IWL_WARNING("Could not cancel scan.\n"); + else { + IWL_DEBUG_INFO("Committing rxon.filter_flags = " + "0x%04X\n", filter_flags); + priv->staging_rxon.filter_flags = + cpu_to_le32(filter_flags); + iwl_commit_rxon(priv); + } + } + mutex_unlock(&priv->mutex); + + return count; +} + +static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags, + store_filter_flags); + +static ssize_t show_tune(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + + return sprintf(buf, "0x%04X\n", + (priv->phymode << 8) | + le16_to_cpu(priv->active_rxon.channel)); +} + +static void iwl_set_flags_for_phymode(struct iwl_priv *priv, u8 phymode); + +static ssize_t store_tune(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + char *p = (char *)buf; + u16 tune = simple_strtoul(p, &p, 0); + u8 phymode = (tune >> 8) & 0xff; + u16 channel = tune & 0xff; + + IWL_DEBUG_INFO("Tune request to:%d channel:%d\n", phymode, channel); + + mutex_lock(&priv->mutex); + if ((le16_to_cpu(priv->staging_rxon.channel) != channel) || + (priv->phymode != phymode)) { + const struct iwl_channel_info *ch_info; + + ch_info = iwl_get_channel_info(priv, phymode, channel); + if (!ch_info) { + IWL_WARNING("Requested invalid phymode/channel " + "combination: %d %d\n", phymode, channel); + mutex_unlock(&priv->mutex); + return -EINVAL; + } + + /* Cancel any currently running scans... */ + if (iwl_scan_cancel_timeout(priv, 100)) + IWL_WARNING("Could not cancel scan.\n"); + else { + IWL_DEBUG_INFO("Committing phymode and " + "rxon.channel = %d %d\n", + phymode, channel); + + iwl_set_rxon_channel(priv, phymode, channel); + iwl_set_flags_for_phymode(priv, phymode); + + iwl_set_rate(priv); + iwl_commit_rxon(priv); + } + } + mutex_unlock(&priv->mutex); + + return count; +} + +static DEVICE_ATTR(tune, S_IWUSR | S_IRUGO, show_tune, store_tune); + +#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT + +static ssize_t show_measurement(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + struct iwl_spectrum_notification measure_report; + u32 size = sizeof(measure_report), len = 0, ofs = 0; + u8 *data = (u8 *) & measure_report; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + if (!(priv->measurement_status & MEASUREMENT_READY)) { + spin_unlock_irqrestore(&priv->lock, flags); + return 0; + } + memcpy(&measure_report, &priv->measure_report, size); + priv->measurement_status = 0; + spin_unlock_irqrestore(&priv->lock, flags); + + while (size && (PAGE_SIZE - len)) { + hex_dump_to_buffer(data + ofs, size, 16, 1, buf + len, + PAGE_SIZE - len, 1); + len = strlen(buf); + if (PAGE_SIZE - len) + buf[len++] = '\n'; + + ofs += 16; + size -= min(size, 16U); + } + + return len; +} + +static ssize_t store_measurement(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + struct ieee80211_measurement_params params = { + .channel = le16_to_cpu(priv->active_rxon.channel), + .start_time = cpu_to_le64(priv->last_tsf), + .duration = cpu_to_le16(1), + }; + u8 type = IWL_MEASURE_BASIC; + u8 buffer[32]; + u8 channel; + + if (count) { + char *p = buffer; + strncpy(buffer, buf, min(sizeof(buffer), count)); + channel = simple_strtoul(p, NULL, 0); + if (channel) + params.channel = channel; + + p = buffer; + while (*p && *p != ' ') + p++; + if (*p) + type = simple_strtoul(p + 1, NULL, 0); + } + + IWL_DEBUG_INFO("Invoking measurement of type %d on " + "channel %d (for '%s')\n", type, params.channel, buf); + iwl_get_measurement(priv, ¶ms, type); + + return count; +} + +static DEVICE_ATTR(measurement, S_IRUSR | S_IWUSR, + show_measurement, store_measurement); +#endif /* CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT */ + +static ssize_t store_retry_rate(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + + priv->retry_rate = simple_strtoul(buf, NULL, 0); + if (priv->retry_rate <= 0) + priv->retry_rate = 1; + + return count; +} + +static ssize_t show_retry_rate(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + return sprintf(buf, "%d", priv->retry_rate); +} + +static DEVICE_ATTR(retry_rate, S_IWUSR | S_IRUSR, show_retry_rate, + store_retry_rate); + +static ssize_t store_power_level(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + int rc; + int mode; + + mode = simple_strtoul(buf, NULL, 0); + mutex_lock(&priv->mutex); + + if (!iwl_is_ready(priv)) { + rc = -EAGAIN; + goto out; + } + + if ((mode < 1) || (mode > IWL_POWER_LIMIT) || (mode == IWL_POWER_AC)) + mode = IWL_POWER_AC; + else + mode |= IWL_POWER_ENABLED; + + if (mode != priv->power_mode) { + rc = iwl_send_power_mode(priv, IWL_POWER_LEVEL(mode)); + if (rc) { + IWL_DEBUG_MAC80211("failed setting power mode.\n"); + goto out; + } + priv->power_mode = mode; + } + + rc = count; + + out: + mutex_unlock(&priv->mutex); + return rc; +} + +#define MAX_WX_STRING 80 + +/* Values are in microsecond */ +static const s32 timeout_duration[] = { + 350000, + 250000, + 75000, + 37000, + 25000, +}; +static const s32 period_duration[] = { + 400000, + 700000, + 1000000, + 1000000, + 1000000 +}; + +static ssize_t show_power_level(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + int level = IWL_POWER_LEVEL(priv->power_mode); + char *p = buf; + + p += sprintf(p, "%d ", level); + switch (level) { + case IWL_POWER_MODE_CAM: + case IWL_POWER_AC: + p += sprintf(p, "(AC)"); + break; + case IWL_POWER_BATTERY: + p += sprintf(p, "(BATTERY)"); + break; + default: + p += sprintf(p, + "(Timeout %dms, Period %dms)", + timeout_duration[level - 1] / 1000, + period_duration[level - 1] / 1000); + } + + if (!(priv->power_mode & IWL_POWER_ENABLED)) + p += sprintf(p, " OFF\n"); + else + p += sprintf(p, " \n"); + + return (p - buf + 1); + +} + +static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level, + store_power_level); + +static ssize_t show_channels(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + int len = 0, i; + struct ieee80211_channel *channels = NULL; + const struct ieee80211_hw_mode *hw_mode = NULL; + int count = 0; + + if (!iwl_is_ready(priv)) + return -EAGAIN; + + hw_mode = iwl_get_hw_mode(priv, MODE_IEEE80211G); + if (!hw_mode) + hw_mode = iwl_get_hw_mode(priv, MODE_IEEE80211B); + if (hw_mode) { + channels = hw_mode->channels; + count = hw_mode->num_channels; + } + + len += + sprintf(&buf[len], + "Displaying %d channels in 2.4GHz band " + "(802.11bg):\n", count); + + for (i = 0; i < count; i++) + len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n", + channels[i].chan, + channels[i].power_level, + channels[i]. + flag & IEEE80211_CHAN_W_RADAR_DETECT ? + " (IEEE 802.11h required)" : "", + (!(channels[i].flag & IEEE80211_CHAN_W_IBSS) + || (channels[i]. + flag & + IEEE80211_CHAN_W_RADAR_DETECT)) ? "" : + ", IBSS", + channels[i]. + flag & IEEE80211_CHAN_W_ACTIVE_SCAN ? + "active/passive" : "passive only"); + + hw_mode = iwl_get_hw_mode(priv, MODE_IEEE80211A); + if (hw_mode) { + channels = hw_mode->channels; + count = hw_mode->num_channels; + } else { + channels = NULL; + count = 0; + } + + len += sprintf(&buf[len], "Displaying %d channels in 5.2GHz band " + "(802.11a):\n", count); + + for (i = 0; i < count; i++) + len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n", + channels[i].chan, + channels[i].power_level, + channels[i]. + flag & IEEE80211_CHAN_W_RADAR_DETECT ? + " (IEEE 802.11h required)" : "", + (!(channels[i].flag & IEEE80211_CHAN_W_IBSS) + || (channels[i]. + flag & + IEEE80211_CHAN_W_RADAR_DETECT)) ? "" : + ", IBSS", + channels[i]. + flag & IEEE80211_CHAN_W_ACTIVE_SCAN ? + "active/passive" : "passive only"); + + return len; +} + +static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL); + +static ssize_t show_statistics(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + u32 size = sizeof(struct iwl_notif_statistics); + u32 len = 0, ofs = 0; + u8 *data = (u8 *) & priv->statistics; + int rc = 0; + + if (!iwl_is_alive(priv)) + return -EAGAIN; + + mutex_lock(&priv->mutex); + rc = iwl_send_statistics_request(priv); + mutex_unlock(&priv->mutex); + + if (rc) { + len = sprintf(buf, + "Error sending statistics request: 0x%08X\n", rc); + return len; + } + + while (size && (PAGE_SIZE - len)) { + hex_dump_to_buffer(data + ofs, size, 16, 1, buf + len, + PAGE_SIZE - len, 1); + len = strlen(buf); + if (PAGE_SIZE - len) + buf[len++] = '\n'; + + ofs += 16; + size -= min(size, 16U); + } + + return len; +} + +static DEVICE_ATTR(statistics, S_IRUGO, show_statistics, NULL); + +static ssize_t show_antenna(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + + if (!iwl_is_alive(priv)) + return -EAGAIN; + + return sprintf(buf, "%d\n", priv->antenna); +} + +static ssize_t store_antenna(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int ant; + struct iwl_priv *priv = dev_get_drvdata(d); + + if (count == 0) + return 0; + + if (sscanf(buf, "%1i", &ant) != 1) { + IWL_DEBUG_INFO("not in hex or decimal form.\n"); + return count; + } + + if ((ant >= 0) && (ant <= 2)) { + IWL_DEBUG_INFO("Setting antenna select to %d.\n", ant); + priv->antenna = (enum iwl_antenna)ant; + } else + IWL_DEBUG_INFO("Bad antenna select value %d.\n", ant); + + + return count; +} + +static DEVICE_ATTR(antenna, S_IWUSR | S_IRUGO, show_antenna, store_antenna); + +static ssize_t show_status(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + if (!iwl_is_alive(priv)) + return -EAGAIN; + return sprintf(buf, "0x%08x\n", (int)priv->status); +} + +static DEVICE_ATTR(status, S_IRUGO, show_status, NULL); + +static ssize_t dump_error_log(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + char *p = (char *)buf; + + if (p[0] == '1') + iwl_dump_nic_error_log((struct iwl_priv *)d->driver_data); + + return strnlen(buf, count); +} + +static DEVICE_ATTR(dump_errors, S_IWUSR, NULL, dump_error_log); + +static ssize_t dump_event_log(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + char *p = (char *)buf; + + if (p[0] == '1') + iwl_dump_nic_event_log((struct iwl_priv *)d->driver_data); + + return strnlen(buf, count); +} + +static DEVICE_ATTR(dump_events, S_IWUSR, NULL, dump_event_log); + +/***************************************************************************** + * + * driver setup and teardown + * + *****************************************************************************/ + +static void iwl_setup_deferred_work(struct iwl_priv *priv) +{ + priv->workqueue = create_workqueue(DRV_NAME); + + init_waitqueue_head(&priv->wait_command_queue); + + INIT_WORK(&priv->up, iwl_bg_up); + INIT_WORK(&priv->restart, iwl_bg_restart); + INIT_WORK(&priv->rx_replenish, iwl_bg_rx_replenish); + INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed); + INIT_WORK(&priv->request_scan, iwl_bg_request_scan); + INIT_WORK(&priv->abort_scan, iwl_bg_abort_scan); + INIT_WORK(&priv->rf_kill, iwl_bg_rf_kill); + INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update); + INIT_DELAYED_WORK(&priv->post_associate, iwl_bg_post_associate); + INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start); + INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start); + INIT_DELAYED_WORK(&priv->scan_check, iwl_bg_scan_check); + + iwl_hw_setup_deferred_work(priv); + + tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) + iwl_irq_tasklet, (unsigned long)priv); +} + +static void iwl_cancel_deferred_work(struct iwl_priv *priv) +{ + iwl_hw_cancel_deferred_work(priv); + + cancel_delayed_work(&priv->scan_check); + cancel_delayed_work(&priv->alive_start); + cancel_delayed_work(&priv->post_associate); + cancel_work_sync(&priv->beacon_update); +} + +static struct attribute *iwl_sysfs_entries[] = { + &dev_attr_antenna.attr, + &dev_attr_channels.attr, + &dev_attr_dump_errors.attr, + &dev_attr_dump_events.attr, + &dev_attr_flags.attr, + &dev_attr_filter_flags.attr, +#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT + &dev_attr_measurement.attr, +#endif + &dev_attr_power_level.attr, + &dev_attr_retry_rate.attr, + &dev_attr_rf_kill.attr, + &dev_attr_rs_window.attr, + &dev_attr_statistics.attr, + &dev_attr_status.attr, + &dev_attr_temperature.attr, + &dev_attr_tune.attr, + &dev_attr_tx_power.attr, + + NULL +}; + +static struct attribute_group iwl_attribute_group = { + .name = NULL, /* put in device directory */ + .attrs = iwl_sysfs_entries, +}; + +static struct ieee80211_ops iwl_hw_ops = { + .tx = iwl_mac_tx, + .open = iwl_mac_open, + .stop = iwl_mac_stop, + .add_interface = iwl_mac_add_interface, + .remove_interface = iwl_mac_remove_interface, + .config = iwl_mac_config, + .config_interface = iwl_mac_config_interface, + .set_key = iwl_mac_set_key, + .get_stats = iwl_mac_get_stats, + .get_tx_stats = iwl_mac_get_tx_stats, + .conf_tx = iwl_mac_conf_tx, + .get_tsf = iwl_mac_get_tsf, + .reset_tsf = iwl_mac_reset_tsf, + .beacon_update = iwl_mac_beacon_update, +#ifdef CONFIG_IWLWIFI_HT + .conf_ht = iwl_mac_conf_ht, + .get_ht_capab = iwl_mac_get_ht_capab, +#ifdef CONFIG_IWLWIFI_HT_AGG + .ht_tx_agg_start = iwl_mac_ht_tx_agg_start, + .ht_tx_agg_stop = iwl_mac_ht_tx_agg_stop, + .ht_rx_agg_start = iwl_mac_ht_rx_agg_start, + .ht_rx_agg_stop = iwl_mac_ht_rx_agg_stop, +#endif /* CONFIG_IWLWIFI_HT_AGG */ +#endif /* CONFIG_IWLWIFI_HT */ + .hw_scan = iwl_mac_hw_scan +}; + +static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + int err = 0; + struct iwl_priv *priv; + struct ieee80211_hw *hw; + int i; + + if (iwl_param_disable_hw_scan) { + IWL_DEBUG_INFO("Disabling hw_scan\n"); + iwl_hw_ops.hw_scan = NULL; + } + + if ((iwl_param_queues_num > IWL_MAX_NUM_QUEUES) || + (iwl_param_queues_num < IWL_MIN_NUM_QUEUES)) { + IWL_ERROR("invalid queues_num, should be between %d and %d\n", + IWL_MIN_NUM_QUEUES, IWL_MAX_NUM_QUEUES); + err = -EINVAL; + goto out; + } + + /* mac80211 allocates memory for this device instance, including + * space for this driver's private structure */ + hw = ieee80211_alloc_hw(sizeof(struct iwl_priv), &iwl_hw_ops); + if (hw == NULL) { + IWL_ERROR("Can not allocate network device\n"); + err = -ENOMEM; + goto out; + } + SET_IEEE80211_DEV(hw, &pdev->dev); + + IWL_DEBUG_INFO("*** LOAD DRIVER ***\n"); + priv = hw->priv; + priv->hw = hw; + + priv->pci_dev = pdev; + priv->antenna = (enum iwl_antenna)iwl_param_antenna; +#ifdef CONFIG_IWLWIFI_DEBUG + iwl_debug_level = iwl_param_debug; + atomic_set(&priv->restrict_refcnt, 0); +#endif + priv->retry_rate = 1; + + priv->ibss_beacon = NULL; + + /* Tell mac80211 and its clients (e.g. Wireless Extensions) + * the range of signal quality values that we'll provide. + * Negative values for level/noise indicate that we'll provide dBm. + * For WE, at least, non-0 values here *enable* display of values + * in app (iwconfig). */ + hw->max_rssi = -20; /* signal level, negative indicates dBm */ + hw->max_noise = -20; /* noise level, negative indicates dBm */ + hw->max_signal = 100; /* link quality indication (%) */ + + /* Tell mac80211 our Tx characteristics */ + hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE; + + hw->queues = 4; +#ifdef CONFIG_IWLWIFI_HT +#ifdef CONFIG_IWLWIFI_HT_AGG + hw->queues = 16; +#endif /* CONFIG_IWLWIFI_HT_AGG */ +#endif /* CONFIG_IWLWIFI_HT */ + + spin_lock_init(&priv->lock); + spin_lock_init(&priv->power_data.lock); + spin_lock_init(&priv->sta_lock); + spin_lock_init(&priv->hcmd_lock); + spin_lock_init(&priv->lq_mngr.lock); + + for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++) + INIT_LIST_HEAD(&priv->ibss_mac_hash[i]); + + INIT_LIST_HEAD(&priv->free_frames); + + mutex_init(&priv->mutex); + if (pci_enable_device(pdev)) { + err = -ENODEV; + goto out_ieee80211_free_hw; + } + + pci_set_master(pdev); + + iwl_clear_stations_table(priv); + + priv->data_retry_limit = -1; + priv->ieee_channels = NULL; + priv->ieee_rates = NULL; + priv->phymode = -1; + + err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (!err) + err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); + if (err) { + printk(KERN_WARNING DRV_NAME ": No suitable DMA available.\n"); + goto out_pci_disable_device; + } + + pci_set_drvdata(pdev, priv); + err = pci_request_regions(pdev, DRV_NAME); + if (err) + goto out_pci_disable_device; + /* We disable the RETRY_TIMEOUT register (0x41) to keep + * PCI Tx retries from interfering with C3 CPU state */ + pci_write_config_byte(pdev, 0x41, 0x00); + priv->hw_base = pci_iomap(pdev, 0, 0); + if (!priv->hw_base) { + err = -ENODEV; + goto out_pci_release_regions; + } + + IWL_DEBUG_INFO("pci_resource_len = 0x%08llx\n", + (unsigned long long) pci_resource_len(pdev, 0)); + IWL_DEBUG_INFO("pci_resource_base = %p\n", priv->hw_base); + + /* Initialize module parameter values here */ + + if (iwl_param_disable) { + set_bit(STATUS_RF_KILL_SW, &priv->status); + IWL_DEBUG_INFO("Radio disabled.\n"); + } + + priv->iw_mode = IEEE80211_IF_TYPE_STA; + + priv->ps_mode = 0; + priv->use_ant_b_for_management_frame = 1; /* start with ant B */ + priv->is_ht_enabled = 1; + priv->channel_width = IWL_CHANNEL_WIDTH_40MHZ; + priv->valid_antenna = 0x7; /* assume all 3 connected */ + priv->ps_mode = IWL_MIMO_PS_NONE; + priv->cck_power_index_compensation = iwl_read32( + priv, CSR_HW_REV_WA_REG); + + iwl4965_set_rxon_chain(priv); + + printk(KERN_INFO DRV_NAME + ": Detected Intel Wireless WiFi Link 4965AGN\n"); + + /* Device-specific setup */ + if (iwl_hw_set_hw_setting(priv)) { + IWL_ERROR("failed to set hw settings\n"); + mutex_unlock(&priv->mutex); + goto out_iounmap; + } + +#ifdef CONFIG_IWLWIFI_QOS + if (iwl_param_qos_enable) + priv->qos_data.qos_enable = 1; + + iwl_reset_qos(priv); + + priv->qos_data.qos_active = 0; + priv->qos_data.qos_cap.val = 0; +#endif /* CONFIG_IWLWIFI_QOS */ + + iwl_set_rxon_channel(priv, MODE_IEEE80211G, 6); + iwl_setup_deferred_work(priv); + iwl_setup_rx_handlers(priv); + + priv->rates_mask = IWL_RATES_MASK; + /* If power management is turned on, default to AC mode */ + priv->power_mode = IWL_POWER_AC; + priv->user_txpower_limit = IWL_DEFAULT_TX_POWER; + + pci_enable_msi(pdev); + + err = request_irq(pdev->irq, iwl_isr, IRQF_SHARED, DRV_NAME, priv); + if (err) { + IWL_ERROR("Error allocating IRQ %d\n", pdev->irq); + goto out_disable_msi; + } + + mutex_lock(&priv->mutex); + + err = sysfs_create_group(&pdev->dev.kobj, &iwl_attribute_group); + if (err) { + IWL_ERROR("failed to create sysfs device attributes\n"); + mutex_unlock(&priv->mutex); + goto out_release_irq; + } + + /* fetch ucode file from disk, alloc and copy to bus-master buffers ... + * ucode filename and max sizes are card-specific. */ + err = iwl_read_ucode(priv); + if (err) { + IWL_ERROR("Could not read microcode: %d\n", err); + mutex_unlock(&priv->mutex); + goto out_pci_alloc; + } + + mutex_unlock(&priv->mutex); + + IWL_DEBUG_INFO("Queing UP work.\n"); + + queue_work(priv->workqueue, &priv->up); + + return 0; + + out_pci_alloc: + iwl_dealloc_ucode_pci(priv); + + sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group); + + out_release_irq: + free_irq(pdev->irq, priv); + + out_disable_msi: + pci_disable_msi(pdev); + destroy_workqueue(priv->workqueue); + priv->workqueue = NULL; + iwl_unset_hw_setting(priv); + + out_iounmap: + pci_iounmap(pdev, priv->hw_base); + out_pci_release_regions: + pci_release_regions(pdev); + out_pci_disable_device: + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + out_ieee80211_free_hw: + ieee80211_free_hw(priv->hw); + out: + return err; +} + +static void iwl_pci_remove(struct pci_dev *pdev) +{ + struct iwl_priv *priv = pci_get_drvdata(pdev); + struct list_head *p, *q; + int i; + + if (!priv) + return; + + IWL_DEBUG_INFO("*** UNLOAD DRIVER ***\n"); + + mutex_lock(&priv->mutex); + set_bit(STATUS_EXIT_PENDING, &priv->status); + __iwl_down(priv); + mutex_unlock(&priv->mutex); + + /* Free MAC hash list for ADHOC */ + for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++) { + list_for_each_safe(p, q, &priv->ibss_mac_hash[i]) { + list_del(p); + kfree(list_entry(p, struct iwl_ibss_seq, list)); + } + } + + sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group); + + iwl_dealloc_ucode_pci(priv); + + if (priv->rxq.bd) + iwl_rx_queue_free(priv, &priv->rxq); + iwl_hw_txq_ctx_free(priv); + + iwl_unset_hw_setting(priv); + iwl_clear_stations_table(priv); + + if (priv->mac80211_registered) { + ieee80211_unregister_hw(priv->hw); + iwl_rate_control_unregister(priv->hw); + } + + /* ieee80211_unregister_hw calls iwl_mac_stop, which flushes + * priv->workqueue... so we can't take down the workqueue + * until now... */ + destroy_workqueue(priv->workqueue); + priv->workqueue = NULL; + + free_irq(pdev->irq, priv); + pci_disable_msi(pdev); + pci_iounmap(pdev, priv->hw_base); + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + + kfree(priv->channel_info); + + kfree(priv->ieee_channels); + kfree(priv->ieee_rates); + + if (priv->ibss_beacon) + dev_kfree_skb(priv->ibss_beacon); + + ieee80211_free_hw(priv->hw); +} + +#ifdef CONFIG_PM + +static int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct iwl_priv *priv = pci_get_drvdata(pdev); + + mutex_lock(&priv->mutex); + + set_bit(STATUS_IN_SUSPEND, &priv->status); + + /* Take down the device; powers it off, etc. */ + __iwl_down(priv); + + if (priv->mac80211_registered) + ieee80211_stop_queues(priv->hw); + + pci_save_state(pdev); + pci_disable_device(pdev); + pci_set_power_state(pdev, PCI_D3hot); + + mutex_unlock(&priv->mutex); + + return 0; +} + +static void iwl_resume(struct iwl_priv *priv) +{ + unsigned long flags; + + /* The following it a temporary work around due to the + * suspend / resume not fully initializing the NIC correctly. + * Without all of the following, resume will not attempt to take + * down the NIC (it shouldn't really need to) and will just try + * and bring the NIC back up. However that fails during the + * ucode verification process. This then causes iwl_down to be + * called *after* iwl_hw_nic_init() has succeeded -- which + * then lets the next init sequence succeed. So, we've + * replicated all of that NIC init code here... */ + + iwl_write32(priv, CSR_INT, 0xFFFFFFFF); + + iwl_hw_nic_init(priv); + + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, + CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); + iwl_write32(priv, CSR_INT, 0xFFFFFFFF); + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + + /* tell the device to stop sending interrupts */ + iwl_disable_interrupts(priv); + + spin_lock_irqsave(&priv->lock, flags); + iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + + if (!iwl_grab_restricted_access(priv)) { + iwl_write_restricted_reg(priv, APMG_CLK_DIS_REG, + APMG_CLK_VAL_DMA_CLK_RQT); + iwl_release_restricted_access(priv); + } + spin_unlock_irqrestore(&priv->lock, flags); + + udelay(5); + + iwl_hw_nic_reset(priv); + + /* Bring the device back up */ + clear_bit(STATUS_IN_SUSPEND, &priv->status); + queue_work(priv->workqueue, &priv->up); +} + +static int iwl_pci_resume(struct pci_dev *pdev) +{ + struct iwl_priv *priv = pci_get_drvdata(pdev); + int err; + + printk(KERN_INFO "Coming out of suspend...\n"); + + mutex_lock(&priv->mutex); + + pci_set_power_state(pdev, PCI_D0); + err = pci_enable_device(pdev); + pci_restore_state(pdev); + + /* + * Suspend/Resume resets the PCI configuration space, so we have to + * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries + * from interfering with C3 CPU state. pci_restore_state won't help + * here since it only restores the first 64 bytes pci config header. + */ + pci_write_config_byte(pdev, 0x41, 0x00); + + iwl_resume(priv); + mutex_unlock(&priv->mutex); + + return 0; +} + +#endif /* CONFIG_PM */ + +/***************************************************************************** + * + * driver and module entry point + * + *****************************************************************************/ + +static struct pci_driver iwl_driver = { + .name = DRV_NAME, + .id_table = iwl_hw_card_ids, + .probe = iwl_pci_probe, + .remove = __devexit_p(iwl_pci_remove), +#ifdef CONFIG_PM + .suspend = iwl_pci_suspend, + .resume = iwl_pci_resume, +#endif +}; + +static int __init iwl_init(void) +{ + + int ret; + printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n"); + printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n"); + ret = pci_register_driver(&iwl_driver); + if (ret) { + IWL_ERROR("Unable to initialize PCI module\n"); + return ret; + } +#ifdef CONFIG_IWLWIFI_DEBUG + ret = driver_create_file(&iwl_driver.driver, &driver_attr_debug_level); + if (ret) { + IWL_ERROR("Unable to create driver sysfs file\n"); + pci_unregister_driver(&iwl_driver); + return ret; + } +#endif + + return ret; +} + +static void __exit iwl_exit(void) +{ +#ifdef CONFIG_IWLWIFI_DEBUG + driver_remove_file(&iwl_driver.driver, &driver_attr_debug_level); +#endif + pci_unregister_driver(&iwl_driver); +} + +module_param_named(antenna, iwl_param_antenna, int, 0444); +MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])"); +module_param_named(disable, iwl_param_disable, int, 0444); +MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])"); +module_param_named(hwcrypto, iwl_param_hwcrypto, int, 0444); +MODULE_PARM_DESC(hwcrypto, + "using hardware crypto engine (default 0 [software])\n"); +module_param_named(debug, iwl_param_debug, int, 0444); +MODULE_PARM_DESC(debug, "debug output mask"); +module_param_named(disable_hw_scan, iwl_param_disable_hw_scan, int, 0444); +MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)"); + +module_param_named(queues_num, iwl_param_queues_num, int, 0444); +MODULE_PARM_DESC(queues_num, "number of hw queues."); + +/* QoS */ +module_param_named(qos_enable, iwl_param_qos_enable, int, 0444); +MODULE_PARM_DESC(qos_enable, "enable all QoS functionality"); + +module_exit(iwl_exit); +module_init(iwl_init); diff --git a/drivers/net/wireless/iwlwifi/iwlwifi.h b/drivers/net/wireless/iwlwifi/iwlwifi.h new file mode 100644 index 00000000000..00c79e200c6 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwlwifi.h @@ -0,0 +1,713 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project, as well + * as portions of the ieee80211 subsystem header files. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#ifndef __iwlwifi_h__ +#define __iwlwifi_h__ + +#include /* for struct pci_device_id */ +#include +#include + +struct iwl_priv; + +/* Hardware specific file defines the PCI IDs table for that hardware module */ +extern struct pci_device_id iwl_hw_card_ids[]; + +#if IWL == 3945 + +#define DRV_NAME "iwl3945" +#include "iwl-hw.h" +#include "iwl-3945-hw.h" + +#elif IWL == 4965 + +#define DRV_NAME "iwl4965" +#include "iwl-hw.h" +#include "iwl-4965-hw.h" + +#endif + +#include "iwl-prph.h" + +/* + * Driver implementation data structures, constants, inline + * functions + * + * NOTE: DO NOT PUT HARDWARE/UCODE SPECIFIC DECLRATIONS HERE + * + * Hardware specific declrations go into iwl-*hw.h + * + */ + +#include "iwl-debug.h" + +/* Default noise level to report when noise measurement is not available. + * This may be because we're: + * 1) Not associated (4965, no beacon statistics being sent to driver) + * 2) Scanning (noise measurement does not apply to associated channel) + * 3) Receiving CCK (3945 delivers noise info only for OFDM frames) + * Use default noise value of -127 ... this is below the range of measurable + * Rx dBm for either 3945 or 4965, so it can indicate "unmeasurable" to user. + * Also, -127 works better than 0 when averaging frames with/without + * noise info (e.g. averaging might be done in app); measured dBm values are + * always negative ... using a negative value as the default keeps all + * averages within an s8's (used in some apps) range of negative values. */ +#define IWL_NOISE_MEAS_NOT_AVAILABLE (-127) + +/* Module parameters accessible from iwl-*.c */ +extern int iwl_param_disable_hw_scan; +extern int iwl_param_debug; +extern int iwl_param_mode; +extern int iwl_param_disable; +extern int iwl_param_antenna; +extern int iwl_param_hwcrypto; +extern int iwl_param_qos_enable; +extern int iwl_param_queues_num; + +enum iwl_antenna { + IWL_ANTENNA_DIVERSITY, + IWL_ANTENNA_MAIN, + IWL_ANTENNA_AUX +}; + +/* + * RTS threshold here is total size [2347] minus 4 FCS bytes + * Per spec: + * a value of 0 means RTS on all data/management packets + * a value > max MSDU size means no RTS + * else RTS for data/management frames where MPDU is larger + * than RTS value. + */ +#define DEFAULT_RTS_THRESHOLD 2347U +#define MIN_RTS_THRESHOLD 0U +#define MAX_RTS_THRESHOLD 2347U +#define MAX_MSDU_SIZE 2304U +#define MAX_MPDU_SIZE 2346U +#define DEFAULT_BEACON_INTERVAL 100U +#define DEFAULT_SHORT_RETRY_LIMIT 7U +#define DEFAULT_LONG_RETRY_LIMIT 4U + +struct iwl_rx_mem_buffer { + dma_addr_t dma_addr; + struct sk_buff *skb; + struct list_head list; +}; + +struct iwl_rt_rx_hdr { + struct ieee80211_radiotap_header rt_hdr; + __le64 rt_tsf; /* TSF */ + u8 rt_flags; /* radiotap packet flags */ + u8 rt_rate; /* rate in 500kb/s */ + __le16 rt_channelMHz; /* channel in MHz */ + __le16 rt_chbitmask; /* channel bitfield */ + s8 rt_dbmsignal; /* signal in dBm, kluged to signed */ + s8 rt_dbmnoise; + u8 rt_antenna; /* antenna number */ + u8 payload[0]; /* payload... */ +} __attribute__ ((packed)); + +struct iwl_rt_tx_hdr { + struct ieee80211_radiotap_header rt_hdr; + u8 rt_rate; /* rate in 500kb/s */ + __le16 rt_channel; /* channel in mHz */ + __le16 rt_chbitmask; /* channel bitfield */ + s8 rt_dbmsignal; /* signal in dBm, kluged to signed */ + u8 rt_antenna; /* antenna number */ + u8 payload[0]; /* payload... */ +} __attribute__ ((packed)); + +/* + * Generic queue structure + * + * Contains common data for Rx and Tx queues + */ +struct iwl_queue { + int n_bd; /* number of BDs in this queue */ + int first_empty; /* 1-st empty entry (index) host_w*/ + int last_used; /* last used entry (index) host_r*/ + dma_addr_t dma_addr; /* physical addr for BD's */ + int n_window; /* safe queue window */ + u32 id; + int low_mark; /* low watermark, resume queue if free + * space more than this */ + int high_mark; /* high watermark, stop queue if free + * space less than this */ +} __attribute__ ((packed)); + +#define MAX_NUM_OF_TBS (20) + +struct iwl_tx_info { + struct ieee80211_tx_status status; + struct sk_buff *skb[MAX_NUM_OF_TBS]; +}; + +/** + * struct iwl_tx_queue - Tx Queue for DMA + * @need_update: need to update read/write index + * @shed_retry: queue is HT AGG enabled + * + * Queue consists of circular buffer of BD's and required locking structures. + */ +struct iwl_tx_queue { + struct iwl_queue q; + struct iwl_tfd_frame *bd; + struct iwl_cmd *cmd; + dma_addr_t dma_addr_cmd; + struct iwl_tx_info *txb; + int need_update; + int sched_retry; + int active; +}; + +#include "iwl-channel.h" + +#if IWL == 3945 +#include "iwl-3945-rs.h" +#else +#include "iwl-4965-rs.h" +#endif + +#define IWL_TX_FIFO_AC0 0 +#define IWL_TX_FIFO_AC1 1 +#define IWL_TX_FIFO_AC2 2 +#define IWL_TX_FIFO_AC3 3 +#define IWL_TX_FIFO_HCCA_1 5 +#define IWL_TX_FIFO_HCCA_2 6 +#define IWL_TX_FIFO_NONE 7 + +/* Minimum number of queues. MAX_NUM is defined in hw specific files */ +#define IWL_MIN_NUM_QUEUES 4 + +/* Power management (not Tx power) structures */ + +struct iwl_power_vec_entry { + struct iwl_powertable_cmd cmd; + u8 no_dtim; +}; +#define IWL_POWER_RANGE_0 (0) +#define IWL_POWER_RANGE_1 (1) + +#define IWL_POWER_MODE_CAM 0x00 /* Continuously Aware Mode, always on */ +#define IWL_POWER_INDEX_3 0x03 +#define IWL_POWER_INDEX_5 0x05 +#define IWL_POWER_AC 0x06 +#define IWL_POWER_BATTERY 0x07 +#define IWL_POWER_LIMIT 0x07 +#define IWL_POWER_MASK 0x0F +#define IWL_POWER_ENABLED 0x10 +#define IWL_POWER_LEVEL(x) ((x) & IWL_POWER_MASK) + +struct iwl_power_mgr { + spinlock_t lock; + struct iwl_power_vec_entry pwr_range_0[IWL_POWER_AC]; + struct iwl_power_vec_entry pwr_range_1[IWL_POWER_AC]; + u8 active_index; + u32 dtim_val; +}; + +#define IEEE80211_DATA_LEN 2304 +#define IEEE80211_4ADDR_LEN 30 +#define IEEE80211_HLEN (IEEE80211_4ADDR_LEN) +#define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN) + +struct iwl_frame { + union { + struct ieee80211_hdr frame; + struct iwl_tx_beacon_cmd beacon; + u8 raw[IEEE80211_FRAME_LEN]; + u8 cmd[360]; + } u; + struct list_head list; +}; + +#define SEQ_TO_QUEUE(x) ((x >> 8) & 0xbf) +#define QUEUE_TO_SEQ(x) ((x & 0xbf) << 8) +#define SEQ_TO_INDEX(x) (x & 0xff) +#define INDEX_TO_SEQ(x) (x & 0xff) +#define SEQ_HUGE_FRAME (0x4000) +#define SEQ_RX_FRAME __constant_cpu_to_le16(0x8000) +#define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4) +#define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ) +#define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4) + +enum { + /* CMD_SIZE_NORMAL = 0, */ + CMD_SIZE_HUGE = (1 << 0), + /* CMD_SYNC = 0, */ + CMD_ASYNC = (1 << 1), + /* CMD_NO_SKB = 0, */ + CMD_WANT_SKB = (1 << 2), +}; + +struct iwl_cmd; +struct iwl_priv; + +struct iwl_cmd_meta { + struct iwl_cmd_meta *source; + union { + struct sk_buff *skb; + int (*callback)(struct iwl_priv *priv, + struct iwl_cmd *cmd, struct sk_buff *skb); + } __attribute__ ((packed)) u; + + /* The CMD_SIZE_HUGE flag bit indicates that the command + * structure is stored at the end of the shared queue memory. */ + u32 flags; + +} __attribute__ ((packed)); + +struct iwl_cmd { + struct iwl_cmd_meta meta; + struct iwl_cmd_header hdr; + union { + struct iwl_addsta_cmd addsta; + struct iwl_led_cmd led; + u32 flags; + u8 val8; + u16 val16; + u32 val32; + struct iwl_bt_cmd bt; + struct iwl_rxon_time_cmd rxon_time; + struct iwl_powertable_cmd powertable; + struct iwl_qosparam_cmd qosparam; + struct iwl_tx_cmd tx; + struct iwl_tx_beacon_cmd tx_beacon; + struct iwl_rxon_assoc_cmd rxon_assoc; + u8 *indirect; + u8 payload[360]; + } __attribute__ ((packed)) cmd; +} __attribute__ ((packed)); + +struct iwl_host_cmd { + u8 id; + u16 len; + struct iwl_cmd_meta meta; + const void *data; +}; + +#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_cmd) - \ + sizeof(struct iwl_cmd_meta)) + +/* + * RX related structures and functions + */ +#define RX_FREE_BUFFERS 64 +#define RX_LOW_WATERMARK 8 + +#define SUP_RATE_11A_MAX_NUM_CHANNELS 8 +#define SUP_RATE_11B_MAX_NUM_CHANNELS 4 +#define SUP_RATE_11G_MAX_NUM_CHANNELS 12 + +/** + * struct iwl_rx_queue - Rx queue + * @processed: Internal index to last handled Rx packet + * @read: Shared index to newest available Rx buffer + * @write: Shared index to oldest written Rx packet + * @free_count: Number of pre-allocated buffers in rx_free + * @rx_free: list of free SKBs for use + * @rx_used: List of Rx buffers with no SKB + * @need_update: flag to indicate we need to update read/write index + * + * NOTE: rx_free and rx_used are used as a FIFO for iwl_rx_mem_buffers + */ +struct iwl_rx_queue { + __le32 *bd; + dma_addr_t dma_addr; + struct iwl_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS]; + struct iwl_rx_mem_buffer *queue[RX_QUEUE_SIZE]; + u32 processed; + u32 read; + u32 write; + u32 free_count; + struct list_head rx_free; + struct list_head rx_used; + int need_update; + spinlock_t lock; +}; + +#define IWL_SUPPORTED_RATES_IE_LEN 8 + +#define SCAN_INTERVAL 100 + +#define MAX_A_CHANNELS 252 +#define MIN_A_CHANNELS 7 + +#define MAX_B_CHANNELS 14 +#define MIN_B_CHANNELS 1 + +#define STATUS_HCMD_ACTIVE 0 /* host command in progress */ +#define STATUS_INT_ENABLED 1 +#define STATUS_RF_KILL_HW 2 +#define STATUS_RF_KILL_SW 3 +#define STATUS_INIT 4 +#define STATUS_ALIVE 5 +#define STATUS_READY 6 +#define STATUS_TEMPERATURE 7 +#define STATUS_GEO_CONFIGURED 8 +#define STATUS_EXIT_PENDING 9 +#define STATUS_IN_SUSPEND 10 +#define STATUS_STATISTICS 11 +#define STATUS_SCANNING 12 +#define STATUS_SCAN_ABORTING 13 +#define STATUS_SCAN_HW 14 +#define STATUS_POWER_PMI 15 +#define STATUS_FW_ERROR 16 + +#define MAX_TID_COUNT 9 + +#define IWL_INVALID_RATE 0xFF +#define IWL_INVALID_VALUE -1 + +#if IWL == 4965 +#ifdef CONFIG_IWLWIFI_HT +#ifdef CONFIG_IWLWIFI_HT_AGG +struct iwl_ht_agg { + u16 txq_id; + u16 frame_count; + u16 wait_for_ba; + u16 start_idx; + u32 bitmap0; + u32 bitmap1; + u32 rate_n_flags; +}; +#endif /* CONFIG_IWLWIFI_HT_AGG */ +#endif /* CONFIG_IWLWIFI_HT */ +#endif + +struct iwl_tid_data { + u16 seq_number; +#if IWL == 4965 +#ifdef CONFIG_IWLWIFI_HT +#ifdef CONFIG_IWLWIFI_HT_AGG + struct iwl_ht_agg agg; +#endif /* CONFIG_IWLWIFI_HT_AGG */ +#endif /* CONFIG_IWLWIFI_HT */ +#endif +}; + +struct iwl_hw_key { + ieee80211_key_alg alg; + int keylen; + u8 key[32]; +}; + +union iwl_ht_rate_supp { + u16 rates; + struct { + u8 siso_rate; + u8 mimo_rate; + }; +}; + +#ifdef CONFIG_IWLWIFI_HT +#define CFG_HT_RX_AMPDU_FACTOR_DEF (0x3) +#define HT_IE_MAX_AMSDU_SIZE_4K (0) +#define CFG_HT_MPDU_DENSITY_2USEC (0x5) +#define CFG_HT_MPDU_DENSITY_DEF CFG_HT_MPDU_DENSITY_2USEC + +struct sta_ht_info { + u8 is_ht; + u16 rx_mimo_ps_mode; + u16 tx_mimo_ps_mode; + u16 control_channel; + u8 max_amsdu_size; + u8 ampdu_factor; + u8 mpdu_density; + u8 operating_mode; + u8 supported_chan_width; + u8 extension_chan_offset; + u8 is_green_field; + u8 sgf; + u8 supp_rates[16]; + u8 tx_chan_width; + u8 chan_width_cap; +}; +#endif /*CONFIG_IWLWIFI_HT */ + +#ifdef CONFIG_IWLWIFI_QOS + +union iwl_qos_capabity { + struct { + u8 edca_count:4; /* bit 0-3 */ + u8 q_ack:1; /* bit 4 */ + u8 queue_request:1; /* bit 5 */ + u8 txop_request:1; /* bit 6 */ + u8 reserved:1; /* bit 7 */ + } q_AP; + struct { + u8 acvo_APSD:1; /* bit 0 */ + u8 acvi_APSD:1; /* bit 1 */ + u8 ac_bk_APSD:1; /* bit 2 */ + u8 ac_be_APSD:1; /* bit 3 */ + u8 q_ack:1; /* bit 4 */ + u8 max_len:2; /* bit 5-6 */ + u8 more_data_ack:1; /* bit 7 */ + } q_STA; + u8 val; +}; + +/* QoS sturctures */ +struct iwl_qos_info { + int qos_enable; + int qos_active; + union iwl_qos_capabity qos_cap; + struct iwl_qosparam_cmd def_qos_parm; +}; +#endif /*CONFIG_IWLWIFI_QOS */ + +#define STA_PS_STATUS_WAKE 0 +#define STA_PS_STATUS_SLEEP 1 + +struct iwl_station_entry { + struct iwl_addsta_cmd sta; + struct iwl_tid_data tid[MAX_TID_COUNT]; +#if IWL == 3945 + union { + struct { + u8 rate; + u8 flags; + } s; + u16 rate_n_flags; + } current_rate; +#endif + u8 used; + u8 ps_status; + struct iwl_hw_key keyinfo; +}; + +/* one for each uCode image (inst/data, boot/init/runtime) */ +struct fw_image_desc { + void *v_addr; /* access by driver */ + dma_addr_t p_addr; /* access by card's busmaster DMA */ + u32 len; /* bytes */ +}; + +/* uCode file layout */ +struct iwl_ucode { + __le32 ver; /* major/minor/subminor */ + __le32 inst_size; /* bytes of runtime instructions */ + __le32 data_size; /* bytes of runtime data */ + __le32 init_size; /* bytes of initialization instructions */ + __le32 init_data_size; /* bytes of initialization data */ + __le32 boot_size; /* bytes of bootstrap instructions */ + u8 data[0]; /* data in same order as "size" elements */ +}; + +#define IWL_IBSS_MAC_HASH_SIZE 32 + +struct iwl_ibss_seq { + u8 mac[ETH_ALEN]; + u16 seq_num; + u16 frag_num; + unsigned long packet_time; + struct list_head list; +}; + +struct iwl_driver_hw_info { + u16 max_txq_num; + u16 ac_queue_count; + u32 rx_buffer_size; + u16 tx_cmd_len; + u16 max_rxq_size; + u16 max_rxq_log; + u32 cck_flag; + u8 max_stations; + u8 bcast_sta_id; + void *shared_virt; + dma_addr_t shared_phys; +}; + + +#define STA_FLG_RTS_MIMO_PROT_MSK __constant_cpu_to_le32(1 << 17) +#define STA_FLG_AGG_MPDU_8US_MSK __constant_cpu_to_le32(1 << 18) +#define STA_FLG_MAX_AGG_SIZE_POS (19) +#define STA_FLG_MAX_AGG_SIZE_MSK __constant_cpu_to_le32(3 << 19) +#define STA_FLG_FAT_EN_MSK __constant_cpu_to_le32(1 << 21) +#define STA_FLG_MIMO_DIS_MSK __constant_cpu_to_le32(1 << 22) +#define STA_FLG_AGG_MPDU_DENSITY_POS (23) +#define STA_FLG_AGG_MPDU_DENSITY_MSK __constant_cpu_to_le32(7 << 23) +#define HT_SHORT_GI_20MHZ_ONLY (1 << 0) +#define HT_SHORT_GI_40MHZ_ONLY (1 << 1) + + +#include "iwl-priv.h" + +/* Requires full declaration of iwl_priv before including */ +#include "iwl-io.h" + +#define IWL_RX_HDR(x) ((struct iwl_rx_frame_hdr *)(\ + x->u.rx_frame.stats.payload + \ + x->u.rx_frame.stats.phy_count)) +#define IWL_RX_END(x) ((struct iwl_rx_frame_end *)(\ + IWL_RX_HDR(x)->payload + \ + le16_to_cpu(IWL_RX_HDR(x)->len))) +#define IWL_RX_STATS(x) (&x->u.rx_frame.stats) +#define IWL_RX_DATA(x) (IWL_RX_HDR(x)->payload) + + +/****************************************************************************** + * + * Functions implemented in iwl-base.c which are forward declared here + * for use by iwl-*.c + * + *****************************************************************************/ +struct iwl_addsta_cmd; +extern int iwl_send_add_station(struct iwl_priv *priv, + struct iwl_addsta_cmd *sta, u8 flags); +extern const char *iwl_get_tx_fail_reason(u32 status); +extern u8 iwl_add_station(struct iwl_priv *priv, const u8 *bssid, + int is_ap, u8 flags); +extern int iwl_is_network_packet(struct iwl_priv *priv, + struct ieee80211_hdr *header); +extern int iwl_power_init_handle(struct iwl_priv *priv); +extern int iwl_eeprom_init(struct iwl_priv *priv); +#ifdef CONFIG_IWLWIFI_DEBUG +extern void iwl_report_frame(struct iwl_priv *priv, + struct iwl_rx_packet *pkt, + struct ieee80211_hdr *header, int group100); +#else +static inline void iwl_report_frame(struct iwl_priv *priv, + struct iwl_rx_packet *pkt, + struct ieee80211_hdr *header, + int group100) {} +#endif +extern int iwl_tx_queue_update_write_ptr(struct iwl_priv *priv, + struct iwl_tx_queue *txq); +extern void iwl_handle_data_packet_monitor(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb, + void *data, short len, + struct ieee80211_rx_status *stats, + u16 phy_flags); +extern int is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr + *header); +extern void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq); +extern int iwl_rx_queue_alloc(struct iwl_priv *priv); +extern void iwl_rx_queue_reset(struct iwl_priv *priv, + struct iwl_rx_queue *rxq); +extern int iwl_calc_db_from_ratio(int sig_ratio); +extern int iwl_calc_sig_qual(int rssi_dbm, int noise_dbm); +extern int iwl_tx_queue_init(struct iwl_priv *priv, + struct iwl_tx_queue *txq, int count, u32 id); +extern int iwl_rx_queue_restock(struct iwl_priv *priv); +extern void iwl_rx_replenish(void *data); +extern void iwl_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq); +extern int iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u16 len, + const void *data); +extern int __must_check iwl_send_cmd_async(struct iwl_priv *priv, + struct iwl_host_cmd *cmd); +extern int __must_check iwl_send_cmd_sync(struct iwl_priv *priv, + struct iwl_host_cmd *cmd); +extern int __must_check iwl_send_cmd(struct iwl_priv *priv, + struct iwl_host_cmd *cmd); +extern unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv, + struct ieee80211_hdr *hdr, + const u8 *dest, int left); +extern int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, + struct iwl_rx_queue *q); +extern int iwl_send_statistics_request(struct iwl_priv *priv); +extern void iwl_set_decrypted_flag(struct iwl_priv *priv, struct sk_buff *skb, + u32 decrypt_res, + struct ieee80211_rx_status *stats); +extern __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr); + +extern const u8 BROADCAST_ADDR[ETH_ALEN]; + +/* + * Currently used by iwl-3945-rs... look at restructuring so that it doesn't + * call this... todo... fix that. +*/ +extern u8 iwl_sync_station(struct iwl_priv *priv, int sta_id, + u16 tx_rate, u8 flags); + +static inline int iwl_is_associated(struct iwl_priv *priv) +{ + return (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ? 1 : 0; +} + +/****************************************************************************** + * + * Functions implemented in iwl-[34]*.c which are forward declared here + * for use by iwl-base.c + * + * NOTE: The implementation of these functions are hardware specific + * which is why they are in the hardware specific files (vs. iwl-base.c) + * + * Naming convention -- + * iwl_ <-- Its part of iwlwifi (should be changed to iwl_) + * iwl_hw_ <-- Hardware specific (implemented in iwl-XXXX.c by all HW) + * iwlXXXX_ <-- Hardware specific (implemented in iwl-XXXX.c for XXXX) + * iwl_bg_ <-- Called from work queue context + * iwl_mac_ <-- mac80211 callback + * + ****************************************************************************/ +extern void iwl_hw_rx_handler_setup(struct iwl_priv *priv); +extern void iwl_hw_setup_deferred_work(struct iwl_priv *priv); +extern void iwl_hw_cancel_deferred_work(struct iwl_priv *priv); +extern int iwl_hw_rxq_stop(struct iwl_priv *priv); +extern int iwl_hw_set_hw_setting(struct iwl_priv *priv); +extern int iwl_hw_nic_init(struct iwl_priv *priv); +extern void iwl_hw_card_show_info(struct iwl_priv *priv); +extern int iwl_hw_nic_stop_master(struct iwl_priv *priv); +extern void iwl_hw_txq_ctx_free(struct iwl_priv *priv); +extern void iwl_hw_txq_ctx_stop(struct iwl_priv *priv); +extern int iwl_hw_nic_reset(struct iwl_priv *priv); +extern int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *tfd, + dma_addr_t addr, u16 len); +extern int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq); +extern int iwl_hw_get_temperature(struct iwl_priv *priv); +extern int iwl_hw_tx_queue_init(struct iwl_priv *priv, + struct iwl_tx_queue *txq); +extern unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv, + struct iwl_frame *frame, u8 rate); +extern int iwl_hw_get_rx_read(struct iwl_priv *priv); +extern void iwl_hw_build_tx_cmd_rate(struct iwl_priv *priv, + struct iwl_cmd *cmd, + struct ieee80211_tx_control *ctrl, + struct ieee80211_hdr *hdr, + int sta_id, int tx_id); +extern int iwl_hw_reg_send_txpower(struct iwl_priv *priv); +extern int iwl_hw_reg_set_txpower(struct iwl_priv *priv, s8 power); +extern void iwl_hw_rx_statistics(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb); +extern void iwl_disable_events(struct iwl_priv *priv); +extern int iwl4965_get_temperature(const struct iwl_priv *priv); + +/** + * iwl_hw_find_station - Find station id for a given BSSID + * @bssid: MAC address of station ID to find + * + * NOTE: This should not be hardware specific but the code has + * not yet been merged into a single common layer for managing the + * station tables. + */ +extern u8 iwl_hw_find_station(struct iwl_priv *priv, const u8 *bssid); + +extern int iwl_hw_channel_switch(struct iwl_priv *priv, u16 channel); +extern int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index); +#endif -- cgit v1.2.3-70-g09d2 From 95ea36275f3c9a1d3d04c217b4b576c657c4e70e Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Tue, 25 Sep 2007 17:57:13 -0700 Subject: [RT2x00]: add driver for Ralink wireless hardware Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- CREDITS | 31 + MAINTAINERS | 8 + drivers/net/wireless/Kconfig | 1 + drivers/net/wireless/Makefile | 1 + drivers/net/wireless/rt2x00/Kconfig | 130 ++ drivers/net/wireless/rt2x00/Makefile | 22 + drivers/net/wireless/rt2x00/rt2400pci.c | 1689 +++++++++++++++++ drivers/net/wireless/rt2x00/rt2400pci.h | 943 ++++++++++ drivers/net/wireless/rt2x00/rt2500pci.c | 2000 ++++++++++++++++++++ drivers/net/wireless/rt2x00/rt2500pci.h | 1236 ++++++++++++ drivers/net/wireless/rt2x00/rt2500usb.c | 1837 ++++++++++++++++++ drivers/net/wireless/rt2x00/rt2500usb.h | 798 ++++++++ drivers/net/wireless/rt2x00/rt2x00.h | 807 ++++++++ drivers/net/wireless/rt2x00/rt2x00config.c | 165 ++ drivers/net/wireless/rt2x00/rt2x00debug.c | 331 ++++ drivers/net/wireless/rt2x00/rt2x00debug.h | 57 + drivers/net/wireless/rt2x00/rt2x00dev.c | 1133 +++++++++++ drivers/net/wireless/rt2x00/rt2x00firmware.c | 124 ++ drivers/net/wireless/rt2x00/rt2x00lib.h | 125 ++ drivers/net/wireless/rt2x00/rt2x00mac.c | 459 +++++ drivers/net/wireless/rt2x00/rt2x00pci.c | 481 +++++ drivers/net/wireless/rt2x00/rt2x00pci.h | 127 ++ drivers/net/wireless/rt2x00/rt2x00reg.h | 283 +++ drivers/net/wireless/rt2x00/rt2x00rfkill.c | 148 ++ drivers/net/wireless/rt2x00/rt2x00ring.h | 255 +++ drivers/net/wireless/rt2x00/rt2x00usb.c | 595 ++++++ drivers/net/wireless/rt2x00/rt2x00usb.h | 180 ++ drivers/net/wireless/rt2x00/rt61pci.c | 2603 ++++++++++++++++++++++++++ drivers/net/wireless/rt2x00/rt61pci.h | 1457 ++++++++++++++ drivers/net/wireless/rt2x00/rt73usb.c | 2124 +++++++++++++++++++++ drivers/net/wireless/rt2x00/rt73usb.h | 1024 ++++++++++ 31 files changed, 21174 insertions(+) create mode 100644 drivers/net/wireless/rt2x00/Kconfig create mode 100644 drivers/net/wireless/rt2x00/Makefile create mode 100644 drivers/net/wireless/rt2x00/rt2400pci.c create mode 100644 drivers/net/wireless/rt2x00/rt2400pci.h create mode 100644 drivers/net/wireless/rt2x00/rt2500pci.c create mode 100644 drivers/net/wireless/rt2x00/rt2500pci.h create mode 100644 drivers/net/wireless/rt2x00/rt2500usb.c create mode 100644 drivers/net/wireless/rt2x00/rt2500usb.h create mode 100644 drivers/net/wireless/rt2x00/rt2x00.h create mode 100644 drivers/net/wireless/rt2x00/rt2x00config.c create mode 100644 drivers/net/wireless/rt2x00/rt2x00debug.c create mode 100644 drivers/net/wireless/rt2x00/rt2x00debug.h create mode 100644 drivers/net/wireless/rt2x00/rt2x00dev.c create mode 100644 drivers/net/wireless/rt2x00/rt2x00firmware.c create mode 100644 drivers/net/wireless/rt2x00/rt2x00lib.h create mode 100644 drivers/net/wireless/rt2x00/rt2x00mac.c create mode 100644 drivers/net/wireless/rt2x00/rt2x00pci.c create mode 100644 drivers/net/wireless/rt2x00/rt2x00pci.h create mode 100644 drivers/net/wireless/rt2x00/rt2x00reg.h create mode 100644 drivers/net/wireless/rt2x00/rt2x00rfkill.c create mode 100644 drivers/net/wireless/rt2x00/rt2x00ring.h create mode 100644 drivers/net/wireless/rt2x00/rt2x00usb.c create mode 100644 drivers/net/wireless/rt2x00/rt2x00usb.h create mode 100644 drivers/net/wireless/rt2x00/rt61pci.c create mode 100644 drivers/net/wireless/rt2x00/rt61pci.h create mode 100644 drivers/net/wireless/rt2x00/rt73usb.c create mode 100644 drivers/net/wireless/rt2x00/rt73usb.h (limited to 'drivers') diff --git a/CREDITS b/CREDITS index 832436e1dd9..550bb2b9fe8 100644 --- a/CREDITS +++ b/CREDITS @@ -665,6 +665,11 @@ D: Minor updates to SCSI types, added /proc/pid/maps protection S: (ask for current address) S: USA +N: Robin Cornelius +E: robincornelius@users.sourceforge.net +D: Ralink rt2x00 WLAN driver +S: Cornwall, U.K. + N: Mark Corner E: mcorner@umich.edu W: http://www.eecs.umich.edu/~mcorner/ @@ -679,6 +684,11 @@ D: Kernel module SMART utilities S: Santa Cruz, California S: USA +N: Luis Correia +E: lfcorreia@users.sf.net +D: Ralink rt2x00 WLAN driver +S: Belas, Portugal + N: Alan Cox W: http://www.linux.org.uk/diary/ D: Linux Networking (0.99.10->2.0.29) @@ -833,6 +843,12 @@ S: Lancs S: PR4 6AX S: United Kingdom +N: Ivo van Doorn +E: IvDoorn@gmail.com +W: http://www.mendiosus.nl +D: Ralink rt2x00 WLAN driver +S: Haarlem, The Netherlands + N: John G Dorsey E: john+@cs.cmu.edu D: ARM Linux ports to Assabet/Neponset, Spot @@ -3517,6 +3533,12 @@ S: Maastrichterweg 63 S: 5554 GG Valkenswaard S: The Netherlands +N: Mark Wallis +E: mwallis@serialmonkey.com +W: http://mark.serialmonkey.com +D: Ralink rt2x00 WLAN driver +S: Newcastle, Australia + N: Peter Shaobo Wang E: pwang@mmdcorp.com W: http://www.mmdcorp.com/pw/linux @@ -3651,6 +3673,15 @@ S: Alte Regensburger Str. 11a S: 93149 Nittenau S: Germany +N: Gertjan van Wingerde +E: gwingerde@home.nl +D: Ralink rt2x00 WLAN driver +D: Minix V2 file-system +D: Misc fixes +S: Geessinkweg 177 +S: 7544 TX Enschede +S: The Netherlands + N: Lars Wirzenius E: liw@iki.fi D: Linux System Administrator's Guide, author, former maintainer diff --git a/MAINTAINERS b/MAINTAINERS index 934afd3dfa4..6ae2b997526 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3147,6 +3147,14 @@ M: corey@world.std.com L: linux-wireless@vger.kernel.org S: Maintained +RALINK RT2X00 WLAN DRIVER +P: rt2x00 project +L: linux-wireless@vger.kernel.org +L: rt2400-devel@lists.sourceforge.net +W: http://rt2x00.serialmonkey.com/ +S: Maintained +F: drivers/net/wireless/rt2x00/ + RANDOM NUMBER DRIVER P: Matt Mackall M: mpm@selenic.com diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 085ba132835..f481c757e22 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -583,5 +583,6 @@ source "drivers/net/wireless/bcm43xx/Kconfig" source "drivers/net/wireless/b43/Kconfig" source "drivers/net/wireless/b43legacy/Kconfig" source "drivers/net/wireless/zd1211rw/Kconfig" +source "drivers/net/wireless/rt2x00/Kconfig" endmenu diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 351024f2fe7..a7a15e3509e 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -53,3 +53,4 @@ obj-$(CONFIG_RTL8187) += rtl8187.o obj-$(CONFIG_ADM8211) += adm8211.o obj-$(CONFIG_IWLWIFI) += iwlwifi/ +obj-$(CONFIG_RT2X00) += rt2x00/ diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig new file mode 100644 index 00000000000..da05b1faf60 --- /dev/null +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -0,0 +1,130 @@ +config RT2X00 + tristate "Ralink driver support" + depends on MAC80211 && WLAN_80211 && EXPERIMENTAL + ---help--- + This will enable the experimental support for the Ralink drivers, + developed in the rt2x00 project . + + These drivers will make use of the Devicescape ieee80211 stack. + + When building one of the individual drivers, the rt2x00 library + will also be created. That library (when the driver is built as + a module) will be called "rt2x00lib.ko". + +config RT2X00_LIB + tristate + depends on RT2X00 + +config RT2X00_LIB_PCI + tristate + depends on RT2X00 + select RT2X00_LIB + +config RT2X00_LIB_USB + tristate + depends on RT2X00 + select RT2X00_LIB + +config RT2X00_LIB_FIRMWARE + boolean + depends on RT2X00_LIB + select CRC_ITU_T + select FW_LOADER + +config RT2X00_LIB_RFKILL + boolean + depends on RT2X00_LIB + select RFKILL + select INPUT_POLLDEV + +config RT2400PCI + tristate "Ralink rt2400 pci/pcmcia support" + depends on RT2X00 && PCI + select RT2X00_LIB_PCI + select EEPROM_93CX6 + ---help--- + This is an experimental driver for the Ralink rt2400 wireless chip. + + When compiled as a module, this driver will be called "rt2400pci.ko". + +config RT2400PCI_RFKILL + bool "RT2400 rfkill support" + depends on RT2400PCI + select RT2X00_LIB_RFKILL + ---help--- + This adds support for integrated rt2400 devices that feature a + hardware button to control the radio state. + This feature depends on the RF switch subsystem rfkill. + +config RT2500PCI + tristate "Ralink rt2500 pci/pcmcia support" + depends on RT2X00 && PCI + select RT2X00_LIB_PCI + select EEPROM_93CX6 + ---help--- + This is an experimental driver for the Ralink rt2500 wireless chip. + + When compiled as a module, this driver will be called "rt2500pci.ko". + +config RT2500PCI_RFKILL + bool "RT2500 rfkill support" + depends on RT2500PCI + select RT2X00_LIB_RFKILL + ---help--- + This adds support for integrated rt2500 devices that feature a + hardware button to control the radio state. + This feature depends on the RF switch subsystem rfkill. + +config RT61PCI + tristate "Ralink rt61 pci/pcmcia support" + depends on RT2X00 && PCI + select RT2X00_LIB_PCI + select RT2X00_LIB_FIRMWARE + select EEPROM_93CX6 + ---help--- + This is an experimental driver for the Ralink rt61 wireless chip. + + When compiled as a module, this driver will be called "rt61pci.ko". + +config RT61PCI_RFKILL + bool "RT61 rfkill support" + depends on RT61PCI + select RT2X00_LIB_RFKILL + ---help--- + This adds support for integrated rt61 devices that feature a + hardware button to control the radio state. + This feature depends on the RF switch subsystem rfkill. + +config RT2500USB + tristate "Ralink rt2500 usb support" + depends on RT2X00 && USB + select RT2X00_LIB_USB + ---help--- + This is an experimental driver for the Ralink rt2500 wireless chip. + + When compiled as a module, this driver will be called "rt2500usb.ko". + +config RT73USB + tristate "Ralink rt73 usb support" + depends on RT2X00 && USB + select RT2X00_LIB_USB + select RT2X00_LIB_FIRMWARE + ---help--- + This is an experimental driver for the Ralink rt73 wireless chip. + + When compiled as a module, this driver will be called "rt73usb.ko". + +config RT2X00_LIB_DEBUGFS + bool "Ralink debugfs support" + depends on RT2X00_LIB && MAC80211_DEBUGFS + ---help--- + Enable creation of debugfs files for the rt2x00 drivers. + These debugfs files support both reading and writing of the + most important register types of the rt2x00 devices. + +config RT2X00_DEBUG + bool "Ralink debug output" + depends on RT2X00_LIB + ---help--- + Enable debugging output for all rt2x00 modules + diff --git a/drivers/net/wireless/rt2x00/Makefile b/drivers/net/wireless/rt2x00/Makefile new file mode 100644 index 00000000000..30d654a42ee --- /dev/null +++ b/drivers/net/wireless/rt2x00/Makefile @@ -0,0 +1,22 @@ +rt2x00lib-objs := rt2x00dev.o rt2x00mac.o rt2x00config.o + +ifeq ($(CONFIG_RT2X00_LIB_DEBUGFS),y) + rt2x00lib-objs += rt2x00debug.o +endif + +ifeq ($(CONFIG_RT2X00_LIB_RFKILL),y) + rt2x00lib-objs += rt2x00rfkill.o +endif + +ifeq ($(CONFIG_RT2X00_LIB_FIRMWARE),y) + rt2x00lib-objs += rt2x00firmware.o +endif + +obj-$(CONFIG_RT2X00_LIB) += rt2x00lib.o +obj-$(CONFIG_RT2X00_LIB_PCI) += rt2x00pci.o +obj-$(CONFIG_RT2X00_LIB_USB) += rt2x00usb.o +obj-$(CONFIG_RT2400PCI) += rt2400pci.o +obj-$(CONFIG_RT2500PCI) += rt2500pci.o +obj-$(CONFIG_RT61PCI) += rt61pci.o +obj-$(CONFIG_RT2500USB) += rt2500usb.o +obj-$(CONFIG_RT73USB) += rt73usb.o diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c new file mode 100644 index 00000000000..38e2188937c --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -0,0 +1,1689 @@ +/* + Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the + Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + Module: rt2400pci + Abstract: rt2400pci device specific routines. + Supported chipsets: RT2460. + */ + +/* + * Set enviroment defines for rt2x00.h + */ +#define DRV_NAME "rt2400pci" + +#include +#include +#include +#include +#include +#include +#include + +#include "rt2x00.h" +#include "rt2x00pci.h" +#include "rt2400pci.h" + +/* + * Register access. + * All access to the CSR registers will go through the methods + * rt2x00pci_register_read and rt2x00pci_register_write. + * BBP and RF register require indirect register access, + * and use the CSR registers BBPCSR and RFCSR to achieve this. + * These indirect registers work with busy bits, + * and we will try maximal REGISTER_BUSY_COUNT times to access + * the register while taking a REGISTER_BUSY_DELAY us delay + * between each attampt. When the busy bit is still set at that time, + * the access attempt is considered to have failed, + * and we will print an error. + */ +static u32 rt2400pci_bbp_check(const struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + unsigned int i; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2x00pci_register_read(rt2x00dev, BBPCSR, ®); + if (!rt2x00_get_field32(reg, BBPCSR_BUSY)) + break; + udelay(REGISTER_BUSY_DELAY); + } + + return reg; +} + +static void rt2400pci_bbp_write(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, const u8 value) +{ + u32 reg; + + /* + * Wait until the BBP becomes ready. + */ + reg = rt2400pci_bbp_check(rt2x00dev); + if (rt2x00_get_field32(reg, BBPCSR_BUSY)) { + ERROR(rt2x00dev, "BBPCSR register busy. Write failed.\n"); + return; + } + + /* + * Write the data into the BBP. + */ + reg = 0; + rt2x00_set_field32(®, BBPCSR_VALUE, value); + rt2x00_set_field32(®, BBPCSR_REGNUM, word); + rt2x00_set_field32(®, BBPCSR_BUSY, 1); + rt2x00_set_field32(®, BBPCSR_WRITE_CONTROL, 1); + + rt2x00pci_register_write(rt2x00dev, BBPCSR, reg); +} + +static void rt2400pci_bbp_read(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, u8 *value) +{ + u32 reg; + + /* + * Wait until the BBP becomes ready. + */ + reg = rt2400pci_bbp_check(rt2x00dev); + if (rt2x00_get_field32(reg, BBPCSR_BUSY)) { + ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n"); + return; + } + + /* + * Write the request into the BBP. + */ + reg = 0; + rt2x00_set_field32(®, BBPCSR_REGNUM, word); + rt2x00_set_field32(®, BBPCSR_BUSY, 1); + rt2x00_set_field32(®, BBPCSR_WRITE_CONTROL, 0); + + rt2x00pci_register_write(rt2x00dev, BBPCSR, reg); + + /* + * Wait until the BBP becomes ready. + */ + reg = rt2400pci_bbp_check(rt2x00dev); + if (rt2x00_get_field32(reg, BBPCSR_BUSY)) { + ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n"); + *value = 0xff; + return; + } + + *value = rt2x00_get_field32(reg, BBPCSR_VALUE); +} + +static void rt2400pci_rf_write(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, const u32 value) +{ + u32 reg; + unsigned int i; + + if (!word) + return; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2x00pci_register_read(rt2x00dev, RFCSR, ®); + if (!rt2x00_get_field32(reg, RFCSR_BUSY)) + goto rf_write; + udelay(REGISTER_BUSY_DELAY); + } + + ERROR(rt2x00dev, "RFCSR register busy. Write failed.\n"); + return; + +rf_write: + reg = 0; + rt2x00_set_field32(®, RFCSR_VALUE, value); + rt2x00_set_field32(®, RFCSR_NUMBER_OF_BITS, 20); + rt2x00_set_field32(®, RFCSR_IF_SELECT, 0); + rt2x00_set_field32(®, RFCSR_BUSY, 1); + + rt2x00pci_register_write(rt2x00dev, RFCSR, reg); + rt2x00_rf_write(rt2x00dev, word, value); +} + +static void rt2400pci_eepromregister_read(struct eeprom_93cx6 *eeprom) +{ + struct rt2x00_dev *rt2x00dev = eeprom->data; + u32 reg; + + rt2x00pci_register_read(rt2x00dev, CSR21, ®); + + eeprom->reg_data_in = !!rt2x00_get_field32(reg, CSR21_EEPROM_DATA_IN); + eeprom->reg_data_out = !!rt2x00_get_field32(reg, CSR21_EEPROM_DATA_OUT); + eeprom->reg_data_clock = + !!rt2x00_get_field32(reg, CSR21_EEPROM_DATA_CLOCK); + eeprom->reg_chip_select = + !!rt2x00_get_field32(reg, CSR21_EEPROM_CHIP_SELECT); +} + +static void rt2400pci_eepromregister_write(struct eeprom_93cx6 *eeprom) +{ + struct rt2x00_dev *rt2x00dev = eeprom->data; + u32 reg = 0; + + rt2x00_set_field32(®, CSR21_EEPROM_DATA_IN, !!eeprom->reg_data_in); + rt2x00_set_field32(®, CSR21_EEPROM_DATA_OUT, !!eeprom->reg_data_out); + rt2x00_set_field32(®, CSR21_EEPROM_DATA_CLOCK, + !!eeprom->reg_data_clock); + rt2x00_set_field32(®, CSR21_EEPROM_CHIP_SELECT, + !!eeprom->reg_chip_select); + + rt2x00pci_register_write(rt2x00dev, CSR21, reg); +} + +#ifdef CONFIG_RT2X00_LIB_DEBUGFS +#define CSR_OFFSET(__word) ( CSR_REG_BASE + ((__word) * sizeof(u32)) ) + +static void rt2400pci_read_csr(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, u32 *data) +{ + rt2x00pci_register_read(rt2x00dev, CSR_OFFSET(word), data); +} + +static void rt2400pci_write_csr(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, u32 data) +{ + rt2x00pci_register_write(rt2x00dev, CSR_OFFSET(word), data); +} + +static const struct rt2x00debug rt2400pci_rt2x00debug = { + .owner = THIS_MODULE, + .csr = { + .read = rt2400pci_read_csr, + .write = rt2400pci_write_csr, + .word_size = sizeof(u32), + .word_count = CSR_REG_SIZE / sizeof(u32), + }, + .eeprom = { + .read = rt2x00_eeprom_read, + .write = rt2x00_eeprom_write, + .word_size = sizeof(u16), + .word_count = EEPROM_SIZE / sizeof(u16), + }, + .bbp = { + .read = rt2400pci_bbp_read, + .write = rt2400pci_bbp_write, + .word_size = sizeof(u8), + .word_count = BBP_SIZE / sizeof(u8), + }, + .rf = { + .read = rt2x00_rf_read, + .write = rt2400pci_rf_write, + .word_size = sizeof(u32), + .word_count = RF_SIZE / sizeof(u32), + }, +}; +#endif /* CONFIG_RT2X00_LIB_DEBUGFS */ + +#ifdef CONFIG_RT2400PCI_RFKILL +static int rt2400pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + rt2x00pci_register_read(rt2x00dev, GPIOCSR, ®); + return rt2x00_get_field32(reg, GPIOCSR_BIT0); +} +#endif /* CONFIG_RT2400PCI_RFKILL */ + +/* + * Configuration handlers. + */ +static void rt2400pci_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *addr) +{ + __le32 reg[2]; + + memset(®, 0, sizeof(reg)); + memcpy(®, addr, ETH_ALEN); + + /* + * The MAC address is passed to us as an array of bytes, + * that array is little endian, so no need for byte ordering. + */ + rt2x00pci_register_multiwrite(rt2x00dev, CSR3, ®, sizeof(reg)); +} + +static void rt2400pci_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) +{ + __le32 reg[2]; + + memset(®, 0, sizeof(reg)); + memcpy(®, bssid, ETH_ALEN); + + /* + * The BSSID is passed to us as an array of bytes, + * that array is little endian, so no need for byte ordering. + */ + rt2x00pci_register_multiwrite(rt2x00dev, CSR5, ®, sizeof(reg)); +} + +static void rt2400pci_config_packet_filter(struct rt2x00_dev *rt2x00dev, + const unsigned int filter) +{ + int promisc = !!(filter & IFF_PROMISC); + u32 reg; + + rt2x00pci_register_read(rt2x00dev, RXCSR0, ®); + rt2x00_set_field32(®, RXCSR0_DROP_NOT_TO_ME, !promisc); + rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); +} + +static void rt2400pci_config_type(struct rt2x00_dev *rt2x00dev, int type) +{ + u32 reg; + + rt2x00pci_register_write(rt2x00dev, CSR14, 0); + + /* + * Apply hardware packet filter. + */ + rt2x00pci_register_read(rt2x00dev, RXCSR0, ®); + + if (!is_monitor_present(&rt2x00dev->interface) && + (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_STA)) + rt2x00_set_field32(®, RXCSR0_DROP_TODS, 1); + else + rt2x00_set_field32(®, RXCSR0_DROP_TODS, 0); + + /* + * If there is a non-monitor interface present + * the packet should be strict (even if a monitor interface is present!). + * When there is only 1 interface present which is in monitor mode + * we should start accepting _all_ frames. + */ + if (is_interface_present(&rt2x00dev->interface)) { + rt2x00_set_field32(®, RXCSR0_DROP_CRC, 1); + rt2x00_set_field32(®, RXCSR0_DROP_PHYSICAL, 1); + rt2x00_set_field32(®, RXCSR0_DROP_CONTROL, 1); + rt2x00_set_field32(®, RXCSR0_DROP_VERSION_ERROR, 1); + } else if (is_monitor_present(&rt2x00dev->interface)) { + rt2x00_set_field32(®, RXCSR0_DROP_CRC, 0); + rt2x00_set_field32(®, RXCSR0_DROP_PHYSICAL, 0); + rt2x00_set_field32(®, RXCSR0_DROP_CONTROL, 0); + rt2x00_set_field32(®, RXCSR0_DROP_VERSION_ERROR, 0); + } + + rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); + + /* + * Enable beacon config + */ + rt2x00pci_register_read(rt2x00dev, BCNCSR1, ®); + rt2x00_set_field32(®, BCNCSR1_PRELOAD, + PREAMBLE + get_duration(IEEE80211_HEADER, 2)); + rt2x00pci_register_write(rt2x00dev, BCNCSR1, reg); + + /* + * Enable synchronisation. + */ + rt2x00pci_register_read(rt2x00dev, CSR14, ®); + if (is_interface_present(&rt2x00dev->interface)) { + rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); + rt2x00_set_field32(®, CSR14_TBCN, 1); + } + + rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); + if (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_AP) + rt2x00_set_field32(®, CSR14_TSF_SYNC, 2); + else if (type == IEEE80211_IF_TYPE_STA) + rt2x00_set_field32(®, CSR14_TSF_SYNC, 1); + else if (is_monitor_present(&rt2x00dev->interface) && + !is_interface_present(&rt2x00dev->interface)) + rt2x00_set_field32(®, CSR14_TSF_SYNC, 0); + + rt2x00pci_register_write(rt2x00dev, CSR14, reg); +} + +static void rt2400pci_config_rate(struct rt2x00_dev *rt2x00dev, const int rate) +{ + struct ieee80211_conf *conf = &rt2x00dev->hw->conf; + u32 reg; + u32 preamble; + u16 value; + + if (DEVICE_GET_RATE_FIELD(rate, PREAMBLE)) + preamble = SHORT_PREAMBLE; + else + preamble = PREAMBLE; + + reg = DEVICE_GET_RATE_FIELD(rate, RATEMASK) & DEV_BASIC_RATEMASK; + rt2x00pci_register_write(rt2x00dev, ARCSR1, reg); + + rt2x00pci_register_read(rt2x00dev, TXCSR1, ®); + value = ((conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) ? + SHORT_DIFS : DIFS) + + PLCP + preamble + get_duration(ACK_SIZE, 10); + rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, value); + value = SIFS + PLCP + preamble + get_duration(ACK_SIZE, 10); + rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME, value); + rt2x00pci_register_write(rt2x00dev, TXCSR1, reg); + + preamble = DEVICE_GET_RATE_FIELD(rate, PREAMBLE) ? 0x08 : 0x00; + + rt2x00pci_register_read(rt2x00dev, ARCSR2, ®); + rt2x00_set_field32(®, ARCSR2_SIGNAL, 0x00 | preamble); + rt2x00_set_field32(®, ARCSR2_SERVICE, 0x04); + rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 10)); + rt2x00pci_register_write(rt2x00dev, ARCSR2, reg); + + rt2x00pci_register_read(rt2x00dev, ARCSR3, ®); + rt2x00_set_field32(®, ARCSR3_SIGNAL, 0x01 | preamble); + rt2x00_set_field32(®, ARCSR3_SERVICE, 0x04); + rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 20)); + rt2x00pci_register_write(rt2x00dev, ARCSR3, reg); + + rt2x00pci_register_read(rt2x00dev, ARCSR4, ®); + rt2x00_set_field32(®, ARCSR4_SIGNAL, 0x02 | preamble); + rt2x00_set_field32(®, ARCSR4_SERVICE, 0x04); + rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 55)); + rt2x00pci_register_write(rt2x00dev, ARCSR4, reg); + + rt2x00pci_register_read(rt2x00dev, ARCSR5, ®); + rt2x00_set_field32(®, ARCSR5_SIGNAL, 0x03 | preamble); + rt2x00_set_field32(®, ARCSR5_SERVICE, 0x84); + rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 110)); + rt2x00pci_register_write(rt2x00dev, ARCSR5, reg); +} + +static void rt2400pci_config_phymode(struct rt2x00_dev *rt2x00dev, + const int phymode) +{ + struct ieee80211_hw_mode *mode; + struct ieee80211_rate *rate; + + rt2x00dev->curr_hwmode = HWMODE_B; + + mode = &rt2x00dev->hwmodes[rt2x00dev->curr_hwmode]; + rate = &mode->rates[mode->num_rates - 1]; + + rt2400pci_config_rate(rt2x00dev, rate->val2); +} + +static void rt2400pci_config_channel(struct rt2x00_dev *rt2x00dev, + const int index, const int channel) +{ + struct rf_channel reg; + + /* + * Fill rf_reg structure. + */ + memcpy(®, &rt2x00dev->spec.channels[index], sizeof(reg)); + + /* + * Switch on tuning bits. + */ + rt2x00_set_field32(®.rf1, RF1_TUNER, 1); + rt2x00_set_field32(®.rf3, RF3_TUNER, 1); + + rt2400pci_rf_write(rt2x00dev, 1, reg.rf1); + rt2400pci_rf_write(rt2x00dev, 2, reg.rf2); + rt2400pci_rf_write(rt2x00dev, 3, reg.rf3); + + /* + * RF2420 chipset don't need any additional actions. + */ + if (rt2x00_rf(&rt2x00dev->chip, RF2420)) + return; + + /* + * For the RT2421 chipsets we need to write an invalid + * reference clock rate to activate auto_tune. + * After that we set the value back to the correct channel. + */ + rt2400pci_rf_write(rt2x00dev, 1, reg.rf1); + rt2400pci_rf_write(rt2x00dev, 2, 0x000c2a32); + rt2400pci_rf_write(rt2x00dev, 3, reg.rf3); + + msleep(1); + + rt2400pci_rf_write(rt2x00dev, 1, reg.rf1); + rt2400pci_rf_write(rt2x00dev, 2, reg.rf2); + rt2400pci_rf_write(rt2x00dev, 3, reg.rf3); + + msleep(1); + + /* + * Switch off tuning bits. + */ + rt2x00_set_field32(®.rf1, RF1_TUNER, 0); + rt2x00_set_field32(®.rf3, RF3_TUNER, 0); + + rt2400pci_rf_write(rt2x00dev, 1, reg.rf1); + rt2400pci_rf_write(rt2x00dev, 3, reg.rf3); + + /* + * Clear false CRC during channel switch. + */ + rt2x00pci_register_read(rt2x00dev, CNT0, ®.rf1); +} + +static void rt2400pci_config_txpower(struct rt2x00_dev *rt2x00dev, int txpower) +{ + rt2400pci_bbp_write(rt2x00dev, 3, TXPOWER_TO_DEV(txpower)); +} + +static void rt2400pci_config_antenna(struct rt2x00_dev *rt2x00dev, + int antenna_tx, int antenna_rx) +{ + u8 r1; + u8 r4; + + rt2400pci_bbp_read(rt2x00dev, 4, &r4); + rt2400pci_bbp_read(rt2x00dev, 1, &r1); + + /* + * Configure the TX antenna. + */ + switch (antenna_tx) { + case ANTENNA_SW_DIVERSITY: + case ANTENNA_HW_DIVERSITY: + rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 1); + break; + case ANTENNA_A: + rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 0); + break; + case ANTENNA_B: + rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 2); + break; + } + + /* + * Configure the RX antenna. + */ + switch (antenna_rx) { + case ANTENNA_SW_DIVERSITY: + case ANTENNA_HW_DIVERSITY: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); + break; + case ANTENNA_A: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 0); + break; + case ANTENNA_B: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2); + break; + } + + rt2400pci_bbp_write(rt2x00dev, 4, r4); + rt2400pci_bbp_write(rt2x00dev, 1, r1); +} + +static void rt2400pci_config_duration(struct rt2x00_dev *rt2x00dev, + int short_slot_time, int beacon_int) +{ + u32 reg; + + rt2x00pci_register_read(rt2x00dev, CSR11, ®); + rt2x00_set_field32(®, CSR11_SLOT_TIME, + short_slot_time ? SHORT_SLOT_TIME : SLOT_TIME); + rt2x00pci_register_write(rt2x00dev, CSR11, reg); + + rt2x00pci_register_read(rt2x00dev, CSR18, ®); + rt2x00_set_field32(®, CSR18_SIFS, SIFS); + rt2x00_set_field32(®, CSR18_PIFS, + short_slot_time ? SHORT_PIFS : PIFS); + rt2x00pci_register_write(rt2x00dev, CSR18, reg); + + rt2x00pci_register_read(rt2x00dev, CSR19, ®); + rt2x00_set_field32(®, CSR19_DIFS, + short_slot_time ? SHORT_DIFS : DIFS); + rt2x00_set_field32(®, CSR19_EIFS, EIFS); + rt2x00pci_register_write(rt2x00dev, CSR19, reg); + + rt2x00pci_register_read(rt2x00dev, TXCSR1, ®); + rt2x00_set_field32(®, TXCSR1_TSF_OFFSET, IEEE80211_HEADER); + rt2x00_set_field32(®, TXCSR1_AUTORESPONDER, 1); + rt2x00pci_register_write(rt2x00dev, TXCSR1, reg); + + rt2x00pci_register_read(rt2x00dev, CSR12, ®); + rt2x00_set_field32(®, CSR12_BEACON_INTERVAL, beacon_int * 16); + rt2x00_set_field32(®, CSR12_CFP_MAX_DURATION, beacon_int * 16); + rt2x00pci_register_write(rt2x00dev, CSR12, reg); +} + +static void rt2400pci_config(struct rt2x00_dev *rt2x00dev, + const unsigned int flags, + struct ieee80211_conf *conf) +{ + int short_slot_time = conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME; + + if (flags & CONFIG_UPDATE_PHYMODE) + rt2400pci_config_phymode(rt2x00dev, conf->phymode); + if (flags & CONFIG_UPDATE_CHANNEL) + rt2400pci_config_channel(rt2x00dev, conf->channel_val, + conf->channel); + if (flags & CONFIG_UPDATE_TXPOWER) + rt2400pci_config_txpower(rt2x00dev, conf->power_level); + if (flags & CONFIG_UPDATE_ANTENNA) + rt2400pci_config_antenna(rt2x00dev, conf->antenna_sel_tx, + conf->antenna_sel_rx); + if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT)) + rt2400pci_config_duration(rt2x00dev, short_slot_time, + conf->beacon_int); +} + +static void rt2400pci_config_cw(struct rt2x00_dev *rt2x00dev, + struct ieee80211_tx_queue_params *params) +{ + u32 reg; + + rt2x00pci_register_read(rt2x00dev, CSR11, ®); + rt2x00_set_field32(®, CSR11_CWMIN, params->cw_min); + rt2x00_set_field32(®, CSR11_CWMAX, params->cw_max); + rt2x00pci_register_write(rt2x00dev, CSR11, reg); +} + +/* + * LED functions. + */ +static void rt2400pci_enable_led(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + rt2x00pci_register_read(rt2x00dev, LEDCSR, ®); + + rt2x00_set_field32(®, LEDCSR_ON_PERIOD, 70); + rt2x00_set_field32(®, LEDCSR_OFF_PERIOD, 30); + + if (rt2x00dev->led_mode == LED_MODE_TXRX_ACTIVITY) { + rt2x00_set_field32(®, LEDCSR_LINK, 1); + rt2x00_set_field32(®, LEDCSR_ACTIVITY, 0); + } else if (rt2x00dev->led_mode == LED_MODE_ASUS) { + rt2x00_set_field32(®, LEDCSR_LINK, 0); + rt2x00_set_field32(®, LEDCSR_ACTIVITY, 1); + } else { + rt2x00_set_field32(®, LEDCSR_LINK, 1); + rt2x00_set_field32(®, LEDCSR_ACTIVITY, 1); + } + + rt2x00pci_register_write(rt2x00dev, LEDCSR, reg); +} + +static void rt2400pci_disable_led(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + rt2x00pci_register_read(rt2x00dev, LEDCSR, ®); + rt2x00_set_field32(®, LEDCSR_LINK, 0); + rt2x00_set_field32(®, LEDCSR_ACTIVITY, 0); + rt2x00pci_register_write(rt2x00dev, LEDCSR, reg); +} + +/* + * Link tuning + */ +static void rt2400pci_link_stats(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + u8 bbp; + + /* + * Update FCS error count from register. + */ + rt2x00pci_register_read(rt2x00dev, CNT0, ®); + rt2x00dev->link.rx_failed = rt2x00_get_field32(reg, CNT0_FCS_ERROR); + + /* + * Update False CCA count from register. + */ + rt2400pci_bbp_read(rt2x00dev, 39, &bbp); + rt2x00dev->link.false_cca = bbp; +} + +static void rt2400pci_reset_tuner(struct rt2x00_dev *rt2x00dev) +{ + rt2400pci_bbp_write(rt2x00dev, 13, 0x08); + rt2x00dev->link.vgc_level = 0x08; +} + +static void rt2400pci_link_tuner(struct rt2x00_dev *rt2x00dev) +{ + u8 reg; + + /* + * The link tuner should not run longer then 60 seconds, + * and should run once every 2 seconds. + */ + if (rt2x00dev->link.count > 60 || !(rt2x00dev->link.count & 1)) + return; + + /* + * Base r13 link tuning on the false cca count. + */ + rt2400pci_bbp_read(rt2x00dev, 13, ®); + + if (rt2x00dev->link.false_cca > 512 && reg < 0x20) { + rt2400pci_bbp_write(rt2x00dev, 13, ++reg); + rt2x00dev->link.vgc_level = reg; + } else if (rt2x00dev->link.false_cca < 100 && reg > 0x08) { + rt2400pci_bbp_write(rt2x00dev, 13, --reg); + rt2x00dev->link.vgc_level = reg; + } +} + +/* + * Initialization functions. + */ +static void rt2400pci_init_rxring(struct rt2x00_dev *rt2x00dev) +{ + struct data_ring *ring = rt2x00dev->rx; + struct data_desc *rxd; + unsigned int i; + u32 word; + + memset(ring->data_addr, 0x00, rt2x00_get_ring_size(ring)); + + for (i = 0; i < ring->stats.limit; i++) { + rxd = ring->entry[i].priv; + + rt2x00_desc_read(rxd, 2, &word); + rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH, + ring->data_size); + rt2x00_desc_write(rxd, 2, word); + + rt2x00_desc_read(rxd, 1, &word); + rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, + ring->entry[i].data_dma); + rt2x00_desc_write(rxd, 1, word); + + rt2x00_desc_read(rxd, 0, &word); + rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); + rt2x00_desc_write(rxd, 0, word); + } + + rt2x00_ring_index_clear(rt2x00dev->rx); +} + +static void rt2400pci_init_txring(struct rt2x00_dev *rt2x00dev, const int queue) +{ + struct data_ring *ring = rt2x00lib_get_ring(rt2x00dev, queue); + struct data_desc *txd; + unsigned int i; + u32 word; + + memset(ring->data_addr, 0x00, rt2x00_get_ring_size(ring)); + + for (i = 0; i < ring->stats.limit; i++) { + txd = ring->entry[i].priv; + + rt2x00_desc_read(txd, 1, &word); + rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, + ring->entry[i].data_dma); + rt2x00_desc_write(txd, 1, word); + + rt2x00_desc_read(txd, 2, &word); + rt2x00_set_field32(&word, TXD_W2_BUFFER_LENGTH, + ring->data_size); + rt2x00_desc_write(txd, 2, word); + + rt2x00_desc_read(txd, 0, &word); + rt2x00_set_field32(&word, TXD_W0_VALID, 0); + rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); + rt2x00_desc_write(txd, 0, word); + } + + rt2x00_ring_index_clear(ring); +} + +static int rt2400pci_init_rings(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + /* + * Initialize rings. + */ + rt2400pci_init_rxring(rt2x00dev); + rt2400pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA0); + rt2400pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA1); + rt2400pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_AFTER_BEACON); + rt2400pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON); + + /* + * Initialize registers. + */ + rt2x00pci_register_read(rt2x00dev, TXCSR2, ®); + rt2x00_set_field32(®, TXCSR2_TXD_SIZE, + rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].desc_size); + rt2x00_set_field32(®, TXCSR2_NUM_TXD, + rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA1].stats.limit); + rt2x00_set_field32(®, TXCSR2_NUM_ATIM, + rt2x00dev->bcn[1].stats.limit); + rt2x00_set_field32(®, TXCSR2_NUM_PRIO, + rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].stats.limit); + rt2x00pci_register_write(rt2x00dev, TXCSR2, reg); + + rt2x00pci_register_read(rt2x00dev, TXCSR3, ®); + rt2x00_set_field32(®, TXCSR3_TX_RING_REGISTER, + rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA1].data_dma); + rt2x00pci_register_write(rt2x00dev, TXCSR3, reg); + + rt2x00pci_register_read(rt2x00dev, TXCSR5, ®); + rt2x00_set_field32(®, TXCSR5_PRIO_RING_REGISTER, + rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].data_dma); + rt2x00pci_register_write(rt2x00dev, TXCSR5, reg); + + rt2x00pci_register_read(rt2x00dev, TXCSR4, ®); + rt2x00_set_field32(®, TXCSR4_ATIM_RING_REGISTER, + rt2x00dev->bcn[1].data_dma); + rt2x00pci_register_write(rt2x00dev, TXCSR4, reg); + + rt2x00pci_register_read(rt2x00dev, TXCSR6, ®); + rt2x00_set_field32(®, TXCSR6_BEACON_RING_REGISTER, + rt2x00dev->bcn[0].data_dma); + rt2x00pci_register_write(rt2x00dev, TXCSR6, reg); + + rt2x00pci_register_read(rt2x00dev, RXCSR1, ®); + rt2x00_set_field32(®, RXCSR1_RXD_SIZE, rt2x00dev->rx->desc_size); + rt2x00_set_field32(®, RXCSR1_NUM_RXD, rt2x00dev->rx->stats.limit); + rt2x00pci_register_write(rt2x00dev, RXCSR1, reg); + + rt2x00pci_register_read(rt2x00dev, RXCSR2, ®); + rt2x00_set_field32(®, RXCSR2_RX_RING_REGISTER, + rt2x00dev->rx->data_dma); + rt2x00pci_register_write(rt2x00dev, RXCSR2, reg); + + return 0; +} + +static int rt2400pci_init_registers(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + rt2x00pci_register_write(rt2x00dev, PSCSR0, 0x00020002); + rt2x00pci_register_write(rt2x00dev, PSCSR1, 0x00000002); + rt2x00pci_register_write(rt2x00dev, PSCSR2, 0x00023f20); + rt2x00pci_register_write(rt2x00dev, PSCSR3, 0x00000002); + + rt2x00pci_register_read(rt2x00dev, TIMECSR, ®); + rt2x00_set_field32(®, TIMECSR_US_COUNT, 33); + rt2x00_set_field32(®, TIMECSR_US_64_COUNT, 63); + rt2x00_set_field32(®, TIMECSR_BEACON_EXPECT, 0); + rt2x00pci_register_write(rt2x00dev, TIMECSR, reg); + + rt2x00pci_register_read(rt2x00dev, CSR9, ®); + rt2x00_set_field32(®, CSR9_MAX_FRAME_UNIT, + (rt2x00dev->rx->data_size / 128)); + rt2x00pci_register_write(rt2x00dev, CSR9, reg); + + rt2x00pci_register_write(rt2x00dev, CNT3, 0x3f080000); + + rt2x00pci_register_read(rt2x00dev, ARCSR0, ®); + rt2x00_set_field32(®, ARCSR0_AR_BBP_DATA0, 133); + rt2x00_set_field32(®, ARCSR0_AR_BBP_ID0, 134); + rt2x00_set_field32(®, ARCSR0_AR_BBP_DATA1, 136); + rt2x00_set_field32(®, ARCSR0_AR_BBP_ID1, 135); + rt2x00pci_register_write(rt2x00dev, ARCSR0, reg); + + rt2x00pci_register_read(rt2x00dev, RXCSR3, ®); + rt2x00_set_field32(®, RXCSR3_BBP_ID0, 3); /* Tx power.*/ + rt2x00_set_field32(®, RXCSR3_BBP_ID0_VALID, 1); + rt2x00_set_field32(®, RXCSR3_BBP_ID1, 32); /* Signal */ + rt2x00_set_field32(®, RXCSR3_BBP_ID1_VALID, 1); + rt2x00_set_field32(®, RXCSR3_BBP_ID2, 36); /* Rssi */ + rt2x00_set_field32(®, RXCSR3_BBP_ID2_VALID, 1); + rt2x00pci_register_write(rt2x00dev, RXCSR3, reg); + + rt2x00pci_register_write(rt2x00dev, PWRCSR0, 0x3f3b3100); + + if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE)) + return -EBUSY; + + rt2x00pci_register_write(rt2x00dev, MACCSR0, 0x00217223); + rt2x00pci_register_write(rt2x00dev, MACCSR1, 0x00235518); + + rt2x00pci_register_read(rt2x00dev, MACCSR2, ®); + rt2x00_set_field32(®, MACCSR2_DELAY, 64); + rt2x00pci_register_write(rt2x00dev, MACCSR2, reg); + + rt2x00pci_register_read(rt2x00dev, RALINKCSR, ®); + rt2x00_set_field32(®, RALINKCSR_AR_BBP_DATA0, 17); + rt2x00_set_field32(®, RALINKCSR_AR_BBP_ID0, 154); + rt2x00_set_field32(®, RALINKCSR_AR_BBP_DATA1, 0); + rt2x00_set_field32(®, RALINKCSR_AR_BBP_ID1, 154); + rt2x00pci_register_write(rt2x00dev, RALINKCSR, reg); + + rt2x00pci_register_read(rt2x00dev, CSR1, ®); + rt2x00_set_field32(®, CSR1_SOFT_RESET, 1); + rt2x00_set_field32(®, CSR1_BBP_RESET, 0); + rt2x00_set_field32(®, CSR1_HOST_READY, 0); + rt2x00pci_register_write(rt2x00dev, CSR1, reg); + + rt2x00pci_register_read(rt2x00dev, CSR1, ®); + rt2x00_set_field32(®, CSR1_SOFT_RESET, 0); + rt2x00_set_field32(®, CSR1_HOST_READY, 1); + rt2x00pci_register_write(rt2x00dev, CSR1, reg); + + /* + * We must clear the FCS and FIFO error count. + * These registers are cleared on read, + * so we may pass a useless variable to store the value. + */ + rt2x00pci_register_read(rt2x00dev, CNT0, ®); + rt2x00pci_register_read(rt2x00dev, CNT4, ®); + + return 0; +} + +static int rt2400pci_init_bbp(struct rt2x00_dev *rt2x00dev) +{ + unsigned int i; + u16 eeprom; + u8 reg_id; + u8 value; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2400pci_bbp_read(rt2x00dev, 0, &value); + if ((value != 0xff) && (value != 0x00)) + goto continue_csr_init; + NOTICE(rt2x00dev, "Waiting for BBP register.\n"); + udelay(REGISTER_BUSY_DELAY); + } + + ERROR(rt2x00dev, "BBP register access failed, aborting.\n"); + return -EACCES; + +continue_csr_init: + rt2400pci_bbp_write(rt2x00dev, 1, 0x00); + rt2400pci_bbp_write(rt2x00dev, 3, 0x27); + rt2400pci_bbp_write(rt2x00dev, 4, 0x08); + rt2400pci_bbp_write(rt2x00dev, 10, 0x0f); + rt2400pci_bbp_write(rt2x00dev, 15, 0x72); + rt2400pci_bbp_write(rt2x00dev, 16, 0x74); + rt2400pci_bbp_write(rt2x00dev, 17, 0x20); + rt2400pci_bbp_write(rt2x00dev, 18, 0x72); + rt2400pci_bbp_write(rt2x00dev, 19, 0x0b); + rt2400pci_bbp_write(rt2x00dev, 20, 0x00); + rt2400pci_bbp_write(rt2x00dev, 28, 0x11); + rt2400pci_bbp_write(rt2x00dev, 29, 0x04); + rt2400pci_bbp_write(rt2x00dev, 30, 0x21); + rt2400pci_bbp_write(rt2x00dev, 31, 0x00); + + DEBUG(rt2x00dev, "Start initialization from EEPROM...\n"); + for (i = 0; i < EEPROM_BBP_SIZE; i++) { + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom); + + if (eeprom != 0xffff && eeprom != 0x0000) { + reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID); + value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE); + DEBUG(rt2x00dev, "BBP: 0x%02x, value: 0x%02x.\n", + reg_id, value); + rt2400pci_bbp_write(rt2x00dev, reg_id, value); + } + } + DEBUG(rt2x00dev, "...End initialization from EEPROM.\n"); + + return 0; +} + +/* + * Device state switch handlers. + */ +static void rt2400pci_toggle_rx(struct rt2x00_dev *rt2x00dev, + enum dev_state state) +{ + u32 reg; + + rt2x00pci_register_read(rt2x00dev, RXCSR0, ®); + rt2x00_set_field32(®, RXCSR0_DISABLE_RX, + state == STATE_RADIO_RX_OFF); + rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); +} + +static void rt2400pci_toggle_irq(struct rt2x00_dev *rt2x00dev, + enum dev_state state) +{ + int mask = (state == STATE_RADIO_IRQ_OFF); + u32 reg; + + /* + * When interrupts are being enabled, the interrupt registers + * should clear the register to assure a clean state. + */ + if (state == STATE_RADIO_IRQ_ON) { + rt2x00pci_register_read(rt2x00dev, CSR7, ®); + rt2x00pci_register_write(rt2x00dev, CSR7, reg); + } + + /* + * Only toggle the interrupts bits we are going to use. + * Non-checked interrupt bits are disabled by default. + */ + rt2x00pci_register_read(rt2x00dev, CSR8, ®); + rt2x00_set_field32(®, CSR8_TBCN_EXPIRE, mask); + rt2x00_set_field32(®, CSR8_TXDONE_TXRING, mask); + rt2x00_set_field32(®, CSR8_TXDONE_ATIMRING, mask); + rt2x00_set_field32(®, CSR8_TXDONE_PRIORING, mask); + rt2x00_set_field32(®, CSR8_RXDONE, mask); + rt2x00pci_register_write(rt2x00dev, CSR8, reg); +} + +static int rt2400pci_enable_radio(struct rt2x00_dev *rt2x00dev) +{ + /* + * Initialize all registers. + */ + if (rt2400pci_init_rings(rt2x00dev) || + rt2400pci_init_registers(rt2x00dev) || + rt2400pci_init_bbp(rt2x00dev)) { + ERROR(rt2x00dev, "Register initialization failed.\n"); + return -EIO; + } + + /* + * Enable interrupts. + */ + rt2400pci_toggle_irq(rt2x00dev, STATE_RADIO_IRQ_ON); + + /* + * Enable LED + */ + rt2400pci_enable_led(rt2x00dev); + + return 0; +} + +static void rt2400pci_disable_radio(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + /* + * Disable LED + */ + rt2400pci_disable_led(rt2x00dev); + + rt2x00pci_register_write(rt2x00dev, PWRCSR0, 0); + + /* + * Disable synchronisation. + */ + rt2x00pci_register_write(rt2x00dev, CSR14, 0); + + /* + * Cancel RX and TX. + */ + rt2x00pci_register_read(rt2x00dev, TXCSR0, ®); + rt2x00_set_field32(®, TXCSR0_ABORT, 1); + rt2x00pci_register_write(rt2x00dev, TXCSR0, reg); + + /* + * Disable interrupts. + */ + rt2400pci_toggle_irq(rt2x00dev, STATE_RADIO_IRQ_OFF); +} + +static int rt2400pci_set_state(struct rt2x00_dev *rt2x00dev, + enum dev_state state) +{ + u32 reg; + unsigned int i; + char put_to_sleep; + char bbp_state; + char rf_state; + + put_to_sleep = (state != STATE_AWAKE); + + rt2x00pci_register_read(rt2x00dev, PWRCSR1, ®); + rt2x00_set_field32(®, PWRCSR1_SET_STATE, 1); + rt2x00_set_field32(®, PWRCSR1_BBP_DESIRE_STATE, state); + rt2x00_set_field32(®, PWRCSR1_RF_DESIRE_STATE, state); + rt2x00_set_field32(®, PWRCSR1_PUT_TO_SLEEP, put_to_sleep); + rt2x00pci_register_write(rt2x00dev, PWRCSR1, reg); + + /* + * Device is not guaranteed to be in the requested state yet. + * We must wait until the register indicates that the + * device has entered the correct state. + */ + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2x00pci_register_read(rt2x00dev, PWRCSR1, ®); + bbp_state = rt2x00_get_field32(reg, PWRCSR1_BBP_CURR_STATE); + rf_state = rt2x00_get_field32(reg, PWRCSR1_RF_CURR_STATE); + if (bbp_state == state && rf_state == state) + return 0; + msleep(10); + } + + NOTICE(rt2x00dev, "Device failed to enter state %d, " + "current device state: bbp %d and rf %d.\n", + state, bbp_state, rf_state); + + return -EBUSY; +} + +static int rt2400pci_set_device_state(struct rt2x00_dev *rt2x00dev, + enum dev_state state) +{ + int retval = 0; + + switch (state) { + case STATE_RADIO_ON: + retval = rt2400pci_enable_radio(rt2x00dev); + break; + case STATE_RADIO_OFF: + rt2400pci_disable_radio(rt2x00dev); + break; + case STATE_RADIO_RX_ON: + case STATE_RADIO_RX_OFF: + rt2400pci_toggle_rx(rt2x00dev, state); + break; + case STATE_DEEP_SLEEP: + case STATE_SLEEP: + case STATE_STANDBY: + case STATE_AWAKE: + retval = rt2400pci_set_state(rt2x00dev, state); + break; + default: + retval = -ENOTSUPP; + break; + } + + return retval; +} + +/* + * TX descriptor initialization + */ +static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, + struct data_desc *txd, + struct data_entry_desc *desc, + struct ieee80211_hdr *ieee80211hdr, + unsigned int length, + struct ieee80211_tx_control *control) +{ + u32 word; + u32 signal = 0; + u32 service = 0; + u32 length_high = 0; + u32 length_low = 0; + + /* + * The PLCP values should be treated as if they + * were BBP values. + */ + rt2x00_set_field32(&signal, BBPCSR_VALUE, desc->signal); + rt2x00_set_field32(&signal, BBPCSR_REGNUM, 5); + rt2x00_set_field32(&signal, BBPCSR_BUSY, 1); + + rt2x00_set_field32(&service, BBPCSR_VALUE, desc->service); + rt2x00_set_field32(&service, BBPCSR_REGNUM, 6); + rt2x00_set_field32(&service, BBPCSR_BUSY, 1); + + rt2x00_set_field32(&length_high, BBPCSR_VALUE, desc->length_high); + rt2x00_set_field32(&length_high, BBPCSR_REGNUM, 7); + rt2x00_set_field32(&length_high, BBPCSR_BUSY, 1); + + rt2x00_set_field32(&length_low, BBPCSR_VALUE, desc->length_low); + rt2x00_set_field32(&length_low, BBPCSR_REGNUM, 8); + rt2x00_set_field32(&length_low, BBPCSR_BUSY, 1); + + /* + * Start writing the descriptor words. + */ + rt2x00_desc_read(txd, 2, &word); + rt2x00_set_field32(&word, TXD_W2_DATABYTE_COUNT, length); + rt2x00_desc_write(txd, 2, word); + + rt2x00_desc_read(txd, 3, &word); + rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL, signal); + rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE, service); + rt2x00_desc_write(txd, 3, word); + + rt2x00_desc_read(txd, 4, &word); + rt2x00_set_field32(&word, TXD_W4_PLCP_LENGTH_LOW, length_low); + rt2x00_set_field32(&word, TXD_W4_PLCP_LENGTH_HIGH, length_high); + rt2x00_desc_write(txd, 4, word); + + rt2x00_desc_read(txd, 0, &word); + rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 1); + rt2x00_set_field32(&word, TXD_W0_VALID, 1); + rt2x00_set_field32(&word, TXD_W0_MORE_FRAG, + test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags)); + rt2x00_set_field32(&word, TXD_W0_ACK, + !(control->flags & IEEE80211_TXCTL_NO_ACK)); + rt2x00_set_field32(&word, TXD_W0_TIMESTAMP, + test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags)); + rt2x00_set_field32(&word, TXD_W0_RTS, + test_bit(ENTRY_TXD_RTS_FRAME, &desc->flags)); + rt2x00_set_field32(&word, TXD_W0_IFS, desc->ifs); + rt2x00_set_field32(&word, TXD_W0_RETRY_MODE, + !!(control->flags & + IEEE80211_TXCTL_LONG_RETRY_LIMIT)); + rt2x00_desc_write(txd, 0, word); +} + +/* + * TX data initialization + */ +static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, + unsigned int queue) +{ + u32 reg; + + if (queue == IEEE80211_TX_QUEUE_BEACON) { + rt2x00pci_register_read(rt2x00dev, CSR14, ®); + if (!rt2x00_get_field32(reg, CSR14_BEACON_GEN)) { + rt2x00_set_field32(®, CSR14_BEACON_GEN, 1); + rt2x00pci_register_write(rt2x00dev, CSR14, reg); + } + return; + } + + rt2x00pci_register_read(rt2x00dev, TXCSR0, ®); + if (queue == IEEE80211_TX_QUEUE_DATA0) + rt2x00_set_field32(®, TXCSR0_KICK_PRIO, 1); + else if (queue == IEEE80211_TX_QUEUE_DATA1) + rt2x00_set_field32(®, TXCSR0_KICK_TX, 1); + else if (queue == IEEE80211_TX_QUEUE_AFTER_BEACON) + rt2x00_set_field32(®, TXCSR0_KICK_ATIM, 1); + rt2x00pci_register_write(rt2x00dev, TXCSR0, reg); +} + +/* + * RX control handlers + */ +static int rt2400pci_fill_rxdone(struct data_entry *entry, + int *signal, int *rssi, int *ofdm, int *size) +{ + struct data_desc *rxd = entry->priv; + u32 word0; + u32 word2; + + rt2x00_desc_read(rxd, 0, &word0); + rt2x00_desc_read(rxd, 2, &word2); + + if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR) || + rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR)) + return -EINVAL; + + /* + * Obtain the status about this packet. + */ + *signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL); + *rssi = rt2x00_get_field32(word2, RXD_W2_RSSI) - + entry->ring->rt2x00dev->rssi_offset; + *ofdm = 0; + *size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); + + return 0; +} + +/* + * Interrupt functions. + */ +static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev, const int queue) +{ + struct data_ring *ring = rt2x00lib_get_ring(rt2x00dev, queue); + struct data_entry *entry; + struct data_desc *txd; + u32 word; + int tx_status; + int retry; + + while (!rt2x00_ring_empty(ring)) { + entry = rt2x00_get_data_entry_done(ring); + txd = entry->priv; + rt2x00_desc_read(txd, 0, &word); + + if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || + !rt2x00_get_field32(word, TXD_W0_VALID)) + break; + + /* + * Obtain the status about this packet. + */ + tx_status = rt2x00_get_field32(word, TXD_W0_RESULT); + retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT); + + rt2x00lib_txdone(entry, tx_status, retry); + + /* + * Make this entry available for reuse. + */ + entry->flags = 0; + rt2x00_set_field32(&word, TXD_W0_VALID, 0); + rt2x00_desc_write(txd, 0, word); + rt2x00_ring_index_done_inc(ring); + } + + /* + * If the data ring was full before the txdone handler + * we must make sure the packet queue in the mac80211 stack + * is reenabled when the txdone handler has finished. + */ + entry = ring->entry; + if (!rt2x00_ring_full(ring)) + ieee80211_wake_queue(rt2x00dev->hw, + entry->tx_status.control.queue); +} + +static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance) +{ + struct rt2x00_dev *rt2x00dev = dev_instance; + u32 reg; + + /* + * Get the interrupt sources & saved to local variable. + * Write register value back to clear pending interrupts. + */ + rt2x00pci_register_read(rt2x00dev, CSR7, ®); + rt2x00pci_register_write(rt2x00dev, CSR7, reg); + + if (!reg) + return IRQ_NONE; + + if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + return IRQ_HANDLED; + + /* + * Handle interrupts, walk through all bits + * and run the tasks, the bits are checked in order of + * priority. + */ + + /* + * 1 - Beacon timer expired interrupt. + */ + if (rt2x00_get_field32(reg, CSR7_TBCN_EXPIRE)) + rt2x00lib_beacondone(rt2x00dev); + + /* + * 2 - Rx ring done interrupt. + */ + if (rt2x00_get_field32(reg, CSR7_RXDONE)) + rt2x00pci_rxdone(rt2x00dev); + + /* + * 3 - Atim ring transmit done interrupt. + */ + if (rt2x00_get_field32(reg, CSR7_TXDONE_ATIMRING)) + rt2400pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_AFTER_BEACON); + + /* + * 4 - Priority ring transmit done interrupt. + */ + if (rt2x00_get_field32(reg, CSR7_TXDONE_PRIORING)) + rt2400pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_DATA0); + + /* + * 5 - Tx ring transmit done interrupt. + */ + if (rt2x00_get_field32(reg, CSR7_TXDONE_TXRING)) + rt2400pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_DATA1); + + return IRQ_HANDLED; +} + +/* + * Device probe functions. + */ +static int rt2400pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) +{ + struct eeprom_93cx6 eeprom; + u32 reg; + u16 word; + u8 *mac; + + rt2x00pci_register_read(rt2x00dev, CSR21, ®); + + eeprom.data = rt2x00dev; + eeprom.register_read = rt2400pci_eepromregister_read; + eeprom.register_write = rt2400pci_eepromregister_write; + eeprom.width = rt2x00_get_field32(reg, CSR21_TYPE_93C46) ? + PCI_EEPROM_WIDTH_93C46 : PCI_EEPROM_WIDTH_93C66; + eeprom.reg_data_in = 0; + eeprom.reg_data_out = 0; + eeprom.reg_data_clock = 0; + eeprom.reg_chip_select = 0; + + eeprom_93cx6_multiread(&eeprom, EEPROM_BASE, rt2x00dev->eeprom, + EEPROM_SIZE / sizeof(u16)); + + /* + * Start validation of the data that has been read. + */ + mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); + if (!is_valid_ether_addr(mac)) { + random_ether_addr(mac); + EEPROM(rt2x00dev, "MAC: " MAC_FMT "\n", MAC_ARG(mac)); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); + if (word == 0xffff) { + ERROR(rt2x00dev, "Invalid EEPROM data detected.\n"); + return -EINVAL; + } + + return 0; +} + +static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + u16 value; + u16 eeprom; + + /* + * Read EEPROM word for configuration. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); + + /* + * Identify RF chipset. + */ + value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); + rt2x00pci_register_read(rt2x00dev, CSR0, ®); + rt2x00_set_chip(rt2x00dev, RT2460, value, reg); + + if (!rt2x00_rf(&rt2x00dev->chip, RF2420) && + !rt2x00_rf(&rt2x00dev->chip, RF2421)) { + ERROR(rt2x00dev, "Invalid RF chipset detected.\n"); + return -ENODEV; + } + + /* + * Identify default antenna configuration. + */ + rt2x00dev->hw->conf.antenna_sel_tx = + rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TX_DEFAULT); + rt2x00dev->hw->conf.antenna_sel_rx = + rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT); + + /* + * Store led mode, for correct led behaviour. + */ + rt2x00dev->led_mode = + rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE); + + /* + * Detect if this device has an hardware controlled radio. + */ + if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) + __set_bit(DEVICE_SUPPORT_HW_BUTTON, &rt2x00dev->flags); + + /* + * Check if the BBP tuning should be enabled. + */ + if (!rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_AGCVGC_TUNING)) + __set_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags); + + return 0; +} + +/* + * RF value list for RF2420 & RF2421 + * Supports: 2.4 GHz + */ +static const struct rf_channel rf_vals_bg[] = { + { 1, 0x00022058, 0x000c1fda, 0x00000101, 0 }, + { 2, 0x00022058, 0x000c1fee, 0x00000101, 0 }, + { 3, 0x00022058, 0x000c2002, 0x00000101, 0 }, + { 4, 0x00022058, 0x000c2016, 0x00000101, 0 }, + { 5, 0x00022058, 0x000c202a, 0x00000101, 0 }, + { 6, 0x00022058, 0x000c203e, 0x00000101, 0 }, + { 7, 0x00022058, 0x000c2052, 0x00000101, 0 }, + { 8, 0x00022058, 0x000c2066, 0x00000101, 0 }, + { 9, 0x00022058, 0x000c207a, 0x00000101, 0 }, + { 10, 0x00022058, 0x000c208e, 0x00000101, 0 }, + { 11, 0x00022058, 0x000c20a2, 0x00000101, 0 }, + { 12, 0x00022058, 0x000c20b6, 0x00000101, 0 }, + { 13, 0x00022058, 0x000c20ca, 0x00000101, 0 }, + { 14, 0x00022058, 0x000c20fa, 0x00000101, 0 }, +}; + +static void rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) +{ + struct hw_mode_spec *spec = &rt2x00dev->spec; + u8 *txpower; + unsigned int i; + + /* + * Initialize all hw fields. + */ + rt2x00dev->hw->flags = + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_MONITOR_DURING_OPER | + IEEE80211_HW_NO_PROBE_FILTERING; + rt2x00dev->hw->extra_tx_headroom = 0; + rt2x00dev->hw->max_signal = MAX_SIGNAL; + rt2x00dev->hw->max_rssi = MAX_RX_SSI; + rt2x00dev->hw->queues = 2; + + SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev); + SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, + rt2x00_eeprom_addr(rt2x00dev, + EEPROM_MAC_ADDR_0)); + + /* + * Convert tx_power array in eeprom. + */ + txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START); + for (i = 0; i < 14; i++) + txpower[i] = TXPOWER_FROM_DEV(txpower[i]); + + /* + * Initialize hw_mode information. + */ + spec->num_modes = 1; + spec->num_rates = 4; + spec->tx_power_a = NULL; + spec->tx_power_bg = txpower; + spec->tx_power_default = DEFAULT_TXPOWER; + + spec->num_channels = ARRAY_SIZE(rf_vals_bg); + spec->channels = rf_vals_bg; +} + +static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev) +{ + int retval; + + /* + * Allocate eeprom data. + */ + retval = rt2400pci_validate_eeprom(rt2x00dev); + if (retval) + return retval; + + retval = rt2400pci_init_eeprom(rt2x00dev); + if (retval) + return retval; + + /* + * Initialize hw specifications. + */ + rt2400pci_probe_hw_mode(rt2x00dev); + + /* + * This device requires the beacon ring + */ + __set_bit(REQUIRE_BEACON_RING, &rt2x00dev->flags); + + /* + * Set the rssi offset. + */ + rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET; + + return 0; +} + +/* + * IEEE80211 stack callback functions. + */ +static int rt2400pci_set_retry_limit(struct ieee80211_hw *hw, + u32 short_retry, u32 long_retry) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + u32 reg; + + rt2x00pci_register_read(rt2x00dev, CSR11, ®); + rt2x00_set_field32(®, CSR11_LONG_RETRY, long_retry); + rt2x00_set_field32(®, CSR11_SHORT_RETRY, short_retry); + rt2x00pci_register_write(rt2x00dev, CSR11, reg); + + return 0; +} + +static int rt2400pci_conf_tx(struct ieee80211_hw *hw, + int queue, + const struct ieee80211_tx_queue_params *params) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + + /* + * We don't support variating cw_min and cw_max variables + * per queue. So by default we only configure the TX queue, + * and ignore all other configurations. + */ + if (queue != IEEE80211_TX_QUEUE_DATA0) + return -EINVAL; + + if (rt2x00mac_conf_tx(hw, queue, params)) + return -EINVAL; + + /* + * Write configuration to register. + */ + rt2400pci_config_cw(rt2x00dev, &rt2x00dev->tx->tx_params); + + return 0; +} + +static u64 rt2400pci_get_tsf(struct ieee80211_hw *hw) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + u64 tsf; + u32 reg; + + rt2x00pci_register_read(rt2x00dev, CSR17, ®); + tsf = (u64) rt2x00_get_field32(reg, CSR17_HIGH_TSFTIMER) << 32; + rt2x00pci_register_read(rt2x00dev, CSR16, ®); + tsf |= rt2x00_get_field32(reg, CSR16_LOW_TSFTIMER); + + return tsf; +} + +static void rt2400pci_reset_tsf(struct ieee80211_hw *hw) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + + rt2x00pci_register_write(rt2x00dev, CSR16, 0); + rt2x00pci_register_write(rt2x00dev, CSR17, 0); +} + +static int rt2400pci_tx_last_beacon(struct ieee80211_hw *hw) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + u32 reg; + + rt2x00pci_register_read(rt2x00dev, CSR15, ®); + return rt2x00_get_field32(reg, CSR15_BEACON_SENT); +} + +static const struct ieee80211_ops rt2400pci_mac80211_ops = { + .tx = rt2x00mac_tx, + .add_interface = rt2x00mac_add_interface, + .remove_interface = rt2x00mac_remove_interface, + .config = rt2x00mac_config, + .config_interface = rt2x00mac_config_interface, + .set_multicast_list = rt2x00mac_set_multicast_list, + .get_stats = rt2x00mac_get_stats, + .set_retry_limit = rt2400pci_set_retry_limit, + .conf_tx = rt2400pci_conf_tx, + .get_tx_stats = rt2x00mac_get_tx_stats, + .get_tsf = rt2400pci_get_tsf, + .reset_tsf = rt2400pci_reset_tsf, + .beacon_update = rt2x00pci_beacon_update, + .tx_last_beacon = rt2400pci_tx_last_beacon, +}; + +static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = { + .irq_handler = rt2400pci_interrupt, + .probe_hw = rt2400pci_probe_hw, + .initialize = rt2x00pci_initialize, + .uninitialize = rt2x00pci_uninitialize, + .set_device_state = rt2400pci_set_device_state, +#ifdef CONFIG_RT2400PCI_RFKILL + .rfkill_poll = rt2400pci_rfkill_poll, +#endif /* CONFIG_RT2400PCI_RFKILL */ + .link_stats = rt2400pci_link_stats, + .reset_tuner = rt2400pci_reset_tuner, + .link_tuner = rt2400pci_link_tuner, + .write_tx_desc = rt2400pci_write_tx_desc, + .write_tx_data = rt2x00pci_write_tx_data, + .kick_tx_queue = rt2400pci_kick_tx_queue, + .fill_rxdone = rt2400pci_fill_rxdone, + .config_mac_addr = rt2400pci_config_mac_addr, + .config_bssid = rt2400pci_config_bssid, + .config_packet_filter = rt2400pci_config_packet_filter, + .config_type = rt2400pci_config_type, + .config = rt2400pci_config, +}; + +static const struct rt2x00_ops rt2400pci_ops = { + .name = DRV_NAME, + .rxd_size = RXD_DESC_SIZE, + .txd_size = TXD_DESC_SIZE, + .eeprom_size = EEPROM_SIZE, + .rf_size = RF_SIZE, + .lib = &rt2400pci_rt2x00_ops, + .hw = &rt2400pci_mac80211_ops, +#ifdef CONFIG_RT2X00_LIB_DEBUGFS + .debugfs = &rt2400pci_rt2x00debug, +#endif /* CONFIG_RT2X00_LIB_DEBUGFS */ +}; + +/* + * RT2400pci module information. + */ +static struct pci_device_id rt2400pci_device_table[] = { + { PCI_DEVICE(0x1814, 0x0101), PCI_DEVICE_DATA(&rt2400pci_ops) }, + { 0, } +}; + +MODULE_AUTHOR(DRV_PROJECT); +MODULE_VERSION(DRV_VERSION); +MODULE_DESCRIPTION("Ralink RT2400 PCI & PCMCIA Wireless LAN driver."); +MODULE_SUPPORTED_DEVICE("Ralink RT2460 PCI & PCMCIA chipset based cards"); +MODULE_DEVICE_TABLE(pci, rt2400pci_device_table); +MODULE_LICENSE("GPL"); + +static struct pci_driver rt2400pci_driver = { + .name = DRV_NAME, + .id_table = rt2400pci_device_table, + .probe = rt2x00pci_probe, + .remove = __devexit_p(rt2x00pci_remove), + .suspend = rt2x00pci_suspend, + .resume = rt2x00pci_resume, +}; + +static int __init rt2400pci_init(void) +{ + return pci_register_driver(&rt2400pci_driver); +} + +static void __exit rt2400pci_exit(void) +{ + pci_unregister_driver(&rt2400pci_driver); +} + +module_init(rt2400pci_init); +module_exit(rt2400pci_exit); diff --git a/drivers/net/wireless/rt2x00/rt2400pci.h b/drivers/net/wireless/rt2x00/rt2400pci.h new file mode 100644 index 00000000000..ae22501f085 --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2400pci.h @@ -0,0 +1,943 @@ +/* + Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the + Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + Module: rt2400pci + Abstract: Data structures and registers for the rt2400pci module. + Supported chipsets: RT2460. + */ + +#ifndef RT2400PCI_H +#define RT2400PCI_H + +/* + * RF chip defines. + */ +#define RF2420 0x0000 +#define RF2421 0x0001 + +/* + * Signal information. + * Defaul offset is required for RSSI <-> dBm conversion. + */ +#define MAX_SIGNAL 100 +#define MAX_RX_SSI -1 +#define DEFAULT_RSSI_OFFSET 100 + +/* + * Register layout information. + */ +#define CSR_REG_BASE 0x0000 +#define CSR_REG_SIZE 0x014c +#define EEPROM_BASE 0x0000 +#define EEPROM_SIZE 0x0100 +#define BBP_SIZE 0x0020 +#define RF_SIZE 0x0010 + +/* + * Control/Status Registers(CSR). + * Some values are set in TU, whereas 1 TU == 1024 us. + */ + +/* + * CSR0: ASIC revision number. + */ +#define CSR0 0x0000 + +/* + * CSR1: System control register. + * SOFT_RESET: Software reset, 1: reset, 0: normal. + * BBP_RESET: Hardware reset, 1: reset, 0, release. + * HOST_READY: Host ready after initialization. + */ +#define CSR1 0x0004 +#define CSR1_SOFT_RESET FIELD32(0x00000001) +#define CSR1_BBP_RESET FIELD32(0x00000002) +#define CSR1_HOST_READY FIELD32(0x00000004) + +/* + * CSR2: System admin status register (invalid). + */ +#define CSR2 0x0008 + +/* + * CSR3: STA MAC address register 0. + */ +#define CSR3 0x000c +#define CSR3_BYTE0 FIELD32(0x000000ff) +#define CSR3_BYTE1 FIELD32(0x0000ff00) +#define CSR3_BYTE2 FIELD32(0x00ff0000) +#define CSR3_BYTE3 FIELD32(0xff000000) + +/* + * CSR4: STA MAC address register 1. + */ +#define CSR4 0x0010 +#define CSR4_BYTE4 FIELD32(0x000000ff) +#define CSR4_BYTE5 FIELD32(0x0000ff00) + +/* + * CSR5: BSSID register 0. + */ +#define CSR5 0x0014 +#define CSR5_BYTE0 FIELD32(0x000000ff) +#define CSR5_BYTE1 FIELD32(0x0000ff00) +#define CSR5_BYTE2 FIELD32(0x00ff0000) +#define CSR5_BYTE3 FIELD32(0xff000000) + +/* + * CSR6: BSSID register 1. + */ +#define CSR6 0x0018 +#define CSR6_BYTE4 FIELD32(0x000000ff) +#define CSR6_BYTE5 FIELD32(0x0000ff00) + +/* + * CSR7: Interrupt source register. + * Write 1 to clear interrupt. + * TBCN_EXPIRE: Beacon timer expired interrupt. + * TWAKE_EXPIRE: Wakeup timer expired interrupt. + * TATIMW_EXPIRE: Timer of atim window expired interrupt. + * TXDONE_TXRING: Tx ring transmit done interrupt. + * TXDONE_ATIMRING: Atim ring transmit done interrupt. + * TXDONE_PRIORING: Priority ring transmit done interrupt. + * RXDONE: Receive done interrupt. + */ +#define CSR7 0x001c +#define CSR7_TBCN_EXPIRE FIELD32(0x00000001) +#define CSR7_TWAKE_EXPIRE FIELD32(0x00000002) +#define CSR7_TATIMW_EXPIRE FIELD32(0x00000004) +#define CSR7_TXDONE_TXRING FIELD32(0x00000008) +#define CSR7_TXDONE_ATIMRING FIELD32(0x00000010) +#define CSR7_TXDONE_PRIORING FIELD32(0x00000020) +#define CSR7_RXDONE FIELD32(0x00000040) + +/* + * CSR8: Interrupt mask register. + * Write 1 to mask interrupt. + * TBCN_EXPIRE: Beacon timer expired interrupt. + * TWAKE_EXPIRE: Wakeup timer expired interrupt. + * TATIMW_EXPIRE: Timer of atim window expired interrupt. + * TXDONE_TXRING: Tx ring transmit done interrupt. + * TXDONE_ATIMRING: Atim ring transmit done interrupt. + * TXDONE_PRIORING: Priority ring transmit done interrupt. + * RXDONE: Receive done interrupt. + */ +#define CSR8 0x0020 +#define CSR8_TBCN_EXPIRE FIELD32(0x00000001) +#define CSR8_TWAKE_EXPIRE FIELD32(0x00000002) +#define CSR8_TATIMW_EXPIRE FIELD32(0x00000004) +#define CSR8_TXDONE_TXRING FIELD32(0x00000008) +#define CSR8_TXDONE_ATIMRING FIELD32(0x00000010) +#define CSR8_TXDONE_PRIORING FIELD32(0x00000020) +#define CSR8_RXDONE FIELD32(0x00000040) + +/* + * CSR9: Maximum frame length register. + * MAX_FRAME_UNIT: Maximum frame length in 128b unit, default: 12. + */ +#define CSR9 0x0024 +#define CSR9_MAX_FRAME_UNIT FIELD32(0x00000f80) + +/* + * CSR11: Back-off control register. + * CWMIN: CWmin. Default cwmin is 31 (2^5 - 1). + * CWMAX: CWmax. Default cwmax is 1023 (2^10 - 1). + * SLOT_TIME: Slot time, default is 20us for 802.11b. + * LONG_RETRY: Long retry count. + * SHORT_RETRY: Short retry count. + */ +#define CSR11 0x002c +#define CSR11_CWMIN FIELD32(0x0000000f) +#define CSR11_CWMAX FIELD32(0x000000f0) +#define CSR11_SLOT_TIME FIELD32(0x00001f00) +#define CSR11_LONG_RETRY FIELD32(0x00ff0000) +#define CSR11_SHORT_RETRY FIELD32(0xff000000) + +/* + * CSR12: Synchronization configuration register 0. + * All units in 1/16 TU. + * BEACON_INTERVAL: Beacon interval, default is 100 TU. + * CFPMAX_DURATION: Cfp maximum duration, default is 100 TU. + */ +#define CSR12 0x0030 +#define CSR12_BEACON_INTERVAL FIELD32(0x0000ffff) +#define CSR12_CFP_MAX_DURATION FIELD32(0xffff0000) + +/* + * CSR13: Synchronization configuration register 1. + * All units in 1/16 TU. + * ATIMW_DURATION: Atim window duration. + * CFP_PERIOD: Cfp period, default is 0 TU. + */ +#define CSR13 0x0034 +#define CSR13_ATIMW_DURATION FIELD32(0x0000ffff) +#define CSR13_CFP_PERIOD FIELD32(0x00ff0000) + +/* + * CSR14: Synchronization control register. + * TSF_COUNT: Enable tsf auto counting. + * TSF_SYNC: Tsf sync, 0: disable, 1: infra, 2: ad-hoc/master mode. + * TBCN: Enable tbcn with reload value. + * TCFP: Enable tcfp & cfp / cp switching. + * TATIMW: Enable tatimw & atim window switching. + * BEACON_GEN: Enable beacon generator. + * CFP_COUNT_PRELOAD: Cfp count preload value. + * TBCM_PRELOAD: Tbcn preload value in units of 64us. + */ +#define CSR14 0x0038 +#define CSR14_TSF_COUNT FIELD32(0x00000001) +#define CSR14_TSF_SYNC FIELD32(0x00000006) +#define CSR14_TBCN FIELD32(0x00000008) +#define CSR14_TCFP FIELD32(0x00000010) +#define CSR14_TATIMW FIELD32(0x00000020) +#define CSR14_BEACON_GEN FIELD32(0x00000040) +#define CSR14_CFP_COUNT_PRELOAD FIELD32(0x0000ff00) +#define CSR14_TBCM_PRELOAD FIELD32(0xffff0000) + +/* + * CSR15: Synchronization status register. + * CFP: ASIC is in contention-free period. + * ATIMW: ASIC is in ATIM window. + * BEACON_SENT: Beacon is send. + */ +#define CSR15 0x003c +#define CSR15_CFP FIELD32(0x00000001) +#define CSR15_ATIMW FIELD32(0x00000002) +#define CSR15_BEACON_SENT FIELD32(0x00000004) + +/* + * CSR16: TSF timer register 0. + */ +#define CSR16 0x0040 +#define CSR16_LOW_TSFTIMER FIELD32(0xffffffff) + +/* + * CSR17: TSF timer register 1. + */ +#define CSR17 0x0044 +#define CSR17_HIGH_TSFTIMER FIELD32(0xffffffff) + +/* + * CSR18: IFS timer register 0. + * SIFS: Sifs, default is 10 us. + * PIFS: Pifs, default is 30 us. + */ +#define CSR18 0x0048 +#define CSR18_SIFS FIELD32(0x0000ffff) +#define CSR18_PIFS FIELD32(0xffff0000) + +/* + * CSR19: IFS timer register 1. + * DIFS: Difs, default is 50 us. + * EIFS: Eifs, default is 364 us. + */ +#define CSR19 0x004c +#define CSR19_DIFS FIELD32(0x0000ffff) +#define CSR19_EIFS FIELD32(0xffff0000) + +/* + * CSR20: Wakeup timer register. + * DELAY_AFTER_TBCN: Delay after tbcn expired in units of 1/16 TU. + * TBCN_BEFORE_WAKEUP: Number of beacon before wakeup. + * AUTOWAKE: Enable auto wakeup / sleep mechanism. + */ +#define CSR20 0x0050 +#define CSR20_DELAY_AFTER_TBCN FIELD32(0x0000ffff) +#define CSR20_TBCN_BEFORE_WAKEUP FIELD32(0x00ff0000) +#define CSR20_AUTOWAKE FIELD32(0x01000000) + +/* + * CSR21: EEPROM control register. + * RELOAD: Write 1 to reload eeprom content. + * TYPE_93C46: 1: 93c46, 0:93c66. + */ +#define CSR21 0x0054 +#define CSR21_RELOAD FIELD32(0x00000001) +#define CSR21_EEPROM_DATA_CLOCK FIELD32(0x00000002) +#define CSR21_EEPROM_CHIP_SELECT FIELD32(0x00000004) +#define CSR21_EEPROM_DATA_IN FIELD32(0x00000008) +#define CSR21_EEPROM_DATA_OUT FIELD32(0x00000010) +#define CSR21_TYPE_93C46 FIELD32(0x00000020) + +/* + * CSR22: CFP control register. + * CFP_DURATION_REMAIN: Cfp duration remain, in units of TU. + * RELOAD_CFP_DURATION: Write 1 to reload cfp duration remain. + */ +#define CSR22 0x0058 +#define CSR22_CFP_DURATION_REMAIN FIELD32(0x0000ffff) +#define CSR22_RELOAD_CFP_DURATION FIELD32(0x00010000) + +/* + * Transmit related CSRs. + * Some values are set in TU, whereas 1 TU == 1024 us. + */ + +/* + * TXCSR0: TX Control Register. + * KICK_TX: Kick tx ring. + * KICK_ATIM: Kick atim ring. + * KICK_PRIO: Kick priority ring. + * ABORT: Abort all transmit related ring operation. + */ +#define TXCSR0 0x0060 +#define TXCSR0_KICK_TX FIELD32(0x00000001) +#define TXCSR0_KICK_ATIM FIELD32(0x00000002) +#define TXCSR0_KICK_PRIO FIELD32(0x00000004) +#define TXCSR0_ABORT FIELD32(0x00000008) + +/* + * TXCSR1: TX Configuration Register. + * ACK_TIMEOUT: Ack timeout, default = sifs + 2*slottime + acktime @ 1mbps. + * ACK_CONSUME_TIME: Ack consume time, default = sifs + acktime @ 1mbps. + * TSF_OFFSET: Insert tsf offset. + * AUTORESPONDER: Enable auto responder which include ack & cts. + */ +#define TXCSR1 0x0064 +#define TXCSR1_ACK_TIMEOUT FIELD32(0x000001ff) +#define TXCSR1_ACK_CONSUME_TIME FIELD32(0x0003fe00) +#define TXCSR1_TSF_OFFSET FIELD32(0x00fc0000) +#define TXCSR1_AUTORESPONDER FIELD32(0x01000000) + +/* + * TXCSR2: Tx descriptor configuration register. + * TXD_SIZE: Tx descriptor size, default is 48. + * NUM_TXD: Number of tx entries in ring. + * NUM_ATIM: Number of atim entries in ring. + * NUM_PRIO: Number of priority entries in ring. + */ +#define TXCSR2 0x0068 +#define TXCSR2_TXD_SIZE FIELD32(0x000000ff) +#define TXCSR2_NUM_TXD FIELD32(0x0000ff00) +#define TXCSR2_NUM_ATIM FIELD32(0x00ff0000) +#define TXCSR2_NUM_PRIO FIELD32(0xff000000) + +/* + * TXCSR3: TX Ring Base address register. + */ +#define TXCSR3 0x006c +#define TXCSR3_TX_RING_REGISTER FIELD32(0xffffffff) + +/* + * TXCSR4: TX Atim Ring Base address register. + */ +#define TXCSR4 0x0070 +#define TXCSR4_ATIM_RING_REGISTER FIELD32(0xffffffff) + +/* + * TXCSR5: TX Prio Ring Base address register. + */ +#define TXCSR5 0x0074 +#define TXCSR5_PRIO_RING_REGISTER FIELD32(0xffffffff) + +/* + * TXCSR6: Beacon Base address register. + */ +#define TXCSR6 0x0078 +#define TXCSR6_BEACON_RING_REGISTER FIELD32(0xffffffff) + +/* + * TXCSR7: Auto responder control register. + * AR_POWERMANAGEMENT: Auto responder power management bit. + */ +#define TXCSR7 0x007c +#define TXCSR7_AR_POWERMANAGEMENT FIELD32(0x00000001) + +/* + * Receive related CSRs. + * Some values are set in TU, whereas 1 TU == 1024 us. + */ + +/* + * RXCSR0: RX Control Register. + * DISABLE_RX: Disable rx engine. + * DROP_CRC: Drop crc error. + * DROP_PHYSICAL: Drop physical error. + * DROP_CONTROL: Drop control frame. + * DROP_NOT_TO_ME: Drop not to me unicast frame. + * DROP_TODS: Drop frame tods bit is true. + * DROP_VERSION_ERROR: Drop version error frame. + * PASS_CRC: Pass all packets with crc attached. + */ +#define RXCSR0 0x0080 +#define RXCSR0_DISABLE_RX FIELD32(0x00000001) +#define RXCSR0_DROP_CRC FIELD32(0x00000002) +#define RXCSR0_DROP_PHYSICAL FIELD32(0x00000004) +#define RXCSR0_DROP_CONTROL FIELD32(0x00000008) +#define RXCSR0_DROP_NOT_TO_ME FIELD32(0x00000010) +#define RXCSR0_DROP_TODS FIELD32(0x00000020) +#define RXCSR0_DROP_VERSION_ERROR FIELD32(0x00000040) +#define RXCSR0_PASS_CRC FIELD32(0x00000080) + +/* + * RXCSR1: RX descriptor configuration register. + * RXD_SIZE: Rx descriptor size, default is 32b. + * NUM_RXD: Number of rx entries in ring. + */ +#define RXCSR1 0x0084 +#define RXCSR1_RXD_SIZE FIELD32(0x000000ff) +#define RXCSR1_NUM_RXD FIELD32(0x0000ff00) + +/* + * RXCSR2: RX Ring base address register. + */ +#define RXCSR2 0x0088 +#define RXCSR2_RX_RING_REGISTER FIELD32(0xffffffff) + +/* + * RXCSR3: BBP ID register for Rx operation. + * BBP_ID#: BBP register # id. + * BBP_ID#_VALID: BBP register # id is valid or not. + */ +#define RXCSR3 0x0090 +#define RXCSR3_BBP_ID0 FIELD32(0x0000007f) +#define RXCSR3_BBP_ID0_VALID FIELD32(0x00000080) +#define RXCSR3_BBP_ID1 FIELD32(0x00007f00) +#define RXCSR3_BBP_ID1_VALID FIELD32(0x00008000) +#define RXCSR3_BBP_ID2 FIELD32(0x007f0000) +#define RXCSR3_BBP_ID2_VALID FIELD32(0x00800000) +#define RXCSR3_BBP_ID3 FIELD32(0x7f000000) +#define RXCSR3_BBP_ID3_VALID FIELD32(0x80000000) + +/* + * RXCSR4: BBP ID register for Rx operation. + * BBP_ID#: BBP register # id. + * BBP_ID#_VALID: BBP register # id is valid or not. + */ +#define RXCSR4 0x0094 +#define RXCSR4_BBP_ID4 FIELD32(0x0000007f) +#define RXCSR4_BBP_ID4_VALID FIELD32(0x00000080) +#define RXCSR4_BBP_ID5 FIELD32(0x00007f00) +#define RXCSR4_BBP_ID5_VALID FIELD32(0x00008000) + +/* + * ARCSR0: Auto Responder PLCP config register 0. + * ARCSR0_AR_BBP_DATA#: Auto responder BBP register # data. + * ARCSR0_AR_BBP_ID#: Auto responder BBP register # Id. + */ +#define ARCSR0 0x0098 +#define ARCSR0_AR_BBP_DATA0 FIELD32(0x000000ff) +#define ARCSR0_AR_BBP_ID0 FIELD32(0x0000ff00) +#define ARCSR0_AR_BBP_DATA1 FIELD32(0x00ff0000) +#define ARCSR0_AR_BBP_ID1 FIELD32(0xff000000) + +/* + * ARCSR1: Auto Responder PLCP config register 1. + * ARCSR0_AR_BBP_DATA#: Auto responder BBP register # data. + * ARCSR0_AR_BBP_ID#: Auto responder BBP register # Id. + */ +#define ARCSR1 0x009c +#define ARCSR1_AR_BBP_DATA2 FIELD32(0x000000ff) +#define ARCSR1_AR_BBP_ID2 FIELD32(0x0000ff00) +#define ARCSR1_AR_BBP_DATA3 FIELD32(0x00ff0000) +#define ARCSR1_AR_BBP_ID3 FIELD32(0xff000000) + +/* + * Miscellaneous Registers. + * Some values are set in TU, whereas 1 TU == 1024 us. + */ + +/* + * PCICSR: PCI control register. + * BIG_ENDIAN: 1: big endian, 0: little endian. + * RX_TRESHOLD: Rx threshold in dw to start pci access + * 0: 16dw (default), 1: 8dw, 2: 4dw, 3: 32dw. + * TX_TRESHOLD: Tx threshold in dw to start pci access + * 0: 0dw (default), 1: 1dw, 2: 4dw, 3: forward. + * BURST_LENTH: Pci burst length 0: 4dw (default, 1: 8dw, 2: 16dw, 3:32dw. + * ENABLE_CLK: Enable clk_run, pci clock can't going down to non-operational. + */ +#define PCICSR 0x008c +#define PCICSR_BIG_ENDIAN FIELD32(0x00000001) +#define PCICSR_RX_TRESHOLD FIELD32(0x00000006) +#define PCICSR_TX_TRESHOLD FIELD32(0x00000018) +#define PCICSR_BURST_LENTH FIELD32(0x00000060) +#define PCICSR_ENABLE_CLK FIELD32(0x00000080) + +/* + * CNT0: FCS error count. + * FCS_ERROR: FCS error count, cleared when read. + */ +#define CNT0 0x00a0 +#define CNT0_FCS_ERROR FIELD32(0x0000ffff) + +/* + * Statistic Register. + * CNT1: PLCP error count. + * CNT2: Long error count. + * CNT3: CCA false alarm count. + * CNT4: Rx FIFO overflow count. + * CNT5: Tx FIFO underrun count. + */ +#define TIMECSR2 0x00a8 +#define CNT1 0x00ac +#define CNT2 0x00b0 +#define TIMECSR3 0x00b4 +#define CNT3 0x00b8 +#define CNT4 0x00bc +#define CNT5 0x00c0 + +/* + * Baseband Control Register. + */ + +/* + * PWRCSR0: Power mode configuration register. + */ +#define PWRCSR0 0x00c4 + +/* + * Power state transition time registers. + */ +#define PSCSR0 0x00c8 +#define PSCSR1 0x00cc +#define PSCSR2 0x00d0 +#define PSCSR3 0x00d4 + +/* + * PWRCSR1: Manual power control / status register. + * Allowed state: 0 deep_sleep, 1: sleep, 2: standby, 3: awake. + * SET_STATE: Set state. Write 1 to trigger, self cleared. + * BBP_DESIRE_STATE: BBP desired state. + * RF_DESIRE_STATE: RF desired state. + * BBP_CURR_STATE: BBP current state. + * RF_CURR_STATE: RF current state. + * PUT_TO_SLEEP: Put to sleep. Write 1 to trigger, self cleared. + */ +#define PWRCSR1 0x00d8 +#define PWRCSR1_SET_STATE FIELD32(0x00000001) +#define PWRCSR1_BBP_DESIRE_STATE FIELD32(0x00000006) +#define PWRCSR1_RF_DESIRE_STATE FIELD32(0x00000018) +#define PWRCSR1_BBP_CURR_STATE FIELD32(0x00000060) +#define PWRCSR1_RF_CURR_STATE FIELD32(0x00000180) +#define PWRCSR1_PUT_TO_SLEEP FIELD32(0x00000200) + +/* + * TIMECSR: Timer control register. + * US_COUNT: 1 us timer count in units of clock cycles. + * US_64_COUNT: 64 us timer count in units of 1 us timer. + * BEACON_EXPECT: Beacon expect window. + */ +#define TIMECSR 0x00dc +#define TIMECSR_US_COUNT FIELD32(0x000000ff) +#define TIMECSR_US_64_COUNT FIELD32(0x0000ff00) +#define TIMECSR_BEACON_EXPECT FIELD32(0x00070000) + +/* + * MACCSR0: MAC configuration register 0. + */ +#define MACCSR0 0x00e0 + +/* + * MACCSR1: MAC configuration register 1. + * KICK_RX: Kick one-shot rx in one-shot rx mode. + * ONESHOT_RXMODE: Enable one-shot rx mode for debugging. + * BBPRX_RESET_MODE: Ralink bbp rx reset mode. + * AUTO_TXBBP: Auto tx logic access bbp control register. + * AUTO_RXBBP: Auto rx logic access bbp control register. + * LOOPBACK: Loopback mode. 0: normal, 1: internal, 2: external, 3:rsvd. + * INTERSIL_IF: Intersil if calibration pin. + */ +#define MACCSR1 0x00e4 +#define MACCSR1_KICK_RX FIELD32(0x00000001) +#define MACCSR1_ONESHOT_RXMODE FIELD32(0x00000002) +#define MACCSR1_BBPRX_RESET_MODE FIELD32(0x00000004) +#define MACCSR1_AUTO_TXBBP FIELD32(0x00000008) +#define MACCSR1_AUTO_RXBBP FIELD32(0x00000010) +#define MACCSR1_LOOPBACK FIELD32(0x00000060) +#define MACCSR1_INTERSIL_IF FIELD32(0x00000080) + +/* + * RALINKCSR: Ralink Rx auto-reset BBCR. + * AR_BBP_DATA#: Auto reset BBP register # data. + * AR_BBP_ID#: Auto reset BBP register # id. + */ +#define RALINKCSR 0x00e8 +#define RALINKCSR_AR_BBP_DATA0 FIELD32(0x000000ff) +#define RALINKCSR_AR_BBP_ID0 FIELD32(0x0000ff00) +#define RALINKCSR_AR_BBP_DATA1 FIELD32(0x00ff0000) +#define RALINKCSR_AR_BBP_ID1 FIELD32(0xff000000) + +/* + * BCNCSR: Beacon interval control register. + * CHANGE: Write one to change beacon interval. + * DELTATIME: The delta time value. + * NUM_BEACON: Number of beacon according to mode. + * MODE: Please refer to asic specs. + * PLUS: Plus or minus delta time value. + */ +#define BCNCSR 0x00ec +#define BCNCSR_CHANGE FIELD32(0x00000001) +#define BCNCSR_DELTATIME FIELD32(0x0000001e) +#define BCNCSR_NUM_BEACON FIELD32(0x00001fe0) +#define BCNCSR_MODE FIELD32(0x00006000) +#define BCNCSR_PLUS FIELD32(0x00008000) + +/* + * BBP / RF / IF Control Register. + */ + +/* + * BBPCSR: BBP serial control register. + * VALUE: Register value to program into BBP. + * REGNUM: Selected BBP register. + * BUSY: 1: asic is busy execute BBP programming. + * WRITE_CONTROL: 1: write BBP, 0: read BBP. + */ +#define BBPCSR 0x00f0 +#define BBPCSR_VALUE FIELD32(0x000000ff) +#define BBPCSR_REGNUM FIELD32(0x00007f00) +#define BBPCSR_BUSY FIELD32(0x00008000) +#define BBPCSR_WRITE_CONTROL FIELD32(0x00010000) + +/* + * RFCSR: RF serial control register. + * VALUE: Register value + id to program into rf/if. + * NUMBER_OF_BITS: Number of bits used in value (i:20, rfmd:22). + * IF_SELECT: Chip to program: 0: rf, 1: if. + * PLL_LD: Rf pll_ld status. + * BUSY: 1: asic is busy execute rf programming. + */ +#define RFCSR 0x00f4 +#define RFCSR_VALUE FIELD32(0x00ffffff) +#define RFCSR_NUMBER_OF_BITS FIELD32(0x1f000000) +#define RFCSR_IF_SELECT FIELD32(0x20000000) +#define RFCSR_PLL_LD FIELD32(0x40000000) +#define RFCSR_BUSY FIELD32(0x80000000) + +/* + * LEDCSR: LED control register. + * ON_PERIOD: On period, default 70ms. + * OFF_PERIOD: Off period, default 30ms. + * LINK: 0: linkoff, 1: linkup. + * ACTIVITY: 0: idle, 1: active. + */ +#define LEDCSR 0x00f8 +#define LEDCSR_ON_PERIOD FIELD32(0x000000ff) +#define LEDCSR_OFF_PERIOD FIELD32(0x0000ff00) +#define LEDCSR_LINK FIELD32(0x00010000) +#define LEDCSR_ACTIVITY FIELD32(0x00020000) + +/* + * ASIC pointer information. + * RXPTR: Current RX ring address. + * TXPTR: Current Tx ring address. + * PRIPTR: Current Priority ring address. + * ATIMPTR: Current ATIM ring address. + */ +#define RXPTR 0x0100 +#define TXPTR 0x0104 +#define PRIPTR 0x0108 +#define ATIMPTR 0x010c + +/* + * GPIO and others. + */ + +/* + * GPIOCSR: GPIO control register. + */ +#define GPIOCSR 0x0120 +#define GPIOCSR_BIT0 FIELD32(0x00000001) +#define GPIOCSR_BIT1 FIELD32(0x00000002) +#define GPIOCSR_BIT2 FIELD32(0x00000004) +#define GPIOCSR_BIT3 FIELD32(0x00000008) +#define GPIOCSR_BIT4 FIELD32(0x00000010) +#define GPIOCSR_BIT5 FIELD32(0x00000020) +#define GPIOCSR_BIT6 FIELD32(0x00000040) +#define GPIOCSR_BIT7 FIELD32(0x00000080) + +/* + * BBPPCSR: BBP Pin control register. + */ +#define BBPPCSR 0x0124 + +/* + * BCNCSR1: Tx BEACON offset time control register. + * PRELOAD: Beacon timer offset in units of usec. + */ +#define BCNCSR1 0x0130 +#define BCNCSR1_PRELOAD FIELD32(0x0000ffff) + +/* + * MACCSR2: TX_PE to RX_PE turn-around time control register + * DELAY: RX_PE low width, in units of pci clock cycle. + */ +#define MACCSR2 0x0134 +#define MACCSR2_DELAY FIELD32(0x000000ff) + +/* + * ARCSR2: 1 Mbps ACK/CTS PLCP. + */ +#define ARCSR2 0x013c +#define ARCSR2_SIGNAL FIELD32(0x000000ff) +#define ARCSR2_SERVICE FIELD32(0x0000ff00) +#define ARCSR2_LENGTH_LOW FIELD32(0x00ff0000) +#define ARCSR2_LENGTH FIELD32(0xffff0000) + +/* + * ARCSR3: 2 Mbps ACK/CTS PLCP. + */ +#define ARCSR3 0x0140 +#define ARCSR3_SIGNAL FIELD32(0x000000ff) +#define ARCSR3_SERVICE FIELD32(0x0000ff00) +#define ARCSR3_LENGTH FIELD32(0xffff0000) + +/* + * ARCSR4: 5.5 Mbps ACK/CTS PLCP. + */ +#define ARCSR4 0x0144 +#define ARCSR4_SIGNAL FIELD32(0x000000ff) +#define ARCSR4_SERVICE FIELD32(0x0000ff00) +#define ARCSR4_LENGTH FIELD32(0xffff0000) + +/* + * ARCSR5: 11 Mbps ACK/CTS PLCP. + */ +#define ARCSR5 0x0148 +#define ARCSR5_SIGNAL FIELD32(0x000000ff) +#define ARCSR5_SERVICE FIELD32(0x0000ff00) +#define ARCSR5_LENGTH FIELD32(0xffff0000) + +/* + * BBP registers. + * The wordsize of the BBP is 8 bits. + */ + +/* + * R1: TX antenna control + */ +#define BBP_R1_TX_ANTENNA FIELD8(0x03) + +/* + * R4: RX antenna control + */ +#define BBP_R4_RX_ANTENNA FIELD8(0x06) + +/* + * RF registers + */ + +/* + * RF 1 + */ +#define RF1_TUNER FIELD32(0x00020000) + +/* + * RF 3 + */ +#define RF3_TUNER FIELD32(0x00000100) +#define RF3_TXPOWER FIELD32(0x00003e00) + +/* + * EEPROM content. + * The wordsize of the EEPROM is 16 bits. + */ + +/* + * HW MAC address. + */ +#define EEPROM_MAC_ADDR_0 0x0002 +#define EEPROM_MAC_ADDR_BYTE0 FIELD16(0x00ff) +#define EEPROM_MAC_ADDR_BYTE1 FIELD16(0xff00) +#define EEPROM_MAC_ADDR1 0x0003 +#define EEPROM_MAC_ADDR_BYTE2 FIELD16(0x00ff) +#define EEPROM_MAC_ADDR_BYTE3 FIELD16(0xff00) +#define EEPROM_MAC_ADDR_2 0x0004 +#define EEPROM_MAC_ADDR_BYTE4 FIELD16(0x00ff) +#define EEPROM_MAC_ADDR_BYTE5 FIELD16(0xff00) + +/* + * EEPROM antenna. + * ANTENNA_NUM: Number of antenna's. + * TX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B. + * RX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B. + * RF_TYPE: Rf_type of this adapter. + * LED_MODE: 0: default, 1: TX/RX activity,2: Single (ignore link), 3: rsvd. + * RX_AGCVGC: 0: disable, 1:enable BBP R13 tuning. + * HARDWARE_RADIO: 1: Hardware controlled radio. Read GPIO0. + */ +#define EEPROM_ANTENNA 0x0b +#define EEPROM_ANTENNA_NUM FIELD16(0x0003) +#define EEPROM_ANTENNA_TX_DEFAULT FIELD16(0x000c) +#define EEPROM_ANTENNA_RX_DEFAULT FIELD16(0x0030) +#define EEPROM_ANTENNA_RF_TYPE FIELD16(0x0040) +#define EEPROM_ANTENNA_LED_MODE FIELD16(0x0180) +#define EEPROM_ANTENNA_RX_AGCVGC_TUNING FIELD16(0x0200) +#define EEPROM_ANTENNA_HARDWARE_RADIO FIELD16(0x0400) + +/* + * EEPROM BBP. + */ +#define EEPROM_BBP_START 0x0c +#define EEPROM_BBP_SIZE 7 +#define EEPROM_BBP_VALUE FIELD16(0x00ff) +#define EEPROM_BBP_REG_ID FIELD16(0xff00) + +/* + * EEPROM TXPOWER + */ +#define EEPROM_TXPOWER_START 0x13 +#define EEPROM_TXPOWER_SIZE 7 +#define EEPROM_TXPOWER_1 FIELD16(0x00ff) +#define EEPROM_TXPOWER_2 FIELD16(0xff00) + +/* + * DMA descriptor defines. + */ +#define TXD_DESC_SIZE ( 8 * sizeof(struct data_desc) ) +#define RXD_DESC_SIZE ( 8 * sizeof(struct data_desc) ) + +/* + * TX descriptor format for TX, PRIO, ATIM and Beacon Ring. + */ + +/* + * Word0 + */ +#define TXD_W0_OWNER_NIC FIELD32(0x00000001) +#define TXD_W0_VALID FIELD32(0x00000002) +#define TXD_W0_RESULT FIELD32(0x0000001c) +#define TXD_W0_RETRY_COUNT FIELD32(0x000000e0) +#define TXD_W0_MORE_FRAG FIELD32(0x00000100) +#define TXD_W0_ACK FIELD32(0x00000200) +#define TXD_W0_TIMESTAMP FIELD32(0x00000400) +#define TXD_W0_RTS FIELD32(0x00000800) +#define TXD_W0_IFS FIELD32(0x00006000) +#define TXD_W0_RETRY_MODE FIELD32(0x00008000) +#define TXD_W0_AGC FIELD32(0x00ff0000) +#define TXD_W0_R2 FIELD32(0xff000000) + +/* + * Word1 + */ +#define TXD_W1_BUFFER_ADDRESS FIELD32(0xffffffff) + +/* + * Word2 + */ +#define TXD_W2_BUFFER_LENGTH FIELD32(0x0000ffff) +#define TXD_W2_DATABYTE_COUNT FIELD32(0xffff0000) + +/* + * Word3 & 4: PLCP information + */ +#define TXD_W3_PLCP_SIGNAL FIELD32(0x0000ffff) +#define TXD_W3_PLCP_SERVICE FIELD32(0xffff0000) +#define TXD_W4_PLCP_LENGTH_LOW FIELD32(0x0000ffff) +#define TXD_W4_PLCP_LENGTH_HIGH FIELD32(0xffff0000) + +/* + * Word5 + */ +#define TXD_W5_BBCR4 FIELD32(0x0000ffff) +#define TXD_W5_AGC_REG FIELD32(0x007f0000) +#define TXD_W5_AGC_REG_VALID FIELD32(0x00800000) +#define TXD_W5_XXX_REG FIELD32(0x7f000000) +#define TXD_W5_XXX_REG_VALID FIELD32(0x80000000) + +/* + * Word6 + */ +#define TXD_W6_SK_BUFF FIELD32(0xffffffff) + +/* + * Word7 + */ +#define TXD_W7_RESERVED FIELD32(0xffffffff) + +/* + * RX descriptor format for RX Ring. + */ + +/* + * Word0 + */ +#define RXD_W0_OWNER_NIC FIELD32(0x00000001) +#define RXD_W0_UNICAST_TO_ME FIELD32(0x00000002) +#define RXD_W0_MULTICAST FIELD32(0x00000004) +#define RXD_W0_BROADCAST FIELD32(0x00000008) +#define RXD_W0_MY_BSS FIELD32(0x00000010) +#define RXD_W0_CRC_ERROR FIELD32(0x00000020) +#define RXD_W0_PHYSICAL_ERROR FIELD32(0x00000080) +#define RXD_W0_DATABYTE_COUNT FIELD32(0xffff0000) + +/* + * Word1 + */ +#define RXD_W1_BUFFER_ADDRESS FIELD32(0xffffffff) + +/* + * Word2 + */ +#define RXD_W2_BUFFER_LENGTH FIELD32(0x0000ffff) +#define RXD_W2_SIGNAL FIELD32(0x00ff0000) +#define RXD_W2_RSSI FIELD32(0xff000000) + +/* + * Word3 + */ +#define RXD_W3_BBR2 FIELD32(0x000000ff) +#define RXD_W3_BBR3 FIELD32(0x0000ff00) +#define RXD_W3_BBR4 FIELD32(0x00ff0000) +#define RXD_W3_BBR5 FIELD32(0xff000000) + +/* + * Word4 + */ +#define RXD_W4_RX_END_TIME FIELD32(0xffffffff) + +/* + * Word5 & 6 & 7: Reserved + */ +#define RXD_W5_RESERVED FIELD32(0xffffffff) +#define RXD_W6_RESERVED FIELD32(0xffffffff) +#define RXD_W7_RESERVED FIELD32(0xffffffff) + +/* + * Macro's for converting txpower from EEPROM to dscape value + * and from dscape value to register value. + * NOTE: Logics in rt2400pci for txpower are reversed + * compared to the other rt2x00 drivers. A higher txpower + * value means that the txpower must be lowered. This is + * important when converting the value coming from the + * dscape stack to the rt2400 acceptable value. + */ +#define MIN_TXPOWER 31 +#define MAX_TXPOWER 62 +#define DEFAULT_TXPOWER 39 + +#define TXPOWER_FROM_DEV(__txpower) \ +({ \ + ((__txpower) > MAX_TXPOWER) ? DEFAULT_TXPOWER - MIN_TXPOWER : \ + ((__txpower) < MIN_TXPOWER) ? DEFAULT_TXPOWER - MIN_TXPOWER : \ + (((__txpower) - MAX_TXPOWER) + MIN_TXPOWER); \ +}) + +#define TXPOWER_TO_DEV(__txpower) \ +({ \ + (__txpower) += MIN_TXPOWER; \ + ((__txpower) <= MIN_TXPOWER) ? MAX_TXPOWER : \ + (((__txpower) >= MAX_TXPOWER) ? MIN_TXPOWER : \ + (MAX_TXPOWER - ((__txpower) - MIN_TXPOWER))); \ +}) + +#endif /* RT2400PCI_H */ diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c new file mode 100644 index 00000000000..f6115c626fa --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -0,0 +1,2000 @@ +/* + Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the + Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + Module: rt2500pci + Abstract: rt2500pci device specific routines. + Supported chipsets: RT2560. + */ + +/* + * Set enviroment defines for rt2x00.h + */ +#define DRV_NAME "rt2500pci" + +#include +#include +#include +#include +#include +#include +#include + +#include "rt2x00.h" +#include "rt2x00pci.h" +#include "rt2500pci.h" + +/* + * Register access. + * All access to the CSR registers will go through the methods + * rt2x00pci_register_read and rt2x00pci_register_write. + * BBP and RF register require indirect register access, + * and use the CSR registers BBPCSR and RFCSR to achieve this. + * These indirect registers work with busy bits, + * and we will try maximal REGISTER_BUSY_COUNT times to access + * the register while taking a REGISTER_BUSY_DELAY us delay + * between each attampt. When the busy bit is still set at that time, + * the access attempt is considered to have failed, + * and we will print an error. + */ +static u32 rt2500pci_bbp_check(const struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + unsigned int i; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2x00pci_register_read(rt2x00dev, BBPCSR, ®); + if (!rt2x00_get_field32(reg, BBPCSR_BUSY)) + break; + udelay(REGISTER_BUSY_DELAY); + } + + return reg; +} + +static void rt2500pci_bbp_write(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, const u8 value) +{ + u32 reg; + + /* + * Wait until the BBP becomes ready. + */ + reg = rt2500pci_bbp_check(rt2x00dev); + if (rt2x00_get_field32(reg, BBPCSR_BUSY)) { + ERROR(rt2x00dev, "BBPCSR register busy. Write failed.\n"); + return; + } + + /* + * Write the data into the BBP. + */ + reg = 0; + rt2x00_set_field32(®, BBPCSR_VALUE, value); + rt2x00_set_field32(®, BBPCSR_REGNUM, word); + rt2x00_set_field32(®, BBPCSR_BUSY, 1); + rt2x00_set_field32(®, BBPCSR_WRITE_CONTROL, 1); + + rt2x00pci_register_write(rt2x00dev, BBPCSR, reg); +} + +static void rt2500pci_bbp_read(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, u8 *value) +{ + u32 reg; + + /* + * Wait until the BBP becomes ready. + */ + reg = rt2500pci_bbp_check(rt2x00dev); + if (rt2x00_get_field32(reg, BBPCSR_BUSY)) { + ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n"); + return; + } + + /* + * Write the request into the BBP. + */ + reg = 0; + rt2x00_set_field32(®, BBPCSR_REGNUM, word); + rt2x00_set_field32(®, BBPCSR_BUSY, 1); + rt2x00_set_field32(®, BBPCSR_WRITE_CONTROL, 0); + + rt2x00pci_register_write(rt2x00dev, BBPCSR, reg); + + /* + * Wait until the BBP becomes ready. + */ + reg = rt2500pci_bbp_check(rt2x00dev); + if (rt2x00_get_field32(reg, BBPCSR_BUSY)) { + ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n"); + *value = 0xff; + return; + } + + *value = rt2x00_get_field32(reg, BBPCSR_VALUE); +} + +static void rt2500pci_rf_write(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, const u32 value) +{ + u32 reg; + unsigned int i; + + if (!word) + return; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2x00pci_register_read(rt2x00dev, RFCSR, ®); + if (!rt2x00_get_field32(reg, RFCSR_BUSY)) + goto rf_write; + udelay(REGISTER_BUSY_DELAY); + } + + ERROR(rt2x00dev, "RFCSR register busy. Write failed.\n"); + return; + +rf_write: + reg = 0; + rt2x00_set_field32(®, RFCSR_VALUE, value); + rt2x00_set_field32(®, RFCSR_NUMBER_OF_BITS, 20); + rt2x00_set_field32(®, RFCSR_IF_SELECT, 0); + rt2x00_set_field32(®, RFCSR_BUSY, 1); + + rt2x00pci_register_write(rt2x00dev, RFCSR, reg); + rt2x00_rf_write(rt2x00dev, word, value); +} + +static void rt2500pci_eepromregister_read(struct eeprom_93cx6 *eeprom) +{ + struct rt2x00_dev *rt2x00dev = eeprom->data; + u32 reg; + + rt2x00pci_register_read(rt2x00dev, CSR21, ®); + + eeprom->reg_data_in = !!rt2x00_get_field32(reg, CSR21_EEPROM_DATA_IN); + eeprom->reg_data_out = !!rt2x00_get_field32(reg, CSR21_EEPROM_DATA_OUT); + eeprom->reg_data_clock = + !!rt2x00_get_field32(reg, CSR21_EEPROM_DATA_CLOCK); + eeprom->reg_chip_select = + !!rt2x00_get_field32(reg, CSR21_EEPROM_CHIP_SELECT); +} + +static void rt2500pci_eepromregister_write(struct eeprom_93cx6 *eeprom) +{ + struct rt2x00_dev *rt2x00dev = eeprom->data; + u32 reg = 0; + + rt2x00_set_field32(®, CSR21_EEPROM_DATA_IN, !!eeprom->reg_data_in); + rt2x00_set_field32(®, CSR21_EEPROM_DATA_OUT, !!eeprom->reg_data_out); + rt2x00_set_field32(®, CSR21_EEPROM_DATA_CLOCK, + !!eeprom->reg_data_clock); + rt2x00_set_field32(®, CSR21_EEPROM_CHIP_SELECT, + !!eeprom->reg_chip_select); + + rt2x00pci_register_write(rt2x00dev, CSR21, reg); +} + +#ifdef CONFIG_RT2X00_LIB_DEBUGFS +#define CSR_OFFSET(__word) ( CSR_REG_BASE + ((__word) * sizeof(u32)) ) + +static void rt2500pci_read_csr(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, u32 *data) +{ + rt2x00pci_register_read(rt2x00dev, CSR_OFFSET(word), data); +} + +static void rt2500pci_write_csr(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, u32 data) +{ + rt2x00pci_register_write(rt2x00dev, CSR_OFFSET(word), data); +} + +static const struct rt2x00debug rt2500pci_rt2x00debug = { + .owner = THIS_MODULE, + .csr = { + .read = rt2500pci_read_csr, + .write = rt2500pci_write_csr, + .word_size = sizeof(u32), + .word_count = CSR_REG_SIZE / sizeof(u32), + }, + .eeprom = { + .read = rt2x00_eeprom_read, + .write = rt2x00_eeprom_write, + .word_size = sizeof(u16), + .word_count = EEPROM_SIZE / sizeof(u16), + }, + .bbp = { + .read = rt2500pci_bbp_read, + .write = rt2500pci_bbp_write, + .word_size = sizeof(u8), + .word_count = BBP_SIZE / sizeof(u8), + }, + .rf = { + .read = rt2x00_rf_read, + .write = rt2500pci_rf_write, + .word_size = sizeof(u32), + .word_count = RF_SIZE / sizeof(u32), + }, +}; +#endif /* CONFIG_RT2X00_LIB_DEBUGFS */ + +#ifdef CONFIG_RT2500PCI_RFKILL +static int rt2500pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + rt2x00pci_register_read(rt2x00dev, GPIOCSR, ®); + return rt2x00_get_field32(reg, GPIOCSR_BIT0); +} +#endif /* CONFIG_RT2400PCI_RFKILL */ + +/* + * Configuration handlers. + */ +static void rt2500pci_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *addr) +{ + __le32 reg[2]; + + memset(®, 0, sizeof(reg)); + memcpy(®, addr, ETH_ALEN); + + /* + * The MAC address is passed to us as an array of bytes, + * that array is little endian, so no need for byte ordering. + */ + rt2x00pci_register_multiwrite(rt2x00dev, CSR3, ®, sizeof(reg)); +} + +static void rt2500pci_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) +{ + __le32 reg[2]; + + memset(®, 0, sizeof(reg)); + memcpy(®, bssid, ETH_ALEN); + + /* + * The BSSID is passed to us as an array of bytes, + * that array is little endian, so no need for byte ordering. + */ + rt2x00pci_register_multiwrite(rt2x00dev, CSR5, ®, sizeof(reg)); +} + +static void rt2500pci_config_packet_filter(struct rt2x00_dev *rt2x00dev, + const unsigned int filter) +{ + int promisc = !!(filter & IFF_PROMISC); + int multicast = !!(filter & IFF_MULTICAST); + int broadcast = !!(filter & IFF_BROADCAST); + u32 reg; + + rt2x00pci_register_read(rt2x00dev, RXCSR0, ®); + rt2x00_set_field32(®, RXCSR0_DROP_NOT_TO_ME, !promisc); + rt2x00_set_field32(®, RXCSR0_DROP_MCAST, !multicast); + rt2x00_set_field32(®, RXCSR0_DROP_BCAST, !broadcast); + rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); +} + +static void rt2500pci_config_type(struct rt2x00_dev *rt2x00dev, const int type) +{ + u32 reg; + + rt2x00pci_register_write(rt2x00dev, CSR14, 0); + + /* + * Apply hardware packet filter. + */ + rt2x00pci_register_read(rt2x00dev, RXCSR0, ®); + + if (!is_monitor_present(&rt2x00dev->interface) && + (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_STA)) + rt2x00_set_field32(®, RXCSR0_DROP_TODS, 1); + else + rt2x00_set_field32(®, RXCSR0_DROP_TODS, 0); + + /* + * If there is a non-monitor interface present + * the packet should be strict (even if a monitor interface is present!). + * When there is only 1 interface present which is in monitor mode + * we should start accepting _all_ frames. + */ + if (is_interface_present(&rt2x00dev->interface)) { + rt2x00_set_field32(®, RXCSR0_DROP_CRC, 1); + rt2x00_set_field32(®, RXCSR0_DROP_PHYSICAL, 1); + rt2x00_set_field32(®, RXCSR0_DROP_CONTROL, 1); + rt2x00_set_field32(®, RXCSR0_DROP_VERSION_ERROR, 1); + } else if (is_monitor_present(&rt2x00dev->interface)) { + rt2x00_set_field32(®, RXCSR0_DROP_CRC, 0); + rt2x00_set_field32(®, RXCSR0_DROP_PHYSICAL, 0); + rt2x00_set_field32(®, RXCSR0_DROP_CONTROL, 0); + rt2x00_set_field32(®, RXCSR0_DROP_VERSION_ERROR, 0); + } + + rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); + + /* + * Enable beacon config + */ + rt2x00pci_register_read(rt2x00dev, BCNCSR1, ®); + rt2x00_set_field32(®, BCNCSR1_PRELOAD, + PREAMBLE + get_duration(IEEE80211_HEADER, 2)); + rt2x00_set_field32(®, BCNCSR1_BEACON_CWMIN, + rt2x00lib_get_ring(rt2x00dev, + IEEE80211_TX_QUEUE_BEACON) + ->tx_params.cw_min); + rt2x00pci_register_write(rt2x00dev, BCNCSR1, reg); + + /* + * Enable synchronisation. + */ + rt2x00pci_register_read(rt2x00dev, CSR14, ®); + if (is_interface_present(&rt2x00dev->interface)) { + rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); + rt2x00_set_field32(®, CSR14_TBCN, 1); + } + + rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); + if (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_AP) + rt2x00_set_field32(®, CSR14_TSF_SYNC, 2); + else if (type == IEEE80211_IF_TYPE_STA) + rt2x00_set_field32(®, CSR14_TSF_SYNC, 1); + else if (is_monitor_present(&rt2x00dev->interface) && + !is_interface_present(&rt2x00dev->interface)) + rt2x00_set_field32(®, CSR14_TSF_SYNC, 0); + + rt2x00pci_register_write(rt2x00dev, CSR14, reg); +} + +static void rt2500pci_config_rate(struct rt2x00_dev *rt2x00dev, const int rate) +{ + struct ieee80211_conf *conf = &rt2x00dev->hw->conf; + u32 reg; + u32 preamble; + u16 value; + + if (DEVICE_GET_RATE_FIELD(rate, PREAMBLE)) + preamble = SHORT_PREAMBLE; + else + preamble = PREAMBLE; + + reg = DEVICE_GET_RATE_FIELD(rate, RATEMASK) & DEV_BASIC_RATEMASK; + rt2x00pci_register_write(rt2x00dev, ARCSR1, reg); + + rt2x00pci_register_read(rt2x00dev, TXCSR1, ®); + value = ((conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) ? + SHORT_DIFS : DIFS) + + PLCP + preamble + get_duration(ACK_SIZE, 10); + rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, value); + value = SIFS + PLCP + preamble + get_duration(ACK_SIZE, 10); + rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME, value); + rt2x00pci_register_write(rt2x00dev, TXCSR1, reg); + + preamble = DEVICE_GET_RATE_FIELD(rate, PREAMBLE) ? 0x08 : 0x00; + + rt2x00pci_register_read(rt2x00dev, ARCSR2, ®); + rt2x00_set_field32(®, ARCSR2_SIGNAL, 0x00 | preamble); + rt2x00_set_field32(®, ARCSR2_SERVICE, 0x04); + rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 10)); + rt2x00pci_register_write(rt2x00dev, ARCSR2, reg); + + rt2x00pci_register_read(rt2x00dev, ARCSR3, ®); + rt2x00_set_field32(®, ARCSR3_SIGNAL, 0x01 | preamble); + rt2x00_set_field32(®, ARCSR3_SERVICE, 0x04); + rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 20)); + rt2x00pci_register_write(rt2x00dev, ARCSR3, reg); + + rt2x00pci_register_read(rt2x00dev, ARCSR4, ®); + rt2x00_set_field32(®, ARCSR4_SIGNAL, 0x02 | preamble); + rt2x00_set_field32(®, ARCSR4_SERVICE, 0x04); + rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 55)); + rt2x00pci_register_write(rt2x00dev, ARCSR4, reg); + + rt2x00pci_register_read(rt2x00dev, ARCSR5, ®); + rt2x00_set_field32(®, ARCSR5_SIGNAL, 0x03 | preamble); + rt2x00_set_field32(®, ARCSR5_SERVICE, 0x84); + rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 110)); + rt2x00pci_register_write(rt2x00dev, ARCSR5, reg); +} + +static void rt2500pci_config_phymode(struct rt2x00_dev *rt2x00dev, + const int phymode) +{ + struct ieee80211_hw_mode *mode; + struct ieee80211_rate *rate; + + if (phymode == MODE_IEEE80211A) + rt2x00dev->curr_hwmode = HWMODE_A; + else if (phymode == MODE_IEEE80211B) + rt2x00dev->curr_hwmode = HWMODE_B; + else + rt2x00dev->curr_hwmode = HWMODE_G; + + mode = &rt2x00dev->hwmodes[rt2x00dev->curr_hwmode]; + rate = &mode->rates[mode->num_rates - 1]; + + rt2500pci_config_rate(rt2x00dev, rate->val2); +} + +static void rt2500pci_config_channel(struct rt2x00_dev *rt2x00dev, + const int index, const int channel, + const int txpower) +{ + struct rf_channel reg; + u8 r70; + + /* + * Fill rf_reg structure. + */ + memcpy(®, &rt2x00dev->spec.channels[index], sizeof(reg)); + + /* + * Set TXpower. + */ + rt2x00_set_field32(®.rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); + + /* + * Switch on tuning bits. + * For RT2523 devices we do not need to update the R1 register. + */ + if (!rt2x00_rf(&rt2x00dev->chip, RF2523)) + rt2x00_set_field32(®.rf1, RF1_TUNER, 1); + rt2x00_set_field32(®.rf3, RF3_TUNER, 1); + + /* + * For RT2525 we should first set the channel to half band higher. + */ + if (rt2x00_rf(&rt2x00dev->chip, RF2525)) { + static const u32 vals[] = { + 0x00080cbe, 0x00080d02, 0x00080d06, 0x00080d0a, + 0x00080d0e, 0x00080d12, 0x00080d16, 0x00080d1a, + 0x00080d1e, 0x00080d22, 0x00080d26, 0x00080d2a, + 0x00080d2e, 0x00080d3a + }; + + rt2500pci_rf_write(rt2x00dev, 1, reg.rf1); + rt2500pci_rf_write(rt2x00dev, 2, vals[channel - 1]); + rt2500pci_rf_write(rt2x00dev, 3, reg.rf3); + if (reg.rf4) + rt2500pci_rf_write(rt2x00dev, 4, reg.rf4); + } + + rt2500pci_rf_write(rt2x00dev, 1, reg.rf1); + rt2500pci_rf_write(rt2x00dev, 2, reg.rf2); + rt2500pci_rf_write(rt2x00dev, 3, reg.rf3); + if (reg.rf4) + rt2500pci_rf_write(rt2x00dev, 4, reg.rf4); + + /* + * Channel 14 requires the Japan filter bit to be set. + */ + r70 = 0x46; + rt2x00_set_field8(&r70, BBP_R70_JAPAN_FILTER, channel == 14); + rt2500pci_bbp_write(rt2x00dev, 70, r70); + + msleep(1); + + /* + * Switch off tuning bits. + * For RT2523 devices we do not need to update the R1 register. + */ + if (!rt2x00_rf(&rt2x00dev->chip, RF2523)) { + rt2x00_set_field32(®.rf1, RF1_TUNER, 0); + rt2500pci_rf_write(rt2x00dev, 1, reg.rf1); + } + + rt2x00_set_field32(®.rf3, RF3_TUNER, 0); + rt2500pci_rf_write(rt2x00dev, 3, reg.rf3); + + /* + * Clear false CRC during channel switch. + */ + rt2x00pci_register_read(rt2x00dev, CNT0, ®.rf1); +} + +static void rt2500pci_config_txpower(struct rt2x00_dev *rt2x00dev, + const int txpower) +{ + u32 rf3; + + rt2x00_rf_read(rt2x00dev, 3, &rf3); + rt2x00_set_field32(&rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); + rt2500pci_rf_write(rt2x00dev, 3, rf3); +} + +static void rt2500pci_config_antenna(struct rt2x00_dev *rt2x00dev, + const int antenna_tx, const int antenna_rx) +{ + u32 reg; + u8 r14; + u8 r2; + + rt2x00pci_register_read(rt2x00dev, BBPCSR1, ®); + rt2500pci_bbp_read(rt2x00dev, 14, &r14); + rt2500pci_bbp_read(rt2x00dev, 2, &r2); + + /* + * Configure the TX antenna. + */ + switch (antenna_tx) { + case ANTENNA_SW_DIVERSITY: + case ANTENNA_HW_DIVERSITY: + rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 2); + rt2x00_set_field32(®, BBPCSR1_CCK, 2); + rt2x00_set_field32(®, BBPCSR1_OFDM, 2); + break; + case ANTENNA_A: + rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 0); + rt2x00_set_field32(®, BBPCSR1_CCK, 0); + rt2x00_set_field32(®, BBPCSR1_OFDM, 0); + break; + case ANTENNA_B: + rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 2); + rt2x00_set_field32(®, BBPCSR1_CCK, 2); + rt2x00_set_field32(®, BBPCSR1_OFDM, 2); + break; + } + + /* + * Configure the RX antenna. + */ + switch (antenna_rx) { + case ANTENNA_SW_DIVERSITY: + case ANTENNA_HW_DIVERSITY: + rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 2); + break; + case ANTENNA_A: + rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 0); + break; + case ANTENNA_B: + rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 2); + break; + } + + /* + * RT2525E and RT5222 need to flip TX I/Q + */ + if (rt2x00_rf(&rt2x00dev->chip, RF2525E) || + rt2x00_rf(&rt2x00dev->chip, RF5222)) { + rt2x00_set_field8(&r2, BBP_R2_TX_IQ_FLIP, 1); + rt2x00_set_field32(®, BBPCSR1_CCK_FLIP, 1); + rt2x00_set_field32(®, BBPCSR1_OFDM_FLIP, 1); + + /* + * RT2525E does not need RX I/Q Flip. + */ + if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) + rt2x00_set_field8(&r14, BBP_R14_RX_IQ_FLIP, 0); + } else { + rt2x00_set_field32(®, BBPCSR1_CCK_FLIP, 0); + rt2x00_set_field32(®, BBPCSR1_OFDM_FLIP, 0); + } + + rt2x00pci_register_write(rt2x00dev, BBPCSR1, reg); + rt2500pci_bbp_write(rt2x00dev, 14, r14); + rt2500pci_bbp_write(rt2x00dev, 2, r2); +} + +static void rt2500pci_config_duration(struct rt2x00_dev *rt2x00dev, + const int short_slot_time, + const int beacon_int) +{ + u32 reg; + + rt2x00pci_register_read(rt2x00dev, CSR11, ®); + rt2x00_set_field32(®, CSR11_SLOT_TIME, + short_slot_time ? SHORT_SLOT_TIME : SLOT_TIME); + rt2x00pci_register_write(rt2x00dev, CSR11, reg); + + rt2x00pci_register_read(rt2x00dev, CSR18, ®); + rt2x00_set_field32(®, CSR18_SIFS, SIFS); + rt2x00_set_field32(®, CSR18_PIFS, + short_slot_time ? SHORT_PIFS : PIFS); + rt2x00pci_register_write(rt2x00dev, CSR18, reg); + + rt2x00pci_register_read(rt2x00dev, CSR19, ®); + rt2x00_set_field32(®, CSR19_DIFS, + short_slot_time ? SHORT_DIFS : DIFS); + rt2x00_set_field32(®, CSR19_EIFS, EIFS); + rt2x00pci_register_write(rt2x00dev, CSR19, reg); + + rt2x00pci_register_read(rt2x00dev, TXCSR1, ®); + rt2x00_set_field32(®, TXCSR1_TSF_OFFSET, IEEE80211_HEADER); + rt2x00_set_field32(®, TXCSR1_AUTORESPONDER, 1); + rt2x00pci_register_write(rt2x00dev, TXCSR1, reg); + + rt2x00pci_register_read(rt2x00dev, CSR12, ®); + rt2x00_set_field32(®, CSR12_BEACON_INTERVAL, beacon_int * 16); + rt2x00_set_field32(®, CSR12_CFP_MAX_DURATION, beacon_int * 16); + rt2x00pci_register_write(rt2x00dev, CSR12, reg); +} + +static void rt2500pci_config(struct rt2x00_dev *rt2x00dev, + const unsigned int flags, + struct ieee80211_conf *conf) +{ + int short_slot_time = conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME; + + if (flags & CONFIG_UPDATE_PHYMODE) + rt2500pci_config_phymode(rt2x00dev, conf->phymode); + if (flags & CONFIG_UPDATE_CHANNEL) + rt2500pci_config_channel(rt2x00dev, conf->channel_val, + conf->channel, conf->power_level); + if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL)) + rt2500pci_config_txpower(rt2x00dev, conf->power_level); + if (flags & CONFIG_UPDATE_ANTENNA) + rt2500pci_config_antenna(rt2x00dev, conf->antenna_sel_tx, + conf->antenna_sel_rx); + if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT)) + rt2500pci_config_duration(rt2x00dev, short_slot_time, + conf->beacon_int); +} + +/* + * LED functions. + */ +static void rt2500pci_enable_led(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + rt2x00pci_register_read(rt2x00dev, LEDCSR, ®); + + rt2x00_set_field32(®, LEDCSR_ON_PERIOD, 70); + rt2x00_set_field32(®, LEDCSR_OFF_PERIOD, 30); + + if (rt2x00dev->led_mode == LED_MODE_TXRX_ACTIVITY) { + rt2x00_set_field32(®, LEDCSR_LINK, 1); + rt2x00_set_field32(®, LEDCSR_ACTIVITY, 0); + } else if (rt2x00dev->led_mode == LED_MODE_ASUS) { + rt2x00_set_field32(®, LEDCSR_LINK, 0); + rt2x00_set_field32(®, LEDCSR_ACTIVITY, 1); + } else { + rt2x00_set_field32(®, LEDCSR_LINK, 1); + rt2x00_set_field32(®, LEDCSR_ACTIVITY, 1); + } + + rt2x00pci_register_write(rt2x00dev, LEDCSR, reg); +} + +static void rt2500pci_disable_led(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + rt2x00pci_register_read(rt2x00dev, LEDCSR, ®); + rt2x00_set_field32(®, LEDCSR_LINK, 0); + rt2x00_set_field32(®, LEDCSR_ACTIVITY, 0); + rt2x00pci_register_write(rt2x00dev, LEDCSR, reg); +} + +/* + * Link tuning + */ +static void rt2500pci_link_stats(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + /* + * Update FCS error count from register. + */ + rt2x00pci_register_read(rt2x00dev, CNT0, ®); + rt2x00dev->link.rx_failed = rt2x00_get_field32(reg, CNT0_FCS_ERROR); + + /* + * Update False CCA count from register. + */ + rt2x00pci_register_read(rt2x00dev, CNT3, ®); + rt2x00dev->link.false_cca = rt2x00_get_field32(reg, CNT3_FALSE_CCA); +} + +static void rt2500pci_reset_tuner(struct rt2x00_dev *rt2x00dev) +{ + rt2500pci_bbp_write(rt2x00dev, 17, 0x48); + rt2x00dev->link.vgc_level = 0x48; +} + +static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev) +{ + int rssi = rt2x00_get_link_rssi(&rt2x00dev->link); + u8 r17; + + /* + * To prevent collisions with MAC ASIC on chipsets + * up to version C the link tuning should halt after 20 + * seconds. + */ + if (rt2x00_get_rev(&rt2x00dev->chip) < RT2560_VERSION_D && + rt2x00dev->link.count > 20) + return; + + rt2500pci_bbp_read(rt2x00dev, 17, &r17); + + /* + * Chipset versions C and lower should directly continue + * to the dynamic CCA tuning. + */ + if (rt2x00_get_rev(&rt2x00dev->chip) < RT2560_VERSION_D) + goto dynamic_cca_tune; + + /* + * A too low RSSI will cause too much false CCA which will + * then corrupt the R17 tuning. To remidy this the tuning should + * be stopped (While making sure the R17 value will not exceed limits) + */ + if (rssi < -80 && rt2x00dev->link.count > 20) { + if (r17 >= 0x41) { + r17 = rt2x00dev->link.vgc_level; + rt2500pci_bbp_write(rt2x00dev, 17, r17); + } + return; + } + + /* + * Special big-R17 for short distance + */ + if (rssi >= -58) { + if (r17 != 0x50) + rt2500pci_bbp_write(rt2x00dev, 17, 0x50); + return; + } + + /* + * Special mid-R17 for middle distance + */ + if (rssi >= -74) { + if (r17 != 0x41) + rt2500pci_bbp_write(rt2x00dev, 17, 0x41); + return; + } + + /* + * Leave short or middle distance condition, restore r17 + * to the dynamic tuning range. + */ + if (r17 >= 0x41) { + rt2500pci_bbp_write(rt2x00dev, 17, rt2x00dev->link.vgc_level); + return; + } + +dynamic_cca_tune: + + /* + * R17 is inside the dynamic tuning range, + * start tuning the link based on the false cca counter. + */ + if (rt2x00dev->link.false_cca > 512 && r17 < 0x40) { + rt2500pci_bbp_write(rt2x00dev, 17, ++r17); + rt2x00dev->link.vgc_level = r17; + } else if (rt2x00dev->link.false_cca < 100 && r17 > 0x32) { + rt2500pci_bbp_write(rt2x00dev, 17, --r17); + rt2x00dev->link.vgc_level = r17; + } +} + +/* + * Initialization functions. + */ +static void rt2500pci_init_rxring(struct rt2x00_dev *rt2x00dev) +{ + struct data_ring *ring = rt2x00dev->rx; + struct data_desc *rxd; + unsigned int i; + u32 word; + + memset(ring->data_addr, 0x00, rt2x00_get_ring_size(ring)); + + for (i = 0; i < ring->stats.limit; i++) { + rxd = ring->entry[i].priv; + + rt2x00_desc_read(rxd, 1, &word); + rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, + ring->entry[i].data_dma); + rt2x00_desc_write(rxd, 1, word); + + rt2x00_desc_read(rxd, 0, &word); + rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); + rt2x00_desc_write(rxd, 0, word); + } + + rt2x00_ring_index_clear(rt2x00dev->rx); +} + +static void rt2500pci_init_txring(struct rt2x00_dev *rt2x00dev, const int queue) +{ + struct data_ring *ring = rt2x00lib_get_ring(rt2x00dev, queue); + struct data_desc *txd; + unsigned int i; + u32 word; + + memset(ring->data_addr, 0x00, rt2x00_get_ring_size(ring)); + + for (i = 0; i < ring->stats.limit; i++) { + txd = ring->entry[i].priv; + + rt2x00_desc_read(txd, 1, &word); + rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, + ring->entry[i].data_dma); + rt2x00_desc_write(txd, 1, word); + + rt2x00_desc_read(txd, 0, &word); + rt2x00_set_field32(&word, TXD_W0_VALID, 0); + rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); + rt2x00_desc_write(txd, 0, word); + } + + rt2x00_ring_index_clear(ring); +} + +static int rt2500pci_init_rings(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + /* + * Initialize rings. + */ + rt2500pci_init_rxring(rt2x00dev); + rt2500pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA0); + rt2500pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA1); + rt2500pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_AFTER_BEACON); + rt2500pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON); + + /* + * Initialize registers. + */ + rt2x00pci_register_read(rt2x00dev, TXCSR2, ®); + rt2x00_set_field32(®, TXCSR2_TXD_SIZE, + rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].desc_size); + rt2x00_set_field32(®, TXCSR2_NUM_TXD, + rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA1].stats.limit); + rt2x00_set_field32(®, TXCSR2_NUM_ATIM, + rt2x00dev->bcn[1].stats.limit); + rt2x00_set_field32(®, TXCSR2_NUM_PRIO, + rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].stats.limit); + rt2x00pci_register_write(rt2x00dev, TXCSR2, reg); + + rt2x00pci_register_read(rt2x00dev, TXCSR3, ®); + rt2x00_set_field32(®, TXCSR3_TX_RING_REGISTER, + rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA1].data_dma); + rt2x00pci_register_write(rt2x00dev, TXCSR3, reg); + + rt2x00pci_register_read(rt2x00dev, TXCSR5, ®); + rt2x00_set_field32(®, TXCSR5_PRIO_RING_REGISTER, + rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].data_dma); + rt2x00pci_register_write(rt2x00dev, TXCSR5, reg); + + rt2x00pci_register_read(rt2x00dev, TXCSR4, ®); + rt2x00_set_field32(®, TXCSR4_ATIM_RING_REGISTER, + rt2x00dev->bcn[1].data_dma); + rt2x00pci_register_write(rt2x00dev, TXCSR4, reg); + + rt2x00pci_register_read(rt2x00dev, TXCSR6, ®); + rt2x00_set_field32(®, TXCSR6_BEACON_RING_REGISTER, + rt2x00dev->bcn[0].data_dma); + rt2x00pci_register_write(rt2x00dev, TXCSR6, reg); + + rt2x00pci_register_read(rt2x00dev, RXCSR1, ®); + rt2x00_set_field32(®, RXCSR1_RXD_SIZE, rt2x00dev->rx->desc_size); + rt2x00_set_field32(®, RXCSR1_NUM_RXD, rt2x00dev->rx->stats.limit); + rt2x00pci_register_write(rt2x00dev, RXCSR1, reg); + + rt2x00pci_register_read(rt2x00dev, RXCSR2, ®); + rt2x00_set_field32(®, RXCSR2_RX_RING_REGISTER, + rt2x00dev->rx->data_dma); + rt2x00pci_register_write(rt2x00dev, RXCSR2, reg); + + return 0; +} + +static int rt2500pci_init_registers(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + rt2x00pci_register_write(rt2x00dev, PSCSR0, 0x00020002); + rt2x00pci_register_write(rt2x00dev, PSCSR1, 0x00000002); + rt2x00pci_register_write(rt2x00dev, PSCSR2, 0x00020002); + rt2x00pci_register_write(rt2x00dev, PSCSR3, 0x00000002); + + rt2x00pci_register_read(rt2x00dev, TIMECSR, ®); + rt2x00_set_field32(®, TIMECSR_US_COUNT, 33); + rt2x00_set_field32(®, TIMECSR_US_64_COUNT, 63); + rt2x00_set_field32(®, TIMECSR_BEACON_EXPECT, 0); + rt2x00pci_register_write(rt2x00dev, TIMECSR, reg); + + rt2x00pci_register_read(rt2x00dev, CSR9, ®); + rt2x00_set_field32(®, CSR9_MAX_FRAME_UNIT, + rt2x00dev->rx->data_size / 128); + rt2x00pci_register_write(rt2x00dev, CSR9, reg); + + /* + * Always use CWmin and CWmax set in descriptor. + */ + rt2x00pci_register_read(rt2x00dev, CSR11, ®); + rt2x00_set_field32(®, CSR11_CW_SELECT, 0); + rt2x00pci_register_write(rt2x00dev, CSR11, reg); + + rt2x00pci_register_write(rt2x00dev, CNT3, 0); + + rt2x00pci_register_read(rt2x00dev, TXCSR8, ®); + rt2x00_set_field32(®, TXCSR8_BBP_ID0, 10); + rt2x00_set_field32(®, TXCSR8_BBP_ID0_VALID, 1); + rt2x00_set_field32(®, TXCSR8_BBP_ID1, 11); + rt2x00_set_field32(®, TXCSR8_BBP_ID1_VALID, 1); + rt2x00_set_field32(®, TXCSR8_BBP_ID2, 13); + rt2x00_set_field32(®, TXCSR8_BBP_ID2_VALID, 1); + rt2x00_set_field32(®, TXCSR8_BBP_ID3, 12); + rt2x00_set_field32(®, TXCSR8_BBP_ID3_VALID, 1); + rt2x00pci_register_write(rt2x00dev, TXCSR8, reg); + + rt2x00pci_register_read(rt2x00dev, ARTCSR0, ®); + rt2x00_set_field32(®, ARTCSR0_ACK_CTS_1MBS, 112); + rt2x00_set_field32(®, ARTCSR0_ACK_CTS_2MBS, 56); + rt2x00_set_field32(®, ARTCSR0_ACK_CTS_5_5MBS, 20); + rt2x00_set_field32(®, ARTCSR0_ACK_CTS_11MBS, 10); + rt2x00pci_register_write(rt2x00dev, ARTCSR0, reg); + + rt2x00pci_register_read(rt2x00dev, ARTCSR1, ®); + rt2x00_set_field32(®, ARTCSR1_ACK_CTS_6MBS, 45); + rt2x00_set_field32(®, ARTCSR1_ACK_CTS_9MBS, 37); + rt2x00_set_field32(®, ARTCSR1_ACK_CTS_12MBS, 33); + rt2x00_set_field32(®, ARTCSR1_ACK_CTS_18MBS, 29); + rt2x00pci_register_write(rt2x00dev, ARTCSR1, reg); + + rt2x00pci_register_read(rt2x00dev, ARTCSR2, ®); + rt2x00_set_field32(®, ARTCSR2_ACK_CTS_24MBS, 29); + rt2x00_set_field32(®, ARTCSR2_ACK_CTS_36MBS, 25); + rt2x00_set_field32(®, ARTCSR2_ACK_CTS_48MBS, 25); + rt2x00_set_field32(®, ARTCSR2_ACK_CTS_54MBS, 25); + rt2x00pci_register_write(rt2x00dev, ARTCSR2, reg); + + rt2x00pci_register_read(rt2x00dev, RXCSR3, ®); + rt2x00_set_field32(®, RXCSR3_BBP_ID0, 47); /* CCK Signal */ + rt2x00_set_field32(®, RXCSR3_BBP_ID0_VALID, 1); + rt2x00_set_field32(®, RXCSR3_BBP_ID1, 51); /* Rssi */ + rt2x00_set_field32(®, RXCSR3_BBP_ID1_VALID, 1); + rt2x00_set_field32(®, RXCSR3_BBP_ID2, 42); /* OFDM Rate */ + rt2x00_set_field32(®, RXCSR3_BBP_ID2_VALID, 1); + rt2x00_set_field32(®, RXCSR3_BBP_ID3, 51); /* RSSI */ + rt2x00_set_field32(®, RXCSR3_BBP_ID3_VALID, 1); + rt2x00pci_register_write(rt2x00dev, RXCSR3, reg); + + rt2x00pci_register_read(rt2x00dev, PCICSR, ®); + rt2x00_set_field32(®, PCICSR_BIG_ENDIAN, 0); + rt2x00_set_field32(®, PCICSR_RX_TRESHOLD, 0); + rt2x00_set_field32(®, PCICSR_TX_TRESHOLD, 3); + rt2x00_set_field32(®, PCICSR_BURST_LENTH, 1); + rt2x00_set_field32(®, PCICSR_ENABLE_CLK, 1); + rt2x00_set_field32(®, PCICSR_READ_MULTIPLE, 1); + rt2x00_set_field32(®, PCICSR_WRITE_INVALID, 1); + rt2x00pci_register_write(rt2x00dev, PCICSR, reg); + + rt2x00pci_register_write(rt2x00dev, PWRCSR0, 0x3f3b3100); + + rt2x00pci_register_write(rt2x00dev, GPIOCSR, 0x0000ff00); + rt2x00pci_register_write(rt2x00dev, TESTCSR, 0x000000f0); + + if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE)) + return -EBUSY; + + rt2x00pci_register_write(rt2x00dev, MACCSR0, 0x00213223); + rt2x00pci_register_write(rt2x00dev, MACCSR1, 0x00235518); + + rt2x00pci_register_read(rt2x00dev, MACCSR2, ®); + rt2x00_set_field32(®, MACCSR2_DELAY, 64); + rt2x00pci_register_write(rt2x00dev, MACCSR2, reg); + + rt2x00pci_register_read(rt2x00dev, RALINKCSR, ®); + rt2x00_set_field32(®, RALINKCSR_AR_BBP_DATA0, 17); + rt2x00_set_field32(®, RALINKCSR_AR_BBP_ID0, 26); + rt2x00_set_field32(®, RALINKCSR_AR_BBP_VALID0, 1); + rt2x00_set_field32(®, RALINKCSR_AR_BBP_DATA1, 0); + rt2x00_set_field32(®, RALINKCSR_AR_BBP_ID1, 26); + rt2x00_set_field32(®, RALINKCSR_AR_BBP_VALID1, 1); + rt2x00pci_register_write(rt2x00dev, RALINKCSR, reg); + + rt2x00pci_register_write(rt2x00dev, BBPCSR1, 0x82188200); + + rt2x00pci_register_write(rt2x00dev, TXACKCSR0, 0x00000020); + + rt2x00pci_register_read(rt2x00dev, CSR1, ®); + rt2x00_set_field32(®, CSR1_SOFT_RESET, 1); + rt2x00_set_field32(®, CSR1_BBP_RESET, 0); + rt2x00_set_field32(®, CSR1_HOST_READY, 0); + rt2x00pci_register_write(rt2x00dev, CSR1, reg); + + rt2x00pci_register_read(rt2x00dev, CSR1, ®); + rt2x00_set_field32(®, CSR1_SOFT_RESET, 0); + rt2x00_set_field32(®, CSR1_HOST_READY, 1); + rt2x00pci_register_write(rt2x00dev, CSR1, reg); + + /* + * We must clear the FCS and FIFO error count. + * These registers are cleared on read, + * so we may pass a useless variable to store the value. + */ + rt2x00pci_register_read(rt2x00dev, CNT0, ®); + rt2x00pci_register_read(rt2x00dev, CNT4, ®); + + return 0; +} + +static int rt2500pci_init_bbp(struct rt2x00_dev *rt2x00dev) +{ + unsigned int i; + u16 eeprom; + u8 reg_id; + u8 value; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2500pci_bbp_read(rt2x00dev, 0, &value); + if ((value != 0xff) && (value != 0x00)) + goto continue_csr_init; + NOTICE(rt2x00dev, "Waiting for BBP register.\n"); + udelay(REGISTER_BUSY_DELAY); + } + + ERROR(rt2x00dev, "BBP register access failed, aborting.\n"); + return -EACCES; + +continue_csr_init: + rt2500pci_bbp_write(rt2x00dev, 3, 0x02); + rt2500pci_bbp_write(rt2x00dev, 4, 0x19); + rt2500pci_bbp_write(rt2x00dev, 14, 0x1c); + rt2500pci_bbp_write(rt2x00dev, 15, 0x30); + rt2500pci_bbp_write(rt2x00dev, 16, 0xac); + rt2500pci_bbp_write(rt2x00dev, 18, 0x18); + rt2500pci_bbp_write(rt2x00dev, 19, 0xff); + rt2500pci_bbp_write(rt2x00dev, 20, 0x1e); + rt2500pci_bbp_write(rt2x00dev, 21, 0x08); + rt2500pci_bbp_write(rt2x00dev, 22, 0x08); + rt2500pci_bbp_write(rt2x00dev, 23, 0x08); + rt2500pci_bbp_write(rt2x00dev, 24, 0x70); + rt2500pci_bbp_write(rt2x00dev, 25, 0x40); + rt2500pci_bbp_write(rt2x00dev, 26, 0x08); + rt2500pci_bbp_write(rt2x00dev, 27, 0x23); + rt2500pci_bbp_write(rt2x00dev, 30, 0x10); + rt2500pci_bbp_write(rt2x00dev, 31, 0x2b); + rt2500pci_bbp_write(rt2x00dev, 32, 0xb9); + rt2500pci_bbp_write(rt2x00dev, 34, 0x12); + rt2500pci_bbp_write(rt2x00dev, 35, 0x50); + rt2500pci_bbp_write(rt2x00dev, 39, 0xc4); + rt2500pci_bbp_write(rt2x00dev, 40, 0x02); + rt2500pci_bbp_write(rt2x00dev, 41, 0x60); + rt2500pci_bbp_write(rt2x00dev, 53, 0x10); + rt2500pci_bbp_write(rt2x00dev, 54, 0x18); + rt2500pci_bbp_write(rt2x00dev, 56, 0x08); + rt2500pci_bbp_write(rt2x00dev, 57, 0x10); + rt2500pci_bbp_write(rt2x00dev, 58, 0x08); + rt2500pci_bbp_write(rt2x00dev, 61, 0x6d); + rt2500pci_bbp_write(rt2x00dev, 62, 0x10); + + DEBUG(rt2x00dev, "Start initialization from EEPROM...\n"); + for (i = 0; i < EEPROM_BBP_SIZE; i++) { + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom); + + if (eeprom != 0xffff && eeprom != 0x0000) { + reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID); + value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE); + DEBUG(rt2x00dev, "BBP: 0x%02x, value: 0x%02x.\n", + reg_id, value); + rt2500pci_bbp_write(rt2x00dev, reg_id, value); + } + } + DEBUG(rt2x00dev, "...End initialization from EEPROM.\n"); + + return 0; +} + +/* + * Device state switch handlers. + */ +static void rt2500pci_toggle_rx(struct rt2x00_dev *rt2x00dev, + enum dev_state state) +{ + u32 reg; + + rt2x00pci_register_read(rt2x00dev, RXCSR0, ®); + rt2x00_set_field32(®, RXCSR0_DISABLE_RX, + state == STATE_RADIO_RX_OFF); + rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); +} + +static void rt2500pci_toggle_irq(struct rt2x00_dev *rt2x00dev, + enum dev_state state) +{ + int mask = (state == STATE_RADIO_IRQ_OFF); + u32 reg; + + /* + * When interrupts are being enabled, the interrupt registers + * should clear the register to assure a clean state. + */ + if (state == STATE_RADIO_IRQ_ON) { + rt2x00pci_register_read(rt2x00dev, CSR7, ®); + rt2x00pci_register_write(rt2x00dev, CSR7, reg); + } + + /* + * Only toggle the interrupts bits we are going to use. + * Non-checked interrupt bits are disabled by default. + */ + rt2x00pci_register_read(rt2x00dev, CSR8, ®); + rt2x00_set_field32(®, CSR8_TBCN_EXPIRE, mask); + rt2x00_set_field32(®, CSR8_TXDONE_TXRING, mask); + rt2x00_set_field32(®, CSR8_TXDONE_ATIMRING, mask); + rt2x00_set_field32(®, CSR8_TXDONE_PRIORING, mask); + rt2x00_set_field32(®, CSR8_RXDONE, mask); + rt2x00pci_register_write(rt2x00dev, CSR8, reg); +} + +static int rt2500pci_enable_radio(struct rt2x00_dev *rt2x00dev) +{ + /* + * Initialize all registers. + */ + if (rt2500pci_init_rings(rt2x00dev) || + rt2500pci_init_registers(rt2x00dev) || + rt2500pci_init_bbp(rt2x00dev)) { + ERROR(rt2x00dev, "Register initialization failed.\n"); + return -EIO; + } + + /* + * Enable interrupts. + */ + rt2500pci_toggle_irq(rt2x00dev, STATE_RADIO_IRQ_ON); + + /* + * Enable LED + */ + rt2500pci_enable_led(rt2x00dev); + + return 0; +} + +static void rt2500pci_disable_radio(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + /* + * Disable LED + */ + rt2500pci_disable_led(rt2x00dev); + + rt2x00pci_register_write(rt2x00dev, PWRCSR0, 0); + + /* + * Disable synchronisation. + */ + rt2x00pci_register_write(rt2x00dev, CSR14, 0); + + /* + * Cancel RX and TX. + */ + rt2x00pci_register_read(rt2x00dev, TXCSR0, ®); + rt2x00_set_field32(®, TXCSR0_ABORT, 1); + rt2x00pci_register_write(rt2x00dev, TXCSR0, reg); + + /* + * Disable interrupts. + */ + rt2500pci_toggle_irq(rt2x00dev, STATE_RADIO_IRQ_OFF); +} + +static int rt2500pci_set_state(struct rt2x00_dev *rt2x00dev, + enum dev_state state) +{ + u32 reg; + unsigned int i; + char put_to_sleep; + char bbp_state; + char rf_state; + + put_to_sleep = (state != STATE_AWAKE); + + rt2x00pci_register_read(rt2x00dev, PWRCSR1, ®); + rt2x00_set_field32(®, PWRCSR1_SET_STATE, 1); + rt2x00_set_field32(®, PWRCSR1_BBP_DESIRE_STATE, state); + rt2x00_set_field32(®, PWRCSR1_RF_DESIRE_STATE, state); + rt2x00_set_field32(®, PWRCSR1_PUT_TO_SLEEP, put_to_sleep); + rt2x00pci_register_write(rt2x00dev, PWRCSR1, reg); + + /* + * Device is not guaranteed to be in the requested state yet. + * We must wait until the register indicates that the + * device has entered the correct state. + */ + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2x00pci_register_read(rt2x00dev, PWRCSR1, ®); + bbp_state = rt2x00_get_field32(reg, PWRCSR1_BBP_CURR_STATE); + rf_state = rt2x00_get_field32(reg, PWRCSR1_RF_CURR_STATE); + if (bbp_state == state && rf_state == state) + return 0; + msleep(10); + } + + NOTICE(rt2x00dev, "Device failed to enter state %d, " + "current device state: bbp %d and rf %d.\n", + state, bbp_state, rf_state); + + return -EBUSY; +} + +static int rt2500pci_set_device_state(struct rt2x00_dev *rt2x00dev, + enum dev_state state) +{ + int retval = 0; + + switch (state) { + case STATE_RADIO_ON: + retval = rt2500pci_enable_radio(rt2x00dev); + break; + case STATE_RADIO_OFF: + rt2500pci_disable_radio(rt2x00dev); + break; + case STATE_RADIO_RX_ON: + case STATE_RADIO_RX_OFF: + rt2500pci_toggle_rx(rt2x00dev, state); + break; + case STATE_DEEP_SLEEP: + case STATE_SLEEP: + case STATE_STANDBY: + case STATE_AWAKE: + retval = rt2500pci_set_state(rt2x00dev, state); + break; + default: + retval = -ENOTSUPP; + break; + } + + return retval; +} + +/* + * TX descriptor initialization + */ +static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, + struct data_desc *txd, + struct data_entry_desc *desc, + struct ieee80211_hdr *ieee80211hdr, + unsigned int length, + struct ieee80211_tx_control *control) +{ + u32 word; + + /* + * Start writing the descriptor words. + */ + rt2x00_desc_read(txd, 2, &word); + rt2x00_set_field32(&word, TXD_W2_IV_OFFSET, IEEE80211_HEADER); + rt2x00_set_field32(&word, TXD_W2_AIFS, desc->aifs); + rt2x00_set_field32(&word, TXD_W2_CWMIN, desc->cw_min); + rt2x00_set_field32(&word, TXD_W2_CWMAX, desc->cw_max); + rt2x00_desc_write(txd, 2, word); + + rt2x00_desc_read(txd, 3, &word); + rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL, desc->signal); + rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE, desc->service); + rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_LOW, desc->length_low); + rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_HIGH, desc->length_high); + rt2x00_desc_write(txd, 3, word); + + rt2x00_desc_read(txd, 10, &word); + rt2x00_set_field32(&word, TXD_W10_RTS, + test_bit(ENTRY_TXD_RTS_FRAME, &desc->flags)); + rt2x00_desc_write(txd, 10, word); + + rt2x00_desc_read(txd, 0, &word); + rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 1); + rt2x00_set_field32(&word, TXD_W0_VALID, 1); + rt2x00_set_field32(&word, TXD_W0_MORE_FRAG, + test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags)); + rt2x00_set_field32(&word, TXD_W0_ACK, + !(control->flags & IEEE80211_TXCTL_NO_ACK)); + rt2x00_set_field32(&word, TXD_W0_TIMESTAMP, + test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags)); + rt2x00_set_field32(&word, TXD_W0_OFDM, + test_bit(ENTRY_TXD_OFDM_RATE, &desc->flags)); + rt2x00_set_field32(&word, TXD_W0_CIPHER_OWNER, 1); + rt2x00_set_field32(&word, TXD_W0_IFS, desc->ifs); + rt2x00_set_field32(&word, TXD_W0_RETRY_MODE, + !!(control->flags & + IEEE80211_TXCTL_LONG_RETRY_LIMIT)); + rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, length); + rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE); + rt2x00_desc_write(txd, 0, word); +} + +/* + * TX data initialization + */ +static void rt2500pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, + unsigned int queue) +{ + u32 reg; + + if (queue == IEEE80211_TX_QUEUE_BEACON) { + rt2x00pci_register_read(rt2x00dev, CSR14, ®); + if (!rt2x00_get_field32(reg, CSR14_BEACON_GEN)) { + rt2x00_set_field32(®, CSR14_BEACON_GEN, 1); + rt2x00pci_register_write(rt2x00dev, CSR14, reg); + } + return; + } + + rt2x00pci_register_read(rt2x00dev, TXCSR0, ®); + if (queue == IEEE80211_TX_QUEUE_DATA0) + rt2x00_set_field32(®, TXCSR0_KICK_PRIO, 1); + else if (queue == IEEE80211_TX_QUEUE_DATA1) + rt2x00_set_field32(®, TXCSR0_KICK_TX, 1); + else if (queue == IEEE80211_TX_QUEUE_AFTER_BEACON) + rt2x00_set_field32(®, TXCSR0_KICK_ATIM, 1); + rt2x00pci_register_write(rt2x00dev, TXCSR0, reg); +} + +/* + * RX control handlers + */ +static int rt2500pci_fill_rxdone(struct data_entry *entry, + int *signal, int *rssi, int *ofdm, int *size) +{ + struct data_desc *rxd = entry->priv; + u32 word0; + u32 word2; + + rt2x00_desc_read(rxd, 0, &word0); + rt2x00_desc_read(rxd, 2, &word2); + + if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR) || + rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR) || + rt2x00_get_field32(word0, RXD_W0_ICV_ERROR)) + return -EINVAL; + + *signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL); + *rssi = rt2x00_get_field32(word2, RXD_W2_RSSI) - + entry->ring->rt2x00dev->rssi_offset; + *ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); + *size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); + + return 0; +} + +/* + * Interrupt functions. + */ +static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev, const int queue) +{ + struct data_ring *ring = rt2x00lib_get_ring(rt2x00dev, queue); + struct data_entry *entry; + struct data_desc *txd; + u32 word; + int tx_status; + int retry; + + while (!rt2x00_ring_empty(ring)) { + entry = rt2x00_get_data_entry_done(ring); + txd = entry->priv; + rt2x00_desc_read(txd, 0, &word); + + if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || + !rt2x00_get_field32(word, TXD_W0_VALID)) + break; + + /* + * Obtain the status about this packet. + */ + tx_status = rt2x00_get_field32(word, TXD_W0_RESULT); + retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT); + + rt2x00lib_txdone(entry, tx_status, retry); + + /* + * Make this entry available for reuse. + */ + entry->flags = 0; + rt2x00_set_field32(&word, TXD_W0_VALID, 0); + rt2x00_desc_write(txd, 0, word); + rt2x00_ring_index_done_inc(ring); + } + + /* + * If the data ring was full before the txdone handler + * we must make sure the packet queue in the mac80211 stack + * is reenabled when the txdone handler has finished. + */ + entry = ring->entry; + if (!rt2x00_ring_full(ring)) + ieee80211_wake_queue(rt2x00dev->hw, + entry->tx_status.control.queue); +} + +static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance) +{ + struct rt2x00_dev *rt2x00dev = dev_instance; + u32 reg; + + /* + * Get the interrupt sources & saved to local variable. + * Write register value back to clear pending interrupts. + */ + rt2x00pci_register_read(rt2x00dev, CSR7, ®); + rt2x00pci_register_write(rt2x00dev, CSR7, reg); + + if (!reg) + return IRQ_NONE; + + if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + return IRQ_HANDLED; + + /* + * Handle interrupts, walk through all bits + * and run the tasks, the bits are checked in order of + * priority. + */ + + /* + * 1 - Beacon timer expired interrupt. + */ + if (rt2x00_get_field32(reg, CSR7_TBCN_EXPIRE)) + rt2x00lib_beacondone(rt2x00dev); + + /* + * 2 - Rx ring done interrupt. + */ + if (rt2x00_get_field32(reg, CSR7_RXDONE)) + rt2x00pci_rxdone(rt2x00dev); + + /* + * 3 - Atim ring transmit done interrupt. + */ + if (rt2x00_get_field32(reg, CSR7_TXDONE_ATIMRING)) + rt2500pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_AFTER_BEACON); + + /* + * 4 - Priority ring transmit done interrupt. + */ + if (rt2x00_get_field32(reg, CSR7_TXDONE_PRIORING)) + rt2500pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_DATA0); + + /* + * 5 - Tx ring transmit done interrupt. + */ + if (rt2x00_get_field32(reg, CSR7_TXDONE_TXRING)) + rt2500pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_DATA1); + + return IRQ_HANDLED; +} + +/* + * Device probe functions. + */ +static int rt2500pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) +{ + struct eeprom_93cx6 eeprom; + u32 reg; + u16 word; + u8 *mac; + + rt2x00pci_register_read(rt2x00dev, CSR21, ®); + + eeprom.data = rt2x00dev; + eeprom.register_read = rt2500pci_eepromregister_read; + eeprom.register_write = rt2500pci_eepromregister_write; + eeprom.width = rt2x00_get_field32(reg, CSR21_TYPE_93C46) ? + PCI_EEPROM_WIDTH_93C46 : PCI_EEPROM_WIDTH_93C66; + eeprom.reg_data_in = 0; + eeprom.reg_data_out = 0; + eeprom.reg_data_clock = 0; + eeprom.reg_chip_select = 0; + + eeprom_93cx6_multiread(&eeprom, EEPROM_BASE, rt2x00dev->eeprom, + EEPROM_SIZE / sizeof(u16)); + + /* + * Start validation of the data that has been read. + */ + mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); + if (!is_valid_ether_addr(mac)) { + random_ether_addr(mac); + EEPROM(rt2x00dev, "MAC: " MAC_FMT "\n", MAC_ARG(mac)); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2); + rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, 0); + rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT, 0); + rt2x00_set_field16(&word, EEPROM_ANTENNA_LED_MODE, 0); + rt2x00_set_field16(&word, EEPROM_ANTENNA_DYN_TXAGC, 0); + rt2x00_set_field16(&word, EEPROM_ANTENNA_HARDWARE_RADIO, 0); + rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF2522); + rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word); + EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_NIC_CARDBUS_ACCEL, 0); + rt2x00_set_field16(&word, EEPROM_NIC_DYN_BBP_TUNE, 0); + rt2x00_set_field16(&word, EEPROM_NIC_CCK_TX_POWER, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word); + EEPROM(rt2x00dev, "NIC: 0x%04x\n", word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_CALIBRATE_OFFSET_RSSI, + DEFAULT_RSSI_OFFSET); + rt2x00_eeprom_write(rt2x00dev, EEPROM_CALIBRATE_OFFSET, word); + EEPROM(rt2x00dev, "Calibrate offset: 0x%04x\n", word); + } + + return 0; +} + +static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + u16 value; + u16 eeprom; + + /* + * Read EEPROM word for configuration. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); + + /* + * Identify RF chipset. + */ + value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); + rt2x00pci_register_read(rt2x00dev, CSR0, ®); + rt2x00_set_chip(rt2x00dev, RT2560, value, reg); + + if (!rt2x00_rf(&rt2x00dev->chip, RF2522) && + !rt2x00_rf(&rt2x00dev->chip, RF2523) && + !rt2x00_rf(&rt2x00dev->chip, RF2524) && + !rt2x00_rf(&rt2x00dev->chip, RF2525) && + !rt2x00_rf(&rt2x00dev->chip, RF2525E) && + !rt2x00_rf(&rt2x00dev->chip, RF5222)) { + ERROR(rt2x00dev, "Invalid RF chipset detected.\n"); + return -ENODEV; + } + + /* + * Identify default antenna configuration. + */ + rt2x00dev->hw->conf.antenna_sel_tx = + rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TX_DEFAULT); + rt2x00dev->hw->conf.antenna_sel_rx = + rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT); + + /* + * Store led mode, for correct led behaviour. + */ + rt2x00dev->led_mode = + rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE); + + /* + * Detect if this device has an hardware controlled radio. + */ + if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) + __set_bit(DEVICE_SUPPORT_HW_BUTTON, &rt2x00dev->flags); + + /* + * Check if the BBP tuning should be enabled. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom); + + if (rt2x00_get_field16(eeprom, EEPROM_NIC_DYN_BBP_TUNE)) + __set_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags); + + /* + * Read the RSSI <-> dBm offset information. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET, &eeprom); + rt2x00dev->rssi_offset = + rt2x00_get_field16(eeprom, EEPROM_CALIBRATE_OFFSET_RSSI); + + return 0; +} + +/* + * RF value list for RF2522 + * Supports: 2.4 GHz + */ +static const struct rf_channel rf_vals_bg_2522[] = { + { 1, 0x00002050, 0x000c1fda, 0x00000101, 0 }, + { 2, 0x00002050, 0x000c1fee, 0x00000101, 0 }, + { 3, 0x00002050, 0x000c2002, 0x00000101, 0 }, + { 4, 0x00002050, 0x000c2016, 0x00000101, 0 }, + { 5, 0x00002050, 0x000c202a, 0x00000101, 0 }, + { 6, 0x00002050, 0x000c203e, 0x00000101, 0 }, + { 7, 0x00002050, 0x000c2052, 0x00000101, 0 }, + { 8, 0x00002050, 0x000c2066, 0x00000101, 0 }, + { 9, 0x00002050, 0x000c207a, 0x00000101, 0 }, + { 10, 0x00002050, 0x000c208e, 0x00000101, 0 }, + { 11, 0x00002050, 0x000c20a2, 0x00000101, 0 }, + { 12, 0x00002050, 0x000c20b6, 0x00000101, 0 }, + { 13, 0x00002050, 0x000c20ca, 0x00000101, 0 }, + { 14, 0x00002050, 0x000c20fa, 0x00000101, 0 }, +}; + +/* + * RF value list for RF2523 + * Supports: 2.4 GHz + */ +static const struct rf_channel rf_vals_bg_2523[] = { + { 1, 0x00022010, 0x00000c9e, 0x000e0111, 0x00000a1b }, + { 2, 0x00022010, 0x00000ca2, 0x000e0111, 0x00000a1b }, + { 3, 0x00022010, 0x00000ca6, 0x000e0111, 0x00000a1b }, + { 4, 0x00022010, 0x00000caa, 0x000e0111, 0x00000a1b }, + { 5, 0x00022010, 0x00000cae, 0x000e0111, 0x00000a1b }, + { 6, 0x00022010, 0x00000cb2, 0x000e0111, 0x00000a1b }, + { 7, 0x00022010, 0x00000cb6, 0x000e0111, 0x00000a1b }, + { 8, 0x00022010, 0x00000cba, 0x000e0111, 0x00000a1b }, + { 9, 0x00022010, 0x00000cbe, 0x000e0111, 0x00000a1b }, + { 10, 0x00022010, 0x00000d02, 0x000e0111, 0x00000a1b }, + { 11, 0x00022010, 0x00000d06, 0x000e0111, 0x00000a1b }, + { 12, 0x00022010, 0x00000d0a, 0x000e0111, 0x00000a1b }, + { 13, 0x00022010, 0x00000d0e, 0x000e0111, 0x00000a1b }, + { 14, 0x00022010, 0x00000d1a, 0x000e0111, 0x00000a03 }, +}; + +/* + * RF value list for RF2524 + * Supports: 2.4 GHz + */ +static const struct rf_channel rf_vals_bg_2524[] = { + { 1, 0x00032020, 0x00000c9e, 0x00000101, 0x00000a1b }, + { 2, 0x00032020, 0x00000ca2, 0x00000101, 0x00000a1b }, + { 3, 0x00032020, 0x00000ca6, 0x00000101, 0x00000a1b }, + { 4, 0x00032020, 0x00000caa, 0x00000101, 0x00000a1b }, + { 5, 0x00032020, 0x00000cae, 0x00000101, 0x00000a1b }, + { 6, 0x00032020, 0x00000cb2, 0x00000101, 0x00000a1b }, + { 7, 0x00032020, 0x00000cb6, 0x00000101, 0x00000a1b }, + { 8, 0x00032020, 0x00000cba, 0x00000101, 0x00000a1b }, + { 9, 0x00032020, 0x00000cbe, 0x00000101, 0x00000a1b }, + { 10, 0x00032020, 0x00000d02, 0x00000101, 0x00000a1b }, + { 11, 0x00032020, 0x00000d06, 0x00000101, 0x00000a1b }, + { 12, 0x00032020, 0x00000d0a, 0x00000101, 0x00000a1b }, + { 13, 0x00032020, 0x00000d0e, 0x00000101, 0x00000a1b }, + { 14, 0x00032020, 0x00000d1a, 0x00000101, 0x00000a03 }, +}; + +/* + * RF value list for RF2525 + * Supports: 2.4 GHz + */ +static const struct rf_channel rf_vals_bg_2525[] = { + { 1, 0x00022020, 0x00080c9e, 0x00060111, 0x00000a1b }, + { 2, 0x00022020, 0x00080ca2, 0x00060111, 0x00000a1b }, + { 3, 0x00022020, 0x00080ca6, 0x00060111, 0x00000a1b }, + { 4, 0x00022020, 0x00080caa, 0x00060111, 0x00000a1b }, + { 5, 0x00022020, 0x00080cae, 0x00060111, 0x00000a1b }, + { 6, 0x00022020, 0x00080cb2, 0x00060111, 0x00000a1b }, + { 7, 0x00022020, 0x00080cb6, 0x00060111, 0x00000a1b }, + { 8, 0x00022020, 0x00080cba, 0x00060111, 0x00000a1b }, + { 9, 0x00022020, 0x00080cbe, 0x00060111, 0x00000a1b }, + { 10, 0x00022020, 0x00080d02, 0x00060111, 0x00000a1b }, + { 11, 0x00022020, 0x00080d06, 0x00060111, 0x00000a1b }, + { 12, 0x00022020, 0x00080d0a, 0x00060111, 0x00000a1b }, + { 13, 0x00022020, 0x00080d0e, 0x00060111, 0x00000a1b }, + { 14, 0x00022020, 0x00080d1a, 0x00060111, 0x00000a03 }, +}; + +/* + * RF value list for RF2525e + * Supports: 2.4 GHz + */ +static const struct rf_channel rf_vals_bg_2525e[] = { + { 1, 0x00022020, 0x00081136, 0x00060111, 0x00000a0b }, + { 2, 0x00022020, 0x0008113a, 0x00060111, 0x00000a0b }, + { 3, 0x00022020, 0x0008113e, 0x00060111, 0x00000a0b }, + { 4, 0x00022020, 0x00081182, 0x00060111, 0x00000a0b }, + { 5, 0x00022020, 0x00081186, 0x00060111, 0x00000a0b }, + { 6, 0x00022020, 0x0008118a, 0x00060111, 0x00000a0b }, + { 7, 0x00022020, 0x0008118e, 0x00060111, 0x00000a0b }, + { 8, 0x00022020, 0x00081192, 0x00060111, 0x00000a0b }, + { 9, 0x00022020, 0x00081196, 0x00060111, 0x00000a0b }, + { 10, 0x00022020, 0x0008119a, 0x00060111, 0x00000a0b }, + { 11, 0x00022020, 0x0008119e, 0x00060111, 0x00000a0b }, + { 12, 0x00022020, 0x000811a2, 0x00060111, 0x00000a0b }, + { 13, 0x00022020, 0x000811a6, 0x00060111, 0x00000a0b }, + { 14, 0x00022020, 0x000811ae, 0x00060111, 0x00000a1b }, +}; + +/* + * RF value list for RF5222 + * Supports: 2.4 GHz & 5.2 GHz + */ +static const struct rf_channel rf_vals_5222[] = { + { 1, 0x00022020, 0x00001136, 0x00000101, 0x00000a0b }, + { 2, 0x00022020, 0x0000113a, 0x00000101, 0x00000a0b }, + { 3, 0x00022020, 0x0000113e, 0x00000101, 0x00000a0b }, + { 4, 0x00022020, 0x00001182, 0x00000101, 0x00000a0b }, + { 5, 0x00022020, 0x00001186, 0x00000101, 0x00000a0b }, + { 6, 0x00022020, 0x0000118a, 0x00000101, 0x00000a0b }, + { 7, 0x00022020, 0x0000118e, 0x00000101, 0x00000a0b }, + { 8, 0x00022020, 0x00001192, 0x00000101, 0x00000a0b }, + { 9, 0x00022020, 0x00001196, 0x00000101, 0x00000a0b }, + { 10, 0x00022020, 0x0000119a, 0x00000101, 0x00000a0b }, + { 11, 0x00022020, 0x0000119e, 0x00000101, 0x00000a0b }, + { 12, 0x00022020, 0x000011a2, 0x00000101, 0x00000a0b }, + { 13, 0x00022020, 0x000011a6, 0x00000101, 0x00000a0b }, + { 14, 0x00022020, 0x000011ae, 0x00000101, 0x00000a1b }, + + /* 802.11 UNI / HyperLan 2 */ + { 36, 0x00022010, 0x00018896, 0x00000101, 0x00000a1f }, + { 40, 0x00022010, 0x0001889a, 0x00000101, 0x00000a1f }, + { 44, 0x00022010, 0x0001889e, 0x00000101, 0x00000a1f }, + { 48, 0x00022010, 0x000188a2, 0x00000101, 0x00000a1f }, + { 52, 0x00022010, 0x000188a6, 0x00000101, 0x00000a1f }, + { 66, 0x00022010, 0x000188aa, 0x00000101, 0x00000a1f }, + { 60, 0x00022010, 0x000188ae, 0x00000101, 0x00000a1f }, + { 64, 0x00022010, 0x000188b2, 0x00000101, 0x00000a1f }, + + /* 802.11 HyperLan 2 */ + { 100, 0x00022010, 0x00008802, 0x00000101, 0x00000a0f }, + { 104, 0x00022010, 0x00008806, 0x00000101, 0x00000a0f }, + { 108, 0x00022010, 0x0000880a, 0x00000101, 0x00000a0f }, + { 112, 0x00022010, 0x0000880e, 0x00000101, 0x00000a0f }, + { 116, 0x00022010, 0x00008812, 0x00000101, 0x00000a0f }, + { 120, 0x00022010, 0x00008816, 0x00000101, 0x00000a0f }, + { 124, 0x00022010, 0x0000881a, 0x00000101, 0x00000a0f }, + { 128, 0x00022010, 0x0000881e, 0x00000101, 0x00000a0f }, + { 132, 0x00022010, 0x00008822, 0x00000101, 0x00000a0f }, + { 136, 0x00022010, 0x00008826, 0x00000101, 0x00000a0f }, + + /* 802.11 UNII */ + { 140, 0x00022010, 0x0000882a, 0x00000101, 0x00000a0f }, + { 149, 0x00022020, 0x000090a6, 0x00000101, 0x00000a07 }, + { 153, 0x00022020, 0x000090ae, 0x00000101, 0x00000a07 }, + { 157, 0x00022020, 0x000090b6, 0x00000101, 0x00000a07 }, + { 161, 0x00022020, 0x000090be, 0x00000101, 0x00000a07 }, +}; + +static void rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) +{ + struct hw_mode_spec *spec = &rt2x00dev->spec; + u8 *txpower; + unsigned int i; + + /* + * Initialize all hw fields. + */ + rt2x00dev->hw->flags = + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_MONITOR_DURING_OPER | + IEEE80211_HW_NO_PROBE_FILTERING; + rt2x00dev->hw->extra_tx_headroom = 0; + rt2x00dev->hw->max_signal = MAX_SIGNAL; + rt2x00dev->hw->max_rssi = MAX_RX_SSI; + rt2x00dev->hw->queues = 2; + + SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev); + SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, + rt2x00_eeprom_addr(rt2x00dev, + EEPROM_MAC_ADDR_0)); + + /* + * Convert tx_power array in eeprom. + */ + txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START); + for (i = 0; i < 14; i++) + txpower[i] = TXPOWER_FROM_DEV(txpower[i]); + + /* + * Initialize hw_mode information. + */ + spec->num_modes = 2; + spec->num_rates = 12; + spec->tx_power_a = NULL; + spec->tx_power_bg = txpower; + spec->tx_power_default = DEFAULT_TXPOWER; + + if (rt2x00_rf(&rt2x00dev->chip, RF2522)) { + spec->num_channels = ARRAY_SIZE(rf_vals_bg_2522); + spec->channels = rf_vals_bg_2522; + } else if (rt2x00_rf(&rt2x00dev->chip, RF2523)) { + spec->num_channels = ARRAY_SIZE(rf_vals_bg_2523); + spec->channels = rf_vals_bg_2523; + } else if (rt2x00_rf(&rt2x00dev->chip, RF2524)) { + spec->num_channels = ARRAY_SIZE(rf_vals_bg_2524); + spec->channels = rf_vals_bg_2524; + } else if (rt2x00_rf(&rt2x00dev->chip, RF2525)) { + spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525); + spec->channels = rf_vals_bg_2525; + } else if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) { + spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525e); + spec->channels = rf_vals_bg_2525e; + } else if (rt2x00_rf(&rt2x00dev->chip, RF5222)) { + spec->num_channels = ARRAY_SIZE(rf_vals_5222); + spec->channels = rf_vals_5222; + spec->num_modes = 3; + } +} + +static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev) +{ + int retval; + + /* + * Allocate eeprom data. + */ + retval = rt2500pci_validate_eeprom(rt2x00dev); + if (retval) + return retval; + + retval = rt2500pci_init_eeprom(rt2x00dev); + if (retval) + return retval; + + /* + * Initialize hw specifications. + */ + rt2500pci_probe_hw_mode(rt2x00dev); + + /* + * This device requires the beacon ring + */ + __set_bit(REQUIRE_BEACON_RING, &rt2x00dev->flags); + + /* + * Set the rssi offset. + */ + rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET; + + return 0; +} + +/* + * IEEE80211 stack callback functions. + */ +static int rt2500pci_set_retry_limit(struct ieee80211_hw *hw, + u32 short_retry, u32 long_retry) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + u32 reg; + + rt2x00pci_register_read(rt2x00dev, CSR11, ®); + rt2x00_set_field32(®, CSR11_LONG_RETRY, long_retry); + rt2x00_set_field32(®, CSR11_SHORT_RETRY, short_retry); + rt2x00pci_register_write(rt2x00dev, CSR11, reg); + + return 0; +} + +static u64 rt2500pci_get_tsf(struct ieee80211_hw *hw) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + u64 tsf; + u32 reg; + + rt2x00pci_register_read(rt2x00dev, CSR17, ®); + tsf = (u64) rt2x00_get_field32(reg, CSR17_HIGH_TSFTIMER) << 32; + rt2x00pci_register_read(rt2x00dev, CSR16, ®); + tsf |= rt2x00_get_field32(reg, CSR16_LOW_TSFTIMER); + + return tsf; +} + +static void rt2500pci_reset_tsf(struct ieee80211_hw *hw) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + + rt2x00pci_register_write(rt2x00dev, CSR16, 0); + rt2x00pci_register_write(rt2x00dev, CSR17, 0); +} + +static int rt2500pci_tx_last_beacon(struct ieee80211_hw *hw) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + u32 reg; + + rt2x00pci_register_read(rt2x00dev, CSR15, ®); + return rt2x00_get_field32(reg, CSR15_BEACON_SENT); +} + +static const struct ieee80211_ops rt2500pci_mac80211_ops = { + .tx = rt2x00mac_tx, + .add_interface = rt2x00mac_add_interface, + .remove_interface = rt2x00mac_remove_interface, + .config = rt2x00mac_config, + .config_interface = rt2x00mac_config_interface, + .set_multicast_list = rt2x00mac_set_multicast_list, + .get_stats = rt2x00mac_get_stats, + .set_retry_limit = rt2500pci_set_retry_limit, + .conf_tx = rt2x00mac_conf_tx, + .get_tx_stats = rt2x00mac_get_tx_stats, + .get_tsf = rt2500pci_get_tsf, + .reset_tsf = rt2500pci_reset_tsf, + .beacon_update = rt2x00pci_beacon_update, + .tx_last_beacon = rt2500pci_tx_last_beacon, +}; + +static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = { + .irq_handler = rt2500pci_interrupt, + .probe_hw = rt2500pci_probe_hw, + .initialize = rt2x00pci_initialize, + .uninitialize = rt2x00pci_uninitialize, + .set_device_state = rt2500pci_set_device_state, +#ifdef CONFIG_RT2500PCI_RFKILL + .rfkill_poll = rt2500pci_rfkill_poll, +#endif /* CONFIG_RT2500PCI_RFKILL */ + .link_stats = rt2500pci_link_stats, + .reset_tuner = rt2500pci_reset_tuner, + .link_tuner = rt2500pci_link_tuner, + .write_tx_desc = rt2500pci_write_tx_desc, + .write_tx_data = rt2x00pci_write_tx_data, + .kick_tx_queue = rt2500pci_kick_tx_queue, + .fill_rxdone = rt2500pci_fill_rxdone, + .config_mac_addr = rt2500pci_config_mac_addr, + .config_bssid = rt2500pci_config_bssid, + .config_packet_filter = rt2500pci_config_packet_filter, + .config_type = rt2500pci_config_type, + .config = rt2500pci_config, +}; + +static const struct rt2x00_ops rt2500pci_ops = { + .name = DRV_NAME, + .rxd_size = RXD_DESC_SIZE, + .txd_size = TXD_DESC_SIZE, + .eeprom_size = EEPROM_SIZE, + .rf_size = RF_SIZE, + .lib = &rt2500pci_rt2x00_ops, + .hw = &rt2500pci_mac80211_ops, +#ifdef CONFIG_RT2X00_LIB_DEBUGFS + .debugfs = &rt2500pci_rt2x00debug, +#endif /* CONFIG_RT2X00_LIB_DEBUGFS */ +}; + +/* + * RT2500pci module information. + */ +static struct pci_device_id rt2500pci_device_table[] = { + { PCI_DEVICE(0x1814, 0x0201), PCI_DEVICE_DATA(&rt2500pci_ops) }, + { 0, } +}; + +MODULE_AUTHOR(DRV_PROJECT); +MODULE_VERSION(DRV_VERSION); +MODULE_DESCRIPTION("Ralink RT2500 PCI & PCMCIA Wireless LAN driver."); +MODULE_SUPPORTED_DEVICE("Ralink RT2560 PCI & PCMCIA chipset based cards"); +MODULE_DEVICE_TABLE(pci, rt2500pci_device_table); +MODULE_LICENSE("GPL"); + +static struct pci_driver rt2500pci_driver = { + .name = DRV_NAME, + .id_table = rt2500pci_device_table, + .probe = rt2x00pci_probe, + .remove = __devexit_p(rt2x00pci_remove), + .suspend = rt2x00pci_suspend, + .resume = rt2x00pci_resume, +}; + +static int __init rt2500pci_init(void) +{ + return pci_register_driver(&rt2500pci_driver); +} + +static void __exit rt2500pci_exit(void) +{ + pci_unregister_driver(&rt2500pci_driver); +} + +module_init(rt2500pci_init); +module_exit(rt2500pci_exit); diff --git a/drivers/net/wireless/rt2x00/rt2500pci.h b/drivers/net/wireless/rt2x00/rt2500pci.h new file mode 100644 index 00000000000..d92aa56b2f4 --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2500pci.h @@ -0,0 +1,1236 @@ +/* + Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the + Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + Module: rt2500pci + Abstract: Data structures and registers for the rt2500pci module. + Supported chipsets: RT2560. + */ + +#ifndef RT2500PCI_H +#define RT2500PCI_H + +/* + * RF chip defines. + */ +#define RF2522 0x0000 +#define RF2523 0x0001 +#define RF2524 0x0002 +#define RF2525 0x0003 +#define RF2525E 0x0004 +#define RF5222 0x0010 + +/* + * RT2560 version + */ +#define RT2560_VERSION_B 2 +#define RT2560_VERSION_C 3 +#define RT2560_VERSION_D 4 + +/* + * Signal information. + * Defaul offset is required for RSSI <-> dBm conversion. + */ +#define MAX_SIGNAL 100 +#define MAX_RX_SSI -1 +#define DEFAULT_RSSI_OFFSET 121 + +/* + * Register layout information. + */ +#define CSR_REG_BASE 0x0000 +#define CSR_REG_SIZE 0x0174 +#define EEPROM_BASE 0x0000 +#define EEPROM_SIZE 0x0200 +#define BBP_SIZE 0x0040 +#define RF_SIZE 0x0014 + +/* + * Control/Status Registers(CSR). + * Some values are set in TU, whereas 1 TU == 1024 us. + */ + +/* + * CSR0: ASIC revision number. + */ +#define CSR0 0x0000 + +/* + * CSR1: System control register. + * SOFT_RESET: Software reset, 1: reset, 0: normal. + * BBP_RESET: Hardware reset, 1: reset, 0, release. + * HOST_READY: Host ready after initialization. + */ +#define CSR1 0x0004 +#define CSR1_SOFT_RESET FIELD32(0x00000001) +#define CSR1_BBP_RESET FIELD32(0x00000002) +#define CSR1_HOST_READY FIELD32(0x00000004) + +/* + * CSR2: System admin status register (invalid). + */ +#define CSR2 0x0008 + +/* + * CSR3: STA MAC address register 0. + */ +#define CSR3 0x000c +#define CSR3_BYTE0 FIELD32(0x000000ff) +#define CSR3_BYTE1 FIELD32(0x0000ff00) +#define CSR3_BYTE2 FIELD32(0x00ff0000) +#define CSR3_BYTE3 FIELD32(0xff000000) + +/* + * CSR4: STA MAC address register 1. + */ +#define CSR4 0x0010 +#define CSR4_BYTE4 FIELD32(0x000000ff) +#define CSR4_BYTE5 FIELD32(0x0000ff00) + +/* + * CSR5: BSSID register 0. + */ +#define CSR5 0x0014 +#define CSR5_BYTE0 FIELD32(0x000000ff) +#define CSR5_BYTE1 FIELD32(0x0000ff00) +#define CSR5_BYTE2 FIELD32(0x00ff0000) +#define CSR5_BYTE3 FIELD32(0xff000000) + +/* + * CSR6: BSSID register 1. + */ +#define CSR6 0x0018 +#define CSR6_BYTE4 FIELD32(0x000000ff) +#define CSR6_BYTE5 FIELD32(0x0000ff00) + +/* + * CSR7: Interrupt source register. + * Write 1 to clear. + * TBCN_EXPIRE: Beacon timer expired interrupt. + * TWAKE_EXPIRE: Wakeup timer expired interrupt. + * TATIMW_EXPIRE: Timer of atim window expired interrupt. + * TXDONE_TXRING: Tx ring transmit done interrupt. + * TXDONE_ATIMRING: Atim ring transmit done interrupt. + * TXDONE_PRIORING: Priority ring transmit done interrupt. + * RXDONE: Receive done interrupt. + * DECRYPTION_DONE: Decryption done interrupt. + * ENCRYPTION_DONE: Encryption done interrupt. + * UART1_TX_TRESHOLD: UART1 TX reaches threshold. + * UART1_RX_TRESHOLD: UART1 RX reaches threshold. + * UART1_IDLE_TRESHOLD: UART1 IDLE over threshold. + * UART1_TX_BUFF_ERROR: UART1 TX buffer error. + * UART1_RX_BUFF_ERROR: UART1 RX buffer error. + * UART2_TX_TRESHOLD: UART2 TX reaches threshold. + * UART2_RX_TRESHOLD: UART2 RX reaches threshold. + * UART2_IDLE_TRESHOLD: UART2 IDLE over threshold. + * UART2_TX_BUFF_ERROR: UART2 TX buffer error. + * UART2_RX_BUFF_ERROR: UART2 RX buffer error. + * TIMER_CSR3_EXPIRE: TIMECSR3 timer expired (802.1H quiet period). + + */ +#define CSR7 0x001c +#define CSR7_TBCN_EXPIRE FIELD32(0x00000001) +#define CSR7_TWAKE_EXPIRE FIELD32(0x00000002) +#define CSR7_TATIMW_EXPIRE FIELD32(0x00000004) +#define CSR7_TXDONE_TXRING FIELD32(0x00000008) +#define CSR7_TXDONE_ATIMRING FIELD32(0x00000010) +#define CSR7_TXDONE_PRIORING FIELD32(0x00000020) +#define CSR7_RXDONE FIELD32(0x00000040) +#define CSR7_DECRYPTION_DONE FIELD32(0x00000080) +#define CSR7_ENCRYPTION_DONE FIELD32(0x00000100) +#define CSR7_UART1_TX_TRESHOLD FIELD32(0x00000200) +#define CSR7_UART1_RX_TRESHOLD FIELD32(0x00000400) +#define CSR7_UART1_IDLE_TRESHOLD FIELD32(0x00000800) +#define CSR7_UART1_TX_BUFF_ERROR FIELD32(0x00001000) +#define CSR7_UART1_RX_BUFF_ERROR FIELD32(0x00002000) +#define CSR7_UART2_TX_TRESHOLD FIELD32(0x00004000) +#define CSR7_UART2_RX_TRESHOLD FIELD32(0x00008000) +#define CSR7_UART2_IDLE_TRESHOLD FIELD32(0x00010000) +#define CSR7_UART2_TX_BUFF_ERROR FIELD32(0x00020000) +#define CSR7_UART2_RX_BUFF_ERROR FIELD32(0x00040000) +#define CSR7_TIMER_CSR3_EXPIRE FIELD32(0x00080000) + +/* + * CSR8: Interrupt mask register. + * Write 1 to mask interrupt. + * TBCN_EXPIRE: Beacon timer expired interrupt. + * TWAKE_EXPIRE: Wakeup timer expired interrupt. + * TATIMW_EXPIRE: Timer of atim window expired interrupt. + * TXDONE_TXRING: Tx ring transmit done interrupt. + * TXDONE_ATIMRING: Atim ring transmit done interrupt. + * TXDONE_PRIORING: Priority ring transmit done interrupt. + * RXDONE: Receive done interrupt. + * DECRYPTION_DONE: Decryption done interrupt. + * ENCRYPTION_DONE: Encryption done interrupt. + * UART1_TX_TRESHOLD: UART1 TX reaches threshold. + * UART1_RX_TRESHOLD: UART1 RX reaches threshold. + * UART1_IDLE_TRESHOLD: UART1 IDLE over threshold. + * UART1_TX_BUFF_ERROR: UART1 TX buffer error. + * UART1_RX_BUFF_ERROR: UART1 RX buffer error. + * UART2_TX_TRESHOLD: UART2 TX reaches threshold. + * UART2_RX_TRESHOLD: UART2 RX reaches threshold. + * UART2_IDLE_TRESHOLD: UART2 IDLE over threshold. + * UART2_TX_BUFF_ERROR: UART2 TX buffer error. + * UART2_RX_BUFF_ERROR: UART2 RX buffer error. + * TIMER_CSR3_EXPIRE: TIMECSR3 timer expired (802.1H quiet period). + */ +#define CSR8 0x0020 +#define CSR8_TBCN_EXPIRE FIELD32(0x00000001) +#define CSR8_TWAKE_EXPIRE FIELD32(0x00000002) +#define CSR8_TATIMW_EXPIRE FIELD32(0x00000004) +#define CSR8_TXDONE_TXRING FIELD32(0x00000008) +#define CSR8_TXDONE_ATIMRING FIELD32(0x00000010) +#define CSR8_TXDONE_PRIORING FIELD32(0x00000020) +#define CSR8_RXDONE FIELD32(0x00000040) +#define CSR8_DECRYPTION_DONE FIELD32(0x00000080) +#define CSR8_ENCRYPTION_DONE FIELD32(0x00000100) +#define CSR8_UART1_TX_TRESHOLD FIELD32(0x00000200) +#define CSR8_UART1_RX_TRESHOLD FIELD32(0x00000400) +#define CSR8_UART1_IDLE_TRESHOLD FIELD32(0x00000800) +#define CSR8_UART1_TX_BUFF_ERROR FIELD32(0x00001000) +#define CSR8_UART1_RX_BUFF_ERROR FIELD32(0x00002000) +#define CSR8_UART2_TX_TRESHOLD FIELD32(0x00004000) +#define CSR8_UART2_RX_TRESHOLD FIELD32(0x00008000) +#define CSR8_UART2_IDLE_TRESHOLD FIELD32(0x00010000) +#define CSR8_UART2_TX_BUFF_ERROR FIELD32(0x00020000) +#define CSR8_UART2_RX_BUFF_ERROR FIELD32(0x00040000) +#define CSR8_TIMER_CSR3_EXPIRE FIELD32(0x00080000) + +/* + * CSR9: Maximum frame length register. + * MAX_FRAME_UNIT: Maximum frame length in 128b unit, default: 12. + */ +#define CSR9 0x0024 +#define CSR9_MAX_FRAME_UNIT FIELD32(0x00000f80) + +/* + * SECCSR0: WEP control register. + * KICK_DECRYPT: Kick decryption engine, self-clear. + * ONE_SHOT: 0: ring mode, 1: One shot only mode. + * DESC_ADDRESS: Descriptor physical address of frame. + */ +#define SECCSR0 0x0028 +#define SECCSR0_KICK_DECRYPT FIELD32(0x00000001) +#define SECCSR0_ONE_SHOT FIELD32(0x00000002) +#define SECCSR0_DESC_ADDRESS FIELD32(0xfffffffc) + +/* + * CSR11: Back-off control register. + * CWMIN: CWmin. Default cwmin is 31 (2^5 - 1). + * CWMAX: CWmax. Default cwmax is 1023 (2^10 - 1). + * SLOT_TIME: Slot time, default is 20us for 802.11b + * CW_SELECT: CWmin/CWmax selection, 1: Register, 0: TXD. + * LONG_RETRY: Long retry count. + * SHORT_RETRY: Short retry count. + */ +#define CSR11 0x002c +#define CSR11_CWMIN FIELD32(0x0000000f) +#define CSR11_CWMAX FIELD32(0x000000f0) +#define CSR11_SLOT_TIME FIELD32(0x00001f00) +#define CSR11_CW_SELECT FIELD32(0x00002000) +#define CSR11_LONG_RETRY FIELD32(0x00ff0000) +#define CSR11_SHORT_RETRY FIELD32(0xff000000) + +/* + * CSR12: Synchronization configuration register 0. + * All units in 1/16 TU. + * BEACON_INTERVAL: Beacon interval, default is 100 TU. + * CFP_MAX_DURATION: Cfp maximum duration, default is 100 TU. + */ +#define CSR12 0x0030 +#define CSR12_BEACON_INTERVAL FIELD32(0x0000ffff) +#define CSR12_CFP_MAX_DURATION FIELD32(0xffff0000) + +/* + * CSR13: Synchronization configuration register 1. + * All units in 1/16 TU. + * ATIMW_DURATION: Atim window duration. + * CFP_PERIOD: Cfp period, default is 0 TU. + */ +#define CSR13 0x0034 +#define CSR13_ATIMW_DURATION FIELD32(0x0000ffff) +#define CSR13_CFP_PERIOD FIELD32(0x00ff0000) + +/* + * CSR14: Synchronization control register. + * TSF_COUNT: Enable tsf auto counting. + * TSF_SYNC: Tsf sync, 0: disable, 1: infra, 2: ad-hoc/master mode. + * TBCN: Enable tbcn with reload value. + * TCFP: Enable tcfp & cfp / cp switching. + * TATIMW: Enable tatimw & atim window switching. + * BEACON_GEN: Enable beacon generator. + * CFP_COUNT_PRELOAD: Cfp count preload value. + * TBCM_PRELOAD: Tbcn preload value in units of 64us. + */ +#define CSR14 0x0038 +#define CSR14_TSF_COUNT FIELD32(0x00000001) +#define CSR14_TSF_SYNC FIELD32(0x00000006) +#define CSR14_TBCN FIELD32(0x00000008) +#define CSR14_TCFP FIELD32(0x00000010) +#define CSR14_TATIMW FIELD32(0x00000020) +#define CSR14_BEACON_GEN FIELD32(0x00000040) +#define CSR14_CFP_COUNT_PRELOAD FIELD32(0x0000ff00) +#define CSR14_TBCM_PRELOAD FIELD32(0xffff0000) + +/* + * CSR15: Synchronization status register. + * CFP: ASIC is in contention-free period. + * ATIMW: ASIC is in ATIM window. + * BEACON_SENT: Beacon is send. + */ +#define CSR15 0x003c +#define CSR15_CFP FIELD32(0x00000001) +#define CSR15_ATIMW FIELD32(0x00000002) +#define CSR15_BEACON_SENT FIELD32(0x00000004) + +/* + * CSR16: TSF timer register 0. + */ +#define CSR16 0x0040 +#define CSR16_LOW_TSFTIMER FIELD32(0xffffffff) + +/* + * CSR17: TSF timer register 1. + */ +#define CSR17 0x0044 +#define CSR17_HIGH_TSFTIMER FIELD32(0xffffffff) + +/* + * CSR18: IFS timer register 0. + * SIFS: Sifs, default is 10 us. + * PIFS: Pifs, default is 30 us. + */ +#define CSR18 0x0048 +#define CSR18_SIFS FIELD32(0x000001ff) +#define CSR18_PIFS FIELD32(0x001f0000) + +/* + * CSR19: IFS timer register 1. + * DIFS: Difs, default is 50 us. + * EIFS: Eifs, default is 364 us. + */ +#define CSR19 0x004c +#define CSR19_DIFS FIELD32(0x0000ffff) +#define CSR19_EIFS FIELD32(0xffff0000) + +/* + * CSR20: Wakeup timer register. + * DELAY_AFTER_TBCN: Delay after tbcn expired in units of 1/16 TU. + * TBCN_BEFORE_WAKEUP: Number of beacon before wakeup. + * AUTOWAKE: Enable auto wakeup / sleep mechanism. + */ +#define CSR20 0x0050 +#define CSR20_DELAY_AFTER_TBCN FIELD32(0x0000ffff) +#define CSR20_TBCN_BEFORE_WAKEUP FIELD32(0x00ff0000) +#define CSR20_AUTOWAKE FIELD32(0x01000000) + +/* + * CSR21: EEPROM control register. + * RELOAD: Write 1 to reload eeprom content. + * TYPE_93C46: 1: 93c46, 0:93c66. + */ +#define CSR21 0x0054 +#define CSR21_RELOAD FIELD32(0x00000001) +#define CSR21_EEPROM_DATA_CLOCK FIELD32(0x00000002) +#define CSR21_EEPROM_CHIP_SELECT FIELD32(0x00000004) +#define CSR21_EEPROM_DATA_IN FIELD32(0x00000008) +#define CSR21_EEPROM_DATA_OUT FIELD32(0x00000010) +#define CSR21_TYPE_93C46 FIELD32(0x00000020) + +/* + * CSR22: CFP control register. + * CFP_DURATION_REMAIN: Cfp duration remain, in units of TU. + * RELOAD_CFP_DURATION: Write 1 to reload cfp duration remain. + */ +#define CSR22 0x0058 +#define CSR22_CFP_DURATION_REMAIN FIELD32(0x0000ffff) +#define CSR22_RELOAD_CFP_DURATION FIELD32(0x00010000) + +/* + * Transmit related CSRs. + * Some values are set in TU, whereas 1 TU == 1024 us. + */ + +/* + * TXCSR0: TX Control Register. + * KICK_TX: Kick tx ring. + * KICK_ATIM: Kick atim ring. + * KICK_PRIO: Kick priority ring. + * ABORT: Abort all transmit related ring operation. + */ +#define TXCSR0 0x0060 +#define TXCSR0_KICK_TX FIELD32(0x00000001) +#define TXCSR0_KICK_ATIM FIELD32(0x00000002) +#define TXCSR0_KICK_PRIO FIELD32(0x00000004) +#define TXCSR0_ABORT FIELD32(0x00000008) + +/* + * TXCSR1: TX Configuration Register. + * ACK_TIMEOUT: Ack timeout, default = sifs + 2*slottime + acktime @ 1mbps. + * ACK_CONSUME_TIME: Ack consume time, default = sifs + acktime @ 1mbps. + * TSF_OFFSET: Insert tsf offset. + * AUTORESPONDER: Enable auto responder which include ack & cts. + */ +#define TXCSR1 0x0064 +#define TXCSR1_ACK_TIMEOUT FIELD32(0x000001ff) +#define TXCSR1_ACK_CONSUME_TIME FIELD32(0x0003fe00) +#define TXCSR1_TSF_OFFSET FIELD32(0x00fc0000) +#define TXCSR1_AUTORESPONDER FIELD32(0x01000000) + +/* + * TXCSR2: Tx descriptor configuration register. + * TXD_SIZE: Tx descriptor size, default is 48. + * NUM_TXD: Number of tx entries in ring. + * NUM_ATIM: Number of atim entries in ring. + * NUM_PRIO: Number of priority entries in ring. + */ +#define TXCSR2 0x0068 +#define TXCSR2_TXD_SIZE FIELD32(0x000000ff) +#define TXCSR2_NUM_TXD FIELD32(0x0000ff00) +#define TXCSR2_NUM_ATIM FIELD32(0x00ff0000) +#define TXCSR2_NUM_PRIO FIELD32(0xff000000) + +/* + * TXCSR3: TX Ring Base address register. + */ +#define TXCSR3 0x006c +#define TXCSR3_TX_RING_REGISTER FIELD32(0xffffffff) + +/* + * TXCSR4: TX Atim Ring Base address register. + */ +#define TXCSR4 0x0070 +#define TXCSR4_ATIM_RING_REGISTER FIELD32(0xffffffff) + +/* + * TXCSR5: TX Prio Ring Base address register. + */ +#define TXCSR5 0x0074 +#define TXCSR5_PRIO_RING_REGISTER FIELD32(0xffffffff) + +/* + * TXCSR6: Beacon Base address register. + */ +#define TXCSR6 0x0078 +#define TXCSR6_BEACON_RING_REGISTER FIELD32(0xffffffff) + +/* + * TXCSR7: Auto responder control register. + * AR_POWERMANAGEMENT: Auto responder power management bit. + */ +#define TXCSR7 0x007c +#define TXCSR7_AR_POWERMANAGEMENT FIELD32(0x00000001) + +/* + * TXCSR8: CCK Tx BBP register. + */ +#define TXCSR8 0x0098 +#define TXCSR8_BBP_ID0 FIELD32(0x0000007f) +#define TXCSR8_BBP_ID0_VALID FIELD32(0x00000080) +#define TXCSR8_BBP_ID1 FIELD32(0x00007f00) +#define TXCSR8_BBP_ID1_VALID FIELD32(0x00008000) +#define TXCSR8_BBP_ID2 FIELD32(0x007f0000) +#define TXCSR8_BBP_ID2_VALID FIELD32(0x00800000) +#define TXCSR8_BBP_ID3 FIELD32(0x7f000000) +#define TXCSR8_BBP_ID3_VALID FIELD32(0x80000000) + +/* + * TXCSR9: OFDM TX BBP registers + * OFDM_SIGNAL: BBP rate field address for OFDM. + * OFDM_SERVICE: BBP service field address for OFDM. + * OFDM_LENGTH_LOW: BBP length low byte address for OFDM. + * OFDM_LENGTH_HIGH: BBP length high byte address for OFDM. + */ +#define TXCSR9 0x0094 +#define TXCSR9_OFDM_RATE FIELD32(0x000000ff) +#define TXCSR9_OFDM_SERVICE FIELD32(0x0000ff00) +#define TXCSR9_OFDM_LENGTH_LOW FIELD32(0x00ff0000) +#define TXCSR9_OFDM_LENGTH_HIGH FIELD32(0xff000000) + +/* + * Receive related CSRs. + * Some values are set in TU, whereas 1 TU == 1024 us. + */ + +/* + * RXCSR0: RX Control Register. + * DISABLE_RX: Disable rx engine. + * DROP_CRC: Drop crc error. + * DROP_PHYSICAL: Drop physical error. + * DROP_CONTROL: Drop control frame. + * DROP_NOT_TO_ME: Drop not to me unicast frame. + * DROP_TODS: Drop frame tods bit is true. + * DROP_VERSION_ERROR: Drop version error frame. + * PASS_CRC: Pass all packets with crc attached. + * PASS_CRC: Pass all packets with crc attached. + * PASS_PLCP: Pass all packets with 4 bytes PLCP attached. + * DROP_MCAST: Drop multicast frames. + * DROP_BCAST: Drop broadcast frames. + * ENABLE_QOS: Accept QOS data frame and parse QOS field. + */ +#define RXCSR0 0x0080 +#define RXCSR0_DISABLE_RX FIELD32(0x00000001) +#define RXCSR0_DROP_CRC FIELD32(0x00000002) +#define RXCSR0_DROP_PHYSICAL FIELD32(0x00000004) +#define RXCSR0_DROP_CONTROL FIELD32(0x00000008) +#define RXCSR0_DROP_NOT_TO_ME FIELD32(0x00000010) +#define RXCSR0_DROP_TODS FIELD32(0x00000020) +#define RXCSR0_DROP_VERSION_ERROR FIELD32(0x00000040) +#define RXCSR0_PASS_CRC FIELD32(0x00000080) +#define RXCSR0_PASS_PLCP FIELD32(0x00000100) +#define RXCSR0_DROP_MCAST FIELD32(0x00000200) +#define RXCSR0_DROP_BCAST FIELD32(0x00000400) +#define RXCSR0_ENABLE_QOS FIELD32(0x00000800) + +/* + * RXCSR1: RX descriptor configuration register. + * RXD_SIZE: Rx descriptor size, default is 32b. + * NUM_RXD: Number of rx entries in ring. + */ +#define RXCSR1 0x0084 +#define RXCSR1_RXD_SIZE FIELD32(0x000000ff) +#define RXCSR1_NUM_RXD FIELD32(0x0000ff00) + +/* + * RXCSR2: RX Ring base address register. + */ +#define RXCSR2 0x0088 +#define RXCSR2_RX_RING_REGISTER FIELD32(0xffffffff) + +/* + * RXCSR3: BBP ID register for Rx operation. + * BBP_ID#: BBP register # id. + * BBP_ID#_VALID: BBP register # id is valid or not. + */ +#define RXCSR3 0x0090 +#define RXCSR3_BBP_ID0 FIELD32(0x0000007f) +#define RXCSR3_BBP_ID0_VALID FIELD32(0x00000080) +#define RXCSR3_BBP_ID1 FIELD32(0x00007f00) +#define RXCSR3_BBP_ID1_VALID FIELD32(0x00008000) +#define RXCSR3_BBP_ID2 FIELD32(0x007f0000) +#define RXCSR3_BBP_ID2_VALID FIELD32(0x00800000) +#define RXCSR3_BBP_ID3 FIELD32(0x7f000000) +#define RXCSR3_BBP_ID3_VALID FIELD32(0x80000000) + +/* + * ARCSR1: Auto Responder PLCP config register 1. + * AR_BBP_DATA#: Auto responder BBP register # data. + * AR_BBP_ID#: Auto responder BBP register # Id. + */ +#define ARCSR1 0x009c +#define ARCSR1_AR_BBP_DATA2 FIELD32(0x000000ff) +#define ARCSR1_AR_BBP_ID2 FIELD32(0x0000ff00) +#define ARCSR1_AR_BBP_DATA3 FIELD32(0x00ff0000) +#define ARCSR1_AR_BBP_ID3 FIELD32(0xff000000) + +/* + * Miscellaneous Registers. + * Some values are set in TU, whereas 1 TU == 1024 us. + + */ + +/* + * PCICSR: PCI control register. + * BIG_ENDIAN: 1: big endian, 0: little endian. + * RX_TRESHOLD: Rx threshold in dw to start pci access + * 0: 16dw (default), 1: 8dw, 2: 4dw, 3: 32dw. + * TX_TRESHOLD: Tx threshold in dw to start pci access + * 0: 0dw (default), 1: 1dw, 2: 4dw, 3: forward. + * BURST_LENTH: Pci burst length 0: 4dw (default, 1: 8dw, 2: 16dw, 3:32dw. + * ENABLE_CLK: Enable clk_run, pci clock can't going down to non-operational. + * READ_MULTIPLE: Enable memory read multiple. + * WRITE_INVALID: Enable memory write & invalid. + */ +#define PCICSR 0x008c +#define PCICSR_BIG_ENDIAN FIELD32(0x00000001) +#define PCICSR_RX_TRESHOLD FIELD32(0x00000006) +#define PCICSR_TX_TRESHOLD FIELD32(0x00000018) +#define PCICSR_BURST_LENTH FIELD32(0x00000060) +#define PCICSR_ENABLE_CLK FIELD32(0x00000080) +#define PCICSR_READ_MULTIPLE FIELD32(0x00000100) +#define PCICSR_WRITE_INVALID FIELD32(0x00000200) + +/* + * CNT0: FCS error count. + * FCS_ERROR: FCS error count, cleared when read. + */ +#define CNT0 0x00a0 +#define CNT0_FCS_ERROR FIELD32(0x0000ffff) + +/* + * Statistic Register. + * CNT1: PLCP error count. + * CNT2: Long error count. + */ +#define TIMECSR2 0x00a8 +#define CNT1 0x00ac +#define CNT2 0x00b0 +#define TIMECSR3 0x00b4 + +/* + * CNT3: CCA false alarm count. + */ +#define CNT3 0x00b8 +#define CNT3_FALSE_CCA FIELD32(0x0000ffff) + +/* + * Statistic Register. + * CNT4: Rx FIFO overflow count. + * CNT5: Tx FIFO underrun count. + */ +#define CNT4 0x00bc +#define CNT5 0x00c0 + +/* + * Baseband Control Register. + */ + +/* + * PWRCSR0: Power mode configuration register. + */ +#define PWRCSR0 0x00c4 + +/* + * Power state transition time registers. + */ +#define PSCSR0 0x00c8 +#define PSCSR1 0x00cc +#define PSCSR2 0x00d0 +#define PSCSR3 0x00d4 + +/* + * PWRCSR1: Manual power control / status register. + * Allowed state: 0 deep_sleep, 1: sleep, 2: standby, 3: awake. + * SET_STATE: Set state. Write 1 to trigger, self cleared. + * BBP_DESIRE_STATE: BBP desired state. + * RF_DESIRE_STATE: RF desired state. + * BBP_CURR_STATE: BBP current state. + * RF_CURR_STATE: RF current state. + * PUT_TO_SLEEP: Put to sleep. Write 1 to trigger, self cleared. + */ +#define PWRCSR1 0x00d8 +#define PWRCSR1_SET_STATE FIELD32(0x00000001) +#define PWRCSR1_BBP_DESIRE_STATE FIELD32(0x00000006) +#define PWRCSR1_RF_DESIRE_STATE FIELD32(0x00000018) +#define PWRCSR1_BBP_CURR_STATE FIELD32(0x00000060) +#define PWRCSR1_RF_CURR_STATE FIELD32(0x00000180) +#define PWRCSR1_PUT_TO_SLEEP FIELD32(0x00000200) + +/* + * TIMECSR: Timer control register. + * US_COUNT: 1 us timer count in units of clock cycles. + * US_64_COUNT: 64 us timer count in units of 1 us timer. + * BEACON_EXPECT: Beacon expect window. + */ +#define TIMECSR 0x00dc +#define TIMECSR_US_COUNT FIELD32(0x000000ff) +#define TIMECSR_US_64_COUNT FIELD32(0x0000ff00) +#define TIMECSR_BEACON_EXPECT FIELD32(0x00070000) + +/* + * MACCSR0: MAC configuration register 0. + */ +#define MACCSR0 0x00e0 + +/* + * MACCSR1: MAC configuration register 1. + * KICK_RX: Kick one-shot rx in one-shot rx mode. + * ONESHOT_RXMODE: Enable one-shot rx mode for debugging. + * BBPRX_RESET_MODE: Ralink bbp rx reset mode. + * AUTO_TXBBP: Auto tx logic access bbp control register. + * AUTO_RXBBP: Auto rx logic access bbp control register. + * LOOPBACK: Loopback mode. 0: normal, 1: internal, 2: external, 3:rsvd. + * INTERSIL_IF: Intersil if calibration pin. + */ +#define MACCSR1 0x00e4 +#define MACCSR1_KICK_RX FIELD32(0x00000001) +#define MACCSR1_ONESHOT_RXMODE FIELD32(0x00000002) +#define MACCSR1_BBPRX_RESET_MODE FIELD32(0x00000004) +#define MACCSR1_AUTO_TXBBP FIELD32(0x00000008) +#define MACCSR1_AUTO_RXBBP FIELD32(0x00000010) +#define MACCSR1_LOOPBACK FIELD32(0x00000060) +#define MACCSR1_INTERSIL_IF FIELD32(0x00000080) + +/* + * RALINKCSR: Ralink Rx auto-reset BBCR. + * AR_BBP_DATA#: Auto reset BBP register # data. + * AR_BBP_ID#: Auto reset BBP register # id. + */ +#define RALINKCSR 0x00e8 +#define RALINKCSR_AR_BBP_DATA0 FIELD32(0x000000ff) +#define RALINKCSR_AR_BBP_ID0 FIELD32(0x00007f00) +#define RALINKCSR_AR_BBP_VALID0 FIELD32(0x00008000) +#define RALINKCSR_AR_BBP_DATA1 FIELD32(0x00ff0000) +#define RALINKCSR_AR_BBP_ID1 FIELD32(0x7f000000) +#define RALINKCSR_AR_BBP_VALID1 FIELD32(0x80000000) + +/* + * BCNCSR: Beacon interval control register. + * CHANGE: Write one to change beacon interval. + * DELTATIME: The delta time value. + * NUM_BEACON: Number of beacon according to mode. + * MODE: Please refer to asic specs. + * PLUS: Plus or minus delta time value. + */ +#define BCNCSR 0x00ec +#define BCNCSR_CHANGE FIELD32(0x00000001) +#define BCNCSR_DELTATIME FIELD32(0x0000001e) +#define BCNCSR_NUM_BEACON FIELD32(0x00001fe0) +#define BCNCSR_MODE FIELD32(0x00006000) +#define BCNCSR_PLUS FIELD32(0x00008000) + +/* + * BBP / RF / IF Control Register. + */ + +/* + * BBPCSR: BBP serial control register. + * VALUE: Register value to program into BBP. + * REGNUM: Selected BBP register. + * BUSY: 1: asic is busy execute BBP programming. + * WRITE_CONTROL: 1: write BBP, 0: read BBP. + */ +#define BBPCSR 0x00f0 +#define BBPCSR_VALUE FIELD32(0x000000ff) +#define BBPCSR_REGNUM FIELD32(0x00007f00) +#define BBPCSR_BUSY FIELD32(0x00008000) +#define BBPCSR_WRITE_CONTROL FIELD32(0x00010000) + +/* + * RFCSR: RF serial control register. + * VALUE: Register value + id to program into rf/if. + * NUMBER_OF_BITS: Number of bits used in value (i:20, rfmd:22). + * IF_SELECT: Chip to program: 0: rf, 1: if. + * PLL_LD: Rf pll_ld status. + * BUSY: 1: asic is busy execute rf programming. + */ +#define RFCSR 0x00f4 +#define RFCSR_VALUE FIELD32(0x00ffffff) +#define RFCSR_NUMBER_OF_BITS FIELD32(0x1f000000) +#define RFCSR_IF_SELECT FIELD32(0x20000000) +#define RFCSR_PLL_LD FIELD32(0x40000000) +#define RFCSR_BUSY FIELD32(0x80000000) + +/* + * LEDCSR: LED control register. + * ON_PERIOD: On period, default 70ms. + * OFF_PERIOD: Off period, default 30ms. + * LINK: 0: linkoff, 1: linkup. + * ACTIVITY: 0: idle, 1: active. + * LINK_POLARITY: 0: active low, 1: active high. + * ACTIVITY_POLARITY: 0: active low, 1: active high. + * LED_DEFAULT: LED state for "enable" 0: ON, 1: OFF. + */ +#define LEDCSR 0x00f8 +#define LEDCSR_ON_PERIOD FIELD32(0x000000ff) +#define LEDCSR_OFF_PERIOD FIELD32(0x0000ff00) +#define LEDCSR_LINK FIELD32(0x00010000) +#define LEDCSR_ACTIVITY FIELD32(0x00020000) +#define LEDCSR_LINK_POLARITY FIELD32(0x00040000) +#define LEDCSR_ACTIVITY_POLARITY FIELD32(0x00080000) +#define LEDCSR_LED_DEFAULT FIELD32(0x00100000) + +/* + * AES control register. + */ +#define SECCSR3 0x00fc + +/* + * ASIC pointer information. + * RXPTR: Current RX ring address. + * TXPTR: Current Tx ring address. + * PRIPTR: Current Priority ring address. + * ATIMPTR: Current ATIM ring address. + */ +#define RXPTR 0x0100 +#define TXPTR 0x0104 +#define PRIPTR 0x0108 +#define ATIMPTR 0x010c + +/* + * TXACKCSR0: TX ACK timeout. + */ +#define TXACKCSR0 0x0110 + +/* + * ACK timeout count registers. + * ACKCNT0: TX ACK timeout count. + * ACKCNT1: RX ACK timeout count. + */ +#define ACKCNT0 0x0114 +#define ACKCNT1 0x0118 + +/* + * GPIO and others. + */ + +/* + * GPIOCSR: GPIO control register. + */ +#define GPIOCSR 0x0120 +#define GPIOCSR_BIT0 FIELD32(0x00000001) +#define GPIOCSR_BIT1 FIELD32(0x00000002) +#define GPIOCSR_BIT2 FIELD32(0x00000004) +#define GPIOCSR_BIT3 FIELD32(0x00000008) +#define GPIOCSR_BIT4 FIELD32(0x00000010) +#define GPIOCSR_BIT5 FIELD32(0x00000020) +#define GPIOCSR_BIT6 FIELD32(0x00000040) +#define GPIOCSR_BIT7 FIELD32(0x00000080) +#define GPIOCSR_DIR0 FIELD32(0x00000100) +#define GPIOCSR_DIR1 FIELD32(0x00000200) +#define GPIOCSR_DIR2 FIELD32(0x00000400) +#define GPIOCSR_DIR3 FIELD32(0x00000800) +#define GPIOCSR_DIR4 FIELD32(0x00001000) +#define GPIOCSR_DIR5 FIELD32(0x00002000) +#define GPIOCSR_DIR6 FIELD32(0x00004000) +#define GPIOCSR_DIR7 FIELD32(0x00008000) + +/* + * FIFO pointer registers. + * FIFOCSR0: TX FIFO pointer. + * FIFOCSR1: RX FIFO pointer. + */ +#define FIFOCSR0 0x0128 +#define FIFOCSR1 0x012c + +/* + * BCNCSR1: Tx BEACON offset time control register. + * PRELOAD: Beacon timer offset in units of usec. + * BEACON_CWMIN: 2^CwMin. + */ +#define BCNCSR1 0x0130 +#define BCNCSR1_PRELOAD FIELD32(0x0000ffff) +#define BCNCSR1_BEACON_CWMIN FIELD32(0x000f0000) + +/* + * MACCSR2: TX_PE to RX_PE turn-around time control register + * DELAY: RX_PE low width, in units of pci clock cycle. + */ +#define MACCSR2 0x0134 +#define MACCSR2_DELAY FIELD32(0x000000ff) + +/* + * TESTCSR: TEST mode selection register. + */ +#define TESTCSR 0x0138 + +/* + * ARCSR2: 1 Mbps ACK/CTS PLCP. + */ +#define ARCSR2 0x013c +#define ARCSR2_SIGNAL FIELD32(0x000000ff) +#define ARCSR2_SERVICE FIELD32(0x0000ff00) +#define ARCSR2_LENGTH FIELD32(0xffff0000) + +/* + * ARCSR3: 2 Mbps ACK/CTS PLCP. + */ +#define ARCSR3 0x0140 +#define ARCSR3_SIGNAL FIELD32(0x000000ff) +#define ARCSR3_SERVICE FIELD32(0x0000ff00) +#define ARCSR3_LENGTH FIELD32(0xffff0000) + +/* + * ARCSR4: 5.5 Mbps ACK/CTS PLCP. + */ +#define ARCSR4 0x0144 +#define ARCSR4_SIGNAL FIELD32(0x000000ff) +#define ARCSR4_SERVICE FIELD32(0x0000ff00) +#define ARCSR4_LENGTH FIELD32(0xffff0000) + +/* + * ARCSR5: 11 Mbps ACK/CTS PLCP. + */ +#define ARCSR5 0x0148 +#define ARCSR5_SIGNAL FIELD32(0x000000ff) +#define ARCSR5_SERVICE FIELD32(0x0000ff00) +#define ARCSR5_LENGTH FIELD32(0xffff0000) + +/* + * ARTCSR0: CCK ACK/CTS payload consumed time for 1/2/5.5/11 mbps. + */ +#define ARTCSR0 0x014c +#define ARTCSR0_ACK_CTS_11MBS FIELD32(0x000000ff) +#define ARTCSR0_ACK_CTS_5_5MBS FIELD32(0x0000ff00) +#define ARTCSR0_ACK_CTS_2MBS FIELD32(0x00ff0000) +#define ARTCSR0_ACK_CTS_1MBS FIELD32(0xff000000) + + +/* + * ARTCSR1: OFDM ACK/CTS payload consumed time for 6/9/12/18 mbps. + */ +#define ARTCSR1 0x0150 +#define ARTCSR1_ACK_CTS_6MBS FIELD32(0x000000ff) +#define ARTCSR1_ACK_CTS_9MBS FIELD32(0x0000ff00) +#define ARTCSR1_ACK_CTS_12MBS FIELD32(0x00ff0000) +#define ARTCSR1_ACK_CTS_18MBS FIELD32(0xff000000) + +/* + * ARTCSR2: OFDM ACK/CTS payload consumed time for 24/36/48/54 mbps. + */ +#define ARTCSR2 0x0154 +#define ARTCSR2_ACK_CTS_24MBS FIELD32(0x000000ff) +#define ARTCSR2_ACK_CTS_36MBS FIELD32(0x0000ff00) +#define ARTCSR2_ACK_CTS_48MBS FIELD32(0x00ff0000) +#define ARTCSR2_ACK_CTS_54MBS FIELD32(0xff000000) + +/* + * SECCSR1_RT2509: WEP control register. + * KICK_ENCRYPT: Kick encryption engine, self-clear. + * ONE_SHOT: 0: ring mode, 1: One shot only mode. + * DESC_ADDRESS: Descriptor physical address of frame. + */ +#define SECCSR1 0x0158 +#define SECCSR1_KICK_ENCRYPT FIELD32(0x00000001) +#define SECCSR1_ONE_SHOT FIELD32(0x00000002) +#define SECCSR1_DESC_ADDRESS FIELD32(0xfffffffc) + +/* + * BBPCSR1: BBP TX configuration. + */ +#define BBPCSR1 0x015c +#define BBPCSR1_CCK FIELD32(0x00000003) +#define BBPCSR1_CCK_FLIP FIELD32(0x00000004) +#define BBPCSR1_OFDM FIELD32(0x00030000) +#define BBPCSR1_OFDM_FLIP FIELD32(0x00040000) + +/* + * Dual band configuration registers. + * DBANDCSR0: Dual band configuration register 0. + * DBANDCSR1: Dual band configuration register 1. + */ +#define DBANDCSR0 0x0160 +#define DBANDCSR1 0x0164 + +/* + * BBPPCSR: BBP Pin control register. + */ +#define BBPPCSR 0x0168 + +/* + * MAC special debug mode selection registers. + * DBGSEL0: MAC special debug mode selection register 0. + * DBGSEL1: MAC special debug mode selection register 1. + */ +#define DBGSEL0 0x016c +#define DBGSEL1 0x0170 + +/* + * BISTCSR: BBP BIST register. + */ +#define BISTCSR 0x0174 + +/* + * Multicast filter registers. + * MCAST0: Multicast filter register 0. + * MCAST1: Multicast filter register 1. + */ +#define MCAST0 0x0178 +#define MCAST1 0x017c + +/* + * UART registers. + * UARTCSR0: UART1 TX register. + * UARTCSR1: UART1 RX register. + * UARTCSR3: UART1 frame control register. + * UARTCSR4: UART1 buffer control register. + * UART2CSR0: UART2 TX register. + * UART2CSR1: UART2 RX register. + * UART2CSR3: UART2 frame control register. + * UART2CSR4: UART2 buffer control register. + */ +#define UARTCSR0 0x0180 +#define UARTCSR1 0x0184 +#define UARTCSR3 0x0188 +#define UARTCSR4 0x018c +#define UART2CSR0 0x0190 +#define UART2CSR1 0x0194 +#define UART2CSR3 0x0198 +#define UART2CSR4 0x019c + +/* + * BBP registers. + * The wordsize of the BBP is 8 bits. + */ + +/* + * R2: TX antenna control + */ +#define BBP_R2_TX_ANTENNA FIELD8(0x03) +#define BBP_R2_TX_IQ_FLIP FIELD8(0x04) + +/* + * R14: RX antenna control + */ +#define BBP_R14_RX_ANTENNA FIELD8(0x03) +#define BBP_R14_RX_IQ_FLIP FIELD8(0x04) + +/* + * BBP_R70 + */ +#define BBP_R70_JAPAN_FILTER FIELD8(0x08) + +/* + * RF registers + */ + +/* + * RF 1 + */ +#define RF1_TUNER FIELD32(0x00020000) + +/* + * RF 3 + */ +#define RF3_TUNER FIELD32(0x00000100) +#define RF3_TXPOWER FIELD32(0x00003e00) + +/* + * EEPROM content. + * The wordsize of the EEPROM is 16 bits. + */ + +/* + * HW MAC address. + */ +#define EEPROM_MAC_ADDR_0 0x0002 +#define EEPROM_MAC_ADDR_BYTE0 FIELD16(0x00ff) +#define EEPROM_MAC_ADDR_BYTE1 FIELD16(0xff00) +#define EEPROM_MAC_ADDR1 0x0003 +#define EEPROM_MAC_ADDR_BYTE2 FIELD16(0x00ff) +#define EEPROM_MAC_ADDR_BYTE3 FIELD16(0xff00) +#define EEPROM_MAC_ADDR_2 0x0004 +#define EEPROM_MAC_ADDR_BYTE4 FIELD16(0x00ff) +#define EEPROM_MAC_ADDR_BYTE5 FIELD16(0xff00) + +/* + * EEPROM antenna. + * ANTENNA_NUM: Number of antenna's. + * TX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B. + * RX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B. + * LED_MODE: 0: default, 1: TX/RX activity,2: Single (ignore link), 3: rsvd. + * DYN_TXAGC: Dynamic TX AGC control. + * HARDWARE_RADIO: 1: Hardware controlled radio. Read GPIO0. + * RF_TYPE: Rf_type of this adapter. + */ +#define EEPROM_ANTENNA 0x10 +#define EEPROM_ANTENNA_NUM FIELD16(0x0003) +#define EEPROM_ANTENNA_TX_DEFAULT FIELD16(0x000c) +#define EEPROM_ANTENNA_RX_DEFAULT FIELD16(0x0030) +#define EEPROM_ANTENNA_LED_MODE FIELD16(0x01c0) +#define EEPROM_ANTENNA_DYN_TXAGC FIELD16(0x0200) +#define EEPROM_ANTENNA_HARDWARE_RADIO FIELD16(0x0400) +#define EEPROM_ANTENNA_RF_TYPE FIELD16(0xf800) + +/* + * EEPROM NIC config. + * CARDBUS_ACCEL: 0: enable, 1: disable. + * DYN_BBP_TUNE: 0: enable, 1: disable. + * CCK_TX_POWER: CCK TX power compensation. + */ +#define EEPROM_NIC 0x11 +#define EEPROM_NIC_CARDBUS_ACCEL FIELD16(0x0001) +#define EEPROM_NIC_DYN_BBP_TUNE FIELD16(0x0002) +#define EEPROM_NIC_CCK_TX_POWER FIELD16(0x000c) + +/* + * EEPROM geography. + * GEO: Default geography setting for device. + */ +#define EEPROM_GEOGRAPHY 0x12 +#define EEPROM_GEOGRAPHY_GEO FIELD16(0x0f00) + +/* + * EEPROM BBP. + */ +#define EEPROM_BBP_START 0x13 +#define EEPROM_BBP_SIZE 16 +#define EEPROM_BBP_VALUE FIELD16(0x00ff) +#define EEPROM_BBP_REG_ID FIELD16(0xff00) + +/* + * EEPROM TXPOWER + */ +#define EEPROM_TXPOWER_START 0x23 +#define EEPROM_TXPOWER_SIZE 7 +#define EEPROM_TXPOWER_1 FIELD16(0x00ff) +#define EEPROM_TXPOWER_2 FIELD16(0xff00) + +/* + * RSSI <-> dBm offset calibration + */ +#define EEPROM_CALIBRATE_OFFSET 0x3e +#define EEPROM_CALIBRATE_OFFSET_RSSI FIELD16(0x00ff) + +/* + * DMA descriptor defines. + */ +#define TXD_DESC_SIZE ( 11 * sizeof(struct data_desc) ) +#define RXD_DESC_SIZE ( 11 * sizeof(struct data_desc) ) + +/* + * TX descriptor format for TX, PRIO, ATIM and Beacon Ring. + */ + +/* + * Word0 + */ +#define TXD_W0_OWNER_NIC FIELD32(0x00000001) +#define TXD_W0_VALID FIELD32(0x00000002) +#define TXD_W0_RESULT FIELD32(0x0000001c) +#define TXD_W0_RETRY_COUNT FIELD32(0x000000e0) +#define TXD_W0_MORE_FRAG FIELD32(0x00000100) +#define TXD_W0_ACK FIELD32(0x00000200) +#define TXD_W0_TIMESTAMP FIELD32(0x00000400) +#define TXD_W0_OFDM FIELD32(0x00000800) +#define TXD_W0_CIPHER_OWNER FIELD32(0x00001000) +#define TXD_W0_IFS FIELD32(0x00006000) +#define TXD_W0_RETRY_MODE FIELD32(0x00008000) +#define TXD_W0_DATABYTE_COUNT FIELD32(0x0fff0000) +#define TXD_W0_CIPHER_ALG FIELD32(0xe0000000) + +/* + * Word1 + */ +#define TXD_W1_BUFFER_ADDRESS FIELD32(0xffffffff) + +/* + * Word2 + */ +#define TXD_W2_IV_OFFSET FIELD32(0x0000003f) +#define TXD_W2_AIFS FIELD32(0x000000c0) +#define TXD_W2_CWMIN FIELD32(0x00000f00) +#define TXD_W2_CWMAX FIELD32(0x0000f000) + +/* + * Word3: PLCP information + */ +#define TXD_W3_PLCP_SIGNAL FIELD32(0x000000ff) +#define TXD_W3_PLCP_SERVICE FIELD32(0x0000ff00) +#define TXD_W3_PLCP_LENGTH_LOW FIELD32(0x00ff0000) +#define TXD_W3_PLCP_LENGTH_HIGH FIELD32(0xff000000) + +/* + * Word4 + */ +#define TXD_W4_IV FIELD32(0xffffffff) + +/* + * Word5 + */ +#define TXD_W5_EIV FIELD32(0xffffffff) + +/* + * Word6-9: Key + */ +#define TXD_W6_KEY FIELD32(0xffffffff) +#define TXD_W7_KEY FIELD32(0xffffffff) +#define TXD_W8_KEY FIELD32(0xffffffff) +#define TXD_W9_KEY FIELD32(0xffffffff) + +/* + * Word10 + */ +#define TXD_W10_RTS FIELD32(0x00000001) +#define TXD_W10_TX_RATE FIELD32(0x000000fe) + +/* + * RX descriptor format for RX Ring. + */ + +/* + * Word0 + */ +#define RXD_W0_OWNER_NIC FIELD32(0x00000001) +#define RXD_W0_UNICAST_TO_ME FIELD32(0x00000002) +#define RXD_W0_MULTICAST FIELD32(0x00000004) +#define RXD_W0_BROADCAST FIELD32(0x00000008) +#define RXD_W0_MY_BSS FIELD32(0x00000010) +#define RXD_W0_CRC_ERROR FIELD32(0x00000020) +#define RXD_W0_OFDM FIELD32(0x00000040) +#define RXD_W0_PHYSICAL_ERROR FIELD32(0x00000080) +#define RXD_W0_CIPHER_OWNER FIELD32(0x00000100) +#define RXD_W0_ICV_ERROR FIELD32(0x00000200) +#define RXD_W0_IV_OFFSET FIELD32(0x0000fc00) +#define RXD_W0_DATABYTE_COUNT FIELD32(0x0fff0000) +#define RXD_W0_CIPHER_ALG FIELD32(0xe0000000) + +/* + * Word1 + */ +#define RXD_W1_BUFFER_ADDRESS FIELD32(0xffffffff) + +/* + * Word2 + */ +#define RXD_W2_SIGNAL FIELD32(0x000000ff) +#define RXD_W2_RSSI FIELD32(0x0000ff00) +#define RXD_W2_TA FIELD32(0xffff0000) + +/* + * Word3 + */ +#define RXD_W3_TA FIELD32(0xffffffff) + +/* + * Word4 + */ +#define RXD_W4_IV FIELD32(0xffffffff) + +/* + * Word5 + */ +#define RXD_W5_EIV FIELD32(0xffffffff) + +/* + * Word6-9: Key + */ +#define RXD_W6_KEY FIELD32(0xffffffff) +#define RXD_W7_KEY FIELD32(0xffffffff) +#define RXD_W8_KEY FIELD32(0xffffffff) +#define RXD_W9_KEY FIELD32(0xffffffff) + +/* + * Word10 + */ +#define RXD_W10_DROP FIELD32(0x00000001) + +/* + * Macro's for converting txpower from EEPROM to dscape value + * and from dscape value to register value. + */ +#define MIN_TXPOWER 0 +#define MAX_TXPOWER 31 +#define DEFAULT_TXPOWER 24 + +#define TXPOWER_FROM_DEV(__txpower) \ +({ \ + ((__txpower) > MAX_TXPOWER) ? \ + DEFAULT_TXPOWER : (__txpower); \ +}) + +#define TXPOWER_TO_DEV(__txpower) \ +({ \ + ((__txpower) <= MIN_TXPOWER) ? MIN_TXPOWER : \ + (((__txpower) >= MAX_TXPOWER) ? MAX_TXPOWER : \ + (__txpower)); \ +}) + +#endif /* RT2500PCI_H */ diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c new file mode 100644 index 00000000000..847bd7f58ee --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -0,0 +1,1837 @@ +/* + Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the + Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + Module: rt2500usb + Abstract: rt2500usb device specific routines. + Supported chipsets: RT2570. + */ + +/* + * Set enviroment defines for rt2x00.h + */ +#define DRV_NAME "rt2500usb" + +#include +#include +#include +#include +#include +#include + +#include "rt2x00.h" +#include "rt2x00usb.h" +#include "rt2500usb.h" + +/* + * Register access. + * All access to the CSR registers will go through the methods + * rt2500usb_register_read and rt2500usb_register_write. + * BBP and RF register require indirect register access, + * and use the CSR registers BBPCSR and RFCSR to achieve this. + * These indirect registers work with busy bits, + * and we will try maximal REGISTER_BUSY_COUNT times to access + * the register while taking a REGISTER_BUSY_DELAY us delay + * between each attampt. When the busy bit is still set at that time, + * the access attempt is considered to have failed, + * and we will print an error. + */ +static inline void rt2500usb_register_read(const struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + u16 *value) +{ + __le16 reg; + rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ, + USB_VENDOR_REQUEST_IN, offset, + ®, sizeof(u16), REGISTER_TIMEOUT); + *value = le16_to_cpu(reg); +} + +static inline void rt2500usb_register_multiread(const struct rt2x00_dev + *rt2x00dev, + const unsigned int offset, + void *value, const u16 length) +{ + int timeout = REGISTER_TIMEOUT * (length / sizeof(u16)); + rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ, + USB_VENDOR_REQUEST_IN, offset, + value, length, timeout); +} + +static inline void rt2500usb_register_write(const struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + u16 value) +{ + __le16 reg = cpu_to_le16(value); + rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE, + USB_VENDOR_REQUEST_OUT, offset, + ®, sizeof(u16), REGISTER_TIMEOUT); +} + +static inline void rt2500usb_register_multiwrite(const struct rt2x00_dev + *rt2x00dev, + const unsigned int offset, + void *value, const u16 length) +{ + int timeout = REGISTER_TIMEOUT * (length / sizeof(u16)); + rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE, + USB_VENDOR_REQUEST_OUT, offset, + value, length, timeout); +} + +static u16 rt2500usb_bbp_check(const struct rt2x00_dev *rt2x00dev) +{ + u16 reg; + unsigned int i; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2500usb_register_read(rt2x00dev, PHY_CSR8, ®); + if (!rt2x00_get_field16(reg, PHY_CSR8_BUSY)) + break; + udelay(REGISTER_BUSY_DELAY); + } + + return reg; +} + +static void rt2500usb_bbp_write(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, const u8 value) +{ + u16 reg; + + /* + * Wait until the BBP becomes ready. + */ + reg = rt2500usb_bbp_check(rt2x00dev); + if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) { + ERROR(rt2x00dev, "PHY_CSR8 register busy. Write failed.\n"); + return; + } + + /* + * Write the data into the BBP. + */ + reg = 0; + rt2x00_set_field16(®, PHY_CSR7_DATA, value); + rt2x00_set_field16(®, PHY_CSR7_REG_ID, word); + rt2x00_set_field16(®, PHY_CSR7_READ_CONTROL, 0); + + rt2500usb_register_write(rt2x00dev, PHY_CSR7, reg); +} + +static void rt2500usb_bbp_read(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, u8 *value) +{ + u16 reg; + + /* + * Wait until the BBP becomes ready. + */ + reg = rt2500usb_bbp_check(rt2x00dev); + if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) { + ERROR(rt2x00dev, "PHY_CSR8 register busy. Read failed.\n"); + return; + } + + /* + * Write the request into the BBP. + */ + reg = 0; + rt2x00_set_field16(®, PHY_CSR7_REG_ID, word); + rt2x00_set_field16(®, PHY_CSR7_READ_CONTROL, 1); + + rt2500usb_register_write(rt2x00dev, PHY_CSR7, reg); + + /* + * Wait until the BBP becomes ready. + */ + reg = rt2500usb_bbp_check(rt2x00dev); + if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) { + ERROR(rt2x00dev, "PHY_CSR8 register busy. Read failed.\n"); + *value = 0xff; + return; + } + + rt2500usb_register_read(rt2x00dev, PHY_CSR7, ®); + *value = rt2x00_get_field16(reg, PHY_CSR7_DATA); +} + +static void rt2500usb_rf_write(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, const u32 value) +{ + u16 reg; + unsigned int i; + + if (!word) + return; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2500usb_register_read(rt2x00dev, PHY_CSR10, ®); + if (!rt2x00_get_field16(reg, PHY_CSR10_RF_BUSY)) + goto rf_write; + udelay(REGISTER_BUSY_DELAY); + } + + ERROR(rt2x00dev, "PHY_CSR10 register busy. Write failed.\n"); + return; + +rf_write: + reg = 0; + rt2x00_set_field16(®, PHY_CSR9_RF_VALUE, value); + rt2500usb_register_write(rt2x00dev, PHY_CSR9, reg); + + reg = 0; + rt2x00_set_field16(®, PHY_CSR10_RF_VALUE, value >> 16); + rt2x00_set_field16(®, PHY_CSR10_RF_NUMBER_OF_BITS, 20); + rt2x00_set_field16(®, PHY_CSR10_RF_IF_SELECT, 0); + rt2x00_set_field16(®, PHY_CSR10_RF_BUSY, 1); + + rt2500usb_register_write(rt2x00dev, PHY_CSR10, reg); + rt2x00_rf_write(rt2x00dev, word, value); +} + +#ifdef CONFIG_RT2X00_LIB_DEBUGFS +#define CSR_OFFSET(__word) ( CSR_REG_BASE + ((__word) * sizeof(u16)) ) + +static void rt2500usb_read_csr(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, u32 *data) +{ + rt2500usb_register_read(rt2x00dev, CSR_OFFSET(word), (u16 *) data); +} + +static void rt2500usb_write_csr(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, u32 data) +{ + rt2500usb_register_write(rt2x00dev, CSR_OFFSET(word), data); +} + +static const struct rt2x00debug rt2500usb_rt2x00debug = { + .owner = THIS_MODULE, + .csr = { + .read = rt2500usb_read_csr, + .write = rt2500usb_write_csr, + .word_size = sizeof(u16), + .word_count = CSR_REG_SIZE / sizeof(u16), + }, + .eeprom = { + .read = rt2x00_eeprom_read, + .write = rt2x00_eeprom_write, + .word_size = sizeof(u16), + .word_count = EEPROM_SIZE / sizeof(u16), + }, + .bbp = { + .read = rt2500usb_bbp_read, + .write = rt2500usb_bbp_write, + .word_size = sizeof(u8), + .word_count = BBP_SIZE / sizeof(u8), + }, + .rf = { + .read = rt2x00_rf_read, + .write = rt2500usb_rf_write, + .word_size = sizeof(u32), + .word_count = RF_SIZE / sizeof(u32), + }, +}; +#endif /* CONFIG_RT2X00_LIB_DEBUGFS */ + +/* + * Configuration handlers. + */ +static void rt2500usb_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *addr) +{ + __le16 reg[3]; + + memset(®, 0, sizeof(reg)); + memcpy(®, addr, ETH_ALEN); + + /* + * The MAC address is passed to us as an array of bytes, + * that array is little endian, so no need for byte ordering. + */ + rt2500usb_register_multiwrite(rt2x00dev, MAC_CSR2, ®, sizeof(reg)); +} + +static void rt2500usb_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) +{ + __le16 reg[3]; + + memset(®, 0, sizeof(reg)); + memcpy(®, bssid, ETH_ALEN); + + /* + * The BSSID is passed to us as an array of bytes, + * that array is little endian, so no need for byte ordering. + */ + rt2500usb_register_multiwrite(rt2x00dev, MAC_CSR5, ®, sizeof(reg)); +} + +static void rt2500usb_config_packet_filter(struct rt2x00_dev *rt2x00dev, + const unsigned int filter) +{ + int promisc = !!(filter & IFF_PROMISC); + int multicast = !!(filter & IFF_MULTICAST); + int broadcast = !!(filter & IFF_BROADCAST); + u16 reg; + + rt2500usb_register_read(rt2x00dev, TXRX_CSR2, ®); + rt2x00_set_field16(®, TXRX_CSR2_DROP_NOT_TO_ME, !promisc); + rt2x00_set_field16(®, TXRX_CSR2_DROP_MULTICAST, !multicast); + rt2x00_set_field16(®, TXRX_CSR2_DROP_BROADCAST, !broadcast); + rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg); +} + +static void rt2500usb_config_type(struct rt2x00_dev *rt2x00dev, const int type) +{ + u16 reg; + + rt2500usb_register_write(rt2x00dev, TXRX_CSR19, 0); + + /* + * Apply hardware packet filter. + */ + rt2500usb_register_read(rt2x00dev, TXRX_CSR2, ®); + + if (!is_monitor_present(&rt2x00dev->interface) && + (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_STA)) + rt2x00_set_field16(®, TXRX_CSR2_DROP_TODS, 1); + else + rt2x00_set_field16(®, TXRX_CSR2_DROP_TODS, 0); + + /* + * If there is a non-monitor interface present + * the packet should be strict (even if a monitor interface is present!). + * When there is only 1 interface present which is in monitor mode + * we should start accepting _all_ frames. + */ + if (is_interface_present(&rt2x00dev->interface)) { + rt2x00_set_field16(®, TXRX_CSR2_DROP_CRC, 1); + rt2x00_set_field16(®, TXRX_CSR2_DROP_PHYSICAL, 1); + rt2x00_set_field16(®, TXRX_CSR2_DROP_CONTROL, 1); + rt2x00_set_field16(®, TXRX_CSR2_DROP_VERSION_ERROR, 1); + } else if (is_monitor_present(&rt2x00dev->interface)) { + rt2x00_set_field16(®, TXRX_CSR2_DROP_CRC, 0); + rt2x00_set_field16(®, TXRX_CSR2_DROP_PHYSICAL, 0); + rt2x00_set_field16(®, TXRX_CSR2_DROP_CONTROL, 0); + rt2x00_set_field16(®, TXRX_CSR2_DROP_VERSION_ERROR, 0); + } + + rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg); + + /* + * Enable beacon config + */ + rt2500usb_register_read(rt2x00dev, TXRX_CSR20, ®); + rt2x00_set_field16(®, TXRX_CSR20_OFFSET, + (PREAMBLE + get_duration(IEEE80211_HEADER, 2)) >> 6); + if (type == IEEE80211_IF_TYPE_STA) + rt2x00_set_field16(®, TXRX_CSR20_BCN_EXPECT_WINDOW, 0); + else + rt2x00_set_field16(®, TXRX_CSR20_BCN_EXPECT_WINDOW, 2); + rt2500usb_register_write(rt2x00dev, TXRX_CSR20, reg); + + /* + * Enable synchronisation. + */ + rt2500usb_register_read(rt2x00dev, TXRX_CSR18, ®); + rt2x00_set_field16(®, TXRX_CSR18_OFFSET, 0); + rt2500usb_register_write(rt2x00dev, TXRX_CSR18, reg); + + rt2500usb_register_read(rt2x00dev, TXRX_CSR19, ®); + if (is_interface_present(&rt2x00dev->interface)) { + rt2x00_set_field16(®, TXRX_CSR19_TSF_COUNT, 1); + rt2x00_set_field16(®, TXRX_CSR19_TBCN, 1); + } + + rt2x00_set_field16(®, TXRX_CSR19_BEACON_GEN, 0); + if (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_AP) + rt2x00_set_field16(®, TXRX_CSR19_TSF_SYNC, 2); + else if (type == IEEE80211_IF_TYPE_STA) + rt2x00_set_field16(®, TXRX_CSR19_TSF_SYNC, 1); + else if (is_monitor_present(&rt2x00dev->interface) && + !is_interface_present(&rt2x00dev->interface)) + rt2x00_set_field16(®, TXRX_CSR19_TSF_SYNC, 0); + + rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg); +} + +static void rt2500usb_config_rate(struct rt2x00_dev *rt2x00dev, const int rate) +{ + struct ieee80211_conf *conf = &rt2x00dev->hw->conf; + u16 reg; + u16 value; + u16 preamble; + + if (DEVICE_GET_RATE_FIELD(rate, PREAMBLE)) + preamble = SHORT_PREAMBLE; + else + preamble = PREAMBLE; + + reg = DEVICE_GET_RATE_FIELD(rate, RATEMASK) & DEV_BASIC_RATEMASK; + + rt2500usb_register_write(rt2x00dev, TXRX_CSR11, reg); + + rt2500usb_register_read(rt2x00dev, TXRX_CSR1, ®); + value = ((conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) ? + SHORT_DIFS : DIFS) + + PLCP + preamble + get_duration(ACK_SIZE, 10); + rt2x00_set_field16(®, TXRX_CSR1_ACK_TIMEOUT, value); + rt2500usb_register_write(rt2x00dev, TXRX_CSR1, reg); + + rt2500usb_register_read(rt2x00dev, TXRX_CSR10, ®); + if (preamble == SHORT_PREAMBLE) + rt2x00_set_field16(®, TXRX_CSR10_AUTORESPOND_PREAMBLE, 1); + else + rt2x00_set_field16(®, TXRX_CSR10_AUTORESPOND_PREAMBLE, 0); + rt2500usb_register_write(rt2x00dev, TXRX_CSR10, reg); +} + +static void rt2500usb_config_phymode(struct rt2x00_dev *rt2x00dev, + const int phymode) +{ + struct ieee80211_hw_mode *mode; + struct ieee80211_rate *rate; + + if (phymode == MODE_IEEE80211A) + rt2x00dev->curr_hwmode = HWMODE_A; + else if (phymode == MODE_IEEE80211B) + rt2x00dev->curr_hwmode = HWMODE_B; + else + rt2x00dev->curr_hwmode = HWMODE_G; + + mode = &rt2x00dev->hwmodes[rt2x00dev->curr_hwmode]; + rate = &mode->rates[mode->num_rates - 1]; + + rt2500usb_config_rate(rt2x00dev, rate->val2); + + if (phymode == MODE_IEEE80211B) { + rt2500usb_register_write(rt2x00dev, MAC_CSR11, 0x000b); + rt2500usb_register_write(rt2x00dev, MAC_CSR12, 0x0040); + } else { + rt2500usb_register_write(rt2x00dev, MAC_CSR11, 0x0005); + rt2500usb_register_write(rt2x00dev, MAC_CSR12, 0x016c); + } +} + +static void rt2500usb_config_channel(struct rt2x00_dev *rt2x00dev, + const int index, const int channel, + const int txpower) +{ + struct rf_channel reg; + + /* + * Fill rf_reg structure. + */ + memcpy(®, &rt2x00dev->spec.channels[index], sizeof(reg)); + + /* + * Set TXpower. + */ + rt2x00_set_field32(®.rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); + + /* + * For RT2525E we should first set the channel to half band higher. + */ + if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) { + static const u32 vals[] = { + 0x000008aa, 0x000008ae, 0x000008ae, 0x000008b2, + 0x000008b2, 0x000008b6, 0x000008b6, 0x000008ba, + 0x000008ba, 0x000008be, 0x000008b7, 0x00000902, + 0x00000902, 0x00000906 + }; + + rt2500usb_rf_write(rt2x00dev, 2, vals[channel - 1]); + if (reg.rf4) + rt2500usb_rf_write(rt2x00dev, 4, reg.rf4); + } + + rt2500usb_rf_write(rt2x00dev, 1, reg.rf1); + rt2500usb_rf_write(rt2x00dev, 2, reg.rf2); + rt2500usb_rf_write(rt2x00dev, 3, reg.rf3); + if (reg.rf4) + rt2500usb_rf_write(rt2x00dev, 4, reg.rf4); +} + +static void rt2500usb_config_txpower(struct rt2x00_dev *rt2x00dev, + const int txpower) +{ + u32 rf3; + + rt2x00_rf_read(rt2x00dev, 3, &rf3); + rt2x00_set_field32(&rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); + rt2500usb_rf_write(rt2x00dev, 3, rf3); +} + +static void rt2500usb_config_antenna(struct rt2x00_dev *rt2x00dev, + const int antenna_tx, const int antenna_rx) +{ + u8 r2; + u8 r14; + u16 csr5; + u16 csr6; + + rt2500usb_bbp_read(rt2x00dev, 2, &r2); + rt2500usb_bbp_read(rt2x00dev, 14, &r14); + rt2500usb_register_read(rt2x00dev, PHY_CSR5, &csr5); + rt2500usb_register_read(rt2x00dev, PHY_CSR6, &csr6); + + /* + * Configure the TX antenna. + */ + switch (antenna_tx) { + case ANTENNA_SW_DIVERSITY: + case ANTENNA_HW_DIVERSITY: + rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 1); + rt2x00_set_field16(&csr5, PHY_CSR5_CCK, 1); + rt2x00_set_field16(&csr6, PHY_CSR6_OFDM, 1); + break; + case ANTENNA_A: + rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 0); + rt2x00_set_field16(&csr5, PHY_CSR5_CCK, 0); + rt2x00_set_field16(&csr6, PHY_CSR6_OFDM, 0); + break; + case ANTENNA_B: + rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 2); + rt2x00_set_field16(&csr5, PHY_CSR5_CCK, 2); + rt2x00_set_field16(&csr6, PHY_CSR6_OFDM, 2); + break; + } + + /* + * Configure the RX antenna. + */ + switch (antenna_rx) { + case ANTENNA_SW_DIVERSITY: + case ANTENNA_HW_DIVERSITY: + rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 1); + break; + case ANTENNA_A: + rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 0); + break; + case ANTENNA_B: + rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 2); + break; + } + + /* + * RT2525E and RT5222 need to flip TX I/Q + */ + if (rt2x00_rf(&rt2x00dev->chip, RF2525E) || + rt2x00_rf(&rt2x00dev->chip, RF5222)) { + rt2x00_set_field8(&r2, BBP_R2_TX_IQ_FLIP, 1); + rt2x00_set_field16(&csr5, PHY_CSR5_CCK_FLIP, 1); + rt2x00_set_field16(&csr6, PHY_CSR6_OFDM_FLIP, 1); + + /* + * RT2525E does not need RX I/Q Flip. + */ + if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) + rt2x00_set_field8(&r14, BBP_R14_RX_IQ_FLIP, 0); + } else { + rt2x00_set_field16(&csr5, PHY_CSR5_CCK_FLIP, 0); + rt2x00_set_field16(&csr6, PHY_CSR6_OFDM_FLIP, 0); + } + + rt2500usb_bbp_write(rt2x00dev, 2, r2); + rt2500usb_bbp_write(rt2x00dev, 14, r14); + rt2500usb_register_write(rt2x00dev, PHY_CSR5, csr5); + rt2500usb_register_write(rt2x00dev, PHY_CSR6, csr6); +} + +static void rt2500usb_config_duration(struct rt2x00_dev *rt2x00dev, + const int short_slot_time, + const int beacon_int) +{ + u16 reg; + + rt2500usb_register_write(rt2x00dev, MAC_CSR10, + short_slot_time ? SHORT_SLOT_TIME : SLOT_TIME); + + rt2500usb_register_read(rt2x00dev, TXRX_CSR18, ®); + rt2x00_set_field16(®, TXRX_CSR18_INTERVAL, beacon_int * 4); + rt2500usb_register_write(rt2x00dev, TXRX_CSR18, reg); +} + +static void rt2500usb_config(struct rt2x00_dev *rt2x00dev, + const unsigned int flags, + struct ieee80211_conf *conf) +{ + int short_slot_time = conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME; + + if (flags & CONFIG_UPDATE_PHYMODE) + rt2500usb_config_phymode(rt2x00dev, conf->phymode); + if (flags & CONFIG_UPDATE_CHANNEL) + rt2500usb_config_channel(rt2x00dev, conf->channel_val, + conf->channel, conf->power_level); + if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL)) + rt2500usb_config_txpower(rt2x00dev, conf->power_level); + if (flags & CONFIG_UPDATE_ANTENNA) + rt2500usb_config_antenna(rt2x00dev, conf->antenna_sel_tx, + conf->antenna_sel_rx); + if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT)) + rt2500usb_config_duration(rt2x00dev, short_slot_time, + conf->beacon_int); +} + +/* + * LED functions. + */ +static void rt2500usb_enable_led(struct rt2x00_dev *rt2x00dev) +{ + u16 reg; + + rt2500usb_register_read(rt2x00dev, MAC_CSR21, ®); + rt2x00_set_field16(®, MAC_CSR21_ON_PERIOD, 70); + rt2x00_set_field16(®, MAC_CSR21_OFF_PERIOD, 30); + rt2500usb_register_write(rt2x00dev, MAC_CSR21, reg); + + rt2500usb_register_read(rt2x00dev, MAC_CSR20, ®); + + if (rt2x00dev->led_mode == LED_MODE_TXRX_ACTIVITY) { + rt2x00_set_field16(®, MAC_CSR20_LINK, 1); + rt2x00_set_field16(®, MAC_CSR20_ACTIVITY, 0); + } else if (rt2x00dev->led_mode == LED_MODE_ASUS) { + rt2x00_set_field16(®, MAC_CSR20_LINK, 0); + rt2x00_set_field16(®, MAC_CSR20_ACTIVITY, 1); + } else { + rt2x00_set_field16(®, MAC_CSR20_LINK, 1); + rt2x00_set_field16(®, MAC_CSR20_ACTIVITY, 1); + } + + rt2500usb_register_write(rt2x00dev, MAC_CSR20, reg); +} + +static void rt2500usb_disable_led(struct rt2x00_dev *rt2x00dev) +{ + u16 reg; + + rt2500usb_register_read(rt2x00dev, MAC_CSR20, ®); + rt2x00_set_field16(®, MAC_CSR20_LINK, 0); + rt2x00_set_field16(®, MAC_CSR20_ACTIVITY, 0); + rt2500usb_register_write(rt2x00dev, MAC_CSR20, reg); +} + +/* + * Link tuning + */ +static void rt2500usb_link_stats(struct rt2x00_dev *rt2x00dev) +{ + u16 reg; + + /* + * Update FCS error count from register. + */ + rt2500usb_register_read(rt2x00dev, STA_CSR0, ®); + rt2x00dev->link.rx_failed = rt2x00_get_field16(reg, STA_CSR0_FCS_ERROR); + + /* + * Update False CCA count from register. + */ + rt2500usb_register_read(rt2x00dev, STA_CSR3, ®); + rt2x00dev->link.false_cca = + rt2x00_get_field16(reg, STA_CSR3_FALSE_CCA_ERROR); +} + +static void rt2500usb_reset_tuner(struct rt2x00_dev *rt2x00dev) +{ + u16 eeprom; + u16 value; + + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R24, &eeprom); + value = rt2x00_get_field16(eeprom, EEPROM_BBPTUNE_R24_LOW); + rt2500usb_bbp_write(rt2x00dev, 24, value); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R25, &eeprom); + value = rt2x00_get_field16(eeprom, EEPROM_BBPTUNE_R25_LOW); + rt2500usb_bbp_write(rt2x00dev, 25, value); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R61, &eeprom); + value = rt2x00_get_field16(eeprom, EEPROM_BBPTUNE_R61_LOW); + rt2500usb_bbp_write(rt2x00dev, 61, value); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_VGC, &eeprom); + value = rt2x00_get_field16(eeprom, EEPROM_BBPTUNE_VGCUPPER); + rt2500usb_bbp_write(rt2x00dev, 17, value); + + rt2x00dev->link.vgc_level = value; +} + +static void rt2500usb_link_tuner(struct rt2x00_dev *rt2x00dev) +{ + int rssi = rt2x00_get_link_rssi(&rt2x00dev->link); + u16 bbp_thresh; + u16 vgc_bound; + u16 sens; + u16 r24; + u16 r25; + u16 r61; + u16 r17_sens; + u8 r17; + u8 up_bound; + u8 low_bound; + + /* + * Determine the BBP tuning threshold and correctly + * set BBP 24, 25 and 61. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE, &bbp_thresh); + bbp_thresh = rt2x00_get_field16(bbp_thresh, EEPROM_BBPTUNE_THRESHOLD); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R24, &r24); + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R25, &r25); + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R61, &r61); + + if ((rssi + bbp_thresh) > 0) { + r24 = rt2x00_get_field16(r24, EEPROM_BBPTUNE_R24_HIGH); + r25 = rt2x00_get_field16(r25, EEPROM_BBPTUNE_R25_HIGH); + r61 = rt2x00_get_field16(r61, EEPROM_BBPTUNE_R61_HIGH); + } else { + r24 = rt2x00_get_field16(r24, EEPROM_BBPTUNE_R24_LOW); + r25 = rt2x00_get_field16(r25, EEPROM_BBPTUNE_R25_LOW); + r61 = rt2x00_get_field16(r61, EEPROM_BBPTUNE_R61_LOW); + } + + rt2500usb_bbp_write(rt2x00dev, 24, r24); + rt2500usb_bbp_write(rt2x00dev, 25, r25); + rt2500usb_bbp_write(rt2x00dev, 61, r61); + + /* + * Read current r17 value, as well as the sensitivity values + * for the r17 register. + */ + rt2500usb_bbp_read(rt2x00dev, 17, &r17); + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R17, &r17_sens); + + /* + * A too low RSSI will cause too much false CCA which will + * then corrupt the R17 tuning. To remidy this the tuning should + * be stopped (While making sure the R17 value will not exceed limits) + */ + if (rssi >= -40) { + if (r17 != 0x60) + rt2500usb_bbp_write(rt2x00dev, 17, 0x60); + return; + } + + /* + * Special big-R17 for short distance + */ + if (rssi >= -58) { + sens = rt2x00_get_field16(r17_sens, EEPROM_BBPTUNE_R17_LOW); + if (r17 != sens) + rt2500usb_bbp_write(rt2x00dev, 17, sens); + return; + } + + /* + * Special mid-R17 for middle distance + */ + if (rssi >= -74) { + sens = rt2x00_get_field16(r17_sens, EEPROM_BBPTUNE_R17_HIGH); + if (r17 != sens) + rt2500usb_bbp_write(rt2x00dev, 17, sens); + return; + } + + /* + * Leave short or middle distance condition, restore r17 + * to the dynamic tuning range. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_VGC, &vgc_bound); + vgc_bound = rt2x00_get_field16(vgc_bound, EEPROM_BBPTUNE_VGCUPPER); + + low_bound = 0x32; + if (rssi >= -77) + up_bound = vgc_bound; + else + up_bound = vgc_bound - (-77 - rssi); + + if (up_bound < low_bound) + up_bound = low_bound; + + if (r17 > up_bound) { + rt2500usb_bbp_write(rt2x00dev, 17, up_bound); + rt2x00dev->link.vgc_level = up_bound; + } else if (rt2x00dev->link.false_cca > 512 && r17 < up_bound) { + rt2500usb_bbp_write(rt2x00dev, 17, ++r17); + rt2x00dev->link.vgc_level = r17; + } else if (rt2x00dev->link.false_cca < 100 && r17 > low_bound) { + rt2500usb_bbp_write(rt2x00dev, 17, --r17); + rt2x00dev->link.vgc_level = r17; + } +} + +/* + * Initialization functions. + */ +static int rt2500usb_init_registers(struct rt2x00_dev *rt2x00dev) +{ + u16 reg; + + rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, 0x0001, + USB_MODE_TEST, REGISTER_TIMEOUT); + rt2x00usb_vendor_request_sw(rt2x00dev, USB_SINGLE_WRITE, 0x0308, + 0x00f0, REGISTER_TIMEOUT); + + rt2500usb_register_read(rt2x00dev, TXRX_CSR2, ®); + rt2x00_set_field16(®, TXRX_CSR2_DISABLE_RX, 1); + rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg); + + rt2500usb_register_write(rt2x00dev, MAC_CSR13, 0x1111); + rt2500usb_register_write(rt2x00dev, MAC_CSR14, 0x1e11); + + rt2500usb_register_read(rt2x00dev, MAC_CSR1, ®); + rt2x00_set_field16(®, MAC_CSR1_SOFT_RESET, 1); + rt2x00_set_field16(®, MAC_CSR1_BBP_RESET, 1); + rt2x00_set_field16(®, MAC_CSR1_HOST_READY, 0); + rt2500usb_register_write(rt2x00dev, MAC_CSR1, reg); + + rt2500usb_register_read(rt2x00dev, MAC_CSR1, ®); + rt2x00_set_field16(®, MAC_CSR1_SOFT_RESET, 0); + rt2x00_set_field16(®, MAC_CSR1_BBP_RESET, 0); + rt2x00_set_field16(®, MAC_CSR1_HOST_READY, 0); + rt2500usb_register_write(rt2x00dev, MAC_CSR1, reg); + + rt2500usb_register_read(rt2x00dev, TXRX_CSR5, ®); + rt2x00_set_field16(®, TXRX_CSR5_BBP_ID0, 13); + rt2x00_set_field16(®, TXRX_CSR5_BBP_ID0_VALID, 1); + rt2x00_set_field16(®, TXRX_CSR5_BBP_ID1, 12); + rt2x00_set_field16(®, TXRX_CSR5_BBP_ID1_VALID, 1); + rt2500usb_register_write(rt2x00dev, TXRX_CSR5, reg); + + rt2500usb_register_read(rt2x00dev, TXRX_CSR6, ®); + rt2x00_set_field16(®, TXRX_CSR6_BBP_ID0, 10); + rt2x00_set_field16(®, TXRX_CSR6_BBP_ID0_VALID, 1); + rt2x00_set_field16(®, TXRX_CSR6_BBP_ID1, 11); + rt2x00_set_field16(®, TXRX_CSR6_BBP_ID1_VALID, 1); + rt2500usb_register_write(rt2x00dev, TXRX_CSR6, reg); + + rt2500usb_register_read(rt2x00dev, TXRX_CSR7, ®); + rt2x00_set_field16(®, TXRX_CSR7_BBP_ID0, 7); + rt2x00_set_field16(®, TXRX_CSR7_BBP_ID0_VALID, 1); + rt2x00_set_field16(®, TXRX_CSR7_BBP_ID1, 6); + rt2x00_set_field16(®, TXRX_CSR7_BBP_ID1_VALID, 1); + rt2500usb_register_write(rt2x00dev, TXRX_CSR7, reg); + + rt2500usb_register_read(rt2x00dev, TXRX_CSR8, ®); + rt2x00_set_field16(®, TXRX_CSR8_BBP_ID0, 5); + rt2x00_set_field16(®, TXRX_CSR8_BBP_ID0_VALID, 1); + rt2x00_set_field16(®, TXRX_CSR8_BBP_ID1, 0); + rt2x00_set_field16(®, TXRX_CSR8_BBP_ID1_VALID, 0); + rt2500usb_register_write(rt2x00dev, TXRX_CSR8, reg); + + rt2500usb_register_write(rt2x00dev, TXRX_CSR21, 0xe78f); + rt2500usb_register_write(rt2x00dev, MAC_CSR9, 0xff1d); + + if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE)) + return -EBUSY; + + rt2500usb_register_read(rt2x00dev, MAC_CSR1, ®); + rt2x00_set_field16(®, MAC_CSR1_SOFT_RESET, 0); + rt2x00_set_field16(®, MAC_CSR1_BBP_RESET, 0); + rt2x00_set_field16(®, MAC_CSR1_HOST_READY, 1); + rt2500usb_register_write(rt2x00dev, MAC_CSR1, reg); + + if (rt2x00_get_rev(&rt2x00dev->chip) >= RT2570_VERSION_C) { + rt2500usb_register_read(rt2x00dev, PHY_CSR2, ®); + reg &= ~0x0002; + } else { + reg = 0x3002; + } + rt2500usb_register_write(rt2x00dev, PHY_CSR2, reg); + + rt2500usb_register_write(rt2x00dev, MAC_CSR11, 0x0002); + rt2500usb_register_write(rt2x00dev, MAC_CSR22, 0x0053); + rt2500usb_register_write(rt2x00dev, MAC_CSR15, 0x01ee); + rt2500usb_register_write(rt2x00dev, MAC_CSR16, 0x0000); + + rt2500usb_register_read(rt2x00dev, MAC_CSR8, ®); + rt2x00_set_field16(®, MAC_CSR8_MAX_FRAME_UNIT, + rt2x00dev->rx->data_size); + rt2500usb_register_write(rt2x00dev, MAC_CSR8, reg); + + rt2500usb_register_read(rt2x00dev, TXRX_CSR0, ®); + rt2x00_set_field16(®, TXRX_CSR0_IV_OFFSET, IEEE80211_HEADER); + rt2x00_set_field16(®, TXRX_CSR0_KEY_ID, 0xff); + rt2500usb_register_write(rt2x00dev, TXRX_CSR0, reg); + + rt2500usb_register_read(rt2x00dev, MAC_CSR18, ®); + rt2x00_set_field16(®, MAC_CSR18_DELAY_AFTER_BEACON, 90); + rt2500usb_register_write(rt2x00dev, MAC_CSR18, reg); + + rt2500usb_register_read(rt2x00dev, PHY_CSR4, ®); + rt2x00_set_field16(®, PHY_CSR4_LOW_RF_LE, 1); + rt2500usb_register_write(rt2x00dev, PHY_CSR4, reg); + + rt2500usb_register_read(rt2x00dev, TXRX_CSR1, ®); + rt2x00_set_field16(®, TXRX_CSR1_AUTO_SEQUENCE, 1); + rt2500usb_register_write(rt2x00dev, TXRX_CSR1, reg); + + return 0; +} + +static int rt2500usb_init_bbp(struct rt2x00_dev *rt2x00dev) +{ + unsigned int i; + u16 eeprom; + u8 value; + u8 reg_id; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2500usb_bbp_read(rt2x00dev, 0, &value); + if ((value != 0xff) && (value != 0x00)) + goto continue_csr_init; + NOTICE(rt2x00dev, "Waiting for BBP register.\n"); + udelay(REGISTER_BUSY_DELAY); + } + + ERROR(rt2x00dev, "BBP register access failed, aborting.\n"); + return -EACCES; + +continue_csr_init: + rt2500usb_bbp_write(rt2x00dev, 3, 0x02); + rt2500usb_bbp_write(rt2x00dev, 4, 0x19); + rt2500usb_bbp_write(rt2x00dev, 14, 0x1c); + rt2500usb_bbp_write(rt2x00dev, 15, 0x30); + rt2500usb_bbp_write(rt2x00dev, 16, 0xac); + rt2500usb_bbp_write(rt2x00dev, 18, 0x18); + rt2500usb_bbp_write(rt2x00dev, 19, 0xff); + rt2500usb_bbp_write(rt2x00dev, 20, 0x1e); + rt2500usb_bbp_write(rt2x00dev, 21, 0x08); + rt2500usb_bbp_write(rt2x00dev, 22, 0x08); + rt2500usb_bbp_write(rt2x00dev, 23, 0x08); + rt2500usb_bbp_write(rt2x00dev, 24, 0x80); + rt2500usb_bbp_write(rt2x00dev, 25, 0x50); + rt2500usb_bbp_write(rt2x00dev, 26, 0x08); + rt2500usb_bbp_write(rt2x00dev, 27, 0x23); + rt2500usb_bbp_write(rt2x00dev, 30, 0x10); + rt2500usb_bbp_write(rt2x00dev, 31, 0x2b); + rt2500usb_bbp_write(rt2x00dev, 32, 0xb9); + rt2500usb_bbp_write(rt2x00dev, 34, 0x12); + rt2500usb_bbp_write(rt2x00dev, 35, 0x50); + rt2500usb_bbp_write(rt2x00dev, 39, 0xc4); + rt2500usb_bbp_write(rt2x00dev, 40, 0x02); + rt2500usb_bbp_write(rt2x00dev, 41, 0x60); + rt2500usb_bbp_write(rt2x00dev, 53, 0x10); + rt2500usb_bbp_write(rt2x00dev, 54, 0x18); + rt2500usb_bbp_write(rt2x00dev, 56, 0x08); + rt2500usb_bbp_write(rt2x00dev, 57, 0x10); + rt2500usb_bbp_write(rt2x00dev, 58, 0x08); + rt2500usb_bbp_write(rt2x00dev, 61, 0x60); + rt2500usb_bbp_write(rt2x00dev, 62, 0x10); + rt2500usb_bbp_write(rt2x00dev, 75, 0xff); + + DEBUG(rt2x00dev, "Start initialization from EEPROM...\n"); + for (i = 0; i < EEPROM_BBP_SIZE; i++) { + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom); + + if (eeprom != 0xffff && eeprom != 0x0000) { + reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID); + value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE); + DEBUG(rt2x00dev, "BBP: 0x%02x, value: 0x%02x.\n", + reg_id, value); + rt2500usb_bbp_write(rt2x00dev, reg_id, value); + } + } + DEBUG(rt2x00dev, "...End initialization from EEPROM.\n"); + + return 0; +} + +/* + * Device state switch handlers. + */ +static void rt2500usb_toggle_rx(struct rt2x00_dev *rt2x00dev, + enum dev_state state) +{ + u16 reg; + + rt2500usb_register_read(rt2x00dev, TXRX_CSR2, ®); + rt2x00_set_field16(®, TXRX_CSR2_DISABLE_RX, + state == STATE_RADIO_RX_OFF); + rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg); +} + +static int rt2500usb_enable_radio(struct rt2x00_dev *rt2x00dev) +{ + /* + * Initialize all registers. + */ + if (rt2500usb_init_registers(rt2x00dev) || + rt2500usb_init_bbp(rt2x00dev)) { + ERROR(rt2x00dev, "Register initialization failed.\n"); + return -EIO; + } + + rt2x00usb_enable_radio(rt2x00dev); + + /* + * Enable LED + */ + rt2500usb_enable_led(rt2x00dev); + + return 0; +} + +static void rt2500usb_disable_radio(struct rt2x00_dev *rt2x00dev) +{ + /* + * Disable LED + */ + rt2500usb_disable_led(rt2x00dev); + + rt2500usb_register_write(rt2x00dev, MAC_CSR13, 0x2121); + rt2500usb_register_write(rt2x00dev, MAC_CSR14, 0x2121); + + /* + * Disable synchronisation. + */ + rt2500usb_register_write(rt2x00dev, TXRX_CSR19, 0); + + rt2x00usb_disable_radio(rt2x00dev); +} + +static int rt2500usb_set_state(struct rt2x00_dev *rt2x00dev, + enum dev_state state) +{ + u16 reg; + u16 reg2; + unsigned int i; + char put_to_sleep; + char bbp_state; + char rf_state; + + put_to_sleep = (state != STATE_AWAKE); + + reg = 0; + rt2x00_set_field16(®, MAC_CSR17_BBP_DESIRE_STATE, state); + rt2x00_set_field16(®, MAC_CSR17_RF_DESIRE_STATE, state); + rt2x00_set_field16(®, MAC_CSR17_PUT_TO_SLEEP, put_to_sleep); + rt2500usb_register_write(rt2x00dev, MAC_CSR17, reg); + rt2x00_set_field16(®, MAC_CSR17_SET_STATE, 1); + rt2500usb_register_write(rt2x00dev, MAC_CSR17, reg); + + /* + * Device is not guaranteed to be in the requested state yet. + * We must wait until the register indicates that the + * device has entered the correct state. + */ + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2500usb_register_read(rt2x00dev, MAC_CSR17, ®2); + bbp_state = rt2x00_get_field16(reg2, MAC_CSR17_BBP_CURR_STATE); + rf_state = rt2x00_get_field16(reg2, MAC_CSR17_RF_CURR_STATE); + if (bbp_state == state && rf_state == state) + return 0; + rt2500usb_register_write(rt2x00dev, MAC_CSR17, reg); + msleep(30); + } + + NOTICE(rt2x00dev, "Device failed to enter state %d, " + "current device state: bbp %d and rf %d.\n", + state, bbp_state, rf_state); + + return -EBUSY; +} + +static int rt2500usb_set_device_state(struct rt2x00_dev *rt2x00dev, + enum dev_state state) +{ + int retval = 0; + + switch (state) { + case STATE_RADIO_ON: + retval = rt2500usb_enable_radio(rt2x00dev); + break; + case STATE_RADIO_OFF: + rt2500usb_disable_radio(rt2x00dev); + break; + case STATE_RADIO_RX_ON: + case STATE_RADIO_RX_OFF: + rt2500usb_toggle_rx(rt2x00dev, state); + break; + case STATE_DEEP_SLEEP: + case STATE_SLEEP: + case STATE_STANDBY: + case STATE_AWAKE: + retval = rt2500usb_set_state(rt2x00dev, state); + break; + default: + retval = -ENOTSUPP; + break; + } + + return retval; +} + +/* + * TX descriptor initialization + */ +static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, + struct data_desc *txd, + struct data_entry_desc *desc, + struct ieee80211_hdr *ieee80211hdr, + unsigned int length, + struct ieee80211_tx_control *control) +{ + u32 word; + + /* + * Start writing the descriptor words. + */ + rt2x00_desc_read(txd, 1, &word); + rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER); + rt2x00_set_field32(&word, TXD_W1_AIFS, desc->aifs); + rt2x00_set_field32(&word, TXD_W1_CWMIN, desc->cw_min); + rt2x00_set_field32(&word, TXD_W1_CWMAX, desc->cw_max); + rt2x00_desc_write(txd, 1, word); + + rt2x00_desc_read(txd, 2, &word); + rt2x00_set_field32(&word, TXD_W2_PLCP_SIGNAL, desc->signal); + rt2x00_set_field32(&word, TXD_W2_PLCP_SERVICE, desc->service); + rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_LOW, desc->length_low); + rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, desc->length_high); + rt2x00_desc_write(txd, 2, word); + + rt2x00_desc_read(txd, 0, &word); + rt2x00_set_field32(&word, TXD_W0_RETRY_LIMIT, control->retry_limit); + rt2x00_set_field32(&word, TXD_W0_MORE_FRAG, + test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags)); + rt2x00_set_field32(&word, TXD_W0_ACK, + !(control->flags & IEEE80211_TXCTL_NO_ACK)); + rt2x00_set_field32(&word, TXD_W0_TIMESTAMP, + test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags)); + rt2x00_set_field32(&word, TXD_W0_OFDM, + test_bit(ENTRY_TXD_OFDM_RATE, &desc->flags)); + rt2x00_set_field32(&word, TXD_W0_NEW_SEQ, + !!(control->flags & IEEE80211_TXCTL_FIRST_FRAGMENT)); + rt2x00_set_field32(&word, TXD_W0_IFS, desc->ifs); + rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, length); + rt2x00_set_field32(&word, TXD_W0_CIPHER, CIPHER_NONE); + rt2x00_desc_write(txd, 0, word); +} + +/* + * TX data initialization + */ +static void rt2500usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, + unsigned int queue) +{ + u16 reg; + + if (queue != IEEE80211_TX_QUEUE_BEACON) + return; + + rt2500usb_register_read(rt2x00dev, TXRX_CSR19, ®); + if (!rt2x00_get_field16(reg, TXRX_CSR19_BEACON_GEN)) { + rt2x00_set_field16(®, TXRX_CSR19_BEACON_GEN, 1); + /* + * Beacon generation will fail initially. + * To prevent this we need to register the TXRX_CSR19 + * register several times. + */ + rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg); + rt2500usb_register_write(rt2x00dev, TXRX_CSR19, 0); + rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg); + rt2500usb_register_write(rt2x00dev, TXRX_CSR19, 0); + rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg); + } +} + +/* + * RX control handlers + */ +static int rt2500usb_fill_rxdone(struct data_entry *entry, + int *signal, int *rssi, int *ofdm, int *size) +{ + struct urb *urb = entry->priv; + struct data_desc *rxd = (struct data_desc *)(entry->skb->data + + (urb->actual_length - + entry->ring->desc_size)); + u32 word0; + u32 word1; + + rt2x00_desc_read(rxd, 0, &word0); + rt2x00_desc_read(rxd, 1, &word1); + + if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR) || + rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR) || + rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR)) + return -EINVAL; + + /* + * Obtain the status about this packet. + */ + *signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL); + *rssi = rt2x00_get_field32(word1, RXD_W1_RSSI) - + entry->ring->rt2x00dev->rssi_offset; + *ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); + *size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); + + return 0; +} + +/* + * Interrupt functions. + */ +static void rt2500usb_beacondone(struct urb *urb) +{ + struct data_entry *entry = (struct data_entry *)urb->context; + struct data_ring *ring = entry->ring; + + if (!test_bit(DEVICE_ENABLED_RADIO, &ring->rt2x00dev->flags)) + return; + + /* + * Check if this was the guardian beacon, + * if that was the case we need to send the real beacon now. + * Otherwise we should free the sk_buffer, the device + * should be doing the rest of the work now. + */ + if (ring->index == 1) { + rt2x00_ring_index_done_inc(ring); + entry = rt2x00_get_data_entry(ring); + usb_submit_urb(entry->priv, GFP_ATOMIC); + rt2x00_ring_index_inc(ring); + } else if (ring->index_done == 1) { + entry = rt2x00_get_data_entry_done(ring); + if (entry->skb) { + dev_kfree_skb(entry->skb); + entry->skb = NULL; + } + rt2x00_ring_index_done_inc(ring); + } +} + +/* + * Device probe functions. + */ +static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) +{ + u16 word; + u8 *mac; + + rt2x00usb_eeprom_read(rt2x00dev, rt2x00dev->eeprom, EEPROM_SIZE); + + /* + * Start validation of the data that has been read. + */ + mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); + if (!is_valid_ether_addr(mac)) { + random_ether_addr(mac); + EEPROM(rt2x00dev, "MAC: " MAC_FMT "\n", MAC_ARG(mac)); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2); + rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, 0); + rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT, 0); + rt2x00_set_field16(&word, EEPROM_ANTENNA_LED_MODE, 0); + rt2x00_set_field16(&word, EEPROM_ANTENNA_DYN_TXAGC, 0); + rt2x00_set_field16(&word, EEPROM_ANTENNA_HARDWARE_RADIO, 0); + rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF2522); + rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word); + EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_NIC_CARDBUS_ACCEL, 0); + rt2x00_set_field16(&word, EEPROM_NIC_DYN_BBP_TUNE, 0); + rt2x00_set_field16(&word, EEPROM_NIC_CCK_TX_POWER, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word); + EEPROM(rt2x00dev, "NIC: 0x%04x\n", word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_CALIBRATE_OFFSET_RSSI, + DEFAULT_RSSI_OFFSET); + rt2x00_eeprom_write(rt2x00dev, EEPROM_CALIBRATE_OFFSET, word); + EEPROM(rt2x00dev, "Calibrate offset: 0x%04x\n", word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_BBPTUNE_THRESHOLD, 45); + rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE, word); + EEPROM(rt2x00dev, "BBPtune: 0x%04x\n", word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_VGC, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_BBPTUNE_VGCUPPER, 0x40); + rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_VGC, word); + EEPROM(rt2x00dev, "BBPtune vgc: 0x%04x\n", word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R17, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_BBPTUNE_R17_LOW, 0x48); + rt2x00_set_field16(&word, EEPROM_BBPTUNE_R17_HIGH, 0x41); + rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_R17, word); + EEPROM(rt2x00dev, "BBPtune r17: 0x%04x\n", word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R24, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_BBPTUNE_R24_LOW, 0x40); + rt2x00_set_field16(&word, EEPROM_BBPTUNE_R24_HIGH, 0x80); + rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_R24, word); + EEPROM(rt2x00dev, "BBPtune r24: 0x%04x\n", word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R25, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_BBPTUNE_R25_LOW, 0x40); + rt2x00_set_field16(&word, EEPROM_BBPTUNE_R25_HIGH, 0x50); + rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_R25, word); + EEPROM(rt2x00dev, "BBPtune r25: 0x%04x\n", word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R61, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_BBPTUNE_R61_LOW, 0x60); + rt2x00_set_field16(&word, EEPROM_BBPTUNE_R61_HIGH, 0x6d); + rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_R61, word); + EEPROM(rt2x00dev, "BBPtune r61: 0x%04x\n", word); + } + + return 0; +} + +static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev) +{ + u16 reg; + u16 value; + u16 eeprom; + + /* + * Read EEPROM word for configuration. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); + + /* + * Identify RF chipset. + */ + value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); + rt2500usb_register_read(rt2x00dev, MAC_CSR0, ®); + rt2x00_set_chip(rt2x00dev, RT2570, value, reg); + + if (rt2x00_rev(&rt2x00dev->chip, 0xffff0)) { + ERROR(rt2x00dev, "Invalid RT chipset detected.\n"); + return -ENODEV; + } + + if (!rt2x00_rf(&rt2x00dev->chip, RF2522) && + !rt2x00_rf(&rt2x00dev->chip, RF2523) && + !rt2x00_rf(&rt2x00dev->chip, RF2524) && + !rt2x00_rf(&rt2x00dev->chip, RF2525) && + !rt2x00_rf(&rt2x00dev->chip, RF2525E) && + !rt2x00_rf(&rt2x00dev->chip, RF5222)) { + ERROR(rt2x00dev, "Invalid RF chipset detected.\n"); + return -ENODEV; + } + + /* + * Identify default antenna configuration. + */ + rt2x00dev->hw->conf.antenna_sel_tx = + rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TX_DEFAULT); + rt2x00dev->hw->conf.antenna_sel_rx = + rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT); + + /* + * Store led mode, for correct led behaviour. + */ + rt2x00dev->led_mode = + rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE); + + /* + * Check if the BBP tuning should be disabled. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom); + if (rt2x00_get_field16(eeprom, EEPROM_NIC_DYN_BBP_TUNE)) + __set_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags); + + /* + * Read the RSSI <-> dBm offset information. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET, &eeprom); + rt2x00dev->rssi_offset = + rt2x00_get_field16(eeprom, EEPROM_CALIBRATE_OFFSET_RSSI); + + return 0; +} + +/* + * RF value list for RF2522 + * Supports: 2.4 GHz + */ +static const struct rf_channel rf_vals_bg_2522[] = { + { 1, 0x00002050, 0x000c1fda, 0x00000101, 0 }, + { 2, 0x00002050, 0x000c1fee, 0x00000101, 0 }, + { 3, 0x00002050, 0x000c2002, 0x00000101, 0 }, + { 4, 0x00002050, 0x000c2016, 0x00000101, 0 }, + { 5, 0x00002050, 0x000c202a, 0x00000101, 0 }, + { 6, 0x00002050, 0x000c203e, 0x00000101, 0 }, + { 7, 0x00002050, 0x000c2052, 0x00000101, 0 }, + { 8, 0x00002050, 0x000c2066, 0x00000101, 0 }, + { 9, 0x00002050, 0x000c207a, 0x00000101, 0 }, + { 10, 0x00002050, 0x000c208e, 0x00000101, 0 }, + { 11, 0x00002050, 0x000c20a2, 0x00000101, 0 }, + { 12, 0x00002050, 0x000c20b6, 0x00000101, 0 }, + { 13, 0x00002050, 0x000c20ca, 0x00000101, 0 }, + { 14, 0x00002050, 0x000c20fa, 0x00000101, 0 }, +}; + +/* + * RF value list for RF2523 + * Supports: 2.4 GHz + */ +static const struct rf_channel rf_vals_bg_2523[] = { + { 1, 0x00022010, 0x00000c9e, 0x000e0111, 0x00000a1b }, + { 2, 0x00022010, 0x00000ca2, 0x000e0111, 0x00000a1b }, + { 3, 0x00022010, 0x00000ca6, 0x000e0111, 0x00000a1b }, + { 4, 0x00022010, 0x00000caa, 0x000e0111, 0x00000a1b }, + { 5, 0x00022010, 0x00000cae, 0x000e0111, 0x00000a1b }, + { 6, 0x00022010, 0x00000cb2, 0x000e0111, 0x00000a1b }, + { 7, 0x00022010, 0x00000cb6, 0x000e0111, 0x00000a1b }, + { 8, 0x00022010, 0x00000cba, 0x000e0111, 0x00000a1b }, + { 9, 0x00022010, 0x00000cbe, 0x000e0111, 0x00000a1b }, + { 10, 0x00022010, 0x00000d02, 0x000e0111, 0x00000a1b }, + { 11, 0x00022010, 0x00000d06, 0x000e0111, 0x00000a1b }, + { 12, 0x00022010, 0x00000d0a, 0x000e0111, 0x00000a1b }, + { 13, 0x00022010, 0x00000d0e, 0x000e0111, 0x00000a1b }, + { 14, 0x00022010, 0x00000d1a, 0x000e0111, 0x00000a03 }, +}; + +/* + * RF value list for RF2524 + * Supports: 2.4 GHz + */ +static const struct rf_channel rf_vals_bg_2524[] = { + { 1, 0x00032020, 0x00000c9e, 0x00000101, 0x00000a1b }, + { 2, 0x00032020, 0x00000ca2, 0x00000101, 0x00000a1b }, + { 3, 0x00032020, 0x00000ca6, 0x00000101, 0x00000a1b }, + { 4, 0x00032020, 0x00000caa, 0x00000101, 0x00000a1b }, + { 5, 0x00032020, 0x00000cae, 0x00000101, 0x00000a1b }, + { 6, 0x00032020, 0x00000cb2, 0x00000101, 0x00000a1b }, + { 7, 0x00032020, 0x00000cb6, 0x00000101, 0x00000a1b }, + { 8, 0x00032020, 0x00000cba, 0x00000101, 0x00000a1b }, + { 9, 0x00032020, 0x00000cbe, 0x00000101, 0x00000a1b }, + { 10, 0x00032020, 0x00000d02, 0x00000101, 0x00000a1b }, + { 11, 0x00032020, 0x00000d06, 0x00000101, 0x00000a1b }, + { 12, 0x00032020, 0x00000d0a, 0x00000101, 0x00000a1b }, + { 13, 0x00032020, 0x00000d0e, 0x00000101, 0x00000a1b }, + { 14, 0x00032020, 0x00000d1a, 0x00000101, 0x00000a03 }, +}; + +/* + * RF value list for RF2525 + * Supports: 2.4 GHz + */ +static const struct rf_channel rf_vals_bg_2525[] = { + { 1, 0x00022020, 0x00080c9e, 0x00060111, 0x00000a1b }, + { 2, 0x00022020, 0x00080ca2, 0x00060111, 0x00000a1b }, + { 3, 0x00022020, 0x00080ca6, 0x00060111, 0x00000a1b }, + { 4, 0x00022020, 0x00080caa, 0x00060111, 0x00000a1b }, + { 5, 0x00022020, 0x00080cae, 0x00060111, 0x00000a1b }, + { 6, 0x00022020, 0x00080cb2, 0x00060111, 0x00000a1b }, + { 7, 0x00022020, 0x00080cb6, 0x00060111, 0x00000a1b }, + { 8, 0x00022020, 0x00080cba, 0x00060111, 0x00000a1b }, + { 9, 0x00022020, 0x00080cbe, 0x00060111, 0x00000a1b }, + { 10, 0x00022020, 0x00080d02, 0x00060111, 0x00000a1b }, + { 11, 0x00022020, 0x00080d06, 0x00060111, 0x00000a1b }, + { 12, 0x00022020, 0x00080d0a, 0x00060111, 0x00000a1b }, + { 13, 0x00022020, 0x00080d0e, 0x00060111, 0x00000a1b }, + { 14, 0x00022020, 0x00080d1a, 0x00060111, 0x00000a03 }, +}; + +/* + * RF value list for RF2525e + * Supports: 2.4 GHz + */ +static const struct rf_channel rf_vals_bg_2525e[] = { + { 1, 0x00022010, 0x0000089a, 0x00060111, 0x00000e1b }, + { 2, 0x00022010, 0x0000089e, 0x00060111, 0x00000e07 }, + { 3, 0x00022010, 0x0000089e, 0x00060111, 0x00000e1b }, + { 4, 0x00022010, 0x000008a2, 0x00060111, 0x00000e07 }, + { 5, 0x00022010, 0x000008a2, 0x00060111, 0x00000e1b }, + { 6, 0x00022010, 0x000008a6, 0x00060111, 0x00000e07 }, + { 7, 0x00022010, 0x000008a6, 0x00060111, 0x00000e1b }, + { 8, 0x00022010, 0x000008aa, 0x00060111, 0x00000e07 }, + { 9, 0x00022010, 0x000008aa, 0x00060111, 0x00000e1b }, + { 10, 0x00022010, 0x000008ae, 0x00060111, 0x00000e07 }, + { 11, 0x00022010, 0x000008ae, 0x00060111, 0x00000e1b }, + { 12, 0x00022010, 0x000008b2, 0x00060111, 0x00000e07 }, + { 13, 0x00022010, 0x000008b2, 0x00060111, 0x00000e1b }, + { 14, 0x00022010, 0x000008b6, 0x00060111, 0x00000e23 }, +}; + +/* + * RF value list for RF5222 + * Supports: 2.4 GHz & 5.2 GHz + */ +static const struct rf_channel rf_vals_5222[] = { + { 1, 0x00022020, 0x00001136, 0x00000101, 0x00000a0b }, + { 2, 0x00022020, 0x0000113a, 0x00000101, 0x00000a0b }, + { 3, 0x00022020, 0x0000113e, 0x00000101, 0x00000a0b }, + { 4, 0x00022020, 0x00001182, 0x00000101, 0x00000a0b }, + { 5, 0x00022020, 0x00001186, 0x00000101, 0x00000a0b }, + { 6, 0x00022020, 0x0000118a, 0x00000101, 0x00000a0b }, + { 7, 0x00022020, 0x0000118e, 0x00000101, 0x00000a0b }, + { 8, 0x00022020, 0x00001192, 0x00000101, 0x00000a0b }, + { 9, 0x00022020, 0x00001196, 0x00000101, 0x00000a0b }, + { 10, 0x00022020, 0x0000119a, 0x00000101, 0x00000a0b }, + { 11, 0x00022020, 0x0000119e, 0x00000101, 0x00000a0b }, + { 12, 0x00022020, 0x000011a2, 0x00000101, 0x00000a0b }, + { 13, 0x00022020, 0x000011a6, 0x00000101, 0x00000a0b }, + { 14, 0x00022020, 0x000011ae, 0x00000101, 0x00000a1b }, + + /* 802.11 UNI / HyperLan 2 */ + { 36, 0x00022010, 0x00018896, 0x00000101, 0x00000a1f }, + { 40, 0x00022010, 0x0001889a, 0x00000101, 0x00000a1f }, + { 44, 0x00022010, 0x0001889e, 0x00000101, 0x00000a1f }, + { 48, 0x00022010, 0x000188a2, 0x00000101, 0x00000a1f }, + { 52, 0x00022010, 0x000188a6, 0x00000101, 0x00000a1f }, + { 66, 0x00022010, 0x000188aa, 0x00000101, 0x00000a1f }, + { 60, 0x00022010, 0x000188ae, 0x00000101, 0x00000a1f }, + { 64, 0x00022010, 0x000188b2, 0x00000101, 0x00000a1f }, + + /* 802.11 HyperLan 2 */ + { 100, 0x00022010, 0x00008802, 0x00000101, 0x00000a0f }, + { 104, 0x00022010, 0x00008806, 0x00000101, 0x00000a0f }, + { 108, 0x00022010, 0x0000880a, 0x00000101, 0x00000a0f }, + { 112, 0x00022010, 0x0000880e, 0x00000101, 0x00000a0f }, + { 116, 0x00022010, 0x00008812, 0x00000101, 0x00000a0f }, + { 120, 0x00022010, 0x00008816, 0x00000101, 0x00000a0f }, + { 124, 0x00022010, 0x0000881a, 0x00000101, 0x00000a0f }, + { 128, 0x00022010, 0x0000881e, 0x00000101, 0x00000a0f }, + { 132, 0x00022010, 0x00008822, 0x00000101, 0x00000a0f }, + { 136, 0x00022010, 0x00008826, 0x00000101, 0x00000a0f }, + + /* 802.11 UNII */ + { 140, 0x00022010, 0x0000882a, 0x00000101, 0x00000a0f }, + { 149, 0x00022020, 0x000090a6, 0x00000101, 0x00000a07 }, + { 153, 0x00022020, 0x000090ae, 0x00000101, 0x00000a07 }, + { 157, 0x00022020, 0x000090b6, 0x00000101, 0x00000a07 }, + { 161, 0x00022020, 0x000090be, 0x00000101, 0x00000a07 }, +}; + +static void rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) +{ + struct hw_mode_spec *spec = &rt2x00dev->spec; + u8 *txpower; + unsigned int i; + + /* + * Initialize all hw fields. + */ + rt2x00dev->hw->flags = + IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | + IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_MONITOR_DURING_OPER | + IEEE80211_HW_NO_PROBE_FILTERING; + rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE; + rt2x00dev->hw->max_signal = MAX_SIGNAL; + rt2x00dev->hw->max_rssi = MAX_RX_SSI; + rt2x00dev->hw->queues = 2; + + SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_usb(rt2x00dev)->dev); + SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, + rt2x00_eeprom_addr(rt2x00dev, + EEPROM_MAC_ADDR_0)); + + /* + * Convert tx_power array in eeprom. + */ + txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START); + for (i = 0; i < 14; i++) + txpower[i] = TXPOWER_FROM_DEV(txpower[i]); + + /* + * Initialize hw_mode information. + */ + spec->num_modes = 2; + spec->num_rates = 12; + spec->tx_power_a = NULL; + spec->tx_power_bg = txpower; + spec->tx_power_default = DEFAULT_TXPOWER; + + if (rt2x00_rf(&rt2x00dev->chip, RF2522)) { + spec->num_channels = ARRAY_SIZE(rf_vals_bg_2522); + spec->channels = rf_vals_bg_2522; + } else if (rt2x00_rf(&rt2x00dev->chip, RF2523)) { + spec->num_channels = ARRAY_SIZE(rf_vals_bg_2523); + spec->channels = rf_vals_bg_2523; + } else if (rt2x00_rf(&rt2x00dev->chip, RF2524)) { + spec->num_channels = ARRAY_SIZE(rf_vals_bg_2524); + spec->channels = rf_vals_bg_2524; + } else if (rt2x00_rf(&rt2x00dev->chip, RF2525)) { + spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525); + spec->channels = rf_vals_bg_2525; + } else if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) { + spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525e); + spec->channels = rf_vals_bg_2525e; + } else if (rt2x00_rf(&rt2x00dev->chip, RF5222)) { + spec->num_channels = ARRAY_SIZE(rf_vals_5222); + spec->channels = rf_vals_5222; + spec->num_modes = 3; + } +} + +static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev) +{ + int retval; + + /* + * Allocate eeprom data. + */ + retval = rt2500usb_validate_eeprom(rt2x00dev); + if (retval) + return retval; + + retval = rt2500usb_init_eeprom(rt2x00dev); + if (retval) + return retval; + + /* + * Initialize hw specifications. + */ + rt2500usb_probe_hw_mode(rt2x00dev); + + /* + * USB devices require scheduled packet filter toggling + *This device requires the beacon ring + */ + __set_bit(PACKET_FILTER_SCHEDULED, &rt2x00dev->flags); + __set_bit(REQUIRE_BEACON_RING, &rt2x00dev->flags); + + /* + * Set the rssi offset. + */ + rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET; + + return 0; +} + +/* + * IEEE80211 stack callback functions. + */ +static int rt2500usb_beacon_update(struct ieee80211_hw *hw, + struct sk_buff *skb, + struct ieee80211_tx_control *control) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct usb_device *usb_dev = + interface_to_usbdev(rt2x00dev_usb(rt2x00dev)); + struct data_ring *ring = + rt2x00lib_get_ring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON); + struct data_entry *beacon; + struct data_entry *guardian; + int length; + + /* + * Just in case the ieee80211 doesn't set this, + * but we need this queue set for the descriptor + * initialization. + */ + control->queue = IEEE80211_TX_QUEUE_BEACON; + + /* + * Obtain 2 entries, one for the guardian byte, + * the second for the actual beacon. + */ + guardian = rt2x00_get_data_entry(ring); + rt2x00_ring_index_inc(ring); + beacon = rt2x00_get_data_entry(ring); + + /* + * First we create the beacon. + */ + skb_push(skb, ring->desc_size); + rt2x00lib_write_tx_desc(rt2x00dev, (struct data_desc *)skb->data, + (struct ieee80211_hdr *)(skb->data + + ring->desc_size), + skb->len - ring->desc_size, control); + + /* + * Length passed to usb_fill_urb cannot be an odd number, + * so add 1 byte to make it even. + */ + length = skb->len; + if (length % 2) + length++; + + usb_fill_bulk_urb(beacon->priv, usb_dev, + usb_sndbulkpipe(usb_dev, 1), + skb->data, length, rt2500usb_beacondone, beacon); + + beacon->skb = skb; + + /* + * Second we need to create the guardian byte. + * We only need a single byte, so lets recycle + * the 'flags' field we are not using for beacons. + */ + guardian->flags = 0; + usb_fill_bulk_urb(guardian->priv, usb_dev, + usb_sndbulkpipe(usb_dev, 1), + &guardian->flags, 1, rt2500usb_beacondone, guardian); + + /* + * Send out the guardian byte. + */ + usb_submit_urb(guardian->priv, GFP_ATOMIC); + + /* + * Enable beacon generation. + */ + rt2500usb_kick_tx_queue(rt2x00dev, IEEE80211_TX_QUEUE_BEACON); + + return 0; +} + +static const struct ieee80211_ops rt2500usb_mac80211_ops = { + .tx = rt2x00mac_tx, + .add_interface = rt2x00mac_add_interface, + .remove_interface = rt2x00mac_remove_interface, + .config = rt2x00mac_config, + .config_interface = rt2x00mac_config_interface, + .set_multicast_list = rt2x00mac_set_multicast_list, + .get_stats = rt2x00mac_get_stats, + .conf_tx = rt2x00mac_conf_tx, + .get_tx_stats = rt2x00mac_get_tx_stats, + .beacon_update = rt2500usb_beacon_update, +}; + +static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = { + .probe_hw = rt2500usb_probe_hw, + .initialize = rt2x00usb_initialize, + .uninitialize = rt2x00usb_uninitialize, + .set_device_state = rt2500usb_set_device_state, + .link_stats = rt2500usb_link_stats, + .reset_tuner = rt2500usb_reset_tuner, + .link_tuner = rt2500usb_link_tuner, + .write_tx_desc = rt2500usb_write_tx_desc, + .write_tx_data = rt2x00usb_write_tx_data, + .kick_tx_queue = rt2500usb_kick_tx_queue, + .fill_rxdone = rt2500usb_fill_rxdone, + .config_mac_addr = rt2500usb_config_mac_addr, + .config_bssid = rt2500usb_config_bssid, + .config_packet_filter = rt2500usb_config_packet_filter, + .config_type = rt2500usb_config_type, + .config = rt2500usb_config, +}; + +static const struct rt2x00_ops rt2500usb_ops = { + .name = DRV_NAME, + .rxd_size = RXD_DESC_SIZE, + .txd_size = TXD_DESC_SIZE, + .eeprom_size = EEPROM_SIZE, + .rf_size = RF_SIZE, + .lib = &rt2500usb_rt2x00_ops, + .hw = &rt2500usb_mac80211_ops, +#ifdef CONFIG_RT2X00_LIB_DEBUGFS + .debugfs = &rt2500usb_rt2x00debug, +#endif /* CONFIG_RT2X00_LIB_DEBUGFS */ +}; + +/* + * rt2500usb module information. + */ +static struct usb_device_id rt2500usb_device_table[] = { + /* ASUS */ + { USB_DEVICE(0x0b05, 0x1706), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x0b05, 0x1707), USB_DEVICE_DATA(&rt2500usb_ops) }, + /* Belkin */ + { USB_DEVICE(0x050d, 0x7050), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x050d, 0x7051), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x050d, 0x705a), USB_DEVICE_DATA(&rt2500usb_ops) }, + /* Cisco Systems */ + { USB_DEVICE(0x13b1, 0x000d), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x13b1, 0x0011), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x13b1, 0x001a), USB_DEVICE_DATA(&rt2500usb_ops) }, + /* Conceptronic */ + { USB_DEVICE(0x14b2, 0x3c02), USB_DEVICE_DATA(&rt2500usb_ops) }, + /* D-LINK */ + { USB_DEVICE(0x2001, 0x3c00), USB_DEVICE_DATA(&rt2500usb_ops) }, + /* Gigabyte */ + { USB_DEVICE(0x1044, 0x8001), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x1044, 0x8007), USB_DEVICE_DATA(&rt2500usb_ops) }, + /* Hercules */ + { USB_DEVICE(0x06f8, 0xe000), USB_DEVICE_DATA(&rt2500usb_ops) }, + /* Melco */ + { USB_DEVICE(0x0411, 0x0066), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x0411, 0x0067), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x0411, 0x008b), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x0411, 0x0097), USB_DEVICE_DATA(&rt2500usb_ops) }, + + /* MSI */ + { USB_DEVICE(0x0db0, 0x6861), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x0db0, 0x6865), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x0db0, 0x6869), USB_DEVICE_DATA(&rt2500usb_ops) }, + /* Ralink */ + { USB_DEVICE(0x148f, 0x1706), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x148f, 0x2570), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x148f, 0x2573), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x148f, 0x9020), USB_DEVICE_DATA(&rt2500usb_ops) }, + /* Siemens */ + { USB_DEVICE(0x0681, 0x3c06), USB_DEVICE_DATA(&rt2500usb_ops) }, + /* SMC */ + { USB_DEVICE(0x0707, 0xee13), USB_DEVICE_DATA(&rt2500usb_ops) }, + /* Spairon */ + { USB_DEVICE(0x114b, 0x0110), USB_DEVICE_DATA(&rt2500usb_ops) }, + /* Trust */ + { USB_DEVICE(0x0eb0, 0x9020), USB_DEVICE_DATA(&rt2500usb_ops) }, + /* Zinwell */ + { USB_DEVICE(0x5a57, 0x0260), USB_DEVICE_DATA(&rt2500usb_ops) }, + { 0, } +}; + +MODULE_AUTHOR(DRV_PROJECT); +MODULE_VERSION(DRV_VERSION); +MODULE_DESCRIPTION("Ralink RT2500 USB Wireless LAN driver."); +MODULE_SUPPORTED_DEVICE("Ralink RT2570 USB chipset based cards"); +MODULE_DEVICE_TABLE(usb, rt2500usb_device_table); +MODULE_LICENSE("GPL"); + +static struct usb_driver rt2500usb_driver = { + .name = DRV_NAME, + .id_table = rt2500usb_device_table, + .probe = rt2x00usb_probe, + .disconnect = rt2x00usb_disconnect, + .suspend = rt2x00usb_suspend, + .resume = rt2x00usb_resume, +}; + +static int __init rt2500usb_init(void) +{ + return usb_register(&rt2500usb_driver); +} + +static void __exit rt2500usb_exit(void) +{ + usb_deregister(&rt2500usb_driver); +} + +module_init(rt2500usb_init); +module_exit(rt2500usb_exit); diff --git a/drivers/net/wireless/rt2x00/rt2500usb.h b/drivers/net/wireless/rt2x00/rt2500usb.h new file mode 100644 index 00000000000..b18d56e73cf --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2500usb.h @@ -0,0 +1,798 @@ +/* + Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the + Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + Module: rt2500usb + Abstract: Data structures and registers for the rt2500usb module. + Supported chipsets: RT2570. + */ + +#ifndef RT2500USB_H +#define RT2500USB_H + +/* + * RF chip defines. + */ +#define RF2522 0x0000 +#define RF2523 0x0001 +#define RF2524 0x0002 +#define RF2525 0x0003 +#define RF2525E 0x0005 +#define RF5222 0x0010 + +/* + * RT2570 version + */ +#define RT2570_VERSION_B 2 +#define RT2570_VERSION_C 3 +#define RT2570_VERSION_D 4 + +/* + * Signal information. + * Defaul offset is required for RSSI <-> dBm conversion. + */ +#define MAX_SIGNAL 100 +#define MAX_RX_SSI -1 +#define DEFAULT_RSSI_OFFSET 120 + +/* + * Register layout information. + */ +#define CSR_REG_BASE 0x0400 +#define CSR_REG_SIZE 0x0100 +#define EEPROM_BASE 0x0000 +#define EEPROM_SIZE 0x006a +#define BBP_SIZE 0x0060 +#define RF_SIZE 0x0014 + +/* + * Control/Status Registers(CSR). + * Some values are set in TU, whereas 1 TU == 1024 us. + */ + +/* + * MAC_CSR0: ASIC revision number. + */ +#define MAC_CSR0 0x0400 + +/* + * MAC_CSR1: System control. + * SOFT_RESET: Software reset, 1: reset, 0: normal. + * BBP_RESET: Hardware reset, 1: reset, 0, release. + * HOST_READY: Host ready after initialization. + */ +#define MAC_CSR1 0x0402 +#define MAC_CSR1_SOFT_RESET FIELD16(0x00000001) +#define MAC_CSR1_BBP_RESET FIELD16(0x00000002) +#define MAC_CSR1_HOST_READY FIELD16(0x00000004) + +/* + * MAC_CSR2: STA MAC register 0. + */ +#define MAC_CSR2 0x0404 +#define MAC_CSR2_BYTE0 FIELD16(0x00ff) +#define MAC_CSR2_BYTE1 FIELD16(0xff00) + +/* + * MAC_CSR3: STA MAC register 1. + */ +#define MAC_CSR3 0x0406 +#define MAC_CSR3_BYTE2 FIELD16(0x00ff) +#define MAC_CSR3_BYTE3 FIELD16(0xff00) + +/* + * MAC_CSR4: STA MAC register 2. + */ +#define MAC_CSR4 0X0408 +#define MAC_CSR4_BYTE4 FIELD16(0x00ff) +#define MAC_CSR4_BYTE5 FIELD16(0xff00) + +/* + * MAC_CSR5: BSSID register 0. + */ +#define MAC_CSR5 0x040a +#define MAC_CSR5_BYTE0 FIELD16(0x00ff) +#define MAC_CSR5_BYTE1 FIELD16(0xff00) + +/* + * MAC_CSR6: BSSID register 1. + */ +#define MAC_CSR6 0x040c +#define MAC_CSR6_BYTE2 FIELD16(0x00ff) +#define MAC_CSR6_BYTE3 FIELD16(0xff00) + +/* + * MAC_CSR7: BSSID register 2. + */ +#define MAC_CSR7 0x040e +#define MAC_CSR7_BYTE4 FIELD16(0x00ff) +#define MAC_CSR7_BYTE5 FIELD16(0xff00) + +/* + * MAC_CSR8: Max frame length. + */ +#define MAC_CSR8 0x0410 +#define MAC_CSR8_MAX_FRAME_UNIT FIELD16(0x0fff) + +/* + * Misc MAC_CSR registers. + * MAC_CSR9: Timer control. + * MAC_CSR10: Slot time. + * MAC_CSR11: IFS. + * MAC_CSR12: EIFS. + * MAC_CSR13: Power mode0. + * MAC_CSR14: Power mode1. + * MAC_CSR15: Power saving transition0 + * MAC_CSR16: Power saving transition1 + */ +#define MAC_CSR9 0x0412 +#define MAC_CSR10 0x0414 +#define MAC_CSR11 0x0416 +#define MAC_CSR12 0x0418 +#define MAC_CSR13 0x041a +#define MAC_CSR14 0x041c +#define MAC_CSR15 0x041e +#define MAC_CSR16 0x0420 + +/* + * MAC_CSR17: Manual power control / status register. + * Allowed state: 0 deep_sleep, 1: sleep, 2: standby, 3: awake. + * SET_STATE: Set state. Write 1 to trigger, self cleared. + * BBP_DESIRE_STATE: BBP desired state. + * RF_DESIRE_STATE: RF desired state. + * BBP_CURRENT_STATE: BBP current state. + * RF_CURRENT_STATE: RF current state. + * PUT_TO_SLEEP: Put to sleep. Write 1 to trigger, self cleared. + */ +#define MAC_CSR17 0x0422 +#define MAC_CSR17_SET_STATE FIELD16(0x0001) +#define MAC_CSR17_BBP_DESIRE_STATE FIELD16(0x0006) +#define MAC_CSR17_RF_DESIRE_STATE FIELD16(0x0018) +#define MAC_CSR17_BBP_CURR_STATE FIELD16(0x0060) +#define MAC_CSR17_RF_CURR_STATE FIELD16(0x0180) +#define MAC_CSR17_PUT_TO_SLEEP FIELD16(0x0200) + +/* + * MAC_CSR18: Wakeup timer register. + * DELAY_AFTER_BEACON: Delay after Tbcn expired in units of 1/16 TU. + * BEACONS_BEFORE_WAKEUP: Number of beacon before wakeup. + * AUTO_WAKE: Enable auto wakeup / sleep mechanism. + */ +#define MAC_CSR18 0x0424 +#define MAC_CSR18_DELAY_AFTER_BEACON FIELD16(0x00ff) +#define MAC_CSR18_BEACONS_BEFORE_WAKEUP FIELD16(0x7f00) +#define MAC_CSR18_AUTO_WAKE FIELD16(0x8000) + +/* + * MAC_CSR19: GPIO control register. + */ +#define MAC_CSR19 0x0426 + +/* + * MAC_CSR20: LED control register. + * ACTIVITY: 0: idle, 1: active. + * LINK: 0: linkoff, 1: linkup. + * ACTIVITY_POLARITY: 0: active low, 1: active high. + */ +#define MAC_CSR20 0x0428 +#define MAC_CSR20_ACTIVITY FIELD16(0x0001) +#define MAC_CSR20_LINK FIELD16(0x0002) +#define MAC_CSR20_ACTIVITY_POLARITY FIELD16(0x0004) + +/* + * MAC_CSR21: LED control register. + * ON_PERIOD: On period, default 70ms. + * OFF_PERIOD: Off period, default 30ms. + */ +#define MAC_CSR21 0x042a +#define MAC_CSR21_ON_PERIOD FIELD16(0x00ff) +#define MAC_CSR21_OFF_PERIOD FIELD16(0xff00) + +/* + * Collision window control register. + */ +#define MAC_CSR22 0x042c + +/* + * Transmit related CSRs. + * Some values are set in TU, whereas 1 TU == 1024 us. + */ + +/* + * TXRX_CSR0: Security control register. + */ +#define TXRX_CSR0 0x0440 +#define TXRX_CSR0_ALGORITHM FIELD16(0x0007) +#define TXRX_CSR0_IV_OFFSET FIELD16(0x01f8) +#define TXRX_CSR0_KEY_ID FIELD16(0x1e00) + +/* + * TXRX_CSR1: TX configuration. + * ACK_TIMEOUT: ACK Timeout in unit of 1-us. + * TSF_OFFSET: TSF offset in MAC header. + * AUTO_SEQUENCE: Let ASIC control frame sequence number. + */ +#define TXRX_CSR1 0x0442 +#define TXRX_CSR1_ACK_TIMEOUT FIELD16(0x00ff) +#define TXRX_CSR1_TSF_OFFSET FIELD16(0x7f00) +#define TXRX_CSR1_AUTO_SEQUENCE FIELD16(0x8000) + +/* + * TXRX_CSR2: RX control. + * DISABLE_RX: Disable rx engine. + * DROP_CRC: Drop crc error. + * DROP_PHYSICAL: Drop physical error. + * DROP_CONTROL: Drop control frame. + * DROP_NOT_TO_ME: Drop not to me unicast frame. + * DROP_TODS: Drop frame tods bit is true. + * DROP_VERSION_ERROR: Drop version error frame. + * DROP_MCAST: Drop multicast frames. + * DROP_BCAST: Drop broadcast frames. + */ +#define TXRX_CSR2 0x0444 +#define TXRX_CSR2_DISABLE_RX FIELD16(0x0001) +#define TXRX_CSR2_DROP_CRC FIELD16(0x0002) +#define TXRX_CSR2_DROP_PHYSICAL FIELD16(0x0004) +#define TXRX_CSR2_DROP_CONTROL FIELD16(0x0008) +#define TXRX_CSR2_DROP_NOT_TO_ME FIELD16(0x0010) +#define TXRX_CSR2_DROP_TODS FIELD16(0x0020) +#define TXRX_CSR2_DROP_VERSION_ERROR FIELD16(0x0040) +#define TXRX_CSR2_DROP_MULTICAST FIELD16(0x0200) +#define TXRX_CSR2_DROP_BROADCAST FIELD16(0x0400) + +/* + * RX BBP ID registers + * TXRX_CSR3: CCK RX BBP ID. + * TXRX_CSR4: OFDM RX BBP ID. + */ +#define TXRX_CSR3 0x0446 +#define TXRX_CSR4 0x0448 + +/* + * TXRX_CSR5: CCK TX BBP ID0. + */ +#define TXRX_CSR5 0x044a +#define TXRX_CSR5_BBP_ID0 FIELD16(0x007f) +#define TXRX_CSR5_BBP_ID0_VALID FIELD16(0x0080) +#define TXRX_CSR5_BBP_ID1 FIELD16(0x7f00) +#define TXRX_CSR5_BBP_ID1_VALID FIELD16(0x8000) + +/* + * TXRX_CSR6: CCK TX BBP ID1. + */ +#define TXRX_CSR6 0x044c +#define TXRX_CSR6_BBP_ID0 FIELD16(0x007f) +#define TXRX_CSR6_BBP_ID0_VALID FIELD16(0x0080) +#define TXRX_CSR6_BBP_ID1 FIELD16(0x7f00) +#define TXRX_CSR6_BBP_ID1_VALID FIELD16(0x8000) + +/* + * TXRX_CSR7: OFDM TX BBP ID0. + */ +#define TXRX_CSR7 0x044e +#define TXRX_CSR7_BBP_ID0 FIELD16(0x007f) +#define TXRX_CSR7_BBP_ID0_VALID FIELD16(0x0080) +#define TXRX_CSR7_BBP_ID1 FIELD16(0x7f00) +#define TXRX_CSR7_BBP_ID1_VALID FIELD16(0x8000) + +/* + * TXRX_CSR5: OFDM TX BBP ID1. + */ +#define TXRX_CSR8 0x0450 +#define TXRX_CSR8_BBP_ID0 FIELD16(0x007f) +#define TXRX_CSR8_BBP_ID0_VALID FIELD16(0x0080) +#define TXRX_CSR8_BBP_ID1 FIELD16(0x7f00) +#define TXRX_CSR8_BBP_ID1_VALID FIELD16(0x8000) + +/* + * TXRX_CSR9: TX ACK time-out. + */ +#define TXRX_CSR9 0x0452 + +/* + * TXRX_CSR10: Auto responder control. + */ +#define TXRX_CSR10 0x0454 +#define TXRX_CSR10_AUTORESPOND_PREAMBLE FIELD16(0x0004) + +/* + * TXRX_CSR11: Auto responder basic rate. + */ +#define TXRX_CSR11 0x0456 + +/* + * ACK/CTS time registers. + */ +#define TXRX_CSR12 0x0458 +#define TXRX_CSR13 0x045a +#define TXRX_CSR14 0x045c +#define TXRX_CSR15 0x045e +#define TXRX_CSR16 0x0460 +#define TXRX_CSR17 0x0462 + +/* + * TXRX_CSR18: Synchronization control register. + */ +#define TXRX_CSR18 0x0464 +#define TXRX_CSR18_OFFSET FIELD16(0x000f) +#define TXRX_CSR18_INTERVAL FIELD16(0xfff0) + +/* + * TXRX_CSR19: Synchronization control register. + * TSF_COUNT: Enable TSF auto counting. + * TSF_SYNC: Tsf sync, 0: disable, 1: infra, 2: ad-hoc/master mode. + * TBCN: Enable Tbcn with reload value. + * BEACON_GEN: Enable beacon generator. + */ +#define TXRX_CSR19 0x0466 +#define TXRX_CSR19_TSF_COUNT FIELD16(0x0001) +#define TXRX_CSR19_TSF_SYNC FIELD16(0x0006) +#define TXRX_CSR19_TBCN FIELD16(0x0008) +#define TXRX_CSR19_BEACON_GEN FIELD16(0x0010) + +/* + * TXRX_CSR20: Tx BEACON offset time control register. + * OFFSET: In units of usec. + * BCN_EXPECT_WINDOW: Default: 2^CWmin + */ +#define TXRX_CSR20 0x0468 +#define TXRX_CSR20_OFFSET FIELD16(0x1fff) +#define TXRX_CSR20_BCN_EXPECT_WINDOW FIELD16(0xe000) + +/* + * TXRX_CSR21 + */ +#define TXRX_CSR21 0x046a + +/* + * Encryption related CSRs. + * + */ + +/* + * SEC_CSR0-SEC_CSR7: Shared key 0, word 0-7 + */ +#define SEC_CSR0 0x0480 +#define SEC_CSR1 0x0482 +#define SEC_CSR2 0x0484 +#define SEC_CSR3 0x0486 +#define SEC_CSR4 0x0488 +#define SEC_CSR5 0x048a +#define SEC_CSR6 0x048c +#define SEC_CSR7 0x048e + +/* + * SEC_CSR8-SEC_CSR15: Shared key 1, word 0-7 + */ +#define SEC_CSR8 0x0490 +#define SEC_CSR9 0x0492 +#define SEC_CSR10 0x0494 +#define SEC_CSR11 0x0496 +#define SEC_CSR12 0x0498 +#define SEC_CSR13 0x049a +#define SEC_CSR14 0x049c +#define SEC_CSR15 0x049e + +/* + * SEC_CSR16-SEC_CSR23: Shared key 2, word 0-7 + */ +#define SEC_CSR16 0x04a0 +#define SEC_CSR17 0x04a2 +#define SEC_CSR18 0X04A4 +#define SEC_CSR19 0x04a6 +#define SEC_CSR20 0x04a8 +#define SEC_CSR21 0x04aa +#define SEC_CSR22 0x04ac +#define SEC_CSR23 0x04ae + +/* + * SEC_CSR24-SEC_CSR31: Shared key 3, word 0-7 + */ +#define SEC_CSR24 0x04b0 +#define SEC_CSR25 0x04b2 +#define SEC_CSR26 0x04b4 +#define SEC_CSR27 0x04b6 +#define SEC_CSR28 0x04b8 +#define SEC_CSR29 0x04ba +#define SEC_CSR30 0x04bc +#define SEC_CSR31 0x04be + +/* + * PHY control registers. + */ + +/* + * PHY_CSR0: RF switching timing control. + */ +#define PHY_CSR0 0x04c0 + +/* + * PHY_CSR1: TX PA configuration. + */ +#define PHY_CSR1 0x04c2 + +/* + * MAC configuration registers. + * PHY_CSR2: TX MAC configuration. + * PHY_CSR3: RX MAC configuration. + */ +#define PHY_CSR2 0x04c4 +#define PHY_CSR3 0x04c6 + +/* + * PHY_CSR4: Interface configuration. + */ +#define PHY_CSR4 0x04c8 +#define PHY_CSR4_LOW_RF_LE FIELD16(0x0001) + +/* + * BBP pre-TX registers. + * PHY_CSR5: BBP pre-TX CCK. + */ +#define PHY_CSR5 0x04ca +#define PHY_CSR5_CCK FIELD16(0x0003) +#define PHY_CSR5_CCK_FLIP FIELD16(0x0004) + +/* + * BBP pre-TX registers. + * PHY_CSR6: BBP pre-TX OFDM. + */ +#define PHY_CSR6 0x04cc +#define PHY_CSR6_OFDM FIELD16(0x0003) +#define PHY_CSR6_OFDM_FLIP FIELD16(0x0004) + +/* + * PHY_CSR7: BBP access register 0. + * BBP_DATA: BBP data. + * BBP_REG_ID: BBP register ID. + * BBP_READ_CONTROL: 0: write, 1: read. + */ +#define PHY_CSR7 0x04ce +#define PHY_CSR7_DATA FIELD16(0x00ff) +#define PHY_CSR7_REG_ID FIELD16(0x7f00) +#define PHY_CSR7_READ_CONTROL FIELD16(0x8000) + +/* + * PHY_CSR8: BBP access register 1. + * BBP_BUSY: ASIC is busy execute BBP programming. + */ +#define PHY_CSR8 0x04d0 +#define PHY_CSR8_BUSY FIELD16(0x0001) + +/* + * PHY_CSR9: RF access register. + * RF_VALUE: Register value + id to program into rf/if. + */ +#define PHY_CSR9 0x04d2 +#define PHY_CSR9_RF_VALUE FIELD16(0xffff) + +/* + * PHY_CSR10: RF access register. + * RF_VALUE: Register value + id to program into rf/if. + * RF_NUMBER_OF_BITS: Number of bits used in value (i:20, rfmd:22). + * RF_IF_SELECT: Chip to program: 0: rf, 1: if. + * RF_PLL_LD: Rf pll_ld status. + * RF_BUSY: 1: asic is busy execute rf programming. + */ +#define PHY_CSR10 0x04d4 +#define PHY_CSR10_RF_VALUE FIELD16(0x00ff) +#define PHY_CSR10_RF_NUMBER_OF_BITS FIELD16(0x1f00) +#define PHY_CSR10_RF_IF_SELECT FIELD16(0x2000) +#define PHY_CSR10_RF_PLL_LD FIELD16(0x4000) +#define PHY_CSR10_RF_BUSY FIELD16(0x8000) + +/* + * STA_CSR0: FCS error count. + * FCS_ERROR: FCS error count, cleared when read. + */ +#define STA_CSR0 0x04e0 +#define STA_CSR0_FCS_ERROR FIELD16(0xffff) + +/* + * STA_CSR1: PLCP error count. + */ +#define STA_CSR1 0x04e2 + +/* + * STA_CSR2: LONG error count. + */ +#define STA_CSR2 0x04e4 + +/* + * STA_CSR3: CCA false alarm. + * FALSE_CCA_ERROR: False CCA error count, cleared when read. + */ +#define STA_CSR3 0x04e6 +#define STA_CSR3_FALSE_CCA_ERROR FIELD16(0xffff) + +/* + * STA_CSR4: RX FIFO overflow. + */ +#define STA_CSR4 0x04e8 + +/* + * STA_CSR5: Beacon sent counter. + */ +#define STA_CSR5 0x04ea + +/* + * Statistics registers + */ +#define STA_CSR6 0x04ec +#define STA_CSR7 0x04ee +#define STA_CSR8 0x04f0 +#define STA_CSR9 0x04f2 +#define STA_CSR10 0x04f4 + +/* + * BBP registers. + * The wordsize of the BBP is 8 bits. + */ + +/* + * R2: TX antenna control + */ +#define BBP_R2_TX_ANTENNA FIELD8(0x03) +#define BBP_R2_TX_IQ_FLIP FIELD8(0x04) + +/* + * R14: RX antenna control + */ +#define BBP_R14_RX_ANTENNA FIELD8(0x03) +#define BBP_R14_RX_IQ_FLIP FIELD8(0x04) + +/* + * RF registers. + */ + +/* + * RF 1 + */ +#define RF1_TUNER FIELD32(0x00020000) + +/* + * RF 3 + */ +#define RF3_TUNER FIELD32(0x00000100) +#define RF3_TXPOWER FIELD32(0x00003e00) + +/* + * EEPROM contents. + */ + +/* + * HW MAC address. + */ +#define EEPROM_MAC_ADDR_0 0x0002 +#define EEPROM_MAC_ADDR_BYTE0 FIELD16(0x00ff) +#define EEPROM_MAC_ADDR_BYTE1 FIELD16(0xff00) +#define EEPROM_MAC_ADDR1 0x0003 +#define EEPROM_MAC_ADDR_BYTE2 FIELD16(0x00ff) +#define EEPROM_MAC_ADDR_BYTE3 FIELD16(0xff00) +#define EEPROM_MAC_ADDR_2 0x0004 +#define EEPROM_MAC_ADDR_BYTE4 FIELD16(0x00ff) +#define EEPROM_MAC_ADDR_BYTE5 FIELD16(0xff00) + +/* + * EEPROM antenna. + * ANTENNA_NUM: Number of antenna's. + * TX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B. + * RX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B. + * LED_MODE: 0: default, 1: TX/RX activity, 2: Single (ignore link), 3: rsvd. + * DYN_TXAGC: Dynamic TX AGC control. + * HARDWARE_RADIO: 1: Hardware controlled radio. Read GPIO0. + * RF_TYPE: Rf_type of this adapter. + */ +#define EEPROM_ANTENNA 0x000b +#define EEPROM_ANTENNA_NUM FIELD16(0x0003) +#define EEPROM_ANTENNA_TX_DEFAULT FIELD16(0x000c) +#define EEPROM_ANTENNA_RX_DEFAULT FIELD16(0x0030) +#define EEPROM_ANTENNA_LED_MODE FIELD16(0x01c0) +#define EEPROM_ANTENNA_DYN_TXAGC FIELD16(0x0200) +#define EEPROM_ANTENNA_HARDWARE_RADIO FIELD16(0x0400) +#define EEPROM_ANTENNA_RF_TYPE FIELD16(0xf800) + +/* + * EEPROM NIC config. + * CARDBUS_ACCEL: 0: enable, 1: disable. + * DYN_BBP_TUNE: 0: enable, 1: disable. + * CCK_TX_POWER: CCK TX power compensation. + */ +#define EEPROM_NIC 0x000c +#define EEPROM_NIC_CARDBUS_ACCEL FIELD16(0x0001) +#define EEPROM_NIC_DYN_BBP_TUNE FIELD16(0x0002) +#define EEPROM_NIC_CCK_TX_POWER FIELD16(0x000c) + +/* + * EEPROM geography. + * GEO: Default geography setting for device. + */ +#define EEPROM_GEOGRAPHY 0x000d +#define EEPROM_GEOGRAPHY_GEO FIELD16(0x0f00) + +/* + * EEPROM BBP. + */ +#define EEPROM_BBP_START 0x000e +#define EEPROM_BBP_SIZE 16 +#define EEPROM_BBP_VALUE FIELD16(0x00ff) +#define EEPROM_BBP_REG_ID FIELD16(0xff00) + +/* + * EEPROM TXPOWER + */ +#define EEPROM_TXPOWER_START 0x001e +#define EEPROM_TXPOWER_SIZE 7 +#define EEPROM_TXPOWER_1 FIELD16(0x00ff) +#define EEPROM_TXPOWER_2 FIELD16(0xff00) + +/* + * EEPROM Tuning threshold + */ +#define EEPROM_BBPTUNE 0x0030 +#define EEPROM_BBPTUNE_THRESHOLD FIELD16(0x00ff) + +/* + * EEPROM BBP R24 Tuning. + */ +#define EEPROM_BBPTUNE_R24 0x0031 +#define EEPROM_BBPTUNE_R24_LOW FIELD16(0x00ff) +#define EEPROM_BBPTUNE_R24_HIGH FIELD16(0xff00) + +/* + * EEPROM BBP R25 Tuning. + */ +#define EEPROM_BBPTUNE_R25 0x0032 +#define EEPROM_BBPTUNE_R25_LOW FIELD16(0x00ff) +#define EEPROM_BBPTUNE_R25_HIGH FIELD16(0xff00) + +/* + * EEPROM BBP R24 Tuning. + */ +#define EEPROM_BBPTUNE_R61 0x0033 +#define EEPROM_BBPTUNE_R61_LOW FIELD16(0x00ff) +#define EEPROM_BBPTUNE_R61_HIGH FIELD16(0xff00) + +/* + * EEPROM BBP VGC Tuning. + */ +#define EEPROM_BBPTUNE_VGC 0x0034 +#define EEPROM_BBPTUNE_VGCUPPER FIELD16(0x00ff) + +/* + * EEPROM BBP R17 Tuning. + */ +#define EEPROM_BBPTUNE_R17 0x0035 +#define EEPROM_BBPTUNE_R17_LOW FIELD16(0x00ff) +#define EEPROM_BBPTUNE_R17_HIGH FIELD16(0xff00) + +/* + * RSSI <-> dBm offset calibration + */ +#define EEPROM_CALIBRATE_OFFSET 0x0036 +#define EEPROM_CALIBRATE_OFFSET_RSSI FIELD16(0x00ff) + +/* + * DMA descriptor defines. + */ +#define TXD_DESC_SIZE ( 5 * sizeof(struct data_desc) ) +#define RXD_DESC_SIZE ( 4 * sizeof(struct data_desc) ) + +/* + * TX descriptor format for TX, PRIO, ATIM and Beacon Ring. + */ + +/* + * Word0 + */ +#define TXD_W0_PACKET_ID FIELD32(0x0000000f) +#define TXD_W0_RETRY_LIMIT FIELD32(0x000000f0) +#define TXD_W0_MORE_FRAG FIELD32(0x00000100) +#define TXD_W0_ACK FIELD32(0x00000200) +#define TXD_W0_TIMESTAMP FIELD32(0x00000400) +#define TXD_W0_OFDM FIELD32(0x00000800) +#define TXD_W0_NEW_SEQ FIELD32(0x00001000) +#define TXD_W0_IFS FIELD32(0x00006000) +#define TXD_W0_DATABYTE_COUNT FIELD32(0x0fff0000) +#define TXD_W0_CIPHER FIELD32(0x20000000) +#define TXD_W0_KEY_ID FIELD32(0xc0000000) + +/* + * Word1 + */ +#define TXD_W1_IV_OFFSET FIELD32(0x0000003f) +#define TXD_W1_AIFS FIELD32(0x000000c0) +#define TXD_W1_CWMIN FIELD32(0x00000f00) +#define TXD_W1_CWMAX FIELD32(0x0000f000) + +/* + * Word2: PLCP information + */ +#define TXD_W2_PLCP_SIGNAL FIELD32(0x000000ff) +#define TXD_W2_PLCP_SERVICE FIELD32(0x0000ff00) +#define TXD_W2_PLCP_LENGTH_LOW FIELD32(0x00ff0000) +#define TXD_W2_PLCP_LENGTH_HIGH FIELD32(0xff000000) + +/* + * Word3 + */ +#define TXD_W3_IV FIELD32(0xffffffff) + +/* + * Word4 + */ +#define TXD_W4_EIV FIELD32(0xffffffff) + +/* + * RX descriptor format for RX Ring. + */ + +/* + * Word0 + */ +#define RXD_W0_UNICAST_TO_ME FIELD32(0x00000002) +#define RXD_W0_MULTICAST FIELD32(0x00000004) +#define RXD_W0_BROADCAST FIELD32(0x00000008) +#define RXD_W0_MY_BSS FIELD32(0x00000010) +#define RXD_W0_CRC_ERROR FIELD32(0x00000020) +#define RXD_W0_OFDM FIELD32(0x00000040) +#define RXD_W0_PHYSICAL_ERROR FIELD32(0x00000080) +#define RXD_W0_CIPHER FIELD32(0x00000100) +#define RXD_W0_CIPHER_ERROR FIELD32(0x00000200) +#define RXD_W0_DATABYTE_COUNT FIELD32(0x0fff0000) + +/* + * Word1 + */ +#define RXD_W1_RSSI FIELD32(0x000000ff) +#define RXD_W1_SIGNAL FIELD32(0x0000ff00) + +/* + * Word2 + */ +#define RXD_W2_IV FIELD32(0xffffffff) + +/* + * Word3 + */ +#define RXD_W3_EIV FIELD32(0xffffffff) + +/* + * Macro's for converting txpower from EEPROM to dscape value + * and from dscape value to register value. + */ +#define MIN_TXPOWER 0 +#define MAX_TXPOWER 31 +#define DEFAULT_TXPOWER 24 + +#define TXPOWER_FROM_DEV(__txpower) \ +({ \ + ((__txpower) > MAX_TXPOWER) ? \ + DEFAULT_TXPOWER : (__txpower); \ +}) + +#define TXPOWER_TO_DEV(__txpower) \ +({ \ + ((__txpower) <= MIN_TXPOWER) ? MIN_TXPOWER : \ + (((__txpower) >= MAX_TXPOWER) ? MAX_TXPOWER : \ + (__txpower)); \ +}) + +#endif /* RT2500USB_H */ diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h new file mode 100644 index 00000000000..80b079d723d --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -0,0 +1,807 @@ +/* + Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the + Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + Module: rt2x00 + Abstract: rt2x00 global information. + */ + +#ifndef RT2X00_H +#define RT2X00_H + +#include +#include +#include +#include +#include + +#include + +#include "rt2x00debug.h" +#include "rt2x00reg.h" +#include "rt2x00ring.h" + +/* + * Module information. + * DRV_NAME should be set within the individual module source files. + */ +#define DRV_VERSION "2.0.8" +#define DRV_PROJECT "http://rt2x00.serialmonkey.com" + +/* + * Debug definitions. + * Debug output has to be enabled during compile time. + */ +#define DEBUG_PRINTK_MSG(__dev, __kernlvl, __lvl, __msg, __args...) \ + printk(__kernlvl "%s -> %s: %s - " __msg, \ + wiphy_name((__dev)->hw->wiphy), __FUNCTION__, __lvl, ##__args) + +#define DEBUG_PRINTK_PROBE(__kernlvl, __lvl, __msg, __args...) \ + printk(__kernlvl "%s -> %s: %s - " __msg, \ + DRV_NAME, __FUNCTION__, __lvl, ##__args) + +#ifdef CONFIG_RT2X00_DEBUG +#define DEBUG_PRINTK(__dev, __kernlvl, __lvl, __msg, __args...) \ + DEBUG_PRINTK_MSG(__dev, __kernlvl, __lvl, __msg, ##__args); +#else +#define DEBUG_PRINTK(__dev, __kernlvl, __lvl, __msg, __args...) \ + do { } while (0) +#endif /* CONFIG_RT2X00_DEBUG */ + +/* + * Various debug levels. + * The debug levels PANIC and ERROR both indicate serious problems, + * for this reason they should never be ignored. + * The special ERROR_PROBE message is for messages that are generated + * when the rt2x00_dev is not yet initialized. + */ +#define PANIC(__dev, __msg, __args...) \ + DEBUG_PRINTK_MSG(__dev, KERN_CRIT, "Panic", __msg, ##__args) +#define ERROR(__dev, __msg, __args...) \ + DEBUG_PRINTK_MSG(__dev, KERN_ERR, "Error", __msg, ##__args) +#define ERROR_PROBE(__msg, __args...) \ + DEBUG_PRINTK_PROBE(KERN_ERR, "Error", __msg, ##__args) +#define WARNING(__dev, __msg, __args...) \ + DEBUG_PRINTK(__dev, KERN_WARNING, "Warning", __msg, ##__args) +#define NOTICE(__dev, __msg, __args...) \ + DEBUG_PRINTK(__dev, KERN_NOTICE, "Notice", __msg, ##__args) +#define INFO(__dev, __msg, __args...) \ + DEBUG_PRINTK(__dev, KERN_INFO, "Info", __msg, ##__args) +#define DEBUG(__dev, __msg, __args...) \ + DEBUG_PRINTK(__dev, KERN_DEBUG, "Debug", __msg, ##__args) +#define EEPROM(__dev, __msg, __args...) \ + DEBUG_PRINTK(__dev, KERN_DEBUG, "EEPROM recovery", __msg, ##__args) + +/* + * Ring sizes. + * Ralink PCI devices demand the Frame size to be a multiple of 128 bytes. + * DATA_FRAME_SIZE is used for TX, RX, ATIM and PRIO rings. + * MGMT_FRAME_SIZE is used for the BEACON ring. + */ +#define DATA_FRAME_SIZE 2432 +#define MGMT_FRAME_SIZE 256 + +/* + * Number of entries in a packet ring. + * PCI devices only need 1 Beacon entry, + * but USB devices require a second because they + * have to send a Guardian byte first. + */ +#define RX_ENTRIES 12 +#define TX_ENTRIES 12 +#define ATIM_ENTRIES 1 +#define BEACON_ENTRIES 2 + +/* + * Standard timing and size defines. + * These values should follow the ieee80211 specifications. + */ +#define ACK_SIZE 14 +#define IEEE80211_HEADER 24 +#define PLCP 48 +#define BEACON 100 +#define PREAMBLE 144 +#define SHORT_PREAMBLE 72 +#define SLOT_TIME 20 +#define SHORT_SLOT_TIME 9 +#define SIFS 10 +#define PIFS ( SIFS + SLOT_TIME ) +#define SHORT_PIFS ( SIFS + SHORT_SLOT_TIME ) +#define DIFS ( PIFS + SLOT_TIME ) +#define SHORT_DIFS ( SHORT_PIFS + SHORT_SLOT_TIME ) +#define EIFS ( SIFS + (8 * (IEEE80211_HEADER + ACK_SIZE)) ) + +/* + * IEEE802.11 header defines + */ +static inline int is_rts_frame(u16 fc) +{ + return !!(((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) && + ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_RTS)); +} + +static inline int is_cts_frame(u16 fc) +{ + return !!(((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) && + ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_CTS)); +} + +static inline int is_probe_resp(u16 fc) +{ + return !!(((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) && + ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP)); +} + +/* + * Chipset identification + * The chipset on the device is composed of a RT and RF chip. + * The chipset combination is important for determining device capabilities. + */ +struct rt2x00_chip { + u16 rt; +#define RT2460 0x0101 +#define RT2560 0x0201 +#define RT2570 0x1201 +#define RT2561 0x0301 +#define RT2561s 0x0302 +#define RT2661 0x0401 +#define RT2571 0x1300 + + u16 rf; + u32 rev; +}; + +/* + * RF register values that belong to a particular channel. + */ +struct rf_channel { + int channel; + u32 rf1; + u32 rf2; + u32 rf3; + u32 rf4; +}; + +/* + * To optimize the quality of the link we need to store + * the quality of received frames and periodically + * optimize the link. + */ +struct link { + /* + * Link tuner counter + * The number of times the link has been tuned + * since the radio has been switched on. + */ + u32 count; + + /* + * Statistics required for Link tuning. + * For the average RSSI value we use the "Walking average" approach. + * When adding RSSI to the average value the following calculation + * is needed: + * + * avg_rssi = ((avg_rssi * 7) + rssi) / 8; + * + * The advantage of this approach is that we only need 1 variable + * to store the average in (No need for a count and a total). + * But more importantly, normal average values will over time + * move less and less towards newly added values this results + * that with link tuning, the device can have a very good RSSI + * for a few minutes but when the device is moved away from the AP + * the average will not decrease fast enough to compensate. + * The walking average compensates this and will move towards + * the new values correctly allowing a effective link tuning. + */ + int avg_rssi; + int vgc_level; + int false_cca; + + /* + * Statistics required for Signal quality calculation. + * For calculating the Signal quality we have to determine + * the total number of success and failed RX and TX frames. + * After that we also use the average RSSI value to help + * determining the signal quality. + * For the calculation we will use the following algorithm: + * + * rssi_percentage = (avg_rssi * 100) / rssi_offset + * rx_percentage = (rx_success * 100) / rx_total + * tx_percentage = (tx_success * 100) / tx_total + * avg_signal = ((WEIGHT_RSSI * avg_rssi) + + * (WEIGHT_TX * tx_percentage) + + * (WEIGHT_RX * rx_percentage)) / 100 + * + * This value should then be checked to not be greated then 100. + */ + int rx_percentage; + int rx_success; + int rx_failed; + int tx_percentage; + int tx_success; + int tx_failed; +#define WEIGHT_RSSI 20 +#define WEIGHT_RX 40 +#define WEIGHT_TX 40 + + /* + * Work structure for scheduling periodic link tuning. + */ + struct delayed_work work; +}; + +/* + * Clear all counters inside the link structure. + * This can be easiest achieved by memsetting everything + * except for the work structure at the end. + */ +static inline void rt2x00_clear_link(struct link *link) +{ + memset(link, 0x00, sizeof(*link) - sizeof(link->work)); + link->rx_percentage = 50; + link->tx_percentage = 50; +} + +/* + * Update the rssi using the walking average approach. + */ +static inline void rt2x00_update_link_rssi(struct link *link, int rssi) +{ + if (!link->avg_rssi) + link->avg_rssi = rssi; + else + link->avg_rssi = ((link->avg_rssi * 7) + rssi) / 8; +} + +/* + * When the avg_rssi is unset or no frames have been received), + * we need to return the default value which needs to be less + * than -80 so the device will select the maximum sensitivity. + */ +static inline int rt2x00_get_link_rssi(struct link *link) +{ + return (link->avg_rssi && link->rx_success) ? link->avg_rssi : -128; +} + +/* + * Interface structure + * Configuration details about the current interface. + */ +struct interface { + /* + * Interface identification. The value is assigned + * to us by the 80211 stack, and is used to request + * new beacons. + */ + int id; + + /* + * Current working type (IEEE80211_IF_TYPE_*). + * This excludes the type IEEE80211_IF_TYPE_MNTR + * since that is counted seperately in the monitor_count + * field. + * When set to INVALID_INTERFACE, no interface is configured. + */ + int type; +#define INVALID_INTERFACE IEEE80211_IF_TYPE_MGMT + + /* + * MAC of the device. + */ + u8 mac[ETH_ALEN]; + + /* + * BBSID of the AP to associate with. + */ + u8 bssid[ETH_ALEN]; + + /* + * Store the packet filter mode for the current interface. + * monitor mode always disabled filtering. But in such + * cases we still need to store the value here in case + * the monitor mode interfaces are removed, while a + * non-monitor mode interface remains. + */ + unsigned short filter; + + /* + * Monitor mode count, the number of interfaces + * in monitor mode that that have been added. + */ + unsigned short monitor_count; +}; + +static inline int is_interface_present(struct interface *intf) +{ + return !!intf->id; +} + +static inline int is_monitor_present(struct interface *intf) +{ + return !!intf->monitor_count; +} + +/* + * Details about the supported modes, rates and channels + * of a particular chipset. This is used by rt2x00lib + * to build the ieee80211_hw_mode array for mac80211. + */ +struct hw_mode_spec { + /* + * Number of modes, rates and channels. + */ + int num_modes; + int num_rates; + int num_channels; + + /* + * txpower values. + */ + const u8 *tx_power_a; + const u8 *tx_power_bg; + u8 tx_power_default; + + /* + * Device/chipset specific value. + */ + const struct rf_channel *channels; +}; + +/* + * rt2x00lib callback functions. + */ +struct rt2x00lib_ops { + /* + * Interrupt handlers. + */ + irq_handler_t irq_handler; + + /* + * Device init handlers. + */ + int (*probe_hw) (struct rt2x00_dev *rt2x00dev); + char *(*get_firmware_name) (struct rt2x00_dev *rt2x00dev); + int (*load_firmware) (struct rt2x00_dev *rt2x00dev, void *data, + const size_t len); + + /* + * Device initialization/deinitialization handlers. + */ + int (*initialize) (struct rt2x00_dev *rt2x00dev); + void (*uninitialize) (struct rt2x00_dev *rt2x00dev); + + /* + * Radio control handlers. + */ + int (*set_device_state) (struct rt2x00_dev *rt2x00dev, + enum dev_state state); + int (*rfkill_poll) (struct rt2x00_dev *rt2x00dev); + void (*link_stats) (struct rt2x00_dev *rt2x00dev); + void (*reset_tuner) (struct rt2x00_dev *rt2x00dev); + void (*link_tuner) (struct rt2x00_dev *rt2x00dev); + + /* + * TX control handlers + */ + void (*write_tx_desc) (struct rt2x00_dev *rt2x00dev, + struct data_desc *txd, + struct data_entry_desc *desc, + struct ieee80211_hdr *ieee80211hdr, + unsigned int length, + struct ieee80211_tx_control *control); + int (*write_tx_data) (struct rt2x00_dev *rt2x00dev, + struct data_ring *ring, struct sk_buff *skb, + struct ieee80211_tx_control *control); + void (*kick_tx_queue) (struct rt2x00_dev *rt2x00dev, + unsigned int queue); + + /* + * RX control handlers + */ + int (*fill_rxdone) (struct data_entry *entry, + int *signal, int *rssi, int *ofdm, int *size); + + /* + * Configuration handlers. + */ + void (*config_mac_addr) (struct rt2x00_dev *rt2x00dev, u8 *mac); + void (*config_bssid) (struct rt2x00_dev *rt2x00dev, u8 *bssid); + void (*config_packet_filter) (struct rt2x00_dev *rt2x00dev, + const unsigned int filter); + void (*config_type) (struct rt2x00_dev *rt2x00dev, const int type); + void (*config) (struct rt2x00_dev *rt2x00dev, const unsigned int flags, + struct ieee80211_conf *conf); +#define CONFIG_UPDATE_PHYMODE ( 1 << 1 ) +#define CONFIG_UPDATE_CHANNEL ( 1 << 2 ) +#define CONFIG_UPDATE_TXPOWER ( 1 << 3 ) +#define CONFIG_UPDATE_ANTENNA ( 1 << 4 ) +#define CONFIG_UPDATE_SLOT_TIME ( 1 << 5 ) +#define CONFIG_UPDATE_BEACON_INT ( 1 << 6 ) +#define CONFIG_UPDATE_ALL 0xffff +}; + +/* + * rt2x00 driver callback operation structure. + */ +struct rt2x00_ops { + const char *name; + const unsigned int rxd_size; + const unsigned int txd_size; + const unsigned int eeprom_size; + const unsigned int rf_size; + const struct rt2x00lib_ops *lib; + const struct ieee80211_ops *hw; +#ifdef CONFIG_RT2X00_LIB_DEBUGFS + const struct rt2x00debug *debugfs; +#endif /* CONFIG_RT2X00_LIB_DEBUGFS */ +}; + +/* + * rt2x00 device structure. + */ +struct rt2x00_dev { + /* + * Device structure. + * The structure stored in here depends on the + * system bus (PCI or USB). + * When accessing this variable, the rt2x00dev_{pci,usb} + * macro's should be used for correct typecasting. + */ + void *dev; +#define rt2x00dev_pci(__dev) ( (struct pci_dev*)(__dev)->dev ) +#define rt2x00dev_usb(__dev) ( (struct usb_interface*)(__dev)->dev ) + + /* + * Callback functions. + */ + const struct rt2x00_ops *ops; + + /* + * IEEE80211 control structure. + */ + struct ieee80211_hw *hw; + struct ieee80211_hw_mode *hwmodes; + unsigned int curr_hwmode; +#define HWMODE_B 0 +#define HWMODE_G 1 +#define HWMODE_A 2 + + /* + * rfkill structure for RF state switching support. + * This will only be compiled in when required. + */ +#ifdef CONFIG_RT2X00_LIB_RFKILL + struct rfkill *rfkill; + struct input_polled_dev *poll_dev; +#endif /* CONFIG_RT2X00_LIB_RFKILL */ + + /* + * If enabled, the debugfs interface structures + * required for deregistration of debugfs. + */ +#ifdef CONFIG_RT2X00_LIB_DEBUGFS + const struct rt2x00debug_intf *debugfs_intf; +#endif /* CONFIG_RT2X00_LIB_DEBUGFS */ + + /* + * Device flags. + * In these flags the current status and some + * of the device capabilities are stored. + */ + unsigned long flags; +#define DEVICE_ENABLED_RADIO 1 +#define DEVICE_ENABLED_RADIO_HW 2 +#define DEVICE_INITIALIZED 3 +#define DEVICE_INITIALIZED_HW 4 +#define REQUIRE_FIRMWARE 5 +#define PACKET_FILTER_SCHEDULED 6 +#define PACKET_FILTER_PENDING 7 +#define INTERFACE_RESUME 8 +#define INTERFACE_ENABLED 9 +#define INTERFACE_ENABLED_MONITOR 10 +#define REQUIRE_BEACON_RING 11 +#define DEVICE_SUPPORT_HW_BUTTON 12 +#define CONFIG_FRAME_TYPE 13 +#define CONFIG_RF_SEQUENCE 14 +/* Hole: Add new Flag here */ +#define CONFIG_EXTERNAL_LNA_A 16 +#define CONFIG_EXTERNAL_LNA_BG 17 +#define CONFIG_DOUBLE_ANTENNA 18 +#define CONFIG_DISABLE_LINK_TUNING 19 + + /* + * Chipset identification. + */ + struct rt2x00_chip chip; + + /* + * hw capability specifications. + */ + struct hw_mode_spec spec; + + /* + * Register pointers + * csr_addr: Base register address. (PCI) + * csr_cache: CSR cache for usb_control_msg. (USB) + */ + void __iomem *csr_addr; + void *csr_cache; + + /* + * Interface configuration. + */ + struct interface interface; + + /* + * Link quality + */ + struct link link; + + /* + * EEPROM data. + */ + __le16 *eeprom; + + /* + * Active RF register values. + * These are stored here so we don't need + * to read the rf registers and can directly + * use this value instead. + * This field should be accessed by using + * rt2x00_rf_read() and rt2x00_rf_write(). + */ + u32 *rf; + + /* + * Current TX power value. + */ + u16 tx_power; + + /* + * LED register (for rt61pci & rt73usb). + */ + u16 led_reg; + + /* + * Led mode (LED_MODE_*) + */ + u8 led_mode; + + /* + * Rssi <-> Dbm offset + */ + u8 rssi_offset; + + /* + * Frequency offset (for rt61pci & rt73usb). + */ + u8 freq_offset; + + /* + * Low level statistics which will have + * to be kept up to date while device is running. + */ + struct ieee80211_low_level_stats low_level_stats; + + /* + * RX configuration information. + */ + struct ieee80211_rx_status rx_status; + + /* + * Beacon scheduled work. + */ + struct work_struct beacon_work; + + /* + * Data ring arrays for RX, TX and Beacon. + * The Beacon array also contains the Atim ring + * if that is supported by the device. + */ + int data_rings; + struct data_ring *rx; + struct data_ring *tx; + struct data_ring *bcn; + + /* + * Firmware image. + */ + const struct firmware *fw; +}; + +/* + * For-each loop for the ring array. + * All rings have been allocated as a single array, + * this means we can create a very simply loop macro + * that is capable of looping through all rings. + * ring_end(), txring_end() and ring_loop() are helper macro's which + * should not be used directly. Instead the following should be used: + * ring_for_each() - Loops through all rings (RX, TX, Beacon & Atim) + * txring_for_each() - Loops through TX data rings (TX only) + * txringall_for_each() - Loops through all TX rings (TX, Beacon & Atim) + */ +#define ring_end(__dev) \ + &(__dev)->rx[(__dev)->data_rings] + +#define txring_end(__dev) \ + &(__dev)->tx[(__dev)->hw->queues] + +#define ring_loop(__entry, __start, __end) \ + for ((__entry) = (__start); \ + prefetch(&(__entry)[1]), (__entry) != (__end); \ + (__entry) = &(__entry)[1]) + +#define ring_for_each(__dev, __entry) \ + ring_loop(__entry, (__dev)->rx, ring_end(__dev)) + +#define txring_for_each(__dev, __entry) \ + ring_loop(__entry, (__dev)->tx, txring_end(__dev)) + +#define txringall_for_each(__dev, __entry) \ + ring_loop(__entry, (__dev)->tx, ring_end(__dev)) + +/* + * Generic RF access. + * The RF is being accessed by word index. + */ +static inline void rt2x00_rf_read(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, u32 *data) +{ + *data = rt2x00dev->rf[word]; +} + +static inline void rt2x00_rf_write(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, u32 data) +{ + rt2x00dev->rf[word] = data; +} + +/* + * Generic EEPROM access. + * The EEPROM is being accessed by word index. + */ +static inline void *rt2x00_eeprom_addr(const struct rt2x00_dev *rt2x00dev, + const unsigned int word) +{ + return (void *)&rt2x00dev->eeprom[word]; +} + +static inline void rt2x00_eeprom_read(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, u16 *data) +{ + *data = le16_to_cpu(rt2x00dev->eeprom[word]); +} + +static inline void rt2x00_eeprom_write(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, u16 data) +{ + rt2x00dev->eeprom[word] = cpu_to_le16(data); +} + +/* + * Chipset handlers + */ +static inline void rt2x00_set_chip(struct rt2x00_dev *rt2x00dev, + const u16 rt, const u16 rf, const u32 rev) +{ + INFO(rt2x00dev, + "Chipset detected - rt: %04x, rf: %04x, rev: %08x.\n", + rt, rf, rev); + + rt2x00dev->chip.rt = rt; + rt2x00dev->chip.rf = rf; + rt2x00dev->chip.rev = rev; +} + +static inline char rt2x00_rt(const struct rt2x00_chip *chipset, const u16 chip) +{ + return (chipset->rt == chip); +} + +static inline char rt2x00_rf(const struct rt2x00_chip *chipset, const u16 chip) +{ + return (chipset->rf == chip); +} + +static inline u16 rt2x00_get_rev(const struct rt2x00_chip *chipset) +{ + return chipset->rev; +} + +static inline u16 rt2x00_rev(const struct rt2x00_chip *chipset, const u32 mask) +{ + return chipset->rev & mask; +} + +/* + * Duration calculations + * The rate variable passed is: 100kbs. + * To convert from bytes to bits we multiply size with 8, + * then the size is multiplied with 10 to make the + * real rate -> rate argument correction. + */ +static inline u16 get_duration(const unsigned int size, const u8 rate) +{ + return ((size * 8 * 10) / rate); +} + +static inline u16 get_duration_res(const unsigned int size, const u8 rate) +{ + return ((size * 8 * 10) % rate); +} + +/* + * Library functions. + */ +struct data_ring *rt2x00lib_get_ring(struct rt2x00_dev *rt2x00dev, + const unsigned int queue); + +/* + * Interrupt context handlers. + */ +void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev); +void rt2x00lib_txdone(struct data_entry *entry, + const int status, const int retry); +void rt2x00lib_rxdone(struct data_entry *entry, struct sk_buff *skb, + const int signal, const int rssi, const int ofdm); + +/* + * TX descriptor initializer + */ +void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev, + struct data_desc *txd, + struct ieee80211_hdr *ieee80211hdr, + unsigned int length, + struct ieee80211_tx_control *control); + +/* + * mac80211 handlers. + */ +int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ieee80211_tx_control *control); +int rt2x00mac_start(struct ieee80211_hw *hw); +void rt2x00mac_stop(struct ieee80211_hw *hw); +int rt2x00mac_add_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf); +void rt2x00mac_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf); +int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf); +int rt2x00mac_config_interface(struct ieee80211_hw *hw, int if_id, + struct ieee80211_if_conf *conf); +void rt2x00mac_set_multicast_list(struct ieee80211_hw *hw, + unsigned short flags, int mc_count); +int rt2x00mac_get_stats(struct ieee80211_hw *hw, + struct ieee80211_low_level_stats *stats); +int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw, + struct ieee80211_tx_queue_stats *stats); +int rt2x00mac_conf_tx(struct ieee80211_hw *hw, int queue, + const struct ieee80211_tx_queue_params *params); + +/* + * Driver allocation handlers. + */ +int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev); +void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev); +#ifdef CONFIG_PM +int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev, pm_message_t state); +int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev); +#endif /* CONFIG_PM */ + +#endif /* RT2X00_H */ diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c new file mode 100644 index 00000000000..de890a17d8f --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -0,0 +1,165 @@ +/* + Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the + Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + Module: rt2x00lib + Abstract: rt2x00 generic configuration routines. + */ + +/* + * Set enviroment defines for rt2x00.h + */ +#define DRV_NAME "rt2x00lib" + +#include +#include + +#include "rt2x00.h" +#include "rt2x00lib.h" + +void rt2x00lib_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *mac) +{ + if (mac) + rt2x00dev->ops->lib->config_mac_addr(rt2x00dev, mac); +} + +void rt2x00lib_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) +{ + if (bssid) + rt2x00dev->ops->lib->config_bssid(rt2x00dev, bssid); +} + +void rt2x00lib_config_packet_filter(struct rt2x00_dev *rt2x00dev, int filter) +{ + /* + * Only configure the device when something has changed, + * or if we are in RESUME state in which case all configuration + * will be forced upon the device. + */ + if (!test_bit(INTERFACE_RESUME, &rt2x00dev->flags) && + !test_bit(PACKET_FILTER_PENDING, &rt2x00dev->flags)) + return; + + /* + * Write configuration to device and clear the update flag. + */ + rt2x00dev->ops->lib->config_packet_filter(rt2x00dev, filter); + __clear_bit(PACKET_FILTER_PENDING, &rt2x00dev->flags); +} + +void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, int type) +{ + struct interface *intf = &rt2x00dev->interface; + + /* + * Fallback when a invalid interface is attempted to + * be configured. If a monitor interface is present, + * we are going configure that, otherwise exit. + */ + if (type == INVALID_INTERFACE) { + if (is_monitor_present(intf)) + type = IEEE80211_IF_TYPE_MNTR; + else + return; + } + + /* + * Only configure the device when something has changed, + * or if we are in RESUME state in which case all configuration + * will be forced upon the device. + */ + if (!test_bit(INTERFACE_RESUME, &rt2x00dev->flags) && + (!(is_interface_present(intf) ^ + test_bit(INTERFACE_ENABLED, &rt2x00dev->flags)) && + !(is_monitor_present(intf) ^ + test_bit(INTERFACE_ENABLED_MONITOR, &rt2x00dev->flags)))) + return; + + /* + * Configure device. + */ + rt2x00dev->ops->lib->config_type(rt2x00dev, type); + + /* + * Update the configuration flags. + */ + if (type != IEEE80211_IF_TYPE_MNTR) { + if (is_interface_present(intf)) + __set_bit(INTERFACE_ENABLED, &rt2x00dev->flags); + else + __clear_bit(INTERFACE_ENABLED, &rt2x00dev->flags); + } else { + if (is_monitor_present(intf)) + __set_bit(INTERFACE_ENABLED_MONITOR, &rt2x00dev->flags); + else + __clear_bit(INTERFACE_ENABLED_MONITOR, + &rt2x00dev->flags); + } +} + +void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, struct ieee80211_conf *conf) +{ + int flags = 0; + + /* + * If we are in RESUME state we should + * force all configuration options. + */ + if (test_bit(INTERFACE_RESUME, &rt2x00dev->flags)) { + flags = CONFIG_UPDATE_ALL; + goto config; + } + + /* + * Check which configuration options have been + * updated and should be send to the device. + */ + if (rt2x00dev->rx_status.phymode != conf->phymode) + flags |= CONFIG_UPDATE_PHYMODE; + if (rt2x00dev->rx_status.channel != conf->channel) + flags |= CONFIG_UPDATE_CHANNEL; + if (rt2x00dev->tx_power != conf->power_level) + flags |= CONFIG_UPDATE_TXPOWER; + if (rt2x00dev->rx_status.antenna == conf->antenna_sel_rx) + flags |= CONFIG_UPDATE_ANTENNA; + + /* + * The following configuration options are never + * stored anywhere and will always be updated. + */ + flags |= CONFIG_UPDATE_SLOT_TIME; + flags |= CONFIG_UPDATE_BEACON_INT; + +config: + rt2x00dev->ops->lib->config(rt2x00dev, flags, conf); + + /* + * Some configuration changes affect the link quality + * which means we need to reset the link tuner. + */ + if (flags & (CONFIG_UPDATE_CHANNEL | CONFIG_UPDATE_ANTENNA)) + rt2x00lib_reset_link_tuner(rt2x00dev); + + rt2x00dev->rx_status.phymode = conf->phymode; + rt2x00dev->rx_status.freq = conf->freq; + rt2x00dev->rx_status.channel = conf->channel; + rt2x00dev->tx_power = conf->power_level; + rt2x00dev->rx_status.antenna = conf->antenna_sel_rx; +} diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c new file mode 100644 index 00000000000..4d2aaecd9df --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00debug.c @@ -0,0 +1,331 @@ +/* + Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the + Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + Module: rt2x00lib + Abstract: rt2x00 debugfs specific routines. + */ + +/* + * Set enviroment defines for rt2x00.h + */ +#define DRV_NAME "rt2x00lib" + +#include +#include +#include +#include + +#include "rt2x00.h" +#include "rt2x00lib.h" + +#define PRINT_LINE_LEN_MAX 32 + +struct rt2x00debug_intf { + /* + * Pointer to driver structure where + * this debugfs entry belongs to. + */ + struct rt2x00_dev *rt2x00dev; + + /* + * Reference to the rt2x00debug structure + * which can be used to communicate with + * the registers. + */ + const struct rt2x00debug *debug; + + /* + * Debugfs entries for: + * - driver folder + * - driver file + * - chipset file + * - register offset/value files + * - eeprom offset/value files + * - bbp offset/value files + * - rf offset/value files + */ + struct dentry *driver_folder; + struct dentry *driver_entry; + struct dentry *chipset_entry; + struct dentry *csr_off_entry; + struct dentry *csr_val_entry; + struct dentry *eeprom_off_entry; + struct dentry *eeprom_val_entry; + struct dentry *bbp_off_entry; + struct dentry *bbp_val_entry; + struct dentry *rf_off_entry; + struct dentry *rf_val_entry; + + /* + * Driver and chipset files will use a data buffer + * that has been created in advance. This will simplify + * the code since we can use the debugfs functions. + */ + struct debugfs_blob_wrapper driver_blob; + struct debugfs_blob_wrapper chipset_blob; + + /* + * Requested offset for each register type. + */ + unsigned int offset_csr; + unsigned int offset_eeprom; + unsigned int offset_bbp; + unsigned int offset_rf; +}; + +static int rt2x00debug_file_open(struct inode *inode, struct file *file) +{ + struct rt2x00debug_intf *intf = inode->i_private; + + file->private_data = inode->i_private; + + if (!try_module_get(intf->debug->owner)) + return -EBUSY; + + return 0; +} + +static int rt2x00debug_file_release(struct inode *inode, struct file *file) +{ + struct rt2x00debug_intf *intf = file->private_data; + + module_put(intf->debug->owner); + + return 0; +} + +#define RT2X00DEBUGFS_OPS_READ(__name, __format, __type) \ +static ssize_t rt2x00debug_read_##__name(struct file *file, \ + char __user *buf, \ + size_t length, \ + loff_t *offset) \ +{ \ + struct rt2x00debug_intf *intf = file->private_data; \ + const struct rt2x00debug *debug = intf->debug; \ + char line[16]; \ + size_t size; \ + __type value; \ + \ + if (*offset) \ + return 0; \ + \ + if (intf->offset_##__name >= debug->__name.word_count) \ + return -EINVAL; \ + \ + debug->__name.read(intf->rt2x00dev, \ + intf->offset_##__name, &value); \ + \ + size = sprintf(line, __format, value); \ + \ + if (copy_to_user(buf, line, size)) \ + return -EFAULT; \ + \ + *offset += size; \ + return size; \ +} + +#define RT2X00DEBUGFS_OPS_WRITE(__name, __type) \ +static ssize_t rt2x00debug_write_##__name(struct file *file, \ + const char __user *buf,\ + size_t length, \ + loff_t *offset) \ +{ \ + struct rt2x00debug_intf *intf = file->private_data; \ + const struct rt2x00debug *debug = intf->debug; \ + char line[16]; \ + size_t size; \ + __type value; \ + \ + if (*offset) \ + return 0; \ + \ + if (!capable(CAP_NET_ADMIN)) \ + return -EPERM; \ + \ + if (intf->offset_##__name >= debug->__name.word_count) \ + return -EINVAL; \ + \ + if (copy_from_user(line, buf, length)) \ + return -EFAULT; \ + \ + size = strlen(line); \ + value = simple_strtoul(line, NULL, 0); \ + \ + debug->__name.write(intf->rt2x00dev, \ + intf->offset_##__name, value); \ + \ + *offset += size; \ + return size; \ +} + +#define RT2X00DEBUGFS_OPS(__name, __format, __type) \ +RT2X00DEBUGFS_OPS_READ(__name, __format, __type); \ +RT2X00DEBUGFS_OPS_WRITE(__name, __type); \ + \ +static const struct file_operations rt2x00debug_fop_##__name = {\ + .owner = THIS_MODULE, \ + .read = rt2x00debug_read_##__name, \ + .write = rt2x00debug_write_##__name, \ + .open = rt2x00debug_file_open, \ + .release = rt2x00debug_file_release, \ +}; + +RT2X00DEBUGFS_OPS(csr, "0x%.8x\n", u32); +RT2X00DEBUGFS_OPS(eeprom, "0x%.4x\n", u16); +RT2X00DEBUGFS_OPS(bbp, "0x%.2x\n", u8); +RT2X00DEBUGFS_OPS(rf, "0x%.8x\n", u32); + +static struct dentry *rt2x00debug_create_file_driver(const char *name, + struct rt2x00debug_intf + *intf, + struct debugfs_blob_wrapper + *blob) +{ + char *data; + + data = kzalloc(3 * PRINT_LINE_LEN_MAX, GFP_KERNEL); + if (!data) + return NULL; + + blob->data = data; + data += sprintf(data, "driver: %s\n", intf->rt2x00dev->ops->name); + data += sprintf(data, "version: %s\n", DRV_VERSION); + data += sprintf(data, "compiled: %s %s\n", __DATE__, __TIME__); + blob->size = strlen(blob->data); + + return debugfs_create_blob(name, S_IRUGO, intf->driver_folder, blob); +} + +static struct dentry *rt2x00debug_create_file_chipset(const char *name, + struct rt2x00debug_intf + *intf, + struct + debugfs_blob_wrapper + *blob) +{ + const struct rt2x00debug *debug = intf->debug; + char *data; + + data = kzalloc(4 * PRINT_LINE_LEN_MAX, GFP_KERNEL); + if (!data) + return NULL; + + blob->data = data; + data += sprintf(data, "csr length: %d\n", debug->csr.word_count); + data += sprintf(data, "eeprom length: %d\n", debug->eeprom.word_count); + data += sprintf(data, "bbp length: %d\n", debug->bbp.word_count); + data += sprintf(data, "rf length: %d\n", debug->rf.word_count); + blob->size = strlen(blob->data); + + return debugfs_create_blob(name, S_IRUGO, intf->driver_folder, blob); +} + +void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) +{ + const struct rt2x00debug *debug = rt2x00dev->ops->debugfs; + struct rt2x00debug_intf *intf; + + intf = kzalloc(sizeof(struct rt2x00debug_intf), GFP_KERNEL); + if (!intf) { + ERROR(rt2x00dev, "Failed to allocate debug handler.\n"); + return; + } + + intf->debug = debug; + intf->rt2x00dev = rt2x00dev; + rt2x00dev->debugfs_intf = intf; + + intf->driver_folder = + debugfs_create_dir(intf->rt2x00dev->ops->name, + rt2x00dev->hw->wiphy->debugfsdir); + if (IS_ERR(intf->driver_folder)) + goto exit; + + intf->driver_entry = + rt2x00debug_create_file_driver("driver", intf, &intf->driver_blob); + if (IS_ERR(intf->driver_entry)) + goto exit; + + intf->chipset_entry = + rt2x00debug_create_file_chipset("chipset", + intf, &intf->chipset_blob); + if (IS_ERR(intf->chipset_entry)) + goto exit; + +#define RT2X00DEBUGFS_CREATE_ENTRY(__intf, __name) \ +({ \ + (__intf)->__name##_off_entry = \ + debugfs_create_u32(__stringify(__name) "_offset", \ + S_IRUGO | S_IWUSR, \ + (__intf)->driver_folder, \ + &(__intf)->offset_##__name); \ + if (IS_ERR((__intf)->__name##_off_entry)) \ + goto exit; \ + \ + (__intf)->__name##_val_entry = \ + debugfs_create_file(__stringify(__name) "_value", \ + S_IRUGO | S_IWUSR, \ + (__intf)->driver_folder, \ + (__intf), &rt2x00debug_fop_##__name);\ + if (IS_ERR((__intf)->__name##_val_entry)) \ + goto exit; \ +}) + + RT2X00DEBUGFS_CREATE_ENTRY(intf, csr); + RT2X00DEBUGFS_CREATE_ENTRY(intf, eeprom); + RT2X00DEBUGFS_CREATE_ENTRY(intf, bbp); + RT2X00DEBUGFS_CREATE_ENTRY(intf, rf); + +#undef RT2X00DEBUGFS_CREATE_ENTRY + + return; + +exit: + rt2x00debug_deregister(rt2x00dev); + ERROR(rt2x00dev, "Failed to register debug handler.\n"); + + return; +} + +void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev) +{ + const struct rt2x00debug_intf *intf = rt2x00dev->debugfs_intf; + + if (unlikely(!intf)) + return; + + debugfs_remove(intf->rf_val_entry); + debugfs_remove(intf->rf_off_entry); + debugfs_remove(intf->bbp_val_entry); + debugfs_remove(intf->bbp_off_entry); + debugfs_remove(intf->eeprom_val_entry); + debugfs_remove(intf->eeprom_off_entry); + debugfs_remove(intf->csr_val_entry); + debugfs_remove(intf->csr_off_entry); + debugfs_remove(intf->chipset_entry); + debugfs_remove(intf->driver_entry); + debugfs_remove(intf->driver_folder); + kfree(intf->chipset_blob.data); + kfree(intf->driver_blob.data); + kfree(intf); + + rt2x00dev->debugfs_intf = NULL; +} diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.h b/drivers/net/wireless/rt2x00/rt2x00debug.h new file mode 100644 index 00000000000..860e8fa3a0d --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00debug.h @@ -0,0 +1,57 @@ +/* + Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the + Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + Module: rt2x00debug + Abstract: Data structures for the rt2x00debug. + */ + +#ifndef RT2X00DEBUG_H +#define RT2X00DEBUG_H + +struct rt2x00_dev; + +#define RT2X00DEBUGFS_REGISTER_ENTRY(__name, __type) \ +struct reg##__name { \ + void (*read)(const struct rt2x00_dev *rt2x00dev, \ + const unsigned int word, __type *data); \ + void (*write)(const struct rt2x00_dev *rt2x00dev, \ + const unsigned int word, __type data); \ + \ + unsigned int word_size; \ + unsigned int word_count; \ +} __name + +struct rt2x00debug { + /* + * Reference to the modules structure. + */ + struct module *owner; + + /* + * Register access entries. + */ + RT2X00DEBUGFS_REGISTER_ENTRY(csr, u32); + RT2X00DEBUGFS_REGISTER_ENTRY(eeprom, u16); + RT2X00DEBUGFS_REGISTER_ENTRY(bbp, u8); + RT2X00DEBUGFS_REGISTER_ENTRY(rf, u32); +}; + +#endif /* RT2X00DEBUG_H */ diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c new file mode 100644 index 00000000000..cd82eeface8 --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -0,0 +1,1133 @@ +/* + Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the + Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + Module: rt2x00lib + Abstract: rt2x00 generic device routines. + */ + +/* + * Set enviroment defines for rt2x00.h + */ +#define DRV_NAME "rt2x00lib" + +#include +#include + +#include "rt2x00.h" +#include "rt2x00lib.h" + +/* + * Ring handler. + */ +struct data_ring *rt2x00lib_get_ring(struct rt2x00_dev *rt2x00dev, + const unsigned int queue) +{ + int beacon = test_bit(REQUIRE_BEACON_RING, &rt2x00dev->flags); + + /* + * Check if we are requesting a reqular TX ring, + * or if we are requesting a Beacon or Atim ring. + * For Atim rings, we should check if it is supported. + */ + if (queue < rt2x00dev->hw->queues && rt2x00dev->tx) + return &rt2x00dev->tx[queue]; + + if (!rt2x00dev->bcn || !beacon) + return NULL; + + if (queue == IEEE80211_TX_QUEUE_BEACON) + return &rt2x00dev->bcn[0]; + else if (queue == IEEE80211_TX_QUEUE_AFTER_BEACON) + return &rt2x00dev->bcn[1]; + + return NULL; +} +EXPORT_SYMBOL_GPL(rt2x00lib_get_ring); + +/* + * Link tuning handlers + */ +static void rt2x00lib_start_link_tuner(struct rt2x00_dev *rt2x00dev) +{ + rt2x00_clear_link(&rt2x00dev->link); + + /* + * Reset the link tuner. + */ + rt2x00dev->ops->lib->reset_tuner(rt2x00dev); + + queue_delayed_work(rt2x00dev->hw->workqueue, + &rt2x00dev->link.work, LINK_TUNE_INTERVAL); +} + +static void rt2x00lib_stop_link_tuner(struct rt2x00_dev *rt2x00dev) +{ + if (delayed_work_pending(&rt2x00dev->link.work)) + cancel_rearming_delayed_work(&rt2x00dev->link.work); +} + +void rt2x00lib_reset_link_tuner(struct rt2x00_dev *rt2x00dev) +{ + rt2x00lib_stop_link_tuner(rt2x00dev); + rt2x00lib_start_link_tuner(rt2x00dev); +} + +/* + * Radio control handlers. + */ +int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev) +{ + int status; + + /* + * Don't enable the radio twice. + * And check if the hardware button has been disabled. + */ + if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) || + (test_bit(DEVICE_SUPPORT_HW_BUTTON, &rt2x00dev->flags) && + !test_bit(DEVICE_ENABLED_RADIO_HW, &rt2x00dev->flags))) + return 0; + + /* + * Enable radio. + */ + status = rt2x00dev->ops->lib->set_device_state(rt2x00dev, + STATE_RADIO_ON); + if (status) + return status; + + __set_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags); + + /* + * Enable RX. + */ + rt2x00lib_toggle_rx(rt2x00dev, 1); + + /* + * Start the TX queues. + */ + ieee80211_start_queues(rt2x00dev->hw); + + return 0; +} + +void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev) +{ + if (!__test_and_clear_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + return; + + /* + * Stop beacon generation. + */ + if (work_pending(&rt2x00dev->beacon_work)) + cancel_work_sync(&rt2x00dev->beacon_work); + + /* + * Stop the TX queues. + */ + ieee80211_stop_queues(rt2x00dev->hw); + + /* + * Disable RX. + */ + rt2x00lib_toggle_rx(rt2x00dev, 0); + + /* + * Disable radio. + */ + rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_RADIO_OFF); +} + +void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, int enable) +{ + enum dev_state state = enable ? STATE_RADIO_RX_ON : STATE_RADIO_RX_OFF; + + /* + * When we are disabling the RX, we should also stop the link tuner. + */ + if (!enable) + rt2x00lib_stop_link_tuner(rt2x00dev); + + rt2x00dev->ops->lib->set_device_state(rt2x00dev, state); + + /* + * When we are enabling the RX, we should also start the link tuner. + */ + if (enable && is_interface_present(&rt2x00dev->interface)) + rt2x00lib_start_link_tuner(rt2x00dev); +} + +static void rt2x00lib_precalculate_link_signal(struct link *link) +{ + if (link->rx_failed || link->rx_success) + link->rx_percentage = + (link->rx_success * 100) / + (link->rx_failed + link->rx_success); + else + link->rx_percentage = 50; + + if (link->tx_failed || link->tx_success) + link->tx_percentage = + (link->tx_success * 100) / + (link->tx_failed + link->tx_success); + else + link->tx_percentage = 50; + + link->rx_success = 0; + link->rx_failed = 0; + link->tx_success = 0; + link->tx_failed = 0; +} + +static int rt2x00lib_calculate_link_signal(struct rt2x00_dev *rt2x00dev, + int rssi) +{ + int rssi_percentage = 0; + int signal; + + /* + * We need a positive value for the RSSI. + */ + if (rssi < 0) + rssi += rt2x00dev->rssi_offset; + + /* + * Calculate the different percentages, + * which will be used for the signal. + */ + if (rt2x00dev->rssi_offset) + rssi_percentage = (rssi * 100) / rt2x00dev->rssi_offset; + + /* + * Add the individual percentages and use the WEIGHT + * defines to calculate the current link signal. + */ + signal = ((WEIGHT_RSSI * rssi_percentage) + + (WEIGHT_TX * rt2x00dev->link.tx_percentage) + + (WEIGHT_RX * rt2x00dev->link.rx_percentage)) / 100; + + return (signal > 100) ? 100 : signal; +} + +static void rt2x00lib_link_tuner(struct work_struct *work) +{ + struct rt2x00_dev *rt2x00dev = + container_of(work, struct rt2x00_dev, link.work.work); + + /* + * Update statistics. + */ + rt2x00dev->ops->lib->link_stats(rt2x00dev); + + rt2x00dev->low_level_stats.dot11FCSErrorCount += + rt2x00dev->link.rx_failed; + + rt2x00lib_precalculate_link_signal(&rt2x00dev->link); + + /* + * Only perform the link tuning when Link tuning + * has been enabled (This could have been disabled from the EEPROM). + */ + if (!test_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags)) + rt2x00dev->ops->lib->link_tuner(rt2x00dev); + + /* + * Increase tuner counter, and reschedule the next link tuner run. + */ + rt2x00dev->link.count++; + queue_delayed_work(rt2x00dev->hw->workqueue, &rt2x00dev->link.work, + LINK_TUNE_INTERVAL); +} + +/* + * Interrupt context handlers. + */ +static void rt2x00lib_beacondone_scheduled(struct work_struct *work) +{ + struct rt2x00_dev *rt2x00dev = + container_of(work, struct rt2x00_dev, beacon_work); + struct data_ring *ring = + rt2x00lib_get_ring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON); + struct data_entry *entry = rt2x00_get_data_entry(ring); + struct sk_buff *skb; + + skb = ieee80211_beacon_get(rt2x00dev->hw, + rt2x00dev->interface.id, + &entry->tx_status.control); + if (!skb) + return; + + rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw, skb, + &entry->tx_status.control); + + dev_kfree_skb(skb); +} + +void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev) +{ + if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + return; + + queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->beacon_work); +} +EXPORT_SYMBOL_GPL(rt2x00lib_beacondone); + +void rt2x00lib_txdone(struct data_entry *entry, + const int status, const int retry) +{ + struct rt2x00_dev *rt2x00dev = entry->ring->rt2x00dev; + struct ieee80211_tx_status *tx_status = &entry->tx_status; + struct ieee80211_low_level_stats *stats = &rt2x00dev->low_level_stats; + int success = !!(status == TX_SUCCESS || status == TX_SUCCESS_RETRY); + int fail = !!(status == TX_FAIL_RETRY || status == TX_FAIL_INVALID || + status == TX_FAIL_OTHER); + + /* + * Update TX statistics. + */ + tx_status->flags = 0; + tx_status->ack_signal = 0; + tx_status->excessive_retries = (status == TX_FAIL_RETRY); + tx_status->retry_count = retry; + rt2x00dev->link.tx_success += success; + rt2x00dev->link.tx_failed += retry + fail; + + if (!(tx_status->control.flags & IEEE80211_TXCTL_NO_ACK)) { + if (success) + tx_status->flags |= IEEE80211_TX_STATUS_ACK; + else + stats->dot11ACKFailureCount++; + } + + tx_status->queue_length = entry->ring->stats.limit; + tx_status->queue_number = tx_status->control.queue; + + if (tx_status->control.flags & IEEE80211_TXCTL_USE_RTS_CTS) { + if (success) + stats->dot11RTSSuccessCount++; + else + stats->dot11RTSFailureCount++; + } + + /* + * Send the tx_status to mac80211, + * that method also cleans up the skb structure. + */ + ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb, tx_status); + entry->skb = NULL; +} +EXPORT_SYMBOL_GPL(rt2x00lib_txdone); + +void rt2x00lib_rxdone(struct data_entry *entry, struct sk_buff *skb, + const int signal, const int rssi, const int ofdm) +{ + struct rt2x00_dev *rt2x00dev = entry->ring->rt2x00dev; + struct ieee80211_rx_status *rx_status = &rt2x00dev->rx_status; + struct ieee80211_hw_mode *mode; + struct ieee80211_rate *rate; + unsigned int i; + int val = 0; + + /* + * Update RX statistics. + */ + mode = &rt2x00dev->hwmodes[rt2x00dev->curr_hwmode]; + for (i = 0; i < mode->num_rates; i++) { + rate = &mode->rates[i]; + + /* + * When frame was received with an OFDM bitrate, + * the signal is the PLCP value. If it was received with + * a CCK bitrate the signal is the rate in 0.5kbit/s. + */ + if (!ofdm) + val = DEVICE_GET_RATE_FIELD(rate->val, RATE); + else + val = DEVICE_GET_RATE_FIELD(rate->val, PLCP); + + if (val == signal) { + val = rate->val; + break; + } + } + + rt2x00_update_link_rssi(&rt2x00dev->link, rssi); + rt2x00dev->link.rx_success++; + rx_status->rate = val; + rx_status->signal = rt2x00lib_calculate_link_signal(rt2x00dev, rssi); + rx_status->ssi = rssi; + + /* + * Send frame to mac80211 + */ + ieee80211_rx_irqsafe(rt2x00dev->hw, skb, rx_status); +} +EXPORT_SYMBOL_GPL(rt2x00lib_rxdone); + +/* + * TX descriptor initializer + */ +void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev, + struct data_desc *txd, + struct ieee80211_hdr *ieee80211hdr, + unsigned int length, + struct ieee80211_tx_control *control) +{ + struct data_entry_desc desc; + struct data_ring *ring; + int tx_rate; + int bitrate; + int duration; + int residual; + u16 frame_control; + u16 seq_ctrl; + + /* + * Make sure the descriptor is properly cleared. + */ + memset(&desc, 0x00, sizeof(desc)); + + /* + * Get ring pointer, if we fail to obtain the + * correct ring, then use the first TX ring. + */ + ring = rt2x00lib_get_ring(rt2x00dev, control->queue); + if (!ring) + ring = rt2x00lib_get_ring(rt2x00dev, IEEE80211_TX_QUEUE_DATA0); + + desc.cw_min = ring->tx_params.cw_min; + desc.cw_max = ring->tx_params.cw_max; + desc.aifs = ring->tx_params.aifs; + + /* + * Identify queue + */ + if (control->queue < rt2x00dev->hw->queues) + desc.queue = control->queue; + else if (control->queue == IEEE80211_TX_QUEUE_BEACON || + control->queue == IEEE80211_TX_QUEUE_AFTER_BEACON) + desc.queue = QUEUE_MGMT; + else + desc.queue = QUEUE_OTHER; + + /* + * Read required fields from ieee80211 header. + */ + frame_control = le16_to_cpu(ieee80211hdr->frame_control); + seq_ctrl = le16_to_cpu(ieee80211hdr->seq_ctrl); + + tx_rate = control->tx_rate; + + /* + * Check if this is a RTS/CTS frame + */ + if (is_rts_frame(frame_control) || is_cts_frame(frame_control)) { + __set_bit(ENTRY_TXD_BURST, &desc.flags); + if (is_rts_frame(frame_control)) + __set_bit(ENTRY_TXD_RTS_FRAME, &desc.flags); + if (control->rts_cts_rate) + tx_rate = control->rts_cts_rate; + } + + /* + * Check for OFDM + */ + if (DEVICE_GET_RATE_FIELD(tx_rate, RATEMASK) & DEV_OFDM_RATEMASK) + __set_bit(ENTRY_TXD_OFDM_RATE, &desc.flags); + + /* + * Check if more fragments are pending + */ + if (ieee80211_get_morefrag(ieee80211hdr)) { + __set_bit(ENTRY_TXD_BURST, &desc.flags); + __set_bit(ENTRY_TXD_MORE_FRAG, &desc.flags); + } + + /* + * Beacons and probe responses require the tsf timestamp + * to be inserted into the frame. + */ + if (control->queue == IEEE80211_TX_QUEUE_BEACON || + is_probe_resp(frame_control)) + __set_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc.flags); + + /* + * Determine with what IFS priority this frame should be send. + * Set ifs to IFS_SIFS when the this is not the first fragment, + * or this fragment came after RTS/CTS. + */ + if ((seq_ctrl & IEEE80211_SCTL_FRAG) > 0 || + test_bit(ENTRY_TXD_RTS_FRAME, &desc.flags)) + desc.ifs = IFS_SIFS; + else + desc.ifs = IFS_BACKOFF; + + /* + * PLCP setup + * Length calculation depends on OFDM/CCK rate. + */ + desc.signal = DEVICE_GET_RATE_FIELD(tx_rate, PLCP); + desc.service = 0x04; + + if (test_bit(ENTRY_TXD_OFDM_RATE, &desc.flags)) { + desc.length_high = ((length + FCS_LEN) >> 6) & 0x3f; + desc.length_low = ((length + FCS_LEN) & 0x3f); + } else { + bitrate = DEVICE_GET_RATE_FIELD(tx_rate, RATE); + + /* + * Convert length to microseconds. + */ + residual = get_duration_res(length + FCS_LEN, bitrate); + duration = get_duration(length + FCS_LEN, bitrate); + + if (residual != 0) { + duration++; + + /* + * Check if we need to set the Length Extension + */ + if (bitrate == 110 && residual <= 3) + desc.service |= 0x80; + } + + desc.length_high = (duration >> 8) & 0xff; + desc.length_low = duration & 0xff; + + /* + * When preamble is enabled we should set the + * preamble bit for the signal. + */ + if (DEVICE_GET_RATE_FIELD(tx_rate, PREAMBLE)) + desc.signal |= 0x08; + } + + rt2x00dev->ops->lib->write_tx_desc(rt2x00dev, txd, &desc, + ieee80211hdr, length, control); +} +EXPORT_SYMBOL_GPL(rt2x00lib_write_tx_desc); + +/* + * Driver initialization handlers. + */ +static void rt2x00lib_channel(struct ieee80211_channel *entry, + const int channel, const int tx_power, + const int value) +{ + entry->chan = channel; + if (channel <= 14) + entry->freq = 2407 + (5 * channel); + else + entry->freq = 5000 + (5 * channel); + entry->val = value; + entry->flag = + IEEE80211_CHAN_W_IBSS | + IEEE80211_CHAN_W_ACTIVE_SCAN | + IEEE80211_CHAN_W_SCAN; + entry->power_level = tx_power; + entry->antenna_max = 0xff; +} + +static void rt2x00lib_rate(struct ieee80211_rate *entry, + const int rate, const int mask, + const int plcp, const int flags) +{ + entry->rate = rate; + entry->val = + DEVICE_SET_RATE_FIELD(rate, RATE) | + DEVICE_SET_RATE_FIELD(mask, RATEMASK) | + DEVICE_SET_RATE_FIELD(plcp, PLCP); + entry->flags = flags; + entry->val2 = entry->val; + if (entry->flags & IEEE80211_RATE_PREAMBLE2) + entry->val2 |= DEVICE_SET_RATE_FIELD(1, PREAMBLE); + entry->min_rssi_ack = 0; + entry->min_rssi_ack_delta = 0; +} + +static int rt2x00lib_probe_hw_modes(struct rt2x00_dev *rt2x00dev, + struct hw_mode_spec *spec) +{ + struct ieee80211_hw *hw = rt2x00dev->hw; + struct ieee80211_hw_mode *hwmodes; + struct ieee80211_channel *channels; + struct ieee80211_rate *rates; + unsigned int i; + unsigned char tx_power; + + hwmodes = kzalloc(sizeof(*hwmodes) * spec->num_modes, GFP_KERNEL); + if (!hwmodes) + goto exit; + + channels = kzalloc(sizeof(*channels) * spec->num_channels, GFP_KERNEL); + if (!channels) + goto exit_free_modes; + + rates = kzalloc(sizeof(*rates) * spec->num_rates, GFP_KERNEL); + if (!rates) + goto exit_free_channels; + + /* + * Initialize Rate list. + */ + rt2x00lib_rate(&rates[0], 10, DEV_RATEMASK_1MB, + 0x00, IEEE80211_RATE_CCK); + rt2x00lib_rate(&rates[1], 20, DEV_RATEMASK_2MB, + 0x01, IEEE80211_RATE_CCK_2); + rt2x00lib_rate(&rates[2], 55, DEV_RATEMASK_5_5MB, + 0x02, IEEE80211_RATE_CCK_2); + rt2x00lib_rate(&rates[3], 110, DEV_RATEMASK_11MB, + 0x03, IEEE80211_RATE_CCK_2); + + if (spec->num_rates > 4) { + rt2x00lib_rate(&rates[4], 60, DEV_RATEMASK_6MB, + 0x0b, IEEE80211_RATE_OFDM); + rt2x00lib_rate(&rates[5], 90, DEV_RATEMASK_9MB, + 0x0f, IEEE80211_RATE_OFDM); + rt2x00lib_rate(&rates[6], 120, DEV_RATEMASK_12MB, + 0x0a, IEEE80211_RATE_OFDM); + rt2x00lib_rate(&rates[7], 180, DEV_RATEMASK_18MB, + 0x0e, IEEE80211_RATE_OFDM); + rt2x00lib_rate(&rates[8], 240, DEV_RATEMASK_24MB, + 0x09, IEEE80211_RATE_OFDM); + rt2x00lib_rate(&rates[9], 360, DEV_RATEMASK_36MB, + 0x0d, IEEE80211_RATE_OFDM); + rt2x00lib_rate(&rates[10], 480, DEV_RATEMASK_48MB, + 0x08, IEEE80211_RATE_OFDM); + rt2x00lib_rate(&rates[11], 540, DEV_RATEMASK_54MB, + 0x0c, IEEE80211_RATE_OFDM); + } + + /* + * Initialize Channel list. + */ + for (i = 0; i < spec->num_channels; i++) { + if (spec->channels[i].channel <= 14) + tx_power = spec->tx_power_bg[i]; + else if (spec->tx_power_a) + tx_power = spec->tx_power_a[i]; + else + tx_power = spec->tx_power_default; + + rt2x00lib_channel(&channels[i], + spec->channels[i].channel, tx_power, i); + } + + /* + * Intitialize 802.11b + * Rates: CCK. + * Channels: OFDM. + */ + if (spec->num_modes > HWMODE_B) { + hwmodes[HWMODE_B].mode = MODE_IEEE80211B; + hwmodes[HWMODE_B].num_channels = 14; + hwmodes[HWMODE_B].num_rates = 4; + hwmodes[HWMODE_B].channels = channels; + hwmodes[HWMODE_B].rates = rates; + } + + /* + * Intitialize 802.11g + * Rates: CCK, OFDM. + * Channels: OFDM. + */ + if (spec->num_modes > HWMODE_G) { + hwmodes[HWMODE_G].mode = MODE_IEEE80211G; + hwmodes[HWMODE_G].num_channels = 14; + hwmodes[HWMODE_G].num_rates = spec->num_rates; + hwmodes[HWMODE_G].channels = channels; + hwmodes[HWMODE_G].rates = rates; + } + + /* + * Intitialize 802.11a + * Rates: OFDM. + * Channels: OFDM, UNII, HiperLAN2. + */ + if (spec->num_modes > HWMODE_A) { + hwmodes[HWMODE_A].mode = MODE_IEEE80211A; + hwmodes[HWMODE_A].num_channels = spec->num_channels - 14; + hwmodes[HWMODE_A].num_rates = spec->num_rates - 4; + hwmodes[HWMODE_A].channels = &channels[14]; + hwmodes[HWMODE_A].rates = &rates[4]; + } + + if (spec->num_modes > HWMODE_G && + ieee80211_register_hwmode(hw, &hwmodes[HWMODE_G])) + goto exit_free_rates; + + if (spec->num_modes > HWMODE_B && + ieee80211_register_hwmode(hw, &hwmodes[HWMODE_B])) + goto exit_free_rates; + + if (spec->num_modes > HWMODE_A && + ieee80211_register_hwmode(hw, &hwmodes[HWMODE_A])) + goto exit_free_rates; + + rt2x00dev->hwmodes = hwmodes; + + return 0; + +exit_free_rates: + kfree(rates); + +exit_free_channels: + kfree(channels); + +exit_free_modes: + kfree(hwmodes); + +exit: + ERROR(rt2x00dev, "Allocation ieee80211 modes failed.\n"); + return -ENOMEM; +} + +static void rt2x00lib_remove_hw(struct rt2x00_dev *rt2x00dev) +{ + if (test_bit(DEVICE_INITIALIZED_HW, &rt2x00dev->flags)) + ieee80211_unregister_hw(rt2x00dev->hw); + + if (likely(rt2x00dev->hwmodes)) { + kfree(rt2x00dev->hwmodes->channels); + kfree(rt2x00dev->hwmodes->rates); + kfree(rt2x00dev->hwmodes); + rt2x00dev->hwmodes = NULL; + } +} + +static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev) +{ + struct hw_mode_spec *spec = &rt2x00dev->spec; + int status; + + /* + * Initialize HW modes. + */ + status = rt2x00lib_probe_hw_modes(rt2x00dev, spec); + if (status) + return status; + + /* + * Register HW. + */ + status = ieee80211_register_hw(rt2x00dev->hw); + if (status) { + rt2x00lib_remove_hw(rt2x00dev); + return status; + } + + __set_bit(DEVICE_INITIALIZED_HW, &rt2x00dev->flags); + + return 0; +} + +/* + * Initialization/uninitialization handlers. + */ +static int rt2x00lib_alloc_entries(struct data_ring *ring, + const u16 max_entries, const u16 data_size, + const u16 desc_size) +{ + struct data_entry *entry; + unsigned int i; + + ring->stats.limit = max_entries; + ring->data_size = data_size; + ring->desc_size = desc_size; + + /* + * Allocate all ring entries. + */ + entry = kzalloc(ring->stats.limit * sizeof(*entry), GFP_KERNEL); + if (!entry) + return -ENOMEM; + + for (i = 0; i < ring->stats.limit; i++) { + entry[i].flags = 0; + entry[i].ring = ring; + entry[i].skb = NULL; + } + + ring->entry = entry; + + return 0; +} + +static int rt2x00lib_alloc_ring_entries(struct rt2x00_dev *rt2x00dev) +{ + struct data_ring *ring; + + /* + * Allocate the RX ring. + */ + if (rt2x00lib_alloc_entries(rt2x00dev->rx, RX_ENTRIES, DATA_FRAME_SIZE, + rt2x00dev->ops->rxd_size)) + return -ENOMEM; + + /* + * First allocate the TX rings. + */ + txring_for_each(rt2x00dev, ring) { + if (rt2x00lib_alloc_entries(ring, TX_ENTRIES, DATA_FRAME_SIZE, + rt2x00dev->ops->txd_size)) + return -ENOMEM; + } + + if (!test_bit(REQUIRE_BEACON_RING, &rt2x00dev->flags)) + return 0; + + /* + * Allocate the BEACON ring. + */ + if (rt2x00lib_alloc_entries(&rt2x00dev->bcn[0], BEACON_ENTRIES, + MGMT_FRAME_SIZE, rt2x00dev->ops->txd_size)) + return -ENOMEM; + + /* + * Allocate the Atim ring. + */ + if (rt2x00lib_alloc_entries(&rt2x00dev->bcn[1], ATIM_ENTRIES, + DATA_FRAME_SIZE, rt2x00dev->ops->txd_size)) + return -ENOMEM; + + return 0; +} + +static void rt2x00lib_free_ring_entries(struct rt2x00_dev *rt2x00dev) +{ + struct data_ring *ring; + + ring_for_each(rt2x00dev, ring) { + kfree(ring->entry); + ring->entry = NULL; + } +} + +void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev) +{ + if (!__test_and_clear_bit(DEVICE_INITIALIZED, &rt2x00dev->flags)) + return; + + /* + * Unregister rfkill. + */ + rt2x00rfkill_unregister(rt2x00dev); + + /* + * Allow the HW to uninitialize. + */ + rt2x00dev->ops->lib->uninitialize(rt2x00dev); + + /* + * Free allocated ring entries. + */ + rt2x00lib_free_ring_entries(rt2x00dev); +} + +int rt2x00lib_initialize(struct rt2x00_dev *rt2x00dev) +{ + int status; + + if (test_bit(DEVICE_INITIALIZED, &rt2x00dev->flags)) + return 0; + + /* + * Allocate all ring entries. + */ + status = rt2x00lib_alloc_ring_entries(rt2x00dev); + if (status) { + ERROR(rt2x00dev, "Ring entries allocation failed.\n"); + return status; + } + + /* + * Initialize the device. + */ + status = rt2x00dev->ops->lib->initialize(rt2x00dev); + if (status) + goto exit; + + __set_bit(DEVICE_INITIALIZED, &rt2x00dev->flags); + + /* + * Register the rfkill handler. + */ + status = rt2x00rfkill_register(rt2x00dev); + if (status) + goto exit_unitialize; + + return 0; + +exit_unitialize: + rt2x00lib_uninitialize(rt2x00dev); + +exit: + rt2x00lib_free_ring_entries(rt2x00dev); + + return status; +} + +/* + * driver allocation handlers. + */ +static int rt2x00lib_alloc_rings(struct rt2x00_dev *rt2x00dev) +{ + struct data_ring *ring; + + /* + * We need the following rings: + * RX: 1 + * TX: hw->queues + * Beacon: 1 (if required) + * Atim: 1 (if required) + */ + rt2x00dev->data_rings = 1 + rt2x00dev->hw->queues + + (2 * test_bit(REQUIRE_BEACON_RING, &rt2x00dev->flags)); + + ring = kzalloc(rt2x00dev->data_rings * sizeof(*ring), GFP_KERNEL); + if (!ring) { + ERROR(rt2x00dev, "Ring allocation failed.\n"); + return -ENOMEM; + } + + /* + * Initialize pointers + */ + rt2x00dev->rx = ring; + rt2x00dev->tx = &rt2x00dev->rx[1]; + if (test_bit(REQUIRE_BEACON_RING, &rt2x00dev->flags)) + rt2x00dev->bcn = &rt2x00dev->tx[rt2x00dev->hw->queues]; + + /* + * Initialize ring parameters. + * cw_min: 2^5 = 32. + * cw_max: 2^10 = 1024. + */ + ring_for_each(rt2x00dev, ring) { + ring->rt2x00dev = rt2x00dev; + ring->tx_params.aifs = 2; + ring->tx_params.cw_min = 5; + ring->tx_params.cw_max = 10; + } + + return 0; +} + +static void rt2x00lib_free_rings(struct rt2x00_dev *rt2x00dev) +{ + kfree(rt2x00dev->rx); + rt2x00dev->rx = NULL; + rt2x00dev->tx = NULL; + rt2x00dev->bcn = NULL; +} + +int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) +{ + int retval = -ENOMEM; + + /* + * Let the driver probe the device to detect the capabilities. + */ + retval = rt2x00dev->ops->lib->probe_hw(rt2x00dev); + if (retval) { + ERROR(rt2x00dev, "Failed to allocate device.\n"); + goto exit; + } + + /* + * Initialize configuration work. + */ + INIT_WORK(&rt2x00dev->beacon_work, rt2x00lib_beacondone_scheduled); + INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00lib_link_tuner); + + /* + * Reset current working type. + */ + rt2x00dev->interface.type = INVALID_INTERFACE; + + /* + * Allocate ring array. + */ + retval = rt2x00lib_alloc_rings(rt2x00dev); + if (retval) + goto exit; + + /* + * Initialize ieee80211 structure. + */ + retval = rt2x00lib_probe_hw(rt2x00dev); + if (retval) { + ERROR(rt2x00dev, "Failed to initialize hw.\n"); + goto exit; + } + + /* + * Allocatie rfkill. + */ + retval = rt2x00rfkill_allocate(rt2x00dev); + if (retval) + goto exit; + + /* + * Open the debugfs entry. + */ + rt2x00debug_register(rt2x00dev); + + return 0; + +exit: + rt2x00lib_remove_dev(rt2x00dev); + + return retval; +} +EXPORT_SYMBOL_GPL(rt2x00lib_probe_dev); + +void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev) +{ + /* + * Disable radio. + */ + rt2x00lib_disable_radio(rt2x00dev); + + /* + * Uninitialize device. + */ + rt2x00lib_uninitialize(rt2x00dev); + + /* + * Close debugfs entry. + */ + rt2x00debug_deregister(rt2x00dev); + + /* + * Free rfkill + */ + rt2x00rfkill_free(rt2x00dev); + + /* + * Free ieee80211_hw memory. + */ + rt2x00lib_remove_hw(rt2x00dev); + + /* + * Free firmware image. + */ + rt2x00lib_free_firmware(rt2x00dev); + + /* + * Free ring structures. + */ + rt2x00lib_free_rings(rt2x00dev); +} +EXPORT_SYMBOL_GPL(rt2x00lib_remove_dev); + +/* + * Device state handlers + */ +#ifdef CONFIG_PM +int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev, pm_message_t state) +{ + int retval; + + NOTICE(rt2x00dev, "Going to sleep.\n"); + + /* + * Disable radio and unitialize all items + * that must be recreated on resume. + */ + rt2x00lib_disable_radio(rt2x00dev); + rt2x00lib_uninitialize(rt2x00dev); + rt2x00debug_deregister(rt2x00dev); + + /* + * Set device mode to sleep for power management. + */ + retval = rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_SLEEP); + if (retval) + return retval; + + return 0; +} +EXPORT_SYMBOL_GPL(rt2x00lib_suspend); + +int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) +{ + struct interface *intf = &rt2x00dev->interface; + int retval; + + NOTICE(rt2x00dev, "Waking up.\n"); + __set_bit(INTERFACE_RESUME, &rt2x00dev->flags); + + /* + * Open the debugfs entry. + */ + rt2x00debug_register(rt2x00dev); + + /* + * Reinitialize device and all active interfaces. + */ + retval = rt2x00mac_start(rt2x00dev->hw); + if (retval) + goto exit; + + /* + * Reconfigure device. + */ + retval = rt2x00mac_config(rt2x00dev->hw, &rt2x00dev->hw->conf); + if (retval) + goto exit; + + rt2x00lib_config_mac_addr(rt2x00dev, intf->mac); + rt2x00lib_config_bssid(rt2x00dev, intf->bssid); + rt2x00lib_config_type(rt2x00dev, intf->type); + rt2x00lib_config_packet_filter(rt2x00dev, intf->filter); + + /* + * When in Master or Ad-hoc mode, + * restart Beacon transmitting by faking a beacondone event. + */ + if (intf->type == IEEE80211_IF_TYPE_AP || + intf->type == IEEE80211_IF_TYPE_IBSS) + rt2x00lib_beacondone(rt2x00dev); + + __clear_bit(INTERFACE_RESUME, &rt2x00dev->flags); + + return 0; + +exit: + rt2x00lib_disable_radio(rt2x00dev); + rt2x00lib_uninitialize(rt2x00dev); + rt2x00debug_deregister(rt2x00dev); + + __clear_bit(INTERFACE_RESUME, &rt2x00dev->flags); + + return retval; +} +EXPORT_SYMBOL_GPL(rt2x00lib_resume); +#endif /* CONFIG_PM */ + +/* + * rt2x00lib module information. + */ +MODULE_AUTHOR(DRV_PROJECT); +MODULE_VERSION(DRV_VERSION); +MODULE_DESCRIPTION("rt2x00 library"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/wireless/rt2x00/rt2x00firmware.c b/drivers/net/wireless/rt2x00/rt2x00firmware.c new file mode 100644 index 00000000000..236025f8b90 --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00firmware.c @@ -0,0 +1,124 @@ +/* + Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the + Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + Module: rt2x00lib + Abstract: rt2x00 firmware loading routines. + */ + +/* + * Set enviroment defines for rt2x00.h + */ +#define DRV_NAME "rt2x00lib" + +#include +#include +#include + +#include "rt2x00.h" +#include "rt2x00lib.h" + +static int rt2x00lib_request_firmware(struct rt2x00_dev *rt2x00dev) +{ + struct device *device = wiphy_dev(rt2x00dev->hw->wiphy); + const struct firmware *fw; + char *fw_name; + int retval; + u16 crc; + u16 tmp; + + /* + * Read correct firmware from harddisk. + */ + fw_name = rt2x00dev->ops->lib->get_firmware_name(rt2x00dev); + if (!fw_name) { + ERROR(rt2x00dev, + "Invalid firmware filename.\n" + "Please file bug report to %s.\n", DRV_PROJECT); + return -EINVAL; + } + + INFO(rt2x00dev, "Loading firmware file '%s'.\n", fw_name); + + retval = request_firmware(&fw, fw_name, device); + if (retval) { + ERROR(rt2x00dev, "Failed to request Firmware.\n"); + return retval; + } + + if (!fw || !fw->size || !fw->data) { + ERROR(rt2x00dev, "Failed to read Firmware.\n"); + return -ENOENT; + } + + /* + * Validate the firmware using 16 bit CRC. + * The last 2 bytes of the firmware are the CRC + * so substract those 2 bytes from the CRC checksum, + * and set those 2 bytes to 0 when calculating CRC. + */ + tmp = 0; + crc = crc_itu_t(0, fw->data, fw->size - 2); + crc = crc_itu_t(crc, (u8 *)&tmp, 2); + + if (crc != (fw->data[fw->size - 2] << 8 | fw->data[fw->size - 1])) { + ERROR(rt2x00dev, "Firmware CRC error.\n"); + retval = -ENOENT; + goto exit; + } + + INFO(rt2x00dev, "Firmware detected - version: %d.%d.\n", + fw->data[fw->size - 4], fw->data[fw->size - 3]); + + rt2x00dev->fw = fw; + + return 0; + +exit: + release_firmware(fw); + + return retval; +} + +int rt2x00lib_load_firmware(struct rt2x00_dev *rt2x00dev) +{ + int retval; + + if (!rt2x00dev->fw) { + retval = rt2x00lib_request_firmware(rt2x00dev); + if (retval) + return retval; + } + + /* + * Send firmware to the device. + */ + retval = rt2x00dev->ops->lib->load_firmware(rt2x00dev, + rt2x00dev->fw->data, + rt2x00dev->fw->size); + return retval; +} + +void rt2x00lib_free_firmware(struct rt2x00_dev *rt2x00dev) +{ + release_firmware(rt2x00dev->fw); + rt2x00dev->fw = NULL; +} + diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h new file mode 100644 index 00000000000..3324090a96a --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -0,0 +1,125 @@ +/* + Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the + Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + Module: rt2x00lib + Abstract: Data structures and definitions for the rt2x00lib module. + */ + +#ifndef RT2X00LIB_H +#define RT2X00LIB_H + +/* + * Interval defines + */ +#define LINK_TUNE_INTERVAL ( round_jiffies(HZ) ) +#define RFKILL_POLL_INTERVAL ( HZ / 4 ) + +/* + * Radio control handlers. + */ +int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev); +void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev); +void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, int enable); +void rt2x00lib_reset_link_tuner(struct rt2x00_dev *rt2x00dev); + +/* + * Initialization handlers. + */ +int rt2x00lib_initialize(struct rt2x00_dev *rt2x00dev); +void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev); + +/* + * Configuration handlers. + */ +void rt2x00lib_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *mac); +void rt2x00lib_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid); +void rt2x00lib_config_packet_filter(struct rt2x00_dev *rt2x00dev, int filter); +void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, int type); +void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, struct ieee80211_conf *conf); + +/* + * Firmware handlers. + */ +#ifdef CONFIG_RT2X00_LIB_FIRMWARE +int rt2x00lib_load_firmware(struct rt2x00_dev *rt2x00dev); +void rt2x00lib_free_firmware(struct rt2x00_dev *rt2x00dev); +#else +static inline int rt2x00lib_load_firmware(struct rt2x00_dev *rt2x00dev) +{ + return 0; +} +static inline void rt2x00lib_free_firmware(struct rt2x00_dev *rt2x00dev) +{ +} +#endif /* CONFIG_RT2X00_LIB_FIRMWARE */ + +/* + * Debugfs handlers. + */ +#ifdef CONFIG_RT2X00_LIB_DEBUGFS +void rt2x00debug_register(struct rt2x00_dev *rt2x00dev); +void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev); +#else +static inline void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) +{ +} + +static inline void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev) +{ +} +#endif /* CONFIG_RT2X00_LIB_DEBUGFS */ + +/* + * RFkill handlers. + */ +#ifdef CONFIG_RT2X00_LIB_RFKILL +int rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev); +void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev); +int rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev); +void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev); +#else +static inline int rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev) +{ + /* + * Force enable this flag, this will assure that + * devices with a hardware button but without rfkill support + * can still use their hardware. + */ + __set_bit(DEVICE_ENABLED_RADIO_HW, &rt2x00dev->flags); + + return 0; +} + +static inline void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev) +{ +} + +static inline int rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev) +{ + return 0; +} + +static inline void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev) +{ +} +#endif /* CONFIG_RT2X00_LIB_RFKILL */ + +#endif /* RT2X00LIB_H */ diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c new file mode 100644 index 00000000000..778ed41e21e --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -0,0 +1,459 @@ +/* + Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the + Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + Module: rt2x00mac + Abstract: rt2x00 generic mac80211 routines. + */ + +/* + * Set enviroment defines for rt2x00.h + */ +#define DRV_NAME "rt2x00lib" + +#include +#include + +#include "rt2x00.h" +#include "rt2x00lib.h" + +static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, + struct data_ring *ring, + struct sk_buff *frag_skb, + struct ieee80211_tx_control *control) +{ + struct sk_buff *skb; + int size; + + if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) + size = sizeof(struct ieee80211_cts); + else + size = sizeof(struct ieee80211_rts); + + skb = dev_alloc_skb(size + rt2x00dev->hw->extra_tx_headroom); + if (!skb) { + WARNING(rt2x00dev, "Failed to create RTS/CTS frame.\n"); + return NETDEV_TX_BUSY; + } + + skb_reserve(skb, rt2x00dev->hw->extra_tx_headroom); + skb_put(skb, size); + + if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) + ieee80211_ctstoself_get(rt2x00dev->hw, rt2x00dev->interface.id, + frag_skb->data, frag_skb->len, control, + (struct ieee80211_cts *)(skb->data)); + else + ieee80211_rts_get(rt2x00dev->hw, rt2x00dev->interface.id, + frag_skb->data, frag_skb->len, control, + (struct ieee80211_rts *)(skb->data)); + + if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, ring, skb, control)) { + WARNING(rt2x00dev, "Failed to send RTS/CTS frame.\n"); + return NETDEV_TX_BUSY; + } + + return NETDEV_TX_OK; +} + +int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ieee80211_tx_control *control) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data; + struct data_ring *ring; + u16 frame_control; + + /* + * Determine which ring to put packet on. + */ + ring = rt2x00lib_get_ring(rt2x00dev, control->queue); + if (unlikely(!ring)) { + ERROR(rt2x00dev, + "Attempt to send packet over invalid queue %d.\n" + "Please file bug report to %s.\n", + control->queue, DRV_PROJECT); + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + + /* + * If CTS/RTS is required. and this frame is not CTS or RTS, + * create and queue that frame first. But make sure we have + * at least enough entries available to send this CTS/RTS + * frame as well as the data frame. + */ + frame_control = le16_to_cpu(ieee80211hdr->frame_control); + if (!is_rts_frame(frame_control) && !is_cts_frame(frame_control) && + (control->flags & (IEEE80211_TXCTL_USE_RTS_CTS | + IEEE80211_TXCTL_USE_CTS_PROTECT))) { + if (rt2x00_ring_free(ring) <= 1) + return NETDEV_TX_BUSY; + + if (rt2x00mac_tx_rts_cts(rt2x00dev, ring, skb, control)) + return NETDEV_TX_BUSY; + } + + if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, ring, skb, control)) + return NETDEV_TX_BUSY; + + if (rt2x00dev->ops->lib->kick_tx_queue) + rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, control->queue); + + return NETDEV_TX_OK; +} +EXPORT_SYMBOL_GPL(rt2x00mac_tx); + +int rt2x00mac_start(struct ieee80211_hw *hw) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + int status; + + if (test_bit(DEVICE_INITIALIZED, &rt2x00dev->flags)) + return 0; + + /* + * If this is the first interface which is added, + * we should load the firmware now. + */ + if (test_bit(REQUIRE_FIRMWARE, &rt2x00dev->flags)) { + status = rt2x00lib_load_firmware(rt2x00dev); + if (status) + return status; + } + + /* + * Initialize the device. + */ + status = rt2x00lib_initialize(rt2x00dev); + if (status) + return status; + + /* + * Enable radio. + */ + status = rt2x00lib_enable_radio(rt2x00dev); + if (status) { + rt2x00lib_uninitialize(rt2x00dev); + return status; + } + + return 0; +} +EXPORT_SYMBOL_GPL(rt2x00mac_start); + +void rt2x00mac_stop(struct ieee80211_hw *hw) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + + /* + * Perhaps we can add something smarter here, + * but for now just disabling the radio should do. + */ + rt2x00lib_disable_radio(rt2x00dev); +} +EXPORT_SYMBOL_GPL(rt2x00mac_stop); + +int rt2x00mac_add_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct interface *intf = &rt2x00dev->interface; + int retval; + + /* + * We only support 1 non-monitor interface. + */ + if (conf->type != IEEE80211_IF_TYPE_MNTR && is_interface_present(intf)) + return -ENOBUFS; + + /* + * HACK: Placeholder until start/stop handler has been + * added to the mac80211 callback functions structure. + */ + retval = rt2x00mac_start(hw); + if (retval) + return retval; + + /* + * We support muliple monitor mode interfaces. + * All we need to do is increase the monitor_count. + */ + if (conf->type == IEEE80211_IF_TYPE_MNTR) { + intf->monitor_count++; + } else { + intf->id = conf->if_id; + intf->type = conf->type; + if (conf->type == IEEE80211_IF_TYPE_AP) + memcpy(&intf->bssid, conf->mac_addr, ETH_ALEN); + memcpy(&intf->mac, conf->mac_addr, ETH_ALEN); + intf->filter = 0; + } + + /* + * Configure interface. + * The MAC adddress must be configured after the device + * has been initialized. Else the device can reset the + * MAC registers. + */ + rt2x00lib_config_mac_addr(rt2x00dev, intf->mac); + rt2x00lib_config_type(rt2x00dev, conf->type); + rt2x00lib_config_packet_filter(rt2x00dev, intf->filter); + + return 0; +} +EXPORT_SYMBOL_GPL(rt2x00mac_add_interface); + +void rt2x00mac_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct interface *intf = &rt2x00dev->interface; + + /* + * We only support 1 non-monitor interface. + */ + if (conf->type != IEEE80211_IF_TYPE_MNTR && !is_interface_present(intf)) + return; + + /* + * When removing an monitor interface, decrease monitor_count. + * For non-monitor interfaces, all interface data needs to be reset. + */ + if (conf->type == IEEE80211_IF_TYPE_MNTR) { + intf->monitor_count--; + } else if (intf->type == conf->type) { + intf->id = 0; + intf->type = INVALID_INTERFACE; + memset(&intf->bssid, 0x00, ETH_ALEN); + memset(&intf->mac, 0x00, ETH_ALEN); + intf->filter = 0; + } + + /* + * Make sure the bssid and mac address registers + * are cleared to prevent false ACKing of frames. + */ + rt2x00lib_config_mac_addr(rt2x00dev, intf->mac); + rt2x00lib_config_bssid(rt2x00dev, intf->bssid); + rt2x00lib_config_type(rt2x00dev, intf->type); + + /* + * HACK: Placeholder untill start/stop handler has been + * added to the mac80211 callback functions structure. + */ + rt2x00mac_stop(hw); +} +EXPORT_SYMBOL_GPL(rt2x00mac_remove_interface); + +int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + + /* + * If the device is not initialized we shouldn't accept + * any configuration changes. Mac80211 might be calling + * this function while we are trying to remove the device + * or perhaps suspending it. + */ + if (!test_bit(DEVICE_INITIALIZED, &rt2x00dev->flags)) + return 0; + + /* + * Check if we need to disable the radio, + * if this is not the case, at least the RX must be disabled. + */ + if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) { + if (!conf->radio_enabled) + rt2x00lib_disable_radio(rt2x00dev); + else + rt2x00lib_toggle_rx(rt2x00dev, 0); + } + + rt2x00lib_config(rt2x00dev, conf); + + /* + * If promisc mode cannot be configured in irq context, + * then it is now the time to configure it. + */ + if (test_bit(PACKET_FILTER_SCHEDULED, &rt2x00dev->flags)) + rt2x00lib_config_packet_filter(rt2x00dev, + rt2x00dev->interface.filter); + + /* + * Reenable RX only if the radio should be on. + */ + if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + rt2x00lib_toggle_rx(rt2x00dev, 1); + else if (conf->radio_enabled) + return rt2x00lib_enable_radio(rt2x00dev); + + return 0; +} +EXPORT_SYMBOL_GPL(rt2x00mac_config); + +int rt2x00mac_config_interface(struct ieee80211_hw *hw, int if_id, + struct ieee80211_if_conf *conf) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct interface *intf = &rt2x00dev->interface; + int status; + + /* + * If the device is not initialized we shouldn't accept + * any configuration changes. Mac80211 might be calling + * this function while we are trying to remove the device + * or perhaps suspending it. + */ + if (!test_bit(DEVICE_INITIALIZED, &rt2x00dev->flags)) + return 0; + + /* + * Monitor mode does not need configuring. + * If the given type does not match the configured type, + * there has been a problem. + */ + if (conf->type == IEEE80211_IF_TYPE_MNTR) + return 0; + else if (conf->type != intf->type) + return -EINVAL; + + /* + * If the interface does not work in master mode, + * then the bssid value in the interface structure + * should now be set. + */ + if (conf->type != IEEE80211_IF_TYPE_AP) + memcpy(&intf->bssid, conf->bssid, ETH_ALEN); + rt2x00lib_config_bssid(rt2x00dev, intf->bssid); + + /* + * We only need to initialize the beacon when master mode is enabled. + */ + if (conf->type != IEEE80211_IF_TYPE_AP || !conf->beacon) + return 0; + + status = rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw, + conf->beacon, + conf->beacon_control); + if (status) + dev_kfree_skb(conf->beacon); + + return status; +} +EXPORT_SYMBOL_GPL(rt2x00mac_config_interface); + +void rt2x00mac_set_multicast_list(struct ieee80211_hw *hw, + unsigned short flags, int mc_count) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + + /* + * Check if the new state is different then the old state. + */ + if (rt2x00dev->interface.filter == flags) + return; + + rt2x00dev->interface.filter = flags; + + /* + * Raise the pending bit to indicate the + * packet filter should be updated. + */ + __set_bit(PACKET_FILTER_PENDING, &rt2x00dev->flags); + + /* + * Check if Packet filter actions are allowed in + * atomic context. If not, raise the pending flag and + * let it be. + */ + if (!test_bit(PACKET_FILTER_SCHEDULED, &rt2x00dev->flags) || + !in_atomic()) + rt2x00lib_config_packet_filter(rt2x00dev, flags); +} +EXPORT_SYMBOL_GPL(rt2x00mac_set_multicast_list); + +int rt2x00mac_get_stats(struct ieee80211_hw *hw, + struct ieee80211_low_level_stats *stats) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + + /* + * The dot11ACKFailureCount, dot11RTSFailureCount and + * dot11RTSSuccessCount are updated in interrupt time. + * dot11FCSErrorCount is updated in the link tuner. + */ + memcpy(stats, &rt2x00dev->low_level_stats, sizeof(*stats)); + + return 0; +} +EXPORT_SYMBOL_GPL(rt2x00mac_get_stats); + +int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw, + struct ieee80211_tx_queue_stats *stats) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + unsigned int i; + + for (i = 0; i < hw->queues; i++) + memcpy(&stats->data[i], &rt2x00dev->tx[i].stats, + sizeof(rt2x00dev->tx[i].stats)); + + return 0; +} +EXPORT_SYMBOL_GPL(rt2x00mac_get_tx_stats); + +int rt2x00mac_conf_tx(struct ieee80211_hw *hw, int queue, + const struct ieee80211_tx_queue_params *params) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct data_ring *ring; + + ring = rt2x00lib_get_ring(rt2x00dev, queue); + if (unlikely(!ring)) + return -EINVAL; + + /* + * The passed variables are stored as real value ((2^n)-1). + * Ralink registers require to know the bit number 'n'. + */ + if (params->cw_min) + ring->tx_params.cw_min = fls(params->cw_min); + else + ring->tx_params.cw_min = 5; /* cw_min: 2^5 = 32. */ + + if (params->cw_max) + ring->tx_params.cw_max = fls(params->cw_max); + else + ring->tx_params.cw_max = 10; /* cw_min: 2^10 = 1024. */ + + if (params->aifs) + ring->tx_params.aifs = params->aifs; + else + ring->tx_params.aifs = 2; + + INFO(rt2x00dev, + "Configured TX ring %d - CWmin: %d, CWmax: %d, Aifs: %d.\n", + queue, ring->tx_params.cw_min, ring->tx_params.cw_max, + ring->tx_params.aifs); + + return 0; +} +EXPORT_SYMBOL_GPL(rt2x00mac_conf_tx); diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c new file mode 100644 index 00000000000..85629f1999a --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -0,0 +1,481 @@ +/* + Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the + Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + Module: rt2x00pci + Abstract: rt2x00 generic pci device routines. + */ + +/* + * Set enviroment defines for rt2x00.h + */ +#define DRV_NAME "rt2x00pci" + +#include +#include +#include +#include + +#include "rt2x00.h" +#include "rt2x00pci.h" + +/* + * Beacon handlers. + */ +int rt2x00pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ieee80211_tx_control *control) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct data_ring *ring = + rt2x00lib_get_ring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON); + struct data_entry *entry = rt2x00_get_data_entry(ring); + + /* + * Just in case mac80211 doesn't set this correctly, + * but we need this queue set for the descriptor + * initialization. + */ + control->queue = IEEE80211_TX_QUEUE_BEACON; + + /* + * Update the beacon entry. + */ + memcpy(entry->data_addr, skb->data, skb->len); + rt2x00lib_write_tx_desc(rt2x00dev, entry->priv, + (struct ieee80211_hdr *)skb->data, + skb->len, control); + + /* + * Enable beacon generation. + */ + rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, control->queue); + + return 0; +} +EXPORT_SYMBOL_GPL(rt2x00pci_beacon_update); + +/* + * TX data handlers. + */ +int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev, + struct data_ring *ring, struct sk_buff *skb, + struct ieee80211_tx_control *control) +{ + struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data; + struct data_entry *entry = rt2x00_get_data_entry(ring); + struct data_desc *txd = entry->priv; + u32 word; + + if (rt2x00_ring_full(ring)) { + ieee80211_stop_queue(rt2x00dev->hw, control->queue); + return -EINVAL; + } + + rt2x00_desc_read(txd, 0, &word); + + if (rt2x00_get_field32(word, TXD_ENTRY_OWNER_NIC) || + rt2x00_get_field32(word, TXD_ENTRY_VALID)) { + ERROR(rt2x00dev, + "Arrived at non-free entry in the non-full queue %d.\n" + "Please file bug report to %s.\n", + control->queue, DRV_PROJECT); + ieee80211_stop_queue(rt2x00dev->hw, control->queue); + return -EINVAL; + } + + entry->skb = skb; + memcpy(&entry->tx_status.control, control, sizeof(*control)); + memcpy(entry->data_addr, skb->data, skb->len); + rt2x00lib_write_tx_desc(rt2x00dev, txd, ieee80211hdr, + skb->len, control); + + rt2x00_ring_index_inc(ring); + + if (rt2x00_ring_full(ring)) + ieee80211_stop_queue(rt2x00dev->hw, control->queue); + + return 0; +} +EXPORT_SYMBOL_GPL(rt2x00pci_write_tx_data); + +/* + * RX data handlers. + */ +void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) +{ + struct data_ring *ring = rt2x00dev->rx; + struct data_entry *entry; + struct data_desc *rxd; + struct sk_buff *skb; + u32 desc; + int retval; + int signal; + int rssi; + int ofdm; + int size; + + while (1) { + entry = rt2x00_get_data_entry(ring); + rxd = entry->priv; + rt2x00_desc_read(rxd, 0, &desc); + + if (rt2x00_get_field32(desc, RXD_ENTRY_OWNER_NIC)) + break; + + retval = rt2x00dev->ops->lib->fill_rxdone(entry, &signal, + &rssi, &ofdm, &size); + if (retval) + goto skip_entry; + + /* + * Allocate the sk_buffer, initialize it and copy + * all data into it. + */ + skb = dev_alloc_skb(size + NET_IP_ALIGN); + if (!skb) + return; + + skb_reserve(skb, NET_IP_ALIGN); + skb_put(skb, size); + memcpy(skb->data, entry->data_addr, size); + + /* + * Send the frame to rt2x00lib for further processing. + */ + rt2x00lib_rxdone(entry, skb, signal, rssi, ofdm); + +skip_entry: + if (test_bit(DEVICE_ENABLED_RADIO, &ring->rt2x00dev->flags)) { + rt2x00_set_field32(&desc, RXD_ENTRY_OWNER_NIC, 1); + rt2x00_desc_write(rxd, 0, desc); + } + + rt2x00_ring_index_inc(ring); + } +} +EXPORT_SYMBOL_GPL(rt2x00pci_rxdone); + +/* + * Device initialization handlers. + */ +#define priv_offset(__ring, __i) \ +({ \ + ring->data_addr + (i * ring->desc_size); \ +}) + +#define data_addr_offset(__ring, __i) \ +({ \ + (__ring)->data_addr + \ + ((__ring)->stats.limit * (__ring)->desc_size) + \ + ((__i) * (__ring)->data_size); \ +}) + +#define data_dma_offset(__ring, __i) \ +({ \ + (__ring)->data_dma + \ + ((__ring)->stats.limit * (__ring)->desc_size) + \ + ((__i) * (__ring)->data_size); \ +}) + +static int rt2x00pci_alloc_dma(struct rt2x00_dev *rt2x00dev, + struct data_ring *ring) +{ + unsigned int i; + + /* + * Allocate DMA memory for descriptor and buffer. + */ + ring->data_addr = pci_alloc_consistent(rt2x00dev_pci(rt2x00dev), + rt2x00_get_ring_size(ring), + &ring->data_dma); + if (!ring->data_addr) + return -ENOMEM; + + /* + * Initialize all ring entries to contain valid + * addresses. + */ + for (i = 0; i < ring->stats.limit; i++) { + ring->entry[i].priv = priv_offset(ring, i); + ring->entry[i].data_addr = data_addr_offset(ring, i); + ring->entry[i].data_dma = data_dma_offset(ring, i); + } + + return 0; +} + +static void rt2x00pci_free_dma(struct rt2x00_dev *rt2x00dev, + struct data_ring *ring) +{ + if (ring->data_addr) + pci_free_consistent(rt2x00dev_pci(rt2x00dev), + rt2x00_get_ring_size(ring), + ring->data_addr, ring->data_dma); + ring->data_addr = NULL; +} + +int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev) +{ + struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev); + struct data_ring *ring; + int status; + + /* + * Allocate DMA + */ + ring_for_each(rt2x00dev, ring) { + status = rt2x00pci_alloc_dma(rt2x00dev, ring); + if (status) + goto exit; + } + + /* + * Register interrupt handler. + */ + status = request_irq(pci_dev->irq, rt2x00dev->ops->lib->irq_handler, + IRQF_SHARED, pci_name(pci_dev), rt2x00dev); + if (status) { + ERROR(rt2x00dev, "IRQ %d allocation failed (error %d).\n", + pci_dev->irq, status); + return status; + } + + return 0; + +exit: + rt2x00pci_uninitialize(rt2x00dev); + + return status; +} +EXPORT_SYMBOL_GPL(rt2x00pci_initialize); + +void rt2x00pci_uninitialize(struct rt2x00_dev *rt2x00dev) +{ + struct data_ring *ring; + + /* + * Free irq line. + */ + free_irq(rt2x00dev_pci(rt2x00dev)->irq, rt2x00dev); + + /* + * Free DMA + */ + ring_for_each(rt2x00dev, ring) + rt2x00pci_free_dma(rt2x00dev, ring); +} +EXPORT_SYMBOL_GPL(rt2x00pci_uninitialize); + +/* + * PCI driver handlers. + */ +static void rt2x00pci_free_reg(struct rt2x00_dev *rt2x00dev) +{ + kfree(rt2x00dev->rf); + rt2x00dev->rf = NULL; + + kfree(rt2x00dev->eeprom); + rt2x00dev->eeprom = NULL; + + if (rt2x00dev->csr_addr) { + iounmap(rt2x00dev->csr_addr); + rt2x00dev->csr_addr = NULL; + } +} + +static int rt2x00pci_alloc_reg(struct rt2x00_dev *rt2x00dev) +{ + struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev); + + rt2x00dev->csr_addr = ioremap(pci_resource_start(pci_dev, 0), + pci_resource_len(pci_dev, 0)); + if (!rt2x00dev->csr_addr) + goto exit; + + rt2x00dev->eeprom = kzalloc(rt2x00dev->ops->eeprom_size, GFP_KERNEL); + if (!rt2x00dev->eeprom) + goto exit; + + rt2x00dev->rf = kzalloc(rt2x00dev->ops->rf_size, GFP_KERNEL); + if (!rt2x00dev->rf) + goto exit; + + return 0; + +exit: + ERROR_PROBE("Failed to allocate registers.\n"); + + rt2x00pci_free_reg(rt2x00dev); + + return -ENOMEM; +} + +int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) +{ + struct rt2x00_ops *ops = (struct rt2x00_ops *)id->driver_data; + struct ieee80211_hw *hw; + struct rt2x00_dev *rt2x00dev; + int retval; + + retval = pci_request_regions(pci_dev, pci_name(pci_dev)); + if (retval) { + ERROR_PROBE("PCI request regions failed.\n"); + return retval; + } + + retval = pci_enable_device(pci_dev); + if (retval) { + ERROR_PROBE("Enable device failed.\n"); + goto exit_release_regions; + } + + pci_set_master(pci_dev); + + if (pci_set_mwi(pci_dev)) + ERROR_PROBE("MWI not available.\n"); + + if (pci_set_dma_mask(pci_dev, DMA_64BIT_MASK) && + pci_set_dma_mask(pci_dev, DMA_32BIT_MASK)) { + ERROR_PROBE("PCI DMA not supported.\n"); + retval = -EIO; + goto exit_disable_device; + } + + hw = ieee80211_alloc_hw(sizeof(struct rt2x00_dev), ops->hw); + if (!hw) { + ERROR_PROBE("Failed to allocate hardware.\n"); + retval = -ENOMEM; + goto exit_disable_device; + } + + pci_set_drvdata(pci_dev, hw); + + rt2x00dev = hw->priv; + rt2x00dev->dev = pci_dev; + rt2x00dev->ops = ops; + rt2x00dev->hw = hw; + + retval = rt2x00pci_alloc_reg(rt2x00dev); + if (retval) + goto exit_free_device; + + retval = rt2x00lib_probe_dev(rt2x00dev); + if (retval) + goto exit_free_reg; + + return 0; + +exit_free_reg: + rt2x00pci_free_reg(rt2x00dev); + +exit_free_device: + ieee80211_free_hw(hw); + +exit_disable_device: + if (retval != -EBUSY) + pci_disable_device(pci_dev); + +exit_release_regions: + pci_release_regions(pci_dev); + + pci_set_drvdata(pci_dev, NULL); + + return retval; +} +EXPORT_SYMBOL_GPL(rt2x00pci_probe); + +void rt2x00pci_remove(struct pci_dev *pci_dev) +{ + struct ieee80211_hw *hw = pci_get_drvdata(pci_dev); + struct rt2x00_dev *rt2x00dev = hw->priv; + + /* + * Free all allocated data. + */ + rt2x00lib_remove_dev(rt2x00dev); + rt2x00pci_free_reg(rt2x00dev); + ieee80211_free_hw(hw); + + /* + * Free the PCI device data. + */ + pci_set_drvdata(pci_dev, NULL); + pci_disable_device(pci_dev); + pci_release_regions(pci_dev); +} +EXPORT_SYMBOL_GPL(rt2x00pci_remove); + +#ifdef CONFIG_PM +int rt2x00pci_suspend(struct pci_dev *pci_dev, pm_message_t state) +{ + struct ieee80211_hw *hw = pci_get_drvdata(pci_dev); + struct rt2x00_dev *rt2x00dev = hw->priv; + int retval; + + retval = rt2x00lib_suspend(rt2x00dev, state); + if (retval) + return retval; + + rt2x00pci_free_reg(rt2x00dev); + + pci_save_state(pci_dev); + pci_disable_device(pci_dev); + return pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state)); +} +EXPORT_SYMBOL_GPL(rt2x00pci_suspend); + +int rt2x00pci_resume(struct pci_dev *pci_dev) +{ + struct ieee80211_hw *hw = pci_get_drvdata(pci_dev); + struct rt2x00_dev *rt2x00dev = hw->priv; + int retval; + + if (pci_set_power_state(pci_dev, PCI_D0) || + pci_enable_device(pci_dev) || + pci_restore_state(pci_dev)) { + ERROR(rt2x00dev, "Failed to resume device.\n"); + return -EIO; + } + + retval = rt2x00pci_alloc_reg(rt2x00dev); + if (retval) + return retval; + + retval = rt2x00lib_resume(rt2x00dev); + if (retval) + goto exit_free_reg; + + return 0; + +exit_free_reg: + rt2x00pci_free_reg(rt2x00dev); + + return retval; +} +EXPORT_SYMBOL_GPL(rt2x00pci_resume); +#endif /* CONFIG_PM */ + +/* + * rt2x00pci module information. + */ +MODULE_AUTHOR(DRV_PROJECT); +MODULE_VERSION(DRV_VERSION); +MODULE_DESCRIPTION("rt2x00 library"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h new file mode 100644 index 00000000000..82adeac061d --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00pci.h @@ -0,0 +1,127 @@ +/* + Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the + Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + Module: rt2x00pci + Abstract: Data structures for the rt2x00pci module. + */ + +#ifndef RT2X00PCI_H +#define RT2X00PCI_H + +#include + +/* + * This variable should be used with the + * pci_driver structure initialization. + */ +#define PCI_DEVICE_DATA(__ops) .driver_data = (kernel_ulong_t)(__ops) + +/* + * Register defines. + * Some registers require multiple attempts before success, + * in those cases REGISTER_BUSY_COUNT attempts should be + * taken with a REGISTER_BUSY_DELAY interval. + */ +#define REGISTER_BUSY_COUNT 5 +#define REGISTER_BUSY_DELAY 100 + +/* + * Descriptor availability flags. + * All PCI device descriptors have these 2 flags + * with the exact same definition. + * By storing them here we can use them inside rt2x00pci + * for some simple entry availability checking. + */ +#define TXD_ENTRY_OWNER_NIC FIELD32(0x00000001) +#define TXD_ENTRY_VALID FIELD32(0x00000002) +#define RXD_ENTRY_OWNER_NIC FIELD32(0x00000001) + +/* + * Register access. + */ +static inline void rt2x00pci_register_read(const struct rt2x00_dev *rt2x00dev, + const unsigned long offset, + u32 *value) +{ + *value = readl(rt2x00dev->csr_addr + offset); +} + +static inline void +rt2x00pci_register_multiread(const struct rt2x00_dev *rt2x00dev, + const unsigned long offset, + void *value, const u16 length) +{ + memcpy_fromio(value, rt2x00dev->csr_addr + offset, length); +} + +static inline void rt2x00pci_register_write(const struct rt2x00_dev *rt2x00dev, + const unsigned long offset, + u32 value) +{ + writel(value, rt2x00dev->csr_addr + offset); +} + +static inline void +rt2x00pci_register_multiwrite(const struct rt2x00_dev *rt2x00dev, + const unsigned long offset, + void *value, const u16 length) +{ + memcpy_toio(rt2x00dev->csr_addr + offset, value, length); +} + +/* + * Beacon handlers. + */ +int rt2x00pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ieee80211_tx_control *control); + +/* + * TX data handlers. + */ +int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev, + struct data_ring *ring, struct sk_buff *skb, + struct ieee80211_tx_control *control); + +/* + * RX data handlers. + */ +void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev); + +/* + * Device initialization handlers. + */ +int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev); +void rt2x00pci_uninitialize(struct rt2x00_dev *rt2x00dev); + +/* + * PCI driver handlers. + */ +int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id); +void rt2x00pci_remove(struct pci_dev *pci_dev); +#ifdef CONFIG_PM +int rt2x00pci_suspend(struct pci_dev *pci_dev, pm_message_t state); +int rt2x00pci_resume(struct pci_dev *pci_dev); +#else +#define rt2x00pci_suspend NULL +#define rt2x00pci_resume NULL +#endif /* CONFIG_PM */ + +#endif /* RT2X00PCI_H */ diff --git a/drivers/net/wireless/rt2x00/rt2x00reg.h b/drivers/net/wireless/rt2x00/rt2x00reg.h new file mode 100644 index 00000000000..7927d5f7bcc --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00reg.h @@ -0,0 +1,283 @@ +/* + Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the + Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + Module: rt2x00 + Abstract: rt2x00 generic register information. + */ + +#ifndef RT2X00REG_H +#define RT2X00REG_H + +/* + * TX result flags. + */ +enum TX_STATUS { + TX_SUCCESS = 0, + TX_SUCCESS_RETRY = 1, + TX_FAIL_RETRY = 2, + TX_FAIL_INVALID = 3, + TX_FAIL_OTHER = 4, +}; + +/* + * Antenna values + */ +enum antenna { + ANTENNA_SW_DIVERSITY = 0, + ANTENNA_A = 1, + ANTENNA_B = 2, + ANTENNA_HW_DIVERSITY = 3, +}; + +/* + * Led mode values. + */ +enum led_mode { + LED_MODE_DEFAULT = 0, + LED_MODE_TXRX_ACTIVITY = 1, + LED_MODE_SIGNAL_STRENGTH = 2, + LED_MODE_ASUS = 3, + LED_MODE_ALPHA = 4, +}; + +/* + * Device states + */ +enum dev_state { + STATE_DEEP_SLEEP = 0, + STATE_SLEEP = 1, + STATE_STANDBY = 2, + STATE_AWAKE = 3, + +/* + * Additional device states, these values are + * not strict since they are not directly passed + * into the device. + */ + STATE_RADIO_ON, + STATE_RADIO_OFF, + STATE_RADIO_RX_ON, + STATE_RADIO_RX_OFF, + STATE_RADIO_IRQ_ON, + STATE_RADIO_IRQ_OFF, +}; + +/* + * IFS backoff values + */ +enum ifs { + IFS_BACKOFF = 0, + IFS_SIFS = 1, + IFS_NEW_BACKOFF = 2, + IFS_NONE = 3, +}; + +/* + * Cipher types for hardware encryption + */ +enum cipher { + CIPHER_NONE = 0, + CIPHER_WEP64 = 1, + CIPHER_WEP128 = 2, + CIPHER_TKIP = 3, + CIPHER_AES = 4, +/* + * The following fields were added by rt61pci and rt73usb. + */ + CIPHER_CKIP64 = 5, + CIPHER_CKIP128 = 6, + CIPHER_TKIP_NO_MIC = 7, +}; + +/* + * Register handlers. + * We store the position of a register field inside a field structure, + * This will simplify the process of setting and reading a certain field + * inside the register while making sure the process remains byte order safe. + */ +struct rt2x00_field8 { + u8 bit_offset; + u8 bit_mask; +}; + +struct rt2x00_field16 { + u16 bit_offset; + u16 bit_mask; +}; + +struct rt2x00_field32 { + u32 bit_offset; + u32 bit_mask; +}; + +/* + * Power of two check, this will check + * if the mask that has been given contains + * and contiguous set of bits. + */ +#define is_power_of_two(x) ( !((x) & ((x)-1)) ) +#define low_bit_mask(x) ( ((x)-1) & ~(x) ) +#define is_valid_mask(x) is_power_of_two(1 + (x) + low_bit_mask(x)) + +#define FIELD8(__mask) \ +({ \ + BUILD_BUG_ON(!(__mask) || \ + !is_valid_mask(__mask) || \ + (__mask) != (u8)(__mask)); \ + (struct rt2x00_field8) { \ + __ffs(__mask), (__mask) \ + }; \ +}) + +#define FIELD16(__mask) \ +({ \ + BUILD_BUG_ON(!(__mask) || \ + !is_valid_mask(__mask) || \ + (__mask) != (u16)(__mask));\ + (struct rt2x00_field16) { \ + __ffs(__mask), (__mask) \ + }; \ +}) + +#define FIELD32(__mask) \ +({ \ + BUILD_BUG_ON(!(__mask) || \ + !is_valid_mask(__mask) || \ + (__mask) != (u32)(__mask));\ + (struct rt2x00_field32) { \ + __ffs(__mask), (__mask) \ + }; \ +}) + +static inline void rt2x00_set_field32(u32 *reg, + const struct rt2x00_field32 field, + const u32 value) +{ + *reg &= ~(field.bit_mask); + *reg |= (value << field.bit_offset) & field.bit_mask; +} + +static inline u32 rt2x00_get_field32(const u32 reg, + const struct rt2x00_field32 field) +{ + return (reg & field.bit_mask) >> field.bit_offset; +} + +static inline void rt2x00_set_field16(u16 *reg, + const struct rt2x00_field16 field, + const u16 value) +{ + *reg &= ~(field.bit_mask); + *reg |= (value << field.bit_offset) & field.bit_mask; +} + +static inline u16 rt2x00_get_field16(const u16 reg, + const struct rt2x00_field16 field) +{ + return (reg & field.bit_mask) >> field.bit_offset; +} + +static inline void rt2x00_set_field8(u8 *reg, + const struct rt2x00_field8 field, + const u8 value) +{ + *reg &= ~(field.bit_mask); + *reg |= (value << field.bit_offset) & field.bit_mask; +} + +static inline u8 rt2x00_get_field8(const u8 reg, + const struct rt2x00_field8 field) +{ + return (reg & field.bit_mask) >> field.bit_offset; +} + +/* + * Device specific rate value. + * We will have to create the device specific rate value + * passed to the ieee80211 kernel. We need to make it a consist of + * multiple fields because we want to store more then 1 device specific + * values inside the value. + * 1 - rate, stored as 100 kbit/s. + * 2 - preamble, short_preamble enabled flag. + * 3 - MASK_RATE, which rates are enabled in this mode, this mask + * corresponds with the TX register format for the current device. + * 4 - plcp, 802.11b rates are device specific, + * 802.11g rates are set according to the ieee802.11a-1999 p.14. + * The bit to enable preamble is set in a seperate define. + */ +#define DEV_RATE FIELD32(0x000007ff) +#define DEV_PREAMBLE FIELD32(0x00000800) +#define DEV_RATEMASK FIELD32(0x00fff000) +#define DEV_PLCP FIELD32(0xff000000) + +/* + * Bitfields + */ +#define DEV_RATEBIT_1MB ( 1 << 0 ) +#define DEV_RATEBIT_2MB ( 1 << 1 ) +#define DEV_RATEBIT_5_5MB ( 1 << 2 ) +#define DEV_RATEBIT_11MB ( 1 << 3 ) +#define DEV_RATEBIT_6MB ( 1 << 4 ) +#define DEV_RATEBIT_9MB ( 1 << 5 ) +#define DEV_RATEBIT_12MB ( 1 << 6 ) +#define DEV_RATEBIT_18MB ( 1 << 7 ) +#define DEV_RATEBIT_24MB ( 1 << 8 ) +#define DEV_RATEBIT_36MB ( 1 << 9 ) +#define DEV_RATEBIT_48MB ( 1 << 10 ) +#define DEV_RATEBIT_54MB ( 1 << 11 ) + +/* + * Bitmasks for DEV_RATEMASK + */ +#define DEV_RATEMASK_1MB ( (DEV_RATEBIT_1MB << 1) -1 ) +#define DEV_RATEMASK_2MB ( (DEV_RATEBIT_2MB << 1) -1 ) +#define DEV_RATEMASK_5_5MB ( (DEV_RATEBIT_5_5MB << 1) -1 ) +#define DEV_RATEMASK_11MB ( (DEV_RATEBIT_11MB << 1) -1 ) +#define DEV_RATEMASK_6MB ( (DEV_RATEBIT_6MB << 1) -1 ) +#define DEV_RATEMASK_9MB ( (DEV_RATEBIT_9MB << 1) -1 ) +#define DEV_RATEMASK_12MB ( (DEV_RATEBIT_12MB << 1) -1 ) +#define DEV_RATEMASK_18MB ( (DEV_RATEBIT_18MB << 1) -1 ) +#define DEV_RATEMASK_24MB ( (DEV_RATEBIT_24MB << 1) -1 ) +#define DEV_RATEMASK_36MB ( (DEV_RATEBIT_36MB << 1) -1 ) +#define DEV_RATEMASK_48MB ( (DEV_RATEBIT_48MB << 1) -1 ) +#define DEV_RATEMASK_54MB ( (DEV_RATEBIT_54MB << 1) -1 ) + +/* + * Bitmask groups of bitrates + */ +#define DEV_BASIC_RATEMASK \ + ( DEV_RATEMASK_11MB | \ + DEV_RATEBIT_6MB | DEV_RATEBIT_12MB | DEV_RATEBIT_24MB ) + +#define DEV_CCK_RATEMASK ( DEV_RATEMASK_11MB ) +#define DEV_OFDM_RATEMASK ( DEV_RATEMASK_54MB & ~DEV_CCK_RATEMASK ) + +/* + * Macro's to set and get specific fields from the device specific val and val2 + * fields inside the ieee80211_rate entry. + */ +#define DEVICE_SET_RATE_FIELD(__value, __mask) \ + (int)( ((__value) << DEV_##__mask.bit_offset) & DEV_##__mask.bit_mask ) + +#define DEVICE_GET_RATE_FIELD(__value, __mask) \ + (int)( ((__value) & DEV_##__mask.bit_mask) >> DEV_##__mask.bit_offset ) + +#endif /* RT2X00REG_H */ diff --git a/drivers/net/wireless/rt2x00/rt2x00rfkill.c b/drivers/net/wireless/rt2x00/rt2x00rfkill.c new file mode 100644 index 00000000000..dc5b696f475 --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00rfkill.c @@ -0,0 +1,148 @@ +/* + Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the + Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + Module: rt2x00rfkill + Abstract: rt2x00 rfkill routines. + */ + +/* + * Set enviroment defines for rt2x00.h + */ +#define DRV_NAME "rt2x00lib" + +#include +#include +#include +#include + +#include "rt2x00.h" +#include "rt2x00lib.h" + +static int rt2x00rfkill_toggle_radio(void *data, enum rfkill_state state) +{ + struct rt2x00_dev *rt2x00dev = data; + int retval = 0; + + if (unlikely(!rt2x00dev)) + return 0; + + /* + * Only continue if we have an active interface, + * either monitor or non-monitor should be present. + */ + if (!is_interface_present(&rt2x00dev->interface) && + !is_monitor_present(&rt2x00dev->interface)) + return 0; + + if (state == RFKILL_STATE_ON) { + INFO(rt2x00dev, "Hardware button pressed, enabling radio.\n"); + __set_bit(DEVICE_ENABLED_RADIO_HW, &rt2x00dev->flags); + retval = rt2x00lib_enable_radio(rt2x00dev); + } else if (state == RFKILL_STATE_OFF) { + INFO(rt2x00dev, "Hardware button pressed, disabling radio.\n"); + __clear_bit(DEVICE_ENABLED_RADIO_HW, &rt2x00dev->flags); + rt2x00lib_disable_radio(rt2x00dev); + } + + return retval; +} + +static void rt2x00rfkill_poll(struct input_polled_dev *poll_dev) +{ + struct rt2x00_dev *rt2x00dev = poll_dev->private; + int state = rt2x00dev->ops->lib->rfkill_poll(rt2x00dev); + + if (rt2x00dev->rfkill->state != state) + input_report_key(poll_dev->input, KEY_WLAN, 1); +} + +int rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev) +{ + int retval; + + if (!test_bit(DEVICE_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) + return 0; + + retval = rfkill_register(rt2x00dev->rfkill); + if (retval) { + ERROR(rt2x00dev, "Failed to register rfkill handler.\n"); + return retval; + } + + retval = input_register_polled_device(rt2x00dev->poll_dev); + if (retval) { + ERROR(rt2x00dev, "Failed to register polled device.\n"); + rfkill_unregister(rt2x00dev->rfkill); + return retval; + } + + return 0; +} + +void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev) +{ + if (!test_bit(DEVICE_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) + return; + + input_unregister_polled_device(rt2x00dev->poll_dev); + rfkill_unregister(rt2x00dev->rfkill); +} + +int rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev) +{ + struct device *device = wiphy_dev(rt2x00dev->hw->wiphy); + + if (!test_bit(DEVICE_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) + return 0; + + rt2x00dev->rfkill = rfkill_allocate(device, RFKILL_TYPE_WLAN); + if (!rt2x00dev->rfkill) { + ERROR(rt2x00dev, "Failed to allocate rfkill handler.\n"); + return -ENOMEM; + } + + rt2x00dev->rfkill->name = rt2x00dev->ops->name; + rt2x00dev->rfkill->data = rt2x00dev; + rt2x00dev->rfkill->state = rt2x00dev->ops->lib->rfkill_poll(rt2x00dev); + rt2x00dev->rfkill->toggle_radio = rt2x00rfkill_toggle_radio; + + rt2x00dev->poll_dev = input_allocate_polled_device(); + if (!rt2x00dev->poll_dev) { + ERROR(rt2x00dev, "Failed to allocate polled device.\n"); + rfkill_free(rt2x00dev->rfkill); + return -ENOMEM; + } + + rt2x00dev->poll_dev->private = rt2x00dev; + rt2x00dev->poll_dev->poll = rt2x00rfkill_poll; + rt2x00dev->poll_dev->poll_interval = RFKILL_POLL_INTERVAL; + + return 0; +} + +void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev) +{ + if (!test_bit(DEVICE_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) + return; + + input_free_polled_device(rt2x00dev->poll_dev); + rfkill_free(rt2x00dev->rfkill); +} diff --git a/drivers/net/wireless/rt2x00/rt2x00ring.h b/drivers/net/wireless/rt2x00/rt2x00ring.h new file mode 100644 index 00000000000..122c75248e7 --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00ring.h @@ -0,0 +1,255 @@ +/* + Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the + Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + Module: rt2x00 + Abstract: rt2x00 ring datastructures and routines + */ + +#ifndef RT2X00RING_H +#define RT2X00RING_H + +/* + * data_desc + * Each data entry also contains a descriptor which is used by the + * device to determine what should be done with the packet and + * what the current status is. + * This structure is greatly simplified, but the descriptors + * are basically a list of little endian 32 bit values. + * Make the array by default 1 word big, this will allow us + * to use sizeof() correctly. + */ +struct data_desc { + __le32 word[1]; +}; + +/* + * data_entry_desc + * Summary of information that should be written into the + * descriptor for sending a TX frame. + */ +struct data_entry_desc { + unsigned long flags; +#define ENTRY_TXDONE 1 +#define ENTRY_TXD_RTS_FRAME 2 +#define ENTRY_TXD_OFDM_RATE 3 +#define ENTRY_TXD_MORE_FRAG 4 +#define ENTRY_TXD_REQ_TIMESTAMP 5 +#define ENTRY_TXD_BURST 6 + +/* + * Queue ID. ID's 0-4 are data TX rings + */ + int queue; +#define QUEUE_MGMT 13 +#define QUEUE_RX 14 +#define QUEUE_OTHER 15 + + /* + * PLCP values. + */ + u16 length_high; + u16 length_low; + u16 signal; + u16 service; + + /* + * Timing information + */ + int aifs; + int ifs; + int cw_min; + int cw_max; +}; + +/* + * data_entry + * The data ring is a list of data entries. + * Each entry holds a reference to the descriptor + * and the data buffer. For TX rings the reference to the + * sk_buff of the packet being transmitted is also stored here. + */ +struct data_entry { + /* + * Status flags + */ + unsigned long flags; +#define ENTRY_OWNER_NIC 1 + + /* + * Ring we belong to. + */ + struct data_ring *ring; + + /* + * sk_buff for the packet which is being transmitted + * in this entry (Only used with TX related rings). + */ + struct sk_buff *skb; + + /* + * Store a ieee80211_tx_status structure in each + * ring entry, this will optimize the txdone + * handler. + */ + struct ieee80211_tx_status tx_status; + + /* + * private pointer specific to driver. + */ + void *priv; + + /* + * Data address for this entry. + */ + void *data_addr; + dma_addr_t data_dma; +}; + +/* + * data_ring + * Data rings are used by the device to send and receive packets. + * The data_addr is the base address of the data memory. + * To determine at which point in the ring we are, + * have to use the rt2x00_ring_index_*() functions. + */ +struct data_ring { + /* + * Pointer to main rt2x00dev structure where this + * ring belongs to. + */ + struct rt2x00_dev *rt2x00dev; + + /* + * Base address for the device specific data entries. + */ + struct data_entry *entry; + + /* + * TX queue statistic info. + */ + struct ieee80211_tx_queue_stats_data stats; + + /* + * TX Queue parameters. + */ + struct ieee80211_tx_queue_params tx_params; + + /* + * Base address for data ring. + */ + dma_addr_t data_dma; + void *data_addr; + + /* + * Index variables. + */ + u16 index; + u16 index_done; + + /* + * Size of packet and descriptor in bytes. + */ + u16 data_size; + u16 desc_size; +}; + +/* + * Handlers to determine the address of the current device specific + * data entry, where either index or index_done points to. + */ +static inline struct data_entry *rt2x00_get_data_entry(struct data_ring *ring) +{ + return &ring->entry[ring->index]; +} + +static inline struct data_entry *rt2x00_get_data_entry_done(struct data_ring + *ring) +{ + return &ring->entry[ring->index_done]; +} + +/* + * Total ring memory + */ +static inline int rt2x00_get_ring_size(struct data_ring *ring) +{ + return ring->stats.limit * (ring->desc_size + ring->data_size); +} + +/* + * Ring index manipulation functions. + */ +static inline void rt2x00_ring_index_inc(struct data_ring *ring) +{ + ring->index++; + if (ring->index >= ring->stats.limit) + ring->index = 0; + ring->stats.len++; +} + +static inline void rt2x00_ring_index_done_inc(struct data_ring *ring) +{ + ring->index_done++; + if (ring->index_done >= ring->stats.limit) + ring->index_done = 0; + ring->stats.len--; + ring->stats.count++; +} + +static inline void rt2x00_ring_index_clear(struct data_ring *ring) +{ + ring->index = 0; + ring->index_done = 0; + ring->stats.len = 0; + ring->stats.count = 0; +} + +static inline int rt2x00_ring_empty(struct data_ring *ring) +{ + return ring->stats.len == 0; +} + +static inline int rt2x00_ring_full(struct data_ring *ring) +{ + return ring->stats.len == ring->stats.limit; +} + +static inline int rt2x00_ring_free(struct data_ring *ring) +{ + return ring->stats.limit - ring->stats.len; +} + +/* + * TX/RX Descriptor access functions. + */ +static inline void rt2x00_desc_read(struct data_desc *desc, + const u8 word, u32 *value) +{ + *value = le32_to_cpu(desc->word[word]); +} + +static inline void rt2x00_desc_write(struct data_desc *desc, + const u8 word, const u32 value) +{ + desc->word[word] = cpu_to_le32(value); +} + +#endif /* RT2X00RING_H */ diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c new file mode 100644 index 00000000000..a0f05ca54bb --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -0,0 +1,595 @@ +/* + Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the + Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + Module: rt2x00usb + Abstract: rt2x00 generic usb device routines. + */ + +/* + * Set enviroment defines for rt2x00.h + */ +#define DRV_NAME "rt2x00usb" + +#include +#include +#include + +#include "rt2x00.h" +#include "rt2x00usb.h" + +/* + * Interfacing with the HW. + */ +int rt2x00usb_vendor_request(const struct rt2x00_dev *rt2x00dev, + const u8 request, const u8 requesttype, + const u16 offset, const u16 value, + void *buffer, const u16 buffer_length, + u16 timeout) +{ + struct usb_device *usb_dev = + interface_to_usbdev(rt2x00dev_usb(rt2x00dev)); + int status; + unsigned int i; + unsigned int pipe = + (requesttype == USB_VENDOR_REQUEST_IN) ? + usb_rcvctrlpipe(usb_dev, 0) : usb_sndctrlpipe(usb_dev, 0); + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + status = usb_control_msg(usb_dev, pipe, request, requesttype, + value, offset, buffer, buffer_length, + timeout); + if (status >= 0) + return 0; + + /* + * Check for errors, + * -ETIMEDOUT: We need a bit more time to complete. + * -ENODEV: Device has disappeared, no point continuing. + */ + if (status == -ETIMEDOUT) + timeout *= 2; + else if (status == -ENODEV) + break; + } + + ERROR(rt2x00dev, + "Vendor Request 0x%02x failed for offset 0x%04x with error %d.\n", + request, offset, status); + + return status; +} +EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request); + +int rt2x00usb_vendor_request_buff(const struct rt2x00_dev *rt2x00dev, + const u8 request, const u8 requesttype, + const u16 offset, void *buffer, + const u16 buffer_length, u16 timeout) +{ + int status; + + /* + * Check for Cache availability. + */ + if (unlikely(!rt2x00dev->csr_cache || buffer_length > CSR_CACHE_SIZE)) { + ERROR(rt2x00dev, "CSR cache not available.\n"); + return -ENOMEM; + } + + if (requesttype == USB_VENDOR_REQUEST_OUT) + memcpy(rt2x00dev->csr_cache, buffer, buffer_length); + + status = rt2x00usb_vendor_request(rt2x00dev, request, requesttype, + offset, 0, rt2x00dev->csr_cache, + buffer_length, timeout); + + if (!status && requesttype == USB_VENDOR_REQUEST_IN) + memcpy(buffer, rt2x00dev->csr_cache, buffer_length); + + return status; +} +EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request_buff); + +/* + * TX data handlers. + */ +static void rt2x00usb_interrupt_txdone(struct urb *urb) +{ + struct data_entry *entry = (struct data_entry *)urb->context; + struct data_ring *ring = entry->ring; + struct rt2x00_dev *rt2x00dev = ring->rt2x00dev; + struct data_desc *txd = (struct data_desc *)entry->skb->data; + u32 word; + int tx_status; + + if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) || + !__test_and_clear_bit(ENTRY_OWNER_NIC, &entry->flags)) + return; + + rt2x00_desc_read(txd, 0, &word); + + /* + * Remove the descriptor data from the buffer. + */ + skb_pull(entry->skb, ring->desc_size); + + /* + * Obtain the status about this packet. + */ + tx_status = !urb->status ? TX_SUCCESS : TX_FAIL_RETRY; + + rt2x00lib_txdone(entry, tx_status, 0); + + /* + * Make this entry available for reuse. + */ + entry->flags = 0; + rt2x00_ring_index_done_inc(entry->ring); + + /* + * If the data ring was full before the txdone handler + * we must make sure the packet queue in the mac80211 stack + * is reenabled when the txdone handler has finished. + */ + if (!rt2x00_ring_full(ring)) + ieee80211_wake_queue(rt2x00dev->hw, + entry->tx_status.control.queue); +} + +int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev, + struct data_ring *ring, struct sk_buff *skb, + struct ieee80211_tx_control *control) +{ + struct usb_device *usb_dev = + interface_to_usbdev(rt2x00dev_usb(rt2x00dev)); + struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data; + struct data_entry *entry = rt2x00_get_data_entry(ring); + u32 length = skb->len; + + if (rt2x00_ring_full(ring)) { + ieee80211_stop_queue(rt2x00dev->hw, control->queue); + return -EINVAL; + } + + if (test_bit(ENTRY_OWNER_NIC, &entry->flags)) { + ERROR(rt2x00dev, + "Arrived at non-free entry in the non-full queue %d.\n" + "Please file bug report to %s.\n", + control->queue, DRV_PROJECT); + ieee80211_stop_queue(rt2x00dev->hw, control->queue); + return -EINVAL; + } + + /* + * Add the descriptor in front of the skb. + */ + skb_push(skb, rt2x00dev->hw->extra_tx_headroom); + memset(skb->data, 0x00, rt2x00dev->hw->extra_tx_headroom); + + rt2x00lib_write_tx_desc(rt2x00dev, (struct data_desc *)skb->data, + ieee80211hdr, length, control); + memcpy(&entry->tx_status.control, control, sizeof(*control)); + entry->skb = skb; + + /* + * Length passed to usb_fill_urb cannot be an odd number, + * so add 1 byte to make it even. + */ + length += rt2x00dev->hw->extra_tx_headroom; + if (length % 2) + length++; + + __set_bit(ENTRY_OWNER_NIC, &entry->flags); + usb_fill_bulk_urb(entry->priv, usb_dev, + usb_sndbulkpipe(usb_dev, 1), + skb->data, length, rt2x00usb_interrupt_txdone, entry); + usb_submit_urb(entry->priv, GFP_ATOMIC); + + rt2x00_ring_index_inc(ring); + + if (rt2x00_ring_full(ring)) + ieee80211_stop_queue(rt2x00dev->hw, control->queue); + + return 0; +} +EXPORT_SYMBOL_GPL(rt2x00usb_write_tx_data); + +/* + * RX data handlers. + */ +static void rt2x00usb_interrupt_rxdone(struct urb *urb) +{ + struct data_entry *entry = (struct data_entry *)urb->context; + struct data_ring *ring = entry->ring; + struct rt2x00_dev *rt2x00dev = ring->rt2x00dev; + struct sk_buff *skb; + int retval; + int signal; + int rssi; + int ofdm; + int size; + int frame_size; + + if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) || + !test_and_clear_bit(ENTRY_OWNER_NIC, &entry->flags)) + return; + + /* + * Check if the received data is simply too small + * to be actually valid, or if the urb is signaling + * a problem. + */ + if (urb->actual_length < entry->ring->desc_size || urb->status) + goto skip_entry; + + retval = rt2x00dev->ops->lib->fill_rxdone(entry, &signal, &rssi, + &ofdm, &size); + if (retval) + goto skip_entry; + + /* + * Allocate a new sk buffer to replace the current one. + * If allocation fails, we should drop the current frame + * so we can recycle the existing sk buffer for the new frame. + */ + frame_size = entry->ring->data_size + entry->ring->desc_size; + skb = dev_alloc_skb(frame_size + NET_IP_ALIGN); + if (!skb) + goto skip_entry; + + skb_reserve(skb, NET_IP_ALIGN); + skb_put(skb, frame_size); + + /* + * Trim the skb_buffer to only contain the valid + * frame data (so ignore the device's descriptor). + */ + skb_trim(entry->skb, size); + + /* + * Send the frame to rt2x00lib for further processing. + */ + rt2x00lib_rxdone(entry, entry->skb, signal, rssi, ofdm); + + /* + * Replace current entry's skb with the newly allocated one, + * and reinitialize the urb. + */ + entry->skb = skb; + urb->transfer_buffer = entry->skb->data; + urb->transfer_buffer_length = entry->skb->len; + +skip_entry: + if (test_bit(DEVICE_ENABLED_RADIO, &ring->rt2x00dev->flags)) { + __set_bit(ENTRY_OWNER_NIC, &entry->flags); + usb_submit_urb(urb, GFP_ATOMIC); + } + + rt2x00_ring_index_inc(ring); +} + +/* + * Radio handlers + */ +void rt2x00usb_enable_radio(struct rt2x00_dev *rt2x00dev) +{ + struct usb_device *usb_dev = + interface_to_usbdev(rt2x00dev_usb(rt2x00dev)); + struct data_ring *ring; + struct data_entry *entry; + unsigned int i; + + /* + * Initialize the TX rings + */ + txringall_for_each(rt2x00dev, ring) { + for (i = 0; i < ring->stats.limit; i++) + ring->entry[i].flags = 0; + + rt2x00_ring_index_clear(ring); + } + + /* + * Initialize and start the RX ring. + */ + rt2x00_ring_index_clear(rt2x00dev->rx); + + for (i = 0; i < rt2x00dev->rx->stats.limit; i++) { + entry = &rt2x00dev->rx->entry[i]; + + usb_fill_bulk_urb(entry->priv, usb_dev, + usb_rcvbulkpipe(usb_dev, 1), + entry->skb->data, entry->skb->len, + rt2x00usb_interrupt_rxdone, entry); + + __set_bit(ENTRY_OWNER_NIC, &entry->flags); + usb_submit_urb(entry->priv, GFP_ATOMIC); + } +} +EXPORT_SYMBOL_GPL(rt2x00usb_enable_radio); + +void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev) +{ + struct data_ring *ring; + unsigned int i; + + rt2x00usb_vendor_request_sw(rt2x00dev, USB_RX_CONTROL, 0x0000, 0x0000, + REGISTER_TIMEOUT); + + /* + * Cancel all rings. + */ + ring_for_each(rt2x00dev, ring) { + for (i = 0; i < ring->stats.limit; i++) + usb_kill_urb(ring->entry[i].priv); + } +} +EXPORT_SYMBOL_GPL(rt2x00usb_disable_radio); + +/* + * Device initialization handlers. + */ +static int rt2x00usb_alloc_urb(struct rt2x00_dev *rt2x00dev, + struct data_ring *ring) +{ + unsigned int i; + + /* + * Allocate the URB's + */ + for (i = 0; i < ring->stats.limit; i++) { + ring->entry[i].priv = usb_alloc_urb(0, GFP_KERNEL); + if (!ring->entry[i].priv) + return -ENOMEM; + } + + return 0; +} + +static void rt2x00usb_free_urb(struct rt2x00_dev *rt2x00dev, + struct data_ring *ring) +{ + unsigned int i; + + if (!ring->entry) + return; + + for (i = 0; i < ring->stats.limit; i++) { + usb_kill_urb(ring->entry[i].priv); + usb_free_urb(ring->entry[i].priv); + if (ring->entry[i].skb) + kfree_skb(ring->entry[i].skb); + } +} + +int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev) +{ + struct data_ring *ring; + struct sk_buff *skb; + unsigned int entry_size; + unsigned int i; + int status; + + /* + * Allocate DMA + */ + ring_for_each(rt2x00dev, ring) { + status = rt2x00usb_alloc_urb(rt2x00dev, ring); + if (status) + goto exit; + } + + /* + * For the RX ring, skb's should be allocated. + */ + entry_size = rt2x00dev->rx->data_size + rt2x00dev->rx->desc_size; + for (i = 0; i < rt2x00dev->rx->stats.limit; i++) { + skb = dev_alloc_skb(NET_IP_ALIGN + entry_size); + if (!skb) + goto exit; + + skb_reserve(skb, NET_IP_ALIGN); + skb_put(skb, entry_size); + + rt2x00dev->rx->entry[i].skb = skb; + } + + return 0; + +exit: + rt2x00usb_uninitialize(rt2x00dev); + + return status; +} +EXPORT_SYMBOL_GPL(rt2x00usb_initialize); + +void rt2x00usb_uninitialize(struct rt2x00_dev *rt2x00dev) +{ + struct data_ring *ring; + + ring_for_each(rt2x00dev, ring) + rt2x00usb_free_urb(rt2x00dev, ring); +} +EXPORT_SYMBOL_GPL(rt2x00usb_uninitialize); + +/* + * USB driver handlers. + */ +static void rt2x00usb_free_reg(struct rt2x00_dev *rt2x00dev) +{ + kfree(rt2x00dev->rf); + rt2x00dev->rf = NULL; + + kfree(rt2x00dev->eeprom); + rt2x00dev->eeprom = NULL; + + kfree(rt2x00dev->csr_cache); + rt2x00dev->csr_cache = NULL; +} + +static int rt2x00usb_alloc_reg(struct rt2x00_dev *rt2x00dev) +{ + rt2x00dev->csr_cache = kzalloc(CSR_CACHE_SIZE, GFP_KERNEL); + if (!rt2x00dev->csr_cache) + goto exit; + + rt2x00dev->eeprom = kzalloc(rt2x00dev->ops->eeprom_size, GFP_KERNEL); + if (!rt2x00dev->eeprom) + goto exit; + + rt2x00dev->rf = kzalloc(rt2x00dev->ops->rf_size, GFP_KERNEL); + if (!rt2x00dev->rf) + goto exit; + + return 0; + +exit: + ERROR_PROBE("Failed to allocate registers.\n"); + + rt2x00usb_free_reg(rt2x00dev); + + return -ENOMEM; +} + +int rt2x00usb_probe(struct usb_interface *usb_intf, + const struct usb_device_id *id) +{ + struct usb_device *usb_dev = interface_to_usbdev(usb_intf); + struct rt2x00_ops *ops = (struct rt2x00_ops *)id->driver_info; + struct ieee80211_hw *hw; + struct rt2x00_dev *rt2x00dev; + int retval; + + usb_dev = usb_get_dev(usb_dev); + + hw = ieee80211_alloc_hw(sizeof(struct rt2x00_dev), ops->hw); + if (!hw) { + ERROR_PROBE("Failed to allocate hardware.\n"); + retval = -ENOMEM; + goto exit_put_device; + } + + usb_set_intfdata(usb_intf, hw); + + rt2x00dev = hw->priv; + rt2x00dev->dev = usb_intf; + rt2x00dev->ops = ops; + rt2x00dev->hw = hw; + + retval = rt2x00usb_alloc_reg(rt2x00dev); + if (retval) + goto exit_free_device; + + retval = rt2x00lib_probe_dev(rt2x00dev); + if (retval) + goto exit_free_reg; + + return 0; + +exit_free_reg: + rt2x00usb_free_reg(rt2x00dev); + +exit_free_device: + ieee80211_free_hw(hw); + +exit_put_device: + usb_put_dev(usb_dev); + + usb_set_intfdata(usb_intf, NULL); + + return retval; +} +EXPORT_SYMBOL_GPL(rt2x00usb_probe); + +void rt2x00usb_disconnect(struct usb_interface *usb_intf) +{ + struct ieee80211_hw *hw = usb_get_intfdata(usb_intf); + struct rt2x00_dev *rt2x00dev = hw->priv; + + /* + * Free all allocated data. + */ + rt2x00lib_remove_dev(rt2x00dev); + rt2x00usb_free_reg(rt2x00dev); + ieee80211_free_hw(hw); + + /* + * Free the USB device data. + */ + usb_set_intfdata(usb_intf, NULL); + usb_put_dev(interface_to_usbdev(usb_intf)); +} +EXPORT_SYMBOL_GPL(rt2x00usb_disconnect); + +#ifdef CONFIG_PM +int rt2x00usb_suspend(struct usb_interface *usb_intf, pm_message_t state) +{ + struct ieee80211_hw *hw = usb_get_intfdata(usb_intf); + struct rt2x00_dev *rt2x00dev = hw->priv; + int retval; + + retval = rt2x00lib_suspend(rt2x00dev, state); + if (retval) + return retval; + + rt2x00usb_free_reg(rt2x00dev); + + /* + * Decrease usbdev refcount. + */ + usb_put_dev(interface_to_usbdev(usb_intf)); + + return 0; +} +EXPORT_SYMBOL_GPL(rt2x00usb_suspend); + +int rt2x00usb_resume(struct usb_interface *usb_intf) +{ + struct ieee80211_hw *hw = usb_get_intfdata(usb_intf); + struct rt2x00_dev *rt2x00dev = hw->priv; + int retval; + + usb_get_dev(interface_to_usbdev(usb_intf)); + + retval = rt2x00usb_alloc_reg(rt2x00dev); + if (retval) + return retval; + + retval = rt2x00lib_resume(rt2x00dev); + if (retval) + goto exit_free_reg; + + return 0; + +exit_free_reg: + rt2x00usb_free_reg(rt2x00dev); + + return retval; +} +EXPORT_SYMBOL_GPL(rt2x00usb_resume); +#endif /* CONFIG_PM */ + +/* + * rt2x00pci module information. + */ +MODULE_AUTHOR(DRV_PROJECT); +MODULE_VERSION(DRV_VERSION); +MODULE_DESCRIPTION("rt2x00 library"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h new file mode 100644 index 00000000000..d4113e5158f --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00usb.h @@ -0,0 +1,180 @@ +/* + Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the + Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + Module: rt2x00usb + Abstract: Data structures for the rt2x00usb module. + */ + +#ifndef RT2X00USB_H +#define RT2X00USB_H + +/* + * This variable should be used with the + * usb_driver structure initialization. + */ +#define USB_DEVICE_DATA(__ops) .driver_info = (kernel_ulong_t)(__ops) + +/* + * Register defines. + * Some registers require multiple attempts before success, + * in those cases REGISTER_BUSY_COUNT attempts should be + * taken with a REGISTER_BUSY_DELAY interval. + * For USB vendor requests we need to pass a timeout + * time in ms, for this we use the REGISTER_TIMEOUT, + * however when loading firmware a higher value is + * required. In that case we use the REGISTER_TIMEOUT_FIRMWARE. + */ +#define REGISTER_BUSY_COUNT 5 +#define REGISTER_BUSY_DELAY 100 +#define REGISTER_TIMEOUT 20 +#define REGISTER_TIMEOUT_FIRMWARE 1000 + +/* + * Cache size + */ +#define CSR_CACHE_SIZE 8 +#define CSR_CACHE_SIZE_FIRMWARE 64 + +/* + * USB request types. + */ +#define USB_VENDOR_REQUEST ( USB_TYPE_VENDOR | USB_RECIP_DEVICE ) +#define USB_VENDOR_REQUEST_IN ( USB_DIR_IN | USB_VENDOR_REQUEST ) +#define USB_VENDOR_REQUEST_OUT ( USB_DIR_OUT | USB_VENDOR_REQUEST ) + +/* + * USB vendor commands. + */ +#define USB_DEVICE_MODE 0x01 +#define USB_SINGLE_WRITE 0x02 +#define USB_SINGLE_READ 0x03 +#define USB_MULTI_WRITE 0x06 +#define USB_MULTI_READ 0x07 +#define USB_EEPROM_WRITE 0x08 +#define USB_EEPROM_READ 0x09 +#define USB_LED_CONTROL 0x0a /* RT73USB */ +#define USB_RX_CONTROL 0x0c + +/* + * Device modes offset + */ +#define USB_MODE_RESET 0x01 +#define USB_MODE_UNPLUG 0x02 +#define USB_MODE_FUNCTION 0x03 +#define USB_MODE_TEST 0x04 +#define USB_MODE_SLEEP 0x07 /* RT73USB */ +#define USB_MODE_FIRMWARE 0x08 /* RT73USB */ +#define USB_MODE_WAKEUP 0x09 /* RT73USB */ + +/* + * Used to read/write from/to the device. + * This is the main function to communicate with the device, + * the buffer argument _must_ either be NULL or point to + * a buffer allocated by kmalloc. Failure to do so can lead + * to unexpected behavior depending on the architecture. + */ +int rt2x00usb_vendor_request(const struct rt2x00_dev *rt2x00dev, + const u8 request, const u8 requesttype, + const u16 offset, const u16 value, + void *buffer, const u16 buffer_length, + u16 timeout); + +/* + * Used to read/write from/to the device. + * This function will use a previously with kmalloc allocated cache + * to communicate with the device. The contents of the buffer pointer + * will be copied to this cache when writing, or read from the cache + * when reading. + * Buffers send to rt2x00usb_vendor_request _must_ be allocated with + * kmalloc. Hence the reason for using a previously allocated cache + * which has been allocated properly. + */ +int rt2x00usb_vendor_request_buff(const struct rt2x00_dev *rt2x00dev, + const u8 request, const u8 requesttype, + const u16 offset, void *buffer, + const u16 buffer_length, u16 timeout); + +/* + * Simple wrapper around rt2x00usb_vendor_request to write a single + * command to the device. Since we don't use the buffer argument we + * don't have to worry about kmalloc here. + */ +static inline int rt2x00usb_vendor_request_sw(const struct rt2x00_dev + *rt2x00dev, + const u8 request, + const u16 offset, + const u16 value, + int timeout) +{ + return rt2x00usb_vendor_request(rt2x00dev, request, + USB_VENDOR_REQUEST_OUT, offset, + value, NULL, 0, timeout); +} + +/* + * Simple wrapper around rt2x00usb_vendor_request to read the eeprom + * from the device. Note that the eeprom argument _must_ be allocated using + * kmalloc for correct handling inside the kernel USB layer. + */ +static inline int rt2x00usb_eeprom_read(const struct rt2x00_dev *rt2x00dev, + __le16 *eeprom, const u16 lenght) +{ + int timeout = REGISTER_TIMEOUT * (lenght / sizeof(u16)); + + return rt2x00usb_vendor_request(rt2x00dev, USB_EEPROM_READ, + USB_VENDOR_REQUEST_IN, 0x0000, + 0x0000, eeprom, lenght, timeout); +} + +/* + * Radio handlers + */ +void rt2x00usb_enable_radio(struct rt2x00_dev *rt2x00dev); +void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev); + +/* + * TX data handlers. + */ +int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev, + struct data_ring *ring, struct sk_buff *skb, + struct ieee80211_tx_control *control); + +/* + * Device initialization handlers. + */ +int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev); +void rt2x00usb_uninitialize(struct rt2x00_dev *rt2x00dev); + +/* + * USB driver handlers. + */ +int rt2x00usb_probe(struct usb_interface *usb_intf, + const struct usb_device_id *id); +void rt2x00usb_disconnect(struct usb_interface *usb_intf); +#ifdef CONFIG_PM +int rt2x00usb_suspend(struct usb_interface *usb_intf, pm_message_t state); +int rt2x00usb_resume(struct usb_interface *usb_intf); +#else +#define rt2x00usb_suspend NULL +#define rt2x00usb_resume NULL +#endif /* CONFIG_PM */ + +#endif /* RT2X00USB_H */ diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c new file mode 100644 index 00000000000..730bed5a198 --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -0,0 +1,2603 @@ +/* + Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the + Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + Module: rt61pci + Abstract: rt61pci device specific routines. + Supported chipsets: RT2561, RT2561s, RT2661. + */ + +/* + * Set enviroment defines for rt2x00.h + */ +#define DRV_NAME "rt61pci" + +#include +#include +#include +#include +#include +#include +#include + +#include "rt2x00.h" +#include "rt2x00pci.h" +#include "rt61pci.h" + +/* + * Register access. + * BBP and RF register require indirect register access, + * and use the CSR registers PHY_CSR3 and PHY_CSR4 to achieve this. + * These indirect registers work with busy bits, + * and we will try maximal REGISTER_BUSY_COUNT times to access + * the register while taking a REGISTER_BUSY_DELAY us delay + * between each attampt. When the busy bit is still set at that time, + * the access attempt is considered to have failed, + * and we will print an error. + */ +static u32 rt61pci_bbp_check(const struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + unsigned int i; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2x00pci_register_read(rt2x00dev, PHY_CSR3, ®); + if (!rt2x00_get_field32(reg, PHY_CSR3_BUSY)) + break; + udelay(REGISTER_BUSY_DELAY); + } + + return reg; +} + +static void rt61pci_bbp_write(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, const u8 value) +{ + u32 reg; + + /* + * Wait until the BBP becomes ready. + */ + reg = rt61pci_bbp_check(rt2x00dev); + if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) { + ERROR(rt2x00dev, "PHY_CSR3 register busy. Write failed.\n"); + return; + } + + /* + * Write the data into the BBP. + */ + reg = 0; + rt2x00_set_field32(®, PHY_CSR3_VALUE, value); + rt2x00_set_field32(®, PHY_CSR3_REGNUM, word); + rt2x00_set_field32(®, PHY_CSR3_BUSY, 1); + rt2x00_set_field32(®, PHY_CSR3_READ_CONTROL, 0); + + rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg); +} + +static void rt61pci_bbp_read(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, u8 *value) +{ + u32 reg; + + /* + * Wait until the BBP becomes ready. + */ + reg = rt61pci_bbp_check(rt2x00dev); + if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) { + ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n"); + return; + } + + /* + * Write the request into the BBP. + */ + reg = 0; + rt2x00_set_field32(®, PHY_CSR3_REGNUM, word); + rt2x00_set_field32(®, PHY_CSR3_BUSY, 1); + rt2x00_set_field32(®, PHY_CSR3_READ_CONTROL, 1); + + rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg); + + /* + * Wait until the BBP becomes ready. + */ + reg = rt61pci_bbp_check(rt2x00dev); + if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) { + ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n"); + *value = 0xff; + return; + } + + *value = rt2x00_get_field32(reg, PHY_CSR3_VALUE); +} + +static void rt61pci_rf_write(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, const u32 value) +{ + u32 reg; + unsigned int i; + + if (!word) + return; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2x00pci_register_read(rt2x00dev, PHY_CSR4, ®); + if (!rt2x00_get_field32(reg, PHY_CSR4_BUSY)) + goto rf_write; + udelay(REGISTER_BUSY_DELAY); + } + + ERROR(rt2x00dev, "PHY_CSR4 register busy. Write failed.\n"); + return; + +rf_write: + reg = 0; + rt2x00_set_field32(®, PHY_CSR4_VALUE, value); + rt2x00_set_field32(®, PHY_CSR4_NUMBER_OF_BITS, 21); + rt2x00_set_field32(®, PHY_CSR4_IF_SELECT, 0); + rt2x00_set_field32(®, PHY_CSR4_BUSY, 1); + + rt2x00pci_register_write(rt2x00dev, PHY_CSR4, reg); + rt2x00_rf_write(rt2x00dev, word, value); +} + +static void rt61pci_mcu_request(const struct rt2x00_dev *rt2x00dev, + const u8 command, const u8 token, + const u8 arg0, const u8 arg1) +{ + u32 reg; + + rt2x00pci_register_read(rt2x00dev, H2M_MAILBOX_CSR, ®); + + if (rt2x00_get_field32(reg, H2M_MAILBOX_CSR_OWNER)) { + ERROR(rt2x00dev, "mcu request error. " + "Request 0x%02x failed for token 0x%02x.\n", + command, token); + return; + } + + rt2x00_set_field32(®, H2M_MAILBOX_CSR_OWNER, 1); + rt2x00_set_field32(®, H2M_MAILBOX_CSR_CMD_TOKEN, token); + rt2x00_set_field32(®, H2M_MAILBOX_CSR_ARG0, arg0); + rt2x00_set_field32(®, H2M_MAILBOX_CSR_ARG1, arg1); + rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CSR, reg); + + rt2x00pci_register_read(rt2x00dev, HOST_CMD_CSR, ®); + rt2x00_set_field32(®, HOST_CMD_CSR_HOST_COMMAND, command); + rt2x00_set_field32(®, HOST_CMD_CSR_INTERRUPT_MCU, 1); + rt2x00pci_register_write(rt2x00dev, HOST_CMD_CSR, reg); +} + +static void rt61pci_eepromregister_read(struct eeprom_93cx6 *eeprom) +{ + struct rt2x00_dev *rt2x00dev = eeprom->data; + u32 reg; + + rt2x00pci_register_read(rt2x00dev, E2PROM_CSR, ®); + + eeprom->reg_data_in = !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_IN); + eeprom->reg_data_out = !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_OUT); + eeprom->reg_data_clock = + !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_CLOCK); + eeprom->reg_chip_select = + !!rt2x00_get_field32(reg, E2PROM_CSR_CHIP_SELECT); +} + +static void rt61pci_eepromregister_write(struct eeprom_93cx6 *eeprom) +{ + struct rt2x00_dev *rt2x00dev = eeprom->data; + u32 reg = 0; + + rt2x00_set_field32(®, E2PROM_CSR_DATA_IN, !!eeprom->reg_data_in); + rt2x00_set_field32(®, E2PROM_CSR_DATA_OUT, !!eeprom->reg_data_out); + rt2x00_set_field32(®, E2PROM_CSR_DATA_CLOCK, + !!eeprom->reg_data_clock); + rt2x00_set_field32(®, E2PROM_CSR_CHIP_SELECT, + !!eeprom->reg_chip_select); + + rt2x00pci_register_write(rt2x00dev, E2PROM_CSR, reg); +} + +#ifdef CONFIG_RT2X00_LIB_DEBUGFS +#define CSR_OFFSET(__word) ( CSR_REG_BASE + ((__word) * sizeof(u32)) ) + +static void rt61pci_read_csr(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, u32 *data) +{ + rt2x00pci_register_read(rt2x00dev, CSR_OFFSET(word), data); +} + +static void rt61pci_write_csr(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, u32 data) +{ + rt2x00pci_register_write(rt2x00dev, CSR_OFFSET(word), data); +} + +static const struct rt2x00debug rt61pci_rt2x00debug = { + .owner = THIS_MODULE, + .csr = { + .read = rt61pci_read_csr, + .write = rt61pci_write_csr, + .word_size = sizeof(u32), + .word_count = CSR_REG_SIZE / sizeof(u32), + }, + .eeprom = { + .read = rt2x00_eeprom_read, + .write = rt2x00_eeprom_write, + .word_size = sizeof(u16), + .word_count = EEPROM_SIZE / sizeof(u16), + }, + .bbp = { + .read = rt61pci_bbp_read, + .write = rt61pci_bbp_write, + .word_size = sizeof(u8), + .word_count = BBP_SIZE / sizeof(u8), + }, + .rf = { + .read = rt2x00_rf_read, + .write = rt61pci_rf_write, + .word_size = sizeof(u32), + .word_count = RF_SIZE / sizeof(u32), + }, +}; +#endif /* CONFIG_RT2X00_LIB_DEBUGFS */ + +#ifdef CONFIG_RT61PCI_RFKILL +static int rt61pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + rt2x00pci_register_read(rt2x00dev, MAC_CSR13, ®); + return rt2x00_get_field32(reg, MAC_CSR13_BIT5);; +} +#endif /* CONFIG_RT2400PCI_RFKILL */ + +/* + * Configuration handlers. + */ +static void rt61pci_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *addr) +{ + __le32 reg[2]; + u32 tmp; + + memset(®, 0, sizeof(reg)); + memcpy(®, addr, ETH_ALEN); + + tmp = le32_to_cpu(reg[1]); + rt2x00_set_field32(&tmp, MAC_CSR3_UNICAST_TO_ME_MASK, 0xff); + reg[1] = cpu_to_le32(tmp); + + /* + * The MAC address is passed to us as an array of bytes, + * that array is little endian, so no need for byte ordering. + */ + rt2x00pci_register_multiwrite(rt2x00dev, MAC_CSR2, ®, sizeof(reg)); +} + +static void rt61pci_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) +{ + __le32 reg[2]; + u32 tmp; + + memset(®, 0, sizeof(reg)); + memcpy(®, bssid, ETH_ALEN); + + tmp = le32_to_cpu(reg[1]); + rt2x00_set_field32(&tmp, MAC_CSR5_BSS_ID_MASK, 3); + reg[1] = cpu_to_le32(tmp); + + /* + * The BSSID is passed to us as an array of bytes, + * that array is little endian, so no need for byte ordering. + */ + rt2x00pci_register_multiwrite(rt2x00dev, MAC_CSR4, ®, sizeof(reg)); +} + +static void rt61pci_config_packet_filter(struct rt2x00_dev *rt2x00dev, + const unsigned int filter) +{ + int promisc = !!(filter & IFF_PROMISC); + int multicast = !!(filter & IFF_MULTICAST); + int broadcast = !!(filter & IFF_BROADCAST); + u32 reg; + + rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®); + rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME, !promisc); + rt2x00_set_field32(®, TXRX_CSR0_DROP_MULTICAST, !multicast); + rt2x00_set_field32(®, TXRX_CSR0_DROP_BORADCAST, !broadcast); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); +} + +static void rt61pci_config_type(struct rt2x00_dev *rt2x00dev, const int type) +{ + u32 reg; + + /* + * Clear current synchronisation setup. + * For the Beacon base registers we only need to clear + * the first byte since that byte contains the VALID and OWNER + * bits which (when set to 0) will invalidate the entire beacon. + */ + rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, 0); + rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE0, 0); + rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE1, 0); + rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE2, 0); + rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE3, 0); + + /* + * Apply hardware packet filter. + */ + rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®); + + if (!is_monitor_present(&rt2x00dev->interface) && + (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_STA)) + rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, 1); + else + rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, 0); + + /* + * If there is a non-monitor interface present + * the packet should be strict (even if a monitor interface is present!). + * When there is only 1 interface present which is in monitor mode + * we should start accepting _all_ frames. + */ + if (is_interface_present(&rt2x00dev->interface)) { + rt2x00_set_field32(®, TXRX_CSR0_DROP_CRC, 1); + rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, 1); + rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL, 1); + rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 1); + rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS, 1); + } else if (is_monitor_present(&rt2x00dev->interface)) { + rt2x00_set_field32(®, TXRX_CSR0_DROP_CRC, 0); + rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, 0); + rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL, 0); + rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 0); + rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS, 0); + } + + rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); + + /* + * Enable synchronisation. + */ + rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®); + if (is_interface_present(&rt2x00dev->interface)) { + rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); + rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); + } + + rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); + if (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_AP) + rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 2); + else if (type == IEEE80211_IF_TYPE_STA) + rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 1); + else if (is_monitor_present(&rt2x00dev->interface) && + !is_interface_present(&rt2x00dev->interface)) + rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 0); + + rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); +} + +static void rt61pci_config_rate(struct rt2x00_dev *rt2x00dev, const int rate) +{ + struct ieee80211_conf *conf = &rt2x00dev->hw->conf; + u32 reg; + u32 value; + u32 preamble; + + if (DEVICE_GET_RATE_FIELD(rate, PREAMBLE)) + preamble = SHORT_PREAMBLE; + else + preamble = PREAMBLE; + + /* + * Extract the allowed ratemask from the device specific rate value, + * We need to set TXRX_CSR5 to the basic rate mask so we need to mask + * off the non-basic rates. + */ + reg = DEVICE_GET_RATE_FIELD(rate, RATEMASK) & DEV_BASIC_RATEMASK; + + rt2x00pci_register_write(rt2x00dev, TXRX_CSR5, reg); + + rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®); + value = ((conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) ? + SHORT_DIFS : DIFS) + + PLCP + preamble + get_duration(ACK_SIZE, 10); + rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, value); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); + + rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, ®); + if (preamble == SHORT_PREAMBLE) + rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, 1); + else + rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, 0); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg); +} + +static void rt61pci_config_phymode(struct rt2x00_dev *rt2x00dev, + const int phymode) +{ + struct ieee80211_hw_mode *mode; + struct ieee80211_rate *rate; + + if (phymode == MODE_IEEE80211A) + rt2x00dev->curr_hwmode = HWMODE_A; + else if (phymode == MODE_IEEE80211B) + rt2x00dev->curr_hwmode = HWMODE_B; + else + rt2x00dev->curr_hwmode = HWMODE_G; + + mode = &rt2x00dev->hwmodes[rt2x00dev->curr_hwmode]; + rate = &mode->rates[mode->num_rates - 1]; + + rt61pci_config_rate(rt2x00dev, rate->val2); +} + +static void rt61pci_config_lock_channel(struct rt2x00_dev *rt2x00dev, + struct rf_channel *rf, + const int txpower) +{ + u8 r3; + u8 r94; + u8 smart; + + rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); + rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset); + + smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) || + rt2x00_rf(&rt2x00dev->chip, RF2527)); + + rt61pci_bbp_read(rt2x00dev, 3, &r3); + rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart); + rt61pci_bbp_write(rt2x00dev, 3, r3); + + r94 = 6; + if (txpower > MAX_TXPOWER && txpower <= (MAX_TXPOWER + r94)) + r94 += txpower - MAX_TXPOWER; + else if (txpower < MIN_TXPOWER && txpower >= (MIN_TXPOWER - r94)) + r94 += txpower; + rt61pci_bbp_write(rt2x00dev, 94, r94); + + rt61pci_rf_write(rt2x00dev, 1, rf->rf1); + rt61pci_rf_write(rt2x00dev, 2, rf->rf2); + rt61pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); + rt61pci_rf_write(rt2x00dev, 4, rf->rf4); + + udelay(200); + + rt61pci_rf_write(rt2x00dev, 1, rf->rf1); + rt61pci_rf_write(rt2x00dev, 2, rf->rf2); + rt61pci_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004); + rt61pci_rf_write(rt2x00dev, 4, rf->rf4); + + udelay(200); + + rt61pci_rf_write(rt2x00dev, 1, rf->rf1); + rt61pci_rf_write(rt2x00dev, 2, rf->rf2); + rt61pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); + rt61pci_rf_write(rt2x00dev, 4, rf->rf4); + + msleep(1); +} + +static void rt61pci_config_channel(struct rt2x00_dev *rt2x00dev, + const int index, const int channel, + const int txpower) +{ + struct rf_channel rf; + + /* + * Fill rf_reg structure. + */ + memcpy(&rf, &rt2x00dev->spec.channels[index], sizeof(rf)); + + rt61pci_config_lock_channel(rt2x00dev, &rf, txpower); +} + +static void rt61pci_config_txpower(struct rt2x00_dev *rt2x00dev, + const int txpower) +{ + struct rf_channel rf; + + rt2x00_rf_read(rt2x00dev, 1, &rf.rf1); + rt2x00_rf_read(rt2x00dev, 2, &rf.rf2); + rt2x00_rf_read(rt2x00dev, 3, &rf.rf3); + rt2x00_rf_read(rt2x00dev, 4, &rf.rf4); + + rt61pci_config_lock_channel(rt2x00dev, &rf, txpower); +} + +static void rt61pci_config_antenna_5x(struct rt2x00_dev *rt2x00dev, + const int antenna_tx, + const int antenna_rx) +{ + u8 r3; + u8 r4; + u8 r77; + + rt61pci_bbp_read(rt2x00dev, 3, &r3); + rt61pci_bbp_read(rt2x00dev, 4, &r4); + rt61pci_bbp_read(rt2x00dev, 77, &r77); + + rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, + !rt2x00_rf(&rt2x00dev->chip, RF5225)); + + switch (antenna_rx) { + case ANTENNA_SW_DIVERSITY: + case ANTENNA_HW_DIVERSITY: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2); + rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, + !!(rt2x00dev->curr_hwmode != HWMODE_A)); + break; + case ANTENNA_A: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); + rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0); + + if (rt2x00dev->curr_hwmode == HWMODE_A) + rt2x00_set_field8(&r77, BBP_R77_PAIR, 0); + else + rt2x00_set_field8(&r77, BBP_R77_PAIR, 3); + break; + case ANTENNA_B: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); + rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0); + + if (rt2x00dev->curr_hwmode == HWMODE_A) + rt2x00_set_field8(&r77, BBP_R77_PAIR, 3); + else + rt2x00_set_field8(&r77, BBP_R77_PAIR, 0); + break; + } + + rt61pci_bbp_write(rt2x00dev, 77, r77); + rt61pci_bbp_write(rt2x00dev, 3, r3); + rt61pci_bbp_write(rt2x00dev, 4, r4); +} + +static void rt61pci_config_antenna_2x(struct rt2x00_dev *rt2x00dev, + const int antenna_tx, + const int antenna_rx) +{ + u8 r3; + u8 r4; + u8 r77; + + rt61pci_bbp_read(rt2x00dev, 3, &r3); + rt61pci_bbp_read(rt2x00dev, 4, &r4); + rt61pci_bbp_read(rt2x00dev, 77, &r77); + + rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, + !rt2x00_rf(&rt2x00dev->chip, RF2527)); + rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, + !test_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags)); + + switch (antenna_rx) { + case ANTENNA_SW_DIVERSITY: + case ANTENNA_HW_DIVERSITY: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2); + break; + case ANTENNA_A: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); + rt2x00_set_field8(&r77, BBP_R77_PAIR, 3); + break; + case ANTENNA_B: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); + rt2x00_set_field8(&r77, BBP_R77_PAIR, 0); + break; + } + + rt61pci_bbp_write(rt2x00dev, 77, r77); + rt61pci_bbp_write(rt2x00dev, 3, r3); + rt61pci_bbp_write(rt2x00dev, 4, r4); +} + +static void rt61pci_config_antenna_2529_rx(struct rt2x00_dev *rt2x00dev, + const int p1, const int p2) +{ + u32 reg; + + rt2x00pci_register_read(rt2x00dev, MAC_CSR13, ®); + + if (p1 != 0xff) { + rt2x00_set_field32(®, MAC_CSR13_BIT4, !!p1); + rt2x00_set_field32(®, MAC_CSR13_BIT12, 0); + rt2x00pci_register_write(rt2x00dev, MAC_CSR13, reg); + } + if (p2 != 0xff) { + rt2x00_set_field32(®, MAC_CSR13_BIT3, !p2); + rt2x00_set_field32(®, MAC_CSR13_BIT11, 0); + rt2x00pci_register_write(rt2x00dev, MAC_CSR13, reg); + } +} + +static void rt61pci_config_antenna_2529(struct rt2x00_dev *rt2x00dev, + const int antenna_tx, + const int antenna_rx) +{ + u16 eeprom; + u8 r3; + u8 r4; + u8 r77; + + rt61pci_bbp_read(rt2x00dev, 3, &r3); + rt61pci_bbp_read(rt2x00dev, 4, &r4); + rt61pci_bbp_read(rt2x00dev, 77, &r77); + rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom); + + rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, 0); + + if (rt2x00_get_field16(eeprom, EEPROM_NIC_ENABLE_DIVERSITY) && + rt2x00_get_field16(eeprom, EEPROM_NIC_TX_DIVERSITY)) { + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2); + rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 1); + rt61pci_config_antenna_2529_rx(rt2x00dev, 0, 1); + } else if (rt2x00_get_field16(eeprom, EEPROM_NIC_ENABLE_DIVERSITY)) { + if (rt2x00_get_field16(eeprom, EEPROM_NIC_TX_RX_FIXED) >= 2) { + rt2x00_set_field8(&r77, BBP_R77_PAIR, 3); + rt61pci_bbp_write(rt2x00dev, 77, r77); + } + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); + rt61pci_config_antenna_2529_rx(rt2x00dev, 1, 1); + } else if (!rt2x00_get_field16(eeprom, EEPROM_NIC_ENABLE_DIVERSITY) && + rt2x00_get_field16(eeprom, EEPROM_NIC_TX_DIVERSITY)) { + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2); + rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0); + + switch (rt2x00_get_field16(eeprom, EEPROM_NIC_TX_RX_FIXED)) { + case 0: + rt61pci_config_antenna_2529_rx(rt2x00dev, 0, 1); + break; + case 1: + rt61pci_config_antenna_2529_rx(rt2x00dev, 1, 0); + break; + case 2: + rt61pci_config_antenna_2529_rx(rt2x00dev, 0, 0); + break; + case 3: + rt61pci_config_antenna_2529_rx(rt2x00dev, 1, 1); + break; + } + } else if (!rt2x00_get_field16(eeprom, EEPROM_NIC_ENABLE_DIVERSITY) && + !rt2x00_get_field16(eeprom, EEPROM_NIC_TX_DIVERSITY)) { + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); + rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0); + + switch (rt2x00_get_field16(eeprom, EEPROM_NIC_TX_RX_FIXED)) { + case 0: + rt2x00_set_field8(&r77, BBP_R77_PAIR, 0); + rt61pci_bbp_write(rt2x00dev, 77, r77); + rt61pci_config_antenna_2529_rx(rt2x00dev, 0, 1); + break; + case 1: + rt2x00_set_field8(&r77, BBP_R77_PAIR, 0); + rt61pci_bbp_write(rt2x00dev, 77, r77); + rt61pci_config_antenna_2529_rx(rt2x00dev, 1, 0); + break; + case 2: + rt2x00_set_field8(&r77, BBP_R77_PAIR, 3); + rt61pci_bbp_write(rt2x00dev, 77, r77); + rt61pci_config_antenna_2529_rx(rt2x00dev, 0, 0); + break; + case 3: + rt2x00_set_field8(&r77, BBP_R77_PAIR, 3); + rt61pci_bbp_write(rt2x00dev, 77, r77); + rt61pci_config_antenna_2529_rx(rt2x00dev, 1, 1); + break; + } + } + + rt61pci_bbp_write(rt2x00dev, 3, r3); + rt61pci_bbp_write(rt2x00dev, 4, r4); +} + +struct antenna_sel { + u8 word; + /* + * value[0] -> non-LNA + * value[1] -> LNA + */ + u8 value[2]; +}; + +static const struct antenna_sel antenna_sel_a[] = { + { 96, { 0x58, 0x78 } }, + { 104, { 0x38, 0x48 } }, + { 75, { 0xfe, 0x80 } }, + { 86, { 0xfe, 0x80 } }, + { 88, { 0xfe, 0x80 } }, + { 35, { 0x60, 0x60 } }, + { 97, { 0x58, 0x58 } }, + { 98, { 0x58, 0x58 } }, +}; + +static const struct antenna_sel antenna_sel_bg[] = { + { 96, { 0x48, 0x68 } }, + { 104, { 0x2c, 0x3c } }, + { 75, { 0xfe, 0x80 } }, + { 86, { 0xfe, 0x80 } }, + { 88, { 0xfe, 0x80 } }, + { 35, { 0x50, 0x50 } }, + { 97, { 0x48, 0x48 } }, + { 98, { 0x48, 0x48 } }, +}; + +static void rt61pci_config_antenna(struct rt2x00_dev *rt2x00dev, + const int antenna_tx, const int antenna_rx) +{ + const struct antenna_sel *sel; + unsigned int lna; + unsigned int i; + u32 reg; + + rt2x00pci_register_read(rt2x00dev, PHY_CSR0, ®); + + if (rt2x00dev->curr_hwmode == HWMODE_A) { + sel = antenna_sel_a; + lna = test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags); + + rt2x00_set_field32(®, PHY_CSR0_PA_PE_BG, 0); + rt2x00_set_field32(®, PHY_CSR0_PA_PE_A, 1); + } else { + sel = antenna_sel_bg; + lna = test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags); + + rt2x00_set_field32(®, PHY_CSR0_PA_PE_BG, 1); + rt2x00_set_field32(®, PHY_CSR0_PA_PE_A, 0); + } + + for (i = 0; i < ARRAY_SIZE(antenna_sel_a); i++) + rt61pci_bbp_write(rt2x00dev, sel[i].word, sel[i].value[lna]); + + rt2x00pci_register_write(rt2x00dev, PHY_CSR0, reg); + + if (rt2x00_rf(&rt2x00dev->chip, RF5225) || + rt2x00_rf(&rt2x00dev->chip, RF5325)) + rt61pci_config_antenna_5x(rt2x00dev, antenna_tx, antenna_rx); + else if (rt2x00_rf(&rt2x00dev->chip, RF2527)) + rt61pci_config_antenna_2x(rt2x00dev, antenna_tx, antenna_rx); + else if (rt2x00_rf(&rt2x00dev->chip, RF2529)) { + if (test_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags)) + rt61pci_config_antenna_2x(rt2x00dev, antenna_tx, + antenna_rx); + else + rt61pci_config_antenna_2529(rt2x00dev, antenna_tx, + antenna_rx); + } +} + +static void rt61pci_config_duration(struct rt2x00_dev *rt2x00dev, + const int short_slot_time, + const int beacon_int) +{ + u32 reg; + + rt2x00pci_register_read(rt2x00dev, MAC_CSR9, ®); + rt2x00_set_field32(®, MAC_CSR9_SLOT_TIME, + short_slot_time ? SHORT_SLOT_TIME : SLOT_TIME); + rt2x00pci_register_write(rt2x00dev, MAC_CSR9, reg); + + rt2x00pci_register_read(rt2x00dev, MAC_CSR8, ®); + rt2x00_set_field32(®, MAC_CSR8_SIFS, SIFS); + rt2x00_set_field32(®, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3); + rt2x00_set_field32(®, MAC_CSR8_EIFS, EIFS); + rt2x00pci_register_write(rt2x00dev, MAC_CSR8, reg); + + rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®); + rt2x00_set_field32(®, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); + + rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, ®); + rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_ENABLE, 1); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg); + + rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®); + rt2x00_set_field32(®, TXRX_CSR9_BEACON_INTERVAL, beacon_int * 16); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); +} + +static void rt61pci_config(struct rt2x00_dev *rt2x00dev, + const unsigned int flags, + struct ieee80211_conf *conf) +{ + int short_slot_time = conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME; + + if (flags & CONFIG_UPDATE_PHYMODE) + rt61pci_config_phymode(rt2x00dev, conf->phymode); + if (flags & CONFIG_UPDATE_CHANNEL) + rt61pci_config_channel(rt2x00dev, conf->channel_val, + conf->channel, conf->power_level); + if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL)) + rt61pci_config_txpower(rt2x00dev, conf->power_level); + if (flags & CONFIG_UPDATE_ANTENNA) + rt61pci_config_antenna(rt2x00dev, conf->antenna_sel_tx, + conf->antenna_sel_rx); + if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT)) + rt61pci_config_duration(rt2x00dev, short_slot_time, + conf->beacon_int); +} + +/* + * LED functions. + */ +static void rt61pci_enable_led(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + u16 led_reg; + u8 arg0; + u8 arg1; + + rt2x00pci_register_read(rt2x00dev, MAC_CSR14, ®); + rt2x00_set_field32(®, MAC_CSR14_ON_PERIOD, 70); + rt2x00_set_field32(®, MAC_CSR14_OFF_PERIOD, 30); + rt2x00pci_register_write(rt2x00dev, MAC_CSR14, reg); + + led_reg = rt2x00dev->led_reg; + rt2x00_set_field16(&led_reg, MCU_LEDCS_RADIO_STATUS, 1); + if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A) + rt2x00_set_field16(&led_reg, MCU_LEDCS_LINK_A_STATUS, 1); + else + rt2x00_set_field16(&led_reg, MCU_LEDCS_LINK_BG_STATUS, 1); + + arg0 = led_reg & 0xff; + arg1 = (led_reg >> 8) & 0xff; + + rt61pci_mcu_request(rt2x00dev, MCU_LED, 0xff, arg0, arg1); +} + +static void rt61pci_disable_led(struct rt2x00_dev *rt2x00dev) +{ + u16 led_reg; + u8 arg0; + u8 arg1; + + led_reg = rt2x00dev->led_reg; + rt2x00_set_field16(&led_reg, MCU_LEDCS_RADIO_STATUS, 0); + rt2x00_set_field16(&led_reg, MCU_LEDCS_LINK_BG_STATUS, 0); + rt2x00_set_field16(&led_reg, MCU_LEDCS_LINK_A_STATUS, 0); + + arg0 = led_reg & 0xff; + arg1 = (led_reg >> 8) & 0xff; + + rt61pci_mcu_request(rt2x00dev, MCU_LED, 0xff, arg0, arg1); +} + +static void rt61pci_activity_led(struct rt2x00_dev *rt2x00dev, int rssi) +{ + u8 led; + + if (rt2x00dev->led_mode != LED_MODE_SIGNAL_STRENGTH) + return; + + /* + * Led handling requires a positive value for the rssi, + * to do that correctly we need to add the correction. + */ + rssi += rt2x00dev->rssi_offset; + + if (rssi <= 30) + led = 0; + else if (rssi <= 39) + led = 1; + else if (rssi <= 49) + led = 2; + else if (rssi <= 53) + led = 3; + else if (rssi <= 63) + led = 4; + else + led = 5; + + rt61pci_mcu_request(rt2x00dev, MCU_LED_STRENGTH, 0xff, led, 0); +} + +/* + * Link tuning + */ +static void rt61pci_link_stats(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + /* + * Update FCS error count from register. + */ + rt2x00pci_register_read(rt2x00dev, STA_CSR0, ®); + rt2x00dev->link.rx_failed = rt2x00_get_field32(reg, STA_CSR0_FCS_ERROR); + + /* + * Update False CCA count from register. + */ + rt2x00pci_register_read(rt2x00dev, STA_CSR1, ®); + rt2x00dev->link.false_cca = + rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR); +} + +static void rt61pci_reset_tuner(struct rt2x00_dev *rt2x00dev) +{ + rt61pci_bbp_write(rt2x00dev, 17, 0x20); + rt2x00dev->link.vgc_level = 0x20; +} + +static void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev) +{ + int rssi = rt2x00_get_link_rssi(&rt2x00dev->link); + u8 r17; + u8 up_bound; + u8 low_bound; + + /* + * Update Led strength + */ + rt61pci_activity_led(rt2x00dev, rssi); + + rt61pci_bbp_read(rt2x00dev, 17, &r17); + + /* + * Determine r17 bounds. + */ + if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A) { + low_bound = 0x28; + up_bound = 0x48; + if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) { + low_bound += 0x10; + up_bound += 0x10; + } + } else { + low_bound = 0x20; + up_bound = 0x40; + if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) { + low_bound += 0x10; + up_bound += 0x10; + } + } + + /* + * Special big-R17 for very short distance + */ + if (rssi >= -35) { + if (r17 != 0x60) + rt61pci_bbp_write(rt2x00dev, 17, 0x60); + return; + } + + /* + * Special big-R17 for short distance + */ + if (rssi >= -58) { + if (r17 != up_bound) + rt61pci_bbp_write(rt2x00dev, 17, up_bound); + return; + } + + /* + * Special big-R17 for middle-short distance + */ + if (rssi >= -66) { + low_bound += 0x10; + if (r17 != low_bound) + rt61pci_bbp_write(rt2x00dev, 17, low_bound); + return; + } + + /* + * Special mid-R17 for middle distance + */ + if (rssi >= -74) { + low_bound += 0x08; + if (r17 != low_bound) + rt61pci_bbp_write(rt2x00dev, 17, low_bound); + return; + } + + /* + * Special case: Change up_bound based on the rssi. + * Lower up_bound when rssi is weaker then -74 dBm. + */ + up_bound -= 2 * (-74 - rssi); + if (low_bound > up_bound) + up_bound = low_bound; + + if (r17 > up_bound) { + rt61pci_bbp_write(rt2x00dev, 17, up_bound); + return; + } + + /* + * r17 does not yet exceed upper limit, continue and base + * the r17 tuning on the false CCA count. + */ + if (rt2x00dev->link.false_cca > 512 && r17 < up_bound) { + if (++r17 > up_bound) + r17 = up_bound; + rt61pci_bbp_write(rt2x00dev, 17, r17); + } else if (rt2x00dev->link.false_cca < 100 && r17 > low_bound) { + if (--r17 < low_bound) + r17 = low_bound; + rt61pci_bbp_write(rt2x00dev, 17, r17); + } +} + +/* + * Firmware name function. + */ +static char *rt61pci_get_firmware_name(struct rt2x00_dev *rt2x00dev) +{ + char *fw_name; + + switch (rt2x00dev->chip.rt) { + case RT2561: + fw_name = FIRMWARE_RT2561; + break; + case RT2561s: + fw_name = FIRMWARE_RT2561s; + break; + case RT2661: + fw_name = FIRMWARE_RT2661; + break; + default: + fw_name = NULL; + break; + } + + return fw_name; +} + +/* + * Initialization functions. + */ +static int rt61pci_load_firmware(struct rt2x00_dev *rt2x00dev, void *data, + const size_t len) +{ + int i; + u32 reg; + + /* + * Wait for stable hardware. + */ + for (i = 0; i < 100; i++) { + rt2x00pci_register_read(rt2x00dev, MAC_CSR0, ®); + if (reg) + break; + msleep(1); + } + + if (!reg) { + ERROR(rt2x00dev, "Unstable hardware.\n"); + return -EBUSY; + } + + /* + * Prepare MCU and mailbox for firmware loading. + */ + reg = 0; + rt2x00_set_field32(®, MCU_CNTL_CSR_RESET, 1); + rt2x00pci_register_write(rt2x00dev, MCU_CNTL_CSR, reg); + rt2x00pci_register_write(rt2x00dev, M2H_CMD_DONE_CSR, 0xffffffff); + rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0); + rt2x00pci_register_write(rt2x00dev, HOST_CMD_CSR, 0); + + /* + * Write firmware to device. + */ + reg = 0; + rt2x00_set_field32(®, MCU_CNTL_CSR_RESET, 1); + rt2x00_set_field32(®, MCU_CNTL_CSR_SELECT_BANK, 1); + rt2x00pci_register_write(rt2x00dev, MCU_CNTL_CSR, reg); + + rt2x00pci_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE, + data, len); + + rt2x00_set_field32(®, MCU_CNTL_CSR_SELECT_BANK, 0); + rt2x00pci_register_write(rt2x00dev, MCU_CNTL_CSR, reg); + + rt2x00_set_field32(®, MCU_CNTL_CSR_RESET, 0); + rt2x00pci_register_write(rt2x00dev, MCU_CNTL_CSR, reg); + + for (i = 0; i < 100; i++) { + rt2x00pci_register_read(rt2x00dev, MCU_CNTL_CSR, ®); + if (rt2x00_get_field32(reg, MCU_CNTL_CSR_READY)) + break; + msleep(1); + } + + if (i == 100) { + ERROR(rt2x00dev, "MCU Control register not ready.\n"); + return -EBUSY; + } + + /* + * Reset MAC and BBP registers. + */ + reg = 0; + rt2x00_set_field32(®, MAC_CSR1_SOFT_RESET, 1); + rt2x00_set_field32(®, MAC_CSR1_BBP_RESET, 1); + rt2x00pci_register_write(rt2x00dev, MAC_CSR1, reg); + + rt2x00pci_register_read(rt2x00dev, MAC_CSR1, ®); + rt2x00_set_field32(®, MAC_CSR1_SOFT_RESET, 0); + rt2x00_set_field32(®, MAC_CSR1_BBP_RESET, 0); + rt2x00pci_register_write(rt2x00dev, MAC_CSR1, reg); + + rt2x00pci_register_read(rt2x00dev, MAC_CSR1, ®); + rt2x00_set_field32(®, MAC_CSR1_HOST_READY, 1); + rt2x00pci_register_write(rt2x00dev, MAC_CSR1, reg); + + return 0; +} + +static void rt61pci_init_rxring(struct rt2x00_dev *rt2x00dev) +{ + struct data_ring *ring = rt2x00dev->rx; + struct data_desc *rxd; + unsigned int i; + u32 word; + + memset(ring->data_addr, 0x00, rt2x00_get_ring_size(ring)); + + for (i = 0; i < ring->stats.limit; i++) { + rxd = ring->entry[i].priv; + + rt2x00_desc_read(rxd, 5, &word); + rt2x00_set_field32(&word, RXD_W5_BUFFER_PHYSICAL_ADDRESS, + ring->entry[i].data_dma); + rt2x00_desc_write(rxd, 5, word); + + rt2x00_desc_read(rxd, 0, &word); + rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); + rt2x00_desc_write(rxd, 0, word); + } + + rt2x00_ring_index_clear(rt2x00dev->rx); +} + +static void rt61pci_init_txring(struct rt2x00_dev *rt2x00dev, const int queue) +{ + struct data_ring *ring = rt2x00lib_get_ring(rt2x00dev, queue); + struct data_desc *txd; + unsigned int i; + u32 word; + + memset(ring->data_addr, 0x00, rt2x00_get_ring_size(ring)); + + for (i = 0; i < ring->stats.limit; i++) { + txd = ring->entry[i].priv; + + rt2x00_desc_read(txd, 1, &word); + rt2x00_set_field32(&word, TXD_W1_BUFFER_COUNT, 1); + rt2x00_desc_write(txd, 1, word); + + rt2x00_desc_read(txd, 5, &word); + rt2x00_set_field32(&word, TXD_W5_PID_TYPE, queue); + rt2x00_set_field32(&word, TXD_W5_PID_SUBTYPE, i); + rt2x00_desc_write(txd, 5, word); + + rt2x00_desc_read(txd, 6, &word); + rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS, + ring->entry[i].data_dma); + rt2x00_desc_write(txd, 6, word); + + rt2x00_desc_read(txd, 0, &word); + rt2x00_set_field32(&word, TXD_W0_VALID, 0); + rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); + rt2x00_desc_write(txd, 0, word); + } + + rt2x00_ring_index_clear(ring); +} + +static int rt61pci_init_rings(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + /* + * Initialize rings. + */ + rt61pci_init_rxring(rt2x00dev); + rt61pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA0); + rt61pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA1); + rt61pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA2); + rt61pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA3); + rt61pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA4); + + /* + * Initialize registers. + */ + rt2x00pci_register_read(rt2x00dev, TX_RING_CSR0, ®); + rt2x00_set_field32(®, TX_RING_CSR0_AC0_RING_SIZE, + rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].stats.limit); + rt2x00_set_field32(®, TX_RING_CSR0_AC1_RING_SIZE, + rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA1].stats.limit); + rt2x00_set_field32(®, TX_RING_CSR0_AC2_RING_SIZE, + rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA2].stats.limit); + rt2x00_set_field32(®, TX_RING_CSR0_AC3_RING_SIZE, + rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA3].stats.limit); + rt2x00pci_register_write(rt2x00dev, TX_RING_CSR0, reg); + + rt2x00pci_register_read(rt2x00dev, TX_RING_CSR1, ®); + rt2x00_set_field32(®, TX_RING_CSR1_MGMT_RING_SIZE, + rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA4].stats.limit); + rt2x00_set_field32(®, TX_RING_CSR1_TXD_SIZE, + rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].desc_size / + 4); + rt2x00pci_register_write(rt2x00dev, TX_RING_CSR1, reg); + + rt2x00pci_register_read(rt2x00dev, AC0_BASE_CSR, ®); + rt2x00_set_field32(®, AC0_BASE_CSR_RING_REGISTER, + rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].data_dma); + rt2x00pci_register_write(rt2x00dev, AC0_BASE_CSR, reg); + + rt2x00pci_register_read(rt2x00dev, AC1_BASE_CSR, ®); + rt2x00_set_field32(®, AC1_BASE_CSR_RING_REGISTER, + rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA1].data_dma); + rt2x00pci_register_write(rt2x00dev, AC1_BASE_CSR, reg); + + rt2x00pci_register_read(rt2x00dev, AC2_BASE_CSR, ®); + rt2x00_set_field32(®, AC2_BASE_CSR_RING_REGISTER, + rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA2].data_dma); + rt2x00pci_register_write(rt2x00dev, AC2_BASE_CSR, reg); + + rt2x00pci_register_read(rt2x00dev, AC3_BASE_CSR, ®); + rt2x00_set_field32(®, AC3_BASE_CSR_RING_REGISTER, + rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA3].data_dma); + rt2x00pci_register_write(rt2x00dev, AC3_BASE_CSR, reg); + + rt2x00pci_register_read(rt2x00dev, MGMT_BASE_CSR, ®); + rt2x00_set_field32(®, MGMT_BASE_CSR_RING_REGISTER, + rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA4].data_dma); + rt2x00pci_register_write(rt2x00dev, MGMT_BASE_CSR, reg); + + rt2x00pci_register_read(rt2x00dev, RX_RING_CSR, ®); + rt2x00_set_field32(®, RX_RING_CSR_RING_SIZE, + rt2x00dev->rx->stats.limit); + rt2x00_set_field32(®, RX_RING_CSR_RXD_SIZE, + rt2x00dev->rx->desc_size / 4); + rt2x00_set_field32(®, RX_RING_CSR_RXD_WRITEBACK_SIZE, 4); + rt2x00pci_register_write(rt2x00dev, RX_RING_CSR, reg); + + rt2x00pci_register_read(rt2x00dev, RX_BASE_CSR, ®); + rt2x00_set_field32(®, RX_BASE_CSR_RING_REGISTER, + rt2x00dev->rx->data_dma); + rt2x00pci_register_write(rt2x00dev, RX_BASE_CSR, reg); + + rt2x00pci_register_read(rt2x00dev, TX_DMA_DST_CSR, ®); + rt2x00_set_field32(®, TX_DMA_DST_CSR_DEST_AC0, 2); + rt2x00_set_field32(®, TX_DMA_DST_CSR_DEST_AC1, 2); + rt2x00_set_field32(®, TX_DMA_DST_CSR_DEST_AC2, 2); + rt2x00_set_field32(®, TX_DMA_DST_CSR_DEST_AC3, 2); + rt2x00_set_field32(®, TX_DMA_DST_CSR_DEST_MGMT, 0); + rt2x00pci_register_write(rt2x00dev, TX_DMA_DST_CSR, reg); + + rt2x00pci_register_read(rt2x00dev, LOAD_TX_RING_CSR, ®); + rt2x00_set_field32(®, LOAD_TX_RING_CSR_LOAD_TXD_AC0, 1); + rt2x00_set_field32(®, LOAD_TX_RING_CSR_LOAD_TXD_AC1, 1); + rt2x00_set_field32(®, LOAD_TX_RING_CSR_LOAD_TXD_AC2, 1); + rt2x00_set_field32(®, LOAD_TX_RING_CSR_LOAD_TXD_AC3, 1); + rt2x00_set_field32(®, LOAD_TX_RING_CSR_LOAD_TXD_MGMT, 1); + rt2x00pci_register_write(rt2x00dev, LOAD_TX_RING_CSR, reg); + + rt2x00pci_register_read(rt2x00dev, RX_CNTL_CSR, ®); + rt2x00_set_field32(®, RX_CNTL_CSR_LOAD_RXD, 1); + rt2x00pci_register_write(rt2x00dev, RX_CNTL_CSR, reg); + + return 0; +} + +static int rt61pci_init_registers(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®); + rt2x00_set_field32(®, TXRX_CSR0_AUTO_TX_SEQ, 1); + rt2x00_set_field32(®, TXRX_CSR0_DISABLE_RX, 0); + rt2x00_set_field32(®, TXRX_CSR0_TX_WITHOUT_WAITING, 0); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); + + rt2x00pci_register_read(rt2x00dev, TXRX_CSR1, ®); + rt2x00_set_field32(®, TXRX_CSR1_BBP_ID0, 47); /* CCK Signal */ + rt2x00_set_field32(®, TXRX_CSR1_BBP_ID0_VALID, 1); + rt2x00_set_field32(®, TXRX_CSR1_BBP_ID1, 30); /* Rssi */ + rt2x00_set_field32(®, TXRX_CSR1_BBP_ID1_VALID, 1); + rt2x00_set_field32(®, TXRX_CSR1_BBP_ID2, 42); /* OFDM Rate */ + rt2x00_set_field32(®, TXRX_CSR1_BBP_ID2_VALID, 1); + rt2x00_set_field32(®, TXRX_CSR1_BBP_ID3, 30); /* Rssi */ + rt2x00_set_field32(®, TXRX_CSR1_BBP_ID3_VALID, 1); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR1, reg); + + /* + * CCK TXD BBP registers + */ + rt2x00pci_register_read(rt2x00dev, TXRX_CSR2, ®); + rt2x00_set_field32(®, TXRX_CSR2_BBP_ID0, 13); + rt2x00_set_field32(®, TXRX_CSR2_BBP_ID0_VALID, 1); + rt2x00_set_field32(®, TXRX_CSR2_BBP_ID1, 12); + rt2x00_set_field32(®, TXRX_CSR2_BBP_ID1_VALID, 1); + rt2x00_set_field32(®, TXRX_CSR2_BBP_ID2, 11); + rt2x00_set_field32(®, TXRX_CSR2_BBP_ID2_VALID, 1); + rt2x00_set_field32(®, TXRX_CSR2_BBP_ID3, 10); + rt2x00_set_field32(®, TXRX_CSR2_BBP_ID3_VALID, 1); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR2, reg); + + /* + * OFDM TXD BBP registers + */ + rt2x00pci_register_read(rt2x00dev, TXRX_CSR3, ®); + rt2x00_set_field32(®, TXRX_CSR3_BBP_ID0, 7); + rt2x00_set_field32(®, TXRX_CSR3_BBP_ID0_VALID, 1); + rt2x00_set_field32(®, TXRX_CSR3_BBP_ID1, 6); + rt2x00_set_field32(®, TXRX_CSR3_BBP_ID1_VALID, 1); + rt2x00_set_field32(®, TXRX_CSR3_BBP_ID2, 5); + rt2x00_set_field32(®, TXRX_CSR3_BBP_ID2_VALID, 1); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR3, reg); + + rt2x00pci_register_read(rt2x00dev, TXRX_CSR7, ®); + rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_6MBS, 59); + rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_9MBS, 53); + rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_12MBS, 49); + rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_18MBS, 46); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR7, reg); + + rt2x00pci_register_read(rt2x00dev, TXRX_CSR8, ®); + rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_24MBS, 44); + rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_36MBS, 42); + rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_48MBS, 42); + rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_54MBS, 42); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR8, reg); + + rt2x00pci_register_write(rt2x00dev, TXRX_CSR15, 0x0000000f); + + rt2x00pci_register_write(rt2x00dev, MAC_CSR6, 0x00000fff); + + rt2x00pci_register_read(rt2x00dev, MAC_CSR9, ®); + rt2x00_set_field32(®, MAC_CSR9_CW_SELECT, 0); + rt2x00pci_register_write(rt2x00dev, MAC_CSR9, reg); + + rt2x00pci_register_write(rt2x00dev, MAC_CSR10, 0x0000071c); + + if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE)) + return -EBUSY; + + rt2x00pci_register_write(rt2x00dev, MAC_CSR13, 0x0000e000); + + /* + * Invalidate all Shared Keys (SEC_CSR0), + * and clear the Shared key Cipher algorithms (SEC_CSR1 & SEC_CSR5) + */ + rt2x00pci_register_write(rt2x00dev, SEC_CSR0, 0x00000000); + rt2x00pci_register_write(rt2x00dev, SEC_CSR1, 0x00000000); + rt2x00pci_register_write(rt2x00dev, SEC_CSR5, 0x00000000); + + rt2x00pci_register_write(rt2x00dev, PHY_CSR1, 0x000023b0); + rt2x00pci_register_write(rt2x00dev, PHY_CSR5, 0x060a100c); + rt2x00pci_register_write(rt2x00dev, PHY_CSR6, 0x00080606); + rt2x00pci_register_write(rt2x00dev, PHY_CSR7, 0x00000a08); + + rt2x00pci_register_write(rt2x00dev, PCI_CFG_CSR, 0x28ca4404); + + rt2x00pci_register_write(rt2x00dev, TEST_MODE_CSR, 0x00000200); + + rt2x00pci_register_write(rt2x00dev, M2H_CMD_DONE_CSR, 0xffffffff); + + rt2x00pci_register_read(rt2x00dev, AC_TXOP_CSR0, ®); + rt2x00_set_field32(®, AC_TXOP_CSR0_AC0_TX_OP, 0); + rt2x00_set_field32(®, AC_TXOP_CSR0_AC1_TX_OP, 0); + rt2x00pci_register_write(rt2x00dev, AC_TXOP_CSR0, reg); + + rt2x00pci_register_read(rt2x00dev, AC_TXOP_CSR1, ®); + rt2x00_set_field32(®, AC_TXOP_CSR1_AC2_TX_OP, 192); + rt2x00_set_field32(®, AC_TXOP_CSR1_AC3_TX_OP, 48); + rt2x00pci_register_write(rt2x00dev, AC_TXOP_CSR1, reg); + + /* + * We must clear the error counters. + * These registers are cleared on read, + * so we may pass a useless variable to store the value. + */ + rt2x00pci_register_read(rt2x00dev, STA_CSR0, ®); + rt2x00pci_register_read(rt2x00dev, STA_CSR1, ®); + rt2x00pci_register_read(rt2x00dev, STA_CSR2, ®); + + /* + * Reset MAC and BBP registers. + */ + rt2x00pci_register_read(rt2x00dev, MAC_CSR1, ®); + rt2x00_set_field32(®, MAC_CSR1_SOFT_RESET, 1); + rt2x00_set_field32(®, MAC_CSR1_BBP_RESET, 1); + rt2x00pci_register_write(rt2x00dev, MAC_CSR1, reg); + + rt2x00pci_register_read(rt2x00dev, MAC_CSR1, ®); + rt2x00_set_field32(®, MAC_CSR1_SOFT_RESET, 0); + rt2x00_set_field32(®, MAC_CSR1_BBP_RESET, 0); + rt2x00pci_register_write(rt2x00dev, MAC_CSR1, reg); + + rt2x00pci_register_read(rt2x00dev, MAC_CSR1, ®); + rt2x00_set_field32(®, MAC_CSR1_HOST_READY, 1); + rt2x00pci_register_write(rt2x00dev, MAC_CSR1, reg); + + return 0; +} + +static int rt61pci_init_bbp(struct rt2x00_dev *rt2x00dev) +{ + unsigned int i; + u16 eeprom; + u8 reg_id; + u8 value; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt61pci_bbp_read(rt2x00dev, 0, &value); + if ((value != 0xff) && (value != 0x00)) + goto continue_csr_init; + NOTICE(rt2x00dev, "Waiting for BBP register.\n"); + udelay(REGISTER_BUSY_DELAY); + } + + ERROR(rt2x00dev, "BBP register access failed, aborting.\n"); + return -EACCES; + +continue_csr_init: + rt61pci_bbp_write(rt2x00dev, 3, 0x00); + rt61pci_bbp_write(rt2x00dev, 15, 0x30); + rt61pci_bbp_write(rt2x00dev, 21, 0xc8); + rt61pci_bbp_write(rt2x00dev, 22, 0x38); + rt61pci_bbp_write(rt2x00dev, 23, 0x06); + rt61pci_bbp_write(rt2x00dev, 24, 0xfe); + rt61pci_bbp_write(rt2x00dev, 25, 0x0a); + rt61pci_bbp_write(rt2x00dev, 26, 0x0d); + rt61pci_bbp_write(rt2x00dev, 34, 0x12); + rt61pci_bbp_write(rt2x00dev, 37, 0x07); + rt61pci_bbp_write(rt2x00dev, 39, 0xf8); + rt61pci_bbp_write(rt2x00dev, 41, 0x60); + rt61pci_bbp_write(rt2x00dev, 53, 0x10); + rt61pci_bbp_write(rt2x00dev, 54, 0x18); + rt61pci_bbp_write(rt2x00dev, 60, 0x10); + rt61pci_bbp_write(rt2x00dev, 61, 0x04); + rt61pci_bbp_write(rt2x00dev, 62, 0x04); + rt61pci_bbp_write(rt2x00dev, 75, 0xfe); + rt61pci_bbp_write(rt2x00dev, 86, 0xfe); + rt61pci_bbp_write(rt2x00dev, 88, 0xfe); + rt61pci_bbp_write(rt2x00dev, 90, 0x0f); + rt61pci_bbp_write(rt2x00dev, 99, 0x00); + rt61pci_bbp_write(rt2x00dev, 102, 0x16); + rt61pci_bbp_write(rt2x00dev, 107, 0x04); + + DEBUG(rt2x00dev, "Start initialization from EEPROM...\n"); + for (i = 0; i < EEPROM_BBP_SIZE; i++) { + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom); + + if (eeprom != 0xffff && eeprom != 0x0000) { + reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID); + value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE); + DEBUG(rt2x00dev, "BBP: 0x%02x, value: 0x%02x.\n", + reg_id, value); + rt61pci_bbp_write(rt2x00dev, reg_id, value); + } + } + DEBUG(rt2x00dev, "...End initialization from EEPROM.\n"); + + return 0; +} + +/* + * Device state switch handlers. + */ +static void rt61pci_toggle_rx(struct rt2x00_dev *rt2x00dev, + enum dev_state state) +{ + u32 reg; + + rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®); + rt2x00_set_field32(®, TXRX_CSR0_DISABLE_RX, + state == STATE_RADIO_RX_OFF); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); +} + +static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev, + enum dev_state state) +{ + int mask = (state == STATE_RADIO_IRQ_OFF); + u32 reg; + + /* + * When interrupts are being enabled, the interrupt registers + * should clear the register to assure a clean state. + */ + if (state == STATE_RADIO_IRQ_ON) { + rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, ®); + rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg); + + rt2x00pci_register_read(rt2x00dev, MCU_INT_SOURCE_CSR, ®); + rt2x00pci_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg); + } + + /* + * Only toggle the interrupts bits we are going to use. + * Non-checked interrupt bits are disabled by default. + */ + rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, ®); + rt2x00_set_field32(®, INT_MASK_CSR_TXDONE, mask); + rt2x00_set_field32(®, INT_MASK_CSR_RXDONE, mask); + rt2x00_set_field32(®, INT_MASK_CSR_ENABLE_MITIGATION, mask); + rt2x00_set_field32(®, INT_MASK_CSR_MITIGATION_PERIOD, 0xff); + rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg); + + rt2x00pci_register_read(rt2x00dev, MCU_INT_MASK_CSR, ®); + rt2x00_set_field32(®, MCU_INT_MASK_CSR_0, mask); + rt2x00_set_field32(®, MCU_INT_MASK_CSR_1, mask); + rt2x00_set_field32(®, MCU_INT_MASK_CSR_2, mask); + rt2x00_set_field32(®, MCU_INT_MASK_CSR_3, mask); + rt2x00_set_field32(®, MCU_INT_MASK_CSR_4, mask); + rt2x00_set_field32(®, MCU_INT_MASK_CSR_5, mask); + rt2x00_set_field32(®, MCU_INT_MASK_CSR_6, mask); + rt2x00_set_field32(®, MCU_INT_MASK_CSR_7, mask); + rt2x00pci_register_write(rt2x00dev, MCU_INT_MASK_CSR, reg); +} + +static int rt61pci_enable_radio(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + /* + * Initialize all registers. + */ + if (rt61pci_init_rings(rt2x00dev) || + rt61pci_init_registers(rt2x00dev) || + rt61pci_init_bbp(rt2x00dev)) { + ERROR(rt2x00dev, "Register initialization failed.\n"); + return -EIO; + } + + /* + * Enable interrupts. + */ + rt61pci_toggle_irq(rt2x00dev, STATE_RADIO_IRQ_ON); + + /* + * Enable RX. + */ + rt2x00pci_register_read(rt2x00dev, RX_CNTL_CSR, ®); + rt2x00_set_field32(®, RX_CNTL_CSR_ENABLE_RX_DMA, 1); + rt2x00pci_register_write(rt2x00dev, RX_CNTL_CSR, reg); + + /* + * Enable LED + */ + rt61pci_enable_led(rt2x00dev); + + return 0; +} + +static void rt61pci_disable_radio(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + /* + * Disable LED + */ + rt61pci_disable_led(rt2x00dev); + + rt2x00pci_register_write(rt2x00dev, MAC_CSR10, 0x00001818); + + /* + * Disable synchronisation. + */ + rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, 0); + + /* + * Cancel RX and TX. + */ + rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, ®); + rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC0, 1); + rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC1, 1); + rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC2, 1); + rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC3, 1); + rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_MGMT, 1); + rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg); + + /* + * Disable interrupts. + */ + rt61pci_toggle_irq(rt2x00dev, STATE_RADIO_IRQ_OFF); +} + +static int rt61pci_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state) +{ + u32 reg; + unsigned int i; + char put_to_sleep; + char current_state; + + put_to_sleep = (state != STATE_AWAKE); + + rt2x00pci_register_read(rt2x00dev, MAC_CSR12, ®); + rt2x00_set_field32(®, MAC_CSR12_FORCE_WAKEUP, !put_to_sleep); + rt2x00_set_field32(®, MAC_CSR12_PUT_TO_SLEEP, put_to_sleep); + rt2x00pci_register_write(rt2x00dev, MAC_CSR12, reg); + + /* + * Device is not guaranteed to be in the requested state yet. + * We must wait until the register indicates that the + * device has entered the correct state. + */ + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2x00pci_register_read(rt2x00dev, MAC_CSR12, ®); + current_state = + rt2x00_get_field32(reg, MAC_CSR12_BBP_CURRENT_STATE); + if (current_state == !put_to_sleep) + return 0; + msleep(10); + } + + NOTICE(rt2x00dev, "Device failed to enter state %d, " + "current device state %d.\n", !put_to_sleep, current_state); + + return -EBUSY; +} + +static int rt61pci_set_device_state(struct rt2x00_dev *rt2x00dev, + enum dev_state state) +{ + int retval = 0; + + switch (state) { + case STATE_RADIO_ON: + retval = rt61pci_enable_radio(rt2x00dev); + break; + case STATE_RADIO_OFF: + rt61pci_disable_radio(rt2x00dev); + break; + case STATE_RADIO_RX_ON: + case STATE_RADIO_RX_OFF: + rt61pci_toggle_rx(rt2x00dev, state); + break; + case STATE_DEEP_SLEEP: + case STATE_SLEEP: + case STATE_STANDBY: + case STATE_AWAKE: + retval = rt61pci_set_state(rt2x00dev, state); + break; + default: + retval = -ENOTSUPP; + break; + } + + return retval; +} + +/* + * TX descriptor initialization + */ +static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, + struct data_desc *txd, + struct data_entry_desc *desc, + struct ieee80211_hdr *ieee80211hdr, + unsigned int length, + struct ieee80211_tx_control *control) +{ + u32 word; + + /* + * Start writing the descriptor words. + */ + rt2x00_desc_read(txd, 1, &word); + rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, desc->queue); + rt2x00_set_field32(&word, TXD_W1_AIFSN, desc->aifs); + rt2x00_set_field32(&word, TXD_W1_CWMIN, desc->cw_min); + rt2x00_set_field32(&word, TXD_W1_CWMAX, desc->cw_max); + rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER); + rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE, 1); + rt2x00_desc_write(txd, 1, word); + + rt2x00_desc_read(txd, 2, &word); + rt2x00_set_field32(&word, TXD_W2_PLCP_SIGNAL, desc->signal); + rt2x00_set_field32(&word, TXD_W2_PLCP_SERVICE, desc->service); + rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_LOW, desc->length_low); + rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, desc->length_high); + rt2x00_desc_write(txd, 2, word); + + rt2x00_desc_read(txd, 5, &word); + rt2x00_set_field32(&word, TXD_W5_TX_POWER, + TXPOWER_TO_DEV(control->power_level)); + rt2x00_set_field32(&word, TXD_W5_WAITING_DMA_DONE_INT, 1); + rt2x00_desc_write(txd, 5, word); + + rt2x00_desc_read(txd, 11, &word); + rt2x00_set_field32(&word, TXD_W11_BUFFER_LENGTH0, length); + rt2x00_desc_write(txd, 11, word); + + rt2x00_desc_read(txd, 0, &word); + rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 1); + rt2x00_set_field32(&word, TXD_W0_VALID, 1); + rt2x00_set_field32(&word, TXD_W0_MORE_FRAG, + test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags)); + rt2x00_set_field32(&word, TXD_W0_ACK, + !(control->flags & IEEE80211_TXCTL_NO_ACK)); + rt2x00_set_field32(&word, TXD_W0_TIMESTAMP, + test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags)); + rt2x00_set_field32(&word, TXD_W0_OFDM, + test_bit(ENTRY_TXD_OFDM_RATE, &desc->flags)); + rt2x00_set_field32(&word, TXD_W0_IFS, desc->ifs); + rt2x00_set_field32(&word, TXD_W0_RETRY_MODE, + !!(control->flags & + IEEE80211_TXCTL_LONG_RETRY_LIMIT)); + rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, 0); + rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, length); + rt2x00_set_field32(&word, TXD_W0_BURST, + test_bit(ENTRY_TXD_BURST, &desc->flags)); + rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE); + rt2x00_desc_write(txd, 0, word); +} + +/* + * TX data initialization + */ +static void rt61pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, + unsigned int queue) +{ + u32 reg; + + if (queue == IEEE80211_TX_QUEUE_BEACON) { + /* + * For Wi-Fi faily generated beacons between participating + * stations. Set TBTT phase adaptive adjustment step to 8us. + */ + rt2x00pci_register_write(rt2x00dev, TXRX_CSR10, 0x00001008); + + rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®); + if (!rt2x00_get_field32(reg, TXRX_CSR9_BEACON_GEN)) { + rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 1); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); + } + return; + } + + rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, ®); + if (queue == IEEE80211_TX_QUEUE_DATA0) + rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC0, 1); + else if (queue == IEEE80211_TX_QUEUE_DATA1) + rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC1, 1); + else if (queue == IEEE80211_TX_QUEUE_DATA2) + rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC2, 1); + else if (queue == IEEE80211_TX_QUEUE_DATA3) + rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC3, 1); + else if (queue == IEEE80211_TX_QUEUE_DATA4) + rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_MGMT, 1); + rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg); +} + +/* + * RX control handlers + */ +static int rt61pci_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1) +{ + u16 eeprom; + u8 offset; + u8 lna; + + lna = rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_LNA); + switch (lna) { + case 3: + offset = 90; + break; + case 2: + offset = 74; + break; + case 1: + offset = 64; + break; + default: + return 0; + } + + if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A) { + if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) + offset += 14; + + if (lna == 3 || lna == 2) + offset += 10; + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom); + offset -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1); + } else { + if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) + offset += 14; + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom); + offset -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1); + } + + return rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_AGC) * 2 - offset; +} + +static int rt61pci_fill_rxdone(struct data_entry *entry, + int *signal, int *rssi, int *ofdm, int *size) +{ + struct data_desc *rxd = entry->priv; + u32 word0; + u32 word1; + + rt2x00_desc_read(rxd, 0, &word0); + rt2x00_desc_read(rxd, 1, &word1); + + if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR) || + rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR)) + return -EINVAL; + + /* + * Obtain the status about this packet. + */ + *signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL); + *rssi = rt61pci_agc_to_rssi(entry->ring->rt2x00dev, word1); + *ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); + *size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); + + return 0; +} + +/* + * Interrupt functions. + */ +static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev) +{ + struct data_ring *ring; + struct data_entry *entry; + struct data_desc *txd; + u32 word; + u32 reg; + u32 old_reg; + int type; + int index; + int tx_status; + int retry; + + /* + * During each loop we will compare the freshly read + * STA_CSR4 register value with the value read from + * the previous loop. If the 2 values are equal then + * we should stop processing because the chance it + * quite big that the device has been unplugged and + * we risk going into an endless loop. + */ + old_reg = 0; + + while (1) { + rt2x00pci_register_read(rt2x00dev, STA_CSR4, ®); + if (!rt2x00_get_field32(reg, STA_CSR4_VALID)) + break; + + if (old_reg == reg) + break; + old_reg = reg; + + /* + * Skip this entry when it contains an invalid + * ring identication number. + */ + type = rt2x00_get_field32(reg, STA_CSR4_PID_TYPE); + ring = rt2x00lib_get_ring(rt2x00dev, type); + if (unlikely(!ring)) + continue; + + /* + * Skip this entry when it contains an invalid + * index number. + */ + index = rt2x00_get_field32(reg, STA_CSR4_PID_SUBTYPE); + if (unlikely(index >= ring->stats.limit)) + continue; + + entry = &ring->entry[index]; + txd = entry->priv; + rt2x00_desc_read(txd, 0, &word); + + if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || + !rt2x00_get_field32(word, TXD_W0_VALID)) + return; + + /* + * Obtain the status about this packet. + */ + tx_status = rt2x00_get_field32(reg, STA_CSR4_TX_RESULT); + retry = rt2x00_get_field32(reg, STA_CSR4_RETRY_COUNT); + + rt2x00lib_txdone(entry, tx_status, retry); + + /* + * Make this entry available for reuse. + */ + entry->flags = 0; + rt2x00_set_field32(&word, TXD_W0_VALID, 0); + rt2x00_desc_write(txd, 0, word); + rt2x00_ring_index_done_inc(entry->ring); + + /* + * If the data ring was full before the txdone handler + * we must make sure the packet queue in the mac80211 stack + * is reenabled when the txdone handler has finished. + */ + if (!rt2x00_ring_full(ring)) + ieee80211_wake_queue(rt2x00dev->hw, + entry->tx_status.control.queue); + } +} + +static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance) +{ + struct rt2x00_dev *rt2x00dev = dev_instance; + u32 reg_mcu; + u32 reg; + + /* + * Get the interrupt sources & saved to local variable. + * Write register value back to clear pending interrupts. + */ + rt2x00pci_register_read(rt2x00dev, MCU_INT_SOURCE_CSR, ®_mcu); + rt2x00pci_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg_mcu); + + rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, ®); + rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg); + + if (!reg && !reg_mcu) + return IRQ_NONE; + + if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + return IRQ_HANDLED; + + /* + * Handle interrupts, walk through all bits + * and run the tasks, the bits are checked in order of + * priority. + */ + + /* + * 1 - Rx ring done interrupt. + */ + if (rt2x00_get_field32(reg, INT_SOURCE_CSR_RXDONE)) + rt2x00pci_rxdone(rt2x00dev); + + /* + * 2 - Tx ring done interrupt. + */ + if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TXDONE)) + rt61pci_txdone(rt2x00dev); + + /* + * 3 - Handle MCU command done. + */ + if (reg_mcu) + rt2x00pci_register_write(rt2x00dev, + M2H_CMD_DONE_CSR, 0xffffffff); + + return IRQ_HANDLED; +} + +/* + * Device probe functions. + */ +static int rt61pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) +{ + struct eeprom_93cx6 eeprom; + u32 reg; + u16 word; + u8 *mac; + s8 value; + + rt2x00pci_register_read(rt2x00dev, E2PROM_CSR, ®); + + eeprom.data = rt2x00dev; + eeprom.register_read = rt61pci_eepromregister_read; + eeprom.register_write = rt61pci_eepromregister_write; + eeprom.width = rt2x00_get_field32(reg, E2PROM_CSR_TYPE_93C46) ? + PCI_EEPROM_WIDTH_93C46 : PCI_EEPROM_WIDTH_93C66; + eeprom.reg_data_in = 0; + eeprom.reg_data_out = 0; + eeprom.reg_data_clock = 0; + eeprom.reg_chip_select = 0; + + eeprom_93cx6_multiread(&eeprom, EEPROM_BASE, rt2x00dev->eeprom, + EEPROM_SIZE / sizeof(u16)); + + /* + * Start validation of the data that has been read. + */ + mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); + if (!is_valid_ether_addr(mac)) { + random_ether_addr(mac); + EEPROM(rt2x00dev, "MAC: " MAC_FMT "\n", MAC_ARG(mac)); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2); + rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, 2); + rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT, 2); + rt2x00_set_field16(&word, EEPROM_ANTENNA_FRAME_TYPE, 0); + rt2x00_set_field16(&word, EEPROM_ANTENNA_DYN_TXAGC, 0); + rt2x00_set_field16(&word, EEPROM_ANTENNA_HARDWARE_RADIO, 0); + rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF5225); + rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word); + EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_NIC_ENABLE_DIVERSITY, 0); + rt2x00_set_field16(&word, EEPROM_NIC_TX_DIVERSITY, 0); + rt2x00_set_field16(&word, EEPROM_NIC_TX_RX_FIXED, 0); + rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_BG, 0); + rt2x00_set_field16(&word, EEPROM_NIC_CARDBUS_ACCEL, 0); + rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_A, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word); + EEPROM(rt2x00dev, "NIC: 0x%04x\n", word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_LED, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_LED_LED_MODE, + LED_MODE_DEFAULT); + rt2x00_eeprom_write(rt2x00dev, EEPROM_LED, word); + EEPROM(rt2x00dev, "Led: 0x%04x\n", word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_FREQ_OFFSET, 0); + rt2x00_set_field16(&word, EEPROM_FREQ_SEQ, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_FREQ, word); + EEPROM(rt2x00dev, "Freq: 0x%04x\n", word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_1, 0); + rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_2, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_BG, word); + EEPROM(rt2x00dev, "RSSI OFFSET BG: 0x%04x\n", word); + } else { + value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_BG_1); + if (value < -10 || value > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_1, 0); + value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_BG_2); + if (value < -10 || value > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_2, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_BG, word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_1, 0); + rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_2, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_A, word); + EEPROM(rt2x00dev, "RSSI OFFSET BG: 0x%04x\n", word); + } else { + value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_A_1); + if (value < -10 || value > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_1, 0); + value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_A_2); + if (value < -10 || value > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_2, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_A, word); + } + + return 0; +} + +static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + u16 value; + u16 eeprom; + u16 device; + + /* + * Read EEPROM word for configuration. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); + + /* + * Identify RF chipset. + * To determine the RT chip we have to read the + * PCI header of the device. + */ + pci_read_config_word(rt2x00dev_pci(rt2x00dev), + PCI_CONFIG_HEADER_DEVICE, &device); + value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); + rt2x00pci_register_read(rt2x00dev, MAC_CSR0, ®); + rt2x00_set_chip(rt2x00dev, device, value, reg); + + if (!rt2x00_rf(&rt2x00dev->chip, RF5225) && + !rt2x00_rf(&rt2x00dev->chip, RF5325) && + !rt2x00_rf(&rt2x00dev->chip, RF2527) && + !rt2x00_rf(&rt2x00dev->chip, RF2529)) { + ERROR(rt2x00dev, "Invalid RF chipset detected.\n"); + return -ENODEV; + } + + /* + * Identify default antenna configuration. + */ + rt2x00dev->hw->conf.antenna_sel_tx = + rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TX_DEFAULT); + rt2x00dev->hw->conf.antenna_sel_rx = + rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT); + + /* + * Read the Frame type. + */ + if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_FRAME_TYPE)) + __set_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags); + + /* + * Determine number of antenna's. + */ + if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_NUM) == 2) + __set_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags); + + /* + * Detect if this device has an hardware controlled radio. + */ + if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) + __set_bit(DEVICE_SUPPORT_HW_BUTTON, &rt2x00dev->flags); + + /* + * Read frequency offset and RF programming sequence. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom); + if (rt2x00_get_field16(eeprom, EEPROM_FREQ_SEQ)) + __set_bit(CONFIG_RF_SEQUENCE, &rt2x00dev->flags); + + rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET); + + /* + * Read external LNA informations. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom); + + if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_A)) + __set_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags); + if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_BG)) + __set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags); + + /* + * Store led settings, for correct led behaviour. + * If the eeprom value is invalid, + * switch to default led mode. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_LED, &eeprom); + + rt2x00dev->led_mode = rt2x00_get_field16(eeprom, EEPROM_LED_LED_MODE); + + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LED_MODE, + rt2x00dev->led_mode); + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_0, + rt2x00_get_field16(eeprom, + EEPROM_LED_POLARITY_GPIO_0)); + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_1, + rt2x00_get_field16(eeprom, + EEPROM_LED_POLARITY_GPIO_1)); + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_2, + rt2x00_get_field16(eeprom, + EEPROM_LED_POLARITY_GPIO_2)); + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_3, + rt2x00_get_field16(eeprom, + EEPROM_LED_POLARITY_GPIO_3)); + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_4, + rt2x00_get_field16(eeprom, + EEPROM_LED_POLARITY_GPIO_4)); + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_ACT, + rt2x00_get_field16(eeprom, EEPROM_LED_POLARITY_ACT)); + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_READY_BG, + rt2x00_get_field16(eeprom, + EEPROM_LED_POLARITY_RDY_G)); + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_READY_A, + rt2x00_get_field16(eeprom, + EEPROM_LED_POLARITY_RDY_A)); + + return 0; +} + +/* + * RF value list for RF5225 & RF5325 + * Supports: 2.4 GHz & 5.2 GHz, rf_sequence disabled + */ +static const struct rf_channel rf_vals_noseq[] = { + { 1, 0x00002ccc, 0x00004786, 0x00068455, 0x000ffa0b }, + { 2, 0x00002ccc, 0x00004786, 0x00068455, 0x000ffa1f }, + { 3, 0x00002ccc, 0x0000478a, 0x00068455, 0x000ffa0b }, + { 4, 0x00002ccc, 0x0000478a, 0x00068455, 0x000ffa1f }, + { 5, 0x00002ccc, 0x0000478e, 0x00068455, 0x000ffa0b }, + { 6, 0x00002ccc, 0x0000478e, 0x00068455, 0x000ffa1f }, + { 7, 0x00002ccc, 0x00004792, 0x00068455, 0x000ffa0b }, + { 8, 0x00002ccc, 0x00004792, 0x00068455, 0x000ffa1f }, + { 9, 0x00002ccc, 0x00004796, 0x00068455, 0x000ffa0b }, + { 10, 0x00002ccc, 0x00004796, 0x00068455, 0x000ffa1f }, + { 11, 0x00002ccc, 0x0000479a, 0x00068455, 0x000ffa0b }, + { 12, 0x00002ccc, 0x0000479a, 0x00068455, 0x000ffa1f }, + { 13, 0x00002ccc, 0x0000479e, 0x00068455, 0x000ffa0b }, + { 14, 0x00002ccc, 0x000047a2, 0x00068455, 0x000ffa13 }, + + /* 802.11 UNI / HyperLan 2 */ + { 36, 0x00002ccc, 0x0000499a, 0x0009be55, 0x000ffa23 }, + { 40, 0x00002ccc, 0x000049a2, 0x0009be55, 0x000ffa03 }, + { 44, 0x00002ccc, 0x000049a6, 0x0009be55, 0x000ffa0b }, + { 48, 0x00002ccc, 0x000049aa, 0x0009be55, 0x000ffa13 }, + { 52, 0x00002ccc, 0x000049ae, 0x0009ae55, 0x000ffa1b }, + { 56, 0x00002ccc, 0x000049b2, 0x0009ae55, 0x000ffa23 }, + { 60, 0x00002ccc, 0x000049ba, 0x0009ae55, 0x000ffa03 }, + { 64, 0x00002ccc, 0x000049be, 0x0009ae55, 0x000ffa0b }, + + /* 802.11 HyperLan 2 */ + { 100, 0x00002ccc, 0x00004a2a, 0x000bae55, 0x000ffa03 }, + { 104, 0x00002ccc, 0x00004a2e, 0x000bae55, 0x000ffa0b }, + { 108, 0x00002ccc, 0x00004a32, 0x000bae55, 0x000ffa13 }, + { 112, 0x00002ccc, 0x00004a36, 0x000bae55, 0x000ffa1b }, + { 116, 0x00002ccc, 0x00004a3a, 0x000bbe55, 0x000ffa23 }, + { 120, 0x00002ccc, 0x00004a82, 0x000bbe55, 0x000ffa03 }, + { 124, 0x00002ccc, 0x00004a86, 0x000bbe55, 0x000ffa0b }, + { 128, 0x00002ccc, 0x00004a8a, 0x000bbe55, 0x000ffa13 }, + { 132, 0x00002ccc, 0x00004a8e, 0x000bbe55, 0x000ffa1b }, + { 136, 0x00002ccc, 0x00004a92, 0x000bbe55, 0x000ffa23 }, + + /* 802.11 UNII */ + { 140, 0x00002ccc, 0x00004a9a, 0x000bbe55, 0x000ffa03 }, + { 149, 0x00002ccc, 0x00004aa2, 0x000bbe55, 0x000ffa1f }, + { 153, 0x00002ccc, 0x00004aa6, 0x000bbe55, 0x000ffa27 }, + { 157, 0x00002ccc, 0x00004aae, 0x000bbe55, 0x000ffa07 }, + { 161, 0x00002ccc, 0x00004ab2, 0x000bbe55, 0x000ffa0f }, + { 165, 0x00002ccc, 0x00004ab6, 0x000bbe55, 0x000ffa17 }, + + /* MMAC(Japan)J52 ch 34,38,42,46 */ + { 34, 0x00002ccc, 0x0000499a, 0x0009be55, 0x000ffa0b }, + { 38, 0x00002ccc, 0x0000499e, 0x0009be55, 0x000ffa13 }, + { 42, 0x00002ccc, 0x000049a2, 0x0009be55, 0x000ffa1b }, + { 46, 0x00002ccc, 0x000049a6, 0x0009be55, 0x000ffa23 }, +}; + +/* + * RF value list for RF5225 & RF5325 + * Supports: 2.4 GHz & 5.2 GHz, rf_sequence enabled + */ +static const struct rf_channel rf_vals_seq[] = { + { 1, 0x00002ccc, 0x00004786, 0x00068455, 0x000ffa0b }, + { 2, 0x00002ccc, 0x00004786, 0x00068455, 0x000ffa1f }, + { 3, 0x00002ccc, 0x0000478a, 0x00068455, 0x000ffa0b }, + { 4, 0x00002ccc, 0x0000478a, 0x00068455, 0x000ffa1f }, + { 5, 0x00002ccc, 0x0000478e, 0x00068455, 0x000ffa0b }, + { 6, 0x00002ccc, 0x0000478e, 0x00068455, 0x000ffa1f }, + { 7, 0x00002ccc, 0x00004792, 0x00068455, 0x000ffa0b }, + { 8, 0x00002ccc, 0x00004792, 0x00068455, 0x000ffa1f }, + { 9, 0x00002ccc, 0x00004796, 0x00068455, 0x000ffa0b }, + { 10, 0x00002ccc, 0x00004796, 0x00068455, 0x000ffa1f }, + { 11, 0x00002ccc, 0x0000479a, 0x00068455, 0x000ffa0b }, + { 12, 0x00002ccc, 0x0000479a, 0x00068455, 0x000ffa1f }, + { 13, 0x00002ccc, 0x0000479e, 0x00068455, 0x000ffa0b }, + { 14, 0x00002ccc, 0x000047a2, 0x00068455, 0x000ffa13 }, + + /* 802.11 UNI / HyperLan 2 */ + { 36, 0x00002cd4, 0x0004481a, 0x00098455, 0x000c0a03 }, + { 40, 0x00002cd0, 0x00044682, 0x00098455, 0x000c0a03 }, + { 44, 0x00002cd0, 0x00044686, 0x00098455, 0x000c0a1b }, + { 48, 0x00002cd0, 0x0004468e, 0x00098655, 0x000c0a0b }, + { 52, 0x00002cd0, 0x00044692, 0x00098855, 0x000c0a23 }, + { 56, 0x00002cd0, 0x0004469a, 0x00098c55, 0x000c0a13 }, + { 60, 0x00002cd0, 0x000446a2, 0x00098e55, 0x000c0a03 }, + { 64, 0x00002cd0, 0x000446a6, 0x00099255, 0x000c0a1b }, + + /* 802.11 HyperLan 2 */ + { 100, 0x00002cd4, 0x0004489a, 0x000b9855, 0x000c0a03 }, + { 104, 0x00002cd4, 0x000448a2, 0x000b9855, 0x000c0a03 }, + { 108, 0x00002cd4, 0x000448aa, 0x000b9855, 0x000c0a03 }, + { 112, 0x00002cd4, 0x000448b2, 0x000b9a55, 0x000c0a03 }, + { 116, 0x00002cd4, 0x000448ba, 0x000b9a55, 0x000c0a03 }, + { 120, 0x00002cd0, 0x00044702, 0x000b9a55, 0x000c0a03 }, + { 124, 0x00002cd0, 0x00044706, 0x000b9a55, 0x000c0a1b }, + { 128, 0x00002cd0, 0x0004470e, 0x000b9c55, 0x000c0a0b }, + { 132, 0x00002cd0, 0x00044712, 0x000b9c55, 0x000c0a23 }, + { 136, 0x00002cd0, 0x0004471a, 0x000b9e55, 0x000c0a13 }, + + /* 802.11 UNII */ + { 140, 0x00002cd0, 0x00044722, 0x000b9e55, 0x000c0a03 }, + { 149, 0x00002cd0, 0x0004472e, 0x000ba255, 0x000c0a1b }, + { 153, 0x00002cd0, 0x00044736, 0x000ba255, 0x000c0a0b }, + { 157, 0x00002cd4, 0x0004490a, 0x000ba255, 0x000c0a17 }, + { 161, 0x00002cd4, 0x00044912, 0x000ba255, 0x000c0a17 }, + { 165, 0x00002cd4, 0x0004491a, 0x000ba255, 0x000c0a17 }, + + /* MMAC(Japan)J52 ch 34,38,42,46 */ + { 34, 0x00002ccc, 0x0000499a, 0x0009be55, 0x000c0a0b }, + { 38, 0x00002ccc, 0x0000499e, 0x0009be55, 0x000c0a13 }, + { 42, 0x00002ccc, 0x000049a2, 0x0009be55, 0x000c0a1b }, + { 46, 0x00002ccc, 0x000049a6, 0x0009be55, 0x000c0a23 }, +}; + +static void rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) +{ + struct hw_mode_spec *spec = &rt2x00dev->spec; + u8 *txpower; + unsigned int i; + + /* + * Initialize all hw fields. + */ + rt2x00dev->hw->flags = + IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_MONITOR_DURING_OPER | + IEEE80211_HW_NO_PROBE_FILTERING; + rt2x00dev->hw->extra_tx_headroom = 0; + rt2x00dev->hw->max_signal = MAX_SIGNAL; + rt2x00dev->hw->max_rssi = MAX_RX_SSI; + rt2x00dev->hw->queues = 5; + + SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev); + SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, + rt2x00_eeprom_addr(rt2x00dev, + EEPROM_MAC_ADDR_0)); + + /* + * Convert tx_power array in eeprom. + */ + txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_G_START); + for (i = 0; i < 14; i++) + txpower[i] = TXPOWER_FROM_DEV(txpower[i]); + + /* + * Initialize hw_mode information. + */ + spec->num_modes = 2; + spec->num_rates = 12; + spec->tx_power_a = NULL; + spec->tx_power_bg = txpower; + spec->tx_power_default = DEFAULT_TXPOWER; + + if (!test_bit(CONFIG_RF_SEQUENCE, &rt2x00dev->flags)) { + spec->num_channels = 14; + spec->channels = rf_vals_noseq; + } else { + spec->num_channels = 14; + spec->channels = rf_vals_seq; + } + + if (rt2x00_rf(&rt2x00dev->chip, RF5225) || + rt2x00_rf(&rt2x00dev->chip, RF5325)) { + spec->num_modes = 3; + spec->num_channels = ARRAY_SIZE(rf_vals_seq); + + txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A_START); + for (i = 0; i < 14; i++) + txpower[i] = TXPOWER_FROM_DEV(txpower[i]); + + spec->tx_power_a = txpower; + } +} + +static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev) +{ + int retval; + + /* + * Allocate eeprom data. + */ + retval = rt61pci_validate_eeprom(rt2x00dev); + if (retval) + return retval; + + retval = rt61pci_init_eeprom(rt2x00dev); + if (retval) + return retval; + + /* + * Initialize hw specifications. + */ + rt61pci_probe_hw_mode(rt2x00dev); + + /* + * This device requires firmware + */ + __set_bit(REQUIRE_FIRMWARE, &rt2x00dev->flags); + + /* + * Set the rssi offset. + */ + rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET; + + return 0; +} + +/* + * IEEE80211 stack callback functions. + */ +static int rt61pci_set_retry_limit(struct ieee80211_hw *hw, + u32 short_retry, u32 long_retry) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + u32 reg; + + rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, ®); + rt2x00_set_field32(®, TXRX_CSR4_LONG_RETRY_LIMIT, long_retry); + rt2x00_set_field32(®, TXRX_CSR4_SHORT_RETRY_LIMIT, short_retry); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg); + + return 0; +} + +static u64 rt61pci_get_tsf(struct ieee80211_hw *hw) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + u64 tsf; + u32 reg; + + rt2x00pci_register_read(rt2x00dev, TXRX_CSR13, ®); + tsf = (u64) rt2x00_get_field32(reg, TXRX_CSR13_HIGH_TSFTIMER) << 32; + rt2x00pci_register_read(rt2x00dev, TXRX_CSR12, ®); + tsf |= rt2x00_get_field32(reg, TXRX_CSR12_LOW_TSFTIMER); + + return tsf; +} + +static void rt61pci_reset_tsf(struct ieee80211_hw *hw) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + + rt2x00pci_register_write(rt2x00dev, TXRX_CSR12, 0); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR13, 0); +} + +int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ieee80211_tx_control *control) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + + /* + * Just in case the ieee80211 doesn't set this, + * but we need this queue set for the descriptor + * initialization. + */ + control->queue = IEEE80211_TX_QUEUE_BEACON; + + /* + * We need to append the descriptor in front of the + * beacon frame. + */ + if (skb_headroom(skb) < TXD_DESC_SIZE) { + if (pskb_expand_head(skb, TXD_DESC_SIZE, 0, GFP_ATOMIC)) { + dev_kfree_skb(skb); + return -ENOMEM; + } + } + + /* + * First we create the beacon. + */ + skb_push(skb, TXD_DESC_SIZE); + rt2x00lib_write_tx_desc(rt2x00dev, (struct data_desc *)skb->data, + (struct ieee80211_hdr *)(skb->data + + TXD_DESC_SIZE), + skb->len - TXD_DESC_SIZE, control); + + /* + * Write entire beacon with descriptor to register, + * and kick the beacon generator. + */ + rt2x00pci_register_multiwrite(rt2x00dev, HW_BEACON_BASE0, skb->data, skb->len); + rt61pci_kick_tx_queue(rt2x00dev, IEEE80211_TX_QUEUE_BEACON); + + return 0; +} + +static const struct ieee80211_ops rt61pci_mac80211_ops = { + .tx = rt2x00mac_tx, + .add_interface = rt2x00mac_add_interface, + .remove_interface = rt2x00mac_remove_interface, + .config = rt2x00mac_config, + .config_interface = rt2x00mac_config_interface, + .set_multicast_list = rt2x00mac_set_multicast_list, + .get_stats = rt2x00mac_get_stats, + .set_retry_limit = rt61pci_set_retry_limit, + .conf_tx = rt2x00mac_conf_tx, + .get_tx_stats = rt2x00mac_get_tx_stats, + .get_tsf = rt61pci_get_tsf, + .reset_tsf = rt61pci_reset_tsf, + .beacon_update = rt61pci_beacon_update, +}; + +static const struct rt2x00lib_ops rt61pci_rt2x00_ops = { + .irq_handler = rt61pci_interrupt, + .probe_hw = rt61pci_probe_hw, + .get_firmware_name = rt61pci_get_firmware_name, + .load_firmware = rt61pci_load_firmware, + .initialize = rt2x00pci_initialize, + .uninitialize = rt2x00pci_uninitialize, + .set_device_state = rt61pci_set_device_state, +#ifdef CONFIG_RT61PCI_RFKILL + .rfkill_poll = rt61pci_rfkill_poll, +#endif /* CONFIG_RT61PCI_RFKILL */ + .link_stats = rt61pci_link_stats, + .reset_tuner = rt61pci_reset_tuner, + .link_tuner = rt61pci_link_tuner, + .write_tx_desc = rt61pci_write_tx_desc, + .write_tx_data = rt2x00pci_write_tx_data, + .kick_tx_queue = rt61pci_kick_tx_queue, + .fill_rxdone = rt61pci_fill_rxdone, + .config_mac_addr = rt61pci_config_mac_addr, + .config_bssid = rt61pci_config_bssid, + .config_packet_filter = rt61pci_config_packet_filter, + .config_type = rt61pci_config_type, + .config = rt61pci_config, +}; + +static const struct rt2x00_ops rt61pci_ops = { + .name = DRV_NAME, + .rxd_size = RXD_DESC_SIZE, + .txd_size = TXD_DESC_SIZE, + .eeprom_size = EEPROM_SIZE, + .rf_size = RF_SIZE, + .lib = &rt61pci_rt2x00_ops, + .hw = &rt61pci_mac80211_ops, +#ifdef CONFIG_RT2X00_LIB_DEBUGFS + .debugfs = &rt61pci_rt2x00debug, +#endif /* CONFIG_RT2X00_LIB_DEBUGFS */ +}; + +/* + * RT61pci module information. + */ +static struct pci_device_id rt61pci_device_table[] = { + /* RT2561s */ + { PCI_DEVICE(0x1814, 0x0301), PCI_DEVICE_DATA(&rt61pci_ops) }, + /* RT2561 v2 */ + { PCI_DEVICE(0x1814, 0x0302), PCI_DEVICE_DATA(&rt61pci_ops) }, + /* RT2661 */ + { PCI_DEVICE(0x1814, 0x0401), PCI_DEVICE_DATA(&rt61pci_ops) }, + { 0, } +}; + +MODULE_AUTHOR(DRV_PROJECT); +MODULE_VERSION(DRV_VERSION); +MODULE_DESCRIPTION("Ralink RT61 PCI & PCMCIA Wireless LAN driver."); +MODULE_SUPPORTED_DEVICE("Ralink RT2561, RT2561s & RT2661 " + "PCI & PCMCIA chipset based cards"); +MODULE_DEVICE_TABLE(pci, rt61pci_device_table); +MODULE_FIRMWARE(FIRMWARE_RT2561); +MODULE_FIRMWARE(FIRMWARE_RT2561s); +MODULE_FIRMWARE(FIRMWARE_RT2661); +MODULE_LICENSE("GPL"); + +static struct pci_driver rt61pci_driver = { + .name = DRV_NAME, + .id_table = rt61pci_device_table, + .probe = rt2x00pci_probe, + .remove = __devexit_p(rt2x00pci_remove), + .suspend = rt2x00pci_suspend, + .resume = rt2x00pci_resume, +}; + +static int __init rt61pci_init(void) +{ + return pci_register_driver(&rt61pci_driver); +} + +static void __exit rt61pci_exit(void) +{ + pci_unregister_driver(&rt61pci_driver); +} + +module_init(rt61pci_init); +module_exit(rt61pci_exit); diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h new file mode 100644 index 00000000000..6721d7dd32b --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt61pci.h @@ -0,0 +1,1457 @@ +/* + Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the + Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + Module: rt61pci + Abstract: Data structures and registers for the rt61pci module. + Supported chipsets: RT2561, RT2561s, RT2661. + */ + +#ifndef RT61PCI_H +#define RT61PCI_H + +/* + * RF chip defines. + */ +#define RF5225 0x0001 +#define RF5325 0x0002 +#define RF2527 0x0003 +#define RF2529 0x0004 + +/* + * Signal information. + * Defaul offset is required for RSSI <-> dBm conversion. + */ +#define MAX_SIGNAL 100 +#define MAX_RX_SSI -1 +#define DEFAULT_RSSI_OFFSET 120 + +/* + * Register layout information. + */ +#define CSR_REG_BASE 0x3000 +#define CSR_REG_SIZE 0x04b0 +#define EEPROM_BASE 0x0000 +#define EEPROM_SIZE 0x0100 +#define BBP_SIZE 0x0080 +#define RF_SIZE 0x0014 + +/* + * PCI registers. + */ + +/* + * PCI Configuration Header + */ +#define PCI_CONFIG_HEADER_VENDOR 0x0000 +#define PCI_CONFIG_HEADER_DEVICE 0x0002 + +/* + * HOST_CMD_CSR: For HOST to interrupt embedded processor + */ +#define HOST_CMD_CSR 0x0008 +#define HOST_CMD_CSR_HOST_COMMAND FIELD32(0x0000007f) +#define HOST_CMD_CSR_INTERRUPT_MCU FIELD32(0x00000080) + +/* + * MCU_CNTL_CSR + * SELECT_BANK: Select 8051 program bank. + * RESET: Enable 8051 reset state. + * READY: Ready state for 8051. + */ +#define MCU_CNTL_CSR 0x000c +#define MCU_CNTL_CSR_SELECT_BANK FIELD32(0x00000001) +#define MCU_CNTL_CSR_RESET FIELD32(0x00000002) +#define MCU_CNTL_CSR_READY FIELD32(0x00000004) + +/* + * SOFT_RESET_CSR + */ +#define SOFT_RESET_CSR 0x0010 + +/* + * MCU_INT_SOURCE_CSR: MCU interrupt source/mask register. + */ +#define MCU_INT_SOURCE_CSR 0x0014 +#define MCU_INT_SOURCE_CSR_0 FIELD32(0x00000001) +#define MCU_INT_SOURCE_CSR_1 FIELD32(0x00000002) +#define MCU_INT_SOURCE_CSR_2 FIELD32(0x00000004) +#define MCU_INT_SOURCE_CSR_3 FIELD32(0x00000008) +#define MCU_INT_SOURCE_CSR_4 FIELD32(0x00000010) +#define MCU_INT_SOURCE_CSR_5 FIELD32(0x00000020) +#define MCU_INT_SOURCE_CSR_6 FIELD32(0x00000040) +#define MCU_INT_SOURCE_CSR_7 FIELD32(0x00000080) +#define MCU_INT_SOURCE_CSR_TWAKEUP FIELD32(0x00000100) +#define MCU_INT_SOURCE_CSR_TBTT_EXPIRE FIELD32(0x00000200) + +/* + * MCU_INT_MASK_CSR: MCU interrupt source/mask register. + */ +#define MCU_INT_MASK_CSR 0x0018 +#define MCU_INT_MASK_CSR_0 FIELD32(0x00000001) +#define MCU_INT_MASK_CSR_1 FIELD32(0x00000002) +#define MCU_INT_MASK_CSR_2 FIELD32(0x00000004) +#define MCU_INT_MASK_CSR_3 FIELD32(0x00000008) +#define MCU_INT_MASK_CSR_4 FIELD32(0x00000010) +#define MCU_INT_MASK_CSR_5 FIELD32(0x00000020) +#define MCU_INT_MASK_CSR_6 FIELD32(0x00000040) +#define MCU_INT_MASK_CSR_7 FIELD32(0x00000080) +#define MCU_INT_MASK_CSR_TWAKEUP FIELD32(0x00000100) +#define MCU_INT_MASK_CSR_TBTT_EXPIRE FIELD32(0x00000200) + +/* + * PCI_USEC_CSR + */ +#define PCI_USEC_CSR 0x001c + +/* + * Security key table memory. + * 16 entries 32-byte for shared key table + * 64 entries 32-byte for pairwise key table + * 64 entries 8-byte for pairwise ta key table + */ +#define SHARED_KEY_TABLE_BASE 0x1000 +#define PAIRWISE_KEY_TABLE_BASE 0x1200 +#define PAIRWISE_TA_TABLE_BASE 0x1a00 + +struct hw_key_entry { + u8 key[16]; + u8 tx_mic[8]; + u8 rx_mic[8]; +} __attribute__ ((packed)); + +struct hw_pairwise_ta_entry { + u8 address[6]; + u8 reserved[2]; +} __attribute__ ((packed)); + +/* + * Other on-chip shared memory space. + */ +#define HW_CIS_BASE 0x2000 +#define HW_NULL_BASE 0x2b00 + +/* + * Since NULL frame won't be that long (256 byte), + * We steal 16 tail bytes to save debugging settings. + */ +#define HW_DEBUG_SETTING_BASE 0x2bf0 + +/* + * On-chip BEACON frame space. + */ +#define HW_BEACON_BASE0 0x2c00 +#define HW_BEACON_BASE1 0x2d00 +#define HW_BEACON_BASE2 0x2e00 +#define HW_BEACON_BASE3 0x2f00 +#define HW_BEACON_OFFSET 0x0100 + +/* + * HOST-MCU shared memory. + */ + +/* + * H2M_MAILBOX_CSR: Host-to-MCU Mailbox. + */ +#define H2M_MAILBOX_CSR 0x2100 +#define H2M_MAILBOX_CSR_ARG0 FIELD32(0x000000ff) +#define H2M_MAILBOX_CSR_ARG1 FIELD32(0x0000ff00) +#define H2M_MAILBOX_CSR_CMD_TOKEN FIELD32(0x00ff0000) +#define H2M_MAILBOX_CSR_OWNER FIELD32(0xff000000) + +/* + * MCU_LEDCS: LED control for MCU Mailbox. + */ +#define MCU_LEDCS_LED_MODE FIELD16(0x001f) +#define MCU_LEDCS_RADIO_STATUS FIELD16(0x0020) +#define MCU_LEDCS_LINK_BG_STATUS FIELD16(0x0040) +#define MCU_LEDCS_LINK_A_STATUS FIELD16(0x0080) +#define MCU_LEDCS_POLARITY_GPIO_0 FIELD16(0x0100) +#define MCU_LEDCS_POLARITY_GPIO_1 FIELD16(0x0200) +#define MCU_LEDCS_POLARITY_GPIO_2 FIELD16(0x0400) +#define MCU_LEDCS_POLARITY_GPIO_3 FIELD16(0x0800) +#define MCU_LEDCS_POLARITY_GPIO_4 FIELD16(0x1000) +#define MCU_LEDCS_POLARITY_ACT FIELD16(0x2000) +#define MCU_LEDCS_POLARITY_READY_BG FIELD16(0x4000) +#define MCU_LEDCS_POLARITY_READY_A FIELD16(0x8000) + +/* + * M2H_CMD_DONE_CSR. + */ +#define M2H_CMD_DONE_CSR 0x2104 + +/* + * MCU_TXOP_ARRAY_BASE. + */ +#define MCU_TXOP_ARRAY_BASE 0x2110 + +/* + * MAC Control/Status Registers(CSR). + * Some values are set in TU, whereas 1 TU == 1024 us. + */ + +/* + * MAC_CSR0: ASIC revision number. + */ +#define MAC_CSR0 0x3000 + +/* + * MAC_CSR1: System control register. + * SOFT_RESET: Software reset bit, 1: reset, 0: normal. + * BBP_RESET: Hardware reset BBP. + * HOST_READY: Host is ready after initialization, 1: ready. + */ +#define MAC_CSR1 0x3004 +#define MAC_CSR1_SOFT_RESET FIELD32(0x00000001) +#define MAC_CSR1_BBP_RESET FIELD32(0x00000002) +#define MAC_CSR1_HOST_READY FIELD32(0x00000004) + +/* + * MAC_CSR2: STA MAC register 0. + */ +#define MAC_CSR2 0x3008 +#define MAC_CSR2_BYTE0 FIELD32(0x000000ff) +#define MAC_CSR2_BYTE1 FIELD32(0x0000ff00) +#define MAC_CSR2_BYTE2 FIELD32(0x00ff0000) +#define MAC_CSR2_BYTE3 FIELD32(0xff000000) + +/* + * MAC_CSR3: STA MAC register 1. + */ +#define MAC_CSR3 0x300c +#define MAC_CSR3_BYTE4 FIELD32(0x000000ff) +#define MAC_CSR3_BYTE5 FIELD32(0x0000ff00) +#define MAC_CSR3_UNICAST_TO_ME_MASK FIELD32(0x00ff0000) + +/* + * MAC_CSR4: BSSID register 0. + */ +#define MAC_CSR4 0x3010 +#define MAC_CSR4_BYTE0 FIELD32(0x000000ff) +#define MAC_CSR4_BYTE1 FIELD32(0x0000ff00) +#define MAC_CSR4_BYTE2 FIELD32(0x00ff0000) +#define MAC_CSR4_BYTE3 FIELD32(0xff000000) + +/* + * MAC_CSR5: BSSID register 1. + * BSS_ID_MASK: 3: one BSSID, 0: 4 BSSID, 2 or 1: 2 BSSID. + */ +#define MAC_CSR5 0x3014 +#define MAC_CSR5_BYTE4 FIELD32(0x000000ff) +#define MAC_CSR5_BYTE5 FIELD32(0x0000ff00) +#define MAC_CSR5_BSS_ID_MASK FIELD32(0x00ff0000) + +/* + * MAC_CSR6: Maximum frame length register. + */ +#define MAC_CSR6 0x3018 +#define MAC_CSR6_MAX_FRAME_UNIT FIELD32(0x00000fff) + +/* + * MAC_CSR7: Reserved + */ +#define MAC_CSR7 0x301c + +/* + * MAC_CSR8: SIFS/EIFS register. + * All units are in US. + */ +#define MAC_CSR8 0x3020 +#define MAC_CSR8_SIFS FIELD32(0x000000ff) +#define MAC_CSR8_SIFS_AFTER_RX_OFDM FIELD32(0x0000ff00) +#define MAC_CSR8_EIFS FIELD32(0xffff0000) + +/* + * MAC_CSR9: Back-Off control register. + * SLOT_TIME: Slot time, default is 20us for 802.11BG. + * CWMIN: Bit for Cwmin. default Cwmin is 31 (2^5 - 1). + * CWMAX: Bit for Cwmax, default Cwmax is 1023 (2^10 - 1). + * CW_SELECT: 1: CWmin/Cwmax select from register, 0:select from TxD. + */ +#define MAC_CSR9 0x3024 +#define MAC_CSR9_SLOT_TIME FIELD32(0x000000ff) +#define MAC_CSR9_CWMIN FIELD32(0x00000f00) +#define MAC_CSR9_CWMAX FIELD32(0x0000f000) +#define MAC_CSR9_CW_SELECT FIELD32(0x00010000) + +/* + * MAC_CSR10: Power state configuration. + */ +#define MAC_CSR10 0x3028 + +/* + * MAC_CSR11: Power saving transition time register. + * DELAY_AFTER_TBCN: Delay after Tbcn expired in units of TU. + * TBCN_BEFORE_WAKEUP: Number of beacon before wakeup. + * WAKEUP_LATENCY: In unit of TU. + */ +#define MAC_CSR11 0x302c +#define MAC_CSR11_DELAY_AFTER_TBCN FIELD32(0x000000ff) +#define MAC_CSR11_TBCN_BEFORE_WAKEUP FIELD32(0x00007f00) +#define MAC_CSR11_AUTOWAKE FIELD32(0x00008000) +#define MAC_CSR11_WAKEUP_LATENCY FIELD32(0x000f0000) + +/* + * MAC_CSR12: Manual power control / status register (merge CSR20 & PWRCSR1). + * CURRENT_STATE: 0:sleep, 1:awake. + * FORCE_WAKEUP: This has higher priority than PUT_TO_SLEEP. + * BBP_CURRENT_STATE: 0: BBP sleep, 1: BBP awake. + */ +#define MAC_CSR12 0x3030 +#define MAC_CSR12_CURRENT_STATE FIELD32(0x00000001) +#define MAC_CSR12_PUT_TO_SLEEP FIELD32(0x00000002) +#define MAC_CSR12_FORCE_WAKEUP FIELD32(0x00000004) +#define MAC_CSR12_BBP_CURRENT_STATE FIELD32(0x00000008) + +/* + * MAC_CSR13: GPIO. + */ +#define MAC_CSR13 0x3034 +#define MAC_CSR13_BIT0 FIELD32(0x00000001) +#define MAC_CSR13_BIT1 FIELD32(0x00000002) +#define MAC_CSR13_BIT2 FIELD32(0x00000004) +#define MAC_CSR13_BIT3 FIELD32(0x00000008) +#define MAC_CSR13_BIT4 FIELD32(0x00000010) +#define MAC_CSR13_BIT5 FIELD32(0x00000020) +#define MAC_CSR13_BIT6 FIELD32(0x00000040) +#define MAC_CSR13_BIT7 FIELD32(0x00000080) +#define MAC_CSR13_BIT8 FIELD32(0x00000100) +#define MAC_CSR13_BIT9 FIELD32(0x00000200) +#define MAC_CSR13_BIT10 FIELD32(0x00000400) +#define MAC_CSR13_BIT11 FIELD32(0x00000800) +#define MAC_CSR13_BIT12 FIELD32(0x00001000) + +/* + * MAC_CSR14: LED control register. + * ON_PERIOD: On period, default 70ms. + * OFF_PERIOD: Off period, default 30ms. + * HW_LED: HW TX activity, 1: normal OFF, 0: normal ON. + * SW_LED: s/w LED, 1: ON, 0: OFF. + * HW_LED_POLARITY: 0: active low, 1: active high. + */ +#define MAC_CSR14 0x3038 +#define MAC_CSR14_ON_PERIOD FIELD32(0x000000ff) +#define MAC_CSR14_OFF_PERIOD FIELD32(0x0000ff00) +#define MAC_CSR14_HW_LED FIELD32(0x00010000) +#define MAC_CSR14_SW_LED FIELD32(0x00020000) +#define MAC_CSR14_HW_LED_POLARITY FIELD32(0x00040000) +#define MAC_CSR14_SW_LED2 FIELD32(0x00080000) + +/* + * MAC_CSR15: NAV control. + */ +#define MAC_CSR15 0x303c + +/* + * TXRX control registers. + * Some values are set in TU, whereas 1 TU == 1024 us. + */ + +/* + * TXRX_CSR0: TX/RX configuration register. + * TSF_OFFSET: Default is 24. + * AUTO_TX_SEQ: 1: ASIC auto replace sequence nr in outgoing frame. + * DISABLE_RX: Disable Rx engine. + * DROP_CRC: Drop CRC error. + * DROP_PHYSICAL: Drop physical error. + * DROP_CONTROL: Drop control frame. + * DROP_NOT_TO_ME: Drop not to me unicast frame. + * DROP_TO_DS: Drop fram ToDs bit is true. + * DROP_VERSION_ERROR: Drop version error frame. + * DROP_MULTICAST: Drop multicast frames. + * DROP_BORADCAST: Drop broadcast frames. + * ROP_ACK_CTS: Drop received ACK and CTS. + */ +#define TXRX_CSR0 0x3040 +#define TXRX_CSR0_RX_ACK_TIMEOUT FIELD32(0x000001ff) +#define TXRX_CSR0_TSF_OFFSET FIELD32(0x00007e00) +#define TXRX_CSR0_AUTO_TX_SEQ FIELD32(0x00008000) +#define TXRX_CSR0_DISABLE_RX FIELD32(0x00010000) +#define TXRX_CSR0_DROP_CRC FIELD32(0x00020000) +#define TXRX_CSR0_DROP_PHYSICAL FIELD32(0x00040000) +#define TXRX_CSR0_DROP_CONTROL FIELD32(0x00080000) +#define TXRX_CSR0_DROP_NOT_TO_ME FIELD32(0x00100000) +#define TXRX_CSR0_DROP_TO_DS FIELD32(0x00200000) +#define TXRX_CSR0_DROP_VERSION_ERROR FIELD32(0x00400000) +#define TXRX_CSR0_DROP_MULTICAST FIELD32(0x00800000) +#define TXRX_CSR0_DROP_BORADCAST FIELD32(0x01000000) +#define TXRX_CSR0_DROP_ACK_CTS FIELD32(0x02000000) +#define TXRX_CSR0_TX_WITHOUT_WAITING FIELD32(0x04000000) + +/* + * TXRX_CSR1 + */ +#define TXRX_CSR1 0x3044 +#define TXRX_CSR1_BBP_ID0 FIELD32(0x0000007f) +#define TXRX_CSR1_BBP_ID0_VALID FIELD32(0x00000080) +#define TXRX_CSR1_BBP_ID1 FIELD32(0x00007f00) +#define TXRX_CSR1_BBP_ID1_VALID FIELD32(0x00008000) +#define TXRX_CSR1_BBP_ID2 FIELD32(0x007f0000) +#define TXRX_CSR1_BBP_ID2_VALID FIELD32(0x00800000) +#define TXRX_CSR1_BBP_ID3 FIELD32(0x7f000000) +#define TXRX_CSR1_BBP_ID3_VALID FIELD32(0x80000000) + +/* + * TXRX_CSR2 + */ +#define TXRX_CSR2 0x3048 +#define TXRX_CSR2_BBP_ID0 FIELD32(0x0000007f) +#define TXRX_CSR2_BBP_ID0_VALID FIELD32(0x00000080) +#define TXRX_CSR2_BBP_ID1 FIELD32(0x00007f00) +#define TXRX_CSR2_BBP_ID1_VALID FIELD32(0x00008000) +#define TXRX_CSR2_BBP_ID2 FIELD32(0x007f0000) +#define TXRX_CSR2_BBP_ID2_VALID FIELD32(0x00800000) +#define TXRX_CSR2_BBP_ID3 FIELD32(0x7f000000) +#define TXRX_CSR2_BBP_ID3_VALID FIELD32(0x80000000) + +/* + * TXRX_CSR3 + */ +#define TXRX_CSR3 0x304c +#define TXRX_CSR3_BBP_ID0 FIELD32(0x0000007f) +#define TXRX_CSR3_BBP_ID0_VALID FIELD32(0x00000080) +#define TXRX_CSR3_BBP_ID1 FIELD32(0x00007f00) +#define TXRX_CSR3_BBP_ID1_VALID FIELD32(0x00008000) +#define TXRX_CSR3_BBP_ID2 FIELD32(0x007f0000) +#define TXRX_CSR3_BBP_ID2_VALID FIELD32(0x00800000) +#define TXRX_CSR3_BBP_ID3 FIELD32(0x7f000000) +#define TXRX_CSR3_BBP_ID3_VALID FIELD32(0x80000000) + +/* + * TXRX_CSR4: Auto-Responder/Tx-retry register. + * AUTORESPOND_PREAMBLE: 0:long, 1:short preamble. + * OFDM_TX_RATE_DOWN: 1:enable. + * OFDM_TX_RATE_STEP: 0:1-step, 1: 2-step, 2:3-step, 3:4-step. + * OFDM_TX_FALLBACK_CCK: 0: Fallback to OFDM 6M only, 1: Fallback to CCK 1M,2M. + */ +#define TXRX_CSR4 0x3050 +#define TXRX_CSR4_TX_ACK_TIMEOUT FIELD32(0x000000ff) +#define TXRX_CSR4_CNTL_ACK_POLICY FIELD32(0x00000700) +#define TXRX_CSR4_ACK_CTS_PSM FIELD32(0x00010000) +#define TXRX_CSR4_AUTORESPOND_ENABLE FIELD32(0x00020000) +#define TXRX_CSR4_AUTORESPOND_PREAMBLE FIELD32(0x00040000) +#define TXRX_CSR4_OFDM_TX_RATE_DOWN FIELD32(0x00080000) +#define TXRX_CSR4_OFDM_TX_RATE_STEP FIELD32(0x00300000) +#define TXRX_CSR4_OFDM_TX_FALLBACK_CCK FIELD32(0x00400000) +#define TXRX_CSR4_LONG_RETRY_LIMIT FIELD32(0x0f000000) +#define TXRX_CSR4_SHORT_RETRY_LIMIT FIELD32(0xf0000000) + +/* + * TXRX_CSR5 + */ +#define TXRX_CSR5 0x3054 + +/* + * TXRX_CSR6: ACK/CTS payload consumed time + */ +#define TXRX_CSR6 0x3058 + +/* + * TXRX_CSR7: OFDM ACK/CTS payload consumed time for 6/9/12/18 mbps. + */ +#define TXRX_CSR7 0x305c +#define TXRX_CSR7_ACK_CTS_6MBS FIELD32(0x000000ff) +#define TXRX_CSR7_ACK_CTS_9MBS FIELD32(0x0000ff00) +#define TXRX_CSR7_ACK_CTS_12MBS FIELD32(0x00ff0000) +#define TXRX_CSR7_ACK_CTS_18MBS FIELD32(0xff000000) + +/* + * TXRX_CSR8: OFDM ACK/CTS payload consumed time for 24/36/48/54 mbps. + */ +#define TXRX_CSR8 0x3060 +#define TXRX_CSR8_ACK_CTS_24MBS FIELD32(0x000000ff) +#define TXRX_CSR8_ACK_CTS_36MBS FIELD32(0x0000ff00) +#define TXRX_CSR8_ACK_CTS_48MBS FIELD32(0x00ff0000) +#define TXRX_CSR8_ACK_CTS_54MBS FIELD32(0xff000000) + +/* + * TXRX_CSR9: Synchronization control register. + * BEACON_INTERVAL: In unit of 1/16 TU. + * TSF_TICKING: Enable TSF auto counting. + * TSF_SYNC: Tsf sync, 0: disable, 1: infra, 2: ad-hoc/master mode. + * BEACON_GEN: Enable beacon generator. + */ +#define TXRX_CSR9 0x3064 +#define TXRX_CSR9_BEACON_INTERVAL FIELD32(0x0000ffff) +#define TXRX_CSR9_TSF_TICKING FIELD32(0x00010000) +#define TXRX_CSR9_TSF_SYNC FIELD32(0x00060000) +#define TXRX_CSR9_TBTT_ENABLE FIELD32(0x00080000) +#define TXRX_CSR9_BEACON_GEN FIELD32(0x00100000) +#define TXRX_CSR9_TIMESTAMP_COMPENSATE FIELD32(0xff000000) + +/* + * TXRX_CSR10: BEACON alignment. + */ +#define TXRX_CSR10 0x3068 + +/* + * TXRX_CSR11: AES mask. + */ +#define TXRX_CSR11 0x306c + +/* + * TXRX_CSR12: TSF low 32. + */ +#define TXRX_CSR12 0x3070 +#define TXRX_CSR12_LOW_TSFTIMER FIELD32(0xffffffff) + +/* + * TXRX_CSR13: TSF high 32. + */ +#define TXRX_CSR13 0x3074 +#define TXRX_CSR13_HIGH_TSFTIMER FIELD32(0xffffffff) + +/* + * TXRX_CSR14: TBTT timer. + */ +#define TXRX_CSR14 0x3078 + +/* + * TXRX_CSR15: TKIP MIC priority byte "AND" mask. + */ +#define TXRX_CSR15 0x307c + +/* + * PHY control registers. + * Some values are set in TU, whereas 1 TU == 1024 us. + */ + +/* + * PHY_CSR0: RF/PS control. + */ +#define PHY_CSR0 0x3080 +#define PHY_CSR0_PA_PE_BG FIELD32(0x00010000) +#define PHY_CSR0_PA_PE_A FIELD32(0x00020000) + +/* + * PHY_CSR1 + */ +#define PHY_CSR1 0x3084 + +/* + * PHY_CSR2: Pre-TX BBP control. + */ +#define PHY_CSR2 0x3088 + +/* + * PHY_CSR3: BBP serial control register. + * VALUE: Register value to program into BBP. + * REG_NUM: Selected BBP register. + * READ_CONTROL: 0: Write BBP, 1: Read BBP. + * BUSY: 1: ASIC is busy execute BBP programming. + */ +#define PHY_CSR3 0x308c +#define PHY_CSR3_VALUE FIELD32(0x000000ff) +#define PHY_CSR3_REGNUM FIELD32(0x00007f00) +#define PHY_CSR3_READ_CONTROL FIELD32(0x00008000) +#define PHY_CSR3_BUSY FIELD32(0x00010000) + +/* + * PHY_CSR4: RF serial control register + * VALUE: Register value (include register id) serial out to RF/IF chip. + * NUMBER_OF_BITS: Number of bits used in RFRegValue (I:20, RFMD:22). + * IF_SELECT: 1: select IF to program, 0: select RF to program. + * PLL_LD: RF PLL_LD status. + * BUSY: 1: ASIC is busy execute RF programming. + */ +#define PHY_CSR4 0x3090 +#define PHY_CSR4_VALUE FIELD32(0x00ffffff) +#define PHY_CSR4_NUMBER_OF_BITS FIELD32(0x1f000000) +#define PHY_CSR4_IF_SELECT FIELD32(0x20000000) +#define PHY_CSR4_PLL_LD FIELD32(0x40000000) +#define PHY_CSR4_BUSY FIELD32(0x80000000) + +/* + * PHY_CSR5: RX to TX signal switch timing control. + */ +#define PHY_CSR5 0x3094 +#define PHY_CSR5_IQ_FLIP FIELD32(0x00000004) + +/* + * PHY_CSR6: TX to RX signal timing control. + */ +#define PHY_CSR6 0x3098 +#define PHY_CSR6_IQ_FLIP FIELD32(0x00000004) + +/* + * PHY_CSR7: TX DAC switching timing control. + */ +#define PHY_CSR7 0x309c + +/* + * Security control register. + */ + +/* + * SEC_CSR0: Shared key table control. + */ +#define SEC_CSR0 0x30a0 +#define SEC_CSR0_BSS0_KEY0_VALID FIELD32(0x00000001) +#define SEC_CSR0_BSS0_KEY1_VALID FIELD32(0x00000002) +#define SEC_CSR0_BSS0_KEY2_VALID FIELD32(0x00000004) +#define SEC_CSR0_BSS0_KEY3_VALID FIELD32(0x00000008) +#define SEC_CSR0_BSS1_KEY0_VALID FIELD32(0x00000010) +#define SEC_CSR0_BSS1_KEY1_VALID FIELD32(0x00000020) +#define SEC_CSR0_BSS1_KEY2_VALID FIELD32(0x00000040) +#define SEC_CSR0_BSS1_KEY3_VALID FIELD32(0x00000080) +#define SEC_CSR0_BSS2_KEY0_VALID FIELD32(0x00000100) +#define SEC_CSR0_BSS2_KEY1_VALID FIELD32(0x00000200) +#define SEC_CSR0_BSS2_KEY2_VALID FIELD32(0x00000400) +#define SEC_CSR0_BSS2_KEY3_VALID FIELD32(0x00000800) +#define SEC_CSR0_BSS3_KEY0_VALID FIELD32(0x00001000) +#define SEC_CSR0_BSS3_KEY1_VALID FIELD32(0x00002000) +#define SEC_CSR0_BSS3_KEY2_VALID FIELD32(0x00004000) +#define SEC_CSR0_BSS3_KEY3_VALID FIELD32(0x00008000) + +/* + * SEC_CSR1: Shared key table security mode register. + */ +#define SEC_CSR1 0x30a4 +#define SEC_CSR1_BSS0_KEY0_CIPHER_ALG FIELD32(0x00000007) +#define SEC_CSR1_BSS0_KEY1_CIPHER_ALG FIELD32(0x00000070) +#define SEC_CSR1_BSS0_KEY2_CIPHER_ALG FIELD32(0x00000700) +#define SEC_CSR1_BSS0_KEY3_CIPHER_ALG FIELD32(0x00007000) +#define SEC_CSR1_BSS1_KEY0_CIPHER_ALG FIELD32(0x00070000) +#define SEC_CSR1_BSS1_KEY1_CIPHER_ALG FIELD32(0x00700000) +#define SEC_CSR1_BSS1_KEY2_CIPHER_ALG FIELD32(0x07000000) +#define SEC_CSR1_BSS1_KEY3_CIPHER_ALG FIELD32(0x70000000) + +/* + * Pairwise key table valid bitmap registers. + * SEC_CSR2: pairwise key table valid bitmap 0. + * SEC_CSR3: pairwise key table valid bitmap 1. + */ +#define SEC_CSR2 0x30a8 +#define SEC_CSR3 0x30ac + +/* + * SEC_CSR4: Pairwise key table lookup control. + */ +#define SEC_CSR4 0x30b0 + +/* + * SEC_CSR5: shared key table security mode register. + */ +#define SEC_CSR5 0x30b4 +#define SEC_CSR5_BSS2_KEY0_CIPHER_ALG FIELD32(0x00000007) +#define SEC_CSR5_BSS2_KEY1_CIPHER_ALG FIELD32(0x00000070) +#define SEC_CSR5_BSS2_KEY2_CIPHER_ALG FIELD32(0x00000700) +#define SEC_CSR5_BSS2_KEY3_CIPHER_ALG FIELD32(0x00007000) +#define SEC_CSR5_BSS3_KEY0_CIPHER_ALG FIELD32(0x00070000) +#define SEC_CSR5_BSS3_KEY1_CIPHER_ALG FIELD32(0x00700000) +#define SEC_CSR5_BSS3_KEY2_CIPHER_ALG FIELD32(0x07000000) +#define SEC_CSR5_BSS3_KEY3_CIPHER_ALG FIELD32(0x70000000) + +/* + * STA control registers. + */ + +/* + * STA_CSR0: RX PLCP error count & RX FCS error count. + */ +#define STA_CSR0 0x30c0 +#define STA_CSR0_FCS_ERROR FIELD32(0x0000ffff) +#define STA_CSR0_PLCP_ERROR FIELD32(0xffff0000) + +/* + * STA_CSR1: RX False CCA count & RX LONG frame count. + */ +#define STA_CSR1 0x30c4 +#define STA_CSR1_PHYSICAL_ERROR FIELD32(0x0000ffff) +#define STA_CSR1_FALSE_CCA_ERROR FIELD32(0xffff0000) + +/* + * STA_CSR2: TX Beacon count and RX FIFO overflow count. + */ +#define STA_CSR2 0x30c8 +#define STA_CSR2_RX_FIFO_OVERFLOW_COUNT FIELD32(0x0000ffff) +#define STA_CSR2_RX_OVERFLOW_COUNT FIELD32(0xffff0000) + +/* + * STA_CSR3: TX Beacon count. + */ +#define STA_CSR3 0x30cc +#define STA_CSR3_TX_BEACON_COUNT FIELD32(0x0000ffff) + +/* + * STA_CSR4: TX Result status register. + * VALID: 1:This register contains a valid TX result. + */ +#define STA_CSR4 0x30d0 +#define STA_CSR4_VALID FIELD32(0x00000001) +#define STA_CSR4_TX_RESULT FIELD32(0x0000000e) +#define STA_CSR4_RETRY_COUNT FIELD32(0x000000f0) +#define STA_CSR4_PID_SUBTYPE FIELD32(0x00001f00) +#define STA_CSR4_PID_TYPE FIELD32(0x0000e000) +#define STA_CSR4_TXRATE FIELD32(0x000f0000) + +/* + * QOS control registers. + */ + +/* + * QOS_CSR0: TXOP holder MAC address register. + */ +#define QOS_CSR0 0x30e0 +#define QOS_CSR0_BYTE0 FIELD32(0x000000ff) +#define QOS_CSR0_BYTE1 FIELD32(0x0000ff00) +#define QOS_CSR0_BYTE2 FIELD32(0x00ff0000) +#define QOS_CSR0_BYTE3 FIELD32(0xff000000) + +/* + * QOS_CSR1: TXOP holder MAC address register. + */ +#define QOS_CSR1 0x30e4 +#define QOS_CSR1_BYTE4 FIELD32(0x000000ff) +#define QOS_CSR1_BYTE5 FIELD32(0x0000ff00) + +/* + * QOS_CSR2: TXOP holder timeout register. + */ +#define QOS_CSR2 0x30e8 + +/* + * RX QOS-CFPOLL MAC address register. + * QOS_CSR3: RX QOS-CFPOLL MAC address 0. + * QOS_CSR4: RX QOS-CFPOLL MAC address 1. + */ +#define QOS_CSR3 0x30ec +#define QOS_CSR4 0x30f0 + +/* + * QOS_CSR5: "QosControl" field of the RX QOS-CFPOLL. + */ +#define QOS_CSR5 0x30f4 + +/* + * Host DMA registers. + */ + +/* + * AC0_BASE_CSR: AC_BK base address. + */ +#define AC0_BASE_CSR 0x3400 +#define AC0_BASE_CSR_RING_REGISTER FIELD32(0xffffffff) + +/* + * AC1_BASE_CSR: AC_BE base address. + */ +#define AC1_BASE_CSR 0x3404 +#define AC1_BASE_CSR_RING_REGISTER FIELD32(0xffffffff) + +/* + * AC2_BASE_CSR: AC_VI base address. + */ +#define AC2_BASE_CSR 0x3408 +#define AC2_BASE_CSR_RING_REGISTER FIELD32(0xffffffff) + +/* + * AC3_BASE_CSR: AC_VO base address. + */ +#define AC3_BASE_CSR 0x340c +#define AC3_BASE_CSR_RING_REGISTER FIELD32(0xffffffff) + +/* + * MGMT_BASE_CSR: MGMT ring base address. + */ +#define MGMT_BASE_CSR 0x3410 +#define MGMT_BASE_CSR_RING_REGISTER FIELD32(0xffffffff) + +/* + * TX_RING_CSR0: TX Ring size for AC_BK, AC_BE, AC_VI, AC_VO. + */ +#define TX_RING_CSR0 0x3418 +#define TX_RING_CSR0_AC0_RING_SIZE FIELD32(0x000000ff) +#define TX_RING_CSR0_AC1_RING_SIZE FIELD32(0x0000ff00) +#define TX_RING_CSR0_AC2_RING_SIZE FIELD32(0x00ff0000) +#define TX_RING_CSR0_AC3_RING_SIZE FIELD32(0xff000000) + +/* + * TX_RING_CSR1: TX Ring size for MGMT Ring, HCCA Ring + * TXD_SIZE: In unit of 32-bit. + */ +#define TX_RING_CSR1 0x341c +#define TX_RING_CSR1_MGMT_RING_SIZE FIELD32(0x000000ff) +#define TX_RING_CSR1_HCCA_RING_SIZE FIELD32(0x0000ff00) +#define TX_RING_CSR1_TXD_SIZE FIELD32(0x003f0000) + +/* + * AIFSN_CSR: AIFSN for each EDCA AC. + * AIFSN0: For AC_BK. + * AIFSN1: For AC_BE. + * AIFSN2: For AC_VI. + * AIFSN3: For AC_VO. + */ +#define AIFSN_CSR 0x3420 +#define AIFSN_CSR_AIFSN0 FIELD32(0x0000000f) +#define AIFSN_CSR_AIFSN1 FIELD32(0x000000f0) +#define AIFSN_CSR_AIFSN2 FIELD32(0x00000f00) +#define AIFSN_CSR_AIFSN3 FIELD32(0x0000f000) + +/* + * CWMIN_CSR: CWmin for each EDCA AC. + * CWMIN0: For AC_BK. + * CWMIN1: For AC_BE. + * CWMIN2: For AC_VI. + * CWMIN3: For AC_VO. + */ +#define CWMIN_CSR 0x3424 +#define CWMIN_CSR_CWMIN0 FIELD32(0x0000000f) +#define CWMIN_CSR_CWMIN1 FIELD32(0x000000f0) +#define CWMIN_CSR_CWMIN2 FIELD32(0x00000f00) +#define CWMIN_CSR_CWMIN3 FIELD32(0x0000f000) + +/* + * CWMAX_CSR: CWmax for each EDCA AC. + * CWMAX0: For AC_BK. + * CWMAX1: For AC_BE. + * CWMAX2: For AC_VI. + * CWMAX3: For AC_VO. + */ +#define CWMAX_CSR 0x3428 +#define CWMAX_CSR_CWMAX0 FIELD32(0x0000000f) +#define CWMAX_CSR_CWMAX1 FIELD32(0x000000f0) +#define CWMAX_CSR_CWMAX2 FIELD32(0x00000f00) +#define CWMAX_CSR_CWMAX3 FIELD32(0x0000f000) + +/* + * TX_DMA_DST_CSR: TX DMA destination + * 0: TX ring0, 1: TX ring1, 2: TX ring2 3: invalid + */ +#define TX_DMA_DST_CSR 0x342c +#define TX_DMA_DST_CSR_DEST_AC0 FIELD32(0x00000003) +#define TX_DMA_DST_CSR_DEST_AC1 FIELD32(0x0000000c) +#define TX_DMA_DST_CSR_DEST_AC2 FIELD32(0x00000030) +#define TX_DMA_DST_CSR_DEST_AC3 FIELD32(0x000000c0) +#define TX_DMA_DST_CSR_DEST_MGMT FIELD32(0x00000300) + +/* + * TX_CNTL_CSR: KICK/Abort TX. + * KICK_TX_AC0: For AC_BK. + * KICK_TX_AC1: For AC_BE. + * KICK_TX_AC2: For AC_VI. + * KICK_TX_AC3: For AC_VO. + * ABORT_TX_AC0: For AC_BK. + * ABORT_TX_AC1: For AC_BE. + * ABORT_TX_AC2: For AC_VI. + * ABORT_TX_AC3: For AC_VO. + */ +#define TX_CNTL_CSR 0x3430 +#define TX_CNTL_CSR_KICK_TX_AC0 FIELD32(0x00000001) +#define TX_CNTL_CSR_KICK_TX_AC1 FIELD32(0x00000002) +#define TX_CNTL_CSR_KICK_TX_AC2 FIELD32(0x00000004) +#define TX_CNTL_CSR_KICK_TX_AC3 FIELD32(0x00000008) +#define TX_CNTL_CSR_KICK_TX_MGMT FIELD32(0x00000010) +#define TX_CNTL_CSR_ABORT_TX_AC0 FIELD32(0x00010000) +#define TX_CNTL_CSR_ABORT_TX_AC1 FIELD32(0x00020000) +#define TX_CNTL_CSR_ABORT_TX_AC2 FIELD32(0x00040000) +#define TX_CNTL_CSR_ABORT_TX_AC3 FIELD32(0x00080000) +#define TX_CNTL_CSR_ABORT_TX_MGMT FIELD32(0x00100000) + +/* + * LOAD_TX_RING_CSR: Load RX de + */ +#define LOAD_TX_RING_CSR 0x3434 +#define LOAD_TX_RING_CSR_LOAD_TXD_AC0 FIELD32(0x00000001) +#define LOAD_TX_RING_CSR_LOAD_TXD_AC1 FIELD32(0x00000002) +#define LOAD_TX_RING_CSR_LOAD_TXD_AC2 FIELD32(0x00000004) +#define LOAD_TX_RING_CSR_LOAD_TXD_AC3 FIELD32(0x00000008) +#define LOAD_TX_RING_CSR_LOAD_TXD_MGMT FIELD32(0x00000010) + +/* + * Several read-only registers, for debugging. + */ +#define AC0_TXPTR_CSR 0x3438 +#define AC1_TXPTR_CSR 0x343c +#define AC2_TXPTR_CSR 0x3440 +#define AC3_TXPTR_CSR 0x3444 +#define MGMT_TXPTR_CSR 0x3448 + +/* + * RX_BASE_CSR + */ +#define RX_BASE_CSR 0x3450 +#define RX_BASE_CSR_RING_REGISTER FIELD32(0xffffffff) + +/* + * RX_RING_CSR. + * RXD_SIZE: In unit of 32-bit. + */ +#define RX_RING_CSR 0x3454 +#define RX_RING_CSR_RING_SIZE FIELD32(0x000000ff) +#define RX_RING_CSR_RXD_SIZE FIELD32(0x00003f00) +#define RX_RING_CSR_RXD_WRITEBACK_SIZE FIELD32(0x00070000) + +/* + * RX_CNTL_CSR + */ +#define RX_CNTL_CSR 0x3458 +#define RX_CNTL_CSR_ENABLE_RX_DMA FIELD32(0x00000001) +#define RX_CNTL_CSR_LOAD_RXD FIELD32(0x00000002) + +/* + * RXPTR_CSR: Read-only, for debugging. + */ +#define RXPTR_CSR 0x345c + +/* + * PCI_CFG_CSR + */ +#define PCI_CFG_CSR 0x3460 + +/* + * BUF_FORMAT_CSR + */ +#define BUF_FORMAT_CSR 0x3464 + +/* + * INT_SOURCE_CSR: Interrupt source register. + * Write one to clear corresponding bit. + */ +#define INT_SOURCE_CSR 0x3468 +#define INT_SOURCE_CSR_TXDONE FIELD32(0x00000001) +#define INT_SOURCE_CSR_RXDONE FIELD32(0x00000002) +#define INT_SOURCE_CSR_BEACON_DONE FIELD32(0x00000004) +#define INT_SOURCE_CSR_TX_ABORT_DONE FIELD32(0x00000010) +#define INT_SOURCE_CSR_AC0_DMA_DONE FIELD32(0x00010000) +#define INT_SOURCE_CSR_AC1_DMA_DONE FIELD32(0x00020000) +#define INT_SOURCE_CSR_AC2_DMA_DONE FIELD32(0x00040000) +#define INT_SOURCE_CSR_AC3_DMA_DONE FIELD32(0x00080000) +#define INT_SOURCE_CSR_MGMT_DMA_DONE FIELD32(0x00100000) +#define INT_SOURCE_CSR_HCCA_DMA_DONE FIELD32(0x00200000) + +/* + * INT_MASK_CSR: Interrupt MASK register. 1: the interrupt is mask OFF. + * MITIGATION_PERIOD: Interrupt mitigation in unit of 32 PCI clock. + */ +#define INT_MASK_CSR 0x346c +#define INT_MASK_CSR_TXDONE FIELD32(0x00000001) +#define INT_MASK_CSR_RXDONE FIELD32(0x00000002) +#define INT_MASK_CSR_BEACON_DONE FIELD32(0x00000004) +#define INT_MASK_CSR_TX_ABORT_DONE FIELD32(0x00000010) +#define INT_MASK_CSR_ENABLE_MITIGATION FIELD32(0x00000080) +#define INT_MASK_CSR_MITIGATION_PERIOD FIELD32(0x0000ff00) +#define INT_MASK_CSR_AC0_DMA_DONE FIELD32(0x00010000) +#define INT_MASK_CSR_AC1_DMA_DONE FIELD32(0x00020000) +#define INT_MASK_CSR_AC2_DMA_DONE FIELD32(0x00040000) +#define INT_MASK_CSR_AC3_DMA_DONE FIELD32(0x00080000) +#define INT_MASK_CSR_MGMT_DMA_DONE FIELD32(0x00100000) +#define INT_MASK_CSR_HCCA_DMA_DONE FIELD32(0x00200000) + +/* + * E2PROM_CSR: EEPROM control register. + * RELOAD: Write 1 to reload eeprom content. + * TYPE_93C46: 1: 93c46, 0:93c66. + * LOAD_STATUS: 1:loading, 0:done. + */ +#define E2PROM_CSR 0x3470 +#define E2PROM_CSR_RELOAD FIELD32(0x00000001) +#define E2PROM_CSR_DATA_CLOCK FIELD32(0x00000002) +#define E2PROM_CSR_CHIP_SELECT FIELD32(0x00000004) +#define E2PROM_CSR_DATA_IN FIELD32(0x00000008) +#define E2PROM_CSR_DATA_OUT FIELD32(0x00000010) +#define E2PROM_CSR_TYPE_93C46 FIELD32(0x00000020) +#define E2PROM_CSR_LOAD_STATUS FIELD32(0x00000040) + +/* + * AC_TXOP_CSR0: AC_BK/AC_BE TXOP register. + * AC0_TX_OP: For AC_BK, in unit of 32us. + * AC1_TX_OP: For AC_BE, in unit of 32us. + */ +#define AC_TXOP_CSR0 0x3474 +#define AC_TXOP_CSR0_AC0_TX_OP FIELD32(0x0000ffff) +#define AC_TXOP_CSR0_AC1_TX_OP FIELD32(0xffff0000) + +/* + * AC_TXOP_CSR1: AC_VO/AC_VI TXOP register. + * AC2_TX_OP: For AC_VI, in unit of 32us. + * AC3_TX_OP: For AC_VO, in unit of 32us. + */ +#define AC_TXOP_CSR1 0x3478 +#define AC_TXOP_CSR1_AC2_TX_OP FIELD32(0x0000ffff) +#define AC_TXOP_CSR1_AC3_TX_OP FIELD32(0xffff0000) + +/* + * DMA_STATUS_CSR + */ +#define DMA_STATUS_CSR 0x3480 + +/* + * TEST_MODE_CSR + */ +#define TEST_MODE_CSR 0x3484 + +/* + * UART0_TX_CSR + */ +#define UART0_TX_CSR 0x3488 + +/* + * UART0_RX_CSR + */ +#define UART0_RX_CSR 0x348c + +/* + * UART0_FRAME_CSR + */ +#define UART0_FRAME_CSR 0x3490 + +/* + * UART0_BUFFER_CSR + */ +#define UART0_BUFFER_CSR 0x3494 + +/* + * IO_CNTL_CSR + */ +#define IO_CNTL_CSR 0x3498 + +/* + * UART_INT_SOURCE_CSR + */ +#define UART_INT_SOURCE_CSR 0x34a8 + +/* + * UART_INT_MASK_CSR + */ +#define UART_INT_MASK_CSR 0x34ac + +/* + * PBF_QUEUE_CSR + */ +#define PBF_QUEUE_CSR 0x34b0 + +/* + * Firmware DMA registers. + * Firmware DMA registers are dedicated for MCU usage + * and should not be touched by host driver. + * Therefore we skip the definition of these registers. + */ +#define FW_TX_BASE_CSR 0x34c0 +#define FW_TX_START_CSR 0x34c4 +#define FW_TX_LAST_CSR 0x34c8 +#define FW_MODE_CNTL_CSR 0x34cc +#define FW_TXPTR_CSR 0x34d0 + +/* + * 8051 firmware image. + */ +#define FIRMWARE_RT2561 "rt2561.bin" +#define FIRMWARE_RT2561s "rt2561s.bin" +#define FIRMWARE_RT2661 "rt2661.bin" +#define FIRMWARE_IMAGE_BASE 0x4000 + +/* + * BBP registers. + * The wordsize of the BBP is 8 bits. + */ + +/* + * R2 + */ +#define BBP_R2_BG_MODE FIELD8(0x20) + +/* + * R3 + */ +#define BBP_R3_SMART_MODE FIELD8(0x01) + +/* + * R4: RX antenna control + * FRAME_END: 1 - DPDT, 0 - SPDT (Only valid for 802.11G, RF2527 & RF2529) + */ +#define BBP_R4_RX_ANTENNA FIELD8(0x03) +#define BBP_R4_RX_FRAME_END FIELD8(0x20) + +/* + * R77 + */ +#define BBP_R77_PAIR FIELD8(0x03) + +/* + * RF registers + */ + +/* + * RF 3 + */ +#define RF3_TXPOWER FIELD32(0x00003e00) + +/* + * RF 4 + */ +#define RF4_FREQ_OFFSET FIELD32(0x0003f000) + +/* + * EEPROM content. + * The wordsize of the EEPROM is 16 bits. + */ + +/* + * HW MAC address. + */ +#define EEPROM_MAC_ADDR_0 0x0002 +#define EEPROM_MAC_ADDR_BYTE0 FIELD16(0x00ff) +#define EEPROM_MAC_ADDR_BYTE1 FIELD16(0xff00) +#define EEPROM_MAC_ADDR1 0x0004 +#define EEPROM_MAC_ADDR_BYTE2 FIELD16(0x00ff) +#define EEPROM_MAC_ADDR_BYTE3 FIELD16(0xff00) +#define EEPROM_MAC_ADDR_2 0x0006 +#define EEPROM_MAC_ADDR_BYTE4 FIELD16(0x00ff) +#define EEPROM_MAC_ADDR_BYTE5 FIELD16(0xff00) + +/* + * EEPROM antenna. + * ANTENNA_NUM: Number of antenna's. + * TX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B. + * RX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B. + * FRAME_TYPE: 0: DPDT , 1: SPDT , noted this bit is valid for g only. + * DYN_TXAGC: Dynamic TX AGC control. + * HARDWARE_RADIO: 1: Hardware controlled radio. Read GPIO0. + * RF_TYPE: Rf_type of this adapter. + */ +#define EEPROM_ANTENNA 0x0010 +#define EEPROM_ANTENNA_NUM FIELD16(0x0003) +#define EEPROM_ANTENNA_TX_DEFAULT FIELD16(0x000c) +#define EEPROM_ANTENNA_RX_DEFAULT FIELD16(0x0030) +#define EEPROM_ANTENNA_FRAME_TYPE FIELD16(0x0040) +#define EEPROM_ANTENNA_DYN_TXAGC FIELD16(0x0200) +#define EEPROM_ANTENNA_HARDWARE_RADIO FIELD16(0x0400) +#define EEPROM_ANTENNA_RF_TYPE FIELD16(0xf800) + +/* + * EEPROM NIC config. + * ENABLE_DIVERSITY: 1:enable, 0:disable. + * EXTERNAL_LNA_BG: External LNA enable for 2.4G. + * CARDBUS_ACCEL: 0:enable, 1:disable. + * EXTERNAL_LNA_A: External LNA enable for 5G. + */ +#define EEPROM_NIC 0x0011 +#define EEPROM_NIC_ENABLE_DIVERSITY FIELD16(0x0001) +#define EEPROM_NIC_TX_DIVERSITY FIELD16(0x0002) +#define EEPROM_NIC_TX_RX_FIXED FIELD16(0x000c) +#define EEPROM_NIC_EXTERNAL_LNA_BG FIELD16(0x0010) +#define EEPROM_NIC_CARDBUS_ACCEL FIELD16(0x0020) +#define EEPROM_NIC_EXTERNAL_LNA_A FIELD16(0x0040) + +/* + * EEPROM geography. + * GEO_A: Default geographical setting for 5GHz band + * GEO: Default geographical setting. + */ +#define EEPROM_GEOGRAPHY 0x0012 +#define EEPROM_GEOGRAPHY_GEO_A FIELD16(0x00ff) +#define EEPROM_GEOGRAPHY_GEO FIELD16(0xff00) + +/* + * EEPROM BBP. + */ +#define EEPROM_BBP_START 0x0013 +#define EEPROM_BBP_SIZE 16 +#define EEPROM_BBP_VALUE FIELD16(0x00ff) +#define EEPROM_BBP_REG_ID FIELD16(0xff00) + +/* + * EEPROM TXPOWER 802.11G + */ +#define EEPROM_TXPOWER_G_START 0x0023 +#define EEPROM_TXPOWER_G_SIZE 7 +#define EEPROM_TXPOWER_G_1 FIELD16(0x00ff) +#define EEPROM_TXPOWER_G_2 FIELD16(0xff00) + +/* + * EEPROM Frequency + */ +#define EEPROM_FREQ 0x002f +#define EEPROM_FREQ_OFFSET FIELD16(0x00ff) +#define EEPROM_FREQ_SEQ_MASK FIELD16(0xff00) +#define EEPROM_FREQ_SEQ FIELD16(0x0300) + +/* + * EEPROM LED. + * POLARITY_RDY_G: Polarity RDY_G setting. + * POLARITY_RDY_A: Polarity RDY_A setting. + * POLARITY_ACT: Polarity ACT setting. + * POLARITY_GPIO_0: Polarity GPIO0 setting. + * POLARITY_GPIO_1: Polarity GPIO1 setting. + * POLARITY_GPIO_2: Polarity GPIO2 setting. + * POLARITY_GPIO_3: Polarity GPIO3 setting. + * POLARITY_GPIO_4: Polarity GPIO4 setting. + * LED_MODE: Led mode. + */ +#define EEPROM_LED 0x0030 +#define EEPROM_LED_POLARITY_RDY_G FIELD16(0x0001) +#define EEPROM_LED_POLARITY_RDY_A FIELD16(0x0002) +#define EEPROM_LED_POLARITY_ACT FIELD16(0x0004) +#define EEPROM_LED_POLARITY_GPIO_0 FIELD16(0x0008) +#define EEPROM_LED_POLARITY_GPIO_1 FIELD16(0x0010) +#define EEPROM_LED_POLARITY_GPIO_2 FIELD16(0x0020) +#define EEPROM_LED_POLARITY_GPIO_3 FIELD16(0x0040) +#define EEPROM_LED_POLARITY_GPIO_4 FIELD16(0x0080) +#define EEPROM_LED_LED_MODE FIELD16(0x1f00) + +/* + * EEPROM TXPOWER 802.11A + */ +#define EEPROM_TXPOWER_A_START 0x0031 +#define EEPROM_TXPOWER_A_SIZE 12 +#define EEPROM_TXPOWER_A_1 FIELD16(0x00ff) +#define EEPROM_TXPOWER_A_2 FIELD16(0xff00) + +/* + * EEPROM RSSI offset 802.11BG + */ +#define EEPROM_RSSI_OFFSET_BG 0x004d +#define EEPROM_RSSI_OFFSET_BG_1 FIELD16(0x00ff) +#define EEPROM_RSSI_OFFSET_BG_2 FIELD16(0xff00) + +/* + * EEPROM RSSI offset 802.11A + */ +#define EEPROM_RSSI_OFFSET_A 0x004e +#define EEPROM_RSSI_OFFSET_A_1 FIELD16(0x00ff) +#define EEPROM_RSSI_OFFSET_A_2 FIELD16(0xff00) + +/* + * MCU mailbox commands. + */ +#define MCU_SLEEP 0x30 +#define MCU_WAKEUP 0x31 +#define MCU_LED 0x50 +#define MCU_LED_STRENGTH 0x52 + +/* + * DMA descriptor defines. + */ +#define TXD_DESC_SIZE ( 16 * sizeof(struct data_desc) ) +#define RXD_DESC_SIZE ( 16 * sizeof(struct data_desc) ) + +/* + * TX descriptor format for TX, PRIO and Beacon Ring. + */ + +/* + * Word0 + * TKIP_MIC: ASIC appends TKIP MIC if TKIP is used. + * KEY_TABLE: Use per-client pairwise KEY table. + * KEY_INDEX: + * Key index (0~31) to the pairwise KEY table. + * 0~3 to shared KEY table 0 (BSS0). + * 4~7 to shared KEY table 1 (BSS1). + * 8~11 to shared KEY table 2 (BSS2). + * 12~15 to shared KEY table 3 (BSS3). + * BURST: Next frame belongs to same "burst" event. + */ +#define TXD_W0_OWNER_NIC FIELD32(0x00000001) +#define TXD_W0_VALID FIELD32(0x00000002) +#define TXD_W0_MORE_FRAG FIELD32(0x00000004) +#define TXD_W0_ACK FIELD32(0x00000008) +#define TXD_W0_TIMESTAMP FIELD32(0x00000010) +#define TXD_W0_OFDM FIELD32(0x00000020) +#define TXD_W0_IFS FIELD32(0x00000040) +#define TXD_W0_RETRY_MODE FIELD32(0x00000080) +#define TXD_W0_TKIP_MIC FIELD32(0x00000100) +#define TXD_W0_KEY_TABLE FIELD32(0x00000200) +#define TXD_W0_KEY_INDEX FIELD32(0x0000fc00) +#define TXD_W0_DATABYTE_COUNT FIELD32(0x0fff0000) +#define TXD_W0_BURST FIELD32(0x10000000) +#define TXD_W0_CIPHER_ALG FIELD32(0xe0000000) + +/* + * Word1 + * HOST_Q_ID: EDCA/HCCA queue ID. + * HW_SEQUENCE: MAC overwrites the frame sequence number. + * BUFFER_COUNT: Number of buffers in this TXD. + */ +#define TXD_W1_HOST_Q_ID FIELD32(0x0000000f) +#define TXD_W1_AIFSN FIELD32(0x000000f0) +#define TXD_W1_CWMIN FIELD32(0x00000f00) +#define TXD_W1_CWMAX FIELD32(0x0000f000) +#define TXD_W1_IV_OFFSET FIELD32(0x003f0000) +#define TXD_W1_PIGGY_BACK FIELD32(0x01000000) +#define TXD_W1_HW_SEQUENCE FIELD32(0x10000000) +#define TXD_W1_BUFFER_COUNT FIELD32(0xe0000000) + +/* + * Word2: PLCP information + */ +#define TXD_W2_PLCP_SIGNAL FIELD32(0x000000ff) +#define TXD_W2_PLCP_SERVICE FIELD32(0x0000ff00) +#define TXD_W2_PLCP_LENGTH_LOW FIELD32(0x00ff0000) +#define TXD_W2_PLCP_LENGTH_HIGH FIELD32(0xff000000) + +/* + * Word3 + */ +#define TXD_W3_IV FIELD32(0xffffffff) + +/* + * Word4 + */ +#define TXD_W4_EIV FIELD32(0xffffffff) + +/* + * Word5 + * FRAME_OFFSET: Frame start offset inside ASIC TXFIFO (after TXINFO field). + * TXD_W5_PID_SUBTYPE: Driver assigned packet ID index for txdone handler. + * TXD_W5_PID_TYPE: Driver assigned packet ID type for txdone handler. + * WAITING_DMA_DONE_INT: TXD been filled with data + * and waiting for TxDoneISR housekeeping. + */ +#define TXD_W5_FRAME_OFFSET FIELD32(0x000000ff) +#define TXD_W5_PID_SUBTYPE FIELD32(0x00001f00) +#define TXD_W5_PID_TYPE FIELD32(0x0000e000) +#define TXD_W5_TX_POWER FIELD32(0x00ff0000) +#define TXD_W5_WAITING_DMA_DONE_INT FIELD32(0x01000000) + +/* + * the above 24-byte is called TXINFO and will be DMAed to MAC block + * through TXFIFO. MAC block use this TXINFO to control the transmission + * behavior of this frame. + * The following fields are not used by MAC block. + * They are used by DMA block and HOST driver only. + * Once a frame has been DMA to ASIC, all the following fields are useless + * to ASIC. + */ + +/* + * Word6-10: Buffer physical address + */ +#define TXD_W6_BUFFER_PHYSICAL_ADDRESS FIELD32(0xffffffff) +#define TXD_W7_BUFFER_PHYSICAL_ADDRESS FIELD32(0xffffffff) +#define TXD_W8_BUFFER_PHYSICAL_ADDRESS FIELD32(0xffffffff) +#define TXD_W9_BUFFER_PHYSICAL_ADDRESS FIELD32(0xffffffff) +#define TXD_W10_BUFFER_PHYSICAL_ADDRESS FIELD32(0xffffffff) + +/* + * Word11-13: Buffer length + */ +#define TXD_W11_BUFFER_LENGTH0 FIELD32(0x00000fff) +#define TXD_W11_BUFFER_LENGTH1 FIELD32(0x0fff0000) +#define TXD_W12_BUFFER_LENGTH2 FIELD32(0x00000fff) +#define TXD_W12_BUFFER_LENGTH3 FIELD32(0x0fff0000) +#define TXD_W13_BUFFER_LENGTH4 FIELD32(0x00000fff) + +/* + * Word14 + */ +#define TXD_W14_SK_BUFFER FIELD32(0xffffffff) + +/* + * Word15 + */ +#define TXD_W15_NEXT_SK_BUFFER FIELD32(0xffffffff) + +/* + * RX descriptor format for RX Ring. + */ + +/* + * Word0 + * CIPHER_ERROR: 1:ICV error, 2:MIC error, 3:invalid key. + * KEY_INDEX: Decryption key actually used. + */ +#define RXD_W0_OWNER_NIC FIELD32(0x00000001) +#define RXD_W0_DROP FIELD32(0x00000002) +#define RXD_W0_UNICAST_TO_ME FIELD32(0x00000004) +#define RXD_W0_MULTICAST FIELD32(0x00000008) +#define RXD_W0_BROADCAST FIELD32(0x00000010) +#define RXD_W0_MY_BSS FIELD32(0x00000020) +#define RXD_W0_CRC_ERROR FIELD32(0x00000040) +#define RXD_W0_OFDM FIELD32(0x00000080) +#define RXD_W0_CIPHER_ERROR FIELD32(0x00000300) +#define RXD_W0_KEY_INDEX FIELD32(0x0000fc00) +#define RXD_W0_DATABYTE_COUNT FIELD32(0x0fff0000) +#define RXD_W0_CIPHER_ALG FIELD32(0xe0000000) + +/* + * Word1 + * SIGNAL: RX raw data rate reported by BBP. + */ +#define RXD_W1_SIGNAL FIELD32(0x000000ff) +#define RXD_W1_RSSI_AGC FIELD32(0x00001f00) +#define RXD_W1_RSSI_LNA FIELD32(0x00006000) +#define RXD_W1_FRAME_OFFSET FIELD32(0x7f000000) + +/* + * Word2 + * IV: Received IV of originally encrypted. + */ +#define RXD_W2_IV FIELD32(0xffffffff) + +/* + * Word3 + * EIV: Received EIV of originally encrypted. + */ +#define RXD_W3_EIV FIELD32(0xffffffff) + +/* + * Word4 + */ +#define RXD_W4_RESERVED FIELD32(0xffffffff) + +/* + * the above 20-byte is called RXINFO and will be DMAed to MAC RX block + * and passed to the HOST driver. + * The following fields are for DMA block and HOST usage only. + * Can't be touched by ASIC MAC block. + */ + +/* + * Word5 + */ +#define RXD_W5_BUFFER_PHYSICAL_ADDRESS FIELD32(0xffffffff) + +/* + * Word6-15: Reserved + */ +#define RXD_W6_RESERVED FIELD32(0xffffffff) +#define RXD_W7_RESERVED FIELD32(0xffffffff) +#define RXD_W8_RESERVED FIELD32(0xffffffff) +#define RXD_W9_RESERVED FIELD32(0xffffffff) +#define RXD_W10_RESERVED FIELD32(0xffffffff) +#define RXD_W11_RESERVED FIELD32(0xffffffff) +#define RXD_W12_RESERVED FIELD32(0xffffffff) +#define RXD_W13_RESERVED FIELD32(0xffffffff) +#define RXD_W14_RESERVED FIELD32(0xffffffff) +#define RXD_W15_RESERVED FIELD32(0xffffffff) + +/* + * Macro's for converting txpower from EEPROM to dscape value + * and from dscape value to register value. + */ +#define MIN_TXPOWER 0 +#define MAX_TXPOWER 31 +#define DEFAULT_TXPOWER 24 + +#define TXPOWER_FROM_DEV(__txpower) \ +({ \ + ((__txpower) > MAX_TXPOWER) ? \ + DEFAULT_TXPOWER : (__txpower); \ +}) + +#define TXPOWER_TO_DEV(__txpower) \ +({ \ + ((__txpower) <= MIN_TXPOWER) ? MIN_TXPOWER : \ + (((__txpower) >= MAX_TXPOWER) ? MAX_TXPOWER : \ + (__txpower)); \ +}) + +#endif /* RT61PCI_H */ diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c new file mode 100644 index 00000000000..b047c7c0f9e --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -0,0 +1,2124 @@ +/* + Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the + Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + Module: rt73usb + Abstract: rt73usb device specific routines. + Supported chipsets: rt2571W & rt2671. + */ + +/* + * Set enviroment defines for rt2x00.h + */ +#define DRV_NAME "rt73usb" + +#include +#include +#include +#include +#include +#include + +#include "rt2x00.h" +#include "rt2x00usb.h" +#include "rt73usb.h" + +/* + * Register access. + * All access to the CSR registers will go through the methods + * rt73usb_register_read and rt73usb_register_write. + * BBP and RF register require indirect register access, + * and use the CSR registers BBPCSR and RFCSR to achieve this. + * These indirect registers work with busy bits, + * and we will try maximal REGISTER_BUSY_COUNT times to access + * the register while taking a REGISTER_BUSY_DELAY us delay + * between each attampt. When the busy bit is still set at that time, + * the access attempt is considered to have failed, + * and we will print an error. + */ +static inline void rt73usb_register_read(const struct rt2x00_dev *rt2x00dev, + const unsigned int offset, u32 *value) +{ + __le32 reg; + rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ, + USB_VENDOR_REQUEST_IN, offset, + ®, sizeof(u32), REGISTER_TIMEOUT); + *value = le32_to_cpu(reg); +} + +static inline void rt73usb_register_multiread(const struct rt2x00_dev + *rt2x00dev, + const unsigned int offset, + void *value, const u32 length) +{ + int timeout = REGISTER_TIMEOUT * (length / sizeof(u32)); + rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ, + USB_VENDOR_REQUEST_IN, offset, + value, length, timeout); +} + +static inline void rt73usb_register_write(const struct rt2x00_dev *rt2x00dev, + const unsigned int offset, u32 value) +{ + __le32 reg = cpu_to_le32(value); + rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE, + USB_VENDOR_REQUEST_OUT, offset, + ®, sizeof(u32), REGISTER_TIMEOUT); +} + +static inline void rt73usb_register_multiwrite(const struct rt2x00_dev + *rt2x00dev, + const unsigned int offset, + void *value, const u32 length) +{ + int timeout = REGISTER_TIMEOUT * (length / sizeof(u32)); + rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE, + USB_VENDOR_REQUEST_OUT, offset, + value, length, timeout); +} + +static u32 rt73usb_bbp_check(const struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + unsigned int i; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt73usb_register_read(rt2x00dev, PHY_CSR3, ®); + if (!rt2x00_get_field32(reg, PHY_CSR3_BUSY)) + break; + udelay(REGISTER_BUSY_DELAY); + } + + return reg; +} + +static void rt73usb_bbp_write(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, const u8 value) +{ + u32 reg; + + /* + * Wait until the BBP becomes ready. + */ + reg = rt73usb_bbp_check(rt2x00dev); + if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) { + ERROR(rt2x00dev, "PHY_CSR3 register busy. Write failed.\n"); + return; + } + + /* + * Write the data into the BBP. + */ + reg = 0; + rt2x00_set_field32(®, PHY_CSR3_VALUE, value); + rt2x00_set_field32(®, PHY_CSR3_REGNUM, word); + rt2x00_set_field32(®, PHY_CSR3_BUSY, 1); + rt2x00_set_field32(®, PHY_CSR3_READ_CONTROL, 0); + + rt73usb_register_write(rt2x00dev, PHY_CSR3, reg); +} + +static void rt73usb_bbp_read(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, u8 *value) +{ + u32 reg; + + /* + * Wait until the BBP becomes ready. + */ + reg = rt73usb_bbp_check(rt2x00dev); + if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) { + ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n"); + return; + } + + /* + * Write the request into the BBP. + */ + reg = 0; + rt2x00_set_field32(®, PHY_CSR3_REGNUM, word); + rt2x00_set_field32(®, PHY_CSR3_BUSY, 1); + rt2x00_set_field32(®, PHY_CSR3_READ_CONTROL, 1); + + rt73usb_register_write(rt2x00dev, PHY_CSR3, reg); + + /* + * Wait until the BBP becomes ready. + */ + reg = rt73usb_bbp_check(rt2x00dev); + if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) { + ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n"); + *value = 0xff; + return; + } + + *value = rt2x00_get_field32(reg, PHY_CSR3_VALUE); +} + +static void rt73usb_rf_write(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, const u32 value) +{ + u32 reg; + unsigned int i; + + if (!word) + return; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt73usb_register_read(rt2x00dev, PHY_CSR4, ®); + if (!rt2x00_get_field32(reg, PHY_CSR4_BUSY)) + goto rf_write; + udelay(REGISTER_BUSY_DELAY); + } + + ERROR(rt2x00dev, "PHY_CSR4 register busy. Write failed.\n"); + return; + +rf_write: + reg = 0; + rt2x00_set_field32(®, PHY_CSR4_VALUE, value); + + if (rt2x00_rf(&rt2x00dev->chip, RF5225) || + rt2x00_rf(&rt2x00dev->chip, RF2527)) + rt2x00_set_field32(®, PHY_CSR4_NUMBER_OF_BITS, 21); + else + rt2x00_set_field32(®, PHY_CSR4_NUMBER_OF_BITS, 20); + + rt2x00_set_field32(®, PHY_CSR4_IF_SELECT, 0); + rt2x00_set_field32(®, PHY_CSR4_BUSY, 1); + + rt73usb_register_write(rt2x00dev, PHY_CSR4, reg); + rt2x00_rf_write(rt2x00dev, word, value); +} + +#ifdef CONFIG_RT2X00_LIB_DEBUGFS +#define CSR_OFFSET(__word) ( CSR_REG_BASE + ((__word) * sizeof(u32)) ) + +static void rt73usb_read_csr(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, u32 *data) +{ + rt73usb_register_read(rt2x00dev, CSR_OFFSET(word), data); +} + +static void rt73usb_write_csr(const struct rt2x00_dev *rt2x00dev, + const unsigned int word, u32 data) +{ + rt73usb_register_write(rt2x00dev, CSR_OFFSET(word), data); +} + +static const struct rt2x00debug rt73usb_rt2x00debug = { + .owner = THIS_MODULE, + .csr = { + .read = rt73usb_read_csr, + .write = rt73usb_write_csr, + .word_size = sizeof(u32), + .word_count = CSR_REG_SIZE / sizeof(u32), + }, + .eeprom = { + .read = rt2x00_eeprom_read, + .write = rt2x00_eeprom_write, + .word_size = sizeof(u16), + .word_count = EEPROM_SIZE / sizeof(u16), + }, + .bbp = { + .read = rt73usb_bbp_read, + .write = rt73usb_bbp_write, + .word_size = sizeof(u8), + .word_count = BBP_SIZE / sizeof(u8), + }, + .rf = { + .read = rt2x00_rf_read, + .write = rt73usb_rf_write, + .word_size = sizeof(u32), + .word_count = RF_SIZE / sizeof(u32), + }, +}; +#endif /* CONFIG_RT2X00_LIB_DEBUGFS */ + +/* + * Configuration handlers. + */ +static void rt73usb_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *addr) +{ + __le32 reg[2]; + u32 tmp; + + memset(®, 0, sizeof(reg)); + memcpy(®, addr, ETH_ALEN); + + tmp = le32_to_cpu(reg[1]); + rt2x00_set_field32(&tmp, MAC_CSR3_UNICAST_TO_ME_MASK, 0xff); + reg[1] = cpu_to_le32(tmp); + + /* + * The MAC address is passed to us as an array of bytes, + * that array is little endian, so no need for byte ordering. + */ + rt73usb_register_multiwrite(rt2x00dev, MAC_CSR2, ®, sizeof(reg)); +} + +static void rt73usb_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) +{ + __le32 reg[2]; + u32 tmp; + + memset(®, 0, sizeof(reg)); + memcpy(®, bssid, ETH_ALEN); + + tmp = le32_to_cpu(reg[1]); + rt2x00_set_field32(&tmp, MAC_CSR5_BSS_ID_MASK, 3); + reg[1] = cpu_to_le32(tmp); + + /* + * The BSSID is passed to us as an array of bytes, + * that array is little endian, so no need for byte ordering. + */ + rt73usb_register_multiwrite(rt2x00dev, MAC_CSR4, ®, sizeof(reg)); +} + +static void rt73usb_config_packet_filter(struct rt2x00_dev *rt2x00dev, + const unsigned int filter) +{ + int promisc = !!(filter & IFF_PROMISC); + int multicast = !!(filter & IFF_MULTICAST); + int broadcast = !!(filter & IFF_BROADCAST); + u32 reg; + + rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); + rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME, !promisc); + rt2x00_set_field32(®, TXRX_CSR0_DROP_MULTICAST, !multicast); + rt2x00_set_field32(®, TXRX_CSR0_DROP_BORADCAST, !broadcast); + rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg); +} + +static void rt73usb_config_type(struct rt2x00_dev *rt2x00dev, const int type) +{ + u32 reg; + + /* + * Clear current synchronisation setup. + * For the Beacon base registers we only need to clear + * the first byte since that byte contains the VALID and OWNER + * bits which (when set to 0) will invalidate the entire beacon. + */ + rt73usb_register_write(rt2x00dev, TXRX_CSR9, 0); + rt73usb_register_write(rt2x00dev, HW_BEACON_BASE0, 0); + rt73usb_register_write(rt2x00dev, HW_BEACON_BASE1, 0); + rt73usb_register_write(rt2x00dev, HW_BEACON_BASE2, 0); + rt73usb_register_write(rt2x00dev, HW_BEACON_BASE3, 0); + + /* + * Apply hardware packet filter. + */ + rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); + + if (!is_monitor_present(&rt2x00dev->interface) && + (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_STA)) + rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, 1); + else + rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, 0); + + /* + * If there is a non-monitor interface present + * the packet should be strict (even if a monitor interface is present!). + * When there is only 1 interface present which is in monitor mode + * we should start accepting _all_ frames. + */ + if (is_interface_present(&rt2x00dev->interface)) { + rt2x00_set_field32(®, TXRX_CSR0_DROP_CRC, 1); + rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, 1); + rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL, 1); + rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 1); + rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS, 1); + } else if (is_monitor_present(&rt2x00dev->interface)) { + rt2x00_set_field32(®, TXRX_CSR0_DROP_CRC, 0); + rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, 0); + rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL, 0); + rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 0); + rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS, 0); + } + + rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg); + + /* + * Enable synchronisation. + */ + rt73usb_register_read(rt2x00dev, TXRX_CSR9, ®); + if (is_interface_present(&rt2x00dev->interface)) { + rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); + rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); + } + + rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); + if (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_AP) + rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 2); + else if (type == IEEE80211_IF_TYPE_STA) + rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 1); + else if (is_monitor_present(&rt2x00dev->interface) && + !is_interface_present(&rt2x00dev->interface)) + rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 0); + + rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg); +} + +static void rt73usb_config_rate(struct rt2x00_dev *rt2x00dev, const int rate) +{ + struct ieee80211_conf *conf = &rt2x00dev->hw->conf; + u32 reg; + u32 value; + u32 preamble; + + if (DEVICE_GET_RATE_FIELD(rate, PREAMBLE)) + preamble = SHORT_PREAMBLE; + else + preamble = PREAMBLE; + + reg = DEVICE_GET_RATE_FIELD(rate, RATEMASK) & DEV_BASIC_RATEMASK; + + rt73usb_register_write(rt2x00dev, TXRX_CSR5, reg); + + rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); + value = ((conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) ? + SHORT_DIFS : DIFS) + + PLCP + preamble + get_duration(ACK_SIZE, 10); + rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, value); + rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg); + + rt73usb_register_read(rt2x00dev, TXRX_CSR4, ®); + if (preamble == SHORT_PREAMBLE) + rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, 1); + else + rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, 0); + rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg); +} + +static void rt73usb_config_phymode(struct rt2x00_dev *rt2x00dev, + const int phymode) +{ + struct ieee80211_hw_mode *mode; + struct ieee80211_rate *rate; + + if (phymode == MODE_IEEE80211A) + rt2x00dev->curr_hwmode = HWMODE_A; + else if (phymode == MODE_IEEE80211B) + rt2x00dev->curr_hwmode = HWMODE_B; + else + rt2x00dev->curr_hwmode = HWMODE_G; + + mode = &rt2x00dev->hwmodes[rt2x00dev->curr_hwmode]; + rate = &mode->rates[mode->num_rates - 1]; + + rt73usb_config_rate(rt2x00dev, rate->val2); +} + +static void rt73usb_config_lock_channel(struct rt2x00_dev *rt2x00dev, + struct rf_channel *rf, + const int txpower) +{ + u8 r3; + u8 r94; + u8 smart; + + rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); + rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset); + + smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) || + rt2x00_rf(&rt2x00dev->chip, RF2527)); + + rt73usb_bbp_read(rt2x00dev, 3, &r3); + rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart); + rt73usb_bbp_write(rt2x00dev, 3, r3); + + r94 = 6; + if (txpower > MAX_TXPOWER && txpower <= (MAX_TXPOWER + r94)) + r94 += txpower - MAX_TXPOWER; + else if (txpower < MIN_TXPOWER && txpower >= (MIN_TXPOWER - r94)) + r94 += txpower; + rt73usb_bbp_write(rt2x00dev, 94, r94); + + rt73usb_rf_write(rt2x00dev, 1, rf->rf1); + rt73usb_rf_write(rt2x00dev, 2, rf->rf2); + rt73usb_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); + rt73usb_rf_write(rt2x00dev, 4, rf->rf4); + + rt73usb_rf_write(rt2x00dev, 1, rf->rf1); + rt73usb_rf_write(rt2x00dev, 2, rf->rf2); + rt73usb_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004); + rt73usb_rf_write(rt2x00dev, 4, rf->rf4); + + rt73usb_rf_write(rt2x00dev, 1, rf->rf1); + rt73usb_rf_write(rt2x00dev, 2, rf->rf2); + rt73usb_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); + rt73usb_rf_write(rt2x00dev, 4, rf->rf4); + + udelay(10); +} + +static void rt73usb_config_channel(struct rt2x00_dev *rt2x00dev, + const int index, const int channel, + const int txpower) +{ + struct rf_channel rf; + + /* + * Fill rf_reg structure. + */ + memcpy(&rf, &rt2x00dev->spec.channels[index], sizeof(rf)); + + rt73usb_config_lock_channel(rt2x00dev, &rf, txpower); +} + +static void rt73usb_config_txpower(struct rt2x00_dev *rt2x00dev, + const int txpower) +{ + struct rf_channel rf; + + rt2x00_rf_read(rt2x00dev, 1, &rf.rf1); + rt2x00_rf_read(rt2x00dev, 2, &rf.rf2); + rt2x00_rf_read(rt2x00dev, 3, &rf.rf3); + rt2x00_rf_read(rt2x00dev, 4, &rf.rf4); + + rt73usb_config_lock_channel(rt2x00dev, &rf, txpower); +} + +static void rt73usb_config_antenna_5x(struct rt2x00_dev *rt2x00dev, + const int antenna_tx, + const int antenna_rx) +{ + u8 r3; + u8 r4; + u8 r77; + + rt73usb_bbp_read(rt2x00dev, 3, &r3); + rt73usb_bbp_read(rt2x00dev, 4, &r4); + rt73usb_bbp_read(rt2x00dev, 77, &r77); + + rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, 0); + + switch (antenna_rx) { + case ANTENNA_SW_DIVERSITY: + case ANTENNA_HW_DIVERSITY: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2); + rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, + !!(rt2x00dev->curr_hwmode != HWMODE_A)); + break; + case ANTENNA_A: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); + rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0); + + if (rt2x00dev->curr_hwmode == HWMODE_A) + rt2x00_set_field8(&r77, BBP_R77_PAIR, 0); + else + rt2x00_set_field8(&r77, BBP_R77_PAIR, 3); + break; + case ANTENNA_B: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); + rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0); + + if (rt2x00dev->curr_hwmode == HWMODE_A) + rt2x00_set_field8(&r77, BBP_R77_PAIR, 3); + else + rt2x00_set_field8(&r77, BBP_R77_PAIR, 0); + break; + } + + rt73usb_bbp_write(rt2x00dev, 77, r77); + rt73usb_bbp_write(rt2x00dev, 3, r3); + rt73usb_bbp_write(rt2x00dev, 4, r4); +} + +static void rt73usb_config_antenna_2x(struct rt2x00_dev *rt2x00dev, + const int antenna_tx, + const int antenna_rx) +{ + u8 r3; + u8 r4; + u8 r77; + + rt73usb_bbp_read(rt2x00dev, 3, &r3); + rt73usb_bbp_read(rt2x00dev, 4, &r4); + rt73usb_bbp_read(rt2x00dev, 77, &r77); + + rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, 0); + rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, + !test_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags)); + + switch (antenna_rx) { + case ANTENNA_SW_DIVERSITY: + case ANTENNA_HW_DIVERSITY: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2); + break; + case ANTENNA_A: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); + rt2x00_set_field8(&r77, BBP_R77_PAIR, 3); + break; + case ANTENNA_B: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); + rt2x00_set_field8(&r77, BBP_R77_PAIR, 0); + break; + } + + rt73usb_bbp_write(rt2x00dev, 77, r77); + rt73usb_bbp_write(rt2x00dev, 3, r3); + rt73usb_bbp_write(rt2x00dev, 4, r4); +} + +struct antenna_sel { + u8 word; + /* + * value[0] -> non-LNA + * value[1] -> LNA + */ + u8 value[2]; +}; + +static const struct antenna_sel antenna_sel_a[] = { + { 96, { 0x58, 0x78 } }, + { 104, { 0x38, 0x48 } }, + { 75, { 0xfe, 0x80 } }, + { 86, { 0xfe, 0x80 } }, + { 88, { 0xfe, 0x80 } }, + { 35, { 0x60, 0x60 } }, + { 97, { 0x58, 0x58 } }, + { 98, { 0x58, 0x58 } }, +}; + +static const struct antenna_sel antenna_sel_bg[] = { + { 96, { 0x48, 0x68 } }, + { 104, { 0x2c, 0x3c } }, + { 75, { 0xfe, 0x80 } }, + { 86, { 0xfe, 0x80 } }, + { 88, { 0xfe, 0x80 } }, + { 35, { 0x50, 0x50 } }, + { 97, { 0x48, 0x48 } }, + { 98, { 0x48, 0x48 } }, +}; + +static void rt73usb_config_antenna(struct rt2x00_dev *rt2x00dev, + const int antenna_tx, const int antenna_rx) +{ + const struct antenna_sel *sel; + unsigned int lna; + unsigned int i; + u32 reg; + + rt73usb_register_read(rt2x00dev, PHY_CSR0, ®); + + if (rt2x00dev->curr_hwmode == HWMODE_A) { + sel = antenna_sel_a; + lna = test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags); + + rt2x00_set_field32(®, PHY_CSR0_PA_PE_BG, 0); + rt2x00_set_field32(®, PHY_CSR0_PA_PE_A, 1); + } else { + sel = antenna_sel_bg; + lna = test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags); + + rt2x00_set_field32(®, PHY_CSR0_PA_PE_BG, 1); + rt2x00_set_field32(®, PHY_CSR0_PA_PE_A, 0); + } + + for (i = 0; i < ARRAY_SIZE(antenna_sel_a); i++) + rt73usb_bbp_write(rt2x00dev, sel[i].word, sel[i].value[lna]); + + rt73usb_register_write(rt2x00dev, PHY_CSR0, reg); + + if (rt2x00_rf(&rt2x00dev->chip, RF5226) || + rt2x00_rf(&rt2x00dev->chip, RF5225)) + rt73usb_config_antenna_5x(rt2x00dev, antenna_tx, antenna_rx); + else if (rt2x00_rf(&rt2x00dev->chip, RF2528) || + rt2x00_rf(&rt2x00dev->chip, RF2527)) + rt73usb_config_antenna_2x(rt2x00dev, antenna_tx, antenna_rx); +} + +static void rt73usb_config_duration(struct rt2x00_dev *rt2x00dev, + const int short_slot_time, + const int beacon_int) +{ + u32 reg; + + rt73usb_register_read(rt2x00dev, MAC_CSR9, ®); + rt2x00_set_field32(®, MAC_CSR9_SLOT_TIME, + short_slot_time ? SHORT_SLOT_TIME : SLOT_TIME); + rt73usb_register_write(rt2x00dev, MAC_CSR9, reg); + + rt73usb_register_read(rt2x00dev, MAC_CSR8, ®); + rt2x00_set_field32(®, MAC_CSR8_SIFS, SIFS); + rt2x00_set_field32(®, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3); + rt2x00_set_field32(®, MAC_CSR8_EIFS, EIFS); + rt73usb_register_write(rt2x00dev, MAC_CSR8, reg); + + rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); + rt2x00_set_field32(®, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER); + rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg); + + rt73usb_register_read(rt2x00dev, TXRX_CSR4, ®); + rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_ENABLE, 1); + rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg); + + rt73usb_register_read(rt2x00dev, TXRX_CSR9, ®); + rt2x00_set_field32(®, TXRX_CSR9_BEACON_INTERVAL, beacon_int * 16); + rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg); +} + +static void rt73usb_config(struct rt2x00_dev *rt2x00dev, + const unsigned int flags, + struct ieee80211_conf *conf) +{ + int short_slot_time = conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME; + + if (flags & CONFIG_UPDATE_PHYMODE) + rt73usb_config_phymode(rt2x00dev, conf->phymode); + if (flags & CONFIG_UPDATE_CHANNEL) + rt73usb_config_channel(rt2x00dev, conf->channel_val, + conf->channel, conf->power_level); + if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL)) + rt73usb_config_txpower(rt2x00dev, conf->power_level); + if (flags & CONFIG_UPDATE_ANTENNA) + rt73usb_config_antenna(rt2x00dev, conf->antenna_sel_tx, + conf->antenna_sel_rx); + if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT)) + rt73usb_config_duration(rt2x00dev, short_slot_time, + conf->beacon_int); +} + +/* + * LED functions. + */ +static void rt73usb_enable_led(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + rt73usb_register_read(rt2x00dev, MAC_CSR14, ®); + rt2x00_set_field32(®, MAC_CSR14_ON_PERIOD, 70); + rt2x00_set_field32(®, MAC_CSR14_OFF_PERIOD, 30); + rt73usb_register_write(rt2x00dev, MAC_CSR14, reg); + + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_RADIO_STATUS, 1); + if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A) + rt2x00_set_field16(&rt2x00dev->led_reg, + MCU_LEDCS_LINK_A_STATUS, 1); + else + rt2x00_set_field16(&rt2x00dev->led_reg, + MCU_LEDCS_LINK_BG_STATUS, 1); + + rt2x00usb_vendor_request_sw(rt2x00dev, USB_LED_CONTROL, 0x0000, + rt2x00dev->led_reg, REGISTER_TIMEOUT); +} + +static void rt73usb_disable_led(struct rt2x00_dev *rt2x00dev) +{ + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_RADIO_STATUS, 0); + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LINK_BG_STATUS, 0); + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LINK_A_STATUS, 0); + + rt2x00usb_vendor_request_sw(rt2x00dev, USB_LED_CONTROL, 0x0000, + rt2x00dev->led_reg, REGISTER_TIMEOUT); +} + +static void rt73usb_activity_led(struct rt2x00_dev *rt2x00dev, int rssi) +{ + u32 led; + + if (rt2x00dev->led_mode != LED_MODE_SIGNAL_STRENGTH) + return; + + /* + * Led handling requires a positive value for the rssi, + * to do that correctly we need to add the correction. + */ + rssi += rt2x00dev->rssi_offset; + + if (rssi <= 30) + led = 0; + else if (rssi <= 39) + led = 1; + else if (rssi <= 49) + led = 2; + else if (rssi <= 53) + led = 3; + else if (rssi <= 63) + led = 4; + else + led = 5; + + rt2x00usb_vendor_request_sw(rt2x00dev, USB_LED_CONTROL, led, + rt2x00dev->led_reg, REGISTER_TIMEOUT); +} + +/* + * Link tuning + */ +static void rt73usb_link_stats(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + /* + * Update FCS error count from register. + */ + rt73usb_register_read(rt2x00dev, STA_CSR0, ®); + rt2x00dev->link.rx_failed = rt2x00_get_field32(reg, STA_CSR0_FCS_ERROR); + + /* + * Update False CCA count from register. + */ + rt73usb_register_read(rt2x00dev, STA_CSR1, ®); + reg = rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR); + rt2x00dev->link.false_cca = + rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR); +} + +static void rt73usb_reset_tuner(struct rt2x00_dev *rt2x00dev) +{ + rt73usb_bbp_write(rt2x00dev, 17, 0x20); + rt2x00dev->link.vgc_level = 0x20; +} + +static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev) +{ + int rssi = rt2x00_get_link_rssi(&rt2x00dev->link); + u8 r17; + u8 up_bound; + u8 low_bound; + + /* + * Update Led strength + */ + rt73usb_activity_led(rt2x00dev, rssi); + + rt73usb_bbp_read(rt2x00dev, 17, &r17); + + /* + * Determine r17 bounds. + */ + if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A) { + low_bound = 0x28; + up_bound = 0x48; + + if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) { + low_bound += 0x10; + up_bound += 0x10; + } + } else { + if (rssi > -82) { + low_bound = 0x1c; + up_bound = 0x40; + } else if (rssi > -84) { + low_bound = 0x1c; + up_bound = 0x20; + } else { + low_bound = 0x1c; + up_bound = 0x1c; + } + + if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) { + low_bound += 0x14; + up_bound += 0x10; + } + } + + /* + * Special big-R17 for very short distance + */ + if (rssi > -35) { + if (r17 != 0x60) + rt73usb_bbp_write(rt2x00dev, 17, 0x60); + return; + } + + /* + * Special big-R17 for short distance + */ + if (rssi >= -58) { + if (r17 != up_bound) + rt73usb_bbp_write(rt2x00dev, 17, up_bound); + return; + } + + /* + * Special big-R17 for middle-short distance + */ + if (rssi >= -66) { + low_bound += 0x10; + if (r17 != low_bound) + rt73usb_bbp_write(rt2x00dev, 17, low_bound); + return; + } + + /* + * Special mid-R17 for middle distance + */ + if (rssi >= -74) { + if (r17 != (low_bound + 0x10)) + rt73usb_bbp_write(rt2x00dev, 17, low_bound + 0x08); + return; + } + + /* + * Special case: Change up_bound based on the rssi. + * Lower up_bound when rssi is weaker then -74 dBm. + */ + up_bound -= 2 * (-74 - rssi); + if (low_bound > up_bound) + up_bound = low_bound; + + if (r17 > up_bound) { + rt73usb_bbp_write(rt2x00dev, 17, up_bound); + return; + } + + /* + * r17 does not yet exceed upper limit, continue and base + * the r17 tuning on the false CCA count. + */ + if (rt2x00dev->link.false_cca > 512 && r17 < up_bound) { + r17 += 4; + if (r17 > up_bound) + r17 = up_bound; + rt73usb_bbp_write(rt2x00dev, 17, r17); + } else if (rt2x00dev->link.false_cca < 100 && r17 > low_bound) { + r17 -= 4; + if (r17 < low_bound) + r17 = low_bound; + rt73usb_bbp_write(rt2x00dev, 17, r17); + } +} + +/* + * Firmware name function. + */ +static char *rt73usb_get_firmware_name(struct rt2x00_dev *rt2x00dev) +{ + return FIRMWARE_RT2571; +} + +/* + * Initialization functions. + */ +static int rt73usb_load_firmware(struct rt2x00_dev *rt2x00dev, void *data, + const size_t len) +{ + unsigned int i; + int status; + u32 reg; + char *ptr = data; + char *cache; + int buflen; + int timeout; + + /* + * Wait for stable hardware. + */ + for (i = 0; i < 100; i++) { + rt73usb_register_read(rt2x00dev, MAC_CSR0, ®); + if (reg) + break; + msleep(1); + } + + if (!reg) { + ERROR(rt2x00dev, "Unstable hardware.\n"); + return -EBUSY; + } + + /* + * Write firmware to device. + * We setup a seperate cache for this action, + * since we are going to write larger chunks of data + * then normally used cache size. + */ + cache = kmalloc(CSR_CACHE_SIZE_FIRMWARE, GFP_KERNEL); + if (!cache) { + ERROR(rt2x00dev, "Failed to allocate firmware cache.\n"); + return -ENOMEM; + } + + for (i = 0; i < len; i += CSR_CACHE_SIZE_FIRMWARE) { + buflen = min_t(int, len - i, CSR_CACHE_SIZE_FIRMWARE); + timeout = REGISTER_TIMEOUT * (buflen / sizeof(u32)); + + memcpy(cache, ptr, buflen); + + rt2x00usb_vendor_request(rt2x00dev, USB_MULTI_WRITE, + USB_VENDOR_REQUEST_OUT, + FIRMWARE_IMAGE_BASE + i, 0x0000, + cache, buflen, timeout); + + ptr += buflen; + } + + kfree(cache); + + /* + * Send firmware request to device to load firmware, + * we need to specify a long timeout time. + */ + status = rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, + 0x0000, USB_MODE_FIRMWARE, + REGISTER_TIMEOUT_FIRMWARE); + if (status < 0) { + ERROR(rt2x00dev, "Failed to write Firmware to device.\n"); + return status; + } + + rt73usb_disable_led(rt2x00dev); + + return 0; +} + +static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); + rt2x00_set_field32(®, TXRX_CSR0_AUTO_TX_SEQ, 1); + rt2x00_set_field32(®, TXRX_CSR0_DISABLE_RX, 0); + rt2x00_set_field32(®, TXRX_CSR0_TX_WITHOUT_WAITING, 0); + rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg); + + rt73usb_register_read(rt2x00dev, TXRX_CSR1, ®); + rt2x00_set_field32(®, TXRX_CSR1_BBP_ID0, 47); /* CCK Signal */ + rt2x00_set_field32(®, TXRX_CSR1_BBP_ID0_VALID, 1); + rt2x00_set_field32(®, TXRX_CSR1_BBP_ID1, 30); /* Rssi */ + rt2x00_set_field32(®, TXRX_CSR1_BBP_ID1_VALID, 1); + rt2x00_set_field32(®, TXRX_CSR1_BBP_ID2, 42); /* OFDM Rate */ + rt2x00_set_field32(®, TXRX_CSR1_BBP_ID2_VALID, 1); + rt2x00_set_field32(®, TXRX_CSR1_BBP_ID3, 30); /* Rssi */ + rt2x00_set_field32(®, TXRX_CSR1_BBP_ID3_VALID, 1); + rt73usb_register_write(rt2x00dev, TXRX_CSR1, reg); + + /* + * CCK TXD BBP registers + */ + rt73usb_register_read(rt2x00dev, TXRX_CSR2, ®); + rt2x00_set_field32(®, TXRX_CSR2_BBP_ID0, 13); + rt2x00_set_field32(®, TXRX_CSR2_BBP_ID0_VALID, 1); + rt2x00_set_field32(®, TXRX_CSR2_BBP_ID1, 12); + rt2x00_set_field32(®, TXRX_CSR2_BBP_ID1_VALID, 1); + rt2x00_set_field32(®, TXRX_CSR2_BBP_ID2, 11); + rt2x00_set_field32(®, TXRX_CSR2_BBP_ID2_VALID, 1); + rt2x00_set_field32(®, TXRX_CSR2_BBP_ID3, 10); + rt2x00_set_field32(®, TXRX_CSR2_BBP_ID3_VALID, 1); + rt73usb_register_write(rt2x00dev, TXRX_CSR2, reg); + + /* + * OFDM TXD BBP registers + */ + rt73usb_register_read(rt2x00dev, TXRX_CSR3, ®); + rt2x00_set_field32(®, TXRX_CSR3_BBP_ID0, 7); + rt2x00_set_field32(®, TXRX_CSR3_BBP_ID0_VALID, 1); + rt2x00_set_field32(®, TXRX_CSR3_BBP_ID1, 6); + rt2x00_set_field32(®, TXRX_CSR3_BBP_ID1_VALID, 1); + rt2x00_set_field32(®, TXRX_CSR3_BBP_ID2, 5); + rt2x00_set_field32(®, TXRX_CSR3_BBP_ID2_VALID, 1); + rt73usb_register_write(rt2x00dev, TXRX_CSR3, reg); + + rt73usb_register_read(rt2x00dev, TXRX_CSR7, ®); + rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_6MBS, 59); + rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_9MBS, 53); + rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_12MBS, 49); + rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_18MBS, 46); + rt73usb_register_write(rt2x00dev, TXRX_CSR7, reg); + + rt73usb_register_read(rt2x00dev, TXRX_CSR8, ®); + rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_24MBS, 44); + rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_36MBS, 42); + rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_48MBS, 42); + rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_54MBS, 42); + rt73usb_register_write(rt2x00dev, TXRX_CSR8, reg); + + rt73usb_register_write(rt2x00dev, TXRX_CSR15, 0x0000000f); + + rt73usb_register_read(rt2x00dev, MAC_CSR6, ®); + rt2x00_set_field32(®, MAC_CSR6_MAX_FRAME_UNIT, 0xfff); + rt73usb_register_write(rt2x00dev, MAC_CSR6, reg); + + rt73usb_register_write(rt2x00dev, MAC_CSR10, 0x00000718); + + if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE)) + return -EBUSY; + + rt73usb_register_write(rt2x00dev, MAC_CSR13, 0x00007f00); + + /* + * Invalidate all Shared Keys (SEC_CSR0), + * and clear the Shared key Cipher algorithms (SEC_CSR1 & SEC_CSR5) + */ + rt73usb_register_write(rt2x00dev, SEC_CSR0, 0x00000000); + rt73usb_register_write(rt2x00dev, SEC_CSR1, 0x00000000); + rt73usb_register_write(rt2x00dev, SEC_CSR5, 0x00000000); + + reg = 0x000023b0; + if (rt2x00_rf(&rt2x00dev->chip, RF5225) || + rt2x00_rf(&rt2x00dev->chip, RF2527)) + rt2x00_set_field32(®, PHY_CSR1_RF_RPI, 1); + rt73usb_register_write(rt2x00dev, PHY_CSR1, reg); + + rt73usb_register_write(rt2x00dev, PHY_CSR5, 0x00040a06); + rt73usb_register_write(rt2x00dev, PHY_CSR6, 0x00080606); + rt73usb_register_write(rt2x00dev, PHY_CSR7, 0x00000408); + + rt73usb_register_read(rt2x00dev, AC_TXOP_CSR0, ®); + rt2x00_set_field32(®, AC_TXOP_CSR0_AC0_TX_OP, 0); + rt2x00_set_field32(®, AC_TXOP_CSR0_AC1_TX_OP, 0); + rt73usb_register_write(rt2x00dev, AC_TXOP_CSR0, reg); + + rt73usb_register_read(rt2x00dev, AC_TXOP_CSR1, ®); + rt2x00_set_field32(®, AC_TXOP_CSR1_AC2_TX_OP, 192); + rt2x00_set_field32(®, AC_TXOP_CSR1_AC3_TX_OP, 48); + rt73usb_register_write(rt2x00dev, AC_TXOP_CSR1, reg); + + rt73usb_register_read(rt2x00dev, MAC_CSR9, ®); + rt2x00_set_field32(®, MAC_CSR9_CW_SELECT, 0); + rt73usb_register_write(rt2x00dev, MAC_CSR9, reg); + + /* + * We must clear the error counters. + * These registers are cleared on read, + * so we may pass a useless variable to store the value. + */ + rt73usb_register_read(rt2x00dev, STA_CSR0, ®); + rt73usb_register_read(rt2x00dev, STA_CSR1, ®); + rt73usb_register_read(rt2x00dev, STA_CSR2, ®); + + /* + * Reset MAC and BBP registers. + */ + rt73usb_register_read(rt2x00dev, MAC_CSR1, ®); + rt2x00_set_field32(®, MAC_CSR1_SOFT_RESET, 1); + rt2x00_set_field32(®, MAC_CSR1_BBP_RESET, 1); + rt73usb_register_write(rt2x00dev, MAC_CSR1, reg); + + rt73usb_register_read(rt2x00dev, MAC_CSR1, ®); + rt2x00_set_field32(®, MAC_CSR1_SOFT_RESET, 0); + rt2x00_set_field32(®, MAC_CSR1_BBP_RESET, 0); + rt73usb_register_write(rt2x00dev, MAC_CSR1, reg); + + rt73usb_register_read(rt2x00dev, MAC_CSR1, ®); + rt2x00_set_field32(®, MAC_CSR1_HOST_READY, 1); + rt73usb_register_write(rt2x00dev, MAC_CSR1, reg); + + return 0; +} + +static int rt73usb_init_bbp(struct rt2x00_dev *rt2x00dev) +{ + unsigned int i; + u16 eeprom; + u8 reg_id; + u8 value; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt73usb_bbp_read(rt2x00dev, 0, &value); + if ((value != 0xff) && (value != 0x00)) + goto continue_csr_init; + NOTICE(rt2x00dev, "Waiting for BBP register.\n"); + udelay(REGISTER_BUSY_DELAY); + } + + ERROR(rt2x00dev, "BBP register access failed, aborting.\n"); + return -EACCES; + +continue_csr_init: + rt73usb_bbp_write(rt2x00dev, 3, 0x80); + rt73usb_bbp_write(rt2x00dev, 15, 0x30); + rt73usb_bbp_write(rt2x00dev, 21, 0xc8); + rt73usb_bbp_write(rt2x00dev, 22, 0x38); + rt73usb_bbp_write(rt2x00dev, 23, 0x06); + rt73usb_bbp_write(rt2x00dev, 24, 0xfe); + rt73usb_bbp_write(rt2x00dev, 25, 0x0a); + rt73usb_bbp_write(rt2x00dev, 26, 0x0d); + rt73usb_bbp_write(rt2x00dev, 32, 0x0b); + rt73usb_bbp_write(rt2x00dev, 34, 0x12); + rt73usb_bbp_write(rt2x00dev, 37, 0x07); + rt73usb_bbp_write(rt2x00dev, 39, 0xf8); + rt73usb_bbp_write(rt2x00dev, 41, 0x60); + rt73usb_bbp_write(rt2x00dev, 53, 0x10); + rt73usb_bbp_write(rt2x00dev, 54, 0x18); + rt73usb_bbp_write(rt2x00dev, 60, 0x10); + rt73usb_bbp_write(rt2x00dev, 61, 0x04); + rt73usb_bbp_write(rt2x00dev, 62, 0x04); + rt73usb_bbp_write(rt2x00dev, 75, 0xfe); + rt73usb_bbp_write(rt2x00dev, 86, 0xfe); + rt73usb_bbp_write(rt2x00dev, 88, 0xfe); + rt73usb_bbp_write(rt2x00dev, 90, 0x0f); + rt73usb_bbp_write(rt2x00dev, 99, 0x00); + rt73usb_bbp_write(rt2x00dev, 102, 0x16); + rt73usb_bbp_write(rt2x00dev, 107, 0x04); + + DEBUG(rt2x00dev, "Start initialization from EEPROM...\n"); + for (i = 0; i < EEPROM_BBP_SIZE; i++) { + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom); + + if (eeprom != 0xffff && eeprom != 0x0000) { + reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID); + value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE); + DEBUG(rt2x00dev, "BBP: 0x%02x, value: 0x%02x.\n", + reg_id, value); + rt73usb_bbp_write(rt2x00dev, reg_id, value); + } + } + DEBUG(rt2x00dev, "...End initialization from EEPROM.\n"); + + return 0; +} + +/* + * Device state switch handlers. + */ +static void rt73usb_toggle_rx(struct rt2x00_dev *rt2x00dev, + enum dev_state state) +{ + u32 reg; + + rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); + rt2x00_set_field32(®, TXRX_CSR0_DISABLE_RX, + state == STATE_RADIO_RX_OFF); + rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg); +} + +static int rt73usb_enable_radio(struct rt2x00_dev *rt2x00dev) +{ + /* + * Initialize all registers. + */ + if (rt73usb_init_registers(rt2x00dev) || + rt73usb_init_bbp(rt2x00dev)) { + ERROR(rt2x00dev, "Register initialization failed.\n"); + return -EIO; + } + + rt2x00usb_enable_radio(rt2x00dev); + + /* + * Enable LED + */ + rt73usb_enable_led(rt2x00dev); + + return 0; +} + +static void rt73usb_disable_radio(struct rt2x00_dev *rt2x00dev) +{ + /* + * Disable LED + */ + rt73usb_disable_led(rt2x00dev); + + rt73usb_register_write(rt2x00dev, MAC_CSR10, 0x00001818); + + /* + * Disable synchronisation. + */ + rt73usb_register_write(rt2x00dev, TXRX_CSR9, 0); + + rt2x00usb_disable_radio(rt2x00dev); +} + +static int rt73usb_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state) +{ + u32 reg; + unsigned int i; + char put_to_sleep; + char current_state; + + put_to_sleep = (state != STATE_AWAKE); + + rt73usb_register_read(rt2x00dev, MAC_CSR12, ®); + rt2x00_set_field32(®, MAC_CSR12_FORCE_WAKEUP, !put_to_sleep); + rt2x00_set_field32(®, MAC_CSR12_PUT_TO_SLEEP, put_to_sleep); + rt73usb_register_write(rt2x00dev, MAC_CSR12, reg); + + /* + * Device is not guaranteed to be in the requested state yet. + * We must wait until the register indicates that the + * device has entered the correct state. + */ + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt73usb_register_read(rt2x00dev, MAC_CSR12, ®); + current_state = + rt2x00_get_field32(reg, MAC_CSR12_BBP_CURRENT_STATE); + if (current_state == !put_to_sleep) + return 0; + msleep(10); + } + + NOTICE(rt2x00dev, "Device failed to enter state %d, " + "current device state %d.\n", !put_to_sleep, current_state); + + return -EBUSY; +} + +static int rt73usb_set_device_state(struct rt2x00_dev *rt2x00dev, + enum dev_state state) +{ + int retval = 0; + + switch (state) { + case STATE_RADIO_ON: + retval = rt73usb_enable_radio(rt2x00dev); + break; + case STATE_RADIO_OFF: + rt73usb_disable_radio(rt2x00dev); + break; + case STATE_RADIO_RX_ON: + case STATE_RADIO_RX_OFF: + rt73usb_toggle_rx(rt2x00dev, state); + break; + case STATE_DEEP_SLEEP: + case STATE_SLEEP: + case STATE_STANDBY: + case STATE_AWAKE: + retval = rt73usb_set_state(rt2x00dev, state); + break; + default: + retval = -ENOTSUPP; + break; + } + + return retval; +} + +/* + * TX descriptor initialization + */ +static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, + struct data_desc *txd, + struct data_entry_desc *desc, + struct ieee80211_hdr *ieee80211hdr, + unsigned int length, + struct ieee80211_tx_control *control) +{ + u32 word; + + /* + * Start writing the descriptor words. + */ + rt2x00_desc_read(txd, 1, &word); + rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, desc->queue); + rt2x00_set_field32(&word, TXD_W1_AIFSN, desc->aifs); + rt2x00_set_field32(&word, TXD_W1_CWMIN, desc->cw_min); + rt2x00_set_field32(&word, TXD_W1_CWMAX, desc->cw_max); + rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER); + rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE, 1); + rt2x00_desc_write(txd, 1, word); + + rt2x00_desc_read(txd, 2, &word); + rt2x00_set_field32(&word, TXD_W2_PLCP_SIGNAL, desc->signal); + rt2x00_set_field32(&word, TXD_W2_PLCP_SERVICE, desc->service); + rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_LOW, desc->length_low); + rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, desc->length_high); + rt2x00_desc_write(txd, 2, word); + + rt2x00_desc_read(txd, 5, &word); + rt2x00_set_field32(&word, TXD_W5_TX_POWER, + TXPOWER_TO_DEV(control->power_level)); + rt2x00_set_field32(&word, TXD_W5_WAITING_DMA_DONE_INT, 1); + rt2x00_desc_write(txd, 5, word); + + rt2x00_desc_read(txd, 0, &word); + rt2x00_set_field32(&word, TXD_W0_BURST, + test_bit(ENTRY_TXD_BURST, &desc->flags)); + rt2x00_set_field32(&word, TXD_W0_VALID, 1); + rt2x00_set_field32(&word, TXD_W0_MORE_FRAG, + test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags)); + rt2x00_set_field32(&word, TXD_W0_ACK, + !(control->flags & IEEE80211_TXCTL_NO_ACK)); + rt2x00_set_field32(&word, TXD_W0_TIMESTAMP, + test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags)); + rt2x00_set_field32(&word, TXD_W0_OFDM, + test_bit(ENTRY_TXD_OFDM_RATE, &desc->flags)); + rt2x00_set_field32(&word, TXD_W0_IFS, desc->ifs); + rt2x00_set_field32(&word, TXD_W0_RETRY_MODE, + !!(control->flags & + IEEE80211_TXCTL_LONG_RETRY_LIMIT)); + rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, 0); + rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, length); + rt2x00_set_field32(&word, TXD_W0_BURST2, + test_bit(ENTRY_TXD_BURST, &desc->flags)); + rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE); + rt2x00_desc_write(txd, 0, word); +} + +/* + * TX data initialization + */ +static void rt73usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, + unsigned int queue) +{ + u32 reg; + + if (queue != IEEE80211_TX_QUEUE_BEACON) + return; + + /* + * For Wi-Fi faily generated beacons between participating stations. + * Set TBTT phase adaptive adjustment step to 8us (default 16us) + */ + rt73usb_register_write(rt2x00dev, TXRX_CSR10, 0x00001008); + + rt73usb_register_read(rt2x00dev, TXRX_CSR9, ®); + if (!rt2x00_get_field32(reg, TXRX_CSR9_BEACON_GEN)) { + rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 1); + rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg); + } +} + +/* + * RX control handlers + */ +static int rt73usb_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1) +{ + u16 eeprom; + u8 offset; + u8 lna; + + lna = rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_LNA); + switch (lna) { + case 3: + offset = 90; + break; + case 2: + offset = 74; + break; + case 1: + offset = 64; + break; + default: + return 0; + } + + if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A) { + if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) { + if (lna == 3 || lna == 2) + offset += 10; + } else { + if (lna == 3) + offset += 6; + else if (lna == 2) + offset += 8; + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom); + offset -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1); + } else { + if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) + offset += 14; + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom); + offset -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1); + } + + return rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_AGC) * 2 - offset; +} + +static int rt73usb_fill_rxdone(struct data_entry *entry, + int *signal, int *rssi, int *ofdm, int *size) +{ + struct data_desc *rxd = (struct data_desc *)entry->skb->data; + u32 word0; + u32 word1; + + rt2x00_desc_read(rxd, 0, &word0); + rt2x00_desc_read(rxd, 1, &word1); + + if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR) || + rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR)) + return -EINVAL; + + /* + * Obtain the status about this packet. + */ + *signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL); + *rssi = rt73usb_agc_to_rssi(entry->ring->rt2x00dev, word1); + *ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); + *size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); + + /* + * Pull the skb to clear the descriptor area. + */ + skb_pull(entry->skb, entry->ring->desc_size); + + return 0; +} + +/* + * Device probe functions. + */ +static int rt73usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) +{ + u16 word; + u8 *mac; + s8 value; + + rt2x00usb_eeprom_read(rt2x00dev, rt2x00dev->eeprom, EEPROM_SIZE); + + /* + * Start validation of the data that has been read. + */ + mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); + if (!is_valid_ether_addr(mac)) { + random_ether_addr(mac); + EEPROM(rt2x00dev, "MAC: " MAC_FMT "\n", MAC_ARG(mac)); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2); + rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, 2); + rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT, 2); + rt2x00_set_field16(&word, EEPROM_ANTENNA_FRAME_TYPE, 0); + rt2x00_set_field16(&word, EEPROM_ANTENNA_DYN_TXAGC, 0); + rt2x00_set_field16(&word, EEPROM_ANTENNA_HARDWARE_RADIO, 0); + rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF5226); + rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word); + EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word); + EEPROM(rt2x00dev, "NIC: 0x%04x\n", word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_LED, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_LED_POLARITY_RDY_G, 0); + rt2x00_set_field16(&word, EEPROM_LED_POLARITY_RDY_A, 0); + rt2x00_set_field16(&word, EEPROM_LED_POLARITY_ACT, 0); + rt2x00_set_field16(&word, EEPROM_LED_POLARITY_GPIO_0, 0); + rt2x00_set_field16(&word, EEPROM_LED_POLARITY_GPIO_1, 0); + rt2x00_set_field16(&word, EEPROM_LED_POLARITY_GPIO_2, 0); + rt2x00_set_field16(&word, EEPROM_LED_POLARITY_GPIO_3, 0); + rt2x00_set_field16(&word, EEPROM_LED_POLARITY_GPIO_4, 0); + rt2x00_set_field16(&word, EEPROM_LED_LED_MODE, + LED_MODE_DEFAULT); + rt2x00_eeprom_write(rt2x00dev, EEPROM_LED, word); + EEPROM(rt2x00dev, "Led: 0x%04x\n", word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_FREQ_OFFSET, 0); + rt2x00_set_field16(&word, EEPROM_FREQ_SEQ, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_FREQ, word); + EEPROM(rt2x00dev, "Freq: 0x%04x\n", word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_1, 0); + rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_2, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_BG, word); + EEPROM(rt2x00dev, "RSSI OFFSET BG: 0x%04x\n", word); + } else { + value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_BG_1); + if (value < -10 || value > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_1, 0); + value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_BG_2); + if (value < -10 || value > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_2, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_BG, word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_1, 0); + rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_2, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_A, word); + EEPROM(rt2x00dev, "RSSI OFFSET BG: 0x%04x\n", word); + } else { + value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_A_1); + if (value < -10 || value > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_1, 0); + value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_A_2); + if (value < -10 || value > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_2, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_A, word); + } + + return 0; +} + +static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + u16 value; + u16 eeprom; + + /* + * Read EEPROM word for configuration. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); + + /* + * Identify RF chipset. + */ + value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); + rt73usb_register_read(rt2x00dev, MAC_CSR0, ®); + rt2x00_set_chip(rt2x00dev, RT2571, value, reg); + + if (!rt2x00_rev(&rt2x00dev->chip, 0x25730)) { + ERROR(rt2x00dev, "Invalid RT chipset detected.\n"); + return -ENODEV; + } + + if (!rt2x00_rf(&rt2x00dev->chip, RF5226) && + !rt2x00_rf(&rt2x00dev->chip, RF2528) && + !rt2x00_rf(&rt2x00dev->chip, RF5225) && + !rt2x00_rf(&rt2x00dev->chip, RF2527)) { + ERROR(rt2x00dev, "Invalid RF chipset detected.\n"); + return -ENODEV; + } + + /* + * Identify default antenna configuration. + */ + rt2x00dev->hw->conf.antenna_sel_tx = + rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TX_DEFAULT); + rt2x00dev->hw->conf.antenna_sel_rx = + rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT); + + /* + * Read the Frame type. + */ + if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_FRAME_TYPE)) + __set_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags); + + /* + * Read frequency offset. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom); + rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET); + + /* + * Read external LNA informations. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom); + + if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA)) { + __set_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags); + __set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags); + } + + /* + * Store led settings, for correct led behaviour. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_LED, &eeprom); + + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LED_MODE, + rt2x00dev->led_mode); + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_0, + rt2x00_get_field16(eeprom, + EEPROM_LED_POLARITY_GPIO_0)); + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_1, + rt2x00_get_field16(eeprom, + EEPROM_LED_POLARITY_GPIO_1)); + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_2, + rt2x00_get_field16(eeprom, + EEPROM_LED_POLARITY_GPIO_2)); + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_3, + rt2x00_get_field16(eeprom, + EEPROM_LED_POLARITY_GPIO_3)); + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_4, + rt2x00_get_field16(eeprom, + EEPROM_LED_POLARITY_GPIO_4)); + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_ACT, + rt2x00_get_field16(eeprom, EEPROM_LED_POLARITY_ACT)); + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_READY_BG, + rt2x00_get_field16(eeprom, + EEPROM_LED_POLARITY_RDY_G)); + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_READY_A, + rt2x00_get_field16(eeprom, + EEPROM_LED_POLARITY_RDY_A)); + + return 0; +} + +/* + * RF value list for RF2528 + * Supports: 2.4 GHz + */ +static const struct rf_channel rf_vals_bg_2528[] = { + { 1, 0x00002c0c, 0x00000786, 0x00068255, 0x000fea0b }, + { 2, 0x00002c0c, 0x00000786, 0x00068255, 0x000fea1f }, + { 3, 0x00002c0c, 0x0000078a, 0x00068255, 0x000fea0b }, + { 4, 0x00002c0c, 0x0000078a, 0x00068255, 0x000fea1f }, + { 5, 0x00002c0c, 0x0000078e, 0x00068255, 0x000fea0b }, + { 6, 0x00002c0c, 0x0000078e, 0x00068255, 0x000fea1f }, + { 7, 0x00002c0c, 0x00000792, 0x00068255, 0x000fea0b }, + { 8, 0x00002c0c, 0x00000792, 0x00068255, 0x000fea1f }, + { 9, 0x00002c0c, 0x00000796, 0x00068255, 0x000fea0b }, + { 10, 0x00002c0c, 0x00000796, 0x00068255, 0x000fea1f }, + { 11, 0x00002c0c, 0x0000079a, 0x00068255, 0x000fea0b }, + { 12, 0x00002c0c, 0x0000079a, 0x00068255, 0x000fea1f }, + { 13, 0x00002c0c, 0x0000079e, 0x00068255, 0x000fea0b }, + { 14, 0x00002c0c, 0x000007a2, 0x00068255, 0x000fea13 }, +}; + +/* + * RF value list for RF5226 + * Supports: 2.4 GHz & 5.2 GHz + */ +static const struct rf_channel rf_vals_5226[] = { + { 1, 0x00002c0c, 0x00000786, 0x00068255, 0x000fea0b }, + { 2, 0x00002c0c, 0x00000786, 0x00068255, 0x000fea1f }, + { 3, 0x00002c0c, 0x0000078a, 0x00068255, 0x000fea0b }, + { 4, 0x00002c0c, 0x0000078a, 0x00068255, 0x000fea1f }, + { 5, 0x00002c0c, 0x0000078e, 0x00068255, 0x000fea0b }, + { 6, 0x00002c0c, 0x0000078e, 0x00068255, 0x000fea1f }, + { 7, 0x00002c0c, 0x00000792, 0x00068255, 0x000fea0b }, + { 8, 0x00002c0c, 0x00000792, 0x00068255, 0x000fea1f }, + { 9, 0x00002c0c, 0x00000796, 0x00068255, 0x000fea0b }, + { 10, 0x00002c0c, 0x00000796, 0x00068255, 0x000fea1f }, + { 11, 0x00002c0c, 0x0000079a, 0x00068255, 0x000fea0b }, + { 12, 0x00002c0c, 0x0000079a, 0x00068255, 0x000fea1f }, + { 13, 0x00002c0c, 0x0000079e, 0x00068255, 0x000fea0b }, + { 14, 0x00002c0c, 0x000007a2, 0x00068255, 0x000fea13 }, + + /* 802.11 UNI / HyperLan 2 */ + { 36, 0x00002c0c, 0x0000099a, 0x00098255, 0x000fea23 }, + { 40, 0x00002c0c, 0x000009a2, 0x00098255, 0x000fea03 }, + { 44, 0x00002c0c, 0x000009a6, 0x00098255, 0x000fea0b }, + { 48, 0x00002c0c, 0x000009aa, 0x00098255, 0x000fea13 }, + { 52, 0x00002c0c, 0x000009ae, 0x00098255, 0x000fea1b }, + { 56, 0x00002c0c, 0x000009b2, 0x00098255, 0x000fea23 }, + { 60, 0x00002c0c, 0x000009ba, 0x00098255, 0x000fea03 }, + { 64, 0x00002c0c, 0x000009be, 0x00098255, 0x000fea0b }, + + /* 802.11 HyperLan 2 */ + { 100, 0x00002c0c, 0x00000a2a, 0x000b8255, 0x000fea03 }, + { 104, 0x00002c0c, 0x00000a2e, 0x000b8255, 0x000fea0b }, + { 108, 0x00002c0c, 0x00000a32, 0x000b8255, 0x000fea13 }, + { 112, 0x00002c0c, 0x00000a36, 0x000b8255, 0x000fea1b }, + { 116, 0x00002c0c, 0x00000a3a, 0x000b8255, 0x000fea23 }, + { 120, 0x00002c0c, 0x00000a82, 0x000b8255, 0x000fea03 }, + { 124, 0x00002c0c, 0x00000a86, 0x000b8255, 0x000fea0b }, + { 128, 0x00002c0c, 0x00000a8a, 0x000b8255, 0x000fea13 }, + { 132, 0x00002c0c, 0x00000a8e, 0x000b8255, 0x000fea1b }, + { 136, 0x00002c0c, 0x00000a92, 0x000b8255, 0x000fea23 }, + + /* 802.11 UNII */ + { 140, 0x00002c0c, 0x00000a9a, 0x000b8255, 0x000fea03 }, + { 149, 0x00002c0c, 0x00000aa2, 0x000b8255, 0x000fea1f }, + { 153, 0x00002c0c, 0x00000aa6, 0x000b8255, 0x000fea27 }, + { 157, 0x00002c0c, 0x00000aae, 0x000b8255, 0x000fea07 }, + { 161, 0x00002c0c, 0x00000ab2, 0x000b8255, 0x000fea0f }, + { 165, 0x00002c0c, 0x00000ab6, 0x000b8255, 0x000fea17 }, + + /* MMAC(Japan)J52 ch 34,38,42,46 */ + { 34, 0x00002c0c, 0x0008099a, 0x000da255, 0x000d3a0b }, + { 38, 0x00002c0c, 0x0008099e, 0x000da255, 0x000d3a13 }, + { 42, 0x00002c0c, 0x000809a2, 0x000da255, 0x000d3a1b }, + { 46, 0x00002c0c, 0x000809a6, 0x000da255, 0x000d3a23 }, +}; + +/* + * RF value list for RF5225 & RF2527 + * Supports: 2.4 GHz & 5.2 GHz + */ +static const struct rf_channel rf_vals_5225_2527[] = { + { 1, 0x00002ccc, 0x00004786, 0x00068455, 0x000ffa0b }, + { 2, 0x00002ccc, 0x00004786, 0x00068455, 0x000ffa1f }, + { 3, 0x00002ccc, 0x0000478a, 0x00068455, 0x000ffa0b }, + { 4, 0x00002ccc, 0x0000478a, 0x00068455, 0x000ffa1f }, + { 5, 0x00002ccc, 0x0000478e, 0x00068455, 0x000ffa0b }, + { 6, 0x00002ccc, 0x0000478e, 0x00068455, 0x000ffa1f }, + { 7, 0x00002ccc, 0x00004792, 0x00068455, 0x000ffa0b }, + { 8, 0x00002ccc, 0x00004792, 0x00068455, 0x000ffa1f }, + { 9, 0x00002ccc, 0x00004796, 0x00068455, 0x000ffa0b }, + { 10, 0x00002ccc, 0x00004796, 0x00068455, 0x000ffa1f }, + { 11, 0x00002ccc, 0x0000479a, 0x00068455, 0x000ffa0b }, + { 12, 0x00002ccc, 0x0000479a, 0x00068455, 0x000ffa1f }, + { 13, 0x00002ccc, 0x0000479e, 0x00068455, 0x000ffa0b }, + { 14, 0x00002ccc, 0x000047a2, 0x00068455, 0x000ffa13 }, + + /* 802.11 UNI / HyperLan 2 */ + { 36, 0x00002ccc, 0x0000499a, 0x0009be55, 0x000ffa23 }, + { 40, 0x00002ccc, 0x000049a2, 0x0009be55, 0x000ffa03 }, + { 44, 0x00002ccc, 0x000049a6, 0x0009be55, 0x000ffa0b }, + { 48, 0x00002ccc, 0x000049aa, 0x0009be55, 0x000ffa13 }, + { 52, 0x00002ccc, 0x000049ae, 0x0009ae55, 0x000ffa1b }, + { 56, 0x00002ccc, 0x000049b2, 0x0009ae55, 0x000ffa23 }, + { 60, 0x00002ccc, 0x000049ba, 0x0009ae55, 0x000ffa03 }, + { 64, 0x00002ccc, 0x000049be, 0x0009ae55, 0x000ffa0b }, + + /* 802.11 HyperLan 2 */ + { 100, 0x00002ccc, 0x00004a2a, 0x000bae55, 0x000ffa03 }, + { 104, 0x00002ccc, 0x00004a2e, 0x000bae55, 0x000ffa0b }, + { 108, 0x00002ccc, 0x00004a32, 0x000bae55, 0x000ffa13 }, + { 112, 0x00002ccc, 0x00004a36, 0x000bae55, 0x000ffa1b }, + { 116, 0x00002ccc, 0x00004a3a, 0x000bbe55, 0x000ffa23 }, + { 120, 0x00002ccc, 0x00004a82, 0x000bbe55, 0x000ffa03 }, + { 124, 0x00002ccc, 0x00004a86, 0x000bbe55, 0x000ffa0b }, + { 128, 0x00002ccc, 0x00004a8a, 0x000bbe55, 0x000ffa13 }, + { 132, 0x00002ccc, 0x00004a8e, 0x000bbe55, 0x000ffa1b }, + { 136, 0x00002ccc, 0x00004a92, 0x000bbe55, 0x000ffa23 }, + + /* 802.11 UNII */ + { 140, 0x00002ccc, 0x00004a9a, 0x000bbe55, 0x000ffa03 }, + { 149, 0x00002ccc, 0x00004aa2, 0x000bbe55, 0x000ffa1f }, + { 153, 0x00002ccc, 0x00004aa6, 0x000bbe55, 0x000ffa27 }, + { 157, 0x00002ccc, 0x00004aae, 0x000bbe55, 0x000ffa07 }, + { 161, 0x00002ccc, 0x00004ab2, 0x000bbe55, 0x000ffa0f }, + { 165, 0x00002ccc, 0x00004ab6, 0x000bbe55, 0x000ffa17 }, + + /* MMAC(Japan)J52 ch 34,38,42,46 */ + { 34, 0x00002ccc, 0x0000499a, 0x0009be55, 0x000ffa0b }, + { 38, 0x00002ccc, 0x0000499e, 0x0009be55, 0x000ffa13 }, + { 42, 0x00002ccc, 0x000049a2, 0x0009be55, 0x000ffa1b }, + { 46, 0x00002ccc, 0x000049a6, 0x0009be55, 0x000ffa23 }, +}; + + +static void rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) +{ + struct hw_mode_spec *spec = &rt2x00dev->spec; + u8 *txpower; + unsigned int i; + + /* + * Initialize all hw fields. + */ + rt2x00dev->hw->flags = + IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_MONITOR_DURING_OPER | + IEEE80211_HW_NO_PROBE_FILTERING; + rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE; + rt2x00dev->hw->max_signal = MAX_SIGNAL; + rt2x00dev->hw->max_rssi = MAX_RX_SSI; + rt2x00dev->hw->queues = 5; + + SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_usb(rt2x00dev)->dev); + SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, + rt2x00_eeprom_addr(rt2x00dev, + EEPROM_MAC_ADDR_0)); + + /* + * Convert tx_power array in eeprom. + */ + txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_G_START); + for (i = 0; i < 14; i++) + txpower[i] = TXPOWER_FROM_DEV(txpower[i]); + + /* + * Initialize hw_mode information. + */ + spec->num_modes = 2; + spec->num_rates = 12; + spec->tx_power_a = NULL; + spec->tx_power_bg = txpower; + spec->tx_power_default = DEFAULT_TXPOWER; + + if (rt2x00_rf(&rt2x00dev->chip, RF2528)) { + spec->num_channels = ARRAY_SIZE(rf_vals_bg_2528); + spec->channels = rf_vals_bg_2528; + } else if (rt2x00_rf(&rt2x00dev->chip, RF5226)) { + spec->num_channels = ARRAY_SIZE(rf_vals_5226); + spec->channels = rf_vals_5226; + } else if (rt2x00_rf(&rt2x00dev->chip, RF2527)) { + spec->num_channels = 14; + spec->channels = rf_vals_5225_2527; + } else if (rt2x00_rf(&rt2x00dev->chip, RF5225)) { + spec->num_channels = ARRAY_SIZE(rf_vals_5225_2527); + spec->channels = rf_vals_5225_2527; + } + + if (rt2x00_rf(&rt2x00dev->chip, RF5225) || + rt2x00_rf(&rt2x00dev->chip, RF5226)) { + spec->num_modes = 3; + + txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A_START); + for (i = 0; i < 14; i++) + txpower[i] = TXPOWER_FROM_DEV(txpower[i]); + + spec->tx_power_a = txpower; + } +} + +static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) +{ + int retval; + + /* + * Allocate eeprom data. + */ + retval = rt73usb_validate_eeprom(rt2x00dev); + if (retval) + return retval; + + retval = rt73usb_init_eeprom(rt2x00dev); + if (retval) + return retval; + + /* + * Initialize hw specifications. + */ + rt73usb_probe_hw_mode(rt2x00dev); + + /* + * USB devices require scheduled packet filter toggling + * This device requires firmware + */ + __set_bit(REQUIRE_FIRMWARE, &rt2x00dev->flags); + __set_bit(PACKET_FILTER_SCHEDULED, &rt2x00dev->flags); + + /* + * Set the rssi offset. + */ + rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET; + + return 0; +} + +/* + * IEEE80211 stack callback functions. + */ +static int rt73usb_set_retry_limit(struct ieee80211_hw *hw, + u32 short_retry, u32 long_retry) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + u32 reg; + + rt73usb_register_read(rt2x00dev, TXRX_CSR4, ®); + rt2x00_set_field32(®, TXRX_CSR4_LONG_RETRY_LIMIT, long_retry); + rt2x00_set_field32(®, TXRX_CSR4_SHORT_RETRY_LIMIT, short_retry); + rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg); + + return 0; +} + +#if 0 +/* + * Mac80211 demands get_tsf must be atomic. + * This is not possible for rt73usb since all register access + * functions require sleeping. Untill mac80211 no longer needs + * get_tsf to be atomic, this function should be disabled. + */ +static u64 rt73usb_get_tsf(struct ieee80211_hw *hw) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + u64 tsf; + u32 reg; + + rt73usb_register_read(rt2x00dev, TXRX_CSR13, ®); + tsf = (u64) rt2x00_get_field32(reg, TXRX_CSR13_HIGH_TSFTIMER) << 32; + rt73usb_register_read(rt2x00dev, TXRX_CSR12, ®); + tsf |= rt2x00_get_field32(reg, TXRX_CSR12_LOW_TSFTIMER); + + return tsf; +} +#endif + +static void rt73usb_reset_tsf(struct ieee80211_hw *hw) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + + rt73usb_register_write(rt2x00dev, TXRX_CSR12, 0); + rt73usb_register_write(rt2x00dev, TXRX_CSR13, 0); +} + +int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ieee80211_tx_control *control) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + int timeout; + + /* + * Just in case the ieee80211 doesn't set this, + * but we need this queue set for the descriptor + * initialization. + */ + control->queue = IEEE80211_TX_QUEUE_BEACON; + + /* + * First we create the beacon. + */ + skb_push(skb, TXD_DESC_SIZE); + rt2x00lib_write_tx_desc(rt2x00dev, (struct data_desc *)skb->data, + (struct ieee80211_hdr *)(skb->data + + TXD_DESC_SIZE), + skb->len - TXD_DESC_SIZE, control); + + /* + * Write entire beacon with descriptor to register, + * and kick the beacon generator. + */ + timeout = REGISTER_TIMEOUT * (skb->len / sizeof(u32)); + rt2x00usb_vendor_request(rt2x00dev, USB_MULTI_WRITE, + USB_VENDOR_REQUEST_OUT, + HW_BEACON_BASE0, 0x0000, + skb->data, skb->len, timeout); + rt73usb_kick_tx_queue(rt2x00dev, IEEE80211_TX_QUEUE_BEACON); + + return 0; +} + +static const struct ieee80211_ops rt73usb_mac80211_ops = { + .tx = rt2x00mac_tx, + .add_interface = rt2x00mac_add_interface, + .remove_interface = rt2x00mac_remove_interface, + .config = rt2x00mac_config, + .config_interface = rt2x00mac_config_interface, + .set_multicast_list = rt2x00mac_set_multicast_list, + .get_stats = rt2x00mac_get_stats, + .set_retry_limit = rt73usb_set_retry_limit, + .conf_tx = rt2x00mac_conf_tx, + .get_tx_stats = rt2x00mac_get_tx_stats, +#if 0 +/* + * See comment at the rt73usb_get_tsf function. + */ + .get_tsf = rt73usb_get_tsf, +#endif + .reset_tsf = rt73usb_reset_tsf, + .beacon_update = rt73usb_beacon_update, +}; + +static const struct rt2x00lib_ops rt73usb_rt2x00_ops = { + .probe_hw = rt73usb_probe_hw, + .get_firmware_name = rt73usb_get_firmware_name, + .load_firmware = rt73usb_load_firmware, + .initialize = rt2x00usb_initialize, + .uninitialize = rt2x00usb_uninitialize, + .set_device_state = rt73usb_set_device_state, + .link_stats = rt73usb_link_stats, + .reset_tuner = rt73usb_reset_tuner, + .link_tuner = rt73usb_link_tuner, + .write_tx_desc = rt73usb_write_tx_desc, + .write_tx_data = rt2x00usb_write_tx_data, + .kick_tx_queue = rt73usb_kick_tx_queue, + .fill_rxdone = rt73usb_fill_rxdone, + .config_mac_addr = rt73usb_config_mac_addr, + .config_bssid = rt73usb_config_bssid, + .config_packet_filter = rt73usb_config_packet_filter, + .config_type = rt73usb_config_type, + .config = rt73usb_config, +}; + +static const struct rt2x00_ops rt73usb_ops = { + .name = DRV_NAME, + .rxd_size = RXD_DESC_SIZE, + .txd_size = TXD_DESC_SIZE, + .eeprom_size = EEPROM_SIZE, + .rf_size = RF_SIZE, + .lib = &rt73usb_rt2x00_ops, + .hw = &rt73usb_mac80211_ops, +#ifdef CONFIG_RT2X00_LIB_DEBUGFS + .debugfs = &rt73usb_rt2x00debug, +#endif /* CONFIG_RT2X00_LIB_DEBUGFS */ +}; + +/* + * rt73usb module information. + */ +static struct usb_device_id rt73usb_device_table[] = { + /* AboCom */ + { USB_DEVICE(0x07b8, 0xb21d), USB_DEVICE_DATA(&rt73usb_ops) }, + /* Askey */ + { USB_DEVICE(0x1690, 0x0722), USB_DEVICE_DATA(&rt73usb_ops) }, + /* ASUS */ + { USB_DEVICE(0x0b05, 0x1723), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x0b05, 0x1724), USB_DEVICE_DATA(&rt73usb_ops) }, + /* Belkin */ + { USB_DEVICE(0x050d, 0x7050), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x050d, 0x705a), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x050d, 0x905b), USB_DEVICE_DATA(&rt73usb_ops) }, + /* Billionton */ + { USB_DEVICE(0x1631, 0xc019), USB_DEVICE_DATA(&rt73usb_ops) }, + /* Buffalo */ + { USB_DEVICE(0x0411, 0x00f4), USB_DEVICE_DATA(&rt73usb_ops) }, + /* CNet */ + { USB_DEVICE(0x1371, 0x9022), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x1371, 0x9032), USB_DEVICE_DATA(&rt73usb_ops) }, + /* Conceptronic */ + { USB_DEVICE(0x14b2, 0x3c22), USB_DEVICE_DATA(&rt73usb_ops) }, + /* D-Link */ + { USB_DEVICE(0x07d1, 0x3c03), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x07d1, 0x3c04), USB_DEVICE_DATA(&rt73usb_ops) }, + /* Gemtek */ + { USB_DEVICE(0x15a9, 0x0004), USB_DEVICE_DATA(&rt73usb_ops) }, + /* Gigabyte */ + { USB_DEVICE(0x1044, 0x8008), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x1044, 0x800a), USB_DEVICE_DATA(&rt73usb_ops) }, + /* Huawei-3Com */ + { USB_DEVICE(0x1472, 0x0009), USB_DEVICE_DATA(&rt73usb_ops) }, + /* Hercules */ + { USB_DEVICE(0x06f8, 0xe010), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x06f8, 0xe020), USB_DEVICE_DATA(&rt73usb_ops) }, + /* Linksys */ + { USB_DEVICE(0x13b1, 0x0020), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x13b1, 0x0023), USB_DEVICE_DATA(&rt73usb_ops) }, + /* MSI */ + { USB_DEVICE(0x0db0, 0x6877), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x0db0, 0x6874), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x0db0, 0xa861), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x0db0, 0xa874), USB_DEVICE_DATA(&rt73usb_ops) }, + /* Ralink */ + { USB_DEVICE(0x148f, 0x2573), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x148f, 0x2671), USB_DEVICE_DATA(&rt73usb_ops) }, + /* Qcom */ + { USB_DEVICE(0x18e8, 0x6196), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x18e8, 0x6229), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x18e8, 0x6238), USB_DEVICE_DATA(&rt73usb_ops) }, + /* Senao */ + { USB_DEVICE(0x1740, 0x7100), USB_DEVICE_DATA(&rt73usb_ops) }, + /* Sitecom */ + { USB_DEVICE(0x0df6, 0x9712), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x0df6, 0x90ac), USB_DEVICE_DATA(&rt73usb_ops) }, + /* Surecom */ + { USB_DEVICE(0x0769, 0x31f3), USB_DEVICE_DATA(&rt73usb_ops) }, + /* Planex */ + { USB_DEVICE(0x2019, 0xab01), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x2019, 0xab50), USB_DEVICE_DATA(&rt73usb_ops) }, + { 0, } +}; + +MODULE_AUTHOR(DRV_PROJECT); +MODULE_VERSION(DRV_VERSION); +MODULE_DESCRIPTION("Ralink RT73 USB Wireless LAN driver."); +MODULE_SUPPORTED_DEVICE("Ralink RT2571W & RT2671 USB chipset based cards"); +MODULE_DEVICE_TABLE(usb, rt73usb_device_table); +MODULE_FIRMWARE(FIRMWARE_RT2571); +MODULE_LICENSE("GPL"); + +static struct usb_driver rt73usb_driver = { + .name = DRV_NAME, + .id_table = rt73usb_device_table, + .probe = rt2x00usb_probe, + .disconnect = rt2x00usb_disconnect, + .suspend = rt2x00usb_suspend, + .resume = rt2x00usb_resume, +}; + +static int __init rt73usb_init(void) +{ + return usb_register(&rt73usb_driver); +} + +static void __exit rt73usb_exit(void) +{ + usb_deregister(&rt73usb_driver); +} + +module_init(rt73usb_init); +module_exit(rt73usb_exit); diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h new file mode 100644 index 00000000000..5d63a1a714f --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt73usb.h @@ -0,0 +1,1024 @@ +/* + Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the + Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + Module: rt73usb + Abstract: Data structures and registers for the rt73usb module. + Supported chipsets: rt2571W & rt2671. + */ + +#ifndef RT73USB_H +#define RT73USB_H + +/* + * RF chip defines. + */ +#define RF5226 0x0001 +#define RF2528 0x0002 +#define RF5225 0x0003 +#define RF2527 0x0004 + +/* + * Signal information. + * Defaul offset is required for RSSI <-> dBm conversion. + */ +#define MAX_SIGNAL 100 +#define MAX_RX_SSI -1 +#define DEFAULT_RSSI_OFFSET 120 + +/* + * Register layout information. + */ +#define CSR_REG_BASE 0x3000 +#define CSR_REG_SIZE 0x04b0 +#define EEPROM_BASE 0x0000 +#define EEPROM_SIZE 0x0100 +#define BBP_SIZE 0x0080 +#define RF_SIZE 0x0014 + +/* + * USB registers. + */ + +/* + * MCU_LEDCS: LED control for MCU Mailbox. + */ +#define MCU_LEDCS_LED_MODE FIELD16(0x001f) +#define MCU_LEDCS_RADIO_STATUS FIELD16(0x0020) +#define MCU_LEDCS_LINK_BG_STATUS FIELD16(0x0040) +#define MCU_LEDCS_LINK_A_STATUS FIELD16(0x0080) +#define MCU_LEDCS_POLARITY_GPIO_0 FIELD16(0x0100) +#define MCU_LEDCS_POLARITY_GPIO_1 FIELD16(0x0200) +#define MCU_LEDCS_POLARITY_GPIO_2 FIELD16(0x0400) +#define MCU_LEDCS_POLARITY_GPIO_3 FIELD16(0x0800) +#define MCU_LEDCS_POLARITY_GPIO_4 FIELD16(0x1000) +#define MCU_LEDCS_POLARITY_ACT FIELD16(0x2000) +#define MCU_LEDCS_POLARITY_READY_BG FIELD16(0x4000) +#define MCU_LEDCS_POLARITY_READY_A FIELD16(0x8000) + +/* + * 8051 firmware image. + */ +#define FIRMWARE_RT2571 "rt73.bin" +#define FIRMWARE_IMAGE_BASE 0x0800 + +/* + * Security key table memory. + * 16 entries 32-byte for shared key table + * 64 entries 32-byte for pairwise key table + * 64 entries 8-byte for pairwise ta key table + */ +#define SHARED_KEY_TABLE_BASE 0x1000 +#define PAIRWISE_KEY_TABLE_BASE 0x1200 +#define PAIRWISE_TA_TABLE_BASE 0x1a00 + +struct hw_key_entry { + u8 key[16]; + u8 tx_mic[8]; + u8 rx_mic[8]; +} __attribute__ ((packed)); + +struct hw_pairwise_ta_entry { + u8 address[6]; + u8 reserved[2]; +} __attribute__ ((packed)); + +/* + * Since NULL frame won't be that long (256 byte), + * We steal 16 tail bytes to save debugging settings. + */ +#define HW_DEBUG_SETTING_BASE 0x2bf0 + +/* + * On-chip BEACON frame space. + */ +#define HW_BEACON_BASE0 0x2400 +#define HW_BEACON_BASE1 0x2500 +#define HW_BEACON_BASE2 0x2600 +#define HW_BEACON_BASE3 0x2700 + +/* + * MAC Control/Status Registers(CSR). + * Some values are set in TU, whereas 1 TU == 1024 us. + */ + +/* + * MAC_CSR0: ASIC revision number. + */ +#define MAC_CSR0 0x3000 + +/* + * MAC_CSR1: System control register. + * SOFT_RESET: Software reset bit, 1: reset, 0: normal. + * BBP_RESET: Hardware reset BBP. + * HOST_READY: Host is ready after initialization, 1: ready. + */ +#define MAC_CSR1 0x3004 +#define MAC_CSR1_SOFT_RESET FIELD32(0x00000001) +#define MAC_CSR1_BBP_RESET FIELD32(0x00000002) +#define MAC_CSR1_HOST_READY FIELD32(0x00000004) + +/* + * MAC_CSR2: STA MAC register 0. + */ +#define MAC_CSR2 0x3008 +#define MAC_CSR2_BYTE0 FIELD32(0x000000ff) +#define MAC_CSR2_BYTE1 FIELD32(0x0000ff00) +#define MAC_CSR2_BYTE2 FIELD32(0x00ff0000) +#define MAC_CSR2_BYTE3 FIELD32(0xff000000) + +/* + * MAC_CSR3: STA MAC register 1. + */ +#define MAC_CSR3 0x300c +#define MAC_CSR3_BYTE4 FIELD32(0x000000ff) +#define MAC_CSR3_BYTE5 FIELD32(0x0000ff00) +#define MAC_CSR3_UNICAST_TO_ME_MASK FIELD32(0x00ff0000) + +/* + * MAC_CSR4: BSSID register 0. + */ +#define MAC_CSR4 0x3010 +#define MAC_CSR4_BYTE0 FIELD32(0x000000ff) +#define MAC_CSR4_BYTE1 FIELD32(0x0000ff00) +#define MAC_CSR4_BYTE2 FIELD32(0x00ff0000) +#define MAC_CSR4_BYTE3 FIELD32(0xff000000) + +/* + * MAC_CSR5: BSSID register 1. + * BSS_ID_MASK: 3: one BSSID, 0: 4 BSSID, 2 or 1: 2 BSSID. + */ +#define MAC_CSR5 0x3014 +#define MAC_CSR5_BYTE4 FIELD32(0x000000ff) +#define MAC_CSR5_BYTE5 FIELD32(0x0000ff00) +#define MAC_CSR5_BSS_ID_MASK FIELD32(0x00ff0000) + +/* + * MAC_CSR6: Maximum frame length register. + */ +#define MAC_CSR6 0x3018 +#define MAC_CSR6_MAX_FRAME_UNIT FIELD32(0x00000fff) + +/* + * MAC_CSR7: Reserved + */ +#define MAC_CSR7 0x301c + +/* + * MAC_CSR8: SIFS/EIFS register. + * All units are in US. + */ +#define MAC_CSR8 0x3020 +#define MAC_CSR8_SIFS FIELD32(0x000000ff) +#define MAC_CSR8_SIFS_AFTER_RX_OFDM FIELD32(0x0000ff00) +#define MAC_CSR8_EIFS FIELD32(0xffff0000) + +/* + * MAC_CSR9: Back-Off control register. + * SLOT_TIME: Slot time, default is 20us for 802.11BG. + * CWMIN: Bit for Cwmin. default Cwmin is 31 (2^5 - 1). + * CWMAX: Bit for Cwmax, default Cwmax is 1023 (2^10 - 1). + * CW_SELECT: 1: CWmin/Cwmax select from register, 0:select from TxD. + */ +#define MAC_CSR9 0x3024 +#define MAC_CSR9_SLOT_TIME FIELD32(0x000000ff) +#define MAC_CSR9_CWMIN FIELD32(0x00000f00) +#define MAC_CSR9_CWMAX FIELD32(0x0000f000) +#define MAC_CSR9_CW_SELECT FIELD32(0x00010000) + +/* + * MAC_CSR10: Power state configuration. + */ +#define MAC_CSR10 0x3028 + +/* + * MAC_CSR11: Power saving transition time register. + * DELAY_AFTER_TBCN: Delay after Tbcn expired in units of TU. + * TBCN_BEFORE_WAKEUP: Number of beacon before wakeup. + * WAKEUP_LATENCY: In unit of TU. + */ +#define MAC_CSR11 0x302c +#define MAC_CSR11_DELAY_AFTER_TBCN FIELD32(0x000000ff) +#define MAC_CSR11_TBCN_BEFORE_WAKEUP FIELD32(0x00007f00) +#define MAC_CSR11_AUTOWAKE FIELD32(0x00008000) +#define MAC_CSR11_WAKEUP_LATENCY FIELD32(0x000f0000) + +/* + * MAC_CSR12: Manual power control / status register (merge CSR20 & PWRCSR1). + * CURRENT_STATE: 0:sleep, 1:awake. + * FORCE_WAKEUP: This has higher priority than PUT_TO_SLEEP. + * BBP_CURRENT_STATE: 0: BBP sleep, 1: BBP awake. + */ +#define MAC_CSR12 0x3030 +#define MAC_CSR12_CURRENT_STATE FIELD32(0x00000001) +#define MAC_CSR12_PUT_TO_SLEEP FIELD32(0x00000002) +#define MAC_CSR12_FORCE_WAKEUP FIELD32(0x00000004) +#define MAC_CSR12_BBP_CURRENT_STATE FIELD32(0x00000008) + +/* + * MAC_CSR13: GPIO. + */ +#define MAC_CSR13 0x3034 + +/* + * MAC_CSR14: LED control register. + * ON_PERIOD: On period, default 70ms. + * OFF_PERIOD: Off period, default 30ms. + * HW_LED: HW TX activity, 1: normal OFF, 0: normal ON. + * SW_LED: s/w LED, 1: ON, 0: OFF. + * HW_LED_POLARITY: 0: active low, 1: active high. + */ +#define MAC_CSR14 0x3038 +#define MAC_CSR14_ON_PERIOD FIELD32(0x000000ff) +#define MAC_CSR14_OFF_PERIOD FIELD32(0x0000ff00) +#define MAC_CSR14_HW_LED FIELD32(0x00010000) +#define MAC_CSR14_SW_LED FIELD32(0x00020000) +#define MAC_CSR14_HW_LED_POLARITY FIELD32(0x00040000) +#define MAC_CSR14_SW_LED2 FIELD32(0x00080000) + +/* + * MAC_CSR15: NAV control. + */ +#define MAC_CSR15 0x303c + +/* + * TXRX control registers. + * Some values are set in TU, whereas 1 TU == 1024 us. + */ + +/* + * TXRX_CSR0: TX/RX configuration register. + * TSF_OFFSET: Default is 24. + * AUTO_TX_SEQ: 1: ASIC auto replace sequence nr in outgoing frame. + * DISABLE_RX: Disable Rx engine. + * DROP_CRC: Drop CRC error. + * DROP_PHYSICAL: Drop physical error. + * DROP_CONTROL: Drop control frame. + * DROP_NOT_TO_ME: Drop not to me unicast frame. + * DROP_TO_DS: Drop fram ToDs bit is true. + * DROP_VERSION_ERROR: Drop version error frame. + * DROP_MULTICAST: Drop multicast frames. + * DROP_BORADCAST: Drop broadcast frames. + * ROP_ACK_CTS: Drop received ACK and CTS. + */ +#define TXRX_CSR0 0x3040 +#define TXRX_CSR0_RX_ACK_TIMEOUT FIELD32(0x000001ff) +#define TXRX_CSR0_TSF_OFFSET FIELD32(0x00007e00) +#define TXRX_CSR0_AUTO_TX_SEQ FIELD32(0x00008000) +#define TXRX_CSR0_DISABLE_RX FIELD32(0x00010000) +#define TXRX_CSR0_DROP_CRC FIELD32(0x00020000) +#define TXRX_CSR0_DROP_PHYSICAL FIELD32(0x00040000) +#define TXRX_CSR0_DROP_CONTROL FIELD32(0x00080000) +#define TXRX_CSR0_DROP_NOT_TO_ME FIELD32(0x00100000) +#define TXRX_CSR0_DROP_TO_DS FIELD32(0x00200000) +#define TXRX_CSR0_DROP_VERSION_ERROR FIELD32(0x00400000) +#define TXRX_CSR0_DROP_MULTICAST FIELD32(0x00800000) +#define TXRX_CSR0_DROP_BORADCAST FIELD32(0x01000000) +#define TXRX_CSR0_DROP_ACK_CTS FIELD32(0x02000000) +#define TXRX_CSR0_TX_WITHOUT_WAITING FIELD32(0x04000000) + +/* + * TXRX_CSR1 + */ +#define TXRX_CSR1 0x3044 +#define TXRX_CSR1_BBP_ID0 FIELD32(0x0000007f) +#define TXRX_CSR1_BBP_ID0_VALID FIELD32(0x00000080) +#define TXRX_CSR1_BBP_ID1 FIELD32(0x00007f00) +#define TXRX_CSR1_BBP_ID1_VALID FIELD32(0x00008000) +#define TXRX_CSR1_BBP_ID2 FIELD32(0x007f0000) +#define TXRX_CSR1_BBP_ID2_VALID FIELD32(0x00800000) +#define TXRX_CSR1_BBP_ID3 FIELD32(0x7f000000) +#define TXRX_CSR1_BBP_ID3_VALID FIELD32(0x80000000) + +/* + * TXRX_CSR2 + */ +#define TXRX_CSR2 0x3048 +#define TXRX_CSR2_BBP_ID0 FIELD32(0x0000007f) +#define TXRX_CSR2_BBP_ID0_VALID FIELD32(0x00000080) +#define TXRX_CSR2_BBP_ID1 FIELD32(0x00007f00) +#define TXRX_CSR2_BBP_ID1_VALID FIELD32(0x00008000) +#define TXRX_CSR2_BBP_ID2 FIELD32(0x007f0000) +#define TXRX_CSR2_BBP_ID2_VALID FIELD32(0x00800000) +#define TXRX_CSR2_BBP_ID3 FIELD32(0x7f000000) +#define TXRX_CSR2_BBP_ID3_VALID FIELD32(0x80000000) + +/* + * TXRX_CSR3 + */ +#define TXRX_CSR3 0x304c +#define TXRX_CSR3_BBP_ID0 FIELD32(0x0000007f) +#define TXRX_CSR3_BBP_ID0_VALID FIELD32(0x00000080) +#define TXRX_CSR3_BBP_ID1 FIELD32(0x00007f00) +#define TXRX_CSR3_BBP_ID1_VALID FIELD32(0x00008000) +#define TXRX_CSR3_BBP_ID2 FIELD32(0x007f0000) +#define TXRX_CSR3_BBP_ID2_VALID FIELD32(0x00800000) +#define TXRX_CSR3_BBP_ID3 FIELD32(0x7f000000) +#define TXRX_CSR3_BBP_ID3_VALID FIELD32(0x80000000) + +/* + * TXRX_CSR4: Auto-Responder/Tx-retry register. + * AUTORESPOND_PREAMBLE: 0:long, 1:short preamble. + * OFDM_TX_RATE_DOWN: 1:enable. + * OFDM_TX_RATE_STEP: 0:1-step, 1: 2-step, 2:3-step, 3:4-step. + * OFDM_TX_FALLBACK_CCK: 0: Fallback to OFDM 6M only, 1: Fallback to CCK 1M,2M. + */ +#define TXRX_CSR4 0x3050 +#define TXRX_CSR4_TX_ACK_TIMEOUT FIELD32(0x000000ff) +#define TXRX_CSR4_CNTL_ACK_POLICY FIELD32(0x00000700) +#define TXRX_CSR4_ACK_CTS_PSM FIELD32(0x00010000) +#define TXRX_CSR4_AUTORESPOND_ENABLE FIELD32(0x00020000) +#define TXRX_CSR4_AUTORESPOND_PREAMBLE FIELD32(0x00040000) +#define TXRX_CSR4_OFDM_TX_RATE_DOWN FIELD32(0x00080000) +#define TXRX_CSR4_OFDM_TX_RATE_STEP FIELD32(0x00300000) +#define TXRX_CSR4_OFDM_TX_FALLBACK_CCK FIELD32(0x00400000) +#define TXRX_CSR4_LONG_RETRY_LIMIT FIELD32(0x0f000000) +#define TXRX_CSR4_SHORT_RETRY_LIMIT FIELD32(0xf0000000) + +/* + * TXRX_CSR5 + */ +#define TXRX_CSR5 0x3054 + +/* + * TXRX_CSR6: ACK/CTS payload consumed time + */ +#define TXRX_CSR6 0x3058 + +/* + * TXRX_CSR7: OFDM ACK/CTS payload consumed time for 6/9/12/18 mbps. + */ +#define TXRX_CSR7 0x305c +#define TXRX_CSR7_ACK_CTS_6MBS FIELD32(0x000000ff) +#define TXRX_CSR7_ACK_CTS_9MBS FIELD32(0x0000ff00) +#define TXRX_CSR7_ACK_CTS_12MBS FIELD32(0x00ff0000) +#define TXRX_CSR7_ACK_CTS_18MBS FIELD32(0xff000000) + +/* + * TXRX_CSR8: OFDM ACK/CTS payload consumed time for 24/36/48/54 mbps. + */ +#define TXRX_CSR8 0x3060 +#define TXRX_CSR8_ACK_CTS_24MBS FIELD32(0x000000ff) +#define TXRX_CSR8_ACK_CTS_36MBS FIELD32(0x0000ff00) +#define TXRX_CSR8_ACK_CTS_48MBS FIELD32(0x00ff0000) +#define TXRX_CSR8_ACK_CTS_54MBS FIELD32(0xff000000) + +/* + * TXRX_CSR9: Synchronization control register. + * BEACON_INTERVAL: In unit of 1/16 TU. + * TSF_TICKING: Enable TSF auto counting. + * TSF_SYNC: Tsf sync, 0: disable, 1: infra, 2: ad-hoc/master mode. + * BEACON_GEN: Enable beacon generator. + */ +#define TXRX_CSR9 0x3064 +#define TXRX_CSR9_BEACON_INTERVAL FIELD32(0x0000ffff) +#define TXRX_CSR9_TSF_TICKING FIELD32(0x00010000) +#define TXRX_CSR9_TSF_SYNC FIELD32(0x00060000) +#define TXRX_CSR9_TBTT_ENABLE FIELD32(0x00080000) +#define TXRX_CSR9_BEACON_GEN FIELD32(0x00100000) +#define TXRX_CSR9_TIMESTAMP_COMPENSATE FIELD32(0xff000000) + +/* + * TXRX_CSR10: BEACON alignment. + */ +#define TXRX_CSR10 0x3068 + +/* + * TXRX_CSR11: AES mask. + */ +#define TXRX_CSR11 0x306c + +/* + * TXRX_CSR12: TSF low 32. + */ +#define TXRX_CSR12 0x3070 +#define TXRX_CSR12_LOW_TSFTIMER FIELD32(0xffffffff) + +/* + * TXRX_CSR13: TSF high 32. + */ +#define TXRX_CSR13 0x3074 +#define TXRX_CSR13_HIGH_TSFTIMER FIELD32(0xffffffff) + +/* + * TXRX_CSR14: TBTT timer. + */ +#define TXRX_CSR14 0x3078 + +/* + * TXRX_CSR15: TKIP MIC priority byte "AND" mask. + */ +#define TXRX_CSR15 0x307c + +/* + * PHY control registers. + * Some values are set in TU, whereas 1 TU == 1024 us. + */ + +/* + * PHY_CSR0: RF/PS control. + */ +#define PHY_CSR0 0x3080 +#define PHY_CSR0_PA_PE_BG FIELD32(0x00010000) +#define PHY_CSR0_PA_PE_A FIELD32(0x00020000) + +/* + * PHY_CSR1 + */ +#define PHY_CSR1 0x3084 +#define PHY_CSR1_RF_RPI FIELD32(0x00010000) + +/* + * PHY_CSR2: Pre-TX BBP control. + */ +#define PHY_CSR2 0x3088 + +/* + * PHY_CSR3: BBP serial control register. + * VALUE: Register value to program into BBP. + * REG_NUM: Selected BBP register. + * READ_CONTROL: 0: Write BBP, 1: Read BBP. + * BUSY: 1: ASIC is busy execute BBP programming. + */ +#define PHY_CSR3 0x308c +#define PHY_CSR3_VALUE FIELD32(0x000000ff) +#define PHY_CSR3_REGNUM FIELD32(0x00007f00) +#define PHY_CSR3_READ_CONTROL FIELD32(0x00008000) +#define PHY_CSR3_BUSY FIELD32(0x00010000) + +/* + * PHY_CSR4: RF serial control register + * VALUE: Register value (include register id) serial out to RF/IF chip. + * NUMBER_OF_BITS: Number of bits used in RFRegValue (I:20, RFMD:22). + * IF_SELECT: 1: select IF to program, 0: select RF to program. + * PLL_LD: RF PLL_LD status. + * BUSY: 1: ASIC is busy execute RF programming. + */ +#define PHY_CSR4 0x3090 +#define PHY_CSR4_VALUE FIELD32(0x00ffffff) +#define PHY_CSR4_NUMBER_OF_BITS FIELD32(0x1f000000) +#define PHY_CSR4_IF_SELECT FIELD32(0x20000000) +#define PHY_CSR4_PLL_LD FIELD32(0x40000000) +#define PHY_CSR4_BUSY FIELD32(0x80000000) + +/* + * PHY_CSR5: RX to TX signal switch timing control. + */ +#define PHY_CSR5 0x3094 +#define PHY_CSR5_IQ_FLIP FIELD32(0x00000004) + +/* + * PHY_CSR6: TX to RX signal timing control. + */ +#define PHY_CSR6 0x3098 +#define PHY_CSR6_IQ_FLIP FIELD32(0x00000004) + +/* + * PHY_CSR7: TX DAC switching timing control. + */ +#define PHY_CSR7 0x309c + +/* + * Security control register. + */ + +/* + * SEC_CSR0: Shared key table control. + */ +#define SEC_CSR0 0x30a0 +#define SEC_CSR0_BSS0_KEY0_VALID FIELD32(0x00000001) +#define SEC_CSR0_BSS0_KEY1_VALID FIELD32(0x00000002) +#define SEC_CSR0_BSS0_KEY2_VALID FIELD32(0x00000004) +#define SEC_CSR0_BSS0_KEY3_VALID FIELD32(0x00000008) +#define SEC_CSR0_BSS1_KEY0_VALID FIELD32(0x00000010) +#define SEC_CSR0_BSS1_KEY1_VALID FIELD32(0x00000020) +#define SEC_CSR0_BSS1_KEY2_VALID FIELD32(0x00000040) +#define SEC_CSR0_BSS1_KEY3_VALID FIELD32(0x00000080) +#define SEC_CSR0_BSS2_KEY0_VALID FIELD32(0x00000100) +#define SEC_CSR0_BSS2_KEY1_VALID FIELD32(0x00000200) +#define SEC_CSR0_BSS2_KEY2_VALID FIELD32(0x00000400) +#define SEC_CSR0_BSS2_KEY3_VALID FIELD32(0x00000800) +#define SEC_CSR0_BSS3_KEY0_VALID FIELD32(0x00001000) +#define SEC_CSR0_BSS3_KEY1_VALID FIELD32(0x00002000) +#define SEC_CSR0_BSS3_KEY2_VALID FIELD32(0x00004000) +#define SEC_CSR0_BSS3_KEY3_VALID FIELD32(0x00008000) + +/* + * SEC_CSR1: Shared key table security mode register. + */ +#define SEC_CSR1 0x30a4 +#define SEC_CSR1_BSS0_KEY0_CIPHER_ALG FIELD32(0x00000007) +#define SEC_CSR1_BSS0_KEY1_CIPHER_ALG FIELD32(0x00000070) +#define SEC_CSR1_BSS0_KEY2_CIPHER_ALG FIELD32(0x00000700) +#define SEC_CSR1_BSS0_KEY3_CIPHER_ALG FIELD32(0x00007000) +#define SEC_CSR1_BSS1_KEY0_CIPHER_ALG FIELD32(0x00070000) +#define SEC_CSR1_BSS1_KEY1_CIPHER_ALG FIELD32(0x00700000) +#define SEC_CSR1_BSS1_KEY2_CIPHER_ALG FIELD32(0x07000000) +#define SEC_CSR1_BSS1_KEY3_CIPHER_ALG FIELD32(0x70000000) + +/* + * Pairwise key table valid bitmap registers. + * SEC_CSR2: pairwise key table valid bitmap 0. + * SEC_CSR3: pairwise key table valid bitmap 1. + */ +#define SEC_CSR2 0x30a8 +#define SEC_CSR3 0x30ac + +/* + * SEC_CSR4: Pairwise key table lookup control. + */ +#define SEC_CSR4 0x30b0 + +/* + * SEC_CSR5: shared key table security mode register. + */ +#define SEC_CSR5 0x30b4 +#define SEC_CSR5_BSS2_KEY0_CIPHER_ALG FIELD32(0x00000007) +#define SEC_CSR5_BSS2_KEY1_CIPHER_ALG FIELD32(0x00000070) +#define SEC_CSR5_BSS2_KEY2_CIPHER_ALG FIELD32(0x00000700) +#define SEC_CSR5_BSS2_KEY3_CIPHER_ALG FIELD32(0x00007000) +#define SEC_CSR5_BSS3_KEY0_CIPHER_ALG FIELD32(0x00070000) +#define SEC_CSR5_BSS3_KEY1_CIPHER_ALG FIELD32(0x00700000) +#define SEC_CSR5_BSS3_KEY2_CIPHER_ALG FIELD32(0x07000000) +#define SEC_CSR5_BSS3_KEY3_CIPHER_ALG FIELD32(0x70000000) + +/* + * STA control registers. + */ + +/* + * STA_CSR0: RX PLCP error count & RX FCS error count. + */ +#define STA_CSR0 0x30c0 +#define STA_CSR0_FCS_ERROR FIELD32(0x0000ffff) +#define STA_CSR0_PLCP_ERROR FIELD32(0xffff0000) + +/* + * STA_CSR1: RX False CCA count & RX LONG frame count. + */ +#define STA_CSR1 0x30c4 +#define STA_CSR1_PHYSICAL_ERROR FIELD32(0x0000ffff) +#define STA_CSR1_FALSE_CCA_ERROR FIELD32(0xffff0000) + +/* + * STA_CSR2: TX Beacon count and RX FIFO overflow count. + */ +#define STA_CSR2 0x30c8 +#define STA_CSR2_RX_FIFO_OVERFLOW_COUNT FIELD32(0x0000ffff) +#define STA_CSR2_RX_OVERFLOW_COUNT FIELD32(0xffff0000) + +/* + * STA_CSR3: TX Beacon count. + */ +#define STA_CSR3 0x30cc +#define STA_CSR3_TX_BEACON_COUNT FIELD32(0x0000ffff) + +/* + * STA_CSR4: TX Retry count. + */ +#define STA_CSR4 0x30d0 +#define STA_CSR4_TX_NO_RETRY_COUNT FIELD32(0x0000ffff) +#define STA_CSR4_TX_ONE_RETRY_COUNT FIELD32(0xffff0000) + +/* + * STA_CSR5: TX Retry count. + */ +#define STA_CSR5 0x30d4 +#define STA_CSR4_TX_MULTI_RETRY_COUNT FIELD32(0x0000ffff) +#define STA_CSR4_TX_RETRY_FAIL_COUNT FIELD32(0xffff0000) + +/* + * QOS control registers. + */ + +/* + * QOS_CSR1: TXOP holder MAC address register. + */ +#define QOS_CSR1 0x30e4 +#define QOS_CSR1_BYTE4 FIELD32(0x000000ff) +#define QOS_CSR1_BYTE5 FIELD32(0x0000ff00) + +/* + * QOS_CSR2: TXOP holder timeout register. + */ +#define QOS_CSR2 0x30e8 + +/* + * RX QOS-CFPOLL MAC address register. + * QOS_CSR3: RX QOS-CFPOLL MAC address 0. + * QOS_CSR4: RX QOS-CFPOLL MAC address 1. + */ +#define QOS_CSR3 0x30ec +#define QOS_CSR4 0x30f0 + +/* + * QOS_CSR5: "QosControl" field of the RX QOS-CFPOLL. + */ +#define QOS_CSR5 0x30f4 + +/* + * WMM Scheduler Register + */ + +/* + * AIFSN_CSR: AIFSN for each EDCA AC. + * AIFSN0: For AC_BK. + * AIFSN1: For AC_BE. + * AIFSN2: For AC_VI. + * AIFSN3: For AC_VO. + */ +#define AIFSN_CSR 0x0400 +#define AIFSN_CSR_AIFSN0 FIELD32(0x0000000f) +#define AIFSN_CSR_AIFSN1 FIELD32(0x000000f0) +#define AIFSN_CSR_AIFSN2 FIELD32(0x00000f00) +#define AIFSN_CSR_AIFSN3 FIELD32(0x0000f000) + +/* + * CWMIN_CSR: CWmin for each EDCA AC. + * CWMIN0: For AC_BK. + * CWMIN1: For AC_BE. + * CWMIN2: For AC_VI. + * CWMIN3: For AC_VO. + */ +#define CWMIN_CSR 0x0404 +#define CWMIN_CSR_CWMIN0 FIELD32(0x0000000f) +#define CWMIN_CSR_CWMIN1 FIELD32(0x000000f0) +#define CWMIN_CSR_CWMIN2 FIELD32(0x00000f00) +#define CWMIN_CSR_CWMIN3 FIELD32(0x0000f000) + +/* + * CWMAX_CSR: CWmax for each EDCA AC. + * CWMAX0: For AC_BK. + * CWMAX1: For AC_BE. + * CWMAX2: For AC_VI. + * CWMAX3: For AC_VO. + */ +#define CWMAX_CSR 0x0408 +#define CWMAX_CSR_CWMAX0 FIELD32(0x0000000f) +#define CWMAX_CSR_CWMAX1 FIELD32(0x000000f0) +#define CWMAX_CSR_CWMAX2 FIELD32(0x00000f00) +#define CWMAX_CSR_CWMAX3 FIELD32(0x0000f000) + +/* + * AC_TXOP_CSR0: AC_BK/AC_BE TXOP register. + * AC0_TX_OP: For AC_BK, in unit of 32us. + * AC1_TX_OP: For AC_BE, in unit of 32us. + */ +#define AC_TXOP_CSR0 0x040c +#define AC_TXOP_CSR0_AC0_TX_OP FIELD32(0x0000ffff) +#define AC_TXOP_CSR0_AC1_TX_OP FIELD32(0xffff0000) + +/* + * AC_TXOP_CSR1: AC_VO/AC_VI TXOP register. + * AC2_TX_OP: For AC_VI, in unit of 32us. + * AC3_TX_OP: For AC_VO, in unit of 32us. + */ +#define AC_TXOP_CSR1 0x0410 +#define AC_TXOP_CSR1_AC2_TX_OP FIELD32(0x0000ffff) +#define AC_TXOP_CSR1_AC3_TX_OP FIELD32(0xffff0000) + +/* + * BBP registers. + * The wordsize of the BBP is 8 bits. + */ + +/* + * R2 + */ +#define BBP_R2_BG_MODE FIELD8(0x20) + +/* + * R3 + */ +#define BBP_R3_SMART_MODE FIELD8(0x01) + +/* + * R4: RX antenna control + * FRAME_END: 1 - DPDT, 0 - SPDT (Only valid for 802.11G, RF2527 & RF2529) + */ +#define BBP_R4_RX_ANTENNA FIELD8(0x03) +#define BBP_R4_RX_FRAME_END FIELD8(0x20) + +/* + * R77 + */ +#define BBP_R77_PAIR FIELD8(0x03) + +/* + * RF registers + */ + +/* + * RF 3 + */ +#define RF3_TXPOWER FIELD32(0x00003e00) + +/* + * RF 4 + */ +#define RF4_FREQ_OFFSET FIELD32(0x0003f000) + +/* + * EEPROM content. + * The wordsize of the EEPROM is 16 bits. + */ + +/* + * HW MAC address. + */ +#define EEPROM_MAC_ADDR_0 0x0002 +#define EEPROM_MAC_ADDR_BYTE0 FIELD16(0x00ff) +#define EEPROM_MAC_ADDR_BYTE1 FIELD16(0xff00) +#define EEPROM_MAC_ADDR1 0x0003 +#define EEPROM_MAC_ADDR_BYTE2 FIELD16(0x00ff) +#define EEPROM_MAC_ADDR_BYTE3 FIELD16(0xff00) +#define EEPROM_MAC_ADDR_2 0x0004 +#define EEPROM_MAC_ADDR_BYTE4 FIELD16(0x00ff) +#define EEPROM_MAC_ADDR_BYTE5 FIELD16(0xff00) + +/* + * EEPROM antenna. + * ANTENNA_NUM: Number of antenna's. + * TX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B. + * RX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B. + * FRAME_TYPE: 0: DPDT , 1: SPDT , noted this bit is valid for g only. + * DYN_TXAGC: Dynamic TX AGC control. + * HARDWARE_RADIO: 1: Hardware controlled radio. Read GPIO0. + * RF_TYPE: Rf_type of this adapter. + */ +#define EEPROM_ANTENNA 0x0010 +#define EEPROM_ANTENNA_NUM FIELD16(0x0003) +#define EEPROM_ANTENNA_TX_DEFAULT FIELD16(0x000c) +#define EEPROM_ANTENNA_RX_DEFAULT FIELD16(0x0030) +#define EEPROM_ANTENNA_FRAME_TYPE FIELD16(0x0040) +#define EEPROM_ANTENNA_DYN_TXAGC FIELD16(0x0200) +#define EEPROM_ANTENNA_HARDWARE_RADIO FIELD16(0x0400) +#define EEPROM_ANTENNA_RF_TYPE FIELD16(0xf800) + +/* + * EEPROM NIC config. + * EXTERNAL_LNA: External LNA. + */ +#define EEPROM_NIC 0x0011 +#define EEPROM_NIC_EXTERNAL_LNA FIELD16(0x0010) + +/* + * EEPROM geography. + * GEO_A: Default geographical setting for 5GHz band + * GEO: Default geographical setting. + */ +#define EEPROM_GEOGRAPHY 0x0012 +#define EEPROM_GEOGRAPHY_GEO_A FIELD16(0x00ff) +#define EEPROM_GEOGRAPHY_GEO FIELD16(0xff00) + +/* + * EEPROM BBP. + */ +#define EEPROM_BBP_START 0x0013 +#define EEPROM_BBP_SIZE 16 +#define EEPROM_BBP_VALUE FIELD16(0x00ff) +#define EEPROM_BBP_REG_ID FIELD16(0xff00) + +/* + * EEPROM TXPOWER 802.11G + */ +#define EEPROM_TXPOWER_G_START 0x0023 +#define EEPROM_TXPOWER_G_SIZE 7 +#define EEPROM_TXPOWER_G_1 FIELD16(0x00ff) +#define EEPROM_TXPOWER_G_2 FIELD16(0xff00) + +/* + * EEPROM Frequency + */ +#define EEPROM_FREQ 0x002f +#define EEPROM_FREQ_OFFSET FIELD16(0x00ff) +#define EEPROM_FREQ_SEQ_MASK FIELD16(0xff00) +#define EEPROM_FREQ_SEQ FIELD16(0x0300) + +/* + * EEPROM LED. + * POLARITY_RDY_G: Polarity RDY_G setting. + * POLARITY_RDY_A: Polarity RDY_A setting. + * POLARITY_ACT: Polarity ACT setting. + * POLARITY_GPIO_0: Polarity GPIO0 setting. + * POLARITY_GPIO_1: Polarity GPIO1 setting. + * POLARITY_GPIO_2: Polarity GPIO2 setting. + * POLARITY_GPIO_3: Polarity GPIO3 setting. + * POLARITY_GPIO_4: Polarity GPIO4 setting. + * LED_MODE: Led mode. + */ +#define EEPROM_LED 0x0030 +#define EEPROM_LED_POLARITY_RDY_G FIELD16(0x0001) +#define EEPROM_LED_POLARITY_RDY_A FIELD16(0x0002) +#define EEPROM_LED_POLARITY_ACT FIELD16(0x0004) +#define EEPROM_LED_POLARITY_GPIO_0 FIELD16(0x0008) +#define EEPROM_LED_POLARITY_GPIO_1 FIELD16(0x0010) +#define EEPROM_LED_POLARITY_GPIO_2 FIELD16(0x0020) +#define EEPROM_LED_POLARITY_GPIO_3 FIELD16(0x0040) +#define EEPROM_LED_POLARITY_GPIO_4 FIELD16(0x0080) +#define EEPROM_LED_LED_MODE FIELD16(0x1f00) + +/* + * EEPROM TXPOWER 802.11A + */ +#define EEPROM_TXPOWER_A_START 0x0031 +#define EEPROM_TXPOWER_A_SIZE 12 +#define EEPROM_TXPOWER_A_1 FIELD16(0x00ff) +#define EEPROM_TXPOWER_A_2 FIELD16(0xff00) + +/* + * EEPROM RSSI offset 802.11BG + */ +#define EEPROM_RSSI_OFFSET_BG 0x004d +#define EEPROM_RSSI_OFFSET_BG_1 FIELD16(0x00ff) +#define EEPROM_RSSI_OFFSET_BG_2 FIELD16(0xff00) + +/* + * EEPROM RSSI offset 802.11A + */ +#define EEPROM_RSSI_OFFSET_A 0x004e +#define EEPROM_RSSI_OFFSET_A_1 FIELD16(0x00ff) +#define EEPROM_RSSI_OFFSET_A_2 FIELD16(0xff00) + +/* + * DMA descriptor defines. + */ +#define TXD_DESC_SIZE ( 6 * sizeof(struct data_desc) ) +#define RXD_DESC_SIZE ( 6 * sizeof(struct data_desc) ) + +/* + * TX descriptor format for TX, PRIO and Beacon Ring. + */ + +/* + * Word0 + * BURST: Next frame belongs to same "burst" event. + * TKIP_MIC: ASIC appends TKIP MIC if TKIP is used. + * KEY_TABLE: Use per-client pairwise KEY table. + * KEY_INDEX: + * Key index (0~31) to the pairwise KEY table. + * 0~3 to shared KEY table 0 (BSS0). + * 4~7 to shared KEY table 1 (BSS1). + * 8~11 to shared KEY table 2 (BSS2). + * 12~15 to shared KEY table 3 (BSS3). + * BURST2: For backward compatibility, set to same value as BURST. + */ +#define TXD_W0_BURST FIELD32(0x00000001) +#define TXD_W0_VALID FIELD32(0x00000002) +#define TXD_W0_MORE_FRAG FIELD32(0x00000004) +#define TXD_W0_ACK FIELD32(0x00000008) +#define TXD_W0_TIMESTAMP FIELD32(0x00000010) +#define TXD_W0_OFDM FIELD32(0x00000020) +#define TXD_W0_IFS FIELD32(0x00000040) +#define TXD_W0_RETRY_MODE FIELD32(0x00000080) +#define TXD_W0_TKIP_MIC FIELD32(0x00000100) +#define TXD_W0_KEY_TABLE FIELD32(0x00000200) +#define TXD_W0_KEY_INDEX FIELD32(0x0000fc00) +#define TXD_W0_DATABYTE_COUNT FIELD32(0x0fff0000) +#define TXD_W0_BURST2 FIELD32(0x10000000) +#define TXD_W0_CIPHER_ALG FIELD32(0xe0000000) + +/* + * Word1 + * HOST_Q_ID: EDCA/HCCA queue ID. + * HW_SEQUENCE: MAC overwrites the frame sequence number. + * BUFFER_COUNT: Number of buffers in this TXD. + */ +#define TXD_W1_HOST_Q_ID FIELD32(0x0000000f) +#define TXD_W1_AIFSN FIELD32(0x000000f0) +#define TXD_W1_CWMIN FIELD32(0x00000f00) +#define TXD_W1_CWMAX FIELD32(0x0000f000) +#define TXD_W1_IV_OFFSET FIELD32(0x003f0000) +#define TXD_W1_HW_SEQUENCE FIELD32(0x10000000) +#define TXD_W1_BUFFER_COUNT FIELD32(0xe0000000) + +/* + * Word2: PLCP information + */ +#define TXD_W2_PLCP_SIGNAL FIELD32(0x000000ff) +#define TXD_W2_PLCP_SERVICE FIELD32(0x0000ff00) +#define TXD_W2_PLCP_LENGTH_LOW FIELD32(0x00ff0000) +#define TXD_W2_PLCP_LENGTH_HIGH FIELD32(0xff000000) + +/* + * Word3 + */ +#define TXD_W3_IV FIELD32(0xffffffff) + +/* + * Word4 + */ +#define TXD_W4_EIV FIELD32(0xffffffff) + +/* + * Word5 + * FRAME_OFFSET: Frame start offset inside ASIC TXFIFO (after TXINFO field). + * PACKET_ID: Driver assigned packet ID to categorize TXResult in interrupt. + * WAITING_DMA_DONE_INT: TXD been filled with data + * and waiting for TxDoneISR housekeeping. + */ +#define TXD_W5_FRAME_OFFSET FIELD32(0x000000ff) +#define TXD_W5_PACKET_ID FIELD32(0x0000ff00) +#define TXD_W5_TX_POWER FIELD32(0x00ff0000) +#define TXD_W5_WAITING_DMA_DONE_INT FIELD32(0x01000000) + +/* + * RX descriptor format for RX Ring. + */ + +/* + * Word0 + * CIPHER_ERROR: 1:ICV error, 2:MIC error, 3:invalid key. + * KEY_INDEX: Decryption key actually used. + */ +#define RXD_W0_OWNER_NIC FIELD32(0x00000001) +#define RXD_W0_DROP FIELD32(0x00000002) +#define RXD_W0_UNICAST_TO_ME FIELD32(0x00000004) +#define RXD_W0_MULTICAST FIELD32(0x00000008) +#define RXD_W0_BROADCAST FIELD32(0x00000010) +#define RXD_W0_MY_BSS FIELD32(0x00000020) +#define RXD_W0_CRC_ERROR FIELD32(0x00000040) +#define RXD_W0_OFDM FIELD32(0x00000080) +#define RXD_W0_CIPHER_ERROR FIELD32(0x00000300) +#define RXD_W0_KEY_INDEX FIELD32(0x0000fc00) +#define RXD_W0_DATABYTE_COUNT FIELD32(0x0fff0000) +#define RXD_W0_CIPHER_ALG FIELD32(0xe0000000) + +/* + * WORD1 + * SIGNAL: RX raw data rate reported by BBP. + * RSSI: RSSI reported by BBP. + */ +#define RXD_W1_SIGNAL FIELD32(0x000000ff) +#define RXD_W1_RSSI_AGC FIELD32(0x00001f00) +#define RXD_W1_RSSI_LNA FIELD32(0x00006000) +#define RXD_W1_FRAME_OFFSET FIELD32(0x7f000000) + +/* + * Word2 + * IV: Received IV of originally encrypted. + */ +#define RXD_W2_IV FIELD32(0xffffffff) + +/* + * Word3 + * EIV: Received EIV of originally encrypted. + */ +#define RXD_W3_EIV FIELD32(0xffffffff) + +/* + * Word4 + */ +#define RXD_W4_RESERVED FIELD32(0xffffffff) + +/* + * the above 20-byte is called RXINFO and will be DMAed to MAC RX block + * and passed to the HOST driver. + * The following fields are for DMA block and HOST usage only. + * Can't be touched by ASIC MAC block. + */ + +/* + * Word5 + */ +#define RXD_W5_RESERVED FIELD32(0xffffffff) + +/* + * Macro's for converting txpower from EEPROM to dscape value + * and from dscape value to register value. + */ +#define MIN_TXPOWER 0 +#define MAX_TXPOWER 31 +#define DEFAULT_TXPOWER 24 + +#define TXPOWER_FROM_DEV(__txpower) \ +({ \ + ((__txpower) > MAX_TXPOWER) ? \ + DEFAULT_TXPOWER : (__txpower); \ +}) + +#define TXPOWER_TO_DEV(__txpower) \ +({ \ + ((__txpower) <= MIN_TXPOWER) ? MIN_TXPOWER : \ + (((__txpower) >= MAX_TXPOWER) ? MAX_TXPOWER : \ + (__txpower)); \ +}) + +#endif /* RT73USB_H */ -- cgit v1.2.3-70-g09d2 From 0795af5729b18218767fab27c44b1384f72dc9ad Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 3 Oct 2007 17:59:30 -0700 Subject: [NET]: Introduce and use print_mac() and DECLARE_MAC_BUF() This is nicer than the MAC_FMT stuff. Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/3c503.c | 4 +- drivers/net/3c505.c | 10 +- drivers/net/3c507.c | 6 +- drivers/net/3c509.c | 18 +-- drivers/net/3c515.c | 4 +- drivers/net/3c523.c | 22 ++- drivers/net/3c527.c | 7 +- drivers/net/3c59x.c | 7 +- drivers/net/8139cp.c | 8 +- drivers/net/8139too.c | 8 +- drivers/net/82596.c | 18 +-- drivers/net/a2065.c | 6 +- drivers/net/ac3200.c | 8 +- drivers/net/acenic.c | 7 +- drivers/net/amd8111e.c | 12 +- drivers/net/apne.c | 9 +- drivers/net/ariadne.c | 44 +++--- drivers/net/arm/am79c961a.c | 8 +- drivers/net/arm/at91_ether.c | 18 +-- drivers/net/arm/ether1.c | 8 +- drivers/net/arm/ether3.c | 8 +- drivers/net/arm/etherh.c | 8 +- drivers/net/at1700.c | 4 +- drivers/net/atarilance.c | 43 +++-- drivers/net/atp.c | 8 +- drivers/net/b44.c | 9 +- drivers/net/bmac.c | 6 +- drivers/net/bnx2.c | 12 +- drivers/net/bonding/bond_main.c | 34 ++-- drivers/net/bonding/bond_sysfs.c | 11 +- drivers/net/cassini.c | 11 +- drivers/net/cris/eth_v10.c | 8 +- drivers/net/cs89x0.c | 15 +- drivers/net/de600.c | 6 +- drivers/net/de620.c | 8 +- drivers/net/declance.c | 14 +- drivers/net/depca.c | 13 +- drivers/net/dgrs.c | 18 +-- drivers/net/dl2k.c | 7 +- drivers/net/dm9000.c | 9 +- drivers/net/e100.c | 9 +- drivers/net/e1000/e1000_main.c | 5 +- drivers/net/eepro.c | 5 +- drivers/net/eepro100.c | 9 +- drivers/net/epic100.c | 9 +- drivers/net/es3210.c | 22 +-- drivers/net/ewrk3.c | 16 +- drivers/net/fealnx.c | 9 +- drivers/net/fec.c | 7 +- drivers/net/forcedeth.c | 12 +- drivers/net/gianfar.c | 7 +- drivers/net/hamachi.c | 8 +- drivers/net/hamradio/bpqether.c | 23 +-- drivers/net/hp-plus.c | 6 +- drivers/net/hp.c | 5 +- drivers/net/hp100.c | 6 +- drivers/net/hydra.c | 7 +- drivers/net/ibm_emac/ibm_emac_core.c | 14 +- drivers/net/ibmlana.c | 6 +- drivers/net/ibmveth.c | 9 +- drivers/net/ioc3-eth.c | 12 +- drivers/net/isa-skeleton.c | 5 +- drivers/net/jazzsonic.c | 10 +- drivers/net/lance.c | 6 +- drivers/net/lguest_net.c | 4 +- drivers/net/lib82596.c | 18 +-- drivers/net/lne390.c | 9 +- drivers/net/mac89x0.c | 11 +- drivers/net/macb.c | 6 +- drivers/net/mace.c | 9 +- drivers/net/macmace.c | 6 +- drivers/net/macsonic.c | 21 +-- drivers/net/meth.c | 6 +- drivers/net/mv643xx_eth.c | 5 +- drivers/net/mvme147.c | 11 +- drivers/net/myri10ge/myri10ge.c | 11 +- drivers/net/myri_sbus.c | 29 ++-- drivers/net/natsemi.c | 11 +- drivers/net/ne-h8300.c | 8 +- drivers/net/ne.c | 5 +- drivers/net/ne2.c | 17 +- drivers/net/ne2k-pci.c | 11 +- drivers/net/ne3210.c | 11 +- drivers/net/netconsole.c | 14 +- drivers/net/netxen/netxen_nic_main.c | 13 +- drivers/net/netxen/netxen_nic_niu.c | 14 +- drivers/net/ni5010.c | 4 +- drivers/net/ns83820.c | 7 +- drivers/net/pasemi_mac.c | 6 +- drivers/net/pci-skeleton.c | 9 +- drivers/net/pcmcia/3c574_cs.c | 9 +- drivers/net/pcmcia/3c589_cs.c | 10 +- drivers/net/pcmcia/axnet_cs.c | 9 +- drivers/net/pcmcia/fmvj18x_cs.c | 8 +- drivers/net/pcmcia/nmclan_cs.c | 9 +- drivers/net/pcmcia/pcnet_cs.c | 7 +- drivers/net/pcmcia/smc91c92_cs.c | 8 +- drivers/net/pcmcia/xirc2ps_cs.c | 9 +- drivers/net/pppoe.c | 8 +- drivers/net/ps3_gelic_net.c | 7 +- drivers/net/qla3xxx.c | 7 +- drivers/net/rionet.c | 6 +- drivers/net/rrunner.c | 8 +- drivers/net/s2io.c | 11 +- drivers/net/sb1250-mac.c | 7 +- drivers/net/seeq8005.c | 4 +- drivers/net/sgiseeq.c | 6 +- drivers/net/sis190.c | 10 +- drivers/net/sis900.c | 9 +- drivers/net/skge.c | 7 +- drivers/net/sky2.c | 7 +- drivers/net/smc-mca.c | 8 +- drivers/net/smc-ultra.c | 8 +- drivers/net/smc-ultra32.c | 8 +- drivers/net/smc9194.c | 7 +- drivers/net/smc91x.c | 9 +- drivers/net/starfire.c | 26 ++-- drivers/net/sun3lance.c | 36 ++--- drivers/net/sunbmac.c | 8 +- drivers/net/sundance.c | 10 +- drivers/net/sungem.c | 12 +- drivers/net/sunhme.c | 12 +- drivers/net/sunlance.c | 9 +- drivers/net/tokenring/abyss.c | 12 +- drivers/net/tokenring/ibmtr.c | 26 ++-- drivers/net/tokenring/lanstreamer.c | 64 ++++---- drivers/net/tokenring/madgemc.c | 19 +-- drivers/net/tokenring/olympic.c | 138 +++++++---------- drivers/net/tokenring/proteon.c | 8 +- drivers/net/tokenring/skisa.c | 8 +- drivers/net/tokenring/tmspci.c | 10 +- drivers/net/tsi108_eth.c | 7 +- drivers/net/tulip/de2104x.c | 9 +- drivers/net/tulip/de4x5.c | 33 ++-- drivers/net/tulip/dmfe.c | 15 +- drivers/net/tulip/tulip_core.c | 15 +- drivers/net/tulip/uli526x.c | 9 +- drivers/net/tulip/winbond-840.c | 29 ++-- drivers/net/tulip/xircom_cb.c | 7 +- drivers/net/tun.c | 33 ++-- drivers/net/typhoon.c | 10 +- drivers/net/usb/pegasus.c | 11 +- drivers/net/usb/usbnet.c | 8 +- drivers/net/via-rhine.c | 13 +- drivers/net/wd.c | 7 +- drivers/net/wireless/adm8211.c | 5 +- drivers/net/wireless/airo.c | 32 ++-- drivers/net/wireless/arlan-main.c | 23 +-- drivers/net/wireless/atmel.c | 7 +- drivers/net/wireless/b43/main.c | 5 +- drivers/net/wireless/b43legacy/main.c | 3 +- drivers/net/wireless/bcm43xx/bcm43xx.h | 6 - drivers/net/wireless/hostap/hostap_80211_rx.c | 49 +++--- drivers/net/wireless/hostap/hostap_80211_tx.c | 13 +- drivers/net/wireless/hostap/hostap_ap.c | 198 +++++++++++++---------- drivers/net/wireless/hostap/hostap_common.h | 3 - drivers/net/wireless/hostap/hostap_hw.c | 11 +- drivers/net/wireless/hostap/hostap_info.c | 17 +- drivers/net/wireless/hostap/hostap_ioctl.c | 15 +- drivers/net/wireless/hostap/hostap_main.c | 30 ++-- drivers/net/wireless/hostap/hostap_proc.c | 15 +- drivers/net/wireless/ipw2100.c | 48 +++--- drivers/net/wireless/ipw2200.c | 207 ++++++++++++++----------- drivers/net/wireless/iwlwifi/iwl-3945-rs.c | 5 +- drivers/net/wireless/iwlwifi/iwl-3945.c | 34 ++-- drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 17 +- drivers/net/wireless/iwlwifi/iwl-4965.c | 73 +++++---- drivers/net/wireless/iwlwifi/iwl3945-base.c | 65 +++++--- drivers/net/wireless/iwlwifi/iwl4965-base.c | 59 ++++--- drivers/net/wireless/libertas/assoc.c | 19 ++- drivers/net/wireless/libertas/cmdresp.c | 5 +- drivers/net/wireless/libertas/debugfs.c | 5 +- drivers/net/wireless/libertas/join.c | 16 +- drivers/net/wireless/libertas/main.c | 12 +- drivers/net/wireless/libertas/scan.c | 14 +- drivers/net/wireless/libertas/wext.c | 5 +- drivers/net/wireless/netwave_cs.c | 14 +- drivers/net/wireless/orinoco.c | 7 +- drivers/net/wireless/prism54/isl_ioctl.c | 50 ++---- drivers/net/wireless/ray_cs.c | 13 +- drivers/net/wireless/rt2x00/rt2400pci.c | 4 +- drivers/net/wireless/rt2x00/rt2500pci.c | 5 +- drivers/net/wireless/rt2x00/rt2500usb.c | 4 +- drivers/net/wireless/rt2x00/rt61pci.c | 4 +- drivers/net/wireless/rt2x00/rt73usb.c | 4 +- drivers/net/wireless/rtl8187_dev.c | 5 +- drivers/net/wireless/wavelan.c | 53 +++---- drivers/net/wireless/wavelan_cs.c | 54 +++---- drivers/net/wireless/wl3501_cs.c | 22 +-- drivers/net/wireless/zd1211rw/zd_chip.c | 3 +- drivers/net/wireless/zd1211rw/zd_mac.c | 8 +- drivers/net/yellowfin.c | 19 ++- drivers/net/znet.c | 11 +- drivers/net/zorro8390.c | 15 +- include/linux/if_ether.h | 8 + include/net/ieee80211.h | 5 - include/net/mac80211.h | 4 - net/802/tr.c | 28 ++-- net/appletalk/aarp.c | 9 +- net/atm/br2684.c | 16 +- net/atm/lec.c | 29 ++-- net/core/netpoll.c | 12 +- net/core/pktgen.c | 17 +- net/ethernet/eth.c | 8 + net/ieee80211/ieee80211_crypt_ccmp.c | 27 ++-- net/ieee80211/ieee80211_crypt_tkip.c | 31 ++-- net/ieee80211/ieee80211_rx.c | 59 +++---- net/ieee80211/ieee80211_wx.c | 5 +- net/ieee80211/softmac/ieee80211softmac_assoc.c | 4 +- net/ieee80211/softmac/ieee80211softmac_auth.c | 35 +++-- net/ieee80211/softmac/ieee80211softmac_wx.c | 1 + net/irda/irlan/irlan_client.c | 6 +- net/llc/llc_proc.c | 12 +- net/mac80211/debugfs_key.c | 3 +- net/mac80211/debugfs_netdev.c | 3 +- net/mac80211/debugfs_sta.c | 6 +- net/mac80211/event.c | 5 +- net/mac80211/ieee80211.c | 5 +- net/mac80211/ieee80211_ioctl.c | 5 +- net/mac80211/ieee80211_sta.c | 180 +++++++++++---------- net/mac80211/key.c | 10 +- net/mac80211/rc80211_simple.c | 5 +- net/mac80211/rx.c | 103 ++++++------ net/mac80211/sta_info.c | 13 +- net/mac80211/tkip.c | 10 +- net/mac80211/tx.c | 32 ++-- net/mac80211/wpa.c | 19 ++- net/tipc/eth_media.c | 4 +- 228 files changed, 1875 insertions(+), 1952 deletions(-) (limited to 'drivers') diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c index f9e7ffbcb77..9c23336750e 100644 --- a/drivers/net/3c503.c +++ b/drivers/net/3c503.c @@ -177,6 +177,7 @@ el2_probe1(struct net_device *dev, int ioaddr) int i, iobase_reg, membase_reg, saved_406, wordlength, retval; static unsigned version_printed; unsigned long vendor_id; + DECLARE_MAC_BUF(mac); if (!request_region(ioaddr, EL2_IO_EXTENT, DRV_NAME)) return -EBUSY; @@ -226,7 +227,8 @@ el2_probe1(struct net_device *dev, int ioaddr) /* Retrieve and print the ethernet address. */ for (i = 0; i < 6; i++) - printk(" %2.2x", dev->dev_addr[i] = inb(ioaddr + i)); + dev->dev_addr[i] = inb(ioaddr + i); + printk("%s", print_mac(mac, dev->dev_addr)); /* Map the 8390 back into the window. */ outb(ECNTRL_THIN, ioaddr + 0x406); diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c index c05bb3fc57a..9c6573419f5 100644 --- a/drivers/net/3c505.c +++ b/drivers/net/3c505.c @@ -1386,6 +1386,7 @@ static int __init elplus_setup(struct net_device *dev) unsigned long timeout; unsigned long cookie = 0; int err = -ENODEV; + DECLARE_MAC_BUF(mac); /* * setup adapter structure @@ -1521,11 +1522,10 @@ static int __init elplus_setup(struct net_device *dev) /* * print remainder of startup message */ - printk(KERN_INFO "%s: 3c505 at %#lx, irq %d, dma %d, ", - dev->name, dev->base_addr, dev->irq, dev->dma); - printk("addr %02x:%02x:%02x:%02x:%02x:%02x, ", - dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + printk(KERN_INFO "%s: 3c505 at %#lx, irq %d, dma %d, " + "addr %s, ", + dev->name, dev->base_addr, dev->irq, dev->dma, + print_mac(mac, dev->dev_addr)); /* * read more information from the adapter diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c index 3d06271c3a8..964d31ac944 100644 --- a/drivers/net/3c507.c +++ b/drivers/net/3c507.c @@ -357,6 +357,7 @@ static int __init el16_probe1(struct net_device *dev, int ioaddr) static unsigned char init_ID_done, version_printed; int i, irq, irqval, retval; struct net_local *lp; + DECLARE_MAC_BUF(mac); if (init_ID_done == 0) { ushort lrs_state = 0xff; @@ -402,10 +403,9 @@ static int __init el16_probe1(struct net_device *dev, int ioaddr) dev->base_addr = ioaddr; outb(0x01, ioaddr + MISC_CTRL); - for (i = 0; i < 6; i++) { + for (i = 0; i < 6; i++) dev->dev_addr[i] = inb(ioaddr + i); - printk(" %02x", dev->dev_addr[i]); - } + printk(" %s", print_mac(mac, dev->dev_addr)); if (mem_start) net_debug = mem_start & 7; diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index 7466987d845..c576fe76d54 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -313,8 +313,9 @@ static int nopnp; static int __init el3_common_init(struct net_device *dev) { struct el3_private *lp = netdev_priv(dev); - short i; int err; + DECLARE_MAC_BUF(mac); + const char *if_names[] = {"10baseT", "AUI", "undefined", "BNC"}; spin_lock_init(&lp->lock); @@ -346,17 +347,10 @@ static int __init el3_common_init(struct net_device *dev) return err; } - { - const char *if_names[] = {"10baseT", "AUI", "undefined", "BNC"}; - printk("%s: 3c5x9 found at %#3.3lx, %s port, address ", - dev->name, dev->base_addr, - if_names[(dev->if_port & 0x03)]); - } - - /* Read in the station address. */ - for (i = 0; i < 6; i++) - printk(" %2.2x", dev->dev_addr[i]); - printk(", IRQ %d.\n", dev->irq); + printk(KERN_INFO "%s: 3c5x9 found at %#3.3lx, %s port, " + "address %s, IRQ %d.\n", + dev->name, dev->base_addr, if_names[(dev->if_port & 0x03)], + print_mac(mac, dev->dev_addr), dev->irq); if (el3_debug > 0) printk(KERN_INFO "%s", version); diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c index 38a2ebea9b4..275e7510eba 100644 --- a/drivers/net/3c515.c +++ b/drivers/net/3c515.c @@ -569,6 +569,7 @@ static int corkscrew_setup(struct net_device *dev, int ioaddr, unsigned int eeprom[0x40], checksum = 0; /* EEPROM contents */ int i; int irq; + DECLARE_MAC_BUF(mac); if (idev) { irq = pnp_irq(idev, 0); @@ -630,8 +631,7 @@ static int corkscrew_setup(struct net_device *dev, int ioaddr, checksum = (checksum ^ (checksum >> 8)) & 0xff; if (checksum != 0x00) printk(" ***INVALID CHECKSUM %4.4x*** ", checksum); - for (i = 0; i < 6; i++) - printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]); + printk(" %s", print_mac(mac, dev->dev_addr)); if (eeprom[16] == 0x11c7) { /* Corkscrew */ if (request_dma(dev->dma, "3c515")) { printk(", DMA %d allocation failed", dev->dma); diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c index 10852b2a40a..239fc42fb8d 100644 --- a/drivers/net/3c523.c +++ b/drivers/net/3c523.c @@ -383,8 +383,8 @@ void alloc586(struct net_device *dev) static int elmc_getinfo(char *buf, int slot, void *d) { int len = 0; - struct net_device *dev = (struct net_device *) d; - int i; + struct net_device *dev = d; + DECLARE_MAC_BUF(mac); if (dev == NULL) return len; @@ -399,12 +399,8 @@ static int elmc_getinfo(char *buf, int slot, void *d) len += sprintf(buf + len, "Transceiver: %s\n", dev->if_port ? "External" : "Internal"); len += sprintf(buf + len, "Device: %s\n", dev->name); - len += sprintf(buf + len, "Hardware Address:"); - for (i = 0; i < 6; i++) { - len += sprintf(buf + len, " %02x", dev->dev_addr[i]); - } - buf[len++] = '\n'; - buf[len] = 0; + len += sprintf(buf + len, "Hardware Address: %s\n", + print_mac(mac, dev->dev_addr)); return len; } /* elmc_getinfo() */ @@ -422,6 +418,7 @@ static int __init do_elmc_probe(struct net_device *dev) unsigned int size = 0; int retval; struct priv *pr = dev->priv; + DECLARE_MAC_BUF(mac); if (MCA_bus == 0) { return -ENODEV; @@ -544,12 +541,11 @@ static int __init do_elmc_probe(struct net_device *dev) /* The hardware address for the 3c523 is stored in the first six bytes of the IO address. */ - printk(KERN_INFO "%s: hardware address ", dev->name); - for (i = 0; i < 6; i++) { + for (i = 0; i < 6; i++) dev->dev_addr[i] = inb(dev->base_addr + i); - printk(" %02x", dev->dev_addr[i]); - } - printk("\n"); + + printk(KERN_INFO "%s: hardware address %s\n", + dev->name, print_mac(mac, dev->dev_addr)); dev->open = &elmc_open; dev->stop = &elmc_close; diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c index 5b5f44cdfc1..b72b89d53ec 100644 --- a/drivers/net/3c527.c +++ b/drivers/net/3c527.c @@ -336,6 +336,7 @@ static int __init mc32_probe1(struct net_device *dev, int slot) "82586 initialisation failure", "Adapter list configuration error" }; + DECLARE_MAC_BUF(mac); /* Time to play MCA games */ @@ -396,17 +397,17 @@ static int __init mc32_probe1(struct net_device *dev, int slot) * Go PROM browsing */ - printk("%s: Address ", dev->name); - /* Retrieve and print the ethernet address. */ for (i = 0; i < 6; i++) { mca_write_pos(slot, 6, i+12); mca_write_pos(slot, 7, 0); - printk(" %2.2x", dev->dev_addr[i] = mca_read_pos(slot,3)); + dev->dev_addr[i] = mca_read_pos(slot,3); } + printk("%s: Address %s", dev->name, print_mac(mac, dev->dev_addr)); + mca_write_pos(slot, 6, 0); mca_write_pos(slot, 7, 0); diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index ad0f6a729d2..58311199e32 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -1014,6 +1014,7 @@ static int __devinit vortex_probe1(struct device *gendev, char *print_name = "3c59x"; struct pci_dev *pdev = NULL; struct eisa_device *edev = NULL; + DECLARE_MAC_BUF(mac); if (!printed_version) { printk (version); @@ -1205,10 +1206,8 @@ static int __devinit vortex_probe1(struct device *gendev, for (i = 0; i < 3; i++) ((u16 *)dev->dev_addr)[i] = htons(eeprom[i + 10]); memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); - if (print_info) { - for (i = 0; i < 6; i++) - printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]); - } + if (print_info) + printk(" %s", print_mac(mac, dev->dev_addr)); /* Unfortunately an all zero eeprom passes the checksum and this gets found in the wild in failure cases. Crypto is hard 8) */ if (!is_valid_ether_addr(dev->dev_addr)) { diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index 58fad1b2f72..7edd50cf777 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -1823,6 +1823,7 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) void __iomem *regs; resource_size_t pciaddr; unsigned int addr_len, i, pci_using_dac; + DECLARE_MAC_BUF(mac); #ifndef MODULE static int version_printed; @@ -1964,13 +1965,10 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out_iomap; printk (KERN_INFO "%s: RTL-8139C+ at 0x%lx, " - "%02x:%02x:%02x:%02x:%02x:%02x, " - "IRQ %d\n", + "%s, IRQ %d\n", dev->name, dev->base_addr, - dev->dev_addr[0], dev->dev_addr[1], - dev->dev_addr[2], dev->dev_addr[3], - dev->dev_addr[4], dev->dev_addr[5], + print_mac(mac, dev->dev_addr), dev->irq); pci_set_drvdata(pdev, dev); diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index 28c1aaf1fe1..d3088a786e2 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -926,6 +926,7 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, int i, addr_len, option; void __iomem *ioaddr; static int board_idx = -1; + DECLARE_MAC_BUF(mac); assert (pdev != NULL); assert (ent != NULL); @@ -1017,14 +1018,11 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, pci_set_drvdata (pdev, dev); printk (KERN_INFO "%s: %s at 0x%lx, " - "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, " - "IRQ %d\n", + "%s, IRQ %d\n", dev->name, board_info[ent->driver_data].name, dev->base_addr, - dev->dev_addr[0], dev->dev_addr[1], - dev->dev_addr[2], dev->dev_addr[3], - dev->dev_addr[4], dev->dev_addr[5], + print_mac(mac, dev->dev_addr), dev->irq); printk (KERN_DEBUG "%s: Identified 8139 chip type '%s'\n", diff --git a/drivers/net/82596.c b/drivers/net/82596.c index 6b03416731d..bb30d5be782 100644 --- a/drivers/net/82596.c +++ b/drivers/net/82596.c @@ -1116,15 +1116,12 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev) static void print_eth(unsigned char *add, char *str) { - int i; + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); - printk(KERN_DEBUG "i596 0x%p, ", add); - for (i = 0; i < 6; i++) - printk(" %02X", add[i + 6]); - printk(" -->"); - for (i = 0; i < 6; i++) - printk(" %02X", add[i]); - printk(" %02X%02X, %s\n", add[12], add[13], str); + printk(KERN_DEBUG "i596 0x%p, %s --> %s %02X%02X, %s\n", + add, print_mac(mac, add + 6), print_mac(mac2, add), + add[12], add[13], str); } static int io = 0x300; @@ -1539,6 +1536,7 @@ static void set_multicast_list(struct net_device *dev) struct dev_mc_list *dmi; unsigned char *cp; struct mc_cmd *cmd; + DECLARE_MAC_BUF(mac); if (wait_cfg(dev, &lp->mc_cmd.cmd, 1000, "multicast list change request timed out")) return; @@ -1549,8 +1547,8 @@ static void set_multicast_list(struct net_device *dev) for (dmi = dev->mc_list; cnt && dmi != NULL; dmi = dmi->next, cnt--, cp += 6) { memcpy(cp, dmi->dmi_addr, 6); if (i596_debug > 1) - DEB(DEB_MULTI,printk(KERN_INFO "%s: Adding address %02x:%02x:%02x:%02x:%02x:%02x\n", - dev->name, cp[0],cp[1],cp[2],cp[3],cp[4],cp[5])); + DEB(DEB_MULTI,printk(KERN_INFO "%s: Adding address %s\n", + dev->name, print_mac(mac, cp))); } i596_add_cmd(dev, &cmd->cmd); } diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c index 77773ce52ef..18f7f815f66 100644 --- a/drivers/net/a2065.c +++ b/drivers/net/a2065.c @@ -716,6 +716,7 @@ static int __devinit a2065_init_one(struct zorro_dev *z, unsigned long board, base_addr, mem_start; struct resource *r1, *r2; int err; + DECLARE_MAC_BUF(mac); board = z->resource.start; base_addr = board+A2065_LANCE; @@ -792,9 +793,8 @@ static int __devinit a2065_init_one(struct zorro_dev *z, zorro_set_drvdata(z, dev); printk(KERN_INFO "%s: A2065 at 0x%08lx, Ethernet Address " - "%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, board, - dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + "%s\n", dev->name, board, + print_mac(mac, dev->dev_addr)); return 0; } diff --git a/drivers/net/ac3200.c b/drivers/net/ac3200.c index 65b2de56ed2..5136d94923a 100644 --- a/drivers/net/ac3200.c +++ b/drivers/net/ac3200.c @@ -146,6 +146,7 @@ out: static int __init ac_probe1(int ioaddr, struct net_device *dev) { int i, retval; + DECLARE_MAC_BUF(mac); if (!request_region(ioaddr, AC_IO_EXTENT, DRV_NAME)) return -EBUSY; @@ -167,10 +168,11 @@ static int __init ac_probe1(int ioaddr, struct net_device *dev) inb(ioaddr + AC_ID_PORT + 2), inb(ioaddr + AC_ID_PORT + 3)); #endif - printk("AC3200 in EISA slot %d, node", ioaddr/0x1000); - for(i = 0; i < 6; i++) - printk(" %02x", dev->dev_addr[i] = inb(ioaddr + AC_SA_PROM + i)); + for (i = 0; i < 6; i++) + dev->dev_addr[i] = inb(ioaddr + AC_SA_PROM + i); + printk(KERN_DEBUG "AC3200 in EISA slot %d, node %s", + ioaddr/0x1000, print_mac(mac, dev->dev_addr)); #if 0 /* Check the vendor ID/prefix. Redundant after checking the EISA ID */ if (inb(ioaddr + AC_SA_PROM + 0) != AC_ADDR0 diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c index ca00f41e4d8..2c2ed6dc98b 100644 --- a/drivers/net/acenic.c +++ b/drivers/net/acenic.c @@ -893,6 +893,7 @@ static int __devinit ace_init(struct net_device *dev) int board_idx, ecode = 0; short i; unsigned char cache_size; + DECLARE_MAC_BUF(mac); ap = netdev_priv(dev); regs = ap->regs; @@ -1012,10 +1013,6 @@ static int __devinit ace_init(struct net_device *dev) writel(mac1, ®s->MacAddrHi); writel(mac2, ®s->MacAddrLo); - printk("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", - (mac1 >> 8) & 0xff, mac1 & 0xff, (mac2 >> 24) &0xff, - (mac2 >> 16) & 0xff, (mac2 >> 8) & 0xff, mac2 & 0xff); - dev->dev_addr[0] = (mac1 >> 8) & 0xff; dev->dev_addr[1] = mac1 & 0xff; dev->dev_addr[2] = (mac2 >> 24) & 0xff; @@ -1023,6 +1020,8 @@ static int __devinit ace_init(struct net_device *dev) dev->dev_addr[4] = (mac2 >> 8) & 0xff; dev->dev_addr[5] = mac2 & 0xff; + printk("MAC: %s\n", print_mac(mac, dev->dev_addr)); + /* * Looks like this is necessary to deal with on all architectures, * even this %$#%$# N440BX Intel based thing doesn't get it right. diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c index afb60a5927a..73f40a45441 100644 --- a/drivers/net/amd8111e.c +++ b/drivers/net/amd8111e.c @@ -1934,6 +1934,7 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev, unsigned long reg_addr,reg_len; struct amd8111e_priv* lp; struct net_device* dev; + DECLARE_MAC_BUF(mac); err = pci_enable_device(pdev); if(err){ @@ -2006,7 +2007,7 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev, /* Initializing MAC address */ for(i = 0; i < ETH_ADDR_LEN; i++) - dev->dev_addr[i] =readb(lp->mmio + PADR + i); + dev->dev_addr[i] = readb(lp->mmio + PADR + i); /* Setting user defined parametrs */ lp->ext_phy_option = speed_duplex[card_idx]; @@ -2075,11 +2076,10 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev, /* display driver and device information */ chip_version = (readl(lp->mmio + CHIPID) & 0xf0000000)>>28; - printk(KERN_INFO "%s: AMD-8111e Driver Version: %s\n", dev->name,MODULE_VERS); - printk(KERN_INFO "%s: [ Rev %x ] PCI 10/100BaseT Ethernet ", dev->name, chip_version); - for (i = 0; i < 6; i++) - printk("%2.2x%c",dev->dev_addr[i],i == 5 ? ' ' : ':'); - printk( "\n"); + printk(KERN_INFO "%s: AMD-8111e Driver Version: %s\n", + dev->name,MODULE_VERS); + printk(KERN_INFO "%s: [ Rev %x ] PCI 10/100BaseT Ethernet %s\n", + dev->name, chip_version, print_mac(mac, dev->dev_addr)); if (lp->ext_phy_id) printk(KERN_INFO "%s: Found MII PHY ID 0x%08x at address 0x%02x\n", dev->name, lp->ext_phy_id, lp->ext_phy_addr); diff --git a/drivers/net/apne.c b/drivers/net/apne.c index b5a974a964c..c12cbdf368b 100644 --- a/drivers/net/apne.c +++ b/drivers/net/apne.c @@ -204,6 +204,7 @@ static int __init apne_probe1(struct net_device *dev, int ioaddr) int neX000, ctron; #endif static unsigned version_printed; + DECLARE_MAC_BUF(mac); if (ei_debug && version_printed++ == 0) printk(version); @@ -316,12 +317,12 @@ static int __init apne_probe1(struct net_device *dev, int ioaddr) i = request_irq(dev->irq, apne_interrupt, IRQF_SHARED, DRV_NAME, dev); if (i) return i; - for(i = 0; i < ETHER_ADDR_LEN; i++) { - printk(" %2.2x", SA_prom[i]); + for(i = 0; i < ETHER_ADDR_LEN; i++) dev->dev_addr[i] = SA_prom[i]; - } - printk("\n%s: %s found.\n", dev->name, name); + printk(" %s\n", print_mac(mac, dev->dev_addr)); + + printk("%s: %s found.\n", dev->name, name); ei_status.name = name; ei_status.tx_start_page = start_page; diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c index 2c020a36177..3fa3bccd1ad 100644 --- a/drivers/net/ariadne.c +++ b/drivers/net/ariadne.c @@ -166,6 +166,7 @@ static int __devinit ariadne_init_one(struct zorro_dev *z, struct net_device *dev; struct ariadne_private *priv; int err; + DECLARE_MAC_BUF(mac); r1 = request_mem_region(base_addr, sizeof(struct Am79C960), "Am79C960"); if (!r1) @@ -216,9 +217,8 @@ static int __devinit ariadne_init_one(struct zorro_dev *z, zorro_set_drvdata(z, dev); printk(KERN_INFO "%s: Ariadne at 0x%08lx, Ethernet Address " - "%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, board, - dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + "%s\n", dev->name, board, + print_mac(mac, dev->dev_addr)); return 0; } @@ -614,21 +614,17 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Fill in a Tx ring entry */ #if 0 - printk(KERN_DEBUG "TX pkt type 0x%04x from ", ((u_short *)skb->data)[6]); - { - int i; - u_char *ptr = &((u_char *)skb->data)[6]; - for (i = 0; i < 6; i++) - printk("%02x", ptr[i]); - } - printk(" to "); - { - int i; - u_char *ptr = (u_char *)skb->data; - for (i = 0; i < 6; i++) - printk("%02x", ptr[i]); - } - printk(" data 0x%08x len %d\n", (int)skb->data, (int)skb->len); +{ + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); + + printk(KERN_DEBUG "TX pkt type 0x%04x from %s to %s " + " data 0x%08x len %d\n", + ((u_short *)skb->data)[6], + print_mac(mac, ((const u8 *)skb->data)+6), + print_mac(mac, (const u8 *)skb->data), + (int)skb->data, (int)skb->len); +} #endif local_irq_save(flags); @@ -748,22 +744,22 @@ static int ariadne_rx(struct net_device *dev) skb_copy_to_linear_data(skb, (char *)priv->rx_buff[entry], pkt_len); skb->protocol=eth_type_trans(skb,dev); #if 0 +{ + DECLARE_MAC_BUF(mac); + printk(KERN_DEBUG "RX pkt type 0x%04x from ", ((u_short *)skb->data)[6]); { - int i; u_char *ptr = &((u_char *)skb->data)[6]; - for (i = 0; i < 6; i++) - printk("%02x", ptr[i]); + printk("%s", print_mac(mac, ptr)); } printk(" to "); { - int i; u_char *ptr = (u_char *)skb->data; - for (i = 0; i < 6; i++) - printk("%02x", ptr[i]); + printk("%s", print_mac(mac, ptr)); } printk(" data 0x%08x len %d\n", (int)skb->data, (int)skb->len); +} #endif netif_rx(skb); diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c index 77964556776..ba6bd03a015 100644 --- a/drivers/net/arm/am79c961a.c +++ b/drivers/net/arm/am79c961a.c @@ -741,12 +741,10 @@ static int __init am79c961_probe(struct platform_device *pdev) ret = register_netdev(dev); if (ret == 0) { - printk(KERN_INFO "%s: ether address ", dev->name); - - /* Retrive and print the ethernet address. */ - for (i = 0; i < 6; i++) - printk (i == 5 ? "%02x\n" : "%02x:", dev->dev_addr[i]); + DECLARE_MAC_BUF(mac); + printk(KERN_INFO "%s: ether address %s\n", + dev->name, print_mac(mac, dev->dev_addr)); return 0; } diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c index 619810a01e5..25b114a4e2b 100644 --- a/drivers/net/arm/at91_ether.c +++ b/drivers/net/arm/at91_ether.c @@ -485,6 +485,7 @@ static void update_mac_address(struct net_device *dev) static int set_mac_address(struct net_device *dev, void* addr) { struct sockaddr *address = addr; + DECLARE_MAC_BUF(mac); if (!is_valid_ether_addr(address->sa_data)) return -EADDRNOTAVAIL; @@ -492,9 +493,8 @@ static int set_mac_address(struct net_device *dev, void* addr) memcpy(dev->dev_addr, address->sa_data, dev->addr_len); update_mac_address(dev); - printk("%s: Setting MAC address to %02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, - dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + printk("%s: Setting MAC address to %s\n", dev->name, + print_mac(mac, dev->dev_addr)); return 0; } @@ -979,6 +979,7 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add struct at91_private *lp; unsigned int val; int res; + DECLARE_MAC_BUF(mac); dev = alloc_etherdev(sizeof(struct at91_private)); if (!dev) @@ -1081,12 +1082,11 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add } /* Display ethernet banner */ - printk(KERN_INFO "%s: AT91 ethernet at 0x%08x int=%d %s%s (%02x:%02x:%02x:%02x:%02x:%02x)\n", - dev->name, (uint) dev->base_addr, dev->irq, - at91_emac_read(AT91_EMAC_CFG) & AT91_EMAC_SPD ? "100-" : "10-", - at91_emac_read(AT91_EMAC_CFG) & AT91_EMAC_FD ? "FullDuplex" : "HalfDuplex", - dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + printk(KERN_INFO "%s: AT91 ethernet at 0x%08x int=%d %s%s (%s)\n", + dev->name, (uint) dev->base_addr, dev->irq, + at91_emac_read(AT91_EMAC_CFG) & AT91_EMAC_SPD ? "100-" : "10-", + at91_emac_read(AT91_EMAC_CFG) & AT91_EMAC_FD ? "FullDuplex" : "HalfDuplex", + print_mac(mac, dev->dev_addr)); if ((phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) printk(KERN_INFO "%s: Davicom 9161 PHY %s\n", dev->name, (lp->phy_media == PORT_FIBRE) ? "(Fiber)" : "(Copper)"); else if (phy_type == MII_LXT971A_ID) diff --git a/drivers/net/arm/ether1.c b/drivers/net/arm/ether1.c index 6ec8a587c1d..3bb9e293e2e 100644 --- a/drivers/net/arm/ether1.c +++ b/drivers/net/arm/ether1.c @@ -996,6 +996,7 @@ ether1_probe(struct expansion_card *ec, const struct ecard_id *id) { struct net_device *dev; int i, ret = 0; + DECLARE_MAC_BUF(mac); ether1_banner(); @@ -1043,12 +1044,9 @@ ether1_probe(struct expansion_card *ec, const struct ecard_id *id) if (ret) goto free; - printk(KERN_INFO "%s: ether1 in slot %d, ", - dev->name, ec->slot_no); + printk(KERN_INFO "%s: ether1 in slot %d, %s\n", + dev->name, ec->slot_no, print_mac(mac, dev->dev_addr)); - for (i = 0; i < 6; i++) - printk ("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':'); - ecard_set_drvdata(ec, dev); return 0; diff --git a/drivers/net/arm/ether3.c b/drivers/net/arm/ether3.c index 4a914748c0e..67e96ae8503 100644 --- a/drivers/net/arm/ether3.c +++ b/drivers/net/arm/ether3.c @@ -775,7 +775,8 @@ ether3_probe(struct expansion_card *ec, const struct ecard_id *id) { const struct ether3_data *data = id->data; struct net_device *dev; - int i, bus_type, ret; + int bus_type, ret; + DECLARE_MAC_BUF(mac); ether3_banner(); @@ -858,9 +859,8 @@ ether3_probe(struct expansion_card *ec, const struct ecard_id *id) if (ret) goto free; - printk("%s: %s in slot %d, ", dev->name, data->name, ec->slot_no); - for (i = 0; i < 6; i++) - printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':'); + printk("%s: %s in slot %d, %s\n", + dev->name, data->name, ec->slot_no, print_mac(mac, dev->dev_addr)); ecard_set_drvdata(ec, dev); return 0; diff --git a/drivers/net/arm/etherh.c b/drivers/net/arm/etherh.c index 5d093b3ddcd..00081d2b9cd 100644 --- a/drivers/net/arm/etherh.c +++ b/drivers/net/arm/etherh.c @@ -648,6 +648,7 @@ etherh_probe(struct expansion_card *ec, const struct ecard_id *id) struct net_device *dev; struct etherh_priv *eh; int i, ret; + DECLARE_MAC_BUF(mac); etherh_banner(); @@ -745,11 +746,8 @@ etherh_probe(struct expansion_card *ec, const struct ecard_id *id) if (ret) goto free; - printk(KERN_INFO "%s: %s in slot %d, ", - dev->name, data->name, ec->slot_no); - - for (i = 0; i < 6; i++) - printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':'); + printk(KERN_INFO "%s: %s in slot %d, %s\n", + dev->name, data->name, ec->slot_no, print_mac(mac, dev->dev_addr)); ecard_set_drvdata(ec, dev); diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c index a124fdb2bce..b032c1bf492 100644 --- a/drivers/net/at1700.c +++ b/drivers/net/at1700.c @@ -265,6 +265,7 @@ static int __init at1700_probe1(struct net_device *dev, int ioaddr) unsigned int i, irq, is_fmv18x = 0, is_at1700 = 0; int slot, ret = -ENODEV; struct net_local *lp = netdev_priv(dev); + DECLARE_MAC_BUF(mac); if (!request_region(ioaddr, AT1700_IO_EXTENT, DRV_NAME)) return -EBUSY; @@ -388,16 +389,15 @@ found: if (is_at1700) { for(i = 0; i < 3; i++) { unsigned short eeprom_val = read_eeprom(ioaddr, 4+i); - printk("%04x", eeprom_val); ((unsigned short *)dev->dev_addr)[i] = ntohs(eeprom_val); } } else { for(i = 0; i < 6; i++) { unsigned char val = inb(ioaddr + SAPROM + i); - printk("%02x", val); dev->dev_addr[i] = val; } } + printk("%s", print_mac(mac, dev->dev_addr)); /* The EEPROM word 12 bit 0x0400 means use regular 100 ohm 10baseT signals, rather than 150 ohm shielded twisted pair compensation. diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c index 8bf548e1cb4..ebf1a3a88e1 100644 --- a/drivers/net/atarilance.c +++ b/drivers/net/atarilance.c @@ -467,6 +467,7 @@ static unsigned long __init lance_probe1( struct net_device *dev, int i; static int did_version; unsigned short save1, save2; + DECLARE_MAC_BUF(mac); PROBE_PRINT(( "Probing for Lance card at mem %#lx io %#lx\n", (long)memaddr, (long)ioaddr )); @@ -595,8 +596,7 @@ static unsigned long __init lance_probe1( struct net_device *dev, i = IO->mem; break; } - for( i = 0; i < 6; ++i ) - printk( "%02x%s", dev->dev_addr[i], (i < 5) ? ":" : "\n" ); + printk("%s\n", print_mac(mac, dev->dev_addr)); if (lp->cardtype == OLD_RIEBL) { printk( "%s: Warning: This is a default ethernet address!\n", dev->name ); @@ -779,6 +779,8 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) int entry, len; struct lance_tx_head *head; unsigned long flags; + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); DPRINTK( 2, ( "%s: lance_start_xmit() called, csr0 %4.4x.\n", dev->name, DREG )); @@ -801,17 +803,13 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) /* Fill in a Tx ring entry */ if (lance_debug >= 3) { - u_char *p; - int i; - printk( "%s: TX pkt type 0x%04x from ", dev->name, - ((u_short *)skb->data)[6]); - for( p = &((u_char *)skb->data)[6], i = 0; i < 6; i++ ) - printk("%02x%s", *p++, i != 5 ? ":" : "" ); - printk(" to "); - for( p = (u_char *)skb->data, i = 0; i < 6; i++ ) - printk("%02x%s", *p++, i != 5 ? ":" : "" ); - printk(" data at 0x%08x len %d\n", (int)skb->data, - (int)skb->len ); + printk( "%s: TX pkt type 0x%04x from " + "%s to %s" + " data at 0x%08x len %d\n", + dev->name, ((u_short *)skb->data)[6], + print_mac(mac, &skb->data[6]), + print_mac(mac2, skb->data), + (int)skb->data, (int)skb->len ); } /* We're not prepared for the int until the last flags are set/reset. And @@ -1021,19 +1019,18 @@ static int lance_rx( struct net_device *dev ) } if (lance_debug >= 3) { - u_char *data = PKTBUF_ADDR(head), *p; - printk( "%s: RX pkt type 0x%04x from ", dev->name, - ((u_short *)data)[6]); - for( p = &data[6], i = 0; i < 6; i++ ) - printk("%02x%s", *p++, i != 5 ? ":" : "" ); - printk(" to "); - for( p = data, i = 0; i < 6; i++ ) - printk("%02x%s", *p++, i != 5 ? ":" : "" ); - printk(" data %02x %02x %02x %02x %02x %02x %02x %02x " + u_char *data = PKTBUF_ADDR(head); + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); + + printk(KERN_DEBUG "%s: RX pkt type 0x%04x from %s to %s ", + "data %02x %02x %02x %02x %02x %02x %02x %02x " "len %d\n", + dev->name, ((u_short *)data)[6], + print_mac(mac, &data[6]), print_mac(mac2, data), data[15], data[16], data[17], data[18], data[19], data[20], data[21], data[22], - pkt_len ); + pkt_len); } skb_reserve( skb, 2 ); /* 16 byte align */ diff --git a/drivers/net/atp.c b/drivers/net/atp.c index cec2e3672cd..62f09e59d9c 100644 --- a/drivers/net/atp.c +++ b/drivers/net/atp.c @@ -248,6 +248,7 @@ static int __init atp_probe1(long ioaddr) struct net_local *lp; int saved_ctrl_reg, status, i; int res; + DECLARE_MAC_BUF(mac); outb(0xff, ioaddr + PAR_DATA); /* Save the original value of the Control register, in case we guessed @@ -322,10 +323,9 @@ static int __init atp_probe1(long ioaddr) printk(KERN_INFO "%s", version); #endif - printk(KERN_NOTICE "%s: Pocket adapter found at %#3lx, IRQ %d, SAPROM " - "%02X:%02X:%02X:%02X:%02X:%02X.\n", dev->name, dev->base_addr, - dev->irq, dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + printk(KERN_NOTICE "%s: Pocket adapter found at %#3lx, IRQ %d, " + "SAPROM %s.\n", + dev->name, dev->base_addr, dev->irq, print_mac(mac, dev->dev_addr)); /* Reset the ethernet hardware and activate the printer pass-through. */ write_reg_high(ioaddr, CMR1, CMR1h_RESET | CMR1h_MUX); diff --git a/drivers/net/b44.c b/drivers/net/b44.c index 6d193705a3b..40842a6aa99 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -2100,7 +2100,8 @@ static int __devinit b44_init_one(struct pci_dev *pdev, unsigned long b44reg_base, b44reg_len; struct net_device *dev; struct b44 *bp; - int err, i; + int err; + DECLARE_MAC_BUF(mac); if (b44_version_printed++ == 0) printk(KERN_INFO "%s", version); @@ -2229,10 +2230,8 @@ static int __devinit b44_init_one(struct pci_dev *pdev, */ b44_chip_reset(bp); - printk(KERN_INFO "%s: Broadcom 4400 10/100BaseT Ethernet ", dev->name); - for (i = 0; i < 6; i++) - printk("%2.2x%c", dev->dev_addr[i], - i == 5 ? '\n' : ':'); + printk(KERN_INFO "%s: Broadcom 4400 10/100BaseT Ethernet %s\n", + dev->name, print_mac(mac, dev->dev_addr)); return 0; diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c index 2761441f664..a42bd19646d 100644 --- a/drivers/net/bmac.c +++ b/drivers/net/bmac.c @@ -1258,6 +1258,7 @@ static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_device_i unsigned char addr[6]; struct net_device *dev; int is_bmac_plus = ((int)match->data) != 0; + DECLARE_MAC_BUF(mac); if (macio_resource_count(mdev) != 3 || macio_irq_count(mdev) != 3) { printk(KERN_ERR "BMAC: can't use, need 3 addrs and 3 intrs\n"); @@ -1367,9 +1368,8 @@ static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_device_i goto err_out_irq2; } - printk(KERN_INFO "%s: BMAC%s at", dev->name, (is_bmac_plus? "+": "")); - for (j = 0; j < 6; ++j) - printk("%c%.2x", (j? ':': ' '), dev->dev_addr[j]); + printk(KERN_INFO "%s: BMAC%s at %s", + dev->name, (is_bmac_plus ? "+" : ""), print_mac(mac, dev->dev_addr)); XXDEBUG((", base_addr=%#0lx", dev->base_addr)); printk("\n"); diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 5ee805b3e0e..ee9aed3aa48 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -6821,8 +6821,9 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) static int version_printed = 0; struct net_device *dev = NULL; struct bnx2 *bp; - int rc, i; + int rc; char str[40]; + DECLARE_MAC_BUF(mac); if (version_printed++ == 0) printk(KERN_INFO "%s", version); @@ -6890,19 +6891,14 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) } printk(KERN_INFO "%s: %s (%c%d) %s found at mem %lx, " - "IRQ %d, ", + "IRQ %d, node addr %s\n", dev->name, bp->name, ((CHIP_ID(bp) & 0xf000) >> 12) + 'A', ((CHIP_ID(bp) & 0x0ff0) >> 4), bnx2_bus_string(bp, str), dev->base_addr, - bp->pdev->irq); - - printk("node addr "); - for (i = 0; i < 6; i++) - printk("%2.2x", dev->dev_addr[i]); - printk("\n"); + bp->pdev->irq, print_mac(mac, dev->dev_addr)); return 0; } diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index ea58144c220..8f77db2112c 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1604,6 +1604,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) struct slave *slave, *oldcurrent; struct sockaddr addr; int mac_addr_differ; + DECLARE_MAC_BUF(mac); /* slave is not a slave or master is not master of this slave */ if (!(slave_dev->flags & IFF_SLAVE) || @@ -1631,19 +1632,13 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) ETH_ALEN); if (!mac_addr_differ && (bond->slave_cnt > 1)) { printk(KERN_WARNING DRV_NAME - ": %s: Warning: the permanent HWaddr of %s " - "- %02X:%02X:%02X:%02X:%02X:%02X - is " - "still in use by %s. Set the HWaddr of " - "%s to a different address to avoid " - "conflicts.\n", + ": %s: Warning: the permanent HWaddr of %s - " + "%s - is still in use by %s. " + "Set the HWaddr of %s to a different address " + "to avoid conflicts.\n", bond_dev->name, slave_dev->name, - slave->perm_hwaddr[0], - slave->perm_hwaddr[1], - slave->perm_hwaddr[2], - slave->perm_hwaddr[3], - slave->perm_hwaddr[4], - slave->perm_hwaddr[5], + print_mac(mac, slave->perm_hwaddr), bond_dev->name, slave_dev->name); } @@ -3006,6 +3001,7 @@ static void bond_info_show_master(struct seq_file *seq) if (bond->params.mode == BOND_MODE_8023AD) { struct ad_info ad_info; + DECLARE_MAC_BUF(mac); seq_puts(seq, "\n802.3ad info\n"); seq_printf(seq, "LACP rate: %s\n", @@ -3025,13 +3021,8 @@ static void bond_info_show_master(struct seq_file *seq) ad_info.actor_key); seq_printf(seq, "\tPartner Key: %d\n", ad_info.partner_key); - seq_printf(seq, "\tPartner Mac Address: %02x:%02x:%02x:%02x:%02x:%02x\n", - ad_info.partner_system[0], - ad_info.partner_system[1], - ad_info.partner_system[2], - ad_info.partner_system[3], - ad_info.partner_system[4], - ad_info.partner_system[5]); + seq_printf(seq, "\tPartner Mac Address: %s\n", + print_mac(mac, ad_info.partner_system)); } } } @@ -3039,6 +3030,7 @@ static void bond_info_show_master(struct seq_file *seq) static void bond_info_show_slave(struct seq_file *seq, const struct slave *slave) { struct bonding *bond = seq->private; + DECLARE_MAC_BUF(mac); seq_printf(seq, "\nSlave Interface: %s\n", slave->dev->name); seq_printf(seq, "MII Status: %s\n", @@ -3047,10 +3039,8 @@ static void bond_info_show_slave(struct seq_file *seq, const struct slave *slave slave->link_failure_count); seq_printf(seq, - "Permanent HW addr: %02x:%02x:%02x:%02x:%02x:%02x\n", - slave->perm_hwaddr[0], slave->perm_hwaddr[1], - slave->perm_hwaddr[2], slave->perm_hwaddr[3], - slave->perm_hwaddr[4], slave->perm_hwaddr[5]); + "Permanent HW addr: %s\n", + print_mac(mac, slave->perm_hwaddr)); if (bond->params.mode == BOND_MODE_8023AD) { const struct aggregator *agg diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index a771853219d..f10927639b5 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -1361,17 +1361,14 @@ static ssize_t bonding_show_ad_partner_mac(struct device *d, { int count = 0; struct bonding *bond = to_bond(d); + DECLARE_MAC_BUF(mac); if (bond->params.mode == BOND_MODE_8023AD) { struct ad_info ad_info; if (!bond_3ad_get_active_agg_info(bond, &ad_info)) { - count = sprintf(buf,"%02x:%02x:%02x:%02x:%02x:%02x\n", - ad_info.partner_system[0], - ad_info.partner_system[1], - ad_info.partner_system[2], - ad_info.partner_system[3], - ad_info.partner_system[4], - ad_info.partner_system[5]) + 1; + count = sprintf(buf,"%s\n", + print_mac(mac, ad_info.partner_system)) + + 1; } } else diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c index f44f3d2a4b4..adc2e4d5a69 100644 --- a/drivers/net/cassini.c +++ b/drivers/net/cassini.c @@ -4877,6 +4877,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev, int i, err, pci_using_dac; u16 pci_cmd; u8 orig_cacheline_size = 0, cas_cacheline_size = 0; + DECLARE_MAC_BUF(mac); if (cas_version_printed++ == 0) printk(KERN_INFO "%s", version); @@ -5084,16 +5085,12 @@ static int __devinit cas_init_one(struct pci_dev *pdev, i = readl(cp->regs + REG_BIM_CFG); printk(KERN_INFO "%s: Sun Cassini%s (%sbit/%sMHz PCI/%s) " - "Ethernet[%d] ", dev->name, + "Ethernet[%d] %s\n", dev->name, (cp->cas_flags & CAS_FLAG_REG_PLUS) ? "+" : "", (i & BIM_CFG_32BIT) ? "32" : "64", (i & BIM_CFG_66MHZ) ? "66" : "33", - (cp->phy_type == CAS_PHY_SERDES) ? "Fi" : "Cu", pdev->irq); - - for (i = 0; i < 6; i++) - printk("%2.2x%c", dev->dev_addr[i], - i == 5 ? ' ' : ':'); - printk("\n"); + (cp->phy_type == CAS_PHY_SERDES) ? "Fi" : "Cu", pdev->irq, + print_mac(mac, dev->dev_addr)); pci_set_drvdata(pdev, dev); cp->hw_running = 1; diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c index 5bdf5ca85a6..314b2f68f78 100644 --- a/drivers/net/cris/eth_v10.c +++ b/drivers/net/cris/eth_v10.c @@ -618,12 +618,8 @@ e100_set_mac_address(struct net_device *dev, void *p) /* show it in the log as well */ - printk(KERN_INFO "%s: changed MAC to ", dev->name); - - for (i = 0; i < 5; i++) - printk("%02X:", dev->dev_addr[i]); - - printk("%02X\n", dev->dev_addr[i]); + printk(KERN_INFO "%s: changed MAC to %s\n", + dev->name, print_mac(mac, dev->dev_addr)); spin_unlock(&np->lock); diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c index 4cf82cf5ac1..57175097513 100644 --- a/drivers/net/cs89x0.c +++ b/drivers/net/cs89x0.c @@ -516,6 +516,7 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) unsigned rev_type = 0; int eeprom_buff[CHKSUM_LEN]; int retval; + DECLARE_MAC_BUF(mac); /* Initialize the device structure. */ if (!modular) { @@ -840,11 +841,7 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) } /* print the ethernet address. */ - printk(", MAC"); - for (i = 0; i < ETH_ALEN; i++) - { - printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]); - } + printk(", MAC %s", print_mac(mac, dev->dev_addr)); dev->open = net_open; dev->stop = net_close; @@ -1806,17 +1803,15 @@ static int set_mac_address(struct net_device *dev, void *p) int i; struct sockaddr *addr = p; - if (netif_running(dev)) return -EBUSY; memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); if (net_debug) { - printk("%s: Setting MAC address to ", dev->name); - for (i = 0; i < dev->addr_len; i++) - printk(" %2.2x", dev->dev_addr[i]); - printk(".\n"); + DECLARE_MAC_BUF(mac); + printk("%s: Setting MAC address to %s.\n", + dev->name, print_mac(mac, dev->dev_addr)); } /* set the Ethernet address */ for (i=0; i < ETH_ALEN/2; i++) diff --git a/drivers/net/de600.c b/drivers/net/de600.c index 421c2ca4971..cb849b091f9 100644 --- a/drivers/net/de600.c +++ b/drivers/net/de600.c @@ -384,6 +384,7 @@ static struct net_device * __init de600_probe(void) int i; struct net_device *dev; int err; + DECLARE_MAC_BUF(mac); dev = alloc_etherdev(0); if (!dev) @@ -438,10 +439,7 @@ static struct net_device * __init de600_probe(void) goto out1; } - printk(", Ethernet Address: %02X", dev->dev_addr[0]); - for (i = 1; i < ETH_ALEN; i++) - printk(":%02X",dev->dev_addr[i]); - printk("\n"); + printk(", Ethernet Address: %s\n", print_mac(mac, dev->dev_addr)); dev->open = de600_open; dev->stop = de600_close; diff --git a/drivers/net/de620.c b/drivers/net/de620.c index 4b93902906b..3f5190c654c 100644 --- a/drivers/net/de620.c +++ b/drivers/net/de620.c @@ -807,6 +807,7 @@ struct net_device * __init de620_probe(int unit) struct net_device *dev; int err = -ENOMEM; int i; + DECLARE_MAC_BUF(mac); dev = alloc_etherdev(0); if (!dev) @@ -853,13 +854,14 @@ struct net_device * __init de620_probe(int unit) } /* else, got it! */ - printk(", Ethernet Address: %2.2X", - dev->dev_addr[0] = nic_data.NodeID[0]); + dev->dev_addr[0] = nic_data.NodeID[0]; for (i = 1; i < ETH_ALEN; i++) { - printk(":%2.2X", dev->dev_addr[i] = nic_data.NodeID[i]); + dev->dev_addr[i] = nic_data.NodeID[i]; dev->broadcast[i] = 0xff; } + printk(", Ethernet Address: %s", print_mac(mac, dev->dev_addr)); + printk(" (%dk RAM,", (nic_data.RAM_Size) ? (nic_data.RAM_Size >> 2) : 64); diff --git a/drivers/net/declance.c b/drivers/net/declance.c index 7e7ac3330e6..00e0194bfef 100644 --- a/drivers/net/declance.c +++ b/drivers/net/declance.c @@ -1027,6 +1027,7 @@ static int __init dec_lance_probe(struct device *bdev, const int type) int i, ret; unsigned long esar_base; unsigned char *esar; + DECLARE_MAC_BUF(mac); if (dec_lance_debug && version_printed++ == 0) printk(version); @@ -1214,21 +1215,20 @@ static int __init dec_lance_probe(struct device *bdev, const int type) */ switch (type) { case ASIC_LANCE: - printk("%s: IOASIC onboard LANCE, addr = ", name); + printk("%s: IOASIC onboard LANCE", name); break; case PMAD_LANCE: - printk("%s: PMAD-AA, addr = ", name); + printk("%s: PMAD-AA", name); break; case PMAX_LANCE: - printk("%s: PMAX onboard LANCE, addr = ", name); + printk("%s: PMAX onboard LANCE", name); break; } - for (i = 0; i < 6; i++) { + for (i = 0; i < 6; i++) dev->dev_addr[i] = esar[i * 4]; - printk("%2.2x%c", dev->dev_addr[i], i == 5 ? ',' : ':'); - } - printk(" irq = %d\n", dev->irq); + printk(", addr = %s, irq = %d\n", + print_mac(mac, dev->dev_addr), dev->irq); dev->open = &lance_open; dev->stop = &lance_close; diff --git a/drivers/net/depca.c b/drivers/net/depca.c index 28fa2bdc8c7..ace39ec0a36 100644 --- a/drivers/net/depca.c +++ b/drivers/net/depca.c @@ -573,6 +573,7 @@ static int __init depca_hw_init (struct net_device *dev, struct device *device) s16 nicsr; u_long ioaddr; u_long mem_start; + DECLARE_MAC_BUF(mac); /* * We are now supposed to enter this function with the @@ -632,14 +633,11 @@ static int __init depca_hw_init (struct net_device *dev, struct device *device) printk(", h/w address "); status = get_hw_addr(dev); + printk("%s", print_mac(mac, dev->dev_addr)); if (status != 0) { printk(" which has an Ethernet PROM CRC error.\n"); return -ENXIO; } - for (i = 0; i < ETH_ALEN - 1; i++) { /* get the ethernet address */ - printk("%2.2x:", dev->dev_addr[i]); - } - printk("%2.2x", dev->dev_addr[i]); /* Set up the maximum amount of network RAM(kB) */ netRAM = ((lp->adapter != DEPCA) ? 64 : 48); @@ -1843,6 +1841,7 @@ static void depca_dbg_open(struct net_device *dev) u_long ioaddr = dev->base_addr; struct depca_init *p = &lp->init_block; int i; + DECLARE_MAC_BUF(mac); if (depca_debug > 1) { /* Do not copy the shadow init block into shared memory */ @@ -1881,11 +1880,7 @@ static void depca_dbg_open(struct net_device *dev) printk("...0x%8.8x\n", readl(&lp->tx_ring[i].base)); printk("Initialisation block at 0x%8.8lx(Phys)\n", lp->mem_start); printk(" mode: 0x%4.4x\n", p->mode); - printk(" physical address: "); - for (i = 0; i < ETH_ALEN - 1; i++) { - printk("%2.2x:", p->phys_addr[i]); - } - printk("%2.2x\n", p->phys_addr[i]); + printk(" physical address: %s\n", print_mac(mac, p->phys_addr)); printk(" multicast hash table: "); for (i = 0; i < (HASH_TABLE_LEN >> 3) - 1; i++) { printk("%2.2x:", p->mcast_table[i]); diff --git a/drivers/net/dgrs.c b/drivers/net/dgrs.c index a9ef79da3dc..054f2ba5f69 100644 --- a/drivers/net/dgrs.c +++ b/drivers/net/dgrs.c @@ -1139,6 +1139,7 @@ dgrs_probe1(struct net_device *dev) DGRS_PRIV *priv = (DGRS_PRIV *) dev->priv; unsigned long i; int rc; + DECLARE_MAC_BUF(mac); printk("%s: Digi RightSwitch io=%lx mem=%lx irq=%d plx=%lx dma=%lx\n", dev->name, dev->base_addr, dev->mem_start, dev->irq, @@ -1154,11 +1155,9 @@ dgrs_probe1(struct net_device *dev) /* * Get ether address of board */ - printk("%s: Ethernet address", dev->name); memcpy(dev->dev_addr, priv->port->ethaddr, 6); - for (i = 0; i < 6; ++i) - printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]); - printk("\n"); + printk("%s: Ethernet address %s\n", + dev->name, print_mac(mac, dev->dev_addr)); if (dev->dev_addr[0] & 1) { @@ -1214,15 +1213,12 @@ static int __init dgrs_initclone(struct net_device *dev) { DGRS_PRIV *priv = (DGRS_PRIV *) dev->priv; - int i; + DECLARE_MAC_BUF(mac); - printk("%s: Digi RightSwitch port %d ", - dev->name, priv->chan); - for (i = 0; i < 6; ++i) - printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]); - printk("\n"); + printk("%s: Digi RightSwitch port %d %s\n", + dev->name, priv->chan, print_mac(mac, dev->dev_addr)); - return (0); + return 0; } static struct net_device * __init diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c index 12486e13b85..e91b7096838 100644 --- a/drivers/net/dl2k.c +++ b/drivers/net/dl2k.c @@ -97,6 +97,7 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent) static int version_printed; void *ring_space; dma_addr_t ring_dma; + DECLARE_MAC_BUF(mac); if (!version_printed++) printk ("%s", version); @@ -256,10 +257,8 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent) card_idx++; - printk (KERN_INFO "%s: %s, %02x:%02x:%02x:%02x:%02x:%02x, IRQ %d\n", - dev->name, np->name, - dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5], irq); + printk (KERN_INFO "%s: %s, %s, IRQ %d\n", + dev->name, np->name, print_mac(mac, dev->dev_addr), irq); if (tx_coalesce > 1) printk(KERN_INFO "tx_coalesce:\t%d packets\n", tx_coalesce); diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index f691ef61b2d..27ac010900a 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -595,11 +595,10 @@ dm9000_probe(struct platform_device *pdev) ret = register_netdev(ndev); if (ret == 0) { - printk("%s: dm9000 at %p,%p IRQ %d MAC: ", - ndev->name, db->io_addr, db->io_data, ndev->irq); - for (i = 0; i < 5; i++) - printk("%02x:", ndev->dev_addr[i]); - printk("%02x\n", ndev->dev_addr[5]); + DECLARE_MAC_BUF(mac); + printk("%s: dm9000 at %p,%p IRQ %d MAC: %s\n", + ndev->name, db->io_addr, db->io_data, ndev->irq, + print_mac(mac, ndev->dev_addr)); } return 0; diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 99126564f1a..720994b1e13 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -2548,6 +2548,7 @@ static int __devinit e100_probe(struct pci_dev *pdev, struct net_device *netdev; struct nic *nic; int err; + DECLARE_MAC_BUF(mac); if(!(netdev = alloc_etherdev(sizeof(struct nic)))) { if(((1 << debug) - 1) & NETIF_MSG_PROBE) @@ -2679,11 +2680,9 @@ static int __devinit e100_probe(struct pci_dev *pdev, goto err_out_free; } - DPRINTK(PROBE, INFO, "addr 0x%llx, irq %d, " - "MAC addr %02X:%02X:%02X:%02X:%02X:%02X\n", - (unsigned long long)pci_resource_start(pdev, use_io ? 1 : 0), pdev->irq, - netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2], - netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]); + DPRINTK(PROBE, INFO, "addr 0x%llx, irq %d, MAC addr %s\n", + (unsigned long long)pci_resource_start(pdev, use_io ? 1 : 0), + pdev->irq, print_mac(mac, netdev->dev_addr)); return 0; diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 7befb706ad5..ad444c9a5d0 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -872,6 +872,8 @@ e1000_probe(struct pci_dev *pdev, int i, err, pci_using_dac; uint16_t eeprom_data = 0; uint16_t eeprom_apme_mask = E1000_EEPROM_APME; + DECLARE_MAC_BUF(mac); + if ((err = pci_enable_device(pdev))) return err; @@ -1132,8 +1134,7 @@ e1000_probe(struct pci_dev *pdev, "32-bit")); } - for (i = 0; i < 6; i++) - printk("%2.2x%c", netdev->dev_addr[i], i == 5 ? '\n' : ':'); + printk("%s\n", print_mac(mac, netdev->dev_addr)); /* reset the hardware with the new settings */ e1000_reset(adapter); diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c index 54811f6f766..83bda6ccde9 100644 --- a/drivers/net/eepro.c +++ b/drivers/net/eepro.c @@ -690,6 +690,7 @@ static void __init eepro_print_info (struct net_device *dev) struct eepro_local * lp = netdev_priv(dev); int i; const char * ifmap[] = {"AUI", "10Base2", "10BaseT"}; + DECLARE_MAC_BUF(mac); i = inb(dev->base_addr + ID_REG); printk(KERN_DEBUG " id: %#x ",i); @@ -711,10 +712,10 @@ static void __init eepro_print_info (struct net_device *dev) case LAN595: printk("%s: Intel 82595-based lan card at %#x,", dev->name, (unsigned)dev->base_addr); + break; } - for (i=0; i < 6; i++) - printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]); + printk(" %s", print_mac(mac, dev->dev_addr)); if (net_debug > 3) printk(KERN_DEBUG ", %dK RCV buffer", diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c index f8b69ceb2be..1548a80f917 100644 --- a/drivers/net/eepro100.c +++ b/drivers/net/eepro100.c @@ -622,6 +622,7 @@ static int __devinit speedo_found1(struct pci_dev *pdev, int size; void *tx_ring_space; dma_addr_t tx_ring_dma; + DECLARE_MAC_BUF(mac); size = TX_RING_SIZE * sizeof(struct TxFD) + sizeof(struct speedo_stats); tx_ring_space = pci_alloc_consistent(pdev, size, &tx_ring_dma); @@ -705,12 +706,8 @@ static int __devinit speedo_found1(struct pci_dev *pdev, else product = pci_name(pdev); - printk(KERN_INFO "%s: %s, ", dev->name, product); - - for (i = 0; i < 5; i++) - printk("%2.2X:", dev->dev_addr[i]); - printk("%2.2X, ", dev->dev_addr[i]); - printk("IRQ %d.\n", pdev->irq); + printk(KERN_INFO "%s: %s, %s, IRQ %d.\n", dev->name, product, + print_mac(mac, dev->dev_addr), pdev->irq); sp = netdev_priv(dev); diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index 5ac56f20003..ecdd3fc8d70 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -317,6 +317,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev, int i, ret, option = 0, duplex = 0; void *ring_space; dma_addr_t ring_dma; + DECLARE_MAC_BUF(mac); /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -493,11 +494,9 @@ static int __devinit epic_init_one (struct pci_dev *pdev, if (ret < 0) goto err_out_unmap_rx; - printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", - dev->name, pci_id_tbl[chip_idx].name, ioaddr, dev->irq); - for (i = 0; i < 5; i++) - printk("%2.2x:", dev->dev_addr[i]); - printk("%2.2x.\n", dev->dev_addr[i]); + printk(KERN_INFO "%s: %s at %#lx, IRQ %d, %s\n", + dev->name, pci_id_tbl[chip_idx].name, ioaddr, dev->irq, + print_mac(mac, dev->dev_addr)); out: return ret; diff --git a/drivers/net/es3210.c b/drivers/net/es3210.c index 238fa8aff02..deefa51b8c3 100644 --- a/drivers/net/es3210.c +++ b/drivers/net/es3210.c @@ -179,6 +179,7 @@ static int __init es_probe1(struct net_device *dev, int ioaddr) { int i, retval; unsigned long eisa_id; + DECLARE_MAC_BUF(mac); if (!request_region(ioaddr + ES_SA_PROM, ES_IO_EXTENT, "es3210")) return -ENODEV; @@ -190,7 +191,6 @@ static int __init es_probe1(struct net_device *dev, int ioaddr) inb(ioaddr + ES_CFG4), inb(ioaddr + ES_CFG5), inb(ioaddr + ES_CFG6)); #endif - /* Check the EISA ID of the card. */ eisa_id = inl(ioaddr + ES_ID_PORT); if ((eisa_id != ES_EISA_ID1) && (eisa_id != ES_EISA_ID2)) { @@ -198,21 +198,21 @@ static int __init es_probe1(struct net_device *dev, int ioaddr) goto out; } + for (i = 0; i < ETHER_ADDR_LEN ; i++) + dev->dev_addr[i] = inb(ioaddr + ES_SA_PROM + i); + /* Check the Racal vendor ID as well. */ - if (inb(ioaddr + ES_SA_PROM + 0) != ES_ADDR0 - || inb(ioaddr + ES_SA_PROM + 1) != ES_ADDR1 - || inb(ioaddr + ES_SA_PROM + 2) != ES_ADDR2 ) { - printk("es3210.c: card not found"); - for(i = 0; i < ETHER_ADDR_LEN; i++) - printk(" %02x", inb(ioaddr + ES_SA_PROM + i)); - printk(" (invalid prefix).\n"); + if (dev->dev_addr[0] != ES_ADDR0 || + dev->dev_addr[1] != ES_ADDR1 || + dev->dev_addr[2] != ES_ADDR2) { + printk("es3210.c: card not found %s (invalid_prefix).\n", + print_mac(mac, dev->dev_addr)); retval = -ENODEV; goto out; } - printk("es3210.c: ES3210 rev. %ld at %#x, node", eisa_id>>24, ioaddr); - for(i = 0; i < ETHER_ADDR_LEN; i++) - printk(" %02x", (dev->dev_addr[i] = inb(ioaddr + ES_SA_PROM + i))); + printk("es3210.c: ES3210 rev. %ld at %#x, node %s", + eisa_id>>24, ioaddr, print_mac(mac, dev->dev_addr)); /* Snarf the interrupt now. */ if (dev->irq == 0) { diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c index 142aa225d89..593a120e31b 100644 --- a/drivers/net/ewrk3.c +++ b/drivers/net/ewrk3.c @@ -396,6 +396,7 @@ ewrk3_hw_init(struct net_device *dev, u_long iobase) u_long mem_start, shmem_length; u_char cr, cmr, icr, nicsr, lemac, hard_strapped = 0; u_char eeprom_image[EEPROM_MAX], chksum, eisa_cr = 0; + DECLARE_MAC_BUF(mac); /* ** Stop the EWRK3. Enable the DBR ROM. Disable interrupts and remote boot. @@ -460,10 +461,7 @@ ewrk3_hw_init(struct net_device *dev, u_long iobase) if (lemac != LeMAC2) DevicePresent(iobase); /* need after EWRK3_INIT */ status = get_hw_addr(dev, eeprom_image, lemac); - for (i = 0; i < ETH_ALEN - 1; i++) { /* get the ethernet addr. */ - printk("%2.2x:", dev->dev_addr[i]); - } - printk("%2.2x,\n", dev->dev_addr[i]); + printk("%s\n", print_mac(mac, dev->dev_addr)); if (status) { printk(" which has an EEPROM CRC error.\n"); @@ -628,7 +626,7 @@ static int ewrk3_open(struct net_device *dev) { struct ewrk3_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; - int i, status = 0; + int status = 0; u_char icr, csr; /* @@ -648,12 +646,10 @@ static int ewrk3_open(struct net_device *dev) ewrk3_init(dev); if (ewrk3_debug > 1) { + DECLARE_MAC_BUF(mac); printk("%s: ewrk3 open with irq %d\n", dev->name, dev->irq); - printk(" physical address: "); - for (i = 0; i < 5; i++) { - printk("%2.2x:", (u_char) dev->dev_addr[i]); - } - printk("%2.2x\n", (u_char) dev->dev_addr[i]); + printk(" physical address: %s\n", + print_mac(mac, dev->dev_addr)); if (lp->shmem_length == 0) { printk(" no shared memory, I/O only mode\n"); } else { diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c index 402b071d8d5..43f7647ff24 100644 --- a/drivers/net/fealnx.c +++ b/drivers/net/fealnx.c @@ -486,6 +486,7 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev, #else int bar = 1; #endif + DECLARE_MAC_BUF(mac); /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -664,11 +665,9 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev, if (err) goto err_out_free_tx; - printk(KERN_INFO "%s: %s at %p, ", - dev->name, skel_netdrv_tbl[chip_id].chip_name, ioaddr); - for (i = 0; i < 5; i++) - printk("%2.2x:", dev->dev_addr[i]); - printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); + printk(KERN_INFO "%s: %s at %p, %s, IRQ %d.\n", + dev->name, skel_netdrv_tbl[chip_id].chip_name, ioaddr, + print_mac(mac, dev->dev_addr), irq); return 0; diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 4419c3cee99..2b5782056dd 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -2635,6 +2635,7 @@ static int __init fec_enet_module_init(void) { struct net_device *dev; int i, j, err; + DECLARE_MAC_BUF(mac); printk("FEC ENET Version 0.2\n"); @@ -2653,10 +2654,8 @@ static int __init fec_enet_module_init(void) return -EIO; } - printk("%s: ethernet ", dev->name); - for (j = 0; (j < 5); j++) - printk("%02x:", dev->dev_addr[j]); - printk("%02x\n", dev->dev_addr[5]); + printk("%s: ethernet %s\n", + dev->name, print_mac(mac, dev->dev_addr)); } return 0; } diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index be744573b1c..f7354bc9b00 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -4991,6 +4991,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i u32 powerstate, txreg; u32 phystate_orig = 0, phystate; int phyinitialized = 0; + DECLARE_MAC_BUF(mac); dev = alloc_etherdev(sizeof(struct fe_priv)); err = -ENOMEM; @@ -5205,10 +5206,8 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i * Bad mac address. At least one bios sets the mac address * to 01:23:45:67:89:ab */ - printk(KERN_ERR "%s: Invalid Mac address detected: %02x:%02x:%02x:%02x:%02x:%02x\n", - pci_name(pci_dev), - dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + printk(KERN_ERR "%s: Invalid Mac address detected: %s\n", + pci_name(pci_dev), print_mac(mac, dev->dev_addr)); printk(KERN_ERR "Please complain to your hardware vendor. Switching to a random MAC.\n"); dev->dev_addr[0] = 0x00; dev->dev_addr[1] = 0x00; @@ -5216,9 +5215,8 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i get_random_bytes(&dev->dev_addr[3], 3); } - dprintk(KERN_DEBUG "%s: MAC Address %02x:%02x:%02x:%02x:%02x:%02x\n", pci_name(pci_dev), - dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + dprintk(KERN_DEBUG "%s: MAC Address %s\n", + pci_name(pci_dev), print_mac(mac, dev->dev_addr)); /* set mac address */ nv_copy_mac_to_hw(dev); diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 5a1a1165b48..0db5e6fabe7 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -170,6 +170,7 @@ static int gfar_probe(struct platform_device *pdev) struct resource *r; int idx; int err = 0; + DECLARE_MAC_BUF(mac); einfo = (struct gianfar_platform_data *) pdev->dev.platform_data; @@ -356,10 +357,8 @@ static int gfar_probe(struct platform_device *pdev) gfar_init_sysfs(dev); /* Print out the device info */ - printk(KERN_INFO DEVICE_NAME, dev->name); - for (idx = 0; idx < 6; idx++) - printk("%2.2x%c", dev->dev_addr[idx], idx == 5 ? ' ' : ':'); - printk("\n"); + printk(KERN_INFO DEVICE_NAME "%s\n", + dev->name, print_mac(mac, dev->dev_addr)); /* Even more device info helps when determining which kernel */ /* provided which set of benchmarks. */ diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c index da12b3db023..015ed3a4057 100644 --- a/drivers/net/hamachi.c +++ b/drivers/net/hamachi.c @@ -580,6 +580,7 @@ static int __devinit hamachi_init_one (struct pci_dev *pdev, void *ring_space; dma_addr_t ring_dma; int ret = -ENOMEM; + DECLARE_MAC_BUF(mac); /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -741,12 +742,9 @@ static int __devinit hamachi_init_one (struct pci_dev *pdev, goto err_out_unmap_rx; } - printk(KERN_INFO "%s: %s type %x at %p, ", + printk(KERN_INFO "%s: %s type %x at %p, %s, IRQ %d.\n", dev->name, chip_tbl[chip_id].name, readl(ioaddr + ChipRev), - ioaddr); - for (i = 0; i < 5; i++) - printk("%2.2x:", dev->dev_addr[i]); - printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); + ioaddr, print_mac(mac, dev->dev_addr), irq); i = readb(ioaddr + PCIClkMeas); printk(KERN_INFO "%s: %d-bit %d Mhz PCI bus (%d), Virtual Jumpers " "%2.2x, LPA %4.4x.\n", diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index df09210f735..c05bc37df35 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -64,7 +64,7 @@ #include #include #include -#include +#include #include #include #include @@ -95,7 +95,6 @@ static char bpq_eth_addr[6]; static int bpq_rcv(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *); static int bpq_device_event(struct notifier_block *, unsigned long, void *); -static const char *bpq_print_ethaddr(const unsigned char *); static struct packet_type bpq_packet_type = { .type = __constant_htons(ETH_P_BPQ), @@ -383,16 +382,6 @@ static int bpq_close(struct net_device *dev) /* * Proc filesystem */ -static const char * bpq_print_ethaddr(const unsigned char *e) -{ - static char buf[18]; - - sprintf(buf, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X", - e[0], e[1], e[2], e[3], e[4], e[5]); - - return buf; -} - static void *bpq_seq_start(struct seq_file *seq, loff_t *pos) { int i = 1; @@ -438,14 +427,16 @@ static int bpq_seq_show(struct seq_file *seq, void *v) "dev ether destination accept from\n"); else { const struct bpqdev *bpqdev = v; + DECLARE_MAC_BUF(mac); seq_printf(seq, "%-5s %-10s %s ", bpqdev->axdev->name, bpqdev->ethdev->name, - bpq_print_ethaddr(bpqdev->dest_addr)); + print_mac(mac, bpqdev->dest_addr)); - seq_printf(seq, "%s\n", - (bpqdev->acpt_addr[0] & 0x01) ? "*" - : bpq_print_ethaddr(bpqdev->acpt_addr)); + if (is_multicast_ether_addr(bpqdev->acpt_addr)) + seq_printf(seq, "*\n"); + else + seq_printf(seq, "%s\n", print_mac(mac, bpqdev->acpt_addr)); } return 0; diff --git a/drivers/net/hp-plus.c b/drivers/net/hp-plus.c index 8d4f810fa28..c2c4f49d757 100644 --- a/drivers/net/hp-plus.c +++ b/drivers/net/hp-plus.c @@ -166,6 +166,7 @@ static int __init hpp_probe1(struct net_device *dev, int ioaddr) const char name[] = "HP-PC-LAN+"; int mem_start; static unsigned version_printed; + DECLARE_MAC_BUF(mac); if (!request_region(ioaddr, HP_IO_EXTENT, DRV_NAME)) return -EBUSY; @@ -180,7 +181,7 @@ static int __init hpp_probe1(struct net_device *dev, int ioaddr) if (ei_debug && version_printed++ == 0) printk(version); - printk("%s: %s at %#3x,", dev->name, name, ioaddr); + printk("%s: %s at %#3x, ", dev->name, name, ioaddr); /* Retrieve and checksum the station address. */ outw(MAC_Page, ioaddr + HP_PAGING); @@ -189,10 +190,11 @@ static int __init hpp_probe1(struct net_device *dev, int ioaddr) unsigned char inval = inb(ioaddr + 8 + i); dev->dev_addr[i] = inval; checksum += inval; - printk(" %2.2x", inval); } checksum += inb(ioaddr + 14); + printk("%s", print_mac(mac, dev->dev_addr)); + if (checksum != 0xff) { printk(" bad checksum %2.2x.\n", checksum); retval = -ENODEV; diff --git a/drivers/net/hp.c b/drivers/net/hp.c index 1f11126de35..c649a8019be 100644 --- a/drivers/net/hp.c +++ b/drivers/net/hp.c @@ -127,6 +127,7 @@ static int __init hp_probe1(struct net_device *dev, int ioaddr) int i, retval, board_id, wordmode; const char *name; static unsigned version_printed; + DECLARE_MAC_BUF(mac); if (!request_region(ioaddr, HP_IO_EXTENT, DRV_NAME)) return -EBUSY; @@ -158,7 +159,9 @@ static int __init hp_probe1(struct net_device *dev, int ioaddr) printk("%s: %s (ID %02x) at %#3x,", dev->name, name, board_id, ioaddr); for(i = 0; i < ETHER_ADDR_LEN; i++) - printk(" %2.2x", dev->dev_addr[i] = inb(ioaddr + i)); + dev->dev_addr[i] = inb(ioaddr + i); + + printk(" %s", print_mac(mac, dev->dev_addr)); /* Snarf the interrupt now. Someday this could be moved to open(). */ if (dev->irq < 2) { diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c index 406d6525e22..e4fde17e284 100644 --- a/drivers/net/hp100.c +++ b/drivers/net/hp100.c @@ -2093,9 +2093,9 @@ static void hp100_set_multicast_list(struct net_device *dev) addrs = dmi->dmi_addr; if ((*addrs & 0x01) == 0x01) { /* multicast address? */ #ifdef HP100_DEBUG - printk("hp100: %s: multicast = %02x:%02x:%02x:%02x:%02x:%02x, ", - dev->name, addrs[0], addrs[1], addrs[2], - addrs[3], addrs[4], addrs[5]); + DECLARE_MAC_BUF(mac); + printk("hp100: %s: multicast = %s, ", + dev->name, print_mac(mac, addrs)); #endif for (j = idx = 0; j < 6; j++) { idx ^= *addrs++ & 0x3f; diff --git a/drivers/net/hydra.c b/drivers/net/hydra.c index 31300a9dd96..b96cf2dcb10 100644 --- a/drivers/net/hydra.c +++ b/drivers/net/hydra.c @@ -103,6 +103,7 @@ static int __devinit hydra_init(struct zorro_dev *z) int start_page, stop_page; int j; int err; + DECLARE_MAC_BUF(mac); static u32 hydra_offsets[16] = { 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, @@ -162,10 +163,8 @@ static int __devinit hydra_init(struct zorro_dev *z) zorro_set_drvdata(z, dev); printk(KERN_INFO "%s: Hydra at 0x%08lx, address " - "%02x:%02x:%02x:%02x:%02x:%02x (hydra.c " HYDRA_VERSION ")\n", - dev->name, z->resource.start, dev->dev_addr[0], dev->dev_addr[1], - dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], - dev->dev_addr[5]); + "%s (hydra.c " HYDRA_VERSION ")\n", + dev->name, z->resource.start, print_mac(mac, dev->dev_addr)); return 0; } diff --git a/drivers/net/ibm_emac/ibm_emac_core.c b/drivers/net/ibm_emac/ibm_emac_core.c index d7da56b105c..7d4fa7644e4 100644 --- a/drivers/net/ibm_emac/ibm_emac_core.c +++ b/drivers/net/ibm_emac/ibm_emac_core.c @@ -353,10 +353,9 @@ static void emac_hash_mc(struct ocp_enet_private *dev) for (dmi = dev->ndev->mc_list; dmi; dmi = dmi->next) { int bit; - DBG2("%d: mc %02x:%02x:%02x:%02x:%02x:%02x" NL, - dev->def->index, - dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2], - dmi->dmi_addr[3], dmi->dmi_addr[4], dmi->dmi_addr[5]); + DECLARE_MAC_BUF(mac); + DBG2("%d: mc %s" NL, + dev->def->index, print_mac(mac, dmi->dmi_addr)); bit = 63 - (ether_crc(ETH_ALEN, dmi->dmi_addr) >> 26); gaht[bit >> 4] |= 0x8000 >> (bit & 0x0f); @@ -1940,6 +1939,7 @@ static int __init emac_probe(struct ocp_device *ocpdev) struct ocp_device *maldev; struct ocp_enet_private *dev; int err, i; + DECLARE_MAC_BUF(mac); DBG("%d: probe" NL, ocpdev->def->index); @@ -2188,10 +2188,8 @@ static int __init emac_probe(struct ocp_device *ocpdev) ocp_set_drvdata(ocpdev, dev); - printk("%s: emac%d, MAC %02x:%02x:%02x:%02x:%02x:%02x\n", - ndev->name, dev->def->index, - ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2], - ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]); + printk("%s: emac%d, MAC %s\n", + ndev->name, dev->def->index, print_mac(mac, ndev->dev_addr)); if (dev->phy.address >= 0) printk("%s: found %s PHY (0x%02x)\n", ndev->name, diff --git a/drivers/net/ibmlana.c b/drivers/net/ibmlana.c index eebf39acf58..91d83aca6bc 100644 --- a/drivers/net/ibmlana.c +++ b/drivers/net/ibmlana.c @@ -898,6 +898,7 @@ static int ibmlana_probe(struct net_device *dev) int base = 0, irq = 0, iobase = 0, memlen = 0; ibmlana_priv *priv; ibmlana_medium medium; + DECLARE_MAC_BUF(mac); /* can't work without an MCA bus ;-) */ if (MCA_bus == 0) @@ -981,11 +982,10 @@ static int ibmlana_probe(struct net_device *dev) /* print config */ printk(KERN_INFO "%s: IRQ %d, I/O %#lx, memory %#lx-%#lx, " - "MAC address %02x:%02x:%02x:%02x:%02x:%02x.\n", + "MAC address %s.\n", dev->name, priv->realirq, dev->base_addr, dev->mem_start, dev->mem_end - 1, - dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + print_mac(mac, dev->dev_addr)); printk(KERN_INFO "%s: %s medium\n", dev->name, MediaNames[priv->medium]); /* reset board */ diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 0636883449f..228973484ed 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -1276,16 +1276,13 @@ static int ibmveth_seq_show(struct seq_file *seq, void *v) struct ibmveth_adapter *adapter = seq->private; char *current_mac = ((char*) &adapter->netdev->dev_addr); char *firmware_mac = ((char*) &adapter->mac_addr) ; + DECLARE_MAC_BUF(mac); seq_printf(seq, "%s %s\n\n", ibmveth_driver_string, ibmveth_driver_version); seq_printf(seq, "Unit Address: 0x%x\n", adapter->vdev->unit_address); - seq_printf(seq, "Current MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", - current_mac[0], current_mac[1], current_mac[2], - current_mac[3], current_mac[4], current_mac[5]); - seq_printf(seq, "Firmware MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", - firmware_mac[0], firmware_mac[1], firmware_mac[2], - firmware_mac[3], firmware_mac[4], firmware_mac[5]); + seq_printf(seq, "Current MAC: %s\n", print_mac(mac, current_mac)); + seq_printf(seq, "Firmware MAC: %s\n", print_mac(mac, firmware_mac)); seq_printf(seq, "\nAdapter Statistics:\n"); seq_printf(seq, " TX: vio_map_single failres: %ld\n", adapter->tx_map_failed); diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c index 05d2bc15144..373f72cdbe8 100644 --- a/drivers/net/ioc3-eth.c +++ b/drivers/net/ioc3-eth.c @@ -443,18 +443,12 @@ static void ioc3_get_eaddr_nic(struct ioc3_private *ip) */ static void ioc3_get_eaddr(struct ioc3_private *ip) { - int i; - + DECLARE_MAC_BUF(mac); ioc3_get_eaddr_nic(ip); - printk("Ethernet address is "); - for (i = 0; i < 6; i++) { - printk("%02x", priv_netdev(ip)->dev_addr[i]); - if (i < 5) - printk(":"); - } - printk(".\n"); + printk("Ethernet address is %s.\n", + print_mac(mac, priv_netdev(ip)->dev_addr)); } static void __ioc3_set_mac_address(struct net_device *dev) diff --git a/drivers/net/isa-skeleton.c b/drivers/net/isa-skeleton.c index 54178111eec..d6ff26af37b 100644 --- a/drivers/net/isa-skeleton.c +++ b/drivers/net/isa-skeleton.c @@ -192,6 +192,7 @@ static int __init netcard_probe1(struct net_device *dev, int ioaddr) static unsigned version_printed; int i; int err = -ENODEV; + DECLARE_MAC_BUF(mac); /* Grab the region so that no one else tries to probe our ioports. */ if (!request_region(ioaddr, NETCARD_IO_EXTENT, cardname)) @@ -217,7 +218,9 @@ static int __init netcard_probe1(struct net_device *dev, int ioaddr) /* Retrieve and print the ethernet address. */ for (i = 0; i < 6; i++) - printk(" %2.2x", dev->dev_addr[i] = inb(ioaddr + i)); + dev->dev_addr[i] = inb(ioaddr + i); + + printk("%s", print_mac(mac, dev->dev_addr)); err = -EAGAIN; #ifdef jumpered_interrupts diff --git a/drivers/net/jazzsonic.c b/drivers/net/jazzsonic.c index 13847a3e43e..d3825c8ee99 100644 --- a/drivers/net/jazzsonic.c +++ b/drivers/net/jazzsonic.c @@ -209,6 +209,7 @@ static int __init jazz_sonic_probe(struct platform_device *pdev) struct resource *res; int err = 0; int i; + DECLARE_MAC_BUF(mac); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) @@ -233,13 +234,8 @@ static int __init jazz_sonic_probe(struct platform_device *pdev) if (err) goto out1; - printk("%s: MAC ", dev->name); - for (i = 0; i < 6; i++) { - printk("%2.2x", dev->dev_addr[i]); - if (i < 5) - printk(":"); - } - printk(" IRQ %d\n", dev->irq); + printk("%s: MAC %s IRQ %d\n", + dev->name, print_mac(mac, dev->dev_addr), dev->irq); return 0; diff --git a/drivers/net/lance.c b/drivers/net/lance.c index 7b17212d687..977ed3401bb 100644 --- a/drivers/net/lance.c +++ b/drivers/net/lance.c @@ -466,6 +466,7 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int unsigned long flags; int err = -ENOMEM; void __iomem *bios; + DECLARE_MAC_BUF(mac); /* First we look for special cases. Check for HP's on-board ethernet by looking for 'HP' in the BIOS. @@ -522,12 +523,13 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int /* We can't allocate dev->priv from alloc_etherdev() because it must a ISA DMA-able region. */ chipname = chip_table[lance_version].name; - printk("%s: %s at %#3x,", dev->name, chipname, ioaddr); + printk("%s: %s at %#3x, ", dev->name, chipname, ioaddr); /* There is a 16 byte station address PROM at the base address. The first six bytes are the station address. */ for (i = 0; i < 6; i++) - printk(" %2.2x", dev->dev_addr[i] = inb(ioaddr + i)); + dev->dev_addr[i] = inb(ioaddr + i); + printk("%s", print_mac(mac, dev->dev_addr)); dev->base_addr = ioaddr; /* Make certain the data structures used by the LANCE are aligned and DMAble. */ diff --git a/drivers/net/lguest_net.c b/drivers/net/lguest_net.c index 7f34c92bcd8..abce2ee8430 100644 --- a/drivers/net/lguest_net.c +++ b/drivers/net/lguest_net.c @@ -235,9 +235,9 @@ static int lguestnet_start_xmit(struct sk_buff *skb, struct net_device *dev) struct lguestnet_info *info = netdev_priv(dev); /* Extract the destination ethernet address from the packet. */ const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest; + DECLARE_MAC_BUF(mac); - pr_debug("%s: xmit %02x:%02x:%02x:%02x:%02x:%02x\n", - dev->name, dest[0],dest[1],dest[2],dest[3],dest[4],dest[5]); + pr_debug("%s: xmit %s\n", dev->name, print_mac(mac, dest)); /* If it's a multicast packet, we broadcast to everyone. That's not * very efficient, but there are very few applications which actually diff --git a/drivers/net/lib82596.c b/drivers/net/lib82596.c index afa4638052a..ffaa14f2cd0 100644 --- a/drivers/net/lib82596.c +++ b/drivers/net/lib82596.c @@ -1034,15 +1034,12 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev) static void print_eth(unsigned char *add, char *str) { - int i; + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); - printk(KERN_DEBUG "i596 0x%p, ", add); - for (i = 0; i < 6; i++) - printk(" %02X", add[i + 6]); - printk(" -->"); - for (i = 0; i < 6; i++) - printk(" %02X", add[i]); - printk(" %02X%02X, %s\n", add[12], add[13], str); + printk(KERN_DEBUG "i596 0x%p, %s --> %s %02X%02X, %s\n", + add, print_mac(mac, add + 6), print_mac(mac2, add), + add[12], add[13], str); } static int __devinit i82596_probe(struct net_device *dev) @@ -1352,6 +1349,7 @@ static void set_multicast_list(struct net_device *dev) struct i596_private *lp = netdev_priv(dev); struct i596_dma *dma = lp->dma; int config = 0, cnt; + DECLARE_MAC_BUF(mac); DEB(DEB_MULTI, printk(KERN_DEBUG @@ -1415,8 +1413,8 @@ static void set_multicast_list(struct net_device *dev) if (i596_debug > 1) DEB(DEB_MULTI, printk(KERN_DEBUG - "%s: Adding address %02x:%02x:%02x:%02x:%02x:%02x\n", - dev->name, cp[0], cp[1], cp[2], cp[3], cp[4], cp[5])); + "%s: Adding address %s\n", + dev->name, print_mac(mac, cp))); } DMA_WBACK_INV(dev, &dma->mc_cmd, sizeof(struct mc_cmd)); i596_add_cmd(dev, &cmd->cmd); diff --git a/drivers/net/lne390.c b/drivers/net/lne390.c index 2dd39698321..b3698909788 100644 --- a/drivers/net/lne390.c +++ b/drivers/net/lne390.c @@ -169,6 +169,7 @@ static int __init lne390_probe1(struct net_device *dev, int ioaddr) { int i, revision, ret; unsigned long eisa_id; + DECLARE_MAC_BUF(mac); if (inb_p(ioaddr + LNE390_ID_PORT) == 0xff) return -ENODEV; @@ -200,10 +201,12 @@ static int __init lne390_probe1(struct net_device *dev, int ioaddr) } #endif - printk("lne390.c: LNE390%X in EISA slot %d, address", 0xa+revision, ioaddr/0x1000); for(i = 0; i < ETHER_ADDR_LEN; i++) - printk(" %02x", (dev->dev_addr[i] = inb(ioaddr + LNE390_SA_PROM + i))); - printk(".\nlne390.c: "); + dev->dev_addr[i] = inb(ioaddr + LNE390_SA_PROM + i); + printk("lne390.c: LNE390%X in EISA slot %d, address %s.\n", + 0xa+revision, ioaddr/0x1000, print_mac(mac, dev->dev_addr)); + + printk("lne390.c: "); /* Snarf the interrupt now. CFG file has them all listed as `edge' with share=NO */ if (dev->irq == 0) { diff --git a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c index f6f3fdfe41d..30854f09496 100644 --- a/drivers/net/mac89x0.c +++ b/drivers/net/mac89x0.c @@ -181,6 +181,7 @@ struct net_device * __init mac89x0_probe(int unit) unsigned long ioaddr; unsigned short sig; int err = -ENODEV; + DECLARE_MAC_BUF(mac); dev = alloc_etherdev(sizeof(struct net_local)); if (!dev) @@ -272,13 +273,11 @@ struct net_device * __init mac89x0_probe(int unit) } dev->irq = SLOT2IRQ(slot); - printk(" IRQ %d ADDR ", dev->irq); - /* print the ethernet address. */ - for (i = 0; i < ETH_ALEN; i++) - printk("%2.2x%s", dev->dev_addr[i], - ((i < ETH_ALEN-1) ? ":" : "")); - printk("\n"); + /* print the IRQ and ethernet address. */ + + printk(" IRQ %d ADDR %s\n", + dev->irq, print_mac(mac, dev->dev_addr)); dev->open = net_open; dev->stop = net_close; diff --git a/drivers/net/macb.c b/drivers/net/macb.c index c6707580c30..047ea7be485 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -1071,6 +1071,7 @@ static int __devinit macb_probe(struct platform_device *pdev) unsigned long pclk_hz; u32 config; int err = -ENXIO; + DECLARE_MAC_BUF(mac); regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!regs) { @@ -1190,10 +1191,9 @@ static int __devinit macb_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dev); printk(KERN_INFO "%s: Atmel MACB at 0x%08lx irq %d " - "(%02x:%02x:%02x:%02x:%02x:%02x)\n", + "(%s)\n", dev->name, dev->base_addr, dev->irq, - dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + print_mac(mac, dev->dev_addr)); phydev = bp->phy_dev; printk(KERN_INFO "%s: attached PHY driver [%s] " diff --git a/drivers/net/mace.c b/drivers/net/mace.c index ee132b1e09b..95ebe72f320 100644 --- a/drivers/net/mace.c +++ b/drivers/net/mace.c @@ -101,6 +101,7 @@ static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_i struct mace_data *mp; const unsigned char *addr; int j, rev, rc = -EBUSY; + DECLARE_MAC_BUF(mac); if (macio_resource_count(mdev) != 3 || macio_irq_count(mdev) != 3) { printk(KERN_ERR "can't use MACE %s: need 3 addrs and 3 irqs\n", @@ -240,11 +241,9 @@ static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_i goto err_free_rx_irq; } - printk(KERN_INFO "%s: MACE at", dev->name); - for (j = 0; j < 6; ++j) { - printk("%c%.2x", (j? ':': ' '), dev->dev_addr[j]); - } - printk(", chip revision %d.%d\n", mp->chipid >> 8, mp->chipid & 0xff); + printk(KERN_INFO "%s: MACE at %s, chip revision %d.%d\n", + dev->name, print_mac(mac, dev->dev_addr), + mp->chipid >> 8, mp->chipid & 0xff); return 0; diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c index 57f7c1a2c1d..6589239b79e 100644 --- a/drivers/net/macmace.c +++ b/drivers/net/macmace.c @@ -194,6 +194,7 @@ static int __devinit mace_probe(struct platform_device *pdev) unsigned char checksum = 0; static int found = 0; int err; + DECLARE_MAC_BUF(mac); if (found || macintosh_config->ether_type != MAC_ETHER_MACE) return -ENODEV; @@ -248,9 +249,8 @@ static int __devinit mace_probe(struct platform_device *pdev) dev->set_multicast_list = mace_set_multicast; dev->set_mac_address = mace_set_address; - printk(KERN_INFO "%s: 68K MACE, hardware address %.2X", dev->name, dev->dev_addr[0]); - for (j = 1 ; j < 6 ; j++) printk(":%.2X", dev->dev_addr[j]); - printk("\n"); + printk(KERN_INFO "%s: 68K MACE, hardware address %s\n", + dev->name, print_mac(mac, dev->dev_addr)); err = register_netdev(dev); if (!err) diff --git a/drivers/net/macsonic.c b/drivers/net/macsonic.c index a55a8399344..b267161418e 100644 --- a/drivers/net/macsonic.c +++ b/drivers/net/macsonic.c @@ -223,6 +223,7 @@ int __init mac_onboard_sonic_ethernet_addr(struct net_device* dev) struct sonic_local *lp = netdev_priv(dev); const int prom_addr = ONBOARD_SONIC_PROM_BASE; int i; + DECLARE_MAC_BUF(mac); /* On NuBus boards we can sometimes look in the ROM resources. No such luck for comm-slot/onboard. */ @@ -266,13 +267,8 @@ int __init mac_onboard_sonic_ethernet_addr(struct net_device* dev) dev->dev_addr[1] = val >> 8; dev->dev_addr[0] = val & 0xff; - printk(KERN_INFO "HW Address from CAM 15: "); - for (i = 0; i < 6; i++) { - printk("%2.2x", dev->dev_addr[i]); - if (i < 5) - printk(":"); - } - printk("\n"); + printk(KERN_INFO "HW Address from CAM 15: %s\n", + print_mac(mac, dev->dev_addr)); } else return 0; if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) && @@ -567,7 +563,7 @@ static int __init mac_sonic_probe(struct platform_device *pdev) struct net_device *dev; struct sonic_local *lp; int err; - int i; + DECLARE_MAC_BUF(mac); dev = alloc_etherdev(sizeof(struct sonic_local)); if (!dev) @@ -591,13 +587,8 @@ found: if (err) goto out; - printk("%s: MAC ", dev->name); - for (i = 0; i < 6; i++) { - printk("%2.2x", dev->dev_addr[i]); - if (i < 5) - printk(":"); - } - printk(" IRQ %d\n", dev->irq); + printk("%s: MAC %s IRQ %d\n", + dev->name, print_mac(mac, dev->dev_addr), dev->irq); return 0; diff --git a/drivers/net/meth.c b/drivers/net/meth.c index fe5b6c37207..e25dbab6736 100644 --- a/drivers/net/meth.c +++ b/drivers/net/meth.c @@ -95,11 +95,11 @@ char o2meth_eaddr[8]={0,0,0,0,0,0,0,0}; static inline void load_eaddr(struct net_device *dev) { int i; - DPRINTK("Loading MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n", - (int)o2meth_eaddr[0]&0xFF,(int)o2meth_eaddr[1]&0xFF,(int)o2meth_eaddr[2]&0xFF, - (int)o2meth_eaddr[3]&0xFF,(int)o2meth_eaddr[4]&0xFF,(int)o2meth_eaddr[5]&0xFF); + DECLARE_MAC_BUF(mac); + for (i = 0; i < 6; i++) dev->dev_addr[i] = o2meth_eaddr[i]; + DPRINTK("Loading MAC Address: %s\n", print_mac(mac, dev->dev_addr)); mace->eth.mac_addr = (*(unsigned long*)o2meth_eaddr) >> 16; } diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 34df02cfdbe..e379165d837 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -784,6 +784,7 @@ static int mv643xx_eth_open(struct net_device *dev) unsigned int port_num = mp->port_num; unsigned int size; int err; + DECLARE_MAC_BUF(mac); /* Clear any pending ethernet port interrupts */ mv_write(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num), 0); @@ -1413,8 +1414,8 @@ static int mv643xx_eth_probe(struct platform_device *pdev) p = dev->dev_addr; printk(KERN_NOTICE - "%s: port %d with MAC address %02x:%02x:%02x:%02x:%02x:%02x\n", - dev->name, port_num, p[0], p[1], p[2], p[3], p[4], p[5]); + "%s: port %d with MAC address %s\n", + dev->name, port_num, print_mac(mac, p)); if (dev->features & NETIF_F_SG) printk(KERN_NOTICE "%s: Scatter Gather Enabled\n", dev->name); diff --git a/drivers/net/mvme147.c b/drivers/net/mvme147.c index 837ad0f2b05..86c9c06433c 100644 --- a/drivers/net/mvme147.c +++ b/drivers/net/mvme147.c @@ -67,6 +67,7 @@ struct net_device * __init mvme147lance_probe(int unit) u_long *addr; u_long address; int err; + DECLARE_MAC_BUF(mac); if (!MACH_IS_MVME147 || called) return ERR_PTR(-ENODEV); @@ -101,12 +102,10 @@ struct net_device * __init mvme147lance_probe(int unit) address=address>>8; dev->dev_addr[3]=address&0xff; - printk("%s: MVME147 at 0x%08lx, irq %d, Hardware Address %02x:%02x:%02x:%02x:%02x:%02x\n", - dev->name, dev->base_addr, MVME147_LANCE_IRQ, - dev->dev_addr[0], - dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], - dev->dev_addr[5]); + printk("%s: MVME147 at 0x%08lx, irq %d, " + "Hardware Address %s\n", + dev->name, dev->base_addr, MVME147_LANCE_IRQ, + print_mac(mac, dev->dev_addr)); lp = (struct m147lance_private *)dev->priv; lp->ram = __get_dma_pages(GFP_ATOMIC, 3); /* 16K */ diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 2f8864e70ca..38b03f538e9 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -2395,6 +2395,7 @@ static void myri10ge_set_multicast_list(struct net_device *dev) struct dev_mc_list *mc_list; __be32 data[2] = { 0, 0 }; int err; + DECLARE_MAC_BUF(mac); mgp = netdev_priv(dev); /* can be called from atomic contexts, @@ -2442,14 +2443,8 @@ static void myri10ge_set_multicast_list(struct net_device *dev) printk(KERN_ERR "myri10ge: %s: Failed " "MXGEFW_JOIN_MULTICAST_GROUP, error status:" "%d\t", dev->name, err); - printk(KERN_ERR "MAC %02x:%02x:%02x:%02x:%02x:%02x\n", - ((unsigned char *)&mc_list->dmi_addr)[0], - ((unsigned char *)&mc_list->dmi_addr)[1], - ((unsigned char *)&mc_list->dmi_addr)[2], - ((unsigned char *)&mc_list->dmi_addr)[3], - ((unsigned char *)&mc_list->dmi_addr)[4], - ((unsigned char *)&mc_list->dmi_addr)[5] - ); + printk(KERN_ERR "MAC %s\n", + print_mac(mac, mc_list->dmi_addr)); goto abort; } } diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c index 35c4c598c8d..d68ee51c095 100644 --- a/drivers/net/myri_sbus.c +++ b/drivers/net/myri_sbus.c @@ -311,12 +311,12 @@ static void myri_is_not_so_happy(struct myri_eth *mp) #ifdef DEBUG_HEADER static void dump_ehdr(struct ethhdr *ehdr) { - printk("ehdr[h_dst(%02x:%02x:%02x:%02x:%02x:%02x)" - "h_source(%02x:%02x:%02x:%02x:%02x:%02x)h_proto(%04x)]\n", - ehdr->h_dest[0], ehdr->h_dest[1], ehdr->h_dest[2], - ehdr->h_dest[3], ehdr->h_dest[4], ehdr->h_dest[4], - ehdr->h_source[0], ehdr->h_source[1], ehdr->h_source[2], - ehdr->h_source[3], ehdr->h_source[4], ehdr->h_source[4], + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); + printk("ehdr[h_dst(%s)" + "h_source(%s)" + "h_proto(%04x)]\n", + print_mac(mac, ehdr->h_dest), print_mac(mac2, ehdr->h_source), ehdr->h_proto); } @@ -325,13 +325,7 @@ static void dump_ehdr_and_myripad(unsigned char *stuff) struct ethhdr *ehdr = (struct ethhdr *) (stuff + 2); printk("pad[%02x:%02x]", stuff[0], stuff[1]); - printk("ehdr[h_dst(%02x:%02x:%02x:%02x:%02x:%02x)" - "h_source(%02x:%02x:%02x:%02x:%02x:%02x)h_proto(%04x)]\n", - ehdr->h_dest[0], ehdr->h_dest[1], ehdr->h_dest[2], - ehdr->h_dest[3], ehdr->h_dest[4], ehdr->h_dest[4], - ehdr->h_source[0], ehdr->h_source[1], ehdr->h_source[2], - ehdr->h_source[3], ehdr->h_source[4], ehdr->h_source[4], - ehdr->h_proto); + dump_ehdr(ehdr); } #endif @@ -895,6 +889,7 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev) struct myri_eth *mp; unsigned char prop_buf[32]; int i; + DECLARE_MAC_BUF(mac); DET(("myri_ether_init(%p,%d):\n", sdev, num)); dev = alloc_etherdev(sizeof(struct myri_eth)); @@ -1089,12 +1084,8 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev) num++; - printk("%s: MyriCOM MyriNET Ethernet ", dev->name); - - for (i = 0; i < 6; i++) - printk("%2.2x%c", dev->dev_addr[i], - i == 5 ? ' ' : ':'); - printk("\n"); + printk("%s: MyriCOM MyriNET Ethernet %s\n", + dev->name, print_mac(mac, dev->dev_addr)); return 0; diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index 5ee4e8795d2..ea38da6d31f 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -805,6 +805,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, const int pcibar = 1; /* PCI base address register */ int prev_eedata; u32 tmp; + DECLARE_MAC_BUF(mac); /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -958,12 +959,10 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, goto err_create_file; if (netif_msg_drv(np)) { - printk(KERN_INFO "natsemi %s: %s at %#08lx (%s), ", - dev->name, natsemi_pci_info[chip_idx].name, iostart, - pci_name(np->pci_dev)); - for (i = 0; i < ETH_ALEN-1; i++) - printk("%02x:", dev->dev_addr[i]); - printk("%02x, IRQ %d", dev->dev_addr[i], irq); + printk(KERN_INFO "natsemi %s: %s at %#08lx " + "(%s), %s, IRQ %d", + dev->name, natsemi_pci_info[chip_idx].name, iostart, + pci_name(np->pci_dev), print_mac(mac, dev->dev_addr), irq); if (dev->if_port == PORT_TP) printk(", port TP.\n"); else if (np->ignore_phy) diff --git a/drivers/net/ne-h8300.c b/drivers/net/ne-h8300.c index 2b85d1b5334..368f2560856 100644 --- a/drivers/net/ne-h8300.c +++ b/drivers/net/ne-h8300.c @@ -204,6 +204,7 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr) static unsigned version_printed; struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); unsigned char bus_width; + DECLARE_MAC_BUF(mac); if (!request_region(ioaddr, NE_IO_EXTENT, DRV_NAME)) return -EBUSY; @@ -296,12 +297,11 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr) dev->base_addr = ioaddr; - for(i = 0; i < ETHER_ADDR_LEN; i++) { - printk(" %2.2x", SA_prom[i]); + for(i = 0; i < ETHER_ADDR_LEN; i++) dev->dev_addr[i] = SA_prom[i]; - } + printk(" %s\n", print_mac(mac, dev->dev_addr)); - printk("\n%s: %s found at %#x, using IRQ %d.\n", + printk("%s: %s found at %#x, using IRQ %d.\n", dev->name, name, ioaddr, dev->irq); ei_status.name = name; diff --git a/drivers/net/ne.c b/drivers/net/ne.c index 27d87985bb6..874d291cbae 100644 --- a/drivers/net/ne.c +++ b/drivers/net/ne.c @@ -291,6 +291,7 @@ static int __init ne_probe1(struct net_device *dev, unsigned long ioaddr) int neX000, ctron, copam, bad_card; int reg0, ret; static unsigned version_printed; + DECLARE_MAC_BUF(mac); if (!request_region(ioaddr, NE_IO_EXTENT, DRV_NAME)) return -EBUSY; @@ -503,16 +504,14 @@ static int __init ne_probe1(struct net_device *dev, unsigned long ioaddr) for (i = 0 ; i < ETHER_ADDR_LEN ; i++) { dev->dev_addr[i] = SA_prom[i] = inb_p(ioaddr + EN1_PHYS_SHIFT(i)); - printk(" %2.2x", SA_prom[i]); } #else for(i = 0; i < ETHER_ADDR_LEN; i++) { - printk(" %2.2x", SA_prom[i]); dev->dev_addr[i] = SA_prom[i]; } #endif - printk("\n"); + printk("%s\n", print_mac(mac, dev->dev_addr)); ei_status.name = name; ei_status.tx_start_page = start_page; diff --git a/drivers/net/ne2.c b/drivers/net/ne2.c index f73073b1218..f4cd8c7e81b 100644 --- a/drivers/net/ne2.c +++ b/drivers/net/ne2.c @@ -302,6 +302,7 @@ out: static int ne2_procinfo(char *buf, int slot, struct net_device *dev) { int len=0; + DECLARE_MAC_BUF(mac); len += sprintf(buf+len, "The NE/2 Ethernet Adapter\n" ); len += sprintf(buf+len, "Driver written by Wim Dumon "); @@ -312,12 +313,7 @@ static int ne2_procinfo(char *buf, int slot, struct net_device *dev) len += sprintf(buf+len, "Based on the original NE2000 drivers\n" ); len += sprintf(buf+len, "Base IO: %#x\n", (unsigned int)dev->base_addr); len += sprintf(buf+len, "IRQ : %d\n", dev->irq); - -#define HW_ADDR(i) dev->dev_addr[i] - len += sprintf(buf+len, "HW addr : %x:%x:%x:%x:%x:%x\n", - HW_ADDR(0), HW_ADDR(1), HW_ADDR(2), - HW_ADDR(3), HW_ADDR(4), HW_ADDR(5) ); -#undef HW_ADDR + len += sprintf(buf+len, "HW addr : %s\n", print_mac(mac, dev->dev_addr)); return len; } @@ -330,6 +326,7 @@ static int __init ne2_probe1(struct net_device *dev, int slot) const char *name = "NE/2"; int start_page, stop_page; static unsigned version_printed; + DECLARE_MAC_BUF(mac); if (ei_debug && version_printed++ == 0) printk(version); @@ -469,12 +466,12 @@ static int __init ne2_probe1(struct net_device *dev, int slot) dev->base_addr = base_addr; - for(i = 0; i < ETHER_ADDR_LEN; i++) { - printk(" %2.2x", SA_prom[i]); + for(i = 0; i < ETHER_ADDR_LEN; i++) dev->dev_addr[i] = SA_prom[i]; - } - printk("\n%s: %s found at %#x, using IRQ %d.\n", + printk(" %s\n", print_mac(mac, dev->dev_addr)); + + printk("%s: %s found at %#x, using IRQ %d.\n", dev->name, name, base_addr, dev->irq); mca_set_adapter_procfn(slot, (MCA_ProcFn) ne2_procinfo, dev); diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c index a5879672903..b569c90da4b 100644 --- a/drivers/net/ne2k-pci.c +++ b/drivers/net/ne2k-pci.c @@ -212,6 +212,7 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev, static unsigned int fnd_cnt; long ioaddr; int flags = pci_clone_list[chip_idx].flags; + DECLARE_MAC_BUF(mac); /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -365,12 +366,12 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev, if (i) goto err_out_free_netdev; - printk("%s: %s found at %#lx, IRQ %d, ", - dev->name, pci_clone_list[chip_idx].name, ioaddr, dev->irq); - for(i = 0; i < 6; i++) { - printk("%2.2X%s", SA_prom[i], i == 5 ? ".\n": ":"); + for(i = 0; i < 6; i++) dev->dev_addr[i] = SA_prom[i]; - } + printk("%s: %s found at %#lx, IRQ %d, %s.\n", + dev->name, pci_clone_list[chip_idx].name, ioaddr, dev->irq, + print_mac(mac, dev->dev_addr)); + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); return 0; diff --git a/drivers/net/ne3210.c b/drivers/net/ne3210.c index b1bf8331e87..425043a88db 100644 --- a/drivers/net/ne3210.c +++ b/drivers/net/ne3210.c @@ -99,6 +99,7 @@ static int __init ne3210_eisa_probe (struct device *device) int i, retval, port_index; struct eisa_device *edev = to_eisa_device (device); struct net_device *dev; + DECLARE_MAC_BUF(mac); /* Allocate dev->priv and fill in 8390 specific dev fields. */ if (!(dev = alloc_ei_netdev ())) { @@ -127,17 +128,15 @@ static int __init ne3210_eisa_probe (struct device *device) inb(ioaddr + NE3210_CFG1), inb(ioaddr + NE3210_CFG2)); #endif - port_index = inb(ioaddr + NE3210_CFG2) >> 6; - printk("ne3210.c: NE3210 in EISA slot %d, media: %s, addr:", - edev->slot, ifmap[port_index]); for(i = 0; i < ETHER_ADDR_LEN; i++) - printk(" %02x", (dev->dev_addr[i] = inb(ioaddr + NE3210_SA_PROM + i))); - + dev->dev_addr[i] = inb(ioaddr + NE3210_SA_PROM + i); + printk("ne3210.c: NE3210 in EISA slot %d, media: %s, addr: %s.\n", + edev->slot, ifmap[port_index], print_mac(mac, dev->dev_addr)); /* Snarf the interrupt now. CFG file has them all listed as `edge' with share=NO */ dev->irq = irq_map[(inb(ioaddr + NE3210_CFG2) >> 3) & 0x07]; - printk(".\nne3210.c: using IRQ %d, ", dev->irq); + printk("ne3210.c: using IRQ %d, ", dev->irq); retval = request_irq(dev->irq, ei_interrupt, 0, DRV_NAME, dev); if (retval) { diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 69ef1eb03be..5ffbb889164 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -306,18 +306,16 @@ static ssize_t show_remote_ip(struct netconsole_target *nt, char *buf) static ssize_t show_local_mac(struct netconsole_target *nt, char *buf) { - return snprintf(buf, PAGE_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x\n", - nt->np.local_mac[0], nt->np.local_mac[1], - nt->np.local_mac[2], nt->np.local_mac[3], - nt->np.local_mac[4], nt->np.local_mac[5]); + DECLARE_MAC_BUF(mac); + return snprintf(buf, PAGE_SIZE, "%s\n", + print_mac(mac, nt->np.local_mac)); } static ssize_t show_remote_mac(struct netconsole_target *nt, char *buf) { - return snprintf(buf, PAGE_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x\n", - nt->np.remote_mac[0], nt->np.remote_mac[1], - nt->np.remote_mac[2], nt->np.remote_mac[3], - nt->np.remote_mac[4], nt->np.remote_mac[5]); + DECLARE_MAC_BUF(mac); + return snprintf(buf, PAGE_SIZE, "%s\n", + print_mac(mac, nt->np.remote_mac)); } /* diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 1b165a8c74f..b9cde65e7f3 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -285,6 +285,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) int valid_mac = 0; u32 val; int pci_func_id = PCI_FUNC(pdev->devfn); + DECLARE_MAC_BUF(mac); printk(KERN_INFO "%s \n", netxen_nic_driver_string); @@ -573,15 +574,9 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) memcpy(netdev->perm_addr, netdev->dev_addr, netdev->addr_len); if (!is_valid_ether_addr(netdev->perm_addr)) { - printk(KERN_ERR "%s: Bad MAC address " - "%02x:%02x:%02x:%02x:%02x:%02x.\n", - netxen_nic_driver_name, - netdev->dev_addr[0], - netdev->dev_addr[1], - netdev->dev_addr[2], - netdev->dev_addr[3], - netdev->dev_addr[4], - netdev->dev_addr[5]); + printk(KERN_ERR "%s: Bad MAC address %s.\n", + netxen_nic_driver_name, + print_mac(mac, netdev->dev_addr)); } else { if (adapter->macaddr_set) adapter->macaddr_set(adapter, diff --git a/drivers/net/netxen/netxen_nic_niu.c b/drivers/net/netxen/netxen_nic_niu.c index 05e0577a0e1..5b9e1b300fa 100644 --- a/drivers/net/netxen/netxen_nic_niu.c +++ b/drivers/net/netxen/netxen_nic_niu.c @@ -603,6 +603,7 @@ int netxen_niu_macaddr_set(struct netxen_adapter *adapter, int phy = physical_port[adapter->portnum]; unsigned char mac_addr[6]; int i; + DECLARE_MAC_BUF(mac); for (i = 0; i < 10; i++) { temp[0] = temp[1] = 0; @@ -627,15 +628,10 @@ int netxen_niu_macaddr_set(struct netxen_adapter *adapter, if (i == 10) { printk(KERN_ERR "%s: cannot set Mac addr for %s\n", netxen_nic_driver_name, adapter->netdev->name); - printk(KERN_ERR "MAC address set: " - "%02x:%02x:%02x:%02x:%02x:%02x.\n", - addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); - - printk(KERN_ERR "MAC address get: " - "%02x:%02x:%02x:%02x:%02x:%02x.\n", - mac_addr[0], - mac_addr[1], - mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); + printk(KERN_ERR "MAC address set: %s.\n", + print_mac(mac, addr)); + printk(KERN_ERR "MAC address get: %s.\n", + print_mac(mac, mac_addr)); } return 0; } diff --git a/drivers/net/ni5010.c b/drivers/net/ni5010.c index 1dc74a78afa..14a768fbce2 100644 --- a/drivers/net/ni5010.c +++ b/drivers/net/ni5010.c @@ -203,6 +203,7 @@ static int __init ni5010_probe1(struct net_device *dev, int ioaddr) unsigned int data = 0; int boguscount = 40; int err = -ENODEV; + DECLARE_MAC_BUF(mac); dev->base_addr = ioaddr; dev->irq = irq; @@ -268,8 +269,9 @@ static int __init ni5010_probe1(struct net_device *dev, int ioaddr) for (i=0; i<6; i++) { outw(i, IE_GP); - printk("%2.2x ", dev->dev_addr[i] = inb(IE_SAPROM)); + dev->dev_addr[i] = inb(IE_SAPROM); } + printk("%s ", print_mac(mac, dev->dev_addr)); PRINTK2((KERN_DEBUG "%s: I/O #4 passed!\n", dev->name)); diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c index de495b69729..ea71f6d8266 100644 --- a/drivers/net/ns83820.c +++ b/drivers/net/ns83820.c @@ -1962,6 +1962,7 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_ long addr; int err; int using_dac = 0; + DECLARE_MAC_BUF(mac); /* See if we can set the dma mask early on; failure is fatal. */ if (sizeof(dma_addr_t) == 8 && @@ -2226,13 +2227,11 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_ ndev->features |= NETIF_F_HIGHDMA; } - printk(KERN_INFO "%s: ns83820 v" VERSION ": DP83820 v%u.%u: %02x:%02x:%02x:%02x:%02x:%02x io=0x%08lx irq=%d f=%s\n", + printk(KERN_INFO "%s: ns83820 v" VERSION ": DP83820 v%u.%u: %s io=0x%08lx irq=%d f=%s\n", ndev->name, (unsigned)readl(dev->base + SRR) >> 8, (unsigned)readl(dev->base + SRR) & 0xff, - ndev->dev_addr[0], ndev->dev_addr[1], - ndev->dev_addr[2], ndev->dev_addr[3], - ndev->dev_addr[4], ndev->dev_addr[5], + print_mac(mac, ndev->dev_addr), addr, pci_dev->irq, (ndev->features & NETIF_F_HIGHDMA) ? "h,sg" : "sg" ); diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index f310d94443a..4d87cd65626 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -1155,6 +1155,7 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct net_device *dev; struct pasemi_mac *mac; int err; + DECLARE_MAC_BUF(mac_buf); err = pci_enable_device(pdev); if (err) @@ -1237,11 +1238,10 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto out; } else printk(KERN_INFO "%s: PA Semi %s: intf %d, txch %d, rxch %d, " - "hw addr %02x:%02x:%02x:%02x:%02x:%02x\n", + "hw addr %s\n", dev->name, mac->type == MAC_TYPE_GMAC ? "GMAC" : "XAUI", mac->dma_if, mac->dma_txch, mac->dma_rxch, - dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + print_mac(mac_buf, dev->dev_addr)); return err; diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c index 7dace63fb6e..ed402e00e73 100644 --- a/drivers/net/pci-skeleton.c +++ b/drivers/net/pci-skeleton.c @@ -737,6 +737,7 @@ static int __devinit netdrv_init_one (struct pci_dev *pdev, int i, addr_len, option; void *ioaddr = NULL; static int board_idx = -1; + DECLARE_MAC_BUF(mac); /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -796,15 +797,11 @@ static int __devinit netdrv_init_one (struct pci_dev *pdev, tp->phys[0] = 32; - printk (KERN_INFO "%s: %s at 0x%lx, " - "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, " - "IRQ %d\n", + printk (KERN_INFO "%s: %s at 0x%lx, %sIRQ %d\n", dev->name, board_info[ent->driver_data].name, dev->base_addr, - dev->dev_addr[0], dev->dev_addr[1], - dev->dev_addr[2], dev->dev_addr[3], - dev->dev_addr[4], dev->dev_addr[5], + print_mac(mac, dev->dev_addr), dev->irq); printk (KERN_DEBUG "%s: Identified 8139 chip type '%s'\n", diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index 2b395ee21f7..73dcbb7296d 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -343,6 +343,7 @@ static int tc574_config(struct pcmcia_device *link) u16 *phys_addr; char *cardname; union wn3_config config; + DECLARE_MAC_BUF(mac); phys_addr = (u16 *)dev->dev_addr; @@ -458,10 +459,10 @@ static int tc574_config(struct pcmcia_device *link) strcpy(lp->node.dev_name, dev->name); - printk(KERN_INFO "%s: %s at io %#3lx, irq %d, hw_addr ", - dev->name, cardname, dev->base_addr, dev->irq); - for (i = 0; i < 6; i++) - printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : ".\n")); + printk(KERN_INFO "%s: %s at io %#3lx, irq %d, " + "hw_addr %s.\n", + dev->name, cardname, dev->base_addr, dev->irq, + print_mac(mac, dev->dev_addr)); printk(" %dK FIFO split %s Rx:Tx, %sMII interface.\n", 8 << config.u.ram_size, ram_split[config.u.ram_split], config.u.autoselect ? "autoselect " : ""); diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c index 2136c80c058..32076ca6a9e 100644 --- a/drivers/net/pcmcia/3c589_cs.c +++ b/drivers/net/pcmcia/3c589_cs.c @@ -255,6 +255,7 @@ static int tc589_config(struct pcmcia_device *link) int last_fn, last_ret, i, j, multi = 0, fifo; kio_addr_t ioaddr; char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"}; + DECLARE_MAC_BUF(mac); DEBUG(0, "3c589_config(0x%p)\n", link); @@ -330,11 +331,10 @@ static int tc589_config(struct pcmcia_device *link) strcpy(lp->node.dev_name, dev->name); - printk(KERN_INFO "%s: 3Com 3c%s, io %#3lx, irq %d, hw_addr ", - dev->name, (multi ? "562" : "589"), dev->base_addr, - dev->irq); - for (i = 0; i < 6; i++) - printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n")); + printk(KERN_INFO "%s: 3Com 3c%s, io %#3lx, irq %d, " + "hw_addr %s\n", + dev->name, (multi ? "562" : "589"), dev->base_addr, dev->irq, + print_mac(mac, dev->dev_addr)); printk(KERN_INFO " %dK FIFO split %s Rx:Tx, %s xcvr\n", (fifo & 7) ? 32 : 8, ram_split[(fifo >> 16) & 3], if_names[dev->if_port]); diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index 28eea206766..de59313d10f 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -292,6 +292,7 @@ static int axnet_config(struct pcmcia_device *link) cisparse_t parse; int i, j, last_ret, last_fn; u_short buf[64]; + DECLARE_MAC_BUF(mac); DEBUG(0, "axnet_config(0x%p)\n", link); @@ -403,11 +404,11 @@ static int axnet_config(struct pcmcia_device *link) strcpy(info->node.dev_name, dev->name); - printk(KERN_INFO "%s: Asix AX88%d90: io %#3lx, irq %d, hw_addr ", + printk(KERN_INFO "%s: Asix AX88%d90: io %#3lx, irq %d, " + "hw_addr %s\n", dev->name, ((info->flags & IS_AX88790) ? 7 : 1), - dev->base_addr, dev->irq); - for (i = 0; i < 6; i++) - printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n")); + dev->base_addr, dev->irq, + print_mac(mac, dev->dev_addr)); if (info->phy_id != -1) { DEBUG(0, " MII transceiver at index %d, status %x.\n", info->phy_id, j); } else { diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c index 7f29e95a064..62844677c78 100644 --- a/drivers/net/pcmcia/fmvj18x_cs.c +++ b/drivers/net/pcmcia/fmvj18x_cs.c @@ -346,6 +346,7 @@ static int fmvj18x_config(struct pcmcia_device *link) cardtype_t cardtype; char *card_name = "unknown"; u_char *node_id; + DECLARE_MAC_BUF(mac); DEBUG(0, "fmvj18x_config(0x%p)\n", link); @@ -533,11 +534,10 @@ static int fmvj18x_config(struct pcmcia_device *link) strcpy(lp->node.dev_name, dev->name); /* print current configuration */ - printk(KERN_INFO "%s: %s, sram %s, port %#3lx, irq %d, hw_addr ", + printk(KERN_INFO "%s: %s, sram %s, port %#3lx, irq %d, " + "hw_addr %s\n", dev->name, card_name, sram_config == 0 ? "4K TX*2" : "8K TX*2", - dev->base_addr, dev->irq); - for (i = 0; i < 6; i++) - printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n")); + dev->base_addr, dev->irq, print_mac(mac, dev->dev_addr)); return 0; diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c index 1bb2ffa294d..a355a93b908 100644 --- a/drivers/net/pcmcia/nmclan_cs.c +++ b/drivers/net/pcmcia/nmclan_cs.c @@ -658,6 +658,7 @@ static int nmclan_config(struct pcmcia_device *link) u_char buf[64]; int i, last_ret, last_fn; kio_addr_t ioaddr; + DECLARE_MAC_BUF(mac); DEBUG(0, "nmclan_config(0x%p)\n", link); @@ -716,10 +717,10 @@ static int nmclan_config(struct pcmcia_device *link) strcpy(lp->node.dev_name, dev->name); - printk(KERN_INFO "%s: nmclan: port %#3lx, irq %d, %s port, hw_addr ", - dev->name, dev->base_addr, dev->irq, if_names[dev->if_port]); - for (i = 0; i < 6; i++) - printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n")); + printk(KERN_INFO "%s: nmclan: port %#3lx, irq %d, %s port," + " hw_addr %s\n", + dev->name, dev->base_addr, dev->irq, if_names[dev->if_port], + print_mac(mac, dev->dev_addr)); return 0; cs_failed: diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index 8ce251cd320..6a647516c38 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -38,7 +38,7 @@ #include #include #include -#include <../drivers/net/8390.h> +#include "../8390.h" #include #include @@ -521,6 +521,7 @@ static int pcnet_config(struct pcmcia_device *link) int has_shmem = 0; u_short buf[64]; hw_info_t *hw_info; + DECLARE_MAC_BUF(mac); DEBUG(0, "pcnet_config(0x%p)\n", link); @@ -670,9 +671,7 @@ static int pcnet_config(struct pcmcia_device *link) printk (" mem %#5lx,", dev->mem_start); if (info->flags & HAS_MISC_REG) printk(" %s xcvr,", if_names[dev->if_port]); - printk(" hw_addr "); - for (i = 0; i < 6; i++) - printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n")); + printk(" hw_addr %s\n", print_mac(mac, dev->dev_addr)); return 0; cs_failed: diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index b25f1985d03..58d716fd17c 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -962,6 +962,7 @@ static int smc91c92_config(struct pcmcia_device *link) int i, j, rev; kio_addr_t ioaddr; u_long mir; + DECLARE_MAC_BUF(mac); DEBUG(0, "smc91c92_config(0x%p)\n", link); @@ -1074,10 +1075,9 @@ static int smc91c92_config(struct pcmcia_device *link) strcpy(smc->node.dev_name, dev->name); printk(KERN_INFO "%s: smc91c%s rev %d: io %#3lx, irq %d, " - "hw_addr ", dev->name, name, (rev & 0x0f), dev->base_addr, - dev->irq); - for (i = 0; i < 6; i++) - printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n")); + "hw_addr %s\n", + dev->name, name, (rev & 0x0f), dev->base_addr, dev->irq, + print_mac(mac, dev->dev_addr)); if (rev > 0) { if (mir & 0x3ff) diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index d5c2d2c8c85..c3b69602e27 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -731,6 +731,7 @@ xirc2ps_config(struct pcmcia_device * link) u_char buf[64]; cistpl_lan_node_id_t *node_id = (cistpl_lan_node_id_t*)parse.funce.data; cistpl_cftable_entry_t *cf = &parse.cftable_entry; + DECLARE_MAC_BUF(mac); local->dingo_ccr = NULL; @@ -1032,11 +1033,9 @@ xirc2ps_config(struct pcmcia_device * link) strcpy(local->node.dev_name, dev->name); /* give some infos about the hardware */ - printk(KERN_INFO "%s: %s: port %#3lx, irq %d, hwaddr", - dev->name, local->manf_str,(u_long)dev->base_addr, (int)dev->irq); - for (i = 0; i < 6; i++) - printk("%c%02X", i?':':' ', dev->dev_addr[i]); - printk("\n"); + printk(KERN_INFO "%s: %s: port %#3lx, irq %d, hwaddr %s\n", + dev->name, local->manf_str,(u_long)dev->base_addr, (int)dev->irq, + print_mac(mac, dev->dev_addr)); return 0; diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index 2f130e06b6d..ba2eb04aac9 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -955,6 +955,7 @@ static int pppoe_seq_show(struct seq_file *seq, void *v) { struct pppox_sock *po; char *dev_name; + DECLARE_MAC_BUF(mac); if (v == SEQ_START_TOKEN) { seq_puts(seq, "Id Address Device\n"); @@ -964,11 +965,8 @@ static int pppoe_seq_show(struct seq_file *seq, void *v) po = v; dev_name = po->pppoe_pa.dev; - seq_printf(seq, "%08X %02X:%02X:%02X:%02X:%02X:%02X %8s\n", - po->pppoe_pa.sid, - po->pppoe_pa.remote[0], po->pppoe_pa.remote[1], - po->pppoe_pa.remote[2], po->pppoe_pa.remote[3], - po->pppoe_pa.remote[4], po->pppoe_pa.remote[5], dev_name); + seq_printf(seq, "%08X %s %8s\n", + po->pppoe_pa.sid, print_mac(mac, po->pppoe_pa.remote), dev_name); out: return 0; } diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c index f375bbbd660..0a42bf51746 100644 --- a/drivers/net/ps3_gelic_net.c +++ b/drivers/net/ps3_gelic_net.c @@ -1348,6 +1348,7 @@ static int gelic_net_setup_netdev(struct gelic_net_card *card) unsigned int i; int status; u64 v1, v2; + DECLARE_MAC_BUF(mac); SET_NETDEV_DEV(netdev, &card->dev->core); spin_lock_init(&card->tx_dma_lock); @@ -1373,10 +1374,8 @@ static int gelic_net_setup_netdev(struct gelic_net_card *card) v1 <<= 16; memcpy(addr.sa_data, &v1, ETH_ALEN); memcpy(netdev->dev_addr, addr.sa_data, ETH_ALEN); - dev_info(ctodev(card), "MAC addr %02x:%02x:%02x:%02x:%02x:%02x\n", - netdev->dev_addr[0], netdev->dev_addr[1], - netdev->dev_addr[2], netdev->dev_addr[3], - netdev->dev_addr[4], netdev->dev_addr[5]); + dev_info(ctodev(card), "MAC addr %s\n", + print_mac(mac, netdev->dev_addr)); card->vlan_index = -1; /* no vlan */ for (i = 0; i < GELIC_NET_VLAN_MAX; i++) { diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c index 97c6ed07dd1..ed79aa820df 100755 --- a/drivers/net/qla3xxx.c +++ b/drivers/net/qla3xxx.c @@ -3557,6 +3557,7 @@ static void ql_display_dev_info(struct net_device *ndev) { struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev); struct pci_dev *pdev = qdev->pdev; + DECLARE_MAC_BUF(mac); printk(KERN_INFO PFX "\n%s Adapter %d RevisionID %d found %s on PCI slot %d.\n", @@ -3582,10 +3583,8 @@ static void ql_display_dev_info(struct net_device *ndev) if (netif_msg_probe(qdev)) printk(KERN_INFO PFX - "%s: MAC address %02x:%02x:%02x:%02x:%02x:%02x\n", - ndev->name, ndev->dev_addr[0], ndev->dev_addr[1], - ndev->dev_addr[2], ndev->dev_addr[3], ndev->dev_addr[4], - ndev->dev_addr[5]); + "%s: MAC address %s\n", + ndev->name, print_mac(mac, ndev->dev_addr)); } static int ql_adapter_down(struct ql3_adapter *qdev, int do_reset) diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c index d43dcf3ed5a..e7fd08adbba 100644 --- a/drivers/net/rionet.c +++ b/drivers/net/rionet.c @@ -432,6 +432,7 @@ static int rionet_setup_netdev(struct rio_mport *mport) struct net_device *ndev = NULL; struct rionet_private *rnet; u16 device_id; + DECLARE_MAC_BUF(mac); /* Allocate our net_device structure */ ndev = alloc_etherdev(sizeof(struct rionet_private)); @@ -472,13 +473,12 @@ static int rionet_setup_netdev(struct rio_mport *mport) if (rc != 0) goto out; - printk("%s: %s %s Version %s, MAC %02x:%02x:%02x:%02x:%02x:%02x\n", + printk("%s: %s %s Version %s, MAC %s\n", ndev->name, DRV_NAME, DRV_DESC, DRV_VERSION, - ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2], - ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]); + print_mac(mac, ndev->dev_addr)); out: return rc; diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c index 03facba0525..19152f54ef2 100644 --- a/drivers/net/rrunner.c +++ b/drivers/net/rrunner.c @@ -520,7 +520,7 @@ static int __devinit rr_init(struct net_device *dev) struct rr_regs __iomem *regs; struct eeprom *hw = NULL; u32 sram_size, rev; - int i; + DECLARE_MAC_BUF(mac); rrpriv = netdev_priv(dev); regs = rrpriv->regs; @@ -558,11 +558,7 @@ static int __devinit rr_init(struct net_device *dev) *(u32 *)(dev->dev_addr+2) = htonl(rr_read_eeprom_word(rrpriv, &hw->manf.BoardULA[4])); - printk(" MAC: "); - - for (i = 0; i < 5; i++) - printk("%2.2x:", dev->dev_addr[i]); - printk("%2.2x\n", dev->dev_addr[i]); + printk(" MAC: %s\n", print_mac(mac, dev->dev_addr)); sram_size = rr_read_eeprom_word(rrpriv, (void *)8); printk(" SRAM size 0x%06x\n", sram_size); diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index a285dd734a0..26895de3e26 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -7417,6 +7417,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) struct config_param *config; int mode; u8 dev_intr_type = intr_type; + DECLARE_MAC_BUF(mac); if ((ret = s2io_verify_parm(pdev, &dev_intr_type))) return ret; @@ -7720,14 +7721,8 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) sp->product_name, pdev->revision); DBG_PRINT(ERR_DBG, "%s: Driver version %s\n", dev->name, s2io_driver_version); - DBG_PRINT(ERR_DBG, "%s: MAC ADDR: " - "%02x:%02x:%02x:%02x:%02x:%02x", dev->name, - sp->def_mac_addr[0].mac_addr[0], - sp->def_mac_addr[0].mac_addr[1], - sp->def_mac_addr[0].mac_addr[2], - sp->def_mac_addr[0].mac_addr[3], - sp->def_mac_addr[0].mac_addr[4], - sp->def_mac_addr[0].mac_addr[5]); + DBG_PRINT(ERR_DBG, "%s: MAC ADDR: %s\n", + dev->name, print_mac(mac, dev->dev_addr)); DBG_PRINT(ERR_DBG, "SERIAL NUMBER: %s\n", sp->serial_num); if (sp->device_type & XFRAME_II_DEVICE) { mode = s2io_print_pci_mode(sp); diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index 76e7ee9a6cb..6001ab47fba 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -2407,6 +2407,7 @@ static int sbmac_init(struct net_device *dev, int idx) uint64_t ea_reg; int i; int err; + DECLARE_MAC_BUF(mac); sc = netdev_priv(dev); @@ -2487,10 +2488,8 @@ static int sbmac_init(struct net_device *dev, int idx) * was being displayed) */ printk(KERN_INFO - "%s: SiByte Ethernet at 0x%08lX, address: %02X:%02X:%02X:%02X:%02X:%02X\n", - dev->name, dev->base_addr, - eaddr[0],eaddr[1],eaddr[2],eaddr[3],eaddr[4],eaddr[5]); - + "%s: SiByte Ethernet at 0x%08lX, address: %s\n", + dev->name, dev->base_addr, print_mac(mac, eaddr)); return 0; diff --git a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c index 8ef94028cba..48c64fb20ee 100644 --- a/drivers/net/seeq8005.c +++ b/drivers/net/seeq8005.c @@ -158,6 +158,7 @@ static int __init seeq8005_probe1(struct net_device *dev, int ioaddr) int old_dmaar; int old_rear; int retval; + DECLARE_MAC_BUF(mac); if (!request_region(ioaddr, SEEQ8005_IO_EXTENT, "seeq8005")) return -ENODEV; @@ -301,7 +302,8 @@ static int __init seeq8005_probe1(struct net_device *dev, int ioaddr) /* Retrieve and print the ethernet address. */ for (i = 0; i < 6; i++) - printk(" %2.2x", dev->dev_addr[i] = SA_prom[i+6]); + dev->dev_addr[i] = SA_prom[i+6]; + printk("%s", print_mac(mac, dev->dev_addr)); if (dev->irq == 0xff) ; /* Do nothing: a user-level program will set it. */ diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c index 5189ef06688..ff405631035 100644 --- a/drivers/net/sgiseeq.c +++ b/drivers/net/sgiseeq.c @@ -622,6 +622,7 @@ static int __init sgiseeq_probe(struct platform_device *pdev) struct sgiseeq_private *sp; struct net_device *dev; int err, i; + DECLARE_MAC_BUF(mac); dev = alloc_etherdev(sizeof (struct sgiseeq_private)); if (!dev) { @@ -695,9 +696,8 @@ static int __init sgiseeq_probe(struct platform_device *pdev) goto err_out_free_page; } - printk(KERN_INFO "%s: %s ", dev->name, sgiseeqstr); - for (i = 0; i < 6; i++) - printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':'); + printk(KERN_INFO "%s: %s %s\n", + dev->name, sgiseeqstr, print_mac(mac, dev->dev_addr)); return 0; diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index 808141b4658..720088396bb 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c @@ -1759,6 +1759,7 @@ static int __devinit sis190_init_one(struct pci_dev *pdev, struct net_device *dev; void __iomem *ioaddr; int rc; + DECLARE_MAC_BUF(mac); if (!printed_version) { net_drv(&debug, KERN_INFO SIS190_DRIVER_NAME " loaded.\n"); @@ -1809,12 +1810,9 @@ static int __devinit sis190_init_one(struct pci_dev *pdev, goto err_remove_mii; net_probe(tp, KERN_INFO "%s: %s at %p (IRQ: %d), " - "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n", - pci_name(pdev), sis_chip_info[ent->driver_data].name, - ioaddr, dev->irq, - dev->dev_addr[0], dev->dev_addr[1], - dev->dev_addr[2], dev->dev_addr[3], - dev->dev_addr[4], dev->dev_addr[5]); + "%s\n", + pci_name(pdev), sis_chip_info[ent->driver_data].name, + ioaddr, dev->irq, print_mac(mac, dev->dev_addr)); net_probe(tp, KERN_INFO "%s: %s mode.\n", dev->name, (tp->features & F_HAS_RGMII) ? "RGMII" : "GMII"); diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index 5da8e671324..0857d2c88aa 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -404,6 +404,7 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev, int i, ret; const char *card_name = card_names[pci_id->driver_data]; const char *dev_name = pci_name(pci_dev); + DECLARE_MAC_BUF(mac); /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -533,11 +534,9 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev, goto err_unmap_rx; /* print some information about our NIC */ - printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", net_dev->name, - card_name, ioaddr, net_dev->irq); - for (i = 0; i < 5; i++) - printk("%2.2x:", (u8)net_dev->dev_addr[i]); - printk("%2.2x.\n", net_dev->dev_addr[i]); + printk(KERN_INFO "%s: %s at %#lx, IRQ %d, %s\n", + net_dev->name, card_name, ioaddr, net_dev->irq, + print_mac(mac, net_dev->dev_addr)); /* Detect Wake on Lan support */ ret = (inl(net_dev->base_addr + CFGPMC) & PMESP) >> 27; diff --git a/drivers/net/skge.c b/drivers/net/skge.c index cac499f8413..ec1acfddf35 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -3616,12 +3616,11 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port, static void __devinit skge_show_addr(struct net_device *dev) { const struct skge_port *skge = netdev_priv(dev); + DECLARE_MAC_BUF(mac); if (netif_msg_probe(skge)) - printk(KERN_INFO PFX "%s: addr %02x:%02x:%02x:%02x:%02x:%02x\n", - dev->name, - dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + printk(KERN_INFO PFX "%s: addr %s\n", + dev->name, print_mac(mac, dev->dev_addr)); } static int __devinit skge_probe(struct pci_dev *pdev, diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index b8c15f881eb..a70bcbcf8a1 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -3984,12 +3984,11 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, static void __devinit sky2_show_addr(struct net_device *dev) { const struct sky2_port *sky2 = netdev_priv(dev); + DECLARE_MAC_BUF(mac); if (netif_msg_probe(sky2)) - printk(KERN_INFO PFX "%s: addr %02x:%02x:%02x:%02x:%02x:%02x\n", - dev->name, - dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + printk(KERN_INFO PFX "%s: addr %s\n", + dev->name, print_mac(mac, dev->dev_addr)); } /* Handle software interrupt used during MSI test */ diff --git a/drivers/net/smc-mca.c b/drivers/net/smc-mca.c index 3b43fa8fd08..d6abb68e6e2 100644 --- a/drivers/net/smc-mca.c +++ b/drivers/net/smc-mca.c @@ -196,6 +196,7 @@ static int __init ultramca_probe(struct device *gen_dev) int tirq = 0; int base_addr = ultra_io[ultra_found]; int irq = ultra_irq[ultra_found]; + DECLARE_MAC_BUF(mac); if (base_addr || irq) { printk(KERN_INFO "Probing for SMC MCA adapter"); @@ -330,10 +331,11 @@ static int __init ultramca_probe(struct device *gen_dev) reg4 = inb(ioaddr + 4) & 0x7f; outb(reg4, ioaddr + 4); - printk(KERN_INFO "smc_mca[%d]: Parameters: %#3x,", slot + 1, ioaddr); - for (i = 0; i < 6; i++) - printk(" %2.2X", dev->dev_addr[i] = inb(ioaddr + 8 + i)); + dev->dev_addr[i] = inb(ioaddr + 8 + i); + + printk(KERN_INFO "smc_mca[%d]: Parameters: %#3x, %s", + slot + 1, ioaddr, print_mac(mac, dev->dev_addr)); /* Switch from the station address to the alternate register set * and read the useful registers there. diff --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c index d02bd7bc1ba..00d6cf1af48 100644 --- a/drivers/net/smc-ultra.c +++ b/drivers/net/smc-ultra.c @@ -198,6 +198,7 @@ static int __init ultra_probe1(struct net_device *dev, int ioaddr) unsigned char num_pages, irqreg, addr, piomode; unsigned char idreg = inb(ioaddr + 7); unsigned char reg4 = inb(ioaddr + 4) & 0x7f; + DECLARE_MAC_BUF(mac); if (!request_region(ioaddr, ULTRA_IO_EXTENT, DRV_NAME)) return -EBUSY; @@ -224,10 +225,11 @@ static int __init ultra_probe1(struct net_device *dev, int ioaddr) model_name = (idreg & 0xF0) == 0x20 ? "SMC Ultra" : "SMC EtherEZ"; - printk("%s: %s at %#3x,", dev->name, model_name, ioaddr); - for (i = 0; i < 6; i++) - printk(" %2.2X", dev->dev_addr[i] = inb(ioaddr + 8 + i)); + dev->dev_addr[i] = inb(ioaddr + 8 + i); + + printk("%s: %s at %#3x, %s", dev->name, model_name, + ioaddr, print_mac(mac, dev->dev_addr)); /* Switch from the station address to the alternate register set and read the useful registers there. */ diff --git a/drivers/net/smc-ultra32.c b/drivers/net/smc-ultra32.c index 043a5002029..a5a91ace28c 100644 --- a/drivers/net/smc-ultra32.c +++ b/drivers/net/smc-ultra32.c @@ -163,6 +163,7 @@ static int __init ultra32_probe1(struct net_device *dev, int ioaddr) unsigned char idreg; unsigned char reg4; const char *ifmap[] = {"UTP No Link", "", "UTP/AUI", "UTP/BNC"}; + DECLARE_MAC_BUF(mac); if (!request_region(ioaddr, ULTRA32_IO_EXTENT, DRV_NAME)) return -EBUSY; @@ -203,10 +204,11 @@ static int __init ultra32_probe1(struct net_device *dev, int ioaddr) model_name = "SMC Ultra32"; - printk("%s: %s at 0x%X,", dev->name, model_name, ioaddr); - for (i = 0; i < 6; i++) - printk(" %2.2X", dev->dev_addr[i] = inb(ioaddr + 8 + i)); + dev->dev_addr[i] = inb(ioaddr + 8 + i); + + printk("%s: %s at 0x%X, %s", + dev->name, model_name, ioaddr, print_mac(mac, dev->dev_addr)); /* Switch from the station address to the alternate register set and read the useful registers there. */ diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c index 5b6748e3ea0..cb2698de519 100644 --- a/drivers/net/smc9194.c +++ b/drivers/net/smc9194.c @@ -876,6 +876,8 @@ static int __init smc_probe(struct net_device *dev, int ioaddr) word memory_info_register; word memory_cfg_register; + DECLARE_MAC_BUF(mac); + /* Grab the region so that no one else tries to probe our ioports. */ if (!request_region(ioaddr, SMC_IO_EXTENT, DRV_NAME)) return -EBUSY; @@ -1031,10 +1033,7 @@ static int __init smc_probe(struct net_device *dev, int ioaddr) /* . Print the Ethernet address */ - printk("ADDR: "); - for (i = 0; i < 5; i++) - printk("%2.2x:", dev->dev_addr[i] ); - printk("%2.2x \n", dev->dev_addr[5] ); + printk("ADDR: %s\n", print_mac(mac, dev->dev_addr)); /* set the private data to zero by default */ memset(dev->priv, 0, sizeof(struct smc_local)); diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index fe28d277f21..24e610e711e 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -1822,9 +1822,10 @@ static int __init smc_probe(struct net_device *dev, void __iomem *ioaddr) { struct smc_local *lp = netdev_priv(dev); static int version_printed = 0; - int i, retval; + int retval; unsigned int val, revision_register; const char *version_string; + DECLARE_MAC_BUF(mac); DBG(2, "%s: %s\n", CARDNAME, __FUNCTION__); @@ -2014,10 +2015,8 @@ static int __init smc_probe(struct net_device *dev, void __iomem *ioaddr) "set using ifconfig\n", dev->name); } else { /* Print the Ethernet address */ - printk("%s: Ethernet addr: ", dev->name); - for (i = 0; i < 5; i++) - printk("%2.2x:", dev->dev_addr[i]); - printk("%2.2x\n", dev->dev_addr[5]); + printk("%s: Ethernet addr: %s\n", + dev->name, print_mac(mac, dev->dev_addr)); } if (lp->phy_type == 0) { diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index 5785429ca0e..ea253754763 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -694,6 +694,7 @@ static int __devinit starfire_init_one(struct pci_dev *pdev, void __iomem *base; int drv_flags, io_size; int boguscnt; + DECLARE_MAC_BUF(mac); /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -863,11 +864,9 @@ static int __devinit starfire_init_one(struct pci_dev *pdev, if (register_netdev(dev)) goto err_out_cleardev; - printk(KERN_INFO "%s: %s at %p, ", - dev->name, netdrv_tbl[chip_idx].name, base); - for (i = 0; i < 5; i++) - printk("%2.2x:", dev->dev_addr[i]); - printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); + printk(KERN_INFO "%s: %s at %p, %s, IRQ %d.\n", + dev->name, netdrv_tbl[chip_idx].name, base, + print_mac(mac, dev->dev_addr), irq); if (drv_flags & CanHaveMII) { int phy, phy_idx = 0; @@ -1472,13 +1471,16 @@ static int __netdev_rx(struct net_device *dev, int *quota) } #ifndef final_version /* Remove after testing. */ /* You will want this info for the initial debug. */ - if (debug > 5) - printk(KERN_DEBUG " Rx data %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:" - "%2.2x %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x %2.2x%2.2x.\n", - skb->data[0], skb->data[1], skb->data[2], skb->data[3], - skb->data[4], skb->data[5], skb->data[6], skb->data[7], - skb->data[8], skb->data[9], skb->data[10], - skb->data[11], skb->data[12], skb->data[13]); + if (debug > 5) { + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); + + printk(KERN_DEBUG " Rx data %s %s" + " %2.2x%2.2x.\n", + print_mac(mac, &skb->data[0]), + print_mac(mac2, &skb->data[6]), + skb->data[12], skb->data[13]); + } #endif skb->protocol = eth_type_trans(skb, dev); diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c index f8fbc049270..f8d46134dac 100644 --- a/drivers/net/sun3lance.c +++ b/drivers/net/sun3lance.c @@ -300,6 +300,7 @@ static int __init lance_probe( struct net_device *dev) static int did_version; volatile unsigned short *ioaddr_probe; unsigned short tmp1, tmp2; + DECLARE_MAC_BUF(mac); #ifdef CONFIG_SUN3 ioaddr = (unsigned long)ioremap(LANCE_OBIO, PAGE_SIZE); @@ -375,8 +376,7 @@ static int __init lance_probe( struct net_device *dev) MEM->init.hwaddr[4] = dev->dev_addr[5]; MEM->init.hwaddr[5] = dev->dev_addr[4]; - for( i = 0; i < 6; ++i ) - printk( "%02x%s", dev->dev_addr[i], (i < 5) ? ":" : "\n" ); + printk("%s\n", print_mac(mac, dev->dev_addr)); MEM->init.mode = 0x0000; MEM->init.filter[0] = 0x00000000; @@ -590,17 +590,12 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) /* Fill in a Tx ring entry */ #if 0 if (lance_debug >= 2) { - u_char *p; - int i; - printk( "%s: TX pkt %d type 0x%04x from ", dev->name, - lp->new_tx, ((u_short *)skb->data)[6]); - for( p = &((u_char *)skb->data)[6], i = 0; i < 6; i++ ) - printk("%02x%s", *p++, i != 5 ? ":" : "" ); - printk(" to "); - for( p = (u_char *)skb->data, i = 0; i < 6; i++ ) - printk("%02x%s", *p++, i != 5 ? ":" : "" ); - printk(" data at 0x%08x len %d\n", (int)skb->data, - (int)skb->len ); + printk( "%s: TX pkt %d type 0x%04x" + " from %s to %s" + " data at 0x%08x len %d\n", + dev->name, lp->new_tx, ((u_short *)skb->data)[6], + DEV_ADDR(&skb->data[6]), DEV_ADDR(skb->data), + (int)skb->data, (int)skb->len ); } #endif /* We're not prepared for the int until the last flags are set/reset. @@ -825,13 +820,14 @@ static int lance_rx( struct net_device *dev ) #if 0 if (lance_debug >= 3) { - u_char *data = PKTBUF_ADDR(head), *p; - printk( "%s: RX pkt %d type 0x%04x from ", dev->name, entry, ((u_short *)data)[6]); - for( p = &data[6], i = 0; i < 6; i++ ) - printk("%02x%s", *p++, i != 5 ? ":" : "" ); - printk(" to "); - for( p = data, i = 0; i < 6; i++ ) - printk("%02x%s", *p++, i != 5 ? ":" : "" ); + u_char *data = PKTBUF_ADDR(head); + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2) + printk("%s: RX pkt %d type 0x%04x" + " from %s to %s", + dev->name, lp->new_tx, ((u_short *)data)[6], + print_mac(mac, &data[6]), print_mac(mac2, data)); + printk(" data %02x %02x %02x %02x %02x %02x %02x %02x " "len %d at %08x\n", data[15], data[16], data[17], data[18], diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c index 4ba3e4857e9..fe3ac6f9ae8 100644 --- a/drivers/net/sunbmac.c +++ b/drivers/net/sunbmac.c @@ -1082,6 +1082,7 @@ static int __init bigmac_ether_init(struct sbus_dev *qec_sdev) struct bigmac *bp; u8 bsizes, bsizes_more; int i; + DECLARE_MAC_BUF(mac); /* Get a new device struct for this interface. */ dev = alloc_etherdev(sizeof(struct bigmac)); @@ -1226,11 +1227,8 @@ static int __init bigmac_ether_init(struct sbus_dev *qec_sdev) dev_set_drvdata(&bp->bigmac_sdev->ofdev.dev, bp); - printk(KERN_INFO "%s: BigMAC 100baseT Ethernet ", dev->name); - for (i = 0; i < 6; i++) - printk("%2.2x%c", dev->dev_addr[i], - i == 5 ? ' ' : ':'); - printk("\n"); + printk(KERN_INFO "%s: BigMAC 100baseT Ethernet %s\n", + dev->name, print_mac(mac, dev->dev_addr)); return 0; diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index 3c553dcc2b9..a37637ec9b7 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -467,7 +467,7 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, int bar = 1; #endif int phy, phy_idx = 0; - + DECLARE_MAC_BUF(mac); /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -546,11 +546,9 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, if (i) goto err_out_unmap_rx; - printk(KERN_INFO "%s: %s at %p, ", - dev->name, pci_id_tbl[chip_idx].name, ioaddr); - for (i = 0; i < 5; i++) - printk("%2.2x:", dev->dev_addr[i]); - printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); + printk(KERN_INFO "%s: %s at %p, %s, IRQ %d.\n", + dev->name, pci_id_tbl[chip_idx].name, ioaddr, + print_mac(mac, dev->dev_addr), irq); np->phys[0] = 1; /* Default setting */ np->mii_preamble_required++; diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index 869ac44c51f..53b8344a68e 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -2965,7 +2965,8 @@ static int __devinit gem_init_one(struct pci_dev *pdev, unsigned long gemreg_base, gemreg_len; struct net_device *dev; struct gem *gp; - int i, err, pci_using_dac; + int err, pci_using_dac; + DECLARE_MAC_BUF(mac); if (gem_version_printed++ == 0) printk(KERN_INFO "%s", version); @@ -3149,12 +3150,9 @@ static int __devinit gem_init_one(struct pci_dev *pdev, goto err_out_free_consistent; } - printk(KERN_INFO "%s: Sun GEM (PCI) 10/100/1000BaseT Ethernet ", - dev->name); - for (i = 0; i < 6; i++) - printk("%2.2x%c", dev->dev_addr[i], - i == 5 ? ' ' : ':'); - printk("\n"); + printk(KERN_INFO "%s: Sun GEM (PCI) 10/100/1000BaseT Ethernet " + "%s\n", + dev->name, print_mac(mac, dev->dev_addr)); if (gp->phy_type == phy_mii_mdio0 || gp->phy_type == phy_mii_mdio1) diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index 170580c1312..120c8affe83 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -2664,6 +2664,7 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe struct net_device *dev; int i, qfe_slot = -1; int err = -ENODEV; + DECLARE_MAC_BUF(mac); if (is_qfe) { qp = quattro_sbus_find(sdev); @@ -2850,10 +2851,7 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe printk(KERN_INFO "%s: HAPPY MEAL (SBUS) 10/100baseT Ethernet ", dev->name); - for (i = 0; i < 6; i++) - printk("%2.2x%c", - dev->dev_addr[i], i == 5 ? ' ' : ':'); - printk("\n"); + printk("%s\n", print_mac(mac, dev->dev_addr)); return 0; @@ -2988,6 +2986,7 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev, int i, qfe_slot = -1; char prom_name[64]; int err; + DECLARE_MAC_BUF(mac); /* Now make sure pci_dev cookie is there. */ #ifdef CONFIG_SPARC @@ -3201,10 +3200,7 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev, printk(KERN_INFO "%s: HAPPY MEAL (PCI/CheerIO) 10/100BaseT Ethernet ", dev->name); - for (i = 0; i < 6; i++) - printk("%2.2x%c", dev->dev_addr[i], i == 5 ? ' ' : ':'); - - printk("\n"); + printk("%s\n", print_mac(mac, dev->dev_addr)); return 0; diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c index 7bf5c90b774..26ade68aeab 100644 --- a/drivers/net/sunlance.c +++ b/drivers/net/sunlance.c @@ -1321,6 +1321,7 @@ static int __devinit sparc_lance_probe_one(struct sbus_dev *sdev, struct net_device *dev; struct lance_private *lp; int i; + DECLARE_MAC_BUF(mac); dev = alloc_etherdev(sizeof(struct lance_private) + 8); if (!dev) @@ -1478,12 +1479,8 @@ no_link_test: dev_set_drvdata(&sdev->ofdev.dev, lp); - printk(KERN_INFO "%s: LANCE ", dev->name); - - for (i = 0; i < 6; i++) - printk("%2.2x%c", dev->dev_addr[i], - i == 5 ? ' ': ':'); - printk("\n"); + printk(KERN_INFO "%s: LANCE %s\n", + dev->name, print_mac(mac, dev->dev_addr)); return 0; diff --git a/drivers/net/tokenring/abyss.c b/drivers/net/tokenring/abyss.c index 22fad511240..124cfd4fbcf 100644 --- a/drivers/net/tokenring/abyss.c +++ b/drivers/net/tokenring/abyss.c @@ -97,8 +97,9 @@ static int __devinit abyss_attach(struct pci_dev *pdev, const struct pci_device_ static int versionprinted; struct net_device *dev; struct net_local *tp; - int i, ret, pci_irq_line; + int ret, pci_irq_line; unsigned long pci_ioaddr; + DECLARE_MAC_BUF(mac); if (versionprinted++ == 0) printk("%s", version); @@ -145,12 +146,9 @@ static int __devinit abyss_attach(struct pci_dev *pdev, const struct pci_device_ } abyss_read_eeprom(dev); - - printk("%s: Ring Station Address: ", dev->name); - printk("%2.2x", dev->dev_addr[0]); - for (i = 1; i < 6; i++) - printk(":%2.2x", dev->dev_addr[i]); - printk("\n"); + + printk("%s: Ring Station Address: %s\n", + dev->name, print_mac(mac, dev->dev_addr)); tp = netdev_priv(dev); tp->setnselout = abyss_setnselout_pins; diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c index 65e21eb7e68..e494c63bfbd 100644 --- a/drivers/net/tokenring/ibmtr.c +++ b/drivers/net/tokenring/ibmtr.c @@ -389,6 +389,7 @@ static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr) unsigned long timeout; static int version_printed; #endif + DECLARE_MAC_BUF(mac); /* Query the adapter PIO base port which will return * indication of where MMIO was placed. We also have a @@ -702,9 +703,8 @@ static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr) channel_def[cardpresent - 1], adapter_def(ti->adapter_type)); DPRINTK("using irq %d, PIOaddr %hx, %dK shared RAM.\n", irq, PIOaddr, ti->mapped_ram_size / 2); - DPRINTK("Hardware address : %02X:%02X:%02X:%02X:%02X:%02X\n", - dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + DPRINTK("Hardware address : %s\n", + print_mac(mac, dev->dev_addr)); if (ti->page_mask) DPRINTK("Shared RAM paging enabled. " "Page size: %uK Shared Ram size %dK\n", @@ -1739,18 +1739,20 @@ static void tr_rx(struct net_device *dev) if (!IPv4_p) { void __iomem *trhhdr = rbuf + offsetof(struct rec_buf, data); - + u8 saddr[6]; + u8 daddr[6]; + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); + int i; + for (i = 0 ; i < 6 ; i++) + saddr[i] = readb(trhhdr + SADDR_OFST + i); + for (i = 0 ; i < 6 ; i++) + daddr[i] = readb(trhhdr + DADDR_OFST + i); DPRINTK("Probably non-IP frame received.\n"); DPRINTK("ssap: %02X dsap: %02X " - "saddr: %02X:%02X:%02X:%02X:%02X:%02X " - "daddr: %02X:%02X:%02X:%02X:%02X:%02X\n", + "saddr: %s daddr: %$s\n", readb(llc + SSAP_OFST), readb(llc + DSAP_OFST), - readb(trhhdr+SADDR_OFST), readb(trhhdr+ SADDR_OFST+1), - readb(trhhdr+SADDR_OFST+2), readb(trhhdr+SADDR_OFST+3), - readb(trhhdr+SADDR_OFST+4), readb(trhhdr+SADDR_OFST+5), - readb(trhhdr+DADDR_OFST), readb(trhhdr+DADDR_OFST + 1), - readb(trhhdr+DADDR_OFST+2), readb(trhhdr+DADDR_OFST+3), - readb(trhhdr+DADDR_OFST+4), readb(trhhdr+DADDR_OFST+5)); + print_mac(mac, saddr), print_mac(mac2, daddr)); } #endif diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c index f114fb729f5..47d84cd2809 100644 --- a/drivers/net/tokenring/lanstreamer.c +++ b/drivers/net/tokenring/lanstreamer.c @@ -447,6 +447,9 @@ static int streamer_reset(struct net_device *dev) unsigned int uaa_addr; struct sk_buff *skb = NULL; __u16 misr; +#if STREAMER_DEBUG + DECLARE_MAC_BUF(mac); +#endif streamer_priv = netdev_priv(dev); streamer_mmio = streamer_priv->streamer_mmio; @@ -575,11 +578,8 @@ static int streamer_reset(struct net_device *dev) dev->dev_addr[i+1]= addr & 0xff; } #if STREAMER_DEBUG - printk("Adapter address: "); - for (i = 0; i < 6; i++) { - printk("%02x:", dev->dev_addr[i]); - } - printk("\n"); + printk("Adapter address: %s\n", + print_mac(mac, dev->dev_addr)); #endif } return 0; @@ -1539,6 +1539,7 @@ static void streamer_arb_cmd(struct net_device *dev) #if STREAMER_NETWORK_MONITOR struct trh_hdr *mac_hdr; + DECLARE_MAC_BUF(mac); #endif writew(streamer_priv->arb, streamer_mmio + LAPA); @@ -1611,15 +1612,11 @@ static void streamer_arb_cmd(struct net_device *dev) dev->name); mac_hdr = tr_hdr(mac_frame); printk(KERN_WARNING - "%s: MAC Frame Dest. Addr: %02x:%02x:%02x:%02x:%02x:%02x \n", - dev->name, mac_hdr->daddr[0], mac_hdr->daddr[1], - mac_hdr->daddr[2], mac_hdr->daddr[3], - mac_hdr->daddr[4], mac_hdr->daddr[5]); + "%s: MAC Frame Dest. Addr: %s\n", + dev->name, print_mac(mac, mac_hdr->daddr)); printk(KERN_WARNING - "%s: MAC Frame Srce. Addr: %02x:%02x:%02x:%02x:%02x:%02x \n", - dev->name, mac_hdr->saddr[0], mac_hdr->saddr[1], - mac_hdr->saddr[2], mac_hdr->saddr[3], - mac_hdr->saddr[4], mac_hdr->saddr[5]); + "%s: MAC Frame Srce. Addr: %s\n", + dev->name, DEV->ADDR6(mac_hdr->saddr)); #endif netif_rx(mac_frame); @@ -1854,6 +1851,8 @@ static int sprintf_info(char *buffer, struct net_device *dev) struct streamer_parameters_table spt; int size = 0; int i; + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); writew(streamer_priv->streamer_addr_table_addr, streamer_mmio + LAPA); for (i = 0; i < 14; i += 2) { @@ -1875,37 +1874,30 @@ static int sprintf_info(char *buffer, struct net_device *dev) size = sprintf(buffer, "\n%6s: Adapter Address : Node Address : Functional Addr\n", dev->name); size += sprintf(buffer + size, - "%6s: %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x\n", - dev->name, dev->dev_addr[0], dev->dev_addr[1], - dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], - dev->dev_addr[5], sat.node_addr[0], sat.node_addr[1], - sat.node_addr[2], sat.node_addr[3], sat.node_addr[4], - sat.node_addr[5], sat.func_addr[0], sat.func_addr[1], - sat.func_addr[2], sat.func_addr[3]); + "%6s: %s : %s : %02x:%02x:%02x:%02x\n", + dev->name, print_mac(mac, dev->dev_addr), + print_mac(mac2, sat.node_addr), + sat.func_addr[0], sat.func_addr[1], + sat.func_addr[2], sat.func_addr[3]); size += sprintf(buffer + size, "\n%6s: Token Ring Parameters Table:\n", dev->name); size += sprintf(buffer + size, "%6s: Physical Addr : Up Node Address : Poll Address : AccPri : Auth Src : Att Code :\n", dev->name); size += sprintf(buffer + size, - "%6s: %02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x:%02x:%02x : %04x : %04x : %04x :\n", + "%6s: %02x:%02x:%02x:%02x : %s : %s : %04x : %04x : %04x :\n", dev->name, spt.phys_addr[0], spt.phys_addr[1], spt.phys_addr[2], spt.phys_addr[3], - spt.up_node_addr[0], spt.up_node_addr[1], - spt.up_node_addr[2], spt.up_node_addr[3], - spt.up_node_addr[4], spt.up_node_addr[4], - spt.poll_addr[0], spt.poll_addr[1], spt.poll_addr[2], - spt.poll_addr[3], spt.poll_addr[4], spt.poll_addr[5], + print_mac(mac, spt.up_node_addr), + print_mac(mac2, spt.poll_addr), ntohs(spt.acc_priority), ntohs(spt.auth_source_class), ntohs(spt.att_code)); size += sprintf(buffer + size, "%6s: Source Address : Bcn T : Maj. V : Lan St : Lcl Rg : Mon Err : Frame Correl : \n", dev->name); size += sprintf(buffer + size, - "%6s: %02x:%02x:%02x:%02x:%02x:%02x : %04x : %04x : %04x : %04x : %04x : %04x : \n", - dev->name, spt.source_addr[0], spt.source_addr[1], - spt.source_addr[2], spt.source_addr[3], - spt.source_addr[4], spt.source_addr[5], + "%6s: %s : %04x : %04x : %04x : %04x : %04x : %04x : \n", + dev->name, print_mac(mac, spt.source_addr), ntohs(spt.beacon_type), ntohs(spt.major_vector), ntohs(spt.lan_status), ntohs(spt.local_ring), ntohs(spt.mon_error), ntohs(spt.frame_correl)); @@ -1914,14 +1906,12 @@ static int sprintf_info(char *buffer, struct net_device *dev) dev->name); size += sprintf(buffer + size, - "%6s: : %02x : %02x : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x : \n", + "%6s: : %02x : %02x : %s : %02x:%02x:%02x:%02x : \n", dev->name, ntohs(spt.beacon_transmit), - ntohs(spt.beacon_receive), spt.beacon_naun[0], - spt.beacon_naun[1], spt.beacon_naun[2], - spt.beacon_naun[3], spt.beacon_naun[4], - spt.beacon_naun[5], spt.beacon_phys[0], - spt.beacon_phys[1], spt.beacon_phys[2], - spt.beacon_phys[3]); + ntohs(spt.beacon_receive), + print_mac(mac, spt.beacon_naun), + spt.beacon_phys[0], spt.beacon_phys[1], + spt.beacon_phys[2], spt.beacon_phys[3]); return size; } #endif diff --git a/drivers/net/tokenring/madgemc.c b/drivers/net/tokenring/madgemc.c index d0ce2ce675d..5a4151362fc 100644 --- a/drivers/net/tokenring/madgemc.c +++ b/drivers/net/tokenring/madgemc.c @@ -151,7 +151,8 @@ static int __devinit madgemc_probe(struct device *device) struct net_local *tp; struct card_info *card; struct mca_device *mdev = to_mca_device(device); - int ret = 0, i = 0; + int ret = 0; + DECLARE_MAC_BUF(mac); if (versionprinted++ == 0) printk("%s", version); @@ -322,11 +323,8 @@ static int __devinit madgemc_probe(struct device *device) mca_device_set_name(mdev, (card->cardtype == 0x08)?MADGEMC16_CARDNAME:MADGEMC32_CARDNAME); mca_set_adapter_procfn(mdev->slot, madgemc_mcaproc, dev); - printk("%s: Ring Station Address: ", dev->name); - printk("%2.2x", dev->dev_addr[0]); - for (i = 1; i < 6; i++) - printk(":%2.2x", dev->dev_addr[i]); - printk("\n"); + printk("%s: Ring Station Address: %s\n", + dev->name, print_mac(mac, dev->dev_addr)); if (tmsdev_init(dev, device)) { printk("%s: unable to get memory for dev->priv.\n", @@ -692,11 +690,11 @@ static int madgemc_mcaproc(char *buf, int slot, void *d) struct net_local *tp = netdev_priv(dev); struct card_info *curcard = tp->tmspriv; int len = 0; + DECLARE_MAC_BUF(mac); len += sprintf(buf+len, "-------\n"); if (curcard) { struct net_local *tp = netdev_priv(dev); - int i; len += sprintf(buf+len, "Card Revision: %d\n", curcard->cardrev); len += sprintf(buf+len, "RAM Size: %dkb\n", curcard->ramsize); @@ -716,11 +714,8 @@ static int madgemc_mcaproc(char *buf, int slot, void *d) } len += sprintf(buf+len, " (%s)\n", (curcard->fairness)?"Unfair":"Fair"); - len += sprintf(buf+len, "Ring Station Address: "); - len += sprintf(buf+len, "%2.2x", dev->dev_addr[0]); - for (i = 1; i < 6; i++) - len += sprintf(buf+len, " %2.2x", dev->dev_addr[i]); - len += sprintf(buf+len, "\n"); + len += sprintf(buf+len, "Ring Station Address: %s\n", + print_mac(mac, dev->dev_addr)); } else len += sprintf(buf+len, "Card not configured\n"); diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c index a149d5e2965..74c1f0f189f 100644 --- a/drivers/net/tokenring/olympic.c +++ b/drivers/net/tokenring/olympic.c @@ -418,14 +418,15 @@ static int __devinit olympic_init(struct net_device *dev) writel(uaa_addr,olympic_mmio+LAPA); adapter_addr=olympic_priv->olympic_lap + (uaa_addr & (~0xf800)); + memcpy_fromio(&dev->dev_addr[0], adapter_addr,6); + #if OLYMPIC_DEBUG - printk("adapter address: %02x:%02x:%02x:%02x:%02x:%02x\n", - readb(adapter_addr), readb(adapter_addr+1),readb(adapter_addr+2), - readb(adapter_addr+3),readb(adapter_addr+4),readb(adapter_addr+5)); + { + DECLARE_MAC_BUF(mac); + printk("adapter address: %s\n", print_mac(mac, dev->dev_addr)); + } #endif - memcpy_fromio(&dev->dev_addr[0], adapter_addr,6); - olympic_priv->olympic_addr_table_addr = swab16(readw(init_srb + 12)); olympic_priv->olympic_parms_addr = swab16(readw(init_srb + 14)); @@ -440,6 +441,7 @@ static int olympic_open(struct net_device *dev) unsigned long flags, t; int i, open_finished = 1 ; u8 resp, err; + DECLARE_MAC_BUF(mac); DECLARE_WAITQUEUE(wait,current) ; @@ -567,14 +569,8 @@ static int olympic_open(struct net_device *dev) goto out; case 0x32: - printk(KERN_WARNING "%s: Invalid LAA: %02x:%02x:%02x:%02x:%02x:%02x\n", - dev->name, - olympic_priv->olympic_laa[0], - olympic_priv->olympic_laa[1], - olympic_priv->olympic_laa[2], - olympic_priv->olympic_laa[3], - olympic_priv->olympic_laa[4], - olympic_priv->olympic_laa[5]) ; + printk(KERN_WARNING "%s: Invalid LAA: %s\n", + dev->name, print_mac(mac, olympic_priv->olympic_laa)); goto out; default: @@ -704,30 +700,26 @@ static int olympic_open(struct net_device *dev) #endif if (olympic_priv->olympic_network_monitor) { - u8 __iomem *oat ; - u8 __iomem *opt ; - oat = (olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr) ; - opt = (olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr) ; - - printk("%s: Node Address: %02x:%02x:%02x:%02x:%02x:%02x\n",dev->name, - readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)), - readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+1), - readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+2), - readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+3), - readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+4), - readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+5)); + u8 __iomem *oat; + u8 __iomem *opt; + int i; + u8 addr[6]; + DECLARE_MAC_BUF(mac); + oat = (olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr); + opt = (olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr); + + for (i = 0; i < 6; i++) + addr[i] = readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+i); + printk("%s: Node Address: %s\n",dev->name, print_mac(mac, addr)); printk("%s: Functional Address: %02x:%02x:%02x:%02x\n",dev->name, readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)), readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+1), readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+2), readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+3)); - printk("%s: NAUN Address: %02x:%02x:%02x:%02x:%02x:%02x\n",dev->name, - readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)), - readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+1), - readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+2), - readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+3), - readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+4), - readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+5)); + + for (i = 0; i < 6; i++) + addr[i] = readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+i); + printk("%s: NAUN Address: %s\n",dev->name, print_mac(mac, addr)); } netif_start_queue(dev); @@ -1445,11 +1437,14 @@ static void olympic_arb_cmd(struct net_device *dev) mac_frame->protocol = tr_type_trans(mac_frame, dev); if (olympic_priv->olympic_network_monitor) { - struct trh_hdr *mac_hdr ; - printk(KERN_WARNING "%s: Received MAC Frame, details: \n",dev->name) ; + struct trh_hdr *mac_hdr; + DECLARE_MAC_BUF(mac); + printk(KERN_WARNING "%s: Received MAC Frame, details: \n",dev->name); mac_hdr = tr_hdr(mac_frame); - printk(KERN_WARNING "%s: MAC Frame Dest. Addr: %02x:%02x:%02x:%02x:%02x:%02x \n", dev->name , mac_hdr->daddr[0], mac_hdr->daddr[1], mac_hdr->daddr[2], mac_hdr->daddr[3], mac_hdr->daddr[4], mac_hdr->daddr[5]) ; - printk(KERN_WARNING "%s: MAC Frame Srce. Addr: %02x:%02x:%02x:%02x:%02x:%02x \n", dev->name , mac_hdr->saddr[0], mac_hdr->saddr[1], mac_hdr->saddr[2], mac_hdr->saddr[3], mac_hdr->saddr[4], mac_hdr->saddr[5]) ; + printk(KERN_WARNING "%s: MAC Frame Dest. Addr: %s\n", + dev->name, print_mac(mac, mac_hdr->daddr)); + printk(KERN_WARNING "%s: MAC Frame Srce. Addr: %s\n", + dev->name, print_mac(mac, mac_hdr->saddr)); } netif_rx(mac_frame); dev->last_rx = jiffies; @@ -1644,26 +1639,24 @@ static int olympic_proc_info(char *buffer, char **start, off_t offset, int lengt int len=0; off_t begin=0; off_t pos=0; - + u8 addr[6]; + u8 addr2[6]; + int i; + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); + size = sprintf(buffer, "IBM Pit/Pit-Phy/Olympic Chipset Token Ring Adapter %s\n",dev->name); size += sprintf(buffer+size, "\n%6s: Adapter Address : Node Address : Functional Addr\n", dev->name); - size += sprintf(buffer+size, "%6s: %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x\n", + for (i = 0 ; i < 6 ; i++) + addr[i] = readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr) + i); + + size += sprintf(buffer+size, "%6s: %s : %s : %02x:%02x:%02x:%02x\n", dev->name, - dev->dev_addr[0], - dev->dev_addr[1], - dev->dev_addr[2], - dev->dev_addr[3], - dev->dev_addr[4], - dev->dev_addr[5], - readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)), - readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+1), - readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+2), - readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+3), - readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+4), - readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+5), + print_mac(mac, dev->dev_addr), + print_mac(mac2, addr), readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)), readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+1), readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+2), @@ -1673,25 +1666,20 @@ static int olympic_proc_info(char *buffer, char **start, off_t offset, int lengt size += sprintf(buffer+size, "%6s: Physical Addr : Up Node Address : Poll Address : AccPri : Auth Src : Att Code :\n", dev->name) ; - - size += sprintf(buffer+size, "%6s: %02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x:%02x:%02x : %04x : %04x : %04x :\n", + + for (i = 0 ; i < 6 ; i++) + addr[i] = readb(opt+offsetof(struct olympic_parameters_table, up_node_addr) + i); + for (i = 0 ; i < 6 ; i++) + addr2[i] = readb(opt+offsetof(struct olympic_parameters_table, poll_addr) + i); + + size += sprintf(buffer+size, "%6s: %02x:%02x:%02x:%02x : %s : %s : %04x : %04x : %04x :\n", dev->name, readb(opt+offsetof(struct olympic_parameters_table, phys_addr)), readb(opt+offsetof(struct olympic_parameters_table, phys_addr)+1), readb(opt+offsetof(struct olympic_parameters_table, phys_addr)+2), readb(opt+offsetof(struct olympic_parameters_table, phys_addr)+3), - readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)), - readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+1), - readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+2), - readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+3), - readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+4), - readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+5), - readb(opt+offsetof(struct olympic_parameters_table, poll_addr)), - readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+1), - readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+2), - readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+3), - readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+4), - readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+5), + print_mac(mac, addr), + print_mac(mac2, addr2), swab16(readw(opt+offsetof(struct olympic_parameters_table, acc_priority))), swab16(readw(opt+offsetof(struct olympic_parameters_table, auth_source_class))), swab16(readw(opt+offsetof(struct olympic_parameters_table, att_code)))); @@ -1699,14 +1687,11 @@ static int olympic_proc_info(char *buffer, char **start, off_t offset, int lengt size += sprintf(buffer+size, "%6s: Source Address : Bcn T : Maj. V : Lan St : Lcl Rg : Mon Err : Frame Correl : \n", dev->name) ; - size += sprintf(buffer+size, "%6s: %02x:%02x:%02x:%02x:%02x:%02x : %04x : %04x : %04x : %04x : %04x : %04x : \n", + for (i = 0 ; i < 6 ; i++) + addr[i] = readb(opt+offsetof(struct olympic_parameters_table, source_addr) + i); + size += sprintf(buffer+size, "%6s: %s : %04x : %04x : %04x : %04x : %04x : %04x : \n", dev->name, - readb(opt+offsetof(struct olympic_parameters_table, source_addr)), - readb(opt+offsetof(struct olympic_parameters_table, source_addr)+1), - readb(opt+offsetof(struct olympic_parameters_table, source_addr)+2), - readb(opt+offsetof(struct olympic_parameters_table, source_addr)+3), - readb(opt+offsetof(struct olympic_parameters_table, source_addr)+4), - readb(opt+offsetof(struct olympic_parameters_table, source_addr)+5), + print_mac(mac, addr), swab16(readw(opt+offsetof(struct olympic_parameters_table, beacon_type))), swab16(readw(opt+offsetof(struct olympic_parameters_table, major_vector))), swab16(readw(opt+offsetof(struct olympic_parameters_table, lan_status))), @@ -1717,16 +1702,13 @@ static int olympic_proc_info(char *buffer, char **start, off_t offset, int lengt size += sprintf(buffer+size, "%6s: Beacon Details : Tx : Rx : NAUN Node Address : NAUN Node Phys : \n", dev->name) ; - size += sprintf(buffer+size, "%6s: : %02x : %02x : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x : \n", + for (i = 0 ; i < 6 ; i++) + addr[i] = readb(opt+offsetof(struct olympic_parameters_table, beacon_naun) + i); + size += sprintf(buffer+size, "%6s: : %02x : %02x : %s : %02x:%02x:%02x:%02x : \n", dev->name, swab16(readw(opt+offsetof(struct olympic_parameters_table, beacon_transmit))), swab16(readw(opt+offsetof(struct olympic_parameters_table, beacon_receive))), - readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)), - readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+1), - readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+2), - readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+3), - readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+4), - readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+5), + print_mac(mac, addr), readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)), readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)+1), readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)+2), diff --git a/drivers/net/tokenring/proteon.c b/drivers/net/tokenring/proteon.c index 85d156dea03..ca6b65919b3 100644 --- a/drivers/net/tokenring/proteon.c +++ b/drivers/net/tokenring/proteon.c @@ -122,6 +122,7 @@ static int __init setup_card(struct net_device *dev, struct device *pdev) static int versionprinted; const unsigned *port; int j,err = 0; + DECLARE_MAC_BUF(mac); if (!dev) return -ENOMEM; @@ -152,11 +153,8 @@ static int __init setup_card(struct net_device *dev, struct device *pdev) proteon_read_eeprom(dev); - printk(KERN_DEBUG "proteon.c: Ring Station Address: "); - printk("%2.2x", dev->dev_addr[0]); - for (j = 1; j < 6; j++) - printk(":%2.2x", dev->dev_addr[j]); - printk("\n"); + printk(KERN_DEBUG "proteon.c: Ring Station Address: %s\n", + print_mac(mac, dev->dev_addr)); tp = netdev_priv(dev); tp->setnselout = proteon_setnselout_pins; diff --git a/drivers/net/tokenring/skisa.c b/drivers/net/tokenring/skisa.c index ecbddc80a2a..32e8d5a9f95 100644 --- a/drivers/net/tokenring/skisa.c +++ b/drivers/net/tokenring/skisa.c @@ -139,6 +139,7 @@ static int __init setup_card(struct net_device *dev, struct device *pdev) static int versionprinted; const unsigned *port; int j, err = 0; + DECLARE_MAC_BUF(mac); if (!dev) return -ENOMEM; @@ -169,11 +170,8 @@ static int __init setup_card(struct net_device *dev, struct device *pdev) sk_isa_read_eeprom(dev); - printk(KERN_DEBUG "skisa.c: Ring Station Address: "); - printk("%2.2x", dev->dev_addr[0]); - for (j = 1; j < 6; j++) - printk(":%2.2x", dev->dev_addr[j]); - printk("\n"); + printk(KERN_DEBUG "skisa.c: Ring Station Address: %s\n", + print_mac(mac, dev->dev_addr)); tp = netdev_priv(dev); tp->setnselout = sk_isa_setnselout_pins; diff --git a/drivers/net/tokenring/tmspci.c b/drivers/net/tokenring/tmspci.c index ecdd8511a67..1c18f782f52 100644 --- a/drivers/net/tokenring/tmspci.c +++ b/drivers/net/tokenring/tmspci.c @@ -96,10 +96,11 @@ static int __devinit tms_pci_attach(struct pci_dev *pdev, const struct pci_devic static int versionprinted; struct net_device *dev; struct net_local *tp; - int i, ret; + int ret; unsigned int pci_irq_line; unsigned long pci_ioaddr; struct card_info *cardinfo = &card_info_table[ent->driver_data]; + DECLARE_MAC_BUF(mac); if (versionprinted++ == 0) printk("%s", version); @@ -136,11 +137,8 @@ static int __devinit tms_pci_attach(struct pci_dev *pdev, const struct pci_devic tms_pci_read_eeprom(dev); - printk("%s: Ring Station Address: ", dev->name); - printk("%2.2x", dev->dev_addr[0]); - for (i = 1; i < 6; i++) - printk(":%2.2x", dev->dev_addr[i]); - printk("\n"); + printk("%s: Ring Station Address: %s\n", + dev->name, print_mac(mac, dev->dev_addr)); ret = tmsdev_init(dev, &pdev->dev); if (ret) { diff --git a/drivers/net/tsi108_eth.c b/drivers/net/tsi108_eth.c index fe3225df0d3..df10af7df7b 100644 --- a/drivers/net/tsi108_eth.c +++ b/drivers/net/tsi108_eth.c @@ -1540,6 +1540,7 @@ tsi108_init_one(struct platform_device *pdev) struct tsi108_prv_data *data = NULL; hw_info *einfo; int err = 0; + DECLARE_MAC_BUF(mac); einfo = pdev->dev.platform_data; @@ -1628,10 +1629,8 @@ tsi108_init_one(struct platform_device *pdev) goto register_fail; } - printk(KERN_INFO "%s: Tsi108 Gigabit Ethernet, MAC: " - "%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, - dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + printk(KERN_INFO "%s: Tsi108 Gigabit Ethernet, MAC: %s\n" + dev->name, print_mac(mac, dev->dev_addr)); #ifdef DEBUG data->msg_enable = DEBUG; dump_eth_one(dev); diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index ba3d0e5574a..f12e33a1736 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -1929,6 +1929,7 @@ static int __devinit de_init_one (struct pci_dev *pdev, void __iomem *regs; unsigned long pciaddr; static int board_idx = -1; + DECLARE_MAC_BUF(mac); board_idx++; @@ -2042,15 +2043,11 @@ static int __devinit de_init_one (struct pci_dev *pdev, goto err_out_iomap; /* print info about board and interface just registered */ - printk (KERN_INFO "%s: %s at 0x%lx, " - "%02x:%02x:%02x:%02x:%02x:%02x, " - "IRQ %d\n", + printk (KERN_INFO "%s: %s at 0x%lx, %s, IRQ %d\n", dev->name, de->de21040 ? "21040" : "21041", dev->base_addr, - dev->dev_addr[0], dev->dev_addr[1], - dev->dev_addr[2], dev->dev_addr[3], - dev->dev_addr[4], dev->dev_addr[5], + print_mac(mac, dev->dev_addr), dev->irq); pci_set_drvdata(pdev, dev); diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c index ee4215ca63f..4633cc6dd41 100644 --- a/drivers/net/tulip/de4x5.c +++ b/drivers/net/tulip/de4x5.c @@ -1088,6 +1088,7 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev) struct de4x5_private *lp = netdev_priv(dev); struct pci_dev *pdev = NULL; int i, status=0; + DECLARE_MAC_BUF(mac); gendev->driver_data = dev; @@ -1123,12 +1124,8 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev) dev->base_addr = iobase; printk ("%s: %s at 0x%04lx", gendev->bus_id, name, iobase); - printk(", h/w address "); status = get_hw_addr(dev); - for (i = 0; i < ETH_ALEN - 1; i++) { /* get the ethernet addr. */ - printk("%2.2x:", dev->dev_addr[i]); - } - printk("%2.2x,\n", dev->dev_addr[i]); + printk(", h/w address %s\n", print_mac(mac, dev->dev_addr)); if (status != 0) { printk(" which has an Ethernet PROM CRC error.\n"); @@ -5468,19 +5465,16 @@ static void de4x5_dbg_srom(struct de4x5_srom *p) { int i; + DECLARE_MAC_BUF(mac); if (de4x5_debug & DEBUG_SROM) { printk("Sub-system Vendor ID: %04x\n", *((u_short *)p->sub_vendor_id)); printk("Sub-system ID: %04x\n", *((u_short *)p->sub_system_id)); printk("ID Block CRC: %02x\n", (u_char)(p->id_block_crc)); printk("SROM version: %02x\n", (u_char)(p->version)); - printk("# controllers: %02x\n", (u_char)(p->num_controllers)); + printk("# controllers: %02x\n", (u_char)(p->num_controllers)); - printk("Hardware Address: "); - for (i=0;iieee_addr+i)); - } - printk("%02x\n", (u_char)*(p->ieee_addr+i)); + printk("Hardware Address: %s\n", print_mac(mac, p->ieee_addr)); printk("CRC checksum: %04x\n", (u_short)(p->chksum)); for (i=0; i<64; i++) { printk("%3d %04x\n", i<<1, (u_short)*((u_short *)p+i)); @@ -5494,21 +5488,12 @@ static void de4x5_dbg_rx(struct sk_buff *skb, int len) { int i, j; + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); if (de4x5_debug & DEBUG_RX) { - printk("R: %02x:%02x:%02x:%02x:%02x:%02x <- %02x:%02x:%02x:%02x:%02x:%02x len/SAP:%02x%02x [%d]\n", - (u_char)skb->data[0], - (u_char)skb->data[1], - (u_char)skb->data[2], - (u_char)skb->data[3], - (u_char)skb->data[4], - (u_char)skb->data[5], - (u_char)skb->data[6], - (u_char)skb->data[7], - (u_char)skb->data[8], - (u_char)skb->data[9], - (u_char)skb->data[10], - (u_char)skb->data[11], + printk("R: %s <- %s len/SAP:%02x%02x [%d]\n", + print_mac(mac, skb->data), print_mac(mac2, &skb->data[6]), (u_char)skb->data[12], (u_char)skb->data[13], len); diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c index e2596e9ab1d..ca90566d5bc 100644 --- a/drivers/net/tulip/dmfe.c +++ b/drivers/net/tulip/dmfe.c @@ -362,6 +362,7 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev, struct net_device *dev; u32 pci_pmr; int i, err; + DECLARE_MAC_BUF(mac); DMFE_DBUG(0, "dmfe_init_one()", 0); @@ -470,13 +471,13 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev, if (err) goto err_out_res; - printk(KERN_INFO "%s: Davicom DM%04lx at pci%s,", - dev->name, - ent->driver_data >> 16, - pci_name(pdev)); - for (i = 0; i < 6; i++) - printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]); - printk(", irq %d.\n", dev->irq); + printk(KERN_INFO "%s: Davicom DM%04lx at pci%s, " + "%s, irq %d.\n", + dev->name, + ent->driver_data >> 16, + pci_name(pdev), + print_mac(mac, dev->dev_addr), + dev->irq); pci_set_master(pdev); diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index 66977aaa717..80fee229253 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -1051,12 +1051,11 @@ static void set_rx_mode(struct net_device *dev) filterbit &= 0x3f; mc_filter[filterbit >> 5] |= 1 << (filterbit & 31); if (tulip_debug > 2) { - printk(KERN_INFO "%s: Added filter for %2.2x:%2.2x:%2.2x:" - "%2.2x:%2.2x:%2.2x %8.8x bit %d.\n", dev->name, - mclist->dmi_addr[0], mclist->dmi_addr[1], - mclist->dmi_addr[2], mclist->dmi_addr[3], - mclist->dmi_addr[4], mclist->dmi_addr[5], - ether_crc(ETH_ALEN, mclist->dmi_addr), filterbit); + DECLARE_MAC_BUF(mac); + printk(KERN_INFO "%s: Added filter for %s" + " %8.8x bit %d.\n", + dev->name, print_mac(mac, mclist->dmi_addr), + ether_crc(ETH_ALEN, mclist->dmi_addr), filterbit); } } if (mc_filter[0] == tp->mc_filter[0] && @@ -1256,6 +1255,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, const char *chip_name = tulip_tbl[chip_idx].chip_name; unsigned int eeprom_missing = 0; unsigned int force_csr0 = 0; + DECLARE_MAC_BUF(mac); #ifndef MODULE static int did_version; /* Already printed version info. */ @@ -1639,8 +1639,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, if (eeprom_missing) printk(" EEPROM not present,"); - for (i = 0; i < 6; i++) - printk("%c%2.2X", i ? ':' : ' ', dev->dev_addr[i]); + printk(" %s", print_mac(mac, dev->dev_addr)); printk(", IRQ %d.\n", irq); if (tp->chip_id == PNIC2) diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c index 2b7257d97c3..a4fd782bcd2 100644 --- a/drivers/net/tulip/uli526x.c +++ b/drivers/net/tulip/uli526x.c @@ -258,6 +258,7 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev, struct uli526x_board_info *db; /* board information structure */ struct net_device *dev; int i, err; + DECLARE_MAC_BUF(mac); ULI526X_DBUG(0, "uli526x_init_one()", 0); @@ -372,11 +373,9 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev, if (err) goto err_out_res; - printk(KERN_INFO "%s: ULi M%04lx at pci%s,",dev->name,ent->driver_data >> 16,pci_name(pdev)); - - for (i = 0; i < 6; i++) - printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]); - printk(", irq %d.\n", dev->irq); + printk(KERN_INFO "%s: ULi M%04lx at pci%s, %s, irq %d.\n", + dev->name,ent->driver_data >> 16,pci_name(pdev), + print_mac(mac, dev->dev_addr), dev->irq); pci_set_master(pdev); diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c index e00833fadc0..3c40dd6e1a2 100644 --- a/drivers/net/tulip/winbond-840.c +++ b/drivers/net/tulip/winbond-840.c @@ -354,6 +354,7 @@ static int __devinit w840_probe1 (struct pci_dev *pdev, int irq; int i, option = find_cnt < MAX_UNITS ? options[find_cnt] : 0; void __iomem *ioaddr; + DECLARE_MAC_BUF(mac); i = pci_enable_device(pdev); if (i) return i; @@ -433,11 +434,9 @@ static int __devinit w840_probe1 (struct pci_dev *pdev, if (i) goto err_out_cleardev; - printk(KERN_INFO "%s: %s at %p, ", - dev->name, pci_id_tbl[chip_idx].name, ioaddr); - for (i = 0; i < 5; i++) - printk("%2.2x:", dev->dev_addr[i]); - printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); + printk(KERN_INFO "%s: %s at %p, %s, IRQ %d.\n", + dev->name, pci_id_tbl[chip_idx].name, ioaddr, + print_mac(mac, dev->dev_addr), irq); if (np->drv_flags & CanHaveMII) { int phy, phy_idx = 0; @@ -1245,16 +1244,16 @@ static int netdev_rx(struct net_device *dev) } #ifndef final_version /* Remove after testing. */ /* You will want this info for the initial debug. */ - if (debug > 5) - printk(KERN_DEBUG " Rx data %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:" - "%2.2x %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x %2.2x%2.2x " - "%d.%d.%d.%d.\n", - skb->data[0], skb->data[1], skb->data[2], skb->data[3], - skb->data[4], skb->data[5], skb->data[6], skb->data[7], - skb->data[8], skb->data[9], skb->data[10], - skb->data[11], skb->data[12], skb->data[13], - skb->data[14], skb->data[15], skb->data[16], - skb->data[17]); + if (debug > 5) { + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); + + printk(KERN_DEBUG " Rx data %s %s" + " %2.2x%2.2x %d.%d.%d.%d.\n", + print_mac(mac, &skb->data[0]), print_mac(mac2, &skb->data[6]), + skb->data[12], skb->data[13], + skb->data[14], skb->data[15], skb->data[16], skb->data[17]); + } #endif skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c index de8c92083e9..70befe33e45 100644 --- a/drivers/net/tulip/xircom_cb.c +++ b/drivers/net/tulip/xircom_cb.c @@ -1074,6 +1074,7 @@ static void read_mac_address(struct xircom_private *card) unsigned char j, tuple, link, data_id, data_count; unsigned long flags; int i; + DECLARE_MAC_BUF(mac); enter("read_mac_address"); @@ -1103,11 +1104,7 @@ static void read_mac_address(struct xircom_private *card) } } spin_unlock_irqrestore(&card->lock, flags); -#ifdef DEBUG - for (i = 0; i < 6; i++) - printk("%c%2.2X", i ? ':' : ' ', card->dev->dev_addr[i]); - printk("\n"); -#endif + pr_debug(" %s\n", print_mac(mac, card->dev->dev_addr)); leave("read_mac_address"); } diff --git a/drivers/net/tun.c b/drivers/net/tun.c index d8b8e68ef70..1f764469597 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -159,16 +159,15 @@ tun_net_mclist(struct net_device *dev) struct tun_struct *tun = netdev_priv(dev); const struct dev_mc_list *mclist; int i; + DECLARE_MAC_BUF(mac); DBG(KERN_DEBUG "%s: tun_net_mclist: mc_count %d\n", dev->name, dev->mc_count); memset(tun->chr_filter, 0, sizeof tun->chr_filter); for (i = 0, mclist = dev->mc_list; i < dev->mc_count && mclist != NULL; i++, mclist = mclist->next) { add_multi(tun->net_filter, mclist->dmi_addr); - DBG(KERN_DEBUG "%s: tun_net_mclist: %x:%x:%x:%x:%x:%x\n", - dev->name, - mclist->dmi_addr[0], mclist->dmi_addr[1], mclist->dmi_addr[2], - mclist->dmi_addr[3], mclist->dmi_addr[4], mclist->dmi_addr[5]); + DBG(KERN_DEBUG "%s: tun_net_mclist: %s\n", + dev->name, print_mac(mac, mclist->dmi_addr)); } } @@ -358,6 +357,7 @@ static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv, DECLARE_WAITQUEUE(wait, current); struct sk_buff *skb; ssize_t len, ret = 0; + DECLARE_MAC_BUF(mac); if (!tun) return -EBADFD; @@ -412,16 +412,14 @@ static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv, (addr[0] == 0x33 && addr[1] == 0x33)) && ((tun->if_flags & IFF_ALLMULTI) || (tun->chr_filter[bit_nr >> 5] & (1 << (bit_nr & 31)))))) { - DBG(KERN_DEBUG "%s: tun_chr_readv: accepted: %x:%x:%x:%x:%x:%x\n", - tun->dev->name, addr[0], addr[1], addr[2], - addr[3], addr[4], addr[5]); + DBG(KERN_DEBUG "%s: tun_chr_readv: accepted: %s\n", + tun->dev->name, print_mac(mac, addr)); ret = tun_put_user(tun, skb, (struct iovec *) iv, len); kfree_skb(skb); break; } else { - DBG(KERN_DEBUG "%s: tun_chr_readv: rejected: %x:%x:%x:%x:%x:%x\n", - tun->dev->name, addr[0], addr[1], addr[2], - addr[3], addr[4], addr[5]); + DBG(KERN_DEBUG "%s: tun_chr_readv: rejected: %s\n", + tun->dev->name, print_mac(mac, addr)); kfree_skb(skb); continue; } @@ -564,6 +562,7 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file, struct tun_struct *tun = file->private_data; void __user* argp = (void __user*)arg; struct ifreq ifr; + DECLARE_MAC_BUF(mac); if (cmd == TUNSETIFF || _IOC_TYPE(cmd) == 0x89) if (copy_from_user(&ifr, argp, sizeof ifr)) @@ -692,22 +691,16 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file, /** Add the specified group to the character device's multicast filter * list. */ add_multi(tun->chr_filter, ifr.ifr_hwaddr.sa_data); - DBG(KERN_DEBUG "%s: add multi: %x:%x:%x:%x:%x:%x\n", - tun->dev->name, - (u8)ifr.ifr_hwaddr.sa_data[0], (u8)ifr.ifr_hwaddr.sa_data[1], - (u8)ifr.ifr_hwaddr.sa_data[2], (u8)ifr.ifr_hwaddr.sa_data[3], - (u8)ifr.ifr_hwaddr.sa_data[4], (u8)ifr.ifr_hwaddr.sa_data[5]); + DBG(KERN_DEBUG "%s: add multi: %s\n", + tun->dev->name, print_mac(mac, ifr.ifr_hwaddr.sa_data)); return 0; case SIOCDELMULTI: /** Remove the specified group from the character device's multicast * filter list. */ del_multi(tun->chr_filter, ifr.ifr_hwaddr.sa_data); - DBG(KERN_DEBUG "%s: del multi: %x:%x:%x:%x:%x:%x\n", - tun->dev->name, - (u8)ifr.ifr_hwaddr.sa_data[0], (u8)ifr.ifr_hwaddr.sa_data[1], - (u8)ifr.ifr_hwaddr.sa_data[2], (u8)ifr.ifr_hwaddr.sa_data[3], - (u8)ifr.ifr_hwaddr.sa_data[4], (u8)ifr.ifr_hwaddr.sa_data[5]); + DBG(KERN_DEBUG "%s: del multi: %s\n", + tun->dev->name, print_mac(mac, ifr.ifr_hwaddr.sa_data)); return 0; default: diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index c6d8513ecad..43894e95fcb 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -2316,8 +2316,8 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dma_addr_t shared_dma; struct cmd_desc xp_cmd; struct resp_desc xp_resp[3]; - int i; int err = 0; + DECLARE_MAC_BUF(mac); if(!did_version++) printk(KERN_INFO "%s", version); @@ -2532,13 +2532,11 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_drvdata(pdev, dev); - printk(KERN_INFO "%s: %s at %s 0x%llx, ", + printk(KERN_INFO "%s: %s at %s 0x%llx, %s\n", dev->name, typhoon_card_info[card_id].name, use_mmio ? "MMIO" : "IO", - (unsigned long long)pci_resource_start(pdev, use_mmio)); - for(i = 0; i < 5; i++) - printk("%2.2x:", dev->dev_addr[i]); - printk("%2.2x\n", dev->dev_addr[i]); + (unsigned long long)pci_resource_start(pdev, use_mmio), + print_mac(mac, dev->dev_addr)); /* xp_resp still contains the response to the READ_VERSIONS command. * For debugging, let the user know what version he has. diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c index 432a2f05446..d1ed68a11e7 100644 --- a/drivers/net/usb/pegasus.c +++ b/drivers/net/usb/pegasus.c @@ -1297,6 +1297,7 @@ static int pegasus_probe(struct usb_interface *intf, pegasus_t *pegasus; int dev_index = id - pegasus_ids; int res = -ENOMEM; + DECLARE_MAC_BUF(mac); usb_get_dev(dev); net = alloc_etherdev(sizeof(struct pegasus)); @@ -1367,12 +1368,10 @@ static int pegasus_probe(struct usb_interface *intf, queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check, CARRIER_CHECK_DELAY); - dev_info(&intf->dev, "%s, %s, %02x:%02x:%02x:%02x:%02x:%02x\n", - net->name, - usb_dev_id[dev_index].name, - net->dev_addr [0], net->dev_addr [1], - net->dev_addr [2], net->dev_addr [3], - net->dev_addr [4], net->dev_addr [5]); + dev_info(&intf->dev, "%s, %s, %s\n", + net->name, + usb_dev_id[dev_index].name, + print_mac(mac, net->dev_addr)); return 0; out3: diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 3542ca5fb0f..acd5f1c0e63 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -1134,6 +1134,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) struct usb_device *xdev; int status; const char *name; + DECLARE_MAC_BUF(mac); name = udev->dev.driver->name; info = (struct driver_info *) prod->driver_info; @@ -1241,14 +1242,11 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) if (status) goto out3; if (netif_msg_probe (dev)) - devinfo (dev, "register '%s' at usb-%s-%s, %s, " - "%02x:%02x:%02x:%02x:%02x:%02x", + devinfo (dev, "register '%s' at usb-%s-%s, %s, %s", udev->dev.driver->name, xdev->bus->bus_name, xdev->devpath, dev->driver_info->description, - net->dev_addr [0], net->dev_addr [1], - net->dev_addr [2], net->dev_addr [3], - net->dev_addr [4], net->dev_addr [5]); + print_mac(mac, net->dev_addr)); // ok, it's ready to go. usb_set_intfdata (udev, dev); diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index d55c4fdff48..9669bce0fd0 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -638,6 +638,7 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, #else int bar = 0; #endif + DECLARE_MAC_BUF(mac); /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -794,18 +795,14 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, if (rc) goto err_out_unmap; - printk(KERN_INFO "%s: VIA %s at 0x%lx, ", + printk(KERN_INFO "%s: VIA %s at 0x%lx, %s, IRQ %d.\n", dev->name, name, #ifdef USE_MMIO - memaddr + memaddr, #else - (long)ioaddr + (long)ioaddr, #endif - ); - - for (i = 0; i < 5; i++) - printk("%2.2x:", dev->dev_addr[i]); - printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], pdev->irq); + print_mac(mac, dev->dev_addr), pdev->irq); pci_set_drvdata(pdev, dev); diff --git a/drivers/net/wd.c b/drivers/net/wd.c index cef365881ac..fa14255282a 100644 --- a/drivers/net/wd.c +++ b/drivers/net/wd.c @@ -156,6 +156,7 @@ static int __init wd_probe1(struct net_device *dev, int ioaddr) int word16 = 0; /* 0 = 8 bit, 1 = 16 bit */ const char *model_name; static unsigned version_printed; + DECLARE_MAC_BUF(mac); for (i = 0; i < 8; i++) checksum += inb(ioaddr + 8 + i); @@ -174,9 +175,11 @@ static int __init wd_probe1(struct net_device *dev, int ioaddr) if (ei_debug && version_printed++ == 0) printk(version); - printk("%s: WD80x3 at %#3x,", dev->name, ioaddr); for (i = 0; i < 6; i++) - printk(" %2.2X", dev->dev_addr[i] = inb(ioaddr + 8 + i)); + dev->dev_addr[i] = inb(ioaddr + 8 + i); + + printk("%s: WD80x3 at %#3x, %s", + dev->name, ioaddr, print_mac(mac, dev->dev_addr)); /* The following PureData probe code was contributed by Mike Jagdis . Puredata does software diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index eec01fc1528..ac2ea237019 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -1787,6 +1787,7 @@ static int __devinit adm8211_probe(struct pci_dev *pdev, int err; u32 reg; u8 perm_addr[ETH_ALEN]; + DECLARE_MAC_BUF(mac); #ifndef MODULE static unsigned int cardidx; @@ -1938,8 +1939,8 @@ static int __devinit adm8211_probe(struct pci_dev *pdev, goto err_free_desc; } - printk(KERN_INFO "%s: hwaddr " MAC_FMT ", Rev 0x%02x\n", - wiphy_name(dev->wiphy), MAC_ARG(dev->wiphy->perm_addr), + printk(KERN_INFO "%s: hwaddr %s, Rev 0x%02x\n", + wiphy_name(dev->wiphy), print_mac(mac, dev->wiphy->perm_addr), priv->revid); return 0; diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 7d717c4d984..95d3cd1c49a 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -2821,6 +2821,7 @@ static struct net_device *_init_airo_card( unsigned short irq, int port, struct net_device *dev; struct airo_info *ai; int i, rc; + DECLARE_MAC_BUF(mac); /* Create the network device object. */ dev = alloc_netdev(sizeof(*ai), "", ether_setup); @@ -2923,9 +2924,8 @@ static struct net_device *_init_airo_card( unsigned short irq, int port, goto err_out_reg; set_bit(FLAG_REGISTERED,&ai->flags); - airo_print_info(dev->name, "MAC enabled %x:%x:%x:%x:%x:%x", - dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5] ); + airo_print_info(dev->name, "MAC enabled %s", + print_mac(mac, dev->dev_addr)); /* Allocate the transmit buffers */ if (probe && !test_bit(FLAG_MPI,&ai->flags)) @@ -2982,6 +2982,7 @@ int reset_airo_card( struct net_device *dev ) { int i; struct airo_info *ai = dev->priv; + DECLARE_MAC_BUF(mac); if (reset_card (dev, 1)) return -1; @@ -2990,9 +2991,8 @@ int reset_airo_card( struct net_device *dev ) airo_print_err(dev->name, "MAC could not be enabled"); return -1; } - airo_print_info(dev->name, "MAC enabled %x:%x:%x:%x:%x:%x", - dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + airo_print_info(dev->name, "MAC enabled %s", + print_mac(mac, dev->dev_addr)); /* Allocate the transmit buffers if needed */ if (!test_bit(FLAG_MPI,&ai->flags)) for( i = 0; i < MAX_FIDS; i++ ) @@ -5426,6 +5426,7 @@ static int proc_APList_open( struct inode *inode, struct file *file ) { int i; char *ptr; APListRid APList_rid; + DECLARE_MAC_BUF(mac); if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL) return -ENOMEM; @@ -5449,13 +5450,8 @@ static int proc_APList_open( struct inode *inode, struct file *file ) { // We end when we find a zero MAC if ( !*(int*)APList_rid.ap[i] && !*(int*)&APList_rid.ap[i][2]) break; - ptr += sprintf(ptr, "%02x:%02x:%02x:%02x:%02x:%02x\n", - (int)APList_rid.ap[i][0], - (int)APList_rid.ap[i][1], - (int)APList_rid.ap[i][2], - (int)APList_rid.ap[i][3], - (int)APList_rid.ap[i][4], - (int)APList_rid.ap[i][5]); + ptr += sprintf(ptr, "%s\n", + print_mac(mac, APList_rid.ap[i])); } if (i==0) ptr += sprintf(ptr, "Not using specific APs\n"); @@ -5474,6 +5470,7 @@ static int proc_BSSList_open( struct inode *inode, struct file *file ) { int rc; /* If doLoseSync is not 1, we won't do a Lose Sync */ int doLoseSync = -1; + DECLARE_MAC_BUF(mac); if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL) return -ENOMEM; @@ -5510,13 +5507,8 @@ static int proc_BSSList_open( struct inode *inode, struct file *file ) { we have to add a spin lock... */ rc = readBSSListRid(ai, doLoseSync, &BSSList_rid); while(rc == 0 && BSSList_rid.index != 0xffff) { - ptr += sprintf(ptr, "%02x:%02x:%02x:%02x:%02x:%02x %*s rssi = %d", - (int)BSSList_rid.bssid[0], - (int)BSSList_rid.bssid[1], - (int)BSSList_rid.bssid[2], - (int)BSSList_rid.bssid[3], - (int)BSSList_rid.bssid[4], - (int)BSSList_rid.bssid[5], + ptr += sprintf(ptr, "%s %*s rssi = %d", + print_mac(mac, BSSList_rid.bssid), (int)BSSList_rid.ssidLen, BSSList_rid.ssid, (int)BSSList_rid.dBm); diff --git a/drivers/net/wireless/arlan-main.c b/drivers/net/wireless/arlan-main.c index 3eaaab0ba0c..dbdfc9e39d2 100644 --- a/drivers/net/wireless/arlan-main.c +++ b/drivers/net/wireless/arlan-main.c @@ -1469,10 +1469,10 @@ static void arlan_rx_interrupt(struct net_device *dev, u_char rxStatus, u_short while (dmi) { if (dmi->dmi_addrlen == 6) { + DECLARE_MAC_BUF(mac); if (arlan_debug & ARLAN_DEBUG_HEADER_DUMP) - printk(KERN_ERR "%s mcl %2x:%2x:%2x:%2x:%2x:%2x \n", dev->name, - dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2], - dmi->dmi_addr[3], dmi->dmi_addr[4], dmi->dmi_addr[5]); + printk(KERN_ERR "%s mcl %s\n", + dev->name, print_mac(mac, dmi->dmi_addr)); for (i = 0; i < 6; i++) if (dmi->dmi_addr[i] != hw_dst_addr[i]) break; @@ -1512,17 +1512,18 @@ static void arlan_rx_interrupt(struct net_device *dev, u_char rxStatus, u_short { char immedDestAddress[6]; char immedSrcAddress[6]; + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); + DECLARE_MAC_BUF(mac3); + DECLARE_MAC_BUF(mac4); memcpy_fromio(immedDestAddress, arlan->immedDestAddress, 6); memcpy_fromio(immedSrcAddress, arlan->immedSrcAddress, 6); - printk(KERN_WARNING "%s t %2x:%2x:%2x:%2x:%2x:%2x f %2x:%2x:%2x:%2x:%2x:%2x imd %2x:%2x:%2x:%2x:%2x:%2x ims %2x:%2x:%2x:%2x:%2x:%2x\n", dev->name, - (unsigned char) skbtmp[0], (unsigned char) skbtmp[1], (unsigned char) skbtmp[2], (unsigned char) skbtmp[3], - (unsigned char) skbtmp[4], (unsigned char) skbtmp[5], (unsigned char) skbtmp[6], (unsigned char) skbtmp[7], - (unsigned char) skbtmp[8], (unsigned char) skbtmp[9], (unsigned char) skbtmp[10], (unsigned char) skbtmp[11], - immedDestAddress[0], immedDestAddress[1], immedDestAddress[2], - immedDestAddress[3], immedDestAddress[4], immedDestAddress[5], - immedSrcAddress[0], immedSrcAddress[1], immedSrcAddress[2], - immedSrcAddress[3], immedSrcAddress[4], immedSrcAddress[5]); + printk(KERN_WARNING "%s t %s f %s imd %s ims %s\n", + dev->name, print_mac(mac, skbtmp), + print_mac(mac2, &skbtmp[6]), + print_mac(mac3, immedDestAddress), + print_mac(mac4, immedSrcAddress)); } skb->protocol = eth_type_trans(skb, dev); IFDEBUG(ARLAN_DEBUG_HEADER_DUMP) diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index 47dbdf95ea6..059ce3f07db 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -1484,6 +1484,7 @@ struct net_device *init_atmel_card(unsigned short irq, unsigned long port, struct net_device *dev; struct atmel_private *priv; int rc; + DECLARE_MAC_BUF(mac); /* Create the network device object. */ dev = alloc_etherdev(sizeof(*priv)); @@ -1598,10 +1599,8 @@ struct net_device *init_atmel_card(unsigned short irq, unsigned long port, if (!ent) printk(KERN_WARNING "atmel: unable to create /proc entry.\n"); - printk(KERN_INFO "%s: Atmel at76c50x. Version %d.%d. MAC %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n", - dev->name, DRIVER_MAJOR, DRIVER_MINOR, - dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5] ); + printk(KERN_INFO "%s: Atmel at76c50x. Version %d.%d. MAC %s\n", + dev->name, DRIVER_MAJOR, DRIVER_MINOR, print_mac(mac, dev->dev_addr)); return dev; diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 184ebe3ed73..fd4ef27fcf2 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -2883,6 +2883,7 @@ static int b43_dev_set_key(struct ieee80211_hw *hw, u8 algorithm; u8 index; int err = -EINVAL; + DECLARE_MAC_BUF(mac); if (modparam_nohwcrypt) return -ENOSPC; /* User disabled HW-crypto */ @@ -2969,9 +2970,9 @@ out_unlock: out: if (!err) { b43dbg(wl, "%s hardware based encryption for keyidx: %d, " - "mac: " MAC_FMT "\n", + "mac: %s\n", cmd == SET_KEY ? "Using" : "Disabling", key->keyidx, - MAC_ARG(addr)); + print_mac(mac, addr)); } return err; } diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index ac4831adb57..61b94218094 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -2679,6 +2679,7 @@ static int b43legacy_dev_set_key(struct ieee80211_hw *hw, struct b43legacy_wldev *dev = wl->current_dev; unsigned long flags; int err = -EOPNOTSUPP; + DECLARE_MAC_BUF(mac); if (!dev) return -ENODEV; @@ -2691,7 +2692,7 @@ static int b43legacy_dev_set_key(struct ieee80211_hw *hw, spin_unlock_irqrestore(&wl->irq_lock, flags); mutex_unlock(&wl->mutex); b43legacydbg(wl, "Using software based encryption for " - "mac: " MAC_FMT "\n", MAC_ARG(addr)); + "mac: %s\n", print_mac(mac, addr)); return err; } diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index 10e07e86542..5fdbf24d244 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -994,10 +994,4 @@ int bcm43xx_pci_write_config32(struct bcm43xx_private *bcm, int offset, u32 valu __value; \ }) -/** Helpers to print MAC addresses. */ -#define BCM43xx_MACFMT "%02x:%02x:%02x:%02x:%02x:%02x" -#define BCM43xx_MACARG(x) ((u8*)(x))[0], ((u8*)(x))[1], \ - ((u8*)(x))[2], ((u8*)(x))[3], \ - ((u8*)(x))[4], ((u8*)(x))[5] - #endif /* BCM43xx_H_ */ diff --git a/drivers/net/wireless/hostap/hostap_80211_rx.c b/drivers/net/wireless/hostap/hostap_80211_rx.c index cbedc9ee740..ef084df3d48 100644 --- a/drivers/net/wireless/hostap/hostap_80211_rx.c +++ b/drivers/net/wireless/hostap/hostap_80211_rx.c @@ -19,6 +19,7 @@ void hostap_dump_rx_80211(const char *name, struct sk_buff *skb, { struct ieee80211_hdr_4addr *hdr; u16 fc; + DECLARE_MAC_BUF(mac); hdr = (struct ieee80211_hdr_4addr *) skb->data; @@ -44,10 +45,11 @@ void hostap_dump_rx_80211(const char *name, struct sk_buff *skb, printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id), le16_to_cpu(hdr->seq_ctl)); - printk(KERN_DEBUG " A1=" MACSTR " A2=" MACSTR " A3=" MACSTR, - MAC2STR(hdr->addr1), MAC2STR(hdr->addr2), MAC2STR(hdr->addr3)); + printk(KERN_DEBUG " A1=%s", print_mac(mac, hdr->addr1)); + printk(" A2=%s", print_mac(mac, hdr->addr2)); + printk(" A3=%s", print_mac(mac, hdr->addr3)); if (skb->len >= 30) - printk(" A4=" MACSTR, MAC2STR(hdr->addr4)); + printk(" A4=%s", print_mac(mac, hdr->addr4)); printk("\n"); } @@ -534,6 +536,7 @@ static int hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr_4addr *hdr, u16 fc, struct net_device **wds) { + DECLARE_MAC_BUF(mac); /* FIX: is this really supposed to accept WDS frames only in Master * mode? What about Repeater or Managed with WDS frames? */ if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) != @@ -549,10 +552,10 @@ hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr_4addr *hdr, hdr->addr1[4] != 0xff || hdr->addr1[5] != 0xff)) { /* RA (or BSSID) is not ours - drop */ PDEBUG(DEBUG_EXTRA, "%s: received WDS frame with " - "not own or broadcast %s=" MACSTR "\n", + "not own or broadcast %s=%s\n", local->dev->name, fc & IEEE80211_FCTL_FROMDS ? "RA" : "BSSID", - MAC2STR(hdr->addr1)); + print_mac(mac, hdr->addr1)); return -1; } @@ -565,8 +568,8 @@ hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr_4addr *hdr, /* require that WDS link has been registered with TA or the * frame is from current AP when using 'AP client mode' */ PDEBUG(DEBUG_EXTRA, "%s: received WDS[4 addr] frame " - "from unknown TA=" MACSTR "\n", - local->dev->name, MAC2STR(hdr->addr2)); + "from unknown TA=%s\n", + local->dev->name, print_mac(mac, hdr->addr2)); if (local->ap && local->ap->autom_ap_wds) hostap_wds_link_oper(local, hdr->addr2, WDS_ADD); return -1; @@ -632,6 +635,7 @@ hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb, { struct ieee80211_hdr_4addr *hdr; int res, hdrlen; + DECLARE_MAC_BUF(mac); if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL) return 0; @@ -643,8 +647,8 @@ hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb, strcmp(crypt->ops->name, "TKIP") == 0) { if (net_ratelimit()) { printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " - "received packet from " MACSTR "\n", - local->dev->name, MAC2STR(hdr->addr2)); + "received packet from %s\n", + local->dev->name, print_mac(mac, hdr->addr2)); } return -1; } @@ -653,9 +657,9 @@ hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb, res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv); atomic_dec(&crypt->refcnt); if (res < 0) { - printk(KERN_DEBUG "%s: decryption failed (SA=" MACSTR + printk(KERN_DEBUG "%s: decryption failed (SA=%s" ") res=%d\n", - local->dev->name, MAC2STR(hdr->addr2), res); + local->dev->name, print_mac(mac, hdr->addr2), res); local->comm_tallies.rx_discards_wep_undecryptable++; return -1; } @@ -671,6 +675,7 @@ hostap_rx_frame_decrypt_msdu(local_info_t *local, struct sk_buff *skb, { struct ieee80211_hdr_4addr *hdr; int res, hdrlen; + DECLARE_MAC_BUF(mac); if (crypt == NULL || crypt->ops->decrypt_msdu == NULL) return 0; @@ -683,8 +688,8 @@ hostap_rx_frame_decrypt_msdu(local_info_t *local, struct sk_buff *skb, atomic_dec(&crypt->refcnt); if (res < 0) { printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed" - " (SA=" MACSTR " keyidx=%d)\n", - local->dev->name, MAC2STR(hdr->addr2), keyidx); + " (SA=%s keyidx=%d)\n", + local->dev->name, print_mac(mac, hdr->addr2), keyidx); return -1; } @@ -716,6 +721,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, struct ieee80211_crypt_data *crypt = NULL; void *sta = NULL; int keyidx = 0; + DECLARE_MAC_BUF(mac); iface = netdev_priv(dev); local = iface->local; @@ -792,8 +798,8 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, * frames silently instead of filling system log with * these reports. */ printk(KERN_DEBUG "%s: WEP decryption failed (not set)" - " (SA=" MACSTR ")\n", - local->dev->name, MAC2STR(hdr->addr2)); + " (SA=%s)\n", + local->dev->name, print_mac(mac, hdr->addr2)); #endif local->comm_tallies.rx_discards_wep_undecryptable++; goto rx_dropped; @@ -807,8 +813,8 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, (keyidx = hostap_rx_frame_decrypt(local, skb, crypt)) < 0) { printk(KERN_DEBUG "%s: failed to decrypt mgmt::auth " - "from " MACSTR "\n", dev->name, - MAC2STR(hdr->addr2)); + "from %s\n", dev->name, + print_mac(mac, hdr->addr2)); /* TODO: could inform hostapd about this so that it * could send auth failure report */ goto rx_dropped; @@ -976,8 +982,8 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, "unencrypted EAPOL frame\n", local->dev->name); } else { printk(KERN_DEBUG "%s: encryption configured, but RX " - "frame not encrypted (SA=" MACSTR ")\n", - local->dev->name, MAC2STR(hdr->addr2)); + "frame not encrypted (SA=%s)\n", + local->dev->name, print_mac(mac, hdr->addr2)); goto rx_dropped; } } @@ -986,8 +992,9 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, !hostap_is_eapol_frame(local, skb)) { if (net_ratelimit()) { printk(KERN_DEBUG "%s: dropped unencrypted RX data " - "frame from " MACSTR " (drop_unencrypted=1)\n", - dev->name, MAC2STR(hdr->addr2)); + "frame from %s" + " (drop_unencrypted=1)\n", + dev->name, print_mac(mac, hdr->addr2)); } goto rx_dropped; } diff --git a/drivers/net/wireless/hostap/hostap_80211_tx.c b/drivers/net/wireless/hostap/hostap_80211_tx.c index 3df3c60263d..e7afc3ec3e6 100644 --- a/drivers/net/wireless/hostap/hostap_80211_tx.c +++ b/drivers/net/wireless/hostap/hostap_80211_tx.c @@ -17,6 +17,7 @@ void hostap_dump_tx_80211(const char *name, struct sk_buff *skb) { struct ieee80211_hdr_4addr *hdr; u16 fc; + DECLARE_MAC_BUF(mac); hdr = (struct ieee80211_hdr_4addr *) skb->data; @@ -40,10 +41,11 @@ void hostap_dump_tx_80211(const char *name, struct sk_buff *skb) printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id), le16_to_cpu(hdr->seq_ctl)); - printk(KERN_DEBUG " A1=" MACSTR " A2=" MACSTR " A3=" MACSTR, - MAC2STR(hdr->addr1), MAC2STR(hdr->addr2), MAC2STR(hdr->addr3)); + printk(KERN_DEBUG " A1=%s", print_mac(mac, hdr->addr1)); + printk(" A2=%s", print_mac(mac, hdr->addr2)); + printk(" A3=%s", print_mac(mac, hdr->addr3)); if (skb->len >= 30) - printk(" A4=" MACSTR, MAC2STR(hdr->addr4)); + printk(" A4=%s", print_mac(mac, hdr->addr4)); printk("\n"); } @@ -312,6 +314,7 @@ static struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, struct ieee80211_hdr_4addr *hdr; u16 fc; int prefix_len, postfix_len, hdr_len, res; + DECLARE_MAC_BUF(mac); iface = netdev_priv(skb->dev); local = iface->local; @@ -326,8 +329,8 @@ static struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, hdr = (struct ieee80211_hdr_4addr *) skb->data; if (net_ratelimit()) { printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " - "TX packet to " MACSTR "\n", - local->dev->name, MAC2STR(hdr->addr1)); + "TX packet to %s\n", + local->dev->name, print_mac(mac, hdr->addr1)); } kfree_skb(skb); return NULL; diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c index 90900525379..6bbdb76b32d 100644 --- a/drivers/net/wireless/hostap/hostap_ap.c +++ b/drivers/net/wireless/hostap/hostap_ap.c @@ -94,6 +94,7 @@ static void ap_sta_hash_add(struct ap_data *ap, struct sta_info *sta) static void ap_sta_hash_del(struct ap_data *ap, struct sta_info *sta) { struct sta_info *s; + DECLARE_MAC_BUF(mac); s = ap->sta_hash[STA_HASH(sta->addr)]; if (s == NULL) return; @@ -108,18 +109,20 @@ static void ap_sta_hash_del(struct ap_data *ap, struct sta_info *sta) if (s->hnext != NULL) s->hnext = s->hnext->hnext; else - printk("AP: could not remove STA " MACSTR " from hash table\n", - MAC2STR(sta->addr)); + printk("AP: could not remove STA %s" + " from hash table\n", + print_mac(mac, sta->addr)); } static void ap_free_sta(struct ap_data *ap, struct sta_info *sta) { + DECLARE_MAC_BUF(mac); if (sta->ap && sta->local) hostap_event_expired_sta(sta->local->dev, sta); if (ap->proc != NULL) { char name[20]; - sprintf(name, MACSTR, MAC2STR(sta->addr)); + sprintf(name, "%s", print_mac(mac, sta->addr)); remove_proc_entry(name, ap->proc); } @@ -182,6 +185,7 @@ static void ap_handle_timer(unsigned long data) struct ap_data *ap; unsigned long next_time = 0; int was_assoc; + DECLARE_MAC_BUF(mac); if (sta == NULL || sta->local == NULL || sta->local->ap == NULL) { PDEBUG(DEBUG_AP, "ap_handle_timer() called with NULL data\n"); @@ -238,8 +242,8 @@ static void ap_handle_timer(unsigned long data) if (sta->ap) { if (ap->autom_ap_wds) { PDEBUG(DEBUG_AP, "%s: removing automatic WDS " - "connection to AP " MACSTR "\n", - local->dev->name, MAC2STR(sta->addr)); + "connection to AP %s\n", + local->dev->name, print_mac(mac, sta->addr)); hostap_wds_link_oper(local, sta->addr, WDS_DEL); } } else if (sta->timeout_next == STA_NULLFUNC) { @@ -255,11 +259,11 @@ static void ap_handle_timer(unsigned long data) } else { int deauth = sta->timeout_next == STA_DEAUTH; u16 resp; - PDEBUG(DEBUG_AP, "%s: sending %s info to STA " MACSTR + PDEBUG(DEBUG_AP, "%s: sending %s info to STA %s" "(last=%lu, jiffies=%lu)\n", local->dev->name, deauth ? "deauthentication" : "disassociation", - MAC2STR(sta->addr), sta->last_rx, jiffies); + print_mac(mac, sta->addr), sta->last_rx, jiffies); resp = cpu_to_le16(deauth ? WLAN_REASON_PREV_AUTH_NOT_VALID : WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY); @@ -271,9 +275,10 @@ static void ap_handle_timer(unsigned long data) if (sta->timeout_next == STA_DEAUTH) { if (sta->flags & WLAN_STA_PERM) { - PDEBUG(DEBUG_AP, "%s: STA " MACSTR " would have been " - "removed, but it has 'perm' flag\n", - local->dev->name, MAC2STR(sta->addr)); + PDEBUG(DEBUG_AP, "%s: STA %s" + " would have been removed, " + "but it has 'perm' flag\n", + local->dev->name, print_mac(mac, sta->addr)); } else ap_free_sta(ap, sta); return; @@ -327,6 +332,7 @@ static int ap_control_proc_read(char *page, char **start, off_t off, struct ap_data *ap = (struct ap_data *) data; char *policy_txt; struct mac_entry *entry; + DECLARE_MAC_BUF(mac); if (off != 0) { *eof = 1; @@ -357,7 +363,7 @@ static int ap_control_proc_read(char *page, char **start, off_t off, break; } - p += sprintf(p, MACSTR "\n", MAC2STR(entry->addr)); + p += sprintf(p, "%s\n", print_mac(mac, entry->addr)); } spin_unlock_bh(&ap->mac_restrictions.lock); @@ -514,6 +520,7 @@ static int prism2_ap_proc_read(char *page, char **start, off_t off, struct ap_data *ap = (struct ap_data *) data; struct sta_info *sta; int i; + DECLARE_MAC_BUF(mac); if (off > PROC_LIMIT) { *eof = 1; @@ -526,7 +533,8 @@ static int prism2_ap_proc_read(char *page, char **start, off_t off, if (!sta->ap) continue; - p += sprintf(p, MACSTR " %d %d %d %d '", MAC2STR(sta->addr), + p += sprintf(p, "%s %d %d %d %d '", + print_mac(mac, sta->addr), sta->u.ap.channel, sta->last_rx_signal, sta->last_rx_silence, sta->last_rx_rate); for (i = 0; i < sta->u.ap.ssid_len; i++) @@ -623,6 +631,7 @@ static void hostap_ap_tx_cb_auth(struct sk_buff *skb, int ok, void *data) u16 fc, *pos, auth_alg, auth_transaction, status; struct sta_info *sta = NULL; char *txt = NULL; + DECLARE_MAC_BUF(mac); if (ap->local->hostapd) { dev_kfree_skb(skb); @@ -674,9 +683,9 @@ static void hostap_ap_tx_cb_auth(struct sk_buff *skb, int ok, void *data) if (sta) atomic_dec(&sta->users); if (txt) { - PDEBUG(DEBUG_AP, "%s: " MACSTR " auth_cb - alg=%d trans#=%d " - "status=%d - %s\n", - dev->name, MAC2STR(hdr->addr1), auth_alg, + PDEBUG(DEBUG_AP, "%s: %s auth_cb - alg=%d " + "trans#=%d status=%d - %s\n", + dev->name, print_mac(mac, hdr->addr1), auth_alg, auth_transaction, status, txt); } dev_kfree_skb(skb); @@ -692,6 +701,7 @@ static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data) u16 fc, *pos, status; struct sta_info *sta = NULL; char *txt = NULL; + DECLARE_MAC_BUF(mac); if (ap->local->hostapd) { dev_kfree_skb(skb); @@ -742,8 +752,8 @@ static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data) if (sta) atomic_dec(&sta->users); if (txt) { - PDEBUG(DEBUG_AP, "%s: " MACSTR " assoc_cb - %s\n", - dev->name, MAC2STR(hdr->addr1), txt); + PDEBUG(DEBUG_AP, "%s: %s assoc_cb - %s\n", + dev->name, print_mac(mac, hdr->addr1), txt); } dev_kfree_skb(skb); } @@ -755,6 +765,7 @@ static void hostap_ap_tx_cb_poll(struct sk_buff *skb, int ok, void *data) struct ap_data *ap = data; struct ieee80211_hdr_4addr *hdr; struct sta_info *sta; + DECLARE_MAC_BUF(mac); if (skb->len < 24) goto fail; @@ -766,9 +777,9 @@ static void hostap_ap_tx_cb_poll(struct sk_buff *skb, int ok, void *data) sta->flags &= ~WLAN_STA_PENDING_POLL; spin_unlock(&ap->sta_table_lock); } else { - PDEBUG(DEBUG_AP, "%s: STA " MACSTR " did not ACK activity " - "poll frame\n", ap->local->dev->name, - MAC2STR(hdr->addr1)); + PDEBUG(DEBUG_AP, "%s: STA %s" + " did not ACK activity poll frame\n", + ap->local->dev->name, print_mac(mac, hdr->addr1)); } fail: @@ -985,6 +996,7 @@ static int prism2_sta_proc_read(char *page, char **start, off_t off, char *p = page; struct sta_info *sta = (struct sta_info *) data; int i; + DECLARE_MAC_BUF(mac); /* FIX: possible race condition.. the STA data could have just expired, * but proc entry was still here so that the read could have started; @@ -995,11 +1007,11 @@ static int prism2_sta_proc_read(char *page, char **start, off_t off, return 0; } - p += sprintf(p, "%s=" MACSTR "\nusers=%d\naid=%d\n" + p += sprintf(p, "%s=%s\nusers=%d\naid=%d\n" "flags=0x%04x%s%s%s%s%s%s%s\n" "capability=0x%02x\nlisten_interval=%d\nsupported_rates=", sta->ap ? "AP" : "STA", - MAC2STR(sta->addr), atomic_read(&sta->users), sta->aid, + print_mac(mac, sta->addr), atomic_read(&sta->users), sta->aid, sta->flags, sta->flags & WLAN_STA_AUTH ? " AUTH" : "", sta->flags & WLAN_STA_ASSOC ? " ASSOC" : "", @@ -1060,6 +1072,7 @@ static void handle_add_proc_queue(struct work_struct *work) struct sta_info *sta; char name[20]; struct add_sta_proc_data *entry, *prev; + DECLARE_MAC_BUF(mac); entry = ap->add_sta_proc_entries; ap->add_sta_proc_entries = NULL; @@ -1072,7 +1085,7 @@ static void handle_add_proc_queue(struct work_struct *work) spin_unlock_bh(&ap->sta_table_lock); if (sta) { - sprintf(name, MACSTR, MAC2STR(sta->addr)); + sprintf(name, "%s", print_mac(mac, sta->addr)); sta->proc = create_proc_read_entry( name, 0, ap->proc, prism2_sta_proc_read, sta); @@ -1290,6 +1303,7 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb, struct sta_info *sta = NULL; struct ieee80211_crypt_data *crypt; char *txt = ""; + DECLARE_MAC_BUF(mac); len = skb->len - IEEE80211_MGMT_HDR_LEN; @@ -1298,8 +1312,8 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb, if (len < 6) { PDEBUG(DEBUG_AP, "%s: handle_authen - too short payload " - "(len=%d) from " MACSTR "\n", dev->name, len, - MAC2STR(hdr->addr2)); + "(len=%d) from %s\n", dev->name, len, + print_mac(mac, hdr->addr2)); return; } @@ -1364,8 +1378,8 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb, if (time_after(jiffies, sta->u.ap.last_beacon + (10 * sta->listen_interval * HZ) / 1024)) { PDEBUG(DEBUG_AP, "%s: no beacons received for a while," - " assuming AP " MACSTR " is now STA\n", - dev->name, MAC2STR(sta->addr)); + " assuming AP %s is now STA\n", + dev->name, print_mac(mac, sta->addr)); sta->ap = 0; sta->flags = 0; sta->u.sta.challenge = NULL; @@ -1480,9 +1494,9 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb, } if (resp) { - PDEBUG(DEBUG_AP, "%s: " MACSTR " auth (alg=%d trans#=%d " - "stat=%d len=%d fc=%04x) ==> %d (%s)\n", - dev->name, MAC2STR(hdr->addr2), auth_alg, + PDEBUG(DEBUG_AP, "%s: %s auth (alg=%d " + "trans#=%d stat=%d len=%d fc=%04x) ==> %d (%s)\n", + dev->name, print_mac(mac, hdr->addr2), auth_alg, auth_transaction, status_code, len, fc, resp, txt); } } @@ -1502,13 +1516,14 @@ static void handle_assoc(local_info_t *local, struct sk_buff *skb, int send_deauth = 0; char *txt = ""; u8 prev_ap[ETH_ALEN]; + DECLARE_MAC_BUF(mac); left = len = skb->len - IEEE80211_MGMT_HDR_LEN; if (len < (reassoc ? 10 : 4)) { PDEBUG(DEBUG_AP, "%s: handle_assoc - too short payload " - "(len=%d, reassoc=%d) from " MACSTR "\n", - dev->name, len, reassoc, MAC2STR(hdr->addr2)); + "(len=%d, reassoc=%d) from %s\n", + dev->name, len, reassoc, print_mac(mac, hdr->addr2)); return; } @@ -1585,9 +1600,9 @@ static void handle_assoc(local_info_t *local, struct sk_buff *skb, } if (left > 0) { - PDEBUG(DEBUG_AP, "%s: assoc from " MACSTR " with extra" - " data (%d bytes) [", - dev->name, MAC2STR(hdr->addr2), left); + PDEBUG(DEBUG_AP, "%s: assoc from %s" + " with extra data (%d bytes) [", + dev->name, print_mac(mac, hdr->addr2), left); while (left > 0) { PDEBUG2(DEBUG_AP, "<%02x>", *u); u++; left--; @@ -1687,10 +1702,10 @@ static void handle_assoc(local_info_t *local, struct sk_buff *skb, } #if 0 - PDEBUG(DEBUG_AP, "%s: " MACSTR " %sassoc (len=%d prev_ap=" MACSTR - ") => %d(%d) (%s)\n", - dev->name, MAC2STR(hdr->addr2), reassoc ? "re" : "", len, - MAC2STR(prev_ap), resp, send_deauth, txt); + PDEBUG(DEBUG_AP, "%s: %s %sassoc (len=%d " + "prev_ap=%s) => %d(%d) (%s)\n", + dev->name, print_mac(mac, hdr->addr2), reassoc ? "re" : "", len, + print_mac(mac, prev_ap), resp, send_deauth, txt); #endif } @@ -1705,6 +1720,7 @@ static void handle_deauth(local_info_t *local, struct sk_buff *skb, int len; u16 reason_code, *pos; struct sta_info *sta = NULL; + DECLARE_MAC_BUF(mac); len = skb->len - IEEE80211_MGMT_HDR_LEN; @@ -1716,8 +1732,8 @@ static void handle_deauth(local_info_t *local, struct sk_buff *skb, pos = (u16 *) body; reason_code = __le16_to_cpu(*pos); - PDEBUG(DEBUG_AP, "%s: deauthentication: " MACSTR " len=%d, " - "reason_code=%d\n", dev->name, MAC2STR(hdr->addr2), len, + PDEBUG(DEBUG_AP, "%s: deauthentication: %s len=%d, " + "reason_code=%d\n", dev->name, print_mac(mac, hdr->addr2), len, reason_code); spin_lock_bh(&local->ap->sta_table_lock); @@ -1729,9 +1745,9 @@ static void handle_deauth(local_info_t *local, struct sk_buff *skb, } spin_unlock_bh(&local->ap->sta_table_lock); if (sta == NULL) { - printk("%s: deauthentication from " MACSTR ", " + printk("%s: deauthentication from %s, " "reason_code=%d, but STA not authenticated\n", dev->name, - MAC2STR(hdr->addr2), reason_code); + print_mac(mac, hdr->addr2), reason_code); } } @@ -1746,6 +1762,7 @@ static void handle_disassoc(local_info_t *local, struct sk_buff *skb, int len; u16 reason_code, *pos; struct sta_info *sta = NULL; + DECLARE_MAC_BUF(mac); len = skb->len - IEEE80211_MGMT_HDR_LEN; @@ -1757,8 +1774,8 @@ static void handle_disassoc(local_info_t *local, struct sk_buff *skb, pos = (u16 *) body; reason_code = __le16_to_cpu(*pos); - PDEBUG(DEBUG_AP, "%s: disassociation: " MACSTR " len=%d, " - "reason_code=%d\n", dev->name, MAC2STR(hdr->addr2), len, + PDEBUG(DEBUG_AP, "%s: disassociation: %s len=%d, " + "reason_code=%d\n", dev->name, print_mac(mac, hdr->addr2), len, reason_code); spin_lock_bh(&local->ap->sta_table_lock); @@ -1770,9 +1787,9 @@ static void handle_disassoc(local_info_t *local, struct sk_buff *skb, } spin_unlock_bh(&local->ap->sta_table_lock); if (sta == NULL) { - printk("%s: disassociation from " MACSTR ", " + printk("%s: disassociation from %s, " "reason_code=%d, but STA not authenticated\n", - dev->name, MAC2STR(hdr->addr2), reason_code); + dev->name, print_mac(mac, hdr->addr2), reason_code); } } @@ -1862,15 +1879,16 @@ static void handle_pspoll(local_info_t *local, struct sta_info *sta; u16 aid; struct sk_buff *skb; + DECLARE_MAC_BUF(mac); - PDEBUG(DEBUG_PS2, "handle_pspoll: BSSID=" MACSTR ", TA=" MACSTR - " PWRMGT=%d\n", - MAC2STR(hdr->addr1), MAC2STR(hdr->addr2), + PDEBUG(DEBUG_PS2, "handle_pspoll: BSSID=%s" + ", TA=%s PWRMGT=%d\n", + print_mac(mac, hdr->addr1), print_mac(mac, hdr->addr2), !!(le16_to_cpu(hdr->frame_ctl) & IEEE80211_FCTL_PM)); if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) { - PDEBUG(DEBUG_AP, "handle_pspoll - addr1(BSSID)=" MACSTR - " not own MAC\n", MAC2STR(hdr->addr1)); + PDEBUG(DEBUG_AP, "handle_pspoll - addr1(BSSID)=%s" + " not own MAC\n", print_mac(mac, hdr->addr1)); return; } @@ -1948,6 +1966,7 @@ static void handle_wds_oper_queue(struct work_struct *work) wds_oper_queue); local_info_t *local = ap->local; struct wds_oper_data *entry, *prev; + DECLARE_MAC_BUF(mac); spin_lock_bh(&local->lock); entry = local->ap->wds_oper_entries; @@ -1956,10 +1975,10 @@ static void handle_wds_oper_queue(struct work_struct *work) while (entry) { PDEBUG(DEBUG_AP, "%s: %s automatic WDS connection " - "to AP " MACSTR "\n", + "to AP %s\n", local->dev->name, entry->type == WDS_ADD ? "adding" : "removing", - MAC2STR(entry->addr)); + print_mac(mac, entry->addr)); if (entry->type == WDS_ADD) prism2_wds_add(local, entry->addr, 0); else if (entry->type == WDS_DEL) @@ -2135,6 +2154,7 @@ static void handle_ap_item(local_info_t *local, struct sk_buff *skb, #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ u16 fc, type, stype; struct ieee80211_hdr_4addr *hdr; + DECLARE_MAC_BUF(mac); /* FIX: should give skb->len to handler functions and check that the * buffer is long enough */ @@ -2163,8 +2183,8 @@ static void handle_ap_item(local_info_t *local, struct sk_buff *skb, if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) { PDEBUG(DEBUG_AP, "handle_ap_item - addr1(BSSID)=" - MACSTR " not own MAC\n", - MAC2STR(hdr->addr1)); + "%s not own MAC\n", + print_mac(mac, hdr->addr1)); goto done; } @@ -2200,14 +2220,14 @@ static void handle_ap_item(local_info_t *local, struct sk_buff *skb, } if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) { - PDEBUG(DEBUG_AP, "handle_ap_item - addr1(DA)=" MACSTR - " not own MAC\n", MAC2STR(hdr->addr1)); + PDEBUG(DEBUG_AP, "handle_ap_item - addr1(DA)=%s" + " not own MAC\n", print_mac(mac, hdr->addr1)); goto done; } if (memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN)) { - PDEBUG(DEBUG_AP, "handle_ap_item - addr3(BSSID)=" MACSTR - " not own MAC\n", MAC2STR(hdr->addr3)); + PDEBUG(DEBUG_AP, "handle_ap_item - addr3(BSSID)=%s" + " not own MAC\n", print_mac(mac, hdr->addr3)); goto done; } @@ -2288,6 +2308,7 @@ static void schedule_packet_send(local_info_t *local, struct sta_info *sta) struct sk_buff *skb; struct ieee80211_hdr_4addr *hdr; struct hostap_80211_rx_status rx_stats; + DECLARE_MAC_BUF(mac); if (skb_queue_empty(&sta->tx_buf)) return; @@ -2308,8 +2329,8 @@ static void schedule_packet_send(local_info_t *local, struct sta_info *sta) memcpy(hdr->addr2, sta->addr, ETH_ALEN); hdr->duration_id = cpu_to_le16(sta->aid | BIT(15) | BIT(14)); - PDEBUG(DEBUG_PS2, "%s: Scheduling buffered packet delivery for " - "STA " MACSTR "\n", local->dev->name, MAC2STR(sta->addr)); + PDEBUG(DEBUG_PS2, "%s: Scheduling buffered packet delivery for STA " + "%s\n", local->dev->name, print_mac(mac, sta->addr)); skb->dev = local->dev; @@ -2636,6 +2657,7 @@ static int ap_update_sta_tx_rate(struct sta_info *sta, struct net_device *dev) int ret = sta->tx_rate; struct hostap_interface *iface; local_info_t *local; + DECLARE_MAC_BUF(mac); iface = netdev_priv(dev); local = iface->local; @@ -2663,9 +2685,9 @@ static int ap_update_sta_tx_rate(struct sta_info *sta, struct net_device *dev) case 3: sta->tx_rate = 110; break; default: sta->tx_rate = 0; break; } - PDEBUG(DEBUG_AP, "%s: STA " MACSTR " TX rate raised to" - " %d\n", dev->name, MAC2STR(sta->addr), - sta->tx_rate); + PDEBUG(DEBUG_AP, "%s: STA %s" + " TX rate raised to %d\n", + dev->name, print_mac(mac, sta->addr), sta->tx_rate); } sta->tx_since_last_failure = 0; } @@ -2683,6 +2705,7 @@ ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx) int set_tim, ret; struct ieee80211_hdr_4addr *hdr; struct hostap_skb_tx_data *meta; + DECLARE_MAC_BUF(mac); meta = (struct hostap_skb_tx_data *) skb->cb; ret = AP_TX_CONTINUE; @@ -2718,7 +2741,8 @@ ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx) * print out any errors here. */ if (net_ratelimit()) { printk(KERN_DEBUG "AP: drop packet to non-associated " - "STA " MACSTR "\n", MAC2STR(hdr->addr1)); + "STA %s\n", + print_mac(mac, hdr->addr1)); } #endif local->ap->tx_drop_nonassoc++; @@ -2756,8 +2780,9 @@ ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx) } if (skb_queue_len(&sta->tx_buf) >= STA_MAX_TX_BUFFER) { - PDEBUG(DEBUG_PS, "%s: No more space in STA (" MACSTR ")'s PS " - "mode buffer\n", local->dev->name, MAC2STR(sta->addr)); + PDEBUG(DEBUG_PS, "%s: No more space in STA (%s" + ")'s PS mode buffer\n", + local->dev->name, print_mac(mac, sta->addr)); /* Make sure that TIM is set for the station (it might not be * after AP wlan hw reset). */ /* FIX: should fix hw reset to restore bits based on STA @@ -2821,6 +2846,7 @@ void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb) struct sta_info *sta; struct ieee80211_hdr_4addr *hdr; struct hostap_skb_tx_data *meta; + DECLARE_MAC_BUF(mac); hdr = (struct ieee80211_hdr_4addr *) skb->data; meta = (struct hostap_skb_tx_data *) skb->cb; @@ -2829,9 +2855,9 @@ void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb) sta = ap_get_sta(local->ap, hdr->addr1); if (!sta) { spin_unlock(&local->ap->sta_table_lock); - PDEBUG(DEBUG_AP, "%s: Could not find STA " MACSTR " for this " - "TX error (@%lu)\n", - local->dev->name, MAC2STR(hdr->addr1), jiffies); + PDEBUG(DEBUG_AP, "%s: Could not find STA %s" + " for this TX error (@%lu)\n", + local->dev->name, print_mac(mac, hdr->addr1), jiffies); return; } @@ -2858,8 +2884,9 @@ void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb) case 3: sta->tx_rate = 110; break; default: sta->tx_rate = 0; break; } - PDEBUG(DEBUG_AP, "%s: STA " MACSTR " TX rate lowered " - "to %d\n", local->dev->name, MAC2STR(sta->addr), + PDEBUG(DEBUG_AP, "%s: STA %s" + " TX rate lowered to %d\n", + local->dev->name, print_mac(mac, sta->addr), sta->tx_rate); } sta->tx_consecutive_exc = 0; @@ -2871,16 +2898,17 @@ void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb) static void hostap_update_sta_ps2(local_info_t *local, struct sta_info *sta, int pwrmgt, int type, int stype) { + DECLARE_MAC_BUF(mac); if (pwrmgt && !(sta->flags & WLAN_STA_PS)) { sta->flags |= WLAN_STA_PS; - PDEBUG(DEBUG_PS2, "STA " MACSTR " changed to use PS " + PDEBUG(DEBUG_PS2, "STA %s changed to use PS " "mode (type=0x%02X, stype=0x%02X)\n", - MAC2STR(sta->addr), type >> 2, stype >> 4); + print_mac(mac, sta->addr), type >> 2, stype >> 4); } else if (!pwrmgt && (sta->flags & WLAN_STA_PS)) { sta->flags &= ~WLAN_STA_PS; - PDEBUG(DEBUG_PS2, "STA " MACSTR " changed to not use " + PDEBUG(DEBUG_PS2, "STA %s changed to not use " "PS mode (type=0x%02X, stype=0x%02X)\n", - MAC2STR(sta->addr), type >> 2, stype >> 4); + print_mac(mac, sta->addr), type >> 2, stype >> 4); if (type != IEEE80211_FTYPE_CTL || stype != IEEE80211_STYPE_PSPOLL) schedule_packet_send(local, sta); @@ -2924,6 +2952,7 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, struct sta_info *sta; u16 fc, type, stype; struct ieee80211_hdr_4addr *hdr; + DECLARE_MAC_BUF(mac); if (local->ap == NULL) return AP_RX_CONTINUE; @@ -2954,9 +2983,10 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT } else { printk(KERN_DEBUG "%s: dropped received packet" - " from non-associated STA " MACSTR + " from non-associated STA " + "%s" " (type=0x%02x, subtype=0x%02x)\n", - dev->name, MAC2STR(hdr->addr2), + dev->name, print_mac(mac, hdr->addr2), type >> 2, stype >> 4); hostap_rx(dev, skb, rx_stats); #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ @@ -2991,8 +3021,8 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, * being associated. */ printk(KERN_DEBUG "%s: rejected received nullfunc " "frame without ToDS from not associated STA " - MACSTR "\n", - dev->name, MAC2STR(hdr->addr2)); + "%s\n", + dev->name, print_mac(mac, hdr->addr2)); hostap_rx(dev, skb, rx_stats); #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ } @@ -3009,9 +3039,9 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, * If BSSID is own, report the dropping of this frame. */ if (memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN) == 0) { printk(KERN_DEBUG "%s: dropped received packet from " - MACSTR " with no ToDS flag (type=0x%02x, " - "subtype=0x%02x)\n", dev->name, - MAC2STR(hdr->addr2), type >> 2, stype >> 4); + "%s with no ToDS flag " + "(type=0x%02x, subtype=0x%02x)\n", dev->name, + print_mac(mac, hdr->addr2), type >> 2, stype >> 4); hostap_dump_rx_80211(dev->name, skb, rx_stats); } ret = AP_RX_DROP; diff --git a/drivers/net/wireless/hostap/hostap_common.h b/drivers/net/wireless/hostap/hostap_common.h index b31e6a05f23..ceb7f1e5e9e 100644 --- a/drivers/net/wireless/hostap/hostap_common.h +++ b/drivers/net/wireless/hostap/hostap_common.h @@ -6,9 +6,6 @@ #define BIT(x) (1 << (x)) -#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] -#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" - /* IEEE 802.11 defines */ diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c index adedb971654..7fa7ab0a4b2 100644 --- a/drivers/net/wireless/hostap/hostap_hw.c +++ b/drivers/net/wireless/hostap/hostap_hw.c @@ -2335,6 +2335,10 @@ static void prism2_txexc(local_info_t *local) int show_dump, res; char *payload = NULL; struct hfa384x_tx_frame txdesc; + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); + DECLARE_MAC_BUF(mac3); + DECLARE_MAC_BUF(mac4); show_dump = local->frame_dump & PRISM2_DUMP_TXEXC_HDR; local->stats.tx_errors++; @@ -2400,10 +2404,9 @@ static void prism2_txexc(local_info_t *local) WLAN_FC_GET_STYPE(fc) >> 4, fc & IEEE80211_FCTL_TODS ? " ToDS" : "", fc & IEEE80211_FCTL_FROMDS ? " FromDS" : ""); - PDEBUG(DEBUG_EXTRA, " A1=" MACSTR " A2=" MACSTR " A3=" - MACSTR " A4=" MACSTR "\n", - MAC2STR(txdesc.addr1), MAC2STR(txdesc.addr2), - MAC2STR(txdesc.addr3), MAC2STR(txdesc.addr4)); + PDEBUG(DEBUG_EXTRA, " A1=%s A2=%s A3=%s A4=%s\n", + print_mac(mac, txdesc.addr1), print_mac(mac2, txdesc.addr2), + print_mac(mac3, txdesc.addr3), print_mac(mac4, txdesc.addr4)); } diff --git a/drivers/net/wireless/hostap/hostap_info.c b/drivers/net/wireless/hostap/hostap_info.c index b6a02a02da7..636f4b2382e 100644 --- a/drivers/net/wireless/hostap/hostap_info.c +++ b/drivers/net/wireless/hostap/hostap_info.c @@ -166,6 +166,7 @@ static void prism2_host_roaming(local_info_t *local) struct hfa384x_hostscan_result *selected, *entry; int i; unsigned long flags; + DECLARE_MAC_BUF(mac); if (local->last_join_time && time_before(jiffies, local->last_join_time + 10 * HZ)) { @@ -198,8 +199,9 @@ static void prism2_host_roaming(local_info_t *local) local->preferred_ap[2] || local->preferred_ap[3] || local->preferred_ap[4] || local->preferred_ap[5]) { /* Try to find preferred AP */ - PDEBUG(DEBUG_EXTRA, "%s: Preferred AP BSSID " MACSTR "\n", - dev->name, MAC2STR(local->preferred_ap)); + PDEBUG(DEBUG_EXTRA, "%s: Preferred AP BSSID " + "%s\n", + dev->name, print_mac(mac, local->preferred_ap)); for (i = 0; i < local->last_scan_results_count; i++) { entry = &local->last_scan_results[i]; if (memcmp(local->preferred_ap, entry->bssid, 6) == 0) @@ -216,8 +218,9 @@ static void prism2_host_roaming(local_info_t *local) req.channel = selected->chid; spin_unlock_irqrestore(&local->lock, flags); - PDEBUG(DEBUG_EXTRA, "%s: JoinRequest: BSSID=" MACSTR " channel=%d\n", - dev->name, MAC2STR(req.bssid), le16_to_cpu(req.channel)); + PDEBUG(DEBUG_EXTRA, "%s: JoinRequest: BSSID=%s" + " channel=%d\n", + dev->name, print_mac(mac, req.bssid), le16_to_cpu(req.channel)); if (local->func->set_rid(dev, HFA384X_RID_JOINREQUEST, &req, sizeof(req))) { printk(KERN_DEBUG "%s: JoinRequest failed\n", dev->name); @@ -409,6 +412,7 @@ static void handle_info_queue_linkstatus(local_info_t *local) int val = local->prev_link_status; int connected; union iwreq_data wrqu; + DECLARE_MAC_BUF(mac); connected = val == HFA384X_LINKSTATUS_CONNECTED || @@ -420,9 +424,10 @@ static void handle_info_queue_linkstatus(local_info_t *local) printk(KERN_DEBUG "%s: could not read CURRENTBSSID after " "LinkStatus event\n", local->dev->name); } else { - PDEBUG(DEBUG_EXTRA, "%s: LinkStatus: BSSID=" MACSTR "\n", + PDEBUG(DEBUG_EXTRA, "%s: LinkStatus: BSSID=" + "%s\n", local->dev->name, - MAC2STR((unsigned char *) local->bssid)); + print_mac(mac, (unsigned char *) local->bssid)); if (local->wds_type & HOSTAP_WDS_AP_CLIENT) hostap_add_sta(local->ap, local->bssid); } diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c index 730b3541e32..7036ecff5ec 100644 --- a/drivers/net/wireless/hostap/hostap_ioctl.c +++ b/drivers/net/wireless/hostap/hostap_ioctl.c @@ -664,6 +664,7 @@ static int hostap_join_ap(struct net_device *dev) unsigned long flags; int i; struct hfa384x_hostscan_result *entry; + DECLARE_MAC_BUF(mac); iface = netdev_priv(dev); local = iface->local; @@ -685,14 +686,14 @@ static int hostap_join_ap(struct net_device *dev) if (local->func->set_rid(dev, HFA384X_RID_JOINREQUEST, &req, sizeof(req))) { - printk(KERN_DEBUG "%s: JoinRequest " MACSTR + printk(KERN_DEBUG "%s: JoinRequest %s" " failed\n", - dev->name, MAC2STR(local->preferred_ap)); + dev->name, print_mac(mac, local->preferred_ap)); return -1; } - printk(KERN_DEBUG "%s: Trying to join BSSID " MACSTR "\n", - dev->name, MAC2STR(local->preferred_ap)); + printk(KERN_DEBUG "%s: Trying to join BSSID %s\n", + dev->name, print_mac(mac, local->preferred_ap)); return 0; } @@ -3697,8 +3698,10 @@ static int prism2_ioctl_set_assoc_ap_addr(local_info_t *local, struct prism2_hostapd_param *param, int param_len) { - printk(KERN_DEBUG "%ssta: associated as client with AP " MACSTR "\n", - local->dev->name, MAC2STR(param->sta_addr)); + DECLARE_MAC_BUF(mac); + printk(KERN_DEBUG "%ssta: associated as client with AP " + "%s\n", + local->dev->name, print_mac(mac, param->sta_addr)); memcpy(local->assoc_ap_addr, param->sta_addr, ETH_ALEN); return 0; } diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c index 9a470e80ca2..4cb09d81b40 100644 --- a/drivers/net/wireless/hostap/hostap_main.c +++ b/drivers/net/wireless/hostap/hostap_main.c @@ -530,6 +530,10 @@ int hostap_set_auth_algs(local_info_t *local) void hostap_dump_rx_header(const char *name, const struct hfa384x_rx_frame *rx) { u16 status, fc; + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); + DECLARE_MAC_BUF(mac3); + DECLARE_MAC_BUF(mac4); status = __le16_to_cpu(rx->status); @@ -548,13 +552,12 @@ void hostap_dump_rx_header(const char *name, const struct hfa384x_rx_frame *rx) fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "", fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : ""); - printk(KERN_DEBUG " A1=" MACSTR " A2=" MACSTR " A3=" MACSTR " A4=" - MACSTR "\n", - MAC2STR(rx->addr1), MAC2STR(rx->addr2), MAC2STR(rx->addr3), - MAC2STR(rx->addr4)); + printk(KERN_DEBUG " A1=%s A2=%s A3=%s A4=%s\n", + print_mac(mac, rx->addr1), print_mac(mac2, rx->addr2), + print_mac(mac3, rx->addr3), print_mac(mac4, rx->addr4)); - printk(KERN_DEBUG " dst=" MACSTR " src=" MACSTR " len=%d\n", - MAC2STR(rx->dst_addr), MAC2STR(rx->src_addr), + printk(KERN_DEBUG " dst=%s src=%s len=%d\n", + print_mac(mac, rx->dst_addr), print_mac(mac2, rx->src_addr), __be16_to_cpu(rx->len)); } @@ -562,6 +565,10 @@ void hostap_dump_rx_header(const char *name, const struct hfa384x_rx_frame *rx) void hostap_dump_tx_header(const char *name, const struct hfa384x_tx_frame *tx) { u16 fc; + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); + DECLARE_MAC_BUF(mac3); + DECLARE_MAC_BUF(mac4); printk(KERN_DEBUG "%s: TX status=0x%04x retry_count=%d tx_rate=%d " "tx_control=0x%04x; jiffies=%ld\n", @@ -577,13 +584,12 @@ void hostap_dump_tx_header(const char *name, const struct hfa384x_tx_frame *tx) fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "", fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : ""); - printk(KERN_DEBUG " A1=" MACSTR " A2=" MACSTR " A3=" MACSTR " A4=" - MACSTR "\n", - MAC2STR(tx->addr1), MAC2STR(tx->addr2), MAC2STR(tx->addr3), - MAC2STR(tx->addr4)); + printk(KERN_DEBUG " A1=%s A2=%s A3=%s A4=%s\n", + print_mac(mac, tx->addr1), print_mac(mac2, tx->addr2), + print_mac(mac3, tx->addr3), print_mac(mac4, tx->addr4)); - printk(KERN_DEBUG " dst=" MACSTR " src=" MACSTR " len=%d\n", - MAC2STR(tx->dst_addr), MAC2STR(tx->src_addr), + printk(KERN_DEBUG " dst=%s src=%s len=%d\n", + print_mac(mac, tx->dst_addr), print_mac(mac2, tx->src_addr), __be16_to_cpu(tx->len)); } diff --git a/drivers/net/wireless/hostap/hostap_proc.c b/drivers/net/wireless/hostap/hostap_proc.c index d1d8ce022e6..b03536008ad 100644 --- a/drivers/net/wireless/hostap/hostap_proc.c +++ b/drivers/net/wireless/hostap/hostap_proc.c @@ -106,6 +106,7 @@ static int prism2_wds_proc_read(char *page, char **start, off_t off, local_info_t *local = (local_info_t *) data; struct list_head *ptr; struct hostap_interface *iface; + DECLARE_MAC_BUF(mac); if (off > PROC_LIMIT) { *eof = 1; @@ -117,9 +118,9 @@ static int prism2_wds_proc_read(char *page, char **start, off_t off, iface = list_entry(ptr, struct hostap_interface, list); if (iface->type != HOSTAP_INTERFACE_WDS) continue; - p += sprintf(p, "%s\t" MACSTR "\n", + p += sprintf(p, "%s\t%s\n", iface->dev->name, - MAC2STR(iface->u.wds.remote_addr)); + print_mac(mac, iface->u.wds.remote_addr)); if ((p - page) > PROC_LIMIT) { printk(KERN_DEBUG "%s: wds proc did not fit\n", local->dev->name); @@ -147,6 +148,7 @@ static int prism2_bss_list_proc_read(char *page, char **start, off_t off, struct list_head *ptr; struct hostap_bss_info *bss; int i; + DECLARE_MAC_BUF(mac); if (off > PROC_LIMIT) { *eof = 1; @@ -158,8 +160,8 @@ static int prism2_bss_list_proc_read(char *page, char **start, off_t off, spin_lock_bh(&local->lock); list_for_each(ptr, &local->bss_list) { bss = list_entry(ptr, struct hostap_bss_info, list); - p += sprintf(p, MACSTR "\t%lu\t%u\t0x%x\t", - MAC2STR(bss->bssid), bss->last_update, + p += sprintf(p, "%s\t%lu\t%u\t0x%x\t", + print_mac(mac, bss->bssid), bss->last_update, bss->count, bss->capab_info); for (i = 0; i < bss->ssid_len; i++) { p += sprintf(p, "%c", @@ -312,6 +314,7 @@ static int prism2_scan_results_proc_read(char *page, char **start, off_t off, int entry, i, len, total = 0; struct hfa384x_hostscan_result *scanres; u8 *pos; + DECLARE_MAC_BUF(mac); p += sprintf(p, "CHID ANL SL BcnInt Capab Rate BSSID ATIM SupRates " "SSID\n"); @@ -329,14 +332,14 @@ static int prism2_scan_results_proc_read(char *page, char **start, off_t off, if ((p - page) > (PAGE_SIZE - 200)) break; - p += sprintf(p, "%d %d %d %d 0x%02x %d " MACSTR " %d ", + p += sprintf(p, "%d %d %d %d 0x%02x %d %s %d ", le16_to_cpu(scanres->chid), (s16) le16_to_cpu(scanres->anl), (s16) le16_to_cpu(scanres->sl), le16_to_cpu(scanres->beacon_interval), le16_to_cpu(scanres->capability), le16_to_cpu(scanres->rate), - MAC2STR(scanres->bssid), + print_mac(mac, scanres->bssid), le16_to_cpu(scanres->atim)); pos = scanres->sup_rates; diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index b3c07b93afc..2d46a16c094 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -1922,6 +1922,7 @@ static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status) u32 chan; char *txratename; u8 bssid[ETH_ALEN]; + DECLARE_MAC_BUF(mac); /* * TBD: BSSID is usually 00:00:00:00:00:00 here and not @@ -1983,9 +1984,9 @@ static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status) } IPW_DEBUG_INFO("%s: Associated with '%s' at %s, channel %d (BSSID=" - MAC_FMT ")\n", + "%s)\n", priv->net_dev->name, escape_essid(essid, essid_len), - txratename, chan, MAC_ARG(bssid)); + txratename, chan, print_mac(mac, bssid)); /* now we copy read ssid into dev */ if (!(priv->config & CFG_STATIC_ESSID)) { @@ -2053,10 +2054,12 @@ static int ipw2100_set_essid(struct ipw2100_priv *priv, char *essid, static void isr_indicate_association_lost(struct ipw2100_priv *priv, u32 status) { + DECLARE_MAC_BUF(mac); + IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, - "disassociated: '%s' " MAC_FMT " \n", + "disassociated: '%s' %s \n", escape_essid(priv->essid, priv->essid_len), - MAC_ARG(priv->bssid)); + print_mac(mac, priv->bssid)); priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING); @@ -4049,6 +4052,7 @@ static ssize_t show_bssinfo(struct device *d, struct device_attribute *attr, char *out = buf; int length; int ret; + DECLARE_MAC_BUF(mac); if (priv->status & STATUS_RF_KILL_MASK) return 0; @@ -4076,9 +4080,7 @@ static ssize_t show_bssinfo(struct device *d, struct device_attribute *attr, __LINE__); out += sprintf(out, "ESSID: %s\n", essid); - out += sprintf(out, "BSSID: %02x:%02x:%02x:%02x:%02x:%02x\n", - bssid[0], bssid[1], bssid[2], - bssid[3], bssid[4], bssid[5]); + out += sprintf(out, "BSSID: %s\n", print_mac(mac, bssid)); out += sprintf(out, "Channel: %d\n", chan); return out - buf; @@ -4652,19 +4654,20 @@ static void ipw2100_rx_free(struct ipw2100_priv *priv) static int ipw2100_read_mac_address(struct ipw2100_priv *priv) { u32 length = ETH_ALEN; - u8 mac[ETH_ALEN]; + u8 addr[ETH_ALEN]; + DECLARE_MAC_BUF(mac); int err; - err = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ADAPTER_MAC, mac, &length); + err = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ADAPTER_MAC, addr, &length); if (err) { IPW_DEBUG_INFO("MAC address read failed\n"); return -EIO; } - IPW_DEBUG_INFO("card MAC is %02X:%02X:%02X:%02X:%02X:%02X\n", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); - memcpy(priv->net_dev->dev_addr, mac, ETH_ALEN); + memcpy(priv->net_dev->dev_addr, addr, ETH_ALEN); + IPW_DEBUG_INFO("card MAC is %s\n", + print_mac(mac, priv->net_dev->dev_addr)); return 0; } @@ -5043,10 +5046,10 @@ static int ipw2100_set_mandatory_bssid(struct ipw2100_priv *priv, u8 * bssid, int err; #ifdef CONFIG_IPW2100_DEBUG + DECLARE_MAC_BUF(mac); if (bssid != NULL) - IPW_DEBUG_HC("MANDATORY_BSSID: %02X:%02X:%02X:%02X:%02X:%02X\n", - bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], - bssid[5]); + IPW_DEBUG_HC("MANDATORY_BSSID: %s\n", + print_mac(mac, bssid)); else IPW_DEBUG_HC("MANDATORY_BSSID: \n"); #endif @@ -6892,6 +6895,7 @@ static int ipw2100_wx_set_wap(struct net_device *dev, static const unsigned char off[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + DECLARE_MAC_BUF(mac); // sanity checks if (wrqu->ap_addr.sa_family != ARPHRD_ETHER) @@ -6917,13 +6921,8 @@ static int ipw2100_wx_set_wap(struct net_device *dev, err = ipw2100_set_mandatory_bssid(priv, wrqu->ap_addr.sa_data, 0); - IPW_DEBUG_WX("SET BSSID -> %02X:%02X:%02X:%02X:%02X:%02X\n", - wrqu->ap_addr.sa_data[0] & 0xff, - wrqu->ap_addr.sa_data[1] & 0xff, - wrqu->ap_addr.sa_data[2] & 0xff, - wrqu->ap_addr.sa_data[3] & 0xff, - wrqu->ap_addr.sa_data[4] & 0xff, - wrqu->ap_addr.sa_data[5] & 0xff); + IPW_DEBUG_WX("SET BSSID -> %s\n", + print_mac(mac, wrqu->ap_addr.sa_data)); done: mutex_unlock(&priv->action_mutex); @@ -6939,6 +6938,7 @@ static int ipw2100_wx_get_wap(struct net_device *dev, */ struct ipw2100_priv *priv = ieee80211_priv(dev); + DECLARE_MAC_BUF(mac); /* If we are associated, trying to associate, or have a statically * configured BSSID then return that; otherwise return ANY */ @@ -6948,8 +6948,8 @@ static int ipw2100_wx_get_wap(struct net_device *dev, } else memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN); - IPW_DEBUG_WX("Getting WAP BSSID: " MAC_FMT "\n", - MAC_ARG(wrqu->ap_addr.sa_data)); + IPW_DEBUG_WX("Getting WAP BSSID: %s\n", + print_mac(mac, wrqu->ap_addr.sa_data)); return 0; } diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index afad8bb7e33..2119a79dcc8 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -2247,8 +2247,8 @@ static int ipw_send_adapter_address(struct ipw_priv *priv, u8 * mac) return -1; } - IPW_DEBUG_INFO("%s: Setting MAC to " MAC_FMT "\n", - priv->net_dev->name, MAC_ARG(mac)); + IPW_DEBUG_INFO("%s: Setting MAC to %s\n", + priv->net_dev->name, print_mac(mac, mac)); return ipw_send_cmd_pdu(priv, IPW_CMD_ADAPTER_ADDRESS, ETH_ALEN, mac); } @@ -3796,6 +3796,7 @@ static u8 ipw_add_station(struct ipw_priv *priv, u8 * bssid) { struct ipw_station_entry entry; int i; + DECLARE_MAC_BUF(mac); for (i = 0; i < priv->num_stations; i++) { if (!memcmp(priv->stations[i], bssid, ETH_ALEN)) { @@ -3812,7 +3813,7 @@ static u8 ipw_add_station(struct ipw_priv *priv, u8 * bssid) if (i == MAX_STATIONS) return IPW_INVALID_STATION; - IPW_DEBUG_SCAN("Adding AdHoc station: " MAC_FMT "\n", MAC_ARG(bssid)); + IPW_DEBUG_SCAN("Adding AdHoc station: %s\n", print_mac(mac, bssid)); entry.reserved = 0; entry.support_mode = 0; @@ -3839,6 +3840,7 @@ static u8 ipw_find_station(struct ipw_priv *priv, u8 * bssid) static void ipw_send_disassociate(struct ipw_priv *priv, int quiet) { int err; + DECLARE_MAC_BUF(mac); if (priv->status & STATUS_ASSOCIATING) { IPW_DEBUG_ASSOC("Disassociating while associating.\n"); @@ -3851,9 +3853,9 @@ static void ipw_send_disassociate(struct ipw_priv *priv, int quiet) return; } - IPW_DEBUG_ASSOC("Disassocation attempt from " MAC_FMT " " + IPW_DEBUG_ASSOC("Disassocation attempt from %s " "on channel %d.\n", - MAC_ARG(priv->assoc_request.bssid), + print_mac(mac, priv->assoc_request.bssid), priv->assoc_request.channel); priv->status &= ~(STATUS_ASSOCIATING | STATUS_ASSOCIATED); @@ -4348,6 +4350,7 @@ static void ipw_handle_missed_beacon(struct ipw_priv *priv, static void ipw_rx_notification(struct ipw_priv *priv, struct ipw_rx_notification *notif) { + DECLARE_MAC_BUF(mac); notif->size = le16_to_cpu(notif->size); IPW_DEBUG_NOTIF("type = %i (%d bytes)\n", notif->subtype, notif->size); @@ -4360,11 +4363,11 @@ static void ipw_rx_notification(struct ipw_priv *priv, case CMAS_ASSOCIATED:{ IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, - "associated: '%s' " MAC_FMT + "associated: '%s' %s" " \n", escape_essid(priv->essid, priv->essid_len), - MAC_ARG(priv->bssid)); + print_mac(mac, priv->bssid)); switch (priv->ieee->iw_mode) { case IW_MODE_INFRA: @@ -4444,13 +4447,13 @@ static void ipw_rx_notification(struct ipw_priv *priv, IPW_DL_STATE | IPW_DL_ASSOC, "deauthenticated: '%s' " - MAC_FMT + "%s" ": (0x%04X) - %s \n", escape_essid(priv-> essid, priv-> essid_len), - MAC_ARG(priv->bssid), + print_mac(mac, priv->bssid), ntohs(auth->status), ipw_get_status_code (ntohs @@ -4467,11 +4470,11 @@ static void ipw_rx_notification(struct ipw_priv *priv, IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, - "authenticated: '%s' " MAC_FMT + "authenticated: '%s' %s" "\n", escape_essid(priv->essid, priv->essid_len), - MAC_ARG(priv->bssid)); + print_mac(mac, priv->bssid)); break; } @@ -4496,11 +4499,11 @@ static void ipw_rx_notification(struct ipw_priv *priv, IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, - "disassociated: '%s' " MAC_FMT + "disassociated: '%s' %s" " \n", escape_essid(priv->essid, priv->essid_len), - MAC_ARG(priv->bssid)); + print_mac(mac, priv->bssid)); priv->status &= ~(STATUS_DISASSOCIATING | @@ -4535,10 +4538,10 @@ static void ipw_rx_notification(struct ipw_priv *priv, switch (auth->state) { case CMAS_AUTHENTICATED: IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE, - "authenticated: '%s' " MAC_FMT " \n", + "authenticated: '%s' %s \n", escape_essid(priv->essid, priv->essid_len), - MAC_ARG(priv->bssid)); + print_mac(mac, priv->bssid)); priv->status |= STATUS_AUTH; break; @@ -4554,10 +4557,10 @@ static void ipw_rx_notification(struct ipw_priv *priv, } IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, - "deauthenticated: '%s' " MAC_FMT "\n", + "deauthenticated: '%s' %s\n", escape_essid(priv->essid, priv->essid_len), - MAC_ARG(priv->bssid)); + print_mac(mac, priv->bssid)); priv->status &= ~(STATUS_ASSOCIATING | STATUS_AUTH | @@ -5383,25 +5386,27 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, int roaming) { struct ipw_supported_rates rates; + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); /* Verify that this network's capability is compatible with the * current mode (AdHoc or Infrastructure) */ if ((priv->ieee->iw_mode == IW_MODE_ADHOC && !(network->capability & WLAN_CAPABILITY_IBSS))) { - IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded due to " + IPW_DEBUG_MERGE("Network '%s (%s)' excluded due to " "capability mismatch.\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid)); + print_mac(mac, network->bssid)); return 0; } /* If we do not have an ESSID for this AP, we can not associate with * it */ if (network->flags & NETWORK_EMPTY_ESSID) { - IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded " + IPW_DEBUG_MERGE("Network '%s (%s)' excluded " "because of hidden ESSID.\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid)); + print_mac(mac, network->bssid)); return 0; } @@ -5411,11 +5416,11 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, if ((network->ssid_len != match->network->ssid_len) || memcmp(network->ssid, match->network->ssid, network->ssid_len)) { - IPW_DEBUG_MERGE("Netowrk '%s (" MAC_FMT ")' excluded " + IPW_DEBUG_MERGE("Network '%s (%s)' excluded " "because of non-network ESSID.\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid)); + print_mac(mac, network->bssid)); return 0; } } else { @@ -5430,9 +5435,9 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, strncpy(escaped, escape_essid(network->ssid, network->ssid_len), sizeof(escaped)); - IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded " + IPW_DEBUG_MERGE("Network '%s (%s)' excluded " "because of ESSID mismatch: '%s'.\n", - escaped, MAC_ARG(network->bssid), + escaped, print_mac(mac, network->bssid), escape_essid(priv->essid, priv->essid_len)); return 0; @@ -5459,10 +5464,10 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, /* Now go through and see if the requested network is valid... */ if (priv->ieee->scan_age != 0 && time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) { - IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded " + IPW_DEBUG_MERGE("Network '%s (%s)' excluded " "because of age: %ums.\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid), + print_mac(mac, network->bssid), jiffies_to_msecs(jiffies - network->last_scanned)); return 0; @@ -5470,10 +5475,10 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, if ((priv->config & CFG_STATIC_CHANNEL) && (network->channel != priv->channel)) { - IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded " + IPW_DEBUG_MERGE("Network '%s (%s)' excluded " "because of channel mismatch: %d != %d.\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid), + print_mac(mac, network->bssid), network->channel, priv->channel); return 0; } @@ -5481,10 +5486,10 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, /* Verify privacy compatability */ if (((priv->capability & CAP_PRIVACY_ON) ? 1 : 0) != ((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) { - IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded " + IPW_DEBUG_MERGE("Network '%s (%s)' excluded " "because of privacy mismatch: %s != %s.\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid), + print_mac(mac, network->bssid), priv-> capability & CAP_PRIVACY_ON ? "on" : "off", network-> @@ -5494,40 +5499,41 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, } if (!memcmp(network->bssid, priv->bssid, ETH_ALEN)) { - IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded " - "because of the same BSSID match: " MAC_FMT + IPW_DEBUG_MERGE("Network '%s (%s)' excluded " + "because of the same BSSID match: %s" ".\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid), MAC_ARG(priv->bssid)); + print_mac(mac, network->bssid), + print_mac(mac2, priv->bssid)); return 0; } /* Filter out any incompatible freq / mode combinations */ if (!ieee80211_is_valid_mode(priv->ieee, network->mode)) { - IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded " + IPW_DEBUG_MERGE("Network '%s (%s)' excluded " "because of invalid frequency/mode " "combination.\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid)); + print_mac(mac, network->bssid)); return 0; } /* Ensure that the rates supported by the driver are compatible with * this AP, including verification of basic rates (mandatory) */ if (!ipw_compatible_rates(priv, network, &rates)) { - IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded " + IPW_DEBUG_MERGE("Network '%s (%s)' excluded " "because configured rate mask excludes " "AP mandatory rate.\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid)); + print_mac(mac, network->bssid)); return 0; } if (rates.num_rates == 0) { - IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded " + IPW_DEBUG_MERGE("Network '%s (%s)' excluded " "because of no compatible rates.\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid)); + print_mac(mac, network->bssid)); return 0; } @@ -5538,9 +5544,9 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, /* Set up 'new' AP to this network */ ipw_copy_rates(&match->rates, &rates); match->network = network; - IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' is a viable match.\n", + IPW_DEBUG_MERGE("Network '%s (%s)' is a viable match.\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid)); + print_mac(mac, network->bssid)); return 1; } @@ -5594,6 +5600,7 @@ static int ipw_best_network(struct ipw_priv *priv, struct ieee80211_network *network, int roaming) { struct ipw_supported_rates rates; + DECLARE_MAC_BUF(mac); /* Verify that this network's capability is compatible with the * current mode (AdHoc or Infrastructure) */ @@ -5601,20 +5608,20 @@ static int ipw_best_network(struct ipw_priv *priv, !(network->capability & WLAN_CAPABILITY_ESS)) || (priv->ieee->iw_mode == IW_MODE_ADHOC && !(network->capability & WLAN_CAPABILITY_IBSS))) { - IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded due to " + IPW_DEBUG_ASSOC("Network '%s (%s)' excluded due to " "capability mismatch.\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid)); + print_mac(mac, network->bssid)); return 0; } /* If we do not have an ESSID for this AP, we can not associate with * it */ if (network->flags & NETWORK_EMPTY_ESSID) { - IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " + IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " "because of hidden ESSID.\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid)); + print_mac(mac, network->bssid)); return 0; } @@ -5624,11 +5631,11 @@ static int ipw_best_network(struct ipw_priv *priv, if ((network->ssid_len != match->network->ssid_len) || memcmp(network->ssid, match->network->ssid, network->ssid_len)) { - IPW_DEBUG_ASSOC("Netowrk '%s (" MAC_FMT ")' excluded " + IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " "because of non-network ESSID.\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid)); + print_mac(mac, network->bssid)); return 0; } } else { @@ -5642,9 +5649,9 @@ static int ipw_best_network(struct ipw_priv *priv, strncpy(escaped, escape_essid(network->ssid, network->ssid_len), sizeof(escaped)); - IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " + IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " "because of ESSID mismatch: '%s'.\n", - escaped, MAC_ARG(network->bssid), + escaped, print_mac(mac, network->bssid), escape_essid(priv->essid, priv->essid_len)); return 0; @@ -5658,12 +5665,12 @@ static int ipw_best_network(struct ipw_priv *priv, strncpy(escaped, escape_essid(network->ssid, network->ssid_len), sizeof(escaped)); - IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded because " - "'%s (" MAC_FMT ")' has a stronger signal.\n", - escaped, MAC_ARG(network->bssid), + IPW_DEBUG_ASSOC("Network '%s (%s)' excluded because " + "'%s (%s)' has a stronger signal.\n", + escaped, print_mac(mac, network->bssid), escape_essid(match->network->ssid, match->network->ssid_len), - MAC_ARG(match->network->bssid)); + print_mac(mac, match->network->bssid)); return 0; } @@ -5671,11 +5678,11 @@ static int ipw_best_network(struct ipw_priv *priv, * last 3 seconds, do not try and associate again... */ if (network->last_associate && time_after(network->last_associate + (HZ * 3UL), jiffies)) { - IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " + IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " "because of storming (%ums since last " "assoc attempt).\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid), + print_mac(mac, network->bssid), jiffies_to_msecs(jiffies - network->last_associate)); return 0; @@ -5684,10 +5691,10 @@ static int ipw_best_network(struct ipw_priv *priv, /* Now go through and see if the requested network is valid... */ if (priv->ieee->scan_age != 0 && time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) { - IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " + IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " "because of age: %ums.\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid), + print_mac(mac, network->bssid), jiffies_to_msecs(jiffies - network->last_scanned)); return 0; @@ -5695,10 +5702,10 @@ static int ipw_best_network(struct ipw_priv *priv, if ((priv->config & CFG_STATIC_CHANNEL) && (network->channel != priv->channel)) { - IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " + IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " "because of channel mismatch: %d != %d.\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid), + print_mac(mac, network->bssid), network->channel, priv->channel); return 0; } @@ -5706,10 +5713,10 @@ static int ipw_best_network(struct ipw_priv *priv, /* Verify privacy compatability */ if (((priv->capability & CAP_PRIVACY_ON) ? 1 : 0) != ((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) { - IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " + IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " "because of privacy mismatch: %s != %s.\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid), + print_mac(mac, network->bssid), priv->capability & CAP_PRIVACY_ON ? "on" : "off", network->capability & @@ -5719,48 +5726,48 @@ static int ipw_best_network(struct ipw_priv *priv, if ((priv->config & CFG_STATIC_BSSID) && memcmp(network->bssid, priv->bssid, ETH_ALEN)) { - IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " - "because of BSSID mismatch: " MAC_FMT ".\n", + IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " + "because of BSSID mismatch: %s.\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid), MAC_ARG(priv->bssid)); + print_mac(mac, network->bssid), print_mac(mac, priv->bssid)); return 0; } /* Filter out any incompatible freq / mode combinations */ if (!ieee80211_is_valid_mode(priv->ieee, network->mode)) { - IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " + IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " "because of invalid frequency/mode " "combination.\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid)); + print_mac(mac, network->bssid)); return 0; } /* Filter out invalid channel in current GEO */ if (!ieee80211_is_valid_channel(priv->ieee, network->channel)) { - IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " + IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " "because of invalid channel in current GEO\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid)); + print_mac(mac, network->bssid)); return 0; } /* Ensure that the rates supported by the driver are compatible with * this AP, including verification of basic rates (mandatory) */ if (!ipw_compatible_rates(priv, network, &rates)) { - IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " + IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " "because configured rate mask excludes " "AP mandatory rate.\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid)); + print_mac(mac, network->bssid)); return 0; } if (rates.num_rates == 0) { - IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " + IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " "because of no compatible rates.\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid)); + print_mac(mac, network->bssid)); return 0; } @@ -5772,9 +5779,9 @@ static int ipw_best_network(struct ipw_priv *priv, ipw_copy_rates(&match->rates, &rates); match->network = network; - IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' is a viable match.\n", + IPW_DEBUG_ASSOC("Network '%s (%s)' is a viable match.\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid)); + print_mac(mac, network->bssid)); return 1; } @@ -6016,6 +6023,7 @@ static void ipw_bg_adhoc_check(struct work_struct *work) static void ipw_debug_config(struct ipw_priv *priv) { + DECLARE_MAC_BUF(mac); IPW_DEBUG_INFO("Scan completed, no valid APs matched " "[CFG 0x%08X]\n", priv->config); if (priv->config & CFG_STATIC_CHANNEL) @@ -6028,8 +6036,8 @@ static void ipw_debug_config(struct ipw_priv *priv) else IPW_DEBUG_INFO("ESSID unlocked.\n"); if (priv->config & CFG_STATIC_BSSID) - IPW_DEBUG_INFO("BSSID locked to " MAC_FMT "\n", - MAC_ARG(priv->bssid)); + IPW_DEBUG_INFO("BSSID locked to %s\n", + print_mac(mac, priv->bssid)); else IPW_DEBUG_INFO("BSSID unlocked.\n"); if (priv->capability & CAP_PRIVACY_ON) @@ -7221,6 +7229,7 @@ static int ipw_associate_network(struct ipw_priv *priv, struct ipw_supported_rates *rates, int roaming) { int err; + DECLARE_MAC_BUF(mac); if (priv->config & CFG_FIXED_RATE) ipw_set_fixed_rate(priv, network->mode); @@ -7388,9 +7397,9 @@ static int ipw_associate_network(struct ipw_priv *priv, return err; } - IPW_DEBUG(IPW_DL_STATE, "associating: '%s' " MAC_FMT " \n", + IPW_DEBUG(IPW_DL_STATE, "associating: '%s' %s \n", escape_essid(priv->essid, priv->essid_len), - MAC_ARG(priv->bssid)); + print_mac(mac, priv->bssid)); return 0; } @@ -8202,6 +8211,9 @@ static void ipw_rx(struct ipw_priv *priv) struct ieee80211_hdr_4addr *header; u32 r, w, i; u8 network_packet; + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); + DECLARE_MAC_BUF(mac3); r = ipw_read32(priv, IPW_RX_READ_INDEX); w = ipw_read32(priv, IPW_RX_WRITE_INDEX); @@ -8328,14 +8340,17 @@ static void ipw_rx(struct ipw_priv *priv) header))) { IPW_DEBUG_DROP("Dropping: " - MAC_FMT ", " - MAC_FMT ", " - MAC_FMT "\n", - MAC_ARG(header-> + "%s, " + "%s, " + "%s\n", + print_mac(mac, + header-> addr1), - MAC_ARG(header-> + print_mac(mac2, + header-> addr2), - MAC_ARG(header-> + print_mac(mac3, + header-> addr3)); break; } @@ -8867,6 +8882,7 @@ static int ipw_wx_set_wap(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); + DECLARE_MAC_BUF(mac); static const unsigned char any[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff @@ -8897,8 +8913,8 @@ static int ipw_wx_set_wap(struct net_device *dev, return 0; } - IPW_DEBUG_WX("Setting mandatory BSSID to " MAC_FMT "\n", - MAC_ARG(wrqu->ap_addr.sa_data)); + IPW_DEBUG_WX("Setting mandatory BSSID to %s\n", + print_mac(mac, wrqu->ap_addr.sa_data)); memcpy(priv->bssid, wrqu->ap_addr.sa_data, ETH_ALEN); @@ -8916,6 +8932,8 @@ static int ipw_wx_get_wap(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); + DECLARE_MAC_BUF(mac); + /* If we are associated, trying to associate, or have a statically * configured BSSID then return that; otherwise return ANY */ mutex_lock(&priv->mutex); @@ -8926,8 +8944,8 @@ static int ipw_wx_get_wap(struct net_device *dev, } else memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN); - IPW_DEBUG_WX("Getting WAP BSSID: " MAC_FMT "\n", - MAC_ARG(wrqu->ap_addr.sa_data)); + IPW_DEBUG_WX("Getting WAP BSSID: %s\n", + print_mac(mac, wrqu->ap_addr.sa_data)); mutex_unlock(&priv->mutex); return 0; } @@ -10133,6 +10151,7 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, u8 id, hdr_len, unicast; u16 remaining_bytes; int fc; + DECLARE_MAC_BUF(mac); hdr_len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); switch (priv->ieee->iw_mode) { @@ -10143,8 +10162,8 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, id = ipw_add_station(priv, hdr->addr1); if (id == IPW_INVALID_STATION) { IPW_WARNING("Attempt to send data to " - "invalid cell: " MAC_FMT "\n", - MAC_ARG(hdr->addr1)); + "invalid cell: %s\n", + print_mac(mac, hdr->addr1)); goto drop; } } @@ -10460,13 +10479,15 @@ static int ipw_net_set_mac_address(struct net_device *dev, void *p) { struct ipw_priv *priv = ieee80211_priv(dev); struct sockaddr *addr = p; + DECLARE_MAC_BUF(mac); + if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; mutex_lock(&priv->mutex); priv->config |= CFG_CUSTOM_MAC; memcpy(priv->mac_addr, addr->sa_data, ETH_ALEN); - printk(KERN_INFO "%s: Setting MAC to " MAC_FMT "\n", - priv->net_dev->name, MAC_ARG(priv->mac_addr)); + printk(KERN_INFO "%s: Setting MAC to %s\n", + priv->net_dev->name, print_mac(mac, priv->mac_addr)); queue_work(priv->workqueue, &priv->adapter_restart); mutex_unlock(&priv->mutex); return 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index a4f4c8798a8..b0d28ae0b32 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -646,6 +646,7 @@ static struct ieee80211_rate *rs_get_rate(void *priv_rate, struct sta_info *sta; u16 fc, rate_mask; struct iwl_priv *priv = (struct iwl_priv *)priv_rate; + DECLARE_MAC_BUF(mac); IWL_DEBUG_RATE("enter\n"); @@ -681,8 +682,8 @@ static struct ieee80211_rate *rs_get_rate(void *priv_rate, u8 sta_id = iwl_hw_find_station(priv, hdr->addr1); if (sta_id == IWL_INVALID_STATION) { - IWL_DEBUG_RATE("LQ: ADD station " MAC_FMT "\n", - MAC_ARG(hdr->addr1)); + IWL_DEBUG_RATE("LQ: ADD station %s\n", + print_mac(mac, hdr->addr1)); sta_id = iwl_add_station(priv, hdr->addr1, 0, CMD_ASYNC); } diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 26f03a0b878..55f7d89aad8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -457,13 +457,16 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv, } case IEEE80211_STYPE_PROBE_REQ:{ + DECLARE_MAC_BUF(mac1); + DECLARE_MAC_BUF(mac2); + DECLARE_MAC_BUF(mac3); if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) IWL_DEBUG_DROP - ("Dropping (non network): " MAC_FMT - ", " MAC_FMT ", " MAC_FMT "\n", - MAC_ARG(header->addr1), - MAC_ARG(header->addr2), - MAC_ARG(header->addr3)); + ("Dropping (non network): %s" + ", %s, %s\n", + print_mac(mac1, header->addr1), + print_mac(mac2, header->addr2), + print_mac(mac3, header->addr3)); return; } } @@ -474,18 +477,22 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv, case IEEE80211_FTYPE_CTL: break; - case IEEE80211_FTYPE_DATA: + case IEEE80211_FTYPE_DATA: { + DECLARE_MAC_BUF(mac1); + DECLARE_MAC_BUF(mac2); + DECLARE_MAC_BUF(mac3); + if (unlikely(is_duplicate_packet(priv, header))) - IWL_DEBUG_DROP("Dropping (dup): " MAC_FMT ", " - MAC_FMT ", " MAC_FMT "\n", - MAC_ARG(header->addr1), - MAC_ARG(header->addr2), - MAC_ARG(header->addr3)); + IWL_DEBUG_DROP("Dropping (dup): %s, %s, %s\n", + print_mac(mac1, header->addr1), + print_mac(mac2, header->addr2), + print_mac(mac3, header->addr3)); else iwl3945_handle_data_packet(priv, 1, rxb, &stats, phy_flags); break; } + } } int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr, @@ -563,6 +570,7 @@ u8 iwl_hw_find_station(struct iwl_priv *priv, const u8 *addr) int i; int ret = IWL_INVALID_STATION; unsigned long flags; + DECLARE_MAC_BUF(mac); spin_lock_irqsave(&priv->sta_lock, flags); for (i = IWL_STA_ID; i < priv->hw_setting.max_stations; i++) @@ -573,8 +581,8 @@ u8 iwl_hw_find_station(struct iwl_priv *priv, const u8 *addr) goto out; } - IWL_DEBUG_INFO("can not find STA " MAC_FMT " (total %d)\n", - MAC_ARG(addr), priv->num_stations); + IWL_DEBUG_INFO("can not find STA %s (total %d)\n", + print_mac(mac, addr), priv->num_stations); out: spin_unlock_irqrestore(&priv->sta_lock, flags); return ret; diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index f3638607d64..7b74481f528 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -1737,10 +1737,11 @@ static struct ieee80211_rate *rs_get_rate(void *priv_rate, if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && !lq->ibss_sta_added) { u8 sta_id = iwl_hw_find_station(priv, hdr->addr1); + DECLARE_MAC_BUF(mac); if (sta_id == IWL_INVALID_STATION) { - IWL_DEBUG_RATE("LQ: ADD station " MAC_FMT "\n", - MAC_ARG(hdr->addr1)); + IWL_DEBUG_RATE("LQ: ADD station %s\n", + print_mac(mac, hdr->addr1)); sta_id = iwl_add_station(priv, hdr->addr1, 0, CMD_ASYNC); } @@ -1811,14 +1812,16 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, crl->ibss_sta_added = 0; if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { u8 sta_id = iwl_hw_find_station(priv, sta->addr); + DECLARE_MAC_BUF(mac); + /* for IBSS the call are from tasklet */ - IWL_DEBUG_HT("LQ: ADD station " MAC_FMT " \n", - MAC_ARG(sta->addr)); + IWL_DEBUG_HT("LQ: ADD station %s\n", + print_mac(mac, sta->addr)); if (sta_id == IWL_INVALID_STATION) { - IWL_DEBUG_RATE("LQ: ADD station " MAC_FMT "\n", - MAC_ARG(sta->addr)); - sta_id = iwl_add_station(priv, + IWL_DEBUG_RATE("LQ: ADD station %s\n", + print_mac(mac, sta->addr)); + sta_id = iwl_add_station(priv, sta->addr, 0, CMD_ASYNC); } if ((sta_id != IWL_INVALID_STATION)) { diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index ba35b3ac7c7..e624f2a41e0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -164,6 +164,7 @@ u8 iwl_hw_find_station(struct iwl_priv *priv, const u8 *addr) int start = 0; int ret = IWL_INVALID_STATION; unsigned long flags; + DECLARE_MAC_BUF(mac); if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) || (priv->iw_mode == IEEE80211_IF_TYPE_AP)) @@ -181,8 +182,8 @@ u8 iwl_hw_find_station(struct iwl_priv *priv, const u8 *addr) goto out; } - IWL_DEBUG_ASSOC("can not find STA " MAC_FMT " total %d\n", - MAC_ARG(addr), priv->num_stations); + IWL_DEBUG_ASSOC("can not find STA %s total %d\n", + print_mac(mac, addr), priv->num_stations); out: spin_unlock_irqrestore(&priv->sta_lock, flags); @@ -3909,12 +3910,15 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv, case IEEE80211_STYPE_PROBE_REQ: if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && !iwl_is_associated(priv)) { + DECLARE_MAC_BUF(mac1); + DECLARE_MAC_BUF(mac2); + DECLARE_MAC_BUF(mac3); + IWL_DEBUG_DROP("Dropping (non network): " - MAC_FMT ", " MAC_FMT ", " - MAC_FMT "\n", - MAC_ARG(header->addr1), - MAC_ARG(header->addr2), - MAC_ARG(header->addr3)); + "%s, %s, %s\n", + print_mac(mac1, header->addr1), + print_mac(mac2, header->addr2), + print_mac(mac3, header->addr3)); return; } } @@ -3936,28 +3940,31 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv, break; - case IEEE80211_FTYPE_DATA: + case IEEE80211_FTYPE_DATA: { + DECLARE_MAC_BUF(mac1); + DECLARE_MAC_BUF(mac2); + DECLARE_MAC_BUF(mac3); + if (priv->iw_mode == IEEE80211_IF_TYPE_AP) iwl4965_update_ps_mode(priv, fc & IEEE80211_FCTL_PM, header->addr2); if (unlikely(!network_packet)) IWL_DEBUG_DROP("Dropping (non network): " - MAC_FMT ", " MAC_FMT ", " - MAC_FMT "\n", - MAC_ARG(header->addr1), - MAC_ARG(header->addr2), - MAC_ARG(header->addr3)); + "%s, %s, %s\n", + print_mac(mac1, header->addr1), + print_mac(mac2, header->addr2), + print_mac(mac3, header->addr3)); else if (unlikely(is_duplicate_packet(priv, header))) - IWL_DEBUG_DROP("Dropping (dup): " MAC_FMT ", " - MAC_FMT ", " MAC_FMT "\n", - MAC_ARG(header->addr1), - MAC_ARG(header->addr2), - MAC_ARG(header->addr3)); + IWL_DEBUG_DROP("Dropping (dup): %s, %s, %s\n", + print_mac(mac1, header->addr1), + print_mac(mac2, header->addr2), + print_mac(mac3, header->addr3)); else iwl4965_handle_data_packet(priv, 1, include_phy, rxb, &stats); break; + } default: break; @@ -4106,10 +4113,12 @@ static void iwl4965_rx_reply_compressed_ba(struct iwl_priv *priv, /* TODO: Need to get this copy more sefely - now good for debug */ /* - IWL_DEBUG_TX_REPLY("REPLY_COMPRESSED_BA [%d]Received from " MAC_FMT ", - sta_id = %d\n", + { + DECLARE_MAC_BUF(mac); + IWL_DEBUG_TX_REPLY("REPLY_COMPRESSED_BA [%d]Received from %s, " + "sta_id = %d\n", agg->wait_for_ba, - MAC_ARG((u8*) &ba_resp->sta_addr_lo32), + print_mac(mac, (u8*) &ba_resp->sta_addr_lo32), ba_resp->sta_id); IWL_DEBUG_TX_REPLY("TID = %d, SeqCtl = %d, bitmap = 0x%X%X, scd_flow = " "%d, scd_ssn = %d\n", @@ -4123,6 +4132,7 @@ static void iwl4965_rx_reply_compressed_ba(struct iwl_priv *priv, agg->start_idx, agg->bitmap1, agg->bitmap0); + } */ iwl4965_tx_status_reply_compressed_ba(priv, agg, ba_resp); /* releases all the TFDs until the SSN */ @@ -4539,14 +4549,15 @@ int iwl_mac_ht_tx_agg_start(struct ieee80211_hw *hw, u8 *da, u16 tid, int ssn = -1; unsigned long flags; struct iwl_tid_data *tid_data; + DECLARE_MAC_BUF(mac); if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo))) tx_fifo = default_tid_to_tx_fifo[tid]; else return -EINVAL; - IWL_WARNING("iwl-AGG iwl_mac_ht_tx_agg_start on da=" MAC_FMT - " tid=%d\n", MAC_ARG(da), tid); + IWL_WARNING("iwl-AGG iwl_mac_ht_tx_agg_start on da=%s" + " tid=%d\n", print_mac(mac, da), tid); sta_id = iwl_hw_find_station(priv, da); if (sta_id == IWL_INVALID_STATION) @@ -4577,6 +4588,8 @@ int iwl_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, u8 *da, u16 tid, int tx_fifo_id, txq_id, sta_id, ssn = -1; struct iwl_tid_data *tid_data; int rc; + DECLARE_MAC_BUF(mac); + if (!da) { IWL_ERROR("%s: da = NULL\n", __func__); return -EINVAL; @@ -4602,8 +4615,8 @@ int iwl_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, u8 *da, u16 tid, return rc; iwl4965_ba_status(priv, tid, BA_STATUS_INITIATOR_DELBA); - IWL_DEBUG_INFO("iwl_mac_ht_tx_agg_stop on da=" MAC_FMT " tid=%d\n", - MAC_ARG(da), tid); + IWL_DEBUG_INFO("iwl_mac_ht_tx_agg_stop on da=%s tid=%d\n", + print_mac(mac, da), tid); return 0; } @@ -4613,9 +4626,10 @@ int iwl_mac_ht_rx_agg_start(struct ieee80211_hw *hw, u8 *da, { struct iwl_priv *priv = hw->priv; int sta_id; + DECLARE_MAC_BUF(mac); - IWL_WARNING("iwl-AGG iwl_mac_ht_rx_agg_start on da=" MAC_FMT - " tid=%d\n", MAC_ARG(da), tid); + IWL_WARNING("iwl-AGG iwl_mac_ht_rx_agg_start on da=%s" + " tid=%d\n", print_mac(mac, da), tid); sta_id = iwl_hw_find_station(priv, da); iwl4965_sta_modify_add_ba_tid(priv, sta_id, tid, start_seq_num); return 0; @@ -4626,9 +4640,10 @@ int iwl_mac_ht_rx_agg_stop(struct ieee80211_hw *hw, u8 *da, { struct iwl_priv *priv = hw->priv; int sta_id; + DECLARE_MAC_BUF(mac); - IWL_WARNING("iwl-AGG iwl_mac_ht_rx_agg_stop on da=" MAC_FMT " tid=%d\n", - MAC_ARG(da), tid); + IWL_WARNING("iwl-AGG iwl_mac_ht_rx_agg_stop on da=%s tid=%d\n", + print_mac(mac, da), tid); sta_id = iwl_hw_find_station(priv, da); iwl4965_sta_modify_del_ba_tid(priv, sta_id, tid); return 0; diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 474b6402040..cc405f4a864 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -460,6 +460,7 @@ u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags) int index = IWL_INVALID_STATION; struct iwl_station_entry *station; unsigned long flags_spin; + DECLARE_MAC_BUF(mac); spin_lock_irqsave(&priv->sta_lock, flags_spin); if (is_ap) @@ -492,7 +493,7 @@ u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags) return index; } - IWL_DEBUG_ASSOC("Add STA ID %d: " MAC_FMT "\n", index, MAC_ARG(addr)); + IWL_DEBUG_ASSOC("Add STA ID %d: %s\n", index, print_mac(mac, addr)); station = &priv->stations[index]; station->used = 1; priv->num_stations++; @@ -1064,6 +1065,7 @@ static int iwl_commit_rxon(struct iwl_priv *priv) /* cast away the const for active_rxon in this function */ struct iwl_rxon_cmd *active_rxon = (void *)&priv->active_rxon; int rc = 0; + DECLARE_MAC_BUF(mac); if (!iwl_is_alive(priv)) return -1; @@ -1134,11 +1136,11 @@ static int iwl_commit_rxon(struct iwl_priv *priv) IWL_DEBUG_INFO("Sending RXON\n" "* with%s RXON_FILTER_ASSOC_MSK\n" "* channel = %d\n" - "* bssid = " MAC_FMT "\n", + "* bssid = %s\n", ((priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ? "" : "out"), le16_to_cpu(priv->staging_rxon.channel), - MAC_ARG(priv->staging_rxon.bssid_addr)); + print_mac(mac, priv->staging_rxon.bssid_addr)); /* Apply the new configuration */ rc = iwl_send_cmd_pdu(priv, REPLY_RXON, @@ -2693,7 +2695,9 @@ static int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) /* If this frame is part of a IBSS network, then we use the * target specific station id */ - case IEEE80211_IF_TYPE_IBSS: + case IEEE80211_IF_TYPE_IBSS: { + DECLARE_MAC_BUF(mac); + sta_id = iwl_hw_find_station(priv, hdr->addr1); if (sta_id != IWL_INVALID_STATION) return sta_id; @@ -2703,12 +2707,12 @@ static int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) if (sta_id != IWL_INVALID_STATION) return sta_id; - IWL_DEBUG_DROP("Station " MAC_FMT " not in station map. " + IWL_DEBUG_DROP("Station %s not in station map. " "Defaulting to broadcast...\n", - MAC_ARG(hdr->addr1)); + print_mac(mac, hdr->addr1)); iwl_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); return priv->hw_setting.bcast_sta_id; - + } default: IWL_WARNING("Unkown mode of operation: %d", priv->iw_mode); return priv->hw_setting.bcast_sta_id; @@ -2781,8 +2785,10 @@ static int iwl_tx_skb(struct iwl_priv *priv, hdr_len = ieee80211_get_hdrlen(fc); sta_id = iwl_get_sta_id(priv, hdr); if (sta_id == IWL_INVALID_STATION) { - IWL_DEBUG_DROP("Dropping - INVALID STATION: " MAC_FMT "\n", - MAC_ARG(hdr->addr1)); + DECLARE_MAC_BUF(mac); + + IWL_DEBUG_DROP("Dropping - INVALID STATION: %s\n", + print_mac(mac, hdr->addr1)); goto drop; } @@ -4385,6 +4391,8 @@ int iwl_tx_queue_update_write_ptr(struct iwl_priv *priv, #ifdef CONFIG_IWLWIFI_DEBUG static void iwl_print_rx_config_cmd(struct iwl_rxon_cmd *rxon) { + DECLARE_MAC_BUF(mac); + IWL_DEBUG_RADIO("RX CONFIG:\n"); iwl_print_hex_dump(IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon)); IWL_DEBUG_RADIO("u16 channel: 0x%x\n", le16_to_cpu(rxon->channel)); @@ -4395,10 +4403,10 @@ static void iwl_print_rx_config_cmd(struct iwl_rxon_cmd *rxon) IWL_DEBUG_RADIO("u8 ofdm_basic_rates: 0x%02x\n", rxon->ofdm_basic_rates); IWL_DEBUG_RADIO("u8 cck_basic_rates: 0x%02x\n", rxon->cck_basic_rates); - IWL_DEBUG_RADIO("u8[6] node_addr: " MAC_FMT "\n", - MAC_ARG(rxon->node_addr)); - IWL_DEBUG_RADIO("u8[6] bssid_addr: " MAC_FMT "\n", - MAC_ARG(rxon->bssid_addr)); + IWL_DEBUG_RADIO("u8[6] node_addr: %s\n", + print_mac(mac, rxon->node_addr)); + IWL_DEBUG_RADIO("u8[6] bssid_addr: %s\n", + print_mac(mac, rxon->bssid_addr)); IWL_DEBUG_RADIO("u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id)); } #endif @@ -6322,6 +6330,7 @@ static void iwl_down(struct iwl_priv *priv) static int __iwl_up(struct iwl_priv *priv) { + DECLARE_MAC_BUF(mac); int rc, i; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { @@ -6381,8 +6390,8 @@ static int __iwl_up(struct iwl_priv *priv) /* MAC Address location in EEPROM same for 3945/4965 */ get_eeprom_mac(priv, priv->mac_addr); - IWL_DEBUG_INFO("MAC address: " MAC_FMT "\n", - MAC_ARG(priv->mac_addr)); + IWL_DEBUG_INFO("MAC address: %s\n", + print_mac(mac, priv->mac_addr)); SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr); @@ -6728,6 +6737,7 @@ static void iwl_bg_post_associate(struct work_struct *data) int rc = 0; struct ieee80211_conf *conf = NULL; + DECLARE_MAC_BUF(mac); if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { IWL_ERROR("%s Should not be called in AP mode\n", __FUNCTION__); @@ -6735,8 +6745,9 @@ static void iwl_bg_post_associate(struct work_struct *data) } - IWL_DEBUG_ASSOC("Associated as %d to: " MAC_FMT "\n", - priv->assoc_id, MAC_ARG(priv->active_rxon.bssid_addr)); + IWL_DEBUG_ASSOC("Associated as %d to: %s\n", + priv->assoc_id, + print_mac(mac, priv->active_rxon.bssid_addr)); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; @@ -6916,11 +6927,12 @@ static int iwl_mac_add_interface(struct ieee80211_hw *hw, { struct iwl_priv *priv = hw->priv; unsigned long flags; + DECLARE_MAC_BUF(mac); IWL_DEBUG_MAC80211("enter: id %d, type %d\n", conf->if_id, conf->type); if (conf->mac_addr) - IWL_DEBUG_MAC80211("enter: MAC " MAC_FMT "\n", - MAC_ARG(conf->mac_addr)); + IWL_DEBUG_MAC80211("enter: MAC %s\n", + print_mac(mac, conf->mac_addr)); if (priv->interface_id) { IWL_DEBUG_MAC80211("leave - interface_id != 0\n"); @@ -7094,6 +7106,7 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id, struct ieee80211_if_conf *conf) { struct iwl_priv *priv = hw->priv; + DECLARE_MAC_BUF(mac); unsigned long flags; int rc; @@ -7111,8 +7124,8 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id, IWL_DEBUG_MAC80211("enter: interface id %d\n", if_id); if (conf->bssid) - IWL_DEBUG_MAC80211("bssid: " MAC_FMT "\n", - MAC_ARG(conf->bssid)); + IWL_DEBUG_MAC80211("bssid: %s\n", + print_mac(mac, conf->bssid)); if (unlikely(test_bit(STATUS_SCANNING, &priv->status)) && !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) { @@ -7131,8 +7144,8 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id, if (!conf->bssid) { conf->bssid = priv->mac_addr; memcpy(priv->bssid, priv->mac_addr, ETH_ALEN); - IWL_DEBUG_MAC80211("bssid was set to: " MAC_FMT "\n", - MAC_ARG(conf->bssid)); + IWL_DEBUG_MAC80211("bssid was set to: %s\n", + print_mac(mac, conf->bssid)); } if (priv->ibss_beacon) dev_kfree_skb(priv->ibss_beacon); @@ -7282,8 +7295,10 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, set_key_cmd cmd, sta_id = iwl_hw_find_station(priv, addr); if (sta_id == IWL_INVALID_STATION) { - IWL_DEBUG_MAC80211("leave - " MAC_FMT " not in station map.\n", - MAC_ARG(addr)); + DECLARE_MAC_BUF(mac); + + IWL_DEBUG_MAC80211("leave - %s not in station map.\n", + print_mac(mac, addr)); return -EINVAL; } diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index b79dabc8c01..6cea3118b7c 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -459,6 +459,7 @@ u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags) int index = IWL_INVALID_STATION; struct iwl_station_entry *station; unsigned long flags_spin; + DECLARE_MAC_BUF(mac); spin_lock_irqsave(&priv->sta_lock, flags_spin); if (is_ap) @@ -493,7 +494,7 @@ u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags) } - IWL_DEBUG_ASSOC("Add STA ID %d: " MAC_FMT "\n", index, MAC_ARG(addr)); + IWL_DEBUG_ASSOC("Add STA ID %d: %s\n", index, print_mac(mac, addr)); station = &priv->stations[index]; station->used = 1; priv->num_stations++; @@ -1083,6 +1084,7 @@ static int iwl_commit_rxon(struct iwl_priv *priv) { /* cast away the const for active_rxon in this function */ struct iwl_rxon_cmd *active_rxon = (void *)&priv->active_rxon; + DECLARE_MAC_BUF(mac); int rc = 0; if (!iwl_is_alive(priv)) @@ -1160,11 +1162,11 @@ static int iwl_commit_rxon(struct iwl_priv *priv) IWL_DEBUG_INFO("Sending RXON\n" "* with%s RXON_FILTER_ASSOC_MSK\n" "* channel = %d\n" - "* bssid = " MAC_FMT "\n", + "* bssid = %s\n", ((priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ? "" : "out"), le16_to_cpu(priv->staging_rxon.channel), - MAC_ARG(priv->staging_rxon.bssid_addr)); + print_mac(mac, priv->staging_rxon.bssid_addr)); /* Apply the new configuration */ rc = iwl_send_cmd_pdu(priv, REPLY_RXON, @@ -2748,6 +2750,7 @@ static int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) { int sta_id; u16 fc = le16_to_cpu(hdr->frame_control); + DECLARE_MAC_BUF(mac); /* If this frame is broadcast or not data then use the broadcast * station id */ @@ -2781,9 +2784,9 @@ static int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) if (sta_id != IWL_INVALID_STATION) return sta_id; - IWL_DEBUG_DROP("Station " MAC_FMT " not in station map. " + IWL_DEBUG_DROP("Station %s not in station map. " "Defaulting to broadcast...\n", - MAC_ARG(hdr->addr1)); + print_mac(mac, hdr->addr1)); iwl_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); return priv->hw_setting.bcast_sta_id; @@ -2859,8 +2862,10 @@ static int iwl_tx_skb(struct iwl_priv *priv, hdr_len = ieee80211_get_hdrlen(fc); sta_id = iwl_get_sta_id(priv, hdr); if (sta_id == IWL_INVALID_STATION) { - IWL_DEBUG_DROP("Dropping - INVALID STATION: " MAC_FMT "\n", - MAC_ARG(hdr->addr1)); + DECLARE_MAC_BUF(mac); + + IWL_DEBUG_DROP("Dropping - INVALID STATION: %s\n", + print_mac(mac, hdr->addr1)); goto drop; } @@ -4703,6 +4708,8 @@ int iwl_tx_queue_update_write_ptr(struct iwl_priv *priv, #ifdef CONFIG_IWLWIFI_DEBUG static void iwl_print_rx_config_cmd(struct iwl_rxon_cmd *rxon) { + DECLARE_MAC_BUF(mac); + IWL_DEBUG_RADIO("RX CONFIG:\n"); iwl_print_hex_dump(IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon)); IWL_DEBUG_RADIO("u16 channel: 0x%x\n", le16_to_cpu(rxon->channel)); @@ -4713,10 +4720,10 @@ static void iwl_print_rx_config_cmd(struct iwl_rxon_cmd *rxon) IWL_DEBUG_RADIO("u8 ofdm_basic_rates: 0x%02x\n", rxon->ofdm_basic_rates); IWL_DEBUG_RADIO("u8 cck_basic_rates: 0x%02x\n", rxon->cck_basic_rates); - IWL_DEBUG_RADIO("u8[6] node_addr: " MAC_FMT "\n", - MAC_ARG(rxon->node_addr)); - IWL_DEBUG_RADIO("u8[6] bssid_addr: " MAC_FMT "\n", - MAC_ARG(rxon->bssid_addr)); + IWL_DEBUG_RADIO("u8[6] node_addr: %s\n", + print_mac(mac, rxon->node_addr)); + IWL_DEBUG_RADIO("u8[6] bssid_addr: %s\n", + print_mac(mac, rxon->bssid_addr)); IWL_DEBUG_RADIO("u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id)); } #endif @@ -6670,6 +6677,7 @@ static void iwl_down(struct iwl_priv *priv) static int __iwl_up(struct iwl_priv *priv) { + DECLARE_MAC_BUF(mac); int rc, i; u32 hw_rf_kill = 0; @@ -6742,8 +6750,8 @@ static int __iwl_up(struct iwl_priv *priv) /* MAC Address location in EEPROM same for 3945/4965 */ get_eeprom_mac(priv, priv->mac_addr); - IWL_DEBUG_INFO("MAC address: " MAC_FMT "\n", - MAC_ARG(priv->mac_addr)); + IWL_DEBUG_INFO("MAC address: %s\n", + print_mac(mac, priv->mac_addr)); SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr); @@ -7096,14 +7104,16 @@ static void iwl_bg_post_associate(struct work_struct *data) int rc = 0; struct ieee80211_conf *conf = NULL; + DECLARE_MAC_BUF(mac); if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { IWL_ERROR("%s Should not be called in AP mode\n", __FUNCTION__); return; } - IWL_DEBUG_ASSOC("Associated as %d to: " MAC_FMT "\n", - priv->assoc_id, MAC_ARG(priv->active_rxon.bssid_addr)); + IWL_DEBUG_ASSOC("Associated as %d to: %s\n", + priv->assoc_id, + print_mac(mac, priv->active_rxon.bssid_addr)); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) @@ -7299,11 +7309,12 @@ static int iwl_mac_add_interface(struct ieee80211_hw *hw, { struct iwl_priv *priv = hw->priv; unsigned long flags; + DECLARE_MAC_BUF(mac); IWL_DEBUG_MAC80211("enter: id %d, type %d\n", conf->if_id, conf->type); if (conf->mac_addr) - IWL_DEBUG_MAC80211("enter: MAC " MAC_FMT "\n", - MAC_ARG(conf->mac_addr)); + IWL_DEBUG_MAC80211("enter: MAC %s\n", + print_mac(mac, conf->mac_addr)); if (priv->interface_id) { IWL_DEBUG_MAC80211("leave - interface_id != 0\n"); @@ -7494,6 +7505,7 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id, struct ieee80211_if_conf *conf) { struct iwl_priv *priv = hw->priv; + DECLARE_MAC_BUF(mac); unsigned long flags; int rc; @@ -7511,8 +7523,8 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id, IWL_DEBUG_MAC80211("enter: interface id %d\n", if_id); if (conf->bssid) - IWL_DEBUG_MAC80211("bssid: " MAC_FMT "\n", - MAC_ARG(conf->bssid)); + IWL_DEBUG_MAC80211("bssid: %s\n", + print_mac(mac, conf->bssid)); if (unlikely(test_bit(STATUS_SCANNING, &priv->status)) && !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) { @@ -7531,8 +7543,8 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id, if (!conf->bssid) { conf->bssid = priv->mac_addr; memcpy(priv->bssid, priv->mac_addr, ETH_ALEN); - IWL_DEBUG_MAC80211("bssid was set to: " MAC_FMT "\n", - MAC_ARG(conf->bssid)); + IWL_DEBUG_MAC80211("bssid was set to: %s\n", + print_mac(mac, conf->bssid)); } if (priv->ibss_beacon) dev_kfree_skb(priv->ibss_beacon); @@ -7666,6 +7678,7 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, set_key_cmd cmd, struct ieee80211_key_conf *key) { struct iwl_priv *priv = hw->priv; + DECLARE_MAC_BUF(mac); int rc = 0; u8 sta_id; @@ -7682,8 +7695,8 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, set_key_cmd cmd, sta_id = iwl_hw_find_station(priv, addr); if (sta_id == IWL_INVALID_STATION) { - IWL_DEBUG_MAC80211("leave - " MAC_FMT " not in station map.\n", - MAC_ARG(addr)); + IWL_DEBUG_MAC80211("leave - %s not in station map.\n", + print_mac(mac, addr)); return -EINVAL; } diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index 3131afcf459..2c6ddb1f007 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -16,6 +16,7 @@ static const u8 bssid_off[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; static void print_assoc_req(const char * extra, struct assoc_request * assoc_req) { + DECLARE_MAC_BUF(mac); lbs_deb_assoc( "#### Association Request: %s\n" " flags: 0x%08lX\n" @@ -23,13 +24,13 @@ static void print_assoc_req(const char * extra, struct assoc_request * assoc_req " channel: %d\n" " band: %d\n" " mode: %d\n" - " BSSID: " MAC_FMT "\n" + " BSSID: %s\n" " Encryption:%s%s%s\n" " auth: %d\n", extra, assoc_req->flags, escape_essid(assoc_req->ssid, assoc_req->ssid_len), assoc_req->channel, assoc_req->band, assoc_req->mode, - MAC_ARG(assoc_req->bssid), + print_mac(mac, assoc_req->bssid), assoc_req->secinfo.WPAenabled ? " WPA" : "", assoc_req->secinfo.WPA2enabled ? " WPA2" : "", assoc_req->secinfo.wep_enabled ? " WEP" : "", @@ -104,16 +105,17 @@ static int assoc_helper_bssid(wlan_private *priv, wlan_adapter *adapter = priv->adapter; int ret = 0; struct bss_descriptor * bss; + DECLARE_MAC_BUF(mac); - lbs_deb_enter_args(LBS_DEB_ASSOC, "BSSID " MAC_FMT, - MAC_ARG(assoc_req->bssid)); + lbs_deb_enter_args(LBS_DEB_ASSOC, "BSSID %s", + print_mac(mac, assoc_req->bssid)); /* Search for index position in list for requested MAC */ bss = libertas_find_bssid_in_list(adapter, assoc_req->bssid, assoc_req->mode); if (bss == NULL) { - lbs_deb_assoc("ASSOC: WAP: BSSID " MAC_FMT " not found, " - "cannot associate.\n", MAC_ARG(assoc_req->bssid)); + lbs_deb_assoc("ASSOC: WAP: BSSID %s not found, " + "cannot associate.\n", print_mac(mac, assoc_req->bssid)); goto out; } @@ -481,6 +483,7 @@ void libertas_association_worker(struct work_struct *work) struct assoc_request * assoc_req = NULL; int ret = 0; int find_any_ssid = 0; + DECLARE_MAC_BUF(mac); lbs_deb_enter(LBS_DEB_ASSOC); @@ -629,10 +632,10 @@ void libertas_association_worker(struct work_struct *work) if (success) { lbs_deb_assoc("ASSOC: association attempt successful. " - "Associated to '%s' (" MAC_FMT ")\n", + "Associated to '%s' (%s)\n", escape_essid(adapter->curbssparams.ssid, adapter->curbssparams.ssid_len), - MAC_ARG(adapter->curbssparams.bssid)); + print_mac(mac, adapter->curbssparams.bssid)); libertas_prepare_and_send_command(priv, CMD_802_11_RSSI, 0, CMD_OPTION_WAITFORRSP, 0, NULL); diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index d64ad87db45..fe70e30b1f3 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -159,6 +159,7 @@ static int wlan_ret_get_hw_spec(wlan_private * priv, struct cmd_ds_get_hw_spec *hwspec = &resp->params.hwspec; wlan_adapter *adapter = priv->adapter; int ret = 0; + DECLARE_MAC_BUF(mac); lbs_deb_enter(LBS_DEB_CMD); @@ -169,8 +170,8 @@ static int wlan_ret_get_hw_spec(wlan_private * priv, lbs_deb_cmd("GET_HW_SPEC: firmware release %u.%u.%up%u\n", adapter->fwreleasenumber[2], adapter->fwreleasenumber[1], adapter->fwreleasenumber[0], adapter->fwreleasenumber[3]); - lbs_deb_cmd("GET_HW_SPEC: MAC addr " MAC_FMT "\n", - MAC_ARG(hwspec->permanentaddr)); + lbs_deb_cmd("GET_HW_SPEC: MAC addr %s\n", + print_mac(mac, hwspec->permanentaddr)); lbs_deb_cmd("GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x\n", hwspec->hwifversion, hwspec->version); diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c index 816f42e4f5b..cb00b080409 100644 --- a/drivers/net/wireless/libertas/debugfs.c +++ b/drivers/net/wireless/libertas/debugfs.c @@ -63,6 +63,7 @@ static ssize_t libertas_getscantable(struct file *file, char __user *userbuf, int numscansdone = 0, res; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; + DECLARE_MAC_BUF(mac); struct bss_descriptor * iter_bss; pos += snprintf(buf+pos, len-pos, @@ -75,9 +76,9 @@ static ssize_t libertas_getscantable(struct file *file, char __user *userbuf, u16 spectrum_mgmt = (iter_bss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT); pos += snprintf(buf+pos, len-pos, - "%02u| %03d | %04ld | " MAC_FMT " |", + "%02u| %03d | %04ld | %s |", numscansdone, iter_bss->channel, iter_bss->rssi, - MAC_ARG(iter_bss->bssid)); + print_mac(mac, iter_bss->bssid)); pos += snprintf(buf+pos, len-pos, " %04x-", iter_bss->capability); pos += snprintf(buf+pos, len-pos, "%c%c%c |", ibss ? 'A' : 'I', privacy ? 'P' : ' ', diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c index 0ad1362b14e..8dcff00574f 100644 --- a/drivers/net/wireless/libertas/join.c +++ b/drivers/net/wireless/libertas/join.c @@ -293,6 +293,7 @@ int libertas_cmd_80211_authenticate(wlan_private * priv, struct cmd_ds_802_11_authenticate *pauthenticate = &cmd->params.auth; int ret = -1; u8 *bssid = pdata_buf; + DECLARE_MAC_BUF(mac); lbs_deb_enter(LBS_DEB_JOIN); @@ -319,8 +320,8 @@ int libertas_cmd_80211_authenticate(wlan_private * priv, memcpy(pauthenticate->macaddr, bssid, ETH_ALEN); - lbs_deb_join("AUTH_CMD: BSSID is : " MAC_FMT " auth=0x%X\n", - MAC_ARG(bssid), pauthenticate->authtype); + lbs_deb_join("AUTH_CMD: BSSID is : %s auth=0x%X\n", + print_mac(mac, bssid), pauthenticate->authtype); ret = 0; out: @@ -598,6 +599,7 @@ int libertas_cmd_80211_ad_hoc_join(wlan_private * priv, int cmdappendsize = 0; int ret = 0; u16 ratesize = 0; + DECLARE_MAC_BUF(mac); lbs_deb_enter(LBS_DEB_JOIN); @@ -621,8 +623,9 @@ int libertas_cmd_80211_ad_hoc_join(wlan_private * priv, /* information on BSSID descriptor passed to FW */ lbs_deb_join( - "ADHOC_J_CMD: BSSID = " MAC_FMT ", SSID = '%s'\n", - MAC_ARG(join_cmd->bss.bssid), join_cmd->bss.ssid); + "ADHOC_J_CMD: BSSID = %s, SSID = '%s'\n", + print_mac(mac, join_cmd->bss.bssid), + join_cmd->bss.ssid); /* failtimeout */ join_cmd->failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT); @@ -829,6 +832,7 @@ int libertas_ret_80211_ad_hoc_start(wlan_private * priv, struct cmd_ds_802_11_ad_hoc_result *padhocresult; union iwreq_data wrqu; struct bss_descriptor *bss; + DECLARE_MAC_BUF(mac); lbs_deb_enter(LBS_DEB_JOIN); @@ -894,8 +898,8 @@ int libertas_ret_80211_ad_hoc_start(wlan_private * priv, lbs_deb_join("ADHOC_RESP: - Joined/Started Ad Hoc\n"); lbs_deb_join("ADHOC_RESP: channel = %d\n", adapter->curbssparams.channel); - lbs_deb_join("ADHOC_RESP: BSSID = " MAC_FMT "\n", - MAC_ARG(padhocresult->bssid)); + lbs_deb_join("ADHOC_RESP: BSSID = %s\n", + print_mac(mac, padhocresult->bssid)); done: lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index a54171af7b9..5ead08312e1 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -677,6 +677,7 @@ static void libertas_set_multicast_list(struct net_device *dev) wlan_private *priv = dev->priv; wlan_adapter *adapter = priv->adapter; int oldpacketfilter; + DECLARE_MAC_BUF(mac); lbs_deb_enter(LBS_DEB_NET); @@ -723,14 +724,9 @@ static void libertas_set_multicast_list(struct net_device *dev) dev->mc_count); for (i = 0; i < dev->mc_count; i++) { - lbs_deb_net("Multicast address %d:" - MAC_FMT "\n", i, - adapter->multicastlist[i][0], - adapter->multicastlist[i][1], - adapter->multicastlist[i][2], - adapter->multicastlist[i][3], - adapter->multicastlist[i][4], - adapter->multicastlist[i][5]); + lbs_deb_net("Multicast address %d:%s\n", + i, print_mac(mac, + adapter->multicastlist[i])); } /* send multicast addresses to firmware */ libertas_prepare_and_send_command(priv, diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index e2e9ebcd834..8f073ad1957 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -777,6 +777,7 @@ int wlan_scan_networks(wlan_private * priv, #ifdef CONFIG_LIBERTAS_DEBUG struct bss_descriptor * iter_bss; int i = 0; + DECLARE_MAC_BUF(mac); #endif lbs_deb_enter(LBS_DEB_SCAN); @@ -831,8 +832,8 @@ int wlan_scan_networks(wlan_private * priv, /* Dump the scan table */ mutex_lock(&adapter->lock); list_for_each_entry (iter_bss, &adapter->network_list, list) { - lbs_deb_scan("Scan:(%02d) " MAC_FMT ", RSSI[%03d], SSID[%s]\n", - i++, MAC_ARG(iter_bss->bssid), (s32) iter_bss->rssi, + lbs_deb_scan("Scan:(%02d) %s, RSSI[%03d], SSID[%s]\n", + i++, print_mac(mac, iter_bss->bssid), (s32) iter_bss->rssi, escape_essid(iter_bss->ssid, iter_bss->ssid_len)); } mutex_unlock(&adapter->lock); @@ -876,6 +877,7 @@ static int libertas_process_bss(struct bss_descriptor * bss, struct ieeetypes_dsparamset *pDS; struct ieeetypes_cfparamset *pCF; struct ieeetypes_ibssparamset *pibss; + DECLARE_MAC_BUF(mac); struct ieeetypes_countryinfoset *pcountryinfo; u8 *pos, *end, *p; u8 n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0; @@ -906,7 +908,7 @@ static int libertas_process_bss(struct bss_descriptor * bss, *bytesleft -= beaconsize; memcpy(bss->bssid, pos, ETH_ALEN); - lbs_deb_scan("process_bss: AP BSSID " MAC_FMT "\n", MAC_ARG(bss->bssid)); + lbs_deb_scan("process_bss: AP BSSID %s\n", print_mac(mac, bss->bssid)); pos += ETH_ALEN; if ((end - pos) < 12) { @@ -1724,6 +1726,7 @@ int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp) struct bss_descriptor new; struct bss_descriptor * found = NULL; struct bss_descriptor * oldest = NULL; + DECLARE_MAC_BUF(mac); /* Process the data fields and IEs returned for this BSS */ memset(&new, 0, sizeof (struct bss_descriptor)); @@ -1762,9 +1765,8 @@ int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp) continue; } - lbs_deb_scan("SCAN_RESP: BSSID = " MAC_FMT "\n", - new.bssid[0], new.bssid[1], new.bssid[2], - new.bssid[3], new.bssid[4], new.bssid[5]); + lbs_deb_scan("SCAN_RESP: BSSID = %s\n", + print_mac(mac, new.bssid)); /* Copy the locally created newbssentry to the scan table */ memcpy(found, &new, offsetof(struct bss_descriptor, list)); diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index f8036efd729..0b2103e0af5 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -1160,7 +1160,7 @@ static int wlan_get_encode(struct net_device *dev, dwrq->flags |= IW_ENCODE_NOKEY; - lbs_deb_wext("key: " MAC_FMT ", keylen %d\n", + lbs_deb_wext("key: %02x:%02x:%02x:%02x:%02x:%02x, keylen %d\n", extra[0], extra[1], extra[2], extra[3], extra[4], extra[5], dwrq->length); @@ -1980,13 +1980,14 @@ static int wlan_set_wap(struct net_device *dev, struct iw_request_info *info, wlan_adapter *adapter = priv->adapter; struct assoc_request * assoc_req; int ret = 0; + DECLARE_MAC_BUF(mac); lbs_deb_enter(LBS_DEB_WEXT); if (awrq->sa_family != ARPHRD_ETHER) return -EINVAL; - lbs_deb_wext("ASSOC: WAP: sa_data " MAC_FMT "\n", MAC_ARG(awrq->sa_data)); + lbs_deb_wext("ASSOC: WAP: sa_data %s\n", print_mac(mac, awrq->sa_data)); mutex_lock(&adapter->lock); diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c index d8a59afa717..c2d71afd57e 100644 --- a/drivers/net/wireless/netwave_cs.c +++ b/drivers/net/wireless/netwave_cs.c @@ -737,6 +737,7 @@ static int netwave_pcmcia_config(struct pcmcia_device *link) { win_req_t req; memreq_t mem; u_char __iomem *ramBase = NULL; + DECLARE_MAC_BUF(mac); DEBUG(0, "netwave_pcmcia_config(0x%p)\n", link); @@ -805,12 +806,13 @@ static int netwave_pcmcia_config(struct pcmcia_device *link) { for (i = 0; i < 6; i++) dev->dev_addr[i] = readb(ramBase + NETWAVE_EREG_PA + i); - printk(KERN_INFO "%s: Netwave: port %#3lx, irq %d, mem %lx id " - "%c%c, hw_addr ", dev->name, dev->base_addr, dev->irq, - (u_long) ramBase, (int) readb(ramBase+NETWAVE_EREG_NI), - (int) readb(ramBase+NETWAVE_EREG_NI+1)); - for (i = 0; i < 6; i++) - printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n")); + printk(KERN_INFO "%s: Netwave: port %#3lx, irq %d, mem %lx" + "id %c%c, hw_addr %s\n", + dev->name, dev->base_addr, dev->irq, + (u_long) ramBase, + (int) readb(ramBase+NETWAVE_EREG_NI), + (int) readb(ramBase+NETWAVE_EREG_NI+1), + print_mac(mac, dev->dev_addr)); /* get revision words */ printk(KERN_DEBUG "Netwave_reset: revision %04x %04x\n", diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 062286dc8e1..ca6c2da7bc5 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -2232,6 +2232,7 @@ static int orinoco_init(struct net_device *dev) struct hermes_idstring nickbuf; u16 reclen; int len; + DECLARE_MAC_BUF(mac); /* No need to lock, the hw_unavailable flag is already set in * alloc_orinocodev() */ @@ -2274,10 +2275,8 @@ static int orinoco_init(struct net_device *dev) goto out; } - printk(KERN_DEBUG "%s: MAC address %02X:%02X:%02X:%02X:%02X:%02X\n", - dev->name, dev->dev_addr[0], dev->dev_addr[1], - dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], - dev->dev_addr[5]); + printk(KERN_DEBUG "%s: MAC address %s\n", + dev->name, print_mac(mac, dev->dev_addr)); /* Get the station name */ err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME, diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c index 77ea13bf0c0..6d80ca421cf 100644 --- a/drivers/net/wireless/prism54/isl_ioctl.c +++ b/drivers/net/wireless/prism54/isl_ioctl.c @@ -2029,12 +2029,12 @@ static void format_event(islpci_private *priv, char *dest, const char *str, const struct obj_mlme *mlme, u16 *length, int error) { - const u8 *a = mlme->address; + DECLARE_MAC_BUF(mac); int n = snprintf(dest, IW_CUSTOM_MAX, - "%s %s %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X %s (%2.2X)", + "%s %s %s %s (%2.2X)", str, ((priv->iw_mode == IW_MODE_MASTER) ? "from" : "to"), - a[0], a[1], a[2], a[3], a[4], a[5], + print_mac(mac, mlme->address), (error ? (mlme->code ? " : REJECTED " : " : ACCEPTED ") : ""), mlme->code); BUG_ON(n > IW_CUSTOM_MAX); @@ -2105,15 +2105,13 @@ struct ieee80211_beacon_phdr { #define WLAN_EID_GENERIC 0xdd static u8 wpa_oid[4] = { 0x00, 0x50, 0xf2, 1 }; -#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] -#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" - static void prism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid, u8 *wpa_ie, size_t wpa_ie_len) { struct list_head *ptr; struct islpci_bss_wpa_ie *bss = NULL; + DECLARE_MAC_BUF(mac); if (wpa_ie_len > MAX_WPA_IE_LEN) wpa_ie_len = MAX_WPA_IE_LEN; @@ -2154,8 +2152,8 @@ prism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid, bss->wpa_ie_len = wpa_ie_len; bss->last_update = jiffies; } else { - printk(KERN_DEBUG "Failed to add BSS WPA entry for " MACSTR - "\n", MAC2STR(bssid)); + printk(KERN_DEBUG "Failed to add BSS WPA entry for " + "%s\n", print_mac(mac, bssid)); } /* expire old entries from WPA list */ @@ -2221,6 +2219,7 @@ prism54_process_bss_data(islpci_private *priv, u32 oid, u8 *addr, { struct ieee80211_beacon_phdr *hdr; u8 *pos, *end; + DECLARE_MAC_BUF(mac); if (!priv->wpa) return; @@ -2231,7 +2230,7 @@ prism54_process_bss_data(islpci_private *priv, u32 oid, u8 *addr, while (pos < end) { if (pos + 2 + pos[1] > end) { printk(KERN_DEBUG "Parsing Beacon/ProbeResp failed " - "for " MACSTR "\n", MAC2STR(addr)); + "for %s\n", print_mac(mac, addr)); return; } if (pos[0] == WLAN_EID_GENERIC && pos[1] >= 4 && @@ -2270,6 +2269,7 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid, size_t len = 0; /* u16, better? */ u8 *payload = NULL, *pos = NULL; int ret; + DECLARE_MAC_BUF(mac); /* I think all trapable objects are listed here. * Some oids have a EX version. The difference is that they are emitted @@ -2358,14 +2358,8 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid, break; memcpy(&confirm->address, mlmeex->address, ETH_ALEN); - printk(KERN_DEBUG "Authenticate from: address:\t%02x:%02x:%02x:%02x:%02x:%02x\n", - mlmeex->address[0], - mlmeex->address[1], - mlmeex->address[2], - mlmeex->address[3], - mlmeex->address[4], - mlmeex->address[5] - ); + printk(KERN_DEBUG "Authenticate from: address:\t%s\n", + print_mac(mac, mlmeex->address)); confirm->id = -1; /* or mlmeex->id ? */ confirm->state = 0; /* not used */ confirm->code = 0; @@ -2410,15 +2404,8 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid, wpa_ie_len = prism54_wpa_bss_ie_get(priv, mlmeex->address, wpa_ie); if (!wpa_ie_len) { - printk(KERN_DEBUG "No WPA IE found from " - "address:\t%02x:%02x:%02x:%02x:%02x:%02x\n", - mlmeex->address[0], - mlmeex->address[1], - mlmeex->address[2], - mlmeex->address[3], - mlmeex->address[4], - mlmeex->address[5] - ); + printk(KERN_DEBUG "No WPA IE found from address:\t%s\n", + print_mac(mac, mlmeex->address)); kfree(confirm); break; } @@ -2454,15 +2441,8 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid, wpa_ie_len = prism54_wpa_bss_ie_get(priv, mlmeex->address, wpa_ie); if (!wpa_ie_len) { - printk(KERN_DEBUG "No WPA IE found from " - "address:\t%02x:%02x:%02x:%02x:%02x:%02x\n", - mlmeex->address[0], - mlmeex->address[1], - mlmeex->address[2], - mlmeex->address[3], - mlmeex->address[4], - mlmeex->address[5] - ); + printk(KERN_DEBUG "No WPA IE found from address:\t%s\n", + print_mac(mac, mlmeex->address)); kfree(confirm); break; } diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 429bca8d0b5..f87fe10059a 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -412,6 +412,7 @@ static int ray_config(struct pcmcia_device *link) memreq_t mem; struct net_device *dev = (struct net_device *)link->priv; ray_dev_t *local = netdev_priv(dev); + DECLARE_MAC_BUF(mac); DEBUG(1, "ray_config(0x%p)\n", link); @@ -482,10 +483,8 @@ static int ray_config(struct pcmcia_device *link) strcpy(local->node.dev_name, dev->name); link->dev_node = &local->node; - printk(KERN_INFO "%s: RayLink, irq %d, hw_addr ", - dev->name, dev->irq); - for (i = 0; i < 6; i++) - printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n")); + printk(KERN_INFO "%s: RayLink, irq %d, hw_addr %s\n", + dev->name, dev->irq, print_mac(mac, dev->dev_addr)); return 0; @@ -2610,6 +2609,7 @@ static int ray_cs_proc_read(char *buf, char **start, off_t offset, int len) UCHAR *p; struct freq_hop_element *pfh; UCHAR c[33]; + DECLARE_MAC_BUF(mac); link = this_device; if (!link) @@ -2639,9 +2639,8 @@ static int ray_cs_proc_read(char *buf, char **start, off_t offset, int len) nettype[local->sparm.b5.a_network_type], c); p = local->bss_id; - len += sprintf(buf + len, - "BSSID = %02x:%02x:%02x:%02x:%02x:%02x\n", - p[0],p[1],p[2],p[3],p[4],p[5]); + len += sprintf(buf + len, "BSSID = %s\n", + print_mac(mac, p)); len += sprintf(buf + len, "Country code = %d\n", local->sparm.b5.a_curr_country_code); diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 38e2188937c..398c20105c8 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1362,8 +1362,10 @@ static int rt2400pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) */ mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); if (!is_valid_ether_addr(mac)) { + DECLARE_MAC_BUF(macbuf); + random_ether_addr(mac); - EEPROM(rt2x00dev, "MAC: " MAC_FMT "\n", MAC_ARG(mac)); + EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac)); } rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index f6115c626fa..e8d63aaab7b 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1509,8 +1509,11 @@ static int rt2500pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) */ mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); if (!is_valid_ether_addr(mac)) { + DECLARE_MAC_BUF(macbuf); + random_ether_addr(mac); - EEPROM(rt2x00dev, "MAC: " MAC_FMT "\n", MAC_ARG(mac)); + EEPROM(rt2x00dev, "MAC: %s\n", + print_mac(macbuf, mac)); } rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 847bd7f58ee..614600c5510 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1233,8 +1233,10 @@ static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) */ mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); if (!is_valid_ether_addr(mac)) { + DECLARE_MAC_BUF(macbuf); + random_ether_addr(mac); - EEPROM(rt2x00dev, "MAC: " MAC_FMT "\n", MAC_ARG(mac)); + EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac)); } rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 730bed5a198..09c8c96e2f8 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2019,8 +2019,10 @@ static int rt61pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) */ mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); if (!is_valid_ether_addr(mac)) { + DECLARE_MAC_BUF(macbuf); + random_ether_addr(mac); - EEPROM(rt2x00dev, "MAC: " MAC_FMT "\n", MAC_ARG(mac)); + EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac)); } rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index b047c7c0f9e..3397881bd63 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1475,8 +1475,10 @@ static int rt73usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) */ mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); if (!is_valid_ether_addr(mac)) { + DECLARE_MAC_BUF(macbuf); + random_ether_addr(mac); - EEPROM(rt2x00dev, "MAC: " MAC_FMT "\n", MAC_ARG(mac)); + EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac)); } rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index 7dbf11e30db..bf9f0cc5a64 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c @@ -574,6 +574,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, struct ieee80211_channel *channel; u16 txpwr, reg; int err, i; + DECLARE_MAC_BUF(mac); dev = ieee80211_alloc_hw(sizeof(*priv), &rtl8187_ops); if (!dev) { @@ -681,8 +682,8 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, goto err_free_dev; } - printk(KERN_INFO "%s: hwaddr " MAC_FMT ", rtl8187 V%d + %s\n", - wiphy_name(dev->wiphy), MAC_ARG(dev->wiphy->perm_addr), + printk(KERN_INFO "%s: hwaddr %s, rtl8187 V%d + %s\n", + wiphy_name(dev->wiphy), print_mac(mac, dev->wiphy->perm_addr), priv->asic_rev, priv->rf_init == rtl8225_rf_init ? "rtl8225" : "rtl8225z2"); diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c index 33ed9fe95f3..a1f8a168784 100644 --- a/drivers/net/wireless/wavelan.c +++ b/drivers/net/wireless/wavelan.c @@ -880,6 +880,8 @@ static void wv_82586_reconfig(struct net_device * dev) */ static void wv_psa_show(psa_t * p) { + DECLARE_MAC_BUF(mac); + printk(KERN_DEBUG "##### WaveLAN PSA contents: #####\n"); printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n", p->psa_io_base_addr_1, @@ -891,22 +893,13 @@ static void wv_psa_show(psa_t * p) printk(KERN_DEBUG "psa_holi_params: 0x%02x, ", p->psa_holi_params); printk("psa_int_req_no: %d\n", p->psa_int_req_no); #ifdef DEBUG_SHOW_UNUSED - printk(KERN_DEBUG - "psa_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X\n", - p->psa_unused0[0], p->psa_unused0[1], p->psa_unused0[2], - p->psa_unused0[3], p->psa_unused0[4], p->psa_unused0[5], - p->psa_unused0[6]); + printk(KERN_DEBUG "psa_unused0[]: %s\n", + print_mac(mac, p->psa_unused0)); #endif /* DEBUG_SHOW_UNUSED */ - printk(KERN_DEBUG - "psa_univ_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n", - p->psa_univ_mac_addr[0], p->psa_univ_mac_addr[1], - p->psa_univ_mac_addr[2], p->psa_univ_mac_addr[3], - p->psa_univ_mac_addr[4], p->psa_univ_mac_addr[5]); - printk(KERN_DEBUG - "psa_local_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n", - p->psa_local_mac_addr[0], p->psa_local_mac_addr[1], - p->psa_local_mac_addr[2], p->psa_local_mac_addr[3], - p->psa_local_mac_addr[4], p->psa_local_mac_addr[5]); + printk(KERN_DEBUG "psa_univ_mac_addr[]: %s\n", + print_mac(mac, p->psa_univ_mac_addr)); + printk(KERN_DEBUG "psa_local_mac_addr[]: %s\n", + print_mac(mac, p->psa_local_mac_addr)); printk(KERN_DEBUG "psa_univ_local_sel: %d, ", p->psa_univ_local_sel); printk("psa_comp_number: %d, ", p->psa_comp_number); @@ -1248,14 +1241,14 @@ static inline void wv_packet_info(u8 * p, /* Packet to dump */ { /* Name of the function */ int i; int maxi; + DECLARE_MAC_BUF(mac); printk(KERN_DEBUG - "%s: %s(): dest %02X:%02X:%02X:%02X:%02X:%02X, length %d\n", - msg1, msg2, p[0], p[1], p[2], p[3], p[4], p[5], length); + "%s: %s(): dest %s, length %d\n", + msg1, msg2, print_mac(mac, p), length); printk(KERN_DEBUG - "%s: %s(): src %02X:%02X:%02X:%02X:%02X:%02X, type 0x%02X%02X\n", - msg1, msg2, p[6], p[7], p[8], p[9], p[10], p[11], p[12], - p[13]); + "%s: %s(): src %s, type 0x%02X%02X\n", + msg1, msg2, print_mac(mac, &p[6]), p[12], p[13]); #ifdef DEBUG_PACKET_DUMP @@ -1286,7 +1279,9 @@ static void wv_init_info(struct net_device * dev) short ioaddr = dev->base_addr; net_local *lp = (net_local *) dev->priv; psa_t psa; - int i; +#ifdef DEBUG_BASIC_SHOW + DECLARE_MAC_BUF(mac); +#endif /* Read the parameter storage area */ psa_read(ioaddr, lp->hacr, 0, (unsigned char *) &psa, sizeof(psa)); @@ -1303,10 +1298,8 @@ static void wv_init_info(struct net_device * dev) #ifdef DEBUG_BASIC_SHOW /* Now, let's go for the basic stuff. */ - printk(KERN_NOTICE "%s: WaveLAN at %#x,", dev->name, ioaddr); - for (i = 0; i < WAVELAN_ADDR_SIZE; i++) - printk("%s%02X", (i == 0) ? " " : ":", dev->dev_addr[i]); - printk(", IRQ %d", dev->irq); + printk(KERN_NOTICE "%s: WaveLAN at %#x, %s, IRQ %d", + dev->name, ioaddr, print_mac(mac, dev->dev_addr), dev->irq); /* Print current network ID. */ if (psa.psa_nwid_select) @@ -3596,15 +3589,15 @@ static void wv_82586_config(struct net_device * dev) WAVELAN_ADDR_SIZE >> 1); #ifdef DEBUG_CONFIG_INFO + { + DECLARE_MAC_BUF(mac); printk(KERN_DEBUG "%s: wv_82586_config(): set %d multicast addresses:\n", dev->name, lp->mc_count); for (dmi = dev->mc_list; dmi; dmi = dmi->next) - printk(KERN_DEBUG - " %02x:%02x:%02x:%02x:%02x:%02x\n", - dmi->dmi_addr[0], dmi->dmi_addr[1], - dmi->dmi_addr[2], dmi->dmi_addr[3], - dmi->dmi_addr[4], dmi->dmi_addr[5]); + printk(KERN_DEBUG " %s\n", + print_mac(mac, dmi->dmi_addr)); + } #endif } diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index 9b7f4495786..577c647824f 100644 --- a/drivers/net/wireless/wavelan_cs.c +++ b/drivers/net/wireless/wavelan_cs.c @@ -1042,6 +1042,7 @@ wv_82593_reconfig(struct net_device * dev) static void wv_psa_show(psa_t * p) { + DECLARE_MAC_BUF(mac); printk(KERN_DEBUG "##### wavelan psa contents: #####\n"); printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n", p->psa_io_base_addr_1, @@ -1055,29 +1056,13 @@ wv_psa_show(psa_t * p) printk(KERN_DEBUG "psa_holi_params: 0x%02x, ", p->psa_holi_params); printk("psa_int_req_no: %d\n", p->psa_int_req_no); #ifdef DEBUG_SHOW_UNUSED - printk(KERN_DEBUG "psa_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X\n", - p->psa_unused0[0], - p->psa_unused0[1], - p->psa_unused0[2], - p->psa_unused0[3], - p->psa_unused0[4], - p->psa_unused0[5], - p->psa_unused0[6]); + printk(KERN_DEBUG "psa_unused0[]: %s\n", + print_mac(mac, p->psa_unused0)); #endif /* DEBUG_SHOW_UNUSED */ - printk(KERN_DEBUG "psa_univ_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n", - p->psa_univ_mac_addr[0], - p->psa_univ_mac_addr[1], - p->psa_univ_mac_addr[2], - p->psa_univ_mac_addr[3], - p->psa_univ_mac_addr[4], - p->psa_univ_mac_addr[5]); - printk(KERN_DEBUG "psa_local_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n", - p->psa_local_mac_addr[0], - p->psa_local_mac_addr[1], - p->psa_local_mac_addr[2], - p->psa_local_mac_addr[3], - p->psa_local_mac_addr[4], - p->psa_local_mac_addr[5]); + printk(KERN_DEBUG "psa_univ_mac_addr[]: %s\n", + print_mac(mac, p->psa_univ_mac_addr)); + printk(KERN_DEBUG "psa_local_mac_addr[]: %s\n", + print_mac(mac, p->psa_local_mac_addr)); printk(KERN_DEBUG "psa_univ_local_sel: %d, ", p->psa_univ_local_sel); printk("psa_comp_number: %d, ", p->psa_comp_number); printk("psa_thr_pre_set: 0x%02x\n", p->psa_thr_pre_set); @@ -1277,11 +1262,12 @@ wv_packet_info(u_char * p, /* Packet to dump */ { int i; int maxi; + DECLARE_MAC_BUF(mac); - printk(KERN_DEBUG "%s: %s(): dest %02X:%02X:%02X:%02X:%02X:%02X, length %d\n", - msg1, msg2, p[0], p[1], p[2], p[3], p[4], p[5], length); - printk(KERN_DEBUG "%s: %s(): src %02X:%02X:%02X:%02X:%02X:%02X, type 0x%02X%02X\n", - msg1, msg2, p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13]); + printk(KERN_DEBUG "%s: %s(): dest %s, length %d\n", + msg1, msg2, print_mac(mac, p), length); + printk(KERN_DEBUG "%s: %s(): src %s, type 0x%02X%02X\n", + msg1, msg2, print_mac(mac, &p[6]), p[12], p[13]); #ifdef DEBUG_PACKET_DUMP @@ -1312,7 +1298,7 @@ wv_init_info(struct net_device * dev) { kio_addr_t base = dev->base_addr; psa_t psa; - int i; + DECLARE_MAC_BUF(mac); /* Read the parameter storage area */ psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa)); @@ -1329,10 +1315,10 @@ wv_init_info(struct net_device * dev) #ifdef DEBUG_BASIC_SHOW /* Now, let's go for the basic stuff */ - printk(KERN_NOTICE "%s: WaveLAN: port %#lx, irq %d, hw_addr", - dev->name, base, dev->irq); - for(i = 0; i < WAVELAN_ADDR_SIZE; i++) - printk("%s%02X", (i == 0) ? " " : ":", dev->dev_addr[i]); + printk(KERN_NOTICE "%s: WaveLAN: port %#lx, irq %d, " + "hw_addr %s", + dev->name, base, dev->irq, + print_mac(mac, dev->dev_addr)); /* Print current network id */ if(psa.psa_nwid_select) @@ -3691,12 +3677,12 @@ wv_82593_config(struct net_device * dev) int addrs_len = WAVELAN_ADDR_SIZE * lp->mc_count; #ifdef DEBUG_CONFIG_INFO + DECLARE_MAC_BUF(mac); printk(KERN_DEBUG "%s: wv_hw_config(): set %d multicast addresses:\n", dev->name, lp->mc_count); for(dmi=dev->mc_list; dmi; dmi=dmi->next) - printk(KERN_DEBUG " %02x:%02x:%02x:%02x:%02x:%02x\n", - dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2], - dmi->dmi_addr[3], dmi->dmi_addr[4], dmi->dmi_addr[5] ); + printk(KERN_DEBUG " %s\n", + print_mac(mac, dmi->dmi_addr)); #endif /* Initialize adapter's ethernet multicast addresses */ diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index 2690f291e3f..42a36b3f3ff 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -860,11 +860,10 @@ static int wl3501_esbq_confirm(struct wl3501_card *this) static void wl3501_online(struct net_device *dev) { struct wl3501_card *this = netdev_priv(dev); + DECLARE_MAC_BUF(mac); - printk(KERN_INFO "%s: Wireless LAN online. BSSID: " - "%02X %02X %02X %02X %02X %02X\n", dev->name, - this->bssid[0], this->bssid[1], this->bssid[2], - this->bssid[3], this->bssid[4], this->bssid[5]); + printk(KERN_INFO "%s: Wireless LAN online. BSSID: %s\n", + dev->name, print_mac(mac, this->bssid)); netif_wake_queue(dev); } @@ -1966,6 +1965,7 @@ static int wl3501_config(struct pcmcia_device *link) struct net_device *dev = link->priv; int i = 0, j, last_fn, last_ret; struct wl3501_card *this; + DECLARE_MAC_BUF(mac); /* Try allocating IO ports. This tries a few fixed addresses. If you * want, you can also read the card's config table to pick addresses -- @@ -2019,14 +2019,14 @@ static int wl3501_config(struct pcmcia_device *link) } strcpy(this->node.dev_name, dev->name); - /* print probe information */ - printk(KERN_INFO "%s: wl3501 @ 0x%3.3x, IRQ %d, MAC addr in flash ROM:", - dev->name, this->base_addr, (int)dev->irq); - for (i = 0; i < 6; i++) { + for (i = 0; i < 6; i++) dev->dev_addr[i] = ((char *)&this->mac_addr)[i]; - printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]); - } - printk("\n"); + + /* print probe information */ + printk(KERN_INFO "%s: wl3501 @ 0x%3.3x, IRQ %d, " + "MAC addr in flash ROM:%s\n", + dev->name, this->base_addr, (int)dev->irq, + print_mac(mac, dev->dev_addr)); /* * Initialize card parameters - added by jss */ diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c index 495904218b1..750c0f99e86 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.c +++ b/drivers/net/wireless/zd1211rw/zd_chip.c @@ -377,6 +377,7 @@ int zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr) [0] = { .addr = CR_MAC_ADDR_P1 }, [1] = { .addr = CR_MAC_ADDR_P2 }, }; + DECLARE_MAC_BUF(mac); reqs[0].value = (mac_addr[3] << 24) | (mac_addr[2] << 16) @@ -386,7 +387,7 @@ int zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr) | mac_addr[4]; dev_dbg_f(zd_chip_dev(chip), - "mac addr " MAC_FMT "\n", MAC_ARG(mac_addr)); + "mac addr %s\n", print_mac(mac, mac_addr)); mutex_lock(&chip->mutex); r = zd_iowrite32a_locked(chip, reqs, ARRAY_SIZE(reqs)); diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 451308d7095..06b342b3979 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -289,12 +289,13 @@ int zd_mac_set_mac_address(struct net_device *netdev, void *p) struct sockaddr *addr = p; struct zd_mac *mac = zd_netdev_mac(netdev); struct zd_chip *chip = &mac->chip; + DECLARE_MAC_BUF(mac2); if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; dev_dbg_f(zd_mac_dev(mac), - "Setting MAC to " MAC_FMT "\n", MAC_ARG(addr->sa_data)); + "Setting MAC to %s\n", print_mac(mac2, addr->sa_data)); if (netdev->flags & IFF_UP) { r = zd_write_mac_addr(chip, addr->sa_data); @@ -329,6 +330,7 @@ void zd_mac_set_multicast_list(struct net_device *dev) struct zd_mc_hash hash; struct dev_mc_list *mc; unsigned long flags; + DECLARE_MAC_BUF(mac2); if (dev->flags & (IFF_PROMISC|IFF_ALLMULTI) || ieee->iw_mode == IW_MODE_MONITOR) { @@ -336,8 +338,8 @@ void zd_mac_set_multicast_list(struct net_device *dev) } else { zd_mc_clear(&hash); for (mc = dev->mc_list; mc; mc = mc->next) { - dev_dbg_f(zd_mac_dev(mac), "mc addr " MAC_FMT "\n", - MAC_ARG(mc->dmi_addr)); + dev_dbg_f(zd_mac_dev(mac), "mc addr %s\n", + print_mac(mac2, mc->dmi_addr)); zd_mc_add_addr(&hash, mc->dmi_addr); } } diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c index 709623e1c61..87f002ade53 100644 --- a/drivers/net/yellowfin.c +++ b/drivers/net/yellowfin.c @@ -374,6 +374,7 @@ static int __devinit yellowfin_init_one(struct pci_dev *pdev, #else int bar = 1; #endif + DECLARE_MAC_BUF(mac); /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -480,12 +481,10 @@ static int __devinit yellowfin_init_one(struct pci_dev *pdev, if (i) goto err_out_unmap_status; - printk(KERN_INFO "%s: %s type %8x at %p, ", + printk(KERN_INFO "%s: %s type %8x at %p, %s, IRQ %d.\n", dev->name, pci_id_tbl[chip_idx].name, - ioread32(ioaddr + ChipRev), ioaddr); - for (i = 0; i < 5; i++) - printk("%2.2x:", dev->dev_addr[i]); - printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); + ioread32(ioaddr + ChipRev), ioaddr, + print_mac(mac, dev->dev_addr), irq); if (np->drv_flags & HasMII) { int phy, phy_idx = 0; @@ -1101,11 +1100,11 @@ static int yellowfin_rx(struct net_device *dev) memcmp(le32_to_cpu(yp->rx_ring_dma + entry*sizeof(struct yellowfin_desc)), "\377\377\377\377\377\377", 6) != 0) { - if (bogus_rx++ == 0) - printk(KERN_WARNING "%s: Bad frame to %2.2x:%2.2x:%2.2x:%2.2x:" - "%2.2x:%2.2x.\n", - dev->name, buf_addr[0], buf_addr[1], buf_addr[2], - buf_addr[3], buf_addr[4], buf_addr[5]); + if (bogus_rx++ == 0) { + DECLARE_MAC_BUF(mac); + printk(KERN_WARNING "%s: Bad frame to %s\n", + dev->name, print_mac(mac, buf_addr)); + } #endif } else { struct sk_buff *skb; diff --git a/drivers/net/znet.c b/drivers/net/znet.c index 43712c7b9ec..a86c022d6a9 100644 --- a/drivers/net/znet.c +++ b/drivers/net/znet.c @@ -370,6 +370,7 @@ static int __init znet_probe (void) struct net_device *dev; char *p; int err = -ENOMEM; + DECLARE_MAC_BUF(mac); /* This code scans the region 0xf0000 to 0xfffff for a "NETIDBLK". */ for(p = (char *)phys_to_virt(0xf0000); p < (char *)phys_to_virt(0x100000); p++) @@ -392,14 +393,14 @@ static int __init znet_probe (void) dev->base_addr = netinfo->iobase1; dev->irq = netinfo->irq1; - printk(KERN_INFO "%s: ZNET at %#3lx,", dev->name, dev->base_addr); - /* The station address is in the "netidblk" at 0x0f0000. */ for (i = 0; i < 6; i++) - printk(" %2.2x", dev->dev_addr[i] = netinfo->netid[i]); + dev->dev_addr[i] = netinfo->netid[i]; - printk(", using IRQ %d DMA %d and %d.\n", dev->irq, netinfo->dma1, - netinfo->dma2); + printk(KERN_INFO "%s: ZNET at %#3lx, %s" + ", using IRQ %d DMA %d and %d.\n", + dev->name, dev->base_addr, print_mac(mac, dev->dev_addr), + dev->irq, netinfo->dma1, netinfo->dma2); if (znet_debug > 1) { printk(KERN_INFO "%s: vendor '%16.16s' IRQ1 %d IRQ2 %d DMA1 %d DMA2 %d.\n", diff --git a/drivers/net/zorro8390.c b/drivers/net/zorro8390.c index fb215eb6dcf..3926b2aa9cc 100644 --- a/drivers/net/zorro8390.c +++ b/drivers/net/zorro8390.c @@ -151,6 +151,7 @@ static int __devinit zorro8390_init(struct net_device *dev, 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, }; + DECLARE_MAC_BUF(mac); /* Reset card. Who knows what dain-bramaged state it was left in. */ { @@ -211,12 +212,12 @@ static int __devinit zorro8390_init(struct net_device *dev, i = request_irq(IRQ_AMIGA_PORTS, __ei_interrupt, IRQF_SHARED, DRV_NAME, dev); if (i) return i; - for(i = 0; i < ETHER_ADDR_LEN; i++) { + for(i = 0; i < ETHER_ADDR_LEN; i++) + dev->dev_addr[i] = SA_prom[i]; + #ifdef DEBUG - printk(" %2.2x", SA_prom[i]); + printk("%s", print_mac(mac, dev->dev_addr)); #endif - dev->dev_addr[i] = SA_prom[i]; - } ei_status.name = name; ei_status.tx_start_page = start_page; @@ -243,10 +244,8 @@ static int __devinit zorro8390_init(struct net_device *dev, return err; } - printk(KERN_INFO "%s: %s at 0x%08lx, Ethernet Address " - "%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, name, board, - dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + printk(KERN_INFO "%s: %s at 0x%08lx, Ethernet Address %s\n", + dev->name, name, board, print_mac(mac, dev->dev_addr)); return 0; } diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h index 3213f6f4aa5..0e791e2c0c5 100644 --- a/include/linux/if_ether.h +++ b/include/linux/if_ether.h @@ -120,6 +120,14 @@ static inline struct ethhdr *eth_hdr(const struct sk_buff *skb) #ifdef CONFIG_SYSCTL extern struct ctl_table ether_table[]; #endif + +/* + * Display a 6 byte device address (MAC) in a readable format. + */ +#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x" +extern char *print_mac(char *buf, const u8 *addr); +#define DECLARE_MAC_BUF(var) char var[18] __maybe_unused + #endif #endif /* _LINUX_IF_ETHER_H */ diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h index bbd85cd61ed..164d1321116 100644 --- a/include/net/ieee80211.h +++ b/include/net/ieee80211.h @@ -119,11 +119,6 @@ do { if (ieee80211_debug_level & (level)) \ #define IEEE80211_DEBUG(level, fmt, args...) do {} while (0) #endif /* CONFIG_IEEE80211_DEBUG */ -/* debug macros not dependent on CONFIG_IEEE80211_DEBUG */ - -#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x" -#define MAC_ARG(x) ((u8*)(x))[0],((u8*)(x))[1],((u8*)(x))[2],((u8*)(x))[3],((u8*)(x))[4],((u8*)(x))[5] - /* escape_essid() is intended to be used in debug (and possibly error) * messages. It should never be used for passing essid to user space. */ const char *escape_essid(const char *essid, u8 essid_len); diff --git a/include/net/mac80211.h b/include/net/mac80211.h index a2c14f95b9a..947f3c820e4 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1106,8 +1106,4 @@ static inline int ieee80211_get_morefrag(struct ieee80211_hdr *hdr) IEEE80211_FCTL_MOREFRAGS) != 0; } -#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x" -#define MAC_ARG(x) ((u8*)(x))[0], ((u8*)(x))[1], ((u8*)(x))[2], \ - ((u8*)(x))[3], ((u8*)(x))[4], ((u8*)(x))[5] - #endif /* MAC80211_H */ diff --git a/net/802/tr.c b/net/802/tr.c index 55c76d77d32..aa3c2e936ab 100644 --- a/net/802/tr.c +++ b/net/802/tr.c @@ -283,8 +283,10 @@ void tr_source_route(struct sk_buff *skb,struct trh_hdr *trh,struct net_device * if(entry) { #if TR_SR_DEBUG -printk("source routing for %02X:%02X:%02X:%02X:%02X:%02X\n",trh->daddr[0], - trh->daddr[1],trh->daddr[2],trh->daddr[3],trh->daddr[4],trh->daddr[5]); +{ +DECLARE_MAC_BUF(mac); +printk("source routing for %s\n",print_mac(mac, trh->daddr)); +} #endif if(!entry->local_ring && (ntohs(entry->rcf) & TR_RCF_LEN_MASK) >> 8) { @@ -366,10 +368,9 @@ static void tr_add_rif_info(struct trh_hdr *trh, struct net_device *dev) if(entry==NULL) { #if TR_SR_DEBUG -printk("adding rif_entry: addr:%02X:%02X:%02X:%02X:%02X:%02X rcf:%04X\n", - trh->saddr[0],trh->saddr[1],trh->saddr[2], - trh->saddr[3],trh->saddr[4],trh->saddr[5], - ntohs(trh->rcf)); + DECLARE_MAC_BUF(mac); + printk("adding rif_entry: addr:%s rcf:%04X\n", + print_mac(mac, trh->saddr), ntohs(trh->rcf)); #endif /* * Allocate our new entry. A failure to allocate loses @@ -414,10 +415,11 @@ printk("adding rif_entry: addr:%02X:%02X:%02X:%02X:%02X:%02X rcf:%04X\n", !(trh->rcf & htons(TR_RCF_BROADCAST_MASK))) { #if TR_SR_DEBUG -printk("updating rif_entry: addr:%02X:%02X:%02X:%02X:%02X:%02X rcf:%04X\n", - trh->saddr[0],trh->saddr[1],trh->saddr[2], - trh->saddr[3],trh->saddr[4],trh->saddr[5], - ntohs(trh->rcf)); +{ +DECLARE_MAC_BUF(mac); +printk("updating rif_entry: addr:%s rcf:%04X\n", + print_mac(mac, trh->saddr), ntohs(trh->rcf)); +} #endif entry->rcf = trh->rcf & htons((unsigned short)~TR_RCF_BROADCAST_MASK); memcpy(&(entry->rseg[0]),&(trh->rseg[0]),8*sizeof(unsigned short)); @@ -528,6 +530,7 @@ static int rif_seq_show(struct seq_file *seq, void *v) { int j, rcf_len, segment, brdgnmb; struct rif_cache *entry = v; + DECLARE_MAC_BUF(mac); if (v == SEQ_START_TOKEN) seq_puts(seq, @@ -537,10 +540,9 @@ static int rif_seq_show(struct seq_file *seq, void *v) long ttl = (long) (entry->last_used + sysctl_tr_rif_timeout) - (long) jiffies; - seq_printf(seq, "%s %02X:%02X:%02X:%02X:%02X:%02X %7li ", + seq_printf(seq, "%s %s %7li ", dev?dev->name:"?", - entry->addr[0],entry->addr[1],entry->addr[2], - entry->addr[3],entry->addr[4],entry->addr[5], + print_mac(mac, entry->addr), ttl/HZ); if (entry->local_ring) diff --git a/net/appletalk/aarp.c b/net/appletalk/aarp.c index e9a51a69870..92cd74973c9 100644 --- a/net/appletalk/aarp.c +++ b/net/appletalk/aarp.c @@ -997,6 +997,7 @@ static int aarp_seq_show(struct seq_file *seq, void *v) struct aarp_iter_state *iter = seq->private; struct aarp_entry *entry = v; unsigned long now = jiffies; + DECLARE_MAC_BUF(mac); if (v == SEQ_START_TOKEN) seq_puts(seq, @@ -1007,13 +1008,7 @@ static int aarp_seq_show(struct seq_file *seq, void *v) ntohs(entry->target_addr.s_net), (unsigned int) entry->target_addr.s_node, entry->dev ? entry->dev->name : "????"); - seq_printf(seq, "%02X:%02X:%02X:%02X:%02X:%02X", - entry->hwaddr[0] & 0xFF, - entry->hwaddr[1] & 0xFF, - entry->hwaddr[2] & 0xFF, - entry->hwaddr[3] & 0xFF, - entry->hwaddr[4] & 0xFF, - entry->hwaddr[5] & 0xFF); + seq_printf(seq, "%s", print_mac(mac, entry->hwaddr)); seq_printf(seq, " %8s", dt2str((long)entry->expires_at - (long)now)); if (iter->table == unresolved) diff --git a/net/atm/br2684.c b/net/atm/br2684.c index 81eb4f4cbe1..c742d37bfb9 100644 --- a/net/atm/br2684.c +++ b/net/atm/br2684.c @@ -709,17 +709,13 @@ static int br2684_seq_show(struct seq_file *seq, void *v) br2684_devs); const struct net_device *net_dev = brdev->net_dev; const struct br2684_vcc *brvcc; + DECLARE_MAC_BUF(mac); - seq_printf(seq, "dev %.16s: num=%d, mac=%02X:%02X:" - "%02X:%02X:%02X:%02X (%s)\n", net_dev->name, - brdev->number, - net_dev->dev_addr[0], - net_dev->dev_addr[1], - net_dev->dev_addr[2], - net_dev->dev_addr[3], - net_dev->dev_addr[4], - net_dev->dev_addr[5], - brdev->mac_was_set ? "set" : "auto"); + seq_printf(seq, "dev %.16s: num=%d, mac=%s (%s)\n", + net_dev->name, + brdev->number, + print_mac(mac, net_dev->dev_addr), + brdev->mac_was_set ? "set" : "auto"); list_for_each_entry(brvcc, &brdev->brvccs, brvccs) { seq_printf(seq, " vcc %d.%d.%d: encaps=%s" diff --git a/net/atm/lec.c b/net/atm/lec.c index 813a090dcaf..c909c76223e 100644 --- a/net/atm/lec.c +++ b/net/atm/lec.c @@ -266,6 +266,7 @@ static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev) char buf[300]; int i = 0; #endif /* DUMP_PACKETS >0 */ + DECLARE_MAC_BUF(mac); pr_debug("lec_start_xmit called\n"); if (!priv->lecd) { @@ -373,19 +374,15 @@ static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev) if (entry && (entry->tx_wait.qlen < LEC_UNRES_QUE_LEN)) { pr_debug("%s:lec_start_xmit: queuing packet, ", dev->name); - pr_debug("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n", - lec_h->h_dest[0], lec_h->h_dest[1], - lec_h->h_dest[2], lec_h->h_dest[3], - lec_h->h_dest[4], lec_h->h_dest[5]); + pr_debug("MAC address %s\n", + print_mac(mac, lec_h->h_dest)); skb_queue_tail(&entry->tx_wait, skb); } else { pr_debug ("%s:lec_start_xmit: tx queue full or no arp entry, dropping, ", dev->name); - pr_debug("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n", - lec_h->h_dest[0], lec_h->h_dest[1], - lec_h->h_dest[2], lec_h->h_dest[3], - lec_h->h_dest[4], lec_h->h_dest[5]); + pr_debug("MAC address %s\n", + print_mac(mac, lec_h->h_dest)); priv->stats.tx_dropped++; dev_kfree_skb(skb); } @@ -397,9 +394,8 @@ static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev) while (entry && (skb2 = skb_dequeue(&entry->tx_wait))) { pr_debug("lec.c: emptying tx queue, "); - pr_debug("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n", - lec_h->h_dest[0], lec_h->h_dest[1], lec_h->h_dest[2], - lec_h->h_dest[3], lec_h->h_dest[4], lec_h->h_dest[5]); + pr_debug("MAC address %s\n", + print_mac(mac, lec_h->h_dest)); lec_send(vcc, skb2, priv); } @@ -453,6 +449,7 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb) struct lec_arp_table *entry; int i; char *tmp; /* FIXME */ + DECLARE_MAC_BUF(mac); atomic_sub(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc); mesg = (struct atmlec_msg *)skb->data; @@ -539,13 +536,9 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb) struct net_bridge_fdb_entry *f; pr_debug - ("%s: bridge zeppelin asks about 0x%02x:%02x:%02x:%02x:%02x:%02x\n", - dev->name, mesg->content.proxy.mac_addr[0], - mesg->content.proxy.mac_addr[1], - mesg->content.proxy.mac_addr[2], - mesg->content.proxy.mac_addr[3], - mesg->content.proxy.mac_addr[4], - mesg->content.proxy.mac_addr[5]); + ("%s: bridge zeppelin asks about %s\n", + dev->name, + print_mac(mac, mesg->content.proxy.mac_addr)); if (br_fdb_get_hook == NULL || dev->br_port == NULL) break; diff --git a/net/core/netpoll.c b/net/core/netpoll.c index bb7523a5b40..e13602d8154 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -534,6 +534,7 @@ out: void netpoll_print_options(struct netpoll *np) { + DECLARE_MAC_BUF(mac); printk(KERN_INFO "%s: local port %d\n", np->name, np->local_port); printk(KERN_INFO "%s: local IP %d.%d.%d.%d\n", @@ -544,15 +545,8 @@ void netpoll_print_options(struct netpoll *np) np->name, np->remote_port); printk(KERN_INFO "%s: remote IP %d.%d.%d.%d\n", np->name, HIPQUAD(np->remote_ip)); - printk(KERN_INFO "%s: remote ethernet address " - "%02x:%02x:%02x:%02x:%02x:%02x\n", - np->name, - np->remote_mac[0], - np->remote_mac[1], - np->remote_mac[2], - np->remote_mac[3], - np->remote_mac[4], - np->remote_mac[5]); + printk(KERN_INFO "%s: remote ethernet address %s\n", + np->name, print_mac(mac, np->remote_mac)); } int netpoll_parse_options(struct netpoll *np, char *opt) diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 94e42be16da..f07bd590f8f 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -599,11 +599,11 @@ static const struct file_operations pktgen_fops = { static int pktgen_if_show(struct seq_file *seq, void *v) { - int i; struct pktgen_dev *pkt_dev = seq->private; __u64 sa; __u64 stopped; __u64 now = getCurUs(); + DECLARE_MAC_BUF(mac); seq_printf(seq, "Params: count %llu min_pkt_size: %u max_pkt_size: %u\n", @@ -648,19 +648,12 @@ static int pktgen_if_show(struct seq_file *seq, void *v) seq_puts(seq, " src_mac: "); - if (is_zero_ether_addr(pkt_dev->src_mac)) - for (i = 0; i < 6; i++) - seq_printf(seq, "%02X%s", pkt_dev->odev->dev_addr[i], - i == 5 ? " " : ":"); - else - for (i = 0; i < 6; i++) - seq_printf(seq, "%02X%s", pkt_dev->src_mac[i], - i == 5 ? " " : ":"); + seq_printf(seq, "%s ", + print_mac(mac, is_zero_ether_addr(pkt_dev->src_mac) ? + pkt_dev->odev->dev_addr : pkt_dev->src_mac)); seq_printf(seq, "dst_mac: "); - for (i = 0; i < 6; i++) - seq_printf(seq, "%02X%s", pkt_dev->dst_mac[i], - i == 5 ? "\n" : ":"); + seq_printf(seq, "%s\n", print_mac(mac, pkt_dev->dst_mac)); seq_printf(seq, " udp_src_min: %d udp_src_max: %d udp_dst_min: %d udp_dst_max: %d\n", diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c index 57c592ed010..2aaf6faf74a 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c @@ -337,3 +337,11 @@ struct net_device *alloc_etherdev_mq(int sizeof_priv, unsigned int queue_count) return alloc_netdev_mq(sizeof_priv, "eth%d", ether_setup, queue_count); } EXPORT_SYMBOL(alloc_etherdev_mq); + +char *print_mac(char *buf, const u8 *addr) +{ + sprintf(buf, MAC_FMT, + addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); + return buf; +} +EXPORT_SYMBOL(print_mac); diff --git a/net/ieee80211/ieee80211_crypt_ccmp.c b/net/ieee80211/ieee80211_crypt_ccmp.c index 2e6b099fc84..0936a3e0210 100644 --- a/net/ieee80211/ieee80211_crypt_ccmp.c +++ b/net/ieee80211/ieee80211_crypt_ccmp.c @@ -297,6 +297,7 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv) int i, blocks, last, len; size_t data_len = skb->len - hdr_len - CCMP_HDR_LEN - CCMP_MIC_LEN; u8 *mic = skb->data + skb->len - CCMP_MIC_LEN; + DECLARE_MAC_BUF(mac); if (skb->len < hdr_len + CCMP_HDR_LEN + CCMP_MIC_LEN) { key->dot11RSNAStatsCCMPFormatErrors++; @@ -309,7 +310,7 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv) if (!(keyidx & (1 << 5))) { if (net_ratelimit()) { printk(KERN_DEBUG "CCMP: received packet without ExtIV" - " flag from " MAC_FMT "\n", MAC_ARG(hdr->addr2)); + " flag from %s\n", print_mac(mac, hdr->addr2)); } key->dot11RSNAStatsCCMPFormatErrors++; return -2; @@ -322,9 +323,9 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv) } if (!key->key_set) { if (net_ratelimit()) { - printk(KERN_DEBUG "CCMP: received packet from " MAC_FMT + printk(KERN_DEBUG "CCMP: received packet from %s" " with keyid=%d that does not have a configured" - " key\n", MAC_ARG(hdr->addr2), keyidx); + " key\n", print_mac(mac, hdr->addr2), keyidx); } return -3; } @@ -339,11 +340,13 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv) if (ccmp_replay_check(pn, key->rx_pn)) { if (net_ratelimit()) { - IEEE80211_DEBUG_DROP("CCMP: replay detected: STA=" MAC_FMT - " previous PN %02x%02x%02x%02x%02x%02x " - "received PN %02x%02x%02x%02x%02x%02x\n", - MAC_ARG(hdr->addr2), MAC_ARG(key->rx_pn), - MAC_ARG(pn)); + IEEE80211_DEBUG_DROP("CCMP: replay detected: STA=%s " + "previous PN %02x%02x%02x%02x%02x%02x " + "received PN %02x%02x%02x%02x%02x%02x\n", + print_mac(mac, hdr->addr2), + key->rx_pn[0], key->rx_pn[1], key->rx_pn[2], + key->rx_pn[3], key->rx_pn[4], key->rx_pn[5], + pn[0], pn[1], pn[2], pn[3], pn[4], pn[5]); } key->dot11RSNAStatsCCMPReplays++; return -4; @@ -371,7 +374,7 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv) if (memcmp(mic, a, CCMP_MIC_LEN) != 0) { if (net_ratelimit()) { printk(KERN_DEBUG "CCMP: decrypt failed: STA=" - MAC_FMT "\n", MAC_ARG(hdr->addr2)); + "%s\n", print_mac(mac, hdr->addr2)); } key->dot11RSNAStatsCCMPDecryptErrors++; return -5; @@ -443,12 +446,16 @@ static int ieee80211_ccmp_get_key(void *key, int len, u8 * seq, void *priv) static char *ieee80211_ccmp_print_stats(char *p, void *priv) { struct ieee80211_ccmp_data *ccmp = priv; + p += sprintf(p, "key[%d] alg=CCMP key_set=%d " "tx_pn=%02x%02x%02x%02x%02x%02x " "rx_pn=%02x%02x%02x%02x%02x%02x " "format_errors=%d replays=%d decrypt_errors=%d\n", ccmp->key_idx, ccmp->key_set, - MAC_ARG(ccmp->tx_pn), MAC_ARG(ccmp->rx_pn), + ccmp->tx_pn[0], ccmp->tx_pn[1], ccmp->tx_pn[2], + ccmp->tx_pn[3], ccmp->tx_pn[4], ccmp->tx_pn[5], + ccmp->rx_pn[0], ccmp->rx_pn[1], ccmp->rx_pn[2], + ccmp->rx_pn[3], ccmp->rx_pn[4], ccmp->rx_pn[5], ccmp->dot11RSNAStatsCCMPFormatErrors, ccmp->dot11RSNAStatsCCMPReplays, ccmp->dot11RSNAStatsCCMPDecryptErrors); diff --git a/net/ieee80211/ieee80211_crypt_tkip.c b/net/ieee80211/ieee80211_crypt_tkip.c index 5a48d8e0aec..6cc54eeca3e 100644 --- a/net/ieee80211/ieee80211_crypt_tkip.c +++ b/net/ieee80211/ieee80211_crypt_tkip.c @@ -359,14 +359,15 @@ static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) u8 rc4key[16], *pos, *icv; u32 crc; struct scatterlist sg; + DECLARE_MAC_BUF(mac); if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) { if (net_ratelimit()) { struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *)skb->data; printk(KERN_DEBUG ": TKIP countermeasures: dropped " - "TX packet to " MAC_FMT "\n", - MAC_ARG(hdr->addr1)); + "TX packet to %s\n", + print_mac(mac, hdr->addr1)); } return -1; } @@ -421,14 +422,15 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) u32 crc; struct scatterlist sg; int plen; + DECLARE_MAC_BUF(mac); hdr = (struct ieee80211_hdr_4addr *)skb->data; if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) { if (net_ratelimit()) { printk(KERN_DEBUG ": TKIP countermeasures: dropped " - "received packet from " MAC_FMT "\n", - MAC_ARG(hdr->addr2)); + "received packet from %s\n", + print_mac(mac, hdr->addr2)); } return -1; } @@ -441,7 +443,7 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) if (!(keyidx & (1 << 5))) { if (net_ratelimit()) { printk(KERN_DEBUG "TKIP: received packet without ExtIV" - " flag from " MAC_FMT "\n", MAC_ARG(hdr->addr2)); + " flag from %s\n", print_mac(mac, hdr->addr2)); } return -2; } @@ -453,9 +455,9 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) } if (!tkey->key_set) { if (net_ratelimit()) { - printk(KERN_DEBUG "TKIP: received packet from " MAC_FMT + printk(KERN_DEBUG "TKIP: received packet from %s" " with keyid=%d that does not have a configured" - " key\n", MAC_ARG(hdr->addr2), keyidx); + " key\n", print_mac(mac, hdr->addr2), keyidx); } return -3; } @@ -465,9 +467,9 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) if (tkip_replay_check(iv32, iv16, tkey->rx_iv32, tkey->rx_iv16)) { if (net_ratelimit()) { - IEEE80211_DEBUG_DROP("TKIP: replay detected: STA=" MAC_FMT + IEEE80211_DEBUG_DROP("TKIP: replay detected: STA=%s" " previous TSC %08x%04x received TSC " - "%08x%04x\n", MAC_ARG(hdr->addr2), + "%08x%04x\n", print_mac(mac, hdr->addr2), tkey->rx_iv32, tkey->rx_iv16, iv32, iv16); } tkey->dot11RSNAStatsTKIPReplays++; @@ -489,8 +491,8 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4)) { if (net_ratelimit()) { printk(KERN_DEBUG ": TKIP: failed to decrypt " - "received packet from " MAC_FMT "\n", - MAC_ARG(hdr->addr2)); + "received packet from %s\n", + print_mac(mac, hdr->addr2)); } return -7; } @@ -508,7 +510,7 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) } if (net_ratelimit()) { IEEE80211_DEBUG_DROP("TKIP: ICV error detected: STA=" - MAC_FMT "\n", MAC_ARG(hdr->addr2)); + "%s\n", print_mac(mac, hdr->addr2)); } tkey->dot11RSNAStatsTKIPICVErrors++; return -5; @@ -639,6 +641,7 @@ static int ieee80211_michael_mic_verify(struct sk_buff *skb, int keyidx, { struct ieee80211_tkip_data *tkey = priv; u8 mic[8]; + DECLARE_MAC_BUF(mac); if (!tkey->key_set) return -1; @@ -651,8 +654,8 @@ static int ieee80211_michael_mic_verify(struct sk_buff *skb, int keyidx, struct ieee80211_hdr_4addr *hdr; hdr = (struct ieee80211_hdr_4addr *)skb->data; printk(KERN_DEBUG "%s: Michael MIC verification failed for " - "MSDU from " MAC_FMT " keyidx=%d\n", - skb->dev ? skb->dev->name : "N/A", MAC_ARG(hdr->addr2), + "MSDU from %s keyidx=%d\n", + skb->dev ? skb->dev->name : "N/A", print_mac(mac, hdr->addr2), keyidx); if (skb->dev) ieee80211_michael_mic_failure(skb->dev, hdr, keyidx); diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c index 6284c99b456..21c0fadde03 100644 --- a/net/ieee80211/ieee80211_rx.c +++ b/net/ieee80211/ieee80211_rx.c @@ -271,6 +271,7 @@ ieee80211_rx_frame_decrypt(struct ieee80211_device *ieee, struct sk_buff *skb, { struct ieee80211_hdr_3addr *hdr; int res, hdrlen; + DECLARE_MAC_BUF(mac); if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL) return 0; @@ -282,8 +283,8 @@ ieee80211_rx_frame_decrypt(struct ieee80211_device *ieee, struct sk_buff *skb, res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv); atomic_dec(&crypt->refcnt); if (res < 0) { - IEEE80211_DEBUG_DROP("decryption failed (SA=" MAC_FMT - ") res=%d\n", MAC_ARG(hdr->addr2), res); + IEEE80211_DEBUG_DROP("decryption failed (SA=%s" + ") res=%d\n", print_mac(mac, hdr->addr2), res); if (res == -2) IEEE80211_DEBUG_DROP("Decryption failed ICV " "mismatch (key %d)\n", @@ -303,6 +304,7 @@ ieee80211_rx_frame_decrypt_msdu(struct ieee80211_device *ieee, { struct ieee80211_hdr_3addr *hdr; int res, hdrlen; + DECLARE_MAC_BUF(mac); if (crypt == NULL || crypt->ops->decrypt_msdu == NULL) return 0; @@ -315,8 +317,8 @@ ieee80211_rx_frame_decrypt_msdu(struct ieee80211_device *ieee, atomic_dec(&crypt->refcnt); if (res < 0) { printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed" - " (SA=" MAC_FMT " keyidx=%d)\n", - ieee->dev->name, MAC_ARG(hdr->addr2), keyidx); + " (SA=%s keyidx=%d)\n", + ieee->dev->name, print_mac(mac, hdr->addr2), keyidx); return -1; } @@ -350,6 +352,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, struct ieee80211_crypt_data *crypt = NULL; int keyidx = 0; int can_be_decrypted = 0; + DECLARE_MAC_BUF(mac); hdr = (struct ieee80211_hdr_4addr *)skb->data; stats = &ieee->stats; @@ -459,8 +462,8 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, * frames silently instead of filling system log with * these reports. */ IEEE80211_DEBUG_DROP("Decryption failed (not set)" - " (SA=" MAC_FMT ")\n", - MAC_ARG(hdr->addr2)); + " (SA=%s)\n", + print_mac(mac, hdr->addr2)); ieee->ieee_stats.rx_discards_undecryptable++; goto rx_dropped; } @@ -471,8 +474,8 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, fc & IEEE80211_FCTL_PROTECTED && ieee->host_decrypt && (keyidx = hostap_rx_frame_decrypt(ieee, skb, crypt)) < 0) { printk(KERN_DEBUG "%s: failed to decrypt mgmt::auth " - "from " MAC_FMT "\n", dev->name, - MAC_ARG(hdr->addr2)); + "from %s\n", dev->name, + print_mac(mac, hdr->addr2)); /* TODO: could inform hostapd about this so that it * could send auth failure report */ goto rx_dropped; @@ -650,8 +653,8 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, * configured */ } else { IEEE80211_DEBUG_DROP("encryption configured, but RX " - "frame not encrypted (SA=" MAC_FMT - ")\n", MAC_ARG(hdr->addr2)); + "frame not encrypted (SA=%s" + ")\n", print_mac(mac, hdr->addr2)); goto rx_dropped; } } @@ -659,9 +662,9 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !ieee->open_wep && !ieee80211_is_eapol_frame(ieee, skb)) { IEEE80211_DEBUG_DROP("dropped unencrypted RX data " - "frame from " MAC_FMT + "frame from %s" " (drop_unencrypted=1)\n", - MAC_ARG(hdr->addr2)); + print_mac(mac, hdr->addr2)); goto rx_dropped; } @@ -1411,6 +1414,8 @@ static int ieee80211_network_init(struct ieee80211_device *ieee, struct ieee8021 struct ieee80211_network *network, struct ieee80211_rx_stats *stats) { + DECLARE_MAC_BUF(mac); + network->qos_data.active = 0; network->qos_data.supported = 0; network->qos_data.param_count = 0; @@ -1457,11 +1462,11 @@ static int ieee80211_network_init(struct ieee80211_device *ieee, struct ieee8021 } if (network->mode == 0) { - IEEE80211_DEBUG_SCAN("Filtered out '%s (" MAC_FMT ")' " + IEEE80211_DEBUG_SCAN("Filtered out '%s (%s)' " "network.\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid)); + print_mac(mac, network->bssid)); return 1; } @@ -1490,6 +1495,7 @@ static void update_network(struct ieee80211_network *dst, { int qos_active; u8 old_param; + DECLARE_MAC_BUF(mac); ieee80211_network_reset(dst); dst->ibss_dfs = src->ibss_dfs; @@ -1503,8 +1509,8 @@ static void update_network(struct ieee80211_network *dst, memcpy(&dst->stats, &src->stats, sizeof(struct ieee80211_rx_stats)); else - IEEE80211_DEBUG_SCAN("Network " MAC_FMT " info received " - "off channel (%d vs. %d)\n", MAC_ARG(src->bssid), + IEEE80211_DEBUG_SCAN("Network %s info received " + "off channel (%d vs. %d)\n", print_mac(mac, src->bssid), dst->channel, src->stats.received_channel); dst->capability = src->capability; @@ -1576,12 +1582,13 @@ static void ieee80211_process_probe_response(struct ieee80211_device struct ieee80211_info_element *info_element = beacon->info_element; #endif unsigned long flags; + DECLARE_MAC_BUF(mac); - IEEE80211_DEBUG_SCAN("'%s' (" MAC_FMT + IEEE80211_DEBUG_SCAN("'%s' (%s" "): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n", escape_essid(info_element->data, info_element->len), - MAC_ARG(beacon->header.addr3), + print_mac(mac, beacon->header.addr3), (beacon->capability & (1 << 0xf)) ? '1' : '0', (beacon->capability & (1 << 0xe)) ? '1' : '0', (beacon->capability & (1 << 0xd)) ? '1' : '0', @@ -1600,10 +1607,10 @@ static void ieee80211_process_probe_response(struct ieee80211_device (beacon->capability & (1 << 0x0)) ? '1' : '0'); if (ieee80211_network_init(ieee, beacon, &network, stats)) { - IEEE80211_DEBUG_SCAN("Dropped '%s' (" MAC_FMT ") via %s.\n", + IEEE80211_DEBUG_SCAN("Dropped '%s' (%s) via %s.\n", escape_essid(info_element->data, info_element->len), - MAC_ARG(beacon->header.addr3), + print_mac(mac, beacon->header.addr3), is_beacon(beacon->header.frame_ctl) ? "BEACON" : "PROBE RESPONSE"); return; @@ -1637,11 +1644,11 @@ static void ieee80211_process_probe_response(struct ieee80211_device /* If there are no more slots, expire the oldest */ list_del(&oldest->list); target = oldest; - IEEE80211_DEBUG_SCAN("Expired '%s' (" MAC_FMT ") from " + IEEE80211_DEBUG_SCAN("Expired '%s' (%s) from " "network list.\n", escape_essid(target->ssid, target->ssid_len), - MAC_ARG(target->bssid)); + print_mac(mac, target->bssid)); ieee80211_network_reset(target); } else { /* Otherwise just pull from the free list */ @@ -1651,10 +1658,10 @@ static void ieee80211_process_probe_response(struct ieee80211_device } #ifdef CONFIG_IEEE80211_DEBUG - IEEE80211_DEBUG_SCAN("Adding '%s' (" MAC_FMT ") via %s.\n", + IEEE80211_DEBUG_SCAN("Adding '%s' (%s) via %s.\n", escape_essid(network.ssid, network.ssid_len), - MAC_ARG(network.bssid), + print_mac(mac, network.bssid), is_beacon(beacon->header.frame_ctl) ? "BEACON" : "PROBE RESPONSE"); #endif @@ -1662,10 +1669,10 @@ static void ieee80211_process_probe_response(struct ieee80211_device network.ibss_dfs = NULL; list_add_tail(&target->list, &ieee->network_list); } else { - IEEE80211_DEBUG_SCAN("Updating '%s' (" MAC_FMT ") via %s.\n", + IEEE80211_DEBUG_SCAN("Updating '%s' (%s) via %s.\n", escape_essid(target->ssid, target->ssid_len), - MAC_ARG(target->bssid), + print_mac(mac, target->bssid), is_beacon(beacon->header.frame_ctl) ? "BEACON" : "PROBE RESPONSE"); update_network(target, &network); diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c index 465b73d5053..9b58dd67acb 100644 --- a/net/ieee80211/ieee80211_wx.c +++ b/net/ieee80211/ieee80211_wx.c @@ -257,6 +257,7 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee, char *ev = extra; char *stop = ev + wrqu->data.length; int i = 0; + DECLARE_MAC_BUF(mac); IEEE80211_DEBUG_WX("Getting scan\n"); @@ -274,10 +275,10 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee, ev = ieee80211_translate_scan(ieee, ev, stop, network); else IEEE80211_DEBUG_SCAN("Not showing network '%s (" - MAC_FMT ")' due to age (%dms).\n", + "%s)' due to age (%dms).\n", escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid), + print_mac(mac, network->bssid), jiffies_to_msecs(jiffies - network-> last_scanned)); diff --git a/net/ieee80211/softmac/ieee80211softmac_assoc.c b/net/ieee80211/softmac/ieee80211softmac_assoc.c index e475f2e1be1..4c0feb2dacd 100644 --- a/net/ieee80211/softmac/ieee80211softmac_assoc.c +++ b/net/ieee80211/softmac/ieee80211softmac_assoc.c @@ -372,6 +372,7 @@ ieee80211softmac_handle_assoc_response(struct net_device * dev, u16 status = le16_to_cpup(&resp->status); struct ieee80211softmac_network *network = NULL; unsigned long flags; + DECLARE_MAC_BUF(mac2); if (unlikely(!mac->running)) return -ENODEV; @@ -388,7 +389,8 @@ ieee80211softmac_handle_assoc_response(struct net_device * dev, /* someone sending us things without us knowing him? Ignore. */ if (!network) { - dprintk(KERN_INFO PFX "Received unrequested assocation response from " MAC_FMT "\n", MAC_ARG(resp->header.addr3)); + dprintk(KERN_INFO PFX "Received unrequested assocation response from %s\n", + print_mac(mac2, resp->header.addr3)); spin_unlock_irqrestore(&mac->lock, flags); return 0; } diff --git a/net/ieee80211/softmac/ieee80211softmac_auth.c b/net/ieee80211/softmac/ieee80211softmac_auth.c index 826c32d2446..855fa0fe641 100644 --- a/net/ieee80211/softmac/ieee80211softmac_auth.c +++ b/net/ieee80211/softmac/ieee80211softmac_auth.c @@ -35,6 +35,7 @@ ieee80211softmac_auth_req(struct ieee80211softmac_device *mac, { struct ieee80211softmac_auth_queue_item *auth; unsigned long flags; + DECLARE_MAC_BUF(mac2); if (net->authenticating || net->authenticated) return 0; @@ -43,7 +44,7 @@ ieee80211softmac_auth_req(struct ieee80211softmac_device *mac, /* Add the network if it's not already added */ ieee80211softmac_add_network(mac, net); - dprintk(KERN_NOTICE PFX "Queueing Authentication Request to "MAC_FMT"\n", MAC_ARG(net->bssid)); + dprintk(KERN_NOTICE PFX "Queueing Authentication Request to %s\n", print_mac(mac2, net->bssid)); /* Queue the auth request */ auth = (struct ieee80211softmac_auth_queue_item *) kmalloc(sizeof(struct ieee80211softmac_auth_queue_item), GFP_KERNEL); @@ -76,6 +77,7 @@ ieee80211softmac_auth_queue(struct work_struct *work) struct ieee80211softmac_auth_queue_item *auth; struct ieee80211softmac_network *net; unsigned long flags; + DECLARE_MAC_BUF(mac2); auth = container_of(work, struct ieee80211softmac_auth_queue_item, work.work); @@ -99,13 +101,14 @@ ieee80211softmac_auth_queue(struct work_struct *work) auth->retry--; spin_unlock_irqrestore(&mac->lock, flags); if (ieee80211softmac_send_mgt_frame(mac, auth->net, IEEE80211_STYPE_AUTH, auth->state)) - dprintk(KERN_NOTICE PFX "Sending Authentication Request to "MAC_FMT" failed (this shouldn't happen, wait for the timeout).\n", MAC_ARG(net->bssid)); + dprintk(KERN_NOTICE PFX "Sending Authentication Request to %s failed (this shouldn't happen, wait for the timeout).\n", + print_mac(mac2, net->bssid)); else - dprintk(KERN_NOTICE PFX "Sent Authentication Request to "MAC_FMT".\n", MAC_ARG(net->bssid)); + dprintk(KERN_NOTICE PFX "Sent Authentication Request to %s.\n", print_mac(mac2, net->bssid)); return; } - printkl(KERN_WARNING PFX "Authentication timed out with "MAC_FMT"\n", MAC_ARG(net->bssid)); + printkl(KERN_WARNING PFX "Authentication timed out with %s\n", print_mac(mac2, net->bssid)); /* Remove this item from the queue */ spin_lock_irqsave(&mac->lock, flags); net->authenticating = 0; @@ -142,6 +145,7 @@ ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth) struct ieee80211softmac_network *net = NULL; unsigned long flags; u8 * data; + DECLARE_MAC_BUF(mac2); if (unlikely(!mac->running)) return -ENODEV; @@ -161,7 +165,7 @@ ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth) /* Make sure that we've got an auth queue item for this request */ if(aq == NULL) { - dprintkl(KERN_DEBUG PFX "Authentication response received from "MAC_FMT" but no queue item exists.\n", MAC_ARG(auth->header.addr2)); + dprintkl(KERN_DEBUG PFX "Authentication response received from %s but no queue item exists.\n", print_mac(mac2, auth->header.addr2)); /* Error #? */ return -1; } @@ -169,7 +173,7 @@ ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth) /* Check for out of order authentication */ if(!net->authenticating) { - dprintkl(KERN_DEBUG PFX "Authentication response received from "MAC_FMT" but did not request authentication.\n",MAC_ARG(auth->header.addr2)); + dprintkl(KERN_DEBUG PFX "Authentication response received from %s but did not request authentication.\n",print_mac(mac2, auth->header.addr2)); return -1; } @@ -187,7 +191,7 @@ ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth) spin_unlock_irqrestore(&mac->lock, flags); /* Send event */ - printkl(KERN_NOTICE PFX "Open Authentication completed with "MAC_FMT"\n", MAC_ARG(net->bssid)); + printkl(KERN_NOTICE PFX "Open Authentication completed with %s\n", print_mac(mac2, net->bssid)); ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_AUTHENTICATED, net); break; default: @@ -197,8 +201,8 @@ ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth) net->authenticating = 0; spin_unlock_irqrestore(&mac->lock, flags); - printkl(KERN_NOTICE PFX "Open Authentication with "MAC_FMT" failed, error code: %i\n", - MAC_ARG(net->bssid), le16_to_cpup(&auth->status)); + printkl(KERN_NOTICE PFX "Open Authentication with %s failed, error code: %i\n", + print_mac(mac2, net->bssid), le16_to_cpup(&auth->status)); /* Count the error? */ break; } @@ -253,13 +257,13 @@ ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth) net->authenticating = 0; net->authenticated = 1; spin_unlock_irqrestore(&mac->lock, flags); - printkl(KERN_NOTICE PFX "Shared Key Authentication completed with "MAC_FMT"\n", - MAC_ARG(net->bssid)); + printkl(KERN_NOTICE PFX "Shared Key Authentication completed with %s\n", + print_mac(mac2, net->bssid)); ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_AUTHENTICATED, net); break; default: - printkl(KERN_NOTICE PFX "Shared Key Authentication with "MAC_FMT" failed, error code: %i\n", - MAC_ARG(net->bssid), le16_to_cpup(&auth->status)); + printkl(KERN_NOTICE PFX "Shared Key Authentication with %s failed, error code: %i\n", + print_mac(mac2, net->bssid), le16_to_cpup(&auth->status)); /* Lock and reset flags */ spin_lock_irqsave(&mac->lock, flags); net->authenticating = 0; @@ -375,6 +379,7 @@ ieee80211softmac_deauth_resp(struct net_device *dev, struct ieee80211_deauth *de struct ieee80211softmac_network *net = NULL; struct ieee80211softmac_device *mac = ieee80211_priv(dev); + DECLARE_MAC_BUF(mac2); if (unlikely(!mac->running)) return -ENODEV; @@ -387,8 +392,8 @@ ieee80211softmac_deauth_resp(struct net_device *dev, struct ieee80211_deauth *de net = ieee80211softmac_get_network_by_bssid(mac, deauth->header.addr2); if (net == NULL) { - dprintkl(KERN_DEBUG PFX "Received deauthentication packet from "MAC_FMT", but that network is unknown.\n", - MAC_ARG(deauth->header.addr2)); + dprintkl(KERN_DEBUG PFX "Received deauthentication packet from %s, but that network is unknown.\n", + print_mac(mac2, deauth->header.addr2)); return 0; } diff --git a/net/ieee80211/softmac/ieee80211softmac_wx.c b/net/ieee80211/softmac/ieee80211softmac_wx.c index 5742dc803b7..8e8ad08a411 100644 --- a/net/ieee80211/softmac/ieee80211softmac_wx.c +++ b/net/ieee80211/softmac/ieee80211softmac_wx.c @@ -72,6 +72,7 @@ ieee80211softmac_wx_set_essid(struct net_device *net_dev, struct ieee80211softmac_device *sm = ieee80211_priv(net_dev); struct ieee80211softmac_auth_queue_item *authptr; int length = 0; + DECLARE_MAC_BUF(mac); check_assoc_again: mutex_lock(&sm->associnfo.mutex); diff --git a/net/irda/irlan/irlan_client.c b/net/irda/irlan/irlan_client.c index a4c1c954582..87039c2fb6a 100644 --- a/net/irda/irlan/irlan_client.c +++ b/net/irda/irlan/irlan_client.c @@ -436,6 +436,7 @@ static void irlan_check_response_param(struct irlan_cb *self, char *param, __u16 tmp_cpu; /* Temporary value in host order */ __u8 *bytes; int i; + DECLARE_MAC_BUF(mac); IRDA_DEBUG(4, "%s(), parm=%s\n", __FUNCTION__ , param); @@ -520,9 +521,8 @@ static void irlan_check_response_param(struct irlan_cb *self, char *param, /* FILTER_ENTRY, have we got an ethernet address? */ if (strcmp(param, "FILTER_ENTRY") == 0) { bytes = value; - IRDA_DEBUG(4, "Ethernet address = %02x:%02x:%02x:%02x:%02x:%02x\n", - bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], - bytes[5]); + IRDA_DEBUG(4, "Ethernet address = %s\n", + print_mac(mac, bytes)); for (i = 0; i < 6; i++) self->dev->dev_addr[i] = bytes[i]; } diff --git a/net/llc/llc_proc.c b/net/llc/llc_proc.c index 4865d82896b..cb34bc0518e 100644 --- a/net/llc/llc_proc.c +++ b/net/llc/llc_proc.c @@ -25,10 +25,10 @@ #include #include -static void llc_ui_format_mac(struct seq_file *seq, unsigned char *mac) +static void llc_ui_format_mac(struct seq_file *seq, u8 *addr) { - seq_printf(seq, "%02X:%02X:%02X:%02X:%02X:%02X", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + DECLARE_MAC_BUF(mac); + seq_printf(seq, "%s", print_mac(mac, addr)); } static struct sock *llc_get_sk_idx(loff_t pos) @@ -128,8 +128,10 @@ static int llc_seq_socket_show(struct seq_file *seq, void *v) if (llc->dev) llc_ui_format_mac(seq, llc->dev->dev_addr); - else - seq_printf(seq, "00:00:00:00:00:00"); + else { + u8 addr[6] = {0,0,0,0,0,0}; + llc_ui_format_mac(seq, addr); + } seq_printf(seq, "@%02X ", llc->sap->laddr.lsap); llc_ui_format_mac(seq, llc->daddr.mac); seq_printf(seq, "@%02X %8d %8d %2d %3d %4d\n", llc->daddr.lsap, diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index 8e4a1bcd16e..c881524c872 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c @@ -262,11 +262,12 @@ void ieee80211_debugfs_key_sta_link(struct ieee80211_key *key, struct sta_info *sta) { char buf[50]; + DECLARE_MAC_BUF(mac); if (!key->debugfs.dir) return; - sprintf(buf, "../../stations/" MAC_FMT, MAC_ARG(sta->addr)); + sprintf(buf, "../../stations/%s", print_mac(mac, sta->addr)); key->debugfs.stalink = debugfs_create_symlink("station", key->debugfs.dir, buf); } diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 8ceda33efc1..9efb84c47bb 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -66,7 +66,8 @@ static ssize_t ieee80211_if_fmt_##name( \ const struct ieee80211_sub_if_data *sdata, char *buf, \ int buflen) \ { \ - return scnprintf(buf, buflen, MAC_FMT "\n", MAC_ARG(sdata->field));\ + DECLARE_MAC_BUF(mac); \ + return scnprintf(buf, buflen, "%s\n", print_mac(mac, sdata->field));\ } #define __IEEE80211_IF_FILE(name) \ diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 2daaa802bbd..f7c717c906d 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -203,15 +203,15 @@ STA_OPS(wme_tx_queue); void ieee80211_sta_debugfs_add(struct sta_info *sta) { - char buf[3*6]; struct dentry *stations_dir = sta->local->debugfs.stations; + DECLARE_MAC_BUF(mac); if (!stations_dir) return; - sprintf(buf, MAC_FMT, MAC_ARG(sta->addr)); + print_mac(mac, sta->addr); - sta->debugfs.dir = debugfs_create_dir(buf, stations_dir); + sta->debugfs.dir = debugfs_create_dir(mac, stations_dir); if (!sta->debugfs.dir) return; diff --git a/net/mac80211/event.c b/net/mac80211/event.c index 68a526cb762..2280f40b456 100644 --- a/net/mac80211/event.c +++ b/net/mac80211/event.c @@ -22,13 +22,14 @@ void mac80211_ev_michael_mic_failure(struct net_device *dev, int keyidx, { union iwreq_data wrqu; char *buf = kmalloc(128, GFP_ATOMIC); + DECLARE_MAC_BUF(mac); if (buf) { /* TODO: needed parameters: count, key type, TSC */ sprintf(buf, "MLME-MICHAELMICFAILURE.indication(" - "keyid=%d %scast addr=" MAC_FMT ")", + "keyid=%d %scast addr=%s)", keyidx, hdr->addr1[0] & 0x01 ? "broad" : "uni", - MAC_ARG(hdr->addr2)); + print_mac(mac, hdr->addr2)); memset(&wrqu, 0, sizeof(wrqu)); wrqu.data.length = strlen(buf); wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf); diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 0c1f7b2e157..4229d150e78 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -602,6 +602,7 @@ int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr) struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct sta_info *sta; + DECLARE_MAC_BUF(mac); if (compare_ether_addr(remote_addr, sdata->u.wds.remote_addr) == 0) return 0; @@ -619,8 +620,8 @@ int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr) sta_info_put(sta); } else { printk(KERN_DEBUG "%s: could not find STA entry for WDS link " - "peer " MAC_FMT "\n", - dev->name, MAC_ARG(sdata->u.wds.remote_addr)); + "peer %s\n", + dev->name, print_mac(mac, sdata->u.wds.remote_addr)); } /* Update WDS link data */ diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index 51dca21f77c..6ccdde82bde 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c @@ -98,9 +98,10 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, sta = sta_info_get(local, sta_addr); if (!sta) { #ifdef CONFIG_MAC80211_VERBOSE_DEBUG + DECLARE_MAC_BUF(mac); printk(KERN_DEBUG "%s: set_encrypt - unknown addr " - MAC_FMT "\n", - dev->name, MAC_ARG(sta_addr)); + "%s\n", + dev->name, print_mac(mac, sta_addr)); #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ return -ENOENT; diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 8fdbd38e02c..f47cbd294ce 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -319,14 +319,15 @@ static void ieee80211_handle_erp_ie(struct net_device *dev, u8 erp_value) int use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0; int preamble_mode = (erp_value & WLAN_ERP_BARKER_PREAMBLE) != 0; u8 changes = 0; + DECLARE_MAC_BUF(mac); if (use_protection != !!(sdata->flags & IEEE80211_SDATA_USE_PROTECTION)) { if (net_ratelimit()) { printk(KERN_DEBUG "%s: CTS protection %s (BSSID=" - MAC_FMT ")\n", + "%s)\n", dev->name, use_protection ? "enabled" : "disabled", - MAC_ARG(ifsta->bssid)); + print_mac(mac, ifsta->bssid)); } if (use_protection) sdata->flags |= IEEE80211_SDATA_USE_PROTECTION; @@ -338,11 +339,11 @@ static void ieee80211_handle_erp_ie(struct net_device *dev, u8 erp_value) if (preamble_mode != !(sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE)) { if (net_ratelimit()) { printk(KERN_DEBUG "%s: switched to %s barker preamble" - " (BSSID=" MAC_FMT ")\n", + " (BSSID=%s)\n", dev->name, (preamble_mode == WLAN_ERP_PREAMBLE_SHORT) ? "short" : "long", - MAC_ARG(ifsta->bssid)); + print_mac(mac, ifsta->bssid)); } if (preamble_mode) sdata->flags &= ~IEEE80211_SDATA_SHORT_PREAMBLE; @@ -524,18 +525,20 @@ static void ieee80211_send_auth(struct net_device *dev, static void ieee80211_authenticate(struct net_device *dev, struct ieee80211_if_sta *ifsta) { + DECLARE_MAC_BUF(mac); + ifsta->auth_tries++; if (ifsta->auth_tries > IEEE80211_AUTH_MAX_TRIES) { - printk(KERN_DEBUG "%s: authentication with AP " MAC_FMT + printk(KERN_DEBUG "%s: authentication with AP %s" " timed out\n", - dev->name, MAC_ARG(ifsta->bssid)); + dev->name, print_mac(mac, ifsta->bssid)); ifsta->state = IEEE80211_DISABLED; return; } ifsta->state = IEEE80211_AUTHENTICATE; - printk(KERN_DEBUG "%s: authenticate with AP " MAC_FMT "\n", - dev->name, MAC_ARG(ifsta->bssid)); + printk(KERN_DEBUG "%s: authenticate with AP %s\n", + dev->name, print_mac(mac, ifsta->bssid)); ieee80211_send_auth(dev, ifsta, 1, NULL, 0, 0); @@ -744,18 +747,20 @@ static int ieee80211_privacy_mismatch(struct net_device *dev, static void ieee80211_associate(struct net_device *dev, struct ieee80211_if_sta *ifsta) { + DECLARE_MAC_BUF(mac); + ifsta->assoc_tries++; if (ifsta->assoc_tries > IEEE80211_ASSOC_MAX_TRIES) { - printk(KERN_DEBUG "%s: association with AP " MAC_FMT + printk(KERN_DEBUG "%s: association with AP %s" " timed out\n", - dev->name, MAC_ARG(ifsta->bssid)); + dev->name, print_mac(mac, ifsta->bssid)); ifsta->state = IEEE80211_DISABLED; return; } ifsta->state = IEEE80211_ASSOCIATE; - printk(KERN_DEBUG "%s: associate with AP " MAC_FMT "\n", - dev->name, MAC_ARG(ifsta->bssid)); + printk(KERN_DEBUG "%s: associate with AP %s\n", + dev->name, print_mac(mac, ifsta->bssid)); if (ieee80211_privacy_mismatch(dev, ifsta)) { printk(KERN_DEBUG "%s: mismatch in privacy configuration and " "mixed-cell disabled - abort association\n", dev->name); @@ -775,6 +780,7 @@ static void ieee80211_associated(struct net_device *dev, struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct sta_info *sta; int disassoc; + DECLARE_MAC_BUF(mac); /* TODO: start monitoring current AP signal quality and number of * missed beacons. Scan other channels every now and then and search @@ -785,8 +791,8 @@ static void ieee80211_associated(struct net_device *dev, sta = sta_info_get(local, ifsta->bssid); if (!sta) { - printk(KERN_DEBUG "%s: No STA entry for own AP " MAC_FMT "\n", - dev->name, MAC_ARG(ifsta->bssid)); + printk(KERN_DEBUG "%s: No STA entry for own AP %s\n", + dev->name, print_mac(mac, ifsta->bssid)); disassoc = 1; } else { disassoc = 0; @@ -794,9 +800,9 @@ static void ieee80211_associated(struct net_device *dev, sta->last_rx + IEEE80211_MONITORING_INTERVAL)) { if (ifsta->flags & IEEE80211_STA_PROBEREQ_POLL) { printk(KERN_DEBUG "%s: No ProbeResp from " - "current AP " MAC_FMT " - assume out of " + "current AP %s - assume out of " "range\n", - dev->name, MAC_ARG(ifsta->bssid)); + dev->name, print_mac(mac, ifsta->bssid)); disassoc = 1; sta_info_free(sta); } else @@ -944,37 +950,38 @@ static void ieee80211_rx_mgmt_auth(struct net_device *dev, { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); u16 auth_alg, auth_transaction, status_code; + DECLARE_MAC_BUF(mac); if (ifsta->state != IEEE80211_AUTHENTICATE && sdata->type != IEEE80211_IF_TYPE_IBSS) { printk(KERN_DEBUG "%s: authentication frame received from " - MAC_FMT ", but not in authenticate state - ignored\n", - dev->name, MAC_ARG(mgmt->sa)); + "%s, but not in authenticate state - ignored\n", + dev->name, print_mac(mac, mgmt->sa)); return; } if (len < 24 + 6) { printk(KERN_DEBUG "%s: too short (%zd) authentication frame " - "received from " MAC_FMT " - ignored\n", - dev->name, len, MAC_ARG(mgmt->sa)); + "received from %s - ignored\n", + dev->name, len, print_mac(mac, mgmt->sa)); return; } if (sdata->type != IEEE80211_IF_TYPE_IBSS && memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) { printk(KERN_DEBUG "%s: authentication frame received from " - "unknown AP (SA=" MAC_FMT " BSSID=" MAC_FMT ") - " - "ignored\n", dev->name, MAC_ARG(mgmt->sa), - MAC_ARG(mgmt->bssid)); + "unknown AP (SA=%s BSSID=%s) - " + "ignored\n", dev->name, print_mac(mac, mgmt->sa), + print_mac(mac, mgmt->bssid)); return; } if (sdata->type != IEEE80211_IF_TYPE_IBSS && memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0) { printk(KERN_DEBUG "%s: authentication frame received from " - "unknown BSSID (SA=" MAC_FMT " BSSID=" MAC_FMT ") - " - "ignored\n", dev->name, MAC_ARG(mgmt->sa), - MAC_ARG(mgmt->bssid)); + "unknown BSSID (SA=%s BSSID=%s) - " + "ignored\n", dev->name, print_mac(mac, mgmt->sa), + print_mac(mac, mgmt->bssid)); return; } @@ -982,9 +989,9 @@ static void ieee80211_rx_mgmt_auth(struct net_device *dev, auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); status_code = le16_to_cpu(mgmt->u.auth.status_code); - printk(KERN_DEBUG "%s: RX authentication from " MAC_FMT " (alg=%d " + printk(KERN_DEBUG "%s: RX authentication from %s (alg=%d " "transaction=%d status=%d)\n", - dev->name, MAC_ARG(mgmt->sa), auth_alg, + dev->name, print_mac(mac, mgmt->sa), auth_alg, auth_transaction, status_code); if (sdata->type == IEEE80211_IF_TYPE_IBSS) { @@ -1071,27 +1078,28 @@ static void ieee80211_rx_mgmt_deauth(struct net_device *dev, size_t len) { u16 reason_code; + DECLARE_MAC_BUF(mac); if (len < 24 + 2) { printk(KERN_DEBUG "%s: too short (%zd) deauthentication frame " - "received from " MAC_FMT " - ignored\n", - dev->name, len, MAC_ARG(mgmt->sa)); + "received from %s - ignored\n", + dev->name, len, print_mac(mac, mgmt->sa)); return; } if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) { printk(KERN_DEBUG "%s: deauthentication frame received from " - "unknown AP (SA=" MAC_FMT " BSSID=" MAC_FMT ") - " - "ignored\n", dev->name, MAC_ARG(mgmt->sa), - MAC_ARG(mgmt->bssid)); + "unknown AP (SA=%s BSSID=%s) - " + "ignored\n", dev->name, print_mac(mac, mgmt->sa), + print_mac(mac, mgmt->bssid)); return; } reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); - printk(KERN_DEBUG "%s: RX deauthentication from " MAC_FMT + printk(KERN_DEBUG "%s: RX deauthentication from %s" " (reason=%d)\n", - dev->name, MAC_ARG(mgmt->sa), reason_code); + dev->name, print_mac(mac, mgmt->sa), reason_code); if (ifsta->flags & IEEE80211_STA_AUTHENTICATED) { printk(KERN_DEBUG "%s: deauthenticated\n", dev->name); @@ -1116,27 +1124,28 @@ static void ieee80211_rx_mgmt_disassoc(struct net_device *dev, size_t len) { u16 reason_code; + DECLARE_MAC_BUF(mac); if (len < 24 + 2) { printk(KERN_DEBUG "%s: too short (%zd) disassociation frame " - "received from " MAC_FMT " - ignored\n", - dev->name, len, MAC_ARG(mgmt->sa)); + "received from %s - ignored\n", + dev->name, len, print_mac(mac, mgmt->sa)); return; } if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) { printk(KERN_DEBUG "%s: disassociation frame received from " - "unknown AP (SA=" MAC_FMT " BSSID=" MAC_FMT ") - " - "ignored\n", dev->name, MAC_ARG(mgmt->sa), - MAC_ARG(mgmt->bssid)); + "unknown AP (SA=%s BSSID=%s) - " + "ignored\n", dev->name, print_mac(mac, mgmt->sa), + print_mac(mac, mgmt->bssid)); return; } reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); - printk(KERN_DEBUG "%s: RX disassociation from " MAC_FMT + printk(KERN_DEBUG "%s: RX disassociation from %s" " (reason=%d)\n", - dev->name, MAC_ARG(mgmt->sa), reason_code); + dev->name, print_mac(mac, mgmt->sa), reason_code); if (ifsta->flags & IEEE80211_STA_ASSOCIATED) printk(KERN_DEBUG "%s: disassociated\n", dev->name); @@ -1165,29 +1174,30 @@ static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev, struct ieee802_11_elems elems; u8 *pos; int i, j; + DECLARE_MAC_BUF(mac); /* AssocResp and ReassocResp have identical structure, so process both * of them in this function. */ if (ifsta->state != IEEE80211_ASSOCIATE) { printk(KERN_DEBUG "%s: association frame received from " - MAC_FMT ", but not in associate state - ignored\n", - dev->name, MAC_ARG(mgmt->sa)); + "%s, but not in associate state - ignored\n", + dev->name, print_mac(mac, mgmt->sa)); return; } if (len < 24 + 6) { printk(KERN_DEBUG "%s: too short (%zd) association frame " - "received from " MAC_FMT " - ignored\n", - dev->name, len, MAC_ARG(mgmt->sa)); + "received from %s - ignored\n", + dev->name, len, print_mac(mac, mgmt->sa)); return; } if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) { printk(KERN_DEBUG "%s: association frame received from " - "unknown AP (SA=" MAC_FMT " BSSID=" MAC_FMT ") - " - "ignored\n", dev->name, MAC_ARG(mgmt->sa), - MAC_ARG(mgmt->bssid)); + "unknown AP (SA=%s BSSID=%s) - " + "ignored\n", dev->name, print_mac(mac, mgmt->sa), + print_mac(mac, mgmt->bssid)); return; } @@ -1199,9 +1209,9 @@ static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev, "set\n", dev->name, aid); aid &= ~(BIT(15) | BIT(14)); - printk(KERN_DEBUG "%s: RX %sssocResp from " MAC_FMT " (capab=0x%x " + printk(KERN_DEBUG "%s: RX %sssocResp from %s (capab=0x%x " "status=%d aid=%d)\n", - dev->name, reassoc ? "Rea" : "A", MAC_ARG(mgmt->sa), + dev->name, reassoc ? "Rea" : "A", print_mac(mac, mgmt->sa), capab_info, status_code, aid); if (status_code != WLAN_STATUS_SUCCESS) { @@ -1435,14 +1445,16 @@ static void ieee80211_rx_bss_info(struct net_device *dev, struct sta_info *sta; struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); u64 timestamp; + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); if (!beacon && memcmp(mgmt->da, dev->dev_addr, ETH_ALEN)) return; /* ignore ProbeResp to foreign address */ #if 0 - printk(KERN_DEBUG "%s: RX %s from " MAC_FMT " to " MAC_FMT "\n", + printk(KERN_DEBUG "%s: RX %s from %s to %s\n", dev->name, beacon ? "Beacon" : "Probe Response", - MAC_ARG(mgmt->sa), MAC_ARG(mgmt->da)); + print_mac(mac, mgmt->sa), print_mac(mac2, mgmt->da)); #endif baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt; @@ -1461,10 +1473,10 @@ static void ieee80211_rx_bss_info(struct net_device *dev, else tsf = -1LLU; if (time_after(jiffies, last_tsf_debug + 5 * HZ)) { - printk(KERN_DEBUG "RX beacon SA=" MAC_FMT " BSSID=" - MAC_FMT " TSF=0x%llx BCN=0x%llx diff=%lld " + printk(KERN_DEBUG "RX beacon SA=%s BSSID=" + "%s TSF=0x%llx BCN=0x%llx diff=%lld " "@%lu\n", - MAC_ARG(mgmt->sa), MAC_ARG(mgmt->bssid), + print_mac(mac, mgmt->sa), print_mac(mac2, mgmt->bssid), (unsigned long long)tsf, (unsigned long long)timestamp, (unsigned long long)(tsf - timestamp), @@ -1518,9 +1530,9 @@ static void ieee80211_rx_bss_info(struct net_device *dev, } if (sta->supp_rates != prev_rates) { printk(KERN_DEBUG "%s: updated supp_rates set for " - MAC_FMT " based on beacon info (0x%x & 0x%x -> " + "%s based on beacon info (0x%x & 0x%x -> " "0x%x)\n", - dev->name, MAC_ARG(sta->addr), prev_rates, + dev->name, print_mac(mac, sta->addr), prev_rates, supp_rates, sta->supp_rates); } sta_info_put(sta); @@ -1722,6 +1734,11 @@ static void ieee80211_rx_mgmt_probe_req(struct net_device *dev, struct sk_buff *skb; struct ieee80211_mgmt *resp; u8 *pos, *end; + DECLARE_MAC_BUF(mac); +#ifdef CONFIG_MAC80211_IBSS_DEBUG + DECLARE_MAC_BUF(mac2); + DECLARE_MAC_BUF(mac3); +#endif if (sdata->type != IEEE80211_IF_TYPE_IBSS || ifsta->state != IEEE80211_IBSS_JOINED || @@ -1734,10 +1751,10 @@ static void ieee80211_rx_mgmt_probe_req(struct net_device *dev, tx_last_beacon = 1; #ifdef CONFIG_MAC80211_IBSS_DEBUG - printk(KERN_DEBUG "%s: RX ProbeReq SA=" MAC_FMT " DA=" MAC_FMT " BSSID=" - MAC_FMT " (tx_last_beacon=%d)\n", - dev->name, MAC_ARG(mgmt->sa), MAC_ARG(mgmt->da), - MAC_ARG(mgmt->bssid), tx_last_beacon); + printk(KERN_DEBUG "%s: RX ProbeReq SA=%s DA=%s BSSID=" + "%s (tx_last_beacon=%d)\n", + dev->name, print_mac(mac, mgmt->sa), print_mac(mac2, mgmt->da), + print_mac(mac3, mgmt->bssid), tx_last_beacon); #endif /* CONFIG_MAC80211_IBSS_DEBUG */ if (!tx_last_beacon) @@ -1753,8 +1770,8 @@ static void ieee80211_rx_mgmt_probe_req(struct net_device *dev, pos + 2 + pos[1] > end) { if (net_ratelimit()) { printk(KERN_DEBUG "%s: Invalid SSID IE in ProbeReq " - "from " MAC_FMT "\n", - dev->name, MAC_ARG(mgmt->sa)); + "from %s\n", + dev->name, print_mac(mac, mgmt->sa)); } return; } @@ -1773,8 +1790,8 @@ static void ieee80211_rx_mgmt_probe_req(struct net_device *dev, resp = (struct ieee80211_mgmt *) skb->data; memcpy(resp->da, mgmt->sa, ETH_ALEN); #ifdef CONFIG_MAC80211_IBSS_DEBUG - printk(KERN_DEBUG "%s: Sending ProbeResp to " MAC_FMT "\n", - dev->name, MAC_ARG(resp->da)); + printk(KERN_DEBUG "%s: Sending ProbeResp to %s\n", + dev->name, print_mac(mac, resp->da)); #endif /* CONFIG_MAC80211_IBSS_DEBUG */ ieee80211_sta_tx(dev, skb, 0); } @@ -1925,13 +1942,14 @@ static void ieee80211_sta_expire(struct net_device *dev) struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct sta_info *sta, *tmp; LIST_HEAD(tmp_list); + DECLARE_MAC_BUF(mac); write_lock_bh(&local->sta_lock); list_for_each_entry_safe(sta, tmp, &local->sta_list, list) if (time_after(jiffies, sta->last_rx + IEEE80211_IBSS_INACTIVITY_LIMIT)) { - printk(KERN_DEBUG "%s: expiring inactive STA " MAC_FMT - "\n", dev->name, MAC_ARG(sta->addr)); + printk(KERN_DEBUG "%s: expiring inactive STA %s\n", + dev->name, print_mac(mac, sta->addr)); __sta_info_get(sta); sta_info_remove(sta); list_add(&sta->list, &tmp_list); @@ -2362,6 +2380,7 @@ static int ieee80211_sta_create_ibss(struct net_device *dev, struct ieee80211_hw_mode *mode; u8 bssid[ETH_ALEN], *pos; int i; + DECLARE_MAC_BUF(mac); #if 0 /* Easier testing, use fixed BSSID. */ @@ -2377,8 +2396,8 @@ static int ieee80211_sta_create_ibss(struct net_device *dev, bssid[0] |= 0x02; #endif - printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID " MAC_FMT "\n", - dev->name, MAC_ARG(bssid)); + printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %s\n", + dev->name, print_mac(mac, bssid)); bss = ieee80211_rx_bss_add(dev, bssid); if (!bss) @@ -2418,6 +2437,8 @@ static int ieee80211_sta_find_ibss(struct net_device *dev, int found = 0; u8 bssid[ETH_ALEN]; int active_ibss; + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); if (ifsta->ssid_len == 0) return -EINVAL; @@ -2434,8 +2455,8 @@ static int ieee80211_sta_find_ibss(struct net_device *dev, || !(bss->capability & WLAN_CAPABILITY_IBSS)) continue; #ifdef CONFIG_MAC80211_IBSS_DEBUG - printk(KERN_DEBUG " bssid=" MAC_FMT " found\n", - MAC_ARG(bss->bssid)); + printk(KERN_DEBUG " bssid=%s found\n", + print_mac(mac, bss->bssid)); #endif /* CONFIG_MAC80211_IBSS_DEBUG */ memcpy(bssid, bss->bssid, ETH_ALEN); found = 1; @@ -2445,14 +2466,14 @@ static int ieee80211_sta_find_ibss(struct net_device *dev, spin_unlock_bh(&local->sta_bss_lock); #ifdef CONFIG_MAC80211_IBSS_DEBUG - printk(KERN_DEBUG " sta_find_ibss: selected " MAC_FMT " current " - MAC_FMT "\n", MAC_ARG(bssid), MAC_ARG(ifsta->bssid)); + printk(KERN_DEBUG " sta_find_ibss: selected %s current " + "%s\n", print_mac(mac, bssid), print_mac(mac2, ifsta->bssid)); #endif /* CONFIG_MAC80211_IBSS_DEBUG */ if (found && memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0 && (bss = ieee80211_rx_bss_get(dev, bssid))) { - printk(KERN_DEBUG "%s: Selected IBSS BSSID " MAC_FMT + printk(KERN_DEBUG "%s: Selected IBSS BSSID %s" " based on configured SSID\n", - dev->name, MAC_ARG(bssid)); + dev->name, print_mac(mac, bssid)); return ieee80211_sta_join_ibss(dev, ifsta, bss); } #ifdef CONFIG_MAC80211_IBSS_DEBUG @@ -3070,19 +3091,20 @@ struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev, struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct sta_info *sta; struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + DECLARE_MAC_BUF(mac); /* TODO: Could consider removing the least recently used entry and * allow new one to be added. */ if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) { if (net_ratelimit()) { printk(KERN_DEBUG "%s: No room for a new IBSS STA " - "entry " MAC_FMT "\n", dev->name, MAC_ARG(addr)); + "entry %s\n", dev->name, print_mac(mac, addr)); } return NULL; } - printk(KERN_DEBUG "%s: Adding new IBSS station " MAC_FMT " (dev=%s)\n", - local->mdev->name, MAC_ARG(addr), dev->name); + printk(KERN_DEBUG "%s: Adding new IBSS station %s (dev=%s)\n", + local->mdev->name, print_mac(mac, addr), dev->name); sta = sta_info_add(local, dev, addr, GFP_ATOMIC); if (!sta) diff --git a/net/mac80211/key.c b/net/mac80211/key.c index dd6fc4aa3ff..c10e53afbb4 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -63,6 +63,7 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key) { const u8 *addr; int ret; + DECLARE_MAC_BUF(mac); if (!key->local->ops->set_key) return; @@ -78,15 +79,16 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key) if (ret && ret != -ENOSPC && ret != -EOPNOTSUPP) printk(KERN_ERR "mac80211-%s: failed to set key " - "(%d, " MAC_FMT ") to hardware (%d)\n", + "(%d, %s) to hardware (%d)\n", wiphy_name(key->local->hw.wiphy), - key->conf.keyidx, MAC_ARG(addr), ret); + key->conf.keyidx, print_mac(mac, addr), ret); } static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) { const u8 *addr; int ret; + DECLARE_MAC_BUF(mac); if (!key->local->ops->set_key) return; @@ -102,9 +104,9 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) if (ret) printk(KERN_ERR "mac80211-%s: failed to remove key " - "(%d, " MAC_FMT ") from hardware (%d)\n", + "(%d, %s) from hardware (%d)\n", wiphy_name(key->local->hw.wiphy), - key->conf.keyidx, MAC_ARG(addr), ret); + key->conf.keyidx, print_mac(mac, addr), ret); key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; } diff --git a/net/mac80211/rc80211_simple.c b/net/mac80211/rc80211_simple.c index ef91ce428ac..314b8de8886 100644 --- a/net/mac80211/rc80211_simple.c +++ b/net/mac80211/rc80211_simple.c @@ -201,9 +201,10 @@ static void rate_control_simple_tx_status(void *priv, struct net_device *dev, srctrl->avg_rate_update = jiffies; if (srctrl->tx_avg_rate_num > 0) { #ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "%s: STA " MAC_FMT " Average rate: " + DECLARE_MAC_BUF(mac); + printk(KERN_DEBUG "%s: STA %s Average rate: " "%d (%d/%d)\n", - dev->name, MAC_ARG(sta->addr), + dev->name, print_mac(mac, sta->addr), srctrl->tx_avg_rate_sum / srctrl->tx_avg_rate_num, srctrl->tx_avg_rate_sum, diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index c985c7a537d..e9dcc6229c3 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -403,6 +403,8 @@ ieee80211_rx_h_load_key(struct ieee80211_txrx_data *rx) static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta) { struct ieee80211_sub_if_data *sdata; + DECLARE_MAC_BUF(mac); + sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); if (sdata->bss) @@ -410,8 +412,8 @@ static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta) sta->flags |= WLAN_STA_PS; sta->pspoll = 0; #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - printk(KERN_DEBUG "%s: STA " MAC_FMT " aid %d enters power " - "save mode\n", dev->name, MAC_ARG(sta->addr), sta->aid); + printk(KERN_DEBUG "%s: STA %s aid %d enters power save mode\n", + dev->name, print_mac(mac, sta->addr), sta->aid); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ } @@ -422,6 +424,7 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta) int sent = 0; struct ieee80211_sub_if_data *sdata; struct ieee80211_tx_packet_data *pkt_data; + DECLARE_MAC_BUF(mac); sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); if (sdata->bss) @@ -435,8 +438,8 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta) bss_tim_clear(local, sdata->bss, sta->aid); } #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - printk(KERN_DEBUG "%s: STA " MAC_FMT " aid %d exits power " - "save mode\n", dev->name, MAC_ARG(sta->addr), sta->aid); + printk(KERN_DEBUG "%s: STA %s aid %d exits power save mode\n", + dev->name, print_mac(mac, sta->addr), sta->aid); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ /* Send all buffered frames to the station */ while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) { @@ -450,9 +453,9 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta) local->total_ps_buffered--; sent++; #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - printk(KERN_DEBUG "%s: STA " MAC_FMT " aid %d send PS frame " + printk(KERN_DEBUG "%s: STA %s aid %d send PS frame " "since STA not sleeping anymore\n", dev->name, - MAC_ARG(sta->addr), sta->aid); + print_mac(mac, sta->addr), sta->aid); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ pkt_data->flags |= IEEE80211_TXPD_REQUEUE; dev_queue_xmit(skb); @@ -590,13 +593,15 @@ ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata, #ifdef CONFIG_MAC80211_DEBUG struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) entry->skb_list.next->data; + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); printk(KERN_DEBUG "%s: RX reassembly removed oldest " "fragment entry (idx=%d age=%lu seq=%d last_frag=%d " - "addr1=" MAC_FMT " addr2=" MAC_FMT "\n", + "addr1=%s addr2=%s\n", sdata->dev->name, idx, jiffies - entry->first_frag_time, entry->seq, - entry->last_frag, MAC_ARG(hdr->addr1), - MAC_ARG(hdr->addr2)); + entry->last_frag, print_mac(mac, hdr->addr1), + print_mac(mac2, hdr->addr2)); #endif /* CONFIG_MAC80211_DEBUG */ __skb_queue_purge(&entry->skb_list); } @@ -662,6 +667,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) unsigned int frag, seq; struct ieee80211_fragment_entry *entry; struct sk_buff *skb; + DECLARE_MAC_BUF(mac); hdr = (struct ieee80211_hdr *) rx->skb->data; sc = le16_to_cpu(hdr->seq_ctrl); @@ -720,10 +726,10 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) if (memcmp(pn, rpn, CCMP_PN_LEN) != 0) { if (net_ratelimit()) printk(KERN_DEBUG "%s: defrag: CCMP PN not " - "sequential A2=" MAC_FMT + "sequential A2=%s" " PN=%02x%02x%02x%02x%02x%02x " "(expected %02x%02x%02x%02x%02x%02x)\n", - rx->dev->name, MAC_ARG(hdr->addr2), + rx->dev->name, print_mac(mac, hdr->addr2), rpn[0], rpn[1], rpn[2], rpn[3], rpn[4], rpn[5], pn[0], pn[1], pn[2], pn[3], pn[4], pn[5]); @@ -774,6 +780,7 @@ ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx) { struct sk_buff *skb; int no_pending_pkts; + DECLARE_MAC_BUF(mac); if (likely(!rx->sta || (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_CTL || @@ -799,9 +806,8 @@ ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx) rx->sta->pspoll = 1; #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - printk(KERN_DEBUG "STA " MAC_FMT " aid %d: PS Poll (entries " - "after %d)\n", - MAC_ARG(rx->sta->addr), rx->sta->aid, + printk(KERN_DEBUG "STA %s aid %d: PS Poll (entries after %d)\n", + print_mac(mac, rx->sta->addr), rx->sta->aid, skb_queue_len(&rx->sta->ps_tx_buf)); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ @@ -824,9 +830,9 @@ ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx) } #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG } else if (!rx->u.rx.sent_ps_buffered) { - printk(KERN_DEBUG "%s: STA " MAC_FMT " sent PS Poll even " + printk(KERN_DEBUG "%s: STA %s sent PS Poll even " "though there is no buffered frames for it\n", - rx->dev->name, MAC_ARG(rx->sta->addr)); + rx->dev->name, print_mac(mac, rx->sta->addr)); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ } @@ -881,9 +887,10 @@ ieee80211_rx_h_802_1x_pae(struct ieee80211_txrx_data *rx) #ifdef CONFIG_MAC80211_DEBUG struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; - printk(KERN_DEBUG "%s: dropped frame from " MAC_FMT + DECLARE_MAC_BUF(mac); + printk(KERN_DEBUG "%s: dropped frame from %s" " (unauthorized port)\n", rx->dev->name, - MAC_ARG(hdr->addr2)); + print_mac(mac, hdr->addr2)); #endif /* CONFIG_MAC80211_DEBUG */ return TXRX_DROP; } @@ -928,6 +935,10 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) u8 src[ETH_ALEN]; struct sk_buff *skb = rx->skb, *skb2; struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); + DECLARE_MAC_BUF(mac3); + DECLARE_MAC_BUF(mac4); fc = rx->fc; if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)) @@ -958,13 +969,11 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) sdata->type != IEEE80211_IF_TYPE_VLAN)) { if (net_ratelimit()) printk(KERN_DEBUG "%s: dropped ToDS frame " - "(BSSID=" MAC_FMT - " SA=" MAC_FMT - " DA=" MAC_FMT ")\n", + "(BSSID=%s SA=%s DA=%s)\n", dev->name, - MAC_ARG(hdr->addr1), - MAC_ARG(hdr->addr2), - MAC_ARG(hdr->addr3)); + print_mac(mac, hdr->addr1), + print_mac(mac2, hdr->addr2), + print_mac(mac3, hdr->addr3)); return TXRX_DROP; } break; @@ -976,14 +985,12 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) if (unlikely(sdata->type != IEEE80211_IF_TYPE_WDS)) { if (net_ratelimit()) printk(KERN_DEBUG "%s: dropped FromDS&ToDS " - "frame (RA=" MAC_FMT - " TA=" MAC_FMT " DA=" MAC_FMT - " SA=" MAC_FMT ")\n", + "frame (RA=%s TA=%s DA=%s SA=%s)\n", rx->dev->name, - MAC_ARG(hdr->addr1), - MAC_ARG(hdr->addr2), - MAC_ARG(hdr->addr3), - MAC_ARG(hdr->addr4)); + print_mac(mac, hdr->addr1), + print_mac(mac2, hdr->addr2), + print_mac(mac3, hdr->addr3), + print_mac(mac4, hdr->addr4)); return TXRX_DROP; } break; @@ -1004,12 +1011,12 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) if (sdata->type != IEEE80211_IF_TYPE_IBSS) { if (net_ratelimit()) { - printk(KERN_DEBUG "%s: dropped IBSS frame (DA=" - MAC_FMT " SA=" MAC_FMT " BSSID=" MAC_FMT - ")\n", - dev->name, MAC_ARG(hdr->addr1), - MAC_ARG(hdr->addr2), - MAC_ARG(hdr->addr3)); + printk(KERN_DEBUG "%s: dropped IBSS frame " + "(DA=%s SA=%s BSSID=%s)\n", + dev->name, + print_mac(mac, hdr->addr1), + print_mac(mac2, hdr->addr2), + print_mac(mac3, hdr->addr3)); } return TXRX_DROP; } @@ -1172,6 +1179,8 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev, struct ieee80211_txrx_data *rx) { int keyidx, hdrlen; + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); hdrlen = ieee80211_get_hdrlen_from_skb(rx->skb); if (rx->skb->len >= hdrlen + 4) @@ -1181,9 +1190,9 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev, if (net_ratelimit()) printk(KERN_DEBUG "%s: TKIP hwaccel reported Michael MIC " - "failure from " MAC_FMT " to " MAC_FMT " keyidx=%d\n", - dev->name, MAC_ARG(hdr->addr2), MAC_ARG(hdr->addr1), - keyidx); + "failure from %s to %s keyidx=%d\n", + dev->name, print_mac(mac, hdr->addr2), + print_mac(mac2, hdr->addr1), keyidx); if (!sta) { /* @@ -1192,8 +1201,8 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev, */ if (net_ratelimit()) printk(KERN_DEBUG "%s: ignored spurious Michael MIC " - "error for unknown address " MAC_FMT "\n", - dev->name, MAC_ARG(hdr->addr2)); + "error for unknown address %s\n", + dev->name, print_mac(mac, hdr->addr2)); goto ignore; } @@ -1201,7 +1210,7 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev, if (net_ratelimit()) printk(KERN_DEBUG "%s: ignored spurious Michael MIC " "error for a frame with no PROTECTED flag (src " - MAC_FMT ")\n", dev->name, MAC_ARG(hdr->addr2)); + "%s)\n", dev->name, print_mac(mac, hdr->addr2)); goto ignore; } @@ -1215,8 +1224,8 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev, if (net_ratelimit()) printk(KERN_DEBUG "%s: ignored Michael MIC error for " "a frame with non-zero keyidx (%d)" - " (src " MAC_FMT ")\n", dev->name, keyidx, - MAC_ARG(hdr->addr2)); + " (src %s)\n", dev->name, keyidx, + print_mac(mac, hdr->addr2)); goto ignore; } @@ -1226,8 +1235,8 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev, if (net_ratelimit()) printk(KERN_DEBUG "%s: ignored spurious Michael MIC " "error for a frame that cannot be encrypted " - "(fc=0x%04x) (src " MAC_FMT ")\n", - dev->name, rx->fc, MAC_ARG(hdr->addr2)); + "(fc=0x%04x) (src %s)\n", + dev->name, rx->fc, print_mac(mac, hdr->addr2)); goto ignore; } diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index c17172abb21..44d98340495 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -132,6 +132,7 @@ struct sta_info * sta_info_add(struct ieee80211_local *local, struct net_device *dev, u8 *addr, gfp_t gfp) { struct sta_info *sta; + DECLARE_MAC_BUF(mac); sta = kzalloc(sizeof(*sta), gfp); if (!sta) @@ -164,8 +165,8 @@ struct sta_info * sta_info_add(struct ieee80211_local *local, write_unlock_bh(&local->sta_lock); #ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "%s: Added STA " MAC_FMT "\n", - local->mdev->name, MAC_ARG(addr)); + printk(KERN_DEBUG "%s: Added STA %s\n", + local->mdev->name, print_mac(mac, addr)); #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ #ifdef CONFIG_MAC80211_DEBUGFS @@ -207,6 +208,7 @@ void sta_info_free(struct sta_info *sta) { struct sk_buff *skb; struct ieee80211_local *local = sta->local; + DECLARE_MAC_BUF(mac); might_sleep(); @@ -223,8 +225,8 @@ void sta_info_free(struct sta_info *sta) } #ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "%s: Removed STA " MAC_FMT "\n", - local->mdev->name, MAC_ARG(sta->addr)); + printk(KERN_DEBUG "%s: Removed STA %s\n", + local->mdev->name, print_mac(mac, sta->addr)); #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ ieee80211_key_free(sta->key); @@ -263,6 +265,7 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local, { unsigned long flags; struct sk_buff *skb; + DECLARE_MAC_BUF(mac); if (skb_queue_empty(&sta->ps_tx_buf)) return; @@ -281,7 +284,7 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local, if (skb) { local->total_ps_buffered--; printk(KERN_DEBUG "Buffered frame expired (STA " - MAC_FMT ")\n", MAC_ARG(sta->addr)); + "%s)\n", print_mac(mac, sta->addr)); dev_kfree_skb(skb); } else break; diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c index b9c1d540518..5b11f14abfb 100644 --- a/net/mac80211/tkip.c +++ b/net/mac80211/tkip.c @@ -275,9 +275,10 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, (iv32 == key->u.tkip.iv32_rx[queue] && iv16 <= key->u.tkip.iv16_rx[queue]))) { #ifdef CONFIG_TKIP_DEBUG + DECLARE_MAC_BUF(mac); printk(KERN_DEBUG "TKIP replay detected for RX frame from " - MAC_FMT " (RX IV (%04x,%02x) <= prev. IV (%04x,%02x)\n", - MAC_ARG(ta), + "%s (RX IV (%04x,%02x) <= prev. IV (%04x,%02x)\n", + print_mac(mac, ta), iv32, iv16, key->u.tkip.iv32_rx[queue], key->u.tkip.iv16_rx[queue]); #endif /* CONFIG_TKIP_DEBUG */ @@ -299,8 +300,9 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, #ifdef CONFIG_TKIP_DEBUG { int i; - printk(KERN_DEBUG "TKIP decrypt: Phase1 TA=" MAC_FMT - " TK=", MAC_ARG(ta)); + DECLARE_MAC_BUF(mac); + printk(KERN_DEBUG "TKIP decrypt: Phase1 TA=%s" + " TK=", print_mac(mac, ta)); for (i = 0; i < 16; i++) printk("%02x ", key->conf.key[ diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index ca262a99e56..04b4fa9c69e 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -54,6 +54,7 @@ static void ieee80211_dump_frame(const char *ifname, const char *title, const struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; u16 fc; int hdrlen; + DECLARE_MAC_BUF(mac); printk(KERN_DEBUG "%s: %s (len=%d)", ifname, title, skb->len); if (skb->len < 4) { @@ -69,13 +70,13 @@ static void ieee80211_dump_frame(const char *ifname, const char *title, printk(" FC=0x%04x DUR=0x%04x", fc, le16_to_cpu(hdr->duration_id)); if (hdrlen >= 10) - printk(" A1=" MAC_FMT, MAC_ARG(hdr->addr1)); + printk(" A1=%s", print_mac(mac, hdr->addr1)); if (hdrlen >= 16) - printk(" A2=" MAC_FMT, MAC_ARG(hdr->addr2)); + printk(" A2=%s", print_mac(mac, hdr->addr2)); if (hdrlen >= 24) - printk(" A3=" MAC_FMT, MAC_ARG(hdr->addr3)); + printk(" A3=%s", print_mac(mac, hdr->addr3)); if (hdrlen >= 30) - printk(" A4=" MAC_FMT, MAC_ARG(hdr->addr4)); + printk(" A4=%s", print_mac(mac, hdr->addr4)); printk("\n"); } #else /* CONFIG_MAC80211_LOWTX_FRAME_DUMP */ @@ -236,9 +237,10 @@ ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx) tx->sdata->type != IEEE80211_IF_TYPE_IBSS && (tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) { #ifdef CONFIG_MAC80211_VERBOSE_DEBUG + DECLARE_MAC_BUF(mac); printk(KERN_DEBUG "%s: dropped data frame to not " - "associated station " MAC_FMT "\n", - tx->dev->name, MAC_ARG(hdr->addr1)); + "associated station %s\n", + tx->dev->name, print_mac(mac, hdr->addr1)); #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ I802_DEBUG_INC(tx->local->tx_handlers_drop_not_assoc); return TXRX_DROP; @@ -259,9 +261,10 @@ ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx) if (unlikely(!tx->u.tx.mgmt_interface && tx->sdata->ieee802_1x && !(sta_flags & WLAN_STA_AUTHORIZED))) { #ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "%s: dropped frame to " MAC_FMT + DECLARE_MAC_BUF(mac); + printk(KERN_DEBUG "%s: dropped frame to %s" " (unauthorized port)\n", tx->dev->name, - MAC_ARG(hdr->addr1)); + print_mac(mac, hdr->addr1)); #endif I802_DEBUG_INC(tx->local->tx_handlers_drop_unauth_port); return TXRX_DROP; @@ -357,6 +360,7 @@ static inline ieee80211_txrx_result ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx) { struct sta_info *sta = tx->sta; + DECLARE_MAC_BUF(mac); if (unlikely(!sta || ((tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT && @@ -366,9 +370,9 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx) if (unlikely((sta->flags & WLAN_STA_PS) && !sta->pspoll)) { struct ieee80211_tx_packet_data *pkt_data; #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - printk(KERN_DEBUG "STA " MAC_FMT " aid %d: PS buffer (entries " + printk(KERN_DEBUG "STA %s aid %d: PS buffer (entries " "before %d)\n", - MAC_ARG(sta->addr), sta->aid, + print_mac(mac, sta->addr), sta->aid, skb_queue_len(&sta->ps_tx_buf)); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ sta->flags |= WLAN_STA_TIM; @@ -377,9 +381,9 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx) if (skb_queue_len(&sta->ps_tx_buf) >= STA_MAX_TX_BUFFER) { struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf); if (net_ratelimit()) { - printk(KERN_DEBUG "%s: STA " MAC_FMT " TX " + printk(KERN_DEBUG "%s: STA %s TX " "buffer full - dropping oldest frame\n", - tx->dev->name, MAC_ARG(sta->addr)); + tx->dev->name, print_mac(mac, sta->addr)); } dev_kfree_skb(old); } else @@ -399,9 +403,9 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx) } #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG else if (unlikely(sta->flags & WLAN_STA_PS)) { - printk(KERN_DEBUG "%s: STA " MAC_FMT " in PS mode, but pspoll " + printk(KERN_DEBUG "%s: STA %s in PS mode, but pspoll " "set -> send frame\n", tx->dev->name, - MAC_ARG(sta->addr)); + print_mac(mac, sta->addr)); } #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ sta->pspoll = 0; diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 6e12638054a..360d11e9de1 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -132,6 +132,7 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx) u8 mic[MICHAEL_MIC_LEN]; struct sk_buff *skb = rx->skb; int authenticator = 1, wpa_test = 0; + DECLARE_MAC_BUF(mac); fc = rx->fc; @@ -164,7 +165,7 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx) return TXRX_DROP; printk(KERN_DEBUG "%s: invalid Michael MIC in data frame from " - MAC_FMT "\n", rx->dev->name, MAC_ARG(sa)); + "%s\n", rx->dev->name, print_mac(mac, sa)); mac80211_ev_michael_mic_failure(rx->dev, rx->key->conf.keyidx, (void *) skb->data); @@ -287,6 +288,7 @@ ieee80211_rx_h_tkip_decrypt(struct ieee80211_txrx_data *rx) int hdrlen, res, hwaccel = 0, wpa_test = 0; struct ieee80211_key *key = rx->key; struct sk_buff *skb = rx->skb; + DECLARE_MAC_BUF(mac); fc = le16_to_cpu(hdr->frame_control); hdrlen = ieee80211_get_hdrlen(fc); @@ -319,8 +321,8 @@ ieee80211_rx_h_tkip_decrypt(struct ieee80211_txrx_data *rx) hwaccel, rx->u.rx.queue); if (res != TKIP_DECRYPT_OK || wpa_test) { printk(KERN_DEBUG "%s: TKIP decrypt failed for RX frame from " - MAC_FMT " (res=%d)\n", - rx->dev->name, MAC_ARG(rx->sta->addr), res); + "%s (res=%d)\n", + rx->dev->name, print_mac(mac, rx->sta->addr), res); return TXRX_DROP; } @@ -542,6 +544,7 @@ ieee80211_rx_h_ccmp_decrypt(struct ieee80211_txrx_data *rx) struct sk_buff *skb = rx->skb; u8 pn[CCMP_PN_LEN]; int data_len; + DECLARE_MAC_BUF(mac); fc = le16_to_cpu(hdr->frame_control); hdrlen = ieee80211_get_hdrlen(fc); @@ -564,10 +567,11 @@ ieee80211_rx_h_ccmp_decrypt(struct ieee80211_txrx_data *rx) if (memcmp(pn, key->u.ccmp.rx_pn[rx->u.rx.queue], CCMP_PN_LEN) <= 0) { #ifdef CONFIG_MAC80211_DEBUG u8 *ppn = key->u.ccmp.rx_pn[rx->u.rx.queue]; + printk(KERN_DEBUG "%s: CCMP replay detected for RX frame from " - MAC_FMT " (RX PN %02x%02x%02x%02x%02x%02x <= prev. PN " + "%s (RX PN %02x%02x%02x%02x%02x%02x <= prev. PN " "%02x%02x%02x%02x%02x%02x)\n", rx->dev->name, - MAC_ARG(rx->sta->addr), + print_mac(mac, rx->sta->addr), pn[0], pn[1], pn[2], pn[3], pn[4], pn[5], ppn[0], ppn[1], ppn[2], ppn[3], ppn[4], ppn[5]); #endif /* CONFIG_MAC80211_DEBUG */ @@ -591,8 +595,8 @@ ieee80211_rx_h_ccmp_decrypt(struct ieee80211_txrx_data *rx) skb->data + skb->len - CCMP_MIC_LEN, skb->data + hdrlen + CCMP_HDR_LEN)) { printk(KERN_DEBUG "%s: CCMP decrypt failed for RX " - "frame from " MAC_FMT "\n", rx->dev->name, - MAC_ARG(rx->sta->addr)); + "frame from %s\n", rx->dev->name, + print_mac(mac, rx->sta->addr)); return TXRX_DROP; } } @@ -606,4 +610,3 @@ ieee80211_rx_h_ccmp_decrypt(struct ieee80211_txrx_data *rx) return TXRX_CONTINUE; } - diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c index d6fc0575816..1a99e294714 100644 --- a/net/tipc/eth_media.c +++ b/net/tipc/eth_media.c @@ -243,12 +243,12 @@ static int recv_notification(struct notifier_block *nb, unsigned long evt, static char *eth_addr2str(struct tipc_media_addr *a, char *str_buf, int str_size) { unchar *addr = (unchar *)&a->dev_addr; + DECLARE_MAC_BUF(mac); if (str_size < 18) *str_buf = '\0'; else - sprintf(str_buf, "%02x:%02x:%02x:%02x:%02x:%02x", - addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); + sprintf(str_buf, "%s", print_mac(mac, addr)); return str_buf; } -- cgit v1.2.3-70-g09d2 From eff1a59c48e3c6a006eb4fe5f2e405a996f2259d Mon Sep 17 00:00:00 2001 From: Michael Wu Date: Tue, 25 Sep 2007 18:11:01 -0700 Subject: [P54]: add mac80211-based driver for prism54 softmac hardware Signed-off-by: Michael Wu Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- MAINTAINERS | 8 + drivers/net/wireless/Kconfig | 13 + drivers/net/wireless/Makefile | 4 + drivers/net/wireless/net2280.h | 452 ++++++++++++++++++ drivers/net/wireless/p54.h | 80 ++++ drivers/net/wireless/p54common.c | 983 +++++++++++++++++++++++++++++++++++++++ drivers/net/wireless/p54common.h | 329 +++++++++++++ drivers/net/wireless/p54pci.c | 691 +++++++++++++++++++++++++++ drivers/net/wireless/p54pci.h | 106 +++++ drivers/net/wireless/p54usb.c | 906 ++++++++++++++++++++++++++++++++++++ drivers/net/wireless/p54usb.h | 133 ++++++ 11 files changed, 3705 insertions(+) create mode 100644 drivers/net/wireless/net2280.h create mode 100644 drivers/net/wireless/p54.h create mode 100644 drivers/net/wireless/p54common.c create mode 100644 drivers/net/wireless/p54common.h create mode 100644 drivers/net/wireless/p54pci.c create mode 100644 drivers/net/wireless/p54pci.h create mode 100644 drivers/net/wireless/p54usb.c create mode 100644 drivers/net/wireless/p54usb.h (limited to 'drivers') diff --git a/MAINTAINERS b/MAINTAINERS index 6ae2b997526..c96505c2678 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3060,6 +3060,14 @@ L: kpreempt-tech@lists.sourceforge.net W: ftp://ftp.kernel.org/pub/linux/kernel/people/rml/preempt-kernel S: Supported +P54 WIRELESS DRIVER +P: Michael Wu +M: flamingice@sourmilk.net +L: linux-wireless@vger.kernel.org +W: http://prism54.org +T: git kernel.org:/pub/scm/linux/kernel/git/mwu/mac80211-drivers.git +S: Maintained + PRISM54 WIRELESS DRIVER P: Luis R. Rodriguez M: mcgrof@gmail.com diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index f481c757e22..5a6fdfd0f14 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -577,6 +577,19 @@ config ADM8211 Thanks to Infineon-ADMtek for their support of this driver. +config P54_COMMON + tristate "Softmac Prism54 support" + depends on MAC80211 && WLAN_80211 && FW_LOADER && EXPERIMENTAL + +config P54_USB + tristate "Prism54 USB support" + depends on P54_COMMON && USB + select CRC32 + +config P54_PCI + tristate "Prism54 PCI support" + depends on P54_COMMON && PCI + source "drivers/net/wireless/iwlwifi/Kconfig" source "drivers/net/wireless/hostap/Kconfig" source "drivers/net/wireless/bcm43xx/Kconfig" diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index a7a15e3509e..6f32b53ee12 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -54,3 +54,7 @@ obj-$(CONFIG_ADM8211) += adm8211.o obj-$(CONFIG_IWLWIFI) += iwlwifi/ obj-$(CONFIG_RT2X00) += rt2x00/ + +obj-$(CONFIG_P54_COMMON) += p54common.o +obj-$(CONFIG_P54_USB) += p54usb.o +obj-$(CONFIG_P54_PCI) += p54pci.o diff --git a/drivers/net/wireless/net2280.h b/drivers/net/wireless/net2280.h new file mode 100644 index 00000000000..120eb831b28 --- /dev/null +++ b/drivers/net/wireless/net2280.h @@ -0,0 +1,452 @@ +#ifndef NET2280_H +#define NET2280_H +/* + * NetChip 2280 high/full speed USB device controller. + * Unlike many such controllers, this one talks PCI. + */ + +/* + * Copyright (C) 2002 NetChip Technology, Inc. (http://www.netchip.com) + * Copyright (C) 2003 David Brownell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/*-------------------------------------------------------------------------*/ + +/* NET2280 MEMORY MAPPED REGISTERS + * + * The register layout came from the chip documentation, and the bit + * number definitions were extracted from chip specification. + * + * Use the shift operator ('<<') to build bit masks, with readl/writel + * to access the registers through PCI. + */ + +/* main registers, BAR0 + 0x0000 */ +struct net2280_regs { + // offset 0x0000 + __le32 devinit; +#define LOCAL_CLOCK_FREQUENCY 8 +#define FORCE_PCI_RESET 7 +#define PCI_ID 6 +#define PCI_ENABLE 5 +#define FIFO_SOFT_RESET 4 +#define CFG_SOFT_RESET 3 +#define PCI_SOFT_RESET 2 +#define USB_SOFT_RESET 1 +#define M8051_RESET 0 + __le32 eectl; +#define EEPROM_ADDRESS_WIDTH 23 +#define EEPROM_CHIP_SELECT_ACTIVE 22 +#define EEPROM_PRESENT 21 +#define EEPROM_VALID 20 +#define EEPROM_BUSY 19 +#define EEPROM_CHIP_SELECT_ENABLE 18 +#define EEPROM_BYTE_READ_START 17 +#define EEPROM_BYTE_WRITE_START 16 +#define EEPROM_READ_DATA 8 +#define EEPROM_WRITE_DATA 0 + __le32 eeclkfreq; + u32 _unused0; + // offset 0x0010 + + __le32 pciirqenb0; /* interrupt PCI master ... */ +#define SETUP_PACKET_INTERRUPT_ENABLE 7 +#define ENDPOINT_F_INTERRUPT_ENABLE 6 +#define ENDPOINT_E_INTERRUPT_ENABLE 5 +#define ENDPOINT_D_INTERRUPT_ENABLE 4 +#define ENDPOINT_C_INTERRUPT_ENABLE 3 +#define ENDPOINT_B_INTERRUPT_ENABLE 2 +#define ENDPOINT_A_INTERRUPT_ENABLE 1 +#define ENDPOINT_0_INTERRUPT_ENABLE 0 + __le32 pciirqenb1; +#define PCI_INTERRUPT_ENABLE 31 +#define POWER_STATE_CHANGE_INTERRUPT_ENABLE 27 +#define PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE 26 +#define PCI_PARITY_ERROR_INTERRUPT_ENABLE 25 +#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE 20 +#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE 19 +#define PCI_TARGET_ABORT_ASSERTED_INTERRUPT_ENABLE 18 +#define PCI_RETRY_ABORT_INTERRUPT_ENABLE 17 +#define PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE 16 +#define GPIO_INTERRUPT_ENABLE 13 +#define DMA_D_INTERRUPT_ENABLE 12 +#define DMA_C_INTERRUPT_ENABLE 11 +#define DMA_B_INTERRUPT_ENABLE 10 +#define DMA_A_INTERRUPT_ENABLE 9 +#define EEPROM_DONE_INTERRUPT_ENABLE 8 +#define VBUS_INTERRUPT_ENABLE 7 +#define CONTROL_STATUS_INTERRUPT_ENABLE 6 +#define ROOT_PORT_RESET_INTERRUPT_ENABLE 4 +#define SUSPEND_REQUEST_INTERRUPT_ENABLE 3 +#define SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE 2 +#define RESUME_INTERRUPT_ENABLE 1 +#define SOF_INTERRUPT_ENABLE 0 + __le32 cpu_irqenb0; /* ... or onboard 8051 */ +#define SETUP_PACKET_INTERRUPT_ENABLE 7 +#define ENDPOINT_F_INTERRUPT_ENABLE 6 +#define ENDPOINT_E_INTERRUPT_ENABLE 5 +#define ENDPOINT_D_INTERRUPT_ENABLE 4 +#define ENDPOINT_C_INTERRUPT_ENABLE 3 +#define ENDPOINT_B_INTERRUPT_ENABLE 2 +#define ENDPOINT_A_INTERRUPT_ENABLE 1 +#define ENDPOINT_0_INTERRUPT_ENABLE 0 + __le32 cpu_irqenb1; +#define CPU_INTERRUPT_ENABLE 31 +#define POWER_STATE_CHANGE_INTERRUPT_ENABLE 27 +#define PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE 26 +#define PCI_PARITY_ERROR_INTERRUPT_ENABLE 25 +#define PCI_INTA_INTERRUPT_ENABLE 24 +#define PCI_PME_INTERRUPT_ENABLE 23 +#define PCI_SERR_INTERRUPT_ENABLE 22 +#define PCI_PERR_INTERRUPT_ENABLE 21 +#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE 20 +#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE 19 +#define PCI_RETRY_ABORT_INTERRUPT_ENABLE 17 +#define PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE 16 +#define GPIO_INTERRUPT_ENABLE 13 +#define DMA_D_INTERRUPT_ENABLE 12 +#define DMA_C_INTERRUPT_ENABLE 11 +#define DMA_B_INTERRUPT_ENABLE 10 +#define DMA_A_INTERRUPT_ENABLE 9 +#define EEPROM_DONE_INTERRUPT_ENABLE 8 +#define VBUS_INTERRUPT_ENABLE 7 +#define CONTROL_STATUS_INTERRUPT_ENABLE 6 +#define ROOT_PORT_RESET_INTERRUPT_ENABLE 4 +#define SUSPEND_REQUEST_INTERRUPT_ENABLE 3 +#define SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE 2 +#define RESUME_INTERRUPT_ENABLE 1 +#define SOF_INTERRUPT_ENABLE 0 + + // offset 0x0020 + u32 _unused1; + __le32 usbirqenb1; +#define USB_INTERRUPT_ENABLE 31 +#define POWER_STATE_CHANGE_INTERRUPT_ENABLE 27 +#define PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE 26 +#define PCI_PARITY_ERROR_INTERRUPT_ENABLE 25 +#define PCI_INTA_INTERRUPT_ENABLE 24 +#define PCI_PME_INTERRUPT_ENABLE 23 +#define PCI_SERR_INTERRUPT_ENABLE 22 +#define PCI_PERR_INTERRUPT_ENABLE 21 +#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE 20 +#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE 19 +#define PCI_RETRY_ABORT_INTERRUPT_ENABLE 17 +#define PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE 16 +#define GPIO_INTERRUPT_ENABLE 13 +#define DMA_D_INTERRUPT_ENABLE 12 +#define DMA_C_INTERRUPT_ENABLE 11 +#define DMA_B_INTERRUPT_ENABLE 10 +#define DMA_A_INTERRUPT_ENABLE 9 +#define EEPROM_DONE_INTERRUPT_ENABLE 8 +#define VBUS_INTERRUPT_ENABLE 7 +#define CONTROL_STATUS_INTERRUPT_ENABLE 6 +#define ROOT_PORT_RESET_INTERRUPT_ENABLE 4 +#define SUSPEND_REQUEST_INTERRUPT_ENABLE 3 +#define SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE 2 +#define RESUME_INTERRUPT_ENABLE 1 +#define SOF_INTERRUPT_ENABLE 0 + __le32 irqstat0; +#define INTA_ASSERTED 12 +#define SETUP_PACKET_INTERRUPT 7 +#define ENDPOINT_F_INTERRUPT 6 +#define ENDPOINT_E_INTERRUPT 5 +#define ENDPOINT_D_INTERRUPT 4 +#define ENDPOINT_C_INTERRUPT 3 +#define ENDPOINT_B_INTERRUPT 2 +#define ENDPOINT_A_INTERRUPT 1 +#define ENDPOINT_0_INTERRUPT 0 + __le32 irqstat1; +#define POWER_STATE_CHANGE_INTERRUPT 27 +#define PCI_ARBITER_TIMEOUT_INTERRUPT 26 +#define PCI_PARITY_ERROR_INTERRUPT 25 +#define PCI_INTA_INTERRUPT 24 +#define PCI_PME_INTERRUPT 23 +#define PCI_SERR_INTERRUPT 22 +#define PCI_PERR_INTERRUPT 21 +#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT 20 +#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT 19 +#define PCI_RETRY_ABORT_INTERRUPT 17 +#define PCI_MASTER_CYCLE_DONE_INTERRUPT 16 +#define GPIO_INTERRUPT 13 +#define DMA_D_INTERRUPT 12 +#define DMA_C_INTERRUPT 11 +#define DMA_B_INTERRUPT 10 +#define DMA_A_INTERRUPT 9 +#define EEPROM_DONE_INTERRUPT 8 +#define VBUS_INTERRUPT 7 +#define CONTROL_STATUS_INTERRUPT 6 +#define ROOT_PORT_RESET_INTERRUPT 4 +#define SUSPEND_REQUEST_INTERRUPT 3 +#define SUSPEND_REQUEST_CHANGE_INTERRUPT 2 +#define RESUME_INTERRUPT 1 +#define SOF_INTERRUPT 0 + // offset 0x0030 + __le32 idxaddr; + __le32 idxdata; + __le32 fifoctl; +#define PCI_BASE2_RANGE 16 +#define IGNORE_FIFO_AVAILABILITY 3 +#define PCI_BASE2_SELECT 2 +#define FIFO_CONFIGURATION_SELECT 0 + u32 _unused2; + // offset 0x0040 + __le32 memaddr; +#define START 28 +#define DIRECTION 27 +#define FIFO_DIAGNOSTIC_SELECT 24 +#define MEMORY_ADDRESS 0 + __le32 memdata0; + __le32 memdata1; + u32 _unused3; + // offset 0x0050 + __le32 gpioctl; +#define GPIO3_LED_SELECT 12 +#define GPIO3_INTERRUPT_ENABLE 11 +#define GPIO2_INTERRUPT_ENABLE 10 +#define GPIO1_INTERRUPT_ENABLE 9 +#define GPIO0_INTERRUPT_ENABLE 8 +#define GPIO3_OUTPUT_ENABLE 7 +#define GPIO2_OUTPUT_ENABLE 6 +#define GPIO1_OUTPUT_ENABLE 5 +#define GPIO0_OUTPUT_ENABLE 4 +#define GPIO3_DATA 3 +#define GPIO2_DATA 2 +#define GPIO1_DATA 1 +#define GPIO0_DATA 0 + __le32 gpiostat; +#define GPIO3_INTERRUPT 3 +#define GPIO2_INTERRUPT 2 +#define GPIO1_INTERRUPT 1 +#define GPIO0_INTERRUPT 0 +} __attribute__ ((packed)); + +/* usb control, BAR0 + 0x0080 */ +struct net2280_usb_regs { + // offset 0x0080 + __le32 stdrsp; +#define STALL_UNSUPPORTED_REQUESTS 31 +#define SET_TEST_MODE 16 +#define GET_OTHER_SPEED_CONFIGURATION 15 +#define GET_DEVICE_QUALIFIER 14 +#define SET_ADDRESS 13 +#define ENDPOINT_SET_CLEAR_HALT 12 +#define DEVICE_SET_CLEAR_DEVICE_REMOTE_WAKEUP 11 +#define GET_STRING_DESCRIPTOR_2 10 +#define GET_STRING_DESCRIPTOR_1 9 +#define GET_STRING_DESCRIPTOR_0 8 +#define GET_SET_INTERFACE 6 +#define GET_SET_CONFIGURATION 5 +#define GET_CONFIGURATION_DESCRIPTOR 4 +#define GET_DEVICE_DESCRIPTOR 3 +#define GET_ENDPOINT_STATUS 2 +#define GET_INTERFACE_STATUS 1 +#define GET_DEVICE_STATUS 0 + __le32 prodvendid; +#define PRODUCT_ID 16 +#define VENDOR_ID 0 + __le32 relnum; + __le32 usbctl; +#define SERIAL_NUMBER_INDEX 16 +#define PRODUCT_ID_STRING_ENABLE 13 +#define VENDOR_ID_STRING_ENABLE 12 +#define USB_ROOT_PORT_WAKEUP_ENABLE 11 +#define VBUS_PIN 10 +#define TIMED_DISCONNECT 9 +#define SUSPEND_IMMEDIATELY 7 +#define SELF_POWERED_USB_DEVICE 6 +#define REMOTE_WAKEUP_SUPPORT 5 +#define PME_POLARITY 4 +#define USB_DETECT_ENABLE 3 +#define PME_WAKEUP_ENABLE 2 +#define DEVICE_REMOTE_WAKEUP_ENABLE 1 +#define SELF_POWERED_STATUS 0 + // offset 0x0090 + __le32 usbstat; +#define HIGH_SPEED 7 +#define FULL_SPEED 6 +#define GENERATE_RESUME 5 +#define GENERATE_DEVICE_REMOTE_WAKEUP 4 + __le32 xcvrdiag; +#define FORCE_HIGH_SPEED_MODE 31 +#define FORCE_FULL_SPEED_MODE 30 +#define USB_TEST_MODE 24 +#define LINE_STATE 16 +#define TRANSCEIVER_OPERATION_MODE 2 +#define TRANSCEIVER_SELECT 1 +#define TERMINATION_SELECT 0 + __le32 setup0123; + __le32 setup4567; + // offset 0x0090 + u32 _unused0; + __le32 ouraddr; +#define FORCE_IMMEDIATE 7 +#define OUR_USB_ADDRESS 0 + __le32 ourconfig; +} __attribute__ ((packed)); + +/* pci control, BAR0 + 0x0100 */ +struct net2280_pci_regs { + // offset 0x0100 + __le32 pcimstctl; +#define PCI_ARBITER_PARK_SELECT 13 +#define PCI_MULTI LEVEL_ARBITER 12 +#define PCI_RETRY_ABORT_ENABLE 11 +#define DMA_MEMORY_WRITE_AND_INVALIDATE_ENABLE 10 +#define DMA_READ_MULTIPLE_ENABLE 9 +#define DMA_READ_LINE_ENABLE 8 +#define PCI_MASTER_COMMAND_SELECT 6 +#define MEM_READ_OR_WRITE 0 +#define IO_READ_OR_WRITE 1 +#define CFG_READ_OR_WRITE 2 +#define PCI_MASTER_START 5 +#define PCI_MASTER_READ_WRITE 4 +#define PCI_MASTER_WRITE 0 +#define PCI_MASTER_READ 1 +#define PCI_MASTER_BYTE_WRITE_ENABLES 0 + __le32 pcimstaddr; + __le32 pcimstdata; + __le32 pcimststat; +#define PCI_ARBITER_CLEAR 2 +#define PCI_EXTERNAL_ARBITER 1 +#define PCI_HOST_MODE 0 +} __attribute__ ((packed)); + +/* dma control, BAR0 + 0x0180 ... array of four structs like this, + * for channels 0..3. see also struct net2280_dma: descriptor + * that can be loaded into some of these registers. + */ +struct net2280_dma_regs { /* [11.7] */ + // offset 0x0180, 0x01a0, 0x01c0, 0x01e0, + __le32 dmactl; +#define DMA_SCATTER_GATHER_DONE_INTERRUPT_ENABLE 25 +#define DMA_CLEAR_COUNT_ENABLE 21 +#define DESCRIPTOR_POLLING_RATE 19 +#define POLL_CONTINUOUS 0 +#define POLL_1_USEC 1 +#define POLL_100_USEC 2 +#define POLL_1_MSEC 3 +#define DMA_VALID_BIT_POLLING_ENABLE 18 +#define DMA_VALID_BIT_ENABLE 17 +#define DMA_SCATTER_GATHER_ENABLE 16 +#define DMA_OUT_AUTO_START_ENABLE 4 +#define DMA_PREEMPT_ENABLE 3 +#define DMA_FIFO_VALIDATE 2 +#define DMA_ENABLE 1 +#define DMA_ADDRESS_HOLD 0 + __le32 dmastat; +#define DMA_SCATTER_GATHER_DONE_INTERRUPT 25 +#define DMA_TRANSACTION_DONE_INTERRUPT 24 +#define DMA_ABORT 1 +#define DMA_START 0 + u32 _unused0[2]; + // offset 0x0190, 0x01b0, 0x01d0, 0x01f0, + __le32 dmacount; +#define VALID_BIT 31 +#define DMA_DIRECTION 30 +#define DMA_DONE_INTERRUPT_ENABLE 29 +#define END_OF_CHAIN 28 +#define DMA_BYTE_COUNT_MASK ((1<<24)-1) +#define DMA_BYTE_COUNT 0 + __le32 dmaaddr; + __le32 dmadesc; + u32 _unused1; +} __attribute__ ((packed)); + +/* dedicated endpoint registers, BAR0 + 0x0200 */ + +struct net2280_dep_regs { /* [11.8] */ + // offset 0x0200, 0x0210, 0x220, 0x230, 0x240 + __le32 dep_cfg; + // offset 0x0204, 0x0214, 0x224, 0x234, 0x244 + __le32 dep_rsp; + u32 _unused[2]; +} __attribute__ ((packed)); + +/* configurable endpoint registers, BAR0 + 0x0300 ... array of seven structs + * like this, for ep0 then the configurable endpoints A..F + * ep0 reserved for control; E and F have only 64 bytes of fifo + */ +struct net2280_ep_regs { /* [11.9] */ + // offset 0x0300, 0x0320, 0x0340, 0x0360, 0x0380, 0x03a0, 0x03c0 + __le32 ep_cfg; +#define ENDPOINT_BYTE_COUNT 16 +#define ENDPOINT_ENABLE 10 +#define ENDPOINT_TYPE 8 +#define ENDPOINT_DIRECTION 7 +#define ENDPOINT_NUMBER 0 + __le32 ep_rsp; +#define SET_NAK_OUT_PACKETS 15 +#define SET_EP_HIDE_STATUS_PHASE 14 +#define SET_EP_FORCE_CRC_ERROR 13 +#define SET_INTERRUPT_MODE 12 +#define SET_CONTROL_STATUS_PHASE_HANDSHAKE 11 +#define SET_NAK_OUT_PACKETS_MODE 10 +#define SET_ENDPOINT_TOGGLE 9 +#define SET_ENDPOINT_HALT 8 +#define CLEAR_NAK_OUT_PACKETS 7 +#define CLEAR_EP_HIDE_STATUS_PHASE 6 +#define CLEAR_EP_FORCE_CRC_ERROR 5 +#define CLEAR_INTERRUPT_MODE 4 +#define CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE 3 +#define CLEAR_NAK_OUT_PACKETS_MODE 2 +#define CLEAR_ENDPOINT_TOGGLE 1 +#define CLEAR_ENDPOINT_HALT 0 + __le32 ep_irqenb; +#define SHORT_PACKET_OUT_DONE_INTERRUPT_ENABLE 6 +#define SHORT_PACKET_TRANSFERRED_INTERRUPT_ENABLE 5 +#define DATA_PACKET_RECEIVED_INTERRUPT_ENABLE 3 +#define DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE 2 +#define DATA_OUT_PING_TOKEN_INTERRUPT_ENABLE 1 +#define DATA_IN_TOKEN_INTERRUPT_ENABLE 0 + __le32 ep_stat; +#define FIFO_VALID_COUNT 24 +#define HIGH_BANDWIDTH_OUT_TRANSACTION_PID 22 +#define TIMEOUT 21 +#define USB_STALL_SENT 20 +#define USB_IN_NAK_SENT 19 +#define USB_IN_ACK_RCVD 18 +#define USB_OUT_PING_NAK_SENT 17 +#define USB_OUT_ACK_SENT 16 +#define FIFO_OVERFLOW 13 +#define FIFO_UNDERFLOW 12 +#define FIFO_FULL 11 +#define FIFO_EMPTY 10 +#define FIFO_FLUSH 9 +#define SHORT_PACKET_OUT_DONE_INTERRUPT 6 +#define SHORT_PACKET_TRANSFERRED_INTERRUPT 5 +#define NAK_OUT_PACKETS 4 +#define DATA_PACKET_RECEIVED_INTERRUPT 3 +#define DATA_PACKET_TRANSMITTED_INTERRUPT 2 +#define DATA_OUT_PING_TOKEN_INTERRUPT 1 +#define DATA_IN_TOKEN_INTERRUPT 0 + // offset 0x0310, 0x0330, 0x0350, 0x0370, 0x0390, 0x03b0, 0x03d0 + __le32 ep_avail; + __le32 ep_data; + u32 _unused0[2]; +} __attribute__ ((packed)); + +struct net2280_reg_write { + __le16 port; + __le32 addr; + __le32 val; +} __attribute__ ((packed)); + +struct net2280_reg_read { + __le16 port; + __le32 addr; +} __attribute__ ((packed)); +#endif /* NET2280_H */ diff --git a/drivers/net/wireless/p54.h b/drivers/net/wireless/p54.h new file mode 100644 index 00000000000..e558d697d9e --- /dev/null +++ b/drivers/net/wireless/p54.h @@ -0,0 +1,80 @@ +#ifndef PRISM54_H +#define PRISM54_H + +/* + * Shared defines for all mac80211 Prism54 code + * + * Copyright (c) 2006, Michael Wu + * + * Based on the islsm (softmac prism54) driver, which is: + * Copyright 2004-2006 Jean-Baptiste Note , et al. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +enum control_frame_types { + P54_CONTROL_TYPE_FILTER_SET = 0, + P54_CONTROL_TYPE_CHANNEL_CHANGE, + P54_CONTROL_TYPE_FREQDONE, + P54_CONTROL_TYPE_DCFINIT, + P54_CONTROL_TYPE_FREEQUEUE = 7, + P54_CONTROL_TYPE_TXDONE, + P54_CONTROL_TYPE_PING, + P54_CONTROL_TYPE_STAT_READBACK, + P54_CONTROL_TYPE_BBP, + P54_CONTROL_TYPE_EEPROM_READBACK, + P54_CONTROL_TYPE_LED +}; + +struct p54_control_hdr { + __le16 magic1; + __le16 len; + __le32 req_id; + __le16 type; /* enum control_frame_types */ + u8 retry1; + u8 retry2; + u8 data[0]; +} __attribute__ ((packed)); + +#define EEPROM_READBACK_LEN (sizeof(struct p54_control_hdr) + 4 /* p54_eeprom_lm86 */) +#define MAX_RX_SIZE (IEEE80211_MAX_RTS_THRESHOLD + sizeof(struct p54_control_hdr) + 20 /* length of struct p54_rx_hdr */ + 16 ) + +#define ISL38XX_DEV_FIRMWARE_ADDR 0x20000 + +struct p54_common { + u32 rx_start; + u32 rx_end; + struct sk_buff_head tx_queue; + void (*tx)(struct ieee80211_hw *dev, struct p54_control_hdr *data, + size_t len, int free_on_tx); + int (*open)(struct ieee80211_hw *dev); + void (*stop)(struct ieee80211_hw *dev); + int mode; + u8 *mac_addr; + struct pda_iq_autocal_entry *iq_autocal; + unsigned int iq_autocal_len; + struct pda_channel_output_limit *output_limit; + unsigned int output_limit_len; + struct pda_pa_curve_data *curve_data; + __le16 rxhw; + u8 version; + unsigned int tx_hdr_len; + void *cached_vdcf; + unsigned int fw_var; + /* FIXME: this channels/modes/rates stuff sucks */ + struct ieee80211_channel channels[14]; + struct ieee80211_rate rates[12]; + struct ieee80211_hw_mode modes[2]; + struct ieee80211_tx_queue_stats tx_stats; +}; + +int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb); +void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw); +int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len); +void p54_fill_eeprom_readback(struct p54_control_hdr *hdr); +struct ieee80211_hw *p54_init_common(size_t priv_data_len); +void p54_free_common(struct ieee80211_hw *dev); + +#endif /* PRISM54_H */ diff --git a/drivers/net/wireless/p54common.c b/drivers/net/wireless/p54common.c new file mode 100644 index 00000000000..b05b5c5b4c0 --- /dev/null +++ b/drivers/net/wireless/p54common.c @@ -0,0 +1,983 @@ + +/* + * Common code for mac80211 Prism54 drivers + * + * Copyright (c) 2006, Michael Wu + * Copyright (c) 2007, Christian Lamparter + * + * Based on the islsm (softmac prism54) driver, which is: + * Copyright 2004-2006 Jean-Baptiste Note , et al. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include + +#include + +#include "p54.h" +#include "p54common.h" + +MODULE_AUTHOR("Michael Wu "); +MODULE_DESCRIPTION("Softmac Prism54 common code"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("prism54common"); + +void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) +{ + struct p54_common *priv = dev->priv; + struct bootrec_exp_if *exp_if; + struct bootrec *bootrec; + u32 *data = (u32 *)fw->data; + u32 *end_data = (u32 *)fw->data + (fw->size >> 2); + u8 *fw_version = NULL; + size_t len; + int i; + + if (priv->rx_start) + return; + + while (data < end_data && *data) + data++; + + while (data < end_data && !*data) + data++; + + bootrec = (struct bootrec *) data; + + while (bootrec->data <= end_data && + (bootrec->data + (len = le32_to_cpu(bootrec->len))) <= end_data) { + u32 code = le32_to_cpu(bootrec->code); + switch (code) { + case BR_CODE_COMPONENT_ID: + switch (be32_to_cpu(*bootrec->data)) { + case FW_FMAC: + printk(KERN_INFO "p54: FreeMAC firmware\n"); + break; + case FW_LM20: + printk(KERN_INFO "p54: LM20 firmware\n"); + break; + case FW_LM86: + printk(KERN_INFO "p54: LM86 firmware\n"); + break; + case FW_LM87: + printk(KERN_INFO "p54: LM87 firmware - not supported yet!\n"); + break; + default: + printk(KERN_INFO "p54: unknown firmware\n"); + break; + } + break; + case BR_CODE_COMPONENT_VERSION: + /* 24 bytes should be enough for all firmwares */ + if (strnlen((unsigned char*)bootrec->data, 24) < 24) + fw_version = (unsigned char*)bootrec->data; + break; + case BR_CODE_DESCR: + priv->rx_start = le32_to_cpu(bootrec->data[1]); + /* FIXME add sanity checking */ + priv->rx_end = le32_to_cpu(bootrec->data[2]) - 0x3500; + break; + case BR_CODE_EXPOSED_IF: + exp_if = (struct bootrec_exp_if *) bootrec->data; + for (i = 0; i < (len * sizeof(*exp_if) / 4); i++) + if (exp_if[i].if_id == 0x1a) + priv->fw_var = le16_to_cpu(exp_if[i].variant); + break; + case BR_CODE_DEPENDENT_IF: + break; + case BR_CODE_END_OF_BRA: + case LEGACY_BR_CODE_END_OF_BRA: + end_data = NULL; + break; + default: + break; + } + bootrec = (struct bootrec *)&bootrec->data[len]; + } + + if (fw_version) + printk(KERN_INFO "p54: FW rev %s - Softmac protocol %x.%x\n", + fw_version, priv->fw_var >> 8, priv->fw_var & 0xff); + + if (priv->fw_var >= 0x300) { + /* Firmware supports QoS, use it! */ + priv->tx_stats.data[0].limit = 3; + priv->tx_stats.data[1].limit = 4; + priv->tx_stats.data[2].limit = 3; + priv->tx_stats.data[3].limit = 1; + dev->queues = 4; + } +} +EXPORT_SYMBOL_GPL(p54_parse_firmware); + +static int p54_convert_rev0_to_rev1(struct ieee80211_hw *dev, + struct pda_pa_curve_data *curve_data) +{ + struct p54_common *priv = dev->priv; + struct pda_pa_curve_data_sample_rev1 *rev1; + struct pda_pa_curve_data_sample_rev0 *rev0; + size_t cd_len = sizeof(*curve_data) + + (curve_data->points_per_channel*sizeof(*rev1) + 2) * + curve_data->channels; + unsigned int i, j; + void *source, *target; + + priv->curve_data = kmalloc(cd_len, GFP_KERNEL); + if (!priv->curve_data) + return -ENOMEM; + + memcpy(priv->curve_data, curve_data, sizeof(*curve_data)); + source = curve_data->data; + target = priv->curve_data->data; + for (i = 0; i < curve_data->channels; i++) { + __le16 *freq = source; + source += sizeof(__le16); + *((__le16 *)target) = *freq; + target += sizeof(__le16); + for (j = 0; j < curve_data->points_per_channel; j++) { + rev1 = target; + rev0 = source; + + rev1->rf_power = rev0->rf_power; + rev1->pa_detector = rev0->pa_detector; + rev1->data_64qam = rev0->pcv; + /* "invent" the points for the other modulations */ +#define SUB(x,y) (u8)((x) - (y)) > (x) ? 0 : (x) - (y) + rev1->data_16qam = SUB(rev0->pcv, 12); + rev1->data_qpsk = SUB(rev1->data_16qam, 12); + rev1->data_bpsk = SUB(rev1->data_qpsk, 12); + rev1->data_barker= SUB(rev1->data_bpsk, 14); +#undef SUB + target += sizeof(*rev1); + source += sizeof(*rev0); + } + } + + return 0; +} + +int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) +{ + struct p54_common *priv = dev->priv; + struct eeprom_pda_wrap *wrap = NULL; + struct pda_entry *entry; + int i = 0; + unsigned int data_len, entry_len; + void *tmp; + int err; + + wrap = (struct eeprom_pda_wrap *) eeprom; + entry = (void *)wrap->data + wrap->len; + i += 2; + i += le16_to_cpu(entry->len)*2; + while (i < len) { + entry_len = le16_to_cpu(entry->len); + data_len = ((entry_len - 1) << 1); + switch (le16_to_cpu(entry->code)) { + case PDR_MAC_ADDRESS: + SET_IEEE80211_PERM_ADDR(dev, entry->data); + break; + case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS: + if (data_len < 2) { + err = -EINVAL; + goto err; + } + + if (2 + entry->data[1]*sizeof(*priv->output_limit) > data_len) { + err = -EINVAL; + goto err; + } + + priv->output_limit = kmalloc(entry->data[1] * + sizeof(*priv->output_limit), GFP_KERNEL); + + if (!priv->output_limit) { + err = -ENOMEM; + goto err; + } + + memcpy(priv->output_limit, &entry->data[2], + entry->data[1]*sizeof(*priv->output_limit)); + priv->output_limit_len = entry->data[1]; + break; + case PDR_PRISM_PA_CAL_CURVE_DATA: + if (data_len < sizeof(struct pda_pa_curve_data)) { + err = -EINVAL; + goto err; + } + + if (((struct pda_pa_curve_data *)entry->data)->cal_method_rev) { + priv->curve_data = kmalloc(data_len, GFP_KERNEL); + if (!priv->curve_data) { + err = -ENOMEM; + goto err; + } + + memcpy(priv->curve_data, entry->data, data_len); + } else { + err = p54_convert_rev0_to_rev1(dev, (struct pda_pa_curve_data *)entry->data); + if (err) + goto err; + } + + break; + case PDR_PRISM_ZIF_TX_IQ_CALIBRATION: + priv->iq_autocal = kmalloc(data_len, GFP_KERNEL); + if (!priv->iq_autocal) { + err = -ENOMEM; + goto err; + } + + memcpy(priv->iq_autocal, entry->data, data_len); + priv->iq_autocal_len = data_len / sizeof(struct pda_iq_autocal_entry); + break; + case PDR_INTERFACE_LIST: + tmp = entry->data; + while ((u8 *)tmp < entry->data + data_len) { + struct bootrec_exp_if *exp_if = tmp; + if (le16_to_cpu(exp_if->if_id) == 0xF) + priv->rxhw = exp_if->variant & cpu_to_le16(0x07); + tmp += sizeof(struct bootrec_exp_if); + } + break; + case PDR_HARDWARE_PLATFORM_COMPONENT_ID: + priv->version = *(u8 *)(entry->data + 1); + break; + case PDR_END: + i = len; + break; + } + + entry = (void *)entry + (entry_len + 1)*2; + i += 2; + i += entry_len*2; + } + + if (!priv->iq_autocal || !priv->output_limit || !priv->curve_data) { + printk(KERN_ERR "p54: not all required entries found in eeprom!\n"); + err = -EINVAL; + goto err; + } + + return 0; + + err: + if (priv->iq_autocal) { + kfree(priv->iq_autocal); + priv->iq_autocal = NULL; + } + + if (priv->output_limit) { + kfree(priv->output_limit); + priv->output_limit = NULL; + } + + if (priv->curve_data) { + kfree(priv->curve_data); + priv->curve_data = NULL; + } + + printk(KERN_ERR "p54: eeprom parse failed!\n"); + return err; +} +EXPORT_SYMBOL_GPL(p54_parse_eeprom); + +void p54_fill_eeprom_readback(struct p54_control_hdr *hdr) +{ + struct p54_eeprom_lm86 *eeprom_hdr; + + hdr->magic1 = cpu_to_le16(0x8000); + hdr->len = cpu_to_le16(sizeof(*eeprom_hdr) + 0x2000); + hdr->type = cpu_to_le16(P54_CONTROL_TYPE_EEPROM_READBACK); + hdr->retry1 = hdr->retry2 = 0; + eeprom_hdr = (struct p54_eeprom_lm86 *) hdr->data; + eeprom_hdr->offset = 0x0; + eeprom_hdr->len = cpu_to_le16(0x2000); +} +EXPORT_SYMBOL_GPL(p54_fill_eeprom_readback); + +static void p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) +{ + struct p54_rx_hdr *hdr = (struct p54_rx_hdr *) skb->data; + struct ieee80211_rx_status rx_status = {0}; + u16 freq = le16_to_cpu(hdr->freq); + + rx_status.ssi = hdr->rssi; + rx_status.rate = hdr->rate & 0x1f; /* report short preambles & CCK too */ + rx_status.channel = freq == 2484 ? 14 : (freq - 2407)/5; + rx_status.freq = freq; + rx_status.phymode = MODE_IEEE80211G; + rx_status.antenna = hdr->antenna; + rx_status.mactime = le64_to_cpu(hdr->timestamp); + + skb_pull(skb, sizeof(*hdr)); + skb_trim(skb, le16_to_cpu(hdr->len)); + + ieee80211_rx_irqsafe(dev, skb, &rx_status); +} + +static void inline p54_wake_free_queues(struct ieee80211_hw *dev) +{ + struct p54_common *priv = dev->priv; + int i; + + /* ieee80211_start_queues is great if all queues are really empty. + * But, what if some are full? */ + + for (i = 0; i < dev->queues; i++) + if (priv->tx_stats.data[i].len < priv->tx_stats.data[i].limit) + ieee80211_wake_queue(dev, i); +} + +static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) +{ + struct p54_common *priv = dev->priv; + struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data; + struct p54_frame_sent_hdr *payload = (struct p54_frame_sent_hdr *) hdr->data; + struct sk_buff *entry = (struct sk_buff *) priv->tx_queue.next; + u32 addr = le32_to_cpu(hdr->req_id) - 0x70; + struct memrecord *range = NULL; + u32 freed = 0; + u32 last_addr = priv->rx_start; + + while (entry != (struct sk_buff *)&priv->tx_queue) { + range = (struct memrecord *)&entry->cb; + if (range->start_addr == addr) { + struct ieee80211_tx_status status = {{0}}; + struct p54_control_hdr *entry_hdr; + struct p54_tx_control_allocdata *entry_data; + int pad = 0; + + if (entry->next != (struct sk_buff *)&priv->tx_queue) + freed = ((struct memrecord *)&entry->next->cb)->start_addr - last_addr; + else + freed = priv->rx_end - last_addr; + + last_addr = range->end_addr; + __skb_unlink(entry, &priv->tx_queue); + if (!range->control) { + kfree_skb(entry); + break; + } + memcpy(&status.control, range->control, + sizeof(status.control)); + kfree(range->control); + priv->tx_stats.data[status.control.queue].len--; + + entry_hdr = (struct p54_control_hdr *) entry->data; + entry_data = (struct p54_tx_control_allocdata *) entry_hdr->data; + if ((entry_hdr->magic1 & cpu_to_le16(0x4000)) != 0) + pad = entry_data->align[0]; + + if (!status.control.flags & IEEE80211_TXCTL_NO_ACK) { + if (!(payload->status & 0x01)) + status.flags |= IEEE80211_TX_STATUS_ACK; + else + status.excessive_retries = 1; + } + status.retry_count = payload->retries - 1; + status.ack_signal = le16_to_cpu(payload->ack_rssi); + skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data)); + ieee80211_tx_status_irqsafe(dev, entry, &status); + break; + } else + last_addr = range->end_addr; + entry = entry->next; + } + + if (freed >= IEEE80211_MAX_RTS_THRESHOLD + 0x170 + + sizeof(struct p54_control_hdr)) + p54_wake_free_queues(dev); +} + +static void p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb) +{ + struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data; + + switch (le16_to_cpu(hdr->type)) { + case P54_CONTROL_TYPE_TXDONE: + p54_rx_frame_sent(dev, skb); + break; + case P54_CONTROL_TYPE_BBP: + break; + default: + printk(KERN_DEBUG "%s: not handling 0x%02x type control frame\n", + wiphy_name(dev->wiphy), le16_to_cpu(hdr->type)); + break; + } +} + +/* returns zero if skb can be reused */ +int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb) +{ + u8 type = le16_to_cpu(*((__le16 *)skb->data)) >> 8; + switch (type) { + case 0x00: + case 0x01: + p54_rx_data(dev, skb); + return -1; + case 0x4d: + /* TODO: do something better... but then again, I've never seen this happen */ + printk(KERN_ERR "%s: Received fault. Probably need to restart hardware now..\n", + wiphy_name(dev->wiphy)); + break; + case 0x80: + p54_rx_control(dev, skb); + break; + default: + printk(KERN_ERR "%s: unknown frame RXed (0x%02x)\n", + wiphy_name(dev->wiphy), type); + break; + } + return 0; +} +EXPORT_SYMBOL_GPL(p54_rx); + +/* + * So, the firmware is somewhat stupid and doesn't know what places in its + * memory incoming data should go to. By poking around in the firmware, we + * can find some unused memory to upload our packets to. However, data that we + * want the card to TX needs to stay intact until the card has told us that + * it is done with it. This function finds empty places we can upload to and + * marks allocated areas as reserved if necessary. p54_rx_frame_sent frees + * allocated areas. + */ +static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, + struct p54_control_hdr *data, u32 len, + struct ieee80211_tx_control *control) +{ + struct p54_common *priv = dev->priv; + struct sk_buff *entry = priv->tx_queue.next; + struct sk_buff *target_skb = NULL; + struct memrecord *range; + u32 last_addr = priv->rx_start; + u32 largest_hole = 0; + u32 target_addr = priv->rx_start; + unsigned long flags; + unsigned int left; + len = (len + 0x170 + 3) & ~0x3; /* 0x70 headroom, 0x100 tailroom */ + + spin_lock_irqsave(&priv->tx_queue.lock, flags); + left = skb_queue_len(&priv->tx_queue); + while (left--) { + u32 hole_size; + range = (struct memrecord *)&entry->cb; + hole_size = range->start_addr - last_addr; + if (!target_skb && hole_size >= len) { + target_skb = entry->prev; + hole_size -= len; + target_addr = last_addr; + } + largest_hole = max(largest_hole, hole_size); + last_addr = range->end_addr; + entry = entry->next; + } + if (!target_skb && priv->rx_end - last_addr >= len) { + target_skb = priv->tx_queue.prev; + largest_hole = max(largest_hole, priv->rx_end - last_addr - len); + if (!skb_queue_empty(&priv->tx_queue)) { + range = (struct memrecord *)&target_skb->cb; + target_addr = range->end_addr; + } + } else + largest_hole = max(largest_hole, priv->rx_end - last_addr); + + if (skb) { + range = (struct memrecord *)&skb->cb; + range->start_addr = target_addr; + range->end_addr = target_addr + len; + range->control = control; + __skb_queue_after(&priv->tx_queue, target_skb, skb); + if (largest_hole < IEEE80211_MAX_RTS_THRESHOLD + 0x170 + + sizeof(struct p54_control_hdr)) + ieee80211_stop_queues(dev); + } + spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + + data->req_id = cpu_to_le32(target_addr + 0x70); +} + +static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb, + struct ieee80211_tx_control *control) +{ + struct ieee80211_tx_queue_stats_data *current_queue; + struct p54_common *priv = dev->priv; + struct p54_control_hdr *hdr; + struct p54_tx_control_allocdata *txhdr; + struct ieee80211_tx_control *control_copy; + size_t padding, len; + u8 rate; + + current_queue = &priv->tx_stats.data[control->queue]; + if (unlikely(current_queue->len > current_queue->limit)) + return NETDEV_TX_BUSY; + current_queue->len++; + current_queue->count++; + if (current_queue->len == current_queue->limit) + ieee80211_stop_queue(dev, control->queue); + + padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3; + len = skb->len; + + control_copy = kmalloc(sizeof(*control), GFP_ATOMIC); + if (control_copy) + memcpy(control_copy, control, sizeof(*control)); + + txhdr = (struct p54_tx_control_allocdata *) + skb_push(skb, sizeof(*txhdr) + padding); + hdr = (struct p54_control_hdr *) skb_push(skb, sizeof(*hdr)); + + if (padding) + hdr->magic1 = cpu_to_le16(0x4010); + else + hdr->magic1 = cpu_to_le16(0x0010); + hdr->len = cpu_to_le16(len); + hdr->type = (control->flags & IEEE80211_TXCTL_NO_ACK) ? 0 : cpu_to_le16(1); + hdr->retry1 = hdr->retry2 = control->retry_limit; + p54_assign_address(dev, skb, hdr, skb->len, control_copy); + + memset(txhdr->wep_key, 0x0, 16); + txhdr->padding = 0; + txhdr->padding2 = 0; + + /* TODO: add support for alternate retry TX rates */ + rate = control->tx_rate; + if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) + rate |= 0x40; + else if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) + rate |= 0x20; + memset(txhdr->rateset, rate, 8); + txhdr->wep_key_present = 0; + txhdr->wep_key_len = 0; + txhdr->frame_type = cpu_to_le32(control->queue + 4); + txhdr->magic4 = 0; + txhdr->antenna = (control->antenna_sel_tx == 0) ? + 2 : control->antenna_sel_tx - 1; + txhdr->output_power = 0x7f; // HW Maximum + txhdr->magic5 = (control->flags & IEEE80211_TXCTL_NO_ACK) ? + 0 : ((rate > 0x3) ? cpu_to_le32(0x33) : cpu_to_le32(0x23)); + if (padding) + txhdr->align[0] = padding; + + priv->tx(dev, hdr, skb->len, 0); + return 0; +} + +static int p54_set_filter(struct ieee80211_hw *dev, u16 filter_type, + const u8 *dst, const u8 *src, u8 antenna, + u32 magic3, u32 magic8, u32 magic9) +{ + struct p54_common *priv = dev->priv; + struct p54_control_hdr *hdr; + struct p54_tx_control_filter *filter; + + hdr = kzalloc(sizeof(*hdr) + sizeof(*filter) + + priv->tx_hdr_len, GFP_KERNEL); + if (!hdr) + return -ENOMEM; + + hdr = (void *)hdr + priv->tx_hdr_len; + + filter = (struct p54_tx_control_filter *) hdr->data; + hdr->magic1 = cpu_to_le16(0x8001); + hdr->len = cpu_to_le16(sizeof(*filter)); + p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*filter), NULL); + hdr->type = cpu_to_le16(P54_CONTROL_TYPE_FILTER_SET); + + filter->filter_type = cpu_to_le16(filter_type); + memcpy(filter->dst, dst, ETH_ALEN); + if (!src) + memset(filter->src, ~0, ETH_ALEN); + else + memcpy(filter->src, src, ETH_ALEN); + filter->antenna = antenna; + filter->magic3 = cpu_to_le32(magic3); + filter->rx_addr = cpu_to_le32(priv->rx_end); + filter->max_rx = cpu_to_le16(0x0620); /* FIXME: for usb ver 1.. maybe */ + filter->rxhw = priv->rxhw; + filter->magic8 = cpu_to_le16(magic8); + filter->magic9 = cpu_to_le16(magic9); + + priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*filter), 1); + return 0; +} + +static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq) +{ + struct p54_common *priv = dev->priv; + struct p54_control_hdr *hdr; + struct p54_tx_control_channel *chan; + unsigned int i; + size_t payload_len = sizeof(*chan) + sizeof(u32)*2 + + sizeof(*chan->curve_data) * + priv->curve_data->points_per_channel; + void *entry; + + hdr = kzalloc(sizeof(*hdr) + payload_len + + priv->tx_hdr_len, GFP_KERNEL); + if (!hdr) + return -ENOMEM; + + hdr = (void *)hdr + priv->tx_hdr_len; + + chan = (struct p54_tx_control_channel *) hdr->data; + + hdr->magic1 = cpu_to_le16(0x8001); + hdr->len = cpu_to_le16(sizeof(*chan)); + hdr->type = cpu_to_le16(P54_CONTROL_TYPE_CHANNEL_CHANGE); + p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + payload_len, NULL); + + chan->magic1 = cpu_to_le16(0x1); + chan->magic2 = cpu_to_le16(0x0); + + for (i = 0; i < priv->iq_autocal_len; i++) { + if (priv->iq_autocal[i].freq != freq) + continue; + + memcpy(&chan->iq_autocal, &priv->iq_autocal[i], + sizeof(*priv->iq_autocal)); + break; + } + if (i == priv->iq_autocal_len) + goto err; + + for (i = 0; i < priv->output_limit_len; i++) { + if (priv->output_limit[i].freq != freq) + continue; + + chan->val_barker = 0x38; + chan->val_bpsk = priv->output_limit[i].val_bpsk; + chan->val_qpsk = priv->output_limit[i].val_qpsk; + chan->val_16qam = priv->output_limit[i].val_16qam; + chan->val_64qam = priv->output_limit[i].val_64qam; + break; + } + if (i == priv->output_limit_len) + goto err; + + chan->pa_points_per_curve = priv->curve_data->points_per_channel; + + entry = priv->curve_data->data; + for (i = 0; i < priv->curve_data->channels; i++) { + if (*((__le16 *)entry) != freq) { + entry += sizeof(__le16); + entry += sizeof(struct pda_pa_curve_data_sample_rev1) * + chan->pa_points_per_curve; + continue; + } + + entry += sizeof(__le16); + memcpy(chan->curve_data, entry, sizeof(*chan->curve_data) * + chan->pa_points_per_curve); + break; + } + + memcpy(hdr->data + payload_len - 4, &chan->val_bpsk, 4); + + priv->tx(dev, hdr, sizeof(*hdr) + payload_len, 1); + return 0; + + err: + printk(KERN_ERR "%s: frequency change failed\n", wiphy_name(dev->wiphy)); + kfree(hdr); + return -EINVAL; +} + +static int p54_set_leds(struct ieee80211_hw *dev, int mode, int link, int act) +{ + struct p54_common *priv = dev->priv; + struct p54_control_hdr *hdr; + struct p54_tx_control_led *led; + + hdr = kzalloc(sizeof(*hdr) + sizeof(*led) + + priv->tx_hdr_len, GFP_KERNEL); + if (!hdr) + return -ENOMEM; + + hdr = (void *)hdr + priv->tx_hdr_len; + hdr->magic1 = cpu_to_le16(0x8001); + hdr->len = cpu_to_le16(sizeof(*led)); + hdr->type = cpu_to_le16(P54_CONTROL_TYPE_LED); + p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*led), NULL); + + led = (struct p54_tx_control_led *) hdr->data; + led->mode = cpu_to_le16(mode); + led->led_permanent = cpu_to_le16(link); + led->led_temporary = cpu_to_le16(act); + led->duration = cpu_to_le16(1000); + + priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*led), 1); + + return 0; +} + +#define P54_SET_QUEUE(queue, ai_fs, cw_min, cw_max, burst) \ +do { \ + queue.aifs = cpu_to_le16(ai_fs); \ + queue.cwmin = cpu_to_le16(cw_min); \ + queue.cwmax = cpu_to_le16(cw_max); \ + queue.txop = (burst == 0) ? \ + 0 : cpu_to_le16((burst * 100) / 32 + 1); \ +} while(0) + +static void p54_init_vdcf(struct ieee80211_hw *dev) +{ + struct p54_common *priv = dev->priv; + struct p54_control_hdr *hdr; + struct p54_tx_control_vdcf *vdcf; + + /* all USB V1 adapters need a extra headroom */ + hdr = (void *)priv->cached_vdcf + priv->tx_hdr_len; + hdr->magic1 = cpu_to_le16(0x8001); + hdr->len = cpu_to_le16(sizeof(*vdcf)); + hdr->type = cpu_to_le16(P54_CONTROL_TYPE_DCFINIT); + hdr->req_id = cpu_to_le32(priv->rx_start); + + vdcf = (struct p54_tx_control_vdcf *) hdr->data; + + P54_SET_QUEUE(vdcf->queue[0], 0x0002, 0x0003, 0x0007, 0x000f); + P54_SET_QUEUE(vdcf->queue[1], 0x0002, 0x0007, 0x000f, 0x001e); + P54_SET_QUEUE(vdcf->queue[2], 0x0002, 0x000f, 0x03ff, 0x0014); + P54_SET_QUEUE(vdcf->queue[3], 0x0007, 0x000f, 0x03ff, 0x0000); +} + +static void p54_set_vdcf(struct ieee80211_hw *dev) +{ + struct p54_common *priv = dev->priv; + struct p54_control_hdr *hdr; + struct p54_tx_control_vdcf *vdcf; + + hdr = (void *)priv->cached_vdcf + priv->tx_hdr_len; + + p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*vdcf), NULL); + + vdcf = (struct p54_tx_control_vdcf *) hdr->data; + + if (dev->conf.flags & IEEE80211_CONF_SHORT_SLOT_TIME) { + vdcf->slottime = 9; + vdcf->magic1 = 0x00; + vdcf->magic2 = 0x10; + } else { + vdcf->slottime = 20; + vdcf->magic1 = 0x0a; + vdcf->magic2 = 0x06; + } + + /* (see prism54/isl_oid.h for further details) */ + vdcf->frameburst = cpu_to_le16(0); + + priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*vdcf), 0); +} + +static int p54_add_interface(struct ieee80211_hw *dev, + struct ieee80211_if_init_conf *conf) +{ + struct p54_common *priv = dev->priv; + int err; + + /* NOTE: using IEEE80211_IF_TYPE_MGMT to indicate no mode selected */ + if (priv->mode != IEEE80211_IF_TYPE_MGMT) + return -1; + + switch (conf->type) { + case IEEE80211_IF_TYPE_STA: + priv->mode = conf->type; + break; + default: + return -EOPNOTSUPP; + } + + priv->mac_addr = conf->mac_addr; + + err = priv->open(dev); + if (err) { + priv->mode = IEEE80211_IF_TYPE_MGMT; + skb_queue_purge(&priv->tx_queue); + return err; + } + + p54_set_filter(dev, 0, priv->mac_addr, NULL, 0, 1, 0, 0xF642); + p54_set_filter(dev, 0, priv->mac_addr, NULL, 1, 0, 0, 0xF642); + p54_set_vdcf(dev); + + switch (conf->type) { + case IEEE80211_IF_TYPE_STA: + p54_set_filter(dev, 1, priv->mac_addr, NULL, 0, 0x15F, 0x1F4, 0); + break; + } + + p54_set_leds(dev, 1, 0, 0); + + return 0; +} + +static void p54_remove_interface(struct ieee80211_hw *dev, + struct ieee80211_if_init_conf *conf) +{ + struct p54_common *priv = dev->priv; + struct sk_buff *skb; + while ((skb = skb_dequeue(&priv->tx_queue))) { + struct memrecord *range = (struct memrecord *)&skb->cb; + if (range->control) + kfree(range->control); + kfree_skb(skb); + } + priv->mode = IEEE80211_IF_TYPE_MGMT; + priv->stop(dev); +} + +static int p54_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) +{ + int ret; + + ret = p54_set_freq(dev, cpu_to_le16(conf->freq)); + p54_set_vdcf(dev); + return ret; +} + +static int p54_config_interface(struct ieee80211_hw *dev, int if_id, + struct ieee80211_if_conf *conf) +{ + struct p54_common *priv = dev->priv; + + p54_set_filter(dev, 0, priv->mac_addr, conf->bssid, 0, 1, 0, 0xF642); + p54_set_filter(dev, 0, priv->mac_addr, conf->bssid, 2, 0, 0, 0); + p54_set_leds(dev, 1, !is_multicast_ether_addr(conf->bssid), 0); + return 0; +} + +static int p54_conf_tx(struct ieee80211_hw *dev, int queue, + const struct ieee80211_tx_queue_params *params) +{ + struct p54_common *priv = dev->priv; + struct p54_tx_control_vdcf *vdcf; + + vdcf = (struct p54_tx_control_vdcf *)(((struct p54_control_hdr *) + ((void *)priv->cached_vdcf + priv->tx_hdr_len))->data); + + if ((params) && !((queue < 0) || (queue > 4))) { + P54_SET_QUEUE(vdcf->queue[queue], params->aifs, + params->cw_min, params->cw_max, params->burst_time); + } else + return -EINVAL; + + p54_set_vdcf(dev); + + return 0; +} + +static int p54_get_stats(struct ieee80211_hw *dev, + struct ieee80211_low_level_stats *stats) +{ + /* TODO */ + return 0; +} + +static int p54_get_tx_stats(struct ieee80211_hw *dev, + struct ieee80211_tx_queue_stats *stats) +{ + struct p54_common *priv = dev->priv; + unsigned int i; + + for (i = 0; i < dev->queues; i++) + memcpy(&stats->data[i], &priv->tx_stats.data[i], + sizeof(stats->data[i])); + + return 0; +} + +static const struct ieee80211_ops p54_ops = { + .tx = p54_tx, + .add_interface = p54_add_interface, + .remove_interface = p54_remove_interface, + .config = p54_config, + .config_interface = p54_config_interface, + .conf_tx = p54_conf_tx, + .get_stats = p54_get_stats, + .get_tx_stats = p54_get_tx_stats +}; + +struct ieee80211_hw *p54_init_common(size_t priv_data_len) +{ + struct ieee80211_hw *dev; + struct p54_common *priv; + int i; + + dev = ieee80211_alloc_hw(priv_data_len, &p54_ops); + if (!dev) + return NULL; + + priv = dev->priv; + priv->mode = IEEE80211_IF_TYPE_MGMT; + skb_queue_head_init(&priv->tx_queue); + memcpy(priv->channels, p54_channels, sizeof(p54_channels)); + memcpy(priv->rates, p54_rates, sizeof(p54_rates)); + priv->modes[1].mode = MODE_IEEE80211B; + priv->modes[1].num_rates = 4; + priv->modes[1].rates = priv->rates; + priv->modes[1].num_channels = ARRAY_SIZE(p54_channels); + priv->modes[1].channels = priv->channels; + priv->modes[0].mode = MODE_IEEE80211G; + priv->modes[0].num_rates = ARRAY_SIZE(p54_rates); + priv->modes[0].rates = priv->rates; + priv->modes[0].num_channels = ARRAY_SIZE(p54_channels); + priv->modes[0].channels = priv->channels; + dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | /* not sure */ + IEEE80211_HW_RX_INCLUDES_FCS; + dev->channel_change_time = 1000; /* TODO: find actual value */ + dev->max_rssi = 127; + + priv->tx_stats.data[0].limit = 5; + dev->queues = 1; + + dev->extra_tx_headroom = sizeof(struct p54_control_hdr) + 4 + + sizeof(struct p54_tx_control_allocdata); + + priv->cached_vdcf = kzalloc(sizeof(struct p54_tx_control_vdcf) + + priv->tx_hdr_len + sizeof(struct p54_control_hdr), GFP_KERNEL); + + if (!priv->cached_vdcf) { + ieee80211_free_hw(dev); + return NULL; + } + + p54_init_vdcf(dev); + + for (i = 0; i < 2; i++) { + if (ieee80211_register_hwmode(dev, &priv->modes[i])) { + kfree(priv->cached_vdcf); + ieee80211_free_hw(dev); + return NULL; + } + } + + return dev; +} +EXPORT_SYMBOL_GPL(p54_init_common); + +void p54_free_common(struct ieee80211_hw *dev) +{ + struct p54_common *priv = dev->priv; + kfree(priv->iq_autocal); + kfree(priv->output_limit); + kfree(priv->curve_data); + kfree(priv->cached_vdcf); +} +EXPORT_SYMBOL_GPL(p54_free_common); + +static int __init p54_init(void) +{ + return 0; +} + +static void __exit p54_exit(void) +{ +} + +module_init(p54_init); +module_exit(p54_exit); diff --git a/drivers/net/wireless/p54common.h b/drivers/net/wireless/p54common.h new file mode 100644 index 00000000000..a721334e20d --- /dev/null +++ b/drivers/net/wireless/p54common.h @@ -0,0 +1,329 @@ +#ifndef PRISM54COMMON_H +#define PRISM54COMMON_H + +/* + * Common code specific definitions for mac80211 Prism54 drivers + * + * Copyright (c) 2006, Michael Wu + * Copyright (c) 2007, Christian Lamparter + * + * Based on the islsm (softmac prism54) driver, which is: + * Copyright 2004-2006 Jean-Baptiste Note , et al. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +struct bootrec { + __le32 code; + __le32 len; + u32 data[0]; +} __attribute__((packed)); + +struct bootrec_exp_if { + __le16 role; + __le16 if_id; + __le16 variant; + __le16 btm_compat; + __le16 top_compat; +} __attribute__((packed)); + +#define BR_CODE_MIN 0x80000000 +#define BR_CODE_COMPONENT_ID 0x80000001 +#define BR_CODE_COMPONENT_VERSION 0x80000002 +#define BR_CODE_DEPENDENT_IF 0x80000003 +#define BR_CODE_EXPOSED_IF 0x80000004 +#define BR_CODE_DESCR 0x80000101 +#define BR_CODE_MAX 0x8FFFFFFF +#define BR_CODE_END_OF_BRA 0xFF0000FF +#define LEGACY_BR_CODE_END_OF_BRA 0xFFFFFFFF + +#define FW_FMAC 0x464d4143 +#define FW_LM86 0x4c4d3836 +#define FW_LM87 0x4c4d3837 +#define FW_LM20 0x4c4d3230 + +/* PDA defines are Copyright (C) 2005 Nokia Corporation (taken from islsm_pda.h) */ + +struct pda_entry { + __le16 len; /* includes both code and data */ + __le16 code; + u8 data[0]; +} __attribute__ ((packed)); + +struct eeprom_pda_wrap { + u32 magic; + u16 pad; + u16 len; + u32 arm_opcode; + u8 data[0]; +} __attribute__ ((packed)); + +struct pda_iq_autocal_entry { + __le16 freq; + __le16 iq_param[4]; +} __attribute__ ((packed)); + +struct pda_channel_output_limit { + __le16 freq; + u8 val_bpsk; + u8 val_qpsk; + u8 val_16qam; + u8 val_64qam; + u8 rate_set_mask; + u8 rate_set_size; +} __attribute__ ((packed)); + +struct pda_pa_curve_data_sample_rev0 { + u8 rf_power; + u8 pa_detector; + u8 pcv; +} __attribute__ ((packed)); + +struct pda_pa_curve_data_sample_rev1 { + u8 rf_power; + u8 pa_detector; + u8 data_barker; + u8 data_bpsk; + u8 data_qpsk; + u8 data_16qam; + u8 data_64qam; + u8 padding; +} __attribute__ ((packed)); + +struct pda_pa_curve_data { + u8 cal_method_rev; + u8 channels; + u8 points_per_channel; + u8 padding; + u8 data[0]; +} __attribute__ ((packed)); + +/* + * this defines the PDR codes used to build PDAs as defined in document + * number 553155. The current implementation mirrors version 1.1 of the + * document and lists only PDRs supported by the ARM platform. + */ + +/* common and choice range (0x0000 - 0x0fff) */ +#define PDR_END 0x0000 +#define PDR_MANUFACTURING_PART_NUMBER 0x0001 +#define PDR_PDA_VERSION 0x0002 +#define PDR_NIC_SERIAL_NUMBER 0x0003 + +#define PDR_MAC_ADDRESS 0x0101 +#define PDR_REGULATORY_DOMAIN_LIST 0x0103 +#define PDR_TEMPERATURE_TYPE 0x0107 + +#define PDR_PRISM_PCI_IDENTIFIER 0x0402 + +/* ARM range (0x1000 - 0x1fff) */ +#define PDR_COUNTRY_INFORMATION 0x1000 +#define PDR_INTERFACE_LIST 0x1001 +#define PDR_HARDWARE_PLATFORM_COMPONENT_ID 0x1002 +#define PDR_OEM_NAME 0x1003 +#define PDR_PRODUCT_NAME 0x1004 +#define PDR_UTF8_OEM_NAME 0x1005 +#define PDR_UTF8_PRODUCT_NAME 0x1006 +#define PDR_COUNTRY_LIST 0x1007 +#define PDR_DEFAULT_COUNTRY 0x1008 + +#define PDR_ANTENNA_GAIN 0x1100 + +#define PDR_PRISM_INDIGO_PA_CALIBRATION_DATA 0x1901 +#define PDR_RSSI_LINEAR_APPROXIMATION 0x1902 +#define PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS 0x1903 +#define PDR_PRISM_PA_CAL_CURVE_DATA 0x1904 +#define PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND 0x1905 +#define PDR_PRISM_ZIF_TX_IQ_CALIBRATION 0x1906 +#define PDR_REGULATORY_POWER_LIMITS 0x1907 +#define PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED 0x1908 +#define PDR_RADIATED_TRANSMISSION_CORRECTION 0x1909 +#define PDR_PRISM_TX_IQ_CALIBRATION 0x190a + +/* reserved range (0x2000 - 0x7fff) */ + +/* customer range (0x8000 - 0xffff) */ +#define PDR_BASEBAND_REGISTERS 0x8000 +#define PDR_PER_CHANNEL_BASEBAND_REGISTERS 0x8001 + +/* stored in skb->cb */ +struct memrecord { + u32 start_addr; + u32 end_addr; + struct ieee80211_tx_control *control; +}; + +struct p54_eeprom_lm86 { + __le16 offset; + __le16 len; + u8 data[0]; +} __attribute__ ((packed)); + +struct p54_rx_hdr { + __le16 magic; + __le16 len; + __le16 freq; + u8 antenna; + u8 rate; + u8 rssi; + u8 quality; + u16 unknown2; + __le64 timestamp; + u8 data[0]; +} __attribute__ ((packed)); + +struct p54_frame_sent_hdr { + u8 status; + u8 retries; + __le16 ack_rssi; + __le16 seq; + u16 rate; +} __attribute__ ((packed)); + +struct p54_tx_control_allocdata { + u8 rateset[8]; + u16 padding; + u8 wep_key_present; + u8 wep_key_len; + u8 wep_key[16]; + __le32 frame_type; + u32 padding2; + __le16 magic4; + u8 antenna; + u8 output_power; + __le32 magic5; + u8 align[0]; +} __attribute__ ((packed)); + +struct p54_tx_control_filter { + __le16 filter_type; + u8 dst[ETH_ALEN]; + u8 src[ETH_ALEN]; + u8 antenna; + u8 debug; + __le32 magic3; + u8 rates[8]; // FIXME: what's this for? + __le32 rx_addr; + __le16 max_rx; + __le16 rxhw; + __le16 magic8; + __le16 magic9; +} __attribute__ ((packed)); + +struct p54_tx_control_channel { + __le16 magic1; + __le16 magic2; + u8 padding1[20]; + struct pda_iq_autocal_entry iq_autocal; + u8 pa_points_per_curve; + u8 val_barker; + u8 val_bpsk; + u8 val_qpsk; + u8 val_16qam; + u8 val_64qam; + struct pda_pa_curve_data_sample_rev1 curve_data[0]; + /* additional padding/data after curve_data */ +} __attribute__ ((packed)); + +struct p54_tx_control_led { + __le16 mode; + __le16 led_temporary; + __le16 led_permanent; + __le16 duration; +} __attribute__ ((packed)); + +struct p54_tx_vdcf_queues { + __le16 aifs; + __le16 cwmin; + __le16 cwmax; + __le16 txop; +} __attribute__ ((packed)); + +struct p54_tx_control_vdcf { + u8 padding; + u8 slottime; + u8 magic1; + u8 magic2; + struct p54_tx_vdcf_queues queue[8]; + u8 pad2[4]; + __le16 frameburst; +} __attribute__ ((packed)); + +static const struct ieee80211_rate p54_rates[] = { + { .rate = 10, + .val = 0, + .val2 = 0x10, + .flags = IEEE80211_RATE_CCK_2 }, + { .rate = 20, + .val = 1, + .val2 = 0x11, + .flags = IEEE80211_RATE_CCK_2 }, + { .rate = 55, + .val = 2, + .val2 = 0x12, + .flags = IEEE80211_RATE_CCK_2 }, + { .rate = 110, + .val = 3, + .val2 = 0x13, + .flags = IEEE80211_RATE_CCK_2 }, + { .rate = 60, + .val = 4, + .flags = IEEE80211_RATE_OFDM }, + { .rate = 90, + .val = 5, + .flags = IEEE80211_RATE_OFDM }, + { .rate = 120, + .val = 6, + .flags = IEEE80211_RATE_OFDM }, + { .rate = 180, + .val = 7, + .flags = IEEE80211_RATE_OFDM }, + { .rate = 240, + .val = 8, + .flags = IEEE80211_RATE_OFDM }, + { .rate = 360, + .val = 9, + .flags = IEEE80211_RATE_OFDM }, + { .rate = 480, + .val = 10, + .flags = IEEE80211_RATE_OFDM }, + { .rate = 540, + .val = 11, + .flags = IEEE80211_RATE_OFDM }, +}; + +// TODO: just generate this.. +static const struct ieee80211_channel p54_channels[] = { + { .chan = 1, + .freq = 2412}, + { .chan = 2, + .freq = 2417}, + { .chan = 3, + .freq = 2422}, + { .chan = 4, + .freq = 2427}, + { .chan = 5, + .freq = 2432}, + { .chan = 6, + .freq = 2437}, + { .chan = 7, + .freq = 2442}, + { .chan = 8, + .freq = 2447}, + { .chan = 9, + .freq = 2452}, + { .chan = 10, + .freq = 2457}, + { .chan = 11, + .freq = 2462}, + { .chan = 12, + .freq = 2467}, + { .chan = 13, + .freq = 2472}, + { .chan = 14, + .freq = 2484} +}; + +#endif /* PRISM54COMMON_H */ diff --git a/drivers/net/wireless/p54pci.c b/drivers/net/wireless/p54pci.c new file mode 100644 index 00000000000..e9ecc663dc7 --- /dev/null +++ b/drivers/net/wireless/p54pci.c @@ -0,0 +1,691 @@ + +/* + * Linux device driver for PCI based Prism54 + * + * Copyright (c) 2006, Michael Wu + * + * Based on the islsm (softmac prism54) driver, which is: + * Copyright 2004-2006 Jean-Baptiste Note , et al. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "p54.h" +#include "p54pci.h" + +MODULE_AUTHOR("Michael Wu "); +MODULE_DESCRIPTION("Prism54 PCI wireless driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("prism54pci"); + +static struct pci_device_id p54p_table[] __devinitdata = { + /* Intersil PRISM Duette/Prism GT Wireless LAN adapter */ + { PCI_DEVICE(0x1260, 0x3890) }, + /* 3COM 3CRWE154G72 Wireless LAN adapter */ + { PCI_DEVICE(0x10b7, 0x6001) }, + /* Intersil PRISM Indigo Wireless LAN adapter */ + { PCI_DEVICE(0x1260, 0x3877) }, + /* Intersil PRISM Javelin/Xbow Wireless LAN adapter */ + { PCI_DEVICE(0x1260, 0x3886) }, +}; + +MODULE_DEVICE_TABLE(pci, p54p_table); + +static int p54p_upload_firmware(struct ieee80211_hw *dev) +{ + struct p54p_priv *priv = dev->priv; + const struct firmware *fw_entry = NULL; + __le32 reg; + int err; + u32 *data; + u32 remains, left, device_addr; + + P54P_WRITE(int_enable, 0); + P54P_READ(int_enable); + udelay(10); + + reg = P54P_READ(ctrl_stat); + reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET); + reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RAMBOOT); + P54P_WRITE(ctrl_stat, reg); + P54P_READ(ctrl_stat); + udelay(10); + + reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET); + P54P_WRITE(ctrl_stat, reg); + wmb(); + udelay(10); + + reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET); + P54P_WRITE(ctrl_stat, reg); + wmb(); + + mdelay(50); + + err = request_firmware(&fw_entry, "isl3886", &priv->pdev->dev); + if (err) { + printk(KERN_ERR "%s (prism54pci): cannot find firmware " + "(isl3886)\n", pci_name(priv->pdev)); + return err; + } + + p54_parse_firmware(dev, fw_entry); + + data = (u32 *) fw_entry->data; + remains = fw_entry->size; + device_addr = ISL38XX_DEV_FIRMWARE_ADDR; + while (remains) { + u32 i = 0; + left = min((u32)0x1000, remains); + P54P_WRITE(direct_mem_base, cpu_to_le32(device_addr)); + P54P_READ(int_enable); + + device_addr += 0x1000; + while (i < left) { + P54P_WRITE(direct_mem_win[i], *data++); + i += sizeof(u32); + } + + remains -= left; + P54P_READ(int_enable); + } + + release_firmware(fw_entry); + + reg = P54P_READ(ctrl_stat); + reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN); + reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET); + reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RAMBOOT); + P54P_WRITE(ctrl_stat, reg); + P54P_READ(ctrl_stat); + udelay(10); + + reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET); + P54P_WRITE(ctrl_stat, reg); + wmb(); + udelay(10); + + reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET); + P54P_WRITE(ctrl_stat, reg); + wmb(); + udelay(10); + + return 0; +} + +static irqreturn_t p54p_simple_interrupt(int irq, void *dev_id) +{ + struct p54p_priv *priv = (struct p54p_priv *) dev_id; + __le32 reg; + + reg = P54P_READ(int_ident); + P54P_WRITE(int_ack, reg); + + if (reg & P54P_READ(int_enable)) + complete(&priv->boot_comp); + + return IRQ_HANDLED; +} + +static int p54p_read_eeprom(struct ieee80211_hw *dev) +{ + struct p54p_priv *priv = dev->priv; + int err; + struct p54_control_hdr *hdr; + void *eeprom; + dma_addr_t rx_mapping, tx_mapping; + u16 alen; + + init_completion(&priv->boot_comp); + err = request_irq(priv->pdev->irq, &p54p_simple_interrupt, + IRQF_SHARED, "prism54pci", priv); + if (err) { + printk(KERN_ERR "%s (prism54pci): failed to register IRQ handler\n", + pci_name(priv->pdev)); + return err; + } + + eeprom = kmalloc(0x2010 + EEPROM_READBACK_LEN, GFP_KERNEL); + if (!eeprom) { + printk(KERN_ERR "%s (prism54pci): no memory for eeprom!\n", + pci_name(priv->pdev)); + err = -ENOMEM; + goto out; + } + + memset(priv->ring_control, 0, sizeof(*priv->ring_control)); + P54P_WRITE(ring_control_base, priv->ring_control_dma); + P54P_READ(ring_control_base); + udelay(10); + + P54P_WRITE(int_enable, cpu_to_le32(ISL38XX_INT_IDENT_INIT)); + P54P_READ(int_enable); + udelay(10); + + P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET)); + + if (!wait_for_completion_interruptible_timeout(&priv->boot_comp, HZ)) { + printk(KERN_ERR "%s (prism54pci): Cannot boot firmware!\n", + pci_name(priv->pdev)); + err = -EINVAL; + goto out; + } + + P54P_WRITE(int_enable, cpu_to_le32(ISL38XX_INT_IDENT_UPDATE)); + P54P_READ(int_enable); + + hdr = eeprom + 0x2010; + p54_fill_eeprom_readback(hdr); + hdr->req_id = cpu_to_le32(priv->common.rx_start); + + rx_mapping = pci_map_single(priv->pdev, eeprom, + 0x2010, PCI_DMA_FROMDEVICE); + tx_mapping = pci_map_single(priv->pdev, (void *)hdr, + EEPROM_READBACK_LEN, PCI_DMA_TODEVICE); + + priv->ring_control->rx_mgmt[0].host_addr = cpu_to_le32(rx_mapping); + priv->ring_control->rx_mgmt[0].len = cpu_to_le16(0x2010); + priv->ring_control->tx_data[0].host_addr = cpu_to_le32(tx_mapping); + priv->ring_control->tx_data[0].device_addr = hdr->req_id; + priv->ring_control->tx_data[0].len = cpu_to_le16(EEPROM_READBACK_LEN); + + priv->ring_control->host_idx[2] = cpu_to_le32(1); + priv->ring_control->host_idx[1] = cpu_to_le32(1); + + wmb(); + mdelay(100); + P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE)); + + wait_for_completion_interruptible_timeout(&priv->boot_comp, HZ); + wait_for_completion_interruptible_timeout(&priv->boot_comp, HZ); + + pci_unmap_single(priv->pdev, tx_mapping, + EEPROM_READBACK_LEN, PCI_DMA_TODEVICE); + pci_unmap_single(priv->pdev, rx_mapping, + 0x2010, PCI_DMA_FROMDEVICE); + + alen = le16_to_cpu(priv->ring_control->rx_mgmt[0].len); + if (le32_to_cpu(priv->ring_control->device_idx[2]) != 1 || + alen < 0x10) { + printk(KERN_ERR "%s (prism54pci): Cannot read eeprom!\n", + pci_name(priv->pdev)); + err = -EINVAL; + goto out; + } + + p54_parse_eeprom(dev, (u8 *)eeprom + 0x10, alen - 0x10); + + out: + kfree(eeprom); + P54P_WRITE(int_enable, 0); + P54P_READ(int_enable); + udelay(10); + free_irq(priv->pdev->irq, priv); + P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET)); + return err; +} + +static void p54p_refill_rx_ring(struct ieee80211_hw *dev) +{ + struct p54p_priv *priv = dev->priv; + u32 limit, host_idx, idx; + + host_idx = le32_to_cpu(priv->ring_control->host_idx[0]); + limit = host_idx; + limit -= le32_to_cpu(priv->ring_control->device_idx[0]); + limit = ARRAY_SIZE(priv->ring_control->rx_data) - limit; + + idx = host_idx % ARRAY_SIZE(priv->ring_control->rx_data); + while (limit-- > 1) { + struct p54p_desc *desc = &priv->ring_control->rx_data[idx]; + + if (!desc->host_addr) { + struct sk_buff *skb; + dma_addr_t mapping; + skb = dev_alloc_skb(MAX_RX_SIZE); + if (!skb) + break; + + mapping = pci_map_single(priv->pdev, + skb_tail_pointer(skb), + MAX_RX_SIZE, + PCI_DMA_FROMDEVICE); + desc->host_addr = cpu_to_le32(mapping); + desc->device_addr = 0; // FIXME: necessary? + desc->len = cpu_to_le16(MAX_RX_SIZE); + desc->flags = 0; + priv->rx_buf[idx] = skb; + } + + idx++; + host_idx++; + idx %= ARRAY_SIZE(priv->ring_control->rx_data); + } + + wmb(); + priv->ring_control->host_idx[0] = cpu_to_le32(host_idx); +} + +static irqreturn_t p54p_interrupt(int irq, void *dev_id) +{ + struct ieee80211_hw *dev = dev_id; + struct p54p_priv *priv = dev->priv; + __le32 reg; + + spin_lock(&priv->lock); + reg = P54P_READ(int_ident); + if (unlikely(reg == 0xFFFFFFFF)) { + spin_unlock(&priv->lock); + return IRQ_HANDLED; + } + + P54P_WRITE(int_ack, reg); + + reg &= P54P_READ(int_enable); + + if (reg & cpu_to_le32(ISL38XX_INT_IDENT_UPDATE)) { + struct p54p_desc *desc; + u32 idx, i; + i = priv->tx_idx; + i %= ARRAY_SIZE(priv->ring_control->tx_data); + priv->tx_idx = idx = le32_to_cpu(priv->ring_control->device_idx[1]); + idx %= ARRAY_SIZE(priv->ring_control->tx_data); + + while (i != idx) { + desc = &priv->ring_control->tx_data[i]; + if (priv->tx_buf[i]) { + kfree(priv->tx_buf[i]); + priv->tx_buf[i] = NULL; + } + + pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr), + le16_to_cpu(desc->len), PCI_DMA_TODEVICE); + + desc->host_addr = 0; + desc->device_addr = 0; + desc->len = 0; + desc->flags = 0; + + i++; + i %= ARRAY_SIZE(priv->ring_control->tx_data); + } + + i = priv->rx_idx; + i %= ARRAY_SIZE(priv->ring_control->rx_data); + priv->rx_idx = idx = le32_to_cpu(priv->ring_control->device_idx[0]); + idx %= ARRAY_SIZE(priv->ring_control->rx_data); + while (i != idx) { + u16 len; + struct sk_buff *skb; + desc = &priv->ring_control->rx_data[i]; + len = le16_to_cpu(desc->len); + skb = priv->rx_buf[i]; + + skb_put(skb, len); + + if (p54_rx(dev, skb)) { + pci_unmap_single(priv->pdev, + le32_to_cpu(desc->host_addr), + MAX_RX_SIZE, PCI_DMA_FROMDEVICE); + + priv->rx_buf[i] = NULL; + desc->host_addr = 0; + } else { + skb_trim(skb, 0); + desc->len = cpu_to_le16(MAX_RX_SIZE); + } + + i++; + i %= ARRAY_SIZE(priv->ring_control->rx_data); + } + + p54p_refill_rx_ring(dev); + + wmb(); + P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE)); + } else if (reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT)) + complete(&priv->boot_comp); + + spin_unlock(&priv->lock); + + return reg ? IRQ_HANDLED : IRQ_NONE; +} + +static void p54p_tx(struct ieee80211_hw *dev, struct p54_control_hdr *data, + size_t len, int free_on_tx) +{ + struct p54p_priv *priv = dev->priv; + unsigned long flags; + struct p54p_desc *desc; + dma_addr_t mapping; + u32 device_idx, idx, i; + + spin_lock_irqsave(&priv->lock, flags); + + device_idx = le32_to_cpu(priv->ring_control->device_idx[1]); + idx = le32_to_cpu(priv->ring_control->host_idx[1]); + i = idx % ARRAY_SIZE(priv->ring_control->tx_data); + + mapping = pci_map_single(priv->pdev, data, len, PCI_DMA_TODEVICE); + desc = &priv->ring_control->tx_data[i]; + desc->host_addr = cpu_to_le32(mapping); + desc->device_addr = data->req_id; + desc->len = cpu_to_le16(len); + desc->flags = 0; + + wmb(); + priv->ring_control->host_idx[1] = cpu_to_le32(idx + 1); + + if (free_on_tx) + priv->tx_buf[i] = data; + + spin_unlock_irqrestore(&priv->lock, flags); + + P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE)); + P54P_READ(dev_int); + + /* FIXME: unlikely to happen because the device usually runs out of + memory before we fill the ring up, but we can make it impossible */ + if (idx - device_idx > ARRAY_SIZE(priv->ring_control->tx_data) - 2) + printk(KERN_INFO "%s: tx overflow.\n", wiphy_name(dev->wiphy)); +} + +static int p54p_open(struct ieee80211_hw *dev) +{ + struct p54p_priv *priv = dev->priv; + int err; + + init_completion(&priv->boot_comp); + err = request_irq(priv->pdev->irq, &p54p_interrupt, + IRQF_SHARED, "prism54pci", dev); + if (err) { + printk(KERN_ERR "%s: failed to register IRQ handler\n", + wiphy_name(dev->wiphy)); + return err; + } + + memset(priv->ring_control, 0, sizeof(*priv->ring_control)); + priv->rx_idx = priv->tx_idx = 0; + p54p_refill_rx_ring(dev); + + p54p_upload_firmware(dev); + + P54P_WRITE(ring_control_base, priv->ring_control_dma); + P54P_READ(ring_control_base); + wmb(); + udelay(10); + + P54P_WRITE(int_enable, cpu_to_le32(ISL38XX_INT_IDENT_INIT)); + P54P_READ(int_enable); + wmb(); + udelay(10); + + P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET)); + P54P_READ(dev_int); + + if (!wait_for_completion_interruptible_timeout(&priv->boot_comp, HZ)) { + printk(KERN_ERR "%s: Cannot boot firmware!\n", + wiphy_name(dev->wiphy)); + free_irq(priv->pdev->irq, dev); + return -ETIMEDOUT; + } + + P54P_WRITE(int_enable, cpu_to_le32(ISL38XX_INT_IDENT_UPDATE)); + P54P_READ(int_enable); + wmb(); + udelay(10); + + P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE)); + P54P_READ(dev_int); + wmb(); + udelay(10); + + return 0; +} + +static void p54p_stop(struct ieee80211_hw *dev) +{ + struct p54p_priv *priv = dev->priv; + unsigned int i; + struct p54p_desc *desc; + + P54P_WRITE(int_enable, 0); + P54P_READ(int_enable); + udelay(10); + + free_irq(priv->pdev->irq, dev); + + P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET)); + + for (i = 0; i < ARRAY_SIZE(priv->rx_buf); i++) { + desc = &priv->ring_control->rx_data[i]; + if (desc->host_addr) + pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr), + MAX_RX_SIZE, PCI_DMA_FROMDEVICE); + kfree_skb(priv->rx_buf[i]); + priv->rx_buf[i] = NULL; + } + + for (i = 0; i < ARRAY_SIZE(priv->tx_buf); i++) { + desc = &priv->ring_control->tx_data[i]; + if (desc->host_addr) + pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr), + le16_to_cpu(desc->len), PCI_DMA_TODEVICE); + + kfree(priv->tx_buf[i]); + priv->tx_buf[i] = NULL; + } + + memset(priv->ring_control, 0, sizeof(*priv->ring_control)); +} + +static int __devinit p54p_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct p54p_priv *priv; + struct ieee80211_hw *dev; + unsigned long mem_addr, mem_len; + int err; + DECLARE_MAC_BUF(mac); + + err = pci_enable_device(pdev); + if (err) { + printk(KERN_ERR "%s (prism54pci): Cannot enable new PCI device\n", + pci_name(pdev)); + return err; + } + + mem_addr = pci_resource_start(pdev, 0); + mem_len = pci_resource_len(pdev, 0); + if (mem_len < sizeof(struct p54p_csr)) { + printk(KERN_ERR "%s (prism54pci): Too short PCI resources\n", + pci_name(pdev)); + pci_disable_device(pdev); + return err; + } + + err = pci_request_regions(pdev, "prism54pci"); + if (err) { + printk(KERN_ERR "%s (prism54pci): Cannot obtain PCI resources\n", + pci_name(pdev)); + return err; + } + + if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) || + pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) { + printk(KERN_ERR "%s (prism54pci): No suitable DMA available\n", + pci_name(pdev)); + goto err_free_reg; + } + + pci_set_master(pdev); + pci_try_set_mwi(pdev); + + pci_write_config_byte(pdev, 0x40, 0); + pci_write_config_byte(pdev, 0x41, 0); + + dev = p54_init_common(sizeof(*priv)); + if (!dev) { + printk(KERN_ERR "%s (prism54pci): ieee80211 alloc failed\n", + pci_name(pdev)); + err = -ENOMEM; + goto err_free_reg; + } + + priv = dev->priv; + priv->pdev = pdev; + + SET_IEEE80211_DEV(dev, &pdev->dev); + pci_set_drvdata(pdev, dev); + + priv->map = ioremap(mem_addr, mem_len); + if (!priv->map) { + printk(KERN_ERR "%s (prism54pci): Cannot map device memory\n", + pci_name(pdev)); + err = -EINVAL; // TODO: use a better error code? + goto err_free_dev; + } + + priv->ring_control = pci_alloc_consistent(pdev, sizeof(*priv->ring_control), + &priv->ring_control_dma); + if (!priv->ring_control) { + printk(KERN_ERR "%s (prism54pci): Cannot allocate rings\n", + pci_name(pdev)); + err = -ENOMEM; + goto err_iounmap; + } + memset(priv->ring_control, 0, sizeof(*priv->ring_control)); + + err = p54p_upload_firmware(dev); + if (err) + goto err_free_desc; + + err = p54p_read_eeprom(dev); + if (err) + goto err_free_desc; + + priv->common.open = p54p_open; + priv->common.stop = p54p_stop; + priv->common.tx = p54p_tx; + + spin_lock_init(&priv->lock); + + err = ieee80211_register_hw(dev); + if (err) { + printk(KERN_ERR "%s (prism54pci): Cannot register netdevice\n", + pci_name(pdev)); + goto err_free_common; + } + + printk(KERN_INFO "%s: hwaddr %s, isl38%02x\n", + wiphy_name(dev->wiphy), + print_mac(mac, dev->wiphy->perm_addr), + priv->common.version); + + return 0; + + err_free_common: + p54_free_common(dev); + + err_free_desc: + pci_free_consistent(pdev, sizeof(*priv->ring_control), + priv->ring_control, priv->ring_control_dma); + + err_iounmap: + iounmap(priv->map); + + err_free_dev: + pci_set_drvdata(pdev, NULL); + ieee80211_free_hw(dev); + + err_free_reg: + pci_release_regions(pdev); + pci_disable_device(pdev); + return err; +} + +static void __devexit p54p_remove(struct pci_dev *pdev) +{ + struct ieee80211_hw *dev = pci_get_drvdata(pdev); + struct p54p_priv *priv; + + if (!dev) + return; + + ieee80211_unregister_hw(dev); + priv = dev->priv; + pci_free_consistent(pdev, sizeof(*priv->ring_control), + priv->ring_control, priv->ring_control_dma); + p54_free_common(dev); + iounmap(priv->map); + pci_release_regions(pdev); + pci_disable_device(pdev); + ieee80211_free_hw(dev); +} + +#ifdef CONFIG_PM +static int p54p_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct ieee80211_hw *dev = pci_get_drvdata(pdev); + struct p54p_priv *priv = dev->priv; + + if (priv->common.mode != IEEE80211_IF_TYPE_MGMT) { + ieee80211_stop_queues(dev); + p54p_stop(dev); + } + + pci_save_state(pdev); + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + return 0; +} + +static int p54p_resume(struct pci_dev *pdev) +{ + struct ieee80211_hw *dev = pci_get_drvdata(pdev); + struct p54p_priv *priv = dev->priv; + + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + + if (priv->common.mode != IEEE80211_IF_TYPE_MGMT) { + p54p_open(dev); + ieee80211_start_queues(dev); + } + + return 0; +} +#endif /* CONFIG_PM */ + +static struct pci_driver p54p_driver = { + .name = "prism54pci", + .id_table = p54p_table, + .probe = p54p_probe, + .remove = __devexit_p(p54p_remove), +#ifdef CONFIG_PM + .suspend = p54p_suspend, + .resume = p54p_resume, +#endif /* CONFIG_PM */ +}; + +static int __init p54p_init(void) +{ + return pci_register_driver(&p54p_driver); +} + +static void __exit p54p_exit(void) +{ + pci_unregister_driver(&p54p_driver); +} + +module_init(p54p_init); +module_exit(p54p_exit); diff --git a/drivers/net/wireless/p54pci.h b/drivers/net/wireless/p54pci.h new file mode 100644 index 00000000000..52feb597dc4 --- /dev/null +++ b/drivers/net/wireless/p54pci.h @@ -0,0 +1,106 @@ +#ifndef PRISM54PCI_H +#define PRISM54PCI_H + +/* + * Defines for PCI based mac80211 Prism54 driver + * + * Copyright (c) 2006, Michael Wu + * + * Based on the islsm (softmac prism54) driver, which is: + * Copyright 2004-2006 Jean-Baptiste Note , et al. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* Device Interrupt register bits */ +#define ISL38XX_DEV_INT_RESET 0x0001 +#define ISL38XX_DEV_INT_UPDATE 0x0002 +#define ISL38XX_DEV_INT_WAKEUP 0x0008 +#define ISL38XX_DEV_INT_SLEEP 0x0010 +#define ISL38XX_DEV_INT_ABORT 0x0020 +/* these two only used in USB */ +#define ISL38XX_DEV_INT_DATA 0x0040 +#define ISL38XX_DEV_INT_MGMT 0x0080 + +#define ISL38XX_DEV_INT_PCIUART_CTS 0x4000 +#define ISL38XX_DEV_INT_PCIUART_DR 0x8000 + +/* Interrupt Identification/Acknowledge/Enable register bits */ +#define ISL38XX_INT_IDENT_UPDATE 0x0002 +#define ISL38XX_INT_IDENT_INIT 0x0004 +#define ISL38XX_INT_IDENT_WAKEUP 0x0008 +#define ISL38XX_INT_IDENT_SLEEP 0x0010 +#define ISL38XX_INT_IDENT_PCIUART_CTS 0x4000 +#define ISL38XX_INT_IDENT_PCIUART_DR 0x8000 + +/* Control/Status register bits */ +#define ISL38XX_CTRL_STAT_SLEEPMODE 0x00000200 +#define ISL38XX_CTRL_STAT_CLKRUN 0x00800000 +#define ISL38XX_CTRL_STAT_RESET 0x10000000 +#define ISL38XX_CTRL_STAT_RAMBOOT 0x20000000 +#define ISL38XX_CTRL_STAT_STARTHALTED 0x40000000 +#define ISL38XX_CTRL_STAT_HOST_OVERRIDE 0x80000000 + +struct p54p_csr { + __le32 dev_int; + u8 unused_1[12]; + __le32 int_ident; + __le32 int_ack; + __le32 int_enable; + u8 unused_2[4]; + union { + __le32 ring_control_base; + __le32 gen_purp_com[2]; + }; + u8 unused_3[8]; + __le32 direct_mem_base; + u8 unused_4[44]; + __le32 dma_addr; + __le32 dma_len; + __le32 dma_ctrl; + u8 unused_5[12]; + __le32 ctrl_stat; + u8 unused_6[1924]; + u8 cardbus_cis[0x800]; + u8 direct_mem_win[0x1000]; +} __attribute__ ((packed)); + +/* usb backend only needs the register defines above */ +#ifndef PRISM54USB_H +struct p54p_desc { + __le32 host_addr; + __le32 device_addr; + __le16 len; + __le16 flags; +} __attribute__ ((packed)); + +struct p54p_ring_control { + __le32 host_idx[4]; + __le32 device_idx[4]; + struct p54p_desc rx_data[8]; + struct p54p_desc tx_data[32]; + struct p54p_desc rx_mgmt[4]; + struct p54p_desc tx_mgmt[4]; +} __attribute__ ((packed)); + +#define P54P_READ(r) __raw_readl(&priv->map->r) +#define P54P_WRITE(r, val) __raw_writel((__force u32)(val), &priv->map->r) + +struct p54p_priv { + struct p54_common common; + struct pci_dev *pdev; + struct p54p_csr __iomem *map; + + spinlock_t lock; + struct p54p_ring_control *ring_control; + dma_addr_t ring_control_dma; + u32 rx_idx, tx_idx; + struct sk_buff *rx_buf[8]; + void *tx_buf[32]; + struct completion boot_comp; +}; + +#endif /* PRISM54USB_H */ +#endif /* PRISM54PCI_H */ diff --git a/drivers/net/wireless/p54usb.c b/drivers/net/wireless/p54usb.c new file mode 100644 index 00000000000..7446c39ce5d --- /dev/null +++ b/drivers/net/wireless/p54usb.c @@ -0,0 +1,906 @@ + +/* + * Linux device driver for USB based Prism54 + * + * Copyright (c) 2006, Michael Wu + * + * Based on the islsm (softmac prism54) driver, which is: + * Copyright 2004-2006 Jean-Baptiste Note , et al. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "p54.h" +#include "p54usb.h" + +MODULE_AUTHOR("Michael Wu "); +MODULE_DESCRIPTION("Prism54 USB wireless driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("prism54usb"); + +static struct usb_device_id p54u_table[] __devinitdata = { + /* Version 1 devices (pci chip + net2280) */ + {USB_DEVICE(0x0506, 0x0a11)}, /* 3COM 3CRWE254G72 */ + {USB_DEVICE(0x0707, 0xee06)}, /* SMC 2862W-G */ + {USB_DEVICE(0x083a, 0x4501)}, /* Accton 802.11g WN4501 USB */ + {USB_DEVICE(0x083a, 0x4502)}, /* Siemens Gigaset USB Adapter */ + {USB_DEVICE(0x0846, 0x4200)}, /* Netgear WG121 */ + {USB_DEVICE(0x0846, 0x4210)}, /* Netgear WG121 the second ? */ + {USB_DEVICE(0x0846, 0x4220)}, /* Netgear WG111 */ + {USB_DEVICE(0x0cde, 0x0006)}, /* Medion 40900, Roper Europe */ + {USB_DEVICE(0x124a, 0x4023)}, /* Shuttle PN15, Airvast WM168g, IOGear GWU513 */ + {USB_DEVICE(0x1915, 0x2234)}, /* Linksys WUSB54G OEM */ + {USB_DEVICE(0x1915, 0x2235)}, /* Linksys WUSB54G Portable OEM */ + {USB_DEVICE(0x2001, 0x3701)}, /* DLink DWL-G120 Spinnaker */ + {USB_DEVICE(0x2001, 0x3703)}, /* DLink DWL-G122 */ + {USB_DEVICE(0x5041, 0x2234)}, /* Linksys WUSB54G */ + {USB_DEVICE(0x5041, 0x2235)}, /* Linksys WUSB54G Portable */ + + /* Version 2 devices (3887) */ + {USB_DEVICE(0x050d, 0x7050)}, /* Belkin F5D7050 ver 1000 */ + {USB_DEVICE(0x0572, 0x2000)}, /* Cohiba Proto board */ + {USB_DEVICE(0x0572, 0x2002)}, /* Cohiba Proto board */ + {USB_DEVICE(0x0707, 0xee13)}, /* SMC 2862W-G version 2 */ + {USB_DEVICE(0x083a, 0x4521)}, /* Siemens Gigaset USB Adapter 54 version 2 */ + {USB_DEVICE(0x0846, 0x4240)}, /* Netgear WG111 (v2) */ + {USB_DEVICE(0x0915, 0x2000)}, /* Cohiba Proto board */ + {USB_DEVICE(0x0915, 0x2002)}, /* Cohiba Proto board */ + {USB_DEVICE(0x0baf, 0x0118)}, /* U.S. Robotics U5 802.11g Adapter*/ + {USB_DEVICE(0x0bf8, 0x1009)}, /* FUJITSU E-5400 USB D1700*/ + {USB_DEVICE(0x0cde, 0x0006)}, /* Medion MD40900 */ + {USB_DEVICE(0x0cde, 0x0008)}, /* Sagem XG703A */ + {USB_DEVICE(0x0d8e, 0x3762)}, /* DLink DWL-G120 Cohiba */ + {USB_DEVICE(0x09aa, 0x1000)}, /* Spinnaker Proto board */ + {USB_DEVICE(0x1435, 0x0427)}, /* Inventel UR054G */ + {USB_DEVICE(0x2001, 0x3704)}, /* DLink DWL-G122 rev A2 */ + {USB_DEVICE(0x413c, 0x8102)}, /* Spinnaker DUT */ + {USB_DEVICE(0x413c, 0x8104)}, /* Cohiba Proto board */ + {} +}; + +MODULE_DEVICE_TABLE(usb, p54u_table); + +static void p54u_rx_cb(struct urb *urb) +{ + struct sk_buff *skb = (struct sk_buff *) urb->context; + struct p54u_rx_info *info = (struct p54u_rx_info *)skb->cb; + struct ieee80211_hw *dev = info->dev; + struct p54u_priv *priv = dev->priv; + + if (unlikely(urb->status)) { + info->urb = NULL; + usb_free_urb(urb); + return; + } + + skb_unlink(skb, &priv->rx_queue); + skb_put(skb, urb->actual_length); + if (!priv->hw_type) + skb_pull(skb, sizeof(struct net2280_tx_hdr)); + + if (p54_rx(dev, skb)) { + skb = dev_alloc_skb(MAX_RX_SIZE); + if (unlikely(!skb)) { + usb_free_urb(urb); + /* TODO check rx queue length and refill *somewhere* */ + return; + } + + info = (struct p54u_rx_info *) skb->cb; + info->urb = urb; + info->dev = dev; + urb->transfer_buffer = skb_tail_pointer(skb); + urb->context = skb; + skb_queue_tail(&priv->rx_queue, skb); + } else { + skb_trim(skb, 0); + skb_queue_tail(&priv->rx_queue, skb); + } + + usb_submit_urb(urb, GFP_ATOMIC); +} + +static void p54u_tx_cb(struct urb *urb) +{ + usb_free_urb(urb); +} + +static void p54u_tx_free_cb(struct urb *urb) +{ + kfree(urb->transfer_buffer); + usb_free_urb(urb); +} + +static int p54u_init_urbs(struct ieee80211_hw *dev) +{ + struct p54u_priv *priv = dev->priv; + struct urb *entry; + struct sk_buff *skb; + struct p54u_rx_info *info; + + while (skb_queue_len(&priv->rx_queue) < 32) { + skb = __dev_alloc_skb(MAX_RX_SIZE, GFP_KERNEL); + if (!skb) + break; + entry = usb_alloc_urb(0, GFP_KERNEL); + if (!entry) { + kfree_skb(skb); + break; + } + usb_fill_bulk_urb(entry, priv->udev, usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), skb_tail_pointer(skb), MAX_RX_SIZE, p54u_rx_cb, skb); + info = (struct p54u_rx_info *) skb->cb; + info->urb = entry; + info->dev = dev; + skb_queue_tail(&priv->rx_queue, skb); + usb_submit_urb(entry, GFP_KERNEL); + } + + return 0; +} + +static void p54u_free_urbs(struct ieee80211_hw *dev) +{ + struct p54u_priv *priv = dev->priv; + struct p54u_rx_info *info; + struct sk_buff *skb; + + while ((skb = skb_dequeue(&priv->rx_queue))) { + info = (struct p54u_rx_info *) skb->cb; + if (!info->urb) + continue; + + usb_kill_urb(info->urb); + kfree_skb(skb); + } +} + +static void p54u_tx_3887(struct ieee80211_hw *dev, struct p54_control_hdr *data, + size_t len, int free_on_tx) +{ + struct p54u_priv *priv = dev->priv; + struct urb *addr_urb, *data_urb; + + addr_urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!addr_urb) + return; + + data_urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!data_urb) { + usb_free_urb(addr_urb); + return; + } + + usb_fill_bulk_urb(addr_urb, priv->udev, + usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), &data->req_id, + sizeof(data->req_id), p54u_tx_cb, dev); + usb_fill_bulk_urb(data_urb, priv->udev, + usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), data, len, + free_on_tx ? p54u_tx_free_cb : p54u_tx_cb, dev); + + usb_submit_urb(addr_urb, GFP_ATOMIC); + usb_submit_urb(data_urb, GFP_ATOMIC); +} + +static void p54u_tx_net2280(struct ieee80211_hw *dev, struct p54_control_hdr *data, + size_t len, int free_on_tx) +{ + struct p54u_priv *priv = dev->priv; + struct urb *int_urb, *data_urb; + struct net2280_tx_hdr *hdr; + struct net2280_reg_write *reg; + + reg = kmalloc(sizeof(*reg), GFP_ATOMIC); + if (!reg) + return; + + int_urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!int_urb) { + kfree(reg); + return; + } + + data_urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!data_urb) { + kfree(reg); + usb_free_urb(int_urb); + return; + } + + reg->port = cpu_to_le16(NET2280_DEV_U32); + reg->addr = cpu_to_le32(P54U_DEV_BASE); + reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA); + + len += sizeof(*data); + hdr = (void *)data - sizeof(*hdr); + memset(hdr, 0, sizeof(*hdr)); + hdr->device_addr = data->req_id; + hdr->len = cpu_to_le16(len); + + usb_fill_bulk_urb(int_urb, priv->udev, + usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg), + p54u_tx_free_cb, dev); + usb_submit_urb(int_urb, GFP_ATOMIC); + + usb_fill_bulk_urb(data_urb, priv->udev, + usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), hdr, len + sizeof(*hdr), + free_on_tx ? p54u_tx_free_cb : p54u_tx_cb, dev); + usb_submit_urb(data_urb, GFP_ATOMIC); +} + +static int p54u_write(struct p54u_priv *priv, + struct net2280_reg_write *buf, + enum net2280_op_type type, + __le32 addr, __le32 val) +{ + unsigned int ep; + int alen; + + if (type & 0x0800) + ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV); + else + ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_BRG); + + buf->port = cpu_to_le16(type); + buf->addr = addr; + buf->val = val; + + return usb_bulk_msg(priv->udev, ep, buf, sizeof(*buf), &alen, 1000); +} + +static int p54u_read(struct p54u_priv *priv, void *buf, + enum net2280_op_type type, + __le32 addr, __le32 *val) +{ + struct net2280_reg_read *read = buf; + __le32 *reg = buf; + unsigned int ep; + int alen, err; + + if (type & 0x0800) + ep = P54U_PIPE_DEV; + else + ep = P54U_PIPE_BRG; + + read->port = cpu_to_le16(type); + read->addr = addr; + + err = usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep), + read, sizeof(*read), &alen, 1000); + if (err) + return err; + + err = usb_bulk_msg(priv->udev, usb_rcvbulkpipe(priv->udev, ep), + reg, sizeof(*reg), &alen, 1000); + if (err) + return err; + + *val = *reg; + return 0; +} + +static int p54u_bulk_msg(struct p54u_priv *priv, unsigned int ep, + void *data, size_t len) +{ + int alen; + return usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep), + data, len, &alen, 2000); +} + +static int p54u_read_eeprom(struct ieee80211_hw *dev) +{ + struct p54u_priv *priv = dev->priv; + void *buf; + struct p54_control_hdr *hdr; + int err, alen; + size_t offset = priv->hw_type ? 0x10 : 0x20; + + buf = kmalloc(0x2020, GFP_KERNEL); + if (!buf) { + printk(KERN_ERR "prism54usb: cannot allocate memory for" + "eeprom readback!\n"); + return -ENOMEM; + } + + if (priv->hw_type) { + *((u32 *) buf) = priv->common.rx_start; + err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32)); + if (err) { + printk(KERN_ERR "prism54usb: addr send failed\n"); + goto fail; + } + } else { + struct net2280_reg_write *reg = buf; + reg->port = cpu_to_le16(NET2280_DEV_U32); + reg->addr = cpu_to_le32(P54U_DEV_BASE); + reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA); + err = p54u_bulk_msg(priv, P54U_PIPE_DEV, buf, sizeof(*reg)); + if (err) { + printk(KERN_ERR "prism54usb: dev_int send failed\n"); + goto fail; + } + } + + hdr = buf + priv->common.tx_hdr_len; + p54_fill_eeprom_readback(hdr); + hdr->req_id = cpu_to_le32(priv->common.rx_start); + if (priv->common.tx_hdr_len) { + struct net2280_tx_hdr *tx_hdr = buf; + tx_hdr->device_addr = hdr->req_id; + tx_hdr->len = cpu_to_le16(EEPROM_READBACK_LEN); + } + + /* we can just pretend to send 0x2000 bytes of nothing in the headers */ + err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, + EEPROM_READBACK_LEN + priv->common.tx_hdr_len); + if (err) { + printk(KERN_ERR "prism54usb: eeprom req send failed\n"); + goto fail; + } + + err = usb_bulk_msg(priv->udev, + usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), + buf, 0x2020, &alen, 1000); + if (!err && alen > offset) { + p54_parse_eeprom(dev, (u8 *)buf + offset, alen - offset); + } else { + printk(KERN_ERR "prism54usb: eeprom read failed!\n"); + err = -EINVAL; + goto fail; + } + + fail: + kfree(buf); + return err; +} + +static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) +{ + static char start_string[] = "~~~~<\r"; + struct p54u_priv *priv = dev->priv; + const struct firmware *fw_entry = NULL; + int err, alen; + u8 carry = 0; + u8 *buf, *tmp, *data; + unsigned int left, remains, block_size; + struct x2_header *hdr; + unsigned long timeout; + + tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL); + if (!buf) { + printk(KERN_ERR "p54usb: cannot allocate firmware upload buffer!\n"); + err = -ENOMEM; + goto err_bufalloc; + } + + memcpy(buf, start_string, 4); + err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 4); + if (err) { + printk(KERN_ERR "p54usb: reset failed! (%d)\n", err); + goto err_reset; + } + + err = request_firmware(&fw_entry, "isl3887usb_bare", &priv->udev->dev); + if (err) { + printk(KERN_ERR "p54usb: cannot find firmware (isl3887usb_bare)!\n"); + goto err_req_fw_failed; + } + + p54_parse_firmware(dev, fw_entry); + + left = block_size = min((size_t)P54U_FW_BLOCK, fw_entry->size); + strcpy(buf, start_string); + left -= strlen(start_string); + tmp += strlen(start_string); + + data = fw_entry->data; + remains = fw_entry->size; + + hdr = (struct x2_header *)(buf + strlen(start_string)); + memcpy(hdr->signature, X2_SIGNATURE, X2_SIGNATURE_SIZE); + hdr->fw_load_addr = cpu_to_le32(ISL38XX_DEV_FIRMWARE_ADDR); + hdr->fw_length = cpu_to_le32(fw_entry->size); + hdr->crc = cpu_to_le32(~crc32_le(~0, (void *)&hdr->fw_load_addr, + sizeof(u32)*2)); + left -= sizeof(*hdr); + tmp += sizeof(*hdr); + + while (remains) { + while (left--) { + if (carry) { + *tmp++ = carry; + carry = 0; + remains--; + continue; + } + switch (*data) { + case '~': + *tmp++ = '}'; + carry = '^'; + break; + case '}': + *tmp++ = '}'; + carry = ']'; + break; + default: + *tmp++ = *data; + remains--; + break; + } + data++; + } + + err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_size); + if (err) { + printk(KERN_ERR "prism54usb: firmware upload failed!\n"); + goto err_upload_failed; + } + + tmp = buf; + left = block_size = min((unsigned int)P54U_FW_BLOCK, remains); + } + + *((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, fw_entry->data, fw_entry->size)); + err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32)); + if (err) { + printk(KERN_ERR "prism54usb: firmware upload failed!\n"); + goto err_upload_failed; + } + + timeout = jiffies + msecs_to_jiffies(1000); + while (!(err = usb_bulk_msg(priv->udev, + usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) { + if (alen > 2 && !memcmp(buf, "OK", 2)) + break; + + if (alen > 5 && !memcmp(buf, "ERROR", 5)) { + printk(KERN_INFO "prism54usb: firmware upload failed!\n"); + err = -EINVAL; + break; + } + + if (time_after(jiffies, timeout)) { + printk(KERN_ERR "prism54usb: firmware boot timed out!\n"); + err = -ETIMEDOUT; + break; + } + } + if (err) + goto err_upload_failed; + + buf[0] = 'g'; + buf[1] = '\r'; + err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 2); + if (err) { + printk(KERN_ERR "prism54usb: firmware boot failed!\n"); + goto err_upload_failed; + } + + timeout = jiffies + msecs_to_jiffies(1000); + while (!(err = usb_bulk_msg(priv->udev, + usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) { + if (alen > 0 && buf[0] == 'g') + break; + + if (time_after(jiffies, timeout)) { + err = -ETIMEDOUT; + break; + } + } + if (err) + goto err_upload_failed; + + err_upload_failed: + release_firmware(fw_entry); + err_req_fw_failed: + err_reset: + kfree(buf); + err_bufalloc: + return err; +} + +static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev) +{ + struct p54u_priv *priv = dev->priv; + const struct firmware *fw_entry = NULL; + const struct p54p_csr *devreg = (const struct p54p_csr *) P54U_DEV_BASE; + int err, alen; + void *buf; + __le32 reg; + unsigned int remains, offset; + u8 *data; + + buf = kmalloc(512, GFP_KERNEL); + if (!buf) { + printk(KERN_ERR "p54usb: firmware buffer alloc failed!\n"); + return -ENOMEM; + } + + err = request_firmware(&fw_entry, "isl3890usb", &priv->udev->dev); + if (err) { + printk(KERN_ERR "p54usb: cannot find firmware (isl3890usb)!\n"); + kfree(buf); + return err; + } + + p54_parse_firmware(dev, fw_entry); + +#define P54U_WRITE(type, addr, data) \ + do {\ + err = p54u_write(priv, buf, type,\ + cpu_to_le32((u32)(unsigned long)addr), data);\ + if (err) \ + goto fail;\ + } while (0) + +#define P54U_READ(type, addr) \ + do {\ + err = p54u_read(priv, buf, type,\ + cpu_to_le32((u32)(unsigned long)addr), ®);\ + if (err)\ + goto fail;\ + } while (0) + + /* power down net2280 bridge */ + P54U_READ(NET2280_BRG_U32, NET2280_GPIOCTL); + reg |= cpu_to_le32(P54U_BRG_POWER_DOWN); + reg &= cpu_to_le32(~P54U_BRG_POWER_UP); + P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg); + + mdelay(100); + + /* power up bridge */ + reg |= cpu_to_le32(P54U_BRG_POWER_UP); + reg &= cpu_to_le32(~P54U_BRG_POWER_DOWN); + P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg); + + mdelay(100); + + P54U_WRITE(NET2280_BRG_U32, NET2280_DEVINIT, + cpu_to_le32(NET2280_CLK_30Mhz | + NET2280_PCI_ENABLE | + NET2280_PCI_SOFT_RESET)); + + mdelay(20); + + P54U_WRITE(NET2280_BRG_CFG_U16, PCI_COMMAND, + cpu_to_le32(PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER)); + + P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_0, + cpu_to_le32(NET2280_BASE)); + + P54U_READ(NET2280_BRG_CFG_U16, PCI_STATUS); + reg |= cpu_to_le32(PCI_STATUS_REC_MASTER_ABORT); + P54U_WRITE(NET2280_BRG_CFG_U16, PCI_STATUS, reg); + + // TODO: we really need this? + P54U_READ(NET2280_BRG_U32, NET2280_RELNUM); + + P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_RSP, + cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE)); + P54U_WRITE(NET2280_BRG_U32, NET2280_EPC_RSP, + cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE)); + + P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_2, + cpu_to_le32(NET2280_BASE2)); + + /* finally done setting up the bridge */ + + P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | PCI_COMMAND, + cpu_to_le32(PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER)); + + P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | 0x40 /* TRDY timeout */, 0); + P54U_WRITE(NET2280_DEV_CFG_U32, 0x10000 | PCI_BASE_ADDRESS_0, + cpu_to_le32(P54U_DEV_BASE)); + + P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0); + P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1, + cpu_to_le32(NET2280_PCI_INTA_INTERRUPT)); + + /* do romboot */ + P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable, 0); + + P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat); + reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET); + reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RAMBOOT); + reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN); + P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg); + + mdelay(20); + + reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET); + P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg); + + mdelay(20); + + reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET); + P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg); + + mdelay(100); + + P54U_READ(NET2280_DEV_U32, &devreg->int_ident); + P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg); + + /* finally, we can upload firmware now! */ + remains = fw_entry->size; + data = fw_entry->data; + offset = ISL38XX_DEV_FIRMWARE_ADDR; + + while (remains) { + unsigned int block_len = min(remains, (unsigned int)512); + memcpy(buf, data, block_len); + + err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_len); + if (err) { + printk(KERN_ERR "prism54usb: firmware block upload " + "failed\n"); + goto fail; + } + + P54U_WRITE(NET2280_DEV_U32, &devreg->direct_mem_base, + cpu_to_le32(0xc0000f00)); + + P54U_WRITE(NET2280_DEV_U32, + 0x0020 | (unsigned long)&devreg->direct_mem_win, 0); + P54U_WRITE(NET2280_DEV_U32, + 0x0020 | (unsigned long)&devreg->direct_mem_win, + cpu_to_le32(1)); + + P54U_WRITE(NET2280_DEV_U32, + 0x0024 | (unsigned long)&devreg->direct_mem_win, + cpu_to_le32(block_len)); + P54U_WRITE(NET2280_DEV_U32, + 0x0028 | (unsigned long)&devreg->direct_mem_win, + cpu_to_le32(offset)); + + P54U_WRITE(NET2280_DEV_U32, &devreg->dma_addr, + cpu_to_le32(NET2280_EPA_FIFO_PCI_ADDR)); + P54U_WRITE(NET2280_DEV_U32, &devreg->dma_len, + cpu_to_le32(block_len >> 2)); + P54U_WRITE(NET2280_DEV_U32, &devreg->dma_ctrl, + cpu_to_le32(ISL38XX_DMA_MASTER_CONTROL_TRIGGER)); + + mdelay(10); + + P54U_READ(NET2280_DEV_U32, + 0x002C | (unsigned long)&devreg->direct_mem_win); + if (!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_DONE)) || + !(reg & cpu_to_le32(ISL38XX_DMA_STATUS_READY))) { + printk(KERN_ERR "prism54usb: firmware DMA transfer " + "failed\n"); + goto fail; + } + + P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_STAT, + cpu_to_le32(NET2280_FIFO_FLUSH)); + + remains -= block_len; + data += block_len; + offset += block_len; + } + + /* do ramboot */ + P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat); + reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET); + reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN); + reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RAMBOOT); + P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg); + + mdelay(20); + + reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET); + P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg); + + reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET); + P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg); + + mdelay(100); + + P54U_READ(NET2280_DEV_U32, &devreg->int_ident); + P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg); + + /* start up the firmware */ + P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable, + cpu_to_le32(ISL38XX_INT_IDENT_INIT)); + + P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1, + cpu_to_le32(NET2280_PCI_INTA_INTERRUPT)); + + P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, + cpu_to_le32(NET2280_PCI_INTA_INTERRUPT_ENABLE | + NET2280_USB_INTERRUPT_ENABLE)); + + P54U_WRITE(NET2280_DEV_U32, &devreg->dev_int, + cpu_to_le32(ISL38XX_DEV_INT_RESET)); + + err = usb_interrupt_msg(priv->udev, + usb_rcvbulkpipe(priv->udev, P54U_PIPE_INT), + buf, sizeof(__le32), &alen, 1000); + if (err || alen != sizeof(__le32)) + goto fail; + + P54U_READ(NET2280_DEV_U32, &devreg->int_ident); + P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg); + + if (!(reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT))) + err = -EINVAL; + + P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0); + P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1, + cpu_to_le32(NET2280_PCI_INTA_INTERRUPT)); + +#undef P54U_WRITE +#undef P54U_READ + + fail: + release_firmware(fw_entry); + kfree(buf); + return err; +} + +static int p54u_open(struct ieee80211_hw *dev) +{ + struct p54u_priv *priv = dev->priv; + int err; + + err = p54u_init_urbs(dev); + if (err) { + return err; + } + + priv->common.open = p54u_init_urbs; + + return 0; +} + +static void p54u_stop(struct ieee80211_hw *dev) +{ + /* TODO: figure out how to reliably stop the 3887 and net2280 so + the hardware is still usable next time we want to start it. + until then, we just stop listening to the hardware.. */ + p54u_free_urbs(dev); + return; +} + +static int __devinit p54u_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(intf); + struct ieee80211_hw *dev; + struct p54u_priv *priv; + int err; + unsigned int i, recognized_pipes; + DECLARE_MAC_BUF(mac); + + dev = p54_init_common(sizeof(*priv)); + if (!dev) { + printk(KERN_ERR "prism54usb: ieee80211 alloc failed\n"); + return -ENOMEM; + } + + priv = dev->priv; + + SET_IEEE80211_DEV(dev, &intf->dev); + usb_set_intfdata(intf, dev); + priv->udev = udev; + + usb_get_dev(udev); + + /* really lazy and simple way of figuring out if we're a 3887 */ + /* TODO: should just stick the identification in the device table */ + i = intf->altsetting->desc.bNumEndpoints; + recognized_pipes = 0; + while (i--) { + switch (intf->altsetting->endpoint[i].desc.bEndpointAddress) { + case P54U_PIPE_DATA: + case P54U_PIPE_MGMT: + case P54U_PIPE_BRG: + case P54U_PIPE_DEV: + case P54U_PIPE_DATA | USB_DIR_IN: + case P54U_PIPE_MGMT | USB_DIR_IN: + case P54U_PIPE_BRG | USB_DIR_IN: + case P54U_PIPE_DEV | USB_DIR_IN: + case P54U_PIPE_INT | USB_DIR_IN: + recognized_pipes++; + } + } + priv->common.open = p54u_open; + + if (recognized_pipes < P54U_PIPE_NUMBER) { + priv->hw_type = P54U_3887; + priv->common.tx = p54u_tx_3887; + } else { + dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr); + priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr); + priv->common.tx = p54u_tx_net2280; + } + priv->common.stop = p54u_stop; + + if (priv->hw_type) + err = p54u_upload_firmware_3887(dev); + else + err = p54u_upload_firmware_net2280(dev); + if (err) + goto err_free_dev; + + err = p54u_read_eeprom(dev); + if (err) + goto err_free_dev; + + if (!is_valid_ether_addr(dev->wiphy->perm_addr)) { + u8 perm_addr[ETH_ALEN]; + + printk(KERN_WARNING "prism54usb: Invalid hwaddr! Using randomly generated MAC addr\n"); + random_ether_addr(perm_addr); + SET_IEEE80211_PERM_ADDR(dev, perm_addr); + } + + skb_queue_head_init(&priv->rx_queue); + + err = ieee80211_register_hw(dev); + if (err) { + printk(KERN_ERR "prism54usb: Cannot register netdevice\n"); + goto err_free_dev; + } + + printk(KERN_INFO "%s: hwaddr %s, isl38%02x\n", + wiphy_name(dev->wiphy), + print_mac(mac, dev->wiphy->perm_addr), + priv->common.version); + + return 0; + + err_free_dev: + ieee80211_free_hw(dev); + usb_set_intfdata(intf, NULL); + usb_put_dev(udev); + return err; +} + +static void __devexit p54u_disconnect(struct usb_interface *intf) +{ + struct ieee80211_hw *dev = usb_get_intfdata(intf); + struct p54u_priv *priv; + + if (!dev) + return; + + ieee80211_unregister_hw(dev); + + priv = dev->priv; + usb_put_dev(interface_to_usbdev(intf)); + p54_free_common(dev); + ieee80211_free_hw(dev); +} + +static struct usb_driver p54u_driver = { + .name = "prism54usb", + .id_table = p54u_table, + .probe = p54u_probe, + .disconnect = p54u_disconnect, +}; + +static int __init p54u_init(void) +{ + return usb_register(&p54u_driver); +} + +static void __exit p54u_exit(void) +{ + usb_deregister(&p54u_driver); +} + +module_init(p54u_init); +module_exit(p54u_exit); diff --git a/drivers/net/wireless/p54usb.h b/drivers/net/wireless/p54usb.h new file mode 100644 index 00000000000..d1896b396c1 --- /dev/null +++ b/drivers/net/wireless/p54usb.h @@ -0,0 +1,133 @@ +#ifndef PRISM54USB_H +#define PRISM54USB_H + +/* + * Defines for USB based mac80211 Prism54 driver + * + * Copyright (c) 2006, Michael Wu + * + * Based on the islsm (softmac prism54) driver, which is: + * Copyright 2004-2006 Jean-Baptiste Note , et al. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* for isl3886 register definitions used on ver 1 devices */ +#include "p54pci.h" +#include "net2280.h" + +/* pci */ +#define NET2280_BASE 0x10000000 +#define NET2280_BASE2 0x20000000 + +/* gpio */ +#define P54U_BRG_POWER_UP (1 << GPIO0_DATA) +#define P54U_BRG_POWER_DOWN (1 << GPIO1_DATA) + +/* devinit */ +#define NET2280_CLK_4Mhz (15 << LOCAL_CLOCK_FREQUENCY) +#define NET2280_CLK_30Mhz (2 << LOCAL_CLOCK_FREQUENCY) +#define NET2280_CLK_60Mhz (1 << LOCAL_CLOCK_FREQUENCY) +#define NET2280_CLK_STOP (0 << LOCAL_CLOCK_FREQUENCY) +#define NET2280_PCI_ENABLE (1 << PCI_ENABLE) +#define NET2280_PCI_SOFT_RESET (1 << PCI_SOFT_RESET) + +/* endpoints */ +#define NET2280_CLEAR_NAK_OUT_PACKETS_MODE (1 << CLEAR_NAK_OUT_PACKETS_MODE) +#define NET2280_FIFO_FLUSH (1 << FIFO_FLUSH) + +/* irq */ +#define NET2280_USB_INTERRUPT_ENABLE (1 << USB_INTERRUPT_ENABLE) +#define NET2280_PCI_INTA_INTERRUPT (1 << PCI_INTA_INTERRUPT) +#define NET2280_PCI_INTA_INTERRUPT_ENABLE (1 << PCI_INTA_INTERRUPT_ENABLE) + +/* registers */ +#define NET2280_DEVINIT 0x00 +#define NET2280_USBIRQENB1 0x24 +#define NET2280_IRQSTAT1 0x2c +#define NET2280_FIFOCTL 0x38 +#define NET2280_GPIOCTL 0x50 +#define NET2280_RELNUM 0x88 +#define NET2280_EPA_RSP 0x324 +#define NET2280_EPA_STAT 0x32c +#define NET2280_EPB_STAT 0x34c +#define NET2280_EPC_RSP 0x364 +#define NET2280_EPC_STAT 0x36c +#define NET2280_EPD_STAT 0x38c + +#define NET2280_EPA_CFG 0x320 +#define NET2280_EPB_CFG 0x340 +#define NET2280_EPC_CFG 0x360 +#define NET2280_EPD_CFG 0x380 +#define NET2280_EPE_CFG 0x3A0 +#define NET2280_EPF_CFG 0x3C0 +#define P54U_DEV_BASE 0x40000000 + +struct net2280_tx_hdr { + __le32 device_addr; + __le16 len; + __le16 follower; /* ? */ + u8 padding[8]; +} __attribute__((packed)); + +/* Some flags for the isl hardware registers controlling DMA inside the + * chip */ +#define ISL38XX_DMA_STATUS_DONE 0x00000001 +#define ISL38XX_DMA_STATUS_READY 0x00000002 +#define NET2280_EPA_FIFO_PCI_ADDR 0x20000000 +#define ISL38XX_DMA_MASTER_CONTROL_TRIGGER 0x00000004 + +enum net2280_op_type { + NET2280_BRG_U32 = 0x001F, + NET2280_BRG_CFG_U32 = 0x000F, + NET2280_BRG_CFG_U16 = 0x0003, + NET2280_DEV_U32 = 0x080F, + NET2280_DEV_CFG_U32 = 0x088F, + NET2280_DEV_CFG_U16 = 0x0883 +}; + +#define P54U_FW_BLOCK 2048 + +#define X2_SIGNATURE "x2 " +#define X2_SIGNATURE_SIZE 4 + +struct x2_header { + u8 signature[X2_SIGNATURE_SIZE]; + __le32 fw_load_addr; + __le32 fw_length; + __le32 crc; +} __attribute__((packed)); + +/* pipes 3 and 4 are not used by the driver */ +#define P54U_PIPE_NUMBER 9 + +enum p54u_pipe_addr { + P54U_PIPE_DATA = 0x01, + P54U_PIPE_MGMT = 0x02, + P54U_PIPE_3 = 0x03, + P54U_PIPE_4 = 0x04, + P54U_PIPE_BRG = 0x0d, + P54U_PIPE_DEV = 0x0e, + P54U_PIPE_INT = 0x0f +}; + +struct p54u_rx_info { + struct urb *urb; + struct ieee80211_hw *dev; +}; + +struct p54u_priv { + struct p54_common common; + struct usb_device *udev; + enum { + P54U_NET2280 = 0, + P54U_3887 + } hw_type; + + spinlock_t lock; + struct sk_buff_head rx_queue; +}; + +#endif /* PRISM54USB_H */ -- cgit v1.2.3-70-g09d2 From 753f492093da7a40141bfe083073400f518f4c68 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Wed, 19 Sep 2007 14:20:30 -0700 Subject: [B44]: port to native ssb support Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/Kconfig | 28 +- drivers/net/b44.c | 743 +++++++++++++++++++++++++--------------------------- drivers/net/b44.h | 81 +----- 3 files changed, 386 insertions(+), 466 deletions(-) (limited to 'drivers') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index fd284a93c9d..83b3f7b8fb7 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1448,18 +1448,38 @@ config APRICOT called apricot. config B44 - tristate "Broadcom 4400 ethernet support" - depends on NET_PCI && PCI + tristate "Broadcom 440x/47xx ethernet support" + depends on SSB_POSSIBLE + select SSB select MII help - If you have a network (Ethernet) controller of this type, say Y and - read the Ethernet-HOWTO, available from + If you have a network (Ethernet) controller of this type, say Y + or M and read the Ethernet-HOWTO, available from . To compile this driver as a module, choose M here and read . The module will be called b44. +# Auto-select SSB PCI-HOST support, if possible +config B44_PCI_AUTOSELECT + bool + depends on B44 && SSB_PCIHOST_POSSIBLE + select SSB_PCIHOST + default y + +# Auto-select SSB PCICORE driver, if possible +config B44_PCICORE_AUTOSELECT + bool + depends on B44 && SSB_DRIVER_PCICORE_POSSIBLE + select SSB_DRIVER_PCICORE + default y + +config B44_PCI + bool + depends on B44_PCI_AUTOSELECT && B44_PCICORE_AUTOSELECT + default y + config FORCEDETH tristate "nForce Ethernet support" depends on NET_PCI && PCI diff --git a/drivers/net/b44.c b/drivers/net/b44.c index 40842a6aa99..e90ba217d24 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -1,8 +1,11 @@ -/* b44.c: Broadcom 4400 device driver. +/* b44.c: Broadcom 44xx/47xx Fast Ethernet device driver. * * Copyright (C) 2002 David S. Miller (davem@redhat.com) - * Fixed by Pekka Pietikainen (pp@ee.oulu.fi) + * Copyright (C) 2004 Pekka Pietikainen (pp@ee.oulu.fi) + * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org) + * Copyright (C) 2006 Felix Fietkau (nbd@openwrt.org) * Copyright (C) 2006 Broadcom Corporation. + * Copyright (C) 2007 Michael Buesch * * Distribute under GPL. */ @@ -21,17 +24,18 @@ #include #include #include +#include #include #include #include + #include "b44.h" #define DRV_MODULE_NAME "b44" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "1.01" -#define DRV_MODULE_RELDATE "Jun 16, 2006" +#define DRV_MODULE_VERSION "2.0" #define B44_DEF_MSG_ENABLE \ (NETIF_MSG_DRV | \ @@ -85,10 +89,10 @@ #define B44_ETHIPV4UDP_HLEN 42 static char version[] __devinitdata = - DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; + DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION "\n"; -MODULE_AUTHOR("Florian Schirmer, Pekka Pietikainen, David S. Miller"); -MODULE_DESCRIPTION("Broadcom 4400 10/100 PCI ethernet driver"); +MODULE_AUTHOR("Felix Fietkau, Florian Schirmer, Pekka Pietikainen, David S. Miller"); +MODULE_DESCRIPTION("Broadcom 44xx/47xx 10/100 PCI ethernet driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_MODULE_VERSION); @@ -96,18 +100,28 @@ static int b44_debug = -1; /* -1 == use B44_DEF_MSG_ENABLE as value */ module_param(b44_debug, int, 0); MODULE_PARM_DESC(b44_debug, "B44 bitmapped debugging message enable value"); -static struct pci_device_id b44_pci_tbl[] = { - { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, - { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B0, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, - { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B1, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, - { } /* terminate list with empty entry */ -}; +#ifdef CONFIG_B44_PCI +static const struct pci_device_id b44_pci_tbl[] = { + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B0) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B1) }, + { 0 } /* terminate list with empty entry */ +}; MODULE_DEVICE_TABLE(pci, b44_pci_tbl); +static struct pci_driver b44_pci_driver = { + .name = DRV_MODULE_NAME, + .id_table = b44_pci_tbl, +}; +#endif /* CONFIG_B44_PCI */ + +static const struct ssb_device_id b44_ssb_tbl[] = { + SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_ETHERNET, SSB_ANY_REV), + SSB_DEVTABLE_END +}; +MODULE_DEVICE_TABLE(ssb, b44_ssb_tbl); + static void b44_halt(struct b44 *); static void b44_init_rings(struct b44 *); @@ -119,6 +133,7 @@ static void b44_init_hw(struct b44 *, int); static int dma_desc_align_mask; static int dma_desc_sync_size; +static int instance; static const char b44_gstrings[][ETH_GSTRING_LEN] = { #define _B44(x...) # x, @@ -126,35 +141,35 @@ B44_STAT_REG_DECLARE #undef _B44 }; -static inline void b44_sync_dma_desc_for_device(struct pci_dev *pdev, - dma_addr_t dma_base, - unsigned long offset, - enum dma_data_direction dir) +static inline void b44_sync_dma_desc_for_device(struct ssb_device *sdev, + dma_addr_t dma_base, + unsigned long offset, + enum dma_data_direction dir) { - dma_sync_single_range_for_device(&pdev->dev, dma_base, - offset & dma_desc_align_mask, - dma_desc_sync_size, dir); + dma_sync_single_range_for_device(sdev->dev, dma_base, + offset & dma_desc_align_mask, + dma_desc_sync_size, dir); } -static inline void b44_sync_dma_desc_for_cpu(struct pci_dev *pdev, - dma_addr_t dma_base, - unsigned long offset, - enum dma_data_direction dir) +static inline void b44_sync_dma_desc_for_cpu(struct ssb_device *sdev, + dma_addr_t dma_base, + unsigned long offset, + enum dma_data_direction dir) { - dma_sync_single_range_for_cpu(&pdev->dev, dma_base, - offset & dma_desc_align_mask, - dma_desc_sync_size, dir); + dma_sync_single_range_for_cpu(sdev->dev, dma_base, + offset & dma_desc_align_mask, + dma_desc_sync_size, dir); } static inline unsigned long br32(const struct b44 *bp, unsigned long reg) { - return readl(bp->regs + reg); + return ssb_read32(bp->sdev, reg); } static inline void bw32(const struct b44 *bp, unsigned long reg, unsigned long val) { - writel(val, bp->regs + reg); + ssb_write32(bp->sdev, reg, val); } static int b44_wait_bit(struct b44 *bp, unsigned long reg, @@ -182,117 +197,29 @@ static int b44_wait_bit(struct b44 *bp, unsigned long reg, return 0; } -/* Sonics SiliconBackplane support routines. ROFL, you should see all the - * buzz words used on this company's website :-) - * - * All of these routines must be invoked with bp->lock held and - * interrupts disabled. - */ - -#define SB_PCI_DMA 0x40000000 /* Client Mode PCI memory access space (1 GB) */ -#define BCM4400_PCI_CORE_ADDR 0x18002000 /* Address of PCI core on BCM4400 cards */ - -static u32 ssb_get_core_rev(struct b44 *bp) -{ - return (br32(bp, B44_SBIDHIGH) & SBIDHIGH_RC_MASK); -} - -static u32 ssb_pci_setup(struct b44 *bp, u32 cores) -{ - u32 bar_orig, pci_rev, val; - - pci_read_config_dword(bp->pdev, SSB_BAR0_WIN, &bar_orig); - pci_write_config_dword(bp->pdev, SSB_BAR0_WIN, BCM4400_PCI_CORE_ADDR); - pci_rev = ssb_get_core_rev(bp); - - val = br32(bp, B44_SBINTVEC); - val |= cores; - bw32(bp, B44_SBINTVEC, val); - - val = br32(bp, SSB_PCI_TRANS_2); - val |= SSB_PCI_PREF | SSB_PCI_BURST; - bw32(bp, SSB_PCI_TRANS_2, val); - - pci_write_config_dword(bp->pdev, SSB_BAR0_WIN, bar_orig); - - return pci_rev; -} - -static void ssb_core_disable(struct b44 *bp) -{ - if (br32(bp, B44_SBTMSLOW) & SBTMSLOW_RESET) - return; - - bw32(bp, B44_SBTMSLOW, (SBTMSLOW_REJECT | SBTMSLOW_CLOCK)); - b44_wait_bit(bp, B44_SBTMSLOW, SBTMSLOW_REJECT, 100000, 0); - b44_wait_bit(bp, B44_SBTMSHIGH, SBTMSHIGH_BUSY, 100000, 1); - bw32(bp, B44_SBTMSLOW, (SBTMSLOW_FGC | SBTMSLOW_CLOCK | - SBTMSLOW_REJECT | SBTMSLOW_RESET)); - br32(bp, B44_SBTMSLOW); - udelay(1); - bw32(bp, B44_SBTMSLOW, (SBTMSLOW_REJECT | SBTMSLOW_RESET)); - br32(bp, B44_SBTMSLOW); - udelay(1); -} - -static void ssb_core_reset(struct b44 *bp) +static inline void __b44_cam_read(struct b44 *bp, unsigned char *data, int index) { u32 val; - ssb_core_disable(bp); - bw32(bp, B44_SBTMSLOW, (SBTMSLOW_RESET | SBTMSLOW_CLOCK | SBTMSLOW_FGC)); - br32(bp, B44_SBTMSLOW); - udelay(1); - - /* Clear SERR if set, this is a hw bug workaround. */ - if (br32(bp, B44_SBTMSHIGH) & SBTMSHIGH_SERR) - bw32(bp, B44_SBTMSHIGH, 0); - - val = br32(bp, B44_SBIMSTATE); - if (val & (SBIMSTATE_IBE | SBIMSTATE_TO)) - bw32(bp, B44_SBIMSTATE, val & ~(SBIMSTATE_IBE | SBIMSTATE_TO)); - - bw32(bp, B44_SBTMSLOW, (SBTMSLOW_CLOCK | SBTMSLOW_FGC)); - br32(bp, B44_SBTMSLOW); - udelay(1); - - bw32(bp, B44_SBTMSLOW, (SBTMSLOW_CLOCK)); - br32(bp, B44_SBTMSLOW); - udelay(1); -} + bw32(bp, B44_CAM_CTRL, (CAM_CTRL_READ | + (index << CAM_CTRL_INDEX_SHIFT))); -static int ssb_core_unit(struct b44 *bp) -{ -#if 0 - u32 val = br32(bp, B44_SBADMATCH0); - u32 base; + b44_wait_bit(bp, B44_CAM_CTRL, CAM_CTRL_BUSY, 100, 1); - type = val & SBADMATCH0_TYPE_MASK; - switch (type) { - case 0: - base = val & SBADMATCH0_BS0_MASK; - break; + val = br32(bp, B44_CAM_DATA_LO); - case 1: - base = val & SBADMATCH0_BS1_MASK; - break; + data[2] = (val >> 24) & 0xFF; + data[3] = (val >> 16) & 0xFF; + data[4] = (val >> 8) & 0xFF; + data[5] = (val >> 0) & 0xFF; - case 2: - default: - base = val & SBADMATCH0_BS2_MASK; - break; - }; -#endif - return 0; -} + val = br32(bp, B44_CAM_DATA_HI); -static int ssb_is_core_up(struct b44 *bp) -{ - return ((br32(bp, B44_SBTMSLOW) & (SBTMSLOW_RESET | SBTMSLOW_REJECT | SBTMSLOW_CLOCK)) - == SBTMSLOW_CLOCK); + data[0] = (val >> 8) & 0xFF; + data[1] = (val >> 0) & 0xFF; } -static void __b44_cam_write(struct b44 *bp, unsigned char *data, int index) +static inline void __b44_cam_write(struct b44 *bp, unsigned char *data, int index) { u32 val; @@ -328,14 +255,14 @@ static void b44_enable_ints(struct b44 *bp) bw32(bp, B44_IMASK, bp->imask); } -static int b44_readphy(struct b44 *bp, int reg, u32 *val) +static int __b44_readphy(struct b44 *bp, int phy_addr, int reg, u32 *val) { int err; bw32(bp, B44_EMAC_ISTAT, EMAC_INT_MII); bw32(bp, B44_MDIO_DATA, (MDIO_DATA_SB_START | (MDIO_OP_READ << MDIO_DATA_OP_SHIFT) | - (bp->phy_addr << MDIO_DATA_PMD_SHIFT) | + (phy_addr << MDIO_DATA_PMD_SHIFT) | (reg << MDIO_DATA_RA_SHIFT) | (MDIO_TA_VALID << MDIO_DATA_TA_SHIFT))); err = b44_wait_bit(bp, B44_EMAC_ISTAT, EMAC_INT_MII, 100, 0); @@ -344,29 +271,40 @@ static int b44_readphy(struct b44 *bp, int reg, u32 *val) return err; } -static int b44_writephy(struct b44 *bp, int reg, u32 val) +static int __b44_writephy(struct b44 *bp, int phy_addr, int reg, u32 val) { bw32(bp, B44_EMAC_ISTAT, EMAC_INT_MII); bw32(bp, B44_MDIO_DATA, (MDIO_DATA_SB_START | (MDIO_OP_WRITE << MDIO_DATA_OP_SHIFT) | - (bp->phy_addr << MDIO_DATA_PMD_SHIFT) | + (phy_addr << MDIO_DATA_PMD_SHIFT) | (reg << MDIO_DATA_RA_SHIFT) | (MDIO_TA_VALID << MDIO_DATA_TA_SHIFT) | (val & MDIO_DATA_DATA))); return b44_wait_bit(bp, B44_EMAC_ISTAT, EMAC_INT_MII, 100, 0); } +static inline int b44_readphy(struct b44 *bp, int reg, u32 *val) +{ + if (bp->phy_addr == B44_PHY_ADDR_NO_PHY) + return 0; + + return __b44_readphy(bp, bp->phy_addr, reg, val); +} + +static inline int b44_writephy(struct b44 *bp, int reg, u32 val) +{ + if (bp->phy_addr == B44_PHY_ADDR_NO_PHY) + return 0; + + return __b44_writephy(bp, bp->phy_addr, reg, val); +} + /* miilib interface */ -/* FIXME FIXME: phy_id is ignored, bp->phy_addr use is unconditional - * due to code existing before miilib use was added to this driver. - * Someone should remove this artificial driver limitation in - * b44_{read,write}phy. bp->phy_addr itself is fine (and needed). - */ static int b44_mii_read(struct net_device *dev, int phy_id, int location) { u32 val; struct b44 *bp = netdev_priv(dev); - int rc = b44_readphy(bp, location, &val); + int rc = __b44_readphy(bp, phy_id, location, &val); if (rc) return 0xffffffff; return val; @@ -376,7 +314,7 @@ static void b44_mii_write(struct net_device *dev, int phy_id, int location, int val) { struct b44 *bp = netdev_priv(dev); - b44_writephy(bp, location, val); + __b44_writephy(bp, phy_id, location, val); } static int b44_phy_reset(struct b44 *bp) @@ -384,6 +322,8 @@ static int b44_phy_reset(struct b44 *bp) u32 val; int err; + if (bp->phy_addr == B44_PHY_ADDR_NO_PHY) + return 0; err = b44_writephy(bp, MII_BMCR, BMCR_RESET); if (err) return err; @@ -442,11 +382,52 @@ static void b44_set_flow_ctrl(struct b44 *bp, u32 local, u32 remote) __b44_set_flow_ctrl(bp, pause_enab); } +#ifdef SSB_DRIVER_MIPS +extern char *nvram_get(char *name); +static void b44_wap54g10_workaround(struct b44 *bp) +{ + const char *str; + u32 val; + int err; + + /* + * workaround for bad hardware design in Linksys WAP54G v1.0 + * see https://dev.openwrt.org/ticket/146 + * check and reset bit "isolate" + */ + str = nvram_get("boardnum"); + if (!str) + return; + if (simple_strtoul(str, NULL, 0) == 2) { + err = __b44_readphy(bp, 0, MII_BMCR, &val); + if (err) + goto error; + if (!(val & BMCR_ISOLATE)) + return; + val &= ~BMCR_ISOLATE; + err = __b44_writephy(bp, 0, MII_BMCR, val); + if (err) + goto error; + } + return; +error: + printk(KERN_WARNING PFX "PHY: cannot reset MII transceiver isolate bit.\n"); +} +#else +static inline void b44_wap54g10_workaround(struct b44 *bp) +{ +} +#endif + static int b44_setup_phy(struct b44 *bp) { u32 val; int err; + b44_wap54g10_workaround(bp); + + if (bp->phy_addr == B44_PHY_ADDR_NO_PHY) + return 0; if ((err = b44_readphy(bp, B44_MII_ALEDCTRL, &val)) != 0) goto out; if ((err = b44_writephy(bp, B44_MII_ALEDCTRL, @@ -542,6 +523,19 @@ static void b44_check_phy(struct b44 *bp) { u32 bmsr, aux; + if (bp->phy_addr == B44_PHY_ADDR_NO_PHY) { + bp->flags |= B44_FLAG_100_BASE_T; + bp->flags |= B44_FLAG_FULL_DUPLEX; + if (!netif_carrier_ok(bp->dev)) { + u32 val = br32(bp, B44_TX_CTRL); + val |= TX_CTRL_DUPLEX; + bw32(bp, B44_TX_CTRL, val); + netif_carrier_on(bp->dev); + b44_link_report(bp); + } + return; + } + if (!b44_readphy(bp, MII_BMSR, &bmsr) && !b44_readphy(bp, B44_MII_AUXCTRL, &aux) && (bmsr != 0xffff)) { @@ -617,10 +611,10 @@ static void b44_tx(struct b44 *bp) BUG_ON(skb == NULL); - pci_unmap_single(bp->pdev, - pci_unmap_addr(rp, mapping), + dma_unmap_single(bp->sdev->dev, + rp->mapping, skb->len, - PCI_DMA_TODEVICE); + DMA_TO_DEVICE); rp->skb = NULL; dev_kfree_skb_irq(skb); } @@ -657,9 +651,9 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked) if (skb == NULL) return -ENOMEM; - mapping = pci_map_single(bp->pdev, skb->data, + mapping = dma_map_single(bp->sdev->dev, skb->data, RX_PKT_BUF_SZ, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); /* Hardware bug work-around, the chip is unable to do PCI DMA to/from anything above 1GB :-( */ @@ -667,18 +661,19 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked) mapping + RX_PKT_BUF_SZ > DMA_30BIT_MASK) { /* Sigh... */ if (!dma_mapping_error(mapping)) - pci_unmap_single(bp->pdev, mapping, RX_PKT_BUF_SZ,PCI_DMA_FROMDEVICE); + dma_unmap_single(bp->sdev->dev, mapping, + RX_PKT_BUF_SZ, DMA_FROM_DEVICE); dev_kfree_skb_any(skb); skb = __netdev_alloc_skb(bp->dev, RX_PKT_BUF_SZ, GFP_ATOMIC|GFP_DMA); if (skb == NULL) return -ENOMEM; - mapping = pci_map_single(bp->pdev, skb->data, + mapping = dma_map_single(bp->sdev->dev, skb->data, RX_PKT_BUF_SZ, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); if (dma_mapping_error(mapping) || mapping + RX_PKT_BUF_SZ > DMA_30BIT_MASK) { if (!dma_mapping_error(mapping)) - pci_unmap_single(bp->pdev, mapping, RX_PKT_BUF_SZ,PCI_DMA_FROMDEVICE); + dma_unmap_single(bp->sdev->dev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE); dev_kfree_skb_any(skb); return -ENOMEM; } @@ -691,7 +686,7 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked) rh->flags = 0; map->skb = skb; - pci_unmap_addr_set(map, mapping, mapping); + map->mapping = mapping; if (src_map != NULL) src_map->skb = NULL; @@ -705,9 +700,9 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked) dp->addr = cpu_to_le32((u32) mapping + RX_PKT_OFFSET + bp->dma_offset); if (bp->flags & B44_FLAG_RX_RING_HACK) - b44_sync_dma_desc_for_device(bp->pdev, bp->rx_ring_dma, - dest_idx * sizeof(dp), - DMA_BIDIRECTIONAL); + b44_sync_dma_desc_for_device(bp->sdev, bp->rx_ring_dma, + dest_idx * sizeof(dp), + DMA_BIDIRECTIONAL); return RX_PKT_BUF_SZ; } @@ -730,13 +725,12 @@ static void b44_recycle_rx(struct b44 *bp, int src_idx, u32 dest_idx_unmasked) rh = (struct rx_header *) src_map->skb->data; rh->len = 0; rh->flags = 0; - pci_unmap_addr_set(dest_map, mapping, - pci_unmap_addr(src_map, mapping)); + dest_map->mapping = src_map->mapping; if (bp->flags & B44_FLAG_RX_RING_HACK) - b44_sync_dma_desc_for_cpu(bp->pdev, bp->rx_ring_dma, - src_idx * sizeof(src_desc), - DMA_BIDIRECTIONAL); + b44_sync_dma_desc_for_cpu(bp->sdev, bp->rx_ring_dma, + src_idx * sizeof(src_desc), + DMA_BIDIRECTIONAL); ctrl = src_desc->ctrl; if (dest_idx == (B44_RX_RING_SIZE - 1)) @@ -750,13 +744,13 @@ static void b44_recycle_rx(struct b44 *bp, int src_idx, u32 dest_idx_unmasked) src_map->skb = NULL; if (bp->flags & B44_FLAG_RX_RING_HACK) - b44_sync_dma_desc_for_device(bp->pdev, bp->rx_ring_dma, - dest_idx * sizeof(dest_desc), - DMA_BIDIRECTIONAL); + b44_sync_dma_desc_for_device(bp->sdev, bp->rx_ring_dma, + dest_idx * sizeof(dest_desc), + DMA_BIDIRECTIONAL); - pci_dma_sync_single_for_device(bp->pdev, le32_to_cpu(src_desc->addr), - RX_PKT_BUF_SZ, - PCI_DMA_FROMDEVICE); + dma_sync_single_for_device(bp->sdev->dev, le32_to_cpu(src_desc->addr), + RX_PKT_BUF_SZ, + DMA_FROM_DEVICE); } static int b44_rx(struct b44 *bp, int budget) @@ -772,13 +766,13 @@ static int b44_rx(struct b44 *bp, int budget) while (cons != prod && budget > 0) { struct ring_info *rp = &bp->rx_buffers[cons]; struct sk_buff *skb = rp->skb; - dma_addr_t map = pci_unmap_addr(rp, mapping); + dma_addr_t map = rp->mapping; struct rx_header *rh; u16 len; - pci_dma_sync_single_for_cpu(bp->pdev, map, + dma_sync_single_for_cpu(bp->sdev->dev, map, RX_PKT_BUF_SZ, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); rh = (struct rx_header *) skb->data; len = le16_to_cpu(rh->len); if ((len > (RX_PKT_BUF_SZ - RX_PKT_OFFSET)) || @@ -810,8 +804,8 @@ static int b44_rx(struct b44 *bp, int budget) skb_size = b44_alloc_rx_skb(bp, cons, bp->rx_prod); if (skb_size < 0) goto drop_it; - pci_unmap_single(bp->pdev, map, - skb_size, PCI_DMA_FROMDEVICE); + dma_unmap_single(bp->sdev->dev, map, + skb_size, DMA_FROM_DEVICE); /* Leave out rx_header */ skb_put(skb, len + RX_PKT_OFFSET); skb_pull(skb, RX_PKT_OFFSET); @@ -970,24 +964,25 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev) goto err_out; } - mapping = pci_map_single(bp->pdev, skb->data, len, PCI_DMA_TODEVICE); + mapping = dma_map_single(bp->sdev->dev, skb->data, len, DMA_TO_DEVICE); if (dma_mapping_error(mapping) || mapping + len > DMA_30BIT_MASK) { struct sk_buff *bounce_skb; /* Chip can't handle DMA to/from >1GB, use bounce buffer */ if (!dma_mapping_error(mapping)) - pci_unmap_single(bp->pdev, mapping, len, PCI_DMA_TODEVICE); + dma_unmap_single(bp->sdev->dev, mapping, len, + DMA_TO_DEVICE); bounce_skb = __dev_alloc_skb(len, GFP_ATOMIC | GFP_DMA); if (!bounce_skb) goto err_out; - mapping = pci_map_single(bp->pdev, bounce_skb->data, - len, PCI_DMA_TODEVICE); + mapping = dma_map_single(bp->sdev->dev, bounce_skb->data, + len, DMA_TO_DEVICE); if (dma_mapping_error(mapping) || mapping + len > DMA_30BIT_MASK) { if (!dma_mapping_error(mapping)) - pci_unmap_single(bp->pdev, mapping, - len, PCI_DMA_TODEVICE); + dma_unmap_single(bp->sdev->dev, mapping, + len, DMA_TO_DEVICE); dev_kfree_skb_any(bounce_skb); goto err_out; } @@ -999,7 +994,7 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev) entry = bp->tx_prod; bp->tx_buffers[entry].skb = skb; - pci_unmap_addr_set(&bp->tx_buffers[entry], mapping, mapping); + bp->tx_buffers[entry].mapping = mapping; ctrl = (len & DESC_CTRL_LEN); ctrl |= DESC_CTRL_IOC | DESC_CTRL_SOF | DESC_CTRL_EOF; @@ -1010,9 +1005,9 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev) bp->tx_ring[entry].addr = cpu_to_le32((u32) mapping+bp->dma_offset); if (bp->flags & B44_FLAG_TX_RING_HACK) - b44_sync_dma_desc_for_device(bp->pdev, bp->tx_ring_dma, - entry * sizeof(bp->tx_ring[0]), - DMA_TO_DEVICE); + b44_sync_dma_desc_for_device(bp->sdev, bp->tx_ring_dma, + entry * sizeof(bp->tx_ring[0]), + DMA_TO_DEVICE); entry = NEXT_TX(entry); @@ -1085,10 +1080,8 @@ static void b44_free_rings(struct b44 *bp) if (rp->skb == NULL) continue; - pci_unmap_single(bp->pdev, - pci_unmap_addr(rp, mapping), - RX_PKT_BUF_SZ, - PCI_DMA_FROMDEVICE); + dma_unmap_single(bp->sdev->dev, rp->mapping, RX_PKT_BUF_SZ, + DMA_FROM_DEVICE); dev_kfree_skb_any(rp->skb); rp->skb = NULL; } @@ -1099,10 +1092,8 @@ static void b44_free_rings(struct b44 *bp) if (rp->skb == NULL) continue; - pci_unmap_single(bp->pdev, - pci_unmap_addr(rp, mapping), - rp->skb->len, - PCI_DMA_TODEVICE); + dma_unmap_single(bp->sdev->dev, rp->mapping, rp->skb->len, + DMA_TO_DEVICE); dev_kfree_skb_any(rp->skb); rp->skb = NULL; } @@ -1124,14 +1115,14 @@ static void b44_init_rings(struct b44 *bp) memset(bp->tx_ring, 0, B44_TX_RING_BYTES); if (bp->flags & B44_FLAG_RX_RING_HACK) - dma_sync_single_for_device(&bp->pdev->dev, bp->rx_ring_dma, - DMA_TABLE_BYTES, - PCI_DMA_BIDIRECTIONAL); + dma_sync_single_for_device(bp->sdev->dev, bp->rx_ring_dma, + DMA_TABLE_BYTES, + DMA_BIDIRECTIONAL); if (bp->flags & B44_FLAG_TX_RING_HACK) - dma_sync_single_for_device(&bp->pdev->dev, bp->tx_ring_dma, - DMA_TABLE_BYTES, - PCI_DMA_TODEVICE); + dma_sync_single_for_device(bp->sdev->dev, bp->tx_ring_dma, + DMA_TABLE_BYTES, + DMA_TO_DEVICE); for (i = 0; i < bp->rx_pending; i++) { if (b44_alloc_rx_skb(bp, -1, i) < 0) @@ -1151,24 +1142,24 @@ static void b44_free_consistent(struct b44 *bp) bp->tx_buffers = NULL; if (bp->rx_ring) { if (bp->flags & B44_FLAG_RX_RING_HACK) { - dma_unmap_single(&bp->pdev->dev, bp->rx_ring_dma, - DMA_TABLE_BYTES, - DMA_BIDIRECTIONAL); + dma_unmap_single(bp->sdev->dev, bp->rx_ring_dma, + DMA_TABLE_BYTES, + DMA_BIDIRECTIONAL); kfree(bp->rx_ring); } else - pci_free_consistent(bp->pdev, DMA_TABLE_BYTES, + dma_free_coherent(bp->sdev->dev, DMA_TABLE_BYTES, bp->rx_ring, bp->rx_ring_dma); bp->rx_ring = NULL; bp->flags &= ~B44_FLAG_RX_RING_HACK; } if (bp->tx_ring) { if (bp->flags & B44_FLAG_TX_RING_HACK) { - dma_unmap_single(&bp->pdev->dev, bp->tx_ring_dma, - DMA_TABLE_BYTES, - DMA_TO_DEVICE); + dma_unmap_single(bp->sdev->dev, bp->tx_ring_dma, + DMA_TABLE_BYTES, + DMA_TO_DEVICE); kfree(bp->tx_ring); } else - pci_free_consistent(bp->pdev, DMA_TABLE_BYTES, + dma_free_coherent(bp->sdev->dev, DMA_TABLE_BYTES, bp->tx_ring, bp->tx_ring_dma); bp->tx_ring = NULL; bp->flags &= ~B44_FLAG_TX_RING_HACK; @@ -1179,22 +1170,22 @@ static void b44_free_consistent(struct b44 *bp) * Must not be invoked with interrupt sources disabled and * the hardware shutdown down. Can sleep. */ -static int b44_alloc_consistent(struct b44 *bp) +static int b44_alloc_consistent(struct b44 *bp, gfp_t gfp) { int size; size = B44_RX_RING_SIZE * sizeof(struct ring_info); - bp->rx_buffers = kzalloc(size, GFP_KERNEL); + bp->rx_buffers = kzalloc(size, gfp); if (!bp->rx_buffers) goto out_err; size = B44_TX_RING_SIZE * sizeof(struct ring_info); - bp->tx_buffers = kzalloc(size, GFP_KERNEL); + bp->tx_buffers = kzalloc(size, gfp); if (!bp->tx_buffers) goto out_err; size = DMA_TABLE_BYTES; - bp->rx_ring = pci_alloc_consistent(bp->pdev, size, &bp->rx_ring_dma); + bp->rx_ring = dma_alloc_coherent(bp->sdev->dev, size, &bp->rx_ring_dma, gfp); if (!bp->rx_ring) { /* Allocation may have failed due to pci_alloc_consistent insisting on use of GFP_DMA, which is more restrictive @@ -1202,13 +1193,13 @@ static int b44_alloc_consistent(struct b44 *bp) struct dma_desc *rx_ring; dma_addr_t rx_ring_dma; - rx_ring = kzalloc(size, GFP_KERNEL); + rx_ring = kzalloc(size, gfp); if (!rx_ring) goto out_err; - rx_ring_dma = dma_map_single(&bp->pdev->dev, rx_ring, - DMA_TABLE_BYTES, - DMA_BIDIRECTIONAL); + rx_ring_dma = dma_map_single(bp->sdev->dev, rx_ring, + DMA_TABLE_BYTES, + DMA_BIDIRECTIONAL); if (dma_mapping_error(rx_ring_dma) || rx_ring_dma + size > DMA_30BIT_MASK) { @@ -1221,21 +1212,21 @@ static int b44_alloc_consistent(struct b44 *bp) bp->flags |= B44_FLAG_RX_RING_HACK; } - bp->tx_ring = pci_alloc_consistent(bp->pdev, size, &bp->tx_ring_dma); + bp->tx_ring = dma_alloc_coherent(bp->sdev->dev, size, &bp->tx_ring_dma, gfp); if (!bp->tx_ring) { - /* Allocation may have failed due to pci_alloc_consistent + /* Allocation may have failed due to dma_alloc_coherent insisting on use of GFP_DMA, which is more restrictive than necessary... */ struct dma_desc *tx_ring; dma_addr_t tx_ring_dma; - tx_ring = kzalloc(size, GFP_KERNEL); + tx_ring = kzalloc(size, gfp); if (!tx_ring) goto out_err; - tx_ring_dma = dma_map_single(&bp->pdev->dev, tx_ring, - DMA_TABLE_BYTES, - DMA_TO_DEVICE); + tx_ring_dma = dma_map_single(bp->sdev->dev, tx_ring, + DMA_TABLE_BYTES, + DMA_TO_DEVICE); if (dma_mapping_error(tx_ring_dma) || tx_ring_dma + size > DMA_30BIT_MASK) { @@ -1270,7 +1261,9 @@ static void b44_clear_stats(struct b44 *bp) /* bp->lock is held. */ static void b44_chip_reset(struct b44 *bp) { - if (ssb_is_core_up(bp)) { + struct ssb_device *sdev = bp->sdev; + + if (ssb_device_is_enabled(bp->sdev)) { bw32(bp, B44_RCV_LAZY, 0); bw32(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE); b44_wait_bit(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE, 200, 1); @@ -1282,19 +1275,25 @@ static void b44_chip_reset(struct b44 *bp) } bw32(bp, B44_DMARX_CTRL, 0); bp->rx_prod = bp->rx_cons = 0; - } else { - ssb_pci_setup(bp, (bp->core_unit == 0 ? - SBINTVEC_ENET0 : - SBINTVEC_ENET1)); - } - - ssb_core_reset(bp); + } else + ssb_pcicore_dev_irqvecs_enable(&sdev->bus->pcicore, sdev); + ssb_device_enable(bp->sdev, 0); b44_clear_stats(bp); - /* Make PHY accessible. */ - bw32(bp, B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE | - (0x0d & MDIO_CTRL_MAXF_MASK))); + switch (sdev->bus->bustype) { + case SSB_BUSTYPE_SSB: + bw32(bp, B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE | + (((ssb_clockspeed(sdev->bus) + (B44_MDC_RATIO / 2)) / B44_MDC_RATIO) + & MDIO_CTRL_MAXF_MASK))); + break; + case SSB_BUSTYPE_PCI: + case SSB_BUSTYPE_PCMCIA: + bw32(bp, B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE | + (0x0d & MDIO_CTRL_MAXF_MASK))); + break; + } + br32(bp, B44_MDIO_CTRL); if (!(br32(bp, B44_DEVCTRL) & DEVCTRL_IPP)) { @@ -1337,6 +1336,7 @@ static int b44_set_mac_addr(struct net_device *dev, void *p) { struct b44 *bp = netdev_priv(dev); struct sockaddr *addr = p; + u32 val; if (netif_running(dev)) return -EBUSY; @@ -1347,7 +1347,11 @@ static int b44_set_mac_addr(struct net_device *dev, void *p) memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); spin_lock_irq(&bp->lock); - __b44_set_mac_addr(bp); + + val = br32(bp, B44_RXCONFIG); + if (!(val & RXCONFIG_CAM_ABSENT)) + __b44_set_mac_addr(bp); + spin_unlock_irq(&bp->lock); return 0; @@ -1404,7 +1408,7 @@ static int b44_open(struct net_device *dev) struct b44 *bp = netdev_priv(dev); int err; - err = b44_alloc_consistent(bp); + err = b44_alloc_consistent(bp, GFP_KERNEL); if (err) goto out; @@ -1436,18 +1440,6 @@ out: return err; } -#if 0 -/*static*/ void b44_dump_state(struct b44 *bp) -{ - u32 val32, val32_2, val32_3, val32_4, val32_5; - u16 val16; - - pci_read_config_word(bp->pdev, PCI_STATUS, &val16); - printk("DEBUG: PCI status [%04x] \n", val16); - -} -#endif - #ifdef CONFIG_NET_POLL_CONTROLLER /* * Polling receive - used by netconsole and other diagnostic tools @@ -1558,10 +1550,24 @@ static void b44_setup_pseudo_magicp(struct b44 *bp) } +#ifdef CONFIG_B44_PCI +static void b44_setup_wol_pci(struct b44 *bp) +{ + u16 val; + + if (bp->sdev->bus->bustype != SSB_BUSTYPE_SSB) { + bw32(bp, SSB_TMSLOW, br32(bp, SSB_TMSLOW) | SSB_TMSLOW_PE); + pci_read_config_word(bp->sdev->bus->host_pci, SSB_PMCSR, &val); + pci_write_config_word(bp->sdev->bus->host_pci, SSB_PMCSR, val | SSB_PE); + } +} +#else +static inline void b44_setup_wol_pci(struct b44 *bp) { } +#endif /* CONFIG_B44_PCI */ + static void b44_setup_wol(struct b44 *bp) { u32 val; - u16 pmval; bw32(bp, B44_RXCONFIG, RXCONFIG_ALLMULTI); @@ -1585,13 +1591,7 @@ static void b44_setup_wol(struct b44 *bp) } else { b44_setup_pseudo_magicp(bp); } - - val = br32(bp, B44_SBTMSLOW); - bw32(bp, B44_SBTMSLOW, val | SBTMSLOW_PE); - - pci_read_config_word(bp->pdev, SSB_PMCSR, &pmval); - pci_write_config_word(bp->pdev, SSB_PMCSR, pmval | SSB_PE); - + b44_setup_wol_pci(bp); } static int b44_close(struct net_device *dev) @@ -1606,9 +1606,6 @@ static int b44_close(struct net_device *dev) spin_lock_irq(&bp->lock); -#if 0 - b44_dump_state(bp); -#endif b44_halt(bp); b44_free_rings(bp); netif_carrier_off(dev); @@ -1689,7 +1686,7 @@ static void __b44_set_rx_mode(struct net_device *dev) val = br32(bp, B44_RXCONFIG); val &= ~(RXCONFIG_PROMISC | RXCONFIG_ALLMULTI); - if (dev->flags & IFF_PROMISC) { + if ((dev->flags & IFF_PROMISC) || (val & RXCONFIG_CAM_ABSENT)) { val |= RXCONFIG_PROMISC; bw32(bp, B44_RXCONFIG, val); } else { @@ -1737,11 +1734,19 @@ static void b44_set_msglevel(struct net_device *dev, u32 value) static void b44_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *info) { struct b44 *bp = netdev_priv(dev); - struct pci_dev *pci_dev = bp->pdev; + struct ssb_bus *bus = bp->sdev->bus; - strcpy (info->driver, DRV_MODULE_NAME); - strcpy (info->version, DRV_MODULE_VERSION); - strcpy (info->bus_info, pci_name(pci_dev)); + strncpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver)); + strncpy(info->version, DRV_MODULE_VERSION, sizeof(info->driver)); + switch (bus->bustype) { + case SSB_BUSTYPE_PCI: + strncpy(info->bus_info, pci_name(bus->host_pci), sizeof(info->bus_info)); + break; + case SSB_BUSTYPE_PCMCIA: + case SSB_BUSTYPE_SSB: + strncpy(info->bus_info, "SSB", sizeof(info->bus_info)); + break; + } } static int b44_nway_reset(struct net_device *dev) @@ -2040,33 +2045,23 @@ out: return err; } -/* Read 128-bytes of EEPROM. */ -static int b44_read_eeprom(struct b44 *bp, u8 *data) -{ - long i; - __le16 *ptr = (__le16 *) data; - - for (i = 0; i < 128; i += 2) - ptr[i / 2] = cpu_to_le16(readw(bp->regs + 4096 + i)); - - return 0; -} - static int __devinit b44_get_invariants(struct b44 *bp) { - u8 eeprom[128]; - int err; + struct ssb_device *sdev = bp->sdev; + int err = 0; + u8 *addr; - err = b44_read_eeprom(bp, &eeprom[0]); - if (err) - goto out; + bp->dma_offset = ssb_dma_translation(sdev); - bp->dev->dev_addr[0] = eeprom[79]; - bp->dev->dev_addr[1] = eeprom[78]; - bp->dev->dev_addr[2] = eeprom[81]; - bp->dev->dev_addr[3] = eeprom[80]; - bp->dev->dev_addr[4] = eeprom[83]; - bp->dev->dev_addr[5] = eeprom[82]; + if (sdev->bus->bustype == SSB_BUSTYPE_SSB && + instance > 1) { + addr = sdev->bus->sprom.r1.et1mac; + bp->phy_addr = sdev->bus->sprom.r1.et1phyaddr; + } else { + addr = sdev->bus->sprom.r1.et0mac; + bp->phy_addr = sdev->bus->sprom.r1.et0phyaddr; + } + memcpy(bp->dev->dev_addr, addr, 6); if (!is_valid_ether_addr(&bp->dev->dev_addr[0])){ printk(KERN_ERR PFX "Invalid MAC address found in EEPROM\n"); @@ -2075,103 +2070,53 @@ static int __devinit b44_get_invariants(struct b44 *bp) memcpy(bp->dev->perm_addr, bp->dev->dev_addr, bp->dev->addr_len); - bp->phy_addr = eeprom[90] & 0x1f; - bp->imask = IMASK_DEF; - bp->core_unit = ssb_core_unit(bp); - bp->dma_offset = SB_PCI_DMA; - /* XXX - really required? bp->flags |= B44_FLAG_BUGGY_TXPTR; - */ + */ - if (ssb_get_core_rev(bp) >= 7) - bp->flags |= B44_FLAG_B0_ANDLATER; + if (bp->sdev->id.revision >= 7) + bp->flags |= B44_FLAG_B0_ANDLATER; -out: return err; } -static int __devinit b44_init_one(struct pci_dev *pdev, - const struct pci_device_id *ent) +static int __devinit b44_init_one(struct ssb_device *sdev, + const struct ssb_device_id *ent) { static int b44_version_printed = 0; - unsigned long b44reg_base, b44reg_len; struct net_device *dev; struct b44 *bp; int err; DECLARE_MAC_BUF(mac); + instance++; + if (b44_version_printed++ == 0) printk(KERN_INFO "%s", version); - err = pci_enable_device(pdev); - if (err) { - dev_err(&pdev->dev, "Cannot enable PCI device, " - "aborting.\n"); - return err; - } - - if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { - dev_err(&pdev->dev, - "Cannot find proper PCI device " - "base address, aborting.\n"); - err = -ENODEV; - goto err_out_disable_pdev; - } - - err = pci_request_regions(pdev, DRV_MODULE_NAME); - if (err) { - dev_err(&pdev->dev, - "Cannot obtain PCI resources, aborting.\n"); - goto err_out_disable_pdev; - } - - pci_set_master(pdev); - - err = pci_set_dma_mask(pdev, (u64) DMA_30BIT_MASK); - if (err) { - dev_err(&pdev->dev, "No usable DMA configuration, aborting.\n"); - goto err_out_free_res; - } - - err = pci_set_consistent_dma_mask(pdev, (u64) DMA_30BIT_MASK); - if (err) { - dev_err(&pdev->dev, "No usable DMA configuration, aborting.\n"); - goto err_out_free_res; - } - - b44reg_base = pci_resource_start(pdev, 0); - b44reg_len = pci_resource_len(pdev, 0); dev = alloc_etherdev(sizeof(*bp)); if (!dev) { - dev_err(&pdev->dev, "Etherdev alloc failed, aborting.\n"); + dev_err(sdev->dev, "Etherdev alloc failed, aborting.\n"); err = -ENOMEM; - goto err_out_free_res; + goto out; } - SET_NETDEV_DEV(dev,&pdev->dev); + SET_NETDEV_DEV(dev, sdev->dev); /* No interesting netdevice features in this card... */ dev->features |= 0; bp = netdev_priv(dev); - bp->pdev = pdev; + bp->sdev = sdev; bp->dev = dev; bp->msg_enable = netif_msg_init(b44_debug, B44_DEF_MSG_ENABLE); spin_lock_init(&bp->lock); - bp->regs = ioremap(b44reg_base, b44reg_len); - if (bp->regs == 0UL) { - dev_err(&pdev->dev, "Cannot map device registers, aborting.\n"); - err = -ENOMEM; - goto err_out_free_dev; - } - bp->rx_pending = B44_DEF_RX_RING_PENDING; bp->tx_pending = B44_DEF_TX_RING_PENDING; @@ -2189,16 +2134,28 @@ static int __devinit b44_init_one(struct pci_dev *pdev, dev->poll_controller = b44_poll_controller; #endif dev->change_mtu = b44_change_mtu; - dev->irq = pdev->irq; + dev->irq = sdev->irq; SET_ETHTOOL_OPS(dev, &b44_ethtool_ops); netif_carrier_off(dev); + err = ssb_bus_powerup(sdev->bus, 0); + if (err) { + dev_err(sdev->dev, + "Failed to powerup the bus\n"); + goto err_out_free_dev; + } + err = ssb_dma_set_mask(sdev, DMA_30BIT_MASK); + if (err) { + dev_err(sdev->dev, + "Required 30BIT DMA mask unsupported by the system.\n"); + goto err_out_powerdown; + } err = b44_get_invariants(bp); if (err) { - dev_err(&pdev->dev, + dev_err(sdev->dev, "Problem fetching invariants of chip, aborting.\n"); - goto err_out_iounmap; + goto err_out_powerdown; } bp->mii_if.dev = dev; @@ -2217,59 +2174,49 @@ static int __devinit b44_init_one(struct pci_dev *pdev, err = register_netdev(dev); if (err) { - dev_err(&pdev->dev, "Cannot register net device, aborting.\n"); - goto err_out_iounmap; + dev_err(sdev->dev, "Cannot register net device, aborting.\n"); + goto err_out_powerdown; } - pci_set_drvdata(pdev, dev); - - pci_save_state(bp->pdev); + ssb_set_drvdata(sdev, dev); /* Chip reset provides power to the b44 MAC & PCI cores, which * is necessary for MAC register access. */ b44_chip_reset(bp); - printk(KERN_INFO "%s: Broadcom 4400 10/100BaseT Ethernet %s\n", + printk(KERN_INFO "%s: Broadcom 44xx/47xx 10/100BaseT Ethernet %s\n", dev->name, print_mac(mac, dev->dev_addr)); return 0; -err_out_iounmap: - iounmap(bp->regs); +err_out_powerdown: + ssb_bus_may_powerdown(sdev->bus); err_out_free_dev: free_netdev(dev); -err_out_free_res: - pci_release_regions(pdev); - -err_out_disable_pdev: - pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); +out: return err; } -static void __devexit b44_remove_one(struct pci_dev *pdev) +static void __devexit b44_remove_one(struct ssb_device *sdev) { - struct net_device *dev = pci_get_drvdata(pdev); - struct b44 *bp = netdev_priv(dev); + struct net_device *dev = ssb_get_drvdata(sdev); unregister_netdev(dev); - iounmap(bp->regs); + ssb_bus_may_powerdown(sdev->bus); free_netdev(dev); - pci_release_regions(pdev); - pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); + ssb_set_drvdata(sdev, NULL); } -static int b44_suspend(struct pci_dev *pdev, pm_message_t state) +static int b44_suspend(struct ssb_device *sdev, pm_message_t state) { - struct net_device *dev = pci_get_drvdata(pdev); + struct net_device *dev = ssb_get_drvdata(sdev); struct b44 *bp = netdev_priv(dev); - if (!netif_running(dev)) - return 0; + if (!netif_running(dev)) + return 0; del_timer_sync(&bp->timer); @@ -2287,33 +2234,29 @@ static int b44_suspend(struct pci_dev *pdev, pm_message_t state) b44_init_hw(bp, B44_PARTIAL_RESET); b44_setup_wol(bp); } - pci_disable_device(pdev); + return 0; } -static int b44_resume(struct pci_dev *pdev) +static int b44_resume(struct ssb_device *sdev) { - struct net_device *dev = pci_get_drvdata(pdev); + struct net_device *dev = ssb_get_drvdata(sdev); struct b44 *bp = netdev_priv(dev); int rc = 0; - pci_restore_state(pdev); - rc = pci_enable_device(pdev); + rc = ssb_bus_powerup(sdev->bus, 0); if (rc) { - printk(KERN_ERR PFX "%s: pci_enable_device failed\n", - dev->name); + dev_err(sdev->dev, + "Failed to powerup the bus\n"); return rc; } - pci_set_master(pdev); - if (!netif_running(dev)) return 0; rc = request_irq(dev->irq, b44_interrupt, IRQF_SHARED, dev->name, dev); if (rc) { printk(KERN_ERR PFX "%s: request_irq failed\n", dev->name); - pci_disable_device(pdev); return rc; } @@ -2332,29 +2275,53 @@ static int b44_resume(struct pci_dev *pdev) return 0; } -static struct pci_driver b44_driver = { +static struct ssb_driver b44_ssb_driver = { .name = DRV_MODULE_NAME, - .id_table = b44_pci_tbl, + .id_table = b44_ssb_tbl, .probe = b44_init_one, .remove = __devexit_p(b44_remove_one), - .suspend = b44_suspend, - .resume = b44_resume, + .suspend = b44_suspend, + .resume = b44_resume, }; +static inline int b44_pci_init(void) +{ + int err = 0; +#ifdef CONFIG_B44_PCI + err = ssb_pcihost_register(&b44_pci_driver); +#endif + return err; +} + +static inline void b44_pci_exit(void) +{ +#ifdef CONFIG_B44_PCI + ssb_pcihost_unregister(&b44_pci_driver); +#endif +} + static int __init b44_init(void) { unsigned int dma_desc_align_size = dma_get_cache_alignment(); + int err; /* Setup paramaters for syncing RX/TX DMA descriptors */ dma_desc_align_mask = ~(dma_desc_align_size - 1); dma_desc_sync_size = max_t(unsigned int, dma_desc_align_size, sizeof(struct dma_desc)); - return pci_register_driver(&b44_driver); + err = b44_pci_init(); + if (err) + return err; + err = ssb_driver_register(&b44_ssb_driver); + if (err) + b44_pci_exit(); + return err; } static void __exit b44_cleanup(void) { - pci_unregister_driver(&b44_driver); + ssb_driver_unregister(&b44_ssb_driver); + b44_pci_exit(); } module_init(b44_init); diff --git a/drivers/net/b44.h b/drivers/net/b44.h index 63c55a4ab3c..7db0c84a795 100644 --- a/drivers/net/b44.h +++ b/drivers/net/b44.h @@ -129,6 +129,7 @@ #define RXCONFIG_FLOW 0x00000020 /* Flow Control Enable */ #define RXCONFIG_FLOW_ACCEPT 0x00000040 /* Accept Unicast Flow Control Frame */ #define RXCONFIG_RFILT 0x00000080 /* Reject Filter */ +#define RXCONFIG_CAM_ABSENT 0x00000100 /* CAM Absent */ #define B44_RXMAXLEN 0x0404UL /* EMAC RX Max Packet Length */ #define B44_TXMAXLEN 0x0408UL /* EMAC TX Max Packet Length */ #define B44_MDIO_CTRL 0x0410UL /* EMAC MDIO Control */ @@ -227,76 +228,6 @@ #define B44_RX_PAUSE 0x05D4UL /* MIB RX Pause Packets */ #define B44_RX_NPAUSE 0x05D8UL /* MIB RX Non-Pause Packets */ -/* Silicon backplane register definitions */ -#define B44_SBIMSTATE 0x0F90UL /* SB Initiator Agent State */ -#define SBIMSTATE_PC 0x0000000f /* Pipe Count */ -#define SBIMSTATE_AP_MASK 0x00000030 /* Arbitration Priority */ -#define SBIMSTATE_AP_BOTH 0x00000000 /* Use both timeslices and token */ -#define SBIMSTATE_AP_TS 0x00000010 /* Use timeslices only */ -#define SBIMSTATE_AP_TK 0x00000020 /* Use token only */ -#define SBIMSTATE_AP_RSV 0x00000030 /* Reserved */ -#define SBIMSTATE_IBE 0x00020000 /* In Band Error */ -#define SBIMSTATE_TO 0x00040000 /* Timeout */ -#define B44_SBINTVEC 0x0F94UL /* SB Interrupt Mask */ -#define SBINTVEC_PCI 0x00000001 /* Enable interrupts for PCI */ -#define SBINTVEC_ENET0 0x00000002 /* Enable interrupts for enet 0 */ -#define SBINTVEC_ILINE20 0x00000004 /* Enable interrupts for iline20 */ -#define SBINTVEC_CODEC 0x00000008 /* Enable interrupts for v90 codec */ -#define SBINTVEC_USB 0x00000010 /* Enable interrupts for usb */ -#define SBINTVEC_EXTIF 0x00000020 /* Enable interrupts for external i/f */ -#define SBINTVEC_ENET1 0x00000040 /* Enable interrupts for enet 1 */ -#define B44_SBTMSLOW 0x0F98UL /* SB Target State Low */ -#define SBTMSLOW_RESET 0x00000001 /* Reset */ -#define SBTMSLOW_REJECT 0x00000002 /* Reject */ -#define SBTMSLOW_CLOCK 0x00010000 /* Clock Enable */ -#define SBTMSLOW_FGC 0x00020000 /* Force Gated Clocks On */ -#define SBTMSLOW_PE 0x40000000 /* Power Management Enable */ -#define SBTMSLOW_BE 0x80000000 /* BIST Enable */ -#define B44_SBTMSHIGH 0x0F9CUL /* SB Target State High */ -#define SBTMSHIGH_SERR 0x00000001 /* S-error */ -#define SBTMSHIGH_INT 0x00000002 /* Interrupt */ -#define SBTMSHIGH_BUSY 0x00000004 /* Busy */ -#define SBTMSHIGH_GCR 0x20000000 /* Gated Clock Request */ -#define SBTMSHIGH_BISTF 0x40000000 /* BIST Failed */ -#define SBTMSHIGH_BISTD 0x80000000 /* BIST Done */ -#define B44_SBIDHIGH 0x0FFCUL /* SB Identification High */ -#define SBIDHIGH_RC_MASK 0x0000000f /* Revision Code */ -#define SBIDHIGH_CC_MASK 0x0000fff0 /* Core Code */ -#define SBIDHIGH_CC_SHIFT 4 -#define SBIDHIGH_VC_MASK 0xffff0000 /* Vendor Code */ -#define SBIDHIGH_VC_SHIFT 16 - -/* SSB PCI config space registers. */ -#define SSB_PMCSR 0x44 -#define SSB_PE 0x100 -#define SSB_BAR0_WIN 0x80 -#define SSB_BAR1_WIN 0x84 -#define SSB_SPROM_CONTROL 0x88 -#define SSB_BAR1_CONTROL 0x8c - -/* SSB core and host control registers. */ -#define SSB_CONTROL 0x0000UL -#define SSB_ARBCONTROL 0x0010UL -#define SSB_ISTAT 0x0020UL -#define SSB_IMASK 0x0024UL -#define SSB_MBOX 0x0028UL -#define SSB_BCAST_ADDR 0x0050UL -#define SSB_BCAST_DATA 0x0054UL -#define SSB_PCI_TRANS_0 0x0100UL -#define SSB_PCI_TRANS_1 0x0104UL -#define SSB_PCI_TRANS_2 0x0108UL -#define SSB_SPROM 0x0800UL - -#define SSB_PCI_MEM 0x00000000 -#define SSB_PCI_IO 0x00000001 -#define SSB_PCI_CFG0 0x00000002 -#define SSB_PCI_CFG1 0x00000003 -#define SSB_PCI_PREF 0x00000004 -#define SSB_PCI_BURST 0x00000008 -#define SSB_PCI_MASK0 0xfc000000 -#define SSB_PCI_MASK1 0xfc000000 -#define SSB_PCI_MASK2 0xc0000000 - /* 4400 PHY registers */ #define B44_MII_AUXCTRL 24 /* Auxiliary Control */ #define MII_AUXCTRL_DUPLEX 0x0001 /* Full Duplex */ @@ -346,10 +277,12 @@ struct rx_header { struct ring_info { struct sk_buff *skb; - DECLARE_PCI_UNMAP_ADDR(mapping); + dma_addr_t mapping; }; #define B44_MCAST_TABLE_SIZE 32 +#define B44_PHY_ADDR_NO_PHY 30 +#define B44_MDC_RATIO 5000000 #define B44_STAT_REG_DECLARE \ _B44(tx_good_octets) \ @@ -410,6 +343,8 @@ B44_STAT_REG_DECLARE #undef _B44 }; +struct ssb_device; + struct b44 { spinlock_t lock; @@ -452,8 +387,7 @@ struct b44 { struct net_device_stats stats; struct b44_hw_stats hw_stats; - void __iomem *regs; - struct pci_dev *pdev; + struct ssb_device *sdev; struct net_device *dev; dma_addr_t rx_ring_dma, tx_ring_dma; @@ -461,7 +395,6 @@ struct b44 { u32 rx_pending; u32 tx_pending; u8 phy_addr; - u8 core_unit; struct mii_if_info mii_if; }; -- cgit v1.2.3-70-g09d2 From b9f2c0440d806e01968c3ed4def930a43be248ad Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 3 Oct 2007 18:07:32 -0700 Subject: [netdrvr] Stop using legacy hooks ->self_test_count, ->get_stats_count These have been superceded by the new ->get_sset_count() hook. Signed-off-by: Jeff Garzik Signed-off-by: David S. Miller --- drivers/net/3c59x.c | 11 +++-- drivers/net/8139cp.c | 11 +++-- drivers/net/8139too.c | 11 +++-- drivers/net/atl1/atl1_ethtool.c | 11 +++-- drivers/net/b44.c | 11 +++-- drivers/net/bnx2.c | 20 ++++----- drivers/net/cassini.c | 11 +++-- drivers/net/chelsio/cxgb2.c | 11 +++-- drivers/net/cxgb3/cxgb3_main.c | 11 +++-- drivers/net/e100.c | 19 ++++----- drivers/net/e1000/e1000_ethtool.c | 22 +++++----- drivers/net/e1000e/ethtool.c | 21 +++++----- drivers/net/ehea/ehea_ethtool.c | 13 ++++-- drivers/net/forcedeth.c | 45 ++++++++++----------- drivers/net/gianfar_ethtool.c | 20 ++++----- drivers/net/ibm_emac/ibm_emac_core.c | 12 ++++-- drivers/net/ibmveth.c | 11 +++-- drivers/net/ixgb/ixgb_ethtool.c | 11 +++-- drivers/net/ixgbe/ixgbe_ethtool.c | 11 +++-- drivers/net/mv643xx_eth.c | 10 +++-- drivers/net/myri10ge/myri10ge.c | 11 +++-- drivers/net/netxen/netxen_nic_ethtool.c | 21 +++++----- drivers/net/pcnet32.c | 11 +++-- drivers/net/qla3xxx.c | 2 - drivers/net/r8169.c | 11 +++-- drivers/net/s2io.c | 47 +++++++++------------ drivers/net/sc92031.c | 11 +++-- drivers/net/skge.c | 11 +++-- drivers/net/sky2.c | 11 +++-- drivers/net/spider_net_ethtool.c | 11 +++-- drivers/net/tc35815.c | 12 ++++-- drivers/net/tg3.c | 19 ++++----- drivers/net/ucc_geth_ethtool.c | 26 +++++++----- drivers/net/veth.c | 11 +++-- drivers/net/wireless/libertas/ethtool.c | 72 +++++++++++++++------------------ 35 files changed, 345 insertions(+), 245 deletions(-) (limited to 'drivers') diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 58311199e32..93eb78425d6 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -2833,9 +2833,14 @@ static void vortex_set_msglevel(struct net_device *dev, u32 dbg) vortex_debug = dbg; } -static int vortex_get_stats_count(struct net_device *dev) +static int vortex_get_sset_count(struct net_device *dev, int sset) { - return VORTEX_NUM_STATS; + switch (sset) { + case ETH_SS_STATS: + return VORTEX_NUM_STATS; + default: + return -EOPNOTSUPP; + } } static void vortex_get_ethtool_stats(struct net_device *dev, @@ -2892,7 +2897,7 @@ static const struct ethtool_ops vortex_ethtool_ops = { .get_msglevel = vortex_get_msglevel, .set_msglevel = vortex_set_msglevel, .get_ethtool_stats = vortex_get_ethtool_stats, - .get_stats_count = vortex_get_stats_count, + .get_sset_count = vortex_get_sset_count, .get_settings = vortex_get_settings, .set_settings = vortex_set_settings, .get_link = ethtool_op_get_link, diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index 7edd50cf777..d437823c2c5 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -1383,9 +1383,14 @@ static int cp_get_regs_len(struct net_device *dev) return CP_REGS_SIZE; } -static int cp_get_stats_count (struct net_device *dev) +static int cp_get_sset_count (struct net_device *dev, int sset) { - return CP_NUM_STATS; + switch (sset) { + case ETH_SS_STATS: + return CP_NUM_STATS; + default: + return -EOPNOTSUPP; + } } static int cp_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) @@ -1563,7 +1568,7 @@ static void cp_get_ethtool_stats (struct net_device *dev, static const struct ethtool_ops cp_ethtool_ops = { .get_drvinfo = cp_get_drvinfo, .get_regs_len = cp_get_regs_len, - .get_stats_count = cp_get_stats_count, + .get_sset_count = cp_get_sset_count, .get_settings = cp_get_settings, .set_settings = cp_set_settings, .nway_reset = cp_nway_reset, diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index d3088a786e2..973b684c11e 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -2406,9 +2406,14 @@ static void rtl8139_get_regs(struct net_device *dev, struct ethtool_regs *regs, } #endif /* CONFIG_8139TOO_MMIO */ -static int rtl8139_get_stats_count(struct net_device *dev) +static int rtl8139_get_sset_count(struct net_device *dev, int sset) { - return RTL_NUM_STATS; + switch (sset) { + case ETH_SS_STATS: + return RTL_NUM_STATS; + default: + return -EOPNOTSUPP; + } } static void rtl8139_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data) @@ -2439,7 +2444,7 @@ static const struct ethtool_ops rtl8139_ethtool_ops = { .get_wol = rtl8139_get_wol, .set_wol = rtl8139_set_wol, .get_strings = rtl8139_get_strings, - .get_stats_count = rtl8139_get_stats_count, + .get_sset_count = rtl8139_get_sset_count, .get_ethtool_stats = rtl8139_get_ethtool_stats, }; diff --git a/drivers/net/atl1/atl1_ethtool.c b/drivers/net/atl1/atl1_ethtool.c index 53353b60a9c..68a83be843a 100644 --- a/drivers/net/atl1/atl1_ethtool.c +++ b/drivers/net/atl1/atl1_ethtool.c @@ -88,9 +88,14 @@ static void atl1_get_ethtool_stats(struct net_device *netdev, } -static int atl1_get_stats_count(struct net_device *netdev) +static int atl1_get_sset_count(struct net_device *netdev, int sset) { - return ARRAY_SIZE(atl1_gstrings_stats); + switch (sset) { + case ETH_SS_STATS: + return ARRAY_SIZE(atl1_gstrings_stats); + default: + return -EOPNOTSUPP; + } } static int atl1_get_settings(struct net_device *netdev, @@ -495,6 +500,6 @@ const struct ethtool_ops atl1_ethtool_ops = { .get_strings = atl1_get_strings, .nway_reset = atl1_nway_reset, .get_ethtool_stats = atl1_get_ethtool_stats, - .get_stats_count = atl1_get_stats_count, + .get_sset_count = atl1_get_sset_count, .set_tso = ethtool_op_set_tso, }; diff --git a/drivers/net/b44.c b/drivers/net/b44.c index e90ba217d24..3d247f3f4a3 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -1962,9 +1962,14 @@ static void b44_get_strings(struct net_device *dev, u32 stringset, u8 *data) } } -static int b44_get_stats_count(struct net_device *dev) +static int b44_get_sset_count(struct net_device *dev, int sset) { - return ARRAY_SIZE(b44_gstrings); + switch (sset) { + case ETH_SS_STATS: + return ARRAY_SIZE(b44_gstrings); + default: + return -EOPNOTSUPP; + } } static void b44_get_ethtool_stats(struct net_device *dev, @@ -2025,7 +2030,7 @@ static const struct ethtool_ops b44_ethtool_ops = { .get_msglevel = b44_get_msglevel, .set_msglevel = b44_set_msglevel, .get_strings = b44_get_strings, - .get_stats_count = b44_get_stats_count, + .get_sset_count = b44_get_sset_count, .get_ethtool_stats = b44_get_ethtool_stats, }; diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index ee9aed3aa48..57f7d994c9c 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -6068,9 +6068,16 @@ static struct { }; static int -bnx2_self_test_count(struct net_device *dev) +bnx2_get_sset_count(struct net_device *dev, int sset) { - return BNX2_NUM_TESTS; + switch (sset) { + case ETH_SS_TEST: + return BNX2_NUM_TESTS; + case ETH_SS_STATS: + return BNX2_NUM_STATS; + default: + return -EOPNOTSUPP; + } } static void @@ -6144,12 +6151,6 @@ bnx2_get_strings(struct net_device *dev, u32 stringset, u8 *buf) } } -static int -bnx2_get_stats_count(struct net_device *dev) -{ - return BNX2_NUM_STATS; -} - static void bnx2_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *buf) @@ -6260,12 +6261,11 @@ static const struct ethtool_ops bnx2_ethtool_ops = { .set_tx_csum = bnx2_set_tx_csum, .set_sg = ethtool_op_set_sg, .set_tso = bnx2_set_tso, - .self_test_count = bnx2_self_test_count, .self_test = bnx2_self_test, .get_strings = bnx2_get_strings, .phys_id = bnx2_phys_id, - .get_stats_count = bnx2_get_stats_count, .get_ethtool_stats = bnx2_get_ethtool_stats, + .get_sset_count = bnx2_get_sset_count, }; /* Called with rtnl_lock */ diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c index adc2e4d5a69..563bf5f6fa2 100644 --- a/drivers/net/cassini.c +++ b/drivers/net/cassini.c @@ -4772,9 +4772,14 @@ static void cas_get_regs(struct net_device *dev, struct ethtool_regs *regs, cas_read_regs(cp, p, regs->len / sizeof(u32)); } -static int cas_get_stats_count(struct net_device *dev) +static int cas_get_sset_count(struct net_device *dev, int sset) { - return CAS_NUM_STAT_KEYS; + switch (sset) { + case ETH_SS_STATS: + return CAS_NUM_STAT_KEYS; + default: + return -EOPNOTSUPP; + } } static void cas_get_strings(struct net_device *dev, u32 stringset, u8 *data) @@ -4818,7 +4823,7 @@ static const struct ethtool_ops cas_ethtool_ops = { .set_msglevel = cas_set_msglevel, .get_regs_len = cas_get_regs_len, .get_regs = cas_get_regs, - .get_stats_count = cas_get_stats_count, + .get_sset_count = cas_get_sset_count, .get_strings = cas_get_strings, .get_ethtool_stats = cas_get_ethtool_stats, }; diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c index 7029f13d008..2dbf8dc116c 100644 --- a/drivers/net/chelsio/cxgb2.c +++ b/drivers/net/chelsio/cxgb2.c @@ -439,9 +439,14 @@ static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) strcpy(info->bus_info, pci_name(adapter->pdev)); } -static int get_stats_count(struct net_device *dev) +static int get_sset_count(struct net_device *dev, int sset) { - return ARRAY_SIZE(stats_strings); + switch (sset) { + case ETH_SS_STATS: + return ARRAY_SIZE(stats_strings); + default: + return -EOPNOTSUPP; + } } static void get_strings(struct net_device *dev, u32 stringset, u8 *data) @@ -798,7 +803,7 @@ static const struct ethtool_ops t1_ethtool_ops = { .set_sg = ethtool_op_set_sg, .get_link = ethtool_op_get_link, .get_strings = get_strings, - .get_stats_count = get_stats_count, + .get_sset_count = get_sset_count, .get_ethtool_stats = get_stats, .get_regs_len = get_regs_len, .get_regs = get_regs, diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index 04633ea5520..e22d0653105 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -1131,9 +1131,14 @@ static char stats_strings[][ETH_GSTRING_LEN] = { }; -static int get_stats_count(struct net_device *dev) +static int get_sset_count(struct net_device *dev, int sset) { - return ARRAY_SIZE(stats_strings); + switch (sset) { + case ETH_SS_STATS: + return ARRAY_SIZE(stats_strings); + default: + return -EOPNOTSUPP; + } } #define T3_REGMAP_SIZE (3 * 1024) @@ -1640,7 +1645,7 @@ static const struct ethtool_ops cxgb_ethtool_ops = { .get_strings = get_strings, .phys_id = cxgb3_phys_id, .nway_reset = restart_autoneg, - .get_stats_count = get_stats_count, + .get_sset_count = get_sset_count, .get_ethtool_stats = get_stats, .get_regs_len = get_regs_len, .get_regs = get_regs, diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 720994b1e13..7bd96040268 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -2374,11 +2374,6 @@ static const char e100_gstrings_test[][ETH_GSTRING_LEN] = { }; #define E100_TEST_LEN sizeof(e100_gstrings_test) / ETH_GSTRING_LEN -static int e100_diag_test_count(struct net_device *netdev) -{ - return E100_TEST_LEN; -} - static void e100_diag_test(struct net_device *netdev, struct ethtool_test *test, u64 *data) { @@ -2441,9 +2436,16 @@ static const char e100_gstrings_stats[][ETH_GSTRING_LEN] = { #define E100_NET_STATS_LEN 21 #define E100_STATS_LEN sizeof(e100_gstrings_stats) / ETH_GSTRING_LEN -static int e100_get_stats_count(struct net_device *netdev) +static int e100_get_sset_count(struct net_device *netdev, int sset) { - return E100_STATS_LEN; + switch (sset) { + case ETH_SS_TEST: + return E100_TEST_LEN; + case ETH_SS_STATS: + return E100_STATS_LEN; + default: + return -EOPNOTSUPP; + } } static void e100_get_ethtool_stats(struct net_device *netdev, @@ -2494,12 +2496,11 @@ static const struct ethtool_ops e100_ethtool_ops = { .set_eeprom = e100_set_eeprom, .get_ringparam = e100_get_ringparam, .set_ringparam = e100_set_ringparam, - .self_test_count = e100_diag_test_count, .self_test = e100_diag_test, .get_strings = e100_get_strings, .phys_id = e100_phys_id, - .get_stats_count = e100_get_stats_count, .get_ethtool_stats = e100_get_ethtool_stats, + .get_sset_count = e100_get_sset_count, }; static int e100_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index e6c4a3bb9e4..6c9a643426f 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -618,8 +618,6 @@ e1000_get_drvinfo(struct net_device *netdev, strncpy(drvinfo->fw_version, firmware_version, 32); strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32); - drvinfo->n_stats = E1000_STATS_LEN; - drvinfo->testinfo_len = E1000_TEST_LEN; drvinfo->regdump_len = e1000_get_regs_len(netdev); drvinfo->eedump_len = e1000_get_eeprom_len(netdev); } @@ -1611,9 +1609,16 @@ e1000_link_test(struct e1000_adapter *adapter, uint64_t *data) } static int -e1000_diag_test_count(struct net_device *netdev) +e1000_get_sset_count(struct net_device *netdev, int sset) { - return E1000_TEST_LEN; + switch (sset) { + case ETH_SS_TEST: + return E1000_TEST_LEN; + case ETH_SS_STATS: + return E1000_STATS_LEN; + default: + return -EOPNOTSUPP; + } } extern void e1000_power_up_phy(struct e1000_adapter *); @@ -1898,12 +1903,6 @@ e1000_nway_reset(struct net_device *netdev) return 0; } -static int -e1000_get_stats_count(struct net_device *netdev) -{ - return E1000_STATS_LEN; -} - static void e1000_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats, uint64_t *data) @@ -1967,12 +1966,11 @@ static const struct ethtool_ops e1000_ethtool_ops = { .set_tx_csum = e1000_set_tx_csum, .set_sg = ethtool_op_set_sg, .set_tso = e1000_set_tso, - .self_test_count = e1000_diag_test_count, .self_test = e1000_diag_test, .get_strings = e1000_get_strings, .phys_id = e1000_phys_id, - .get_stats_count = e1000_get_stats_count, .get_ethtool_stats = e1000_get_ethtool_stats, + .get_sset_count = e1000_get_sset_count, }; void e1000_set_ethtool_ops(struct net_device *netdev) diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c index 0e80406bfbd..3423f33769b 100644 --- a/drivers/net/e1000e/ethtool.c +++ b/drivers/net/e1000e/ethtool.c @@ -577,8 +577,6 @@ static void e1000_get_drvinfo(struct net_device *netdev, strncpy(drvinfo->fw_version, firmware_version, 32); strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32); - drvinfo->n_stats = E1000_STATS_LEN; - drvinfo->testinfo_len = E1000_TEST_LEN; drvinfo->regdump_len = e1000_get_regs_len(netdev); drvinfo->eedump_len = e1000_get_eeprom_len(netdev); } @@ -1493,9 +1491,16 @@ static int e1000_link_test(struct e1000_adapter *adapter, u64 *data) return *data; } -static int e1000_diag_test_count(struct net_device *netdev) +static int e1000e_get_sset_count(struct net_device *netdev, int sset) { - return E1000_TEST_LEN; + switch (sset) { + case ETH_SS_TEST: + return E1000_TEST_LEN; + case ETH_SS_STATS: + return E1000_STATS_LEN; + default: + return -EOPNOTSUPP; + } } static void e1000_diag_test(struct net_device *netdev, @@ -1692,11 +1697,6 @@ static int e1000_nway_reset(struct net_device *netdev) return 0; } -static int e1000_get_stats_count(struct net_device *netdev) -{ - return E1000_STATS_LEN; -} - static void e1000_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats, u64 *data) @@ -1760,12 +1760,11 @@ static const struct ethtool_ops e1000_ethtool_ops = { .set_sg = ethtool_op_set_sg, .get_tso = ethtool_op_get_tso, .set_tso = e1000_set_tso, - .self_test_count = e1000_diag_test_count, .self_test = e1000_diag_test, .get_strings = e1000_get_strings, .phys_id = e1000_phys_id, - .get_stats_count = e1000_get_stats_count, .get_ethtool_stats = e1000_get_ethtool_stats, + .get_sset_count = e1000e_get_sset_count, }; void e1000e_set_ethtool_ops(struct net_device *netdev) diff --git a/drivers/net/ehea/ehea_ethtool.c b/drivers/net/ehea/ehea_ethtool.c index 6498455bf97..679f40ee957 100644 --- a/drivers/net/ehea/ehea_ethtool.c +++ b/drivers/net/ehea/ehea_ethtool.c @@ -196,9 +196,14 @@ static void ehea_get_strings(struct net_device *dev, u32 stringset, u8 *data) } } -static int ehea_get_stats_count(struct net_device *dev) +static int ehea_get_sset_count(struct net_device *dev, int sset) { - return ARRAY_SIZE(ehea_ethtool_stats_keys); + switch (sset) { + case ETH_SS_STATS: + return ARRAY_SIZE(ehea_ethtool_stats_keys); + default: + return -EOPNOTSUPP; + } } static void ehea_get_ethtool_stats(struct net_device *dev, @@ -207,7 +212,7 @@ static void ehea_get_ethtool_stats(struct net_device *dev, int i, k, tmp; struct ehea_port *port = netdev_priv(dev); - for (i = 0; i < ehea_get_stats_count(dev); i++) + for (i = 0; i < ehea_get_sset_count(dev, ETH_SS_STATS); i++) data[i] = 0; i = 0; @@ -264,7 +269,7 @@ const struct ethtool_ops ehea_ethtool_ops = { .get_link = ethtool_op_get_link, .set_tso = ethtool_op_set_tso, .get_strings = ehea_get_strings, - .get_stats_count = ehea_get_stats_count, + .get_sset_count = ehea_get_sset_count, .get_ethtool_stats = ehea_get_ethtool_stats, .get_rx_csum = ehea_get_rx_csum, .set_settings = ehea_set_settings, diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index f7354bc9b00..666de42e5a7 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -4333,16 +4333,26 @@ static int nv_set_sg(struct net_device *dev, u32 data) return -EOPNOTSUPP; } -static int nv_get_stats_count(struct net_device *dev) +static int nv_get_sset_count(struct net_device *dev, int sset) { struct fe_priv *np = netdev_priv(dev); - if (np->driver_data & DEV_HAS_STATISTICS_V1) - return NV_DEV_STATISTICS_V1_COUNT; - else if (np->driver_data & DEV_HAS_STATISTICS_V2) - return NV_DEV_STATISTICS_V2_COUNT; - else - return 0; + switch (sset) { + case ETH_SS_TEST: + if (np->driver_data & DEV_HAS_TEST_EXTENDED) + return NV_TEST_COUNT_EXTENDED; + else + return NV_TEST_COUNT_BASE; + case ETH_SS_STATS: + if (np->driver_data & DEV_HAS_STATISTICS_V1) + return NV_DEV_STATISTICS_V1_COUNT; + else if (np->driver_data & DEV_HAS_STATISTICS_V2) + return NV_DEV_STATISTICS_V2_COUNT; + else + return 0; + default: + return -EOPNOTSUPP; + } } static void nv_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *estats, u64 *buffer) @@ -4352,17 +4362,7 @@ static void nv_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *e /* update stats */ nv_do_stats_poll((unsigned long)dev); - memcpy(buffer, &np->estats, nv_get_stats_count(dev)*sizeof(u64)); -} - -static int nv_self_test_count(struct net_device *dev) -{ - struct fe_priv *np = netdev_priv(dev); - - if (np->driver_data & DEV_HAS_TEST_EXTENDED) - return NV_TEST_COUNT_EXTENDED; - else - return NV_TEST_COUNT_BASE; + memcpy(buffer, &np->estats, nv_get_sset_count(dev, ETH_SS_STATS)*sizeof(u64)); } static int nv_link_test(struct net_device *dev) @@ -4609,7 +4609,7 @@ static void nv_self_test(struct net_device *dev, struct ethtool_test *test, u64 struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); int result; - memset(buffer, 0, nv_self_test_count(dev)*sizeof(u64)); + memset(buffer, 0, nv_get_sset_count(dev, ETH_SS_TEST)*sizeof(u64)); if (!nv_link_test(dev)) { test->flags |= ETH_TEST_FL_FAILED; @@ -4692,10 +4692,10 @@ static void nv_get_strings(struct net_device *dev, u32 stringset, u8 *buffer) { switch (stringset) { case ETH_SS_STATS: - memcpy(buffer, &nv_estats_str, nv_get_stats_count(dev)*sizeof(struct nv_ethtool_str)); + memcpy(buffer, &nv_estats_str, nv_get_sset_count(dev, ETH_SS_STATS)*sizeof(struct nv_ethtool_str)); break; case ETH_SS_TEST: - memcpy(buffer, &nv_etests_str, nv_self_test_count(dev)*sizeof(struct nv_ethtool_str)); + memcpy(buffer, &nv_etests_str, nv_get_sset_count(dev, ETH_SS_TEST)*sizeof(struct nv_ethtool_str)); break; } } @@ -4720,9 +4720,8 @@ static const struct ethtool_ops ops = { .set_tx_csum = nv_set_tx_csum, .set_sg = nv_set_sg, .get_strings = nv_get_strings, - .get_stats_count = nv_get_stats_count, .get_ethtool_stats = nv_get_ethtool_stats, - .self_test_count = nv_self_test_count, + .get_sset_count = nv_get_sset_count, .self_test = nv_self_test, }; diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c index 2470903fbc7..6007147cc1e 100644 --- a/drivers/net/gianfar_ethtool.c +++ b/drivers/net/gianfar_ethtool.c @@ -152,15 +152,19 @@ static void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy, buf[i] = extra[i]; } -/* Returns the number of stats (and their corresponding strings) */ -static int gfar_stats_count(struct net_device *dev) +static int gfar_sset_count(struct net_device *dev, int sset) { struct gfar_private *priv = netdev_priv(dev); - if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON) - return GFAR_STATS_LEN; - else - return GFAR_EXTRA_STATS_LEN; + switch (sset) { + case ETH_SS_STATS: + if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON) + return GFAR_STATS_LEN; + else + return GFAR_EXTRA_STATS_LEN; + default: + return -EOPNOTSUPP; + } } /* Fills in the drvinfo structure with some basic info */ @@ -171,8 +175,6 @@ static void gfar_gdrvinfo(struct net_device *dev, struct strncpy(drvinfo->version, gfar_driver_version, GFAR_INFOSTR_LEN); strncpy(drvinfo->fw_version, "N/A", GFAR_INFOSTR_LEN); strncpy(drvinfo->bus_info, "N/A", GFAR_INFOSTR_LEN); - drvinfo->n_stats = GFAR_STATS_LEN; - drvinfo->testinfo_len = 0; drvinfo->regdump_len = 0; drvinfo->eedump_len = 0; } @@ -575,7 +577,7 @@ const struct ethtool_ops gfar_ethtool_ops = { .get_ringparam = gfar_gringparam, .set_ringparam = gfar_sringparam, .get_strings = gfar_gstrings, - .get_stats_count = gfar_stats_count, + .get_sset_count = gfar_sset_count, .get_ethtool_stats = gfar_fill_stats, .get_rx_csum = gfar_get_rx_csum, .get_tx_csum = gfar_get_tx_csum, diff --git a/drivers/net/ibm_emac/ibm_emac_core.c b/drivers/net/ibm_emac/ibm_emac_core.c index 7d4fa7644e4..73664f226f3 100644 --- a/drivers/net/ibm_emac/ibm_emac_core.c +++ b/drivers/net/ibm_emac/ibm_emac_core.c @@ -1842,9 +1842,14 @@ static int emac_ethtool_nway_reset(struct net_device *ndev) return res; } -static int emac_ethtool_get_stats_count(struct net_device *ndev) +static int emac_get_sset_count(struct net_device *ndev, int sset) { - return EMAC_ETHTOOL_STATS_COUNT; + switch (sset) { + case ETH_SS_STATS: + return EMAC_ETHTOOL_STATS_COUNT; + default: + return -EOPNOTSUPP; + } } static void emac_ethtool_get_strings(struct net_device *ndev, u32 stringset, @@ -1875,7 +1880,6 @@ static void emac_ethtool_get_drvinfo(struct net_device *ndev, strcpy(info->version, DRV_VERSION); info->fw_version[0] = '\0'; sprintf(info->bus_info, "PPC 4xx EMAC %d", dev->def->index); - info->n_stats = emac_ethtool_get_stats_count(ndev); info->regdump_len = emac_ethtool_get_regs_len(ndev); } @@ -1895,7 +1899,7 @@ static const struct ethtool_ops emac_ethtool_ops = { .get_rx_csum = emac_ethtool_get_rx_csum, .get_strings = emac_ethtool_get_strings, - .get_stats_count = emac_ethtool_get_stats_count, + .get_sset_count = emac_get_sset_count, .get_ethtool_stats = emac_ethtool_get_ethtool_stats, .get_link = ethtool_op_get_link, diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 228973484ed..4ac161e1ca1 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -802,9 +802,14 @@ static void ibmveth_get_strings(struct net_device *dev, u32 stringset, u8 *data) memcpy(data, ibmveth_stats[i].name, ETH_GSTRING_LEN); } -static int ibmveth_get_stats_count(struct net_device *dev) +static int ibmveth_get_sset_count(struct net_device *dev, int sset) { - return ARRAY_SIZE(ibmveth_stats); + switch (sset) { + case ETH_SS_STATS: + return ARRAY_SIZE(ibmveth_stats); + default: + return -EOPNOTSUPP; + } } static void ibmveth_get_ethtool_stats(struct net_device *dev, @@ -825,7 +830,7 @@ static const struct ethtool_ops netdev_ethtool_ops = { .get_rx_csum = ibmveth_get_rx_csum, .set_rx_csum = ibmveth_set_rx_csum, .get_strings = ibmveth_get_strings, - .get_stats_count = ibmveth_get_stats_count, + .get_sset_count = ibmveth_get_sset_count, .get_ethtool_stats = ibmveth_get_ethtool_stats, }; diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c index 181b59dc1ac..ddad26bb5c5 100644 --- a/drivers/net/ixgb/ixgb_ethtool.c +++ b/drivers/net/ixgb/ixgb_ethtool.c @@ -659,9 +659,14 @@ ixgb_phys_id(struct net_device *netdev, uint32_t data) } static int -ixgb_get_stats_count(struct net_device *netdev) +ixgb_get_sset_count(struct net_device *netdev, int sset) { - return IXGB_STATS_LEN; + switch (sset) { + case ETH_SS_STATS: + return IXGB_STATS_LEN; + default: + return -EOPNOTSUPP; + } } static void @@ -719,7 +724,7 @@ static const struct ethtool_ops ixgb_ethtool_ops = { .set_tso = ixgb_set_tso, .get_strings = ixgb_get_strings, .phys_id = ixgb_phys_id, - .get_stats_count = ixgb_get_stats_count, + .get_sset_count = ixgb_get_sset_count, .get_ethtool_stats = ixgb_get_ethtool_stats, }; diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index 43a2a46e287..a4e576a0c54 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -737,9 +737,14 @@ err_setup: return err; } -static int ixgbe_get_stats_count(struct net_device *netdev) +static int ixgbe_get_sset_count(struct net_device *netdev, int sset) { - return IXGBE_STATS_LEN; + switch (sset) { + case ETH_SS_STATS: + return IXGBE_STATS_LEN; + default: + return -EOPNOTSUPP; + } } static void ixgbe_get_ethtool_stats(struct net_device *netdev, @@ -931,7 +936,7 @@ static struct ethtool_ops ixgbe_ethtool_ops = { .set_tso = ixgbe_set_tso, .get_strings = ixgbe_get_strings, .phys_id = ixgbe_phys_id, - .get_stats_count = ixgbe_get_stats_count, + .get_sset_count = ixgbe_get_sset_count, .get_ethtool_stats = ixgbe_get_ethtool_stats, .get_coalesce = ixgbe_get_coalesce, .set_coalesce = ixgbe_set_coalesce, diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index e379165d837..b33d21f4eff 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -2674,9 +2674,14 @@ static void mv643xx_get_drvinfo(struct net_device *netdev, drvinfo->n_stats = MV643XX_STATS_LEN; } -static int mv643xx_get_stats_count(struct net_device *netdev) +static int mv643xx_get_sset_count(struct net_device *netdev, int sset) { - return MV643XX_STATS_LEN; + switch (sset) { + case ETH_SS_STATS: + return MV643XX_STATS_LEN; + default: + return -EOPNOTSUPP; + } } static void mv643xx_get_ethtool_stats(struct net_device *netdev, @@ -2737,7 +2742,6 @@ static const struct ethtool_ops mv643xx_ethtool_ops = { .get_drvinfo = mv643xx_get_drvinfo, .get_link = mv643xx_eth_get_link, .set_sg = ethtool_op_set_sg, - .get_stats_count = mv643xx_get_stats_count, .get_ethtool_stats = mv643xx_get_ethtool_stats, .get_strings = mv643xx_get_strings, .nway_reset = mv643xx_eth_nway_restart, diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 38b03f538e9..e8afa101433 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -1418,9 +1418,14 @@ myri10ge_get_strings(struct net_device *netdev, u32 stringset, u8 * data) } } -static int myri10ge_get_stats_count(struct net_device *netdev) +static int myri10ge_get_sset_count(struct net_device *netdev, int sset) { - return MYRI10GE_STATS_LEN; + switch (sset) { + case ETH_SS_STATS: + return MYRI10GE_STATS_LEN; + default: + return -EOPNOTSUPP; + } } static void @@ -1504,7 +1509,7 @@ static const struct ethtool_ops myri10ge_ethtool_ops = { .set_tso = ethtool_op_set_tso, .get_link = ethtool_op_get_link, .get_strings = myri10ge_get_strings, - .get_stats_count = myri10ge_get_stats_count, + .get_sset_count = myri10ge_get_sset_count, .get_ethtool_stats = myri10ge_get_ethtool_stats, .set_msglevel = myri10ge_set_msglevel, .get_msglevel = myri10ge_get_msglevel diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index 08c76b34366..78e42316e70 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c @@ -115,8 +115,6 @@ netxen_nic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) sprintf(drvinfo->fw_version, "%d.%d.%d", fw_major, fw_minor, fw_build); strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32); - drvinfo->n_stats = NETXEN_NIC_STATS_LEN; - drvinfo->testinfo_len = NETXEN_NIC_TEST_LEN; drvinfo->regdump_len = NETXEN_NIC_REGS_LEN; drvinfo->eedump_len = netxen_nic_get_eeprom_len(dev); } @@ -672,9 +670,16 @@ static int netxen_nic_reg_test(struct net_device *dev) return 0; } -static int netxen_nic_diag_test_count(struct net_device *dev) +static int netxen_get_sset_count(struct net_device *dev, int sset) { - return NETXEN_NIC_TEST_LEN; + switch (sset) { + case ETH_SS_TEST: + return NETXEN_NIC_TEST_LEN; + case ETH_SS_STATS: + return NETXEN_NIC_STATS_LEN; + default: + return -EOPNOTSUPP; + } } static void @@ -709,11 +714,6 @@ netxen_nic_get_strings(struct net_device *dev, u32 stringset, u8 * data) } } -static int netxen_nic_get_stats_count(struct net_device *dev) -{ - return NETXEN_NIC_STATS_LEN; -} - static void netxen_nic_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 * data) @@ -747,9 +747,8 @@ struct ethtool_ops netxen_nic_ethtool_ops = { .set_tx_csum = ethtool_op_set_tx_csum, .set_sg = ethtool_op_set_sg, .set_tso = ethtool_op_set_tso, - .self_test_count = netxen_nic_diag_test_count, .self_test = netxen_nic_diag_test, .get_strings = netxen_nic_get_strings, - .get_stats_count = netxen_nic_get_stats_count, .get_ethtool_stats = netxen_nic_get_ethtool_stats, + .get_sset_count = netxen_get_sset_count, }; diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 4840ddea71a..36f92dd5550 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -847,9 +847,14 @@ static void pcnet32_get_strings(struct net_device *dev, u32 stringset, memcpy(data, pcnet32_gstrings_test, sizeof(pcnet32_gstrings_test)); } -static int pcnet32_self_test_count(struct net_device *dev) +static int pcnet32_get_sset_count(struct net_device *dev, int sset) { - return PCNET32_TEST_LEN; + switch (sset) { + case ETH_SS_TEST: + return PCNET32_TEST_LEN; + default: + return -EOPNOTSUPP; + } } static void pcnet32_ethtool_test(struct net_device *dev, @@ -1510,11 +1515,11 @@ static const struct ethtool_ops pcnet32_ethtool_ops = { .get_ringparam = pcnet32_get_ringparam, .set_ringparam = pcnet32_set_ringparam, .get_strings = pcnet32_get_strings, - .self_test_count = pcnet32_self_test_count, .self_test = pcnet32_ethtool_test, .phys_id = pcnet32_phys_id, .get_regs_len = pcnet32_get_regs_len, .get_regs = pcnet32_get_regs, + .get_sset_count = pcnet32_get_sset_count, }; /* only probes for non-PCI devices, the rest are handled by diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c index ed79aa820df..48069ece4e5 100755 --- a/drivers/net/qla3xxx.c +++ b/drivers/net/qla3xxx.c @@ -1865,8 +1865,6 @@ static void ql_get_drvinfo(struct net_device *ndev, strncpy(drvinfo->version, ql3xxx_driver_version, 32); strncpy(drvinfo->fw_version, "N/A", 32); strncpy(drvinfo->bus_info, pci_name(qdev->pdev), 32); - drvinfo->n_stats = 0; - drvinfo->testinfo_len = 0; drvinfo->regdump_len = 0; drvinfo->eedump_len = 0; } diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 06a1a6f2d17..eecd811feea 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -992,9 +992,14 @@ struct rtl8169_counters { u16 tx_underun; }; -static int rtl8169_get_stats_count(struct net_device *dev) +static int rtl8169_get_sset_count(struct net_device *dev, int sset) { - return ARRAY_SIZE(rtl8169_gstrings); + switch (sset) { + case ETH_SS_STATS: + return ARRAY_SIZE(rtl8169_gstrings); + default: + return -EOPNOTSUPP; + } } static void rtl8169_get_ethtool_stats(struct net_device *dev, @@ -1068,7 +1073,7 @@ static const struct ethtool_ops rtl8169_ethtool_ops = { .get_wol = rtl8169_get_wol, .set_wol = rtl8169_set_wol, .get_strings = rtl8169_get_strings, - .get_stats_count = rtl8169_get_stats_count, + .get_sset_count = rtl8169_get_sset_count, .get_ethtool_stats = rtl8169_get_ethtool_stats, }; diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 26895de3e26..7f6b0e611e3 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -5040,12 +5040,6 @@ static void s2io_ethtool_gdrvinfo(struct net_device *dev, strncpy(info->bus_info, pci_name(sp->pdev), sizeof(info->bus_info)); info->regdump_len = XENA_REG_SPACE; info->eedump_len = XENA_EEPROM_SPACE; - info->testinfo_len = S2IO_TEST_LEN; - - if (sp->device_type == XFRAME_I_DEVICE) - info->n_stats = XFRAME_I_STAT_LEN; - else - info->n_stats = XFRAME_II_STAT_LEN; } /** @@ -6241,9 +6235,25 @@ static int s2io_get_eeprom_len(struct net_device *dev) return (XENA_EEPROM_SPACE); } -static int s2io_ethtool_self_test_count(struct net_device *dev) +static int s2io_get_sset_count(struct net_device *dev, int sset) { - return (S2IO_TEST_LEN); + struct s2io_nic *sp = dev->priv; + + switch (sset) { + case ETH_SS_TEST: + return S2IO_TEST_LEN; + case ETH_SS_STATS: + switch(sp->device_type) { + case XFRAME_I_DEVICE: + return XFRAME_I_STAT_LEN; + case XFRAME_II_DEVICE: + return XFRAME_II_STAT_LEN; + default: + return 0; + } + default: + return -EOPNOTSUPP; + } } static void s2io_ethtool_get_strings(struct net_device *dev, @@ -6270,22 +6280,6 @@ static void s2io_ethtool_get_strings(struct net_device *dev, sizeof(ethtool_driver_stats_keys)); } } -static int s2io_ethtool_get_stats_count(struct net_device *dev) -{ - struct s2io_nic *sp = dev->priv; - int stat_count = 0; - switch(sp->device_type) { - case XFRAME_I_DEVICE: - stat_count = XFRAME_I_STAT_LEN; - break; - - case XFRAME_II_DEVICE: - stat_count = XFRAME_II_STAT_LEN; - break; - } - - return stat_count; -} static int s2io_ethtool_op_set_tx_csum(struct net_device *dev, u32 data) { @@ -6331,12 +6325,11 @@ static const struct ethtool_ops netdev_ethtool_ops = { .get_tso = s2io_ethtool_op_get_tso, .set_tso = s2io_ethtool_op_set_tso, .set_ufo = ethtool_op_set_ufo, - .self_test_count = s2io_ethtool_self_test_count, .self_test = s2io_ethtool_test, .get_strings = s2io_ethtool_get_strings, .phys_id = s2io_ethtool_idnic, - .get_stats_count = s2io_ethtool_get_stats_count, - .get_ethtool_stats = s2io_get_ethtool_stats + .get_ethtool_stats = s2io_get_ethtool_stats, + .get_sset_count = s2io_get_sset_count, }; /** diff --git a/drivers/net/sc92031.c b/drivers/net/sc92031.c index 02c472ecbe5..37b42394560 100644 --- a/drivers/net/sc92031.c +++ b/drivers/net/sc92031.c @@ -1372,9 +1372,14 @@ static void sc92031_ethtool_get_strings(struct net_device *dev, SILAN_STATS_NUM * ETH_GSTRING_LEN); } -static int sc92031_ethtool_get_stats_count(struct net_device *dev) +static int sc92031_ethtool_get_sset_count(struct net_device *dev, int sset) { - return SILAN_STATS_NUM; + switch (sset) { + case ETH_SS_STATS: + return SILAN_STATS_NUM; + default: + return -EOPNOTSUPP; + } } static void sc92031_ethtool_get_ethtool_stats(struct net_device *dev, @@ -1397,7 +1402,7 @@ static struct ethtool_ops sc92031_ethtool_ops = { .nway_reset = sc92031_ethtool_nway_reset, .get_link = ethtool_op_get_link, .get_strings = sc92031_ethtool_get_strings, - .get_stats_count = sc92031_ethtool_get_stats_count, + .get_sset_count = sc92031_ethtool_get_sset_count, .get_ethtool_stats = sc92031_ethtool_get_ethtool_stats, }; diff --git a/drivers/net/skge.c b/drivers/net/skge.c index ec1acfddf35..2aae9fe38c5 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -410,9 +410,14 @@ static const struct skge_stat { { "rx_fcs_error", XM_RXF_FCS_ERR, GM_RXF_FCS_ERR }, }; -static int skge_get_stats_count(struct net_device *dev) +static int skge_get_sset_count(struct net_device *dev, int sset) { - return ARRAY_SIZE(skge_stats); + switch (sset) { + case ETH_SS_STATS: + return ARRAY_SIZE(skge_stats); + default: + return -EOPNOTSUPP; + } } static void skge_get_ethtool_stats(struct net_device *dev, @@ -817,7 +822,7 @@ static const struct ethtool_ops skge_ethtool_ops = { .set_rx_csum = skge_set_rx_csum, .get_strings = skge_get_strings, .phys_id = skge_phys_id, - .get_stats_count = skge_get_stats_count, + .get_sset_count = skge_get_sset_count, .get_ethtool_stats = skge_get_ethtool_stats, }; diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index a70bcbcf8a1..fe0e7560d23 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -3190,9 +3190,14 @@ static void sky2_set_msglevel(struct net_device *netdev, u32 value) sky2->msg_enable = value; } -static int sky2_get_stats_count(struct net_device *dev) +static int sky2_get_sset_count(struct net_device *dev, int sset) { - return ARRAY_SIZE(sky2_stats); + switch (sset) { + case ETH_SS_STATS: + return ARRAY_SIZE(sky2_stats); + default: + return -EOPNOTSUPP; + } } static void sky2_get_ethtool_stats(struct net_device *dev, @@ -3723,7 +3728,7 @@ static const struct ethtool_ops sky2_ethtool_ops = { .get_pauseparam = sky2_get_pauseparam, .set_pauseparam = sky2_set_pauseparam, .phys_id = sky2_phys_id, - .get_stats_count = sky2_get_stats_count, + .get_sset_count = sky2_get_sset_count, .get_ethtool_stats = sky2_get_ethtool_stats, }; diff --git a/drivers/net/spider_net_ethtool.c b/drivers/net/spider_net_ethtool.c index 1460d5006d1..94273037102 100644 --- a/drivers/net/spider_net_ethtool.c +++ b/drivers/net/spider_net_ethtool.c @@ -147,9 +147,14 @@ spider_net_ethtool_get_ringparam(struct net_device *netdev, ering->rx_pending = card->rx_chain.num_desc; } -static int spider_net_get_stats_count(struct net_device *netdev) +static int spider_net_get_sset_count(struct net_device *netdev, int sset) { - return SPIDER_NET_NUM_STATS; + switch (sset) { + case ETH_SS_STATS: + return SPIDER_NET_NUM_STATS; + default: + return -EOPNOTSUPP; + } } static void spider_net_get_ethtool_stats(struct net_device *netdev, @@ -191,7 +196,7 @@ const struct ethtool_ops spider_net_ethtool_ops = { .set_tx_csum = ethtool_op_set_tx_csum, .get_ringparam = spider_net_ethtool_get_ringparam, .get_strings = spider_net_get_strings, - .get_stats_count = spider_net_get_stats_count, + .get_sset_count = spider_net_get_sset_count, .get_ethtool_stats = spider_net_get_ethtool_stats, }; diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c index df8237360f5..a679f4310ce 100644 --- a/drivers/net/tc35815.c +++ b/drivers/net/tc35815.c @@ -2162,10 +2162,16 @@ static void tc35815_set_msglevel(struct net_device *dev, u32 datum) lp->msg_enable = datum; } -static int tc35815_get_stats_count(struct net_device *dev) +static int tc35815_get_sset_count(struct net_device *dev, int sset) { struct tc35815_local *lp = dev->priv; - return sizeof(lp->lstats) / sizeof(int); + + switch (sset) { + case ETH_SS_STATS: + return sizeof(lp->lstats) / sizeof(int); + default: + return -EOPNOTSUPP; + } } static void tc35815_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data) @@ -2200,7 +2206,7 @@ static const struct ethtool_ops tc35815_ethtool_ops = { .get_msglevel = tc35815_get_msglevel, .set_msglevel = tc35815_set_msglevel, .get_strings = tc35815_get_strings, - .get_stats_count = tc35815_get_stats_count, + .get_sset_count = tc35815_get_sset_count, .get_ethtool_stats = tc35815_get_ethtool_stats, }; diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 1b860e0817f..d4ac6e9ef6d 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -8347,14 +8347,16 @@ static int tg3_set_tx_csum(struct net_device *dev, u32 data) return 0; } -static int tg3_get_stats_count (struct net_device *dev) +static int tg3_get_sset_count (struct net_device *dev, int sset) { - return TG3_NUM_STATS; -} - -static int tg3_get_test_count (struct net_device *dev) -{ - return TG3_NUM_TEST; + switch (sset) { + case ETH_SS_TEST: + return TG3_NUM_TEST; + case ETH_SS_STATS: + return TG3_NUM_STATS; + default: + return -EOPNOTSUPP; + } } static void tg3_get_strings (struct net_device *dev, u32 stringset, u8 *buf) @@ -9281,14 +9283,13 @@ static const struct ethtool_ops tg3_ethtool_ops = { .set_tx_csum = tg3_set_tx_csum, .set_sg = ethtool_op_set_sg, .set_tso = tg3_set_tso, - .self_test_count = tg3_get_test_count, .self_test = tg3_self_test, .get_strings = tg3_get_strings, .phys_id = tg3_phys_id, - .get_stats_count = tg3_get_stats_count, .get_ethtool_stats = tg3_get_ethtool_stats, .get_coalesce = tg3_get_coalesce, .set_coalesce = tg3_set_coalesce, + .get_sset_count = tg3_get_sset_count, }; static void __devinit tg3_get_eeprom_size(struct tg3 *tp) diff --git a/drivers/net/ucc_geth_ethtool.c b/drivers/net/ucc_geth_ethtool.c index 73aa677a4a3..9a9622c13e2 100644 --- a/drivers/net/ucc_geth_ethtool.c +++ b/drivers/net/ucc_geth_ethtool.c @@ -276,20 +276,26 @@ uec_set_ringparam(struct net_device *netdev, return ret; } -static int uec_get_stats_count(struct net_device *netdev) +static int uec_get_sset_count(struct net_device *netdev, int sset) { struct ucc_geth_private *ugeth = netdev_priv(netdev); u32 stats_mode = ugeth->ug_info->statisticsMode; int len = 0; - if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE) - len += UEC_HW_STATS_LEN; - if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX) - len += UEC_TX_FW_STATS_LEN; - if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX) - len += UEC_RX_FW_STATS_LEN; + switch (sset) { + case ETH_SS_STATS: + if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE) + len += UEC_HW_STATS_LEN; + if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX) + len += UEC_TX_FW_STATS_LEN; + if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX) + len += UEC_RX_FW_STATS_LEN; + + return len; - return len; + default: + return -EOPNOTSUPP; + } } static void uec_get_strings(struct net_device *netdev, u32 stringset, u8 *buf) @@ -353,8 +359,6 @@ uec_get_drvinfo(struct net_device *netdev, strncpy(drvinfo->version, DRV_VERSION, 32); strncpy(drvinfo->fw_version, "N/A", 32); strncpy(drvinfo->bus_info, "QUICC ENGINE", 32); - drvinfo->n_stats = uec_get_stats_count(netdev); - drvinfo->testinfo_len = 0; drvinfo->eedump_len = 0; drvinfo->regdump_len = uec_get_regs_len(netdev); } @@ -374,7 +378,7 @@ static const struct ethtool_ops uec_ethtool_ops = { .get_pauseparam = uec_get_pauseparam, .set_pauseparam = uec_set_pauseparam, .set_sg = ethtool_op_set_sg, - .get_stats_count = uec_get_stats_count, + .get_sset_count = uec_get_sset_count, .get_strings = uec_get_strings, .get_ethtool_stats = uec_get_ethtool_stats, }; diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 2c86a4459d8..fdd1e034569 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -79,9 +79,14 @@ static void veth_get_strings(struct net_device *dev, u32 stringset, u8 *buf) } } -static int veth_get_stats_count(struct net_device *dev) +static int veth_get_sset_count(struct net_device *dev, int sset) { - return ARRAY_SIZE(ethtool_stats_keys); + switch (sset) { + case ETH_SS_STATS: + return ARRAY_SIZE(ethtool_stats_keys); + default: + return -EOPNOTSUPP; + } } static void veth_get_ethtool_stats(struct net_device *dev, @@ -135,7 +140,7 @@ static struct ethtool_ops veth_ethtool_ops = { .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, .get_strings = veth_get_strings, - .get_stats_count = veth_get_stats_count, + .get_sset_count = veth_get_sset_count, .get_ethtool_stats = veth_get_ethtool_stats, }; diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c index d793d843f7d..3dae15211b6 100644 --- a/drivers/net/wireless/libertas/ethtool.c +++ b/drivers/net/wireless/libertas/ethtool.c @@ -109,29 +109,8 @@ static void libertas_ethtool_get_stats(struct net_device * dev, struct ethtool_stats * stats, u64 * data) { wlan_private *priv = dev->priv; - - lbs_deb_enter(LBS_DEB_ETHTOOL); - - stats->cmd = ETHTOOL_GSTATS; - BUG_ON(stats->n_stats != MESH_STATS_NUM); - - data[0] = priv->mstats.fwd_drop_rbt; - data[1] = priv->mstats.fwd_drop_ttl; - data[2] = priv->mstats.fwd_drop_noroute; - data[3] = priv->mstats.fwd_drop_nobuf; - data[4] = priv->mstats.fwd_unicast_cnt; - data[5] = priv->mstats.fwd_bcast_cnt; - data[6] = priv->mstats.drop_blind; - data[7] = priv->mstats.tx_failed_cnt; - - lbs_deb_enter(LBS_DEB_ETHTOOL); -} - -static int libertas_ethtool_get_stats_count(struct net_device * dev) -{ - int ret; - wlan_private *priv = dev->priv; struct cmd_ds_mesh_access mesh_access; + int ret; lbs_deb_enter(LBS_DEB_ETHTOOL); @@ -140,25 +119,38 @@ static int libertas_ethtool_get_stats_count(struct net_device * dev) CMD_MESH_ACCESS, CMD_ACT_MESH_GET_STATS, CMD_OPTION_WAITFORRSP, 0, &mesh_access); - if (ret) { - ret = 0; - goto done; - } - - priv->mstats.fwd_drop_rbt = le32_to_cpu(mesh_access.data[0]); - priv->mstats.fwd_drop_ttl = le32_to_cpu(mesh_access.data[1]); - priv->mstats.fwd_drop_noroute = le32_to_cpu(mesh_access.data[2]); - priv->mstats.fwd_drop_nobuf = le32_to_cpu(mesh_access.data[3]); - priv->mstats.fwd_unicast_cnt = le32_to_cpu(mesh_access.data[4]); - priv->mstats.fwd_bcast_cnt = le32_to_cpu(mesh_access.data[5]); - priv->mstats.drop_blind = le32_to_cpu(mesh_access.data[6]); - priv->mstats.tx_failed_cnt = le32_to_cpu(mesh_access.data[7]); + if (ret) + return; + + priv->mstats.fwd_drop_rbt = le32_to_cpu(mesh_access.data[0]); + priv->mstats.fwd_drop_ttl = le32_to_cpu(mesh_access.data[1]); + priv->mstats.fwd_drop_noroute = le32_to_cpu(mesh_access.data[2]); + priv->mstats.fwd_drop_nobuf = le32_to_cpu(mesh_access.data[3]); + priv->mstats.fwd_unicast_cnt = le32_to_cpu(mesh_access.data[4]); + priv->mstats.fwd_bcast_cnt = le32_to_cpu(mesh_access.data[5]); + priv->mstats.drop_blind = le32_to_cpu(mesh_access.data[6]); + priv->mstats.tx_failed_cnt = le32_to_cpu(mesh_access.data[7]); + + data[0] = priv->mstats.fwd_drop_rbt; + data[1] = priv->mstats.fwd_drop_ttl; + data[2] = priv->mstats.fwd_drop_noroute; + data[3] = priv->mstats.fwd_drop_nobuf; + data[4] = priv->mstats.fwd_unicast_cnt; + data[5] = priv->mstats.fwd_bcast_cnt; + data[6] = priv->mstats.drop_blind; + data[7] = priv->mstats.tx_failed_cnt; - ret = MESH_STATS_NUM; + lbs_deb_enter(LBS_DEB_ETHTOOL); +} -done: - lbs_deb_enter_args(LBS_DEB_ETHTOOL, "ret %d", ret); - return ret; +static int libertas_ethtool_get_sset_count(struct net_device * dev, int sset) +{ + switch (sset) { + case ETH_SS_STATS: + return MESH_STATS_NUM; + default: + return -EOPNOTSUPP; + } } static void libertas_ethtool_get_strings (struct net_device * dev, @@ -185,7 +177,7 @@ struct ethtool_ops libertas_ethtool_ops = { .get_drvinfo = libertas_ethtool_get_drvinfo, .get_eeprom = libertas_ethtool_get_eeprom, .get_eeprom_len = libertas_ethtool_get_eeprom_len, - .get_stats_count = libertas_ethtool_get_stats_count, + .get_sset_count = libertas_ethtool_get_sset_count, .get_ethtool_stats = libertas_ethtool_get_stats, .get_strings = libertas_ethtool_get_strings, }; -- cgit v1.2.3-70-g09d2 From bd684e43d6290d40876230a68a0a6481dc24950a Mon Sep 17 00:00:00 2001 From: Sivakumar Subramani Date: Fri, 14 Sep 2007 07:28:50 -0400 Subject: S2io: Change kmalloc+memset to k[zc]alloc - Changed kmalloc+memset to k[zc]alloc as per Mariusz's patch Signed-off-by: Sivakumar Subramani Signed-off-by: Ramkrishna Vepa Signed-off-by: Jeff Garzik --- drivers/net/s2io.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 7f6b0e611e3..75102fb6951 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -561,7 +561,7 @@ static int init_shared_mem(struct s2io_nic *nic) for (i = 0; i < config->tx_fifo_num; i++) { int fifo_len = config->tx_cfg[i].fifo_len; int list_holder_size = fifo_len * sizeof(struct list_info_hold); - mac_control->fifos[i].list_info = kmalloc(list_holder_size, + mac_control->fifos[i].list_info = kzalloc(list_holder_size, GFP_KERNEL); if (!mac_control->fifos[i].list_info) { DBG_PRINT(INFO_DBG, @@ -569,7 +569,6 @@ static int init_shared_mem(struct s2io_nic *nic) return -ENOMEM; } mem_allocated += list_holder_size; - memset(mac_control->fifos[i].list_info, 0, list_holder_size); } for (i = 0; i < config->tx_fifo_num; i++) { int page_num = TXD_MEM_PAGE_CNT(config->tx_cfg[i].fifo_len, @@ -3661,9 +3660,9 @@ static int s2io_enable_msi_x(struct s2io_nic *nic) u16 msi_control; /* Temp variable */ int ret, i, j, msix_indx = 1; - nic->entries = kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct msix_entry), + nic->entries = kcalloc(MAX_REQUESTED_MSI_X, sizeof(struct msix_entry), GFP_KERNEL); - if (nic->entries == NULL) { + if (!nic->entries) { DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", \ __FUNCTION__); nic->mac_control.stats_info->sw_stat.mem_alloc_fail_cnt++; @@ -3671,12 +3670,11 @@ static int s2io_enable_msi_x(struct s2io_nic *nic) } nic->mac_control.stats_info->sw_stat.mem_allocated += (MAX_REQUESTED_MSI_X * sizeof(struct msix_entry)); - memset(nic->entries, 0,MAX_REQUESTED_MSI_X * sizeof(struct msix_entry)); nic->s2io_entries = - kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry), + kcalloc(MAX_REQUESTED_MSI_X, sizeof(struct s2io_msix_entry), GFP_KERNEL); - if (nic->s2io_entries == NULL) { + if (!nic->s2io_entries) { DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", __FUNCTION__); nic->mac_control.stats_info->sw_stat.mem_alloc_fail_cnt++; @@ -3687,8 +3685,6 @@ static int s2io_enable_msi_x(struct s2io_nic *nic) } nic->mac_control.stats_info->sw_stat.mem_allocated += (MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry)); - memset(nic->s2io_entries, 0, - MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry)); for (i=0; i< MAX_REQUESTED_MSI_X; i++) { nic->entries[i].entry = i; -- cgit v1.2.3-70-g09d2 From 8a4bdbaa93c2df4cfac2174ba536cd586014787d Mon Sep 17 00:00:00 2001 From: Sivakumar Subramani Date: Tue, 18 Sep 2007 18:14:20 -0400 Subject: S2io: Removed unused feature - bimodal interrupts Removed bimodal interrupt support - unused feature Signed-off-by: Sivakumar Subramani Signed-off-by: Ramkrishna Vepa Signed-off-by: Jeff Garzik [also, trim trailing whitespace] --- drivers/net/s2io.c | 232 ++++++++++++++++++++--------------------------------- drivers/net/s2io.h | 1 - 2 files changed, 88 insertions(+), 145 deletions(-) (limited to 'drivers') diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 75102fb6951..3885f6b83cc 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -84,7 +84,7 @@ #include "s2io.h" #include "s2io-regs.h" -#define DRV_VERSION "2.0.26.2" +#define DRV_VERSION "2.0.26.4" /* S2io Driver name & version. */ static char s2io_driver_name[] = "Neterion"; @@ -452,7 +452,6 @@ S2IO_PARM_INT(mc_pause_threshold_q4q7, 187); S2IO_PARM_INT(shared_splits, 0); S2IO_PARM_INT(tmac_util_period, 5); S2IO_PARM_INT(rmac_util_period, 5); -S2IO_PARM_INT(bimodal, 0); S2IO_PARM_INT(l3l4hdr_size, 128); /* Frequency of Rx desc syncs expressed as power of 2 */ S2IO_PARM_INT(rxsync_frequency, 3); @@ -699,7 +698,7 @@ static int init_shared_mem(struct s2io_nic *nic) GFP_KERNEL); if (!rx_blocks->rxds) return -ENOMEM; - mem_allocated += + mem_allocated += (sizeof(struct rxd_info)* rxd_count[nic->rxd_mode]); for (l=0; lrxd_mode];l++) { rx_blocks->rxds[l].virt_addr = @@ -761,7 +760,7 @@ static int init_shared_mem(struct s2io_nic *nic) (BUF0_LEN + ALIGN_SIZE, GFP_KERNEL); if (!ba->ba_0_org) return -ENOMEM; - mem_allocated += + mem_allocated += (BUF0_LEN + ALIGN_SIZE); tmp = (unsigned long)ba->ba_0_org; tmp += ALIGN_SIZE; @@ -772,7 +771,7 @@ static int init_shared_mem(struct s2io_nic *nic) (BUF1_LEN + ALIGN_SIZE, GFP_KERNEL); if (!ba->ba_1_org) return -ENOMEM; - mem_allocated + mem_allocated += (BUF1_LEN + ALIGN_SIZE); tmp = (unsigned long) ba->ba_1_org; tmp += ALIGN_SIZE; @@ -857,7 +856,7 @@ static void free_shared_mem(struct s2io_nic *nic) mac_control->fifos[i]. list_info[mem_blks]. list_phy_addr); - nic->mac_control.stats_info->sw_stat.mem_freed + nic->mac_control.stats_info->sw_stat.mem_freed += PAGE_SIZE; } /* If we got a zero DMA address during allocation, @@ -872,11 +871,11 @@ static void free_shared_mem(struct s2io_nic *nic) dev->name); DBG_PRINT(INIT_DBG, "Virtual address %p\n", mac_control->zerodma_virt_addr); - nic->mac_control.stats_info->sw_stat.mem_freed + nic->mac_control.stats_info->sw_stat.mem_freed += PAGE_SIZE; } kfree(mac_control->fifos[i].list_info); - nic->mac_control.stats_info->sw_stat.mem_freed += + nic->mac_control.stats_info->sw_stat.mem_freed += (nic->config.tx_cfg[i].fifo_len *sizeof(struct list_info_hold)); } @@ -894,7 +893,7 @@ static void free_shared_mem(struct s2io_nic *nic) tmp_v_addr, tmp_p_addr); nic->mac_control.stats_info->sw_stat.mem_freed += size; kfree(mac_control->rings[i].rx_blocks[j].rxds); - nic->mac_control.stats_info->sw_stat.mem_freed += + nic->mac_control.stats_info->sw_stat.mem_freed += ( sizeof(struct rxd_info)* rxd_count[nic->rxd_mode]); } } @@ -925,7 +924,7 @@ static void free_shared_mem(struct s2io_nic *nic) (rxd_count[nic->rxd_mode] + 1)); } kfree(mac_control->rings[i].ba); - nic->mac_control.stats_info->sw_stat.mem_freed += + nic->mac_control.stats_info->sw_stat.mem_freed += (sizeof(struct buffAdd *) * blk_cnt); } } @@ -935,12 +934,12 @@ static void free_shared_mem(struct s2io_nic *nic) mac_control->stats_mem_sz, mac_control->stats_mem, mac_control->stats_mem_phy); - nic->mac_control.stats_info->sw_stat.mem_freed += + nic->mac_control.stats_info->sw_stat.mem_freed += mac_control->stats_mem_sz; } if (nic->ufo_in_band_v) { kfree(nic->ufo_in_band_v); - nic->mac_control.stats_info->sw_stat.mem_freed + nic->mac_control.stats_info->sw_stat.mem_freed += (ufo_size * sizeof(u64)); } } @@ -1485,7 +1484,7 @@ static int init_nic(struct s2io_nic *nic) &bar0->rts_frm_len_n[i]); } } - + /* Disable differentiated services steering logic */ for (i = 0; i < 64; i++) { if (rts_ds_steer(nic, i, 0) == FAILURE) { @@ -1565,90 +1564,57 @@ static int init_nic(struct s2io_nic *nic) time++; } - if (nic->config.bimodal) { - int k = 0; - for (k = 0; k < config->rx_ring_num; k++) { - val64 = TTI_CMD_MEM_WE | TTI_CMD_MEM_STROBE_NEW_CMD; - val64 |= TTI_CMD_MEM_OFFSET(0x38+k); - writeq(val64, &bar0->tti_command_mem); - + /* RTI Initialization */ + if (nic->device_type == XFRAME_II_DEVICE) { /* - * Once the operation completes, the Strobe bit of the command - * register will be reset. We poll for this particular condition - * We wait for a maximum of 500ms for the operation to complete, - * if it's not complete by then we return error. - */ - time = 0; - while (TRUE) { - val64 = readq(&bar0->tti_command_mem); - if (!(val64 & TTI_CMD_MEM_STROBE_NEW_CMD)) { - break; - } - if (time > 10) { - DBG_PRINT(ERR_DBG, - "%s: TTI init Failed\n", - dev->name); - return -1; - } - time++; - msleep(50); - } - } - } else { - - /* RTI Initialization */ - if (nic->device_type == XFRAME_II_DEVICE) { - /* - * Programmed to generate Apprx 500 Intrs per - * second - */ - int count = (nic->config.bus_speed * 125)/4; - val64 = RTI_DATA1_MEM_RX_TIMER_VAL(count); - } else { - val64 = RTI_DATA1_MEM_RX_TIMER_VAL(0xFFF); - } - val64 |= RTI_DATA1_MEM_RX_URNG_A(0xA) | - RTI_DATA1_MEM_RX_URNG_B(0x10) | - RTI_DATA1_MEM_RX_URNG_C(0x30) | RTI_DATA1_MEM_RX_TIMER_AC_EN; - - writeq(val64, &bar0->rti_data1_mem); + * Programmed to generate Apprx 500 Intrs per + * second + */ + int count = (nic->config.bus_speed * 125)/4; + val64 = RTI_DATA1_MEM_RX_TIMER_VAL(count); + } else + val64 = RTI_DATA1_MEM_RX_TIMER_VAL(0xFFF); + val64 |= RTI_DATA1_MEM_RX_URNG_A(0xA) | + RTI_DATA1_MEM_RX_URNG_B(0x10) | + RTI_DATA1_MEM_RX_URNG_C(0x30) | RTI_DATA1_MEM_RX_TIMER_AC_EN; + + writeq(val64, &bar0->rti_data1_mem); + + val64 = RTI_DATA2_MEM_RX_UFC_A(0x1) | + RTI_DATA2_MEM_RX_UFC_B(0x2) ; + if (nic->config.intr_type == MSI_X) + val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x20) | \ + RTI_DATA2_MEM_RX_UFC_D(0x40)); + else + val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x40) | \ + RTI_DATA2_MEM_RX_UFC_D(0x80)); + writeq(val64, &bar0->rti_data2_mem); - val64 = RTI_DATA2_MEM_RX_UFC_A(0x1) | - RTI_DATA2_MEM_RX_UFC_B(0x2) ; - if (nic->config.intr_type == MSI_X) - val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x20) | \ - RTI_DATA2_MEM_RX_UFC_D(0x40)); - else - val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x40) | \ - RTI_DATA2_MEM_RX_UFC_D(0x80)); - writeq(val64, &bar0->rti_data2_mem); + for (i = 0; i < config->rx_ring_num; i++) { + val64 = RTI_CMD_MEM_WE | RTI_CMD_MEM_STROBE_NEW_CMD + | RTI_CMD_MEM_OFFSET(i); + writeq(val64, &bar0->rti_command_mem); - for (i = 0; i < config->rx_ring_num; i++) { - val64 = RTI_CMD_MEM_WE | RTI_CMD_MEM_STROBE_NEW_CMD - | RTI_CMD_MEM_OFFSET(i); - writeq(val64, &bar0->rti_command_mem); + /* + * Once the operation completes, the Strobe bit of the + * command register will be reset. We poll for this + * particular condition. We wait for a maximum of 500ms + * for the operation to complete, if it's not complete + * by then we return error. + */ + time = 0; + while (TRUE) { + val64 = readq(&bar0->rti_command_mem); + if (!(val64 & RTI_CMD_MEM_STROBE_NEW_CMD)) + break; - /* - * Once the operation completes, the Strobe bit of the - * command register will be reset. We poll for this - * particular condition. We wait for a maximum of 500ms - * for the operation to complete, if it's not complete - * by then we return error. - */ - time = 0; - while (TRUE) { - val64 = readq(&bar0->rti_command_mem); - if (!(val64 & RTI_CMD_MEM_STROBE_NEW_CMD)) { - break; - } - if (time > 10) { - DBG_PRINT(ERR_DBG, "%s: RTI init Failed\n", - dev->name); - return -1; - } - time++; - msleep(50); + if (time > 10) { + DBG_PRINT(ERR_DBG, "%s: RTI init Failed\n", + dev->name); + return -1; } + time++; + msleep(50); } } @@ -2005,7 +1971,7 @@ static int verify_pcc_quiescent(struct s2io_nic *sp, int flag) int ret = 0, herc; struct XENA_dev_config __iomem *bar0 = sp->bar0; u64 val64 = readq(&bar0->adapter_status); - + herc = (sp->device_type == XFRAME_II_DEVICE); if (flag == FALSE) { @@ -2151,8 +2117,6 @@ static int start_nic(struct s2io_nic *nic) &bar0->prc_rxd0_n[i]); val64 = readq(&bar0->prc_ctrl_n[i]); - if (nic->config.bimodal) - val64 |= PRC_CTRL_BIMODAL_INTERRUPT; if (nic->rxd_mode == RXD_MODE_1) val64 |= PRC_CTRL_RC_ENABLED; else @@ -2312,7 +2276,7 @@ static void free_tx_buffers(struct s2io_nic *nic) mac_control->fifos[i].list_info[j].list_virt_addr; skb = s2io_txdl_getskb(&mac_control->fifos[i], txdp, j); if (skb) { - nic->mac_control.stats_info->sw_stat.mem_freed + nic->mac_control.stats_info->sw_stat.mem_freed += skb->truesize; dev_kfree_skb(skb); cnt++; @@ -2477,7 +2441,7 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no) mem_alloc_fail_cnt++; return -ENOMEM ; } - nic->mac_control.stats_info->sw_stat.mem_allocated + nic->mac_control.stats_info->sw_stat.mem_allocated += skb->truesize; if (nic->rxd_mode == RXD_MODE_1) { /* 1 buffer mode - normal operation mode */ @@ -2492,7 +2456,7 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no) DMA_ERROR_CODE)) goto pci_map_failed; - rxdp->Control_2 = + rxdp->Control_2 = SET_BUFFER0_SIZE_1(size - NET_IP_ALIGN); } else if (nic->rxd_mode == RXD_MODE_3B) { @@ -3406,7 +3370,7 @@ static void s2io_reset(struct s2io_nic * sp) /* Reset device statistics maintained by OS */ memset(&sp->stats, 0, sizeof (struct net_device_stats)); - + up_cnt = sp->mac_control.stats_info->sw_stat.link_up_cnt; down_cnt = sp->mac_control.stats_info->sw_stat.link_down_cnt; up_time = sp->mac_control.stats_info->sw_stat.link_up_time; @@ -3668,22 +3632,22 @@ static int s2io_enable_msi_x(struct s2io_nic *nic) nic->mac_control.stats_info->sw_stat.mem_alloc_fail_cnt++; return -ENOMEM; } - nic->mac_control.stats_info->sw_stat.mem_allocated + nic->mac_control.stats_info->sw_stat.mem_allocated += (MAX_REQUESTED_MSI_X * sizeof(struct msix_entry)); nic->s2io_entries = kcalloc(MAX_REQUESTED_MSI_X, sizeof(struct s2io_msix_entry), GFP_KERNEL); if (!nic->s2io_entries) { - DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", + DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", __FUNCTION__); nic->mac_control.stats_info->sw_stat.mem_alloc_fail_cnt++; kfree(nic->entries); - nic->mac_control.stats_info->sw_stat.mem_freed + nic->mac_control.stats_info->sw_stat.mem_freed += (MAX_REQUESTED_MSI_X * sizeof(struct msix_entry)); return -ENOMEM; } - nic->mac_control.stats_info->sw_stat.mem_allocated + nic->mac_control.stats_info->sw_stat.mem_allocated += (MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry)); for (i=0; i< MAX_REQUESTED_MSI_X; i++) { @@ -3702,27 +3666,15 @@ static int s2io_enable_msi_x(struct s2io_nic *nic) } writeq(tx_mat, &bar0->tx_mat0_n[0]); - if (!nic->config.bimodal) { - rx_mat = readq(&bar0->rx_mat); - for (j=0; jconfig.rx_ring_num; j++, msix_indx++) { - rx_mat |= RX_MAT_SET(j, msix_indx); - nic->s2io_entries[msix_indx].arg - = &nic->mac_control.rings[j]; - nic->s2io_entries[msix_indx].type = MSIX_RING_TYPE; - nic->s2io_entries[msix_indx].in_use = MSIX_FLG; - } - writeq(rx_mat, &bar0->rx_mat); - } else { - tx_mat = readq(&bar0->tx_mat0_n[7]); - for (j=0; jconfig.rx_ring_num; j++, msix_indx++) { - tx_mat |= TX_MAT_SET(i, msix_indx); - nic->s2io_entries[msix_indx].arg - = &nic->mac_control.rings[j]; - nic->s2io_entries[msix_indx].type = MSIX_RING_TYPE; - nic->s2io_entries[msix_indx].in_use = MSIX_FLG; - } - writeq(tx_mat, &bar0->tx_mat0_n[7]); + rx_mat = readq(&bar0->rx_mat); + for (j = 0; j < nic->config.rx_ring_num; j++, msix_indx++) { + rx_mat |= RX_MAT_SET(j, msix_indx); + nic->s2io_entries[msix_indx].arg + = &nic->mac_control.rings[j]; + nic->s2io_entries[msix_indx].type = MSIX_RING_TYPE; + nic->s2io_entries[msix_indx].in_use = MSIX_FLG; } + writeq(rx_mat, &bar0->rx_mat); nic->avail_msix_vectors = 0; ret = pci_enable_msix(nic->pdev, nic->entries, MAX_REQUESTED_MSI_X); @@ -3734,10 +3686,10 @@ static int s2io_enable_msi_x(struct s2io_nic *nic) if (ret) { DBG_PRINT(ERR_DBG, "%s: Enabling MSIX failed\n", nic->dev->name); kfree(nic->entries); - nic->mac_control.stats_info->sw_stat.mem_freed + nic->mac_control.stats_info->sw_stat.mem_freed += (MAX_REQUESTED_MSI_X * sizeof(struct msix_entry)); kfree(nic->s2io_entries); - nic->mac_control.stats_info->sw_stat.mem_freed + nic->mac_control.stats_info->sw_stat.mem_freed += (MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry)); nic->entries = NULL; nic->s2io_entries = NULL; @@ -3906,12 +3858,12 @@ hw_init_failed: if (sp->config.intr_type == MSI_X) { if (sp->entries) { kfree(sp->entries); - sp->mac_control.stats_info->sw_stat.mem_freed + sp->mac_control.stats_info->sw_stat.mem_freed += (MAX_REQUESTED_MSI_X * sizeof(struct msix_entry)); } if (sp->s2io_entries) { kfree(sp->s2io_entries); - sp->mac_control.stats_info->sw_stat.mem_freed + sp->mac_control.stats_info->sw_stat.mem_freed += (MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry)); } } @@ -4676,7 +4628,7 @@ static void s2io_updt_stats(struct s2io_nic *sp) if (cnt == 5) break; /* Updt failed */ } while(1); - } + } } /** @@ -5165,13 +5117,13 @@ static void s2io_ethtool_gringparam(struct net_device *dev, ering->rx_max_pending = MAX_RX_DESC_2; ering->tx_max_pending = MAX_TX_DESC; - for (i = 0 ; i < sp->config.tx_fifo_num ; i++) + for (i = 0 ; i < sp->config.tx_fifo_num ; i++) tx_desc_count += sp->config.tx_cfg[i].fifo_len; - + DBG_PRINT(INFO_DBG,"\nmax txds : %d\n",sp->config.max_txds); ering->tx_pending = tx_desc_count; rx_desc_count = 0; - for (i = 0 ; i < sp->config.rx_ring_num ; i++) + for (i = 0 ; i < sp->config.rx_ring_num ; i++) rx_desc_count += sp->config.rx_cfg[i].num_rxd; ering->rx_pending = rx_desc_count; @@ -6539,7 +6491,7 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp, mem_alloc_fail_cnt++; return -ENOMEM ; } - sp->mac_control.stats_info->sw_stat.mem_allocated + sp->mac_control.stats_info->sw_stat.mem_allocated += (*skb)->truesize; /* storing the mapped addr in a temp variable * such it will be used for next rxd whose @@ -6572,7 +6524,7 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp, mem_alloc_fail_cnt++; return -ENOMEM; } - sp->mac_control.stats_info->sw_stat.mem_allocated + sp->mac_control.stats_info->sw_stat.mem_allocated += (*skb)->truesize; rxdp3->Buffer2_ptr = *temp2 = pci_map_single(sp->pdev, (*skb)->data, @@ -7107,7 +7059,7 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp) DBG_PRINT(ERR_DBG, "%s: Rx error Value: 0x%x\n", dev->name, err_mask); sp->stats.rx_crc_errors++; - sp->mac_control.stats_info->sw_stat.mem_freed + sp->mac_control.stats_info->sw_stat.mem_freed += skb->truesize; dev_kfree_skb(skb); atomic_dec(&sp->rx_bufs_left[ring_no]); @@ -7261,13 +7213,13 @@ static void s2io_link(struct s2io_nic * sp, int link) DBG_PRINT(ERR_DBG, "%s: Link down\n", dev->name); netif_carrier_off(dev); if(sp->mac_control.stats_info->sw_stat.link_up_cnt) - sp->mac_control.stats_info->sw_stat.link_up_time = + sp->mac_control.stats_info->sw_stat.link_up_time = jiffies - sp->start_time; sp->mac_control.stats_info->sw_stat.link_down_cnt++; } else { DBG_PRINT(ERR_DBG, "%s: Link Up\n", dev->name); if (sp->mac_control.stats_info->sw_stat.link_down_cnt) - sp->mac_control.stats_info->sw_stat.link_down_time = + sp->mac_control.stats_info->sw_stat.link_down_time = jiffies - sp->start_time; sp->mac_control.stats_info->sw_stat.link_up_cnt++; netif_carrier_on(dev); @@ -7752,14 +7704,6 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) /* Initialize device name */ sprintf(sp->name, "%s Neterion %s", dev->name, sp->product_name); - /* Initialize bimodal Interrupts */ - sp->config.bimodal = bimodal; - if (!(sp->device_type & XFRAME_II_DEVICE) && bimodal) { - sp->config.bimodal = 0; - DBG_PRINT(ERR_DBG,"%s:Bimodal intr not supported by Xframe I\n", - dev->name); - } - /* * Make Link state as off at this point, when the Link change * interrupt comes the state will be automatically changed to diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 1a70cf02c91..9b645f40639 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -444,7 +444,6 @@ struct config_param { #define MAX_RX_BLOCKS_PER_RING 150 struct rx_ring_config rx_cfg[MAX_RX_RINGS]; /*Per-Rx Ring config */ - u8 bimodal; /*Flag for setting bimodal interrupts*/ #define HEADER_ETHERNET_II_802_3_SIZE 14 #define HEADER_802_2_SIZE 3 -- cgit v1.2.3-70-g09d2 From 2fd37688455857b7b92bc2b1379a4c48aa9af147 Mon Sep 17 00:00:00 2001 From: Sivakumar Subramani Date: Fri, 14 Sep 2007 07:39:19 -0400 Subject: S2io: Added support set_mac_address driver entry point - Added set_mac_address driver entry point - Copying permanent mac address to dev->perm_addr - Incorporated following review comments from Jeff - Converted the macro to a function and removed call to memset - regarding function naming convention, for all callbacks and entry points will have 's2io_' prefix and helper functions will have 'do_s2io_' prefix. Signed-off-by: Sreenivasa Honnur Signed-off-by: Jeff Garzik --- drivers/net/s2io.c | 107 +++++++++++++++++++++++++++++++++-------------------- drivers/net/s2io.h | 2 +- 2 files changed, 68 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 3885f6b83cc..01e4b1c26a3 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -355,6 +355,16 @@ static char ethtool_driver_stats_keys[][ETH_GSTRING_LEN] = { timer.data = (unsigned long) arg; \ mod_timer(&timer, (jiffies + exp)) \ +/* copy mac addr to def_mac_addr array */ +static void do_s2io_copy_mac_addr(struct s2io_nic *sp, int offset, u64 mac_addr) +{ + sp->def_mac_addr[offset].mac_addr[5] = (u8) (mac_addr); + sp->def_mac_addr[offset].mac_addr[4] = (u8) (mac_addr >> 8); + sp->def_mac_addr[offset].mac_addr[3] = (u8) (mac_addr >> 16); + sp->def_mac_addr[offset].mac_addr[2] = (u8) (mac_addr >> 24); + sp->def_mac_addr[offset].mac_addr[1] = (u8) (mac_addr >> 32); + sp->def_mac_addr[offset].mac_addr[0] = (u8) (mac_addr >> 40); +} /* Add the vlan */ static void s2io_vlan_rx_register(struct net_device *dev, struct vlan_group *grp) @@ -3412,7 +3422,7 @@ static void s2io_reset(struct s2io_nic * sp) } /* restore the previously assigned mac address */ - s2io_set_mac_addr(sp->dev, (u8 *)&sp->def_mac_addr[0].mac_addr); + do_s2io_prog_unicast(sp->dev, (u8 *)&sp->def_mac_addr[0].mac_addr); sp->device_enabled_once = FALSE; } @@ -3843,7 +3853,7 @@ static int s2io_open(struct net_device *dev) goto hw_init_failed; } - if (s2io_set_mac_addr(dev, dev->dev_addr) == FAILURE) { + if (do_s2io_prog_unicast(dev, dev->dev_addr) == FAILURE) { DBG_PRINT(ERR_DBG, "Set Mac Address Failed\n"); s2io_card_down(sp); err = -ENODEV; @@ -4845,8 +4855,48 @@ static void s2io_set_multicast(struct net_device *dev) } } +/* add unicast MAC address to CAM */ +static int do_s2io_add_unicast(struct s2io_nic *sp, u64 addr, int off) +{ + u64 val64; + struct XENA_dev_config __iomem *bar0 = sp->bar0; + + writeq(RMAC_ADDR_DATA0_MEM_ADDR(addr), + &bar0->rmac_addr_data0_mem); + + val64 = + RMAC_ADDR_CMD_MEM_WE | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | + RMAC_ADDR_CMD_MEM_OFFSET(off); + writeq(val64, &bar0->rmac_addr_cmd_mem); + + /* Wait till command completes */ + if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem, + RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, + S2IO_BIT_RESET)) { + DBG_PRINT(INFO_DBG, "add_mac_addr failed\n"); + return FAILURE; + } + return SUCCESS; +} + +/** + * s2io_set_mac_addr driver entry point + */ +static int s2io_set_mac_addr(struct net_device *dev, void *p) +{ + struct sockaddr *addr = p; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EINVAL; + + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + + /* store the MAC address in CAM */ + return (do_s2io_prog_unicast(dev, dev->dev_addr)); +} + /** - * s2io_set_mac_addr - Programs the Xframe mac address + * do_s2io_prog_unicast - Programs the Xframe mac address * @dev : pointer to the device structure. * @addr: a uchar pointer to the new mac address which is to be set. * Description : This procedure will program the Xframe to receive @@ -4854,56 +4904,31 @@ static void s2io_set_multicast(struct net_device *dev) * Return value: SUCCESS on success and an appropriate (-)ve integer * as defined in errno.h file on failure. */ - -static int s2io_set_mac_addr(struct net_device *dev, u8 * addr) +static int do_s2io_prog_unicast(struct net_device *dev, u8 *addr) { struct s2io_nic *sp = dev->priv; - struct XENA_dev_config __iomem *bar0 = sp->bar0; - register u64 val64, mac_addr = 0; + register u64 mac_addr = 0, perm_addr = 0; int i; - u64 old_mac_addr = 0; /* - * Set the new MAC address as the new unicast filter and reflect this - * change on the device address registered with the OS. It will be - * at offset 0. - */ + * Set the new MAC address as the new unicast filter and reflect this + * change on the device address registered with the OS. It will be + * at offset 0. + */ for (i = 0; i < ETH_ALEN; i++) { mac_addr <<= 8; mac_addr |= addr[i]; - old_mac_addr <<= 8; - old_mac_addr |= sp->def_mac_addr[0].mac_addr[i]; + perm_addr <<= 8; + perm_addr |= sp->def_mac_addr[0].mac_addr[i]; } - if(0 == mac_addr) + /* check if the dev_addr is different than perm_addr */ + if (mac_addr == perm_addr) return SUCCESS; /* Update the internal structure with this new mac address */ - if(mac_addr != old_mac_addr) { - memset(sp->def_mac_addr[0].mac_addr, 0, sizeof(ETH_ALEN)); - sp->def_mac_addr[0].mac_addr[5] = (u8) (mac_addr); - sp->def_mac_addr[0].mac_addr[4] = (u8) (mac_addr >> 8); - sp->def_mac_addr[0].mac_addr[3] = (u8) (mac_addr >> 16); - sp->def_mac_addr[0].mac_addr[2] = (u8) (mac_addr >> 24); - sp->def_mac_addr[0].mac_addr[1] = (u8) (mac_addr >> 32); - sp->def_mac_addr[0].mac_addr[0] = (u8) (mac_addr >> 40); - } - - writeq(RMAC_ADDR_DATA0_MEM_ADDR(mac_addr), - &bar0->rmac_addr_data0_mem); - - val64 = - RMAC_ADDR_CMD_MEM_WE | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | - RMAC_ADDR_CMD_MEM_OFFSET(0); - writeq(val64, &bar0->rmac_addr_cmd_mem); - /* Wait till command completes */ - if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem, - RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, S2IO_BIT_RESET)) { - DBG_PRINT(ERR_DBG, "%s: set_mac_addr failed\n", dev->name); - return FAILURE; - } - - return SUCCESS; + do_s2io_copy_mac_addr(sp, 0, mac_addr); + return (do_s2io_add_unicast(sp, mac_addr, 0)); } /** @@ -7530,6 +7555,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) dev->get_stats = &s2io_get_stats; dev->set_multicast_list = &s2io_set_multicast; dev->do_ioctl = &s2io_ioctl; + dev->set_mac_address = &s2io_set_mac_addr; dev->change_mtu = &s2io_change_mtu; SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops); dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; @@ -7615,6 +7641,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) /* Set the factory defined MAC address initially */ dev->addr_len = ETH_ALEN; memcpy(dev->dev_addr, sp->def_mac_addr, ETH_ALEN); + memcpy(dev->perm_addr, dev->dev_addr, ETH_ALEN); /* Store the values of the MSIX table in the s2io_nic structure */ store_xmsi_data(sp); diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 9b645f40639..f6b45565304 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -1047,7 +1047,7 @@ static void s2io_link(struct s2io_nic * sp, int link); static void s2io_reset(struct s2io_nic * sp); static int s2io_poll(struct napi_struct *napi, int budget); static void s2io_init_pci(struct s2io_nic * sp); -static int s2io_set_mac_addr(struct net_device *dev, u8 * addr); +static int do_s2io_prog_unicast(struct net_device *dev, u8 *addr); static void s2io_alarm_handle(unsigned long data); static irqreturn_t s2io_msix_ring_handle(int irq, void *dev_id); -- cgit v1.2.3-70-g09d2 From 1a7eb72b68c1c6a00a237bc242885222ab74536f Mon Sep 17 00:00:00 2001 From: Sivakumar Subramani Date: Fri, 14 Sep 2007 07:43:16 -0400 Subject: S2io: Updating transceiver information in ethtool function - Update transceiver information in ethtool function Signed-off-by: Sreenivasa Honnur Signed-off-by: Jeff Garzik --- drivers/net/s2io.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 01e4b1c26a3..203cc1e87de 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -84,7 +84,7 @@ #include "s2io.h" #include "s2io-regs.h" -#define DRV_VERSION "2.0.26.4" +#define DRV_VERSION "2.0.26.5" /* S2io Driver name & version. */ static char s2io_driver_name[] = "Neterion"; @@ -4976,7 +4976,9 @@ static int s2io_ethtool_gset(struct net_device *dev, struct ethtool_cmd *info) info->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE); info->advertising = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE); info->port = PORT_FIBRE; - /* info->transceiver?? TODO */ + + /* info->transceiver */ + info->transceiver = XCVR_EXTERNAL; if (netif_carrier_ok(sp->dev)) { info->speed = 10000; -- cgit v1.2.3-70-g09d2 From 73f83182862a2c9113421720997c75ee939902f8 Mon Sep 17 00:00:00 2001 From: Alex Landau Date: Wed, 19 Sep 2007 23:14:18 +0800 Subject: Blackfin EMAC driver: add function to change the MAC address Alex Landau writes in the forums: Previously, changing the MAC address (e.g. via ifconfig) resulted in a generic function to be called that only changed a variable in memory. This patch also updated the Blackfin MAC address registers to filter the correct new MAC. Signed-off-by: Alex Landau Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu Acked-by: Jeff Garzik Signed-off-by: Jeff Garzik --- drivers/net/bfin_mac.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c index cebe55440e1..ead7be96997 100644 --- a/drivers/net/bfin_mac.c +++ b/drivers/net/bfin_mac.c @@ -463,7 +463,7 @@ void setup_system_regs(struct net_device *dev) bfin_write_DMA1_Y_MODIFY(0); } -void setup_mac_addr(u8 * mac_addr) +static void setup_mac_addr(u8 *mac_addr) { u32 addr_low = le32_to_cpu(*(__le32 *) & mac_addr[0]); u16 addr_hi = le16_to_cpu(*(__le16 *) & mac_addr[4]); @@ -473,6 +473,16 @@ void setup_mac_addr(u8 * mac_addr) bfin_write_EMAC_ADDRHI(addr_hi); } +static int bf537mac_set_mac_address(struct net_device *dev, void *p) +{ + struct sockaddr *addr = p; + if (netif_running(dev)) + return -EBUSY; + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + setup_mac_addr(dev->dev_addr); + return 0; +} + static void adjust_tx_list(void) { int timeout_cnt = MAX_TIMEOUT_CNT; @@ -876,6 +886,7 @@ static int __init bf537mac_probe(struct net_device *dev) dev->open = bf537mac_open; dev->stop = bf537mac_close; dev->hard_start_xmit = bf537mac_hard_start_xmit; + dev->set_mac_address = bf537mac_set_mac_address; dev->tx_timeout = bf537mac_timeout; dev->set_multicast_list = bf537mac_set_multicast_list; #ifdef CONFIG_NET_POLL_CONTROLLER -- cgit v1.2.3-70-g09d2 From 496a34c2249fecc87ee689eede2bb8510c1b37a9 Mon Sep 17 00:00:00 2001 From: Bryan Wu Date: Wed, 19 Sep 2007 23:37:14 +0800 Subject: Blackfin EMAC driver: add power management interface and change the bf537mac_reset to bf537mac_disable Signed-off-by: Bryan Wu Acked-by: Jeff Garzik Signed-off-by: Jeff Garzik --- drivers/net/bfin_mac.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c index ead7be96997..5cb4433d561 100644 --- a/drivers/net/bfin_mac.c +++ b/drivers/net/bfin_mac.c @@ -672,7 +672,7 @@ static void bf537mac_poll(struct net_device *dev) } #endif /* CONFIG_NET_POLL_CONTROLLER */ -static void bf537mac_reset(void) +static void bf537mac_disable(void) { unsigned int opmode; @@ -730,7 +730,7 @@ static void bf537mac_timeout(struct net_device *dev) { pr_debug("%s: %s\n", dev->name, __FUNCTION__); - bf537mac_reset(); + bf537mac_disable(); /* reset tx queue */ tx_list_tail = tx_list_head->next; @@ -810,7 +810,7 @@ static int bf537mac_open(struct net_device *dev) bf537mac_setphy(dev); setup_system_regs(dev); - bf537mac_reset(); + bf537mac_disable(); bf537mac_enable(dev); pr_debug("hardware init finished\n"); @@ -968,15 +968,30 @@ static int bfin_mac_remove(struct platform_device *pdev) return 0; } -static int bfin_mac_suspend(struct platform_device *pdev, pm_message_t state) +#ifdef CONFIG_PM +static int bfin_mac_suspend(struct platform_device *pdev, pm_message_t mesg) { + struct net_device *net_dev = platform_get_drvdata(pdev); + + if (netif_running(net_dev)) + bf537mac_close(net_dev); + return 0; } static int bfin_mac_resume(struct platform_device *pdev) { + struct net_device *net_dev = platform_get_drvdata(pdev); + + if (netif_running(net_dev)) + bf537mac_open(net_dev); + return 0; } +#else +#define bfin_mac_suspend NULL +#define bfin_mac_resume NULL +#endif /* CONFIG_PM */ static struct platform_driver bfin_mac_driver = { .probe = bfin_mac_probe, -- cgit v1.2.3-70-g09d2 From 4ae5a3ad5aa35972863f9c656ebd35446fbb5192 Mon Sep 17 00:00:00 2001 From: Bryan Wu Date: Wed, 19 Sep 2007 23:37:36 +0800 Subject: Blackfin EMAC driver: Add phy abstraction layer supporting in bfin_emac driver - add MDIO functions and register mdio bus - add phy abstraction layer (PAL) functions and use PAL API - test on STAMP537 board Signed-off-by: Bryan Wu Acked-by: Jeff Garzik Signed-off-by: Jeff Garzik --- drivers/net/bfin_mac.c | 311 +++++++++++++++++++++++++++++-------------------- drivers/net/bfin_mac.h | 53 ++------- 2 files changed, 196 insertions(+), 168 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c index 5cb4433d561..53fe7ded5d5 100644 --- a/drivers/net/bfin_mac.c +++ b/drivers/net/bfin_mac.c @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -94,6 +95,9 @@ static struct net_dma_desc_tx *current_tx_ptr; static struct net_dma_desc_tx *tx_desc; static struct net_dma_desc_rx *rx_desc; +static void bf537mac_disable(void); +static void bf537mac_enable(void); + static void desc_list_free(void) { struct net_dma_desc_rx *r; @@ -282,8 +286,11 @@ static int setup_pin_mux(int action) return 0; } +/* + * MII operations + */ /* Wait until the previous MDC/MDIO transaction has completed */ -static void poll_mdc_done(void) +static void mdio_poll(void) { int timeout_cnt = MAX_TIMEOUT_CNT; @@ -299,154 +306,201 @@ static void poll_mdc_done(void) } /* Read an off-chip register in a PHY through the MDC/MDIO port */ -static u16 read_phy_reg(u16 PHYAddr, u16 RegAddr) +static int mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum) { - poll_mdc_done(); + mdio_poll(); + /* read mode */ - bfin_write_EMAC_STAADD(SET_PHYAD(PHYAddr) | - SET_REGAD(RegAddr) | + bfin_write_EMAC_STAADD(SET_PHYAD((u16) phy_addr) | + SET_REGAD((u16) regnum) | STABUSY); - poll_mdc_done(); - return (u16) bfin_read_EMAC_STADAT(); + mdio_poll(); + + return (int) bfin_read_EMAC_STADAT(); } /* Write an off-chip register in a PHY through the MDC/MDIO port */ -static void raw_write_phy_reg(u16 PHYAddr, u16 RegAddr, u32 Data) +static int mdiobus_write(struct mii_bus *bus, int phy_addr, int regnum, + u16 value) { - bfin_write_EMAC_STADAT(Data); + mdio_poll(); + + bfin_write_EMAC_STADAT((u32) value); /* write mode */ - bfin_write_EMAC_STAADD(SET_PHYAD(PHYAddr) | - SET_REGAD(RegAddr) | + bfin_write_EMAC_STAADD(SET_PHYAD((u16) phy_addr) | + SET_REGAD((u16) regnum) | STAOP | STABUSY); - poll_mdc_done(); + mdio_poll(); + + return 0; } -static void write_phy_reg(u16 PHYAddr, u16 RegAddr, u32 Data) +static int mdiobus_reset(struct mii_bus *bus) { - poll_mdc_done(); - raw_write_phy_reg(PHYAddr, RegAddr, Data); + return 0; } -/* set up the phy */ -static void bf537mac_setphy(struct net_device *dev) +static void bf537_adjust_link(struct net_device *dev) { - u16 phydat; struct bf537mac_local *lp = netdev_priv(dev); + struct phy_device *phydev = lp->phydev; + unsigned long flags; + int new_state = 0; + + spin_lock_irqsave(&lp->lock, flags); + if (phydev->link) { + /* Now we make sure that we can be in full duplex mode. + * If not, we operate in half-duplex mode. */ + if (phydev->duplex != lp->old_duplex) { + u32 opmode = bfin_read_EMAC_OPMODE(); + new_state = 1; + + if (phydev->duplex) + opmode |= FDMODE; + else + opmode &= ~(FDMODE); + + bfin_write_EMAC_OPMODE(opmode); + lp->old_duplex = phydev->duplex; + } - /* Program PHY registers */ - pr_debug("start setting up phy\n"); - - /* issue a reset */ - raw_write_phy_reg(lp->PhyAddr, PHYREG_MODECTL, 0x8000); - - /* wait half a second */ - msleep(500); - - phydat = read_phy_reg(lp->PhyAddr, PHYREG_MODECTL); - - /* advertise flow control supported */ - phydat = read_phy_reg(lp->PhyAddr, PHYREG_ANAR); - phydat |= (1 << 10); - write_phy_reg(lp->PhyAddr, PHYREG_ANAR, phydat); + if (phydev->speed != lp->old_speed) { +#if defined(CONFIG_BFIN_MAC_RMII) + u32 opmode = bfin_read_EMAC_OPMODE(); + bf537mac_disable(); + switch (phydev->speed) { + case 10: + opmode |= RMII_10; + break; + case 100: + opmode &= ~(RMII_10); + break; + default: + printk(KERN_WARNING + "%s: Ack! Speed (%d) is not 10/100!\n", + DRV_NAME, phydev->speed); + break; + } + bfin_write_EMAC_OPMODE(opmode); + bf537mac_enable(); +#endif - phydat = 0; - if (lp->Negotiate) - phydat |= 0x1000; /* enable auto negotiation */ - else { - if (lp->FullDuplex) - phydat |= (1 << 8); /* full duplex */ - else - phydat &= (~(1 << 8)); /* half duplex */ + new_state = 1; + lp->old_speed = phydev->speed; + } - if (!lp->Port10) - phydat |= (1 << 13); /* 100 Mbps */ - else - phydat &= (~(1 << 13)); /* 10 Mbps */ + if (!lp->old_link) { + new_state = 1; + lp->old_link = 1; + netif_schedule(dev); + } + } else if (lp->old_link) { + new_state = 1; + lp->old_link = 0; + lp->old_speed = 0; + lp->old_duplex = -1; } - if (lp->Loopback) - phydat |= (1 << 14); /* enable TX->RX loopback */ - - write_phy_reg(lp->PhyAddr, PHYREG_MODECTL, phydat); - msleep(500); - - phydat = read_phy_reg(lp->PhyAddr, PHYREG_MODECTL); - /* check for SMSC PHY */ - if ((read_phy_reg(lp->PhyAddr, PHYREG_PHYID1) == 0x7) && - ((read_phy_reg(lp->PhyAddr, PHYREG_PHYID2) & 0xfff0) == 0xC0A0)) { - /* - * we have SMSC PHY so reqest interrupt - * on link down condition - */ - - /* enable interrupts */ - write_phy_reg(lp->PhyAddr, 30, 0x0ff); + if (new_state) { + u32 opmode = bfin_read_EMAC_OPMODE(); + phy_print_status(phydev); + pr_debug("EMAC_OPMODE = 0x%08x\n", opmode); } + + spin_unlock_irqrestore(&lp->lock, flags); } -/**************************************************************************/ -void setup_system_regs(struct net_device *dev) +static int mii_probe(struct net_device *dev) { - int phyaddr; - unsigned short sysctl, phydat; - u32 opmode; struct bf537mac_local *lp = netdev_priv(dev); - int count = 0; - - phyaddr = lp->PhyAddr; + struct phy_device *phydev = NULL; + unsigned short sysctl; + int i; - /* Enable PHY output */ + /* Enable PHY output early */ if (!(bfin_read_VR_CTL() & PHYCLKOE)) bfin_write_VR_CTL(bfin_read_VR_CTL() | PHYCLKOE); /* MDC = 2.5 MHz */ - sysctl = SET_MDCDIV(24); - /* Odd word alignment for Receive Frame DMA word */ - /* Configure checksum support and rcve frame word alignment */ -#if defined(BFIN_MAC_CSUM_OFFLOAD) - sysctl |= RXDWA | RXCKS; -#else - sysctl |= RXDWA; -#endif + sysctl = bfin_read_EMAC_SYSCTL(); + sysctl |= SET_MDCDIV(24); bfin_write_EMAC_SYSCTL(sysctl); - /* auto negotiation on */ - /* full duplex */ - /* 100 Mbps */ - phydat = PHY_ANEG_EN | PHY_DUPLEX | PHY_SPD_SET; - write_phy_reg(phyaddr, PHYREG_MODECTL, phydat); - /* test if full duplex supported */ - do { - msleep(100); - phydat = read_phy_reg(phyaddr, PHYREG_MODESTAT); - if (count > 30) { - printk(KERN_NOTICE DRV_NAME ": Link is down\n"); - printk(KERN_NOTICE DRV_NAME - "please check your network connection\n"); - break; - } - count++; - } while (!(phydat & 0x0004)); + /* search for connect PHY device */ + for (i = 0; i < PHY_MAX_ADDR; i++) { + struct phy_device *const tmp_phydev = lp->mii_bus.phy_map[i]; - phydat = read_phy_reg(phyaddr, PHYREG_ANLPAR); + if (!tmp_phydev) + continue; /* no PHY here... */ - if ((phydat & 0x0100) || (phydat & 0x0040)) { - opmode = FDMODE; - } else { - opmode = 0; - printk(KERN_INFO DRV_NAME - ": Network is set to half duplex\n"); + phydev = tmp_phydev; + break; /* found it */ + } + + /* now we are supposed to have a proper phydev, to attach to... */ + if (!phydev) { + printk(KERN_INFO "%s: Don't found any phy device at all\n", + dev->name); + return -ENODEV; } #if defined(CONFIG_BFIN_MAC_RMII) - opmode |= RMII; /* For Now only 100MBit are supported */ + phydev = phy_connect(dev, phydev->dev.bus_id, &bf537_adjust_link, 0, + PHY_INTERFACE_MODE_RMII); +#else + phydev = phy_connect(dev, phydev->dev.bus_id, &bf537_adjust_link, 0, + PHY_INTERFACE_MODE_MII); #endif - bfin_write_EMAC_OPMODE(opmode); + if (IS_ERR(phydev)) { + printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name); + return PTR_ERR(phydev); + } + + /* mask with MAC supported features */ + phydev->supported &= (SUPPORTED_10baseT_Half + | SUPPORTED_10baseT_Full + | SUPPORTED_100baseT_Half + | SUPPORTED_100baseT_Full + | SUPPORTED_Autoneg + | SUPPORTED_Pause | SUPPORTED_Asym_Pause + | SUPPORTED_MII + | SUPPORTED_TP); + + phydev->advertising = phydev->supported; + + lp->old_link = 0; + lp->old_speed = 0; + lp->old_duplex = -1; + lp->phydev = phydev; + + printk(KERN_INFO "%s: attached PHY driver [%s] " + "(mii_bus:phy_addr=%s, irq=%d)\n", + DRV_NAME, phydev->drv->name, phydev->dev.bus_id, phydev->irq); + + return 0; +} + +/**************************************************************************/ +void setup_system_regs(struct net_device *dev) +{ + unsigned short sysctl; + + /* + * Odd word alignment for Receive Frame DMA word + * Configure checksum support and rcve frame word alignment + */ + sysctl = bfin_read_EMAC_SYSCTL(); +#if defined(BFIN_MAC_CSUM_OFFLOAD) + sysctl |= RXDWA | RXCKS; +#else + sysctl |= RXDWA; +#endif + bfin_write_EMAC_SYSCTL(sysctl); bfin_write_EMAC_MMC_CTL(RSTC | CROLL); @@ -686,18 +740,18 @@ static void bf537mac_disable(void) /* * Enable Interrupts, Receive, and Transmit */ -static int bf537mac_enable(struct net_device *dev) +static void bf537mac_enable(void) { u32 opmode; - pr_debug("%s: %s\n", dev->name, __FUNCTION__); + pr_debug("%s: %s\n", DRV_NAME, __FUNCTION__); /* Set RX DMA */ bfin_write_DMA1_NEXT_DESC_PTR(&(rx_list_head->desc_a)); bfin_write_DMA1_CONFIG(rx_list_head->desc_a.config); /* Wait MII done */ - poll_mdc_done(); + mdio_poll(); /* We enable only RX here */ /* ASTP : Enable Automatic Pad Stripping @@ -721,8 +775,6 @@ static int bf537mac_enable(struct net_device *dev) #endif /* Turn on the EMAC rx */ bfin_write_EMAC_OPMODE(opmode); - - return 0; } /* Our watchdog timed out. Called by the networking layer */ @@ -735,7 +787,7 @@ static void bf537mac_timeout(struct net_device *dev) /* reset tx queue */ tx_list_tail = tx_list_head->next; - bf537mac_enable(dev); + bf537mac_enable(); /* We can accept TX packets again */ dev->trans_start = jiffies; @@ -789,6 +841,7 @@ static void bf537mac_shutdown(struct net_device *dev) */ static int bf537mac_open(struct net_device *dev) { + struct bf537mac_local *lp = netdev_priv(dev); int retval; pr_debug("%s: %s\n", dev->name, __FUNCTION__); @@ -808,10 +861,10 @@ static int bf537mac_open(struct net_device *dev) if (retval) return retval; - bf537mac_setphy(dev); + phy_start(lp->phydev); setup_system_regs(dev); bf537mac_disable(); - bf537mac_enable(dev); + bf537mac_enable(); pr_debug("hardware init finished\n"); netif_start_queue(dev); @@ -828,11 +881,14 @@ static int bf537mac_open(struct net_device *dev) */ static int bf537mac_close(struct net_device *dev) { + struct bf537mac_local *lp = netdev_priv(dev); pr_debug("%s: %s\n", dev->name, __FUNCTION__); netif_stop_queue(dev); netif_carrier_off(dev); + phy_stop(lp->phydev); + /* clear everything */ bf537mac_shutdown(dev); @@ -846,6 +902,7 @@ static int __init bf537mac_probe(struct net_device *dev) { struct bf537mac_local *lp = netdev_priv(dev); int retval; + int i; /* Grab the MAC address in the MAC */ *(__le32 *) (&(dev->dev_addr[0])) = cpu_to_le32(bfin_read_EMAC_ADDRLO()); @@ -862,7 +919,6 @@ static int __init bf537mac_probe(struct net_device *dev) /* set the GPIO pins to Ethernet mode */ retval = setup_pin_mux(1); - if (retval) return retval; @@ -880,6 +936,23 @@ static int __init bf537mac_probe(struct net_device *dev) setup_mac_addr(dev->dev_addr); + /* MDIO bus initial */ + lp->mii_bus.priv = dev; + lp->mii_bus.read = mdiobus_read; + lp->mii_bus.write = mdiobus_write; + lp->mii_bus.reset = mdiobus_reset; + lp->mii_bus.name = "bfin_mac_mdio"; + lp->mii_bus.id = 0; + lp->mii_bus.irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL); + for (i = 0; i < PHY_MAX_ADDR; ++i) + lp->mii_bus.irq[i] = PHY_POLL; + + mdiobus_register(&lp->mii_bus); + + retval = mii_probe(dev); + if (retval) + return retval; + /* Fill in the fields of the device structure with ethernet values. */ ether_setup(dev); @@ -893,13 +966,6 @@ static int __init bf537mac_probe(struct net_device *dev) dev->poll_controller = bf537mac_poll; #endif - /* fill in some of the fields */ - lp->version = 1; - lp->PhyAddr = 0x01; - lp->CLKIN = 25; - lp->FullDuplex = 0; - lp->Negotiate = 1; - lp->FlowControl = 0; spin_lock_init(&lp->lock); /* now, enable interrupts */ @@ -912,9 +978,6 @@ static int __init bf537mac_probe(struct net_device *dev) return -EBUSY; } - /* Enable PHY output early */ - if (!(bfin_read_VR_CTL() & PHYCLKOE)) - bfin_write_VR_CTL(bfin_read_VR_CTL() | PHYCLKOE); retval = register_netdev(dev); if (retval == 0) { diff --git a/drivers/net/bfin_mac.h b/drivers/net/bfin_mac.h index b8272469228..3a107ad7538 100644 --- a/drivers/net/bfin_mac.h +++ b/drivers/net/bfin_mac.h @@ -31,32 +31,6 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* - * PHY REGISTER NAMES - */ -#define PHYREG_MODECTL 0x0000 -#define PHYREG_MODESTAT 0x0001 -#define PHYREG_PHYID1 0x0002 -#define PHYREG_PHYID2 0x0003 -#define PHYREG_ANAR 0x0004 -#define PHYREG_ANLPAR 0x0005 -#define PHYREG_ANER 0x0006 -#define PHYREG_NSR 0x0010 -#define PHYREG_LBREMR 0x0011 -#define PHYREG_REC 0x0012 -#define PHYREG_10CFG 0x0013 -#define PHYREG_PHY1_1 0x0014 -#define PHYREG_PHY1_2 0x0015 -#define PHYREG_PHY2 0x0016 -#define PHYREG_TW_1 0x0017 -#define PHYREG_TW_2 0x0018 -#define PHYREG_TEST 0x0019 - -#define PHY_RESET 0x8000 -#define PHY_ANEG_EN 0x1000 -#define PHY_DUPLEX 0x0100 -#define PHY_SPD_SET 0x2000 - #define BFIN_MAC_CSUM_OFFLOAD struct dma_descriptor { @@ -104,27 +78,18 @@ struct bf537mac_local { * can find out semi-useless statistics of how well the card is * performing */ - int version; + struct net_device_stats stats; - int FlowEnabled; /* record if data flow is active */ - int EtherIntIVG; /* IVG for the ethernet interrupt */ - int RXIVG; /* IVG for the RX completion */ - int TXIVG; /* IVG for the TX completion */ - int PhyAddr; /* PHY address */ - int OpMode; /* set these bits n the OPMODE regs */ - int Port10; /* set port speed to 10 Mbit/s */ - int GenChksums; /* IP checksums to be calculated */ - int NoRcveLnth; /* dont insert recv length at start of buffer */ - int StripPads; /* remove trailing pad bytes */ - int FullDuplex; /* set full duplex mode */ - int Negotiate; /* enable auto negotiation */ - int Loopback; /* loopback at the PHY */ - int Cache; /* Buffers may be cached */ - int FlowControl; /* flow control active */ - int CLKIN; /* clock in value in MHZ */ - unsigned short IntMask; /* interrupt mask */ unsigned char Mac[6]; /* MAC address of the board */ spinlock_t lock; + + /* MII and PHY stuffs */ + int old_link; /* used by bf537_adjust_link */ + int old_speed; + int old_duplex; + + struct phy_device *phydev; + struct mii_bus mii_bus; }; extern void get_bf537_ether_addr(char *addr); -- cgit v1.2.3-70-g09d2 From eeb70af91d3f38ba429d3c8e0519b3c1ff8a0955 Mon Sep 17 00:00:00 2001 From: Bryan Wu Date: Wed, 19 Sep 2007 23:37:41 +0800 Subject: Blackfin EMAC driver: add a select for the PHYLIB of this driver Since we are adding requirement for the PHYLIB for this driver, there should be a select for that Cc: Robin Getz Signed-off-by: Bryan Wu Signed-off-by: Jeff Garzik --- drivers/net/Kconfig | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 83b3f7b8fb7..9dc4a80a6ac 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -838,6 +838,8 @@ config BFIN_MAC tristate "Blackfin 536/537 on-chip mac support" depends on NET_ETHERNET && (BF537 || BF536) && (!BF537_PORT_H) select CRC32 + select MII + select PHYLIB select BFIN_MAC_USE_L1 if DMA_UNCACHED_NONE help This is the driver for blackfin on-chip mac device. Say Y if you want it -- cgit v1.2.3-70-g09d2 From 03233b90b0977d577322a6e1ddd56d9cc570d406 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 23 Aug 2007 02:31:17 +0100 Subject: 8139cp: trivial endianness annotations Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/8139cp.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index d437823c2c5..abb2a347108 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -303,25 +303,25 @@ static const unsigned int cp_rx_config = (RX_DMA_BURST << RxCfgDMAShift); struct cp_desc { - u32 opts1; + __le32 opts1; u32 opts2; - u64 addr; + __le64 addr; }; struct cp_dma_stats { - u64 tx_ok; - u64 rx_ok; - u64 tx_err; - u32 rx_err; - u16 rx_fifo; - u16 frame_align; - u32 tx_ok_1col; - u32 tx_ok_mcol; - u64 rx_ok_phys; - u64 rx_ok_bcast; - u32 rx_ok_mcast; - u16 tx_abort; - u16 tx_underrun; + __le64 tx_ok; + __le64 rx_ok; + __le64 tx_err; + __le32 rx_err; + __le16 rx_fifo; + __le16 frame_align; + __le32 tx_ok_1col; + __le32 tx_ok_mcol; + __le64 rx_ok_phys; + __le64 rx_ok_bcast; + __le32 rx_ok_mcast; + __le16 tx_abort; + __le16 tx_underrun; } __attribute__((packed)); struct cp_extra_stats { @@ -1018,8 +1018,8 @@ static void cp_init_hw (struct cp_private *cp) cpw8_f (Cfg9346, Cfg9346_Unlock); /* Restore our idea of the MAC address. */ - cpw32_f (MAC0 + 0, cpu_to_le32 (*(u32 *) (dev->dev_addr + 0))); - cpw32_f (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4))); + cpw32_f (MAC0 + 0, le32_to_cpu (*(__le32 *) (dev->dev_addr + 0))); + cpw32_f (MAC0 + 4, le32_to_cpu (*(__le32 *) (dev->dev_addr + 4))); cp_start_hw(cp); cpw8(TxThresh, 0x06); /* XXX convert magic num to a constant */ @@ -1930,8 +1930,8 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) /* read MAC address from EEPROM */ addr_len = read_eeprom (regs, 0, 8) == 0x8129 ? 8 : 6; for (i = 0; i < 3; i++) - ((u16 *) (dev->dev_addr))[i] = - le16_to_cpu (read_eeprom (regs, i + 7, addr_len)); + ((__le16 *) (dev->dev_addr))[i] = + cpu_to_le16(read_eeprom (regs, i + 7, addr_len)); memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); dev->open = cp_open; -- cgit v1.2.3-70-g09d2 From 1d3bb996481e116f5f2b127cbd29b83365d2cf62 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 23 Aug 2007 13:56:01 +1000 Subject: Device tree aware EMAC driver Based on BenH's earlier work, this is a new version of the EMAC driver for the built-in ethernet found on PowerPC 4xx embedded CPUs. The same ASIC is also found in the Axon bridge chip. This new version is designed to work in the arch/powerpc tree, using the device tree to probe the device, rather than the old and ugly arch/ppc OCP layer. This driver is designed to sit alongside the old driver (that lies in drivers/net/ibm_emac and this one in drivers/net/ibm_newemac). The old driver is left in place to support arch/ppc until arch/ppc itself reaches its final demise (not too long now, with luck). This driver still has a number of things that could do with cleaning up, but I think they can be fixed up after merging. Specifically: - Should be adjusted to properly use the dma mapping API. Axon needs this. - Probe logic needs reworking, in conjuction with the general probing code for of_platform devices. The dependencies here between EMAC, MAL, ZMII etc. make this complicated. At present, it usually works, because we initialize and register the sub-drivers before the EMAC driver itself, and (being in driver code) runs after the devices themselves have been instantiated from the device tree. Signed-off-by: David Gibson Signed-off-by: Jeff Garzik --- Documentation/powerpc/booting-without-of.txt | 156 ++ arch/powerpc/platforms/44x/Kconfig | 3 +- arch/powerpc/platforms/cell/Kconfig | 4 + drivers/net/Kconfig | 71 +- drivers/net/Makefile | 1 + drivers/net/ibm_emac/Kconfig | 70 + drivers/net/ibm_newemac/Kconfig | 63 + drivers/net/ibm_newemac/Makefile | 11 + drivers/net/ibm_newemac/core.c | 2907 ++++++++++++++++++++++++++ drivers/net/ibm_newemac/core.h | 355 ++++ drivers/net/ibm_newemac/debug.c | 238 +++ drivers/net/ibm_newemac/debug.h | 78 + drivers/net/ibm_newemac/emac.h | 268 +++ drivers/net/ibm_newemac/mal.c | 728 +++++++ drivers/net/ibm_newemac/mal.h | 276 +++ drivers/net/ibm_newemac/phy.c | 373 ++++ drivers/net/ibm_newemac/phy.h | 80 + drivers/net/ibm_newemac/rgmii.c | 323 +++ drivers/net/ibm_newemac/rgmii.h | 76 + drivers/net/ibm_newemac/tah.c | 173 ++ drivers/net/ibm_newemac/tah.h | 90 + drivers/net/ibm_newemac/zmii.c | 322 +++ drivers/net/ibm_newemac/zmii.h | 73 + 23 files changed, 6668 insertions(+), 71 deletions(-) create mode 100644 drivers/net/ibm_emac/Kconfig create mode 100644 drivers/net/ibm_newemac/Kconfig create mode 100644 drivers/net/ibm_newemac/Makefile create mode 100644 drivers/net/ibm_newemac/core.c create mode 100644 drivers/net/ibm_newemac/core.h create mode 100644 drivers/net/ibm_newemac/debug.c create mode 100644 drivers/net/ibm_newemac/debug.h create mode 100644 drivers/net/ibm_newemac/emac.h create mode 100644 drivers/net/ibm_newemac/mal.c create mode 100644 drivers/net/ibm_newemac/mal.h create mode 100644 drivers/net/ibm_newemac/phy.c create mode 100644 drivers/net/ibm_newemac/phy.h create mode 100644 drivers/net/ibm_newemac/rgmii.c create mode 100644 drivers/net/ibm_newemac/rgmii.h create mode 100644 drivers/net/ibm_newemac/tah.c create mode 100644 drivers/net/ibm_newemac/tah.h create mode 100644 drivers/net/ibm_newemac/zmii.c create mode 100644 drivers/net/ibm_newemac/zmii.h (limited to 'drivers') diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt index 76733a3962f..838fd323e79 100644 --- a/Documentation/powerpc/booting-without-of.txt +++ b/Documentation/powerpc/booting-without-of.txt @@ -1824,6 +1824,162 @@ platforms are moved over to use the flattened-device-tree model. fsl,has-rstcr; }; + + h) 4xx/Axon EMAC ethernet nodes + + The EMAC ethernet controller in IBM and AMCC 4xx chips, and also + the Axon bridge. To operate this needs to interact with a ths + special McMAL DMA controller, and sometimes an RGMII or ZMII + interface. In addition to the nodes and properties described + below, the node for the OPB bus on which the EMAC sits must have a + correct clock-frequency property. + + i) The EMAC node itself + + Required properties: + - device_type : "network" + + - compatible : compatible list, contains 2 entries, first is + "ibm,emac-CHIP" where CHIP is the host ASIC (440gx, + 405gp, Axon) and second is either "ibm,emac" or + "ibm,emac4". For Axon, thus, we have: "ibm,emac-axon", + "ibm,emac4" + - interrupts : + - interrupt-parent : optional, if needed for interrupt mapping + - reg : + - local-mac-address : 6 bytes, MAC address + - mal-device : phandle of the associated McMAL node + - mal-tx-channel : 1 cell, index of the tx channel on McMAL associated + with this EMAC + - mal-rx-channel : 1 cell, index of the rx channel on McMAL associated + with this EMAC + - cell-index : 1 cell, hardware index of the EMAC cell on a given + ASIC (typically 0x0 and 0x1 for EMAC0 and EMAC1 on + each Axon chip) + - max-frame-size : 1 cell, maximum frame size supported in bytes + - rx-fifo-size : 1 cell, Rx fifo size in bytes for 10 and 100 Mb/sec + operations. + For Axon, 2048 + - tx-fifo-size : 1 cell, Tx fifo size in bytes for 10 and 100 Mb/sec + operations. + For Axon, 2048. + - fifo-entry-size : 1 cell, size of a fifo entry (used to calculate + thresholds). + For Axon, 0x00000010 + - mal-burst-size : 1 cell, MAL burst size (used to calculate thresholds) + in bytes. + For Axon, 0x00000100 (I think ...) + - phy-mode : string, mode of operations of the PHY interface. + Supported values are: "mii", "rmii", "smii", "rgmii", + "tbi", "gmii", rtbi", "sgmii". + For Axon on CAB, it is "rgmii" + - mdio-device : 1 cell, required iff using shared MDIO registers + (440EP). phandle of the EMAC to use to drive the + MDIO lines for the PHY used by this EMAC. + - zmii-device : 1 cell, required iff connected to a ZMII. phandle of + the ZMII device node + - zmii-channel : 1 cell, required iff connected to a ZMII. Which ZMII + channel or 0xffffffff if ZMII is only used for MDIO. + - rgmii-device : 1 cell, required iff connected to an RGMII. phandle + of the RGMII device node. + For Axon: phandle of plb5/plb4/opb/rgmii + - rgmii-channel : 1 cell, required iff connected to an RGMII. Which + RGMII channel is used by this EMAC. + Fox Axon: present, whatever value is appropriate for each + EMAC, that is the content of the current (bogus) "phy-port" + property. + + Recommended properties: + - linux,network-index : This is the intended "index" of this + network device. This is used by the bootwrapper to interpret + MAC addresses passed by the firmware when no information other + than indices is available to associate an address with a device. + + Optional properties: + - phy-address : 1 cell, optional, MDIO address of the PHY. If absent, + a search is performed. + - phy-map : 1 cell, optional, bitmap of addresses to probe the PHY + for, used if phy-address is absent. bit 0x00000001 is + MDIO address 0. + For Axon it can be absent, thouugh my current driver + doesn't handle phy-address yet so for now, keep + 0x00ffffff in it. + - rx-fifo-size-gige : 1 cell, Rx fifo size in bytes for 1000 Mb/sec + operations (if absent the value is the same as + rx-fifo-size). For Axon, either absent or 2048. + - tx-fifo-size-gige : 1 cell, Tx fifo size in bytes for 1000 Mb/sec + operations (if absent the value is the same as + tx-fifo-size). For Axon, either absent or 2048. + - tah-device : 1 cell, optional. If connected to a TAH engine for + offload, phandle of the TAH device node. + - tah-channel : 1 cell, optional. If appropriate, channel used on the + TAH engine. + + Example: + + EMAC0: ethernet@40000800 { + linux,network-index = <0>; + device_type = "network"; + compatible = "ibm,emac-440gp", "ibm,emac"; + interrupt-parent = <&UIC1>; + interrupts = <1c 4 1d 4>; + reg = <40000800 70>; + local-mac-address = [00 04 AC E3 1B 1E]; + mal-device = <&MAL0>; + mal-tx-channel = <0 1>; + mal-rx-channel = <0>; + cell-index = <0>; + max-frame-size = <5dc>; + rx-fifo-size = <1000>; + tx-fifo-size = <800>; + phy-mode = "rmii"; + phy-map = <00000001>; + zmii-device = <&ZMII0>; + zmii-channel = <0>; + }; + + ii) McMAL node + + Required properties: + - device_type : "dma-controller" + - compatible : compatible list, containing 2 entries, first is + "ibm,mcmal-CHIP" where CHIP is the host ASIC (like + emac) and the second is either "ibm,mcmal" or + "ibm,mcmal2". + For Axon, "ibm,mcmal-axon","ibm,mcmal2" + - interrupts : . + For Axon: This is _different_ from the current + firmware. We use the "delayed" interrupts for txeob + and rxeob. Thus we end up with mapping those 5 MPIC + interrupts, all level positive sensitive: 10, 11, 32, + 33, 34 (in decimal) + - dcr-reg : < DCR registers range > + - dcr-parent : if needed for dcr-reg + - num-tx-chans : 1 cell, number of Tx channels + - num-rx-chans : 1 cell, number of Rx channels + + iii) ZMII node + + Required properties: + - compatible : compatible list, containing 2 entries, first is + "ibm,zmii-CHIP" where CHIP is the host ASIC (like + EMAC) and the second is "ibm,zmii". + For Axon, there is no ZMII node. + - reg : + + iv) RGMII node + + Required properties: + - compatible : compatible list, containing 2 entries, first is + "ibm,rgmii-CHIP" where CHIP is the host ASIC (like + EMAC) and the second is "ibm,rgmii". + For Axon, "ibm,rgmii-axon","ibm,rgmii" + - reg : + - revision : as provided by the RGMII new version register if + available. + For Axon: 0x0000012a + More devices will be defined as this spec matures. VII - Specifying interrupt information for devices diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig index 1b3e008fd14..8e66949e7c6 100644 --- a/arch/powerpc/platforms/44x/Kconfig +++ b/arch/powerpc/platforms/44x/Kconfig @@ -38,8 +38,7 @@ config 440EP config 440GP bool -# Disabled until the new EMAC Driver is merged. -# select IBM_NEW_EMAC_ZMII + select IBM_NEW_EMAC_ZMII config 440GX bool diff --git a/arch/powerpc/platforms/cell/Kconfig b/arch/powerpc/platforms/cell/Kconfig index ac8032034fb..e1e2f6a4301 100644 --- a/arch/powerpc/platforms/cell/Kconfig +++ b/arch/powerpc/platforms/cell/Kconfig @@ -10,6 +10,10 @@ config PPC_CELL_NATIVE select PPC_INDIRECT_IO select PPC_NATIVE select MPIC + select IBM_NEW_EMAC_EMAC4 + select IBM_NEW_EMAC_RGMII + select IBM_NEW_EMAC_ZMII #test only + select IBM_NEW_EMAC_TAH #test only default n config PPC_IBM_CELL_BLADE diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 9dc4a80a6ac..cfa97f3fbeb 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1247,75 +1247,8 @@ config IBMVETH . The module will be called ibmveth. -config IBM_EMAC - tristate "PowerPC 4xx on-chip Ethernet support" - depends on 4xx && !PPC_MERGE - help - This driver supports the PowerPC 4xx EMAC family of on-chip - Ethernet controllers. - -config IBM_EMAC_RXB - int "Number of receive buffers" - depends on IBM_EMAC - default "128" - -config IBM_EMAC_TXB - int "Number of transmit buffers" - depends on IBM_EMAC - default "64" - -config IBM_EMAC_POLL_WEIGHT - int "MAL NAPI polling weight" - depends on IBM_EMAC - default "32" - -config IBM_EMAC_RX_COPY_THRESHOLD - int "RX skb copy threshold (bytes)" - depends on IBM_EMAC - default "256" - -config IBM_EMAC_RX_SKB_HEADROOM - int "Additional RX skb headroom (bytes)" - depends on IBM_EMAC - default "0" - help - Additional receive skb headroom. Note, that driver - will always reserve at least 2 bytes to make IP header - aligned, so usually there is no need to add any additional - headroom. - - If unsure, set to 0. - -config IBM_EMAC_PHY_RX_CLK_FIX - bool "PHY Rx clock workaround" - depends on IBM_EMAC && (405EP || 440GX || 440EP || 440GR) - help - Enable this if EMAC attached to a PHY which doesn't generate - RX clock if there is no link, if this is the case, you will - see "TX disable timeout" or "RX disable timeout" in the system - log. - - If unsure, say N. - -config IBM_EMAC_DEBUG - bool "Debugging" - depends on IBM_EMAC - default n - -config IBM_EMAC_ZMII - bool - depends on IBM_EMAC && (NP405H || NP405L || 44x) - default y - -config IBM_EMAC_RGMII - bool - depends on IBM_EMAC && 440GX - default y - -config IBM_EMAC_TAH - bool - depends on IBM_EMAC && 440GX - default y +source "drivers/net/ibm_emac/Kconfig" +source "drivers/net/ibm_newemac/Kconfig" config NET_PCI bool "EISA, VLB, PCI and on board controllers" diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 2ab33e8b915..9cbef582987 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_E1000) += e1000/ obj-$(CONFIG_E1000E) += e1000e/ obj-$(CONFIG_IBM_EMAC) += ibm_emac/ +obj-$(CONFIG_IBM_NEW_EMAC) += ibm_newemac/ obj-$(CONFIG_IXGBE) += ixgbe/ obj-$(CONFIG_IXGB) += ixgb/ obj-$(CONFIG_IP1000) += ipg.o diff --git a/drivers/net/ibm_emac/Kconfig b/drivers/net/ibm_emac/Kconfig new file mode 100644 index 00000000000..f61c48047dc --- /dev/null +++ b/drivers/net/ibm_emac/Kconfig @@ -0,0 +1,70 @@ +config IBM_EMAC + tristate "PowerPC 4xx on-chip Ethernet support" + depends on 4xx && !PPC_MERGE + help + This driver supports the PowerPC 4xx EMAC family of on-chip + Ethernet controllers. + +config IBM_EMAC_RXB + int "Number of receive buffers" + depends on IBM_EMAC + default "128" + +config IBM_EMAC_TXB + int "Number of transmit buffers" + depends on IBM_EMAC + default "64" + +config IBM_EMAC_POLL_WEIGHT + int "MAL NAPI polling weight" + depends on IBM_EMAC + default "32" + +config IBM_EMAC_RX_COPY_THRESHOLD + int "RX skb copy threshold (bytes)" + depends on IBM_EMAC + default "256" + +config IBM_EMAC_RX_SKB_HEADROOM + int "Additional RX skb headroom (bytes)" + depends on IBM_EMAC + default "0" + help + Additional receive skb headroom. Note, that driver + will always reserve at least 2 bytes to make IP header + aligned, so usually there is no need to add any additional + headroom. + + If unsure, set to 0. + +config IBM_EMAC_PHY_RX_CLK_FIX + bool "PHY Rx clock workaround" + depends on IBM_EMAC && (405EP || 440GX || 440EP || 440GR) + help + Enable this if EMAC attached to a PHY which doesn't generate + RX clock if there is no link, if this is the case, you will + see "TX disable timeout" or "RX disable timeout" in the system + log. + + If unsure, say N. + +config IBM_EMAC_DEBUG + bool "Debugging" + depends on IBM_EMAC + default n + +config IBM_EMAC_ZMII + bool + depends on IBM_EMAC && (NP405H || NP405L || 44x) + default y + +config IBM_EMAC_RGMII + bool + depends on IBM_EMAC && 440GX + default y + +config IBM_EMAC_TAH + bool + depends on IBM_EMAC && 440GX + default y + diff --git a/drivers/net/ibm_newemac/Kconfig b/drivers/net/ibm_newemac/Kconfig new file mode 100644 index 00000000000..0d3e7380bad --- /dev/null +++ b/drivers/net/ibm_newemac/Kconfig @@ -0,0 +1,63 @@ +config IBM_NEW_EMAC + tristate "IBM EMAC Ethernet support" + depends on PPC_DCR && PPC_MERGE + help + This driver supports the IBM EMAC family of Ethernet controllers + typically found on 4xx embedded PowerPC chips, but also on the + Axon southbridge for Cell. + +config IBM_NEW_EMAC_RXB + int "Number of receive buffers" + depends on IBM_NEW_EMAC + default "128" + +config IBM_NEW_EMAC_TXB + int "Number of transmit buffers" + depends on IBM_NEW_EMAC + default "64" + +config IBM_NEW_EMAC_POLL_WEIGHT + int "MAL NAPI polling weight" + depends on IBM_NEW_EMAC + default "32" + +config IBM_NEW_EMAC_RX_COPY_THRESHOLD + int "RX skb copy threshold (bytes)" + depends on IBM_NEW_EMAC + default "256" + +config IBM_NEW_EMAC_RX_SKB_HEADROOM + int "Additional RX skb headroom (bytes)" + depends on IBM_NEW_EMAC + default "0" + help + Additional receive skb headroom. Note, that driver + will always reserve at least 2 bytes to make IP header + aligned, so usually there is no need to add any additional + headroom. + + If unsure, set to 0. + +config IBM_NEW_EMAC_DEBUG + bool "Debugging" + depends on IBM_NEW_EMAC + default n + +# The options below has to be select'ed by the respective +# processor types or platforms + +config IBM_NEW_EMAC_ZMII + bool + default n + +config IBM_NEW_EMAC_RGMII + bool + default n + +config IBM_NEW_EMAC_TAH + bool + default n + +config IBM_NEW_EMAC_EMAC4 + bool + default n diff --git a/drivers/net/ibm_newemac/Makefile b/drivers/net/ibm_newemac/Makefile new file mode 100644 index 00000000000..0b5c9951276 --- /dev/null +++ b/drivers/net/ibm_newemac/Makefile @@ -0,0 +1,11 @@ +# +# Makefile for the PowerPC 4xx on-chip ethernet driver +# + +obj-$(CONFIG_IBM_NEW_EMAC) += ibm_newemac.o + +ibm_newemac-y := mal.o core.o phy.o +ibm_newemac-$(CONFIG_IBM_NEW_EMAC_ZMII) += zmii.o +ibm_newemac-$(CONFIG_IBM_NEW_EMAC_RGMII) += rgmii.o +ibm_newemac-$(CONFIG_IBM_NEW_EMAC_TAH) += tah.o +ibm_newemac-$(CONFIG_IBM_NEW_EMAC_DEBUG) += debug.o diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c new file mode 100644 index 00000000000..653bfdc291e --- /dev/null +++ b/drivers/net/ibm_newemac/core.c @@ -0,0 +1,2907 @@ +/* + * drivers/net/ibm_newemac/core.c + * + * Driver for PowerPC 4xx on-chip ethernet controller. + * + * Copyright (c) 2004, 2005 Zultys Technologies. + * Eugene Surovegin or + * + * Based on original work by + * Matt Porter + * (c) 2003 Benjamin Herrenschmidt + * Armin Kuster + * Johnnie Peters + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "core.h" + +/* + * Lack of dma_unmap_???? calls is intentional. + * + * API-correct usage requires additional support state information to be + * maintained for every RX and TX buffer descriptor (BD). Unfortunately, due to + * EMAC design (e.g. TX buffer passed from network stack can be split into + * several BDs, dma_map_single/dma_map_page can be used to map particular BD), + * maintaining such information will add additional overhead. + * Current DMA API implementation for 4xx processors only ensures cache coherency + * and dma_unmap_???? routines are empty and are likely to stay this way. + * I decided to omit dma_unmap_??? calls because I don't want to add additional + * complexity just for the sake of following some abstract API, when it doesn't + * add any real benefit to the driver. I understand that this decision maybe + * controversial, but I really tried to make code API-correct and efficient + * at the same time and didn't come up with code I liked :(. --ebs + */ + +#define DRV_NAME "emac" +#define DRV_VERSION "3.54" +#define DRV_DESC "PPC 4xx OCP EMAC driver" + +MODULE_DESCRIPTION(DRV_DESC); +MODULE_AUTHOR + ("Eugene Surovegin or "); +MODULE_LICENSE("GPL"); + +/* + * PPC64 doesn't (yet) have a cacheable_memcpy + */ +#ifdef CONFIG_PPC64 +#define cacheable_memcpy(d,s,n) memcpy((d),(s),(n)) +#endif + +/* minimum number of free TX descriptors required to wake up TX process */ +#define EMAC_TX_WAKEUP_THRESH (NUM_TX_BUFF / 4) + +/* If packet size is less than this number, we allocate small skb and copy packet + * contents into it instead of just sending original big skb up + */ +#define EMAC_RX_COPY_THRESH CONFIG_IBM_NEW_EMAC_RX_COPY_THRESHOLD + +/* Since multiple EMACs share MDIO lines in various ways, we need + * to avoid re-using the same PHY ID in cases where the arch didn't + * setup precise phy_map entries + * + * XXX This is something that needs to be reworked as we can have multiple + * EMAC "sets" (multiple ASICs containing several EMACs) though we can + * probably require in that case to have explicit PHY IDs in the device-tree + */ +static u32 busy_phy_map; +static DEFINE_MUTEX(emac_phy_map_lock); + +/* This is the wait queue used to wait on any event related to probe, that + * is discovery of MALs, other EMACs, ZMII/RGMIIs, etc... + */ +static DECLARE_WAIT_QUEUE_HEAD(emac_probe_wait); + +/* Having stable interface names is a doomed idea. However, it would be nice + * if we didn't have completely random interface names at boot too :-) It's + * just a matter of making everybody's life easier. Since we are doing + * threaded probing, it's a bit harder though. The base idea here is that + * we make up a list of all emacs in the device-tree before we register the + * driver. Every emac will then wait for the previous one in the list to + * initialize before itself. We should also keep that list ordered by + * cell_index. + * That list is only 4 entries long, meaning that additional EMACs don't + * get ordering guarantees unless EMAC_BOOT_LIST_SIZE is increased. + */ + +#define EMAC_BOOT_LIST_SIZE 4 +static struct device_node *emac_boot_list[EMAC_BOOT_LIST_SIZE]; + +/* How long should I wait for dependent devices ? */ +#define EMAC_PROBE_DEP_TIMEOUT (HZ * 5) + +/* I don't want to litter system log with timeout errors + * when we have brain-damaged PHY. + */ +static inline void emac_report_timeout_error(struct emac_instance *dev, + const char *error) +{ + if (net_ratelimit()) + printk(KERN_ERR "%s: %s\n", dev->ndev->name, error); +} + +/* PHY polling intervals */ +#define PHY_POLL_LINK_ON HZ +#define PHY_POLL_LINK_OFF (HZ / 5) + +/* Graceful stop timeouts in us. + * We should allow up to 1 frame time (full-duplex, ignoring collisions) + */ +#define STOP_TIMEOUT_10 1230 +#define STOP_TIMEOUT_100 124 +#define STOP_TIMEOUT_1000 13 +#define STOP_TIMEOUT_1000_JUMBO 73 + +/* Please, keep in sync with struct ibm_emac_stats/ibm_emac_error_stats */ +static const char emac_stats_keys[EMAC_ETHTOOL_STATS_COUNT][ETH_GSTRING_LEN] = { + "rx_packets", "rx_bytes", "tx_packets", "tx_bytes", "rx_packets_csum", + "tx_packets_csum", "tx_undo", "rx_dropped_stack", "rx_dropped_oom", + "rx_dropped_error", "rx_dropped_resize", "rx_dropped_mtu", + "rx_stopped", "rx_bd_errors", "rx_bd_overrun", "rx_bd_bad_packet", + "rx_bd_runt_packet", "rx_bd_short_event", "rx_bd_alignment_error", + "rx_bd_bad_fcs", "rx_bd_packet_too_long", "rx_bd_out_of_range", + "rx_bd_in_range", "rx_parity", "rx_fifo_overrun", "rx_overrun", + "rx_bad_packet", "rx_runt_packet", "rx_short_event", + "rx_alignment_error", "rx_bad_fcs", "rx_packet_too_long", + "rx_out_of_range", "rx_in_range", "tx_dropped", "tx_bd_errors", + "tx_bd_bad_fcs", "tx_bd_carrier_loss", "tx_bd_excessive_deferral", + "tx_bd_excessive_collisions", "tx_bd_late_collision", + "tx_bd_multple_collisions", "tx_bd_single_collision", + "tx_bd_underrun", "tx_bd_sqe", "tx_parity", "tx_underrun", "tx_sqe", + "tx_errors" +}; + +static irqreturn_t emac_irq(int irq, void *dev_instance); +static void emac_clean_tx_ring(struct emac_instance *dev); +static void __emac_set_multicast_list(struct emac_instance *dev); + +static inline int emac_phy_supports_gige(int phy_mode) +{ + return phy_mode == PHY_MODE_GMII || + phy_mode == PHY_MODE_RGMII || + phy_mode == PHY_MODE_TBI || + phy_mode == PHY_MODE_RTBI; +} + +static inline int emac_phy_gpcs(int phy_mode) +{ + return phy_mode == PHY_MODE_TBI || + phy_mode == PHY_MODE_RTBI; +} + +static inline void emac_tx_enable(struct emac_instance *dev) +{ + struct emac_regs __iomem *p = dev->emacp; + u32 r; + + DBG(dev, "tx_enable" NL); + + r = in_be32(&p->mr0); + if (!(r & EMAC_MR0_TXE)) + out_be32(&p->mr0, r | EMAC_MR0_TXE); +} + +static void emac_tx_disable(struct emac_instance *dev) +{ + struct emac_regs __iomem *p = dev->emacp; + u32 r; + + DBG(dev, "tx_disable" NL); + + r = in_be32(&p->mr0); + if (r & EMAC_MR0_TXE) { + int n = dev->stop_timeout; + out_be32(&p->mr0, r & ~EMAC_MR0_TXE); + while (!(in_be32(&p->mr0) & EMAC_MR0_TXI) && n) { + udelay(1); + --n; + } + if (unlikely(!n)) + emac_report_timeout_error(dev, "TX disable timeout"); + } +} + +static void emac_rx_enable(struct emac_instance *dev) +{ + struct emac_regs __iomem *p = dev->emacp; + u32 r; + + if (unlikely(test_bit(MAL_COMMAC_RX_STOPPED, &dev->commac.flags))) + goto out; + + DBG(dev, "rx_enable" NL); + + r = in_be32(&p->mr0); + if (!(r & EMAC_MR0_RXE)) { + if (unlikely(!(r & EMAC_MR0_RXI))) { + /* Wait if previous async disable is still in progress */ + int n = dev->stop_timeout; + while (!(r = in_be32(&p->mr0) & EMAC_MR0_RXI) && n) { + udelay(1); + --n; + } + if (unlikely(!n)) + emac_report_timeout_error(dev, + "RX disable timeout"); + } + out_be32(&p->mr0, r | EMAC_MR0_RXE); + } + out: + ; +} + +static void emac_rx_disable(struct emac_instance *dev) +{ + struct emac_regs __iomem *p = dev->emacp; + u32 r; + + DBG(dev, "rx_disable" NL); + + r = in_be32(&p->mr0); + if (r & EMAC_MR0_RXE) { + int n = dev->stop_timeout; + out_be32(&p->mr0, r & ~EMAC_MR0_RXE); + while (!(in_be32(&p->mr0) & EMAC_MR0_RXI) && n) { + udelay(1); + --n; + } + if (unlikely(!n)) + emac_report_timeout_error(dev, "RX disable timeout"); + } +} + +static inline void emac_netif_stop(struct emac_instance *dev) +{ + netif_tx_lock_bh(dev->ndev); + dev->no_mcast = 1; + netif_tx_unlock_bh(dev->ndev); + dev->ndev->trans_start = jiffies; /* prevent tx timeout */ + mal_poll_disable(dev->mal, &dev->commac); + netif_tx_disable(dev->ndev); +} + +static inline void emac_netif_start(struct emac_instance *dev) +{ + netif_tx_lock_bh(dev->ndev); + dev->no_mcast = 0; + if (dev->mcast_pending && netif_running(dev->ndev)) + __emac_set_multicast_list(dev); + netif_tx_unlock_bh(dev->ndev); + + netif_wake_queue(dev->ndev); + + /* NOTE: unconditional netif_wake_queue is only appropriate + * so long as all callers are assured to have free tx slots + * (taken from tg3... though the case where that is wrong is + * not terribly harmful) + */ + mal_poll_enable(dev->mal, &dev->commac); +} + +static inline void emac_rx_disable_async(struct emac_instance *dev) +{ + struct emac_regs __iomem *p = dev->emacp; + u32 r; + + DBG(dev, "rx_disable_async" NL); + + r = in_be32(&p->mr0); + if (r & EMAC_MR0_RXE) + out_be32(&p->mr0, r & ~EMAC_MR0_RXE); +} + +static int emac_reset(struct emac_instance *dev) +{ + struct emac_regs __iomem *p = dev->emacp; + int n = 20; + + DBG(dev, "reset" NL); + + if (!dev->reset_failed) { + /* 40x erratum suggests stopping RX channel before reset, + * we stop TX as well + */ + emac_rx_disable(dev); + emac_tx_disable(dev); + } + + out_be32(&p->mr0, EMAC_MR0_SRST); + while ((in_be32(&p->mr0) & EMAC_MR0_SRST) && n) + --n; + + if (n) { + dev->reset_failed = 0; + return 0; + } else { + emac_report_timeout_error(dev, "reset timeout"); + dev->reset_failed = 1; + return -ETIMEDOUT; + } +} + +static void emac_hash_mc(struct emac_instance *dev) +{ + struct emac_regs __iomem *p = dev->emacp; + u16 gaht[4] = { 0 }; + struct dev_mc_list *dmi; + + DBG(dev, "hash_mc %d" NL, dev->ndev->mc_count); + + for (dmi = dev->ndev->mc_list; dmi; dmi = dmi->next) { + int bit; + DBG2(dev, "mc %02x:%02x:%02x:%02x:%02x:%02x" NL, + dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2], + dmi->dmi_addr[3], dmi->dmi_addr[4], dmi->dmi_addr[5]); + + bit = 63 - (ether_crc(ETH_ALEN, dmi->dmi_addr) >> 26); + gaht[bit >> 4] |= 0x8000 >> (bit & 0x0f); + } + out_be32(&p->gaht1, gaht[0]); + out_be32(&p->gaht2, gaht[1]); + out_be32(&p->gaht3, gaht[2]); + out_be32(&p->gaht4, gaht[3]); +} + +static inline u32 emac_iff2rmr(struct net_device *ndev) +{ + struct emac_instance *dev = netdev_priv(ndev); + u32 r; + + r = EMAC_RMR_SP | EMAC_RMR_SFCS | EMAC_RMR_IAE | EMAC_RMR_BAE; + + if (emac_has_feature(dev, EMAC_FTR_EMAC4)) + r |= EMAC4_RMR_BASE; + else + r |= EMAC_RMR_BASE; + + if (ndev->flags & IFF_PROMISC) + r |= EMAC_RMR_PME; + else if (ndev->flags & IFF_ALLMULTI || ndev->mc_count > 32) + r |= EMAC_RMR_PMME; + else if (ndev->mc_count > 0) + r |= EMAC_RMR_MAE; + + return r; +} + +static u32 __emac_calc_base_mr1(struct emac_instance *dev, int tx_size, int rx_size) +{ + u32 ret = EMAC_MR1_VLE | EMAC_MR1_IST | EMAC_MR1_TR0_MULT; + + DBG2(dev, "__emac_calc_base_mr1" NL); + + switch(tx_size) { + case 2048: + ret |= EMAC_MR1_TFS_2K; + break; + default: + printk(KERN_WARNING "%s: Unknown Rx FIFO size %d\n", + dev->ndev->name, tx_size); + } + + switch(rx_size) { + case 16384: + ret |= EMAC_MR1_RFS_16K; + break; + case 4096: + ret |= EMAC_MR1_RFS_4K; + break; + default: + printk(KERN_WARNING "%s: Unknown Rx FIFO size %d\n", + dev->ndev->name, rx_size); + } + + return ret; +} + +static u32 __emac4_calc_base_mr1(struct emac_instance *dev, int tx_size, int rx_size) +{ + u32 ret = EMAC_MR1_VLE | EMAC_MR1_IST | EMAC4_MR1_TR | + EMAC4_MR1_OBCI(dev->opb_bus_freq); + + DBG2(dev, "__emac4_calc_base_mr1" NL); + + switch(tx_size) { + case 4096: + ret |= EMAC4_MR1_TFS_4K; + break; + case 2048: + ret |= EMAC4_MR1_TFS_2K; + break; + default: + printk(KERN_WARNING "%s: Unknown Rx FIFO size %d\n", + dev->ndev->name, tx_size); + } + + switch(rx_size) { + case 16384: + ret |= EMAC4_MR1_RFS_16K; + break; + case 4096: + ret |= EMAC4_MR1_RFS_4K; + break; + case 2048: + ret |= EMAC4_MR1_RFS_2K; + break; + default: + printk(KERN_WARNING "%s: Unknown Rx FIFO size %d\n", + dev->ndev->name, rx_size); + } + + return ret; +} + +static u32 emac_calc_base_mr1(struct emac_instance *dev, int tx_size, int rx_size) +{ + return emac_has_feature(dev, EMAC_FTR_EMAC4) ? + __emac4_calc_base_mr1(dev, tx_size, rx_size) : + __emac_calc_base_mr1(dev, tx_size, rx_size); +} + +static inline u32 emac_calc_trtr(struct emac_instance *dev, unsigned int size) +{ + if (emac_has_feature(dev, EMAC_FTR_EMAC4)) + return ((size >> 6) - 1) << EMAC_TRTR_SHIFT_EMAC4; + else + return ((size >> 6) - 1) << EMAC_TRTR_SHIFT; +} + +static inline u32 emac_calc_rwmr(struct emac_instance *dev, + unsigned int low, unsigned int high) +{ + if (emac_has_feature(dev, EMAC_FTR_EMAC4)) + return (low << 22) | ( (high & 0x3ff) << 6); + else + return (low << 23) | ( (high & 0x1ff) << 7); +} + +static int emac_configure(struct emac_instance *dev) +{ + struct emac_regs __iomem *p = dev->emacp; + struct net_device *ndev = dev->ndev; + int tx_size, rx_size; + u32 r, mr1 = 0; + + DBG(dev, "configure" NL); + + if (emac_reset(dev) < 0) + return -ETIMEDOUT; + + if (emac_has_feature(dev, EMAC_FTR_HAS_TAH)) + tah_reset(dev->tah_dev); + + DBG(dev, " duplex = %d, pause = %d, asym_pause = %d\n", + dev->phy.duplex, dev->phy.pause, dev->phy.asym_pause); + + /* Default fifo sizes */ + tx_size = dev->tx_fifo_size; + rx_size = dev->rx_fifo_size; + + /* Check for full duplex */ + if (dev->phy.duplex == DUPLEX_FULL) + mr1 |= EMAC_MR1_FDE | EMAC_MR1_MWSW_001; + + /* Adjust fifo sizes, mr1 and timeouts based on link speed */ + dev->stop_timeout = STOP_TIMEOUT_10; + switch (dev->phy.speed) { + case SPEED_1000: + if (emac_phy_gpcs(dev->phy.mode)) { + mr1 |= EMAC_MR1_MF_1000GPCS | + EMAC_MR1_MF_IPPA(dev->phy.address); + + /* Put some arbitrary OUI, Manuf & Rev IDs so we can + * identify this GPCS PHY later. + */ + out_be32(&p->ipcr, 0xdeadbeef); + } else + mr1 |= EMAC_MR1_MF_1000; + + /* Extended fifo sizes */ + tx_size = dev->tx_fifo_size_gige; + rx_size = dev->rx_fifo_size_gige; + + if (dev->ndev->mtu > ETH_DATA_LEN) { + mr1 |= EMAC_MR1_JPSM; + dev->stop_timeout = STOP_TIMEOUT_1000_JUMBO; + } else + dev->stop_timeout = STOP_TIMEOUT_1000; + break; + case SPEED_100: + mr1 |= EMAC_MR1_MF_100; + dev->stop_timeout = STOP_TIMEOUT_100; + break; + default: /* make gcc happy */ + break; + } + + if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII)) + rgmii_set_speed(dev->rgmii_dev, dev->rgmii_port, + dev->phy.speed); + if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII)) + zmii_set_speed(dev->zmii_dev, dev->zmii_port, dev->phy.speed); + + /* on 40x erratum forces us to NOT use integrated flow control, + * let's hope it works on 44x ;) + */ + if (!emac_has_feature(dev, EMAC_FTR_NO_FLOW_CONTROL_40x) && + dev->phy.duplex == DUPLEX_FULL) { + if (dev->phy.pause) + mr1 |= EMAC_MR1_EIFC | EMAC_MR1_APP; + else if (dev->phy.asym_pause) + mr1 |= EMAC_MR1_APP; + } + + /* Add base settings & fifo sizes & program MR1 */ + mr1 |= emac_calc_base_mr1(dev, tx_size, rx_size); + out_be32(&p->mr1, mr1); + + /* Set individual MAC address */ + out_be32(&p->iahr, (ndev->dev_addr[0] << 8) | ndev->dev_addr[1]); + out_be32(&p->ialr, (ndev->dev_addr[2] << 24) | + (ndev->dev_addr[3] << 16) | (ndev->dev_addr[4] << 8) | + ndev->dev_addr[5]); + + /* VLAN Tag Protocol ID */ + out_be32(&p->vtpid, 0x8100); + + /* Receive mode register */ + r = emac_iff2rmr(ndev); + if (r & EMAC_RMR_MAE) + emac_hash_mc(dev); + out_be32(&p->rmr, r); + + /* FIFOs thresholds */ + if (emac_has_feature(dev, EMAC_FTR_EMAC4)) + r = EMAC4_TMR1((dev->mal_burst_size / dev->fifo_entry_size) + 1, + tx_size / 2 / dev->fifo_entry_size); + else + r = EMAC_TMR1((dev->mal_burst_size / dev->fifo_entry_size) + 1, + tx_size / 2 / dev->fifo_entry_size); + out_be32(&p->tmr1, r); + out_be32(&p->trtr, emac_calc_trtr(dev, tx_size / 2)); + + /* PAUSE frame is sent when RX FIFO reaches its high-water mark, + there should be still enough space in FIFO to allow the our link + partner time to process this frame and also time to send PAUSE + frame itself. + + Here is the worst case scenario for the RX FIFO "headroom" + (from "The Switch Book") (100Mbps, without preamble, inter-frame gap): + + 1) One maximum-length frame on TX 1522 bytes + 2) One PAUSE frame time 64 bytes + 3) PAUSE frame decode time allowance 64 bytes + 4) One maximum-length frame on RX 1522 bytes + 5) Round-trip propagation delay of the link (100Mb) 15 bytes + ---------- + 3187 bytes + + I chose to set high-water mark to RX_FIFO_SIZE / 4 (1024 bytes) + low-water mark to RX_FIFO_SIZE / 8 (512 bytes) + */ + r = emac_calc_rwmr(dev, rx_size / 8 / dev->fifo_entry_size, + rx_size / 4 / dev->fifo_entry_size); + out_be32(&p->rwmr, r); + + /* Set PAUSE timer to the maximum */ + out_be32(&p->ptr, 0xffff); + + /* IRQ sources */ + r = EMAC_ISR_OVR | EMAC_ISR_BP | EMAC_ISR_SE | + EMAC_ISR_ALE | EMAC_ISR_BFCS | EMAC_ISR_PTLE | EMAC_ISR_ORE | + EMAC_ISR_IRE | EMAC_ISR_TE; + if (emac_has_feature(dev, EMAC_FTR_EMAC4)) + r |= EMAC4_ISR_TXPE | EMAC4_ISR_RXPE /* | EMAC4_ISR_TXUE | + EMAC4_ISR_RXOE | */; + out_be32(&p->iser, r); + + /* We need to take GPCS PHY out of isolate mode after EMAC reset */ + if (emac_phy_gpcs(dev->phy.mode)) + emac_mii_reset_phy(&dev->phy); + + return 0; +} + +static void emac_reinitialize(struct emac_instance *dev) +{ + DBG(dev, "reinitialize" NL); + + emac_netif_stop(dev); + if (!emac_configure(dev)) { + emac_tx_enable(dev); + emac_rx_enable(dev); + } + emac_netif_start(dev); +} + +static void emac_full_tx_reset(struct emac_instance *dev) +{ + DBG(dev, "full_tx_reset" NL); + + emac_tx_disable(dev); + mal_disable_tx_channel(dev->mal, dev->mal_tx_chan); + emac_clean_tx_ring(dev); + dev->tx_cnt = dev->tx_slot = dev->ack_slot = 0; + + emac_configure(dev); + + mal_enable_tx_channel(dev->mal, dev->mal_tx_chan); + emac_tx_enable(dev); + emac_rx_enable(dev); +} + +static void emac_reset_work(struct work_struct *work) +{ + struct emac_instance *dev = container_of(work, struct emac_instance, reset_work); + + DBG(dev, "reset_work" NL); + + mutex_lock(&dev->link_lock); + emac_netif_stop(dev); + emac_full_tx_reset(dev); + emac_netif_start(dev); + mutex_unlock(&dev->link_lock); +} + +static void emac_tx_timeout(struct net_device *ndev) +{ + struct emac_instance *dev = netdev_priv(ndev); + + DBG(dev, "tx_timeout" NL); + + schedule_work(&dev->reset_work); +} + + +static inline int emac_phy_done(struct emac_instance *dev, u32 stacr) +{ + int done = !!(stacr & EMAC_STACR_OC); + + if (emac_has_feature(dev, EMAC_FTR_STACR_OC_INVERT)) + done = !done; + + return done; +}; + +static int __emac_mdio_read(struct emac_instance *dev, u8 id, u8 reg) +{ + struct emac_regs __iomem *p = dev->emacp; + u32 r = 0; + int n, err = -ETIMEDOUT; + + mutex_lock(&dev->mdio_lock); + + DBG2(dev, "mdio_read(%02x,%02x)" NL, id, reg); + + /* Enable proper MDIO port */ + if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII)) + zmii_get_mdio(dev->zmii_dev, dev->zmii_port); + if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII)) + rgmii_get_mdio(dev->rgmii_dev, dev->rgmii_port); + + /* Wait for management interface to become idle */ + n = 10; + while (!emac_phy_done(dev, in_be32(&p->stacr))) { + udelay(1); + if (!--n) { + DBG2(dev, " -> timeout wait idle\n"); + goto bail; + } + } + + /* Issue read command */ + if (emac_has_feature(dev, EMAC_FTR_EMAC4)) + r = EMAC4_STACR_BASE(dev->opb_bus_freq); + else + r = EMAC_STACR_BASE(dev->opb_bus_freq); + if (emac_has_feature(dev, EMAC_FTR_STACR_OC_INVERT)) + r |= EMAC_STACR_OC; + if (emac_has_feature(dev, EMAC_FTR_HAS_AXON_STACR)) + r |= EMACX_STACR_STAC_READ; + else + r |= EMAC_STACR_STAC_READ; + r |= (reg & EMAC_STACR_PRA_MASK) + | ((id & EMAC_STACR_PCDA_MASK) << EMAC_STACR_PCDA_SHIFT); + out_be32(&p->stacr, r); + + /* Wait for read to complete */ + n = 100; + while (!emac_phy_done(dev, (r = in_be32(&p->stacr)))) { + udelay(1); + if (!--n) { + DBG2(dev, " -> timeout wait complete\n"); + goto bail; + } + } + + if (unlikely(r & EMAC_STACR_PHYE)) { + DBG(dev, "mdio_read(%02x, %02x) failed" NL, id, reg); + err = -EREMOTEIO; + goto bail; + } + + r = ((r >> EMAC_STACR_PHYD_SHIFT) & EMAC_STACR_PHYD_MASK); + + DBG2(dev, "mdio_read -> %04x" NL, r); + err = 0; + bail: + if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII)) + rgmii_put_mdio(dev->rgmii_dev, dev->rgmii_port); + if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII)) + zmii_put_mdio(dev->zmii_dev, dev->zmii_port); + mutex_unlock(&dev->mdio_lock); + + return err == 0 ? r : err; +} + +static void __emac_mdio_write(struct emac_instance *dev, u8 id, u8 reg, + u16 val) +{ + struct emac_regs __iomem *p = dev->emacp; + u32 r = 0; + int n, err = -ETIMEDOUT; + + mutex_lock(&dev->mdio_lock); + + DBG2(dev, "mdio_write(%02x,%02x,%04x)" NL, id, reg, val); + + /* Enable proper MDIO port */ + if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII)) + zmii_get_mdio(dev->zmii_dev, dev->zmii_port); + if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII)) + rgmii_get_mdio(dev->rgmii_dev, dev->rgmii_port); + + /* Wait for management interface to be idle */ + n = 10; + while (!emac_phy_done(dev, in_be32(&p->stacr))) { + udelay(1); + if (!--n) { + DBG2(dev, " -> timeout wait idle\n"); + goto bail; + } + } + + /* Issue write command */ + if (emac_has_feature(dev, EMAC_FTR_EMAC4)) + r = EMAC4_STACR_BASE(dev->opb_bus_freq); + else + r = EMAC_STACR_BASE(dev->opb_bus_freq); + if (emac_has_feature(dev, EMAC_FTR_STACR_OC_INVERT)) + r |= EMAC_STACR_OC; + if (emac_has_feature(dev, EMAC_FTR_HAS_AXON_STACR)) + r |= EMACX_STACR_STAC_WRITE; + else + r |= EMAC_STACR_STAC_WRITE; + r |= (reg & EMAC_STACR_PRA_MASK) | + ((id & EMAC_STACR_PCDA_MASK) << EMAC_STACR_PCDA_SHIFT) | + (val << EMAC_STACR_PHYD_SHIFT); + out_be32(&p->stacr, r); + + /* Wait for write to complete */ + n = 100; + while (!emac_phy_done(dev, in_be32(&p->stacr))) { + udelay(1); + if (!--n) { + DBG2(dev, " -> timeout wait complete\n"); + goto bail; + } + } + err = 0; + bail: + if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII)) + rgmii_put_mdio(dev->rgmii_dev, dev->rgmii_port); + if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII)) + zmii_put_mdio(dev->zmii_dev, dev->zmii_port); + mutex_unlock(&dev->mdio_lock); +} + +static int emac_mdio_read(struct net_device *ndev, int id, int reg) +{ + struct emac_instance *dev = netdev_priv(ndev); + int res; + + res = __emac_mdio_read(dev->mdio_instance ? dev->mdio_instance : dev, + (u8) id, (u8) reg); + return res; +} + +static void emac_mdio_write(struct net_device *ndev, int id, int reg, int val) +{ + struct emac_instance *dev = netdev_priv(ndev); + + __emac_mdio_write(dev->mdio_instance ? dev->mdio_instance : dev, + (u8) id, (u8) reg, (u16) val); +} + +/* Tx lock BH */ +static void __emac_set_multicast_list(struct emac_instance *dev) +{ + struct emac_regs __iomem *p = dev->emacp; + u32 rmr = emac_iff2rmr(dev->ndev); + + DBG(dev, "__multicast %08x" NL, rmr); + + /* I decided to relax register access rules here to avoid + * full EMAC reset. + * + * There is a real problem with EMAC4 core if we use MWSW_001 bit + * in MR1 register and do a full EMAC reset. + * One TX BD status update is delayed and, after EMAC reset, it + * never happens, resulting in TX hung (it'll be recovered by TX + * timeout handler eventually, but this is just gross). + * So we either have to do full TX reset or try to cheat here :) + * + * The only required change is to RX mode register, so I *think* all + * we need is just to stop RX channel. This seems to work on all + * tested SoCs. --ebs + * + * If we need the full reset, we might just trigger the workqueue + * and do it async... a bit nasty but should work --BenH + */ + dev->mcast_pending = 0; + emac_rx_disable(dev); + if (rmr & EMAC_RMR_MAE) + emac_hash_mc(dev); + out_be32(&p->rmr, rmr); + emac_rx_enable(dev); +} + +/* Tx lock BH */ +static void emac_set_multicast_list(struct net_device *ndev) +{ + struct emac_instance *dev = netdev_priv(ndev); + + DBG(dev, "multicast" NL); + + BUG_ON(!netif_running(dev->ndev)); + + if (dev->no_mcast) { + dev->mcast_pending = 1; + return; + } + __emac_set_multicast_list(dev); +} + +static int emac_resize_rx_ring(struct emac_instance *dev, int new_mtu) +{ + int rx_sync_size = emac_rx_sync_size(new_mtu); + int rx_skb_size = emac_rx_skb_size(new_mtu); + int i, ret = 0; + + mutex_lock(&dev->link_lock); + emac_netif_stop(dev); + emac_rx_disable(dev); + mal_disable_rx_channel(dev->mal, dev->mal_rx_chan); + + if (dev->rx_sg_skb) { + ++dev->estats.rx_dropped_resize; + dev_kfree_skb(dev->rx_sg_skb); + dev->rx_sg_skb = NULL; + } + + /* Make a first pass over RX ring and mark BDs ready, dropping + * non-processed packets on the way. We need this as a separate pass + * to simplify error recovery in the case of allocation failure later. + */ + for (i = 0; i < NUM_RX_BUFF; ++i) { + if (dev->rx_desc[i].ctrl & MAL_RX_CTRL_FIRST) + ++dev->estats.rx_dropped_resize; + + dev->rx_desc[i].data_len = 0; + dev->rx_desc[i].ctrl = MAL_RX_CTRL_EMPTY | + (i == (NUM_RX_BUFF - 1) ? MAL_RX_CTRL_WRAP : 0); + } + + /* Reallocate RX ring only if bigger skb buffers are required */ + if (rx_skb_size <= dev->rx_skb_size) + goto skip; + + /* Second pass, allocate new skbs */ + for (i = 0; i < NUM_RX_BUFF; ++i) { + struct sk_buff *skb = alloc_skb(rx_skb_size, GFP_ATOMIC); + if (!skb) { + ret = -ENOMEM; + goto oom; + } + + BUG_ON(!dev->rx_skb[i]); + dev_kfree_skb(dev->rx_skb[i]); + + skb_reserve(skb, EMAC_RX_SKB_HEADROOM + 2); + dev->rx_desc[i].data_ptr = + dma_map_single(&dev->ofdev->dev, skb->data - 2, rx_sync_size, + DMA_FROM_DEVICE) + 2; + dev->rx_skb[i] = skb; + } + skip: + /* Check if we need to change "Jumbo" bit in MR1 */ + if ((new_mtu > ETH_DATA_LEN) ^ (dev->ndev->mtu > ETH_DATA_LEN)) { + /* This is to prevent starting RX channel in emac_rx_enable() */ + set_bit(MAL_COMMAC_RX_STOPPED, &dev->commac.flags); + + dev->ndev->mtu = new_mtu; + emac_full_tx_reset(dev); + } + + mal_set_rcbs(dev->mal, dev->mal_rx_chan, emac_rx_size(new_mtu)); + oom: + /* Restart RX */ + clear_bit(MAL_COMMAC_RX_STOPPED, &dev->commac.flags); + dev->rx_slot = 0; + mal_enable_rx_channel(dev->mal, dev->mal_rx_chan); + emac_rx_enable(dev); + emac_netif_start(dev); + mutex_unlock(&dev->link_lock); + + return ret; +} + +/* Process ctx, rtnl_lock semaphore */ +static int emac_change_mtu(struct net_device *ndev, int new_mtu) +{ + struct emac_instance *dev = netdev_priv(ndev); + int ret = 0; + + if (new_mtu < EMAC_MIN_MTU || new_mtu > dev->max_mtu) + return -EINVAL; + + DBG(dev, "change_mtu(%d)" NL, new_mtu); + + if (netif_running(ndev)) { + /* Check if we really need to reinitalize RX ring */ + if (emac_rx_skb_size(ndev->mtu) != emac_rx_skb_size(new_mtu)) + ret = emac_resize_rx_ring(dev, new_mtu); + } + + if (!ret) { + ndev->mtu = new_mtu; + dev->rx_skb_size = emac_rx_skb_size(new_mtu); + dev->rx_sync_size = emac_rx_sync_size(new_mtu); + } + + return ret; +} + +static void emac_clean_tx_ring(struct emac_instance *dev) +{ + int i; + + for (i = 0; i < NUM_TX_BUFF; ++i) { + if (dev->tx_skb[i]) { + dev_kfree_skb(dev->tx_skb[i]); + dev->tx_skb[i] = NULL; + if (dev->tx_desc[i].ctrl & MAL_TX_CTRL_READY) + ++dev->estats.tx_dropped; + } + dev->tx_desc[i].ctrl = 0; + dev->tx_desc[i].data_ptr = 0; + } +} + +static void emac_clean_rx_ring(struct emac_instance *dev) +{ + int i; + + for (i = 0; i < NUM_RX_BUFF; ++i) + if (dev->rx_skb[i]) { + dev->rx_desc[i].ctrl = 0; + dev_kfree_skb(dev->rx_skb[i]); + dev->rx_skb[i] = NULL; + dev->rx_desc[i].data_ptr = 0; + } + + if (dev->rx_sg_skb) { + dev_kfree_skb(dev->rx_sg_skb); + dev->rx_sg_skb = NULL; + } +} + +static inline int emac_alloc_rx_skb(struct emac_instance *dev, int slot, + gfp_t flags) +{ + struct sk_buff *skb = alloc_skb(dev->rx_skb_size, flags); + if (unlikely(!skb)) + return -ENOMEM; + + dev->rx_skb[slot] = skb; + dev->rx_desc[slot].data_len = 0; + + skb_reserve(skb, EMAC_RX_SKB_HEADROOM + 2); + dev->rx_desc[slot].data_ptr = + dma_map_single(&dev->ofdev->dev, skb->data - 2, dev->rx_sync_size, + DMA_FROM_DEVICE) + 2; + wmb(); + dev->rx_desc[slot].ctrl = MAL_RX_CTRL_EMPTY | + (slot == (NUM_RX_BUFF - 1) ? MAL_RX_CTRL_WRAP : 0); + + return 0; +} + +static void emac_print_link_status(struct emac_instance *dev) +{ + if (netif_carrier_ok(dev->ndev)) + printk(KERN_INFO "%s: link is up, %d %s%s\n", + dev->ndev->name, dev->phy.speed, + dev->phy.duplex == DUPLEX_FULL ? "FDX" : "HDX", + dev->phy.pause ? ", pause enabled" : + dev->phy.asym_pause ? ", asymmetric pause enabled" : ""); + else + printk(KERN_INFO "%s: link is down\n", dev->ndev->name); +} + +/* Process ctx, rtnl_lock semaphore */ +static int emac_open(struct net_device *ndev) +{ + struct emac_instance *dev = netdev_priv(ndev); + int err, i; + + DBG(dev, "open" NL); + + /* Setup error IRQ handler */ + err = request_irq(dev->emac_irq, emac_irq, 0, "EMAC", dev); + if (err) { + printk(KERN_ERR "%s: failed to request IRQ %d\n", + ndev->name, dev->emac_irq); + return err; + } + + /* Allocate RX ring */ + for (i = 0; i < NUM_RX_BUFF; ++i) + if (emac_alloc_rx_skb(dev, i, GFP_KERNEL)) { + printk(KERN_ERR "%s: failed to allocate RX ring\n", + ndev->name); + goto oom; + } + + dev->tx_cnt = dev->tx_slot = dev->ack_slot = dev->rx_slot = 0; + clear_bit(MAL_COMMAC_RX_STOPPED, &dev->commac.flags); + dev->rx_sg_skb = NULL; + + mutex_lock(&dev->link_lock); + + /* XXX Start PHY polling now. Shouldn't wr do like sungem instead and + * always poll the PHY even when the iface is down ? That would allow + * things like laptop-net to work. --BenH + */ + if (dev->phy.address >= 0) { + int link_poll_interval; + if (dev->phy.def->ops->poll_link(&dev->phy)) { + dev->phy.def->ops->read_link(&dev->phy); + netif_carrier_on(dev->ndev); + link_poll_interval = PHY_POLL_LINK_ON; + } else { + netif_carrier_off(dev->ndev); + link_poll_interval = PHY_POLL_LINK_OFF; + } + dev->link_polling = 1; + wmb(); + schedule_delayed_work(&dev->link_work, link_poll_interval); + emac_print_link_status(dev); + } else + netif_carrier_on(dev->ndev); + + emac_configure(dev); + mal_poll_add(dev->mal, &dev->commac); + mal_enable_tx_channel(dev->mal, dev->mal_tx_chan); + mal_set_rcbs(dev->mal, dev->mal_rx_chan, emac_rx_size(ndev->mtu)); + mal_enable_rx_channel(dev->mal, dev->mal_rx_chan); + emac_tx_enable(dev); + emac_rx_enable(dev); + emac_netif_start(dev); + + mutex_unlock(&dev->link_lock); + + return 0; + oom: + emac_clean_rx_ring(dev); + free_irq(dev->emac_irq, dev); + + return -ENOMEM; +} + +/* BHs disabled */ +#if 0 +static int emac_link_differs(struct emac_instance *dev) +{ + u32 r = in_be32(&dev->emacp->mr1); + + int duplex = r & EMAC_MR1_FDE ? DUPLEX_FULL : DUPLEX_HALF; + int speed, pause, asym_pause; + + if (r & EMAC_MR1_MF_1000) + speed = SPEED_1000; + else if (r & EMAC_MR1_MF_100) + speed = SPEED_100; + else + speed = SPEED_10; + + switch (r & (EMAC_MR1_EIFC | EMAC_MR1_APP)) { + case (EMAC_MR1_EIFC | EMAC_MR1_APP): + pause = 1; + asym_pause = 0; + break; + case EMAC_MR1_APP: + pause = 0; + asym_pause = 1; + break; + default: + pause = asym_pause = 0; + } + return speed != dev->phy.speed || duplex != dev->phy.duplex || + pause != dev->phy.pause || asym_pause != dev->phy.asym_pause; +} +#endif + +static void emac_link_timer(struct work_struct *work) +{ + struct emac_instance *dev = + container_of((struct delayed_work *)work, + struct emac_instance, link_work); + int link_poll_interval; + + mutex_lock(&dev->link_lock); + + DBG2(dev, "link timer" NL); + + if (dev->phy.def->ops->poll_link(&dev->phy)) { + if (!netif_carrier_ok(dev->ndev)) { + /* Get new link parameters */ + dev->phy.def->ops->read_link(&dev->phy); + + netif_carrier_on(dev->ndev); + emac_netif_stop(dev); + emac_full_tx_reset(dev); + emac_netif_start(dev); + emac_print_link_status(dev); + } + link_poll_interval = PHY_POLL_LINK_ON; + } else { + if (netif_carrier_ok(dev->ndev)) { + emac_reinitialize(dev); + netif_carrier_off(dev->ndev); + netif_tx_disable(dev->ndev); + emac_print_link_status(dev); + } + link_poll_interval = PHY_POLL_LINK_OFF; + } + schedule_delayed_work(&dev->link_work, link_poll_interval); + + mutex_unlock(&dev->link_lock); +} + +static void emac_force_link_update(struct emac_instance *dev) +{ + netif_carrier_off(dev->ndev); + if (dev->link_polling) { + cancel_rearming_delayed_work(&dev->link_work); + if (dev->link_polling) + schedule_delayed_work(&dev->link_work, PHY_POLL_LINK_OFF); + } +} + +/* Process ctx, rtnl_lock semaphore */ +static int emac_close(struct net_device *ndev) +{ + struct emac_instance *dev = netdev_priv(ndev); + + DBG(dev, "close" NL); + + if (dev->phy.address >= 0) + cancel_rearming_delayed_work(&dev->link_work); + + emac_netif_stop(dev); + flush_scheduled_work(); + + emac_rx_disable(dev); + emac_tx_disable(dev); + mal_disable_rx_channel(dev->mal, dev->mal_rx_chan); + mal_disable_tx_channel(dev->mal, dev->mal_tx_chan); + mal_poll_del(dev->mal, &dev->commac); + + emac_clean_tx_ring(dev); + emac_clean_rx_ring(dev); + + free_irq(dev->emac_irq, dev); + + return 0; +} + +static inline u16 emac_tx_csum(struct emac_instance *dev, + struct sk_buff *skb) +{ + if (emac_has_feature(dev, EMAC_FTR_HAS_TAH && + skb->ip_summed == CHECKSUM_PARTIAL)) { + ++dev->stats.tx_packets_csum; + return EMAC_TX_CTRL_TAH_CSUM; + } + return 0; +} + +static inline int emac_xmit_finish(struct emac_instance *dev, int len) +{ + struct emac_regs __iomem *p = dev->emacp; + struct net_device *ndev = dev->ndev; + + /* Send the packet out. If the if makes a significant perf + * difference, then we can store the TMR0 value in "dev" + * instead + */ + if (emac_has_feature(dev, EMAC_FTR_EMAC4)) + out_be32(&p->tmr0, EMAC_TMR0_XMIT); + else + out_be32(&p->tmr0, EMAC4_TMR0_XMIT); + + if (unlikely(++dev->tx_cnt == NUM_TX_BUFF)) { + netif_stop_queue(ndev); + DBG2(dev, "stopped TX queue" NL); + } + + ndev->trans_start = jiffies; + ++dev->stats.tx_packets; + dev->stats.tx_bytes += len; + + return 0; +} + +/* Tx lock BH */ +static int emac_start_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + struct emac_instance *dev = netdev_priv(ndev); + unsigned int len = skb->len; + int slot; + + u16 ctrl = EMAC_TX_CTRL_GFCS | EMAC_TX_CTRL_GP | MAL_TX_CTRL_READY | + MAL_TX_CTRL_LAST | emac_tx_csum(dev, skb); + + slot = dev->tx_slot++; + if (dev->tx_slot == NUM_TX_BUFF) { + dev->tx_slot = 0; + ctrl |= MAL_TX_CTRL_WRAP; + } + + DBG2(dev, "xmit(%u) %d" NL, len, slot); + + dev->tx_skb[slot] = skb; + dev->tx_desc[slot].data_ptr = dma_map_single(&dev->ofdev->dev, + skb->data, len, + DMA_TO_DEVICE); + dev->tx_desc[slot].data_len = (u16) len; + wmb(); + dev->tx_desc[slot].ctrl = ctrl; + + return emac_xmit_finish(dev, len); +} + +#ifdef CONFIG_IBM_NEW_EMAC_TAH +static inline int emac_xmit_split(struct emac_instance *dev, int slot, + u32 pd, int len, int last, u16 base_ctrl) +{ + while (1) { + u16 ctrl = base_ctrl; + int chunk = min(len, MAL_MAX_TX_SIZE); + len -= chunk; + + slot = (slot + 1) % NUM_TX_BUFF; + + if (last && !len) + ctrl |= MAL_TX_CTRL_LAST; + if (slot == NUM_TX_BUFF - 1) + ctrl |= MAL_TX_CTRL_WRAP; + + dev->tx_skb[slot] = NULL; + dev->tx_desc[slot].data_ptr = pd; + dev->tx_desc[slot].data_len = (u16) chunk; + dev->tx_desc[slot].ctrl = ctrl; + ++dev->tx_cnt; + + if (!len) + break; + + pd += chunk; + } + return slot; +} + +/* Tx lock BH disabled (SG version for TAH equipped EMACs) */ +static int emac_start_xmit_sg(struct sk_buff *skb, struct net_device *ndev) +{ + struct emac_instance *dev = netdev_priv(ndev); + int nr_frags = skb_shinfo(skb)->nr_frags; + int len = skb->len, chunk; + int slot, i; + u16 ctrl; + u32 pd; + + /* This is common "fast" path */ + if (likely(!nr_frags && len <= MAL_MAX_TX_SIZE)) + return emac_start_xmit(skb, ndev); + + len -= skb->data_len; + + /* Note, this is only an *estimation*, we can still run out of empty + * slots because of the additional fragmentation into + * MAL_MAX_TX_SIZE-sized chunks + */ + if (unlikely(dev->tx_cnt + nr_frags + mal_tx_chunks(len) > NUM_TX_BUFF)) + goto stop_queue; + + ctrl = EMAC_TX_CTRL_GFCS | EMAC_TX_CTRL_GP | MAL_TX_CTRL_READY | + emac_tx_csum(dev, skb); + slot = dev->tx_slot; + + /* skb data */ + dev->tx_skb[slot] = NULL; + chunk = min(len, MAL_MAX_TX_SIZE); + dev->tx_desc[slot].data_ptr = pd = + dma_map_single(&dev->ofdev->dev, skb->data, len, DMA_TO_DEVICE); + dev->tx_desc[slot].data_len = (u16) chunk; + len -= chunk; + if (unlikely(len)) + slot = emac_xmit_split(dev, slot, pd + chunk, len, !nr_frags, + ctrl); + /* skb fragments */ + for (i = 0; i < nr_frags; ++i) { + struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i]; + len = frag->size; + + if (unlikely(dev->tx_cnt + mal_tx_chunks(len) >= NUM_TX_BUFF)) + goto undo_frame; + + pd = dma_map_page(&dev->ofdev->dev, frag->page, frag->page_offset, len, + DMA_TO_DEVICE); + + slot = emac_xmit_split(dev, slot, pd, len, i == nr_frags - 1, + ctrl); + } + + DBG2(dev, "xmit_sg(%u) %d - %d" NL, skb->len, dev->tx_slot, slot); + + /* Attach skb to the last slot so we don't release it too early */ + dev->tx_skb[slot] = skb; + + /* Send the packet out */ + if (dev->tx_slot == NUM_TX_BUFF - 1) + ctrl |= MAL_TX_CTRL_WRAP; + wmb(); + dev->tx_desc[dev->tx_slot].ctrl = ctrl; + dev->tx_slot = (slot + 1) % NUM_TX_BUFF; + + return emac_xmit_finish(dev, skb->len); + + undo_frame: + /* Well, too bad. Our previous estimation was overly optimistic. + * Undo everything. + */ + while (slot != dev->tx_slot) { + dev->tx_desc[slot].ctrl = 0; + --dev->tx_cnt; + if (--slot < 0) + slot = NUM_TX_BUFF - 1; + } + ++dev->estats.tx_undo; + + stop_queue: + netif_stop_queue(ndev); + DBG2(dev, "stopped TX queue" NL); + return 1; +} +#else +# define emac_start_xmit_sg emac_start_xmit +#endif /* !defined(CONFIG_IBM_NEW_EMAC_TAH) */ + +/* Tx lock BHs */ +static void emac_parse_tx_error(struct emac_instance *dev, u16 ctrl) +{ + struct emac_error_stats *st = &dev->estats; + + DBG(dev, "BD TX error %04x" NL, ctrl); + + ++st->tx_bd_errors; + if (ctrl & EMAC_TX_ST_BFCS) + ++st->tx_bd_bad_fcs; + if (ctrl & EMAC_TX_ST_LCS) + ++st->tx_bd_carrier_loss; + if (ctrl & EMAC_TX_ST_ED) + ++st->tx_bd_excessive_deferral; + if (ctrl & EMAC_TX_ST_EC) + ++st->tx_bd_excessive_collisions; + if (ctrl & EMAC_TX_ST_LC) + ++st->tx_bd_late_collision; + if (ctrl & EMAC_TX_ST_MC) + ++st->tx_bd_multple_collisions; + if (ctrl & EMAC_TX_ST_SC) + ++st->tx_bd_single_collision; + if (ctrl & EMAC_TX_ST_UR) + ++st->tx_bd_underrun; + if (ctrl & EMAC_TX_ST_SQE) + ++st->tx_bd_sqe; +} + +static void emac_poll_tx(void *param) +{ + struct emac_instance *dev = param; + u32 bad_mask; + + DBG2(dev, "poll_tx, %d %d" NL, dev->tx_cnt, dev->ack_slot); + + if (emac_has_feature(dev, EMAC_FTR_HAS_TAH)) + bad_mask = EMAC_IS_BAD_TX_TAH; + else + bad_mask = EMAC_IS_BAD_TX; + + netif_tx_lock_bh(dev->ndev); + if (dev->tx_cnt) { + u16 ctrl; + int slot = dev->ack_slot, n = 0; + again: + ctrl = dev->tx_desc[slot].ctrl; + if (!(ctrl & MAL_TX_CTRL_READY)) { + struct sk_buff *skb = dev->tx_skb[slot]; + ++n; + + if (skb) { + dev_kfree_skb(skb); + dev->tx_skb[slot] = NULL; + } + slot = (slot + 1) % NUM_TX_BUFF; + + if (unlikely(ctrl & bad_mask)) + emac_parse_tx_error(dev, ctrl); + + if (--dev->tx_cnt) + goto again; + } + if (n) { + dev->ack_slot = slot; + if (netif_queue_stopped(dev->ndev) && + dev->tx_cnt < EMAC_TX_WAKEUP_THRESH) + netif_wake_queue(dev->ndev); + + DBG2(dev, "tx %d pkts" NL, n); + } + } + netif_tx_unlock_bh(dev->ndev); +} + +static inline void emac_recycle_rx_skb(struct emac_instance *dev, int slot, + int len) +{ + struct sk_buff *skb = dev->rx_skb[slot]; + + DBG2(dev, "recycle %d %d" NL, slot, len); + + if (len) + dma_map_single(&dev->ofdev->dev, skb->data - 2, + EMAC_DMA_ALIGN(len + 2), DMA_FROM_DEVICE); + + dev->rx_desc[slot].data_len = 0; + wmb(); + dev->rx_desc[slot].ctrl = MAL_RX_CTRL_EMPTY | + (slot == (NUM_RX_BUFF - 1) ? MAL_RX_CTRL_WRAP : 0); +} + +static void emac_parse_rx_error(struct emac_instance *dev, u16 ctrl) +{ + struct emac_error_stats *st = &dev->estats; + + DBG(dev, "BD RX error %04x" NL, ctrl); + + ++st->rx_bd_errors; + if (ctrl & EMAC_RX_ST_OE) + ++st->rx_bd_overrun; + if (ctrl & EMAC_RX_ST_BP) + ++st->rx_bd_bad_packet; + if (ctrl & EMAC_RX_ST_RP) + ++st->rx_bd_runt_packet; + if (ctrl & EMAC_RX_ST_SE) + ++st->rx_bd_short_event; + if (ctrl & EMAC_RX_ST_AE) + ++st->rx_bd_alignment_error; + if (ctrl & EMAC_RX_ST_BFCS) + ++st->rx_bd_bad_fcs; + if (ctrl & EMAC_RX_ST_PTL) + ++st->rx_bd_packet_too_long; + if (ctrl & EMAC_RX_ST_ORE) + ++st->rx_bd_out_of_range; + if (ctrl & EMAC_RX_ST_IRE) + ++st->rx_bd_in_range; +} + +static inline void emac_rx_csum(struct emac_instance *dev, + struct sk_buff *skb, u16 ctrl) +{ +#ifdef CONFIG_IBM_NEW_EMAC_TAH + if (!ctrl && dev->tah_dev) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + ++dev->stats.rx_packets_csum; + } +#endif +} + +static inline int emac_rx_sg_append(struct emac_instance *dev, int slot) +{ + if (likely(dev->rx_sg_skb != NULL)) { + int len = dev->rx_desc[slot].data_len; + int tot_len = dev->rx_sg_skb->len + len; + + if (unlikely(tot_len + 2 > dev->rx_skb_size)) { + ++dev->estats.rx_dropped_mtu; + dev_kfree_skb(dev->rx_sg_skb); + dev->rx_sg_skb = NULL; + } else { + cacheable_memcpy(dev->rx_sg_skb->tail, + dev->rx_skb[slot]->data, len); + skb_put(dev->rx_sg_skb, len); + emac_recycle_rx_skb(dev, slot, len); + return 0; + } + } + emac_recycle_rx_skb(dev, slot, 0); + return -1; +} + +/* NAPI poll context */ +static int emac_poll_rx(void *param, int budget) +{ + struct emac_instance *dev = param; + int slot = dev->rx_slot, received = 0; + + DBG2(dev, "poll_rx(%d)" NL, budget); + + again: + while (budget > 0) { + int len; + struct sk_buff *skb; + u16 ctrl = dev->rx_desc[slot].ctrl; + + if (ctrl & MAL_RX_CTRL_EMPTY) + break; + + skb = dev->rx_skb[slot]; + mb(); + len = dev->rx_desc[slot].data_len; + + if (unlikely(!MAL_IS_SINGLE_RX(ctrl))) + goto sg; + + ctrl &= EMAC_BAD_RX_MASK; + if (unlikely(ctrl && ctrl != EMAC_RX_TAH_BAD_CSUM)) { + emac_parse_rx_error(dev, ctrl); + ++dev->estats.rx_dropped_error; + emac_recycle_rx_skb(dev, slot, 0); + len = 0; + goto next; + } + + if (len && len < EMAC_RX_COPY_THRESH) { + struct sk_buff *copy_skb = + alloc_skb(len + EMAC_RX_SKB_HEADROOM + 2, GFP_ATOMIC); + if (unlikely(!copy_skb)) + goto oom; + + skb_reserve(copy_skb, EMAC_RX_SKB_HEADROOM + 2); + cacheable_memcpy(copy_skb->data - 2, skb->data - 2, + len + 2); + emac_recycle_rx_skb(dev, slot, len); + skb = copy_skb; + } else if (unlikely(emac_alloc_rx_skb(dev, slot, GFP_ATOMIC))) + goto oom; + + skb_put(skb, len); + push_packet: + skb->dev = dev->ndev; + skb->protocol = eth_type_trans(skb, dev->ndev); + emac_rx_csum(dev, skb, ctrl); + + if (unlikely(netif_receive_skb(skb) == NET_RX_DROP)) + ++dev->estats.rx_dropped_stack; + next: + ++dev->stats.rx_packets; + skip: + dev->stats.rx_bytes += len; + slot = (slot + 1) % NUM_RX_BUFF; + --budget; + ++received; + continue; + sg: + if (ctrl & MAL_RX_CTRL_FIRST) { + BUG_ON(dev->rx_sg_skb); + if (unlikely(emac_alloc_rx_skb(dev, slot, GFP_ATOMIC))) { + DBG(dev, "rx OOM %d" NL, slot); + ++dev->estats.rx_dropped_oom; + emac_recycle_rx_skb(dev, slot, 0); + } else { + dev->rx_sg_skb = skb; + skb_put(skb, len); + } + } else if (!emac_rx_sg_append(dev, slot) && + (ctrl & MAL_RX_CTRL_LAST)) { + + skb = dev->rx_sg_skb; + dev->rx_sg_skb = NULL; + + ctrl &= EMAC_BAD_RX_MASK; + if (unlikely(ctrl && ctrl != EMAC_RX_TAH_BAD_CSUM)) { + emac_parse_rx_error(dev, ctrl); + ++dev->estats.rx_dropped_error; + dev_kfree_skb(skb); + len = 0; + } else + goto push_packet; + } + goto skip; + oom: + DBG(dev, "rx OOM %d" NL, slot); + /* Drop the packet and recycle skb */ + ++dev->estats.rx_dropped_oom; + emac_recycle_rx_skb(dev, slot, 0); + goto next; + } + + if (received) { + DBG2(dev, "rx %d BDs" NL, received); + dev->rx_slot = slot; + } + + if (unlikely(budget && test_bit(MAL_COMMAC_RX_STOPPED, &dev->commac.flags))) { + mb(); + if (!(dev->rx_desc[slot].ctrl & MAL_RX_CTRL_EMPTY)) { + DBG2(dev, "rx restart" NL); + received = 0; + goto again; + } + + if (dev->rx_sg_skb) { + DBG2(dev, "dropping partial rx packet" NL); + ++dev->estats.rx_dropped_error; + dev_kfree_skb(dev->rx_sg_skb); + dev->rx_sg_skb = NULL; + } + + clear_bit(MAL_COMMAC_RX_STOPPED, &dev->commac.flags); + mal_enable_rx_channel(dev->mal, dev->mal_rx_chan); + emac_rx_enable(dev); + dev->rx_slot = 0; + } + return received; +} + +/* NAPI poll context */ +static int emac_peek_rx(void *param) +{ + struct emac_instance *dev = param; + + return !(dev->rx_desc[dev->rx_slot].ctrl & MAL_RX_CTRL_EMPTY); +} + +/* NAPI poll context */ +static int emac_peek_rx_sg(void *param) +{ + struct emac_instance *dev = param; + + int slot = dev->rx_slot; + while (1) { + u16 ctrl = dev->rx_desc[slot].ctrl; + if (ctrl & MAL_RX_CTRL_EMPTY) + return 0; + else if (ctrl & MAL_RX_CTRL_LAST) + return 1; + + slot = (slot + 1) % NUM_RX_BUFF; + + /* I'm just being paranoid here :) */ + if (unlikely(slot == dev->rx_slot)) + return 0; + } +} + +/* Hard IRQ */ +static void emac_rxde(void *param) +{ + struct emac_instance *dev = param; + + ++dev->estats.rx_stopped; + emac_rx_disable_async(dev); +} + +/* Hard IRQ */ +static irqreturn_t emac_irq(int irq, void *dev_instance) +{ + struct emac_instance *dev = dev_instance; + struct emac_regs __iomem *p = dev->emacp; + struct emac_error_stats *st = &dev->estats; + u32 isr; + + spin_lock(&dev->lock); + + isr = in_be32(&p->isr); + out_be32(&p->isr, isr); + + DBG(dev, "isr = %08x" NL, isr); + + if (isr & EMAC4_ISR_TXPE) + ++st->tx_parity; + if (isr & EMAC4_ISR_RXPE) + ++st->rx_parity; + if (isr & EMAC4_ISR_TXUE) + ++st->tx_underrun; + if (isr & EMAC4_ISR_RXOE) + ++st->rx_fifo_overrun; + if (isr & EMAC_ISR_OVR) + ++st->rx_overrun; + if (isr & EMAC_ISR_BP) + ++st->rx_bad_packet; + if (isr & EMAC_ISR_RP) + ++st->rx_runt_packet; + if (isr & EMAC_ISR_SE) + ++st->rx_short_event; + if (isr & EMAC_ISR_ALE) + ++st->rx_alignment_error; + if (isr & EMAC_ISR_BFCS) + ++st->rx_bad_fcs; + if (isr & EMAC_ISR_PTLE) + ++st->rx_packet_too_long; + if (isr & EMAC_ISR_ORE) + ++st->rx_out_of_range; + if (isr & EMAC_ISR_IRE) + ++st->rx_in_range; + if (isr & EMAC_ISR_SQE) + ++st->tx_sqe; + if (isr & EMAC_ISR_TE) + ++st->tx_errors; + + spin_unlock(&dev->lock); + + return IRQ_HANDLED; +} + +static struct net_device_stats *emac_stats(struct net_device *ndev) +{ + struct emac_instance *dev = netdev_priv(ndev); + struct emac_stats *st = &dev->stats; + struct emac_error_stats *est = &dev->estats; + struct net_device_stats *nst = &dev->nstats; + unsigned long flags; + + DBG2(dev, "stats" NL); + + /* Compute "legacy" statistics */ + spin_lock_irqsave(&dev->lock, flags); + nst->rx_packets = (unsigned long)st->rx_packets; + nst->rx_bytes = (unsigned long)st->rx_bytes; + nst->tx_packets = (unsigned long)st->tx_packets; + nst->tx_bytes = (unsigned long)st->tx_bytes; + nst->rx_dropped = (unsigned long)(est->rx_dropped_oom + + est->rx_dropped_error + + est->rx_dropped_resize + + est->rx_dropped_mtu); + nst->tx_dropped = (unsigned long)est->tx_dropped; + + nst->rx_errors = (unsigned long)est->rx_bd_errors; + nst->rx_fifo_errors = (unsigned long)(est->rx_bd_overrun + + est->rx_fifo_overrun + + est->rx_overrun); + nst->rx_frame_errors = (unsigned long)(est->rx_bd_alignment_error + + est->rx_alignment_error); + nst->rx_crc_errors = (unsigned long)(est->rx_bd_bad_fcs + + est->rx_bad_fcs); + nst->rx_length_errors = (unsigned long)(est->rx_bd_runt_packet + + est->rx_bd_short_event + + est->rx_bd_packet_too_long + + est->rx_bd_out_of_range + + est->rx_bd_in_range + + est->rx_runt_packet + + est->rx_short_event + + est->rx_packet_too_long + + est->rx_out_of_range + + est->rx_in_range); + + nst->tx_errors = (unsigned long)(est->tx_bd_errors + est->tx_errors); + nst->tx_fifo_errors = (unsigned long)(est->tx_bd_underrun + + est->tx_underrun); + nst->tx_carrier_errors = (unsigned long)est->tx_bd_carrier_loss; + nst->collisions = (unsigned long)(est->tx_bd_excessive_deferral + + est->tx_bd_excessive_collisions + + est->tx_bd_late_collision + + est->tx_bd_multple_collisions); + spin_unlock_irqrestore(&dev->lock, flags); + return nst; +} + +static struct mal_commac_ops emac_commac_ops = { + .poll_tx = &emac_poll_tx, + .poll_rx = &emac_poll_rx, + .peek_rx = &emac_peek_rx, + .rxde = &emac_rxde, +}; + +static struct mal_commac_ops emac_commac_sg_ops = { + .poll_tx = &emac_poll_tx, + .poll_rx = &emac_poll_rx, + .peek_rx = &emac_peek_rx_sg, + .rxde = &emac_rxde, +}; + +/* Ethtool support */ +static int emac_ethtool_get_settings(struct net_device *ndev, + struct ethtool_cmd *cmd) +{ + struct emac_instance *dev = netdev_priv(ndev); + + cmd->supported = dev->phy.features; + cmd->port = PORT_MII; + cmd->phy_address = dev->phy.address; + cmd->transceiver = + dev->phy.address >= 0 ? XCVR_EXTERNAL : XCVR_INTERNAL; + + mutex_lock(&dev->link_lock); + cmd->advertising = dev->phy.advertising; + cmd->autoneg = dev->phy.autoneg; + cmd->speed = dev->phy.speed; + cmd->duplex = dev->phy.duplex; + mutex_unlock(&dev->link_lock); + + return 0; +} + +static int emac_ethtool_set_settings(struct net_device *ndev, + struct ethtool_cmd *cmd) +{ + struct emac_instance *dev = netdev_priv(ndev); + u32 f = dev->phy.features; + + DBG(dev, "set_settings(%d, %d, %d, 0x%08x)" NL, + cmd->autoneg, cmd->speed, cmd->duplex, cmd->advertising); + + /* Basic sanity checks */ + if (dev->phy.address < 0) + return -EOPNOTSUPP; + if (cmd->autoneg != AUTONEG_ENABLE && cmd->autoneg != AUTONEG_DISABLE) + return -EINVAL; + if (cmd->autoneg == AUTONEG_ENABLE && cmd->advertising == 0) + return -EINVAL; + if (cmd->duplex != DUPLEX_HALF && cmd->duplex != DUPLEX_FULL) + return -EINVAL; + + if (cmd->autoneg == AUTONEG_DISABLE) { + switch (cmd->speed) { + case SPEED_10: + if (cmd->duplex == DUPLEX_HALF + && !(f & SUPPORTED_10baseT_Half)) + return -EINVAL; + if (cmd->duplex == DUPLEX_FULL + && !(f & SUPPORTED_10baseT_Full)) + return -EINVAL; + break; + case SPEED_100: + if (cmd->duplex == DUPLEX_HALF + && !(f & SUPPORTED_100baseT_Half)) + return -EINVAL; + if (cmd->duplex == DUPLEX_FULL + && !(f & SUPPORTED_100baseT_Full)) + return -EINVAL; + break; + case SPEED_1000: + if (cmd->duplex == DUPLEX_HALF + && !(f & SUPPORTED_1000baseT_Half)) + return -EINVAL; + if (cmd->duplex == DUPLEX_FULL + && !(f & SUPPORTED_1000baseT_Full)) + return -EINVAL; + break; + default: + return -EINVAL; + } + + mutex_lock(&dev->link_lock); + dev->phy.def->ops->setup_forced(&dev->phy, cmd->speed, + cmd->duplex); + mutex_unlock(&dev->link_lock); + + } else { + if (!(f & SUPPORTED_Autoneg)) + return -EINVAL; + + mutex_lock(&dev->link_lock); + dev->phy.def->ops->setup_aneg(&dev->phy, + (cmd->advertising & f) | + (dev->phy.advertising & + (ADVERTISED_Pause | + ADVERTISED_Asym_Pause))); + mutex_unlock(&dev->link_lock); + } + emac_force_link_update(dev); + + return 0; +} + +static void emac_ethtool_get_ringparam(struct net_device *ndev, + struct ethtool_ringparam *rp) +{ + rp->rx_max_pending = rp->rx_pending = NUM_RX_BUFF; + rp->tx_max_pending = rp->tx_pending = NUM_TX_BUFF; +} + +static void emac_ethtool_get_pauseparam(struct net_device *ndev, + struct ethtool_pauseparam *pp) +{ + struct emac_instance *dev = netdev_priv(ndev); + + mutex_lock(&dev->link_lock); + if ((dev->phy.features & SUPPORTED_Autoneg) && + (dev->phy.advertising & (ADVERTISED_Pause | ADVERTISED_Asym_Pause))) + pp->autoneg = 1; + + if (dev->phy.duplex == DUPLEX_FULL) { + if (dev->phy.pause) + pp->rx_pause = pp->tx_pause = 1; + else if (dev->phy.asym_pause) + pp->tx_pause = 1; + } + mutex_unlock(&dev->link_lock); +} + +static u32 emac_ethtool_get_rx_csum(struct net_device *ndev) +{ + struct emac_instance *dev = netdev_priv(ndev); + + return dev->tah_dev != 0; +} + +static int emac_get_regs_len(struct emac_instance *dev) +{ + if (emac_has_feature(dev, EMAC_FTR_EMAC4)) + return sizeof(struct emac_ethtool_regs_subhdr) + + EMAC4_ETHTOOL_REGS_SIZE; + else + return sizeof(struct emac_ethtool_regs_subhdr) + + EMAC_ETHTOOL_REGS_SIZE; +} + +static int emac_ethtool_get_regs_len(struct net_device *ndev) +{ + struct emac_instance *dev = netdev_priv(ndev); + int size; + + size = sizeof(struct emac_ethtool_regs_hdr) + + emac_get_regs_len(dev) + mal_get_regs_len(dev->mal); + if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII)) + size += zmii_get_regs_len(dev->zmii_dev); + if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII)) + size += rgmii_get_regs_len(dev->rgmii_dev); + if (emac_has_feature(dev, EMAC_FTR_HAS_TAH)) + size += tah_get_regs_len(dev->tah_dev); + + return size; +} + +static void *emac_dump_regs(struct emac_instance *dev, void *buf) +{ + struct emac_ethtool_regs_subhdr *hdr = buf; + + hdr->index = dev->cell_index; + if (emac_has_feature(dev, EMAC_FTR_EMAC4)) { + hdr->version = EMAC4_ETHTOOL_REGS_VER; + memcpy_fromio(hdr + 1, dev->emacp, EMAC4_ETHTOOL_REGS_SIZE); + return ((void *)(hdr + 1) + EMAC4_ETHTOOL_REGS_SIZE); + } else { + hdr->version = EMAC_ETHTOOL_REGS_VER; + memcpy_fromio(hdr + 1, dev->emacp, EMAC_ETHTOOL_REGS_SIZE); + return ((void *)(hdr + 1) + EMAC_ETHTOOL_REGS_SIZE); + } +} + +static void emac_ethtool_get_regs(struct net_device *ndev, + struct ethtool_regs *regs, void *buf) +{ + struct emac_instance *dev = netdev_priv(ndev); + struct emac_ethtool_regs_hdr *hdr = buf; + + hdr->components = 0; + buf = hdr + 1; + + buf = mal_dump_regs(dev->mal, buf); + buf = emac_dump_regs(dev, buf); + if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII)) { + hdr->components |= EMAC_ETHTOOL_REGS_ZMII; + buf = zmii_dump_regs(dev->zmii_dev, buf); + } + if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII)) { + hdr->components |= EMAC_ETHTOOL_REGS_RGMII; + buf = rgmii_dump_regs(dev->rgmii_dev, buf); + } + if (emac_has_feature(dev, EMAC_FTR_HAS_TAH)) { + hdr->components |= EMAC_ETHTOOL_REGS_TAH; + buf = tah_dump_regs(dev->tah_dev, buf); + } +} + +static int emac_ethtool_nway_reset(struct net_device *ndev) +{ + struct emac_instance *dev = netdev_priv(ndev); + int res = 0; + + DBG(dev, "nway_reset" NL); + + if (dev->phy.address < 0) + return -EOPNOTSUPP; + + mutex_lock(&dev->link_lock); + if (!dev->phy.autoneg) { + res = -EINVAL; + goto out; + } + + dev->phy.def->ops->setup_aneg(&dev->phy, dev->phy.advertising); + out: + mutex_unlock(&dev->link_lock); + emac_force_link_update(dev); + return res; +} + +static int emac_ethtool_get_stats_count(struct net_device *ndev) +{ + return EMAC_ETHTOOL_STATS_COUNT; +} + +static void emac_ethtool_get_strings(struct net_device *ndev, u32 stringset, + u8 * buf) +{ + if (stringset == ETH_SS_STATS) + memcpy(buf, &emac_stats_keys, sizeof(emac_stats_keys)); +} + +static void emac_ethtool_get_ethtool_stats(struct net_device *ndev, + struct ethtool_stats *estats, + u64 * tmp_stats) +{ + struct emac_instance *dev = netdev_priv(ndev); + + memcpy(tmp_stats, &dev->stats, sizeof(dev->stats)); + tmp_stats += sizeof(dev->stats) / sizeof(u64); + memcpy(tmp_stats, &dev->estats, sizeof(dev->estats)); +} + +static void emac_ethtool_get_drvinfo(struct net_device *ndev, + struct ethtool_drvinfo *info) +{ + struct emac_instance *dev = netdev_priv(ndev); + + strcpy(info->driver, "ibm_emac"); + strcpy(info->version, DRV_VERSION); + info->fw_version[0] = '\0'; + sprintf(info->bus_info, "PPC 4xx EMAC-%d %s", + dev->cell_index, dev->ofdev->node->full_name); + info->n_stats = emac_ethtool_get_stats_count(ndev); + info->regdump_len = emac_ethtool_get_regs_len(ndev); +} + +static const struct ethtool_ops emac_ethtool_ops = { + .get_settings = emac_ethtool_get_settings, + .set_settings = emac_ethtool_set_settings, + .get_drvinfo = emac_ethtool_get_drvinfo, + + .get_regs_len = emac_ethtool_get_regs_len, + .get_regs = emac_ethtool_get_regs, + + .nway_reset = emac_ethtool_nway_reset, + + .get_ringparam = emac_ethtool_get_ringparam, + .get_pauseparam = emac_ethtool_get_pauseparam, + + .get_rx_csum = emac_ethtool_get_rx_csum, + + .get_strings = emac_ethtool_get_strings, + .get_stats_count = emac_ethtool_get_stats_count, + .get_ethtool_stats = emac_ethtool_get_ethtool_stats, + + .get_link = ethtool_op_get_link, + .get_tx_csum = ethtool_op_get_tx_csum, + .get_sg = ethtool_op_get_sg, +}; + +static int emac_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) +{ + struct emac_instance *dev = netdev_priv(ndev); + uint16_t *data = (uint16_t *) & rq->ifr_ifru; + + DBG(dev, "ioctl %08x" NL, cmd); + + if (dev->phy.address < 0) + return -EOPNOTSUPP; + + switch (cmd) { + case SIOCGMIIPHY: + case SIOCDEVPRIVATE: + data[0] = dev->phy.address; + /* Fall through */ + case SIOCGMIIREG: + case SIOCDEVPRIVATE + 1: + data[3] = emac_mdio_read(ndev, dev->phy.address, data[1]); + return 0; + + case SIOCSMIIREG: + case SIOCDEVPRIVATE + 2: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + emac_mdio_write(ndev, dev->phy.address, data[1], data[2]); + return 0; + default: + return -EOPNOTSUPP; + } +} + +struct emac_depentry { + u32 phandle; + struct device_node *node; + struct of_device *ofdev; + void *drvdata; +}; + +#define EMAC_DEP_MAL_IDX 0 +#define EMAC_DEP_ZMII_IDX 1 +#define EMAC_DEP_RGMII_IDX 2 +#define EMAC_DEP_TAH_IDX 3 +#define EMAC_DEP_MDIO_IDX 4 +#define EMAC_DEP_PREV_IDX 5 +#define EMAC_DEP_COUNT 6 + +static int __devinit emac_check_deps(struct emac_instance *dev, + struct emac_depentry *deps) +{ + int i, there = 0; + struct device_node *np; + + for (i = 0; i < EMAC_DEP_COUNT; i++) { + /* no dependency on that item, allright */ + if (deps[i].phandle == 0) { + there++; + continue; + } + /* special case for blist as the dependency might go away */ + if (i == EMAC_DEP_PREV_IDX) { + np = *(dev->blist - 1); + if (np == NULL) { + deps[i].phandle = 0; + there++; + continue; + } + if (deps[i].node == NULL) + deps[i].node = of_node_get(np); + } + if (deps[i].node == NULL) + deps[i].node = of_find_node_by_phandle(deps[i].phandle); + if (deps[i].node == NULL) + continue; + if (deps[i].ofdev == NULL) + deps[i].ofdev = of_find_device_by_node(deps[i].node); + if (deps[i].ofdev == NULL) + continue; + if (deps[i].drvdata == NULL) + deps[i].drvdata = dev_get_drvdata(&deps[i].ofdev->dev); + if (deps[i].drvdata != NULL) + there++; + } + return (there == EMAC_DEP_COUNT); +} + +static void emac_put_deps(struct emac_instance *dev) +{ + if (dev->mal_dev) + of_dev_put(dev->mal_dev); + if (dev->zmii_dev) + of_dev_put(dev->zmii_dev); + if (dev->rgmii_dev) + of_dev_put(dev->rgmii_dev); + if (dev->mdio_dev) + of_dev_put(dev->mdio_dev); + if (dev->tah_dev) + of_dev_put(dev->tah_dev); +} + +static int __devinit emac_of_bus_notify(struct notifier_block *nb, + unsigned long action, void *data) +{ + /* We are only intereted in device addition */ + if (action == BUS_NOTIFY_BOUND_DRIVER) + wake_up_all(&emac_probe_wait); + return 0; +} + +static struct notifier_block emac_of_bus_notifier = { + .notifier_call = emac_of_bus_notify +}; + +static int __devinit emac_wait_deps(struct emac_instance *dev) +{ + struct emac_depentry deps[EMAC_DEP_COUNT]; + int i, err; + + memset(&deps, 0, sizeof(deps)); + + deps[EMAC_DEP_MAL_IDX].phandle = dev->mal_ph; + deps[EMAC_DEP_ZMII_IDX].phandle = dev->zmii_ph; + deps[EMAC_DEP_RGMII_IDX].phandle = dev->rgmii_ph; + if (dev->tah_ph) + deps[EMAC_DEP_TAH_IDX].phandle = dev->tah_ph; + if (dev->mdio_ph) + deps[EMAC_DEP_MDIO_IDX].phandle = dev->mdio_ph; + if (dev->blist && dev->blist > emac_boot_list) + deps[EMAC_DEP_PREV_IDX].phandle = 0xffffffffu; + bus_register_notifier(&of_platform_bus_type, &emac_of_bus_notifier); + wait_event_timeout(emac_probe_wait, + emac_check_deps(dev, deps), + EMAC_PROBE_DEP_TIMEOUT); + bus_unregister_notifier(&of_platform_bus_type, &emac_of_bus_notifier); + err = emac_check_deps(dev, deps) ? 0 : -ENODEV; + for (i = 0; i < EMAC_DEP_COUNT; i++) { + if (deps[i].node) + of_node_put(deps[i].node); + if (err && deps[i].ofdev) + of_dev_put(deps[i].ofdev); + } + if (err == 0) { + dev->mal_dev = deps[EMAC_DEP_MAL_IDX].ofdev; + dev->zmii_dev = deps[EMAC_DEP_ZMII_IDX].ofdev; + dev->rgmii_dev = deps[EMAC_DEP_RGMII_IDX].ofdev; + dev->tah_dev = deps[EMAC_DEP_TAH_IDX].ofdev; + dev->mdio_dev = deps[EMAC_DEP_MDIO_IDX].ofdev; + } + if (deps[EMAC_DEP_PREV_IDX].ofdev) + of_dev_put(deps[EMAC_DEP_PREV_IDX].ofdev); + return err; +} + +static int __devinit emac_read_uint_prop(struct device_node *np, const char *name, + u32 *val, int fatal) +{ + int len; + const u32 *prop = of_get_property(np, name, &len); + if (prop == NULL || len < sizeof(u32)) { + if (fatal) + printk(KERN_ERR "%s: missing %s property\n", + np->full_name, name); + return -ENODEV; + } + *val = *prop; + return 0; +} + +static int __devinit emac_init_phy(struct emac_instance *dev) +{ + struct device_node *np = dev->ofdev->node; + struct net_device *ndev = dev->ndev; + u32 phy_map, adv; + int i; + + dev->phy.dev = ndev; + dev->phy.mode = dev->phy_mode; + + /* PHY-less configuration. + * XXX I probably should move these settings to the dev tree + */ + if (dev->phy_address == 0xffffffff && dev->phy_map == 0xffffffff) { + emac_reset(dev); + + /* PHY-less configuration. + * XXX I probably should move these settings to the dev tree + */ + dev->phy.address = -1; + dev->phy.features = SUPPORTED_100baseT_Full | SUPPORTED_MII; + dev->phy.pause = 1; + + return 0; + } + + mutex_lock(&emac_phy_map_lock); + phy_map = dev->phy_map | busy_phy_map; + + DBG(dev, "PHY maps %08x %08x" NL, dev->phy_map, busy_phy_map); + + dev->phy.mdio_read = emac_mdio_read; + dev->phy.mdio_write = emac_mdio_write; + + /* Configure EMAC with defaults so we can at least use MDIO + * This is needed mostly for 440GX + */ + if (emac_phy_gpcs(dev->phy.mode)) { + /* XXX + * Make GPCS PHY address equal to EMAC index. + * We probably should take into account busy_phy_map + * and/or phy_map here. + * + * Note that the busy_phy_map is currently global + * while it should probably be per-ASIC... + */ + dev->phy.address = dev->cell_index; + } + + emac_configure(dev); + + if (dev->phy_address != 0xffffffff) + phy_map = ~(1 << dev->phy_address); + + for (i = 0; i < 0x20; phy_map >>= 1, ++i) + if (!(phy_map & 1)) { + int r; + busy_phy_map |= 1 << i; + + /* Quick check if there is a PHY at the address */ + r = emac_mdio_read(dev->ndev, i, MII_BMCR); + if (r == 0xffff || r < 0) + continue; + if (!emac_mii_phy_probe(&dev->phy, i)) + break; + } + mutex_unlock(&emac_phy_map_lock); + if (i == 0x20) { + printk(KERN_WARNING "%s: can't find PHY!\n", np->full_name); + return -ENXIO; + } + + /* Init PHY */ + if (dev->phy.def->ops->init) + dev->phy.def->ops->init(&dev->phy); + + /* Disable any PHY features not supported by the platform */ + dev->phy.def->features &= ~dev->phy_feat_exc; + + /* Setup initial link parameters */ + if (dev->phy.features & SUPPORTED_Autoneg) { + adv = dev->phy.features; + if (!emac_has_feature(dev, EMAC_FTR_NO_FLOW_CONTROL_40x)) + adv |= ADVERTISED_Pause | ADVERTISED_Asym_Pause; + /* Restart autonegotiation */ + dev->phy.def->ops->setup_aneg(&dev->phy, adv); + } else { + u32 f = dev->phy.def->features; + int speed = SPEED_10, fd = DUPLEX_HALF; + + /* Select highest supported speed/duplex */ + if (f & SUPPORTED_1000baseT_Full) { + speed = SPEED_1000; + fd = DUPLEX_FULL; + } else if (f & SUPPORTED_1000baseT_Half) + speed = SPEED_1000; + else if (f & SUPPORTED_100baseT_Full) { + speed = SPEED_100; + fd = DUPLEX_FULL; + } else if (f & SUPPORTED_100baseT_Half) + speed = SPEED_100; + else if (f & SUPPORTED_10baseT_Full) + fd = DUPLEX_FULL; + + /* Force link parameters */ + dev->phy.def->ops->setup_forced(&dev->phy, speed, fd); + } + return 0; +} + +static int __devinit emac_init_config(struct emac_instance *dev) +{ + struct device_node *np = dev->ofdev->node; + const void *p; + unsigned int plen; + const char *pm, *phy_modes[] = { + [PHY_MODE_NA] = "", + [PHY_MODE_MII] = "mii", + [PHY_MODE_RMII] = "rmii", + [PHY_MODE_SMII] = "smii", + [PHY_MODE_RGMII] = "rgmii", + [PHY_MODE_TBI] = "tbi", + [PHY_MODE_GMII] = "gmii", + [PHY_MODE_RTBI] = "rtbi", + [PHY_MODE_SGMII] = "sgmii", + }; + + /* Read config from device-tree */ + if (emac_read_uint_prop(np, "mal-device", &dev->mal_ph, 1)) + return -ENXIO; + if (emac_read_uint_prop(np, "mal-tx-channel", &dev->mal_tx_chan, 1)) + return -ENXIO; + if (emac_read_uint_prop(np, "mal-rx-channel", &dev->mal_rx_chan, 1)) + return -ENXIO; + if (emac_read_uint_prop(np, "cell-index", &dev->cell_index, 1)) + return -ENXIO; + if (emac_read_uint_prop(np, "max-frame-size", &dev->max_mtu, 0)) + dev->max_mtu = 1500; + if (emac_read_uint_prop(np, "rx-fifo-size", &dev->rx_fifo_size, 0)) + dev->rx_fifo_size = 2048; + if (emac_read_uint_prop(np, "tx-fifo-size", &dev->tx_fifo_size, 0)) + dev->tx_fifo_size = 2048; + if (emac_read_uint_prop(np, "rx-fifo-size-gige", &dev->rx_fifo_size_gige, 0)) + dev->rx_fifo_size_gige = dev->rx_fifo_size; + if (emac_read_uint_prop(np, "tx-fifo-size-gige", &dev->tx_fifo_size_gige, 0)) + dev->tx_fifo_size_gige = dev->tx_fifo_size; + if (emac_read_uint_prop(np, "phy-address", &dev->phy_address, 0)) + dev->phy_address = 0xffffffff; + if (emac_read_uint_prop(np, "phy-map", &dev->phy_map, 0)) + dev->phy_map = 0xffffffff; + if (emac_read_uint_prop(np->parent, "clock-frequency", &dev->opb_bus_freq, 1)) + return -ENXIO; + if (emac_read_uint_prop(np, "tah-device", &dev->tah_ph, 0)) + dev->tah_ph = 0; + if (emac_read_uint_prop(np, "tah-channel", &dev->tah_port, 0)) + dev->tah_ph = 0; + if (emac_read_uint_prop(np, "mdio-device", &dev->mdio_ph, 0)) + dev->mdio_ph = 0; + if (emac_read_uint_prop(np, "zmii-device", &dev->zmii_ph, 0)) + dev->zmii_ph = 0;; + if (emac_read_uint_prop(np, "zmii-channel", &dev->zmii_port, 0)) + dev->zmii_port = 0xffffffff;; + if (emac_read_uint_prop(np, "rgmii-device", &dev->rgmii_ph, 0)) + dev->rgmii_ph = 0;; + if (emac_read_uint_prop(np, "rgmii-channel", &dev->rgmii_port, 0)) + dev->rgmii_port = 0xffffffff;; + if (emac_read_uint_prop(np, "fifo-entry-size", &dev->fifo_entry_size, 0)) + dev->fifo_entry_size = 16; + if (emac_read_uint_prop(np, "mal-burst-size", &dev->mal_burst_size, 0)) + dev->mal_burst_size = 256; + + /* PHY mode needs some decoding */ + dev->phy_mode = PHY_MODE_NA; + pm = of_get_property(np, "phy-mode", &plen); + if (pm != NULL) { + int i; + for (i = 0; i < ARRAY_SIZE(phy_modes); i++) + if (!strcasecmp(pm, phy_modes[i])) { + dev->phy_mode = i; + break; + } + } + + /* Backward compat with non-final DT */ + if (dev->phy_mode == PHY_MODE_NA && pm != NULL && plen == 4) { + u32 nmode = *(const u32 *)pm; + if (nmode > PHY_MODE_NA && nmode <= PHY_MODE_SGMII) + dev->phy_mode = nmode; + } + + /* Check EMAC version */ + if (of_device_is_compatible(np, "ibm,emac4")) + dev->features |= EMAC_FTR_EMAC4; + if (of_device_is_compatible(np, "ibm,emac-axon") + || of_device_is_compatible(np, "ibm,emac-440epx")) + dev->features |= EMAC_FTR_HAS_AXON_STACR + | EMAC_FTR_STACR_OC_INVERT; + if (of_device_is_compatible(np, "ibm,emac-440spe")) + dev->features |= EMAC_FTR_STACR_OC_INVERT; + + /* Fixup some feature bits based on the device tree and verify + * we have support for them compiled in + */ + if (dev->tah_ph != 0) { +#ifdef CONFIG_IBM_NEW_EMAC_TAH + dev->features |= EMAC_FTR_HAS_TAH; +#else + printk(KERN_ERR "%s: TAH support not enabled !\n", + np->full_name); + return -ENXIO; +#endif + } + + if (dev->zmii_ph != 0) { +#ifdef CONFIG_IBM_NEW_EMAC_ZMII + dev->features |= EMAC_FTR_HAS_ZMII; +#else + printk(KERN_ERR "%s: ZMII support not enabled !\n", + np->full_name); + return -ENXIO; +#endif + } + + if (dev->rgmii_ph != 0) { +#ifdef CONFIG_IBM_NEW_EMAC_RGMII + dev->features |= EMAC_FTR_HAS_RGMII; +#else + printk(KERN_ERR "%s: RGMII support not enabled !\n", + np->full_name); + return -ENXIO; +#endif + } + + /* Read MAC-address */ + p = of_get_property(np, "local-mac-address", NULL); + if (p == NULL) { + printk(KERN_ERR "%s: Can't find local-mac-address property\n", + np->full_name); + return -ENXIO; + } + memcpy(dev->ndev->dev_addr, p, 6); + + DBG(dev, "features : 0x%08x / 0x%08x\n", dev->features, EMAC_FTRS_POSSIBLE); + DBG(dev, "tx_fifo_size : %d (%d gige)\n", dev->tx_fifo_size, dev->tx_fifo_size_gige); + DBG(dev, "rx_fifo_size : %d (%d gige)\n", dev->rx_fifo_size, dev->rx_fifo_size_gige); + DBG(dev, "max_mtu : %d\n", dev->max_mtu); + DBG(dev, "OPB freq : %d\n", dev->opb_bus_freq); + + return 0; +} + +static int __devinit emac_probe(struct of_device *ofdev, + const struct of_device_id *match) +{ + struct net_device *ndev; + struct emac_instance *dev; + struct device_node *np = ofdev->node; + struct device_node **blist = NULL; + int err, i; + + /* Find ourselves in the bootlist if we are there */ + for (i = 0; i < EMAC_BOOT_LIST_SIZE; i++) + if (emac_boot_list[i] == np) + blist = &emac_boot_list[i]; + + /* Allocate our net_device structure */ + err = -ENOMEM; + ndev = alloc_etherdev(sizeof(struct emac_instance)); + if (!ndev) { + printk(KERN_ERR "%s: could not allocate ethernet device!\n", + np->full_name); + goto err_gone; + } + dev = netdev_priv(ndev); + dev->ndev = ndev; + dev->ofdev = ofdev; + dev->blist = blist; + SET_MODULE_OWNER(ndev); + SET_NETDEV_DEV(ndev, &ofdev->dev); + + /* Initialize some embedded data structures */ + mutex_init(&dev->mdio_lock); + mutex_init(&dev->link_lock); + spin_lock_init(&dev->lock); + INIT_WORK(&dev->reset_work, emac_reset_work); + + /* Init various config data based on device-tree */ + err = emac_init_config(dev); + if (err != 0) + goto err_free; + + /* Get interrupts. EMAC irq is mandatory, WOL irq is optional */ + dev->emac_irq = irq_of_parse_and_map(np, 0); + dev->wol_irq = irq_of_parse_and_map(np, 1); + if (dev->emac_irq == NO_IRQ) { + printk(KERN_ERR "%s: Can't map main interrupt\n", np->full_name); + goto err_free; + } + ndev->irq = dev->emac_irq; + + /* Map EMAC regs */ + if (of_address_to_resource(np, 0, &dev->rsrc_regs)) { + printk(KERN_ERR "%s: Can't get registers address\n", + np->full_name); + goto err_irq_unmap; + } + // TODO : request_mem_region + dev->emacp = ioremap(dev->rsrc_regs.start, sizeof(struct emac_regs)); + if (dev->emacp == NULL) { + printk(KERN_ERR "%s: Can't map device registers!\n", + np->full_name); + err = -ENOMEM; + goto err_irq_unmap; + } + + /* Wait for dependent devices */ + err = emac_wait_deps(dev); + if (err) { + printk(KERN_ERR + "%s: Timeout waiting for dependent devices\n", + np->full_name); + /* display more info about what's missing ? */ + goto err_reg_unmap; + } + dev->mal = dev_get_drvdata(&dev->mal_dev->dev); + if (dev->mdio_dev != NULL) + dev->mdio_instance = dev_get_drvdata(&dev->mdio_dev->dev); + + /* Register with MAL */ + dev->commac.ops = &emac_commac_ops; + dev->commac.dev = dev; + dev->commac.tx_chan_mask = MAL_CHAN_MASK(dev->mal_tx_chan); + dev->commac.rx_chan_mask = MAL_CHAN_MASK(dev->mal_rx_chan); + err = mal_register_commac(dev->mal, &dev->commac); + if (err) { + printk(KERN_ERR "%s: failed to register with mal %s!\n", + np->full_name, dev->mal_dev->node->full_name); + goto err_rel_deps; + } + dev->rx_skb_size = emac_rx_skb_size(ndev->mtu); + dev->rx_sync_size = emac_rx_sync_size(ndev->mtu); + + /* Get pointers to BD rings */ + dev->tx_desc = + dev->mal->bd_virt + mal_tx_bd_offset(dev->mal, dev->mal_tx_chan); + dev->rx_desc = + dev->mal->bd_virt + mal_rx_bd_offset(dev->mal, dev->mal_rx_chan); + + DBG(dev, "tx_desc %p" NL, dev->tx_desc); + DBG(dev, "rx_desc %p" NL, dev->rx_desc); + + /* Clean rings */ + memset(dev->tx_desc, 0, NUM_TX_BUFF * sizeof(struct mal_descriptor)); + memset(dev->rx_desc, 0, NUM_RX_BUFF * sizeof(struct mal_descriptor)); + + /* Attach to ZMII, if needed */ + if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII) && + (err = zmii_attach(dev->zmii_dev, dev->zmii_port, &dev->phy_mode)) != 0) + goto err_unreg_commac; + + /* Attach to RGMII, if needed */ + if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII) && + (err = rgmii_attach(dev->rgmii_dev, dev->rgmii_port, dev->phy_mode)) != 0) + goto err_detach_zmii; + + /* Attach to TAH, if needed */ + if (emac_has_feature(dev, EMAC_FTR_HAS_TAH) && + (err = tah_attach(dev->tah_dev, dev->tah_port)) != 0) + goto err_detach_rgmii; + + /* Set some link defaults before we can find out real parameters */ + dev->phy.speed = SPEED_100; + dev->phy.duplex = DUPLEX_FULL; + dev->phy.autoneg = AUTONEG_DISABLE; + dev->phy.pause = dev->phy.asym_pause = 0; + dev->stop_timeout = STOP_TIMEOUT_100; + INIT_DELAYED_WORK(&dev->link_work, emac_link_timer); + + /* Find PHY if any */ + err = emac_init_phy(dev); + if (err != 0) + goto err_detach_tah; + + /* Fill in the driver function table */ + ndev->open = &emac_open; +#ifdef CONFIG_IBM_NEW_EMAC_TAH + if (dev->tah_dev) { + ndev->hard_start_xmit = &emac_start_xmit_sg; + ndev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; + } else +#endif + ndev->hard_start_xmit = &emac_start_xmit; + ndev->tx_timeout = &emac_tx_timeout; + ndev->watchdog_timeo = 5 * HZ; + ndev->stop = &emac_close; + ndev->get_stats = &emac_stats; + ndev->set_multicast_list = &emac_set_multicast_list; + ndev->do_ioctl = &emac_ioctl; + if (emac_phy_supports_gige(dev->phy_mode)) { + ndev->change_mtu = &emac_change_mtu; + dev->commac.ops = &emac_commac_sg_ops; + } + SET_ETHTOOL_OPS(ndev, &emac_ethtool_ops); + + netif_carrier_off(ndev); + netif_stop_queue(ndev); + + err = register_netdev(ndev); + if (err) { + printk(KERN_ERR "%s: failed to register net device (%d)!\n", + np->full_name, err); + goto err_detach_tah; + } + + /* Set our drvdata last as we don't want them visible until we are + * fully initialized + */ + wmb(); + dev_set_drvdata(&ofdev->dev, dev); + + /* There's a new kid in town ! Let's tell everybody */ + wake_up_all(&emac_probe_wait); + + + printk(KERN_INFO + "%s: EMAC-%d %s, MAC %02x:%02x:%02x:%02x:%02x:%02x\n", + ndev->name, dev->cell_index, np->full_name, + ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2], + ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]); + + if (dev->phy.address >= 0) + printk("%s: found %s PHY (0x%02x)\n", ndev->name, + dev->phy.def->name, dev->phy.address); + + emac_dbg_register(dev); + + /* Life is good */ + return 0; + + /* I have a bad feeling about this ... */ + + err_detach_tah: + if (emac_has_feature(dev, EMAC_FTR_HAS_TAH)) + tah_detach(dev->tah_dev, dev->tah_port); + err_detach_rgmii: + if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII)) + rgmii_detach(dev->rgmii_dev, dev->rgmii_port); + err_detach_zmii: + if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII)) + zmii_detach(dev->zmii_dev, dev->zmii_port); + err_unreg_commac: + mal_unregister_commac(dev->mal, &dev->commac); + err_rel_deps: + emac_put_deps(dev); + err_reg_unmap: + iounmap(dev->emacp); + err_irq_unmap: + if (dev->wol_irq != NO_IRQ) + irq_dispose_mapping(dev->wol_irq); + if (dev->emac_irq != NO_IRQ) + irq_dispose_mapping(dev->emac_irq); + err_free: + kfree(ndev); + err_gone: + /* if we were on the bootlist, remove us as we won't show up and + * wake up all waiters to notify them in case they were waiting + * on us + */ + if (blist) { + *blist = NULL; + wake_up_all(&emac_probe_wait); + } + return err; +} + +static int __devexit emac_remove(struct of_device *ofdev) +{ + struct emac_instance *dev = dev_get_drvdata(&ofdev->dev); + + DBG(dev, "remove" NL); + + dev_set_drvdata(&ofdev->dev, NULL); + + unregister_netdev(dev->ndev); + + if (emac_has_feature(dev, EMAC_FTR_HAS_TAH)) + tah_detach(dev->tah_dev, dev->tah_port); + if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII)) + rgmii_detach(dev->rgmii_dev, dev->rgmii_port); + if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII)) + zmii_detach(dev->zmii_dev, dev->zmii_port); + + mal_unregister_commac(dev->mal, &dev->commac); + emac_put_deps(dev); + + emac_dbg_unregister(dev); + iounmap(dev->emacp); + + if (dev->wol_irq != NO_IRQ) + irq_dispose_mapping(dev->wol_irq); + if (dev->emac_irq != NO_IRQ) + irq_dispose_mapping(dev->emac_irq); + + kfree(dev->ndev); + + return 0; +} + +/* XXX Features in here should be replaced by properties... */ +static struct of_device_id emac_match[] = +{ + { + .type = "network", + .compatible = "ibm,emac", + }, + { + .type = "network", + .compatible = "ibm,emac4", + }, + {}, +}; + +static struct of_platform_driver emac_driver = { + .name = "emac", + .match_table = emac_match, + + .probe = emac_probe, + .remove = emac_remove, +}; + +static void __init emac_make_bootlist(void) +{ + struct device_node *np = NULL; + int j, max, i = 0, k; + int cell_indices[EMAC_BOOT_LIST_SIZE]; + + /* Collect EMACs */ + while((np = of_find_all_nodes(np)) != NULL) { + const u32 *idx; + + if (of_match_node(emac_match, np) == NULL) + continue; + if (of_get_property(np, "unused", NULL)) + continue; + idx = of_get_property(np, "cell-index", NULL); + if (idx == NULL) + continue; + cell_indices[i] = *idx; + emac_boot_list[i++] = of_node_get(np); + if (i >= EMAC_BOOT_LIST_SIZE) { + of_node_put(np); + break; + } + } + max = i; + + /* Bubble sort them (doh, what a creative algorithm :-) */ + for (i = 0; max > 1 && (i < (max - 1)); i++) + for (j = i; j < max; j++) { + if (cell_indices[i] > cell_indices[j]) { + np = emac_boot_list[i]; + emac_boot_list[i] = emac_boot_list[j]; + emac_boot_list[j] = np; + k = cell_indices[i]; + cell_indices[i] = cell_indices[j]; + cell_indices[j] = k; + } + } +} + +static int __init emac_init(void) +{ + int rc; + + printk(KERN_INFO DRV_DESC ", version " DRV_VERSION "\n"); + + /* Init debug stuff */ + emac_init_debug(); + + /* Build EMAC boot list */ + emac_make_bootlist(); + + /* Init submodules */ + rc = mal_init(); + if (rc) + goto err; + rc = zmii_init(); + if (rc) + goto err_mal; + rc = rgmii_init(); + if (rc) + goto err_zmii; + rc = tah_init(); + if (rc) + goto err_rgmii; + rc = of_register_platform_driver(&emac_driver); + if (rc) + goto err_tah; + + return 0; + + err_tah: + tah_exit(); + err_rgmii: + rgmii_exit(); + err_zmii: + zmii_exit(); + err_mal: + mal_exit(); + err: + return rc; +} + +static void __exit emac_exit(void) +{ + int i; + + of_unregister_platform_driver(&emac_driver); + + tah_exit(); + rgmii_exit(); + zmii_exit(); + mal_exit(); + emac_fini_debug(); + + /* Destroy EMAC boot list */ + for (i = 0; i < EMAC_BOOT_LIST_SIZE; i++) + if (emac_boot_list[i]) + of_node_put(emac_boot_list[i]); +} + +module_init(emac_init); +module_exit(emac_exit); diff --git a/drivers/net/ibm_newemac/core.h b/drivers/net/ibm_newemac/core.h new file mode 100644 index 00000000000..4011803117c --- /dev/null +++ b/drivers/net/ibm_newemac/core.h @@ -0,0 +1,355 @@ +/* + * drivers/net/ibm_newemac/core.h + * + * Driver for PowerPC 4xx on-chip ethernet controller. + * + * Copyright (c) 2004, 2005 Zultys Technologies. + * Eugene Surovegin or + * + * Based on original work by + * Armin Kuster + * Johnnie Peters + * Copyright 2000, 2001 MontaVista Softare Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#ifndef __IBM_NEWEMAC_CORE_H +#define __IBM_NEWEMAC_CORE_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "emac.h" +#include "phy.h" +#include "zmii.h" +#include "rgmii.h" +#include "mal.h" +#include "tah.h" +#include "debug.h" + +#define NUM_TX_BUFF CONFIG_IBM_NEW_EMAC_TXB +#define NUM_RX_BUFF CONFIG_IBM_NEW_EMAC_RXB + +/* Simple sanity check */ +#if NUM_TX_BUFF > 256 || NUM_RX_BUFF > 256 +#error Invalid number of buffer descriptors (greater than 256) +#endif + +#define EMAC_MIN_MTU 46 + +/* Maximum L2 header length (VLAN tagged, no FCS) */ +#define EMAC_MTU_OVERHEAD (6 * 2 + 2 + 4) + +/* RX BD size for the given MTU */ +static inline int emac_rx_size(int mtu) +{ + if (mtu > ETH_DATA_LEN) + return MAL_MAX_RX_SIZE; + else + return mal_rx_size(ETH_DATA_LEN + EMAC_MTU_OVERHEAD); +} + +#define EMAC_DMA_ALIGN(x) ALIGN((x), dma_get_cache_alignment()) + +#define EMAC_RX_SKB_HEADROOM \ + EMAC_DMA_ALIGN(CONFIG_IBM_NEW_EMAC_RX_SKB_HEADROOM) + +/* Size of RX skb for the given MTU */ +static inline int emac_rx_skb_size(int mtu) +{ + int size = max(mtu + EMAC_MTU_OVERHEAD, emac_rx_size(mtu)); + return EMAC_DMA_ALIGN(size + 2) + EMAC_RX_SKB_HEADROOM; +} + +/* RX DMA sync size */ +static inline int emac_rx_sync_size(int mtu) +{ + return EMAC_DMA_ALIGN(emac_rx_size(mtu) + 2); +} + +/* Driver statistcs is split into two parts to make it more cache friendly: + * - normal statistics (packet count, etc) + * - error statistics + * + * When statistics is requested by ethtool, these parts are concatenated, + * normal one goes first. + * + * Please, keep these structures in sync with emac_stats_keys. + */ + +/* Normal TX/RX Statistics */ +struct emac_stats { + u64 rx_packets; + u64 rx_bytes; + u64 tx_packets; + u64 tx_bytes; + u64 rx_packets_csum; + u64 tx_packets_csum; +}; + +/* Error statistics */ +struct emac_error_stats { + u64 tx_undo; + + /* Software RX Errors */ + u64 rx_dropped_stack; + u64 rx_dropped_oom; + u64 rx_dropped_error; + u64 rx_dropped_resize; + u64 rx_dropped_mtu; + u64 rx_stopped; + /* BD reported RX errors */ + u64 rx_bd_errors; + u64 rx_bd_overrun; + u64 rx_bd_bad_packet; + u64 rx_bd_runt_packet; + u64 rx_bd_short_event; + u64 rx_bd_alignment_error; + u64 rx_bd_bad_fcs; + u64 rx_bd_packet_too_long; + u64 rx_bd_out_of_range; + u64 rx_bd_in_range; + /* EMAC IRQ reported RX errors */ + u64 rx_parity; + u64 rx_fifo_overrun; + u64 rx_overrun; + u64 rx_bad_packet; + u64 rx_runt_packet; + u64 rx_short_event; + u64 rx_alignment_error; + u64 rx_bad_fcs; + u64 rx_packet_too_long; + u64 rx_out_of_range; + u64 rx_in_range; + + /* Software TX Errors */ + u64 tx_dropped; + /* BD reported TX errors */ + u64 tx_bd_errors; + u64 tx_bd_bad_fcs; + u64 tx_bd_carrier_loss; + u64 tx_bd_excessive_deferral; + u64 tx_bd_excessive_collisions; + u64 tx_bd_late_collision; + u64 tx_bd_multple_collisions; + u64 tx_bd_single_collision; + u64 tx_bd_underrun; + u64 tx_bd_sqe; + /* EMAC IRQ reported TX errors */ + u64 tx_parity; + u64 tx_underrun; + u64 tx_sqe; + u64 tx_errors; +}; + +#define EMAC_ETHTOOL_STATS_COUNT ((sizeof(struct emac_stats) + \ + sizeof(struct emac_error_stats)) \ + / sizeof(u64)) + +struct emac_instance { + struct net_device *ndev; + struct resource rsrc_regs; + struct emac_regs __iomem *emacp; + struct of_device *ofdev; + struct device_node **blist; /* bootlist entry */ + + /* MAL linkage */ + u32 mal_ph; + struct of_device *mal_dev; + u32 mal_rx_chan; + u32 mal_tx_chan; + struct mal_instance *mal; + struct mal_commac commac; + + /* PHY infos */ + u32 phy_mode; + u32 phy_map; + u32 phy_address; + u32 phy_feat_exc; + struct mii_phy phy; + struct mutex link_lock; + struct delayed_work link_work; + int link_polling; + + /* Shared MDIO if any */ + u32 mdio_ph; + struct of_device *mdio_dev; + struct emac_instance *mdio_instance; + struct mutex mdio_lock; + + /* ZMII infos if any */ + u32 zmii_ph; + u32 zmii_port; + struct of_device *zmii_dev; + + /* RGMII infos if any */ + u32 rgmii_ph; + u32 rgmii_port; + struct of_device *rgmii_dev; + + /* TAH infos if any */ + u32 tah_ph; + u32 tah_port; + struct of_device *tah_dev; + + /* IRQs */ + int wol_irq; + int emac_irq; + + /* OPB bus frequency in Mhz */ + u32 opb_bus_freq; + + /* Cell index within an ASIC (for clk mgmnt) */ + u32 cell_index; + + /* Max supported MTU */ + u32 max_mtu; + + /* Feature bits (from probe table) */ + unsigned int features; + + /* Tx and Rx fifo sizes & other infos in bytes */ + u32 tx_fifo_size; + u32 tx_fifo_size_gige; + u32 rx_fifo_size; + u32 rx_fifo_size_gige; + u32 fifo_entry_size; + u32 mal_burst_size; /* move to MAL ? */ + + /* Descriptor management + */ + struct mal_descriptor *tx_desc; + int tx_cnt; + int tx_slot; + int ack_slot; + + struct mal_descriptor *rx_desc; + int rx_slot; + struct sk_buff *rx_sg_skb; /* 1 */ + int rx_skb_size; + int rx_sync_size; + + struct sk_buff *tx_skb[NUM_TX_BUFF]; + struct sk_buff *rx_skb[NUM_RX_BUFF]; + + /* Stats + */ + struct emac_error_stats estats; + struct net_device_stats nstats; + struct emac_stats stats; + + /* Misc + */ + int reset_failed; + int stop_timeout; /* in us */ + int no_mcast; + int mcast_pending; + struct work_struct reset_work; + spinlock_t lock; +}; + +/* + * Features of various EMAC implementations + */ + +/* + * No flow control on 40x according to the original driver + */ +#define EMAC_FTR_NO_FLOW_CONTROL_40x 0x00000001 +/* + * Cell is an EMAC4 + */ +#define EMAC_FTR_EMAC4 0x00000002 +/* + * For the 440SPe, AMCC inexplicably changed the polarity of + * the "operation complete" bit in the MII control register. + */ +#define EMAC_FTR_STACR_OC_INVERT 0x00000004 +/* + * Set if we have a TAH. + */ +#define EMAC_FTR_HAS_TAH 0x00000008 +/* + * Set if we have a ZMII. + */ +#define EMAC_FTR_HAS_ZMII 0x00000010 +/* + * Set if we have a RGMII. + */ +#define EMAC_FTR_HAS_RGMII 0x00000020 +/* + * Set if we have axon-type STACR + */ +#define EMAC_FTR_HAS_AXON_STACR 0x00000040 + + +/* Right now, we don't quite handle the always/possible masks on the + * most optimal way as we don't have a way to say something like + * always EMAC4. Patches welcome. + */ +enum { + EMAC_FTRS_ALWAYS = 0, + + EMAC_FTRS_POSSIBLE = +#ifdef CONFIG_IBM_NEW_EMAC_EMAC4 + EMAC_FTR_EMAC4 | EMAC_FTR_HAS_AXON_STACR | + EMAC_FTR_STACR_OC_INVERT | +#endif +#ifdef CONFIG_IBM_NEW_EMAC_TAH + EMAC_FTR_HAS_TAH | +#endif +#ifdef CONFIG_IBM_NEW_EMAC_ZMII + EMAC_FTR_HAS_ZMII | +#endif +#ifdef CONFIG_IBM_NEW_EMAC_RGMII + EMAC_FTR_HAS_RGMII | +#endif + 0, +}; + +static inline int emac_has_feature(struct emac_instance *dev, + unsigned long feature) +{ + return (EMAC_FTRS_ALWAYS & feature) || + (EMAC_FTRS_POSSIBLE & dev->features & feature); +} + + +/* Ethtool get_regs complex data. + * We want to get not just EMAC registers, but also MAL, ZMII, RGMII, TAH + * when available. + * + * Returned BLOB consists of the ibm_emac_ethtool_regs_hdr, + * MAL registers, EMAC registers and optional ZMII, RGMII, TAH registers. + * Each register component is preceded with emac_ethtool_regs_subhdr. + * Order of the optional headers follows their relative bit posititions + * in emac_ethtool_regs_hdr.components + */ +#define EMAC_ETHTOOL_REGS_ZMII 0x00000001 +#define EMAC_ETHTOOL_REGS_RGMII 0x00000002 +#define EMAC_ETHTOOL_REGS_TAH 0x00000004 + +struct emac_ethtool_regs_hdr { + u32 components; +}; + +struct emac_ethtool_regs_subhdr { + u32 version; + u32 index; +}; + +#endif /* __IBM_NEWEMAC_CORE_H */ diff --git a/drivers/net/ibm_newemac/debug.c b/drivers/net/ibm_newemac/debug.c new file mode 100644 index 00000000000..170524ee0f1 --- /dev/null +++ b/drivers/net/ibm_newemac/debug.c @@ -0,0 +1,238 @@ +/* + * drivers/net/ibm_newemac/debug.c + * + * Driver for PowerPC 4xx on-chip ethernet controller, debug print routines. + * + * Copyright (c) 2004, 2005 Zultys Technologies + * Eugene Surovegin or + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#include +#include +#include +#include +#include +#include + +#include "core.h" + +static spinlock_t emac_dbg_lock = SPIN_LOCK_UNLOCKED; + +static void emac_desc_dump(struct emac_instance *p) +{ + int i; + printk("** EMAC %s TX BDs **\n" + " tx_cnt = %d tx_slot = %d ack_slot = %d\n", + p->ofdev->node->full_name, + p->tx_cnt, p->tx_slot, p->ack_slot); + for (i = 0; i < NUM_TX_BUFF / 2; ++i) + printk + ("bd[%2d] 0x%08x %c 0x%04x %4u - bd[%2d] 0x%08x %c 0x%04x %4u\n", + i, p->tx_desc[i].data_ptr, p->tx_skb[i] ? 'V' : ' ', + p->tx_desc[i].ctrl, p->tx_desc[i].data_len, + NUM_TX_BUFF / 2 + i, + p->tx_desc[NUM_TX_BUFF / 2 + i].data_ptr, + p->tx_skb[NUM_TX_BUFF / 2 + i] ? 'V' : ' ', + p->tx_desc[NUM_TX_BUFF / 2 + i].ctrl, + p->tx_desc[NUM_TX_BUFF / 2 + i].data_len); + + printk("** EMAC %s RX BDs **\n" + " rx_slot = %d flags = 0x%lx rx_skb_size = %d rx_sync_size = %d\n" + " rx_sg_skb = 0x%p\n", + p->ofdev->node->full_name, + p->rx_slot, p->commac.flags, p->rx_skb_size, + p->rx_sync_size, p->rx_sg_skb); + for (i = 0; i < NUM_RX_BUFF / 2; ++i) + printk + ("bd[%2d] 0x%08x %c 0x%04x %4u - bd[%2d] 0x%08x %c 0x%04x %4u\n", + i, p->rx_desc[i].data_ptr, p->rx_skb[i] ? 'V' : ' ', + p->rx_desc[i].ctrl, p->rx_desc[i].data_len, + NUM_RX_BUFF / 2 + i, + p->rx_desc[NUM_RX_BUFF / 2 + i].data_ptr, + p->rx_skb[NUM_RX_BUFF / 2 + i] ? 'V' : ' ', + p->rx_desc[NUM_RX_BUFF / 2 + i].ctrl, + p->rx_desc[NUM_RX_BUFF / 2 + i].data_len); +} + +static void emac_mac_dump(struct emac_instance *dev) +{ + struct emac_regs __iomem *p = dev->emacp; + + printk("** EMAC %s registers **\n" + "MR0 = 0x%08x MR1 = 0x%08x TMR0 = 0x%08x TMR1 = 0x%08x\n" + "RMR = 0x%08x ISR = 0x%08x ISER = 0x%08x\n" + "IAR = %04x%08x VTPID = 0x%04x VTCI = 0x%04x\n" + "IAHT: 0x%04x 0x%04x 0x%04x 0x%04x " + "GAHT: 0x%04x 0x%04x 0x%04x 0x%04x\n" + "LSA = %04x%08x IPGVR = 0x%04x\n" + "STACR = 0x%08x TRTR = 0x%08x RWMR = 0x%08x\n" + "OCTX = 0x%08x OCRX = 0x%08x IPCR = 0x%08x\n", + dev->ofdev->node->full_name, in_be32(&p->mr0), in_be32(&p->mr1), + in_be32(&p->tmr0), in_be32(&p->tmr1), + in_be32(&p->rmr), in_be32(&p->isr), in_be32(&p->iser), + in_be32(&p->iahr), in_be32(&p->ialr), in_be32(&p->vtpid), + in_be32(&p->vtci), + in_be32(&p->iaht1), in_be32(&p->iaht2), in_be32(&p->iaht3), + in_be32(&p->iaht4), + in_be32(&p->gaht1), in_be32(&p->gaht2), in_be32(&p->gaht3), + in_be32(&p->gaht4), + in_be32(&p->lsah), in_be32(&p->lsal), in_be32(&p->ipgvr), + in_be32(&p->stacr), in_be32(&p->trtr), in_be32(&p->rwmr), + in_be32(&p->octx), in_be32(&p->ocrx), in_be32(&p->ipcr) + ); + + emac_desc_dump(dev); +} + +static void emac_mal_dump(struct mal_instance *mal) +{ + int i; + + printk("** MAL %s Registers **\n" + "CFG = 0x%08x ESR = 0x%08x IER = 0x%08x\n" + "TX|CASR = 0x%08x CARR = 0x%08x EOBISR = 0x%08x DEIR = 0x%08x\n" + "RX|CASR = 0x%08x CARR = 0x%08x EOBISR = 0x%08x DEIR = 0x%08x\n", + mal->ofdev->node->full_name, + get_mal_dcrn(mal, MAL_CFG), get_mal_dcrn(mal, MAL_ESR), + get_mal_dcrn(mal, MAL_IER), + get_mal_dcrn(mal, MAL_TXCASR), get_mal_dcrn(mal, MAL_TXCARR), + get_mal_dcrn(mal, MAL_TXEOBISR), get_mal_dcrn(mal, MAL_TXDEIR), + get_mal_dcrn(mal, MAL_RXCASR), get_mal_dcrn(mal, MAL_RXCARR), + get_mal_dcrn(mal, MAL_RXEOBISR), get_mal_dcrn(mal, MAL_RXDEIR) + ); + + printk("TX|"); + for (i = 0; i < mal->num_tx_chans; ++i) { + if (i && !(i % 4)) + printk("\n "); + printk("CTP%d = 0x%08x ", i, get_mal_dcrn(mal, MAL_TXCTPR(i))); + } + printk("\nRX|"); + for (i = 0; i < mal->num_rx_chans; ++i) { + if (i && !(i % 4)) + printk("\n "); + printk("CTP%d = 0x%08x ", i, get_mal_dcrn(mal, MAL_RXCTPR(i))); + } + printk("\n "); + for (i = 0; i < mal->num_rx_chans; ++i) { + u32 r = get_mal_dcrn(mal, MAL_RCBS(i)); + if (i && !(i % 3)) + printk("\n "); + printk("RCBS%d = 0x%08x (%d) ", i, r, r * 16); + } + printk("\n"); +} + +static struct emac_instance *__emacs[4]; +static struct mal_instance *__mals[1]; + +void emac_dbg_register(struct emac_instance *dev) +{ + unsigned long flags; + int i; + + spin_lock_irqsave(&emac_dbg_lock, flags); + for (i = 0; i < ARRAY_SIZE(__emacs); i++) + if (__emacs[i] == NULL) { + __emacs[i] = dev; + break; + } + spin_unlock_irqrestore(&emac_dbg_lock, flags); +} + +void emac_dbg_unregister(struct emac_instance *dev) +{ + unsigned long flags; + int i; + + spin_lock_irqsave(&emac_dbg_lock, flags); + for (i = 0; i < ARRAY_SIZE(__emacs); i++) + if (__emacs[i] == dev) { + __emacs[i] = NULL; + break; + } + spin_unlock_irqrestore(&emac_dbg_lock, flags); +} + +void mal_dbg_register(struct mal_instance *mal) +{ + unsigned long flags; + int i; + + spin_lock_irqsave(&emac_dbg_lock, flags); + for (i = 0; i < ARRAY_SIZE(__mals); i++) + if (__mals[i] == NULL) { + __mals[i] = mal; + break; + } + spin_unlock_irqrestore(&emac_dbg_lock, flags); +} + +void mal_dbg_unregister(struct mal_instance *mal) +{ + unsigned long flags; + int i; + + spin_lock_irqsave(&emac_dbg_lock, flags); + for (i = 0; i < ARRAY_SIZE(__mals); i++) + if (__mals[i] == mal) { + __mals[i] = NULL; + break; + } + spin_unlock_irqrestore(&emac_dbg_lock, flags); +} + +void emac_dbg_dump_all(void) +{ + unsigned int i; + unsigned long flags; + + spin_lock_irqsave(&emac_dbg_lock, flags); + + for (i = 0; i < ARRAY_SIZE(__mals); ++i) + if (__mals[i]) + emac_mal_dump(__mals[i]); + + for (i = 0; i < ARRAY_SIZE(__emacs); ++i) + if (__emacs[i]) + emac_mac_dump(__emacs[i]); + + spin_unlock_irqrestore(&emac_dbg_lock, flags); +} + +#if defined(CONFIG_MAGIC_SYSRQ) +static void emac_sysrq_handler(int key, struct tty_struct *tty) +{ + emac_dbg_dump_all(); +} + +static struct sysrq_key_op emac_sysrq_op = { + .handler = emac_sysrq_handler, + .help_msg = "emaC", + .action_msg = "Show EMAC(s) status", +}; + +int __init emac_init_debug(void) +{ + return register_sysrq_key('c', &emac_sysrq_op); +} + +void __exit emac_fini_debug(void) +{ + unregister_sysrq_key('c', &emac_sysrq_op); +} + +#else +int __init emac_init_debug(void) +{ + return 0; +} +void __exit emac_fini_debug(void) +{ +} +#endif /* CONFIG_MAGIC_SYSRQ */ diff --git a/drivers/net/ibm_newemac/debug.h b/drivers/net/ibm_newemac/debug.h new file mode 100644 index 00000000000..1dd2dcbc157 --- /dev/null +++ b/drivers/net/ibm_newemac/debug.h @@ -0,0 +1,78 @@ +/* + * drivers/net/ibm_newemac/debug.h + * + * Driver for PowerPC 4xx on-chip ethernet controller, debug print routines. + * + * Copyright (c) 2004, 2005 Zultys Technologies + * Eugene Surovegin or + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#ifndef __IBM_NEWEMAC_DEBUG_H +#define __IBM_NEWEMAC_DEBUG_H + +#include + +#include "core.h" + +#if defined(CONFIG_IBM_NEW_EMAC_DEBUG) + +struct emac_instance; +struct mal_instance; + +extern void emac_dbg_register(struct emac_instance *dev); +extern void emac_dbg_unregister(struct emac_instance *dev); +extern void mal_dbg_register(struct mal_instance *mal); +extern void mal_dbg_unregister(struct mal_instance *mal); +extern int emac_init_debug(void) __init; +extern void emac_fini_debug(void) __exit; +extern void emac_dbg_dump_all(void); + +# define DBG_LEVEL 1 + +#else + +# define emac_dbg_register(x) do { } while(0) +# define emac_dbg_unregister(x) do { } while(0) +# define mal_dbg_register(x) do { } while(0) +# define mal_dbg_unregister(x) do { } while(0) +# define emac_init_debug() do { } while(0) +# define emac_fini_debug() do { } while(0) +# define emac_dbg_dump_all() do { } while(0) + +# define DBG_LEVEL 0 + +#endif + +#define EMAC_DBG(dev, name, fmt, arg...) \ + printk(KERN_DEBUG #name "%s: " fmt, dev->ofdev->node->full_name, ## arg) + +#if DBG_LEVEL > 0 +# define DBG(d,f,x...) EMAC_DBG(d, emac, f, ##x) +# define MAL_DBG(d,f,x...) EMAC_DBG(d, mal, f, ##x) +# define ZMII_DBG(d,f,x...) EMAC_DBG(d, zmii, f, ##x) +# define RGMII_DBG(d,f,x...) EMAC_DBG(d, rgmii, f, ##x) +# define NL "\n" +#else +# define DBG(f,x...) ((void)0) +# define MAL_DBG(d,f,x...) ((void)0) +# define ZMII_DBG(d,f,x...) ((void)0) +# define RGMII_DBG(d,f,x...) ((void)0) +#endif +#if DBG_LEVEL > 1 +# define DBG2(d,f,x...) DBG(d,f, ##x) +# define MAL_DBG2(d,f,x...) MAL_DBG(d,f, ##x) +# define ZMII_DBG2(d,f,x...) ZMII_DBG(d,f, ##x) +# define RGMII_DBG2(d,f,x...) RGMII_DBG(d,f, ##x) +#else +# define DBG2(f,x...) ((void)0) +# define MAL_DBG2(d,f,x...) ((void)0) +# define ZMII_DBG2(d,f,x...) ((void)0) +# define RGMII_DBG2(d,f,x...) ((void)0) +#endif + +#endif /* __IBM_NEWEMAC_DEBUG_H */ diff --git a/drivers/net/ibm_newemac/emac.h b/drivers/net/ibm_newemac/emac.h new file mode 100644 index 00000000000..bef92efeead --- /dev/null +++ b/drivers/net/ibm_newemac/emac.h @@ -0,0 +1,268 @@ +/* + * drivers/net/ibm_newemac/emac.h + * + * Register definitions for PowerPC 4xx on-chip ethernet contoller + * + * Copyright (c) 2004, 2005 Zultys Technologies. + * Eugene Surovegin or + * + * Based on original work by + * Matt Porter + * Armin Kuster + * Copyright 2002-2004 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#ifndef __IBM_NEWEMAC_H +#define __IBM_NEWEMAC_H + +#include + +/* EMAC registers Write Access rules */ +struct emac_regs { + u32 mr0; /* special */ + u32 mr1; /* Reset */ + u32 tmr0; /* special */ + u32 tmr1; /* special */ + u32 rmr; /* Reset */ + u32 isr; /* Always */ + u32 iser; /* Reset */ + u32 iahr; /* Reset, R, T */ + u32 ialr; /* Reset, R, T */ + u32 vtpid; /* Reset, R, T */ + u32 vtci; /* Reset, R, T */ + u32 ptr; /* Reset, T */ + u32 iaht1; /* Reset, R */ + u32 iaht2; /* Reset, R */ + u32 iaht3; /* Reset, R */ + u32 iaht4; /* Reset, R */ + u32 gaht1; /* Reset, R */ + u32 gaht2; /* Reset, R */ + u32 gaht3; /* Reset, R */ + u32 gaht4; /* Reset, R */ + u32 lsah; + u32 lsal; + u32 ipgvr; /* Reset, T */ + u32 stacr; /* special */ + u32 trtr; /* special */ + u32 rwmr; /* Reset */ + u32 octx; + u32 ocrx; + u32 ipcr; +}; + +/* + * PHY mode settings (EMAC <-> ZMII/RGMII bridge <-> PHY) + */ +#define PHY_MODE_NA 0 +#define PHY_MODE_MII 1 +#define PHY_MODE_RMII 2 +#define PHY_MODE_SMII 3 +#define PHY_MODE_RGMII 4 +#define PHY_MODE_TBI 5 +#define PHY_MODE_GMII 6 +#define PHY_MODE_RTBI 7 +#define PHY_MODE_SGMII 8 + + +#define EMAC_ETHTOOL_REGS_VER 0 +#define EMAC_ETHTOOL_REGS_SIZE (sizeof(struct emac_regs) - sizeof(u32)) +#define EMAC4_ETHTOOL_REGS_VER 1 +#define EMAC4_ETHTOOL_REGS_SIZE sizeof(struct emac_regs) + +/* EMACx_MR0 */ +#define EMAC_MR0_RXI 0x80000000 +#define EMAC_MR0_TXI 0x40000000 +#define EMAC_MR0_SRST 0x20000000 +#define EMAC_MR0_TXE 0x10000000 +#define EMAC_MR0_RXE 0x08000000 +#define EMAC_MR0_WKE 0x04000000 + +/* EMACx_MR1 */ +#define EMAC_MR1_FDE 0x80000000 +#define EMAC_MR1_ILE 0x40000000 +#define EMAC_MR1_VLE 0x20000000 +#define EMAC_MR1_EIFC 0x10000000 +#define EMAC_MR1_APP 0x08000000 +#define EMAC_MR1_IST 0x01000000 + +#define EMAC_MR1_MF_MASK 0x00c00000 +#define EMAC_MR1_MF_10 0x00000000 +#define EMAC_MR1_MF_100 0x00400000 +#define EMAC_MR1_MF_1000 0x00800000 +#define EMAC_MR1_MF_1000GPCS 0x00c00000 +#define EMAC_MR1_MF_IPPA(id) (((id) & 0x1f) << 6) + +#define EMAC_MR1_RFS_4K 0x00300000 +#define EMAC_MR1_RFS_16K 0x00000000 +#define EMAC_MR1_TFS_2K 0x00080000 +#define EMAC_MR1_TR0_MULT 0x00008000 +#define EMAC_MR1_JPSM 0x00000000 +#define EMAC_MR1_MWSW_001 0x00000000 +#define EMAC_MR1_BASE(opb) (EMAC_MR1_TFS_2K | EMAC_MR1_TR0_MULT) + + +#define EMAC4_MR1_RFS_2K 0x00100000 +#define EMAC4_MR1_RFS_4K 0x00180000 +#define EMAC4_MR1_RFS_16K 0x00280000 +#define EMAC4_MR1_TFS_2K 0x00020000 +#define EMAC4_MR1_TFS_4K 0x00030000 +#define EMAC4_MR1_TR 0x00008000 +#define EMAC4_MR1_MWSW_001 0x00001000 +#define EMAC4_MR1_JPSM 0x00000800 +#define EMAC4_MR1_OBCI_MASK 0x00000038 +#define EMAC4_MR1_OBCI_50 0x00000000 +#define EMAC4_MR1_OBCI_66 0x00000008 +#define EMAC4_MR1_OBCI_83 0x00000010 +#define EMAC4_MR1_OBCI_100 0x00000018 +#define EMAC4_MR1_OBCI_100P 0x00000020 +#define EMAC4_MR1_OBCI(freq) ((freq) <= 50 ? EMAC4_MR1_OBCI_50 : \ + (freq) <= 66 ? EMAC4_MR1_OBCI_66 : \ + (freq) <= 83 ? EMAC4_MR1_OBCI_83 : \ + (freq) <= 100 ? EMAC4_MR1_OBCI_100 : \ + EMAC4_MR1_OBCI_100P) + +/* EMACx_TMR0 */ +#define EMAC_TMR0_GNP 0x80000000 +#define EMAC_TMR0_DEFAULT 0x00000000 +#define EMAC4_TMR0_TFAE_2_32 0x00000001 +#define EMAC4_TMR0_TFAE_4_64 0x00000002 +#define EMAC4_TMR0_TFAE_8_128 0x00000003 +#define EMAC4_TMR0_TFAE_16_256 0x00000004 +#define EMAC4_TMR0_TFAE_32_512 0x00000005 +#define EMAC4_TMR0_TFAE_64_1024 0x00000006 +#define EMAC4_TMR0_TFAE_128_2048 0x00000007 +#define EMAC4_TMR0_DEFAULT EMAC4_TMR0_TFAE_2_32 +#define EMAC_TMR0_XMIT (EMAC_TMR0_GNP | EMAC_TMR0_DEFAULT) +#define EMAC4_TMR0_XMIT (EMAC_TMR0_GNP | EMAC4_TMR0_DEFAULT) + +/* EMACx_TMR1 */ + +#define EMAC_TMR1(l,h) (((l) << 27) | (((h) & 0xff) << 16)) +#define EMAC4_TMR1(l,h) (((l) << 27) | (((h) & 0x3ff) << 14)) + +/* EMACx_RMR */ +#define EMAC_RMR_SP 0x80000000 +#define EMAC_RMR_SFCS 0x40000000 +#define EMAC_RMR_RRP 0x20000000 +#define EMAC_RMR_RFP 0x10000000 +#define EMAC_RMR_ROP 0x08000000 +#define EMAC_RMR_RPIR 0x04000000 +#define EMAC_RMR_PPP 0x02000000 +#define EMAC_RMR_PME 0x01000000 +#define EMAC_RMR_PMME 0x00800000 +#define EMAC_RMR_IAE 0x00400000 +#define EMAC_RMR_MIAE 0x00200000 +#define EMAC_RMR_BAE 0x00100000 +#define EMAC_RMR_MAE 0x00080000 +#define EMAC_RMR_BASE 0x00000000 +#define EMAC4_RMR_RFAF_2_32 0x00000001 +#define EMAC4_RMR_RFAF_4_64 0x00000002 +#define EMAC4_RMR_RFAF_8_128 0x00000003 +#define EMAC4_RMR_RFAF_16_256 0x00000004 +#define EMAC4_RMR_RFAF_32_512 0x00000005 +#define EMAC4_RMR_RFAF_64_1024 0x00000006 +#define EMAC4_RMR_RFAF_128_2048 0x00000007 +#define EMAC4_RMR_BASE EMAC4_RMR_RFAF_128_2048 + +/* EMACx_ISR & EMACx_ISER */ +#define EMAC4_ISR_TXPE 0x20000000 +#define EMAC4_ISR_RXPE 0x10000000 +#define EMAC4_ISR_TXUE 0x08000000 +#define EMAC4_ISR_RXOE 0x04000000 +#define EMAC_ISR_OVR 0x02000000 +#define EMAC_ISR_PP 0x01000000 +#define EMAC_ISR_BP 0x00800000 +#define EMAC_ISR_RP 0x00400000 +#define EMAC_ISR_SE 0x00200000 +#define EMAC_ISR_ALE 0x00100000 +#define EMAC_ISR_BFCS 0x00080000 +#define EMAC_ISR_PTLE 0x00040000 +#define EMAC_ISR_ORE 0x00020000 +#define EMAC_ISR_IRE 0x00010000 +#define EMAC_ISR_SQE 0x00000080 +#define EMAC_ISR_TE 0x00000040 +#define EMAC_ISR_MOS 0x00000002 +#define EMAC_ISR_MOF 0x00000001 + +/* EMACx_STACR */ +#define EMAC_STACR_PHYD_MASK 0xffff +#define EMAC_STACR_PHYD_SHIFT 16 +#define EMAC_STACR_OC 0x00008000 +#define EMAC_STACR_PHYE 0x00004000 +#define EMAC_STACR_STAC_MASK 0x00003000 +#define EMAC_STACR_STAC_READ 0x00001000 +#define EMAC_STACR_STAC_WRITE 0x00002000 +#define EMAC_STACR_OPBC_MASK 0x00000C00 +#define EMAC_STACR_OPBC_50 0x00000000 +#define EMAC_STACR_OPBC_66 0x00000400 +#define EMAC_STACR_OPBC_83 0x00000800 +#define EMAC_STACR_OPBC_100 0x00000C00 +#define EMAC_STACR_OPBC(freq) ((freq) <= 50 ? EMAC_STACR_OPBC_50 : \ + (freq) <= 66 ? EMAC_STACR_OPBC_66 : \ + (freq) <= 83 ? EMAC_STACR_OPBC_83 : EMAC_STACR_OPBC_100) +#define EMAC_STACR_BASE(opb) EMAC_STACR_OPBC(opb) +#define EMAC4_STACR_BASE(opb) 0x00000000 +#define EMAC_STACR_PCDA_MASK 0x1f +#define EMAC_STACR_PCDA_SHIFT 5 +#define EMAC_STACR_PRA_MASK 0x1f +#define EMACX_STACR_STAC_MASK 0x00003800 +#define EMACX_STACR_STAC_READ 0x00001000 +#define EMACX_STACR_STAC_WRITE 0x00000800 +#define EMACX_STACR_STAC_IND_ADDR 0x00002000 +#define EMACX_STACR_STAC_IND_READ 0x00003800 +#define EMACX_STACR_STAC_IND_READINC 0x00003000 +#define EMACX_STACR_STAC_IND_WRITE 0x00002800 + + +/* EMACx_TRTR */ +#define EMAC_TRTR_SHIFT_EMAC4 27 +#define EMAC_TRTR_SHIFT 24 + +/* EMAC specific TX descriptor control fields (write access) */ +#define EMAC_TX_CTRL_GFCS 0x0200 +#define EMAC_TX_CTRL_GP 0x0100 +#define EMAC_TX_CTRL_ISA 0x0080 +#define EMAC_TX_CTRL_RSA 0x0040 +#define EMAC_TX_CTRL_IVT 0x0020 +#define EMAC_TX_CTRL_RVT 0x0010 +#define EMAC_TX_CTRL_TAH_CSUM 0x000e + +/* EMAC specific TX descriptor status fields (read access) */ +#define EMAC_TX_ST_BFCS 0x0200 +#define EMAC_TX_ST_LCS 0x0080 +#define EMAC_TX_ST_ED 0x0040 +#define EMAC_TX_ST_EC 0x0020 +#define EMAC_TX_ST_LC 0x0010 +#define EMAC_TX_ST_MC 0x0008 +#define EMAC_TX_ST_SC 0x0004 +#define EMAC_TX_ST_UR 0x0002 +#define EMAC_TX_ST_SQE 0x0001 +#define EMAC_IS_BAD_TX (EMAC_TX_ST_LCS | EMAC_TX_ST_ED | \ + EMAC_TX_ST_EC | EMAC_TX_ST_LC | \ + EMAC_TX_ST_MC | EMAC_TX_ST_UR) +#define EMAC_IS_BAD_TX_TAH (EMAC_TX_ST_LCS | EMAC_TX_ST_ED | \ + EMAC_TX_ST_EC | EMAC_TX_ST_LC) + +/* EMAC specific RX descriptor status fields (read access) */ +#define EMAC_RX_ST_OE 0x0200 +#define EMAC_RX_ST_PP 0x0100 +#define EMAC_RX_ST_BP 0x0080 +#define EMAC_RX_ST_RP 0x0040 +#define EMAC_RX_ST_SE 0x0020 +#define EMAC_RX_ST_AE 0x0010 +#define EMAC_RX_ST_BFCS 0x0008 +#define EMAC_RX_ST_PTL 0x0004 +#define EMAC_RX_ST_ORE 0x0002 +#define EMAC_RX_ST_IRE 0x0001 +#define EMAC_RX_TAH_BAD_CSUM 0x0003 +#define EMAC_BAD_RX_MASK (EMAC_RX_ST_OE | EMAC_RX_ST_BP | \ + EMAC_RX_ST_RP | EMAC_RX_ST_SE | \ + EMAC_RX_ST_AE | EMAC_RX_ST_BFCS | \ + EMAC_RX_ST_PTL | EMAC_RX_ST_ORE | \ + EMAC_RX_ST_IRE ) +#endif /* __IBM_NEWEMAC_H */ diff --git a/drivers/net/ibm_newemac/mal.c b/drivers/net/ibm_newemac/mal.c new file mode 100644 index 00000000000..c4335b7d308 --- /dev/null +++ b/drivers/net/ibm_newemac/mal.c @@ -0,0 +1,728 @@ +/* + * drivers/net/ibm_newemac/mal.c + * + * Memory Access Layer (MAL) support + * + * Copyright (c) 2004, 2005 Zultys Technologies. + * Eugene Surovegin or + * + * Based on original work by + * Benjamin Herrenschmidt , + * David Gibson , + * + * Armin Kuster + * Copyright 2002 MontaVista Softare Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include + +#include "core.h" + +static int mal_count; + +int __devinit mal_register_commac(struct mal_instance *mal, + struct mal_commac *commac) +{ + unsigned long flags; + + spin_lock_irqsave(&mal->lock, flags); + + MAL_DBG(mal, "reg(%08x, %08x)" NL, + commac->tx_chan_mask, commac->rx_chan_mask); + + /* Don't let multiple commacs claim the same channel(s) */ + if ((mal->tx_chan_mask & commac->tx_chan_mask) || + (mal->rx_chan_mask & commac->rx_chan_mask)) { + spin_unlock_irqrestore(&mal->lock, flags); + printk(KERN_WARNING "mal%d: COMMAC channels conflict!\n", + mal->index); + return -EBUSY; + } + + mal->tx_chan_mask |= commac->tx_chan_mask; + mal->rx_chan_mask |= commac->rx_chan_mask; + list_add(&commac->list, &mal->list); + + spin_unlock_irqrestore(&mal->lock, flags); + + return 0; +} + +void __devexit mal_unregister_commac(struct mal_instance *mal, + struct mal_commac *commac) +{ + unsigned long flags; + + spin_lock_irqsave(&mal->lock, flags); + + MAL_DBG(mal, "unreg(%08x, %08x)" NL, + commac->tx_chan_mask, commac->rx_chan_mask); + + mal->tx_chan_mask &= ~commac->tx_chan_mask; + mal->rx_chan_mask &= ~commac->rx_chan_mask; + list_del_init(&commac->list); + + spin_unlock_irqrestore(&mal->lock, flags); +} + +int mal_set_rcbs(struct mal_instance *mal, int channel, unsigned long size) +{ + BUG_ON(channel < 0 || channel >= mal->num_rx_chans || + size > MAL_MAX_RX_SIZE); + + MAL_DBG(mal, "set_rbcs(%d, %lu)" NL, channel, size); + + if (size & 0xf) { + printk(KERN_WARNING + "mal%d: incorrect RX size %lu for the channel %d\n", + mal->index, size, channel); + return -EINVAL; + } + + set_mal_dcrn(mal, MAL_RCBS(channel), size >> 4); + return 0; +} + +int mal_tx_bd_offset(struct mal_instance *mal, int channel) +{ + BUG_ON(channel < 0 || channel >= mal->num_tx_chans); + + return channel * NUM_TX_BUFF; +} + +int mal_rx_bd_offset(struct mal_instance *mal, int channel) +{ + BUG_ON(channel < 0 || channel >= mal->num_rx_chans); + return mal->num_tx_chans * NUM_TX_BUFF + channel * NUM_RX_BUFF; +} + +void mal_enable_tx_channel(struct mal_instance *mal, int channel) +{ + unsigned long flags; + + spin_lock_irqsave(&mal->lock, flags); + + MAL_DBG(mal, "enable_tx(%d)" NL, channel); + + set_mal_dcrn(mal, MAL_TXCASR, + get_mal_dcrn(mal, MAL_TXCASR) | MAL_CHAN_MASK(channel)); + + spin_unlock_irqrestore(&mal->lock, flags); +} + +void mal_disable_tx_channel(struct mal_instance *mal, int channel) +{ + set_mal_dcrn(mal, MAL_TXCARR, MAL_CHAN_MASK(channel)); + + MAL_DBG(mal, "disable_tx(%d)" NL, channel); +} + +void mal_enable_rx_channel(struct mal_instance *mal, int channel) +{ + unsigned long flags; + + spin_lock_irqsave(&mal->lock, flags); + + MAL_DBG(mal, "enable_rx(%d)" NL, channel); + + set_mal_dcrn(mal, MAL_RXCASR, + get_mal_dcrn(mal, MAL_RXCASR) | MAL_CHAN_MASK(channel)); + + spin_unlock_irqrestore(&mal->lock, flags); +} + +void mal_disable_rx_channel(struct mal_instance *mal, int channel) +{ + set_mal_dcrn(mal, MAL_RXCARR, MAL_CHAN_MASK(channel)); + + MAL_DBG(mal, "disable_rx(%d)" NL, channel); +} + +void mal_poll_add(struct mal_instance *mal, struct mal_commac *commac) +{ + unsigned long flags; + + spin_lock_irqsave(&mal->lock, flags); + + MAL_DBG(mal, "poll_add(%p)" NL, commac); + + /* starts disabled */ + set_bit(MAL_COMMAC_POLL_DISABLED, &commac->flags); + + list_add_tail(&commac->poll_list, &mal->poll_list); + + spin_unlock_irqrestore(&mal->lock, flags); +} + +void mal_poll_del(struct mal_instance *mal, struct mal_commac *commac) +{ + unsigned long flags; + + spin_lock_irqsave(&mal->lock, flags); + + MAL_DBG(mal, "poll_del(%p)" NL, commac); + + list_del(&commac->poll_list); + + spin_unlock_irqrestore(&mal->lock, flags); +} + +/* synchronized by mal_poll() */ +static inline void mal_enable_eob_irq(struct mal_instance *mal) +{ + MAL_DBG2(mal, "enable_irq" NL); + + // XXX might want to cache MAL_CFG as the DCR read can be slooooow + set_mal_dcrn(mal, MAL_CFG, get_mal_dcrn(mal, MAL_CFG) | MAL_CFG_EOPIE); +} + +/* synchronized by __LINK_STATE_RX_SCHED bit in ndev->state */ +static inline void mal_disable_eob_irq(struct mal_instance *mal) +{ + // XXX might want to cache MAL_CFG as the DCR read can be slooooow + set_mal_dcrn(mal, MAL_CFG, get_mal_dcrn(mal, MAL_CFG) & ~MAL_CFG_EOPIE); + + MAL_DBG2(mal, "disable_irq" NL); +} + +static irqreturn_t mal_serr(int irq, void *dev_instance) +{ + struct mal_instance *mal = dev_instance; + + u32 esr = get_mal_dcrn(mal, MAL_ESR); + + /* Clear the error status register */ + set_mal_dcrn(mal, MAL_ESR, esr); + + MAL_DBG(mal, "SERR %08x" NL, esr); + + if (esr & MAL_ESR_EVB) { + if (esr & MAL_ESR_DE) { + /* We ignore Descriptor error, + * TXDE or RXDE interrupt will be generated anyway. + */ + return IRQ_HANDLED; + } + + if (esr & MAL_ESR_PEIN) { + /* PLB error, it's probably buggy hardware or + * incorrect physical address in BD (i.e. bug) + */ + if (net_ratelimit()) + printk(KERN_ERR + "mal%d: system error, " + "PLB (ESR = 0x%08x)\n", + mal->index, esr); + return IRQ_HANDLED; + } + + /* OPB error, it's probably buggy hardware or incorrect + * EBC setup + */ + if (net_ratelimit()) + printk(KERN_ERR + "mal%d: system error, OPB (ESR = 0x%08x)\n", + mal->index, esr); + } + return IRQ_HANDLED; +} + +static inline void mal_schedule_poll(struct mal_instance *mal) +{ + if (likely(netif_rx_schedule_prep(&mal->poll_dev))) { + MAL_DBG2(mal, "schedule_poll" NL); + mal_disable_eob_irq(mal); + __netif_rx_schedule(&mal->poll_dev); + } else + MAL_DBG2(mal, "already in poll" NL); +} + +static irqreturn_t mal_txeob(int irq, void *dev_instance) +{ + struct mal_instance *mal = dev_instance; + + u32 r = get_mal_dcrn(mal, MAL_TXEOBISR); + + MAL_DBG2(mal, "txeob %08x" NL, r); + + mal_schedule_poll(mal); + set_mal_dcrn(mal, MAL_TXEOBISR, r); + + return IRQ_HANDLED; +} + +static irqreturn_t mal_rxeob(int irq, void *dev_instance) +{ + struct mal_instance *mal = dev_instance; + + u32 r = get_mal_dcrn(mal, MAL_RXEOBISR); + + MAL_DBG2(mal, "rxeob %08x" NL, r); + + mal_schedule_poll(mal); + set_mal_dcrn(mal, MAL_RXEOBISR, r); + + return IRQ_HANDLED; +} + +static irqreturn_t mal_txde(int irq, void *dev_instance) +{ + struct mal_instance *mal = dev_instance; + + u32 deir = get_mal_dcrn(mal, MAL_TXDEIR); + set_mal_dcrn(mal, MAL_TXDEIR, deir); + + MAL_DBG(mal, "txde %08x" NL, deir); + + if (net_ratelimit()) + printk(KERN_ERR + "mal%d: TX descriptor error (TXDEIR = 0x%08x)\n", + mal->index, deir); + + return IRQ_HANDLED; +} + +static irqreturn_t mal_rxde(int irq, void *dev_instance) +{ + struct mal_instance *mal = dev_instance; + struct list_head *l; + + u32 deir = get_mal_dcrn(mal, MAL_RXDEIR); + + MAL_DBG(mal, "rxde %08x" NL, deir); + + list_for_each(l, &mal->list) { + struct mal_commac *mc = list_entry(l, struct mal_commac, list); + if (deir & mc->rx_chan_mask) { + set_bit(MAL_COMMAC_RX_STOPPED, &mc->flags); + mc->ops->rxde(mc->dev); + } + } + + mal_schedule_poll(mal); + set_mal_dcrn(mal, MAL_RXDEIR, deir); + + return IRQ_HANDLED; +} + +void mal_poll_disable(struct mal_instance *mal, struct mal_commac *commac) +{ + /* Spinlock-type semantics: only one caller disable poll at a time */ + while (test_and_set_bit(MAL_COMMAC_POLL_DISABLED, &commac->flags)) + msleep(1); + + /* Synchronize with the MAL NAPI poller. */ + while (test_bit(__LINK_STATE_RX_SCHED, &mal->poll_dev.state)) + msleep(1); +} + +void mal_poll_enable(struct mal_instance *mal, struct mal_commac *commac) +{ + smp_wmb(); + clear_bit(MAL_COMMAC_POLL_DISABLED, &commac->flags); + + // XXX might want to kick a poll now... +} + +static int mal_poll(struct net_device *ndev, int *budget) +{ + struct mal_instance *mal = netdev_priv(ndev); + struct list_head *l; + int rx_work_limit = min(ndev->quota, *budget), received = 0, done; + unsigned long flags; + + MAL_DBG2(mal, "poll(%d) %d ->" NL, *budget, + rx_work_limit); + again: + /* Process TX skbs */ + list_for_each(l, &mal->poll_list) { + struct mal_commac *mc = + list_entry(l, struct mal_commac, poll_list); + mc->ops->poll_tx(mc->dev); + } + + /* Process RX skbs. + * + * We _might_ need something more smart here to enforce polling + * fairness. + */ + list_for_each(l, &mal->poll_list) { + struct mal_commac *mc = + list_entry(l, struct mal_commac, poll_list); + int n; + if (unlikely(test_bit(MAL_COMMAC_POLL_DISABLED, &mc->flags))) + continue; + n = mc->ops->poll_rx(mc->dev, rx_work_limit); + if (n) { + received += n; + rx_work_limit -= n; + if (rx_work_limit <= 0) { + done = 0; + // XXX What if this is the last one ? + goto more_work; + } + } + } + + /* We need to disable IRQs to protect from RXDE IRQ here */ + spin_lock_irqsave(&mal->lock, flags); + __netif_rx_complete(ndev); + mal_enable_eob_irq(mal); + spin_unlock_irqrestore(&mal->lock, flags); + + done = 1; + + /* Check for "rotting" packet(s) */ + list_for_each(l, &mal->poll_list) { + struct mal_commac *mc = + list_entry(l, struct mal_commac, poll_list); + if (unlikely(test_bit(MAL_COMMAC_POLL_DISABLED, &mc->flags))) + continue; + if (unlikely(mc->ops->peek_rx(mc->dev) || + test_bit(MAL_COMMAC_RX_STOPPED, &mc->flags))) { + MAL_DBG2(mal, "rotting packet" NL); + if (netif_rx_reschedule(ndev, received)) + mal_disable_eob_irq(mal); + else + MAL_DBG2(mal, "already in poll list" NL); + + if (rx_work_limit > 0) + goto again; + else + goto more_work; + } + mc->ops->poll_tx(mc->dev); + } + + more_work: + ndev->quota -= received; + *budget -= received; + + MAL_DBG2(mal, "poll() %d <- %d" NL, *budget, + done ? 0 : 1); + + return done ? 0 : 1; +} + +static void mal_reset(struct mal_instance *mal) +{ + int n = 10; + + MAL_DBG(mal, "reset" NL); + + set_mal_dcrn(mal, MAL_CFG, MAL_CFG_SR); + + /* Wait for reset to complete (1 system clock) */ + while ((get_mal_dcrn(mal, MAL_CFG) & MAL_CFG_SR) && n) + --n; + + if (unlikely(!n)) + printk(KERN_ERR "mal%d: reset timeout\n", mal->index); +} + +int mal_get_regs_len(struct mal_instance *mal) +{ + return sizeof(struct emac_ethtool_regs_subhdr) + + sizeof(struct mal_regs); +} + +void *mal_dump_regs(struct mal_instance *mal, void *buf) +{ + struct emac_ethtool_regs_subhdr *hdr = buf; + struct mal_regs *regs = (struct mal_regs *)(hdr + 1); + int i; + + hdr->version = mal->version; + hdr->index = mal->index; + + regs->tx_count = mal->num_tx_chans; + regs->rx_count = mal->num_rx_chans; + + regs->cfg = get_mal_dcrn(mal, MAL_CFG); + regs->esr = get_mal_dcrn(mal, MAL_ESR); + regs->ier = get_mal_dcrn(mal, MAL_IER); + regs->tx_casr = get_mal_dcrn(mal, MAL_TXCASR); + regs->tx_carr = get_mal_dcrn(mal, MAL_TXCARR); + regs->tx_eobisr = get_mal_dcrn(mal, MAL_TXEOBISR); + regs->tx_deir = get_mal_dcrn(mal, MAL_TXDEIR); + regs->rx_casr = get_mal_dcrn(mal, MAL_RXCASR); + regs->rx_carr = get_mal_dcrn(mal, MAL_RXCARR); + regs->rx_eobisr = get_mal_dcrn(mal, MAL_RXEOBISR); + regs->rx_deir = get_mal_dcrn(mal, MAL_RXDEIR); + + for (i = 0; i < regs->tx_count; ++i) + regs->tx_ctpr[i] = get_mal_dcrn(mal, MAL_TXCTPR(i)); + + for (i = 0; i < regs->rx_count; ++i) { + regs->rx_ctpr[i] = get_mal_dcrn(mal, MAL_RXCTPR(i)); + regs->rcbs[i] = get_mal_dcrn(mal, MAL_RCBS(i)); + } + return regs + 1; +} + +static int __devinit mal_probe(struct of_device *ofdev, + const struct of_device_id *match) +{ + struct mal_instance *mal; + int err = 0, i, bd_size; + int index = mal_count++; + const u32 *prop; + u32 cfg; + + mal = kzalloc(sizeof(struct mal_instance), GFP_KERNEL); + if (!mal) { + printk(KERN_ERR + "mal%d: out of memory allocating MAL structure!\n", + index); + return -ENOMEM; + } + mal->index = index; + mal->ofdev = ofdev; + mal->version = of_device_is_compatible(ofdev->node, "ibm,mcmal2") ? 2 : 1; + + MAL_DBG(mal, "probe" NL); + + prop = of_get_property(ofdev->node, "num-tx-chans", NULL); + if (prop == NULL) { + printk(KERN_ERR + "mal%d: can't find MAL num-tx-chans property!\n", + index); + err = -ENODEV; + goto fail; + } + mal->num_tx_chans = prop[0]; + + prop = of_get_property(ofdev->node, "num-rx-chans", NULL); + if (prop == NULL) { + printk(KERN_ERR + "mal%d: can't find MAL num-rx-chans property!\n", + index); + err = -ENODEV; + goto fail; + } + mal->num_rx_chans = prop[0]; + + mal->dcr_base = dcr_resource_start(ofdev->node, 0); + if (mal->dcr_base == 0) { + printk(KERN_ERR + "mal%d: can't find DCR resource!\n", index); + err = -ENODEV; + goto fail; + } + mal->dcr_host = dcr_map(ofdev->node, mal->dcr_base, 0x100); + if (!DCR_MAP_OK(mal->dcr_host)) { + printk(KERN_ERR + "mal%d: failed to map DCRs !\n", index); + err = -ENODEV; + goto fail; + } + + mal->txeob_irq = irq_of_parse_and_map(ofdev->node, 0); + mal->rxeob_irq = irq_of_parse_and_map(ofdev->node, 1); + mal->serr_irq = irq_of_parse_and_map(ofdev->node, 2); + mal->txde_irq = irq_of_parse_and_map(ofdev->node, 3); + mal->rxde_irq = irq_of_parse_and_map(ofdev->node, 4); + if (mal->txeob_irq == NO_IRQ || mal->rxeob_irq == NO_IRQ || + mal->serr_irq == NO_IRQ || mal->txde_irq == NO_IRQ || + mal->rxde_irq == NO_IRQ) { + printk(KERN_ERR + "mal%d: failed to map interrupts !\n", index); + err = -ENODEV; + goto fail_unmap; + } + + INIT_LIST_HEAD(&mal->poll_list); + set_bit(__LINK_STATE_START, &mal->poll_dev.state); + mal->poll_dev.weight = CONFIG_IBM_NEW_EMAC_POLL_WEIGHT; + mal->poll_dev.poll = mal_poll; + mal->poll_dev.priv = mal; + atomic_set(&mal->poll_dev.refcnt, 1); + INIT_LIST_HEAD(&mal->list); + spin_lock_init(&mal->lock); + + /* Load power-on reset defaults */ + mal_reset(mal); + + /* Set the MAL configuration register */ + cfg = (mal->version == 2) ? MAL2_CFG_DEFAULT : MAL1_CFG_DEFAULT; + cfg |= MAL_CFG_PLBB | MAL_CFG_OPBBL | MAL_CFG_LEA; + + /* Current Axon is not happy with priority being non-0, it can + * deadlock, fix it up here + */ + if (of_device_is_compatible(ofdev->node, "ibm,mcmal-axon")) + cfg &= ~(MAL2_CFG_RPP_10 | MAL2_CFG_WPP_10); + + /* Apply configuration */ + set_mal_dcrn(mal, MAL_CFG, cfg); + + /* Allocate space for BD rings */ + BUG_ON(mal->num_tx_chans <= 0 || mal->num_tx_chans > 32); + BUG_ON(mal->num_rx_chans <= 0 || mal->num_rx_chans > 32); + + bd_size = sizeof(struct mal_descriptor) * + (NUM_TX_BUFF * mal->num_tx_chans + + NUM_RX_BUFF * mal->num_rx_chans); + mal->bd_virt = + dma_alloc_coherent(&ofdev->dev, bd_size, &mal->bd_dma, + GFP_KERNEL); + if (mal->bd_virt == NULL) { + printk(KERN_ERR + "mal%d: out of memory allocating RX/TX descriptors!\n", + index); + err = -ENOMEM; + goto fail_unmap; + } + memset(mal->bd_virt, 0, bd_size); + + for (i = 0; i < mal->num_tx_chans; ++i) + set_mal_dcrn(mal, MAL_TXCTPR(i), mal->bd_dma + + sizeof(struct mal_descriptor) * + mal_tx_bd_offset(mal, i)); + + for (i = 0; i < mal->num_rx_chans; ++i) + set_mal_dcrn(mal, MAL_RXCTPR(i), mal->bd_dma + + sizeof(struct mal_descriptor) * + mal_rx_bd_offset(mal, i)); + + err = request_irq(mal->serr_irq, mal_serr, 0, "MAL SERR", mal); + if (err) + goto fail2; + err = request_irq(mal->txde_irq, mal_txde, 0, "MAL TX DE", mal); + if (err) + goto fail3; + err = request_irq(mal->txeob_irq, mal_txeob, 0, "MAL TX EOB", mal); + if (err) + goto fail4; + err = request_irq(mal->rxde_irq, mal_rxde, 0, "MAL RX DE", mal); + if (err) + goto fail5; + err = request_irq(mal->rxeob_irq, mal_rxeob, 0, "MAL RX EOB", mal); + if (err) + goto fail6; + + /* Enable all MAL SERR interrupt sources */ + if (mal->version == 2) + set_mal_dcrn(mal, MAL_IER, MAL2_IER_EVENTS); + else + set_mal_dcrn(mal, MAL_IER, MAL1_IER_EVENTS); + + /* Enable EOB interrupt */ + mal_enable_eob_irq(mal); + + printk(KERN_INFO + "MAL v%d %s, %d TX channels, %d RX channels\n", + mal->version, ofdev->node->full_name, + mal->num_tx_chans, mal->num_rx_chans); + + /* Advertise this instance to the rest of the world */ + wmb(); + dev_set_drvdata(&ofdev->dev, mal); + + mal_dbg_register(mal); + + return 0; + + fail6: + free_irq(mal->rxde_irq, mal); + fail5: + free_irq(mal->txeob_irq, mal); + fail4: + free_irq(mal->txde_irq, mal); + fail3: + free_irq(mal->serr_irq, mal); + fail2: + dma_free_coherent(&ofdev->dev, bd_size, mal->bd_virt, mal->bd_dma); + fail_unmap: + dcr_unmap(mal->dcr_host, mal->dcr_base, 0x100); + fail: + kfree(mal); + + return err; +} + +static int __devexit mal_remove(struct of_device *ofdev) +{ + struct mal_instance *mal = dev_get_drvdata(&ofdev->dev); + + MAL_DBG(mal, "remove" NL); + + /* Syncronize with scheduled polling, + stolen from net/core/dev.c:dev_close() + */ + clear_bit(__LINK_STATE_START, &mal->poll_dev.state); + netif_poll_disable(&mal->poll_dev); + + if (!list_empty(&mal->list)) { + /* This is *very* bad */ + printk(KERN_EMERG + "mal%d: commac list is not empty on remove!\n", + mal->index); + WARN_ON(1); + } + + dev_set_drvdata(&ofdev->dev, NULL); + + free_irq(mal->serr_irq, mal); + free_irq(mal->txde_irq, mal); + free_irq(mal->txeob_irq, mal); + free_irq(mal->rxde_irq, mal); + free_irq(mal->rxeob_irq, mal); + + mal_reset(mal); + + mal_dbg_unregister(mal); + + dma_free_coherent(&ofdev->dev, + sizeof(struct mal_descriptor) * + (NUM_TX_BUFF * mal->num_tx_chans + + NUM_RX_BUFF * mal->num_rx_chans), mal->bd_virt, + mal->bd_dma); + kfree(mal); + + return 0; +} + +static struct of_device_id mal_platform_match[] = +{ + { + .compatible = "ibm,mcmal", + }, + { + .compatible = "ibm,mcmal2", + }, + /* Backward compat */ + { + .type = "mcmal-dma", + .compatible = "ibm,mcmal", + }, + { + .type = "mcmal-dma", + .compatible = "ibm,mcmal2", + }, + {}, +}; + +static struct of_platform_driver mal_of_driver = { + .name = "mcmal", + .match_table = mal_platform_match, + + .probe = mal_probe, + .remove = mal_remove, +}; + +int __init mal_init(void) +{ + return of_register_platform_driver(&mal_of_driver); +} + +void mal_exit(void) +{ + of_unregister_platform_driver(&mal_of_driver); +} diff --git a/drivers/net/ibm_newemac/mal.h b/drivers/net/ibm_newemac/mal.h new file mode 100644 index 00000000000..57b69dc32e9 --- /dev/null +++ b/drivers/net/ibm_newemac/mal.h @@ -0,0 +1,276 @@ +/* + * drivers/net/ibm_newemac/mal.h + * + * Memory Access Layer (MAL) support + * + * Copyright (c) 2004, 2005 Zultys Technologies. + * Eugene Surovegin or + * + * Based on original work by + * Armin Kuster + * Copyright 2002 MontaVista Softare Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#ifndef __IBM_NEWEMAC_MAL_H +#define __IBM_NEWEMAC_MAL_H + +/* + * There are some variations on the MAL, we express them in this driver as + * MAL Version 1 and 2 though that doesn't match any IBM terminology. + * + * We call MAL 1 the version in 405GP, 405GPR, 405EP, 440EP, 440GR and + * NP405H. + * + * We call MAL 2 the version in 440GP, 440GX, 440SP, 440SPE and Axon + * + * The driver expects a "version" property in the emac node containing + * a number 1 or 2. New device-trees for EMAC capable platforms are thus + * required to include that when porting to arch/powerpc. + */ + +/* MALx DCR registers */ +#define MAL_CFG 0x00 +#define MAL_CFG_SR 0x80000000 +#define MAL_CFG_PLBB 0x00004000 +#define MAL_CFG_OPBBL 0x00000080 +#define MAL_CFG_EOPIE 0x00000004 +#define MAL_CFG_LEA 0x00000002 +#define MAL_CFG_SD 0x00000001 + +/* MAL V1 CFG bits */ +#define MAL1_CFG_PLBP_MASK 0x00c00000 +#define MAL1_CFG_PLBP_10 0x00800000 +#define MAL1_CFG_GA 0x00200000 +#define MAL1_CFG_OA 0x00100000 +#define MAL1_CFG_PLBLE 0x00080000 +#define MAL1_CFG_PLBT_MASK 0x00078000 +#define MAL1_CFG_DEFAULT (MAL1_CFG_PLBP_10 | MAL1_CFG_PLBT_MASK) + +/* MAL V2 CFG bits */ +#define MAL2_CFG_RPP_MASK 0x00c00000 +#define MAL2_CFG_RPP_10 0x00800000 +#define MAL2_CFG_RMBS_MASK 0x00300000 +#define MAL2_CFG_WPP_MASK 0x000c0000 +#define MAL2_CFG_WPP_10 0x00080000 +#define MAL2_CFG_WMBS_MASK 0x00030000 +#define MAL2_CFG_PLBLE 0x00008000 +#define MAL2_CFG_DEFAULT (MAL2_CFG_RMBS_MASK | MAL2_CFG_WMBS_MASK | \ + MAL2_CFG_RPP_10 | MAL2_CFG_WPP_10) + +#define MAL_ESR 0x01 +#define MAL_ESR_EVB 0x80000000 +#define MAL_ESR_CIDT 0x40000000 +#define MAL_ESR_CID_MASK 0x3e000000 +#define MAL_ESR_CID_SHIFT 25 +#define MAL_ESR_DE 0x00100000 +#define MAL_ESR_OTE 0x00040000 +#define MAL_ESR_OSE 0x00020000 +#define MAL_ESR_PEIN 0x00010000 +#define MAL_ESR_DEI 0x00000010 +#define MAL_ESR_OTEI 0x00000004 +#define MAL_ESR_OSEI 0x00000002 +#define MAL_ESR_PBEI 0x00000001 + +/* MAL V1 ESR bits */ +#define MAL1_ESR_ONE 0x00080000 +#define MAL1_ESR_ONEI 0x00000008 + +/* MAL V2 ESR bits */ +#define MAL2_ESR_PTE 0x00800000 +#define MAL2_ESR_PRE 0x00400000 +#define MAL2_ESR_PWE 0x00200000 +#define MAL2_ESR_PTEI 0x00000080 +#define MAL2_ESR_PREI 0x00000040 +#define MAL2_ESR_PWEI 0x00000020 + + +#define MAL_IER 0x02 +#define MAL_IER_DE 0x00000010 +#define MAL_IER_OTE 0x00000004 +#define MAL_IER_OE 0x00000002 +#define MAL_IER_PE 0x00000001 +/* MAL V1 IER bits */ +#define MAL1_IER_NWE 0x00000008 +#define MAL1_IER_SOC_EVENTS MAL1_IER_NWE +#define MAL1_IER_EVENTS (MAL1_IER_SOC_EVENTS | MAL_IER_OTE | \ + MAL_IER_OTE | MAL_IER_OE | MAL_IER_PE) + +/* MAL V2 IER bits */ +#define MAL2_IER_PT 0x00000080 +#define MAL2_IER_PRE 0x00000040 +#define MAL2_IER_PWE 0x00000020 +#define MAL2_IER_SOC_EVENTS (MAL2_IER_PT | MAL2_IER_PRE | MAL2_IER_PWE) +#define MAL2_IER_EVENTS (MAL2_IER_SOC_EVENTS | MAL_IER_OTE | \ + MAL_IER_OTE | MAL_IER_OE | MAL_IER_PE) + + +#define MAL_TXCASR 0x04 +#define MAL_TXCARR 0x05 +#define MAL_TXEOBISR 0x06 +#define MAL_TXDEIR 0x07 +#define MAL_RXCASR 0x10 +#define MAL_RXCARR 0x11 +#define MAL_RXEOBISR 0x12 +#define MAL_RXDEIR 0x13 +#define MAL_TXCTPR(n) ((n) + 0x20) +#define MAL_RXCTPR(n) ((n) + 0x40) +#define MAL_RCBS(n) ((n) + 0x60) + +/* In reality MAL can handle TX buffers up to 4095 bytes long, + * but this isn't a good round number :) --ebs + */ +#define MAL_MAX_TX_SIZE 4080 +#define MAL_MAX_RX_SIZE 4080 + +static inline int mal_rx_size(int len) +{ + len = (len + 0xf) & ~0xf; + return len > MAL_MAX_RX_SIZE ? MAL_MAX_RX_SIZE : len; +} + +static inline int mal_tx_chunks(int len) +{ + return (len + MAL_MAX_TX_SIZE - 1) / MAL_MAX_TX_SIZE; +} + +#define MAL_CHAN_MASK(n) (0x80000000 >> (n)) + +/* MAL Buffer Descriptor structure */ +struct mal_descriptor { + u16 ctrl; /* MAL / Commac status control bits */ + u16 data_len; /* Max length is 4K-1 (12 bits) */ + u32 data_ptr; /* pointer to actual data buffer */ +}; + +/* the following defines are for the MadMAL status and control registers. */ +/* MADMAL transmit and receive status/control bits */ +#define MAL_RX_CTRL_EMPTY 0x8000 +#define MAL_RX_CTRL_WRAP 0x4000 +#define MAL_RX_CTRL_CM 0x2000 +#define MAL_RX_CTRL_LAST 0x1000 +#define MAL_RX_CTRL_FIRST 0x0800 +#define MAL_RX_CTRL_INTR 0x0400 +#define MAL_RX_CTRL_SINGLE (MAL_RX_CTRL_LAST | MAL_RX_CTRL_FIRST) +#define MAL_IS_SINGLE_RX(ctrl) (((ctrl) & MAL_RX_CTRL_SINGLE) == MAL_RX_CTRL_SINGLE) + +#define MAL_TX_CTRL_READY 0x8000 +#define MAL_TX_CTRL_WRAP 0x4000 +#define MAL_TX_CTRL_CM 0x2000 +#define MAL_TX_CTRL_LAST 0x1000 +#define MAL_TX_CTRL_INTR 0x0400 + +struct mal_commac_ops { + void (*poll_tx) (void *dev); + int (*poll_rx) (void *dev, int budget); + int (*peek_rx) (void *dev); + void (*rxde) (void *dev); +}; + +struct mal_commac { + struct mal_commac_ops *ops; + void *dev; + struct list_head poll_list; + long flags; +#define MAL_COMMAC_RX_STOPPED 0 +#define MAL_COMMAC_POLL_DISABLED 1 + u32 tx_chan_mask; + u32 rx_chan_mask; + struct list_head list; +}; + +struct mal_instance { + int version; + int dcr_base; + dcr_host_t dcr_host; + + int num_tx_chans; /* Number of TX channels */ + int num_rx_chans; /* Number of RX channels */ + int txeob_irq; /* TX End Of Buffer IRQ */ + int rxeob_irq; /* RX End Of Buffer IRQ */ + int txde_irq; /* TX Descriptor Error IRQ */ + int rxde_irq; /* RX Descriptor Error IRQ */ + int serr_irq; /* MAL System Error IRQ */ + + struct list_head poll_list; + struct net_device poll_dev; + + struct list_head list; + u32 tx_chan_mask; + u32 rx_chan_mask; + + dma_addr_t bd_dma; + struct mal_descriptor *bd_virt; + + struct of_device *ofdev; + int index; + spinlock_t lock; +}; + +static inline u32 get_mal_dcrn(struct mal_instance *mal, int reg) +{ + return dcr_read(mal->dcr_host, mal->dcr_base + reg); +} + +static inline void set_mal_dcrn(struct mal_instance *mal, int reg, u32 val) +{ + dcr_write(mal->dcr_host, mal->dcr_base + reg, val); +} + +/* Register MAL devices */ +int mal_init(void); +void mal_exit(void); + +int mal_register_commac(struct mal_instance *mal, + struct mal_commac *commac); +void mal_unregister_commac(struct mal_instance *mal, + struct mal_commac *commac); +int mal_set_rcbs(struct mal_instance *mal, int channel, unsigned long size); + +/* Returns BD ring offset for a particular channel + (in 'struct mal_descriptor' elements) +*/ +int mal_tx_bd_offset(struct mal_instance *mal, int channel); +int mal_rx_bd_offset(struct mal_instance *mal, int channel); + +void mal_enable_tx_channel(struct mal_instance *mal, int channel); +void mal_disable_tx_channel(struct mal_instance *mal, int channel); +void mal_enable_rx_channel(struct mal_instance *mal, int channel); +void mal_disable_rx_channel(struct mal_instance *mal, int channel); + +void mal_poll_disable(struct mal_instance *mal, struct mal_commac *commac); +void mal_poll_enable(struct mal_instance *mal, struct mal_commac *commac); + +/* Add/remove EMAC to/from MAL polling list */ +void mal_poll_add(struct mal_instance *mal, struct mal_commac *commac); +void mal_poll_del(struct mal_instance *mal, struct mal_commac *commac); + +/* Ethtool MAL registers */ +struct mal_regs { + u32 tx_count; + u32 rx_count; + + u32 cfg; + u32 esr; + u32 ier; + u32 tx_casr; + u32 tx_carr; + u32 tx_eobisr; + u32 tx_deir; + u32 rx_casr; + u32 rx_carr; + u32 rx_eobisr; + u32 rx_deir; + u32 tx_ctpr[32]; + u32 rx_ctpr[32]; + u32 rcbs[32]; +}; + +int mal_get_regs_len(struct mal_instance *mal); +void *mal_dump_regs(struct mal_instance *mal, void *buf); + +#endif /* __IBM_NEWEMAC_MAL_H */ diff --git a/drivers/net/ibm_newemac/phy.c b/drivers/net/ibm_newemac/phy.c new file mode 100644 index 00000000000..aa1f0ddf1e3 --- /dev/null +++ b/drivers/net/ibm_newemac/phy.c @@ -0,0 +1,373 @@ +/* + * drivers/net/ibm_newemac/phy.c + * + * Driver for PowerPC 4xx on-chip ethernet controller, PHY support. + * Borrowed from sungem_phy.c, though I only kept the generic MII + * driver for now. + * + * This file should be shared with other drivers or eventually + * merged as the "low level" part of miilib + * + * (c) 2003, Benjamin Herrenscmidt (benh@kernel.crashing.org) + * (c) 2004-2005, Eugene Surovegin + * + */ +#include +#include +#include +#include +#include +#include +#include + +#include "emac.h" +#include "phy.h" + +static inline int phy_read(struct mii_phy *phy, int reg) +{ + return phy->mdio_read(phy->dev, phy->address, reg); +} + +static inline void phy_write(struct mii_phy *phy, int reg, int val) +{ + phy->mdio_write(phy->dev, phy->address, reg, val); +} + +int emac_mii_reset_phy(struct mii_phy *phy) +{ + int val; + int limit = 10000; + + val = phy_read(phy, MII_BMCR); + val &= ~(BMCR_ISOLATE | BMCR_ANENABLE); + val |= BMCR_RESET; + phy_write(phy, MII_BMCR, val); + + udelay(300); + + while (limit--) { + val = phy_read(phy, MII_BMCR); + if (val >= 0 && (val & BMCR_RESET) == 0) + break; + udelay(10); + } + if ((val & BMCR_ISOLATE) && limit > 0) + phy_write(phy, MII_BMCR, val & ~BMCR_ISOLATE); + + return limit <= 0; +} + +static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise) +{ + int ctl, adv; + + phy->autoneg = AUTONEG_ENABLE; + phy->speed = SPEED_10; + phy->duplex = DUPLEX_HALF; + phy->pause = phy->asym_pause = 0; + phy->advertising = advertise; + + ctl = phy_read(phy, MII_BMCR); + if (ctl < 0) + return ctl; + ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE); + + /* First clear the PHY */ + phy_write(phy, MII_BMCR, ctl); + + /* Setup standard advertise */ + adv = phy_read(phy, MII_ADVERTISE); + if (adv < 0) + return adv; + adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP | + ADVERTISE_PAUSE_ASYM); + if (advertise & ADVERTISED_10baseT_Half) + adv |= ADVERTISE_10HALF; + if (advertise & ADVERTISED_10baseT_Full) + adv |= ADVERTISE_10FULL; + if (advertise & ADVERTISED_100baseT_Half) + adv |= ADVERTISE_100HALF; + if (advertise & ADVERTISED_100baseT_Full) + adv |= ADVERTISE_100FULL; + if (advertise & ADVERTISED_Pause) + adv |= ADVERTISE_PAUSE_CAP; + if (advertise & ADVERTISED_Asym_Pause) + adv |= ADVERTISE_PAUSE_ASYM; + phy_write(phy, MII_ADVERTISE, adv); + + if (phy->features & + (SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half)) { + adv = phy_read(phy, MII_CTRL1000); + if (adv < 0) + return adv; + adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); + if (advertise & ADVERTISED_1000baseT_Full) + adv |= ADVERTISE_1000FULL; + if (advertise & ADVERTISED_1000baseT_Half) + adv |= ADVERTISE_1000HALF; + phy_write(phy, MII_CTRL1000, adv); + } + + /* Start/Restart aneg */ + ctl = phy_read(phy, MII_BMCR); + ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); + phy_write(phy, MII_BMCR, ctl); + + return 0; +} + +static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd) +{ + int ctl; + + phy->autoneg = AUTONEG_DISABLE; + phy->speed = speed; + phy->duplex = fd; + phy->pause = phy->asym_pause = 0; + + ctl = phy_read(phy, MII_BMCR); + if (ctl < 0) + return ctl; + ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE); + + /* First clear the PHY */ + phy_write(phy, MII_BMCR, ctl | BMCR_RESET); + + /* Select speed & duplex */ + switch (speed) { + case SPEED_10: + break; + case SPEED_100: + ctl |= BMCR_SPEED100; + break; + case SPEED_1000: + ctl |= BMCR_SPEED1000; + break; + default: + return -EINVAL; + } + if (fd == DUPLEX_FULL) + ctl |= BMCR_FULLDPLX; + phy_write(phy, MII_BMCR, ctl); + + return 0; +} + +static int genmii_poll_link(struct mii_phy *phy) +{ + int status; + + /* Clear latched value with dummy read */ + phy_read(phy, MII_BMSR); + status = phy_read(phy, MII_BMSR); + if (status < 0 || (status & BMSR_LSTATUS) == 0) + return 0; + if (phy->autoneg == AUTONEG_ENABLE && !(status & BMSR_ANEGCOMPLETE)) + return 0; + return 1; +} + +static int genmii_read_link(struct mii_phy *phy) +{ + if (phy->autoneg == AUTONEG_ENABLE) { + int glpa = 0; + int lpa = phy_read(phy, MII_LPA) & phy_read(phy, MII_ADVERTISE); + if (lpa < 0) + return lpa; + + if (phy->features & + (SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half)) { + int adv = phy_read(phy, MII_CTRL1000); + glpa = phy_read(phy, MII_STAT1000); + + if (glpa < 0 || adv < 0) + return adv; + + glpa &= adv << 2; + } + + phy->speed = SPEED_10; + phy->duplex = DUPLEX_HALF; + phy->pause = phy->asym_pause = 0; + + if (glpa & (LPA_1000FULL | LPA_1000HALF)) { + phy->speed = SPEED_1000; + if (glpa & LPA_1000FULL) + phy->duplex = DUPLEX_FULL; + } else if (lpa & (LPA_100FULL | LPA_100HALF)) { + phy->speed = SPEED_100; + if (lpa & LPA_100FULL) + phy->duplex = DUPLEX_FULL; + } else if (lpa & LPA_10FULL) + phy->duplex = DUPLEX_FULL; + + if (phy->duplex == DUPLEX_FULL) { + phy->pause = lpa & LPA_PAUSE_CAP ? 1 : 0; + phy->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0; + } + } else { + int bmcr = phy_read(phy, MII_BMCR); + if (bmcr < 0) + return bmcr; + + if (bmcr & BMCR_FULLDPLX) + phy->duplex = DUPLEX_FULL; + else + phy->duplex = DUPLEX_HALF; + if (bmcr & BMCR_SPEED1000) + phy->speed = SPEED_1000; + else if (bmcr & BMCR_SPEED100) + phy->speed = SPEED_100; + else + phy->speed = SPEED_10; + + phy->pause = phy->asym_pause = 0; + } + return 0; +} + +/* Generic implementation for most 10/100/1000 PHYs */ +static struct mii_phy_ops generic_phy_ops = { + .setup_aneg = genmii_setup_aneg, + .setup_forced = genmii_setup_forced, + .poll_link = genmii_poll_link, + .read_link = genmii_read_link +}; + +static struct mii_phy_def genmii_phy_def = { + .phy_id = 0x00000000, + .phy_id_mask = 0x00000000, + .name = "Generic MII", + .ops = &generic_phy_ops +}; + +/* CIS8201 */ +#define MII_CIS8201_10BTCSR 0x16 +#define TENBTCSR_ECHO_DISABLE 0x2000 +#define MII_CIS8201_EPCR 0x17 +#define EPCR_MODE_MASK 0x3000 +#define EPCR_GMII_MODE 0x0000 +#define EPCR_RGMII_MODE 0x1000 +#define EPCR_TBI_MODE 0x2000 +#define EPCR_RTBI_MODE 0x3000 +#define MII_CIS8201_ACSR 0x1c +#define ACSR_PIN_PRIO_SELECT 0x0004 + +static int cis8201_init(struct mii_phy *phy) +{ + int epcr; + + epcr = phy_read(phy, MII_CIS8201_EPCR); + if (epcr < 0) + return epcr; + + epcr &= ~EPCR_MODE_MASK; + + switch (phy->mode) { + case PHY_MODE_TBI: + epcr |= EPCR_TBI_MODE; + break; + case PHY_MODE_RTBI: + epcr |= EPCR_RTBI_MODE; + break; + case PHY_MODE_GMII: + epcr |= EPCR_GMII_MODE; + break; + case PHY_MODE_RGMII: + default: + epcr |= EPCR_RGMII_MODE; + } + + phy_write(phy, MII_CIS8201_EPCR, epcr); + + /* MII regs override strap pins */ + phy_write(phy, MII_CIS8201_ACSR, + phy_read(phy, MII_CIS8201_ACSR) | ACSR_PIN_PRIO_SELECT); + + /* Disable TX_EN -> CRS echo mode, otherwise 10/HDX doesn't work */ + phy_write(phy, MII_CIS8201_10BTCSR, + phy_read(phy, MII_CIS8201_10BTCSR) | TENBTCSR_ECHO_DISABLE); + + return 0; +} + +static struct mii_phy_ops cis8201_phy_ops = { + .init = cis8201_init, + .setup_aneg = genmii_setup_aneg, + .setup_forced = genmii_setup_forced, + .poll_link = genmii_poll_link, + .read_link = genmii_read_link +}; + +static struct mii_phy_def cis8201_phy_def = { + .phy_id = 0x000fc410, + .phy_id_mask = 0x000ffff0, + .name = "CIS8201 Gigabit Ethernet", + .ops = &cis8201_phy_ops +}; + +static struct mii_phy_def *mii_phy_table[] = { + &cis8201_phy_def, + &genmii_phy_def, + NULL +}; + +int emac_mii_phy_probe(struct mii_phy *phy, int address) +{ + struct mii_phy_def *def; + int i; + u32 id; + + phy->autoneg = AUTONEG_DISABLE; + phy->advertising = 0; + phy->address = address; + phy->speed = SPEED_10; + phy->duplex = DUPLEX_HALF; + phy->pause = phy->asym_pause = 0; + + /* Take PHY out of isolate mode and reset it. */ + if (emac_mii_reset_phy(phy)) + return -ENODEV; + + /* Read ID and find matching entry */ + id = (phy_read(phy, MII_PHYSID1) << 16) | phy_read(phy, MII_PHYSID2); + for (i = 0; (def = mii_phy_table[i]) != NULL; i++) + if ((id & def->phy_id_mask) == def->phy_id) + break; + /* Should never be NULL (we have a generic entry), but... */ + if (!def) + return -ENODEV; + + phy->def = def; + + /* Determine PHY features if needed */ + phy->features = def->features; + if (!phy->features) { + u16 bmsr = phy_read(phy, MII_BMSR); + if (bmsr & BMSR_ANEGCAPABLE) + phy->features |= SUPPORTED_Autoneg; + if (bmsr & BMSR_10HALF) + phy->features |= SUPPORTED_10baseT_Half; + if (bmsr & BMSR_10FULL) + phy->features |= SUPPORTED_10baseT_Full; + if (bmsr & BMSR_100HALF) + phy->features |= SUPPORTED_100baseT_Half; + if (bmsr & BMSR_100FULL) + phy->features |= SUPPORTED_100baseT_Full; + if (bmsr & BMSR_ESTATEN) { + u16 esr = phy_read(phy, MII_ESTATUS); + if (esr & ESTATUS_1000_TFULL) + phy->features |= SUPPORTED_1000baseT_Full; + if (esr & ESTATUS_1000_THALF) + phy->features |= SUPPORTED_1000baseT_Half; + } + phy->features |= SUPPORTED_MII; + } + + /* Setup default advertising */ + phy->advertising = phy->features; + + return 0; +} + +MODULE_LICENSE("GPL"); diff --git a/drivers/net/ibm_newemac/phy.h b/drivers/net/ibm_newemac/phy.h new file mode 100644 index 00000000000..6feca26afed --- /dev/null +++ b/drivers/net/ibm_newemac/phy.h @@ -0,0 +1,80 @@ +/* + * drivers/net/ibm_newemac/phy.h + * + * Driver for PowerPC 4xx on-chip ethernet controller, PHY support + * + * Benjamin Herrenschmidt + * February 2003 + * + * Minor additions by Eugene Surovegin , 2004 + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This file basically duplicates sungem_phy.{c,h} with different PHYs + * supported. I'm looking into merging that in a single mii layer more + * flexible than mii.c + */ + +#ifndef __IBM_NEWEMAC_PHY_H +#define __IBM_NEWEMAC_PHY_H + +struct mii_phy; + +/* Operations supported by any kind of PHY */ +struct mii_phy_ops { + int (*init) (struct mii_phy * phy); + int (*suspend) (struct mii_phy * phy, int wol_options); + int (*setup_aneg) (struct mii_phy * phy, u32 advertise); + int (*setup_forced) (struct mii_phy * phy, int speed, int fd); + int (*poll_link) (struct mii_phy * phy); + int (*read_link) (struct mii_phy * phy); +}; + +/* Structure used to statically define an mii/gii based PHY */ +struct mii_phy_def { + u32 phy_id; /* Concatenated ID1 << 16 | ID2 */ + u32 phy_id_mask; /* Significant bits */ + u32 features; /* Ethtool SUPPORTED_* defines or + 0 for autodetect */ + int magic_aneg; /* Autoneg does all speed test for us */ + const char *name; + const struct mii_phy_ops *ops; +}; + +/* An instance of a PHY, partially borrowed from mii_if_info */ +struct mii_phy { + struct mii_phy_def *def; + u32 advertising; /* Ethtool ADVERTISED_* defines */ + u32 features; /* Copied from mii_phy_def.features + or determined automaticaly */ + int address; /* PHY address */ + int mode; /* PHY mode */ + + /* 1: autoneg enabled, 0: disabled */ + int autoneg; + + /* forced speed & duplex (no autoneg) + * partner speed & duplex & pause (autoneg) + */ + int speed; + int duplex; + int pause; + int asym_pause; + + /* Provided by host chip */ + struct net_device *dev; + int (*mdio_read) (struct net_device * dev, int addr, int reg); + void (*mdio_write) (struct net_device * dev, int addr, int reg, + int val); +}; + +/* Pass in a struct mii_phy with dev, mdio_read and mdio_write + * filled, the remaining fields will be filled on return + */ +int emac_mii_phy_probe(struct mii_phy *phy, int address); +int emac_mii_reset_phy(struct mii_phy *phy); + +#endif /* __IBM_NEWEMAC_PHY_H */ diff --git a/drivers/net/ibm_newemac/rgmii.c b/drivers/net/ibm_newemac/rgmii.c new file mode 100644 index 00000000000..bcd7fc639c4 --- /dev/null +++ b/drivers/net/ibm_newemac/rgmii.c @@ -0,0 +1,323 @@ +/* + * drivers/net/ibm_newemac/rgmii.c + * + * Driver for PowerPC 4xx on-chip ethernet controller, RGMII bridge support. + * + * Copyright (c) 2004, 2005 Zultys Technologies. + * Eugene Surovegin or + * + * Based on original work by + * Matt Porter + * Copyright 2004 MontaVista Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#include +#include +#include + +#include "emac.h" +#include "debug.h" + +// XXX FIXME: Axon seems to support a subset of the RGMII, we +// thus need to take that into account and possibly change some +// of the bit settings below that don't seem to quite match the +// AXON spec + +/* RGMIIx_FER */ +#define RGMII_FER_MASK(idx) (0x7 << ((idx) * 4)) +#define RGMII_FER_RTBI(idx) (0x4 << ((idx) * 4)) +#define RGMII_FER_RGMII(idx) (0x5 << ((idx) * 4)) +#define RGMII_FER_TBI(idx) (0x6 << ((idx) * 4)) +#define RGMII_FER_GMII(idx) (0x7 << ((idx) * 4)) + +/* RGMIIx_SSR */ +#define RGMII_SSR_MASK(idx) (0x7 << ((idx) * 8)) +#define RGMII_SSR_100(idx) (0x2 << ((idx) * 8)) +#define RGMII_SSR_1000(idx) (0x4 << ((idx) * 8)) + +/* RGMII bridge supports only GMII/TBI and RGMII/RTBI PHYs */ +static inline int rgmii_valid_mode(int phy_mode) +{ + return phy_mode == PHY_MODE_GMII || + phy_mode == PHY_MODE_RGMII || + phy_mode == PHY_MODE_TBI || + phy_mode == PHY_MODE_RTBI; +} + +static inline const char *rgmii_mode_name(int mode) +{ + switch (mode) { + case PHY_MODE_RGMII: + return "RGMII"; + case PHY_MODE_TBI: + return "TBI"; + case PHY_MODE_GMII: + return "GMII"; + case PHY_MODE_RTBI: + return "RTBI"; + default: + BUG(); + } +} + +static inline u32 rgmii_mode_mask(int mode, int input) +{ + switch (mode) { + case PHY_MODE_RGMII: + return RGMII_FER_RGMII(input); + case PHY_MODE_TBI: + return RGMII_FER_TBI(input); + case PHY_MODE_GMII: + return RGMII_FER_GMII(input); + case PHY_MODE_RTBI: + return RGMII_FER_RTBI(input); + default: + BUG(); + } +} + +int __devinit rgmii_attach(struct of_device *ofdev, int input, int mode) +{ + struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev); + struct rgmii_regs *p = dev->base; + + RGMII_DBG(dev, "attach(%d)" NL, input); + + /* Check if we need to attach to a RGMII */ + if (input < 0 || !rgmii_valid_mode(mode)) { + printk(KERN_ERR "%s: unsupported settings !\n", + ofdev->node->full_name); + return -ENODEV; + } + + mutex_lock(&dev->lock); + + /* Enable this input */ + out_be32(&p->fer, in_be32(&p->fer) | rgmii_mode_mask(mode, input)); + + printk(KERN_NOTICE "%s: input %d in %s mode\n", + ofdev->node->full_name, input, rgmii_mode_name(mode)); + + ++dev->users; + + mutex_unlock(&dev->lock); + + return 0; +} + +void rgmii_set_speed(struct of_device *ofdev, int input, int speed) +{ + struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev); + struct rgmii_regs *p = dev->base; + u32 ssr; + + mutex_lock(&dev->lock); + + ssr = in_be32(&p->ssr) & ~RGMII_SSR_MASK(input); + + RGMII_DBG(dev, "speed(%d, %d)" NL, input, speed); + + if (speed == SPEED_1000) + ssr |= RGMII_SSR_1000(input); + else if (speed == SPEED_100) + ssr |= RGMII_SSR_100(input); + + out_be32(&p->ssr, ssr); + + mutex_unlock(&dev->lock); +} + +void rgmii_get_mdio(struct of_device *ofdev, int input) +{ + struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev); + struct rgmii_regs *p = dev->base; + u32 fer; + + RGMII_DBG2(dev, "get_mdio(%d)" NL, input); + + if (dev->type != RGMII_AXON) + return; + + mutex_lock(&dev->lock); + + fer = in_be32(&p->fer); + fer |= 0x00080000u >> input; + out_be32(&p->fer, fer); + (void)in_be32(&p->fer); + + DBG2(dev, " fer = 0x%08x\n", fer); +} + +void rgmii_put_mdio(struct of_device *ofdev, int input) +{ + struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev); + struct rgmii_regs *p = dev->base; + u32 fer; + + RGMII_DBG2(dev, "put_mdio(%d)" NL, input); + + if (dev->type != RGMII_AXON) + return; + + fer = in_be32(&p->fer); + fer &= ~(0x00080000u >> input); + out_be32(&p->fer, fer); + (void)in_be32(&p->fer); + + DBG2(dev, " fer = 0x%08x\n", fer); + + mutex_unlock(&dev->lock); +} + +void __devexit rgmii_detach(struct of_device *ofdev, int input) +{ + struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev); + struct rgmii_regs *p = dev->base; + + mutex_lock(&dev->lock); + + BUG_ON(!dev || dev->users == 0); + + RGMII_DBG(dev, "detach(%d)" NL, input); + + /* Disable this input */ + out_be32(&p->fer, in_be32(&p->fer) & ~RGMII_FER_MASK(input)); + + --dev->users; + + mutex_unlock(&dev->lock); +} + +int rgmii_get_regs_len(struct of_device *ofdev) +{ + return sizeof(struct emac_ethtool_regs_subhdr) + + sizeof(struct rgmii_regs); +} + +void *rgmii_dump_regs(struct of_device *ofdev, void *buf) +{ + struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev); + struct emac_ethtool_regs_subhdr *hdr = buf; + struct rgmii_regs *regs = (struct rgmii_regs *)(hdr + 1); + + hdr->version = 0; + hdr->index = 0; /* for now, are there chips with more than one + * rgmii ? if yes, then we'll add a cell_index + * like we do for emac + */ + memcpy_fromio(regs, dev->base, sizeof(struct rgmii_regs)); + return regs + 1; +} + + +static int __devinit rgmii_probe(struct of_device *ofdev, + const struct of_device_id *match) +{ + struct device_node *np = ofdev->node; + struct rgmii_instance *dev; + struct resource regs; + int rc; + + rc = -ENOMEM; + dev = kzalloc(sizeof(struct rgmii_instance), GFP_KERNEL); + if (dev == NULL) { + printk(KERN_ERR "%s: could not allocate RGMII device!\n", + np->full_name); + goto err_gone; + } + + mutex_init(&dev->lock); + dev->ofdev = ofdev; + + rc = -ENXIO; + if (of_address_to_resource(np, 0, ®s)) { + printk(KERN_ERR "%s: Can't get registers address\n", + np->full_name); + goto err_free; + } + + rc = -ENOMEM; + dev->base = (struct rgmii_regs *)ioremap(regs.start, + sizeof(struct rgmii_regs)); + if (dev->base == NULL) { + printk(KERN_ERR "%s: Can't map device registers!\n", + np->full_name); + goto err_free; + } + + /* Check for RGMII type */ + if (device_is_compatible(ofdev->node, "ibm,rgmii-axon")) + dev->type = RGMII_AXON; + else + dev->type = RGMII_STANDARD; + + DBG2(dev, " Boot FER = 0x%08x, SSR = 0x%08x\n", + in_be32(&dev->base->fer), in_be32(&dev->base->ssr)); + + /* Disable all inputs by default */ + out_be32(&dev->base->fer, 0); + + printk(KERN_INFO + "RGMII %s %s initialized\n", + dev->type == RGMII_STANDARD ? "standard" : "axon", + ofdev->node->full_name); + + wmb(); + dev_set_drvdata(&ofdev->dev, dev); + + return 0; + + err_free: + kfree(dev); + err_gone: + return rc; +} + +static int __devexit rgmii_remove(struct of_device *ofdev) +{ + struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev); + + dev_set_drvdata(&ofdev->dev, NULL); + + WARN_ON(dev->users != 0); + + iounmap(dev->base); + kfree(dev); + + return 0; +} + +static struct of_device_id rgmii_match[] = +{ + { + .type = "rgmii-interface", + .compatible = "ibm,rgmii", + }, + { + .type = "emac-rgmii", + }, + {}, +}; + +static struct of_platform_driver rgmii_driver = { + .name = "emac-rgmii", + .match_table = rgmii_match, + + .probe = rgmii_probe, + .remove = rgmii_remove, +}; + +int __init rgmii_init(void) +{ + return of_register_platform_driver(&rgmii_driver); +} + +void rgmii_exit(void) +{ + of_unregister_platform_driver(&rgmii_driver); +} diff --git a/drivers/net/ibm_newemac/rgmii.h b/drivers/net/ibm_newemac/rgmii.h new file mode 100644 index 00000000000..57806833121 --- /dev/null +++ b/drivers/net/ibm_newemac/rgmii.h @@ -0,0 +1,76 @@ +/* + * drivers/net/ibm_newemac/rgmii.h + * + * Driver for PowerPC 4xx on-chip ethernet controller, RGMII bridge support. + * + * Based on ocp_zmii.h/ibm_emac_zmii.h + * Armin Kuster akuster@mvista.com + * + * Copyright 2004 MontaVista Software, Inc. + * Matt Porter + * + * Copyright (c) 2004, 2005 Zultys Technologies. + * Eugene Surovegin or + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __IBM_NEWEMAC_RGMII_H +#define __IBM_NEWEMAC_RGMII_H + +/* RGMII bridge type */ +#define RGMII_STANDARD 0 +#define RGMII_AXON 1 + +/* RGMII bridge */ +struct rgmii_regs { + u32 fer; /* Function enable register */ + u32 ssr; /* Speed select register */ +}; + +/* RGMII device */ +struct rgmii_instance { + struct rgmii_regs __iomem *base; + + /* Type of RGMII bridge */ + int type; + + /* Only one EMAC whacks us at a time */ + struct mutex lock; + + /* number of EMACs using this RGMII bridge */ + int users; + + /* OF device instance */ + struct of_device *ofdev; +}; + +#ifdef CONFIG_IBM_NEW_EMAC_RGMII + +extern int rgmii_init(void); +extern void rgmii_exit(void); +extern int rgmii_attach(struct of_device *ofdev, int input, int mode); +extern void rgmii_detach(struct of_device *ofdev, int input); +extern void rgmii_get_mdio(struct of_device *ofdev, int input); +extern void rgmii_put_mdio(struct of_device *ofdev, int input); +extern void rgmii_set_speed(struct of_device *ofdev, int input, int speed); +extern int rgmii_get_regs_len(struct of_device *ofdev); +extern void *rgmii_dump_regs(struct of_device *ofdev, void *buf); + +#else + +# define rgmii_init() 0 +# define rgmii_exit() do { } while(0) +# define rgmii_attach(x,y,z) (-ENXIO) +# define rgmii_detach(x,y) do { } while(0) +# define rgmii_get_mdio(o,i) do { } while (0) +# define rgmii_put_mdio(o,i) do { } while (0) +# define rgmii_set_speed(x,y,z) do { } while(0) +# define rgmii_get_regs_len(x) 0 +# define rgmii_dump_regs(x,buf) (buf) +#endif /* !CONFIG_IBM_NEW_EMAC_RGMII */ + +#endif /* __IBM_NEWEMAC_RGMII_H */ diff --git a/drivers/net/ibm_newemac/tah.c b/drivers/net/ibm_newemac/tah.c new file mode 100644 index 00000000000..e05c7e81efb --- /dev/null +++ b/drivers/net/ibm_newemac/tah.c @@ -0,0 +1,173 @@ +/* + * drivers/net/ibm_newemac/tah.c + * + * Driver for PowerPC 4xx on-chip ethernet controller, TAH support. + * + * Copyright 2004 MontaVista Software, Inc. + * Matt Porter + * + * Copyright (c) 2005 Eugene Surovegin + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#include + +#include "emac.h" +#include "core.h" + +int __devinit tah_attach(struct of_device *ofdev, int channel) +{ + struct tah_instance *dev = dev_get_drvdata(&ofdev->dev); + + mutex_lock(&dev->lock); + /* Reset has been done at probe() time... nothing else to do for now */ + ++dev->users; + mutex_unlock(&dev->lock); + + return 0; +} + +void __devexit tah_detach(struct of_device *ofdev, int channel) +{ + struct tah_instance *dev = dev_get_drvdata(&ofdev->dev); + + mutex_lock(&dev->lock); + --dev->users; + mutex_unlock(&dev->lock); +} + +void tah_reset(struct of_device *ofdev) +{ + struct tah_instance *dev = dev_get_drvdata(&ofdev->dev); + struct tah_regs *p = dev->base; + int n; + + /* Reset TAH */ + out_be32(&p->mr, TAH_MR_SR); + n = 100; + while ((in_be32(&p->mr) & TAH_MR_SR) && n) + --n; + + if (unlikely(!n)) + printk(KERN_ERR "%s: reset timeout\n", ofdev->node->full_name); + + /* 10KB TAH TX FIFO accomodates the max MTU of 9000 */ + out_be32(&p->mr, + TAH_MR_CVR | TAH_MR_ST_768 | TAH_MR_TFS_10KB | TAH_MR_DTFP | + TAH_MR_DIG); +} + +int tah_get_regs_len(struct of_device *ofdev) +{ + return sizeof(struct emac_ethtool_regs_subhdr) + + sizeof(struct tah_regs); +} + +void *tah_dump_regs(struct of_device *ofdev, void *buf) +{ + struct tah_instance *dev = dev_get_drvdata(&ofdev->dev); + struct emac_ethtool_regs_subhdr *hdr = buf; + struct tah_regs *regs = (struct tah_regs *)(hdr + 1); + + hdr->version = 0; + hdr->index = 0; /* for now, are there chips with more than one + * zmii ? if yes, then we'll add a cell_index + * like we do for emac + */ + memcpy_fromio(regs, dev->base, sizeof(struct tah_regs)); + return regs + 1; +} + +static int __devinit tah_probe(struct of_device *ofdev, + const struct of_device_id *match) +{ + struct device_node *np = ofdev->node; + struct tah_instance *dev; + struct resource regs; + int rc; + + rc = -ENOMEM; + dev = kzalloc(sizeof(struct tah_instance), GFP_KERNEL); + if (dev == NULL) { + printk(KERN_ERR "%s: could not allocate TAH device!\n", + np->full_name); + goto err_gone; + } + + mutex_init(&dev->lock); + dev->ofdev = ofdev; + + rc = -ENXIO; + if (of_address_to_resource(np, 0, ®s)) { + printk(KERN_ERR "%s: Can't get registers address\n", + np->full_name); + goto err_free; + } + + rc = -ENOMEM; + dev->base = (struct tah_regs *)ioremap(regs.start, + sizeof(struct tah_regs)); + if (dev->base == NULL) { + printk(KERN_ERR "%s: Can't map device registers!\n", + np->full_name); + goto err_free; + } + + /* Initialize TAH and enable IPv4 checksum verification, no TSO yet */ + tah_reset(ofdev); + + printk(KERN_INFO + "TAH %s initialized\n", ofdev->node->full_name); + wmb(); + dev_set_drvdata(&ofdev->dev, dev); + + return 0; + + err_free: + kfree(dev); + err_gone: + return rc; +} + +static int __devexit tah_remove(struct of_device *ofdev) +{ + struct tah_instance *dev = dev_get_drvdata(&ofdev->dev); + + dev_set_drvdata(&ofdev->dev, NULL); + + WARN_ON(dev->users != 0); + + iounmap(dev->base); + kfree(dev); + + return 0; +} + +static struct of_device_id tah_match[] = +{ + { + .type = "tah", + }, + {}, +}; + +static struct of_platform_driver tah_driver = { + .name = "emac-tah", + .match_table = tah_match, + + .probe = tah_probe, + .remove = tah_remove, +}; + +int __init tah_init(void) +{ + return of_register_platform_driver(&tah_driver); +} + +void tah_exit(void) +{ + of_unregister_platform_driver(&tah_driver); +} diff --git a/drivers/net/ibm_newemac/tah.h b/drivers/net/ibm_newemac/tah.h new file mode 100644 index 00000000000..bc41853b6e2 --- /dev/null +++ b/drivers/net/ibm_newemac/tah.h @@ -0,0 +1,90 @@ +/* + * drivers/net/ibm_newemac/tah.h + * + * Driver for PowerPC 4xx on-chip ethernet controller, TAH support. + * + * Copyright 2004 MontaVista Software, Inc. + * Matt Porter + * + * Copyright (c) 2005 Eugene Surovegin + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __IBM_NEWEMAC_TAH_H +#define __IBM_NEWEMAC_TAH_H + +/* TAH */ +struct tah_regs { + u32 revid; + u32 pad[3]; + u32 mr; + u32 ssr0; + u32 ssr1; + u32 ssr2; + u32 ssr3; + u32 ssr4; + u32 ssr5; + u32 tsr; +}; + + +/* TAH device */ +struct tah_instance { + struct tah_regs __iomem *base; + + /* Only one EMAC whacks us at a time */ + struct mutex lock; + + /* number of EMACs using this TAH */ + int users; + + /* OF device instance */ + struct of_device *ofdev; +}; + + +/* TAH engine */ +#define TAH_MR_CVR 0x80000000 +#define TAH_MR_SR 0x40000000 +#define TAH_MR_ST_256 0x01000000 +#define TAH_MR_ST_512 0x02000000 +#define TAH_MR_ST_768 0x03000000 +#define TAH_MR_ST_1024 0x04000000 +#define TAH_MR_ST_1280 0x05000000 +#define TAH_MR_ST_1536 0x06000000 +#define TAH_MR_TFS_16KB 0x00000000 +#define TAH_MR_TFS_2KB 0x00200000 +#define TAH_MR_TFS_4KB 0x00400000 +#define TAH_MR_TFS_6KB 0x00600000 +#define TAH_MR_TFS_8KB 0x00800000 +#define TAH_MR_TFS_10KB 0x00a00000 +#define TAH_MR_DTFP 0x00100000 +#define TAH_MR_DIG 0x00080000 + +#ifdef CONFIG_IBM_NEW_EMAC_TAH + +extern int tah_init(void); +extern void tah_exit(void); +extern int tah_attach(struct of_device *ofdev, int channel); +extern void tah_detach(struct of_device *ofdev, int channel); +extern void tah_reset(struct of_device *ofdev); +extern int tah_get_regs_len(struct of_device *ofdev); +extern void *tah_dump_regs(struct of_device *ofdev, void *buf); + +#else + +# define tah_init() 0 +# define tah_exit() do { } while(0) +# define tah_attach(x,y) (-ENXIO) +# define tah_detach(x,y) do { } while(0) +# define tah_reset(x) do { } while(0) +# define tah_get_regs_len(x) 0 +# define tah_dump_regs(x,buf) (buf) + +#endif /* !CONFIG_IBM_NEW_EMAC_TAH */ + +#endif /* __IBM_NEWEMAC_TAH_H */ diff --git a/drivers/net/ibm_newemac/zmii.c b/drivers/net/ibm_newemac/zmii.c new file mode 100644 index 00000000000..d0631290184 --- /dev/null +++ b/drivers/net/ibm_newemac/zmii.c @@ -0,0 +1,322 @@ +/* + * drivers/net/ibm_newemac/zmii.c + * + * Driver for PowerPC 4xx on-chip ethernet controller, ZMII bridge support. + * + * Copyright (c) 2004, 2005 Zultys Technologies. + * Eugene Surovegin or + * + * Based on original work by + * Armin Kuster + * Copyright 2001 MontaVista Softare Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#include +#include +#include + +#include "emac.h" +#include "core.h" + +/* ZMIIx_FER */ +#define ZMII_FER_MDI(idx) (0x80000000 >> ((idx) * 4)) +#define ZMII_FER_MDI_ALL (ZMII_FER_MDI(0) | ZMII_FER_MDI(1) | \ + ZMII_FER_MDI(2) | ZMII_FER_MDI(3)) + +#define ZMII_FER_SMII(idx) (0x40000000 >> ((idx) * 4)) +#define ZMII_FER_RMII(idx) (0x20000000 >> ((idx) * 4)) +#define ZMII_FER_MII(idx) (0x10000000 >> ((idx) * 4)) + +/* ZMIIx_SSR */ +#define ZMII_SSR_SCI(idx) (0x40000000 >> ((idx) * 4)) +#define ZMII_SSR_FSS(idx) (0x20000000 >> ((idx) * 4)) +#define ZMII_SSR_SP(idx) (0x10000000 >> ((idx) * 4)) + +/* ZMII only supports MII, RMII and SMII + * we also support autodetection for backward compatibility + */ +static inline int zmii_valid_mode(int mode) +{ + return mode == PHY_MODE_MII || + mode == PHY_MODE_RMII || + mode == PHY_MODE_SMII || + mode == PHY_MODE_NA; +} + +static inline const char *zmii_mode_name(int mode) +{ + switch (mode) { + case PHY_MODE_MII: + return "MII"; + case PHY_MODE_RMII: + return "RMII"; + case PHY_MODE_SMII: + return "SMII"; + default: + BUG(); + } +} + +static inline u32 zmii_mode_mask(int mode, int input) +{ + switch (mode) { + case PHY_MODE_MII: + return ZMII_FER_MII(input); + case PHY_MODE_RMII: + return ZMII_FER_RMII(input); + case PHY_MODE_SMII: + return ZMII_FER_SMII(input); + default: + return 0; + } +} + +int __devinit zmii_attach(struct of_device *ofdev, int input, int *mode) +{ + struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev); + struct zmii_regs *p = dev->base; + + ZMII_DBG(dev, "init(%d, %d)" NL, input, *mode); + + if (!zmii_valid_mode(*mode)) + /* Probably an EMAC connected to RGMII, + * but it still may need ZMII for MDIO so + * we don't fail here. + */ + return 0; + + mutex_lock(&dev->lock); + + /* Autodetect ZMII mode if not specified. + * This is only for backward compatibility with the old driver. + * Please, always specify PHY mode in your board port to avoid + * any surprises. + */ + if (dev->mode == PHY_MODE_NA) { + if (*mode == PHY_MODE_NA) { + u32 r = dev->fer_save; + + ZMII_DBG(dev, "autodetecting mode, FER = 0x%08x" NL, r); + + if (r & (ZMII_FER_MII(0) | ZMII_FER_MII(1))) + dev->mode = PHY_MODE_MII; + else if (r & (ZMII_FER_RMII(0) | ZMII_FER_RMII(1))) + dev->mode = PHY_MODE_RMII; + else + dev->mode = PHY_MODE_SMII; + } else + dev->mode = *mode; + + printk(KERN_NOTICE "%s: bridge in %s mode\n", + ofdev->node->full_name, zmii_mode_name(dev->mode)); + } else { + /* All inputs must use the same mode */ + if (*mode != PHY_MODE_NA && *mode != dev->mode) { + printk(KERN_ERR + "%s: invalid mode %d specified for input %d\n", + ofdev->node->full_name, *mode, input); + mutex_unlock(&dev->lock); + return -EINVAL; + } + } + + /* Report back correct PHY mode, + * it may be used during PHY initialization. + */ + *mode = dev->mode; + + /* Enable this input */ + out_be32(&p->fer, in_be32(&p->fer) | zmii_mode_mask(dev->mode, input)); + ++dev->users; + + mutex_unlock(&dev->lock); + + return 0; +} + +void zmii_get_mdio(struct of_device *ofdev, int input) +{ + struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev); + u32 fer; + + ZMII_DBG2(dev, "get_mdio(%d)" NL, input); + + mutex_lock(&dev->lock); + + fer = in_be32(&dev->base->fer) & ~ZMII_FER_MDI_ALL; + out_be32(&dev->base->fer, fer | ZMII_FER_MDI(input)); +} + +void zmii_put_mdio(struct of_device *ofdev, int input) +{ + struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev); + + ZMII_DBG2(dev, "put_mdio(%d)" NL, input); + mutex_unlock(&dev->lock); +} + + +void zmii_set_speed(struct of_device *ofdev, int input, int speed) +{ + struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev); + u32 ssr; + + mutex_lock(&dev->lock); + + ssr = in_be32(&dev->base->ssr); + + ZMII_DBG(dev, "speed(%d, %d)" NL, input, speed); + + if (speed == SPEED_100) + ssr |= ZMII_SSR_SP(input); + else + ssr &= ~ZMII_SSR_SP(input); + + out_be32(&dev->base->ssr, ssr); + + mutex_unlock(&dev->lock); +} + +void __devexit zmii_detach(struct of_device *ofdev, int input) +{ + struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev); + + BUG_ON(!dev || dev->users == 0); + + mutex_lock(&dev->lock); + + ZMII_DBG(dev, "detach(%d)" NL, input); + + /* Disable this input */ + out_be32(&dev->base->fer, + in_be32(&dev->base->fer) & ~zmii_mode_mask(dev->mode, input)); + + --dev->users; + + mutex_unlock(&dev->lock); +} + +int zmii_get_regs_len(struct of_device *ofdev) +{ + return sizeof(struct emac_ethtool_regs_subhdr) + + sizeof(struct zmii_regs); +} + +void *zmii_dump_regs(struct of_device *ofdev, void *buf) +{ + struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev); + struct emac_ethtool_regs_subhdr *hdr = buf; + struct zmii_regs *regs = (struct zmii_regs *)(hdr + 1); + + hdr->version = 0; + hdr->index = 0; /* for now, are there chips with more than one + * zmii ? if yes, then we'll add a cell_index + * like we do for emac + */ + memcpy_fromio(regs, dev->base, sizeof(struct zmii_regs)); + return regs + 1; +} + +static int __devinit zmii_probe(struct of_device *ofdev, + const struct of_device_id *match) +{ + struct device_node *np = ofdev->node; + struct zmii_instance *dev; + struct resource regs; + int rc; + + rc = -ENOMEM; + dev = kzalloc(sizeof(struct zmii_instance), GFP_KERNEL); + if (dev == NULL) { + printk(KERN_ERR "%s: could not allocate ZMII device!\n", + np->full_name); + goto err_gone; + } + + mutex_init(&dev->lock); + dev->ofdev = ofdev; + dev->mode = PHY_MODE_NA; + + rc = -ENXIO; + if (of_address_to_resource(np, 0, ®s)) { + printk(KERN_ERR "%s: Can't get registers address\n", + np->full_name); + goto err_free; + } + + rc = -ENOMEM; + dev->base = (struct zmii_regs *)ioremap(regs.start, + sizeof(struct zmii_regs)); + if (dev->base == NULL) { + printk(KERN_ERR "%s: Can't map device registers!\n", + np->full_name); + goto err_free; + } + + /* We may need FER value for autodetection later */ + dev->fer_save = in_be32(&dev->base->fer); + + /* Disable all inputs by default */ + out_be32(&dev->base->fer, 0); + + printk(KERN_INFO + "ZMII %s initialized\n", ofdev->node->full_name); + wmb(); + dev_set_drvdata(&ofdev->dev, dev); + + return 0; + + err_free: + kfree(dev); + err_gone: + return rc; +} + +static int __devexit zmii_remove(struct of_device *ofdev) +{ + struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev); + + dev_set_drvdata(&ofdev->dev, NULL); + + WARN_ON(dev->users != 0); + + iounmap(dev->base); + kfree(dev); + + return 0; +} + +static struct of_device_id zmii_match[] = +{ + { + .compatible = "ibm,zmii", + }, + /* For backward compat with old DT */ + { + .type = "emac-zmii", + }, + {}, +}; + +static struct of_platform_driver zmii_driver = { + .name = "emac-zmii", + .match_table = zmii_match, + + .probe = zmii_probe, + .remove = zmii_remove, +}; + +int __init zmii_init(void) +{ + return of_register_platform_driver(&zmii_driver); +} + +void zmii_exit(void) +{ + of_unregister_platform_driver(&zmii_driver); +} diff --git a/drivers/net/ibm_newemac/zmii.h b/drivers/net/ibm_newemac/zmii.h new file mode 100644 index 00000000000..82a9968b1f7 --- /dev/null +++ b/drivers/net/ibm_newemac/zmii.h @@ -0,0 +1,73 @@ +/* + * drivers/net/ibm_newemac/zmii.h + * + * Driver for PowerPC 4xx on-chip ethernet controller, ZMII bridge support. + * + * Copyright (c) 2004, 2005 Zultys Technologies. + * Eugene Surovegin or + * + * Based on original work by + * Armin Kuster + * Copyright 2001 MontaVista Softare Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#ifndef __IBM_NEWEMAC_ZMII_H +#define __IBM_NEWEMAC_ZMII_H + +/* ZMII bridge registers */ +struct zmii_regs { + u32 fer; /* Function enable reg */ + u32 ssr; /* Speed select reg */ + u32 smiirs; /* SMII status reg */ +}; + +/* ZMII device */ +struct zmii_instance { + struct zmii_regs __iomem *base; + + /* Only one EMAC whacks us at a time */ + struct mutex lock; + + /* subset of PHY_MODE_XXXX */ + int mode; + + /* number of EMACs using this ZMII bridge */ + int users; + + /* FER value left by firmware */ + u32 fer_save; + + /* OF device instance */ + struct of_device *ofdev; +}; + +#ifdef CONFIG_IBM_NEW_EMAC_ZMII + +extern int zmii_init(void); +extern void zmii_exit(void); +extern int zmii_attach(struct of_device *ofdev, int input, int *mode); +extern void zmii_detach(struct of_device *ofdev, int input); +extern void zmii_get_mdio(struct of_device *ofdev, int input); +extern void zmii_put_mdio(struct of_device *ofdev, int input); +extern void zmii_set_speed(struct of_device *ofdev, int input, int speed); +extern int zmii_get_regs_len(struct of_device *ocpdev); +extern void *zmii_dump_regs(struct of_device *ofdev, void *buf); + +#else +# define zmii_init() 0 +# define zmii_exit() do { } while(0) +# define zmii_attach(x,y,z) (-ENXIO) +# define zmii_detach(x,y) do { } while(0) +# define zmii_get_mdio(x,y) do { } while(0) +# define zmii_put_mdio(x,y) do { } while(0) +# define zmii_set_speed(x,y,z) do { } while(0) +# define zmii_get_regs_len(x) 0 +# define zmii_dump_regs(x,buf) (buf) +#endif /* !CONFIG_IBM_NEW_EMAC_ZMII */ + +#endif /* __IBM_NEWEMAC_ZMII_H */ -- cgit v1.2.3-70-g09d2 From 200eef20db6de7535438c9af9becc8169c6cb6c0 Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Mon, 3 Sep 2007 10:33:35 +0530 Subject: netxen: ethtool fixes Resubmitting the patch. This patch improves ethtool support for printing correct ring statistics, segmentation offload status, etc. Signed-off by: Dhananjay Phadke Signed-off-by: Jeff Garzik --- drivers/net/netxen/netxen_nic.h | 2 +- drivers/net/netxen/netxen_nic_ethtool.c | 27 +++++++++++++++++++++------ drivers/net/netxen/netxen_nic_init.c | 7 +++++-- drivers/net/netxen/netxen_nic_main.c | 1 + 4 files changed, 28 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 7bbd5d14175..fbc2553275d 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -919,7 +919,7 @@ struct netxen_adapter { u16 link_duplex; u16 state; u16 link_autoneg; - int rcsum; + int rx_csum; int status; spinlock_t stats_lock; diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index 78e42316e70..cfb847b0cae 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c @@ -516,17 +516,17 @@ netxen_nic_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ring) ring->rx_jumbo_pending = 0; for (i = 0; i < MAX_RCV_CTX; ++i) { ring->rx_pending += adapter->recv_ctx[i]. - rcv_desc[RCV_DESC_NORMAL_CTXID].rcv_pending; + rcv_desc[RCV_DESC_NORMAL_CTXID].max_rx_desc_count; ring->rx_jumbo_pending += adapter->recv_ctx[i]. - rcv_desc[RCV_DESC_JUMBO_CTXID].rcv_pending; + rcv_desc[RCV_DESC_JUMBO_CTXID].max_rx_desc_count; } + ring->tx_pending = adapter->max_tx_desc_count; - ring->rx_max_pending = adapter->max_rx_desc_count; - ring->tx_max_pending = adapter->max_tx_desc_count; - ring->rx_jumbo_max_pending = adapter->max_jumbo_rx_desc_count; + ring->rx_max_pending = MAX_RCV_DESCRIPTORS; + ring->tx_max_pending = MAX_CMD_DESCRIPTORS_HOST; + ring->rx_jumbo_max_pending = MAX_JUMBO_RCV_DESCRIPTORS; ring->rx_mini_max_pending = 0; ring->rx_mini_pending = 0; - ring->rx_jumbo_pending = 0; } static void @@ -731,6 +731,19 @@ netxen_nic_get_ethtool_stats(struct net_device *dev, } } +static u32 netxen_nic_get_rx_csum(struct net_device *dev) +{ + struct netxen_adapter *adapter = netdev_priv(dev); + return adapter->rx_csum; +} + +static int netxen_nic_set_rx_csum(struct net_device *dev, u32 data) +{ + struct netxen_adapter *adapter = netdev_priv(dev); + adapter->rx_csum = !!data; + return 0; +} + struct ethtool_ops netxen_nic_ethtool_ops = { .get_settings = netxen_nic_get_settings, .set_settings = netxen_nic_set_settings, @@ -751,4 +764,6 @@ struct ethtool_ops netxen_nic_ethtool_ops = { .get_strings = netxen_nic_get_strings, .get_ethtool_stats = netxen_nic_get_ethtool_stats, .get_sset_count = netxen_get_sset_count, + .get_rx_csum = netxen_nic_get_rx_csum, + .set_rx_csum = netxen_nic_set_rx_csum, }; diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 1811bcb8c38..37589265297 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -1118,10 +1118,13 @@ netxen_process_rcv(struct netxen_adapter *adapter, int ctxid, skb = (struct sk_buff *)buffer->skb; - if (likely(netxen_get_sts_status(desc) == STATUS_CKSUM_OK)) { + if (likely(adapter->rx_csum && + netxen_get_sts_status(desc) == STATUS_CKSUM_OK)) { adapter->stats.csummed++; skb->ip_summed = CHECKSUM_UNNECESSARY; - } + } else + skb->ip_summed = CHECKSUM_NONE; + skb->dev = netdev; if (desc_ctx == RCV_DESC_LRO_CTXID) { /* True length was only available on the last pkt */ diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index b9cde65e7f3..2a1d6d7ec35 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -409,6 +409,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* This will be reset for mezz cards */ adapter->portnum = pci_func_id; adapter->status &= ~NETXEN_NETDEV_STATUS; + adapter->rx_csum = 1; netdev->open = netxen_nic_open; netdev->stop = netxen_nic_close; -- cgit v1.2.3-70-g09d2 From 25a72dfe044a716222d7adb4f075afc62ed4061f Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Fri, 14 Sep 2007 11:57:33 +0100 Subject: NET_SB1250_MAC: Update Kconfig entry The SB1250 network interfaces are Gigabit Ethernet ones. Move the Kconfig entry to the appropriate section and add some help text. Signed-off-by: Maciej W. Rozycki Signed-off-by: Jeff Garzik --- drivers/net/Kconfig | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index cfa97f3fbeb..53615374f16 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -481,10 +481,6 @@ config MIPS_AU1X00_ENET If you have an Alchemy Semi AU1X00 based system say Y. Otherwise, say N. -config NET_SB1250_MAC - tristate "SB1250 Ethernet support" - depends on SIBYTE_SB1xxx_SOC - config SGI_IOC3_ETH bool "SGI IOC3 Ethernet" depends on PCI && SGI_IP27 @@ -2127,6 +2123,18 @@ config R8169_VLAN If in doubt, say Y. +config NET_SB1250_MAC + tristate "SB1250 Gigabit Ethernet support" + depends on SIBYTE_SB1xxx_SOC + ---help--- + This driver supports Gigabit Ethernet interfaces based on the + Broadcom SiByte family of System-On-a-Chip parts. They include + the BCM1120, BCM1125, BCM1125H, BCM1250, BCM1255, BCM1280, BCM1455 + and BCM1480 chips. + + To compile this driver as a module, choose M here: the module + will be called sb1250-mac. + config SIS190 tristate "SiS190/SiS191 gigabit ethernet support" depends on PCI -- cgit v1.2.3-70-g09d2 From 1a9e8549efda23a08451d0ac582713dfd04f0951 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Fri, 14 Sep 2007 12:05:00 +0100 Subject: NET_SB1250_MAC: Rename to SB1250_MAC Rename NET_SB1250_MAC to SB1250_MAC to follow the convention. Signed-off-by: Maciej W. Rozycki Signed-off-by: Jeff Garzik --- arch/mips/configs/bigsur_defconfig | 2 +- arch/mips/configs/sb1250-swarm_defconfig | 2 +- drivers/net/Kconfig | 2 +- drivers/net/Makefile | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/arch/mips/configs/bigsur_defconfig b/arch/mips/configs/bigsur_defconfig index 700a3a2d688..9861fe670d8 100644 --- a/arch/mips/configs/bigsur_defconfig +++ b/arch/mips/configs/bigsur_defconfig @@ -574,7 +574,7 @@ CONFIG_MII=y # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set # CONFIG_R8169 is not set -CONFIG_NET_SB1250_MAC=y +CONFIG_SB1250_MAC=y # CONFIG_SIS190 is not set # CONFIG_SKGE is not set # CONFIG_SKY2 is not set diff --git a/arch/mips/configs/sb1250-swarm_defconfig b/arch/mips/configs/sb1250-swarm_defconfig index 93f9e8331ad..2f28557f3d7 100644 --- a/arch/mips/configs/sb1250-swarm_defconfig +++ b/arch/mips/configs/sb1250-swarm_defconfig @@ -566,7 +566,7 @@ CONFIG_MII=y # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set # CONFIG_R8169 is not set -CONFIG_NET_SB1250_MAC=y +CONFIG_SB1250_MAC=y # CONFIG_SIS190 is not set # CONFIG_SKGE is not set # CONFIG_SKY2 is not set diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 53615374f16..467532c7975 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2123,7 +2123,7 @@ config R8169_VLAN If in doubt, say Y. -config NET_SB1250_MAC +config SB1250_MAC tristate "SB1250 Gigabit Ethernet support" depends on SIBYTE_SB1xxx_SOC ---help--- diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 9cbef582987..6220c50596e 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -111,7 +111,7 @@ obj-$(CONFIG_E2100) += e2100.o 8390.o obj-$(CONFIG_ES3210) += es3210.o 8390.o obj-$(CONFIG_LNE390) += lne390.o 8390.o obj-$(CONFIG_NE3210) += ne3210.o 8390.o -obj-$(CONFIG_NET_SB1250_MAC) += sb1250-mac.o +obj-$(CONFIG_SB1250_MAC) += sb1250-mac.o obj-$(CONFIG_B44) += b44.o obj-$(CONFIG_FORCEDETH) += forcedeth.o obj-$(CONFIG_NE_H8300) += ne-h8300.o -- cgit v1.2.3-70-g09d2 From aa90f5032129b43569896c1c6c15a706c02c6abf Mon Sep 17 00:00:00 2001 From: Vitaly Bordug Date: Tue, 18 Sep 2007 20:05:27 +0400 Subject: FS_ENET: TX stuff should use fep->tx_lock, instead of fep->lock. Signed-off-by: Vitaly Bordug Signed-off-by: Jeff Garzik --- drivers/net/fs_enet/fs_enet-main.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index f9079599dd2..83c9bf27ecf 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -335,7 +335,7 @@ static void fs_enet_tx(struct net_device *dev) int dirtyidx, do_wake, do_restart; u16 sc; - spin_lock(&fep->lock); + spin_lock(&fep->tx_lock); bdp = fep->dirty_tx; do_wake = do_restart = 0; @@ -415,7 +415,7 @@ static void fs_enet_tx(struct net_device *dev) if (do_restart) (*fep->ops->tx_restart)(dev); - spin_unlock(&fep->lock); + spin_unlock(&fep->tx_lock); if (do_wake) netif_wake_queue(dev); @@ -818,7 +818,9 @@ static int fs_enet_close(struct net_device *dev) phy_stop(fep->phydev); spin_lock_irqsave(&fep->lock, flags); + spin_lock(&fep->tx_lock); (*fep->ops->stop)(dev); + spin_unlock(&fep->tx_lock); spin_unlock_irqrestore(&fep->lock, flags); /* release any irqs */ -- cgit v1.2.3-70-g09d2 From 9b8ee8e7d6b7f2270b19b3425a393d918fe497d3 Mon Sep 17 00:00:00 2001 From: Vitaly Bordug Date: Tue, 18 Sep 2007 20:05:35 +0400 Subject: FS_ENET: Add polling support Signed-off-by: Vitaly Bordug Signed-off-by: Jeff Garzik --- drivers/net/fs_enet/fs_enet-main.c | 71 +++++++++++++++++++++++--------------- drivers/net/fs_enet/mac-fcc.c | 12 +++---- drivers/net/fs_enet/mac-fec.c | 30 ++++++++-------- drivers/net/fs_enet/mac-scc.c | 20 +++++------ drivers/net/fs_enet/mii-bitbang.c | 10 +++--- 5 files changed, 80 insertions(+), 63 deletions(-) (limited to 'drivers') diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index 83c9bf27ecf..dcbe83c773e 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -1,17 +1,17 @@ /* * Combined Ethernet driver for Motorola MPC8xx and MPC82xx. * - * Copyright (c) 2003 Intracom S.A. + * Copyright (c) 2003 Intracom S.A. * by Pantelis Antoniou - * - * 2005 (c) MontaVista Software, Inc. + * + * 2005 (c) MontaVista Software, Inc. * Vitaly Bordug * * Heavily based on original FEC driver by Dan Malek * and modifications by Joakim Tjernlund * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any * kind, whether express or implied. */ @@ -59,6 +59,9 @@ module_param(fs_enet_debug, int, 0); MODULE_PARM_DESC(fs_enet_debug, "Freescale bitmapped debugging message enable value"); +#ifdef CONFIG_NET_POLL_CONTROLLER +static void fs_enet_netpoll(struct net_device *dev); +#endif static void fs_set_multicast_list(struct net_device *dev) { @@ -104,7 +107,7 @@ static int fs_enet_rx_napi(struct napi_struct *napi, int budget) dev->name); /* - * Check for errors. + * Check for errors. */ if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_CL | BD_ENET_RX_NO | BD_ENET_RX_CR | BD_ENET_RX_OV)) { @@ -181,7 +184,7 @@ static int fs_enet_rx_napi(struct napi_struct *napi, int budget) CBDW_SC(bdp, (sc & ~BD_ENET_RX_STATS) | BD_ENET_RX_EMPTY); /* - * Update BD pointer to next entry. + * Update BD pointer to next entry. */ if ((sc & BD_ENET_RX_WRAP) == 0) bdp++; @@ -234,7 +237,7 @@ static int fs_enet_rx_non_napi(struct net_device *dev) dev->name); /* - * Check for errors. + * Check for errors. */ if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_CL | BD_ENET_RX_NO | BD_ENET_RX_CR | BD_ENET_RX_OV)) { @@ -312,7 +315,7 @@ static int fs_enet_rx_non_napi(struct net_device *dev) CBDW_SC(bdp, (sc & ~BD_ENET_RX_STATS) | BD_ENET_RX_EMPTY); /* - * Update BD pointer to next entry. + * Update BD pointer to next entry. */ if ((sc & BD_ENET_RX_WRAP) == 0) bdp++; @@ -349,7 +352,7 @@ static void fs_enet_tx(struct net_device *dev) skb = fep->tx_skbuff[dirtyidx]; /* - * Check for errors. + * Check for errors. */ if (sc & (BD_ENET_TX_HB | BD_ENET_TX_LC | BD_ENET_TX_RL | BD_ENET_TX_UN | BD_ENET_TX_CSL)) { @@ -389,13 +392,13 @@ static void fs_enet_tx(struct net_device *dev) skb->len, DMA_TO_DEVICE); /* - * Free the sk buffer associated with this last transmit. + * Free the sk buffer associated with this last transmit. */ dev_kfree_skb_irq(skb); fep->tx_skbuff[dirtyidx] = NULL; /* - * Update pointer to next buffer descriptor to be transmitted. + * Update pointer to next buffer descriptor to be transmitted. */ if ((sc & BD_ENET_TX_WRAP) == 0) bdp++; @@ -491,7 +494,7 @@ void fs_init_bds(struct net_device *dev) fep->cur_rx = fep->rx_bd_base; /* - * Initialize the receive buffer descriptors. + * Initialize the receive buffer descriptors. */ for (i = 0, bdp = fep->rx_bd_base; i < fep->rx_ring; i++, bdp++) { skb = dev_alloc_skb(ENET_RX_FRSIZE); @@ -511,7 +514,7 @@ void fs_init_bds(struct net_device *dev) ((i < fep->rx_ring - 1) ? 0 : BD_SC_WRAP)); } /* - * if we failed, fillup remainder + * if we failed, fillup remainder */ for (; i < fep->rx_ring; i++, bdp++) { fep->rx_skbuff[i] = NULL; @@ -519,7 +522,7 @@ void fs_init_bds(struct net_device *dev) } /* - * ...and the same for transmit. + * ...and the same for transmit. */ for (i = 0, bdp = fep->tx_bd_base; i < fep->tx_ring; i++, bdp++) { fep->tx_skbuff[i] = NULL; @@ -537,7 +540,7 @@ void fs_cleanup_bds(struct net_device *dev) int i; /* - * Reset SKB transmit buffers. + * Reset SKB transmit buffers. */ for (i = 0, bdp = fep->tx_bd_base; i < fep->tx_ring; i++, bdp++) { if ((skb = fep->tx_skbuff[i]) == NULL) @@ -552,7 +555,7 @@ void fs_cleanup_bds(struct net_device *dev) } /* - * Reset SKB receive buffers + * Reset SKB receive buffers */ for (i = 0, bdp = fep->rx_bd_base; i < fep->rx_ring; i++, bdp++) { if ((skb = fep->rx_skbuff[i]) == NULL) @@ -582,7 +585,7 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_lock_irqsave(&fep->tx_lock, flags); /* - * Fill in a Tx ring entry + * Fill in a Tx ring entry */ bdp = fep->cur_tx; @@ -601,19 +604,19 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) curidx = bdp - fep->tx_bd_base; /* - * Clear all of the status flags. + * Clear all of the status flags. */ CBDC_SC(bdp, BD_ENET_TX_STATS); /* - * Save skb pointer. + * Save skb pointer. */ fep->tx_skbuff[curidx] = skb; fep->stats.tx_bytes += skb->len; /* - * Push the data cache so the CPM does not get stale memory data. + * Push the data cache so the CPM does not get stale memory data. */ CBDW_BUFADDR(bdp, dma_map_single(fep->dev, skb->data, skb->len, DMA_TO_DEVICE)); @@ -622,7 +625,7 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; /* - * If this was the last BD in the ring, start at the beginning again. + * If this was the last BD in the ring, start at the beginning again. */ if ((CBDR_SC(bdp) & BD_ENET_TX_WRAP) == 0) fep->cur_tx++; @@ -1003,13 +1006,13 @@ static struct net_device *fs_init_instance(struct device *dev, spin_lock_init(&fep->tx_lock); /* - * Set the Ethernet address. + * Set the Ethernet address. */ for (i = 0; i < 6; i++) ndev->dev_addr[i] = fpi->macaddr[i]; - + r = (*fep->ops->allocate_bd)(ndev); - + if (fep->ring_base == NULL) { printk(KERN_ERR DRV_MODULE_NAME ": %s buffer descriptor alloc failed (%d).\n", ndev->name, r); @@ -1028,7 +1031,7 @@ static struct net_device *fs_init_instance(struct device *dev, fep->rx_ring = fpi->rx_ring; /* - * The FEC Ethernet specific entries in the device structure. + * The FEC Ethernet specific entries in the device structure. */ ndev->open = fs_enet_open; ndev->hard_start_xmit = fs_enet_start_xmit; @@ -1037,6 +1040,11 @@ static struct net_device *fs_init_instance(struct device *dev, ndev->stop = fs_enet_close; ndev->get_stats = fs_enet_get_stats; ndev->set_multicast_list = fs_set_multicast_list; + +#ifdef CONFIG_NET_POLL_CONTROLLER + ndev->poll_controller = fs_enet_netpoll; +#endif + netif_napi_add(ndev, &fep->napi, fs_enet_rx_napi, fpi->napi_weight); @@ -1251,7 +1259,7 @@ static int __init fs_init(void) err: cleanup_immap(); return r; - + } static void __exit fs_cleanup(void) @@ -1262,6 +1270,15 @@ static void __exit fs_cleanup(void) cleanup_immap(); } +#ifdef CONFIG_NET_POLL_CONTROLLER +static void fs_enet_netpoll(struct net_device *dev) +{ + disable_irq(dev->irq); + fs_enet_interrupt(dev->irq, dev, NULL); + enable_irq(dev->irq); +} +#endif + /**************************************************************************************/ module_init(fs_init); diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c index 5603121132c..64071514d7d 100644 --- a/drivers/net/fs_enet/mac-fcc.c +++ b/drivers/net/fs_enet/mac-fcc.c @@ -1,14 +1,14 @@ /* * FCC driver for Motorola MPC82xx (PQ2). * - * Copyright (c) 2003 Intracom S.A. + * Copyright (c) 2003 Intracom S.A. * by Pantelis Antoniou * - * 2005 (c) MontaVista Software, Inc. + * 2005 (c) MontaVista Software, Inc. * Vitaly Bordug * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any * kind, whether express or implied. */ @@ -92,7 +92,7 @@ static inline int fcc_cr_cmd(struct fs_enet_private *fep, u32 mcn, u32 op) u32 v; int i; - /* Currently I don't know what feature call will look like. But + /* Currently I don't know what feature call will look like. But I guess there'd be something like do_cpm_cmd() which will require page & sblock */ v = mk_cr_cmd(fpi->cp_page, fpi->cp_block, mcn, op); W32(cpmp, cp_cpcr, v | CPM_CR_FLG); @@ -548,7 +548,7 @@ int get_regs_len(struct net_device *dev) * down. We now issue a restart transmit. Since the * errors close the BD and update the pointers, the restart * _should_ pick up without having to reset any of our - * pointers either. Also, To workaround 8260 device erratum + * pointers either. Also, To workaround 8260 device erratum * CPM37, we must disable and then re-enable the transmitter * following a Late Collision, Underrun, or Retry Limit error. */ diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c index 04b4f80a1cd..cbdc17b743d 100644 --- a/drivers/net/fs_enet/mac-fec.c +++ b/drivers/net/fs_enet/mac-fec.c @@ -1,14 +1,14 @@ /* * Freescale Ethernet controllers * - * Copyright (c) 2005 Intracom S.A. + * Copyright (c) 2005 Intracom S.A. * by Pantelis Antoniou * - * 2005 (c) MontaVista Software, Inc. + * 2005 (c) MontaVista Software, Inc. * Vitaly Bordug * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any * kind, whether express or implied. */ @@ -95,9 +95,9 @@ static int whack_reset(fec_t * fecp) static int do_pd_setup(struct fs_enet_private *fep) { - struct platform_device *pdev = to_platform_device(fep->dev); + struct platform_device *pdev = to_platform_device(fep->dev); struct resource *r; - + /* Fill out IRQ field */ fep->interrupt = platform_get_irq_byname(pdev,"interrupt"); if (fep->interrupt < 0) @@ -110,7 +110,7 @@ static int do_pd_setup(struct fs_enet_private *fep) return -EINVAL; return 0; - + } #define FEC_NAPI_RX_EVENT_MSK (FEC_ENET_RXF | FEC_ENET_RXB) @@ -141,7 +141,7 @@ static int allocate_bd(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); const struct fs_platform_info *fpi = fep->fpi; - + fep->ring_base = dma_alloc_coherent(fep->dev, (fpi->tx_ring + fpi->rx_ring) * sizeof(cbd_t), &fep->ring_mem_addr, @@ -280,13 +280,13 @@ static void restart(struct net_device *dev) FW(fecp, addr_high, addrlo); /* - * Reset all multicast. + * Reset all multicast. */ FW(fecp, hash_table_high, fep->fec.hthi); FW(fecp, hash_table_low, fep->fec.htlo); /* - * Set maximum receive buffer size. + * Set maximum receive buffer size. */ FW(fecp, r_buff_size, PKT_MAXBLR_SIZE); FW(fecp, r_hash, PKT_MAXBUF_SIZE); @@ -296,7 +296,7 @@ static void restart(struct net_device *dev) tx_bd_base_phys = rx_bd_base_phys + sizeof(cbd_t) * fpi->rx_ring; /* - * Set receive and transmit descriptor base. + * Set receive and transmit descriptor base. */ FW(fecp, r_des_start, rx_bd_base_phys); FW(fecp, x_des_start, tx_bd_base_phys); @@ -304,7 +304,7 @@ static void restart(struct net_device *dev) fs_init_bds(dev); /* - * Enable big endian and don't care about SDMA FC. + * Enable big endian and don't care about SDMA FC. */ FW(fecp, fun_code, 0x78000000); @@ -366,13 +366,13 @@ static void restart(struct net_device *dev) } /* - * Enable interrupts we wish to service. + * Enable interrupts we wish to service. */ FW(fecp, imask, FEC_ENET_TXF | FEC_ENET_TXB | FEC_ENET_RXF | FEC_ENET_RXB); /* - * And last, enable the transmit and receive processing. + * And last, enable the transmit and receive processing. */ FW(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN); FW(fecp, r_des_active, 0x01000000); @@ -401,7 +401,7 @@ static void stop(struct net_device *dev) ": %s FEC timeout on graceful transmit stop\n", dev->name); /* - * Disable FEC. Let only MII interrupts. + * Disable FEC. Let only MII interrupts. */ FW(fecp, imask, 0); FC(fecp, ecntrl, FEC_ECNTRL_ETHER_EN); diff --git a/drivers/net/fs_enet/mac-scc.c b/drivers/net/fs_enet/mac-scc.c index 7540966687e..6f32674a78e 100644 --- a/drivers/net/fs_enet/mac-scc.c +++ b/drivers/net/fs_enet/mac-scc.c @@ -1,14 +1,14 @@ /* * Ethernet on Serial Communications Controller (SCC) driver for Motorola MPC8xx and MPC82xx. * - * Copyright (c) 2003 Intracom S.A. + * Copyright (c) 2003 Intracom S.A. * by Pantelis Antoniou - * - * 2005 (c) MontaVista Software, Inc. + * + * 2005 (c) MontaVista Software, Inc. * Vitaly Bordug * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any * kind, whether express or implied. */ @@ -82,7 +82,7 @@ #define SCC_MAX_MULTICAST_ADDRS 64 /* - * Delay to wait for SCC reset command to complete (in us) + * Delay to wait for SCC reset command to complete (in us) */ #define SCC_RESET_DELAY 50 #define MAX_CR_CMD_LOOPS 10000 @@ -189,7 +189,7 @@ static void cleanup_data(struct net_device *dev) } static void set_promiscuous_mode(struct net_device *dev) -{ +{ struct fs_enet_private *fep = netdev_priv(dev); scc_t *sccp = fep->scc.sccp; @@ -323,7 +323,7 @@ static void restart(struct net_device *dev) W16(ep, sen_iaddr3, 0); W16(ep, sen_iaddr4, 0); - /* set address + /* set address */ mac = dev->dev_addr; paddrh = ((u16) mac[5] << 8) | mac[4]; @@ -345,7 +345,7 @@ static void restart(struct net_device *dev) W16(sccp, scc_scce, 0xffff); - /* Enable interrupts we wish to service. + /* Enable interrupts we wish to service. */ W16(sccp, scc_sccm, SCCE_ENET_TXE | SCCE_ENET_RXF | SCCE_ENET_TXB); @@ -373,7 +373,7 @@ static void restart(struct net_device *dev) S32(sccp, scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); } -static void stop(struct net_device *dev) +static void stop(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); scc_t *sccp = fep->scc.sccp; diff --git a/drivers/net/fs_enet/mii-bitbang.c b/drivers/net/fs_enet/mii-bitbang.c index d3840108ffb..1a41ea60f98 100644 --- a/drivers/net/fs_enet/mii-bitbang.c +++ b/drivers/net/fs_enet/mii-bitbang.c @@ -1,14 +1,14 @@ /* * Combined Ethernet driver for Motorola MPC8xx and MPC82xx. * - * Copyright (c) 2003 Intracom S.A. + * Copyright (c) 2003 Intracom S.A. * by Pantelis Antoniou - * - * 2005 (c) MontaVista Software, Inc. + * + * 2005 (c) MontaVista Software, Inc. * Vitaly Bordug * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any * kind, whether express or implied. */ -- cgit v1.2.3-70-g09d2 From d3bb52b0948cf118131c951c5a34a2d4d0246171 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 22 Aug 2007 20:06:58 -0400 Subject: endianness annotations drivers/net/bonding/ Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/bonding/bond_3ad.c | 42 +++++++++------------------------------- drivers/net/bonding/bond_3ad.h | 20 +++++++++---------- drivers/net/bonding/bond_alb.c | 19 +++++++++--------- drivers/net/bonding/bond_alb.h | 4 ++-- drivers/net/bonding/bond_main.c | 22 ++++++++++----------- drivers/net/bonding/bond_sysfs.c | 8 ++++---- drivers/net/bonding/bonding.h | 6 +++--- 7 files changed, 48 insertions(+), 73 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index 94bd7394145..7a045a37056 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -101,7 +101,6 @@ static u16 __get_link_speed(struct port *port); static u8 __get_duplex(struct port *port); static inline void __initialize_port_locks(struct port *port); //conversions -static void __htons_lacpdu(struct lacpdu *lacpdu); static u16 __ad_timer_to_ticks(u16 timer_type, u16 Par); @@ -420,26 +419,6 @@ static inline void __initialize_port_locks(struct port *port) } //conversions -/** - * __htons_lacpdu - convert the contents of a LACPDU to network byte order - * @lacpdu: the speicifed lacpdu - * - * For each multi-byte field in the lacpdu, convert its content - */ -static void __htons_lacpdu(struct lacpdu *lacpdu) -{ - if (lacpdu) { - lacpdu->actor_system_priority = htons(lacpdu->actor_system_priority); - lacpdu->actor_key = htons(lacpdu->actor_key); - lacpdu->actor_port_priority = htons(lacpdu->actor_port_priority); - lacpdu->actor_port = htons(lacpdu->actor_port); - lacpdu->partner_system_priority = htons(lacpdu->partner_system_priority); - lacpdu->partner_key = htons(lacpdu->partner_key); - lacpdu->partner_port_priority = htons(lacpdu->partner_port_priority); - lacpdu->partner_port = htons(lacpdu->partner_port); - lacpdu->collector_max_delay = htons(lacpdu->collector_max_delay); - } -} /** * __ad_timer_to_ticks - convert a given timer type to AD module ticks @@ -827,11 +806,11 @@ static inline void __update_lacpdu_from_port(struct port *port) * lacpdu->actor_information_length initialized */ - lacpdu->actor_system_priority = port->actor_system_priority; + lacpdu->actor_system_priority = htons(port->actor_system_priority); lacpdu->actor_system = port->actor_system; - lacpdu->actor_key = port->actor_oper_port_key; - lacpdu->actor_port_priority = port->actor_port_priority; - lacpdu->actor_port = port->actor_port_number; + lacpdu->actor_key = htons(port->actor_oper_port_key); + lacpdu->actor_port_priority = htons(port->actor_port_priority); + lacpdu->actor_port = htons(port->actor_port_number); lacpdu->actor_state = port->actor_oper_port_state; /* lacpdu->reserved_3_1 initialized @@ -839,11 +818,11 @@ static inline void __update_lacpdu_from_port(struct port *port) * lacpdu->partner_information_length initialized */ - lacpdu->partner_system_priority = port->partner_oper_system_priority; + lacpdu->partner_system_priority = htons(port->partner_oper_system_priority); lacpdu->partner_system = port->partner_oper_system; - lacpdu->partner_key = port->partner_oper_key; - lacpdu->partner_port_priority = port->partner_oper_port_priority; - lacpdu->partner_port = port->partner_oper_port_number; + lacpdu->partner_key = htons(port->partner_oper_key); + lacpdu->partner_port_priority = htons(port->partner_oper_port_priority); + lacpdu->partner_port = htons(port->partner_oper_port_number); lacpdu->partner_state = port->partner_oper_port_state; /* lacpdu->reserved_3_2 initialized @@ -855,9 +834,6 @@ static inline void __update_lacpdu_from_port(struct port *port) * terminator_length initialized * reserved_50[50] initialized */ - - /* Convert all non u8 parameters to Big Endian for transmit */ - __htons_lacpdu(lacpdu); } ////////////////////////////////////////////////////////////////////////////////////// @@ -1834,7 +1810,7 @@ static void ad_initialize_lacpdu(struct lacpdu *lacpdu) } lacpdu->tlv_type_collector_info = 0x03; lacpdu->collector_information_length= 0x10; - lacpdu->collector_max_delay = AD_COLLECTOR_MAX_DELAY; + lacpdu->collector_max_delay = htons(AD_COLLECTOR_MAX_DELAY); for (index=0; index<=11; index++) { lacpdu->reserved_12[index]=0; } diff --git a/drivers/net/bonding/bond_3ad.h b/drivers/net/bonding/bond_3ad.h index 6ad5ad6e65d..862952fa6fd 100644 --- a/drivers/net/bonding/bond_3ad.h +++ b/drivers/net/bonding/bond_3ad.h @@ -108,7 +108,7 @@ typedef enum { typedef struct ad_header { struct mac_addr destination_address; struct mac_addr source_address; - u16 length_type; + __be16 length_type; } ad_header_t; // Link Aggregation Control Protocol(LACP) data unit structure(43.4.2.2 in the 802.3ad standard) @@ -117,25 +117,25 @@ typedef struct lacpdu { u8 version_number; u8 tlv_type_actor_info; // = actor information(type/length/value) u8 actor_information_length; // = 20 - u16 actor_system_priority; + __be16 actor_system_priority; struct mac_addr actor_system; - u16 actor_key; - u16 actor_port_priority; - u16 actor_port; + __be16 actor_key; + __be16 actor_port_priority; + __be16 actor_port; u8 actor_state; u8 reserved_3_1[3]; // = 0 u8 tlv_type_partner_info; // = partner information u8 partner_information_length; // = 20 - u16 partner_system_priority; + __be16 partner_system_priority; struct mac_addr partner_system; - u16 partner_key; - u16 partner_port_priority; - u16 partner_port; + __be16 partner_key; + __be16 partner_port_priority; + __be16 partner_port; u8 partner_state; u8 reserved_3_2[3]; // = 0 u8 tlv_type_collector_info; // = collector information u8 collector_information_length; // = 16 - u16 collector_max_delay; + __be16 collector_max_delay; u8 reserved_12[12]; u8 tlv_type_terminator; // = terminator u8 terminator_length; // = 0 diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index 419a9f8fdd5..aea2217c56e 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -87,20 +87,20 @@ static const int alb_delta_in_ticks = HZ / ALB_TIMER_TICKS_PER_SEC; struct learning_pkt { u8 mac_dst[ETH_ALEN]; u8 mac_src[ETH_ALEN]; - u16 type; + __be16 type; u8 padding[ETH_ZLEN - ETH_HLEN]; }; struct arp_pkt { - u16 hw_addr_space; - u16 prot_addr_space; + __be16 hw_addr_space; + __be16 prot_addr_space; u8 hw_addr_len; u8 prot_addr_len; - u16 op_code; + __be16 op_code; u8 mac_src[ETH_ALEN]; /* sender hardware address */ - u32 ip_src; /* sender IP address */ + __be32 ip_src; /* sender IP address */ u8 mac_dst[ETH_ALEN]; /* target hardware address */ - u32 ip_dst; /* target IP address */ + __be32 ip_dst; /* target IP address */ }; #pragma pack() @@ -582,7 +582,7 @@ static void rlb_req_update_slave_clients(struct bonding *bond, struct slave *sla } /* mark all clients using src_ip to be updated */ -static void rlb_req_update_subnet_clients(struct bonding *bond, u32 src_ip) +static void rlb_req_update_subnet_clients(struct bonding *bond, __be32 src_ip) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); struct rlb_client_info *client_info; @@ -1267,7 +1267,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) struct ethhdr *eth_data; struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); struct slave *tx_slave = NULL; - static const u32 ip_bcast = 0xffffffff; + static const __be32 ip_bcast = htonl(0xffffffff); int hash_size = 0; int do_tx_balance = 1; u32 hash_index = 0; @@ -1311,8 +1311,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) hash_size = sizeof(ipv6_hdr(skb)->daddr); break; case ETH_P_IPX: - if (ipx_hdr(skb)->ipx_checksum != - __constant_htons(IPX_NO_CHECKSUM)) { + if (ipx_hdr(skb)->ipx_checksum != IPX_NO_CHECKSUM) { /* something is wrong with this packet */ do_tx_balance = 0; break; diff --git a/drivers/net/bonding/bond_alb.h b/drivers/net/bonding/bond_alb.h index 28f2a2fd1b5..fd872642989 100644 --- a/drivers/net/bonding/bond_alb.h +++ b/drivers/net/bonding/bond_alb.h @@ -60,8 +60,8 @@ struct tlb_client_info { * ------------------------------------------------------------------------- */ struct rlb_client_info { - u32 ip_src; /* the server IP address */ - u32 ip_dst; /* the client IP address */ + __be32 ip_src; /* the server IP address */ + __be32 ip_dst; /* the client IP address */ u8 mac_dst[ETH_ALEN]; /* the client MAC address */ u32 next; /* The next Hash table entry index */ u32 prev; /* The previous Hash table entry index */ diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 8f77db2112c..64bfec32e2a 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -144,7 +144,7 @@ static struct proc_dir_entry *bond_proc_dir = NULL; #endif extern struct rw_semaphore bonding_rwsem; -static u32 arp_target[BOND_MAX_ARP_TARGETS] = { 0, } ; +static __be32 arp_target[BOND_MAX_ARP_TARGETS] = { 0, } ; static int arp_ip_count = 0; static int bond_mode = BOND_MODE_ROUNDROBIN; static int xmit_hashtype= BOND_XMIT_POLICY_LAYER2; @@ -2226,7 +2226,7 @@ out: } -static u32 bond_glean_dev_ip(struct net_device *dev) +static __be32 bond_glean_dev_ip(struct net_device *dev) { struct in_device *idev; struct in_ifaddr *ifa; @@ -2269,7 +2269,7 @@ static int bond_has_ip(struct bonding *bond) return 0; } -static int bond_has_this_ip(struct bonding *bond, u32 ip) +static int bond_has_this_ip(struct bonding *bond, __be32 ip) { struct vlan_entry *vlan, *vlan_next; @@ -2293,7 +2293,7 @@ static int bond_has_this_ip(struct bonding *bond, u32 ip) * switches in VLAN mode (especially if ports are configured as * "native" to a VLAN) might not pass non-tagged frames. */ -static void bond_arp_send(struct net_device *slave_dev, int arp_op, u32 dest_ip, u32 src_ip, unsigned short vlan_id) +static void bond_arp_send(struct net_device *slave_dev, int arp_op, __be32 dest_ip, __be32 src_ip, unsigned short vlan_id) { struct sk_buff *skb; @@ -2321,7 +2321,7 @@ static void bond_arp_send(struct net_device *slave_dev, int arp_op, u32 dest_ip, static void bond_arp_send_all(struct bonding *bond, struct slave *slave) { int i, vlan_id, rv; - u32 *targets = bond->params.arp_targets; + __be32 *targets = bond->params.arp_targets; struct vlan_entry *vlan, *vlan_next; struct net_device *vlan_dev; struct flowi fl; @@ -2426,10 +2426,10 @@ static void bond_send_gratuitous_arp(struct bonding *bond) } } -static void bond_validate_arp(struct bonding *bond, struct slave *slave, u32 sip, u32 tip) +static void bond_validate_arp(struct bonding *bond, struct slave *slave, __be32 sip, __be32 tip) { int i; - u32 *targets = bond->params.arp_targets; + __be32 *targets = bond->params.arp_targets; targets = bond->params.arp_targets; for (i = 0; (i < BOND_MAX_ARP_TARGETS) && targets[i]; i++) { @@ -2451,7 +2451,7 @@ static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct pack struct slave *slave; struct bonding *bond; unsigned char *arp_ptr; - u32 sip, tip; + __be32 sip, tip; if (dev->nd_net != &init_net) goto out; @@ -3427,14 +3427,14 @@ static int bond_xmit_hash_policy_l34(struct sk_buff *skb, { struct ethhdr *data = (struct ethhdr *)skb->data; struct iphdr *iph = ip_hdr(skb); - u16 *layer4hdr = (u16 *)((u32 *)iph + iph->ihl); + __be16 *layer4hdr = (__be16 *)((u32 *)iph + iph->ihl); int layer4_xor = 0; if (skb->protocol == __constant_htons(ETH_P_IP)) { if (!(iph->frag_off & __constant_htons(IP_MF|IP_OFFSET)) && (iph->protocol == IPPROTO_TCP || iph->protocol == IPPROTO_UDP)) { - layer4_xor = htons((*layer4hdr ^ *(layer4hdr + 1))); + layer4_xor = ntohs((*layer4hdr ^ *(layer4hdr + 1))); } return (layer4_xor ^ ((ntohl(iph->saddr ^ iph->daddr)) & 0xffff)) % count; @@ -4521,7 +4521,7 @@ static int bond_check_params(struct bond_params *params) arp_ip_target[arp_ip_count]); arp_interval = 0; } else { - u32 ip = in_aton(arp_ip_target[arp_ip_count]); + __be32 ip = in_aton(arp_ip_target[arp_ip_count]); arp_target[arp_ip_count] = ip; } } diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index f10927639b5..6f49ca7e9b6 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -682,16 +682,16 @@ static ssize_t bonding_store_arp_targets(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - u32 newtarget; + __be32 newtarget; int i = 0, done = 0, ret = count; struct bonding *bond = to_bond(d); - u32 *targets; + __be32 *targets; targets = bond->params.arp_targets; newtarget = in_aton(buf + 1); /* look for adds */ if (buf[0] == '+') { - if ((newtarget == 0) || (newtarget == INADDR_BROADCAST)) { + if ((newtarget == 0) || (newtarget == htonl(INADDR_BROADCAST))) { printk(KERN_ERR DRV_NAME ": %s: invalid ARP target %u.%u.%u.%u specified for addition\n", bond->dev->name, NIPQUAD(newtarget)); @@ -727,7 +727,7 @@ static ssize_t bonding_store_arp_targets(struct device *d, } else if (buf[0] == '-') { - if ((newtarget == 0) || (newtarget == INADDR_BROADCAST)) { + if ((newtarget == 0) || (newtarget == htonl(INADDR_BROADCAST))) { printk(KERN_ERR DRV_NAME ": %s: invalid ARP target %d.%d.%d.%d specified for removal\n", bond->dev->name, NIPQUAD(newtarget)); diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 6dcbd25e3ef..2a6af7d2372 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -132,7 +132,7 @@ struct bond_params { int downdelay; int lacp_fast; char primary[IFNAMSIZ]; - u32 arp_targets[BOND_MAX_ARP_TARGETS]; + __be32 arp_targets[BOND_MAX_ARP_TARGETS]; }; struct bond_parm_tbl { @@ -142,7 +142,7 @@ struct bond_parm_tbl { struct vlan_entry { struct list_head vlan_list; - u32 vlan_ip; + __be32 vlan_ip; unsigned short vlan_id; }; @@ -193,7 +193,7 @@ struct bonding { struct list_head bond_list; struct dev_mc_list *mc_list; int (*xmit_hash_policy)(struct sk_buff *, struct net_device *, int); - u32 master_ip; + __be32 master_ip; u16 flags; struct ad_bond_info ad_info; struct alb_bond_info alb_info; -- cgit v1.2.3-70-g09d2 From cf9830195a3f35b1248425b69a01ee43f5b68221 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 22 Aug 2007 21:18:56 -0400 Subject: fix vlan in 8139cp on big-endian Layout of opts2 is : MSB(vlan_tag) : LSB(vlan_tag) : flags : 0 : regardless of the host endianness. On little-endian the current code ends up with the right values, but on big-endian it blows. In r8169.c the same bug had been fixed in commit d35da12a40426184b1d0844104b1d464753eba19 (r8169: endianness fixes). Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/8139cp.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index abb2a347108..a453eda834d 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -78,7 +78,7 @@ #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) #define CP_VLAN_TAG_USED 1 #define CP_VLAN_TX_TAG(tx_desc,vlan_tag_value) \ - do { (tx_desc)->opts2 = (vlan_tag_value); } while (0) + do { (tx_desc)->opts2 = cpu_to_le32(vlan_tag_value); } while (0) #else #define CP_VLAN_TAG_USED 0 #define CP_VLAN_TX_TAG(tx_desc,vlan_tag_value) \ @@ -304,7 +304,7 @@ static const unsigned int cp_rx_config = struct cp_desc { __le32 opts1; - u32 opts2; + __le32 opts2; __le64 addr; }; @@ -462,9 +462,9 @@ static inline void cp_rx_skb (struct cp_private *cp, struct sk_buff *skb, cp->dev->last_rx = jiffies; #if CP_VLAN_TAG_USED - if (cp->vlgrp && (desc->opts2 & RxVlanTagged)) { + if (cp->vlgrp && (desc->opts2 & cpu_to_le32(RxVlanTagged))) { vlan_hwaccel_receive_skb(skb, cp->vlgrp, - be16_to_cpu(desc->opts2 & 0xffff)); + swab16(le32_to_cpu(desc->opts2) & 0xffff)); } else #endif netif_receive_skb(skb); @@ -765,7 +765,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) #if CP_VLAN_TAG_USED if (cp->vlgrp && vlan_tx_tag_present(skb)) - vlan_tag = TxVlanTag | cpu_to_be16(vlan_tx_tag_get(skb)); + vlan_tag = TxVlanTag | swab16(vlan_tx_tag_get(skb)); #endif entry = cp->tx_head; -- cgit v1.2.3-70-g09d2 From cc2d6596ca79667830a90ca177ba53b0d83262de Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 22 Aug 2007 21:34:46 -0400 Subject: 3c59x: trivial endianness annotations, NULL noise removal Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/3c59x.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 93eb78425d6..8d3893da06f 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -538,10 +538,10 @@ enum MasterCtrl { #define LAST_FRAG 0x80000000 /* Last Addr/Len pair in descriptor. */ #define DN_COMPLETE 0x00010000 /* This packet has been downloaded */ struct boom_rx_desc { - u32 next; /* Last entry points to 0. */ - s32 status; - u32 addr; /* Up to 63 addr/len pairs possible. */ - s32 length; /* Set LAST_FRAG to indicate last pair. */ + __le32 next; /* Last entry points to 0. */ + __le32 status; + __le32 addr; /* Up to 63 addr/len pairs possible. */ + __le32 length; /* Set LAST_FRAG to indicate last pair. */ }; /* Values for the Rx status entry. */ enum rx_desc_status { @@ -558,16 +558,16 @@ enum rx_desc_status { #endif struct boom_tx_desc { - u32 next; /* Last entry points to 0. */ - s32 status; /* bits 0:12 length, others see below. */ + __le32 next; /* Last entry points to 0. */ + __le32 status; /* bits 0:12 length, others see below. */ #if DO_ZEROCOPY struct { - u32 addr; - s32 length; + __le32 addr; + __le32 length; } frag[1+MAX_SKB_FRAGS]; #else - u32 addr; - s32 length; + __le32 addr; + __le32 length; #endif }; @@ -1131,7 +1131,7 @@ static int __devinit vortex_probe1(struct device *gendev, + sizeof(struct boom_tx_desc) * TX_RING_SIZE, &vp->rx_ring_dma); retval = -ENOMEM; - if (vp->rx_ring == 0) + if (!vp->rx_ring) goto free_region; vp->tx_ring = (struct boom_tx_desc *)(vp->rx_ring + RX_RING_SIZE); @@ -1204,7 +1204,7 @@ static int __devinit vortex_probe1(struct device *gendev, if ((checksum != 0x00) && !(vci->drv_flags & IS_TORNADO)) printk(" ***INVALID CHECKSUM %4.4x*** ", checksum); for (i = 0; i < 3; i++) - ((u16 *)dev->dev_addr)[i] = htons(eeprom[i + 10]); + ((__be16 *)dev->dev_addr)[i] = htons(eeprom[i + 10]); memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); if (print_info) printk(" %s", print_mac(mac, dev->dev_addr)); @@ -2500,7 +2500,7 @@ boomerang_rx(struct net_device *dev) /* Check if the packet is long enough to just accept without copying to a properly sized skbuff. */ - if (pkt_len < rx_copybreak && (skb = dev_alloc_skb(pkt_len + 2)) != 0) { + if (pkt_len < rx_copybreak && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ pci_dma_sync_single_for_cpu(VORTEX_PCI(vp), dma, PKT_BUF_SZ, PCI_DMA_FROMDEVICE); /* 'skb_put()' points to the start of sk_buff data area. */ @@ -2914,7 +2914,7 @@ static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) struct vortex_private *vp = netdev_priv(dev); void __iomem *ioaddr = vp->ioaddr; unsigned long flags; - int state = 0; + pci_power_t state = 0; if(VORTEX_PCI(vp)) state = VORTEX_PCI(vp)->current_state; -- cgit v1.2.3-70-g09d2 From ee41a82fa362449e608c4dab7df261058ffd52c0 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 22 Aug 2007 21:37:46 -0400 Subject: amd8111e: trivial endianness annotations, NULL noise removal Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/amd8111e.c | 6 +++--- drivers/net/amd8111e.h | 24 ++++++++++++------------ 2 files changed, 15 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c index 73f40a45441..babe0de2ce4 100644 --- a/drivers/net/amd8111e.c +++ b/drivers/net/amd8111e.c @@ -1404,7 +1404,7 @@ This function checks if there is any transmit descriptors available to queue mo static int amd8111e_tx_queue_avail(struct amd8111e_priv* lp ) { int tx_index = lp->tx_idx & TX_BUFF_MOD_MASK; - if(lp->tx_skbuff[tx_index] != 0) + if (lp->tx_skbuff[tx_index]) return -1; else return 0; @@ -1441,7 +1441,7 @@ static int amd8111e_start_xmit(struct sk_buff *skb, struct net_device * dev) lp->tx_dma_addr[tx_index] = pci_map_single(lp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE); lp->tx_ring[tx_index].buff_phy_addr = - (u32) cpu_to_le32(lp->tx_dma_addr[tx_index]); + cpu_to_le32(lp->tx_dma_addr[tx_index]); /* Set FCS and LTINT bits */ wmb(); @@ -1998,7 +1998,7 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev, spin_lock_init(&lp->lock); lp->mmio = ioremap(reg_addr, reg_len); - if (lp->mmio == 0) { + if (!lp->mmio) { printk(KERN_ERR "amd8111e: Cannot map device registers, " "exiting\n"); err = -ENOMEM; diff --git a/drivers/net/amd8111e.h b/drivers/net/amd8111e.h index 612e653610e..28c60a71ed5 100644 --- a/drivers/net/amd8111e.h +++ b/drivers/net/amd8111e.h @@ -655,32 +655,32 @@ typedef enum { struct amd8111e_tx_dr{ - u16 buff_count; /* Size of the buffer pointed by this descriptor */ + __le16 buff_count; /* Size of the buffer pointed by this descriptor */ - u16 tx_flags; + __le16 tx_flags; - u16 tag_ctrl_info; + __le16 tag_ctrl_info; - u16 tag_ctrl_cmd; + __le16 tag_ctrl_cmd; - u32 buff_phy_addr; + __le32 buff_phy_addr; - u32 reserved; + __le32 reserved; }; struct amd8111e_rx_dr{ - u32 reserved; + __le32 reserved; - u16 msg_count; /* Received message len */ + __le16 msg_count; /* Received message len */ - u16 tag_ctrl_info; + __le16 tag_ctrl_info; - u16 buff_count; /* Len of the buffer pointed by descriptor. */ + __le16 buff_count; /* Len of the buffer pointed by descriptor. */ - u16 rx_flags; + __le16 rx_flags; - u32 buff_phy_addr; + __le32 buff_phy_addr; }; struct amd8111e_link_config{ -- cgit v1.2.3-70-g09d2 From 05d2fec9f5e5fd1d7169435631b9d55ae4c566d1 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 22 Aug 2007 21:42:28 -0400 Subject: amd8111e big-endian fix amd8111e_calc_coalesce() ends up with insane values of tx_data_rate since ->tx_bytes increments missing conversion from little- to host-endian Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/amd8111e.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c index babe0de2ce4..1cc74ec88a5 100644 --- a/drivers/net/amd8111e.c +++ b/drivers/net/amd8111e.c @@ -709,7 +709,8 @@ static int amd8111e_tx(struct net_device *dev) lp->tx_complete_idx++; /*COAL update tx coalescing parameters */ lp->coal_conf.tx_packets++; - lp->coal_conf.tx_bytes += lp->tx_ring[tx_index].buff_count; + lp->coal_conf.tx_bytes += + le16_to_cpu(lp->tx_ring[tx_index].buff_count); if (netif_queue_stopped(dev) && lp->tx_complete_idx > lp->tx_idx - NUM_TX_BUFFERS +2){ -- cgit v1.2.3-70-g09d2 From 701181ac1d9ac465a3614061cb60ded4033c4d07 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 22 Aug 2007 22:59:11 -0400 Subject: arcnet endianness annotations Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/arcnet/rfc1051.c | 4 ++-- drivers/net/arcnet/rfc1201.c | 6 +++--- include/linux/arcdevice.h | 4 ++-- include/linux/if_arcnet.h | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/arcnet/rfc1051.c b/drivers/net/arcnet/rfc1051.c index 2de8877ece2..dab185bc51f 100644 --- a/drivers/net/arcnet/rfc1051.c +++ b/drivers/net/arcnet/rfc1051.c @@ -34,7 +34,7 @@ #define VERSION "arcnet: RFC1051 \"simple standard\" (`s') encapsulation support loaded.\n" -static unsigned short type_trans(struct sk_buff *skb, struct net_device *dev); +static __be16 type_trans(struct sk_buff *skb, struct net_device *dev); static void rx(struct net_device *dev, int bufnum, struct archdr *pkthdr, int length); static int build_header(struct sk_buff *skb, struct net_device *dev, @@ -86,7 +86,7 @@ MODULE_LICENSE("GPL"); * * With ARCnet we have to convert everything to Ethernet-style stuff. */ -static unsigned short type_trans(struct sk_buff *skb, struct net_device *dev) +static __be16 type_trans(struct sk_buff *skb, struct net_device *dev) { struct arcnet_local *lp = dev->priv; struct archdr *pkt = (struct archdr *) skb->data; diff --git a/drivers/net/arcnet/rfc1201.c b/drivers/net/arcnet/rfc1201.c index 460a095000c..6d6d95cc440 100644 --- a/drivers/net/arcnet/rfc1201.c +++ b/drivers/net/arcnet/rfc1201.c @@ -34,7 +34,7 @@ MODULE_LICENSE("GPL"); #define VERSION "arcnet: RFC1201 \"standard\" (`a') encapsulation support loaded.\n" -static unsigned short type_trans(struct sk_buff *skb, struct net_device *dev); +static __be16 type_trans(struct sk_buff *skb, struct net_device *dev); static void rx(struct net_device *dev, int bufnum, struct archdr *pkthdr, int length); static int build_header(struct sk_buff *skb, struct net_device *dev, @@ -88,7 +88,7 @@ module_exit(arcnet_rfc1201_exit); * * With ARCnet we have to convert everything to Ethernet-style stuff. */ -static unsigned short type_trans(struct sk_buff *skb, struct net_device *dev) +static __be16 type_trans(struct sk_buff *skb, struct net_device *dev) { struct archdr *pkt = (struct archdr *) skb->data; struct arc_rfc1201 *soft = &pkt->soft.rfc1201; @@ -456,7 +456,7 @@ static void load_pkt(struct net_device *dev, struct arc_hardware *hard, excsoft.proto = soft->proto; excsoft.split_flag = 0xff; - excsoft.sequence = 0xffff; + excsoft.sequence = htons(0xffff); hard->offset[0] = 0; ofs = 512 - softlen; diff --git a/include/linux/arcdevice.h b/include/linux/arcdevice.h index 2f85049cfb3..fde675872c5 100644 --- a/include/linux/arcdevice.h +++ b/include/linux/arcdevice.h @@ -214,7 +214,7 @@ extern struct ArcProto *arc_proto_map[256], *arc_proto_default, */ struct Incoming { struct sk_buff *skb; /* packet data buffer */ - uint16_t sequence; /* sequence number of assembly */ + __be16 sequence; /* sequence number of assembly */ uint8_t lastpacket, /* number of last packet (from 1) */ numpackets; /* number of packets in split */ }; @@ -292,7 +292,7 @@ struct arcnet_local { struct { uint16_t sequence; /* sequence number (incs with each packet) */ - uint16_t aborted_seq; + __be16 aborted_seq; struct Incoming incoming[256]; /* one from each address */ } rfc1201; diff --git a/include/linux/if_arcnet.h b/include/linux/if_arcnet.h index af380cb876a..27ea2ac445a 100644 --- a/include/linux/if_arcnet.h +++ b/include/linux/if_arcnet.h @@ -59,7 +59,7 @@ struct arc_rfc1201 { uint8_t proto; /* protocol ID field - varies */ uint8_t split_flag; /* for use with split packets */ - uint16_t sequence; /* sequence number */ + __be16 sequence; /* sequence number */ uint8_t payload[0]; /* space remaining in packet (504 bytes)*/ }; #define RFC1201_HDR_SIZE 4 -- cgit v1.2.3-70-g09d2 From c559a5bc9417c00ba2df59397a27eaf8d8e52aec Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 23 Aug 2007 00:43:22 -0400 Subject: tulip: endianness annotations Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/tulip/de2104x.c | 12 ++++++------ drivers/net/tulip/de4x5.c | 10 +++++----- drivers/net/tulip/tulip.h | 16 ++++++++-------- drivers/net/tulip/tulip_core.c | 10 +++++----- drivers/net/tulip/uli526x.c | 6 +++--- drivers/net/tulip/winbond-840.c | 2 +- 6 files changed, 28 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index f12e33a1736..77d9dd7ea34 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -264,10 +264,10 @@ struct de_srom_info_leaf { } __attribute__((packed)); struct de_desc { - u32 opts1; - u32 opts2; - u32 addr1; - u32 addr2; + __le32 opts1; + __le32 opts2; + __le32 addr1; + __le32 addr2; }; struct media_info { @@ -1771,8 +1771,8 @@ static void __devinit de21041_get_srom_info (struct de_private *de) /* download entire eeprom */ for (i = 0; i < DE_EEPROM_WORDS; i++) - ((u16 *)ee_data)[i] = - le16_to_cpu(tulip_read_eeprom(de->regs, i, ee_addr_size)); + ((__le16 *)ee_data)[i] = + cpu_to_le16(tulip_read_eeprom(de->regs, i, ee_addr_size)); /* DEC now has a specification but early board makers just put the address in the first EEPROM locations. */ diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c index 4633cc6dd41..9b9cd83fb8b 100644 --- a/drivers/net/tulip/de4x5.c +++ b/drivers/net/tulip/de4x5.c @@ -482,7 +482,7 @@ static char version[] __devinitdata = "de4x5.c:V0.546 2001/02/22 davies@maniac.ultranet.com\n"; #define c_char const char -#define TWIDDLE(a) (u_short)le16_to_cpu(get_unaligned((u_short *)(a))) +#define TWIDDLE(a) (u_short)le16_to_cpu(get_unaligned((__le16 *)(a))) /* ** MII Information @@ -756,10 +756,10 @@ struct de4x5_srom { /* Multiple of 4 for DC21040 */ /* Allows 512 byte alignment */ struct de4x5_desc { - volatile s32 status; - u32 des1; - u32 buf; - u32 next; + volatile __le32 status; + __le32 des1; + __le32 buf; + __le32 next; DESC_ALIGN }; diff --git a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h index 5a4d7270973..3f69f53d776 100644 --- a/drivers/net/tulip/tulip.h +++ b/drivers/net/tulip/tulip.h @@ -178,18 +178,18 @@ enum tulip_busconfig_bits { /* The Tulip Rx and Tx buffer descriptors. */ struct tulip_rx_desc { - s32 status; - s32 length; - u32 buffer1; - u32 buffer2; + __le32 status; + __le32 length; + __le32 buffer1; + __le32 buffer2; }; struct tulip_tx_desc { - s32 status; - s32 length; - u32 buffer1; - u32 buffer2; /* We use only buffer 1. */ + __le32 status; + __le32 length; + __le32 buffer1; + __le32 buffer2; /* We use only buffer 1. */ }; diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index 80fee229253..ee08292bcf8 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -326,8 +326,8 @@ static void tulip_up(struct net_device *dev) tp->dirty_rx = tp->dirty_tx = 0; if (tp->flags & MC_HASH_ONLY) { - u32 addr_low = le32_to_cpu(get_unaligned((u32 *)dev->dev_addr)); - u32 addr_high = le16_to_cpu(get_unaligned((u16 *)(dev->dev_addr+4))); + u32 addr_low = le32_to_cpu(get_unaligned((__le32 *)dev->dev_addr)); + u32 addr_high = le16_to_cpu(get_unaligned((__le16 *)(dev->dev_addr+4))); if (tp->chip_id == AX88140) { iowrite32(0, ioaddr + CSR13); iowrite32(addr_low, ioaddr + CSR14); @@ -1443,13 +1443,13 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, do value = ioread32(ioaddr + CSR9); while (value < 0 && --boguscnt > 0); - put_unaligned(le16_to_cpu(value), ((u16*)dev->dev_addr) + i); + put_unaligned(cpu_to_le16(value), ((__le16*)dev->dev_addr) + i); sum += value & 0xffff; } } else if (chip_idx == COMET) { /* No need to read the EEPROM. */ - put_unaligned(cpu_to_le32(ioread32(ioaddr + 0xA4)), (u32 *)dev->dev_addr); - put_unaligned(cpu_to_le16(ioread32(ioaddr + 0xA8)), (u16 *)(dev->dev_addr + 4)); + put_unaligned(cpu_to_le32(ioread32(ioaddr + 0xA4)), (__le32 *)dev->dev_addr); + put_unaligned(cpu_to_le16(ioread32(ioaddr + 0xA8)), (__le16 *)(dev->dev_addr + 4)); for (i = 0; i < 6; i ++) sum += dev->dev_addr[i]; } else { diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c index a4fd782bcd2..53c7523960c 100644 --- a/drivers/net/tulip/uli526x.c +++ b/drivers/net/tulip/uli526x.c @@ -112,13 +112,13 @@ /* Structure/enum declaration ------------------------------- */ struct tx_desc { - u32 tdes0, tdes1, tdes2, tdes3; /* Data for the card */ + __le32 tdes0, tdes1, tdes2, tdes3; /* Data for the card */ char *tx_buf_ptr; /* Data for us */ struct tx_desc *next_tx_desc; } __attribute__(( aligned(32) )); struct rx_desc { - u32 rdes0, rdes1, rdes2, rdes3; /* Data for the card */ + __le32 rdes0, rdes1, rdes2, rdes3; /* Data for the card */ struct sk_buff *rx_skb_ptr; /* Data for us */ struct rx_desc *next_rx_desc; } __attribute__(( aligned(32) )); @@ -344,7 +344,7 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev, /* read 64 word srom data */ for (i = 0; i < 64; i++) - ((u16 *) db->srom)[i] = cpu_to_le16(read_srom_word(db->ioaddr, i)); + ((__le16 *) db->srom)[i] = cpu_to_le16(read_srom_word(db->ioaddr, i)); /* Set Node address */ if(((u16 *) db->srom)[0] == 0xffff || ((u16 *) db->srom)[0] == 0) /* SROM absent, so read MAC address from ID Table */ diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c index 3c40dd6e1a2..3c8e3b63be0 100644 --- a/drivers/net/tulip/winbond-840.c +++ b/drivers/net/tulip/winbond-840.c @@ -381,7 +381,7 @@ static int __devinit w840_probe1 (struct pci_dev *pdev, goto err_out_free_res; for (i = 0; i < 3; i++) - ((u16 *)dev->dev_addr)[i] = le16_to_cpu(eeprom_read(ioaddr, i)); + ((__le16 *)dev->dev_addr)[i] = cpu_to_le16(eeprom_read(ioaddr, i)); /* Reset the chip to erase previous misconfiguration. No hold time required! */ -- cgit v1.2.3-70-g09d2 From 03a710ffcb0c4e682087f4cf4f0236d10ed09253 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 23 Aug 2007 00:44:39 -0400 Subject: typhoon: trivial endianness annotations Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/typhoon.c | 36 +++++----- drivers/net/typhoon.h | 190 +++++++++++++++++++++++++------------------------- 2 files changed, 113 insertions(+), 113 deletions(-) (limited to 'drivers') diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index 43894e95fcb..72e5e9be7e9 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -300,9 +300,9 @@ struct typhoon { const char * name; struct typhoon_shared * shared; dma_addr_t shared_dma; - u16 xcvr_select; - u16 wol_events; - u32 offload; + __le16 xcvr_select; + __le16 wol_events; + __le32 offload; /* unused stuff (future use) */ int capabilities; @@ -828,7 +828,7 @@ typhoon_start_tx(struct sk_buff *skb, struct net_device *dev) first_txd->processFlags |= TYPHOON_TX_PF_INSERT_VLAN | TYPHOON_TX_PF_VLAN_PRIORITY; first_txd->processFlags |= - cpu_to_le32(htons(vlan_tx_tag_get(skb)) << + cpu_to_le32(ntohs(vlan_tx_tag_get(skb)) << TYPHOON_TX_PF_VLAN_TAG_SHIFT); } @@ -920,7 +920,7 @@ typhoon_set_rx_mode(struct net_device *dev) struct typhoon *tp = netdev_priv(dev); struct cmd_desc xp_cmd; u32 mc_filter[2]; - u16 filter; + __le16 filter; filter = TYPHOON_RX_FILTER_DIRECTED | TYPHOON_RX_FILTER_BROADCAST; if(dev->flags & IFF_PROMISC) { @@ -1131,7 +1131,7 @@ typhoon_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct typhoon *tp = netdev_priv(dev); struct cmd_desc xp_cmd; - int xcvr; + __le16 xcvr; int err; err = -EINVAL; @@ -1536,7 +1536,7 @@ out_timeout: static u32 typhoon_clean_tx(struct typhoon *tp, struct transmit_ring *txRing, - volatile u32 * index) + volatile __le32 * index) { u32 lastRead = txRing->lastRead; struct tx_desc *tx; @@ -1572,7 +1572,7 @@ typhoon_clean_tx(struct typhoon *tp, struct transmit_ring *txRing, static void typhoon_tx_complete(struct typhoon *tp, struct transmit_ring *txRing, - volatile u32 * index) + volatile __le32 * index) { u32 lastRead; int numDesc = MAX_SKB_FRAGS + 1; @@ -1662,8 +1662,8 @@ typhoon_alloc_rx_skb(struct typhoon *tp, u32 idx) } static int -typhoon_rx(struct typhoon *tp, struct basic_ring *rxRing, volatile u32 * ready, - volatile u32 * cleared, int budget) +typhoon_rx(struct typhoon *tp, struct basic_ring *rxRing, volatile __le32 * ready, + volatile __le32 * cleared, int budget) { struct rx_desc *rx; struct sk_buff *skb, *new_skb; @@ -1673,7 +1673,7 @@ typhoon_rx(struct typhoon *tp, struct basic_ring *rxRing, volatile u32 * ready, u32 rxaddr; int pkt_len; u32 idx; - u32 csum_bits; + __le32 csum_bits; int received; received = 0; @@ -1840,7 +1840,7 @@ typhoon_free_rx_rings(struct typhoon *tp) } static int -typhoon_sleep(struct typhoon *tp, pci_power_t state, u16 events) +typhoon_sleep(struct typhoon *tp, pci_power_t state, __le16 events) { struct pci_dev *pdev = tp->pdev; void __iomem *ioaddr = tp->ioaddr; @@ -1928,8 +1928,8 @@ typhoon_start_runtime(struct typhoon *tp) goto error_out; INIT_COMMAND_NO_RESPONSE(&xp_cmd, TYPHOON_CMD_SET_MAC_ADDRESS); - xp_cmd.parm1 = cpu_to_le16(ntohs(*(u16 *)&dev->dev_addr[0])); - xp_cmd.parm2 = cpu_to_le32(ntohl(*(u32 *)&dev->dev_addr[2])); + xp_cmd.parm1 = cpu_to_le16(ntohs(*(__be16 *)&dev->dev_addr[0])); + xp_cmd.parm2 = cpu_to_le32(ntohl(*(__be32 *)&dev->dev_addr[2])); err = typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL); if(err < 0) goto error_out; @@ -2229,8 +2229,8 @@ typhoon_suspend(struct pci_dev *pdev, pm_message_t state) } INIT_COMMAND_NO_RESPONSE(&xp_cmd, TYPHOON_CMD_SET_MAC_ADDRESS); - xp_cmd.parm1 = cpu_to_le16(ntohs(*(u16 *)&dev->dev_addr[0])); - xp_cmd.parm2 = cpu_to_le32(ntohl(*(u32 *)&dev->dev_addr[2])); + xp_cmd.parm1 = cpu_to_le16(ntohs(*(__be16 *)&dev->dev_addr[0])); + xp_cmd.parm2 = cpu_to_le32(ntohl(*(__be32 *)&dev->dev_addr[2])); if(typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL) < 0) { printk(KERN_ERR "%s: unable to set mac address in suspend\n", dev->name); @@ -2465,8 +2465,8 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) goto error_out_reset; } - *(u16 *)&dev->dev_addr[0] = htons(le16_to_cpu(xp_resp[0].parm1)); - *(u32 *)&dev->dev_addr[2] = htonl(le32_to_cpu(xp_resp[0].parm2)); + *(__be16 *)&dev->dev_addr[0] = htons(le16_to_cpu(xp_resp[0].parm1)); + *(__be32 *)&dev->dev_addr[2] = htonl(le32_to_cpu(xp_resp[0].parm2)); if(!is_valid_ether_addr(dev->dev_addr)) { printk(ERR_PFX "%s: Could not obtain valid ethernet address, " diff --git a/drivers/net/typhoon.h b/drivers/net/typhoon.h index 2f14a050051..19df20889b8 100644 --- a/drivers/net/typhoon.h +++ b/drivers/net/typhoon.h @@ -64,19 +64,19 @@ struct transmit_ring { */ struct typhoon_indexes { /* The first four are written by the host, and read by the NIC */ - volatile u32 rxHiCleared; - volatile u32 rxLoCleared; - volatile u32 rxBuffReady; - volatile u32 respCleared; + volatile __le32 rxHiCleared; + volatile __le32 rxLoCleared; + volatile __le32 rxBuffReady; + volatile __le32 respCleared; /* The remaining are written by the NIC, and read by the host */ - volatile u32 txLoCleared; - volatile u32 txHiCleared; - volatile u32 rxLoReady; - volatile u32 rxBuffCleared; - volatile u32 cmdCleared; - volatile u32 respReady; - volatile u32 rxHiReady; + volatile __le32 txLoCleared; + volatile __le32 txHiCleared; + volatile __le32 rxLoReady; + volatile __u32 rxBuffCleared; /* AV: really? */ + volatile __le32 cmdCleared; + volatile __le32 respReady; + volatile __le32 rxHiReady; } __attribute__ ((packed)); /* The host<->Typhoon interface @@ -100,31 +100,31 @@ struct typhoon_indexes { * be zero. */ struct typhoon_interface { - u32 ringIndex; - u32 ringIndexHi; - u32 txLoAddr; - u32 txLoAddrHi; - u32 txLoSize; - u32 txHiAddr; - u32 txHiAddrHi; - u32 txHiSize; - u32 rxLoAddr; - u32 rxLoAddrHi; - u32 rxLoSize; - u32 rxBuffAddr; - u32 rxBuffAddrHi; - u32 rxBuffSize; - u32 cmdAddr; - u32 cmdAddrHi; - u32 cmdSize; - u32 respAddr; - u32 respAddrHi; - u32 respSize; - u32 zeroAddr; - u32 zeroAddrHi; - u32 rxHiAddr; - u32 rxHiAddrHi; - u32 rxHiSize; + __le32 ringIndex; + __le32 ringIndexHi; + __le32 txLoAddr; + __le32 txLoAddrHi; + __le32 txLoSize; + __le32 txHiAddr; + __le32 txHiAddrHi; + __le32 txHiSize; + __le32 rxLoAddr; + __le32 rxLoAddrHi; + __le32 rxLoSize; + __le32 rxBuffAddr; + __le32 rxBuffAddrHi; + __le32 rxBuffSize; + __le32 cmdAddr; + __le32 cmdAddrHi; + __le32 cmdSize; + __le32 respAddr; + __le32 respAddrHi; + __le32 respSize; + __le32 zeroAddr; + __le32 zeroAddrHi; + __le32 rxHiAddr; + __le32 rxHiAddrHi; + __le32 rxHiSize; } __attribute__ ((packed)); /* The Typhoon transmit/fragment descriptor @@ -165,10 +165,10 @@ struct tx_desc { #define TYPHOON_RX_ERROR 0x40 #define TYPHOON_DESC_VALID 0x80 u8 numDesc; - u16 len; + __le16 len; u32 addr; u32 addrHi; - u32 processFlags; + __le32 processFlags; #define TYPHOON_TX_PF_NO_CRC __constant_cpu_to_le32(0x00000001) #define TYPHOON_TX_PF_IP_CHKSUM __constant_cpu_to_le32(0x00000002) #define TYPHOON_TX_PF_TCP_CHKSUM __constant_cpu_to_le32(0x00000004) @@ -197,12 +197,12 @@ struct tx_desc { struct tcpopt_desc { u8 flags; u8 numDesc; - u16 mss_flags; + __le16 mss_flags; #define TYPHOON_TSO_FIRST __constant_cpu_to_le16(0x1000) #define TYPHOON_TSO_LAST __constant_cpu_to_le16(0x2000) - u32 respAddrLo; - u32 bytesTx; - u32 status; + __le32 respAddrLo; + __le32 bytesTx; + __le32 status; } __attribute__ ((packed)); /* The IPSEC Offload descriptor @@ -216,12 +216,12 @@ struct tcpopt_desc { struct ipsec_desc { u8 flags; u8 numDesc; - u16 ipsecFlags; + __le16 ipsecFlags; #define TYPHOON_IPSEC_GEN_IV __constant_cpu_to_le16(0x0000) #define TYPHOON_IPSEC_USE_IV __constant_cpu_to_le16(0x0001) - u32 sa1; - u32 sa2; - u32 reserved; + __le32 sa1; + __le32 sa2; + __le32 reserved; } __attribute__ ((packed)); /* The Typhoon receive descriptor (Updated by NIC) @@ -239,10 +239,10 @@ struct ipsec_desc { struct rx_desc { u8 flags; u8 numDesc; - u16 frameLen; + __le16 frameLen; u32 addr; u32 addrHi; - u32 rxStatus; + __le32 rxStatus; #define TYPHOON_RX_ERR_INTERNAL __constant_cpu_to_le32(0x00000000) #define TYPHOON_RX_ERR_FIFO_UNDERRUN __constant_cpu_to_le32(0x00000001) #define TYPHOON_RX_ERR_BAD_SSD __constant_cpu_to_le32(0x00000002) @@ -264,10 +264,10 @@ struct rx_desc { #define TYPHOON_RX_IP_CHK_GOOD __constant_cpu_to_le32(0x00000100) #define TYPHOON_RX_TCP_CHK_GOOD __constant_cpu_to_le32(0x00000200) #define TYPHOON_RX_UDP_CHK_GOOD __constant_cpu_to_le32(0x00000400) - u16 filterResults; + __le16 filterResults; #define TYPHOON_RX_FILTER_MASK __constant_cpu_to_le16(0x7fff) #define TYPHOON_RX_FILTERED __constant_cpu_to_le16(0x8000) - u16 ipsecResults; + __le16 ipsecResults; #define TYPHOON_RX_OUTER_AH_GOOD __constant_cpu_to_le16(0x0001) #define TYPHOON_RX_OUTER_ESP_GOOD __constant_cpu_to_le16(0x0002) #define TYPHOON_RX_INNER_AH_GOOD __constant_cpu_to_le16(0x0004) @@ -278,7 +278,7 @@ struct rx_desc { #define TYPHOON_RX_INNER_ESP_FAIL __constant_cpu_to_le16(0x0080) #define TYPHOON_RX_UNKNOWN_SA __constant_cpu_to_le16(0x0100) #define TYPHOON_RX_ESP_FORMAT_ERR __constant_cpu_to_le16(0x0200) - u32 vlanTag; + __be32 vlanTag; } __attribute__ ((packed)); /* The Typhoon free buffer descriptor, used to give a buffer to the NIC @@ -292,8 +292,8 @@ struct rx_desc { * from the NIC */ struct rx_free { - u32 physAddr; - u32 physAddrHi; + __le32 physAddr; + __le32 physAddrHi; u32 virtAddr; u32 virtAddrHi; } __attribute__ ((packed)); @@ -312,7 +312,7 @@ struct rx_free { struct cmd_desc { u8 flags; u8 numDesc; - u16 cmd; + __le16 cmd; #define TYPHOON_CMD_TX_ENABLE __constant_cpu_to_le16(0x0001) #define TYPHOON_CMD_TX_DISABLE __constant_cpu_to_le16(0x0002) #define TYPHOON_CMD_RX_ENABLE __constant_cpu_to_le16(0x0003) @@ -339,9 +339,9 @@ struct cmd_desc { #define TYPHOON_CMD_GET_IPSEC_ENABLE __constant_cpu_to_le16(0x0067) #define TYPHOON_CMD_GET_CMD_LVL __constant_cpu_to_le16(0x0069) u16 seqNo; - u16 parm1; - u32 parm2; - u32 parm3; + __le16 parm1; + __le32 parm2; + __le32 parm3; } __attribute__ ((packed)); /* The Typhoon response descriptor, see command descriptor for details @@ -349,11 +349,11 @@ struct cmd_desc { struct resp_desc { u8 flags; u8 numDesc; - u16 cmd; - u16 seqNo; - u16 parm1; - u32 parm2; - u32 parm3; + __le16 cmd; + __le16 seqNo; + __le16 parm1; + __le32 parm2; + __le32 parm3; } __attribute__ ((packed)); #define INIT_COMMAND_NO_RESPONSE(x, command) \ @@ -386,31 +386,31 @@ struct resp_desc { struct stats_resp { u8 flags; u8 numDesc; - u16 cmd; - u16 seqNo; - u16 unused; - u32 txPackets; - u64 txBytes; - u32 txDeferred; - u32 txLateCollisions; - u32 txCollisions; - u32 txCarrierLost; - u32 txMultipleCollisions; - u32 txExcessiveCollisions; - u32 txFifoUnderruns; - u32 txMulticastTxOverflows; - u32 txFiltered; - u32 rxPacketsGood; - u64 rxBytesGood; - u32 rxFifoOverruns; - u32 BadSSD; - u32 rxCrcErrors; - u32 rxOversized; - u32 rxBroadcast; - u32 rxMulticast; - u32 rxOverflow; - u32 rxFiltered; - u32 linkStatus; + __le16 cmd; + __le16 seqNo; + __le16 unused; + __le32 txPackets; + __le64 txBytes; + __le32 txDeferred; + __le32 txLateCollisions; + __le32 txCollisions; + __le32 txCarrierLost; + __le32 txMultipleCollisions; + __le32 txExcessiveCollisions; + __le32 txFifoUnderruns; + __le32 txMulticastTxOverflows; + __le32 txFiltered; + __le32 rxPacketsGood; + __le64 rxBytesGood; + __le32 rxFifoOverruns; + __le32 BadSSD; + __le32 rxCrcErrors; + __le32 rxOversized; + __le32 rxBroadcast; + __le32 rxMulticast; + __le32 rxOverflow; + __le32 rxFiltered; + __le32 linkStatus; #define TYPHOON_LINK_STAT_MASK __constant_cpu_to_le32(0x00000001) #define TYPHOON_LINK_GOOD __constant_cpu_to_le32(0x00000001) #define TYPHOON_LINK_BAD __constant_cpu_to_le32(0x00000000) @@ -420,8 +420,8 @@ struct stats_resp { #define TYPHOON_LINK_DUPLEX_MASK __constant_cpu_to_le32(0x00000004) #define TYPHOON_LINK_FULL_DUPLEX __constant_cpu_to_le32(0x00000004) #define TYPHOON_LINK_HALF_DUPLEX __constant_cpu_to_le32(0x00000000) - u32 unused2; - u32 unused3; + __le32 unused2; + __le32 unused3; } __attribute__ ((packed)); /* TYPHOON_CMD_XCVR_SELECT xcvr values (resp.parm1) @@ -509,17 +509,17 @@ struct sa_descriptor { */ struct typhoon_file_header { u8 tag[8]; - u32 version; - u32 numSections; - u32 startAddr; - u32 hmacDigest[5]; + __le32 version; + __le32 numSections; + __le32 startAddr; + __le32 hmacDigest[5]; } __attribute__ ((packed)); struct typhoon_section_header { - u32 len; + __le32 len; u16 checksum; u16 reserved; - u32 startAddr; + __le32 startAddr; } __attribute__ ((packed)); /* The Typhoon Register offsets -- cgit v1.2.3-70-g09d2 From 3e33545ba6f8ca04b28a015e095662a35a4e2670 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 23 Aug 2007 00:45:46 -0400 Subject: pcnet32: endianness Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/pcnet32.c | 98 +++++++++++++++++++++++++-------------------------- 1 file changed, 48 insertions(+), 50 deletions(-) (limited to 'drivers') diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 36f92dd5550..5f994b5beda 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -210,31 +210,31 @@ static int homepna[MAX_UNITS]; /* The PCNET32 Rx and Tx ring descriptors. */ struct pcnet32_rx_head { - u32 base; - s16 buf_length; /* two`s complement of length */ - s16 status; - u32 msg_length; - u32 reserved; + __le32 base; + __le16 buf_length; /* two`s complement of length */ + __le16 status; + __le32 msg_length; + __le32 reserved; }; struct pcnet32_tx_head { - u32 base; - s16 length; /* two`s complement of length */ - s16 status; - u32 misc; - u32 reserved; + __le32 base; + __le16 length; /* two`s complement of length */ + __le16 status; + __le32 misc; + __le32 reserved; }; /* The PCNET32 32-Bit initialization block, described in databook. */ struct pcnet32_init_block { - u16 mode; - u16 tlen_rlen; + __le16 mode; + __le16 tlen_rlen; u8 phys_addr[6]; - u16 reserved; - u32 filter[2]; + __le16 reserved; + __le32 filter[2]; /* Receive and transmit ring base, along with extra bits. */ - u32 rx_ring; - u32 tx_ring; + __le32 rx_ring; + __le32 tx_ring; }; /* PCnet32 access functions */ @@ -610,9 +610,9 @@ static void pcnet32_realloc_rx_ring(struct net_device *dev, new_dma_addr_list[new] = pci_map_single(lp->pci_dev, rx_skbuff->data, PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE); - new_rx_ring[new].base = (u32) le32_to_cpu(new_dma_addr_list[new]); - new_rx_ring[new].buf_length = le16_to_cpu(2 - PKT_BUF_SZ); - new_rx_ring[new].status = le16_to_cpu(0x8000); + new_rx_ring[new].base = cpu_to_le32(new_dma_addr_list[new]); + new_rx_ring[new].buf_length = cpu_to_le16(2 - PKT_BUF_SZ); + new_rx_ring[new].status = cpu_to_le16(0x8000); } /* and free any unneeded buffers */ for (; new < lp->rx_ring_size; new++) { @@ -888,7 +888,7 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1) int x, i; /* counters */ int numbuffs = 4; /* number of TX/RX buffers and descs */ u16 status = 0x8300; /* TX ring status */ - u16 teststatus; /* test of ring status */ + __le16 teststatus; /* test of ring status */ int rc; /* return code */ int size; /* size of packets */ unsigned char *packet; /* source packet data */ @@ -935,7 +935,7 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1) packet = skb->data; skb_put(skb, size); /* create space for data */ lp->tx_skbuff[x] = skb; - lp->tx_ring[x].length = le16_to_cpu(-skb->len); + lp->tx_ring[x].length = cpu_to_le16(-skb->len); lp->tx_ring[x].misc = 0; /* put DA and SA into the skb */ @@ -955,10 +955,9 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1) lp->tx_dma_addr[x] = pci_map_single(lp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE); - lp->tx_ring[x].base = - (u32) le32_to_cpu(lp->tx_dma_addr[x]); + lp->tx_ring[x].base = cpu_to_le32(lp->tx_dma_addr[x]); wmb(); /* Make sure owner changes after all others are visible */ - lp->tx_ring[x].status = le16_to_cpu(status); + lp->tx_ring[x].status = cpu_to_le16(status); } } @@ -969,7 +968,7 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1) x = a->read_csr(ioaddr, CSR15) & 0xfffc; lp->a.write_csr(ioaddr, CSR15, x | 0x0044); - teststatus = le16_to_cpu(0x8000); + teststatus = cpu_to_le16(0x8000); lp->a.write_csr(ioaddr, CSR0, CSR0_START); /* Set STRT bit */ /* Check status of descriptors */ @@ -1099,6 +1098,7 @@ static int pcnet32_phys_id(struct net_device *dev, u32 data) mod_timer(&lp->blink_timer, jiffies); set_current_state(TASK_INTERRUPTIBLE); + /* AV: the limit here makes no sense whatsoever */ if ((!data) || (data > (u32) (MAX_SCHEDULE_TIMEOUT / HZ))) data = (u32) (MAX_SCHEDULE_TIMEOUT / HZ); @@ -1224,7 +1224,7 @@ static void pcnet32_rx_entry(struct net_device *dev, newskb->data, PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE); - rxp->base = le32_to_cpu(lp->rx_dma_addr[entry]); + rxp->base = cpu_to_le32(lp->rx_dma_addr[entry]); rx_in_place = 1; } else skb = NULL; @@ -1283,9 +1283,9 @@ static int pcnet32_rx(struct net_device *dev, int budget) * The docs say that the buffer length isn't touched, but Andrew * Boyd of QNX reports that some revs of the 79C965 clear it. */ - rxp->buf_length = le16_to_cpu(2 - PKT_BUF_SZ); + rxp->buf_length = cpu_to_le16(2 - PKT_BUF_SZ); wmb(); /* Make sure owner changes after others are visible */ - rxp->status = le16_to_cpu(0x8000); + rxp->status = cpu_to_le16(0x8000); entry = (++lp->cur_rx) & lp->rx_mod_mask; rxp = &lp->rx_ring[entry]; } @@ -1875,15 +1875,15 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) && dev->dev_addr[2] == 0x75) lp->options = PCNET32_PORT_FD | PCNET32_PORT_GPSI; - lp->init_block->mode = le16_to_cpu(0x0003); /* Disable Rx and Tx. */ + lp->init_block->mode = cpu_to_le16(0x0003); /* Disable Rx and Tx. */ lp->init_block->tlen_rlen = - le16_to_cpu(lp->tx_len_bits | lp->rx_len_bits); + cpu_to_le16(lp->tx_len_bits | lp->rx_len_bits); for (i = 0; i < 6; i++) lp->init_block->phys_addr[i] = dev->dev_addr[i]; lp->init_block->filter[0] = 0x00000000; lp->init_block->filter[1] = 0x00000000; - lp->init_block->rx_ring = (u32) le32_to_cpu(lp->rx_ring_dma_addr); - lp->init_block->tx_ring = (u32) le32_to_cpu(lp->tx_ring_dma_addr); + lp->init_block->rx_ring = cpu_to_le32(lp->rx_ring_dma_addr); + lp->init_block->tx_ring = cpu_to_le32(lp->tx_ring_dma_addr); /* switch pcnet32 to 32bit mode */ a->write_bcr(ioaddr, 20, 2); @@ -2274,7 +2274,7 @@ static int pcnet32_open(struct net_device *dev) #endif lp->init_block->mode = - le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7); + cpu_to_le16((lp->options & PCNET32_PORT_PORTSEL) << 7); pcnet32_load_multicast(dev); if (pcnet32_init_ring(dev)) { @@ -2401,10 +2401,10 @@ static int pcnet32_init_ring(struct net_device *dev) lp->rx_dma_addr[i] = pci_map_single(lp->pci_dev, rx_skbuff->data, PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE); - lp->rx_ring[i].base = (u32) le32_to_cpu(lp->rx_dma_addr[i]); - lp->rx_ring[i].buf_length = le16_to_cpu(2 - PKT_BUF_SZ); + lp->rx_ring[i].base = cpu_to_le32(lp->rx_dma_addr[i]); + lp->rx_ring[i].buf_length = cpu_to_le16(2 - PKT_BUF_SZ); wmb(); /* Make sure owner changes after all others are visible */ - lp->rx_ring[i].status = le16_to_cpu(0x8000); + lp->rx_ring[i].status = cpu_to_le16(0x8000); } /* The Tx buffer address is filled in as needed, but we do need to clear * the upper ownership bit. */ @@ -2416,11 +2416,11 @@ static int pcnet32_init_ring(struct net_device *dev) } lp->init_block->tlen_rlen = - le16_to_cpu(lp->tx_len_bits | lp->rx_len_bits); + cpu_to_le16(lp->tx_len_bits | lp->rx_len_bits); for (i = 0; i < 6; i++) lp->init_block->phys_addr[i] = dev->dev_addr[i]; - lp->init_block->rx_ring = (u32) le32_to_cpu(lp->rx_ring_dma_addr); - lp->init_block->tx_ring = (u32) le32_to_cpu(lp->tx_ring_dma_addr); + lp->init_block->rx_ring = cpu_to_le32(lp->rx_ring_dma_addr); + lp->init_block->tx_ring = cpu_to_le32(lp->tx_ring_dma_addr); wmb(); /* Make sure all changes are visible */ return 0; } @@ -2529,16 +2529,16 @@ static int pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Caution: the write order is important here, set the status * with the "ownership" bits last. */ - lp->tx_ring[entry].length = le16_to_cpu(-skb->len); + lp->tx_ring[entry].length = cpu_to_le16(-skb->len); lp->tx_ring[entry].misc = 0x00000000; lp->tx_skbuff[entry] = skb; lp->tx_dma_addr[entry] = pci_map_single(lp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE); - lp->tx_ring[entry].base = (u32) le32_to_cpu(lp->tx_dma_addr[entry]); + lp->tx_ring[entry].base = cpu_to_le32(lp->tx_dma_addr[entry]); wmb(); /* Make sure owner changes after all others are visible */ - lp->tx_ring[entry].status = le16_to_cpu(status); + lp->tx_ring[entry].status = cpu_to_le16(status); lp->cur_tx++; lp->stats.tx_bytes += skb->len; @@ -2709,7 +2709,7 @@ static void pcnet32_load_multicast(struct net_device *dev) { struct pcnet32_private *lp = netdev_priv(dev); volatile struct pcnet32_init_block *ib = lp->init_block; - volatile u16 *mcast_table = (u16 *) & ib->filter; + volatile __le16 *mcast_table = (__le16 *)ib->filter; struct dev_mc_list *dmi = dev->mc_list; unsigned long ioaddr = dev->base_addr; char *addrs; @@ -2718,8 +2718,8 @@ static void pcnet32_load_multicast(struct net_device *dev) /* set all multicast bits */ if (dev->flags & IFF_ALLMULTI) { - ib->filter[0] = 0xffffffff; - ib->filter[1] = 0xffffffff; + ib->filter[0] = cpu_to_le32(~0U); + ib->filter[1] = cpu_to_le32(~0U); lp->a.write_csr(ioaddr, PCNET32_MC_FILTER, 0xffff); lp->a.write_csr(ioaddr, PCNET32_MC_FILTER+1, 0xffff); lp->a.write_csr(ioaddr, PCNET32_MC_FILTER+2, 0xffff); @@ -2741,9 +2741,7 @@ static void pcnet32_load_multicast(struct net_device *dev) crc = ether_crc_le(6, addrs); crc = crc >> 26; - mcast_table[crc >> 4] = - le16_to_cpu(le16_to_cpu(mcast_table[crc >> 4]) | - (1 << (crc & 0xf))); + mcast_table[crc >> 4] |= cpu_to_le16(1 << (crc & 0xf)); } for (i = 0; i < 4; i++) lp->a.write_csr(ioaddr, PCNET32_MC_FILTER + i, @@ -2769,12 +2767,12 @@ static void pcnet32_set_multicast_list(struct net_device *dev) printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name); lp->init_block->mode = - le16_to_cpu(0x8000 | (lp->options & PCNET32_PORT_PORTSEL) << + cpu_to_le16(0x8000 | (lp->options & PCNET32_PORT_PORTSEL) << 7); lp->a.write_csr(ioaddr, CSR15, csr15 | 0x8000); } else { lp->init_block->mode = - le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7); + cpu_to_le16((lp->options & PCNET32_PORT_PORTSEL) << 7); lp->a.write_csr(ioaddr, CSR15, csr15 & 0x7fff); pcnet32_load_multicast(dev); } -- cgit v1.2.3-70-g09d2 From c676504ef5fe682bd343149de0e5c57bbf793ff9 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 23 Aug 2007 00:47:03 -0400 Subject: ixgb: endianness Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/ixgb/ixgb_ee.c | 16 ++++++++-------- drivers/net/ixgb/ixgb_ee.h | 28 ++++++++++++++-------------- drivers/net/ixgb/ixgb_ethtool.c | 4 ++-- drivers/net/ixgb/ixgb_hw.h | 4 ++-- 4 files changed, 26 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ixgb/ixgb_ee.c b/drivers/net/ixgb/ixgb_ee.c index 52c99d01d56..e8eb0fd6c57 100644 --- a/drivers/net/ixgb/ixgb_ee.c +++ b/drivers/net/ixgb/ixgb_ee.c @@ -411,7 +411,7 @@ ixgb_write_eeprom(struct ixgb_hw *hw, uint16_t offset, uint16_t data) ixgb_cleanup_eeprom(hw); /* clear the init_ctrl_reg_1 to signify that the cache is invalidated */ - ee_map->init_ctrl_reg_1 = le16_to_cpu(EEPROM_ICW1_SIGNATURE_CLEAR); + ee_map->init_ctrl_reg_1 = cpu_to_le16(EEPROM_ICW1_SIGNATURE_CLEAR); return; } @@ -476,19 +476,19 @@ ixgb_get_eeprom_data(struct ixgb_hw *hw) uint16_t ee_data; ee_data = ixgb_read_eeprom(hw, i); checksum += ee_data; - hw->eeprom[i] = le16_to_cpu(ee_data); + hw->eeprom[i] = cpu_to_le16(ee_data); } if (checksum != (uint16_t) EEPROM_SUM) { DEBUGOUT("ixgb_ee: Checksum invalid.\n"); /* clear the init_ctrl_reg_1 to signify that the cache is * invalidated */ - ee_map->init_ctrl_reg_1 = le16_to_cpu(EEPROM_ICW1_SIGNATURE_CLEAR); + ee_map->init_ctrl_reg_1 = cpu_to_le16(EEPROM_ICW1_SIGNATURE_CLEAR); return (FALSE); } - if ((ee_map->init_ctrl_reg_1 & le16_to_cpu(EEPROM_ICW1_SIGNATURE_MASK)) - != le16_to_cpu(EEPROM_ICW1_SIGNATURE_VALID)) { + if ((ee_map->init_ctrl_reg_1 & cpu_to_le16(EEPROM_ICW1_SIGNATURE_MASK)) + != cpu_to_le16(EEPROM_ICW1_SIGNATURE_VALID)) { DEBUGOUT("ixgb_ee: Signature invalid.\n"); return(FALSE); } @@ -511,8 +511,8 @@ ixgb_check_and_get_eeprom_data (struct ixgb_hw* hw) { struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom; - if ((ee_map->init_ctrl_reg_1 & le16_to_cpu(EEPROM_ICW1_SIGNATURE_MASK)) - == le16_to_cpu(EEPROM_ICW1_SIGNATURE_VALID)) { + if ((ee_map->init_ctrl_reg_1 & cpu_to_le16(EEPROM_ICW1_SIGNATURE_MASK)) + == cpu_to_le16(EEPROM_ICW1_SIGNATURE_VALID)) { return (TRUE); } else { return ixgb_get_eeprom_data(hw); @@ -528,7 +528,7 @@ ixgb_check_and_get_eeprom_data (struct ixgb_hw* hw) * Returns: * Word at indexed offset in eeprom, if valid, 0 otherwise. ******************************************************************************/ -uint16_t +__le16 ixgb_get_eeprom_word(struct ixgb_hw *hw, uint16_t index) { diff --git a/drivers/net/ixgb/ixgb_ee.h b/drivers/net/ixgb/ixgb_ee.h index ef236b935c1..7908bf3005e 100644 --- a/drivers/net/ixgb/ixgb_ee.h +++ b/drivers/net/ixgb/ixgb_ee.h @@ -76,22 +76,22 @@ /* EEPROM structure */ struct ixgb_ee_map_type { uint8_t mac_addr[IXGB_ETH_LENGTH_OF_ADDRESS]; - uint16_t compatibility; - uint16_t reserved1[4]; - uint32_t pba_number; - uint16_t init_ctrl_reg_1; - uint16_t subsystem_id; - uint16_t subvendor_id; - uint16_t device_id; - uint16_t vendor_id; - uint16_t init_ctrl_reg_2; - uint16_t oem_reserved[16]; - uint16_t swdpins_reg; - uint16_t circuit_ctrl_reg; + __le16 compatibility; + __le16 reserved1[4]; + __le32 pba_number; + __le16 init_ctrl_reg_1; + __le16 subsystem_id; + __le16 subvendor_id; + __le16 device_id; + __le16 vendor_id; + __le16 init_ctrl_reg_2; + __le16 oem_reserved[16]; + __le16 swdpins_reg; + __le16 circuit_ctrl_reg; uint8_t d3_power; uint8_t d0_power; - uint16_t reserved2[28]; - uint16_t checksum; + __le16 reserved2[28]; + __le16 checksum; }; /* EEPROM Functions */ diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c index ddad26bb5c5..fddd5844168 100644 --- a/drivers/net/ixgb/ixgb_ethtool.c +++ b/drivers/net/ixgb/ixgb_ethtool.c @@ -422,7 +422,7 @@ ixgb_get_eeprom(struct net_device *netdev, { struct ixgb_adapter *adapter = netdev_priv(netdev); struct ixgb_hw *hw = &adapter->hw; - uint16_t *eeprom_buff; + __le16 *eeprom_buff; int i, max_len, first_word, last_word; int ret_val = 0; @@ -446,7 +446,7 @@ ixgb_get_eeprom(struct net_device *netdev, first_word = eeprom->offset >> 1; last_word = (eeprom->offset + eeprom->len - 1) >> 1; - eeprom_buff = kmalloc(sizeof(uint16_t) * + eeprom_buff = kmalloc(sizeof(__le16) * (last_word - first_word + 1), GFP_KERNEL); if(!eeprom_buff) return -ENOMEM; diff --git a/drivers/net/ixgb/ixgb_hw.h b/drivers/net/ixgb/ixgb_hw.h index 40ef5ca8871..af5643324ee 100644 --- a/drivers/net/ixgb/ixgb_hw.h +++ b/drivers/net/ixgb/ixgb_hw.h @@ -711,7 +711,7 @@ struct ixgb_hw { uint32_t bar2; uint32_t bar3; uint16_t pci_cmd_word; /* PCI command register id from PCI configuration space */ - uint16_t eeprom[IXGB_EEPROM_SIZE]; /* EEPROM contents read at init time */ + __le16 eeprom[IXGB_EEPROM_SIZE]; /* EEPROM contents read at init time */ unsigned long io_base; /* Our I/O mapped location */ uint32_t lastLFC; uint32_t lastRFC; @@ -809,7 +809,7 @@ void ixgb_get_ee_mac_addr(struct ixgb_hw *hw, uint8_t *mac_addr); uint32_t ixgb_get_ee_pba_number(struct ixgb_hw *hw); uint16_t ixgb_get_ee_device_id(struct ixgb_hw *hw); boolean_t ixgb_get_eeprom_data(struct ixgb_hw *hw); -uint16_t ixgb_get_eeprom_word(struct ixgb_hw *hw, uint16_t index); +__le16 ixgb_get_eeprom_word(struct ixgb_hw *hw, uint16_t index); /* Everything else */ void ixgb_led_on(struct ixgb_hw *hw); -- cgit v1.2.3-70-g09d2 From 37e1370b701b9a032399e8e2d130009eefa66782 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 23 Aug 2007 00:54:10 -0400 Subject: drivers/net/irda: endianness, NULL noise Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/irda/mcs7780.c | 2 +- drivers/net/irda/sir_dev.c | 2 +- drivers/net/irda/stir4200.c | 2 +- drivers/net/irda/vlsi_ir.h | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/irda/mcs7780.c b/drivers/net/irda/mcs7780.c index 808939b9f8f..0b769192d4c 100644 --- a/drivers/net/irda/mcs7780.c +++ b/drivers/net/irda/mcs7780.c @@ -464,7 +464,7 @@ static void mcs_unwrap_fir(struct mcs_cb *mcs, __u8 *buf, int len) } fcs = ~(crc32_le(~0, buf, new_len)); - if(fcs != le32_to_cpu(get_unaligned((u32 *)(buf+new_len)))) { + if(fcs != le32_to_cpu(get_unaligned((__le32 *)(buf+new_len)))) { IRDA_ERROR("crc error calc 0x%x len %d\n", fcs, new_len); mcs->stats.rx_errors++; mcs->stats.rx_crc_errors++; diff --git a/drivers/net/irda/sir_dev.c b/drivers/net/irda/sir_dev.c index bbe4e094c42..6078e03de9a 100644 --- a/drivers/net/irda/sir_dev.c +++ b/drivers/net/irda/sir_dev.c @@ -414,7 +414,7 @@ EXPORT_SYMBOL(sirdev_raw_read); int sirdev_set_dtr_rts(struct sir_dev *dev, int dtr, int rts) { int ret = -ENXIO; - if (dev->drv->set_dtr_rts != 0) + if (dev->drv->set_dtr_rts) ret = dev->drv->set_dtr_rts(dev, dtr, rts); return ret; } diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c index 1afaee0fa7e..042bc2f0417 100644 --- a/drivers/net/irda/stir4200.c +++ b/drivers/net/irda/stir4200.c @@ -332,7 +332,7 @@ static void fir_eof(struct stir_cb *stir) } fcs = ~(crc32_le(~0, rx_buff->data, len)); - if (fcs != le32_to_cpu(get_unaligned((u32 *)(rx_buff->data+len)))) { + if (fcs != le32_to_cpu(get_unaligned((__le32 *)(rx_buff->data+len)))) { pr_debug("crc error calc 0x%x len %d\n", fcs, len); stir->stats.rx_errors++; stir->stats.rx_crc_errors++; diff --git a/drivers/net/irda/vlsi_ir.h b/drivers/net/irda/vlsi_ir.h index ca12a609641..c8b9c74eea5 100644 --- a/drivers/net/irda/vlsi_ir.h +++ b/drivers/net/irda/vlsi_ir.h @@ -537,10 +537,10 @@ calc_width_bits(unsigned baudrate, unsigned widthselect, unsigned clockselect) */ struct ring_descr_hw { - volatile u16 rd_count; /* tx/rx count [11:0] */ - u16 reserved; + volatile __le16 rd_count; /* tx/rx count [11:0] */ + __le16 reserved; union { - u32 addr; /* [23:0] of the buffer's busaddress */ + __le32 addr; /* [23:0] of the buffer's busaddress */ struct { u8 addr_res[3]; volatile u8 status; /* descriptor status */ -- cgit v1.2.3-70-g09d2 From 88b1943bd3e4d2620e5936181861e00bf6236aa4 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 23 Aug 2007 02:29:45 -0400 Subject: starfire: trivial endianness annotations Note: we still have several fishy areas - mcast filter and vlan handling. Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/starfire.c | 88 +++++++++++++++++++++++++------------------------- 1 file changed, 44 insertions(+), 44 deletions(-) (limited to 'drivers') diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index ea253754763..bcc430bd9e4 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -155,7 +155,7 @@ static int full_duplex[MAX_UNITS] = {0, }; #if (defined(__i386__) && defined(CONFIG_HIGHMEM64G)) || defined(__x86_64__) || defined (__ia64__) || defined(__alpha__) || defined(__mips64__) || (defined(__mips__) && defined(CONFIG_HIGHMEM) && defined(CONFIG_64BIT_PHYS_ADDR)) /* 64-bit dma_addr_t */ #define ADDR_64BITS /* This chip uses 64 bit addresses. */ -#define netdrv_addr_t u64 +#define netdrv_addr_t __le64 #define cpu_to_dma(x) cpu_to_le64(x) #define dma_to_cpu(x) le64_to_cpu(x) #define RX_DESC_Q_ADDR_SIZE RxDescQAddr64bit @@ -164,7 +164,7 @@ static int full_duplex[MAX_UNITS] = {0, }; #define TX_COMPL_Q_ADDR_SIZE TxComplQAddr64bit #define RX_DESC_ADDR_SIZE RxDescAddr64bit #else /* 32-bit dma_addr_t */ -#define netdrv_addr_t u32 +#define netdrv_addr_t __le32 #define cpu_to_dma(x) cpu_to_le32(x) #define dma_to_cpu(x) le32_to_cpu(x) #define RX_DESC_Q_ADDR_SIZE RxDescQAddr32bit @@ -494,7 +494,7 @@ enum intr_ctrl_bits { /* The Rx and Tx buffer descriptors. */ struct starfire_rx_desc { - dma_addr_t rxaddr; + netdrv_addr_t rxaddr; }; enum rx_desc_bits { RxDescValid=1, RxDescEndRing=2, @@ -502,25 +502,25 @@ enum rx_desc_bits { /* Completion queue entry. */ struct short_rx_done_desc { - u32 status; /* Low 16 bits is length. */ + __le32 status; /* Low 16 bits is length. */ }; struct basic_rx_done_desc { - u32 status; /* Low 16 bits is length. */ - u16 vlanid; - u16 status2; + __le32 status; /* Low 16 bits is length. */ + __le16 vlanid; + __le16 status2; }; struct csum_rx_done_desc { - u32 status; /* Low 16 bits is length. */ - u16 csum; /* Partial checksum */ - u16 status2; + __le32 status; /* Low 16 bits is length. */ + __le16 csum; /* Partial checksum */ + __le16 status2; }; struct full_rx_done_desc { - u32 status; /* Low 16 bits is length. */ - u16 status3; - u16 status2; - u16 vlanid; - u16 csum; /* partial checksum */ - u32 timestamp; + __le32 status; /* Low 16 bits is length. */ + __le16 status3; + __le16 status2; + __le16 vlanid; + __le16 csum; /* partial checksum */ + __le32 timestamp; }; /* XXX: this is ugly and I'm not sure it's worth the trouble -Ion */ #ifdef VLAN_SUPPORT @@ -537,15 +537,15 @@ enum rx_done_bits { /* Type 1 Tx descriptor. */ struct starfire_tx_desc_1 { - u32 status; /* Upper bits are status, lower 16 length. */ - u32 addr; + __le32 status; /* Upper bits are status, lower 16 length. */ + __le32 addr; }; /* Type 2 Tx descriptor. */ struct starfire_tx_desc_2 { - u32 status; /* Upper bits are status, lower 16 length. */ - u32 reserved; - u64 addr; + __le32 status; /* Upper bits are status, lower 16 length. */ + __le32 reserved; + __le64 addr; }; #ifdef ADDR_64BITS @@ -563,9 +563,9 @@ enum tx_desc_bits { TxRingWrap=0x04000000, TxCalTCP=0x02000000, }; struct tx_done_desc { - u32 status; /* timestamp, index. */ + __le32 status; /* timestamp, index. */ #if 0 - u32 intrstatus; /* interrupt status */ + __le32 intrstatus; /* interrupt status */ #endif }; @@ -963,7 +963,7 @@ static int netdev_open(struct net_device *dev) dev->name, dev->irq); /* Allocate the various queues. */ - if (np->queue_mem == 0) { + if (!np->queue_mem) { tx_done_q_size = ((sizeof(struct tx_done_desc) * DONE_Q_SIZE + QUEUE_ALIGN - 1) / QUEUE_ALIGN) * QUEUE_ALIGN; rx_done_q_size = ((sizeof(rx_done_desc) * DONE_Q_SIZE + QUEUE_ALIGN - 1) / QUEUE_ALIGN) * QUEUE_ALIGN; tx_ring_size = ((sizeof(starfire_tx_desc) * TX_RING_SIZE + QUEUE_ALIGN - 1) / QUEUE_ALIGN) * QUEUE_ALIGN; @@ -1036,11 +1036,11 @@ static int netdev_open(struct net_device *dev) writew(0, ioaddr + PerfFilterTable + 4); writew(0, ioaddr + PerfFilterTable + 8); for (i = 1; i < 16; i++) { - u16 *eaddrs = (u16 *)dev->dev_addr; + __be16 *eaddrs = (__be16 *)dev->dev_addr; void __iomem *setup_frm = ioaddr + PerfFilterTable + i * 16; - writew(cpu_to_be16(eaddrs[2]), setup_frm); setup_frm += 4; - writew(cpu_to_be16(eaddrs[1]), setup_frm); setup_frm += 4; - writew(cpu_to_be16(eaddrs[0]), setup_frm); setup_frm += 8; + writew(be16_to_cpu(eaddrs[2]), setup_frm); setup_frm += 4; + writew(be16_to_cpu(eaddrs[1]), setup_frm); setup_frm += 4; + writew(be16_to_cpu(eaddrs[0]), setup_frm); setup_frm += 8; } /* Initialize other registers. */ @@ -1767,26 +1767,26 @@ static void set_rx_mode(struct net_device *dev) } else if (dev->mc_count <= 14) { /* Use the 16 element perfect filter, skip first two entries. */ void __iomem *filter_addr = ioaddr + PerfFilterTable + 2 * 16; - u16 *eaddrs; + __be16 *eaddrs; for (i = 2, mclist = dev->mc_list; mclist && i < dev->mc_count + 2; i++, mclist = mclist->next) { - eaddrs = (u16 *)mclist->dmi_addr; - writew(cpu_to_be16(eaddrs[2]), filter_addr); filter_addr += 4; - writew(cpu_to_be16(eaddrs[1]), filter_addr); filter_addr += 4; - writew(cpu_to_be16(eaddrs[0]), filter_addr); filter_addr += 8; + eaddrs = (__be16 *)mclist->dmi_addr; + writew(be16_to_cpu(eaddrs[2]), filter_addr); filter_addr += 4; + writew(be16_to_cpu(eaddrs[1]), filter_addr); filter_addr += 4; + writew(be16_to_cpu(eaddrs[0]), filter_addr); filter_addr += 8; } - eaddrs = (u16 *)dev->dev_addr; + eaddrs = (__be16 *)dev->dev_addr; while (i++ < 16) { - writew(cpu_to_be16(eaddrs[0]), filter_addr); filter_addr += 4; - writew(cpu_to_be16(eaddrs[1]), filter_addr); filter_addr += 4; - writew(cpu_to_be16(eaddrs[2]), filter_addr); filter_addr += 8; + writew(be16_to_cpu(eaddrs[0]), filter_addr); filter_addr += 4; + writew(be16_to_cpu(eaddrs[1]), filter_addr); filter_addr += 4; + writew(be16_to_cpu(eaddrs[2]), filter_addr); filter_addr += 8; } rx_mode |= AcceptBroadcast|PerfectFilter; } else { /* Must use a multicast hash table. */ void __iomem *filter_addr; - u16 *eaddrs; - u16 mc_filter[32] __attribute__ ((aligned(sizeof(long)))); /* Multicast hash filter */ + __be16 *eaddrs; + __le16 mc_filter[32] __attribute__ ((aligned(sizeof(long)))); /* Multicast hash filter */ memset(mc_filter, 0, sizeof(mc_filter)); for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; @@ -1794,17 +1794,17 @@ static void set_rx_mode(struct net_device *dev) /* The chip uses the upper 9 CRC bits as index into the hash table */ int bit_nr = ether_crc_le(ETH_ALEN, mclist->dmi_addr) >> 23; - __u32 *fptr = (__u32 *) &mc_filter[(bit_nr >> 4) & ~1]; + __le32 *fptr = (__le32 *) &mc_filter[(bit_nr >> 4) & ~1]; *fptr |= cpu_to_le32(1 << (bit_nr & 31)); } /* Clear the perfect filter list, skip first two entries. */ filter_addr = ioaddr + PerfFilterTable + 2 * 16; - eaddrs = (u16 *)dev->dev_addr; + eaddrs = (__be16 *)dev->dev_addr; for (i = 2; i < 16; i++) { - writew(cpu_to_be16(eaddrs[0]), filter_addr); filter_addr += 4; - writew(cpu_to_be16(eaddrs[1]), filter_addr); filter_addr += 4; - writew(cpu_to_be16(eaddrs[2]), filter_addr); filter_addr += 8; + writew(be16_to_cpu(eaddrs[0]), filter_addr); filter_addr += 4; + writew(be16_to_cpu(eaddrs[1]), filter_addr); filter_addr += 4; + writew(be16_to_cpu(eaddrs[2]), filter_addr); filter_addr += 8; } for (filter_addr = ioaddr + HashTable, i = 0; i < 32; filter_addr+= 16, i++) writew(mc_filter[i], filter_addr); -- cgit v1.2.3-70-g09d2 From b1eab70130fd60082cce11caba14fe8c99a018e9 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 23 Aug 2007 02:30:16 -0400 Subject: r8169: endianness Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/r8169.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index eecd811feea..419c00cbe6e 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -977,19 +977,19 @@ static const char rtl8169_gstrings[][ETH_GSTRING_LEN] = { }; struct rtl8169_counters { - u64 tx_packets; - u64 rx_packets; - u64 tx_errors; - u32 rx_errors; - u16 rx_missed; - u16 align_errors; - u32 tx_one_collision; - u32 tx_multi_collision; - u64 rx_unicast; - u64 rx_broadcast; - u32 rx_multicast; - u16 tx_aborted; - u16 tx_underun; + __le64 tx_packets; + __le64 rx_packets; + __le64 tx_errors; + __le32 rx_errors; + __le16 rx_missed; + __le16 align_errors; + __le32 tx_one_collision; + __le32 tx_multi_collision; + __le64 rx_unicast; + __le64 rx_broadcast; + __le32 rx_multicast; + __le16 tx_aborted; + __le16 tx_underun; }; static int rtl8169_get_sset_count(struct net_device *dev, int sset) -- cgit v1.2.3-70-g09d2 From 53c03f5c9e3c05a2484ad6bb1d88c0aa54befa47 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 23 Aug 2007 02:33:30 -0400 Subject: via-rhine: endianness Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/via-rhine.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index 9669bce0fd0..07263cd93f9 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -335,16 +335,16 @@ enum wol_bits { /* The Rx and Tx buffer descriptors. */ struct rx_desc { - s32 rx_status; - u32 desc_length; /* Chain flag, Buffer/frame length */ - u32 addr; - u32 next_desc; + __le32 rx_status; + __le32 desc_length; /* Chain flag, Buffer/frame length */ + __le32 addr; + __le32 next_desc; }; struct tx_desc { - s32 tx_status; - u32 desc_length; /* Chain flag, Tx Config, Frame length */ - u32 addr; - u32 next_desc; + __le32 tx_status; + __le32 desc_length; /* Chain flag, Tx Config, Frame length */ + __le32 addr; + __le32 next_desc; }; /* Initial value for tx_desc.desc_length, Buffer size goes to bits 0-10 */ -- cgit v1.2.3-70-g09d2 From b963dc1df78399a2166c2e6e3eb726a2dc98cf11 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 23 Aug 2007 02:55:33 -0400 Subject: pppoe: endianness Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/pppoe.c | 18 +++++++++--------- include/linux/if_pppox.h | 12 ++++++------ 2 files changed, 15 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index ba2eb04aac9..d48b7b73d89 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -103,7 +103,7 @@ static inline int cmp_2_addr(struct pppoe_addr *a, struct pppoe_addr *b) (memcmp(a->remote, b->remote, ETH_ALEN) == 0)); } -static inline int cmp_addr(struct pppoe_addr *a, unsigned long sid, char *addr) +static inline int cmp_addr(struct pppoe_addr *a, __be16 sid, char *addr) { return (a->sid == sid && (memcmp(a->remote,addr,ETH_ALEN) == 0)); @@ -113,7 +113,7 @@ static inline int cmp_addr(struct pppoe_addr *a, unsigned long sid, char *addr) #error 8 must be a multiple of PPPOE_HASH_BITS #endif -static int hash_item(unsigned int sid, unsigned char *addr) +static int hash_item(__be16 sid, unsigned char *addr) { unsigned char hash = 0; unsigned int i; @@ -122,7 +122,7 @@ static int hash_item(unsigned int sid, unsigned char *addr) hash ^= addr[i]; } for (i = 0 ; i < sizeof(sid_t)*8 ; i += 8 ){ - hash ^= sid>>i; + hash ^= (__force __u32)sid>>i; } for (i = 8 ; (i>>=1) >= PPPOE_HASH_BITS ; ) { hash ^= hash>>i; @@ -139,7 +139,7 @@ static struct pppox_sock *item_hash_table[PPPOE_HASH_SIZE]; * Set/get/delete/rehash items (internal versions) * **********************************************************************/ -static struct pppox_sock *__get_item(unsigned long sid, unsigned char *addr, int ifindex) +static struct pppox_sock *__get_item(__be16 sid, unsigned char *addr, int ifindex) { int hash = hash_item(sid, addr); struct pppox_sock *ret; @@ -171,7 +171,7 @@ static int __set_item(struct pppox_sock *po) return 0; } -static struct pppox_sock *__delete_item(unsigned long sid, char *addr, int ifindex) +static struct pppox_sock *__delete_item(__be16 sid, char *addr, int ifindex) { int hash = hash_item(sid, addr); struct pppox_sock *ret, **src; @@ -197,7 +197,7 @@ static struct pppox_sock *__delete_item(unsigned long sid, char *addr, int ifind * Set/get/delete/rehash items * **********************************************************************/ -static inline struct pppox_sock *get_item(unsigned long sid, +static inline struct pppox_sock *get_item(__be16 sid, unsigned char *addr, int ifindex) { struct pppox_sock *po; @@ -224,7 +224,7 @@ static inline struct pppox_sock *get_item_by_addr(struct sockaddr_pppox *sp) return get_item(sp->sa_addr.pppoe.sid, sp->sa_addr.pppoe.remote, ifindex); } -static inline struct pppox_sock *delete_item(unsigned long sid, char *addr, int ifindex) +static inline struct pppox_sock *delete_item(__be16 sid, char *addr, int ifindex) { struct pppox_sock *ret; @@ -400,7 +400,7 @@ static int pppoe_rcv(struct sk_buff *skb, ph = pppoe_hdr(skb); - po = get_item((unsigned long) ph->sid, eth_hdr(skb)->h_source, dev->ifindex); + po = get_item(ph->sid, eth_hdr(skb)->h_source, dev->ifindex); if (po != NULL) return sk_receive_skb(sk_pppox(po), skb, 0); drop: @@ -437,7 +437,7 @@ static int pppoe_disc_rcv(struct sk_buff *skb, if (ph->code != PADT_CODE) goto abort; - po = get_item((unsigned long) ph->sid, eth_hdr(skb)->h_source, dev->ifindex); + po = get_item(ph->sid, eth_hdr(skb)->h_source, dev->ifindex); if (po) { struct sock *sk = sk_pppox(po); diff --git a/include/linux/if_pppox.h b/include/linux/if_pppox.h index 43cfc9f0c07..40743e03284 100644 --- a/include/linux/if_pppox.h +++ b/include/linux/if_pppox.h @@ -40,7 +40,7 @@ /************************************************************************ * PPPoE addressing definition */ -typedef __u16 sid_t; +typedef __be16 sid_t; struct pppoe_addr{ sid_t sid; /* Session identifier */ unsigned char remote[ETH_ALEN]; /* Remote address */ @@ -90,8 +90,8 @@ struct sockaddr_pppol2tp { #define PADS_CODE 0x65 #define PADT_CODE 0xa7 struct pppoe_tag { - __u16 tag_type; - __u16 tag_len; + __be16 tag_type; + __be16 tag_len; char tag_data[0]; } __attribute ((packed)); @@ -118,8 +118,8 @@ struct pppoe_hdr { #error "Please fix " #endif __u8 code; - __u16 sid; - __u16 length; + __be16 sid; + __be16 length; struct pppoe_tag tag[0]; } __attribute__ ((packed)); @@ -152,7 +152,7 @@ struct pppox_sock { union { struct pppoe_opt pppoe; } proto; - unsigned short num; + __be16 num; }; #define pppoe_dev proto.pppoe.dev #define pppoe_ifindex proto.pppoe.ifindex -- cgit v1.2.3-70-g09d2 From 2929e7700fb64f58f9c501a293b98b6bf6c49403 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 23 Aug 2007 02:57:00 -0400 Subject: tms380tr: trivial endianness annotations Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/tokenring/tms380tr.c | 4 ++-- drivers/net/tokenring/tms380tr.h | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c index 12bd294045a..d5fa36d3651 100644 --- a/drivers/net/tokenring/tms380tr.c +++ b/drivers/net/tokenring/tms380tr.c @@ -2124,7 +2124,7 @@ static void tms380tr_rcv_status_irq(struct net_device *dev) /* Get the frame size (Byte swap for Intel). * Do this early (see workaround comment below) */ - Length = be16_to_cpu((unsigned short)rpl->FrameSize); + Length = be16_to_cpu(rpl->FrameSize); /* Check if the Frame_Start, Frame_End and * Frame_Complete bits are set. @@ -2140,7 +2140,7 @@ static void tms380tr_rcv_status_irq(struct net_device *dev) * Length2 is there because there have also been * cases where the FrameSize was partially written */ - Length2 = be16_to_cpu((unsigned short)rpl->FrameSize); + Length2 = be16_to_cpu(rpl->FrameSize); if(Length == 0 || Length != Length2) { diff --git a/drivers/net/tokenring/tms380tr.h b/drivers/net/tokenring/tms380tr.h index 2a16078ac3f..7daf74e31cc 100644 --- a/drivers/net/tokenring/tms380tr.h +++ b/drivers/net/tokenring/tms380tr.h @@ -476,13 +476,13 @@ typedef struct { * bytes = 0xC000 */ u_int32_t FunctAddr; /* High order bytes = 0xC000 */ - u_int16_t RxListSize; /* RPL size: 0 (=26), 14, 20 or + __be16 RxListSize; /* RPL size: 0 (=26), 14, 20 or * 26 bytes read by the adapter. * (Depending on the number of * fragments/list) */ - u_int16_t TxListSize; /* TPL size */ - u_int16_t BufSize; /* Is automatically rounded up to the + __be16 TxListSize; /* TPL size */ + __be16 BufSize; /* Is automatically rounded up to the * nearest nK boundary. */ u_int16_t FullDuplex; @@ -580,14 +580,14 @@ typedef struct { /*--------------------- Send and Receive definitions -------------------*/ #pragma pack(1) typedef struct { - u_int16_t DataCount; /* Value 0, even and odd values are + __be16 DataCount; /* Value 0, even and odd values are * permitted; value is unaltered most * significant bit set: following * fragments last fragment: most * significant bit is not evaluated. * (???) */ - u_int32_t DataAddr; /* Pointer to frame data fragment; + __be32 DataAddr; /* Pointer to frame data fragment; * even or odd. */ } Fragment; @@ -679,7 +679,7 @@ typedef struct { typedef struct s_TPL TPL; struct s_TPL { /* Transmit Parameter List (align on even word boundaries) */ - u_int32_t NextTPLAddr; /* Pointer to next TPL in chain; if + __be32 NextTPLAddr; /* Pointer to next TPL in chain; if * pointer is odd: this is the last * TPL. Pointing to itself can cause * problems! @@ -689,7 +689,7 @@ struct s_TPL { /* Transmit Parameter List (align on even word boundaries) */ * significant bit first! Set by the * adapter: CSTAT_COMPLETE status. */ - u_int16_t FrameSize; /* Number of bytes to be transmitted + __be16 FrameSize; /* Number of bytes to be transmitted * as a frame including AC/FC, * Destination, Source, Routing field * not including CRC, FS, End Delimiter @@ -1020,7 +1020,7 @@ enum SKB_STAT { #pragma pack(1) typedef struct s_RPL RPL; struct s_RPL { /* Receive Parameter List */ - u_int32_t NextRPLAddr; /* Pointer to next RPL in chain + __be32 NextRPLAddr; /* Pointer to next RPL in chain * (normalized = physical 32 bit * address) if pointer is odd: this * is last RPL. Pointing to itself can @@ -1031,7 +1031,7 @@ struct s_RPL { /* Receive Parameter List */ * adapter in lists that start or end * a frame. */ - volatile u_int16_t FrameSize; /* Number of bytes received as a + volatile __be16 FrameSize; /* Number of bytes received as a * frame including AC/FC, Destination, * Source, Routing field not including * CRC, FS (Frame Status), End Delimiter -- cgit v1.2.3-70-g09d2 From 16989ba6e9c501ffc004ec3c031b1c6065708ccf Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 23 Aug 2007 03:03:13 -0400 Subject: drivers/net/appletalk: endianness Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/appletalk/ipddp.c | 2 +- drivers/net/appletalk/ipddp.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c index 56cb9679402..1071144edd6 100644 --- a/drivers/net/appletalk/ipddp.c +++ b/drivers/net/appletalk/ipddp.c @@ -116,7 +116,7 @@ static struct net_device_stats *ipddp_get_stats(struct net_device *dev) */ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev) { - u32 paddr = ((struct rtable*)skb->dst)->rt_gateway; + __be32 paddr = ((struct rtable*)skb->dst)->rt_gateway; struct ddpehdr *ddp; struct ipddp_route *rt; struct atalk_addr *our_addr; diff --git a/drivers/net/appletalk/ipddp.h b/drivers/net/appletalk/ipddp.h index 52072fb0c61..531519da99a 100644 --- a/drivers/net/appletalk/ipddp.h +++ b/drivers/net/appletalk/ipddp.h @@ -14,7 +14,7 @@ struct ipddp_route { struct net_device *dev; /* Carrier device */ - __u32 ip; /* IP address */ + __be32 ip; /* IP address */ struct atalk_addr at; /* Gateway appletalk address */ int flags; struct ipddp_route *next; -- cgit v1.2.3-70-g09d2 From bd7eb1c549188e4f7993e324b1bbe267fc13675c Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 23 Aug 2007 03:03:51 -0400 Subject: 3c509: endianness Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/3c509.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index c576fe76d54..edda6e10ebe 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -299,7 +299,7 @@ static struct isapnp_device_id el3_isapnp_adapters[] __initdata = { { } /* terminate list */ }; -static u16 el3_isapnp_phys_addr[8][3]; +static __be16 el3_isapnp_phys_addr[8][3]; static int nopnp; #endif /* __ISAPNP__ */ @@ -379,7 +379,7 @@ static int __init el3_probe(int card_idx) struct el3_private *lp; short lrs_state = 0xff, i; int ioaddr, irq, if_port; - u16 phys_addr[3]; + __be16 phys_addr[3]; static int current_tag; int err = -ENODEV; #if defined(__ISAPNP__) -- cgit v1.2.3-70-g09d2 From fb8e4444cc8c7719d9947e21a93e2e84bb1b36eb Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 23 Aug 2007 03:04:12 -0400 Subject: cxgb3: trivial endianness annotations Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/cxgb3/common.h | 4 ++-- drivers/net/cxgb3/sge.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h index 3e5b0db7784..99c75d30f67 100644 --- a/drivers/net/cxgb3/common.h +++ b/drivers/net/cxgb3/common.h @@ -168,8 +168,8 @@ enum { }; struct sg_ent { /* SGE scatter/gather entry */ - u32 len[2]; - u64 addr[2]; + __be32 len[2]; + __be64 addr[2]; }; #ifndef SGE_NUM_GENBITS diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c index 540ce5fa1d3..77f3ec5ff8a 100644 --- a/drivers/net/cxgb3/sge.c +++ b/drivers/net/cxgb3/sge.c @@ -79,7 +79,7 @@ enum { }; struct tx_desc { - u64 flit[TX_DESC_FLITS]; + __be64 flit[TX_DESC_FLITS]; }; struct rx_desc { @@ -904,8 +904,8 @@ static void write_wr_hdr_sgl(unsigned int ndesc, struct sk_buff *skb, const struct sge_txq *q, const struct sg_ent *sgl, unsigned int flits, unsigned int sgl_flits, - unsigned int gen, unsigned int wr_hi, - unsigned int wr_lo) + unsigned int gen, __be32 wr_hi, + __be32 wr_lo) { struct work_request_hdr *wrp = (struct work_request_hdr *)d; struct tx_sw_desc *sd = &q->sdesc[pidx]; -- cgit v1.2.3-70-g09d2 From 1a09404a2338163f181d170c7abdc2242b6c6f03 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Thu, 20 Sep 2007 11:13:40 -0700 Subject: [B43]: Fix sparse warnings. The remaining warning in phy.c will be fixed later. Signed-off-by: Michael Buesch Signed-off-by: David S. Miller --- drivers/net/wireless/b43/debugfs.c | 31 +++++++++++++++++++++---------- drivers/net/wireless/b43/leds.c | 8 ++++---- drivers/net/wireless/b43/leds.h | 8 ++++---- drivers/net/wireless/b43/main.c | 5 ++--- drivers/net/wireless/b43/pcmcia.c | 3 +++ drivers/net/wireless/b43/pio.c | 18 ++++++++++-------- drivers/net/wireless/b43/pio.h | 3 +-- drivers/net/wireless/b43/xmit.c | 8 +++++--- 8 files changed, 50 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/debugfs.c b/drivers/net/wireless/b43/debugfs.c index f82e3ef9bd7..3aafde9f08a 100644 --- a/drivers/net/wireless/b43/debugfs.c +++ b/drivers/net/wireless/b43/debugfs.c @@ -39,7 +39,7 @@ /* The root directory. */ -struct dentry *rootdir; +static struct dentry *rootdir; struct b43_debugfs_fops { ssize_t (*read)(struct b43_wldev *dev, char *buf, size_t bufsize); @@ -76,7 +76,8 @@ struct b43_dfs_file * fops_to_dfs_file(struct b43_wldev *dev, /* wl->irq_lock is locked */ -ssize_t tsf_read_file(struct b43_wldev *dev, char *buf, size_t bufsize) +static ssize_t tsf_read_file(struct b43_wldev *dev, + char *buf, size_t bufsize) { ssize_t count = 0; u64 tsf; @@ -90,7 +91,8 @@ ssize_t tsf_read_file(struct b43_wldev *dev, char *buf, size_t bufsize) } /* wl->irq_lock is locked */ -int tsf_write_file(struct b43_wldev *dev, const char *buf, size_t count) +static int tsf_write_file(struct b43_wldev *dev, + const char *buf, size_t count) { u64 tsf; @@ -102,7 +104,8 @@ int tsf_write_file(struct b43_wldev *dev, const char *buf, size_t count) } /* wl->irq_lock is locked */ -ssize_t ucode_regs_read_file(struct b43_wldev *dev, char *buf, size_t bufsize) +static ssize_t ucode_regs_read_file(struct b43_wldev *dev, + char *buf, size_t bufsize) { ssize_t count = 0; int i; @@ -116,7 +119,8 @@ ssize_t ucode_regs_read_file(struct b43_wldev *dev, char *buf, size_t bufsize) } /* wl->irq_lock is locked */ -ssize_t shm_read_file(struct b43_wldev *dev, char *buf, size_t bufsize) +static ssize_t shm_read_file(struct b43_wldev *dev, + char *buf, size_t bufsize) { ssize_t count = 0; int i; @@ -135,7 +139,8 @@ ssize_t shm_read_file(struct b43_wldev *dev, char *buf, size_t bufsize) return count; } -ssize_t txstat_read_file(struct b43_wldev *dev, char *buf, size_t bufsize) +static ssize_t txstat_read_file(struct b43_wldev *dev, + char *buf, size_t bufsize) { struct b43_txstatus_log *log = &dev->dfsentry->txstatlog; ssize_t count = 0; @@ -182,7 +187,8 @@ out_unlock: return count; } -ssize_t txpower_g_read_file(struct b43_wldev *dev, char *buf, size_t bufsize) +static ssize_t txpower_g_read_file(struct b43_wldev *dev, + char *buf, size_t bufsize) { ssize_t count = 0; @@ -214,7 +220,8 @@ out: return count; } -int txpower_g_write_file(struct b43_wldev *dev, const char *buf, size_t count) +static int txpower_g_write_file(struct b43_wldev *dev, + const char *buf, size_t count) { unsigned long flags; unsigned long phy_flags; @@ -262,7 +269,8 @@ out_unlock: } /* wl->irq_lock is locked */ -int restart_write_file(struct b43_wldev *dev, const char *buf, size_t count) +static int restart_write_file(struct b43_wldev *dev, + const char *buf, size_t count) { int err = 0; @@ -294,7 +302,8 @@ static ssize_t append_lo_table(ssize_t count, char *buf, const size_t bufsize, return count; } -ssize_t loctls_read_file(struct b43_wldev *dev, char *buf, size_t bufsize) +static ssize_t loctls_read_file(struct b43_wldev *dev, + char *buf, size_t bufsize) { ssize_t count = 0; struct b43_txpower_lo_control *lo; @@ -383,6 +392,8 @@ static ssize_t b43_debugfs_read(struct file *file, char __user *userbuf, err = -ENOMEM; goto out_unlock; } + /* Sparse warns about the following memset, because it has a big + * size value. That warning is bogus, so I will ignore it. --mb */ memset(buf, 0, bufsize); if (dfops->take_irqlock) { spin_lock_irq(&dev->wl->irq_lock); diff --git a/drivers/net/wireless/b43/leds.c b/drivers/net/wireless/b43/leds.c index 535f960412d..85d965de579 100644 --- a/drivers/net/wireless/b43/leds.c +++ b/drivers/net/wireless/b43/leds.c @@ -32,14 +32,13 @@ static void b43_led_changestate(struct b43_led *led) { struct b43_wldev *dev = led->dev; - const int index = b43_led_index(led); - const u16 mask = (1 << index); + const int index = led->index; u16 ledctl; B43_WARN_ON(!(index >= 0 && index < B43_NR_LEDS)); B43_WARN_ON(!led->blink_interval); ledctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL); - ledctl = (ledctl & mask) ? (ledctl & ~mask) : (ledctl | mask); + ledctl ^= (1 << index); b43_write16(dev, B43_MMIO_GPIO_CONTROL, ledctl); } @@ -70,7 +69,7 @@ static void b43_led_blink_start(struct b43_led *led, unsigned long interval) static void b43_led_blink_stop(struct b43_led *led, int sync) { struct b43_wldev *dev = led->dev; - const int index = b43_led_index(led); + const int index = led->index; u16 ledctl; if (!led->blink_interval) @@ -139,6 +138,7 @@ int b43_leds_init(struct b43_wldev *dev) for (i = 0; i < B43_NR_LEDS; i++) { led = &(dev->leds[i]); + led->index = i; led->dev = dev; setup_timer(&led->blink_timer, b43_led_blink, (unsigned long)led); diff --git a/drivers/net/wireless/b43/leds.h b/drivers/net/wireless/b43/leds.h index 36b46cfda22..d94851d291c 100644 --- a/drivers/net/wireless/b43/leds.h +++ b/drivers/net/wireless/b43/leds.h @@ -5,14 +5,14 @@ #include struct b43_led { - u8 behaviour:7; - u8 activelow:1; - + u8 behaviour; + bool activelow; + /* Index in the "leds" array in b43_wldev */ + u8 index; struct b43_wldev *dev; struct timer_list blink_timer; unsigned long blink_interval; }; -#define b43_led_index(led) ((int)((led) - (led)->dev->leds)) /* Delay between state changes when blinking in jiffies */ #define B43_LEDBLINK_SLOW (HZ / 1) diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index fd4ef27fcf2..66c89df51fb 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -1062,7 +1062,7 @@ static void handle_irq_noise(struct b43_wldev *dev) B43_WARN_ON(!dev->noisecalc.calculation_running); if (dev->noisecalc.channel_at_start != phy->channel) goto drop_calculation; - *((u32 *) noise) = cpu_to_le32(b43_jssi_read(dev)); + *((__le32 *)noise) = cpu_to_le32(b43_jssi_read(dev)); if (noise[0] == 0x7F || noise[1] == 0x7F || noise[2] == 0x7F || noise[3] == 0x7F) goto generate_new; @@ -1598,8 +1598,7 @@ static int do_request_fw(struct b43_wldev *dev, const char *name, const struct firmware **fw) { - const size_t plen = sizeof(modparam_fwpostfix) + 32; - char path[plen]; + char path[sizeof(modparam_fwpostfix) + 32]; struct b43_fw_header *hdr; u32 size; int err; diff --git a/drivers/net/wireless/b43/pcmcia.c b/drivers/net/wireless/b43/pcmcia.c index 3e75a8a12c9..b242a9a90dd 100644 --- a/drivers/net/wireless/b43/pcmcia.c +++ b/drivers/net/wireless/b43/pcmcia.c @@ -21,6 +21,8 @@ */ +#include "pcmcia.h" + #include #include @@ -30,6 +32,7 @@ #include #include + static /*const */ struct pcmcia_device_id b43_pcmcia_tbl[] = { PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x448), PCMCIA_DEVICE_NULL, diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c index 4ac91fdd356..67752a28eb9 100644 --- a/drivers/net/wireless/b43/pio.c +++ b/drivers/net/wireless/b43/pio.c @@ -60,7 +60,7 @@ static u16 tx_get_next_word(const u8 * txhdr, source = packet; i -= txhdr_size; } - ret = le16_to_cpu(*((u16 *) (source + i))); + ret = le16_to_cpu(*((__le16 *)(source + i))); *pos += 2; return ret; @@ -104,7 +104,7 @@ static u16 generate_cookie(struct b43_pioqueue *queue, struct b43_pio_txpacket *packet) { u16 cookie = 0x0000; - int packetindex; + u16 packetindex; /* We use the upper 4 bits for the PIO * controller ID and the lower 12 bits @@ -125,7 +125,7 @@ static u16 generate_cookie(struct b43_pioqueue *queue, default: B43_WARN_ON(1); } - packetindex = pio_txpacket_getindex(packet); + packetindex = packet->index; B43_WARN_ON(packetindex & ~0x0FFF); cookie |= (u16) packetindex; @@ -286,6 +286,7 @@ static void setup_txqueues(struct b43_pioqueue *queue) packet->queue = queue; INIT_LIST_HEAD(&packet->list); + packet->index = i; list_add(&packet->list, &queue->txfree); } @@ -518,9 +519,10 @@ static void pio_rx_error(struct b43_pioqueue *queue, void b43_pio_rx(struct b43_pioqueue *queue) { - u16 preamble[21] = { 0 }; + __le16 preamble[21] = { 0 }; struct b43_rxhdr_fw4 *rxhdr; - u16 tmp, len, macstat; + u16 tmp, len; + u32 macstat; int i, preamble_readwords; struct sk_buff *skb; @@ -537,7 +539,7 @@ void b43_pio_rx(struct b43_pioqueue *queue) } b43dbg(queue->dev->wl, "PIO RX timed out\n"); return; - data_ready: +data_ready: len = b43_pio_read(queue, B43_PIO_RXDATA); if (unlikely(len > 0x700)) { @@ -558,7 +560,7 @@ void b43_pio_rx(struct b43_pioqueue *queue) preamble[i + 1] = cpu_to_le16(tmp); } rxhdr = (struct b43_rxhdr_fw4 *)preamble; - macstat = le16_to_cpu(rxhdr->mac_status); + macstat = le32_to_cpu(rxhdr->mac_status); if (macstat & B43_RX_MAC_FCSERR) { pio_rx_error(queue, (queue->mmio_base == B43_MMIO_PIO1_BASE), @@ -583,7 +585,7 @@ void b43_pio_rx(struct b43_pioqueue *queue) skb_put(skb, len); for (i = 0; i < len - 1; i += 2) { tmp = b43_pio_read(queue, B43_PIO_RXDATA); - *((u16 *) (skb->data + i)) = cpu_to_le16(tmp); + *((__le16 *)(skb->data + i)) = cpu_to_le16(tmp); } if (len % 2) { tmp = b43_pio_read(queue, B43_PIO_RXDATA); diff --git a/drivers/net/wireless/b43/pio.h b/drivers/net/wireless/b43/pio.h index 46d6d2ea9b5..34a44c1b631 100644 --- a/drivers/net/wireless/b43/pio.h +++ b/drivers/net/wireless/b43/pio.h @@ -39,10 +39,9 @@ struct b43_pio_txpacket { struct sk_buff *skb; struct ieee80211_tx_status txstat; struct list_head list; + u16 index; /* Index in the tx_packets_cache */ }; -#define pio_txpacket_getindex(packet) ((int)((packet) - (packet)->queue->tx_packets_cache)) - struct b43_pioqueue { struct b43_wldev *dev; u16 mmio_base; diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index e6174b6f11f..0bd6f8a348a 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -121,10 +121,12 @@ void b43_generate_plcp_hdr(struct b43_plcp_hdr4 *plcp, __u8 *raw = plcp->raw; if (b43_is_ofdm_rate(bitrate)) { - *data = b43_plcp_get_ratecode_ofdm(bitrate); + u32 d; + + d = b43_plcp_get_ratecode_ofdm(bitrate); B43_WARN_ON(octets & 0xF000); - *data |= (octets << 5); - *data = cpu_to_le32(*data); + d |= (octets << 5); + *data = cpu_to_le32(d); } else { u32 plen; -- cgit v1.2.3-70-g09d2 From de3cb747ffac5f2a4a6bb156e7e2fd5229e688e5 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 25 Sep 2007 19:16:28 -0700 Subject: [NET]: Dynamically allocate the loopback device, part 1. This patch replaces all occurences to the static variable loopback_dev to a pointer loopback_dev. That provides the mindless, trivial, uninteressting change part for the dynamic allocation for the loopback. Signed-off-by: Eric W. Biederman Signed-off-by: Daniel Lezcano Acked-By: Kirill Korotaev Acked-by: Benjamin Thery Signed-off-by: David S. Miller --- drivers/net/loopback.c | 6 ++++-- include/linux/netdevice.h | 2 +- net/core/dst.c | 8 ++++---- net/decnet/dn_dev.c | 4 ++-- net/decnet/dn_route.c | 14 +++++++------- net/ipv4/devinet.c | 6 +++--- net/ipv4/ipconfig.c | 6 +++--- net/ipv4/ipvs/ip_vs_core.c | 2 +- net/ipv4/route.c | 18 +++++++++--------- net/ipv4/xfrm4_policy.c | 2 +- net/ipv6/addrconf.c | 15 +++++++++------ net/ipv6/ip6_input.c | 2 +- net/ipv6/netfilter/ip6t_REJECT.c | 2 +- net/ipv6/route.c | 15 ++++++--------- net/ipv6/xfrm6_policy.c | 2 +- net/xfrm/xfrm_policy.c | 4 ++-- 16 files changed, 55 insertions(+), 53 deletions(-) (limited to 'drivers') diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 0e2252fd71a..588092e1318 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -202,7 +202,7 @@ static const struct ethtool_ops loopback_ethtool_ops = { * The loopback device is special. There is only one instance and * it is statically allocated. Don't do this for other devices. */ -struct net_device loopback_dev = { +struct net_device __loopback_dev = { .name = "lo", .get_stats = &get_stats, .mtu = (16 * 1024) + 20 + 20 + 12, @@ -227,10 +227,12 @@ struct net_device loopback_dev = { .nd_net = &init_net, }; +struct net_device *loopback_dev = &__loopback_dev; + /* Setup and register the loopback device. */ static int __init loopback_init(void) { - int err = register_netdev(&loopback_dev); + int err = register_netdev(loopback_dev); if (err) panic("loopback: Failed to register netdevice: %d\n", err); diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index cf89ce677e4..baa915f0d28 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -741,7 +741,7 @@ struct packet_type { #include #include -extern struct net_device loopback_dev; /* The loopback */ +extern struct net_device *loopback_dev; /* The loopback */ extern rwlock_t dev_base_lock; /* Device list lock */ diff --git a/net/core/dst.c b/net/core/dst.c index 38c741ac5d0..ad5ffa19d80 100644 --- a/net/core/dst.c +++ b/net/core/dst.c @@ -278,13 +278,13 @@ static inline void dst_ifdown(struct dst_entry *dst, struct net_device *dev, if (!unregister) { dst->input = dst->output = dst_discard; } else { - dst->dev = &loopback_dev; - dev_hold(&loopback_dev); + dst->dev = loopback_dev; + dev_hold(dst->dev); dev_put(dev); if (dst->neighbour && dst->neighbour->dev == dev) { - dst->neighbour->dev = &loopback_dev; + dst->neighbour->dev = loopback_dev; dev_put(dev); - dev_hold(&loopback_dev); + dev_hold(dst->neighbour->dev); } } } diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c index fa24614b5a3..bcaf4c5aa68 100644 --- a/net/decnet/dn_dev.c +++ b/net/decnet/dn_dev.c @@ -869,10 +869,10 @@ last_chance: rv = dn_dev_get_first(dev, addr); read_unlock(&dev_base_lock); dev_put(dev); - if (rv == 0 || dev == &loopback_dev) + if (rv == 0 || dev == loopback_dev) return rv; } - dev = &loopback_dev; + dev = loopback_dev; dev_hold(dev); goto last_chance; } diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index 70b1c3fa00f..96fe0aa1638 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -887,7 +887,7 @@ static int dn_route_output_slow(struct dst_entry **pprt, const struct flowi *old .scope = RT_SCOPE_UNIVERSE, } }, .mark = oldflp->mark, - .iif = loopback_dev.ifindex, + .iif = loopback_dev->ifindex, .oif = oldflp->oif }; struct dn_route *rt = NULL; struct net_device *dev_out = NULL, *dev; @@ -904,7 +904,7 @@ static int dn_route_output_slow(struct dst_entry **pprt, const struct flowi *old "dn_route_output_slow: dst=%04x src=%04x mark=%d" " iif=%d oif=%d\n", dn_ntohs(oldflp->fld_dst), dn_ntohs(oldflp->fld_src), - oldflp->mark, loopback_dev.ifindex, oldflp->oif); + oldflp->mark, loopback_dev->ifindex, oldflp->oif); /* If we have an output interface, verify its a DECnet device */ if (oldflp->oif) { @@ -957,7 +957,7 @@ source_ok: err = -EADDRNOTAVAIL; if (dev_out) dev_put(dev_out); - dev_out = &loopback_dev; + dev_out = loopback_dev; dev_hold(dev_out); if (!fl.fld_dst) { fl.fld_dst = @@ -966,7 +966,7 @@ source_ok: if (!fl.fld_dst) goto out; } - fl.oif = loopback_dev.ifindex; + fl.oif = loopback_dev->ifindex; res.type = RTN_LOCAL; goto make_route; } @@ -1012,7 +1012,7 @@ source_ok: if (dev_out) dev_put(dev_out); if (dn_dev_islocal(neigh->dev, fl.fld_dst)) { - dev_out = &loopback_dev; + dev_out = loopback_dev; res.type = RTN_LOCAL; } else { dev_out = neigh->dev; @@ -1033,7 +1033,7 @@ source_ok: /* Possible improvement - check all devices for local addr */ if (dn_dev_islocal(dev_out, fl.fld_dst)) { dev_put(dev_out); - dev_out = &loopback_dev; + dev_out = loopback_dev; dev_hold(dev_out); res.type = RTN_LOCAL; goto select_source; @@ -1069,7 +1069,7 @@ select_source: fl.fld_src = fl.fld_dst; if (dev_out) dev_put(dev_out); - dev_out = &loopback_dev; + dev_out = loopback_dev; dev_hold(dev_out); fl.oif = dev_out->ifindex; if (res.fi) diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 721b89b6096..affea9b121f 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -203,7 +203,7 @@ static void inetdev_destroy(struct in_device *in_dev) ASSERT_RTNL(); dev = in_dev->dev; - if (dev == &loopback_dev) + if (dev == loopback_dev) return; in_dev->dead = 1; @@ -1061,7 +1061,7 @@ static int inetdev_event(struct notifier_block *this, unsigned long event, in_dev = inetdev_init(dev); if (!in_dev) return notifier_from_errno(-ENOMEM); - if (dev == &loopback_dev) { + if (dev == loopback_dev) { IN_DEV_CONF_SET(in_dev, NOXFRM, 1); IN_DEV_CONF_SET(in_dev, NOPOLICY, 1); } @@ -1077,7 +1077,7 @@ static int inetdev_event(struct notifier_block *this, unsigned long event, case NETDEV_UP: if (dev->mtu < 68) break; - if (dev == &loopback_dev) { + if (dev == loopback_dev) { struct in_ifaddr *ifa; if ((ifa = inet_alloc_ifa()) != NULL) { ifa->ifa_local = diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index 4303851749f..2d2e0cda047 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -190,11 +190,11 @@ static int __init ic_open_devs(void) rtnl_lock(); /* bring loopback device up first */ - if (dev_change_flags(&loopback_dev, loopback_dev.flags | IFF_UP) < 0) - printk(KERN_ERR "IP-Config: Failed to open %s\n", loopback_dev.name); + if (dev_change_flags(loopback_dev, loopback_dev->flags | IFF_UP) < 0) + printk(KERN_ERR "IP-Config: Failed to open %s\n", loopback_dev->name); for_each_netdev(&init_net, dev) { - if (dev == &loopback_dev) + if (dev == loopback_dev) continue; if (user_dev_name[0] ? !strcmp(dev->name, user_dev_name) : (!(dev->flags & IFF_LOOPBACK) && diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c index f005a2f929f..74503267e5d 100644 --- a/net/ipv4/ipvs/ip_vs_core.c +++ b/net/ipv4/ipvs/ip_vs_core.c @@ -961,7 +961,7 @@ ip_vs_in(unsigned int hooknum, struct sk_buff **pskb, * ... don't know why 1st test DOES NOT include 2nd (?) */ if (unlikely(skb->pkt_type != PACKET_HOST - || skb->dev == &loopback_dev || skb->sk)) { + || skb->dev == loopback_dev || skb->sk)) { IP_VS_DBG(12, "packet type=%d proto=%d daddr=%d.%d.%d.%d ignored\n", skb->pkt_type, ip_hdr(skb)->protocol, diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 006d6058a80..ca2878dc618 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1402,8 +1402,8 @@ static void ipv4_dst_ifdown(struct dst_entry *dst, struct net_device *dev, { struct rtable *rt = (struct rtable *) dst; struct in_device *idev = rt->idev; - if (dev != &loopback_dev && idev && idev->dev == dev) { - struct in_device *loopback_idev = in_dev_get(&loopback_dev); + if (dev != loopback_dev && idev && idev->dev == dev) { + struct in_device *loopback_idev = in_dev_get(loopback_dev); if (loopback_idev) { rt->idev = loopback_idev; in_dev_put(idev); @@ -1555,7 +1555,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr, #endif rth->rt_iif = rth->fl.iif = dev->ifindex; - rth->u.dst.dev = &loopback_dev; + rth->u.dst.dev = loopback_dev; dev_hold(rth->u.dst.dev); rth->idev = in_dev_get(rth->u.dst.dev); rth->fl.oif = 0; @@ -1812,7 +1812,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr, if (res.type == RTN_LOCAL) { int result; result = fib_validate_source(saddr, daddr, tos, - loopback_dev.ifindex, + loopback_dev->ifindex, dev, &spec_dst, &itag); if (result < 0) goto martian_source; @@ -1879,7 +1879,7 @@ local_input: #endif rth->rt_iif = rth->fl.iif = dev->ifindex; - rth->u.dst.dev = &loopback_dev; + rth->u.dst.dev = loopback_dev; dev_hold(rth->u.dst.dev); rth->idev = in_dev_get(rth->u.dst.dev); rth->rt_gateway = daddr; @@ -2149,7 +2149,7 @@ static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp) RT_SCOPE_UNIVERSE), } }, .mark = oldflp->mark, - .iif = loopback_dev.ifindex, + .iif = loopback_dev->ifindex, .oif = oldflp->oif }; struct fib_result res; unsigned flags = 0; @@ -2243,9 +2243,9 @@ static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp) fl.fl4_dst = fl.fl4_src = htonl(INADDR_LOOPBACK); if (dev_out) dev_put(dev_out); - dev_out = &loopback_dev; + dev_out = loopback_dev; dev_hold(dev_out); - fl.oif = loopback_dev.ifindex; + fl.oif = loopback_dev->ifindex; res.type = RTN_LOCAL; flags |= RTCF_LOCAL; goto make_route; @@ -2290,7 +2290,7 @@ static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp) fl.fl4_src = fl.fl4_dst; if (dev_out) dev_put(dev_out); - dev_out = &loopback_dev; + dev_out = loopback_dev; dev_hold(dev_out); fl.oif = dev_out->ifindex; if (res.fi) diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index 4ff8ed30024..29ab3de8c47 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c @@ -306,7 +306,7 @@ static void xfrm4_dst_ifdown(struct dst_entry *dst, struct net_device *dev, xdst = (struct xfrm_dst *)dst; if (xdst->u.rt.idev->dev == dev) { - struct in_device *loopback_idev = in_dev_get(&loopback_dev); + struct in_device *loopback_idev = in_dev_get(loopback_dev); BUG_ON(!loopback_idev); do { diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 9c2e94f1c63..b43574f7337 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -2410,7 +2410,7 @@ static int addrconf_ifdown(struct net_device *dev, int how) ASSERT_RTNL(); - if (dev == &loopback_dev && how == 1) + if (dev == loopback_dev && how == 1) how = 0; rt6_ifdown(dev); @@ -4212,16 +4212,19 @@ int __init addrconf_init(void) * device and it being up should be removed. */ rtnl_lock(); - if (!ipv6_add_dev(&loopback_dev)) + if (!ipv6_add_dev(loopback_dev)) err = -ENOMEM; rtnl_unlock(); if (err) return err; - ip6_null_entry.rt6i_idev = in6_dev_get(&loopback_dev); + ip6_null_entry.u.dst.dev = loopback_dev; + ip6_null_entry.rt6i_idev = in6_dev_get(loopback_dev); #ifdef CONFIG_IPV6_MULTIPLE_TABLES - ip6_prohibit_entry.rt6i_idev = in6_dev_get(&loopback_dev); - ip6_blk_hole_entry.rt6i_idev = in6_dev_get(&loopback_dev); + ip6_prohibit_entry.u.dst.dev = loopback_dev; + ip6_prohibit_entry.rt6i_idev = in6_dev_get(loopback_dev); + ip6_blk_hole_entry.u.dst.dev = loopback_dev; + ip6_blk_hole_entry.rt6i_idev = in6_dev_get(loopback_dev); #endif register_netdevice_notifier(&ipv6_dev_notf); @@ -4276,7 +4279,7 @@ void __exit addrconf_cleanup(void) continue; addrconf_ifdown(dev, 1); } - addrconf_ifdown(&loopback_dev, 2); + addrconf_ifdown(loopback_dev, 2); /* * Check hash table. diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index 7d18cac3f11..9149fc23975 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c @@ -91,7 +91,7 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt * * BTW, when we send a packet for our own local address on a * non-loopback interface (e.g. ethX), it is being delivered - * via the loopback interface (lo) here; skb->dev = &loopback_dev. + * via the loopback interface (lo) here; skb->dev = loopback_dev. * It, however, should be considered as if it is being * arrived via the sending interface (ethX), because of the * nature of scoping architecture. --yoshfuji diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c index 2f487cda3b6..50860531cd3 100644 --- a/net/ipv6/netfilter/ip6t_REJECT.c +++ b/net/ipv6/netfilter/ip6t_REJECT.c @@ -167,7 +167,7 @@ static inline void send_unreach(struct sk_buff *skb_in, unsigned char code, unsigned int hooknum) { if (hooknum == NF_IP6_LOCAL_OUT && skb_in->dev == NULL) - skb_in->dev = &loopback_dev; + skb_in->dev = loopback_dev; icmpv6_send(skb_in, ICMPV6_DEST_UNREACH, code, 0, NULL); } diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 104070e92ce..a7a21a7ba79 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -138,7 +138,6 @@ struct rt6_info ip6_null_entry = { .dst = { .__refcnt = ATOMIC_INIT(1), .__use = 1, - .dev = &loopback_dev, .obsolete = -1, .error = -ENETUNREACH, .metrics = { [RTAX_HOPLIMIT - 1] = 255, }, @@ -164,7 +163,6 @@ struct rt6_info ip6_prohibit_entry = { .dst = { .__refcnt = ATOMIC_INIT(1), .__use = 1, - .dev = &loopback_dev, .obsolete = -1, .error = -EACCES, .metrics = { [RTAX_HOPLIMIT - 1] = 255, }, @@ -184,7 +182,6 @@ struct rt6_info ip6_blk_hole_entry = { .dst = { .__refcnt = ATOMIC_INIT(1), .__use = 1, - .dev = &loopback_dev, .obsolete = -1, .error = -EINVAL, .metrics = { [RTAX_HOPLIMIT - 1] = 255, }, @@ -224,8 +221,8 @@ static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, struct rt6_info *rt = (struct rt6_info *)dst; struct inet6_dev *idev = rt->rt6i_idev; - if (dev != &loopback_dev && idev != NULL && idev->dev == dev) { - struct inet6_dev *loopback_idev = in6_dev_get(&loopback_dev); + if (dev != loopback_dev && idev != NULL && idev->dev == dev) { + struct inet6_dev *loopback_idev = in6_dev_get(loopback_dev); if (loopback_idev != NULL) { rt->rt6i_idev = loopback_idev; in6_dev_put(idev); @@ -1188,12 +1185,12 @@ int ip6_route_add(struct fib6_config *cfg) if ((cfg->fc_flags & RTF_REJECT) || (dev && (dev->flags&IFF_LOOPBACK) && !(addr_type&IPV6_ADDR_LOOPBACK))) { /* hold loopback dev/idev if we haven't done so. */ - if (dev != &loopback_dev) { + if (dev != loopback_dev) { if (dev) { dev_put(dev); in6_dev_put(idev); } - dev = &loopback_dev; + dev = loopback_dev; dev_hold(dev); idev = in6_dev_get(dev); if (!idev) { @@ -1897,13 +1894,13 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, if (rt == NULL) return ERR_PTR(-ENOMEM); - dev_hold(&loopback_dev); + dev_hold(loopback_dev); in6_dev_hold(idev); rt->u.dst.flags = DST_HOST; rt->u.dst.input = ip6_input; rt->u.dst.output = ip6_output; - rt->rt6i_dev = &loopback_dev; + rt->rt6i_dev = loopback_dev; rt->rt6i_idev = idev; rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(rt->rt6i_dev); rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_mtu(&rt->u.dst)); diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index 3ec0c4770ee..cc07216cfd5 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c @@ -375,7 +375,7 @@ static void xfrm6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, xdst = (struct xfrm_dst *)dst; if (xdst->u.rt6.rt6i_idev->dev == dev) { - struct inet6_dev *loopback_idev = in6_dev_get(&loopback_dev); + struct inet6_dev *loopback_idev = in6_dev_get(loopback_dev); BUG_ON(!loopback_idev); do { diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 50682d3cd7a..d6dfd7d1948 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -1949,8 +1949,8 @@ static int stale_bundle(struct dst_entry *dst) void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev) { while ((dst = dst->child) && dst->xfrm && dst->dev == dev) { - dst->dev = &loopback_dev; - dev_hold(&loopback_dev); + dst->dev = loopback_dev; + dev_hold(dst->dev); dev_put(dev); } } -- cgit v1.2.3-70-g09d2 From 854d8363f37491c955b0edc60d37b62f3d71bb67 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 25 Sep 2007 19:18:04 -0700 Subject: [NET]: Dynamically allocate the loopback device, part 2. Doing this makes loopback.c a better example of how to do a simple network device, and it removes the special case single static allocation of a struct net_device, hopefully making maintenance easier. Signed-off-by: Eric W. Biederman Signed-off-by: Daniel Lezcano Acked-By: Kirill Korotaev Acked-by: Benjamin Thery --- drivers/net/loopback.c | 72 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 44 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 588092e1318..4b6f7b2abea 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -202,44 +202,60 @@ static const struct ethtool_ops loopback_ethtool_ops = { * The loopback device is special. There is only one instance and * it is statically allocated. Don't do this for other devices. */ -struct net_device __loopback_dev = { - .name = "lo", - .get_stats = &get_stats, - .mtu = (16 * 1024) + 20 + 20 + 12, - .hard_start_xmit = loopback_xmit, - .hard_header = eth_header, - .hard_header_cache = eth_header_cache, - .header_cache_update = eth_header_cache_update, - .hard_header_len = ETH_HLEN, /* 14 */ - .addr_len = ETH_ALEN, /* 6 */ - .tx_queue_len = 0, - .type = ARPHRD_LOOPBACK, /* 0x0001*/ - .rebuild_header = eth_rebuild_header, - .flags = IFF_LOOPBACK, - .features = NETIF_F_SG | NETIF_F_FRAGLIST +static void loopback_setup(struct net_device *dev) +{ + dev->get_stats = &get_stats; + dev->mtu = (16 * 1024) + 20 + 20 + 12; + dev->hard_start_xmit = loopback_xmit; + dev->hard_header = eth_header; + dev->hard_header_cache = eth_header_cache; + dev->header_cache_update = eth_header_cache_update; + dev->hard_header_len = ETH_HLEN; /* 14 */ + dev->addr_len = ETH_ALEN; /* 6 */ + dev->tx_queue_len = 0; + dev->type = ARPHRD_LOOPBACK; /* 0x0001*/ + dev->rebuild_header = eth_rebuild_header; + dev->flags = IFF_LOOPBACK; + dev->features = NETIF_F_SG | NETIF_F_FRAGLIST #ifdef LOOPBACK_TSO - | NETIF_F_TSO + | NETIF_F_TSO #endif - | NETIF_F_NO_CSUM | NETIF_F_HIGHDMA - | NETIF_F_LLTX - | NETIF_F_NETNS_LOCAL, - .ethtool_ops = &loopback_ethtool_ops, - .nd_net = &init_net, -}; - -struct net_device *loopback_dev = &__loopback_dev; + | NETIF_F_NO_CSUM + | NETIF_F_HIGHDMA + | NETIF_F_LLTX + | NETIF_F_NETNS_LOCAL, + dev->ethtool_ops = &loopback_ethtool_ops; +} /* Setup and register the loopback device. */ static int __init loopback_init(void) { - int err = register_netdev(loopback_dev); + struct net_device *dev; + int err; + + err = -ENOMEM; + dev = alloc_netdev(0, "lo", loopback_setup); + if (!dev) + goto out; + err = register_netdev(dev); if (err) - panic("loopback: Failed to register netdevice: %d\n", err); + goto out_free_netdev; + err = 0; + loopback_dev = dev; + +out: + if (err) + panic("loopback: Failed to register netdevice: %d\n", err); return err; -}; -module_init(loopback_init); +out_free_netdev: + free_netdev(dev); + goto out; +} + +fs_initcall(loopback_init); +struct net_device *loopback_dev; EXPORT_SYMBOL(loopback_dev); -- cgit v1.2.3-70-g09d2 From 1156b2c689bf509cdc254394598d410787a02aec Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Tue, 25 Sep 2007 19:34:09 -0700 Subject: [IWLWIFI]: remove per-file CFLAGS for IWL define Signed-off-by: Zhu Yi Signed-off-by: David S. Miller --- drivers/net/wireless/iwlwifi/Makefile | 6 ------ drivers/net/wireless/iwlwifi/iwl-3945-rs.c | 2 ++ drivers/net/wireless/iwlwifi/iwl-3945.c | 2 ++ drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 2 ++ drivers/net/wireless/iwlwifi/iwl-4965.c | 2 ++ drivers/net/wireless/iwlwifi/iwl3945-base.c | 2 ++ drivers/net/wireless/iwlwifi/iwl4965-base.c | 2 ++ 7 files changed, 12 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 03837ff5431..3bbd38358d5 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -1,11 +1,5 @@ obj-$(CONFIG_IWL3945) += iwl3945.o iwl3945-objs = iwl3945-base.o iwl-3945.o iwl-3945-rs.o -CFLAGS_iwl3945-base.o = -DIWL=3945 -CFLAGS_iwl-3945.o = -DIWL=3945 -CFLAGS_iwl-3945-rs.o = -DIWL=3945 obj-$(CONFIG_IWL4965) += iwl4965.o iwl4965-objs = iwl4965-base.o iwl-4965.o iwl-4965-rs.o -CFLAGS_iwl4965-base.o = -DIWL=4965 -CFLAGS_iwl-4965.o = -DIWL=4965 -CFLAGS_iwl-4965-rs.o = -DIWL=4965 diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index b0d28ae0b32..f4aabcf480e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -40,6 +40,8 @@ #include #include +#define IWL 3945 + #include "../net/mac80211/ieee80211_rate.h" #include "iwlwifi.h" diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 55f7d89aad8..acb38750535 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -40,6 +40,8 @@ #include #include +#define IWL 3945 + #include "iwlwifi.h" #include "iwl-helpers.h" #include "iwl-3945.h" diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index 7b74481f528..bc5e67b0b0e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -39,6 +39,8 @@ #include #include +#define IWL 4965 + #include "../net/mac80211/ieee80211_rate.h" #include "iwlwifi.h" diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index e624f2a41e0..b704fe7fca2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -39,6 +39,8 @@ #include #include +#define IWL 4965 + #include "iwlwifi.h" #include "iwl-4965.h" #include "iwl-helpers.h" diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index cc405f4a864..44f983b6d39 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -58,6 +58,8 @@ #include +#define IWL 3945 + #include "iwlwifi.h" #include "iwl-3945.h" #include "iwl-helpers.h" diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 6cea3118b7c..61500a20929 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -58,6 +58,8 @@ #include +#define IWL 4965 + #include "iwlwifi.h" #include "iwl-4965.h" #include "iwl-helpers.h" -- cgit v1.2.3-70-g09d2 From fa46081c506ab518e8ea4095bc21b6d544006c00 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Fri, 31 Aug 2007 00:30:31 +0200 Subject: [ZD1211RW]: Don't needlessly initialize variable to NULL in zd_chip No need to initialize to NULL when variable is never used before it's assigned the return value of a kmalloc() call. Signed-off-by: Jesper Juhl Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/zd1211rw/zd_chip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c index 750c0f99e86..3d60c69b20e 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.c +++ b/drivers/net/wireless/zd1211rw/zd_chip.c @@ -106,7 +106,7 @@ int zd_ioread32v_locked(struct zd_chip *chip, u32 *values, const zd_addr_t *addr { int r; int i; - zd_addr_t *a16 = (zd_addr_t *)NULL; + zd_addr_t *a16; u16 *v16; unsigned int count16; -- cgit v1.2.3-70-g09d2 From 01449c5a469c8c1c647cfd3705b1ff290be6afff Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Sun, 16 Sep 2007 17:26:49 -0500 Subject: [BCM43XX]: Change radio hardware switch status printk from debug to regular Some distros ship bcm43xx with debugging printout disabled. For those BCM43xx devices with radio on/off switches, this makes it impossible to know if the radio is on or off. This patch changes a pair of debug printk's into ordinary printk's. It also changes the message that prints when the radio is initialized to the off state as the old message seems to confuse users. Signed-off-by: Larry Finger Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 4 ++-- drivers/net/wireless/bcm43xx/bcm43xx_radio.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index e038d072398..45683437a98 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -2380,7 +2380,7 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm) goto err_gpio_cleanup; bcm43xx_radio_turn_on(bcm); bcm->radio_hw_enable = bcm43xx_is_hw_radio_enabled(bcm); - dprintk(KERN_INFO PFX "Radio %s by hardware\n", + printk(KERN_INFO PFX "Radio %s by hardware\n", (bcm->radio_hw_enable == 0) ? "disabled" : "enabled"); bcm43xx_write16(bcm, 0x03E6, 0x0000); @@ -3129,7 +3129,7 @@ static void bcm43xx_periodic_every1sec(struct bcm43xx_private *bcm) radio_hw_enable = bcm43xx_is_hw_radio_enabled(bcm); if (unlikely(bcm->radio_hw_enable != radio_hw_enable)) { bcm->radio_hw_enable = radio_hw_enable; - dprintk(KERN_INFO PFX "Radio hardware status changed to %s\n", + printk(KERN_INFO PFX "Radio hardware status changed to %s\n", (radio_hw_enable == 0) ? "disabled" : "enabled"); bcm43xx_leds_update(bcm, 0); } diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c index 6a109f4a1b7..c605099c9ba 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c @@ -2146,7 +2146,7 @@ void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm) } else bcm43xx_phy_write(bcm, 0x0015, 0xAA00); radio->enabled = 0; - dprintk(KERN_INFO PFX "Radio turned off\n"); + dprintk(KERN_INFO PFX "Radio initialized\n"); bcm43xx_leds_update(bcm, 0); } -- cgit v1.2.3-70-g09d2 From ababda03e1a4c41d75cd86c186025532bf91d057 Mon Sep 17 00:00:00 2001 From: Ulrich Kunitz Date: Sat, 1 Sep 2007 22:40:32 +0100 Subject: [ZD1211RD]: add USB id for Telegent TG54USB WLAN adapter Reinhard Speyerer reported at 2007-08-10 a new device. Here are the information strings. Product: Telegent TG54USB WLAN Adapter USB ID: 129b:1666 Chip ID: zd1211 chip 129b:1666 v4330 high 00-01-36 RF2959_RF pa0 ----- FCC ID: N89-UW620Z Signed-off-by: Ulrich Kunitz Signed-off-by: Daniel Drake Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/zd1211rw/zd_usb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index e49628b7d4c..895ff844187 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -55,6 +55,7 @@ static struct usb_device_id usb_ids[] = { { USB_DEVICE(0x14ea, 0xab13), .driver_info = DEVICE_ZD1211 }, { USB_DEVICE(0x13b1, 0x001e), .driver_info = DEVICE_ZD1211 }, { USB_DEVICE(0x0586, 0x3407), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x129b, 0x1666), .driver_info = DEVICE_ZD1211 }, /* ZD1211B */ { USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B }, -- cgit v1.2.3-70-g09d2 From 90f4dd0f4ba910b86f387874ed990ca69c0951a5 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Sun, 16 Sep 2007 15:08:37 -0700 Subject: [P54PCI]: terminate pci table Signed-off-by: Andrew Morton Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/p54pci.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/p54pci.c b/drivers/net/wireless/p54pci.c index e9ecc663dc7..75927583f76 100644 --- a/drivers/net/wireless/p54pci.c +++ b/drivers/net/wireless/p54pci.c @@ -37,6 +37,7 @@ static struct pci_device_id p54p_table[] __devinitdata = { { PCI_DEVICE(0x1260, 0x3877) }, /* Intersil PRISM Javelin/Xbow Wireless LAN adapter */ { PCI_DEVICE(0x1260, 0x3886) }, + { }, }; MODULE_DEVICE_TABLE(pci, p54p_table); -- cgit v1.2.3-70-g09d2 From b85b3b7af52d1c1bd45bfcd47aa425a15fda45f7 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Wed, 19 Sep 2007 18:51:38 +0200 Subject: [B43]: Don't lock irq_lock in debugfs txpower adjust It's not required and the txpower adjustment must not be in atomic. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/b43/debugfs.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/debugfs.c b/drivers/net/wireless/b43/debugfs.c index 3aafde9f08a..734e70e1a06 100644 --- a/drivers/net/wireless/b43/debugfs.c +++ b/drivers/net/wireless/b43/debugfs.c @@ -223,15 +223,10 @@ out: static int txpower_g_write_file(struct b43_wldev *dev, const char *buf, size_t count) { - unsigned long flags; unsigned long phy_flags; - int err = 0; - spin_lock_irqsave(&dev->wl->irq_lock, flags); - if (dev->phy.type != B43_PHYTYPE_G) { - err = -ENODEV; - goto out_unlock; - } + if (dev->phy.type != B43_PHYTYPE_G) + return -ENODEV; if ((count >= 4) && (memcmp(buf, "auto", 4) == 0)) { /* Automatic control */ dev->phy.manual_txpower_control = 0; @@ -240,10 +235,8 @@ static int txpower_g_write_file(struct b43_wldev *dev, int bbatt = 0, rfatt = 0, txmix = 0, pa2db = 0, pa3db = 0; /* Manual control */ if (sscanf(buf, "%d %d %d %d %d", &bbatt, &rfatt, - &txmix, &pa2db, &pa3db) != 5) { - err = -EINVAL; - goto out_unlock; - } + &txmix, &pa2db, &pa3db) != 5) + return -EINVAL; b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt); dev->phy.manual_txpower_control = 1; dev->phy.bbatt.att = bbatt; @@ -262,10 +255,8 @@ static int txpower_g_write_file(struct b43_wldev *dev, b43_radio_unlock(dev); b43_phy_unlock(dev, phy_flags); } -out_unlock: - spin_unlock_irqrestore(&dev->wl->irq_lock, flags); - return err; + return 0; } /* wl->irq_lock is locked */ -- cgit v1.2.3-70-g09d2 From 4b402c65a3a17257af45875159395278e4a2f0cd Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Wed, 19 Sep 2007 18:53:44 +0200 Subject: [SSB]: Use ioreadX() and iowriteX() for PCI. On a PCI bus use ioreadX() and iowriteX(). We map the I/O space with pci_iomap(), so we must use the correct accessor functions, too. readX() and writeX() are not guaranteed to accept the cookie returned from pci_iomap() (though, it currently works on most architectures). Signed-off-by: Michael Buesch Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/ssb/pci.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c index 3d23ca4befe..e19b9f90195 100644 --- a/drivers/ssb/pci.c +++ b/drivers/ssb/pci.c @@ -531,7 +531,7 @@ static u16 ssb_pci_read16(struct ssb_device *dev, u16 offset) if (unlikely(ssb_pci_switch_core(bus, dev))) return 0xFFFF; } - return readw(bus->mmio + offset); + return ioread16(bus->mmio + offset); } static u32 ssb_pci_read32(struct ssb_device *dev, u16 offset) @@ -544,7 +544,7 @@ static u32 ssb_pci_read32(struct ssb_device *dev, u16 offset) if (unlikely(ssb_pci_switch_core(bus, dev))) return 0xFFFFFFFF; } - return readl(bus->mmio + offset); + return ioread32(bus->mmio + offset); } static void ssb_pci_write16(struct ssb_device *dev, u16 offset, u16 value) @@ -557,7 +557,7 @@ static void ssb_pci_write16(struct ssb_device *dev, u16 offset, u16 value) if (unlikely(ssb_pci_switch_core(bus, dev))) return; } - writew(value, bus->mmio + offset); + iowrite16(value, bus->mmio + offset); } static void ssb_pci_write32(struct ssb_device *dev, u16 offset, u32 value) @@ -570,7 +570,7 @@ static void ssb_pci_write32(struct ssb_device *dev, u16 offset, u32 value) if (unlikely(ssb_pci_switch_core(bus, dev))) return; } - writel(value, bus->mmio + offset); + iowrite32(value, bus->mmio + offset); } /* Not "static", as it's used in main.c */ -- cgit v1.2.3-70-g09d2 From 6b9bafec6608539d07f7ccdeefe121dabe06604f Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Wed, 19 Sep 2007 18:55:12 +0200 Subject: [SSB]: Sparse fixes. This fixes all Sparse warnings in SSB. No semantics change. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/ssb/b43_pci_bridge.c | 2 ++ drivers/ssb/driver_chipcommon.c | 7 +++---- drivers/ssb/pci.c | 10 +++++----- 3 files changed, 10 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/ssb/b43_pci_bridge.c b/drivers/ssb/b43_pci_bridge.c index fa3bd292f5f..f145d8a4cfd 100644 --- a/drivers/ssb/b43_pci_bridge.c +++ b/drivers/ssb/b43_pci_bridge.c @@ -13,6 +13,8 @@ #include #include +#include "ssb_private.h" + static const struct pci_device_id b43_pci_bridge_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4301) }, diff --git a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c index a890544e8fb..6fbf1c53b6f 100644 --- a/drivers/ssb/driver_chipcommon.c +++ b/drivers/ssb/driver_chipcommon.c @@ -345,8 +345,7 @@ void ssb_chipco_timing_init(struct ssb_chipcommon *cc, } /* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */ -void -ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc, u32 ticks) +void ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc, u32 ticks) { /* instant NMI */ chipco_write32(cc, SSB_CHIPCO_WATCHDOG, ticks); @@ -359,12 +358,12 @@ u32 ssb_chipco_gpio_in(struct ssb_chipcommon *cc, u32 mask) void ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value) { - return chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUT, mask, value); + chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUT, mask, value); } void ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value) { - return chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUTEN, mask, value); + chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUTEN, mask, value); } #ifdef CONFIG_SSB_SERIAL diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c index e19b9f90195..0ab095c6581 100644 --- a/drivers/ssb/pci.c +++ b/drivers/ssb/pci.c @@ -306,15 +306,15 @@ static void sprom_extract_r1(struct ssb_sprom_r1 *out, const u16 *in) SPEX(pci_pid, SSB_SPROM1_PID, 0xFFFF, 0); for (i = 0; i < 3; i++) { v = in[SPOFF(SSB_SPROM1_IL0MAC) + i]; - *(((u16 *)out->il0mac) + i) = cpu_to_be16(v); + *(((__be16 *)out->il0mac) + i) = cpu_to_be16(v); } for (i = 0; i < 3; i++) { v = in[SPOFF(SSB_SPROM1_ET0MAC) + i]; - *(((u16 *)out->et0mac) + i) = cpu_to_be16(v); + *(((__be16 *)out->et0mac) + i) = cpu_to_be16(v); } for (i = 0; i < 3; i++) { v = in[SPOFF(SSB_SPROM1_ET1MAC) + i]; - *(((u16 *)out->et1mac) + i) = cpu_to_be16(v); + *(((__be16 *)out->et1mac) + i) = cpu_to_be16(v); } SPEX(et0phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0A, 0); SPEX(et1phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1A, @@ -352,7 +352,7 @@ static void sprom_extract_r1(struct ssb_sprom_r1 *out, const u16 *in) SSB_SPROM1_AGAIN_BG_SHIFT); for (i = 0; i < 4; i++) { v = in[SPOFF(SSB_SPROM1_OEM) + i]; - *(((u16 *)out->oem) + i) = cpu_to_le16(v); + *(((__le16 *)out->oem) + i) = cpu_to_le16(v); } } @@ -374,7 +374,7 @@ static void sprom_extract_r2(struct ssb_sprom_r2 *out, const u16 *in) SPEX(ofdm_pwr_off, SSB_SPROM2_OPO, SSB_SPROM2_OPO_VALUE, 0); for (i = 0; i < 4; i++) { v = in[SPOFF(SSB_SPROM2_CCODE) + i]; - *(((u16 *)out->country_str) + i) = cpu_to_le16(v); + *(((__le16 *)out->country_str) + i) = cpu_to_le16(v); } } -- cgit v1.2.3-70-g09d2 From 05155c83d13b983ac2c5691575fd471543df31fe Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Wed, 19 Sep 2007 19:10:08 +0200 Subject: [B43]: Change loglevel of radio-enable message. Also cleanup the code a bit and remove the inline. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/b43/leds.c | 15 +++++++-------- drivers/net/wireless/b43/main.c | 23 +++++++++++++++++++---- drivers/net/wireless/b43/main.h | 17 ----------------- 3 files changed, 26 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/leds.c b/drivers/net/wireless/b43/leds.c index 85d965de579..0f155b4f34e 100644 --- a/drivers/net/wireless/b43/leds.c +++ b/drivers/net/wireless/b43/leds.c @@ -176,6 +176,7 @@ void b43_leds_update(struct b43_wldev *dev, int activity) unsigned long interval = 0; u16 ledctl; unsigned long flags; + bool radio_enabled = (phy->radio_on && dev->radio_hw_enable); spin_lock_irqsave(&dev->wl->leds_lock, flags); ledctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL); @@ -195,21 +196,19 @@ void b43_leds_update(struct b43_wldev *dev, int activity) turn_on = activity; break; case B43_LED_RADIO_ALL: - turn_on = phy->radio_on && b43_is_hw_radio_enabled(dev); + turn_on = radio_enabled; break; case B43_LED_RADIO_A: - turn_on = (phy->radio_on && b43_is_hw_radio_enabled(dev) - && phy->type == B43_PHYTYPE_A); + turn_on = (radio_enabled && phy->type == B43_PHYTYPE_A); break; case B43_LED_RADIO_B: - turn_on = (phy->radio_on && b43_is_hw_radio_enabled(dev) - && (phy->type == B43_PHYTYPE_B - || phy->type == B43_PHYTYPE_G)); + turn_on = (radio_enabled && + (phy->type == B43_PHYTYPE_B + || phy->type == B43_PHYTYPE_G)); break; case B43_LED_MODE_BG: if (phy->type == B43_PHYTYPE_G - && b43_is_hw_radio_enabled(dev) - && 1 /*FIXME: using G rates. */ ) + && radio_enabled) turn_on = 1; break; case B43_LED_TRANSFER: diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 66c89df51fb..1390f41425f 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -2175,6 +2175,21 @@ static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna) b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRPHYCTL, tmp); } +/* Returns TRUE, if the radio is enabled in hardware. */ +static bool b43_is_hw_radio_enabled(struct b43_wldev *dev) +{ + if (dev->phy.rev >= 3) { + if (!(b43_read32(dev, B43_MMIO_RADIO_HWENABLED_HI) + & B43_MMIO_RADIO_HWENABLED_HI_MASK)) + return 1; + } else { + if (b43_read16(dev, B43_MMIO_RADIO_HWENABLED_LO) + & B43_MMIO_RADIO_HWENABLED_LO_MASK) + return 1; + } + return 0; +} + /* This is the opposite of b43_chip_init() */ static void b43_chip_exit(struct b43_wldev *dev) { @@ -2214,7 +2229,7 @@ static int b43_chip_init(struct b43_wldev *dev) b43_radio_turn_on(dev); dev->radio_hw_enable = b43_is_hw_radio_enabled(dev); b43dbg(dev->wl, "Radio %s by hardware\n", - (dev->radio_hw_enable == 0) ? "disabled" : "enabled"); + dev->radio_hw_enable ? "enabled" : "disabled"); b43_write16(dev, 0x03E6, 0x0000); err = b43_phy_init(dev); @@ -2373,14 +2388,14 @@ static void b43_periodic_every15sec(struct b43_wldev *dev) static void b43_periodic_every1sec(struct b43_wldev *dev) { - int radio_hw_enable; + bool radio_hw_enable; /* check if radio hardware enabled status changed */ radio_hw_enable = b43_is_hw_radio_enabled(dev); if (unlikely(dev->radio_hw_enable != radio_hw_enable)) { dev->radio_hw_enable = radio_hw_enable; - b43dbg(dev->wl, "Radio hardware status changed to %s\n", - (radio_hw_enable == 0) ? "disabled" : "enabled"); + b43info(dev->wl, "Radio hardware status changed to %s\n", + radio_hw_enable ? "ENABLED" : "DISABLED"); b43_leds_update(dev, 0); } } diff --git a/drivers/net/wireless/b43/main.h b/drivers/net/wireless/b43/main.h index bd8fcf72dc5..284d17da17d 100644 --- a/drivers/net/wireless/b43/main.h +++ b/drivers/net/wireless/b43/main.h @@ -96,23 +96,6 @@ static inline int b43_is_ofdm_rate(int rate) return !b43_is_cck_rate(rate); } -static inline int b43_is_hw_radio_enabled(struct b43_wldev *dev) -{ - /* function to return state of hardware enable of radio - * returns 0 if radio disabled, 1 if radio enabled - */ - struct b43_phy *phy = &dev->phy; - - if (phy->rev >= 3) - return ((b43_read32(dev, B43_MMIO_RADIO_HWENABLED_HI) - & B43_MMIO_RADIO_HWENABLED_HI_MASK) - == 0) ? 1 : 0; - else - return ((b43_read16(dev, B43_MMIO_RADIO_HWENABLED_LO) - & B43_MMIO_RADIO_HWENABLED_LO_MASK) - == 0) ? 0 : 1; -} - void b43_tsf_read(struct b43_wldev *dev, u64 * tsf); void b43_tsf_write(struct b43_wldev *dev, u64 tsf); -- cgit v1.2.3-70-g09d2 From 6a724d68a38c33ba4c7f7b5f008301ac12c9ced1 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Thu, 20 Sep 2007 22:12:58 +0200 Subject: [B43]: Remove the "radio hw enabled" message on startup. This message is useless. Only report state changes. Cc: Larry Finger Signed-off-by: Michael Buesch Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/b43/main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 1390f41425f..cc5285407e8 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -2227,9 +2227,6 @@ static int b43_chip_init(struct b43_wldev *dev) if (err) goto err_gpio_cleanup; b43_radio_turn_on(dev); - dev->radio_hw_enable = b43_is_hw_radio_enabled(dev); - b43dbg(dev->wl, "Radio %s by hardware\n", - dev->radio_hw_enable ? "enabled" : "disabled"); b43_write16(dev, 0x03E6, 0x0000); err = b43_phy_init(dev); @@ -3252,6 +3249,9 @@ static void setup_struct_wldev_for_init(struct b43_wldev *dev) { /* Flags */ dev->reg124_set_0x4 = 0; + /* Assume the radio is enabled. If it's not enabled, the state will + * immediately get fixed on the first periodic work run. */ + dev->radio_hw_enable = 1; /* Stats */ memset(&dev->stats, 0, sizeof(dev->stats)); -- cgit v1.2.3-70-g09d2 From fda9abcf1a5b6b78a4ead25729583541af9876b5 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Thu, 20 Sep 2007 22:14:18 +0200 Subject: [B43]: Support for turning the radio off from software. This adds support for turning the radio off in software. That's useful in environments, where you don't want the RF to radiate any signals, but don't want to bring the interface down. Cc: Larry Finger Signed-off-by: Michael Buesch Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/b43/b43.h | 11 +++++++++- drivers/net/wireless/b43/main.c | 17 +++++++++++++++ drivers/net/wireless/b43/phy.c | 48 ++++++++++++++++++++++++++++++----------- 3 files changed, 63 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 270a2112de2..a22435ade8c 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -459,7 +459,6 @@ struct b43_phy { u16 radio_ver; /* Radio version */ u8 radio_rev; /* Radio revision */ - bool radio_on; /* Radio switched on/off */ bool locked; /* Only used in b43_phy_{un}lock() */ bool dyn_tssi_tbl; /* tssi2dbm is kmalloc()ed. */ @@ -468,6 +467,16 @@ struct b43_phy { bool aci_wlan_automatic; bool aci_hw_rssi; + /* Radio switched on/off */ + bool radio_on; + struct { + /* Values saved when turning the radio off. + * They are needed when turning it on again. */ + bool valid; + u16 rfover; + u16 rfoverval; + } radio_off_context; + u16 minlowsig[2]; u16 minlowsigpos[2]; diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index cc5285407e8..b44c9f92884 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -2874,6 +2874,21 @@ static int b43_dev_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) b43_set_beacon_int(dev, conf->beacon_int); + if (!!conf->radio_enabled != phy->radio_on) { + if (conf->radio_enabled) { + b43_radio_turn_on(dev); + b43info(dev->wl, "Radio turned on by software\n"); + if (!dev->radio_hw_enable) { + b43info(dev->wl, "The hardware RF-kill button " + "still turns the radio physically off. " + "Press the button to turn it on.\n"); + } + } else { + b43_radio_turn_off(dev); + b43info(dev->wl, "Radio turned off by software\n"); + } + } + spin_lock_irqsave(&wl->irq_lock, flags); b43_interrupt_enable(dev, savedirqs); mmiowb(); @@ -3218,6 +3233,8 @@ static void setup_struct_phy_for_init(struct b43_wldev *dev, phy->aci_wlan_automatic = 0; phy->aci_hw_rssi = 0; + phy->radio_off_context.valid = 0; + lo = phy->lo_control; if (lo) { memset(lo, 0, sizeof(*(phy->lo_control))); diff --git a/drivers/net/wireless/b43/phy.c b/drivers/net/wireless/b43/phy.c index 3282893021b..354d1823875 100644 --- a/drivers/net/wireless/b43/phy.c +++ b/drivers/net/wireless/b43/phy.c @@ -1205,10 +1205,7 @@ static void b43_phy_initb2(struct b43_wldev *dev) val -= 0x0202; } b43_phy_write(dev, 0x03E4, 0x3000); - if (phy->channel == 0xFF) - b43_radio_selectchannel(dev, B43_DEFAULT_CHANNEL_BG, 0); - else - b43_radio_selectchannel(dev, phy->channel, 0); + b43_radio_selectchannel(dev, phy->channel, 0); if (phy->radio_ver != 0x2050) { b43_radio_write16(dev, 0x0075, 0x0080); b43_radio_write16(dev, 0x0079, 0x0081); @@ -1256,10 +1253,7 @@ static void b43_phy_initb4(struct b43_wldev *dev) val -= 0x0202; } b43_phy_write(dev, 0x03E4, 0x3000); - if (phy->channel == 0xFF) - b43_radio_selectchannel(dev, B43_DEFAULT_CHANNEL_BG, 0); - else - b43_radio_selectchannel(dev, phy->channel, 0); + b43_radio_selectchannel(dev, phy->channel, 0); if (phy->radio_ver != 0x2050) { b43_radio_write16(dev, 0x0075, 0x0080); b43_radio_write16(dev, 0x0079, 0x0081); @@ -4110,6 +4104,20 @@ int b43_radio_selectchannel(struct b43_wldev *dev, u16 freq; u16 channelcookie; + if (channel == 0xFF) { + switch (phy->type) { + case B43_PHYTYPE_A: + channel = B43_DEFAULT_CHANNEL_A; + break; + case B43_PHYTYPE_B: + case B43_PHYTYPE_G: + channel = B43_DEFAULT_CHANNEL_BG; + break; + default: + B43_WARN_ON(1); + } + } + /* First we set the channel radio code to prevent the * firmware from sending ghost packets. */ @@ -4302,6 +4310,7 @@ void b43_radio_turn_on(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; int err; + u8 channel; might_sleep(); @@ -4321,14 +4330,23 @@ void b43_radio_turn_on(struct b43_wldev *dev) b43_phy_write(dev, 0x0015, 0x8000); b43_phy_write(dev, 0x0015, 0xCC00); b43_phy_write(dev, 0x0015, (phy->gmode ? 0x00C0 : 0x0000)); + if (phy->radio_off_context.valid) { + /* Restore the RFover values. */ + b43_phy_write(dev, B43_PHY_RFOVER, + phy->radio_off_context.rfover); + b43_phy_write(dev, B43_PHY_RFOVERVAL, + phy->radio_off_context.rfoverval); + phy->radio_off_context.valid = 0; + } + channel = phy->channel; err = b43_radio_selectchannel(dev, B43_DEFAULT_CHANNEL_BG, 1); + err |= b43_radio_selectchannel(dev, channel, 0); B43_WARN_ON(err); break; default: B43_WARN_ON(1); } phy->radio_on = 1; - b43dbg(dev->wl, "Radio turned on\n"); } void b43_radio_turn_off(struct b43_wldev *dev) @@ -4342,10 +4360,16 @@ void b43_radio_turn_off(struct b43_wldev *dev) b43_phy_write(dev, 0x0011, b43_phy_read(dev, 0x0011) | 0x0008); } if (phy->type == B43_PHYTYPE_G && dev->dev->id.revision >= 5) { - b43_phy_write(dev, 0x0811, b43_phy_read(dev, 0x0811) | 0x008C); - b43_phy_write(dev, 0x0812, b43_phy_read(dev, 0x0812) & 0xFF73); + u16 rfover, rfoverval; + + rfover = b43_phy_read(dev, B43_PHY_RFOVER); + rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL); + phy->radio_off_context.rfover = rfover; + phy->radio_off_context.rfoverval = rfoverval; + phy->radio_off_context.valid = 1; + b43_phy_write(dev, B43_PHY_RFOVER, rfover | 0x008C); + b43_phy_write(dev, B43_PHY_RFOVERVAL, rfoverval & 0xFF73); } else b43_phy_write(dev, 0x0015, 0xAA00); phy->radio_on = 0; - b43dbg(dev->wl, "Radio turned off\n"); } -- cgit v1.2.3-70-g09d2 From 42a9174f541d2338d35b91869415d9ae9312ca0d Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 20 Sep 2007 21:11:02 -0500 Subject: [B43LEGACY]: Support for turning the radio off from software. This adds support for turning the radio off in software. That's useful in environments, where you don't want the RF to radiate any signals, but don't want to bring the interface down. This patch is based on a similar patch of b43 by Michael Buesch. Signed-off-by: Larry Finger Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/b43legacy/b43legacy.h | 11 ++++++++- drivers/net/wireless/b43legacy/main.c | 16 ++++++++++++ drivers/net/wireless/b43legacy/phy.c | 14 ++--------- drivers/net/wireless/b43legacy/radio.c | 39 +++++++++++++++++++++++++----- 4 files changed, 61 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h index 34a6277051a..746de2ff498 100644 --- a/drivers/net/wireless/b43legacy/b43legacy.h +++ b/drivers/net/wireless/b43legacy/b43legacy.h @@ -411,7 +411,6 @@ struct b43legacy_phy { u8 calibrated:1; u8 radio_rev; /* Radio revision */ - bool radio_on; /* Radio switched on/off */ bool locked; /* Only used in b43legacy_phy_{un}lock() */ bool dyn_tssi_tbl; /* tssi2dbm is kmalloc()ed. */ @@ -420,6 +419,16 @@ struct b43legacy_phy { bool aci_wlan_automatic; bool aci_hw_rssi; + /* Radio switched on/off */ + bool radio_on; + struct { + /* Values saved when turning the radio off. + * They are needed when turning it on again. */ + bool valid; + u16 rfover; + u16 rfoverval; + } radio_off_context; + u16 minlowsig[2]; u16 minlowsigpos[2]; diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 61b94218094..3e935d0d4b8 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -2660,6 +2660,22 @@ static int b43legacy_dev_config(struct ieee80211_hw *hw, b43legacy_set_beacon_int(dev, conf->beacon_int); + if (!!conf->radio_enabled != phy->radio_on) { + if (conf->radio_enabled) { + b43legacy_radio_turn_on(dev); + b43legacyinfo(dev->wl, "Radio turned on by software\n"); + if (!dev->radio_hw_enable) + b43legacyinfo(dev->wl, "The hardware RF-kill" + " button still turns the radio" + " physically off. Press the" + " button to turn it on.\n"); + } else { + b43legacy_radio_turn_off(dev); + b43legacyinfo(dev->wl, "Radio turned off by" + " software\n"); + } + } + spin_lock_irqsave(&wl->irq_lock, flags); b43legacy_interrupt_enable(dev, savedirqs); mmiowb(); diff --git a/drivers/net/wireless/b43legacy/phy.c b/drivers/net/wireless/b43legacy/phy.c index f9edbd5f300..22a4b3d0186 100644 --- a/drivers/net/wireless/b43legacy/phy.c +++ b/drivers/net/wireless/b43legacy/phy.c @@ -462,12 +462,7 @@ static void b43legacy_phy_initb2(struct b43legacy_wldev *dev) val -= 0x0202; } b43legacy_phy_write(dev, 0x03E4, 0x3000); - if (phy->channel == 0xFF) - b43legacy_radio_selectchannel(dev, - B43legacy_RADIO_DEFAULT_CHANNEL_BG, - 0); - else - b43legacy_radio_selectchannel(dev, phy->channel, 0); + b43legacy_radio_selectchannel(dev, phy->channel, 0); if (phy->radio_ver != 0x2050) { b43legacy_radio_write16(dev, 0x0075, 0x0080); b43legacy_radio_write16(dev, 0x0079, 0x0081); @@ -516,12 +511,7 @@ static void b43legacy_phy_initb4(struct b43legacy_wldev *dev) val -= 0x0202; } b43legacy_phy_write(dev, 0x03E4, 0x3000); - if (phy->channel == 0xFF) - b43legacy_radio_selectchannel(dev, - B43legacy_RADIO_DEFAULT_CHANNEL_BG, - 0); - else - b43legacy_radio_selectchannel(dev, phy->channel, 0); + b43legacy_radio_selectchannel(dev, phy->channel, 0); if (phy->radio_ver != 0x2050) { b43legacy_radio_write16(dev, 0x0075, 0x0080); b43legacy_radio_write16(dev, 0x0079, 0x0081); diff --git a/drivers/net/wireless/b43legacy/radio.c b/drivers/net/wireless/b43legacy/radio.c index 2a11ee63f40..54067f08282 100644 --- a/drivers/net/wireless/b43legacy/radio.c +++ b/drivers/net/wireless/b43legacy/radio.c @@ -1767,6 +1767,17 @@ int b43legacy_radio_selectchannel(struct b43legacy_wldev *dev, { struct b43legacy_phy *phy = &dev->phy; + if (channel == 0xFF) { + switch (phy->type) { + case B43legacy_PHYTYPE_B: + case B43legacy_PHYTYPE_G: + channel = B43legacy_RADIO_DEFAULT_CHANNEL_BG; + break; + default: + B43legacy_WARN_ON(1); + } + } + /* TODO: Check if channel is valid - return -EINVAL if not */ if (synthetic_pu_workaround) b43legacy_synth_pu_workaround(dev, channel); @@ -2070,6 +2081,7 @@ void b43legacy_radio_turn_on(struct b43legacy_wldev *dev) { struct b43legacy_phy *phy = &dev->phy; int err; + u8 channel; might_sleep(); @@ -2083,15 +2095,24 @@ void b43legacy_radio_turn_on(struct b43legacy_wldev *dev) b43legacy_phy_write(dev, 0x0015, 0xCC00); b43legacy_phy_write(dev, 0x0015, (phy->gmode ? 0x00C0 : 0x0000)); + if (phy->radio_off_context.valid) { + /* Restore the RFover values. */ + b43legacy_phy_write(dev, B43legacy_PHY_RFOVER, + phy->radio_off_context.rfover); + b43legacy_phy_write(dev, B43legacy_PHY_RFOVERVAL, + phy->radio_off_context.rfoverval); + phy->radio_off_context.valid = 0; + } + channel = phy->channel; err = b43legacy_radio_selectchannel(dev, B43legacy_RADIO_DEFAULT_CHANNEL_BG, 1); - B43legacy_WARN_ON(err != 0); + err |= b43legacy_radio_selectchannel(dev, channel, 0); + B43legacy_WARN_ON(err); break; default: B43legacy_BUG_ON(1); } phy->radio_on = 1; - b43legacydbg(dev->wl, "Radio turned on\n"); b43legacy_leds_update(dev, 0); } @@ -2100,10 +2121,16 @@ void b43legacy_radio_turn_off(struct b43legacy_wldev *dev) struct b43legacy_phy *phy = &dev->phy; if (phy->type == B43legacy_PHYTYPE_G && dev->dev->id.revision >= 5) { - b43legacy_phy_write(dev, 0x0811, b43legacy_phy_read(dev, 0x0811) - | 0x008C); - b43legacy_phy_write(dev, 0x0812, b43legacy_phy_read(dev, 0x0812) - & 0xFF73); + u16 rfover, rfoverval; + + rfover = b43legacy_phy_read(dev, B43legacy_PHY_RFOVER); + rfoverval = b43legacy_phy_read(dev, B43legacy_PHY_RFOVERVAL); + phy->radio_off_context.rfover = rfover; + phy->radio_off_context.rfoverval = rfoverval; + phy->radio_off_context.valid = 1; + b43legacy_phy_write(dev, B43legacy_PHY_RFOVER, rfover | 0x008C); + b43legacy_phy_write(dev, B43legacy_PHY_RFOVERVAL, + rfoverval & 0xFF73); } else b43legacy_phy_write(dev, 0x0015, 0xAA00); phy->radio_on = 0; -- cgit v1.2.3-70-g09d2 From 1065de1562b1552a24f83e379bcb5fed351a8bc4 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 20 Sep 2007 20:10:07 -0500 Subject: [B43LEGACY]: Change the hardware radio enable logic and cleanup code This change cleans up the radio-related messages in several ways. (1) The state of the rfkill switch is assumed to be on, rather than tested. Now, any user without such a switch will not see any messages. For devices with such a switch, a message will be logged only if the initial state is off, or if the switch is toggled. (2) The routine for testing the switch state is no longer inline. (3) The LED handling routine is simplified. (4) The "Radio turned off" message that has confused some users has been changed to "Radio initialized". This patch is patterned after a similar change to b43 by Michael Buesch. Signed-off-by: Larry Finger Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/b43legacy/leds.c | 12 ++++-------- drivers/net/wireless/b43legacy/main.c | 25 ++++++++++++++++++++----- drivers/net/wireless/b43legacy/main.h | 20 -------------------- drivers/net/wireless/b43legacy/radio.c | 2 +- 4 files changed, 25 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43legacy/leds.c b/drivers/net/wireless/b43legacy/leds.c index 498912ddedd..a584ea81050 100644 --- a/drivers/net/wireless/b43legacy/leds.c +++ b/drivers/net/wireless/b43legacy/leds.c @@ -182,6 +182,7 @@ void b43legacy_leds_update(struct b43legacy_wldev *dev, int activity) unsigned long interval = 0; u16 ledctl; unsigned long flags; + bool radio_enabled = (phy->radio_on && dev->radio_hw_enable); spin_lock_irqsave(&dev->wl->leds_lock, flags); ledctl = b43legacy_read16(dev, B43legacy_MMIO_GPIO_CONTROL); @@ -201,20 +202,15 @@ void b43legacy_leds_update(struct b43legacy_wldev *dev, int activity) turn_on = activity; break; case B43legacy_LED_RADIO_ALL: - turn_on = phy->radio_on && - b43legacy_is_hw_radio_enabled(dev); + turn_on = radio_enabled; break; case B43legacy_LED_RADIO_A: break; case B43legacy_LED_RADIO_B: - turn_on = (phy->radio_on && - b43legacy_is_hw_radio_enabled(dev) && - (phy->type == B43legacy_PHYTYPE_B || - phy->type == B43legacy_PHYTYPE_G)); + turn_on = radio_enabled; break; case B43legacy_LED_MODE_BG: - if (phy->type == B43legacy_PHYTYPE_G && - b43legacy_is_hw_radio_enabled(dev)) + if (phy->type == B43legacy_PHYTYPE_G && radio_enabled) turn_on = 1; break; case B43legacy_LED_TRANSFER: diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 3e935d0d4b8..a793f183a2c 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -2007,6 +2007,21 @@ static void b43legacy_mgmtframe_txantenna(struct b43legacy_wldev *dev, B43legacy_SHM_SH_PRPHYCTL, tmp); } +/* Returns TRUE, if the radio is enabled in hardware. */ +static bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev) +{ + if (dev->phy.rev >= 3) { + if (!(b43legacy_read32(dev, B43legacy_MMIO_RADIO_HWENABLED_HI) + & B43legacy_MMIO_RADIO_HWENABLED_HI_MASK)) + return 1; + } else { + if (b43legacy_read16(dev, B43legacy_MMIO_RADIO_HWENABLED_LO) + & B43legacy_MMIO_RADIO_HWENABLED_LO_MASK) + return 1; + } + return 0; +} + /* This is the opposite of b43legacy_chip_init() */ static void b43legacy_chip_exit(struct b43legacy_wldev *dev) { @@ -2046,9 +2061,6 @@ static int b43legacy_chip_init(struct b43legacy_wldev *dev) if (err) goto err_gpio_cleanup; b43legacy_radio_turn_on(dev); - dev->radio_hw_enable = b43legacy_is_hw_radio_enabled(dev); - b43legacyinfo(dev->wl, "Radio %s by hardware\n", - (dev->radio_hw_enable == 0) ? "disabled" : "enabled"); b43legacy_write16(dev, 0x03E6, 0x0000); err = b43legacy_phy_init(dev); @@ -2170,14 +2182,14 @@ static void b43legacy_periodic_every15sec(struct b43legacy_wldev *dev) static void b43legacy_periodic_every1sec(struct b43legacy_wldev *dev) { - int radio_hw_enable; + bool radio_hw_enable; /* check if radio hardware enabled status changed */ radio_hw_enable = b43legacy_is_hw_radio_enabled(dev); if (unlikely(dev->radio_hw_enable != radio_hw_enable)) { dev->radio_hw_enable = radio_hw_enable; b43legacyinfo(dev->wl, "Radio hardware status changed to %s\n", - (radio_hw_enable == 0) ? "disabled" : "enabled"); + (radio_hw_enable) ? "enabled" : "disabled"); b43legacy_leds_update(dev, 0); } } @@ -2933,6 +2945,9 @@ static void setup_struct_phy_for_init(struct b43legacy_wldev *dev, /* Flags */ phy->locked = 0; + /* Assume the radio is enabled. If it's not enabled, the state will + * immediately get fixed on the first periodic work run. */ + dev->radio_hw_enable = 1; phy->savedpctlreg = 0xFFFF; phy->aci_enable = 0; diff --git a/drivers/net/wireless/b43legacy/main.h b/drivers/net/wireless/b43legacy/main.h index 673935e67e6..68435c50d8e 100644 --- a/drivers/net/wireless/b43legacy/main.h +++ b/drivers/net/wireless/b43legacy/main.h @@ -97,26 +97,6 @@ int b43legacy_is_ofdm_rate(int rate) return !b43legacy_is_cck_rate(rate); } -static inline -int b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev) -{ - /* function to return state of hardware enable of radio - * returns 0 if radio disabled, 1 if radio enabled - */ - struct b43legacy_phy *phy = &dev->phy; - - if (phy->rev >= 3) - return ((b43legacy_read32(dev, - B43legacy_MMIO_RADIO_HWENABLED_HI) - & B43legacy_MMIO_RADIO_HWENABLED_HI_MASK) - == 0) ? 1 : 0; - else - return ((b43legacy_read16(dev, - B43legacy_MMIO_RADIO_HWENABLED_LO) - & B43legacy_MMIO_RADIO_HWENABLED_LO_MASK) - == 0) ? 0 : 1; -} - void b43legacy_tsf_read(struct b43legacy_wldev *dev, u64 *tsf); void b43legacy_tsf_write(struct b43legacy_wldev *dev, u64 tsf); diff --git a/drivers/net/wireless/b43legacy/radio.c b/drivers/net/wireless/b43legacy/radio.c index 54067f08282..a361dee664a 100644 --- a/drivers/net/wireless/b43legacy/radio.c +++ b/drivers/net/wireless/b43legacy/radio.c @@ -2134,7 +2134,7 @@ void b43legacy_radio_turn_off(struct b43legacy_wldev *dev) } else b43legacy_phy_write(dev, 0x0015, 0xAA00); phy->radio_on = 0; - b43legacydbg(dev->wl, "Radio turned off\n"); + b43legacydbg(dev->wl, "Radio initialized\n"); b43legacy_leds_update(dev, 0); } -- cgit v1.2.3-70-g09d2 From 6f05cbe5882e8b0fc5a984313cbb14ce7741411b Mon Sep 17 00:00:00 2001 From: Ryan Mallon Date: Thu, 6 Sep 2007 21:30:32 -0400 Subject: [LIBERTAS]: set dnld_sent correctly for CF parts Corrects a minor bug with priv->dnld_sent being set incorrectly in if_cs_host_to_card. Signed-off-by: Ryan Mallon Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/libertas/if_cs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c index 09c87df5c2f..364da4cac21 100644 --- a/drivers/net/wireless/libertas/if_cs.c +++ b/drivers/net/wireless/libertas/if_cs.c @@ -617,11 +617,12 @@ static int if_cs_host_to_card(wlan_private *priv, u8 type, u8 *buf, u16 nb) switch (type) { case MVMS_DAT: - priv->dnld_sent = DNLD_CMD_SENT; + priv->dnld_sent = DNLD_DATA_SENT; if_cs_send_data(priv, buf, nb); ret = 0; break; case MVMS_CMD: + priv->dnld_sent = DNLD_CMD_SENT; ret = if_cs_send_cmd(priv, buf, nb); break; default: -- cgit v1.2.3-70-g09d2 From 28de0b36be2a4e7fb0ba7c9a77d61aeb229b27c0 Mon Sep 17 00:00:00 2001 From: Ryan Mallon Date: Thu, 6 Sep 2007 21:32:42 -0400 Subject: [LIBERTAS]: fix interrupts in CF driver The following patch fixes the tx transmit timeout problem, which is caused by the interrupts being incorrectly check and masked. The patch moves the interrupt masking code so that interrupts are enabled only when the driver is registered and only disabled when the driver is unregistered. Signed-off-by: Ryan Mallon Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/libertas/if_cs.c | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c index 364da4cac21..e74ec5c309b 100644 --- a/drivers/net/wireless/libertas/if_cs.c +++ b/drivers/net/wireless/libertas/if_cs.c @@ -248,22 +248,26 @@ static irqreturn_t if_cs_interrupt(int irq, void *data) lbs_deb_enter(LBS_DEB_CS); int_cause = if_cs_read16(card, IF_CS_C_INT_CAUSE); - switch (int_cause) { - case 0x0000: - /* not for us */ + if(int_cause == 0x0) { + /* Not for us */ return IRQ_NONE; - case 0xffff: - /* if one reads junk, then probably the card was removed */ + + } else if(int_cause == 0xffff) { + /* Read in junk, the card has probably been removed */ card->priv->adapter->surpriseremoved = 1; - break; - case IF_CS_H_IC_TX_OVER: - if (card->priv->adapter->connect_status == LIBERTAS_CONNECTED) - netif_wake_queue(card->priv->dev); - /* fallthrought */ - default: + + } else { + if(int_cause & IF_CS_H_IC_TX_OVER) { + card->priv->dnld_sent = DNLD_RES_RECEIVED; + if (!card->priv->adapter->cur_cmd) + wake_up_interruptible(&card->priv->waitq); + + if (card->priv->adapter->connect_status == LIBERTAS_CONNECTED) + netif_wake_queue(card->priv->dev); + } + /* clear interrupt */ if_cs_write16(card, IF_CS_C_INT_CAUSE, int_cause & IF_CS_C_IC_MASK); - if_cs_disable_ints(card); } libertas_interrupt(card->priv->dev); @@ -652,7 +656,6 @@ static int if_cs_get_int_status(wlan_private *priv, u8 *ireg) if_cs_write16(card, IF_CS_C_INT_CAUSE, int_cause); *ireg = if_cs_read16(card, IF_CS_C_STATUS) & IF_CS_C_S_MASK; - if_cs_enable_ints(card); if (!*ireg) goto sbi_get_int_status_exit; @@ -841,7 +844,6 @@ static int if_cs_probe(struct pcmcia_device *p_dev) p_dev->irq.AssignedIRQ, p_dev->io.BasePort1, p_dev->io.BasePort1 + p_dev->io.NumPorts1 - 1); - if_cs_enable_ints(card); /* Load the firmware early, before calling into libertas.ko */ ret = if_cs_prog_helper(card); @@ -874,6 +876,8 @@ static int if_cs_probe(struct pcmcia_device *p_dev) goto out3; } + if_cs_enable_ints(card); + /* And finally bring the card up */ if (libertas_start_card(priv) != 0) { lbs_pr_err("could not activate card\n"); @@ -909,6 +913,7 @@ static void if_cs_detach(struct pcmcia_device *p_dev) libertas_stop_card(card->priv); libertas_remove_card(card->priv); + if_cs_disable_ints(card); if_cs_release(p_dev); kfree(card); -- cgit v1.2.3-70-g09d2 From f31ce76b781d15ab6b529663b95223f58171ec80 Mon Sep 17 00:00:00 2001 From: Vladimir Davydov Date: Thu, 6 Sep 2007 21:41:02 -0400 Subject: [LIBERTAS]: fix oops on the blackfin architecture Reserve two bytes to align pointer to the IP header. Signed-off-by: Vladimir Davydov Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/libertas/if_cs.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c index e74ec5c309b..0360cad363a 100644 --- a/drivers/net/wireless/libertas/if_cs.c +++ b/drivers/net/wireless/libertas/if_cs.c @@ -402,10 +402,12 @@ static struct sk_buff *if_cs_receive_data(wlan_private *priv) } //TODO: skb = dev_alloc_skb(len+ETH_FRAME_LEN+MRVDRV_SNAP_HEADER_LEN+EXTRA_LEN); - skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE); + skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + 2); if (!skb) goto out; - data = skb_put(skb, len); + skb_put(skb, len); + skb_reserve(skb, 2);/* 16 byte align */ + data = skb->data; /* read even number of bytes, then odd byte if necessary */ if_cs_read16_rep(priv->card, IF_CS_H_READ, data, len/sizeof(u16)); -- cgit v1.2.3-70-g09d2 From ac630c2b1933e79ff32e3653ae656620cf4b4c79 Mon Sep 17 00:00:00 2001 From: Vladimir Davydov Date: Thu, 6 Sep 2007 21:45:36 -0400 Subject: [LIBERTAS]: fix oops on the blackfin architecture Fixing memory alignment problems on the blackfin architecture (maybe on the ARM also) Signed-off-by: Vladimir Davydov Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/libertas/scan.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 8f073ad1957..fab93d8fe9c 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -13,6 +13,8 @@ #include #include +#include + #include "host.h" #include "decl.h" #include "dev.h" @@ -888,7 +890,7 @@ static int libertas_process_bss(struct bss_descriptor * bss, if (*bytesleft >= sizeof(beaconsize)) { /* Extract & convert beacon size from the command buffer */ - beaconsize = le16_to_cpup((void *)*pbeaconinfo); + beaconsize = le16_to_cpu(get_unaligned((u16 *)*pbeaconinfo)); *bytesleft -= sizeof(beaconsize); *pbeaconinfo += sizeof(beaconsize); } @@ -1698,10 +1700,10 @@ int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp) goto done; } - bytesleft = le16_to_cpu(pscan->bssdescriptsize); + bytesleft = le16_to_cpu(get_unaligned((u16*)&pscan->bssdescriptsize)); lbs_deb_scan("SCAN_RESP: bssdescriptsize %d\n", bytesleft); - scanrespsize = le16_to_cpu(resp->size); + scanrespsize = le16_to_cpu(get_unaligned((u16*)&resp->size)); lbs_deb_scan("SCAN_RESP: returned %d AP before parsing\n", pscan->nr_sets); -- cgit v1.2.3-70-g09d2 From 5f6d88b9149d537f3db0798f7d312be632422e15 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 26 Sep 2007 22:08:12 -0700 Subject: [NET]: Dynamically allocate the per cpu counters for the loopback device. This patch add support for dynamically allocating the statistics counters for the loopback device and adds appropriate device methods for allocating and freeing the loopback device. This completes support for creating multiple instances of the loopback device, in preparation for creating per network namespace instances. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- drivers/net/loopback.c | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 4b6f7b2abea..f3018bb7570 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -62,7 +62,6 @@ struct pcpu_lstats { unsigned long packets; unsigned long bytes; }; -static DEFINE_PER_CPU(struct pcpu_lstats, pcpu_lstats); #define LOOPBACK_OVERHEAD (128 + MAX_HEADER + 16 + 16) @@ -134,7 +133,7 @@ static void emulate_large_send_offload(struct sk_buff *skb) */ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) { - struct pcpu_lstats *lb_stats; + struct pcpu_lstats *pcpu_lstats, *lb_stats; skb_orphan(skb); @@ -155,7 +154,8 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) dev->last_rx = jiffies; /* it's OK to use __get_cpu_var() because BHs are off */ - lb_stats = &__get_cpu_var(pcpu_lstats); + pcpu_lstats = netdev_priv(dev); + lb_stats = per_cpu_ptr(pcpu_lstats, smp_processor_id()); lb_stats->bytes += skb->len; lb_stats->packets++; @@ -166,15 +166,17 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) static struct net_device_stats *get_stats(struct net_device *dev) { + const struct pcpu_lstats *pcpu_lstats; struct net_device_stats *stats = &dev->stats; unsigned long bytes = 0; unsigned long packets = 0; int i; + pcpu_lstats = netdev_priv(dev); for_each_possible_cpu(i) { const struct pcpu_lstats *lb_stats; - lb_stats = &per_cpu(pcpu_lstats, i); + lb_stats = per_cpu_ptr(pcpu_lstats, i); bytes += lb_stats->bytes; packets += lb_stats->packets; } @@ -198,6 +200,26 @@ static const struct ethtool_ops loopback_ethtool_ops = { .get_rx_csum = always_on, }; +static int loopback_dev_init(struct net_device *dev) +{ + struct pcpu_lstats *lstats; + + lstats = alloc_percpu(struct pcpu_lstats); + if (!lstats) + return -ENOMEM; + + dev->priv = lstats; + return 0; +} + +static void loopback_dev_free(struct net_device *dev) +{ + struct pcpu_lstats *lstats = netdev_priv(dev); + + free_percpu(lstats); + free_netdev(dev); +} + /* * The loopback device is special. There is only one instance and * it is statically allocated. Don't do this for other devices. @@ -225,6 +247,8 @@ static void loopback_setup(struct net_device *dev) | NETIF_F_LLTX | NETIF_F_NETNS_LOCAL, dev->ethtool_ops = &loopback_ethtool_ops; + dev->init = loopback_dev_init; + dev->destructor = loopback_dev_free; } /* Setup and register the loopback device. */ -- cgit v1.2.3-70-g09d2 From 2774c7aba6c97a2535be3309a2209770953780b3 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 26 Sep 2007 22:10:56 -0700 Subject: [NET]: Make the loopback device per network namespace. This patch makes loopback_dev per network namespace. Adding code to create a different loopback device for each network namespace and adding the code to free a loopback device when a network namespace exits. This patch modifies all users the loopback_dev so they access it as init_net.loopback_dev, keeping all of the code compiling and working. A later pass will be needed to update the users to use something other than the initial network namespace. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- drivers/net/loopback.c | 26 +++++++++++++++++++++----- include/linux/netdevice.h | 1 - include/net/net_namespace.h | 3 +++ net/core/dst.c | 5 +++-- net/decnet/dn_dev.c | 4 ++-- net/decnet/dn_route.c | 14 +++++++------- net/ipv4/route.c | 18 +++++++++--------- net/ipv4/xfrm4_policy.c | 2 +- net/ipv6/addrconf.c | 18 +++++++++--------- net/ipv6/netfilter/ip6t_REJECT.c | 2 +- net/ipv6/route.c | 12 ++++++------ net/ipv6/xfrm6_policy.c | 2 +- net/xfrm/xfrm_policy.c | 2 +- 13 files changed, 64 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index f3018bb7570..0f9d8c60c96 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -57,6 +57,7 @@ #include #include #include +#include struct pcpu_lstats { unsigned long packets; @@ -252,7 +253,7 @@ static void loopback_setup(struct net_device *dev) } /* Setup and register the loopback device. */ -static int __init loopback_init(void) +static int loopback_net_init(struct net *net) { struct net_device *dev; int err; @@ -262,12 +263,13 @@ static int __init loopback_init(void) if (!dev) goto out; + dev->nd_net = net; err = register_netdev(dev); if (err) goto out_free_netdev; err = 0; - loopback_dev = dev; + net->loopback_dev = dev; out: if (err) @@ -279,7 +281,21 @@ out_free_netdev: goto out; } -fs_initcall(loopback_init); +static void loopback_net_exit(struct net *net) +{ + struct net_device *dev = net->loopback_dev; + + unregister_netdev(dev); +} + +static struct pernet_operations loopback_net_ops = { + .init = loopback_net_init, + .exit = loopback_net_exit, +}; + +static int __init loopback_init(void) +{ + return register_pernet_device(&loopback_net_ops); +} -struct net_device *loopback_dev; -EXPORT_SYMBOL(loopback_dev); +fs_initcall(loopback_init); diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 2088097663b..71cf409ad17 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -742,7 +742,6 @@ struct packet_type { #include #include -extern struct net_device *loopback_dev; /* The loopback */ extern rwlock_t dev_base_lock; /* Device list lock */ diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 3ea4194613e..13b0e3b547f 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -9,6 +9,7 @@ #include struct proc_dir_entry; +struct net_device; struct net { atomic_t count; /* To decided when the network * namespace should be freed. @@ -23,6 +24,8 @@ struct net { struct proc_dir_entry *proc_net_stat; struct proc_dir_entry *proc_net_root; + struct net_device *loopback_dev; /* The loopback */ + struct list_head dev_base_head; struct hlist_head *dev_name_head; struct hlist_head *dev_index_head; diff --git a/net/core/dst.c b/net/core/dst.c index ad5ffa19d80..16958e64e57 100644 --- a/net/core/dst.c +++ b/net/core/dst.c @@ -18,6 +18,7 @@ #include #include +#include #include /* @@ -278,11 +279,11 @@ static inline void dst_ifdown(struct dst_entry *dst, struct net_device *dev, if (!unregister) { dst->input = dst->output = dst_discard; } else { - dst->dev = loopback_dev; + dst->dev = init_net.loopback_dev; dev_hold(dst->dev); dev_put(dev); if (dst->neighbour && dst->neighbour->dev == dev) { - dst->neighbour->dev = loopback_dev; + dst->neighbour->dev = init_net.loopback_dev; dev_put(dev); dev_hold(dst->neighbour->dev); } diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c index bcaf4c5aa68..26130afd802 100644 --- a/net/decnet/dn_dev.c +++ b/net/decnet/dn_dev.c @@ -869,10 +869,10 @@ last_chance: rv = dn_dev_get_first(dev, addr); read_unlock(&dev_base_lock); dev_put(dev); - if (rv == 0 || dev == loopback_dev) + if (rv == 0 || dev == init_net.loopback_dev) return rv; } - dev = loopback_dev; + dev = init_net.loopback_dev; dev_hold(dev); goto last_chance; } diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index 96fe0aa1638..b7ebf9947eb 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -887,7 +887,7 @@ static int dn_route_output_slow(struct dst_entry **pprt, const struct flowi *old .scope = RT_SCOPE_UNIVERSE, } }, .mark = oldflp->mark, - .iif = loopback_dev->ifindex, + .iif = init_net.loopback_dev->ifindex, .oif = oldflp->oif }; struct dn_route *rt = NULL; struct net_device *dev_out = NULL, *dev; @@ -904,7 +904,7 @@ static int dn_route_output_slow(struct dst_entry **pprt, const struct flowi *old "dn_route_output_slow: dst=%04x src=%04x mark=%d" " iif=%d oif=%d\n", dn_ntohs(oldflp->fld_dst), dn_ntohs(oldflp->fld_src), - oldflp->mark, loopback_dev->ifindex, oldflp->oif); + oldflp->mark, init_net.loopback_dev->ifindex, oldflp->oif); /* If we have an output interface, verify its a DECnet device */ if (oldflp->oif) { @@ -957,7 +957,7 @@ source_ok: err = -EADDRNOTAVAIL; if (dev_out) dev_put(dev_out); - dev_out = loopback_dev; + dev_out = init_net.loopback_dev; dev_hold(dev_out); if (!fl.fld_dst) { fl.fld_dst = @@ -966,7 +966,7 @@ source_ok: if (!fl.fld_dst) goto out; } - fl.oif = loopback_dev->ifindex; + fl.oif = init_net.loopback_dev->ifindex; res.type = RTN_LOCAL; goto make_route; } @@ -1012,7 +1012,7 @@ source_ok: if (dev_out) dev_put(dev_out); if (dn_dev_islocal(neigh->dev, fl.fld_dst)) { - dev_out = loopback_dev; + dev_out = init_net.loopback_dev; res.type = RTN_LOCAL; } else { dev_out = neigh->dev; @@ -1033,7 +1033,7 @@ source_ok: /* Possible improvement - check all devices for local addr */ if (dn_dev_islocal(dev_out, fl.fld_dst)) { dev_put(dev_out); - dev_out = loopback_dev; + dev_out = init_net.loopback_dev; dev_hold(dev_out); res.type = RTN_LOCAL; goto select_source; @@ -1069,7 +1069,7 @@ select_source: fl.fld_src = fl.fld_dst; if (dev_out) dev_put(dev_out); - dev_out = loopback_dev; + dev_out = init_net.loopback_dev; dev_hold(dev_out); fl.oif = dev_out->ifindex; if (res.fi) diff --git a/net/ipv4/route.c b/net/ipv4/route.c index ca2878dc618..2a9b363e820 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1402,8 +1402,8 @@ static void ipv4_dst_ifdown(struct dst_entry *dst, struct net_device *dev, { struct rtable *rt = (struct rtable *) dst; struct in_device *idev = rt->idev; - if (dev != loopback_dev && idev && idev->dev == dev) { - struct in_device *loopback_idev = in_dev_get(loopback_dev); + if (dev != init_net.loopback_dev && idev && idev->dev == dev) { + struct in_device *loopback_idev = in_dev_get(init_net.loopback_dev); if (loopback_idev) { rt->idev = loopback_idev; in_dev_put(idev); @@ -1555,7 +1555,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr, #endif rth->rt_iif = rth->fl.iif = dev->ifindex; - rth->u.dst.dev = loopback_dev; + rth->u.dst.dev = init_net.loopback_dev; dev_hold(rth->u.dst.dev); rth->idev = in_dev_get(rth->u.dst.dev); rth->fl.oif = 0; @@ -1812,7 +1812,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr, if (res.type == RTN_LOCAL) { int result; result = fib_validate_source(saddr, daddr, tos, - loopback_dev->ifindex, + init_net.loopback_dev->ifindex, dev, &spec_dst, &itag); if (result < 0) goto martian_source; @@ -1879,7 +1879,7 @@ local_input: #endif rth->rt_iif = rth->fl.iif = dev->ifindex; - rth->u.dst.dev = loopback_dev; + rth->u.dst.dev = init_net.loopback_dev; dev_hold(rth->u.dst.dev); rth->idev = in_dev_get(rth->u.dst.dev); rth->rt_gateway = daddr; @@ -2149,7 +2149,7 @@ static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp) RT_SCOPE_UNIVERSE), } }, .mark = oldflp->mark, - .iif = loopback_dev->ifindex, + .iif = init_net.loopback_dev->ifindex, .oif = oldflp->oif }; struct fib_result res; unsigned flags = 0; @@ -2243,9 +2243,9 @@ static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp) fl.fl4_dst = fl.fl4_src = htonl(INADDR_LOOPBACK); if (dev_out) dev_put(dev_out); - dev_out = loopback_dev; + dev_out = init_net.loopback_dev; dev_hold(dev_out); - fl.oif = loopback_dev->ifindex; + fl.oif = init_net.loopback_dev->ifindex; res.type = RTN_LOCAL; flags |= RTCF_LOCAL; goto make_route; @@ -2290,7 +2290,7 @@ static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp) fl.fl4_src = fl.fl4_dst; if (dev_out) dev_put(dev_out); - dev_out = loopback_dev; + dev_out = init_net.loopback_dev; dev_hold(dev_out); fl.oif = dev_out->ifindex; if (res.fi) diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index 29ab3de8c47..329825ca68f 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c @@ -306,7 +306,7 @@ static void xfrm4_dst_ifdown(struct dst_entry *dst, struct net_device *dev, xdst = (struct xfrm_dst *)dst; if (xdst->u.rt.idev->dev == dev) { - struct in_device *loopback_idev = in_dev_get(loopback_dev); + struct in_device *loopback_idev = in_dev_get(init_net.loopback_dev); BUG_ON(!loopback_idev); do { diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index b43574f7337..6d5c3c29914 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -2410,7 +2410,7 @@ static int addrconf_ifdown(struct net_device *dev, int how) ASSERT_RTNL(); - if (dev == loopback_dev && how == 1) + if (dev == init_net.loopback_dev && how == 1) how = 0; rt6_ifdown(dev); @@ -4212,19 +4212,19 @@ int __init addrconf_init(void) * device and it being up should be removed. */ rtnl_lock(); - if (!ipv6_add_dev(loopback_dev)) + if (!ipv6_add_dev(init_net.loopback_dev)) err = -ENOMEM; rtnl_unlock(); if (err) return err; - ip6_null_entry.u.dst.dev = loopback_dev; - ip6_null_entry.rt6i_idev = in6_dev_get(loopback_dev); + ip6_null_entry.u.dst.dev = init_net.loopback_dev; + ip6_null_entry.rt6i_idev = in6_dev_get(init_net.loopback_dev); #ifdef CONFIG_IPV6_MULTIPLE_TABLES - ip6_prohibit_entry.u.dst.dev = loopback_dev; - ip6_prohibit_entry.rt6i_idev = in6_dev_get(loopback_dev); - ip6_blk_hole_entry.u.dst.dev = loopback_dev; - ip6_blk_hole_entry.rt6i_idev = in6_dev_get(loopback_dev); + ip6_prohibit_entry.u.dst.dev = init_net.loopback_dev; + ip6_prohibit_entry.rt6i_idev = in6_dev_get(init_net.loopback_dev); + ip6_blk_hole_entry.u.dst.dev = init_net.loopback_dev; + ip6_blk_hole_entry.rt6i_idev = in6_dev_get(init_net.loopback_dev); #endif register_netdevice_notifier(&ipv6_dev_notf); @@ -4279,7 +4279,7 @@ void __exit addrconf_cleanup(void) continue; addrconf_ifdown(dev, 1); } - addrconf_ifdown(loopback_dev, 2); + addrconf_ifdown(init_net.loopback_dev, 2); /* * Check hash table. diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c index 50860531cd3..3fd08d5567a 100644 --- a/net/ipv6/netfilter/ip6t_REJECT.c +++ b/net/ipv6/netfilter/ip6t_REJECT.c @@ -167,7 +167,7 @@ static inline void send_unreach(struct sk_buff *skb_in, unsigned char code, unsigned int hooknum) { if (hooknum == NF_IP6_LOCAL_OUT && skb_in->dev == NULL) - skb_in->dev = loopback_dev; + skb_in->dev = init_net.loopback_dev; icmpv6_send(skb_in, ICMPV6_DEST_UNREACH, code, 0, NULL); } diff --git a/net/ipv6/route.c b/net/ipv6/route.c index a7a21a7ba79..6ff19f9eb9e 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -221,8 +221,8 @@ static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, struct rt6_info *rt = (struct rt6_info *)dst; struct inet6_dev *idev = rt->rt6i_idev; - if (dev != loopback_dev && idev != NULL && idev->dev == dev) { - struct inet6_dev *loopback_idev = in6_dev_get(loopback_dev); + if (dev != init_net.loopback_dev && idev != NULL && idev->dev == dev) { + struct inet6_dev *loopback_idev = in6_dev_get(init_net.loopback_dev); if (loopback_idev != NULL) { rt->rt6i_idev = loopback_idev; in6_dev_put(idev); @@ -1185,12 +1185,12 @@ int ip6_route_add(struct fib6_config *cfg) if ((cfg->fc_flags & RTF_REJECT) || (dev && (dev->flags&IFF_LOOPBACK) && !(addr_type&IPV6_ADDR_LOOPBACK))) { /* hold loopback dev/idev if we haven't done so. */ - if (dev != loopback_dev) { + if (dev != init_net.loopback_dev) { if (dev) { dev_put(dev); in6_dev_put(idev); } - dev = loopback_dev; + dev = init_net.loopback_dev; dev_hold(dev); idev = in6_dev_get(dev); if (!idev) { @@ -1894,13 +1894,13 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, if (rt == NULL) return ERR_PTR(-ENOMEM); - dev_hold(loopback_dev); + dev_hold(init_net.loopback_dev); in6_dev_hold(idev); rt->u.dst.flags = DST_HOST; rt->u.dst.input = ip6_input; rt->u.dst.output = ip6_output; - rt->rt6i_dev = loopback_dev; + rt->rt6i_dev = init_net.loopback_dev; rt->rt6i_idev = idev; rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(rt->rt6i_dev); rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_mtu(&rt->u.dst)); diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index cc07216cfd5..15aa4c58c31 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c @@ -375,7 +375,7 @@ static void xfrm6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, xdst = (struct xfrm_dst *)dst; if (xdst->u.rt6.rt6i_idev->dev == dev) { - struct inet6_dev *loopback_idev = in6_dev_get(loopback_dev); + struct inet6_dev *loopback_idev = in6_dev_get(init_net.loopback_dev); BUG_ON(!loopback_idev); do { diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index d6dfd7d1948..76f172f13f9 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -1949,7 +1949,7 @@ static int stale_bundle(struct dst_entry *dst) void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev) { while ((dst = dst->child) && dst->xfrm && dst->dev == dev) { - dst->dev = loopback_dev; + dst->dev = init_net.loopback_dev; dev_hold(dst->dev); dev_put(dev); } -- cgit v1.2.3-70-g09d2 From 4c94f8c0c9a82fad84bc5df453aff755cfed70b7 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 26 Sep 2007 22:11:56 -0700 Subject: [NET]: Remove no longer relevant comment in loopback driver. It talks about __get_cpu_var() which the driver no longer does. Signed-off-by: David S. Miller --- drivers/net/loopback.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 0f9d8c60c96..f11120b7a3b 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -154,7 +154,6 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) #endif dev->last_rx = jiffies; - /* it's OK to use __get_cpu_var() because BHs are off */ pcpu_lstats = netdev_priv(dev); lb_stats = per_cpu_ptr(pcpu_lstats, smp_processor_id()); lb_stats->bytes += skb->len; -- cgit v1.2.3-70-g09d2 From 0c4e85813d0a94eeb8bf813397a4907bdd7bb610 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 9 Oct 2007 01:36:32 -0700 Subject: [NET]: Wrap netdevice hardware header creation. Add inline for common usage of hardware header creation, and fix bug in IPV6 mcast where the assumption about negative return is an errno. Negative return from hard_header means not enough space was available,(ie -N bytes). Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/hamradio/bpqether.c | 2 +- drivers/net/macvlan.c | 4 ++-- drivers/net/pppoe.c | 8 ++++---- drivers/net/wan/lapbether.c | 2 +- include/linux/netdevice.h | 9 +++++++++ include/net/dn_route.h | 3 +-- net/802/p8023.c | 2 +- net/8021q/vlan_dev.c | 14 ++++++-------- net/core/neighbour.c | 17 ++++++++--------- net/core/netpoll.c | 8 +++----- net/decnet/dn_neigh.c | 3 ++- net/econet/af_econet.c | 14 +++++++------- net/ethernet/pe2.c | 4 +--- net/ipv4/arp.c | 3 +-- net/ipv4/ipconfig.c | 4 ++-- net/ipv6/mcast.c | 15 +++++---------- net/packet/af_packet.c | 14 ++++---------- net/sched/sch_teql.c | 5 ++++- net/tipc/eth_media.c | 2 +- 19 files changed, 63 insertions(+), 70 deletions(-) (limited to 'drivers') diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index c05bc37df35..4bff23e3b97 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -286,7 +286,7 @@ static int bpq_xmit(struct sk_buff *skb, struct net_device *dev) skb->protocol = ax25_type_trans(skb, dev); skb_reset_network_header(skb); - dev->hard_header(skb, dev, ETH_P_BPQ, bpq->dest_addr, NULL, 0); + dev_hard_header(skb, dev, ETH_P_BPQ, bpq->dest_addr, NULL, 0); bpq->stats.tx_packets++; bpq->stats.tx_bytes+=skb->len; diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 2f6cdaa8872..a22087ca968 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -170,8 +170,8 @@ static int macvlan_hard_header(struct sk_buff *skb, struct net_device *dev, const struct macvlan_dev *vlan = netdev_priv(dev); struct net_device *lowerdev = vlan->lowerdev; - return lowerdev->hard_header(skb, lowerdev, type, daddr, - saddr ? : dev->dev_addr, len); + return dev_hard_header(skb, lowerdev, type, daddr, + saddr ? : dev->dev_addr, len); } static int macvlan_open(struct net_device *dev) diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index d48b7b73d89..8936ed3469c 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -834,8 +834,8 @@ static int pppoe_sendmsg(struct kiocb *iocb, struct socket *sock, } error = total_len; - dev->hard_header(skb, dev, ETH_P_PPP_SES, - po->pppoe_pa.remote, NULL, total_len); + dev_hard_header(skb, dev, ETH_P_PPP_SES, + po->pppoe_pa.remote, NULL, total_len); memcpy(ph, &hdr, sizeof(struct pppoe_hdr)); @@ -886,8 +886,8 @@ static int __pppoe_xmit(struct sock *sk, struct sk_buff *skb) skb->protocol = __constant_htons(ETH_P_PPP_SES); skb->dev = dev; - dev->hard_header(skb, dev, ETH_P_PPP_SES, - po->pppoe_pa.remote, NULL, data_len); + dev_hard_header(skb, dev, ETH_P_PPP_SES, + po->pppoe_pa.remote, NULL, data_len); dev_queue_xmit(skb); diff --git a/drivers/net/wan/lapbether.c b/drivers/net/wan/lapbether.c index 36e683ccae5..fb37b809523 100644 --- a/drivers/net/wan/lapbether.c +++ b/drivers/net/wan/lapbether.c @@ -216,7 +216,7 @@ static void lapbeth_data_transmit(struct net_device *ndev, struct sk_buff *skb) skb->dev = dev = lapbeth->ethdev; - dev->hard_header(skb, dev, ETH_P_DEC, bcast_addr, NULL, 0); + dev_hard_header(skb, dev, ETH_P_DEC, bcast_addr, NULL, 0); dev_queue_xmit(skb); } diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 71cf409ad17..b33d084712f 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -800,6 +800,15 @@ extern int dev_restart(struct net_device *dev); extern int netpoll_trap(void); #endif +static inline int dev_hard_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, + void *daddr, void *saddr, unsigned len) +{ + if (!dev->hard_header) + return 0; + return dev->hard_header(skb, dev, type, daddr, saddr, len); +} + typedef int gifconf_func_t(struct net_device * dev, char __user * bufptr, int len); extern int register_gifconf(unsigned int family, gifconf_func_t * gifconf); static inline int unregister_gifconf(unsigned int family) diff --git a/include/net/dn_route.h b/include/net/dn_route.h index c10e8e7e59a..60c9f22d869 100644 --- a/include/net/dn_route.h +++ b/include/net/dn_route.h @@ -100,8 +100,7 @@ static inline void dn_rt_finish_output(struct sk_buff *skb, char *dst, char *src if ((dev->type != ARPHRD_ETHER) && (dev->type != ARPHRD_LOOPBACK)) dst = NULL; - if (!dev->hard_header || (dev->hard_header(skb, dev, ETH_P_DNA_RT, - dst, src, skb->len) >= 0)) + if (dev_hard_header(skb, dev, ETH_P_DNA_RT, dst, src, skb->len) >= 0) dn_rt_send(skb); else kfree_skb(skb); diff --git a/net/802/p8023.c b/net/802/p8023.c index 53cf0570928..6ab1835041a 100644 --- a/net/802/p8023.c +++ b/net/802/p8023.c @@ -31,7 +31,7 @@ static int p8023_request(struct datalink_proto *dl, { struct net_device *dev = skb->dev; - dev->hard_header(skb, dev, ETH_P_802_3, dest_node, NULL, skb->len); + dev_hard_header(skb, dev, ETH_P_802_3, dest_node, NULL, skb->len); return dev_queue_xmit(skb); } diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 6644e8f5f19..ca8090fdabb 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -434,21 +434,19 @@ int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev, if (build_vlan_header) { /* Now make the underlying real hard header */ - rc = dev->hard_header(skb, dev, ETH_P_8021Q, daddr, saddr, len + VLAN_HLEN); - - if (rc > 0) { + rc = dev_hard_header(skb, dev, ETH_P_8021Q, daddr, saddr, + len + VLAN_HLEN); + if (rc > 0) rc += VLAN_HLEN; - } else if (rc < 0) { + else if (rc < 0) rc -= VLAN_HLEN; - } - } else { + } else /* If here, then we'll just make a normal looking ethernet frame, * but, the hard_start_xmit method will insert the tag (it has to * be able to do this for bridged and other skbs that don't come * down the protocol stack in an orderly manner. */ - rc = dev->hard_header(skb, dev, type, daddr, saddr, len); - } + rc = dev_hard_header(skb, dev, type, daddr, saddr, len); return rc; } diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 2c6577c1eed..10bcb9f8da5 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -1125,9 +1125,8 @@ int neigh_compat_output(struct sk_buff *skb) __skb_pull(skb, skb_network_offset(skb)); - if (dev->hard_header && - dev->hard_header(skb, dev, ntohs(skb->protocol), NULL, NULL, - skb->len) < 0 && + if (dev_hard_header(skb, dev, ntohs(skb->protocol), NULL, NULL, + skb->len) < 0 && dev->rebuild_header(skb)) return 0; @@ -1154,13 +1153,13 @@ int neigh_resolve_output(struct sk_buff *skb) write_lock_bh(&neigh->lock); if (!dst->hh) neigh_hh_init(neigh, dst, dst->ops->protocol); - err = dev->hard_header(skb, dev, ntohs(skb->protocol), - neigh->ha, NULL, skb->len); + err = dev_hard_header(skb, dev, ntohs(skb->protocol), + neigh->ha, NULL, skb->len); write_unlock_bh(&neigh->lock); } else { read_lock_bh(&neigh->lock); - err = dev->hard_header(skb, dev, ntohs(skb->protocol), - neigh->ha, NULL, skb->len); + err = dev_hard_header(skb, dev, ntohs(skb->protocol), + neigh->ha, NULL, skb->len); read_unlock_bh(&neigh->lock); } if (err >= 0) @@ -1191,8 +1190,8 @@ int neigh_connected_output(struct sk_buff *skb) __skb_pull(skb, skb_network_offset(skb)); read_lock_bh(&neigh->lock); - err = dev->hard_header(skb, dev, ntohs(skb->protocol), - neigh->ha, NULL, skb->len); + err = dev_hard_header(skb, dev, ntohs(skb->protocol), + neigh->ha, NULL, skb->len); read_unlock_bh(&neigh->lock); if (err >= 0) err = neigh->ops->queue_xmit(skb); diff --git a/net/core/netpoll.c b/net/core/netpoll.c index e13602d8154..95daba62496 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -415,11 +415,9 @@ static void arp_reply(struct sk_buff *skb) send_skb->protocol = htons(ETH_P_ARP); /* Fill the device header for the ARP frame */ - - if (np->dev->hard_header && - np->dev->hard_header(send_skb, skb->dev, ptype, - sha, np->local_mac, - send_skb->len) < 0) { + if (dev_hard_header(send_skb, skb->dev, ptype, + sha, np->local_mac, + send_skb->len) < 0) { kfree_skb(send_skb); return; } diff --git a/net/decnet/dn_neigh.c b/net/decnet/dn_neigh.c index a424a8ddbaf..b66e3be3eb8 100644 --- a/net/decnet/dn_neigh.c +++ b/net/decnet/dn_neigh.c @@ -211,7 +211,8 @@ static int dn_neigh_output_packet(struct sk_buff *skb) char mac_addr[ETH_ALEN]; dn_dn2eth(mac_addr, rt->rt_local_src); - if (!dev->hard_header || dev->hard_header(skb, dev, ntohs(skb->protocol), neigh->ha, mac_addr, skb->len) >= 0) + if (dev_hard_header(skb, dev, ntohs(skb->protocol), neigh->ha, + mac_addr, skb->len) >= 0) return neigh->ops->queue_xmit(skb); if (net_ratelimit()) diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c index 9938e76a8ff..9cae16b4e0b 100644 --- a/net/econet/af_econet.c +++ b/net/econet/af_econet.c @@ -336,6 +336,7 @@ static int econet_sendmsg(struct kiocb *iocb, struct socket *sock, /* Real hardware Econet. We're not worthy etc. */ #ifdef CONFIG_ECONET_NATIVE unsigned short proto = 0; + int res; dev_hold(dev); @@ -354,12 +355,12 @@ static int econet_sendmsg(struct kiocb *iocb, struct socket *sock, eb->sec = *saddr; eb->sent = ec_tx_done; - if (dev->hard_header) { - int res; + err = -EINVAL; + res = dev_hard_header(skb, dev, ntohs(proto), &addr, NULL, len); + if (res < 0) + goto out_free; + if (res > 0) { struct ec_framehdr *fh; - err = -EINVAL; - res = dev->hard_header(skb, dev, ntohs(proto), - &addr, NULL, len); /* Poke in our control byte and port number. Hack, hack. */ fh = (struct ec_framehdr *)(skb->data); @@ -368,8 +369,7 @@ static int econet_sendmsg(struct kiocb *iocb, struct socket *sock, if (sock->type != SOCK_DGRAM) { skb_reset_tail_pointer(skb); skb->len = 0; - } else if (res < 0) - goto out_free; + } } /* Copy the data. Returns -EFAULT on error */ diff --git a/net/ethernet/pe2.c b/net/ethernet/pe2.c index 9d57b4fb644..d60e15d9365 100644 --- a/net/ethernet/pe2.c +++ b/net/ethernet/pe2.c @@ -12,9 +12,7 @@ static int pEII_request(struct datalink_proto *dl, struct net_device *dev = skb->dev; skb->protocol = htons(ETH_P_IPX); - if (dev->hard_header) - dev->hard_header(skb, dev, ETH_P_IPX, - dest_node, NULL, skb->len); + dev_hard_header(skb, dev, ETH_P_IPX, dest_node, NULL, skb->len); return dev_queue_xmit(skb); } diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 3a683006d76..5b24c65b13c 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -591,8 +591,7 @@ struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip, /* * Fill the device header for the ARP frame */ - if (dev->hard_header && - dev->hard_header(skb,dev,ptype,dest_hw,src_hw,skb->len) < 0) + if (dev_hard_header(skb, dev, ptype, dest_hw, src_hw, skb->len) < 0) goto out; /* diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index af5d5b39fc1..c5c107a0182 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -757,8 +757,8 @@ static void __init ic_bootp_send_if(struct ic_device *d, unsigned long jiffies_d /* Chain packet down the line... */ skb->dev = dev; skb->protocol = htons(ETH_P_IP); - if ((dev->hard_header && - dev->hard_header(skb, dev, ntohs(skb->protocol), dev->broadcast, dev->dev_addr, skb->len) < 0) || + if (dev_hard_header(skb, dev, ntohs(skb->protocol), + dev->broadcast, dev->dev_addr, skb->len) < 0 || dev_queue_xmit(skb) < 0) printk("E"); } diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 86d908b1cae..8668ab3af32 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -1438,17 +1438,12 @@ static struct sk_buff *mld_newpack(struct net_device *dev, int size) static inline int mld_dev_queue_xmit2(struct sk_buff *skb) { struct net_device *dev = skb->dev; + unsigned char ha[MAX_ADDR_LEN]; - if (dev->hard_header) { - unsigned char ha[MAX_ADDR_LEN]; - int err; - - ndisc_mc_map(&ipv6_hdr(skb)->daddr, ha, dev, 1); - err = dev->hard_header(skb, dev, ETH_P_IPV6, ha, NULL, skb->len); - if (err < 0) { - kfree_skb(skb); - return err; - } + ndisc_mc_map(&ipv6_hdr(skb)->daddr, ha, dev, 1); + if (dev_hard_header(skb, dev, ETH_P_IPV6, ha, NULL, skb->len) < 0) { + kfree_skb(skb); + return -EINVAL; } return dev_queue_xmit(skb); } diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 745e2cb87c9..c5244b30964 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -765,16 +765,10 @@ static int packet_sendmsg(struct kiocb *iocb, struct socket *sock, skb_reserve(skb, LL_RESERVED_SPACE(dev)); skb_reset_network_header(skb); - if (dev->hard_header) { - int res; - err = -EINVAL; - res = dev->hard_header(skb, dev, ntohs(proto), addr, NULL, len); - if (sock->type != SOCK_DGRAM) { - skb_reset_tail_pointer(skb); - skb->len = 0; - } else if (res < 0) - goto out_free; - } + err = -EINVAL; + if (sock->type == SOCK_DGRAM && + dev_hard_header(skb, dev, ntohs(proto), addr, NULL, len) < 0) + goto out_free; /* Returns -EFAULT on error */ err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len); diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c index 146f453d737..d13970f3c7b 100644 --- a/net/sched/sch_teql.c +++ b/net/sched/sch_teql.c @@ -232,9 +232,12 @@ __teql_resolve(struct sk_buff *skb, struct sk_buff *skb_res, struct net_device * } if (neigh_event_send(n, skb_res) == 0) { int err; + read_lock(&n->lock); - err = dev->hard_header(skb, dev, ntohs(skb->protocol), n->ha, NULL, skb->len); + err = dev_hard_header(skb, dev, ntohs(skb->protocol), + n->ha, NULL, skb->len); read_unlock(&n->lock); + if (err < 0) { neigh_release(n); return -EINVAL; diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c index 1a99e294714..3bbef2ab22a 100644 --- a/net/tipc/eth_media.c +++ b/net/tipc/eth_media.c @@ -77,7 +77,7 @@ static int send_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr, skb_reset_network_header(clone); dev = ((struct eth_bearer *)(tb_ptr->usr_handle))->dev; clone->dev = dev; - dev->hard_header(clone, dev, ETH_P_TIPC, + dev_hard_header(clone, dev, ETH_P_TIPC, &dest->dev_addr.eth_addr, dev->dev_addr, clone->len); dev_queue_xmit(clone); -- cgit v1.2.3-70-g09d2 From b95cce3576813ac3f86bafa6b5daaaaf7574b0fe Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 26 Sep 2007 22:13:38 -0700 Subject: [NET]: Wrap hard_header_parse Wrap the hard_header_parse function to simplify next step of header_ops conversion. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/ieee1394/eth1394.c | 10 +++++----- drivers/net/wireless/airo.c | 7 +------ drivers/s390/net/qeth_main.c | 6 +++--- include/linux/netdevice.h | 12 +++++++++++- net/ethernet/eth.c | 4 ++-- net/ipv4/netfilter/ip_queue.c | 6 ++---- net/ipv6/netfilter/ip6_queue.c | 5 +---- net/mac80211/ieee80211.c | 2 +- net/netfilter/nfnetlink_log.c | 11 ++++++----- net/netfilter/nfnetlink_queue.c | 13 ++++++------- net/packet/af_packet.c | 8 ++------ 11 files changed, 40 insertions(+), 44 deletions(-) (limited to 'drivers') diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c index 33b80817d68..b31f90082e3 100644 --- a/drivers/ieee1394/eth1394.c +++ b/drivers/ieee1394/eth1394.c @@ -162,7 +162,8 @@ static int ether1394_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned len); static int ether1394_rebuild_header(struct sk_buff *skb); -static int ether1394_header_parse(struct sk_buff *skb, unsigned char *haddr); +static int ether1394_header_parse(const struct sk_buff *skb, + unsigned char *haddr); static int ether1394_header_cache(struct neighbour *neigh, struct hh_cache *hh); static void ether1394_header_cache_update(struct hh_cache *hh, struct net_device *dev, @@ -751,11 +752,10 @@ static int ether1394_rebuild_header(struct sk_buff *skb) return 0; } -static int ether1394_header_parse(struct sk_buff *skb, unsigned char *haddr) +static int ether1394_header_parse(const struct sk_buff *skb, + unsigned char *haddr) { - struct net_device *dev = skb->dev; - - memcpy(haddr, dev->dev_addr, ETH1394_ALEN); + memcpy(haddr, skb->dev->dev_addr, ETH1394_ALEN); return ETH1394_ALEN; } diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 95d3cd1c49a..cd03a61359a 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -2481,7 +2481,7 @@ void stop_airo_card( struct net_device *dev, int freeres ) EXPORT_SYMBOL(stop_airo_card); -static int wll_header_parse(struct sk_buff *skb, unsigned char *haddr) +static int wll_header_parse(const struct sk_buff *skb, unsigned char *haddr) { memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); return ETH_ALEN; @@ -2698,11 +2698,6 @@ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci) static void wifi_setup(struct net_device *dev) { - dev->hard_header = NULL; - dev->rebuild_header = NULL; - dev->hard_header_cache = NULL; - dev->header_cache_update= NULL; - dev->hard_header_parse = wll_header_parse; dev->hard_start_xmit = &airo_start_xmit11; dev->get_stats = &airo_get_stats; diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index 8c46978e0af..65225b3989d 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c @@ -6561,10 +6561,10 @@ static struct ethtool_ops qeth_ethtool_ops = { }; static int -qeth_hard_header_parse(struct sk_buff *skb, unsigned char *haddr) +qeth_hard_header_parse(const struct sk_buff *skb, unsigned char *haddr) { - struct qeth_card *card; - struct ethhdr *eth; + const struct qeth_card *card; + const struct ethhdr *eth; card = qeth_get_card_from_dev(skb->dev); if (card->options.layer2) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index b33d084712f..aae9ec367f5 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -657,7 +657,7 @@ struct net_device void (*vlan_rx_kill_vid)(struct net_device *dev, unsigned short vid); - int (*hard_header_parse)(struct sk_buff *skb, + int (*hard_header_parse)(const struct sk_buff *skb, unsigned char *haddr); int (*neigh_setup)(struct net_device *dev, struct neigh_parms *); #ifdef CONFIG_NETPOLL @@ -809,6 +809,16 @@ static inline int dev_hard_header(struct sk_buff *skb, struct net_device *dev, return dev->hard_header(skb, dev, type, daddr, saddr, len); } +static inline int dev_parse_header(const struct sk_buff *skb, + unsigned char *haddr) +{ + const struct net_device *dev = skb->dev; + + if (!dev->hard_header_parse) + return 0; + return dev->hard_header_parse(skb, haddr); +} + typedef int gifconf_func_t(struct net_device * dev, char __user * bufptr, int len); extern int register_gifconf(unsigned int family, gifconf_func_t * gifconf); static inline int unregister_gifconf(unsigned int family) diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c index 2aaf6faf74a..bdeb2f0ace3 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c @@ -207,9 +207,9 @@ EXPORT_SYMBOL(eth_type_trans); * @skb: packet to extract header from * @haddr: destination buffer */ -static int eth_header_parse(struct sk_buff *skb, unsigned char *haddr) +static int eth_header_parse(const struct sk_buff *skb, unsigned char *haddr) { - struct ethhdr *eth = eth_hdr(skb); + const struct ethhdr *eth = eth_hdr(skb); memcpy(haddr, eth->h_source, ETH_ALEN); return ETH_ALEN; } diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index 82fda92e6b9..aaa3f5c5676 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c @@ -250,10 +250,8 @@ ipq_build_packet_message(struct ipq_queue_entry *entry, int *errp) if (entry->info->indev && entry->skb->dev) { pmsg->hw_type = entry->skb->dev->type; - if (entry->skb->dev->hard_header_parse) - pmsg->hw_addrlen = - entry->skb->dev->hard_header_parse(entry->skb, - pmsg->hw_addr); + pmsg->hw_addrlen = dev_parse_header(entry->skb, + pmsg->hw_addr); } if (data_len) diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index 2f5a5245383..c75f467a8f5 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c @@ -248,10 +248,7 @@ ipq_build_packet_message(struct ipq_queue_entry *entry, int *errp) if (entry->info->indev && entry->skb->dev) { pmsg->hw_type = entry->skb->dev->type; - if (entry->skb->dev->hard_header_parse) - pmsg->hw_addrlen = - entry->skb->dev->hard_header_parse(entry->skb, - pmsg->hw_addr); + pmsg->hw_addrlen = dev_parse_header(entry->skb, pmsg->hw_addr); } if (data_len) diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 89be6629cfc..0cdcf0d0c6c 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -47,7 +47,7 @@ struct ieee80211_tx_status_rtap_hdr { /* common interface routines */ -static int header_parse_80211(struct sk_buff *skb, unsigned char *haddr) +static int header_parse_80211(const struct sk_buff *skb, unsigned char *haddr) { memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */ return ETH_ALEN; diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index 8e4001b8f76..332e0f7f6f9 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c @@ -481,12 +481,13 @@ __build_packet_message(struct nfulnl_instance *inst, NFA_PUT(inst->skb, NFULA_MARK, sizeof(tmp_uint), &tmp_uint); } - if (indev && skb->dev && skb->dev->hard_header_parse) { + if (indev && skb->dev) { struct nfulnl_msg_packet_hw phw; - int len = skb->dev->hard_header_parse((struct sk_buff *)skb, - phw.hw_addr); - phw.hw_addrlen = htons(len); - NFA_PUT(inst->skb, NFULA_HWADDR, sizeof(phw), &phw); + int len = dev_parse_header(skb, phw.hw_addr); + if (len > 0) { + phw.hw_addrlen = htons(len); + NFA_PUT(inst->skb, NFULA_HWADDR, sizeof(phw), &phw); + } } if (skb->tstamp.tv64) { diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index c97369f48db..a813185c766 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -485,14 +485,13 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue, NFA_PUT(skb, NFQA_MARK, sizeof(u_int32_t), &tmp_uint); } - if (indev && entskb->dev - && entskb->dev->hard_header_parse) { + if (indev && entskb->dev) { struct nfqnl_msg_packet_hw phw; - - int len = entskb->dev->hard_header_parse(entskb, - phw.hw_addr); - phw.hw_addrlen = htons(len); - NFA_PUT(skb, NFQA_HWADDR, sizeof(phw), &phw); + int len = dev_parse_header(entskb, phw.hw_addr); + if (len) { + phw.hw_addrlen = htons(len); + NFA_PUT(skb, NFQA_HWADDR, sizeof(phw), &phw); + } } if (entskb->tstamp.tv64) { diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index c5244b30964..c9ee343c2a6 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -519,10 +519,8 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet sll->sll_ifindex = orig_dev->ifindex; else sll->sll_ifindex = dev->ifindex; - sll->sll_halen = 0; - if (dev->hard_header_parse) - sll->sll_halen = dev->hard_header_parse(skb, sll->sll_addr); + sll->sll_halen = dev_parse_header(skb, sll->sll_addr); PACKET_SKB_CB(skb)->origlen = skb->len; @@ -658,9 +656,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe h->tp_usec = tv.tv_usec; sll = (struct sockaddr_ll*)((u8*)h + TPACKET_ALIGN(sizeof(*h))); - sll->sll_halen = 0; - if (dev->hard_header_parse) - sll->sll_halen = dev->hard_header_parse(skb, sll->sll_addr); + sll->sll_halen = dev_parse_header(skb, sll->sll_addr); sll->sll_family = AF_PACKET; sll->sll_hatype = dev->type; sll->sll_protocol = skb->protocol; -- cgit v1.2.3-70-g09d2 From 3b04ddde02cf1b6f14f2697da5c20eca5715017f Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 9 Oct 2007 01:40:57 -0700 Subject: [NET]: Move hardware header operations out of netdevice. Since hardware header operations are part of the protocol class not the device instance, make them into a separate object and save memory. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/ieee1394/eth1394.c | 40 ++++++----- drivers/infiniband/ulp/ipoib/ipoib_main.c | 8 ++- drivers/isdn/i4l/isdn_net.c | 105 ++++++++++------------------- drivers/media/dvb/dvb-core/dvb_net.c | 9 ++- drivers/net/appletalk/cops.c | 20 +----- drivers/net/appletalk/ltpc.c | 10 --- drivers/net/arcnet/arcnet.c | 18 +++-- drivers/net/hamradio/6pack.c | 13 +++- drivers/net/hamradio/baycom_epp.c | 3 +- drivers/net/hamradio/bpqether.c | 3 +- drivers/net/hamradio/dmascc.c | 3 +- drivers/net/hamradio/hdlcdrv.c | 3 +- drivers/net/hamradio/mkiss.c | 14 ++-- drivers/net/hamradio/scc.c | 4 +- drivers/net/hamradio/yam.c | 3 +- drivers/net/loopback.c | 8 +-- drivers/net/macvlan.c | 15 ++++- drivers/net/myri_sbus.c | 28 +++++--- drivers/net/plip.c | 50 ++++++-------- drivers/net/shaper.c | 61 +++-------------- drivers/net/skfp/skfddi.c | 1 - drivers/net/wan/cycx_x25.c | 31 ++++++--- drivers/net/wan/dlci.c | 10 ++- drivers/net/wan/hdlc.c | 10 ++- drivers/net/wan/hdlc_cisco.c | 10 +-- drivers/net/wan/hdlc_ppp.c | 2 +- drivers/net/wan/lmc/lmc_proto.c | 2 +- drivers/net/wan/syncppp.c | 19 +++--- drivers/net/wireless/airo.c | 6 +- drivers/net/wireless/hostap/hostap.h | 3 +- drivers/net/wireless/hostap/hostap_hw.c | 3 +- drivers/net/wireless/hostap/hostap_ioctl.c | 5 +- drivers/net/wireless/hostap/hostap_main.c | 47 ++++++++----- drivers/net/wireless/hostap/hostap_wlan.h | 2 - drivers/net/wireless/strip.c | 13 ++-- drivers/s390/net/qeth.h | 3 +- drivers/s390/net/qeth_main.c | 44 +++++++----- include/linux/etherdevice.h | 20 +++--- include/linux/if_ether.h | 2 + include/linux/if_shaper.h | 11 --- include/linux/isdn.h | 7 -- include/linux/netdevice.h | 43 ++++++------ include/net/ax25.h | 5 +- include/net/pkt_sched.h | 5 +- net/802/fc.c | 11 +-- net/802/fddi.c | 10 ++- net/802/hippi.c | 16 +++-- net/802/tr.c | 15 +++-- net/8021q/vlan.c | 14 ++-- net/8021q/vlan.h | 4 +- net/8021q/vlan_dev.c | 4 +- net/appletalk/dev.c | 4 -- net/ax25/ax25_ip.c | 15 ++++- net/core/dev.c | 16 ----- net/core/neighbour.c | 11 +-- net/ethernet/eth.c | 36 ++++++---- net/ipv4/arp.c | 6 +- net/ipv4/ip_gre.c | 13 ++-- net/ipv4/ip_output.c | 2 +- net/ipv6/ndisc.c | 6 +- net/mac80211/ieee80211.c | 12 +++- net/netrom/nr_dev.c | 14 ++-- net/packet/af_packet.c | 6 +- net/rose/rose_dev.c | 13 ++-- net/sched/sch_teql.c | 6 +- 65 files changed, 481 insertions(+), 475 deletions(-) (limited to 'drivers') diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c index b31f90082e3..dc9dce22f6a 100644 --- a/drivers/ieee1394/eth1394.c +++ b/drivers/ieee1394/eth1394.c @@ -159,15 +159,16 @@ MODULE_PARM_DESC(max_partial_datagrams, static int ether1394_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, - unsigned len); + unsigned short type, const void *daddr, + const void *saddr, unsigned len); static int ether1394_rebuild_header(struct sk_buff *skb); static int ether1394_header_parse(const struct sk_buff *skb, unsigned char *haddr); -static int ether1394_header_cache(struct neighbour *neigh, struct hh_cache *hh); +static int ether1394_header_cache(const struct neighbour *neigh, + struct hh_cache *hh); static void ether1394_header_cache_update(struct hh_cache *hh, - struct net_device *dev, - unsigned char *haddr); + const struct net_device *dev, + const unsigned char *haddr); static int ether1394_tx(struct sk_buff *skb, struct net_device *dev); static void ether1394_iso(struct hpsb_iso *iso); @@ -507,6 +508,14 @@ static void ether1394_reset_priv(struct net_device *dev, int set_mtu) spin_unlock_irqrestore(&priv->lock, flags); } +static const struct header_ops ether1394_header_ops = { + .create = ether1394_header, + .rebuild = ether1394_rebuild_header, + .cache = ether1394_header_cache, + .cache_update = ether1394_header_cache_update, + .parse = ether1394_header_parse, +}; + static void ether1394_init_dev(struct net_device *dev) { dev->open = ether1394_open; @@ -516,11 +525,7 @@ static void ether1394_init_dev(struct net_device *dev) dev->tx_timeout = ether1394_tx_timeout; dev->change_mtu = ether1394_change_mtu; - dev->hard_header = ether1394_header; - dev->rebuild_header = ether1394_rebuild_header; - dev->hard_header_cache = ether1394_header_cache; - dev->header_cache_update= ether1394_header_cache_update; - dev->hard_header_parse = ether1394_header_parse; + dev->header_ops = ðer1394_header_ops; SET_ETHTOOL_OPS(dev, ðtool_ops); @@ -711,8 +716,8 @@ static void ether1394_host_reset(struct hpsb_host *host) * saddr=NULL means use device source address * daddr=NULL means leave destination address (eg unresolved arp). */ static int ether1394_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, - unsigned len) + unsigned short type, const void *daddr, + const void *saddr, unsigned len) { struct eth1394hdr *eth = (struct eth1394hdr *)skb_push(skb, ETH1394_HLEN); @@ -759,7 +764,8 @@ static int ether1394_header_parse(const struct sk_buff *skb, return ETH1394_ALEN; } -static int ether1394_header_cache(struct neighbour *neigh, struct hh_cache *hh) +static int ether1394_header_cache(const struct neighbour *neigh, + struct hh_cache *hh) { unsigned short type = hh->hh_type; struct net_device *dev = neigh->dev; @@ -778,8 +784,8 @@ static int ether1394_header_cache(struct neighbour *neigh, struct hh_cache *hh) /* Called by Address Resolution module to notify changes in address. */ static void ether1394_header_cache_update(struct hh_cache *hh, - struct net_device *dev, - unsigned char * haddr) + const struct net_device *dev, + const unsigned char * haddr) { memcpy((u8 *)hh->hh_data + 16 - ETH1394_HLEN, haddr, dev->addr_len); } @@ -899,8 +905,8 @@ static u16 ether1394_parse_encap(struct sk_buff *skb, struct net_device *dev, } /* Now add the ethernet header. */ - if (dev->hard_header(skb, dev, ntohs(ether_type), &dest_hw, NULL, - skb->len) >= 0) + if (dev_hard_header(skb, dev, ntohs(ether_type), &dest_hw, NULL, + skb->len) >= 0) ret = ether1394_type_trans(skb, dev); return ret; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index b1c3d6cd8eb..2bd76ef5715 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -780,7 +780,7 @@ static void ipoib_timeout(struct net_device *dev) static int ipoib_hard_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, - void *daddr, void *saddr, unsigned len) + const void *daddr, const void *saddr, unsigned len) { struct ipoib_header *header; @@ -940,6 +940,10 @@ void ipoib_dev_cleanup(struct net_device *dev) priv->tx_ring = NULL; } +static const struct header_ops ipoib_header_ops = { + .create = ipoib_hard_header, +}; + static void ipoib_setup(struct net_device *dev) { struct ipoib_dev_priv *priv = netdev_priv(dev); @@ -950,7 +954,7 @@ static void ipoib_setup(struct net_device *dev) dev->hard_start_xmit = ipoib_start_xmit; dev->get_stats = ipoib_get_stats; dev->tx_timeout = ipoib_timeout; - dev->hard_header = ipoib_hard_header; + dev->header_ops = &ipoib_header_ops; dev->set_multicast_list = ipoib_set_mcast_list; dev->neigh_setup = ipoib_neigh_setup_dev; diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c index aa83277aba7..54546604656 100644 --- a/drivers/isdn/i4l/isdn_net.c +++ b/drivers/isdn/i4l/isdn_net.c @@ -1873,54 +1873,14 @@ isdn_net_rcv_skb(int idx, struct sk_buff *skb) return 0; } -static int -my_eth_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, - void *daddr, void *saddr, unsigned len) -{ - struct ethhdr *eth = (struct ethhdr *) skb_push(skb, ETH_HLEN); - - /* - * Set the protocol type. For a packet of type ETH_P_802_3 we - * put the length here instead. It is up to the 802.2 layer to - * carry protocol information. - */ - - if (type != ETH_P_802_3) - eth->h_proto = htons(type); - else - eth->h_proto = htons(len); - - /* - * Set the source hardware address. - */ - if (saddr) - memcpy(eth->h_source, saddr, dev->addr_len); - else - memcpy(eth->h_source, dev->dev_addr, dev->addr_len); - - /* - * Anyway, the loopback-device should never use this function... - */ - - if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) { - memset(eth->h_dest, 0, dev->addr_len); - return ETH_HLEN /*(dev->hard_header_len)*/; - } - if (daddr) { - memcpy(eth->h_dest, daddr, dev->addr_len); - return ETH_HLEN /*dev->hard_header_len*/; - } - return -ETH_HLEN /*dev->hard_header_len*/; -} - /* * build an header * depends on encaps that is being used. */ -static int -isdn_net_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, - void *daddr, void *saddr, unsigned plen) +static int isdn_net_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, + const void *daddr, const void *saddr, unsigned plen) { isdn_net_local *lp = dev->priv; unsigned char *p; @@ -1928,7 +1888,7 @@ isdn_net_header(struct sk_buff *skb, struct net_device *dev, unsigned short type switch (lp->p_encap) { case ISDN_NET_ENCAP_ETHER: - len = my_eth_header(skb, dev, type, daddr, saddr, plen); + len = eth_header(skb, dev, type, daddr, saddr, plen); break; #ifdef CONFIG_ISDN_PPP case ISDN_NET_ENCAP_SYNCPPP: @@ -2005,6 +1965,32 @@ isdn_net_rebuild_header(struct sk_buff *skb) return ret; } +static int isdn_header_cache(const struct neighbour *neigh, struct hh_cache *hh) +{ + const struct net_device *dev = neigh->dev; + isdn_net_local *lp = dev->priv; + + if (lp->p_encap == ISDN_NET_ENCAP_ETHER) + return eth_header_cache(neigh, hh); + return -1; +} + +static void isdn_header_cache_update(struct hh_cache *hh, + const struct net_device *dev, + const unsigned char *haddr) +{ + isdn_net_local *lp = dev->priv; + if (lp->p_encap == ISDN_NET_ENCAP_ETHER) + return eth_header_cache_update(hh, dev, haddr); +} + +static const struct header_ops isdn_header_ops = { + .create = isdn_net_header, + .rebuild = isdn_net_rebuild_header, + .cache = isdn_header_cache, + .cache_update = isdn_header_cache_update, +}; + /* * Interface-setup. (just after registering a new interface) */ @@ -2012,18 +1998,12 @@ static int isdn_net_init(struct net_device *ndev) { ushort max_hlhdr_len = 0; - isdn_net_local *lp = (isdn_net_local *) ndev->priv; - int drvidx, i; + int drvidx; ether_setup(ndev); - lp->org_hhc = ndev->hard_header_cache; - lp->org_hcu = ndev->header_cache_update; + ndev->header_ops = NULL; /* Setup the generic properties */ - - ndev->hard_header = NULL; - ndev->hard_header_cache = NULL; - ndev->header_cache_update = NULL; ndev->mtu = 1500; ndev->flags = IFF_NOARP|IFF_POINTOPOINT; ndev->type = ARPHRD_ETHER; @@ -2032,9 +2012,6 @@ isdn_net_init(struct net_device *ndev) /* for clients with MPPP maybe higher values better */ ndev->tx_queue_len = 30; - for (i = 0; i < ETH_ALEN; i++) - ndev->broadcast[i] = 0xff; - /* The ISDN-specific entries in the device structure. */ ndev->open = &isdn_net_open; ndev->hard_start_xmit = &isdn_net_start_xmit; @@ -2052,7 +2029,6 @@ isdn_net_init(struct net_device *ndev) ndev->hard_header_len = ETH_HLEN + max_hlhdr_len; ndev->stop = &isdn_net_close; ndev->get_stats = &isdn_net_get_stats; - ndev->rebuild_header = &isdn_net_rebuild_header; ndev->do_ioctl = NULL; return 0; } @@ -2861,21 +2837,14 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg) } if (cfg->p_encap != lp->p_encap) { if (cfg->p_encap == ISDN_NET_ENCAP_RAWIP) { - p->dev.hard_header = NULL; - p->dev.hard_header_cache = NULL; - p->dev.header_cache_update = NULL; + p->dev.header_ops = NULL; p->dev.flags = IFF_NOARP|IFF_POINTOPOINT; } else { - p->dev.hard_header = isdn_net_header; - if (cfg->p_encap == ISDN_NET_ENCAP_ETHER) { - p->dev.hard_header_cache = lp->org_hhc; - p->dev.header_cache_update = lp->org_hcu; + p->dev.header_ops = &isdn_header_ops; + if (cfg->p_encap == ISDN_NET_ENCAP_ETHER) p->dev.flags = IFF_BROADCAST | IFF_MULTICAST; - } else { - p->dev.hard_header_cache = NULL; - p->dev.header_cache_update = NULL; + else p->dev.flags = IFF_NOARP|IFF_POINTOPOINT; - } } } lp->p_encap = cfg->p_encap; @@ -3127,8 +3096,6 @@ isdn_net_realrm(isdn_net_dev * p, isdn_net_dev * q) ((isdn_net_local *) (p->local->master->priv))->slave = p->local->slave; } else { /* Unregister only if it's a master-device */ - p->dev.hard_header_cache = p->local->org_hhc; - p->dev.header_cache_update = p->local->org_hcu; unregister_netdev(&p->dev); } /* Unlink device from chain */ diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c index bdd797071cb..06800e5a077 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ b/drivers/media/dvb/dvb-core/dvb_net.c @@ -1225,10 +1225,17 @@ static struct net_device_stats * dvb_net_get_stats(struct net_device *dev) return &((struct dvb_net_priv*) dev->priv)->stats; } +static const struct header_ops dvb_header_ops = { + .create = eth_header, + .parse = eth_header_parse, + .rebuild = eth_rebuild_header, +}; + static void dvb_net_setup(struct net_device *dev) { ether_setup(dev); + dev->header_ops = &dvb_header_ops; dev->open = dvb_net_open; dev->stop = dvb_net_stop; dev->hard_start_xmit = dvb_net_tx; @@ -1237,7 +1244,7 @@ static void dvb_net_setup(struct net_device *dev) dev->set_mac_address = dvb_net_set_mac; dev->mtu = 4096; dev->mc_count = 0; - dev->hard_header_cache = NULL; + dev->flags |= IFF_NOARP; } diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c index c4b560d42a6..92c3a4cf0bb 100644 --- a/drivers/net/appletalk/cops.c +++ b/drivers/net/appletalk/cops.c @@ -194,10 +194,6 @@ static void cops_timeout(struct net_device *dev); static void cops_rx (struct net_device *dev); static int cops_send_packet (struct sk_buff *skb, struct net_device *dev); static void set_multicast_list (struct net_device *dev); -static int cops_hard_header (struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, - unsigned len); - static int cops_ioctl (struct net_device *dev, struct ifreq *rq, int cmd); static int cops_close (struct net_device *dev); static struct net_device_stats *cops_get_stats (struct net_device *dev); @@ -331,7 +327,6 @@ static int __init cops_probe1(struct net_device *dev, int ioaddr) dev->base_addr = ioaddr; lp = netdev_priv(dev); - memset(lp, 0, sizeof(struct cops_local)); spin_lock_init(&lp->lock); /* Copy local board variable to lp struct. */ @@ -340,7 +335,7 @@ static int __init cops_probe1(struct net_device *dev, int ioaddr) dev->hard_start_xmit = cops_send_packet; dev->tx_timeout = cops_timeout; dev->watchdog_timeo = HZ * 2; - dev->hard_header = cops_hard_header; + dev->get_stats = cops_get_stats; dev->open = cops_open; dev->stop = cops_close; @@ -944,19 +939,6 @@ static void set_multicast_list(struct net_device *dev) printk("%s: set_multicast_list executed\n", dev->name); } -/* - * Another Dummy function to keep the Appletalk layer happy. - */ - -static int cops_hard_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, - unsigned len) -{ - if(cops_debug >= 3) - printk("%s: cops_hard_header executed. Wow!\n", dev->name); - return 0; -} - /* * System ioctls for the COPS LocalTalk card. */ diff --git a/drivers/net/appletalk/ltpc.c b/drivers/net/appletalk/ltpc.c index cb4744e5690..6ab2c2d4d67 100644 --- a/drivers/net/appletalk/ltpc.c +++ b/drivers/net/appletalk/ltpc.c @@ -870,15 +870,6 @@ static void set_multicast_list(struct net_device *dev) /* Actually netatalk needs fixing! */ } -static int ltpc_hard_header (struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len) -{ - if(debug & DEBUG_VERBOSE) - printk("ltpc_hard_header called for device %s\n", - dev->name); - return 0; -} - static int ltpc_poll_counter; static void ltpc_poll(unsigned long l) @@ -1141,7 +1132,6 @@ struct net_device * __init ltpc_probe(void) /* Fill in the fields of the device structure with ethernet-generic values. */ dev->hard_start_xmit = ltpc_xmit; - dev->hard_header = ltpc_hard_header; dev->get_stats = ltpc_get_stats; /* add the ltpc-specific things */ diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c index 681e20b8466..c59c8067de9 100644 --- a/drivers/net/arcnet/arcnet.c +++ b/drivers/net/arcnet/arcnet.c @@ -102,8 +102,8 @@ static int arcnet_close(struct net_device *dev); static int arcnet_send_packet(struct sk_buff *skb, struct net_device *dev); static void arcnet_timeout(struct net_device *dev); static int arcnet_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, - unsigned len); + unsigned short type, const void *daddr, + const void *saddr, unsigned len); static int arcnet_rebuild_header(struct sk_buff *skb); static struct net_device_stats *arcnet_get_stats(struct net_device *dev); static int go_tx(struct net_device *dev); @@ -317,11 +317,17 @@ static int choose_mtu(void) return mtu == 65535 ? XMTU : mtu; } +static const struct header_ops arcnet_header_ops = { + .create = arcnet_header, + .rebuild = arcnet_rebuild_header, +}; + /* Setup a struct device for ARCnet. */ static void arcdev_setup(struct net_device *dev) { dev->type = ARPHRD_ARCNET; + dev->header_ops = &arcnet_header_ops; dev->hard_header_len = sizeof(struct archdr); dev->mtu = choose_mtu(); @@ -342,8 +348,6 @@ static void arcdev_setup(struct net_device *dev) dev->hard_start_xmit = arcnet_send_packet; dev->tx_timeout = arcnet_timeout; dev->get_stats = arcnet_get_stats; - dev->hard_header = arcnet_header; - dev->rebuild_header = arcnet_rebuild_header; } struct net_device *alloc_arcdev(char *name) @@ -488,10 +492,10 @@ static int arcnet_close(struct net_device *dev) static int arcnet_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, - unsigned len) + unsigned short type, const void *daddr, + const void *saddr, unsigned len) { - struct arcnet_local *lp = dev->priv; + const struct arcnet_local *lp = netdev_priv(dev); uint8_t _daddr, proto_num; struct ArcProto *proto; diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index 0a847326a5e..ecd156def03 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -288,7 +288,8 @@ static int sp_close(struct net_device *dev) /* Return the frame type ID */ static int sp_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len) + unsigned short type, const void *daddr, + const void *saddr, unsigned len) { #ifdef CONFIG_INET if (type != htons(ETH_P_AX25)) @@ -323,6 +324,11 @@ static int sp_rebuild_header(struct sk_buff *skb) #endif } +static const struct header_ops sp_header_ops = { + .create = sp_header, + .rebuild = sp_rebuild_header, +}; + static void sp_setup(struct net_device *dev) { /* Finish setting up the DEVICE info. */ @@ -331,14 +337,15 @@ static void sp_setup(struct net_device *dev) dev->open = sp_open_dev; dev->destructor = free_netdev; dev->stop = sp_close; - dev->hard_header = sp_header; + dev->get_stats = sp_get_stats; dev->set_mac_address = sp_set_mac_address; dev->hard_header_len = AX25_MAX_HEADER_LEN; + dev->header_ops = &sp_header_ops; + dev->addr_len = AX25_ADDR_LEN; dev->type = ARPHRD_AX25; dev->tx_queue_len = 10; - dev->rebuild_header = sp_rebuild_header; dev->tx_timeout = NULL; /* Only activated in AX.25 mode */ diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c index 355c6cf3d11..1a5a75acf73 100644 --- a/drivers/net/hamradio/baycom_epp.c +++ b/drivers/net/hamradio/baycom_epp.c @@ -1159,8 +1159,7 @@ static void baycom_probe(struct net_device *dev) /* Fill in the fields of the device structure */ bc->skb = NULL; - dev->hard_header = ax25_hard_header; - dev->rebuild_header = ax25_rebuild_header; + dev->header_ops = &ax25_header_ops; dev->set_mac_address = baycom_set_mac_address; dev->type = ARPHRD_AX25; /* AF_AX25 device */ diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index 4bff23e3b97..5ddf8b0c34f 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -483,8 +483,7 @@ static void bpq_setup(struct net_device *dev) dev->flags = 0; #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) - dev->hard_header = ax25_hard_header; - dev->rebuild_header = ax25_rebuild_header; + dev->header_ops = &ax25_header_ops; #endif dev->type = ARPHRD_AX25; diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c index 205f0967249..bc02e469480 100644 --- a/drivers/net/hamradio/dmascc.c +++ b/drivers/net/hamradio/dmascc.c @@ -581,8 +581,7 @@ static int __init setup_adapter(int card_base, int type, int n) dev->do_ioctl = scc_ioctl; dev->hard_start_xmit = scc_send_packet; dev->get_stats = scc_get_stats; - dev->hard_header = ax25_hard_header; - dev->rebuild_header = ax25_rebuild_header; + dev->header_ops = &ax25_header_ops; dev->set_mac_address = scc_set_mac_address; } if (register_netdev(info->dev[0])) { diff --git a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c index b33adc6a340..ae9629fa688 100644 --- a/drivers/net/hamradio/hdlcdrv.c +++ b/drivers/net/hamradio/hdlcdrv.c @@ -682,8 +682,7 @@ static void hdlcdrv_setup(struct net_device *dev) s->skb = NULL; - dev->hard_header = ax25_hard_header; - dev->rebuild_header = ax25_rebuild_header; + dev->header_ops = &ax25_header_ops; dev->set_mac_address = hdlcdrv_set_mac_address; dev->type = ARPHRD_AX25; /* AF_AX25 device */ diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index d08fbc39664..9e43c47691c 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -578,8 +578,9 @@ static int ax_open_dev(struct net_device *dev) #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) /* Return the frame type ID */ -static int ax_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, - void *daddr, void *saddr, unsigned len) +static int ax_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, const void *daddr, + const void *saddr, unsigned len) { #ifdef CONFIG_INET if (type != htons(ETH_P_AX25)) @@ -670,6 +671,11 @@ static struct net_device_stats *ax_get_stats(struct net_device *dev) return &ax->stats; } +static const struct header_ops ax_header_ops = { + .create = ax_header, + .rebuild = ax_rebuild_header, +}; + static void ax_setup(struct net_device *dev) { /* Finish setting up the DEVICE info. */ @@ -683,8 +689,8 @@ static void ax_setup(struct net_device *dev) dev->addr_len = 0; dev->type = ARPHRD_AX25; dev->tx_queue_len = 10; - dev->hard_header = ax_header; - dev->rebuild_header = ax_rebuild_header; + dev->header_ops = &ax_header_ops; + memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN); memcpy(dev->dev_addr, &ax25_defaddr, AX25_ADDR_LEN); diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c index 39b3b82aa4a..353d13e543c 100644 --- a/drivers/net/hamradio/scc.c +++ b/drivers/net/hamradio/scc.c @@ -1551,8 +1551,8 @@ static void scc_net_setup(struct net_device *dev) dev->stop = scc_net_close; dev->hard_start_xmit = scc_net_tx; - dev->hard_header = ax25_hard_header; - dev->rebuild_header = ax25_rebuild_header; + dev->header_ops = &ax25_header_ops; + dev->set_mac_address = scc_net_set_mac_address; dev->get_stats = scc_net_get_stats; dev->do_ioctl = scc_net_ioctl; diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c index 401724ddafc..1c942862a3f 100644 --- a/drivers/net/hamradio/yam.c +++ b/drivers/net/hamradio/yam.c @@ -1097,8 +1097,7 @@ static void yam_setup(struct net_device *dev) skb_queue_head_init(&yp->send_queue); - dev->hard_header = ax25_hard_header; - dev->rebuild_header = ax25_rebuild_header; + dev->header_ops = &ax25_header_ops; dev->set_mac_address = yam_set_mac_address; diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index f11120b7a3b..b6d4ae3ad50 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -221,22 +221,17 @@ static void loopback_dev_free(struct net_device *dev) } /* - * The loopback device is special. There is only one instance and - * it is statically allocated. Don't do this for other devices. + * The loopback device is special. There is only one instance. */ static void loopback_setup(struct net_device *dev) { dev->get_stats = &get_stats; dev->mtu = (16 * 1024) + 20 + 20 + 12; dev->hard_start_xmit = loopback_xmit; - dev->hard_header = eth_header; - dev->hard_header_cache = eth_header_cache; - dev->header_cache_update = eth_header_cache_update; dev->hard_header_len = ETH_HLEN; /* 14 */ dev->addr_len = ETH_ALEN; /* 6 */ dev->tx_queue_len = 0; dev->type = ARPHRD_LOOPBACK; /* 0x0001*/ - dev->rebuild_header = eth_rebuild_header; dev->flags = IFF_LOOPBACK; dev->features = NETIF_F_SG | NETIF_F_FRAGLIST #ifdef LOOPBACK_TSO @@ -247,6 +242,7 @@ static void loopback_setup(struct net_device *dev) | NETIF_F_LLTX | NETIF_F_NETNS_LOCAL, dev->ethtool_ops = &loopback_ethtool_ops; + dev->header_ops = ð_header_ops; dev->init = loopback_dev_init; dev->destructor = loopback_dev_free; } diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index a22087ca968..b7c81c874f7 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -164,8 +164,8 @@ static int macvlan_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) } static int macvlan_hard_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, - unsigned len) + unsigned short type, const void *daddr, + const void *saddr, unsigned len) { const struct macvlan_dev *vlan = netdev_priv(dev); struct net_device *lowerdev = vlan->lowerdev; @@ -174,6 +174,15 @@ static int macvlan_hard_header(struct sk_buff *skb, struct net_device *dev, saddr ? : dev->dev_addr, len); } +static const struct header_ops macvlan_hard_header_ops = { + .create = macvlan_hard_header, + .rebuild = eth_rebuild_header, + .parse = eth_header_parse, + .rebuild = eth_rebuild_header, + .cache = eth_header_cache, + .cache_update = eth_header_cache_update, +}; + static int macvlan_open(struct net_device *dev) { struct macvlan_dev *vlan = netdev_priv(dev); @@ -295,9 +304,9 @@ static void macvlan_setup(struct net_device *dev) dev->change_mtu = macvlan_change_mtu; dev->change_rx_flags = macvlan_change_rx_flags; dev->set_multicast_list = macvlan_set_multicast_list; - dev->hard_header = macvlan_hard_header; dev->hard_start_xmit = macvlan_hard_start_xmit; dev->destructor = free_netdev; + dev->header_ops = &macvlan_hard_header_ops, dev->ethtool_ops = &macvlan_ethtool_ops; dev->tx_queue_len = 0; } diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c index d68ee51c095..8d29319cc5c 100644 --- a/drivers/net/myri_sbus.c +++ b/drivers/net/myri_sbus.c @@ -676,8 +676,9 @@ static int myri_start_xmit(struct sk_buff *skb, struct net_device *dev) * saddr=NULL means use device source address * daddr=NULL means leave destination address (eg unresolved arp) */ -static int myri_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, - void *daddr, void *saddr, unsigned len) +static int myri_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, const void *daddr, + const void *saddr, unsigned len) { struct ethhdr *eth = (struct ethhdr *) skb_push(skb, ETH_HLEN); unsigned char *pad = (unsigned char *) skb_push(skb, MYRI_PAD_LEN); @@ -759,18 +760,18 @@ static int myri_rebuild_header(struct sk_buff *skb) return 0; } -int myri_header_cache(struct neighbour *neigh, struct hh_cache *hh) +static int myri_header_cache(const struct neighbour *neigh, struct hh_cache *hh) { unsigned short type = hh->hh_type; unsigned char *pad; struct ethhdr *eth; - struct net_device *dev = neigh->dev; + const struct net_device *dev = neigh->dev; pad = ((unsigned char *) hh->hh_data) + HH_DATA_OFF(sizeof(*eth) + MYRI_PAD_LEN); eth = (struct ethhdr *) (pad + MYRI_PAD_LEN); - if (type == __constant_htons(ETH_P_802_3)) + if (type == htons(ETH_P_802_3)) return -1; /* Refill MyriNet padding identifiers, this is just being anal. */ @@ -786,7 +787,9 @@ int myri_header_cache(struct neighbour *neigh, struct hh_cache *hh) /* Called by Address Resolution module to notify changes in address. */ -void myri_header_cache_update(struct hh_cache *hh, struct net_device *dev, unsigned char * haddr) +void myri_header_cache_update(struct hh_cache *hh, + const struct net_device *dev, + const unsigned char * haddr) { memcpy(((u8*)hh->hh_data) + HH_DATA_OFF(sizeof(struct ethhdr)), haddr, dev->addr_len); @@ -881,6 +884,13 @@ static void dump_eeprom(struct myri_eth *mp) } #endif +static const struct header_ops myri_header_ops = { + .create = myri_header, + .rebuild = myri_rebuild_header, + .cache = myri_header_cache, + .cache_update = myri_header_cache_update, +}; + static int __devinit myri_ether_init(struct sbus_dev *sdev) { static int num; @@ -1065,11 +1075,9 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev) dev->mtu = MYRINET_MTU; dev->change_mtu = myri_change_mtu; - dev->hard_header = myri_header; - dev->rebuild_header = myri_rebuild_header; + dev->header_ops = &myri_header_ops; + dev->hard_header_len = (ETH_HLEN + MYRI_PAD_LEN); - dev->hard_header_cache = myri_header_cache; - dev->header_cache_update= myri_header_cache_update; /* Load code onto the LANai. */ DET(("Loading LANAI firmware\n")); diff --git a/drivers/net/plip.c b/drivers/net/plip.c index c17d9ac9ff3..b5e9981d106 100644 --- a/drivers/net/plip.c +++ b/drivers/net/plip.c @@ -148,9 +148,9 @@ static void plip_interrupt(int irq, void *dev_id); /* Functions for DEV methods */ static int plip_tx_packet(struct sk_buff *skb, struct net_device *dev); static int plip_hard_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, - void *saddr, unsigned len); -static int plip_hard_header_cache(struct neighbour *neigh, + unsigned short type, const void *daddr, + const void *saddr, unsigned len); +static int plip_hard_header_cache(const struct neighbour *neigh, struct hh_cache *hh); static int plip_open(struct net_device *dev); static int plip_close(struct net_device *dev); @@ -219,11 +219,6 @@ struct net_local { int is_deferred; int port_owner; int should_relinquish; - int (*orig_hard_header)(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, - void *saddr, unsigned len); - int (*orig_hard_header_cache)(struct neighbour *neigh, - struct hh_cache *hh); spinlock_t lock; atomic_t kill_timer; struct semaphore killed_timer_sem; @@ -265,6 +260,11 @@ static inline unsigned char read_status (struct net_device *dev) return port->ops->read_status (port); } +static const struct header_ops plip_header_ops = { + .create = plip_hard_header, + .cache = plip_hard_header_cache, +}; + /* Entry point of PLIP driver. Probe the hardware, and register/initialize the driver. @@ -284,17 +284,12 @@ plip_init_netdev(struct net_device *dev) dev->open = plip_open; dev->stop = plip_close; dev->do_ioctl = plip_ioctl; - dev->header_cache_update = NULL; + dev->tx_queue_len = 10; dev->flags = IFF_POINTOPOINT|IFF_NOARP; memset(dev->dev_addr, 0xfc, ETH_ALEN); - /* Set the private structure */ - nl->orig_hard_header = dev->hard_header; - dev->hard_header = plip_hard_header; - - nl->orig_hard_header_cache = dev->hard_header_cache; - dev->hard_header_cache = plip_hard_header_cache; + dev->header_ops = &plip_header_ops; nl->port_owner = 0; @@ -993,14 +988,14 @@ plip_tx_packet(struct sk_buff *skb, struct net_device *dev) } static void -plip_rewrite_address(struct net_device *dev, struct ethhdr *eth) +plip_rewrite_address(const struct net_device *dev, struct ethhdr *eth) { - struct in_device *in_dev; + const struct in_device *in_dev = dev->ip_ptr; - if ((in_dev=dev->ip_ptr) != NULL) { + if (in_dev) { /* Any address will do - we take the first */ - struct in_ifaddr *ifa=in_dev->ifa_list; - if (ifa != NULL) { + const struct in_ifaddr *ifa = in_dev->ifa_list; + if (ifa) { memcpy(eth->h_source, dev->dev_addr, 6); memset(eth->h_dest, 0xfc, 2); memcpy(eth->h_dest+2, &ifa->ifa_address, 4); @@ -1010,26 +1005,25 @@ plip_rewrite_address(struct net_device *dev, struct ethhdr *eth) static int plip_hard_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, - void *saddr, unsigned len) + unsigned short type, const void *daddr, + const void *saddr, unsigned len) { - struct net_local *nl = netdev_priv(dev); int ret; - if ((ret = nl->orig_hard_header(skb, dev, type, daddr, saddr, len)) >= 0) + ret = eth_header(skb, dev, type, daddr, saddr, len); + if (ret >= 0) plip_rewrite_address (dev, (struct ethhdr *)skb->data); return ret; } -int plip_hard_header_cache(struct neighbour *neigh, +int plip_hard_header_cache(const struct neighbour *neigh, struct hh_cache *hh) { - struct net_local *nl = neigh->dev->priv; int ret; - if ((ret = nl->orig_hard_header_cache(neigh, hh)) == 0) - { + ret = eth_header_cache(neigh, hh); + if (ret == 0) { struct ethhdr *eth; eth = (struct ethhdr*)(((u8*)hh->hh_data) + diff --git a/drivers/net/shaper.c b/drivers/net/shaper.c index 315feba7dac..228f650250f 100644 --- a/drivers/net/shaper.c +++ b/drivers/net/shaper.c @@ -331,15 +331,16 @@ static int shaper_close(struct net_device *dev) */ static int shaper_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len) + unsigned short type, + const void *daddr, const void *saddr, unsigned len) { struct shaper *sh=dev->priv; int v; if(sh_debug) printk("Shaper header\n"); - skb->dev=sh->dev; - v=sh->hard_header(skb,sh->dev,type,daddr,saddr,len); - skb->dev=dev; + skb->dev = sh->dev; + v = dev_hard_header(skb, sh->dev, type, daddr, saddr, len); + skb->dev = dev; return v; } @@ -351,7 +352,7 @@ static int shaper_rebuild_header(struct sk_buff *skb) if(sh_debug) printk("Shaper rebuild header\n"); skb->dev=sh->dev; - v=sh->rebuild_header(skb); + v = sh->dev->header_ops->rebuild(skb); skb->dev=dev; return v; } @@ -415,51 +416,17 @@ static int shaper_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p) #endif +static const struct header_ops shaper_ops = { + .create = shaper_header, + .rebuild = shaper_rebuild_header, +}; + static int shaper_attach(struct net_device *shdev, struct shaper *sh, struct net_device *dev) { sh->dev = dev; - sh->hard_start_xmit=dev->hard_start_xmit; sh->get_stats=dev->get_stats; - if(dev->hard_header) - { - sh->hard_header=dev->hard_header; - shdev->hard_header = shaper_header; - } - else - shdev->hard_header = NULL; - if(dev->rebuild_header) - { - sh->rebuild_header = dev->rebuild_header; - shdev->rebuild_header = shaper_rebuild_header; - } - else - shdev->rebuild_header = NULL; - -#if 0 - if(dev->hard_header_cache) - { - sh->hard_header_cache = dev->hard_header_cache; - shdev->hard_header_cache= shaper_cache; - } - else - { - shdev->hard_header_cache= NULL; - } - - if(dev->header_cache_update) - { - sh->header_cache_update = dev->header_cache_update; - shdev->header_cache_update = shaper_cache_update; - } - else - shdev->header_cache_update= NULL; -#else - shdev->header_cache_update = NULL; - shdev->hard_header_cache = NULL; -#endif shdev->neigh_setup = shaper_neigh_setup_dev; - shdev->hard_header_len=dev->hard_header_len; shdev->type=dev->type; shdev->addr_len=dev->addr_len; @@ -542,12 +509,6 @@ static void __init shaper_setup(struct net_device *dev) * Handlers for when we attach to a device. */ - dev->hard_header = shaper_header; - dev->rebuild_header = shaper_rebuild_header; -#if 0 - dev->hard_header_cache = shaper_cache; - dev->header_cache_update= shaper_cache_update; -#endif dev->neigh_setup = shaper_neigh_setup_dev; dev->do_ioctl = shaper_ioctl; dev->hard_header_len = 0; diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c index ca508708229..7cf9b9f35de 100644 --- a/drivers/net/skfp/skfddi.c +++ b/drivers/net/skfp/skfddi.c @@ -260,7 +260,6 @@ static int skfp_init_one(struct pci_dev *pdev, dev->set_multicast_list = &skfp_ctl_set_multicast_list; dev->set_mac_address = &skfp_ctl_set_mac_address; dev->do_ioctl = &skfp_ioctl; - dev->header_cache_update = NULL; /* not supported */ SET_NETDEV_DEV(dev, &pdev->dev); diff --git a/drivers/net/wan/cycx_x25.c b/drivers/net/wan/cycx_x25.c index 46e053106d4..8a1778cf98d 100644 --- a/drivers/net/wan/cycx_x25.c +++ b/drivers/net/wan/cycx_x25.c @@ -131,14 +131,15 @@ static int cycx_wan_update(struct wan_device *wandev), cycx_wan_del_if(struct wan_device *wandev, struct net_device *dev); /* Network device interface */ -static int cycx_netdevice_init(struct net_device *dev), - cycx_netdevice_open(struct net_device *dev), - cycx_netdevice_stop(struct net_device *dev), - cycx_netdevice_hard_header(struct sk_buff *skb, - struct net_device *dev, u16 type, - void *daddr, void *saddr, unsigned len), - cycx_netdevice_rebuild_header(struct sk_buff *skb), - cycx_netdevice_hard_start_xmit(struct sk_buff *skb, +static int cycx_netdevice_init(struct net_device *dev); +static int cycx_netdevice_open(struct net_device *dev); +static int cycx_netdevice_stop(struct net_device *dev); +static int cycx_netdevice_hard_header(struct sk_buff *skb, + struct net_device *dev, u16 type, + const void *daddr, const void *saddr, + unsigned len); +static int cycx_netdevice_rebuild_header(struct sk_buff *skb); +static int cycx_netdevice_hard_start_xmit(struct sk_buff *skb, struct net_device *dev); static struct net_device_stats * @@ -468,7 +469,14 @@ static int cycx_wan_del_if(struct wan_device *wandev, struct net_device *dev) return 0; } + /* Network Device Interface */ + +static const struct header_ops cycx_header_ops = { + .create = cycx_netdevice_hard_header, + .rebuild = cycx_netdevice_rebuild_header, +}; + /* Initialize Linux network interface. * * This routine is called only once for each interface, during Linux network @@ -483,8 +491,8 @@ static int cycx_netdevice_init(struct net_device *dev) /* Initialize device driver entry points */ dev->open = cycx_netdevice_open; dev->stop = cycx_netdevice_stop; - dev->hard_header = cycx_netdevice_hard_header; - dev->rebuild_header = cycx_netdevice_rebuild_header; + dev->header_ops = &cycx_header_ops; + dev->hard_start_xmit = cycx_netdevice_hard_start_xmit; dev->get_stats = cycx_netdevice_get_stats; @@ -554,7 +562,8 @@ static int cycx_netdevice_stop(struct net_device *dev) * Return: media header length. */ static int cycx_netdevice_hard_header(struct sk_buff *skb, struct net_device *dev, u16 type, - void *daddr, void *saddr, unsigned len) + const void *daddr, const void *saddr, + unsigned len) { skb->protocol = type; diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c index bc12810157e..96b232446c0 100644 --- a/drivers/net/wan/dlci.c +++ b/drivers/net/wan/dlci.c @@ -66,8 +66,8 @@ static void dlci_setup(struct net_device *); */ static int dlci_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, - unsigned len) + unsigned short type, const void *daddr, + const void *saddr, unsigned len) { struct frhdr hdr; struct dlci_local *dlp; @@ -485,6 +485,10 @@ static int dlci_ioctl(unsigned int cmd, void __user *arg) return(err); } +static const struct header_ops dlci_header_ops = { + .create = dlci_header, +}; + static void dlci_setup(struct net_device *dev) { struct dlci_local *dlp = dev->priv; @@ -494,7 +498,7 @@ static void dlci_setup(struct net_device *dev) dev->stop = dlci_close; dev->do_ioctl = dlci_dev_ioctl; dev->hard_start_xmit = dlci_transmit; - dev->hard_header = dlci_header; + dev->header_ops = &dlci_header_ops; dev->get_stats = dlci_get_stats; dev->change_mtu = dlci_change_mtu; dev->destructor = free_netdev; diff --git a/drivers/net/wan/hdlc.c b/drivers/net/wan/hdlc.c index ee23b91f23d..d553e6f3285 100644 --- a/drivers/net/wan/hdlc.c +++ b/drivers/net/wan/hdlc.c @@ -232,6 +232,8 @@ int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) return -EINVAL; } +static const struct header_ops hdlc_null_ops; + static void hdlc_setup_dev(struct net_device *dev) { /* Re-init all variables changed by HDLC protocol drivers, @@ -243,13 +245,9 @@ static void hdlc_setup_dev(struct net_device *dev) dev->type = ARPHRD_RAWHDLC; dev->hard_header_len = 16; dev->addr_len = 0; - dev->hard_header = NULL; - dev->rebuild_header = NULL; - dev->set_mac_address = NULL; - dev->hard_header_cache = NULL; - dev->header_cache_update = NULL; + dev->header_ops = &hdlc_null_ops; + dev->change_mtu = hdlc_change_mtu; - dev->hard_header_parse = NULL; } static void hdlc_setup(struct net_device *dev) diff --git a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c index 9ec6cf2e510..038a6e748bb 100644 --- a/drivers/net/wan/hdlc_cisco.c +++ b/drivers/net/wan/hdlc_cisco.c @@ -74,7 +74,7 @@ static inline struct cisco_state * state(hdlc_device *hdlc) static int cisco_hard_header(struct sk_buff *skb, struct net_device *dev, - u16 type, void *daddr, void *saddr, + u16 type, const void *daddr, const void *saddr, unsigned int len) { struct hdlc_header *data; @@ -309,7 +309,6 @@ static void cisco_stop(struct net_device *dev) } - static struct hdlc_proto proto = { .start = cisco_start, .stop = cisco_stop, @@ -317,7 +316,10 @@ static struct hdlc_proto proto = { .ioctl = cisco_ioctl, .module = THIS_MODULE, }; - + +static const struct header_ops cisco_header_ops = { + .create = cisco_hard_header, +}; static int cisco_ioctl(struct net_device *dev, struct ifreq *ifr) { @@ -365,7 +367,7 @@ static int cisco_ioctl(struct net_device *dev, struct ifreq *ifr) memcpy(&state(hdlc)->settings, &new_settings, size); dev->hard_start_xmit = hdlc->xmit; - dev->hard_header = cisco_hard_header; + dev->header_ops = &cisco_header_ops; dev->type = ARPHRD_CISCO; netif_dormant_on(dev); return 0; diff --git a/drivers/net/wan/hdlc_ppp.c b/drivers/net/wan/hdlc_ppp.c index 4591437dd2f..3caeb528eac 100644 --- a/drivers/net/wan/hdlc_ppp.c +++ b/drivers/net/wan/hdlc_ppp.c @@ -73,7 +73,7 @@ static void ppp_close(struct net_device *dev) sppp_close(dev); sppp_detach(dev); - dev->rebuild_header = NULL; + dev->change_mtu = state(hdlc)->old_change_mtu; dev->mtu = HDLC_MAX_MTU; dev->hard_header_len = 16; diff --git a/drivers/net/wan/lmc/lmc_proto.c b/drivers/net/wan/lmc/lmc_proto.c index 31e1799571a..426c0678d98 100644 --- a/drivers/net/wan/lmc/lmc_proto.c +++ b/drivers/net/wan/lmc/lmc_proto.c @@ -111,7 +111,7 @@ void lmc_proto_attach(lmc_softc_t *sc) /*FOLD00*/ * They set a few basics because they don't use sync_ppp */ dev->flags |= IFF_POINTOPOINT; - dev->hard_header = NULL; + dev->hard_header_len = 0; dev->addr_len = 0; } diff --git a/drivers/net/wan/syncppp.c b/drivers/net/wan/syncppp.c index 5c71af6ea3a..232ecba5340 100644 --- a/drivers/net/wan/syncppp.c +++ b/drivers/net/wan/syncppp.c @@ -359,8 +359,10 @@ done: * Handle transmit packets. */ -static int sppp_hard_header(struct sk_buff *skb, struct net_device *dev, __u16 type, - void *daddr, void *saddr, unsigned int len) +static int sppp_hard_header(struct sk_buff *skb, + struct net_device *dev, __u16 type, + const void *daddr, const void *saddr, + unsigned int len) { struct sppp *sp = (struct sppp *)sppp_of(dev); struct ppp_header *h; @@ -392,10 +394,9 @@ static int sppp_hard_header(struct sk_buff *skb, struct net_device *dev, __u16 t return sizeof(struct ppp_header); } -static int sppp_rebuild_header(struct sk_buff *skb) -{ - return 0; -} +static const struct header_ops sppp_header_ops = { + .create = sppp_hard_header, +}; /* * Send keepalive packets, every 10 seconds. @@ -1098,8 +1099,8 @@ void sppp_attach(struct ppp_device *pd) * hard_start_xmit. */ - dev->hard_header = sppp_hard_header; - dev->rebuild_header = sppp_rebuild_header; + dev->header_ops = &sppp_header_ops; + dev->tx_queue_len = 10; dev->type = ARPHRD_HDLC; dev->addr_len = 0; @@ -1115,8 +1116,6 @@ void sppp_attach(struct ppp_device *pd) dev->stop = sppp_close; #endif dev->change_mtu = sppp_change_mtu; - dev->hard_header_cache = NULL; - dev->header_cache_update = NULL; dev->flags = IFF_MULTICAST|IFF_POINTOPOINT|IFF_NOARP; } diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index cd03a61359a..074055e18c5 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -2696,9 +2696,13 @@ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci) return rc; } +static const struct header_ops airo_header_ops = { + .parse = wll_header_parse, +}; + static void wifi_setup(struct net_device *dev) { - dev->hard_header_parse = wll_header_parse; + dev->header_ops = &airo_header_ops; dev->hard_start_xmit = &airo_start_xmit11; dev->get_stats = &airo_get_stats; dev->set_mac_address = &airo_set_mac_address; diff --git a/drivers/net/wireless/hostap/hostap.h b/drivers/net/wireless/hostap/hostap.h index ef37a75d550..951df83702f 100644 --- a/drivers/net/wireless/hostap/hostap.h +++ b/drivers/net/wireless/hostap/hostap.h @@ -30,8 +30,7 @@ void hostap_dump_rx_header(const char *name, const struct hfa384x_rx_frame *rx); void hostap_dump_tx_header(const char *name, const struct hfa384x_tx_frame *tx); -int hostap_80211_header_parse(struct sk_buff *skb, unsigned char *haddr); -int hostap_80211_prism_header_parse(struct sk_buff *skb, unsigned char *haddr); +extern const struct header_ops hostap_80211_ops; int hostap_80211_get_hdrlen(u16 fc); struct net_device_stats *hostap_get_stats(struct net_device *dev); void hostap_setup_dev(struct net_device *dev, local_info_t *local, diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c index 7fa7ab0a4b2..b20bb013d57 100644 --- a/drivers/net/wireless/hostap/hostap_hw.c +++ b/drivers/net/wireless/hostap/hostap_hw.c @@ -3258,11 +3258,10 @@ while (0) INIT_LIST_HEAD(&local->bss_list); hostap_setup_dev(dev, local, 1); - local->saved_eth_header_parse = dev->hard_header_parse; dev->hard_start_xmit = hostap_master_start_xmit; dev->type = ARPHRD_IEEE80211; - dev->hard_header_parse = hostap_80211_header_parse; + dev->header_ops = &hostap_80211_ops; rtnl_lock(); ret = dev_alloc_name(dev, "wifi%d"); diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c index 7036ecff5ec..40f516d42c5 100644 --- a/drivers/net/wireless/hostap/hostap_ioctl.c +++ b/drivers/net/wireless/hostap/hostap_ioctl.c @@ -897,11 +897,8 @@ static void hostap_monitor_set_type(local_info_t *local) if (local->monitor_type == PRISM2_MONITOR_PRISM || local->monitor_type == PRISM2_MONITOR_CAPHDR) { dev->type = ARPHRD_IEEE80211_PRISM; - dev->hard_header_parse = - hostap_80211_prism_header_parse; } else { dev->type = ARPHRD_IEEE80211; - dev->hard_header_parse = hostap_80211_header_parse; } } @@ -1141,7 +1138,7 @@ static int hostap_monitor_mode_disable(local_info_t *local) printk(KERN_DEBUG "%s: Disabling monitor mode\n", dev->name); dev->type = ARPHRD_ETHER; - dev->hard_header_parse = local->saved_eth_header_parse; + if (local->func->cmd(dev, HFA384X_CMDCODE_TEST | (HFA384X_TEST_STOP << 8), 0, NULL, NULL)) diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c index 4cb09d81b40..b75cf9205ce 100644 --- a/drivers/net/wireless/hostap/hostap_main.c +++ b/drivers/net/wireless/hostap/hostap_main.c @@ -594,24 +594,27 @@ void hostap_dump_tx_header(const char *name, const struct hfa384x_tx_frame *tx) } -int hostap_80211_header_parse(struct sk_buff *skb, unsigned char *haddr) +int hostap_80211_header_parse(const struct sk_buff *skb, unsigned char *haddr) { - memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */ - return ETH_ALEN; -} - + struct hostap_interface *iface = netdev_priv(skb->dev); + local_info_t *local = iface->local; + + if (local->monitor_type == PRISM2_MONITOR_PRISM || + local->monitor_type == PRISM2_MONITOR_CAPHDR) { + const unsigned char *mac = skb_mac_header(skb); + + if (*(u32 *)mac == LWNG_CAP_DID_BASE) { + memcpy(haddr, + mac + sizeof(struct linux_wlan_ng_prism_hdr) + 10, + ETH_ALEN); /* addr2 */ + } else { /* (*(u32 *)mac == htonl(LWNG_CAPHDR_VERSION)) */ + memcpy(haddr, + mac + sizeof(struct linux_wlan_ng_cap_hdr) + 10, + ETH_ALEN); /* addr2 */ + } + } else + memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */ -int hostap_80211_prism_header_parse(struct sk_buff *skb, unsigned char *haddr) -{ - const unsigned char *mac = skb_mac_header(skb); - - if (*(u32 *)mac == LWNG_CAP_DID_BASE) { - memcpy(haddr, mac + sizeof(struct linux_wlan_ng_prism_hdr) + 10, - ETH_ALEN); /* addr2 */ - } else { /* (*(u32 *)mac == htonl(LWNG_CAPHDR_VERSION)) */ - memcpy(haddr, mac + sizeof(struct linux_wlan_ng_cap_hdr) + 10, - ETH_ALEN); /* addr2 */ - } return ETH_ALEN; } @@ -843,6 +846,15 @@ static void prism2_tx_timeout(struct net_device *dev) local->func->schedule_reset(local); } +const struct header_ops hostap_80211_ops = { + .create = eth_header, + .rebuild = eth_rebuild_header, + .cache = eth_header_cache, + .cache_update = eth_header_cache_update, + + .parse = hostap_80211_header_parse, +}; +EXPORT_SYMBOL(hostap_80211_ops); void hostap_setup_dev(struct net_device *dev, local_info_t *local, int main_dev) @@ -883,7 +895,6 @@ void hostap_setup_dev(struct net_device *dev, local_info_t *local, netif_stop_queue(dev); } - static int hostap_enable_hostapd(local_info_t *local, int rtnl_locked) { struct net_device *dev = local->dev; @@ -901,7 +912,7 @@ static int hostap_enable_hostapd(local_info_t *local, int rtnl_locked) local->apdev->hard_start_xmit = hostap_mgmt_start_xmit; local->apdev->type = ARPHRD_IEEE80211; - local->apdev->hard_header_parse = hostap_80211_header_parse; + local->apdev->header_ops = &hostap_80211_ops; return 0; } diff --git a/drivers/net/wireless/hostap/hostap_wlan.h b/drivers/net/wireless/hostap/hostap_wlan.h index a42325c145b..c27b2c1c06a 100644 --- a/drivers/net/wireless/hostap/hostap_wlan.h +++ b/drivers/net/wireless/hostap/hostap_wlan.h @@ -736,8 +736,6 @@ struct local_info { PRISM2_MONITOR_80211 = 0, PRISM2_MONITOR_PRISM = 1, PRISM2_MONITOR_CAPHDR = 2 } monitor_type; - int (*saved_eth_header_parse)(struct sk_buff *skb, - unsigned char *haddr); int monitor_allow_fcserr; int hostapd; /* whether user space daemon, hostapd, is used for AP diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c index 404cd151231..4bd14b33186 100644 --- a/drivers/net/wireless/strip.c +++ b/drivers/net/wireless/strip.c @@ -1631,8 +1631,8 @@ static void strip_IdleTask(unsigned long parameter) */ static int strip_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, - unsigned len) + unsigned short type, const void *daddr, + const void *saddr, unsigned len) { struct strip *strip_info = netdev_priv(dev); STRIP_Header *header = (STRIP_Header *) skb_push(skb, sizeof(STRIP_Header)); @@ -2497,6 +2497,11 @@ static int strip_close_low(struct net_device *dev) return 0; } +static const struct header_ops strip_header_ops = { + .create = strip_header, + .rebuild = strip_rebuild_header, +}; + /* * This routine is called by DDI when the * (dynamically assigned) device is registered @@ -2531,8 +2536,8 @@ static void strip_dev_setup(struct net_device *dev) dev->open = strip_open_low; dev->stop = strip_close_low; dev->hard_start_xmit = strip_xmit; - dev->hard_header = strip_header; - dev->rebuild_header = strip_rebuild_header; + dev->header_ops = &strip_header_ops; + dev->set_mac_address = strip_set_mac_address; dev->get_stats = strip_get_stats; dev->change_mtu = strip_change_mtu; diff --git a/drivers/s390/net/qeth.h b/drivers/s390/net/qeth.h index 6d4959807ab..8c6b72d05b1 100644 --- a/drivers/s390/net/qeth.h +++ b/drivers/s390/net/qeth.h @@ -833,8 +833,7 @@ struct qeth_card { struct qeth_qdio_info qdio; struct qeth_perf_stats perf_stats; int use_hard_stop; - int (*orig_hard_header)(struct sk_buff *,struct net_device *, - unsigned short,void *,void *,unsigned); + const struct header_ops *orig_header_ops; struct qeth_osn_info osn_info; atomic_t force_alloc_skb; }; diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index 65225b3989d..778ddfb9907 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c @@ -160,6 +160,9 @@ qeth_set_multicast_list(struct net_device *); static void qeth_setadp_promisc_mode(struct qeth_card *); +static int +qeth_hard_header_parse(const struct sk_buff *skb, unsigned char *haddr); + static void qeth_notify_processes(void) { @@ -3787,8 +3790,8 @@ qeth_get_netdevice(enum qeth_card_types type, enum qeth_link_types linktype) /*hard_header fake function; used in case fake_ll is set */ static int qeth_fake_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, - unsigned len) + unsigned short type, const void *daddr, const void *saddr, + unsigned len) { if(dev->type == ARPHRD_IEEE802_TR){ struct trh_hdr *hdr; @@ -3811,6 +3814,11 @@ qeth_fake_header(struct sk_buff *skb, struct net_device *dev, } } +static const struct header_ops qeth_fake_ops = { + .create = qeth_fake_header, + .parse = qeth_hard_header_parse, +}; + static int qeth_send_packet(struct qeth_card *, struct sk_buff *); @@ -4649,7 +4657,7 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb) [qeth_get_priority_queue(card, skb, ipv, cast_type)]; if (!card->options.layer2) { ipv = qeth_get_ip_version(skb); - if ((card->dev->hard_header == qeth_fake_header) && ipv) { + if ((card->dev->header_ops == &qeth_fake_ops) && ipv) { new_skb = qeth_pskb_unshare(skb, GFP_ATOMIC); if (!new_skb) return -ENOMEM; @@ -6566,6 +6574,9 @@ qeth_hard_header_parse(const struct sk_buff *skb, unsigned char *haddr) const struct qeth_card *card; const struct ethhdr *eth; + if (dev->type != ARPHRD_IEEE802_TR) + return 0; + card = qeth_get_card_from_dev(skb->dev); if (card->options.layer2) goto haveheader; @@ -6596,6 +6607,10 @@ haveheader: return ETH_ALEN; } +static const struct header_ops qeth_null_ops = { + .parse = qeth_hard_header_parse, +}; + static int qeth_netdev_init(struct net_device *dev) { @@ -6620,12 +6635,8 @@ qeth_netdev_init(struct net_device *dev) dev->vlan_rx_kill_vid = qeth_vlan_rx_kill_vid; dev->vlan_rx_add_vid = qeth_vlan_rx_add_vid; #endif - if (qeth_get_netdev_flags(card) & IFF_NOARP) { - dev->rebuild_header = NULL; - dev->hard_header = NULL; - dev->header_cache_update = NULL; - dev->hard_header_cache = NULL; - } + dev->header_ops = &qeth_null_ops; + #ifdef CONFIG_QETH_IPV6 /*IPv6 address autoconfiguration stuff*/ if (!(card->info.unique_id & UNIQUE_ID_NOT_BY_CARD)) @@ -6633,11 +6644,8 @@ qeth_netdev_init(struct net_device *dev) #endif if (card->options.fake_ll && (qeth_get_netdev_flags(card) & IFF_NOARP)) - dev->hard_header = qeth_fake_header; - if (dev->type == ARPHRD_IEEE802_TR) - dev->hard_header_parse = NULL; - else - dev->hard_header_parse = qeth_hard_header_parse; + dev->header_ops = &qeth_fake_ops; + dev->set_mac_address = qeth_layer2_set_mac_address; dev->flags |= qeth_get_netdev_flags(card); if ((card->options.fake_broadcast) || @@ -6740,10 +6748,10 @@ retry: } /*network device will be recovered*/ if (card->dev) { - card->dev->hard_header = card->orig_hard_header; + card->dev->header_ops = card->orig_header_ops; if (card->options.fake_ll && (qeth_get_netdev_flags(card) & IFF_NOARP)) - card->dev->hard_header = qeth_fake_header; + card->dev->header_ops = &qeth_fake_ops; return 0; } /* at first set_online allocate netdev */ @@ -6757,7 +6765,7 @@ retry: goto out; } card->dev->priv = card; - card->orig_hard_header = card->dev->hard_header; + card->orig_header_ops = card->dev->header_ops; card->dev->type = qeth_get_arphdr_type(card->info.type, card->info.link_type); card->dev->init = qeth_netdev_init; @@ -8308,7 +8316,7 @@ qeth_arp_constructor(struct neighbour *neigh) if (card == NULL) goto out; if((card->options.layer2) || - (card->dev->hard_header == qeth_fake_header)) + (card->dev->header_ops == &qeth_fake_ops)) goto out; rcu_read_lock(); diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h index 6cdb97365e4..b7558ec81ed 100644 --- a/include/linux/etherdevice.h +++ b/include/linux/etherdevice.h @@ -29,15 +29,19 @@ #include #ifdef __KERNEL__ -extern int eth_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, - void *saddr, unsigned len); -extern int eth_rebuild_header(struct sk_buff *skb); extern __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev); -extern void eth_header_cache_update(struct hh_cache *hh, struct net_device *dev, - unsigned char * haddr); -extern int eth_header_cache(struct neighbour *neigh, - struct hh_cache *hh); +extern const struct header_ops eth_header_ops; + +extern int eth_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, + const void *daddr, const void *saddr, unsigned len); +extern int eth_rebuild_header(struct sk_buff *skb); +extern int eth_header_parse(const struct sk_buff *skb, unsigned char *haddr); +extern int eth_header_cache(const struct neighbour *neigh, struct hh_cache *hh); +extern void eth_header_cache_update(struct hh_cache *hh, + const struct net_device *dev, + const unsigned char *haddr); + extern struct net_device *alloc_etherdev_mq(int sizeof_priv, unsigned int queue_count); #define alloc_etherdev(sizeof_priv) alloc_etherdev_mq(sizeof_priv, 1) diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h index 0e791e2c0c5..5f929779366 100644 --- a/include/linux/if_ether.h +++ b/include/linux/if_ether.h @@ -117,6 +117,8 @@ static inline struct ethhdr *eth_hdr(const struct sk_buff *skb) return (struct ethhdr *)skb_mac_header(skb); } +int eth_header_parse(const struct sk_buff *skb, unsigned char *haddr); + #ifdef CONFIG_SYSCTL extern struct ctl_table ether_table[]; #endif diff --git a/include/linux/if_shaper.h b/include/linux/if_shaper.h index 51574743aa1..3b1b7ba1982 100644 --- a/include/linux/if_shaper.h +++ b/include/linux/if_shaper.h @@ -25,17 +25,6 @@ struct shaper an empty queue */ spinlock_t lock; struct net_device *dev; - int (*hard_start_xmit) (struct sk_buff *skb, - struct net_device *dev); - int (*hard_header) (struct sk_buff *skb, - struct net_device *dev, - unsigned short type, - void *daddr, - void *saddr, - unsigned len); - int (*rebuild_header)(struct sk_buff *skb); - int (*hard_header_cache)(struct neighbour *neigh, struct hh_cache *hh); - void (*header_cache_update)(struct hh_cache *hh, struct net_device *dev, unsigned char * haddr); struct net_device_stats* (*get_stats)(struct net_device *dev); struct timer_list timer; }; diff --git a/include/linux/isdn.h b/include/linux/isdn.h index 3c7875b7ab5..a6fb366748b 100644 --- a/include/linux/isdn.h +++ b/include/linux/isdn.h @@ -353,13 +353,6 @@ typedef struct isdn_net_local_s { /* a particular channel (including */ /* the frame_cnt */ - int (*org_hhc)( - struct neighbour *neigh, - struct hh_cache *hh); - /* Ptr to orig. header_cache_update */ - void (*org_hcu)(struct hh_cache *, - struct net_device *, - unsigned char *); int pppbind; /* ippp device for bindings */ int dialtimeout; /* How long shall we try on dialing? (jiffies) */ int dialwait; /* How long shall we wait after failed attempt? (jiffies) */ diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index aae9ec367f5..91cd3f3db50 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -250,6 +250,19 @@ struct hh_cache #define LL_RESERVED_SPACE_EXTRA(dev,extra) \ ((((dev)->hard_header_len+extra)&~(HH_DATA_MOD - 1)) + HH_DATA_MOD) +struct header_ops { + int (*create) (struct sk_buff *skb, struct net_device *dev, + unsigned short type, const void *daddr, + const void *saddr, unsigned len); + int (*parse)(const struct sk_buff *skb, unsigned char *haddr); + int (*rebuild)(struct sk_buff *skb); +#define HAVE_HEADER_CACHE + int (*cache)(const struct neighbour *neigh, struct hh_cache *hh); + void (*cache_update)(struct hh_cache *hh, + const struct net_device *dev, + const unsigned char *haddr); +}; + /* These flag bits are private to the generic network queueing * layer, they may not be explicitly referenced by any other * code. @@ -492,6 +505,9 @@ struct net_device #endif const struct ethtool_ops *ethtool_ops; + /* Hardware header description */ + const struct header_ops *header_ops; + /* * This marks the end of the "visible" part of the structure. All * fields hereafter are internal to the system, and may change at @@ -615,13 +631,6 @@ struct net_device int (*open)(struct net_device *dev); int (*stop)(struct net_device *dev); #define HAVE_NETDEV_POLL - int (*hard_header) (struct sk_buff *skb, - struct net_device *dev, - unsigned short type, - void *daddr, - void *saddr, - unsigned len); - int (*rebuild_header)(struct sk_buff *skb); #define HAVE_CHANGE_RX_FLAGS void (*change_rx_flags)(struct net_device *dev, int flags); @@ -638,12 +647,6 @@ struct net_device #define HAVE_SET_CONFIG int (*set_config)(struct net_device *dev, struct ifmap *map); -#define HAVE_HEADER_CACHE - int (*hard_header_cache)(struct neighbour *neigh, - struct hh_cache *hh); - void (*header_cache_update)(struct hh_cache *hh, - struct net_device *dev, - unsigned char * haddr); #define HAVE_CHANGE_MTU int (*change_mtu)(struct net_device *dev, int new_mtu); @@ -657,8 +660,6 @@ struct net_device void (*vlan_rx_kill_vid)(struct net_device *dev, unsigned short vid); - int (*hard_header_parse)(const struct sk_buff *skb, - unsigned char *haddr); int (*neigh_setup)(struct net_device *dev, struct neigh_parms *); #ifdef CONFIG_NETPOLL struct netpoll_info *npinfo; @@ -802,11 +803,13 @@ extern int netpoll_trap(void); static inline int dev_hard_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, - void *daddr, void *saddr, unsigned len) + const void *daddr, const void *saddr, + unsigned len) { - if (!dev->hard_header) + if (!dev->header_ops) return 0; - return dev->hard_header(skb, dev, type, daddr, saddr, len); + + return dev->header_ops->create(skb, dev, type, daddr, saddr, len); } static inline int dev_parse_header(const struct sk_buff *skb, @@ -814,9 +817,9 @@ static inline int dev_parse_header(const struct sk_buff *skb, { const struct net_device *dev = skb->dev; - if (!dev->hard_header_parse) + if (!dev->header_ops->parse) return 0; - return dev->hard_header_parse(skb, haddr); + return dev->header_ops->parse(skb, haddr); } typedef int gifconf_func_t(struct net_device * dev, char __user * bufptr, int len); diff --git a/include/net/ax25.h b/include/net/ax25.h index 99a4e364c74..4e3cd93f81f 100644 --- a/include/net/ax25.h +++ b/include/net/ax25.h @@ -363,8 +363,11 @@ extern int ax25_rx_iframe(ax25_cb *, struct sk_buff *); extern int ax25_kiss_rcv(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *); /* ax25_ip.c */ -extern int ax25_hard_header(struct sk_buff *, struct net_device *, unsigned short, void *, void *, unsigned int); +extern int ax25_hard_header(struct sk_buff *, struct net_device *, + unsigned short, const void *, + const void *, unsigned int); extern int ax25_rebuild_header(struct sk_buff *); +extern const struct header_ops ax25_header_ops; /* ax25_out.c */ extern ax25_cb *ax25_send_frame(struct sk_buff *, int, ax25_address *, ax25_address *, ax25_digi *, struct net_device *); diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h index 9e22526e80e..ab61809a961 100644 --- a/include/net/pkt_sched.h +++ b/include/net/pkt_sched.h @@ -97,10 +97,9 @@ extern int tc_classify(struct sk_buff *skb, struct tcf_proto *tp, /* Calculate maximal size of packet seen by hard_start_xmit routine of this device. */ -static inline unsigned psched_mtu(struct net_device *dev) +static inline unsigned psched_mtu(const struct net_device *dev) { - unsigned mtu = dev->mtu; - return dev->hard_header ? mtu + dev->hard_header_len : mtu; + return dev->mtu + dev->hard_header_len; } #endif diff --git a/net/802/fc.c b/net/802/fc.c index 675d9ba8e59..cb3475ea6fd 100644 --- a/net/802/fc.c +++ b/net/802/fc.c @@ -35,7 +35,7 @@ static int fc_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, - void *daddr, void *saddr, unsigned len) + const void *daddr, const void *saddr, unsigned len) { struct fch_hdr *fch; int hdr_len; @@ -95,11 +95,14 @@ static int fc_rebuild_header(struct sk_buff *skb) #endif } +static const struct header_ops fc_header_ops = { + .create = fc_header, + .rebuild = fc_rebuild_header, +}; + static void fc_setup(struct net_device *dev) { - dev->hard_header = fc_header; - dev->rebuild_header = fc_rebuild_header; - + dev->header_ops = &fc_header_ops; dev->type = ARPHRD_IEEE802; dev->hard_header_len = FC_HLEN; dev->mtu = 2024; diff --git a/net/802/fddi.c b/net/802/fddi.c index 91dde41b548..0549317b935 100644 --- a/net/802/fddi.c +++ b/net/802/fddi.c @@ -52,7 +52,7 @@ static int fddi_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, - void *daddr, void *saddr, unsigned len) + const void *daddr, const void *saddr, unsigned len) { int hl = FDDI_K_SNAP_HLEN; struct fddihdr *fddi; @@ -175,11 +175,15 @@ static int fddi_change_mtu(struct net_device *dev, int new_mtu) return(0); } +static const struct header_ops fddi_header_ops = { + .create = fddi_header, + .rebuild = fddi_rebuild_header, +}; + static void fddi_setup(struct net_device *dev) { dev->change_mtu = fddi_change_mtu; - dev->hard_header = fddi_header; - dev->rebuild_header = fddi_rebuild_header; + dev->header_ops = &fddi_header_ops; dev->type = ARPHRD_FDDI; dev->hard_header_len = FDDI_K_SNAP_HLEN+3; /* Assume 802.2 SNAP hdr len + 3 pad bytes */ diff --git a/net/802/hippi.c b/net/802/hippi.c index 87ffc12b689..e35dc1e0915 100644 --- a/net/802/hippi.c +++ b/net/802/hippi.c @@ -45,8 +45,8 @@ */ static int hippi_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, - unsigned len) + unsigned short type, + const void *daddr, const void *saddr, unsigned len) { struct hippi_hdr *hip = (struct hippi_hdr *)skb_push(skb, HIPPI_HLEN); struct hippi_cb *hcb = (struct hippi_cb *) skb->cb; @@ -182,16 +182,18 @@ static int hippi_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p) return 0; } +static const struct header_ops hippi_header_ops = { + .create = hippi_header, + .rebuild = hippi_rebuild_header, +}; + + static void hippi_setup(struct net_device *dev) { dev->set_multicast_list = NULL; dev->change_mtu = hippi_change_mtu; - dev->hard_header = hippi_header; - dev->rebuild_header = hippi_rebuild_header; + dev->header_ops = &hippi_header_ops; dev->set_mac_address = hippi_mac_addr; - dev->hard_header_parse = NULL; - dev->hard_header_cache = NULL; - dev->header_cache_update = NULL; dev->neigh_setup = hippi_neigh_setup_dev; /* diff --git a/net/802/tr.c b/net/802/tr.c index aa3c2e936ab..a2bd0f2e3af 100644 --- a/net/802/tr.c +++ b/net/802/tr.c @@ -100,7 +100,7 @@ static inline unsigned long rif_hash(const unsigned char *addr) static int tr_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, - void *daddr, void *saddr, unsigned len) + const void *daddr, const void *saddr, unsigned len) { struct trh_hdr *trh; int hdr_len; @@ -142,7 +142,7 @@ static int tr_header(struct sk_buff *skb, struct net_device *dev, if(daddr) { memcpy(trh->daddr,daddr,dev->addr_len); - tr_source_route(skb,trh,dev); + tr_source_route(skb, trh, dev); return(hdr_len); } @@ -247,7 +247,8 @@ __be16 tr_type_trans(struct sk_buff *skb, struct net_device *dev) * We try to do source routing... */ -void tr_source_route(struct sk_buff *skb,struct trh_hdr *trh,struct net_device *dev) +void tr_source_route(struct sk_buff *skb,struct trh_hdr *trh, + struct net_device *dev) { int slack; unsigned int hash; @@ -592,14 +593,18 @@ static const struct file_operations rif_seq_fops = { #endif +static const struct header_ops tr_header_ops = { + .create = tr_header, + .rebuild= tr_rebuild_header, +}; + static void tr_setup(struct net_device *dev) { /* * Configure and register */ - dev->hard_header = tr_header; - dev->rebuild_header = tr_rebuild_header; + dev->header_ops = &tr_header_ops; dev->type = ARPHRD_IEEE802_TR; dev->hard_header_len = TR_HLEN; diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 4d003e39175..f2bee234d36 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -314,6 +314,12 @@ int unregister_vlan_device(struct net_device *dev) */ static struct lock_class_key vlan_netdev_xmit_lock_key; +static const struct header_ops vlan_header_ops = { + .create = vlan_dev_hard_header, + .rebuild = vlan_dev_rebuild_header, + .parse = eth_header_parse, +}; + static int vlan_dev_init(struct net_device *dev) { struct net_device *real_dev = VLAN_DEV_INFO(dev)->real_dev; @@ -331,18 +337,14 @@ static int vlan_dev_init(struct net_device *dev) memcpy(dev->broadcast, real_dev->broadcast, dev->addr_len); if (real_dev->features & NETIF_F_HW_VLAN_TX) { - dev->hard_header = real_dev->hard_header; + dev->header_ops = real_dev->header_ops; dev->hard_header_len = real_dev->hard_header_len; dev->hard_start_xmit = vlan_dev_hwaccel_hard_start_xmit; - dev->rebuild_header = real_dev->rebuild_header; } else { - dev->hard_header = vlan_dev_hard_header; + dev->header_ops = &vlan_header_ops; dev->hard_header_len = real_dev->hard_header_len + VLAN_HLEN; dev->hard_start_xmit = vlan_dev_hard_start_xmit; - dev->rebuild_header = vlan_dev_rebuild_header; } - dev->hard_header_parse = real_dev->hard_header_parse; - dev->hard_header_cache = NULL; lockdep_set_class(&dev->_xmit_lock, &vlan_netdev_xmit_lock_key); return 0; diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h index 7df5b293557..cf4a80d06b3 100644 --- a/net/8021q/vlan.h +++ b/net/8021q/vlan.h @@ -53,8 +53,8 @@ int vlan_dev_rebuild_header(struct sk_buff *skb); int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptype, struct net_device *orig_dev); int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, - unsigned len); + unsigned short type, const void *daddr, + const void *saddr, unsigned len); int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev); int vlan_dev_hwaccel_hard_start_xmit(struct sk_buff *skb, struct net_device *dev); int vlan_dev_change_mtu(struct net_device *dev, int new_mtu); diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index ca8090fdabb..1a1740aa9a8 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -343,8 +343,8 @@ static inline unsigned short vlan_dev_get_egress_qos_mask(struct net_device* dev * physical devices. */ int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, - unsigned len) + unsigned short type, + const void *daddr, const void *saddr, unsigned len) { struct vlan_hdr *vhdr; unsigned short veth_TCI = 0; diff --git a/net/appletalk/dev.c b/net/appletalk/dev.c index 9e4dffc1e42..d856a62ab50 100644 --- a/net/appletalk/dev.c +++ b/net/appletalk/dev.c @@ -24,11 +24,7 @@ static void ltalk_setup(struct net_device *dev) /* Fill in the fields of the device structure with localtalk-generic values. */ dev->change_mtu = ltalk_change_mtu; - dev->hard_header = NULL; - dev->rebuild_header = NULL; dev->set_mac_address = ltalk_mac_addr; - dev->hard_header_cache = NULL; - dev->header_cache_update= NULL; dev->type = ARPHRD_LOCALTLK; dev->hard_header_len = LTALK_HLEN; diff --git a/net/ax25/ax25_ip.c b/net/ax25/ax25_ip.c index 930e4918037..f047a57aa95 100644 --- a/net/ax25/ax25_ip.c +++ b/net/ax25/ax25_ip.c @@ -46,7 +46,9 @@ #ifdef CONFIG_INET -int ax25_hard_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned len) +int ax25_hard_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, const void *daddr, + const void *saddr, unsigned len) { unsigned char *buff; @@ -215,7 +217,9 @@ put: #else /* INET */ -int ax25_hard_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned len) +int ax25_hard_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, const void *daddr, + const void *saddr, unsigned len) { return -AX25_HEADER_LEN; } @@ -227,5 +231,12 @@ int ax25_rebuild_header(struct sk_buff *skb) #endif +const struct header_ops ax25_header_ops = { + .create = ax25_hard_header, + .rebuild = ax25_rebuild_header, +}; + EXPORT_SYMBOL(ax25_hard_header); EXPORT_SYMBOL(ax25_rebuild_header); +EXPORT_SYMBOL(ax25_header_ops); + diff --git a/net/core/dev.c b/net/core/dev.c index 3923d513305..d9986466258 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -967,14 +967,6 @@ void dev_load(struct net *net, const char *name) request_module("%s", name); } -static int default_rebuild_header(struct sk_buff *skb) -{ - printk(KERN_DEBUG "%s: default_rebuild_header called -- BUG!\n", - skb->dev ? skb->dev->name : "NULL!!!"); - kfree_skb(skb); - return 1; -} - /** * dev_open - prepare an interface for use. * @dev: device to open @@ -3561,14 +3553,6 @@ int register_netdevice(struct net_device *dev) } } - /* - * nil rebuild_header routine, - * that should be never called and used as just bug trap. - */ - - if (!dev->rebuild_header) - dev->rebuild_header = default_rebuild_header; - ret = netdev_register_kobject(dev); if (ret) goto err_uninit; diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 10bcb9f8da5..c52df858d0b 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -897,8 +897,8 @@ out_unlock_bh: static void neigh_update_hhs(struct neighbour *neigh) { struct hh_cache *hh; - void (*update)(struct hh_cache*, struct net_device*, unsigned char *) = - neigh->dev->header_cache_update; + void (*update)(struct hh_cache*, const struct net_device*, const unsigned char *) + = neigh->dev->header_ops->cache_update; if (update) { for (hh = neigh->hh; hh; hh = hh->hh_next) { @@ -1095,7 +1095,8 @@ static void neigh_hh_init(struct neighbour *n, struct dst_entry *dst, hh->hh_type = protocol; atomic_set(&hh->hh_refcnt, 0); hh->hh_next = NULL; - if (dev->hard_header_cache(n, hh)) { + + if (dev->header_ops->cache(n, hh)) { kfree(hh); hh = NULL; } else { @@ -1127,7 +1128,7 @@ int neigh_compat_output(struct sk_buff *skb) if (dev_hard_header(skb, dev, ntohs(skb->protocol), NULL, NULL, skb->len) < 0 && - dev->rebuild_header(skb)) + dev->header_ops->rebuild(skb)) return 0; return dev_queue_xmit(skb); @@ -1149,7 +1150,7 @@ int neigh_resolve_output(struct sk_buff *skb) if (!neigh_event_send(neigh, skb)) { int err; struct net_device *dev = neigh->dev; - if (dev->hard_header_cache && !dst->hh) { + if (dev->header_ops->cache && !dst->hh) { write_lock_bh(&neigh->lock); if (!dst->hh) neigh_hh_init(neigh, dst, dst->ops->protocol); diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c index bdeb2f0ace3..ed8a3d49487 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c @@ -75,8 +75,9 @@ __setup("ether=", netdev_boot_setup); * Set the protocol type. For a packet of type ETH_P_802_3 we put the length * in here instead. It is up to the 802.2 layer to carry protocol information. */ -int eth_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, - void *daddr, void *saddr, unsigned len) +int eth_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, + const void *daddr, const void *saddr, unsigned len) { struct ethhdr *eth = (struct ethhdr *)skb_push(skb, ETH_HLEN); @@ -109,6 +110,7 @@ int eth_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, return -ETH_HLEN; } +EXPORT_SYMBOL(eth_header); /** * eth_rebuild_header- rebuild the Ethernet MAC header. @@ -141,6 +143,7 @@ int eth_rebuild_header(struct sk_buff *skb) return 0; } +EXPORT_SYMBOL(eth_rebuild_header); /** * eth_type_trans - determine the packet's protocol ID. @@ -207,12 +210,13 @@ EXPORT_SYMBOL(eth_type_trans); * @skb: packet to extract header from * @haddr: destination buffer */ -static int eth_header_parse(const struct sk_buff *skb, unsigned char *haddr) +int eth_header_parse(const struct sk_buff *skb, unsigned char *haddr) { const struct ethhdr *eth = eth_hdr(skb); memcpy(haddr, eth->h_source, ETH_ALEN); return ETH_ALEN; } +EXPORT_SYMBOL(eth_header_parse); /** * eth_header_cache - fill cache entry from neighbour @@ -220,11 +224,11 @@ static int eth_header_parse(const struct sk_buff *skb, unsigned char *haddr) * @hh: destination cache entry * Create an Ethernet header template from the neighbour. */ -int eth_header_cache(struct neighbour *neigh, struct hh_cache *hh) +int eth_header_cache(const struct neighbour *neigh, struct hh_cache *hh) { __be16 type = hh->hh_type; struct ethhdr *eth; - struct net_device *dev = neigh->dev; + const struct net_device *dev = neigh->dev; eth = (struct ethhdr *) (((u8 *) hh->hh_data) + (HH_DATA_OFF(sizeof(*eth)))); @@ -238,6 +242,7 @@ int eth_header_cache(struct neighbour *neigh, struct hh_cache *hh) hh->hh_len = ETH_HLEN; return 0; } +EXPORT_SYMBOL(eth_header_cache); /** * eth_header_cache_update - update cache entry @@ -247,12 +252,14 @@ int eth_header_cache(struct neighbour *neigh, struct hh_cache *hh) * * Called by Address Resolution module to notify changes in address. */ -void eth_header_cache_update(struct hh_cache *hh, struct net_device *dev, - unsigned char *haddr) +void eth_header_cache_update(struct hh_cache *hh, + const struct net_device *dev, + const unsigned char *haddr) { memcpy(((u8 *) hh->hh_data) + HH_DATA_OFF(sizeof(struct ethhdr)), haddr, ETH_ALEN); } +EXPORT_SYMBOL(eth_header_cache_update); /** * eth_mac_addr - set new Ethernet hardware address @@ -291,6 +298,14 @@ static int eth_change_mtu(struct net_device *dev, int new_mtu) return 0; } +const struct header_ops eth_header_ops ____cacheline_aligned = { + .create = eth_header, + .parse = eth_header_parse, + .rebuild = eth_rebuild_header, + .cache = eth_header_cache, + .cache_update = eth_header_cache_update, +}; + /** * ether_setup - setup Ethernet network device * @dev: network device @@ -298,13 +313,10 @@ static int eth_change_mtu(struct net_device *dev, int new_mtu) */ void ether_setup(struct net_device *dev) { + dev->header_ops = ð_header_ops; + dev->change_mtu = eth_change_mtu; - dev->hard_header = eth_header; - dev->rebuild_header = eth_rebuild_header; dev->set_mac_address = eth_mac_addr; - dev->hard_header_cache = eth_header_cache; - dev->header_cache_update= eth_header_cache_update; - dev->hard_header_parse = eth_header_parse; dev->type = ARPHRD_ETHER; dev->hard_header_len = ETH_HLEN; diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 5b24c65b13c..d8248198bcd 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -253,7 +253,7 @@ static int arp_constructor(struct neighbour *neigh) neigh->parms = neigh_parms_clone(parms); rcu_read_unlock(); - if (dev->hard_header == NULL) { + if (!dev->header_ops) { neigh->nud_state = NUD_NOARP; neigh->ops = &arp_direct_ops; neigh->output = neigh->ops->queue_xmit; @@ -310,10 +310,12 @@ static int arp_constructor(struct neighbour *neigh) neigh->nud_state = NUD_NOARP; memcpy(neigh->ha, dev->broadcast, dev->addr_len); } - if (dev->hard_header_cache) + + if (dev->header_ops->cache) neigh->ops = &arp_hh_ops; else neigh->ops = &arp_generic_ops; + if (neigh->nud_state&NUD_VALID) neigh->output = neigh->ops->connected_output; else diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index ffa9f1c9dcb..f151900efaf 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -684,7 +684,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) goto tx_error; } - if (dev->hard_header) { + if (dev->header_ops) { gre_hlen = 0; tiph = (struct iphdr*)skb->data; } else { @@ -1063,8 +1063,9 @@ static int ipgre_tunnel_change_mtu(struct net_device *dev, int new_mtu) */ -static int ipgre_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, - void *daddr, void *saddr, unsigned len) +static int ipgre_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, + const void *daddr, const void *saddr, unsigned len) { struct ip_tunnel *t = netdev_priv(dev); struct iphdr *iph = (struct iphdr *)skb_push(skb, t->hlen); @@ -1091,6 +1092,10 @@ static int ipgre_header(struct sk_buff *skb, struct net_device *dev, unsigned sh return -t->hlen; } +static const struct header_ops ipgre_header_ops = { + .create = ipgre_header, +}; + static int ipgre_open(struct net_device *dev) { struct ip_tunnel *t = netdev_priv(dev); @@ -1187,7 +1192,7 @@ static int ipgre_tunnel_init(struct net_device *dev) if (!iph->saddr) return -EINVAL; dev->flags = IFF_BROADCAST; - dev->hard_header = ipgre_header; + dev->header_ops = &ipgre_header_ops; dev->open = ipgre_open; dev->stop = ipgre_close; } diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 77f67b7cb9b..699f06781fd 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -169,7 +169,7 @@ static inline int ip_finish_output2(struct sk_buff *skb) IP_INC_STATS(IPSTATS_MIB_OUTBCASTPKTS); /* Be paranoid, rather than too clever. */ - if (unlikely(skb_headroom(skb) < hh_len && dev->hard_header)) { + if (unlikely(skb_headroom(skb) < hh_len && dev->header_ops)) { struct sk_buff *skb2; skb2 = skb_realloc_headroom(skb, LL_RESERVED_SPACE(dev)); diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 7ea5a502ca0..b761dbed8ce 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -354,7 +354,7 @@ static int ndisc_constructor(struct neighbour *neigh) rcu_read_unlock(); neigh->type = is_multicast ? RTN_MULTICAST : RTN_UNICAST; - if (dev->hard_header == NULL) { + if (!dev->header_ops) { neigh->nud_state = NUD_NOARP; neigh->ops = &ndisc_direct_ops; neigh->output = neigh->ops->queue_xmit; @@ -371,7 +371,7 @@ static int ndisc_constructor(struct neighbour *neigh) neigh->nud_state = NUD_NOARP; memcpy(neigh->ha, dev->broadcast, dev->addr_len); } - if (dev->hard_header_cache) + if (dev->header_ops->cache) neigh->ops = &ndisc_hh_ops; else neigh->ops = &ndisc_generic_ops; @@ -807,7 +807,7 @@ static void ndisc_recv_ns(struct sk_buff *skb) neigh_update(neigh, lladdr, NUD_STALE, NEIGH_UPDATE_F_WEAK_OVERRIDE| NEIGH_UPDATE_F_OVERRIDE); - if (neigh || !dev->hard_header) { + if (neigh || !dev->header_ops) { ndisc_send_na(dev, neigh, saddr, &msg->target, is_router, 1, (ifp != NULL && inc), inc); diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 0cdcf0d0c6c..57ec8880bb1 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -228,7 +228,6 @@ void ieee80211_if_mgmt_setup(struct net_device *dev) dev->open = ieee80211_mgmt_open; dev->stop = ieee80211_mgmt_stop; dev->type = ARPHRD_IEEE80211_PRISM; - dev->hard_header_parse = header_parse_80211; dev->uninit = ieee80211_if_reinit; dev->destructor = ieee80211_if_free; } @@ -546,10 +545,19 @@ static void ieee80211_set_multicast_list(struct net_device *dev) netif_tx_unlock(local->mdev); } +static const struct header_ops ieee80211_header_ops = { + .create = eth_header, + .parse = header_parse_80211, + .rebuild = eth_rebuild_header, + .cache = eth_header_cache, + .cache_update = eth_header_cache_update, +}; + /* Must not be called for mdev and apdev */ void ieee80211_if_setup(struct net_device *dev) { ether_setup(dev); + dev->header_ops = &ieee80211_header_ops; dev->hard_start_xmit = ieee80211_subif_start_xmit; dev->wireless_handlers = &ieee80211_iw_handler_def; dev->set_multicast_list = ieee80211_set_multicast_list; @@ -1197,7 +1205,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, mdev->open = ieee80211_master_open; mdev->stop = ieee80211_master_stop; mdev->type = ARPHRD_IEEE80211; - mdev->hard_header_parse = header_parse_80211; + mdev->header_ops = &ieee80211_header_ops; sdata->type = IEEE80211_IF_TYPE_AP; sdata->dev = mdev; diff --git a/net/netrom/nr_dev.c b/net/netrom/nr_dev.c index c7b5d930e73..8c68da5ef0a 100644 --- a/net/netrom/nr_dev.c +++ b/net/netrom/nr_dev.c @@ -95,8 +95,9 @@ static int nr_rebuild_header(struct sk_buff *skb) #endif -static int nr_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, - void *daddr, void *saddr, unsigned len) +static int nr_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, + const void *daddr, const void *saddr, unsigned len) { unsigned char *buff = skb_push(skb, NR_NETWORK_LEN + NR_TRANSPORT_LEN); @@ -193,6 +194,12 @@ static struct net_device_stats *nr_get_stats(struct net_device *dev) return &nr->stats; } +static const struct header_ops nr_header_ops = { + .create = nr_header, + .rebuild= nr_rebuild_header, +}; + + void nr_setup(struct net_device *dev) { dev->mtu = NR_MAX_PACKET_SIZE; @@ -200,11 +207,10 @@ void nr_setup(struct net_device *dev) dev->open = nr_open; dev->stop = nr_close; - dev->hard_header = nr_header; + dev->header_ops = &nr_header_ops; dev->hard_header_len = NR_NETWORK_LEN + NR_TRANSPORT_LEN; dev->addr_len = AX25_ADDR_LEN; dev->type = ARPHRD_NETROM; - dev->rebuild_header = nr_rebuild_header; dev->set_mac_address = nr_set_mac_address; /* New-style flags. */ diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index c9ee343c2a6..e11000a8e95 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -389,7 +389,7 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock, skb_reset_network_header(skb); /* Try to align data part correctly */ - if (dev->hard_header) { + if (dev->header_ops) { skb->data -= dev->hard_header_len; skb->tail -= dev->hard_header_len; if (len < dev->hard_header_len) @@ -466,7 +466,7 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet skb->dev = dev; - if (dev->hard_header) { + if (dev->header_ops) { /* The device has an explicit notion of ll header, exported to higher levels. @@ -581,7 +581,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe sk = pt->af_packet_priv; po = pkt_sk(sk); - if (dev->hard_header) { + if (dev->header_ops) { if (sk->sk_type != SOCK_DGRAM) skb_push(skb, skb->data - skb_mac_header(skb)); else if (skb->pkt_type == PACKET_OUTGOING) { diff --git a/net/rose/rose_dev.c b/net/rose/rose_dev.c index 8d88795dc66..1b6741f1d74 100644 --- a/net/rose/rose_dev.c +++ b/net/rose/rose_dev.c @@ -35,8 +35,9 @@ #include #include -static int rose_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, - void *daddr, void *saddr, unsigned len) +static int rose_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, + const void *daddr, const void *saddr, unsigned len) { unsigned char *buff = skb_push(skb, ROSE_MIN_LEN + 2); @@ -148,6 +149,11 @@ static struct net_device_stats *rose_get_stats(struct net_device *dev) return netdev_priv(dev); } +static const struct header_ops rose_header_ops = { + .create = rose_header, + .rebuild= rose_rebuild_header, +}; + void rose_setup(struct net_device *dev) { dev->mtu = ROSE_MAX_PACKET_SIZE - 2; @@ -155,11 +161,10 @@ void rose_setup(struct net_device *dev) dev->open = rose_open; dev->stop = rose_close; - dev->hard_header = rose_header; + dev->header_ops = &rose_header_ops; dev->hard_header_len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN; dev->addr_len = ROSE_ADDR_LEN; dev->type = ARPHRD_ROSE; - dev->rebuild_header = rose_rebuild_header; dev->set_mac_address = rose_set_mac_address; /* New-style flags. */ diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c index d13970f3c7b..be57cf317a7 100644 --- a/net/sched/sch_teql.c +++ b/net/sched/sch_teql.c @@ -249,10 +249,10 @@ __teql_resolve(struct sk_buff *skb, struct sk_buff *skb_res, struct net_device * return (skb_res == NULL) ? -EAGAIN : 1; } -static __inline__ int -teql_resolve(struct sk_buff *skb, struct sk_buff *skb_res, struct net_device *dev) +static inline int teql_resolve(struct sk_buff *skb, + struct sk_buff *skb_res, struct net_device *dev) { - if (dev->hard_header == NULL || + if (dev->header_ops == NULL || skb->dst == NULL || skb->dst->neighbour == NULL) return 0; -- cgit v1.2.3-70-g09d2 From 7a876fae9da2b1417246a3eac0ac83889f12fa27 Mon Sep 17 00:00:00 2001 From: Satyam Sharma Date: Wed, 26 Sep 2007 22:29:02 -0700 Subject: [SPIDERNET] spider_net_ethtool: Keep up with recent netdev stats changes drivers/net/spider_net_ethtool.c: In function 'spider_net_get_ethtool_stats': drivers/net/spider_net_ethtool.c:160: error: structure has no member named 'netdev_stats' drivers/net/spider_net_ethtool.c:161: error: structure has no member named 'netdev_stats' drivers/net/spider_net_ethtool.c:162: error: structure has no member named 'netdev_stats' drivers/net/spider_net_ethtool.c:163: error: structure has no member named 'netdev_stats' drivers/net/spider_net_ethtool.c:164: error: structure has no member named 'netdev_stats' drivers/net/spider_net_ethtool.c:165: error: structure has no member named 'netdev_stats' drivers/net/spider_net_ethtool.c:166: error: structure has no member named 'netdev_stats' make[2]: *** [drivers/net/spider_net_ethtool.o] Error 1 Also do another ARRAY_SIZE() cleanup while at it. Signed-off-by: Satyam Sharma Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/net/spider_net_ethtool.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/spider_net_ethtool.c b/drivers/net/spider_net_ethtool.c index 94273037102..85691d2a0be 100644 --- a/drivers/net/spider_net_ethtool.c +++ b/drivers/net/spider_net_ethtool.c @@ -28,8 +28,6 @@ #include "spider_net.h" -#define SPIDER_NET_NUM_STATS 13 - static struct { const char str[ETH_GSTRING_LEN]; } ethtool_stats_keys[] = { @@ -151,7 +149,7 @@ static int spider_net_get_sset_count(struct net_device *netdev, int sset) { switch (sset) { case ETH_SS_STATS: - return SPIDER_NET_NUM_STATS; + return ARRAY_SIZE(ethtool_stats_keys); default: return -EOPNOTSUPP; } @@ -162,13 +160,13 @@ static void spider_net_get_ethtool_stats(struct net_device *netdev, { struct spider_net_card *card = netdev->priv; - data[0] = card->netdev_stats.tx_packets; - data[1] = card->netdev_stats.tx_bytes; - data[2] = card->netdev_stats.rx_packets; - data[3] = card->netdev_stats.rx_bytes; - data[4] = card->netdev_stats.tx_errors; - data[5] = card->netdev_stats.tx_dropped; - data[6] = card->netdev_stats.rx_dropped; + data[0] = netdev->stats.tx_packets; + data[1] = netdev->stats.tx_bytes; + data[2] = netdev->stats.rx_packets; + data[3] = netdev->stats.rx_bytes; + data[4] = netdev->stats.tx_errors; + data[5] = netdev->stats.tx_dropped; + data[6] = netdev->stats.rx_dropped; data[7] = card->spider_stats.rx_desc_error; data[8] = card->spider_stats.tx_timeouts; data[9] = card->spider_stats.alloc_rx_skb_error; -- cgit v1.2.3-70-g09d2 From dcffde5345c917b98b094d0ef27f6280bc7d4655 Mon Sep 17 00:00:00 2001 From: Satyam Sharma Date: Wed, 26 Sep 2007 22:29:51 -0700 Subject: [PASEMI_MAC]: remove unused function drivers/net/pasemi_mac.c: At top level: drivers/net/pasemi_mac.c:89: warning: 'read_iob_reg' defined but not used Signed-off-by: Satyam Sharma Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/net/pasemi_mac.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 4d87cd65626..912bc5d33d2 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -85,11 +85,6 @@ MODULE_PARM_DESC(debug, "PA Semi MAC bitmapped debugging message enable value"); static struct pasdma_status *dma_status; -static unsigned int read_iob_reg(struct pasemi_mac *mac, unsigned int reg) -{ - return in_le32(mac->iob_regs+reg); -} - static void write_iob_reg(struct pasemi_mac *mac, unsigned int reg, unsigned int val) { -- cgit v1.2.3-70-g09d2 From 32db927686f6d475fc05b6229f82ed576c0c8096 Mon Sep 17 00:00:00 2001 From: Jonathan Bastien-Filiatrault Date: Wed, 26 Sep 2007 22:34:25 -0700 Subject: [IRDA]: Document the fact that smsc-ircc2 will not use PNP by default This avoids user confusion when they see that their device is not detected. Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/net/irda/smsc-ircc2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c index 029fdde2a4d..7e7b5828214 100644 --- a/drivers/net/irda/smsc-ircc2.c +++ b/drivers/net/irda/smsc-ircc2.c @@ -81,7 +81,7 @@ MODULE_LICENSE("GPL"); static int smsc_nopnp = 1; module_param_named(nopnp, smsc_nopnp, bool, 0); -MODULE_PARM_DESC(nopnp, "Do not use PNP to detect controller settings"); +MODULE_PARM_DESC(nopnp, "Do not use PNP to detect controller settings, defaults to true"); #define DMA_INVAL 255 static int ircc_dma = DMA_INVAL; -- cgit v1.2.3-70-g09d2 From 070ac3a2651e3c1c4d277c5f1981517427c386a7 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Thu, 27 Sep 2007 12:04:19 -0700 Subject: [NET]: Proper comment for loopback initialization order. Loopback device is special. It should be initialized at the very beginning. Initialization order has been changed by Eric W. Biederman and this change is non-obvious and important enough to add proper comment. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- drivers/net/loopback.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index b6d4ae3ad50..2617320efa9 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -293,4 +293,7 @@ static int __init loopback_init(void) return register_pernet_device(&loopback_net_ops); } +/* Loopback is special. It should be initialized before any other network + * device and network subsystem. + */ fs_initcall(loopback_init); -- cgit v1.2.3-70-g09d2 From 4150c57212ad134765dd78c654a4b9906252b66d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 17 Sep 2007 01:29:23 -0400 Subject: [PATCH] mac80211: revamp interface and filter configuration Drivers are currently supposed to keep track of monitor interfaces if they allow so-called "hard" monitor, and they are also supposed to keep track of multicast etc. This patch changes that, replaces the set_multicast_list() callback with a new configure_filter() callback that takes filter flags (FIF_*) instead of interface flags (IFF_*). For a driver, this means it should open the filter as much as necessary to get all frames requested by the filter flags. Accordingly, the filter flags are named "positively", e.g. FIF_ALLMULTI. Multicast filtering is a bit special in that drivers that have no multicast address filters need to allow multicast frames through when either the FIF_ALLMULTI flag is set or when the mc_count value is positive. At the same time, drivers are no longer notified about monitor interfaces at all, this means they now need to implement the start() and stop() callbacks and the new change_filter_flags() callback. Also, the start()/stop() ordering changed, start() is now called *before* any add_interface() as it really should be, and stop() after any remove_interface(). The patch also changes the behaviour of setting the bssid to multicast for scanning when IEEE80211_HW_NO_PROBE_FILTERING is set; the IEEE80211_HW_NO_PROBE_FILTERING flag is removed and the filter flag FIF_BCN_PRBRESP_PROMISC introduced. This is a lot more efficient for hardware like b43 that supports it and other hardware can still set the BSSID to all-ones. Driver modifications by Johannes Berg (b43 & iwlwifi), Michael Wu (rtl8187, adm8211, and p54), Larry Finger (b43legacy), and Ivo van Doorn (rt2x00). Signed-off-by: Johannes Berg Signed-off-by: Michael Wu Signed-off-by: Larry Finger Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/adm8211.c | 144 ++++++----- drivers/net/wireless/adm8211.h | 1 - drivers/net/wireless/b43/b43.h | 15 +- drivers/net/wireless/b43/main.c | 248 ++++++++++--------- drivers/net/wireless/b43legacy/b43legacy.h | 20 +- drivers/net/wireless/b43legacy/main.c | 245 ++++++++++--------- drivers/net/wireless/iwlwifi/iwl3945-base.c | 28 ++- drivers/net/wireless/iwlwifi/iwl4965-base.c | 26 +- drivers/net/wireless/p54.h | 3 +- drivers/net/wireless/p54common.c | 80 +++++-- drivers/net/wireless/rt2x00/rt2400pci.c | 155 ++++++------ drivers/net/wireless/rt2x00/rt2500pci.c | 165 +++++++------ drivers/net/wireless/rt2x00/rt2500usb.c | 179 ++++++++------ drivers/net/wireless/rt2x00/rt2x00.h | 37 +-- drivers/net/wireless/rt2x00/rt2x00config.c | 60 +---- drivers/net/wireless/rt2x00/rt2x00dev.c | 33 ++- drivers/net/wireless/rt2x00/rt2x00lib.h | 1 - drivers/net/wireless/rt2x00/rt2x00mac.c | 104 ++------ drivers/net/wireless/rt2x00/rt2x00pci.c | 31 +-- drivers/net/wireless/rt2x00/rt2x00rfkill.c | 6 +- drivers/net/wireless/rt2x00/rt2x00ring.h | 17 +- drivers/net/wireless/rt2x00/rt2x00usb.c | 16 +- drivers/net/wireless/rt2x00/rt61pci.c | 164 +++++++------ drivers/net/wireless/rt2x00/rt73usb.c | 175 ++++++++------ drivers/net/wireless/rt2x00/rt73usb.h | 2 +- drivers/net/wireless/rtl8187.h | 5 +- drivers/net/wireless/rtl8187_dev.c | 129 ++++++++-- drivers/net/wireless/rtl818x.h | 1 + include/net/mac80211.h | 151 +++++++----- net/mac80211/debugfs_netdev.c | 16 -- net/mac80211/ieee80211.c | 360 +++++++++++----------------- net/mac80211/ieee80211_i.h | 3 +- net/mac80211/ieee80211_sta.c | 26 +- net/mac80211/rx.c | 4 +- 34 files changed, 1383 insertions(+), 1267 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index ac2ea237019..49a6b9eda4e 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -281,49 +281,6 @@ static int adm8211_get_stats(struct ieee80211_hw *dev, return 0; } -static void adm8211_set_rx_mode(struct ieee80211_hw *dev, - unsigned short flags, int mc_count) -{ - struct adm8211_priv *priv = dev->priv; - unsigned int bit_nr; - u32 mc_filter[2]; - struct dev_mc_list *mclist; - void *tmp; - - if (flags & IFF_PROMISC) { - priv->nar |= ADM8211_NAR_PR; - priv->nar &= ~ADM8211_NAR_MM; - mc_filter[1] = mc_filter[0] = ~0; - } else if ((flags & IFF_ALLMULTI) || (mc_count > -1)) { - priv->nar &= ~ADM8211_NAR_PR; - priv->nar |= ADM8211_NAR_MM; - mc_filter[1] = mc_filter[0] = ~0; - } else { - priv->nar &= ~(ADM8211_NAR_MM | ADM8211_NAR_PR); - mc_filter[1] = mc_filter[0] = 0; - mclist = NULL; - while ((mclist = ieee80211_get_mc_list_item(dev, mclist, &tmp))) { - bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; - - bit_nr &= 0x3F; - mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); - } - } - - ADM8211_IDLE_RX(); - - ADM8211_CSR_WRITE(MAR0, mc_filter[0]); - ADM8211_CSR_WRITE(MAR1, mc_filter[1]); - ADM8211_CSR_READ(NAR); - - if (flags & IFF_PROMISC) - dev->flags |= IEEE80211_HW_RX_INCLUDES_FCS; - else - dev->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS; - - ADM8211_RESTORE(); -} - static int adm8211_get_tx_stats(struct ieee80211_hw *dev, struct ieee80211_tx_queue_stats *stats) { @@ -1254,13 +1211,6 @@ static void adm8211_hw_init(struct ieee80211_hw *dev) /* Clear the missed-packet counter. */ ADM8211_CSR_READ(LPC); - - if (!priv->mac_addr) - return; - - /* set mac address */ - ADM8211_CSR_WRITE(PAR0, *(u32 *)priv->mac_addr); - ADM8211_CSR_WRITE(PAR1, *(u16 *)&priv->mac_addr[4]); } static int adm8211_hw_reset(struct ieee80211_hw *dev) @@ -1334,7 +1284,7 @@ static void adm8211_set_interval(struct ieee80211_hw *dev, ADM8211_CSR_WRITE(BPLI, reg); } -static void adm8211_set_bssid(struct ieee80211_hw *dev, u8 *bssid) +static void adm8211_set_bssid(struct ieee80211_hw *dev, const u8 *bssid) { struct adm8211_priv *priv = dev->priv; u32 reg; @@ -1395,24 +1345,87 @@ static int adm8211_config_interface(struct ieee80211_hw *dev, int if_id, return 0; } +static void adm8211_configure_filter(struct ieee80211_hw *dev, + unsigned int changed_flags, + unsigned int *total_flags, + int mc_count, struct dev_mc_list *mclist) +{ + static const u8 bcast[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + struct adm8211_priv *priv = dev->priv; + unsigned int bit_nr, new_flags; + u32 mc_filter[2]; + int i; + + new_flags = 0; + + if (*total_flags & FIF_PROMISC_IN_BSS) { + new_flags |= FIF_PROMISC_IN_BSS; + priv->nar |= ADM8211_NAR_PR; + priv->nar &= ~ADM8211_NAR_MM; + mc_filter[1] = mc_filter[0] = ~0; + } else if ((*total_flags & FIF_ALLMULTI) || (mc_count > 32)) { + new_flags |= FIF_ALLMULTI; + priv->nar &= ~ADM8211_NAR_PR; + priv->nar |= ADM8211_NAR_MM; + mc_filter[1] = mc_filter[0] = ~0; + } else { + priv->nar &= ~(ADM8211_NAR_MM | ADM8211_NAR_PR); + mc_filter[1] = mc_filter[0] = 0; + for (i = 0; i < mc_count; i++) { + if (!mclist) + break; + bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; + + bit_nr &= 0x3F; + mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); + mclist = mclist->next; + } + } + + ADM8211_IDLE_RX(); + + ADM8211_CSR_WRITE(MAR0, mc_filter[0]); + ADM8211_CSR_WRITE(MAR1, mc_filter[1]); + ADM8211_CSR_READ(NAR); + + if (priv->nar & ADM8211_NAR_PR) + dev->flags |= IEEE80211_HW_RX_INCLUDES_FCS; + else + dev->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS; + + if (*total_flags & FIF_BCN_PRBRESP_PROMISC) + adm8211_set_bssid(dev, bcast); + else + adm8211_set_bssid(dev, priv->bssid); + + ADM8211_RESTORE(); + + *total_flags = new_flags; +} + static int adm8211_add_interface(struct ieee80211_hw *dev, struct ieee80211_if_init_conf *conf) { struct adm8211_priv *priv = dev->priv; - /* NOTE: using IEEE80211_IF_TYPE_MGMT to indicate no mode selected */ - if (priv->mode != IEEE80211_IF_TYPE_MGMT) - return -1; + if (priv->mode != IEEE80211_IF_TYPE_MNTR) + return -EOPNOTSUPP; switch (conf->type) { case IEEE80211_IF_TYPE_STA: - case IEEE80211_IF_TYPE_MNTR: priv->mode = conf->type; break; default: return -EOPNOTSUPP; } - priv->mac_addr = conf->mac_addr; + ADM8211_IDLE(); + + ADM8211_CSR_WRITE(PAR0, *(u32 *)conf->mac_addr); + ADM8211_CSR_WRITE(PAR1, *(u16 *)(conf->mac_addr + 4)); + + adm8211_update_mode(dev); + + ADM8211_RESTORE(); return 0; } @@ -1421,7 +1434,7 @@ static void adm8211_remove_interface(struct ieee80211_hw *dev, struct ieee80211_if_init_conf *conf) { struct adm8211_priv *priv = dev->priv; - priv->mode = IEEE80211_IF_TYPE_MGMT; + priv->mode = IEEE80211_IF_TYPE_MNTR; } static int adm8211_init_rings(struct ieee80211_hw *dev) @@ -1505,7 +1518,7 @@ static void adm8211_free_rings(struct ieee80211_hw *dev) } } -static int adm8211_open(struct ieee80211_hw *dev) +static int adm8211_start(struct ieee80211_hw *dev) { struct adm8211_priv *priv = dev->priv; int retval; @@ -1550,7 +1563,7 @@ fail: return retval; } -static int adm8211_stop(struct ieee80211_hw *dev) +static void adm8211_stop(struct ieee80211_hw *dev) { struct adm8211_priv *priv = dev->priv; @@ -1562,7 +1575,6 @@ static int adm8211_stop(struct ieee80211_hw *dev) free_irq(priv->pdev->irq, dev); adm8211_free_rings(dev); - return 0; } static void adm8211_calc_durations(int *dur, int *plcp, size_t payload_len, int len, @@ -1765,13 +1777,13 @@ static int adm8211_alloc_rings(struct ieee80211_hw *dev) static const struct ieee80211_ops adm8211_ops = { .tx = adm8211_tx, - .open = adm8211_open, + .start = adm8211_start, .stop = adm8211_stop, .add_interface = adm8211_add_interface, .remove_interface = adm8211_remove_interface, .config = adm8211_config, .config_interface = adm8211_config_interface, - .set_multicast_list = adm8211_set_rx_mode, + .configure_filter = adm8211_configure_filter, .get_stats = adm8211_get_stats, .get_tx_stats = adm8211_get_tx_stats, .get_tsf = adm8211_get_tsft @@ -1905,7 +1917,7 @@ static int __devinit adm8211_probe(struct pci_dev *pdev, priv->tx_power = 0x40; priv->lpf_cutoff = 0xFF; priv->lnags_threshold = 0xFF; - priv->mode = IEEE80211_IF_TYPE_MGMT; + priv->mode = IEEE80211_IF_TYPE_MNTR; /* Power-on issue. EEPROM won't read correctly without */ if (priv->revid >= ADM8211_REV_BA) { @@ -2000,7 +2012,7 @@ static int adm8211_suspend(struct pci_dev *pdev, pm_message_t state) struct ieee80211_hw *dev = pci_get_drvdata(pdev); struct adm8211_priv *priv = dev->priv; - if (priv->mode != IEEE80211_IF_TYPE_MGMT) { + if (priv->mode != IEEE80211_IF_TYPE_MNTR) { ieee80211_stop_queues(dev); adm8211_stop(dev); } @@ -2018,8 +2030,8 @@ static int adm8211_resume(struct pci_dev *pdev) pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); - if (priv->mode != IEEE80211_IF_TYPE_MGMT) { - adm8211_open(dev); + if (priv->mode != IEEE80211_IF_TYPE_MNTR) { + adm8211_start(dev); ieee80211_start_queues(dev); } diff --git a/drivers/net/wireless/adm8211.h b/drivers/net/wireless/adm8211.h index 795d895f5c9..5991b17c4a7 100644 --- a/drivers/net/wireless/adm8211.h +++ b/drivers/net/wireless/adm8211.h @@ -612,7 +612,6 @@ struct adm8211_priv { u8 bssid[ETH_ALEN]; u8 ssid[32]; size_t ssid_len; - u8 *mac_addr; u8 soft_rx_crc; u8 retry_limit; diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index a22435ade8c..2c8fa1c3465 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -604,9 +604,8 @@ struct b43_wl { * at a time. General information about this interface follows. */ - /* Opaque ID of the operating interface (!= monitor - * interface) from the ieee80211 subsystem. - * Do not modify. + /* Opaque ID of the operating interface from the ieee80211 + * subsystem. Do not modify. */ int if_id; /* The MAC address of the operating interface. */ @@ -615,14 +614,10 @@ struct b43_wl { u8 bssid[ETH_ALEN]; /* Interface type. (IEEE80211_IF_TYPE_XXX) */ int if_type; - /* Counter of active monitor interfaces. */ - int monitor; /* Is the card operating in AP, STA or IBSS mode? */ bool operating; - /* Promisc mode active? - * Note that (monitor != 0) implies promisc. - */ - bool promisc; + /* filter flags */ + unsigned int filter_flags; /* Stats about the wireless interface */ struct ieee80211_low_level_stats ieee_stats; @@ -779,8 +774,6 @@ static inline struct b43_wldev *dev_to_b43_wldev(struct device *dev) /* Is the device operating in a specified mode (IEEE80211_IF_TYPE_XXX). */ static inline int b43_is_mode(struct b43_wl *wl, int type) { - if (type == IEEE80211_IF_TYPE_MNTR) - return !!(wl->monitor); return (wl->operating && wl->if_type == type); } diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index b44c9f92884..72467c86f8d 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -92,14 +92,6 @@ static char modparam_fwpostfix[16]; module_param_string(fwpostfix, modparam_fwpostfix, 16, 0444); MODULE_PARM_DESC(fwpostfix, "Postfix for the .fw files to load."); -static int modparam_mon_keep_bad; -module_param_named(mon_keep_bad, modparam_mon_keep_bad, int, 0444); -MODULE_PARM_DESC(mon_keep_bad, "Keep bad frames in monitor mode"); - -static int modparam_mon_keep_badplcp; -module_param_named(mon_keep_badplcp, modparam_mon_keep_bad, int, 0444); -MODULE_PARM_DESC(mon_keep_badplcp, "Keep frames with bad PLCP in monitor mode"); - static int modparam_hwpctl; module_param_named(hwpctl, modparam_hwpctl, int, 0444); MODULE_PARM_DESC(hwpctl, "Enable hardware-side power control (default off)"); @@ -561,15 +553,10 @@ static void b43_write_mac_bssid_templates(struct b43_wldev *dev) } } -static void b43_upload_card_macaddress(struct b43_wldev *dev, - const u8 * mac_addr) +static void b43_upload_card_macaddress(struct b43_wldev *dev) { - if (mac_addr) - memcpy(dev->wl->mac_addr, mac_addr, ETH_ALEN); - else - memset(dev->wl->mac_addr, 0, ETH_ALEN); b43_write_mac_bssid_templates(dev); - b43_macfilter_set(dev, B43_MACFILTER_SELF, mac_addr); + b43_macfilter_set(dev, B43_MACFILTER_SELF, dev->wl->mac_addr); } static void b43_set_slot_time(struct b43_wldev *dev, u16 slot_time) @@ -2052,33 +2039,25 @@ static void b43_adjust_opmode(struct b43_wldev *dev) ctl &= ~B43_MACCTL_KEEP_BADPLCP; ctl &= ~B43_MACCTL_KEEP_BAD; ctl &= ~B43_MACCTL_PROMISC; + ctl &= ~B43_MACCTL_BEACPROMISC; ctl |= B43_MACCTL_INFRA; - if (wl->operating) { - switch (wl->if_type) { - case IEEE80211_IF_TYPE_AP: - ctl |= B43_MACCTL_AP; - break; - case IEEE80211_IF_TYPE_IBSS: - ctl &= ~B43_MACCTL_INFRA; - break; - case IEEE80211_IF_TYPE_STA: - case IEEE80211_IF_TYPE_MNTR: - case IEEE80211_IF_TYPE_WDS: - break; - default: - B43_WARN_ON(1); - } - } - if (wl->monitor) { + if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) + ctl |= B43_MACCTL_AP; + else if (b43_is_mode(wl, IEEE80211_IF_TYPE_IBSS)) + ctl &= ~B43_MACCTL_INFRA; + + if (wl->filter_flags & FIF_CONTROL) ctl |= B43_MACCTL_KEEP_CTL; - if (modparam_mon_keep_bad) - ctl |= B43_MACCTL_KEEP_BAD; - if (modparam_mon_keep_badplcp) - ctl |= B43_MACCTL_KEEP_BADPLCP; - } - if (wl->promisc) + if (wl->filter_flags & FIF_FCSFAIL) + ctl |= B43_MACCTL_KEEP_BAD; + if (wl->filter_flags & FIF_PLCPFAIL) + ctl |= B43_MACCTL_KEEP_BADPLCP; + if (wl->filter_flags & FIF_PROMISC_IN_BSS) ctl |= B43_MACCTL_PROMISC; + if (wl->filter_flags & FIF_BCN_PRBRESP_PROMISC) + ctl |= B43_MACCTL_BEACPROMISC; + /* Workaround: On old hardware the HW-MAC-address-filter * doesn't work properly, so always run promisc in filter * it in software. */ @@ -2254,9 +2233,6 @@ static int b43_chip_init(struct b43_wldev *dev) & ~B43_MACCTL_INFRA); b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL) | B43_MACCTL_INFRA); - /* Let beacons come through */ - b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL) - | B43_MACCTL_BEACPROMISC); if (b43_using_pio(dev)) { b43_write32(dev, 0x0210, 0x00000100); @@ -2899,9 +2875,9 @@ static int b43_dev_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) return err; } -static int b43_dev_set_key(struct ieee80211_hw *hw, - set_key_cmd cmd, const u8 *local_addr, - const u8 *addr, struct ieee80211_key_conf *key) +static int b43_dev_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + const u8 *local_addr, const u8 *addr, + struct ieee80211_key_conf *key) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev = wl->current_dev; @@ -3003,21 +2979,40 @@ out: return err; } -static void b43_set_multicast_list(struct ieee80211_hw *hw, - unsigned short netflags, int mc_count) +static void b43_configure_filter(struct ieee80211_hw *hw, + unsigned int changed, unsigned int *fflags, + int mc_count, struct dev_addr_list *mc_list) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev = wl->current_dev; unsigned long flags; - if (!dev) + if (!dev) { + *fflags = 0; return; - spin_lock_irqsave(&wl->irq_lock, flags); - if (wl->promisc != !!(netflags & IFF_PROMISC)) { - wl->promisc = !!(netflags & IFF_PROMISC); - if (b43_status(dev) >= B43_STAT_INITIALIZED) - b43_adjust_opmode(dev); } + + spin_lock_irqsave(&wl->irq_lock, flags); + *fflags &= FIF_PROMISC_IN_BSS | + FIF_ALLMULTI | + FIF_FCSFAIL | + FIF_PLCPFAIL | + FIF_CONTROL | + FIF_OTHER_BSS | + FIF_BCN_PRBRESP_PROMISC; + + changed &= FIF_PROMISC_IN_BSS | + FIF_ALLMULTI | + FIF_FCSFAIL | + FIF_PLCPFAIL | + FIF_CONTROL | + FIF_OTHER_BSS | + FIF_BCN_PRBRESP_PROMISC; + + wl->filter_flags = *fflags; + + if (changed && b43_status(dev) >= B43_STAT_INITIALIZED) + b43_adjust_opmode(dev); spin_unlock_irqrestore(&wl->irq_lock, flags); } @@ -3032,21 +3027,19 @@ static int b43_config_interface(struct ieee80211_hw *hw, return -ENODEV; mutex_lock(&wl->mutex); spin_lock_irqsave(&wl->irq_lock, flags); - if (conf->type != IEEE80211_IF_TYPE_MNTR) { - B43_WARN_ON(wl->if_id != if_id); - if (conf->bssid) - memcpy(wl->bssid, conf->bssid, ETH_ALEN); - else - memset(wl->bssid, 0, ETH_ALEN); - if (b43_status(dev) >= B43_STAT_INITIALIZED) { - if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) { - B43_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP); - b43_set_ssid(dev, conf->ssid, conf->ssid_len); - if (conf->beacon) - b43_refresh_templates(dev, conf->beacon); - } - b43_write_mac_bssid_templates(dev); + B43_WARN_ON(wl->if_id != if_id); + if (conf->bssid) + memcpy(wl->bssid, conf->bssid, ETH_ALEN); + else + memset(wl->bssid, 0, ETH_ALEN); + if (b43_status(dev) >= B43_STAT_INITIALIZED) { + if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) { + B43_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP); + b43_set_ssid(dev, conf->ssid, conf->ssid_len); + if (conf->beacon) + b43_refresh_templates(dev, conf->beacon); } + b43_write_mac_bssid_templates(dev); } spin_unlock_irqrestore(&wl->irq_lock, flags); mutex_unlock(&wl->mutex); @@ -3472,7 +3465,8 @@ static int b43_wireless_core_init(struct b43_wldev *dev) ssb_bus_powerup(bus, 1); /* Enable dynamic PCTL */ memset(wl->bssid, 0, ETH_ALEN); - b43_upload_card_macaddress(dev, NULL); + memset(wl->mac_addr, 0, ETH_ALEN); + b43_upload_card_macaddress(dev); b43_security_init(dev); b43_rng_init(wl); @@ -3502,21 +3496,80 @@ static int b43_add_interface(struct ieee80211_hw *hw, struct b43_wldev *dev; unsigned long flags; int err = -EOPNOTSUPP; - int did_init = 0; + + /* TODO: allow WDS/AP devices to coexist */ + + if (conf->type != IEEE80211_IF_TYPE_AP && + conf->type != IEEE80211_IF_TYPE_STA && + conf->type != IEEE80211_IF_TYPE_WDS && + conf->type != IEEE80211_IF_TYPE_IBSS) + return -EOPNOTSUPP; mutex_lock(&wl->mutex); - if ((conf->type != IEEE80211_IF_TYPE_MNTR) && wl->operating) + if (wl->operating) goto out_mutex_unlock; b43dbg(wl, "Adding Interface type %d\n", conf->type); dev = wl->current_dev; + wl->operating = 1; + wl->if_id = conf->if_id; + wl->if_type = conf->type; + memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN); + + spin_lock_irqsave(&wl->irq_lock, flags); + b43_adjust_opmode(dev); + b43_upload_card_macaddress(dev); + spin_unlock_irqrestore(&wl->irq_lock, flags); + + err = 0; + out_mutex_unlock: + mutex_unlock(&wl->mutex); + + return err; +} + +static void b43_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct b43_wl *wl = hw_to_b43_wl(hw); + struct b43_wldev *dev = wl->current_dev; + unsigned long flags; + + b43dbg(wl, "Removing Interface type %d\n", conf->type); + + mutex_lock(&wl->mutex); + + B43_WARN_ON(!wl->operating); + B43_WARN_ON(wl->if_id != conf->if_id); + + wl->operating = 0; + + spin_lock_irqsave(&wl->irq_lock, flags); + b43_adjust_opmode(dev); + memset(wl->mac_addr, 0, ETH_ALEN); + b43_upload_card_macaddress(dev); + spin_unlock_irqrestore(&wl->irq_lock, flags); + + mutex_unlock(&wl->mutex); +} + +static int b43_start(struct ieee80211_hw *hw) +{ + struct b43_wl *wl = hw_to_b43_wl(hw); + struct b43_wldev *dev = wl->current_dev; + int did_init = 0; + int err; + + mutex_lock(&wl->mutex); + if (b43_status(dev) < B43_STAT_INITIALIZED) { err = b43_wireless_core_init(dev); if (err) goto out_mutex_unlock; did_init = 1; } + if (b43_status(dev) < B43_STAT_STARTED) { err = b43_wireless_core_start(dev); if (err) { @@ -3526,59 +3579,21 @@ static int b43_add_interface(struct ieee80211_hw *hw, } } - spin_lock_irqsave(&wl->irq_lock, flags); - switch (conf->type) { - case IEEE80211_IF_TYPE_MNTR: - wl->monitor++; - break; - default: - wl->operating = 1; - wl->if_id = conf->if_id; - wl->if_type = conf->type; - b43_upload_card_macaddress(dev, conf->mac_addr); - } - b43_adjust_opmode(dev); - spin_unlock_irqrestore(&wl->irq_lock, flags); - - err = 0; - out_mutex_unlock: + out_mutex_unlock: mutex_unlock(&wl->mutex); return err; } -static void b43_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) +void b43_stop(struct ieee80211_hw *hw) { struct b43_wl *wl = hw_to_b43_wl(hw); - struct b43_wldev *dev; - unsigned long flags; - - b43dbg(wl, "Removing Interface type %d\n", conf->type); + struct b43_wldev *dev = wl->current_dev; mutex_lock(&wl->mutex); - if (conf->type == IEEE80211_IF_TYPE_MNTR) { - wl->monitor--; - B43_WARN_ON(wl->monitor < 0); - } else { - B43_WARN_ON(!wl->operating); - wl->operating = 0; - } - - dev = wl->current_dev; - if (!wl->operating && wl->monitor == 0) { - /* No interface left. */ - if (b43_status(dev) >= B43_STAT_STARTED) - b43_wireless_core_stop(dev); - b43_wireless_core_exit(dev); - } else { - /* Just monitor interfaces left. */ - spin_lock_irqsave(&wl->irq_lock, flags); - b43_adjust_opmode(dev); - if (!wl->operating) - b43_upload_card_macaddress(dev, NULL); - spin_unlock_irqrestore(&wl->irq_lock, flags); - } + if (b43_status(dev) >= B43_STAT_STARTED) + b43_wireless_core_stop(dev); + b43_wireless_core_exit(dev); mutex_unlock(&wl->mutex); } @@ -3589,10 +3604,12 @@ static const struct ieee80211_ops b43_hw_ops = { .remove_interface = b43_remove_interface, .config = b43_dev_config, .config_interface = b43_config_interface, - .set_multicast_list = b43_set_multicast_list, + .configure_filter = b43_configure_filter, .set_key = b43_dev_set_key, .get_stats = b43_get_stats, .get_tx_stats = b43_get_tx_stats, + .start = b43_start, + .stop = b43_stop, }; /* Hard-reset the chip. Do not call this directly. @@ -3930,8 +3947,7 @@ static int b43_wireless_init(struct ssb_device *dev) } /* fill hw info */ - hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | - IEEE80211_HW_MONITOR_DURING_OPER; + hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE; hw->max_signal = 100; hw->max_rssi = -110; hw->max_noise = -110; diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h index 746de2ff498..afe145cec06 100644 --- a/drivers/net/wireless/b43legacy/b43legacy.h +++ b/drivers/net/wireless/b43legacy/b43legacy.h @@ -179,6 +179,7 @@ #define B43legacy_MACCTL_IHR_ENABLED 0x00000400 /* IHR Region Enabled */ #define B43legacy_MACCTL_INFRA 0x00020000 /* Infrastructure mode */ #define B43legacy_MACCTL_AP 0x00040000 /* AccessPoint mode */ +#define B43legacy_MACCTL_BEACPROMISC 0x00100000 /* Beacon Promiscuous */ #define B43legacy_MACCTL_KEEP_BADPLCP 0x00200000 /* Keep bad PLCP frames */ #define B43legacy_MACCTL_KEEP_CTL 0x00400000 /* Keep control frames */ #define B43legacy_MACCTL_KEEP_BAD 0x00800000 /* Keep bad frames (FCS) */ @@ -570,25 +571,20 @@ struct b43legacy_wl { * at a time. General information about this interface follows. */ - /* Opaque ID of the operating interface (!= monitor - * interface) from the ieee80211 subsystem. - * Do not modify. + /* Opaque ID of the operating interface from the ieee80211 + * subsystem. Do not modify. */ int if_id; /* MAC address (can be NULL). */ - const u8 *mac_addr; + u8 mac_addr[ETH_ALEN]; /* Current BSSID (can be NULL). */ - const u8 *bssid; + u8 bssid[ETH_ALEN]; /* Interface type. (IEEE80211_IF_TYPE_XXX) */ int if_type; - /* Counter of active monitor interfaces. */ - int monitor; /* Is the card operating in AP, STA or IBSS mode? */ bool operating; - /* Promisc mode active? - * Note that (monitor != 0) implies promisc. - */ - bool promisc; + /* filter flags */ + unsigned int filter_flags; /* Stats about the wireless interface */ struct ieee80211_low_level_stats ieee_stats; @@ -753,8 +749,6 @@ struct b43legacy_wldev *dev_to_b43legacy_wldev(struct device *dev) static inline int b43legacy_is_mode(struct b43legacy_wl *wl, int type) { - if (type == IEEE80211_IF_TYPE_MNTR) - return !!(wl->monitor); return (wl->operating && wl->if_type == type); } diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index a793f183a2c..f0749510bcd 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -91,14 +91,6 @@ static char modparam_fwpostfix[16]; module_param_string(fwpostfix, modparam_fwpostfix, 16, 0444); MODULE_PARM_DESC(fwpostfix, "Postfix for the firmware files to load."); -static int modparam_mon_keep_bad; -module_param_named(mon_keep_bad, modparam_mon_keep_bad, int, 0444); -MODULE_PARM_DESC(mon_keep_bad, "Keep bad frames in monitor mode"); - -static int modparam_mon_keep_badplcp; -module_param_named(mon_keep_badplcp, modparam_mon_keep_bad, int, 0444); -MODULE_PARM_DESC(mon_keep_badplcp, "Keep frames with bad PLCP in monitor mode"); - /* The following table supports BCM4301, BCM4303 and BCM4306/2 devices. */ static const struct ssb_device_id b43legacy_ssb_tbl[] = { SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 2), @@ -566,12 +558,11 @@ static void b43legacy_write_mac_bssid_templates(struct b43legacy_wldev *dev) } } -static void b43legacy_upload_card_macaddress(struct b43legacy_wldev *dev, - const u8 *mac_addr) +static void b43legacy_upload_card_macaddress(struct b43legacy_wldev *dev) { - dev->wl->mac_addr = mac_addr; b43legacy_write_mac_bssid_templates(dev); - b43legacy_macfilter_set(dev, B43legacy_MACFILTER_SELF, mac_addr); + b43legacy_macfilter_set(dev, B43legacy_MACFILTER_SELF, + dev->wl->mac_addr); } static void b43legacy_set_slot_time(struct b43legacy_wldev *dev, @@ -1874,34 +1865,25 @@ static void b43legacy_adjust_opmode(struct b43legacy_wldev *dev) ctl &= ~B43legacy_MACCTL_KEEP_BADPLCP; ctl &= ~B43legacy_MACCTL_KEEP_BAD; ctl &= ~B43legacy_MACCTL_PROMISC; + ctl &= ~B43legacy_MACCTL_BEACPROMISC; ctl |= B43legacy_MACCTL_INFRA; - if (wl->operating) { - switch (wl->if_type) { - case IEEE80211_IF_TYPE_AP: - ctl |= B43legacy_MACCTL_AP; - break; - case IEEE80211_IF_TYPE_IBSS: - ctl &= ~B43legacy_MACCTL_INFRA; - break; - case IEEE80211_IF_TYPE_STA: - case IEEE80211_IF_TYPE_MNTR: - case IEEE80211_IF_TYPE_WDS: - break; - default: - b43legacyerr(wl, "Improper value of %d for" - " wl->if_type\n", wl->if_type); - } - } - if (wl->monitor) { + if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP)) + ctl |= B43legacy_MACCTL_AP; + else if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_IBSS)) + ctl &= ~B43legacy_MACCTL_INFRA; + + if (wl->filter_flags & FIF_CONTROL) ctl |= B43legacy_MACCTL_KEEP_CTL; - if (modparam_mon_keep_bad) - ctl |= B43legacy_MACCTL_KEEP_BAD; - if (modparam_mon_keep_badplcp) - ctl |= B43legacy_MACCTL_KEEP_BADPLCP; - } - if (wl->promisc) + if (wl->filter_flags & FIF_FCSFAIL) + ctl |= B43legacy_MACCTL_KEEP_BAD; + if (wl->filter_flags & FIF_PLCPFAIL) + ctl |= B43legacy_MACCTL_KEEP_BADPLCP; + if (wl->filter_flags & FIF_PROMISC_IN_BSS) ctl |= B43legacy_MACCTL_PROMISC; + if (wl->filter_flags & FIF_BCN_PRBRESP_PROMISC) + ctl |= B43legacy_MACCTL_BEACPROMISC; + /* Workaround: On old hardware the HW-MAC-address-filter * doesn't work properly, so always run promisc in filter * it in software. */ @@ -2091,10 +2073,6 @@ static int b43legacy_chip_init(struct b43legacy_wldev *dev) value32 |= B43legacy_SBF_MODE_NOTADHOC; b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, value32); - value32 = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD); - value32 |= 0x100000; - b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, value32); - if (b43legacy_using_pio(dev)) { b43legacy_write32(dev, 0x0210, 0x00000100); b43legacy_write32(dev, 0x0230, 0x00000100); @@ -2699,7 +2677,7 @@ out_unlock_mutex: } static int b43legacy_dev_set_key(struct ieee80211_hw *hw, - set_key_cmd cmd, + enum set_key_cmd cmd, const u8 *local_addr, const u8 *addr, struct ieee80211_key_conf *key) { @@ -2724,22 +2702,42 @@ static int b43legacy_dev_set_key(struct ieee80211_hw *hw, return err; } -static void b43legacy_set_multicast_list(struct ieee80211_hw *hw, - unsigned short netflags, - int mc_count) +static void b43legacy_configure_filter(struct ieee80211_hw *hw, + unsigned int changed, + unsigned int *fflags, + int mc_count, + struct dev_addr_list *mc_list) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev = wl->current_dev; unsigned long flags; - if (!dev) + if (!dev) { + *fflags = 0; return; - spin_lock_irqsave(&wl->irq_lock, flags); - if (wl->promisc != !!(netflags & IFF_PROMISC)) { - wl->promisc = !!(netflags & IFF_PROMISC); - if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) - b43legacy_adjust_opmode(dev); } + + spin_lock_irqsave(&wl->irq_lock, flags); + *fflags &= FIF_PROMISC_IN_BSS | + FIF_ALLMULTI | + FIF_FCSFAIL | + FIF_PLCPFAIL | + FIF_CONTROL | + FIF_OTHER_BSS | + FIF_BCN_PRBRESP_PROMISC; + + changed &= FIF_PROMISC_IN_BSS | + FIF_ALLMULTI | + FIF_FCSFAIL | + FIF_PLCPFAIL | + FIF_CONTROL | + FIF_OTHER_BSS | + FIF_BCN_PRBRESP_PROMISC; + + wl->filter_flags = *fflags; + + if (changed && b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) + b43legacy_adjust_opmode(dev); spin_unlock_irqrestore(&wl->irq_lock, flags); } @@ -2755,21 +2753,19 @@ static int b43legacy_config_interface(struct ieee80211_hw *hw, return -ENODEV; mutex_lock(&wl->mutex); spin_lock_irqsave(&wl->irq_lock, flags); - if (conf->type != IEEE80211_IF_TYPE_MNTR) { - B43legacy_WARN_ON(wl->if_id != if_id); - wl->bssid = conf->bssid; - if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) { - if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP)) { - B43legacy_WARN_ON(conf->type != - IEEE80211_IF_TYPE_AP); - b43legacy_set_ssid(dev, conf->ssid, - conf->ssid_len); - if (conf->beacon) - b43legacy_refresh_templates(dev, - conf->beacon); - } - b43legacy_write_mac_bssid_templates(dev); + B43legacy_WARN_ON(wl->if_id != if_id); + if (conf->bssid) + memcpy(wl->bssid, conf->bssid, ETH_ALEN); + else + memset(wl->bssid, 0, ETH_ALEN); + if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) { + if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP)) { + B43legacy_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP); + b43legacy_set_ssid(dev, conf->ssid, conf->ssid_len); + if (conf->beacon) + b43legacy_refresh_templates(dev, conf->beacon); } + b43legacy_write_mac_bssid_templates(dev); } spin_unlock_irqrestore(&wl->irq_lock, flags); mutex_unlock(&wl->mutex); @@ -3216,8 +3212,9 @@ static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev) b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0414, 0x01F4); ssb_bus_powerup(bus, 1); /* Enable dynamic PCTL */ - wl->bssid = NULL; - b43legacy_upload_card_macaddress(dev, NULL); + memset(wl->bssid, 0, ETH_ALEN); + memset(wl->mac_addr, 0, ETH_ALEN); + b43legacy_upload_card_macaddress(dev); b43legacy_security_init(dev); b43legacy_rng_init(wl); @@ -3246,22 +3243,80 @@ static int b43legacy_add_interface(struct ieee80211_hw *hw, struct b43legacy_wldev *dev; unsigned long flags; int err = -EOPNOTSUPP; - int did_init = 0; + + /* TODO: allow WDS/AP devices to coexist */ + + if (conf->type != IEEE80211_IF_TYPE_AP && + conf->type != IEEE80211_IF_TYPE_STA && + conf->type != IEEE80211_IF_TYPE_WDS && + conf->type != IEEE80211_IF_TYPE_IBSS) + return -EOPNOTSUPP; mutex_lock(&wl->mutex); - if ((conf->type != IEEE80211_IF_TYPE_MNTR) && - wl->operating) + if (wl->operating) goto out_mutex_unlock; b43legacydbg(wl, "Adding Interface type %d\n", conf->type); dev = wl->current_dev; + wl->operating = 1; + wl->if_id = conf->if_id; + wl->if_type = conf->type; + memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN); + + spin_lock_irqsave(&wl->irq_lock, flags); + b43legacy_adjust_opmode(dev); + b43legacy_upload_card_macaddress(dev); + spin_unlock_irqrestore(&wl->irq_lock, flags); + + err = 0; + out_mutex_unlock: + mutex_unlock(&wl->mutex); + + return err; +} + +static void b43legacy_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); + struct b43legacy_wldev *dev = wl->current_dev; + unsigned long flags; + + b43legacydbg(wl, "Removing Interface type %d\n", conf->type); + + mutex_lock(&wl->mutex); + + B43legacy_WARN_ON(!wl->operating); + B43legacy_WARN_ON(wl->if_id != conf->if_id); + + wl->operating = 0; + + spin_lock_irqsave(&wl->irq_lock, flags); + b43legacy_adjust_opmode(dev); + memset(wl->mac_addr, 0, ETH_ALEN); + b43legacy_upload_card_macaddress(dev); + spin_unlock_irqrestore(&wl->irq_lock, flags); + + mutex_unlock(&wl->mutex); +} + +static int b43legacy_start(struct ieee80211_hw *hw) +{ + struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); + struct b43legacy_wldev *dev = wl->current_dev; + int did_init = 0; + int err; + + mutex_lock(&wl->mutex); + if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) { err = b43legacy_wireless_core_init(dev); if (err) goto out_mutex_unlock; did_init = 1; } + if (b43legacy_status(dev) < B43legacy_STAT_STARTED) { err = b43legacy_wireless_core_start(dev); if (err) { @@ -3271,59 +3326,21 @@ static int b43legacy_add_interface(struct ieee80211_hw *hw, } } - spin_lock_irqsave(&wl->irq_lock, flags); - switch (conf->type) { - case IEEE80211_IF_TYPE_MNTR: - wl->monitor++; - break; - default: - wl->operating = 1; - wl->if_id = conf->if_id; - wl->if_type = conf->type; - b43legacy_upload_card_macaddress(dev, conf->mac_addr); - } - b43legacy_adjust_opmode(dev); - spin_unlock_irqrestore(&wl->irq_lock, flags); - - err = 0; out_mutex_unlock: mutex_unlock(&wl->mutex); return err; } -static void b43legacy_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) +void b43legacy_stop(struct ieee80211_hw *hw) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); - struct b43legacy_wldev *dev; - unsigned long flags; - - b43legacydbg(wl, "Removing Interface type %d\n", conf->type); + struct b43legacy_wldev *dev = wl->current_dev; mutex_lock(&wl->mutex); - if (conf->type == IEEE80211_IF_TYPE_MNTR) { - wl->monitor--; - B43legacy_WARN_ON(wl->monitor < 0); - } else { - B43legacy_WARN_ON(!wl->operating); - wl->operating = 0; - } - - dev = wl->current_dev; - if (!wl->operating && wl->monitor == 0) { - /* No interface left. */ - if (b43legacy_status(dev) >= B43legacy_STAT_STARTED) - b43legacy_wireless_core_stop(dev); - b43legacy_wireless_core_exit(dev); - } else { - /* Just monitor interfaces left. */ - spin_lock_irqsave(&wl->irq_lock, flags); - b43legacy_adjust_opmode(dev); - if (!wl->operating) - b43legacy_upload_card_macaddress(dev, NULL); - spin_unlock_irqrestore(&wl->irq_lock, flags); - } + if (b43legacy_status(dev) >= B43legacy_STAT_STARTED) + b43legacy_wireless_core_stop(dev); + b43legacy_wireless_core_exit(dev); mutex_unlock(&wl->mutex); } @@ -3336,9 +3353,11 @@ static const struct ieee80211_ops b43legacy_hw_ops = { .config = b43legacy_dev_config, .config_interface = b43legacy_config_interface, .set_key = b43legacy_dev_set_key, - .set_multicast_list = b43legacy_set_multicast_list, + .configure_filter = b43legacy_configure_filter, .get_stats = b43legacy_get_stats, .get_tx_stats = b43legacy_get_tx_stats, + .start = b43legacy_start, + .stop = b43legacy_stop, }; /* Hard-reset the chip. Do not call this directly. diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 44f983b6d39..8acda640df2 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -6870,7 +6870,7 @@ static void iwl_bg_scan_completed(struct work_struct *work) * *****************************************************************************/ -static int iwl_mac_open(struct ieee80211_hw *hw) +static int iwl_mac_start(struct ieee80211_hw *hw) { struct iwl_priv *priv = hw->priv; @@ -6889,7 +6889,7 @@ static int iwl_mac_open(struct ieee80211_hw *hw) return 0; } -static int iwl_mac_stop(struct ieee80211_hw *hw) +static void iwl_mac_stop(struct ieee80211_hw *hw) { struct iwl_priv *priv = hw->priv; @@ -6898,8 +6898,6 @@ static int iwl_mac_stop(struct ieee80211_hw *hw) /*netif_stop_queue(dev); */ flush_workqueue(priv->workqueue); IWL_DEBUG_MAC80211("leave\n"); - - return 0; } static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, @@ -7115,6 +7113,8 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id, if (conf == NULL) return -EIO; + /* XXX: this MUST use conf->mac_addr */ + if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) && (!conf->beacon || !conf->ssid_len)) { IWL_DEBUG_MAC80211 @@ -7129,8 +7129,13 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id, IWL_DEBUG_MAC80211("bssid: %s\n", print_mac(mac, conf->bssid)); +/* + * very dubious code was here; the probe filtering flag is never set: + * if (unlikely(test_bit(STATUS_SCANNING, &priv->status)) && !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) { + */ + if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) { IWL_DEBUG_MAC80211("leave - scanning\n"); mutex_unlock(&priv->mutex); return 0; @@ -7205,6 +7210,18 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id, return 0; } +static void iwl_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + int mc_count, struct dev_addr_list *mc_list) +{ + /* + * XXX: dummy + * see also iwl_connection_init_rx_config + */ + *total_flags = 0; +} + static void iwl_mac_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { @@ -8265,12 +8282,13 @@ static struct attribute_group iwl_attribute_group = { static struct ieee80211_ops iwl_hw_ops = { .tx = iwl_mac_tx, - .open = iwl_mac_open, + .start = iwl_mac_start, .stop = iwl_mac_stop, .add_interface = iwl_mac_add_interface, .remove_interface = iwl_mac_remove_interface, .config = iwl_mac_config, .config_interface = iwl_mac_config_interface, + .configure_filter = iwl_configure_filter, .set_key = iwl_mac_set_key, .get_stats = iwl_mac_get_stats, .get_tx_stats = iwl_mac_get_tx_stats, diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 61500a20929..7b9227c562b 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -7252,7 +7252,7 @@ static void iwl_bg_scan_completed(struct work_struct *work) * *****************************************************************************/ -static int iwl_mac_open(struct ieee80211_hw *hw) +static int iwl_mac_start(struct ieee80211_hw *hw) { struct iwl_priv *priv = hw->priv; @@ -7271,7 +7271,7 @@ static int iwl_mac_open(struct ieee80211_hw *hw) return 0; } -static int iwl_mac_stop(struct ieee80211_hw *hw) +static void iwl_mac_stop(struct ieee80211_hw *hw) { struct iwl_priv *priv = hw->priv; @@ -7280,8 +7280,6 @@ static int iwl_mac_stop(struct ieee80211_hw *hw) /*netif_stop_queue(dev); */ flush_workqueue(priv->workqueue); IWL_DEBUG_MAC80211("leave\n"); - - return 0; } static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, @@ -7528,8 +7526,13 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id, IWL_DEBUG_MAC80211("bssid: %s\n", print_mac(mac, conf->bssid)); +/* + * very dubious code was here; the probe filtering flag is never set: + * if (unlikely(test_bit(STATUS_SCANNING, &priv->status)) && !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) { + */ + if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) { IWL_DEBUG_MAC80211("leave - scanning\n"); mutex_unlock(&priv->mutex); return 0; @@ -7604,6 +7607,18 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id, return 0; } +static void iwl_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + int mc_count, struct dev_addr_list *mc_list) +{ + /* + * XXX: dummy + * see also iwl_connection_init_rx_config + */ + *total_flags = 0; +} + static void iwl_mac_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { @@ -8852,12 +8867,13 @@ static struct attribute_group iwl_attribute_group = { static struct ieee80211_ops iwl_hw_ops = { .tx = iwl_mac_tx, - .open = iwl_mac_open, + .start = iwl_mac_start, .stop = iwl_mac_stop, .add_interface = iwl_mac_add_interface, .remove_interface = iwl_mac_remove_interface, .config = iwl_mac_config, .config_interface = iwl_mac_config_interface, + .configure_filter = iwl_configure_filter, .set_key = iwl_mac_set_key, .get_stats = iwl_mac_get_stats, .get_tx_stats = iwl_mac_get_tx_stats, diff --git a/drivers/net/wireless/p54.h b/drivers/net/wireless/p54.h index e558d697d9e..744c866066c 100644 --- a/drivers/net/wireless/p54.h +++ b/drivers/net/wireless/p54.h @@ -52,7 +52,8 @@ struct p54_common { int (*open)(struct ieee80211_hw *dev); void (*stop)(struct ieee80211_hw *dev); int mode; - u8 *mac_addr; + u8 mac_addr[ETH_ALEN]; + u8 bssid[ETH_ALEN]; struct pda_iq_autocal_entry *iq_autocal; unsigned int iq_autocal_len; struct pda_channel_output_limit *output_limit; diff --git a/drivers/net/wireless/p54common.c b/drivers/net/wireless/p54common.c index b05b5c5b4c0..9befd6cc791 100644 --- a/drivers/net/wireless/p54common.c +++ b/drivers/net/wireless/p54common.c @@ -774,15 +774,39 @@ static void p54_set_vdcf(struct ieee80211_hw *dev) priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*vdcf), 0); } +static int p54_start(struct ieee80211_hw *dev) +{ + struct p54_common *priv = dev->priv; + int err; + + err = priv->open(dev); + if (!err) + priv->mode = IEEE80211_IF_TYPE_MNTR; + + return err; +} + +static void p54_stop(struct ieee80211_hw *dev) +{ + struct p54_common *priv = dev->priv; + struct sk_buff *skb; + while ((skb = skb_dequeue(&priv->tx_queue))) { + struct memrecord *range = (struct memrecord *)&skb->cb; + if (range->control) + kfree(range->control); + kfree_skb(skb); + } + priv->stop(dev); + priv->mode = IEEE80211_IF_TYPE_MGMT; +} + static int p54_add_interface(struct ieee80211_hw *dev, struct ieee80211_if_init_conf *conf) { struct p54_common *priv = dev->priv; - int err; - /* NOTE: using IEEE80211_IF_TYPE_MGMT to indicate no mode selected */ - if (priv->mode != IEEE80211_IF_TYPE_MGMT) - return -1; + if (priv->mode != IEEE80211_IF_TYPE_MNTR) + return -EOPNOTSUPP; switch (conf->type) { case IEEE80211_IF_TYPE_STA: @@ -792,23 +816,18 @@ static int p54_add_interface(struct ieee80211_hw *dev, return -EOPNOTSUPP; } - priv->mac_addr = conf->mac_addr; - - err = priv->open(dev); - if (err) { - priv->mode = IEEE80211_IF_TYPE_MGMT; - skb_queue_purge(&priv->tx_queue); - return err; - } + memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); p54_set_filter(dev, 0, priv->mac_addr, NULL, 0, 1, 0, 0xF642); p54_set_filter(dev, 0, priv->mac_addr, NULL, 1, 0, 0, 0xF642); - p54_set_vdcf(dev); switch (conf->type) { case IEEE80211_IF_TYPE_STA: p54_set_filter(dev, 1, priv->mac_addr, NULL, 0, 0x15F, 0x1F4, 0); break; + default: + BUG(); /* impossible */ + break; } p54_set_leds(dev, 1, 0, 0); @@ -820,15 +839,9 @@ static void p54_remove_interface(struct ieee80211_hw *dev, struct ieee80211_if_init_conf *conf) { struct p54_common *priv = dev->priv; - struct sk_buff *skb; - while ((skb = skb_dequeue(&priv->tx_queue))) { - struct memrecord *range = (struct memrecord *)&skb->cb; - if (range->control) - kfree(range->control); - kfree_skb(skb); - } - priv->mode = IEEE80211_IF_TYPE_MGMT; - priv->stop(dev); + priv->mode = IEEE80211_IF_TYPE_MNTR; + memset(priv->mac_addr, 0, ETH_ALEN); + p54_set_filter(dev, 0, priv->mac_addr, NULL, 2, 0, 0, 0); } static int p54_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) @@ -848,9 +861,29 @@ static int p54_config_interface(struct ieee80211_hw *dev, int if_id, p54_set_filter(dev, 0, priv->mac_addr, conf->bssid, 0, 1, 0, 0xF642); p54_set_filter(dev, 0, priv->mac_addr, conf->bssid, 2, 0, 0, 0); p54_set_leds(dev, 1, !is_multicast_ether_addr(conf->bssid), 0); + memcpy(priv->bssid, conf->bssid, ETH_ALEN); return 0; } +static void p54_configure_filter(struct ieee80211_hw *dev, + unsigned int changed_flags, + unsigned int *total_flags, + int mc_count, struct dev_mc_list *mclist) +{ + struct p54_common *priv = dev->priv; + + *total_flags &= FIF_BCN_PRBRESP_PROMISC; + + if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { + if (*total_flags & FIF_BCN_PRBRESP_PROMISC) + p54_set_filter(dev, 0, priv->mac_addr, + NULL, 2, 0, 0, 0); + else + p54_set_filter(dev, 0, priv->mac_addr, + priv->bssid, 2, 0, 0, 0); + } +} + static int p54_conf_tx(struct ieee80211_hw *dev, int queue, const struct ieee80211_tx_queue_params *params) { @@ -893,10 +926,13 @@ static int p54_get_tx_stats(struct ieee80211_hw *dev, static const struct ieee80211_ops p54_ops = { .tx = p54_tx, + .start = p54_start, + .stop = p54_stop, .add_interface = p54_add_interface, .remove_interface = p54_remove_interface, .config = p54_config, .config_interface = p54_config_interface, + .configure_filter = p54_configure_filter, .conf_tx = p54_conf_tx, .get_stats = p54_get_stats, .get_tx_stats = p54_get_tx_stats diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 398c20105c8..03a94a33e6b 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -277,54 +277,13 @@ static void rt2400pci_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) rt2x00pci_register_multiwrite(rt2x00dev, CSR5, ®, sizeof(reg)); } -static void rt2400pci_config_packet_filter(struct rt2x00_dev *rt2x00dev, - const unsigned int filter) -{ - int promisc = !!(filter & IFF_PROMISC); - u32 reg; - - rt2x00pci_register_read(rt2x00dev, RXCSR0, ®); - rt2x00_set_field32(®, RXCSR0_DROP_NOT_TO_ME, !promisc); - rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); -} - static void rt2400pci_config_type(struct rt2x00_dev *rt2x00dev, int type) { + struct interface *intf = &rt2x00dev->interface; u32 reg; rt2x00pci_register_write(rt2x00dev, CSR14, 0); - /* - * Apply hardware packet filter. - */ - rt2x00pci_register_read(rt2x00dev, RXCSR0, ®); - - if (!is_monitor_present(&rt2x00dev->interface) && - (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_STA)) - rt2x00_set_field32(®, RXCSR0_DROP_TODS, 1); - else - rt2x00_set_field32(®, RXCSR0_DROP_TODS, 0); - - /* - * If there is a non-monitor interface present - * the packet should be strict (even if a monitor interface is present!). - * When there is only 1 interface present which is in monitor mode - * we should start accepting _all_ frames. - */ - if (is_interface_present(&rt2x00dev->interface)) { - rt2x00_set_field32(®, RXCSR0_DROP_CRC, 1); - rt2x00_set_field32(®, RXCSR0_DROP_PHYSICAL, 1); - rt2x00_set_field32(®, RXCSR0_DROP_CONTROL, 1); - rt2x00_set_field32(®, RXCSR0_DROP_VERSION_ERROR, 1); - } else if (is_monitor_present(&rt2x00dev->interface)) { - rt2x00_set_field32(®, RXCSR0_DROP_CRC, 0); - rt2x00_set_field32(®, RXCSR0_DROP_PHYSICAL, 0); - rt2x00_set_field32(®, RXCSR0_DROP_CONTROL, 0); - rt2x00_set_field32(®, RXCSR0_DROP_VERSION_ERROR, 0); - } - - rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); - /* * Enable beacon config */ @@ -337,20 +296,16 @@ static void rt2400pci_config_type(struct rt2x00_dev *rt2x00dev, int type) * Enable synchronisation. */ rt2x00pci_register_read(rt2x00dev, CSR14, ®); - if (is_interface_present(&rt2x00dev->interface)) { - rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); - rt2x00_set_field32(®, CSR14_TBCN, 1); - } - + rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); + rt2x00_set_field32(®, CSR14_TBCN, 1); rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); - if (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_AP) + if (is_interface_type(intf, IEEE80211_IF_TYPE_IBSS) || + is_interface_type(intf, IEEE80211_IF_TYPE_AP)) rt2x00_set_field32(®, CSR14_TSF_SYNC, 2); - else if (type == IEEE80211_IF_TYPE_STA) + else if (is_interface_type(intf, IEEE80211_IF_TYPE_STA)) rt2x00_set_field32(®, CSR14_TSF_SYNC, 1); - else if (is_monitor_present(&rt2x00dev->interface) && - !is_interface_present(&rt2x00dev->interface)) + else rt2x00_set_field32(®, CSR14_TSF_SYNC, 0); - rt2x00pci_register_write(rt2x00dev, CSR14, reg); } @@ -1104,7 +1059,7 @@ static int rt2400pci_set_device_state(struct rt2x00_dev *rt2x00dev, */ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct data_desc *txd, - struct data_entry_desc *desc, + struct txdata_entry_desc *desc, struct ieee80211_hdr *ieee80211hdr, unsigned int length, struct ieee80211_tx_control *control) @@ -1200,8 +1155,8 @@ static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, /* * RX control handlers */ -static int rt2400pci_fill_rxdone(struct data_entry *entry, - int *signal, int *rssi, int *ofdm, int *size) +static void rt2400pci_fill_rxdone(struct data_entry *entry, + struct rxdata_entry_desc *desc) { struct data_desc *rxd = entry->priv; u32 word0; @@ -1210,20 +1165,20 @@ static int rt2400pci_fill_rxdone(struct data_entry *entry, rt2x00_desc_read(rxd, 0, &word0); rt2x00_desc_read(rxd, 2, &word2); - if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR) || - rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR)) - return -EINVAL; + desc->flags = 0; + if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) + desc->flags |= RX_FLAG_FAILED_FCS_CRC; + if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR)) + desc->flags |= RX_FLAG_FAILED_PLCP_CRC; /* * Obtain the status about this packet. */ - *signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL); - *rssi = rt2x00_get_field32(word2, RXD_W2_RSSI) - + desc->signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL); + desc->rssi = rt2x00_get_field32(word2, RXD_W2_RSSI) - entry->ring->rt2x00dev->rssi_offset; - *ofdm = 0; - *size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); - - return 0; + desc->ofdm = 0; + desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); } /* @@ -1460,10 +1415,7 @@ static void rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) /* * Initialize all hw fields. */ - rt2x00dev->hw->flags = - IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_MONITOR_DURING_OPER | - IEEE80211_HW_NO_PROBE_FILTERING; + rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; rt2x00dev->hw->extra_tx_headroom = 0; rt2x00dev->hw->max_signal = MAX_SIGNAL; rt2x00dev->hw->max_rssi = MAX_RX_SSI; @@ -1530,6 +1482,68 @@ static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * IEEE80211 stack callback functions. */ +static void rt2400pci_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + int mc_count, + struct dev_addr_list *mc_list) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct interface *intf = &rt2x00dev->interface; + u32 reg; + + /* + * Mask off any flags we are going to ignore from + * the total_flags field. + */ + *total_flags &= + FIF_ALLMULTI | + FIF_FCSFAIL | + FIF_PLCPFAIL | + FIF_CONTROL | + FIF_OTHER_BSS | + FIF_PROMISC_IN_BSS; + + /* + * Apply some rules to the filters: + * - Some filters imply different filters to be set. + * - Some things we can't filter out at all. + * - Some filters are set based on interface type. + */ + *total_flags |= FIF_ALLMULTI; + if (changed_flags & FIF_OTHER_BSS || + changed_flags & FIF_PROMISC_IN_BSS) + *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS; + if (is_interface_type(intf, IEEE80211_IF_TYPE_AP)) + *total_flags |= FIF_PROMISC_IN_BSS; + + /* + * Check if there is any work left for us. + */ + if (intf->filter == *total_flags) + return; + intf->filter = *total_flags; + + /* + * Start configuration steps. + * Note that the version error will always be dropped + * since there is no filter for it at this time. + */ + rt2x00pci_register_read(rt2x00dev, RXCSR0, ®); + rt2x00_set_field32(®, RXCSR0_DROP_CRC, + !(*total_flags & FIF_FCSFAIL)); + rt2x00_set_field32(®, RXCSR0_DROP_PHYSICAL, + !(*total_flags & FIF_PLCPFAIL)); + rt2x00_set_field32(®, RXCSR0_DROP_CONTROL, + !(*total_flags & FIF_CONTROL)); + rt2x00_set_field32(®, RXCSR0_DROP_NOT_TO_ME, + !(*total_flags & FIF_PROMISC_IN_BSS)); + rt2x00_set_field32(®, RXCSR0_DROP_TODS, + !(*total_flags & FIF_PROMISC_IN_BSS)); + rt2x00_set_field32(®, RXCSR0_DROP_VERSION_ERROR, 1); + rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); +} + static int rt2400pci_set_retry_limit(struct ieee80211_hw *hw, u32 short_retry, u32 long_retry) { @@ -1602,11 +1616,13 @@ static int rt2400pci_tx_last_beacon(struct ieee80211_hw *hw) static const struct ieee80211_ops rt2400pci_mac80211_ops = { .tx = rt2x00mac_tx, + .start = rt2x00mac_start, + .stop = rt2x00mac_stop, .add_interface = rt2x00mac_add_interface, .remove_interface = rt2x00mac_remove_interface, .config = rt2x00mac_config, .config_interface = rt2x00mac_config_interface, - .set_multicast_list = rt2x00mac_set_multicast_list, + .configure_filter = rt2400pci_configure_filter, .get_stats = rt2x00mac_get_stats, .set_retry_limit = rt2400pci_set_retry_limit, .conf_tx = rt2400pci_conf_tx, @@ -1635,7 +1651,6 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = { .fill_rxdone = rt2400pci_fill_rxdone, .config_mac_addr = rt2400pci_config_mac_addr, .config_bssid = rt2400pci_config_bssid, - .config_packet_filter = rt2400pci_config_packet_filter, .config_type = rt2400pci_config_type, .config = rt2400pci_config, }; diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index e8d63aaab7b..892baa907a6 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -277,58 +277,13 @@ static void rt2500pci_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) rt2x00pci_register_multiwrite(rt2x00dev, CSR5, ®, sizeof(reg)); } -static void rt2500pci_config_packet_filter(struct rt2x00_dev *rt2x00dev, - const unsigned int filter) -{ - int promisc = !!(filter & IFF_PROMISC); - int multicast = !!(filter & IFF_MULTICAST); - int broadcast = !!(filter & IFF_BROADCAST); - u32 reg; - - rt2x00pci_register_read(rt2x00dev, RXCSR0, ®); - rt2x00_set_field32(®, RXCSR0_DROP_NOT_TO_ME, !promisc); - rt2x00_set_field32(®, RXCSR0_DROP_MCAST, !multicast); - rt2x00_set_field32(®, RXCSR0_DROP_BCAST, !broadcast); - rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); -} - static void rt2500pci_config_type(struct rt2x00_dev *rt2x00dev, const int type) { + struct interface *intf = &rt2x00dev->interface; u32 reg; rt2x00pci_register_write(rt2x00dev, CSR14, 0); - /* - * Apply hardware packet filter. - */ - rt2x00pci_register_read(rt2x00dev, RXCSR0, ®); - - if (!is_monitor_present(&rt2x00dev->interface) && - (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_STA)) - rt2x00_set_field32(®, RXCSR0_DROP_TODS, 1); - else - rt2x00_set_field32(®, RXCSR0_DROP_TODS, 0); - - /* - * If there is a non-monitor interface present - * the packet should be strict (even if a monitor interface is present!). - * When there is only 1 interface present which is in monitor mode - * we should start accepting _all_ frames. - */ - if (is_interface_present(&rt2x00dev->interface)) { - rt2x00_set_field32(®, RXCSR0_DROP_CRC, 1); - rt2x00_set_field32(®, RXCSR0_DROP_PHYSICAL, 1); - rt2x00_set_field32(®, RXCSR0_DROP_CONTROL, 1); - rt2x00_set_field32(®, RXCSR0_DROP_VERSION_ERROR, 1); - } else if (is_monitor_present(&rt2x00dev->interface)) { - rt2x00_set_field32(®, RXCSR0_DROP_CRC, 0); - rt2x00_set_field32(®, RXCSR0_DROP_PHYSICAL, 0); - rt2x00_set_field32(®, RXCSR0_DROP_CONTROL, 0); - rt2x00_set_field32(®, RXCSR0_DROP_VERSION_ERROR, 0); - } - - rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); - /* * Enable beacon config */ @@ -345,20 +300,16 @@ static void rt2500pci_config_type(struct rt2x00_dev *rt2x00dev, const int type) * Enable synchronisation. */ rt2x00pci_register_read(rt2x00dev, CSR14, ®); - if (is_interface_present(&rt2x00dev->interface)) { - rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); - rt2x00_set_field32(®, CSR14_TBCN, 1); - } - + rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); + rt2x00_set_field32(®, CSR14_TBCN, 1); rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); - if (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_AP) + if (is_interface_type(intf, IEEE80211_IF_TYPE_IBSS) || + is_interface_type(intf, IEEE80211_IF_TYPE_AP)) rt2x00_set_field32(®, CSR14_TSF_SYNC, 2); - else if (type == IEEE80211_IF_TYPE_STA) + else if (is_interface_type(intf, IEEE80211_IF_TYPE_STA)) rt2x00_set_field32(®, CSR14_TSF_SYNC, 1); - else if (is_monitor_present(&rt2x00dev->interface) && - !is_interface_present(&rt2x00dev->interface)) + else rt2x00_set_field32(®, CSR14_TSF_SYNC, 0); - rt2x00pci_register_write(rt2x00dev, CSR14, reg); } @@ -1269,7 +1220,7 @@ static int rt2500pci_set_device_state(struct rt2x00_dev *rt2x00dev, */ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct data_desc *txd, - struct data_entry_desc *desc, + struct txdata_entry_desc *desc, struct ieee80211_hdr *ieee80211hdr, unsigned int length, struct ieee80211_tx_control *control) @@ -1349,8 +1300,8 @@ static void rt2500pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, /* * RX control handlers */ -static int rt2500pci_fill_rxdone(struct data_entry *entry, - int *signal, int *rssi, int *ofdm, int *size) +static void rt2500pci_fill_rxdone(struct data_entry *entry, + struct rxdata_entry_desc *desc) { struct data_desc *rxd = entry->priv; u32 word0; @@ -1359,18 +1310,17 @@ static int rt2500pci_fill_rxdone(struct data_entry *entry, rt2x00_desc_read(rxd, 0, &word0); rt2x00_desc_read(rxd, 2, &word2); - if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR) || - rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR) || - rt2x00_get_field32(word0, RXD_W0_ICV_ERROR)) - return -EINVAL; + desc->flags = 0; + if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) + desc->flags |= RX_FLAG_FAILED_FCS_CRC; + if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR)) + desc->flags |= RX_FLAG_FAILED_PLCP_CRC; - *signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL); - *rssi = rt2x00_get_field32(word2, RXD_W2_RSSI) - + desc->signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL); + desc->rssi = rt2x00_get_field32(word2, RXD_W2_RSSI) - entry->ring->rt2x00dev->rssi_offset; - *ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); - *size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); - - return 0; + desc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); + desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); } /* @@ -1779,10 +1729,7 @@ static void rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) /* * Initialize all hw fields. */ - rt2x00dev->hw->flags = - IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_MONITOR_DURING_OPER | - IEEE80211_HW_NO_PROBE_FILTERING; + rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; rt2x00dev->hw->extra_tx_headroom = 0; rt2x00dev->hw->max_signal = MAX_SIGNAL; rt2x00dev->hw->max_rssi = MAX_RX_SSI; @@ -1867,6 +1814,73 @@ static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * IEEE80211 stack callback functions. */ +static void rt2500pci_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + int mc_count, + struct dev_addr_list *mc_list) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct interface *intf = &rt2x00dev->interface; + u32 reg; + + /* + * Mask off any flags we are going to ignore from + * the total_flags field. + */ + *total_flags &= + FIF_ALLMULTI | + FIF_FCSFAIL | + FIF_PLCPFAIL | + FIF_CONTROL | + FIF_OTHER_BSS | + FIF_PROMISC_IN_BSS; + + /* + * Apply some rules to the filters: + * - Some filters imply different filters to be set. + * - Some things we can't filter out at all. + * - Some filters are set based on interface type. + */ + if (mc_count) + *total_flags |= FIF_ALLMULTI; + if (changed_flags & FIF_OTHER_BSS || + changed_flags & FIF_PROMISC_IN_BSS) + *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS; + if (is_interface_type(intf, IEEE80211_IF_TYPE_AP)) + *total_flags |= FIF_PROMISC_IN_BSS; + + /* + * Check if there is any work left for us. + */ + if (intf->filter == *total_flags) + return; + intf->filter = *total_flags; + + /* + * Start configuration steps. + * Note that the version error will always be dropped + * and broadcast frames will always be accepted since + * there is no filter for it at this time. + */ + rt2x00pci_register_read(rt2x00dev, RXCSR0, ®); + rt2x00_set_field32(®, RXCSR0_DROP_CRC, + !(*total_flags & FIF_FCSFAIL)); + rt2x00_set_field32(®, RXCSR0_DROP_PHYSICAL, + !(*total_flags & FIF_PLCPFAIL)); + rt2x00_set_field32(®, RXCSR0_DROP_CONTROL, + !(*total_flags & FIF_CONTROL)); + rt2x00_set_field32(®, RXCSR0_DROP_NOT_TO_ME, + !(*total_flags & FIF_PROMISC_IN_BSS)); + rt2x00_set_field32(®, RXCSR0_DROP_TODS, + !(*total_flags & FIF_PROMISC_IN_BSS)); + rt2x00_set_field32(®, RXCSR0_DROP_VERSION_ERROR, 1); + rt2x00_set_field32(®, RXCSR0_DROP_MCAST, + !(*total_flags & FIF_ALLMULTI)); + rt2x00_set_field32(®, RXCSR0_DROP_BCAST, 0); + rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); +} + static int rt2500pci_set_retry_limit(struct ieee80211_hw *hw, u32 short_retry, u32 long_retry) { @@ -1914,11 +1928,13 @@ static int rt2500pci_tx_last_beacon(struct ieee80211_hw *hw) static const struct ieee80211_ops rt2500pci_mac80211_ops = { .tx = rt2x00mac_tx, + .start = rt2x00mac_start, + .stop = rt2x00mac_stop, .add_interface = rt2x00mac_add_interface, .remove_interface = rt2x00mac_remove_interface, .config = rt2x00mac_config, .config_interface = rt2x00mac_config_interface, - .set_multicast_list = rt2x00mac_set_multicast_list, + .configure_filter = rt2500pci_configure_filter, .get_stats = rt2x00mac_get_stats, .set_retry_limit = rt2500pci_set_retry_limit, .conf_tx = rt2x00mac_conf_tx, @@ -1947,7 +1963,6 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = { .fill_rxdone = rt2500pci_fill_rxdone, .config_mac_addr = rt2500pci_config_mac_addr, .config_bssid = rt2500pci_config_bssid, - .config_packet_filter = rt2500pci_config_packet_filter, .config_type = rt2500pci_config_type, .config = rt2500pci_config, }; diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 614600c5510..f4e6f6eb7fb 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -282,65 +282,20 @@ static void rt2500usb_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) rt2500usb_register_multiwrite(rt2x00dev, MAC_CSR5, ®, sizeof(reg)); } -static void rt2500usb_config_packet_filter(struct rt2x00_dev *rt2x00dev, - const unsigned int filter) -{ - int promisc = !!(filter & IFF_PROMISC); - int multicast = !!(filter & IFF_MULTICAST); - int broadcast = !!(filter & IFF_BROADCAST); - u16 reg; - - rt2500usb_register_read(rt2x00dev, TXRX_CSR2, ®); - rt2x00_set_field16(®, TXRX_CSR2_DROP_NOT_TO_ME, !promisc); - rt2x00_set_field16(®, TXRX_CSR2_DROP_MULTICAST, !multicast); - rt2x00_set_field16(®, TXRX_CSR2_DROP_BROADCAST, !broadcast); - rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg); -} - static void rt2500usb_config_type(struct rt2x00_dev *rt2x00dev, const int type) { + struct interface *intf = &rt2x00dev->interface; u16 reg; rt2500usb_register_write(rt2x00dev, TXRX_CSR19, 0); - /* - * Apply hardware packet filter. - */ - rt2500usb_register_read(rt2x00dev, TXRX_CSR2, ®); - - if (!is_monitor_present(&rt2x00dev->interface) && - (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_STA)) - rt2x00_set_field16(®, TXRX_CSR2_DROP_TODS, 1); - else - rt2x00_set_field16(®, TXRX_CSR2_DROP_TODS, 0); - - /* - * If there is a non-monitor interface present - * the packet should be strict (even if a monitor interface is present!). - * When there is only 1 interface present which is in monitor mode - * we should start accepting _all_ frames. - */ - if (is_interface_present(&rt2x00dev->interface)) { - rt2x00_set_field16(®, TXRX_CSR2_DROP_CRC, 1); - rt2x00_set_field16(®, TXRX_CSR2_DROP_PHYSICAL, 1); - rt2x00_set_field16(®, TXRX_CSR2_DROP_CONTROL, 1); - rt2x00_set_field16(®, TXRX_CSR2_DROP_VERSION_ERROR, 1); - } else if (is_monitor_present(&rt2x00dev->interface)) { - rt2x00_set_field16(®, TXRX_CSR2_DROP_CRC, 0); - rt2x00_set_field16(®, TXRX_CSR2_DROP_PHYSICAL, 0); - rt2x00_set_field16(®, TXRX_CSR2_DROP_CONTROL, 0); - rt2x00_set_field16(®, TXRX_CSR2_DROP_VERSION_ERROR, 0); - } - - rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg); - /* * Enable beacon config */ rt2500usb_register_read(rt2x00dev, TXRX_CSR20, ®); rt2x00_set_field16(®, TXRX_CSR20_OFFSET, (PREAMBLE + get_duration(IEEE80211_HEADER, 2)) >> 6); - if (type == IEEE80211_IF_TYPE_STA) + if (is_interface_type(intf, IEEE80211_IF_TYPE_STA)) rt2x00_set_field16(®, TXRX_CSR20_BCN_EXPECT_WINDOW, 0); else rt2x00_set_field16(®, TXRX_CSR20_BCN_EXPECT_WINDOW, 2); @@ -354,20 +309,16 @@ static void rt2500usb_config_type(struct rt2x00_dev *rt2x00dev, const int type) rt2500usb_register_write(rt2x00dev, TXRX_CSR18, reg); rt2500usb_register_read(rt2x00dev, TXRX_CSR19, ®); - if (is_interface_present(&rt2x00dev->interface)) { - rt2x00_set_field16(®, TXRX_CSR19_TSF_COUNT, 1); - rt2x00_set_field16(®, TXRX_CSR19_TBCN, 1); - } - + rt2x00_set_field16(®, TXRX_CSR19_TSF_COUNT, 1); + rt2x00_set_field16(®, TXRX_CSR19_TBCN, 1); rt2x00_set_field16(®, TXRX_CSR19_BEACON_GEN, 0); - if (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_AP) + if (is_interface_type(intf, IEEE80211_IF_TYPE_IBSS) || + is_interface_type(intf, IEEE80211_IF_TYPE_AP)) rt2x00_set_field16(®, TXRX_CSR19_TSF_SYNC, 2); - else if (type == IEEE80211_IF_TYPE_STA) + else if (is_interface_type(intf, IEEE80211_IF_TYPE_STA)) rt2x00_set_field16(®, TXRX_CSR19_TSF_SYNC, 1); - else if (is_monitor_present(&rt2x00dev->interface) && - !is_interface_present(&rt2x00dev->interface)) + else rt2x00_set_field16(®, TXRX_CSR19_TSF_SYNC, 0); - rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg); } @@ -1084,7 +1035,7 @@ static int rt2500usb_set_device_state(struct rt2x00_dev *rt2x00dev, */ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct data_desc *txd, - struct data_entry_desc *desc, + struct txdata_entry_desc *desc, struct ieee80211_hdr *ieee80211hdr, unsigned int length, struct ieee80211_tx_control *control) @@ -1156,8 +1107,8 @@ static void rt2500usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, /* * RX control handlers */ -static int rt2500usb_fill_rxdone(struct data_entry *entry, - int *signal, int *rssi, int *ofdm, int *size) +static void rt2500usb_fill_rxdone(struct data_entry *entry, + struct rxdata_entry_desc *desc) { struct urb *urb = entry->priv; struct data_desc *rxd = (struct data_desc *)(entry->skb->data + @@ -1169,21 +1120,22 @@ static int rt2500usb_fill_rxdone(struct data_entry *entry, rt2x00_desc_read(rxd, 0, &word0); rt2x00_desc_read(rxd, 1, &word1); - if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR) || - rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR) || - rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR)) - return -EINVAL; + desc->flags = 0; + if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) + desc->flags |= RX_FLAG_FAILED_FCS_CRC; + if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR)) + desc->flags |= RX_FLAG_FAILED_PLCP_CRC; /* * Obtain the status about this packet. */ - *signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL); - *rssi = rt2x00_get_field32(word1, RXD_W1_RSSI) - + desc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL); + desc->rssi = rt2x00_get_field32(word1, RXD_W1_RSSI) - entry->ring->rt2x00dev->rssi_offset; - *ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); - *size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); + desc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); + desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); - return 0; + return; } /* @@ -1549,9 +1501,7 @@ static void rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) rt2x00dev->hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_MONITOR_DURING_OPER | - IEEE80211_HW_NO_PROBE_FILTERING; + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE; rt2x00dev->hw->max_signal = MAX_SIGNAL; rt2x00dev->hw->max_rssi = MAX_RX_SSI; @@ -1621,10 +1571,8 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev) rt2500usb_probe_hw_mode(rt2x00dev); /* - * USB devices require scheduled packet filter toggling - *This device requires the beacon ring + * This device requires the beacon ring */ - __set_bit(PACKET_FILTER_SCHEDULED, &rt2x00dev->flags); __set_bit(REQUIRE_BEACON_RING, &rt2x00dev->flags); /* @@ -1638,6 +1586,82 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev) /* * IEEE80211 stack callback functions. */ +static void rt2500usb_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + int mc_count, + struct dev_addr_list *mc_list) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct interface *intf = &rt2x00dev->interface; + u16 reg; + + /* + * Mask off any flags we are going to ignore from + * the total_flags field. + */ + *total_flags &= + FIF_ALLMULTI | + FIF_FCSFAIL | + FIF_PLCPFAIL | + FIF_CONTROL | + FIF_OTHER_BSS | + FIF_PROMISC_IN_BSS; + + /* + * Apply some rules to the filters: + * - Some filters imply different filters to be set. + * - Some things we can't filter out at all. + * - Some filters are set based on interface type. + */ + if (mc_count) + *total_flags |= FIF_ALLMULTI; + if (changed_flags & FIF_OTHER_BSS || + changed_flags & FIF_PROMISC_IN_BSS) + *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS; + if (is_interface_type(intf, IEEE80211_IF_TYPE_AP)) + *total_flags |= FIF_PROMISC_IN_BSS; + + /* + * Check if there is any work left for us. + */ + if (intf->filter == *total_flags) + return; + intf->filter = *total_flags; + + /* + * When in atomic context, reschedule and let rt2x00lib + * call this function again. + */ + if (in_atomic()) { + queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->filter_work); + return; + } + + /* + * Start configuration steps. + * Note that the version error will always be dropped + * and broadcast frames will always be accepted since + * there is no filter for it at this time. + */ + rt2500usb_register_read(rt2x00dev, TXRX_CSR2, ®); + rt2x00_set_field16(®, TXRX_CSR2_DROP_CRC, + !(*total_flags & FIF_FCSFAIL)); + rt2x00_set_field16(®, TXRX_CSR2_DROP_PHYSICAL, + !(*total_flags & FIF_PLCPFAIL)); + rt2x00_set_field16(®, TXRX_CSR2_DROP_CONTROL, + !(*total_flags & FIF_CONTROL)); + rt2x00_set_field16(®, TXRX_CSR2_DROP_NOT_TO_ME, + !(*total_flags & FIF_PROMISC_IN_BSS)); + rt2x00_set_field16(®, TXRX_CSR2_DROP_TODS, + !(*total_flags & FIF_PROMISC_IN_BSS)); + rt2x00_set_field16(®, TXRX_CSR2_DROP_VERSION_ERROR, 1); + rt2x00_set_field16(®, TXRX_CSR2_DROP_MULTICAST, + !(*total_flags & FIF_ALLMULTI)); + rt2x00_set_field16(®, TXRX_CSR2_DROP_BROADCAST, 0); + rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg); +} + static int rt2500usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_tx_control *control) @@ -1714,11 +1738,13 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw, static const struct ieee80211_ops rt2500usb_mac80211_ops = { .tx = rt2x00mac_tx, + .start = rt2x00mac_start, + .stop = rt2x00mac_stop, .add_interface = rt2x00mac_add_interface, .remove_interface = rt2x00mac_remove_interface, .config = rt2x00mac_config, .config_interface = rt2x00mac_config_interface, - .set_multicast_list = rt2x00mac_set_multicast_list, + .configure_filter = rt2500usb_configure_filter, .get_stats = rt2x00mac_get_stats, .conf_tx = rt2x00mac_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, @@ -1739,7 +1765,6 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = { .fill_rxdone = rt2500usb_fill_rxdone, .config_mac_addr = rt2500usb_config_mac_addr, .config_bssid = rt2500usb_config_bssid, - .config_packet_filter = rt2500usb_config_packet_filter, .config_type = rt2500usb_config_type, .config = rt2500usb_config, }; diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 80b079d723d..046eecfb16c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -294,9 +294,6 @@ struct interface { /* * Current working type (IEEE80211_IF_TYPE_*). - * This excludes the type IEEE80211_IF_TYPE_MNTR - * since that is counted seperately in the monitor_count - * field. * When set to INVALID_INTERFACE, no interface is configured. */ int type; @@ -314,18 +311,8 @@ struct interface { /* * Store the packet filter mode for the current interface. - * monitor mode always disabled filtering. But in such - * cases we still need to store the value here in case - * the monitor mode interfaces are removed, while a - * non-monitor mode interface remains. */ - unsigned short filter; - - /* - * Monitor mode count, the number of interfaces - * in monitor mode that that have been added. - */ - unsigned short monitor_count; + unsigned int filter; }; static inline int is_interface_present(struct interface *intf) @@ -333,9 +320,9 @@ static inline int is_interface_present(struct interface *intf) return !!intf->id; } -static inline int is_monitor_present(struct interface *intf) +static inline int is_interface_type(struct interface *intf, int type) { - return !!intf->monitor_count; + return intf->type == type; } /* @@ -402,7 +389,7 @@ struct rt2x00lib_ops { */ void (*write_tx_desc) (struct rt2x00_dev *rt2x00dev, struct data_desc *txd, - struct data_entry_desc *desc, + struct txdata_entry_desc *desc, struct ieee80211_hdr *ieee80211hdr, unsigned int length, struct ieee80211_tx_control *control); @@ -415,8 +402,8 @@ struct rt2x00lib_ops { /* * RX control handlers */ - int (*fill_rxdone) (struct data_entry *entry, - int *signal, int *rssi, int *ofdm, int *size); + void (*fill_rxdone) (struct data_entry *entry, + struct rxdata_entry_desc *desc); /* * Configuration handlers. @@ -511,11 +498,10 @@ struct rt2x00_dev { #define DEVICE_INITIALIZED 3 #define DEVICE_INITIALIZED_HW 4 #define REQUIRE_FIRMWARE 5 -#define PACKET_FILTER_SCHEDULED 6 -#define PACKET_FILTER_PENDING 7 +/* Hole: Add new Flag here */ #define INTERFACE_RESUME 8 #define INTERFACE_ENABLED 9 -#define INTERFACE_ENABLED_MONITOR 10 +/* Hole: Add new Flag here */ #define REQUIRE_BEACON_RING 11 #define DEVICE_SUPPORT_HW_BUTTON 12 #define CONFIG_FRAME_TYPE 13 @@ -606,9 +592,10 @@ struct rt2x00_dev { struct ieee80211_rx_status rx_status; /* - * Beacon scheduled work. + * Scheduled work. */ struct work_struct beacon_work; + struct work_struct filter_work; /* * Data ring arrays for RX, TX and Beacon. @@ -760,7 +747,7 @@ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev); void rt2x00lib_txdone(struct data_entry *entry, const int status, const int retry); void rt2x00lib_rxdone(struct data_entry *entry, struct sk_buff *skb, - const int signal, const int rssi, const int ofdm); + struct rxdata_entry_desc *desc); /* * TX descriptor initializer @@ -785,8 +772,6 @@ void rt2x00mac_remove_interface(struct ieee80211_hw *hw, int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf); int rt2x00mac_config_interface(struct ieee80211_hw *hw, int if_id, struct ieee80211_if_conf *conf); -void rt2x00mac_set_multicast_list(struct ieee80211_hw *hw, - unsigned short flags, int mc_count); int rt2x00mac_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats); int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index de890a17d8f..f962ce49708 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -46,72 +46,24 @@ void rt2x00lib_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) rt2x00dev->ops->lib->config_bssid(rt2x00dev, bssid); } -void rt2x00lib_config_packet_filter(struct rt2x00_dev *rt2x00dev, int filter) -{ - /* - * Only configure the device when something has changed, - * or if we are in RESUME state in which case all configuration - * will be forced upon the device. - */ - if (!test_bit(INTERFACE_RESUME, &rt2x00dev->flags) && - !test_bit(PACKET_FILTER_PENDING, &rt2x00dev->flags)) - return; - - /* - * Write configuration to device and clear the update flag. - */ - rt2x00dev->ops->lib->config_packet_filter(rt2x00dev, filter); - __clear_bit(PACKET_FILTER_PENDING, &rt2x00dev->flags); -} - void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, int type) { struct interface *intf = &rt2x00dev->interface; - /* - * Fallback when a invalid interface is attempted to - * be configured. If a monitor interface is present, - * we are going configure that, otherwise exit. - */ - if (type == INVALID_INTERFACE) { - if (is_monitor_present(intf)) - type = IEEE80211_IF_TYPE_MNTR; - else - return; - } - - /* - * Only configure the device when something has changed, - * or if we are in RESUME state in which case all configuration - * will be forced upon the device. - */ if (!test_bit(INTERFACE_RESUME, &rt2x00dev->flags) && - (!(is_interface_present(intf) ^ - test_bit(INTERFACE_ENABLED, &rt2x00dev->flags)) && - !(is_monitor_present(intf) ^ - test_bit(INTERFACE_ENABLED_MONITOR, &rt2x00dev->flags)))) + (!!test_bit(INTERFACE_ENABLED, &rt2x00dev->flags) == + !!is_interface_present(intf))) return; - /* - * Configure device. - */ rt2x00dev->ops->lib->config_type(rt2x00dev, type); /* * Update the configuration flags. */ - if (type != IEEE80211_IF_TYPE_MNTR) { - if (is_interface_present(intf)) - __set_bit(INTERFACE_ENABLED, &rt2x00dev->flags); - else - __clear_bit(INTERFACE_ENABLED, &rt2x00dev->flags); - } else { - if (is_monitor_present(intf)) - __set_bit(INTERFACE_ENABLED_MONITOR, &rt2x00dev->flags); - else - __clear_bit(INTERFACE_ENABLED_MONITOR, - &rt2x00dev->flags); - } + if (is_interface_present(intf)) + __set_bit(INTERFACE_ENABLED, &rt2x00dev->flags); + else + __clear_bit(INTERFACE_ENABLED, &rt2x00dev->flags); } void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, struct ieee80211_conf *conf) diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index cd82eeface8..bbccb893387 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -135,10 +135,12 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev) return; /* - * Stop beacon generation. + * Stop all scheduled work. */ if (work_pending(&rt2x00dev->beacon_work)) cancel_work_sync(&rt2x00dev->beacon_work); + if (work_pending(&rt2x00dev->filter_work)) + cancel_work_sync(&rt2x00dev->filter_work); /* * Stop the TX queues. @@ -257,6 +259,17 @@ static void rt2x00lib_link_tuner(struct work_struct *work) LINK_TUNE_INTERVAL); } +static void rt2x00lib_packetfilter_scheduled(struct work_struct *work) +{ + struct rt2x00_dev *rt2x00dev = + container_of(work, struct rt2x00_dev, filter_work); + + rt2x00dev->ops->hw->configure_filter(rt2x00dev->hw, + rt2x00dev->interface.filter, + &rt2x00dev->interface.filter, + 0, NULL); +} + /* * Interrupt context handlers. */ @@ -337,7 +350,7 @@ void rt2x00lib_txdone(struct data_entry *entry, EXPORT_SYMBOL_GPL(rt2x00lib_txdone); void rt2x00lib_rxdone(struct data_entry *entry, struct sk_buff *skb, - const int signal, const int rssi, const int ofdm) + struct rxdata_entry_desc *desc) { struct rt2x00_dev *rt2x00dev = entry->ring->rt2x00dev; struct ieee80211_rx_status *rx_status = &rt2x00dev->rx_status; @@ -358,22 +371,24 @@ void rt2x00lib_rxdone(struct data_entry *entry, struct sk_buff *skb, * the signal is the PLCP value. If it was received with * a CCK bitrate the signal is the rate in 0.5kbit/s. */ - if (!ofdm) + if (!desc->ofdm) val = DEVICE_GET_RATE_FIELD(rate->val, RATE); else val = DEVICE_GET_RATE_FIELD(rate->val, PLCP); - if (val == signal) { + if (val == desc->signal) { val = rate->val; break; } } - rt2x00_update_link_rssi(&rt2x00dev->link, rssi); + rt2x00_update_link_rssi(&rt2x00dev->link, desc->rssi); rt2x00dev->link.rx_success++; rx_status->rate = val; - rx_status->signal = rt2x00lib_calculate_link_signal(rt2x00dev, rssi); - rx_status->ssi = rssi; + rx_status->signal = + rt2x00lib_calculate_link_signal(rt2x00dev, desc->rssi); + rx_status->ssi = desc->rssi; + rx_status->flag = desc->flags; /* * Send frame to mac80211 @@ -391,7 +406,7 @@ void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev, unsigned int length, struct ieee80211_tx_control *control) { - struct data_entry_desc desc; + struct txdata_entry_desc desc; struct data_ring *ring; int tx_rate; int bitrate; @@ -956,6 +971,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) * Initialize configuration work. */ INIT_WORK(&rt2x00dev->beacon_work, rt2x00lib_beacondone_scheduled); + INIT_WORK(&rt2x00dev->filter_work, rt2x00lib_packetfilter_scheduled); INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00lib_link_tuner); /* @@ -1098,7 +1114,6 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) rt2x00lib_config_mac_addr(rt2x00dev, intf->mac); rt2x00lib_config_bssid(rt2x00dev, intf->bssid); rt2x00lib_config_type(rt2x00dev, intf->type); - rt2x00lib_config_packet_filter(rt2x00dev, intf->filter); /* * When in Master or Ad-hoc mode, diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index 3324090a96a..fcc2ffdd1a3 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -51,7 +51,6 @@ void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev); */ void rt2x00lib_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *mac); void rt2x00lib_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid); -void rt2x00lib_config_packet_filter(struct rt2x00_dev *rt2x00dev, int filter); void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, int type); void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, struct ieee80211_conf *conf); diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 778ed41e21e..17802f6d3d6 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -176,46 +176,26 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, { struct rt2x00_dev *rt2x00dev = hw->priv; struct interface *intf = &rt2x00dev->interface; - int retval; /* * We only support 1 non-monitor interface. */ - if (conf->type != IEEE80211_IF_TYPE_MNTR && is_interface_present(intf)) + if (is_interface_present(intf)) return -ENOBUFS; - /* - * HACK: Placeholder until start/stop handler has been - * added to the mac80211 callback functions structure. - */ - retval = rt2x00mac_start(hw); - if (retval) - return retval; - - /* - * We support muliple monitor mode interfaces. - * All we need to do is increase the monitor_count. - */ - if (conf->type == IEEE80211_IF_TYPE_MNTR) { - intf->monitor_count++; - } else { - intf->id = conf->if_id; - intf->type = conf->type; - if (conf->type == IEEE80211_IF_TYPE_AP) - memcpy(&intf->bssid, conf->mac_addr, ETH_ALEN); - memcpy(&intf->mac, conf->mac_addr, ETH_ALEN); - intf->filter = 0; - } + intf->id = conf->if_id; + intf->type = conf->type; + if (conf->type == IEEE80211_IF_TYPE_AP) + memcpy(&intf->bssid, conf->mac_addr, ETH_ALEN); + memcpy(&intf->mac, conf->mac_addr, ETH_ALEN); /* - * Configure interface. * The MAC adddress must be configured after the device - * has been initialized. Else the device can reset the - * MAC registers. + * has been initialized. Otherwise the device can reset + * the MAC registers. */ rt2x00lib_config_mac_addr(rt2x00dev, intf->mac); rt2x00lib_config_type(rt2x00dev, conf->type); - rt2x00lib_config_packet_filter(rt2x00dev, intf->filter); return 0; } @@ -230,22 +210,13 @@ void rt2x00mac_remove_interface(struct ieee80211_hw *hw, /* * We only support 1 non-monitor interface. */ - if (conf->type != IEEE80211_IF_TYPE_MNTR && !is_interface_present(intf)) + if (!is_interface_present(intf)) return; - /* - * When removing an monitor interface, decrease monitor_count. - * For non-monitor interfaces, all interface data needs to be reset. - */ - if (conf->type == IEEE80211_IF_TYPE_MNTR) { - intf->monitor_count--; - } else if (intf->type == conf->type) { - intf->id = 0; - intf->type = INVALID_INTERFACE; - memset(&intf->bssid, 0x00, ETH_ALEN); - memset(&intf->mac, 0x00, ETH_ALEN); - intf->filter = 0; - } + intf->id = 0; + intf->type = INVALID_INTERFACE; + memset(&intf->bssid, 0x00, ETH_ALEN); + memset(&intf->mac, 0x00, ETH_ALEN); /* * Make sure the bssid and mac address registers @@ -254,12 +225,6 @@ void rt2x00mac_remove_interface(struct ieee80211_hw *hw, rt2x00lib_config_mac_addr(rt2x00dev, intf->mac); rt2x00lib_config_bssid(rt2x00dev, intf->bssid); rt2x00lib_config_type(rt2x00dev, intf->type); - - /* - * HACK: Placeholder untill start/stop handler has been - * added to the mac80211 callback functions structure. - */ - rt2x00mac_stop(hw); } EXPORT_SYMBOL_GPL(rt2x00mac_remove_interface); @@ -289,14 +254,6 @@ int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) rt2x00lib_config(rt2x00dev, conf); - /* - * If promisc mode cannot be configured in irq context, - * then it is now the time to configure it. - */ - if (test_bit(PACKET_FILTER_SCHEDULED, &rt2x00dev->flags)) - rt2x00lib_config_packet_filter(rt2x00dev, - rt2x00dev->interface.filter); - /* * Reenable RX only if the radio should be on. */ @@ -326,13 +283,10 @@ int rt2x00mac_config_interface(struct ieee80211_hw *hw, int if_id, return 0; /* - * Monitor mode does not need configuring. * If the given type does not match the configured type, * there has been a problem. */ - if (conf->type == IEEE80211_IF_TYPE_MNTR) - return 0; - else if (conf->type != intf->type) + if (conf->type != intf->type) return -EINVAL; /* @@ -360,36 +314,6 @@ int rt2x00mac_config_interface(struct ieee80211_hw *hw, int if_id, } EXPORT_SYMBOL_GPL(rt2x00mac_config_interface); -void rt2x00mac_set_multicast_list(struct ieee80211_hw *hw, - unsigned short flags, int mc_count) -{ - struct rt2x00_dev *rt2x00dev = hw->priv; - - /* - * Check if the new state is different then the old state. - */ - if (rt2x00dev->interface.filter == flags) - return; - - rt2x00dev->interface.filter = flags; - - /* - * Raise the pending bit to indicate the - * packet filter should be updated. - */ - __set_bit(PACKET_FILTER_PENDING, &rt2x00dev->flags); - - /* - * Check if Packet filter actions are allowed in - * atomic context. If not, raise the pending flag and - * let it be. - */ - if (!test_bit(PACKET_FILTER_SCHEDULED, &rt2x00dev->flags) || - !in_atomic()) - rt2x00lib_config_packet_filter(rt2x00dev, flags); -} -EXPORT_SYMBOL_GPL(rt2x00mac_set_multicast_list); - int rt2x00mac_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats) { diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index 85629f1999a..2780df00623 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -124,47 +124,40 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) struct data_entry *entry; struct data_desc *rxd; struct sk_buff *skb; - u32 desc; - int retval; - int signal; - int rssi; - int ofdm; - int size; + struct rxdata_entry_desc desc; + u32 word; while (1) { entry = rt2x00_get_data_entry(ring); rxd = entry->priv; - rt2x00_desc_read(rxd, 0, &desc); + rt2x00_desc_read(rxd, 0, &word); - if (rt2x00_get_field32(desc, RXD_ENTRY_OWNER_NIC)) + if (rt2x00_get_field32(word, RXD_ENTRY_OWNER_NIC)) break; - retval = rt2x00dev->ops->lib->fill_rxdone(entry, &signal, - &rssi, &ofdm, &size); - if (retval) - goto skip_entry; + memset(&desc, 0x00, sizeof(desc)); + rt2x00dev->ops->lib->fill_rxdone(entry, &desc); /* * Allocate the sk_buffer, initialize it and copy * all data into it. */ - skb = dev_alloc_skb(size + NET_IP_ALIGN); + skb = dev_alloc_skb(desc.size + NET_IP_ALIGN); if (!skb) return; skb_reserve(skb, NET_IP_ALIGN); - skb_put(skb, size); - memcpy(skb->data, entry->data_addr, size); + skb_put(skb, desc.size); + memcpy(skb->data, entry->data_addr, desc.size); /* * Send the frame to rt2x00lib for further processing. */ - rt2x00lib_rxdone(entry, skb, signal, rssi, ofdm); + rt2x00lib_rxdone(entry, skb, &desc); -skip_entry: if (test_bit(DEVICE_ENABLED_RADIO, &ring->rt2x00dev->flags)) { - rt2x00_set_field32(&desc, RXD_ENTRY_OWNER_NIC, 1); - rt2x00_desc_write(rxd, 0, desc); + rt2x00_set_field32(&word, RXD_ENTRY_OWNER_NIC, 1); + rt2x00_desc_write(rxd, 0, word); } rt2x00_ring_index_inc(ring); diff --git a/drivers/net/wireless/rt2x00/rt2x00rfkill.c b/drivers/net/wireless/rt2x00/rt2x00rfkill.c index dc5b696f475..b54457c921c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00rfkill.c +++ b/drivers/net/wireless/rt2x00/rt2x00rfkill.c @@ -45,11 +45,9 @@ static int rt2x00rfkill_toggle_radio(void *data, enum rfkill_state state) return 0; /* - * Only continue if we have an active interface, - * either monitor or non-monitor should be present. + * Only continue if we have an active interface. */ - if (!is_interface_present(&rt2x00dev->interface) && - !is_monitor_present(&rt2x00dev->interface)) + if (!is_interface_present(&rt2x00dev->interface)) return 0; if (state == RFKILL_STATE_ON) { diff --git a/drivers/net/wireless/rt2x00/rt2x00ring.h b/drivers/net/wireless/rt2x00/rt2x00ring.h index 122c75248e7..1a864d32cfb 100644 --- a/drivers/net/wireless/rt2x00/rt2x00ring.h +++ b/drivers/net/wireless/rt2x00/rt2x00ring.h @@ -41,11 +41,24 @@ struct data_desc { }; /* - * data_entry_desc + * rxdata_entry_desc + * Summary of information that has been read from the + * RX frame descriptor. + */ +struct rxdata_entry_desc { + int signal; + int rssi; + int ofdm; + int size; + int flags; +}; + +/* + * txdata_entry_desc * Summary of information that should be written into the * descriptor for sending a TX frame. */ -struct data_entry_desc { +struct txdata_entry_desc { unsigned long flags; #define ENTRY_TXDONE 1 #define ENTRY_TXD_RTS_FRAME 2 diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index a0f05ca54bb..8d208118902 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -220,11 +220,7 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb) struct data_ring *ring = entry->ring; struct rt2x00_dev *rt2x00dev = ring->rt2x00dev; struct sk_buff *skb; - int retval; - int signal; - int rssi; - int ofdm; - int size; + struct rxdata_entry_desc desc; int frame_size; if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) || @@ -239,10 +235,8 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb) if (urb->actual_length < entry->ring->desc_size || urb->status) goto skip_entry; - retval = rt2x00dev->ops->lib->fill_rxdone(entry, &signal, &rssi, - &ofdm, &size); - if (retval) - goto skip_entry; + memset(&desc, 0x00, sizeof(desc)); + rt2x00dev->ops->lib->fill_rxdone(entry, &desc); /* * Allocate a new sk buffer to replace the current one. @@ -261,12 +255,12 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb) * Trim the skb_buffer to only contain the valid * frame data (so ignore the device's descriptor). */ - skb_trim(entry->skb, size); + skb_trim(entry->skb, desc.size); /* * Send the frame to rt2x00lib for further processing. */ - rt2x00lib_rxdone(entry, entry->skb, signal, rssi, ofdm); + rt2x00lib_rxdone(entry, entry->skb, &desc); /* * Replace current entry's skb with the newly allocated one, diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 09c8c96e2f8..dea7a8a4fa0 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -312,23 +312,9 @@ static void rt61pci_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) rt2x00pci_register_multiwrite(rt2x00dev, MAC_CSR4, ®, sizeof(reg)); } -static void rt61pci_config_packet_filter(struct rt2x00_dev *rt2x00dev, - const unsigned int filter) -{ - int promisc = !!(filter & IFF_PROMISC); - int multicast = !!(filter & IFF_MULTICAST); - int broadcast = !!(filter & IFF_BROADCAST); - u32 reg; - - rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®); - rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME, !promisc); - rt2x00_set_field32(®, TXRX_CSR0_DROP_MULTICAST, !multicast); - rt2x00_set_field32(®, TXRX_CSR0_DROP_BORADCAST, !broadcast); - rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); -} - static void rt61pci_config_type(struct rt2x00_dev *rt2x00dev, const int type) { + struct interface *intf = &rt2x00dev->interface; u32 reg; /* @@ -343,57 +329,20 @@ static void rt61pci_config_type(struct rt2x00_dev *rt2x00dev, const int type) rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE2, 0); rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE3, 0); - /* - * Apply hardware packet filter. - */ - rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®); - - if (!is_monitor_present(&rt2x00dev->interface) && - (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_STA)) - rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, 1); - else - rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, 0); - - /* - * If there is a non-monitor interface present - * the packet should be strict (even if a monitor interface is present!). - * When there is only 1 interface present which is in monitor mode - * we should start accepting _all_ frames. - */ - if (is_interface_present(&rt2x00dev->interface)) { - rt2x00_set_field32(®, TXRX_CSR0_DROP_CRC, 1); - rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, 1); - rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL, 1); - rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 1); - rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS, 1); - } else if (is_monitor_present(&rt2x00dev->interface)) { - rt2x00_set_field32(®, TXRX_CSR0_DROP_CRC, 0); - rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, 0); - rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL, 0); - rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 0); - rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS, 0); - } - - rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); - /* * Enable synchronisation. */ rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®); - if (is_interface_present(&rt2x00dev->interface)) { - rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); - rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); - } - + rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); + rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); - if (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_AP) + if (is_interface_type(intf, IEEE80211_IF_TYPE_IBSS) || + is_interface_type(intf, IEEE80211_IF_TYPE_AP)) rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 2); - else if (type == IEEE80211_IF_TYPE_STA) + else if (is_interface_type(intf, IEEE80211_IF_TYPE_STA)) rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 1); - else if (is_monitor_present(&rt2x00dev->interface) && - !is_interface_present(&rt2x00dev->interface)) + else rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 0); - rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); } @@ -1686,7 +1635,7 @@ static int rt61pci_set_device_state(struct rt2x00_dev *rt2x00dev, */ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct data_desc *txd, - struct data_entry_desc *desc, + struct txdata_entry_desc *desc, struct ieee80211_hdr *ieee80211hdr, unsigned int length, struct ieee80211_tx_control *control) @@ -1826,8 +1775,8 @@ static int rt61pci_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1) return rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_AGC) * 2 - offset; } -static int rt61pci_fill_rxdone(struct data_entry *entry, - int *signal, int *rssi, int *ofdm, int *size) +static void rt61pci_fill_rxdone(struct data_entry *entry, + struct rxdata_entry_desc *desc) { struct data_desc *rxd = entry->priv; u32 word0; @@ -1836,19 +1785,19 @@ static int rt61pci_fill_rxdone(struct data_entry *entry, rt2x00_desc_read(rxd, 0, &word0); rt2x00_desc_read(rxd, 1, &word1); - if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR) || - rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR)) - return -EINVAL; + desc->flags = 0; + if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) + desc->flags |= RX_FLAG_FAILED_FCS_CRC; /* * Obtain the status about this packet. */ - *signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL); - *rssi = rt61pci_agc_to_rssi(entry->ring->rt2x00dev, word1); - *ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); - *size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); + desc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL); + desc->rssi = rt61pci_agc_to_rssi(entry->ring->rt2x00dev, word1); + desc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); + desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); - return 0; + return; } /* @@ -2340,9 +2289,7 @@ static void rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) */ rt2x00dev->hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | - IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_MONITOR_DURING_OPER | - IEEE80211_HW_NO_PROBE_FILTERING; + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; rt2x00dev->hw->extra_tx_headroom = 0; rt2x00dev->hw->max_signal = MAX_SIGNAL; rt2x00dev->hw->max_rssi = MAX_RX_SSI; @@ -2426,6 +2373,74 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * IEEE80211 stack callback functions. */ +static void rt61pci_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + int mc_count, + struct dev_addr_list *mc_list) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct interface *intf = &rt2x00dev->interface; + u32 reg; + + /* + * Mask off any flags we are going to ignore from + * the total_flags field. + */ + *total_flags &= + FIF_ALLMULTI | + FIF_FCSFAIL | + FIF_PLCPFAIL | + FIF_CONTROL | + FIF_OTHER_BSS | + FIF_PROMISC_IN_BSS; + + /* + * Apply some rules to the filters: + * - Some filters imply different filters to be set. + * - Some things we can't filter out at all. + * - Some filters are set based on interface type. + */ + if (mc_count) + *total_flags |= FIF_ALLMULTI; + if (changed_flags & FIF_OTHER_BSS || + changed_flags & FIF_PROMISC_IN_BSS) + *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS; + if (is_interface_type(intf, IEEE80211_IF_TYPE_AP)) + *total_flags |= FIF_PROMISC_IN_BSS; + + /* + * Check if there is any work left for us. + */ + if (intf->filter == *total_flags) + return; + intf->filter = *total_flags; + + /* + * Start configuration steps. + * Note that the version error will always be dropped + * and broadcast frames will always be accepted since + * there is no filter for it at this time. + */ + rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®); + rt2x00_set_field32(®, TXRX_CSR0_DROP_CRC, + !(*total_flags & FIF_FCSFAIL)); + rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, + !(*total_flags & FIF_PLCPFAIL)); + rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL, + !(*total_flags & FIF_CONTROL)); + rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME, + !(*total_flags & FIF_PROMISC_IN_BSS)); + rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, + !(*total_flags & FIF_PROMISC_IN_BSS)); + rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 1); + rt2x00_set_field32(®, TXRX_CSR0_DROP_MULTICAST, + !(*total_flags & FIF_ALLMULTI)); + rt2x00_set_field32(®, TXRX_CSR0_DROP_BORADCAST, 0); + rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS, 1); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); +} + static int rt61pci_set_retry_limit(struct ieee80211_hw *hw, u32 short_retry, u32 long_retry) { @@ -2506,11 +2521,13 @@ int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, static const struct ieee80211_ops rt61pci_mac80211_ops = { .tx = rt2x00mac_tx, + .start = rt2x00mac_start, + .stop = rt2x00mac_stop, .add_interface = rt2x00mac_add_interface, .remove_interface = rt2x00mac_remove_interface, .config = rt2x00mac_config, .config_interface = rt2x00mac_config_interface, - .set_multicast_list = rt2x00mac_set_multicast_list, + .configure_filter = rt61pci_configure_filter, .get_stats = rt2x00mac_get_stats, .set_retry_limit = rt61pci_set_retry_limit, .conf_tx = rt2x00mac_conf_tx, @@ -2540,7 +2557,6 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = { .fill_rxdone = rt61pci_fill_rxdone, .config_mac_addr = rt61pci_config_mac_addr, .config_bssid = rt61pci_config_bssid, - .config_packet_filter = rt61pci_config_packet_filter, .config_type = rt61pci_config_type, .config = rt61pci_config, }; diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 3397881bd63..aac13aa4039 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -293,23 +293,9 @@ static void rt73usb_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) rt73usb_register_multiwrite(rt2x00dev, MAC_CSR4, ®, sizeof(reg)); } -static void rt73usb_config_packet_filter(struct rt2x00_dev *rt2x00dev, - const unsigned int filter) -{ - int promisc = !!(filter & IFF_PROMISC); - int multicast = !!(filter & IFF_MULTICAST); - int broadcast = !!(filter & IFF_BROADCAST); - u32 reg; - - rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); - rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME, !promisc); - rt2x00_set_field32(®, TXRX_CSR0_DROP_MULTICAST, !multicast); - rt2x00_set_field32(®, TXRX_CSR0_DROP_BORADCAST, !broadcast); - rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg); -} - static void rt73usb_config_type(struct rt2x00_dev *rt2x00dev, const int type) { + struct interface *intf = &rt2x00dev->interface; u32 reg; /* @@ -324,57 +310,20 @@ static void rt73usb_config_type(struct rt2x00_dev *rt2x00dev, const int type) rt73usb_register_write(rt2x00dev, HW_BEACON_BASE2, 0); rt73usb_register_write(rt2x00dev, HW_BEACON_BASE3, 0); - /* - * Apply hardware packet filter. - */ - rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); - - if (!is_monitor_present(&rt2x00dev->interface) && - (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_STA)) - rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, 1); - else - rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, 0); - - /* - * If there is a non-monitor interface present - * the packet should be strict (even if a monitor interface is present!). - * When there is only 1 interface present which is in monitor mode - * we should start accepting _all_ frames. - */ - if (is_interface_present(&rt2x00dev->interface)) { - rt2x00_set_field32(®, TXRX_CSR0_DROP_CRC, 1); - rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, 1); - rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL, 1); - rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 1); - rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS, 1); - } else if (is_monitor_present(&rt2x00dev->interface)) { - rt2x00_set_field32(®, TXRX_CSR0_DROP_CRC, 0); - rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, 0); - rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL, 0); - rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 0); - rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS, 0); - } - - rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg); - /* * Enable synchronisation. */ rt73usb_register_read(rt2x00dev, TXRX_CSR9, ®); - if (is_interface_present(&rt2x00dev->interface)) { - rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); - rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); - } - + rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); + rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); - if (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_AP) + if (is_interface_type(intf, IEEE80211_IF_TYPE_IBSS) || + is_interface_type(intf, IEEE80211_IF_TYPE_AP)) rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 2); - else if (type == IEEE80211_IF_TYPE_STA) + else if (is_interface_type(intf, IEEE80211_IF_TYPE_STA)) rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 1); - else if (is_monitor_present(&rt2x00dev->interface) && - !is_interface_present(&rt2x00dev->interface)) + else rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 0); - rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg); } @@ -1301,7 +1250,7 @@ static int rt73usb_set_device_state(struct rt2x00_dev *rt2x00dev, */ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct data_desc *txd, - struct data_entry_desc *desc, + struct txdata_entry_desc *desc, struct ieee80211_hdr *ieee80211hdr, unsigned int length, struct ieee80211_tx_control *control) @@ -1429,8 +1378,8 @@ static int rt73usb_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1) return rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_AGC) * 2 - offset; } -static int rt73usb_fill_rxdone(struct data_entry *entry, - int *signal, int *rssi, int *ofdm, int *size) +static void rt73usb_fill_rxdone(struct data_entry *entry, + struct rxdata_entry_desc *desc) { struct data_desc *rxd = (struct data_desc *)entry->skb->data; u32 word0; @@ -1439,24 +1388,24 @@ static int rt73usb_fill_rxdone(struct data_entry *entry, rt2x00_desc_read(rxd, 0, &word0); rt2x00_desc_read(rxd, 1, &word1); - if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR) || - rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR)) - return -EINVAL; + desc->flags = 0; + if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) + desc->flags |= RX_FLAG_FAILED_FCS_CRC; /* * Obtain the status about this packet. */ - *signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL); - *rssi = rt73usb_agc_to_rssi(entry->ring->rt2x00dev, word1); - *ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); - *size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); + desc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL); + desc->rssi = rt73usb_agc_to_rssi(entry->ring->rt2x00dev, word1); + desc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); + desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); /* * Pull the skb to clear the descriptor area. */ skb_pull(entry->skb, entry->ring->desc_size); - return 0; + return; } /* @@ -1802,9 +1751,7 @@ static void rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) */ rt2x00dev->hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | - IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_MONITOR_DURING_OPER | - IEEE80211_HW_NO_PROBE_FILTERING; + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE; rt2x00dev->hw->max_signal = MAX_SIGNAL; rt2x00dev->hw->max_rssi = MAX_RX_SSI; @@ -1878,11 +1825,9 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) rt73usb_probe_hw_mode(rt2x00dev); /* - * USB devices require scheduled packet filter toggling * This device requires firmware */ __set_bit(REQUIRE_FIRMWARE, &rt2x00dev->flags); - __set_bit(PACKET_FILTER_SCHEDULED, &rt2x00dev->flags); /* * Set the rssi offset. @@ -1895,6 +1840,83 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) /* * IEEE80211 stack callback functions. */ +static void rt73usb_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + int mc_count, + struct dev_addr_list *mc_list) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct interface *intf = &rt2x00dev->interface; + u32 reg; + + /* + * Mask off any flags we are going to ignore from + * the total_flags field. + */ + *total_flags &= + FIF_ALLMULTI | + FIF_FCSFAIL | + FIF_PLCPFAIL | + FIF_CONTROL | + FIF_OTHER_BSS | + FIF_PROMISC_IN_BSS; + + /* + * Apply some rules to the filters: + * - Some filters imply different filters to be set. + * - Some things we can't filter out at all. + * - Some filters are set based on interface type. + */ + if (mc_count) + *total_flags |= FIF_ALLMULTI; + if (changed_flags & FIF_OTHER_BSS || + changed_flags & FIF_PROMISC_IN_BSS) + *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS; + if (is_interface_type(intf, IEEE80211_IF_TYPE_AP)) + *total_flags |= FIF_PROMISC_IN_BSS; + + /* + * Check if there is any work left for us. + */ + if (intf->filter == *total_flags) + return; + intf->filter = *total_flags; + + /* + * When in atomic context, reschedule and let rt2x00lib + * call this function again. + */ + if (in_atomic()) { + queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->filter_work); + return; + } + + /* + * Start configuration steps. + * Note that the version error will always be dropped + * and broadcast frames will always be accepted since + * there is no filter for it at this time. + */ + rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); + rt2x00_set_field32(®, TXRX_CSR0_DROP_CRC, + !(*total_flags & FIF_FCSFAIL)); + rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, + !(*total_flags & FIF_PLCPFAIL)); + rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL, + !(*total_flags & FIF_CONTROL)); + rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME, + !(*total_flags & FIF_PROMISC_IN_BSS)); + rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, + !(*total_flags & FIF_PROMISC_IN_BSS)); + rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 1); + rt2x00_set_field32(®, TXRX_CSR0_DROP_MULTICAST, + !(*total_flags & FIF_ALLMULTI)); + rt2x00_set_field32(®, TXRX_CSR0_DROP_BROADCAST, 0); + rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS, 1); + rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg); +} + static int rt73usb_set_retry_limit(struct ieee80211_hw *hw, u32 short_retry, u32 long_retry) { @@ -1977,11 +1999,13 @@ int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, static const struct ieee80211_ops rt73usb_mac80211_ops = { .tx = rt2x00mac_tx, + .start = rt2x00mac_start, + .stop = rt2x00mac_stop, .add_interface = rt2x00mac_add_interface, .remove_interface = rt2x00mac_remove_interface, .config = rt2x00mac_config, .config_interface = rt2x00mac_config_interface, - .set_multicast_list = rt2x00mac_set_multicast_list, + .configure_filter = rt73usb_configure_filter, .get_stats = rt2x00mac_get_stats, .set_retry_limit = rt73usb_set_retry_limit, .conf_tx = rt2x00mac_conf_tx, @@ -2012,7 +2036,6 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = { .fill_rxdone = rt73usb_fill_rxdone, .config_mac_addr = rt73usb_config_mac_addr, .config_bssid = rt73usb_config_bssid, - .config_packet_filter = rt73usb_config_packet_filter, .config_type = rt73usb_config_type, .config = rt73usb_config, }; diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h index 5d63a1a714f..f0951519f74 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.h +++ b/drivers/net/wireless/rt2x00/rt73usb.h @@ -290,7 +290,7 @@ struct hw_pairwise_ta_entry { #define TXRX_CSR0_DROP_TO_DS FIELD32(0x00200000) #define TXRX_CSR0_DROP_VERSION_ERROR FIELD32(0x00400000) #define TXRX_CSR0_DROP_MULTICAST FIELD32(0x00800000) -#define TXRX_CSR0_DROP_BORADCAST FIELD32(0x01000000) +#define TXRX_CSR0_DROP_BROADCAST FIELD32(0x01000000) #define TXRX_CSR0_DROP_ACK_CTS FIELD32(0x02000000) #define TXRX_CSR0_TX_WITHOUT_WAITING FIELD32(0x04000000) diff --git a/drivers/net/wireless/rtl8187.h b/drivers/net/wireless/rtl8187.h index 7993b3d8720..6ad322ef0da 100644 --- a/drivers/net/wireless/rtl8187.h +++ b/drivers/net/wireless/rtl8187.h @@ -36,8 +36,7 @@ struct rtl8187_rx_info { }; struct rtl8187_rx_hdr { - __le16 len; - __le16 rate; + __le32 flags; u8 noise; u8 signal; u8 agc; @@ -74,7 +73,7 @@ struct rtl8187_priv { struct ieee80211_rate rates[12]; struct ieee80211_hw_mode modes[2]; struct usb_device *udev; - u8 *hwaddr; + u32 rx_conf; u16 txpwr_base; u8 asic_rev; struct sk_buff_head rx_queue; diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index bf9f0cc5a64..b0a92f543da 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c @@ -41,6 +41,57 @@ static struct usb_device_id rtl8187_table[] __devinitdata = { MODULE_DEVICE_TABLE(usb, rtl8187_table); +static void rtl8187_iowrite_async_cb(struct urb *urb) +{ + kfree(urb->context); + usb_free_urb(urb); +} + +static void rtl8187_iowrite_async(struct rtl8187_priv *priv, __le16 addr, + void *data, u16 len) +{ + struct usb_ctrlrequest *dr; + struct urb *urb; + struct rtl8187_async_write_data { + u8 data[4]; + struct usb_ctrlrequest dr; + } *buf; + + buf = kmalloc(sizeof(*buf), GFP_ATOMIC); + if (!buf) + return; + + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!urb) { + kfree(buf); + return; + } + + dr = &buf->dr; + + dr->bRequestType = RTL8187_REQT_WRITE; + dr->bRequest = RTL8187_REQ_SET_REG; + dr->wValue = addr; + dr->wIndex = 0; + dr->wLength = cpu_to_le16(len); + + memcpy(buf, data, len); + + usb_fill_control_urb(urb, priv->udev, usb_sndctrlpipe(priv->udev, 0), + (unsigned char *)dr, buf, len, + rtl8187_iowrite_async_cb, buf); + usb_submit_urb(urb, GFP_ATOMIC); +} + +static inline void rtl818x_iowrite32_async(struct rtl8187_priv *priv, + __le32 *addr, u32 val) +{ + __le32 buf = cpu_to_le32(val); + + rtl8187_iowrite_async(priv, cpu_to_le16((unsigned long)addr), + &buf, sizeof(buf)); +} + void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data) { struct rtl8187_priv *priv = dev->priv; @@ -125,6 +176,7 @@ static void rtl8187_rx_cb(struct urb *urb) struct rtl8187_rx_hdr *hdr; struct ieee80211_rx_status rx_status = { 0 }; int rate, signal; + u32 flags; spin_lock(&priv->rx_queue.lock); if (skb->next) @@ -143,10 +195,11 @@ static void rtl8187_rx_cb(struct urb *urb) skb_put(skb, urb->actual_length); hdr = (struct rtl8187_rx_hdr *)(skb_tail_pointer(skb) - sizeof(*hdr)); - skb_trim(skb, le16_to_cpu(hdr->len) & 0x0FFF); + flags = le32_to_cpu(hdr->flags); + skb_trim(skb, flags & 0x0FFF); signal = hdr->agc >> 1; - rate = (le16_to_cpu(hdr->rate) >> 4) & 0xF; + rate = (flags >> 20) & 0xF; if (rate > 3) { /* OFDM rate */ if (signal > 90) signal = 90; @@ -169,6 +222,8 @@ static void rtl8187_rx_cb(struct urb *urb) rx_status.channel = dev->conf.channel; rx_status.phymode = dev->conf.phymode; rx_status.mactime = le64_to_cpu(hdr->mac_time); + if (flags & (1 << 13)) + rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; ieee80211_rx_irqsafe(dev, skb, &rx_status); skb = dev_alloc_skb(RTL8187_MAX_RX); @@ -293,8 +348,6 @@ static int rtl8187_init_hw(struct ieee80211_hw *dev) rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0); rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); - for (i = 0; i < ETH_ALEN; i++) - rtl818x_iowrite8(priv, &priv->map->MAC[i], priv->hwaddr[i]); rtl818x_iowrite16(priv, (__le16 *)0xFFF4, 0xFFFF); reg = rtl818x_ioread8(priv, &priv->map->CONFIG1); @@ -365,7 +418,7 @@ static void rtl8187_set_channel(struct ieee80211_hw *dev, int channel) rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg); } -static int rtl8187_open(struct ieee80211_hw *dev) +static int rtl8187_start(struct ieee80211_hw *dev) { struct rtl8187_priv *priv = dev->priv; u32 reg; @@ -383,16 +436,13 @@ static int rtl8187_open(struct ieee80211_hw *dev) RTL818X_RX_CONF_RX_AUTORESETPHY | RTL818X_RX_CONF_BSSID | RTL818X_RX_CONF_MGMT | - RTL818X_RX_CONF_CTRL | RTL818X_RX_CONF_DATA | (7 << 13 /* RX FIFO threshold NONE */) | (7 << 10 /* MAX RX DMA */) | RTL818X_RX_CONF_BROADCAST | - RTL818X_RX_CONF_MULTICAST | RTL818X_RX_CONF_NICMAC; - if (priv->mode == IEEE80211_IF_TYPE_MNTR) - reg |= RTL818X_RX_CONF_MONITOR; + priv->rx_conf = reg; rtl818x_iowrite32(priv, &priv->map->RX_CONF, reg); reg = rtl818x_ioread8(priv, &priv->map->CW_CONF); @@ -419,7 +469,7 @@ static int rtl8187_open(struct ieee80211_hw *dev) return 0; } -static int rtl8187_stop(struct ieee80211_hw *dev) +static void rtl8187_stop(struct ieee80211_hw *dev) { struct rtl8187_priv *priv = dev->priv; struct rtl8187_rx_info *info; @@ -445,28 +495,31 @@ static int rtl8187_stop(struct ieee80211_hw *dev) usb_kill_urb(info->urb); kfree_skb(skb); } - return 0; + return; } static int rtl8187_add_interface(struct ieee80211_hw *dev, struct ieee80211_if_init_conf *conf) { struct rtl8187_priv *priv = dev->priv; + int i; - /* NOTE: using IEEE80211_IF_TYPE_MGMT to indicate no mode selected */ - if (priv->mode != IEEE80211_IF_TYPE_MGMT) - return -1; + if (priv->mode != IEEE80211_IF_TYPE_MNTR) + return -EOPNOTSUPP; switch (conf->type) { case IEEE80211_IF_TYPE_STA: - case IEEE80211_IF_TYPE_MNTR: priv->mode = conf->type; break; default: return -EOPNOTSUPP; } - priv->hwaddr = conf->mac_addr ? conf->mac_addr : dev->wiphy->perm_addr; + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + for (i = 0; i < ETH_ALEN; i++) + rtl818x_iowrite8(priv, &priv->map->MAC[i], + ((u8 *)conf->mac_addr)[i]); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); return 0; } @@ -475,7 +528,7 @@ static void rtl8187_remove_interface(struct ieee80211_hw *dev, struct ieee80211_if_init_conf *conf) { struct rtl8187_priv *priv = dev->priv; - priv->mode = IEEE80211_IF_TYPE_MGMT; + priv->mode = IEEE80211_IF_TYPE_MNTR; } static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) @@ -523,14 +576,52 @@ static int rtl8187_config_interface(struct ieee80211_hw *dev, int if_id, return 0; } +static void rtl8187_configure_filter(struct ieee80211_hw *dev, + unsigned int changed_flags, + unsigned int *total_flags, + int mc_count, struct dev_addr_list *mc_list) +{ + struct rtl8187_priv *priv = dev->priv; + + *total_flags = 0; + + if (changed_flags & FIF_PROMISC_IN_BSS) + priv->rx_conf ^= RTL818X_RX_CONF_NICMAC; + if (changed_flags & FIF_ALLMULTI) + priv->rx_conf ^= RTL818X_RX_CONF_MULTICAST; + if (changed_flags & FIF_FCSFAIL) + priv->rx_conf ^= RTL818X_RX_CONF_FCS; + if (changed_flags & FIF_CONTROL) + priv->rx_conf ^= RTL818X_RX_CONF_CTRL; + if (changed_flags & FIF_OTHER_BSS) + priv->rx_conf ^= RTL818X_RX_CONF_MONITOR; + + if (mc_count > 0) + priv->rx_conf |= RTL818X_RX_CONF_MULTICAST; + + if (priv->rx_conf & RTL818X_RX_CONF_NICMAC) + *total_flags |= FIF_PROMISC_IN_BSS; + if (priv->rx_conf & RTL818X_RX_CONF_MULTICAST) + *total_flags |= FIF_ALLMULTI; + if (priv->rx_conf & RTL818X_RX_CONF_FCS) + *total_flags |= FIF_FCSFAIL; + if (priv->rx_conf & RTL818X_RX_CONF_CTRL) + *total_flags |= FIF_CONTROL; + if (priv->rx_conf & RTL818X_RX_CONF_MONITOR) + *total_flags |= FIF_OTHER_BSS; + + rtl818x_iowrite32_async(priv, &priv->map->RX_CONF, priv->rx_conf); +} + static const struct ieee80211_ops rtl8187_ops = { .tx = rtl8187_tx, - .open = rtl8187_open, + .start = rtl8187_start, .stop = rtl8187_stop, .add_interface = rtl8187_add_interface, .remove_interface = rtl8187_remove_interface, .config = rtl8187_config, .config_interface = rtl8187_config_interface, + .configure_filter = rtl8187_configure_filter, }; static void rtl8187_eeprom_register_read(struct eeprom_93cx6 *eeprom) @@ -604,7 +695,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, priv->modes[1].rates = priv->rates; priv->modes[1].num_channels = ARRAY_SIZE(rtl818x_channels); priv->modes[1].channels = priv->channels; - priv->mode = IEEE80211_IF_TYPE_MGMT; + priv->mode = IEEE80211_IF_TYPE_MNTR; dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | IEEE80211_HW_RX_INCLUDES_FCS; dev->extra_tx_headroom = sizeof(struct rtl8187_tx_hdr); diff --git a/drivers/net/wireless/rtl818x.h b/drivers/net/wireless/rtl818x.h index 283de30628e..880d4becae3 100644 --- a/drivers/net/wireless/rtl818x.h +++ b/drivers/net/wireless/rtl818x.h @@ -71,6 +71,7 @@ struct rtl818x_csr { #define RTL818X_RX_CONF_NICMAC (1 << 1) #define RTL818X_RX_CONF_MULTICAST (1 << 2) #define RTL818X_RX_CONF_BROADCAST (1 << 3) +#define RTL818X_RX_CONF_FCS (1 << 5) #define RTL818X_RX_CONF_DATA (1 << 18) #define RTL818X_RX_CONF_CTRL (1 << 19) #define RTL818X_RX_CONF_MGMT (1 << 20) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 5ff45553a98..855754d4c50 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -467,7 +467,6 @@ enum ieee80211_if_types { * @mac_addr: pointer to MAC address of the interface. This pointer is valid * until the interface is removed (i.e. it cannot be used after * remove_interface() callback was called for this interface). - * This pointer will be %NULL for monitor interfaces, be careful. * * This structure is used in add_interface() and remove_interface() * callbacks of &struct ieee80211_hw. @@ -653,13 +652,9 @@ struct ieee80211_hw { /* hole at 8 */ - /* Device is capable of performing full monitor mode even during - * normal operation. */ -#define IEEE80211_HW_MONITOR_DURING_OPER (1<<9) +/* hole at 9 */ - /* Device does not need BSSID filter set to broadcast in order to - * receive all probe responses while scanning */ -#define IEEE80211_HW_NO_PROBE_FILTERING (1<<10) +/* hole at 10 */ /* Channels are already configured to the default regulatory domain * specified in the device's EEPROM */ @@ -694,6 +689,39 @@ static inline void SET_IEEE80211_PERM_ADDR(struct ieee80211_hw *hw, u8 *addr) memcpy(hw->wiphy->perm_addr, addr, ETH_ALEN); } +/* + * flags for change_filter_flags() + * + * Note that e.g. if PROMISC_IN_BSS is unset then + * you should still do MAC address filtering if + * possible even if OTHER_BSS is set to indicate + * no BSSID filtering should be done. + */ +/* + * promiscuous mode within your BSS, + * think of the BSS as your network segment and then this corresponds + * to the regular ethernet device promiscuous mode + */ +#define FIF_PROMISC_IN_BSS 0x01 +/* show all multicast frames */ +#define FIF_ALLMULTI 0x02 +/* show frames with failed FCS, but set RX_FLAG_FAILED_FCS_CRC for them */ +#define FIF_FCSFAIL 0x04 +/* show frames with failed PLCP CRC, but set RX_FLAG_FAILED_PLCP_CRC for them */ +#define FIF_PLCPFAIL 0x08 +/* + * This flag is set during scanning to indicate to the hardware + * that it should not filter beacons or probe responses by BSSID. + */ +#define FIF_BCN_PRBRESP_PROMISC 0x10 +/* + * show control frames, if PROMISC_IN_BSS is not set then + * only those addressed to this station + */ +#define FIF_CONTROL 0x20 +/* show frames from other BSSes */ +#define FIF_OTHER_BSS 0x40 + /* Configuration block used by the low-level driver to tell the 802.11 code * about supported hardware features and to pass function pointers to callback * functions. */ @@ -706,32 +734,55 @@ struct ieee80211_ops { int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_tx_control *control); - /* Handler that is called when any netdevice attached to the hardware - * device is set UP for the first time. This can be used, e.g., to - * enable interrupts and beacon sending. */ - int (*open)(struct ieee80211_hw *hw); - - /* Handler that is called when the last netdevice attached to the - * hardware device is set DOWN. This can be used, e.g., to disable - * interrupts and beacon sending. */ - int (*stop)(struct ieee80211_hw *hw); - - /* Handler for asking a driver if a new interface can be added (or, - * more exactly, set UP). If the handler returns zero, the interface - * is added. Driver should perform any initialization it needs prior - * to returning zero. By returning non-zero addition of the interface - * is inhibited. Unless monitor_during_oper is set, it is guaranteed - * that monitor interfaces and normal interfaces are mutually - * exclusive. If assigned, the open() handler is called after - * add_interface() if this is the first device added. The - * add_interface() callback has to be assigned because it is the only - * way to obtain the requested MAC address for any interface. + /* + * Called before the first netdevice attached to the hardware + * is enabled. This should turn on the hardware and must turn on + * frame reception (for possibly enabled monitor interfaces.) + * Returns negative error codes, these may be seen in userspace, + * or zero. + * When the device is started it should not have a MAC address + * to avoid acknowledging frames before a non-monitor device + * is added. + * + * Must be implemented. + */ + int (*start)(struct ieee80211_hw *hw); + + /* + * Called after last netdevice attached to the hardware + * is disabled. This should turn off the hardware (at least + * it must turn off frame reception.) + * May be called right after add_interface if that rejects + * an interface. + * + * Must be implemented. + */ + void (*stop)(struct ieee80211_hw *hw); + + /* + * Called when a netdevice attached to the hardware is enabled. + * Because it is not called for monitor mode devices, open() + * and stop() must be implemented. + * The driver should perform any initialization it needs before + * the device can be enabled. The initial configuration for the + * interface is given in the conf parameter. + * + * Must be implemented. */ int (*add_interface)(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf); - /* Notify a driver that an interface is going down. The stop() handler - * is called prior to this if this is a last interface. */ + /* + * Notifies a driver that an interface is going down. The stop() handler + * is called after this if it is the last interface and no monitor + * interfaces are present. + * When all interfaces are removed, the MAC address in the hardware + * must be cleared so the device no longer acknowledges packets, + * the mac_addr member of the conf structure is, however, set to the + * MAC address of the device going away. + * + * Hence, this callback must be implemented. + */ void (*remove_interface)(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf); @@ -744,15 +795,21 @@ struct ieee80211_ops { int (*config_interface)(struct ieee80211_hw *hw, int if_id, struct ieee80211_if_conf *conf); - /* ieee80211 drivers do not have access to the &struct net_device - * that is (are) connected with their device. Hence (and because - * we need to combine the multicast lists and flags for multiple - * virtual interfaces), they cannot assign set_multicast_list. - * The parameters here replace dev->flags and dev->mc_count, - * dev->mc_list is replaced by calling ieee80211_get_mc_list_item. - * Must be atomic. */ - void (*set_multicast_list)(struct ieee80211_hw *hw, - unsigned short flags, int mc_count); + /* + * Configure the device's RX filter. + * + * The multicast address filter must be changed if the hardware flags + * indicate that one is present. + * + * All unsupported flags in 'total_flags' must be cleared, + * clear all bits except those you honoured. + * + * The callback must be implemented and must be atomic. + */ + void (*configure_filter)(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + int mc_count, struct dev_addr_list *mc_list); /* Set TIM bit handler. If the hardware/firmware takes care of beacon * generation, IEEE 802.11 code uses this function to tell the @@ -1155,24 +1212,6 @@ void ieee80211_stop_queues(struct ieee80211_hw *hw); */ void ieee80211_wake_queues(struct ieee80211_hw *hw); -/** - * ieee80211_get_mc_list_item - iteration over items in multicast list - * @hw: pointer as obtained from ieee80211_alloc_hw(). - * @prev: value returned by previous call to ieee80211_get_mc_list_item() or - * NULL to start a new iteration. - * @ptr: pointer to buffer of void * type for internal usage of - * ieee80211_get_mc_list_item(). - * - * Iterates over items in multicast list of given device. To get the first - * item, pass NULL in @prev and in *@ptr. In subsequent calls, pass the - * value returned by previous call in @prev. Don't alter *@ptr during - * iteration. When there are no more items, NULL is returned. - */ -struct dev_mc_list * -ieee80211_get_mc_list_item(struct ieee80211_hw *hw, - struct dev_mc_list *prev, - void **ptr); - /* called by driver to notify scan status completed */ void ieee80211_scan_completed(struct ieee80211_hw *hw); diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 9efb84c47bb..c9948fa58e0 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -165,20 +165,6 @@ IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC); /* VLAN attributes */ IEEE80211_IF_FILE(vlan_id, u.vlan.id, DEC); -/* MONITOR attributes */ -static ssize_t ieee80211_if_fmt_mode( - const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) -{ - struct ieee80211_local *local = sdata->local; - - return scnprintf(buf, buflen, "%s\n", - ((local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER) || - local->open_count == local->monitors) ? - "hard" : "soft"); -} -__IEEE80211_IF_FILE(mode); - - #define DEBUGFS_ADD(name, type)\ sdata->debugfs.type.name = debugfs_create_file(#name, 0444,\ sdata->debugfsdir, sdata, &name##_ops); @@ -242,7 +228,6 @@ static void add_vlan_files(struct ieee80211_sub_if_data *sdata) static void add_monitor_files(struct ieee80211_sub_if_data *sdata) { - DEBUGFS_ADD(mode, monitor); } static void add_files(struct ieee80211_sub_if_data *sdata) @@ -337,7 +322,6 @@ static void del_vlan_files(struct ieee80211_sub_if_data *sdata) static void del_monitor_files(struct ieee80211_sub_if_data *sdata) { - DEBUGFS_DEL(mode, monitor); } static void del_files(struct ieee80211_sub_if_data *sdata, int type) diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 57ec8880bb1..319ec2a1d84 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -53,6 +53,38 @@ static int header_parse_80211(const struct sk_buff *skb, unsigned char *haddr) return ETH_ALEN; } +/* must be called under mdev tx lock */ +static void ieee80211_configure_filter(struct ieee80211_local *local) +{ + unsigned int changed_flags; + unsigned int new_flags = 0; + + if (local->iff_promiscs) + new_flags |= FIF_PROMISC_IN_BSS; + + if (local->iff_allmultis) + new_flags |= FIF_ALLMULTI; + + if (local->monitors) + new_flags |= FIF_CONTROL | + FIF_OTHER_BSS | + FIF_BCN_PRBRESP_PROMISC; + + changed_flags = local->filter_flags ^ new_flags; + + /* be a bit nasty */ + new_flags |= (1<<31); + + local->ops->configure_filter(local_to_hw(local), + changed_flags, &new_flags, + local->mdev->mc_count, + local->mdev->mc_list); + + WARN_ON(new_flags & (1<<31)); + + local->filter_flags = new_flags & ~(1<<31); +} + /* master interface */ static int ieee80211_master_open(struct net_device *dev) @@ -86,6 +118,13 @@ static int ieee80211_master_stop(struct net_device *dev) return 0; } +static void ieee80211_master_set_multicast_list(struct net_device *dev) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + + ieee80211_configure_filter(local); +} + /* management interface */ static void @@ -267,49 +306,6 @@ static inline int identical_mac_addr_allowed(int type1, int type2) type2 == IEEE80211_IF_TYPE_VLAN))); } -/* Check if running monitor interfaces should go to a "soft monitor" mode - * and switch them if necessary. */ -static inline void ieee80211_start_soft_monitor(struct ieee80211_local *local) -{ - struct ieee80211_if_init_conf conf; - - if (local->open_count && local->open_count == local->monitors && - !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER) && - local->ops->remove_interface) { - conf.if_id = -1; - conf.type = IEEE80211_IF_TYPE_MNTR; - conf.mac_addr = NULL; - local->ops->remove_interface(local_to_hw(local), &conf); - } -} - -/* Check if running monitor interfaces should go to a "hard monitor" mode - * and switch them if necessary. */ -static void ieee80211_start_hard_monitor(struct ieee80211_local *local) -{ - struct ieee80211_if_init_conf conf; - - if (local->open_count && local->open_count == local->monitors && - !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) { - conf.if_id = -1; - conf.type = IEEE80211_IF_TYPE_MNTR; - conf.mac_addr = NULL; - local->ops->add_interface(local_to_hw(local), &conf); - } -} - -static void ieee80211_if_open(struct net_device *dev) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - switch (sdata->type) { - case IEEE80211_IF_TYPE_STA: - case IEEE80211_IF_TYPE_IBSS: - sdata->u.sta.flags &= ~IEEE80211_STA_PREV_BSSID_SET; - break; - } -} - static int ieee80211_open(struct net_device *dev) { struct ieee80211_sub_if_data *sdata, *nsdata; @@ -335,84 +331,96 @@ static int ieee80211_open(struct net_device *dev) is_zero_ether_addr(sdata->u.wds.remote_addr)) return -ENOLINK; - if (sdata->type == IEEE80211_IF_TYPE_MNTR && local->open_count && - !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) { - /* run the interface in a "soft monitor" mode */ - local->monitors++; - local->open_count++; - local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP; - return 0; - } - ieee80211_if_open(dev); - ieee80211_start_soft_monitor(local); - - conf.if_id = dev->ifindex; - conf.type = sdata->type; - if (sdata->type == IEEE80211_IF_TYPE_MNTR) - conf.mac_addr = NULL; - else - conf.mac_addr = dev->dev_addr; - res = local->ops->add_interface(local_to_hw(local), &conf); - if (res) { - if (sdata->type == IEEE80211_IF_TYPE_MNTR) - ieee80211_start_hard_monitor(local); - return res; - } - if (local->open_count == 0) { res = 0; - tasklet_enable(&local->tx_pending_tasklet); - tasklet_enable(&local->tasklet); - if (local->ops->open) - res = local->ops->open(local_to_hw(local)); - if (res == 0) { - res = dev_open(local->mdev); - if (res) { - if (local->ops->stop) - local->ops->stop(local_to_hw(local)); - } else { - res = ieee80211_hw_config(local); - if (res && local->ops->stop) - local->ops->stop(local_to_hw(local)); - else if (!res && local->apdev) - dev_open(local->apdev); - } - } - if (res) { - if (local->ops->remove_interface) - local->ops->remove_interface(local_to_hw(local), - &conf); + if (local->ops->start) + res = local->ops->start(local_to_hw(local)); + if (res) return res; - } } - local->open_count++; - if (sdata->type == IEEE80211_IF_TYPE_MNTR) { + switch (sdata->type) { + case IEEE80211_IF_TYPE_MNTR: + /* must be before the call to ieee80211_configure_filter */ local->monitors++; - local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP; - } else { + if (local->monitors == 1) { + netif_tx_lock_bh(local->mdev); + ieee80211_configure_filter(local); + netif_tx_unlock_bh(local->mdev); + + local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP; + ieee80211_hw_config(local); + } + break; + case IEEE80211_IF_TYPE_STA: + case IEEE80211_IF_TYPE_IBSS: + sdata->u.sta.flags &= ~IEEE80211_STA_PREV_BSSID_SET; + /* fall through */ + default: + conf.if_id = dev->ifindex; + conf.type = sdata->type; + conf.mac_addr = dev->dev_addr; + res = local->ops->add_interface(local_to_hw(local), &conf); + if (res && !local->open_count && local->ops->stop) + local->ops->stop(local_to_hw(local)); + if (res) + return res; + ieee80211_if_config(dev); ieee80211_reset_erp_info(dev); ieee80211_enable_keys(sdata); + + if (sdata->type == IEEE80211_IF_TYPE_STA && + !local->user_space_mlme) + netif_carrier_off(dev); + else + netif_carrier_on(dev); } - if (sdata->type == IEEE80211_IF_TYPE_STA && - !local->user_space_mlme) - netif_carrier_off(dev); - else - netif_carrier_on(dev); + if (local->open_count == 0) { + res = dev_open(local->mdev); + WARN_ON(res); + if (local->apdev) { + res = dev_open(local->apdev); + WARN_ON(res); + } + tasklet_enable(&local->tx_pending_tasklet); + tasklet_enable(&local->tasklet); + } + + local->open_count++; netif_start_queue(dev); + return 0; } -static void ieee80211_if_shutdown(struct net_device *dev) +static int ieee80211_stop(struct net_device *dev) { + struct ieee80211_sub_if_data *sdata; struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_if_init_conf conf; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + netif_stop_queue(dev); + + dev_mc_unsync(local->mdev, dev); + + local->open_count--; - ASSERT_RTNL(); switch (sdata->type) { + case IEEE80211_IF_TYPE_MNTR: + local->monitors--; + if (local->monitors == 0) { + netif_tx_lock_bh(local->mdev); + ieee80211_configure_filter(local); + netif_tx_unlock_bh(local->mdev); + + local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP; + ieee80211_hw_config(local); + } + break; case IEEE80211_IF_TYPE_STA: case IEEE80211_IF_TYPE_IBSS: sdata->u.sta.state = IEEE80211_DISABLED; @@ -433,116 +441,61 @@ static void ieee80211_if_shutdown(struct net_device *dev) cancel_delayed_work(&local->scan_work); } flush_workqueue(local->hw.workqueue); - break; - } -} - -static int ieee80211_stop(struct net_device *dev) -{ - struct ieee80211_sub_if_data *sdata; - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - if (sdata->type == IEEE80211_IF_TYPE_MNTR && - local->open_count > 1 && - !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) { - /* remove "soft monitor" interface */ - local->open_count--; - local->monitors--; - if (!local->monitors) - local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP; - return 0; - } - - netif_stop_queue(dev); - ieee80211_if_shutdown(dev); - - if (sdata->type == IEEE80211_IF_TYPE_MNTR) { - local->monitors--; - if (!local->monitors) - local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP; - } else { + /* fall through */ + default: + conf.if_id = dev->ifindex; + conf.type = sdata->type; + conf.mac_addr = dev->dev_addr; /* disable all keys for as long as this netdev is down */ ieee80211_disable_keys(sdata); + local->ops->remove_interface(local_to_hw(local), &conf); } - local->open_count--; if (local->open_count == 0) { if (netif_running(local->mdev)) dev_close(local->mdev); + if (local->apdev) dev_close(local->apdev); + if (local->ops->stop) local->ops->stop(local_to_hw(local)); + tasklet_disable(&local->tx_pending_tasklet); tasklet_disable(&local->tasklet); } - if (local->ops->remove_interface) { - struct ieee80211_if_init_conf conf; - - conf.if_id = dev->ifindex; - conf.type = sdata->type; - conf.mac_addr = dev->dev_addr; - local->ops->remove_interface(local_to_hw(local), &conf); - } - - ieee80211_start_hard_monitor(local); return 0; } -enum netif_tx_lock_class { - TX_LOCK_NORMAL, - TX_LOCK_MASTER, -}; - -static inline void netif_tx_lock_nested(struct net_device *dev, int subclass) -{ - spin_lock_nested(&dev->_xmit_lock, subclass); - dev->xmit_lock_owner = smp_processor_id(); -} - static void ieee80211_set_multicast_list(struct net_device *dev) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - unsigned short flags; + int allmulti, promisc, sdata_allmulti, sdata_promisc; - netif_tx_lock_nested(local->mdev, TX_LOCK_MASTER); - if (((dev->flags & IFF_ALLMULTI) != 0) ^ - ((sdata->flags & IEEE80211_SDATA_ALLMULTI) != 0)) { - if (sdata->flags & IEEE80211_SDATA_ALLMULTI) - local->iff_allmultis--; - else + allmulti = !!(dev->flags & IFF_ALLMULTI); + promisc = !!(dev->flags & IFF_PROMISC); + sdata_allmulti = sdata->flags & IEEE80211_SDATA_ALLMULTI; + sdata_promisc = sdata->flags & IEEE80211_SDATA_PROMISC; + + if (allmulti != sdata_allmulti) { + if (dev->flags & IFF_ALLMULTI) local->iff_allmultis++; + else + local->iff_allmultis--; sdata->flags ^= IEEE80211_SDATA_ALLMULTI; } - if (((dev->flags & IFF_PROMISC) != 0) ^ - ((sdata->flags & IEEE80211_SDATA_PROMISC) != 0)) { - if (sdata->flags & IEEE80211_SDATA_PROMISC) - local->iff_promiscs--; - else + + if (promisc != sdata_promisc) { + if (dev->flags & IFF_PROMISC) local->iff_promiscs++; + else + local->iff_promiscs--; sdata->flags ^= IEEE80211_SDATA_PROMISC; } - if (dev->mc_count != sdata->mc_count) { - local->mc_count = local->mc_count - sdata->mc_count + - dev->mc_count; - sdata->mc_count = dev->mc_count; - } - if (local->ops->set_multicast_list) { - flags = local->mdev->flags; - if (local->iff_allmultis) - flags |= IFF_ALLMULTI; - if (local->iff_promiscs) - flags |= IFF_PROMISC; - read_lock(&local->sub_if_lock); - local->ops->set_multicast_list(local_to_hw(local), flags, - local->mc_count); - read_unlock(&local->sub_if_lock); - } - netif_tx_unlock(local->mdev); + + dev_mc_sync(local->mdev, dev); } static const struct header_ops ieee80211_header_ops = { @@ -612,7 +565,6 @@ static int __ieee80211_if_config(struct net_device *dev, struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_if_conf conf; - static u8 scan_bssid[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; if (!local->ops->config_interface || !netif_running(dev)) return 0; @@ -621,11 +573,7 @@ static int __ieee80211_if_config(struct net_device *dev, conf.type = sdata->type; if (sdata->type == IEEE80211_IF_TYPE_STA || sdata->type == IEEE80211_IF_TYPE_IBSS) { - if (local->sta_scanning && - local->scan_dev == dev) - conf.bssid = scan_bssid; - else - conf.bssid = sdata->u.sta.bssid; + conf.bssid = sdata->u.sta.bssid; conf.ssid = sdata->u.sta.ssid; conf.ssid_len = sdata->u.sta.ssid_len; conf.generic_elem = sdata->u.sta.extra_ie; @@ -722,37 +670,6 @@ void ieee80211_reset_erp_info(struct net_device *dev) IEEE80211_ERP_CHANGE_PREAMBLE); } -struct dev_mc_list *ieee80211_get_mc_list_item(struct ieee80211_hw *hw, - struct dev_mc_list *prev, - void **ptr) -{ - struct ieee80211_local *local = hw_to_local(hw); - struct ieee80211_sub_if_data *sdata = *ptr; - struct dev_mc_list *mc; - - if (!prev) { - WARN_ON(sdata); - sdata = NULL; - } - if (!prev || !prev->next) { - if (sdata) - sdata = list_entry(sdata->list.next, - struct ieee80211_sub_if_data, list); - else - sdata = list_entry(local->sub_if_list.next, - struct ieee80211_sub_if_data, list); - if (&sdata->list != &local->sub_if_list) - mc = sdata->dev->mc_list; - else - mc = NULL; - } else - mc = prev->next; - - *ptr = sdata; - return mc; -} -EXPORT_SYMBOL(ieee80211_get_mc_list_item); - void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_tx_status *status) @@ -1158,8 +1075,12 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST); BUG_ON(!ops->tx); + BUG_ON(!ops->start); + BUG_ON(!ops->stop); BUG_ON(!ops->config); BUG_ON(!ops->add_interface); + BUG_ON(!ops->remove_interface); + BUG_ON(!ops->configure_filter); local->ops = ops; /* for now, mdev needs sub_if_data :/ */ @@ -1206,6 +1127,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, mdev->stop = ieee80211_master_stop; mdev->type = ARPHRD_IEEE80211; mdev->header_ops = &ieee80211_header_ops; + mdev->set_multicast_list = ieee80211_master_set_multicast_list; sdata->type = IEEE80211_IF_TYPE_AP; sdata->dev = mdev; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index c3f6f89755b..74deecd0967 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -297,8 +297,6 @@ struct ieee80211_sub_if_data { struct net_device *dev; struct ieee80211_local *local; - int mc_count; - unsigned int flags; int drop_unencrypted; @@ -411,6 +409,7 @@ struct ieee80211_local { struct net_device *apdev; /* wlan#ap - management frames (hostapd) */ int open_count; int monitors; + unsigned int filter_flags; /* FIF_* */ struct iw_statistics wstats; u8 wstats_flags; int tx_headroom; /* required headroom for hardware/radiotap */ diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 3f0a2faf37d..17455c6a522 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -2662,10 +2662,16 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw) printk(KERN_DEBUG "%s: failed to restore operational" "channel after scan\n", dev->name); - if (!(local->hw.flags & IEEE80211_HW_NO_PROBE_FILTERING) && - ieee80211_if_config(dev)) - printk(KERN_DEBUG "%s: failed to restore operational" - "BSSID after scan\n", dev->name); + + netif_tx_lock_bh(local->mdev); + local->filter_flags &= ~FIF_BCN_PRBRESP_PROMISC; + local->ops->configure_filter(local_to_hw(local), + FIF_BCN_PRBRESP_PROMISC, + &local->filter_flags, + local->mdev->mc_count, + local->mdev->mc_list); + + netif_tx_unlock_bh(local->mdev); memset(&wrqu, 0, sizeof(wrqu)); wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); @@ -2849,10 +2855,14 @@ static int ieee80211_sta_start_scan(struct net_device *dev, local->scan_channel_idx = 0; local->scan_dev = dev; - if (!(local->hw.flags & IEEE80211_HW_NO_PROBE_FILTERING) && - ieee80211_if_config(dev)) - printk(KERN_DEBUG "%s: failed to set BSSID for scan\n", - dev->name); + netif_tx_lock_bh(local->mdev); + local->filter_flags |= FIF_BCN_PRBRESP_PROMISC; + local->ops->configure_filter(local_to_hw(local), + FIF_BCN_PRBRESP_PROMISC, + &local->filter_flags, + local->mdev->mc_count, + local->mdev->mc_list); + netif_tx_unlock_bh(local->mdev); /* TODO: start scan as soon as all nullfunc frames are ACKed */ queue_delayed_work(local->hw.workqueue, &local->scan_work, diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index b5f2e4c25c7..2535d8d4ce9 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1307,7 +1307,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, } else if (!multicast && compare_ether_addr(sdata->dev->dev_addr, hdr->addr1) != 0) { - if (!(sdata->flags & IEEE80211_SDATA_PROMISC)) + if (!(sdata->dev->flags & IFF_PROMISC)) return 0; rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH; } @@ -1322,7 +1322,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, } else if (!multicast && compare_ether_addr(sdata->dev->dev_addr, hdr->addr1) != 0) { - if (!(sdata->flags & IEEE80211_SDATA_PROMISC)) + if (!(sdata->dev->flags & IFF_PROMISC)) return 0; rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH; } else if (!rx->sta) -- cgit v1.2.3-70-g09d2 From ea49c359f36d5b40bf033c45a08332cb73777aa2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 18 Sep 2007 17:29:21 -0400 Subject: [PATCH] mac80211: remove crypto algorithm typedef The typedef is not required, we can just use "enum ieee80211_key_alg" instead of "ieee80211_key_alg" Signed-off-by: Johannes Berg Signed-off-by: Michael Wu Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl3945-base.c | 2 +- drivers/net/wireless/iwlwifi/iwl4965-base.c | 2 +- drivers/net/wireless/iwlwifi/iwlwifi.h | 2 +- include/net/mac80211.h | 12 ++++++------ net/mac80211/ieee80211_key.h | 2 +- net/mac80211/key.c | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 8acda640df2..0700076e55b 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -7293,7 +7293,7 @@ out_unlock: return rc; } -static int iwl_mac_set_key(struct ieee80211_hw *hw, set_key_cmd cmd, +static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, const u8 *local_addr, const u8 *addr, struct ieee80211_key_conf *key) { diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 7b9227c562b..7bc25f74e3a 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -7690,7 +7690,7 @@ out_unlock: return rc; } -static int iwl_mac_set_key(struct ieee80211_hw *hw, set_key_cmd cmd, +static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, const u8 *local_addr, const u8 *addr, struct ieee80211_key_conf *key) { diff --git a/drivers/net/wireless/iwlwifi/iwlwifi.h b/drivers/net/wireless/iwlwifi/iwlwifi.h index 00c79e200c6..e0b97c34121 100644 --- a/drivers/net/wireless/iwlwifi/iwlwifi.h +++ b/drivers/net/wireless/iwlwifi/iwlwifi.h @@ -412,7 +412,7 @@ struct iwl_tid_data { }; struct iwl_hw_key { - ieee80211_key_alg alg; + enum ieee80211_key_alg alg; int keylen; u8 key[32]; }; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index fcca9c39b9e..8fb975f0bed 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -551,12 +551,12 @@ struct ieee80211_if_conf { * @ALG_TKIP: TKIP * @ALG_CCMP: CCMP (AES) */ -typedef enum ieee80211_key_alg { +enum ieee80211_key_alg { ALG_NONE, ALG_WEP, ALG_TKIP, ALG_CCMP, -} ieee80211_key_alg; +}; /** @@ -596,7 +596,7 @@ enum ieee80211_key_flags { * @key: key material */ struct ieee80211_key_conf { - ieee80211_key_alg alg; + enum ieee80211_key_alg alg; u8 hw_key_idx; u8 flags; s8 keyidx; @@ -616,9 +616,9 @@ struct ieee80211_key_conf { * @SET_KEY: a key is set * @DISABLE_KEY: a key must be disabled */ -typedef enum set_key_cmd { +enum set_key_cmd { SET_KEY, DISABLE_KEY, -} set_key_cmd; +}; /** @@ -1014,7 +1014,7 @@ struct ieee80211_ops { unsigned int *total_flags, int mc_count, struct dev_addr_list *mc_list); int (*set_tim)(struct ieee80211_hw *hw, int aid, int set); - int (*set_key)(struct ieee80211_hw *hw, set_key_cmd cmd, + int (*set_key)(struct ieee80211_hw *hw, enum set_key_cmd cmd, const u8 *local_address, const u8 *address, struct ieee80211_key_conf *key); int (*set_ieee8021x)(struct ieee80211_hw *hw, int use_ieee8021x); diff --git a/net/mac80211/ieee80211_key.h b/net/mac80211/ieee80211_key.h index ae49418f18b..fc770e98d47 100644 --- a/net/mac80211/ieee80211_key.h +++ b/net/mac80211/ieee80211_key.h @@ -114,7 +114,7 @@ struct ieee80211_key { struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata, struct sta_info *sta, - ieee80211_key_alg alg, + enum ieee80211_key_alg alg, int idx, size_t key_len, const u8 *key_data); diff --git a/net/mac80211/key.c b/net/mac80211/key.c index c10e53afbb4..f13d46b2c13 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -113,7 +113,7 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata, struct sta_info *sta, - ieee80211_key_alg alg, + enum ieee80211_key_alg alg, int idx, size_t key_len, const u8 *key_data) -- cgit v1.2.3-70-g09d2 From 725d99d4660fcd9abe37d7b733c9412a58465d13 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Tue, 25 Sep 2007 20:53:20 +0200 Subject: [PATCH] rt2x00: Correct error in calculating rssi for link tuner The call to rt2x00lib_precalculate_link_signal resets link.rx_success which is needed when calculating the average rssi for the link tuner. Change the call order so the link tuner runs first as it doesn't need the result of the precalculate. Signed-off-by: Adam Baker Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00dev.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index bbccb893387..4f66adc5b09 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -242,8 +242,6 @@ static void rt2x00lib_link_tuner(struct work_struct *work) rt2x00dev->low_level_stats.dot11FCSErrorCount += rt2x00dev->link.rx_failed; - rt2x00lib_precalculate_link_signal(&rt2x00dev->link); - /* * Only perform the link tuning when Link tuning * has been enabled (This could have been disabled from the EEPROM). @@ -251,6 +249,12 @@ static void rt2x00lib_link_tuner(struct work_struct *work) if (!test_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags)) rt2x00dev->ops->lib->link_tuner(rt2x00dev); + /* + * Precalculate a portion of the link signal which is + * in based on the tx/rx success/failure counters. + */ + rt2x00lib_precalculate_link_signal(&rt2x00dev->link); + /* * Increase tuner counter, and reschedule the next link tuner run. */ -- cgit v1.2.3-70-g09d2 From 2484591049ad1b92f585c1ff1c1d63f41e149faa Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Tue, 25 Sep 2007 20:53:43 +0200 Subject: [PATCH] rt2x00: Make *_beacon_update static Make rt61pci_beacon_update and rt73usb_beacon_update static, they are only used inside their own source file and then only for setting it as callback funtion for mac80211. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt61pci.c | 2 +- drivers/net/wireless/rt2x00/rt73usb.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index dea7a8a4fa0..3edcd743dce 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2477,7 +2477,7 @@ static void rt61pci_reset_tsf(struct ieee80211_hw *hw) rt2x00pci_register_write(rt2x00dev, TXRX_CSR13, 0); } -int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, +static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_tx_control *control) { struct rt2x00_dev *rt2x00dev = hw->priv; diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index aac13aa4039..b18cc934ff8 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1961,7 +1961,7 @@ static void rt73usb_reset_tsf(struct ieee80211_hw *hw) rt73usb_register_write(rt2x00dev, TXRX_CSR13, 0); } -int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, +static int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_tx_control *control) { struct rt2x00_dev *rt2x00dev = hw->priv; -- cgit v1.2.3-70-g09d2 From e9136550eb7d9409292a93e2d2265afa11bee234 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Tue, 25 Sep 2007 20:54:20 +0200 Subject: [PATCH] rt2x00: Increase rt2x00usb_vendor_request timeout. By increasing the timeout for rt2x00usb_vendor_request, we should limit the number of loops required to send a signal to the device succefully. 500ms timeout is specified by the Ralink legacy drivers for rt2500usb. For rt73usb 1000ms is specified, but that includes the timeout for the firmware which is already specified in a different define. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00usb.c | 10 ++++------ drivers/net/wireless/rt2x00/rt2x00usb.h | 8 ++++---- 2 files changed, 8 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 8d208118902..66e47615f2a 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -42,7 +42,7 @@ int rt2x00usb_vendor_request(const struct rt2x00_dev *rt2x00dev, const u8 request, const u8 requesttype, const u16 offset, const u16 value, void *buffer, const u16 buffer_length, - u16 timeout) + const int timeout) { struct usb_device *usb_dev = interface_to_usbdev(rt2x00dev_usb(rt2x00dev)); @@ -60,12 +60,10 @@ int rt2x00usb_vendor_request(const struct rt2x00_dev *rt2x00dev, return 0; /* - * Check for errors, - * -ETIMEDOUT: We need a bit more time to complete. + * Check for errors * -ENODEV: Device has disappeared, no point continuing. + * All other errors: Try again. */ - if (status == -ETIMEDOUT) - timeout *= 2; else if (status == -ENODEV) break; } @@ -81,7 +79,7 @@ EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request); int rt2x00usb_vendor_request_buff(const struct rt2x00_dev *rt2x00dev, const u8 request, const u8 requesttype, const u16 offset, void *buffer, - const u16 buffer_length, u16 timeout) + const u16 buffer_length, const int timeout) { int status; diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h index d4113e5158f..2681abe4d49 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.h +++ b/drivers/net/wireless/rt2x00/rt2x00usb.h @@ -44,7 +44,7 @@ */ #define REGISTER_BUSY_COUNT 5 #define REGISTER_BUSY_DELAY 100 -#define REGISTER_TIMEOUT 20 +#define REGISTER_TIMEOUT 500 #define REGISTER_TIMEOUT_FIRMWARE 1000 /* @@ -95,7 +95,7 @@ int rt2x00usb_vendor_request(const struct rt2x00_dev *rt2x00dev, const u8 request, const u8 requesttype, const u16 offset, const u16 value, void *buffer, const u16 buffer_length, - u16 timeout); + const int timeout); /* * Used to read/write from/to the device. @@ -110,7 +110,7 @@ int rt2x00usb_vendor_request(const struct rt2x00_dev *rt2x00dev, int rt2x00usb_vendor_request_buff(const struct rt2x00_dev *rt2x00dev, const u8 request, const u8 requesttype, const u16 offset, void *buffer, - const u16 buffer_length, u16 timeout); + const u16 buffer_length, const int timeout); /* * Simple wrapper around rt2x00usb_vendor_request to write a single @@ -122,7 +122,7 @@ static inline int rt2x00usb_vendor_request_sw(const struct rt2x00_dev const u8 request, const u16 offset, const u16 value, - int timeout) + const int timeout) { return rt2x00usb_vendor_request(rt2x00dev, request, USB_VENDOR_REQUEST_OUT, offset, -- cgit v1.2.3-70-g09d2 From 12dadb9009723dd0512091643e6e403f9e1b25cb Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Tue, 25 Sep 2007 20:54:44 +0200 Subject: [PATCH] rt2x00: Correctly identify rt2561turbo Apparently rt2561s actually has PCI ID 0x0301 and rt2561 actually has PCI ID 0x0302. Where rt2561s supports Turbo. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 046eecfb16c..5f05c7ee0df 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -159,8 +159,8 @@ struct rt2x00_chip { #define RT2460 0x0101 #define RT2560 0x0201 #define RT2570 0x1201 -#define RT2561 0x0301 -#define RT2561s 0x0302 +#define RT2561s 0x0301 /* Turbo */ +#define RT2561 0x0302 #define RT2661 0x0401 #define RT2571 0x1300 -- cgit v1.2.3-70-g09d2 From 066cb637b1b562bebd09d237bfaaca6724f247e5 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Tue, 25 Sep 2007 20:55:39 +0200 Subject: [PATCH] rt2x00: Reorganize rt2x00dev->flags The rt2x00dev->flags has become a chaos over time, this will reorganize the flags by renaming, deleting, adding and properly implement the flags. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 4 +-- drivers/net/wireless/rt2x00/rt2500pci.c | 4 +-- drivers/net/wireless/rt2x00/rt2500usb.c | 2 +- drivers/net/wireless/rt2x00/rt2x00.h | 31 ++++++++--------- drivers/net/wireless/rt2x00/rt2x00config.c | 27 ++++----------- drivers/net/wireless/rt2x00/rt2x00dev.c | 55 ++++++++++++++++++++++-------- drivers/net/wireless/rt2x00/rt2x00lib.h | 3 +- drivers/net/wireless/rt2x00/rt2x00mac.c | 55 +++++++++++++++++++++--------- drivers/net/wireless/rt2x00/rt2x00rfkill.c | 12 +++---- drivers/net/wireless/rt2x00/rt61pci.c | 4 +-- drivers/net/wireless/rt2x00/rt73usb.c | 2 +- 11 files changed, 115 insertions(+), 84 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 03a94a33e6b..faa47111a57 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1374,7 +1374,7 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev) * Detect if this device has an hardware controlled radio. */ if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) - __set_bit(DEVICE_SUPPORT_HW_BUTTON, &rt2x00dev->flags); + __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); /* * Check if the BBP tuning should be enabled. @@ -1469,7 +1469,7 @@ static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * This device requires the beacon ring */ - __set_bit(REQUIRE_BEACON_RING, &rt2x00dev->flags); + __set_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags); /* * Set the rssi offset. diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 892baa907a6..929257d34ae 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1545,7 +1545,7 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev) * Detect if this device has an hardware controlled radio. */ if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) - __set_bit(DEVICE_SUPPORT_HW_BUTTON, &rt2x00dev->flags); + __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); /* * Check if the BBP tuning should be enabled. @@ -1801,7 +1801,7 @@ static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * This device requires the beacon ring */ - __set_bit(REQUIRE_BEACON_RING, &rt2x00dev->flags); + __set_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags); /* * Set the rssi offset. diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index f4e6f6eb7fb..7aacc7b5c1b 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1573,7 +1573,7 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev) /* * This device requires the beacon ring */ - __set_bit(REQUIRE_BEACON_RING, &rt2x00dev->flags); + __set_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags); /* * Set the rssi offset. diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 5f05c7ee0df..ea20f3adde5 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -493,24 +493,21 @@ struct rt2x00_dev { * of the device capabilities are stored. */ unsigned long flags; -#define DEVICE_ENABLED_RADIO 1 -#define DEVICE_ENABLED_RADIO_HW 2 +#define DEVICE_PRESENT 1 +#define DEVICE_REGISTERED_HW 2 #define DEVICE_INITIALIZED 3 -#define DEVICE_INITIALIZED_HW 4 -#define REQUIRE_FIRMWARE 5 -/* Hole: Add new Flag here */ -#define INTERFACE_RESUME 8 -#define INTERFACE_ENABLED 9 -/* Hole: Add new Flag here */ -#define REQUIRE_BEACON_RING 11 -#define DEVICE_SUPPORT_HW_BUTTON 12 -#define CONFIG_FRAME_TYPE 13 -#define CONFIG_RF_SEQUENCE 14 -/* Hole: Add new Flag here */ -#define CONFIG_EXTERNAL_LNA_A 16 -#define CONFIG_EXTERNAL_LNA_BG 17 -#define CONFIG_DOUBLE_ANTENNA 18 -#define CONFIG_DISABLE_LINK_TUNING 19 +#define DEVICE_STARTED 4 +#define DEVICE_ENABLED_RADIO 5 +#define DEVICE_ENABLED_RADIO_HW 6 +#define DRIVER_REQUIRE_FIRMWARE 7 +#define DRIVER_REQUIRE_BEACON_RING 8 +#define CONFIG_SUPPORT_HW_BUTTON 9 +#define CONFIG_FRAME_TYPE 10 +#define CONFIG_RF_SEQUENCE 11 +#define CONFIG_EXTERNAL_LNA_A 12 +#define CONFIG_EXTERNAL_LNA_BG 13 +#define CONFIG_DOUBLE_ANTENNA 14 +#define CONFIG_DISABLE_LINK_TUNING 15 /* * Chipset identification. diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index f962ce49708..13b510687bc 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -48,33 +48,20 @@ void rt2x00lib_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, int type) { - struct interface *intf = &rt2x00dev->interface; - - if (!test_bit(INTERFACE_RESUME, &rt2x00dev->flags) && - (!!test_bit(INTERFACE_ENABLED, &rt2x00dev->flags) == - !!is_interface_present(intf))) - return; - - rt2x00dev->ops->lib->config_type(rt2x00dev, type); - - /* - * Update the configuration flags. - */ - if (is_interface_present(intf)) - __set_bit(INTERFACE_ENABLED, &rt2x00dev->flags); - else - __clear_bit(INTERFACE_ENABLED, &rt2x00dev->flags); + if (type != INVALID_INTERFACE) + rt2x00dev->ops->lib->config_type(rt2x00dev, type); } -void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, struct ieee80211_conf *conf) +void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, + struct ieee80211_conf *conf, const int force_config) { int flags = 0; /* - * If we are in RESUME state we should - * force all configuration options. + * In some situations we want to force all configurations + * to be reloaded (When resuming for instance). */ - if (test_bit(INTERFACE_RESUME, &rt2x00dev->flags)) { + if (force_config) { flags = CONFIG_UPDATE_ALL; goto config; } diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 4f66adc5b09..f8f7e6e47f8 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -40,7 +40,7 @@ struct data_ring *rt2x00lib_get_ring(struct rt2x00_dev *rt2x00dev, const unsigned int queue) { - int beacon = test_bit(REQUIRE_BEACON_RING, &rt2x00dev->flags); + int beacon = test_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags); /* * Check if we are requesting a reqular TX ring, @@ -102,7 +102,7 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev) * And check if the hardware button has been disabled. */ if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) || - (test_bit(DEVICE_SUPPORT_HW_BUTTON, &rt2x00dev->flags) && + (test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags) && !test_bit(DEVICE_ENABLED_RADIO_HW, &rt2x00dev->flags))) return 0; @@ -162,6 +162,9 @@ void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, int enable) { enum dev_state state = enable ? STATE_RADIO_RX_ON : STATE_RADIO_RX_OFF; + if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + return; + /* * When we are disabling the RX, we should also stop the link tuner. */ @@ -721,7 +724,7 @@ exit: static void rt2x00lib_remove_hw(struct rt2x00_dev *rt2x00dev) { - if (test_bit(DEVICE_INITIALIZED_HW, &rt2x00dev->flags)) + if (test_bit(DEVICE_REGISTERED_HW, &rt2x00dev->flags)) ieee80211_unregister_hw(rt2x00dev->hw); if (likely(rt2x00dev->hwmodes)) { @@ -753,7 +756,7 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev) return status; } - __set_bit(DEVICE_INITIALIZED_HW, &rt2x00dev->flags); + __set_bit(DEVICE_REGISTERED_HW, &rt2x00dev->flags); return 0; } @@ -810,7 +813,7 @@ static int rt2x00lib_alloc_ring_entries(struct rt2x00_dev *rt2x00dev) return -ENOMEM; } - if (!test_bit(REQUIRE_BEACON_RING, &rt2x00dev->flags)) + if (!test_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags)) return 0; /* @@ -919,7 +922,7 @@ static int rt2x00lib_alloc_rings(struct rt2x00_dev *rt2x00dev) * Atim: 1 (if required) */ rt2x00dev->data_rings = 1 + rt2x00dev->hw->queues + - (2 * test_bit(REQUIRE_BEACON_RING, &rt2x00dev->flags)); + (2 * test_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags)); ring = kzalloc(rt2x00dev->data_rings * sizeof(*ring), GFP_KERNEL); if (!ring) { @@ -932,7 +935,7 @@ static int rt2x00lib_alloc_rings(struct rt2x00_dev *rt2x00dev) */ rt2x00dev->rx = ring; rt2x00dev->tx = &rt2x00dev->rx[1]; - if (test_bit(REQUIRE_BEACON_RING, &rt2x00dev->flags)) + if (test_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags)) rt2x00dev->bcn = &rt2x00dev->tx[rt2x00dev->hw->queues]; /* @@ -1011,6 +1014,8 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) */ rt2x00debug_register(rt2x00dev); + __set_bit(DEVICE_PRESENT, &rt2x00dev->flags); + return 0; exit: @@ -1022,6 +1027,8 @@ EXPORT_SYMBOL_GPL(rt2x00lib_probe_dev); void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev) { + __clear_bit(DEVICE_PRESENT, &rt2x00dev->flags); + /* * Disable radio. */ @@ -1068,6 +1075,13 @@ int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev, pm_message_t state) int retval; NOTICE(rt2x00dev, "Going to sleep.\n"); + __clear_bit(DEVICE_PRESENT, &rt2x00dev->flags); + + /* + * Only continue if mac80211 has open interfaces. + */ + if (!test_bit(DEVICE_STARTED, &rt2x00dev->flags)) + goto exit; /* * Disable radio and unitialize all items @@ -1077,6 +1091,7 @@ int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev, pm_message_t state) rt2x00lib_uninitialize(rt2x00dev); rt2x00debug_deregister(rt2x00dev); +exit: /* * Set device mode to sleep for power management. */ @@ -1094,13 +1109,19 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) int retval; NOTICE(rt2x00dev, "Waking up.\n"); - __set_bit(INTERFACE_RESUME, &rt2x00dev->flags); + __set_bit(DEVICE_PRESENT, &rt2x00dev->flags); /* * Open the debugfs entry. */ rt2x00debug_register(rt2x00dev); + /* + * Only continue if mac80211 has open interfaces. + */ + if (!test_bit(DEVICE_STARTED, &rt2x00dev->flags)) + return 0; + /* * Reinitialize device and all active interfaces. */ @@ -1111,14 +1132,22 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) /* * Reconfigure device. */ - retval = rt2x00mac_config(rt2x00dev->hw, &rt2x00dev->hw->conf); - if (retval) - goto exit; + rt2x00lib_config(rt2x00dev, &rt2x00dev->hw->conf, 1); + if (!rt2x00dev->hw->conf.radio_enabled) + rt2x00lib_disable_radio(rt2x00dev); rt2x00lib_config_mac_addr(rt2x00dev, intf->mac); rt2x00lib_config_bssid(rt2x00dev, intf->bssid); rt2x00lib_config_type(rt2x00dev, intf->type); + /* + * It is possible that during that mac80211 has attempted + * to send frames while we were suspending or resuming. + * In that case we have disabled the TX queue and should + * now enable it again + */ + ieee80211_start_queues(rt2x00dev->hw); + /* * When in Master or Ad-hoc mode, * restart Beacon transmitting by faking a beacondone event. @@ -1127,8 +1156,6 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) intf->type == IEEE80211_IF_TYPE_IBSS) rt2x00lib_beacondone(rt2x00dev); - __clear_bit(INTERFACE_RESUME, &rt2x00dev->flags); - return 0; exit: @@ -1136,8 +1163,6 @@ exit: rt2x00lib_uninitialize(rt2x00dev); rt2x00debug_deregister(rt2x00dev); - __clear_bit(INTERFACE_RESUME, &rt2x00dev->flags); - return retval; } EXPORT_SYMBOL_GPL(rt2x00lib_resume); diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index fcc2ffdd1a3..6dd92eb2b22 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -52,7 +52,8 @@ void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev); void rt2x00lib_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *mac); void rt2x00lib_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid); void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, int type); -void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, struct ieee80211_conf *conf); +void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, + struct ieee80211_conf *conf, const int force_config); /* * Firmware handlers. diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 17802f6d3d6..e98d013a189 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -81,6 +81,17 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, struct data_ring *ring; u16 frame_control; + /* + * Mac80211 might be calling this function while we are trying + * to remove the device or perhaps suspending it. + * Note that we can only stop the TX queues inside the TX path + * due to possible race conditions in mac80211. + */ + if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) { + ieee80211_stop_queues(hw); + return 0; + } + /* * Determine which ring to put packet on. */ @@ -126,14 +137,15 @@ int rt2x00mac_start(struct ieee80211_hw *hw) struct rt2x00_dev *rt2x00dev = hw->priv; int status; - if (test_bit(DEVICE_INITIALIZED, &rt2x00dev->flags)) + if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) || + test_bit(DEVICE_STARTED, &rt2x00dev->flags)) return 0; /* * If this is the first interface which is added, * we should load the firmware now. */ - if (test_bit(REQUIRE_FIRMWARE, &rt2x00dev->flags)) { + if (test_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags)) { status = rt2x00lib_load_firmware(rt2x00dev); if (status) return status; @@ -155,6 +167,8 @@ int rt2x00mac_start(struct ieee80211_hw *hw) return status; } + __set_bit(DEVICE_STARTED, &rt2x00dev->flags); + return 0; } EXPORT_SYMBOL_GPL(rt2x00mac_start); @@ -163,11 +177,16 @@ void rt2x00mac_stop(struct ieee80211_hw *hw) { struct rt2x00_dev *rt2x00dev = hw->priv; + if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) + return; + /* * Perhaps we can add something smarter here, * but for now just disabling the radio should do. */ rt2x00lib_disable_radio(rt2x00dev); + + __clear_bit(DEVICE_STARTED, &rt2x00dev->flags); } EXPORT_SYMBOL_GPL(rt2x00mac_stop); @@ -178,9 +197,12 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, struct interface *intf = &rt2x00dev->interface; /* - * We only support 1 non-monitor interface. + * Don't allow interfaces to be added while + * either the device has disappeared or when + * another interface is already present. */ - if (is_interface_present(intf)) + if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) || + is_interface_present(intf)) return -ENOBUFS; intf->id = conf->if_id; @@ -208,9 +230,12 @@ void rt2x00mac_remove_interface(struct ieee80211_hw *hw, struct interface *intf = &rt2x00dev->interface; /* - * We only support 1 non-monitor interface. + * Don't allow interfaces to be remove while + * either the device has disappeared or when + * no interface is present. */ - if (!is_interface_present(intf)) + if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) || + !is_interface_present(intf)) return; intf->id = 0; @@ -233,12 +258,10 @@ int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) struct rt2x00_dev *rt2x00dev = hw->priv; /* - * If the device is not initialized we shouldn't accept - * any configuration changes. Mac80211 might be calling - * this function while we are trying to remove the device - * or perhaps suspending it. + * Mac80211 might be calling this function while we are trying + * to remove the device or perhaps suspending it. */ - if (!test_bit(DEVICE_INITIALIZED, &rt2x00dev->flags)) + if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) return 0; /* @@ -252,7 +275,7 @@ int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) rt2x00lib_toggle_rx(rt2x00dev, 0); } - rt2x00lib_config(rt2x00dev, conf); + rt2x00lib_config(rt2x00dev, conf, 0); /* * Reenable RX only if the radio should be on. @@ -274,12 +297,10 @@ int rt2x00mac_config_interface(struct ieee80211_hw *hw, int if_id, int status; /* - * If the device is not initialized we shouldn't accept - * any configuration changes. Mac80211 might be calling - * this function while we are trying to remove the device - * or perhaps suspending it. + * Mac80211 might be calling this function while we are trying + * to remove the device or perhaps suspending it. */ - if (!test_bit(DEVICE_INITIALIZED, &rt2x00dev->flags)) + if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) return 0; /* diff --git a/drivers/net/wireless/rt2x00/rt2x00rfkill.c b/drivers/net/wireless/rt2x00/rt2x00rfkill.c index b54457c921c..06af01451cd 100644 --- a/drivers/net/wireless/rt2x00/rt2x00rfkill.c +++ b/drivers/net/wireless/rt2x00/rt2x00rfkill.c @@ -45,9 +45,9 @@ static int rt2x00rfkill_toggle_radio(void *data, enum rfkill_state state) return 0; /* - * Only continue if we have an active interface. + * Only continue if there are enabled interfaces. */ - if (!is_interface_present(&rt2x00dev->interface)) + if (!test_bit(DEVICE_STARTED, &rt2x00dev->flags)) return 0; if (state == RFKILL_STATE_ON) { @@ -76,7 +76,7 @@ int rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev) { int retval; - if (!test_bit(DEVICE_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) + if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) return 0; retval = rfkill_register(rt2x00dev->rfkill); @@ -97,7 +97,7 @@ int rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev) void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev) { - if (!test_bit(DEVICE_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) + if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) return; input_unregister_polled_device(rt2x00dev->poll_dev); @@ -108,7 +108,7 @@ int rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev) { struct device *device = wiphy_dev(rt2x00dev->hw->wiphy); - if (!test_bit(DEVICE_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) + if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) return 0; rt2x00dev->rfkill = rfkill_allocate(device, RFKILL_TYPE_WLAN); @@ -138,7 +138,7 @@ int rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev) void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev) { - if (!test_bit(DEVICE_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) + if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) return; input_free_polled_device(rt2x00dev->poll_dev); diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 3edcd743dce..4c5e317a3ad 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2105,7 +2105,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) * Detect if this device has an hardware controlled radio. */ if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) - __set_bit(DEVICE_SUPPORT_HW_BUTTON, &rt2x00dev->flags); + __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); /* * Read frequency offset and RF programming sequence. @@ -2360,7 +2360,7 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * This device requires firmware */ - __set_bit(REQUIRE_FIRMWARE, &rt2x00dev->flags); + __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); /* * Set the rssi offset. diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index b18cc934ff8..ffed3ec5fb9 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1827,7 +1827,7 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) /* * This device requires firmware */ - __set_bit(REQUIRE_FIRMWARE, &rt2x00dev->flags); + __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); /* * Set the rssi offset. -- cgit v1.2.3-70-g09d2 From 643b252123fab1a524449be3b79937f17e06a5ac Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Tue, 25 Sep 2007 20:13:51 +0200 Subject: rt2x00: Add rt2x00dev->flags to debugfs Loosely based on the patch by Matthijs Kooijman, this will add the dev_flags entry into debugfs which will display rt2x00dev->flags. This will allow easier debugging of flag handling. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00debug.c | 37 +++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c index 4d2aaecd9df..9275d6f9517 100644 --- a/drivers/net/wireless/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/rt2x00/rt2x00debug.c @@ -57,6 +57,7 @@ struct rt2x00debug_intf { * - driver folder * - driver file * - chipset file + * - device flags file * - register offset/value files * - eeprom offset/value files * - bbp offset/value files @@ -65,6 +66,7 @@ struct rt2x00debug_intf { struct dentry *driver_folder; struct dentry *driver_entry; struct dentry *chipset_entry; + struct dentry *dev_flags; struct dentry *csr_off_entry; struct dentry *csr_val_entry; struct dentry *eeprom_off_entry; @@ -193,6 +195,34 @@ RT2X00DEBUGFS_OPS(eeprom, "0x%.4x\n", u16); RT2X00DEBUGFS_OPS(bbp, "0x%.2x\n", u8); RT2X00DEBUGFS_OPS(rf, "0x%.8x\n", u32); +static ssize_t rt2x00debug_read_dev_flags(struct file *file, + char __user *buf, + size_t length, + loff_t *offset) +{ + struct rt2x00debug_intf *intf = file->private_data; + char line[16]; + size_t size; + + if (*offset) + return 0; + + size = sprintf(line, "0x%.8x\n", (unsigned int)intf->rt2x00dev->flags); + + if (copy_to_user(buf, line, size)) + return -EFAULT; + + *offset += size; + return size; +} + +static const struct file_operations rt2x00debug_fop_dev_flags = { + .owner = THIS_MODULE, + .read = rt2x00debug_read_dev_flags, + .open = rt2x00debug_file_open, + .release = rt2x00debug_file_release, +}; + static struct dentry *rt2x00debug_create_file_driver(const char *name, struct rt2x00debug_intf *intf, @@ -270,6 +300,12 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) if (IS_ERR(intf->chipset_entry)) goto exit; + intf->dev_flags = debugfs_create_file("dev_flags", S_IRUGO, + intf->driver_folder, intf, + &rt2x00debug_fop_dev_flags); + if (IS_ERR(intf->dev_flags)) + goto exit; + #define RT2X00DEBUGFS_CREATE_ENTRY(__intf, __name) \ ({ \ (__intf)->__name##_off_entry = \ @@ -320,6 +356,7 @@ void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev) debugfs_remove(intf->eeprom_off_entry); debugfs_remove(intf->csr_val_entry); debugfs_remove(intf->csr_off_entry); + debugfs_remove(intf->dev_flags); debugfs_remove(intf->chipset_entry); debugfs_remove(intf->driver_entry); debugfs_remove(intf->driver_folder); -- cgit v1.2.3-70-g09d2 From 3e30968e55e43ef08ee08c71258711a79c550f25 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Tue, 25 Sep 2007 20:56:36 +0200 Subject: [PATCH] rt2x00: make rt2x00lib_stop_link_tuner() reentrant with link_tuner work Calling cancel_delayed_work_sync() unconditionally won't hurt and it will avoid race conditions when another CPU is already executing link_tuner work. Signed-off-by: Modestas Vainius Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00dev.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index f8f7e6e47f8..e8c91fb71a5 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -80,8 +80,7 @@ static void rt2x00lib_start_link_tuner(struct rt2x00_dev *rt2x00dev) static void rt2x00lib_stop_link_tuner(struct rt2x00_dev *rt2x00dev) { - if (delayed_work_pending(&rt2x00dev->link.work)) - cancel_rearming_delayed_work(&rt2x00dev->link.work); + cancel_delayed_work_sync(&rt2x00dev->link.work); } void rt2x00lib_reset_link_tuner(struct rt2x00_dev *rt2x00dev) -- cgit v1.2.3-70-g09d2 From 25ab002f94c73d9f214130fe0e0a8065e7b55841 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Tue, 25 Sep 2007 20:57:04 +0200 Subject: [PATCH] rt2x00: Stop link tuning when radio is down As pointed out by Modestas Vainius the link tuner could continue working while the radio is already down. This because at the start of disable_radio the ENABLED_RADIO flag is cleared and causes the toggle_rx to skip the stop_link_tuner() call. This will add a check to the start of the link tuner which will automatically stop the link tuner when the radio is disabled. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00dev.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index e8c91fb71a5..92b72526357 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -236,6 +236,13 @@ static void rt2x00lib_link_tuner(struct work_struct *work) struct rt2x00_dev *rt2x00dev = container_of(work, struct rt2x00_dev, link.work.work); + /* + * When the radio is shutting down we should + * immediately cease all link tuning. + */ + if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + return; + /* * Update statistics. */ -- cgit v1.2.3-70-g09d2 From dcf5475bc8458798794af9afafdb3ef33ab67fd9 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Tue, 25 Sep 2007 20:57:25 +0200 Subject: [PATCH] rt2x00: Fix obvious typo in comment Signed-off-by: Modestas Vainius Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2500pci.c | 2 +- drivers/net/wireless/rt2x00/rt61pci.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 929257d34ae..842da900d7c 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -244,7 +244,7 @@ static int rt2500pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) rt2x00pci_register_read(rt2x00dev, GPIOCSR, ®); return rt2x00_get_field32(reg, GPIOCSR_BIT0); } -#endif /* CONFIG_RT2400PCI_RFKILL */ +#endif /* CONFIG_RT2500PCI_RFKILL */ /* * Configuration handlers. diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 4c5e317a3ad..6aa517645b6 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -269,7 +269,7 @@ static int rt61pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) rt2x00pci_register_read(rt2x00dev, MAC_CSR13, ®); return rt2x00_get_field32(reg, MAC_CSR13_BIT5);; } -#endif /* CONFIG_RT2400PCI_RFKILL */ +#endif /* CONFIG_RT61PCI_RFKILL */ /* * Configuration handlers. -- cgit v1.2.3-70-g09d2 From fdd0abc8175dc43a14fe414a09fd7e6a162757bd Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Tue, 25 Sep 2007 20:57:49 +0200 Subject: [PATCH] rt2x00: Fix panic on rmmod with rfkill enabled When ieee80211_hw.config indicates that the radio is enabled and is configuring options that require the link tuner to be restarted the link tuner will cause a kernel panic when rfkill has indicated the radio was in fact disabled. Signed-off-by: Modestas Vainius Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00dev.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 92b72526357..0216096c88c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -85,6 +85,9 @@ static void rt2x00lib_stop_link_tuner(struct rt2x00_dev *rt2x00dev) void rt2x00lib_reset_link_tuner(struct rt2x00_dev *rt2x00dev) { + if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + return; + rt2x00lib_stop_link_tuner(rt2x00dev); rt2x00lib_start_link_tuner(rt2x00dev); } -- cgit v1.2.3-70-g09d2 From 3a1532f2f87175285b9459dcce58e467feec6b78 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Tue, 25 Sep 2007 20:58:08 +0200 Subject: [PATCH] rt2x00: Release rt2x00 2.0.9 Version bump Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index ea20f3adde5..511c11c4edd 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -42,7 +42,7 @@ * Module information. * DRV_NAME should be set within the individual module source files. */ -#define DRV_VERSION "2.0.8" +#define DRV_VERSION "2.0.9" #define DRV_PROJECT "http://rt2x00.serialmonkey.com" /* -- cgit v1.2.3-70-g09d2 From 2e08ac7e27c1e54ebf0f82abc03285663efe7d89 Mon Sep 17 00:00:00 2001 From: Michael Wu Date: Mon, 24 Sep 2007 18:10:25 -0400 Subject: [PATCH] adm8211: kill interrupt loop Looping in the interrupt handler is unnecessary. Signed-off-by: Michael Wu Signed-off-by: John W. Linville --- drivers/net/wireless/adm8211.c | 84 ++++++++++++++++++++---------------------- 1 file changed, 39 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index 49a6b9eda4e..0893d0d4a5e 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -458,51 +458,45 @@ do { \ struct ieee80211_hw *dev = dev_id; struct adm8211_priv *priv = dev->priv; - unsigned int count = 0; - u32 stsr; - - do { - stsr = ADM8211_CSR_READ(STSR); - ADM8211_CSR_WRITE(STSR, stsr); - if (stsr == 0xffffffff) - return IRQ_HANDLED; - - if (!(stsr & (ADM8211_STSR_NISS | ADM8211_STSR_AISS))) - break; - - if (stsr & ADM8211_STSR_RCI) - adm8211_interrupt_rci(dev); - if (stsr & ADM8211_STSR_TCI) - adm8211_interrupt_tci(dev); - - /*ADM8211_INT(LinkOn);*/ - /*ADM8211_INT(LinkOff);*/ - - ADM8211_INT(PCF); - ADM8211_INT(BCNTC); - ADM8211_INT(GPINT); - ADM8211_INT(ATIMTC); - ADM8211_INT(TSFTF); - ADM8211_INT(TSCZ); - ADM8211_INT(SQL); - ADM8211_INT(WEPTD); - ADM8211_INT(ATIME); - /*ADM8211_INT(TBTT);*/ - ADM8211_INT(TEIS); - ADM8211_INT(FBE); - ADM8211_INT(REIS); - ADM8211_INT(GPTT); - ADM8211_INT(RPS); - ADM8211_INT(RDU); - ADM8211_INT(TUF); - /*ADM8211_INT(TRT);*/ - /*ADM8211_INT(TLT);*/ - /*ADM8211_INT(TDU);*/ - ADM8211_INT(TPS); - - } while (count++ < 20); - - return IRQ_RETVAL(count); + u32 stsr = ADM8211_CSR_READ(STSR); + ADM8211_CSR_WRITE(STSR, stsr); + if (stsr == 0xffffffff) + return IRQ_HANDLED; + + if (!(stsr & (ADM8211_STSR_NISS | ADM8211_STSR_AISS))) + return IRQ_HANDLED; + + if (stsr & ADM8211_STSR_RCI) + adm8211_interrupt_rci(dev); + if (stsr & ADM8211_STSR_TCI) + adm8211_interrupt_tci(dev); + + /*ADM8211_INT(LinkOn);*/ + /*ADM8211_INT(LinkOff);*/ + + ADM8211_INT(PCF); + ADM8211_INT(BCNTC); + ADM8211_INT(GPINT); + ADM8211_INT(ATIMTC); + ADM8211_INT(TSFTF); + ADM8211_INT(TSCZ); + ADM8211_INT(SQL); + ADM8211_INT(WEPTD); + ADM8211_INT(ATIME); + /*ADM8211_INT(TBTT);*/ + ADM8211_INT(TEIS); + ADM8211_INT(FBE); + ADM8211_INT(REIS); + ADM8211_INT(GPTT); + ADM8211_INT(RPS); + ADM8211_INT(RDU); + ADM8211_INT(TUF); + /*ADM8211_INT(TRT);*/ + /*ADM8211_INT(TLT);*/ + /*ADM8211_INT(TDU);*/ + ADM8211_INT(TPS); + + return IRQ_HANDLED; #undef ADM8211_INT } -- cgit v1.2.3-70-g09d2 From fb9bc28f8bd8a6b9bc5fba7bcacc4bb131d2d5dc Mon Sep 17 00:00:00 2001 From: Michael Wu Date: Mon, 24 Sep 2007 18:10:25 -0400 Subject: [PATCH] adm8211: Improve writing of mac addrs to registers The mac address write is broken for big endian and the bssid write can be simplified. This patch does both. Signed-off-by: Michael Wu Signed-off-by: John W. Linville --- drivers/net/wireless/adm8211.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index 0893d0d4a5e..4c43cdb567c 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -1283,8 +1283,7 @@ static void adm8211_set_bssid(struct ieee80211_hw *dev, const u8 *bssid) struct adm8211_priv *priv = dev->priv; u32 reg; - reg = bssid[0] | (bssid[1] << 8) | (bssid[2] << 16) | (bssid[3] << 24); - ADM8211_CSR_WRITE(BSSID0, reg); + ADM8211_CSR_WRITE(BSSID0, le32_to_cpu(*(__le32 *)bssid)); reg = ADM8211_CSR_READ(ABDA1); reg &= 0x0000ffff; reg |= (bssid[4] << 16) | (bssid[5] << 24); @@ -1414,8 +1413,8 @@ static int adm8211_add_interface(struct ieee80211_hw *dev, ADM8211_IDLE(); - ADM8211_CSR_WRITE(PAR0, *(u32 *)conf->mac_addr); - ADM8211_CSR_WRITE(PAR1, *(u16 *)(conf->mac_addr + 4)); + ADM8211_CSR_WRITE(PAR0, le32_to_cpu(*(__le32 *)conf->mac_addr)); + ADM8211_CSR_WRITE(PAR1, le16_to_cpu(*(__le16 *)(conf->mac_addr + 4))); adm8211_update_mode(dev); -- cgit v1.2.3-70-g09d2 From 0d282764eb82f89395493b5e0541c1e30c985838 Mon Sep 17 00:00:00 2001 From: Michael Wu Date: Mon, 24 Sep 2007 18:10:25 -0400 Subject: [PATCH] adm8211: kill version printks No need to pollute dmesg with copyright info. Signed-off-by: Michael Wu Signed-off-by: John W. Linville --- drivers/net/wireless/adm8211.c | 15 --------------- 1 file changed, 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index 4c43cdb567c..ce1f8e304ea 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -39,11 +39,6 @@ static unsigned int rx_ring_size __read_mostly = 16; module_param(tx_ring_size, uint, 0); module_param(rx_ring_size, uint, 0); -static const char version[] = KERN_INFO "adm8211: " -"Copyright 2003, Jouni Malinen ; " -"Copyright 2004-2007, Michael Wu \n"; - - static struct pci_device_id adm8211_pci_id_table[] __devinitdata = { /* ADMtek ADM8211 */ { PCI_DEVICE(0x10B7, 0x6000) }, /* 3Com 3CRSHPW796 */ @@ -1794,12 +1789,6 @@ static int __devinit adm8211_probe(struct pci_dev *pdev, u8 perm_addr[ETH_ALEN]; DECLARE_MAC_BUF(mac); -#ifndef MODULE - static unsigned int cardidx; - if (!cardidx++) - printk(version); -#endif - err = pci_enable_device(pdev); if (err) { printk(KERN_ERR "%s (adm8211): Cannot enable new PCI device\n", @@ -2051,10 +2040,6 @@ static struct pci_driver adm8211_driver = { static int __init adm8211_init(void) { -#ifdef MODULE - printk(version); -#endif - return pci_register_driver(&adm8211_driver); } -- cgit v1.2.3-70-g09d2 From f6ac0adf54ed3fc7fa47e66b92defcbdf37b44ab Mon Sep 17 00:00:00 2001 From: Michael Wu Date: Mon, 24 Sep 2007 18:10:25 -0400 Subject: [PATCH] adm8211: Use revision from pci_dev No need to load the revision ourselves anymore. Signed-off-by: Michael Wu Signed-off-by: John W. Linville --- drivers/net/wireless/adm8211.c | 44 ++++++++++++++++++++---------------------- drivers/net/wireless/adm8211.h | 4 +--- 2 files changed, 22 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index ce1f8e304ea..e950a7d5571 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -117,7 +117,7 @@ static int adm8211_read_eeprom(struct ieee80211_hw *dev) break; default: - if (priv->revid < ADM8211_REV_CA) + if (priv->pdev->revision < ADM8211_REV_CA) priv->rf_type = ADM8211_TYPE_RFMD; else priv->rf_type = ADM8211_TYPE_AIROHA; @@ -135,7 +135,7 @@ static int adm8211_read_eeprom(struct ieee80211_hw *dev) case ADM8211_TYPE_ADMTEK: break; default: - if (priv->revid < ADM8211_REV_CA) + if (priv->pdev->revision < ADM8211_REV_CA) priv->bbp_type = ADM8211_TYPE_RFMD; else priv->bbp_type = ADM8211_TYPE_ADMTEK; @@ -175,7 +175,7 @@ static int adm8211_read_eeprom(struct ieee80211_hw *dev) break; default: - if (priv->revid < ADM8211_REV_CA) + if (priv->pdev->revision < ADM8211_REV_CA) priv->specific_bbptype = ADM8211_BBP_RFMD3000; else priv->specific_bbptype = ADM8211_BBP_ADM8011; @@ -194,11 +194,11 @@ static int adm8211_read_eeprom(struct ieee80211_hw *dev) break; default: - if (priv->revid == ADM8211_REV_BA) + if (priv->pdev->revision == ADM8211_REV_BA) priv->transceiver_type = ADM8211_RFMD2958_RF3000_CONTROL_POWER; - else if (priv->revid == ADM8211_REV_CA) + else if (priv->pdev->revision == ADM8211_REV_CA) priv->transceiver_type = ADM8211_AL2210L; - else if (priv->revid == ADM8211_REV_AB) + else if (priv->pdev->revision == ADM8211_REV_AB) priv->transceiver_type = ADM8211_RFMD2948; printk(KERN_WARNING "%s (adm8211): Unknown transceiver: %d\n", @@ -220,7 +220,7 @@ static inline void adm8211_write_sram(struct ieee80211_hw *dev, struct adm8211_priv *priv = dev->priv; ADM8211_CSR_WRITE(WEPCTL, addr | ADM8211_WEPCTL_TABLE_WR | - (priv->revid < ADM8211_REV_BA ? + (priv->pdev->revision < ADM8211_REV_BA ? 0 : ADM8211_WEPCTL_SEL_WEPTABLE )); ADM8211_CSR_READ(WEPCTL); msleep(1); @@ -238,7 +238,7 @@ static void adm8211_write_sram_bytes(struct ieee80211_hw *dev, u32 reg = ADM8211_CSR_READ(WEPCTL); unsigned int i; - if (priv->revid < ADM8211_REV_BA) { + if (priv->pdev->revision < ADM8211_REV_BA) { for (i = 0; i < len; i += 2) { u16 val = buf[i] | (buf[i + 1] << 8); adm8211_write_sram(dev, addr + i / 2, val); @@ -421,7 +421,7 @@ static void adm8211_interrupt_rci(struct ieee80211_hw *dev) if (skb) { struct ieee80211_rx_status rx_status = {0}; - if (priv->revid < ADM8211_REV_CA) + if (priv->pdev->revision < ADM8211_REV_CA) rx_status.ssi = rssi; else rx_status.ssi = 100 - rssi; @@ -703,7 +703,7 @@ static int adm8211_rf_set_channel(struct ieee80211_hw *dev, unsigned int chan) adm8211_rf_write_syn_rfmd2958(dev, 0x0A, reg); /* set TXRX TX_GAIN */ adm8211_rf_write_syn_rfmd2958(dev, 0x09, 0x00050 | - (priv->revid < ADM8211_REV_CA ? tx_power : 0)); + (priv->pdev->revision < ADM8211_REV_CA ? tx_power : 0)); } else { reg = ADM8211_CSR_READ(PLCPHD); reg &= 0xff00ffff; @@ -722,7 +722,7 @@ static int adm8211_rf_set_channel(struct ieee80211_hw *dev, unsigned int chan) tx_power<<2); adm8211_write_bbp(dev, RF3000_LOW_GAIN_CALIB, lpf_cutoff); adm8211_write_bbp(dev, RF3000_HIGH_GAIN_CALIB, lnags_thresh); - adm8211_write_bbp(dev, 0x1c, priv->revid == ADM8211_REV_BA ? + adm8211_write_bbp(dev, 0x1c, priv->pdev->revision == ADM8211_REV_BA ? priv->eeprom->cr28 : 0); adm8211_write_bbp(dev, 0x1d, priv->eeprom->cr29); @@ -761,7 +761,7 @@ static void adm8211_update_mode(struct ieee80211_hw *dev) priv->nar |= ADM8211_NAR_EA | ADM8211_NAR_ST | ADM8211_NAR_SR; /* don't trust the error bits on rev 0x20 and up in adhoc */ - if (priv->revid >= ADM8211_REV_BA) + if (priv->pdev->revision >= ADM8211_REV_BA) priv->soft_rx_crc = 1; break; case IEEE80211_IF_TYPE_MNTR: @@ -862,7 +862,7 @@ static int adm8211_hw_init_bbp(struct ieee80211_hw *dev) break; } - switch (priv->revid) { + switch (priv->pdev->revision) { case ADM8211_REV_CA: if (priv->transceiver_type == ADM8211_RFMD2958 || priv->transceiver_type == ADM8211_RFMD2958_RF3000_CONTROL_POWER || @@ -920,7 +920,7 @@ static int adm8211_hw_init_bbp(struct ieee80211_hw *dev) adm8211_write_bbp(dev, 0x1c, 0x00); adm8211_write_bbp(dev, 0x1d, 0x80); } else { - if (priv->revid == ADM8211_REV_BA) + if (priv->pdev->revision == ADM8211_REV_BA) adm8211_write_bbp(dev, 0x1c, priv->eeprom->cr28); else adm8211_write_bbp(dev, 0x1c, 0x00); @@ -1052,7 +1052,7 @@ static int adm8211_set_rate(struct ieee80211_hw *dev) u8 rate_buf[12] = {0}; /* write supported rates */ - if (priv->revid != ADM8211_REV_BA) { + if (priv->pdev->revision != ADM8211_REV_BA) { rate_buf[0] = ARRAY_SIZE(adm8211_rates); for (i = 0; i < ARRAY_SIZE(adm8211_rates); i++) rate_buf[i + 1] = (adm8211_rates[i].rate / 5) | 0x80; @@ -1136,7 +1136,7 @@ static void adm8211_hw_init(struct ieee80211_hw *dev) * PWR0PE2 = 13 us * PWR1PE2 = 1 us * PWR0TXPE = 8 or 6 */ - if (priv->revid < ADM8211_REV_CA) + if (priv->pdev->revision < ADM8211_REV_CA) ADM8211_CSR_WRITE(TOFS2, 0x8815cd18); else ADM8211_CSR_WRITE(TOFS2, 0x8535cd16); @@ -1165,7 +1165,7 @@ static void adm8211_hw_init(struct ieee80211_hw *dev) /* SLOT=20 us, SIFS=110 cycles of 22 MHz (5 us), * DIFS=50 us, EIFS=100 us */ - if (priv->revid < ADM8211_REV_CA) + if (priv->pdev->revision < ADM8211_REV_CA) ADM8211_CSR_WRITE(IFST, (20 << 23) | (110 << 15) | (50 << 9) | 100); else @@ -1224,13 +1224,13 @@ static int adm8211_hw_reset(struct ieee80211_hw *dev) ADM8211_CSR_WRITE(PAR, tmp); - if (priv->revid == ADM8211_REV_BA && + if (priv->pdev->revision == ADM8211_REV_BA && (priv->transceiver_type == ADM8211_RFMD2958_RF3000_CONTROL_POWER || priv->transceiver_type == ADM8211_RFMD2958)) { reg = ADM8211_CSR_READ(CSR_TEST1); reg |= (1 << 4) | (1 << 5); ADM8211_CSR_WRITE(CSR_TEST1, reg); - } else if (priv->revid == ADM8211_REV_CA) { + } else if (priv->pdev->revision == ADM8211_REV_CA) { reg = ADM8211_CSR_READ(CSR_TEST1); reg &= ~((1 << 4) | (1 << 5)); ADM8211_CSR_WRITE(CSR_TEST1, reg); @@ -1866,8 +1866,6 @@ static int __devinit adm8211_probe(struct pci_dev *pdev, goto err_iounmap; } - pci_read_config_byte(pdev, PCI_CLASS_REVISION, &priv->revid); - *(u32 *)perm_addr = le32_to_cpu((__force __le32)ADM8211_CSR_READ(PAR0)); *(u16 *)&perm_addr[4] = le16_to_cpu((__force __le16)ADM8211_CSR_READ(PAR1) & 0xFFFF); @@ -1902,7 +1900,7 @@ static int __devinit adm8211_probe(struct pci_dev *pdev, priv->mode = IEEE80211_IF_TYPE_MNTR; /* Power-on issue. EEPROM won't read correctly without */ - if (priv->revid >= ADM8211_REV_BA) { + if (pdev->revision >= ADM8211_REV_BA) { ADM8211_CSR_WRITE(FRCTL, 0); ADM8211_CSR_READ(FRCTL); ADM8211_CSR_WRITE(FRCTL, 1); @@ -1935,7 +1933,7 @@ static int __devinit adm8211_probe(struct pci_dev *pdev, printk(KERN_INFO "%s: hwaddr %s, Rev 0x%02x\n", wiphy_name(dev->wiphy), print_mac(mac, dev->wiphy->perm_addr), - priv->revid); + pdev->revision); return 0; diff --git a/drivers/net/wireless/adm8211.h b/drivers/net/wireless/adm8211.h index 5991b17c4a7..ef326fed42e 100644 --- a/drivers/net/wireless/adm8211.h +++ b/drivers/net/wireless/adm8211.h @@ -416,7 +416,7 @@ struct adm8211_desc { #define TDES1_CONTROL_RBS1 (0x00000fff) /* SRAM offsets */ -#define ADM8211_SRAM(x) (priv->revid < ADM8211_REV_BA ? \ +#define ADM8211_SRAM(x) (priv->pdev->revision < ADM8211_REV_BA ? \ ADM8211_SRAM_A_ ## x : ADM8211_SRAM_B_ ## x) #define ADM8211_SRAM_INDIV_KEY 0x0000 @@ -623,8 +623,6 @@ struct adm8211_priv { struct adm8211_eeprom *eeprom; size_t eeprom_len; - u8 revid; - u32 nar; #define ADM8211_TYPE_INTERSIL 0x00 -- cgit v1.2.3-70-g09d2 From d703e29a88c91f015aa691a195e8fd4426c4ec73 Mon Sep 17 00:00:00 2001 From: Michael Wu Date: Mon, 24 Sep 2007 18:10:25 -0400 Subject: [PATCH] adm8211: Pass all TXed frames to tx_status_irqsafe ieee80211_tx_status_irqsafe can handle the freeing of all TXed frames. Also, set excessive_retries for failed frames. Signed-off-by: Michael Wu Signed-off-by: John W. Linville --- drivers/net/wireless/adm8211.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index e950a7d5571..95c8315d71e 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -299,6 +299,7 @@ static void adm8211_interrupt_tci(struct ieee80211_hw *dev) for (dirty_tx = priv->dirty_tx; priv->cur_tx - dirty_tx; dirty_tx++) { unsigned int entry = dirty_tx % priv->tx_ring_size; u32 status = le32_to_cpu(priv->tx_ring[entry].status); + struct ieee80211_tx_status tx_status; struct adm8211_tx_ring_info *info; struct sk_buff *skb; @@ -314,21 +315,19 @@ static void adm8211_interrupt_tci(struct ieee80211_hw *dev) pci_unmap_single(priv->pdev, info->mapping, info->skb->len, PCI_DMA_TODEVICE); - if (info->tx_control.flags & IEEE80211_TXCTL_REQ_TX_STATUS) { - struct ieee80211_tx_status tx_status = {{0}}; - struct ieee80211_hdr *hdr; - size_t hdrlen = info->hdrlen; - - skb_pull(skb, sizeof(struct adm8211_tx_hdr)); - hdr = (struct ieee80211_hdr *)skb_push(skb, hdrlen); - memcpy(hdr, skb->cb, hdrlen); - memcpy(&tx_status.control, &info->tx_control, - sizeof(tx_status.control)); - if (!(status & TDES0_STATUS_ES)) + memset(&tx_status, 0, sizeof(tx_status)); + skb_pull(skb, sizeof(struct adm8211_tx_hdr)); + memcpy(skb_push(skb, info->hdrlen), skb->cb, info->hdrlen); + memcpy(&tx_status.control, &info->tx_control, + sizeof(tx_status.control)); + if (!(tx_status.control.flags & IEEE80211_TXCTL_NO_ACK)) { + if (status & TDES0_STATUS_ES) + tx_status.excessive_retries = 1; + else tx_status.flags |= IEEE80211_TX_STATUS_ACK; - ieee80211_tx_status_irqsafe(dev, skb, &tx_status); - } else - dev_kfree_skb_irq(skb); + } + ieee80211_tx_status_irqsafe(dev, skb, &tx_status); + info->skb = NULL; } -- cgit v1.2.3-70-g09d2 From ce1234d299f3823ea07019c0f7b7b0bcb81ee7a0 Mon Sep 17 00:00:00 2001 From: Michael Wu Date: Mon, 24 Sep 2007 18:10:25 -0400 Subject: [PATCH] adm8211: Detect interface up/down in suspend/resume hooks correctly Interface up/down detection was incorrectly changed during the filter API update. Signed-off-by: Michael Wu Signed-off-by: John W. Linville --- drivers/net/wireless/adm8211.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index 95c8315d71e..e4fdadb5250 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -1540,6 +1540,7 @@ static int adm8211_start(struct ieee80211_hw *dev) ADM8211_CSR_WRITE(IER, ADM8211_IER_NIE | ADM8211_IER_AIE | ADM8211_IER_RCIE | ADM8211_IER_TCIE | ADM8211_IER_TDUIE | ADM8211_IER_GPTIE); + priv->mode = IEEE80211_IF_TYPE_MNTR; adm8211_update_mode(dev); ADM8211_CSR_WRITE(RDR, 0); @@ -1554,6 +1555,7 @@ static void adm8211_stop(struct ieee80211_hw *dev) { struct adm8211_priv *priv = dev->priv; + priv->mode = IEEE80211_IF_TYPE_MGMT; priv->nar = 0; ADM8211_CSR_WRITE(NAR, 0); ADM8211_CSR_WRITE(IER, 0); @@ -1896,7 +1898,7 @@ static int __devinit adm8211_probe(struct pci_dev *pdev, priv->tx_power = 0x40; priv->lpf_cutoff = 0xFF; priv->lnags_threshold = 0xFF; - priv->mode = IEEE80211_IF_TYPE_MNTR; + priv->mode = IEEE80211_IF_TYPE_MGMT; /* Power-on issue. EEPROM won't read correctly without */ if (pdev->revision >= ADM8211_REV_BA) { @@ -1991,7 +1993,7 @@ static int adm8211_suspend(struct pci_dev *pdev, pm_message_t state) struct ieee80211_hw *dev = pci_get_drvdata(pdev); struct adm8211_priv *priv = dev->priv; - if (priv->mode != IEEE80211_IF_TYPE_MNTR) { + if (priv->mode != IEEE80211_IF_TYPE_MGMT) { ieee80211_stop_queues(dev); adm8211_stop(dev); } @@ -2009,7 +2011,7 @@ static int adm8211_resume(struct pci_dev *pdev) pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); - if (priv->mode != IEEE80211_IF_TYPE_MNTR) { + if (priv->mode != IEEE80211_IF_TYPE_MGMT) { adm8211_start(dev); ieee80211_start_queues(dev); } -- cgit v1.2.3-70-g09d2 From 583fab37da52199a8b1ea30d9c39dc95f1ead24f Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 27 Sep 2007 11:27:30 +0800 Subject: [PATCH] iwlwifi: replacing IPW with IWL in error messages This patch repaces IPW with IWL in error messages. Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl3945-base.c | 6 +++--- drivers/net/wireless/iwlwifi/iwl4965-base.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 0700076e55b..2077f26e3e8 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -204,7 +204,7 @@ static void iwl_print_hex_dump(int level, void *p, u32 len) * reclaiming packets (on 'tx done IRQ), if free space become > high mark, * Tx queue resumed. * - * The IPW operates with six queues, one receive queue in the device's + * The IWL operates with six queues, one receive queue in the device's * sram, one transmit queue for sending commands to the device firmware, * and four transmit queues for data. ***************************************************/ @@ -4591,12 +4591,12 @@ static void iwl_dump_nic_event_log(struct iwl_priv *priv) /* bail out if nothing in log */ if (size == 0) { - IWL_ERROR("Start IPW Event Log Dump: nothing in log\n"); + IWL_ERROR("Start IWL Event Log Dump: nothing in log\n"); iwl_release_restricted_access(priv); return; } - IWL_ERROR("Start IPW Event Log Dump: display count %d, wraps %d\n", + IWL_ERROR("Start IWL Event Log Dump: display count %d, wraps %d\n", size, num_wraps); /* if uCode has wrapped back to top of log, start at the oldest entry, diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 7bc25f74e3a..d0ec1a0807e 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -203,7 +203,7 @@ static void iwl_print_hex_dump(int level, void *p, u32 len) * reclaiming packets (on 'tx done IRQ), if free space become > high mark, * Tx queue resumed. * - * The IPW operates with six queues, one receive queue in the device's + * The IWL operates with six queues, one receive queue in the device's * sram, one transmit queue for sending commands to the device firmware, * and four transmit queues for data. ***************************************************/ @@ -4900,12 +4900,12 @@ static void iwl_dump_nic_event_log(struct iwl_priv *priv) /* bail out if nothing in log */ if (size == 0) { - IWL_ERROR("Start IPW Event Log Dump: nothing in log\n"); + IWL_ERROR("Start IWL Event Log Dump: nothing in log\n"); iwl_release_restricted_access(priv); return; } - IWL_ERROR("Start IPW Event Log Dump: display count %d, wraps %d\n", + IWL_ERROR("Start IWL Event Log Dump: display count %d, wraps %d\n", size, num_wraps); /* if uCode has wrapped back to top of log, start at the oldest entry, -- cgit v1.2.3-70-g09d2 From cfe01709871cccf711c70a970bfc1a8d7bd13f84 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 27 Sep 2007 11:27:31 +0800 Subject: [PATCH] iwlwifi: workaournd REPLY_COMPRESSED_BA command in iwl_rx_handle Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl4965-base.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index d0ec1a0807e..db4d82785a6 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -4613,6 +4613,7 @@ static void iwl_rx_handle(struct iwl_priv *priv) reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) && (pkt->hdr.cmd != REPLY_RX_PHY_CMD) && (pkt->hdr.cmd != REPLY_4965_RX) && + (pkt->hdr.cmd != REPLY_COMPRESSED_BA) && (pkt->hdr.cmd != STATISTICS_NOTIFICATION) && (pkt->hdr.cmd != REPLY_TX); -- cgit v1.2.3-70-g09d2 From e1493deb74d22b005769e6ecbd24a00106941c6c Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 27 Sep 2007 11:27:32 +0800 Subject: [PATCH] iwlwifi: Correction for sending beacon in config_ap This patch takes out sending beacon from conditional in config_ap function. Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl4965-base.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index db4d82785a6..fac130d0e9e 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -7493,9 +7493,8 @@ static void iwl_config_ap(struct iwl_priv *priv) iwl_activate_qos(priv, 1); #endif iwl_rxon_add_station(priv, BROADCAST_ADDR, 0); - iwl_send_beacon_cmd(priv); - } else - iwl_send_beacon_cmd(priv); + } + iwl_send_beacon_cmd(priv); /* FIXME - we need to add code here to detect a totally new * configuration, reset the AP, unassoc, rxon timing, assoc, -- cgit v1.2.3-70-g09d2 From 556f8db74809a435195c840f495fd1bf855dfadb Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 27 Sep 2007 11:27:33 +0800 Subject: [PATCH] iwlwifi: clear station table in rxon unconditionally This patch clears stations table for every rxon command. It removes iwl_rxon_add_station function in 3945. Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl3945-base.c | 55 ++++++++--------------------- drivers/net/wireless/iwlwifi/iwl4965-base.c | 24 ++++--------- 2 files changed, 21 insertions(+), 58 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 2077f26e3e8..dacf55ba0b7 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -407,6 +407,7 @@ const u8 BROADCAST_ADDR[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; */ /**************************************************************/ +#if 0 /* temparary disable till we add real remove station */ static u8 iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap) { int index = IWL_INVALID_STATION; @@ -442,7 +443,7 @@ out: spin_unlock_irqrestore(&priv->sta_lock, flags); return 0; } - +#endif static void iwl_clear_stations_table(struct iwl_priv *priv) { unsigned long flags; @@ -834,25 +835,6 @@ int iwl_send_statistics_request(struct iwl_priv *priv) return iwl_send_cmd_u32(priv, REPLY_STATISTICS_CMD, 0); } -/** - * iwl_rxon_add_station - add station into station table. - * - * there is only one AP station with id= IWL_AP_ID - * NOTE: mutex must be held before calling the this fnction -*/ -static int iwl_rxon_add_station(struct iwl_priv *priv, - const u8 *addr, int is_ap) -{ - u8 rc; - - /* Remove this station if it happens to already exist */ - iwl_remove_station(priv, addr, is_ap); - - rc = iwl_add_station(priv, addr, is_ap, 0); - - return rc; -} - /** * iwl_set_rxon_channel - Set the phymode and channel values in staging RXON * @phymode: MODE_IEEE80211A sets to 5.2GHz; all else set to 2.4GHz @@ -1123,16 +1105,6 @@ static int iwl_commit_rxon(struct iwl_priv *priv) "configuration (%d).\n", rc); return rc; } - - /* The RXON bit toggling will have cleared out the - * station table in the uCode, so blank it in the driver - * as well */ - iwl_clear_stations_table(priv); - } else if (priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) { - /* When switching from non-associated to associated, the - * uCode clears out the station table; so clear it in the - * driver as well */ - iwl_clear_stations_table(priv); } IWL_DEBUG_INFO("Sending RXON\n" @@ -1154,6 +1126,8 @@ static int iwl_commit_rxon(struct iwl_priv *priv) memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); + iwl_clear_stations_table(priv); + /* If we issue a new RXON command which required a tune then we must * send a new TXPOWER command or we won't be able to Tx any frames */ rc = iwl_hw_reg_send_txpower(priv); @@ -1163,7 +1137,7 @@ static int iwl_commit_rxon(struct iwl_priv *priv) } /* Add the broadcast address so we can send broadcast frames */ - if (iwl_rxon_add_station(priv, BROADCAST_ADDR, 0) == + if (iwl_add_station(priv, BROADCAST_ADDR, 0, 0) == IWL_INVALID_STATION) { IWL_ERROR("Error adding BROADCAST address for transmit.\n"); return -EIO; @@ -1173,7 +1147,7 @@ static int iwl_commit_rxon(struct iwl_priv *priv) * add the IWL_AP_ID to the station rate table */ if (iwl_is_associated(priv) && (priv->iw_mode == IEEE80211_IF_TYPE_STA)) - if (iwl_rxon_add_station(priv, priv->active_rxon.bssid_addr, 1) + if (iwl_add_station(priv, priv->active_rxon.bssid_addr, 1, 0) == IWL_INVALID_STATION) { IWL_ERROR("Error adding AP address for transmit.\n"); return -EIO; @@ -4658,7 +4632,7 @@ static void iwl_error_recovery(struct iwl_priv *priv) priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; iwl_commit_rxon(priv); - iwl_rxon_add_station(priv, priv->bssid, 1); + iwl_add_station(priv, priv->bssid, 1, 0); spin_lock_irqsave(&priv->lock, flags); priv->assoc_id = le16_to_cpu(priv->staging_rxon.assoc_id); @@ -6804,8 +6778,8 @@ static void iwl_bg_post_associate(struct work_struct *data) /* clear out the station table */ iwl_clear_stations_table(priv); - iwl_rxon_add_station(priv, BROADCAST_ADDR, 0); - iwl_rxon_add_station(priv, priv->bssid, 0); + iwl_add_station(priv, BROADCAST_ADDR, 0, 0); + iwl_add_station(priv, priv->bssid, 0, 0); iwl3945_sync_sta(priv, IWL_STA_ID, (priv->phymode == MODE_IEEE80211A)? IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP, @@ -7092,10 +7066,9 @@ static void iwl_config_ap(struct iwl_priv *priv) /* restore RXON assoc */ priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; iwl_commit_rxon(priv); - iwl_rxon_add_station(priv, BROADCAST_ADDR, 0); - iwl_send_beacon_cmd(priv); - } else - iwl_send_beacon_cmd(priv); + iwl_add_station(priv, BROADCAST_ADDR, 0, 0); + } + iwl_send_beacon_cmd(priv); /* FIXME - we need to add code here to detect a totally new * configuration, reset the AP, unassoc, rxon timing, assoc, @@ -7186,8 +7159,8 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id, RXON_FILTER_ASSOC_MSK; rc = iwl_commit_rxon(priv); if ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && rc) - iwl_rxon_add_station( - priv, priv->active_rxon.bssid_addr, 1); + iwl_add_station(priv, + priv->active_rxon.bssid_addr, 1, 0); } } else { diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index fac130d0e9e..c663288a675 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -407,6 +407,7 @@ const u8 BROADCAST_ADDR[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; /**************************************************************/ +#if 0 /* temparary disable till we add real remove station */ static u8 iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap) { int index = IWL_INVALID_STATION; @@ -442,6 +443,7 @@ out: spin_unlock_irqrestore(&priv->sta_lock, flags); return 0; } +#endif static void iwl_clear_stations_table(struct iwl_priv *priv) { @@ -852,16 +854,12 @@ int iwl_send_statistics_request(struct iwl_priv *priv) static int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap) { - u8 rc; - - /* Remove this station if it happens to already exist */ - iwl_remove_station(priv, addr, is_ap); - - rc = iwl_add_station(priv, addr, is_ap, 0); + u8 sta_id; + sta_id = iwl_add_station(priv, addr, is_ap, 0); iwl4965_add_station(priv, addr, is_ap); - return rc; + return sta_id; } /** @@ -1149,16 +1147,6 @@ static int iwl_commit_rxon(struct iwl_priv *priv) "configuration (%d).\n", rc); return rc; } - - /* The RXON bit toggling will have cleared out the - * station table in the uCode, so blank it in the driver - * as well */ - iwl_clear_stations_table(priv); - } else if (priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) { - /* When switching from non-associated to associated, the - * uCode clears out the station table; so clear it in the - * driver as well */ - iwl_clear_stations_table(priv); } IWL_DEBUG_INFO("Sending RXON\n" @@ -1178,6 +1166,8 @@ static int iwl_commit_rxon(struct iwl_priv *priv) return rc; } + iwl_clear_stations_table(priv); + #ifdef CONFIG_IWLWIFI_SENSITIVITY if (!priv->error_recovering) priv->start_calib = 0; -- cgit v1.2.3-70-g09d2 From 46640a8ccebee34bd16b1af672feaa7dc320f3f6 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 27 Sep 2007 11:27:34 +0800 Subject: [PATCH] iwlwifi: Fix typo in rate sacling algorithm This patch fixes tiny typo in 4965 rate sacling algorithm Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index bc5e67b0b0e..edcc542c3b3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -1672,7 +1672,7 @@ static void rs_initialize_lq(struct iwl_priv *priv, tbl->antenna_type = ANT_AUX; rs_get_tbl_info_from_mcs(&mcs_rate, priv->phymode, tbl, &rate_idx); if (!rs_is_ant_connected(priv->valid_antenna, tbl->antenna_type)) - rs_toggle_antenna(&mcs_rate, tbl), + rs_toggle_antenna(&mcs_rate, tbl); rs_mcs_from_tbl(&mcs_rate, tbl, rate_idx, use_green); tbl->current_rate.rate_n_flags = mcs_rate.rate_n_flags; -- cgit v1.2.3-70-g09d2 From c14c521e440a6a83835a2879a4c5f4311b1df68f Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 27 Sep 2007 11:27:35 +0800 Subject: [PATCH] iwlwifi: fix add_station to avoid FW error There were a few Firmware errors reported the most reproducible http://bughost.org/bugzilla/show_bug.cgi?id=1471 The root cause is rate_n_flags isn't set anymore. This patch fixes the problem. Signed-off-by: Ian Schram Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl3945-base.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index dacf55ba0b7..d153ca5f957 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -464,6 +464,7 @@ u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags) struct iwl_station_entry *station; unsigned long flags_spin; DECLARE_MAC_BUF(mac); + u8 rate; spin_lock_irqsave(&priv->sta_lock, flags_spin); if (is_ap) @@ -507,6 +508,15 @@ u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags) station->sta.sta.sta_id = index; station->sta.station_flags = 0; + rate = (priv->phymode == MODE_IEEE80211A) ? IWL_RATE_6M_PLCP : + IWL_RATE_1M_PLCP | priv->hw_setting.cck_flag; + + /* Turn on both antennas for the station... */ + station->sta.rate_n_flags = + iwl_hw_set_rate_n_flags(rate, RATE_MCS_ANT_AB_MSK); + station->current_rate.rate_n_flags = + le16_to_cpu(station->sta.rate_n_flags); + spin_unlock_irqrestore(&priv->sta_lock, flags_spin); iwl_send_add_station(priv, &station->sta, flags); return index; -- cgit v1.2.3-70-g09d2 From 63fddb9f7f65b41277043344ae0d24dbbb451ada Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 27 Sep 2007 11:27:36 +0800 Subject: [PATCH] iwlwifi: removing unnecessary memset in 4965 rate scale This patch removes redundant memset in rate scale. In rs_alloc_sta, kzalloc is used so the memset can be avoided. In rs_rate_init, it is a bug fix since it overrides everything set in other handlers namely add_debugfs. Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index edcc542c3b3..86e650dbddf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -1776,10 +1776,9 @@ static void *rs_alloc_sta(void *priv, gfp_t gfp) if (crl == NULL) return NULL; - - memset(crl, 0, sizeof(struct iwl_rate_scale_priv)); crl->lq.sta_id = 0xff; + for (j = 0; j < LQ_SIZE; j++) for (i = 0; i < IWL_RATE_COUNT; i++) rs_rate_scale_clear_window(&(crl->lq_info[j].win[i])); @@ -1796,9 +1795,6 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, struct iwl_priv *priv = (struct iwl_priv *)priv_rate; struct iwl_rate_scale_priv *crl = priv_sta; - memset(crl, 0, sizeof(struct iwl_rate_scale_priv)); - - crl->lq.sta_id = 0xff; crl->flush_timer = 0; sta->txrate = 3; for (j = 0; j < LQ_SIZE; j++) -- cgit v1.2.3-70-g09d2 From 93dc646adb94127ca1c2e74275a85265ec57b9af Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 27 Sep 2007 11:27:37 +0800 Subject: [PATCH] iwlwifi: add debugfs framework to rate scale This patch adds debugfs handler to rate scale algorithms. Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index 86e650dbddf..e849ab5aa80 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -1999,6 +1999,23 @@ static void rs_free_sta(void *priv, void *priv_sta) } +#ifdef CONFIG_MAC80211_DEBUGFS +static void rs_add_debugfs(void *priv, void *priv_sta, + struct dentry *dir) +{ + /* struct iwl_rate_scale_priv *rs_priv = priv_sta; */ + IWL_DEBUG_RATE("%s enter\n", __FUNCTION__); + IWL_DEBUG_RATE("%s leave\n", __FUNCTION__); +} + +static void rs_remove_debugfs(void *priv, void *priv_sta) +{ + /* struct iwl_rate_scale_priv *rs_priv = priv_sta; */ + IWL_DEBUG_RATE("%s enter\n", __FUNCTION__); + IWL_DEBUG_RATE("%s leave\n", __FUNCTION__); +} +#endif + static struct rate_control_ops rs_ops = { .module = NULL, .name = RS_NAME, @@ -2010,6 +2027,10 @@ static struct rate_control_ops rs_ops = { .free = rs_free, .alloc_sta = rs_alloc_sta, .free_sta = rs_free_sta, +#ifdef CONFIG_MAC80211_DEBUGFS + .add_sta_debugfs = rs_add_debugfs, + .remove_sta_debugfs = rs_remove_debugfs, +#endif }; int iwl_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) -- cgit v1.2.3-70-g09d2 From 5ae212c9273deb417bcc458d1dfb54ef880e5516 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 27 Sep 2007 11:27:38 +0800 Subject: [PATCH] iwlwifi: add read rate scale table debugfs function This patch adds read rate scale table debugfs function for 4965 rate scaling module. Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 67 +++++++++++++++++++++++++++--- 1 file changed, 61 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index e849ab5aa80..e3a0ccaf71f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -121,6 +121,9 @@ struct iwl_rate_scale_priv { u16 active_rate_basic; struct iwl_link_quality_cmd lq; struct iwl_scale_tbl_info lq_info[LQ_SIZE]; +#ifdef CONFIG_MAC80211_DEBUGFS + struct dentry *rs_sta_dbgfs_scale_table_file; +#endif }; static void rs_rate_scale_perform(struct iwl_priv *priv, @@ -2000,19 +2003,71 @@ static void rs_free_sta(void *priv, void *priv_sta) #ifdef CONFIG_MAC80211_DEBUGFS +static int open_file_generic(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, + char __user *user_buf, size_t count, loff_t *ppos) +{ + char buff[1024]; + int desc = 0; + int i = 0; + + struct iwl_rate_scale_priv *rs_priv = file->private_data; + + desc += sprintf(buff+desc, "sta_id %d\n", rs_priv->lq.sta_id); + desc += sprintf(buff+desc, "failed=%d success=%d rate=%X\n", + rs_priv->total_failed, rs_priv->total_success, + rs_priv->active_rate); + desc += sprintf(buff+desc, "general:" + "flags=0x%X mimo-d=%d s-ant0x%x d-ant=0x%x\n", + rs_priv->lq.general_params.flags, + rs_priv->lq.general_params.mimo_delimiter, + rs_priv->lq.general_params.single_stream_ant_msk, + rs_priv->lq.general_params.dual_stream_ant_msk); + + desc += sprintf(buff+desc, "agg:" + "time_limit=%d dist_start_th=%d frame_cnt_limit=%d\n", + le16_to_cpu(rs_priv->lq.agg_params.agg_time_limit), + rs_priv->lq.agg_params.agg_dis_start_th, + rs_priv->lq.agg_params.agg_frame_cnt_limit); + + desc += sprintf(buff+desc, + "Start idx [0]=0x%x [1]=0x%x [2]=0x%x [3]=0x%x\n", + rs_priv->lq.general_params.start_rate_index[0], + rs_priv->lq.general_params.start_rate_index[1], + rs_priv->lq.general_params.start_rate_index[2], + rs_priv->lq.general_params.start_rate_index[3]); + + + for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) + desc += sprintf(buff+desc, " rate[%d] 0x%X\n", + i, le32_to_cpu(rs_priv->lq.rs_table[i].rate_n_flags)); + + return simple_read_from_buffer(user_buf, count, ppos, buff, desc); +} + +static const struct file_operations rs_sta_dbgfs_scale_table_ops = { + .read = rs_sta_dbgfs_scale_table_read, + .open = open_file_generic, +}; + static void rs_add_debugfs(void *priv, void *priv_sta, struct dentry *dir) { - /* struct iwl_rate_scale_priv *rs_priv = priv_sta; */ - IWL_DEBUG_RATE("%s enter\n", __FUNCTION__); - IWL_DEBUG_RATE("%s leave\n", __FUNCTION__); + struct iwl_rate_scale_priv *rs_priv = priv_sta; + rs_priv->rs_sta_dbgfs_scale_table_file = + debugfs_create_file("rate_scale_table", 0444, dir, + rs_priv, &rs_sta_dbgfs_scale_table_ops); } static void rs_remove_debugfs(void *priv, void *priv_sta) { - /* struct iwl_rate_scale_priv *rs_priv = priv_sta; */ - IWL_DEBUG_RATE("%s enter\n", __FUNCTION__); - IWL_DEBUG_RATE("%s leave\n", __FUNCTION__); + struct iwl_rate_scale_priv *rs_priv = priv_sta; + debugfs_remove(rs_priv->rs_sta_dbgfs_scale_table_file); } #endif -- cgit v1.2.3-70-g09d2 From 588263515fecd926ea82950e5b7752b8696b595c Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 27 Sep 2007 11:27:39 +0800 Subject: [PATCH] iwlwifi: limit printouts on hot path This patch change printouts on TX path to the net_ratelimit version. Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 4 ++-- drivers/net/wireless/iwlwifi/iwl-4965.c | 2 +- drivers/net/wireless/iwlwifi/iwl-debug.h | 3 +++ 3 files changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index e3a0ccaf71f..b9d7ad8b70e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -622,7 +622,7 @@ static void rs_tx_status(void *priv_rate, u16 fc = le16_to_cpu(hdr->frame_control); s32 tpt = 0; - IWL_DEBUG_RATE("get frame ack response, update rate scale window\n"); + IWL_DEBUG_RATE_LIMIT("get frame ack response, update rate scale window\n"); if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1)) return; @@ -1717,7 +1717,7 @@ static struct ieee80211_rate *rs_get_rate(void *priv_rate, struct iwl_priv *priv = (struct iwl_priv *)priv_rate; struct iwl_rate_scale_priv *lq; - IWL_DEBUG_RATE("rate scale calculate new rate for skb\n"); + IWL_DEBUG_RATE_LIMIT("rate scale calculate new rate for skb\n"); memset(extra, 0, sizeof(*extra)); diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index b704fe7fca2..b41addf2056 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -184,7 +184,7 @@ u8 iwl_hw_find_station(struct iwl_priv *priv, const u8 *addr) goto out; } - IWL_DEBUG_ASSOC("can not find STA %s total %d\n", + IWL_DEBUG_ASSOC_LIMIT("can not find STA " MAC_FMT " total %d\n", print_mac(mac, addr), priv->num_stations); out: diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index abd344c549a..72318d78957 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -136,8 +136,11 @@ static inline void IWL_DEBUG_LIMIT(int level, const char *fmt, ...) #define IWL_DEBUG_TXPOWER(f, a...) IWL_DEBUG(IWL_DL_TXPOWER, f, ## a) #define IWL_DEBUG_IO(f, a...) IWL_DEBUG(IWL_DL_IO, f, ## a) #define IWL_DEBUG_RATE(f, a...) IWL_DEBUG(IWL_DL_RATE, f, ## a) +#define IWL_DEBUG_RATE_LIMIT(f, a...) IWL_DEBUG_LIMIT(IWL_DL_RATE, f, ## a) #define IWL_DEBUG_NOTIF(f, a...) IWL_DEBUG(IWL_DL_NOTIF, f, ## a) #define IWL_DEBUG_ASSOC(f, a...) IWL_DEBUG(IWL_DL_ASSOC | IWL_DL_INFO, f, ## a) +#define IWL_DEBUG_ASSOC_LIMIT(f, a...) \ + IWL_DEBUG_LIMIT(IWL_DL_ASSOC | IWL_DL_INFO, f, ## a) #define IWL_DEBUG_HT(f, a...) IWL_DEBUG(IWL_DL_HT, f, ## a) #define IWL_DEBUG_STATS(f, a...) IWL_DEBUG(IWL_DL_STATS, f, ## a) #define IWL_DEBUG_TX_REPLY(f, a...) IWL_DEBUG(IWL_DL_TX_REPLY, f, ## a) -- cgit v1.2.3-70-g09d2 From 02dede04f280a2ea249025414ddb4b1da1fca770 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 27 Sep 2007 11:27:40 +0800 Subject: [PATCH] iwlwifi: add supp_rates to rate scale sta private data This patch adds supp_rate bit mask to rate scale sta private data structre and thus removes sta from the argument list in helper functions. Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 31 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index b9d7ad8b70e..bad746613f5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -115,6 +115,7 @@ struct iwl_rate_scale_priv { u8 is_dup; u8 phymode; u8 ibss_sta_added; + u32 supp_rates; u16 active_rate; u16 active_siso_rate; u16 active_mimo_rate; @@ -132,8 +133,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, struct sta_info *sta); static int rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data, struct iwl_rate *tx_mcs, - struct iwl_link_quality_cmd *tbl, - struct sta_info *sta); + struct iwl_link_quality_cmd *tbl); static s32 expected_tpt_A[IWL_RATE_COUNT] = { @@ -542,14 +542,13 @@ static u16 rs_get_adjacent_rate(u8 index, u16 rate_mask, int rate_type) static int rs_get_lower_rate(struct iwl_rate_scale_priv *lq_data, struct iwl_scale_tbl_info *tbl, u8 scale_index, - u8 ht_possible, struct iwl_rate *mcs_rate, - struct sta_info *sta) + u8 ht_possible, struct iwl_rate *mcs_rate) { - u8 is_green = lq_data->is_green; s32 low; u16 rate_mask; u16 high_low; u8 switch_to_legacy = 0; + u8 is_green = lq_data->is_green; /* check if we need to switch from HT to legacy rates. * assumption is that mandatory rates (1Mbps or 6Mbps) @@ -576,9 +575,9 @@ static int rs_get_lower_rate(struct iwl_rate_scale_priv *lq_data, if (is_legacy(tbl->lq_type)) { if (lq_data->phymode == (u8) MODE_IEEE80211A) rate_mask = (u16)(rate_mask & - (sta->supp_rates << IWL_FIRST_OFDM_RATE)); + (lq_data->supp_rates << IWL_FIRST_OFDM_RATE)); else - rate_mask = (u16)(rate_mask & sta->supp_rates); + rate_mask = (u16)(rate_mask & lq_data->supp_rates); } /* if we did switched from HT to legacy check current rate */ @@ -1391,10 +1390,10 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, if (is_legacy(tbl->lq_type)) { if (lq_data->phymode == (u8) MODE_IEEE80211A) rate_scale_index_msk = (u16) (rate_mask & - (sta->supp_rates << IWL_FIRST_OFDM_RATE)); + (lq_data->supp_rates << IWL_FIRST_OFDM_RATE)); else rate_scale_index_msk = (u16) (rate_mask & - sta->supp_rates); + lq_data->supp_rates); } else rate_scale_index_msk = rate_mask; @@ -1434,7 +1433,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, rs_stay_in_table(lq_data); if (update_lq) { rs_mcs_from_tbl(&mcs_rate, tbl, index, is_green); - rs_fill_link_cmd(lq_data, &mcs_rate, &lq_data->lq, sta); + rs_fill_link_cmd(lq_data, &mcs_rate, &lq_data->lq); rs_send_lq_cmd(priv, &lq_data->lq, CMD_ASYNC); } goto out; @@ -1558,7 +1557,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, lq_update: if (update_lq) { rs_mcs_from_tbl(&mcs_rate, tbl, index, is_green); - rs_fill_link_cmd(lq_data, &mcs_rate, &lq_data->lq, sta); + rs_fill_link_cmd(lq_data, &mcs_rate, &lq_data->lq); rs_send_lq_cmd(priv, &lq_data->lq, CMD_ASYNC); } rs_stay_in_table(lq_data); @@ -1584,7 +1583,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, IWL_DEBUG_HT("Switch current mcs: %X index: %d\n", tbl->current_rate.rate_n_flags, index); rs_fill_link_cmd(lq_data, &tbl->current_rate, - &(lq_data->lq), sta); + &lq_data->lq); rs_send_lq_cmd(priv, &lq_data->lq, CMD_ASYNC); } tbl1 = &(lq_data->lq_info[lq_data->active_tbl]); @@ -1680,7 +1679,7 @@ static void rs_initialize_lq(struct iwl_priv *priv, rs_mcs_from_tbl(&mcs_rate, tbl, rate_idx, use_green); tbl->current_rate.rate_n_flags = mcs_rate.rate_n_flags; rs_get_expected_tpt_table(lq, tbl); - rs_fill_link_cmd(lq, &mcs_rate, &(lq->lq), sta); + rs_fill_link_cmd(lq, &mcs_rate, &lq->lq); rs_send_lq_cmd(priv, &lq->lq, CMD_ASYNC); out: return; @@ -1799,6 +1798,7 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, struct iwl_rate_scale_priv *crl = priv_sta; crl->flush_timer = 0; + crl->supp_rates = sta->supp_rates; sta->txrate = 3; for (j = 0; j < LQ_SIZE; j++) for (i = 0; i < IWL_RATE_COUNT; i++) @@ -1875,8 +1875,7 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, static int rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data, struct iwl_rate *tx_mcs, - struct iwl_link_quality_cmd *lq_cmd, - struct sta_info *sta) + struct iwl_link_quality_cmd *lq_cmd) { int index = 0; int rc = 0; @@ -1934,7 +1933,7 @@ static int rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data, lq_cmd->general_params.mimo_delimiter = index; rs_get_lower_rate(lq_data, &tbl_type, rate_idx, - use_ht_possible, &new_rate, sta); + use_ht_possible, &new_rate); if (is_legacy(tbl_type.lq_type)) { if (ant_toggle_count < NUM_TRY_BEFORE_ANTENNA_TOGGLE) -- cgit v1.2.3-70-g09d2 From 1b696de23bb21b89f4a4c4fd6b12e26fe2cc4a37 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 27 Sep 2007 11:27:41 +0800 Subject: [PATCH] iwlwifi: rs_rate_scale_perform clean up This patch cleans up rs_rate_scale_perform function. It removes dead code, shortens variable names and removes useless return i.e. function now returns void. Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index bad746613f5..c4b8ca12849 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -131,7 +131,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, struct net_device *dev, struct ieee80211_hdr *hdr, struct sta_info *sta); -static int rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data, +static void rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data, struct iwl_rate *tx_mcs, struct iwl_link_quality_cmd *tbl); @@ -1873,16 +1873,15 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, rs_initialize_lq(priv, sta); } -static int rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data, +static void rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data, struct iwl_rate *tx_mcs, struct iwl_link_quality_cmd *lq_cmd) { int index = 0; - int rc = 0; int rate_idx; + int repeat_rate = 0; u8 ant_toggle_count = 0; u8 use_ht_possible = 1; - u8 repeat_cur_rate = 0; struct iwl_rate new_rate; struct iwl_scale_tbl_info tbl_type = { 0 }; @@ -1891,9 +1890,9 @@ static int rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data, if (is_legacy(tbl_type.lq_type)) { ant_toggle_count = 1; - repeat_cur_rate = IWL_NUMBER_TRY; + repeat_rate = IWL_NUMBER_TRY; } else - repeat_cur_rate = IWL_HT_NUMBER_TRY; + repeat_rate = IWL_HT_NUMBER_TRY; lq_cmd->general_params.mimo_delimiter = is_mimo(tbl_type.lq_type) ? 1 : 0; @@ -1907,10 +1906,10 @@ static int rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data, lq_cmd->general_params.single_stream_ant_msk = 2; index++; - repeat_cur_rate--; + repeat_rate--; while (index < LINK_QUAL_MAX_RETRY_NUM) { - while (repeat_cur_rate && (index < LINK_QUAL_MAX_RETRY_NUM)) { + while (repeat_rate > 0 && (index < LINK_QUAL_MAX_RETRY_NUM)) { if (is_legacy(tbl_type.lq_type)) { if (ant_toggle_count < NUM_TRY_BEFORE_ANTENNA_TOGGLE) @@ -1922,7 +1921,7 @@ static int rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data, } lq_cmd->rs_table[index].rate_n_flags = cpu_to_le32(new_rate.rate_n_flags); - repeat_cur_rate--; + repeat_rate--; index++; } @@ -1942,26 +1941,22 @@ static int rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data, rs_toggle_antenna(&new_rate, &tbl_type); ant_toggle_count = 1; } - repeat_cur_rate = IWL_NUMBER_TRY; + repeat_rate = IWL_NUMBER_TRY; } else - repeat_cur_rate = IWL_HT_NUMBER_TRY; + repeat_rate = IWL_HT_NUMBER_TRY; use_ht_possible = 0; lq_cmd->rs_table[index].rate_n_flags = cpu_to_le32(new_rate.rate_n_flags); - /* lq_cmd->rs_table[index].rate_n_flags = 0x800d; */ index++; - repeat_cur_rate--; + repeat_rate--; } - /* lq_cmd->rs_table[0].rate_n_flags = 0x800d; */ - lq_cmd->general_params.dual_stream_ant_msk = 3; lq_cmd->agg_params.agg_dis_start_th = 3; lq_cmd->agg_params.agg_time_limit = cpu_to_le16(4000); - return rc; } static void *rs_alloc(struct ieee80211_local *local) -- cgit v1.2.3-70-g09d2 From 98d7e09af513da19389128f23d49893b11de81fa Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 27 Sep 2007 11:27:42 +0800 Subject: [PATCH] iwlwifi: set fixed rate through debugfs This patch adds fixed rate setting through debugfs $ echo > \ /sys/kernel/debug/ieee80211/phy/stations//rate_scale_table Currently there is no way to turn to rate scaling working again. Will be fixed in later. Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 72 +++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index c4b8ca12849..e5f8cce443b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -123,7 +123,9 @@ struct iwl_rate_scale_priv { struct iwl_link_quality_cmd lq; struct iwl_scale_tbl_info lq_info[LQ_SIZE]; #ifdef CONFIG_MAC80211_DEBUGFS - struct dentry *rs_sta_dbgfs_scale_table_file; + struct dentry *rs_sta_dbgfs_scale_table_file; + struct iwl_rate dbg_fixed; + struct iwl_priv *drv; #endif }; @@ -136,6 +138,14 @@ static void rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data, struct iwl_link_quality_cmd *tbl); +#ifdef CONFIG_MAC80211_DEBUGFS +static void rs_dbgfs_set_mcs(struct iwl_rate_scale_priv *rs_priv, + struct iwl_rate *mcs, int index); +#else +static void rs_dbgfs_set_mcs(struct iwl_rate_scale_priv *rs_priv, + struct iwl_rate *mcs, int index) +{} +#endif static s32 expected_tpt_A[IWL_RATE_COUNT] = { 0, 0, 0, 0, 40, 57, 72, 98, 121, 154, 177, 186, 186 }; @@ -1866,6 +1876,9 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, IWL_DEBUG_HT("MIMO RATE 0x%X SISO MASK 0x%X\n", crl->active_siso_rate, crl->active_mimo_rate); #endif /*CONFIG_IWLWIFI_HT*/ +#ifdef CONFIG_MAC80211_DEBUGFS + crl->drv = priv; +#endif if (priv->assoc_station_added) priv->lq_mngr.lq_ready = 1; @@ -1885,6 +1898,8 @@ static void rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data, struct iwl_rate new_rate; struct iwl_scale_tbl_info tbl_type = { 0 }; + rs_dbgfs_set_mcs(lq_data, tx_mcs, index); + rs_get_tbl_info_from_mcs(tx_mcs, lq_data->phymode, &tbl_type, &rate_idx); @@ -1919,6 +1934,8 @@ static void rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data, ant_toggle_count = 1; } } + + rs_dbgfs_set_mcs(lq_data, &new_rate, index); lq_cmd->rs_table[index].rate_n_flags = cpu_to_le32(new_rate.rate_n_flags); repeat_rate--; @@ -1947,6 +1964,7 @@ static void rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data, use_ht_possible = 0; + rs_dbgfs_set_mcs(lq_data, &new_rate, index); lq_cmd->rs_table[index].rate_n_flags = cpu_to_le32(new_rate.rate_n_flags); @@ -2002,7 +2020,54 @@ static int open_file_generic(struct inode *inode, struct file *file) file->private_data = inode->i_private; return 0; } +static void rs_dbgfs_set_mcs(struct iwl_rate_scale_priv *rs_priv, + struct iwl_rate *mcs, int index) +{ + const u32 cck_rate = 0x820A; + if (rs_priv->dbg_fixed.rate_n_flags) { + if (index < 12) + mcs->rate_n_flags = rs_priv->dbg_fixed.rate_n_flags; + else + mcs->rate_n_flags = cck_rate; + IWL_DEBUG_RATE("Fixed rate ON\n"); + return; + } + + IWL_DEBUG_RATE("Fixed rate OFF\n"); +} +static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + struct iwl_rate_scale_priv *rs_priv = file->private_data; + char buf[64]; + int buf_size; + u32 parsed_rate; + + memset(buf, 0, sizeof(buf)); + buf_size = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + + if (sscanf(buf, "%x", &parsed_rate) == 1) + rs_priv->dbg_fixed.rate_n_flags = parsed_rate; + else + rs_priv->dbg_fixed.rate_n_flags = 0; + + rs_priv->active_rate = 0x0FFF; + rs_priv->active_siso_rate = 0x1FD0; + rs_priv->active_mimo_rate = 0x1FD0; + + IWL_DEBUG_RATE("sta_id %d rate 0x%X\n", + rs_priv->lq.sta_id, rs_priv->dbg_fixed.rate_n_flags); + + if (rs_priv->dbg_fixed.rate_n_flags) { + rs_fill_link_cmd(rs_priv, &rs_priv->dbg_fixed, &rs_priv->lq); + rs_send_lq_cmd(rs_priv->drv, &rs_priv->lq, CMD_ASYNC); + } + + return count; +} static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -2013,9 +2078,11 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, struct iwl_rate_scale_priv *rs_priv = file->private_data; desc += sprintf(buff+desc, "sta_id %d\n", rs_priv->lq.sta_id); - desc += sprintf(buff+desc, "failed=%d success=%d rate=%X\n", + desc += sprintf(buff+desc, "failed=%d success=%d rate=0%X\n", rs_priv->total_failed, rs_priv->total_success, rs_priv->active_rate); + desc += sprintf(buff+desc, "fixed rate 0x%X\n", + rs_priv->dbg_fixed.rate_n_flags); desc += sprintf(buff+desc, "general:" "flags=0x%X mimo-d=%d s-ant0x%x d-ant=0x%x\n", rs_priv->lq.general_params.flags, @@ -2045,6 +2112,7 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, } static const struct file_operations rs_sta_dbgfs_scale_table_ops = { + .write = rs_sta_dbgfs_scale_table_write, .read = rs_sta_dbgfs_scale_table_read, .open = open_file_generic, }; -- cgit v1.2.3-70-g09d2 From 0209dc11c769f51f037a17a4ea7bed43eaee998c Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 27 Sep 2007 11:27:43 +0800 Subject: [PATCH] iwlwifi: add debugfs rate scale stats This patch adds rates scale statistics to debugfs: $ cat /sys/kernel/debug/ieee80211/phy/stations//rate_stats_table Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 40 +++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index e5f8cce443b..287c75705c4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -124,6 +124,7 @@ struct iwl_rate_scale_priv { struct iwl_scale_tbl_info lq_info[LQ_SIZE]; #ifdef CONFIG_MAC80211_DEBUGFS struct dentry *rs_sta_dbgfs_scale_table_file; + struct dentry *rs_sta_dbgfs_stats_table_file; struct iwl_rate dbg_fixed; struct iwl_priv *drv; #endif @@ -2068,6 +2069,7 @@ static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file, return count; } + static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -2116,20 +2118,56 @@ static const struct file_operations rs_sta_dbgfs_scale_table_ops = { .read = rs_sta_dbgfs_scale_table_read, .open = open_file_generic, }; +static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file, + char __user *user_buf, size_t count, loff_t *ppos) +{ + char buff[1024]; + int desc = 0; + int i, j; + + struct iwl_rate_scale_priv *rs_priv = file->private_data; + for (i = 0; i < LQ_SIZE; i++) { + desc += sprintf(buff+desc, "%s type=%d SGI=%d FAT=%d DUP=%d\n" + "rate=0x%X\n", + rs_priv->active_tbl == i?"*":"x", + rs_priv->lq_info[i].lq_type, + rs_priv->lq_info[i].is_SGI, + rs_priv->lq_info[i].is_fat, + rs_priv->lq_info[i].is_dup, + rs_priv->lq_info[i].current_rate.rate_n_flags); + for (j = 0; j < IWL_RATE_COUNT; j++) { + desc += sprintf(buff+desc, + "counter=%d success=%d %%=%d\n", + rs_priv->lq_info[i].win[j].counter, + rs_priv->lq_info[i].win[j].success_counter, + rs_priv->lq_info[i].win[j].success_ratio); + } + } + return simple_read_from_buffer(user_buf, count, ppos, buff, desc); +} + +static const struct file_operations rs_sta_dbgfs_stats_table_ops = { + .read = rs_sta_dbgfs_stats_table_read, + .open = open_file_generic, +}; static void rs_add_debugfs(void *priv, void *priv_sta, struct dentry *dir) { struct iwl_rate_scale_priv *rs_priv = priv_sta; rs_priv->rs_sta_dbgfs_scale_table_file = - debugfs_create_file("rate_scale_table", 0444, dir, + debugfs_create_file("rate_scale_table", 0600, dir, rs_priv, &rs_sta_dbgfs_scale_table_ops); + rs_priv->rs_sta_dbgfs_stats_table_file = + debugfs_create_file("rate_stats_table", 0600, dir, + rs_priv, &rs_sta_dbgfs_stats_table_ops); } static void rs_remove_debugfs(void *priv, void *priv_sta) { struct iwl_rate_scale_priv *rs_priv = priv_sta; debugfs_remove(rs_priv->rs_sta_dbgfs_scale_table_file); + debugfs_remove(rs_priv->rs_sta_dbgfs_stats_table_file); } #endif -- cgit v1.2.3-70-g09d2 From 61f622532371985ec46b9684179152735a80f7e0 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 27 Sep 2007 11:27:44 +0800 Subject: [PATCH] iwlwifi: Update iwlwifi version stamp to 1.1.17 Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl3945-base.c | 2 +- drivers/net/wireless/iwlwifi/iwl4965-base.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index d153ca5f957..2cd7caa69e4 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -103,7 +103,7 @@ int iwl_param_queues_num = IWL_MAX_NUM_QUEUES; #define VS #endif -#define IWLWIFI_VERSION "0.1.15k" VD VS +#define IWLWIFI_VERSION "1.1.17k" VD VS #define DRV_COPYRIGHT "Copyright(c) 2003-2007 Intel Corporation" #define DRV_VERSION IWLWIFI_VERSION diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index c663288a675..5a8342664af 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -102,7 +102,7 @@ int iwl_param_queues_num = IWL_MAX_NUM_QUEUES; #define VS #endif -#define IWLWIFI_VERSION "0.1.15k" VD VS +#define IWLWIFI_VERSION "1.1.17k" VD VS #define DRV_COPYRIGHT "Copyright(c) 2003-2007 Intel Corporation" #define DRV_VERSION IWLWIFI_VERSION -- cgit v1.2.3-70-g09d2 From a50e2e3f3e6303e893c4c438c0692d459d7093a5 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Thu, 27 Sep 2007 17:00:29 -0400 Subject: [PATCH] iwlwifi: fix imcomplete conversion to print_mac API Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index b41addf2056..b50d20267c8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -184,7 +184,7 @@ u8 iwl_hw_find_station(struct iwl_priv *priv, const u8 *addr) goto out; } - IWL_DEBUG_ASSOC_LIMIT("can not find STA " MAC_FMT " total %d\n", + IWL_DEBUG_ASSOC_LIMIT("can not find STA %s total %d\n", print_mac(mac, addr), priv->num_stations); out: -- cgit v1.2.3-70-g09d2 From 9e0db4b12c7deda532ad13d37a84ee41dd691066 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 27 Sep 2007 17:09:39 -0700 Subject: [NET]: Bring comments in loopback.c uptodate. A hint as to why it is safe to use per cpu variables, and note that we actually can have multiple instances of the loopback device now. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- drivers/net/loopback.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 2617320efa9..d6997aec45d 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -154,6 +154,7 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) #endif dev->last_rx = jiffies; + /* it's OK to use per_cpu_ptr() because BHs are off */ pcpu_lstats = netdev_priv(dev); lb_stats = per_cpu_ptr(pcpu_lstats, smp_processor_id()); lb_stats->bytes += skb->len; @@ -221,7 +222,8 @@ static void loopback_dev_free(struct net_device *dev) } /* - * The loopback device is special. There is only one instance. + * The loopback device is special. There is only one instance + * per network namespace. */ static void loopback_setup(struct net_device *dev) { -- cgit v1.2.3-70-g09d2 From de90351219a1f1fd3cb45cf6fcc4e9d6407fd2c9 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Fri, 28 Sep 2007 15:33:51 -0700 Subject: [IPoIB]: Convert to netdevice internal stats Use the stats member of struct netdevice in IPoIB, so we can save memory by deleting the stats member of struct ipoib_dev_priv, and save code by deleting ipoib_get_stats(). Signed-off-by: Roland Dreier Signed-off-by: David S. Miller --- drivers/infiniband/ulp/ipoib/ipoib.h | 2 -- drivers/infiniband/ulp/ipoib/ipoib_cm.c | 20 ++++++++++---------- drivers/infiniband/ulp/ipoib/ipoib_ib.c | 18 +++++++++--------- drivers/infiniband/ulp/ipoib/ipoib_main.c | 22 +++++++--------------- drivers/infiniband/ulp/ipoib/ipoib_multicast.c | 10 +++++----- 5 files changed, 31 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index 35f3ca42bd6..34c6128d2a3 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h @@ -280,8 +280,6 @@ struct ipoib_dev_priv { struct ib_event_handler event_handler; - struct net_device_stats stats; - struct net_device *parent; struct list_head child_intfs; struct list_head list; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 08b4676a382..1afd93cdd6b 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -430,7 +430,7 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc) ipoib_dbg(priv, "cm recv error " "(status=%d, wrid=%d vend_err %x)\n", wc->status, wr_id, wc->vendor_err); - ++priv->stats.rx_dropped; + ++dev->stats.rx_dropped; goto repost; } @@ -457,7 +457,7 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc) * this packet and reuse the old buffer. */ ipoib_dbg(priv, "failed to allocate receive buffer %d\n", wr_id); - ++priv->stats.rx_dropped; + ++dev->stats.rx_dropped; goto repost; } @@ -474,8 +474,8 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc) skb_pull(skb, IPOIB_ENCAP_LEN); dev->last_rx = jiffies; - ++priv->stats.rx_packets; - priv->stats.rx_bytes += skb->len; + ++dev->stats.rx_packets; + dev->stats.rx_bytes += skb->len; skb->dev = dev; /* XXX get correct PACKET_ type here */ @@ -512,8 +512,8 @@ void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_ if (unlikely(skb->len > tx->mtu)) { ipoib_warn(priv, "packet len %d (> %d) too long to send, dropping\n", skb->len, tx->mtu); - ++priv->stats.tx_dropped; - ++priv->stats.tx_errors; + ++dev->stats.tx_dropped; + ++dev->stats.tx_errors; ipoib_cm_skb_too_long(dev, skb, tx->mtu - IPOIB_ENCAP_LEN); return; } @@ -532,7 +532,7 @@ void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_ tx_req->skb = skb; addr = ib_dma_map_single(priv->ca, skb->data, skb->len, DMA_TO_DEVICE); if (unlikely(ib_dma_mapping_error(priv->ca, addr))) { - ++priv->stats.tx_errors; + ++dev->stats.tx_errors; dev_kfree_skb_any(skb); return; } @@ -542,7 +542,7 @@ void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_ if (unlikely(post_send(priv, tx, tx->tx_head & (ipoib_sendq_size - 1), addr, skb->len))) { ipoib_warn(priv, "post_send failed\n"); - ++priv->stats.tx_errors; + ++dev->stats.tx_errors; ib_dma_unmap_single(priv->ca, addr, skb->len, DMA_TO_DEVICE); dev_kfree_skb_any(skb); } else { @@ -580,8 +580,8 @@ static void ipoib_cm_handle_tx_wc(struct net_device *dev, struct ipoib_cm_tx *tx ib_dma_unmap_single(priv->ca, tx_req->mapping, tx_req->skb->len, DMA_TO_DEVICE); /* FIXME: is this right? Shouldn't we only increment on success? */ - ++priv->stats.tx_packets; - priv->stats.tx_bytes += tx_req->skb->len; + ++dev->stats.tx_packets; + dev->stats.tx_bytes += tx_req->skb->len; dev_kfree_skb_any(tx_req->skb); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index 481e4b6bd94..0ec28c302fb 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -208,7 +208,7 @@ static void ipoib_ib_handle_rx_wc(struct net_device *dev, struct ib_wc *wc) * this packet and reuse the old buffer. */ if (unlikely(ipoib_alloc_rx_skb(dev, wr_id))) { - ++priv->stats.rx_dropped; + ++dev->stats.rx_dropped; goto repost; } @@ -225,8 +225,8 @@ static void ipoib_ib_handle_rx_wc(struct net_device *dev, struct ib_wc *wc) skb_pull(skb, IPOIB_ENCAP_LEN); dev->last_rx = jiffies; - ++priv->stats.rx_packets; - priv->stats.rx_bytes += skb->len; + ++dev->stats.rx_packets; + dev->stats.rx_bytes += skb->len; skb->dev = dev; /* XXX get correct PACKET_ type here */ @@ -260,8 +260,8 @@ static void ipoib_ib_handle_tx_wc(struct net_device *dev, struct ib_wc *wc) ib_dma_unmap_single(priv->ca, tx_req->mapping, tx_req->skb->len, DMA_TO_DEVICE); - ++priv->stats.tx_packets; - priv->stats.tx_bytes += tx_req->skb->len; + ++dev->stats.tx_packets; + dev->stats.tx_bytes += tx_req->skb->len; dev_kfree_skb_any(tx_req->skb); @@ -362,8 +362,8 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb, if (unlikely(skb->len > priv->mcast_mtu + IPOIB_ENCAP_LEN)) { ipoib_warn(priv, "packet len %d (> %d) too long to send, dropping\n", skb->len, priv->mcast_mtu + IPOIB_ENCAP_LEN); - ++priv->stats.tx_dropped; - ++priv->stats.tx_errors; + ++dev->stats.tx_dropped; + ++dev->stats.tx_errors; ipoib_cm_skb_too_long(dev, skb, priv->mcast_mtu); return; } @@ -383,7 +383,7 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb, addr = ib_dma_map_single(priv->ca, skb->data, skb->len, DMA_TO_DEVICE); if (unlikely(ib_dma_mapping_error(priv->ca, addr))) { - ++priv->stats.tx_errors; + ++dev->stats.tx_errors; dev_kfree_skb_any(skb); return; } @@ -392,7 +392,7 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb, if (unlikely(post_send(priv, priv->tx_head & (ipoib_sendq_size - 1), address->ah, qpn, addr, skb->len))) { ipoib_warn(priv, "post_send failed\n"); - ++priv->stats.tx_errors; + ++dev->stats.tx_errors; ib_dma_unmap_single(priv->ca, addr, skb->len, DMA_TO_DEVICE); dev_kfree_skb_any(skb); } else { diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 2bd76ef5715..6b1b4b2ec5b 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -517,7 +517,7 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev) neigh = ipoib_neigh_alloc(skb->dst->neighbour); if (!neigh) { - ++priv->stats.tx_dropped; + ++dev->stats.tx_dropped; dev_kfree_skb_any(skb); return; } @@ -582,7 +582,7 @@ err_list: err_path: ipoib_neigh_free(dev, neigh); err_drop: - ++priv->stats.tx_dropped; + ++dev->stats.tx_dropped; dev_kfree_skb_any(skb); spin_unlock(&priv->lock); @@ -631,7 +631,7 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev, } else __path_add(dev, path); } else { - ++priv->stats.tx_dropped; + ++dev->stats.tx_dropped; dev_kfree_skb_any(skb); } @@ -650,7 +650,7 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev, skb_push(skb, sizeof *phdr); __skb_queue_tail(&path->queue, skb); } else { - ++priv->stats.tx_dropped; + ++dev->stats.tx_dropped; dev_kfree_skb_any(skb); } @@ -718,7 +718,7 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) __skb_queue_tail(&neigh->queue, skb); spin_unlock(&priv->lock); } else { - ++priv->stats.tx_dropped; + ++dev->stats.tx_dropped; dev_kfree_skb_any(skb); } } else { @@ -744,7 +744,7 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) IPOIB_QPN(phdr->hwaddr), IPOIB_GID_RAW_ARG(phdr->hwaddr + 4)); dev_kfree_skb_any(skb); - ++priv->stats.tx_dropped; + ++dev->stats.tx_dropped; goto out; } @@ -758,13 +758,6 @@ out: return NETDEV_TX_OK; } -static struct net_device_stats *ipoib_get_stats(struct net_device *dev) -{ - struct ipoib_dev_priv *priv = netdev_priv(dev); - - return &priv->stats; -} - static void ipoib_timeout(struct net_device *dev) { struct ipoib_dev_priv *priv = netdev_priv(dev); @@ -865,7 +858,7 @@ void ipoib_neigh_free(struct net_device *dev, struct ipoib_neigh *neigh) struct sk_buff *skb; *to_ipoib_neigh(neigh->neighbour) = NULL; while ((skb = __skb_dequeue(&neigh->queue))) { - ++priv->stats.tx_dropped; + ++dev->stats.tx_dropped; dev_kfree_skb_any(skb); } if (ipoib_cm_get(neigh)) @@ -952,7 +945,6 @@ static void ipoib_setup(struct net_device *dev) dev->stop = ipoib_stop; dev->change_mtu = ipoib_change_mtu; dev->hard_start_xmit = ipoib_start_xmit; - dev->get_stats = ipoib_get_stats; dev->tx_timeout = ipoib_timeout; dev->header_ops = &ipoib_header_ops; dev->set_multicast_list = ipoib_set_mcast_list; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index aae367057a5..98e904a7f3e 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -125,7 +125,7 @@ static void ipoib_mcast_free(struct ipoib_mcast *mcast) } spin_lock_irqsave(&priv->tx_lock, flags); - priv->stats.tx_dropped += tx_dropped; + dev->stats.tx_dropped += tx_dropped; spin_unlock_irqrestore(&priv->tx_lock, flags); kfree(mcast); @@ -320,7 +320,7 @@ ipoib_mcast_sendonly_join_complete(int status, /* Flush out any queued packets */ spin_lock_irq(&priv->tx_lock); while (!skb_queue_empty(&mcast->pkt_queue)) { - ++priv->stats.tx_dropped; + ++dev->stats.tx_dropped; dev_kfree_skb_any(skb_dequeue(&mcast->pkt_queue)); } spin_unlock_irq(&priv->tx_lock); @@ -675,7 +675,7 @@ void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb) if (!test_bit(IPOIB_MCAST_STARTED, &priv->flags) || !priv->broadcast || !test_bit(IPOIB_MCAST_FLAG_ATTACHED, &priv->broadcast->flags)) { - ++priv->stats.tx_dropped; + ++dev->stats.tx_dropped; dev_kfree_skb_any(skb); goto unlock; } @@ -690,7 +690,7 @@ void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb) if (!mcast) { ipoib_warn(priv, "unable to allocate memory for " "multicast structure\n"); - ++priv->stats.tx_dropped; + ++dev->stats.tx_dropped; dev_kfree_skb_any(skb); goto out; } @@ -705,7 +705,7 @@ void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb) if (skb_queue_len(&mcast->pkt_queue) < IPOIB_MAX_MCAST_QUEUE) skb_queue_tail(&mcast->pkt_queue, skb); else { - ++priv->stats.tx_dropped; + ++dev->stats.tx_dropped; dev_kfree_skb_any(skb); } -- cgit v1.2.3-70-g09d2 From 6a290e3d5d48e8932fae068a558b3d8dff4c7acf Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 26 Sep 2007 16:23:31 -0500 Subject: pasemi_mac: set interface speed correctly on XAUI ports pasemi_mac: set interface speed correctly on XAUI ports Set interface speed for XAUI to 10G per default, not 1G. Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik --- drivers/net/pasemi_mac.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 912bc5d33d2..daba11062d3 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -789,7 +789,10 @@ static int pasemi_mac_open(struct net_device *dev) flags = PAS_MAC_CFG_PCFG_S1 | PAS_MAC_CFG_PCFG_PE | PAS_MAC_CFG_PCFG_PR | PAS_MAC_CFG_PCFG_CE; - flags |= PAS_MAC_CFG_PCFG_TSR_1G | PAS_MAC_CFG_PCFG_SPD_1G; + if (mac->type == MAC_TYPE_GMAC) + flags |= PAS_MAC_CFG_PCFG_TSR_1G | PAS_MAC_CFG_PCFG_SPD_1G; + else + flags |= PAS_MAC_CFG_PCFG_TSR_10G | PAS_MAC_CFG_PCFG_SPD_10G; write_iob_reg(mac, PAS_IOB_DMA_RXCH_CFG(mac->dma_rxch), PAS_IOB_DMA_RXCH_CFG_CNTTH(0)); -- cgit v1.2.3-70-g09d2 From ca7e235f5eb960d83b45cef4384b490672538cd9 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 26 Sep 2007 16:23:59 -0500 Subject: pasemi_mac: flags as passed to spin_*_irqsave() should be unsigned long pasemi_mac: flags as passed to spin_*_irqsave() should be unsigned long. Signed-off-by: Tony Breeds Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik --- drivers/net/pasemi_mac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index daba11062d3..8892b658655 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -552,7 +552,7 @@ static int pasemi_mac_clean_tx(struct pasemi_mac *mac) struct pas_dma_xct_descr *dp; unsigned int start, count, limit; unsigned int total_count; - int flags; + unsigned long flags; struct sk_buff *skbs[32]; dma_addr_t dmas[32]; @@ -973,7 +973,7 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev) struct pas_dma_xct_descr *dp; u64 dflags, mactx, ptr; dma_addr_t map; - int flags; + unsigned long flags; dflags = XCT_MACTX_O | XCT_MACTX_ST | XCT_MACTX_SS | XCT_MACTX_CRC_PAD; -- cgit v1.2.3-70-g09d2 From 36033766533176d61ba15793d8ef219775499c2f Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 26 Sep 2007 16:24:42 -0500 Subject: pasemi_mac: don't enable rx before there are buffers on the ring pasemi_mac: don't enable rx before there are buffers on the ring Reorder initialization of the DMA channels and the interface. Before there was a time window when the interface was enabled before DMA was enabled. Also, now there will always be RX buffers available at the time the MAC interface is enabled, to avoid temporary out-of-buffer errors for the very first packets (on busy networks). Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik --- drivers/net/pasemi_mac.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 8892b658655..643fce860e5 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -786,14 +786,6 @@ static int pasemi_mac_open(struct net_device *dev) write_mac_reg(mac, PAS_MAC_CFG_TXP, flags); - flags = PAS_MAC_CFG_PCFG_S1 | PAS_MAC_CFG_PCFG_PE | - PAS_MAC_CFG_PCFG_PR | PAS_MAC_CFG_PCFG_CE; - - if (mac->type == MAC_TYPE_GMAC) - flags |= PAS_MAC_CFG_PCFG_TSR_1G | PAS_MAC_CFG_PCFG_SPD_1G; - else - flags |= PAS_MAC_CFG_PCFG_TSR_10G | PAS_MAC_CFG_PCFG_SPD_10G; - write_iob_reg(mac, PAS_IOB_DMA_RXCH_CFG(mac->dma_rxch), PAS_IOB_DMA_RXCH_CFG_CNTTH(0)); @@ -808,8 +800,6 @@ static int pasemi_mac_open(struct net_device *dev) write_iob_reg(mac, PAS_IOB_DMA_COM_TIMEOUTCFG, PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(0xffffff)); - write_mac_reg(mac, PAS_MAC_CFG_PCFG, flags); - ret = pasemi_mac_setup_rx_resources(dev); if (ret) goto out_rx_resources; @@ -837,6 +827,17 @@ static int pasemi_mac_open(struct net_device *dev) pasemi_mac_replenish_rx_ring(dev); + flags = PAS_MAC_CFG_PCFG_S1 | PAS_MAC_CFG_PCFG_PE | + PAS_MAC_CFG_PCFG_PR | PAS_MAC_CFG_PCFG_CE; + + if (mac->type == MAC_TYPE_GMAC) + flags |= PAS_MAC_CFG_PCFG_TSR_1G | PAS_MAC_CFG_PCFG_SPD_1G; + else + flags |= PAS_MAC_CFG_PCFG_TSR_10G | PAS_MAC_CFG_PCFG_SPD_10G; + + /* Enable interface in MAC */ + write_mac_reg(mac, PAS_MAC_CFG_PCFG, flags); + ret = pasemi_mac_phy_init(dev); /* Some configs don't have PHYs (XAUI etc), so don't complain about * failed init due to -ENODEV. -- cgit v1.2.3-70-g09d2 From 928773c23a4cf053a34ad480439448f75efa350c Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 26 Sep 2007 16:25:06 -0500 Subject: pasemi_mac: pass in count of buffers to replenish rx ring with pasemi_mac: pass in count of buffers to replenish rx ring with Refactor replenish_rx_ring to take an argument for how many entries to fill. Since it's normally available from where it's called anyway, this is just simpler. It also removes the awkward logic to try to figure out if we're filling for the first time or not. Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik --- drivers/net/pasemi_mac.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 643fce860e5..c2d34a804d4 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -370,23 +370,18 @@ static void pasemi_mac_free_rx_resources(struct net_device *dev) mac->rx = NULL; } -static void pasemi_mac_replenish_rx_ring(struct net_device *dev) +static void pasemi_mac_replenish_rx_ring(struct net_device *dev, int limit) { struct pasemi_mac *mac = netdev_priv(dev); unsigned int i; int start = mac->rx->next_to_fill; - unsigned int limit, count; - - limit = RING_AVAIL(mac->rx); - /* Check to see if we're doing first-time setup */ - if (unlikely(mac->rx->next_to_clean == 0 && mac->rx->next_to_fill == 0)) - limit = RX_RING_SIZE; + int count; if (limit <= 0) return; i = start; - for (count = limit; count; count--) { + for (count = 0; count < limit; count++) { struct pasemi_mac_buffer *info = &RX_DESC_INFO(mac, i); u64 *buff = &RX_BUFF(mac, i); struct sk_buff *skb; @@ -417,10 +412,10 @@ static void pasemi_mac_replenish_rx_ring(struct net_device *dev) wmb(); - write_dma_reg(mac, PAS_DMA_RXCHAN_INCR(mac->dma_rxch), limit - count); - write_dma_reg(mac, PAS_DMA_RXINT_INCR(mac->dma_if), limit - count); + write_dma_reg(mac, PAS_DMA_RXCHAN_INCR(mac->dma_rxch), count); + write_dma_reg(mac, PAS_DMA_RXINT_INCR(mac->dma_if), count); - mac->rx->next_to_fill += limit - count; + mac->rx->next_to_fill += count; } static void pasemi_mac_restart_rx_intr(struct pasemi_mac *mac) @@ -538,7 +533,7 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) } mac->rx->next_to_clean += limit - count; - pasemi_mac_replenish_rx_ring(mac->netdev); + pasemi_mac_replenish_rx_ring(mac->netdev, limit-count); spin_unlock(&mac->rx->lock); @@ -825,7 +820,7 @@ static int pasemi_mac_open(struct net_device *dev) write_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch), PAS_DMA_TXCHAN_TCMDSTA_EN); - pasemi_mac_replenish_rx_ring(dev); + pasemi_mac_replenish_rx_ring(dev, RX_RING_SIZE); flags = PAS_MAC_CFG_PCFG_S1 | PAS_MAC_CFG_PCFG_PE | PAS_MAC_CFG_PCFG_PR | PAS_MAC_CFG_PCFG_CE; -- cgit v1.2.3-70-g09d2 From c7e86e344b3599c0679a4a1f59a27953856f181c Mon Sep 17 00:00:00 2001 From: Nathanael Nerode Date: Wed, 26 Sep 2007 18:14:45 -0700 Subject: dgrs: remove from build, config, and maintainer list Stop building and configuring driver for Digi RightSwitch, which was never actually sold to anyone, and remove it from MAINTAINERS. In response to an investigation into the firmware of the "Digi Rightswitch" driver, Andres Salomon discovered: > > Dear Andres: > > After further research, we found that this product was killed in place > and never reached the market. We would like to request that this not be > included. Since the product never reached market, clearly nobody is using this orphaned driver. Signed-off-by: Nathanael Nerode Cc: "David S. Miller" Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- Documentation/networking/dgrs.txt | 52 - MAINTAINERS | 6 - drivers/net/Kconfig | 15 - drivers/net/Makefile | 1 - drivers/net/dgrs.c | 1593 ------ drivers/net/dgrs.h | 38 - drivers/net/dgrs_asstruct.h | 37 - drivers/net/dgrs_bcomm.h | 148 - drivers/net/dgrs_es4h.h | 183 - drivers/net/dgrs_ether.h | 135 - drivers/net/dgrs_firmware.c | 9966 ------------------------------------- drivers/net/dgrs_i82596.h | 473 -- drivers/net/dgrs_plx9060.h | 175 - 13 files changed, 12822 deletions(-) delete mode 100644 Documentation/networking/dgrs.txt delete mode 100644 drivers/net/dgrs.c delete mode 100644 drivers/net/dgrs.h delete mode 100644 drivers/net/dgrs_asstruct.h delete mode 100644 drivers/net/dgrs_bcomm.h delete mode 100644 drivers/net/dgrs_es4h.h delete mode 100644 drivers/net/dgrs_ether.h delete mode 100644 drivers/net/dgrs_firmware.c delete mode 100644 drivers/net/dgrs_i82596.h delete mode 100644 drivers/net/dgrs_plx9060.h (limited to 'drivers') diff --git a/Documentation/networking/dgrs.txt b/Documentation/networking/dgrs.txt deleted file mode 100644 index 1aa1bb3f94a..00000000000 --- a/Documentation/networking/dgrs.txt +++ /dev/null @@ -1,52 +0,0 @@ - The Digi International RightSwitch SE-X (dgrs) Device Driver - -This is a Linux driver for the Digi International RightSwitch SE-X -EISA and PCI boards. These are 4 (EISA) or 6 (PCI) port Ethernet -switches and a NIC combined into a single board. This driver can -be compiled into the kernel statically or as a loadable module. - -There is also a companion management tool, called "xrightswitch". -The management tool lets you watch the performance graphically, -as well as set the SNMP agent IP and IPX addresses, IEEE Spanning -Tree, and Aging time. These can also be set from the command line -when the driver is loaded. The driver command line options are: - - debug=NNN Debug printing level - dma=0/1 Disable/Enable DMA on PCI card - spantree=0/1 Disable/Enable IEEE spanning tree - hashexpire=NNN Change address aging time (default 300 seconds) - ipaddr=A,B,C,D Set SNMP agent IP address i.e. 199,86,8,221 - iptrap=A,B,C,D Set SNMP agent IP trap address i.e. 199,86,8,221 - ipxnet=NNN Set SNMP agent IPX network number - nicmode=0/1 Disable/Enable multiple NIC mode - -There is also a tool for setting up input and output packet filters -on each port, called "dgrsfilt". - -Both the management tool and the filtering tool are available -separately from the following FTP site: - - ftp://ftp.dgii.com/drivers/rightswitch/linux/ - -When nicmode=1, the board and driver operate as 4 or 6 individual -NIC ports (eth0...eth5) instead of as a switch. All switching -functions are disabled. In the future, the board firmware may include -a routing cache when in this mode. - -Copyright 1995-1996 Digi International Inc. - -This software may be used and distributed according to the terms -of the GNU General Public License, incorporated herein by reference. - -For information on purchasing a RightSwitch SE-4 or SE-6 -board, please contact Digi's sales department at 1-612-912-3444 -or 1-800-DIGIBRD. Outside the U.S., please check our Web page at: - - http://www.dgii.com - -for sales offices worldwide. Tech support is also available through -the channels listed on the Web site, although as long as I am -employed on networking products at Digi I will be happy to provide -any bug fixes that may be needed. - --Rick Richardson, rick@dgii.com diff --git a/MAINTAINERS b/MAINTAINERS index 27e1110ec6c..16646801105 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1274,12 +1274,6 @@ L: Eng.Linux@digi.com W: http://www.digi.com S: Orphaned -DIGI RIGHTSWITCH NETWORK DRIVER -P: Rick Richardson -L: netdev@vger.kernel.org -W: http://www.digi.com -S: Orphaned - DIRECTORY NOTIFICATION P: Stephen Rothwell M: sfr@canb.auug.org.au diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 467532c7975..764325917f6 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1459,21 +1459,6 @@ config TC35815 depends on NET_PCI && PCI && MIPS select MII -config DGRS - tristate "Digi Intl. RightSwitch SE-X support" - depends on NET_PCI && (PCI || EISA) - ---help--- - This is support for the Digi International RightSwitch series of - PCI/EISA Ethernet switch cards. These include the SE-4 and the SE-6 - models. If you have a network card of this type, say Y and read the - Ethernet-HOWTO, available from - . More specific - information is contained in . - - To compile this driver as a module, choose M here and read - . The module - will be called dgrs. - config EEPRO100 tristate "EtherExpressPro/100 support (eepro100, original Becker driver)" depends on NET_PCI && PCI diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 6220c50596e..eb5c655e26d 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -44,7 +44,6 @@ obj-$(CONFIG_SUNVNET) += sunvnet.o obj-$(CONFIG_MACE) += mace.o obj-$(CONFIG_BMAC) += bmac.o -obj-$(CONFIG_DGRS) += dgrs.o obj-$(CONFIG_VORTEX) += 3c59x.o obj-$(CONFIG_TYPHOON) += typhoon.o obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o diff --git a/drivers/net/dgrs.c b/drivers/net/dgrs.c deleted file mode 100644 index 054f2ba5f69..00000000000 --- a/drivers/net/dgrs.c +++ /dev/null @@ -1,1593 +0,0 @@ -/* - * Digi RightSwitch SE-X loadable device driver for Linux - * - * The RightSwitch is a 4 (EISA) or 6 (PCI) port etherswitch and - * a NIC on an internal board. - * - * Author: Rick Richardson, rick@remotepoint.com - * Derived from the SVR4.2 (UnixWare) driver for the same card. - * - * Copyright 1995-1996 Digi International Inc. - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * For information on purchasing a RightSwitch SE-4 or SE-6 - * board, please contact Digi's sales department at 1-612-912-3444 - * or 1-800-DIGIBRD. Outside the U.S., please check our Web page - * at http://www.dgii.com for sales offices worldwide. - * - * OPERATION: - * When compiled as a loadable module, this driver can operate - * the board as either a 4/6 port switch with a 5th or 7th port - * that is a conventional NIC interface as far as the host is - * concerned, OR as 4/6 independent NICs. To select multi-NIC - * mode, add "nicmode=1" on the insmod load line for the driver. - * - * This driver uses the "dev" common ethernet device structure - * and a private "priv" (dev->priv) structure that contains - * mostly DGRS-specific information and statistics. To keep - * the code for both the switch mode and the multi-NIC mode - * as similar as possible, I have introduced the concept of - * "dev0"/"priv0" and "devN"/"privN" pointer pairs in subroutines - * where needed. The first pair of pointers points to the - * "dev" and "priv" structures of the zeroth (0th) device - * interface associated with a board. The second pair of - * pointers points to the current (Nth) device interface - * for the board: the one for which we are processing data. - * - * In switch mode, the pairs of pointers are always the same, - * that is, dev0 == devN and priv0 == privN. This is just - * like previous releases of this driver which did not support - * NIC mode. - * - * In multi-NIC mode, the pairs of pointers may be different. - * We use the devN and privN pointers to reference just the - * name, port number, and statistics for the current interface. - * We use the dev0 and priv0 pointers to access the variables - * that control access to the board, such as board address - * and simulated 82596 variables. This is because there is - * only one "fake" 82596 that serves as the interface to - * the board. We do not want to try to keep the variables - * associated with this 82596 in sync across all devices. - * - * This scheme works well. As you will see, except for - * initialization, there is very little difference between - * the two modes as far as this driver is concerned. On the - * receive side in NIC mode, the interrupt *always* comes in on - * the 0th interface (dev0/priv0). We then figure out which - * real 82596 port it came in on from looking at the "chan" - * member that the board firmware adds at the end of each - * RBD (a.k.a. TBD). We get the channel number like this: - * int chan = ((I596_RBD *) S2H(cbp->xmit.tbdp))->chan; - * - * On the transmit side in multi-NIC mode, we specify the - * output 82596 port by setting the new "dstchan" structure - * member that is at the end of the RFD, like this: - * priv0->rfdp->dstchan = privN->chan; - * - * TODO: - * - Multi-NIC mode is not yet supported when the driver is linked - * into the kernel. - * - Better handling of multicast addresses. - * - * Fixes: - * Arnaldo Carvalho de Melo - 11/01/2001 - * - fix dgrs_found_device wrt checking kmalloc return and - * rollbacking the partial steps of the whole process when - * one of the devices can't be allocated. Fix SET_MODULE_OWNER - * on the loop to use devN instead of repeated calls to dev. - * - * davej - 9/2/2001 - * - Enable PCI device before reading ioaddr/irq - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -static char version[] __initdata = - "$Id: dgrs.c,v 1.13 2000/06/06 04:07:00 rick Exp $"; - -/* - * DGRS include files - */ -typedef unsigned char uchar; -#define vol volatile - -#include "dgrs.h" -#include "dgrs_es4h.h" -#include "dgrs_plx9060.h" -#include "dgrs_i82596.h" -#include "dgrs_ether.h" -#include "dgrs_asstruct.h" -#include "dgrs_bcomm.h" - -#ifdef CONFIG_PCI -static struct pci_device_id dgrs_pci_tbl[] = { - { SE6_PCI_VENDOR_ID, SE6_PCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, }, - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(pci, dgrs_pci_tbl); -#endif - -#ifdef CONFIG_EISA -static struct eisa_device_id dgrs_eisa_tbl[] = { - { "DBI0A01" }, - { } -}; -MODULE_DEVICE_TABLE(eisa, dgrs_eisa_tbl); -#endif - -MODULE_LICENSE("GPL"); - - -/* - * Firmware. Compiled separately for local compilation, - * but #included for Linux distribution. - */ -#ifndef NOFW - #include "dgrs_firmware.c" -#else - extern int dgrs_firmnum; - extern char dgrs_firmver[]; - extern char dgrs_firmdate[]; - extern uchar dgrs_code[]; - extern int dgrs_ncode; -#endif - -/* - * Linux out*() is backwards from all other operating systems - */ -#define OUTB(ADDR, VAL) outb(VAL, ADDR) -#define OUTW(ADDR, VAL) outw(VAL, ADDR) -#define OUTL(ADDR, VAL) outl(VAL, ADDR) - -/* - * Macros to convert switch to host and host to switch addresses - * (assumes a local variable priv points to board dependent struct) - */ -#define S2H(A) ( ((unsigned long)(A)&0x00ffffff) + priv0->vmem ) -#define S2HN(A) ( ((unsigned long)(A)&0x00ffffff) + privN->vmem ) -#define H2S(A) ( ((char *) (A) - priv0->vmem) + 0xA3000000 ) - -/* - * Convert a switch address to a "safe" address for use with the - * PLX 9060 DMA registers and the associated HW kludge that allows - * for host access of the DMA registers. - */ -#define S2DMA(A) ( (unsigned long)(A) & 0x00ffffff) - -/* - * "Space.c" variables, now settable from module interface - * Use the name below, minus the "dgrs_" prefix. See init_module(). - */ -static int dgrs_debug = 1; -static int dgrs_dma = 1; -static int dgrs_spantree = -1; -static int dgrs_hashexpire = -1; -static uchar dgrs_ipaddr[4] = { 0xff, 0xff, 0xff, 0xff}; -static uchar dgrs_iptrap[4] = { 0xff, 0xff, 0xff, 0xff}; -static __u32 dgrs_ipxnet = -1; -static int dgrs_nicmode; - -/* - * Private per-board data structure (dev->priv) - */ -typedef struct -{ - /* - * DGRS specific data - */ - char *vmem; - - struct bios_comm *bcomm; /* Firmware BIOS comm structure */ - PORT *port; /* Ptr to PORT[0] struct in VM */ - I596_SCB *scbp; /* Ptr to SCB struct in VM */ - I596_RFD *rfdp; /* Current RFD list */ - I596_RBD *rbdp; /* Current RBD list */ - - volatile int intrcnt; /* Count of interrupts */ - - /* - * SE-4 (EISA) board variables - */ - uchar is_reg; /* EISA: Value for ES4H_IS reg */ - - /* - * SE-6 (PCI) board variables - * - * The PLX "expansion rom" space is used for DMA register - * access from the host on the SE-6. These are the physical - * and virtual addresses of that space. - */ - ulong plxreg; /* Phys address of PLX chip */ - char *vplxreg; /* Virtual address of PLX chip */ - ulong plxdma; /* Phys addr of PLX "expansion rom" */ - ulong volatile *vplxdma; /* Virtual addr of "expansion rom" */ - int use_dma; /* Flag: use DMA */ - DMACHAIN *dmadesc_s; /* area for DMA chains (SW addr.) */ - DMACHAIN *dmadesc_h; /* area for DMA chains (Host Virtual) */ - - /* - * Multi-NIC mode variables - * - * All entries of the devtbl[] array are valid for the 0th - * device (i.e. eth0, but not eth1...eth5). devtbl[0] is - * valid for all devices (i.e. eth0, eth1, ..., eth5). - */ - int nports; /* Number of physical ports (4 or 6) */ - int chan; /* Channel # (1-6) for this device */ - struct net_device *devtbl[6]; /* Ptrs to N device structs */ - -} DGRS_PRIV; - - -/* - * reset or un-reset the IDT processor - */ -static void -proc_reset(struct net_device *dev0, int reset) -{ - DGRS_PRIV *priv0 = (DGRS_PRIV *) dev0->priv; - - if (priv0->plxreg) - { - ulong val; - val = inl(dev0->base_addr + PLX_MISC_CSR); - if (reset) - val |= SE6_RESET; - else - val &= ~SE6_RESET; - OUTL(dev0->base_addr + PLX_MISC_CSR, val); - } - else - { - OUTB(dev0->base_addr + ES4H_PC, reset ? ES4H_PC_RESET : 0); - } -} - -/* - * See if the board supports bus master DMA - */ -static int -check_board_dma(struct net_device *dev0) -{ - DGRS_PRIV *priv0 = (DGRS_PRIV *) dev0->priv; - ulong x; - - /* - * If Space.c says not to use DMA, or if it's not a PLX based - * PCI board, or if the expansion ROM space is not PCI - * configured, then return false. - */ - if (!dgrs_dma || !priv0->plxreg || !priv0->plxdma) - return (0); - - /* - * Set the local address remap register of the "expansion rom" - * area to 0x80000000 so that we can use it to access the DMA - * registers from the host side. - */ - OUTL(dev0->base_addr + PLX_ROM_BASE_ADDR, 0x80000000); - - /* - * Set the PCI region descriptor to: - * Space 0: - * disable read-prefetch - * enable READY - * enable BURST - * 0 internal wait states - * Expansion ROM: (used for host DMA register access) - * disable read-prefetch - * enable READY - * disable BURST - * 0 internal wait states - */ - OUTL(dev0->base_addr + PLX_BUS_REGION, 0x49430343); - - /* - * Now map the DMA registers into our virtual space - */ - priv0->vplxdma = (ulong *) ioremap (priv0->plxdma, 256); - if (!priv0->vplxdma) - { - printk("%s: can't *remap() the DMA regs\n", dev0->name); - return (0); - } - - /* - * Now test to see if we can access the DMA registers - * If we write -1 and get back 1FFF, then we accessed the - * DMA register. Otherwise, we probably have an old board - * and wrote into regular RAM. - */ - priv0->vplxdma[PLX_DMA0_MODE/4] = 0xFFFFFFFF; - x = priv0->vplxdma[PLX_DMA0_MODE/4]; - if (x != 0x00001FFF) { - iounmap((void *)priv0->vplxdma); - return (0); - } - - return (1); -} - -/* - * Initiate DMA using PLX part on PCI board. Spin the - * processor until completed. All addresses are physical! - * - * If pciaddr is NULL, then it's a chaining DMA, and lcladdr is - * the address of the first DMA descriptor in the chain. - * - * If pciaddr is not NULL, then it's a single DMA. - * - * In either case, "lcladdr" must have been fixed up to make - * sure the MSB isn't set using the S2DMA macro before passing - * the address to this routine. - */ -static int -do_plx_dma( - struct net_device *dev, - ulong pciaddr, - ulong lcladdr, - int len, - int to_host -) -{ - int i; - ulong csr = 0; - DGRS_PRIV *priv = (DGRS_PRIV *) dev->priv; - - if (pciaddr) - { - /* - * Do a single, non-chain DMA - */ - priv->vplxdma[PLX_DMA0_PCI_ADDR/4] = pciaddr; - priv->vplxdma[PLX_DMA0_LCL_ADDR/4] = lcladdr; - priv->vplxdma[PLX_DMA0_SIZE/4] = len; - priv->vplxdma[PLX_DMA0_DESCRIPTOR/4] = to_host - ? PLX_DMA_DESC_TO_HOST - : PLX_DMA_DESC_TO_BOARD; - priv->vplxdma[PLX_DMA0_MODE/4] = - PLX_DMA_MODE_WIDTH32 - | PLX_DMA_MODE_WAITSTATES(0) - | PLX_DMA_MODE_READY - | PLX_DMA_MODE_NOBTERM - | PLX_DMA_MODE_BURST - | PLX_DMA_MODE_NOCHAIN; - } - else - { - /* - * Do a chaining DMA - */ - priv->vplxdma[PLX_DMA0_MODE/4] = - PLX_DMA_MODE_WIDTH32 - | PLX_DMA_MODE_WAITSTATES(0) - | PLX_DMA_MODE_READY - | PLX_DMA_MODE_NOBTERM - | PLX_DMA_MODE_BURST - | PLX_DMA_MODE_CHAIN; - priv->vplxdma[PLX_DMA0_DESCRIPTOR/4] = lcladdr; - } - - priv->vplxdma[PLX_DMA_CSR/4] = - PLX_DMA_CSR_0_ENABLE | PLX_DMA_CSR_0_START; - - /* - * Wait for DMA to complete - */ - for (i = 0; i < 1000000; ++i) - { - /* - * Spin the host CPU for 1 usec, so we don't thrash - * the PCI bus while the PLX 9060 is doing DMA. - */ - udelay(1); - - csr = (volatile unsigned long) priv->vplxdma[PLX_DMA_CSR/4]; - - if (csr & PLX_DMA_CSR_0_DONE) - break; - } - - if ( ! (csr & PLX_DMA_CSR_0_DONE) ) - { - printk("%s: DMA done never occurred. DMA disabled.\n", - dev->name); - priv->use_dma = 0; - return 1; - } - return 0; -} - -/* - * dgrs_rcv_frame() - * - * Process a received frame. This is called from the interrupt - * routine, and works for both switch mode and multi-NIC mode. - * - * Note that when in multi-NIC mode, we want to always access the - * hardware using the dev and priv structures of the first port, - * so that we are using only one set of variables to maintain - * the board interface status, but we want to use the Nth port - * dev and priv structures to maintain statistics and to pass - * the packet up. - * - * Only the first device structure is attached to the interrupt. - * We use the special "chan" variable at the end of the first RBD - * to select the Nth device in multi-NIC mode. - * - * We currently do chained DMA on a per-packet basis when the - * packet is "long", and we spin the CPU a short time polling - * for DMA completion. This avoids a second interrupt overhead, - * and gives the best performance for light traffic to the host. - * - * However, a better scheme that could be implemented would be - * to see how many packets are outstanding for the host, and if - * the number is "large", create a long chain to DMA several - * packets into the host in one go. In this case, we would set - * up some state variables to let the host CPU continue doing - * other things until a DMA completion interrupt comes along. - */ -static void -dgrs_rcv_frame( - struct net_device *dev0, - DGRS_PRIV *priv0, - I596_CB *cbp -) -{ - int len; - I596_TBD *tbdp; - struct sk_buff *skb; - uchar *putp; - uchar *p; - struct net_device *devN; - DGRS_PRIV *privN; - - /* - * Determine Nth priv and dev structure pointers - */ - if (dgrs_nicmode) - { /* Multi-NIC mode */ - int chan = ((I596_RBD *) S2H(cbp->xmit.tbdp))->chan; - - devN = priv0->devtbl[chan-1]; - /* - * If devN is null, we got an interrupt before the I/F - * has been initialized. Pitch the packet. - */ - if (devN == NULL) - goto out; - privN = (DGRS_PRIV *) devN->priv; - } - else - { /* Switch mode */ - devN = dev0; - privN = priv0; - } - - if (0) printk("%s: rcv len=%ld\n", devN->name, cbp->xmit.count); - - /* - * Allocate a message block big enough to hold the whole frame - */ - len = cbp->xmit.count; - if ((skb = dev_alloc_skb(len+5)) == NULL) - { - printk("%s: dev_alloc_skb failed for rcv buffer\n", devN->name); - ++dev0->stats.rx_dropped; - /* discarding the frame */ - goto out; - } - skb_reserve(skb, 2); /* Align IP header */ - -again: - putp = p = skb_put(skb, len); - - /* - * There are three modes here for doing the packet copy. - * If we have DMA, and the packet is "long", we use the - * chaining mode of DMA. If it's shorter, we use single - * DMA's. Otherwise, we use memcpy(). - */ - if (priv0->use_dma && priv0->dmadesc_h && len > 64) - { - /* - * If we can use DMA and it's a long frame, copy it using - * DMA chaining. - */ - DMACHAIN *ddp_h; /* Host virtual DMA desc. pointer */ - DMACHAIN *ddp_s; /* Switch physical DMA desc. pointer */ - uchar *phys_p; - - /* - * Get the physical address of the STREAMS buffer. - * NOTE: allocb() guarantees that the whole buffer - * is in a single page if the length < 4096. - */ - phys_p = (uchar *) virt_to_phys(putp); - - ddp_h = priv0->dmadesc_h; - ddp_s = priv0->dmadesc_s; - tbdp = (I596_TBD *) S2H(cbp->xmit.tbdp); - for (;;) - { - int count; - int amt; - - count = tbdp->count; - amt = count & 0x3fff; - if (amt == 0) - break; /* For safety */ - if ( (p-putp) >= len) - { - printk("%s: cbp = %lx\n", devN->name, (long) H2S(cbp)); - proc_reset(dev0, 1); /* Freeze IDT */ - break; /* For Safety */ - } - - ddp_h->pciaddr = (ulong) phys_p; - ddp_h->lcladdr = S2DMA(tbdp->buf); - ddp_h->len = amt; - - phys_p += amt; - p += amt; - - if (count & I596_TBD_EOF) - { - ddp_h->next = PLX_DMA_DESC_TO_HOST - | PLX_DMA_DESC_EOC; - ++ddp_h; - break; - } - else - { - ++ddp_s; - ddp_h->next = PLX_DMA_DESC_TO_HOST - | (ulong) ddp_s; - tbdp = (I596_TBD *) S2H(tbdp->next); - ++ddp_h; - } - } - if (ddp_h - priv0->dmadesc_h) - { - int rc; - - rc = do_plx_dma(dev0, - 0, (ulong) priv0->dmadesc_s, len, 0); - if (rc) - { - printk("%s: Chained DMA failure\n", devN->name); - goto again; - } - } - } - else if (priv0->use_dma) - { - /* - * If we can use DMA and it's a shorter frame, copy it - * using single DMA transfers. - */ - uchar *phys_p; - - /* - * Get the physical address of the STREAMS buffer. - * NOTE: allocb() guarantees that the whole buffer - * is in a single page if the length < 4096. - */ - phys_p = (uchar *) virt_to_phys(putp); - - tbdp = (I596_TBD *) S2H(cbp->xmit.tbdp); - for (;;) - { - int count; - int amt; - int rc; - - count = tbdp->count; - amt = count & 0x3fff; - if (amt == 0) - break; /* For safety */ - if ( (p-putp) >= len) - { - printk("%s: cbp = %lx\n", devN->name, (long) H2S(cbp)); - proc_reset(dev0, 1); /* Freeze IDT */ - break; /* For Safety */ - } - rc = do_plx_dma(dev0, (ulong) phys_p, - S2DMA(tbdp->buf), amt, 1); - if (rc) - { - memcpy(p, S2H(tbdp->buf), amt); - printk("%s: Single DMA failed\n", devN->name); - } - phys_p += amt; - p += amt; - if (count & I596_TBD_EOF) - break; - tbdp = (I596_TBD *) S2H(tbdp->next); - } - } - else - { - /* - * Otherwise, copy it piece by piece using memcpy() - */ - tbdp = (I596_TBD *) S2H(cbp->xmit.tbdp); - for (;;) - { - int count; - int amt; - - count = tbdp->count; - amt = count & 0x3fff; - if (amt == 0) - break; /* For safety */ - if ( (p-putp) >= len) - { - printk("%s: cbp = %lx\n", devN->name, (long) H2S(cbp)); - proc_reset(dev0, 1); /* Freeze IDT */ - break; /* For Safety */ - } - memcpy(p, S2H(tbdp->buf), amt); - p += amt; - if (count & I596_TBD_EOF) - break; - tbdp = (I596_TBD *) S2H(tbdp->next); - } - } - - /* - * Pass the frame to upper half - */ - skb->protocol = eth_type_trans(skb, devN); - netif_rx(skb); - devN->last_rx = jiffies; - ++devN->stats.rx_packets; - devN->stats.rx_bytes += len; - -out: - cbp->xmit.status = I596_CB_STATUS_C | I596_CB_STATUS_OK; -} - -/* - * Start transmission of a frame - * - * The interface to the board is simple: we pretend that we are - * a fifth 82596 ethernet controller 'receiving' data, and copy the - * data into the same structures that a real 82596 would. This way, - * the board firmware handles the host 'port' the same as any other. - * - * NOTE: we do not use Bus master DMA for this routine. Turns out - * that it is not needed. Slave writes over the PCI bus are about - * as fast as DMA, due to the fact that the PLX part can do burst - * writes. The same is not true for data being read from the board. - * - * For multi-NIC mode, we tell the firmware the desired 82596 - * output port by setting the special "dstchan" member at the - * end of the traditional 82596 RFD structure. - */ - -static int dgrs_start_xmit(struct sk_buff *skb, struct net_device *devN) -{ - DGRS_PRIV *privN = (DGRS_PRIV *) devN->priv; - struct net_device *dev0; - DGRS_PRIV *priv0; - I596_RBD *rbdp; - int count; - int i, len, amt; - - /* - * Determine 0th priv and dev structure pointers - */ - if (dgrs_nicmode) - { - dev0 = privN->devtbl[0]; - priv0 = (DGRS_PRIV *) dev0->priv; - } - else - { - dev0 = devN; - priv0 = privN; - } - - if (dgrs_debug > 1) - printk("%s: xmit len=%d\n", devN->name, (int) skb->len); - - devN->trans_start = jiffies; - netif_start_queue(devN); - - if (priv0->rfdp->cmd & I596_RFD_EL) - { /* Out of RFD's */ - if (0) printk("%s: NO RFD's\n", devN->name); - goto no_resources; - } - - rbdp = priv0->rbdp; - count = 0; - priv0->rfdp->rbdp = (I596_RBD *) H2S(rbdp); - - i = 0; len = skb->len; - for (;;) - { - if (rbdp->size & I596_RBD_EL) - { /* Out of RBD's */ - if (0) printk("%s: NO RBD's\n", devN->name); - goto no_resources; - } - - amt = min_t(unsigned int, len, rbdp->size - count); - skb_copy_from_linear_data_offset(skb, i, S2H(rbdp->buf) + count, amt); - i += amt; - count += amt; - len -= amt; - if (len == 0) - { - if (skb->len < 60) - rbdp->count = 60 | I596_RBD_EOF; - else - rbdp->count = count | I596_RBD_EOF; - rbdp = (I596_RBD *) S2H(rbdp->next); - goto frame_done; - } - else if (count < 32) - { - /* More data to come, but we used less than 32 - * bytes of this RBD. Keep filling this RBD. - */ - {} /* Yes, we do nothing here */ - } - else - { - rbdp->count = count; - rbdp = (I596_RBD *) S2H(rbdp->next); - count = 0; - } - } - -frame_done: - priv0->rbdp = rbdp; - if (dgrs_nicmode) - priv0->rfdp->dstchan = privN->chan; - priv0->rfdp->status = I596_RFD_C | I596_RFD_OK; - priv0->rfdp = (I596_RFD *) S2H(priv0->rfdp->next); - - ++devN->stats.tx_packets; - - dev_kfree_skb (skb); - return (0); - -no_resources: - priv0->scbp->status |= I596_SCB_RNR; /* simulate I82596 */ - return (-EAGAIN); -} - -/* - * Open the interface - */ -static int -dgrs_open( struct net_device *dev ) -{ - netif_start_queue(dev); - return (0); -} - -/* - * Close the interface - */ -static int dgrs_close( struct net_device *dev ) -{ - netif_stop_queue(dev); - return (0); -} - -/* - * Set multicast list and/or promiscuous mode - */ - -static void dgrs_set_multicast_list( struct net_device *dev) -{ - DGRS_PRIV *priv = (DGRS_PRIV *) dev->priv; - - priv->port->is_promisc = (dev->flags & IFF_PROMISC) ? 1 : 0; -} - -/* - * Unique ioctl's - */ -static int dgrs_ioctl(struct net_device *devN, struct ifreq *ifr, int cmd) -{ - DGRS_PRIV *privN = (DGRS_PRIV *) devN->priv; - DGRS_IOCTL ioc; - int i; - - if (cmd != DGRSIOCTL) - return -EINVAL; - - if(copy_from_user(&ioc, ifr->ifr_data, sizeof(DGRS_IOCTL))) - return -EFAULT; - - switch (ioc.cmd) - { - case DGRS_GETMEM: - if (ioc.len != sizeof(ulong)) - return -EINVAL; - if(copy_to_user(ioc.data, &devN->mem_start, ioc.len)) - return -EFAULT; - return (0); - case DGRS_SETFILTER: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - if (ioc.port > privN->bcomm->bc_nports) - return -EINVAL; - if (ioc.filter >= NFILTERS) - return -EINVAL; - if (ioc.len > privN->bcomm->bc_filter_area_len) - return -EINVAL; - - /* Wait for old command to finish */ - for (i = 0; i < 1000; ++i) - { - if ( (volatile long) privN->bcomm->bc_filter_cmd <= 0 ) - break; - udelay(1); - } - if (i >= 1000) - return -EIO; - - privN->bcomm->bc_filter_port = ioc.port; - privN->bcomm->bc_filter_num = ioc.filter; - privN->bcomm->bc_filter_len = ioc.len; - - if (ioc.len) - { - if(copy_from_user(S2HN(privN->bcomm->bc_filter_area), - ioc.data, ioc.len)) - return -EFAULT; - privN->bcomm->bc_filter_cmd = BC_FILTER_SET; - } - else - privN->bcomm->bc_filter_cmd = BC_FILTER_CLR; - return(0); - default: - return -EOPNOTSUPP; - } -} - -/* - * Process interrupts - * - * dev, priv will always refer to the 0th device in Multi-NIC mode. - */ - -static irqreturn_t dgrs_intr(int irq, void *dev_id) -{ - struct net_device *dev0 = dev_id; - DGRS_PRIV *priv0 = dev0->priv; - I596_CB *cbp; - int cmd; - int i; - - ++priv0->intrcnt; - if (1) ++priv0->bcomm->bc_cnt[4]; - if (0) - { - static int cnt = 100; - if (--cnt > 0) - printk("%s: interrupt: irq %d\n", dev0->name, irq); - } - - /* - * Get 596 command - */ - cmd = priv0->scbp->cmd; - - /* - * See if RU has been restarted - */ - if ( (cmd & I596_SCB_RUC) == I596_SCB_RUC_START) - { - if (0) printk("%s: RUC start\n", dev0->name); - priv0->rfdp = (I596_RFD *) S2H(priv0->scbp->rfdp); - priv0->rbdp = (I596_RBD *) S2H(priv0->rfdp->rbdp); - priv0->scbp->status &= ~(I596_SCB_RNR|I596_SCB_RUS); - /* - * Tell upper half (halves) - */ - if (dgrs_nicmode) - { - for (i = 0; i < priv0->nports; ++i) - netif_wake_queue (priv0->devtbl[i]); - } - else - netif_wake_queue (dev0); - /* if (bd->flags & TX_QUEUED) - DL_sched(bd, bdd); */ - } - - /* - * See if any CU commands to process - */ - if ( (cmd & I596_SCB_CUC) != I596_SCB_CUC_START) - { - priv0->scbp->cmd = 0; /* Ignore all other commands */ - goto ack_intr; - } - priv0->scbp->status &= ~(I596_SCB_CNA|I596_SCB_CUS); - - /* - * Process a command - */ - cbp = (I596_CB *) S2H(priv0->scbp->cbp); - priv0->scbp->cmd = 0; /* Safe to clear the command */ - for (;;) - { - switch (cbp->nop.cmd & I596_CB_CMD) - { - case I596_CB_CMD_XMIT: - dgrs_rcv_frame(dev0, priv0, cbp); - break; - default: - cbp->nop.status = I596_CB_STATUS_C | I596_CB_STATUS_OK; - break; - } - if (cbp->nop.cmd & I596_CB_CMD_EL) - break; - cbp = (I596_CB *) S2H(cbp->nop.next); - } - priv0->scbp->status |= I596_SCB_CNA; - - /* - * Ack the interrupt - */ -ack_intr: - if (priv0->plxreg) - OUTL(dev0->base_addr + PLX_LCL2PCI_DOORBELL, 1); - - return IRQ_HANDLED; -} - -/* - * Download the board firmware - */ -static int __init -dgrs_download(struct net_device *dev0) -{ - DGRS_PRIV *priv0 = (DGRS_PRIV *) dev0->priv; - int is; - unsigned long i; - - static const int iv2is[16] = { - 0, 0, 0, ES4H_IS_INT3, - 0, ES4H_IS_INT5, 0, ES4H_IS_INT7, - 0, 0, ES4H_IS_INT10, ES4H_IS_INT11, - ES4H_IS_INT12, 0, 0, ES4H_IS_INT15 }; - - /* - * Map in the dual port memory - */ - priv0->vmem = ioremap(dev0->mem_start, 2048*1024); - if (!priv0->vmem) - { - printk("%s: cannot map in board memory\n", dev0->name); - return -ENXIO; - } - - /* - * Hold the processor and configure the board addresses - */ - if (priv0->plxreg) - { /* PCI bus */ - proc_reset(dev0, 1); - } - else - { /* EISA bus */ - is = iv2is[dev0->irq & 0x0f]; - if (!is) - { - printk("%s: Illegal IRQ %d\n", dev0->name, dev0->irq); - iounmap(priv0->vmem); - priv0->vmem = NULL; - return -ENXIO; - } - OUTB(dev0->base_addr + ES4H_AS_31_24, - (uchar) (dev0->mem_start >> 24) ); - OUTB(dev0->base_addr + ES4H_AS_23_16, - (uchar) (dev0->mem_start >> 16) ); - priv0->is_reg = ES4H_IS_LINEAR | is | - ((uchar) (dev0->mem_start >> 8) & ES4H_IS_AS15); - OUTB(dev0->base_addr + ES4H_IS, priv0->is_reg); - OUTB(dev0->base_addr + ES4H_EC, ES4H_EC_ENABLE); - OUTB(dev0->base_addr + ES4H_PC, ES4H_PC_RESET); - OUTB(dev0->base_addr + ES4H_MW, ES4H_MW_ENABLE | 0x00); - } - - /* - * See if we can do DMA on the SE-6 - */ - priv0->use_dma = check_board_dma(dev0); - if (priv0->use_dma) - printk("%s: Bus Master DMA is enabled.\n", dev0->name); - - /* - * Load and verify the code at the desired address - */ - memcpy(priv0->vmem, dgrs_code, dgrs_ncode); /* Load code */ - if (memcmp(priv0->vmem, dgrs_code, dgrs_ncode)) - { - iounmap(priv0->vmem); - priv0->vmem = NULL; - printk("%s: download compare failed\n", dev0->name); - return -ENXIO; - } - - /* - * Configurables - */ - priv0->bcomm = (struct bios_comm *) (priv0->vmem + 0x0100); - priv0->bcomm->bc_nowait = 1; /* Tell board to make printf not wait */ - priv0->bcomm->bc_squelch = 0; /* Flag from Space.c */ - priv0->bcomm->bc_150ohm = 0; /* Flag from Space.c */ - - priv0->bcomm->bc_spew = 0; /* Debug flag from Space.c */ - priv0->bcomm->bc_maxrfd = 0; /* Debug flag from Space.c */ - priv0->bcomm->bc_maxrbd = 0; /* Debug flag from Space.c */ - - /* - * Tell board we are operating in switch mode (1) or in - * multi-NIC mode (2). - */ - priv0->bcomm->bc_host = dgrs_nicmode ? BC_MULTINIC : BC_SWITCH; - - /* - * Request memory space on board for DMA chains - */ - if (priv0->use_dma) - priv0->bcomm->bc_hostarea_len = (2048/64) * 16; - - /* - * NVRAM configurables from Space.c - */ - priv0->bcomm->bc_spantree = dgrs_spantree; - priv0->bcomm->bc_hashexpire = dgrs_hashexpire; - memcpy(priv0->bcomm->bc_ipaddr, dgrs_ipaddr, 4); - memcpy(priv0->bcomm->bc_iptrap, dgrs_iptrap, 4); - memcpy(priv0->bcomm->bc_ipxnet, &dgrs_ipxnet, 4); - - /* - * Release processor, wait 8 seconds for board to initialize - */ - proc_reset(dev0, 0); - - for (i = jiffies + 8 * HZ; time_after(i, jiffies); ) - { - barrier(); /* Gcc 2.95 needs this */ - if (priv0->bcomm->bc_status >= BC_RUN) - break; - } - - if (priv0->bcomm->bc_status < BC_RUN) - { - printk("%s: board not operating\n", dev0->name); - iounmap(priv0->vmem); - priv0->vmem = NULL; - return -ENXIO; - } - - priv0->port = (PORT *) S2H(priv0->bcomm->bc_port); - priv0->scbp = (I596_SCB *) S2H(priv0->port->scbp); - priv0->rfdp = (I596_RFD *) S2H(priv0->scbp->rfdp); - priv0->rbdp = (I596_RBD *) S2H(priv0->rfdp->rbdp); - - priv0->scbp->status = I596_SCB_CNA; /* CU is idle */ - - /* - * Get switch physical and host virtual pointers to DMA - * chaining area. NOTE: the MSB of the switch physical - * address *must* be turned off. Otherwise, the HW kludge - * that allows host access of the PLX DMA registers will - * erroneously select the PLX registers. - */ - priv0->dmadesc_s = (DMACHAIN *) S2DMA(priv0->bcomm->bc_hostarea); - if (priv0->dmadesc_s) - priv0->dmadesc_h = (DMACHAIN *) S2H(priv0->dmadesc_s); - else - priv0->dmadesc_h = NULL; - - /* - * Enable board interrupts - */ - if (priv0->plxreg) - { /* PCI bus */ - OUTL(dev0->base_addr + PLX_INT_CSR, - inl(dev0->base_addr + PLX_INT_CSR) - | PLX_PCI_DOORBELL_IE); /* Enable intr to host */ - OUTL(dev0->base_addr + PLX_LCL2PCI_DOORBELL, 1); - } - else - { /* EISA bus */ - } - - return (0); -} - -/* - * Probe (init) a board - */ -static int __init -dgrs_probe1(struct net_device *dev) -{ - DGRS_PRIV *priv = (DGRS_PRIV *) dev->priv; - unsigned long i; - int rc; - DECLARE_MAC_BUF(mac); - - printk("%s: Digi RightSwitch io=%lx mem=%lx irq=%d plx=%lx dma=%lx\n", - dev->name, dev->base_addr, dev->mem_start, dev->irq, - priv->plxreg, priv->plxdma); - - /* - * Download the firmware and light the processor - */ - rc = dgrs_download(dev); - if (rc) - goto err_out; - - /* - * Get ether address of board - */ - memcpy(dev->dev_addr, priv->port->ethaddr, 6); - printk("%s: Ethernet address %s\n", - dev->name, print_mac(mac, dev->dev_addr)); - - if (dev->dev_addr[0] & 1) - { - printk("%s: Illegal Ethernet Address\n", dev->name); - rc = -ENXIO; - goto err_out; - } - - /* - * ACK outstanding interrupts, hook the interrupt, - * and verify that we are getting interrupts from the board. - */ - if (priv->plxreg) - OUTL(dev->base_addr + PLX_LCL2PCI_DOORBELL, 1); - - rc = request_irq(dev->irq, &dgrs_intr, IRQF_SHARED, "RightSwitch", dev); - if (rc) - goto err_out; - - priv->intrcnt = 0; - for (i = jiffies + 2*HZ + HZ/2; time_after(i, jiffies); ) - { - cpu_relax(); - if (priv->intrcnt >= 2) - break; - } - if (priv->intrcnt < 2) - { - printk(KERN_ERR "%s: Not interrupting on IRQ %d (%d)\n", - dev->name, dev->irq, priv->intrcnt); - rc = -ENXIO; - goto err_free_irq; - } - - /* - * Entry points... - */ - dev->open = &dgrs_open; - dev->stop = &dgrs_close; - dev->hard_start_xmit = &dgrs_start_xmit; - dev->set_multicast_list = &dgrs_set_multicast_list; - dev->do_ioctl = &dgrs_ioctl; - - return rc; - -err_free_irq: - free_irq(dev->irq, dev); -err_out: - return rc; -} - -static int __init -dgrs_initclone(struct net_device *dev) -{ - DGRS_PRIV *priv = (DGRS_PRIV *) dev->priv; - DECLARE_MAC_BUF(mac); - - printk("%s: Digi RightSwitch port %d %s\n", - dev->name, priv->chan, print_mac(mac, dev->dev_addr)); - - return 0; -} - -static struct net_device * __init -dgrs_found_device( - int io, - ulong mem, - int irq, - ulong plxreg, - ulong plxdma, - struct device *pdev -) -{ - DGRS_PRIV *priv; - struct net_device *dev; - int i, ret = -ENOMEM; - - dev = alloc_etherdev(sizeof(DGRS_PRIV)); - if (!dev) - goto err0; - - priv = (DGRS_PRIV *)dev->priv; - - dev->base_addr = io; - dev->mem_start = mem; - dev->mem_end = mem + 2048 * 1024 - 1; - dev->irq = irq; - priv->plxreg = plxreg; - priv->plxdma = plxdma; - priv->vplxdma = NULL; - - priv->chan = 1; - priv->devtbl[0] = dev; - - SET_NETDEV_DEV(dev, pdev); - - ret = dgrs_probe1(dev); - if (ret) - goto err1; - - ret = register_netdev(dev); - if (ret) - goto err2; - - if ( !dgrs_nicmode ) - return dev; /* Switch mode, we are done */ - - /* - * Operating card as N separate NICs - */ - - priv->nports = priv->bcomm->bc_nports; - - for (i = 1; i < priv->nports; ++i) - { - struct net_device *devN; - DGRS_PRIV *privN; - /* Allocate new dev and priv structures */ - devN = alloc_etherdev(sizeof(DGRS_PRIV)); - ret = -ENOMEM; - if (!devN) - goto fail; - - /* Don't copy the network device structure! */ - - /* copy the priv structure of dev[0] */ - privN = (DGRS_PRIV *)devN->priv; - *privN = *priv; - - /* ... and zero out VM areas */ - privN->vmem = NULL; - privN->vplxdma = NULL; - /* ... and zero out IRQ */ - devN->irq = 0; - /* ... and base MAC address off address of 1st port */ - devN->dev_addr[5] += i; - - ret = dgrs_initclone(devN); - if (ret) - goto fail; - - SET_NETDEV_DEV(dev, pdev); - - ret = register_netdev(devN); - if (ret) { - free_netdev(devN); - goto fail; - } - privN->chan = i+1; - priv->devtbl[i] = devN; - } - return dev; - - fail: - while (i >= 0) { - struct net_device *d = priv->devtbl[i--]; - unregister_netdev(d); - free_netdev(d); - } - - err2: - free_irq(dev->irq, dev); - err1: - free_netdev(dev); - err0: - return ERR_PTR(ret); -} - -static void __devexit dgrs_remove(struct net_device *dev) -{ - DGRS_PRIV *priv = dev->priv; - int i; - - unregister_netdev(dev); - - for (i = 1; i < priv->nports; ++i) { - struct net_device *d = priv->devtbl[i]; - if (d) { - unregister_netdev(d); - free_netdev(d); - } - } - - proc_reset(priv->devtbl[0], 1); - - if (priv->vmem) - iounmap(priv->vmem); - if (priv->vplxdma) - iounmap((uchar *) priv->vplxdma); - - if (dev->irq) - free_irq(dev->irq, dev); - - for (i = 1; i < priv->nports; ++i) { - if (priv->devtbl[i]) - unregister_netdev(priv->devtbl[i]); - } -} - -#ifdef CONFIG_PCI -static int __init dgrs_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - struct net_device *dev; - int err; - uint io; - uint mem; - uint irq; - uint plxreg; - uint plxdma; - - /* - * Get and check the bus-master and latency values. - * Some PCI BIOSes fail to set the master-enable bit, - * and the latency timer must be set to the maximum - * value to avoid data corruption that occurs when the - * timer expires during a transfer. Yes, it's a bug. - */ - err = pci_enable_device(pdev); - if (err) - return err; - err = pci_request_regions(pdev, "RightSwitch"); - if (err) - return err; - - pci_set_master(pdev); - - plxreg = pci_resource_start (pdev, 0); - io = pci_resource_start (pdev, 1); - mem = pci_resource_start (pdev, 2); - pci_read_config_dword(pdev, 0x30, &plxdma); - irq = pdev->irq; - plxdma &= ~15; - - /* - * On some BIOSES, the PLX "expansion rom" (used for DMA) - * address comes up as "0". This is probably because - * the BIOS doesn't see a valid 55 AA ROM signature at - * the "ROM" start and zeroes the address. To get - * around this problem the SE-6 is configured to ask - * for 4 MB of space for the dual port memory. We then - * must set its range back to 2 MB, and use the upper - * half for DMA register access - */ - OUTL(io + PLX_SPACE0_RANGE, 0xFFE00000L); - if (plxdma == 0) - plxdma = mem + (2048L * 1024L); - pci_write_config_dword(pdev, 0x30, plxdma + 1); - pci_read_config_dword(pdev, 0x30, &plxdma); - plxdma &= ~15; - - dev = dgrs_found_device(io, mem, irq, plxreg, plxdma, &pdev->dev); - if (IS_ERR(dev)) { - pci_release_regions(pdev); - return PTR_ERR(dev); - } - - pci_set_drvdata(pdev, dev); - return 0; -} - -static void __devexit dgrs_pci_remove(struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata(pdev); - - dgrs_remove(dev); - pci_release_regions(pdev); - free_netdev(dev); -} - -static struct pci_driver dgrs_pci_driver = { - .name = "dgrs", - .id_table = dgrs_pci_tbl, - .probe = dgrs_pci_probe, - .remove = __devexit_p(dgrs_pci_remove), -}; -#else -static struct pci_driver dgrs_pci_driver = {}; -#endif - - -#ifdef CONFIG_EISA -static int is2iv[8] __initdata = { 0, 3, 5, 7, 10, 11, 12, 15 }; - -static int __init dgrs_eisa_probe (struct device *gendev) -{ - struct net_device *dev; - struct eisa_device *edev = to_eisa_device(gendev); - uint io = edev->base_addr; - uint mem; - uint irq; - int rc = -ENODEV; /* Not EISA configured */ - - if (!request_region(io, 256, "RightSwitch")) { - printk(KERN_ERR "dgrs: eisa io 0x%x, which is busy.\n", io); - return -EBUSY; - } - - if ( ! (inb(io+ES4H_EC) & ES4H_EC_ENABLE) ) - goto err_out; - - mem = (inb(io+ES4H_AS_31_24) << 24) - + (inb(io+ES4H_AS_23_16) << 16); - - irq = is2iv[ inb(io+ES4H_IS) & ES4H_IS_INTMASK ]; - - dev = dgrs_found_device(io, mem, irq, 0L, 0L, gendev); - if (IS_ERR(dev)) { - rc = PTR_ERR(dev); - goto err_out; - } - - gendev->driver_data = dev; - return 0; - err_out: - release_region(io, 256); - return rc; -} - -static int __devexit dgrs_eisa_remove(struct device *gendev) -{ - struct net_device *dev = gendev->driver_data; - - dgrs_remove(dev); - - release_region(dev->base_addr, 256); - - free_netdev(dev); - return 0; -} - - -static struct eisa_driver dgrs_eisa_driver = { - .id_table = dgrs_eisa_tbl, - .driver = { - .name = "dgrs", - .probe = dgrs_eisa_probe, - .remove = __devexit_p(dgrs_eisa_remove), - } -}; -#endif - -/* - * Variables that can be overriden from module command line - */ -static int debug = -1; -static int dma = -1; -static int hashexpire = -1; -static int spantree = -1; -static int ipaddr[4] = { -1 }; -static int iptrap[4] = { -1 }; -static __u32 ipxnet = -1; -static int nicmode = -1; - -module_param(debug, int, 0); -module_param(dma, int, 0); -module_param(hashexpire, int, 0); -module_param(spantree, int, 0); -module_param_array(ipaddr, int, NULL, 0); -module_param_array(iptrap, int, NULL, 0); -module_param(ipxnet, int, 0); -module_param(nicmode, int, 0); -MODULE_PARM_DESC(debug, "Digi RightSwitch enable debugging (0-1)"); -MODULE_PARM_DESC(dma, "Digi RightSwitch enable BM DMA (0-1)"); -MODULE_PARM_DESC(nicmode, "Digi RightSwitch operating mode (1: switch, 2: multi-NIC)"); - -static int __init dgrs_init_module (void) -{ - int i; - int err; - - /* - * Command line variable overrides - * debug=NNN - * dma=0/1 - * spantree=0/1 - * hashexpire=NNN - * ipaddr=A,B,C,D - * iptrap=A,B,C,D - * ipxnet=NNN - * nicmode=NNN - */ - if (debug >= 0) - dgrs_debug = debug; - if (dma >= 0) - dgrs_dma = dma; - if (nicmode >= 0) - dgrs_nicmode = nicmode; - if (hashexpire >= 0) - dgrs_hashexpire = hashexpire; - if (spantree >= 0) - dgrs_spantree = spantree; - if (ipaddr[0] != -1) - for (i = 0; i < 4; ++i) - dgrs_ipaddr[i] = ipaddr[i]; - if (iptrap[0] != -1) - for (i = 0; i < 4; ++i) - dgrs_iptrap[i] = iptrap[i]; - if (ipxnet != -1) - dgrs_ipxnet = htonl( ipxnet ); - - if (dgrs_debug) - { - printk(KERN_INFO "dgrs: SW=%s FW=Build %d %s\nFW Version=%s\n", - version, dgrs_firmnum, dgrs_firmdate, dgrs_firmver); - } - - /* - * Find and configure all the cards - */ -#ifdef CONFIG_EISA - err = eisa_driver_register(&dgrs_eisa_driver); - if (err) - return err; -#endif - err = pci_register_driver(&dgrs_pci_driver); - if (err) - return err; - return 0; -} - -static void __exit dgrs_cleanup_module (void) -{ -#ifdef CONFIG_EISA - eisa_driver_unregister (&dgrs_eisa_driver); -#endif -#ifdef CONFIG_PCI - pci_unregister_driver (&dgrs_pci_driver); -#endif -} - -module_init(dgrs_init_module); -module_exit(dgrs_cleanup_module); diff --git a/drivers/net/dgrs.h b/drivers/net/dgrs.h deleted file mode 100644 index 6058d5301cb..00000000000 --- a/drivers/net/dgrs.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * ioctl's for the Digi Intl. RightSwitch - * - * These network driver ioctl's are a bit obtuse compared to the usual - * ioctl's for a "normal" device driver. Hey, I didn't invent it. - * - * Typical use: - * - * struct ifreq ifr; - * DGRS_IOCTL ioc; - * int x; - * - * strcpy(ifr.ifr_name, "eth1"); - * ifr.ifr_data = (caddr_t) &ioc; - * ioc.cmd = DGRS_GETMEM; - * ioc.len = sizeof(x); - * ioc.data = (caddr_t) &x; - * rc = ioctl(fd, DGRSIOCTL, &ifr); - * printf("rc=%d mem=%x\n", rc, x); - * - */ -#include - -#define DGRSIOCTL SIOCDEVPRIVATE - -typedef struct dgrs_ioctl { - unsigned short cmd; /* Command to run */ - unsigned short len; /* Length of the data buffer */ - unsigned char __user *data; /* Pointer to the data buffer */ - unsigned short port; /* port number for command, if needed */ - unsigned short filter; /* filter number for command, if needed */ -} DGRS_IOCTL; - -/* - * Commands for the driver - */ -#define DGRS_GETMEM 0x01 /* Get the dual port memory address */ -#define DGRS_SETFILTER 0x02 /* Set a filter */ diff --git a/drivers/net/dgrs_asstruct.h b/drivers/net/dgrs_asstruct.h deleted file mode 100644 index f0e2121770f..00000000000 --- a/drivers/net/dgrs_asstruct.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * For declaring structures shared with assembly routines - * - * $Id: asstruct.h,v 1.1.1.1 1994/10/23 05:08:32 rick Exp $ - */ - -#ifdef ASSEMBLER - -# define MO(t,a) (a) -# define VMO(t,a) (a) - -# define BEGIN_STRUCT(x) _Off=0 -# define S1A(t,x,n) _Off=(_Off+0)&~0; x=_Off; _Off=_Off+(1*n) -# define S2A(t,x,n) _Off=(_Off+1)&~1; x=_Off; _Off=_Off+(2*n) -# define S4A(t,x,n) _Off=(_Off+3)&~3; x=_Off; _Off=_Off+(4*n) -# define WORD(x) _Off=(_Off+3)&~3; x=_Off; _Off=_Off+4 -# define WORDA(x,n) _Off=(_Off+3)&~3; x=_Off; _Off=_Off+(4*n) -# define VWORD(x) _Off=(_Off+3)&~3; x=_Off; _Off=_Off+4 -# define S1(t,x) _Off=(_Off+0)&~0; x=_Off; _Off=_Off+1 -# define S2(t,x) _Off=(_Off+1)&~1; x=_Off; _Off=_Off+2 -# define S4(t,x) _Off=(_Off+3)&~3; x=_Off; _Off=_Off+4 -# define END_STRUCT(x) _Off=(_Off+3)&~3; x=_Off - -#else /* C */ - -#define VMO(t,a) (*(volatile t *)(a)) - -# define BEGIN_STRUCT(x) struct x { -# define S1(t,x) t x ; -# define S1A(t,x,n) t x[n] ; -# define S2(t,x) t x ; -# define S2A(t,x,n) t x[n] ; -# define S4(t,x) t x ; -# define S4A(t,x,n) t x[n] ; -# define END_STRUCT(x) } ; - -#endif diff --git a/drivers/net/dgrs_bcomm.h b/drivers/net/dgrs_bcomm.h deleted file mode 100644 index 5e9c2527398..00000000000 --- a/drivers/net/dgrs_bcomm.h +++ /dev/null @@ -1,148 +0,0 @@ -/* - * The bios low-memory structure - * - * Some of the variables in here can be used to set parameters that - * are stored in NVRAM and will retain their old values the next time - * the card is brought up. To use the values stored in NVRAM, the - * parameter should be set to "all ones". This tells the firmware to - * use the NVRAM value or a suitable default. The value that is used - * will be stored back into this structure by the firmware. If the - * value of the variable is not "all ones", then that value will be - * used and will be stored into NVRAM if it isn't already there. - * The variables this applies to are the following: - * Variable Set to: Gets default of: - * bc_hashexpire -1 300 (5 minutes) - * bc_spantree -1 1 (spanning tree on) - * bc_ipaddr FF:FF:FF:FF 0 (no SNMP IP address) - * bc_ipxnet FF:FF:FF:FF 0 (no SNMP IPX net) - * bc_iptrap FF:FF:FF:FF 0 (no SNMP IP trap address) - * - * Some variables MUST have their value set after the firmware - * is loaded onto the board, but before the processor is released. - * These are: - * bc_host 0 means no host "port", run as standalone switch. - * 1 means run as a switch, with a host port. (normal) - * 2 means run as multiple NICs, not as a switch. - * -1 means run in diagnostics mode. - * bc_nowait - * bc_hostarea_len - * bc_filter_len - * - */ -BEGIN_STRUCT(bios_comm) - S4(ulong, bc_intflag) /* Count of all interrupts */ - S4(ulong, bc_lbolt) /* Count of timer interrupts */ - S4(ulong, bc_maincnt) /* Count of main loops */ - S4(ulong, bc_hashcnt) /* Count of entries in hash table */ - S4A(ulong, bc_cnt, 8) /* Misc counters, for debugging */ - S4A(ulong, bc_flag, 8) /* Misc flags, for debugging */ - S4(ulong, bc_memsize) /* Size of memory */ - S4(ulong, bc_dcache) /* Size of working dcache */ - S4(ulong, bc_icache) /* Size of working icache */ - S4(long, bc_status) /* Firmware status */ - S1A(char, bc_file, 8) /* File name of assertion failure */ - S4(ulong, bc_line) /* Line # of assertion failure */ - S4(uchar *, bc_ramstart) - S4(uchar *, bc_ramend) - S4(uchar *, bc_heapstart) /* Start of heap (end of loaded memory) */ - S4(uchar *, bc_heapend) /* End of heap */ - - /* Configurable Parameters */ - S4(long, bc_host) /* 1=Host Port, 0=No Host Port, -1=Test Mode */ - S4(long, bc_nowait) /* Don't wait for 2host circ buffer to empty*/ - S4(long, bc_150ohm) /* 0 == 100 ohm UTP, 1 == 150 ohm STP */ - S4(long, bc_squelch) /* 0 == normal squelch, 1 == reduced squelch */ - S4(ulong, bc_hashexpire) /* Expiry time in seconds for hash table */ - S4(long, bc_spantree) /* 1 == enable IEEE spanning tree */ - - S2A(ushort, bc_eaddr, 3) /* New ether address */ - S2(ushort, bc_dummy1) /* padding for DOS compilers */ - - /* Various debugging aids */ - S4(long, bc_debug) /* Debugging is turned on */ - S4(long, bc_spew) /* Spew data on port 4 for bs_spew seconds */ - S4(long, bc_spewlen) /* Length of spewed data packets */ - S4(long, bc_maxrfd) /* If != 0, max number of RFD's to allocate */ - S4(long, bc_maxrbd) /* If != 0, max number of RBD's to allocate */ - - /* Circular buffers for messages to/from host */ - S4(ulong, bc_2host_head) - S4(ulong, bc_2host_tail) - S4(ulong, bc_2host_mask) - S1A(char, bc_2host, 0x200) /* Circ buff to host */ - - S4(ulong, bc_2idt_head) - S4(ulong, bc_2idt_tail) - S4(ulong, bc_2idt_mask) - S1A(char, bc_2idt, 0x200) /* Circ buff to idt */ - - /* Pointers to structures for driver access */ - S4(uchar *, bc_port) /* pointer to Port[] structures */ - S4(long, bc_nports) /* Number of ports */ - S4(long, bc_portlen) /* sizeof(PORT) */ - S4(uchar *, bc_hash) /* Pointer to hash table */ - S4(long, bc_hashlen) /* sizeof(Table) */ - - /* SNMP agent addresses */ - S1A(uchar, bc_ipaddr, 4) /* IP address for SNMP */ - S1A(uchar, bc_ipxnet, 4) /* IPX net address for SNMP */ - - S4(long, bc_nohostintr) /* Do not cause periodic host interrupts */ - - S4(uchar *, bc_dmaaddr) /* Physical addr of host DMA buf for diags */ - S4(ulong, bc_dmalen) /* Length of DMA buffer 0..2048 */ - - /* - * Board memory allocated on startup for use by host, usually - * for the purposes of creating DMA chain descriptors. The - * "len" must be set before the processor is released. The - * address of the area is returned in bc_hostarea. The area - * is guaranteed to be aligned on a 16 byte boundary. - */ - S4(ulong, bc_hostarea_len) /* RW: Number of bytes to allocate */ - S4(uchar *, bc_hostarea) /* RO: Address of allocated memory */ - - /* - * Variables for communicating filters into the board - */ - S4(ulong *, bc_filter_area) /* RO: Space to put filter into */ - S4(ulong, bc_filter_area_len) /* RO: Length of area, in bytes */ - S4(long, bc_filter_cmd) /* RW: Filter command, see below */ - S4(ulong, bc_filter_len) /* RW: Actual length of filter */ - S4(ulong, bc_filter_port) /* RW: Port # for filter 0..6 */ - S4(ulong, bc_filter_num) /* RW: Filter #, 0=input, 1=output */ - - /* more SNMP agent addresses */ - S1A(uchar, bc_iptrap, 4) /* IP address for SNMP */ - - S4A(long, bc_spare, 2) /* spares */ -END_STRUCT(bios_comm) - -#define bc VMO(struct bios_comm, 0xa3000100) - -/* - * bc_status values - */ -#define BC_INIT 0 -#define BC_RUN 100 - -/* - * bc_host values - */ -#define BC_DIAGS -1 -#define BC_SASWITCH 0 -#define BC_SWITCH 1 -#define BC_MULTINIC 2 - -/* - * Values for spew (debugging) - */ -#define BC_SPEW_ENABLE 0x80000000 - -/* - * filter commands - */ -#define BC_FILTER_ERR -1 -#define BC_FILTER_OK 0 -#define BC_FILTER_SET 1 -#define BC_FILTER_CLR 2 diff --git a/drivers/net/dgrs_es4h.h b/drivers/net/dgrs_es4h.h deleted file mode 100644 index 5518fba46b2..00000000000 --- a/drivers/net/dgrs_es4h.h +++ /dev/null @@ -1,183 +0,0 @@ -/************************************************************************/ -/* */ -/* es4h.h: Hardware definition of the ES/4h Ethernet Switch, from */ -/* both the host and the 3051's point of view. */ -/* NOTE: this name is a misnomer now that there is a PCI */ -/* board. Everything that says "es4h" should really be */ -/* "se4". But we'll keep the old name for now. */ -/* */ -/* $Id: es4h.h,v 1.10 1996/08/22 17:16:53 rick Exp $ */ -/* */ -/************************************************************************/ - -/************************************************************************/ -/* */ -/* EISA I/O Registers. These are located at 0x1000 * slot-number */ -/* plus the indicated address. I.E. 0x4000-0x4009 for slot 4. */ -/* */ -/************************************************************************/ - -#define ES4H_MANUFmsb 0x00 /* Read-only */ -#define ES4H_MANUFlsb 0x01 /* Read-only */ -# define ES4H_MANUF_CODE 0x1049 /* = "DBI" */ - -#define ES4H_PRODUCT 0x02 /* Read-only */ -# define ES4H_PRODUCT_CODE 0x0A -# define EPC_PRODUCT_CODE 0x03 - -#define ES4H_REVISION 0x03 /* Read-only */ -# define ES4H_REVISION_CODE 0x01 - -#define ES4H_EC 0x04 /* EISA Control */ -# define ES4H_EC_RESET 0x04 /* WO, EISA reset */ -# define ES4H_EC_ENABLE 0x01 /* RW, EISA enable - set to */ - /* 1 before memory enable */ -#define ES4H_PC 0x05 /* Processor Control */ -# define ES4H_PC_RESET 0x04 /* RW, 3051 reset */ -# define ES4H_PC_INT 0x08 /* WO, assert 3051 intr. 3 */ - -#define ES4H_MW 0x06 /* Memory Window select and enable */ -# define ES4H_MW_ENABLE 0x80 /* WO, enable memory */ -# define ES4H_MW_SELECT_MASK 0x1f /* WO, 32k window selected */ - -#define ES4H_IS 0x07 /* Interrupt, addr select */ -# define ES4H_IS_INTMASK 0x07 /* WO, interrupt select */ -# define ES4H_IS_INTOFF 0x00 /* No IRQ */ -# define ES4H_IS_INT3 0x03 /* IRQ 3 */ -# define ES4H_IS_INT5 0x02 /* IRQ 5 */ -# define ES4H_IS_INT7 0x01 /* IRQ 7 */ -# define ES4H_IS_INT10 0x04 /* IRQ 10 */ -# define ES4H_IS_INT11 0x05 /* IRQ 11 */ -# define ES4H_IS_INT12 0x06 /* IRQ 12 */ -# define ES4H_IS_INT15 0x07 /* IRQ 15 */ -# define ES4H_IS_INTACK 0x10 /* WO, interrupt ack */ -# define ES4H_IS_INTPEND 0x10 /* RO, interrupt pending */ -# define ES4H_IS_LINEAR 0x40 /* WO, no memory windowing */ -# define ES4H_IS_AS15 0x80 /* RW, address select bit 15 */ - -#define ES4H_AS_23_16 0x08 /* Address select bits 23-16 */ -#define ES4H_AS_31_24 0x09 /* Address select bits 31-24 */ - -#define ES4H_IO_MAX 0x09 /* Size of I/O space */ - -/* - * PCI - */ -#define SE6_RESET PLX_USEROUT - -/************************************************************************/ -/* */ -/* 3051 Memory Map */ -/* */ -/* Note: 3051 has 4K I-cache, 2K D-cache. 1 cycle is 50 nsec. */ -/* */ -/************************************************************************/ -#define SE4_NPORTS 4 /* # of ethernet ports */ -#define SE6_NPORTS 6 /* # of ethernet ports */ -#define SE_NPORTS 6 /* Max # of ethernet ports */ - -#define ES4H_RAM_BASE 0x83000000 /* Base address of RAM */ -#define ES4H_RAM_SIZE 0x00200000 /* Size of RAM (2MB) */ -#define ES4H_RAM_INTBASE 0x83800000 /* Base of int-on-write RAM */ - /* a.k.a. PKT RAM */ - - /* Ethernet controllers */ - /* See: i82596.h */ -#define ES4H_ETHER0_PORT 0xA2000000 -#define ES4H_ETHER0_CMD 0xA2000100 -#define ES4H_ETHER1_PORT 0xA2000200 -#define ES4H_ETHER1_CMD 0xA2000300 -#define ES4H_ETHER2_PORT 0xA2000400 -#define ES4H_ETHER2_CMD 0xA2000500 -#define ES4H_ETHER3_PORT 0xA2000600 -#define ES4H_ETHER3_CMD 0xA2000700 -#define ES4H_ETHER4_PORT 0xA2000800 /* RS SE-6 only */ -#define ES4H_ETHER4_CMD 0xA2000900 /* RS SE-6 only */ -#define ES4H_ETHER5_PORT 0xA2000A00 /* RS SE-6 only */ -#define ES4H_ETHER5_CMD 0xA2000B00 /* RS SE-6 only */ - -#define ES4H_I8254 0xA2040000 /* 82C54 timers */ - /* See: i8254.h */ - -#define SE4_I8254_HZ (23000000/4) /* EISA clock input freq. */ -#define SE4_IDT_HZ (46000000) /* EISA CPU freq. */ -#define SE6_I8254_HZ (20000000/4) /* PCI clock input freq. */ -#define SE6_IDT_HZ (50000000) /* PCI CPU freq. */ -#define ES4H_I8254_HZ (23000000/4) /* EISA clock input freq. */ - -#define ES4H_GPP 0xA2050000 /* General purpose port */ - /* - * SE-4 (EISA) GPP bits - */ -# define ES4H_GPP_C0_100 0x0001 /* WO, Chan 0: 100 ohm TP */ -# define ES4H_GPP_C0_SQE 0x0002 /* WO, Chan 0: normal squelch */ -# define ES4H_GPP_C1_100 0x0004 /* WO, Chan 1: 100 ohm TP */ -# define ES4H_GPP_C1_SQE 0x0008 /* WO, Chan 1: normal squelch */ -# define ES4H_GPP_C2_100 0x0010 /* WO, Chan 2: 100 ohm TP */ -# define ES4H_GPP_C2_SQE 0x0020 /* WO, Chan 2: normal squelch */ -# define ES4H_GPP_C3_100 0x0040 /* WO, Chan 3: 100 ohm TP */ -# define ES4H_GPP_C3_SQE 0x0080 /* WO, Chan 3: normal squelch */ -# define ES4H_GPP_SQE 0x00AA /* WO, All: normal squelch */ -# define ES4H_GPP_100 0x0055 /* WO, All: 100 ohm TP */ -# define ES4H_GPP_HOSTINT 0x0100 /* RO, cause intr. to host */ - /* Hold high > 250 nsec */ -# define SE4_GPP_EED 0x0200 /* RW, EEPROM data bit */ -# define SE4_GPP_EECS 0x0400 /* RW, EEPROM chip select */ -# define SE4_GPP_EECK 0x0800 /* RW, EEPROM clock */ - - /* - * SE-6 (PCI) GPP bits - */ -# define SE6_GPP_EED 0x0001 /* RW, EEPROM data bit */ -# define SE6_GPP_EECS 0x0002 /* RW, EEPROM chip select */ -# define SE6_GPP_EECK 0x0004 /* RW, EEPROM clock */ -# define SE6_GPP_LINK 0x00fc /* R, Link status LEDs */ - -#define ES4H_INTVEC 0xA2060000 /* RO: Interrupt Vector */ -# define ES4H_IV_DMA0 0x01 /* Chan 0 DMA interrupt */ -# define ES4H_IV_PKT0 0x02 /* Chan 0 PKT interrupt */ -# define ES4H_IV_DMA1 0x04 /* Chan 1 DMA interrupt */ -# define ES4H_IV_PKT1 0x08 /* Chan 1 PKT interrupt */ -# define ES4H_IV_DMA2 0x10 /* Chan 2 DMA interrupt */ -# define ES4H_IV_PKT2 0x20 /* Chan 2 PKT interrupt */ -# define ES4H_IV_DMA3 0x40 /* Chan 3 DMA interrupt */ -# define ES4H_IV_PKT3 0x80 /* Chan 3 PKT interrupt */ - -#define ES4H_INTACK 0xA2060000 /* WO: Interrupt Ack */ -# define ES4H_INTACK_8254 0x01 /* Real Time Clock (int 0) */ -# define ES4H_INTACK_HOST 0x02 /* Host (int 1) */ -# define ES4H_INTACK_PKT0 0x04 /* Chan 0 Pkt (int 2) */ -# define ES4H_INTACK_PKT1 0x08 /* Chan 1 Pkt (int 3) */ -# define ES4H_INTACK_PKT2 0x10 /* Chan 2 Pkt (int 4) */ -# define ES4H_INTACK_PKT3 0x20 /* Chan 3 Pkt (int 5) */ - -#define SE6_PLX 0xA2070000 /* PLX 9060, SE-6 (PCI) only */ - /* see plx9060.h */ - -#define SE6_PCI_VENDOR_ID 0x114F /* Digi PCI vendor ID */ -#define SE6_PCI_DEVICE_ID 0x0003 /* RS SE-6 device ID */ -#define SE6_PCI_ID ((SE6_PCI_DEVICE_ID<<16) | SE6_PCI_VENDOR_ID) - -/* - * IDT Interrupts - */ -#define ES4H_INT_8254 IDT_INT0 -#define ES4H_INT_HOST IDT_INT1 -#define ES4H_INT_ETHER0 IDT_INT2 -#define ES4H_INT_ETHER1 IDT_INT3 -#define ES4H_INT_ETHER2 IDT_INT4 -#define ES4H_INT_ETHER3 IDT_INT5 - -/* - * Because there are differences between the SE-4 and the SE-6, - * we assume that the following globals will be set up at init - * time in main.c to containt the appropriate constants from above - */ -extern ushort Gpp; /* Softcopy of GPP register */ -extern ushort EEck; /* Clock bit */ -extern ushort EEcs; /* CS bit */ -extern ushort EEd; /* Data bit */ -extern ulong I8254_Hz; /* i8254 input frequency */ -extern ulong IDT_Hz; /* IDT CPU frequency */ -extern int Nports; /* Number of ethernet controllers */ -extern int Nchan; /* Nports+1 */ diff --git a/drivers/net/dgrs_ether.h b/drivers/net/dgrs_ether.h deleted file mode 100644 index 7539b596bff..00000000000 --- a/drivers/net/dgrs_ether.h +++ /dev/null @@ -1,135 +0,0 @@ -/* - * A filtering function. There are two filters/port. Filter "0" - * is the input filter, and filter "1" is the output filter. - */ -typedef int (FILTER_FUNC)(uchar *pktp, int pktlen, ulong *scratch, int port); -#define NFILTERS 2 - -/* - * The per port structure - */ -typedef struct -{ - int chan; /* Channel number (0-3) */ - ulong portaddr; /* address of 596 port register */ - volatile ulong *ca; /* address of 596 chan attention */ - ulong intmask; /* Interrupt mask for this port */ - ulong intack; /* Ack bit for this port */ - - uchar ethaddr[6]; /* Ethernet address of this port */ - int is_promisc; /* Port is promiscuous */ - - int debug; /* Debugging turned on */ - - I596_ISCP *iscpp; /* Uncached ISCP pointer */ - I596_SCP *scpp; /* Uncached SCP pointer */ - I596_SCB *scbp; /* Uncached SCB pointer */ - - I596_ISCP iscp; - I596_SCB scb; - - /* Command Queue */ - I596_CB *cb0; - I596_CB *cbN; - I596_CB *cb_head; - I596_CB *cb_tail; - - /* Receive Queue */ - I596_RFD *rfd0; - I596_RFD *rfdN; - I596_RFD *rfd_head; - I596_RFD *rfd_tail; - - /* Receive Buffers */ - I596_RBD *rbd0; - I596_RBD *rbdN; - I596_RBD *rbd_head; - I596_RBD *rbd_tail; - int buf_size; /* Size of an RBD buffer */ - int buf_cnt; /* Total RBD's allocated */ - - /* Rx Statistics */ - ulong cnt_rx_cnt; /* Total packets rcvd, good and bad */ - ulong cnt_rx_good; /* Total good packets rcvd */ - ulong cnt_rx_bad; /* Total of all bad packets rcvd */ - /* Subtotals can be gotten from SCB */ - ulong cnt_rx_nores; /* No resources */ - ulong cnt_rx_bytes; /* Total bytes rcvd */ - - /* Tx Statistics */ - ulong cnt_tx_queued; - ulong cnt_tx_done; - ulong cnt_tx_freed; - ulong cnt_tx_nores; /* No resources */ - - ulong cnt_tx_bad; - ulong cnt_tx_err_late; - ulong cnt_tx_err_nocrs; - ulong cnt_tx_err_nocts; - ulong cnt_tx_err_under; - ulong cnt_tx_err_maxcol; - ulong cnt_tx_collisions; - - /* Special stuff for host */ -# define rfd_freed cnt_rx_cnt - ulong rbd_freed; - int host_timer; - - /* Added after first beta */ - ulong cnt_tx_races; /* Counts race conditions */ - int spanstate; - ulong cnt_st_tx; /* send span tree pkts */ - ulong cnt_st_fail_tx; /* Failures to send span tree pkts */ - ulong cnt_st_fail_rbd;/* Failures to send span tree pkts */ - ulong cnt_st_rx; /* rcv span tree pkts */ - ulong cnt_st_rx_bad; /* bogus st packets rcvd */ - ulong cnt_rx_fwd; /* Rcvd packets that were forwarded */ - - ulong cnt_rx_mcast; /* Multicast pkts received */ - ulong cnt_tx_mcast; /* Multicast pkts transmitted */ - ulong cnt_tx_bytes; /* Bytes transmitted */ - - /* - * Packet filtering - * Filter 0: input filter - * Filter 1: output filter - */ - - ulong *filter_space[NFILTERS]; - FILTER_FUNC *filter_func[NFILTERS]; - ulong filter_cnt[NFILTERS]; - ulong filter_len[NFILTERS]; - - ulong pad[ (512-300) / 4]; -} PORT; - -/* - * Port[0] is host interface - * Port[1..SE_NPORTS] are external 10 Base T ports. Fewer may be in - * use, depending on whether this is an SE-4 or - * an SE-6. - * Port[SE_NPORTS] Pseudo-port for Spanning tree and SNMP - */ -extern PORT Port[1+SE_NPORTS+1]; - -extern int Nports; /* Number of genuine ethernet controllers */ -extern int Nchan; /* ... plus one for host interface */ - -extern int FirstChan; /* 0 or 1, depedning on whether host is used */ -extern int NumChan; /* 4 or 5 */ - -/* - * A few globals - */ -extern int IsPromisc; -extern int MultiNicMode; - -/* - * Functions - */ -extern void eth_xmit_spew_on(PORT *p, int cnt); -extern void eth_xmit_spew_off(PORT *p); - -extern I596_RBD *alloc_rbds(PORT *p, int num); - -extern I596_CB * eth_cb_alloc(PORT *p); diff --git a/drivers/net/dgrs_firmware.c b/drivers/net/dgrs_firmware.c deleted file mode 100644 index 8c20d4c9993..00000000000 --- a/drivers/net/dgrs_firmware.c +++ /dev/null @@ -1,9966 +0,0 @@ -static const int dgrs_firmnum = 550; -static char dgrs_firmver[] = "$Version$"; -static char dgrs_firmdate[] = "11/16/96 03:45:15"; -static unsigned char dgrs_code[] __initdata = { - 213,5,192,8,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,64,40,35,41, - 101,115,52,104,46,98,105,110,32,32,32,32, - 32,32,49,46,48,32,48,48,47,48,48,47, - 57,52,0,64,40,35,41,67,111,112,121,114, - 105,103,104,116,32,49,57,57,53,44,32,68, - 105,103,105,32,73,110,116,101,114,110,97,116, - 105,111,110,97,108,46,32,32,65,108,108,32, - 82,105,103,104,116,115,32,82,101,115,101,114, - 118,101,100,46,0,0,0,0,97,5,192,8, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,255,255,0,16,0,0,0,0, - 0,0,0,0,8,0,224,3,0,0,0,0, - 148,255,189,39,16,0,161,175,20,0,162,175, - 24,0,163,175,28,0,164,175,32,0,165,175, - 36,0,166,175,40,0,167,175,44,0,168,175, - 48,0,169,175,52,0,170,175,56,0,171,175, - 60,0,172,175,64,0,173,175,68,0,174,175, - 72,0,175,175,76,0,184,175,80,0,185,175, - 88,0,190,175,92,0,191,175,0,112,8,64, - 18,72,0,0,16,80,0,0,0,96,11,64, - 84,0,168,175,96,0,169,175,100,0,170,175, - 104,0,171,175,33,56,0,1,0,131,24,60, - 0,1,24,39,0,0,8,143,0,0,0,0, - 1,0,8,33,0,0,8,175,0,104,5,64, - 0,96,6,64,124,0,168,48,212,255,0,21, - 0,0,0,0,36,64,166,0,0,255,8,49, - 27,0,0,17,0,0,0,0,130,65,8,0, - 2,131,9,60,33,72,40,1,0,220,41,141, - 66,64,8,0,2,131,10,60,33,80,72,1, - 0,224,74,141,0,0,0,0,38,80,70,1, - 1,255,74,49,33,40,192,0,38,48,202,0, - 0,96,134,64,66,64,8,0,2,131,4,60, - 33,32,136,0,0,226,132,144,9,248,32,1, - 0,0,0,0,104,0,166,143,0,0,0,0, - 0,96,134,64,0,104,5,64,227,255,0,16, - 0,0,0,0,104,0,168,143,96,0,169,143, - 100,0,170,143,0,0,0,0,0,96,136,64, - 19,0,32,1,17,0,64,1,20,0,162,143, - 24,0,163,143,28,0,164,143,32,0,165,143, - 36,0,166,143,40,0,167,143,44,0,168,143, - 48,0,169,143,52,0,170,143,56,0,171,143, - 60,0,172,143,64,0,173,143,68,0,174,143, - 72,0,175,143,76,0,184,143,80,0,185,143, - 88,0,190,143,92,0,191,143,0,0,0,0, - 84,0,186,143,16,0,161,143,108,0,189,39, - 8,0,64,3,16,0,0,66,0,96,26,64, - 0,0,0,0,255,255,27,60,254,0,123,55, - 0,0,0,0,36,208,91,3,0,0,0,0, - 0,96,154,64,0,0,0,0,0,112,26,64, - 0,0,0,0,16,0,0,66,0,0,0,0, - 8,0,64,3,0,0,0,0,255,255,8,36, - 133,255,0,17,0,0,0,0,1,0,8,37, - 130,255,0,21,0,0,0,0,255,255,8,36, - 33,8,0,1,126,255,40,20,0,0,0,0, - 1,0,33,36,123,255,32,20,0,0,0,0, - 255,255,2,36,120,255,72,20,0,0,0,0, - 1,0,66,36,117,255,64,20,0,0,0,0, - 255,255,3,36,114,255,104,20,0,0,0,0, - 1,0,99,36,111,255,96,20,0,0,0,0, - 255,255,4,36,108,255,136,20,0,0,0,0, - 1,0,132,36,105,255,128,20,0,0,0,0, - 255,255,5,36,102,255,168,20,0,0,0,0, - 1,0,165,36,99,255,160,20,0,0,0,0, - 255,255,6,36,96,255,200,20,0,0,0,0, - 1,0,198,36,93,255,192,20,0,0,0,0, - 255,255,7,36,90,255,232,20,0,0,0,0, - 1,0,231,36,87,255,224,20,0,0,0,0, - 255,255,9,36,84,255,40,21,0,0,0,0, - 1,0,41,37,81,255,32,21,0,0,0,0, - 255,255,10,36,78,255,72,21,0,0,0,0, - 1,0,74,37,75,255,64,21,0,0,0,0, - 255,255,11,36,72,255,104,21,0,0,0,0, - 1,0,107,37,69,255,96,21,0,0,0,0, - 255,255,12,36,66,255,136,21,0,0,0,0, - 1,0,140,37,63,255,128,21,0,0,0,0, - 255,255,13,36,60,255,168,21,0,0,0,0, - 1,0,173,37,57,255,160,21,0,0,0,0, - 255,255,14,36,54,255,200,21,0,0,0,0, - 1,0,206,37,51,255,192,21,0,0,0,0, - 255,255,15,36,48,255,232,21,0,0,0,0, - 1,0,239,37,45,255,224,21,0,0,0,0, - 255,255,24,36,42,255,8,23,0,0,0,0, - 1,0,24,39,39,255,0,23,0,0,0,0, - 255,255,16,36,36,255,8,22,0,0,0,0, - 1,0,16,38,33,255,0,22,0,0,0,0, - 255,255,17,36,30,255,40,22,0,0,0,0, - 1,0,49,38,27,255,32,22,0,0,0,0, - 255,255,18,36,24,255,72,22,0,0,0,0, - 1,0,82,38,21,255,64,22,0,0,0,0, - 255,255,19,36,18,255,104,22,0,0,0,0, - 1,0,115,38,15,255,96,22,0,0,0,0, - 255,255,20,36,12,255,136,22,0,0,0,0, - 1,0,148,38,9,255,128,22,0,0,0,0, - 255,255,21,36,6,255,168,22,0,0,0,0, - 1,0,181,38,3,255,160,22,0,0,0,0, - 255,255,22,36,0,255,200,22,0,0,0,0, - 1,0,214,38,253,254,192,22,0,0,0,0, - 255,255,23,36,250,254,232,22,0,0,0,0, - 1,0,247,38,247,254,224,22,0,0,0,0, - 255,255,26,36,244,254,72,23,0,0,0,0, - 1,0,90,39,241,254,64,23,0,0,0,0, - 255,255,27,36,238,254,104,23,0,0,0,0, - 1,0,123,39,235,254,96,23,0,0,0,0, - 255,255,28,36,232,254,136,23,0,0,0,0, - 1,0,156,39,229,254,128,23,0,0,0,0, - 255,255,29,36,226,254,168,23,0,0,0,0, - 1,0,189,39,223,254,160,23,0,0,0,0, - 255,255,30,36,220,254,200,23,0,0,0,0, - 1,0,222,39,217,254,192,23,0,0,0,0, - 255,255,31,36,214,254,232,23,0,0,0,0, - 1,0,255,39,211,254,224,23,0,0,0,0, - 0,131,24,60,0,1,24,39,0,32,1,60, - 37,192,1,3,0,96,8,64,0,0,0,0, - 1,0,1,60,37,64,1,1,0,96,136,64, - 33,16,0,0,165,165,3,60,165,165,99,52, - 0,128,1,60,0,0,35,172,0,128,9,60, - 0,0,41,141,0,0,0,0,0,96,10,64, - 0,0,0,0,8,0,1,60,36,80,65,1, - 29,0,64,21,0,0,0,0,27,0,105,20, - 0,0,0,0,0,1,2,36,0,128,1,60, - 33,8,34,0,0,0,32,172,64,16,2,0, - 1,0,1,60,1,0,33,52,43,8,65,0, - 248,255,32,20,0,0,0,0,255,255,3,36, - 0,128,1,60,0,0,35,172,0,1,2,36, - 0,128,3,60,33,24,98,0,0,0,99,140, - 0,0,0,0,7,0,96,20,0,0,0,0, - 64,16,2,0,1,0,1,60,1,0,33,52, - 43,8,65,0,245,255,32,20,0,0,0,0, - 0,96,128,64,0,0,0,0,84,0,2,175, - 0,96,8,64,0,0,0,0,3,0,1,60, - 37,64,1,1,0,96,136,64,33,16,0,0, - 165,165,3,60,165,165,99,52,0,128,1,60, - 0,0,35,172,0,128,9,60,0,0,41,141, - 0,0,0,0,0,96,10,64,0,0,0,0, - 8,0,1,60,36,80,65,1,29,0,64,21, - 0,0,0,0,27,0,105,20,0,0,0,0, - 0,1,2,36,0,128,1,60,33,8,34,0, - 0,0,32,172,64,16,2,0,1,0,1,60, - 1,0,33,52,43,8,65,0,248,255,32,20, - 0,0,0,0,255,255,3,36,0,128,1,60, - 0,0,35,172,0,1,2,36,0,128,3,60, - 33,24,98,0,0,0,99,140,0,0,0,0, - 7,0,96,20,0,0,0,0,64,16,2,0, - 1,0,1,60,1,0,33,52,43,8,65,0, - 245,255,32,20,0,0,0,0,0,96,128,64, - 0,0,0,0,88,0,2,175,88,0,9,143, - 0,0,0,0,17,0,32,17,0,0,0,0, - 0,0,0,0,3,0,2,60,0,0,0,0, - 0,96,130,64,0,128,8,60,37,72,40,1, - 0,0,0,161,4,0,0,161,8,0,0,161, - 12,0,0,161,16,0,0,161,20,0,0,161, - 24,0,0,161,32,0,8,37,247,255,9,21, - 252,255,0,161,84,0,9,143,0,0,0,0, - 17,0,32,17,0,0,0,0,0,0,0,0, - 1,0,2,60,0,0,0,0,0,96,130,64, - 0,128,8,60,37,72,40,1,0,0,0,161, - 4,0,0,161,8,0,0,161,12,0,0,161, - 16,0,0,161,20,0,0,161,24,0,0,161, - 32,0,8,37,247,255,9,21,252,255,0,161, - 32,0,8,60,0,96,136,64,0,104,128,64, - 0,131,2,60,152,28,66,36,255,31,9,60, - 255,255,41,53,36,16,73,0,0,128,9,60, - 37,16,73,0,8,0,64,0,0,0,0,0, - 2,131,8,60,224,210,8,37,252,255,1,36, - 36,64,1,1,3,131,9,60,124,18,41,37, - 252,255,1,36,36,72,33,1,0,0,10,36, - 0,0,10,173,254,255,9,21,4,0,8,37, - 3,131,8,60,128,18,8,37,252,255,1,36, - 36,64,1,1,31,131,9,60,252,255,41,53, - 252,255,1,36,36,72,33,1,237,254,10,60, - 175,222,74,53,0,0,10,173,254,255,9,21, - 4,0,8,37,2,131,8,60,0,212,8,37, - 252,255,1,36,36,64,1,1,2,131,9,60, - 252,219,41,37,252,255,1,36,36,72,33,1, - 173,222,10,60,239,190,74,53,0,0,10,173, - 254,255,9,21,4,0,8,37,0,4,8,60, - 0,0,0,0,0,24,136,64,0,0,0,0, - 2,131,29,60,0,220,189,39,0,0,30,36, - 2,131,28,60,51,8,192,12,16,78,156,39, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 232,255,189,39,16,0,191,175,8,128,132,39, - 15,63,192,12,0,0,0,0,16,0,191,143, - 24,0,189,39,8,0,224,3,0,0,0,0, - 232,255,189,39,16,0,191,175,12,128,132,39, - 15,63,192,12,0,0,0,0,16,0,191,143, - 24,0,189,39,8,0,224,3,0,0,0,0, - 232,255,189,39,16,0,191,175,16,128,132,39, - 15,63,192,12,0,0,0,0,16,0,191,143, - 24,0,189,39,8,0,224,3,0,0,0,0, - 232,255,189,39,16,0,191,175,20,128,132,39, - 15,63,192,12,0,0,0,0,16,0,191,143, - 24,0,189,39,8,0,224,3,0,0,0,0, - 232,255,189,39,24,133,131,143,6,0,2,36, - 20,0,191,175,6,0,98,20,16,0,176,175, - 7,162,3,60,228,0,99,52,1,0,2,36, - 184,7,192,8,0,0,98,172,0,128,130,151, - 5,162,16,60,0,1,66,52,120,63,192,12, - 0,0,2,166,0,128,130,151,0,0,0,0, - 255,254,66,48,0,0,2,166,20,0,191,143, - 16,0,176,143,8,0,224,3,24,0,189,39, - 232,255,189,39,33,16,128,0,3,0,64,4, - 16,0,191,175,254,255,2,60,192,29,66,52, - 0,163,4,60,96,1,132,52,0,163,1,60, - 92,1,34,172,0,163,1,60,104,1,38,172, - 204,63,192,12,8,0,6,36,228,63,192,12, - 255,255,4,36,204,7,192,8,0,0,0,0, - 16,0,191,143,24,0,189,39,8,0,224,3, - 0,0,0,0,216,255,189,39,1,0,6,36, - 3,131,2,60,143,18,66,36,240,255,3,36, - 36,16,67,0,0,163,1,60,120,1,34,172, - 0,163,2,60,120,1,66,140,33,56,0,0, - 32,0,191,175,28,0,177,175,24,0,176,175, - 16,0,160,175,0,163,1,60,116,1,34,172, - 0,163,3,60,112,1,99,140,0,163,2,60, - 116,1,66,140,0,163,4,60,116,1,132,140, - 35,136,98,0,84,64,192,12,33,40,32,2, - 13,0,64,16,0,0,0,0,1,131,4,60, - 96,127,132,36,24,128,144,39,33,40,0,2, - 1,131,7,60,128,127,231,36,15,63,192,12, - 148,0,6,36,1,0,4,36,33,40,0,2, - 188,7,192,12,148,0,6,36,2,0,33,6, - 33,16,32,2,3,0,34,38,131,136,2,0, - 0,163,2,60,116,1,66,140,0,0,0,0, - 6,0,32,18,237,254,3,60,175,222,99,52, - 0,0,67,172,255,255,49,38,253,255,32,22, - 4,0,66,36,32,0,191,143,28,0,177,143, - 24,0,176,143,8,0,224,3,40,0,189,39, - 224,255,189,39,15,0,132,36,240,255,3,36, - 20,0,177,175,0,163,17,60,120,1,49,142, - 0,163,2,60,120,1,66,140,36,32,131,0, - 33,16,68,0,0,163,1,60,120,1,34,172, - 0,163,3,60,120,1,99,140,0,163,2,60, - 112,1,66,140,24,0,191,175,43,16,67,0, - 13,0,64,16,16,0,176,175,1,131,4,60, - 96,127,132,36,24,128,144,39,33,40,0,2, - 1,131,7,60,176,127,231,36,15,63,192,12, - 171,0,6,36,1,0,4,36,33,40,0,2, - 188,7,192,12,171,0,6,36,33,16,32,2, - 24,0,191,143,20,0,177,143,16,0,176,143, - 8,0,224,3,32,0,189,39,216,255,189,39, - 3,0,2,60,7,162,3,60,36,0,191,175, - 32,0,176,175,0,163,1,60,92,1,32,172, - 0,0,99,140,79,17,66,52,32,0,98,20, - 87,0,4,60,76,0,8,60,64,75,8,53, - 250,2,7,60,128,240,231,52,7,162,6,60, - 152,0,198,52,67,73,3,60,67,3,99,52, - 7,162,4,60,48,1,132,52,7,162,5,60, - 0,1,165,52,6,0,2,36,24,133,130,175, - 0,163,1,60,204,5,34,172,4,0,2,36, - 50,133,130,167,2,0,2,36,48,133,130,167, - 1,0,2,36,20,133,130,167,119,119,2,36, - 28,133,136,175,16,133,135,175,0,0,195,172, - 0,0,130,172,67,1,2,36,0,0,162,172, - 109,8,192,8,31,131,4,60,240,188,132,52, - 189,2,3,60,128,231,99,52,4,0,2,36, - 24,133,130,175,0,163,1,60,204,5,34,172, - 0,8,2,36,50,133,130,167,0,4,2,36, - 48,133,130,167,0,2,2,36,20,133,130,167, - 28,133,132,175,16,133,131,175,31,131,4,60, - 0,240,132,52,24,133,131,143,0,131,2,60, - 0,163,1,60,108,1,34,172,0,163,1,60, - 112,1,36,172,1,0,99,36,32,133,131,175, - 210,7,192,12,0,0,0,0,0,163,2,60, - 132,1,66,140,0,128,128,167,2,0,64,20, - 85,0,2,36,0,128,130,167,0,163,2,60, - 136,1,66,140,0,0,0,0,5,0,64,20, - 0,0,0,0,0,128,130,151,0,0,0,0, - 170,0,66,52,0,128,130,167,0,128,131,151, - 5,162,2,60,0,0,67,164,188,64,192,12, - 1,0,16,36,2,131,4,60,0,220,132,36, - 2,131,5,60,0,224,165,36,2,131,6,60, - 0,226,198,36,8,0,7,36,2,131,2,60, - 112,154,66,36,16,0,162,175,2,131,2,60, - 144,154,66,36,20,0,162,175,2,131,2,60, - 176,154,66,36,24,0,162,175,0,131,2,60, - 36,30,66,36,0,163,1,60,92,1,48,172, - 240,64,192,12,28,0,162,175,0,163,3,60, - 124,1,99,140,40,133,128,175,2,0,98,40, - 7,0,64,16,2,0,2,36,18,0,97,4, - 255,255,2,36,7,0,98,16,0,0,0,0, - 196,8,192,8,0,0,0,0,16,0,98,16, - 0,0,0,0,196,8,192,8,0,0,0,0, - 24,133,133,143,1,131,4,60,15,63,192,12, - 208,127,132,36,0,163,1,60,112,25,192,12, - 124,1,32,172,207,8,192,8,0,0,0,0, - 211,8,192,12,0,0,0,0,207,8,192,8, - 0,0,0,0,40,133,144,175,31,10,192,12, - 0,0,0,0,207,8,192,8,0,0,0,0, - 1,131,4,60,96,127,132,36,24,128,144,39, - 33,40,0,2,32,128,135,39,15,63,192,12, - 58,1,6,36,1,0,4,36,33,40,0,2, - 188,7,192,12,58,1,6,36,36,0,191,143, - 32,0,176,143,8,0,224,3,40,0,189,39, - 192,255,189,39,56,0,191,175,52,0,181,175, - 48,0,180,175,44,0,179,175,40,0,178,175, - 36,0,177,175,180,10,192,12,32,0,176,175, - 33,32,0,0,2,0,2,36,0,163,1,60, - 244,57,192,12,92,1,34,172,3,0,2,36, - 0,163,1,60,0,12,192,12,92,1,34,172, - 1,0,4,36,4,0,2,36,0,163,1,60, - 34,11,192,12,92,1,34,172,5,0,2,36, - 0,163,1,60,92,1,34,172,0,163,19,60, - 124,1,115,142,0,163,3,60,160,1,99,140, - 1,0,98,46,80,133,130,175,0,128,2,60, - 5,0,98,20,0,0,0,0,32,133,130,143, - 0,0,0,0,252,8,192,8,255,255,66,36, - 32,133,130,143,0,0,0,0,84,133,130,175, - 130,11,192,12,0,0,0,0,33,32,64,0, - 2,0,5,36,232,3,6,36,0,131,7,60, - 196,37,231,36,156,11,192,12,16,0,160,175, - 35,35,192,12,0,0,0,0,6,0,2,36, - 0,163,1,60,84,35,192,12,92,1,34,172, - 7,0,2,36,0,163,1,60,141,47,192,12, - 92,1,34,172,8,0,2,36,0,163,1,60, - 120,50,192,12,92,1,34,172,9,0,2,36, - 0,163,1,60,92,1,34,172,0,163,2,60, - 240,5,66,140,0,0,0,0,8,0,64,16, - 10,0,2,36,0,163,4,60,240,5,132,140, - 13,8,192,12,0,0,0,0,0,163,1,60, - 244,5,34,172,10,0,2,36,0,163,1,60, - 92,1,34,172,157,15,192,12,1,0,21,36, - 2,131,2,60,192,246,66,36,33,160,64,0, - 80,133,131,143,11,0,2,36,0,163,1,60, - 92,1,34,172,100,0,2,36,0,163,1,60, - 92,1,34,172,84,133,130,143,64,26,3,0, - 33,136,116,0,64,18,2,0,33,144,84,0, - 0,163,2,60,8,1,66,140,0,0,0,0, - 1,0,66,36,0,163,1,60,8,1,34,172, - 0,163,2,60,8,1,66,140,0,163,2,60, - 124,1,66,140,0,0,0,0,14,0,83,16, - 0,0,0,0,4,0,64,16,33,152,64,0, - 80,133,128,175,76,9,192,8,0,0,0,0, - 80,133,149,175,2,131,4,60,163,23,192,12, - 192,246,132,36,80,133,130,143,0,0,0,0, - 64,18,2,0,33,136,84,0,0,163,2,60, - 0,6,66,140,0,0,0,0,3,0,64,24, - 33,128,32,2,239,15,192,12,0,0,0,0, - 43,16,18,2,11,0,64,16,33,32,0,2, - 151,18,192,12,10,0,5,36,27,22,192,12, - 33,32,0,2,142,22,192,12,33,32,0,2, - 0,2,16,38,43,16,18,2,247,255,64,20, - 33,32,0,2,184,11,192,12,0,0,0,0, - 54,9,192,8,0,0,0,0,56,0,191,143, - 52,0,181,143,48,0,180,143,44,0,179,143, - 40,0,178,143,36,0,177,143,32,0,176,143, - 8,0,224,3,64,0,189,39,4,128,130,143, - 232,255,189,39,20,0,191,175,16,0,176,175, - 1,0,67,36,4,128,131,175,255,255,3,36, - 4,0,67,20,255,31,4,60,0,163,1,60, - 8,1,32,172,255,31,4,60,255,255,132,52, - 0,163,16,60,0,163,2,60,8,1,66,140, - 208,132,131,143,220,5,16,54,35,16,67,0, - 0,163,1,60,16,1,34,172,2,131,2,60, - 192,246,66,36,36,16,68,0,0,160,3,60, - 37,16,67,0,0,163,3,60,8,1,99,140, - 28,0,68,140,0,0,5,142,3,131,2,60, - 20,18,66,140,208,132,131,175,36,133,132,175, - 18,0,162,16,0,163,4,60,99,59,192,12, - 220,5,132,52,255,0,5,60,255,0,165,52, - 0,255,6,60,0,0,4,142,0,255,198,52, - 0,20,4,0,2,28,4,0,37,16,67,0, - 2,26,2,0,36,24,101,0,0,18,2,0, - 36,16,70,0,37,24,98,0,176,133,132,175, - 184,133,131,175,0,163,16,60,16,6,16,54, - 0,0,3,142,3,131,2,60,68,18,66,140, - 0,0,0,0,18,0,98,16,0,163,4,60, - 119,59,192,12,16,6,132,52,255,0,5,60, - 255,0,165,52,0,255,6,60,0,0,4,142, - 0,255,198,52,0,20,4,0,2,28,4,0, - 37,16,67,0,2,26,2,0,36,24,101,0, - 0,18,2,0,36,16,70,0,37,24,98,0, - 196,133,132,175,192,133,131,175,0,163,16,60, - 224,5,16,54,0,0,3,142,3,131,2,60, - 24,18,66,140,0,0,0,0,18,0,98,16, - 0,163,4,60,139,59,192,12,224,5,132,52, - 255,0,5,60,255,0,165,52,0,255,6,60, - 0,0,4,142,0,255,198,52,0,20,4,0, - 2,28,4,0,37,16,67,0,2,26,2,0, - 36,24,101,0,0,18,2,0,36,16,70,0, - 37,24,98,0,188,133,132,175,180,133,131,175, - 44,133,131,143,0,163,2,60,144,1,66,140, - 0,0,0,0,5,0,98,16,0,0,0,0, - 0,163,4,60,144,1,132,140,159,59,192,12, - 0,0,0,0,0,163,3,60,140,1,99,140, - 3,131,2,60,64,18,66,140,0,0,0,0, - 5,0,98,16,0,0,0,0,0,163,4,60, - 140,1,132,140,51,60,192,12,0,0,0,0, - 44,133,130,143,0,0,0,0,3,0,64,16, - 0,0,0,0,116,38,192,12,0,0,0,0, - 164,7,192,12,0,0,0,0,36,128,130,143, - 0,0,0,0,1,0,66,36,36,128,130,175, - 60,0,66,40,8,0,64,20,0,0,0,0, - 3,131,2,60,24,18,66,140,36,128,128,175, - 3,0,64,16,0,0,0,0,222,48,192,12, - 0,0,0,0,0,163,2,60,48,1,66,140, - 0,0,0,0,20,0,64,16,0,0,0,0, - 0,163,1,60,48,1,32,172,0,163,1,60, - 16,1,32,172,0,163,1,60,20,1,32,172, - 0,163,1,60,24,1,32,172,0,163,1,60, - 28,1,32,172,0,163,1,60,32,1,32,172, - 0,163,1,60,36,1,32,172,0,163,1,60, - 40,1,32,172,0,163,1,60,201,13,192,12, - 44,1,32,172,20,0,191,143,16,0,176,143, - 8,0,224,3,24,0,189,39,216,255,189,39, - 36,0,191,175,32,0,178,175,28,0,177,175, - 180,10,192,12,24,0,176,175,33,32,0,0, - 2,0,2,36,0,163,1,60,244,57,192,12, - 92,1,34,172,3,0,2,36,0,163,1,60, - 0,12,192,12,92,1,34,172,1,0,4,36, - 4,0,2,36,0,163,1,60,34,11,192,12, - 92,1,34,172,32,133,131,143,5,0,2,36, - 0,163,1,60,92,1,34,172,80,133,128,175, - 84,133,131,175,130,11,192,12,0,0,0,0, - 33,32,64,0,2,0,5,36,232,3,6,36, - 0,131,7,60,196,37,231,36,156,11,192,12, - 16,0,160,175,0,163,2,60,240,5,66,140, - 0,0,0,0,8,0,64,16,10,0,2,36, - 0,163,4,60,240,5,132,140,13,8,192,12, - 0,0,0,0,0,163,1,60,244,5,34,172, - 10,0,2,36,0,163,1,60,92,1,34,172, - 100,0,2,36,80,133,131,143,2,131,4,60, - 192,246,132,36,0,163,1,60,92,1,34,172, - 84,133,130,143,64,26,3,0,33,144,100,0, - 64,18,2,0,33,136,68,0,0,163,2,60, - 8,1,66,140,33,128,64,2,1,0,66,36, - 0,163,1,60,8,1,34,172,0,163,2,60, - 8,1,66,140,43,16,17,2,11,0,64,16, - 33,32,0,2,151,18,192,12,10,0,5,36, - 27,22,192,12,33,32,0,2,142,22,192,12, - 33,32,0,2,0,2,16,38,43,16,17,2, - 247,255,64,20,33,32,0,2,184,11,192,12, - 0,0,0,0,91,10,192,8,0,0,0,0, - 36,0,191,143,32,0,178,143,28,0,177,143, - 24,0,176,143,8,0,224,3,40,0,189,39, - 4,128,130,143,232,255,189,39,16,0,191,175, - 1,0,67,36,4,128,131,175,255,255,3,36, - 4,0,67,20,255,31,4,60,0,163,1,60, - 8,1,32,172,255,31,4,60,0,163,2,60, - 8,1,66,140,212,132,131,143,255,255,132,52, - 35,16,67,0,0,163,1,60,16,1,34,172, - 2,131,2,60,192,246,66,36,36,16,68,0, - 0,160,3,60,37,16,67,0,0,163,3,60, - 8,1,99,140,28,0,66,140,212,132,131,175, - 36,133,130,175,164,7,192,12,0,0,0,0, - 0,163,2,60,48,1,66,140,0,0,0,0, - 20,0,64,16,0,0,0,0,0,163,1,60, - 48,1,32,172,0,163,1,60,16,1,32,172, - 0,163,1,60,20,1,32,172,0,163,1,60, - 24,1,32,172,0,163,1,60,28,1,32,172, - 0,163,1,60,32,1,32,172,0,163,1,60, - 36,1,32,172,0,163,1,60,40,1,32,172, - 0,163,1,60,201,13,192,12,44,1,32,172, - 16,0,191,143,24,0,189,39,8,0,224,3, - 0,0,0,0,224,255,189,39,24,0,191,175, - 20,0,177,175,120,63,192,12,16,0,176,175, - 52,0,2,36,4,162,1,60,12,0,34,160, - 120,63,192,12,232,3,16,36,28,133,130,143, - 0,0,0,0,27,0,80,0,2,0,0,22, - 0,0,0,0,13,0,7,0,18,16,0,0, - 4,162,17,60,120,63,192,12,0,0,34,162, - 28,133,130,143,0,0,0,0,27,0,80,0, - 2,0,0,22,0,0,0,0,13,0,7,0, - 18,16,0,0,33,40,0,0,33,32,0,0, - 6,162,3,60,2,18,2,0,0,0,34,162, - 1,0,2,36,0,163,1,60,4,1,32,172, - 0,0,98,172,2,131,1,60,33,8,36,0, - 8,245,32,172,1,0,165,36,22,0,162,44, - 250,255,64,20,20,0,132,36,31,131,4,60, - 0,240,132,52,52,128,131,143,1,0,2,36, - 68,133,128,175,48,128,130,175,64,133,128,175, - 32,131,1,60,252,239,36,172,8,0,96,16, - 31,131,5,60,252,239,165,52,31,131,6,60, - 1,131,4,60,224,127,132,36,15,63,192,12, - 0,240,198,52,52,128,128,175,24,0,191,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 32,0,189,39,232,255,189,39,16,0,176,175, - 116,0,2,36,20,0,191,175,4,162,1,60, - 12,0,34,160,130,63,192,12,33,128,128,0, - 4,162,1,60,4,0,48,160,130,63,192,12, - 3,130,16,0,4,162,1,60,130,63,192,12, - 4,0,48,160,20,0,191,143,16,0,176,143, - 8,0,224,3,24,0,189,39,224,255,189,39, - 64,0,2,36,24,0,191,175,20,0,177,175, - 16,0,176,175,4,162,1,60,130,63,192,12, - 12,0,34,160,4,162,17,60,4,0,49,146, - 0,0,0,0,130,63,192,12,255,0,49,50, - 4,162,16,60,4,0,16,146,0,0,0,0, - 130,63,192,12,255,0,16,50,0,130,16,0, - 37,16,17,2,24,0,191,143,20,0,177,143, - 16,0,176,143,8,0,224,3,32,0,189,39, - 48,128,130,143,232,255,189,39,16,0,176,175, - 33,128,128,0,3,0,64,20,20,0,191,175, - 180,10,192,12,0,0,0,0,5,0,0,18, - 0,0,0,0,236,63,192,12,1,4,4,36, - 50,11,192,8,0,0,0,0,228,63,192,12, - 0,4,4,36,20,0,191,143,16,0,176,143, - 8,0,224,3,24,0,189,39,216,255,189,39, - 6,162,3,60,1,0,2,36,32,0,191,175, - 28,0,177,175,24,0,176,175,0,0,98,172, - 0,163,2,60,4,1,66,140,33,136,224,0, - 1,0,66,36,0,163,1,60,4,1,34,172, - 56,128,130,143,0,163,3,60,4,1,99,140, - 1,0,66,36,56,128,130,175,232,3,66,40, - 21,0,64,20,255,127,3,60,68,133,130,143, - 254,255,99,52,56,128,128,175,1,0,66,36, - 43,24,98,0,68,133,130,175,13,0,96,16, - 0,0,0,0,2,131,4,60,28,128,132,36, - 60,128,144,39,33,40,0,2,2,131,7,60, - 60,128,231,36,15,63,192,12,144,0,6,36, - 1,0,4,36,33,40,0,2,188,7,192,12, - 144,0,6,36,64,133,134,143,0,0,0,0, - 14,0,192,24,33,24,0,0,2,131,5,60, - 0,245,165,36,33,32,0,0,2,131,2,60, - 33,16,68,0,0,245,66,140,20,0,132,36, - 1,0,99,36,255,255,66,36,0,0,162,172, - 42,16,102,0,247,255,64,20,20,0,165,36, - 31,131,4,60,252,239,132,52,31,131,2,60, - 0,0,131,140,255,255,66,52,0,0,113,172, - 4,0,99,36,43,16,67,0,3,0,64,16, - 0,0,0,0,31,131,3,60,0,240,99,52, - 0,0,131,172,32,0,191,143,28,0,177,143, - 24,0,176,143,8,0,224,3,40,0,189,39, - 64,133,130,143,232,255,189,39,20,0,191,175, - 22,0,66,40,13,0,64,20,16,0,176,175, - 2,131,4,60,28,128,132,36,60,128,144,39, - 33,40,0,2,2,131,7,60,84,128,231,36, - 15,63,192,12,173,0,6,36,1,0,4,36, - 33,40,0,2,188,7,192,12,173,0,6,36, - 64,133,130,143,0,0,0,0,1,0,67,36, - 64,133,131,175,20,0,191,143,16,0,176,143, - 8,0,224,3,24,0,189,39,128,16,4,0, - 33,16,68,0,16,0,163,143,128,16,2,0, - 2,131,1,60,33,8,34,0,4,245,38,172, - 2,131,1,60,33,8,34,0,12,245,39,172, - 2,131,1,60,33,8,34,0,0,245,38,172, - 2,131,1,60,33,8,34,0,8,245,37,172, - 2,131,1,60,33,8,34,0,16,245,35,172, - 8,0,224,3,33,16,0,1,128,16,4,0, - 33,16,68,0,128,16,2,0,2,131,1,60, - 33,8,34,0,8,0,224,3,8,245,32,172, - 64,133,130,143,192,255,189,39,40,0,180,175, - 33,160,0,0,56,0,191,175,52,0,183,175, - 48,0,182,175,44,0,181,175,36,0,179,175, - 32,0,178,175,28,0,177,175,48,0,64,24, - 24,0,176,175,1,0,23,36,2,0,22,36, - 2,131,16,60,12,245,16,38,4,0,19,38, - 244,255,17,38,252,255,18,38,33,168,0,0, - 0,0,67,142,0,0,0,0,7,0,119,16, - 2,0,98,40,25,0,64,20,0,0,0,0, - 9,0,118,16,0,0,0,0,236,11,192,8, - 20,0,16,38,0,0,34,142,0,0,0,0, - 17,0,64,28,0,0,0,0,230,11,192,8, - 0,0,64,174,0,0,34,142,0,0,0,0, - 11,0,64,28,0,0,0,0,2,131,2,60, - 33,16,85,0,4,245,66,140,0,0,0,0, - 0,0,34,174,0,0,100,142,0,0,2,142, - 0,0,0,0,9,248,64,0,0,0,0,0, - 20,0,16,38,20,0,115,38,20,0,49,38, - 20,0,82,38,64,133,130,143,1,0,148,38, - 42,16,130,2,218,255,64,20,20,0,181,38, - 56,0,191,143,52,0,183,143,48,0,182,143, - 44,0,181,143,40,0,180,143,36,0,179,143, - 32,0,178,143,28,0,177,143,24,0,176,143, - 8,0,224,3,64,0,189,39,0,0,0,0, - 2,131,3,60,192,246,99,36,0,2,2,36, - 0,163,1,60,200,5,35,172,0,163,1,60, - 208,5,34,172,0,163,2,60,124,1,66,140, - 216,255,189,39,16,0,176,175,33,128,0,0, - 28,0,179,175,255,255,19,36,24,0,178,175, - 21,0,114,36,20,0,177,175,32,0,191,175, - 1,0,66,44,80,133,130,175,139,14,192,12, - 20,0,113,36,184,24,192,12,0,0,0,0, - 27,67,192,12,33,32,0,2,6,0,83,20, - 1,0,16,38,2,131,4,60,15,63,192,12, - 112,128,132,36,126,12,192,8,1,0,2,36, - 0,0,34,162,3,18,2,0,0,0,66,162, - 2,0,82,38,3,0,2,42,241,255,64,20, - 2,0,49,38,2,131,17,60,212,246,49,38, - 33,32,32,2,33,40,0,0,255,127,6,60, - 247,24,192,12,255,255,198,52,255,31,3,60, - 255,255,99,52,236,255,48,38,36,0,34,38, - 36,16,67,0,0,160,3,60,37,16,67,0, - 0,32,3,36,236,255,32,174,2,131,1,60, - 220,246,32,172,2,131,1,60,204,246,32,172, - 2,131,1,60,236,246,34,172,0,0,67,164, - 222,21,192,12,33,32,0,2,122,15,192,12, - 33,32,0,2,242,21,192,12,33,32,0,2, - 32,133,130,143,1,0,16,36,42,16,2,2, - 12,0,64,16,255,31,3,60,236,1,49,38, - 133,12,192,12,33,32,0,2,242,21,192,12, - 33,32,32,2,32,133,130,143,1,0,16,38, - 42,16,2,2,248,255,64,20,0,2,49,38, - 255,31,3,60,255,255,99,52,2,131,16,60, - 192,4,16,38,7,0,2,36,0,0,2,174, - 56,0,2,38,36,16,67,0,0,160,3,60, - 37,16,67,0,0,32,3,36,2,131,1,60, - 220,4,32,172,2,131,1,60,204,4,32,172, - 2,131,1,60,236,4,34,172,0,0,67,164, - 2,131,2,60,212,246,66,140,2,131,3,60, - 216,246,99,132,20,0,2,174,24,0,3,166, - 2,131,2,60,217,4,66,144,0,0,0,0, - 7,0,66,36,2,131,1,60,217,4,34,160, - 112,15,192,12,33,32,0,2,33,32,0,2, - 19,15,192,12,32,0,5,36,20,0,16,38, - 33,32,0,2,7,0,5,36,255,127,6,60, - 247,24,192,12,255,255,198,52,33,16,0,0, - 32,0,191,143,28,0,179,143,24,0,178,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 40,0,189,39,200,255,189,39,48,0,180,175, - 33,160,128,0,255,31,6,60,255,255,198,52, - 64,26,20,0,2,131,2,60,192,246,66,36, - 40,0,178,175,33,144,98,0,255,255,132,38, - 64,18,4,0,0,162,3,60,33,16,67,0, - 52,0,191,175,44,0,179,175,36,0,177,175, - 32,0,176,175,4,0,66,174,0,1,66,36, - 8,0,66,174,0,16,2,36,4,16,130,0, - 12,0,66,174,4,0,2,36,4,16,130,0, - 0,160,5,60,16,0,66,174,48,0,66,38, - 36,16,70,0,37,16,69,0,36,0,66,174, - 64,16,4,0,33,16,68,0,128,16,2,0, - 2,131,3,60,240,231,99,36,33,16,67,0, - 36,16,70,0,37,16,69,0,40,0,66,174, - 56,0,66,38,36,16,70,0,37,16,69,0, - 0,0,84,174,44,0,66,174,32,0,64,174, - 2,131,2,60,212,246,66,140,2,131,3,60, - 216,246,99,132,20,0,66,174,24,0,67,166, - 25,0,66,146,0,0,0,0,33,32,84,0, - 2,131,2,60,0,227,66,36,36,16,70,0, - 37,128,69,0,2,131,2,60,32,227,66,36, - 36,16,70,0,25,0,68,162,40,133,131,143, - 0,0,0,0,3,0,96,16,37,136,69,0, - 255,255,130,36,25,0,66,162,12,0,68,142, - 28,0,64,174,228,63,192,12,1,0,132,52, - 4,0,68,142,0,0,0,0,76,67,192,12, - 33,40,0,0,76,63,192,12,0,0,0,0, - 76,63,192,12,0,0,0,0,255,255,2,36, - 4,0,2,174,4,0,2,142,0,0,0,0, - 0,0,2,174,4,0,68,142,0,0,0,0, - 76,67,192,12,1,0,5,54,4,0,4,38, - 33,40,0,0,255,255,6,36,211,67,192,12, - 208,7,7,36,8,0,64,20,255,255,2,52, - 2,131,4,60,184,128,132,36,4,0,6,142, - 0,0,0,0,15,63,192,12,33,40,128,2, - 255,255,2,52,48,1,34,174,4,0,68,142, - 0,0,0,0,76,67,192,12,3,0,37,54, - 48,1,36,38,33,40,0,0,255,255,6,52, - 211,67,192,12,208,7,7,36,7,0,64,20, - 0,0,0,0,2,131,4,60,8,129,132,36, - 48,1,38,142,0,0,0,0,15,63,192,12, - 33,40,128,2,143,63,192,12,0,0,0,0, - 40,0,69,142,4,0,68,142,0,0,0,0, - 76,67,192,12,2,0,165,52,44,0,81,142, - 84,128,131,143,80,128,132,143,100,0,2,36, - 0,0,32,166,2,0,32,166,4,0,32,174, - 8,0,32,174,12,0,32,174,16,0,32,174, - 24,0,32,174,20,0,32,174,28,0,32,174, - 32,0,32,174,36,0,34,166,38,0,34,166, - 36,0,35,166,38,0,36,166,36,0,83,142, - 1,0,2,36,0,0,98,174,44,0,66,142, - 0,0,0,0,4,0,98,174,40,0,67,142, - 116,0,2,60,0,0,98,172,40,0,67,142, - 36,0,66,142,0,0,0,0,8,0,98,172, - 8,0,66,142,0,0,0,0,0,0,64,172, - 0,0,98,142,0,0,0,0,10,0,64,16, - 33,128,0,0,208,7,2,42,7,0,64,16, - 0,0,0,0,143,63,192,12,0,0,0,0, - 0,0,98,142,0,0,0,0,248,255,64,20, - 1,0,16,38,0,0,98,142,0,0,0,0, - 6,0,64,16,33,32,32,2,2,131,4,60, - 76,129,132,36,15,63,192,12,33,40,128,2, - 33,32,32,2,8,0,5,36,0,0,34,150, - 8,0,6,36,0,240,66,48,0,6,66,52, - 2,0,34,166,8,0,66,142,208,7,7,36, - 129,67,192,12,0,0,64,172,6,0,64,20, - 2,0,36,38,2,131,4,60,160,129,132,36, - 15,63,192,12,33,40,128,2,2,0,36,38, - 33,40,0,0,0,0,34,150,33,48,0,0, - 0,240,66,48,2,0,34,166,8,0,66,142, - 208,7,7,36,129,67,192,12,0,0,64,172, - 4,0,64,20,0,0,0,0,2,131,4,60, - 15,63,192,12,248,129,132,36,143,63,192,12, - 0,0,0,0,108,0,80,142,0,128,2,52, - 0,0,0,166,2,0,2,166,44,0,66,142, - 0,32,5,36,4,0,80,172,44,0,67,142, - 0,241,2,52,2,0,98,164,8,0,66,142, - 0,32,6,36,0,0,64,172,44,0,68,142, - 0,0,0,0,129,67,192,12,208,7,7,36, - 12,0,64,20,0,0,0,0,44,0,66,142, - 0,0,0,0,0,0,69,148,2,131,4,60, - 15,63,192,12,16,130,132,36,254,255,4,36, - 2,131,5,60,44,130,165,36,188,7,192,12, - 1,1,6,36,108,0,80,142,2,128,2,52, - 0,0,0,166,2,0,2,166,14,0,2,36, - 8,0,2,162,200,0,2,36,9,0,2,162, - 65,0,2,36,10,0,2,162,46,0,2,36, - 11,0,2,162,87,0,2,36,12,0,0,162, - 13,0,2,162,242,0,2,36,14,0,0,162, - 15,0,2,162,1,0,2,36,16,0,2,162, - 8,0,2,36,17,0,2,162,88,128,130,143, - 0,0,0,0,6,0,64,16,64,0,2,36, - 2,131,4,60,15,63,192,12,56,130,132,36, - 88,128,128,175,64,0,2,36,18,0,2,162, - 255,0,2,36,19,0,2,162,63,0,2,36, - 20,0,0,162,21,0,2,162,44,0,66,142, - 0,32,5,36,4,0,80,172,44,0,67,142, - 0,33,2,36,2,0,98,164,8,0,66,142, - 0,32,6,36,0,0,64,172,44,0,68,142, - 0,0,0,0,129,67,192,12,208,7,7,36, - 12,0,64,20,0,0,0,0,44,0,66,142, - 0,0,0,0,0,0,69,148,2,131,4,60, - 15,63,192,12,16,130,132,36,253,255,4,36, - 2,131,5,60,44,130,165,36,188,7,192,12, - 85,1,6,36,222,21,192,12,33,32,64,2, - 122,15,192,12,33,32,64,2,52,0,191,143, - 48,0,180,143,44,0,179,143,40,0,178,143, - 36,0,177,143,32,0,176,143,8,0,224,3, - 56,0,189,39,248,255,189,39,32,133,133,143, - 0,0,0,0,50,0,160,24,33,32,0,0, - 2,131,3,60,192,246,99,36,44,0,98,140, - 152,0,96,172,156,0,96,172,160,0,96,172, - 164,0,96,172,168,0,96,172,172,0,96,172, - 176,0,96,172,180,0,96,172,184,0,96,172, - 188,0,96,172,192,0,96,172,196,0,96,172, - 200,0,96,172,204,0,96,172,208,0,96,172, - 212,0,96,172,216,0,96,172,224,0,96,172, - 232,0,96,172,236,0,96,172,240,0,96,172, - 244,0,96,172,248,0,96,172,252,0,96,172, - 0,1,96,172,4,1,96,172,8,1,96,172, - 12,0,64,172,44,0,98,140,0,0,0,0, - 16,0,64,172,44,0,98,140,0,0,0,0, - 24,0,64,172,44,0,98,140,0,0,0,0, - 20,0,64,172,44,0,98,140,1,0,132,36, - 28,0,64,172,44,0,98,140,0,2,99,36, - 32,0,64,172,42,16,133,0,210,255,64,20, - 0,0,0,0,33,32,0,0,0,163,3,60, - 0,1,99,52,32,0,5,36,33,16,131,0, - 188,0,69,160,1,0,132,36,0,2,130,44, - 251,255,64,20,0,0,0,0,8,0,224,3, - 8,0,189,39,0,0,0,0,124,133,130,143, - 232,255,189,39,20,0,191,175,17,0,64,20, - 16,0,176,175,208,7,16,36,7,0,0,26, - 0,0,0,0,143,63,192,12,255,255,16,38, - 124,133,130,143,0,0,0,0,249,255,64,16, - 0,0,0,0,6,0,0,22,0,0,0,0, - 2,131,4,60,15,63,192,12,80,130,132,36, - 45,14,192,8,33,16,0,0,220,63,192,12, - 33,32,0,0,33,32,64,0,124,133,144,143, - 128,133,130,143,4,0,3,142,255,255,66,36, - 128,133,130,175,124,133,131,175,220,63,192,12, - 0,0,0,0,33,16,0,2,20,0,191,143, - 16,0,176,143,8,0,224,3,24,0,189,39, - 232,255,189,39,96,133,130,143,33,40,128,0, - 43,16,162,0,6,0,64,20,16,0,191,175, - 100,133,130,143,0,0,0,0,43,16,162,0, - 6,0,64,20,0,0,0,0,2,131,4,60, - 15,63,192,12,116,130,132,36,71,14,192,8, - 0,0,0,0,124,133,131,143,128,133,130,143, - 124,133,133,175,1,0,66,36,4,0,163,172, - 128,133,130,175,16,0,191,143,24,0,189,39, - 8,0,224,3,0,0,0,0,108,133,130,143, - 232,255,189,39,20,0,191,175,17,0,64,20, - 16,0,176,175,208,7,16,36,7,0,0,26, - 0,0,0,0,143,63,192,12,255,255,16,38, - 108,133,130,143,0,0,0,0,249,255,64,16, - 0,0,0,0,6,0,0,22,0,0,0,0, - 2,131,4,60,15,63,192,12,148,130,132,36, - 108,14,192,8,33,16,0,0,220,63,192,12, - 33,32,0,0,33,32,64,0,108,133,144,143, - 120,133,130,143,0,0,3,142,255,255,66,36, - 120,133,130,175,108,133,131,175,220,63,192,12, - 0,0,0,0,33,16,0,2,20,0,191,143, - 16,0,176,143,8,0,224,3,24,0,189,39, - 232,255,189,39,104,133,130,143,33,40,128,0, - 43,16,162,0,6,0,64,20,16,0,191,175, - 112,133,130,143,0,0,0,0,43,16,162,0, - 6,0,64,20,0,0,0,0,2,131,4,60, - 15,63,192,12,184,130,132,36,135,14,192,8, - 0,0,0,0,108,133,130,143,0,0,0,0, - 0,0,162,172,120,133,130,143,108,133,133,175, - 1,0,66,36,120,133,130,175,16,0,191,143, - 24,0,189,39,8,0,224,3,0,0,0,0, - 232,255,189,39,20,0,191,175,16,0,176,175, - 124,133,128,175,13,8,192,12,0,32,4,36, - 255,31,3,60,255,255,99,52,255,1,16,36, - 36,16,67,0,0,160,3,60,37,16,67,0, - 96,133,130,175,0,32,66,36,100,133,130,175, - 0,17,16,0,96,133,132,143,255,255,16,38, - 49,14,192,12,33,32,130,0,251,255,1,6, - 0,17,16,0,0,2,2,36,132,133,130,175, - 108,133,128,175,13,8,192,12,18,0,4,60, - 255,31,3,60,255,255,99,52,255,17,16,36, - 36,16,67,0,0,160,3,60,37,16,67,0, - 18,0,3,60,104,133,130,175,33,16,67,0, - 112,133,130,175,0,18,16,0,104,133,132,143, - 255,255,16,38,112,14,192,12,33,32,130,0, - 251,255,1,6,0,18,16,0,0,18,2,36, - 116,133,130,175,20,0,191,143,16,0,176,143, - 8,0,224,3,24,0,189,39,0,0,0,0, - 0,0,0,0,0,0,0,0,0,163,2,60, - 168,1,66,140,216,255,189,39,28,0,177,175, - 33,136,128,0,32,0,178,175,33,144,160,0, - 36,0,191,175,17,0,64,16,24,0,176,175, - 0,163,2,60,168,1,66,140,0,0,0,0, - 42,16,82,0,12,0,64,16,128,128,18,0, - 0,0,34,142,0,163,18,60,168,1,82,142, - 0,0,0,0,6,0,64,20,128,128,18,0, - 2,131,4,60,224,130,132,36,15,63,192,12, - 33,40,64,2,128,128,18,0,33,128,18,2, - 128,128,16,0,13,8,192,12,33,32,0,2, - 255,31,3,60,255,255,99,52,33,32,0,0, - 36,16,67,0,0,160,3,60,37,16,67,0, - 112,0,34,174,112,0,35,142,33,16,80,0, - 15,0,64,26,116,0,34,174,8,0,5,36, - 1,0,132,36,20,0,98,36,4,0,98,172, - 2,0,101,164,0,0,96,164,8,0,96,172, - 14,0,96,164,12,0,96,164,33,24,64,0, - 42,16,146,0,246,255,64,20,1,0,132,36, - 255,255,132,36,116,0,35,142,112,0,34,142, - 0,0,0,0,240,255,98,172,116,0,35,142, - 0,0,0,0,218,255,98,148,0,0,0,0, - 0,128,66,52,218,255,98,164,116,0,35,142, - 0,0,0,0,238,255,98,148,0,0,0,0, - 0,128,66,52,238,255,98,164,116,0,34,142, - 112,0,35,142,216,255,66,36,120,0,35,174, - 124,0,34,174,36,0,191,143,32,0,178,143, - 28,0,177,143,24,0,176,143,8,0,224,3, - 40,0,189,39,200,255,189,39,32,0,178,175, - 33,144,128,0,0,1,2,36,48,0,191,175, - 44,0,181,175,40,0,180,175,36,0,179,175, - 28,0,177,175,24,0,176,175,144,0,66,174, - 0,163,2,60,172,1,66,140,0,0,0,0, - 17,0,64,16,33,160,160,0,0,163,2,60, - 172,1,66,140,0,0,0,0,42,16,84,0, - 12,0,64,16,128,128,20,0,0,0,66,142, - 0,163,20,60,172,1,148,142,0,0,0,0, - 6,0,64,20,128,128,20,0,2,131,4,60, - 236,130,132,36,15,63,192,12,33,40,128,2, - 128,128,20,0,33,128,20,2,128,128,16,0, - 33,32,0,2,13,8,192,12,148,0,84,174, - 255,31,3,60,255,255,99,52,33,152,0,0, - 36,16,67,0,0,160,3,60,37,16,67,0, - 128,0,66,174,128,0,81,142,33,16,80,0, - 15,0,128,26,132,0,66,174,0,1,21,36, - 20,0,48,38,4,0,48,174,75,14,192,12, - 0,0,32,174,8,0,34,174,12,0,53,174, - 0,0,66,142,1,0,115,38,16,0,34,162, - 17,0,32,162,42,16,116,2,244,255,64,20, - 33,136,0,2,132,0,67,142,128,0,66,142, - 0,0,0,0,240,255,98,172,132,0,67,142, - 0,0,0,0,228,255,98,140,0,0,0,0, - 0,128,66,52,228,255,98,172,132,0,67,142, - 0,0,0,0,248,255,98,140,0,0,0,0, - 0,128,66,52,248,255,98,172,132,0,66,142, - 128,0,67,142,216,255,66,36,136,0,67,174, - 140,0,66,174,48,0,191,143,44,0,181,143, - 40,0,180,143,36,0,179,143,32,0,178,143, - 28,0,177,143,24,0,176,143,8,0,224,3, - 56,0,189,39,152,0,128,172,156,0,128,172, - 160,0,128,172,164,0,128,172,168,0,128,172, - 252,0,128,172,0,1,128,172,152,0,128,172, - 8,0,224,3,216,0,128,172,232,255,189,39, - 16,0,176,175,20,0,191,175,112,15,192,12, - 33,128,128,0,33,32,0,2,192,14,192,12, - 0,4,5,36,33,32,0,2,19,15,192,12, - 128,2,5,36,120,0,3,142,136,0,2,142, - 0,0,0,0,8,0,98,172,44,0,3,142, - 120,0,2,142,0,0,0,0,8,0,98,172, - 0,0,2,142,0,0,0,0,255,255,66,36, - 6,0,66,44,7,0,64,16,16,0,3,36, - 44,0,2,142,0,0,0,0,2,0,67,164, - 8,0,2,142,0,0,0,0,0,0,64,172, - 20,0,191,143,16,0,176,143,8,0,224,3, - 24,0,189,39,184,255,189,39,0,32,6,36, - 68,0,191,175,64,0,190,175,60,0,183,175, - 56,0,182,175,52,0,181,175,48,0,180,175, - 44,0,179,175,40,0,178,175,36,0,177,175, - 32,0,176,175,0,163,1,60,252,5,38,172, - 13,8,192,12,0,32,4,36,255,31,4,60, - 255,255,132,52,33,168,0,0,255,31,6,60, - 255,255,198,52,2,131,3,60,212,247,99,36, - 16,0,101,36,8,0,126,36,248,255,119,36, - 33,176,96,0,36,16,68,0,0,160,3,60, - 37,16,67,0,16,0,166,175,0,163,1,60, - 248,5,34,172,0,163,1,60,0,6,32,172, - 33,160,0,0,33,128,224,2,33,152,160,0, - 33,144,192,3,33,136,192,2,32,133,130,143, - 0,0,32,174,0,0,0,174,0,0,64,174, - 42,16,162,2,10,0,64,16,0,0,96,174, - 0,32,4,36,13,8,192,12,24,0,165,175, - 16,0,166,143,0,128,3,60,36,16,70,0, - 37,16,67,0,0,0,2,174,24,0,165,143, - 4,0,16,38,4,0,115,38,4,0,82,38, - 1,0,148,38,2,0,130,42,234,255,64,20, - 4,0,49,38,0,2,165,36,0,2,222,39, - 0,2,247,38,1,0,181,38,7,0,162,42, - 222,255,64,20,0,2,214,38,68,0,191,143, - 64,0,190,143,60,0,183,143,56,0,182,143, - 52,0,181,143,48,0,180,143,44,0,179,143, - 40,0,178,143,36,0,177,143,32,0,176,143, - 8,0,224,3,72,0,189,39,0,163,4,60, - 0,6,132,140,0,163,3,60,8,6,99,140, - 32,133,130,143,224,255,189,39,16,0,176,175, - 0,163,16,60,12,6,16,142,20,0,177,175, - 0,163,17,60,4,6,49,142,43,16,98,0, - 42,0,64,16,24,0,191,175,2,0,2,46, - 40,0,64,16,255,255,2,36,0,163,2,60, - 252,5,66,140,0,0,0,0,43,16,81,0, - 34,0,64,20,255,255,2,36,64,18,3,0, - 2,131,3,60,192,246,99,36,33,24,67,0, - 1,0,2,36,5,0,130,16,2,0,2,36, - 18,0,130,16,128,16,16,0,36,16,192,8, - 0,0,0,0,128,128,16,0,33,128,3,2, - 12,1,4,142,0,163,5,60,248,5,165,140, - 33,48,32,2,80,68,192,12,36,1,17,174, - 12,1,4,142,12,1,2,142,33,40,32,2, - 114,68,192,12,20,1,2,174,36,16,192,8, - 0,0,0,0,33,16,67,0,20,1,64,172, - 36,1,64,172,0,163,1,60,42,16,192,8, - 0,6,32,172,255,255,2,36,0,163,1,60, - 0,6,34,172,24,0,191,143,20,0,177,143, - 16,0,176,143,8,0,224,3,32,0,189,39, - 176,133,136,143,188,133,137,143,232,255,189,39, - 3,0,0,21,16,0,191,175,124,0,32,17, - 0,0,0,0,12,0,194,148,0,0,0,0, - 0,26,2,0,2,18,2,0,37,56,98,0, - 255,255,227,48,221,5,98,44,36,0,64,20, - 170,170,2,52,0,8,2,36,23,0,98,20, - 6,8,2,36,21,0,0,17,0,0,0,0, - 32,0,194,148,30,0,195,148,0,20,2,0, - 37,56,67,0,36,0,195,148,0,161,2,52, - 5,0,98,16,8,0,2,36,34,0,195,148, - 0,0,0,0,98,0,98,20,0,0,0,0, - 3,0,232,16,255,255,2,36,94,0,226,20, - 0,0,0,0,226,46,192,12,14,0,6,36, - 177,16,192,8,0,0,0,0,7,0,98,20, - 255,255,227,48,71,0,0,17,55,129,2,52, - 108,43,192,12,14,0,6,36,177,16,192,8, - 0,0,0,0,162,16,192,8,55,129,2,52, - 14,0,195,148,0,0,0,0,61,0,98,20, - 255,255,2,52,16,0,195,144,3,0,2,36, - 55,0,98,20,255,255,2,52,20,0,194,148, - 0,0,0,0,0,26,2,0,2,18,2,0, - 37,56,98,0,255,255,227,48,0,8,2,36, - 23,0,98,20,6,8,2,36,21,0,0,17, - 0,0,0,0,40,0,194,148,38,0,195,148, - 0,20,2,0,37,56,67,0,44,0,195,148, - 0,161,2,52,5,0,98,16,8,0,2,36, - 42,0,195,148,0,0,0,0,49,0,98,20, - 0,0,0,0,3,0,232,16,255,255,2,36, - 45,0,226,20,0,0,0,0,226,46,192,12, - 22,0,6,36,177,16,192,8,0,0,0,0, - 7,0,98,20,255,255,227,48,6,0,0,17, - 55,129,2,52,108,43,192,12,22,0,6,36, - 177,16,192,8,0,0,0,0,55,129,2,52, - 30,0,98,20,0,0,0,0,28,0,32,17, - 144,15,3,36,38,0,194,148,28,0,198,140, - 24,0,67,20,0,0,0,0,3,0,201,16, - 0,0,0,0,20,0,192,20,0,0,0,0, - 175,16,192,8,22,0,6,36,14,0,195,148, - 0,0,0,0,14,0,98,20,0,0,0,0, - 12,0,32,17,144,15,3,36,30,0,194,148, - 20,0,198,140,8,0,67,20,0,0,0,0, - 3,0,201,16,0,0,0,0,4,0,192,20, - 0,0,0,0,14,0,6,36,126,49,192,12, - 0,0,0,0,16,0,191,143,24,0,189,39, - 8,0,224,3,0,0,0,0,128,255,189,39, - 116,0,183,175,33,184,128,0,3,0,3,36, - 124,0,191,175,120,0,190,175,112,0,182,175, - 108,0,181,175,104,0,180,175,100,0,179,175, - 96,0,178,175,92,0,177,175,88,0,176,175, - 0,0,245,142,8,0,178,140,192,17,21,0, - 3,131,4,60,33,32,130,0,20,13,132,140, - 8,0,84,142,0,0,0,0,59,0,131,16, - 5,0,130,44,57,0,64,16,128,16,4,0, - 2,131,1,60,33,8,34,0,104,131,34,140, - 0,0,0,0,8,0,64,0,0,0,0,0, - 44,133,130,143,0,0,0,0,48,0,64,16, - 6,0,132,38,4,0,131,150,2,131,2,60, - 68,207,66,148,0,0,0,0,6,0,98,20, - 33,32,0,0,0,0,130,142,48,129,131,143, - 0,0,0,0,38,16,67,0,1,0,68,44, - 72,1,128,16,33,32,160,2,114,42,192,12, - 33,40,128,2,45,18,192,8,33,32,64,2, - 44,133,130,143,0,0,0,0,27,0,64,16, - 6,0,132,38,4,0,131,150,2,131,2,60, - 68,207,66,148,0,0,0,0,6,0,98,20, - 33,32,0,0,0,0,130,142,48,129,131,143, - 0,0,0,0,38,16,67,0,1,0,68,44, - 5,0,128,16,33,32,160,2,114,42,192,12, - 33,40,128,2,45,18,192,8,33,32,64,2, - 6,0,132,38,0,163,6,60,140,1,198,140, - 0,0,0,0,247,24,192,12,33,40,160,2, - 45,18,192,8,33,32,64,2,6,0,132,38, - 0,163,6,60,140,1,198,140,0,0,0,0, - 247,24,192,12,33,40,160,2,203,24,192,12, - 33,32,128,2,20,1,227,142,0,0,0,0, - 14,0,96,16,33,240,64,0,33,32,128,2, - 16,0,166,39,18,0,69,150,0,0,0,0, - 9,248,96,0,33,56,192,3,6,0,64,16, - 33,32,64,2,28,1,226,142,0,0,0,0, - 1,0,66,36,45,18,192,8,28,1,226,174, - 132,0,193,7,7,0,2,36,4,0,131,150, - 2,131,2,60,68,207,66,148,0,0,0,0, - 6,0,98,20,33,32,0,0,0,0,130,142, - 48,129,131,143,0,0,0,0,38,16,67,0, - 1,0,68,44,9,0,128,16,255,255,2,36, - 44,133,130,143,0,0,0,0,251,0,64,16, - 33,32,160,2,114,42,192,12,33,40,128,2, - 45,18,192,8,33,32,64,2,10,0,194,23, - 0,0,0,0,8,0,160,18,0,0,0,0, - 36,133,130,143,0,0,0,0,8,0,64,16, - 1,0,19,36,80,133,147,143,69,17,192,8, - 0,0,0,0,0,1,226,142,80,133,147,143, - 1,0,66,36,0,1,226,174,84,133,130,143, - 0,0,0,0,35,16,83,0,255,255,66,36, - 17,0,66,162,84,133,130,143,33,128,96,2, - 42,16,2,2,15,0,64,16,64,18,16,0, - 2,131,3,60,192,246,99,36,33,136,67,0, - 5,0,21,18,0,0,0,0,247,22,192,12, - 33,32,32,2,217,0,64,16,33,16,0,0, - 84,133,130,143,1,0,16,38,42,16,2,2, - 246,255,64,20,0,2,49,38,84,133,130,143, - 33,128,96,2,42,16,2,2,55,0,64,16, - 64,18,16,0,2,131,3,60,192,246,99,36, - 33,152,67,0,33,136,64,0,192,177,16,0, - 41,0,21,18,0,0,0,0,2,131,2,60, - 33,16,81,0,216,247,66,140,0,0,0,0, - 15,0,64,16,33,32,128,2,16,0,166,39, - 18,0,69,150,0,0,0,0,9,248,64,0, - 33,56,160,2,8,0,64,16,0,0,0,0, - 2,131,2,60,33,16,81,0,224,247,66,140, - 0,0,0,0,1,0,66,36,140,17,192,8, - 32,1,98,174,44,133,130,143,0,0,0,0, - 7,0,64,16,3,0,8,36,3,131,2,60, - 33,16,86,0,20,13,66,140,0,0,0,0, - 6,0,72,20,0,0,0,0,33,32,96,2, - 6,23,192,12,33,40,64,2,146,17,192,8, - 0,2,115,38,17,0,66,146,0,0,0,0, - 255,255,66,36,17,0,66,162,17,0,66,146, - 0,2,115,38,0,2,49,38,84,133,130,143, - 1,0,16,38,42,16,2,2,208,255,64,20, - 128,0,214,38,254,255,2,36,4,0,194,23, - 33,32,224,2,33,40,64,2,47,16,192,12, - 33,48,128,2,17,0,66,146,0,0,0,0, - 140,0,64,16,33,32,64,2,36,18,192,8, - 0,0,0,0,26,0,194,23,0,0,0,0, - 36,133,130,143,0,0,0,0,11,0,64,16, - 33,32,224,2,9,0,160,18,1,0,2,36, - 17,0,66,162,2,131,4,60,192,246,132,36, - 6,23,192,12,33,40,64,2,126,0,64,16, - 33,16,0,0,33,32,224,2,33,40,64,2, - 47,16,192,12,33,48,128,2,36,133,130,143, - 0,0,0,0,115,0,64,16,33,32,64,2, - 116,0,160,22,1,0,2,36,45,18,192,8, - 0,0,0,0,87,0,213,19,64,130,30,0, - 2,131,2,60,33,16,80,0,216,247,66,140, - 0,0,0,0,18,0,64,16,33,32,128,2, - 16,0,166,39,18,0,69,150,0,0,0,0, - 9,248,64,0,33,56,160,2,11,0,64,16, - 33,32,64,2,2,131,2,60,33,16,80,0, - 224,247,66,140,0,0,0,0,1,0,66,36, - 2,131,1,60,33,8,48,0,224,247,34,172, - 45,18,192,8,17,0,128,160,36,133,130,143, - 0,0,0,0,43,0,64,16,0,0,0,0, - 41,0,192,19,0,0,0,0,39,0,160,18, - 64,18,30,0,2,131,16,60,192,246,16,38, - 33,136,80,0,247,22,192,12,33,32,32,2, - 74,0,64,16,33,16,0,0,247,22,192,12, - 33,32,0,2,63,0,64,16,2,0,2,36, - 17,0,66,162,44,133,130,143,0,0,0,0, - 7,0,64,16,192,17,30,0,3,131,3,60, - 33,24,98,0,20,13,99,140,3,0,2,36, - 6,0,98,20,0,0,0,0,33,32,32,2, - 6,23,192,12,33,40,64,2,0,18,192,8, - 0,0,0,0,17,0,66,146,0,0,0,0, - 255,255,66,36,17,0,66,162,17,0,66,146, - 2,131,4,60,192,246,132,36,6,23,192,12, - 33,40,64,2,36,18,192,8,0,0,0,0, - 44,133,130,143,0,0,0,0,7,0,64,16, - 192,17,30,0,3,131,3,60,33,24,98,0, - 20,13,99,140,3,0,2,36,28,0,98,20, - 0,0,0,0,1,0,2,36,17,0,66,162, - 64,18,30,0,2,131,4,60,192,246,132,36, - 32,18,192,8,33,32,68,0,36,133,130,143, - 0,0,0,0,17,0,64,16,0,0,0,0, - 15,0,192,19,1,0,2,36,17,0,66,162, - 2,131,4,60,192,246,132,36,6,23,192,12, - 33,40,64,2,13,0,64,16,33,16,0,0, - 252,0,226,142,0,0,0,0,1,0,66,36, - 47,18,192,8,252,0,226,174,48,18,192,8, - 33,16,0,0,17,0,64,162,33,32,64,2, - 152,21,192,12,0,0,0,0,1,0,2,36, - 124,0,191,143,120,0,190,143,116,0,183,143, - 112,0,182,143,108,0,181,143,104,0,180,143, - 100,0,179,143,96,0,178,143,92,0,177,143, - 88,0,176,143,8,0,224,3,128,0,189,39, - 216,255,189,39,24,0,178,175,33,144,128,0, - 32,0,191,175,28,0,179,175,20,0,177,175, - 16,0,176,175,8,0,177,140,0,0,66,142, - 8,0,38,142,36,0,64,16,0,0,0,0, - 28,0,66,142,0,0,0,0,18,0,64,20, - 1,0,2,36,0,0,194,144,0,0,0,0, - 1,0,66,48,13,0,64,20,1,0,2,36, - 4,0,195,148,24,0,66,150,0,0,0,0, - 6,0,98,20,33,32,0,0,0,0,194,140, - 20,0,67,142,0,0,0,0,38,16,67,0, - 1,0,68,44,10,0,128,16,1,0,2,36, - 17,0,34,162,2,131,4,60,192,246,132,36, - 6,23,192,12,33,40,32,2,45,0,64,16, - 33,16,0,0,139,18,192,8,0,0,0,0, - 17,0,32,162,152,21,192,12,33,32,32,2, - 144,18,192,8,1,0,2,36,16,0,179,140, - 0,0,0,0,6,0,96,26,0,0,0,0, - 32,133,130,143,0,0,0,0,42,16,98,2, - 15,0,64,20,1,0,2,36,2,131,4,60, - 248,130,132,36,2,131,16,60,24,131,16,38, - 33,40,0,2,2,131,7,60,36,131,231,36, - 15,63,192,12,188,2,6,36,1,0,4,36, - 33,40,0,2,188,7,192,12,188,2,6,36, - 1,0,2,36,17,0,34,162,64,18,19,0, - 2,131,4,60,192,246,132,36,33,32,68,0, - 6,23,192,12,33,40,32,2,6,0,64,16, - 33,16,0,0,252,0,66,142,0,0,0,0, - 1,0,66,36,252,0,66,174,1,0,2,36, - 32,0,191,143,28,0,179,143,24,0,178,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 40,0,189,39,72,255,189,39,164,0,181,175, - 33,168,128,0,180,0,191,175,176,0,190,175, - 172,0,183,175,168,0,182,175,160,0,180,175, - 156,0,179,175,152,0,178,175,148,0,177,175, - 144,0,176,175,88,0,165,175,120,0,160,175, - 120,0,168,142,0,0,0,0,96,0,168,175, - 124,0,169,142,0,0,0,0,15,2,160,24, - 104,0,169,175,96,0,168,143,0,0,0,0, - 0,0,4,149,0,0,0,0,0,128,130,48, - 9,2,64,16,0,0,0,0,128,0,160,175, - 8,0,2,141,136,0,169,142,255,255,8,36, - 18,0,72,16,112,0,169,175,112,0,169,143, - 0,0,0,0,0,0,35,141,4,0,40,141, - 128,0,169,143,255,63,98,48,33,72,34,1, - 0,128,99,48,112,0,168,175,246,255,96,16, - 128,0,169,175,96,0,168,143,0,0,0,0, - 8,0,2,141,128,0,169,151,0,0,0,0, - 18,0,73,164,0,32,130,48,200,1,64,16, - 0,0,0,0,40,133,130,143,0,0,0,0, - 75,0,64,16,3,0,8,36,96,0,168,143, - 0,0,0,0,8,0,16,141,0,0,162,142, - 8,0,5,142,30,0,64,16,0,0,0,0, - 28,0,162,142,0,0,0,0,18,0,64,20, - 1,0,9,36,0,0,162,144,0,0,0,0, - 1,0,66,48,13,0,64,20,0,0,0,0, - 4,0,163,148,24,0,162,150,0,0,0,0, - 6,0,98,20,33,32,0,0,0,0,162,140, - 20,0,163,142,0,0,0,0,38,16,67,0, - 1,0,68,44,6,0,128,16,1,0,9,36, - 17,0,9,162,2,131,4,60,192,246,132,36, - 18,19,192,8,33,40,0,2,17,0,0,162, - 130,20,192,8,33,32,0,2,16,0,17,141, - 0,0,0,0,6,0,32,26,0,0,0,0, - 32,133,130,143,0,0,0,0,42,16,34,2, - 15,0,64,20,1,0,9,36,2,131,4,60, - 248,130,132,36,2,131,5,60,24,131,165,36, - 2,131,7,60,36,131,231,36,15,63,192,12, - 188,2,6,36,1,0,4,36,2,131,5,60, - 24,131,165,36,188,7,192,12,188,2,6,36, - 1,0,9,36,17,0,9,162,64,34,17,0, - 2,131,8,60,192,246,8,37,33,32,136,0, - 33,40,0,2,6,23,192,12,0,0,0,0, - 112,1,64,16,33,16,0,0,252,0,162,142, - 0,0,0,0,1,0,66,36,132,20,192,8, - 252,0,162,174,0,0,182,142,96,0,169,143, - 192,17,22,0,8,0,50,141,3,131,3,60, - 33,24,98,0,20,13,99,140,8,0,84,142, - 0,0,0,0,59,0,104,16,5,0,98,44, - 57,0,64,16,128,16,3,0,2,131,1,60, - 33,8,34,0,128,131,34,140,0,0,0,0, - 8,0,64,0,0,0,0,0,44,133,130,143, - 0,0,0,0,48,0,64,16,6,0,132,38, - 4,0,131,150,2,131,2,60,68,207,66,148, - 0,0,0,0,6,0,98,20,33,32,0,0, - 0,0,130,142,48,129,131,143,0,0,0,0, - 38,16,67,0,1,0,68,44,67,1,128,16, - 33,32,192,2,114,42,192,12,33,40,128,2, - 130,20,192,8,33,32,64,2,44,133,130,143, - 0,0,0,0,27,0,64,16,6,0,132,38, - 4,0,131,150,2,131,2,60,68,207,66,148, - 0,0,0,0,6,0,98,20,33,32,0,0, - 0,0,130,142,48,129,131,143,0,0,0,0, - 38,16,67,0,1,0,68,44,5,0,128,16, - 33,32,192,2,114,42,192,12,33,40,128,2, - 130,20,192,8,33,32,64,2,6,0,132,38, - 0,163,6,60,140,1,198,140,0,0,0,0, - 247,24,192,12,33,40,192,2,130,20,192,8, - 33,32,64,2,6,0,132,38,0,163,6,60, - 140,1,198,140,0,0,0,0,247,24,192,12, - 33,40,192,2,203,24,192,12,33,32,128,2, - 20,1,163,142,0,0,0,0,14,0,96,16, - 33,240,64,0,33,32,128,2,16,0,166,39, - 18,0,69,150,0,0,0,0,9,248,96,0, - 33,56,192,3,6,0,64,16,33,32,64,2, - 28,1,162,142,0,0,0,0,1,0,66,36, - 130,20,192,8,28,1,162,174,132,0,193,7, - 7,0,2,36,4,0,131,150,2,131,2,60, - 68,207,66,148,0,0,0,0,6,0,98,20, - 33,32,0,0,0,0,130,142,48,129,131,143, - 0,0,0,0,38,16,67,0,1,0,68,44, - 9,0,128,16,255,255,9,36,44,133,130,143, - 0,0,0,0,246,0,64,16,33,32,192,2, - 114,42,192,12,33,40,128,2,130,20,192,8, - 33,32,64,2,10,0,201,23,0,0,0,0, - 8,0,192,18,0,0,0,0,36,133,130,143, - 0,0,0,0,8,0,64,16,1,0,19,36, - 80,133,147,143,159,19,192,8,0,0,0,0, - 0,1,162,142,80,133,147,143,1,0,66,36, - 0,1,162,174,84,133,130,143,0,0,0,0, - 35,16,83,0,255,255,66,36,17,0,66,162, - 84,133,130,143,33,136,96,2,42,16,34,2, - 15,0,64,16,64,18,17,0,2,131,8,60, - 192,246,8,37,33,128,72,0,5,0,54,18, - 0,0,0,0,247,22,192,12,33,32,0,2, - 212,0,64,16,33,16,0,0,84,133,130,143, - 1,0,49,38,42,16,34,2,246,255,64,20, - 0,2,16,38,84,133,130,143,33,136,96,2, - 42,16,34,2,55,0,64,16,64,18,17,0, - 2,131,9,60,192,246,41,37,33,152,73,0, - 33,128,64,0,192,185,17,0,41,0,54,18, - 0,0,0,0,2,131,2,60,33,16,80,0, - 216,247,66,140,0,0,0,0,15,0,64,16, - 33,32,128,2,16,0,166,39,18,0,69,150, - 0,0,0,0,9,248,64,0,33,56,192,2, - 8,0,64,16,0,0,0,0,2,131,2,60, - 33,16,80,0,224,247,66,140,0,0,0,0, - 1,0,66,36,230,19,192,8,32,1,98,174, - 44,133,130,143,0,0,0,0,7,0,64,16, - 3,0,8,36,3,131,2,60,33,16,87,0, - 20,13,66,140,0,0,0,0,6,0,72,20, - 0,0,0,0,33,32,96,2,6,23,192,12, - 33,40,64,2,236,19,192,8,0,2,115,38, - 17,0,66,146,0,0,0,0,255,255,66,36, - 17,0,66,162,17,0,66,146,0,2,115,38, - 0,2,16,38,84,133,130,143,1,0,49,38, - 42,16,34,2,208,255,64,20,128,0,247,38, - 254,255,2,36,4,0,194,23,33,32,160,2, - 33,40,64,2,47,16,192,12,33,48,128,2, - 17,0,66,146,0,0,0,0,135,0,64,16, - 33,32,64,2,22,19,192,8,0,0,0,0, - 26,0,194,23,0,0,0,0,36,133,130,143, - 0,0,0,0,11,0,64,16,33,32,160,2, - 9,0,192,18,1,0,9,36,17,0,73,162, - 2,131,4,60,192,246,132,36,6,23,192,12, - 33,40,64,2,121,0,64,16,33,16,0,0, - 33,32,160,2,33,40,64,2,47,16,192,12, - 33,48,128,2,36,133,130,143,0,0,0,0, - 110,0,64,16,33,32,64,2,111,0,192,22, - 1,0,2,36,130,20,192,8,0,0,0,0, - 89,0,214,19,64,130,30,0,2,131,2,60, - 33,16,80,0,216,247,66,140,0,0,0,0, - 18,0,64,16,33,32,128,2,16,0,166,39, - 18,0,69,150,0,0,0,0,9,248,64,0, - 33,56,192,2,11,0,64,16,33,32,64,2, - 2,131,8,60,192,246,8,37,2,131,2,60, - 33,16,80,0,224,247,66,140,33,24,8,2, - 1,0,66,36,32,1,98,172,130,20,192,8, - 17,0,128,160,36,133,130,143,0,0,0,0, - 44,0,64,16,0,0,0,0,42,0,192,19, - 0,0,0,0,40,0,192,18,64,18,30,0, - 2,131,9,60,192,246,41,37,33,128,73,0, - 247,22,192,12,33,32,0,2,69,0,64,16, - 33,16,0,0,2,131,4,60,247,22,192,12, - 192,246,132,36,57,0,64,16,2,0,2,36, - 17,0,66,162,44,133,130,143,0,0,0,0, - 7,0,64,16,192,17,30,0,3,131,1,60, - 33,8,34,0,20,13,34,140,3,0,8,36, - 6,0,72,20,0,0,0,0,33,32,0,2, - 6,23,192,12,33,40,64,2,91,20,192,8, - 0,0,0,0,17,0,66,146,0,0,0,0, - 255,255,66,36,17,0,66,162,17,0,66,146, - 2,131,4,60,192,246,132,36,6,23,192,12, - 33,40,64,2,22,19,192,8,0,0,0,0, - 44,133,130,143,0,0,0,0,7,0,64,16, - 192,17,30,0,3,131,1,60,33,8,34,0, - 20,13,34,140,3,0,9,36,22,0,73,20, - 0,0,0,0,1,0,8,36,17,0,72,162, - 64,34,30,0,2,131,9,60,192,246,41,37, - 33,32,137,0,18,19,192,8,33,40,64,2, - 36,133,130,143,0,0,0,0,10,0,64,16, - 0,0,0,0,8,0,192,19,1,0,8,36, - 17,0,72,162,2,131,4,60,192,246,132,36, - 18,19,192,8,33,40,64,2,133,20,192,8, - 33,16,0,0,17,0,64,162,33,32,64,2, - 152,21,192,12,0,0,0,0,1,0,2,36, - 52,0,64,16,0,0,0,0,152,0,162,142, - 0,0,0,0,1,0,66,36,152,0,162,174, - 156,0,162,142,168,0,163,142,1,0,66,36, - 156,0,162,174,128,0,169,143,0,0,0,0, - 33,24,105,0,163,20,192,8,168,0,163,174, - 152,0,162,142,160,0,163,142,1,0,66,36, - 1,0,99,36,152,0,162,174,160,0,163,174, - 96,0,168,143,0,0,0,0,8,0,2,141, - 255,255,9,36,4,0,73,16,0,0,0,0, - 8,0,4,141,152,21,192,12,0,0,0,0, - 120,0,168,143,112,0,169,143,1,0,8,37, - 120,0,168,175,136,0,169,174,96,0,168,143, - 8,128,2,52,0,0,0,165,2,0,2,165, - 104,0,169,143,8,0,2,36,2,0,34,165, - 4,0,40,141,96,0,169,143,104,0,168,175, - 4,0,41,141,120,0,168,143,96,0,169,175, - 88,0,169,143,0,0,0,0,42,16,9,1, - 243,253,64,20,0,0,0,0,96,0,168,143, - 44,0,163,142,120,0,168,174,104,0,169,143, - 0,0,0,0,124,0,169,174,0,0,98,148, - 0,0,0,0,0,16,66,48,43,0,64,16, - 0,0,0,0,2,0,98,148,0,0,0,0, - 39,0,64,20,0,0,0,0,0,0,2,149, - 0,0,0,0,35,0,64,20,0,0,0,0, - 2,0,2,149,8,0,3,36,255,255,66,48, - 30,0,67,20,0,0,0,0,136,0,162,142, - 0,0,0,0,12,0,66,140,0,0,0,0, - 0,128,66,48,23,0,64,20,0,0,0,0, - 164,0,162,142,44,0,163,142,1,0,66,36, - 164,0,162,174,8,0,104,172,136,0,162,142, - 0,0,0,0,8,0,2,173,44,0,163,142, - 16,16,2,36,2,0,98,164,0,0,162,142, - 0,0,0,0,5,0,64,20,0,0,0,0, - 164,7,192,12,0,0,0,0,239,20,192,8, - 0,0,0,0,8,0,162,142,0,0,0,0, - 0,0,64,172,180,0,191,143,176,0,190,143, - 172,0,183,143,168,0,182,143,164,0,181,143, - 160,0,180,143,156,0,179,143,152,0,178,143, - 148,0,177,143,144,0,176,143,8,0,224,3, - 184,0,189,39,216,255,189,39,28,0,177,175, - 33,136,128,0,32,0,178,175,33,144,160,0, - 96,128,132,39,6,0,37,38,24,0,176,175, - 104,128,144,39,36,0,191,175,31,21,192,12, - 33,48,0,2,108,128,132,39,33,40,32,2, - 31,21,192,12,33,48,0,2,10,0,64,26, - 33,128,0,0,116,128,132,39,33,16,17,2, - 12,0,69,144,0,0,0,0,15,63,192,12, - 1,0,16,38,42,16,18,2,248,255,64,20, - 0,0,0,0,124,128,132,39,15,63,192,12, - 0,0,0,0,36,0,191,143,32,0,178,143, - 28,0,177,143,24,0,176,143,8,0,224,3, - 40,0,189,39,208,255,189,39,40,0,191,175, - 2,0,162,144,0,0,163,144,1,0,167,144, - 16,0,162,175,3,0,162,144,33,64,128,0, - 20,0,162,175,4,0,162,144,2,131,4,60, - 68,131,132,36,24,0,162,175,5,0,162,144, - 33,40,0,1,32,0,166,175,33,48,96,0, - 15,63,192,12,28,0,162,175,40,0,191,143, - 48,0,189,39,8,0,224,3,0,0,0,0, - 248,255,189,39,136,0,135,140,255,255,163,36, - 12,0,160,16,33,48,224,0,255,255,5,36, - 12,0,194,140,0,0,0,0,0,128,66,48, - 8,0,64,20,33,16,0,0,255,255,99,36, - 0,0,192,172,4,0,198,140,247,255,101,20, - 0,0,0,0,136,0,134,172,33,16,224,0, - 8,0,224,3,8,0,189,39,224,255,189,39, - 16,0,176,175,33,128,160,0,28,0,191,175, - 24,0,178,175,33,0,128,20,20,0,177,175, - 84,133,130,143,80,133,131,143,0,0,0,0, - 35,16,67,0,17,0,2,162,80,133,145,143, - 84,133,130,143,0,0,0,0,42,16,34,2, - 19,0,64,16,64,18,17,0,2,131,3,60, - 192,246,99,36,33,144,67,0,33,32,64,2, - 6,23,192,12,33,40,0,2,6,0,64,20, - 0,0,0,0,17,0,2,146,0,0,0,0, - 255,255,66,36,17,0,2,162,17,0,2,146, - 84,133,130,143,1,0,49,38,42,16,34,2, - 242,255,64,20,0,2,82,38,17,0,2,146, - 144,21,192,8,0,0,0,0,36,133,130,143, - 0,0,0,0,25,0,64,16,1,0,2,36, - 0,0,130,140,0,0,0,0,20,0,64,16, - 2,0,2,36,17,0,2,162,6,23,192,12, - 33,40,0,2,19,0,64,16,33,16,0,0, - 2,131,4,60,192,246,132,36,6,23,192,12, - 33,40,0,2,7,0,64,20,0,0,0,0, - 17,0,2,146,0,0,0,0,255,255,66,36, - 17,0,2,162,17,0,2,146,0,0,0,0, - 144,21,192,8,1,0,2,36,1,0,2,36, - 17,0,2,162,6,23,192,12,33,40,0,2, - 28,0,191,143,24,0,178,143,20,0,177,143, - 16,0,176,143,8,0,224,3,32,0,189,39, - 0,0,0,0,0,0,0,0,0,129,9,52, - 16,0,130,144,2,131,3,60,192,246,99,36, - 64,18,2,0,33,56,67,0,140,0,230,140, - 0,1,8,36,4,0,197,140,0,0,131,140, - 0,0,128,172,12,0,137,172,4,0,164,172, - 12,0,200,172,33,48,160,0,216,0,226,140, - 33,40,128,0,1,0,66,36,0,128,99,48, - 4,0,96,20,216,0,226,172,4,0,132,140, - 161,21,192,8,0,0,0,0,8,0,224,3, - 140,0,230,172,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,8,0,224,3,0,0,0,0, - 172,0,128,172,176,0,128,172,180,0,128,172, - 184,0,128,172,188,0,128,172,192,0,128,172, - 196,0,128,172,200,0,128,172,204,0,128,172, - 208,0,128,172,212,0,128,172,224,0,128,172, - 8,1,128,172,4,1,128,172,236,0,128,172, - 240,0,128,172,232,0,128,172,244,0,128,172, - 8,0,224,3,248,0,128,172,224,255,189,39, - 16,0,176,175,33,128,128,0,20,0,177,175, - 0,2,17,36,24,0,191,175,13,8,192,12, - 0,48,4,36,255,31,3,60,255,255,99,52, - 33,32,0,0,36,16,67,0,0,128,3,60, - 37,40,67,0,33,24,160,0,0,128,6,52, - 1,0,132,36,24,0,98,36,0,0,96,164, - 2,0,102,164,4,0,98,172,33,24,64,0, - 42,16,145,0,249,255,64,20,1,0,132,36, - 255,255,132,36,64,16,17,0,33,16,81,0, - 192,16,2,0,33,16,69,0,48,0,163,36, - 236,255,69,172,108,0,3,174,104,0,3,174, - 96,0,5,174,100,0,2,174,24,0,191,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 32,0,189,39,248,255,189,39,0,32,14,60, - 4,0,177,175,7,0,17,60,0,0,176,175, - 4,0,16,60,2,131,25,60,192,246,57,39, - 0,1,15,36,108,0,152,140,104,0,137,140, - 176,0,140,140,180,0,141,140,94,0,56,17, - 0,0,0,0,4,0,43,141,0,0,0,0, - 37,16,110,1,0,0,66,148,0,0,0,0, - 0,128,66,48,86,0,64,16,37,16,46,1, - 0,0,67,140,0,0,0,0,36,16,113,0, - 76,0,80,20,0,32,98,48,41,0,64,20, - 15,0,98,48,188,0,130,140,0,0,0,0, - 1,0,66,36,188,0,130,172,0,8,98,48, - 6,0,64,16,0,4,98,48,192,0,130,140, - 0,0,0,0,1,0,66,36,192,0,130,172, - 0,4,98,48,6,0,64,16,0,2,98,48, - 196,0,130,140,0,0,0,0,1,0,66,36, - 196,0,130,172,0,2,98,48,6,0,64,16, - 0,1,98,48,200,0,130,140,0,0,0,0, - 1,0,66,36,200,0,130,172,0,1,98,48, - 6,0,64,16,32,0,98,48,204,0,130,140, - 0,0,0,0,1,0,66,36,204,0,130,172, - 32,0,98,48,6,0,64,16,15,0,98,48, - 208,0,130,140,0,0,0,0,1,0,66,36, - 208,0,130,172,15,0,98,48,212,0,131,140, - 8,0,37,141,33,24,98,0,212,0,131,172, - 17,0,162,144,1,0,140,37,255,255,66,36, - 17,0,162,160,25,0,64,20,37,24,46,1, - 16,0,162,144,1,0,173,37,64,18,2,0, - 33,64,89,0,140,0,7,141,0,129,10,52, - 4,0,230,140,0,0,163,140,0,0,160,172, - 12,0,170,172,4,0,197,172,12,0,239,172, - 33,56,192,0,216,0,2,141,33,48,160,0, - 1,0,66,36,0,128,99,48,4,0,96,20, - 216,0,2,173,4,0,165,140,114,22,192,8, - 0,0,0,0,140,0,7,173,37,24,46,1, - 0,128,2,60,0,0,98,172,40,22,192,8, - 33,72,96,1,104,0,137,172,176,0,140,172, - 180,0,141,172,4,0,177,143,0,0,176,143, - 8,0,224,3,8,0,189,39,224,255,189,39, - 16,0,176,175,33,128,128,0,24,0,191,175, - 20,0,177,175,44,0,17,142,0,0,0,0, - 0,0,34,150,0,0,0,0,0,32,66,48, - 89,0,64,16,0,0,0,0,2,0,34,150, - 0,0,0,0,0,1,66,48,84,0,64,20, - 0,0,0,0,27,22,192,12,0,0,0,0, - 104,0,4,142,0,0,0,0,2,0,130,148, - 0,128,3,52,255,255,66,48,75,0,67,16, - 0,0,0,0,224,0,2,142,0,0,0,0, - 1,0,66,36,224,0,2,174,4,0,36,174, - 0,0,128,164,4,0,130,140,0,0,0,0, - 0,0,64,164,0,0,2,142,0,0,0,0, - 51,0,64,16,0,33,2,36,2,0,34,150, - 0,0,0,0,47,0,64,16,0,33,2,36, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 2,0,34,150,0,0,0,0,211,255,64,20, - 0,33,2,36,2,0,34,166,0,0,2,142, - 0,0,0,0,5,0,64,16,0,0,0,0, - 8,0,2,142,0,0,0,0,242,22,192,8, - 0,0,64,172,164,7,192,12,0,0,0,0, - 24,0,191,143,20,0,177,143,16,0,176,143, - 8,0,224,3,32,0,189,39,108,0,133,140, - 0,0,0,0,4,0,162,140,0,0,0,0, - 4,0,67,140,104,0,130,140,0,0,0,0, - 5,0,98,20,33,16,160,0,184,0,131,140, - 33,16,0,0,1,0,99,36,184,0,131,172, - 8,0,224,3,0,0,0,0,224,255,189,39, - 16,0,176,175,33,128,128,0,28,0,191,175, - 24,0,178,175,20,0,177,175,108,0,18,142, - 8,1,6,142,44,0,17,142,4,0,66,142, - 104,0,7,142,4,0,66,140,18,0,163,148, - 172,0,4,142,0,0,0,0,6,0,71,20, - 255,255,99,48,184,0,3,142,33,16,0,0, - 1,0,99,36,157,23,192,8,184,0,3,174, - 33,48,195,0,1,0,130,36,172,0,2,174, - 8,1,6,174,8,0,162,140,4,1,3,142, - 0,0,70,144,33,32,64,2,8,0,69,174, - 12,0,64,174,1,0,194,48,2,0,64,16, - 1,0,98,36,4,1,2,174,0,0,2,142, - 0,0,0,0,35,0,64,20,0,0,0,0, - 18,0,162,148,0,0,0,0,255,255,66,48, - 12,0,66,174,0,0,34,150,0,0,0,0, - 0,32,66,48,24,0,64,16,12,0,2,36, - 2,0,34,150,0,0,0,0,0,1,66,48, - 19,0,64,20,12,0,2,36,4,0,242,16, - 0,0,0,0,27,22,192,12,33,32,0,2, - 12,0,2,36,2,0,66,166,104,0,4,142, - 0,0,0,0,0,0,128,164,4,0,130,140, - 0,0,0,0,0,0,64,164,0,33,2,36, - 4,0,36,174,164,7,192,12,2,0,34,166, - 154,23,192,8,0,0,0,0,154,23,192,8, - 2,0,130,164,0,0,34,150,0,0,0,0, - 0,32,66,48,69,0,64,16,12,0,2,36, - 4,0,242,16,0,0,0,0,27,22,192,12, - 33,32,0,2,12,0,2,36,2,0,66,166, - 104,0,4,142,0,0,0,0,0,0,128,164, - 4,0,130,140,0,0,0,0,0,0,64,164, - 4,0,36,174,2,0,34,150,0,0,0,0, - 47,0,64,16,0,33,2,36,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,2,0,34,150, - 0,0,0,0,211,255,64,20,0,33,2,36, - 2,0,34,166,8,0,2,142,0,0,0,0, - 154,23,192,8,0,0,64,172,2,0,66,166, - 4,0,67,142,1,0,2,36,108,0,3,174, - 28,0,191,143,24,0,178,143,20,0,177,143, - 16,0,176,143,8,0,224,3,32,0,189,39, - 216,255,189,39,20,0,177,175,33,136,128,0, - 24,0,178,175,2,131,18,60,192,131,82,38, - 28,0,179,175,0,1,19,36,32,0,191,175, - 16,0,176,175,104,0,48,142,108,0,34,142, - 0,0,0,0,4,0,2,22,0,0,0,0, - 2,0,2,150,245,23,192,8,0,0,0,0, - 2,0,2,150,0,0,0,0,7,0,66,48, - 11,0,64,20,33,40,64,2,2,131,4,60, - 160,131,132,36,2,131,7,60,252,131,231,36, - 15,63,192,12,0,2,6,36,1,0,4,36, - 33,40,64,2,188,7,192,12,0,2,6,36, - 2,0,2,150,4,0,3,36,7,0,66,48, - 40,0,67,20,0,128,2,52,8,0,3,142, - 0,0,0,0,17,0,98,144,0,0,0,0, - 255,255,66,36,17,0,98,160,17,0,98,144, - 0,0,0,0,30,0,64,20,0,128,2,52, - 180,0,34,142,33,32,96,0,1,0,66,36, - 180,0,34,174,16,0,130,144,2,131,3,60, - 192,246,99,36,64,18,2,0,33,56,67,0, - 140,0,230,140,0,129,8,52,4,0,197,140, - 0,0,131,140,0,0,128,172,12,0,136,172, - 4,0,164,172,12,0,211,172,33,48,160,0, - 216,0,226,140,33,40,128,0,1,0,66,36, - 0,128,99,48,4,0,96,20,216,0,226,172, - 4,0,132,140,223,23,192,8,0,0,0,0, - 140,0,230,172,0,128,2,52,2,0,2,166, - 0,0,0,166,4,0,16,142,174,23,192,8, - 0,0,0,0,44,0,35,142,104,0,48,174, - 0,0,98,148,0,0,0,0,0,32,66,52, - 0,0,98,164,32,0,191,143,28,0,179,143, - 24,0,178,143,20,0,177,143,16,0,176,143, - 8,0,224,3,40,0,189,39,0,163,2,60, - 0,1,66,52,0,0,66,140,2,131,3,60, - 192,6,99,36,255,3,66,48,60,0,66,36, - 0,128,66,52,8,0,224,3,0,0,98,172, - 208,255,189,39,28,0,177,175,33,136,128,0, - 32,0,178,175,33,144,160,0,24,0,176,175, - 0,163,16,60,0,163,2,60,164,1,66,140, - 0,1,16,54,44,0,191,175,40,0,180,175, - 4,0,64,20,36,0,179,175,60,0,2,36, - 0,163,1,60,164,1,34,172,0,163,2,60, - 164,1,66,140,0,0,0,0,221,5,66,40, - 3,0,64,20,220,5,2,36,0,163,1,60, - 164,1,34,172,0,163,3,60,164,1,99,140, - 255,255,2,36,21,0,98,20,0,0,0,0, - 128,128,130,143,0,0,0,0,5,0,67,20, - 2,0,5,36,130,11,192,12,0,0,0,0, - 128,128,130,175,2,0,5,36,10,0,6,36, - 128,128,132,143,0,131,7,60,8,96,231,36, - 156,11,192,12,16,0,160,175,0,0,2,142, - 2,131,3,60,192,6,99,36,255,3,66,48, - 66,24,192,8,64,0,66,36,0,163,2,60, - 164,1,66,140,2,131,3,60,192,6,99,36, - 0,128,66,52,0,0,98,172,255,31,4,60, - 255,255,132,52,2,131,2,60,208,6,66,36, - 36,16,68,0,0,160,5,60,37,16,69,0, - 2,131,3,60,176,12,99,36,2,131,1,60, - 196,6,32,172,2,131,1,60,200,6,34,172, - 12,0,2,36,0,0,96,164,2,131,1,60, - 178,12,34,164,6,0,65,6,36,16,100,0, - 37,16,69,0,2,131,1,60,180,12,34,172, - 99,24,192,8,255,31,18,60,2,131,2,60, - 178,12,66,148,0,0,0,0,0,128,66,52, - 2,131,1,60,178,12,34,164,255,31,18,60, - 255,255,82,54,2,131,2,60,192,6,66,36, - 36,16,82,0,0,160,20,60,37,16,84,0, - 2,131,1,60,184,12,34,172,2,131,1,60, - 188,12,32,172,44,0,34,142,0,0,0,0, - 0,0,66,148,2,131,19,60,176,12,115,38, - 0,32,66,48,15,0,64,20,33,40,0,0, - 2,131,4,60,160,131,132,36,2,131,16,60, - 192,131,16,38,33,40,0,2,2,131,7,60, - 24,132,231,36,15,63,192,12,71,2,6,36, - 1,0,4,36,33,40,0,2,188,7,192,12, - 71,2,6,36,33,40,0,0,33,48,0,0, - 36,16,114,2,44,0,35,142,37,16,84,0, - 4,0,98,172,44,0,36,142,208,7,7,36, - 129,67,192,12,2,0,132,36,12,0,64,20, - 0,0,0,0,44,0,34,142,0,0,0,0, - 2,0,69,148,2,131,4,60,15,63,192,12, - 56,132,132,36,255,255,4,36,2,131,5,60, - 192,131,165,36,188,7,192,12,79,2,6,36, - 44,0,34,142,0,33,3,36,2,0,67,164, - 8,0,34,142,0,0,0,0,0,0,64,172, - 44,0,191,143,40,0,180,143,36,0,179,143, - 32,0,178,143,28,0,177,143,24,0,176,143, - 8,0,224,3,48,0,189,39,232,255,189,39, - 128,128,132,143,0,128,2,52,16,0,191,175, - 2,131,1,60,3,0,128,4,178,12,34,164, - 177,11,192,12,0,0,0,0,16,0,191,143, - 24,0,189,39,8,0,224,3,0,0,0,0, - 8,0,224,3,0,0,0,0,0,0,0,0, - 0,0,0,0,240,255,2,52,2,131,1,60, - 33,8,34,0,208,12,32,172,240,255,66,36, - 251,255,65,4,0,0,0,0,2,131,2,60, - 208,12,66,36,0,163,1,60,12,1,32,172, - 0,163,1,60,212,5,34,172,1,0,2,60, - 148,133,128,175,144,133,128,175,0,163,1,60, - 8,0,224,3,216,5,34,172,0,0,136,148, - 4,0,138,148,1,0,2,49,34,0,64,20, - 2,0,137,148,0,25,10,0,38,24,106,0, - 38,24,105,0,240,255,99,48,2,131,15,60, - 208,12,239,37,33,40,111,0,68,133,142,143, - 128,0,3,36,0,0,162,140,4,0,171,148, - 23,0,64,16,43,16,194,1,9,0,64,16, - 6,0,172,148,7,0,11,21,8,0,173,148, - 5,0,44,21,0,0,0,0,3,0,77,21, - 10,0,162,148,8,0,224,3,0,0,0,0, - 255,255,99,36,10,0,96,16,240,255,165,36, - 43,16,175,0,238,255,64,16,0,0,162,140, - 248,127,229,37,248,127,165,36,218,24,192,8, - 0,0,162,140,8,0,224,3,254,255,2,36, - 8,0,224,3,255,255,2,36,8,0,224,3, - 0,0,0,0,0,0,136,148,68,133,142,143, - 1,0,2,49,53,0,64,20,2,0,137,148, - 0,131,2,60,4,0,138,148,12,1,89,140, - 0,25,10,0,38,24,106,0,38,24,105,0, - 240,255,99,48,2,131,15,60,208,12,239,37, - 33,56,111,0,128,0,3,36,0,0,248,140, - 4,0,235,148,43,16,216,1,14,0,64,16, - 6,0,236,148,24,0,11,21,8,0,237,148, - 22,0,44,21,255,127,2,60,20,0,77,21, - 255,255,66,52,43,16,2,3,2,0,64,16, - 33,16,198,1,0,0,226,172,10,0,229,164, - 8,0,224,3,0,0,2,36,3,0,0,23, - 1,0,57,35,0,131,2,60,12,1,89,172, - 33,16,198,1,0,0,226,172,10,0,229,164, - 4,0,232,164,6,0,233,164,8,0,234,164, - 8,0,224,3,1,0,2,36,255,255,99,36, - 11,0,96,16,0,0,0,0,240,255,231,36, - 43,16,239,0,221,255,64,16,0,0,248,140, - 248,127,231,37,248,127,231,36,8,25,192,8, - 0,0,248,140,8,0,224,3,0,0,2,36, - 144,133,130,143,0,0,0,0,1,0,66,32, - 144,133,130,175,8,0,224,3,255,255,2,36, - 8,0,224,3,0,0,0,0,164,128,130,143, - 0,0,0,0,7,0,130,20,232,255,189,39, - 160,128,130,143,2,131,3,60,208,12,99,36, - 0,17,2,0,108,25,192,8,33,16,67,0, - 42,16,130,0,3,0,64,16,255,255,2,36, - 164,128,128,175,160,128,130,175,164,128,130,143, - 160,128,131,143,35,48,130,0,1,0,101,36, - 0,16,162,40,25,0,64,16,0,25,5,0, - 68,133,135,143,2,131,2,60,33,16,67,0, - 208,12,66,140,0,0,0,0,43,16,226,0, - 4,0,64,16,0,0,0,0,255,255,198,36, - 6,0,192,16,0,16,162,40,1,0,165,36, - 0,16,162,40,243,255,64,20,16,0,99,36, - 0,16,162,40,7,0,64,16,0,25,5,0, - 2,131,2,60,208,12,66,36,160,128,133,175, - 164,128,132,175,108,25,192,8,33,16,98,0, - 33,16,0,0,255,255,3,36,164,128,128,175, - 160,128,131,175,8,0,224,3,24,0,189,39, - 0,0,0,0,0,0,0,0,24,255,189,39, - 228,0,191,175,224,0,190,175,220,0,183,175, - 216,0,182,175,212,0,181,175,208,0,180,175, - 204,0,179,175,200,0,178,175,196,0,177,175, - 192,0,176,175,44,28,192,12,0,0,0,0, - 176,128,132,39,15,63,192,12,1,0,17,36, - 24,0,176,39,164,68,192,12,33,32,0,2, - 24,0,162,131,0,0,0,0,137,25,192,8, - 32,0,8,36,0,0,2,130,32,0,8,36, - 253,255,72,16,1,0,16,38,255,255,16,38, - 9,0,8,36,249,255,72,16,1,0,16,38, - 255,255,16,38,0,0,2,146,0,0,0,0, - 208,255,66,36,10,0,66,44,27,0,64,16, - 33,32,0,2,33,40,0,0,212,68,192,12, - 33,48,0,0,0,0,3,146,0,0,0,0, - 208,255,99,36,10,0,99,44,9,0,96,16, - 33,136,64,0,1,0,16,38,0,0,2,146, - 0,0,0,0,208,255,66,36,10,0,66,44, - 251,255,64,20,1,0,16,38,255,255,16,38, - 0,0,2,130,32,0,8,36,253,255,72,16, - 1,0,16,38,255,255,16,38,9,0,8,36, - 249,255,72,16,1,0,16,38,255,255,16,38, - 0,0,2,130,0,0,3,146,0,0,0,0, - 22,0,64,16,104,0,180,39,32,0,8,36, - 19,0,72,16,9,0,8,36,17,0,72,16, - 32,0,5,36,9,0,4,36,208,255,98,36, - 10,0,66,44,12,0,64,20,0,0,0,0, - 1,0,16,38,0,0,131,162,0,0,2,130, - 0,0,3,146,0,0,0,0,5,0,64,16, - 1,0,148,38,3,0,69,16,0,0,0,0, - 243,255,68,20,208,255,98,36,0,0,128,162, - 104,0,180,39,0,0,2,130,32,0,8,36, - 253,255,72,16,1,0,16,38,255,255,16,38, - 9,0,8,36,249,255,72,16,1,0,16,38, - 255,255,16,38,33,240,0,2,0,0,196,131, - 0,0,0,0,32,69,192,12,144,0,190,175, - 11,0,64,16,33,32,192,3,33,40,0,0, - 212,68,192,12,33,48,0,0,33,152,64,0, - 33,32,192,3,33,40,0,0,44,69,192,12, - 16,0,6,36,232,25,192,8,33,144,64,0, - 255,255,18,36,255,255,19,36,0,0,3,130, - 0,0,2,146,0,0,0,0,17,0,96,16, - 32,0,8,36,15,0,104,16,1,0,16,38, - 255,255,16,38,32,0,4,36,0,22,2,0, - 3,22,2,0,9,0,8,36,8,0,72,16, - 0,0,0,0,1,0,16,38,0,0,3,130, - 0,0,2,146,3,0,96,16,0,0,0,0, - 246,255,100,20,0,22,2,0,0,0,2,130, - 32,0,8,36,253,255,72,16,1,0,16,38, - 255,255,16,38,9,0,8,36,249,255,72,16, - 1,0,16,38,255,255,16,38,33,184,0,2, - 33,32,224,2,33,40,0,0,212,68,192,12, - 33,48,0,0,33,32,224,2,33,40,0,0, - 16,0,6,36,44,69,192,12,33,176,64,0, - 0,0,227,130,0,0,0,0,15,0,96,16, - 33,168,64,0,32,0,8,36,12,0,104,16, - 32,0,3,36,0,0,2,130,9,0,8,36, - 8,0,72,16,0,0,0,0,1,0,16,38, - 0,0,2,130,0,0,0,0,3,0,64,16, - 0,0,0,0,248,255,67,20,0,0,0,0, - 0,0,131,130,0,0,0,0,121,0,98,44, - 244,1,64,16,128,16,3,0,2,131,1,60, - 33,8,34,0,160,138,34,140,0,0,0,0, - 8,0,64,0,0,0,0,0,1,0,131,130, - 104,0,2,36,26,0,98,16,105,0,98,40, - 7,0,64,16,116,0,2,36,34,0,96,16, - 98,0,2,36,11,0,98,16,0,0,0,0, - 26,28,192,8,0,0,0,0,5,0,98,16, - 119,0,8,36,27,0,104,16,33,16,32,2, - 26,28,192,8,0,0,0,0,4,162,2,60, - 33,144,66,2,2,0,130,130,0,0,0,0, - 214,1,64,20,0,0,0,0,2,131,4,60, - 108,132,132,36,0,0,70,146,82,26,192,8, - 0,0,0,0,2,0,130,130,0,0,0,0, - 205,1,64,20,0,0,0,0,2,131,4,60, - 120,132,132,36,0,0,70,150,0,0,0,0, - 15,63,192,12,33,40,64,2,125,25,192,8, - 0,0,0,0,33,16,32,2,37,255,64,16, - 255,255,49,38,0,0,80,142,2,131,4,60, - 132,132,132,36,33,40,64,2,4,0,82,38, - 15,63,192,12,33,48,0,2,33,16,32,2, - 247,255,64,20,255,255,49,38,125,25,192,8, - 0,0,0,0,1,0,131,130,104,0,2,36, - 23,0,98,16,105,0,98,40,7,0,64,16, - 116,0,2,36,25,0,96,16,98,0,2,36, - 11,0,98,16,0,0,0,0,26,28,192,8, - 0,0,0,0,5,0,98,16,119,0,8,36, - 17,0,104,16,0,0,0,0,26,28,192,8, - 0,0,0,0,4,162,2,60,33,144,66,2, - 2,0,130,130,0,0,0,0,158,1,64,20, - 0,0,0,0,125,25,192,8,0,0,85,162, - 2,0,130,130,0,0,0,0,152,1,64,20, - 0,0,0,0,125,25,192,8,0,0,85,166, - 125,25,192,8,0,0,85,174,0,163,16,60, - 31,163,17,60,255,255,49,54,0,0,2,142, - 0,0,0,0,4,0,82,20,0,0,0,0, - 180,128,132,39,15,63,192,12,33,40,0,2, - 4,0,16,38,43,16,48,2,246,255,64,16, - 0,0,0,0,125,25,192,8,0,0,0,0, - 33,16,32,2,228,254,64,16,255,255,49,38, - 33,32,96,2,164,32,192,12,33,40,192,2, - 33,16,32,2,251,255,64,20,255,255,49,38, - 125,25,192,8,0,0,0,0,1,0,130,130, - 0,0,0,0,117,1,64,20,33,32,32,2, - 133,29,192,12,33,40,96,2,125,25,192,8, - 0,0,0,0,33,32,96,2,33,40,32,2, - 234,31,192,12,33,48,192,2,125,25,192,8, - 0,0,0,0,1,0,130,130,0,0,0,0, - 103,1,64,20,33,16,32,2,200,254,64,16, - 255,255,49,38,33,32,96,2,33,40,192,2, - 182,29,192,12,33,48,0,2,33,16,32,2, - 250,255,64,20,255,255,49,38,125,25,192,8, - 0,0,0,0,33,32,32,2,33,40,96,2, - 33,48,192,2,38,30,192,12,33,56,0,2, - 125,25,192,8,0,0,0,0,5,162,2,60, - 0,0,69,144,2,131,4,60,15,63,192,12, - 144,132,132,36,125,25,192,8,0,0,0,0, - 0,163,1,60,20,1,32,172,14,0,32,18, - 33,128,0,0,164,7,192,12,1,0,16,38, - 143,63,192,12,0,0,0,0,143,63,192,12, - 0,0,0,0,143,63,192,12,0,0,0,0, - 143,63,192,12,0,0,0,0,43,16,17,2, - 244,255,64,20,0,0,0,0,184,63,192,12, - 0,0,0,0,0,163,16,60,20,1,16,142, - 0,0,0,0,7,0,17,22,33,40,32,2, - 2,131,4,60,164,132,132,36,15,63,192,12, - 33,40,32,2,125,25,192,8,0,0,0,0, - 2,131,4,60,188,132,132,36,15,63,192,12, - 33,48,0,2,125,25,192,8,0,0,0,0, - 0,0,226,130,7,162,8,60,16,0,64,16, - 33,144,72,2,33,16,32,2,134,254,64,16, - 255,255,49,38,0,0,85,174,2,131,4,60, - 132,132,132,36,33,40,64,2,15,63,192,12, - 33,48,160,2,4,0,82,38,33,16,32,2, - 247,255,64,20,255,255,49,38,125,25,192,8, - 0,0,0,0,33,16,32,2,119,254,64,16, - 255,255,49,38,0,0,80,142,2,131,4,60, - 132,132,132,36,33,40,64,2,4,0,82,38, - 15,63,192,12,33,48,0,2,33,16,32,2, - 247,255,64,20,255,255,49,38,125,25,192,8, - 0,0,0,0,7,162,16,60,64,0,17,38, - 2,131,4,60,228,132,132,36,33,40,0,2, - 0,0,6,142,0,0,0,0,15,63,192,12, - 4,0,16,38,42,16,17,2,247,255,64,20, - 7,162,8,60,128,0,16,37,176,0,17,37, - 2,131,4,60,228,132,132,36,33,40,0,2, - 0,0,6,142,0,0,0,0,15,63,192,12, - 4,0,16,38,42,16,17,2,247,255,64,20, - 7,162,8,60,192,0,16,37,240,0,17,37, - 2,131,4,60,228,132,132,36,33,40,0,2, - 0,0,6,142,0,0,0,0,15,63,192,12, - 4,0,16,38,42,16,17,2,247,255,64,20, - 0,0,0,0,125,25,192,8,0,0,0,0, - 1,0,130,130,0,0,0,0,222,0,64,20, - 33,16,32,2,63,254,64,16,255,255,49,38, - 33,32,96,2,213,29,192,12,33,40,160,2, - 33,16,32,2,251,255,64,20,255,255,49,38, - 125,25,192,8,0,0,0,0,1,0,130,130, - 0,0,0,0,208,0,64,20,33,16,32,2, - 49,254,64,16,255,255,49,38,33,32,96,2, - 161,31,192,12,33,40,192,2,33,16,32,2, - 251,255,64,20,255,255,49,38,125,25,192,8, - 0,0,0,0,33,16,32,2,38,254,64,16, - 255,255,49,38,208,32,192,12,33,32,0,0, - 33,32,0,0,164,32,192,12,33,40,0,0, - 40,29,192,12,0,0,0,0,133,29,192,12, - 255,255,4,36,33,16,32,2,245,255,64,20, - 255,255,49,38,125,25,192,8,0,0,0,0, - 1,0,131,130,87,0,2,36,27,0,98,16, - 88,0,98,40,7,0,64,16,114,0,2,36, - 37,0,96,16,82,0,2,36,9,0,98,16, - 0,0,0,0,125,25,192,8,0,0,0,0, - 5,0,98,16,119,0,8,36,15,0,104,16, - 0,0,0,0,125,25,192,8,0,0,0,0, - 2,0,130,130,0,0,0,0,159,0,64,20, - 0,0,0,0,60,65,192,12,33,32,96,2, - 184,128,132,39,33,40,96,2,15,63,192,12, - 33,48,64,0,125,25,192,8,0,0,0,0, - 2,0,130,130,0,0,0,0,147,0,64,20, - 33,32,96,2,162,65,192,12,33,40,160,2, - 242,253,64,20,33,40,160,2,2,131,4,60, - 8,133,132,36,15,63,192,12,33,48,96,2, - 125,25,192,8,0,0,0,0,33,16,32,2, - 233,253,64,16,255,255,49,38,40,29,192,12, - 0,0,0,0,33,16,32,2,252,255,64,20, - 255,255,49,38,125,25,192,8,0,0,0,0, - 1,0,133,130,87,0,2,36,29,0,162,16, - 88,0,162,40,5,0,64,16,82,0,2,36, - 11,0,162,16,33,16,32,2,125,25,192,8, - 0,0,0,0,114,0,2,36,5,0,162,16, - 119,0,8,36,19,0,168,16,33,32,64,2, - 125,25,192,8,0,0,0,0,33,16,32,2, - 206,253,64,16,255,255,49,38,168,69,192,12, - 33,32,64,2,184,128,132,39,33,40,64,2, - 15,63,192,12,33,48,64,0,1,0,82,38, - 33,16,32,2,247,255,64,20,255,255,49,38, - 125,25,192,8,0,0,0,0,33,32,64,2, - 29,70,192,12,33,40,160,2,189,253,64,20, - 33,40,160,2,2,131,4,60,40,133,132,36, - 15,63,192,12,33,48,64,2,125,25,192,8, - 0,0,0,0,144,0,164,143,122,28,192,12, - 0,0,0,0,125,25,192,8,0,0,0,0, - 33,16,96,2,175,253,64,16,255,255,115,38, - 143,63,192,12,0,0,0,0,33,16,96,2, - 252,255,64,20,255,255,115,38,125,25,192,8, - 0,0,0,0,33,16,32,2,165,253,64,16, - 255,255,49,38,33,32,96,2,208,32,192,12, - 33,40,192,2,33,16,32,2,251,255,64,20, - 255,255,49,38,125,25,192,8,0,0,0,0, - 1,0,130,146,0,0,0,0,159,255,66,36, - 0,22,2,0,3,30,2,0,24,0,98,44, - 27,0,64,16,128,16,3,0,2,131,1,60, - 33,8,34,0,136,140,34,140,0,0,0,0, - 8,0,64,0,0,0,0,0,12,33,192,12, - 33,32,64,2,125,25,192,8,0,0,0,0, - 15,33,192,12,33,32,96,2,125,25,192,8, - 0,0,0,0,18,33,192,12,33,32,96,2, - 125,25,192,8,0,0,0,0,22,33,192,12, - 33,32,96,2,125,25,192,8,0,0,0,0, - 25,33,192,12,33,32,64,2,125,25,192,8, - 0,0,0,0,33,32,64,2,7,33,192,12, - 33,40,192,2,125,25,192,8,0,0,0,0, - 16,0,182,175,33,32,32,2,33,40,192,3, - 33,48,224,2,161,33,192,12,33,56,160,2, - 125,25,192,8,0,0,0,0,33,136,0,0, - 2,131,4,60,72,133,132,36,15,63,192,12, - 1,0,49,38,32,0,34,46,250,255,64,20, - 0,0,0,0,125,25,192,8,0,0,0,0, - 2,131,4,60,92,133,132,36,15,63,192,12, - 33,40,128,2,123,25,192,8,0,0,0,0, - 228,0,191,143,224,0,190,143,220,0,183,143, - 216,0,182,143,212,0,181,143,208,0,180,143, - 204,0,179,143,200,0,178,143,196,0,177,143, - 192,0,176,143,8,0,224,3,232,0,189,39, - 232,255,189,39,2,131,5,60,192,154,165,36, - 20,0,191,175,16,0,176,175,0,0,162,140, - 0,0,0,0,9,0,64,16,33,128,160,0, - 0,0,5,142,192,128,132,39,15,63,192,12, - 4,0,16,38,0,0,2,142,0,0,0,0, - 249,255,64,20,0,0,0,0,20,0,191,143, - 16,0,176,143,8,0,224,3,24,0,189,39, - 0,0,132,144,0,0,0,0,208,255,130,36, - 10,0,66,44,4,0,64,16,0,22,4,0, - 3,22,2,0,89,28,192,8,208,255,66,36, - 159,255,130,36,6,0,66,44,4,0,64,16, - 0,22,4,0,3,22,2,0,89,28,192,8, - 169,255,66,36,191,255,130,36,6,0,66,44, - 3,0,64,20,0,22,4,0,89,28,192,8, - 255,255,2,36,3,22,2,0,201,255,66,36, - 8,0,224,3,0,0,0,0,216,255,189,39, - 24,0,178,175,33,144,128,0,32,0,191,175, - 28,0,179,175,20,0,177,175,16,0,176,175, - 0,0,81,142,0,0,0,0,65,28,192,12, - 33,32,32,2,33,24,64,0,255,255,19,36, - 9,0,115,16,0,129,3,0,65,28,192,12, - 1,0,36,38,33,24,64,0,4,0,115,16, - 2,0,34,38,0,0,66,174,115,28,192,8, - 37,16,3,2,255,255,2,36,32,0,191,143, - 28,0,179,143,24,0,178,143,20,0,177,143, - 16,0,176,143,8,0,224,3,40,0,189,39, - 176,255,189,39,64,0,180,175,33,160,128,0, - 72,0,191,175,68,0,181,175,60,0,179,175, - 56,0,178,175,52,0,177,175,48,0,176,175, - 0,0,130,130,0,0,0,0,53,0,64,20, - 33,128,0,0,27,67,192,12,33,32,0,0, - 1,0,4,36,27,67,192,12,33,128,64,0, - 2,0,4,36,27,67,192,12,33,136,64,0, - 33,24,64,0,255,255,2,36,5,0,2,18, - 0,0,0,0,3,0,34,18,0,0,0,0, - 6,0,98,20,255,255,2,52,2,131,4,60, - 15,63,192,12,60,137,132,36,29,29,192,8, - 0,0,0,0,5,0,2,18,0,0,0,0, - 3,0,34,18,0,0,0,0,6,0,98,20, - 1,0,2,50,2,131,4,60,15,63,192,12, - 104,137,132,36,29,29,192,8,0,0,0,0, - 6,0,64,16,255,0,5,50,2,131,4,60, - 15,63,192,12,132,137,132,36,29,29,192,8, - 0,0,0,0,2,131,4,60,176,137,132,36, - 3,50,16,0,3,18,17,0,16,0,162,175, - 255,0,98,48,20,0,162,175,3,18,3,0, - 255,0,39,50,15,63,192,12,24,0,162,175, - 29,29,192,8,0,0,0,0,40,0,180,175, - 58,0,21,36,32,0,19,36,255,255,18,36, - 32,0,177,39,40,0,162,143,0,0,0,0, - 0,0,67,128,0,0,0,0,3,0,117,16, - 0,0,0,0,3,0,115,20,0,0,0,0, - 1,0,66,36,40,0,162,175,91,28,192,12, - 40,0,164,39,33,24,64,0,75,0,114,16, - 0,0,0,0,40,0,162,143,0,0,35,166, - 0,0,67,128,0,0,0,0,3,0,117,16, - 0,0,0,0,3,0,115,20,0,0,0,0, - 1,0,66,36,40,0,162,175,91,28,192,12, - 40,0,164,39,33,24,64,0,60,0,114,16, - 1,0,16,38,0,0,34,150,0,26,3,0, - 37,16,67,0,0,0,34,166,3,0,2,42, - 220,255,64,20,2,0,49,38,32,0,165,151, - 0,0,0,0,1,0,162,48,7,0,64,16, - 0,0,0,0,2,131,4,60,208,137,132,36, - 15,63,192,12,255,0,165,48,25,29,192,8, - 0,0,0,0,36,0,162,151,0,0,0,0, - 0,7,66,48,6,0,64,16,0,0,0,0, - 2,131,4,60,15,63,192,12,0,138,132,36, - 25,29,192,8,0,0,0,0,255,66,192,12, - 33,32,0,0,1,0,4,36,34,0,165,151, - 0,0,0,0,255,66,192,12,33,128,0,0, - 36,0,165,151,0,0,0,0,255,66,192,12, - 2,0,4,36,2,131,4,60,15,63,192,12, - 32,138,132,36,2,131,4,60,80,138,132,36, - 15,63,192,12,33,40,0,2,196,128,132,39, - 200,128,134,39,31,21,192,12,32,0,165,39, - 36,0,162,151,1,0,16,38,0,1,66,36, - 36,0,162,167,8,0,2,42,7,0,64,16, - 0,0,0,0,8,29,192,8,0,0,0,0, - 2,131,4,60,116,138,132,36,15,63,192,12, - 33,40,128,2,72,0,191,143,68,0,181,143, - 64,0,180,143,60,0,179,143,56,0,178,143, - 52,0,177,143,48,0,176,143,8,0,224,3, - 80,0,189,39,0,0,0,0,0,0,0,0, - 224,255,189,39,16,0,176,175,33,128,0,0, - 20,0,177,175,33,136,0,0,24,0,191,175, - 33,32,0,2,162,65,192,12,33,40,0,0, - 43,0,64,16,0,0,0,0,1,0,16,38, - 64,0,2,42,249,255,64,20,33,32,0,2, - 33,128,0,0,85,85,17,36,33,32,0,2, - 162,65,192,12,85,85,5,36,32,0,64,16, - 0,0,0,0,1,0,16,38,64,0,2,42, - 249,255,64,20,33,32,0,2,33,128,0,0, - 170,170,17,52,33,32,0,2,162,65,192,12, - 170,170,5,52,21,0,64,16,0,0,0,0, - 1,0,16,38,64,0,2,42,249,255,64,20, - 33,32,0,2,33,128,0,0,255,255,17,52, - 33,32,0,2,162,65,192,12,255,255,5,52, - 10,0,64,16,0,0,0,0,1,0,16,38, - 64,0,2,42,249,255,64,20,33,32,0,2, - 2,131,4,60,15,63,192,12,240,140,132,36, - 101,29,192,8,0,0,0,0,60,65,192,12, - 33,32,0,2,2,131,4,60,4,141,132,36, - 33,40,32,2,33,48,0,2,15,63,192,12, - 33,56,64,0,24,0,191,143,20,0,177,143, - 16,0,176,143,8,0,224,3,32,0,189,39, - 0,0,0,0,0,0,0,0,232,255,189,39, - 16,0,191,175,210,7,192,12,0,0,0,0, - 139,14,192,12,0,0,0,0,180,10,192,12, - 0,0,0,0,32,133,132,143,1,0,2,36, - 42,16,68,0,9,0,64,16,0,2,3,36, - 64,34,4,0,2,131,1,60,33,8,35,0, - 196,246,32,172,0,2,99,36,42,16,100,0, - 250,255,64,20,0,0,0,0,16,0,191,143, - 24,0,189,39,8,0,224,3,0,0,0,0, - 208,255,189,39,24,0,178,175,33,144,128,0, - 32,0,180,175,33,160,160,0,44,0,191,175, - 40,0,182,175,36,0,181,175,28,0,179,175, - 20,0,177,175,3,0,128,26,16,0,176,175, - 149,29,192,8,1,0,147,38,1,0,20,36, - 32,133,147,143,255,255,82,38,255,255,2,36, - 20,0,66,18,255,255,21,36,2,131,22,60, - 192,246,214,38,108,29,192,12,33,128,128,2, - 42,16,19,2,10,0,64,16,64,18,16,0, - 33,136,86,0,242,21,192,12,33,32,32,2, - 133,12,192,12,33,32,0,2,1,0,16,38, - 42,16,19,2,249,255,64,20,0,2,49,38, - 255,255,82,38,240,255,85,22,0,0,0,0, - 44,0,191,143,40,0,182,143,36,0,181,143, - 32,0,180,143,28,0,179,143,24,0,178,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 48,0,189,39,216,255,189,39,24,0,178,175, - 33,144,160,0,28,0,179,175,33,152,192,0, - 32,0,191,175,20,0,177,175,3,0,128,24, - 16,0,176,175,195,29,192,8,1,0,145,36, - 1,0,4,36,32,133,145,143,33,128,128,0, - 42,16,17,2,8,0,64,16,33,32,0,2, - 33,40,64,2,250,29,192,12,33,48,96,2, - 1,0,16,38,42,16,17,2,250,255,64,20, - 33,32,0,2,32,0,191,143,28,0,179,143, - 24,0,178,143,20,0,177,143,16,0,176,143, - 8,0,224,3,40,0,189,39,224,255,189,39, - 24,0,191,175,20,0,177,175,3,0,128,24, - 16,0,176,175,222,29,192,8,1,0,145,36, - 1,0,4,36,32,133,145,143,33,128,128,0, - 42,16,17,2,7,0,64,16,0,0,0,0, - 237,29,192,12,33,32,0,2,1,0,16,38, - 42,16,17,2,251,255,64,20,0,0,0,0, - 24,0,191,143,20,0,177,143,16,0,176,143, - 8,0,224,3,32,0,189,39,64,34,4,0, - 2,131,2,60,192,246,66,36,33,32,130,0, - 44,0,131,140,1,0,2,36,32,0,130,172, - 16,0,2,36,2,0,98,164,8,0,130,140, - 0,0,0,0,8,0,224,3,0,0,64,172, - 208,255,189,39,33,48,128,0,64,18,6,0, - 2,131,3,60,192,246,99,36,36,0,177,175, - 33,136,67,0,40,0,191,175,32,0,176,175, - 4,0,34,142,0,0,0,0,4,0,64,20, - 33,128,160,0,1,0,4,36,133,29,192,12, - 33,40,192,0,3,0,0,30,221,5,2,42, - 17,30,192,8,1,0,16,36,3,0,64,20, - 33,32,32,2,220,5,16,36,33,32,32,2, - 208,7,5,36,108,0,131,140,12,0,2,36, - 2,0,98,164,16,0,162,39,8,0,98,172, - 0,128,2,54,12,0,96,172,16,0,162,175, - 255,255,2,36,20,0,162,175,2,131,2,60, - 0,155,66,36,98,31,192,12,24,0,162,175, - 40,0,191,143,36,0,177,143,32,0,176,143, - 8,0,224,3,48,0,189,39,56,254,189,39, - 160,1,176,175,33,128,192,0,48,1,164,175, - 33,32,224,0,64,18,5,0,2,131,3,60, - 192,246,99,36,33,16,67,0,56,1,162,175, - 64,18,16,0,33,16,67,0,40,0,168,39, - 196,1,191,175,192,1,190,175,188,1,183,175, - 184,1,182,175,180,1,181,175,176,1,180,175, - 172,1,179,175,168,1,178,175,164,1,177,175, - 64,1,162,175,12,0,160,24,96,1,168,175, - 32,133,131,143,0,0,0,0,42,16,163,0, - 19,1,64,16,1,0,2,36,5,0,0,26, - 42,16,3,2,15,1,64,16,1,0,2,36, - 3,0,176,20,33,40,0,0,86,31,192,8, - 1,0,2,36,212,68,192,12,33,48,0,0, - 6,0,65,4,104,1,162,175,33,72,64,0, - 35,72,9,0,104,1,169,175,87,30,192,8, - 112,1,160,175,1,0,8,36,112,1,168,175, - 1,0,4,36,133,29,192,12,33,40,0,0, - 237,29,192,12,33,32,0,2,24,0,169,39, - 56,1,168,143,255,0,2,36,80,1,169,175, - 108,0,8,141,43,1,163,39,72,1,168,175, - 0,0,98,160,255,255,66,36,253,255,65,4, - 255,255,99,36,64,1,169,143,0,0,0,0, - 120,0,41,141,64,1,168,143,128,1,169,175, - 124,0,8,141,64,1,169,143,136,1,168,175, - 44,0,34,141,0,0,0,0,12,0,64,172, - 44,0,34,141,0,0,0,0,16,0,64,172, - 44,0,34,141,120,1,160,175,32,0,64,172, - 44,0,34,141,88,1,160,175,24,0,64,172, - 48,1,168,143,0,0,0,0,168,0,0,25, - 40,0,169,39,144,1,169,175,88,1,168,143, - 0,0,0,0,255,0,2,49,4,0,86,36, - 60,0,194,42,2,0,64,16,0,0,0,0, - 60,0,22,36,104,1,169,143,0,0,0,0, - 2,0,32,17,0,0,0,0,104,1,182,143, - 56,1,164,143,72,1,168,143,12,0,2,36, - 2,0,2,165,80,1,169,143,0,128,194,54, - 8,0,9,173,12,0,0,173,0,0,34,173, - 255,255,8,36,4,0,40,173,144,1,168,143, - 0,0,0,0,8,0,40,173,88,1,168,143, - 96,1,169,143,208,7,5,36,98,31,192,12, - 0,0,40,173,0,128,5,52,0,128,6,52, - 128,1,164,143,0,0,0,0,129,67,192,12, - 2,0,7,36,13,0,64,20,0,0,0,0, - 88,1,165,143,2,131,4,60,15,63,192,12, - 64,141,132,36,120,1,169,143,0,0,0,0, - 1,0,41,37,20,0,34,41,117,0,64,16, - 120,1,169,175,32,31,192,8,0,0,0,0, - 128,1,168,143,64,1,169,143,8,0,2,141, - 255,255,8,36,136,0,53,141,0,0,0,0, - 50,0,72,16,33,184,0,0,1,0,4,36, - 4,0,18,36,4,0,3,36,0,0,190,142, - 8,0,166,142,112,1,169,143,255,63,212,51, - 30,0,32,17,33,184,244,2,42,16,116,0, - 27,0,64,16,33,152,96,0,144,1,168,143, - 0,0,0,0,33,136,72,2,33,128,102,0, - 15,0,128,16,0,0,0,0,0,0,2,146, - 0,0,35,146,0,0,0,0,10,0,67,16, - 33,48,192,2,2,131,4,60,92,141,132,36, - 88,1,165,143,16,0,163,175,0,0,2,146, - 33,56,64,2,15,63,192,12,20,0,162,175, - 33,32,0,0,1,0,115,38,1,0,16,38, - 1,0,49,38,42,16,116,2,235,255,64,20, - 1,0,82,38,33,24,0,0,4,0,181,142, - 0,128,194,51,217,255,64,16,0,0,0,0, - 128,1,169,143,0,0,0,0,8,0,34,141, - 0,0,0,0,25,0,128,16,18,0,87,164, - 9,0,246,18,33,48,192,2,2,131,4,60, - 140,141,132,36,88,1,165,143,0,0,0,0, - 15,63,192,12,33,56,224,2,5,31,192,8, - 0,0,0,0,64,1,168,143,0,0,0,0, - 136,0,2,141,96,1,169,143,8,0,70,140, - 0,0,34,141,0,0,198,140,0,0,0,0, - 7,0,194,16,0,0,0,0,88,1,165,143, - 2,131,4,60,15,63,192,12,184,141,132,36, - 64,1,168,143,0,0,0,0,136,0,4,141, - 152,21,192,12,0,0,0,0,64,1,169,143, - 0,0,0,0,136,0,53,173,128,1,168,143, - 8,128,2,52,0,0,0,165,2,0,2,165, - 8,0,0,173,12,0,0,165,136,1,169,143, - 8,0,2,36,2,0,34,165,4,0,40,141, - 128,1,169,143,136,1,168,175,4,0,41,141, - 64,1,168,143,128,1,169,175,120,0,9,173, - 136,1,169,143,0,0,0,0,124,0,9,173, - 88,1,168,143,48,1,169,143,1,0,8,37, - 42,16,9,1,91,255,64,20,88,1,168,175, - 64,1,168,143,0,0,0,0,44,0,3,141, - 0,0,0,0,12,0,98,140,0,0,0,0, - 5,0,64,16,0,0,0,0,12,0,101,140, - 2,131,4,60,15,63,192,12,212,141,132,36, - 64,1,169,143,0,0,0,0,44,0,35,141, - 0,0,0,0,16,0,98,140,0,0,0,0, - 5,0,64,16,0,0,0,0,16,0,101,140, - 2,131,4,60,15,63,192,12,240,141,132,36, - 64,1,168,143,0,0,0,0,44,0,3,141, - 0,0,0,0,32,0,98,140,0,0,0,0, - 5,0,64,16,0,0,0,0,32,0,101,140, - 2,131,4,60,15,63,192,12,16,142,132,36, - 64,1,169,143,0,0,0,0,44,0,35,141, - 0,0,0,0,24,0,98,140,0,0,0,0, - 5,0,64,16,0,0,0,0,24,0,101,140, - 2,131,4,60,15,63,192,12,48,142,132,36, - 196,1,191,143,192,1,190,143,188,1,183,143, - 184,1,182,143,180,1,181,143,176,1,180,143, - 172,1,179,143,168,1,178,143,164,1,177,143, - 160,1,176,143,8,0,224,3,200,1,189,39, - 224,255,189,39,16,0,176,175,33,128,128,0, - 24,0,191,175,20,0,177,175,44,0,4,142, - 0,0,0,0,0,0,130,148,0,0,0,0, - 0,32,66,48,7,0,64,20,33,136,160,0, - 0,0,133,148,2,131,4,60,15,63,192,12, - 80,142,132,36,156,31,192,8,3,0,2,36, - 2,0,132,36,33,40,0,0,33,48,0,0, - 129,67,192,12,33,56,32,2,13,0,64,16, - 33,40,0,0,44,0,3,142,0,33,2,36, - 2,0,98,164,8,0,2,142,33,48,0,0, - 0,0,64,172,44,0,4,142,33,56,32,2, - 129,67,192,12,2,0,132,36,9,0,64,20, - 0,32,5,36,44,0,2,142,0,0,0,0, - 2,0,69,148,2,131,4,60,15,63,192,12, - 108,142,132,36,156,31,192,8,1,0,2,36, - 44,0,4,142,0,32,6,36,129,67,192,12, - 33,56,32,2,8,0,64,20,33,16,0,0, - 44,0,2,142,0,0,0,0,0,0,69,148, - 2,131,4,60,15,63,192,12,132,142,132,36, - 2,0,2,36,24,0,191,143,20,0,177,143, - 16,0,176,143,8,0,224,3,32,0,189,39, - 224,255,189,39,24,0,178,175,33,144,160,0, - 28,0,191,175,20,0,177,175,7,0,128,4, - 16,0,176,175,24,133,130,143,0,0,0,0, - 255,255,66,36,42,16,68,0,4,0,64,16, - 33,136,128,0,24,133,130,143,33,32,0,0, - 255,255,81,36,33,128,128,0,42,16,48,2, - 7,0,64,20,33,32,0,2,193,31,192,12, - 33,40,64,2,1,0,16,38,42,16,48,2, - 251,255,64,16,33,32,0,2,28,0,191,143, - 24,0,178,143,20,0,177,143,16,0,176,143, - 8,0,224,3,32,0,189,39,8,0,224,3, - 0,0,0,0,232,255,189,39,16,0,191,175, - 236,63,192,12,1,16,4,36,85,0,2,36, - 131,131,1,60,128,18,34,160,16,0,191,143, - 24,0,189,39,8,0,224,3,0,0,0,0, - 216,255,189,39,28,0,177,175,33,136,128,0, - 32,0,178,175,33,144,160,0,212,128,132,39, - 36,0,191,175,15,63,192,12,24,0,176,175, - 9,0,64,26,33,128,0,0,0,0,37,146, - 1,0,49,38,220,128,132,39,15,63,192,12, - 1,0,16,38,42,16,18,2,249,255,64,20, - 0,0,0,0,228,128,132,39,15,63,192,12, - 0,0,0,0,36,0,191,143,32,0,178,143, - 28,0,177,143,24,0,176,143,8,0,224,3, - 40,0,189,39,48,255,189,39,33,56,128,0, - 192,0,178,175,33,144,160,0,200,0,180,175, - 33,160,192,0,255,255,226,36,6,0,66,44, - 204,0,191,175,196,0,179,175,188,0,177,175, - 2,0,64,20,184,0,176,175,1,0,7,36, - 2,0,64,30,0,0,0,0,1,0,18,36, - 2,0,128,30,64,18,7,0,60,0,20,36, - 2,131,3,60,192,246,99,36,33,136,67,0, - 4,0,34,142,0,0,0,0,4,0,64,20, - 33,152,64,2,1,0,4,36,133,29,192,12, - 33,40,224,0,255,31,4,60,255,255,132,52, - 0,128,133,54,120,0,162,39,36,16,68,0, - 0,160,3,60,37,16,67,0,104,0,165,175, - 108,0,160,175,112,0,162,175,12,0,2,36, - 80,0,160,167,82,0,162,167,80,0,162,39, - 36,16,68,0,37,128,67,0,104,0,162,39, - 36,16,68,0,232,128,132,143,37,16,67,0, - 84,0,176,175,88,0,162,175,92,0,160,175, - 5,0,128,16,4,0,2,36,82,0,162,167, - 255,255,2,36,92,0,165,175,88,0,162,175, - 44,0,34,142,0,0,0,0,0,0,66,148, - 0,0,0,0,0,32,66,48,7,0,64,20, - 33,40,0,0,255,255,4,36,2,131,5,60, - 184,142,165,36,188,7,192,12,208,1,6,36, - 33,40,0,0,44,0,34,142,33,48,0,0, - 4,0,80,172,44,0,36,142,208,7,7,36, - 129,67,192,12,2,0,132,36,12,0,64,20, - 0,0,0,0,44,0,34,142,0,0,0,0, - 2,0,69,148,2,131,4,60,15,63,192,12, - 108,142,132,36,255,255,4,36,2,131,5,60, - 184,142,165,36,188,7,192,12,216,1,6,36, - 34,11,192,12,1,0,4,36,0,163,16,60, - 4,1,16,142,0,163,2,60,4,1,66,140, - 0,0,0,0,252,255,2,18,0,33,3,36, - 44,0,34,142,0,0,0,0,2,0,67,164, - 8,0,34,142,0,0,0,0,0,0,64,172, - 0,163,16,60,4,1,16,142,44,0,36,142, - 0,0,0,0,4,0,130,140,0,0,0,0, - 0,0,66,148,0,0,0,0,0,128,66,48, - 10,0,64,20,0,0,0,0,44,0,35,142, - 0,0,0,0,4,0,98,140,0,0,0,0, - 0,0,66,148,0,0,0,0,0,128,66,48, - 250,255,64,16,0,0,0,0,255,255,115,38, - 19,0,96,18,33,40,64,2,44,0,35,142, - 0,0,0,0,4,0,98,140,0,0,0,0, - 0,0,66,148,0,0,0,0,0,128,66,48, - 229,255,64,16,0,0,0,0,4,0,98,140, - 0,0,0,0,0,0,66,148,0,0,0,0, - 0,128,66,48,250,255,64,20,0,0,0,0, - 89,32,192,8,0,0,0,0,2,131,4,60, - 200,142,132,36,33,48,128,2,0,163,3,60, - 4,1,99,140,0,128,2,52,82,0,162,167, - 35,128,112,0,15,63,192,12,33,56,0,2, - 19,0,0,18,64,41,18,0,35,40,178,0, - 128,40,5,0,33,40,178,0,192,40,5,0, - 26,0,176,0,2,0,0,22,0,0,0,0, - 13,0,7,0,255,255,1,36,4,0,1,22, - 0,128,1,60,2,0,161,20,0,0,0,0, - 13,0,6,0,18,40,0,0,236,128,132,39, - 15,63,192,12,0,0,0,0,204,0,191,143, - 200,0,180,143,196,0,179,143,192,0,178,143, - 188,0,177,143,184,0,176,143,8,0,224,3, - 208,0,189,39,224,255,189,39,20,0,177,175, - 33,136,128,0,24,0,191,175,180,10,192,12, - 16,0,176,175,34,11,192,12,1,0,4,36, - 16,133,132,143,0,163,16,60,4,1,16,142, - 193,63,192,12,0,0,0,0,0,163,2,60, - 4,1,66,140,0,0,0,0,35,40,80,0, - 73,252,162,36,99,0,66,44,4,0,64,16, - 0,0,0,0,2,131,4,60,196,32,192,8, - 0,143,132,36,5,0,160,20,0,0,0,0, - 2,131,4,60,36,143,132,36,196,32,192,8, - 33,40,0,0,2,131,4,60,76,143,132,36, - 15,63,192,12,1,0,16,36,3,0,48,18, - 0,0,0,0,34,11,192,12,33,32,0,0, - 0,129,144,175,24,0,191,143,20,0,177,143, - 16,0,176,143,8,0,224,3,32,0,189,39, - 200,255,189,39,32,0,178,175,33,144,128,0, - 33,48,64,2,44,0,181,175,1,131,21,60, - 60,252,181,38,33,56,160,2,40,0,180,175, - 2,131,20,60,144,143,148,38,36,0,179,175, - 0,163,19,60,120,1,115,142,0,163,3,60, - 120,1,99,140,32,131,2,60,48,0,191,175, - 28,0,177,175,24,0,176,175,16,0,180,175, - 33,32,96,2,35,136,67,0,84,64,192,12, - 33,40,32,2,3,0,64,18,33,128,64,0, - 10,0,0,22,0,0,0,0,16,0,180,175, - 33,32,96,2,33,40,32,2,33,48,64,2, - 244,63,192,12,33,56,160,2,33,128,2,2, - 5,0,0,18,33,40,96,2,2,131,4,60, - 168,143,132,36,252,32,192,8,33,40,96,2, - 2,131,4,60,204,143,132,36,15,63,192,12, - 33,48,177,0,48,0,191,143,44,0,181,143, - 40,0,180,143,36,0,179,143,32,0,178,143, - 28,0,177,143,24,0,176,143,8,0,224,3, - 56,0,189,39,0,163,1,60,232,5,36,172, - 0,163,1,60,8,0,224,3,236,5,37,172, - 28,129,132,175,8,0,224,3,0,0,0,0, - 16,129,132,175,8,0,224,3,0,0,0,0, - 15,0,132,48,20,129,132,175,8,0,224,3, - 0,0,0,0,24,129,132,175,8,0,224,3, - 0,0,0,0,32,129,132,175,8,0,224,3, - 0,0,0,0,33,72,128,0,33,80,160,0, - 33,88,192,0,7,162,4,60,48,1,132,52, - 7,162,8,60,0,1,8,53,20,129,130,143, - 24,129,131,143,128,48,2,0,28,129,130,143, - 3,0,197,52,2,0,96,16,0,0,130,172, - 67,0,197,52,16,129,130,143,0,0,0,0, - 2,0,64,16,33,24,160,0,0,1,99,52, - 36,129,130,143,0,0,0,0,2,0,64,16, - 0,0,0,0,0,4,99,52,32,129,130,143, - 0,0,3,173,3,0,64,16,7,162,5,60, - 0,0,2,173,7,162,5,60,4,1,165,52, - 7,162,6,60,8,1,198,52,255,0,2,60, - 255,255,66,52,7,162,3,60,12,1,99,52, - 7,162,4,60,16,1,132,52,36,16,66,1, - 0,0,169,172,0,0,194,172,43,16,7,0, - 192,16,2,0,0,0,107,172,8,0,224,3, - 0,0,130,172,7,162,3,60,40,1,99,52, - 3,0,2,36,0,163,1,60,20,1,32,172, - 8,0,224,3,0,0,98,172,232,255,189,39, - 16,0,191,175,33,24,0,0,7,162,6,60, - 40,1,198,52,15,0,4,60,63,66,132,52, - 0,0,197,140,0,0,0,0,16,0,162,48, - 7,0,64,20,1,0,99,36,42,16,131,0, - 249,255,64,16,0,0,0,0,2,131,4,60, - 122,33,192,8,240,143,132,36,36,129,130,143, - 0,0,0,0,3,0,64,20,33,24,0,0, - 125,33,192,8,33,16,0,0,1,0,5,36, - 15,0,4,60,63,66,132,52,0,163,2,60, - 20,1,66,140,0,0,0,0,247,255,69,16, - 1,0,99,36,42,16,131,0,249,255,64,16, - 0,0,0,0,0,163,5,60,20,1,165,140, - 2,131,4,60,24,144,132,36,15,63,192,12, - 0,0,0,0,1,0,2,36,16,0,191,143, - 24,0,189,39,8,0,224,3,0,0,0,0, - 224,255,189,39,24,0,191,175,33,72,192,0, - 255,31,3,60,255,255,99,52,33,64,0,0, - 36,32,131,0,0,160,2,60,37,32,130,0, - 36,40,163,0,16,0,32,25,37,40,162,0, - 0,0,134,144,0,0,167,144,0,0,0,0, - 7,0,199,16,1,0,165,36,2,131,4,60, - 72,144,132,36,15,63,192,12,33,40,0,1, - 157,33,192,8,1,0,2,36,1,0,8,37, - 42,16,9,1,242,255,64,20,1,0,132,36, - 33,16,0,0,24,0,191,143,32,0,189,39, - 8,0,224,3,0,0,0,0,0,163,2,60, - 232,5,66,140,152,255,189,39,80,0,180,175, - 120,0,180,143,64,0,176,175,33,128,160,0, - 68,0,177,175,33,136,192,0,72,0,178,175, - 33,144,224,0,100,0,191,175,96,0,190,175, - 92,0,183,175,88,0,182,175,84,0,181,175, - 76,0,179,175,12,0,64,16,16,0,164,175, - 0,163,2,60,236,5,66,140,0,0,0,0, - 7,0,64,16,0,0,0,0,0,163,2,60, - 236,5,66,140,0,0,0,0,1,8,66,44, - 10,0,64,20,16,0,2,60,0,163,5,60, - 232,5,165,140,0,163,6,60,236,5,198,140, - 2,131,4,60,15,63,192,12,124,144,132,36, - 7,35,192,8,0,0,0,0,16,0,168,143, - 0,0,0,0,43,16,72,0,6,0,64,16, - 0,0,0,0,2,131,4,60,15,63,192,12, - 172,144,132,36,7,35,192,8,0,0,0,0, - 224,132,130,143,0,0,0,0,11,0,64,20, - 0,0,0,0,0,163,4,60,236,5,132,140, - 13,8,192,12,0,0,0,0,255,31,3,60, - 255,255,99,52,36,16,67,0,0,160,3,60, - 37,16,67,0,224,132,130,175,228,132,130,143, - 0,0,0,0,11,0,64,20,0,0,0,0, - 0,163,4,60,236,5,132,140,13,8,192,12, - 0,0,0,0,255,31,3,60,255,255,99,52, - 36,16,67,0,0,160,3,60,37,16,67,0, - 228,132,130,175,224,132,133,143,0,163,6,60, - 232,5,198,140,228,132,135,143,2,131,4,60, - 15,63,192,12,208,144,132,36,16,129,133,143, - 20,129,134,143,2,131,4,60,15,63,192,12, - 8,145,132,36,7,162,2,60,232,0,66,52, - 0,0,83,140,1,0,3,130,105,0,2,36, - 7,0,98,20,251,255,2,60,1,0,2,36, - 36,129,130,175,4,0,2,60,0,8,66,52, - 10,34,192,8,37,152,98,2,36,129,128,175, - 255,247,66,52,36,152,98,2,7,162,2,60, - 232,0,66,52,0,0,83,172,0,0,5,130, - 114,0,2,36,3,0,162,16,82,0,2,36, - 3,0,162,20,119,0,2,36,42,34,192,8, - 33,176,0,0,3,0,162,16,87,0,2,36, - 3,0,162,20,108,0,2,36,42,34,192,8, - 1,0,22,36,3,0,162,16,76,0,2,36, - 3,0,162,20,116,0,2,36,42,34,192,8, - 2,0,22,36,118,0,162,16,84,0,2,36, - 116,0,162,16,0,0,0,0,2,131,4,60, - 15,63,192,12,52,145,132,36,7,35,192,8, - 0,0,0,0,0,0,38,130,0,0,0,0, - 12,0,192,16,99,0,2,36,3,0,194,16, - 67,0,2,36,4,0,194,20,33,152,0,0, - 5,0,19,36,61,34,192,8,5,0,21,36, - 2,131,1,60,80,155,50,160,61,34,192,8, - 33,168,0,0,33,168,0,0,5,0,19,36, - 2,131,1,60,80,155,32,160,16,0,168,143, - 0,163,18,60,236,5,82,142,0,0,0,0, - 197,0,0,17,255,255,20,37,255,255,194,38, - 2,0,87,44,2,0,30,36,33,128,160,2, - 42,16,112,2,73,0,64,20,0,0,0,0, - 42,0,224,18,5,0,2,36,13,0,2,22, - 0,0,0,0,25,0,64,26,33,136,0,0, - 224,132,130,143,0,0,0,0,33,16,81,0, - 0,0,81,160,1,0,49,38,42,16,50,2, - 249,255,64,20,33,48,64,2,105,34,192,8, - 0,0,0,0,2,131,3,60,33,24,112,0, - 80,155,99,144,0,0,0,0,9,0,64,26, - 33,136,0,0,224,132,130,143,0,0,0,0, - 33,16,81,0,1,0,49,38,0,0,67,160, - 42,16,50,2,249,255,64,20,0,0,0,0, - 33,48,64,2,0,163,4,60,232,5,132,140, - 224,132,133,143,0,0,0,0,28,33,192,12, - 1,0,7,36,76,33,192,12,0,0,0,0, - 83,33,192,12,0,0,0,0,147,0,64,20, - 0,0,0,0,3,0,192,18,33,48,64,2, - 22,0,222,22,0,0,0,0,0,163,4,60, - 232,5,132,140,228,132,133,143,0,0,0,0, - 28,33,192,12,33,56,0,0,76,33,192,12, - 0,0,0,0,83,33,192,12,0,0,0,0, - 131,0,64,20,0,0,0,0,8,0,222,22, - 0,0,0,0,224,132,132,143,228,132,133,143, - 0,0,0,0,129,33,192,12,33,48,64,2, - 122,0,64,20,0,0,0,0,1,0,16,38, - 42,16,112,2,185,255,64,16,0,0,0,0, - 255,255,148,38,255,255,2,36,178,255,130,22, - 33,128,160,2,7,35,192,8,0,0,0,0, - 180,10,192,12,0,0,0,0,34,11,192,12, - 1,0,4,36,0,0,34,130,0,0,0,0, - 6,0,64,16,33,184,0,0,24,0,160,175, - 2,131,1,60,88,155,52,164,171,34,192,8, - 33,176,0,0,6,0,23,36,4,0,2,36, - 24,0,160,175,2,131,1,60,88,155,34,164, - 33,176,0,0,0,8,30,36,24,0,177,143, - 0,0,0,0,42,16,241,2,83,0,64,20, - 64,16,17,0,2,131,8,60,88,155,8,37, - 33,168,72,0,0,0,178,150,0,0,0,0, - 26,0,210,3,2,0,64,22,0,0,0,0, - 13,0,7,0,255,255,1,36,4,0,65,22, - 0,128,1,60,2,0,193,23,0,0,0,0, - 13,0,6,0,18,16,0,0,16,0,168,143, - 0,0,0,0,24,0,72,0,33,56,192,2, - 33,128,0,0,0,163,19,60,4,1,115,142, - 0,163,4,60,232,5,132,140,224,132,133,143, - 18,160,0,0,0,0,0,0,0,0,0,0, - 28,33,192,12,33,48,64,2,10,0,128,26, - 0,0,0,0,76,33,192,12,0,0,0,0, - 83,33,192,12,0,0,0,0,48,0,64,20, - 1,0,16,38,42,16,20,2,248,255,64,20, - 0,0,0,0,2,131,5,60,140,145,165,36, - 0,163,16,60,4,1,16,142,3,0,192,18, - 0,0,0,0,2,131,5,60,128,145,165,36, - 2,131,4,60,96,145,132,36,15,63,192,12, - 33,48,64,2,19,0,19,18,24,0,146,2, - 18,24,0,0,35,16,19,2,0,0,0,0, - 27,0,98,0,2,0,64,20,0,0,0,0, - 13,0,7,0,18,16,0,0,2,131,4,60, - 152,145,132,36,64,41,2,0,35,40,162,0, - 128,40,5,0,33,40,162,0,15,63,192,12, - 192,40,5,0,255,34,192,8,2,0,181,38, - 2,131,4,60,168,145,132,36,15,63,192,12, - 2,0,181,38,1,0,49,38,42,16,241,2, - 178,255,64,16,0,0,0,0,1,0,214,38, - 2,0,194,42,166,255,64,20,0,0,0,0, - 100,0,191,143,96,0,190,143,92,0,183,143, - 88,0,182,143,84,0,181,143,80,0,180,143, - 76,0,179,143,72,0,178,143,68,0,177,143, - 64,0,176,143,8,0,224,3,104,0,189,39, - 0,0,0,0,43,16,134,0,0,0,164,175, - 4,0,165,175,8,0,166,175,7,0,64,20, - 12,0,167,175,43,16,196,0,5,0,64,20, - 1,0,2,36,43,16,167,0,2,0,64,16, - 43,16,229,0,255,255,2,36,8,0,224,3, - 0,0,0,0,232,255,189,39,3,131,4,60, - 208,12,132,36,170,0,5,36,16,0,191,175, - 144,71,192,12,60,0,6,36,2,131,6,60, - 112,155,198,36,2,131,2,60,212,246,66,140, - 2,131,3,60,216,246,99,132,0,0,194,172, - 4,0,195,164,2,131,2,60,138,155,66,148, - 2,131,3,60,132,155,99,148,2,131,4,60, - 134,155,132,148,2,131,5,60,136,155,165,148, - 3,131,1,60,216,12,34,164,2,131,2,60, - 130,155,66,148,3,131,10,60,218,12,74,37, - 3,0,199,136,0,0,199,152,4,0,200,128, - 5,0,201,128,3,0,71,169,0,0,71,185, - 4,0,72,161,5,0,73,161,3,131,1,60, - 238,12,35,164,3,131,1,60,242,12,36,164, - 3,131,1,60,246,12,37,164,3,131,1,60, - 240,12,34,164,16,0,191,143,24,0,189,39, - 8,0,224,3,0,0,0,0,3,131,2,60, - 216,12,66,140,3,131,3,60,220,12,99,140, - 3,131,1,60,208,12,34,172,3,131,1,60, - 212,12,35,172,3,131,2,60,238,12,66,148, - 3,131,3,60,240,12,99,148,3,131,4,60, - 242,12,132,148,232,255,189,39,16,0,176,175, - 3,131,1,60,234,12,35,164,24,133,131,143, - 20,0,191,175,3,131,1,60,224,12,32,172, - 3,131,1,60,228,12,32,172,3,131,1,60, - 248,12,32,172,3,131,1,60,252,12,32,172, - 3,131,1,60,8,13,32,164,3,131,1,60, - 4,13,32,164,3,131,1,60,232,12,34,164, - 33,16,68,0,3,131,1,60,236,12,36,164, - 3,131,1,60,244,12,34,164,8,0,96,24, - 1,0,16,36,150,35,192,12,33,32,0,2, - 24,133,130,143,1,0,16,38,42,16,80,0, - 250,255,64,16,0,0,0,0,206,35,192,12, - 0,0,0,0,52,36,192,12,0,0,0,0, - 1,0,2,36,3,131,1,60,0,13,34,164, - 3,0,2,36,3,131,1,60,2,13,32,164, - 3,131,1,60,20,13,34,172,2,131,1,60, - 164,247,34,172,20,0,191,143,16,0,176,143, - 8,0,224,3,24,0,189,39,224,255,189,39, - 20,0,177,175,33,136,128,0,16,0,176,175, - 192,129,17,0,3,131,4,60,16,13,132,36, - 33,32,4,2,187,0,5,36,24,0,191,175, - 144,71,192,12,128,0,6,36,2,131,2,60, - 140,155,66,148,100,0,3,36,3,131,1,60, - 33,8,48,0,24,13,35,172,0,18,2,0, - 37,16,34,2,3,131,1,60,33,8,48,0, - 16,13,34,164,22,36,192,12,33,32,32,2, - 4,0,2,36,64,138,17,0,3,131,1,60, - 33,8,48,0,20,13,34,172,2,131,1,60, - 33,8,49,0,164,247,34,172,3,131,1,60, - 33,8,48,0,52,13,32,172,3,131,1,60, - 33,8,48,0,56,13,32,172,3,131,1,60, - 33,8,48,0,106,13,32,164,3,131,1,60, - 33,8,48,0,110,13,32,164,3,131,1,60, - 33,8,48,0,114,13,32,164,3,131,1,60, - 33,8,48,0,120,13,32,172,24,0,191,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 32,0,189,39,24,133,130,143,216,255,189,39, - 20,0,177,175,1,0,17,36,36,0,191,175, - 32,0,180,175,28,0,179,175,24,0,178,175, - 55,0,64,24,16,0,176,175,3,131,20,60, - 228,12,148,38,3,131,2,60,56,13,66,36, - 128,0,83,36,124,0,82,36,128,0,16,36, - 0,0,130,142,0,0,0,0,6,0,34,22, - 33,32,32,2,0,0,64,174,101,36,192,12, - 0,0,96,174,8,36,192,8,128,0,115,38, - 3,131,4,60,33,32,144,0,40,13,132,140, - 3,131,5,60,33,40,176,0,44,13,165,140, - 244,255,134,142,248,255,135,142,20,35,192,12, - 0,0,0,0,17,0,64,20,33,32,32,2, - 3,131,3,60,33,24,112,0,48,13,99,148, - 3,131,2,60,33,16,80,0,16,13,66,148, - 0,0,0,0,8,0,98,20,0,0,0,0, - 3,131,1,60,33,8,48,0,106,13,32,164, - 101,36,192,12,33,32,32,2,8,36,192,8, - 128,0,115,38,0,0,64,174,125,36,192,12, - 0,0,96,174,128,0,115,38,128,0,82,38, - 24,133,130,143,1,0,49,38,42,16,81,0, - 210,255,64,16,128,0,16,38,36,0,191,143, - 32,0,180,143,28,0,179,143,24,0,178,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 40,0,189,39,192,33,4,0,3,131,2,60, - 28,13,66,36,33,24,130,0,3,131,5,60, - 208,12,165,140,3,131,6,60,212,12,198,140, - 0,0,101,172,4,0,102,172,12,0,66,36, - 3,131,3,60,224,12,99,140,33,16,130,0, - 3,131,1,60,33,8,36,0,36,13,35,172, - 3,131,3,60,216,12,99,140,3,131,5,60, - 220,12,165,140,0,0,67,172,4,0,69,172, - 3,131,2,60,33,16,68,0,16,13,66,148, - 3,131,1,60,33,8,36,0,8,0,224,3, - 48,13,34,164,24,133,130,143,224,255,189,39, - 20,0,177,175,1,0,17,36,24,0,191,175, - 38,0,64,24,16,0,176,175,128,0,16,36, - 3,131,4,60,33,32,144,0,40,13,132,140, - 3,131,5,60,33,40,176,0,44,13,165,140, - 3,131,6,60,216,12,198,140,3,131,7,60, - 220,12,231,140,20,35,192,12,0,0,0,0, - 18,0,64,20,0,0,0,0,3,131,3,60, - 33,24,112,0,48,13,99,148,3,131,2,60, - 33,16,80,0,16,13,66,148,0,0,0,0, - 9,0,98,20,0,0,0,0,3,131,2,60, - 33,16,80,0,20,13,66,140,0,0,0,0, - 3,0,64,16,0,0,0,0,203,36,192,12, - 33,32,32,2,24,133,130,143,1,0,49,38, - 42,16,81,0,221,255,64,16,128,0,16,38, - 24,0,191,143,20,0,177,143,16,0,176,143, - 8,0,224,3,32,0,189,39,192,41,4,0, - 3,131,3,60,33,24,101,0,20,13,99,140, - 4,0,2,36,16,0,98,20,240,255,189,39, - 1,0,2,36,64,26,4,0,3,131,1,60, - 33,8,37,0,20,13,34,172,2,131,1,60, - 33,8,35,0,164,247,34,172,1,0,2,36, - 3,131,1,60,33,8,37,0,110,13,34,164, - 3,131,1,60,33,8,37,0,112,13,32,164, - 8,0,224,3,16,0,189,39,224,255,189,39, - 24,0,178,175,33,144,128,0,16,0,176,175, - 192,129,18,0,28,0,191,175,20,0,177,175, - 3,131,2,60,33,16,80,0,20,13,66,140, - 0,0,0,0,18,0,64,16,4,0,17,36, - 16,0,81,16,254,255,66,36,2,0,66,44, - 4,0,64,16,64,18,18,0,161,36,192,12, - 0,0,0,0,64,18,18,0,3,131,1,60, - 33,8,48,0,20,13,49,172,2,131,1,60, - 33,8,34,0,164,247,49,172,3,131,1,60, - 33,8,48,0,110,13,32,164,28,0,191,143, - 24,0,178,143,20,0,177,143,16,0,176,143, - 8,0,224,3,32,0,189,39,3,131,4,60, - 208,12,132,140,3,131,5,60,212,12,165,140, - 3,131,6,60,216,12,198,140,3,131,7,60, - 220,12,231,140,232,255,189,39,16,0,191,175, - 20,35,192,12,0,0,0,0,10,0,64,20, - 1,0,2,36,3,131,1,60,252,12,34,172, - 1,0,2,36,3,131,1,60,4,13,34,164, - 3,131,1,60,6,13,32,164,197,36,192,8, - 1,0,2,36,3,131,2,60,248,12,66,140, - 0,0,0,0,9,0,64,20,1,0,2,36, - 72,37,192,12,0,0,0,0,1,0,2,36, - 3,131,1,60,8,13,34,164,3,131,1,60, - 10,13,32,164,1,0,2,36,3,131,1,60, - 248,12,34,172,16,0,191,143,24,0,189,39, - 8,0,224,3,0,0,0,0,224,255,189,39, - 20,0,177,175,33,136,128,0,16,0,176,175, - 192,129,17,0,24,0,191,175,3,131,2,60, - 33,16,80,0,114,13,66,132,0,0,0,0, - 5,0,64,16,1,0,2,36,3,131,1,60, - 33,8,48,0,67,37,192,8,56,13,34,172, - 3,131,4,60,208,12,132,36,3,131,2,60, - 64,13,66,36,33,24,2,2,3,131,1,60, - 33,8,48,0,60,13,32,164,0,0,133,140, - 4,0,134,140,0,0,101,172,4,0,102,172, - 12,0,66,36,3,131,3,60,224,12,99,140, - 33,16,2,2,3,131,1,60,33,8,48,0, - 72,13,35,172,3,131,3,60,216,12,99,140, - 3,131,5,60,220,12,165,140,0,0,67,172, - 4,0,69,172,3,131,2,60,33,16,80,0, - 16,13,66,148,3,131,1,60,33,8,48,0, - 84,13,34,164,0,0,132,140,3,131,5,60, - 212,12,165,140,3,131,6,60,216,12,198,140, - 3,131,7,60,220,12,231,140,20,35,192,12, - 0,0,0,0,5,0,64,20,0,0,0,0, - 3,131,1,60,33,8,48,0,22,37,192,8, - 86,13,32,164,3,131,2,60,228,12,66,140, - 2,131,3,60,128,155,99,148,192,17,2,0, - 3,131,1,60,33,8,34,0,108,13,34,148, - 0,0,0,0,33,16,67,0,3,131,1,60, - 33,8,48,0,86,13,34,164,3,131,2,60, - 232,12,66,148,192,129,17,0,3,131,1,60, - 33,8,48,0,88,13,34,164,3,131,2,60, - 234,12,66,148,33,32,32,2,3,131,1,60, - 33,8,48,0,90,13,34,164,3,131,3,60, - 236,12,99,148,3,131,2,60,33,16,80,0, - 52,13,66,140,3,131,5,60,60,13,165,36, - 3,131,1,60,33,8,48,0,52,13,32,172, - 3,131,1,60,33,8,48,0,96,13,34,172, - 3,131,1,60,33,8,48,0,92,13,35,164, - 3,131,2,60,252,12,66,140,3,131,1,60, - 33,8,48,0,100,13,34,172,80,40,192,12, - 33,40,5,2,1,0,2,36,3,131,1,60, - 33,8,48,0,56,13,32,172,3,131,1,60, - 33,8,48,0,114,13,34,164,3,131,1,60, - 33,8,48,0,116,13,32,164,24,0,191,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 32,0,189,39,232,255,189,39,128,0,2,36, - 3,131,4,60,228,12,132,140,3,131,5,60, - 104,13,165,36,16,0,191,175,192,25,4,0, - 3,131,1,60,33,8,35,0,104,13,34,164, - 151,40,192,12,33,40,101,0,2,131,4,60, - 15,63,192,12,12,146,132,36,16,0,191,143, - 24,0,189,39,8,0,224,3,0,0,0,0, - 232,255,189,39,16,0,191,175,102,37,192,12, - 0,0,0,0,13,38,192,12,0,0,0,0, - 16,0,191,143,24,0,189,39,8,0,224,3, - 0,0,0,0,24,133,130,143,208,255,189,39, - 24,0,178,175,33,144,0,0,28,0,179,175, - 1,0,19,36,44,0,191,175,40,0,182,175, - 36,0,181,175,32,0,180,175,20,0,177,175, - 110,0,64,24,16,0,176,175,3,131,21,60, - 216,12,181,38,3,131,22,60,16,13,214,38, - 128,0,208,38,128,0,20,36,192,17,18,0, - 3,131,4,60,33,32,148,0,40,13,132,140, - 3,131,5,60,33,40,180,0,44,13,165,140, - 0,0,166,142,3,131,7,60,220,12,231,140, - 0,0,0,0,20,35,192,12,33,136,86,0, - 10,0,64,20,0,0,0,0,3,131,3,60, - 33,24,116,0,48,13,99,148,3,131,2,60, - 33,16,84,0,16,13,66,148,0,0,0,0, - 74,0,98,16,0,0,0,0,4,0,2,142, - 0,0,0,0,70,0,64,16,0,0,0,0, - 12,0,4,142,16,0,5,142,0,0,166,142, - 3,131,7,60,220,12,231,140,20,35,192,12, - 0,0,0,0,61,0,65,4,0,0,0,0, - 58,0,64,18,0,0,0,0,12,0,4,142, - 16,0,5,142,12,0,38,142,16,0,39,142, - 20,35,192,12,0,0,0,0,50,0,64,4, - 0,0,0,0,12,0,4,142,16,0,5,142, - 12,0,38,142,16,0,39,142,20,35,192,12, - 0,0,0,0,43,0,64,20,0,0,0,0, - 20,0,5,142,8,0,3,142,20,0,36,142, - 8,0,34,142,33,40,163,0,33,32,130,0, - 43,16,164,0,33,0,64,20,0,0,0,0, - 32,0,164,20,0,0,0,0,24,0,4,142, - 28,0,5,142,24,0,38,142,28,0,39,142, - 20,35,192,12,0,0,0,0,23,0,64,4, - 0,0,0,0,24,0,4,142,28,0,5,142, - 24,0,38,142,28,0,39,142,20,35,192,12, - 0,0,0,0,16,0,64,20,0,0,0,0, - 32,0,4,150,32,0,35,150,0,0,0,0, - 43,16,131,0,9,0,64,20,0,0,0,0, - 8,0,131,20,0,0,0,0,0,0,2,150, - 0,0,35,150,0,0,0,0,43,16,67,0, - 2,0,64,16,0,0,0,0,33,144,96,2, - 128,0,16,38,24,133,130,143,1,0,115,38, - 42,16,83,0,154,255,64,16,128,0,148,38, - 3,131,1,60,228,12,50,172,12,0,64,22, - 192,17,18,0,3,131,2,60,216,12,66,140, - 3,131,3,60,220,12,99,140,3,131,1,60, - 208,12,34,172,3,131,1,60,212,12,35,172, - 3,131,1,60,3,38,192,8,224,12,32,172, - 3,131,3,60,33,24,98,0,28,13,99,140, - 3,131,4,60,33,32,130,0,32,13,132,140, - 3,131,1,60,208,12,35,172,3,131,1,60, - 212,12,36,172,3,131,3,60,33,24,98,0, - 36,13,99,140,3,131,1,60,33,8,34,0, - 24,13,34,140,0,0,0,0,33,24,98,0, - 3,131,1,60,224,12,35,172,44,0,191,143, - 40,0,182,143,36,0,181,143,32,0,180,143, - 28,0,179,143,24,0,178,143,20,0,177,143, - 16,0,176,143,8,0,224,3,48,0,189,39, - 24,133,130,143,208,255,189,39,36,0,181,175, - 1,0,21,36,44,0,191,175,40,0,182,175, - 32,0,180,175,28,0,179,175,24,0,178,175, - 20,0,177,175,82,0,64,24,16,0,176,175, - 3,131,22,60,216,12,214,38,3,131,2,60, - 48,13,66,36,128,0,84,36,96,0,83,36, - 124,0,82,36,120,0,81,36,128,0,16,36, - 0,0,36,142,0,0,69,142,0,0,198,142, - 3,131,7,60,220,12,231,140,20,35,192,12, - 0,0,0,0,55,0,64,20,0,0,0,0, - 0,0,131,150,0,0,98,150,0,0,0,0, - 50,0,98,20,0,0,0,0,3,131,4,60, - 33,32,144,0,28,13,132,140,3,131,5,60, - 33,40,176,0,32,13,165,140,248,255,198,142, - 3,131,7,60,212,12,231,140,20,35,192,12, - 0,0,0,0,37,0,64,16,0,0,0,0, - 8,0,196,142,3,131,3,60,33,24,112,0, - 36,13,99,140,0,0,0,0,43,16,131,0, - 29,0,64,20,0,0,0,0,27,0,131,20, - 0,0,0,0,0,0,196,142,3,131,5,60, - 220,12,165,140,0,0,38,142,0,0,71,142, - 20,35,192,12,0,0,0,0,16,0,64,4, - 0,0,0,0,0,0,196,142,3,131,5,60, - 220,12,165,140,0,0,38,142,0,0,71,142, - 20,35,192,12,0,0,0,0,9,0,64,20, - 0,0,0,0,0,0,99,150,0,0,130,150, - 0,0,0,0,43,16,67,0,3,0,64,20, - 0,0,0,0,22,36,192,12,33,32,160,2, - 128,0,148,38,128,0,115,38,128,0,82,38, - 128,0,49,38,24,133,130,143,1,0,181,38, - 42,16,85,0,185,255,64,16,128,0,16,38, - 44,0,191,143,40,0,182,143,36,0,181,143, - 32,0,180,143,28,0,179,143,24,0,178,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 48,0,189,39,216,255,189,39,3,131,4,60, - 0,13,132,36,32,0,191,175,28,0,179,175, - 24,0,178,175,20,0,177,175,16,0,176,175, - 0,0,130,132,0,0,0,0,14,0,64,16, - 0,0,0,0,3,131,2,60,2,13,66,148, - 3,131,3,60,234,12,99,148,1,0,66,36, - 3,131,1,60,2,13,34,164,255,255,66,48, - 43,16,67,0,3,0,64,20,0,0,0,0, - 11,39,192,12,0,0,128,164,3,131,4,60, - 8,13,132,36,0,0,130,132,0,0,0,0, - 14,0,64,16,0,0,0,0,3,131,2,60, - 10,13,66,148,3,131,3,60,234,12,99,148, - 1,0,66,36,3,131,1,60,10,13,34,164, - 255,255,66,48,43,16,67,0,3,0,64,20, - 0,0,0,0,24,39,192,12,0,0,128,164, - 3,131,4,60,4,13,132,36,0,0,130,132, - 0,0,0,0,14,0,64,16,0,0,0,0, - 3,131,2,60,6,13,66,148,3,131,3,60, - 244,12,99,148,1,0,66,36,3,131,1,60, - 6,13,34,164,255,255,66,48,43,16,67,0, - 3,0,64,20,0,0,0,0,37,39,192,12, - 0,0,128,164,24,133,130,143,0,0,0,0, - 78,0,64,24,1,0,17,36,3,131,2,60, - 16,13,66,36,226,0,83,36,128,0,82,36, - 128,0,16,36,3,131,2,60,33,16,80,0, - 110,13,66,132,0,0,0,0,18,0,64,16, - 0,0,0,0,3,131,2,60,33,16,80,0, - 112,13,66,148,0,0,0,0,1,0,66,36, - 96,0,66,166,3,131,3,60,236,12,99,148, - 255,255,66,48,43,16,67,0,6,0,64,20, - 0,0,0,0,3,131,1,60,33,8,48,0, - 110,13,32,164,79,39,192,12,33,32,32,2, - 3,131,2,60,33,16,80,0,106,13,66,132, - 0,0,0,0,18,0,64,16,0,0,0,0, - 3,131,2,60,33,16,80,0,108,13,66,148, - 0,0,0,0,1,0,66,36,92,0,66,166, - 3,131,3,60,232,12,99,148,255,255,66,48, - 43,16,67,0,6,0,64,20,0,0,0,0, - 3,131,1,60,33,8,48,0,106,13,32,164, - 129,39,192,12,33,32,32,2,0,0,98,134, - 0,0,0,0,16,0,64,16,0,0,0,0, - 3,131,2,60,33,16,80,0,116,13,66,148, - 0,0,0,0,1,0,66,36,100,0,66,166, - 3,131,3,60,246,12,99,148,255,255,66,48, - 43,16,67,0,4,0,64,20,0,0,0,0, - 0,0,96,166,191,39,192,12,33,32,32,2, - 128,0,115,38,128,0,82,38,24,133,130,143, - 1,0,49,38,42,16,81,0,185,255,64,16, - 128,0,16,38,32,0,191,143,28,0,179,143, - 24,0,178,143,20,0,177,143,16,0,176,143, - 8,0,224,3,40,0,189,39,232,255,189,39, - 16,0,191,175,52,36,192,12,0,0,0,0, - 1,0,2,36,3,131,1,60,0,13,34,164, - 3,131,1,60,2,13,32,164,16,0,191,143, - 24,0,189,39,8,0,224,3,0,0,0,0, - 232,255,189,39,16,0,191,175,72,37,192,12, - 0,0,0,0,1,0,2,36,3,131,1,60, - 8,13,34,164,3,131,1,60,10,13,32,164, - 16,0,191,143,24,0,189,39,8,0,224,3, - 0,0,0,0,240,255,189,39,3,131,1,60, - 248,12,32,172,3,131,1,60,252,12,32,172, - 8,0,224,3,16,0,189,39,24,133,130,143, - 224,255,189,39,20,0,177,175,1,0,17,36, - 24,0,191,175,23,0,64,24,16,0,176,175, - 128,0,16,36,3,131,4,60,33,32,144,0, - 40,13,132,140,3,131,5,60,33,40,176,0, - 44,13,165,140,3,131,6,60,216,12,198,140, - 3,131,7,60,220,12,231,140,20,35,192,12, - 0,0,0,0,3,0,64,20,1,0,49,38, - 74,39,192,8,1,0,2,36,24,133,130,143, - 0,0,0,0,42,16,81,0,236,255,64,16, - 128,0,16,38,33,16,0,0,24,0,191,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 32,0,189,39,232,255,189,39,192,41,4,0, - 16,0,191,175,3,131,3,60,33,24,101,0, - 20,13,99,140,1,0,2,36,16,0,98,20, - 2,0,2,36,64,26,4,0,3,131,1,60, - 33,8,37,0,20,13,34,172,2,131,1,60, - 33,8,35,0,164,247,34,172,1,0,2,36, - 3,131,1,60,33,8,37,0,110,13,34,164, - 3,131,1,60,33,8,37,0,125,39,192,8, - 112,13,32,164,21,0,98,20,3,0,3,36, - 64,18,4,0,3,131,1,60,33,8,37,0, - 20,13,35,172,2,131,1,60,33,8,34,0, - 164,247,35,172,3,131,2,60,33,16,69,0, - 120,13,66,140,0,0,0,0,1,0,66,36, - 3,131,1,60,33,8,37,0,44,39,192,12, - 120,13,34,172,3,0,64,16,0,0,0,0, - 161,36,192,12,0,0,0,0,16,0,191,143, - 24,0,189,39,8,0,224,3,0,0,0,0, - 224,255,189,39,16,0,176,175,33,128,128,0, - 20,0,177,175,3,131,17,60,208,12,49,38, - 24,0,191,175,0,0,36,142,3,131,5,60, - 212,12,165,140,3,131,6,60,216,12,198,140, - 3,131,7,60,220,12,231,140,20,35,192,12, - 0,0,0,0,33,32,0,2,22,36,192,12, - 1,0,80,44,92,37,192,12,0,0,0,0, - 206,35,192,12,0,0,0,0,33,0,0,22, - 0,0,0,0,0,0,36,142,3,131,5,60, - 212,12,165,140,3,131,6,60,216,12,198,140, - 3,131,7,60,220,12,231,140,20,35,192,12, - 0,0,0,0,22,0,64,20,0,0,0,0, - 3,131,2,60,238,12,66,148,3,131,3,60, - 240,12,99,148,3,131,4,60,242,12,132,148, - 3,131,1,60,232,12,34,164,3,131,1,60, - 234,12,35,164,3,131,1,60,161,36,192,12, - 236,12,36,164,3,131,1,60,52,36,192,12, - 8,13,32,164,1,0,2,36,3,131,1,60, - 0,13,34,164,3,131,1,60,2,13,32,164, - 24,0,191,143,20,0,177,143,16,0,176,143, - 8,0,224,3,32,0,189,39,232,255,189,39, - 192,17,4,0,16,0,191,175,3,131,1,60, - 33,8,34,0,56,13,34,140,0,0,0,0, - 3,0,64,16,0,0,0,0,203,36,192,12, - 0,0,0,0,16,0,191,143,24,0,189,39, - 8,0,224,3,0,0,0,0,3,131,1,60, - 248,12,32,172,3,131,1,60,8,0,224,3, - 8,13,32,164,232,255,189,39,192,25,4,0, - 1,0,2,36,16,0,191,175,3,131,1,60, - 33,8,35,0,203,36,192,12,52,13,34,172, - 16,0,191,143,24,0,189,39,8,0,224,3, - 0,0,0,0,192,33,4,0,3,131,2,60, - 28,13,66,36,33,24,130,0,4,0,166,140, - 8,0,167,140,0,0,102,172,4,0,103,172, - 12,0,66,36,12,0,163,140,33,16,130,0, - 3,131,1,60,33,8,36,0,36,13,35,172, - 16,0,163,140,20,0,166,140,0,0,67,172, - 4,0,70,172,24,0,163,148,1,0,2,36, - 3,131,1,60,33,8,36,0,106,13,34,164, - 3,131,1,60,33,8,36,0,48,13,35,164, - 26,0,162,148,3,131,1,60,33,8,36,0, - 8,0,224,3,108,13,34,164,28,0,130,148, - 3,131,1,60,232,12,34,164,30,0,130,148, - 3,131,1,60,234,12,34,164,32,0,130,148, - 3,131,1,60,236,12,34,164,40,0,130,140, - 3,131,1,60,8,0,224,3,252,12,34,172, - 224,255,189,39,16,0,176,175,33,128,160,0, - 192,25,4,0,3,131,2,60,16,13,66,36, - 20,0,177,175,33,136,98,0,24,0,191,175, - 4,0,4,142,8,0,5,142,12,0,38,142, - 16,0,39,142,20,35,192,12,0,0,0,0, - 48,0,64,4,1,0,2,36,4,0,4,142, - 8,0,5,142,12,0,38,142,16,0,39,142, - 20,35,192,12,0,0,0,0,40,0,64,20, - 33,16,0,0,12,0,4,142,20,0,35,142, - 0,0,0,0,43,16,131,0,34,0,64,20, - 1,0,2,36,32,0,131,20,33,16,0,0, - 16,0,4,142,20,0,5,142,24,0,38,142, - 28,0,39,142,20,35,192,12,0,0,0,0, - 24,0,64,4,1,0,2,36,16,0,4,142, - 20,0,5,142,24,0,38,142,28,0,39,142, - 20,35,192,12,0,0,0,0,16,0,64,20, - 33,16,0,0,16,0,4,142,20,0,5,142, - 3,131,6,60,216,12,198,140,3,131,7,60, - 220,12,231,140,20,35,192,12,0,0,0,0, - 6,0,64,20,1,0,2,36,24,0,3,150, - 32,0,34,150,0,0,0,0,43,16,67,0, - 1,0,66,56,24,0,191,143,20,0,177,143, - 16,0,176,143,8,0,224,3,32,0,189,39, - 44,133,130,143,216,255,189,39,20,0,177,175, - 33,136,128,0,32,0,180,175,33,160,160,0, - 36,0,191,175,28,0,179,175,24,0,178,175, - 53,0,64,16,16,0,176,175,2,131,19,60, - 192,4,115,38,33,32,96,2,54,21,192,12, - 1,0,5,36,33,128,64,0,8,0,0,22, - 64,26,17,0,2,131,2,60,33,16,67,0, - 176,247,66,140,33,24,99,2,1,0,66,36, - 143,40,192,8,240,242,98,172,8,0,4,142, - 64,146,17,0,20,242,101,38,33,40,69,2, - 172,41,192,12,33,48,128,2,33,24,64,0, - 60,0,98,40,2,0,64,16,0,242,98,38, - 60,0,3,36,33,136,66,2,33,32,32,2, - 33,40,0,2,1,0,2,36,17,0,2,162, - 0,128,98,52,0,0,2,174,6,23,192,12, - 18,0,3,166,10,0,64,20,33,32,0,2, - 2,131,2,60,33,16,82,0,172,247,66,140, - 0,0,0,0,1,0,66,36,152,21,192,12, - 236,0,34,174,143,40,192,8,0,0,0,0, - 2,131,2,60,33,16,82,0,168,247,66,140, - 0,0,0,0,1,0,66,36,232,0,34,174, - 36,0,191,143,32,0,180,143,28,0,179,143, - 24,0,178,143,20,0,177,143,16,0,176,143, - 8,0,224,3,40,0,189,39,44,133,130,143, - 216,255,189,39,20,0,177,175,33,136,128,0, - 32,0,180,175,33,160,160,0,36,0,191,175, - 28,0,179,175,24,0,178,175,53,0,64,16, - 16,0,176,175,2,131,19,60,192,4,115,38, - 33,32,96,2,54,21,192,12,1,0,5,36, - 33,128,64,0,8,0,0,22,64,26,17,0, - 2,131,2,60,33,16,67,0,176,247,66,140, - 33,24,99,2,1,0,66,36,214,40,192,8, - 240,242,98,172,8,0,4,142,64,146,17,0, - 20,242,101,38,33,40,69,2,74,42,192,12, - 33,48,128,2,33,24,64,0,60,0,98,40, - 2,0,64,16,0,242,98,38,60,0,3,36, - 33,136,66,2,33,32,32,2,33,40,0,2, - 1,0,2,36,17,0,2,162,0,128,98,52, - 0,0,2,174,6,23,192,12,18,0,3,166, - 10,0,64,20,33,32,0,2,2,131,2,60, - 33,16,82,0,172,247,66,140,0,0,0,0, - 1,0,66,36,152,21,192,12,236,0,34,174, - 214,40,192,8,0,0,0,0,2,131,2,60, - 33,16,82,0,168,247,66,140,0,0,0,0, - 1,0,66,36,232,0,34,174,36,0,191,143, - 32,0,180,143,28,0,179,143,24,0,178,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 40,0,189,39,216,255,189,39,24,0,178,175, - 33,144,128,0,20,0,177,175,33,136,160,0, - 16,0,176,175,33,128,192,0,36,0,191,175, - 32,0,180,175,28,0,179,175,4,0,36,142, - 8,0,37,142,160,133,134,143,2,131,7,60, - 180,211,231,140,20,35,192,12,0,0,0,0, - 11,0,64,20,0,0,0,0,2,131,4,60, - 144,146,132,36,15,63,192,12,33,40,0,2, - 100,129,132,39,108,129,134,39,31,21,192,12, - 6,0,5,38,92,41,192,8,0,0,0,0, - 3,131,20,60,208,12,148,38,0,0,132,142, - 3,131,5,60,212,12,165,140,3,131,6,60, - 216,12,198,140,3,131,7,60,220,12,231,140, - 0,0,0,0,20,35,192,12,192,129,18,0, - 3,131,3,60,33,24,112,0,20,13,99,140, - 0,0,0,0,80,0,96,16,1,0,83,44, - 33,32,64,2,11,40,192,12,33,40,32,2, - 50,0,64,16,33,32,64,2,223,39,192,12, - 33,40,32,2,92,37,192,12,0,0,0,0, - 206,35,192,12,0,0,0,0,0,0,132,142, - 3,131,5,60,212,12,165,140,3,131,6,60, - 216,12,198,140,3,131,7,60,220,12,231,140, - 20,35,192,12,0,0,0,0,16,0,64,16, - 0,0,0,0,14,0,96,18,0,0,0,0, - 3,131,2,60,248,12,66,140,3,131,1,60, - 9,0,64,16,0,13,32,164,3,131,1,60, - 72,37,192,12,4,13,32,164,1,0,2,36, - 3,131,1,60,8,13,34,164,3,131,1,60, - 10,13,32,164,3,131,2,60,228,12,66,140, - 0,0,0,0,38,0,66,22,0,0,0,0, - 254,39,192,12,33,32,32,2,52,36,192,12, - 0,0,0,0,36,0,34,142,0,0,0,0, - 30,0,64,16,0,0,0,0,206,39,192,12, - 0,0,0,0,92,41,192,8,0,0,0,0, - 3,131,4,60,33,32,144,0,40,13,132,140, - 3,131,5,60,33,40,176,0,44,13,165,140, - 3,131,6,60,216,12,198,140,3,131,7,60, - 220,12,231,140,20,35,192,12,0,0,0,0, - 12,0,64,20,0,0,0,0,3,131,3,60, - 33,24,112,0,48,13,99,148,3,131,2,60, - 33,16,80,0,16,13,66,148,0,0,0,0, - 3,0,98,20,0,0,0,0,203,36,192,12, - 33,32,64,2,36,0,191,143,32,0,180,143, - 28,0,179,143,24,0,178,143,20,0,177,143, - 16,0,176,143,8,0,224,3,40,0,189,39, - 224,255,189,39,20,0,177,175,33,136,128,0, - 16,0,176,175,192,129,17,0,24,0,191,175, - 3,131,2,60,33,16,80,0,20,13,66,140, - 0,0,0,0,28,0,64,16,0,0,0,0, - 3,131,4,60,33,32,144,0,40,13,132,140, - 3,131,5,60,33,40,176,0,44,13,165,140, - 3,131,6,60,216,12,198,140,3,131,7,60, - 220,12,231,140,20,35,192,12,0,0,0,0, - 14,0,64,20,0,0,0,0,3,131,3,60, - 33,24,112,0,48,13,99,148,3,131,2,60, - 33,16,80,0,16,13,66,148,0,0,0,0, - 5,0,98,20,0,0,0,0,161,36,192,12, - 0,0,0,0,211,39,192,12,33,32,32,2, - 24,0,191,143,20,0,177,143,16,0,176,143, - 8,0,224,3,32,0,189,39,2,18,5,0, - 0,0,130,160,8,0,224,3,1,0,133,160, - 2,22,5,0,0,0,130,160,2,20,5,0, - 1,0,130,160,2,18,5,0,2,0,130,160, - 8,0,224,3,3,0,133,160,0,0,130,144, - 1,0,131,144,0,18,2,0,8,0,224,3, - 37,16,98,0,0,0,130,144,1,0,131,144, - 2,0,133,144,0,22,2,0,0,28,3,0, - 33,16,67,0,0,42,5,0,3,0,131,144, - 33,16,69,0,8,0,224,3,37,16,67,0, - 224,255,189,39,16,0,176,175,33,128,128,0, - 24,0,191,175,20,0,177,175,48,129,135,39, - 3,0,226,136,0,0,226,152,4,0,227,128, - 5,0,228,128,3,0,2,170,0,0,2,186, - 4,0,3,162,5,0,4,162,3,0,162,136, - 0,0,162,152,4,0,163,128,5,0,164,128, - 9,0,2,170,6,0,2,186,10,0,3,162, - 11,0,4,162,12,0,4,38,38,0,5,36, - 144,41,192,12,33,136,192,0,14,0,4,38, - 144,41,192,12,66,66,5,36,17,0,4,38, - 33,40,0,0,3,0,2,36,144,41,192,12, - 16,0,2,162,19,0,0,162,20,0,0,162, - 40,0,34,142,0,0,0,0,43,32,2,0, - 36,0,34,142,0,0,0,0,3,0,64,16, - 33,24,128,0,218,41,192,8,128,0,130,52, - 33,16,96,0,21,0,2,162,4,0,37,150, - 0,0,0,0,144,41,192,12,22,0,4,38, - 9,0,34,138,6,0,34,154,10,0,35,130, - 11,0,36,130,27,0,2,170,24,0,2,186, - 28,0,3,162,29,0,4,162,12,0,37,142, - 0,0,0,0,148,41,192,12,30,0,4,38, - 16,0,37,150,0,0,0,0,144,41,192,12, - 34,0,4,38,21,0,34,138,18,0,34,154, - 22,0,35,130,23,0,36,130,39,0,2,170, - 36,0,2,186,40,0,3,162,41,0,4,162, - 24,0,37,150,0,0,0,0,144,41,192,12, - 42,0,4,38,26,0,37,150,0,0,0,0, - 144,41,192,12,44,0,4,38,28,0,37,150, - 0,0,0,0,144,41,192,12,46,0,4,38, - 30,0,37,150,0,0,0,0,144,41,192,12, - 48,0,4,38,32,0,37,150,0,0,0,0, - 144,41,192,12,50,0,4,38,52,0,2,36, - 24,0,191,143,20,0,177,143,16,0,176,143, - 8,0,224,3,32,0,189,39,224,255,189,39, - 16,0,176,175,33,128,160,0,24,0,191,175, - 20,0,177,175,21,0,2,146,33,136,128,0, - 1,0,66,48,40,0,34,174,22,0,2,146, - 22,0,4,38,128,0,66,48,156,41,192,12, - 36,0,34,174,4,0,34,166,27,0,2,138, - 24,0,2,154,28,0,3,130,29,0,4,130, - 9,0,34,170,6,0,34,186,10,0,35,162, - 11,0,36,162,161,41,192,12,30,0,4,38, - 34,0,4,38,156,41,192,12,12,0,34,174, - 16,0,34,166,39,0,2,138,36,0,2,154, - 40,0,3,130,41,0,4,130,21,0,34,170, - 18,0,34,186,22,0,35,162,23,0,36,162, - 156,41,192,12,42,0,4,38,44,0,4,38, - 156,41,192,12,24,0,34,166,46,0,4,38, - 156,41,192,12,26,0,34,166,48,0,4,38, - 156,41,192,12,28,0,34,166,50,0,4,38, - 156,41,192,12,30,0,34,166,32,0,34,166, - 24,0,191,143,20,0,177,143,16,0,176,143, - 8,0,224,3,32,0,189,39,232,255,189,39, - 16,0,176,175,33,128,128,0,20,0,191,175, - 48,129,134,39,3,0,194,136,0,0,194,152, - 4,0,195,128,5,0,196,128,3,0,2,170, - 0,0,2,186,4,0,3,162,5,0,4,162, - 3,0,162,136,0,0,162,152,4,0,163,128, - 5,0,164,128,9,0,2,170,6,0,2,186, - 10,0,3,162,11,0,4,162,12,0,4,38, - 144,41,192,12,7,0,5,36,14,0,4,38, - 144,41,192,12,66,66,5,36,17,0,4,38, - 33,40,0,0,3,0,2,36,144,41,192,12, - 16,0,2,162,21,0,2,36,128,0,3,36, - 19,0,0,162,20,0,3,162,20,0,191,143, - 16,0,176,143,8,0,224,3,24,0,189,39, - 176,255,189,39,68,0,177,175,64,0,176,175, - 33,128,160,0,72,0,191,175,14,0,3,146, - 66,0,2,36,9,0,98,20,33,136,128,0, - 15,0,2,146,0,0,0,0,6,0,67,20, - 64,26,17,0,16,0,3,146,3,0,2,36, - 11,0,98,16,0,0,0,0,64,26,17,0, - 2,131,2,60,33,16,67,0,184,247,66,140, - 0,0,0,0,1,0,66,36,2,131,1,60, - 33,8,35,0,182,42,192,8,184,247,34,172, - 20,0,3,146,0,0,0,0,5,0,96,16, - 128,0,2,36,21,0,98,16,64,26,17,0, - 179,42,192,8,0,0,0,0,16,0,164,39, - 64,26,17,0,2,131,2,60,33,16,67,0, - 180,247,66,140,0,0,0,0,1,0,66,36, - 2,131,1,60,33,8,35,0,180,247,34,172, - 17,42,192,12,33,40,0,2,33,32,32,2, - 16,0,165,39,222,40,192,12,33,48,0,2, - 182,42,192,8,0,0,0,0,2,131,2,60, - 33,16,67,0,180,247,66,140,0,0,0,0, - 1,0,66,36,2,131,1,60,33,8,35,0, - 180,247,34,172,100,41,192,12,33,32,32,2, - 182,42,192,8,0,0,0,0,112,129,132,39, - 15,63,192,12,0,0,0,0,72,0,191,143, - 68,0,177,143,64,0,176,143,8,0,224,3, - 80,0,189,39,8,0,224,3,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 1,0,162,48,8,0,64,16,255,255,198,48, - 67,40,5,0,64,16,5,0,33,16,68,0, - 0,0,66,144,0,0,0,0,203,42,192,8, - 33,48,194,0,67,40,5,0,255,255,165,36, - 255,255,2,36,6,0,162,16,255,255,3,36, - 0,0,130,148,2,0,132,36,255,255,165,36, - 252,255,163,20,33,48,194,0,255,255,195,48, - 2,20,6,0,33,48,98,0,255,255,195,48, - 2,20,6,0,33,48,98,0,8,0,224,3, - 255,255,194,48,208,255,189,39,16,0,176,175, - 33,128,128,0,28,0,179,175,33,152,160,0, - 24,0,178,175,33,144,192,0,36,0,181,175, - 33,168,0,2,32,0,180,175,33,160,0,0, - 40,0,191,175,20,0,177,175,12,0,3,142, - 0,0,2,142,0,0,0,0,35,24,98,0, - 42,16,114,0,2,0,64,16,33,136,64,2, - 33,136,96,0,13,0,32,18,33,40,96,2, - 35,144,81,2,8,0,2,142,0,0,4,142, - 33,48,32,2,80,68,192,12,33,32,68,0, - 8,0,2,142,0,0,2,142,0,0,2,142, - 33,152,113,2,33,16,81,0,0,0,2,174, - 0,0,2,142,0,0,0,0,4,0,64,18, - 33,160,130,2,4,0,16,142,233,42,192,8, - 0,0,0,0,18,0,180,166,33,16,0,2, - 40,0,191,143,36,0,181,143,32,0,180,143, - 28,0,179,143,24,0,178,143,20,0,177,143, - 16,0,176,143,8,0,224,3,48,0,189,39, - 224,255,189,39,24,0,178,175,33,144,128,0, - 2,131,4,60,192,4,132,36,36,0,165,175, - 1,0,5,36,28,0,191,175,20,0,177,175, - 54,21,192,12,16,0,176,175,33,136,64,0, - 8,0,32,22,33,40,0,0,2,131,2,60, - 176,5,66,140,0,0,0,0,1,0,66,36, - 2,131,1,60,102,43,192,8,176,5,34,172, - 0,1,3,36,8,0,48,142,8,0,2,36, - 16,0,2,166,6,0,2,36,18,0,2,162, - 4,0,2,36,14,0,3,166,19,0,2,162, - 20,0,3,166,2,131,6,60,212,4,198,36, - 3,0,194,136,0,0,194,152,4,0,195,132, - 25,0,2,170,22,0,2,186,26,0,3,166, - 2,131,1,60,195,211,34,136,176,133,130,155, - 0,0,0,0,31,0,2,170,28,0,2,186, - 32,0,4,38,144,71,192,12,6,0,6,36, - 39,0,162,139,36,0,162,155,0,0,0,0, - 41,0,2,170,38,0,2,186,132,129,133,39, - 3,0,162,136,0,0,162,152,4,0,163,128, - 5,0,164,128,3,0,2,170,0,0,2,186, - 4,0,3,162,5,0,4,162,2,131,5,60, - 212,4,165,36,3,0,162,136,0,0,162,152, - 4,0,163,128,5,0,164,128,9,0,2,170, - 6,0,2,186,10,0,3,162,11,0,4,162, - 33,32,64,2,8,6,2,36,12,0,2,166, - 60,128,2,52,0,0,34,174,60,0,2,36, - 18,0,34,166,74,21,192,12,33,40,32,2, - 3,0,64,20,0,0,0,0,152,21,192,12, - 33,32,32,2,28,0,191,143,24,0,178,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 32,0,189,39,216,255,189,39,32,0,180,175, - 33,160,128,0,16,0,176,175,33,128,160,0, - 36,0,191,175,28,0,179,175,24,0,178,175, - 20,0,177,175,8,0,2,142,33,152,192,0, - 33,136,83,0,6,0,35,150,0,1,4,36, - 5,0,100,16,0,2,2,36,113,0,98,16, - 0,0,0,0,15,44,192,8,0,0,0,0, - 24,0,35,150,176,133,130,151,0,0,0,0, - 139,0,98,20,0,0,0,0,26,0,35,150, - 2,131,2,60,194,211,66,148,0,0,0,0, - 133,0,98,20,0,0,0,0,0,0,34,150, - 0,0,0,0,129,0,68,20,8,0,2,36, - 2,0,35,150,0,0,0,0,125,0,98,20, - 6,4,2,36,4,0,35,150,0,0,0,0, - 121,0,98,20,0,0,0,0,2,131,4,60, - 192,4,132,36,54,21,192,12,1,0,5,36, - 33,144,64,0,8,0,64,22,0,0,0,0, - 2,131,2,60,176,5,66,140,0,0,0,0, - 1,0,66,36,2,131,1,60,15,44,192,8, - 176,5,34,172,8,0,5,142,8,0,80,142, - 9,0,162,136,6,0,162,152,10,0,163,128, - 11,0,164,128,3,0,2,170,0,0,2,186, - 4,0,3,162,5,0,4,162,2,131,6,60, - 212,4,198,36,3,0,194,136,0,0,194,152, - 4,0,195,128,5,0,196,128,9,0,2,170, - 6,0,2,186,10,0,3,162,11,0,4,162, - 12,0,4,38,12,0,165,36,33,128,19,2, - 80,68,192,12,244,255,102,38,0,1,2,36, - 0,0,2,166,8,0,2,36,2,0,2,166, - 6,0,2,36,4,0,2,162,4,0,2,36, - 5,0,2,162,0,2,2,36,6,0,2,166, - 2,131,5,60,212,4,165,36,3,0,162,136, - 0,0,162,152,4,0,163,132,11,0,2,170, - 8,0,2,186,12,0,3,166,2,131,1,60, - 195,211,34,136,176,133,130,155,0,0,0,0, - 17,0,2,170,14,0,2,186,11,0,34,138, - 8,0,34,154,12,0,35,134,21,0,2,170, - 18,0,2,186,22,0,3,166,17,0,34,138, - 14,0,34,154,0,0,0,0,27,0,2,170, - 24,0,2,186,33,32,128,2,33,40,64,2, - 60,128,2,52,0,0,66,174,60,0,2,36, - 74,21,192,12,18,0,66,166,38,0,64,20, - 0,0,0,0,152,21,192,12,33,32,64,2, - 15,44,192,8,0,0,0,0,14,0,35,150, - 196,133,130,151,0,0,0,0,29,0,98,20, - 0,0,0,0,16,0,35,150,2,131,2,60, - 214,211,66,148,0,0,0,0,23,0,98,20, - 0,0,0,0,0,0,34,150,0,0,0,0, - 19,0,68,20,8,0,2,36,2,0,35,150, - 0,0,0,0,15,0,98,20,6,4,2,36, - 4,0,35,150,0,0,0,0,11,0,98,20, - 0,0,0,0,68,133,130,143,140,129,134,39, - 11,0,35,138,8,0,35,154,12,0,36,134, - 3,0,195,168,0,0,195,184,4,0,196,164, - 20,0,66,36,152,129,130,175,36,0,191,143, - 32,0,180,143,28,0,179,143,24,0,178,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 40,0,189,39,192,255,189,39,80,0,169,143, - 84,0,168,143,56,0,180,175,33,160,128,0, - 44,0,177,175,88,0,177,143,16,0,164,39, - 52,0,179,175,92,0,179,143,3,131,3,60, - 32,17,99,36,40,0,176,175,33,128,192,0, - 60,0,191,175,48,0,178,175,0,0,98,140, - 8,0,50,142,1,0,66,36,0,0,98,172, - 3,0,162,136,0,0,162,152,4,0,163,128, - 5,0,170,128,3,0,66,170,0,0,66,186, - 4,0,67,162,5,0,74,162,2,131,10,60, - 212,4,74,37,3,0,66,137,0,0,66,153, - 4,0,67,129,5,0,69,129,9,0,66,170, - 6,0,66,186,10,0,67,162,11,0,69,162, - 69,0,2,36,16,0,162,163,17,0,168,163, - 18,0,34,150,240,132,131,143,33,48,0,0, - 25,0,169,163,20,0,66,36,0,66,2,0, - 255,255,66,48,2,18,2,0,37,64,2,1, - 0,74,3,0,255,255,98,48,2,18,2,0, - 37,72,34,1,3,131,2,60,0,17,66,140, - 22,0,160,167,26,0,160,167,18,0,168,167, - 176,133,136,143,1,0,99,36,240,132,131,175, - 20,0,169,167,24,0,162,163,28,0,168,175, - 3,0,226,136,0,0,226,152,0,0,0,0, - 35,0,162,171,32,0,162,187,192,42,192,12, - 20,0,5,36,39,16,2,0,26,0,162,167, - 14,0,2,36,44,0,2,22,8,0,2,36, - 12,0,66,166,19,0,162,139,16,0,162,155, - 23,0,163,139,20,0,163,155,27,0,164,139, - 24,0,164,155,31,0,165,139,28,0,165,155, - 17,0,66,170,14,0,66,186,21,0,67,170, - 18,0,67,186,25,0,68,170,22,0,68,186, - 29,0,69,170,26,0,69,186,35,0,162,139, - 32,0,162,155,0,0,0,0,33,0,66,170, - 30,0,66,186,34,0,2,36,0,0,34,174, - 0,0,35,142,18,0,34,150,0,0,0,0, - 33,16,67,0,18,0,34,166,18,0,34,150, - 0,0,0,0,60,0,66,44,68,0,64,16, - 33,32,128,2,0,0,98,142,18,0,35,150, - 60,0,66,36,35,16,67,0,0,0,98,174, - 60,0,2,36,18,0,34,166,201,44,192,8, - 33,32,128,2,164,129,133,39,3,0,162,136, - 0,0,162,152,4,0,163,128,5,0,164,128, - 17,0,66,170,14,0,66,186,18,0,67,162, - 19,0,68,162,8,0,2,36,20,0,66,166, - 19,0,162,139,16,0,162,155,23,0,163,139, - 20,0,163,155,27,0,164,139,24,0,164,155, - 31,0,165,139,28,0,165,155,25,0,66,170, - 22,0,66,186,29,0,67,170,26,0,67,186, - 33,0,68,170,30,0,68,186,37,0,69,170, - 34,0,69,186,35,0,162,139,32,0,162,155, - 0,0,0,0,41,0,66,170,38,0,66,186, - 42,0,2,36,0,0,34,174,0,0,35,142, - 18,0,34,150,0,0,0,0,33,16,67,0, - 18,0,34,166,18,0,34,150,0,0,0,0, - 60,0,66,44,8,0,64,16,0,0,0,0, - 0,0,98,142,18,0,35,150,60,0,66,36, - 35,16,67,0,0,0,98,174,60,0,2,36, - 18,0,34,166,18,0,34,150,0,0,0,0, - 0,26,2,0,2,18,2,0,37,24,98,0, - 12,0,67,166,33,32,128,2,74,21,192,12, - 33,40,32,2,8,0,64,20,33,32,32,2, - 3,131,3,60,36,17,99,36,0,0,98,140, - 0,0,0,0,1,0,66,36,152,21,192,12, - 0,0,98,172,60,0,191,143,56,0,180,143, - 52,0,179,143,48,0,178,143,44,0,177,143, - 40,0,176,143,8,0,224,3,64,0,189,39, - 176,255,189,39,56,0,180,175,112,0,180,143, - 48,0,178,175,100,0,178,143,52,0,179,175, - 104,0,179,143,64,0,182,175,33,176,128,0, - 72,0,190,175,33,240,160,0,60,0,181,175, - 33,168,224,0,68,0,183,175,108,0,183,143, - 2,131,4,60,192,4,132,36,76,0,191,175, - 44,0,177,175,40,0,176,175,32,0,166,175, - 7,2,130,38,2,130,2,0,54,21,192,12, - 33,40,0,2,33,136,64,0,8,0,32,22, - 0,74,18,0,2,131,4,60,232,146,132,36, - 33,40,128,2,15,63,192,12,33,48,0,2, - 74,45,192,8,0,0,0,0,255,255,66,50, - 2,18,2,0,37,72,34,1,0,66,19,0, - 255,255,98,50,2,18,2,0,37,64,2,1, - 8,0,130,38,0,58,2,0,255,255,66,48, - 2,18,2,0,37,56,226,0,0,163,4,60, - 220,5,132,52,4,0,5,36,4,0,34,142, - 0,17,6,36,8,0,80,140,4,0,35,142, - 8,0,2,36,0,0,98,172,0,0,9,166, - 2,0,8,166,6,0,0,166,192,42,192,12, - 4,0,7,166,33,32,160,2,4,0,5,36, - 192,42,192,12,255,255,70,48,4,0,4,38, - 2,0,5,36,192,42,192,12,255,255,70,48, - 33,32,0,2,8,0,5,36,192,42,192,12, - 255,255,70,48,33,32,224,2,33,40,128,2, - 192,42,192,12,255,255,70,48,39,24,2,0, - 255,255,98,48,2,0,64,20,33,40,224,2, - 255,255,3,52,6,0,3,166,4,0,36,142, - 0,0,0,0,220,42,192,12,33,48,128,2, - 33,32,192,2,0,0,67,140,33,40,192,3, - 0,128,99,52,0,0,67,172,4,0,35,142, - 32,0,166,143,18,0,99,148,33,56,160,2, - 18,0,35,166,96,0,170,143,17,0,3,36, - 16,0,163,175,24,0,177,175,28,0,162,175, - 23,44,192,12,20,0,170,175,3,131,3,60, - 124,17,99,36,0,0,98,140,0,0,0,0, - 1,0,66,36,0,0,98,172,76,0,191,143, - 72,0,190,143,68,0,183,143,64,0,182,143, - 60,0,181,143,56,0,180,143,52,0,179,143, - 48,0,178,143,44,0,177,143,40,0,176,143, - 8,0,224,3,80,0,189,39,128,255,189,39, - 116,0,183,175,33,184,128,0,112,0,182,175, - 33,176,160,0,104,0,180,175,33,160,192,0, - 108,0,181,175,33,168,224,0,40,0,164,39, - 96,0,178,175,144,0,178,143,33,40,0,0, - 100,0,179,175,148,0,179,143,16,0,6,36, - 120,0,191,175,92,0,177,175,144,71,192,12, - 88,0,176,175,56,0,177,39,33,32,32,2, - 33,40,0,0,2,0,16,36,40,0,176,167, - 2,0,162,150,0,0,0,0,42,0,162,167, - 19,0,130,138,16,0,130,154,0,0,0,0, - 47,0,162,171,44,0,162,187,144,71,192,12, - 16,0,6,36,33,32,64,2,33,40,96,2, - 40,0,166,39,33,56,32,2,56,0,176,167, - 0,0,162,150,2,131,16,60,8,239,16,38, - 58,0,162,167,15,0,130,138,12,0,130,154, - 0,0,0,0,63,0,162,171,60,0,162,187, - 242,5,2,36,84,0,162,167,72,0,162,39, - 72,0,160,167,76,0,176,175,80,0,176,175, - 247,71,192,12,16,0,162,175,255,255,3,36, - 22,0,67,16,12,0,145,38,33,32,224,2, - 6,0,197,38,35,48,150,2,0,0,163,150, - 4,0,2,36,16,0,162,175,161,0,2,36, - 20,0,162,175,28,0,176,175,0,18,3,0, - 2,26,3,0,37,16,67,0,255,255,66,48, - 24,0,162,175,80,0,162,143,76,0,163,143, - 33,56,32,2,35,16,67,0,255,255,66,48, - 220,44,192,12,32,0,162,175,120,0,191,143, - 116,0,183,143,112,0,182,143,108,0,181,143, - 104,0,180,143,100,0,179,143,96,0,178,143, - 92,0,177,143,88,0,176,143,8,0,224,3, - 128,0,189,39,196,133,130,143,184,255,189,39, - 64,0,191,175,60,0,177,175,109,0,64,16, - 56,0,176,175,255,255,3,36,106,0,67,16, - 0,0,0,0,176,133,130,143,176,133,145,39, - 102,0,64,16,0,0,0,0,100,0,67,16, - 0,0,0,0,2,131,2,60,8,239,66,36, - 44,0,162,175,48,0,162,175,242,5,2,36, - 40,0,160,167,6,0,128,16,52,0,162,167, - 1,0,2,36,23,0,130,16,0,0,0,0, - 36,46,192,8,0,0,0,0,2,131,16,60, - 160,204,16,38,156,71,192,12,33,32,0,2, - 0,163,4,60,4,1,132,140,204,204,3,60, - 205,204,99,52,25,0,131,0,33,40,32,2, - 33,48,0,2,33,56,64,0,40,0,164,39, - 16,64,0,0,194,16,8,0,0,0,0,0, - 104,56,192,12,16,0,162,175,251,45,192,8, - 33,24,64,0,3,131,2,60,28,18,66,148, - 0,0,0,0,2,0,66,48,61,0,64,16, - 0,0,0,0,2,131,16,60,160,204,16,38, - 156,71,192,12,33,32,0,2,0,163,4,60, - 4,1,132,140,204,204,3,60,205,204,99,52, - 25,0,131,0,33,40,32,2,33,48,0,2, - 33,56,64,0,40,0,164,39,16,64,0,0, - 194,16,8,0,0,0,0,0,105,57,192,12, - 16,0,162,175,33,24,64,0,255,255,2,36, - 39,0,98,16,0,0,0,0,140,129,130,147, - 0,0,0,0,1,0,66,48,7,0,64,20, - 0,0,0,0,68,133,131,143,152,129,130,143, - 0,0,0,0,43,16,67,0,11,0,64,16, - 33,32,0,0,68,133,131,143,148,129,130,143, - 0,0,0,0,6,0,98,16,33,32,0,0, - 196,133,133,143,148,129,131,175,17,43,192,12, - 33,32,0,0,33,32,0,0,140,129,133,39, - 14,0,6,36,4,0,2,36,16,0,162,175, - 162,0,2,36,20,0,162,175,24,0,162,175, - 2,131,2,60,8,239,66,36,28,0,162,175, - 48,0,162,143,44,0,163,143,196,133,135,39, - 35,16,67,0,255,255,66,48,220,44,192,12, - 32,0,162,175,64,0,191,143,60,0,177,143, - 56,0,176,143,8,0,224,3,72,0,189,39, - 208,255,189,39,36,0,179,175,33,152,128,0, - 40,0,180,175,33,160,160,0,32,0,178,175, - 24,0,176,175,33,128,224,0,44,0,191,175, - 28,0,177,175,6,0,2,150,64,0,177,143, - 0,0,0,0,20,0,64,16,33,144,192,0, - 12,0,68,38,8,0,5,36,192,42,192,12, - 0,17,6,36,4,0,4,38,2,0,5,36, - 192,42,192,12,255,255,70,48,33,32,0,2, - 33,40,32,2,192,42,192,12,255,255,70,48, - 255,255,66,48,255,255,3,52,4,0,67,16, - 0,0,0,0,3,131,3,60,111,46,192,8, - 120,17,99,36,4,0,2,150,0,0,0,0, - 0,26,2,0,2,18,2,0,37,24,98,0, - 255,255,99,48,4,0,113,16,8,0,7,38, - 3,131,3,60,111,46,192,8,120,17,99,36, - 2,0,2,150,0,0,0,0,0,26,2,0, - 2,18,2,0,37,24,98,0,255,255,99,48, - 161,0,2,36,15,0,98,20,248,255,40,38, - 33,32,96,2,33,40,128,2,3,131,3,60, - 112,17,99,36,0,0,98,140,33,48,64,2, - 16,0,167,175,33,56,0,2,20,0,168,175, - 1,0,66,36,86,45,192,12,0,0,98,172, - 115,46,192,8,0,0,0,0,3,131,3,60, - 116,17,99,36,0,0,98,140,0,0,0,0, - 1,0,66,36,0,0,98,172,44,0,191,143, - 40,0,180,143,36,0,179,143,32,0,178,143, - 28,0,177,143,24,0,176,143,8,0,224,3, - 48,0,189,39,192,255,189,39,52,0,181,175, - 33,168,128,0,44,0,179,175,33,152,160,0, - 48,0,180,175,33,160,192,0,32,0,176,175, - 33,128,224,0,33,32,0,2,33,48,0,0, - 40,0,178,175,80,0,178,143,3,131,3,60, - 144,16,99,36,56,0,191,175,36,0,177,175, - 0,0,98,140,33,40,64,2,1,0,66,36, - 192,42,192,12,0,0,98,172,255,255,66,48, - 255,255,3,52,8,0,67,16,8,0,2,36, - 3,131,2,60,148,16,66,140,0,0,0,0, - 1,0,66,36,3,131,1,60,217,46,192,8, - 148,16,34,172,0,0,3,150,0,0,0,0, - 58,0,98,20,255,1,69,38,2,131,4,60, - 192,4,132,36,3,131,2,60,172,16,66,140, - 3,131,3,60,196,16,99,140,1,0,66,36, - 1,0,99,36,3,131,1,60,172,16,34,172, - 3,131,1,60,196,16,35,172,54,21,192,12, - 2,42,5,0,33,136,64,0,8,0,32,22, - 33,32,0,2,3,131,2,60,200,16,66,140, - 0,0,0,0,1,0,66,36,3,131,1,60, - 217,46,192,8,200,16,34,172,33,40,64,2, - 33,48,0,0,0,0,0,162,192,42,192,12, - 2,0,0,166,33,40,0,2,39,16,2,0, - 2,0,162,164,4,0,36,142,0,0,0,0, - 220,42,192,12,33,48,64,2,33,32,160,2, - 6,0,101,38,35,48,147,2,0,0,67,140, - 12,0,135,38,0,128,99,52,0,0,67,172, - 1,0,3,36,18,0,50,166,16,0,163,175, - 4,0,3,36,20,0,163,175,24,0,177,175, - 23,44,192,12,28,0,162,175,3,131,2,60, - 228,16,66,140,0,0,0,0,1,0,66,36, - 3,131,1,60,228,16,34,172,56,0,191,143, - 52,0,181,143,48,0,180,143,44,0,179,143, - 40,0,178,143,36,0,177,143,32,0,176,143, - 8,0,224,3,64,0,189,39,200,255,189,39, - 44,0,181,175,33,168,128,0,3,131,3,60, - 4,17,99,36,48,0,191,175,40,0,180,175, - 36,0,179,175,32,0,178,175,28,0,177,175, - 24,0,176,175,0,0,98,140,33,136,160,0, - 1,0,66,36,0,0,98,172,18,0,34,150, - 0,0,0,0,255,255,84,48,243,5,130,46, - 8,0,64,20,33,152,192,0,3,131,2,60, - 8,17,66,140,0,0,0,0,1,0,66,36, - 3,131,1,60,132,47,192,8,8,17,34,172, - 2,131,18,60,18,233,82,38,33,32,64,2, - 0,0,48,142,8,0,37,142,255,63,16,50, - 80,68,192,12,33,48,0,2,0,0,34,142, - 0,0,0,0,0,128,66,48,5,0,64,20, - 33,144,80,2,4,0,49,142,0,0,0,0, - 1,47,192,8,33,32,64,2,2,131,18,60, - 18,233,82,38,33,128,114,2,16,0,17,38, - 33,32,32,2,176,133,133,39,168,71,192,12, - 4,0,6,36,9,0,64,16,33,32,32,2, - 128,129,133,39,168,71,192,12,4,0,6,36, - 4,0,64,16,0,0,0,0,3,131,3,60, - 128,47,192,8,12,17,99,36,0,0,4,146, - 64,0,2,36,240,0,131,48,4,0,98,16, - 15,0,130,48,3,131,3,60,128,47,192,8, - 8,17,99,36,128,136,2,0,20,0,34,42, - 4,0,64,16,33,32,0,2,3,131,3,60, - 128,47,192,8,8,17,99,36,33,40,32,2, - 192,42,192,12,33,48,0,0,255,255,66,48, - 255,255,3,52,4,0,67,16,0,0,0,0, - 3,131,3,60,128,47,192,8,8,17,99,36, - 6,0,2,150,0,0,0,0,63,255,66,48, - 18,0,64,16,33,56,17,2,3,131,3,60, - 48,17,99,36,0,0,98,140,0,0,0,0, - 1,0,66,36,0,0,98,172,3,131,2,60, - 56,17,66,140,3,131,3,60,24,17,99,140, - 1,0,66,36,1,0,99,36,3,131,1,60, - 56,17,34,172,3,131,1,60,132,47,192,8, - 24,17,35,172,2,0,2,150,0,0,0,0, - 0,26,2,0,2,18,2,0,37,24,98,0, - 255,255,99,48,35,64,113,0,35,16,242,0, - 35,16,130,2,42,16,72,0,4,0,64,16, - 1,0,2,36,3,131,3,60,128,47,192,8, - 24,17,99,36,9,0,3,146,0,0,0,0, - 5,0,98,16,17,0,2,36,15,0,98,16, - 33,32,160,2,126,47,192,8,0,0,0,0, - 33,32,160,2,33,40,64,2,3,131,3,60, - 28,17,99,36,0,0,98,140,33,48,0,2, - 16,0,168,175,1,0,66,36,123,46,192,12, - 0,0,98,172,132,47,192,8,0,0,0,0, - 33,40,64,2,3,131,3,60,28,17,99,36, - 0,0,98,140,33,48,0,2,16,0,168,175, - 1,0,66,36,41,46,192,12,0,0,98,172, - 132,47,192,8,0,0,0,0,3,131,3,60, - 20,17,99,36,0,0,98,140,0,0,0,0, - 1,0,66,36,0,0,98,172,48,0,191,143, - 44,0,181,143,40,0,180,143,36,0,179,143, - 32,0,178,143,28,0,177,143,24,0,176,143, - 8,0,224,3,56,0,189,39,232,255,189,39, - 255,0,12,60,255,0,140,53,0,255,13,60, - 0,255,173,53,16,0,176,175,3,131,16,60, - 0,17,16,38,33,32,0,2,33,40,0,0, - 0,163,9,60,220,5,41,141,0,163,10,60, - 16,6,74,141,0,163,11,60,224,5,107,141, - 20,0,191,175,0,28,9,0,2,20,9,0, - 37,24,98,0,0,60,10,0,2,20,10,0, - 37,56,226,0,0,68,11,0,2,20,11,0, - 37,64,2,1,2,18,3,0,36,16,76,0, - 0,26,3,0,36,24,109,0,37,16,67,0, - 184,133,130,175,2,18,7,0,36,16,76,0, - 0,58,7,0,36,56,237,0,37,16,71,0, - 192,133,130,175,2,18,8,0,36,16,76,0, - 0,66,8,0,36,64,13,1,37,16,72,0, - 176,133,137,175,196,133,138,175,188,133,139,175, - 180,133,130,175,144,71,192,12,76,0,6,36, - 3,131,4,60,144,16,132,36,33,40,0,0, - 32,0,2,36,0,0,2,174,10,0,2,36, - 3,131,1,60,44,17,34,172,144,71,192,12, - 104,0,6,36,3,131,4,60,112,17,132,36, - 33,40,0,0,144,71,192,12,16,0,6,36, - 3,131,4,60,80,17,132,36,33,40,0,0, - 144,71,192,12,32,0,6,36,20,0,191,143, - 16,0,176,143,8,0,224,3,24,0,189,39, - 176,255,189,39,100,0,162,143,96,0,169,143, - 72,0,182,175,33,176,128,0,48,0,176,175, - 104,0,176,143,34,0,164,39,60,0,179,175, - 108,0,179,143,3,131,3,60,104,17,99,36, - 56,0,178,175,2,131,18,60,212,4,82,38, - 52,0,177,175,33,136,192,0,68,0,181,175, - 112,0,181,143,4,0,6,36,76,0,191,175, - 64,0,180,175,0,66,2,0,255,255,66,48, - 2,18,2,0,37,64,2,1,0,0,98,140, - 8,0,116,142,1,0,66,36,0,0,98,172, - 3,0,162,136,0,0,162,152,4,0,163,128, - 5,0,170,128,3,0,130,170,0,0,130,186, - 4,0,131,162,5,0,138,162,3,0,66,138, - 0,0,66,154,4,0,67,130,5,0,69,130, - 9,0,130,170,6,0,130,186,10,0,131,162, - 11,0,133,162,255,255,2,52,16,0,162,167, - 18,0,98,150,33,40,0,0,20,0,160,163, - 21,0,160,163,30,0,66,36,0,26,2,0, - 255,255,66,48,2,18,2,0,37,24,98,0, - 18,0,163,167,3,0,226,136,0,0,226,152, - 0,0,0,0,25,0,162,171,22,0,162,187, - 3,0,34,137,0,0,34,153,4,0,35,129, - 5,0,39,129,29,0,162,171,26,0,162,187, - 30,0,163,163,31,0,167,163,144,71,192,12, - 32,0,168,167,3,0,66,138,0,0,66,154, - 4,0,67,134,41,0,162,171,38,0,162,187, - 42,0,163,167,33,16,0,2,0,130,16,0, - 255,255,66,48,2,18,2,0,37,128,2,2, - 14,0,2,36,58,0,34,22,44,0,176,167, - 18,0,162,151,0,0,0,0,12,0,130,166, - 19,0,162,139,16,0,162,155,23,0,163,139, - 20,0,163,155,27,0,164,139,24,0,164,155, - 31,0,165,139,28,0,165,155,17,0,130,170, - 14,0,130,186,21,0,131,170,18,0,131,186, - 25,0,132,170,22,0,132,186,29,0,133,170, - 26,0,133,186,35,0,162,139,32,0,162,155, - 39,0,163,139,36,0,163,155,43,0,164,139, - 40,0,164,155,44,0,165,131,33,0,130,170, - 30,0,130,186,37,0,131,170,34,0,131,186, - 41,0,132,170,38,0,132,186,42,0,133,162, - 45,0,162,131,0,0,0,0,43,0,130,162, - 44,0,2,36,0,0,98,174,0,0,99,142, - 18,0,98,150,0,0,0,0,33,16,67,0, - 18,0,98,166,18,0,98,150,0,0,0,0, - 60,0,66,44,80,0,64,16,33,32,192,2, - 0,0,162,142,18,0,99,150,60,0,66,36, - 35,16,67,0,0,0,162,174,60,0,2,36, - 18,0,98,166,172,48,192,8,33,32,192,2, - 208,129,133,39,3,0,162,136,0,0,162,152, - 4,0,163,128,5,0,164,128,17,0,130,170, - 14,0,130,186,18,0,131,162,19,0,132,162, - 129,55,2,36,20,0,130,166,19,0,162,139, - 16,0,162,155,23,0,163,139,20,0,163,155, - 27,0,164,139,24,0,164,155,31,0,165,139, - 28,0,165,155,25,0,130,170,22,0,130,186, - 29,0,131,170,26,0,131,186,33,0,132,170, - 30,0,132,186,37,0,133,170,34,0,133,186, - 35,0,162,139,32,0,162,155,39,0,163,139, - 36,0,163,155,43,0,164,139,40,0,164,155, - 44,0,165,131,41,0,130,170,38,0,130,186, - 45,0,131,170,42,0,131,186,49,0,132,170, - 46,0,132,186,50,0,133,162,45,0,162,131, - 0,0,0,0,51,0,130,162,52,0,2,36, - 0,0,98,174,0,0,99,142,18,0,98,150, - 0,0,0,0,33,16,67,0,18,0,98,166, - 18,0,98,150,0,0,0,0,60,0,66,44, - 8,0,64,16,0,0,0,0,0,0,162,142, - 18,0,99,150,60,0,66,36,35,16,67,0, - 0,0,162,174,60,0,2,36,18,0,98,166, - 18,0,98,150,0,0,0,0,0,26,2,0, - 2,18,2,0,37,24,98,0,12,0,131,166, - 33,32,192,2,74,21,192,12,33,40,96,2, - 8,0,64,20,33,32,96,2,3,131,3,60, - 108,17,99,36,0,0,98,140,0,0,0,0, - 1,0,66,36,152,21,192,12,0,0,98,172, - 76,0,191,143,72,0,182,143,68,0,181,143, - 64,0,180,143,60,0,179,143,56,0,178,143, - 52,0,177,143,48,0,176,143,8,0,224,3, - 80,0,189,39,33,24,0,0,5,0,7,36, - 58,0,6,36,0,0,162,144,0,0,0,0, - 2,17,2,0,2,131,1,60,33,8,34,0, - 176,155,34,144,0,0,0,0,0,0,130,160, - 0,0,162,144,1,0,132,36,15,0,66,48, - 2,131,1,60,33,8,34,0,176,155,34,144, - 1,0,165,36,0,0,130,160,3,0,103,16, - 1,0,132,36,0,0,134,160,1,0,132,36, - 1,0,99,36,6,0,98,40,233,255,64,20, - 0,0,0,0,8,0,224,3,0,0,0,0, - 128,255,189,39,2,101,2,36,0,2,3,36, - 112,0,176,175,44,0,176,39,33,32,0,2, - 33,40,0,0,48,0,6,36,120,0,191,175, - 116,0,177,175,40,0,162,167,144,71,192,12, - 42,0,163,167,3,131,17,60,96,18,49,38, - 2,131,5,60,224,147,165,36,188,71,192,12, - 33,32,32,2,18,0,64,20,33,32,0,2, - 2,131,5,60,236,147,165,36,0,0,162,140, - 4,0,163,140,8,0,164,140,44,0,162,175, - 48,0,163,175,52,0,164,175,12,0,162,128, - 0,0,0,0,56,0,162,163,2,131,5,60, - 212,4,165,36,193,48,192,12,56,0,164,39, - 8,49,192,8,92,0,177,39,33,40,32,2, - 204,63,192,12,48,0,6,36,92,0,177,39, - 33,32,32,2,33,40,0,0,144,71,192,12, - 4,0,6,36,2,131,4,60,212,4,132,36, - 0,0,130,140,4,0,131,132,96,0,162,175, - 100,0,163,167,4,82,2,36,0,1,3,36, - 236,255,132,36,2,0,5,36,102,0,162,167, - 54,21,192,12,104,0,163,167,33,128,64,0, - 22,0,0,18,40,0,165,39,4,0,4,142, - 0,0,0,0,220,42,192,12,66,0,6,36, - 33,32,0,0,0,0,67,140,132,129,133,39, - 0,128,99,52,0,0,67,172,4,0,3,142, - 14,0,6,36,18,0,99,148,33,56,32,2, - 18,0,3,166,82,4,3,36,16,0,165,175, - 20,0,163,175,24,0,163,175,28,0,176,175, - 214,47,192,12,32,0,162,175,120,0,191,143, - 116,0,177,143,112,0,176,143,8,0,224,3, - 128,0,189,39,144,255,189,39,104,0,180,175, - 33,160,128,0,100,0,179,175,33,152,160,0, - 92,0,177,175,33,136,192,0,33,32,224,0, - 40,0,166,39,56,0,167,39,96,0,178,175, - 2,131,18,60,8,239,82,38,88,0,176,175, - 128,0,176,143,242,5,2,36,84,0,162,167, - 72,0,162,39,108,0,191,175,72,0,160,167, - 76,0,178,175,80,0,178,175,16,0,162,175, - 247,71,192,12,33,40,0,2,255,255,3,36, - 37,0,67,16,255,1,5,38,2,131,4,60, - 192,4,132,36,54,21,192,12,2,42,5,0, - 33,128,64,0,30,0,0,18,33,40,64,2, - 80,0,166,143,76,0,162,143,4,0,4,142, - 35,48,194,0,220,42,192,12,255,255,198,48, - 33,32,128,2,0,0,67,140,6,0,101,38, - 0,128,99,52,0,0,67,172,4,0,3,142, - 35,48,51,2,18,0,99,148,18,0,39,38, - 18,0,3,166,28,0,40,150,22,0,35,38, - 16,0,163,175,15,144,3,52,24,0,163,175, - 28,0,176,175,32,0,162,175,0,18,8,0, - 2,66,8,0,37,16,72,0,255,255,66,48, - 214,47,192,12,20,0,162,175,108,0,191,143, - 104,0,180,143,100,0,179,143,96,0,178,143, - 92,0,177,143,88,0,176,143,8,0,224,3, - 112,0,189,39,200,255,189,39,44,0,181,175, - 33,168,128,0,28,0,177,175,33,136,160,0, - 48,0,191,175,40,0,180,175,36,0,179,175, - 32,0,178,175,24,0,176,175,18,0,34,150, - 0,0,0,0,255,255,84,48,243,5,130,46, - 4,0,64,20,33,152,192,0,3,131,3,60, - 241,49,192,8,84,17,99,36,2,131,18,60, - 16,233,82,38,33,32,64,2,0,0,48,142, - 8,0,37,142,255,63,16,50,80,68,192,12, - 33,48,0,2,0,0,34,142,0,0,0,0, - 0,128,66,48,5,0,64,20,33,144,80,2, - 4,0,49,142,0,0,0,0,148,49,192,8, - 33,32,64,2,2,131,2,60,16,233,66,36, - 33,128,98,2,6,0,17,38,33,32,32,2, - 0,163,5,60,224,5,165,52,168,71,192,12, - 4,0,6,36,9,0,64,16,33,32,32,2, - 224,129,133,39,168,71,192,12,4,0,6,36, - 5,0,64,16,10,0,17,38,3,131,3,60, - 241,49,192,8,88,17,99,36,10,0,17,38, - 33,32,32,2,2,131,5,60,212,4,165,36, - 168,71,192,12,6,0,6,36,9,0,64,16, - 33,32,32,2,228,129,133,39,168,71,192,12, - 6,0,6,36,4,0,64,16,0,0,0,0, - 3,131,3,60,241,49,192,8,88,17,99,36, - 0,0,3,150,255,255,2,52,4,0,98,16, - 30,0,7,38,3,131,3,60,241,49,192,8, - 88,17,99,36,2,0,2,150,2,131,5,60, - 16,233,165,36,0,26,2,0,2,18,2,0, - 37,24,98,0,255,255,99,48,226,255,104,36, - 35,16,229,0,35,16,130,2,42,16,72,0, - 4,0,64,16,0,0,0,0,3,131,3,60, - 241,49,192,8,96,17,99,36,16,0,2,150, - 0,0,0,0,0,26,2,0,2,18,2,0, - 37,24,98,0,255,255,99,48,15,144,2,52, - 11,0,98,20,33,32,160,2,3,131,3,60, - 100,17,99,36,0,0,98,140,33,48,0,2, - 16,0,168,175,1,0,66,36,54,49,192,12, - 0,0,98,172,245,49,192,8,0,0,0,0, - 3,131,3,60,92,17,99,36,0,0,98,140, - 0,0,0,0,1,0,66,36,0,0,98,172, - 48,0,191,143,44,0,181,143,40,0,180,143, - 36,0,179,143,32,0,178,143,28,0,177,143, - 24,0,176,143,8,0,224,3,56,0,189,39, - 0,0,0,0,0,0,0,0,232,255,189,39, - 16,0,191,175,13,8,192,12,0,8,4,36, - 8,133,130,175,16,0,191,143,24,0,189,39, - 8,0,224,3,0,0,0,0,232,255,189,39, - 45,0,128,16,16,0,191,175,240,129,133,143, - 7,0,130,36,194,16,2,0,10,0,160,20, - 1,0,70,36,8,133,133,143,0,133,130,39, - 0,133,133,175,0,0,162,172,0,8,2,36, - 240,129,133,175,2,131,1,60,20,211,32,172, - 4,0,162,172,0,0,164,140,0,0,0,0, - 4,0,131,140,0,0,0,0,43,16,102,0, - 14,0,64,20,0,0,0,0,5,0,102,20, - 35,16,102,0,0,0,130,140,0,0,0,0, - 43,50,192,8,0,0,162,172,4,0,130,172, - 192,16,2,0,33,32,130,0,4,0,134,172, - 240,129,133,175,57,50,192,8,8,0,130,36, - 240,129,130,143,0,0,0,0,4,0,130,16, - 33,40,128,0,0,0,132,140,28,50,192,8, - 0,0,0,0,2,131,4,60,15,63,192,12, - 64,148,132,36,33,16,0,0,16,0,191,143, - 24,0,189,39,8,0,224,3,0,0,0,0, - 56,0,128,16,248,255,132,36,240,129,133,143, - 0,0,0,0,78,50,192,8,43,16,164,0, - 0,0,163,140,0,0,0,0,43,16,163,0, - 5,0,64,20,43,16,164,0,12,0,64,20, - 43,16,131,0,10,0,64,20,0,0,0,0, - 33,40,96,0,43,16,164,0,244,255,64,16, - 0,0,0,0,0,0,162,140,0,0,0,0, - 43,16,130,0,239,255,64,16,0,0,0,0, - 4,0,134,140,0,0,163,140,192,16,6,0, - 33,16,130,0,11,0,67,20,0,0,0,0, - 4,0,98,140,0,0,0,0,33,16,194,0, - 4,0,130,172,0,0,162,140,0,0,0,0, - 0,0,66,140,0,0,0,0,102,50,192,8, - 0,0,130,172,0,0,131,172,4,0,163,140, - 0,0,0,0,192,16,3,0,33,16,162,0, - 9,0,68,20,0,0,0,0,4,0,130,140, - 0,0,0,0,33,16,98,0,4,0,162,172, - 0,0,130,140,0,0,0,0,117,50,192,8, - 0,0,162,172,0,0,164,172,240,129,133,175, - 8,0,224,3,0,0,0,0,232,255,189,39, - 16,0,191,175,0,50,192,12,0,0,0,0, - 178,45,192,12,33,32,0,0,16,0,191,143, - 24,0,189,39,8,0,224,3,0,0,0,0, - 1,0,3,36,5,0,195,20,255,255,2,36, - 0,0,226,140,0,0,0,0,43,16,2,0, - 35,16,2,0,8,0,224,3,0,0,0,0, - 224,255,189,39,16,0,176,175,33,128,224,0, - 20,0,177,175,48,0,177,143,1,0,2,36, - 5,0,162,20,24,0,191,175,0,0,194,140, - 0,0,0,0,8,0,64,16,0,0,0,0, - 11,0,2,36,33,32,0,2,33,40,32,2, - 48,72,192,12,96,0,2,174,1,0,66,36, - 100,0,2,174,17,0,34,146,0,0,0,0, - 1,0,66,52,17,0,34,162,24,0,191,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 32,0,189,39,8,0,224,3,0,0,0,0, - 16,0,163,143,0,0,0,0,17,0,98,144, - 0,0,0,0,2,0,66,52,8,0,224,3, - 17,0,98,160,8,0,224,3,0,0,0,0, - 224,255,189,39,16,0,176,175,33,128,128,0, - 244,129,131,151,255,0,2,36,28,0,191,175, - 24,0,178,175,20,0,177,175,4,0,2,174, - 60,0,0,174,1,0,98,36,244,129,130,167, - 10,0,3,166,3,0,162,136,0,0,162,152, - 7,0,163,136,4,0,163,152,11,0,164,136, - 8,0,164,152,15,0,167,136,12,0,167,152, - 15,0,2,170,12,0,2,186,19,0,3,170, - 16,0,3,186,23,0,4,170,20,0,4,186, - 27,0,7,170,24,0,7,186,3,0,194,136, - 0,0,194,152,7,0,195,136,4,0,195,152, - 11,0,196,136,8,0,196,152,15,0,197,136, - 12,0,197,152,31,0,2,170,28,0,2,186, - 35,0,3,170,32,0,3,186,39,0,4,170, - 36,0,4,186,43,0,5,170,40,0,5,186, - 80,0,2,142,76,0,3,142,0,0,0,0, - 35,16,67,0,255,255,81,48,88,0,3,150, - 3,0,2,36,13,0,98,16,0,0,0,0, - 2,131,18,60,160,204,82,38,156,71,192,12, - 33,32,64,2,7,0,81,20,33,32,64,2, - 76,0,5,142,0,0,0,0,168,71,192,12, - 33,48,32,2,21,0,64,16,33,16,0,0, - 2,131,18,60,192,204,82,38,156,71,192,12, - 33,32,64,2,7,0,81,20,33,32,64,2, - 76,0,5,142,0,0,0,0,168,71,192,12, - 33,48,32,2,9,0,64,16,33,16,0,0, - 3,131,3,60,132,17,99,36,0,0,98,140, - 1,0,4,36,1,0,66,36,178,45,192,12, - 0,0,98,172,1,0,2,36,28,0,191,143, - 24,0,178,143,20,0,177,143,16,0,176,143, - 8,0,224,3,32,0,189,39,0,0,0,0, - 0,0,0,0,224,255,189,39,20,0,177,175, - 33,136,224,0,16,0,176,175,48,0,176,143, - 24,0,191,175,156,71,192,12,33,32,32,2, - 0,0,2,174,33,16,32,2,24,0,191,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 32,0,189,39,8,0,224,3,33,16,224,0, - 0,0,227,140,204,204,2,60,205,204,66,52, - 25,0,98,0,16,32,0,0,0,0,0,0, - 0,0,0,0,8,0,224,3,194,16,4,0, - 224,255,189,39,16,0,176,175,33,128,224,0, - 33,32,0,2,33,40,0,0,20,0,177,175, - 48,0,177,143,24,0,191,175,208,71,192,12, - 16,0,6,36,2,0,64,20,35,16,80,0, - 16,0,2,36,0,0,34,174,33,16,0,2, - 24,0,191,143,20,0,177,143,16,0,176,143, - 8,0,224,3,32,0,189,39,232,255,189,39, - 40,0,164,143,44,0,165,143,16,0,191,175, - 205,59,192,12,0,0,0,0,16,0,191,143, - 24,0,189,39,8,0,224,3,0,0,0,0, - 232,255,189,39,40,0,164,143,44,0,165,143, - 16,0,191,175,239,59,192,12,0,0,0,0, - 16,0,191,143,24,0,189,39,8,0,224,3, - 0,0,0,0,232,255,189,39,40,0,164,143, - 44,0,165,143,16,0,191,175,17,60,192,12, - 0,0,0,0,16,0,191,143,24,0,189,39, - 8,0,224,3,0,0,0,0,8,0,224,3, - 33,16,224,0,0,0,226,140,8,0,224,3, - 0,0,0,0,216,255,189,39,24,0,176,175, - 56,0,176,143,32,0,191,175,28,0,177,175, - 36,0,2,142,1,0,3,36,20,0,81,140, - 187,0,163,20,0,0,0,0,0,0,195,140, - 0,0,0,0,183,0,96,16,0,0,0,0, - 32,133,130,143,0,0,0,0,43,16,67,0, - 178,0,64,20,255,255,104,36,64,18,8,0, - 2,131,3,60,192,246,99,36,33,40,67,0, - 255,255,132,36,22,0,130,44,170,0,64,16, - 128,16,4,0,2,131,1,60,33,8,34,0, - 144,148,34,140,0,0,0,0,8,0,64,0, - 0,0,0,0,2,0,2,36,16,0,2,162, - 17,0,2,146,0,0,195,140,0,0,0,0, - 15,52,192,8,2,0,66,52,33,32,32,2, - 17,0,3,146,4,0,2,36,16,0,2,162, - 40,0,0,166,44,0,17,174,2,0,99,52, - 156,71,192,12,17,0,3,162,255,255,66,48, - 33,16,34,2,48,0,2,174,40,52,192,8, - 52,0,0,166,17,0,3,146,2,0,2,36, - 16,0,2,162,243,51,192,8,40,0,17,174, - 17,0,3,146,2,0,2,36,16,0,2,162, - 243,51,192,8,40,0,17,174,66,0,2,36, - 13,0,0,21,16,0,2,162,24,133,132,143, - 0,0,0,0,64,25,4,0,35,24,100,0, - 128,17,3,0,35,16,67,0,192,16,2,0, - 33,16,68,0,128,24,2,0,33,16,67,0, - 178,51,192,8,192,17,2,0,152,0,2,60, - 128,150,66,52,40,0,2,174,17,0,2,146, - 0,0,0,0,199,51,192,8,2,0,66,52, - 17,0,3,146,4,0,2,36,16,0,2,162, - 20,0,162,36,44,0,2,174,26,0,162,36, - 40,0,0,166,48,0,2,174,243,51,192,8, - 52,0,0,166,2,0,2,36,16,0,2,162, - 17,0,2,146,1,0,3,36,40,0,3,174, - 2,0,66,52,40,52,192,8,17,0,2,162, - 17,0,3,146,0,0,0,0,241,51,192,8, - 67,0,2,36,65,0,2,36,16,0,2,162, - 17,0,2,146,168,0,163,140,0,0,0,0, - 15,52,192,8,2,0,66,52,65,0,2,36, - 16,0,2,162,156,0,162,140,0,1,164,140, - 22,52,192,8,0,0,0,0,65,0,2,36, - 16,0,2,162,17,0,2,146,0,1,163,140, - 0,0,0,0,15,52,192,8,2,0,66,52, - 65,0,2,36,16,0,2,162,17,0,2,146, - 164,0,163,140,0,0,0,0,15,52,192,8, - 2,0,66,52,65,0,2,36,16,0,2,162, - 17,0,2,146,160,0,163,140,0,0,0,0, - 15,52,192,8,2,0,66,52,17,0,3,146, - 65,0,2,36,16,0,2,162,40,0,0,174, - 2,0,99,52,40,52,192,8,17,0,3,162, - 65,0,2,36,16,0,2,162,172,0,162,140, - 4,1,164,140,22,52,192,8,0,0,0,0, - 65,0,2,36,16,0,2,162,17,0,2,146, - 4,1,163,140,0,0,0,0,15,52,192,8, - 2,0,66,52,65,0,2,36,16,0,2,162, - 17,0,2,146,184,0,163,140,0,0,0,0, - 15,52,192,8,2,0,66,52,65,0,2,36, - 16,0,2,162,17,0,2,146,188,0,163,140, - 2,0,66,52,40,0,3,174,40,52,192,8, - 17,0,2,162,66,0,2,36,16,0,2,162, - 172,0,162,140,176,0,164,140,17,0,3,146, - 35,16,68,0,2,0,99,52,40,0,2,174, - 40,52,192,8,17,0,3,162,16,0,160,175, - 33,32,224,0,33,40,0,2,2,131,7,60, - 96,204,231,36,226,76,192,12,2,0,6,36, - 40,52,192,8,0,0,0,0,33,32,224,0, - 200,76,192,12,33,40,0,2,32,0,191,143, - 28,0,177,143,24,0,176,143,8,0,224,3, - 40,0,189,39,224,255,189,39,16,0,176,175, - 33,128,224,0,20,0,177,175,48,0,177,143, - 1,0,2,36,10,0,162,20,24,0,191,175, - 0,0,198,140,0,0,0,0,6,0,192,16, - 0,0,0,0,32,133,130,143,0,0,0,0, - 43,16,70,0,5,0,64,16,7,0,2,36, - 33,32,0,2,33,40,32,2,70,52,192,8, - 11,0,2,36,7,0,130,16,33,32,0,2, - 33,40,32,2,17,0,2,36,48,72,192,12, - 96,0,2,174,1,0,66,36,100,0,2,174, - 17,0,34,146,0,0,0,0,1,0,66,52, - 17,0,34,162,24,0,191,143,20,0,177,143, - 16,0,176,143,8,0,224,3,32,0,189,39, - 208,255,189,39,32,0,176,175,64,0,176,143, - 36,0,177,175,33,136,224,0,4,0,160,20, - 40,0,191,175,1,0,2,36,106,52,192,8, - 24,0,162,175,0,0,198,140,32,133,130,143, - 0,0,0,0,43,16,194,0,3,0,64,16, - 1,0,194,36,106,52,192,8,24,0,162,175, - 17,0,2,146,0,0,0,0,18,0,66,52, - 116,52,192,8,17,0,2,162,16,0,176,175, - 1,0,5,36,24,0,166,39,97,51,192,12, - 33,56,32,2,33,32,32,2,33,40,0,2, - 1,0,6,36,253,76,192,12,24,0,167,39, - 40,0,191,143,36,0,177,143,32,0,176,143, - 8,0,224,3,48,0,189,39,16,0,163,143, - 1,0,2,36,13,0,162,20,14,0,2,36, - 0,0,198,140,0,0,0,0,9,0,192,16, - 0,0,0,0,32,133,130,143,0,0,0,0, - 43,16,70,0,4,0,64,20,14,0,2,36, - 7,0,2,36,2,0,130,16,14,0,2,36, - 96,0,226,172,17,0,98,144,0,0,0,0, - 2,0,66,52,8,0,224,3,17,0,98,160, - 16,0,162,143,0,0,0,0,8,0,224,3, - 0,0,226,172,0,0,226,140,8,0,224,3, - 0,0,0,0,232,255,189,39,40,0,168,143, - 1,0,2,36,61,0,162,20,16,0,191,175, - 0,0,197,140,0,0,0,0,57,0,160,16, - 0,0,0,0,32,133,130,143,0,0,0,0, - 43,16,69,0,52,0,64,20,255,255,132,36, - 5,0,130,44,49,0,64,16,128,16,4,0, - 2,131,1,60,33,8,34,0,232,148,34,140, - 0,0,0,0,8,0,64,0,0,0,0,0, - 64,0,2,36,16,0,2,161,0,163,5,60, - 220,5,165,52,3,0,162,136,0,0,162,152, - 0,0,0,0,43,0,2,169,40,0,2,185, - 17,0,2,145,0,0,0,0,213,52,192,8, - 2,0,66,52,2,0,2,36,16,0,2,161, - 17,0,2,145,0,0,195,140,0,0,0,0, - 198,52,192,8,2,0,66,52,64,0,2,36, - 16,0,2,161,17,0,2,145,128,132,131,143, - 2,0,66,52,40,0,3,173,218,52,192,8, - 17,0,2,161,2,0,2,36,16,0,2,161, - 17,0,2,145,0,0,0,0,211,52,192,8, - 1,0,3,36,2,0,2,36,16,0,2,161, - 17,0,2,145,220,5,3,36,40,0,3,173, - 2,0,66,52,218,52,192,8,17,0,2,161, - 33,32,224,0,200,76,192,12,33,40,0,1, - 16,0,191,143,24,0,189,39,8,0,224,3, - 0,0,0,0,208,255,189,39,32,0,176,175, - 64,0,176,143,36,0,177,175,33,136,224,0, - 4,0,160,20,40,0,191,175,1,0,2,36, - 245,52,192,8,24,0,162,175,0,0,198,140, - 32,133,130,143,0,0,0,0,43,16,194,0, - 3,0,64,16,1,0,194,36,245,52,192,8, - 24,0,162,175,17,0,2,146,0,0,0,0, - 18,0,66,52,255,52,192,8,17,0,2,162, - 16,0,176,175,1,0,5,36,24,0,166,39, - 150,52,192,12,33,56,32,2,33,32,32,2, - 33,40,0,2,1,0,6,36,253,76,192,12, - 24,0,167,39,40,0,191,143,36,0,177,143, - 32,0,176,143,8,0,224,3,48,0,189,39, - 232,255,189,39,40,0,165,143,16,0,191,175, - 200,76,192,12,33,32,224,0,16,0,191,143, - 24,0,189,39,8,0,224,3,0,0,0,0, - 16,0,163,143,14,0,2,36,96,0,226,172, - 17,0,98,144,0,0,0,0,2,0,66,52, - 8,0,224,3,17,0,98,160,224,255,189,39, - 16,0,176,175,33,128,224,0,17,0,2,36, - 24,0,191,175,20,0,177,175,96,0,2,174, - 48,0,177,143,33,32,0,2,48,72,192,12, - 33,40,32,2,1,0,66,36,100,0,2,174, - 17,0,34,146,0,0,0,0,1,0,66,52, - 17,0,34,162,24,0,191,143,20,0,177,143, - 16,0,176,143,8,0,224,3,32,0,189,39, - 16,0,163,143,0,0,0,0,17,0,98,144, - 0,0,0,0,18,0,66,52,8,0,224,3, - 17,0,98,160,8,0,224,3,33,16,224,0, - 224,255,189,39,48,0,168,143,1,0,2,36, - 114,0,162,20,24,0,191,175,0,0,195,140, - 0,0,0,0,110,0,96,16,0,0,0,0, - 32,133,130,143,0,0,0,0,43,16,67,0, - 105,0,64,20,255,255,98,36,64,18,2,0, - 2,131,3,60,192,246,99,36,33,24,67,0, - 255,255,132,36,17,0,130,44,97,0,64,16, - 128,16,4,0,2,131,1,60,33,8,34,0, - 0,149,34,140,0,0,0,0,8,0,64,0, - 0,0,0,0,2,0,2,36,16,0,2,161, - 17,0,2,145,0,0,195,140,0,0,0,0, - 140,53,192,8,2,0,66,52,2,0,2,36, - 16,0,2,161,44,0,99,140,17,0,2,145, - 16,0,99,140,0,0,0,0,101,53,192,8, - 2,0,66,52,2,0,2,36,16,0,2,161, - 44,0,99,140,17,0,2,145,12,0,99,140, - 2,0,66,52,17,0,2,161,173,53,192,8, - 40,0,3,173,2,0,2,36,16,0,2,161, - 17,0,2,145,212,0,99,140,0,0,0,0, - 140,53,192,8,2,0,66,52,2,0,2,36, - 16,0,2,161,17,0,2,145,192,0,99,140, - 0,0,0,0,140,53,192,8,2,0,66,52, - 2,0,2,36,16,0,2,161,17,0,2,145, - 208,0,99,140,0,0,0,0,140,53,192,8, - 2,0,66,52,2,0,2,36,16,0,2,161, - 204,0,98,140,184,0,100,140,17,0,3,145, - 33,16,68,0,2,0,99,52,40,0,2,173, - 173,53,192,8,17,0,3,161,2,0,2,36, - 16,0,2,161,17,0,2,145,196,0,99,140, - 2,0,66,52,40,0,3,173,173,53,192,8, - 17,0,2,161,17,0,3,145,2,0,2,36, - 16,0,2,161,40,0,0,173,2,0,99,52, - 173,53,192,8,17,0,3,161,2,0,2,36, - 16,0,2,161,44,0,100,140,17,0,2,145, - 20,0,131,140,24,0,132,140,2,0,66,52, - 17,0,2,161,33,24,100,0,173,53,192,8, - 40,0,3,173,16,0,160,175,33,32,224,0, - 33,40,0,1,2,131,7,60,104,204,231,36, - 226,76,192,12,11,0,6,36,173,53,192,8, - 0,0,0,0,33,32,224,0,200,76,192,12, - 33,40,0,1,24,0,191,143,32,0,189,39, - 8,0,224,3,0,0,0,0,208,255,189,39, - 32,0,176,175,64,0,176,143,36,0,177,175, - 33,136,224,0,4,0,160,20,40,0,191,175, - 1,0,2,36,200,53,192,8,24,0,162,175, - 0,0,198,140,32,133,130,143,0,0,0,0, - 43,16,194,0,3,0,64,16,1,0,194,36, - 200,53,192,8,24,0,162,175,17,0,2,146, - 0,0,0,0,18,0,66,52,210,53,192,8, - 17,0,2,162,16,0,176,175,1,0,5,36, - 24,0,166,39,52,53,192,12,33,56,32,2, - 33,32,32,2,33,40,0,2,1,0,6,36, - 253,76,192,12,24,0,167,39,40,0,191,143, - 36,0,177,143,32,0,176,143,8,0,224,3, - 48,0,189,39,0,0,226,140,8,0,224,3, - 0,0,0,0,3,131,2,60,28,18,66,148, - 0,0,0,0,2,0,66,48,2,0,64,16, - 2,0,3,36,1,0,3,36,8,0,224,3, - 33,16,96,0,232,255,189,39,40,0,164,143, - 16,0,191,175,1,0,132,56,186,59,192,12, - 1,0,132,44,16,0,191,143,24,0,189,39, - 8,0,224,3,0,0,0,0,16,0,163,143, - 6,0,2,36,0,0,98,172,8,0,224,3, - 33,16,224,0,224,255,189,39,48,0,168,143, - 1,0,2,36,52,0,162,20,24,0,191,175, - 0,0,197,140,0,0,0,0,48,0,160,16, - 0,0,0,0,24,133,130,143,0,0,0,0, - 43,16,69,0,43,0,64,20,255,255,132,36, - 5,0,130,44,40,0,64,16,128,16,4,0, - 2,131,1,60,33,8,34,0,72,149,34,140, - 0,0,0,0,8,0,64,0,0,0,0,0, - 2,0,2,36,16,0,2,161,17,0,2,145, - 0,0,195,140,2,0,66,52,40,0,3,173, - 45,54,192,8,17,0,2,161,2,0,2,36, - 16,0,2,161,0,0,194,140,17,0,3,145, - 1,0,66,36,2,0,99,52,40,0,2,173, - 45,54,192,8,17,0,3,161,16,0,160,175, - 33,32,224,0,33,40,0,1,2,131,7,60, - 148,204,231,36,226,76,192,12,2,0,6,36, - 45,54,192,8,0,0,0,0,17,0,3,145, - 2,0,2,36,16,0,2,161,40,0,0,173, - 2,0,99,52,45,54,192,8,17,0,3,161, - 33,32,224,0,200,76,192,12,33,40,0,1, - 24,0,191,143,32,0,189,39,8,0,224,3, - 0,0,0,0,208,255,189,39,32,0,176,175, - 64,0,176,143,36,0,177,175,33,136,224,0, - 4,0,160,20,40,0,191,175,1,0,2,36, - 72,54,192,8,24,0,162,175,0,0,198,140, - 24,133,130,143,0,0,0,0,43,16,194,0, - 3,0,64,16,1,0,194,36,72,54,192,8, - 24,0,162,175,17,0,2,146,0,0,0,0, - 18,0,66,52,82,54,192,8,17,0,2,162, - 16,0,176,175,1,0,5,36,24,0,166,39, - 242,53,192,12,33,56,32,2,33,32,32,2, - 33,40,0,2,1,0,6,36,253,76,192,12, - 24,0,167,39,40,0,191,143,36,0,177,143, - 32,0,176,143,8,0,224,3,48,0,189,39, - 0,0,226,148,8,0,224,3,0,0,0,0, - 8,0,224,3,33,16,224,0,16,0,163,143, - 8,0,2,36,0,0,98,172,8,0,224,3, - 33,16,224,0,224,255,189,39,16,0,176,175, - 48,0,176,143,1,0,2,36,24,0,191,175, - 126,0,162,20,20,0,177,175,0,0,198,140, - 0,0,0,0,122,0,192,16,0,0,0,0, - 24,133,130,143,0,0,0,0,43,16,70,0, - 117,0,64,20,192,17,6,0,3,131,3,60, - 16,13,99,36,33,136,67,0,255,255,132,36, - 10,0,130,44,110,0,64,16,128,16,4,0, - 2,131,1,60,33,8,34,0,96,149,34,140, - 0,0,0,0,8,0,64,0,0,0,0,0, - 17,0,3,146,2,0,2,36,16,0,2,162, - 211,54,192,8,40,0,6,174,2,0,2,36, - 16,0,2,162,0,0,34,150,17,0,3,146, - 0,0,0,0,143,54,192,8,2,18,2,0, - 2,0,2,36,16,0,2,162,4,0,34,142, - 17,0,3,146,1,0,66,36,2,0,99,52, - 40,0,2,174,232,54,192,8,17,0,3,162, - 2,0,2,36,16,0,2,162,4,0,34,142, - 0,0,0,0,2,0,64,16,2,0,3,36, - 1,0,3,36,17,0,2,146,40,0,3,174, - 2,0,66,52,232,54,192,8,17,0,2,162, - 2,0,2,36,16,0,2,162,17,0,2,146, - 8,0,35,142,0,0,0,0,226,54,192,8, - 2,0,66,52,9,50,192,12,8,0,4,36, - 33,48,64,0,15,0,34,138,12,0,34,154, - 19,0,35,138,16,0,35,154,3,0,194,168, - 0,0,194,184,7,0,195,168,196,54,192,8, - 4,0,195,184,2,0,2,36,16,0,2,162, - 17,0,2,146,20,0,35,142,0,0,0,0, - 226,54,192,8,2,0,66,52,9,50,192,12, - 8,0,4,36,33,48,64,0,27,0,34,138, - 24,0,34,154,31,0,35,138,28,0,35,154, - 3,0,194,168,0,0,194,184,7,0,195,168, - 4,0,195,184,0,0,194,148,0,0,0,0, - 0,26,2,0,2,18,2,0,37,24,98,0, - 0,0,195,164,17,0,3,146,4,0,2,36, - 16,0,2,162,1,0,2,36,40,0,2,166, - 8,0,194,36,44,0,6,174,48,0,2,174, - 52,0,0,166,2,0,99,52,232,54,192,8, - 17,0,3,162,2,0,2,36,16,0,2,162, - 17,0,2,146,32,0,35,150,0,0,0,0, - 226,54,192,8,2,0,66,52,2,0,2,36, - 16,0,2,162,17,0,2,146,104,0,35,142, - 2,0,66,52,40,0,3,174,232,54,192,8, - 17,0,2,162,33,32,224,0,200,76,192,12, - 33,40,0,2,24,0,191,143,20,0,177,143, - 16,0,176,143,8,0,224,3,32,0,189,39, - 224,255,189,39,16,0,176,175,33,128,224,0, - 20,0,177,175,48,0,177,143,1,0,2,36, - 10,0,162,20,24,0,191,175,0,0,198,140, - 0,0,0,0,6,0,192,16,0,0,0,0, - 24,133,130,143,0,0,0,0,43,16,70,0, - 5,0,64,16,2,0,2,36,33,32,0,2, - 33,40,32,2,13,55,192,8,11,0,2,36, - 14,0,130,16,2,0,130,44,5,0,64,20, - 6,0,130,44,3,0,64,16,4,0,130,44, - 8,0,64,16,0,0,0,0,33,32,0,2, - 33,40,32,2,17,0,2,36,48,72,192,12, - 96,0,2,174,1,0,66,36,100,0,2,174, - 17,0,34,146,0,0,0,0,1,0,66,52, - 17,0,34,162,24,0,191,143,20,0,177,143, - 16,0,176,143,8,0,224,3,32,0,189,39, - 208,255,189,39,32,0,176,175,64,0,176,143, - 36,0,177,175,33,136,224,0,4,0,160,20, - 40,0,191,175,1,0,2,36,49,55,192,8, - 24,0,162,175,0,0,198,140,24,133,130,143, - 0,0,0,0,43,16,194,0,3,0,64,16, - 1,0,194,36,49,55,192,8,24,0,162,175, - 17,0,2,146,0,0,0,0,18,0,66,52, - 59,55,192,8,17,0,2,162,16,0,176,175, - 1,0,5,36,24,0,166,39,97,54,192,12, - 33,56,32,2,33,32,32,2,33,40,0,2, - 1,0,6,36,253,76,192,12,24,0,167,39, - 40,0,191,143,36,0,177,143,32,0,176,143, - 8,0,224,3,48,0,189,39,232,255,189,39, - 33,64,128,0,16,0,176,175,40,0,176,143, - 1,0,2,36,57,0,162,20,20,0,191,175, - 0,0,196,140,0,0,0,0,54,0,128,16, - 14,0,2,36,24,133,130,143,0,0,0,0, - 43,16,68,0,49,0,64,20,14,0,2,36, - 192,17,4,0,3,131,3,60,16,13,99,36, - 33,48,67,0,4,0,2,36,21,0,2,17, - 5,0,2,45,5,0,64,16,2,0,2,36, - 8,0,2,17,14,0,2,36,129,55,192,8, - 96,0,226,172,5,0,2,36,28,0,2,17, - 14,0,2,36,129,55,192,8,96,0,226,172, - 0,0,195,144,0,0,0,0,0,0,195,164, - 40,0,2,142,0,0,0,0,0,18,2,0, - 37,24,98,0,129,55,192,8,0,0,195,164, - 40,0,3,142,0,0,0,0,5,0,101,16, - 2,0,2,36,7,0,98,16,14,0,2,36, - 129,55,192,8,96,0,226,172,187,42,192,12, - 1,0,5,36,129,55,192,8,0,0,0,0, - 187,42,192,12,33,40,0,0,129,55,192,8, - 0,0,0,0,40,0,2,142,0,0,0,0, - 129,55,192,8,8,0,194,172,14,0,2,36, - 96,0,226,172,17,0,2,146,0,0,0,0, - 2,0,66,52,17,0,2,162,20,0,191,143, - 16,0,176,143,8,0,224,3,24,0,189,39, - 216,255,189,39,20,0,177,175,33,136,128,0, - 28,0,179,175,33,152,160,0,24,0,178,175, - 33,144,224,0,16,0,176,175,56,0,176,143, - 1,0,2,36,46,0,98,22,32,0,191,175, - 0,0,196,140,0,0,0,0,42,0,128,16, - 0,0,0,0,58,25,192,12,0,0,0,0, - 33,32,64,0,37,0,128,16,2,0,2,36, - 11,0,34,18,3,0,34,46,5,0,64,16, - 3,0,2,36,15,0,51,18,4,0,2,36, - 195,55,192,8,33,32,64,2,20,0,34,18, - 33,32,64,2,195,55,192,8,0,0,0,0, - 2,0,2,36,16,0,2,162,17,0,2,146, - 10,0,131,132,2,0,66,52,40,0,3,174, - 197,55,192,8,17,0,2,162,17,0,3,146, - 16,0,2,162,4,0,130,36,44,0,2,174, - 10,0,130,36,40,0,0,166,48,0,2,174, - 191,55,192,8,52,0,0,166,17,0,3,146, - 2,0,2,36,16,0,2,162,40,0,17,174, - 2,0,99,52,197,55,192,8,17,0,3,162, - 33,32,64,2,200,76,192,12,33,40,0,2, - 32,0,191,143,28,0,179,143,24,0,178,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 40,0,189,39,208,255,189,39,32,0,176,175, - 64,0,176,143,40,0,178,175,33,144,128,0, - 36,0,177,175,33,136,224,0,3,0,160,20, - 44,0,191,175,218,55,192,8,1,0,2,36, - 0,0,194,140,0,0,0,0,1,0,66,36, - 24,0,162,175,24,0,164,143,58,25,192,12, - 0,0,0,0,6,0,64,20,33,32,64,2, - 17,0,2,146,0,0,0,0,18,0,66,52, - 239,55,192,8,17,0,2,162,16,0,176,175, - 1,0,5,36,24,0,166,39,137,55,192,12, - 33,56,32,2,33,32,32,2,33,40,0,2, - 1,0,6,36,253,76,192,12,24,0,167,39, - 44,0,191,143,40,0,178,143,36,0,177,143, - 32,0,176,143,8,0,224,3,48,0,189,39, - 232,255,189,39,40,0,168,143,1,0,2,36, - 63,0,162,20,16,0,191,175,0,0,195,140, - 0,0,0,0,59,0,96,16,0,0,0,0, - 24,133,130,143,0,0,0,0,43,16,67,0, - 54,0,64,20,64,18,3,0,2,131,3,60, - 192,246,99,36,33,24,67,0,255,255,132,36, - 5,0,130,44,47,0,64,16,128,16,4,0, - 2,131,1,60,33,8,34,0,136,149,34,140, - 0,0,0,0,8,0,64,0,0,0,0,0, - 2,0,2,36,16,0,2,161,17,0,2,145, - 0,0,195,140,0,0,0,0,43,56,192,8, - 2,0,66,52,2,0,2,36,16,0,2,161, - 17,0,2,145,220,5,3,36,40,0,3,173, - 2,0,66,52,59,56,192,8,17,0,2,161, - 65,0,2,36,16,0,2,161,17,0,2,145, - 156,0,99,140,0,0,0,0,43,56,192,8, - 2,0,66,52,65,0,2,36,16,0,2,161, - 17,0,2,145,172,0,99,140,2,0,66,52, - 40,0,3,173,59,56,192,8,17,0,2,161, - 65,0,2,36,16,0,2,161,156,0,98,140, - 252,0,100,140,17,0,3,145,35,16,68,0, - 2,0,99,52,40,0,2,173,59,56,192,8, - 17,0,3,161,33,32,224,0,200,76,192,12, - 33,40,0,1,16,0,191,143,24,0,189,39, - 8,0,224,3,0,0,0,0,208,255,189,39, - 32,0,176,175,64,0,176,143,36,0,177,175, - 33,136,224,0,4,0,160,20,40,0,191,175, - 1,0,2,36,86,56,192,8,24,0,162,175, - 0,0,198,140,24,133,130,143,0,0,0,0, - 43,16,194,0,3,0,64,16,1,0,194,36, - 86,56,192,8,24,0,162,175,17,0,2,146, - 0,0,0,0,18,0,66,52,96,56,192,8, - 17,0,2,162,16,0,176,175,1,0,5,36, - 24,0,166,39,245,55,192,12,33,56,32,2, - 33,32,32,2,33,40,0,2,1,0,6,36, - 253,76,192,12,24,0,167,39,40,0,191,143, - 36,0,177,143,32,0,176,143,8,0,224,3, - 48,0,189,39,0,0,0,0,0,0,0,0, - 0,0,0,0,200,255,189,39,72,0,163,143, - 44,0,177,175,33,136,128,0,20,0,165,175, - 33,40,224,0,2,131,2,60,172,210,66,140, - 152,132,135,143,33,32,0,0,48,0,191,175, - 40,0,176,175,24,0,160,175,28,0,160,175, - 36,0,160,175,16,0,162,175,104,77,192,12, - 32,0,163,175,33,128,64,0,3,0,0,22, - 33,32,0,2,143,56,192,8,33,16,0,0, - 197,80,192,12,33,40,32,2,255,255,3,36, - 5,0,67,20,0,0,0,0,167,83,192,12, - 33,32,0,2,143,56,192,8,33,16,0,0, - 167,83,192,12,33,32,0,2,8,0,34,142, - 4,0,35,142,0,0,0,0,35,16,67,0, - 255,255,66,48,48,0,191,143,44,0,177,143, - 40,0,176,143,8,0,224,3,56,0,189,39, - 200,255,189,39,44,0,177,175,33,136,128,0, - 72,0,168,143,33,32,0,0,20,0,165,175, - 33,40,224,0,2,131,3,60,172,210,99,140, - 152,132,135,143,1,0,2,36,48,0,191,175, - 40,0,176,175,24,0,162,175,28,0,160,175, - 36,0,160,175,16,0,163,175,104,77,192,12, - 32,0,168,175,33,128,64,0,3,0,0,22, - 33,32,0,2,188,56,192,8,33,16,0,0, - 197,80,192,12,33,40,32,2,255,255,3,36, - 5,0,67,20,0,0,0,0,167,83,192,12, - 33,32,0,2,188,56,192,8,33,16,0,0, - 167,83,192,12,33,32,0,2,8,0,34,142, - 4,0,35,142,0,0,0,0,35,16,67,0, - 255,255,66,48,48,0,191,143,44,0,177,143, - 40,0,176,143,8,0,224,3,56,0,189,39, - 176,255,189,39,44,0,177,175,108,0,177,143, - 68,0,183,175,96,0,183,143,72,0,190,175, - 100,0,190,143,48,0,178,175,33,144,128,0, - 56,0,180,175,33,160,160,0,52,0,179,175, - 33,152,192,0,40,0,176,175,33,128,224,0, - 60,0,181,175,1,0,21,36,76,0,191,175, - 3,0,53,18,64,0,182,175,9,57,192,8, - 255,255,2,36,4,0,6,36,2,131,22,60, - 48,205,214,38,160,132,132,143,104,0,165,143, - 128,32,4,0,80,68,192,12,33,32,150,0, - 33,32,0,0,33,40,0,2,152,132,135,143, - 2,0,2,36,24,0,162,175,160,132,130,143, - 2,131,3,60,172,210,99,140,33,48,96,2, - 20,0,180,175,28,0,160,175,32,0,183,175, - 36,0,181,175,1,0,81,36,104,77,192,12, - 16,0,163,175,33,128,64,0,23,0,0,18, - 33,40,0,0,16,0,190,175,33,32,0,2, - 33,48,32,2,108,84,192,12,33,56,192,2, - 255,255,17,36,13,0,81,16,33,32,0,2, - 197,80,192,12,33,40,64,2,9,0,81,16, - 0,0,0,0,167,83,192,12,33,32,0,2, - 8,0,66,142,4,0,67,142,0,0,0,0, - 35,16,67,0,9,57,192,8,255,255,66,48, - 167,83,192,12,33,32,0,2,33,16,0,0, - 76,0,191,143,72,0,190,143,68,0,183,143, - 64,0,182,143,60,0,181,143,56,0,180,143, - 52,0,179,143,48,0,178,143,44,0,177,143, - 40,0,176,143,8,0,224,3,80,0,189,39, - 176,255,189,39,44,0,177,175,108,0,177,143, - 68,0,183,175,96,0,183,143,72,0,190,175, - 100,0,190,143,48,0,178,175,33,144,128,0, - 56,0,180,175,33,160,160,0,52,0,179,175, - 33,152,192,0,40,0,176,175,33,128,224,0, - 60,0,181,175,1,0,21,36,76,0,191,175, - 3,0,53,18,64,0,182,175,93,57,192,8, - 255,255,2,36,4,0,6,36,2,131,22,60, - 48,205,214,38,160,132,132,143,104,0,165,143, - 128,32,4,0,80,68,192,12,33,32,150,0, - 33,32,0,0,33,40,0,2,152,132,135,143, - 3,0,2,36,24,0,162,175,160,132,130,143, - 2,131,3,60,172,210,99,140,33,48,96,2, - 20,0,180,175,28,0,160,175,32,0,183,175, - 36,0,181,175,1,0,81,36,104,77,192,12, - 16,0,163,175,33,128,64,0,23,0,0,18, - 33,40,0,0,16,0,190,175,33,32,0,2, - 33,48,32,2,108,84,192,12,33,56,192,2, - 255,255,17,36,13,0,81,16,33,32,0,2, - 197,80,192,12,33,40,64,2,9,0,81,16, - 0,0,0,0,167,83,192,12,33,32,0,2, - 8,0,66,142,4,0,67,142,0,0,0,0, - 35,16,67,0,93,57,192,8,255,255,66,48, - 167,83,192,12,33,32,0,2,33,16,0,0, - 76,0,191,143,72,0,190,143,68,0,183,143, - 64,0,182,143,60,0,181,143,56,0,180,143, - 52,0,179,143,48,0,178,143,44,0,177,143, - 40,0,176,143,8,0,224,3,80,0,189,39, - 200,255,189,39,44,0,177,175,33,136,128,0, - 72,0,168,143,33,32,0,0,20,0,165,175, - 33,40,224,0,2,131,3,60,172,210,99,140, - 152,132,135,143,4,0,2,36,48,0,191,175, - 40,0,176,175,24,0,162,175,28,0,160,175, - 36,0,160,175,16,0,163,175,104,77,192,12, - 32,0,168,175,33,128,64,0,3,0,0,22, - 33,32,0,2,145,57,192,8,33,16,0,0, - 197,80,192,12,33,40,32,2,255,255,3,36, - 5,0,67,20,0,0,0,0,167,83,192,12, - 33,32,0,2,145,57,192,8,33,16,0,0, - 167,83,192,12,33,32,0,2,8,0,34,142, - 4,0,35,142,0,0,0,0,35,16,67,0, - 255,255,66,48,48,0,191,143,44,0,177,143, - 40,0,176,143,8,0,224,3,56,0,189,39, - 200,255,189,39,44,0,177,175,33,136,128,0, - 72,0,163,143,33,32,0,0,20,0,165,175, - 33,40,224,0,164,132,135,143,2,131,2,60, - 92,205,66,36,16,0,162,175,6,0,2,36, - 24,0,162,175,1,0,2,36,48,0,191,175, - 40,0,176,175,28,0,162,175,36,0,160,175, - 104,77,192,12,32,0,163,175,33,128,64,0, - 3,0,0,22,33,32,0,2,191,57,192,8, - 33,16,0,0,197,80,192,12,33,40,32,2, - 255,255,3,36,5,0,67,20,0,0,0,0, - 167,83,192,12,33,32,0,2,191,57,192,8, - 33,16,0,0,167,83,192,12,33,32,0,2, - 8,0,34,142,4,0,35,142,0,0,0,0, - 35,16,67,0,255,255,66,48,48,0,191,143, - 44,0,177,143,40,0,176,143,8,0,224,3, - 56,0,189,39,200,255,189,39,44,0,177,175, - 33,136,128,0,72,0,163,143,33,32,0,0, - 20,0,165,175,33,40,224,0,164,132,135,143, - 2,131,2,60,92,205,66,36,16,0,162,175, - 6,0,2,36,24,0,162,175,2,0,2,36, - 48,0,191,175,40,0,176,175,28,0,162,175, - 36,0,160,175,104,77,192,12,32,0,163,175, - 33,128,64,0,3,0,0,22,33,32,0,2, - 237,57,192,8,33,16,0,0,197,80,192,12, - 33,40,32,2,255,255,3,36,5,0,67,20, - 0,0,0,0,167,83,192,12,33,32,0,2, - 237,57,192,8,33,16,0,0,167,83,192,12, - 33,32,0,2,8,0,34,142,4,0,35,142, - 0,0,0,0,35,16,67,0,255,255,66,48, - 48,0,191,143,44,0,177,143,40,0,176,143, - 8,0,224,3,56,0,189,39,0,0,0,0, - 0,0,0,0,224,255,189,39,24,0,178,175, - 33,144,128,0,20,0,177,175,3,131,17,60, - 0,18,49,38,16,0,176,175,33,128,0,0, - 28,0,191,175,208,133,128,175,60,65,192,12, - 33,32,0,2,0,0,34,166,1,0,16,38, - 64,0,2,42,250,255,64,20,2,0,49,38, - 3,131,3,60,18,18,99,144,255,0,2,36, - 3,0,98,16,0,0,0,0,6,0,64,18, - 0,163,4,60,75,59,192,12,32,0,4,36, - 87,59,192,12,255,0,4,36,0,163,4,60, - 220,5,132,52,176,132,133,39,168,71,192,12, - 4,0,6,36,25,0,64,20,0,163,4,60, - 3,131,16,60,20,18,16,38,33,32,0,2, - 176,132,133,39,168,71,192,12,4,0,6,36, - 3,0,64,16,0,163,4,60,7,0,64,18, - 0,0,0,0,220,5,132,52,33,40,0,0, - 144,71,192,12,4,0,6,36,47,58,192,8, - 0,163,4,60,0,163,5,60,220,5,165,52, - 3,0,2,138,0,0,2,154,0,0,0,0, - 3,0,162,168,0,0,162,184,0,163,4,60, - 99,59,192,12,220,5,132,52,0,163,4,60, - 16,6,132,52,176,132,133,39,168,71,192,12, - 4,0,6,36,25,0,64,20,0,163,4,60, - 3,131,16,60,68,18,16,38,33,32,0,2, - 176,132,133,39,168,71,192,12,4,0,6,36, - 3,0,64,16,0,163,4,60,7,0,64,18, - 0,0,0,0,16,6,132,52,33,40,0,0, - 144,71,192,12,4,0,6,36,80,58,192,8, - 0,163,4,60,0,163,5,60,16,6,165,52, - 3,0,2,138,0,0,2,154,0,0,0,0, - 3,0,162,168,0,0,162,184,0,163,4,60, - 119,59,192,12,16,6,132,52,0,163,4,60, - 224,5,132,52,176,132,133,39,168,71,192,12, - 4,0,6,36,25,0,64,20,0,163,4,60, - 3,131,16,60,24,18,16,38,33,32,0,2, - 176,132,133,39,168,71,192,12,4,0,6,36, - 3,0,64,16,0,163,4,60,7,0,64,18, - 0,0,0,0,224,5,132,52,33,40,0,0, - 144,71,192,12,4,0,6,36,113,58,192,8, - 0,163,4,60,0,163,5,60,224,5,165,52, - 3,0,2,138,0,0,2,154,0,0,0,0, - 3,0,162,168,0,0,162,184,0,163,4,60, - 139,59,192,12,224,5,132,52,3,131,3,60, - 28,18,99,36,0,0,98,148,0,0,0,0, - 0,128,66,48,3,0,64,20,1,0,2,36, - 2,0,64,18,0,0,0,0,0,0,98,164, - 0,163,2,60,144,1,66,140,0,0,0,0, - 7,0,64,20,0,0,0,0,3,131,3,60, - 28,18,99,36,0,0,98,148,0,0,0,0, - 146,58,192,8,254,255,66,48,0,163,2,60, - 144,1,66,140,0,0,0,0,7,0,64,24, - 0,0,0,0,3,131,3,60,28,18,99,36, - 0,0,98,148,0,0,0,0,1,0,66,52, - 0,0,98,164,3,131,4,60,28,18,132,148, - 0,0,0,0,159,59,192,12,1,0,132,48, - 3,131,3,60,80,18,99,144,255,0,2,36, - 3,0,98,16,0,0,0,0,5,0,64,18, - 0,0,0,0,2,131,4,60,160,149,132,36, - 205,59,192,12,14,0,5,36,3,131,3,60, - 96,18,99,144,255,0,2,36,3,0,98,16, - 0,0,0,0,5,0,64,18,0,0,0,0, - 2,131,4,60,176,149,132,36,239,59,192,12, - 11,0,5,36,3,131,3,60,112,18,99,144, - 255,0,2,36,3,0,98,16,0,0,0,0, - 5,0,64,18,0,0,0,0,2,131,4,60, - 188,149,132,36,17,60,192,12,15,0,5,36, - 0,163,2,60,140,1,66,140,0,0,0,0, - 7,0,64,16,15,0,2,60,0,163,3,60, - 140,1,99,140,64,66,66,52,43,16,67,0, - 26,0,64,16,0,0,0,0,3,131,3,60, - 64,18,99,140,255,255,2,36,3,0,98,16, - 44,1,2,36,4,0,64,18,0,0,0,0, - 0,163,1,60,221,58,192,8,140,1,34,172, - 5,0,96,20,15,0,4,60,1,0,2,36, - 0,163,1,60,221,58,192,8,140,1,34,172, - 64,66,132,52,43,16,131,0,4,0,64,16, - 0,0,0,0,0,163,1,60,221,58,192,8, - 140,1,36,172,0,163,1,60,140,1,35,172, - 0,163,4,60,140,1,132,140,51,60,192,12, - 0,0,0,0,28,0,191,143,24,0,178,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 32,0,189,39,208,255,189,39,20,0,177,175, - 33,136,128,0,36,0,181,175,33,168,160,0, - 28,0,179,175,33,152,192,0,44,0,191,175, - 40,0,182,175,32,0,180,175,24,0,178,175, - 168,71,192,12,16,0,176,175,76,0,64,16, - 0,0,0,0,3,131,22,60,0,18,214,38, - 35,16,54,2,194,31,2,0,33,16,67,0, - 67,144,2,0,1,0,98,38,194,31,2,0, - 33,16,67,0,67,128,2,0,255,255,20,38, - 64,0,130,46,14,0,64,20,64,0,66,46, - 2,131,4,60,204,149,132,36,180,132,144,39, - 33,40,0,2,2,131,7,60,236,149,231,36, - 15,63,192,12,143,0,6,36,1,0,4,36, - 33,40,0,2,188,7,192,12,143,0,6,36, - 64,0,66,46,14,0,64,20,33,32,32,2, - 2,131,4,60,204,149,132,36,180,132,144,39, - 33,40,0,2,2,131,7,60,20,150,231,36, - 15,63,192,12,144,0,6,36,1,0,4,36, - 33,40,0,2,188,7,192,12,144,0,6,36, - 33,32,32,2,33,40,160,2,80,68,192,12, - 33,48,96,2,64,16,18,0,33,136,86,0, - 33,128,128,2,255,255,2,36,25,0,2,18, - 255,255,20,36,180,132,147,39,33,32,64,2, - 208,133,130,143,1,0,82,38,1,0,66,36, - 208,133,130,175,0,0,37,150,0,0,0,0, - 162,65,192,12,2,0,49,38,10,0,64,20, - 33,40,96,2,2,131,4,60,204,149,132,36, - 188,132,135,39,15,63,192,12,159,0,6,36, - 1,0,4,36,33,40,96,2,188,7,192,12, - 159,0,6,36,255,255,16,38,235,255,20,22, - 33,32,64,2,44,0,191,143,40,0,182,143, - 36,0,181,143,32,0,180,143,28,0,179,143, - 24,0,178,143,20,0,177,143,16,0,176,143, - 8,0,224,3,48,0,189,39,224,255,189,39, - 16,0,164,163,3,131,4,60,18,18,132,36, - 16,0,165,39,24,0,191,175,231,58,192,12, - 1,0,6,36,24,0,191,143,32,0,189,39, - 8,0,224,3,0,0,0,0,224,255,189,39, - 16,0,164,163,3,131,4,60,19,18,132,36, - 16,0,165,39,24,0,191,175,231,58,192,12, - 1,0,6,36,24,0,191,143,32,0,189,39, - 8,0,224,3,0,0,0,0,232,255,189,39, - 33,40,128,0,16,0,176,175,3,131,16,60, - 20,18,16,38,33,32,0,2,20,0,191,175, - 231,58,192,12,4,0,6,36,0,163,5,60, - 220,5,165,52,3,0,2,138,0,0,2,154, - 0,0,0,0,3,0,162,168,0,0,162,184, - 20,0,191,143,16,0,176,143,8,0,224,3, - 24,0,189,39,232,255,189,39,33,40,128,0, - 16,0,176,175,3,131,16,60,68,18,16,38, - 33,32,0,2,20,0,191,175,231,58,192,12, - 4,0,6,36,0,163,5,60,16,6,165,52, - 3,0,2,138,0,0,2,154,0,0,0,0, - 3,0,162,168,0,0,162,184,20,0,191,143, - 16,0,176,143,8,0,224,3,24,0,189,39, - 232,255,189,39,33,40,128,0,16,0,176,175, - 3,131,16,60,24,18,16,38,33,32,0,2, - 20,0,191,175,231,58,192,12,4,0,6,36, - 0,163,5,60,224,5,165,52,3,0,2,138, - 0,0,2,154,0,0,0,0,3,0,162,168, - 0,0,162,184,20,0,191,143,16,0,176,143, - 8,0,224,3,24,0,189,39,3,131,2,60, - 28,18,66,148,224,255,189,39,24,0,191,175, - 8,0,128,16,16,0,162,167,1,0,66,52, - 16,0,162,167,1,0,2,36,44,133,130,175, - 0,163,1,60,177,59,192,8,144,1,34,172, - 254,255,66,48,16,0,162,167,44,133,128,175, - 0,163,1,60,144,1,32,172,3,131,4,60, - 28,18,132,36,16,0,165,39,231,58,192,12, - 2,0,6,36,24,0,191,143,32,0,189,39, - 8,0,224,3,0,0,0,0,3,131,2,60, - 28,18,66,148,224,255,189,39,24,0,191,175, - 3,0,128,16,16,0,162,167,195,59,192,8, - 2,0,66,52,253,255,66,48,16,0,162,167, - 3,131,4,60,28,18,132,36,16,0,165,39, - 231,58,192,12,2,0,6,36,24,0,191,143, - 32,0,189,39,8,0,224,3,0,0,0,0, - 216,255,189,39,32,0,191,175,33,56,128,0, - 33,48,160,0,3,0,226,136,0,0,226,152, - 7,0,227,136,4,0,227,152,11,0,228,136, - 8,0,228,152,15,0,229,136,12,0,229,152, - 19,0,162,171,16,0,162,187,23,0,163,171, - 20,0,163,187,27,0,164,171,24,0,164,187, - 31,0,165,171,28,0,165,187,16,0,194,44, - 3,0,64,16,16,0,163,39,33,16,102,0, - 0,0,64,160,3,131,4,60,80,18,132,36, - 33,40,224,0,231,58,192,12,16,0,6,36, - 32,0,191,143,40,0,189,39,8,0,224,3, - 0,0,0,0,216,255,189,39,32,0,191,175, - 33,56,128,0,33,48,160,0,3,0,226,136, - 0,0,226,152,7,0,227,136,4,0,227,152, - 11,0,228,136,8,0,228,152,15,0,229,136, - 12,0,229,152,19,0,162,171,16,0,162,187, - 23,0,163,171,20,0,163,187,27,0,164,171, - 24,0,164,187,31,0,165,171,28,0,165,187, - 16,0,194,44,3,0,64,16,16,0,163,39, - 33,16,102,0,0,0,64,160,3,131,4,60, - 96,18,132,36,33,40,224,0,231,58,192,12, - 16,0,6,36,32,0,191,143,40,0,189,39, - 8,0,224,3,0,0,0,0,216,255,189,39, - 32,0,191,175,33,56,128,0,33,48,160,0, - 3,0,226,136,0,0,226,152,7,0,227,136, - 4,0,227,152,11,0,228,136,8,0,228,152, - 15,0,229,136,12,0,229,152,19,0,162,171, - 16,0,162,187,23,0,163,171,20,0,163,187, - 27,0,164,171,24,0,164,187,31,0,165,171, - 28,0,165,187,16,0,194,44,3,0,64,16, - 16,0,163,39,33,16,102,0,0,0,64,160, - 3,131,4,60,112,18,132,36,33,40,224,0, - 231,58,192,12,16,0,6,36,32,0,191,143, - 40,0,189,39,8,0,224,3,0,0,0,0, - 232,255,189,39,15,0,2,60,54,66,66,52, - 24,0,164,175,246,255,132,36,43,16,68,0, - 3,0,64,16,16,0,191,175,44,1,2,36, - 24,0,162,175,3,131,4,60,64,18,132,36, - 24,0,165,39,231,58,192,12,4,0,6,36, - 24,0,162,143,0,163,1,60,140,1,34,172, - 16,0,191,143,24,0,189,39,8,0,224,3, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,232,255,189,39,16,0,191,175, - 0,38,4,0,196,64,192,12,3,38,4,0, - 16,0,191,143,24,0,189,39,8,0,224,3, - 0,0,0,0,232,255,189,39,16,0,191,175, - 0,38,4,0,196,64,192,12,3,38,4,0, - 16,0,191,143,24,0,189,39,8,0,224,3, - 0,0,0,0,160,255,189,39,112,0,162,143, - 72,0,176,175,33,128,224,0,88,0,180,175, - 33,160,0,0,84,0,179,175,33,152,192,0, - 92,0,191,175,80,0,178,175,7,0,160,16, - 76,0,177,175,6,0,65,4,51,0,177,39, - 45,0,20,36,3,0,0,18,35,16,2,0, - 255,255,16,38,51,0,177,39,51,0,160,163, - 27,0,68,0,2,0,128,20,0,0,0,0, - 13,0,7,0,18,24,0,0,16,16,0,0, - 2,131,1,60,33,8,34,0,128,205,34,144, - 255,255,49,38,2,0,0,18,0,0,34,162, - 255,255,16,38,33,16,96,0,241,255,64,20, - 1,0,3,36,0,22,19,0,3,22,2,0, - 11,0,67,20,33,32,128,2,255,255,16,38, - 255,255,2,36,7,0,2,18,0,0,0,0, - 255,255,18,36,196,64,192,12,32,0,4,36, - 255,255,16,38,252,255,18,22,33,32,128,2, - 4,0,128,16,0,22,19,0,196,64,192,12, - 0,0,0,0,0,22,19,0,3,22,2,0, - 2,0,3,36,14,0,67,20,255,255,2,36, - 255,255,16,38,11,0,2,18,255,255,18,36, - 196,64,192,12,48,0,4,36,255,255,16,38, - 6,0,18,18,0,0,0,0,156,60,192,8, - 0,0,0,0,0,38,4,0,196,64,192,12, - 3,38,4,0,0,0,34,130,0,0,36,146, - 0,0,0,0,249,255,64,20,1,0,49,38, - 255,255,49,38,0,22,19,0,3,22,2,0, - 3,0,3,36,9,0,67,20,255,255,16,38, - 255,255,2,36,6,0,2,18,255,255,17,36, - 196,64,192,12,32,0,4,36,255,255,16,38, - 252,255,17,22,0,0,0,0,92,0,191,143, - 88,0,180,143,84,0,179,143,80,0,178,143, - 76,0,177,143,72,0,176,143,8,0,224,3, - 96,0,189,39,200,255,189,39,40,0,178,175, - 33,144,128,0,32,0,176,175,33,128,160,0, - 36,0,177,175,33,136,192,0,33,32,32,2, - 48,0,191,175,156,71,192,12,44,0,179,175, - 33,32,0,0,33,24,64,0,42,16,112,0, - 2,0,64,16,33,152,64,2,35,32,3,2, - 0,22,18,0,3,22,2,0,1,0,3,36, - 11,0,67,20,33,128,128,0,255,255,16,38, - 255,255,2,36,8,0,2,18,0,22,19,0, - 255,255,18,36,196,64,192,12,32,0,4,36, - 255,255,16,38,252,255,18,22,0,0,0,0, - 0,22,19,0,3,22,2,0,2,0,3,36, - 14,0,67,20,255,255,2,36,255,255,16,38, - 11,0,2,18,255,255,18,36,196,64,192,12, - 48,0,4,36,255,255,16,38,6,0,18,18, - 0,0,0,0,233,60,192,8,0,0,0,0, - 0,38,4,0,196,64,192,12,3,38,4,0, - 0,0,34,130,0,0,36,146,0,0,0,0, - 249,255,64,20,1,0,49,38,255,255,49,38, - 0,22,19,0,3,22,2,0,3,0,3,36, - 9,0,67,20,255,255,16,38,255,255,2,36, - 6,0,2,18,255,255,17,36,196,64,192,12, - 32,0,4,36,255,255,16,38,252,255,17,22, - 0,0,0,0,48,0,191,143,44,0,179,143, - 40,0,178,143,36,0,177,143,32,0,176,143, - 8,0,224,3,56,0,189,39,32,255,189,39, - 192,0,178,175,33,144,160,0,196,0,179,175, - 33,152,0,0,220,0,191,175,216,0,190,175, - 212,0,183,175,208,0,182,175,204,0,181,175, - 200,0,180,175,188,0,177,175,184,0,176,175, - 1,0,130,128,0,0,0,0,229,1,64,16, - 33,136,0,0,255,255,22,36,1,0,23,36, - 2,0,30,36,1,0,149,36,0,0,162,146, - 0,0,0,0,219,255,66,36,0,22,2,0, - 3,30,2,0,84,0,98,44,217,1,64,16, - 128,16,3,0,2,131,1,60,33,8,34,0, - 80,150,34,140,0,0,0,0,8,0,64,0, - 0,0,0,0,209,61,192,8,37,0,4,36, - 2,131,16,60,64,150,16,38,156,71,192,12, - 33,32,0,2,59,61,192,8,0,0,0,0, - 0,38,4,0,196,64,192,12,3,38,4,0, - 0,0,2,130,0,0,4,146,0,0,0,0, - 249,255,64,20,1,0,16,38,3,63,192,8, - 1,0,162,38,0,38,18,0,209,61,192,8, - 3,38,4,0,2,0,3,36,33,128,32,2, - 33,40,64,2,33,160,0,0,51,0,177,39, - 51,0,160,163,27,0,163,0,2,0,96,20, - 0,0,0,0,13,0,7,0,18,40,0,0, - 16,16,0,0,2,131,1,60,33,8,34,0, - 128,205,34,144,255,255,49,38,2,0,0,18, - 0,0,34,162,255,255,16,38,242,255,160,20, - 0,0,0,0,10,0,119,22,0,22,20,0, - 255,255,16,38,8,0,22,18,3,38,2,0, - 255,255,18,36,196,64,192,12,32,0,4,36, - 255,255,16,38,252,255,18,22,0,22,20,0, - 3,38,2,0,3,0,128,16,0,0,0,0, - 196,64,192,12,0,0,0,0,14,0,126,22, - 0,0,0,0,255,255,16,38,11,0,22,18, - 255,255,18,36,196,64,192,12,48,0,4,36, - 255,255,16,38,6,0,18,18,0,0,0,0, - 111,61,192,8,0,0,0,0,0,38,4,0, - 196,64,192,12,3,38,4,0,0,0,34,130, - 0,0,36,146,0,0,0,0,249,255,64,20, - 1,0,49,38,255,255,49,38,3,0,6,36, - 80,0,102,22,66,0,4,36,255,255,16,38, - 77,0,22,18,255,255,17,36,196,64,192,12, - 32,0,4,36,255,255,16,38,252,255,17,22, - 66,0,4,36,209,61,192,8,0,0,0,0, - 8,0,3,36,33,128,32,2,33,40,64,2, - 33,160,0,0,51,0,177,39,51,0,160,163, - 27,0,163,0,2,0,96,20,0,0,0,0, - 13,0,7,0,18,40,0,0,16,16,0,0, - 2,131,1,60,33,8,34,0,128,205,34,144, - 255,255,49,38,2,0,0,18,0,0,34,162, - 255,255,16,38,242,255,160,20,0,0,0,0, - 10,0,119,22,0,22,20,0,255,255,16,38, - 8,0,22,18,3,38,2,0,255,255,18,36, - 196,64,192,12,32,0,4,36,255,255,16,38, - 252,255,18,22,0,22,20,0,3,38,2,0, - 3,0,128,16,0,0,0,0,196,64,192,12, - 0,0,0,0,14,0,126,22,0,0,0,0, - 255,255,16,38,11,0,22,18,255,255,18,36, - 196,64,192,12,48,0,4,36,255,255,16,38, - 6,0,18,18,0,0,0,0,182,61,192,8, - 0,0,0,0,0,38,4,0,196,64,192,12, - 3,38,4,0,0,0,34,130,0,0,36,146, - 0,0,0,0,249,255,64,20,1,0,49,38, - 255,255,49,38,3,0,6,36,9,0,102,22, - 81,0,4,36,255,255,16,38,6,0,22,18, - 255,255,17,36,196,64,192,12,32,0,4,36, - 255,255,16,38,252,255,17,22,81,0,4,36, - 196,64,192,12,0,0,0,0,3,63,192,8, - 1,0,162,38,33,128,32,2,33,16,64,2, - 33,160,0,0,5,0,65,6,10,0,4,36, - 45,0,20,36,2,0,32,18,35,16,18,0, - 255,255,48,38,51,0,177,39,51,0,160,163, - 27,0,68,0,2,0,128,20,0,0,0,0, - 13,0,7,0,18,24,0,0,16,16,0,0, - 2,131,1,60,33,8,34,0,128,205,34,144, - 255,255,49,38,2,0,0,18,0,0,34,162, - 255,255,16,38,33,16,96,0,241,255,64,20, - 0,0,0,0,10,0,119,22,33,32,128,2, - 255,255,16,38,7,0,22,18,0,0,0,0, - 255,255,18,36,196,64,192,12,32,0,4,36, - 255,255,16,38,252,255,18,22,33,32,128,2, - 3,0,128,16,0,0,0,0,196,64,192,12, - 0,0,0,0,14,0,126,22,0,0,0,0, - 255,255,16,38,11,0,22,18,255,255,18,36, - 196,64,192,12,48,0,4,36,255,255,16,38, - 6,0,18,18,0,0,0,0,4,62,192,8, - 0,0,0,0,0,38,4,0,196,64,192,12, - 3,38,4,0,0,0,34,130,0,0,36,146, - 0,0,0,0,249,255,64,20,1,0,49,38, - 255,255,49,38,3,0,6,36,237,0,102,22, - 1,0,162,38,255,255,16,38,234,0,22,18, - 255,255,17,36,196,64,192,12,32,0,4,36, - 255,255,16,38,252,255,17,22,1,0,162,38, - 3,63,192,8,0,0,0,0,10,0,3,36, - 33,128,32,2,33,40,64,2,33,160,0,0, - 51,0,177,39,51,0,160,163,27,0,163,0, - 2,0,96,20,0,0,0,0,13,0,7,0, - 18,40,0,0,16,16,0,0,2,131,1,60, - 33,8,34,0,128,205,34,144,255,255,49,38, - 2,0,0,18,0,0,34,162,255,255,16,38, - 242,255,160,20,0,0,0,0,10,0,119,22, - 0,22,20,0,255,255,16,38,8,0,22,18, - 3,38,2,0,255,255,18,36,196,64,192,12, - 32,0,4,36,255,255,16,38,252,255,18,22, - 0,22,20,0,3,38,2,0,3,0,128,16, - 0,0,0,0,196,64,192,12,0,0,0,0, - 14,0,126,22,0,0,0,0,255,255,16,38, - 11,0,22,18,255,255,18,36,196,64,192,12, - 48,0,4,36,255,255,16,38,6,0,18,18, - 0,0,0,0,75,62,192,8,0,0,0,0, - 0,38,4,0,196,64,192,12,3,38,4,0, - 0,0,34,130,0,0,36,146,0,0,0,0, - 249,255,64,20,1,0,49,38,255,255,49,38, - 3,0,6,36,166,0,102,22,1,0,162,38, - 255,255,16,38,163,0,22,18,255,255,17,36, - 196,64,192,12,32,0,4,36,255,255,16,38, - 252,255,17,22,1,0,162,38,3,63,192,8, - 0,0,0,0,192,132,144,39,156,71,192,12, - 33,32,0,2,112,62,192,8,0,0,0,0, - 0,38,4,0,196,64,192,12,3,38,4,0, - 0,0,2,130,0,0,4,146,0,0,0,0, - 249,255,64,20,1,0,16,38,16,0,3,36, - 33,128,32,2,33,40,64,2,33,160,0,0, - 51,0,177,39,51,0,160,163,27,0,163,0, - 2,0,96,20,0,0,0,0,13,0,7,0, - 18,40,0,0,16,16,0,0,2,131,1,60, - 33,8,34,0,128,205,34,144,255,255,49,38, - 2,0,0,18,0,0,34,162,255,255,16,38, - 242,255,160,20,0,0,0,0,10,0,119,22, - 0,22,20,0,255,255,16,38,8,0,22,18, - 3,38,2,0,255,255,18,36,196,64,192,12, - 32,0,4,36,255,255,16,38,252,255,18,22, - 0,22,20,0,3,38,2,0,3,0,128,16, - 0,0,0,0,196,64,192,12,0,0,0,0, - 14,0,126,22,0,0,0,0,255,255,16,38, - 11,0,22,18,255,255,18,36,196,64,192,12, - 48,0,4,36,255,255,16,38,6,0,18,18, - 0,0,0,0,159,62,192,8,0,0,0,0, - 0,38,4,0,196,64,192,12,3,38,4,0, - 0,0,34,130,0,0,36,146,0,0,0,0, - 249,255,64,20,1,0,49,38,255,255,49,38, - 3,0,6,36,82,0,102,22,1,0,162,38, - 255,255,16,38,79,0,22,18,255,255,17,36, - 196,64,192,12,32,0,4,36,255,255,16,38, - 252,255,17,22,1,0,162,38,3,63,192,8, - 0,0,0,0,156,71,192,12,33,32,64,2, - 33,24,64,0,42,16,113,0,2,0,64,16, - 33,32,0,0,35,32,35,2,10,0,119,22, - 33,128,128,0,255,255,16,38,7,0,22,18, - 0,0,0,0,255,255,17,36,196,64,192,12, - 32,0,4,36,255,255,16,38,252,255,17,22, - 0,0,0,0,14,0,126,22,0,0,0,0, - 255,255,16,38,11,0,22,18,255,255,17,36, - 196,64,192,12,48,0,4,36,255,255,16,38, - 6,0,17,18,0,0,0,0,211,62,192,8, - 0,0,0,0,0,38,4,0,196,64,192,12, - 3,38,4,0,0,0,66,130,0,0,68,146, - 0,0,0,0,249,255,64,20,1,0,82,38, - 255,255,82,38,3,0,6,36,30,0,102,22, - 1,0,162,38,255,255,16,38,27,0,22,18, - 255,255,17,36,196,64,192,12,32,0,4,36, - 255,255,16,38,252,255,17,22,1,0,162,38, - 3,63,192,8,0,0,0,0,253,62,192,8, - 3,0,19,36,3,0,96,22,128,16,17,0, - 2,0,19,36,128,16,17,0,33,16,81,0, - 64,16,2,0,0,0,163,130,208,255,66,36, - 2,0,96,22,33,136,67,0,1,0,19,36, - 1,0,181,38,0,0,162,130,0,0,0,0, - 33,254,64,20,0,0,0,0,1,0,130,36, - 220,0,191,143,216,0,190,143,212,0,183,143, - 208,0,182,143,204,0,181,143,200,0,180,143, - 196,0,179,143,192,0,178,143,188,0,177,143, - 184,0,176,143,8,0,224,3,224,0,189,39, - 0,0,164,175,4,0,165,175,8,0,166,175, - 12,0,167,175,200,255,189,39,59,0,162,39, - 252,255,3,36,36,16,67,0,52,0,191,175, - 48,0,180,175,44,0,179,175,40,0,178,175, - 36,0,177,175,32,0,176,175,56,0,164,175, - 0,0,80,140,4,0,81,36,0,0,2,130, - 0,0,3,146,0,0,0,0,31,0,64,16, - 37,0,20,36,69,0,19,36,252,255,18,36, - 0,22,3,0,3,38,2,0,18,0,148,20, - 0,0,0,0,1,0,3,130,0,0,0,0, - 4,0,100,16,33,32,0,2,4,0,115,20, - 3,0,34,38,33,32,0,2,56,63,192,8, - 33,40,0,0,36,16,82,0,4,0,81,36, - 0,0,69,140,33,32,0,2,13,61,192,12, - 0,0,0,0,62,63,192,8,33,128,64,0, - 196,64,192,12,1,0,16,38,0,0,2,130, - 0,0,3,146,0,0,0,0,230,255,64,20, - 0,22,3,0,52,0,191,143,48,0,180,143, - 44,0,179,143,40,0,178,143,36,0,177,143, - 32,0,176,143,8,0,224,3,56,0,189,39, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,8,0,224,3,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,8,0,224,3, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 8,0,224,3,0,0,0,0,33,72,224,3, - 170,3,8,36,76,63,192,12,0,0,0,0, - 255,255,8,33,252,255,0,21,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,8,0,32,1, - 0,0,0,0,33,88,224,3,232,3,10,36, - 143,63,192,12,0,0,0,0,255,255,74,33, - 252,255,64,21,0,0,0,0,8,0,96,1, - 0,0,0,0,250,255,132,32,130,32,4,0, - 255,255,132,32,0,0,0,0,253,255,128,20, - 0,0,0,0,8,0,224,3,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 248,255,189,39,255,255,195,36,10,0,192,16, - 33,56,160,0,255,255,6,36,0,0,162,144, - 1,0,165,36,0,0,130,160,4,0,64,16, - 1,0,132,36,255,255,99,36,249,255,102,20, - 0,0,0,0,33,16,224,0,8,0,224,3, - 8,0,189,39,0,96,2,64,0,0,0,0, - 38,64,68,0,1,255,8,49,38,64,2,1, - 0,96,136,64,8,0,224,3,1,255,66,48, - 0,96,2,64,0,0,0,0,1,255,132,48, - 39,32,128,0,36,64,68,0,0,96,136,64, - 8,0,224,3,1,255,66,48,0,96,2,64, - 0,0,0,0,0,255,132,48,37,64,68,0, - 1,0,8,53,0,96,136,64,8,0,224,3, - 1,255,66,48,176,255,189,39,64,0,182,175, - 33,176,128,0,52,0,179,175,33,152,160,0, - 72,0,190,175,33,240,192,0,68,0,183,175, - 33,184,224,0,60,0,181,175,33,168,0,0, - 56,0,180,175,33,160,0,0,76,0,191,175, - 48,0,178,175,44,0,177,175,40,0,176,175, - 2,131,6,60,33,48,212,0,160,205,198,144, - 0,0,0,0,28,0,96,26,33,128,0,0, - 33,24,192,2,33,32,118,2,0,0,102,160, - 1,0,99,36,42,16,100,0,252,255,64,20, - 0,0,0,0,19,0,96,26,33,128,0,0, - 255,0,210,48,33,136,192,2,0,0,39,146, - 0,0,0,0,9,0,242,16,0,0,0,0, - 5,0,224,18,33,40,0,2,96,0,164,143, - 0,0,0,0,9,248,224,2,33,48,64,2, - 32,0,192,23,1,0,181,38,1,0,16,38, - 42,16,19,2,241,255,64,20,1,0,49,38, - 1,0,148,38,4,0,130,46,220,255,64,20, - 0,0,0,0,7,0,96,26,33,128,0,0, - 33,24,192,2,0,0,112,160,1,0,16,38, - 42,16,19,2,252,255,64,20,1,0,99,36, - 20,0,96,26,33,128,0,0,33,136,192,2, - 0,0,39,146,255,0,6,50,11,0,230,16, - 0,0,0,0,5,0,224,18,0,0,0,0, - 96,0,164,143,0,0,0,0,9,248,224,2, - 33,40,0,2,3,0,192,19,1,0,181,38, - 72,64,192,8,1,0,2,36,1,0,16,38, - 42,16,19,2,239,255,64,20,1,0,49,38, - 33,16,160,2,76,0,191,143,72,0,190,143, - 68,0,183,143,64,0,182,143,60,0,181,143, - 56,0,180,143,52,0,179,143,48,0,178,143, - 44,0,177,143,40,0,176,143,8,0,224,3, - 80,0,189,39,160,255,189,39,88,0,190,175, - 33,240,128,0,68,0,179,175,33,152,160,0, - 76,0,181,175,33,168,224,0,72,0,180,175, - 33,160,0,0,33,16,96,2,92,0,191,175, - 84,0,183,175,80,0,182,175,64,0,178,175, - 60,0,177,175,56,0,176,175,2,0,97,6, - 16,0,166,175,3,0,98,38,131,152,2,0, - 33,184,0,0,2,131,22,60,164,205,214,38, - 0,0,210,142,0,0,0,0,7,0,96,18, - 33,128,0,0,33,24,192,3,0,0,114,172, - 1,0,16,38,43,16,19,2,252,255,64,20, - 4,0,99,36,20,0,96,18,33,128,0,0, - 33,136,192,3,0,0,39,142,0,0,0,0, - 11,0,242,16,128,40,16,0,5,0,160,18, - 0,0,0,0,112,0,164,143,0,0,0,0, - 9,248,160,2,33,48,64,2,16,0,168,143, - 0,0,0,0,34,0,0,21,1,0,148,38, - 1,0,16,38,43,16,19,2,239,255,64,20, - 4,0,49,38,1,0,247,38,4,0,226,46, - 222,255,64,20,4,0,214,38,7,0,96,18, - 33,128,0,0,33,24,192,3,0,0,112,172, - 1,0,16,38,43,16,19,2,252,255,64,20, - 4,0,99,36,22,0,96,18,33,128,0,0, - 33,136,192,3,0,0,39,142,0,0,0,0, - 13,0,240,16,128,40,16,0,5,0,160,18, - 0,0,0,0,112,0,164,143,0,0,0,0, - 9,248,160,2,33,48,0,2,16,0,168,143, - 0,0,0,0,3,0,0,17,1,0,148,38, - 174,64,192,8,1,0,2,36,1,0,16,38, - 43,16,19,2,237,255,64,20,4,0,49,38, - 33,16,128,2,92,0,191,143,88,0,190,143, - 84,0,183,143,80,0,182,143,76,0,181,143, - 72,0,180,143,68,0,179,143,64,0,178,143, - 60,0,177,143,56,0,176,143,8,0,224,3, - 96,0,189,39,0,0,0,0,0,0,0,0, - 255,1,2,36,0,163,1,60,176,1,32,172, - 0,163,1,60,180,1,32,172,0,163,1,60, - 8,0,224,3,184,1,34,172,232,255,189,39, - 16,0,176,175,33,128,128,0,20,0,191,175, - 220,63,192,12,33,32,0,0,33,40,64,0, - 0,163,3,60,180,1,99,140,0,163,2,60, - 184,1,66,140,0,163,4,60,128,1,132,140, - 1,0,99,36,11,0,128,20,36,24,98,0, - 0,163,2,60,176,1,66,140,0,0,0,0, - 6,0,98,20,0,0,0,0,0,163,2,60, - 128,1,66,140,0,0,0,0,247,255,64,16, - 0,0,0,0,0,163,2,60,180,1,66,140, - 33,32,160,0,0,163,1,60,33,8,34,0, - 188,1,48,160,0,163,1,60,220,63,192,12, - 180,1,35,172,20,0,191,143,16,0,176,143, - 8,0,224,3,24,0,189,39,8,0,224,3, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,192,255,189,39,33,80,0,0, - 80,0,185,143,84,0,184,143,88,0,175,143, - 1,0,2,36,60,0,177,175,92,0,177,143, - 4,112,226,0,12,0,224,24,56,0,176,175, - 1,0,9,36,33,64,160,3,33,24,32,3, - 0,0,98,140,4,0,99,36,1,0,74,37, - 4,16,73,0,0,0,2,173,42,16,71,1, - 249,255,64,20,4,0,8,37,46,0,192,25, - 33,80,0,0,255,0,16,36,33,72,0,0, - 0,0,145,172,0,0,160,164,34,0,224,24, - 0,0,208,160,33,88,128,0,33,96,160,0, - 33,104,192,0,33,64,32,3,33,24,160,3, - 0,0,98,140,0,0,0,0,36,16,66,1, - 19,0,64,16,0,0,0,0,0,0,2,141, - 0,0,0,0,128,16,2,0,33,16,88,0, - 0,0,66,140,0,0,0,0,0,0,98,173, - 0,0,2,141,0,0,0,0,64,16,2,0, - 33,16,79,0,0,0,66,148,0,0,0,0, - 0,0,130,165,0,0,2,141,0,0,0,0, - 47,65,192,8,0,0,162,161,4,0,8,37, - 1,0,41,37,42,16,39,1,229,255,64,20, - 4,0,99,36,1,0,198,36,2,0,165,36, - 1,0,74,37,42,16,78,1,213,255,64,20, - 4,0,132,36,60,0,177,143,56,0,176,143, - 8,0,224,3,64,0,189,39,0,0,0,0, - 0,0,0,0,0,0,0,0,216,255,189,39, - 63,0,132,48,28,0,179,175,128,1,147,52, - 50,133,130,151,48,133,132,151,0,128,131,151, - 20,0,177,175,16,0,176,175,5,162,16,60, - 32,0,191,175,24,0,178,175,39,16,68,0, - 36,24,98,0,0,128,131,167,0,0,3,166, - 76,63,192,12,0,1,17,36,0,128,130,151, - 48,133,131,151,5,162,18,60,37,16,67,0, - 0,128,130,167,0,0,2,166,36,16,51,2, - 6,0,64,16,0,0,0,0,0,128,131,151, - 20,133,130,151,0,0,0,0,96,65,192,8, - 37,24,98,0,20,133,130,151,0,128,131,151, - 39,16,2,0,36,24,98,0,0,128,131,167, - 0,0,67,166,76,63,192,12,66,136,17,0, - 0,128,130,151,50,133,131,151,0,0,0,0, - 37,16,67,0,0,128,130,167,76,63,192,12, - 0,0,66,166,50,133,130,151,0,128,131,151, - 39,16,2,0,36,24,98,0,255,255,34,50, - 0,128,131,167,0,0,67,166,226,255,64,20, - 36,16,51,2,33,136,0,0,16,0,16,36, - 5,162,18,60,255,255,19,36,76,63,192,12, - 0,0,0,0,0,128,131,151,50,133,130,151, - 0,0,0,0,37,24,98,0,0,128,131,167, - 76,63,192,12,0,0,67,166,8,0,0,18, - 0,0,0,0,0,0,67,150,20,133,130,151, - 0,0,0,0,36,16,67,0,2,0,64,16, - 64,136,17,0,1,0,49,54,76,63,192,12, - 255,255,16,38,50,133,130,151,0,128,131,151, - 39,16,2,0,36,24,98,0,0,128,131,167, - 230,255,19,22,0,0,67,166,48,133,130,151, - 0,128,131,151,39,16,2,0,36,24,98,0, - 5,162,2,60,0,128,131,167,0,0,67,164, - 255,255,34,50,32,0,191,143,28,0,179,143, - 24,0,178,143,20,0,177,143,16,0,176,143, - 8,0,224,3,40,0,189,39,208,255,189,39, - 36,0,181,175,33,168,160,0,32,0,180,175, - 63,0,148,48,33,32,128,2,44,0,191,175, - 40,0,182,175,28,0,179,175,24,0,178,175, - 20,0,177,175,60,65,192,12,16,0,176,175, - 33,152,64,0,255,255,163,50,255,255,98,50, - 3,0,98,20,48,1,22,36,245,66,192,8, - 1,0,2,36,5,162,16,60,50,133,130,151, - 48,133,132,151,0,128,131,151,39,16,68,0, - 36,24,98,0,0,128,131,167,0,0,3,166, - 76,63,192,12,0,1,17,36,0,128,130,151, - 48,133,131,151,5,162,18,60,37,16,67,0, - 0,128,130,167,0,0,2,166,36,16,54,2, - 6,0,64,16,0,0,0,0,0,128,131,151, - 20,133,130,151,0,0,0,0,210,65,192,8, - 37,24,98,0,20,133,130,151,0,128,131,151, - 39,16,2,0,36,24,98,0,0,128,131,167, - 0,0,67,166,76,63,192,12,66,136,17,0, - 0,128,130,151,50,133,131,151,0,0,0,0, - 37,16,67,0,0,128,130,167,76,63,192,12, - 0,0,66,166,50,133,130,151,0,128,131,151, - 39,16,2,0,36,24,98,0,255,255,34,50, - 0,128,131,167,0,0,67,166,226,255,64,20, - 36,16,54,2,255,255,163,50,255,255,98,50, - 39,16,2,0,36,24,98,0,84,0,96,16, - 192,1,147,54,5,162,16,60,50,133,130,151, - 48,133,132,151,0,128,131,151,39,16,68,0, - 36,24,98,0,0,128,131,167,0,0,3,166, - 76,63,192,12,0,1,17,36,0,128,130,151, - 48,133,131,151,5,162,18,60,37,16,67,0, - 0,128,130,167,0,0,2,166,36,16,51,2, - 6,0,64,16,0,0,0,0,0,128,131,151, - 20,133,130,151,0,0,0,0,8,66,192,8, - 37,24,98,0,20,133,130,151,0,128,131,151, - 39,16,2,0,36,24,98,0,0,128,131,167, - 0,0,67,166,76,63,192,12,66,136,17,0, - 0,128,130,151,50,133,131,151,0,0,0,0, - 37,16,67,0,0,128,130,167,76,63,192,12, - 0,0,66,166,50,133,130,151,0,128,131,151, - 39,16,2,0,36,24,98,0,255,255,34,50, - 0,128,131,167,0,0,67,166,226,255,64,20, - 36,16,51,2,5,162,16,60,50,133,130,151, - 48,133,132,151,0,128,131,151,39,16,68,0, - 36,24,98,0,0,128,131,167,76,63,192,12, - 0,0,3,166,0,128,131,151,48,133,130,151, - 0,0,0,0,37,24,98,0,0,0,3,166, - 0,0,4,150,20,133,130,151,0,128,131,167, - 36,16,68,0,9,0,64,20,0,0,0,0, - 76,63,192,12,0,0,0,0,0,0,3,150, - 20,133,130,151,0,0,0,0,36,16,67,0, - 249,255,64,16,0,0,0,0,48,133,130,151, - 0,128,131,151,39,16,2,0,36,24,98,0, - 5,162,2,60,0,128,131,167,0,0,67,164, - 255,255,163,50,255,255,2,52,125,0,98,16, - 64,1,147,54,5,162,16,60,50,133,130,151, - 48,133,132,151,0,128,131,151,39,16,68,0, - 36,24,98,0,0,128,131,167,0,0,3,166, - 76,63,192,12,0,1,17,36,0,128,130,151, - 48,133,131,151,5,162,18,60,37,16,67,0, - 0,128,130,167,0,0,2,166,36,16,51,2, - 6,0,64,16,0,0,0,0,0,128,131,151, - 20,133,130,151,0,0,0,0,95,66,192,8, - 37,24,98,0,20,133,130,151,0,128,131,151, - 39,16,2,0,36,24,98,0,0,128,131,167, - 0,0,67,166,76,63,192,12,66,136,17,0, - 0,128,130,151,50,133,131,151,0,0,0,0, - 37,16,67,0,0,128,130,167,76,63,192,12, - 0,0,66,166,50,133,130,151,0,128,131,151, - 39,16,2,0,36,24,98,0,255,255,34,50, - 0,128,131,167,0,0,67,166,226,255,64,20, - 36,16,51,2,33,144,160,2,0,128,16,52, - 0,128,130,151,48,133,131,151,5,162,17,60, - 37,16,67,0,5,162,3,60,0,128,130,167, - 0,0,98,164,36,16,18,2,6,0,64,16, - 0,0,0,0,0,128,131,151,20,133,130,151, - 0,0,0,0,136,66,192,8,37,24,98,0, - 20,133,130,151,0,128,131,151,39,16,2,0, - 36,24,98,0,0,128,131,167,0,0,35,166, - 76,63,192,12,66,128,16,0,0,128,130,151, - 50,133,131,151,0,0,0,0,37,16,67,0, - 0,128,130,167,76,63,192,12,0,0,34,166, - 50,133,130,151,0,128,131,151,39,16,2,0, - 36,24,98,0,255,255,2,50,0,128,131,167, - 0,0,35,166,226,255,64,20,36,16,18,2, - 5,162,16,60,50,133,130,151,48,133,132,151, - 0,128,131,151,39,16,68,0,36,24,98,0, - 0,128,131,167,76,63,192,12,0,0,3,166, - 0,128,131,151,48,133,130,151,0,0,0,0, - 37,24,98,0,0,0,3,166,0,0,4,150, - 20,133,130,151,0,128,131,167,36,16,68,0, - 9,0,64,20,0,0,0,0,76,63,192,12, - 0,0,0,0,0,0,3,150,20,133,130,151, - 0,0,0,0,36,16,67,0,249,255,64,16, - 0,0,0,0,48,133,130,151,0,128,131,151, - 39,16,2,0,36,24,98,0,5,162,2,60, - 0,128,131,167,0,0,67,164,0,1,19,36, - 5,162,16,60,50,133,130,151,48,133,132,151, - 0,128,131,151,39,16,68,0,36,24,98,0, - 0,128,131,167,0,0,3,166,76,63,192,12, - 0,1,17,36,0,128,130,151,48,133,131,151, - 5,162,18,60,37,16,67,0,0,128,130,167, - 0,0,2,166,36,16,113,2,6,0,64,16, - 0,0,0,0,0,128,131,151,20,133,130,151, - 0,0,0,0,220,66,192,8,37,24,98,0, - 20,133,130,151,0,128,131,151,39,16,2,0, - 36,24,98,0,0,128,131,167,0,0,67,166, - 76,63,192,12,66,136,17,0,0,128,130,151, - 50,133,131,151,0,0,0,0,37,16,67,0, - 0,128,130,167,76,63,192,12,0,0,66,166, - 50,133,130,151,0,128,131,151,39,16,2,0, - 36,24,98,0,255,255,34,50,0,128,131,167, - 0,0,67,166,226,255,64,20,36,16,113,2, - 60,65,192,12,33,32,128,2,38,16,162,2, - 255,255,66,48,1,0,66,44,44,0,191,143, - 40,0,182,143,36,0,181,143,32,0,180,143, - 28,0,179,143,24,0,178,143,20,0,177,143, - 16,0,176,143,8,0,224,3,48,0,189,39, - 224,255,189,39,24,0,178,175,33,144,0,0, - 64,16,4,0,16,0,176,175,33,128,68,0, - 33,32,0,2,20,0,177,175,255,255,177,48, - 28,0,191,175,162,65,192,12,33,40,32,2, - 8,0,64,16,1,0,4,38,162,65,192,12, - 33,40,32,2,4,0,64,16,2,0,4,38, - 162,65,192,12,33,40,32,2,43,144,2,0, - 33,16,64,2,28,0,191,143,24,0,178,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 32,0,189,39,216,255,189,39,64,16,4,0, - 24,0,178,175,33,144,68,0,33,32,64,2, - 36,0,191,175,32,0,180,175,28,0,179,175, - 20,0,177,175,60,65,192,12,16,0,176,175, - 1,0,84,38,33,32,128,2,60,65,192,12, - 33,136,64,0,2,0,83,38,33,32,96,2, - 60,65,192,12,33,128,64,0,255,255,35,50, - 255,255,17,50,8,0,113,20,0,0,0,0, - 255,255,66,48,3,0,34,18,33,32,96,2, - 162,65,192,12,33,40,32,2,66,67,192,8, - 33,16,32,2,255,255,80,48,4,0,112,16, - 33,32,128,2,5,0,48,22,255,255,2,36, - 33,32,64,2,162,65,192,12,33,40,0,2, - 33,16,0,2,36,0,191,143,32,0,180,143, - 28,0,179,143,24,0,178,143,20,0,177,143, - 16,0,176,143,8,0,224,3,40,0,189,39, - 0,0,0,0,0,0,0,0,0,96,8,64, - 0,0,0,0,254,255,1,36,36,72,1,1, - 0,96,137,64,0,0,133,164,2,0,132,32, - 2,44,5,0,0,0,133,164,0,96,136,64, - 8,0,224,3,0,0,0,0,208,255,189,39, - 32,0,178,175,33,144,128,0,28,0,177,175, - 33,136,160,0,36,0,179,175,33,152,192,0, - 40,0,180,175,33,160,224,0,44,0,191,175, - 2,0,32,22,24,0,176,175,255,255,17,36, - 0,0,66,142,0,0,0,0,36,16,81,0, - 3,0,83,20,0,0,0,0,121,67,192,8, - 1,0,2,36,11,0,128,26,33,128,0,0, - 143,63,192,12,0,0,0,0,0,0,66,142, - 0,0,0,0,36,16,81,0,246,255,83,16, - 1,0,16,38,42,16,20,2,247,255,64,20, - 0,0,0,0,33,16,0,0,44,0,191,143, - 40,0,180,143,36,0,179,143,32,0,178,143, - 28,0,177,143,24,0,176,143,8,0,224,3, - 48,0,189,39,208,255,189,39,32,0,178,175, - 33,144,128,0,28,0,177,175,33,136,160,0, - 36,0,179,175,33,152,192,0,40,0,180,175, - 33,160,224,0,44,0,191,175,2,0,32,22, - 24,0,176,175,255,255,17,52,0,0,66,150, - 0,0,0,0,36,16,81,0,3,0,83,20, - 0,0,0,0,162,67,192,8,1,0,2,36, - 11,0,128,26,33,128,0,0,143,63,192,12, - 0,0,0,0,0,0,66,150,0,0,0,0, - 36,16,81,0,246,255,83,16,1,0,16,38, - 42,16,20,2,247,255,64,20,0,0,0,0, - 33,16,0,0,44,0,191,143,40,0,180,143, - 36,0,179,143,32,0,178,143,28,0,177,143, - 24,0,176,143,8,0,224,3,48,0,189,39, - 208,255,189,39,32,0,178,175,33,144,128,0, - 28,0,177,175,33,136,160,0,36,0,179,175, - 33,152,192,0,40,0,180,175,33,160,224,0, - 44,0,191,175,2,0,32,22,24,0,176,175, - 255,0,17,36,0,0,66,146,0,0,0,0, - 36,16,81,0,3,0,83,20,0,0,0,0, - 203,67,192,8,1,0,2,36,11,0,128,26, - 33,128,0,0,143,63,192,12,0,0,0,0, - 0,0,66,146,0,0,0,0,36,16,81,0, - 246,255,83,16,1,0,16,38,42,16,20,2, - 247,255,64,20,0,0,0,0,33,16,0,0, - 44,0,191,143,40,0,180,143,36,0,179,143, - 32,0,178,143,28,0,177,143,24,0,176,143, - 8,0,224,3,48,0,189,39,208,255,189,39, - 32,0,178,175,33,144,128,0,28,0,177,175, - 33,136,160,0,36,0,179,175,33,152,192,0, - 40,0,180,175,33,160,224,0,44,0,191,175, - 2,0,32,22,24,0,176,175,255,255,17,36, - 0,0,66,142,0,0,0,0,36,16,81,0, - 3,0,83,20,0,0,0,0,244,67,192,8, - 1,0,2,36,11,0,128,26,33,128,0,0, - 143,63,192,12,0,0,0,0,0,0,66,142, - 0,0,0,0,36,16,81,0,246,255,83,20, - 1,0,16,38,42,16,20,2,247,255,64,20, - 0,0,0,0,33,16,0,0,44,0,191,143, - 40,0,180,143,36,0,179,143,32,0,178,143, - 28,0,177,143,24,0,176,143,8,0,224,3, - 48,0,189,39,208,255,189,39,32,0,178,175, - 33,144,128,0,28,0,177,175,33,136,160,0, - 36,0,179,175,33,152,192,0,40,0,180,175, - 33,160,224,0,44,0,191,175,2,0,32,22, - 24,0,176,175,255,255,17,52,0,0,66,150, - 0,0,0,0,36,16,81,0,3,0,83,20, - 0,0,0,0,29,68,192,8,1,0,2,36, - 11,0,128,26,33,128,0,0,143,63,192,12, - 0,0,0,0,0,0,66,150,0,0,0,0, - 36,16,81,0,246,255,83,20,1,0,16,38, - 42,16,20,2,247,255,64,20,0,0,0,0, - 33,16,0,0,44,0,191,143,40,0,180,143, - 36,0,179,143,32,0,178,143,28,0,177,143, - 24,0,176,143,8,0,224,3,48,0,189,39, - 208,255,189,39,32,0,178,175,33,144,128,0, - 28,0,177,175,33,136,160,0,36,0,179,175, - 33,152,192,0,40,0,180,175,33,160,224,0, - 44,0,191,175,2,0,32,22,24,0,176,175, - 255,0,17,36,0,0,66,146,0,0,0,0, - 36,16,81,0,3,0,83,20,0,0,0,0, - 70,68,192,8,1,0,2,36,11,0,128,26, - 33,128,0,0,143,63,192,12,0,0,0,0, - 0,0,66,146,0,0,0,0,36,16,81,0, - 246,255,83,20,1,0,16,38,42,16,20,2, - 247,255,64,20,0,0,0,0,33,16,0,0, - 44,0,191,143,40,0,180,143,36,0,179,143, - 32,0,178,143,28,0,177,143,24,0,176,143, - 8,0,224,3,48,0,189,39,0,0,0,0, - 0,0,0,0,248,255,189,39,255,255,195,36, - 8,0,192,16,33,56,128,0,255,255,6,36, - 0,0,162,144,1,0,165,36,255,255,99,36, - 0,0,130,160,251,255,102,20,1,0,132,36, - 33,16,224,0,8,0,224,3,8,0,189,39, - 0,0,0,0,0,0,0,0,0,96,8,64, - 1,0,9,60,0,96,137,64,15,0,138,48, - 33,40,170,0,192,255,165,36,0,0,128,160, - 16,0,128,160,32,0,128,160,251,255,160,28, - 48,0,128,160,64,0,132,36,0,96,136,64, - 0,0,0,0,0,0,0,0,8,0,224,3, - 0,0,0,0,0,0,0,0,1,131,2,60, - 224,17,66,36,0,32,9,60,37,16,73,0, - 8,0,64,0,0,0,0,0,0,96,8,64, - 3,0,9,60,0,96,137,64,15,0,138,48, - 33,40,170,0,192,255,165,36,0,0,128,160, - 16,0,128,160,32,0,128,160,251,255,160,28, - 48,0,128,160,64,0,132,36,0,96,136,64, - 0,0,0,0,0,0,0,0,8,0,224,3, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,163,3,60,192,3,99,140, - 0,163,2,60,188,3,66,140,0,0,0,0, - 16,0,98,16,255,255,2,36,0,163,2,60, - 188,3,66,140,0,163,1,60,33,8,34,0, - 200,3,34,144,0,163,3,60,188,3,99,140, - 0,163,4,60,196,3,132,140,0,22,2,0, - 3,22,2,0,1,0,99,36,36,24,100,0, - 0,163,1,60,188,3,35,172,8,0,224,3, - 0,0,0,0,0,163,6,60,0,1,198,52, - 10,0,9,36,255,255,8,36,13,0,7,36, - 0,163,3,60,192,3,99,140,0,163,2,60, - 188,3,66,140,0,0,0,0,17,0,98,16, - 255,255,5,36,0,163,2,60,188,3,66,140, - 0,0,0,0,33,16,70,0,200,2,66,144, - 0,0,0,0,0,22,2,0,3,46,2,0, - 0,163,2,60,188,3,66,140,0,163,3,60, - 196,3,99,140,1,0,66,36,36,16,67,0, - 0,163,1,60,188,3,34,172,11,0,169,16, - 11,0,162,40,5,0,64,16,0,0,0,0, - 228,255,168,16,0,0,0,0,206,68,192,8, - 0,0,133,160,224,255,167,16,0,0,0,0, - 206,68,192,8,0,0,133,160,208,68,192,8, - 0,0,128,160,169,68,192,8,1,0,132,36, - 8,0,224,3,0,0,0,0,0,0,0,0, - 0,0,0,0,208,255,189,39,24,0,176,175, - 33,128,128,0,36,0,179,175,33,152,160,0, - 28,0,177,175,33,136,0,0,32,0,178,175, - 33,144,0,2,5,0,64,22,40,0,191,175, - 54,0,96,22,33,16,0,0,22,69,192,8, - 0,0,32,174,0,0,67,130,0,0,0,0, - 233,68,192,8,32,0,2,36,0,0,3,130, - 32,0,2,36,253,255,98,16,1,0,16,38, - 255,255,16,38,9,0,2,36,249,255,98,16, - 1,0,16,38,255,255,16,38,0,0,3,130, - 45,0,2,36,4,0,98,20,43,0,2,36, - 1,0,16,38,250,68,192,8,1,0,17,36, - 3,0,98,20,33,32,0,2,1,0,16,38, - 33,32,0,2,44,69,192,12,16,0,165,39, - 7,0,96,18,33,24,64,0,16,0,162,143, - 0,0,0,0,2,0,80,20,0,0,0,0, - 33,16,64,2,0,0,98,174,6,0,32,18, - 0,128,2,60,43,16,67,0,5,0,64,20, - 255,127,2,60,19,69,192,8,33,16,96,0, - 5,0,97,4,255,127,2,60,7,0,32,18, - 255,255,66,52,22,69,192,8,0,128,2,60, - 33,16,96,0,2,0,32,18,0,0,0,0, - 35,16,2,0,40,0,191,143,36,0,179,143, - 32,0,178,143,28,0,177,143,24,0,176,143, - 8,0,224,3,48,0,189,39,0,0,0,0, - 0,0,0,0,0,0,0,0,208,255,130,36, - 10,0,66,44,7,0,64,20,1,0,2,36, - 191,255,130,36,6,0,66,44,3,0,64,20, - 1,0,2,36,159,255,130,36,6,0,66,44, - 8,0,224,3,0,0,0,0,248,255,189,39, - 0,0,176,175,33,56,0,0,33,72,0,0, - 33,80,0,0,33,112,0,0,5,0,128,20, - 33,200,128,0,110,0,160,20,33,16,0,0, - 163,69,192,8,0,0,192,173,0,0,131,128, - 32,0,2,36,253,255,98,16,1,0,132,36, - 255,255,132,36,9,0,2,36,249,255,98,16, - 1,0,132,36,255,255,132,36,0,0,131,128, - 43,0,2,36,3,0,98,20,45,0,2,36, - 75,69,192,8,1,0,132,36,3,0,98,20, - 0,0,0,0,1,0,132,36,1,0,14,36, - 3,0,192,16,16,0,2,36,16,0,194,20, - 0,0,0,0,0,0,131,128,48,0,2,36, - 9,0,98,20,10,0,2,36,1,0,131,128, - 88,0,2,36,3,0,98,16,120,0,2,36, - 3,0,98,20,8,0,2,36,16,0,2,36, - 2,0,132,36,2,0,192,20,0,0,0,0, - 33,48,64,0,0,0,131,128,255,255,2,36, - 27,0,70,0,2,0,192,20,0,0,0,0, - 13,0,7,0,18,64,0,0,16,192,0,0, - 0,0,0,0,0,0,0,0,42,0,96,16, - 48,0,98,44,48,0,207,36,11,0,205,40, - 87,0,204,36,55,0,203,36,5,0,64,20, - 43,16,111,0,3,0,64,16,0,0,0,0, - 130,69,192,8,208,255,99,36,30,0,160,21, - 97,0,98,44,6,0,64,20,65,0,98,44, - 43,16,108,0,3,0,64,16,65,0,98,44, - 130,69,192,8,169,255,99,36,21,0,64,20, - 43,16,107,0,19,0,64,16,0,0,0,0, - 201,255,99,36,43,16,7,1,6,0,64,20, - 1,0,9,36,6,0,232,20,24,0,230,0, - 43,16,3,3,3,0,64,16,0,0,0,0, - 1,0,10,36,24,0,230,0,1,0,132,36, - 18,128,0,0,33,56,3,2,0,0,131,128, - 0,0,0,0,220,255,96,20,48,0,98,44, - 5,0,64,17,0,0,0,0,13,0,160,16, - 255,255,2,36,163,69,192,8,0,0,164,172, - 6,0,160,16,0,0,0,0,3,0,32,21, - 0,0,0,0,160,69,192,8,0,0,185,172, - 0,0,164,172,2,0,192,17,33,16,224,0, - 35,16,2,0,0,0,176,143,8,0,224,3, - 8,0,189,39,0,0,0,0,0,0,0,0, - 200,255,189,39,16,0,176,175,7,162,16,60, - 236,0,16,54,255,240,3,60,255,255,99,52, - 63,0,132,48,36,0,181,175,128,1,149,52, - 24,0,178,175,0,1,18,36,20,0,177,175, - 7,162,17,60,236,0,49,54,44,0,183,175, - 0,4,23,60,32,0,180,175,255,251,20,60, - 255,255,148,54,40,0,182,175,0,1,22,60, - 28,0,179,175,255,254,19,60,48,0,191,175, - 0,0,2,142,0,0,0,0,36,16,67,0, - 224,133,130,175,0,0,2,174,76,63,192,12, - 255,255,115,54,224,133,130,143,0,2,3,60, - 37,16,67,0,224,133,130,175,0,0,2,174, - 36,16,85,2,5,0,64,16,0,0,0,0, - 224,133,130,143,0,0,0,0,214,69,192,8, - 37,16,87,0,224,133,130,143,0,0,0,0, - 36,16,84,0,224,133,130,175,76,63,192,12, - 0,0,34,174,224,133,130,143,0,0,0,0, - 37,16,86,0,224,133,130,175,0,0,34,174, - 76,63,192,12,66,144,18,0,224,133,130,143, - 0,0,0,0,36,16,83,0,224,133,130,175, - 0,0,34,174,255,255,66,50,230,255,64,20, - 36,16,85,2,33,136,0,0,16,0,16,36, - 7,162,18,60,236,0,82,54,0,1,22,60, - 0,8,21,60,255,254,19,60,255,255,115,54, - 255,255,20,36,76,63,192,12,0,0,0,0, - 224,133,130,143,0,0,0,0,37,16,86,0, - 224,133,130,175,76,63,192,12,0,0,66,174, - 7,0,0,18,0,0,0,0,0,0,66,142, - 0,0,0,0,36,16,85,0,2,0,64,16, - 64,136,17,0,1,0,49,54,76,63,192,12, - 255,255,16,38,224,133,130,143,0,0,0,0, - 36,16,83,0,224,133,130,175,0,0,66,174, - 232,255,20,22,7,162,4,60,236,0,132,52, - 255,253,3,60,224,133,130,143,255,255,99,52, - 36,16,67,0,224,133,130,175,0,0,130,172, - 255,255,34,50,48,0,191,143,44,0,183,143, - 40,0,182,143,36,0,181,143,32,0,180,143, - 28,0,179,143,24,0,178,143,20,0,177,143, - 16,0,176,143,8,0,224,3,56,0,189,39, - 200,255,189,39,48,0,190,175,33,240,160,0, - 40,0,182,175,63,0,150,48,33,32,192,2, - 52,0,191,175,44,0,183,175,36,0,181,175, - 32,0,180,175,28,0,179,175,24,0,178,175, - 20,0,177,175,168,69,192,12,16,0,176,175, - 33,152,64,0,255,255,195,51,255,255,98,50, - 3,0,98,20,7,162,16,60,131,71,192,8, - 1,0,2,36,236,0,16,54,255,252,3,60, - 255,255,99,52,0,1,18,36,7,162,17,60, - 236,0,49,54,255,251,21,60,255,255,181,54, - 0,1,23,60,255,254,20,60,224,133,130,143, - 0,0,0,0,36,16,67,0,224,133,130,175, - 0,0,2,174,76,63,192,12,255,255,148,54, - 224,133,130,143,0,2,3,60,37,16,67,0, - 224,133,130,175,0,0,2,174,48,1,66,50, - 5,0,64,16,0,4,6,60,224,133,130,143, - 0,0,0,0,83,70,192,8,37,16,70,0, - 224,133,130,143,0,0,0,0,36,16,85,0, - 224,133,130,175,76,63,192,12,0,0,34,174, - 224,133,130,143,0,0,0,0,37,16,87,0, - 224,133,130,175,0,0,34,174,76,63,192,12, - 66,144,18,0,224,133,130,143,0,0,0,0, - 36,16,84,0,224,133,130,175,0,0,34,174, - 255,255,66,50,230,255,64,20,48,1,66,50, - 255,255,195,51,255,255,98,50,39,16,2,0, - 36,24,98,0,88,0,96,16,192,1,213,54, - 7,162,16,60,236,0,16,54,255,252,3,60, - 255,255,99,52,0,1,18,36,7,162,17,60, - 236,0,49,54,255,251,20,60,255,255,148,54, - 0,1,23,60,255,254,19,60,224,133,130,143, - 0,0,0,0,36,16,67,0,224,133,130,175, - 0,0,2,174,76,63,192,12,255,255,115,54, - 224,133,130,143,0,2,3,60,37,16,67,0, - 224,133,130,175,0,0,2,174,36,16,85,2, - 5,0,64,16,0,4,6,60,224,133,130,143, - 0,0,0,0,140,70,192,8,37,16,70,0, - 224,133,130,143,0,0,0,0,36,16,84,0, - 224,133,130,175,76,63,192,12,0,0,34,174, - 224,133,130,143,0,0,0,0,37,16,87,0, - 224,133,130,175,0,0,34,174,76,63,192,12, - 66,144,18,0,224,133,130,143,0,0,0,0, - 36,16,83,0,224,133,130,175,0,0,34,174, - 255,255,66,50,230,255,64,20,36,16,85,2, - 7,162,16,60,236,0,16,54,255,252,3,60, - 224,133,130,143,255,255,99,52,36,16,67,0, - 224,133,130,175,76,63,192,12,0,0,2,174, - 224,133,130,143,0,2,3,60,37,16,67,0, - 224,133,130,175,0,0,2,174,0,0,2,142, - 0,8,3,60,36,16,67,0,11,0,64,20, - 7,162,4,60,7,162,16,60,236,0,16,54, - 0,8,17,60,76,63,192,12,0,0,0,0, - 0,0,2,142,0,0,0,0,36,16,81,0, - 250,255,64,16,7,162,4,60,236,0,132,52, - 255,253,3,60,224,133,130,143,255,255,99,52, - 36,16,67,0,224,133,130,175,0,0,130,172, - 255,255,195,51,255,255,2,52,133,0,98,16, - 64,1,213,54,7,162,16,60,236,0,16,54, - 255,252,3,60,255,255,99,52,0,1,18,36, - 7,162,17,60,236,0,49,54,255,251,20,60, - 255,255,148,54,0,1,23,60,255,254,19,60, - 224,133,130,143,0,0,0,0,36,16,67,0, - 224,133,130,175,0,0,2,174,76,63,192,12, - 255,255,115,54,224,133,130,143,0,2,3,60, - 37,16,67,0,224,133,130,175,0,0,2,174, - 36,16,85,2,5,0,64,16,0,4,6,60, - 224,133,130,143,0,0,0,0,231,70,192,8, - 37,16,70,0,224,133,130,143,0,0,0,0, - 36,16,84,0,224,133,130,175,76,63,192,12, - 0,0,34,174,224,133,130,143,0,0,0,0, - 37,16,87,0,224,133,130,175,0,0,34,174, - 76,63,192,12,66,144,18,0,224,133,130,143, - 0,0,0,0,36,16,83,0,224,133,130,175, - 0,0,34,174,255,255,66,50,230,255,64,20, - 36,16,85,2,33,160,192,3,7,162,2,60, - 236,0,66,52,0,128,17,52,7,162,16,60, - 236,0,16,54,0,4,23,60,255,251,19,60, - 255,255,115,54,0,1,21,60,255,254,18,60, - 255,255,82,54,224,133,131,143,0,2,4,60, - 37,24,100,0,224,133,131,175,0,0,67,172, - 36,16,52,2,5,0,64,16,0,0,0,0, - 224,133,130,143,0,0,0,0,20,71,192,8, - 37,16,87,0,224,133,130,143,0,0,0,0, - 36,16,83,0,224,133,130,175,76,63,192,12, - 0,0,2,174,224,133,130,143,0,0,0,0, - 37,16,85,0,224,133,130,175,0,0,2,174, - 76,63,192,12,66,136,17,0,224,133,130,143, - 0,0,0,0,36,16,82,0,224,133,130,175, - 0,0,2,174,255,255,34,50,230,255,64,20, - 36,16,52,2,7,162,16,60,236,0,16,54, - 255,252,3,60,224,133,130,143,255,255,99,52, - 36,16,67,0,224,133,130,175,76,63,192,12, - 0,0,2,174,224,133,130,143,0,2,3,60, - 37,16,67,0,224,133,130,175,0,0,2,174, - 0,0,2,142,0,8,3,60,36,16,67,0, - 11,0,64,20,7,162,4,60,7,162,16,60, - 236,0,16,54,0,8,17,60,76,63,192,12, - 0,0,0,0,0,0,2,142,0,0,0,0, - 36,16,81,0,250,255,64,16,7,162,4,60, - 236,0,132,52,255,253,3,60,224,133,130,143, - 255,255,99,52,36,16,67,0,224,133,130,175, - 0,0,130,172,7,162,16,60,236,0,16,54, - 255,252,3,60,255,255,99,52,0,1,18,36, - 7,162,17,60,236,0,49,54,0,4,23,60, - 255,251,20,60,255,255,148,54,0,1,21,60, - 255,254,19,60,224,133,130,143,0,0,0,0, - 36,16,67,0,224,133,130,175,0,0,2,174, - 76,63,192,12,255,255,115,54,224,133,130,143, - 0,2,3,60,37,16,67,0,224,133,130,175, - 0,0,2,174,0,1,66,50,5,0,64,16, - 0,0,0,0,224,133,130,143,0,0,0,0, - 108,71,192,8,37,16,87,0,224,133,130,143, - 0,0,0,0,36,16,84,0,224,133,130,175, - 76,63,192,12,0,0,34,174,224,133,130,143, - 0,0,0,0,37,16,85,0,224,133,130,175, - 0,0,34,174,76,63,192,12,66,144,18,0, - 224,133,130,143,0,0,0,0,36,16,83,0, - 224,133,130,175,0,0,34,174,255,255,66,50, - 230,255,64,20,0,1,66,50,168,69,192,12, - 33,32,192,2,38,16,194,3,255,255,66,48, - 1,0,66,44,52,0,191,143,48,0,190,143, - 44,0,183,143,40,0,182,143,36,0,181,143, - 32,0,180,143,28,0,179,143,24,0,178,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 56,0,189,39,0,0,0,0,248,255,189,39, - 255,255,195,36,6,0,192,16,33,16,128,0, - 255,255,6,36,0,0,133,160,255,255,99,36, - 253,255,102,20,1,0,132,36,8,0,189,39, - 8,0,224,3,0,0,0,0,159,71,192,8, - 33,24,0,0,1,0,99,36,0,0,130,128, - 0,0,0,0,252,255,64,20,1,0,132,36, - 8,0,224,3,33,16,96,0,0,0,0,0, - 0,0,0,0,0,0,0,0,255,255,198,36, - 10,0,192,16,0,0,0,0,0,0,131,128, - 0,0,162,128,0,0,0,0,5,0,98,20, - 0,0,0,0,1,0,132,36,255,255,198,36, - 248,255,192,20,1,0,165,36,0,0,131,144, - 0,0,162,144,0,0,0,0,8,0,224,3, - 35,16,98,0,0,0,0,0,0,0,0,0, - 0,0,0,0,196,71,192,8,240,255,189,39, - 0,0,163,128,3,22,2,0,8,0,67,20, - 0,0,0,0,1,0,132,36,1,0,165,36, - 0,0,130,128,0,0,131,144,0,0,0,0, - 246,255,64,20,0,22,3,0,0,0,131,144, - 0,0,162,144,0,0,0,0,35,16,98,0, - 8,0,224,3,16,0,189,39,0,0,0,0, - 255,255,198,36,9,0,192,4,33,16,0,0, - 0,0,130,144,0,0,0,0,5,0,69,16, - 33,16,128,0,255,255,198,36,250,255,193,4, - 1,0,132,36,33,16,0,0,8,0,224,3, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,2,0,192,20,255,255,2,36, - 1,0,2,36,8,0,224,3,0,0,226,172, - 232,255,189,39,20,0,191,175,16,0,176,175, - 40,0,176,143,33,32,192,0,4,0,5,142, - 0,0,0,0,15,86,192,12,255,255,230,48, - 3,0,64,16,255,255,2,36,243,71,192,8, - 0,0,2,174,0,0,0,174,20,0,191,143, - 16,0,176,143,8,0,224,3,24,0,189,39, - 208,255,189,39,40,0,191,175,33,24,128,0, - 64,0,162,143,32,0,160,175,36,0,162,175, - 12,0,66,148,0,0,0,0,2,0,64,20, - 33,32,160,0,120,5,2,36,255,255,66,48, - 16,0,162,175,1,131,2,60,148,31,66,36, - 20,0,162,175,1,131,2,60,128,31,66,36, - 24,0,162,175,32,0,162,39,28,0,162,175, - 166,85,192,12,33,40,96,0,32,0,162,143, - 40,0,191,143,48,0,189,39,8,0,224,3, - 0,0,0,0,0,0,0,0,88,0,131,148, - 4,0,2,36,9,0,98,20,0,0,0,0, - 33,72,192,8,116,0,132,36,33,16,69,0, - 128,16,2,0,8,0,131,140,0,0,0,0, - 46,72,192,8,33,16,67,0,104,0,132,36, - 12,0,128,16,33,16,0,0,4,0,130,140, - 0,0,0,0,42,16,162,0,243,255,64,20, - 0,17,5,0,4,0,130,140,12,0,132,140, - 0,0,0,0,247,255,128,20,35,40,162,0, - 33,16,0,0,8,0,224,3,0,0,0,0, - 88,0,131,148,4,0,2,36,3,0,98,20, - 33,48,0,0,55,72,192,8,116,0,132,36, - 104,0,132,36,8,0,130,140,0,0,0,0, - 43,16,162,0,14,0,64,16,255,255,2,36, - 92,72,192,8,0,0,0,0,35,24,163,0, - 0,17,3,0,35,16,67,0,0,26,2,0, - 33,16,67,0,0,28,2,0,33,16,67,0, - 35,16,2,0,131,16,2,0,92,72,192,8, - 33,16,194,0,18,0,128,16,0,0,0,0, - 4,0,131,140,0,0,0,0,0,17,3,0, - 33,16,67,0,128,16,2,0,8,0,131,140, - 0,0,0,0,33,16,67,0,43,16,162,0, - 233,255,64,20,0,0,0,0,4,0,130,140, - 12,0,132,140,0,0,0,0,241,255,128,20, - 33,48,194,0,255,255,2,36,8,0,224,3, - 0,0,0,0,0,0,0,0,0,0,0,0, - 8,0,130,36,144,0,163,140,120,132,135,39, - 2,0,96,16,20,0,137,36,33,56,96,0, - 0,0,72,140,4,0,68,140,132,72,192,8, - 0,0,0,0,30,0,0,25,0,0,0,0, - 4,0,227,140,0,0,0,0,4,0,98,140, - 0,0,0,0,55,0,64,16,255,255,2,36, - 0,0,135,140,0,0,98,140,0,0,0,0, - 8,0,71,16,0,0,0,0,8,0,99,36, - 4,0,98,140,0,0,0,0,248,255,64,20, - 255,255,2,36,168,72,192,8,0,0,0,0, - 0,0,130,140,0,0,0,0,4,0,34,173, - 4,0,103,140,255,255,8,37,4,0,132,36, - 0,0,226,148,0,0,0,0,1,0,66,48, - 226,255,64,16,0,0,0,0,0,0,226,148, - 0,0,0,0,64,0,66,48,27,0,64,20, - 255,255,2,36,0,0,226,148,0,0,0,0, - 1,0,66,48,17,0,64,16,0,0,0,0, - 13,0,192,16,1,0,2,36,64,0,162,140, - 0,0,0,0,9,0,64,20,1,0,2,36, - 28,0,226,140,4,0,163,140,0,0,0,0, - 36,16,67,0,3,0,64,20,1,0,2,36, - 168,72,192,8,255,255,2,36,164,72,192,8, - 0,0,34,165,0,0,32,165,8,0,40,173, - 12,0,36,173,16,0,39,173,33,16,0,0, - 8,0,224,3,0,0,0,0,200,255,189,39, - 48,0,191,175,44,0,179,175,40,0,178,175, - 36,0,177,175,32,0,176,175,33,152,128,0, - 33,128,160,0,33,144,192,0,0,0,4,142, - 0,0,0,0,48,0,130,40,2,0,64,16, - 8,0,113,38,48,0,4,36,0,0,36,174, - 9,50,192,12,128,32,4,0,3,0,64,20, - 4,0,34,174,214,72,192,8,255,255,2,36, - 144,0,66,142,120,132,132,39,2,0,64,16, - 0,0,0,0,33,32,64,0,16,0,160,175, - 20,0,179,175,24,0,178,175,0,0,5,142, - 4,0,6,142,0,0,0,0,221,72,192,12, - 33,56,32,2,33,128,64,0,4,0,0,26, - 0,0,0,0,0,0,34,142,214,72,192,8, - 0,0,0,0,110,86,192,12,33,32,32,2, - 33,16,0,2,48,0,191,143,44,0,179,143, - 40,0,178,143,36,0,177,143,32,0,176,143, - 8,0,224,3,56,0,189,39,184,255,189,39, - 68,0,191,175,64,0,190,175,60,0,183,175, - 56,0,182,175,52,0,181,175,48,0,180,175, - 44,0,179,175,40,0,178,175,36,0,177,175, - 32,0,176,175,33,144,128,0,33,176,160,0, - 33,136,224,0,88,0,183,143,92,0,179,143, - 96,0,190,143,32,0,226,38,0,0,36,142, - 0,0,0,0,42,16,130,0,22,0,64,16, - 33,160,192,0,4,0,132,36,9,50,192,12, - 128,32,4,0,33,128,64,0,3,0,0,22, - 33,32,0,2,153,73,192,8,255,255,2,36, - 0,0,38,142,4,0,37,142,0,0,0,0, - 80,68,192,12,128,48,6,0,4,0,36,142, - 61,50,192,12,0,0,0,0,4,0,48,174, - 0,0,34,142,0,0,0,0,4,0,66,36, - 0,0,34,174,0,0,66,150,0,0,0,0, - 1,0,66,48,96,0,64,20,0,0,0,0, - 33,0,192,30,0,0,0,0,4,0,80,142, - 0,0,0,0,4,0,2,142,0,0,0,0, - 108,0,64,16,128,160,23,0,1,0,242,38, - 4,0,34,142,0,0,0,0,33,16,130,2, - 0,0,3,142,0,0,0,0,0,0,67,172, - 0,0,2,142,0,0,0,0,24,0,98,174, - 16,0,178,175,20,0,179,175,24,0,190,175, - 4,0,4,142,33,40,0,0,33,48,0,0, - 221,72,192,12,33,56,32,2,112,0,64,20, - 8,0,16,38,4,0,2,142,0,0,0,0, - 234,255,64,20,33,16,0,0,153,73,192,8, - 0,0,0,0,4,0,80,142,0,0,0,0, - 4,0,2,142,0,0,0,0,76,0,64,16, - 128,168,23,0,1,0,242,38,0,0,3,142, - 0,0,132,142,0,0,0,0,43,16,100,0, - 42,0,64,20,0,0,0,0,19,0,100,20, - 255,255,197,38,4,0,34,142,0,0,0,0, - 33,16,162,2,0,0,67,172,0,0,2,142, - 0,0,0,0,24,0,98,174,16,0,178,175, - 20,0,179,175,24,0,190,175,4,0,4,142, - 4,0,134,38,221,72,192,12,33,56,32,2, - 25,0,64,16,8,0,16,38,153,73,192,8, - 0,0,0,0,0,0,130,142,0,0,0,0, - 43,16,67,0,17,0,64,16,33,40,0,0, - 4,0,34,142,0,0,0,0,33,16,162,2, - 0,0,67,172,0,0,2,142,0,0,0,0, - 24,0,98,174,16,0,178,175,20,0,179,175, - 24,0,190,175,4,0,4,142,33,48,0,0, - 221,72,192,12,33,56,32,2,52,0,64,20, - 0,0,0,0,8,0,16,38,4,0,2,142, - 0,0,0,0,205,255,64,20,33,16,0,0, - 153,73,192,8,0,0,0,0,0,0,66,150, - 0,0,0,0,64,0,66,48,40,0,64,20, - 33,16,0,0,3,0,66,146,0,0,0,0, - 1,0,66,48,11,0,64,16,33,24,64,2, - 64,0,194,143,0,0,0,0,9,0,64,20, - 0,0,0,0,28,0,98,140,4,0,195,143, - 0,0,0,0,36,16,67,0,3,0,64,20, - 0,0,0,0,153,73,192,8,33,16,0,0, - 14,0,192,26,33,16,246,2,0,0,34,174, - 4,0,36,142,128,128,23,0,33,32,4,2, - 33,40,128,2,80,68,192,12,128,48,22,0, - 28,0,118,174,4,0,34,142,0,0,0,0, - 33,128,2,2,149,73,192,8,32,0,112,174, - 0,0,55,174,28,0,96,174,32,0,96,174, - 36,0,114,174,1,0,2,36,20,0,98,166, - 1,0,2,36,68,0,191,143,64,0,190,143, - 60,0,183,143,56,0,182,143,52,0,181,143, - 48,0,180,143,44,0,179,143,40,0,178,143, - 36,0,177,143,32,0,176,143,8,0,224,3, - 72,0,189,39,3,0,160,28,33,16,0,0, - 0,0,224,172,1,0,2,36,8,0,224,3, - 0,0,0,0,208,255,189,39,44,0,191,175, - 40,0,178,175,36,0,177,175,32,0,176,175, - 33,144,128,0,33,136,224,0,64,0,176,143, - 0,0,0,0,6,0,160,24,24,0,160,175, - 17,0,2,146,0,0,0,0,18,0,66,52, - 200,73,192,8,17,0,2,162,33,32,32,2, - 33,40,0,2,1,0,6,36,253,76,192,12, - 24,0,167,39,36,0,2,142,16,0,176,175, - 8,0,66,140,33,32,64,2,1,0,5,36, - 24,0,166,39,9,248,64,0,33,56,32,2, - 44,0,191,143,40,0,178,143,36,0,177,143, - 32,0,176,143,8,0,224,3,48,0,189,39, - 224,255,189,39,28,0,191,175,24,0,178,175, - 20,0,177,175,33,144,128,0,33,136,160,0, - 31,0,81,18,16,0,176,175,4,0,80,142, - 0,0,0,0,4,0,2,142,0,0,0,0, - 10,0,64,16,0,0,0,0,4,0,4,142, - 0,0,0,0,206,73,192,12,33,40,32,2, - 8,0,16,38,4,0,2,142,0,0,0,0, - 248,255,64,20,0,0,0,0,0,0,66,150, - 0,0,0,0,32,0,66,48,4,0,64,16, - 0,0,0,0,4,0,68,142,61,50,192,12, - 0,0,0,0,0,0,66,150,0,0,0,0, - 16,0,66,48,3,0,64,16,0,0,0,0, - 61,50,192,12,33,32,64,2,28,0,191,143, - 24,0,178,143,20,0,177,143,16,0,176,143, - 8,0,224,3,32,0,189,39,120,132,131,39, - 2,0,128,16,0,0,0,0,33,24,128,0, - 0,0,167,140,4,0,165,140,26,74,192,8, - 0,0,0,0,28,0,224,24,0,0,0,0, - 4,0,99,140,0,0,0,0,4,0,98,140, - 0,0,0,0,11,0,64,16,0,0,0,0, - 0,0,164,140,0,0,98,140,0,0,0,0, - 9,0,68,16,0,0,0,0,8,0,99,36, - 4,0,98,140,0,0,0,0,248,255,64,20, - 0,0,0,0,0,0,192,172,33,74,192,8, - 2,0,2,36,4,0,99,140,255,255,231,36, - 4,0,165,36,0,0,98,148,0,0,0,0, - 1,0,66,48,228,255,64,16,0,0,0,0, - 0,0,195,172,42,16,7,0,8,0,224,3, - 0,0,0,0,208,255,189,39,44,0,191,175, - 40,0,182,175,36,0,181,175,32,0,180,175, - 28,0,179,175,24,0,178,175,20,0,177,175, - 16,0,176,175,33,168,192,0,0,0,162,140, - 0,0,0,0,3,0,64,28,33,48,0,0, - 220,74,192,8,5,0,2,36,120,132,147,39, - 2,0,128,16,0,0,224,172,33,152,128,0, - 0,0,177,140,4,0,180,140,84,74,192,8, - 0,0,0,0,29,0,32,26,0,0,0,0, - 4,0,102,142,0,0,0,0,4,0,194,140, - 0,0,0,0,23,0,64,16,0,0,0,0, - 0,0,131,142,0,0,194,140,0,0,0,0, - 6,0,67,16,0,0,0,0,8,0,198,36, - 4,0,194,140,0,0,0,0,248,255,64,20, - 0,0,0,0,4,0,194,140,0,0,0,0, - 9,0,64,16,0,0,0,0,255,255,49,38, - 4,0,148,38,33,152,64,0,0,0,98,150, - 0,0,0,0,1,0,66,48,227,255,64,16, - 0,0,0,0,29,0,32,22,0,0,0,0, - 0,0,99,150,0,0,0,0,1,0,98,48, - 11,0,64,16,4,0,98,48,123,0,64,16, - 3,0,2,36,0,0,162,150,0,0,0,0, - 1,0,66,48,118,0,64,16,4,0,2,36, - 0,0,243,172,219,74,192,8,4,0,213,172, - 0,0,98,150,0,0,0,0,4,0,66,48, - 110,0,64,16,3,0,2,36,0,0,162,150, - 0,0,0,0,1,0,66,48,105,0,64,20, - 4,0,2,36,0,0,243,172,219,74,192,8, - 4,0,213,172,0,0,98,150,0,0,0,0, - 1,0,66,48,97,0,64,20,2,0,2,36, - 2,0,34,42,23,0,64,20,33,144,160,2, - 56,0,22,36,9,50,192,12,16,0,4,36, - 33,128,64,0,40,0,0,18,128,16,17,0, - 33,16,84,0,252,255,66,140,0,0,0,0, - 0,0,2,174,4,0,18,174,8,0,0,174, - 12,0,0,174,9,50,192,12,8,0,4,36, - 33,144,64,0,24,0,64,18,255,255,49,38, - 0,0,86,166,2,0,34,42,236,255,64,16, - 4,0,80,174,4,0,102,142,0,0,0,0, - 4,0,194,140,0,0,0,0,6,0,64,16, - 1,0,17,36,8,0,198,36,4,0,194,140, - 0,0,0,0,252,255,64,20,1,0,49,38, - 1,0,36,38,9,50,192,12,192,32,4,0, - 33,128,64,0,12,0,0,22,33,32,64,2, - 173,74,192,8,0,0,0,0,0,0,18,142, - 0,0,0,0,61,50,192,12,33,32,0,2, - 33,32,64,2,206,73,192,12,33,40,160,2, - 220,74,192,8,1,0,2,36,4,0,102,142, - 0,0,0,0,192,74,192,8,33,168,0,2, - 4,0,194,140,0,0,0,0,14,0,64,16, - 0,0,0,0,0,0,194,140,4,0,195,140, - 0,0,2,174,4,0,3,174,8,0,198,36, - 8,0,16,38,255,255,49,38,0,0,194,140, - 0,0,131,142,0,0,0,0,43,16,67,0, - 240,255,64,20,0,0,0,0,0,0,130,142, - 0,0,0,0,0,0,2,174,4,0,18,174, - 8,0,4,38,33,40,192,0,80,68,192,12, - 192,48,17,0,4,0,102,142,4,0,117,174, - 0,0,98,150,0,0,0,0,32,0,66,48, - 3,0,64,16,0,0,0,0,61,50,192,12, - 33,32,192,0,0,0,98,150,0,0,0,0, - 32,0,66,52,0,0,98,166,33,16,0,0, - 44,0,191,143,40,0,182,143,36,0,181,143, - 32,0,180,143,28,0,179,143,24,0,178,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 48,0,189,39,232,255,189,39,20,0,191,175, - 16,0,176,175,0,0,162,140,0,0,0,0, - 85,0,64,24,33,16,0,0,120,132,144,39, - 2,0,128,16,0,0,0,0,33,128,128,0, - 0,0,164,140,4,0,165,140,0,0,0,0, - 0,0,168,140,0,0,2,150,0,0,0,0, - 33,24,64,0,1,0,66,48,34,0,64,20, - 33,56,0,2,32,0,128,24,8,0,98,48, - 4,0,6,142,5,0,64,16,0,0,0,0, - 12,0,194,140,0,0,0,0,3,0,64,16, - 0,0,0,0,33,56,0,2,0,0,168,140, - 0,0,195,140,0,0,162,140,0,0,0,0, - 10,0,98,16,0,0,0,0,0,0,163,140, - 4,0,194,140,0,0,0,0,20,0,64,16, - 8,0,198,36,0,0,194,140,0,0,0,0, - 249,255,67,20,0,0,0,0,255,255,132,36, - 4,0,208,140,0,0,0,0,0,0,3,150, - 0,0,0,0,1,0,98,48,224,255,64,16, - 4,0,165,36,36,0,128,20,33,16,0,0, - 0,0,2,150,0,0,0,0,2,0,66,48, - 3,0,64,20,0,0,0,0,65,75,192,8, - 33,16,0,0,4,0,230,140,0,0,0,0, - 0,0,194,140,0,0,0,0,7,0,72,16, - 0,0,0,0,8,0,198,36,0,0,194,140, - 0,0,0,0,253,255,72,20,8,0,198,36, - 248,255,198,36,4,0,199,140,0,0,0,0, - 10,0,224,16,33,32,224,0,8,0,194,140, - 12,0,195,140,0,0,194,172,4,0,195,172, - 8,0,198,36,4,0,194,140,0,0,0,0, - 248,255,64,20,33,32,224,0,206,73,192,12, - 33,40,0,2,33,16,0,2,20,0,191,143, - 16,0,176,143,8,0,224,3,24,0,189,39, - 0,0,0,0,0,0,0,0,0,0,0,0, - 192,255,189,39,56,0,191,175,52,0,181,175, - 48,0,180,175,44,0,179,175,40,0,178,175, - 36,0,177,175,32,0,176,175,33,136,128,0, - 33,144,160,0,33,152,192,0,33,160,224,0, - 80,0,181,143,0,0,0,0,36,0,162,142, - 0,0,0,0,20,0,80,140,33,32,128,2, - 48,72,192,12,33,40,160,2,16,0,3,142, - 0,0,0,0,16,0,163,175,20,0,180,175, - 24,0,162,175,0,0,2,142,1,0,4,36, - 33,40,32,2,33,48,64,2,9,248,64,0, - 33,56,96,2,6,0,64,20,33,32,128,2, - 17,0,162,146,0,0,0,0,1,0,66,52, - 113,75,192,8,17,0,162,162,33,40,160,2, - 59,77,192,12,33,48,64,0,56,0,191,143, - 52,0,181,143,48,0,180,143,44,0,179,143, - 40,0,178,143,36,0,177,143,32,0,176,143, - 8,0,224,3,64,0,189,39,192,255,189,39, - 60,0,191,175,56,0,178,175,52,0,177,175, - 48,0,176,175,33,136,224,0,80,0,178,143, - 36,0,160,175,36,0,66,142,0,0,0,0, - 20,0,67,140,2,0,80,144,0,0,0,0, - 255,0,2,50,254,255,71,36,70,0,226,44, - 110,0,64,16,128,16,7,0,2,131,1,60, - 33,8,34,0,160,151,34,140,0,0,0,0, - 8,0,64,0,0,0,0,0,16,0,177,175, - 8,0,98,140,16,0,103,140,9,248,64,0, - 0,0,0,0,2,0,3,36,16,0,67,162, - 251,75,192,8,40,0,66,174,16,0,177,175, - 8,0,98,140,16,0,103,140,9,248,64,0, - 0,0,0,0,40,0,162,175,16,0,80,162, - 40,0,162,143,0,0,0,0,251,75,192,8, - 40,0,66,174,32,0,162,39,16,0,162,175, - 20,0,177,175,36,0,162,39,24,0,162,175, - 8,0,98,140,16,0,103,140,9,248,64,0, - 0,0,0,0,33,48,64,0,16,0,80,162, - 17,0,66,146,0,0,0,0,2,0,66,52, - 17,0,66,162,36,0,162,143,0,0,0,0, - 43,16,2,0,40,0,66,166,44,0,70,174, - 32,0,162,151,0,0,0,0,33,16,194,0, - 48,0,66,174,255,75,192,8,52,0,64,166, - 16,0,177,175,36,0,162,39,20,0,162,175, - 8,0,98,140,16,0,103,140,9,248,64,0, - 0,0,0,0,33,128,64,0,8,0,0,22, - 33,32,32,2,16,0,160,175,33,40,64,2, - 33,48,0,0,226,76,192,12,33,56,0,0, - 255,75,192,8,0,0,0,0,36,0,162,143, - 0,0,0,0,16,0,162,175,0,0,6,142, - 4,0,7,142,0,0,0,0,226,76,192,12, - 33,40,64,2,36,0,162,143,0,0,0,0, - 35,0,64,16,0,0,0,0,61,50,192,12, - 33,32,0,2,255,75,192,8,0,0,0,0, - 5,0,2,36,251,75,192,8,16,0,66,162, - 16,0,177,175,40,0,162,39,20,0,162,175, - 8,0,98,140,16,0,103,140,9,248,64,0, - 0,0,0,0,33,48,64,0,7,0,192,16, - 64,0,2,36,3,0,194,136,0,0,194,152, - 0,0,0,0,43,0,162,171,40,0,162,187, - 64,0,2,36,16,0,66,162,40,0,162,143, - 0,0,0,0,251,75,192,8,40,0,66,174, - 5,0,2,36,96,0,34,174,17,0,66,146, - 0,0,0,0,2,0,66,52,17,0,66,162, - 60,0,191,143,56,0,178,143,52,0,177,143, - 48,0,176,143,8,0,224,3,64,0,189,39, - 80,255,189,39,168,0,191,175,164,0,179,175, - 160,0,178,175,156,0,177,175,152,0,176,175, - 33,152,128,0,33,136,224,0,192,0,178,143, - 0,0,0,0,36,0,66,142,0,0,0,0, - 20,0,67,140,0,0,0,0,16,0,98,140, - 0,0,0,0,16,0,162,175,20,0,177,175, - 4,0,98,140,0,0,0,0,9,248,64,0, - 24,0,167,39,33,128,64,0,6,0,0,22, - 33,32,32,2,17,0,66,146,0,0,0,0, - 18,0,66,52,45,76,192,8,17,0,66,162, - 33,40,64,2,33,48,0,2,253,76,192,12, - 24,0,167,39,16,0,178,175,33,32,96,2, - 33,40,0,2,24,0,166,39,122,75,192,12, - 33,56,32,2,168,0,191,143,164,0,179,143, - 160,0,178,143,156,0,177,143,152,0,176,143, - 8,0,224,3,176,0,189,39,192,255,189,39, - 56,0,191,175,52,0,181,175,48,0,180,175, - 44,0,179,175,40,0,178,175,36,0,177,175, - 32,0,176,175,33,152,128,0,33,160,160,0, - 33,168,192,0,33,136,224,0,80,0,178,143, - 0,0,0,0,36,0,66,142,0,0,0,0, - 20,0,80,140,33,32,32,2,48,72,192,12, - 33,40,64,2,16,0,3,142,0,0,0,0, - 16,0,163,175,20,0,177,175,24,0,162,175, - 0,0,2,142,33,32,0,0,33,40,96,2, - 33,48,128,2,9,248,64,0,33,56,160,2, - 5,0,64,16,33,32,32,2,200,76,192,12, - 33,40,64,2,95,76,192,8,0,0,0,0, - 16,0,178,175,33,32,96,2,33,40,128,2, - 33,48,160,2,122,75,192,12,33,56,32,2, - 56,0,191,143,52,0,181,143,48,0,180,143, - 44,0,179,143,40,0,178,143,36,0,177,143, - 32,0,176,143,8,0,224,3,64,0,189,39, - 192,255,189,39,56,0,191,175,52,0,181,175, - 48,0,180,175,44,0,179,175,40,0,178,175, - 36,0,177,175,32,0,176,175,33,152,128,0, - 33,160,160,0,33,168,192,0,80,0,177,143, - 0,0,0,0,36,0,34,142,0,0,0,0, - 20,0,82,140,2,0,66,144,0,0,0,0, - 254,255,67,36,70,0,98,44,57,0,64,16, - 33,128,224,0,128,16,3,0,2,131,1,60, - 33,8,34,0,184,152,34,140,0,0,0,0, - 8,0,64,0,0,0,0,0,33,32,0,2, - 48,72,192,12,33,40,32,2,40,0,35,142, - 0,0,0,0,16,0,163,175,20,0,176,175, - 173,76,192,8,24,0,162,175,33,32,0,2, - 48,72,192,12,33,40,32,2,44,0,35,142, - 0,0,0,0,16,0,163,175,48,0,35,142, - 44,0,36,142,0,0,0,0,35,24,100,0, - 170,76,192,8,255,255,99,48,33,32,0,2, - 48,72,192,12,33,40,32,2,40,0,35,142, - 0,0,0,0,16,0,163,175,44,0,35,142, - 0,0,0,0,171,76,192,8,20,0,163,175, - 33,32,0,2,48,72,192,12,33,40,32,2, - 40,0,35,38,16,0,163,175,4,0,3,36, - 20,0,163,175,24,0,176,175,28,0,162,175, - 12,0,66,142,33,32,96,2,33,40,128,2, - 16,0,71,142,0,0,0,0,9,248,64,0, - 33,48,160,2,184,76,192,8,0,0,0,0, - 5,0,2,36,96,0,2,174,17,0,34,146, - 0,0,0,0,2,0,66,52,17,0,34,162, - 56,0,191,143,52,0,181,143,48,0,180,143, - 44,0,179,143,40,0,178,143,36,0,177,143, - 32,0,176,143,8,0,224,3,64,0,189,39, - 0,0,0,0,0,0,0,0,0,0,0,0, - 224,255,189,39,24,0,191,175,20,0,177,175, - 16,0,176,175,33,128,128,0,64,0,2,142, - 0,0,0,0,7,0,64,20,33,136,160,0, - 2,0,2,36,48,72,192,12,96,0,2,174, - 1,0,66,36,217,76,192,8,100,0,2,174, - 129,0,2,36,16,0,34,162,17,0,34,146, - 0,0,0,0,2,0,66,52,17,0,34,162, - 24,0,191,143,20,0,177,143,16,0,176,143, - 8,0,224,3,32,0,189,39,232,255,189,39, - 20,0,191,175,16,0,176,175,33,128,128,0, - 33,64,160,0,33,32,192,0,33,40,224,0, - 40,0,162,143,17,0,3,145,0,0,0,0, - 2,0,99,52,17,0,3,161,6,0,3,36, - 4,0,64,16,16,0,3,161,40,0,4,173, - 249,76,192,8,44,0,5,173,80,86,192,12, - 40,0,6,37,2,0,64,16,5,0,2,36, - 96,0,2,174,20,0,191,143,16,0,176,143, - 8,0,224,3,24,0,189,39,200,255,189,39, - 48,0,191,175,44,0,183,175,40,0,182,175, - 36,0,181,175,32,0,180,175,28,0,179,175, - 24,0,178,175,20,0,177,175,16,0,176,175, - 33,176,128,0,33,144,160,0,33,152,192,0, - 37,0,96,18,33,184,224,0,28,0,84,38, - 8,0,67,142,28,0,66,142,0,0,0,0, - 35,128,98,0,42,16,83,0,23,0,64,16, - 33,168,19,2,9,50,192,12,128,32,21,0, - 33,136,64,0,8,0,32,22,128,128,16,0, - 5,0,2,36,96,0,194,174,17,0,66,146, - 0,0,0,0,2,0,66,52,48,77,192,8, - 17,0,66,162,33,32,32,2,12,0,69,142, - 0,0,0,0,80,68,192,12,33,48,0,2, - 110,86,192,12,8,0,68,38,12,0,81,174, - 33,128,48,2,4,0,144,174,4,0,132,142, - 33,40,224,2,80,68,192,12,128,48,19,0, - 0,0,147,174,8,0,85,174,48,0,191,143, - 44,0,183,143,40,0,182,143,36,0,181,143, - 32,0,180,143,28,0,179,143,24,0,178,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 56,0,189,39,224,255,189,39,24,0,191,175, - 20,0,177,175,16,0,176,175,33,136,128,0, - 5,0,192,24,33,128,160,0,3,0,2,36, - 96,0,34,174,95,77,192,8,100,0,38,174, - 19,0,195,36,19,0,98,44,9,0,64,16, - 128,16,3,0,2,131,1,60,33,8,34,0, - 208,153,34,140,0,0,0,0,8,0,64,0, - 0,0,0,0,89,77,192,8,2,0,6,36, - 89,77,192,8,5,0,6,36,89,77,192,8, - 3,0,6,36,89,77,192,8,1,0,6,36, - 35,48,6,0,96,0,38,174,33,32,32,2, - 48,72,192,12,33,40,0,2,1,0,66,36, - 100,0,34,174,17,0,2,146,0,0,0,0, - 1,0,66,52,17,0,2,162,24,0,191,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 32,0,189,39,200,255,189,39,52,0,191,175, - 48,0,190,175,44,0,183,175,40,0,182,175, - 36,0,181,175,32,0,180,175,28,0,179,175, - 24,0,178,175,20,0,177,175,16,0,176,175, - 33,152,128,0,33,168,160,0,33,160,192,0, - 76,0,182,143,80,0,183,143,84,0,190,143, - 92,0,177,143,0,0,0,0,209,83,192,12, - 33,144,224,0,33,128,64,0,3,0,0,22, - 4,0,2,36,168,77,192,8,33,16,0,0, - 88,0,2,166,64,0,19,174,33,32,64,2, - 72,0,165,143,0,0,0,0,80,86,192,12, - 92,0,6,38,255,255,3,36,23,0,67,16, - 0,0,0,0,3,0,194,138,0,0,194,154, - 0,0,0,0,103,0,2,170,100,0,2,186, - 104,0,23,174,108,0,30,174,88,0,168,143, - 0,0,0,0,112,0,8,174,72,0,0,166, - 76,0,20,174,255,255,162,50,33,16,130,2, - 80,0,2,174,84,0,0,166,9,0,32,18, - 120,0,17,174,224,83,192,12,33,32,32,2, - 6,0,64,20,124,0,2,174,167,83,192,12, - 33,32,0,2,168,77,192,8,33,16,0,0, - 124,0,0,174,33,16,0,2,52,0,191,143, - 48,0,190,143,44,0,183,143,40,0,182,143, - 36,0,181,143,32,0,180,143,28,0,179,143, - 24,0,178,143,20,0,177,143,16,0,176,143, - 8,0,224,3,56,0,189,39,224,255,189,39, - 28,0,191,175,24,0,178,175,20,0,177,175, - 16,0,176,175,33,144,128,0,92,0,68,142, - 128,86,192,12,0,0,0,0,96,0,68,142, - 0,0,0,0,128,86,192,12,33,128,64,0, - 100,0,68,142,0,0,0,0,128,86,192,12, - 33,136,64,0,33,128,17,2,6,0,16,38, - 33,16,80,0,90,0,66,166,191,79,192,12, - 104,0,68,38,255,255,67,48,90,0,68,150, - 128,0,98,44,5,0,64,20,2,0,130,36, - 0,1,98,44,2,0,64,20,3,0,130,36, - 4,0,130,36,33,16,67,0,90,0,66,166, - 80,0,66,142,76,0,67,142,90,0,80,150, - 64,0,68,142,0,0,0,0,128,86,192,12, - 35,136,67,0,255,255,67,48,90,0,68,150, - 0,0,0,0,128,0,130,44,9,0,64,20, - 0,1,130,44,4,0,64,16,0,0,0,0, - 33,24,112,0,237,77,192,8,6,0,99,36, - 33,24,112,0,237,77,192,8,7,0,99,36, - 33,24,112,0,5,0,99,36,255,255,36,50, - 128,0,130,44,5,0,64,20,1,0,130,36, - 0,1,130,44,2,0,64,20,2,0,130,36, - 3,0,130,36,33,16,98,0,2,0,66,166, - 2,0,67,150,2,0,68,150,0,0,0,0, - 128,0,130,44,6,0,64,20,1,0,99,36, - 0,1,130,44,4,0,64,20,2,0,98,36, - 3,78,192,8,3,0,98,36,1,0,98,36, - 0,0,66,166,0,0,66,150,28,0,191,143, - 24,0,178,143,20,0,177,143,16,0,176,143, - 8,0,224,3,32,0,189,39,216,255,189,39, - 32,0,191,175,28,0,179,175,24,0,178,175, - 20,0,177,175,16,0,176,175,33,152,128,0, - 171,86,192,12,92,0,100,38,104,0,100,142, - 0,0,0,0,128,86,192,12,33,144,64,0, - 108,0,100,142,0,0,0,0,128,86,192,12, - 33,136,64,0,112,0,100,142,0,0,0,0, - 153,86,192,12,33,128,64,0,10,0,82,38, - 33,136,50,2,33,128,17,2,4,0,16,38, - 33,16,80,0,90,0,98,166,191,79,192,12, - 116,0,100,38,255,255,67,48,90,0,100,150, - 128,0,98,44,5,0,64,20,2,0,130,36, - 0,1,98,44,2,0,64,20,3,0,130,36, - 4,0,130,36,33,16,67,0,90,0,98,166, - 80,0,98,142,76,0,99,142,90,0,113,150, - 64,0,100,142,0,0,0,0,128,86,192,12, - 35,128,67,0,255,255,67,48,90,0,100,150, - 0,0,0,0,128,0,130,44,9,0,64,20, - 0,1,130,44,4,0,64,16,0,0,0,0, - 33,24,113,0,74,78,192,8,6,0,99,36, - 33,24,113,0,74,78,192,8,7,0,99,36, - 33,24,113,0,5,0,99,36,255,255,4,50, - 128,0,130,44,5,0,64,20,1,0,130,36, - 0,1,130,44,2,0,64,20,2,0,130,36, - 3,0,130,36,33,16,98,0,2,0,98,166, - 2,0,99,150,2,0,100,150,0,0,0,0, - 128,0,130,44,6,0,64,20,1,0,99,36, - 0,1,130,44,4,0,64,20,2,0,112,36, - 96,78,192,8,3,0,112,36,1,0,112,36, - 255,255,2,50,32,0,191,143,28,0,179,143, - 24,0,178,143,20,0,177,143,16,0,176,143, - 8,0,224,3,40,0,189,39,208,255,189,39, - 40,0,191,175,36,0,179,175,32,0,178,175, - 28,0,177,175,24,0,176,175,33,128,128,0, - 33,152,192,0,33,144,224,0,33,136,160,0, - 16,0,4,36,32,0,5,36,1,131,6,60, - 56,97,198,36,242,86,192,12,33,56,0,2, - 255,255,36,50,1,131,5,60,56,97,165,36, - 44,87,192,12,33,48,0,2,16,0,176,175, - 2,0,4,36,33,40,0,0,1,131,7,60, - 56,97,231,36,94,87,192,12,33,48,96,2, - 8,0,71,142,4,0,66,142,0,0,0,0, - 35,56,226,0,1,131,2,60,56,97,66,36, - 16,0,162,175,20,0,176,175,4,0,4,36, - 33,40,0,0,4,0,70,142,0,0,0,0, - 194,87,192,12,255,255,231,48,40,0,191,143, - 36,0,179,143,32,0,178,143,28,0,177,143, - 24,0,176,143,8,0,224,3,48,0,189,39, - 216,255,189,39,36,0,191,175,32,0,178,175, - 28,0,177,175,24,0,176,175,33,128,128,0, - 33,136,160,0,88,0,4,150,160,0,5,36, - 1,131,6,60,56,97,198,36,242,86,192,12, - 33,56,32,2,90,0,4,150,1,131,5,60, - 56,97,165,36,44,87,192,12,33,48,32,2, - 16,0,177,175,6,0,4,36,33,40,0,0, - 1,131,7,60,56,97,231,36,15,88,192,12, - 92,0,6,38,1,131,18,60,56,97,82,38, - 16,0,178,175,20,0,177,175,33,32,0,0, - 64,0,5,36,100,0,6,38,194,87,192,12, - 4,0,7,36,16,0,177,175,2,0,4,36, - 33,40,0,0,104,0,6,142,0,0,0,0, - 94,87,192,12,33,56,64,2,16,0,177,175, - 2,0,4,36,33,40,0,0,108,0,6,142, - 0,0,0,0,94,87,192,12,33,56,64,2, - 16,0,177,175,3,0,4,36,64,0,5,36, - 112,0,6,142,0,0,0,0,143,87,192,12, - 33,56,64,2,116,0,4,38,7,79,192,12, - 33,40,32,2,36,0,191,143,32,0,178,143, - 28,0,177,143,24,0,176,143,8,0,224,3, - 40,0,189,39,216,255,189,39,32,0,191,175, - 28,0,177,175,24,0,176,175,33,128,128,0, - 33,136,160,0,88,0,4,150,160,0,5,36, - 1,131,6,60,56,97,198,36,242,86,192,12, - 33,56,32,2,90,0,4,150,1,131,5,60, - 56,97,165,36,44,87,192,12,33,48,32,2, - 16,0,177,175,2,0,4,36,92,0,6,142, - 1,131,7,60,56,97,231,36,94,87,192,12, - 33,40,0,0,16,0,177,175,2,0,4,36, - 96,0,6,142,1,131,7,60,56,97,231,36, - 94,87,192,12,33,40,0,0,16,0,177,175, - 2,0,4,36,100,0,6,142,1,131,7,60, - 56,97,231,36,94,87,192,12,33,40,0,0, - 104,0,4,38,7,79,192,12,33,40,32,2, - 32,0,191,143,28,0,177,143,24,0,176,143, - 8,0,224,3,40,0,189,39,200,255,189,39, - 52,0,191,175,48,0,180,175,44,0,179,175, - 40,0,178,175,36,0,177,175,32,0,176,175, - 33,144,128,0,33,136,160,0,16,0,4,36, - 32,0,5,36,1,131,6,60,56,97,198,36, - 242,86,192,12,33,56,32,2,0,0,68,150, - 1,131,5,60,56,97,165,36,44,87,192,12, - 33,48,32,2,155,0,64,18,0,0,0,0, - 1,131,20,60,56,97,148,38,8,0,80,142, - 0,0,0,0,145,0,0,18,0,0,0,0, - 4,0,66,142,0,0,0,0,141,0,64,24, - 33,152,0,0,16,0,4,36,32,0,5,36, - 33,48,128,2,242,86,192,12,33,56,32,2, - 4,0,4,150,33,40,128,2,44,87,192,12, - 33,48,32,2,16,0,177,175,6,0,4,36, - 33,40,0,0,8,0,6,38,15,88,192,12, - 33,56,128,2,16,0,3,146,65,0,2,36, - 47,0,98,16,66,0,98,40,18,0,64,16, - 5,0,2,36,88,0,98,16,6,0,98,40, - 7,0,64,16,2,0,2,36,30,0,98,16, - 4,0,2,36,51,0,98,16,4,0,4,36, - 174,79,192,8,1,0,115,38,6,0,2,36, - 68,0,98,16,64,0,2,36,78,0,98,16, - 33,32,0,0,174,79,192,8,1,0,115,38, - 68,0,2,36,47,0,98,16,69,0,98,40, - 7,0,64,16,66,0,2,36,24,0,98,16, - 67,0,2,36,25,0,98,16,3,0,4,36, - 174,79,192,8,1,0,115,38,131,0,98,40, - 83,0,64,16,128,0,98,40,68,0,64,16, - 0,0,0,0,174,79,192,8,1,0,115,38, - 16,0,177,175,2,0,4,36,40,0,6,142, - 1,131,7,60,56,97,231,36,94,87,192,12, - 33,40,0,0,174,79,192,8,1,0,115,38, - 16,0,177,175,111,79,192,8,1,0,4,36, - 16,0,177,175,111,79,192,8,2,0,4,36, - 16,0,177,175,40,0,6,142,1,131,7,60, - 56,97,231,36,143,87,192,12,64,0,5,36, - 174,79,192,8,1,0,115,38,48,0,7,142, - 44,0,2,142,0,0,0,0,35,56,226,0, - 16,0,180,175,20,0,177,175,134,79,192,8, - 33,40,0,0,48,0,7,142,44,0,2,142, - 0,0,0,0,35,56,226,0,16,0,180,175, - 20,0,177,175,4,0,4,36,64,0,5,36, - 44,0,6,142,0,0,0,0,194,87,192,12, - 255,255,231,48,174,79,192,8,1,0,115,38, - 16,0,177,175,6,0,4,36,33,40,0,0, - 1,131,7,60,56,97,231,36,15,88,192,12, - 40,0,6,38,174,79,192,8,1,0,115,38, - 5,0,4,36,164,79,192,8,33,40,0,0, - 16,0,180,175,20,0,177,175,64,0,5,36, - 40,0,6,38,194,87,192,12,4,0,7,36, - 174,79,192,8,1,0,115,38,16,0,4,146, - 16,0,5,146,31,0,132,48,224,0,165,48, - 1,131,6,60,56,97,198,36,242,86,192,12, - 33,56,32,2,33,32,0,0,1,131,5,60, - 56,97,165,36,44,87,192,12,33,48,32,2, - 1,0,115,38,4,0,66,142,0,0,0,0, - 42,16,98,2,117,255,64,20,68,0,16,38, - 12,0,82,142,0,0,0,0,105,255,64,22, - 0,0,0,0,52,0,191,143,48,0,180,143, - 44,0,179,143,40,0,178,143,36,0,177,143, - 32,0,176,143,8,0,224,3,56,0,189,39, - 200,255,189,39,52,0,191,175,48,0,182,175, - 44,0,181,175,40,0,180,175,36,0,179,175, - 32,0,178,175,28,0,177,175,24,0,176,175, - 33,168,128,0,33,152,160,2,113,0,160,18, - 33,144,0,0,4,0,22,36,8,0,112,142, - 0,0,0,0,104,0,0,18,0,0,0,0, - 4,0,98,142,0,0,0,0,100,0,64,24, - 33,160,0,0,171,86,192,12,8,0,4,38, - 255,255,67,48,128,0,98,44,5,0,64,20, - 2,0,113,36,0,1,98,44,2,0,64,20, - 3,0,113,36,4,0,113,36,16,0,3,146, - 64,0,2,36,50,0,98,16,65,0,98,40, - 16,0,64,16,68,0,2,36,34,0,118,16, - 5,0,98,40,5,0,64,16,2,0,2,36, - 20,0,98,16,255,255,36,50,22,80,192,8, - 0,0,0,0,5,0,2,36,35,0,98,16, - 6,0,2,36,29,0,98,16,255,255,36,50, - 22,80,192,8,0,0,0,0,19,0,98,16, - 68,0,98,40,12,0,64,20,131,0,98,40, - 28,0,64,16,128,0,98,40,27,0,64,20, - 255,255,36,50,22,80,192,8,18,0,0,166, - 40,0,4,142,128,86,192,12,0,0,0,0, - 21,80,192,8,18,0,2,166,40,0,4,142, - 153,86,192,12,0,0,0,0,21,80,192,8, - 18,0,2,166,48,0,2,142,44,0,3,142, - 0,0,0,0,35,16,67,0,21,80,192,8, - 18,0,2,166,171,86,192,12,40,0,4,38, - 21,80,192,8,18,0,2,166,21,80,192,8, - 18,0,0,166,18,0,22,166,255,255,36,50, - 18,0,3,150,0,0,0,0,128,0,98,44, - 6,0,64,20,1,0,132,36,0,1,98,44, - 4,0,64,20,2,0,98,36,33,80,192,8, - 3,0,98,36,1,0,98,36,33,16,130,0, - 4,0,2,166,4,0,4,150,0,0,0,0, - 1,0,132,36,4,0,3,150,0,0,0,0, - 128,0,98,44,6,0,64,20,255,255,69,50, - 0,1,98,44,4,0,64,20,2,0,162,36, - 49,80,192,8,3,0,162,36,1,0,162,36, - 33,144,68,0,1,0,148,38,4,0,98,142, - 0,0,0,0,42,16,130,2,158,255,64,20, - 68,0,16,38,12,0,115,142,0,0,0,0, - 146,255,96,22,0,0,0,0,0,0,178,166, - 255,255,66,50,52,0,191,143,48,0,182,143, - 44,0,181,143,40,0,180,143,36,0,179,143, - 32,0,178,143,28,0,177,143,24,0,176,143, - 8,0,224,3,56,0,189,39,224,255,189,39, - 24,0,191,175,20,0,177,175,16,0,176,175, - 33,128,128,0,171,86,192,12,8,0,4,38, - 255,255,67,48,128,0,98,44,5,0,64,20, - 2,0,113,36,0,1,98,44,2,0,64,20, - 3,0,113,36,4,0,113,36,16,0,3,146, - 64,0,2,36,52,0,98,16,65,0,98,40, - 17,0,64,16,4,0,2,36,37,0,98,16, - 0,0,0,0,5,0,98,40,5,0,64,16, - 2,0,2,36,22,0,98,16,255,255,36,50, - 145,80,192,8,0,0,0,0,5,0,2,36, - 36,0,98,16,6,0,2,36,30,0,98,16, - 255,255,36,50,145,80,192,8,0,0,0,0, - 68,0,2,36,20,0,98,16,0,0,0,0, - 68,0,98,40,12,0,64,20,131,0,98,40, - 28,0,64,16,128,0,98,40,27,0,64,20, - 255,255,36,50,145,80,192,8,18,0,0,166, - 40,0,4,142,128,86,192,12,0,0,0,0, - 144,80,192,8,18,0,2,166,40,0,4,142, - 153,86,192,12,0,0,0,0,144,80,192,8, - 18,0,2,166,48,0,2,142,44,0,3,142, - 0,0,0,0,143,80,192,8,35,16,67,0, - 171,86,192,12,40,0,4,38,144,80,192,8, - 18,0,2,166,144,80,192,8,18,0,0,166, - 4,0,2,36,18,0,2,166,255,255,36,50, - 18,0,3,150,0,0,0,0,128,0,98,44, - 6,0,64,20,1,0,132,36,0,1,98,44, - 4,0,64,20,2,0,98,36,156,80,192,8, - 3,0,98,36,1,0,98,36,33,16,130,0, - 4,0,2,166,4,0,3,150,4,0,4,150, - 0,0,0,0,128,0,130,44,6,0,64,20, - 1,0,99,36,0,1,130,44,4,0,64,20, - 2,0,98,36,170,80,192,8,3,0,98,36, - 1,0,98,36,255,255,66,48,24,0,191,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 32,0,189,39,232,255,189,39,16,0,191,175, - 64,0,130,140,0,0,0,0,12,0,64,20, - 33,16,0,0,88,0,131,148,4,0,2,36, - 5,0,98,16,0,0,0,0,180,77,192,12, - 0,0,0,0,193,80,192,8,255,255,66,48, - 11,78,192,12,0,0,0,0,255,255,66,48, - 16,0,191,143,24,0,189,39,8,0,224,3, - 0,0,0,0,224,255,189,39,24,0,191,175, - 20,0,177,175,16,0,176,175,33,128,128,0, - 176,80,192,12,33,136,160,0,33,32,0,2, - 33,40,32,2,213,80,192,12,255,255,70,48, - 24,0,191,143,20,0,177,143,16,0,176,143, - 8,0,224,3,32,0,189,39,224,255,189,39, - 28,0,191,175,24,0,178,175,20,0,177,175, - 16,0,176,175,33,144,128,0,33,136,192,0, - 255,255,34,50,41,0,64,16,33,128,160,0, - 4,0,2,142,0,0,0,0,11,0,64,20, - 255,255,35,50,9,50,192,12,255,255,36,50, - 33,24,64,0,32,0,96,16,1,0,2,36, - 0,0,2,166,4,0,3,174,8,0,3,174, - 242,80,192,8,12,0,17,166,12,0,2,150, - 0,0,0,0,43,16,67,0,23,0,64,20, - 255,255,2,36,64,0,66,142,0,0,0,0, - 19,0,64,20,255,255,2,36,33,32,0,2, - 2,0,69,150,33,48,0,0,104,78,192,12, - 72,0,71,38,88,0,67,150,4,0,2,36, - 5,0,98,16,33,32,64,2,217,78,192,12, - 33,40,0,2,8,81,192,8,33,16,0,0, - 153,78,192,12,33,40,0,2,8,81,192,8, - 33,16,0,0,255,255,2,36,28,0,191,143, - 24,0,178,143,20,0,177,143,16,0,176,143, - 8,0,224,3,32,0,189,39,0,0,0,0, - 0,0,0,0,168,255,189,39,80,0,191,175, - 76,0,183,175,72,0,182,175,68,0,181,175, - 64,0,180,175,60,0,179,175,56,0,178,175, - 52,0,177,175,48,0,176,175,33,24,128,0, - 33,152,160,0,33,176,192,0,33,184,224,0, - 104,0,162,143,0,0,0,0,2,0,64,20, - 44,0,160,175,40,0,162,39,0,0,64,172, - 24,0,164,39,33,40,96,0,156,88,192,12, - 33,48,96,2,33,136,64,0,82,0,32,18, - 33,16,0,0,209,83,192,12,0,0,0,0, - 33,144,64,0,5,0,64,22,1,0,2,36, - 183,88,192,12,33,32,32,2,124,81,192,8, - 33,16,0,0,148,0,66,162,196,88,192,12, - 33,32,32,2,224,0,85,48,44,0,176,39, - 33,32,32,2,124,89,192,12,33,40,0,2, - 33,160,64,0,33,32,32,2,198,89,192,12, - 33,40,0,2,2,0,66,166,44,0,162,143, - 0,0,0,0,14,0,64,20,0,0,0,0, - 8,0,35,142,4,0,34,142,0,0,0,0, - 35,128,98,0,2,0,66,150,0,0,0,0, - 33,128,2,2,42,16,19,2,16,0,64,20, - 33,32,32,2,42,16,112,2,16,0,64,16, - 0,0,0,0,167,83,192,12,33,32,64,2, - 183,88,192,12,33,32,32,2,3,131,3,60, - 140,17,99,36,0,0,98,140,0,0,0,0, - 1,0,66,36,0,0,98,172,124,81,192,8, - 33,16,0,0,33,40,0,2,42,89,192,12, - 33,48,0,0,255,0,162,50,255,255,131,50, - 37,16,67,0,48,0,3,36,8,0,67,20, - 33,32,64,2,16,0,176,175,33,40,32,2, - 33,48,192,2,135,81,192,12,33,56,224,2, - 117,81,192,8,33,128,64,0,3,131,3,60, - 140,17,99,36,0,0,98,140,0,0,0,0, - 1,0,66,36,0,0,98,172,33,128,0,0, - 3,0,0,22,0,0,0,0,167,83,192,12, - 33,32,64,2,183,88,192,12,33,32,32,2, - 33,16,0,2,80,0,191,143,76,0,183,143, - 72,0,182,143,68,0,181,143,64,0,180,143, - 60,0,179,143,56,0,178,143,52,0,177,143, - 48,0,176,143,8,0,224,3,88,0,189,39, - 176,255,189,39,76,0,191,175,72,0,182,175, - 68,0,181,175,64,0,180,175,60,0,179,175, - 56,0,178,175,52,0,177,175,48,0,176,175, - 33,128,128,0,33,136,160,0,33,160,192,0, - 33,168,224,0,96,0,182,143,24,0,160,175, - 33,32,32,2,24,0,165,39,2,0,6,36, - 239,90,192,12,33,56,0,0,64,0,2,174, - 24,0,162,143,0,0,0,0,155,0,64,20, - 0,0,0,0,64,0,2,142,0,0,0,0, - 4,0,64,16,33,32,32,2,3,131,3,60, - 60,82,192,8,148,17,99,36,16,0,160,175, - 72,0,5,38,24,0,166,39,110,90,192,12, - 4,0,7,36,24,0,162,143,0,0,0,0, - 139,0,64,20,0,0,0,0,196,88,192,12, - 33,32,32,2,224,0,66,48,160,0,3,36, - 133,0,67,20,33,32,32,2,124,89,192,12, - 24,0,165,39,33,144,64,0,33,32,32,2, - 198,89,192,12,24,0,165,39,33,152,64,0, - 24,0,162,143,0,0,0,0,122,0,64,20, - 0,0,0,0,255,255,66,50,5,0,66,44, - 118,0,64,16,0,0,0,0,8,0,34,142, - 4,0,35,142,0,0,0,0,35,16,67,0, - 255,255,99,50,33,16,67,0,110,0,194,22, - 33,32,0,2,88,0,18,166,90,0,19,166, - 33,40,128,2,178,50,192,12,33,48,160,2, - 118,0,64,20,33,16,0,0,255,255,67,50, - 4,0,2,36,24,0,98,16,33,32,32,2, - 24,0,165,39,2,0,6,36,239,90,192,12, - 33,56,0,0,92,0,2,174,33,32,32,2, - 24,0,165,39,2,0,6,36,239,90,192,12, - 33,56,0,0,96,0,2,174,33,32,32,2, - 24,0,165,39,2,0,6,36,239,90,192,12, - 33,56,0,0,100,0,2,174,24,0,162,143, - 0,0,0,0,78,0,64,20,33,32,32,2, - 67,82,192,8,104,0,5,38,4,0,2,36, - 88,0,2,166,90,0,19,166,124,0,0,174, - 16,0,160,175,92,0,5,38,24,0,166,39, - 186,91,192,12,6,0,7,36,24,0,162,143, - 0,0,0,0,63,0,64,20,100,0,4,38, - 33,40,0,0,144,71,192,12,4,0,6,36, - 32,0,160,167,40,0,160,175,36,0,160,175, - 44,0,160,167,32,0,178,39,64,0,2,36, - 16,0,162,175,33,32,32,2,33,40,64,2, - 24,0,166,39,110,90,192,12,33,56,0,0, - 24,0,162,143,0,0,0,0,5,0,64,16, - 0,0,0,0,24,92,192,12,33,32,64,2, - 58,82,192,8,0,0,0,0,40,0,162,143, - 36,0,163,143,0,0,0,0,35,16,67,0, - 255,255,70,48,5,0,194,44,2,0,64,20, - 0,0,0,0,4,0,6,36,8,0,192,16, - 33,32,32,2,36,0,165,143,0,0,0,0, - 80,68,192,12,100,0,4,38,24,92,192,12, - 32,0,164,39,33,32,32,2,24,0,165,39, - 2,0,6,36,239,90,192,12,33,56,0,0, - 104,0,2,174,33,32,32,2,24,0,165,39, - 2,0,6,36,239,90,192,12,33,56,0,0, - 108,0,2,174,33,32,32,2,24,0,165,39, - 3,0,6,36,239,90,192,12,64,0,7,36, - 112,0,2,174,24,0,162,143,0,0,0,0, - 9,0,64,16,33,32,32,2,3,131,3,60, - 140,17,99,36,0,0,98,140,0,0,0,0, - 1,0,66,36,0,0,98,172,73,82,192,8, - 33,16,0,0,116,0,5,38,33,48,192,2, - 163,82,192,12,33,56,0,2,255,255,3,36, - 248,255,67,16,33,16,0,2,76,0,191,143, - 72,0,182,143,68,0,181,143,64,0,180,143, - 60,0,179,143,56,0,178,143,52,0,177,143, - 48,0,176,143,8,0,224,3,80,0,189,39, - 184,255,189,39,64,0,191,175,60,0,183,175, - 56,0,182,175,52,0,181,175,48,0,180,175, - 44,0,179,175,40,0,178,175,36,0,177,175, - 32,0,176,175,33,128,128,0,16,0,160,175, - 8,0,2,142,4,0,3,142,0,0,0,0, - 35,184,67,0,33,144,0,0,255,255,162,48, - 45,0,64,16,33,136,0,0,3,131,19,60, - 140,17,115,38,255,255,22,36,255,255,181,48, - 8,0,3,142,4,0,2,142,0,0,0,0, - 35,160,98,0,0,0,2,146,0,0,0,0, - 128,0,66,48,32,0,64,20,33,32,0,2, - 124,89,192,12,16,0,165,39,33,32,0,2, - 198,89,192,12,16,0,165,39,33,40,64,0, - 16,0,162,143,0,0,0,0,6,0,64,20, - 33,32,0,2,255,255,165,48,251,88,192,12, - 1,0,6,36,7,0,86,20,0,0,0,0, - 0,0,98,142,0,0,0,0,1,0,66,36, - 0,0,98,174,147,82,192,8,255,255,17,36, - 8,0,2,142,4,0,3,142,0,0,0,0, - 35,16,67,0,33,16,66,2,35,144,84,0, - 255,255,66,50,43,16,85,0,217,255,64,20, - 1,0,49,38,33,32,0,2,33,40,224,2, - 251,88,192,12,33,48,0,0,33,16,32,2, - 64,0,191,143,60,0,183,143,56,0,182,143, - 52,0,181,143,48,0,180,143,44,0,179,143, - 40,0,178,143,36,0,177,143,32,0,176,143, - 8,0,224,3,72,0,189,39,192,255,189,39, - 56,0,191,175,52,0,181,175,48,0,180,175, - 44,0,179,175,40,0,178,175,36,0,177,175, - 32,0,176,175,33,144,128,0,33,152,160,0, - 33,168,224,0,16,0,160,175,124,89,192,12, - 16,0,165,39,33,32,64,2,198,89,192,12, - 16,0,165,39,0,0,98,166,16,0,162,143, - 0,0,0,0,28,0,64,20,0,0,0,0, - 12,0,66,142,8,0,67,142,0,0,0,0, - 35,16,67,0,0,0,99,150,255,255,66,48, - 20,0,98,20,0,0,0,0,4,0,96,174, - 0,0,101,150,0,0,0,0,83,82,192,12, - 33,32,64,2,33,32,64,0,255,255,2,36, - 46,0,130,16,0,0,0,0,3,0,128,20, - 0,0,0,0,246,82,192,8,8,0,96,174, - 224,83,192,12,4,0,100,174,10,0,64,20, - 8,0,98,174,247,82,192,8,255,255,2,36, - 3,131,3,60,140,17,99,36,0,0,98,140, - 0,0,0,0,1,0,66,36,210,82,192,8, - 0,0,98,172,8,0,112,142,4,0,98,142, - 0,0,0,0,23,0,64,24,33,136,0,0, - 255,255,20,36,33,32,64,2,124,89,192,12, - 16,0,165,39,33,32,64,2,198,89,192,12, - 16,0,165,39,4,0,2,166,16,0,162,143, - 0,0,0,0,233,255,64,20,33,32,64,2, - 33,40,0,2,0,83,192,12,33,48,160,2, - 226,255,84,16,1,0,49,38,4,0,98,142, - 0,0,0,0,42,16,34,2,236,255,64,20, - 68,0,16,38,33,16,0,0,56,0,191,143, - 52,0,181,143,48,0,180,143,44,0,179,143, - 40,0,178,143,36,0,177,143,32,0,176,143, - 8,0,224,3,64,0,189,39,184,255,189,39, - 68,0,191,175,64,0,180,175,60,0,179,175, - 56,0,178,175,52,0,177,175,48,0,176,175, - 33,128,128,0,33,144,160,0,24,0,160,175, - 16,0,160,175,8,0,69,38,24,0,166,39, - 186,91,192,12,6,0,7,36,24,0,162,143, - 0,0,0,0,103,0,64,20,0,0,0,0, - 196,88,192,12,33,32,0,2,224,0,84,48, - 33,32,0,2,124,89,192,12,24,0,165,39, - 33,152,64,0,33,32,0,2,198,89,192,12, - 24,0,165,39,33,136,64,0,24,0,162,143, - 0,0,0,0,88,0,64,20,37,16,116,2, - 18,0,81,166,16,0,66,162,16,0,67,146, - 64,0,2,36,48,0,98,16,65,0,98,40, - 16,0,64,16,4,0,2,36,31,0,98,16, - 5,0,98,40,5,0,64,16,2,0,2,36, - 22,0,98,16,33,32,0,2,121,83,192,8, - 0,0,0,0,5,0,2,36,65,0,98,16, - 6,0,2,36,27,0,98,16,33,32,0,2, - 121,83,192,8,0,0,0,0,68,0,2,36, - 15,0,98,16,68,0,98,40,8,0,64,20, - 33,32,0,2,131,0,98,40,57,0,64,16, - 128,0,98,40,51,0,64,16,0,0,0,0, - 121,83,192,8,0,0,0,0,255,255,37,50, - 164,90,192,12,24,0,166,39,117,83,192,8, - 40,0,66,174,33,32,0,2,255,255,37,50, - 40,0,70,38,19,90,192,12,24,0,167,39, - 117,83,192,8,0,0,0,0,255,255,37,50, - 40,0,70,38,24,91,192,12,24,0,167,39, - 117,83,192,8,0,0,0,0,40,0,68,38, - 33,40,0,0,144,71,192,12,4,0,6,36, - 32,0,160,167,40,0,160,175,36,0,160,175, - 44,0,160,167,33,32,0,2,255,255,37,50, - 32,0,166,39,19,90,192,12,24,0,167,39, - 40,0,162,143,36,0,163,143,0,0,0,0, - 35,16,67,0,255,255,70,48,5,0,194,44, - 2,0,64,20,0,0,0,0,4,0,6,36, - 7,0,192,16,0,0,0,0,36,0,165,143, - 0,0,0,0,80,68,192,12,40,0,68,38, - 24,92,192,12,32,0,164,39,24,0,162,143, - 0,0,0,0,8,0,64,16,33,16,0,0, - 3,131,3,60,140,17,99,36,0,0,98,140, - 0,0,0,0,1,0,66,36,0,0,98,172, - 255,255,2,36,68,0,191,143,64,0,180,143, - 60,0,179,143,56,0,178,143,52,0,177,143, - 48,0,176,143,8,0,224,3,72,0,189,39, - 232,255,189,39,20,0,191,175,16,0,176,175, - 33,128,128,0,76,0,2,142,0,0,0,0, - 3,0,64,16,0,0,0,0,24,92,192,12, - 72,0,4,38,88,0,3,150,4,0,2,36, - 5,0,98,20,0,0,0,0,110,86,192,12, - 92,0,4,38,157,83,192,8,116,0,4,38, - 13,84,192,12,104,0,4,38,120,0,4,38, - 13,84,192,12,0,0,0,0,148,0,3,146, - 0,0,0,0,248,83,192,12,33,32,0,2, - 20,0,191,143,16,0,176,143,8,0,224,3, - 24,0,189,39,232,255,189,39,20,0,191,175, - 16,0,176,175,33,128,128,0,5,0,0,18, - 0,0,0,0,136,83,192,12,0,0,0,0, - 61,50,192,12,33,32,0,2,20,0,191,143, - 16,0,176,143,8,0,224,3,24,0,189,39, - 224,255,189,39,24,0,191,175,20,0,177,175, - 16,0,176,175,33,136,128,0,9,50,192,12, - 16,0,4,36,33,128,64,0,11,0,0,18, - 33,32,0,2,33,40,0,0,144,71,192,12, - 16,0,6,36,224,83,192,12,33,32,32,2, - 4,0,64,16,8,0,2,174,4,0,17,174, - 204,83,192,8,33,16,0,2,61,50,192,12, - 33,32,0,2,33,16,0,0,24,0,191,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 32,0,189,39,232,255,189,39,20,0,191,175, - 16,0,176,175,9,50,192,12,152,0,4,36, - 33,128,64,0,4,0,0,18,33,16,0,0, - 248,83,192,12,33,32,0,2,33,16,0,2, - 20,0,191,143,16,0,176,143,8,0,224,3, - 24,0,189,39,224,255,189,39,24,0,191,175, - 20,0,177,175,0,17,4,0,33,16,68,0, - 128,136,2,0,11,0,32,18,16,0,176,175, - 9,50,192,12,33,32,32,2,33,128,64,0, - 4,0,0,18,33,32,0,2,33,40,0,0, - 144,71,192,12,33,48,32,2,243,83,192,8, - 33,16,0,2,33,16,0,0,24,0,191,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 32,0,189,39,232,255,189,39,20,0,191,175, - 16,0,176,175,33,128,128,0,33,40,0,0, - 144,71,192,12,152,0,6,36,255,0,2,36, - 88,0,2,166,120,5,2,36,58,0,2,166, - 72,0,0,166,80,0,0,174,76,0,0,174, - 84,0,0,166,148,0,0,162,149,0,0,162, - 20,0,191,143,16,0,176,143,8,0,224,3, - 24,0,189,39,208,255,189,39,40,0,191,175, - 36,0,179,175,32,0,178,175,28,0,177,175, - 24,0,176,175,33,128,128,0,31,0,0,18, - 1,0,19,36,8,0,18,142,0,0,0,0, - 16,0,64,18,0,0,0,0,4,0,2,142, - 0,0,0,0,9,0,64,24,33,136,0,0, - 59,84,192,12,33,32,64,2,1,0,49,38, - 4,0,2,142,0,0,0,0,42,16,34,2, - 249,255,64,20,68,0,82,38,8,0,4,142, - 61,50,192,12,0,0,0,0,12,0,17,142, - 4,0,96,18,0,0,0,0,33,152,0,0, - 49,84,192,8,4,0,0,174,61,50,192,12, - 33,32,0,2,33,128,32,2,227,255,0,22, - 0,0,0,0,40,0,191,143,36,0,179,143, - 32,0,178,143,28,0,177,143,24,0,176,143, - 8,0,224,3,48,0,189,39,232,255,189,39, - 20,0,191,175,16,0,176,175,33,128,128,0, - 60,0,2,142,0,0,0,0,4,0,64,16, - 0,0,0,0,9,248,64,0,0,0,0,0, - 60,0,0,174,110,86,192,12,8,0,4,38, - 78,84,192,12,33,32,0,2,20,0,191,143, - 16,0,176,143,8,0,224,3,24,0,189,39, - 232,255,189,39,16,0,191,175,16,0,131,144, - 6,0,2,36,18,0,98,16,7,0,98,40, - 5,0,64,16,4,0,2,36,6,0,98,16, - 0,0,0,0,103,84,192,8,0,0,0,0, - 68,0,2,36,11,0,98,20,0,0,0,0, - 44,0,130,140,0,0,0,0,7,0,64,16, - 0,0,0,0,24,92,192,12,40,0,132,36, - 103,84,192,8,0,0,0,0,110,86,192,12, - 40,0,132,36,16,0,191,143,24,0,189,39, - 8,0,224,3,0,0,0,0,0,0,0,0, - 216,255,189,39,32,0,191,175,28,0,179,175, - 24,0,178,175,20,0,177,175,16,0,176,175, - 33,136,192,0,56,0,179,143,0,0,0,0, - 20,72,192,12,33,144,224,0,33,128,64,0, - 11,0,0,18,33,32,32,2,33,40,64,2, - 80,86,192,12,8,0,6,38,255,255,3,36, - 5,0,67,16,2,0,2,36,16,0,2,162, - 40,0,19,174,133,84,192,8,33,16,0,0, - 255,255,2,36,32,0,191,143,28,0,179,143, - 24,0,178,143,20,0,177,143,16,0,176,143, - 8,0,224,3,40,0,189,39,216,255,189,39, - 32,0,191,175,28,0,177,175,24,0,176,175, - 33,128,128,0,96,0,5,174,100,0,6,174, - 128,0,2,142,0,0,0,0,11,0,64,16, - 0,0,0,0,13,84,192,12,104,0,4,38, - 124,0,2,142,0,0,0,0,108,0,2,174, - 128,0,2,142,0,0,0,0,112,0,2,174, - 128,0,0,174,124,0,0,174,88,0,17,150, - 2,0,2,36,88,0,2,166,176,80,192,12, - 33,32,0,2,33,56,64,0,64,0,2,142, - 0,0,0,0,35,0,64,20,255,255,35,50, - 3,0,2,36,14,0,98,16,255,255,227,48, - 58,0,2,150,0,0,0,0,43,16,67,0, - 9,0,64,16,12,0,4,38,48,0,2,142, - 28,0,5,38,52,0,7,142,0,0,0,0, - 9,248,64,0,1,0,6,36,214,84,192,8, - 0,0,0,0,96,0,2,142,0,0,0,0, - 250,255,67,36,13,0,98,44,13,0,64,16, - 128,16,3,0,2,131,1,60,33,8,34,0, - 32,154,34,140,0,0,0,0,8,0,64,0, - 0,0,0,0,204,84,192,8,2,0,2,36, - 204,84,192,8,3,0,2,36,5,0,2,36, - 96,0,2,174,52,0,2,142,0,0,0,0, - 16,0,162,175,44,0,2,142,12,0,4,38, - 28,0,5,38,33,48,0,2,9,248,64,0, - 255,255,231,48,32,0,191,143,28,0,177,143, - 24,0,176,143,8,0,224,3,40,0,189,39, - 224,255,189,39,28,0,191,175,24,0,176,175, - 33,128,128,0,96,0,5,142,0,0,0,0, - 6,0,160,16,0,0,0,0,100,0,6,142, - 140,84,192,12,0,0,0,0,56,85,192,8, - 0,0,0,0,176,80,192,12,33,32,0,2, - 33,56,64,0,88,0,2,150,0,0,0,0, - 2,0,66,44,11,0,64,16,255,255,227,48, - 58,0,2,150,0,0,0,0,43,16,67,0, - 6,0,64,16,33,32,0,2,1,0,5,36, - 140,84,192,12,33,48,0,0,56,85,192,8, - 0,0,0,0,96,0,2,142,0,0,0,0, - 49,0,64,20,2,0,2,36,88,0,3,150, - 3,0,2,36,33,0,98,16,4,0,98,40, - 7,0,64,16,2,0,98,40,41,0,64,16, - 2,0,2,36,39,0,96,4,0,0,0,0, - 13,85,192,8,0,0,0,0,5,0,2,36, - 34,0,98,20,2,0,2,36,3,131,3,60, - 236,17,99,36,0,0,98,140,0,0,0,0, - 1,0,66,36,104,0,4,38,25,0,128,16, - 0,0,98,172,3,131,5,60,176,17,165,36, - 0,0,162,140,108,0,3,142,0,0,0,0, - 33,16,67,0,0,0,162,172,12,0,132,140, - 0,0,0,0,248,255,128,20,2,0,2,36, - 47,85,192,8,88,0,2,166,3,131,4,60, - 236,17,132,36,0,0,130,140,0,0,0,0, - 1,0,66,36,0,0,130,172,200,255,130,140, - 108,0,3,142,0,0,0,0,33,16,67,0, - 200,255,130,172,2,0,2,36,88,0,2,166, - 52,0,2,142,0,0,0,0,16,0,162,175, - 44,0,2,142,12,0,4,38,28,0,5,38, - 33,48,0,2,9,248,64,0,255,255,231,48, - 28,0,191,143,24,0,176,143,8,0,224,3, - 32,0,189,39,232,255,189,39,20,0,191,175, - 16,0,176,175,33,128,128,0,88,0,3,150, - 1,0,2,36,25,0,98,16,2,0,98,40, - 5,0,64,16,3,0,2,36,7,0,96,16, - 0,0,0,0,116,85,192,8,0,0,0,0, - 37,0,98,16,0,0,0,0,116,85,192,8, - 0,0,0,0,112,0,4,142,108,0,3,142, - 0,0,0,0,34,0,96,16,0,0,0,0, - 17,0,130,144,0,0,0,0,2,0,66,48, - 33,0,64,16,255,255,99,36,250,255,96,20, - 68,0,132,36,116,85,192,8,0,0,0,0, - 112,0,4,142,108,0,3,142,0,0,0,0, - 8,0,96,16,0,0,0,0,17,0,130,144, - 0,0,0,0,2,0,66,48,19,0,64,16, - 255,255,99,36,250,255,96,20,68,0,132,36, - 118,93,192,12,33,32,0,2,241,255,64,28, - 255,255,66,40,7,0,64,16,0,0,0,0, - 92,85,192,8,0,0,0,0,120,94,192,12, - 33,32,0,2,5,0,64,20,0,0,0,0, - 219,84,192,12,33,32,0,2,167,83,192,12, - 33,32,0,2,20,0,191,143,16,0,176,143, - 8,0,224,3,24,0,189,39,232,255,189,39, - 20,0,191,175,16,0,176,175,33,128,128,0, - 88,0,3,150,1,0,2,36,17,0,98,16, - 2,0,98,40,5,0,64,16,3,0,2,36, - 9,0,96,16,0,0,0,0,156,85,192,8, - 0,0,0,0,13,0,98,16,5,0,2,36, - 7,0,98,16,0,0,0,0,156,85,192,8, - 0,0,0,0,60,95,192,12,33,32,0,2, - 154,85,192,8,0,0,0,0,0,93,192,12, - 33,32,0,2,154,85,192,8,0,0,0,0, - 252,93,192,12,33,32,0,2,5,0,64,20, - 0,0,0,0,60,85,192,12,33,32,0,2, - 162,85,192,8,0,0,0,0,167,83,192,12, - 33,32,0,2,20,0,191,143,16,0,176,143, - 8,0,224,3,24,0,189,39,192,255,189,39, - 60,0,191,175,56,0,182,175,52,0,181,175, - 48,0,180,175,44,0,179,175,40,0,178,175, - 36,0,177,175,32,0,176,175,33,64,128,0, - 33,136,192,0,33,152,224,0,84,0,182,143, - 88,0,181,143,92,0,180,143,80,0,178,151, - 3,131,3,60,128,17,99,36,0,0,98,140, - 0,0,0,0,1,0,66,36,0,0,98,172, - 24,0,162,39,16,0,162,175,33,32,160,0, - 16,81,192,12,33,40,0,1,33,128,64,0, - 57,0,0,18,255,255,66,50,58,0,3,150, - 0,0,0,0,43,16,67,0,2,0,64,16, - 0,0,0,0,58,0,18,166,44,0,22,174, - 48,0,21,174,52,0,20,174,24,0,162,143, - 0,0,0,0,7,0,64,16,1,0,2,36, - 219,84,192,12,33,32,0,2,167,83,192,12, - 33,32,0,2,5,86,192,8,0,0,0,0, - 88,0,3,150,0,0,0,0,16,0,98,16, - 2,0,98,40,5,0,64,16,3,0,2,36, - 9,0,96,16,0,0,0,0,244,85,192,8, - 0,0,0,0,11,0,98,16,5,0,2,36, - 31,0,98,16,0,0,0,0,244,85,192,8, - 0,0,0,0,3,131,3,60,239,85,192,8, - 184,17,99,36,3,131,3,60,239,85,192,8, - 188,17,99,36,3,131,3,60,192,17,99,36, - 0,0,98,140,0,0,0,0,1,0,66,36, - 3,86,192,8,0,0,98,172,3,131,3,60, - 140,17,99,36,0,0,98,140,0,0,0,0, - 1,0,66,36,0,0,98,172,167,83,192,12, - 33,32,0,2,33,32,32,2,33,40,96,2, - 1,0,6,36,9,248,160,2,33,56,128,2, - 5,86,192,8,0,0,0,0,124,85,192,12, - 33,32,0,2,60,0,191,143,56,0,182,143, - 52,0,181,143,48,0,180,143,44,0,179,143, - 40,0,178,143,36,0,177,143,32,0,176,143, - 8,0,224,3,64,0,189,39,232,255,189,39, - 20,0,191,175,16,0,176,175,33,128,128,0, - 213,80,192,12,255,255,198,48,53,0,64,20, - 255,255,2,36,3,131,3,60,144,17,99,36, - 0,0,98,140,0,0,0,0,1,0,66,36, - 0,0,98,172,96,0,2,142,0,0,0,0, - 32,0,64,16,4,0,2,36,92,0,98,140, - 0,0,0,0,1,0,66,36,92,0,98,172, - 96,0,2,142,0,0,0,0,255,255,67,36, - 5,0,98,44,32,0,64,16,128,16,3,0, - 2,131,1,60,33,8,34,0,88,154,34,140, - 0,0,0,0,8,0,64,0,0,0,0,0, - 3,131,3,60,70,86,192,8,204,17,99,36, - 3,131,3,60,70,86,192,8,212,17,99,36, - 3,131,3,60,70,86,192,8,216,17,99,36, - 3,131,3,60,70,86,192,8,208,17,99,36, - 3,131,3,60,70,86,192,8,220,17,99,36, - 88,0,3,150,0,0,0,0,8,0,98,20, - 33,16,0,0,3,131,3,60,240,17,99,36, - 0,0,98,140,0,0,0,0,1,0,66,36, - 0,0,98,172,33,16,0,0,20,0,191,143, - 16,0,176,143,8,0,224,3,24,0,189,39, - 0,0,0,0,224,255,189,39,28,0,191,175, - 24,0,178,175,20,0,177,175,16,0,176,175, - 33,144,160,0,33,128,192,0,4,0,0,174, - 14,0,128,16,0,0,4,174,128,136,4,0, - 9,50,192,12,33,32,32,2,3,0,64,20, - 4,0,2,174,104,86,192,8,255,255,2,36, - 5,0,32,18,33,40,64,2,4,0,4,142, - 0,0,0,0,80,68,192,12,33,48,32,2, - 33,16,0,0,28,0,191,143,24,0,178,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 32,0,189,39,232,255,189,39,20,0,191,175, - 16,0,176,175,33,128,128,0,4,0,4,142, - 0,0,0,0,4,0,128,16,0,0,0,0, - 61,50,192,12,0,0,0,0,4,0,0,174, - 0,0,0,174,20,0,191,143,16,0,176,143, - 8,0,224,3,24,0,189,39,0,0,0,0, - 0,0,0,0,11,0,128,4,128,0,130,40, - 20,0,64,20,1,0,3,36,255,127,2,36, - 42,16,68,0,16,0,64,16,2,0,3,36, - 127,0,2,60,255,255,66,52,148,86,192,8, - 42,16,68,0,128,255,130,40,9,0,64,16, - 1,0,3,36,0,128,130,40,6,0,64,16, - 2,0,3,36,128,255,2,60,42,16,130,0, - 2,0,64,20,4,0,3,36,3,0,3,36, - 8,0,224,3,33,16,96,0,128,0,130,44, - 14,0,64,20,1,0,2,36,255,127,2,36, - 43,16,68,0,9,0,64,16,127,0,2,60, - 255,255,66,52,43,16,68,0,6,0,64,16, - 3,0,2,36,4,0,128,4,5,0,2,36, - 169,86,192,8,4,0,2,36,2,0,2,36, - 8,0,224,3,0,0,0,0,4,0,135,140, - 0,0,130,140,0,0,0,0,65,0,64,16, - 33,16,0,0,0,0,227,140,4,0,231,36, - 128,16,3,0,33,16,67,0,192,16,2,0, - 0,0,227,140,0,0,0,0,33,24,67,0, - 128,0,98,44,17,0,64,20,4,0,231,36, - 0,64,98,44,15,0,64,20,2,0,5,36, - 31,0,2,60,255,255,66,52,43,16,67,0, - 7,0,64,16,255,15,2,60,255,255,66,52, - 43,16,67,0,6,0,64,20,5,0,5,36, - 204,86,192,8,4,0,5,36,204,86,192,8, - 3,0,5,36,1,0,5,36,2,0,6,36, - 0,0,130,140,0,0,0,0,42,16,194,0, - 31,0,64,16,255,255,162,48,31,0,9,60, - 255,255,41,53,255,15,8,60,255,255,8,53, - 0,0,132,140,0,0,227,140,4,0,231,36, - 128,0,98,44,16,0,64,20,255,255,165,48, - 0,64,98,44,11,0,64,20,43,16,35,1, - 7,0,64,16,43,16,3,1,3,0,64,20, - 0,0,0,0,236,86,192,8,4,0,165,36, - 236,86,192,8,5,0,165,36,236,86,192,8, - 3,0,165,36,236,86,192,8,2,0,165,36, - 1,0,165,36,1,0,198,36,42,16,196,0, - 232,255,64,20,255,255,162,48,8,0,224,3, - 0,0,0,0,208,255,189,39,40,0,191,175, - 33,72,192,0,224,0,165,48,255,255,130,48, - 31,0,66,44,7,0,64,16,33,48,160,0, - 37,16,133,0,16,0,162,163,33,32,224,0, - 16,0,165,39,38,87,192,8,1,0,6,36, - 32,0,163,39,33,40,0,0,31,0,194,52, - 24,0,162,163,255,255,130,48,8,0,64,16, - 25,0,168,39,127,0,130,48,0,0,98,160, - 1,0,99,36,255,255,130,48,194,33,2,0, - 250,255,128,20,1,0,165,36,1,0,166,36, - 33,16,160,0,255,255,66,48,2,0,66,44, - 13,0,64,20,255,255,165,36,255,255,4,52, - 255,255,99,36,0,0,98,144,0,0,0,0, - 128,0,66,52,0,0,2,161,1,0,8,37, - 33,16,160,0,255,255,66,48,2,0,66,44, - 246,255,64,16,33,40,164,0,255,255,98,144, - 0,0,0,0,0,0,2,161,33,32,224,0, - 24,0,165,39,255,255,198,48,9,248,32,1, - 0,0,0,0,40,0,191,143,48,0,189,39, - 8,0,224,3,0,0,0,0,208,255,189,39, - 40,0,191,175,33,72,160,0,255,255,130,48, - 128,0,66,44,6,0,64,16,33,64,192,0, - 16,0,164,163,33,32,0,1,16,0,165,39, - 88,87,192,8,1,0,6,36,24,0,167,39, - 32,0,165,39,255,255,130,48,7,0,64,16, - 33,24,0,0,0,0,164,160,1,0,165,36, - 255,255,130,48,2,34,2,0,251,255,128,20, - 1,0,99,36,128,0,98,52,0,0,226,160, - 1,0,231,36,1,0,102,36,33,16,96,0, - 255,255,66,48,11,0,64,16,255,255,99,36, - 255,255,4,52,255,255,165,36,0,0,162,144, - 0,0,0,0,0,0,226,160,1,0,231,36, - 33,16,96,0,255,255,66,48,248,255,64,20, - 33,24,100,0,33,32,0,1,24,0,165,39, - 255,255,198,48,9,248,32,1,0,0,0,0, - 40,0,191,143,48,0,189,39,8,0,224,3, - 0,0,0,0,200,255,189,39,48,0,191,175, - 44,0,181,175,40,0,180,175,36,0,179,175, - 32,0,178,175,28,0,177,175,24,0,176,175, - 33,136,160,0,33,144,192,0,33,152,224,0, - 72,0,180,143,33,128,128,0,128,86,192,12, - 33,32,64,2,33,168,64,0,255,255,4,50, - 192,0,37,50,33,48,96,2,242,86,192,12, - 33,56,128,2,255,255,176,50,33,32,0,2, - 33,40,96,2,44,87,192,12,33,48,128,2, - 16,0,162,39,33,24,80,0,255,255,99,36, - 6,0,98,16,0,0,114,160,16,0,162,39, - 3,146,18,0,255,255,99,36,253,255,98,20, - 0,0,114,160,33,32,128,2,16,0,165,39, - 9,248,96,2,255,255,166,50,48,0,191,143, - 44,0,181,143,40,0,180,143,36,0,179,143, - 32,0,178,143,28,0,177,143,24,0,176,143, - 8,0,224,3,56,0,189,39,200,255,189,39, - 48,0,191,175,44,0,181,175,40,0,180,175, - 36,0,179,175,32,0,178,175,28,0,177,175, - 24,0,176,175,33,136,160,0,33,144,192,0, - 33,160,224,0,72,0,181,143,33,128,128,0, - 153,86,192,12,33,32,64,2,33,152,64,0, - 255,255,4,50,192,0,37,50,33,48,128,2, - 242,86,192,12,33,56,160,2,255,255,112,50, - 33,32,0,2,33,40,128,2,44,87,192,12, - 33,48,160,2,16,0,162,39,33,32,80,0, - 9,0,0,18,255,255,99,38,255,255,5,52, - 255,255,132,36,0,0,146,160,2,146,18,0, - 33,16,96,0,255,255,66,48,250,255,64,20, - 33,24,101,0,33,32,160,2,16,0,165,39, - 9,248,128,2,255,255,102,50,48,0,191,143, - 44,0,181,143,40,0,180,143,36,0,179,143, - 32,0,178,143,28,0,177,143,24,0,176,143, - 8,0,224,3,56,0,189,39,216,255,189,39, - 32,0,191,175,28,0,179,175,24,0,178,175, - 20,0,177,175,16,0,176,175,33,152,192,0, - 56,0,178,143,60,0,177,143,33,128,224,0, - 255,255,132,48,192,0,165,48,33,48,64,2, - 242,86,192,12,33,56,32,2,255,255,16,50, - 33,32,0,2,33,40,64,2,44,87,192,12, - 33,48,32,2,4,0,0,18,33,32,32,2, - 33,40,96,2,9,248,64,2,33,48,0,2, - 32,0,191,143,28,0,179,143,24,0,178,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 40,0,189,39,224,255,189,39,24,0,191,175, - 33,72,160,0,128,0,130,44,18,0,64,20, - 33,64,192,0,0,64,130,44,13,0,64,20, - 31,0,2,60,255,255,66,52,43,16,68,0, - 7,0,64,16,255,15,2,60,255,255,66,52, - 43,16,68,0,8,0,64,20,5,0,6,36, - 250,87,192,8,4,0,6,36,250,87,192,8, - 3,0,6,36,250,87,192,8,2,0,6,36, - 1,0,6,36,255,255,194,48,16,0,163,39, - 33,40,98,0,9,0,163,16,33,56,0,0, - 16,0,163,39,255,255,165,36,127,0,130,48, - 37,16,226,0,0,0,162,160,194,33,4,0, - 250,255,163,20,128,0,7,36,33,32,0,1, - 16,0,165,39,9,248,32,1,255,255,198,48, - 24,0,191,143,32,0,189,39,8,0,224,3, - 0,0,0,0,208,255,189,39,44,0,191,175, - 40,0,182,175,36,0,181,175,32,0,180,175, - 28,0,179,175,24,0,178,175,20,0,177,175, - 16,0,176,175,33,144,160,0,33,168,192,0, - 33,160,224,0,64,0,182,143,33,136,128,0, - 4,0,179,142,0,0,0,0,171,86,192,12, - 33,32,160,2,33,128,64,0,255,255,36,50, - 192,0,69,50,33,48,128,2,242,86,192,12, - 33,56,192,2,255,255,16,50,33,32,0,2, - 33,40,128,2,44,87,192,12,33,48,192,2, - 23,0,0,18,33,40,128,2,0,0,98,142, - 4,0,115,38,128,32,2,0,33,32,130,0, - 192,32,4,0,0,0,98,142,4,0,115,38, - 33,32,130,0,226,87,192,12,33,48,192,2, - 63,88,192,8,2,0,16,36,0,0,100,142, - 4,0,115,38,226,87,192,12,33,48,192,2, - 1,0,16,38,0,0,162,142,0,0,0,0, - 42,16,2,2,247,255,64,20,33,40,128,2, - 44,0,191,143,40,0,182,143,36,0,181,143, - 32,0,180,143,28,0,179,143,24,0,178,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 48,0,189,39,224,255,189,39,28,0,191,175, - 24,0,178,175,20,0,177,175,16,0,176,175, - 33,136,128,0,33,144,192,0,255,255,67,50, - 12,0,34,150,0,0,0,0,43,16,67,0, - 4,0,64,16,1,0,2,36,12,0,50,150, - 0,0,0,0,255,255,67,50,11,0,98,16, - 2,0,98,40,5,0,64,16,2,0,2,36, - 50,0,96,16,255,255,80,50,137,88,192,8, - 0,0,0,0,15,0,98,16,255,255,80,50, - 137,88,192,8,0,0,0,0,8,0,35,142, - 0,0,0,0,1,0,98,36,8,0,34,174, - 0,0,162,144,0,0,0,0,0,0,98,160, - 12,0,34,150,0,0,0,0,255,255,66,36, - 149,88,192,8,12,0,34,166,8,0,35,142, - 0,0,0,0,1,0,98,36,8,0,34,174, - 0,0,162,144,0,0,0,0,0,0,98,160, - 8,0,35,142,0,0,0,0,1,0,98,36, - 8,0,34,174,1,0,162,144,0,0,0,0, - 0,0,98,160,12,0,34,150,0,0,0,0, - 254,255,66,36,149,88,192,8,12,0,34,166, - 8,0,36,142,0,0,0,0,80,68,192,12, - 33,48,0,2,12,0,34,150,0,0,0,0, - 35,16,82,0,12,0,34,166,8,0,34,142, - 0,0,0,0,33,128,2,2,8,0,48,174, - 255,255,66,50,28,0,191,143,24,0,178,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 32,0,189,39,224,255,189,39,24,0,191,175, - 20,0,177,175,16,0,176,175,33,128,160,0, - 10,0,128,20,33,136,192,0,9,50,192,12, - 16,0,4,36,33,32,64,0,3,0,128,20, - 1,0,2,36,178,88,192,8,33,16,0,0, - 173,88,192,8,0,0,130,160,0,0,128,160, - 4,0,144,172,8,0,144,172,33,16,17,2, - 12,0,130,172,33,16,128,0,24,0,191,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 32,0,189,39,232,255,189,39,16,0,191,175, - 0,0,130,144,0,0,0,0,1,0,66,48, - 3,0,64,16,0,0,0,0,61,50,192,12, - 0,0,0,0,16,0,191,143,24,0,189,39, - 8,0,224,3,0,0,0,0,0,0,130,144, - 0,0,0,0,128,0,66,48,16,0,64,20, - 255,255,2,36,8,0,130,140,12,0,131,140, - 0,0,0,0,43,16,67,0,7,0,64,20, - 0,0,0,0,0,0,130,144,0,0,0,0, - 128,0,66,52,0,0,130,160,216,88,192,8, - 255,255,2,36,8,0,130,140,0,0,0,0, - 0,0,66,144,8,0,224,3,0,0,0,0, - 30,0,192,24,33,56,192,0,0,0,130,144, - 0,0,0,0,128,0,66,48,16,0,64,20, - 255,0,3,36,8,0,131,140,12,0,130,140, - 0,0,0,0,43,16,98,0,5,0,64,16, - 1,0,98,36,8,0,130,172,0,0,99,144, - 240,88,192,8,0,0,0,0,0,0,130,144, - 0,0,0,0,128,0,66,52,0,0,130,160, - 255,0,3,36,0,0,130,144,0,0,0,0, - 128,0,66,48,5,0,64,20,0,0,0,0, - 0,0,163,160,255,255,198,36,228,255,192,28, - 1,0,165,36,8,0,224,3,35,16,230,0, - 1,0,2,36,15,0,194,16,2,0,194,40, - 5,0,64,16,2,0,2,36,7,0,192,16, - 255,255,2,36,40,89,192,8,0,0,0,0, - 11,0,194,16,255,255,2,36,40,89,192,8, - 0,0,0,0,4,0,130,140,0,0,0,0, - 21,89,192,8,33,40,162,0,8,0,130,140, - 0,0,0,0,19,89,192,8,33,40,162,0, - 12,0,130,140,0,0,0,0,35,40,69,0, - 4,0,130,140,0,0,0,0,43,16,162,0, - 17,0,64,20,255,255,2,36,12,0,130,140, - 0,0,0,0,43,16,69,0,12,0,64,20, - 255,255,2,36,12,0,130,140,0,0,0,0, - 43,16,162,0,5,0,64,16,0,0,0,0, - 0,0,130,144,0,0,0,0,127,0,66,48, - 0,0,130,160,8,0,133,172,33,16,0,0, - 8,0,224,3,0,0,0,0,12,0,130,140, - 4,0,131,140,0,0,0,0,35,56,67,0, - 1,0,2,36,15,0,194,16,2,0,194,40, - 5,0,64,16,2,0,2,36,7,0,192,16, - 255,255,2,36,87,89,192,8,0,0,0,0, - 12,0,194,16,255,255,2,36,87,89,192,8, - 0,0,0,0,4,0,130,140,0,0,0,0, - 66,89,192,8,33,16,162,0,8,0,130,140, - 0,0,0,0,33,16,162,0,72,89,192,8, - 12,0,130,172,12,0,130,140,0,0,0,0, - 35,16,69,0,12,0,130,172,8,0,130,140, - 12,0,131,140,0,0,0,0,43,16,67,0, - 5,0,64,16,0,0,0,0,0,0,130,144, - 0,0,0,0,85,89,192,8,127,0,66,48, - 0,0,130,144,0,0,0,0,128,0,66,52, - 0,0,130,160,33,16,224,0,8,0,224,3, - 0,0,0,0,232,255,189,39,20,0,191,175, - 16,0,176,175,12,0,128,20,33,128,160,0, - 9,50,192,12,16,0,4,36,33,32,64,0, - 3,0,128,20,0,0,0,0,119,89,192,8, - 33,16,0,0,0,0,2,146,0,0,0,0, - 108,89,192,8,1,0,66,52,0,0,2,146, - 0,0,0,0,254,0,66,48,0,0,130,160, - 4,0,2,142,0,0,0,0,4,0,130,172, - 8,0,2,142,0,0,0,0,8,0,130,172, - 12,0,2,142,0,0,0,0,12,0,130,172, - 33,16,128,0,20,0,191,143,16,0,176,143, - 8,0,224,3,24,0,189,39,0,0,0,0, - 0,0,130,144,0,0,0,0,128,0,66,48, - 17,0,64,20,31,0,3,36,8,0,131,140, - 12,0,130,140,0,0,0,0,43,16,98,0, - 6,0,64,16,1,0,98,36,8,0,130,172, - 0,0,98,144,0,0,0,0,145,89,192,8, - 31,0,67,48,0,0,130,144,0,0,0,0, - 128,0,66,52,0,0,130,160,31,0,3,36, - 0,0,130,144,0,0,0,0,128,0,66,48, - 4,0,64,16,1,0,2,36,0,0,162,172, - 196,89,192,8,33,16,0,0,255,0,99,48, - 31,0,2,36,6,0,98,16,33,16,96,0, - 196,89,192,8,0,0,0,0,1,0,2,36, - 195,89,192,8,0,0,162,172,33,48,0,0, - 0,0,130,144,0,0,0,0,128,0,66,48, - 16,0,64,20,255,0,3,36,8,0,131,140, - 12,0,130,140,0,0,0,0,43,16,98,0, - 5,0,64,16,1,0,98,36,8,0,130,172, - 0,0,99,144,183,89,192,8,0,0,0,0, - 0,0,130,144,0,0,0,0,128,0,66,52, - 0,0,130,160,255,0,3,36,0,0,130,144, - 0,0,0,0,128,0,66,48,228,255,64,20, - 128,0,98,48,4,0,64,16,127,0,98,48, - 37,16,194,0,163,89,192,8,192,49,2,0, - 255,0,98,48,37,48,70,0,255,255,194,48, - 8,0,224,3,0,0,0,0,0,0,130,144, - 0,0,0,0,128,0,66,48,16,0,64,20, - 255,0,6,36,8,0,131,140,12,0,130,140, - 0,0,0,0,43,16,98,0,5,0,64,16, - 1,0,98,36,8,0,130,172,0,0,102,144, - 218,89,192,8,0,0,0,0,0,0,130,144, - 0,0,0,0,128,0,66,52,0,0,130,160, - 255,0,6,36,0,0,130,144,0,0,0,0, - 128,0,66,48,13,0,64,20,1,0,2,36, - 255,0,195,48,128,0,2,36,4,0,98,20, - 2,0,2,36,0,0,162,172,17,90,192,8, - 255,255,2,52,128,0,194,48,6,0,64,20, - 33,24,0,0,17,90,192,8,255,0,194,48, - 0,0,162,172,17,90,192,8,33,16,0,0, - 127,0,194,48,32,0,64,16,255,255,71,36, - 0,26,3,0,0,0,130,144,0,0,0,0, - 128,0,66,48,16,0,64,20,255,255,102,48, - 8,0,131,140,12,0,130,140,0,0,0,0, - 43,16,98,0,6,0,64,16,1,0,98,36, - 8,0,130,172,0,0,98,144,0,0,0,0, - 7,90,192,8,37,24,194,0,0,0,130,144, - 0,0,0,0,128,0,66,52,0,0,130,160, - 255,0,195,52,0,0,130,144,0,0,0,0, - 128,0,66,48,224,255,64,20,1,0,2,36, - 33,16,224,0,255,0,66,48,226,255,64,20, - 255,255,231,36,255,255,98,48,8,0,224,3, - 0,0,0,0,216,255,189,39,36,0,191,175, - 32,0,180,175,28,0,179,175,24,0,178,175, - 20,0,177,175,16,0,176,175,33,152,128,0, - 33,128,192,0,33,144,160,0,255,255,81,50, - 33,0,32,18,33,160,224,0,255,255,2,52, - 30,0,34,18,0,0,0,0,9,50,192,12, - 33,32,32,2,33,24,64,0,29,0,96,16, - 1,0,2,36,0,0,2,166,4,0,3,174, - 8,0,3,174,12,0,18,166,33,32,96,2, - 8,0,5,142,0,0,0,0,218,88,192,12, - 33,48,32,2,33,24,64,0,255,255,100,48, - 10,0,145,20,1,0,2,36,12,0,2,150, - 0,0,0,0,35,16,67,0,12,0,2,166, - 8,0,2,142,0,0,0,0,33,16,130,0, - 68,90,192,8,8,0,2,174,68,90,192,8, - 0,0,130,174,0,0,0,166,4,0,0,174, - 8,0,0,174,12,0,0,166,36,0,191,143, - 32,0,180,143,28,0,179,143,24,0,178,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 40,0,189,39,224,255,189,39,28,0,191,175, - 24,0,178,175,20,0,177,175,16,0,176,175, - 33,144,128,0,33,136,160,0,33,128,192,0, - 124,89,192,12,33,40,0,2,33,32,64,2, - 198,89,192,12,33,40,0,2,33,40,64,0, - 0,0,2,142,0,0,0,0,7,0,64,20, - 33,32,64,2,255,255,165,48,33,48,32,2, - 19,90,192,12,33,56,0,2,104,90,192,8, - 0,0,0,0,0,0,32,166,4,0,32,174, - 8,0,32,174,12,0,32,166,28,0,191,143, - 24,0,178,143,20,0,177,143,16,0,176,143, - 8,0,224,3,32,0,189,39,216,255,189,39, - 36,0,191,175,32,0,180,175,28,0,179,175, - 24,0,178,175,20,0,177,175,16,0,176,175, - 33,152,128,0,33,136,160,0,33,144,192,0, - 56,0,176,147,0,0,0,0,196,88,192,12, - 33,160,224,0,224,0,66,48,7,0,80,20, - 33,32,96,2,124,89,192,12,33,40,64,2, - 255,255,66,48,255,255,131,50,7,0,67,16, - 33,32,96,2,0,0,66,142,0,0,0,0, - 16,0,64,20,4,0,2,36,152,90,192,8, - 0,0,66,174,198,89,192,12,33,40,64,2, - 33,40,64,0,0,0,66,142,0,0,0,0, - 7,0,64,20,33,32,96,2,255,255,165,48, - 33,48,32,2,19,90,192,12,33,56,64,2, - 156,90,192,8,0,0,0,0,0,0,32,166, - 4,0,32,174,8,0,32,174,12,0,32,166, - 36,0,191,143,32,0,180,143,28,0,179,143, - 24,0,178,143,20,0,177,143,16,0,176,143, - 8,0,224,3,40,0,189,39,33,56,0,0, - 255,255,168,36,255,255,165,48,50,0,160,16, - 1,0,9,36,1,0,12,36,4,0,10,36, - 3,0,11,36,255,255,5,52,0,0,130,144, - 0,0,0,0,128,0,66,48,16,0,64,20, - 255,0,3,36,8,0,131,140,12,0,130,140, - 0,0,0,0,43,16,98,0,5,0,64,16, - 1,0,98,36,8,0,130,172,0,0,99,144, - 193,90,192,8,0,0,0,0,0,0,130,144, - 0,0,0,0,128,0,66,52,0,0,130,160, - 255,0,3,36,0,0,130,144,0,0,0,0, - 128,0,66,48,3,0,64,16,0,0,0,0, - 218,90,192,8,0,0,204,172,11,0,32,17, - 255,255,2,49,5,0,74,20,33,72,0,0, - 3,0,96,16,0,0,0,0,218,90,192,8, - 0,0,203,172,128,0,98,48,3,0,64,16, - 0,18,7,0,255,255,7,36,0,18,7,0, - 37,56,67,0,33,16,0,1,255,255,66,48, - 212,255,64,20,33,64,5,1,8,0,224,3, - 33,16,224,0,224,255,189,39,24,0,191,175, - 20,0,177,175,16,0,176,175,33,128,128,0, - 124,89,192,12,33,136,160,0,33,32,0,2, - 198,89,192,12,33,40,32,2,33,32,0,2, - 255,255,69,48,164,90,192,12,33,48,32,2, - 24,0,191,143,20,0,177,143,16,0,176,143, - 8,0,224,3,32,0,189,39,216,255,189,39, - 32,0,191,175,28,0,179,175,24,0,178,175, - 20,0,177,175,16,0,176,175,33,144,128,0, - 33,136,160,0,33,152,192,0,196,88,192,12, - 33,128,224,0,224,0,66,48,255,0,16,50, - 7,0,80,20,33,32,64,2,124,89,192,12, - 33,40,32,2,255,255,66,48,255,255,99,50, - 8,0,67,16,33,32,64,2,0,0,34,142, - 0,0,0,0,2,0,64,20,4,0,2,36, - 0,0,34,174,17,91,192,8,33,16,0,0, - 198,89,192,12,33,40,32,2,33,32,64,2, - 255,255,69,48,164,90,192,12,33,48,32,2, - 32,0,191,143,28,0,179,143,24,0,178,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 40,0,189,39,208,255,189,39,44,0,191,175, - 40,0,180,175,36,0,179,175,32,0,178,175, - 28,0,177,175,24,0,176,175,33,128,128,0, - 33,152,192,0,33,160,224,0,0,0,96,174, - 4,0,96,174,8,0,3,142,4,0,2,142, - 0,0,0,0,35,24,98,0,255,255,165,48, - 35,0,160,24,33,144,0,0,1,0,6,36, - 0,0,2,146,0,0,0,0,128,0,66,48, - 16,0,64,20,255,0,4,36,8,0,4,142, - 12,0,2,142,0,0,0,0,43,16,130,0, - 5,0,64,16,1,0,130,36,8,0,2,174, - 0,0,132,144,64,91,192,8,0,0,0,0, - 0,0,2,146,0,0,0,0,128,0,66,52, - 0,0,2,162,255,0,4,36,0,0,2,146, - 0,0,0,0,128,0,66,48,3,0,64,16, - 128,0,130,48,150,91,192,8,0,0,134,174, - 2,0,64,20,0,0,0,0,1,0,82,38, - 255,255,165,36,224,255,160,28,0,0,0,0, - 33,32,0,2,33,40,96,0,251,88,192,12, - 33,48,0,0,68,0,64,18,1,0,81,38, - 9,50,192,12,128,32,17,0,33,40,64,0, - 63,0,160,16,0,0,0,0,0,0,113,174, - 4,0,101,174,59,0,64,26,33,56,0,0, - 1,0,8,36,33,48,0,0,0,0,2,146, - 0,0,0,0,128,0,66,48,16,0,64,20, - 255,0,4,36,8,0,3,142,12,0,2,142, - 0,0,0,0,43,16,98,0,5,0,64,16, - 1,0,98,36,8,0,2,174,0,0,100,144, - 114,91,192,8,0,0,0,0,0,0,2,146, - 0,0,0,0,128,0,66,52,0,0,2,162, - 255,0,4,36,0,0,2,146,0,0,0,0, - 128,0,66,48,3,0,64,16,192,49,6,0, - 150,91,192,8,0,0,136,174,127,0,130,48, - 37,48,194,0,128,0,130,48,225,255,64,20, - 0,0,0,0,18,0,224,20,40,0,194,44, - 4,0,64,16,80,0,194,44,0,0,160,172, - 145,91,192,8,4,0,165,36,5,0,64,16, - 216,255,194,36,0,0,168,172,4,0,165,36, - 146,91,192,8,0,0,162,172,2,0,2,36, - 0,0,162,172,4,0,165,36,176,255,194,36, - 146,91,192,8,0,0,162,172,0,0,166,172, - 1,0,231,36,42,16,242,0,200,255,64,20, - 4,0,165,36,44,0,191,143,40,0,180,143, - 36,0,179,143,32,0,178,143,28,0,177,143, - 24,0,176,143,8,0,224,3,48,0,189,39, - 224,255,189,39,28,0,191,175,24,0,178,175, - 20,0,177,175,16,0,176,175,33,136,128,0, - 33,144,160,0,33,128,192,0,124,89,192,12, - 33,40,0,2,33,32,32,2,198,89,192,12, - 33,40,0,2,33,40,64,0,0,0,2,142, - 0,0,0,0,5,0,64,20,33,32,32,2, - 255,255,165,48,33,48,64,2,24,91,192,12, - 33,56,0,2,28,0,191,143,24,0,178,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 32,0,189,39,216,255,189,39,36,0,191,175, - 32,0,180,175,28,0,179,175,24,0,178,175, - 20,0,177,175,16,0,176,175,33,144,128,0, - 33,160,160,0,33,136,192,0,56,0,176,147, - 0,0,0,0,196,88,192,12,33,152,224,0, - 224,0,66,48,7,0,80,20,33,32,64,2, - 124,89,192,12,33,40,32,2,255,255,66,48, - 255,255,99,50,7,0,67,16,33,32,64,2, - 0,0,34,142,0,0,0,0,14,0,64,20, - 4,0,2,36,226,91,192,8,0,0,34,174, - 198,89,192,12,33,40,32,2,33,40,64,0, - 0,0,34,142,0,0,0,0,5,0,64,20, - 33,32,64,2,255,255,165,48,33,48,128,2, - 24,91,192,12,33,56,32,2,36,0,191,143, - 32,0,180,143,28,0,179,143,24,0,178,143, - 20,0,177,143,16,0,176,143,8,0,224,3, - 40,0,189,39,0,0,0,0,0,0,0,0, - 216,255,189,39,32,0,191,175,28,0,179,175, - 24,0,178,175,20,0,177,175,16,0,176,175, - 33,152,128,0,8,0,99,142,4,0,98,142, - 0,0,0,0,35,128,98,0,255,255,4,50, - 19,0,128,16,33,136,160,0,9,50,192,12, - 0,0,0,0,33,144,64,0,3,0,64,22, - 255,255,16,50,17,92,192,8,255,255,2,36, - 33,32,64,2,4,0,101,142,0,0,0,0, - 80,68,192,12,33,48,0,2,1,0,2,36, - 0,0,34,166,4,0,50,174,33,128,80,2, - 15,92,192,8,8,0,48,174,0,0,32,166, - 4,0,32,174,8,0,32,174,12,0,32,166, - 33,16,0,0,32,0,191,143,28,0,179,143, - 24,0,178,143,20,0,177,143,16,0,176,143, - 8,0,224,3,40,0,189,39,232,255,189,39, - 20,0,191,175,16,0,176,175,33,128,128,0, - 0,0,2,150,0,0,0,0,1,0,66,48, - 7,0,64,16,0,0,0,0,4,0,4,142, - 0,0,0,0,3,0,128,16,0,0,0,0, - 61,50,192,12,0,0,0,0,0,0,0,166, - 8,0,0,174,4,0,0,174,12,0,0,166, - 20,0,191,143,16,0,176,143,8,0,224,3, - 24,0,189,39,224,255,189,39,24,0,191,175, - 20,0,177,175,16,0,176,175,33,128,128,0, - 8,0,163,140,4,0,162,140,0,0,0,0, - 35,136,98,0,255,255,35,50,12,0,2,150, - 0,0,0,0,43,16,67,0,4,0,64,16, - 255,255,38,50,12,0,17,150,0,0,0,0, - 255,255,38,50,6,0,192,16,255,255,34,50, - 8,0,4,142,4,0,165,140,80,68,192,12, - 0,0,0,0,255,255,34,50,8,0,3,142, - 0,0,0,0,33,16,67,0,8,0,2,174, - 12,0,2,150,0,0,0,0,35,16,81,0, - 12,0,2,166,24,0,191,143,20,0,177,143, - 16,0,176,143,8,0,224,3,32,0,189,39, - 1,0,2,36,23,0,194,16,2,0,194,40, - 5,0,64,16,2,0,2,36,7,0,192,16, - 255,255,2,36,132,92,192,8,0,0,0,0, - 23,0,194,16,255,255,2,36,132,92,192,8, - 0,0,0,0,255,255,162,48,4,0,131,140, - 0,0,0,0,33,48,67,0,8,0,130,140, - 0,0,0,0,35,16,67,0,12,0,131,148, - 0,0,0,0,33,16,67,0,124,92,192,8, - 35,40,69,0,255,255,162,48,8,0,131,140, - 0,0,0,0,33,48,67,0,12,0,130,148, - 0,0,0,0,124,92,192,8,35,40,69,0, - 12,0,130,148,8,0,131,140,0,0,0,0, - 33,48,67,0,255,255,162,48,35,48,194,0, - 4,0,130,140,0,0,0,0,43,16,194,0, - 4,0,64,20,255,255,2,36,8,0,134,172, - 12,0,133,164,33,16,0,0,8,0,224,3, - 0,0,0,0,216,255,189,39,32,0,191,175, - 28,0,179,175,24,0,178,175,20,0,177,175, - 16,0,176,175,33,128,128,0,33,152,160,0, - 8,0,3,142,4,0,2,142,0,0,0,0, - 35,144,98,0,255,255,66,50,12,0,3,150, - 0,0,0,0,33,16,67,0,255,255,99,50, - 42,16,67,0,35,0,64,16,1,0,2,36, - 0,0,3,150,0,0,0,0,32,0,98,20, - 255,255,2,36,9,50,192,12,255,255,100,50, - 33,136,64,0,3,0,32,22,255,255,70,50, - 189,92,192,8,255,255,2,36,5,0,192,16, - 0,0,0,0,4,0,5,142,0,0,0,0, - 80,68,192,12,33,32,32,2,0,0,2,150, - 0,0,0,0,1,0,66,48,7,0,64,16, - 0,0,0,0,4,0,4,142,0,0,0,0, - 3,0,128,16,0,0,0,0,61,50,192,12, - 0,0,0,0,4,0,17,174,255,255,66,50, - 33,16,34,2,8,0,2,174,35,16,114,2, - 12,0,2,166,33,16,0,0,32,0,191,143, - 28,0,179,143,24,0,178,143,20,0,177,143, - 16,0,176,143,8,0,224,3,40,0,189,39, - 216,255,189,39,32,0,191,175,28,0,179,175, - 24,0,178,175,20,0,177,175,16,0,176,175, - 33,128,128,0,33,136,192,0,255,255,36,50, - 35,0,128,16,33,152,160,0,8,0,2,142, - 4,0,3,142,0,0,0,0,35,16,67,0, - 255,255,66,48,12,0,3,150,0,0,0,0, - 33,16,67,0,42,16,68,0,20,0,64,16, - 0,0,0,0,9,50,192,12,0,0,0,0, - 33,144,64,0,24,0,64,18,255,255,2,36, - 0,0,2,150,0,0,0,0,1,0,66,48, - 8,0,64,16,1,0,2,36,4,0,4,142, - 0,0,0,0,4,0,128,16,0,0,0,0, - 61,50,192,12,0,0,0,0,1,0,2,36, - 0,0,2,166,4,0,18,174,4,0,4,142, - 33,40,96,2,80,68,192,12,255,255,38,50, - 33,32,0,2,255,255,37,50,85,92,192,12, - 33,48,0,0,33,16,0,0,32,0,191,143, - 28,0,179,143,24,0,178,143,20,0,177,143, - 16,0,176,143,8,0,224,3,40,0,189,39, - 0,0,0,0,0,0,0,0,0,0,0,0, - 184,255,189,39,64,0,191,175,60,0,183,175, - 56,0,182,175,52,0,181,175,48,0,180,175, - 44,0,179,175,40,0,178,175,36,0,177,175, - 32,0,176,175,33,144,128,0,112,0,84,142, - 0,0,0,0,92,0,128,18,1,0,2,36, - 108,0,81,142,0,0,0,0,88,0,32,18, - 0,0,0,0,96,0,87,38,136,0,66,174, - 140,0,64,174,96,0,64,174,100,0,64,174, - 224,83,192,12,33,32,32,2,33,168,64,0, - 25,0,160,18,33,128,160,2,108,0,66,142, - 0,0,0,0,124,0,66,174,128,0,84,174, - 108,0,81,174,112,0,85,174,29,0,32,26, - 33,152,0,0,255,255,22,36,33,32,0,2, - 8,0,133,38,33,48,64,2,170,72,192,12, - 1,0,7,36,10,0,86,16,33,32,64,2, - 14,0,64,20,0,0,0,0,64,0,66,142, - 0,0,0,0,10,0,64,20,2,0,5,36, - 56,93,192,8,1,0,102,38,33,32,64,2, - 5,0,5,36,33,48,0,0,140,84,192,12, - 0,0,0,0,107,93,192,8,1,0,2,36, - 1,0,115,38,68,0,16,38,42,16,113,2, - 230,255,64,20,68,0,148,38,40,0,32,18, - 33,128,160,2,17,0,2,146,0,0,0,0, - 34,0,66,48,32,0,64,20,0,0,0,0, - 36,0,2,142,16,0,176,175,16,0,66,140, - 24,0,4,142,28,0,5,142,32,0,6,142, - 0,0,0,0,9,248,64,0,33,56,64,2, - 17,0,2,146,0,0,0,0,32,0,66,52, - 17,0,2,162,0,0,226,142,0,0,0,0, - 15,0,64,16,0,0,0,0,255,255,49,38, - 15,0,32,18,68,0,16,38,17,0,3,146, - 0,0,0,0,32,0,98,48,2,0,64,20, - 34,0,98,52,17,0,2,162,255,255,49,38, - 248,255,32,22,68,0,16,38,107,93,192,8, - 33,16,0,0,255,255,49,38,218,255,32,22, - 68,0,16,38,33,16,0,0,64,0,191,143, - 60,0,183,143,56,0,182,143,52,0,181,143, - 48,0,180,143,44,0,179,143,40,0,178,143, - 36,0,177,143,32,0,176,143,8,0,224,3, - 72,0,189,39,168,255,189,39,80,0,191,175, - 76,0,183,175,72,0,182,175,68,0,181,175, - 64,0,180,175,60,0,179,175,56,0,178,175, - 52,0,177,175,48,0,176,175,33,144,128,0, - 96,0,66,142,0,0,0,0,3,0,64,16, - 33,32,0,0,240,93,192,8,255,255,2,36, - 116,0,66,142,0,0,0,0,7,0,64,16, - 104,0,67,38,12,0,99,140,0,0,0,0, - 12,0,98,140,0,0,0,0,251,255,64,20, - 0,0,0,0,8,0,116,140,0,0,0,0, - 92,0,128,18,33,16,0,0,4,0,115,140, - 0,0,0,0,88,0,96,18,0,0,0,0, - 64,0,66,142,0,0,0,0,55,0,64,20, - 0,0,0,0,33,128,128,2,52,0,96,26, - 33,136,0,0,255,255,23,36,2,0,22,36, - 5,0,21,36,17,0,2,146,0,0,0,0, - 16,0,66,48,40,0,64,16,24,0,165,39, - 8,0,3,142,28,0,2,142,0,0,0,0, - 35,24,98,0,24,0,163,175,12,0,2,142, - 0,0,0,0,28,0,162,175,128,24,3,0, - 33,24,98,0,252,255,98,140,0,0,0,0, - 1,0,66,36,252,255,98,172,12,0,0,174, - 8,0,0,174,33,32,0,2,33,48,64,2, - 170,72,192,12,1,0,7,36,6,0,87,16, - 0,0,0,0,9,0,64,20,1,0,34,38, - 96,0,86,174,196,93,192,8,100,0,66,174, - 96,0,85,174,110,86,192,12,24,0,164,39, - 240,93,192,8,255,255,2,36,110,86,192,12, - 24,0,164,39,17,0,2,146,0,0,0,0, - 12,0,66,48,17,0,2,162,1,0,4,36, - 1,0,49,38,42,16,51,2,209,255,64,20, - 68,0,16,38,27,0,128,16,33,128,128,2, - 23,0,96,26,33,136,0,0,17,0,2,146, - 0,0,0,0,34,0,66,48,14,0,64,20, - 0,0,0,0,36,0,2,142,16,0,176,175, - 16,0,66,140,24,0,4,142,28,0,5,142, - 32,0,6,142,0,0,0,0,9,248,64,0, - 33,56,64,2,17,0,2,146,0,0,0,0, - 32,0,66,52,17,0,2,162,1,0,49,38, - 42,16,51,2,235,255,64,20,68,0,16,38, - 240,93,192,8,1,0,2,36,33,16,0,0, - 80,0,191,143,76,0,183,143,72,0,182,143, - 68,0,181,143,64,0,180,143,60,0,179,143, - 56,0,178,143,52,0,177,143,48,0,176,143, - 8,0,224,3,88,0,189,39,0,0,0,0, - 200,255,189,39,48,0,191,175,44,0,179,175, - 40,0,178,175,36,0,177,175,32,0,176,175, - 33,144,128,0,96,0,64,174,100,0,64,174, - 112,0,80,142,0,0,0,0,105,0,0,18, - 33,16,0,0,108,0,81,142,0,0,0,0, - 101,0,32,18,0,0,0,0,64,0,66,142, - 0,0,0,0,43,0,64,20,33,32,64,2, - 50,0,32,26,33,152,0,0,33,32,0,2, - 33,40,64,2,96,72,192,12,1,0,6,36, - 13,0,64,20,33,32,64,2,20,0,2,150, - 0,0,0,0,1,0,66,48,34,0,64,16, - 2,0,5,36,36,0,2,142,0,0,0,0, - 3,0,66,144,0,0,0,0,2,0,66,48, - 3,0,64,20,0,0,0,0,63,94,192,8, - 2,0,5,36,36,0,2,142,0,0,0,0, - 32,0,66,140,4,0,67,142,0,0,0,0, - 36,16,67,0,16,0,64,16,33,32,64,2, - 36,0,2,142,16,0,3,146,2,0,66,144, - 0,0,0,0,11,0,98,20,3,0,5,36, - 1,0,115,38,42,16,113,2,219,255,64,20, - 68,0,16,38,69,94,192,8,96,0,83,38, - 5,0,5,36,64,94,192,8,33,48,0,0, - 2,0,5,36,1,0,102,38,140,84,192,12, - 0,0,0,0,113,94,192,8,1,0,2,36, - 96,0,83,38,112,0,80,142,0,0,0,0, - 41,0,32,18,33,16,0,0,17,0,2,146, - 0,0,0,0,17,0,66,48,32,0,64,20, - 0,0,0,0,36,0,2,142,16,0,176,175, - 4,0,66,140,24,0,4,142,28,0,5,142, - 32,0,6,142,0,0,0,0,9,248,64,0, - 33,56,64,2,17,0,2,146,0,0,0,0, - 16,0,66,52,17,0,2,162,0,0,98,142, - 0,0,0,0,15,0,64,16,0,0,0,0, - 255,255,49,38,15,0,32,18,68,0,16,38, - 17,0,3,146,0,0,0,0,16,0,98,48, - 2,0,64,20,17,0,98,52,17,0,2,162, - 255,255,49,38,248,255,32,22,68,0,16,38, - 113,94,192,8,33,16,0,0,255,255,49,38, - 218,255,32,22,68,0,16,38,33,16,0,0, - 48,0,191,143,44,0,179,143,40,0,178,143, - 36,0,177,143,32,0,176,143,8,0,224,3, - 56,0,189,39,192,255,189,39,56,0,191,175, - 52,0,183,175,48,0,182,175,44,0,181,175, - 40,0,180,175,36,0,179,175,32,0,178,175, - 28,0,177,175,24,0,176,175,33,144,128,0, - 112,0,84,142,0,0,0,0,171,0,128,18, - 33,16,0,0,108,0,85,142,0,0,0,0, - 166,0,160,18,32,0,2,36,56,0,67,146, - 0,0,0,0,75,0,98,16,96,0,83,38, - 33,0,98,40,5,0,64,16,64,0,2,36, - 9,0,96,16,33,16,0,0,49,95,192,8, - 0,0,0,0,85,0,98,16,128,0,2,36, - 137,0,98,16,33,16,0,0,49,95,192,8, - 0,0,0,0,33,136,160,2,8,0,32,18, - 33,128,128,2,17,0,2,146,0,0,0,0, - 1,0,66,48,139,0,64,16,255,255,49,38, - 250,255,32,22,68,0,16,38,0,0,98,142, - 0,0,0,0,136,0,64,20,33,16,0,0, - 33,136,160,2,43,0,32,18,33,128,128,2, - 14,0,22,36,64,0,23,36,17,0,2,146, - 0,0,0,0,34,0,66,48,33,0,64,20, - 0,0,0,0,36,0,2,142,16,0,176,175, - 12,0,66,140,24,0,4,142,28,0,5,142, - 32,0,6,142,0,0,0,0,9,248,64,0, - 33,56,64,2,17,0,2,146,0,0,0,0, - 32,0,66,52,17,0,2,162,0,0,98,142, - 0,0,0,0,16,0,64,16,0,0,0,0, - 255,255,49,38,10,0,32,18,68,0,16,38, - 17,0,3,146,0,0,0,0,32,0,98,48, - 2,0,64,20,192,0,98,52,17,0,2,162, - 255,255,49,38,248,255,32,22,68,0,16,38, - 0,0,118,174,236,94,192,8,56,0,87,162, - 255,255,49,38,217,255,32,22,68,0,16,38, - 32,0,2,36,56,0,66,162,0,0,98,142, - 0,0,0,0,13,0,64,20,64,0,2,36, - 33,136,160,2,81,0,32,18,33,128,128,2, - 17,0,2,146,0,0,0,0,2,0,66,48, - 74,0,64,16,255,255,49,38,250,255,32,22, - 68,0,16,38,49,95,192,8,33,16,0,0, - 56,0,66,162,14,0,2,36,0,0,98,174, - 33,136,160,2,53,0,32,18,33,128,128,2, - 2,0,23,36,15,0,22,36,17,0,2,146, - 0,0,0,0,194,0,66,48,5,0,64,16, - 0,0,0,0,19,0,87,16,0,0,0,0, - 32,95,192,8,255,255,49,38,64,0,2,142, - 0,0,0,0,34,0,64,16,0,0,0,0, - 16,0,176,175,64,0,2,142,24,0,4,142, - 28,0,5,142,32,0,6,142,0,0,0,0, - 9,248,64,0,33,56,64,2,17,0,2,146, - 0,0,0,0,30,95,192,8,64,0,66,52, - 64,0,2,142,0,0,0,0,13,0,64,16, - 0,0,0,0,16,0,176,175,64,0,2,142, - 24,0,4,142,28,0,5,142,32,0,6,142, - 0,0,0,0,9,248,64,0,33,56,64,2, - 17,0,2,146,0,0,0,0,30,95,192,8, - 64,0,66,52,0,0,118,174,17,0,2,146, - 0,0,0,0,128,0,66,52,17,0,2,162, - 255,255,49,38,208,255,32,22,68,0,16,38, - 33,136,160,2,12,0,32,18,33,128,128,2, - 17,0,2,146,0,0,0,0,128,0,66,48, - 5,0,64,16,255,255,49,38,250,255,32,22, - 68,0,16,38,49,95,192,8,33,16,0,0, - 49,95,192,8,1,0,2,36,33,16,0,0, - 56,0,191,143,52,0,183,143,48,0,182,143, - 44,0,181,143,40,0,180,143,36,0,179,143, - 32,0,178,143,28,0,177,143,24,0,176,143, - 8,0,224,3,64,0,189,39,184,255,189,39, - 64,0,191,175,60,0,183,175,56,0,182,175, - 52,0,181,175,48,0,180,175,44,0,179,175, - 40,0,178,175,36,0,177,175,32,0,176,175, - 33,160,128,0,112,0,147,142,0,0,0,0, - 129,0,96,18,33,16,0,0,108,0,146,142, - 0,0,0,0,125,0,64,18,96,0,151,38, - 96,0,128,174,100,0,128,174,224,83,192,12, - 33,32,64,2,33,168,64,0,5,0,160,22, - 33,136,64,2,33,32,128,2,5,0,5,36, - 123,95,192,8,33,48,0,0,36,0,64,18, - 33,128,160,2,5,0,22,36,16,0,22,162, - 8,0,100,142,12,0,101,142,0,0,0,0, - 80,86,192,12,8,0,6,38,5,0,64,20, - 0,0,0,0,255,255,49,38,68,0,115,38, - 245,255,32,22,68,0,16,38,21,0,32,18, - 42,16,50,2,7,0,64,16,33,128,160,2, - 59,84,192,12,33,32,0,2,1,0,49,38, - 42,16,50,2,251,255,64,20,68,0,16,38, - 61,50,192,12,33,32,160,2,33,32,128,2, - 5,0,5,36,123,95,192,8,33,48,0,0, - 2,0,5,36,1,0,38,38,140,84,192,12, - 0,0,0,0,203,95,192,8,1,0,2,36, - 124,0,146,174,112,0,130,142,0,0,0,0, - 128,0,130,174,112,0,149,174,33,128,160,2, - 27,0,64,26,33,136,0,0,33,32,0,2, - 33,40,128,2,96,72,192,12,1,0,6,36, - 13,0,64,20,0,0,0,0,20,0,2,150, - 0,0,0,0,1,0,66,48,8,0,64,16, - 0,0,0,0,36,0,2,142,0,0,0,0, - 3,0,66,144,0,0,0,0,1,0,66,48, - 5,0,64,20,0,0,0,0,64,0,130,142, - 0,0,0,0,221,255,64,16,33,32,128,2, - 1,0,49,38,42,16,50,2,231,255,64,20, - 68,0,16,38,40,0,64,18,33,128,160,2, - 17,0,2,146,0,0,0,0,34,0,66,48, - 32,0,64,20,0,0,0,0,36,0,2,142, - 16,0,176,175,8,0,66,140,24,0,4,142, - 28,0,5,142,32,0,6,142,0,0,0,0, - 9,248,64,0,33,56,128,2,17,0,2,146, - 0,0,0,0,32,0,66,52,17,0,2,162, - 0,0,226,142,0,0,0,0,15,0,64,16, - 0,0,0,0,255,255,82,38,15,0,64,18, - 68,0,16,38,17,0,3,146,0,0,0,0, - 32,0,98,48,2,0,64,20,34,0,98,52, - 17,0,2,162,255,255,82,38,248,255,64,22, - 68,0,16,38,203,95,192,8,33,16,0,0, - 255,255,82,38,218,255,64,22,68,0,16,38, - 33,16,0,0,64,0,191,143,60,0,183,143, - 56,0,182,143,52,0,181,143,48,0,180,143, - 44,0,179,143,40,0,178,143,36,0,177,143, - 32,0,176,143,8,0,224,3,72,0,189,39, - 0,0,0,0,0,0,0,0,37,115,58,37, - 100,58,32,102,97,105,108,101,100,32,97,115, - 115,101,114,116,105,111,110,32,96,37,115,39, - 10,0,0,0,114,97,109,116,101,115,116,100, - 119,40,98,99,46,98,99,95,104,101,97,112, - 115,116,97,114,116,44,32,108,101,110,44,32, - 49,44,32,48,44,32,48,41,32,61,61,32, - 48,0,0,0,98,99,46,98,99,95,104,101, - 97,112,101,110,100,32,60,61,32,98,99,46, - 98,99,95,114,97,109,101,110,100,0,0,0, - 35,32,112,111,114,116,115,58,32,37,100,10, - 0,0,0,0,42,42,42,80,114,111,102,105, - 108,105,110,103,32,64,32,37,120,44,32,37, - 120,10,0,0,103,111,116,32,104,101,114,101, - 32,99,97,117,115,101,61,37,120,32,115,116, - 97,116,117,115,61,37,120,32,118,101,99,61, - 37,120,10,0,37,115,58,37,100,58,32,102, - 97,105,108,101,100,32,97,115,115,101,114,116, - 105,111,110,32,96,37,115,39,10,0,0,0, - 83,101,99,111,110,100,115,32,60,32,48,120, - 55,70,70,70,102,102,102,102,0,0,0,0, - 84,105,109,101,114,115,85,115,101,100,32,60, - 32,78,84,73,77,69,82,83,0,0,0,0, - 0,0,0,0,69,69,80,82,79,77,32,105, - 115,32,98,97,100,10,0,0,80,111,114,116, - 32,37,100,32,101,116,104,101,114,32,97,100, - 100,114,101,115,115,58,32,37,48,50,88,58, - 37,48,50,88,58,37,48,50,88,58,37,48, - 50,88,58,37,48,50,88,58,37,48,50,88, - 10,0,0,0,35,35,35,32,56,50,53,57, - 54,32,67,104,97,110,32,37,100,58,32,115, - 101,108,102,116,101,115,116,32,102,97,105,108, - 101,100,32,40,37,120,41,10,0,0,0,0, - 42,42,42,32,56,50,53,57,54,32,80,111, - 114,116,32,37,100,58,32,115,101,108,102,116, - 101,115,116,32,112,97,115,115,101,100,10,0, - 56,50,53,57,54,32,80,111,114,116,32,37, - 100,58,32,100,117,109,112,32,102,97,105,108, - 101,100,32,40,37,120,41,10,0,0,0,0, - 42,42,42,32,56,50,53,57,54,32,80,111, - 114,116,32,37,100,58,32,100,117,109,112,32, - 112,97,115,115,101,100,10,0,35,35,35,32, - 56,50,53,57,54,32,80,111,114,116,32,37, - 100,58,32,83,67,80,32,102,101,116,99,104, - 32,102,97,105,108,101,100,10,0,0,0,0, - 42,42,42,32,56,50,53,57,54,32,80,111, - 114,116,32,37,100,58,32,83,67,80,32,102, - 101,116,99,104,32,112,97,115,115,101,100,32, - 37,120,32,10,0,0,0,0,35,35,35,32, - 56,50,53,57,54,32,80,111,114,116,32,37, - 100,58,32,66,85,83,84,73,77,69,82,83, - 32,108,111,97,100,32,102,97,105,108,101,100, - 10,0,0,0,42,42,42,32,56,50,53,57, - 54,32,80,111,114,116,32,37,100,58,32,66, - 85,83,84,73,77,69,82,83,32,108,111,97, - 100,32,112,97,115,115,101,100,10,0,0,0, - 35,35,35,32,65,67,75,32,100,105,100,32, - 110,111,116,32,111,99,99,117,114,10,0,0, - 35,35,35,32,115,116,97,116,117,115,32,115, - 116,105,108,108,32,98,117,115,121,58,32,37, - 120,10,0,0,101,116,104,95,105,110,105,116, - 46,99,0,0,42,42,42,76,49,87,65,10, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,35,35,35,32,84,66,68,32, - 98,108,111,99,107,115,32,97,114,101,110,39, - 116,32,98,101,105,110,103,32,102,114,101,101, - 100,10,0,0,65,116,116,101,109,112,116,32, - 116,111,32,102,114,101,101,32,98,111,103,117, - 115,32,84,66,68,32,37,120,10,0,0,0, - 35,35,35,32,66,85,70,32,98,108,111,99, - 107,115,32,97,114,101,110,39,116,32,98,101, - 105,110,103,32,102,114,101,101,100,10,0,0, - 65,116,116,101,109,112,116,32,116,111,32,102, - 114,101,101,32,98,111,103,117,115,32,66,85, - 70,32,37,120,10,0,0,0,0,0,0,0, - 0,0,0,0,82,70,68,115,32,37,100,32, - 10,0,0,0,82,66,68,115,32,37,100,32, - 10,0,0,0,37,115,58,37,100,58,32,102, - 97,105,108,101,100,32,97,115,115,101,114,116, - 105,111,110,32,96,37,115,39,10,0,0,0, - 101,116,104,95,114,99,118,46,99,0,0,0, - 100,115,116,99,104,97,110,32,62,61,32,49, - 32,38,38,32,100,115,116,99,104,97,110,32, - 60,32,78,99,104,97,110,0,37,115,37,48, - 50,88,58,37,48,50,88,58,37,48,50,88, - 58,37,48,50,88,58,37,48,50,88,58,37, - 48,50,88,37,115,0,0,0,176,72,0,131, - 80,67,0,131,164,67,0,131,24,68,0,131, - 80,67,0,131,0,0,0,0,4,82,0,131, - 184,76,0,131,12,77,0,131,128,77,0,131, - 184,76,0,131,0,0,0,0,0,0,0,0, - 0,0,0,0,37,115,58,37,100,58,32,102, - 97,105,108,101,100,32,97,115,115,101,114,116, - 105,111,110,32,96,37,115,39,10,0,0,0, - 101,116,104,95,120,109,105,116,46,99,0,0, - 99,98,112,45,62,110,111,112,46,99,109,100, - 32,61,61,32,73,53,57,54,95,67,66,95, - 67,77,68,95,78,79,80,124,73,53,57,54, - 95,67,66,95,67,77,68,95,69,76,0,0, - 99,98,112,45,62,110,111,112,46,99,109,100, - 32,38,32,73,53,57,54,95,67,66,95,67, - 77,68,0,0,112,45,62,115,99,98,112,45, - 62,115,116,97,116,117,115,32,38,32,73,53, - 57,54,95,83,67,66,95,67,78,65,0,0, - 35,35,35,32,99,109,100,32,115,116,105,108, - 108,32,98,117,115,121,58,32,37,120,10,0, - 37,100,61,37,100,44,37,120,44,37,100,10, - 0,0,0,0,39,37,115,39,32,37,120,32, - 37,120,10,0,37,48,56,120,58,32,37,48, - 50,120,10,0,37,48,56,120,58,32,37,48, - 52,120,10,0,37,48,56,120,58,32,37,48, - 56,120,10,0,108,105,110,107,32,115,116,97, - 116,101,32,37,48,50,120,10,0,0,0,0, - 42,42,42,32,103,111,116,32,37,100,32,105, - 110,116,101,114,114,117,112,116,115,10,0,0, - 35,35,35,32,69,120,112,101,99,116,101,100, - 32,37,100,32,98,117,116,32,103,111,116,32, - 37,100,32,105,110,116,101,114,114,117,112,116, - 115,10,0,0,80,76,88,57,48,54,48,32, - 65,100,100,114,101,115,115,32,61,32,37,88, - 32,68,65,84,65,32,61,32,37,88,32,10, - 0,0,0,0,42,42,42,32,87,114,105,116, - 101,32,111,102,32,37,120,32,116,111,32,37, - 100,32,102,97,105,108,101,100,10,0,0,0, - 42,42,42,32,87,114,105,116,101,32,111,102, - 32,37,120,32,116,111,32,37,120,32,102,97, - 105,108,101,100,10,0,0,0,42,42,42,42, - 42,42,42,42,42,42,42,42,42,42,42,42, - 0,0,0,0,42,42,42,32,73,108,108,101, - 103,97,108,32,99,111,109,109,97,110,100,32, - 39,37,115,39,10,0,0,0,45,45,45,32, - 99,111,109,109,97,110,100,115,32,109,44,116, - 44,101,44,69,44,97,44,120,44,108,44,115, - 44,112,32,99,97,110,32,98,101,32,112,114, - 101,102,105,120,101,100,32,119,105,116,104,32, - 97,32,114,101,112,101,97,116,32,99,111,117, - 110,116,0,0,108,32,120,112,111,114,116,32, - 114,112,111,114,116,32,91,108,101,110,93,32, - 32,32,32,32,32,32,32,32,32,76,111,111, - 112,98,97,99,107,32,116,101,115,116,32,102, - 114,111,109,32,120,112,111,114,116,32,40,49, - 45,54,41,32,116,111,32,114,112,111,114,116, - 32,40,49,45,54,41,0,0,105,32,32,32, - 32,32,32,32,32,32,73,110,116,101,114,114, - 117,112,116,32,72,111,115,116,32,32,124,32, - 32,115,32,91,112,111,114,116,93,32,91,108, - 101,110,93,32,66,97,99,107,50,98,97,99, - 107,32,120,109,105,116,32,99,110,116,32,112, - 97,99,107,101,116,115,0,0,80,32,32,32, - 32,32,32,32,32,32,84,101,115,116,32,80, - 76,88,32,57,48,54,48,32,32,32,124,32, - 32,100,32,91,114,124,119,124,108,124,116,93, - 32,91,118,97,108,124,39,99,39,93,32,32, - 82,101,97,100,47,87,114,105,116,101,47,76, - 111,111,112,47,84,105,109,101,32,68,77,65, - 0,0,0,0,76,32,32,32,32,32,32,32, - 32,32,82,101,97,100,32,76,105,110,107,32, - 76,69,68,115,32,32,124,32,32,112,32,114, - 101,103,110,111,32,91,118,97,108,93,32,32, - 82,101,97,100,47,91,119,114,105,116,101,93, - 32,80,76,88,32,114,101,103,105,115,116,101, - 114,0,0,0,65,32,97,100,100,114,32,32, - 32,32,83,101,116,32,101,116,104,101,114,32, - 97,100,100,114,32,32,124,32,32,36,32,115, - 99,114,105,112,116,32,32,32,32,32,32,32, - 82,101,97,100,32,99,109,100,115,32,102,114, - 111,109,32,102,105,108,101,32,39,115,99,114, - 105,112,116,39,0,0,0,0,120,32,91,112, - 111,114,116,93,32,32,84,120,32,101,116,104, - 101,114,32,32,32,32,32,32,32,32,124,32, - 32,82,32,91,112,111,114,116,93,32,32,32, - 32,32,32,32,82,120,32,101,116,104,101,114, - 32,91,111,110,32,112,111,114,116,32,49,45, - 54,93,0,0,72,32,32,32,32,32,32,32, - 32,32,84,111,103,103,108,101,32,70,67,67, - 32,116,101,115,116,32,124,32,32,113,44,94, - 68,44,94,90,32,32,32,32,32,32,32,32, - 81,117,105,116,0,0,0,0,97,32,32,32, - 32,32,32,32,32,32,84,101,115,116,32,97, - 108,108,32,32,32,32,32,32,32,32,124,32, - 32,90,32,109,115,101,99,115,32,32,32,32, - 32,32,32,32,80,97,117,115,101,32,102,111, - 114,32,97,32,119,104,105,108,101,0,0,0, - 69,32,32,32,32,32,32,32,32,32,84,101, - 115,116,32,69,69,80,82,79,77,32,32,32, - 32,32,124,32,32,83,114,32,97,100,100,114, - 59,32,83,119,32,97,100,100,114,32,118,97, - 108,59,32,32,82,101,97,100,47,87,114,105, - 116,101,32,80,76,88,32,69,50,32,114,101, - 103,0,0,0,101,32,91,112,111,114,116,93, - 32,32,84,101,115,116,32,101,116,104,101,114, - 110,101,116,32,32,32,124,32,32,69,114,32, - 97,100,100,114,59,32,69,119,32,97,100,100, - 114,32,118,97,108,59,32,32,82,101,97,100, - 47,87,114,105,116,101,32,69,69,80,82,79, - 77,32,114,101,103,0,0,0,116,32,32,32, - 32,32,32,32,32,32,84,101,115,116,32,116, - 105,109,101,114,115,32,32,32,32,32,124,32, - 32,119,91,42,93,32,97,100,100,114,32,118, - 97,108,32,32,87,114,105,116,101,32,109,101, - 109,111,114,121,58,32,119,98,32,119,104,44, - 32,119,119,44,32,119,116,0,109,32,32,32, - 32,32,32,32,32,32,84,101,115,116,32,109, - 101,109,111,114,121,32,32,32,32,32,124,32, - 32,114,91,42,93,32,97,100,100,114,32,32, - 32,32,32,32,82,101,97,100,32,109,101,109, - 111,114,121,58,32,114,98,32,114,104,44,32, - 114,119,44,32,114,116,0,0,42,42,42,32, - 82,105,103,104,116,83,119,105,116,99,104,32, - 68,105,97,103,110,111,115,116,105,99,115,32, - 109,101,110,117,32,42,42,42,0,0,0,0, - 45,45,45,32,84,104,114,101,101,32,99,111, - 112,105,101,115,32,111,102,32,97,100,100,114, - 101,115,115,32,100,111,32,110,111,116,32,97, - 103,114,101,101,33,10,0,0,45,45,45,32, - 69,116,104,101,114,32,65,100,100,114,101,115, - 115,32,78,111,116,32,83,101,116,33,10,0, - 45,45,45,32,69,116,104,101,114,32,65,100, - 100,114,101,115,115,32,105,115,32,97,32,109, - 117,108,116,105,99,97,115,116,32,97,100,100, - 114,101,115,115,33,10,0,0,42,42,42,32, - 37,48,50,88,37,48,50,88,37,48,50,88, - 58,37,48,50,88,58,37,48,50,88,37,48, - 50,88,10,0,45,45,45,32,70,105,114,115, - 116,32,98,121,116,101,32,40,37,48,50,88, - 41,32,105,115,32,97,32,98,114,111,97,100, - 99,97,115,116,32,97,100,100,114,101,115,115, - 10,0,0,0,45,45,45,32,76,97,115,116, - 32,100,105,103,105,116,32,109,117,115,116,32, - 98,101,32,48,32,111,114,32,56,10,0,0, - 42,42,42,32,69,105,103,104,116,32,101,116, - 104,101,114,110,101,116,32,97,100,100,114,101, - 115,115,101,115,32,104,97,118,101,32,98,101, - 101,110,32,117,115,101,100,58,10,0,0,0, - 42,42,42,32,80,111,114,116,32,37,100,32, - 101,116,104,101,114,110,101,116,32,97,100,100, - 114,101,115,115,32,105,115,32,0,0,0,0, - 45,45,45,32,66,97,100,32,101,116,104,101, - 114,32,97,100,100,114,101,115,115,32,39,37, - 115,39,32,115,112,101,99,105,102,105,101,100, - 10,0,0,0,0,0,0,0,244,101,0,131, - 104,112,0,131,104,112,0,131,104,112,0,131, - 104,112,0,131,104,112,0,131,104,112,0,131, - 104,112,0,131,104,112,0,131,104,112,0,131, - 104,112,0,131,104,112,0,131,104,112,0,131, - 104,112,0,131,104,112,0,131,104,112,0,131, - 104,112,0,131,104,112,0,131,104,112,0,131, - 104,112,0,131,104,112,0,131,104,112,0,131, - 104,112,0,131,104,112,0,131,104,112,0,131, - 104,112,0,131,104,112,0,131,104,112,0,131, - 104,112,0,131,104,112,0,131,104,112,0,131, - 104,112,0,131,104,112,0,131,104,112,0,131, - 104,112,0,131,244,101,0,131,104,112,0,131, - 104,112,0,131,104,112,0,131,104,112,0,131, - 104,112,0,131,104,112,0,131,64,112,0,131, - 104,112,0,131,104,112,0,131,104,112,0,131, - 104,112,0,131,104,112,0,131,104,112,0,131, - 104,112,0,131,104,112,0,131,104,112,0,131, - 104,112,0,131,104,112,0,131,104,112,0,131, - 104,112,0,131,104,112,0,131,104,112,0,131, - 104,112,0,131,104,112,0,131,104,112,0,131, - 104,112,0,131,104,112,0,131,104,112,0,131, - 104,112,0,131,28,111,0,131,104,112,0,131, - 104,112,0,131,132,111,0,131,152,109,0,131, - 104,112,0,131,104,112,0,131,244,101,0,131, - 104,112,0,131,104,112,0,131,104,112,0,131, - 24,107,0,131,104,112,0,131,104,112,0,131, - 104,112,0,131,76,108,0,131,104,112,0,131, - 228,108,0,131,112,110,0,131,104,112,0,131, - 104,112,0,131,104,112,0,131,104,112,0,131, - 28,109,0,131,104,112,0,131,48,111,0,131, - 104,112,0,131,104,112,0,131,104,112,0,131, - 104,112,0,131,104,112,0,131,104,112,0,131, - 84,109,0,131,104,112,0,131,104,112,0,131, - 32,112,0,131,136,106,0,131,28,106,0,131, - 104,112,0,131,104,112,0,131,52,107,0,131, - 104,112,0,131,104,112,0,131,252,106,0,131, - 88,111,0,131,104,112,0,131,104,112,0,131, - 196,107,0,131,104,112,0,131,180,104,0,131, - 168,106,0,131,92,106,0,131,104,112,0,131, - 104,112,0,131,148,105,0,131,192,106,0,131, - 0,0,0,0,188,111,0,131,204,111,0,131, - 12,112,0,131,12,112,0,131,12,112,0,131, - 12,112,0,131,12,112,0,131,12,112,0,131, - 12,112,0,131,12,112,0,131,12,112,0,131, - 12,112,0,131,252,111,0,131,12,112,0,131, - 12,112,0,131,12,112,0,131,12,112,0,131, - 236,111,0,131,12,112,0,131,12,112,0,131, - 12,112,0,131,12,112,0,131,220,111,0,131, - 252,111,0,131,0,0,0,0,0,0,0,0, - 42,42,42,32,69,69,80,82,79,77,32,80, - 97,115,115,101,100,10,0,0,33,33,33,32, - 69,69,80,82,79,77,32,70,97,105,108,117, - 114,101,58,32,87,114,111,116,101,32,37,48, - 52,120,32,97,116,32,37,100,44,32,103,111, - 116,32,37,48,52,120,10,0,0,0,0,0, - 0,0,0,0,0,0,0,0,35,35,35,70, - 114,97,109,101,32,37,100,32,100,105,100,32, - 110,111,116,32,97,114,114,105,118,101,10,0, - 35,35,35,32,70,114,97,109,101,32,37,100, - 44,32,108,101,110,32,37,100,44,32,98,121, - 116,101,32,37,100,44,32,119,97,110,116,32, - 37,120,32,103,111,116,32,37,120,10,0,0, - 35,35,35,70,114,97,109,101,32,37,100,32, - 119,114,111,110,103,32,108,101,110,103,116,104, - 32,40,119,97,110,116,32,37,100,32,103,111, - 116,32,37,100,41,10,0,0,35,35,35,70, - 114,97,109,101,32,37,100,58,32,103,111,116, - 32,115,101,113,32,37,100,10,0,0,0,0, - 35,35,35,32,37,100,32,67,82,67,32,101, - 114,114,111,114,115,32,111,99,99,117,114,101, - 100,10,0,0,35,35,35,32,37,100,32,65, - 108,105,103,110,32,101,114,114,111,114,115,32, - 111,99,99,117,114,101,100,10,0,0,0,0, - 35,35,35,32,37,100,32,83,104,111,114,116, - 32,101,114,114,111,114,115,32,111,99,99,117, - 114,101,100,10,0,0,0,0,35,35,35,32, - 37,100,32,79,118,101,114,114,117,110,32,101, - 114,114,111,114,115,32,111,99,99,117,114,101, - 100,10,0,0,35,35,35,32,67,85,32,115, - 116,105,108,108,32,114,117,110,110,105,110,103, - 58,32,37,120,10,0,0,0,35,35,35,32, - 99,109,100,32,115,116,105,108,108,32,98,117, - 115,121,58,32,37,120,10,0,35,35,35,32, - 115,116,97,116,117,115,32,115,116,105,108,108, - 32,98,117,115,121,58,32,37,120,10,0,0, - 67,66,61,37,120,44,32,84,66,68,61,37, - 120,44,32,66,85,70,61,37,120,10,0,0, - 116,101,115,116,95,101,116,104,101,114,46,99, - 0,0,0,0,37,100,32,102,114,97,109,101, - 115,32,111,102,32,108,101,110,103,116,104,32, - 37,100,32,115,101,110,116,32,105,110,32,37, - 100,32,109,115,101,99,115,10,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 42,42,42,32,56,50,53,52,32,84,105,109, - 101,114,32,48,32,79,75,44,32,99,111,117, - 110,116,32,119,97,115,32,37,100,10,0,0, - 42,42,42,32,56,50,53,52,32,84,105,109, - 101,114,32,48,32,110,111,116,32,105,110,116, - 101,114,114,117,112,116,105,110,103,32,37,100, - 10,0,0,0,42,42,42,32,56,50,53,52, - 32,84,105,109,101,114,32,48,32,115,112,101, - 101,100,32,119,114,111,110,103,44,32,103,111, - 116,32,37,100,32,115,104,111,117,108,100,32, - 98,101,32,49,48,48,48,10,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 9,37,120,58,32,119,97,110,116,32,37,120, - 32,103,111,116,32,37,120,10,0,0,0,0, - 45,45,45,32,82,65,77,32,84,101,115,116, - 32,111,102,32,37,120,32,116,111,32,37,120, - 32,102,97,105,108,101,100,10,0,0,0,0, - 42,42,42,32,82,65,77,32,84,101,115,116, - 32,111,102,32,37,120,32,116,111,32,37,120, - 32,112,97,115,115,101,100,10,0,0,0,0, - 35,35,35,32,68,77,65,32,68,79,78,69, - 32,110,101,118,101,114,32,111,99,99,117,114, - 114,101,100,46,32,32,99,115,114,32,61,32, - 37,120,10,0,35,35,35,32,72,111,115,116, - 32,110,101,118,101,114,32,103,111,116,32,68, - 77,65,32,105,110,116,101,114,114,117,112,116, - 46,32,98,99,95,99,110,116,32,61,32,37, - 100,10,0,0,35,35,35,32,68,77,65,32, - 101,114,114,111,114,32,97,116,32,105,110,100, - 101,120,32,37,100,58,32,119,97,110,116,101, - 100,32,37,48,50,120,32,103,111,116,32,37, - 48,50,120,10,0,0,0,0,35,35,35,32, - 73,108,108,101,103,97,108,32,72,111,115,116, - 32,97,100,100,114,32,40,61,37,120,41,32, - 111,114,32,108,101,110,103,116,104,32,40,61, - 37,100,41,10,0,0,0,0,35,35,35,32, - 67,111,117,110,116,32,99,97,110,110,111,116, - 32,98,101,32,62,32,49,48,50,52,42,49, - 48,50,52,10,0,0,0,0,42,42,42,32, - 108,99,108,46,66,117,102,49,32,61,32,37, - 120,32,45,45,62,32,104,111,115,116,46,66, - 117,102,32,61,32,37,120,32,45,45,62,32, - 108,99,108,46,66,117,102,50,32,61,32,37, - 120,10,0,0,42,42,42,32,62,32,68,98, - 32,37,100,32,40,98,117,114,115,116,41,59, - 32,62,32,68,119,32,37,100,32,40,119,97, - 105,116,115,116,97,116,101,115,41,10,0,0, - 35,35,35,32,83,101,99,111,110,100,32,97, - 114,103,32,109,117,115,116,32,98,101,32,39, - 114,39,32,111,114,32,39,119,39,32,111,114, - 32,39,108,39,10,0,0,0,42,42,42,32, - 68,77,65,32,37,115,32,105,110,32,37,52, - 100,32,98,121,116,101,32,99,104,117,110,107, - 115,58,32,0,32,32,116,111,32,104,111,115, - 116,0,0,0,102,114,111,109,32,104,111,115, - 116,0,0,0,37,56,100,32,98,121,116,101, - 115,47,115,101,99,46,10,0,116,105,109,101, - 32,116,111,111,32,115,104,111,114,116,32,116, - 111,32,109,101,97,115,117,114,101,10,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 80,37,100,45,62,37,115,32,10,0,0,0, - 116,114,97,110,115,109,105,116,32,112,101,110, - 100,105,110,103,32,111,110,32,37,100,10,0, - 116,114,97,110,115,109,105,116,32,99,111,110, - 102,105,103,32,111,110,32,37,100,10,0,0, - 116,114,97,110,115,109,105,116,32,116,99,110, - 10,0,0,0,116,99,110,32,101,120,112,10, - 0,0,0,0,102,111,114,119,97,114,100,95, - 100,101,108,97,121,32,101,120,112,32,37,100, - 10,0,0,0,109,101,115,115,97,103,101,95, - 97,103,101,32,101,120,112,32,37,100,10,0, - 104,111,108,100,32,101,120,112,32,37,100,10, - 0,0,0,0,84,120,67,79,78,70,73,71, - 37,100,10,0,84,120,84,67,78,37,100,10, - 0,0,0,0,114,99,118,32,99,111,110,102, - 105,103,32,111,110,32,37,100,10,0,0,0, - 90,69,82,79,32,114,111,111,116,33,32,97, - 116,32,37,120,32,0,0,0,115,117,112,101, - 114,99,101,100,101,115,32,37,100,10,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 65,82,80,82,69,81,32,37,120,33,10,0, - 65,82,80,82,69,80,32,37,120,33,10,0, - 83,101,110,100,32,85,68,80,32,37,100,10, - 0,0,0,0,78,111,32,82,66,68,39,115, - 32,105,110,32,85,68,80,32,40,37,100,32, - 37,100,41,10,0,0,0,0,83,101,110,116, - 32,85,68,80,32,37,100,10,0,0,0,0, - 83,78,77,80,32,39,37,99,39,32,108,101, - 110,32,37,100,10,0,0,0,69,110,118,111, - 121,32,114,99,61,37,100,10,0,0,0,0, - 71,101,110,32,116,114,97,112,32,37,100,32, - 114,99,61,37,100,10,0,0,66,97,100,32, - 85,68,80,32,99,104,101,99,107,115,117,109, - 32,37,120,32,108,101,110,32,37,100,10,0, - 66,97,100,32,85,68,80,32,108,101,110,103, - 116,104,32,119,97,110,116,32,37,100,32,103, - 111,116,32,37,100,10,0,0,66,97,100,32, - 73,67,77,80,32,99,104,101,99,107,115,117, - 109,10,0,0,78,111,32,82,66,68,39,115, - 32,105,110,32,73,67,77,80,10,0,0,0, - 66,97,100,32,73,80,32,99,104,101,99,107, - 115,117,109,10,0,0,0,0,84,114,117,110, - 99,97,116,101,100,32,73,80,10,0,0,0, - 83,69,78,84,32,73,80,88,33,10,0,0, - 110,111,32,115,121,115,78,97,109,101,0,0, - 114,105,103,104,116,115,119,105,116,99,104,45, - 0,0,0,0,78,111,32,82,66,68,39,115, - 32,105,110,32,115,101,110,100,95,115,97,112, - 10,0,0,0,78,111,32,82,66,68,39,115, - 32,105,110,32,73,80,88,10,0,0,0,0, - 84,114,117,110,99,97,116,101,100,32,73,80, - 88,10,0,0,0,0,0,0,0,0,0,0, - 77,97,108,108,111,99,32,114,101,116,117,114, - 110,115,32,78,85,76,76,33,0,0,0,0, - 0,0,0,0,0,0,0,0,68,105,103,105, - 32,73,110,116,108,46,32,82,105,103,104,116, - 83,119,105,116,99,104,32,83,69,45,88,0, - 73,110,116,101,108,32,56,50,53,57,54,0, - 0,0,0,0,0,0,0,0,8,206,0,131, - 36,206,0,131,92,206,0,131,112,206,0,131, - 132,206,0,131,220,206,0,131,4,207,0,131, - 4,207,0,131,36,207,0,131,52,207,0,131, - 80,207,0,131,104,207,0,131,132,207,0,131, - 160,207,0,131,188,207,0,131,188,207,0,131, - 216,207,0,131,240,207,0,131,12,208,0,131, - 40,208,0,131,72,208,0,131,112,208,0,131, - 180,210,0,131,232,210,0,131,4,211,0,131, - 36,211,0,131,60,211,0,131,0,0,0,0, - 64,213,0,131,92,213,0,131,124,213,0,131, - 160,213,0,131,60,214,0,131,60,214,0,131, - 60,214,0,131,188,213,0,131,216,213,0,131, - 244,213,0,131,28,214,0,131,168,214,0,131, - 60,214,0,131,168,214,0,131,168,214,0,131, - 88,214,0,131,132,214,0,131,0,0,0,0, - 36,216,0,131,68,216,0,131,104,216,0,131, - 140,216,0,131,140,216,0,131,0,0,0,0, - 248,217,0,131,12,218,0,131,40,218,0,131, - 76,218,0,131,124,218,0,131,152,218,0,131, - 200,218,0,131,228,218,0,131,88,219,0,131, - 116,219,0,131,64,224,0,131,92,224,0,131, - 124,224,0,131,152,224,0,131,184,224,0,131, - 0,0,0,0,110,111,32,115,121,115,67,111, - 110,116,97,99,116,0,0,0,110,111,32,115, - 121,115,78,97,109,101,0,0,110,111,32,115, - 121,115,76,111,99,97,116,105,111,110,0,0, - 37,115,58,37,100,58,32,102,97,105,108,101, - 100,32,97,115,115,101,114,116,105,111,110,32, - 96,37,115,39,10,0,0,0,110,117,109,114, - 101,103,115,32,60,61,32,78,86,82,65,77, - 95,78,82,69,71,83,32,38,38,32,110,117, - 109,114,101,103,115,32,62,32,48,0,0,0, - 102,105,114,115,116,114,101,103,32,60,32,78, - 86,82,65,77,95,78,82,69,71,83,32,38, - 38,32,102,105,114,115,116,114,101,103,32,62, - 61,32,48,0,0,0,0,0,10,13,69,82, - 82,79,82,32,45,0,0,0,0,0,0,0, - 192,244,0,131,8,252,0,131,8,252,0,131, - 8,252,0,131,8,252,0,131,8,252,0,131, - 8,252,0,131,8,252,0,131,192,251,0,131, - 8,252,0,131,8,252,0,131,200,251,0,131, - 212,251,0,131,212,251,0,131,212,251,0,131, - 212,251,0,131,212,251,0,131,212,251,0,131, - 212,251,0,131,212,251,0,131,212,251,0,131, - 8,252,0,131,8,252,0,131,8,252,0,131, - 8,252,0,131,8,252,0,131,8,252,0,131, - 8,252,0,131,8,252,0,131,8,252,0,131, - 8,252,0,131,8,252,0,131,200,244,0,131, - 8,252,0,131,8,252,0,131,8,252,0,131, - 8,252,0,131,8,252,0,131,8,252,0,131, - 8,252,0,131,8,252,0,131,8,252,0,131, - 8,252,0,131,8,252,0,131,8,252,0,131, - 8,252,0,131,8,252,0,131,8,252,0,131, - 8,252,0,131,8,252,0,131,8,252,0,131, - 212,249,0,131,8,252,0,131,8,252,0,131, - 8,252,0,131,8,252,0,131,8,252,0,131, - 8,252,0,131,8,252,0,131,8,252,0,131, - 8,252,0,131,20,245,0,131,8,245,0,131, - 84,247,0,131,8,252,0,131,8,252,0,131, - 8,252,0,131,8,252,0,131,8,252,0,131, - 8,252,0,131,8,252,0,131,244,251,0,131, - 8,252,0,131,8,252,0,131,48,246,0,131, - 8,252,0,131,8,252,0,131,8,252,0,131, - 240,250,0,131,8,252,0,131,132,248,0,131, - 8,252,0,131,8,252,0,131,160,249,0,131, - 72,46,1,131,228,47,1,131,152,46,1,131, - 132,47,1,131,0,47,1,131,228,47,1,131, - 228,47,1,131,228,47,1,131,228,47,1,131, - 228,47,1,131,228,47,1,131,228,47,1,131, - 228,47,1,131,228,47,1,131,228,47,1,131, - 228,47,1,131,228,47,1,131,228,47,1,131, - 228,47,1,131,228,47,1,131,228,47,1,131, - 228,47,1,131,228,47,1,131,228,47,1,131, - 228,47,1,131,228,47,1,131,228,47,1,131, - 228,47,1,131,228,47,1,131,228,47,1,131, - 228,47,1,131,228,47,1,131,228,47,1,131, - 228,47,1,131,228,47,1,131,228,47,1,131, - 228,47,1,131,228,47,1,131,228,47,1,131, - 228,47,1,131,228,47,1,131,228,47,1,131, - 228,47,1,131,228,47,1,131,228,47,1,131, - 228,47,1,131,228,47,1,131,228,47,1,131, - 228,47,1,131,228,47,1,131,228,47,1,131, - 228,47,1,131,228,47,1,131,228,47,1,131, - 228,47,1,131,228,47,1,131,228,47,1,131, - 228,47,1,131,228,47,1,131,228,47,1,131, - 228,47,1,131,228,47,1,131,144,47,1,131, - 108,46,1,131,108,46,1,131,108,46,1,131, - 152,46,1,131,152,46,1,131,228,47,1,131, - 108,46,1,131,20,50,1,131,216,50,1,131, - 56,50,1,131,224,50,1,131,104,50,1,131, - 216,50,1,131,216,50,1,131,216,50,1,131, - 216,50,1,131,216,50,1,131,216,50,1,131, - 216,50,1,131,216,50,1,131,216,50,1,131, - 216,50,1,131,216,50,1,131,216,50,1,131, - 216,50,1,131,216,50,1,131,216,50,1,131, - 216,50,1,131,216,50,1,131,216,50,1,131, - 216,50,1,131,216,50,1,131,216,50,1,131, - 216,50,1,131,216,50,1,131,216,50,1,131, - 216,50,1,131,216,50,1,131,216,50,1,131, - 216,50,1,131,216,50,1,131,216,50,1,131, - 216,50,1,131,216,50,1,131,216,50,1,131, - 216,50,1,131,216,50,1,131,216,50,1,131, - 216,50,1,131,216,50,1,131,216,50,1,131, - 216,50,1,131,216,50,1,131,216,50,1,131, - 216,50,1,131,216,50,1,131,216,50,1,131, - 216,50,1,131,216,50,1,131,216,50,1,131, - 216,50,1,131,216,50,1,131,216,50,1,131, - 216,50,1,131,216,50,1,131,216,50,1,131, - 216,50,1,131,216,50,1,131,216,50,1,131, - 144,50,1,131,20,50,1,131,20,50,1,131, - 20,50,1,131,56,50,1,131,56,50,1,131, - 216,50,1,131,20,50,1,131,124,53,1,131, - 96,53,1,131,96,53,1,131,96,53,1,131, - 96,53,1,131,96,53,1,131,96,53,1,131, - 96,53,1,131,96,53,1,131,96,53,1,131, - 96,53,1,131,96,53,1,131,96,53,1,131, - 96,53,1,131,88,53,1,131,64,53,1,131, - 80,53,1,131,72,53,1,131,64,53,1,131, - 0,0,0,0,28,83,1,131,36,83,1,131, - 36,83,1,131,36,83,1,131,36,83,1,131, - 28,83,1,131,44,83,1,131,44,83,1,131, - 44,83,1,131,44,83,1,131,44,83,1,131, - 28,83,1,131,44,83,1,131,0,0,0,0, - 196,88,1,131,232,88,1,131,208,88,1,131, - 220,88,1,131,244,88,1,131,0,0,0,0, - 4,0,0,0,5,0,0,0,6,0,0,0, - 7,0,0,0,2,0,0,0,3,0,0,0, - 0,0,0,0,1,0,0,0,72,30,0,131, - 72,30,0,131,216,44,0,131,0,30,0,131, - 108,30,0,131,108,30,0,131,108,30,0,131, - 108,30,0,131,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,20,137,1,131, - 204,136,1,131,132,136,1,131,56,136,1,131, - 236,135,1,131,172,135,1,131,120,135,1,131, - 52,135,1,131,232,134,1,131,160,134,1,131, - 80,134,1,131,8,134,1,131,188,133,1,131, - 120,133,1,131,0,0,0,0,0,0,0,0, - 72,72,72,72,72,72,72,72,72,72,72,72, - 72,72,72,72,72,72,72,72,72,72,72,72, - 72,72,72,72,72,72,72,72,72,72,72,72, - 72,72,72,72,72,72,72,72,72,72,72,72, - 72,72,72,72,72,72,72,72,72,72,72,72, - 72,72,72,72,72,72,72,72,72,72,72,72, - 72,72,72,72,72,0,0,0,0,255,85,170, - 0,0,0,0,4,0,8,0,16,0,32,0, - 64,0,0,1,0,8,0,0,0,0,0,0, - 0,0,0,0,0,4,3,2,1,0,0,0, - 7,0,0,0,1,0,1,0,1,0,2,0, - 20,0,15,0,1,0,0,128,128,0,0,0, - 100,0,0,0,96,207,1,131,92,207,1,131, - 88,207,1,131,84,207,1,131,80,207,1,131, - 0,0,0,0,0,0,0,0,48,49,50,51, - 52,53,54,55,56,57,65,66,67,68,69,70, - 0,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,64,204,0,131,156,202,0,131, - 96,148,1,131,1,0,4,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 200,155,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,124,204,0,131,156,202,0,131, - 168,210,1,131,1,0,6,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 4,156,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,132,204,0,131,156,202,0,131, - 4,1,0,163,1,0,67,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 64,156,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,168,204,0,131,248,204,0,131, - 80,18,3,131,1,0,4,3,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 124,156,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,168,204,0,131,32,205,0,131, - 96,18,3,131,1,0,4,3,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 184,156,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,168,204,0,131,72,205,0,131, - 112,18,3,131,1,0,4,3,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 244,156,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,112,205,0,131,156,202,0,131, - 2,0,0,0,1,0,2,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 48,157,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,0,0, - 220,155,1,131,2,0,0,0,24,156,1,131, - 3,0,0,0,84,156,1,131,4,0,0,0, - 144,156,1,131,5,0,0,0,204,156,1,131, - 6,0,0,0,8,157,1,131,7,0,0,0, - 68,157,1,131,0,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,120,205,0,131, - 156,202,0,131,48,211,1,131,1,0,2,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,172,157,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,2,1,180,208,0,131,132,205,0,131, - 164,202,0,131,76,209,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,4,1,180,208,0,131, - 132,205,0,131,164,202,0,131,76,209,0,131, - 124,148,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,2,1, - 180,208,0,131,132,205,0,131,164,202,0,131, - 76,209,0,131,6,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,2,1,180,208,0,131,132,205,0,131, - 164,202,0,131,76,209,0,131,220,5,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,66,1,180,208,0,131, - 132,205,0,131,164,202,0,131,76,209,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,4,1, - 180,208,0,131,132,205,0,131,164,202,0,131, - 76,209,0,131,0,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,2,3,180,208,0,131,132,205,0,131, - 228,209,0,131,76,209,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,2,1,180,208,0,131, - 132,205,0,131,164,202,0,131,76,209,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,67,1, - 180,208,0,131,132,205,0,131,164,202,0,131, - 76,209,0,131,0,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,65,1,180,208,0,131,132,205,0,131, - 164,202,0,131,76,209,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,65,1,180,208,0,131, - 132,205,0,131,164,202,0,131,76,209,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,65,1, - 180,208,0,131,132,205,0,131,164,202,0,131, - 76,209,0,131,0,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,65,1,180,208,0,131,132,205,0,131, - 164,202,0,131,76,209,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,65,1,180,208,0,131, - 132,205,0,131,164,202,0,131,76,209,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,65,1, - 180,208,0,131,132,205,0,131,164,202,0,131, - 76,209,0,131,0,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,65,1,180,208,0,131,132,205,0,131, - 164,202,0,131,76,209,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,65,1,180,208,0,131, - 132,205,0,131,164,202,0,131,76,209,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,65,1, - 180,208,0,131,132,205,0,131,164,202,0,131, - 76,209,0,131,0,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,65,1,180,208,0,131,132,205,0,131, - 164,202,0,131,76,209,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,65,1,180,208,0,131, - 132,205,0,131,164,202,0,131,76,209,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,66,1, - 180,208,0,131,132,205,0,131,164,202,0,131, - 76,209,0,131,0,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,6,1,180,208,0,131,132,205,0,131, - 164,202,0,131,76,209,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,0,0,232,157,1,131, - 2,0,0,0,16,158,1,131,3,0,0,0, - 56,158,1,131,4,0,0,0,96,158,1,131, - 5,0,0,0,136,158,1,131,6,0,0,0, - 176,158,1,131,7,0,0,0,216,158,1,131, - 8,0,0,0,0,159,1,131,9,0,0,0, - 40,159,1,131,10,0,0,0,80,159,1,131, - 11,0,0,0,120,159,1,131,12,0,0,0, - 160,159,1,131,13,0,0,0,200,159,1,131, - 14,0,0,0,240,159,1,131,15,0,0,0, - 24,160,1,131,16,0,0,0,64,160,1,131, - 17,0,0,0,104,160,1,131,18,0,0,0, - 144,160,1,131,19,0,0,0,184,160,1,131, - 20,0,0,0,224,160,1,131,21,0,0,0, - 8,161,1,131,22,0,0,0,48,161,1,131, - 0,0,0,0,0,0,0,0,1,0,0,0, - 32,208,1,131,0,0,0,0,0,0,0,0, - 1,0,0,0,192,157,1,131,2,0,0,0, - 40,208,1,131,0,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,112,205,0,131, - 60,210,0,131,2,0,0,0,1,0,2,3, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,56,162,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,120,205,0,131, - 60,210,0,131,0,17,3,131,1,0,2,3, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,116,162,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,4,17,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,176,162,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,8,17,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,236,162,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,12,17,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,40,163,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,16,17,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,100,163,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,20,17,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,160,163,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,24,17,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,220,163,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,28,17,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,24,164,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,32,17,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,84,164,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,36,17,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,144,164,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,40,17,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,204,164,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,120,205,0,131, - 156,202,0,131,44,17,3,131,1,0,2,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,8,165,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,48,17,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,68,165,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,52,17,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,128,165,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,56,17,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,188,165,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,60,17,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,248,165,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,64,17,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,52,166,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,68,17,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,112,166,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,64,1,44,202,0,131,88,210,0,131, - 164,202,0,131,120,211,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,2,1,44,202,0,131, - 88,210,0,131,164,202,0,131,120,211,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,64,1, - 44,202,0,131,88,210,0,131,164,202,0,131, - 120,211,0,131,0,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,2,1,44,202,0,131,88,210,0,131, - 164,202,0,131,120,211,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,2,1,44,202,0,131, - 88,210,0,131,164,202,0,131,120,211,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,0,0, - 172,166,1,131,2,0,0,0,212,166,1,131, - 3,0,0,0,252,166,1,131,4,0,0,0, - 36,167,1,131,5,0,0,0,76,167,1,131, - 0,0,0,0,0,0,0,0,1,0,0,0, - 56,208,1,131,0,0,0,0,0,0,0,0, - 1,0,64,3,84,212,0,131,16,212,0,131, - 52,212,0,131,172,212,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,2,3,84,212,0,131, - 16,212,0,131,52,212,0,131,172,212,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,2,3, - 84,212,0,131,16,212,0,131,52,212,0,131, - 172,212,0,131,0,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,2,3,84,212,0,131,16,212,0,131, - 52,212,0,131,172,212,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,2,3,84,212,0,131, - 16,212,0,131,52,212,0,131,172,212,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,2,3, - 84,212,0,131,16,212,0,131,52,212,0,131, - 172,212,0,131,0,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,64,3,84,212,0,131,16,212,0,131, - 52,212,0,131,172,212,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,2,3,84,212,0,131, - 16,212,0,131,52,212,0,131,172,212,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,2,1, - 84,212,0,131,16,212,0,131,164,202,0,131, - 172,212,0,131,0,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,2,3,84,212,0,131,16,212,0,131, - 52,212,0,131,172,212,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,64,3,84,212,0,131, - 16,212,0,131,52,212,0,131,172,212,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,2,3, - 84,212,0,131,16,212,0,131,52,212,0,131, - 172,212,0,131,0,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,6,1,84,212,0,131,16,212,0,131, - 164,202,0,131,172,212,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,0,0,180,167,1,131, - 2,0,0,0,220,167,1,131,3,0,0,0, - 4,168,1,131,4,0,0,0,44,168,1,131, - 5,0,0,0,84,168,1,131,6,0,0,0, - 124,168,1,131,7,0,0,0,164,168,1,131, - 8,0,0,0,204,168,1,131,9,0,0,0, - 244,168,1,131,10,0,0,0,28,169,1,131, - 11,0,0,0,68,169,1,131,12,0,0,0, - 108,169,1,131,13,0,0,0,148,169,1,131, - 0,0,0,0,0,0,0,0,1,0,0,0, - 72,208,1,131,0,0,0,0,0,0,0,0, - 1,0,2,3,84,212,0,131,16,212,0,131, - 52,212,0,131,172,212,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,4,3,84,212,0,131, - 16,212,0,131,52,212,0,131,172,212,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,64,3, - 84,212,0,131,16,212,0,131,52,212,0,131, - 172,212,0,131,0,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,2,3,84,212,0,131,16,212,0,131, - 52,212,0,131,172,212,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,0,0,60,170,1,131, - 2,0,0,0,100,170,1,131,3,0,0,0, - 140,170,1,131,4,0,0,0,180,170,1,131, - 0,0,0,0,0,0,0,0,1,0,0,0, - 88,208,1,131,0,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,72,17,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,20,171,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,0,0,76,162,1,131,2,0,0,0, - 136,162,1,131,3,0,0,0,196,162,1,131, - 4,0,0,0,0,163,1,131,5,0,0,0, - 60,163,1,131,6,0,0,0,120,163,1,131, - 7,0,0,0,180,163,1,131,8,0,0,0, - 240,163,1,131,9,0,0,0,44,164,1,131, - 10,0,0,0,104,164,1,131,11,0,0,0, - 164,164,1,131,12,0,0,0,224,164,1,131, - 13,0,0,0,28,165,1,131,14,0,0,0, - 88,165,1,131,15,0,0,0,148,165,1,131, - 16,0,0,0,208,165,1,131,17,0,0,0, - 12,166,1,131,18,0,0,0,72,166,1,131, - 19,0,0,0,132,166,1,131,20,0,0,0, - 64,208,1,131,21,0,0,0,80,208,1,131, - 22,0,0,0,96,208,1,131,23,0,0,0, - 40,171,1,131,0,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,144,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,16,172,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,148,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,76,172,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,152,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,136,172,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,156,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,196,172,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,160,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,0,173,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,164,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,60,173,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,168,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,120,173,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,172,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,180,173,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,176,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,240,173,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,180,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,44,174,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,184,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,104,174,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,188,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,164,174,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,192,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,224,174,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,196,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,28,175,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,200,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,88,175,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,204,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,148,175,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,208,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,208,175,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,212,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,12,176,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,216,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,72,176,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,220,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,132,176,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,224,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,192,176,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,228,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,252,176,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,232,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,56,177,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,236,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,116,177,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,240,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,176,177,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,244,16,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,236,177,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,0,0,36,172,1,131,2,0,0,0, - 96,172,1,131,3,0,0,0,156,172,1,131, - 4,0,0,0,216,172,1,131,5,0,0,0, - 20,173,1,131,6,0,0,0,80,173,1,131, - 7,0,0,0,140,173,1,131,8,0,0,0, - 200,173,1,131,9,0,0,0,4,174,1,131, - 10,0,0,0,64,174,1,131,11,0,0,0, - 124,174,1,131,12,0,0,0,184,174,1,131, - 13,0,0,0,244,174,1,131,14,0,0,0, - 48,175,1,131,15,0,0,0,108,175,1,131, - 16,0,0,0,168,175,1,131,17,0,0,0, - 228,175,1,131,18,0,0,0,32,176,1,131, - 19,0,0,0,92,176,1,131,20,0,0,0, - 152,176,1,131,21,0,0,0,212,176,1,131, - 22,0,0,0,16,177,1,131,23,0,0,0, - 76,177,1,131,24,0,0,0,136,177,1,131, - 25,0,0,0,196,177,1,131,26,0,0,0, - 0,178,1,131,0,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,112,17,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,0,179,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,116,17,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,60,179,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,120,17,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,120,179,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,76,210,0,131, - 156,202,0,131,124,17,3,131,1,0,65,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,180,179,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,200,212,0,131, - 156,202,0,131,220,5,0,163,1,0,64,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,240,179,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,112,205,0,131, - 156,202,0,131,161,0,0,0,1,0,2,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,44,180,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,0,0,4,180,1,131,2,0,0,0, - 64,180,1,131,0,0,0,0,0,0,0,0, - 1,0,0,0,120,208,1,131,0,0,0,0, - 0,0,0,0,1,0,0,0,20,179,1,131, - 2,0,0,0,80,179,1,131,3,0,0,0, - 140,179,1,131,4,0,0,0,200,179,1,131, - 5,0,0,0,128,208,1,131,0,0,0,0, - 0,0,0,0,1,0,2,1,44,202,0,131, - 208,212,0,131,164,202,0,131,196,214,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,65,1, - 44,202,0,131,208,212,0,131,164,202,0,131, - 196,214,0,131,0,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,65,1,44,202,0,131,208,212,0,131, - 164,202,0,131,196,214,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,65,1,44,202,0,131, - 208,212,0,131,164,202,0,131,196,214,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,65,1, - 44,202,0,131,208,212,0,131,164,202,0,131, - 196,214,0,131,0,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,65,1,44,202,0,131,208,212,0,131, - 164,202,0,131,196,214,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,65,1,44,202,0,131, - 208,212,0,131,164,202,0,131,196,214,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,65,1, - 44,202,0,131,208,212,0,131,164,202,0,131, - 196,214,0,131,0,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,65,1,44,202,0,131,208,212,0,131, - 164,202,0,131,196,214,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,65,1,44,202,0,131, - 208,212,0,131,164,202,0,131,196,214,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,65,1, - 44,202,0,131,208,212,0,131,164,202,0,131, - 196,214,0,131,0,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,65,1,44,202,0,131,208,212,0,131, - 164,202,0,131,196,214,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,65,1,44,202,0,131, - 208,212,0,131,164,202,0,131,196,214,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,6,1, - 44,202,0,131,208,212,0,131,164,202,0,131, - 196,214,0,131,0,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,0,0,192,180,1,131,2,0,0,0, - 232,180,1,131,3,0,0,0,16,181,1,131, - 4,0,0,0,56,181,1,131,5,0,0,0, - 96,181,1,131,6,0,0,0,136,181,1,131, - 7,0,0,0,176,181,1,131,8,0,0,0, - 216,181,1,131,9,0,0,0,0,182,1,131, - 10,0,0,0,40,182,1,131,11,0,0,0, - 80,182,1,131,13,0,0,0,120,182,1,131, - 16,0,0,0,160,182,1,131,17,0,0,0, - 200,182,1,131,0,0,0,0,0,0,0,0, - 1,0,0,0,144,208,1,131,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,1,0,0,0, - 160,208,1,131,2,0,0,0,168,208,1,131, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 1,0,0,0,184,208,1,131,2,0,0,0, - 192,208,1,131,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 1,0,0,0,208,208,1,131,2,0,0,0, - 216,208,1,131,3,0,0,0,224,208,1,131, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 1,0,0,0,240,208,1,131,2,0,0,0, - 248,208,1,131,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,1,0,0,0, - 8,209,1,131,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,1,0,0,0,24,209,1,131, - 2,0,0,0,32,209,1,131,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 1,0,0,0,48,209,1,131,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 1,0,0,0,64,209,1,131,0,0,0,0, - 0,0,0,0,1,0,0,0,232,208,1,131, - 2,0,0,0,0,209,1,131,3,0,0,0, - 16,209,1,131,4,0,0,0,40,209,1,131, - 5,0,0,0,56,209,1,131,6,0,0,0, - 72,209,1,131,0,0,0,0,0,0,0,0, - 2,0,0,0,152,208,1,131,6,0,0,0, - 176,208,1,131,7,0,0,0,200,208,1,131, - 8,0,0,0,80,209,1,131,0,0,0,0, - 0,0,0,0,7,0,0,0,88,209,1,131, - 0,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 128,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 8,185,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 144,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 68,185,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 148,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 128,185,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 132,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 188,185,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 136,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 248,185,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 140,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 52,186,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 156,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 112,186,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 160,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 172,186,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 164,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 232,186,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 168,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 36,187,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 172,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 96,187,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 176,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 156,187,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 180,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 216,187,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 184,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 20,188,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 188,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 80,188,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 192,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 140,188,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 196,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 200,188,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 200,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 4,189,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 204,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 64,189,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 208,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 124,189,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 212,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 184,189,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 220,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 244,189,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 224,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 48,190,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 228,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 108,190,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 232,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 168,190,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 236,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 228,190,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,92,215,0,131,156,202,0,131, - 240,17,3,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 32,191,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,104,215,0,131,140,215,0,131, - 0,0,0,0,1,0,2,3,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 92,191,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,0,0, - 28,185,1,131,2,0,0,0,88,185,1,131, - 3,0,0,0,148,185,1,131,4,0,0,0, - 208,185,1,131,5,0,0,0,12,186,1,131, - 6,0,0,0,72,186,1,131,8,0,0,0, - 132,186,1,131,9,0,0,0,192,186,1,131, - 10,0,0,0,252,186,1,131,11,0,0,0, - 56,187,1,131,12,0,0,0,116,187,1,131, - 13,0,0,0,176,187,1,131,14,0,0,0, - 236,187,1,131,15,0,0,0,40,188,1,131, - 16,0,0,0,100,188,1,131,17,0,0,0, - 160,188,1,131,18,0,0,0,220,188,1,131, - 19,0,0,0,24,189,1,131,20,0,0,0, - 84,189,1,131,21,0,0,0,144,189,1,131, - 22,0,0,0,204,189,1,131,24,0,0,0, - 8,190,1,131,25,0,0,0,68,190,1,131, - 26,0,0,0,128,190,1,131,27,0,0,0, - 188,190,1,131,28,0,0,0,248,190,1,131, - 29,0,0,0,52,191,1,131,30,0,0,0, - 112,191,1,131,0,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,180,215,0,131, - 156,202,0,131,218,12,3,131,1,0,4,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,128,192,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,120,205,0,131, - 156,202,0,131,40,211,1,131,1,0,2,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,188,192,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 8,202,0,131,148,38,1,131,112,205,0,131, - 156,202,0,131,2,0,0,0,1,0,2,1, - 32,45,1,131,208,48,1,131,160,49,1,131, - 20,48,1,131,248,192,1,131,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,2,1,44,202,0,131,200,215,0,131, - 164,202,0,131,196,216,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,2,1,44,202,0,131, - 200,215,0,131,164,202,0,131,196,216,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,6,1, - 44,202,0,131,200,215,0,131,164,202,0,131, - 196,216,0,131,0,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,65,1,44,202,0,131,200,215,0,131, - 164,202,0,131,196,216,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,65,1,44,202,0,131, - 200,215,0,131,164,202,0,131,196,216,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,0,0, - 52,193,1,131,2,0,0,0,92,193,1,131, - 3,0,0,0,132,193,1,131,4,0,0,0, - 172,193,1,131,5,0,0,0,212,193,1,131, - 0,0,0,0,0,0,0,0,1,0,0,0, - 112,209,1,131,0,0,0,0,0,0,0,0, - 1,0,0,0,148,192,1,131,2,0,0,0, - 208,192,1,131,3,0,0,0,12,193,1,131, - 4,0,0,0,120,209,1,131,0,0,0,0, - 0,0,0,0,8,202,0,131,148,38,1,131, - 112,205,0,131,156,202,0,131,3,0,0,0, - 1,0,2,1,32,45,1,131,208,48,1,131, - 160,49,1,131,20,48,1,131,100,194,1,131, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,8,202,0,131,148,38,1,131, - 92,217,0,131,60,210,0,131,216,12,3,131, - 1,0,2,3,32,45,1,131,208,48,1,131, - 160,49,1,131,20,48,1,131,160,194,1,131, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,8,202,0,131,148,38,1,131, - 104,217,0,131,156,202,0,131,0,0,0,0, - 1,0,67,1,32,45,1,131,208,48,1,131, - 160,49,1,131,20,48,1,131,220,194,1,131, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,8,202,0,131,148,38,1,131, - 104,217,0,131,156,202,0,131,0,0,0,0, - 1,0,65,1,32,45,1,131,208,48,1,131, - 160,49,1,131,20,48,1,131,24,195,1,131, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,8,202,0,131,148,38,1,131, - 112,217,0,131,156,202,0,131,216,12,3,131, - 1,0,4,1,32,45,1,131,208,48,1,131, - 160,49,1,131,20,48,1,131,84,195,1,131, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,8,202,0,131,148,38,1,131, - 120,205,0,131,156,202,0,131,224,12,3,131, - 1,0,2,1,32,45,1,131,208,48,1,131, - 160,49,1,131,20,48,1,131,144,195,1,131, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,8,202,0,131,148,38,1,131, - 120,205,0,131,156,202,0,131,228,12,3,131, - 1,0,2,1,32,45,1,131,208,48,1,131, - 160,49,1,131,20,48,1,131,204,195,1,131, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,8,202,0,131,148,38,1,131, - 92,217,0,131,156,202,0,131,232,12,3,131, - 1,0,2,1,32,45,1,131,208,48,1,131, - 160,49,1,131,20,48,1,131,8,196,1,131, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,8,202,0,131,148,38,1,131, - 92,217,0,131,156,202,0,131,234,12,3,131, - 1,0,2,1,32,45,1,131,208,48,1,131, - 160,49,1,131,20,48,1,131,68,196,1,131, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,8,202,0,131,148,38,1,131, - 92,217,0,131,156,202,0,131,246,12,3,131, - 1,0,2,1,32,45,1,131,208,48,1,131, - 160,49,1,131,20,48,1,131,128,196,1,131, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,8,202,0,131,148,38,1,131, - 92,217,0,131,156,202,0,131,236,12,3,131, - 1,0,2,1,32,45,1,131,208,48,1,131, - 160,49,1,131,20,48,1,131,188,196,1,131, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,8,202,0,131,148,38,1,131, - 92,217,0,131,60,210,0,131,238,12,3,131, - 1,0,2,3,32,45,1,131,208,48,1,131, - 160,49,1,131,20,48,1,131,248,196,1,131, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,8,202,0,131,148,38,1,131, - 92,217,0,131,60,210,0,131,240,12,3,131, - 1,0,2,3,32,45,1,131,208,48,1,131, - 160,49,1,131,20,48,1,131,52,197,1,131, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,8,202,0,131,148,38,1,131, - 92,217,0,131,60,210,0,131,242,12,3,131, - 1,0,2,3,32,45,1,131,208,48,1,131, - 160,49,1,131,20,48,1,131,112,197,1,131, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,2,1,180,219,0,131, - 132,217,0,131,164,202,0,131,104,220,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,2,3, - 180,219,0,131,132,217,0,131,0,221,0,131, - 104,220,0,131,0,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,2,1,180,219,0,131,132,217,0,131, - 164,202,0,131,104,220,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,2,3,180,219,0,131, - 132,217,0,131,0,221,0,131,104,220,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,2,3, - 180,219,0,131,132,217,0,131,0,221,0,131, - 104,220,0,131,0,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,4,1,180,219,0,131,132,217,0,131, - 164,202,0,131,104,220,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,2,1,180,219,0,131, - 132,217,0,131,164,202,0,131,104,220,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,4,1, - 180,219,0,131,132,217,0,131,164,202,0,131, - 104,220,0,131,0,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,4,1,180,219,0,131,132,217,0,131, - 164,202,0,131,104,220,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,65,1,180,219,0,131, - 132,217,0,131,164,202,0,131,104,220,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,0,0, - 172,197,1,131,2,0,0,0,212,197,1,131, - 3,0,0,0,252,197,1,131,4,0,0,0, - 36,198,1,131,5,0,0,0,76,198,1,131, - 6,0,0,0,116,198,1,131,7,0,0,0, - 156,198,1,131,8,0,0,0,196,198,1,131, - 9,0,0,0,236,198,1,131,10,0,0,0, - 20,199,1,131,0,0,0,0,0,0,0,0, - 1,0,0,0,136,209,1,131,0,0,0,0, - 0,0,0,0,1,0,0,0,120,194,1,131, - 2,0,0,0,180,194,1,131,3,0,0,0, - 240,194,1,131,4,0,0,0,44,195,1,131, - 5,0,0,0,104,195,1,131,6,0,0,0, - 164,195,1,131,7,0,0,0,224,195,1,131, - 8,0,0,0,28,196,1,131,9,0,0,0, - 88,196,1,131,10,0,0,0,148,196,1,131, - 11,0,0,0,208,196,1,131,12,0,0,0, - 12,197,1,131,13,0,0,0,72,197,1,131, - 14,0,0,0,132,197,1,131,15,0,0,0, - 144,209,1,131,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,76,210,0,131,156,202,0,131, - 160,211,1,131,1,0,65,1,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 44,200,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,8,202,0,131, - 148,38,1,131,120,205,0,131,60,210,0,131, - 140,1,0,163,1,0,2,3,32,45,1,131, - 208,48,1,131,160,49,1,131,20,48,1,131, - 104,200,1,131,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,4,1, - 44,202,0,131,36,222,0,131,164,202,0,131, - 48,223,0,131,0,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,2,1,44,202,0,131,36,222,0,131, - 164,202,0,131,48,223,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,2,1,44,202,0,131, - 36,222,0,131,164,202,0,131,48,223,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,0,0, - 164,200,1,131,2,0,0,0,204,200,1,131, - 3,0,0,0,244,200,1,131,0,0,0,0, - 0,0,0,0,1,0,0,0,168,209,1,131, - 0,0,0,0,0,0,0,0,1,0,2,1, - 44,202,0,131,212,223,0,131,164,202,0,131, - 252,224,0,131,0,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,2,1,44,202,0,131,212,223,0,131, - 164,202,0,131,252,224,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,65,1,44,202,0,131, - 212,223,0,131,164,202,0,131,252,224,0,131, - 0,0,0,0,0,0,0,0,255,0,0,0, - 255,0,0,0,0,0,0,0,1,0,65,1, - 44,202,0,131,212,223,0,131,164,202,0,131, - 252,224,0,131,0,0,0,0,0,0,0,0, - 255,0,0,0,255,0,0,0,0,0,0,0, - 1,0,65,1,44,202,0,131,212,223,0,131, - 164,202,0,131,252,224,0,131,0,0,0,0, - 0,0,0,0,255,0,0,0,255,0,0,0, - 0,0,0,0,1,0,0,0,76,201,1,131, - 2,0,0,0,116,201,1,131,3,0,0,0, - 156,201,1,131,4,0,0,0,196,201,1,131, - 5,0,0,0,236,201,1,131,0,0,0,0, - 0,0,0,0,1,0,0,0,184,209,1,131, - 0,0,0,0,0,0,0,0,1,0,0,0, - 64,200,1,131,2,0,0,0,124,200,1,131, - 3,0,0,0,176,209,1,131,4,0,0,0, - 192,209,1,131,0,0,0,0,0,0,0,0, - 1,0,0,0,128,209,1,131,2,0,0,0, - 152,209,1,131,3,0,0,0,160,209,1,131, - 4,0,0,0,200,209,1,131,0,0,0,0, - 0,0,0,0,1,0,0,0,24,208,1,131, - 2,0,0,0,48,208,1,131,4,0,0,0, - 104,208,1,131,5,0,0,0,112,208,1,131, - 7,0,0,0,136,208,1,131,10,0,0,0, - 96,209,1,131,11,0,0,0,104,209,1,131, - 17,0,0,0,208,209,1,131,0,0,0,0, - 0,0,0,0,1,0,0,0,216,209,1,131, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 1,0,0,0,240,209,1,131,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,1,0,0,0,8,210,1,131, - 2,0,0,0,16,210,1,131,3,0,0,0, - 24,210,1,131,4,0,0,0,32,210,1,131, - 5,0,0,0,40,210,1,131,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,1,0,0,0, - 56,210,1,131,2,0,0,0,64,210,1,131, - 0,0,0,0,0,0,0,0,1,0,0,0, - 72,210,1,131,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,1,0,0,0, - 48,210,1,131,2,0,0,0,80,210,1,131, - 3,0,0,0,88,210,1,131,0,0,0,0, - 0,0,0,0,1,0,0,0,16,208,1,131, - 2,0,0,0,224,209,1,131,3,0,0,0, - 232,209,1,131,4,0,0,0,248,209,1,131, - 5,0,0,0,0,210,1,131,6,0,0,0, - 96,210,1,131,0,0,0,0,0,0,0,0, - 1,0,0,0,104,210,1,131,0,0,0,0, - 0,0,0,0,6,0,0,0,112,210,1,131, - 0,0,0,0,0,0,0,0,3,0,0,0, - 120,210,1,131,0,0,0,0,0,0,0,0, - 1,0,0,0,128,210,1,131,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 1,0,0,0,3,0,0,0,6,0,0,0, - 1,0,0,0,2,0,0,0,1,0,0,0, - 10,0,0,0,7,0,0,0,8,0,0,0, - 2,0,0,0,2,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,112,117,98,108, - 105,99,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,112,114,105,118,97,116,101,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 83,78,77,80,95,116,114,97,112,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,1,0,0,0, - 3,0,0,0,6,0,0,0,1,0,0,0, - 4,0,0,0,1,0,0,0,76,1,0,0, - 5,0,0,0,1,0,0,0,1,0,0,0, - 0,0,0,0,0,0,0,0,1,0,0,0, - 3,0,0,0,6,0,0,0,1,0,0,0, - 2,0,0,0,1,0,0,0,2,0,0,0, - 2,0,0,0,1,0,0,0,1,0,0,0, - 0,0,0,0,1,0,0,0,3,0,0,0, - 6,0,0,0,1,0,0,0,2,0,0,0, - 1,0,0,0,17,0,0,0,0,0,0,0, - 0,0,0,0,48,49,50,51,52,53,54,55, - 56,57,65,66,67,68,69,70,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 255,85,170,0,255,255,255,255,85,85,85,85, - 170,170,170,170,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,64,40,35,41, - 32,67,111,112,121,114,105,103,104,116,32,40, - 99,41,32,49,57,56,54,32,45,32,49,57, - 57,53,32,32,69,112,105,108,111,103,117,101, - 32,84,101,99,104,110,111,108,111,103,121,32, - 67,111,114,112,111,114,97,116,105,111,110,10, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,255,255,255,255, - 72,10,0,0,78,10,0,0,83,10,0,0, - 69,10,0,0,109,97,105,110,46,99,0,0, - 48,0,0,0,55,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,1,0,0,0, - 0,0,0,0,116,105,109,101,114,46,99,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 100,0,0,0,100,0,0,0,1,0,0,0, - 0,0,0,0,115,114,99,32,0,0,0,0, - 32,0,0,0,100,115,116,32,0,0,0,0, - 32,37,48,50,88,0,0,0,10,0,0,0, - 255,255,255,255,48,48,48,48,48,48,0,0, - 48,48,48,48,48,49,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,255,255,255,255, - 0,0,0,0,0,0,0,0,0,0,0,0, - 62,32,0,0,37,120,10,0,37,120,58,9, - 37,120,10,0,37,115,10,0,0,0,0,0, - 10,0,0,0,0,0,0,0,0,0,0,0, - 68,85,77,80,10,0,0,0,37,48,50,120, - 32,0,0,0,10,0,0,0,0,0,0,0, - 37,100,32,112,112,115,10,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 1,0,0,0,0,0,0,0,1,0,0,0, - 119,119,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,1,128,194,0, - 0,0,0,0,1,128,194,0,0,16,0,0, - 66,76,75,0,70,87,68,0,76,82,78,0, - 76,73,83,0,68,73,83,0,72,69,76,76, - 79,10,0,0,116,99,32,101,120,112,10,0, - 102,114,111,109,32,0,0,0,10,0,0,0, - 87,101,105,114,100,0,0,0,0,0,0,0, - 0,0,0,0,255,255,255,255,255,255,255,255, - 255,255,0,0,255,255,255,255,255,255,0,0, - 0,0,0,0,0,0,0,0,80,65,68,37, - 100,10,0,0,170,170,3,0,0,0,0,0, - 83,69,78,84,33,10,0,0,85,68,80,10, - 0,0,0,0,73,67,77,80,10,0,0,0, - 69,67,72,79,10,0,0,0,73,80,10,0, - 170,170,3,0,0,0,0,0,73,80,88,33, - 10,0,0,0,0,0,0,0,255,255,255,255, - 255,255,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,192,155,1,131,0,0,0,0, - 108,157,1,131,0,0,0,0,88,161,1,131, - 0,0,0,0,16,162,1,131,0,0,0,0, - 32,162,1,131,0,0,0,0,116,167,1,131, - 0,0,0,0,164,167,1,131,0,0,0,0, - 188,169,1,131,0,0,0,0,44,170,1,131, - 0,0,0,0,220,170,1,131,0,0,0,0, - 4,171,1,131,0,0,0,0,80,171,1,131, - 0,0,0,0,40,178,1,131,0,0,0,0, - 104,180,1,131,0,0,0,0,128,180,1,131, - 0,0,0,0,144,180,1,131,0,0,0,0, - 240,182,1,131,0,0,0,0,104,183,1,131, - 0,0,0,0,120,183,1,131,0,0,0,0, - 128,183,1,131,0,0,0,0,136,183,1,131, - 0,0,0,0,160,183,1,131,0,0,0,0, - 168,183,1,131,0,0,0,0,176,183,1,131, - 0,0,0,0,200,183,1,131,0,0,0,0, - 208,183,1,131,0,0,0,0,216,183,1,131, - 0,0,0,0,224,183,1,131,0,0,0,0, - 0,184,1,131,0,0,0,0,8,184,1,131, - 0,0,0,0,16,184,1,131,0,0,0,0, - 40,184,1,131,0,0,0,0,48,184,1,131, - 0,0,0,0,64,184,1,131,0,0,0,0, - 72,184,1,131,0,0,0,0,80,184,1,131, - 0,0,0,0,104,184,1,131,0,0,0,0, - 112,184,1,131,0,0,0,0,128,184,1,131, - 0,0,0,0,136,184,1,131,0,0,0,0, - 152,184,1,131,0,0,0,0,208,184,1,131, - 0,0,0,0,248,184,1,131,0,0,0,0, - 152,191,1,131,0,0,0,0,252,193,1,131, - 0,0,0,0,44,194,1,131,0,0,0,0, - 60,194,1,131,0,0,0,0,60,199,1,131, - 0,0,0,0,148,199,1,131,0,0,0,0, - 164,199,1,131,0,0,0,0,36,200,1,131, - 0,0,0,0,28,201,1,131,0,0,0,0, - 60,201,1,131,0,0,0,0,20,202,1,131, - 0,0,0,0,68,202,1,131,0,0,0,0, - 84,202,1,131,0,0,0,0,124,202,1,131, - 0,0,0,0,164,202,1,131,0,0,0,0, - 236,202,1,131,0,0,0,0,252,202,1,131, - 0,0,0,0,4,203,1,131,0,0,0,0, - 12,203,1,131,0,0,0,0,28,203,1,131, - 0,0,0,0,36,203,1,131,0,0,0,0, - 44,203,1,131,0,0,0,0,52,203,1,131, - 0,0,0,0,60,203,1,131,0,0,0,0, - 68,203,1,131,0,0,0,0,76,203,1,131, - 0,0,0,0,124,203,1,131,0,0,0,0, - 132,203,1,131,0,0,0,0,140,203,1,131, - 0,0,0,0,164,203,1,131,0,0,0,0, - 180,203,1,131,0,0,0,0,188,203,1,131, - 0,0,0,0,220,203,1,131,0,0,0,0, - 20,204,1,131,0,0,0,0,36,204,1,131, - 0,0,0,0,52,204,1,131,0,0,0,0, - 68,204,1,131,255,255,255,0,0,0,0,0, - 0,0,0,0,0,0,0,0,1,0,0,0, - 10,0,0,0,10,0,0,0,0,205,1,131, - 10,0,0,0,7,0,0,0,0,0,0,0, - 0,0,0,0,255,255,255,255,110,118,114,97, - 109,46,99,0,114,99,0,0,48,120,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0 - } ; -static const int dgrs_ncode = 119520 ; diff --git a/drivers/net/dgrs_i82596.h b/drivers/net/dgrs_i82596.h deleted file mode 100644 index ac9217ad213..00000000000 --- a/drivers/net/dgrs_i82596.h +++ /dev/null @@ -1,473 +0,0 @@ -/* - * i82596 ethernet controller bits and structures (little endian) - * - * $Id: i82596.h,v 1.8 1996/09/03 11:19:03 rick Exp $ - */ - -/************************************************************************/ -/* */ -/* PORT commands (p. 4-20). The least significant nibble is one */ -/* of these commands, the rest of the command is a memory address */ -/* aligned on a 16 byte boundary. Note that port commands must */ -/* be written to the PORT address and the PORT address+2 with two */ -/* halfword writes. Write the LSH first to PORT, then the MSH to */ -/* PORT+2. Blame Intel. */ -/* */ -/************************************************************************/ -#define I596_PORT_RESET 0x0 /* Reset. Wait 5 SysClks & 10 TxClks */ -#define I596_PORT_SELFTEST 0x1 /* Do a selftest */ -#define I596_PORT_SCP_ADDR 0x2 /* Set new SCP address */ -#define I596_PORT_DUMP 0x3 /* Dump internal data structures */ - -/* - * I596_ST: Selftest results (p. 4-21) - */ -typedef volatile struct -{ - ulong signature; /* ROM checksum */ - ulong result; /* Selftest results: non-zero is a failure */ -} I596_ST; - -#define I596_ST_SELFTEST_FAIL 0x1000 /* Selftest Failed */ -#define I596_ST_DIAGNOSE_FAIL 0x0020 /* Diagnose Failed */ -#define I596_ST_BUSTIMER_FAIL 0x0010 /* Bus Timer Failed */ -#define I596_ST_REGISTER_FAIL 0x0008 /* Register Failed */ -#define I596_ST_ROM_FAIL 0x0004 /* ROM Failed */ - -/* - * I596_DUMP: Dump results - */ -typedef volatile struct -{ - ulong dump[77]; -} I596_DUMP; - -/************************************************************************/ -/* */ -/* I596_TBD: Transmit Buffer Descriptor (p. 4-59) */ -/* */ -/************************************************************************/ -typedef volatile struct _I596_TBD -{ - ulong count; - vol struct _I596_TBD *next; - uchar *buf; - ushort unused1; - ushort unused2; -} I596_TBD; - -#define I596_TBD_NOLINK ((I596_TBD *) 0xffffffff) -#define I596_TBD_EOF 0x8000 -#define I596_TBD_COUNT_MASK 0x3fff - -/************************************************************************/ -/* */ -/* I596_TFD: Transmit Frame Descriptor (p. 4-56) */ -/* a.k.a. I596_CB_XMIT */ -/* */ -/************************************************************************/ -typedef volatile struct -{ - ushort status; - ushort cmd; - union _I596_CB *next; - I596_TBD *tbdp; - ulong count; /* for speed */ - - /* Application defined data follows structure... */ - -#if 0 /* We don't use these intel defined ones */ - uchar addr[6]; - ushort len; - uchar data[1]; -#else - ulong dstchan;/* Used by multi-NIC mode */ -#endif -} I596_TFD; - -#define I596_TFD_NOCRC 0x0010 /* cmd: No CRC insertion */ -#define I596_TFD_FLEX 0x0008 /* cmd: Flexible mode */ - -/************************************************************************/ -/* */ -/* I596_RBD: Receive Buffer Descriptor (p. 4-84) */ -/* */ -/************************************************************************/ -typedef volatile struct _I596_RBD -{ -#ifdef INTEL_RETENTIVE - ushort count; /* Length of data in buf */ - ushort offset; -#else - ulong count; /* Length of data in buf */ -#endif - vol struct _I596_RBD *next; /* Next buffer descriptor in list */ - uchar *buf; /* Data buffer */ -#ifdef INTEL_RETENTIVE - ushort size; /* Size of buf (constant) */ - ushort zero; -#else - ulong size; /* Size of buf (constant) */ -#endif - - /* Application defined data follows structure... */ - - uchar chan; - uchar refcnt; - ushort len; -} I596_RBD; - -#define I596_RBD_NOLINK ((I596_RBD *) 0xffffffff) -#define I596_RBD_EOF 0x8000 /* This is last buffer in a frame */ -#define I596_RBD_F 0x4000 /* The actual count is valid */ - -#define I596_RBD_EL 0x8000 /* Last buffer in list */ - -/************************************************************************/ -/* */ -/* I596_RFD: Receive Frame Descriptor (p. 4-79) */ -/* */ -/************************************************************************/ -typedef volatile struct _I596_RFD -{ - ushort status; - ushort cmd; - vol struct _I596_RFD *next; - vol struct _I596_RBD *rbdp; - ushort count; /* Len of data in RFD: always 0 */ - ushort size; /* Size of RFD buffer: always 0 */ - - /* Application defined data follows structure... */ - -# if 0 /* We don't use these intel defined ones */ - uchar addr[6]; - ushort len; - uchar data[1]; -# else - ulong dstchan;/* Used by multi-nic mode */ -# endif -} I596_RFD; - -#define I596_RFD_C 0x8000 /* status: frame complete */ -#define I596_RFD_B 0x4000 /* status: frame busy or waiting */ -#define I596_RFD_OK 0x2000 /* status: frame OK */ -#define I596_RFD_ERR_LENGTH 0x1000 /* status: length error */ -#define I596_RFD_ERR_CRC 0x0800 /* status: CRC error */ -#define I596_RFD_ERR_ALIGN 0x0400 /* status: alignment error */ -#define I596_RFD_ERR_NOBUFS 0x0200 /* status: resource error */ -#define I596_RFD_ERR_DMA 0x0100 /* status: DMA error */ -#define I596_RFD_ERR_SHORT 0x0080 /* status: too short error */ -#define I596_RFD_NOMATCH 0x0002 /* status: IA was not matched */ -#define I596_RFD_COLLISION 0x0001 /* status: collision during receive */ - -#define I596_RFD_EL 0x8000 /* cmd: end of RFD list */ -#define I596_RFD_FLEX 0x0008 /* cmd: Flexible mode */ -#define I596_RFD_EOF 0x8000 /* count: last buffer in the frame */ -#define I596_RFD_F 0x4000 /* count: The actual count is valid */ - -/************************************************************************/ -/* */ -/* Commands */ -/* */ -/************************************************************************/ - - /* values for cmd halfword in all the structs below */ -#define I596_CB_CMD 0x07 /* CB COMMANDS */ -#define I596_CB_CMD_NOP 0 -#define I596_CB_CMD_IA 1 -#define I596_CB_CMD_CONF 2 -#define I596_CB_CMD_MCAST 3 -#define I596_CB_CMD_XMIT 4 -#define I596_CB_CMD_TDR 5 -#define I596_CB_CMD_DUMP 6 -#define I596_CB_CMD_DIAG 7 - -#define I596_CB_CMD_EL 0x8000 /* CB is last in linked list */ -#define I596_CB_CMD_S 0x4000 /* Suspend after execution */ -#define I596_CB_CMD_I 0x2000 /* cause interrupt */ - - /* values for the status halfword in all the struct below */ -#define I596_CB_STATUS 0xF000 /* All four status bits */ -#define I596_CB_STATUS_C 0x8000 /* Command complete */ -#define I596_CB_STATUS_B 0x4000 /* Command busy executing */ -#define I596_CB_STATUS_C_OR_B 0xC000 /* Command complete or busy */ -#define I596_CB_STATUS_OK 0x2000 /* Command complete, no errors */ -#define I596_CB_STATUS_A 0x1000 /* Command busy executing */ - -#define I596_CB_NOLINK ((I596_CB *) 0xffffffff) - -/* - * I596_CB_NOP: NOP Command (p. 4-34) - */ -typedef volatile struct -{ - ushort status; - ushort cmd; - union _I596_CB *next; -} I596_CB_NOP; - -/* - * Same as above, but command and status in one ulong for speed - */ -typedef volatile struct -{ - ulong csr; - union _I596_CB *next; -} I596_CB_FAST; -#define FASTs(X) (X) -#define FASTc(X) ((X)<<16) - -/* - * I596_CB_IA: Individual (MAC) Address Command (p. 4-35) - */ -typedef volatile struct -{ - ushort status; - ushort cmd; - union _I596_CB *next; - uchar addr[6]; -} I596_CB_IA; - -/* - * I596_CB_CONF: Configure Command (p. 4-37) - */ -typedef volatile struct -{ - ushort status; - ushort cmd; - union _I596_CB *next; - uchar conf[14]; -} I596_CB_CONF; - -#define I596_CONF0_P 0x80 /* Enable RBD Prefetch Bit */ -#define I596_CONF0_COUNT 14 /* Count of configuration bytes */ - -#define I596_CONF1_MON_OFF 0xC0 /* Monitor mode: Monitor off */ -#define I596_CONF1_MON_ON 0x80 /* Monitor mode: Monitor on */ -#define I596_CONF1_TxFIFO(W) (W) /* TxFIFO trigger, in words */ - -#define I596_CONF2_SAVEBF 0x80 /* Save bad frames */ - -#define I596_CONF3_ADDRLEN(B) (B) /* Address length */ -#define I596_CONF3_NOSRCINSERT 0x08 /* Do not insert source address */ -#define I596_CONF3_PREAMBLE8 0x20 /* 8 byte preamble */ -#define I596_CONF3_LOOPOFF 0x00 /* Loopback: Off */ -#define I596_CONF3_LOOPINT 0x40 /* Loopback: internal */ -#define I596_CONF3_LOOPEXT 0xC0 /* Loopback: external */ - -#define I596_CONF4_LINPRI(ST) (ST) /* Linear priority: slot times */ -#define I596_CONF4_EXPPRI(ST) (ST) /* Exponential priority: slot times */ -#define I596_CONF4_IEEE_BOM 0 /* IEEE 802.3 backoff method */ - -#define I596_CONF5_IFS(X) (X) /* Interframe spacing in clocks */ - -#define I596_CONF6_ST_LOW(X) (X&255) /* Slot time, low byte */ - -#define I596_CONF7_ST_HI(X) (X>>8) /* Slot time, high bits */ -#define I596_CONF7_RETRY(X) (X<<4) /* Max retry number */ - -#define I596_CONF8_PROMISC 0x01 /* Rcv all frames */ -#define I596_CONF8_NOBROAD 0x02 -#define I596_CONF8_MANCHESTER 0x04 -#define I596_CONF8_TxNOCRS 0x08 -#define I596_CONF8_NOCRC 0x10 -#define I596_CONF8_CRC_CCITT 0x20 -#define I596_CONF8_BITSTUFFING 0x40 -#define I596_CONF8_PADDING 0x80 - -#define I596_CONF9_CSFILTER(X) (X) -#define I596_CONF9_CSINT(X) 0x08 -#define I596_CONF9_CDFILTER(X) (X<<4) -#define I596_CONF9_CDINT(X) 0x80 - -#define I596_CONF10_MINLEN(X) (X) /* Minimum frame length */ - -#define I596_CONF11_PRECRS_ 0x01 /* Preamble before carrier sense */ -#define I596_CONF11_LNGFLD_ 0x02 /* Padding in End of Carrier */ -#define I596_CONF11_CRCINM_ 0x04 /* CRC in memory */ -#define I596_CONF11_AUTOTX 0x08 /* Auto retransmit */ -#define I596_CONF11_CSBSAC_ 0x10 /* Collision detect by src addr cmp. */ -#define I596_CONF11_MCALL_ 0x20 /* Multicast all */ - -#define I596_CONF13_RESERVED 0x3f /* Reserved: must be ones */ -#define I596_CONF13_MULTIA 0x40 /* Enable multiple addr. reception */ -#define I596_CONF13_DISBOF 0x80 /* Disable backoff algorithm */ -/* - * I596_CB_MCAST: Multicast-Setup Command (p. 4-54) - */ -typedef volatile struct -{ - ushort status; - ushort cmd; - union _I596_CB *next; - ushort count; /* Number of 6-byte addrs that follow */ - uchar addr[6][1]; -} I596_CB_MCAST; - -/* - * I596_CB_XMIT: Transmit Command (p. 4-56) - */ -typedef I596_TFD I596_CB_XMIT; - -#define I596_CB_XMIT_NOCRC 0x0010 /* cmd: No CRC insertion */ -#define I596_CB_XMIT_FLEX 0x0008 /* cmd: Flexible memory mode */ - -#define I596_CB_XMIT_ERR_LATE 0x0800 /* status: error: late collision */ -#define I596_CB_XMIT_ERR_NOCRS 0x0400 /* status: error: no carriers sense */ -#define I596_CB_XMIT_ERR_NOCTS 0x0200 /* status: error: loss of CTS */ -#define I596_CB_XMIT_ERR_UNDER 0x0100 /* status: error: DMA underrun */ -#define I596_CB_XMIT_ERR_MAXCOL 0x0020 /* status: error: maximum collisions */ -#define I596_CB_XMIT_COLLISIONS 0x000f /* status: number of collisions */ - -/* - * I596_CB_TDR: Time Domain Reflectometry Command (p. 4-63) - */ -typedef volatile struct -{ - ushort status; - ushort cmd; - union _I596_CB *next; - ushort time; -} I596_CB_TDR; - -/* - * I596_CB_DUMP: Dump Command (p. 4-65) - */ -typedef volatile struct -{ - ushort status; - ushort cmd; - union _I596_CB *next; - uchar *buf; -} I596_CB_DUMP; - -/* - * I596_CB_DIAG: Diagnose Command (p. 4-77) - */ -typedef volatile struct -{ - ushort status; - ushort cmd; - union _I596_CB *next; -} I596_CB_DIAG; - -/* - * I596_CB: Command Block - */ -typedef union _I596_CB -{ - I596_CB_NOP nop; - I596_CB_IA ia; - I596_CB_CONF conf; - I596_CB_MCAST mcast; - I596_CB_XMIT xmit; - I596_CB_TDR tdr; - I596_CB_DUMP dump; - I596_CB_DIAG diag; - - /* command and status in one ulong for speed... */ - I596_CB_FAST fast; -} I596_CB; - -/************************************************************************/ -/* */ -/* I596_SCB: System Configuration Block (p. 4-26) */ -/* */ -/************************************************************************/ -typedef volatile struct -{ - volatile ushort status; /* Status word */ - volatile ushort cmd; /* Command word */ - I596_CB *cbp; - I596_RFD *rfdp; - ulong crc_errs; - ulong align_errs; - ulong resource_errs; - ulong overrun_errs; - ulong rcvcdt_errs; - ulong short_errs; - ushort toff; - ushort ton; -} I596_SCB; - - /* cmd halfword values */ -#define I596_SCB_ACK 0xF000 /* ACKNOWLEDGMENTS */ -#define I596_SCB_ACK_CX 0x8000 /* Ack command completion */ -#define I596_SCB_ACK_FR 0x4000 /* Ack received frame */ -#define I596_SCB_ACK_CNA 0x2000 /* Ack command unit not active */ -#define I596_SCB_ACK_RNR 0x1000 /* Ack rcv unit not ready */ -#define I596_SCB_ACK_ALL 0xF000 /* Ack everything */ - -#define I596_SCB_CUC 0x0700 /* COMMAND UNIT COMMANDS */ -#define I596_SCB_CUC_NOP 0x0000 /* No operation */ -#define I596_SCB_CUC_START 0x0100 /* Start execution of first CB */ -#define I596_SCB_CUC_RESUME 0x0200 /* Resume execution */ -#define I596_SCB_CUC_SUSPEND 0x0300 /* Suspend after current CB */ -#define I596_SCB_CUC_ABORT 0x0400 /* Abort current CB immediately */ -#define I596_SCB_CUC_LOAD 0x0500 /* Load Bus throttle timers */ -#define I596_SCB_CUC_LOADIMM 0x0600 /* Load Bus throttle timers, now */ - -#define I596_SCB_RUC 0x0070 /* RECEIVE UNIT COMMANDS */ -#define I596_SCB_RUC_NOP 0x0000 /* No operation */ -#define I596_SCB_RUC_START 0x0010 /* Start reception */ -#define I596_SCB_RUC_RESUME 0x0020 /* Resume reception */ -#define I596_SCB_RUC_SUSPEND 0x0030 /* Suspend reception */ -#define I596_SCB_RUC_ABORT 0x0040 /* Abort reception */ - -#define I596_SCB_RESET 0x0080 /* Hard reset chip */ - - /* status halfword values */ -#define I596_SCB_STAT 0xF000 /* STATUS */ -#define I596_SCB_CX 0x8000 /* command completion */ -#define I596_SCB_FR 0x4000 /* received frame */ -#define I596_SCB_CNA 0x2000 /* command unit not active */ -#define I596_SCB_RNR 0x1000 /* rcv unit not ready */ - -#define I596_SCB_CUS 0x0700 /* COMMAND UNIT STATUS */ -#define I596_SCB_CUS_IDLE 0x0000 /* Idle */ -#define I596_SCB_CUS_SUSPENDED 0x0100 /* Suspended */ -#define I596_SCB_CUS_ACTIVE 0x0200 /* Active */ - -#define I596_SCB_RUS 0x00F0 /* RECEIVE UNIT STATUS */ -#define I596_SCB_RUS_IDLE 0x0000 /* Idle */ -#define I596_SCB_RUS_SUSPENDED 0x0010 /* Suspended */ -#define I596_SCB_RUS_NORES 0x0020 /* No Resources */ -#define I596_SCB_RUS_READY 0x0040 /* Ready */ -#define I596_SCB_RUS_NORBDS 0x0080 /* No more RBDs modifier */ - -#define I596_SCB_LOADED 0x0008 /* Bus timers loaded */ - -/************************************************************************/ -/* */ -/* I596_ISCP: Intermediate System Configuration Ptr (p 4-26) */ -/* */ -/************************************************************************/ -typedef volatile struct -{ - ulong busy; /* Set to 1; I596 clears it when scbp is read */ - I596_SCB *scbp; -} I596_ISCP; - -/************************************************************************/ -/* */ -/* I596_SCP: System Configuration Pointer (p. 4-23) */ -/* */ -/************************************************************************/ -typedef volatile struct -{ - ulong sysbus; - ulong dummy; - I596_ISCP *iscpp; -} I596_SCP; - - /* .sysbus values */ -#define I596_SCP_RESERVED 0x400000 /* Reserved bits must be set */ -#define I596_SCP_INTLOW 0x200000 /* Intr. Polarity active low */ -#define I596_SCP_INTHIGH 0 /* Intr. Polarity active high */ -#define I596_SCP_LOCKDIS 0x100000 /* Lock Function disabled */ -#define I596_SCP_LOCKEN 0 /* Lock Function enabled */ -#define I596_SCP_ETHROTTLE 0x080000 /* External Bus Throttle */ -#define I596_SCP_ITHROTTLE 0 /* Internal Bus Throttle */ -#define I596_SCP_LINEAR 0x040000 /* Linear Mode */ -#define I596_SCP_SEGMENTED 0x020000 /* Segmented Mode */ -#define I596_SCP_82586 0x000000 /* 82586 Mode */ diff --git a/drivers/net/dgrs_plx9060.h b/drivers/net/dgrs_plx9060.h deleted file mode 100644 index 6888ae0d0ce..00000000000 --- a/drivers/net/dgrs_plx9060.h +++ /dev/null @@ -1,175 +0,0 @@ -/* - * PLX 9060 PCI Interface chip - */ - -/* - * PCI configuration registers, same offset on local and PCI sides, - * but on PCI side, must use PCI BIOS calls to read/write. - */ -#define PCI_PLXREGS_BASE_ADDR 0x10 - -#define PCI_PLXREGS_IO_ADDR 0x14 - -#define PCI_SPACE0_BASE_ADDR 0x18 - -#define PCI_ROM_BASE_ADDR 0x30 -# define PCI_ROM_ENABLED 0x00000001 - -#define PCI_INT_LINE 0x3C - -/* - * Registers accessible directly from PCI and local side. - * Offset is from PCI side. Add PLX_LCL_OFFSET for local address. - */ -#define PLX_LCL_OFFSET 0x80 /* Offset of regs from local side */ - -/* - * Local Configuration Registers - */ -#define PLX_SPACE0_RANGE 0x00 /* Range for PCI to Lcl Addr Space 0 */ -#define PLX_SPACE0_BASE_ADDR 0x04 /* Lcl Base address remap */ - -#define PLX_ROM_RANGE 0x10 /* Range for expansion ROM (DMA) */ -#define PLX_ROM_BASE_ADDR 0x14 /* Lcl base address remap for ROM */ - -#define PLX_BUS_REGION 0x18 /* Bus Region Descriptors */ - -/* - * Shared Run Time Registers - */ -#define PLX_MBOX0 0x40 -#define PLX_MBOX1 0x44 -#define PLX_MBOX2 0x48 -#define PLX_MBOX3 0x4C -#define PLX_MBOX4 0x50 -#define PLX_MBOX5 0x54 -#define PLX_MBOX6 0x58 -#define PLX_MBOX7 0x5C - -#define PLX_PCI2LCL_DOORBELL 0x60 - -#define PLX_LCL2PCI_DOORBELL 0x64 - -#define PLX_INT_CSR 0x68 /* Interrupt Control/Status */ -# define PLX_LSERR_ENABLE 0x00000001 -# define PLX_LSERR_PE 0x00000002 -# define PLX_SERR 0x00000004 -# undef PLX_UNUSED /* 0x00000008 */ -# undef PLX_UNUSED /* 0x00000010 */ -# undef PLX_UNUSED /* 0x00000020 */ -# undef PLX_UNUSED /* 0x00000040 */ -# undef PLX_UNUSED /* 0x00000080 */ -# define PLX_PCI_IE 0x00000100 -# define PLX_PCI_DOORBELL_IE 0x00000200 -# define PLX_PCI_ABORT_IE 0x00000400 -# define PLX_PCI_LOCAL_IE 0x00000800 -# define PLX_RETRY_ABORT_ENABLE 0x00001000 -# define PLX_PCI_DOORBELL_INT 0x00002000 -# define PLX_PCI_ABORT_INT 0x00004000 -# define PLX_PCI_LOCAL_INT 0x00008000 -# define PLX_LCL_IE 0x00010000 -# define PLX_LCL_DOORBELL_IE 0x00020000 -# define PLX_LCL_DMA0_IE 0x00040000 -# define PLX_LCL_DMA1_IE 0x00080000 -# define PLX_LCL_DOORBELL_INT 0x00100000 -# define PLX_LCL_DMA0_INT 0x00200000 -# define PLX_LCL_DMA1_INT 0x00400000 -# define PLX_LCL_BIST_INT 0x00800000 -# define PLX_BM_DIRECT_ 0x01000000 -# define PLX_BM_DMA0_ 0x02000000 -# define PLX_BM_DMA1_ 0x04000000 -# define PLX_BM_ABORT_ 0x08000000 -# undef PLX_UNUSED /* 0x10000000 */ -# undef PLX_UNUSED /* 0x20000000 */ -# undef PLX_UNUSED /* 0x40000000 */ -# undef PLX_UNUSED /* 0x80000000 */ - -#define PLX_MISC_CSR 0x6c /* EEPROM,PCI,User,Init Control/Status*/ -# define PLX_USEROUT 0x00010000 -# define PLX_USERIN 0x00020000 -# define PLX_EECK 0x01000000 -# define PLX_EECS 0x02000000 -# define PLX_EEWD 0x04000000 -# define PLX_EERD 0x08000000 - -/* - * DMA registers. Offset is from local side - */ -#define PLX_DMA0_MODE 0x100 -# define PLX_DMA_MODE_WIDTH32 0x00000003 -# define PLX_DMA_MODE_WAITSTATES(X) ((X)<<2) -# define PLX_DMA_MODE_NOREADY 0x00000000 -# define PLX_DMA_MODE_READY 0x00000040 -# define PLX_DMA_MODE_NOBTERM 0x00000000 -# define PLX_DMA_MODE_BTERM 0x00000080 -# define PLX_DMA_MODE_NOBURST 0x00000000 -# define PLX_DMA_MODE_BURST 0x00000100 -# define PLX_DMA_MODE_NOCHAIN 0x00000000 -# define PLX_DMA_MODE_CHAIN 0x00000200 -# define PLX_DMA_MODE_DONE_IE 0x00000400 -# define PLX_DMA_MODE_ADDR_HOLD 0x00000800 - -#define PLX_DMA0_PCI_ADDR 0x104 - /* non-chaining mode PCI address */ - -#define PLX_DMA0_LCL_ADDR 0x108 - /* non-chaining mode local address */ - -#define PLX_DMA0_SIZE 0x10C - /* non-chaining mode length */ - -#define PLX_DMA0_DESCRIPTOR 0x110 -# define PLX_DMA_DESC_EOC 0x00000002 -# define PLX_DMA_DESC_TC_IE 0x00000004 -# define PLX_DMA_DESC_TO_HOST 0x00000008 -# define PLX_DMA_DESC_TO_BOARD 0x00000000 -# define PLX_DMA_DESC_NEXTADDR 0xFFFFfff0 - -#define PLX_DMA1_MODE 0x114 -#define PLX_DMA1_PCI_ADDR 0x118 -#define PLX_DMA1_LCL_ADDR 0x11C -#define PLX_DMA1_SIZE 0x110 -#define PLX_DMA1_DESCRIPTOR 0x124 - -#define PLX_DMA_CSR 0x128 -# define PLX_DMA_CSR_0_ENABLE 0x00000001 -# define PLX_DMA_CSR_0_START 0x00000002 -# define PLX_DMA_CSR_0_ABORT 0x00000004 -# define PLX_DMA_CSR_0_CLR_INTR 0x00000008 -# define PLX_DMA_CSR_0_DONE 0x00000010 -# define PLX_DMA_CSR_1_ENABLE 0x00000100 -# define PLX_DMA_CSR_1_START 0x00000200 -# define PLX_DMA_CSR_1_ABORT 0x00000400 -# define PLX_DMA_CSR_1_CLR_INTR 0x00000800 -# define PLX_DMA_CSR_1_DONE 0x00001000 - -#define PLX_DMA_ARB0 0x12C -# define PLX_DMA_ARB0_LATENCY_T 0x000000FF -# define PLX_DMA_ARB0_PAUSE_T 0x0000FF00 -# define PLX_DMA_ARB0_LATENCY_EN 0x00010000 -# define PLX_DMA_ARB0_PAUSE_EN 0x00020000 -# define PLX_DMA_ARB0_BREQ_EN 0x00040000 -# define PLX_DMA_ARB0_PRI 0x00180000 -# define PLX_DMA_ARB0_PRI_ROUND 0x00000000 -# define PLX_DMA_ARB0_PRI_0 0x00080000 -# define PLX_DMA_ARB0_PRI_1 0x00100000 - -#define PLX_DMA_ARB1 0x130 - /* Chan 0: FIFO DEPTH=16 */ -# define PLX_DMA_ARB1_0_P2L_LW_TRIG(X) ( ((X)&15) << 0 ) -# define PLX_DMA_ARB1_0_L2P_LR_TRIG(X) ( ((X)&15) << 4 ) -# define PLX_DMA_ARB1_0_L2P_PW_TRIG(X) ( ((X)&15) << 8 ) -# define PLX_DMA_ARB1_0_P2L_PR_TRIG(X) ( ((X)&15) << 12 ) - /* Chan 1: FIFO DEPTH=8 */ -# define PLX_DMA_ARB1_1_P2L_LW_TRIG(X) ( ((X)& 7) << 16 ) -# define PLX_DMA_ARB1_1_L2P_LR_TRIG(X) ( ((X)& 7) << 20 ) -# define PLX_DMA_ARB1_1_L2P_PW_TRIG(X) ( ((X)& 7) << 24 ) -# define PLX_DMA_ARB1_1_P2L_PR_TRIG(X) ( ((X)& 7) << 28 ) - -typedef struct _dmachain -{ - ulong pciaddr; - ulong lcladdr; - ulong len; - ulong next; -} DMACHAIN; -- cgit v1.2.3-70-g09d2 From 7a1f8104c4a477feaf8b4405429119276341a27e Mon Sep 17 00:00:00 2001 From: Roy Zang Date: Mon, 24 Sep 2007 16:57:42 +0800 Subject: Clean up redundant PHY write line for ULi526x Ethernet driver Clean up redundant PHY write line for ULi526x Ethernet Driver. Signed-off-by: Roy Zang Signed-off-by: Jeff Garzik --- drivers/net/tulip/uli526x.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c index 53c7523960c..e64bde46822 100644 --- a/drivers/net/tulip/uli526x.c +++ b/drivers/net/tulip/uli526x.c @@ -1604,7 +1604,6 @@ static void uli526x_process_mode(struct uli526x_board_info *db) case ULI526X_100MFD: phy_reg = 0x2100; break; } phy_write(db->ioaddr, db->phy_addr, 0, phy_reg, db->chip_id); - phy_write(db->ioaddr, db->phy_addr, 0, phy_reg, db->chip_id); } } } -- cgit v1.2.3-70-g09d2 From 7b5dfe1aa9faf9fab10960e027a7b1c932580f76 Mon Sep 17 00:00:00 2001 From: Krishna Kumar Date: Fri, 21 Sep 2007 09:41:15 -0700 Subject: e1000e: Do not allow requeue of freed skb Returning BUSY will make qdisc_restart enqueue the skb which was already freed. The bad skb was correctly freed and we should return NETDEV_TX_OK. First spotted by Jeff Garzik on 08/13/07. Signed-off-by: Krishna Kumar Signed-off-by: Auke Kok Signed-off-by: Jeff Garzik --- drivers/net/e1000e/netdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 885d9467f40..4a21d7df174 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -3531,7 +3531,7 @@ static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) /* handle pci_map_single() error in e1000_tx_map */ dev_kfree_skb_any(skb); spin_unlock_irqrestore(&adapter->tx_queue_lock, irq_flags); - return NETDEV_TX_BUSY; + return NETDEV_TX_OK; } e1000_tx_queue(adapter, tx_flags, count); -- cgit v1.2.3-70-g09d2 From ac1d49f8431bef861c7dd63e78be25e4c262eb52 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Sat, 29 Sep 2007 01:10:14 -0400 Subject: [netdrvr] sundance: fix phy scanning on IP100A Based on a based from Jesse Huang . Signed-off-by: Jeff Garzik --- drivers/net/sundance.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index a37637ec9b7..ff98f5d597f 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -466,7 +466,7 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, #else int bar = 1; #endif - int phy, phy_idx = 0; + int phy, phy_end, phy_idx = 0; DECLARE_MAC_BUF(mac); /* when built into the kernel, we only print version if device is found */ @@ -552,11 +552,19 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, np->phys[0] = 1; /* Default setting */ np->mii_preamble_required++; + /* * It seems some phys doesn't deal well with address 0 being accessed - * first, so leave address zero to the end of the loop (32 & 31). + * first */ - for (phy = 1; phy <= 32 && phy_idx < MII_CNT; phy++) { + if (sundance_pci_tbl[np->chip_id].device == 0x0200) { + phy = 0; + phy_end = 31; + } else { + phy = 1; + phy_end = 32; /* wraps to zero, due to 'phy & 0x1f' */ + } + for (; phy <= phy_end && phy_idx < MII_CNT; phy++) { int phyx = phy & 0x1f; int mii_status = mdio_read(dev, phyx, MII_BMSR); if (mii_status != 0xffff && mii_status != 0x0000) { -- cgit v1.2.3-70-g09d2 From 73d7396980176a5f4515be2f6e39ee417d2369ba Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Thu, 20 Sep 2007 19:14:01 +0100 Subject: sb1250-mac.c: De-typedef, de-volatile, de-etc... Remove typedefs, volatiles and convert kmalloc()/memset() pairs to kcalloc(). Also reformat the surrounding clutter. Signed-off-by: Maciej W. Rozycki Signed-off-by: Jeff Garzik --- drivers/net/sb1250-mac.c | 278 ++++++++++++++++++++++++----------------------- 1 file changed, 142 insertions(+), 136 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index 6001ab47fba..0cffd46724d 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -140,17 +140,17 @@ MODULE_PARM_DESC(int_timeout_rx, "RX timeout value"); ********************************************************************* */ -typedef enum { sbmac_speed_auto, sbmac_speed_10, - sbmac_speed_100, sbmac_speed_1000 } sbmac_speed_t; +enum sbmac_speed { sbmac_speed_auto, sbmac_speed_10, + sbmac_speed_100, sbmac_speed_1000 }; -typedef enum { sbmac_duplex_auto, sbmac_duplex_half, - sbmac_duplex_full } sbmac_duplex_t; +enum sbmac_duplex { sbmac_duplex_auto, sbmac_duplex_half, + sbmac_duplex_full }; -typedef enum { sbmac_fc_auto, sbmac_fc_disabled, sbmac_fc_frame, - sbmac_fc_collision, sbmac_fc_carrier } sbmac_fc_t; +enum sbmac_fc { sbmac_fc_auto, sbmac_fc_disabled, sbmac_fc_frame, + sbmac_fc_collision, sbmac_fc_carrier } sbmac_fc_t; -typedef enum { sbmac_state_uninit, sbmac_state_off, sbmac_state_on, - sbmac_state_broken } sbmac_state_t; +enum sbmac_state { sbmac_state_uninit, sbmac_state_off, sbmac_state_on, + sbmac_state_broken }; /********************************************************************** @@ -176,55 +176,61 @@ typedef enum { sbmac_state_uninit, sbmac_state_off, sbmac_state_on, * DMA Descriptor structure ********************************************************************* */ -typedef struct sbdmadscr_s { +struct sbdmadscr { uint64_t dscr_a; uint64_t dscr_b; -} sbdmadscr_t; - -typedef unsigned long paddr_t; +}; /********************************************************************** * DMA Controller structure ********************************************************************* */ -typedef struct sbmacdma_s { +struct sbmacdma { /* * This stuff is used to identify the channel and the registers * associated with it. */ - - struct sbmac_softc *sbdma_eth; /* back pointer to associated MAC */ - int sbdma_channel; /* channel number */ - int sbdma_txdir; /* direction (1=transmit) */ - int sbdma_maxdescr; /* total # of descriptors in ring */ + struct sbmac_softc *sbdma_eth; /* back pointer to associated + MAC */ + int sbdma_channel; /* channel number */ + int sbdma_txdir; /* direction (1=transmit) */ + int sbdma_maxdescr; /* total # of descriptors + in ring */ #ifdef CONFIG_SBMAC_COALESCE - int sbdma_int_pktcnt; /* # descriptors rx/tx before interrupt*/ - int sbdma_int_timeout; /* # usec rx/tx interrupt */ + int sbdma_int_pktcnt; + /* # descriptors rx/tx + before interrupt */ + int sbdma_int_timeout; + /* # usec rx/tx interrupt */ #endif - - volatile void __iomem *sbdma_config0; /* DMA config register 0 */ - volatile void __iomem *sbdma_config1; /* DMA config register 1 */ - volatile void __iomem *sbdma_dscrbase; /* Descriptor base address */ - volatile void __iomem *sbdma_dscrcnt; /* Descriptor count register */ - volatile void __iomem *sbdma_curdscr; /* current descriptor address */ - volatile void __iomem *sbdma_oodpktlost;/* pkt drop (rx only) */ - + void __iomem *sbdma_config0; /* DMA config register 0 */ + void __iomem *sbdma_config1; /* DMA config register 1 */ + void __iomem *sbdma_dscrbase; + /* descriptor base address */ + void __iomem *sbdma_dscrcnt; /* descriptor count register */ + void __iomem *sbdma_curdscr; /* current descriptor + address */ + void __iomem *sbdma_oodpktlost; + /* pkt drop (rx only) */ /* * This stuff is for maintenance of the ring */ - - sbdmadscr_t *sbdma_dscrtable_unaligned; - sbdmadscr_t *sbdma_dscrtable; /* base of descriptor table */ - sbdmadscr_t *sbdma_dscrtable_end; /* end of descriptor table */ - - struct sk_buff **sbdma_ctxtable; /* context table, one per descr */ - - paddr_t sbdma_dscrtable_phys; /* and also the phys addr */ - sbdmadscr_t *sbdma_addptr; /* next dscr for sw to add */ - sbdmadscr_t *sbdma_remptr; /* next dscr for sw to remove */ -} sbmacdma_t; + void *sbdma_dscrtable_unaligned; + struct sbdmadscr *sbdma_dscrtable; + /* base of descriptor table */ + struct sbdmadscr *sbdma_dscrtable_end; + /* end of descriptor table */ + struct sk_buff **sbdma_ctxtable; + /* context table, one + per descr */ + dma_addr_t sbdma_dscrtable_phys; + /* and also the phys addr */ + struct sbdmadscr *sbdma_addptr; /* next dscr for sw to add */ + struct sbdmadscr *sbdma_remptr; /* next dscr for sw + to remove */ +}; /********************************************************************** @@ -236,47 +242,45 @@ struct sbmac_softc { /* * Linux-specific things */ + struct net_device *sbm_dev; /* pointer to linux device */ + struct napi_struct napi; + spinlock_t sbm_lock; /* spin lock */ + struct timer_list sbm_timer; /* for monitoring MII */ + int sbm_devflags; /* current device flags */ - struct net_device *sbm_dev; /* pointer to linux device */ - struct napi_struct napi; - spinlock_t sbm_lock; /* spin lock */ - struct timer_list sbm_timer; /* for monitoring MII */ - int sbm_devflags; /* current device flags */ - - int sbm_phy_oldbmsr; - int sbm_phy_oldanlpar; - int sbm_phy_oldk1stsr; - int sbm_phy_oldlinkstat; - int sbm_buffersize; + int sbm_phy_oldbmsr; + int sbm_phy_oldanlpar; + int sbm_phy_oldk1stsr; + int sbm_phy_oldlinkstat; + int sbm_buffersize; - unsigned char sbm_phys[2]; + unsigned char sbm_phys[2]; /* * Controller-specific things */ + void __iomem *sbm_base; /* MAC's base address */ + enum sbmac_state sbm_state; /* current state */ - void __iomem *sbm_base; /* MAC's base address */ - sbmac_state_t sbm_state; /* current state */ + void __iomem *sbm_macenable; /* MAC Enable Register */ + void __iomem *sbm_maccfg; /* MAC Config Register */ + void __iomem *sbm_fifocfg; /* FIFO Config Register */ + void __iomem *sbm_framecfg; /* Frame Config Register */ + void __iomem *sbm_rxfilter; /* Receive Filter Register */ + void __iomem *sbm_isr; /* Interrupt Status Register */ + void __iomem *sbm_imr; /* Interrupt Mask Register */ + void __iomem *sbm_mdio; /* MDIO Register */ - volatile void __iomem *sbm_macenable; /* MAC Enable Register */ - volatile void __iomem *sbm_maccfg; /* MAC Configuration Register */ - volatile void __iomem *sbm_fifocfg; /* FIFO configuration register */ - volatile void __iomem *sbm_framecfg; /* Frame configuration register */ - volatile void __iomem *sbm_rxfilter; /* receive filter register */ - volatile void __iomem *sbm_isr; /* Interrupt status register */ - volatile void __iomem *sbm_imr; /* Interrupt mask register */ - volatile void __iomem *sbm_mdio; /* MDIO register */ + enum sbmac_speed sbm_speed; /* current speed */ + enum sbmac_duplex sbm_duplex; /* current duplex */ + enum sbmac_fc sbm_fc; /* cur. flow control setting */ - sbmac_speed_t sbm_speed; /* current speed */ - sbmac_duplex_t sbm_duplex; /* current duplex */ - sbmac_fc_t sbm_fc; /* current flow control setting */ + unsigned char sbm_hwaddr[ETHER_ADDR_LEN]; - unsigned char sbm_hwaddr[ETHER_ADDR_LEN]; - - sbmacdma_t sbm_txdma; /* for now, only use channel 0 */ - sbmacdma_t sbm_rxdma; - int rx_hw_checksum; - int sbe_idx; + struct sbmacdma sbm_txdma; /* only channel 0 for now */ + struct sbmacdma sbm_rxdma; + int rx_hw_checksum; + int sbe_idx; }; @@ -288,30 +292,31 @@ struct sbmac_softc { * Prototypes ********************************************************************* */ -static void sbdma_initctx(sbmacdma_t *d, - struct sbmac_softc *s, - int chan, - int txrx, - int maxdescr); -static void sbdma_channel_start(sbmacdma_t *d, int rxtx); -static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *m); -static int sbdma_add_txbuffer(sbmacdma_t *d,struct sk_buff *m); -static void sbdma_emptyring(sbmacdma_t *d); -static void sbdma_fillring(sbmacdma_t *d); -static int sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d, int work_to_do, int poll); -static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d, int poll); +static void sbdma_initctx(struct sbmacdma *d, struct sbmac_softc *s, int chan, + int txrx, int maxdescr); +static void sbdma_channel_start(struct sbmacdma *d, int rxtx); +static int sbdma_add_rcvbuffer(struct sbmacdma *d, struct sk_buff *m); +static int sbdma_add_txbuffer(struct sbmacdma *d, struct sk_buff *m); +static void sbdma_emptyring(struct sbmacdma *d); +static void sbdma_fillring(struct sbmacdma *d); +static int sbdma_rx_process(struct sbmac_softc *sc, struct sbmacdma *d, + int work_to_do, int poll); +static void sbdma_tx_process(struct sbmac_softc *sc, struct sbmacdma *d, + int poll); static int sbmac_initctx(struct sbmac_softc *s); static void sbmac_channel_start(struct sbmac_softc *s); static void sbmac_channel_stop(struct sbmac_softc *s); -static sbmac_state_t sbmac_set_channel_state(struct sbmac_softc *,sbmac_state_t); -static void sbmac_promiscuous_mode(struct sbmac_softc *sc,int onoff); +static enum sbmac_state sbmac_set_channel_state(struct sbmac_softc *, + enum sbmac_state); +static void sbmac_promiscuous_mode(struct sbmac_softc *sc, int onoff); static uint64_t sbmac_addr2reg(unsigned char *ptr); -static irqreturn_t sbmac_intr(int irq,void *dev_instance); +static irqreturn_t sbmac_intr(int irq, void *dev_instance); static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev); static void sbmac_setmulti(struct sbmac_softc *sc); static int sbmac_init(struct net_device *dev, int idx); -static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed); -static int sbmac_set_duplex(struct sbmac_softc *s,sbmac_duplex_t duplex,sbmac_fc_t fc); +static int sbmac_set_speed(struct sbmac_softc *s, enum sbmac_speed speed); +static int sbmac_set_duplex(struct sbmac_softc *s, enum sbmac_duplex duplex, + enum sbmac_fc fc); static int sbmac_open(struct net_device *dev); static void sbmac_timer(unsigned long data); @@ -321,13 +326,15 @@ static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static int sbmac_close(struct net_device *dev); static int sbmac_poll(struct napi_struct *napi, int budget); -static int sbmac_mii_poll(struct sbmac_softc *s,int noisy); +static int sbmac_mii_poll(struct sbmac_softc *s, int noisy); static int sbmac_mii_probe(struct net_device *dev); static void sbmac_mii_sync(struct sbmac_softc *s); -static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitcnt); -static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx); -static void sbmac_mii_write(struct sbmac_softc *s,int phyaddr,int regidx, +static void sbmac_mii_senddata(struct sbmac_softc *s, unsigned int data, + int bitcnt); +static unsigned int sbmac_mii_read(struct sbmac_softc *s, int phyaddr, + int regidx); +static void sbmac_mii_write(struct sbmac_softc *s, int phyaddr, int regidx, unsigned int regval); @@ -676,8 +683,8 @@ static void sbmac_mii_write(struct sbmac_softc *s,int phyaddr,int regidx, * way. * * Input parameters: - * d - sbmacdma_t structure (DMA channel context) - * s - sbmac_softc structure (pointer to a MAC) + * d - struct sbmacdma (DMA channel context) + * s - struct sbmac_softc (pointer to a MAC) * chan - channel number (0..1 right now) * txrx - Identifies DMA_TX or DMA_RX for channel direction * maxdescr - number of descriptors @@ -686,11 +693,8 @@ static void sbmac_mii_write(struct sbmac_softc *s,int phyaddr,int regidx, * nothing ********************************************************************* */ -static void sbdma_initctx(sbmacdma_t *d, - struct sbmac_softc *s, - int chan, - int txrx, - int maxdescr) +static void sbdma_initctx(struct sbmacdma *d, struct sbmac_softc *s, int chan, + int txrx, int maxdescr) { #ifdef CONFIG_SBMAC_COALESCE int int_pktcnt, int_timeout; @@ -757,18 +761,17 @@ static void sbdma_initctx(sbmacdma_t *d, d->sbdma_maxdescr = maxdescr; - d->sbdma_dscrtable_unaligned = - d->sbdma_dscrtable = (sbdmadscr_t *) - kmalloc((d->sbdma_maxdescr+1)*sizeof(sbdmadscr_t), GFP_KERNEL); + d->sbdma_dscrtable_unaligned = kcalloc(d->sbdma_maxdescr + 1, + sizeof(*d->sbdma_dscrtable), + GFP_KERNEL); /* * The descriptor table must be aligned to at least 16 bytes or the * MAC will corrupt it. */ - d->sbdma_dscrtable = (sbdmadscr_t *) - ALIGN((unsigned long)d->sbdma_dscrtable, sizeof(sbdmadscr_t)); - - memset(d->sbdma_dscrtable,0,d->sbdma_maxdescr*sizeof(sbdmadscr_t)); + d->sbdma_dscrtable = (struct sbdmadscr *) + ALIGN((unsigned long)d->sbdma_dscrtable_unaligned, + sizeof(*d->sbdma_dscrtable)); d->sbdma_dscrtable_end = d->sbdma_dscrtable + d->sbdma_maxdescr; @@ -779,7 +782,7 @@ static void sbdma_initctx(sbmacdma_t *d, */ d->sbdma_ctxtable = kcalloc(d->sbdma_maxdescr, - sizeof(struct sk_buff *), GFP_KERNEL); + sizeof(*d->sbdma_ctxtable), GFP_KERNEL); #ifdef CONFIG_SBMAC_COALESCE /* @@ -816,7 +819,7 @@ static void sbdma_initctx(sbmacdma_t *d, * nothing ********************************************************************* */ -static void sbdma_channel_start(sbmacdma_t *d, int rxtx ) +static void sbdma_channel_start(struct sbmacdma *d, int rxtx) { /* * Turn on the DMA channel @@ -857,7 +860,7 @@ static void sbdma_channel_start(sbmacdma_t *d, int rxtx ) * nothing ********************************************************************* */ -static void sbdma_channel_stop(sbmacdma_t *d) +static void sbdma_channel_stop(struct sbmacdma *d) { /* * Turn off the DMA channel @@ -906,10 +909,10 @@ static void sbdma_align_skb(struct sk_buff *skb,int power2,int offset) ********************************************************************* */ -static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *sb) +static int sbdma_add_rcvbuffer(struct sbmacdma *d, struct sk_buff *sb) { - sbdmadscr_t *dsc; - sbdmadscr_t *nextdsc; + struct sbdmadscr *dsc; + struct sbdmadscr *nextdsc; struct sk_buff *sb_new = NULL; int pktsize = ENET_PACKET_SIZE; @@ -1021,10 +1024,10 @@ static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *sb) ********************************************************************* */ -static int sbdma_add_txbuffer(sbmacdma_t *d,struct sk_buff *sb) +static int sbdma_add_txbuffer(struct sbmacdma *d, struct sk_buff *sb) { - sbdmadscr_t *dsc; - sbdmadscr_t *nextdsc; + struct sbdmadscr *dsc; + struct sbdmadscr *nextdsc; uint64_t phys; uint64_t ncb; int length; @@ -1110,7 +1113,7 @@ static int sbdma_add_txbuffer(sbmacdma_t *d,struct sk_buff *sb) * nothing ********************************************************************* */ -static void sbdma_emptyring(sbmacdma_t *d) +static void sbdma_emptyring(struct sbmacdma *d) { int idx; struct sk_buff *sb; @@ -1138,7 +1141,7 @@ static void sbdma_emptyring(sbmacdma_t *d) * nothing ********************************************************************* */ -static void sbdma_fillring(sbmacdma_t *d) +static void sbdma_fillring(struct sbmacdma *d) { int idx; @@ -1185,13 +1188,13 @@ static void sbmac_netpoll(struct net_device *netdev) * nothing ********************************************************************* */ -static int sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d, - int work_to_do, int poll) +static int sbdma_rx_process(struct sbmac_softc *sc, struct sbmacdma *d, + int work_to_do, int poll) { struct net_device *dev = sc->sbm_dev; int curidx; int hwidx; - sbdmadscr_t *dsc; + struct sbdmadscr *dsc; struct sk_buff *sb; int len; int work_done = 0; @@ -1223,8 +1226,9 @@ again: prefetch(dsc); prefetch(&d->sbdma_ctxtable[curidx]); - hwidx = (int) (((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) - - d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t)); + hwidx = ((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) - + d->sbdma_dscrtable_phys) / + sizeof(*d->sbdma_dscrtable); /* * If they're the same, that means we've processed all @@ -1348,12 +1352,13 @@ done: * nothing ********************************************************************* */ -static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d, int poll) +static void sbdma_tx_process(struct sbmac_softc *sc, struct sbmacdma *d, + int poll) { struct net_device *dev = sc->sbm_dev; int curidx; int hwidx; - sbdmadscr_t *dsc; + struct sbdmadscr *dsc; struct sk_buff *sb; unsigned long flags; int packets_handled = 0; @@ -1363,8 +1368,8 @@ static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d, int poll) if (d->sbdma_remptr == d->sbdma_addptr) goto end_unlock; - hwidx = (int) (((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) - - d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t)); + hwidx = ((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) - + d->sbdma_dscrtable_phys) / sizeof(*d->sbdma_dscrtable); for (;;) { /* @@ -1501,7 +1506,7 @@ static int sbmac_initctx(struct sbmac_softc *s) } -static void sbdma_uninitctx(struct sbmacdma_s *d) +static void sbdma_uninitctx(struct sbmacdma *d) { if (d->sbdma_dscrtable_unaligned) { kfree(d->sbdma_dscrtable_unaligned); @@ -1537,7 +1542,7 @@ static void sbmac_uninitctx(struct sbmac_softc *sc) static void sbmac_channel_start(struct sbmac_softc *s) { uint64_t reg; - volatile void __iomem *port; + void __iomem *port; uint64_t cfg,fifo,framecfg; int idx, th_value; @@ -1800,10 +1805,10 @@ static void sbmac_channel_stop(struct sbmac_softc *s) * Return value: * old state ********************************************************************* */ -static sbmac_state_t sbmac_set_channel_state(struct sbmac_softc *sc, - sbmac_state_t state) +static enum sbmac_state sbmac_set_channel_state(struct sbmac_softc *sc, + enum sbmac_state state) { - sbmac_state_t oldstate = sc->sbm_state; + enum sbmac_state oldstate = sc->sbm_state; /* * If same as previous state, return @@ -1938,14 +1943,14 @@ static uint64_t sbmac_addr2reg(unsigned char *ptr) * * Input parameters: * s - sbmac structure - * speed - speed to set MAC to (see sbmac_speed_t enum) + * speed - speed to set MAC to (see enum sbmac_speed) * * Return value: * 1 if successful * 0 indicates invalid parameters ********************************************************************* */ -static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed) +static int sbmac_set_speed(struct sbmac_softc *s, enum sbmac_speed speed) { uint64_t cfg; uint64_t framecfg; @@ -2027,15 +2032,16 @@ static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed) * * Input parameters: * s - sbmac structure - * duplex - duplex setting (see sbmac_duplex_t) - * fc - flow control setting (see sbmac_fc_t) + * duplex - duplex setting (see enum sbmac_duplex) + * fc - flow control setting (see enum sbmac_fc) * * Return value: * 1 if ok * 0 if an invalid parameter combination was specified ********************************************************************* */ -static int sbmac_set_duplex(struct sbmac_softc *s,sbmac_duplex_t duplex,sbmac_fc_t fc) +static int sbmac_set_duplex(struct sbmac_softc *s, enum sbmac_duplex duplex, + enum sbmac_fc fc) { uint64_t cfg; @@ -2228,7 +2234,7 @@ static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev) static void sbmac_setmulti(struct sbmac_softc *sc) { uint64_t reg; - volatile void __iomem *port; + void __iomem *port; int idx; struct dev_mc_list *mclist; struct net_device *dev = sc->sbm_dev; -- cgit v1.2.3-70-g09d2 From f5279ffdce9bcff938451303126971098e23aab3 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Fri, 21 Sep 2007 12:52:10 +0100 Subject: sb1250-mac: Driver model & phylib update A driver model and phylib update. It includes the following changes: 1. Removal of unused module options. 2. Phylib support and the resulting removal of generic bits for handling the PHY. 3. Proper reserving of device resources and using ioremap()ped handles to access MAC registers rather than platform-specific macros. 4. Handling of the device using the driver model. Signed-off-by: Maciej W. Rozycki Signed-off-by: Jeff Garzik --- drivers/net/Kconfig | 1 + drivers/net/sb1250-mac.c | 1119 +++++++++++++++++++++------------------------- 2 files changed, 520 insertions(+), 600 deletions(-) (limited to 'drivers') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 764325917f6..9ff1cf46eae 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2111,6 +2111,7 @@ config R8169_VLAN config SB1250_MAC tristate "SB1250 Gigabit Ethernet support" depends on SIBYTE_SB1xxx_SOC + select PHYLIB ---help--- This driver supports Gigabit Ethernet interfaces based on the Broadcom SiByte family of System-On-a-Chip parts. They include diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index 0cffd46724d..7b53d658e33 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2001,2002,2003,2004 Broadcom Corporation + * Copyright (c) 2006, 2007 Maciej W. Rozycki * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -18,7 +19,12 @@ * * This driver is designed for the Broadcom SiByte SOC built-in * Ethernet controllers. Written by Mitch Lichtenberg at Broadcom Corp. + * + * Updated to the driver model and the PHY abstraction layer + * by Maciej W. Rozycki. */ + +#include #include #include #include @@ -32,9 +38,15 @@ #include #include #include -#include /* Processor type for cache alignment. */ -#include +#include +#include +#include +#include +#include + #include +#include +#include /* Processor type for cache alignment. */ /* This is only here until the firmware is ready. In that case, the firmware leaves the ethernet address in the register for us. */ @@ -48,7 +60,7 @@ /* These identify the driver base version and may not be removed. */ #if 0 -static char version1[] __devinitdata = +static char version1[] __initdata = "sb1250-mac.c:1.00 1/11/2001 Written by Mitch Lichtenberg\n"; #endif @@ -57,8 +69,6 @@ static char version1[] __devinitdata = #define CONFIG_SBMAC_COALESCE -#define MAX_UNITS 4 /* More are supported, limit only on options */ - /* Time in jiffies before concluding the transmitter is hung. */ #define TX_TIMEOUT (2*HZ) @@ -74,26 +84,6 @@ static int debug = 1; module_param(debug, int, S_IRUGO); MODULE_PARM_DESC(debug, "Debug messages"); -/* mii status msgs */ -static int noisy_mii = 1; -module_param(noisy_mii, int, S_IRUGO); -MODULE_PARM_DESC(noisy_mii, "MII status messages"); - -/* Used to pass the media type, etc. - Both 'options[]' and 'full_duplex[]' should exist for driver - interoperability. - The media type is usually passed in 'options[]'. -*/ -#ifdef MODULE -static int options[MAX_UNITS] = {-1, -1, -1, -1}; -module_param_array(options, int, NULL, S_IRUGO); -MODULE_PARM_DESC(options, "1-" __MODULE_STRING(MAX_UNITS)); - -static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1}; -module_param_array(full_duplex, int, NULL, S_IRUGO); -MODULE_PARM_DESC(full_duplex, "1-" __MODULE_STRING(MAX_UNITS)); -#endif - #ifdef CONFIG_SBMAC_COALESCE static int int_pktcnt_tx = 255; module_param(int_pktcnt_tx, int, S_IRUGO); @@ -112,6 +102,7 @@ module_param(int_timeout_rx, int, S_IRUGO); MODULE_PARM_DESC(int_timeout_rx, "RX timeout value"); #endif +#include #include #if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80) #include @@ -135,22 +126,43 @@ MODULE_PARM_DESC(int_timeout_rx, "RX timeout value"); #error invalid SiByte MAC configuation #endif +#ifdef K_INT_PHY +#define SBMAC_PHY_INT K_INT_PHY +#else +#define SBMAC_PHY_INT PHY_POLL +#endif + /********************************************************************** * Simple types ********************************************************************* */ +enum sbmac_speed { + sbmac_speed_none = 0, + sbmac_speed_10 = SPEED_10, + sbmac_speed_100 = SPEED_100, + sbmac_speed_1000 = SPEED_1000, +}; -enum sbmac_speed { sbmac_speed_auto, sbmac_speed_10, - sbmac_speed_100, sbmac_speed_1000 }; - -enum sbmac_duplex { sbmac_duplex_auto, sbmac_duplex_half, - sbmac_duplex_full }; +enum sbmac_duplex { + sbmac_duplex_none = -1, + sbmac_duplex_half = DUPLEX_HALF, + sbmac_duplex_full = DUPLEX_FULL, +}; -enum sbmac_fc { sbmac_fc_auto, sbmac_fc_disabled, sbmac_fc_frame, - sbmac_fc_collision, sbmac_fc_carrier } sbmac_fc_t; +enum sbmac_fc { + sbmac_fc_none, + sbmac_fc_disabled, + sbmac_fc_frame, + sbmac_fc_collision, + sbmac_fc_carrier, +}; -enum sbmac_state { sbmac_state_uninit, sbmac_state_off, sbmac_state_on, - sbmac_state_broken }; +enum sbmac_state { + sbmac_state_uninit, + sbmac_state_off, + sbmac_state_on, + sbmac_state_broken, +}; /********************************************************************** @@ -244,18 +256,14 @@ struct sbmac_softc { */ struct net_device *sbm_dev; /* pointer to linux device */ struct napi_struct napi; + struct phy_device *phy_dev; /* the associated PHY device */ + struct mii_bus mii_bus; /* the MII bus */ + int phy_irq[PHY_MAX_ADDR]; spinlock_t sbm_lock; /* spin lock */ - struct timer_list sbm_timer; /* for monitoring MII */ int sbm_devflags; /* current device flags */ - int sbm_phy_oldbmsr; - int sbm_phy_oldanlpar; - int sbm_phy_oldk1stsr; - int sbm_phy_oldlinkstat; int sbm_buffersize; - unsigned char sbm_phys[2]; - /* * Controller-specific things */ @@ -274,6 +282,8 @@ struct sbmac_softc { enum sbmac_speed sbm_speed; /* current speed */ enum sbmac_duplex sbm_duplex; /* current duplex */ enum sbmac_fc sbm_fc; /* cur. flow control setting */ + int sbm_pause; /* current pause setting */ + int sbm_link; /* current link state */ unsigned char sbm_hwaddr[ETHER_ADDR_LEN]; @@ -313,36 +323,37 @@ static uint64_t sbmac_addr2reg(unsigned char *ptr); static irqreturn_t sbmac_intr(int irq, void *dev_instance); static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev); static void sbmac_setmulti(struct sbmac_softc *sc); -static int sbmac_init(struct net_device *dev, int idx); +static int sbmac_init(struct platform_device *pldev, long long base); static int sbmac_set_speed(struct sbmac_softc *s, enum sbmac_speed speed); static int sbmac_set_duplex(struct sbmac_softc *s, enum sbmac_duplex duplex, enum sbmac_fc fc); static int sbmac_open(struct net_device *dev); -static void sbmac_timer(unsigned long data); static void sbmac_tx_timeout (struct net_device *dev); static void sbmac_set_rx_mode(struct net_device *dev); static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static int sbmac_close(struct net_device *dev); static int sbmac_poll(struct napi_struct *napi, int budget); -static int sbmac_mii_poll(struct sbmac_softc *s, int noisy); +static void sbmac_mii_poll(struct net_device *dev); static int sbmac_mii_probe(struct net_device *dev); -static void sbmac_mii_sync(struct sbmac_softc *s); -static void sbmac_mii_senddata(struct sbmac_softc *s, unsigned int data, +static void sbmac_mii_sync(void __iomem *sbm_mdio); +static void sbmac_mii_senddata(void __iomem *sbm_mdio, unsigned int data, int bitcnt); -static unsigned int sbmac_mii_read(struct sbmac_softc *s, int phyaddr, - int regidx); -static void sbmac_mii_write(struct sbmac_softc *s, int phyaddr, int regidx, - unsigned int regval); +static int sbmac_mii_read(struct mii_bus *bus, int phyaddr, int regidx); +static int sbmac_mii_write(struct mii_bus *bus, int phyaddr, int regidx, + u16 val); /********************************************************************** * Globals ********************************************************************* */ -static uint64_t sbmac_orig_hwaddr[MAX_UNITS]; +static char sbmac_string[] = "sb1250-mac"; +static char sbmac_pretty[] = "SB1250 MAC"; + +static char sbmac_mdio_string[] = "sb1250-mac-mdio"; /********************************************************************** @@ -354,185 +365,66 @@ static uint64_t sbmac_orig_hwaddr[MAX_UNITS]; #define MII_COMMAND_WRITE 0x01 #define MII_COMMAND_ACK 0x02 -#define BMCR_RESET 0x8000 -#define BMCR_LOOPBACK 0x4000 -#define BMCR_SPEED0 0x2000 -#define BMCR_ANENABLE 0x1000 -#define BMCR_POWERDOWN 0x0800 -#define BMCR_ISOLATE 0x0400 -#define BMCR_RESTARTAN 0x0200 -#define BMCR_DUPLEX 0x0100 -#define BMCR_COLTEST 0x0080 -#define BMCR_SPEED1 0x0040 -#define BMCR_SPEED1000 BMCR_SPEED1 -#define BMCR_SPEED100 BMCR_SPEED0 -#define BMCR_SPEED10 0 - -#define BMSR_100BT4 0x8000 -#define BMSR_100BT_FDX 0x4000 -#define BMSR_100BT_HDX 0x2000 -#define BMSR_10BT_FDX 0x1000 -#define BMSR_10BT_HDX 0x0800 -#define BMSR_100BT2_FDX 0x0400 -#define BMSR_100BT2_HDX 0x0200 -#define BMSR_1000BT_XSR 0x0100 -#define BMSR_PRESUP 0x0040 -#define BMSR_ANCOMPLT 0x0020 -#define BMSR_REMFAULT 0x0010 -#define BMSR_AUTONEG 0x0008 -#define BMSR_LINKSTAT 0x0004 -#define BMSR_JABDETECT 0x0002 -#define BMSR_EXTCAPAB 0x0001 - -#define PHYIDR1 0x2000 -#define PHYIDR2 0x5C60 - -#define ANAR_NP 0x8000 -#define ANAR_RF 0x2000 -#define ANAR_ASYPAUSE 0x0800 -#define ANAR_PAUSE 0x0400 -#define ANAR_T4 0x0200 -#define ANAR_TXFD 0x0100 -#define ANAR_TXHD 0x0080 -#define ANAR_10FD 0x0040 -#define ANAR_10HD 0x0020 -#define ANAR_PSB 0x0001 - -#define ANLPAR_NP 0x8000 -#define ANLPAR_ACK 0x4000 -#define ANLPAR_RF 0x2000 -#define ANLPAR_ASYPAUSE 0x0800 -#define ANLPAR_PAUSE 0x0400 -#define ANLPAR_T4 0x0200 -#define ANLPAR_TXFD 0x0100 -#define ANLPAR_TXHD 0x0080 -#define ANLPAR_10FD 0x0040 -#define ANLPAR_10HD 0x0020 -#define ANLPAR_PSB 0x0001 /* 802.3 */ - -#define ANER_PDF 0x0010 -#define ANER_LPNPABLE 0x0008 -#define ANER_NPABLE 0x0004 -#define ANER_PAGERX 0x0002 -#define ANER_LPANABLE 0x0001 - -#define ANNPTR_NP 0x8000 -#define ANNPTR_MP 0x2000 -#define ANNPTR_ACK2 0x1000 -#define ANNPTR_TOGTX 0x0800 -#define ANNPTR_CODE 0x0008 - -#define ANNPRR_NP 0x8000 -#define ANNPRR_MP 0x2000 -#define ANNPRR_ACK3 0x1000 -#define ANNPRR_TOGTX 0x0800 -#define ANNPRR_CODE 0x0008 - -#define K1TCR_TESTMODE 0x0000 -#define K1TCR_MSMCE 0x1000 -#define K1TCR_MSCV 0x0800 -#define K1TCR_RPTR 0x0400 -#define K1TCR_1000BT_FDX 0x200 -#define K1TCR_1000BT_HDX 0x100 - -#define K1STSR_MSMCFLT 0x8000 -#define K1STSR_MSCFGRES 0x4000 -#define K1STSR_LRSTAT 0x2000 -#define K1STSR_RRSTAT 0x1000 -#define K1STSR_LP1KFD 0x0800 -#define K1STSR_LP1KHD 0x0400 -#define K1STSR_LPASMDIR 0x0200 - -#define K1SCR_1KX_FDX 0x8000 -#define K1SCR_1KX_HDX 0x4000 -#define K1SCR_1KT_FDX 0x2000 -#define K1SCR_1KT_HDX 0x1000 - -#define STRAP_PHY1 0x0800 -#define STRAP_NCMODE 0x0400 -#define STRAP_MANMSCFG 0x0200 -#define STRAP_ANENABLE 0x0100 -#define STRAP_MSVAL 0x0080 -#define STRAP_1KHDXADV 0x0010 -#define STRAP_1KFDXADV 0x0008 -#define STRAP_100ADV 0x0004 -#define STRAP_SPEEDSEL 0x0000 -#define STRAP_SPEED100 0x0001 - -#define PHYSUP_SPEED1000 0x10 -#define PHYSUP_SPEED100 0x08 -#define PHYSUP_SPEED10 0x00 -#define PHYSUP_LINKUP 0x04 -#define PHYSUP_FDX 0x02 - -#define MII_BMCR 0x00 /* Basic mode control register (rw) */ -#define MII_BMSR 0x01 /* Basic mode status register (ro) */ -#define MII_PHYIDR1 0x02 -#define MII_PHYIDR2 0x03 - -#define MII_K1STSR 0x0A /* 1K Status Register (ro) */ -#define MII_ANLPAR 0x05 /* Autonegotiation lnk partner abilities (rw) */ - - #define M_MAC_MDIO_DIR_OUTPUT 0 /* for clarity */ #define ENABLE 1 #define DISABLE 0 /********************************************************************** - * SBMAC_MII_SYNC(s) + * SBMAC_MII_SYNC(sbm_mdio) * * Synchronize with the MII - send a pattern of bits to the MII * that will guarantee that it is ready to accept a command. * * Input parameters: - * s - sbmac structure + * sbm_mdio - address of the MAC's MDIO register * * Return value: * nothing ********************************************************************* */ -static void sbmac_mii_sync(struct sbmac_softc *s) +static void sbmac_mii_sync(void __iomem *sbm_mdio) { int cnt; uint64_t bits; int mac_mdio_genc; - mac_mdio_genc = __raw_readq(s->sbm_mdio) & M_MAC_GENC; + mac_mdio_genc = __raw_readq(sbm_mdio) & M_MAC_GENC; bits = M_MAC_MDIO_DIR_OUTPUT | M_MAC_MDIO_OUT; - __raw_writeq(bits | mac_mdio_genc, s->sbm_mdio); + __raw_writeq(bits | mac_mdio_genc, sbm_mdio); for (cnt = 0; cnt < 32; cnt++) { - __raw_writeq(bits | M_MAC_MDC | mac_mdio_genc, s->sbm_mdio); - __raw_writeq(bits | mac_mdio_genc, s->sbm_mdio); + __raw_writeq(bits | M_MAC_MDC | mac_mdio_genc, sbm_mdio); + __raw_writeq(bits | mac_mdio_genc, sbm_mdio); } } /********************************************************************** - * SBMAC_MII_SENDDATA(s,data,bitcnt) + * SBMAC_MII_SENDDATA(sbm_mdio, data, bitcnt) * * Send some bits to the MII. The bits to be sent are right- * justified in the 'data' parameter. * * Input parameters: - * s - sbmac structure - * data - data to send - * bitcnt - number of bits to send + * sbm_mdio - address of the MAC's MDIO register + * data - data to send + * bitcnt - number of bits to send ********************************************************************* */ -static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitcnt) +static void sbmac_mii_senddata(void __iomem *sbm_mdio, unsigned int data, + int bitcnt) { int i; uint64_t bits; unsigned int curmask; int mac_mdio_genc; - mac_mdio_genc = __raw_readq(s->sbm_mdio) & M_MAC_GENC; + mac_mdio_genc = __raw_readq(sbm_mdio) & M_MAC_GENC; bits = M_MAC_MDIO_DIR_OUTPUT; - __raw_writeq(bits | mac_mdio_genc, s->sbm_mdio); + __raw_writeq(bits | mac_mdio_genc, sbm_mdio); curmask = 1 << (bitcnt - 1); @@ -540,9 +432,9 @@ static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitc if (data & curmask) bits |= M_MAC_MDIO_OUT; else bits &= ~M_MAC_MDIO_OUT; - __raw_writeq(bits | mac_mdio_genc, s->sbm_mdio); - __raw_writeq(bits | M_MAC_MDC | mac_mdio_genc, s->sbm_mdio); - __raw_writeq(bits | mac_mdio_genc, s->sbm_mdio); + __raw_writeq(bits | mac_mdio_genc, sbm_mdio); + __raw_writeq(bits | M_MAC_MDC | mac_mdio_genc, sbm_mdio); + __raw_writeq(bits | mac_mdio_genc, sbm_mdio); curmask >>= 1; } } @@ -550,21 +442,22 @@ static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitc /********************************************************************** - * SBMAC_MII_READ(s,phyaddr,regidx) - * + * SBMAC_MII_READ(bus, phyaddr, regidx) * Read a PHY register. * * Input parameters: - * s - sbmac structure + * bus - MDIO bus handle * phyaddr - PHY's address - * regidx = index of register to read + * regnum - index of register to read * * Return value: - * value read, or 0 if an error occurred. + * value read, or 0xffff if an error occurred. ********************************************************************* */ -static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx) +static int sbmac_mii_read(struct mii_bus *bus, int phyaddr, int regidx) { + struct sbmac_softc *sc = (struct sbmac_softc *)bus->priv; + void __iomem *sbm_mdio = sc->sbm_mdio; int idx; int error; int regval; @@ -574,8 +467,7 @@ static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx) * Synchronize ourselves so that the PHY knows the next * thing coming down is a command */ - - sbmac_mii_sync(s); + sbmac_mii_sync(sbm_mdio); /* * Send the data to the PHY. The sequence is @@ -584,37 +476,37 @@ static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx) * the PHY addr (5 bits) * the register index (5 bits) */ + sbmac_mii_senddata(sbm_mdio, MII_COMMAND_START, 2); + sbmac_mii_senddata(sbm_mdio, MII_COMMAND_READ, 2); + sbmac_mii_senddata(sbm_mdio, phyaddr, 5); + sbmac_mii_senddata(sbm_mdio, regidx, 5); - sbmac_mii_senddata(s,MII_COMMAND_START, 2); - sbmac_mii_senddata(s,MII_COMMAND_READ, 2); - sbmac_mii_senddata(s,phyaddr, 5); - sbmac_mii_senddata(s,regidx, 5); - - mac_mdio_genc = __raw_readq(s->sbm_mdio) & M_MAC_GENC; + mac_mdio_genc = __raw_readq(sbm_mdio) & M_MAC_GENC; /* * Switch the port around without a clock transition. */ - __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, s->sbm_mdio); + __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, sbm_mdio); /* * Send out a clock pulse to signal we want the status */ - - __raw_writeq(M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc, s->sbm_mdio); - __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, s->sbm_mdio); + __raw_writeq(M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc, + sbm_mdio); + __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, sbm_mdio); /* * If an error occurred, the PHY will signal '1' back */ - error = __raw_readq(s->sbm_mdio) & M_MAC_MDIO_IN; + error = __raw_readq(sbm_mdio) & M_MAC_MDIO_IN; /* * Issue an 'idle' clock pulse, but keep the direction * the same. */ - __raw_writeq(M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc, s->sbm_mdio); - __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, s->sbm_mdio); + __raw_writeq(M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc, + sbm_mdio); + __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, sbm_mdio); regval = 0; @@ -622,55 +514,60 @@ static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx) regval <<= 1; if (error == 0) { - if (__raw_readq(s->sbm_mdio) & M_MAC_MDIO_IN) + if (__raw_readq(sbm_mdio) & M_MAC_MDIO_IN) regval |= 1; } - __raw_writeq(M_MAC_MDIO_DIR_INPUT|M_MAC_MDC | mac_mdio_genc, s->sbm_mdio); - __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, s->sbm_mdio); + __raw_writeq(M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc, + sbm_mdio); + __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, sbm_mdio); } /* Switch back to output */ - __raw_writeq(M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc, s->sbm_mdio); + __raw_writeq(M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc, sbm_mdio); if (error == 0) return regval; - return 0; + return 0xffff; } /********************************************************************** - * SBMAC_MII_WRITE(s,phyaddr,regidx,regval) + * SBMAC_MII_WRITE(bus, phyaddr, regidx, regval) * * Write a value to a PHY register. * * Input parameters: - * s - sbmac structure + * bus - MDIO bus handle * phyaddr - PHY to use - * regidx - register within the PHY - * regval - data to write to register + * regidx - register within the PHY + * regval - data to write to register * * Return value: - * nothing + * 0 for success ********************************************************************* */ -static void sbmac_mii_write(struct sbmac_softc *s,int phyaddr,int regidx, - unsigned int regval) +static int sbmac_mii_write(struct mii_bus *bus, int phyaddr, int regidx, + u16 regval) { + struct sbmac_softc *sc = (struct sbmac_softc *)bus->priv; + void __iomem *sbm_mdio = sc->sbm_mdio; int mac_mdio_genc; - sbmac_mii_sync(s); + sbmac_mii_sync(sbm_mdio); - sbmac_mii_senddata(s,MII_COMMAND_START,2); - sbmac_mii_senddata(s,MII_COMMAND_WRITE,2); - sbmac_mii_senddata(s,phyaddr, 5); - sbmac_mii_senddata(s,regidx, 5); - sbmac_mii_senddata(s,MII_COMMAND_ACK,2); - sbmac_mii_senddata(s,regval,16); + sbmac_mii_senddata(sbm_mdio, MII_COMMAND_START, 2); + sbmac_mii_senddata(sbm_mdio, MII_COMMAND_WRITE, 2); + sbmac_mii_senddata(sbm_mdio, phyaddr, 5); + sbmac_mii_senddata(sbm_mdio, regidx, 5); + sbmac_mii_senddata(sbm_mdio, MII_COMMAND_ACK, 2); + sbmac_mii_senddata(sbm_mdio, regval, 16); - mac_mdio_genc = __raw_readq(s->sbm_mdio) & M_MAC_GENC; + mac_mdio_genc = __raw_readq(sbm_mdio) & M_MAC_GENC; - __raw_writeq(M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc, s->sbm_mdio); + __raw_writeq(M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc, sbm_mdio); + + return 0; } @@ -713,27 +610,27 @@ static void sbdma_initctx(struct sbmacdma *d, struct sbmac_softc *s, int chan, s->sbe_idx =(s->sbm_base - A_MAC_BASE_0)/MAC_SPACING; #endif - __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_BYTES))); - __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_COLLISIONS))); - __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_LATE_COL))); - __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_EX_COL))); - __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_FCS_ERROR))); - __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_ABORT))); - __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_BAD))); - __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_GOOD))); - __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_RUNT))); - __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_OVERSIZE))); - __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BYTES))); - __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_MCAST))); - __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BCAST))); - __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BAD))); - __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_GOOD))); - __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_RUNT))); - __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_OVERSIZE))); - __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_FCS_ERROR))); - __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_LENGTH_ERROR))); - __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_CODE_ERROR))); - __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_ALIGN_ERROR))); + __raw_writeq(0, s->sbm_base + R_MAC_RMON_TX_BYTES); + __raw_writeq(0, s->sbm_base + R_MAC_RMON_COLLISIONS); + __raw_writeq(0, s->sbm_base + R_MAC_RMON_LATE_COL); + __raw_writeq(0, s->sbm_base + R_MAC_RMON_EX_COL); + __raw_writeq(0, s->sbm_base + R_MAC_RMON_FCS_ERROR); + __raw_writeq(0, s->sbm_base + R_MAC_RMON_TX_ABORT); + __raw_writeq(0, s->sbm_base + R_MAC_RMON_TX_BAD); + __raw_writeq(0, s->sbm_base + R_MAC_RMON_TX_GOOD); + __raw_writeq(0, s->sbm_base + R_MAC_RMON_TX_RUNT); + __raw_writeq(0, s->sbm_base + R_MAC_RMON_TX_OVERSIZE); + __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_BYTES); + __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_MCAST); + __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_BCAST); + __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_BAD); + __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_GOOD); + __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_RUNT); + __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_OVERSIZE); + __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_FCS_ERROR); + __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_LENGTH_ERROR); + __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_CODE_ERROR); + __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_ALIGN_ERROR); /* * initialize register pointers @@ -953,7 +850,7 @@ static int sbdma_add_rcvbuffer(struct sbmacdma *d, struct sk_buff *sb) if (sb == NULL) { sb_new = dev_alloc_skb(ENET_PACKET_SIZE + SMP_CACHE_BYTES * 2 + ETHER_ALIGN); if (sb_new == NULL) { - printk(KERN_INFO "%s: sk_buff allocation failed\n", + pr_info("%s: sk_buff allocation failed\n", d->sbdma_eth->sbm_dev->name); return -ENOBUFS; } @@ -1472,14 +1369,6 @@ static int sbmac_initctx(struct sbmac_softc *s) s->sbm_imr = s->sbm_base + R_MAC_INT_MASK; s->sbm_mdio = s->sbm_base + R_MAC_MDIO; - s->sbm_phys[0] = 1; - s->sbm_phys[1] = 0; - - s->sbm_phy_oldbmsr = 0; - s->sbm_phy_oldanlpar = 0; - s->sbm_phy_oldk1stsr = 0; - s->sbm_phy_oldlinkstat = 0; - /* * Initialize the DMA channels. Right now, only one per MAC is used * Note: Only do this _once_, as it allocates memory from the kernel! @@ -1494,14 +1383,6 @@ static int sbmac_initctx(struct sbmac_softc *s) s->sbm_state = sbmac_state_off; - /* - * Initial speed is (XXX TEMP) 10MBit/s HDX no FC - */ - - s->sbm_speed = sbmac_speed_10; - s->sbm_duplex = sbmac_duplex_half; - s->sbm_fc = sbmac_fc_disabled; - return 0; } @@ -2008,8 +1889,6 @@ static int sbmac_set_speed(struct sbmac_softc *s, enum sbmac_speed speed) cfg |= V_MAC_SPEED_SEL_1000MBPS | M_MAC_BURST_EN; break; - case sbmac_speed_auto: /* XXX not implemented */ - /* fall through */ default: return 0; } @@ -2083,8 +1962,6 @@ static int sbmac_set_duplex(struct sbmac_softc *s, enum sbmac_duplex duplex, cfg |= M_MAC_HDX_EN | V_MAC_FC_CMD_ENAB_FALSECARR; break; - case sbmac_fc_auto: /* XXX not implemented */ - /* fall through */ case sbmac_fc_frame: /* not valid in half duplex */ default: /* invalid selection */ return 0; @@ -2103,15 +1980,12 @@ static int sbmac_set_duplex(struct sbmac_softc *s, enum sbmac_duplex duplex, case sbmac_fc_collision: /* not valid in full duplex */ case sbmac_fc_carrier: /* not valid in full duplex */ - case sbmac_fc_auto: /* XXX not implemented */ - /* fall through */ default: return 0; } break; - case sbmac_duplex_auto: - /* XXX not implemented */ - break; + default: + return 0; } /* @@ -2390,7 +2264,7 @@ static int sb1250_change_mtu(struct net_device *_dev, int new_mtu) if (new_mtu > ENET_PACKET_SIZE) return -EINVAL; _dev->mtu = new_mtu; - printk(KERN_INFO "changing the mtu to %d\n", new_mtu); + pr_info("changing the mtu to %d\n", new_mtu); return 0; } @@ -2406,20 +2280,17 @@ static int sb1250_change_mtu(struct net_device *_dev, int new_mtu) * status ********************************************************************* */ -static int sbmac_init(struct net_device *dev, int idx) +static int sbmac_init(struct platform_device *pldev, long long base) { - struct sbmac_softc *sc; + struct net_device *dev = pldev->dev.driver_data; + int idx = pldev->id; + struct sbmac_softc *sc = netdev_priv(dev); unsigned char *eaddr; uint64_t ea_reg; int i; int err; DECLARE_MAC_BUF(mac); - sc = netdev_priv(dev); - - /* Determine controller base address */ - - sc->sbm_base = IOADDR(dev->base_addr); sc->sbm_dev = dev; sc->sbe_idx = idx; @@ -2476,43 +2347,55 @@ static int sbmac_init(struct net_device *dev, int idx) dev->poll_controller = sbmac_netpoll; #endif + dev->irq = UNIT_INT(idx); + /* This is needed for PASS2 for Rx H/W checksum feature */ sbmac_set_iphdr_offset(sc); err = register_netdev(dev); - if (err) - goto out_uninit; - - if (sc->rx_hw_checksum == ENABLE) { - printk(KERN_INFO "%s: enabling TCP rcv checksum\n", - sc->sbm_dev->name); + if (err) { + printk(KERN_ERR "%s.%d: unable to register netdev\n", + sbmac_string, idx); + sbmac_uninitctx(sc); + return err; } + pr_info("%s.%d: registered as %s\n", sbmac_string, idx, dev->name); + + if (sc->rx_hw_checksum == ENABLE) + pr_info("%s: enabling TCP rcv checksum\n", dev->name); + /* * Display Ethernet address (this is called during the config * process so we need to finish off the config message that * was being displayed) */ - printk(KERN_INFO - "%s: SiByte Ethernet at 0x%08lX, address: %s\n", - dev->name, dev->base_addr, print_mac(mac, eaddr)); + pr_info("%s: SiByte Ethernet at 0x%08Lx, address: %s\n", + dev->name, base, print_mac(mac, eaddr)); - return 0; + sc->mii_bus.name = sbmac_mdio_string; + sc->mii_bus.id = idx; + sc->mii_bus.priv = sc; + sc->mii_bus.read = sbmac_mii_read; + sc->mii_bus.write = sbmac_mii_write; + sc->mii_bus.irq = sc->phy_irq; + for (i = 0; i < PHY_MAX_ADDR; ++i) + sc->mii_bus.irq[i] = SBMAC_PHY_INT; -out_uninit: - sbmac_uninitctx(sc); + sc->mii_bus.dev = &pldev->dev; + dev_set_drvdata(&pldev->dev, &sc->mii_bus); - return err; + return 0; } static int sbmac_open(struct net_device *dev) { struct sbmac_softc *sc = netdev_priv(dev); + int err; - if (debug > 1) { - printk(KERN_DEBUG "%s: sbmac_open() irq %d.\n", dev->name, dev->irq); - } + if (debug > 1) + pr_debug("%s: sbmac_open() irq %d.\n", dev->name, dev->irq); /* * map/route interrupt (clear status first, in case something @@ -2521,25 +2404,35 @@ static int sbmac_open(struct net_device *dev) */ __raw_readq(sc->sbm_isr); - if (request_irq(dev->irq, &sbmac_intr, IRQF_SHARED, dev->name, dev)) - return -EBUSY; + err = request_irq(dev->irq, &sbmac_intr, IRQF_SHARED, dev->name, dev); + if (err) { + printk(KERN_ERR "%s: unable to get IRQ %d\n", dev->name, + dev->irq); + goto out_err; + } /* - * Probe phy address + * Probe PHY address */ - - if(sbmac_mii_probe(dev) == -1) { - printk("%s: failed to probe PHY.\n", dev->name); - return -EINVAL; + err = mdiobus_register(&sc->mii_bus); + if (err) { + printk(KERN_ERR "%s: unable to register MDIO bus\n", + dev->name); + goto out_unirq; } - napi_enable(&sc->napi); + sc->sbm_speed = sbmac_speed_none; + sc->sbm_duplex = sbmac_duplex_none; + sc->sbm_fc = sbmac_fc_none; + sc->sbm_pause = -1; + sc->sbm_link = 0; /* - * Configure default speed + * Attach to the PHY */ - - sbmac_mii_poll(sc,noisy_mii); + err = sbmac_mii_probe(dev); + if (err) + goto out_unregister; /* * Turn on the channel @@ -2547,200 +2440,133 @@ static int sbmac_open(struct net_device *dev) sbmac_set_channel_state(sc,sbmac_state_on); - /* - * XXX Station address is in dev->dev_addr - */ - - if (dev->if_port == 0) - dev->if_port = 0; - netif_start_queue(dev); sbmac_set_rx_mode(dev); - /* Set the timer to check for link beat. */ - init_timer(&sc->sbm_timer); - sc->sbm_timer.expires = jiffies + 2 * HZ/100; - sc->sbm_timer.data = (unsigned long)dev; - sc->sbm_timer.function = &sbmac_timer; - add_timer(&sc->sbm_timer); + phy_start(sc->phy_dev); + + napi_enable(&sc->napi); return 0; + +out_unregister: + mdiobus_unregister(&sc->mii_bus); + +out_unirq: + free_irq(dev->irq, dev); + +out_err: + return err; } static int sbmac_mii_probe(struct net_device *dev) { + struct sbmac_softc *sc = netdev_priv(dev); + struct phy_device *phy_dev; int i; - struct sbmac_softc *s = netdev_priv(dev); - u16 bmsr, id1, id2; - u32 vendor, device; - - for (i=1; i<31; i++) { - bmsr = sbmac_mii_read(s, i, MII_BMSR); - if (bmsr != 0) { - s->sbm_phys[0] = i; - id1 = sbmac_mii_read(s, i, MII_PHYIDR1); - id2 = sbmac_mii_read(s, i, MII_PHYIDR2); - vendor = ((u32)id1 << 6) | ((id2 >> 10) & 0x3f); - device = (id2 >> 4) & 0x3f; - - printk(KERN_INFO "%s: found phy %d, vendor %06x part %02x\n", - dev->name, i, vendor, device); - return i; - } - } - return -1; -} - - -static int sbmac_mii_poll(struct sbmac_softc *s,int noisy) -{ - int bmsr,bmcr,k1stsr,anlpar; - int chg; - char buffer[100]; - char *p = buffer; - - /* Read the mode status and mode control registers. */ - bmsr = sbmac_mii_read(s,s->sbm_phys[0],MII_BMSR); - bmcr = sbmac_mii_read(s,s->sbm_phys[0],MII_BMCR); - - /* get the link partner status */ - anlpar = sbmac_mii_read(s,s->sbm_phys[0],MII_ANLPAR); - /* if supported, read the 1000baseT register */ - if (bmsr & BMSR_1000BT_XSR) { - k1stsr = sbmac_mii_read(s,s->sbm_phys[0],MII_K1STSR); - } - else { - k1stsr = 0; - } - - chg = 0; - - if ((bmsr & BMSR_LINKSTAT) == 0) { - /* - * If link status is down, clear out old info so that when - * it comes back up it will force us to reconfigure speed - */ - s->sbm_phy_oldbmsr = 0; - s->sbm_phy_oldanlpar = 0; - s->sbm_phy_oldk1stsr = 0; - return 0; + for (i = 0; i < PHY_MAX_ADDR; i++) { + phy_dev = sc->mii_bus.phy_map[i]; + if (phy_dev) + break; } - - if ((s->sbm_phy_oldbmsr != bmsr) || - (s->sbm_phy_oldanlpar != anlpar) || - (s->sbm_phy_oldk1stsr != k1stsr)) { - if (debug > 1) { - printk(KERN_DEBUG "%s: bmsr:%x/%x anlpar:%x/%x k1stsr:%x/%x\n", - s->sbm_dev->name, - s->sbm_phy_oldbmsr,bmsr, - s->sbm_phy_oldanlpar,anlpar, - s->sbm_phy_oldk1stsr,k1stsr); - } - s->sbm_phy_oldbmsr = bmsr; - s->sbm_phy_oldanlpar = anlpar; - s->sbm_phy_oldk1stsr = k1stsr; - chg = 1; + if (!phy_dev) { + printk(KERN_ERR "%s: no PHY found\n", dev->name); + return -ENXIO; } - if (chg == 0) - return 0; - - p += sprintf(p,"Link speed: "); - - if (k1stsr & K1STSR_LP1KFD) { - s->sbm_speed = sbmac_speed_1000; - s->sbm_duplex = sbmac_duplex_full; - s->sbm_fc = sbmac_fc_frame; - p += sprintf(p,"1000BaseT FDX"); - } - else if (k1stsr & K1STSR_LP1KHD) { - s->sbm_speed = sbmac_speed_1000; - s->sbm_duplex = sbmac_duplex_half; - s->sbm_fc = sbmac_fc_disabled; - p += sprintf(p,"1000BaseT HDX"); - } - else if (anlpar & ANLPAR_TXFD) { - s->sbm_speed = sbmac_speed_100; - s->sbm_duplex = sbmac_duplex_full; - s->sbm_fc = (anlpar & ANLPAR_PAUSE) ? sbmac_fc_frame : sbmac_fc_disabled; - p += sprintf(p,"100BaseT FDX"); - } - else if (anlpar & ANLPAR_TXHD) { - s->sbm_speed = sbmac_speed_100; - s->sbm_duplex = sbmac_duplex_half; - s->sbm_fc = sbmac_fc_disabled; - p += sprintf(p,"100BaseT HDX"); - } - else if (anlpar & ANLPAR_10FD) { - s->sbm_speed = sbmac_speed_10; - s->sbm_duplex = sbmac_duplex_full; - s->sbm_fc = sbmac_fc_frame; - p += sprintf(p,"10BaseT FDX"); - } - else if (anlpar & ANLPAR_10HD) { - s->sbm_speed = sbmac_speed_10; - s->sbm_duplex = sbmac_duplex_half; - s->sbm_fc = sbmac_fc_collision; - p += sprintf(p,"10BaseT HDX"); - } - else { - p += sprintf(p,"Unknown"); + phy_dev = phy_connect(dev, phy_dev->dev.bus_id, &sbmac_mii_poll, 0, + PHY_INTERFACE_MODE_GMII); + if (IS_ERR(phy_dev)) { + printk(KERN_ERR "%s: could not attach to PHY\n", dev->name); + return PTR_ERR(phy_dev); } - if (noisy) { - printk(KERN_INFO "%s: %s\n",s->sbm_dev->name,buffer); - } + /* Remove any features not supported by the controller */ + phy_dev->supported &= SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Half | + SUPPORTED_1000baseT_Full | + SUPPORTED_Autoneg | + SUPPORTED_MII | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause; + phy_dev->advertising = phy_dev->supported; + + pr_info("%s: attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n", + dev->name, phy_dev->drv->name, + phy_dev->dev.bus_id, phy_dev->irq); + + sc->phy_dev = phy_dev; - return 1; + return 0; } -static void sbmac_timer(unsigned long data) +static void sbmac_mii_poll(struct net_device *dev) { - struct net_device *dev = (struct net_device *)data; struct sbmac_softc *sc = netdev_priv(dev); - int next_tick = HZ; - int mii_status; + struct phy_device *phy_dev = sc->phy_dev; + unsigned long flags; + enum sbmac_fc fc; + int link_chg, speed_chg, duplex_chg, pause_chg, fc_chg; + + link_chg = (sc->sbm_link != phy_dev->link); + speed_chg = (sc->sbm_speed != phy_dev->speed); + duplex_chg = (sc->sbm_duplex != phy_dev->duplex); + pause_chg = (sc->sbm_pause != phy_dev->pause); + + if (!link_chg && !speed_chg && !duplex_chg && !pause_chg) + return; /* Hmmm... */ + + if (!phy_dev->link) { + if (link_chg) { + sc->sbm_link = phy_dev->link; + sc->sbm_speed = sbmac_speed_none; + sc->sbm_duplex = sbmac_duplex_none; + sc->sbm_fc = sbmac_fc_disabled; + sc->sbm_pause = -1; + pr_info("%s: link unavailable\n", dev->name); + } + return; + } - spin_lock_irq (&sc->sbm_lock); + if (phy_dev->duplex == DUPLEX_FULL) { + if (phy_dev->pause) + fc = sbmac_fc_frame; + else + fc = sbmac_fc_disabled; + } else + fc = sbmac_fc_collision; + fc_chg = (sc->sbm_fc != fc); - /* make IFF_RUNNING follow the MII status bit "Link established" */ - mii_status = sbmac_mii_read(sc, sc->sbm_phys[0], MII_BMSR); + pr_info("%s: link available: %dbase-%cD\n", dev->name, phy_dev->speed, + phy_dev->duplex == DUPLEX_FULL ? 'F' : 'H'); - if ( (mii_status & BMSR_LINKSTAT) != (sc->sbm_phy_oldlinkstat) ) { - sc->sbm_phy_oldlinkstat = mii_status & BMSR_LINKSTAT; - if (mii_status & BMSR_LINKSTAT) { - netif_carrier_on(dev); - } - else { - netif_carrier_off(dev); - } - } + spin_lock_irqsave(&sc->sbm_lock, flags); - /* - * Poll the PHY to see what speed we should be running at - */ + sc->sbm_speed = phy_dev->speed; + sc->sbm_duplex = phy_dev->duplex; + sc->sbm_fc = fc; + sc->sbm_pause = phy_dev->pause; + sc->sbm_link = phy_dev->link; - if (sbmac_mii_poll(sc,noisy_mii)) { - if (sc->sbm_state != sbmac_state_off) { - /* - * something changed, restart the channel - */ - if (debug > 1) { - printk("%s: restarting channel because speed changed\n", - sc->sbm_dev->name); - } - sbmac_channel_stop(sc); - sbmac_channel_start(sc); - } + if ((speed_chg || duplex_chg || fc_chg) && + sc->sbm_state != sbmac_state_off) { + /* + * something changed, restart the channel + */ + if (debug > 1) + pr_debug("%s: restarting channel " + "because PHY state changed\n", dev->name); + sbmac_channel_stop(sc); + sbmac_channel_start(sc); } - spin_unlock_irq (&sc->sbm_lock); - - sc->sbm_timer.expires = jiffies + next_tick; - add_timer(&sc->sbm_timer); + spin_unlock_irqrestore(&sc->sbm_lock, flags); } @@ -2793,64 +2619,34 @@ static void sbmac_set_rx_mode(struct net_device *dev) static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct sbmac_softc *sc = netdev_priv(dev); - u16 *data = (u16 *)&rq->ifr_ifru; - unsigned long flags; - int retval; - spin_lock_irqsave(&sc->sbm_lock, flags); - retval = 0; - - switch(cmd) { - case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ - data[0] = sc->sbm_phys[0] & 0x1f; - /* Fall Through */ - case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ - data[3] = sbmac_mii_read(sc, data[0] & 0x1f, data[1] & 0x1f); - break; - case SIOCDEVPRIVATE+2: /* Write the specified MII register */ - if (!capable(CAP_NET_ADMIN)) { - retval = -EPERM; - break; - } - if (debug > 1) { - printk(KERN_DEBUG "%s: sbmac_mii_ioctl: write %02X %02X %02X\n",dev->name, - data[0],data[1],data[2]); - } - sbmac_mii_write(sc, data[0] & 0x1f, data[1] & 0x1f, data[2]); - break; - default: - retval = -EOPNOTSUPP; - } + if (!netif_running(dev) || !sc->phy_dev) + return -EINVAL; - spin_unlock_irqrestore(&sc->sbm_lock, flags); - return retval; + return phy_mii_ioctl(sc->phy_dev, if_mii(rq), cmd); } static int sbmac_close(struct net_device *dev) { struct sbmac_softc *sc = netdev_priv(dev); - unsigned long flags; - int irq; napi_disable(&sc->napi); - sbmac_set_channel_state(sc,sbmac_state_off); - - del_timer_sync(&sc->sbm_timer); + phy_stop(sc->phy_dev); - spin_lock_irqsave(&sc->sbm_lock, flags); + sbmac_set_channel_state(sc, sbmac_state_off); netif_stop_queue(dev); - if (debug > 1) { - printk(KERN_DEBUG "%s: Shutting down ethercard\n",dev->name); - } + if (debug > 1) + pr_debug("%s: Shutting down ethercard\n", dev->name); - spin_unlock_irqrestore(&sc->sbm_lock, flags); + phy_disconnect(sc->phy_dev); + sc->phy_dev = NULL; + + mdiobus_unregister(&sc->mii_bus); - irq = dev->irq; - synchronize_irq(irq); - free_irq(irq, dev); + free_irq(dev->irq, dev); sbdma_emptyring(&(sc->sbm_txdma)); sbdma_emptyring(&(sc->sbm_rxdma)); @@ -2883,54 +2679,195 @@ static int sbmac_poll(struct napi_struct *napi, int budget) return work_done; } + +static int __init sbmac_probe(struct platform_device *pldev) +{ + struct net_device *dev; + struct sbmac_softc *sc; + void __iomem *sbm_base; + struct resource *res; + u64 sbmac_orig_hwaddr; + int err; + + res = platform_get_resource(pldev, IORESOURCE_MEM, 0); + BUG_ON(!res); + sbm_base = ioremap_nocache(res->start, res->end - res->start + 1); + if (!sbm_base) { + printk(KERN_ERR "%s: unable to map device registers\n", + pldev->dev.bus_id); + err = -ENOMEM; + goto out_out; + } + + /* + * The R_MAC_ETHERNET_ADDR register will be set to some nonzero + * value for us by the firmware if we're going to use this MAC. + * If we find a zero, skip this MAC. + */ + sbmac_orig_hwaddr = __raw_readq(sbm_base + R_MAC_ETHERNET_ADDR); + pr_debug("%s: %sconfiguring MAC at 0x%08Lx\n", pldev->dev.bus_id, + sbmac_orig_hwaddr ? "" : "not ", (long long)res->start); + if (sbmac_orig_hwaddr == 0) { + err = 0; + goto out_unmap; + } + + /* + * Okay, cool. Initialize this MAC. + */ + dev = alloc_etherdev(sizeof(struct sbmac_softc)); + if (!dev) { + printk(KERN_ERR "%s: unable to allocate etherdev\n", + pldev->dev.bus_id); + err = -ENOMEM; + goto out_unmap; + } + + pldev->dev.driver_data = dev; + SET_NETDEV_DEV(dev, &pldev->dev); + + sc = netdev_priv(dev); + sc->sbm_base = sbm_base; + + err = sbmac_init(pldev, res->start); + if (err) + goto out_kfree; + + return 0; + +out_kfree: + free_netdev(dev); + __raw_writeq(sbmac_orig_hwaddr, sbm_base + R_MAC_ETHERNET_ADDR); + +out_unmap: + iounmap(sbm_base); + +out_out: + return err; +} + +static int __exit sbmac_remove(struct platform_device *pldev) +{ + struct net_device *dev = pldev->dev.driver_data; + struct sbmac_softc *sc = netdev_priv(dev); + + unregister_netdev(dev); + sbmac_uninitctx(sc); + iounmap(sc->sbm_base); + free_netdev(dev); + + return 0; +} + + +static struct platform_device **sbmac_pldev; +static int sbmac_max_units; + #if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR) || defined(SBMAC_ETH3_HWADDR) -static void -sbmac_setup_hwaddr(int chan,char *addr) +static void __init sbmac_setup_hwaddr(int idx, char *addr) { + void __iomem *sbm_base; + unsigned long start, end; uint8_t eaddr[6]; uint64_t val; - unsigned long port; - port = A_MAC_CHANNEL_BASE(chan); - sbmac_parse_hwaddr(addr,eaddr); + if (idx >= sbmac_max_units) + return; + + start = A_MAC_CHANNEL_BASE(idx); + end = A_MAC_CHANNEL_BASE(idx + 1) - 1; + + sbm_base = ioremap_nocache(start, end - start + 1); + if (!sbm_base) { + printk(KERN_ERR "%s: unable to map device registers\n", + sbmac_string); + return; + } + + sbmac_parse_hwaddr(addr, eaddr); val = sbmac_addr2reg(eaddr); - __raw_writeq(val, IOADDR(port+R_MAC_ETHERNET_ADDR)); - val = __raw_readq(IOADDR(port+R_MAC_ETHERNET_ADDR)); + __raw_writeq(val, sbm_base + R_MAC_ETHERNET_ADDR); + val = __raw_readq(sbm_base + R_MAC_ETHERNET_ADDR); + + iounmap(sbm_base); } #endif -static struct net_device *dev_sbmac[MAX_UNITS]; +static int __init sbmac_platform_probe_one(int idx) +{ + struct platform_device *pldev; + struct { + struct resource r; + char name[strlen(sbmac_pretty) + 4]; + } *res; + int err; + + res = kzalloc(sizeof(*res), GFP_KERNEL); + if (!res) { + printk(KERN_ERR "%s.%d: unable to allocate memory\n", + sbmac_string, idx); + err = -ENOMEM; + goto out_err; + } + + /* + * This is the base address of the MAC. + */ + snprintf(res->name, sizeof(res->name), "%s %d", sbmac_pretty, idx); + res->r.name = res->name; + res->r.flags = IORESOURCE_MEM; + res->r.start = A_MAC_CHANNEL_BASE(idx); + res->r.end = A_MAC_CHANNEL_BASE(idx + 1) - 1; + + pldev = platform_device_register_simple(sbmac_string, idx, &res->r, 1); + if (IS_ERR(pldev)) { + printk(KERN_ERR "%s.%d: unable to register platform device\n", + sbmac_string, idx); + err = PTR_ERR(pldev); + goto out_kfree; + } + + if (!pldev->dev.driver) { + err = 0; /* No hardware at this address. */ + goto out_unregister; + } + + sbmac_pldev[idx] = pldev; + return 0; + +out_unregister: + platform_device_unregister(pldev); -static int __init -sbmac_init_module(void) +out_kfree: + kfree(res); + +out_err: + return err; +} + +static void __init sbmac_platform_probe(void) { - int idx; - struct net_device *dev; - unsigned long port; - int chip_max_units; + int i; /* Set the number of available units based on the SOC type. */ switch (soc_type) { case K_SYS_SOC_TYPE_BCM1250: case K_SYS_SOC_TYPE_BCM1250_ALT: - chip_max_units = 3; + sbmac_max_units = 3; break; case K_SYS_SOC_TYPE_BCM1120: case K_SYS_SOC_TYPE_BCM1125: case K_SYS_SOC_TYPE_BCM1125H: - case K_SYS_SOC_TYPE_BCM1250_ALT2: /* Hybrid */ - chip_max_units = 2; + case K_SYS_SOC_TYPE_BCM1250_ALT2: /* Hybrid */ + sbmac_max_units = 2; break; case K_SYS_SOC_TYPE_BCM1x55: case K_SYS_SOC_TYPE_BCM1x80: - chip_max_units = 4; + sbmac_max_units = 4; break; default: - chip_max_units = 0; - break; + return; /* none */ } - if (chip_max_units > MAX_UNITS) - chip_max_units = MAX_UNITS; /* * For bringup when not using the firmware, we can pre-fill @@ -2938,89 +2875,71 @@ sbmac_init_module(void) * specified in this file (or maybe from the config file?) */ #ifdef SBMAC_ETH0_HWADDR - if (chip_max_units > 0) - sbmac_setup_hwaddr(0,SBMAC_ETH0_HWADDR); + sbmac_setup_hwaddr(0, SBMAC_ETH0_HWADDR); #endif #ifdef SBMAC_ETH1_HWADDR - if (chip_max_units > 1) - sbmac_setup_hwaddr(1,SBMAC_ETH1_HWADDR); + sbmac_setup_hwaddr(1, SBMAC_ETH1_HWADDR); #endif #ifdef SBMAC_ETH2_HWADDR - if (chip_max_units > 2) - sbmac_setup_hwaddr(2,SBMAC_ETH2_HWADDR); + sbmac_setup_hwaddr(2, SBMAC_ETH2_HWADDR); #endif #ifdef SBMAC_ETH3_HWADDR - if (chip_max_units > 3) - sbmac_setup_hwaddr(3,SBMAC_ETH3_HWADDR); + sbmac_setup_hwaddr(3, SBMAC_ETH3_HWADDR); #endif + sbmac_pldev = kcalloc(sbmac_max_units, sizeof(*sbmac_pldev), + GFP_KERNEL); + if (!sbmac_pldev) { + printk(KERN_ERR "%s: unable to allocate memory\n", + sbmac_string); + return; + } + /* * Walk through the Ethernet controllers and find * those who have their MAC addresses set. */ - for (idx = 0; idx < chip_max_units; idx++) { + for (i = 0; i < sbmac_max_units; i++) + if (sbmac_platform_probe_one(i)) + break; +} - /* - * This is the base address of the MAC. - */ - port = A_MAC_CHANNEL_BASE(idx); +static void __exit sbmac_platform_cleanup(void) +{ + int i; - /* - * The R_MAC_ETHERNET_ADDR register will be set to some nonzero - * value for us by the firmware if we are going to use this MAC. - * If we find a zero, skip this MAC. - */ + for (i = 0; i < sbmac_max_units; i++) + platform_device_unregister(sbmac_pldev[i]); + kfree(sbmac_pldev); +} - sbmac_orig_hwaddr[idx] = __raw_readq(IOADDR(port+R_MAC_ETHERNET_ADDR)); - if (sbmac_orig_hwaddr[idx] == 0) { - printk(KERN_DEBUG "sbmac: not configuring MAC at " - "%lx\n", port); - continue; - } - /* - * Okay, cool. Initialize this MAC. - */ +static struct platform_driver sbmac_driver = { + .probe = sbmac_probe, + .remove = __exit_p(sbmac_remove), + .driver = { + .name = sbmac_string, + }, +}; - dev = alloc_etherdev(sizeof(struct sbmac_softc)); - if (!dev) - return -ENOMEM; +static int __init sbmac_init_module(void) +{ + int err; - printk(KERN_DEBUG "sbmac: configuring MAC at %lx\n", port); + err = platform_driver_register(&sbmac_driver); + if (err) + return err; - dev->irq = UNIT_INT(idx); - dev->base_addr = port; - dev->mem_end = 0; - if (sbmac_init(dev, idx)) { - port = A_MAC_CHANNEL_BASE(idx); - __raw_writeq(sbmac_orig_hwaddr[idx], IOADDR(port+R_MAC_ETHERNET_ADDR)); - free_netdev(dev); - continue; - } - dev_sbmac[idx] = dev; - } - return 0; -} + sbmac_platform_probe(); + return err; +} -static void __exit -sbmac_cleanup_module(void) +static void __exit sbmac_cleanup_module(void) { - struct net_device *dev; - int idx; - - for (idx = 0; idx < MAX_UNITS; idx++) { - struct sbmac_softc *sc; - dev = dev_sbmac[idx]; - if (!dev) - continue; - - sc = netdev_priv(dev); - unregister_netdev(dev); - sbmac_uninitctx(sc); - free_netdev(dev); - } + sbmac_platform_cleanup(); + platform_driver_unregister(&sbmac_driver); } module_init(sbmac_init_module); -- cgit v1.2.3-70-g09d2 From 501e4d247a7e35a4d3aa8e6973794b1586f6cb30 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 24 Aug 2007 13:56:49 -0700 Subject: via-velocity: use standard VLAN interface (resend) The via-velocity is using a non-standard VLAN interface configured via module parameters (yuck). Replace with the standard acceleration interface. It solves a number of problems with being able to handle multiple vlans, and dynamically reconfigure. This is compile tested only, don't have this board. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/via-velocity.c | 73 ++++++++++++++++++++++++++++------------------ drivers/net/via-velocity.h | 3 +- 2 files changed, 46 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index 511a74c6e78..fd1ff123efa 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -72,6 +72,7 @@ #include #include #include +#include #include #include #include @@ -111,15 +112,6 @@ VELOCITY_PARAM(RxDescriptors, "Number of receive descriptors"); #define TX_DESC_DEF 64 VELOCITY_PARAM(TxDescriptors, "Number of transmit descriptors"); -#define VLAN_ID_MIN 0 -#define VLAN_ID_MAX 4095 -#define VLAN_ID_DEF 0 -/* VID_setting[] is used for setting the VID of NIC. - 0: default VID. - 1-4094: other VIDs. -*/ -VELOCITY_PARAM(VID_setting, "802.1Q VLAN ID"); - #define RX_THRESH_MIN 0 #define RX_THRESH_MAX 3 #define RX_THRESH_DEF 0 @@ -147,13 +139,6 @@ VELOCITY_PARAM(rx_thresh, "Receive fifo threshold"); */ VELOCITY_PARAM(DMA_length, "DMA length"); -#define TAGGING_DEF 0 -/* enable_tagging[] is used for enabling 802.1Q VID tagging. - 0: disable VID seeting(default). - 1: enable VID setting. -*/ -VELOCITY_PARAM(enable_tagging, "Enable 802.1Q tagging"); - #define IP_ALIG_DEF 0 /* IP_byte_align[] is used for IP header DWORD byte aligned 0: indicate the IP header won't be DWORD byte aligned.(Default) . @@ -442,8 +427,7 @@ static void __devinit velocity_get_options(struct velocity_opt *opts, int index, velocity_set_int_opt(&opts->DMA_length, DMA_length[index], DMA_LENGTH_MIN, DMA_LENGTH_MAX, DMA_LENGTH_DEF, "DMA_length", devname); velocity_set_int_opt(&opts->numrx, RxDescriptors[index], RX_DESC_MIN, RX_DESC_MAX, RX_DESC_DEF, "RxDescriptors", devname); velocity_set_int_opt(&opts->numtx, TxDescriptors[index], TX_DESC_MIN, TX_DESC_MAX, TX_DESC_DEF, "TxDescriptors", devname); - velocity_set_int_opt(&opts->vid, VID_setting[index], VLAN_ID_MIN, VLAN_ID_MAX, VLAN_ID_DEF, "VID_setting", devname); - velocity_set_bool_opt(&opts->flags, enable_tagging[index], TAGGING_DEF, VELOCITY_FLAGS_TAGGING, "enable_tagging", devname); + velocity_set_bool_opt(&opts->flags, txcsum_offload[index], TX_CSUM_DEF, VELOCITY_FLAGS_TX_CSUM, "txcsum_offload", devname); velocity_set_int_opt(&opts->flow_cntl, flow_control[index], FLOW_CNTL_MIN, FLOW_CNTL_MAX, FLOW_CNTL_DEF, "flow_control", devname); velocity_set_bool_opt(&opts->flags, IP_byte_align[index], IP_ALIG_DEF, VELOCITY_FLAGS_IP_ALIGN, "IP_byte_align", devname); @@ -465,6 +449,7 @@ static void __devinit velocity_get_options(struct velocity_opt *opts, int index, static void velocity_init_cam_filter(struct velocity_info *vptr) { struct mac_regs __iomem * regs = vptr->mac_regs; + unsigned short vid; /* Turn on MCFG_PQEN, turn off MCFG_RTGOPT */ WORD_REG_BITS_SET(MCFG_PQEN, MCFG_RTGOPT, ®s->MCFG); @@ -477,13 +462,19 @@ static void velocity_init_cam_filter(struct velocity_info *vptr) mac_set_cam_mask(regs, vptr->mCAMmask, VELOCITY_MULTICAST_CAM); /* Enable first VCAM */ - if (vptr->flags & VELOCITY_FLAGS_TAGGING) { - /* If Tagging option is enabled and VLAN ID is not zero, then - turn on MCFG_RTGOPT also */ - if (vptr->options.vid != 0) - WORD_REG_BITS_ON(MCFG_RTGOPT, ®s->MCFG); - - mac_set_cam(regs, 0, (u8 *) & (vptr->options.vid), VELOCITY_VLAN_ID_CAM); + if (vptr->vlgrp) { + for (vid = 0; vid < VLAN_VID_MASK; vid++) { + if (vlan_group_get_device(vptr->vlgrp, vid)) { + /* If Tagging option is enabled and + VLAN ID is not zero, then + turn on MCFG_RTGOPT also */ + if (vid != 0) + WORD_REG_BITS_ON(MCFG_RTGOPT, ®s->MCFG); + + mac_set_cam(regs, 0, (u8 *) &vid, + VELOCITY_VLAN_ID_CAM); + } + } vptr->vCAMmask[0] |= 1; mac_set_cam_mask(regs, vptr->vCAMmask, VELOCITY_VLAN_ID_CAM); } else { @@ -494,6 +485,26 @@ static void velocity_init_cam_filter(struct velocity_info *vptr) } } +static void velocity_vlan_rx_add_vid(struct net_device *dev, unsigned short vid) +{ + struct velocity_info *vptr = netdev_priv(dev); + + spin_lock_irq(&vptr->lock); + velocity_init_cam_filter(vptr); + spin_unlock_irq(&vptr->lock); +} + +static void velocity_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) +{ + struct velocity_info *vptr = netdev_priv(dev); + + spin_lock_irq(&vptr->lock); + vlan_group_set_device(vptr->vlgrp, vid, NULL); + velocity_init_cam_filter(vptr); + spin_unlock_irq(&vptr->lock); +} + + /** * velocity_rx_reset - handle a receive reset * @vptr: velocity we are resetting @@ -790,13 +801,17 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi dev->do_ioctl = velocity_ioctl; dev->ethtool_ops = &velocity_ethtool_ops; dev->change_mtu = velocity_change_mtu; + + dev->vlan_rx_add_vid = velocity_vlan_rx_add_vid; + dev->vlan_rx_kill_vid = velocity_vlan_rx_kill_vid; + #ifdef VELOCITY_ZERO_COPY_SUPPORT dev->features |= NETIF_F_SG; #endif + dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER; - if (vptr->flags & VELOCITY_FLAGS_TX_CSUM) { + if (vptr->flags & VELOCITY_FLAGS_TX_CSUM) dev->features |= NETIF_F_IP_CSUM; - } ret = register_netdev(dev); if (ret < 0) @@ -1989,8 +2004,8 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev) td_ptr->tdesc1.CMDZ = 2; } - if (vptr->flags & VELOCITY_FLAGS_TAGGING) { - td_ptr->tdesc1.pqinf.VID = (vptr->options.vid & 0xfff); + if (vptr->vlgrp && vlan_tx_tag_present(skb)) { + td_ptr->tdesc1.pqinf.VID = vlan_tx_tag_get(skb); td_ptr->tdesc1.pqinf.priority = 0; td_ptr->tdesc1.pqinf.CFI = 0; td_ptr->tdesc1.TCR |= TCR0_VETAG; diff --git a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h index b9e114d36c0..af17161286a 100644 --- a/drivers/net/via-velocity.h +++ b/drivers/net/via-velocity.h @@ -1701,7 +1701,7 @@ struct velocity_opt { int numrx; /* Number of RX descriptors */ int numtx; /* Number of TX descriptors */ enum speed_opt spd_dpx; /* Media link mode */ - int vid; /* vlan id */ + int DMA_length; /* DMA length */ int rx_thresh; /* RX_THRESH */ int flow_cntl; @@ -1727,6 +1727,7 @@ struct velocity_info { dma_addr_t tx_bufs_dma; u8 *tx_bufs; + struct vlan_group *vlgrp; u8 ip_addr[4]; enum chip_type chip_id; -- cgit v1.2.3-70-g09d2 From 01faccbf866195831af202de59f37e29467a3d74 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 24 Aug 2007 14:40:45 -0700 Subject: via-velocity: more cleanup Per Al's suggestion, get rid of the stupid stuff: Remove cam_type switch, And deinline things that aren't important for speed. And make big macro and inline. And remove some dead/unused code. And use const char * for chip name. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/via-velocity.c | 178 ++++++++++++++++++++++++++++++++++++--- drivers/net/via-velocity.h | 204 ++------------------------------------------- 2 files changed, 176 insertions(+), 206 deletions(-) (limited to 'drivers') diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index fd1ff123efa..4ae05799ac4 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -85,6 +85,163 @@ static int velocity_nics = 0; static int msglevel = MSG_LEVEL_INFO; +/** + * mac_get_cam_mask - Read a CAM mask + * @regs: register block for this velocity + * @mask: buffer to store mask + * + * Fetch the mask bits of the selected CAM and store them into the + * provided mask buffer. + */ + +static void mac_get_cam_mask(struct mac_regs __iomem * regs, u8 * mask) +{ + int i; + + /* Select CAM mask */ + BYTE_REG_BITS_SET(CAMCR_PS_CAM_MASK, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); + + writeb(0, ®s->CAMADDR); + + /* read mask */ + for (i = 0; i < 8; i++) + *mask++ = readb(&(regs->MARCAM[i])); + + /* disable CAMEN */ + writeb(0, ®s->CAMADDR); + + /* Select mar */ + BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); + +} + + +/** + * mac_set_cam_mask - Set a CAM mask + * @regs: register block for this velocity + * @mask: CAM mask to load + * + * Store a new mask into a CAM + */ + +static void mac_set_cam_mask(struct mac_regs __iomem * regs, u8 * mask) +{ + int i; + /* Select CAM mask */ + BYTE_REG_BITS_SET(CAMCR_PS_CAM_MASK, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); + + writeb(CAMADDR_CAMEN, ®s->CAMADDR); + + for (i = 0; i < 8; i++) { + writeb(*mask++, &(regs->MARCAM[i])); + } + /* disable CAMEN */ + writeb(0, ®s->CAMADDR); + + /* Select mar */ + BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); +} + +static void mac_set_vlan_cam_mask(struct mac_regs __iomem * regs, u8 * mask) +{ + int i; + /* Select CAM mask */ + BYTE_REG_BITS_SET(CAMCR_PS_CAM_MASK, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); + + writeb(CAMADDR_CAMEN | CAMADDR_VCAMSL, ®s->CAMADDR); + + for (i = 0; i < 8; i++) { + writeb(*mask++, &(regs->MARCAM[i])); + } + /* disable CAMEN */ + writeb(0, ®s->CAMADDR); + + /* Select mar */ + BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); +} + +/** + * mac_set_cam - set CAM data + * @regs: register block of this velocity + * @idx: Cam index + * @addr: 2 or 6 bytes of CAM data + * + * Load an address or vlan tag into a CAM + */ + +static void mac_set_cam(struct mac_regs __iomem * regs, int idx, const u8 *addr) +{ + int i; + + /* Select CAM mask */ + BYTE_REG_BITS_SET(CAMCR_PS_CAM_DATA, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); + + idx &= (64 - 1); + + writeb(CAMADDR_CAMEN | idx, ®s->CAMADDR); + + for (i = 0; i < 6; i++) { + writeb(*addr++, &(regs->MARCAM[i])); + } + BYTE_REG_BITS_ON(CAMCR_CAMWR, ®s->CAMCR); + + udelay(10); + + writeb(0, ®s->CAMADDR); + + /* Select mar */ + BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); +} + +static void mac_set_vlan_cam(struct mac_regs __iomem * regs, int idx, + const u8 *addr) +{ + + /* Select CAM mask */ + BYTE_REG_BITS_SET(CAMCR_PS_CAM_DATA, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); + + idx &= (64 - 1); + + writeb(CAMADDR_CAMEN | CAMADDR_VCAMSL | idx, ®s->CAMADDR); + writew(*((u16 *) addr), ®s->MARCAM[0]); + + BYTE_REG_BITS_ON(CAMCR_CAMWR, ®s->CAMCR); + + udelay(10); + + writeb(0, ®s->CAMADDR); + + /* Select mar */ + BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); +} + + +/** + * mac_wol_reset - reset WOL after exiting low power + * @regs: register block of this velocity + * + * Called after we drop out of wake on lan mode in order to + * reset the Wake on lan features. This function doesn't restore + * the rest of the logic from the result of sleep/wakeup + */ + +static void mac_wol_reset(struct mac_regs __iomem * regs) +{ + + /* Turn off SWPTAG right after leaving power mode */ + BYTE_REG_BITS_OFF(STICKHW_SWPTAG, ®s->STICKHW); + /* clear sticky bits */ + BYTE_REG_BITS_OFF((STICKHW_DS1 | STICKHW_DS0), ®s->STICKHW); + + BYTE_REG_BITS_OFF(CHIPGCR_FCGMII, ®s->CHIPGCR); + BYTE_REG_BITS_OFF(CHIPGCR_FCMODE, ®s->CHIPGCR); + /* disable force PME-enable */ + writeb(WOLCFG_PMEOVR, ®s->WOLCFGClr); + /* disable power-event config bit */ + writew(0xFFFF, ®s->WOLCRClr); + /* clear power status */ + writew(0xFFFF, ®s->WOLSRClr); +} static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); static const struct ethtool_ops velocity_ethtool_ops; @@ -309,7 +466,7 @@ MODULE_DEVICE_TABLE(pci, velocity_id_table); * a pointer a static string valid while the driver is loaded. */ -static char __devinit *get_chip_name(enum chip_type chip_id) +static const char __devinit *get_chip_name(enum chip_type chip_id) { int i; for (i = 0; chip_info_table[i].name != NULL; i++) @@ -458,8 +615,8 @@ static void velocity_init_cam_filter(struct velocity_info *vptr) /* Disable all CAMs */ memset(vptr->vCAMmask, 0, sizeof(u8) * 8); memset(vptr->mCAMmask, 0, sizeof(u8) * 8); - mac_set_cam_mask(regs, vptr->vCAMmask, VELOCITY_VLAN_ID_CAM); - mac_set_cam_mask(regs, vptr->mCAMmask, VELOCITY_MULTICAST_CAM); + mac_set_vlan_cam_mask(regs, vptr->vCAMmask); + mac_set_cam_mask(regs, vptr->mCAMmask); /* Enable first VCAM */ if (vptr->vlgrp) { @@ -471,17 +628,16 @@ static void velocity_init_cam_filter(struct velocity_info *vptr) if (vid != 0) WORD_REG_BITS_ON(MCFG_RTGOPT, ®s->MCFG); - mac_set_cam(regs, 0, (u8 *) &vid, - VELOCITY_VLAN_ID_CAM); + mac_set_vlan_cam(regs, 0, (u8 *) &vid); } } vptr->vCAMmask[0] |= 1; - mac_set_cam_mask(regs, vptr->vCAMmask, VELOCITY_VLAN_ID_CAM); + mac_set_vlan_cam_mask(regs, vptr->vCAMmask); } else { u16 temp = 0; - mac_set_cam(regs, 0, (u8 *) &temp, VELOCITY_VLAN_ID_CAM); + mac_set_vlan_cam(regs, 0, (u8 *) &temp); temp = 1; - mac_set_cam_mask(regs, (u8 *) &temp, VELOCITY_VLAN_ID_CAM); + mac_set_vlan_cam_mask(regs, (u8 *) &temp); } } @@ -2131,14 +2287,14 @@ static void velocity_set_multi(struct net_device *dev) rx_mode = (RCR_AM | RCR_AB); } else { int offset = MCAM_SIZE - vptr->multicast_limit; - mac_get_cam_mask(regs, vptr->mCAMmask, VELOCITY_MULTICAST_CAM); + mac_get_cam_mask(regs, vptr->mCAMmask); for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) { - mac_set_cam(regs, i + offset, mclist->dmi_addr, VELOCITY_MULTICAST_CAM); + mac_set_cam(regs, i + offset, mclist->dmi_addr); vptr->mCAMmask[(offset + i) / 8] |= 1 << ((offset + i) & 7); } - mac_set_cam_mask(regs, vptr->mCAMmask, VELOCITY_MULTICAST_CAM); + mac_set_cam_mask(regs, vptr->mCAMmask); rx_mode = (RCR_AM | RCR_AB); } if (dev->mtu > 1500) diff --git a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h index af17161286a..aa9179623d9 100644 --- a/drivers/net/via-velocity.h +++ b/drivers/net/via-velocity.h @@ -1173,7 +1173,7 @@ enum chip_type { struct velocity_info_tbl { enum chip_type chip_id; - char *name; + const char *name; int txqueue; u32 flags; }; @@ -1194,14 +1194,6 @@ struct velocity_info_tbl { #define mac_disable_int(regs) writel(CR0_GINTMSK1,&((regs)->CR0Clr)) #define mac_enable_int(regs) writel(CR0_GINTMSK1,&((regs)->CR0Set)) -#define mac_hw_mibs_read(regs, MIBs) {\ - int i;\ - BYTE_REG_BITS_ON(MIBCR_MPTRINI,&((regs)->MIBCR));\ - for (i=0;iMIBData));\ - }\ -} - #define mac_set_dma_length(regs, n) {\ BYTE_REG_BITS_SET((n),0x07,&((regs)->DCFG));\ } @@ -1226,195 +1218,17 @@ struct velocity_info_tbl { writew(TRDCSR_WAK<<(n*4),&((regs)->TDCSRSet));\ } -#define mac_eeprom_reload(regs) {\ - int i=0;\ - BYTE_REG_BITS_ON(EECSR_RELOAD,&((regs)->EECSR));\ - do {\ - udelay(10);\ - if (i++>0x1000) {\ - break;\ - }\ - }while (BYTE_REG_BITS_IS_ON(EECSR_RELOAD,&((regs)->EECSR)));\ -} - -enum velocity_cam_type { - VELOCITY_VLAN_ID_CAM = 0, - VELOCITY_MULTICAST_CAM -}; - -/** - * mac_get_cam_mask - Read a CAM mask - * @regs: register block for this velocity - * @mask: buffer to store mask - * @cam_type: CAM to fetch - * - * Fetch the mask bits of the selected CAM and store them into the - * provided mask buffer. - */ - -static inline void mac_get_cam_mask(struct mac_regs __iomem * regs, u8 * mask, enum velocity_cam_type cam_type) -{ - int i; - /* Select CAM mask */ - BYTE_REG_BITS_SET(CAMCR_PS_CAM_MASK, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); - - if (cam_type == VELOCITY_VLAN_ID_CAM) - writeb(CAMADDR_VCAMSL, ®s->CAMADDR); - else - writeb(0, ®s->CAMADDR); - - /* read mask */ - for (i = 0; i < 8; i++) - *mask++ = readb(&(regs->MARCAM[i])); - - /* disable CAMEN */ - writeb(0, ®s->CAMADDR); - - /* Select mar */ - BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); - -} - -/** - * mac_set_cam_mask - Set a CAM mask - * @regs: register block for this velocity - * @mask: CAM mask to load - * @cam_type: CAM to store - * - * Store a new mask into a CAM - */ - -static inline void mac_set_cam_mask(struct mac_regs __iomem * regs, u8 * mask, enum velocity_cam_type cam_type) -{ - int i; - /* Select CAM mask */ - BYTE_REG_BITS_SET(CAMCR_PS_CAM_MASK, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); - - if (cam_type == VELOCITY_VLAN_ID_CAM) - writeb(CAMADDR_CAMEN | CAMADDR_VCAMSL, ®s->CAMADDR); - else - writeb(CAMADDR_CAMEN, ®s->CAMADDR); - - for (i = 0; i < 8; i++) { - writeb(*mask++, &(regs->MARCAM[i])); - } - /* disable CAMEN */ - writeb(0, ®s->CAMADDR); - - /* Select mar */ - BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); -} - -/** - * mac_set_cam - set CAM data - * @regs: register block of this velocity - * @idx: Cam index - * @addr: 2 or 6 bytes of CAM data - * @cam_type: CAM to load - * - * Load an address or vlan tag into a CAM - */ - -static inline void mac_set_cam(struct mac_regs __iomem * regs, int idx, u8 *addr, enum velocity_cam_type cam_type) -{ - int i; - - /* Select CAM mask */ - BYTE_REG_BITS_SET(CAMCR_PS_CAM_DATA, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); - - idx &= (64 - 1); - - if (cam_type == VELOCITY_VLAN_ID_CAM) - writeb(CAMADDR_CAMEN | CAMADDR_VCAMSL | idx, ®s->CAMADDR); - else - writeb(CAMADDR_CAMEN | idx, ®s->CAMADDR); - - if (cam_type == VELOCITY_VLAN_ID_CAM) - writew(*((u16 *) addr), ®s->MARCAM[0]); - else { - for (i = 0; i < 6; i++) { - writeb(*addr++, &(regs->MARCAM[i])); - } - } - BYTE_REG_BITS_ON(CAMCR_CAMWR, ®s->CAMCR); - - udelay(10); - - writeb(0, ®s->CAMADDR); - - /* Select mar */ - BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); -} - -/** - * mac_get_cam - fetch CAM data - * @regs: register block of this velocity - * @idx: Cam index - * @addr: buffer to hold up to 6 bytes of CAM data - * @cam_type: CAM to load - * - * Load an address or vlan tag from a CAM into the buffer provided by - * the caller. VLAN tags are 2 bytes the address cam entries are 6. - */ - -static inline void mac_get_cam(struct mac_regs __iomem * regs, int idx, u8 *addr, enum velocity_cam_type cam_type) -{ - int i; - - /* Select CAM mask */ - BYTE_REG_BITS_SET(CAMCR_PS_CAM_DATA, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); - - idx &= (64 - 1); - - if (cam_type == VELOCITY_VLAN_ID_CAM) - writeb(CAMADDR_CAMEN | CAMADDR_VCAMSL | idx, ®s->CAMADDR); - else - writeb(CAMADDR_CAMEN | idx, ®s->CAMADDR); - - BYTE_REG_BITS_ON(CAMCR_CAMRD, ®s->CAMCR); - - udelay(10); - - if (cam_type == VELOCITY_VLAN_ID_CAM) - *((u16 *) addr) = readw(&(regs->MARCAM[0])); - else - for (i = 0; i < 6; i++, addr++) - *((u8 *) addr) = readb(&(regs->MARCAM[i])); - - writeb(0, ®s->CAMADDR); - - /* Select mar */ - BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, ®s->CAMCR); -} - -/** - * mac_wol_reset - reset WOL after exiting low power - * @regs: register block of this velocity - * - * Called after we drop out of wake on lan mode in order to - * reset the Wake on lan features. This function doesn't restore - * the rest of the logic from the result of sleep/wakeup - */ - -static inline void mac_wol_reset(struct mac_regs __iomem * regs) -{ +static inline void mac_eeprom_reload(struct mac_regs __iomem * regs) { + int i=0; - /* Turn off SWPTAG right after leaving power mode */ - BYTE_REG_BITS_OFF(STICKHW_SWPTAG, ®s->STICKHW); - /* clear sticky bits */ - BYTE_REG_BITS_OFF((STICKHW_DS1 | STICKHW_DS0), ®s->STICKHW); - - BYTE_REG_BITS_OFF(CHIPGCR_FCGMII, ®s->CHIPGCR); - BYTE_REG_BITS_OFF(CHIPGCR_FCMODE, ®s->CHIPGCR); - /* disable force PME-enable */ - writeb(WOLCFG_PMEOVR, ®s->WOLCFGClr); - /* disable power-event config bit */ - writew(0xFFFF, ®s->WOLCRClr); - /* clear power status */ - writew(0xFFFF, ®s->WOLSRClr); + BYTE_REG_BITS_ON(EECSR_RELOAD,&(regs->EECSR)); + do { + udelay(10); + if (i++>0x1000) + break; + } while (BYTE_REG_BITS_IS_ON(EECSR_RELOAD,&(regs->EECSR))); } - /* * Header for WOL definitions. Used to compute hashes */ -- cgit v1.2.3-70-g09d2 From cdcc520d7b73445c3552a70786afed9a2b22c010 Mon Sep 17 00:00:00 2001 From: Chris Snook Date: Thu, 20 Sep 2007 15:57:15 -0400 Subject: atl1: explain 32-bit DMA restriction Document the fact that atl1 uses a single shared register for the high 32 bits of 64-bit DMA addresses, making 64-bit DMA more trouble than it's worth. Signed-off-by: Chris Snook Signed-off-by: Jeff Garzik --- drivers/net/atl1/atl1_main.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/atl1/atl1_main.c b/drivers/net/atl1/atl1_main.c index e1a9223d0c1..4c728f1169c 100644 --- a/drivers/net/atl1/atl1_main.c +++ b/drivers/net/atl1/atl1_main.c @@ -2209,8 +2209,14 @@ static int __devinit atl1_probe(struct pci_dev *pdev, return err; /* - * 64-bit DMA currently has data corruption problems, so let's just - * use 32-bit DMA for now. This is a big hack that is probably wrong. + * The atl1 chip can DMA to 64-bit addresses, but it uses a single + * shared register for the high 32 bits, so only a single, aligned, + * 4 GB physical address range can be used at a time. + * + * Supporting 64-bit DMA on this hardware is more trouble than it's + * worth. It is far easier to limit to 32-bit DMA than update + * various kernel subsystems to support the mechanics required by a + * fixed-high-32-bit system. */ err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); if (err) { -- cgit v1.2.3-70-g09d2 From 7c32f470f4f6a0fdc6944cefcd22f288e59a0ae2 Mon Sep 17 00:00:00 2001 From: Vitaly Bordug Date: Fri, 10 Aug 2007 14:05:16 -0700 Subject: PHY fixed driver: rework release path and update phy_id notation device_bind_driver() error code returning has been fixed. release() function has been written, so that to free resources in correct way; the release path is now clean. Before the rework, it used to cause Device 'fixed@100:1' does not have a release() function, it is broken and must be fixed. BUG: at drivers/base/core.c:104 device_release() Call Trace: [] kobject_cleanup+0x53/0x7e [] kobject_release+0x0/0x9 [] kref_put+0x74/0x81 [] fixed_mdio_register_device+0x230/0x265 [] fixed_init+0x1f/0x35 [] init+0x147/0x2fb [] schedule_tail+0x36/0x92 [] child_rip+0xa/0x12 [] acpi_ds_init_one_object+0x0/0x83 [] init+0x0/0x2fb [] child_rip+0x0/0x12 Also changed the notation of the fixed phy definition on mdio bus to the form of + to make it able to be used by gianfar and ucc_geth that define phy_id strictly as "%d:%d" and cleaned up the whitespace issues. Signed-off-by: Vitaly Bordug Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/phy/Kconfig | 14 +++ drivers/net/phy/fixed.c | 310 +++++++++++++++++++++++----------------------- include/linux/phy_fixed.h | 38 ++++++ 3 files changed, 207 insertions(+), 155 deletions(-) create mode 100644 include/linux/phy_fixed.h (limited to 'drivers') diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index dd09011c7ee..432c210513b 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -76,4 +76,18 @@ config FIXED_MII_100_FDX bool "Emulation for 100M Fdx fixed PHY behavior" depends on FIXED_PHY +config FIXED_MII_1000_FDX + bool "Emulation for 1000M Fdx fixed PHY behavior" + depends on FIXED_PHY + +config FIXED_MII_AMNT + int "Number of emulated PHYs to allocate " + depends on FIXED_PHY + default "1" + ---help--- + Sometimes it is required to have several independent emulated + PHYs on the bus (in case of multi-eth but phy-less HW for instance). + This control will have specified number allocated for each fixed + PHY type enabled. + endif # PHYLIB diff --git a/drivers/net/phy/fixed.c b/drivers/net/phy/fixed.c index bb966911a13..56191822fa2 100644 --- a/drivers/net/phy/fixed.c +++ b/drivers/net/phy/fixed.c @@ -30,53 +30,31 @@ #include #include #include +#include #include #include #include -#define MII_REGS_NUM 7 - -/* - The idea is to emulate normal phy behavior by responding with - pre-defined values to mii BMCR read, so that read_status hook could - take all the needed info. -*/ - -struct fixed_phy_status { - u8 link; - u16 speed; - u8 duplex; -}; - -/*----------------------------------------------------------------------------- - * Private information hoder for mii_bus - *-----------------------------------------------------------------------------*/ -struct fixed_info { - u16 *regs; - u8 regs_num; - struct fixed_phy_status phy_status; - struct phy_device *phydev; /* pointer to the container */ - /* link & speed cb */ - int(*link_update)(struct net_device*, struct fixed_phy_status*); - -}; +/* we need to track the allocated pointers in order to free them on exit */ +static struct fixed_info *fixed_phy_ptrs[CONFIG_FIXED_MII_AMNT*MAX_PHY_AMNT]; /*----------------------------------------------------------------------------- * If something weird is required to be done with link/speed, * network driver is able to assign a function to implement this. * May be useful for PHY's that need to be software-driven. *-----------------------------------------------------------------------------*/ -int fixed_mdio_set_link_update(struct phy_device* phydev, - int(*link_update)(struct net_device*, struct fixed_phy_status*)) +int fixed_mdio_set_link_update(struct phy_device *phydev, + int (*link_update) (struct net_device *, + struct fixed_phy_status *)) { struct fixed_info *fixed; - if(link_update == NULL) + if (link_update == NULL) return -EINVAL; - if(phydev) { - if(phydev->bus) { + if (phydev) { + if (phydev->bus) { fixed = phydev->bus->priv; fixed->link_update = link_update; return 0; @@ -84,54 +62,64 @@ int fixed_mdio_set_link_update(struct phy_device* phydev, } return -EINVAL; } + EXPORT_SYMBOL(fixed_mdio_set_link_update); +struct fixed_info *fixed_mdio_get_phydev (int phydev_ind) +{ + if (phydev_ind >= MAX_PHY_AMNT) + return NULL; + return fixed_phy_ptrs[phydev_ind]; +} + +EXPORT_SYMBOL(fixed_mdio_get_phydev); + /*----------------------------------------------------------------------------- * This is used for updating internal mii regs from the status *-----------------------------------------------------------------------------*/ -#if defined(CONFIG_FIXED_MII_100_FDX) || defined(CONFIG_FIXED_MII_10_FDX) +#if defined(CONFIG_FIXED_MII_100_FDX) || defined(CONFIG_FIXED_MII_10_FDX) || defined(CONFIG_FIXED_MII_1000_FDX) static int fixed_mdio_update_regs(struct fixed_info *fixed) { u16 *regs = fixed->regs; u16 bmsr = 0; u16 bmcr = 0; - if(!regs) { + if (!regs) { printk(KERN_ERR "%s: regs not set up", __FUNCTION__); return -EINVAL; } - if(fixed->phy_status.link) + if (fixed->phy_status.link) bmsr |= BMSR_LSTATUS; - if(fixed->phy_status.duplex) { + if (fixed->phy_status.duplex) { bmcr |= BMCR_FULLDPLX; - switch ( fixed->phy_status.speed ) { + switch (fixed->phy_status.speed) { case 100: bmsr |= BMSR_100FULL; bmcr |= BMCR_SPEED100; - break; + break; case 10: bmsr |= BMSR_10FULL; - break; + break; } } else { - switch ( fixed->phy_status.speed ) { + switch (fixed->phy_status.speed) { case 100: bmsr |= BMSR_100HALF; bmcr |= BMCR_SPEED100; - break; + break; case 10: bmsr |= BMSR_100HALF; - break; + break; } } - regs[MII_BMCR] = bmcr; - regs[MII_BMSR] = bmsr | 0x800; /*we are always capable of 10 hdx*/ + regs[MII_BMCR] = bmcr; + regs[MII_BMSR] = bmsr | 0x800; /*we are always capable of 10 hdx */ return 0; } @@ -141,29 +129,30 @@ static int fixed_mii_read(struct mii_bus *bus, int phy_id, int location) struct fixed_info *fixed = bus->priv; /* if user has registered link update callback, use it */ - if(fixed->phydev) - if(fixed->phydev->attached_dev) { - if(fixed->link_update) { + if (fixed->phydev) + if (fixed->phydev->attached_dev) { + if (fixed->link_update) { fixed->link_update(fixed->phydev->attached_dev, - &fixed->phy_status); + &fixed->phy_status); fixed_mdio_update_regs(fixed); } - } + } if ((unsigned int)location >= fixed->regs_num) return -1; return fixed->regs[location]; } -static int fixed_mii_write(struct mii_bus *bus, int phy_id, int location, u16 val) +static int fixed_mii_write(struct mii_bus *bus, int phy_id, int location, + u16 val) { - /* do nothing for now*/ + /* do nothing for now */ return 0; } static int fixed_mii_reset(struct mii_bus *bus) { - /*nothing here - no way/need to reset it*/ + /*nothing here - no way/need to reset it */ return 0; } #endif @@ -171,8 +160,8 @@ static int fixed_mii_reset(struct mii_bus *bus) static int fixed_config_aneg(struct phy_device *phydev) { /* :TODO:03/13/2006 09:45:37 PM:: - The full autoneg funcionality can be emulated, - but no need to have anything here for now + The full autoneg funcionality can be emulated, + but no need to have anything here for now */ return 0; } @@ -182,59 +171,79 @@ static int fixed_config_aneg(struct phy_device *phydev) * match will never return true... *-----------------------------------------------------------------------------*/ static struct phy_driver fixed_mdio_driver = { - .name = "Fixed PHY", - .features = PHY_BASIC_FEATURES, - .config_aneg = fixed_config_aneg, - .read_status = genphy_read_status, - .driver = { .owner = THIS_MODULE,}, + .name = "Fixed PHY", +#ifdef CONFIG_FIXED_MII_1000_FDX + .features = PHY_GBIT_FEATURES, +#else + .features = PHY_BASIC_FEATURES, +#endif + .config_aneg = fixed_config_aneg, + .read_status = genphy_read_status, + .driver = { .owner = THIS_MODULE, }, }; +static void fixed_mdio_release(struct device *dev) +{ + struct phy_device *phydev = container_of(dev, struct phy_device, dev); + struct mii_bus *bus = phydev->bus; + struct fixed_info *fixed = bus->priv; + + kfree(phydev); + kfree(bus->dev); + kfree(bus); + kfree(fixed->regs); + kfree(fixed); +} + /*----------------------------------------------------------------------------- * This func is used to create all the necessary stuff, bind * the fixed phy driver and register all it on the mdio_bus_type. - * speed is either 10 or 100, duplex is boolean. + * speed is either 10 or 100 or 1000, duplex is boolean. * number is used to create multiple fixed PHYs, so that several devices can * utilize them simultaneously. + * + * The device on mdio bus will look like [bus_id]:[phy_id], + * bus_id = number + * phy_id = speed+duplex. *-----------------------------------------------------------------------------*/ -#if defined(CONFIG_FIXED_MII_100_FDX) || defined(CONFIG_FIXED_MII_10_FDX) -static int fixed_mdio_register_device(int number, int speed, int duplex) +#if defined(CONFIG_FIXED_MII_100_FDX) || defined(CONFIG_FIXED_MII_10_FDX) || defined(CONFIG_FIXED_MII_1000_FDX) +struct fixed_info *fixed_mdio_register_device( + int bus_id, int speed, int duplex, u8 phy_id) { struct mii_bus *new_bus; struct fixed_info *fixed; struct phy_device *phydev; - int err = 0; + int err; - struct device* dev = kzalloc(sizeof(struct device), GFP_KERNEL); + struct device *dev = kzalloc(sizeof(struct device), GFP_KERNEL); - if (NULL == dev) - return -ENOMEM; + if (dev == NULL) + goto err_dev_alloc; new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL); - if (NULL == new_bus) { - kfree(dev); - return -ENOMEM; - } + if (new_bus == NULL) + goto err_bus_alloc; + fixed = kzalloc(sizeof(struct fixed_info), GFP_KERNEL); - if (NULL == fixed) { - kfree(dev); - kfree(new_bus); - return -ENOMEM; - } + if (fixed == NULL) + goto err_fixed_alloc; + + fixed->regs = kzalloc(MII_REGS_NUM * sizeof(int), GFP_KERNEL); + if (NULL == fixed->regs) + goto err_fixed_regs_alloc; - fixed->regs = kzalloc(MII_REGS_NUM*sizeof(int), GFP_KERNEL); fixed->regs_num = MII_REGS_NUM; fixed->phy_status.speed = speed; fixed->phy_status.duplex = duplex; fixed->phy_status.link = 1; - new_bus->name = "Fixed MII Bus", - new_bus->read = &fixed_mii_read, - new_bus->write = &fixed_mii_write, - new_bus->reset = &fixed_mii_reset, - - /*set up workspace*/ + new_bus->name = "Fixed MII Bus"; + new_bus->read = &fixed_mii_read; + new_bus->write = &fixed_mii_write; + new_bus->reset = &fixed_mii_reset; + /*set up workspace */ fixed_mdio_update_regs(fixed); new_bus->priv = fixed; @@ -243,119 +252,110 @@ static int fixed_mdio_register_device(int number, int speed, int duplex) /* create phy_device and register it on the mdio bus */ phydev = phy_device_create(new_bus, 0, 0); + if (phydev == NULL) + goto err_phy_dev_create; /* - Put the phydev pointer into the fixed pack so that bus read/write code could - be able to access for instance attached netdev. Well it doesn't have to do - so, only in case of utilizing user-specified link-update... + * Put the phydev pointer into the fixed pack so that bus read/write + * code could be able to access for instance attached netdev. Well it + * doesn't have to do so, only in case of utilizing user-specified + * link-update... */ - fixed->phydev = phydev; - if(NULL == phydev) { - err = -ENOMEM; - goto device_create_fail; - } + fixed->phydev = phydev; + phydev->speed = speed; + phydev->duplex = duplex; phydev->irq = PHY_IGNORE_INTERRUPT; phydev->dev.bus = &mdio_bus_type; - if(number) - snprintf(phydev->dev.bus_id, BUS_ID_SIZE, - "fixed_%d@%d:%d", number, speed, duplex); - else - snprintf(phydev->dev.bus_id, BUS_ID_SIZE, - "fixed@%d:%d", speed, duplex); - phydev->bus = new_bus; + snprintf(phydev->dev.bus_id, BUS_ID_SIZE, + PHY_ID_FMT, bus_id, phy_id); - err = device_register(&phydev->dev); - if(err) { - printk(KERN_ERR "Phy %s failed to register\n", - phydev->dev.bus_id); - goto bus_register_fail; - } + phydev->bus = new_bus; - /* - the mdio bus has phy_id match... In order not to do it - artificially, we are binding the driver here by hand; - it will be the same for all the fixed phys anyway. - */ phydev->dev.driver = &fixed_mdio_driver.driver; - + phydev->dev.release = fixed_mdio_release; err = phydev->dev.driver->probe(&phydev->dev); - if(err < 0) { - printk(KERN_ERR "Phy %s: problems with fixed driver\n",phydev->dev.bus_id); - goto probe_fail; + if (err < 0) { + printk(KERN_ERR "Phy %s: problems with fixed driver\n", + phydev->dev.bus_id); + goto err_out; } + err = device_register(&phydev->dev); + if (err) { + printk(KERN_ERR "Phy %s failed to register\n", + phydev->dev.bus_id); + goto err_out; + } + //phydev->state = PHY_RUNNING; /* make phy go up quick, but in 10Mbit/HDX + return fixed; - err = device_bind_driver(&phydev->dev); - if (err) - goto probe_fail; - - return 0; - -probe_fail: - device_unregister(&phydev->dev); -bus_register_fail: +err_out: kfree(phydev); -device_create_fail: - kfree(dev); - kfree(new_bus); +err_phy_dev_create: + kfree(fixed->regs); +err_fixed_regs_alloc: kfree(fixed); +err_fixed_alloc: + kfree(new_bus); +err_bus_alloc: + kfree(dev); +err_dev_alloc: + + return NULL; - return err; } #endif - MODULE_DESCRIPTION("Fixed PHY device & driver for PAL"); MODULE_AUTHOR("Vitaly Bordug"); MODULE_LICENSE("GPL"); static int __init fixed_init(void) { -#if 0 - int ret; - int duplex = 0; -#endif - - /* register on the bus... Not expected to be matched with anything there... */ + int cnt = 0; + int i; +/* register on the bus... Not expected to be matched + * with anything there... + * + */ phy_driver_register(&fixed_mdio_driver); - /* So let the fun begin... - We will create several mdio devices here, and will bound the upper - driver to them. - - Then the external software can lookup the phy bus by searching - fixed@speed:duplex, e.g. fixed@100:1, to be connected to the - virtual 100M Fdx phy. - - In case several virtual PHYs required, the bus_id will be in form - fixed_@:, which make it able even to define - driver-specific link control callback, if for instance PHY is completely - SW-driven. - - */ - -#ifdef CONFIG_FIXED_MII_DUPLEX -#if 0 - duplex = 1; -#endif +/* We will create several mdio devices here, and will bound the upper + * driver to them. + * + * Then the external software can lookup the phy bus by searching + * for 0:101, to be connected to the virtual 100M Fdx phy. + * + * In case several virtual PHYs required, the bus_id will be in form + * [num]:[duplex]+[speed], which make it able even to define + * driver-specific link control callback, if for instance PHY is + * completely SW-driven. + */ + for (i=1; i <= CONFIG_FIXED_MII_AMNT; i++) { +#ifdef CONFIG_FIXED_MII_1000_FDX + fixed_phy_ptrs[cnt++] = fixed_mdio_register_device(0, 1000, 1, i); #endif - #ifdef CONFIG_FIXED_MII_100_FDX - fixed_mdio_register_device(0, 100, 1); + fixed_phy_ptrs[cnt++] = fixed_mdio_register_device(1, 100, 1, i); #endif - #ifdef CONFIG_FIXED_MII_10_FDX - fixed_mdio_register_device(0, 10, 1); + fixed_phy_ptrs[cnt++] = fixed_mdio_register_device(2, 10, 1, i); #endif + } + return 0; } static void __exit fixed_exit(void) { + int i; + phy_driver_unregister(&fixed_mdio_driver); - /* :WARNING:02/18/2006 04:32:40 AM:: Cleanup all the created stuff */ + for (i=0; i < MAX_PHY_AMNT; i++) + if ( fixed_phy_ptrs[i] ) + device_unregister(&fixed_phy_ptrs[i]->phydev->dev); } module_init(fixed_init); diff --git a/include/linux/phy_fixed.h b/include/linux/phy_fixed.h new file mode 100644 index 00000000000..04ba70d49fb --- /dev/null +++ b/include/linux/phy_fixed.h @@ -0,0 +1,38 @@ +#ifndef __PHY_FIXED_H +#define __PHY_FIXED_H + +#define MII_REGS_NUM 29 + +/* max number of virtual phy stuff */ +#define MAX_PHY_AMNT 10 +/* + The idea is to emulate normal phy behavior by responding with + pre-defined values to mii BMCR read, so that read_status hook could + take all the needed info. +*/ + +struct fixed_phy_status { + u8 link; + u16 speed; + u8 duplex; +}; + +/*----------------------------------------------------------------------------- + * Private information hoder for mii_bus + *-----------------------------------------------------------------------------*/ +struct fixed_info { + u16 *regs; + u8 regs_num; + struct fixed_phy_status phy_status; + struct phy_device *phydev; /* pointer to the container */ + /* link & speed cb */ + int (*link_update) (struct net_device *, struct fixed_phy_status *); + +}; + + +int fixed_mdio_set_link_update(struct phy_device *, + int (*link_update) (struct net_device *, struct fixed_phy_status *)); +struct fixed_info *fixed_mdio_get_phydev (int phydev_ind); + +#endif /* __PHY_FIXED_H */ -- cgit v1.2.3-70-g09d2 From 007755eb86c3953bb8615bd016246fc99056580c Mon Sep 17 00:00:00 2001 From: Peter Oruba Date: Fri, 28 Sep 2007 22:42:06 -0700 Subject: PCI-X/PCI-Express read control interfaces: use them in e1000 These driver changes incorporate the proposed PCI-X / PCI-Express read byte count interface. Reading and setting those valuse doesn't take place "manually", instead wrapping functions are called to allow quirks for some PCI bridges. Signed-off by: Peter Oruba Based on work by Stephen Hemminger Acked-by: Auke Kok Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000_hw.c | 25 +++---------------------- drivers/net/e1000/e1000_hw.h | 2 ++ drivers/net/e1000/e1000_main.c | 14 ++++++++++++++ 3 files changed, 19 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index 8604adbe351..8fa0fe4009d 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -871,10 +871,6 @@ e1000_init_hw(struct e1000_hw *hw) uint32_t ctrl; uint32_t i; int32_t ret_val; - uint16_t pcix_cmd_word; - uint16_t pcix_stat_hi_word; - uint16_t cmd_mmrbc; - uint16_t stat_mmrbc; uint32_t mta_size; uint32_t reg_data; uint32_t ctrl_ext; @@ -964,24 +960,9 @@ e1000_init_hw(struct e1000_hw *hw) break; default: /* Workaround for PCI-X problem when BIOS sets MMRBC incorrectly. */ - if (hw->bus_type == e1000_bus_type_pcix) { - e1000_read_pci_cfg(hw, PCIX_COMMAND_REGISTER, &pcix_cmd_word); - e1000_read_pci_cfg(hw, PCIX_STATUS_REGISTER_HI, - &pcix_stat_hi_word); - cmd_mmrbc = (pcix_cmd_word & PCIX_COMMAND_MMRBC_MASK) >> - PCIX_COMMAND_MMRBC_SHIFT; - stat_mmrbc = (pcix_stat_hi_word & PCIX_STATUS_HI_MMRBC_MASK) >> - PCIX_STATUS_HI_MMRBC_SHIFT; - if (stat_mmrbc == PCIX_STATUS_HI_MMRBC_4K) - stat_mmrbc = PCIX_STATUS_HI_MMRBC_2K; - if (cmd_mmrbc > stat_mmrbc) { - pcix_cmd_word &= ~PCIX_COMMAND_MMRBC_MASK; - pcix_cmd_word |= stat_mmrbc << PCIX_COMMAND_MMRBC_SHIFT; - e1000_write_pci_cfg(hw, PCIX_COMMAND_REGISTER, - &pcix_cmd_word); - } - } - break; + if (hw->bus_type == e1000_bus_type_pcix && e1000_pcix_get_mmrbc(hw) > 2048) + e1000_pcix_set_mmrbc(hw, 2048); + break; } /* More time needed for PHY to initialize */ diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h index 07f0ea73676..a2a86c54a75 100644 --- a/drivers/net/e1000/e1000_hw.h +++ b/drivers/net/e1000/e1000_hw.h @@ -424,6 +424,8 @@ void e1000_pci_clear_mwi(struct e1000_hw *hw); void e1000_read_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t * value); void e1000_write_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t * value); int32_t e1000_read_pcie_cap_reg(struct e1000_hw *hw, uint32_t reg, uint16_t *value); +void e1000_pcix_set_mmrbc(struct e1000_hw *hw, int mmrbc); +int e1000_pcix_get_mmrbc(struct e1000_hw *hw); /* Port I/O is only supported on 82544 and newer */ void e1000_io_write(struct e1000_hw *hw, unsigned long port, uint32_t value); int32_t e1000_disable_pciex_master(struct e1000_hw *hw); diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index ad444c9a5d0..10505de00bc 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -4903,6 +4903,20 @@ e1000_write_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t *value) pci_write_config_word(adapter->pdev, reg, *value); } +int +e1000_pcix_get_mmrbc(struct e1000_hw *hw) +{ + struct e1000_adapter *adapter = hw->back; + return pcix_get_mmrbc(adapter->pdev); +} + +void +e1000_pcix_set_mmrbc(struct e1000_hw *hw, int mmrbc) +{ + struct e1000_adapter *adapter = hw->back; + pcix_set_mmrbc(adapter->pdev, mmrbc); +} + int32_t e1000_read_pcie_cap_reg(struct e1000_hw *hw, uint32_t reg, uint16_t *value) { -- cgit v1.2.3-70-g09d2 From 0da18e3883d18ac716ad8cc07df9bd30933807ac Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Fri, 28 Sep 2007 22:42:06 -0700 Subject: drivers/net/cxgb3/xgmac.c: remove dead code This patch removes dead code ("tx_xcnt" can never be != 0 at this place) spotted by the Coverity checker. Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/cxgb3/xgmac.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/cxgb3/xgmac.c b/drivers/net/cxgb3/xgmac.c index ff9e9dcbd87..bcb5bc4e649 100644 --- a/drivers/net/cxgb3/xgmac.c +++ b/drivers/net/cxgb3/xgmac.c @@ -522,10 +522,7 @@ int t3b2_mac_watchdog_task(struct cmac *mac) goto rxcheck; } - if (((tx_tcnt != mac->tx_tcnt) && - (tx_xcnt == 0) && (mac->tx_xcnt == 0)) || - ((mac->tx_mcnt == tx_mcnt) && - (tx_xcnt != 0) && (mac->tx_xcnt != 0))) { + if ((tx_tcnt != mac->tx_tcnt) && (mac->tx_xcnt == 0)) { if (mac->toggle_cnt > 4) { status = 2; goto out; -- cgit v1.2.3-70-g09d2 From bcfef8c3681fa59b653871682956a8fdf5c27c5a Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Fri, 28 Sep 2007 22:42:09 -0700 Subject: Avoid possible NULL pointer deref in 3c359 driver In xl_freemem(), if dev_if is NULL, the line struct xl_private *xl_priv =(struct xl_private *)dev->priv; will cause a NULL pointer dereference. (akpm: don't try to fix it: just delete the pointless test-for-null) Signed-off-by: Jesper Juhl Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/tokenring/3c359.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c index 88d03c085d5..7224d368b2a 100644 --- a/drivers/net/tokenring/3c359.c +++ b/drivers/net/tokenring/3c359.c @@ -1045,11 +1045,6 @@ static irqreturn_t xl_interrupt(int irq, void *dev_id) u8 __iomem * xl_mmio = xl_priv->xl_mmio ; u16 intstatus, macstatus ; - if (!dev) { - printk(KERN_WARNING "Device structure dead, aaahhhh !\n") ; - return IRQ_NONE; - } - intstatus = readw(xl_mmio + MMIO_INTSTATUS) ; if (!(intstatus & 1)) /* We didn't generate the interrupt */ -- cgit v1.2.3-70-g09d2 From 13f7b8c011cd8d16ad3063409b9d969466c9e2f4 Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Fri, 28 Sep 2007 22:42:10 -0700 Subject: skge: remove broken and unused PHY_M_PC_MDI_XMODE macro Signed-off-by: Mariusz Kozlowski Cc: Stephen Hemminger Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/skge.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/skge.h b/drivers/net/skge.h index dd0fd45c715..1a57bdd1ddf 100644 --- a/drivers/net/skge.h +++ b/drivers/net/skge.h @@ -1351,8 +1351,6 @@ enum { PHY_M_PC_EN_DET_PLUS = 3<<8, /* Energy Detect Plus (Mode 2) */ }; -#define PHY_M_PC_MDI_XMODE(x) ((((u16)(x)<<5) & PHY_M_PC_MDIX_MSK) - enum { PHY_M_PC_MAN_MDI = 0, /* 00 = Manual MDI configuration */ PHY_M_PC_MAN_MDIX = 1, /* 01 = Manual MDIX configuration */ -- cgit v1.2.3-70-g09d2 From 1f8f4559f8c5829348a010a9e0bbb423310060d1 Mon Sep 17 00:00:00 2001 From: Micah Gruber Date: Fri, 28 Sep 2007 22:42:11 -0700 Subject: Fix a potential NULL pointer dereference in uli526x_interrupt() in drivers/net/tulip/uli526x.c This patch fixes an apparent potential null dereference bug where we dereference dev before a null check. This patch simply remvoes the can't-happen test for a null pointer. Signed-off-by: Micah Gruber Cc: Grant Grundler Acked-by: Jeff Garzik Acked-by: Kyle McMartin Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/tulip/uli526x.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c index e64bde46822..76e55612430 100644 --- a/drivers/net/tulip/uli526x.c +++ b/drivers/net/tulip/uli526x.c @@ -664,11 +664,6 @@ static irqreturn_t uli526x_interrupt(int irq, void *dev_id) unsigned long ioaddr = dev->base_addr; unsigned long flags; - if (!dev) { - ULI526X_DBUG(1, "uli526x_interrupt() without DEVICE arg", 0); - return IRQ_NONE; - } - spin_lock_irqsave(&db->lock, flags); outl(0, ioaddr + DCR7); -- cgit v1.2.3-70-g09d2 From 9ff8c68b3c722f732c7a13d6631b149cca8c7091 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Fri, 28 Sep 2007 22:42:12 -0700 Subject: PHYLIB: Spinlock fixes for softirqs Use spin_lock_bh()/spin_unlock_bh() for the phydev lock throughout as it is used in phy_timer() that is called as a softirq and all the other operations may happen in the user context. There has been a change recently that did such a conversion for some of the operations on the lock, but some have been left intact. Many of them, perhaps all, may be called in the user context and I was able to trigger recursive spinlock acquisition indeed, so I think for the sake of long-term maintenance it is best to convert them all, even if unnecessarily for one or two -- better safe than sorry. Perhaps one in phy_timer() could actually be skipped as only called as a softirq -- I can send an update if that sounds like a good idea. Checked with checkpatch.pl and at the runtime. Signed-off-by: Maciej W. Rozycki Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/phy/phy.c | 24 ++++++++++++------------ drivers/net/phy/phy_device.c | 4 ++-- 2 files changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 17c1e1555d8..4da993dfcfd 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -424,7 +424,7 @@ int phy_start_aneg(struct phy_device *phydev) { int err; - spin_lock(&phydev->lock); + spin_lock_bh(&phydev->lock); if (AUTONEG_DISABLE == phydev->autoneg) phy_sanitize_settings(phydev); @@ -445,7 +445,7 @@ int phy_start_aneg(struct phy_device *phydev) } out_unlock: - spin_unlock(&phydev->lock); + spin_unlock_bh(&phydev->lock); return err; } EXPORT_SYMBOL(phy_start_aneg); @@ -490,10 +490,10 @@ void phy_stop_machine(struct phy_device *phydev) { del_timer_sync(&phydev->phy_timer); - spin_lock(&phydev->lock); + spin_lock_bh(&phydev->lock); if (phydev->state > PHY_UP) phydev->state = PHY_UP; - spin_unlock(&phydev->lock); + spin_unlock_bh(&phydev->lock); phydev->adjust_state = NULL; } @@ -537,9 +537,9 @@ static void phy_force_reduction(struct phy_device *phydev) */ void phy_error(struct phy_device *phydev) { - spin_lock(&phydev->lock); + spin_lock_bh(&phydev->lock); phydev->state = PHY_HALTED; - spin_unlock(&phydev->lock); + spin_unlock_bh(&phydev->lock); } /** @@ -690,10 +690,10 @@ static void phy_change(struct work_struct *work) if (err) goto phy_err; - spin_lock(&phydev->lock); + spin_lock_bh(&phydev->lock); if ((PHY_RUNNING == phydev->state) || (PHY_NOLINK == phydev->state)) phydev->state = PHY_CHANGELINK; - spin_unlock(&phydev->lock); + spin_unlock_bh(&phydev->lock); enable_irq(phydev->irq); @@ -718,7 +718,7 @@ phy_err: */ void phy_stop(struct phy_device *phydev) { - spin_lock(&phydev->lock); + spin_lock_bh(&phydev->lock); if (PHY_HALTED == phydev->state) goto out_unlock; @@ -734,7 +734,7 @@ void phy_stop(struct phy_device *phydev) } out_unlock: - spin_unlock(&phydev->lock); + spin_unlock_bh(&phydev->lock); /* * Cannot call flush_scheduled_work() here as desired because @@ -782,7 +782,7 @@ static void phy_timer(unsigned long data) int needs_aneg = 0; int err = 0; - spin_lock(&phydev->lock); + spin_lock_bh(&phydev->lock); if (phydev->adjust_state) phydev->adjust_state(phydev->attached_dev); @@ -948,7 +948,7 @@ static void phy_timer(unsigned long data) break; } - spin_unlock(&phydev->lock); + spin_unlock_bh(&phydev->lock); if (needs_aneg) err = phy_start_aneg(phydev); diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 49328e05050..c0461217b10 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -670,9 +670,9 @@ static int phy_remove(struct device *dev) phydev = to_phy_device(dev); - spin_lock(&phydev->lock); + spin_lock_bh(&phydev->lock); phydev->state = PHY_DOWN; - spin_unlock(&phydev->lock); + spin_unlock_bh(&phydev->lock); if (phydev->drv->remove) phydev->drv->remove(phydev); -- cgit v1.2.3-70-g09d2 From f7ab697d328b0a417d9e3cb891d45693ea89e83d Mon Sep 17 00:00:00 2001 From: Ed Swierk Date: Fri, 28 Sep 2007 22:42:13 -0700 Subject: forcedeth: "no link" is informational Log "no link during initialization" at KERN_INFO as it's not an error, and occurs every time the interface comes up (when the forcedeth-phy-power-down patch is applied). Signed-off-by: Ed Swierk Cc: Ayaz Abdulla Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/forcedeth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 666de42e5a7..dae30b73134 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -4917,7 +4917,7 @@ static int nv_open(struct net_device *dev) if (ret) { netif_carrier_on(dev); } else { - printk("%s: no link during initialization.\n", dev->name); + printk(KERN_INFO "%s: no link during initialization.\n", dev->name); netif_carrier_off(dev); } if (oom) -- cgit v1.2.3-70-g09d2 From 0ac49527318bc388a881152d60f49d7951606024 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Fri, 28 Sep 2007 22:42:14 -0700 Subject: PHYLIB: IRQ event workqueue handling fixes Keep track of disable_irq_nosync() invocations and call enable_irq() the right number of times if work has been cancelled that would include them. Now that the call to flush_work_keventd() (problematic because of rtnl_mutex being held) has been replaced by cancel_work_sync() another issue has arisen and been left unresolved. As the MDIO bus cannot be accessed from the interrupt context the PHY interrupt handler uses disable_irq_nosync() to prevent from looping and schedules some work to be done as a softirq, which, apart from handling the state change of the originating PHY, is responsible for reenabling the interrupt. Now if the interrupt line is shared by another device and a call to the softirq handler has been cancelled, that call to enable_irq() never happens and the other device cannot use its interrupt anymore as its stuck disabled. I decided to use a counter rather than a flag because there may be more than one call to phy_change() cancelled in the queue -- a real one and a fake one triggered by free_irq() if DEBUG_SHIRQ is used, if nothing else. Therefore because of its nesting property enable_irq() has to be called the right number of times to match the number disable_irq_nosync() was called and restore the original state. This DEBUG_SHIRQ feature is also the reason why free_irq() has to be called before cancel_work_sync(). While at it I updated the comment about phy_stop_interrupts() being called from `keventd' -- this is no longer relevant as the use of cancel_work_sync() makes such an approach unnecessary. OTOH a similar comment referring to flush_scheduled_work() in phy_stop() still applies as using cancel_work_sync() there would be dangerous. Checked with checkpatch.pl and at the run time (with and without DEBUG_SHIRQ). Signed-off-by: Maciej W. Rozycki Cc: Andy Fleming Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/phy/phy.c | 24 +++++++++++++++++++----- include/linux/phy.h | 3 +++ 2 files changed, 22 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 4da993dfcfd..5a314edc274 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -7,7 +7,7 @@ * Author: Andy Fleming * * Copyright (c) 2004 Freescale Semiconductor, Inc. - * Copyright (c) 2006 Maciej W. Rozycki + * Copyright (c) 2006, 2007 Maciej W. Rozycki * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -35,6 +35,7 @@ #include #include +#include #include #include #include @@ -562,6 +563,7 @@ static irqreturn_t phy_interrupt(int irq, void *phy_dat) * queue will write the PHY to disable and clear the * interrupt, and then reenable the irq line. */ disable_irq_nosync(irq); + atomic_inc(&phydev->irq_disable); schedule_work(&phydev->phy_queue); @@ -632,6 +634,7 @@ int phy_start_interrupts(struct phy_device *phydev) INIT_WORK(&phydev->phy_queue, phy_change); + atomic_set(&phydev->irq_disable, 0); if (request_irq(phydev->irq, phy_interrupt, IRQF_SHARED, "phy_interrupt", @@ -662,13 +665,22 @@ int phy_stop_interrupts(struct phy_device *phydev) if (err) phy_error(phydev); + free_irq(phydev->irq, phydev); + /* - * Finish any pending work; we might have been scheduled to be called - * from keventd ourselves, but cancel_work_sync() handles that. + * Cannot call flush_scheduled_work() here as desired because + * of rtnl_lock(), but we do not really care about what would + * be done, except from enable_irq(), so cancel any work + * possibly pending and take care of the matter below. */ cancel_work_sync(&phydev->phy_queue); - - free_irq(phydev->irq, phydev); + /* + * If work indeed has been cancelled, disable_irq() will have + * been left unbalanced from phy_interrupt() and enable_irq() + * has to be called so that other devices on the line work. + */ + while (atomic_dec_return(&phydev->irq_disable) >= 0) + enable_irq(phydev->irq); return err; } @@ -695,6 +707,7 @@ static void phy_change(struct work_struct *work) phydev->state = PHY_CHANGELINK; spin_unlock_bh(&phydev->lock); + atomic_dec(&phydev->irq_disable); enable_irq(phydev->irq); /* Reenable interrupts */ @@ -708,6 +721,7 @@ static void phy_change(struct work_struct *work) irq_enable_err: disable_irq(phydev->irq); + atomic_inc(&phydev->irq_disable); phy_err: phy_error(phydev); } diff --git a/include/linux/phy.h b/include/linux/phy.h index 2a659789f9c..f0742b6aaa6 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -25,6 +25,8 @@ #include #include +#include + #define PHY_BASIC_FEATURES (SUPPORTED_10baseT_Half | \ SUPPORTED_10baseT_Full | \ SUPPORTED_100baseT_Half | \ @@ -281,6 +283,7 @@ struct phy_device { /* Interrupt and Polling infrastructure */ struct work_struct phy_queue; struct timer_list phy_timer; + atomic_t irq_disable; spinlock_t lock; -- cgit v1.2.3-70-g09d2 From 6daf65310374d24d888201b7a6eba90b44008b7b Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Fri, 28 Sep 2007 22:42:15 -0700 Subject: PHYLIB: fix an interrupt loop potential when halting Ensure the PHY_HALTED state is not entered with the IRQ asserted as it could lead to an interrupt loop. There is a small window in phy_stop(), where the state of the PHY machine indicates it has been halted, but its interrupt output might still be unmasked. If an interrupt goes active right at this moment it will loop as the phy_interrupt() handler exits immediately with IRQ_NONE if the halted state is seen. It is unsafe to extend the phydev spinlock to cover phy_interrupt(). It is safe to swap the order of the actions though as all the competing places to unmask the interrupt output of the PHY, which are phy_change() and phy_timer() are already covered with the lock as is the sequence in question. Signed-off-by: Maciej W. Rozycki Cc: Andy Fleming Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/phy/phy.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 5a314edc274..9bc11773705 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -737,8 +737,6 @@ void phy_stop(struct phy_device *phydev) if (PHY_HALTED == phydev->state) goto out_unlock; - phydev->state = PHY_HALTED; - if (phydev->irq != PHY_POLL) { /* Disable PHY Interrupts */ phy_config_interrupt(phydev, PHY_INTERRUPT_DISABLED); @@ -747,6 +745,8 @@ void phy_stop(struct phy_device *phydev) phy_clear_interrupt(phydev); } + phydev->state = PHY_HALTED; + out_unlock: spin_unlock_bh(&phydev->lock); -- cgit v1.2.3-70-g09d2 From 89e536a190f90d038bae7905a0c582cb7089b739 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Fri, 28 Sep 2007 22:42:16 -0700 Subject: ax88796: add 93cx6 eeprom support Hook up the 93cx6 eeprom code to the ax88796 driver and modify the ax88796 driver to read out the mac address from the eeprom. We need this for the ax88796 on certain SuperH boards. The pin configuration used to connect the eeprom to the ax88796 on these boards is the same as pointed out by the ax88796 datasheet, so we can probably reuse this code for multiple platforms in the future. Signed-off-by: Magnus Damm Cc: Ben Dooks Cc: Paul Mundt Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/Kconfig | 7 +++++++ drivers/net/ax88796.c | 49 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/eeprom_93cx6.h | 3 ++- include/net/ax88796.h | 1 + 4 files changed, 59 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 9ff1cf46eae..45f6cf53156 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -240,6 +240,13 @@ config AX88796 AX88796 driver, using platform bus to provide chip detection and resources +config AX88796_93CX6 + bool "ASIX AX88796 external 93CX6 eeprom support" + depends on AX88796 + select EEPROM_93CX6 + help + Select this if your platform comes with an external 93CX6 eeprom. + config MACE tristate "MACE (Power Mac ethernet) support" depends on PPC_PMAC && PPC32 diff --git a/drivers/net/ax88796.c b/drivers/net/ax88796.c index 90e0734e603..9fe0517cf89 100644 --- a/drivers/net/ax88796.c +++ b/drivers/net/ax88796.c @@ -24,6 +24,7 @@ #include #include #include +#include #include @@ -582,6 +583,37 @@ static const struct ethtool_ops ax_ethtool_ops = { .get_link = ax_get_link, }; +#ifdef CONFIG_AX88796_93CX6 +static void ax_eeprom_register_read(struct eeprom_93cx6 *eeprom) +{ + struct ei_device *ei_local = eeprom->data; + u8 reg = ei_inb(ei_local->mem + AX_MEMR); + + eeprom->reg_data_in = reg & AX_MEMR_EEI; + eeprom->reg_data_out = reg & AX_MEMR_EEO; /* Input pin */ + eeprom->reg_data_clock = reg & AX_MEMR_EECLK; + eeprom->reg_chip_select = reg & AX_MEMR_EECS; +} + +static void ax_eeprom_register_write(struct eeprom_93cx6 *eeprom) +{ + struct ei_device *ei_local = eeprom->data; + u8 reg = ei_inb(ei_local->mem + AX_MEMR); + + reg &= ~(AX_MEMR_EEI | AX_MEMR_EECLK | AX_MEMR_EECS); + + if (eeprom->reg_data_in) + reg |= AX_MEMR_EEI; + if (eeprom->reg_data_clock) + reg |= AX_MEMR_EECLK; + if (eeprom->reg_chip_select) + reg |= AX_MEMR_EECS; + + ei_outb(reg, ei_local->mem + AX_MEMR); + udelay(10); +} +#endif + /* setup code */ static void ax_initial_setup(struct net_device *dev, struct ei_device *ei_local) @@ -640,6 +672,23 @@ static int ax_init_dev(struct net_device *dev, int first_init) memcpy(dev->dev_addr, SA_prom, 6); } +#ifdef CONFIG_AX88796_93CX6 + if (first_init && ax->plat->flags & AXFLG_HAS_93CX6) { + unsigned char mac_addr[6]; + struct eeprom_93cx6 eeprom; + + eeprom.data = ei_local; + eeprom.register_read = ax_eeprom_register_read; + eeprom.register_write = ax_eeprom_register_write; + eeprom.width = PCI_EEPROM_WIDTH_93C56; + + eeprom_93cx6_multiread(&eeprom, 0, + (__le16 __force *)mac_addr, + sizeof(mac_addr) >> 1); + + memcpy(dev->dev_addr, mac_addr, 6); + } +#endif if (ax->plat->wordlength == 2) { /* We must set the 8390 for word mode. */ ei_outb(ax->plat->dcr_val, ei_local->mem + EN0_DCFG); diff --git a/include/linux/eeprom_93cx6.h b/include/linux/eeprom_93cx6.h index d774b7778c9..a55c873e8b6 100644 --- a/include/linux/eeprom_93cx6.h +++ b/include/linux/eeprom_93cx6.h @@ -21,13 +21,14 @@ /* Module: eeprom_93cx6 Abstract: EEPROM reader datastructures for 93cx6 chipsets. - Supported chipsets: 93c46 & 93c66. + Supported chipsets: 93c46, 93c56 and 93c66. */ /* * EEPROM operation defines. */ #define PCI_EEPROM_WIDTH_93C46 6 +#define PCI_EEPROM_WIDTH_93C56 8 #define PCI_EEPROM_WIDTH_93C66 8 #define PCI_EEPROM_WIDTH_OPCODE 3 #define PCI_EEPROM_WRITE_OPCODE 0x05 diff --git a/include/net/ax88796.h b/include/net/ax88796.h index ee786a043b3..51329dae44e 100644 --- a/include/net/ax88796.h +++ b/include/net/ax88796.h @@ -14,6 +14,7 @@ #define AXFLG_HAS_EEPROM (1<<0) #define AXFLG_MAC_FROMDEV (1<<1) /* device already has MAC */ +#define AXFLG_HAS_93CX6 (1<<2) /* use eeprom_93cx6 driver */ struct ax_plat_data { unsigned int flags; -- cgit v1.2.3-70-g09d2 From b3448b0bde5f1a858397fe791f76632e978a1dc8 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 30 Sep 2007 17:55:51 -0700 Subject: [BNX2]: factor out gzip unpacker This patch modifies gzip unpacking code in bnx2 driver so that it does not depend on bnx2 internals. I will move this code out of the driver and into zlib in follow-on patch. It can be useful in other drivers which need to store firmwares or any other relatively big binary blobs - fonts, cursor bitmaps, whatever. Patch is run tested by Michael Chan (driver author). Signed-off-by: Denys Vlasenko Acked-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 160 ++++++++++++++++++------------------------------- drivers/net/bnx2.h | 5 +- drivers/net/bnx2_fw.h | 28 +++++---- drivers/net/bnx2_fw2.h | 15 +++-- 4 files changed, 86 insertions(+), 122 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 57f7d994c9c..73d4a579790 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -52,6 +52,8 @@ #include "bnx2_fw.h" #include "bnx2_fw2.h" +#define FW_BUF_SIZE 0x8000 + #define DRV_MODULE_NAME "bnx2" #define PFX DRV_MODULE_NAME ": " #define DRV_MODULE_VERSION "1.6.5" @@ -2759,89 +2761,45 @@ bnx2_set_rx_mode(struct net_device *dev) spin_unlock_bh(&bp->phy_lock); } -#define FW_BUF_SIZE 0x8000 - +/* To be moved to generic lib/ */ static int -bnx2_gunzip_init(struct bnx2 *bp) +bnx2_gunzip(void *gunzip_buf, unsigned sz, u8 *zbuf, int len) { - if ((bp->gunzip_buf = vmalloc(FW_BUF_SIZE)) == NULL) - goto gunzip_nomem1; + struct z_stream_s *strm; + int rc; - if ((bp->strm = kmalloc(sizeof(*bp->strm), GFP_KERNEL)) == NULL) - goto gunzip_nomem2; + /* gzip header (1f,8b,08... 10 bytes total + possible asciz filename) + * is stripped */ - bp->strm->workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL); - if (bp->strm->workspace == NULL) + rc = -ENOMEM; + strm = kmalloc(sizeof(*strm), GFP_KERNEL); + if (strm == NULL) + goto gunzip_nomem2; + strm->workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL); + if (strm->workspace == NULL) goto gunzip_nomem3; - return 0; + strm->next_in = zbuf; + strm->avail_in = len; + strm->next_out = gunzip_buf; + strm->avail_out = sz; + + rc = zlib_inflateInit2(strm, -MAX_WBITS); + if (rc == Z_OK) { + rc = zlib_inflate(strm, Z_FINISH); + /* after Z_FINISH, only Z_STREAM_END is "we unpacked it all" */ + if (rc == Z_STREAM_END) + rc = sz - strm->avail_out; + else + rc = -EINVAL; + zlib_inflateEnd(strm); + } else + rc = -EINVAL; + kfree(strm->workspace); gunzip_nomem3: - kfree(bp->strm); - bp->strm = NULL; - + kfree(strm); gunzip_nomem2: - vfree(bp->gunzip_buf); - bp->gunzip_buf = NULL; - -gunzip_nomem1: - printk(KERN_ERR PFX "%s: Cannot allocate firmware buffer for " - "uncompression.\n", bp->dev->name); - return -ENOMEM; -} - -static void -bnx2_gunzip_end(struct bnx2 *bp) -{ - kfree(bp->strm->workspace); - - kfree(bp->strm); - bp->strm = NULL; - - if (bp->gunzip_buf) { - vfree(bp->gunzip_buf); - bp->gunzip_buf = NULL; - } -} - -static int -bnx2_gunzip(struct bnx2 *bp, u8 *zbuf, int len, void **outbuf, int *outlen) -{ - int n, rc; - - /* check gzip header */ - if ((zbuf[0] != 0x1f) || (zbuf[1] != 0x8b) || (zbuf[2] != Z_DEFLATED)) - return -EINVAL; - - n = 10; - -#define FNAME 0x8 - if (zbuf[3] & FNAME) - while ((zbuf[n++] != 0) && (n < len)); - - bp->strm->next_in = zbuf + n; - bp->strm->avail_in = len - n; - bp->strm->next_out = bp->gunzip_buf; - bp->strm->avail_out = FW_BUF_SIZE; - - rc = zlib_inflateInit2(bp->strm, -MAX_WBITS); - if (rc != Z_OK) - return rc; - - rc = zlib_inflate(bp->strm, Z_FINISH); - - *outlen = FW_BUF_SIZE - bp->strm->avail_out; - *outbuf = bp->gunzip_buf; - - if ((rc != Z_OK) && (rc != Z_STREAM_END)) - printk(KERN_ERR PFX "%s: Firmware decompression error: %s\n", - bp->dev->name, bp->strm->msg); - - zlib_inflateEnd(bp->strm); - - if (rc == Z_STREAM_END) - return 0; - return rc; } @@ -2894,22 +2852,21 @@ load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw) /* Load the Text area. */ offset = cpu_reg->spad_base + (fw->text_addr - cpu_reg->mips_view_base); if (fw->gz_text) { - u32 text_len; - void *text; - - rc = bnx2_gunzip(bp, fw->gz_text, fw->gz_text_len, &text, - &text_len); - if (rc) - return rc; - - fw->text = text; - } - if (fw->gz_text) { + u32 *text; int j; + text = vmalloc(FW_BUF_SIZE); + if (!text) + return -ENOMEM; + rc = bnx2_gunzip(text, FW_BUF_SIZE, fw->gz_text, fw->gz_text_len); + if (rc < 0) { + vfree(text); + return rc; + } for (j = 0; j < (fw->text_len / 4); j++, offset += 4) { - REG_WR_IND(bp, offset, cpu_to_le32(fw->text[j])); + REG_WR_IND(bp, offset, cpu_to_le32(text[j])); } + vfree(text); } /* Load the Data area. */ @@ -2971,27 +2928,27 @@ bnx2_init_cpus(struct bnx2 *bp) { struct cpu_reg cpu_reg; struct fw_info *fw; - int rc = 0; + int rc; void *text; - u32 text_len; - - if ((rc = bnx2_gunzip_init(bp)) != 0) - return rc; /* Initialize the RV2P processor. */ - rc = bnx2_gunzip(bp, bnx2_rv2p_proc1, sizeof(bnx2_rv2p_proc1), &text, - &text_len); - if (rc) + text = vmalloc(FW_BUF_SIZE); + if (!text) + return -ENOMEM; + rc = bnx2_gunzip(text, FW_BUF_SIZE, bnx2_rv2p_proc1, sizeof(bnx2_rv2p_proc1)); + if (rc < 0) { + vfree(text); goto init_cpu_err; + } + load_rv2p_fw(bp, text, rc /* == len */, RV2P_PROC1); - load_rv2p_fw(bp, text, text_len, RV2P_PROC1); - - rc = bnx2_gunzip(bp, bnx2_rv2p_proc2, sizeof(bnx2_rv2p_proc2), &text, - &text_len); - if (rc) + rc = bnx2_gunzip(text, FW_BUF_SIZE, bnx2_rv2p_proc2, sizeof(bnx2_rv2p_proc2)); + if (rc < 0) { + vfree(text); goto init_cpu_err; - - load_rv2p_fw(bp, text, text_len, RV2P_PROC2); + } + load_rv2p_fw(bp, text, rc /* == len */, RV2P_PROC2); + vfree(text); /* Initialize the RX Processor. */ cpu_reg.mode = BNX2_RXP_CPU_MODE; @@ -3107,7 +3064,6 @@ bnx2_init_cpus(struct bnx2 *bp) goto init_cpu_err; } init_cpu_err: - bnx2_gunzip_end(bp); return rc; } diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h index fbae439db64..a717459cc8d 100644 --- a/drivers/net/bnx2.h +++ b/drivers/net/bnx2.h @@ -6681,9 +6681,6 @@ struct bnx2 { u32 flash_size; int status_stats_size; - - struct z_stream_s *strm; - void *gunzip_buf; }; static u32 bnx2_reg_rd_ind(struct bnx2 *bp, u32 offset); @@ -6741,7 +6738,7 @@ struct fw_info { const u32 text_addr; const u32 text_len; const u32 text_index; - u32 *text; +/* u32 *text;*/ u8 *gz_text; const u32 gz_text_len; diff --git a/drivers/net/bnx2_fw.h b/drivers/net/bnx2_fw.h index b49f439e0f6..30f2f4052fc 100644 --- a/drivers/net/bnx2_fw.h +++ b/drivers/net/bnx2_fw.h @@ -15,7 +15,8 @@ */ static u8 bnx2_COM_b06FwText[] = { - 0x1f, 0x8b, 0x08, 0x00, 0x45, 0x30, 0xe7, 0x45, 0x00, 0x03, 0xdc, 0x5a, +/* 0x1f, 0x8b, 0x08, 0x00, 0x45, 0x30, 0xe7, 0x45, 0x00, 0x03, */ + 0xdc, 0x5a, 0x6b, 0x6c, 0x1c, 0xd7, 0x75, 0x3e, 0x33, 0x3b, 0x4b, 0xae, 0xc8, 0x15, 0x35, 0xa2, 0xc6, 0xf4, 0x5a, 0xa2, 0xed, 0x5d, 0x72, 0x28, 0x12, 0x96, 0xec, 0x6e, 0x68, 0xda, 0x62, 0x8c, 0x8d, 0xb4, 0xd9, 0xa5, 0x0c, 0xa1, @@ -1085,8 +1086,9 @@ static struct fw_info bnx2_com_fw_06 = { }; static u8 bnx2_RXP_b06FwText[] = { - 0x1f, 0x8b, 0x08, 0x08, 0xcb, 0xa3, 0x46, 0x45, 0x00, 0x03, 0x74, 0x65, - 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xec, 0x5c, 0x6f, 0x6c, +/* 0x1f, 0x8b, 0x08, 0x08, 0xcb, 0xa3, 0x46, 0x45, 0x00, 0x03, 0x74, 0x65, + 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, */ + 0xec, 0x5c, 0x6f, 0x6c, 0x1c, 0xc7, 0x75, 0x7f, 0x3b, 0xbb, 0xa4, 0x4e, 0xd4, 0x91, 0x5c, 0x1e, 0x4f, 0xf4, 0x49, 0x66, 0x94, 0x5d, 0x71, 0x25, 0x5e, 0x2d, 0xc6, 0x5d, 0x31, 0x57, 0x9b, 0x08, 0xce, 0xf1, 0x79, 0xef, 0x64, 0xb1, 0x86, 0x0a, @@ -1798,8 +1800,9 @@ static struct fw_info bnx2_rxp_fw_06 = { }; static u8 bnx2_rv2p_proc1[] = { - 0x1f, 0x8b, 0x08, 0x08, 0x5e, 0xd0, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65, - 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xc5, 0x56, 0xcf, 0x6b, +/* 0x1f, 0x8b, 0x08, 0x08, 0x5e, 0xd0, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65, + 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, */ + 0xc5, 0x56, 0xcf, 0x6b, 0x13, 0x51, 0x10, 0x9e, 0xec, 0x6e, 0xb2, 0xdb, 0x74, 0xbb, 0x1b, 0x2b, 0xda, 0xa0, 0xb1, 0x8d, 0x51, 0x6a, 0x7f, 0xa4, 0xb4, 0x11, 0x0f, 0x82, 0x42, 0x25, 0x3d, 0x04, 0x54, 0x44, 0x7a, 0x28, 0x22, 0x82, 0x36, 0x8a, @@ -1877,8 +1880,9 @@ static u8 bnx2_rv2p_proc1[] = { 0x12, 0x3d, 0x80, 0x0b, 0x00, 0x00, 0x00 }; static u8 bnx2_rv2p_proc2[] = { - 0x1f, 0x8b, 0x08, 0x08, 0x7e, 0xd1, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65, - 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xcd, 0x58, 0x5b, 0x6c, +/* 0x1f, 0x8b, 0x08, 0x08, 0x7e, 0xd1, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65, + 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, */ + 0xcd, 0x58, 0x5b, 0x6c, 0x54, 0x55, 0x14, 0x3d, 0xf3, 0xe8, 0xcc, 0x9d, 0xe9, 0xed, 0x9d, 0xf2, 0xb2, 0x03, 0xad, 0x08, 0xe5, 0xd1, 0x56, 0x29, 0xe8, 0x54, 0xab, 0x18, 0x15, 0x2c, 0x5a, 0x8c, 0x26, 0x68, 0xf0, 0xf9, 0x63, 0x14, 0x04, 0xda, @@ -2057,8 +2061,9 @@ static u8 bnx2_rv2p_proc2[] = { 0x17, 0x00, 0x00, 0x00 }; static u8 bnx2_TPAT_b06FwText[] = { - 0x1f, 0x8b, 0x08, 0x08, 0x47, 0xd2, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65, - 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xc5, 0x57, 0x4d, 0x68, +/* 0x1f, 0x8b, 0x08, 0x08, 0x47, 0xd2, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65, + 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, */ + 0xc5, 0x57, 0x4d, 0x68, 0x1c, 0xe7, 0x19, 0x7e, 0xe7, 0x77, 0x47, 0x62, 0x25, 0x8d, 0x93, 0x3d, 0xac, 0x5d, 0xa5, 0x99, 0x91, 0x46, 0x3f, 0x54, 0x26, 0x9e, 0x84, 0xa5, 0x56, 0x61, 0x20, 0xe3, 0x99, 0x95, 0x2c, 0x0c, 0x05, 0x07, 0x42, 0x08, @@ -2290,8 +2295,9 @@ static struct fw_info bnx2_tpat_fw_06 = { }; static u8 bnx2_TXP_b06FwText[] = { - 0x1f, 0x8b, 0x08, 0x08, 0x21, 0xd3, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65, - 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xed, 0x5c, 0x6d, 0x6c, +/* 0x1f, 0x8b, 0x08, 0x08, 0x21, 0xd3, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65, + 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, */ + 0xed, 0x5c, 0x6d, 0x6c, 0x1b, 0xf7, 0x79, 0x7f, 0xee, 0x85, 0xd2, 0x51, 0x96, 0xe9, 0x93, 0xc2, 0x78, 0x6c, 0xc0, 0xa6, 0x77, 0xd6, 0x51, 0x66, 0x20, 0xb5, 0xa0, 0x05, 0x36, 0x55, 0x87, 0x43, 0x73, 0x3e, 0x52, 0x2f, 0x4e, 0x5c, 0x57, 0x71, diff --git a/drivers/net/bnx2_fw2.h b/drivers/net/bnx2_fw2.h index 2c067531f03..74f985d8fac 100644 --- a/drivers/net/bnx2_fw2.h +++ b/drivers/net/bnx2_fw2.h @@ -15,7 +15,8 @@ */ static u8 bnx2_COM_b09FwText[] = { - 0x1f, 0x8b, 0x08, 0x00, 0x0e, 0x34, 0xe7, 0x45, 0x00, 0x03, 0xdc, 0x5b, +/* 0x1f, 0x8b, 0x08, 0x00, 0x0e, 0x34, 0xe7, 0x45, 0x00, 0x03, */ + 0xdc, 0x5b, 0x6d, 0x70, 0x5c, 0xd5, 0x79, 0x7e, 0xef, 0xd9, 0xbb, 0xf2, 0x5a, 0x92, 0xe5, 0x6b, 0x79, 0x23, 0x16, 0x4b, 0xc0, 0xae, 0x75, 0x6d, 0x69, 0xb0, 0x43, 0x16, 0xa1, 0x80, 0x9a, 0xd9, 0xc0, 0xb2, 0x2b, 0x33, 0x9e, 0x0c, @@ -1083,7 +1084,8 @@ static struct fw_info bnx2_com_fw_09 = { }; static u8 bnx2_CP_b09FwText[] = { - 0x1f, 0x8b, 0x08, 0x00, 0x0f, 0x34, 0xe7, 0x45, 0x00, 0x03, 0xbd, 0x7d, +/* 0x1f, 0x8b, 0x08, 0x00, 0x0f, 0x34, 0xe7, 0x45, 0x00, 0x03, */ + 0xbd, 0x7d, 0x0d, 0x74, 0x5c, 0x57, 0x7d, 0xe7, 0xff, 0xdd, 0x19, 0x49, 0x63, 0x59, 0x96, 0x9f, 0xe5, 0x89, 0x32, 0x51, 0x84, 0x3d, 0x23, 0x3d, 0xd9, 0x22, 0x12, 0xe1, 0xc5, 0x11, 0xac, 0xda, 0x2a, 0xe9, 0x30, 0x92, 0x3f, 0x12, @@ -2279,7 +2281,8 @@ static struct fw_info bnx2_cp_fw_09 = { }; static u8 bnx2_RXP_b09FwText[] = { - 0x1f, 0x8b, 0x08, 0x00, 0x0e, 0x34, 0xe7, 0x45, 0x00, 0x03, 0xec, 0x5c, +/* 0x1f, 0x8b, 0x08, 0x00, 0x0e, 0x34, 0xe7, 0x45, 0x00, 0x03, */ + 0xec, 0x5c, 0x5d, 0x6c, 0x1c, 0xd7, 0x75, 0x3e, 0xf3, 0x43, 0x6a, 0x49, 0xf1, 0x67, 0xb8, 0x5c, 0xb1, 0x2b, 0x99, 0x96, 0x77, 0xc9, 0x91, 0xc8, 0x58, 0x8a, 0x31, 0xa2, 0x09, 0x5b, 0x48, 0x17, 0xf6, 0x76, 0x76, 0x25, 0xb1, 0xb1, @@ -2988,7 +2991,8 @@ static struct fw_info bnx2_rxp_fw_09 = { }; static u8 bnx2_TPAT_b09FwText[] = { - 0x1f, 0x8b, 0x08, 0x00, 0x0e, 0x34, 0xe7, 0x45, 0x00, 0x03, 0xcd, 0x58, +/* 0x1f, 0x8b, 0x08, 0x00, 0x0e, 0x34, 0xe7, 0x45, 0x00, 0x03, */ + 0xcd, 0x58, 0x5d, 0x68, 0x1c, 0xd7, 0x15, 0x3e, 0xf3, 0xb7, 0x3b, 0x52, 0x24, 0xeb, 0x5a, 0xd9, 0xa6, 0xeb, 0xa0, 0x34, 0x33, 0xda, 0x91, 0xac, 0x22, 0x13, 0x4f, 0x9d, 0x25, 0x16, 0x65, 0x21, 0x93, 0xd9, 0x91, 0xac, 0x98, 0x3c, @@ -3279,7 +3283,8 @@ static struct fw_info bnx2_tpat_fw_09 = { }; static u8 bnx2_TXP_b09FwText[] = { - 0x1f, 0x8b, 0x08, 0x00, 0x0e, 0x34, 0xe7, 0x45, 0x00, 0x03, 0xcd, 0x7c, +/* 0x1f, 0x8b, 0x08, 0x00, 0x0e, 0x34, 0xe7, 0x45, 0x00, 0x03, */ + 0xcd, 0x7c, 0x6f, 0x70, 0x5b, 0xd7, 0x95, 0xdf, 0x79, 0xef, 0x81, 0x24, 0x48, 0xd1, 0xd4, 0x13, 0x17, 0x56, 0x60, 0x87, 0x71, 0x00, 0xf1, 0x81, 0x66, 0x42, 0xae, 0x04, 0x2b, 0x4c, 0xc2, 0x6d, 0xd1, 0xf8, 0x05, 0x00, 0x29, 0x48, -- cgit v1.2.3-70-g09d2 From 8336793baf962163c9fab5a3f39614295fdbab27 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 30 Sep 2007 17:56:49 -0700 Subject: [ZLIB]: Move bnx2 driver gzip unpacker into zlib. Signed-off-by: Denys Vlasenko Acked-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 48 +++-------------------------------- include/linux/zlib.h | 6 ++++- lib/zlib_inflate/inffast.c | 18 +++++++------- lib/zlib_inflate/inflate.c | 55 ++++++++++++++++++++++++++++++++++++++--- lib/zlib_inflate/inflate_syms.c | 1 + 5 files changed, 69 insertions(+), 59 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 73d4a579790..6d6ea56fe38 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -2761,48 +2761,6 @@ bnx2_set_rx_mode(struct net_device *dev) spin_unlock_bh(&bp->phy_lock); } -/* To be moved to generic lib/ */ -static int -bnx2_gunzip(void *gunzip_buf, unsigned sz, u8 *zbuf, int len) -{ - struct z_stream_s *strm; - int rc; - - /* gzip header (1f,8b,08... 10 bytes total + possible asciz filename) - * is stripped */ - - rc = -ENOMEM; - strm = kmalloc(sizeof(*strm), GFP_KERNEL); - if (strm == NULL) - goto gunzip_nomem2; - strm->workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL); - if (strm->workspace == NULL) - goto gunzip_nomem3; - - strm->next_in = zbuf; - strm->avail_in = len; - strm->next_out = gunzip_buf; - strm->avail_out = sz; - - rc = zlib_inflateInit2(strm, -MAX_WBITS); - if (rc == Z_OK) { - rc = zlib_inflate(strm, Z_FINISH); - /* after Z_FINISH, only Z_STREAM_END is "we unpacked it all" */ - if (rc == Z_STREAM_END) - rc = sz - strm->avail_out; - else - rc = -EINVAL; - zlib_inflateEnd(strm); - } else - rc = -EINVAL; - - kfree(strm->workspace); -gunzip_nomem3: - kfree(strm); -gunzip_nomem2: - return rc; -} - static void load_rv2p_fw(struct bnx2 *bp, u32 *rv2p_code, u32 rv2p_code_len, u32 rv2p_proc) @@ -2858,7 +2816,7 @@ load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw) text = vmalloc(FW_BUF_SIZE); if (!text) return -ENOMEM; - rc = bnx2_gunzip(text, FW_BUF_SIZE, fw->gz_text, fw->gz_text_len); + rc = zlib_inflate_blob(text, FW_BUF_SIZE, fw->gz_text, fw->gz_text_len); if (rc < 0) { vfree(text); return rc; @@ -2935,14 +2893,14 @@ bnx2_init_cpus(struct bnx2 *bp) text = vmalloc(FW_BUF_SIZE); if (!text) return -ENOMEM; - rc = bnx2_gunzip(text, FW_BUF_SIZE, bnx2_rv2p_proc1, sizeof(bnx2_rv2p_proc1)); + rc = zlib_inflate_blob(text, FW_BUF_SIZE, bnx2_rv2p_proc1, sizeof(bnx2_rv2p_proc1)); if (rc < 0) { vfree(text); goto init_cpu_err; } load_rv2p_fw(bp, text, rc /* == len */, RV2P_PROC1); - rc = bnx2_gunzip(text, FW_BUF_SIZE, bnx2_rv2p_proc2, sizeof(bnx2_rv2p_proc2)); + rc = zlib_inflate_blob(text, FW_BUF_SIZE, bnx2_rv2p_proc2, sizeof(bnx2_rv2p_proc2)); if (rc < 0) { vfree(text); goto init_cpu_err; diff --git a/include/linux/zlib.h b/include/linux/zlib.h index 9e3192a7dc6..40c49cb3eb5 100644 --- a/include/linux/zlib.h +++ b/include/linux/zlib.h @@ -82,7 +82,7 @@ struct internal_state; typedef struct z_stream_s { - Byte *next_in; /* next input byte */ + const Byte *next_in; /* next input byte */ uInt avail_in; /* number of bytes available at next_in */ uLong total_in; /* total nb of input bytes read so far */ @@ -699,4 +699,8 @@ extern int zlib_inflateInit2(z_streamp strm, int windowBits); struct internal_state {int dummy;}; /* hack for buggy compilers */ #endif +/* Utility function: initialize zlib, unpack binary blob, clean up zlib, + * return len or negative error code. */ +extern int zlib_inflate_blob(void *dst, unsigned dst_sz, const void *src, unsigned src_sz); + #endif /* _ZLIB_H */ diff --git a/lib/zlib_inflate/inffast.c b/lib/zlib_inflate/inffast.c index d84560c076d..8550b0c05d0 100644 --- a/lib/zlib_inflate/inffast.c +++ b/lib/zlib_inflate/inffast.c @@ -69,22 +69,22 @@ void inflate_fast(z_streamp strm, unsigned start) { struct inflate_state *state; - unsigned char *in; /* local strm->next_in */ - unsigned char *last; /* while in < last, enough input available */ - unsigned char *out; /* local strm->next_out */ - unsigned char *beg; /* inflate()'s initial strm->next_out */ - unsigned char *end; /* while out < end, enough space available */ + const unsigned char *in; /* local strm->next_in */ + const unsigned char *last; /* while in < last, enough input available */ + unsigned char *out; /* local strm->next_out */ + unsigned char *beg; /* inflate()'s initial strm->next_out */ + unsigned char *end; /* while out < end, enough space available */ #ifdef INFLATE_STRICT unsigned dmax; /* maximum distance from zlib header */ #endif unsigned wsize; /* window size or zero if not using window */ unsigned whave; /* valid bytes in the window */ unsigned write; /* window write index */ - unsigned char *window; /* allocated sliding window, if wsize != 0 */ + unsigned char *window; /* allocated sliding window, if wsize != 0 */ unsigned long hold; /* local strm->hold */ unsigned bits; /* local strm->bits */ - code const *lcode; /* local strm->lencode */ - code const *dcode; /* local strm->distcode */ + code const *lcode; /* local strm->lencode */ + code const *dcode; /* local strm->distcode */ unsigned lmask; /* mask for first level of length codes */ unsigned dmask; /* mask for first level of distance codes */ code this; /* retrieved table entry */ @@ -92,7 +92,7 @@ void inflate_fast(z_streamp strm, unsigned start) /* window position, window bytes to copy */ unsigned len; /* match length, unused bytes */ unsigned dist; /* match distance */ - unsigned char *from; /* where to copy match from */ + unsigned char *from; /* where to copy match from */ /* copy state to local variables */ state = (struct inflate_state *)strm->state; diff --git a/lib/zlib_inflate/inflate.c b/lib/zlib_inflate/inflate.c index 7e1e3114a73..0ad1ebf0094 100644 --- a/lib/zlib_inflate/inflate.c +++ b/lib/zlib_inflate/inflate.c @@ -332,14 +332,14 @@ static int zlib_inflateSyncPacket(z_streamp strm) int zlib_inflate(z_streamp strm, int flush) { struct inflate_state *state; - unsigned char *next; /* next input */ - unsigned char *put; /* next output */ + const unsigned char *next; /* next input */ + unsigned char *put; /* next output */ unsigned have, left; /* available input and output */ unsigned long hold; /* bit buffer */ unsigned bits; /* bits in bit buffer */ unsigned in, out; /* save starting available input and output */ unsigned copy; /* number of stored or match bytes to copy */ - unsigned char *from; /* where to copy match bytes from */ + unsigned char *from; /* where to copy match bytes from */ code this; /* current decoding table entry */ code last; /* parent table entry */ unsigned len; /* length to copy for repeats, bits to drop */ @@ -897,7 +897,7 @@ int zlib_inflateIncomp(z_stream *z) /* Setup some variables to allow misuse of updateWindow */ z->avail_out = 0; - z->next_out = z->next_in + z->avail_in; + z->next_out = (unsigned char*)z->next_in + z->avail_in; zlib_updatewindow(z, z->avail_in); @@ -916,3 +916,50 @@ int zlib_inflateIncomp(z_stream *z) return Z_OK; } + +#include +#include +#include + +/* Utility function: initialize zlib, unpack binary blob, clean up zlib, + * return len or negative error code. */ +int zlib_inflate_blob(void *gunzip_buf, unsigned sz, const void *buf, unsigned len) +{ + const u8 *zbuf = buf; + struct z_stream_s *strm; + int rc; + + rc = -ENOMEM; + strm = kmalloc(sizeof(*strm), GFP_KERNEL); + if (strm == NULL) + goto gunzip_nomem1; + strm->workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL); + if (strm->workspace == NULL) + goto gunzip_nomem2; + + /* gzip header (1f,8b,08... 10 bytes total + possible asciz filename) + * expected to be stripped from input */ + + strm->next_in = zbuf; + strm->avail_in = len; + strm->next_out = gunzip_buf; + strm->avail_out = sz; + + rc = zlib_inflateInit2(strm, -MAX_WBITS); + if (rc == Z_OK) { + rc = zlib_inflate(strm, Z_FINISH); + /* after Z_FINISH, only Z_STREAM_END is "we unpacked it all" */ + if (rc == Z_STREAM_END) + rc = sz - strm->avail_out; + else + rc = -EINVAL; + zlib_inflateEnd(strm); + } else + rc = -EINVAL; + + kfree(strm->workspace); +gunzip_nomem2: + kfree(strm); +gunzip_nomem1: + return rc; /* returns Z_OK (0) if successful */ +} diff --git a/lib/zlib_inflate/inflate_syms.c b/lib/zlib_inflate/inflate_syms.c index 2061d4f0676..67329fe9907 100644 --- a/lib/zlib_inflate/inflate_syms.c +++ b/lib/zlib_inflate/inflate_syms.c @@ -16,4 +16,5 @@ EXPORT_SYMBOL(zlib_inflateInit2); EXPORT_SYMBOL(zlib_inflateEnd); EXPORT_SYMBOL(zlib_inflateReset); EXPORT_SYMBOL(zlib_inflateIncomp); +EXPORT_SYMBOL(zlib_inflate_blob); MODULE_LICENSE("GPL"); -- cgit v1.2.3-70-g09d2 From 0fb300fa9d54118c6dce772a29362d896775eff2 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Mon, 1 Oct 2007 14:20:17 -0500 Subject: fs_enet: Whitespace cleanup. Signed-off-by: Scott Wood Signed-off-by: Jeff Garzik --- drivers/net/fs_enet/fs_enet-main.c | 85 +++++++++++++++++--------------------- drivers/net/fs_enet/fs_enet.h | 4 +- drivers/net/fs_enet/mac-fcc.c | 1 - drivers/net/fs_enet/mii-bitbang.c | 3 -- drivers/net/fs_enet/mii-fec.c | 1 - 5 files changed, 41 insertions(+), 53 deletions(-) (limited to 'drivers') diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index dcbe83c773e..a15345ba1e5 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -343,7 +343,6 @@ static void fs_enet_tx(struct net_device *dev) do_wake = do_restart = 0; while (((sc = CBDR_SC(bdp)) & BD_ENET_TX_READY) == 0) { - dirtyidx = bdp - fep->tx_bd_base; if (fep->tx_free == fep->tx_ring) @@ -444,7 +443,6 @@ fs_enet_interrupt(int irq, void *dev_id) nr = 0; while ((int_events = (*fep->ops->get_int_events)(dev)) != 0) { - nr++; int_clr_events = int_events; @@ -700,45 +698,43 @@ static void fs_timeout(struct net_device *dev) *-----------------------------------------------------------------------------*/ static void generic_adjust_link(struct net_device *dev) { - struct fs_enet_private *fep = netdev_priv(dev); - struct phy_device *phydev = fep->phydev; - int new_state = 0; - - if (phydev->link) { - - /* adjust to duplex mode */ - if (phydev->duplex != fep->oldduplex){ - new_state = 1; - fep->oldduplex = phydev->duplex; - } - - if (phydev->speed != fep->oldspeed) { - new_state = 1; - fep->oldspeed = phydev->speed; - } - - if (!fep->oldlink) { - new_state = 1; - fep->oldlink = 1; - netif_schedule(dev); - netif_carrier_on(dev); - netif_start_queue(dev); - } - - if (new_state) - fep->ops->restart(dev); - - } else if (fep->oldlink) { - new_state = 1; - fep->oldlink = 0; - fep->oldspeed = 0; - fep->oldduplex = -1; - netif_carrier_off(dev); - netif_stop_queue(dev); - } - - if (new_state && netif_msg_link(fep)) - phy_print_status(phydev); + struct fs_enet_private *fep = netdev_priv(dev); + struct phy_device *phydev = fep->phydev; + int new_state = 0; + + if (phydev->link) { + /* adjust to duplex mode */ + if (phydev->duplex != fep->oldduplex) { + new_state = 1; + fep->oldduplex = phydev->duplex; + } + + if (phydev->speed != fep->oldspeed) { + new_state = 1; + fep->oldspeed = phydev->speed; + } + + if (!fep->oldlink) { + new_state = 1; + fep->oldlink = 1; + netif_schedule(dev); + netif_carrier_on(dev); + netif_start_queue(dev); + } + + if (new_state) + fep->ops->restart(dev); + } else if (fep->oldlink) { + new_state = 1; + fep->oldlink = 0; + fep->oldspeed = 0; + fep->oldduplex = -1; + netif_carrier_off(dev); + netif_stop_queue(dev); + } + + if (new_state && netif_msg_link(fep)) + phy_print_status(phydev); } @@ -782,7 +778,6 @@ static int fs_init_phy(struct net_device *dev) return 0; } - static int fs_enet_open(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); @@ -971,7 +966,7 @@ static struct net_device *fs_init_instance(struct device *dev, #endif #ifdef CONFIG_FS_ENET_HAS_SCC - if (fs_get_scc_index(fpi->fs_no) >=0 ) + if (fs_get_scc_index(fpi->fs_no) >=0) fep->ops = &fs_scc_ops; #endif @@ -1066,9 +1061,8 @@ static struct net_device *fs_init_instance(struct device *dev, return ndev; - err: +err: if (ndev != NULL) { - if (registered) unregister_netdev(ndev); @@ -1259,7 +1253,6 @@ static int __init fs_init(void) err: cleanup_immap(); return r; - } static void __exit fs_cleanup(void) diff --git a/drivers/net/fs_enet/fs_enet.h b/drivers/net/fs_enet/fs_enet.h index 46d0606b143..fbe2087d0d7 100644 --- a/drivers/net/fs_enet/fs_enet.h +++ b/drivers/net/fs_enet/fs_enet.h @@ -15,8 +15,8 @@ #include struct fec_info { - fec_t* fecp; - u32 mii_speed; + fec_t *fecp; + u32 mii_speed; }; #endif diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c index 64071514d7d..1e1024a4d43 100644 --- a/drivers/net/fs_enet/mac-fcc.c +++ b/drivers/net/fs_enet/mac-fcc.c @@ -86,7 +86,6 @@ static inline int fcc_cr_cmd(struct fs_enet_private *fep, u32 mcn, u32 op) { const struct fs_platform_info *fpi = fep->fpi; - cpm2_map_t *immap = fs_enet_immap; cpm_cpm2_t *cpmp = &immap->im_cpm; u32 v; diff --git a/drivers/net/fs_enet/mii-bitbang.c b/drivers/net/fs_enet/mii-bitbang.c index 1a41ea60f98..422f8287787 100644 --- a/drivers/net/fs_enet/mii-bitbang.c +++ b/drivers/net/fs_enet/mii-bitbang.c @@ -12,7 +12,6 @@ * kind, whether express or implied. */ - #include #include #include @@ -308,7 +307,6 @@ static int fs_mii_bitbang_init(struct bb_info *bitbang, struct fs_mii_bb_platfor return 0; } - static int __devinit fs_enet_mdio_probe(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); @@ -371,7 +369,6 @@ bus_register_fail: return err; } - static int fs_enet_mdio_remove(struct device *dev) { struct mii_bus *bus = dev_get_drvdata(dev); diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c index 0a563a83016..53db696b948 100644 --- a/drivers/net/fs_enet/mii-fec.c +++ b/drivers/net/fs_enet/mii-fec.c @@ -113,7 +113,6 @@ static int fs_enet_fec_mii_read(struct mii_bus *bus , int phy_id, int location) } return ret; - } static int fs_enet_fec_mii_write(struct mii_bus *bus, int phy_id, int location, u16 val) -- cgit v1.2.3-70-g09d2 From c6565331b7162a8348c70c37b4c33bedb6d4f02d Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Mon, 1 Oct 2007 14:20:50 -0500 Subject: fs_enet: mac-fcc: Eliminate __fcc-* macros. These macros accomplish nothing other than defeating type checking. This patch also fixes one instance of the wrong register size being used that was revealed by enabling type checking. Signed-off-by: Scott Wood Signed-off-by: Jeff Garzik --- drivers/net/fs_enet/mac-fcc.c | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c index 1e1024a4d43..e990f728d51 100644 --- a/drivers/net/fs_enet/mac-fcc.c +++ b/drivers/net/fs_enet/mac-fcc.c @@ -48,28 +48,19 @@ /* FCC access macros */ -#define __fcc_out32(addr, x) out_be32((unsigned *)addr, x) -#define __fcc_out16(addr, x) out_be16((unsigned short *)addr, x) -#define __fcc_out8(addr, x) out_8((unsigned char *)addr, x) -#define __fcc_in32(addr) in_be32((unsigned *)addr) -#define __fcc_in16(addr) in_be16((unsigned short *)addr) -#define __fcc_in8(addr) in_8((unsigned char *)addr) - -/* parameter space */ - /* write, read, set bits, clear bits */ -#define W32(_p, _m, _v) __fcc_out32(&(_p)->_m, (_v)) -#define R32(_p, _m) __fcc_in32(&(_p)->_m) +#define W32(_p, _m, _v) out_be32(&(_p)->_m, (_v)) +#define R32(_p, _m) in_be32(&(_p)->_m) #define S32(_p, _m, _v) W32(_p, _m, R32(_p, _m) | (_v)) #define C32(_p, _m, _v) W32(_p, _m, R32(_p, _m) & ~(_v)) -#define W16(_p, _m, _v) __fcc_out16(&(_p)->_m, (_v)) -#define R16(_p, _m) __fcc_in16(&(_p)->_m) +#define W16(_p, _m, _v) out_be16(&(_p)->_m, (_v)) +#define R16(_p, _m) in_be16(&(_p)->_m) #define S16(_p, _m, _v) W16(_p, _m, R16(_p, _m) | (_v)) #define C16(_p, _m, _v) W16(_p, _m, R16(_p, _m) & ~(_v)) -#define W8(_p, _m, _v) __fcc_out8(&(_p)->_m, (_v)) -#define R8(_p, _m) __fcc_in8(&(_p)->_m) +#define W8(_p, _m, _v) out_8(&(_p)->_m, (_v)) +#define R8(_p, _m) in_8(&(_p)->_m) #define S8(_p, _m, _v) W8(_p, _m, R8(_p, _m) | (_v)) #define C8(_p, _m, _v) W8(_p, _m, R8(_p, _m) & ~(_v)) @@ -290,7 +281,7 @@ static void restart(struct net_device *dev) /* clear everything (slow & steady does it) */ for (i = 0; i < sizeof(*ep); i++) - __fcc_out8((char *)ep + i, 0); + out_8((char *)ep + i, 0); /* get physical address */ rx_bd_base_phys = fep->ring_mem_addr; @@ -495,7 +486,7 @@ static void tx_kickstart(struct net_device *dev) struct fs_enet_private *fep = netdev_priv(dev); fcc_t *fccp = fep->fcc.fccp; - S32(fccp, fcc_ftodr, 0x80); + S16(fccp, fcc_ftodr, 0x8000); } static u32 get_int_events(struct net_device *dev) -- cgit v1.2.3-70-g09d2 From 0d0d9c150c046cbd3e507adcfa2d78db82f1f452 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Mon, 1 Oct 2007 14:20:52 -0500 Subject: fs_enet: Align receive buffers. At least some hardware driven by this driver needs receive buffers to be aligned on a 16-byte boundary. This usually happens by chance, but it breaks if slab debugging is enabled. Signed-off-by: Scott Wood Signed-off-by: Jeff Garzik --- drivers/net/fs_enet/fs_enet-main.c | 21 +++++++++++++++++++-- drivers/net/fs_enet/fs_enet.h | 3 ++- 2 files changed, 21 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index a15345ba1e5..7a029868787 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -70,6 +70,14 @@ static void fs_set_multicast_list(struct net_device *dev) (*fep->ops->set_multicast_list)(dev); } +static void skb_align(struct sk_buff *skb, int align) +{ + int off = ((unsigned long)skb->data) & (align - 1); + + if (off) + skb_reserve(skb, align - off); +} + /* NAPI receive function */ static int fs_enet_rx_napi(struct napi_struct *napi, int budget) { @@ -159,9 +167,13 @@ static int fs_enet_rx_napi(struct napi_struct *napi, int budget) skb = skbn; skbn = skbt; } - } else + } else { skbn = dev_alloc_skb(ENET_RX_FRSIZE); + if (skbn) + skb_align(skbn, ENET_RX_ALIGN); + } + if (skbn != NULL) { skb_put(skb, pkt_len); /* Make room */ skb->protocol = eth_type_trans(skb, dev); @@ -290,9 +302,13 @@ static int fs_enet_rx_non_napi(struct net_device *dev) skb = skbn; skbn = skbt; } - } else + } else { skbn = dev_alloc_skb(ENET_RX_FRSIZE); + if (skbn) + skb_align(skbn, ENET_RX_ALIGN); + } + if (skbn != NULL) { skb_put(skb, pkt_len); /* Make room */ skb->protocol = eth_type_trans(skb, dev); @@ -502,6 +518,7 @@ void fs_init_bds(struct net_device *dev) dev->name); break; } + skb_align(skb, ENET_RX_ALIGN); fep->rx_skbuff[i] = skb; CBDW_BUFADDR(bdp, dma_map_single(fep->dev, skb->data, diff --git a/drivers/net/fs_enet/fs_enet.h b/drivers/net/fs_enet/fs_enet.h index fbe2087d0d7..85571e49ec7 100644 --- a/drivers/net/fs_enet/fs_enet.h +++ b/drivers/net/fs_enet/fs_enet.h @@ -82,7 +82,8 @@ struct phy_info { /* Must be a multiple of 32 (to cover both FEC & FCC) */ #define PKT_MAXBLR_SIZE ((PKT_MAXBUF_SIZE + 31) & ~31) /* This is needed so that invalidate_xxx wont invalidate too much */ -#define ENET_RX_FRSIZE L1_CACHE_ALIGN(PKT_MAXBUF_SIZE) +#define ENET_RX_ALIGN 16 +#define ENET_RX_FRSIZE L1_CACHE_ALIGN(PKT_MAXBUF_SIZE + ENET_RX_ALIGN - 1) struct fs_enet_mii_bus { struct list_head list; -- cgit v1.2.3-70-g09d2 From 976de6a8c304dcc43e38efcb8a0bace7866b6242 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Tue, 2 Oct 2007 10:55:58 -0500 Subject: fs_enet: Be an of_platform device when CONFIG_PPC_CPM_NEW_BINDING is set. The existing OF glue code was crufty and broken. Rather than fix it, it will be removed, and the ethernet driver now talks to the device tree directly. The old, non-CONFIG_PPC_CPM_NEW_BINDING code can go away once CPM platforms are dropped from arch/ppc (which will hopefully be soon), and existing arch/powerpc boards that I wasn't able to test on for this patchset get converted (which should be even sooner). Signed-off-by: Scott Wood Signed-off-by: Jeff Garzik --- drivers/net/fs_enet/Kconfig | 1 + drivers/net/fs_enet/fs_enet-main.c | 258 ++++++++++++++++++++++++++++++++--- drivers/net/fs_enet/fs_enet.h | 55 +------- drivers/net/fs_enet/mac-fcc.c | 89 ++++++++---- drivers/net/fs_enet/mac-fec.c | 19 ++- drivers/net/fs_enet/mac-scc.c | 53 +++++--- drivers/net/fs_enet/mii-bitbang.c | 269 ++++++++++++++++++++++++++++--------- drivers/net/fs_enet/mii-fec.c | 143 +++++++++++++++++++- include/linux/fs_enet_pd.h | 5 + 9 files changed, 714 insertions(+), 178 deletions(-) (limited to 'drivers') diff --git a/drivers/net/fs_enet/Kconfig b/drivers/net/fs_enet/Kconfig index e27ee210b60..2765e49e07d 100644 --- a/drivers/net/fs_enet/Kconfig +++ b/drivers/net/fs_enet/Kconfig @@ -11,6 +11,7 @@ config FS_ENET_HAS_SCC config FS_ENET_HAS_FCC bool "Chip has an FCC usable for ethernet" depends on FS_ENET && CPM2 + select MDIO_BITBANG default y config FS_ENET_HAS_FEC diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index 7a029868787..fc4fda805d4 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -42,12 +42,18 @@ #include #include +#ifdef CONFIG_PPC_CPM_NEW_BINDING +#include +#endif + #include "fs_enet.h" /*************************************************/ +#ifndef CONFIG_PPC_CPM_NEW_BINDING static char version[] __devinitdata = DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")" "\n"; +#endif MODULE_AUTHOR("Pantelis Antoniou "); MODULE_DESCRIPTION("Freescale Ethernet Driver"); @@ -948,6 +954,7 @@ static int fs_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) extern int fs_mii_connect(struct net_device *dev); extern void fs_mii_disconnect(struct net_device *dev); +#ifndef CONFIG_PPC_CPM_NEW_BINDING static struct net_device *fs_init_instance(struct device *dev, struct fs_platform_info *fpi) { @@ -1129,6 +1136,7 @@ static int fs_cleanup_instance(struct net_device *ndev) return 0; } +#endif /**************************************************************************************/ @@ -1137,35 +1145,250 @@ void *fs_enet_immap = NULL; static int setup_immap(void) { - phys_addr_t paddr = 0; - unsigned long size = 0; - #ifdef CONFIG_CPM1 - paddr = IMAP_ADDR; - size = 0x10000; /* map 64K */ -#endif - -#ifdef CONFIG_CPM2 - paddr = CPM_MAP_ADDR; - size = 0x40000; /* map 256 K */ + fs_enet_immap = ioremap(IMAP_ADDR, 0x4000); + WARN_ON(!fs_enet_immap); +#elif defined(CONFIG_CPM2) + fs_enet_immap = cpm2_immr; #endif - fs_enet_immap = ioremap(paddr, size); - if (fs_enet_immap == NULL) - return -EBADF; /* XXX ahem; maybe just BUG_ON? */ return 0; } static void cleanup_immap(void) { - if (fs_enet_immap != NULL) { - iounmap(fs_enet_immap); - fs_enet_immap = NULL; - } +#if defined(CONFIG_CPM1) + iounmap(fs_enet_immap); +#endif } /**************************************************************************************/ +#ifdef CONFIG_PPC_CPM_NEW_BINDING +static int __devinit find_phy(struct device_node *np, + struct fs_platform_info *fpi) +{ + struct device_node *phynode, *mdionode; + struct resource res; + int ret = 0, len; + + const u32 *data = of_get_property(np, "phy-handle", &len); + if (!data || len != 4) + return -EINVAL; + + phynode = of_find_node_by_phandle(*data); + if (!phynode) + return -EINVAL; + + mdionode = of_get_parent(phynode); + if (!mdionode) + goto out_put_phy; + + ret = of_address_to_resource(mdionode, 0, &res); + if (ret) + goto out_put_mdio; + + data = of_get_property(phynode, "reg", &len); + if (!data || len != 4) + goto out_put_mdio; + + snprintf(fpi->bus_id, 16, PHY_ID_FMT, res.start, *data); + +out_put_mdio: + of_node_put(mdionode); +out_put_phy: + of_node_put(phynode); + return ret; +} + +#ifdef CONFIG_FS_ENET_HAS_FEC +#define IS_FEC(match) ((match)->data == &fs_fec_ops) +#else +#define IS_FEC(match) 0 +#endif + +static int __devinit fs_enet_probe(struct of_device *ofdev, + const struct of_device_id *match) +{ + struct net_device *ndev; + struct fs_enet_private *fep; + struct fs_platform_info *fpi; + const u32 *data; + const u8 *mac_addr; + int privsize, len, ret = -ENODEV; + + fpi = kzalloc(sizeof(*fpi), GFP_KERNEL); + if (!fpi) + return -ENOMEM; + + if (!IS_FEC(match)) { + data = of_get_property(ofdev->node, "fsl,cpm-command", &len); + if (!data || len != 4) + goto out_free_fpi; + + fpi->cp_command = *data; + } + + fpi->rx_ring = 32; + fpi->tx_ring = 32; + fpi->rx_copybreak = 240; + fpi->use_napi = 0; + fpi->napi_weight = 17; + + ret = find_phy(ofdev->node, fpi); + if (ret) + goto out_free_fpi; + + privsize = sizeof(*fep) + + sizeof(struct sk_buff **) * + (fpi->rx_ring + fpi->tx_ring); + + ndev = alloc_etherdev(privsize); + if (!ndev) { + ret = -ENOMEM; + goto out_free_fpi; + } + + SET_MODULE_OWNER(ndev); + dev_set_drvdata(&ofdev->dev, ndev); + + fep = netdev_priv(ndev); + fep->dev = &ofdev->dev; + fep->fpi = fpi; + fep->ops = match->data; + + ret = fep->ops->setup_data(ndev); + if (ret) + goto out_free_dev; + + fep->rx_skbuff = (struct sk_buff **)&fep[1]; + fep->tx_skbuff = fep->rx_skbuff + fpi->rx_ring; + + spin_lock_init(&fep->lock); + spin_lock_init(&fep->tx_lock); + + mac_addr = of_get_mac_address(ofdev->node); + if (mac_addr) + memcpy(ndev->dev_addr, mac_addr, 6); + + ret = fep->ops->allocate_bd(ndev); + if (ret) + goto out_cleanup_data; + + fep->rx_bd_base = fep->ring_base; + fep->tx_bd_base = fep->rx_bd_base + fpi->rx_ring; + + fep->tx_ring = fpi->tx_ring; + fep->rx_ring = fpi->rx_ring; + + ndev->open = fs_enet_open; + ndev->hard_start_xmit = fs_enet_start_xmit; + ndev->tx_timeout = fs_timeout; + ndev->watchdog_timeo = 2 * HZ; + ndev->stop = fs_enet_close; + ndev->get_stats = fs_enet_get_stats; + ndev->set_multicast_list = fs_set_multicast_list; + if (fpi->use_napi) { + ndev->poll = fs_enet_rx_napi; + ndev->weight = fpi->napi_weight; + } + ndev->ethtool_ops = &fs_ethtool_ops; + ndev->do_ioctl = fs_ioctl; + + init_timer(&fep->phy_timer_list); + + netif_carrier_off(ndev); + + ret = register_netdev(ndev); + if (ret) + goto out_free_bd; + + printk(KERN_INFO "%s: fs_enet: %02x:%02x:%02x:%02x:%02x:%02x\n", + ndev->name, + ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2], + ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]); + + return 0; + +out_free_bd: + fep->ops->free_bd(ndev); +out_cleanup_data: + fep->ops->cleanup_data(ndev); +out_free_dev: + free_netdev(ndev); + dev_set_drvdata(&ofdev->dev, NULL); +out_free_fpi: + kfree(fpi); + return ret; +} + +static int fs_enet_remove(struct of_device *ofdev) +{ + struct net_device *ndev = dev_get_drvdata(&ofdev->dev); + struct fs_enet_private *fep = netdev_priv(ndev); + + unregister_netdev(ndev); + + fep->ops->free_bd(ndev); + fep->ops->cleanup_data(ndev); + dev_set_drvdata(fep->dev, NULL); + + free_netdev(ndev); + return 0; +} + +static struct of_device_id fs_enet_match[] = { +#ifdef CONFIG_FS_ENET_HAS_SCC + { + .compatible = "fsl,cpm1-scc-enet", + .data = (void *)&fs_scc_ops, + }, +#endif +#ifdef CONFIG_FS_ENET_HAS_FCC + { + .compatible = "fsl,cpm2-fcc-enet", + .data = (void *)&fs_fcc_ops, + }, +#endif +#ifdef CONFIG_FS_ENET_HAS_FEC + { + .compatible = "fsl,pq1-fec-enet", + .data = (void *)&fs_fec_ops, + }, +#endif + {} +}; + +static struct of_platform_driver fs_enet_driver = { + .name = "fs_enet", + .match_table = fs_enet_match, + .probe = fs_enet_probe, + .remove = fs_enet_remove, +}; + +static int __init fs_init(void) +{ + int r = setup_immap(); + if (r != 0) + return r; + + r = of_register_platform_driver(&fs_enet_driver); + if (r != 0) + goto out; + + return 0; + +out: + cleanup_immap(); + return r; +} + +static void __exit fs_cleanup(void) +{ + of_unregister_platform_driver(&fs_enet_driver); + cleanup_immap(); +} +#else static int __devinit fs_enet_probe(struct device *dev) { struct net_device *ndev; @@ -1279,6 +1502,7 @@ static void __exit fs_cleanup(void) driver_unregister(&fs_enet_scc_driver); cleanup_immap(); } +#endif #ifdef CONFIG_NET_POLL_CONTROLLER static void fs_enet_netpoll(struct net_device *dev) diff --git a/drivers/net/fs_enet/fs_enet.h b/drivers/net/fs_enet/fs_enet.h index 85571e49ec7..5a5c9d18df2 100644 --- a/drivers/net/fs_enet/fs_enet.h +++ b/drivers/net/fs_enet/fs_enet.h @@ -24,19 +24,6 @@ struct fec_info { #include #endif -/* This is used to operate with pins. - Note that the actual port size may - be different; cpm(s) handle it OK */ -struct bb_info { - u8 mdio_dat_msk; - u8 mdio_dir_msk; - u8 *mdio_dir; - u8 *mdio_dat; - u8 mdc_msk; - u8 *mdc_dat; - int delay; -}; - /* hw driver ops */ struct fs_ops { int (*setup_data)(struct net_device *dev); @@ -85,48 +72,12 @@ struct phy_info { #define ENET_RX_ALIGN 16 #define ENET_RX_FRSIZE L1_CACHE_ALIGN(PKT_MAXBUF_SIZE + ENET_RX_ALIGN - 1) -struct fs_enet_mii_bus { - struct list_head list; - spinlock_t mii_lock; - const struct fs_mii_bus_info *bus_info; - int refs; - u32 usage_map; - - int (*mii_read)(struct fs_enet_mii_bus *bus, - int phy_id, int location); - - void (*mii_write)(struct fs_enet_mii_bus *bus, - int phy_id, int location, int value); - - union { - struct { - unsigned int mii_speed; - void *fecp; - } fec; - - struct { - /* note that the actual port size may */ - /* be different; cpm(s) handle it OK */ - u8 mdio_msk; - u8 *mdio_dir; - u8 *mdio_dat; - u8 mdc_msk; - u8 *mdc_dir; - u8 *mdc_dat; - } bitbang; - - struct { - u16 lpa; - } fixed; - }; -}; - struct fs_enet_private { struct napi_struct napi; struct device *dev; /* pointer back to the device (must be initialized first) */ spinlock_t lock; /* during all ops except TX pckt processing */ spinlock_t tx_lock; /* during fs_start_xmit and fs_tx */ - const struct fs_platform_info *fpi; + struct fs_platform_info *fpi; const struct fs_ops *ops; int rx_ring, tx_ring; dma_addr_t ring_mem_addr; @@ -145,7 +96,6 @@ struct fs_enet_private { u32 msg_enable; struct mii_if_info mii_if; unsigned int last_mii_status; - struct fs_enet_mii_bus *mii_bus; int interrupt; struct phy_device *phydev; @@ -187,9 +137,10 @@ struct fs_enet_private { }; /***************************************************************************/ +#ifndef CONFIG_PPC_CPM_NEW_BINDING int fs_enet_mdio_bb_init(void); -int fs_mii_fixed_init(struct fs_enet_mii_bus *bus); int fs_enet_mdio_fec_init(void); +#endif void fs_init_bds(struct net_device *dev); void fs_cleanup_bds(struct net_device *dev); diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c index e990f728d51..6094cbf542a 100644 --- a/drivers/net/fs_enet/mac-fcc.c +++ b/drivers/net/fs_enet/mac-fcc.c @@ -42,6 +42,10 @@ #include #include +#ifdef CONFIG_PPC_CPM_NEW_BINDING +#include +#endif + #include "fs_enet.h" /*************************************************/ @@ -74,33 +78,64 @@ #define MAX_CR_CMD_LOOPS 10000 -static inline int fcc_cr_cmd(struct fs_enet_private *fep, u32 mcn, u32 op) +static inline int fcc_cr_cmd(struct fs_enet_private *fep, u32 op) { const struct fs_platform_info *fpi = fep->fpi; cpm2_map_t *immap = fs_enet_immap; cpm_cpm2_t *cpmp = &immap->im_cpm; - u32 v; int i; - /* Currently I don't know what feature call will look like. But - I guess there'd be something like do_cpm_cmd() which will require page & sblock */ - v = mk_cr_cmd(fpi->cp_page, fpi->cp_block, mcn, op); - W32(cpmp, cp_cpcr, v | CPM_CR_FLG); + W32(cpmp, cp_cpcr, fpi->cp_command | op | CPM_CR_FLG); for (i = 0; i < MAX_CR_CMD_LOOPS; i++) if ((R32(cpmp, cp_cpcr) & CPM_CR_FLG) == 0) - break; - - if (i >= MAX_CR_CMD_LOOPS) { - printk(KERN_ERR "%s(): Not able to issue CPM command\n", - __FUNCTION__); - return 1; - } + return 0; - return 0; + printk(KERN_ERR "%s(): Not able to issue CPM command\n", + __FUNCTION__); + return 1; } static int do_pd_setup(struct fs_enet_private *fep) { +#ifdef CONFIG_PPC_CPM_NEW_BINDING + struct of_device *ofdev = to_of_device(fep->dev); + struct fs_platform_info *fpi = fep->fpi; + int ret = -EINVAL; + + fep->interrupt = of_irq_to_resource(ofdev->node, 0, NULL); + if (fep->interrupt == NO_IRQ) + goto out; + + fep->fcc.fccp = of_iomap(ofdev->node, 0); + if (!fep->fcc.fccp) + goto out; + + fep->fcc.ep = of_iomap(ofdev->node, 1); + if (!fep->fcc.ep) + goto out_fccp; + + fep->fcc.fcccp = of_iomap(ofdev->node, 2); + if (!fep->fcc.fcccp) + goto out_ep; + + fep->fcc.mem = (void *)cpm_dpalloc(128, 8); + fpi->dpram_offset = (u32)cpm2_immr; + if (IS_ERR_VALUE(fpi->dpram_offset)) { + ret = fpi->dpram_offset; + goto out_fcccp; + } + + return 0; + +out_fcccp: + iounmap(fep->fcc.fcccp); +out_ep: + iounmap(fep->fcc.ep); +out_fccp: + iounmap(fep->fcc.fccp); +out: + return ret; +#else struct platform_device *pdev = to_platform_device(fep->dev); struct resource *r; @@ -138,6 +173,7 @@ static int do_pd_setup(struct fs_enet_private *fep) return -EINVAL; return 0; +#endif } #define FCC_NAPI_RX_EVENT_MSK (FCC_ENET_RXF | FCC_ENET_RXB) @@ -148,11 +184,17 @@ static int do_pd_setup(struct fs_enet_private *fep) static int setup_data(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - const struct fs_platform_info *fpi = fep->fpi; +#ifndef CONFIG_PPC_CPM_NEW_BINDING + struct fs_platform_info *fpi = fep->fpi; + + fpi->cp_command = (fpi->cp_page << 26) | + (fpi->cp_block << 21) | + (12 << 6); fep->fcc.idx = fs_get_fcc_index(fpi->fs_no); if ((unsigned int)fep->fcc.idx >= 3) /* max 3 FCCs */ return -EINVAL; +#endif if (do_pd_setup(fep) != 0) return -EINVAL; @@ -226,7 +268,7 @@ static void set_multicast_one(struct net_device *dev, const u8 *mac) W16(ep, fen_taddrh, taddrh); W16(ep, fen_taddrm, taddrm); W16(ep, fen_taddrl, taddrl); - fcc_cr_cmd(fep, 0x0C, CPM_CR_SET_GADDR); + fcc_cr_cmd(fep, CPM_CR_SET_GADDR); } static void set_multicast_finish(struct net_device *dev) @@ -281,7 +323,7 @@ static void restart(struct net_device *dev) /* clear everything (slow & steady does it) */ for (i = 0; i < sizeof(*ep); i++) - out_8((char *)ep + i, 0); + out_8((u8 __iomem *)ep + i, 0); /* get physical address */ rx_bd_base_phys = fep->ring_mem_addr; @@ -397,7 +439,7 @@ static void restart(struct net_device *dev) S8(fcccp, fcc_gfemr, 0x20); } - fcc_cr_cmd(fep, 0x0c, CPM_CR_INIT_TRX); + fcc_cr_cmd(fep, CPM_CR_INIT_TRX); /* clear events */ W16(fccp, fcc_fcce, 0xffff); @@ -515,23 +557,22 @@ int get_regs(struct net_device *dev, void *p, int *sizep) { struct fs_enet_private *fep = netdev_priv(dev); - if (*sizep < sizeof(fcc_t) + sizeof(fcc_c_t) + sizeof(fcc_enet_t)) + if (*sizep < sizeof(fcc_t) + sizeof(fcc_enet_t) + 1) return -EINVAL; memcpy_fromio(p, fep->fcc.fccp, sizeof(fcc_t)); p = (char *)p + sizeof(fcc_t); - memcpy_fromio(p, fep->fcc.fcccp, sizeof(fcc_c_t)); - p = (char *)p + sizeof(fcc_c_t); - memcpy_fromio(p, fep->fcc.ep, sizeof(fcc_enet_t)); + p = (char *)p + sizeof(fcc_enet_t); + memcpy_fromio(p, fep->fcc.fcccp, 1); return 0; } int get_regs_len(struct net_device *dev) { - return sizeof(fcc_t) + sizeof(fcc_c_t) + sizeof(fcc_enet_t); + return sizeof(fcc_t) + sizeof(fcc_enet_t) + 1; } /* Some transmit errors cause the transmitter to shut @@ -551,7 +592,7 @@ void tx_restart(struct net_device *dev) udelay(10); S32(fccp, fcc_gfmr, FCC_GFMR_ENT); - fcc_cr_cmd(fep, 0x0C, CPM_CR_RESTART_TX); + fcc_cr_cmd(fep, CPM_CR_RESTART_TX); } /*************************************************************************/ diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c index cbdc17b743d..924d6617cd3 100644 --- a/drivers/net/fs_enet/mac-fec.c +++ b/drivers/net/fs_enet/mac-fec.c @@ -43,6 +43,10 @@ #include #endif +#ifdef CONFIG_PPC_CPM_NEW_BINDING +#include +#endif + #include "fs_enet.h" #include "fec.h" @@ -95,6 +99,19 @@ static int whack_reset(fec_t * fecp) static int do_pd_setup(struct fs_enet_private *fep) { +#ifdef CONFIG_PPC_CPM_NEW_BINDING + struct of_device *ofdev = to_of_device(fep->dev); + + fep->interrupt = of_irq_to_resource(ofdev->node, 0, NULL); + if (fep->interrupt == NO_IRQ) + return -EINVAL; + + fep->fec.fecp = of_iomap(ofdev->node, 0); + if (!fep->fcc.fccp) + return -EINVAL; + + return 0; +#else struct platform_device *pdev = to_platform_device(fep->dev); struct resource *r; @@ -110,7 +127,7 @@ static int do_pd_setup(struct fs_enet_private *fep) return -EINVAL; return 0; - +#endif } #define FEC_NAPI_RX_EVENT_MSK (FEC_ENET_RXF | FEC_ENET_RXB) diff --git a/drivers/net/fs_enet/mac-scc.c b/drivers/net/fs_enet/mac-scc.c index 6f32674a78e..add9e32d4f4 100644 --- a/drivers/net/fs_enet/mac-scc.c +++ b/drivers/net/fs_enet/mac-scc.c @@ -43,6 +43,10 @@ #include #endif +#ifdef CONFIG_PPC_CPM_NEW_BINDING +#include +#endif + #include "fs_enet.h" /*************************************************/ @@ -89,27 +93,38 @@ static inline int scc_cr_cmd(struct fs_enet_private *fep, u32 op) { - cpm8xx_t *cpmp = &((immap_t *)fs_enet_immap)->im_cpm; - u32 v, ch; - int i = 0; + const struct fs_platform_info *fpi = fep->fpi; + int i; - ch = fep->scc.idx << 2; - v = mk_cr_cmd(ch, op); - W16(cpmp, cp_cpcr, v | CPM_CR_FLG); + W16(cpmp, cp_cpcr, fpi->cp_command | CPM_CR_FLG | (op << 8)); for (i = 0; i < MAX_CR_CMD_LOOPS; i++) if ((R16(cpmp, cp_cpcr) & CPM_CR_FLG) == 0) - break; + return 0; - if (i >= MAX_CR_CMD_LOOPS) { - printk(KERN_ERR "%s(): Not able to issue CPM command\n", - __FUNCTION__); - return 1; - } - return 0; + printk(KERN_ERR "%s(): Not able to issue CPM command\n", + __FUNCTION__); + return 1; } static int do_pd_setup(struct fs_enet_private *fep) { +#ifdef CONFIG_PPC_CPM_NEW_BINDING + struct of_device *ofdev = to_of_device(fep->dev); + + fep->interrupt = of_irq_to_resource(ofdev->node, 0, NULL); + if (fep->interrupt == NO_IRQ) + return -EINVAL; + + fep->scc.sccp = of_iomap(ofdev->node, 0); + if (!fep->scc.sccp) + return -EINVAL; + + fep->scc.ep = of_iomap(ofdev->node, 1); + if (!fep->scc.ep) { + iounmap(fep->scc.sccp); + return -EINVAL; + } +#else struct platform_device *pdev = to_platform_device(fep->dev); struct resource *r; @@ -129,6 +144,7 @@ static int do_pd_setup(struct fs_enet_private *fep) if (fep->scc.ep == NULL) return -EINVAL; +#endif return 0; } @@ -141,12 +157,17 @@ static int do_pd_setup(struct fs_enet_private *fep) static int setup_data(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - const struct fs_platform_info *fpi = fep->fpi; + +#ifdef CONFIG_PPC_CPM_NEW_BINDING + struct fs_platform_info *fpi = fep->fpi; fep->scc.idx = fs_get_scc_index(fpi->fs_no); - if ((unsigned int)fep->fcc.idx > 4) /* max 4 SCCs */ + if ((unsigned int)fep->fcc.idx >= 4) /* max 4 SCCs */ return -EINVAL; + fpi->cp_command = fep->fcc.idx << 6; +#endif + do_pd_setup(fep); fep->scc.hthi = 0; @@ -154,7 +175,7 @@ static int setup_data(struct net_device *dev) fep->ev_napi_rx = SCC_NAPI_RX_EVENT_MSK; fep->ev_rx = SCC_RX_EVENT; - fep->ev_tx = SCC_TX_EVENT; + fep->ev_tx = SCC_TX_EVENT | SCCE_ENET_TXE; fep->ev_err = SCC_ERR_EVENT_MSK; return 0; diff --git a/drivers/net/fs_enet/mii-bitbang.c b/drivers/net/fs_enet/mii-bitbang.c index 422f8287787..7cf132f0f95 100644 --- a/drivers/net/fs_enet/mii-bitbang.c +++ b/drivers/net/fs_enet/mii-bitbang.c @@ -13,11 +13,6 @@ */ #include -#include -#include -#include -#include -#include #include #include #include @@ -25,86 +20,77 @@ #include #include #include -#include -#include #include #include #include #include -#include -#include -#include +#ifdef CONFIG_PPC_CPM_NEW_BINDING +#include +#endif #include "fs_enet.h" -static int bitbang_prep_bit(u8 **datp, u8 *mskp, - struct fs_mii_bit *mii_bit) -{ - void *dat; - int adv; - u8 msk; - - dat = (void*) mii_bit->offset; - - adv = mii_bit->bit >> 3; - dat = (char *)dat + adv; - - msk = 1 << (7 - (mii_bit->bit & 7)); - - *datp = dat; - *mskp = msk; - - return 0; -} +struct bb_info { + __be32 __iomem *dir; + __be32 __iomem *dat; + u32 mdio_msk; + u32 mdc_msk; + int delay; +}; -static inline void bb_set(u8 *p, u8 m) +/* FIXME: If any other users of GPIO crop up, then these will have to + * have some sort of global synchronization to avoid races with other + * pins on the same port. The ideal solution would probably be to + * bind the ports to a GPIO driver, and have this be a client of it. + */ +static inline void bb_set(u32 __iomem *p, u32 m) { - out_8(p, in_8(p) | m); + out_be32(p, in_be32(p) | m); } -static inline void bb_clr(u8 *p, u8 m) +static inline void bb_clr(u32 __iomem *p, u32 m) { - out_8(p, in_8(p) & ~m); + out_be32(p, in_be32(p) & ~m); } -static inline int bb_read(u8 *p, u8 m) +static inline int bb_read(u32 __iomem *p, u32 m) { - return (in_8(p) & m) != 0; + return (in_be32(p) & m) != 0; } static inline void mdio_active(struct bb_info *bitbang) { - bb_set(bitbang->mdio_dir, bitbang->mdio_dir_msk); + bb_set(bitbang->dir, bitbang->mdio_msk); } -static inline void mdio_tristate(struct bb_info *bitbang ) +static inline void mdio_tristate(struct bb_info *bitbang) { - bb_clr(bitbang->mdio_dir, bitbang->mdio_dir_msk); + bb_clr(bitbang->dir, bitbang->mdio_msk); } -static inline int mdio_read(struct bb_info *bitbang ) +static inline int mdio_read(struct bb_info *bitbang) { - return bb_read(bitbang->mdio_dat, bitbang->mdio_dat_msk); + return bb_read(bitbang->dat, bitbang->mdio_msk); } -static inline void mdio(struct bb_info *bitbang , int what) +static inline void mdio(struct bb_info *bitbang, int what) { if (what) - bb_set(bitbang->mdio_dat, bitbang->mdio_dat_msk); + bb_set(bitbang->dat, bitbang->mdio_msk); else - bb_clr(bitbang->mdio_dat, bitbang->mdio_dat_msk); + bb_clr(bitbang->dat, bitbang->mdio_msk); } -static inline void mdc(struct bb_info *bitbang , int what) +static inline void mdc(struct bb_info *bitbang, int what) { if (what) - bb_set(bitbang->mdc_dat, bitbang->mdc_msk); + bb_set(bitbang->dat, bitbang->mdc_msk); else - bb_clr(bitbang->mdc_dat, bitbang->mdc_msk); + bb_clr(bitbang->dat, bitbang->mdc_msk); } -static inline void mii_delay(struct bb_info *bitbang ) +static inline void mii_delay(struct bb_info *bitbang) { udelay(bitbang->delay); } @@ -280,29 +266,178 @@ static int fs_enet_mii_bb_reset(struct mii_bus *bus) return 0; } -static int fs_mii_bitbang_init(struct bb_info *bitbang, struct fs_mii_bb_platform_info* fmpi) +#ifdef CONFIG_PPC_CPM_NEW_BINDING +static int __devinit fs_mii_bitbang_init(struct mii_bus *bus, + struct device_node *np) { - int r; + struct resource res; + const u32 *data; + int mdio_pin, mdc_pin, len; + struct bb_info *bitbang = bus->priv; - bitbang->delay = fmpi->delay; + int ret = of_address_to_resource(np, 0, &res); + if (ret) + return ret; + + if (res.end - res.start < 13) + return -ENODEV; + + /* This should really encode the pin number as well, but all + * we get is an int, and the odds of multiple bitbang mdio buses + * is low enough that it's not worth going too crazy. + */ + bus->id = res.start; + + data = of_get_property(np, "fsl,mdio-pin", &len); + if (!data || len != 4) + return -ENODEV; + mdio_pin = *data; + + data = of_get_property(np, "fsl,mdc-pin", &len); + if (!data || len != 4) + return -ENODEV; + mdc_pin = *data; + + bitbang->dir = ioremap(res.start, res.end - res.start + 1); + if (!bitbang->dir) + return -ENOMEM; + + bitbang->dat = bitbang->dir + 4; + bitbang->mdio_msk = 1 << (31 - mdio_pin); + bitbang->mdc_msk = 1 << (31 - mdc_pin); + bitbang->delay = 1; /* 1 us between operations */ - r = bitbang_prep_bit(&bitbang->mdio_dir, - &bitbang->mdio_dir_msk, - &fmpi->mdio_dir); - if (r != 0) - return r; - - r = bitbang_prep_bit(&bitbang->mdio_dat, - &bitbang->mdio_dat_msk, - &fmpi->mdio_dat); - if (r != 0) - return r; - - r = bitbang_prep_bit(&bitbang->mdc_dat, - &bitbang->mdc_msk, - &fmpi->mdc_dat); - if (r != 0) - return r; + return 0; +} + +static void __devinit add_phy(struct mii_bus *bus, struct device_node *np) +{ + const u32 *data; + int len, id, irq; + + data = of_get_property(np, "reg", &len); + if (!data || len != 4) + return; + + id = *data; + bus->phy_mask &= ~(1 << id); + + irq = of_irq_to_resource(np, 0, NULL); + if (irq != NO_IRQ) + bus->irq[id] = irq; +} + +static int __devinit fs_enet_mdio_probe(struct of_device *ofdev, + const struct of_device_id *match) +{ + struct device_node *np = NULL; + struct mii_bus *new_bus; + struct bb_info *bitbang; + int ret = -ENOMEM; + int i; + + new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL); + if (!new_bus) + goto out; + + bitbang = kzalloc(sizeof(struct bb_info), GFP_KERNEL); + if (!bitbang) + goto out_free_bus; + + new_bus->priv = bitbang; + new_bus->name = "CPM2 Bitbanged MII", + new_bus->read = &fs_enet_mii_bb_read, + new_bus->write = &fs_enet_mii_bb_write, + new_bus->reset = &fs_enet_mii_bb_reset, + + ret = fs_mii_bitbang_init(new_bus, ofdev->node); + if (ret) + goto out_free_bitbang; + + new_bus->phy_mask = ~0; + new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); + if (!new_bus->irq) + goto out_unmap_regs; + + for (i = 0; i < PHY_MAX_ADDR; i++) + new_bus->irq[i] = -1; + + while ((np = of_get_next_child(ofdev->node, np))) + if (!strcmp(np->type, "ethernet-phy")) + add_phy(new_bus, np); + + new_bus->dev = &ofdev->dev; + dev_set_drvdata(&ofdev->dev, new_bus); + + ret = mdiobus_register(new_bus); + if (ret) + goto out_free_irqs; + + return 0; + +out_free_irqs: + dev_set_drvdata(&ofdev->dev, NULL); + kfree(new_bus->irq); +out_unmap_regs: + iounmap(bitbang->dir); +out_free_bitbang: + kfree(bitbang); +out_free_bus: + kfree(new_bus); +out: + return ret; +} + +static int fs_enet_mdio_remove(struct of_device *ofdev) +{ + struct mii_bus *bus = dev_get_drvdata(&ofdev->dev); + struct bb_info *bitbang = bus->priv; + + mdiobus_unregister(bus); + dev_set_drvdata(&ofdev->dev, NULL); + kfree(bus->irq); + iounmap(bitbang->dir); + kfree(bitbang); + kfree(bus); + + return 0; +} + +static struct of_device_id fs_enet_mdio_bb_match[] = { + { + .compatible = "fsl,cpm2-mdio-bitbang", + }, + {}, +}; + +static struct of_platform_driver fs_enet_bb_mdio_driver = { + .name = "fsl-bb-mdio", + .match_table = fs_enet_mdio_bb_match, + .probe = fs_enet_mdio_probe, + .remove = fs_enet_mdio_remove, +}; + +int fs_enet_mdio_bb_init(void) +{ + return of_register_platform_driver(&fs_enet_bb_mdio_driver); +} + +void fs_enet_mdio_bb_exit(void) +{ + of_unregister_platform_driver(&fs_enet_bb_mdio_driver); +} + +module_init(fs_enet_mdio_bb_init); +module_exit(fs_enet_mdio_bb_exit); +#else +static int __devinit fs_mii_bitbang_init(struct bb_info *bitbang, + struct fs_mii_bb_platform_info *fmpi) +{ + bitbang->dir = (u32 __iomem *)fmpi->mdio_dir.offset; + bitbang->dat = (u32 __iomem *)fmpi->mdio_dat.offset; + bitbang->mdio_msk = 1U << (31 - fmpi->mdio_dat.bit); + bitbang->mdc_msk = 1U << (31 - fmpi->mdc_dat.bit); + bitbang->delay = fmpi->delay; return 0; } diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c index 53db696b948..f91c38d0b57 100644 --- a/drivers/net/fs_enet/mii-fec.c +++ b/drivers/net/fs_enet/mii-fec.c @@ -36,6 +36,10 @@ #include #include +#ifdef CONFIG_PPC_CPM_NEW_BINDING +#include +#endif + #include "fs_enet.h" #include "fec.h" @@ -47,6 +51,7 @@ #define FEC_MII_LOOPS 10000 +#ifndef CONFIG_PPC_CPM_NEW_BINDING static int match_has_phy (struct device *dev, void* data) { struct platform_device* pdev = container_of(dev, struct platform_device, dev); @@ -90,6 +95,7 @@ static int fs_mii_fec_init(struct fec_info* fec, struct fs_mii_fec_platform_info return 0; } +#endif static int fs_enet_fec_mii_read(struct mii_bus *bus , int phy_id, int location) { @@ -145,6 +151,141 @@ static int fs_enet_fec_mii_reset(struct mii_bus *bus) return 0; } +#ifdef CONFIG_PPC_CPM_NEW_BINDING +static void __devinit add_phy(struct mii_bus *bus, struct device_node *np) +{ + const u32 *data; + int len, id, irq; + + data = of_get_property(np, "reg", &len); + if (!data || len != 4) + return; + + id = *data; + bus->phy_mask &= ~(1 << id); + + irq = of_irq_to_resource(np, 0, NULL); + if (irq != NO_IRQ) + bus->irq[id] = irq; +} + +static int __devinit fs_enet_mdio_probe(struct of_device *ofdev, + const struct of_device_id *match) +{ + struct device_node *np = NULL; + struct resource res; + struct mii_bus *new_bus; + struct fec_info *fec; + int ret = -ENOMEM, i; + + new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL); + if (!new_bus) + goto out; + + fec = kzalloc(sizeof(struct fec_info), GFP_KERNEL); + if (!fec) + goto out_mii; + + new_bus->priv = fec; + new_bus->name = "FEC MII Bus"; + new_bus->read = &fs_enet_fec_mii_read; + new_bus->write = &fs_enet_fec_mii_write; + new_bus->reset = &fs_enet_fec_mii_reset; + + ret = of_address_to_resource(ofdev->node, 0, &res); + if (ret) + return ret; + + new_bus->id = res.start; + + fec->fecp = ioremap(res.start, res.end - res.start + 1); + if (!fec->fecp) + goto out_fec; + + fec->mii_speed = ((ppc_proc_freq + 4999999) / 5000000) << 1; + + setbits32(&fec->fecp->fec_r_cntrl, FEC_RCNTRL_MII_MODE); + setbits32(&fec->fecp->fec_ecntrl, FEC_ECNTRL_PINMUX | + FEC_ECNTRL_ETHER_EN); + out_be32(&fec->fecp->fec_ievent, FEC_ENET_MII); + out_be32(&fec->fecp->fec_mii_speed, fec->mii_speed); + + new_bus->phy_mask = ~0; + new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); + if (!new_bus->irq) + goto out_unmap_regs; + + for (i = 0; i < PHY_MAX_ADDR; i++) + new_bus->irq[i] = -1; + + while ((np = of_get_next_child(ofdev->node, np))) + if (!strcmp(np->type, "ethernet-phy")) + add_phy(new_bus, np); + + new_bus->dev = &ofdev->dev; + dev_set_drvdata(&ofdev->dev, new_bus); + + ret = mdiobus_register(new_bus); + if (ret) + goto out_free_irqs; + + return 0; + +out_free_irqs: + dev_set_drvdata(&ofdev->dev, NULL); + kfree(new_bus->irq); +out_unmap_regs: + iounmap(fec->fecp); +out_fec: + kfree(fec); +out_mii: + kfree(new_bus); +out: + return ret; +} + +static int fs_enet_mdio_remove(struct of_device *ofdev) +{ + struct mii_bus *bus = dev_get_drvdata(&ofdev->dev); + struct fec_info *fec = bus->priv; + + mdiobus_unregister(bus); + dev_set_drvdata(&ofdev->dev, NULL); + kfree(bus->irq); + iounmap(fec->fecp); + kfree(fec); + kfree(bus); + + return 0; +} + +static struct of_device_id fs_enet_mdio_fec_match[] = { + { + .compatible = "fsl,pq1-fec-mdio", + }, + {}, +}; + +static struct of_platform_driver fs_enet_fec_mdio_driver = { + .name = "fsl-fec-mdio", + .match_table = fs_enet_mdio_fec_match, + .probe = fs_enet_mdio_probe, + .remove = fs_enet_mdio_remove, +}; + +static int fs_enet_mdio_fec_init(void) +{ + return of_register_platform_driver(&fs_enet_fec_mdio_driver); +} + +static void fs_enet_mdio_fec_exit(void) +{ + of_unregister_platform_driver(&fs_enet_fec_mdio_driver); +} + +module_init(fs_enet_mdio_fec_init); +module_exit(fs_enet_mdio_fec_exit); +#else static int __devinit fs_enet_fec_mdio_probe(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); @@ -235,4 +376,4 @@ void fs_enet_mdio_fec_exit(void) { driver_unregister(&fs_enet_fec_mdio_driver); } - +#endif diff --git a/include/linux/fs_enet_pd.h b/include/linux/fs_enet_pd.h index 815c6f94378..9bc045b8c47 100644 --- a/include/linux/fs_enet_pd.h +++ b/include/linux/fs_enet_pd.h @@ -120,6 +120,7 @@ struct fs_platform_info { u32 cp_page; /* CPM page */ u32 cp_block; /* CPM sblock */ + u32 cp_command; /* CPM page/sblock/mcn */ u32 clk_trx; /* some stuff for pins & mux configuration*/ u32 clk_rx; @@ -134,7 +135,11 @@ struct fs_platform_info { u32 device_flags; int phy_addr; /* the phy address (-1 no phy) */ +#ifdef CONFIG_PPC_CPM_NEW_BINDING + char bus_id[16]; +#else const char* bus_id; +#endif int phy_irq; /* the phy irq (if it exists) */ const struct fs_mii_bus_info *bus_info; -- cgit v1.2.3-70-g09d2 From e2ec4581adf7e288c193e981c39ca01cdb20a272 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Mon, 1 Oct 2007 14:20:56 -0500 Subject: Generic bitbanged MDIO library Previously, bitbanged MDIO was only supported in individual hardware-specific drivers. This code factors out the higher level protocol implementation, reducing the hardware-specific portion to functions setting direction, data, and clock. Signed-off-by: Scott Wood Signed-off-by: Jeff Garzik --- drivers/net/phy/Kconfig | 9 ++ drivers/net/phy/Makefile | 1 + drivers/net/phy/mdio-bitbang.c | 187 +++++++++++++++++++++++++++++++++++++++++ include/linux/mdio-bitbang.h | 42 +++++++++ 4 files changed, 239 insertions(+) create mode 100644 drivers/net/phy/mdio-bitbang.c create mode 100644 include/linux/mdio-bitbang.h (limited to 'drivers') diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 432c210513b..54b2ba99664 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -90,4 +90,13 @@ config FIXED_MII_AMNT This control will have specified number allocated for each fixed PHY type enabled. +config MDIO_BITBANG + tristate "Support for bitbanged MDIO buses" + help + This module implements the MDIO bus protocol in software, + for use by low level drivers that export the ability to + drive the relevant pins. + + If in doubt, say N. + endif # PHYLIB diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 8885650647f..3d6cc7b67a8 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -13,3 +13,4 @@ obj-$(CONFIG_VITESSE_PHY) += vitesse.o obj-$(CONFIG_BROADCOM_PHY) += broadcom.o obj-$(CONFIG_ICPLUS_PHY) += icplus.o obj-$(CONFIG_FIXED_PHY) += fixed.o +obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o diff --git a/drivers/net/phy/mdio-bitbang.c b/drivers/net/phy/mdio-bitbang.c new file mode 100644 index 00000000000..8cd243d92af --- /dev/null +++ b/drivers/net/phy/mdio-bitbang.c @@ -0,0 +1,187 @@ +/* + * Bitbanged MDIO support. + * + * Author: Scott Wood + * Copyright (c) 2007 Freescale Semiconductor + * + * Based on CPM2 MDIO code which is: + * + * Copyright (c) 2003 Intracom S.A. + * by Pantelis Antoniou + * + * 2005 (c) MontaVista Software, Inc. + * Vitaly Bordug + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include +#include +#include +#include +#include + +#define MDIO_READ 1 +#define MDIO_WRITE 0 + +#define MDIO_SETUP_TIME 10 +#define MDIO_HOLD_TIME 10 + +/* Minimum MDC period is 400 ns, plus some margin for error. MDIO_DELAY + * is done twice per period. + */ +#define MDIO_DELAY 250 + +/* The PHY may take up to 300 ns to produce data, plus some margin + * for error. + */ +#define MDIO_READ_DELAY 350 + +/* MDIO must already be configured as output. */ +static void mdiobb_send_bit(struct mdiobb_ctrl *ctrl, int val) +{ + const struct mdiobb_ops *ops = ctrl->ops; + + ops->set_mdio_data(ctrl, val); + ndelay(MDIO_DELAY); + ops->set_mdc(ctrl, 1); + ndelay(MDIO_DELAY); + ops->set_mdc(ctrl, 0); +} + +/* MDIO must already be configured as input. */ +static int mdiobb_get_bit(struct mdiobb_ctrl *ctrl) +{ + const struct mdiobb_ops *ops = ctrl->ops; + + ndelay(MDIO_DELAY); + ops->set_mdc(ctrl, 1); + ndelay(MDIO_READ_DELAY); + ops->set_mdc(ctrl, 0); + + return ops->get_mdio_data(ctrl); +} + +/* MDIO must already be configured as output. */ +static void mdiobb_send_num(struct mdiobb_ctrl *ctrl, u16 val, int bits) +{ + int i; + + for (i = bits - 1; i >= 0; i--) + mdiobb_send_bit(ctrl, (val >> i) & 1); +} + +/* MDIO must already be configured as input. */ +static u16 mdiobb_get_num(struct mdiobb_ctrl *ctrl, int bits) +{ + int i; + u16 ret = 0; + + for (i = bits - 1; i >= 0; i--) { + ret <<= 1; + ret |= mdiobb_get_bit(ctrl); + } + + return ret; +} + +/* Utility to send the preamble, address, and + * register (common to read and write). + */ +static void mdiobb_cmd(struct mdiobb_ctrl *ctrl, int read, u8 phy, u8 reg) +{ + const struct mdiobb_ops *ops = ctrl->ops; + int i; + + ops->set_mdio_dir(ctrl, 1); + + /* + * Send a 32 bit preamble ('1's) with an extra '1' bit for good + * measure. The IEEE spec says this is a PHY optional + * requirement. The AMD 79C874 requires one after power up and + * one after a MII communications error. This means that we are + * doing more preambles than we need, but it is safer and will be + * much more robust. + */ + + for (i = 0; i < 32; i++) + mdiobb_send_bit(ctrl, 1); + + /* send the start bit (01) and the read opcode (10) or write (10) */ + mdiobb_send_bit(ctrl, 0); + mdiobb_send_bit(ctrl, 1); + mdiobb_send_bit(ctrl, read); + mdiobb_send_bit(ctrl, !read); + + mdiobb_send_num(ctrl, phy, 5); + mdiobb_send_num(ctrl, reg, 5); +} + + +static int mdiobb_read(struct mii_bus *bus, int phy, int reg) +{ + struct mdiobb_ctrl *ctrl = bus->priv; + int ret, i; + + mdiobb_cmd(ctrl, MDIO_READ, phy, reg); + ctrl->ops->set_mdio_dir(ctrl, 0); + + /* check the turnaround bit: the PHY should be driving it to zero */ + if (mdiobb_get_bit(ctrl) != 0) { + /* PHY didn't drive TA low -- flush any bits it + * may be trying to send. + */ + for (i = 0; i < 32; i++) + mdiobb_get_bit(ctrl); + + return 0xffff; + } + + ret = mdiobb_get_num(ctrl, 16); + mdiobb_get_bit(ctrl); + return ret; +} + +static int mdiobb_write(struct mii_bus *bus, int phy, int reg, u16 val) +{ + struct mdiobb_ctrl *ctrl = bus->priv; + + mdiobb_cmd(ctrl, MDIO_WRITE, phy, reg); + + /* send the turnaround (10) */ + mdiobb_send_bit(ctrl, 1); + mdiobb_send_bit(ctrl, 0); + + mdiobb_send_num(ctrl, val, 16); + + ctrl->ops->set_mdio_dir(ctrl, 0); + mdiobb_get_bit(ctrl); + return 0; +} + +struct mii_bus *alloc_mdio_bitbang(struct mdiobb_ctrl *ctrl) +{ + struct mii_bus *bus; + + bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL); + if (!bus) + return NULL; + + __module_get(ctrl->ops->owner); + + bus->read = mdiobb_read; + bus->write = mdiobb_write; + bus->priv = ctrl; + + return bus; +} + +void free_mdio_bitbang(struct mii_bus *bus) +{ + struct mdiobb_ctrl *ctrl = bus->priv; + + module_put(ctrl->ops->owner); + kfree(bus); +} diff --git a/include/linux/mdio-bitbang.h b/include/linux/mdio-bitbang.h new file mode 100644 index 00000000000..8ea9a42a4c0 --- /dev/null +++ b/include/linux/mdio-bitbang.h @@ -0,0 +1,42 @@ +#ifndef __LINUX_MDIO_BITBANG_H +#define __LINUX_MDIO_BITBANG_H + +#include +#include + +struct mdiobb_ctrl; + +struct mdiobb_ops { + struct module *owner; + + /* Set the Management Data Clock high if level is one, + * low if level is zero. + */ + void (*set_mdc)(struct mdiobb_ctrl *ctrl, int level); + + /* Configure the Management Data I/O pin as an input if + * "output" is zero, or an output if "output" is one. + */ + void (*set_mdio_dir)(struct mdiobb_ctrl *ctrl, int output); + + /* Set the Management Data I/O pin high if value is one, + * low if "value" is zero. This may only be called + * when the MDIO pin is configured as an output. + */ + void (*set_mdio_data)(struct mdiobb_ctrl *ctrl, int value); + + /* Retrieve the state Management Data I/O pin. */ + int (*get_mdio_data)(struct mdiobb_ctrl *ctrl); +}; + +struct mdiobb_ctrl { + const struct mdiobb_ops *ops; +}; + +/* The returned bus is not yet registered with the phy layer. */ +struct mii_bus *alloc_mdio_bitbang(struct mdiobb_ctrl *ctrl); + +/* The bus must already have been unregistered. */ +void free_mdio_bitbang(struct mii_bus *bus); + +#endif -- cgit v1.2.3-70-g09d2 From 2b5b3a604a672be1d41728ed9e448ca3c9c23242 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Mon, 1 Oct 2007 14:20:57 -0500 Subject: fs_enet: Convert mii-bitbang to use the generic bitbang MDIO code. Signed-off-by: Scott Wood Signed-off-by: Jeff Garzik --- drivers/net/fs_enet/mii-bitbang.c | 270 ++++++++------------------------------ 1 file changed, 54 insertions(+), 216 deletions(-) (limited to 'drivers') diff --git a/drivers/net/fs_enet/mii-bitbang.c b/drivers/net/fs_enet/mii-bitbang.c index 7cf132f0f95..b8e4a736a13 100644 --- a/drivers/net/fs_enet/mii-bitbang.c +++ b/drivers/net/fs_enet/mii-bitbang.c @@ -15,15 +15,13 @@ #include #include #include -#include #include -#include +#include #include #include #include -#include -#include #include +#include #ifdef CONFIG_PPC_CPM_NEW_BINDING #include @@ -32,11 +30,11 @@ #include "fs_enet.h" struct bb_info { + struct mdiobb_ctrl ctrl; __be32 __iomem *dir; __be32 __iomem *dat; u32 mdio_msk; u32 mdc_msk; - int delay; }; /* FIXME: If any other users of GPIO crop up, then these will have to @@ -59,212 +57,58 @@ static inline int bb_read(u32 __iomem *p, u32 m) return (in_be32(p) & m) != 0; } -static inline void mdio_active(struct bb_info *bitbang) +static inline void mdio_dir(struct mdiobb_ctrl *ctrl, int dir) { - bb_set(bitbang->dir, bitbang->mdio_msk); -} + struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl); -static inline void mdio_tristate(struct bb_info *bitbang) -{ - bb_clr(bitbang->dir, bitbang->mdio_msk); + if (dir) + bb_set(bitbang->dir, bitbang->mdio_msk); + else + bb_clr(bitbang->dir, bitbang->mdio_msk); + + /* Read back to flush the write. */ + in_be32(bitbang->dir); } -static inline int mdio_read(struct bb_info *bitbang) +static inline int mdio_read(struct mdiobb_ctrl *ctrl) { + struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl); return bb_read(bitbang->dat, bitbang->mdio_msk); } -static inline void mdio(struct bb_info *bitbang, int what) +static inline void mdio(struct mdiobb_ctrl *ctrl, int what) { + struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl); + if (what) bb_set(bitbang->dat, bitbang->mdio_msk); else bb_clr(bitbang->dat, bitbang->mdio_msk); + + /* Read back to flush the write. */ + in_be32(bitbang->dat); } -static inline void mdc(struct bb_info *bitbang, int what) +static inline void mdc(struct mdiobb_ctrl *ctrl, int what) { + struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl); + if (what) bb_set(bitbang->dat, bitbang->mdc_msk); else bb_clr(bitbang->dat, bitbang->mdc_msk); -} - -static inline void mii_delay(struct bb_info *bitbang) -{ - udelay(bitbang->delay); -} - -/* Utility to send the preamble, address, and register (common to read and write). */ -static void bitbang_pre(struct bb_info *bitbang , int read, u8 addr, u8 reg) -{ - int j; - - /* - * Send a 32 bit preamble ('1's) with an extra '1' bit for good measure. - * The IEEE spec says this is a PHY optional requirement. The AMD - * 79C874 requires one after power up and one after a MII communications - * error. This means that we are doing more preambles than we need, - * but it is safer and will be much more robust. - */ - - mdio_active(bitbang); - mdio(bitbang, 1); - for (j = 0; j < 32; j++) { - mdc(bitbang, 0); - mii_delay(bitbang); - mdc(bitbang, 1); - mii_delay(bitbang); - } - - /* send the start bit (01) and the read opcode (10) or write (10) */ - mdc(bitbang, 0); - mdio(bitbang, 0); - mii_delay(bitbang); - mdc(bitbang, 1); - mii_delay(bitbang); - mdc(bitbang, 0); - mdio(bitbang, 1); - mii_delay(bitbang); - mdc(bitbang, 1); - mii_delay(bitbang); - mdc(bitbang, 0); - mdio(bitbang, read); - mii_delay(bitbang); - mdc(bitbang, 1); - mii_delay(bitbang); - mdc(bitbang, 0); - mdio(bitbang, !read); - mii_delay(bitbang); - mdc(bitbang, 1); - mii_delay(bitbang); - - /* send the PHY address */ - for (j = 0; j < 5; j++) { - mdc(bitbang, 0); - mdio(bitbang, (addr & 0x10) != 0); - mii_delay(bitbang); - mdc(bitbang, 1); - mii_delay(bitbang); - addr <<= 1; - } - /* send the register address */ - for (j = 0; j < 5; j++) { - mdc(bitbang, 0); - mdio(bitbang, (reg & 0x10) != 0); - mii_delay(bitbang); - mdc(bitbang, 1); - mii_delay(bitbang); - reg <<= 1; - } + /* Read back to flush the write. */ + in_be32(bitbang->dat); } -static int fs_enet_mii_bb_read(struct mii_bus *bus , int phy_id, int location) -{ - u16 rdreg; - int ret, j; - u8 addr = phy_id & 0xff; - u8 reg = location & 0xff; - struct bb_info* bitbang = bus->priv; - - bitbang_pre(bitbang, 1, addr, reg); - - /* tri-state our MDIO I/O pin so we can read */ - mdc(bitbang, 0); - mdio_tristate(bitbang); - mii_delay(bitbang); - mdc(bitbang, 1); - mii_delay(bitbang); - - /* check the turnaround bit: the PHY should be driving it to zero */ - if (mdio_read(bitbang) != 0) { - /* PHY didn't drive TA low */ - for (j = 0; j < 32; j++) { - mdc(bitbang, 0); - mii_delay(bitbang); - mdc(bitbang, 1); - mii_delay(bitbang); - } - ret = -1; - goto out; - } - - mdc(bitbang, 0); - mii_delay(bitbang); - - /* read 16 bits of register data, MSB first */ - rdreg = 0; - for (j = 0; j < 16; j++) { - mdc(bitbang, 1); - mii_delay(bitbang); - rdreg <<= 1; - rdreg |= mdio_read(bitbang); - mdc(bitbang, 0); - mii_delay(bitbang); - } - - mdc(bitbang, 1); - mii_delay(bitbang); - mdc(bitbang, 0); - mii_delay(bitbang); - mdc(bitbang, 1); - mii_delay(bitbang); - - ret = rdreg; -out: - return ret; -} - -static int fs_enet_mii_bb_write(struct mii_bus *bus, int phy_id, int location, u16 val) -{ - int j; - struct bb_info* bitbang = bus->priv; - - u8 addr = phy_id & 0xff; - u8 reg = location & 0xff; - u16 value = val & 0xffff; - - bitbang_pre(bitbang, 0, addr, reg); - - /* send the turnaround (10) */ - mdc(bitbang, 0); - mdio(bitbang, 1); - mii_delay(bitbang); - mdc(bitbang, 1); - mii_delay(bitbang); - mdc(bitbang, 0); - mdio(bitbang, 0); - mii_delay(bitbang); - mdc(bitbang, 1); - mii_delay(bitbang); - - /* write 16 bits of register data, MSB first */ - for (j = 0; j < 16; j++) { - mdc(bitbang, 0); - mdio(bitbang, (value & 0x8000) != 0); - mii_delay(bitbang); - mdc(bitbang, 1); - mii_delay(bitbang); - value <<= 1; - } - - /* - * Tri-state the MDIO line. - */ - mdio_tristate(bitbang); - mdc(bitbang, 0); - mii_delay(bitbang); - mdc(bitbang, 1); - mii_delay(bitbang); - return 0; -} - -static int fs_enet_mii_bb_reset(struct mii_bus *bus) -{ - /*nothing here - dunno how to reset it*/ - return 0; -} +static struct mdiobb_ops bb_ops = { + .owner = THIS_MODULE, + .set_mdc = mdc, + .set_mdio_dir = mdio_dir, + .set_mdio_data = mdio, + .get_mdio_data = mdio_read, +}; #ifdef CONFIG_PPC_CPM_NEW_BINDING static int __devinit fs_mii_bitbang_init(struct mii_bus *bus, @@ -305,7 +149,6 @@ static int __devinit fs_mii_bitbang_init(struct mii_bus *bus, bitbang->dat = bitbang->dir + 4; bitbang->mdio_msk = 1 << (31 - mdio_pin); bitbang->mdc_msk = 1 << (31 - mdc_pin); - bitbang->delay = 1; /* 1 us between operations */ return 0; } @@ -336,23 +179,21 @@ static int __devinit fs_enet_mdio_probe(struct of_device *ofdev, int ret = -ENOMEM; int i; - new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL); - if (!new_bus) - goto out; - bitbang = kzalloc(sizeof(struct bb_info), GFP_KERNEL); if (!bitbang) - goto out_free_bus; + goto out; + + bitbang->ctrl.ops = &bb_ops; + + new_bus = alloc_mdio_bitbang(&bitbang->ctrl); + if (!new_bus) + goto out_free_priv; - new_bus->priv = bitbang; new_bus->name = "CPM2 Bitbanged MII", - new_bus->read = &fs_enet_mii_bb_read, - new_bus->write = &fs_enet_mii_bb_write, - new_bus->reset = &fs_enet_mii_bb_reset, ret = fs_mii_bitbang_init(new_bus, ofdev->node); if (ret) - goto out_free_bitbang; + goto out_free_bus; new_bus->phy_mask = ~0; new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); @@ -380,10 +221,10 @@ out_free_irqs: kfree(new_bus->irq); out_unmap_regs: iounmap(bitbang->dir); -out_free_bitbang: - kfree(bitbang); out_free_bus: kfree(new_bus); +out_free_priv: + free_mdio_bitbang(new_bus); out: return ret; } @@ -394,6 +235,7 @@ static int fs_enet_mdio_remove(struct of_device *ofdev) struct bb_info *bitbang = bus->priv; mdiobus_unregister(bus); + free_mdio_bitbang(bus); dev_set_drvdata(&ofdev->dev, NULL); kfree(bus->irq); iounmap(bitbang->dir); @@ -417,12 +259,12 @@ static struct of_platform_driver fs_enet_bb_mdio_driver = { .remove = fs_enet_mdio_remove, }; -int fs_enet_mdio_bb_init(void) +static int fs_enet_mdio_bb_init(void) { return of_register_platform_driver(&fs_enet_bb_mdio_driver); } -void fs_enet_mdio_bb_exit(void) +static void fs_enet_mdio_bb_exit(void) { of_unregister_platform_driver(&fs_enet_bb_mdio_driver); } @@ -437,7 +279,6 @@ static int __devinit fs_mii_bitbang_init(struct bb_info *bitbang, bitbang->dat = (u32 __iomem *)fmpi->mdio_dat.offset; bitbang->mdio_msk = 1U << (31 - fmpi->mdio_dat.bit); bitbang->mdc_msk = 1U << (31 - fmpi->mdc_dat.bit); - bitbang->delay = fmpi->delay; return 0; } @@ -453,20 +294,19 @@ static int __devinit fs_enet_mdio_probe(struct device *dev) if (NULL == dev) return -EINVAL; - new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL); + bitbang = kzalloc(sizeof(struct bb_info), GFP_KERNEL); - if (NULL == new_bus) + if (NULL == bitbang) return -ENOMEM; - bitbang = kzalloc(sizeof(struct bb_info), GFP_KERNEL); + bitbang->ctrl.ops = &bb_ops; - if (NULL == bitbang) + new_bus = alloc_mdio_bitbang(&bitbang->ctrl); + + if (NULL == new_bus) return -ENOMEM; new_bus->name = "BB MII Bus", - new_bus->read = &fs_enet_mii_bb_read, - new_bus->write = &fs_enet_mii_bb_write, - new_bus->reset = &fs_enet_mii_bb_reset, new_bus->id = pdev->id; new_bus->phy_mask = ~0x9; @@ -498,8 +338,8 @@ static int __devinit fs_enet_mdio_probe(struct device *dev) return 0; bus_register_fail: + free_mdio_bitbang(new_bus); kfree(bitbang); - kfree(new_bus); return err; } @@ -512,9 +352,7 @@ static int fs_enet_mdio_remove(struct device *dev) dev_set_drvdata(dev, NULL); - iounmap((void *) (&bus->priv)); - bus->priv = NULL; - kfree(bus); + free_mdio_bitbang(bus); return 0; } @@ -535,4 +373,4 @@ void fs_enet_mdio_bb_exit(void) { driver_unregister(&fs_enet_bb_mdio_driver); } - +#endif -- cgit v1.2.3-70-g09d2 From 31a5bb04d59931eb4657826213a439d37d12d4a9 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Mon, 1 Oct 2007 14:20:58 -0500 Subject: fs_enet: sparse fixes Mostly a bunch of __iomem annotations. Signed-off-by: Scott Wood Signed-off-by: Jeff Garzik --- drivers/net/fs_enet/fs_enet-main.c | 18 +++++----- drivers/net/fs_enet/fs_enet.h | 30 ++++++++-------- drivers/net/fs_enet/mac-fcc.c | 71 +++++++++++++++++++++----------------- drivers/net/fs_enet/mac-fec.c | 34 +++++++++--------- drivers/net/fs_enet/mac-scc.c | 37 ++++++++++---------- drivers/net/fs_enet/mii-fec.c | 8 ++--- 6 files changed, 103 insertions(+), 95 deletions(-) (limited to 'drivers') diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index fc4fda805d4..04c6faec88d 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -60,7 +60,7 @@ MODULE_DESCRIPTION("Freescale Ethernet Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_MODULE_VERSION); -int fs_enet_debug = -1; /* -1 == use FS_ENET_DEF_MSG_ENABLE as value */ +static int fs_enet_debug = -1; /* -1 == use FS_ENET_DEF_MSG_ENABLE as value */ module_param(fs_enet_debug, int, 0); MODULE_PARM_DESC(fs_enet_debug, "Freescale bitmapped debugging message enable value"); @@ -90,7 +90,7 @@ static int fs_enet_rx_napi(struct napi_struct *napi, int budget) struct fs_enet_private *fep = container_of(napi, struct fs_enet_private, napi); struct net_device *dev = to_net_dev(fep->dev); const struct fs_platform_info *fpi = fep->fpi; - cbd_t *bdp; + cbd_t __iomem *bdp; struct sk_buff *skb, *skbn, *skbt; int received = 0; u16 pkt_len, sc; @@ -230,7 +230,7 @@ static int fs_enet_rx_non_napi(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); const struct fs_platform_info *fpi = fep->fpi; - cbd_t *bdp; + cbd_t __iomem *bdp; struct sk_buff *skb, *skbn, *skbt; int received = 0; u16 pkt_len, sc; @@ -355,7 +355,7 @@ static int fs_enet_rx_non_napi(struct net_device *dev) static void fs_enet_tx(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - cbd_t *bdp; + cbd_t __iomem *bdp; struct sk_buff *skb; int dirtyidx, do_wake, do_restart; u16 sc; @@ -503,7 +503,7 @@ fs_enet_interrupt(int irq, void *dev_id) void fs_init_bds(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - cbd_t *bdp; + cbd_t __iomem *bdp; struct sk_buff *skb; int i; @@ -557,7 +557,7 @@ void fs_cleanup_bds(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); struct sk_buff *skb; - cbd_t *bdp; + cbd_t __iomem *bdp; int i; /* @@ -598,7 +598,7 @@ void fs_cleanup_bds(struct net_device *dev) static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - cbd_t *bdp; + cbd_t __iomem *bdp; int curidx; u16 sc; unsigned long flags; @@ -1121,7 +1121,7 @@ static int fs_cleanup_instance(struct net_device *ndev) unregister_netdev(ndev); dma_free_coherent(fep->dev, (fpi->tx_ring + fpi->rx_ring) * sizeof(cbd_t), - fep->ring_base, fep->ring_mem_addr); + (void __force *)fep->ring_base, fep->ring_mem_addr); /* reset it */ (*fep->ops->cleanup_data)(ndev); @@ -1141,7 +1141,7 @@ static int fs_cleanup_instance(struct net_device *ndev) /**************************************************************************************/ /* handy pointer to the immap */ -void *fs_enet_immap = NULL; +void __iomem *fs_enet_immap = NULL; static int setup_immap(void) { diff --git a/drivers/net/fs_enet/fs_enet.h b/drivers/net/fs_enet/fs_enet.h index 5a5c9d18df2..baf6477165a 100644 --- a/drivers/net/fs_enet/fs_enet.h +++ b/drivers/net/fs_enet/fs_enet.h @@ -15,7 +15,7 @@ #include struct fec_info { - fec_t *fecp; + fec_t __iomem *fecp; u32 mii_speed; }; #endif @@ -81,14 +81,14 @@ struct fs_enet_private { const struct fs_ops *ops; int rx_ring, tx_ring; dma_addr_t ring_mem_addr; - void *ring_base; + void __iomem *ring_base; struct sk_buff **rx_skbuff; struct sk_buff **tx_skbuff; - cbd_t *rx_bd_base; /* Address of Rx and Tx buffers. */ - cbd_t *tx_bd_base; - cbd_t *dirty_tx; /* ring entries to be free()ed. */ - cbd_t *cur_rx; - cbd_t *cur_tx; + cbd_t __iomem *rx_bd_base; /* Address of Rx and Tx buffers. */ + cbd_t __iomem *tx_bd_base; + cbd_t __iomem *dirty_tx; /* ring entries to be free()ed. */ + cbd_t __iomem *cur_rx; + cbd_t __iomem *cur_tx; int tx_free; struct net_device_stats stats; struct timer_list phy_timer_list; @@ -113,23 +113,23 @@ struct fs_enet_private { union { struct { int idx; /* FEC1 = 0, FEC2 = 1 */ - void *fecp; /* hw registers */ + void __iomem *fecp; /* hw registers */ u32 hthi, htlo; /* state for multicast */ } fec; struct { int idx; /* FCC1-3 = 0-2 */ - void *fccp; /* hw registers */ - void *ep; /* parameter ram */ - void *fcccp; /* hw registers cont. */ - void *mem; /* FCC DPRAM */ + void __iomem *fccp; /* hw registers */ + void __iomem *ep; /* parameter ram */ + void __iomem *fcccp; /* hw registers cont. */ + void __iomem *mem; /* FCC DPRAM */ u32 gaddrh, gaddrl; /* group address */ } fcc; struct { int idx; /* FEC1 = 0, FEC2 = 1 */ - void *sccp; /* hw registers */ - void *ep; /* parameter ram */ + void __iomem *sccp; /* hw registers */ + void __iomem *ep; /* parameter ram */ u32 hthi, htlo; /* state for multicast */ } scc; @@ -200,7 +200,7 @@ extern const struct fs_ops fs_scc_ops; /*******************************************************************/ /* handy pointer to the immap */ -extern void *fs_enet_immap; +extern void __iomem *fs_enet_immap; /*******************************************************************/ diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c index 6094cbf542a..da4efbca646 100644 --- a/drivers/net/fs_enet/mac-fcc.c +++ b/drivers/net/fs_enet/mac-fcc.c @@ -81,8 +81,6 @@ static inline int fcc_cr_cmd(struct fs_enet_private *fep, u32 op) { const struct fs_platform_info *fpi = fep->fpi; - cpm2_map_t *immap = fs_enet_immap; - cpm_cpm2_t *cpmp = &immap->im_cpm; int i; W32(cpmp, cp_cpcr, fpi->cp_command | op | CPM_CR_FLG); @@ -118,8 +116,8 @@ static int do_pd_setup(struct fs_enet_private *fep) if (!fep->fcc.fcccp) goto out_ep; - fep->fcc.mem = (void *)cpm_dpalloc(128, 8); - fpi->dpram_offset = (u32)cpm2_immr; + fep->fcc.mem = (void __iomem *)cpm2_immr; + fpi->dpram_offset = cpm_dpalloc(128, 8); if (IS_ERR_VALUE(fpi->dpram_offset)) { ret = fpi->dpram_offset; goto out_fcccp; @@ -146,29 +144,28 @@ out: /* Attach the memory for the FCC Parameter RAM */ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fcc_pram"); - fep->fcc.ep = (void *)ioremap(r->start, r->end - r->start + 1); + fep->fcc.ep = ioremap(r->start, r->end - r->start + 1); if (fep->fcc.ep == NULL) return -EINVAL; r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fcc_regs"); - fep->fcc.fccp = (void *)ioremap(r->start, r->end - r->start + 1); + fep->fcc.fccp = ioremap(r->start, r->end - r->start + 1); if (fep->fcc.fccp == NULL) return -EINVAL; if (fep->fpi->fcc_regs_c) { - - fep->fcc.fcccp = (void *)fep->fpi->fcc_regs_c; + fep->fcc.fcccp = (void __iomem *)fep->fpi->fcc_regs_c; } else { r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fcc_regs_c"); - fep->fcc.fcccp = (void *)ioremap(r->start, + fep->fcc.fcccp = ioremap(r->start, r->end - r->start + 1); } if (fep->fcc.fcccp == NULL) return -EINVAL; - fep->fcc.mem = (void *)fep->fpi->mem_offset; + fep->fcc.mem = (void __iomem *)fep->fpi->mem_offset; if (fep->fcc.mem == NULL) return -EINVAL; @@ -212,7 +209,7 @@ static int allocate_bd(struct net_device *dev) struct fs_enet_private *fep = netdev_priv(dev); const struct fs_platform_info *fpi = fep->fpi; - fep->ring_base = dma_alloc_coherent(fep->dev, + fep->ring_base = (void __iomem __force *)dma_alloc_coherent(fep->dev, (fpi->tx_ring + fpi->rx_ring) * sizeof(cbd_t), &fep->ring_mem_addr, GFP_KERNEL); @@ -230,7 +227,7 @@ static void free_bd(struct net_device *dev) if (fep->ring_base) dma_free_coherent(fep->dev, (fpi->tx_ring + fpi->rx_ring) * sizeof(cbd_t), - fep->ring_base, fep->ring_mem_addr); + (void __force *)fep->ring_base, fep->ring_mem_addr); } static void cleanup_data(struct net_device *dev) @@ -241,7 +238,7 @@ static void cleanup_data(struct net_device *dev) static void set_promiscuous_mode(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - fcc_t *fccp = fep->fcc.fccp; + fcc_t __iomem *fccp = fep->fcc.fccp; S32(fccp, fcc_fpsmr, FCC_PSMR_PRO); } @@ -249,7 +246,7 @@ static void set_promiscuous_mode(struct net_device *dev) static void set_multicast_start(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - fcc_enet_t *ep = fep->fcc.ep; + fcc_enet_t __iomem *ep = fep->fcc.ep; W32(ep, fen_gaddrh, 0); W32(ep, fen_gaddrl, 0); @@ -258,7 +255,7 @@ static void set_multicast_start(struct net_device *dev) static void set_multicast_one(struct net_device *dev, const u8 *mac) { struct fs_enet_private *fep = netdev_priv(dev); - fcc_enet_t *ep = fep->fcc.ep; + fcc_enet_t __iomem *ep = fep->fcc.ep; u16 taddrh, taddrm, taddrl; taddrh = ((u16)mac[5] << 8) | mac[4]; @@ -274,8 +271,8 @@ static void set_multicast_one(struct net_device *dev, const u8 *mac) static void set_multicast_finish(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - fcc_t *fccp = fep->fcc.fccp; - fcc_enet_t *ep = fep->fcc.ep; + fcc_t __iomem *fccp = fep->fcc.fccp; + fcc_enet_t __iomem *ep = fep->fcc.ep; /* clear promiscuous always */ C32(fccp, fcc_fpsmr, FCC_PSMR_PRO); @@ -310,12 +307,14 @@ static void restart(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); const struct fs_platform_info *fpi = fep->fpi; - fcc_t *fccp = fep->fcc.fccp; - fcc_c_t *fcccp = fep->fcc.fcccp; - fcc_enet_t *ep = fep->fcc.ep; + fcc_t __iomem *fccp = fep->fcc.fccp; + fcc_c_t __iomem *fcccp = fep->fcc.fcccp; + fcc_enet_t __iomem *ep = fep->fcc.ep; dma_addr_t rx_bd_base_phys, tx_bd_base_phys; u16 paddrh, paddrm, paddrl; +#ifndef CONFIG_PPC_CPM_NEW_BINDING u16 mem_addr; +#endif const unsigned char *mac; int i; @@ -347,14 +346,22 @@ static void restart(struct net_device *dev) * this area. */ +#ifdef CONFIG_PPC_CPM_NEW_BINDING + W16(ep, fen_genfcc.fcc_riptr, fpi->dpram_offset); + W16(ep, fen_genfcc.fcc_tiptr, fpi->dpram_offset + 32); + + W16(ep, fen_padptr, fpi->dpram_offset + 64); +#else mem_addr = (u32) fep->fcc.mem; /* de-fixup dpram offset */ W16(ep, fen_genfcc.fcc_riptr, (mem_addr & 0xffff)); W16(ep, fen_genfcc.fcc_tiptr, ((mem_addr + 32) & 0xffff)); + W16(ep, fen_padptr, mem_addr + 64); +#endif /* fill with special symbol... */ - memset(fep->fcc.mem + fpi->dpram_offset + 64, 0x88, 32); + memset_io(fep->fcc.mem + fpi->dpram_offset + 64, 0x88, 32); W32(ep, fen_genfcc.fcc_rbptr, 0); W32(ep, fen_genfcc.fcc_tbptr, 0); @@ -470,7 +477,7 @@ static void restart(struct net_device *dev) static void stop(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - fcc_t *fccp = fep->fcc.fccp; + fcc_t __iomem *fccp = fep->fcc.fccp; /* stop ethernet */ C32(fccp, fcc_gfmr, FCC_GFMR_ENR | FCC_GFMR_ENT); @@ -497,7 +504,7 @@ static void post_free_irq(struct net_device *dev, int irq) static void napi_clear_rx_event(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - fcc_t *fccp = fep->fcc.fccp; + fcc_t __iomem *fccp = fep->fcc.fccp; W16(fccp, fcc_fcce, FCC_NAPI_RX_EVENT_MSK); } @@ -505,7 +512,7 @@ static void napi_clear_rx_event(struct net_device *dev) static void napi_enable_rx(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - fcc_t *fccp = fep->fcc.fccp; + fcc_t __iomem *fccp = fep->fcc.fccp; S16(fccp, fcc_fccm, FCC_NAPI_RX_EVENT_MSK); } @@ -513,7 +520,7 @@ static void napi_enable_rx(struct net_device *dev) static void napi_disable_rx(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - fcc_t *fccp = fep->fcc.fccp; + fcc_t __iomem *fccp = fep->fcc.fccp; C16(fccp, fcc_fccm, FCC_NAPI_RX_EVENT_MSK); } @@ -526,7 +533,7 @@ static void rx_bd_done(struct net_device *dev) static void tx_kickstart(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - fcc_t *fccp = fep->fcc.fccp; + fcc_t __iomem *fccp = fep->fcc.fccp; S16(fccp, fcc_ftodr, 0x8000); } @@ -534,7 +541,7 @@ static void tx_kickstart(struct net_device *dev) static u32 get_int_events(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - fcc_t *fccp = fep->fcc.fccp; + fcc_t __iomem *fccp = fep->fcc.fccp; return (u32)R16(fccp, fcc_fcce); } @@ -542,7 +549,7 @@ static u32 get_int_events(struct net_device *dev) static void clear_int_events(struct net_device *dev, u32 int_events) { struct fs_enet_private *fep = netdev_priv(dev); - fcc_t *fccp = fep->fcc.fccp; + fcc_t __iomem *fccp = fep->fcc.fccp; W16(fccp, fcc_fcce, int_events & 0xffff); } @@ -553,7 +560,7 @@ static void ev_error(struct net_device *dev, u32 int_events) ": %s FS_ENET ERROR(s) 0x%x\n", dev->name, int_events); } -int get_regs(struct net_device *dev, void *p, int *sizep) +static int get_regs(struct net_device *dev, void *p, int *sizep) { struct fs_enet_private *fep = netdev_priv(dev); @@ -570,7 +577,7 @@ int get_regs(struct net_device *dev, void *p, int *sizep) return 0; } -int get_regs_len(struct net_device *dev) +static int get_regs_len(struct net_device *dev) { return sizeof(fcc_t) + sizeof(fcc_enet_t) + 1; } @@ -583,10 +590,10 @@ int get_regs_len(struct net_device *dev) * CPM37, we must disable and then re-enable the transmitter * following a Late Collision, Underrun, or Retry Limit error. */ -void tx_restart(struct net_device *dev) +static void tx_restart(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - fcc_t *fccp = fep->fcc.fccp; + fcc_t __iomem *fccp = fep->fcc.fccp; C32(fccp, fcc_gfmr, FCC_GFMR_ENT); udelay(10); diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c index 924d6617cd3..c1fee48517e 100644 --- a/drivers/net/fs_enet/mac-fec.c +++ b/drivers/net/fs_enet/mac-fec.c @@ -83,7 +83,7 @@ */ #define FEC_RESET_DELAY 50 -static int whack_reset(fec_t * fecp) +static int whack_reset(fec_t __iomem *fecp) { int i; @@ -159,7 +159,7 @@ static int allocate_bd(struct net_device *dev) struct fs_enet_private *fep = netdev_priv(dev); const struct fs_platform_info *fpi = fep->fpi; - fep->ring_base = dma_alloc_coherent(fep->dev, + fep->ring_base = (void __force __iomem *)dma_alloc_coherent(fep->dev, (fpi->tx_ring + fpi->rx_ring) * sizeof(cbd_t), &fep->ring_mem_addr, GFP_KERNEL); @@ -177,7 +177,7 @@ static void free_bd(struct net_device *dev) if(fep->ring_base) dma_free_coherent(fep->dev, (fpi->tx_ring + fpi->rx_ring) * sizeof(cbd_t), - fep->ring_base, + (void __force *)fep->ring_base, fep->ring_mem_addr); } @@ -189,7 +189,7 @@ static void cleanup_data(struct net_device *dev) static void set_promiscuous_mode(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - fec_t *fecp = fep->fec.fecp; + fec_t __iomem *fecp = fep->fec.fecp; FS(fecp, r_cntrl, FEC_RCNTRL_PROM); } @@ -237,7 +237,7 @@ static void set_multicast_one(struct net_device *dev, const u8 *mac) static void set_multicast_finish(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - fec_t *fecp = fep->fec.fecp; + fec_t __iomem *fecp = fep->fec.fecp; /* if all multi or too many multicasts; just enable all */ if ((dev->flags & IFF_ALLMULTI) != 0 || @@ -271,7 +271,7 @@ static void restart(struct net_device *dev) u32 cptr; #endif struct fs_enet_private *fep = netdev_priv(dev); - fec_t *fecp = fep->fec.fecp; + fec_t __iomem *fecp = fep->fec.fecp; const struct fs_platform_info *fpi = fep->fpi; dma_addr_t rx_bd_base_phys, tx_bd_base_phys; int r; @@ -399,7 +399,7 @@ static void stop(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); const struct fs_platform_info *fpi = fep->fpi; - fec_t *fecp = fep->fec.fecp; + fec_t __iomem *fecp = fep->fec.fecp; struct fec_info* feci= fep->phydev->bus->priv; @@ -461,7 +461,7 @@ static void post_free_irq(struct net_device *dev, int irq) static void napi_clear_rx_event(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - fec_t *fecp = fep->fec.fecp; + fec_t __iomem *fecp = fep->fec.fecp; FW(fecp, ievent, FEC_NAPI_RX_EVENT_MSK); } @@ -469,7 +469,7 @@ static void napi_clear_rx_event(struct net_device *dev) static void napi_enable_rx(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - fec_t *fecp = fep->fec.fecp; + fec_t __iomem *fecp = fep->fec.fecp; FS(fecp, imask, FEC_NAPI_RX_EVENT_MSK); } @@ -477,7 +477,7 @@ static void napi_enable_rx(struct net_device *dev) static void napi_disable_rx(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - fec_t *fecp = fep->fec.fecp; + fec_t __iomem *fecp = fep->fec.fecp; FC(fecp, imask, FEC_NAPI_RX_EVENT_MSK); } @@ -485,7 +485,7 @@ static void napi_disable_rx(struct net_device *dev) static void rx_bd_done(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - fec_t *fecp = fep->fec.fecp; + fec_t __iomem *fecp = fep->fec.fecp; FW(fecp, r_des_active, 0x01000000); } @@ -493,7 +493,7 @@ static void rx_bd_done(struct net_device *dev) static void tx_kickstart(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - fec_t *fecp = fep->fec.fecp; + fec_t __iomem *fecp = fep->fec.fecp; FW(fecp, x_des_active, 0x01000000); } @@ -501,7 +501,7 @@ static void tx_kickstart(struct net_device *dev) static u32 get_int_events(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - fec_t *fecp = fep->fec.fecp; + fec_t __iomem *fecp = fep->fec.fecp; return FR(fecp, ievent) & FR(fecp, imask); } @@ -509,7 +509,7 @@ static u32 get_int_events(struct net_device *dev) static void clear_int_events(struct net_device *dev, u32 int_events) { struct fs_enet_private *fep = netdev_priv(dev); - fec_t *fecp = fep->fec.fecp; + fec_t __iomem *fecp = fep->fec.fecp; FW(fecp, ievent, int_events); } @@ -520,7 +520,7 @@ static void ev_error(struct net_device *dev, u32 int_events) ": %s FEC ERROR(s) 0x%x\n", dev->name, int_events); } -int get_regs(struct net_device *dev, void *p, int *sizep) +static int get_regs(struct net_device *dev, void *p, int *sizep) { struct fs_enet_private *fep = netdev_priv(dev); @@ -532,12 +532,12 @@ int get_regs(struct net_device *dev, void *p, int *sizep) return 0; } -int get_regs_len(struct net_device *dev) +static int get_regs_len(struct net_device *dev) { return sizeof(fec_t); } -void tx_restart(struct net_device *dev) +static void tx_restart(struct net_device *dev) { /* nothing */ } diff --git a/drivers/net/fs_enet/mac-scc.c b/drivers/net/fs_enet/mac-scc.c index add9e32d4f4..03134f47a4e 100644 --- a/drivers/net/fs_enet/mac-scc.c +++ b/drivers/net/fs_enet/mac-scc.c @@ -191,7 +191,8 @@ static int allocate_bd(struct net_device *dev) if (IS_ERR_VALUE(fep->ring_mem_addr)) return -ENOMEM; - fep->ring_base = cpm_dpram_addr(fep->ring_mem_addr); + fep->ring_base = (void __iomem __force*) + cpm_dpram_addr(fep->ring_mem_addr); return 0; } @@ -212,7 +213,7 @@ static void cleanup_data(struct net_device *dev) static void set_promiscuous_mode(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - scc_t *sccp = fep->scc.sccp; + scc_t __iomem *sccp = fep->scc.sccp; S16(sccp, scc_psmr, SCC_PSMR_PRO); } @@ -220,7 +221,7 @@ static void set_promiscuous_mode(struct net_device *dev) static void set_multicast_start(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - scc_enet_t *ep = fep->scc.ep; + scc_enet_t __iomem *ep = fep->scc.ep; W16(ep, sen_gaddr1, 0); W16(ep, sen_gaddr2, 0); @@ -231,7 +232,7 @@ static void set_multicast_start(struct net_device *dev) static void set_multicast_one(struct net_device *dev, const u8 * mac) { struct fs_enet_private *fep = netdev_priv(dev); - scc_enet_t *ep = fep->scc.ep; + scc_enet_t __iomem *ep = fep->scc.ep; u16 taddrh, taddrm, taddrl; taddrh = ((u16) mac[5] << 8) | mac[4]; @@ -247,8 +248,8 @@ static void set_multicast_one(struct net_device *dev, const u8 * mac) static void set_multicast_finish(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - scc_t *sccp = fep->scc.sccp; - scc_enet_t *ep = fep->scc.ep; + scc_t __iomem *sccp = fep->scc.sccp; + scc_enet_t __iomem *ep = fep->scc.ep; /* clear promiscuous always */ C16(sccp, scc_psmr, SCC_PSMR_PRO); @@ -285,8 +286,8 @@ static void set_multicast_list(struct net_device *dev) static void restart(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - scc_t *sccp = fep->scc.sccp; - scc_enet_t *ep = fep->scc.ep; + scc_t __iomem *sccp = fep->scc.sccp; + scc_enet_t __iomem *ep = fep->scc.ep; const struct fs_platform_info *fpi = fep->fpi; u16 paddrh, paddrm, paddrl; const unsigned char *mac; @@ -296,7 +297,7 @@ static void restart(struct net_device *dev) /* clear everything (slow & steady does it) */ for (i = 0; i < sizeof(*ep); i++) - __fs_out8((char *)ep + i, 0); + __fs_out8((u8 __iomem *)ep + i, 0); /* point to bds */ W16(ep, sen_genscc.scc_rbase, fep->ring_mem_addr); @@ -397,7 +398,7 @@ static void restart(struct net_device *dev) static void stop(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - scc_t *sccp = fep->scc.sccp; + scc_t __iomem *sccp = fep->scc.sccp; int i; for (i = 0; (R16(sccp, scc_sccm) == 0) && i < SCC_RESET_DELAY; i++) @@ -441,7 +442,7 @@ static void post_free_irq(struct net_device *dev, int irq) static void napi_clear_rx_event(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - scc_t *sccp = fep->scc.sccp; + scc_t __iomem *sccp = fep->scc.sccp; W16(sccp, scc_scce, SCC_NAPI_RX_EVENT_MSK); } @@ -449,7 +450,7 @@ static void napi_clear_rx_event(struct net_device *dev) static void napi_enable_rx(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - scc_t *sccp = fep->scc.sccp; + scc_t __iomem *sccp = fep->scc.sccp; S16(sccp, scc_sccm, SCC_NAPI_RX_EVENT_MSK); } @@ -457,7 +458,7 @@ static void napi_enable_rx(struct net_device *dev) static void napi_disable_rx(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - scc_t *sccp = fep->scc.sccp; + scc_t __iomem *sccp = fep->scc.sccp; C16(sccp, scc_sccm, SCC_NAPI_RX_EVENT_MSK); } @@ -475,7 +476,7 @@ static void tx_kickstart(struct net_device *dev) static u32 get_int_events(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - scc_t *sccp = fep->scc.sccp; + scc_t __iomem *sccp = fep->scc.sccp; return (u32) R16(sccp, scc_scce); } @@ -483,7 +484,7 @@ static u32 get_int_events(struct net_device *dev) static void clear_int_events(struct net_device *dev, u32 int_events) { struct fs_enet_private *fep = netdev_priv(dev); - scc_t *sccp = fep->scc.sccp; + scc_t __iomem *sccp = fep->scc.sccp; W16(sccp, scc_scce, int_events & 0xffff); } @@ -498,20 +499,20 @@ static int get_regs(struct net_device *dev, void *p, int *sizep) { struct fs_enet_private *fep = netdev_priv(dev); - if (*sizep < sizeof(scc_t) + sizeof(scc_enet_t)) + if (*sizep < sizeof(scc_t) + sizeof(scc_enet_t __iomem *)) return -EINVAL; memcpy_fromio(p, fep->scc.sccp, sizeof(scc_t)); p = (char *)p + sizeof(scc_t); - memcpy_fromio(p, fep->scc.ep, sizeof(scc_enet_t)); + memcpy_fromio(p, fep->scc.ep, sizeof(scc_enet_t __iomem *)); return 0; } static int get_regs_len(struct net_device *dev) { - return sizeof(scc_t) + sizeof(scc_enet_t); + return sizeof(scc_t) + sizeof(scc_enet_t __iomem *); } static void tx_restart(struct net_device *dev) diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c index f91c38d0b57..a89cf15090b 100644 --- a/drivers/net/fs_enet/mii-fec.c +++ b/drivers/net/fs_enet/mii-fec.c @@ -70,7 +70,7 @@ static int match_has_phy (struct device *dev, void* data) static int fs_mii_fec_init(struct fec_info* fec, struct fs_mii_fec_platform_info *fmpi) { struct resource *r; - fec_t *fecp; + fec_t __iomem *fecp; char* name = "fsl-cpm-fec"; /* we need fec in order to be useful */ @@ -85,7 +85,7 @@ static int fs_mii_fec_init(struct fec_info* fec, struct fs_mii_fec_platform_info r = platform_get_resource_byname(fec_pdev, IORESOURCE_MEM, "regs"); - fec->fecp = fecp = (fec_t*)ioremap(r->start,sizeof(fec_t)); + fec->fecp = fecp = ioremap(r->start,sizeof(fec_t)); fec->mii_speed = fmpi->mii_speed; setbits32(&fecp->fec_r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */ @@ -100,7 +100,7 @@ static int fs_mii_fec_init(struct fec_info* fec, struct fs_mii_fec_platform_info static int fs_enet_fec_mii_read(struct mii_bus *bus , int phy_id, int location) { struct fec_info* fec = bus->priv; - fec_t *fecp = fec->fecp; + fec_t __iomem *fecp = fec->fecp; int i, ret = -1; if ((in_be32(&fecp->fec_r_cntrl) & FEC_RCNTRL_MII_MODE) == 0) @@ -124,7 +124,7 @@ static int fs_enet_fec_mii_read(struct mii_bus *bus , int phy_id, int location) static int fs_enet_fec_mii_write(struct mii_bus *bus, int phy_id, int location, u16 val) { struct fec_info* fec = bus->priv; - fec_t *fecp = fec->fecp; + fec_t __iomem *fecp = fec->fecp; int i; /* this must never happen */ -- cgit v1.2.3-70-g09d2 From 2c69448bbcedebeb8409ddb05fbc7d3fe1cfbda7 Mon Sep 17 00:00:00 2001 From: Jan-Bernd Themann Date: Mon, 1 Oct 2007 16:33:18 +0200 Subject: ehea: DLPAR memory add fix Due to stability issues in high load situations the HW queue handling has to be changed. The HW queues are now stopped and restarted again instead of destroying and allocating new HW queues. Signed-off-by: Jan-Bernd Themann Signed-off-by: Jeff Garzik --- drivers/net/ehea/ehea.h | 4 +- drivers/net/ehea/ehea_main.c | 276 ++++++++++++++++++++++++++++++++++++++----- drivers/net/ehea/ehea_phyp.h | 1 + drivers/net/ehea/ehea_qmr.c | 20 ++-- drivers/net/ehea/ehea_qmr.h | 4 +- 5 files changed, 259 insertions(+), 46 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h index c0cbd949e33..30220894b01 100644 --- a/drivers/net/ehea/ehea.h +++ b/drivers/net/ehea/ehea.h @@ -40,13 +40,13 @@ #include #define DRV_NAME "ehea" -#define DRV_VERSION "EHEA_0074" +#define DRV_VERSION "EHEA_0077" /* eHEA capability flags */ #define DLPAR_PORT_ADD_REM 1 #define DLPAR_MEM_ADD 2 #define DLPAR_MEM_REM 4 -#define EHEA_CAPABILITIES (DLPAR_PORT_ADD_REM) +#define EHEA_CAPABILITIES (DLPAR_PORT_ADD_REM | DLPAR_MEM_ADD) #define EHEA_MSG_DEFAULT (NETIF_MSG_LINK | NETIF_MSG_TIMER \ | NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR) diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 62d6c1e5f9d..5bc0a1530eb 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -97,6 +97,7 @@ u64 ehea_driver_flags = 0; struct workqueue_struct *ehea_driver_wq; struct work_struct ehea_rereg_mr_task; +struct semaphore dlpar_mem_lock; static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev, const struct of_device_id *id); @@ -177,16 +178,24 @@ static void ehea_refill_rq1(struct ehea_port_res *pr, int index, int nr_of_wqes) struct sk_buff **skb_arr_rq1 = pr->rq1_skba.arr; struct net_device *dev = pr->port->netdev; int max_index_mask = pr->rq1_skba.len - 1; + int fill_wqes = pr->rq1_skba.os_skbs + nr_of_wqes; + int adder = 0; int i; - if (!nr_of_wqes) + pr->rq1_skba.os_skbs = 0; + + if (unlikely(test_bit(__EHEA_STOP_XFER, &ehea_driver_flags))) { + pr->rq1_skba.index = index; + pr->rq1_skba.os_skbs = fill_wqes; return; + } - for (i = 0; i < nr_of_wqes; i++) { + for (i = 0; i < fill_wqes; i++) { if (!skb_arr_rq1[index]) { skb_arr_rq1[index] = netdev_alloc_skb(dev, EHEA_L_PKT_SIZE); if (!skb_arr_rq1[index]) { + pr->rq1_skba.os_skbs = fill_wqes - i; ehea_error("%s: no mem for skb/%d wqes filled", dev->name, i); break; @@ -194,9 +203,14 @@ static void ehea_refill_rq1(struct ehea_port_res *pr, int index, int nr_of_wqes) } index--; index &= max_index_mask; + adder++; } + + if (adder == 0) + return; + /* Ring doorbell */ - ehea_update_rq1a(pr->qp, i); + ehea_update_rq1a(pr->qp, adder); } static int ehea_init_fill_rq1(struct ehea_port_res *pr, int nr_rq1a) @@ -230,16 +244,21 @@ static int ehea_refill_rq_def(struct ehea_port_res *pr, struct sk_buff **skb_arr = q_skba->arr; struct ehea_rwqe *rwqe; int i, index, max_index_mask, fill_wqes; + int adder = 0; int ret = 0; fill_wqes = q_skba->os_skbs + num_wqes; + q_skba->os_skbs = 0; - if (!fill_wqes) + if (unlikely(test_bit(__EHEA_STOP_XFER, &ehea_driver_flags))) { + q_skba->os_skbs = fill_wqes; return ret; + } index = q_skba->index; max_index_mask = q_skba->len - 1; for (i = 0; i < fill_wqes; i++) { + u64 tmp_addr; struct sk_buff *skb = netdev_alloc_skb(dev, packet_size); if (!skb) { ehea_error("%s: no mem for skb/%d wqes filled", @@ -251,30 +270,37 @@ static int ehea_refill_rq_def(struct ehea_port_res *pr, skb_reserve(skb, NET_IP_ALIGN); skb_arr[index] = skb; + tmp_addr = ehea_map_vaddr(skb->data); + if (tmp_addr == -1) { + dev_kfree_skb(skb); + q_skba->os_skbs = fill_wqes - i; + ret = 0; + break; + } rwqe = ehea_get_next_rwqe(qp, rq_nr); rwqe->wr_id = EHEA_BMASK_SET(EHEA_WR_ID_TYPE, wqe_type) | EHEA_BMASK_SET(EHEA_WR_ID_INDEX, index); rwqe->sg_list[0].l_key = pr->recv_mr.lkey; - rwqe->sg_list[0].vaddr = ehea_map_vaddr(skb->data); + rwqe->sg_list[0].vaddr = tmp_addr; rwqe->sg_list[0].len = packet_size; rwqe->data_segments = 1; index++; index &= max_index_mask; - - if (unlikely(test_bit(__EHEA_STOP_XFER, &ehea_driver_flags))) - goto out; + adder++; } q_skba->index = index; + if (adder == 0) + goto out; /* Ring doorbell */ iosync(); if (rq_nr == 2) - ehea_update_rq2a(pr->qp, i); + ehea_update_rq2a(pr->qp, adder); else - ehea_update_rq3a(pr->qp, i); + ehea_update_rq3a(pr->qp, adder); out: return ret; } @@ -1967,11 +1993,12 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev) ehea_dump(swqe, 512, "swqe"); } - if (unlikely(test_bit(__EHEA_STOP_XFER, &ehea_driver_flags))) - goto out; + if (unlikely(test_bit(__EHEA_STOP_XFER, &ehea_driver_flags))) { + netif_stop_queue(dev); + swqe->tx_control |= EHEA_SWQE_PURGE; + } ehea_post_swqe(pr->qp, swqe); - pr->tx_packets++; if (unlikely(atomic_read(&pr->swqe_avail) <= 1)) { spin_lock_irqsave(&pr->netif_queue, flags); @@ -1984,7 +2011,7 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev) } dev->trans_start = jiffies; spin_unlock(&pr->xmit_lock); -out: + return NETDEV_TX_OK; } @@ -2376,6 +2403,192 @@ static int ehea_stop(struct net_device *dev) return ret; } +void ehea_purge_sq(struct ehea_qp *orig_qp) +{ + struct ehea_qp qp = *orig_qp; + struct ehea_qp_init_attr *init_attr = &qp.init_attr; + struct ehea_swqe *swqe; + int wqe_index; + int i; + + for (i = 0; i < init_attr->act_nr_send_wqes; i++) { + swqe = ehea_get_swqe(&qp, &wqe_index); + swqe->tx_control |= EHEA_SWQE_PURGE; + } +} + +int ehea_stop_qps(struct net_device *dev) +{ + struct ehea_port *port = netdev_priv(dev); + struct ehea_adapter *adapter = port->adapter; + struct hcp_modify_qp_cb0* cb0; + int ret = -EIO; + int dret; + int i; + u64 hret; + u64 dummy64 = 0; + u16 dummy16 = 0; + + cb0 = kzalloc(PAGE_SIZE, GFP_KERNEL); + if (!cb0) { + ret = -ENOMEM; + goto out; + } + + for (i = 0; i < (port->num_def_qps + port->num_add_tx_qps); i++) { + struct ehea_port_res *pr = &port->port_res[i]; + struct ehea_qp *qp = pr->qp; + + /* Purge send queue */ + ehea_purge_sq(qp); + + /* Disable queue pair */ + hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle, + EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF), + cb0); + if (hret != H_SUCCESS) { + ehea_error("query_ehea_qp failed (1)"); + goto out; + } + + cb0->qp_ctl_reg = (cb0->qp_ctl_reg & H_QP_CR_RES_STATE) << 8; + cb0->qp_ctl_reg &= ~H_QP_CR_ENABLED; + + hret = ehea_h_modify_ehea_qp(adapter->handle, 0, qp->fw_handle, + EHEA_BMASK_SET(H_QPCB0_QP_CTL_REG, + 1), cb0, &dummy64, + &dummy64, &dummy16, &dummy16); + if (hret != H_SUCCESS) { + ehea_error("modify_ehea_qp failed (1)"); + goto out; + } + + hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle, + EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF), + cb0); + if (hret != H_SUCCESS) { + ehea_error("query_ehea_qp failed (2)"); + goto out; + } + + /* deregister shared memory regions */ + dret = ehea_rem_smrs(pr); + if (dret) { + ehea_error("unreg shared memory region failed"); + goto out; + } + } + + ret = 0; +out: + kfree(cb0); + + return ret; +} + +void ehea_update_rqs(struct ehea_qp *orig_qp, struct ehea_port_res * pr) +{ + struct ehea_qp qp = *orig_qp; + struct ehea_qp_init_attr *init_attr = &qp.init_attr; + struct ehea_rwqe *rwqe; + struct sk_buff **skba_rq2 = pr->rq2_skba.arr; + struct sk_buff **skba_rq3 = pr->rq3_skba.arr; + struct sk_buff *skb; + u32 lkey = pr->recv_mr.lkey; + + + int i; + int index; + + for (i = 0; i < init_attr->act_nr_rwqes_rq2 + 1; i++) { + rwqe = ehea_get_next_rwqe(&qp, 2); + rwqe->sg_list[0].l_key = lkey; + index = EHEA_BMASK_GET(EHEA_WR_ID_INDEX, rwqe->wr_id); + skb = skba_rq2[index]; + if (skb) + rwqe->sg_list[0].vaddr = ehea_map_vaddr(skb->data); + } + + for (i = 0; i < init_attr->act_nr_rwqes_rq3 + 1; i++) { + rwqe = ehea_get_next_rwqe(&qp, 3); + rwqe->sg_list[0].l_key = lkey; + index = EHEA_BMASK_GET(EHEA_WR_ID_INDEX, rwqe->wr_id); + skb = skba_rq3[index]; + if (skb) + rwqe->sg_list[0].vaddr = ehea_map_vaddr(skb->data); + } +} + +int ehea_restart_qps(struct net_device *dev) +{ + struct ehea_port *port = netdev_priv(dev); + struct ehea_adapter *adapter = port->adapter; + int ret = 0; + int i; + + struct hcp_modify_qp_cb0* cb0; + u64 hret; + u64 dummy64 = 0; + u16 dummy16 = 0; + + cb0 = kzalloc(PAGE_SIZE, GFP_KERNEL); + if (!cb0) { + ret = -ENOMEM; + goto out; + } + + for (i = 0; i < (port->num_def_qps + port->num_add_tx_qps); i++) { + struct ehea_port_res *pr = &port->port_res[i]; + struct ehea_qp *qp = pr->qp; + + ret = ehea_gen_smrs(pr); + if (ret) { + ehea_error("creation of shared memory regions failed"); + goto out; + } + + ehea_update_rqs(qp, pr); + + /* Enable queue pair */ + hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle, + EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF), + cb0); + if (hret != H_SUCCESS) { + ehea_error("query_ehea_qp failed (1)"); + goto out; + } + + cb0->qp_ctl_reg = (cb0->qp_ctl_reg & H_QP_CR_RES_STATE) << 8; + cb0->qp_ctl_reg |= H_QP_CR_ENABLED; + + hret = ehea_h_modify_ehea_qp(adapter->handle, 0, qp->fw_handle, + EHEA_BMASK_SET(H_QPCB0_QP_CTL_REG, + 1), cb0, &dummy64, + &dummy64, &dummy16, &dummy16); + if (hret != H_SUCCESS) { + ehea_error("modify_ehea_qp failed (1)"); + goto out; + } + + hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle, + EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF), + cb0); + if (hret != H_SUCCESS) { + ehea_error("query_ehea_qp failed (2)"); + goto out; + } + + /* refill entire queue */ + ehea_refill_rq1(pr, pr->rq1_skba.index, 0); + ehea_refill_rq2(pr, 0); + ehea_refill_rq3(pr, 0); + } +out: + kfree(cb0); + + return ret; +} + static void ehea_reset_port(struct work_struct *work) { int ret; @@ -2395,6 +2608,8 @@ static void ehea_reset_port(struct work_struct *work) if (ret) goto out; + ehea_set_multicast_list(dev); + if (netif_msg_timer(port)) ehea_info("Device %s resetted successfully", dev->name); @@ -2411,6 +2626,7 @@ static void ehea_rereg_mrs(struct work_struct *work) int ret, i; struct ehea_adapter *adapter; + down(&dlpar_mem_lock); ehea_info("LPAR memory enlarged - re-initializing driver"); list_for_each_entry(adapter, &adapter_list, list) @@ -2423,14 +2639,14 @@ static void ehea_rereg_mrs(struct work_struct *work) struct net_device *dev = port->netdev; if (dev->flags & IFF_UP) { - ehea_info("stopping %s", - dev->name); down(&port->port_lock); netif_stop_queue(dev); - + ret = ehea_stop_qps(dev); + if (ret) { + up(&port->port_lock); + goto out; + } port_napi_disable(port); - - ehea_down(dev); up(&port->port_lock); } } @@ -2446,10 +2662,11 @@ static void ehea_rereg_mrs(struct work_struct *work) } ehea_destroy_busmap(); - ret = ehea_create_busmap(); - if (ret) + if (ret) { + ehea_error("creating ehea busmap failed"); goto out; + } clear_bit(__EHEA_STOP_XFER, &ehea_driver_flags); @@ -2471,21 +2688,18 @@ static void ehea_rereg_mrs(struct work_struct *work) struct net_device *dev = port->netdev; if (dev->flags & IFF_UP) { - ehea_info("restarting %s", - dev->name); down(&port->port_lock); - - ret = ehea_up(dev); - if (!ret) { - port_napi_enable(port); + port_napi_enable(port); + ret = ehea_restart_qps(dev); + if (!ret) netif_wake_queue(dev); - } - up(&port->port_lock); } } } } + up(&dlpar_mem_lock); + ehea_info("re-initializing driver complete"); out: return; } @@ -2494,7 +2708,8 @@ static void ehea_tx_watchdog(struct net_device *dev) { struct ehea_port *port = netdev_priv(dev); - if (netif_carrier_ok(dev)) + if (netif_carrier_ok(dev) && + !test_bit(__EHEA_STOP_XFER, &ehea_driver_flags)) queue_work(port->adapter->ehea_wq, &port->reset_task); } @@ -3139,6 +3354,7 @@ int __init ehea_module_init(void) ehea_driver_wq = create_workqueue("ehea_driver_wq"); INIT_WORK(&ehea_rereg_mr_task, ehea_rereg_mrs); + sema_init(&dlpar_mem_lock, 1); ret = check_module_parm(); if (ret) diff --git a/drivers/net/ehea/ehea_phyp.h b/drivers/net/ehea/ehea_phyp.h index 89b63531ff2..faa191d23b8 100644 --- a/drivers/net/ehea/ehea_phyp.h +++ b/drivers/net/ehea/ehea_phyp.h @@ -126,6 +126,7 @@ struct hcp_modify_qp_cb0 { #define H_QP_CR_STATE_RDY2RCV 0x0000030000000000ULL /* Ready to recv */ #define H_QP_CR_STATE_RDY2SND 0x0000050000000000ULL /* Ready to send */ #define H_QP_CR_STATE_ERROR 0x0000800000000000ULL /* Error */ +#define H_QP_CR_RES_STATE 0x0000007F00000000ULL /* Resultant state */ struct hcp_modify_qp_cb1 { u32 qpn; /* 00 */ diff --git a/drivers/net/ehea/ehea_qmr.c b/drivers/net/ehea/ehea_qmr.c index c82e2459607..329a25248d7 100644 --- a/drivers/net/ehea/ehea_qmr.c +++ b/drivers/net/ehea/ehea_qmr.c @@ -563,8 +563,7 @@ int ehea_destroy_qp(struct ehea_qp *qp) int ehea_create_busmap( void ) { u64 vaddr = EHEA_BUSMAP_START; - unsigned long abs_max_pfn = 0; - unsigned long sec_max_pfn; + unsigned long high_section_index = 0; int i; /* @@ -574,14 +573,10 @@ int ehea_create_busmap( void ) ehea_bmap.valid_sections = 0; for (i = 0; i < NR_MEM_SECTIONS; i++) - if (valid_section_nr(i)) { - sec_max_pfn = section_nr_to_pfn(i); - if (sec_max_pfn > abs_max_pfn) - abs_max_pfn = sec_max_pfn; - ehea_bmap.valid_sections++; - } + if (valid_section_nr(i)) + high_section_index = i; - ehea_bmap.entries = abs_max_pfn / EHEA_PAGES_PER_SECTION + 1; + ehea_bmap.entries = high_section_index + 1; ehea_bmap.vaddr = vmalloc(ehea_bmap.entries * sizeof(*ehea_bmap.vaddr)); if (!ehea_bmap.vaddr) @@ -593,6 +588,7 @@ int ehea_create_busmap( void ) if (pfn_valid(pfn)) { ehea_bmap.vaddr[i] = vaddr; vaddr += EHEA_SECTSIZE; + ehea_bmap.valid_sections++; } else ehea_bmap.vaddr[i] = 0; } @@ -637,7 +633,7 @@ int ehea_reg_kernel_mr(struct ehea_adapter *adapter, struct ehea_mr *mr) mr_len = ehea_bmap.valid_sections * EHEA_SECTSIZE; - pt = kzalloc(EHEA_MAX_RPAGE * sizeof(u64), GFP_KERNEL); + pt = kzalloc(PAGE_SIZE, GFP_KERNEL); if (!pt) { ehea_error("no mem"); ret = -ENOMEM; @@ -660,8 +656,8 @@ int ehea_reg_kernel_mr(struct ehea_adapter *adapter, struct ehea_mr *mr) void *sectbase = __va(i << SECTION_SIZE_BITS); unsigned long k = 0; - for (j = 0; j < (PAGES_PER_SECTION / EHEA_MAX_RPAGE); - j++) { + for (j = 0; j < (EHEA_PAGES_PER_SECTION / + EHEA_MAX_RPAGE); j++) { for (m = 0; m < EHEA_MAX_RPAGE; m++) { pg = sectbase + ((k++) * EHEA_PAGESIZE); diff --git a/drivers/net/ehea/ehea_qmr.h b/drivers/net/ehea/ehea_qmr.h index b71f8452a5e..562de0ebdd8 100644 --- a/drivers/net/ehea/ehea_qmr.h +++ b/drivers/net/ehea/ehea_qmr.h @@ -39,7 +39,7 @@ #define EHEA_PAGESHIFT 12 #define EHEA_PAGESIZE (1UL << EHEA_PAGESHIFT) #define EHEA_SECTSIZE (1UL << 24) -#define EHEA_PAGES_PER_SECTION (EHEA_SECTSIZE >> PAGE_SHIFT) +#define EHEA_PAGES_PER_SECTION (EHEA_SECTSIZE >> EHEA_PAGESHIFT) #if (1UL << SECTION_SIZE_BITS) < EHEA_SECTSIZE #error eHEA module can't work if kernel sectionsize < ehea sectionsize @@ -145,7 +145,7 @@ struct ehea_rwqe { #define EHEA_CQE_VLAN_TAG_XTRACT 0x0400 #define EHEA_CQE_TYPE_RQ 0x60 -#define EHEA_CQE_STAT_ERR_MASK 0x721F +#define EHEA_CQE_STAT_ERR_MASK 0x720F #define EHEA_CQE_STAT_FAT_ERR_MASK 0x1F #define EHEA_CQE_STAT_ERR_TCP 0x4000 #define EHEA_CQE_STAT_ERR_IP 0x2000 -- cgit v1.2.3-70-g09d2 From 726d722e41f1c329b7f04c5ee5aef02a60ac1991 Mon Sep 17 00:00:00 2001 From: Markus Brunner Date: Mon, 20 Aug 2007 08:36:50 +0200 Subject: smc911x irq sense request and MPR2 board support Hi, this are the changes to the smc911x driver, which were necessary to get it running on the Magic Panel R2 (smsc9115). It is a SH3-DSP based board. The other patches are available on the linuxsh-dev mailinglist. http://marc.info/?l=linuxsh-dev&r=1&b=200708&w=2 It was necessary to set the irq sense to low level. Therefor the SMC_IRQ_SENSE define was added. How are the chances for inclusion in 2.6.24? Signed-off by: Markus Brunner Signed-off by: Mark Jonas Signed-off-by: Jeff Garzik --- drivers/net/Kconfig | 2 +- drivers/net/smc911x.c | 2 +- drivers/net/smc911x.h | 6 ++++++ 3 files changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 45f6cf53156..0e48b294200 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -944,7 +944,7 @@ config SMC911X tristate "SMSC LAN911[5678] support" select CRC32 select MII - depends on ARCH_PXA + depends on ARCH_PXA || SUPERH help This is a driver for SMSC's LAN911x series of Ethernet chipsets including the new LAN9115, LAN9116, LAN9117, and LAN9118. diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index c0276c04dec..7c60df46fc6 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -2063,7 +2063,7 @@ static int __init smc911x_probe(struct net_device *dev, unsigned long ioaddr) /* Grab the IRQ */ retval = request_irq(dev->irq, &smc911x_interrupt, - IRQF_SHARED | IRQF_TRIGGER_FALLING, dev->name, dev); + IRQF_SHARED | SMC_IRQ_SENSE, dev->name, dev); if (retval) goto err_out; diff --git a/drivers/net/smc911x.h b/drivers/net/smc911x.h index 962a710459f..16a0edc078f 100644 --- a/drivers/net/smc911x.h +++ b/drivers/net/smc911x.h @@ -36,6 +36,12 @@ #define SMC_USE_PXA_DMA 1 #define SMC_USE_16BIT 0 #define SMC_USE_32BIT 1 + #define SMC_IRQ_SENSE IRQF_TRIGGER_FALLING +#elif CONFIG_SH_MAGIC_PANEL_R2 + #define SMC_USE_SH_DMA 0 + #define SMC_USE_16BIT 0 + #define SMC_USE_32BIT 1 + #define SMC_IRQ_SENSE IRQF_TRIGGER_LOW #endif -- cgit v1.2.3-70-g09d2 From 18ad4e700647a9f727fa82a7f8d1f31444abbdfb Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Wed, 19 Sep 2007 21:07:52 +0900 Subject: smc91x Hitachi Solution Engine (SuperH) Support Hi, all. This patch supports Hitachi Solution Engine (SuperH) of smc91x. Please apply this patch . regards, Nobuhiro -- Nobuhiro Iwamatsu E-Mail : iwamatsu@nigauri.org GPG ID : 3170EBE9 Signed-off-by: Nobuhiro Iwamatsu Signed-off-by: Jeff Garzik --- drivers/net/smc91x.h | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h index 6ff3a1627af..af9e6bf5955 100644 --- a/drivers/net/smc91x.h +++ b/drivers/net/smc91x.h @@ -284,6 +284,7 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg) #elif defined(CONFIG_SUPERH) #ifdef CONFIG_SOLUTION_ENGINE +#define SMC_IRQ_FLAGS (0) #define SMC_CAN_USE_8BIT 0 #define SMC_CAN_USE_16BIT 1 #define SMC_CAN_USE_32BIT 0 -- cgit v1.2.3-70-g09d2 From dad8c737962669240470923f951570ed716da1a1 Mon Sep 17 00:00:00 2001 From: Komuro Date: Sun, 30 Sep 2007 10:28:14 +0900 Subject: PCMCIA-NETDEV : add new id (axnet_cs, pcnet_cs) axnet_cs: Laneed LD-CDK/TX pcnet_cs: LEMEL LM-N89TX PRO Signed-off-by: Komuro Signed-off-by: Jeff Garzik --- drivers/net/pcmcia/axnet_cs.c | 1 + drivers/net/pcmcia/pcnet_cs.c | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index de59313d10f..a95a2cae6b2 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -772,6 +772,7 @@ static struct pcmcia_device_id axnet_ids[] = { PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1106), PCMCIA_DEVICE_MANF_CARD(0x8a01, 0xc1ab), PCMCIA_DEVICE_MANF_CARD(0x021b, 0x0202), + PCMCIA_DEVICE_MANF_CARD(0xffff, 0x1090), PCMCIA_DEVICE_PROD_ID12("AmbiCom,Inc.", "Fast Ethernet PC Card(AMB8110)", 0x49b020a7, 0x119cc9fc), PCMCIA_DEVICE_PROD_ID124("Fast Ethernet", "16-bit PC Card", "AX88190", 0xb4be14e3, 0x9a12eb6a, 0xab9be5ef), PCMCIA_DEVICE_PROD_ID12("ASIX", "AX88190", 0x0959823b, 0xab9be5ef), diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index 6a647516c38..9d45e9696e1 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -1662,6 +1662,7 @@ static struct pcmcia_device_id pcnet_ids[] = { PCMCIA_DEVICE_PROD_ID12("Laneed", "LD-CDF", 0x1b7827b2, 0xfec71e40), PCMCIA_DEVICE_PROD_ID12("Laneed", "LD-CDL/T", 0x1b7827b2, 0x79fba4f7), PCMCIA_DEVICE_PROD_ID12("Laneed", "LD-CDS", 0x1b7827b2, 0x931afaab), + PCMCIA_DEVICE_PROD_ID12("LEMEL", "LM-N89TX PRO", 0xbbefb52f, 0xd2897a97), PCMCIA_DEVICE_PROD_ID12("Linksys", "Combo PCMCIA EthernetCard (EC2T)", 0x0733cc81, 0x32ee8c78), PCMCIA_DEVICE_PROD_ID12("LINKSYS", "E-CARD", 0xf7cb0b07, 0x6701da11), PCMCIA_DEVICE_PROD_ID12("Linksys", "EtherFast 10/100 Integrated PC Card (PCM100)", 0x0733cc81, 0x453c3f9d), -- cgit v1.2.3-70-g09d2 From ea1f8d5c3a593a791463c2efc07e5dfebd056500 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Tue, 2 Oct 2007 16:27:35 -0700 Subject: [BNX2]: Optimize firmware loading. This is a follow up to the patches from Denys Vlasenkos to further optimize firmware loading. 1. In bnx2_init_cpus(), we allocate memory for decompression once and use it repeatedly instead of doing this for every firmware image. 2. We eliminate the BSS and SBSS firmware sections in bnx2_fw*.h since these are always zeros. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 40 +++++++++++++++++++--------------------- drivers/net/bnx2.h | 4 +--- drivers/net/bnx2_fw.h | 17 ----------------- drivers/net/bnx2_fw2.h | 20 -------------------- 4 files changed, 20 insertions(+), 61 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 6d6ea56fe38..00aef8b08da 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -2810,21 +2810,16 @@ load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw) /* Load the Text area. */ offset = cpu_reg->spad_base + (fw->text_addr - cpu_reg->mips_view_base); if (fw->gz_text) { - u32 *text; int j; - text = vmalloc(FW_BUF_SIZE); - if (!text) - return -ENOMEM; - rc = zlib_inflate_blob(text, FW_BUF_SIZE, fw->gz_text, fw->gz_text_len); - if (rc < 0) { - vfree(text); + rc = zlib_inflate_blob(fw->text, FW_BUF_SIZE, fw->gz_text, + fw->gz_text_len); + if (rc < 0) return rc; - } + for (j = 0; j < (fw->text_len / 4); j++, offset += 4) { - REG_WR_IND(bp, offset, cpu_to_le32(text[j])); + REG_WR_IND(bp, offset, cpu_to_le32(fw->text[j])); } - vfree(text); } /* Load the Data area. */ @@ -2839,21 +2834,21 @@ load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw) /* Load the SBSS area. */ offset = cpu_reg->spad_base + (fw->sbss_addr - cpu_reg->mips_view_base); - if (fw->sbss) { + if (fw->sbss_len) { int j; for (j = 0; j < (fw->sbss_len / 4); j++, offset += 4) { - REG_WR_IND(bp, offset, fw->sbss[j]); + REG_WR_IND(bp, offset, 0); } } /* Load the BSS area. */ offset = cpu_reg->spad_base + (fw->bss_addr - cpu_reg->mips_view_base); - if (fw->bss) { + if (fw->bss_len) { int j; for (j = 0; j < (fw->bss_len/4); j++, offset += 4) { - REG_WR_IND(bp, offset, fw->bss[j]); + REG_WR_IND(bp, offset, 0); } } @@ -2894,19 +2889,16 @@ bnx2_init_cpus(struct bnx2 *bp) if (!text) return -ENOMEM; rc = zlib_inflate_blob(text, FW_BUF_SIZE, bnx2_rv2p_proc1, sizeof(bnx2_rv2p_proc1)); - if (rc < 0) { - vfree(text); + if (rc < 0) goto init_cpu_err; - } + load_rv2p_fw(bp, text, rc /* == len */, RV2P_PROC1); rc = zlib_inflate_blob(text, FW_BUF_SIZE, bnx2_rv2p_proc2, sizeof(bnx2_rv2p_proc2)); - if (rc < 0) { - vfree(text); + if (rc < 0) goto init_cpu_err; - } + load_rv2p_fw(bp, text, rc /* == len */, RV2P_PROC2); - vfree(text); /* Initialize the RX Processor. */ cpu_reg.mode = BNX2_RXP_CPU_MODE; @@ -2927,6 +2919,7 @@ bnx2_init_cpus(struct bnx2 *bp) else fw = &bnx2_rxp_fw_06; + fw->text = text; rc = load_cpu_fw(bp, &cpu_reg, fw); if (rc) goto init_cpu_err; @@ -2950,6 +2943,7 @@ bnx2_init_cpus(struct bnx2 *bp) else fw = &bnx2_txp_fw_06; + fw->text = text; rc = load_cpu_fw(bp, &cpu_reg, fw); if (rc) goto init_cpu_err; @@ -2973,6 +2967,7 @@ bnx2_init_cpus(struct bnx2 *bp) else fw = &bnx2_tpat_fw_06; + fw->text = text; rc = load_cpu_fw(bp, &cpu_reg, fw); if (rc) goto init_cpu_err; @@ -2996,6 +2991,7 @@ bnx2_init_cpus(struct bnx2 *bp) else fw = &bnx2_com_fw_06; + fw->text = text; rc = load_cpu_fw(bp, &cpu_reg, fw); if (rc) goto init_cpu_err; @@ -3017,11 +3013,13 @@ bnx2_init_cpus(struct bnx2 *bp) if (CHIP_NUM(bp) == CHIP_NUM_5709) { fw = &bnx2_cp_fw_09; + fw->text = text; rc = load_cpu_fw(bp, &cpu_reg, fw); if (rc) goto init_cpu_err; } init_cpu_err: + vfree(text); return rc; } diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h index a717459cc8d..56c190fc6de 100644 --- a/drivers/net/bnx2.h +++ b/drivers/net/bnx2.h @@ -6738,7 +6738,7 @@ struct fw_info { const u32 text_addr; const u32 text_len; const u32 text_index; -/* u32 *text;*/ + u32 *text; u8 *gz_text; const u32 gz_text_len; @@ -6752,13 +6752,11 @@ struct fw_info { const u32 sbss_addr; const u32 sbss_len; const u32 sbss_index; - const u32 *sbss; /* BSS section. */ const u32 bss_addr; const u32 bss_len; const u32 bss_index; - const u32 *bss; /* Read-only section. */ const u32 rodata_addr; diff --git a/drivers/net/bnx2_fw.h b/drivers/net/bnx2_fw.h index 30f2f4052fc..a6d78243163 100644 --- a/drivers/net/bnx2_fw.h +++ b/drivers/net/bnx2_fw.h @@ -1048,8 +1048,6 @@ static const u32 bnx2_COM_b06FwRodata[(0x88/4) + 1] = { 0x08002bd8, 0x08002c08, 0x08002c38, 0x00000000, 0x080060cc, 0x080060cc, 0x080060cc, 0x080060cc, 0x080060cc, 0x08006100, 0x08006100, 0x08006140, 0x0800614c, 0x0800614c, 0x080060cc, 0x00000000, 0x00000000 }; -static const u32 bnx2_COM_b06FwBss[(0x88/4) + 1] = { 0x0 }; -static const u32 bnx2_COM_b06FwSbss[(0x60/4) + 1] = { 0x0 }; static struct fw_info bnx2_com_fw_06 = { .ver_major = 0x3, @@ -1072,12 +1070,10 @@ static struct fw_info bnx2_com_fw_06 = { .sbss_addr = 0x08007e00, .sbss_len = 0x60, .sbss_index = 0x0, - .sbss = bnx2_COM_b06FwSbss, .bss_addr = 0x08007e60, .bss_len = 0x88, .bss_index = 0x0, - .bss = bnx2_COM_b06FwBss, .rodata_addr = 0x08007d58, .rodata_len = 0x88, @@ -1762,9 +1758,6 @@ static u32 bnx2_RXP_b06FwRodata[(0x278/4) + 1] = { 0x08006030, 0x08006030, 0x08006018, 0x08006030, 0x08006030, 0x08006030, 0x08006024, 0x00000000, 0x00000000 }; -static u32 bnx2_RXP_b06FwBss[(0x13dc/4) + 1] = { 0x0 }; -static u32 bnx2_RXP_b06FwSbss[(0x2c/4) + 1] = { 0x0 }; - static struct fw_info bnx2_rxp_fw_06 = { .ver_major = 0x2, .ver_minor = 0x8, @@ -1786,12 +1779,10 @@ static struct fw_info bnx2_rxp_fw_06 = { .sbss_addr = 0x080069c0, .sbss_len = 0x2c, .sbss_index = 0x0, - .sbss = bnx2_RXP_b06FwSbss, .bss_addr = 0x080069f0, .bss_len = 0x13dc, .bss_index = 0x0, - .bss = bnx2_RXP_b06FwBss, .rodata_addr = 0x08006728, .rodata_len = 0x278, @@ -2257,8 +2248,6 @@ static u8 bnx2_TPAT_b06FwText[] = { static u32 bnx2_TPAT_b06FwData[(0x0/4) + 1] = { 0x0 }; static u32 bnx2_TPAT_b06FwRodata[(0x0/4) + 1] = { 0x0 }; -static u32 bnx2_TPAT_b06FwBss[(0x250/4) + 1] = { 0x0 }; -static u32 bnx2_TPAT_b06FwSbss[(0x34/4) + 1] = { 0x0 }; static struct fw_info bnx2_tpat_fw_06 = { .ver_major = 0x1, @@ -2281,12 +2270,10 @@ static struct fw_info bnx2_tpat_fw_06 = { .sbss_addr = 0x08001a60, .sbss_len = 0x34, .sbss_index = 0x0, - .sbss = bnx2_TPAT_b06FwSbss, .bss_addr = 0x08001aa0, .bss_len = 0x250, .bss_index = 0x0, - .bss = bnx2_TPAT_b06FwBss, .rodata_addr = 0x00000000, .rodata_len = 0x0, @@ -2714,8 +2701,6 @@ static u8 bnx2_TXP_b06FwText[] = { static u32 bnx2_TXP_b06FwData[(0x0/4) + 1] = { 0x0 }; static u32 bnx2_TXP_b06FwRodata[(0x0/4) + 1] = { 0x0 }; -static u32 bnx2_TXP_b06FwBss[(0x1c4/4) + 1] = { 0x0 }; -static u32 bnx2_TXP_b06FwSbss[(0x38/4) + 1] = { 0x0 }; static struct fw_info bnx2_txp_fw_06 = { .ver_major = 0x1, @@ -2738,12 +2723,10 @@ static struct fw_info bnx2_txp_fw_06 = { .sbss_addr = 0x08005760, .sbss_len = 0x38, .sbss_index = 0x0, - .sbss = bnx2_TXP_b06FwSbss, .bss_addr = 0x080057a0, .bss_len = 0x1c4, .bss_index = 0x0, - .bss = bnx2_TXP_b06FwBss, .rodata_addr = 0x00000000, .rodata_len = 0x0, diff --git a/drivers/net/bnx2_fw2.h b/drivers/net/bnx2_fw2.h index 74f985d8fac..5bd52bead9b 100644 --- a/drivers/net/bnx2_fw2.h +++ b/drivers/net/bnx2_fw2.h @@ -1046,8 +1046,6 @@ static const u32 bnx2_COM_b09FwRodata[(0x88/4) + 1] = { 0x08002b3c, 0x08002b6c, 0x08002b9c, 0x00000000, 0x0800604c, 0x0800604c, 0x0800604c, 0x0800604c, 0x0800604c, 0x08006078, 0x08006078, 0x080060b8, 0x080060c4, 0x080060c4, 0x0800604c, 0x00000000, 0x00000000 }; -static const u32 bnx2_COM_b09FwBss[(0x88/4) + 1] = { 0x0 }; -static const u32 bnx2_COM_b09FwSbss[(0x60/4) + 1] = { 0x0 }; static struct fw_info bnx2_com_fw_09 = { .ver_major = 0x3, @@ -1070,12 +1068,10 @@ static struct fw_info bnx2_com_fw_09 = { .sbss_addr = 0x08007e60, .sbss_len = 0x60, .sbss_index = 0x0, - .sbss = bnx2_COM_b09FwSbss, .bss_addr = 0x08007ec0, .bss_len = 0x88, .bss_index = 0x0, - .bss = bnx2_COM_b09FwBss, .rodata_addr = 0x08007dc0, .rodata_len = 0x88, @@ -2243,8 +2239,6 @@ static const u32 bnx2_CP_b09FwRodata[(0x118/4) + 1] = { 0x080032e8, 0x08003300, 0x08003320, 0x08003358, 0x08003338, 0x08003338, 0x080050d4, 0x080050d4, 0x080050d4, 0x080050d4, 0x080050d4, 0x080050fc, 0x080050fc, 0x08005124, 0x08005174, 0x08005144, 0x00000000 }; -static const u32 bnx2_CP_b09FwBss[(0x3b0/4) + 1] = { 0x0 }; -static const u32 bnx2_CP_b09FwSbss[(0xa1/4) + 1] = { 0x0 }; static struct fw_info bnx2_cp_fw_09 = { .ver_major = 0x3, @@ -2267,12 +2261,10 @@ static struct fw_info bnx2_cp_fw_09 = { .sbss_addr = 0x08007024, .sbss_len = 0xa1, .sbss_index = 0x0, - .sbss = bnx2_CP_b09FwSbss, .bss_addr = 0x080070d0, .bss_len = 0x3b0, .bss_index = 0x0, - .bss = bnx2_CP_b09FwBss, .rodata_addr = 0x08006ee8, .rodata_len = 0x118, @@ -2953,8 +2945,6 @@ static const u32 bnx2_RXP_b09FwRodata[(0x278/4) + 1] = { 0x08006058, 0x08006070, 0x08006070, 0x08006070, 0x08006058, 0x08006070, 0x08006070, 0x08006070, 0x08006058, 0x08006070, 0x08006070, 0x08006070, 0x08006064, 0x00000000, 0x00000000 }; -static const u32 bnx2_RXP_b09FwBss[(0x13dc/4) + 1] = { 0x0 }; -static const u32 bnx2_RXP_b09FwSbss[(0x20/4) + 1] = { 0x0 }; static struct fw_info bnx2_rxp_fw_09 = { .ver_major = 0x3, @@ -2977,12 +2967,10 @@ static struct fw_info bnx2_rxp_fw_09 = { .sbss_addr = 0x08006a00, .sbss_len = 0x20, .sbss_index = 0x0, - .sbss = bnx2_RXP_b09FwSbss, .bss_addr = 0x08006a20, .bss_len = 0x13dc, .bss_index = 0x0, - .bss = bnx2_RXP_b09FwBss, .rodata_addr = 0x08006768, .rodata_len = 0x278, @@ -3245,8 +3233,6 @@ static u8 bnx2_TPAT_b09FwText[] = { static const u32 bnx2_TPAT_b09FwData[(0x0/4) + 1] = { 0x0 }; static const u32 bnx2_TPAT_b09FwRodata[(0x0/4) + 1] = { 0x0 }; -static const u32 bnx2_TPAT_b09FwBss[(0x850/4) + 1] = { 0x0 }; -static const u32 bnx2_TPAT_b09FwSbss[(0x2c/4) + 1] = { 0x0 }; static struct fw_info bnx2_tpat_fw_09 = { .ver_major = 0x3, @@ -3269,12 +3255,10 @@ static struct fw_info bnx2_tpat_fw_09 = { .sbss_addr = 0x08002088, .sbss_len = 0x2c, .sbss_index = 0x0, - .sbss = bnx2_TPAT_b09FwSbss, .bss_addr = 0x080020c0, .bss_len = 0x850, .bss_index = 0x0, - .bss = bnx2_TPAT_b09FwBss, .rodata_addr = 0x00000000, .rodata_len = 0x0, @@ -4060,8 +4044,6 @@ static const u32 bnx2_TXP_b09FwRodata[(0x30/4) + 1] = { 0x08004060, 0x0800408c, 0x080040d4, 0x080040d4, 0x08003f60, 0x08003f8c, 0x08003f8c, 0x080040d4, 0x080040d4, 0x080040d4, 0x08003ff4, 0x00000000, 0x00000000 }; -static const u32 bnx2_TXP_b09FwBss[(0xa20/4) + 1] = { 0x0 }; -static const u32 bnx2_TXP_b09FwSbss[(0x8c/4) + 1] = { 0x0 }; static struct fw_info bnx2_txp_fw_09 = { .ver_major = 0x3, @@ -4084,12 +4066,10 @@ static struct fw_info bnx2_txp_fw_09 = { .sbss_addr = 0x08004750, .sbss_len = 0x8c, .sbss_index = 0x0, - .sbss = bnx2_TXP_b09FwSbss, .bss_addr = 0x080047e0, .bss_len = 0xa20, .bss_index = 0x0, - .bss = bnx2_TXP_b09FwBss, .rodata_addr = 0x08004638, .rodata_len = 0x30, -- cgit v1.2.3-70-g09d2 From f74347d7ac0aa175b2bbd85eb58a13fbe80a3785 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Tue, 2 Oct 2007 16:28:09 -0700 Subject: [BNX2]: Update version to 1.6.6. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 00aef8b08da..0e4928c751f 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -56,8 +56,8 @@ #define DRV_MODULE_NAME "bnx2" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "1.6.5" -#define DRV_MODULE_RELDATE "September 20, 2007" +#define DRV_MODULE_VERSION "1.6.6" +#define DRV_MODULE_RELDATE "October 2, 2007" #define RUN_AT(x) (jiffies + (x)) -- cgit v1.2.3-70-g09d2 From 09703f5e79a64c744721b9c27502075232ba0ea2 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Wed, 26 Sep 2007 21:45:24 +0100 Subject: [HOSTAP]: set netdev type before registering AP interface As detailed at https://bugs.gentoo.org/159646 hostap with hostapd confuses udev by presenting 2 interfaces with the same MAC address. Also, at the time of detection, the 'type' attribute is 1, identical to other hostap interfaces. The AP interface is supposed to have type ARPHRD_IEEE80211 (801), but this is not set until after registration. Setting it before register_netdev() is called allows us to avoid this confusion. We can do this by propogating the HOSTAP_INTERFACE type through to hostap_setup_dev(). Signed-off-by: Daniel Drake Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/hostap/hostap.h | 2 +- drivers/net/wireless/hostap/hostap_hw.c | 2 +- drivers/net/wireless/hostap/hostap_main.c | 19 +++++++++++-------- 3 files changed, 13 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/hostap/hostap.h b/drivers/net/wireless/hostap/hostap.h index 951df83702f..547ba84dc79 100644 --- a/drivers/net/wireless/hostap/hostap.h +++ b/drivers/net/wireless/hostap/hostap.h @@ -34,7 +34,7 @@ extern const struct header_ops hostap_80211_ops; int hostap_80211_get_hdrlen(u16 fc); struct net_device_stats *hostap_get_stats(struct net_device *dev); void hostap_setup_dev(struct net_device *dev, local_info_t *local, - int main_dev); + int type); void hostap_set_multicast_list_queue(struct work_struct *work); int hostap_set_hostapd(local_info_t *local, int val, int rtnl_locked); int hostap_set_hostapd_sta(local_info_t *local, int val, int rtnl_locked); diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c index b20bb013d57..c592641e914 100644 --- a/drivers/net/wireless/hostap/hostap_hw.c +++ b/drivers/net/wireless/hostap/hostap_hw.c @@ -3257,7 +3257,7 @@ while (0) INIT_LIST_HEAD(&local->bss_list); - hostap_setup_dev(dev, local, 1); + hostap_setup_dev(dev, local, HOSTAP_INTERFACE_MASTER); dev->hard_start_xmit = hostap_master_start_xmit; dev->type = ARPHRD_IEEE80211; diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c index b75cf9205ce..17c58e9bdad 100644 --- a/drivers/net/wireless/hostap/hostap_main.c +++ b/drivers/net/wireless/hostap/hostap_main.c @@ -73,7 +73,7 @@ struct net_device * hostap_add_interface(struct local_info *local, dev->mem_start = mdev->mem_start; dev->mem_end = mdev->mem_end; - hostap_setup_dev(dev, local, 0); + hostap_setup_dev(dev, local, type); dev->destructor = free_netdev; sprintf(dev->name, "%s%s", prefix, name); @@ -857,7 +857,7 @@ const struct header_ops hostap_80211_ops = { EXPORT_SYMBOL(hostap_80211_ops); void hostap_setup_dev(struct net_device *dev, local_info_t *local, - int main_dev) + int type) { struct hostap_interface *iface; @@ -877,15 +877,22 @@ void hostap_setup_dev(struct net_device *dev, local_info_t *local, dev->do_ioctl = hostap_ioctl; dev->open = prism2_open; dev->stop = prism2_close; - dev->hard_start_xmit = hostap_data_start_xmit; dev->set_mac_address = prism2_set_mac_address; dev->set_multicast_list = hostap_set_multicast_list; dev->change_mtu = prism2_change_mtu; dev->tx_timeout = prism2_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; + if (type == HOSTAP_INTERFACE_AP) { + dev->hard_start_xmit = hostap_mgmt_start_xmit; + dev->type = ARPHRD_IEEE80211; + dev->header_ops = &hostap_80211_ops; + } else { + dev->hard_start_xmit = hostap_data_start_xmit; + } + dev->mtu = local->mtu; - if (!main_dev) { + if (type != HOSTAP_INTERFACE_MASTER) { /* use main radio device queue */ dev->tx_queue_len = 0; } @@ -910,10 +917,6 @@ static int hostap_enable_hostapd(local_info_t *local, int rtnl_locked) if (local->apdev == NULL) return -ENOMEM; - local->apdev->hard_start_xmit = hostap_mgmt_start_xmit; - local->apdev->type = ARPHRD_IEEE80211; - local->apdev->header_ops = &hostap_80211_ops; - return 0; } -- cgit v1.2.3-70-g09d2 From 937a049dd903bd810d858d0303cf86af9eb08b6f Mon Sep 17 00:00:00 2001 From: Ulrich Kunitz Date: Tue, 2 Oct 2007 18:36:53 +0100 Subject: [ZD1211RW]: Removed zd_util.c and zd_util.h The kernel now provides a generic hexdump implementation should we need it again, so we can remove it from zd1211rw. After removing that, only one single-user function is left in zd_util. Move that to zd_mac and remove zd_util. Signed-off-by: Ulrich Kunitz Signed-off-by: Daniel Drake Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/zd1211rw/Makefile | 2 +- drivers/net/wireless/zd1211rw/zd_chip.c | 1 - drivers/net/wireless/zd1211rw/zd_mac.c | 4 +- drivers/net/wireless/zd1211rw/zd_usb.c | 1 - drivers/net/wireless/zd1211rw/zd_util.c | 82 --------------------------------- drivers/net/wireless/zd1211rw/zd_util.h | 29 ------------ 6 files changed, 3 insertions(+), 116 deletions(-) delete mode 100644 drivers/net/wireless/zd1211rw/zd_util.c delete mode 100644 drivers/net/wireless/zd1211rw/zd_util.h (limited to 'drivers') diff --git a/drivers/net/wireless/zd1211rw/Makefile b/drivers/net/wireless/zd1211rw/Makefile index 4d505903352..7a2f2a98eda 100644 --- a/drivers/net/wireless/zd1211rw/Makefile +++ b/drivers/net/wireless/zd1211rw/Makefile @@ -4,7 +4,7 @@ zd1211rw-objs := zd_chip.o zd_ieee80211.o \ zd_mac.o zd_netdev.o \ zd_rf_al2230.o zd_rf_rf2959.o \ zd_rf_al7230b.o zd_rf_uw2453.o \ - zd_rf.o zd_usb.o zd_util.o + zd_rf.o zd_usb.o ifeq ($(CONFIG_ZD1211RW_DEBUG),y) EXTRA_CFLAGS += -DDEBUG diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c index 3d60c69b20e..f831b68f1b9 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.c +++ b/drivers/net/wireless/zd1211rw/zd_chip.c @@ -28,7 +28,6 @@ #include "zd_ieee80211.h" #include "zd_mac.h" #include "zd_rf.h" -#include "zd_util.h" void zd_chip_init(struct zd_chip *chip, struct net_device *netdev, diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 06b342b3979..a903645e157 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -28,7 +28,6 @@ #include "zd_ieee80211.h" #include "zd_netdev.h" #include "zd_rf.h" -#include "zd_util.h" static void ieee_init(struct ieee80211_device *ieee); static void softmac_init(struct ieee80211softmac_device *sm); @@ -1066,7 +1065,8 @@ static int fill_rx_stats(struct ieee80211_rx_stats *stats, { const struct rx_status *status; - *pstatus = status = zd_tail(buffer, length, sizeof(struct rx_status)); + *pstatus = status = (struct rx_status *) + (buffer + (length - sizeof(struct rx_status))); if (status->frame_status & ZD_RX_ERROR) { struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); ieee->stats.rx_errors++; diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index 895ff844187..721d737e8d2 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -31,7 +31,6 @@ #include "zd_netdev.h" #include "zd_mac.h" #include "zd_usb.h" -#include "zd_util.h" static struct usb_device_id usb_ids[] = { /* ZD1211 */ diff --git a/drivers/net/wireless/zd1211rw/zd_util.c b/drivers/net/wireless/zd1211rw/zd_util.c deleted file mode 100644 index d20036c15d1..00000000000 --- a/drivers/net/wireless/zd1211rw/zd_util.c +++ /dev/null @@ -1,82 +0,0 @@ -/* zd_util.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Utility program - */ - -#include "zd_def.h" -#include "zd_util.h" - -#ifdef DEBUG -static char hex(u8 v) -{ - v &= 0xf; - return (v < 10 ? '0' : 'a' - 10) + v; -} - -static char hex_print(u8 c) -{ - return (0x20 <= c && c < 0x7f) ? c : '.'; -} - -static void dump_line(const u8 *bytes, size_t size) -{ - char c; - size_t i; - - size = size <= 8 ? size : 8; - printk(KERN_DEBUG "zd1211 %p ", bytes); - for (i = 0; i < 8; i++) { - switch (i) { - case 1: - case 5: - c = '.'; - break; - case 3: - c = ':'; - break; - default: - c = ' '; - } - if (i < size) { - printk("%c%c%c", hex(bytes[i] >> 4), hex(bytes[i]), c); - } else { - printk(" %c", c); - } - } - - for (i = 0; i < size; i++) - printk("%c", hex_print(bytes[i])); - printk("\n"); -} - -void zd_hexdump(const void *bytes, size_t size) -{ - size_t i = 0; - - do { - dump_line((u8 *)bytes + i, size-i); - i += 8; - } while (i < size); -} -#endif /* DEBUG */ - -void *zd_tail(const void *buffer, size_t buffer_size, size_t tail_size) -{ - if (buffer_size < tail_size) - return NULL; - return (u8 *)buffer + (buffer_size - tail_size); -} diff --git a/drivers/net/wireless/zd1211rw/zd_util.h b/drivers/net/wireless/zd1211rw/zd_util.h deleted file mode 100644 index ce26f7adea9..00000000000 --- a/drivers/net/wireless/zd1211rw/zd_util.h +++ /dev/null @@ -1,29 +0,0 @@ -/* zd_util.h - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _ZD_UTIL_H -#define _ZD_UTIL_H - -void *zd_tail(const void *buffer, size_t buffer_size, size_t tail_size); - -#ifdef DEBUG -void zd_hexdump(const void *bytes, size_t size); -#else -#define zd_hexdump(bytes, size) -#endif /* DEBUG */ - -#endif /* _ZD_UTIL_H */ -- cgit v1.2.3-70-g09d2 From 21954c367e4088c491122edd263964345bc1d3bf Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Thu, 27 Sep 2007 15:31:40 +0200 Subject: [B43]: LED triggers support Drive the LEDs through the generic LED triggers. Signed-off-by: Michael Buesch Cc: Larry Finger Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/b43/Kconfig | 6 + drivers/net/wireless/b43/Makefile | 3 +- drivers/net/wireless/b43/b43.h | 6 +- drivers/net/wireless/b43/leds.c | 395 ++++++++++++++++---------------------- drivers/net/wireless/b43/leds.h | 63 +++--- drivers/net/wireless/b43/main.c | 51 ++--- 6 files changed, 229 insertions(+), 295 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig index 4620119891f..1575654556b 100644 --- a/drivers/net/wireless/b43/Kconfig +++ b/drivers/net/wireless/b43/Kconfig @@ -61,6 +61,12 @@ config B43_PCMCIA If unsure, say N. +# LED support +config B43_LEDS + bool + depends on MAC80211_LEDS + default y + config B43_DEBUG bool "Broadcom 43xx debugging" depends on B43 diff --git a/drivers/net/wireless/b43/Makefile b/drivers/net/wireless/b43/Makefile index 370935b84c5..e6331414c4c 100644 --- a/drivers/net/wireless/b43/Makefile +++ b/drivers/net/wireless/b43/Makefile @@ -3,9 +3,10 @@ b43-y += main.o b43-y += tables.o b43-y += phy.o b43-y += sysfs.o -b43-y += leds.o b43-y += xmit.o b43-y += lo.o +# b43 LED support +b43-$(CONFIG_B43_LEDS) += leds.o # b43 PCMCIA support b43-$(CONFIG_B43_PCMCIA) += pcmcia.o # b43 debugging diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 2c8fa1c3465..6e6b59227e1 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -696,8 +696,10 @@ struct b43_wldev { /* Various statistics about the physical device. */ struct b43_stats stats; -#define B43_NR_LEDS 4 - struct b43_led leds[B43_NR_LEDS]; + /* The device LEDs. */ + struct b43_led led_tx; + struct b43_led led_rx; + struct b43_led led_assoc; /* Reason code of the last interrupt. */ u32 irq_reason; diff --git a/drivers/net/wireless/b43/leds.c b/drivers/net/wireless/b43/leds.c index 0f155b4f34e..ddab856f114 100644 --- a/drivers/net/wireless/b43/leds.c +++ b/drivers/net/wireless/b43/leds.c @@ -1,12 +1,13 @@ /* Broadcom B43 wireless driver + LED control Copyright (c) 2005 Martin Langer , - Stefano Brivio - Michael Buesch - Danny van Dyk - Andreas Jaggi + Copyright (c) 2005 Stefano Brivio + Copyright (c) 2005-2007 Michael Buesch + Copyright (c) 2005 Danny van Dyk + Copyright (c) 2005 Andreas Jaggi This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -27,272 +28,204 @@ #include "b43.h" #include "leds.h" -#include "main.h" -static void b43_led_changestate(struct b43_led *led) -{ - struct b43_wldev *dev = led->dev; - const int index = led->index; - u16 ledctl; - - B43_WARN_ON(!(index >= 0 && index < B43_NR_LEDS)); - B43_WARN_ON(!led->blink_interval); - ledctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL); - ledctl ^= (1 << index); - b43_write16(dev, B43_MMIO_GPIO_CONTROL, ledctl); -} -static void b43_led_blink(unsigned long d) +static void b43_led_turn_on(struct b43_wldev *dev, u8 led_index, + bool activelow) { - struct b43_led *led = (struct b43_led *)d; - struct b43_wldev *dev = led->dev; + struct b43_wl *wl = dev->wl; unsigned long flags; + u16 ctl; - spin_lock_irqsave(&dev->wl->leds_lock, flags); - if (led->blink_interval) { - b43_led_changestate(led); - mod_timer(&led->blink_timer, jiffies + led->blink_interval); - } - spin_unlock_irqrestore(&dev->wl->leds_lock, flags); + spin_lock_irqsave(&wl->leds_lock, flags); + ctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL); + if (activelow) + ctl &= ~(1 << led_index); + else + ctl |= (1 << led_index); + b43_write16(dev, B43_MMIO_GPIO_CONTROL, ctl); + spin_unlock_irqrestore(&wl->leds_lock, flags); } -static void b43_led_blink_start(struct b43_led *led, unsigned long interval) +static void b43_led_turn_off(struct b43_wldev *dev, u8 led_index, + bool activelow) { - if (led->blink_interval) - return; - led->blink_interval = interval; - b43_led_changestate(led); - led->blink_timer.expires = jiffies + interval; - add_timer(&led->blink_timer); + struct b43_wl *wl = dev->wl; + unsigned long flags; + u16 ctl; + + spin_lock_irqsave(&wl->leds_lock, flags); + ctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL); + if (activelow) + ctl |= (1 << led_index); + else + ctl &= ~(1 << led_index); + b43_write16(dev, B43_MMIO_GPIO_CONTROL, ctl); + spin_unlock_irqrestore(&wl->leds_lock, flags); } -static void b43_led_blink_stop(struct b43_led *led, int sync) +/* Callback from the LED subsystem. */ +static void b43_led_brightness_set(struct led_classdev *led_dev, + enum led_brightness brightness) { + struct b43_led *led = container_of(led_dev, struct b43_led, led_dev); struct b43_wldev *dev = led->dev; - const int index = led->index; - u16 ledctl; + bool radio_enabled; - if (!led->blink_interval) - return; - if (unlikely(sync)) - del_timer_sync(&led->blink_timer); - else - del_timer(&led->blink_timer); - led->blink_interval = 0; + /* Checking the radio-enabled status here is slightly racy, + * but we want to avoid the locking overhead and we don't care + * whether the LED has the wrong state for a second. */ + radio_enabled = (dev->phy.radio_on && dev->radio_hw_enable); - /* Make sure the LED is turned off. */ - B43_WARN_ON(!(index >= 0 && index < B43_NR_LEDS)); - ledctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL); - if (led->activelow) - ledctl |= (1 << index); + if (brightness == LED_OFF || !radio_enabled) + b43_led_turn_off(dev, led->index, led->activelow); else - ledctl &= ~(1 << index); - b43_write16(dev, B43_MMIO_GPIO_CONTROL, ledctl); + b43_led_turn_on(dev, led->index, led->activelow); } -static void b43_led_init_hardcoded(struct b43_wldev *dev, - struct b43_led *led, int led_index) +static int b43_register_led(struct b43_wldev *dev, struct b43_led *led, + const char *name, char *default_trigger, + u8 led_index, bool activelow) { - struct ssb_bus *bus = dev->dev->bus; + int err; + + b43_led_turn_off(dev, led_index, activelow); + if (led->dev) + return -EEXIST; + if (!default_trigger) + return -EINVAL; + led->dev = dev; + led->index = led_index; + led->activelow = activelow; + strncpy(led->name, name, sizeof(led->name)); + + led->led_dev.name = led->name; + led->led_dev.default_trigger = default_trigger; + led->led_dev.brightness_set = b43_led_brightness_set; + + err = led_classdev_register(dev->dev->dev, &led->led_dev); + if (err) { + b43warn(dev->wl, "LEDs: Failed to register %s\n", name); + led->dev = NULL; + return err; + } + return 0; +} + +static void b43_unregister_led(struct b43_led *led) +{ + if (!led->dev) + return; + led_classdev_unregister(&led->led_dev); + b43_led_turn_off(led->dev, led->index, led->activelow); + led->dev = NULL; +} - /* This function is called, if the behaviour (and activelow) - * information for a LED is missing in the SPROM. - * We hardcode the behaviour values for various devices here. - * Note that the B43_LED_TEST_XXX behaviour values can - * be used to figure out which led is mapped to which index. - */ +static void b43_map_led(struct b43_wldev *dev, + u8 led_index, + enum b43_led_behaviour behaviour, + bool activelow) +{ + struct ieee80211_hw *hw = dev->wl->hw; + char name[B43_LED_MAX_NAME_LEN + 1]; - switch (led_index) { - case 0: - led->behaviour = B43_LED_ACTIVITY; - led->activelow = 1; - if (bus->boardinfo.vendor == PCI_VENDOR_ID_COMPAQ) - led->behaviour = B43_LED_RADIO_ALL; + /* Map the b43 specific LED behaviour value to the + * generic LED triggers. */ + switch (behaviour) { + case B43_LED_INACTIVE: + break; + case B43_LED_OFF: + b43_led_turn_off(dev, led_index, activelow); break; - case 1: - led->behaviour = B43_LED_RADIO_B; - if (bus->boardinfo.vendor == PCI_VENDOR_ID_ASUSTEK) - led->behaviour = B43_LED_ASSOC; + case B43_LED_ON: + b43_led_turn_on(dev, led_index, activelow); break; - case 2: - led->behaviour = B43_LED_RADIO_A; + case B43_LED_ACTIVITY: + case B43_LED_TRANSFER: + case B43_LED_APTRANSFER: + snprintf(name, sizeof(name), + "b43-%s:tx", wiphy_name(hw->wiphy)); + b43_register_led(dev, &dev->led_tx, name, + ieee80211_get_tx_led_name(hw), + led_index, activelow); + snprintf(name, sizeof(name), + "b43-%s:rx", wiphy_name(hw->wiphy)); + b43_register_led(dev, &dev->led_rx, name, + ieee80211_get_rx_led_name(hw), + led_index, activelow); break; - case 3: - led->behaviour = B43_LED_OFF; + /*FIXME: We need another trigger for the "radio-on" LEDs below. + * Wiggle that somehow into the rfkill subsystem. */ + case B43_LED_RADIO_ALL: + case B43_LED_RADIO_A: + case B43_LED_RADIO_B: + case B43_LED_MODE_BG: + case B43_LED_WEIRD: + case B43_LED_ASSOC: + snprintf(name, sizeof(name), + "b43-%s:assoc", wiphy_name(hw->wiphy)); + b43_register_led(dev, &dev->led_assoc, name, + ieee80211_get_assoc_led_name(hw), + led_index, activelow); break; default: - B43_WARN_ON(1); + b43warn(dev->wl, "LEDs: Unknown behaviour 0x%02X\n", + behaviour); + break; } } -int b43_leds_init(struct b43_wldev *dev) +void b43_leds_init(struct b43_wldev *dev) { - struct b43_led *led; + struct ssb_bus *bus = dev->dev->bus; u8 sprom[4]; int i; + enum b43_led_behaviour behaviour; + bool activelow; - sprom[0] = dev->dev->bus->sprom.r1.gpio0; - sprom[1] = dev->dev->bus->sprom.r1.gpio1; - sprom[2] = dev->dev->bus->sprom.r1.gpio2; - sprom[3] = dev->dev->bus->sprom.r1.gpio3; - - for (i = 0; i < B43_NR_LEDS; i++) { - led = &(dev->leds[i]); - led->index = i; - led->dev = dev; - setup_timer(&led->blink_timer, - b43_led_blink, (unsigned long)led); + sprom[0] = bus->sprom.r1.gpio0; + sprom[1] = bus->sprom.r1.gpio1; + sprom[2] = bus->sprom.r1.gpio2; + sprom[3] = bus->sprom.r1.gpio3; + for (i = 0; i < 4; i++) { if (sprom[i] == 0xFF) { - b43_led_init_hardcoded(dev, led, i); + /* There is no LED information in the SPROM + * for this LED. Hardcode it here. */ + activelow = 0; + switch (i) { + case 0: + behaviour = B43_LED_ACTIVITY; + activelow = 1; + if (bus->boardinfo.vendor == PCI_VENDOR_ID_COMPAQ) + behaviour = B43_LED_RADIO_ALL; + break; + case 1: + behaviour = B43_LED_RADIO_B; + if (bus->boardinfo.vendor == PCI_VENDOR_ID_ASUSTEK) + behaviour = B43_LED_ASSOC; + break; + case 2: + behaviour = B43_LED_RADIO_A; + break; + case 3: + behaviour = B43_LED_OFF; + break; + default: + B43_WARN_ON(1); + return; + } } else { - led->behaviour = sprom[i] & B43_LED_BEHAVIOUR; - led->activelow = !!(sprom[i] & B43_LED_ACTIVELOW); + behaviour = sprom[i] & B43_LED_BEHAVIOUR; + activelow = !!(sprom[i] & B43_LED_ACTIVELOW); } + b43_map_led(dev, i, behaviour, activelow); } - - return 0; } void b43_leds_exit(struct b43_wldev *dev) { - struct b43_led *led; - int i; - - for (i = 0; i < B43_NR_LEDS; i++) { - led = &(dev->leds[i]); - b43_led_blink_stop(led, 1); - } - b43_leds_switch_all(dev, 0); -} - -void b43_leds_update(struct b43_wldev *dev, int activity) -{ - struct b43_led *led; - struct b43_phy *phy = &dev->phy; - const int transferring = - (jiffies - dev->stats.last_tx) < B43_LED_XFER_THRES; - int i, turn_on; - unsigned long interval = 0; - u16 ledctl; - unsigned long flags; - bool radio_enabled = (phy->radio_on && dev->radio_hw_enable); - - spin_lock_irqsave(&dev->wl->leds_lock, flags); - ledctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL); - for (i = 0; i < B43_NR_LEDS; i++) { - led = &(dev->leds[i]); - - turn_on = 0; - switch (led->behaviour) { - case B43_LED_INACTIVE: - continue; - case B43_LED_OFF: - break; - case B43_LED_ON: - turn_on = 1; - break; - case B43_LED_ACTIVITY: - turn_on = activity; - break; - case B43_LED_RADIO_ALL: - turn_on = radio_enabled; - break; - case B43_LED_RADIO_A: - turn_on = (radio_enabled && phy->type == B43_PHYTYPE_A); - break; - case B43_LED_RADIO_B: - turn_on = (radio_enabled && - (phy->type == B43_PHYTYPE_B - || phy->type == B43_PHYTYPE_G)); - break; - case B43_LED_MODE_BG: - if (phy->type == B43_PHYTYPE_G - && radio_enabled) - turn_on = 1; - break; - case B43_LED_TRANSFER: - if (transferring) - b43_led_blink_start(led, B43_LEDBLINK_MEDIUM); - else - b43_led_blink_stop(led, 0); - continue; - case B43_LED_APTRANSFER: - if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) { - if (transferring) { - interval = B43_LEDBLINK_FAST; - turn_on = 1; - } - } else { - turn_on = 1; - if (0 /*TODO: not assoc */ ) - interval = B43_LEDBLINK_SLOW; - else if (transferring) - interval = B43_LEDBLINK_FAST; - else - turn_on = 0; - } - if (turn_on) - b43_led_blink_start(led, interval); - else - b43_led_blink_stop(led, 0); - continue; - case B43_LED_WEIRD: - //TODO - break; - case B43_LED_ASSOC: - if (1 /*dev->softmac->associated */ ) - turn_on = 1; - break; -#ifdef CONFIG_B43_DEBUG - case B43_LED_TEST_BLINKSLOW: - b43_led_blink_start(led, B43_LEDBLINK_SLOW); - continue; - case B43_LED_TEST_BLINKMEDIUM: - b43_led_blink_start(led, B43_LEDBLINK_MEDIUM); - continue; - case B43_LED_TEST_BLINKFAST: - b43_led_blink_start(led, B43_LEDBLINK_FAST); - continue; -#endif /* CONFIG_B43_DEBUG */ - default: - B43_WARN_ON(1); - }; - - if (led->activelow) - turn_on = !turn_on; - if (turn_on) - ledctl |= (1 << i); - else - ledctl &= ~(1 << i); - } - b43_write16(dev, B43_MMIO_GPIO_CONTROL, ledctl); - spin_unlock_irqrestore(&dev->wl->leds_lock, flags); -} - -void b43_leds_switch_all(struct b43_wldev *dev, int on) -{ - struct b43_led *led; - u16 ledctl; - int i; - int bit_on; - unsigned long flags; - - spin_lock_irqsave(&dev->wl->leds_lock, flags); - ledctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL); - for (i = 0; i < B43_NR_LEDS; i++) { - led = &(dev->leds[i]); - if (led->behaviour == B43_LED_INACTIVE) - continue; - if (on) - bit_on = led->activelow ? 0 : 1; - else - bit_on = led->activelow ? 1 : 0; - if (bit_on) - ledctl |= (1 << i); - else - ledctl &= ~(1 << i); - } - b43_write16(dev, B43_MMIO_GPIO_CONTROL, ledctl); - spin_unlock_irqrestore(&dev->wl->leds_lock, flags); + b43_unregister_led(&dev->led_tx); + b43_unregister_led(&dev->led_rx); + b43_unregister_led(&dev->led_assoc); } diff --git a/drivers/net/wireless/b43/leds.h b/drivers/net/wireless/b43/leds.h index d94851d291c..b8b1dd52124 100644 --- a/drivers/net/wireless/b43/leds.h +++ b/drivers/net/wireless/b43/leds.h @@ -1,29 +1,33 @@ #ifndef B43_LEDS_H_ #define B43_LEDS_H_ +struct b43_wldev; + +#ifdef CONFIG_B43_LEDS + #include -#include +#include + + +#define B43_LED_MAX_NAME_LEN 31 struct b43_led { - u8 behaviour; - bool activelow; - /* Index in the "leds" array in b43_wldev */ - u8 index; struct b43_wldev *dev; - struct timer_list blink_timer; - unsigned long blink_interval; + /* The LED class device */ + struct led_classdev led_dev; + /* The index number of the LED. */ + u8 index; + /* If activelow is true, the LED is ON if the + * bit is switched off. */ + bool activelow; + /* The unique name string for this LED device. */ + char name[B43_LED_MAX_NAME_LEN + 1]; }; -/* Delay between state changes when blinking in jiffies */ -#define B43_LEDBLINK_SLOW (HZ / 1) -#define B43_LEDBLINK_MEDIUM (HZ / 4) -#define B43_LEDBLINK_FAST (HZ / 8) - -#define B43_LED_XFER_THRES (HZ / 100) - #define B43_LED_BEHAVIOUR 0x7F #define B43_LED_ACTIVELOW 0x80 -enum { /* LED behaviour values */ +/* LED behaviour values */ +enum b43_led_behaviour { B43_LED_OFF, B43_LED_ON, B43_LED_ACTIVITY, @@ -36,20 +40,25 @@ enum { /* LED behaviour values */ B43_LED_WEIRD, //FIXME B43_LED_ASSOC, B43_LED_INACTIVE, - - /* Behaviour values for testing. - * With these values it is easier to figure out - * the real behaviour of leds, in case the SPROM - * is missing information. - */ - B43_LED_TEST_BLINKSLOW, - B43_LED_TEST_BLINKMEDIUM, - B43_LED_TEST_BLINKFAST, }; -int b43_leds_init(struct b43_wldev *dev); +void b43_leds_init(struct b43_wldev *dev); void b43_leds_exit(struct b43_wldev *dev); -void b43_leds_update(struct b43_wldev *dev, int activity); -void b43_leds_switch_all(struct b43_wldev *dev, int on); + + +#else /* CONFIG_B43_LEDS */ +/* LED support disabled */ + +struct b43_led { + /* empty */ +}; + +static inline void b43_leds_init(struct b43_wldev *dev) +{ +} +static inline void b43_leds_exit(struct b43_wldev *dev) +{ +} +#endif /* CONFIG_B43_LEDS */ #endif /* B43_LEDS_H_ */ diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 72467c86f8d..2b81bd6165d 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -84,10 +84,6 @@ static int modparam_long_retry = B43_DEFAULT_LONG_RETRY_LIMIT; module_param_named(long_retry, modparam_long_retry, int, 0444); MODULE_PARM_DESC(long_retry, "Long-Retry-Limit (0 - 15)"); -static int modparam_noleds; -module_param_named(noleds, modparam_noleds, int, 0444); -MODULE_PARM_DESC(noleds, "Turn off all LED activity"); - static char modparam_fwpostfix[16]; module_param_string(fwpostfix, modparam_fwpostfix, 16, 0444); MODULE_PARM_DESC(fwpostfix, "Postfix for the .fw files to load."); @@ -1391,7 +1387,7 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev) u32 reason; u32 dma_reason[ARRAY_SIZE(dev->dma_reason)]; u32 merged_dma_reason = 0; - int i, activity = 0; + int i; unsigned long flags; spin_lock_irqsave(&dev->wl->irq_lock, flags); @@ -1444,8 +1440,9 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev) handle_irq_beacon(dev); if (reason & B43_IRQ_PMQ) handle_irq_pmq(dev); - if (reason & B43_IRQ_TXFIFO_FLUSH_OK) ; - /*TODO*/ if (reason & B43_IRQ_NOISESAMPLE_OK) + if (reason & B43_IRQ_TXFIFO_FLUSH_OK) + ;/* TODO */ + if (reason & B43_IRQ_NOISESAMPLE_OK) handle_irq_noise(dev); /* Check the DMA reason registers for received data. */ @@ -1454,7 +1451,6 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev) b43_pio_rx(dev->pio.queue0); else b43_dma_rx(dev->dma.rx_ring0); - /* We intentionally don't set "activity" to 1, here. */ } B43_WARN_ON(dma_reason[1] & B43_DMAIRQ_RX_DONE); B43_WARN_ON(dma_reason[2] & B43_DMAIRQ_RX_DONE); @@ -1463,19 +1459,13 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev) b43_pio_rx(dev->pio.queue3); else b43_dma_rx(dev->dma.rx_ring3); - activity = 1; } B43_WARN_ON(dma_reason[4] & B43_DMAIRQ_RX_DONE); B43_WARN_ON(dma_reason[5] & B43_DMAIRQ_RX_DONE); - if (reason & B43_IRQ_TX_OK) { + if (reason & B43_IRQ_TX_OK) handle_irq_transmit_status(dev); - activity = 1; - //TODO: In AP mode, this also causes sending of powersave responses. - } - if (!modparam_noleds) - b43_leds_update(dev, activity); b43_interrupt_enable(dev, dev->irq_savedstate); mmiowb(); spin_unlock_irqrestore(&dev->wl->irq_lock, flags); @@ -1927,7 +1917,6 @@ static int b43_gpio_init(struct b43_wldev *dev) b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL) & ~B43_MACCTL_GPOUTSMSK); - b43_leds_switch_all(dev, 0); b43_write16(dev, B43_MMIO_GPIO_MASK, b43_read16(dev, B43_MMIO_GPIO_MASK) | 0x000F); @@ -2173,8 +2162,7 @@ static bool b43_is_hw_radio_enabled(struct b43_wldev *dev) static void b43_chip_exit(struct b43_wldev *dev) { b43_radio_turn_off(dev); - if (!modparam_noleds) - b43_leds_exit(dev); + b43_leds_exit(dev); b43_gpio_cleanup(dev); /* firmware is released later */ } @@ -2202,9 +2190,11 @@ static int b43_chip_init(struct b43_wldev *dev) err = b43_gpio_init(dev); if (err) goto out; /* firmware is released later */ + b43_leds_init(dev); + err = b43_upload_initvals(dev); if (err) - goto err_gpio_cleanup; + goto err_leds_exit; b43_radio_turn_on(dev); b43_write16(dev, 0x03E6, 0x0000); @@ -2275,14 +2265,15 @@ static int b43_chip_init(struct b43_wldev *dev) err = 0; b43dbg(dev->wl, "Chip initialized\n"); - out: +out: return err; - err_radio_off: +err_radio_off: b43_radio_turn_off(dev); - err_gpio_cleanup: +err_leds_exit: + b43_leds_exit(dev); b43_gpio_cleanup(dev); - goto out; + return err; } static void b43_periodic_every120sec(struct b43_wldev *dev) @@ -2369,7 +2360,6 @@ static void b43_periodic_every1sec(struct b43_wldev *dev) dev->radio_hw_enable = radio_hw_enable; b43info(dev->wl, "Radio hardware status changed to %s\n", radio_hw_enable ? "ENABLED" : "DISABLED"); - b43_leds_update(dev, 0); } } @@ -3767,18 +3757,13 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) } else have_bphy = 1; - /* Initialize LEDs structs. */ - err = b43_leds_init(dev); - if (err) - goto err_powerdown; - dev->phy.gmode = (have_gphy || have_bphy); tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0; b43_wireless_core_reset(dev, tmp); err = b43_phy_versioning(dev); if (err) - goto err_leds_exit; + goto err_powerdown; /* Check if this device supports multiband. */ if (!pdev || (pdev->device != 0x4312 && @@ -3807,10 +3792,10 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) err = b43_validate_chipaccess(dev); if (err) - goto err_leds_exit; + goto err_powerdown; err = b43_setup_modes(dev, have_aphy, have_bphy, have_gphy); if (err) - goto err_leds_exit; + goto err_powerdown; /* Now set some default "current_dev" */ if (!wl->current_dev) @@ -3825,8 +3810,6 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) out: return err; -err_leds_exit: - b43_leds_exit(dev); err_powerdown: ssb_bus_may_powerdown(bus); return err; -- cgit v1.2.3-70-g09d2 From 8e9f7529fdfe34ed519f048682eb404fbd8004e8 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Thu, 27 Sep 2007 21:35:34 +0200 Subject: [B43]: RF-kill support This adds full support for the RFKILL button and the RFKILL LED trigger. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/b43/Kconfig | 8 +- drivers/net/wireless/b43/Makefile | 2 + drivers/net/wireless/b43/b43.h | 5 ++ drivers/net/wireless/b43/leds.c | 8 +- drivers/net/wireless/b43/main.c | 18 +++-- drivers/net/wireless/b43/phy.c | 13 +++- drivers/net/wireless/b43/phy.h | 2 +- drivers/net/wireless/b43/rfkill.c | 155 ++++++++++++++++++++++++++++++++++++++ drivers/net/wireless/b43/rfkill.h | 49 ++++++++++++ 9 files changed, 245 insertions(+), 15 deletions(-) create mode 100644 drivers/net/wireless/b43/rfkill.c create mode 100644 drivers/net/wireless/b43/rfkill.h (limited to 'drivers') diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig index 1575654556b..968f0611ed4 100644 --- a/drivers/net/wireless/b43/Kconfig +++ b/drivers/net/wireless/b43/Kconfig @@ -64,7 +64,13 @@ config B43_PCMCIA # LED support config B43_LEDS bool - depends on MAC80211_LEDS + depends on B43 && MAC80211_LEDS + default y + +# RFKILL support +config B43_RFKILL + bool + depends on B43 && RFKILL default y config B43_DEBUG diff --git a/drivers/net/wireless/b43/Makefile b/drivers/net/wireless/b43/Makefile index e6331414c4c..485e59e2dfa 100644 --- a/drivers/net/wireless/b43/Makefile +++ b/drivers/net/wireless/b43/Makefile @@ -5,6 +5,8 @@ b43-y += phy.o b43-y += sysfs.o b43-y += xmit.o b43-y += lo.o +# b43 RFKILL button support +b43-$(CONFIG_B43_RFKILL) += rfkill.o # b43 LED support b43-$(CONFIG_B43_LEDS) += leds.o # b43 PCMCIA support diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 6e6b59227e1..a28ad230d63 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -10,6 +10,7 @@ #include "debugfs.h" #include "leds.h" +#include "rfkill.h" #include "lo.h" #include "phy.h" @@ -625,6 +626,9 @@ struct b43_wl { u8 rng_initialized; char rng_name[30 + 1]; + /* The RF-kill button */ + struct b43_rfkill rfkill; + /* List of all wireless devices on this chip */ struct list_head devlist; u8 nr_devs; @@ -700,6 +704,7 @@ struct b43_wldev { struct b43_led led_tx; struct b43_led led_rx; struct b43_led led_assoc; + struct b43_led led_radio; /* Reason code of the last interrupt. */ u32 irq_reason; diff --git a/drivers/net/wireless/b43/leds.c b/drivers/net/wireless/b43/leds.c index ddab856f114..19e588582c7 100644 --- a/drivers/net/wireless/b43/leds.c +++ b/drivers/net/wireless/b43/leds.c @@ -154,12 +154,16 @@ static void b43_map_led(struct b43_wldev *dev, ieee80211_get_rx_led_name(hw), led_index, activelow); break; - /*FIXME: We need another trigger for the "radio-on" LEDs below. - * Wiggle that somehow into the rfkill subsystem. */ case B43_LED_RADIO_ALL: case B43_LED_RADIO_A: case B43_LED_RADIO_B: case B43_LED_MODE_BG: + snprintf(name, sizeof(name), + "b43-%s:radio", wiphy_name(hw->wiphy)); + b43_register_led(dev, &dev->led_radio, name, + b43_rfkill_led_name(dev), + led_index, activelow); + break; case B43_LED_WEIRD: case B43_LED_ASSOC: snprintf(name, sizeof(name), diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 2b81bd6165d..a9f7148493f 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -2161,7 +2161,7 @@ static bool b43_is_hw_radio_enabled(struct b43_wldev *dev) /* This is the opposite of b43_chip_init() */ static void b43_chip_exit(struct b43_wldev *dev) { - b43_radio_turn_off(dev); + b43_radio_turn_off(dev, 1); b43_leds_exit(dev); b43_gpio_cleanup(dev); /* firmware is released later */ @@ -2269,7 +2269,7 @@ out: return err; err_radio_off: - b43_radio_turn_off(dev); + b43_radio_turn_off(dev, 1); err_leds_exit: b43_leds_exit(dev); b43_gpio_cleanup(dev); @@ -2358,8 +2358,7 @@ static void b43_periodic_every1sec(struct b43_wldev *dev) radio_hw_enable = b43_is_hw_radio_enabled(dev); if (unlikely(dev->radio_hw_enable != radio_hw_enable)) { dev->radio_hw_enable = radio_hw_enable; - b43info(dev->wl, "Radio hardware status changed to %s\n", - radio_hw_enable ? "ENABLED" : "DISABLED"); + b43_rfkill_toggled(dev, radio_hw_enable); } } @@ -2850,7 +2849,7 @@ static int b43_dev_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) "Press the button to turn it on.\n"); } } else { - b43_radio_turn_off(dev); + b43_radio_turn_off(dev, 0); b43info(dev->wl, "Radio turned off by software\n"); } } @@ -3330,11 +3329,15 @@ static void b43_wireless_core_exit(struct b43_wldev *dev) return; b43_set_status(dev, B43_STAT_UNINIT); + mutex_unlock(&dev->wl->mutex); + b43_rfkill_exit(dev); + mutex_lock(&dev->wl->mutex); + b43_rng_exit(dev->wl); b43_pio_free(dev); b43_dma_free(dev); b43_chip_exit(dev); - b43_radio_turn_off(dev); + b43_radio_turn_off(dev, 1); b43_switch_analog(dev, 0); if (phy->dyn_tssi_tbl) kfree(phy->tssi2dbm); @@ -3458,6 +3461,7 @@ static int b43_wireless_core_init(struct b43_wldev *dev) memset(wl->mac_addr, 0, ETH_ALEN); b43_upload_card_macaddress(dev); b43_security_init(dev); + b43_rfkill_init(dev); b43_rng_init(wl); b43_set_status(dev, B43_STAT_INITIALIZED); @@ -3802,7 +3806,7 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) wl->current_dev = dev; INIT_WORK(&dev->restart_work, b43_chip_reset); - b43_radio_turn_off(dev); + b43_radio_turn_off(dev, 1); b43_switch_analog(dev, 0); ssb_device_disable(dev->dev, 0); ssb_bus_may_powerdown(bus); diff --git a/drivers/net/wireless/b43/phy.c b/drivers/net/wireless/b43/phy.c index 354d1823875..5f7ffa0a76c 100644 --- a/drivers/net/wireless/b43/phy.c +++ b/drivers/net/wireless/b43/phy.c @@ -4349,10 +4349,13 @@ void b43_radio_turn_on(struct b43_wldev *dev) phy->radio_on = 1; } -void b43_radio_turn_off(struct b43_wldev *dev) +void b43_radio_turn_off(struct b43_wldev *dev, bool force) { struct b43_phy *phy = &dev->phy; + if (!phy->radio_on && !force) + return; + if (phy->type == B43_PHYTYPE_A) { b43_radio_write16(dev, 0x0004, 0x00FF); b43_radio_write16(dev, 0x0005, 0x00FB); @@ -4364,9 +4367,11 @@ void b43_radio_turn_off(struct b43_wldev *dev) rfover = b43_phy_read(dev, B43_PHY_RFOVER); rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL); - phy->radio_off_context.rfover = rfover; - phy->radio_off_context.rfoverval = rfoverval; - phy->radio_off_context.valid = 1; + if (!force) { + phy->radio_off_context.rfover = rfover; + phy->radio_off_context.rfoverval = rfoverval; + phy->radio_off_context.valid = 1; + } b43_phy_write(dev, B43_PHY_RFOVER, rfover | 0x008C); b43_phy_write(dev, B43_PHY_RFOVERVAL, rfoverval & 0xFF73); } else diff --git a/drivers/net/wireless/b43/phy.h b/drivers/net/wireless/b43/phy.h index d1f623cb9b3..c64d74504fc 100644 --- a/drivers/net/wireless/b43/phy.h +++ b/drivers/net/wireless/b43/phy.h @@ -267,7 +267,7 @@ u16 b43_radio_init2050(struct b43_wldev *dev); void b43_radio_init2060(struct b43_wldev *dev); void b43_radio_turn_on(struct b43_wldev *dev); -void b43_radio_turn_off(struct b43_wldev *dev); +void b43_radio_turn_off(struct b43_wldev *dev, bool force); int b43_radio_selectchannel(struct b43_wldev *dev, u8 channel, int synthetic_pu_workaround); diff --git a/drivers/net/wireless/b43/rfkill.c b/drivers/net/wireless/b43/rfkill.c new file mode 100644 index 00000000000..c25fd9956a9 --- /dev/null +++ b/drivers/net/wireless/b43/rfkill.c @@ -0,0 +1,155 @@ +/* + + Broadcom B43 wireless driver + RFKILL support + + Copyright (c) 2007 Michael Buesch + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "rfkill.h" +#include "b43.h" + + +static void b43_notify_rfkill_press(struct work_struct *work) +{ + struct b43_rfkill *rfk = container_of(work, struct b43_rfkill, + notify_work); + struct b43_wl *wl = container_of(rfk, struct b43_wl, rfkill); + struct b43_wldev *dev; + enum rfkill_state state; + + mutex_lock(&wl->mutex); + dev = wl->current_dev; + if (b43_status(dev) < B43_STAT_INITIALIZED) { + mutex_unlock(&wl->mutex); + return; + } + if (dev->radio_hw_enable) + state = RFKILL_STATE_ON; + else + state = RFKILL_STATE_OFF; + b43info(wl, "Radio hardware status changed to %s\n", + dev->radio_hw_enable ? "ENABLED" : "DISABLED"); + mutex_unlock(&wl->mutex); + + if (rfk->rfkill) { + /* Be careful. This calls back into the software toggle routines. + * So we must unlock before calling. */ + rfkill_switch_all(rfk->rfkill->type, state); + } +} + +/* Called when the RFKILL toggled in hardware. + * This is called with the mutex locked. */ +void b43_rfkill_toggled(struct b43_wldev *dev, bool on) +{ + struct b43_wl *wl = dev->wl; + + B43_WARN_ON(b43_status(dev) < B43_STAT_INITIALIZED); + /* Update the RF status asynchronously, as rfkill will + * call back into the software toggle handler. + * This would deadlock if done synchronously. */ + queue_work(wl->hw->workqueue, &wl->rfkill.notify_work); +} + +/* Called when the RFKILL toggled in software. + * This is called without locking. */ +static int b43_rfkill_soft_toggle(void *data, enum rfkill_state state) +{ + struct b43_wldev *dev = data; + struct b43_wl *wl = dev->wl; + int err = 0; + + mutex_lock(&wl->mutex); + if (b43_status(dev) < B43_STAT_INITIALIZED) + goto out_unlock; + + switch (state) { + case RFKILL_STATE_ON: + if (!dev->radio_hw_enable) { + /* No luck. We can't toggle the hardware RF-kill + * button from software. */ + err = -EBUSY; + goto out_unlock; + } + if (!dev->phy.radio_on) + b43_radio_turn_on(dev); + break; + case RFKILL_STATE_OFF: + if (dev->phy.radio_on) + b43_radio_turn_off(dev, 0); + break; + } + +out_unlock: + mutex_unlock(&wl->mutex); + + return err; +} + +char * b43_rfkill_led_name(struct b43_wldev *dev) +{ + struct b43_wl *wl = dev->wl; + + if (!wl->rfkill.rfkill) + return NULL; + return rfkill_get_led_name(wl->rfkill.rfkill); +} + +void b43_rfkill_init(struct b43_wldev *dev) +{ + struct b43_wl *wl = dev->wl; + struct b43_rfkill *rfk = &(wl->rfkill); + int err; + + snprintf(rfk->name, sizeof(rfk->name), + "b43-%s", wiphy_name(wl->hw->wiphy)); + rfk->rfkill = rfkill_allocate(dev->dev->dev, RFKILL_TYPE_WLAN); + if (!rfk->rfkill) + goto error; + rfk->rfkill->name = rfk->name; + rfk->rfkill->state = RFKILL_STATE_ON; + rfk->rfkill->data = dev; + rfk->rfkill->toggle_radio = b43_rfkill_soft_toggle; + rfk->rfkill->user_claim_unsupported = 1; + + INIT_WORK(&rfk->notify_work, b43_notify_rfkill_press); + + err = rfkill_register(rfk->rfkill); + if (err) + goto error; + + return; +error: + b43warn(dev->wl, "Failed to initialize the RF-kill button\n"); + rfkill_free(rfk->rfkill); + rfk->rfkill = NULL; +} + +void b43_rfkill_exit(struct b43_wldev *dev) +{ + struct b43_rfkill *rfk = &(dev->wl->rfkill); + + if (!rfk->rfkill) + return; + cancel_work_sync(&rfk->notify_work); + rfkill_unregister(rfk->rfkill); + rfkill_free(rfk->rfkill); + rfk->rfkill = NULL; +} diff --git a/drivers/net/wireless/b43/rfkill.h b/drivers/net/wireless/b43/rfkill.h new file mode 100644 index 00000000000..05db0d67a92 --- /dev/null +++ b/drivers/net/wireless/b43/rfkill.h @@ -0,0 +1,49 @@ +#ifndef B43_RFKILL_H_ +#define B43_RFKILL_H_ + +struct b43_wldev; + + +#ifdef CONFIG_B43_RFKILL + +#include + +struct b43_rfkill { + /* The RFKILL subsystem data structure */ + struct rfkill *rfkill; + /* The unique name of this rfkill switch */ + char name[32]; + /* Workqueue for asynchronous notification. */ + struct work_struct notify_work; +}; + +void b43_rfkill_init(struct b43_wldev *dev); +void b43_rfkill_exit(struct b43_wldev *dev); +void b43_rfkill_toggled(struct b43_wldev *dev, bool on); +char * b43_rfkill_led_name(struct b43_wldev *dev); + + +#else /* CONFIG_B43_RFKILL */ +/* No RFKILL support. */ + +struct b43_rfkill { + /* empty */ +}; + +static inline void b43_rfkill_init(struct b43_wldev *dev) +{ +} +static inline void b43_rfkill_exit(struct b43_wldev *dev) +{ +} +static inline void b43_rfkill_toggled(struct b43_wldev *dev, bool on) +{ +} +static inline char * b43_rfkill_led_name(struct b43_wldev *dev) +{ + return NULL; +} + +#endif /* CONFIG_B43_RFKILL */ + +#endif /* B43_RFKILL_H_ */ -- cgit v1.2.3-70-g09d2 From 42bb4cd5ae320dd46630533fecb91b940d4468e2 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 28 Sep 2007 14:22:33 +0200 Subject: [B43]: Use input-polldev for the rfkill switch This removes the direct call to rfkill on an rfkill event and replaces it with an input device. This way userspace is also notified about the event. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/b43/Kconfig | 2 +- drivers/net/wireless/b43/main.c | 53 ++++------------ drivers/net/wireless/b43/rfkill.c | 129 +++++++++++++++++++++++--------------- drivers/net/wireless/b43/rfkill.h | 21 +++++-- 4 files changed, 107 insertions(+), 98 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig index 968f0611ed4..e3c573e56b6 100644 --- a/drivers/net/wireless/b43/Kconfig +++ b/drivers/net/wireless/b43/Kconfig @@ -70,7 +70,7 @@ config B43_LEDS # RFKILL support config B43_RFKILL bool - depends on B43 && RFKILL + depends on B43 && RFKILL && RFKILL_INPUT && INPUT_POLLDEV default y config B43_DEBUG diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index a9f7148493f..a603a154d49 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -2143,21 +2143,6 @@ static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna) b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRPHYCTL, tmp); } -/* Returns TRUE, if the radio is enabled in hardware. */ -static bool b43_is_hw_radio_enabled(struct b43_wldev *dev) -{ - if (dev->phy.rev >= 3) { - if (!(b43_read32(dev, B43_MMIO_RADIO_HWENABLED_HI) - & B43_MMIO_RADIO_HWENABLED_HI_MASK)) - return 1; - } else { - if (b43_read16(dev, B43_MMIO_RADIO_HWENABLED_LO) - & B43_MMIO_RADIO_HWENABLED_LO_MASK) - return 1; - } - return 0; -} - /* This is the opposite of b43_chip_init() */ static void b43_chip_exit(struct b43_wldev *dev) { @@ -2350,32 +2335,18 @@ static void b43_periodic_every15sec(struct b43_wldev *dev) //TODO for APHY (temperature?) } -static void b43_periodic_every1sec(struct b43_wldev *dev) -{ - bool radio_hw_enable; - - /* check if radio hardware enabled status changed */ - radio_hw_enable = b43_is_hw_radio_enabled(dev); - if (unlikely(dev->radio_hw_enable != radio_hw_enable)) { - dev->radio_hw_enable = radio_hw_enable; - b43_rfkill_toggled(dev, radio_hw_enable); - } -} - static void do_periodic_work(struct b43_wldev *dev) { unsigned int state; state = dev->periodic_state; - if (state % 120 == 0) + if (state % 8 == 0) b43_periodic_every120sec(dev); - if (state % 60 == 0) + if (state % 4 == 0) b43_periodic_every60sec(dev); - if (state % 30 == 0) + if (state % 2 == 0) b43_periodic_every30sec(dev); - if (state % 15 == 0) - b43_periodic_every15sec(dev); - b43_periodic_every1sec(dev); + b43_periodic_every15sec(dev); } /* Estimate a "Badness" value based on the periodic work @@ -2386,13 +2357,11 @@ static int estimate_periodic_work_badness(unsigned int state) { int badness = 0; - if (state % 120 == 0) /* every 120 sec */ + if (state % 8 == 0) /* every 120 sec */ badness += 10; - if (state % 60 == 0) /* every 60 sec */ + if (state % 4 == 0) /* every 60 sec */ badness += 5; - if (state % 30 == 0) /* every 30 sec */ - badness += 1; - if (state % 15 == 0) /* every 15 sec */ + if (state % 2 == 0) /* every 30 sec */ badness += 1; #define BADNESS_LIMIT 4 @@ -2443,13 +2412,13 @@ static void b43_periodic_work_handler(struct work_struct *work) spin_unlock_irqrestore(&dev->wl->irq_lock, flags); } dev->periodic_state++; - out_requeue: +out_requeue: if (b43_debug(dev, B43_DBG_PWORK_FAST)) delay = msecs_to_jiffies(50); else - delay = round_jiffies(HZ); + delay = round_jiffies(HZ * 15); queue_delayed_work(dev->wl->hw->workqueue, &dev->periodic_work, delay); - out: +out: mutex_unlock(&dev->wl->mutex); } @@ -3720,6 +3689,7 @@ static int b43_setup_modes(struct b43_wldev *dev, static void b43_wireless_core_detach(struct b43_wldev *dev) { + b43_rfkill_free(dev); /* We release firmware that late to not be required to re-request * is all the time when we reinit the core. */ b43_release_firmware(dev); @@ -3805,6 +3775,7 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) if (!wl->current_dev) wl->current_dev = dev; INIT_WORK(&dev->restart_work, b43_chip_reset); + b43_rfkill_alloc(dev); b43_radio_turn_off(dev, 1); b43_switch_analog(dev, 0); diff --git a/drivers/net/wireless/b43/rfkill.c b/drivers/net/wireless/b43/rfkill.c index c25fd9956a9..800e0a61a7f 100644 --- a/drivers/net/wireless/b43/rfkill.c +++ b/drivers/net/wireless/b43/rfkill.c @@ -26,46 +26,39 @@ #include "b43.h" -static void b43_notify_rfkill_press(struct work_struct *work) +/* Returns TRUE, if the radio is enabled in hardware. */ +static bool b43_is_hw_radio_enabled(struct b43_wldev *dev) { - struct b43_rfkill *rfk = container_of(work, struct b43_rfkill, - notify_work); - struct b43_wl *wl = container_of(rfk, struct b43_wl, rfkill); - struct b43_wldev *dev; - enum rfkill_state state; - - mutex_lock(&wl->mutex); - dev = wl->current_dev; - if (b43_status(dev) < B43_STAT_INITIALIZED) { - mutex_unlock(&wl->mutex); - return; - } - if (dev->radio_hw_enable) - state = RFKILL_STATE_ON; - else - state = RFKILL_STATE_OFF; - b43info(wl, "Radio hardware status changed to %s\n", - dev->radio_hw_enable ? "ENABLED" : "DISABLED"); - mutex_unlock(&wl->mutex); - - if (rfk->rfkill) { - /* Be careful. This calls back into the software toggle routines. - * So we must unlock before calling. */ - rfkill_switch_all(rfk->rfkill->type, state); + if (dev->phy.rev >= 3) { + if (!(b43_read32(dev, B43_MMIO_RADIO_HWENABLED_HI) + & B43_MMIO_RADIO_HWENABLED_HI_MASK)) + return 1; + } else { + if (b43_read16(dev, B43_MMIO_RADIO_HWENABLED_LO) + & B43_MMIO_RADIO_HWENABLED_LO_MASK) + return 1; } + return 0; } -/* Called when the RFKILL toggled in hardware. - * This is called with the mutex locked. */ -void b43_rfkill_toggled(struct b43_wldev *dev, bool on) +/* The poll callback for the hardware button. */ +static void b43_rfkill_poll(struct input_polled_dev *poll_dev) { + struct b43_wldev *dev = poll_dev->private; struct b43_wl *wl = dev->wl; + bool enabled; + mutex_lock(&wl->mutex); B43_WARN_ON(b43_status(dev) < B43_STAT_INITIALIZED); - /* Update the RF status asynchronously, as rfkill will - * call back into the software toggle handler. - * This would deadlock if done synchronously. */ - queue_work(wl->hw->workqueue, &wl->rfkill.notify_work); + enabled = b43_is_hw_radio_enabled(dev); + if (unlikely(enabled != dev->radio_hw_enable)) { + dev->radio_hw_enable = enabled; + b43info(wl, "Radio hardware status changed to %s\n", + enabled ? "ENABLED" : "DISABLED"); + mutex_unlock(&wl->mutex); + input_report_key(poll_dev->input, KEY_WLAN, enabled); + } else + mutex_unlock(&wl->mutex); } /* Called when the RFKILL toggled in software. @@ -118,38 +111,74 @@ void b43_rfkill_init(struct b43_wldev *dev) struct b43_rfkill *rfk = &(wl->rfkill); int err; + if (rfk->rfkill) { + err = rfkill_register(rfk->rfkill); + if (err) { + b43warn(wl, "Failed to register RF-kill button\n"); + goto err_free_rfk; + } + } + if (rfk->poll_dev) { + err = input_register_polled_device(rfk->poll_dev); + if (err) { + b43warn(wl, "Failed to register RF-kill polldev\n"); + goto err_free_polldev; + } + } + + return; +err_free_rfk: + rfkill_free(rfk->rfkill); + rfk->rfkill = NULL; +err_free_polldev: + input_free_polled_device(rfk->poll_dev); + rfk->poll_dev = NULL; +} + +void b43_rfkill_exit(struct b43_wldev *dev) +{ + struct b43_rfkill *rfk = &(dev->wl->rfkill); + + if (rfk->poll_dev) + input_unregister_polled_device(rfk->poll_dev); + if (rfk->rfkill) + rfkill_unregister(rfk->rfkill); +} + +void b43_rfkill_alloc(struct b43_wldev *dev) +{ + struct b43_wl *wl = dev->wl; + struct b43_rfkill *rfk = &(wl->rfkill); + snprintf(rfk->name, sizeof(rfk->name), "b43-%s", wiphy_name(wl->hw->wiphy)); + rfk->rfkill = rfkill_allocate(dev->dev->dev, RFKILL_TYPE_WLAN); - if (!rfk->rfkill) - goto error; + if (!rfk->rfkill) { + b43warn(wl, "Failed to allocate RF-kill button\n"); + return; + } rfk->rfkill->name = rfk->name; rfk->rfkill->state = RFKILL_STATE_ON; rfk->rfkill->data = dev; rfk->rfkill->toggle_radio = b43_rfkill_soft_toggle; rfk->rfkill->user_claim_unsupported = 1; - INIT_WORK(&rfk->notify_work, b43_notify_rfkill_press); - - err = rfkill_register(rfk->rfkill); - if (err) - goto error; - - return; -error: - b43warn(dev->wl, "Failed to initialize the RF-kill button\n"); - rfkill_free(rfk->rfkill); - rfk->rfkill = NULL; + rfk->poll_dev = input_allocate_polled_device(); + if (rfk->poll_dev) { + rfk->poll_dev->private = dev; + rfk->poll_dev->poll = b43_rfkill_poll; + rfk->poll_dev->poll_interval = 1000; /* msecs */ + } else + b43warn(wl, "Failed to allocate RF-kill polldev\n"); } -void b43_rfkill_exit(struct b43_wldev *dev) +void b43_rfkill_free(struct b43_wldev *dev) { struct b43_rfkill *rfk = &(dev->wl->rfkill); - if (!rfk->rfkill) - return; - cancel_work_sync(&rfk->notify_work); - rfkill_unregister(rfk->rfkill); + input_free_polled_device(rfk->poll_dev); + rfk->poll_dev = NULL; rfkill_free(rfk->rfkill); rfk->rfkill = NULL; } diff --git a/drivers/net/wireless/b43/rfkill.h b/drivers/net/wireless/b43/rfkill.h index 05db0d67a92..29544e8c9e5 100644 --- a/drivers/net/wireless/b43/rfkill.h +++ b/drivers/net/wireless/b43/rfkill.h @@ -7,19 +7,25 @@ struct b43_wldev; #ifdef CONFIG_B43_RFKILL #include +#include + struct b43_rfkill { /* The RFKILL subsystem data structure */ struct rfkill *rfkill; + /* The poll device for the RFKILL input button */ + struct input_polled_dev *poll_dev; /* The unique name of this rfkill switch */ char name[32]; - /* Workqueue for asynchronous notification. */ - struct work_struct notify_work; }; +/* All the init functions return void, because we are not interested + * in failing the b43 init process when rfkill init failed. */ +void b43_rfkill_alloc(struct b43_wldev *dev); +void b43_rfkill_free(struct b43_wldev *dev); void b43_rfkill_init(struct b43_wldev *dev); void b43_rfkill_exit(struct b43_wldev *dev); -void b43_rfkill_toggled(struct b43_wldev *dev, bool on); + char * b43_rfkill_led_name(struct b43_wldev *dev); @@ -30,13 +36,16 @@ struct b43_rfkill { /* empty */ }; -static inline void b43_rfkill_init(struct b43_wldev *dev) +static inline void b43_rfkill_alloc(struct b43_wldev *dev) { } -static inline void b43_rfkill_exit(struct b43_wldev *dev) +static inline void b43_rfkill_free(struct b43_wldev *dev) { } -static inline void b43_rfkill_toggled(struct b43_wldev *dev, bool on) +static inline void b43_rfkill_init(struct b43_wldev *dev) +{ +} +static inline void b43_rfkill_exit(struct b43_wldev *dev) { } static inline char * b43_rfkill_led_name(struct b43_wldev *dev) -- cgit v1.2.3-70-g09d2 From 05b64b364822863974c0121359b01d7ba0f22205 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 28 Sep 2007 16:19:03 +0200 Subject: [B43]: Rewrite pwork locking policy. Implement much easier and more lightweight locking for the periodic work. This also removes the last big busywait loop and replaces it by a sleeping loop. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/b43/main.c | 88 +++++++++++++++-------------------------- 1 file changed, 32 insertions(+), 56 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index a603a154d49..6c80f2e2f4e 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -1976,6 +1976,7 @@ void b43_mac_enable(struct b43_wldev *dev) { dev->mac_suspended--; B43_WARN_ON(dev->mac_suspended < 0); + B43_WARN_ON(irqs_disabled()); if (dev->mac_suspended == 0) { b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL) @@ -1986,6 +1987,11 @@ void b43_mac_enable(struct b43_wldev *dev) b43_read32(dev, B43_MMIO_MACCTL); b43_read32(dev, B43_MMIO_GEN_IRQ_REASON); b43_power_saving_ctl_bits(dev, 0); + + /* Re-enable IRQs. */ + spin_lock_irq(&dev->wl->irq_lock); + b43_interrupt_enable(dev, dev->irq_savedstate); + spin_unlock_irq(&dev->wl->irq_lock); } } @@ -1995,23 +2001,34 @@ void b43_mac_suspend(struct b43_wldev *dev) int i; u32 tmp; + might_sleep(); + B43_WARN_ON(irqs_disabled()); B43_WARN_ON(dev->mac_suspended < 0); + if (dev->mac_suspended == 0) { + /* Mask IRQs before suspending MAC. Otherwise + * the MAC stays busy and won't suspend. */ + spin_lock_irq(&dev->wl->irq_lock); + tmp = b43_interrupt_disable(dev, B43_IRQ_ALL); + spin_unlock_irq(&dev->wl->irq_lock); + b43_synchronize_irq(dev); + dev->irq_savedstate = tmp; + b43_power_saving_ctl_bits(dev, B43_PS_AWAKE); b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL) & ~B43_MACCTL_ENABLED); /* force pci to flush the write */ b43_read32(dev, B43_MMIO_MACCTL); - for (i = 10000; i; i--) { + for (i = 40; i; i--) { tmp = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON); if (tmp & B43_IRQ_MAC_SUSPENDED) goto out; - udelay(1); + msleep(1); } b43err(dev->wl, "MAC suspend failed\n"); } - out: +out: dev->mac_suspended++; } @@ -2349,77 +2366,36 @@ static void do_periodic_work(struct b43_wldev *dev) b43_periodic_every15sec(dev); } -/* Estimate a "Badness" value based on the periodic work - * state-machine state. "Badness" is worse (bigger), if the - * periodic work will take longer. +/* Periodic work locking policy: + * The whole periodic work handler is protected by + * wl->mutex. If another lock is needed somewhere in the + * pwork callchain, it's aquired in-place, where it's needed. */ -static int estimate_periodic_work_badness(unsigned int state) -{ - int badness = 0; - - if (state % 8 == 0) /* every 120 sec */ - badness += 10; - if (state % 4 == 0) /* every 60 sec */ - badness += 5; - if (state % 2 == 0) /* every 30 sec */ - badness += 1; - -#define BADNESS_LIMIT 4 - return badness; -} - static void b43_periodic_work_handler(struct work_struct *work) { - struct b43_wldev *dev = - container_of(work, struct b43_wldev, periodic_work.work); - unsigned long flags, delay; - u32 savedirqs = 0; - int badness; + struct b43_wldev *dev = container_of(work, struct b43_wldev, + periodic_work.work); + struct b43_wl *wl = dev->wl; + unsigned long delay; - mutex_lock(&dev->wl->mutex); + mutex_lock(&wl->mutex); if (unlikely(b43_status(dev) != B43_STAT_STARTED)) goto out; if (b43_debug(dev, B43_DBG_PWORK_STOP)) goto out_requeue; - badness = estimate_periodic_work_badness(dev->periodic_state); - if (badness > BADNESS_LIMIT) { - spin_lock_irqsave(&dev->wl->irq_lock, flags); - /* Suspend TX as we don't want to transmit packets while - * we recalibrate the hardware. */ - b43_tx_suspend(dev); - savedirqs = b43_interrupt_disable(dev, B43_IRQ_ALL); - /* Periodic work will take a long time, so we want it to - * be preemtible and release the spinlock. */ - spin_unlock_irqrestore(&dev->wl->irq_lock, flags); - b43_synchronize_irq(dev); - - do_periodic_work(dev); - - spin_lock_irqsave(&dev->wl->irq_lock, flags); - b43_interrupt_enable(dev, savedirqs); - b43_tx_resume(dev); - mmiowb(); - spin_unlock_irqrestore(&dev->wl->irq_lock, flags); - } else { - /* Take the global driver lock. This will lock any operation. */ - spin_lock_irqsave(&dev->wl->irq_lock, flags); - - do_periodic_work(dev); + do_periodic_work(dev); - mmiowb(); - spin_unlock_irqrestore(&dev->wl->irq_lock, flags); - } dev->periodic_state++; out_requeue: if (b43_debug(dev, B43_DBG_PWORK_FAST)) delay = msecs_to_jiffies(50); else delay = round_jiffies(HZ * 15); - queue_delayed_work(dev->wl->hw->workqueue, &dev->periodic_work, delay); + queue_delayed_work(wl->hw->workqueue, &dev->periodic_work, delay); out: - mutex_unlock(&dev->wl->mutex); + mutex_unlock(&wl->mutex); } static void b43_periodic_tasks_setup(struct b43_wldev *dev) -- cgit v1.2.3-70-g09d2 From a28975525016ddcbdaab8225666df1cf2dc9cb2d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 28 Sep 2007 14:01:25 +0200 Subject: [MAC80211]: add "invalid" interface type Since I cannot convince the lazy driver authors (hello Michael) to stop (ab)using the MGMT interface type internally in their drivers, this patch introduces a new _INVALID type especially for their use and changes all affected drivers to use it. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/adm8211.c | 8 ++++---- drivers/net/wireless/p54common.c | 4 ++-- drivers/net/wireless/p54pci.c | 4 ++-- drivers/net/wireless/rt2x00/rt2x00.h | 2 +- include/net/mac80211.h | 3 +++ net/mac80211/ieee80211.c | 4 ++++ net/mac80211/ieee80211_iface.c | 4 ++++ net/mac80211/rx.c | 1 + 8 files changed, 21 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index e4fdadb5250..5bf7913aadd 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -1555,7 +1555,7 @@ static void adm8211_stop(struct ieee80211_hw *dev) { struct adm8211_priv *priv = dev->priv; - priv->mode = IEEE80211_IF_TYPE_MGMT; + priv->mode = IEEE80211_IF_TYPE_INVALID; priv->nar = 0; ADM8211_CSR_WRITE(NAR, 0); ADM8211_CSR_WRITE(IER, 0); @@ -1898,7 +1898,7 @@ static int __devinit adm8211_probe(struct pci_dev *pdev, priv->tx_power = 0x40; priv->lpf_cutoff = 0xFF; priv->lnags_threshold = 0xFF; - priv->mode = IEEE80211_IF_TYPE_MGMT; + priv->mode = IEEE80211_IF_TYPE_INVALID; /* Power-on issue. EEPROM won't read correctly without */ if (pdev->revision >= ADM8211_REV_BA) { @@ -1993,7 +1993,7 @@ static int adm8211_suspend(struct pci_dev *pdev, pm_message_t state) struct ieee80211_hw *dev = pci_get_drvdata(pdev); struct adm8211_priv *priv = dev->priv; - if (priv->mode != IEEE80211_IF_TYPE_MGMT) { + if (priv->mode != IEEE80211_IF_TYPE_INVALID) { ieee80211_stop_queues(dev); adm8211_stop(dev); } @@ -2011,7 +2011,7 @@ static int adm8211_resume(struct pci_dev *pdev) pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); - if (priv->mode != IEEE80211_IF_TYPE_MGMT) { + if (priv->mode != IEEE80211_IF_TYPE_INVALID) { adm8211_start(dev); ieee80211_start_queues(dev); } diff --git a/drivers/net/wireless/p54common.c b/drivers/net/wireless/p54common.c index 9befd6cc791..2c63cf0ad2c 100644 --- a/drivers/net/wireless/p54common.c +++ b/drivers/net/wireless/p54common.c @@ -797,7 +797,7 @@ static void p54_stop(struct ieee80211_hw *dev) kfree_skb(skb); } priv->stop(dev); - priv->mode = IEEE80211_IF_TYPE_MGMT; + priv->mode = IEEE80211_IF_TYPE_INVALID; } static int p54_add_interface(struct ieee80211_hw *dev, @@ -949,7 +949,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) return NULL; priv = dev->priv; - priv->mode = IEEE80211_IF_TYPE_MGMT; + priv->mode = IEEE80211_IF_TYPE_INVALID; skb_queue_head_init(&priv->tx_queue); memcpy(priv->channels, p54_channels, sizeof(p54_channels)); memcpy(priv->rates, p54_rates, sizeof(p54_rates)); diff --git a/drivers/net/wireless/p54pci.c b/drivers/net/wireless/p54pci.c index 75927583f76..410b54387f2 100644 --- a/drivers/net/wireless/p54pci.c +++ b/drivers/net/wireless/p54pci.c @@ -640,7 +640,7 @@ static int p54p_suspend(struct pci_dev *pdev, pm_message_t state) struct ieee80211_hw *dev = pci_get_drvdata(pdev); struct p54p_priv *priv = dev->priv; - if (priv->common.mode != IEEE80211_IF_TYPE_MGMT) { + if (priv->common.mode != IEEE80211_IF_TYPE_INVALID) { ieee80211_stop_queues(dev); p54p_stop(dev); } @@ -658,7 +658,7 @@ static int p54p_resume(struct pci_dev *pdev) pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); - if (priv->common.mode != IEEE80211_IF_TYPE_MGMT) { + if (priv->common.mode != IEEE80211_IF_TYPE_INVALID) { p54p_open(dev); ieee80211_start_queues(dev); } diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 511c11c4edd..6262d4e47c5 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -297,7 +297,7 @@ struct interface { * When set to INVALID_INTERFACE, no interface is configured. */ int type; -#define INVALID_INTERFACE IEEE80211_IF_TYPE_MGMT +#define INVALID_INTERFACE IEEE80211_IF_TYPE_INVALID /* * MAC of the device. diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 6ec12bd3a3e..bd72f59e98f 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -457,6 +457,8 @@ struct ieee80211_conf { /** * enum ieee80211_if_types - types of 802.11 network interfaces * + * @IEEE80211_IF_TYPE_INVALID: invalid interface type, not used + * by mac80211 itself * @IEEE80211_IF_TYPE_AP: interface in AP mode. * @IEEE80211_IF_TYPE_MGMT: special interface for communication with hostap * daemon. Drivers should never see this type. @@ -468,6 +470,7 @@ struct ieee80211_conf { * will never see this type. */ enum ieee80211_if_types { + IEEE80211_IF_TYPE_INVALID, IEEE80211_IF_TYPE_AP, IEEE80211_IF_TYPE_MGMT, IEEE80211_IF_TYPE_STA, diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 62877a8f9f0..373e8b72878 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -351,6 +351,10 @@ static int ieee80211_open(struct net_device *dev) case IEEE80211_IF_TYPE_IBSS: /* no special treatment */ break; + case IEEE80211_IF_TYPE_INVALID: + /* cannot happen */ + WARN_ON(1); + break; } if (local->open_count == 0) { diff --git a/net/mac80211/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c index 08c1e188d4b..ef618e947e2 100644 --- a/net/mac80211/ieee80211_iface.c +++ b/net/mac80211/ieee80211_iface.c @@ -243,6 +243,10 @@ void ieee80211_if_reinit(struct net_device *dev) ieee80211_if_sdata_deinit(sdata); switch (sdata->type) { + case IEEE80211_IF_TYPE_INVALID: + /* cannot happen */ + WARN_ON(1); + break; case IEEE80211_IF_TYPE_MGMT: /* nothing to do */ break; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 03635fb3e9b..b4a62fe3ccb 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1453,6 +1453,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, case IEEE80211_IF_TYPE_MNTR: /* take everything */ break; + case IEEE80211_IF_TYPE_INVALID: case IEEE80211_IF_TYPE_MGMT: /* should never get here */ WARN_ON(1); -- cgit v1.2.3-70-g09d2 From 628a140ba033ef201706a8c7e767c8a0c0f8326c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 26 Sep 2007 17:53:17 +0200 Subject: [MAC80211]: remove ALG_NONE This "algorithm" is used only internally and is not useful. Signed-off-by: Johannes Berg Cc: Michael Buesch Acked-by: Zhu Yi Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/b43/main.c | 3 --- drivers/net/wireless/iwlwifi/iwl3945-base.c | 4 ---- drivers/net/wireless/iwlwifi/iwl4965-base.c | 4 ---- include/net/mac80211.h | 2 -- net/mac80211/ieee80211_ioctl.c | 19 +++++++++++-------- net/mac80211/key.c | 1 - net/mac80211/rx.c | 3 --- net/mac80211/tx.c | 2 -- 8 files changed, 11 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 6c80f2e2f4e..c141a264ac4 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -2827,9 +2827,6 @@ static int b43_dev_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, if (!dev) return -ENODEV; switch (key->alg) { - case ALG_NONE: - algorithm = B43_SEC_ALGO_NONE; - break; case ALG_WEP: if (key->keylen == 5) algorithm = B43_SEC_ALGO_WEP40; diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 2cd7caa69e4..75e3b5c3f15 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -2579,10 +2579,6 @@ static void iwl_build_tx_cmd_hwcrypto(struct iwl_priv *priv, "with key %d\n", ctl->key_idx); break; - case ALG_NONE: - IWL_DEBUG_TX("Tx packet in the clear (encrypt requested).\n"); - break; - default: printk(KERN_ERR "Unknown encode alg %d\n", keyinfo->alg); break; diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 5a8342664af..b1a6e39f782 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -2663,10 +2663,6 @@ static void iwl_build_tx_cmd_hwcrypto(struct iwl_priv *priv, "with key %d\n", ctl->key_idx); break; - case ALG_NONE: - IWL_DEBUG_TX("Tx packet in the clear (encrypt requested).\n"); - break; - default: printk(KERN_ERR "Unknown encode alg %d\n", keyinfo->alg); break; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index c143ac8965d..1a2114b8d22 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -541,13 +541,11 @@ struct ieee80211_if_conf { /** * enum ieee80211_key_alg - key algorithm - * @ALG_NONE: Unset key algorithm, will never be passed to the driver * @ALG_WEP: WEP40 or WEP104 * @ALG_TKIP: TKIP * @ALG_CCMP: CCMP (AES) */ enum ieee80211_key_alg { - ALG_NONE, ALG_WEP, ALG_TKIP, ALG_CCMP, diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index 48e68434b38..6c8e73e0d29 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c @@ -27,8 +27,9 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, - int idx, int alg, int set_tx_key, - const u8 *_key, size_t key_len) + int idx, int alg, int remove, + int set_tx_key, const u8 *_key, + size_t key_len) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); int ret = 0; @@ -75,7 +76,7 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, key = sta->key; } - if (alg == ALG_NONE) { + if (remove) { ieee80211_key_free(key); key = NULL; } else { @@ -827,6 +828,7 @@ static int ieee80211_ioctl_siwencode(struct net_device *dev, struct ieee80211_sub_if_data *sdata; int idx, i, alg = ALG_WEP; u8 bcaddr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + int remove = 0; sdata = IEEE80211_DEV_TO_SUB_IF(dev); @@ -845,7 +847,7 @@ static int ieee80211_ioctl_siwencode(struct net_device *dev, idx--; if (erq->flags & IW_ENCODE_DISABLED) - alg = ALG_NONE; + remove = 1; else if (erq->length == 0) { /* No key data - just set the default TX key index */ ieee80211_set_default_key(sdata, idx); @@ -854,7 +856,7 @@ static int ieee80211_ioctl_siwencode(struct net_device *dev, return ieee80211_set_encryption( dev, bcaddr, - idx, alg, + idx, alg, remove, !sdata->default_key, keybuf, erq->length); } @@ -1005,11 +1007,11 @@ static int ieee80211_ioctl_siwencodeext(struct net_device *dev, { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; - int alg, idx, i; + int uninitialized_var(alg), idx, i, remove = 0; switch (ext->alg) { case IW_ENCODE_ALG_NONE: - alg = ALG_NONE; + remove = 1; break; case IW_ENCODE_ALG_WEP: alg = ALG_WEP; @@ -1025,7 +1027,7 @@ static int ieee80211_ioctl_siwencodeext(struct net_device *dev, } if (erq->flags & IW_ENCODE_DISABLED) - alg = ALG_NONE; + remove = 1; idx = erq->flags & IW_ENCODE_INDEX; if (idx < 1 || idx > 4) { @@ -1044,6 +1046,7 @@ static int ieee80211_ioctl_siwencodeext(struct net_device *dev, idx--; return ieee80211_set_encryption(dev, ext->addr.sa_data, idx, alg, + remove, ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY, ext->key, ext->key_len); diff --git a/net/mac80211/key.c b/net/mac80211/key.c index f13d46b2c13..0b2328f7d67 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -121,7 +121,6 @@ struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata, struct ieee80211_key *key; BUG_ON(idx < 0 || idx >= NUM_DEFAULT_KEYS); - BUG_ON(alg == ALG_NONE); key = kzalloc(sizeof(struct ieee80211_key) + key_len, GFP_KERNEL); if (!key) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index f5caa1a016e..8c16574ec39 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -532,9 +532,6 @@ ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx) return ieee80211_crypto_tkip_decrypt(rx); case ALG_CCMP: return ieee80211_crypto_ccmp_decrypt(rx); - case ALG_NONE: - WARN_ON(1); - return TXRX_CONTINUE; } /* not reached */ diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 8f0007a925a..47416b0645d 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -554,8 +554,6 @@ ieee80211_tx_h_encrypt(struct ieee80211_txrx_data *tx) return ieee80211_crypto_tkip_encrypt(tx); case ALG_CCMP: return ieee80211_crypto_ccmp_encrypt(tx); - case ALG_NONE: - return TXRX_CONTINUE; } /* not reached */ -- cgit v1.2.3-70-g09d2 From 69c29d89185dc1de7224f5f98588ddc061f1fad2 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Tue, 2 Oct 2007 16:24:51 -0500 Subject: pasemi_mac: basic error checking pasemi_mac: basic error checking Add some rudimentary error checking to pasemi_mac. Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik --- drivers/net/pasemi_mac.c | 46 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index c2d34a804d4..b297a67d2fb 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -445,6 +445,38 @@ static void pasemi_mac_restart_tx_intr(struct pasemi_mac *mac) } +static inline void pasemi_mac_rx_error(struct pasemi_mac *mac, u64 macrx) +{ + unsigned int rcmdsta, ccmdsta; + + if (!netif_msg_rx_err(mac)) + return; + + rcmdsta = read_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if)); + ccmdsta = read_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch)); + + printk(KERN_ERR "pasemi_mac: rx error. macrx %016lx, rx status %lx\n", + macrx, *mac->rx_status); + + printk(KERN_ERR "pasemi_mac: rcmdsta %08x ccmdsta %08x\n", + rcmdsta, ccmdsta); +} + +static inline void pasemi_mac_tx_error(struct pasemi_mac *mac, u64 mactx) +{ + unsigned int cmdsta; + + if (!netif_msg_tx_err(mac)) + return; + + cmdsta = read_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch)); + + printk(KERN_ERR "pasemi_mac: tx error. mactx 0x%016lx, "\ + "tx status 0x%016lx\n", mactx, *mac->tx_status); + + printk(KERN_ERR "pasemi_mac: tcmdsta 0x%08x\n", cmdsta); +} + static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) { unsigned int n; @@ -468,10 +500,13 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) prefetchw(dp); macrx = dp->macrx; + if ((macrx & XCT_MACRX_E) || + (*mac->rx_status & PAS_STATUS_ERROR)) + pasemi_mac_rx_error(mac, macrx); + if (!(macrx & XCT_MACRX_O)) break; - info = NULL; /* We have to scan for our skb since there's no way @@ -563,6 +598,10 @@ restart: for (i = start; i < limit; i++) { dp = &TX_DESC(mac, i); + if ((dp->mactx & XCT_MACTX_E) || + (*mac->tx_status & PAS_STATUS_ERROR)) + pasemi_mac_tx_error(mac, dp->mactx); + if (unlikely(dp->mactx & XCT_MACTX_O)) /* Not yet transmitted */ break; @@ -607,9 +646,6 @@ static irqreturn_t pasemi_mac_rx_intr(int irq, void *data) if (!(*mac->rx_status & PAS_STATUS_CAUSE_M)) return IRQ_NONE; - if (*mac->rx_status & PAS_STATUS_ERROR) - printk("rx_status reported error\n"); - /* Don't reset packet count so it won't fire again but clear * all others. */ @@ -1230,7 +1266,7 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) dev_err(&mac->pdev->dev, "register_netdev failed with error %d\n", err); goto out; - } else + } else if netif_msg_probe(mac) printk(KERN_INFO "%s: PA Semi %s: intf %d, txch %d, rxch %d, " "hw addr %s\n", dev->name, mac->type == MAC_TYPE_GMAC ? "GMAC" : "XAUI", -- cgit v1.2.3-70-g09d2 From 18eec695427ce1258fb5dad0ac180fa4d6f64af7 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Tue, 2 Oct 2007 16:25:14 -0500 Subject: pasemi_mac: fix bug in receive buffer dma mapping pasemi_mac: fix bug in receive buffer dma mapping skb->len isn't actually set to the size of the allocated skb, so don't try to use it when figuring out how much to map. (This hasn't surfaced as a real bug because we effectively disable translation for the interface, but it still needs fixing for the future) Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik --- drivers/net/pasemi_mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index b297a67d2fb..b2861e0df86 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -396,7 +396,7 @@ static void pasemi_mac_replenish_rx_ring(struct net_device *dev, int limit) if (unlikely(!skb)) break; - dma = pci_map_single(mac->dma_pdev, skb->data, skb->len, + dma = pci_map_single(mac->dma_pdev, skb->data, BUF_SIZE, PCI_DMA_FROMDEVICE); if (unlikely(dma_mapping_error(dma))) { -- cgit v1.2.3-70-g09d2 From fc9e4d2a93dab4a995e2e75725577b9a60154cbc Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Tue, 2 Oct 2007 16:25:53 -0500 Subject: pasemi_mac: rework ring management pasemi_mac: rework ring management Rework ring management, switching to an opaque ring format instead of the struct-based descriptor+pointer setup, since it will be needed for SG support. Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik --- drivers/net/pasemi_mac.c | 213 +++++++++++++++++++++++------------------------ drivers/net/pasemi_mac.h | 23 ++--- 2 files changed, 108 insertions(+), 128 deletions(-) (limited to 'drivers') diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index b2861e0df86..c2a3524a541 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -63,10 +63,10 @@ NETIF_MSG_RX_ERR | \ NETIF_MSG_TX_ERR) -#define TX_DESC(mac, num) ((mac)->tx->desc[(num) & (TX_RING_SIZE-1)]) -#define TX_DESC_INFO(mac, num) ((mac)->tx->desc_info[(num) & (TX_RING_SIZE-1)]) -#define RX_DESC(mac, num) ((mac)->rx->desc[(num) & (RX_RING_SIZE-1)]) -#define RX_DESC_INFO(mac, num) ((mac)->rx->desc_info[(num) & (RX_RING_SIZE-1)]) +#define TX_RING(mac, num) ((mac)->tx->ring[(num) & (TX_RING_SIZE-1)]) +#define TX_RING_INFO(mac, num) ((mac)->tx->ring_info[(num) & (TX_RING_SIZE-1)]) +#define RX_RING(mac, num) ((mac)->rx->ring[(num) & (RX_RING_SIZE-1)]) +#define RX_RING_INFO(mac, num) ((mac)->rx->ring_info[(num) & (RX_RING_SIZE-1)]) #define RX_BUFF(mac, num) ((mac)->rx->buffers[(num) & (RX_RING_SIZE-1)]) #define RING_USED(ring) (((ring)->next_to_fill - (ring)->next_to_clean) \ @@ -174,22 +174,21 @@ static int pasemi_mac_setup_rx_resources(struct net_device *dev) spin_lock_init(&ring->lock); ring->size = RX_RING_SIZE; - ring->desc_info = kzalloc(sizeof(struct pasemi_mac_buffer) * + ring->ring_info = kzalloc(sizeof(struct pasemi_mac_buffer) * RX_RING_SIZE, GFP_KERNEL); - if (!ring->desc_info) - goto out_desc_info; + if (!ring->ring_info) + goto out_ring_info; /* Allocate descriptors */ - ring->desc = dma_alloc_coherent(&mac->dma_pdev->dev, - RX_RING_SIZE * - sizeof(struct pas_dma_xct_descr), + ring->ring = dma_alloc_coherent(&mac->dma_pdev->dev, + RX_RING_SIZE * sizeof(u64), &ring->dma, GFP_KERNEL); - if (!ring->desc) - goto out_desc; + if (!ring->ring) + goto out_ring_desc; - memset(ring->desc, 0, RX_RING_SIZE * sizeof(struct pas_dma_xct_descr)); + memset(ring->ring, 0, RX_RING_SIZE * sizeof(u64)); ring->buffers = dma_alloc_coherent(&mac->dma_pdev->dev, RX_RING_SIZE * sizeof(u64), @@ -203,7 +202,7 @@ static int pasemi_mac_setup_rx_resources(struct net_device *dev) write_dma_reg(mac, PAS_DMA_RXCHAN_BASEU(chan_id), PAS_DMA_RXCHAN_BASEU_BRBH(ring->dma >> 32) | - PAS_DMA_RXCHAN_BASEU_SIZ(RX_RING_SIZE >> 2)); + PAS_DMA_RXCHAN_BASEU_SIZ(RX_RING_SIZE >> 3)); write_dma_reg(mac, PAS_DMA_RXCHAN_CFG(chan_id), PAS_DMA_RXCHAN_CFG_HBU(2)); @@ -229,11 +228,11 @@ static int pasemi_mac_setup_rx_resources(struct net_device *dev) out_buffers: dma_free_coherent(&mac->dma_pdev->dev, - RX_RING_SIZE * sizeof(struct pas_dma_xct_descr), - mac->rx->desc, mac->rx->dma); -out_desc: - kfree(ring->desc_info); -out_desc_info: + RX_RING_SIZE * sizeof(u64), + mac->rx->ring, mac->rx->dma); +out_ring_desc: + kfree(ring->ring_info); +out_ring_info: kfree(ring); out_ring: return -ENOMEM; @@ -254,25 +253,24 @@ static int pasemi_mac_setup_tx_resources(struct net_device *dev) spin_lock_init(&ring->lock); ring->size = TX_RING_SIZE; - ring->desc_info = kzalloc(sizeof(struct pasemi_mac_buffer) * + ring->ring_info = kzalloc(sizeof(struct pasemi_mac_buffer) * TX_RING_SIZE, GFP_KERNEL); - if (!ring->desc_info) - goto out_desc_info; + if (!ring->ring_info) + goto out_ring_info; /* Allocate descriptors */ - ring->desc = dma_alloc_coherent(&mac->dma_pdev->dev, - TX_RING_SIZE * - sizeof(struct pas_dma_xct_descr), + ring->ring = dma_alloc_coherent(&mac->dma_pdev->dev, + TX_RING_SIZE * sizeof(u64), &ring->dma, GFP_KERNEL); - if (!ring->desc) - goto out_desc; + if (!ring->ring) + goto out_ring_desc; - memset(ring->desc, 0, TX_RING_SIZE * sizeof(struct pas_dma_xct_descr)); + memset(ring->ring, 0, TX_RING_SIZE * sizeof(u64)); write_dma_reg(mac, PAS_DMA_TXCHAN_BASEL(chan_id), PAS_DMA_TXCHAN_BASEL_BRBL(ring->dma)); val = PAS_DMA_TXCHAN_BASEU_BRBH(ring->dma >> 32); - val |= PAS_DMA_TXCHAN_BASEU_SIZ(TX_RING_SIZE >> 2); + val |= PAS_DMA_TXCHAN_BASEU_SIZ(TX_RING_SIZE >> 3); write_dma_reg(mac, PAS_DMA_TXCHAN_BASEU(chan_id), val); @@ -291,9 +289,9 @@ static int pasemi_mac_setup_tx_resources(struct net_device *dev) return 0; -out_desc: - kfree(ring->desc_info); -out_desc_info: +out_ring_desc: + kfree(ring->ring_info); +out_ring_info: kfree(ring); out_ring: return -ENOMEM; @@ -304,31 +302,27 @@ static void pasemi_mac_free_tx_resources(struct net_device *dev) struct pasemi_mac *mac = netdev_priv(dev); unsigned int i; struct pasemi_mac_buffer *info; - struct pas_dma_xct_descr *dp; - - for (i = 0; i < TX_RING_SIZE; i++) { - info = &TX_DESC_INFO(mac, i); - dp = &TX_DESC(mac, i); - if (info->dma) { - if (info->skb) { - pci_unmap_single(mac->dma_pdev, - info->dma, - info->skb->len, - PCI_DMA_TODEVICE); - dev_kfree_skb_any(info->skb); - } - info->dma = 0; - info->skb = NULL; - dp->mactx = 0; - dp->ptr = 0; + + for (i = 0; i < TX_RING_SIZE; i += 2) { + info = &TX_RING_INFO(mac, i+1); + if (info->dma && info->skb) { + pci_unmap_single(mac->dma_pdev, + info->dma, + info->skb->len, + PCI_DMA_TODEVICE); + dev_kfree_skb_any(info->skb); } + TX_RING(mac, i) = 0; + TX_RING(mac, i+1) = 0; + info->dma = 0; + info->skb = NULL; } dma_free_coherent(&mac->dma_pdev->dev, - TX_RING_SIZE * sizeof(struct pas_dma_xct_descr), - mac->tx->desc, mac->tx->dma); + TX_RING_SIZE * sizeof(u64), + mac->tx->ring, mac->tx->dma); - kfree(mac->tx->desc_info); + kfree(mac->tx->ring_info); kfree(mac->tx); mac->tx = NULL; } @@ -338,34 +332,31 @@ static void pasemi_mac_free_rx_resources(struct net_device *dev) struct pasemi_mac *mac = netdev_priv(dev); unsigned int i; struct pasemi_mac_buffer *info; - struct pas_dma_xct_descr *dp; for (i = 0; i < RX_RING_SIZE; i++) { - info = &RX_DESC_INFO(mac, i); - dp = &RX_DESC(mac, i); - if (info->skb) { - if (info->dma) { - pci_unmap_single(mac->dma_pdev, - info->dma, - info->skb->len, - PCI_DMA_FROMDEVICE); - dev_kfree_skb_any(info->skb); - } - info->dma = 0; - info->skb = NULL; - dp->macrx = 0; - dp->ptr = 0; + info = &RX_RING_INFO(mac, i); + if (info->skb && info->dma) { + pci_unmap_single(mac->dma_pdev, + info->dma, + info->skb->len, + PCI_DMA_FROMDEVICE); + dev_kfree_skb_any(info->skb); } + info->dma = 0; + info->skb = NULL; } + for (i = 0; i < RX_RING_SIZE; i++) + RX_RING(mac, i) = 0; + dma_free_coherent(&mac->dma_pdev->dev, - RX_RING_SIZE * sizeof(struct pas_dma_xct_descr), - mac->rx->desc, mac->rx->dma); + RX_RING_SIZE * sizeof(u64), + mac->rx->ring, mac->rx->dma); dma_free_coherent(&mac->dma_pdev->dev, RX_RING_SIZE * sizeof(u64), mac->rx->buffers, mac->rx->buf_dma); - kfree(mac->rx->desc_info); + kfree(mac->rx->ring_info); kfree(mac->rx); mac->rx = NULL; } @@ -373,20 +364,22 @@ static void pasemi_mac_free_rx_resources(struct net_device *dev) static void pasemi_mac_replenish_rx_ring(struct net_device *dev, int limit) { struct pasemi_mac *mac = netdev_priv(dev); - unsigned int i; int start = mac->rx->next_to_fill; - int count; + unsigned int fill, count; if (limit <= 0) return; - i = start; + fill = start; for (count = 0; count < limit; count++) { - struct pasemi_mac_buffer *info = &RX_DESC_INFO(mac, i); - u64 *buff = &RX_BUFF(mac, i); + struct pasemi_mac_buffer *info = &RX_RING_INFO(mac, fill); + u64 *buff = &RX_BUFF(mac, fill); struct sk_buff *skb; dma_addr_t dma; + /* Entry in use? */ + WARN_ON(*buff); + /* skb might still be in there for recycle on short receives */ if (info->skb) skb = info->skb; @@ -407,7 +400,7 @@ static void pasemi_mac_replenish_rx_ring(struct net_device *dev, int limit) info->skb = skb; info->dma = dma; *buff = XCT_RXB_LEN(BUF_SIZE) | XCT_RXB_ADDR(dma); - i++; + fill++; } wmb(); @@ -481,7 +474,6 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) { unsigned int n; int count; - struct pas_dma_xct_descr *dp; struct pasemi_mac_buffer *info; struct sk_buff *skb; unsigned int i, len; @@ -496,9 +488,7 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) rmb(); - dp = &RX_DESC(mac, n); - prefetchw(dp); - macrx = dp->macrx; + macrx = RX_RING(mac, n); if ((macrx & XCT_MACRX_E) || (*mac->rx_status & PAS_STATUS_ERROR)) @@ -516,12 +506,15 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) * interface ring. */ - dma = (dp->ptr & XCT_PTR_ADDR_M); - for (i = n; i < (n + RX_RING_SIZE); i++) { - info = &RX_DESC_INFO(mac, i); + dma = (RX_RING(mac, n+1) & XCT_PTR_ADDR_M); + for (i = mac->rx->next_to_fill; + i < (mac->rx->next_to_fill + RX_RING_SIZE); + i++) { + info = &RX_RING_INFO(mac, i); if (info->dma == dma) break; } + prefetchw(info); skb = info->skb; @@ -546,6 +539,11 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) } else info->skb = NULL; + /* Need to zero it out since hardware doesn't, since the + * replenish loop uses it to tell when it's done. + */ + RX_BUFF(mac, i) = 0; + skb_put(skb, len); if (likely((macrx & XCT_MACRX_HTY_M) == XCT_MACRX_HTY_IPV4_OK)) { @@ -561,13 +559,13 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) skb->protocol = eth_type_trans(skb, mac->netdev); netif_receive_skb(skb); - dp->ptr = 0; - dp->macrx = 0; + RX_RING(mac, n) = 0; + RX_RING(mac, n+1) = 0; - n++; + n += 2; } - mac->rx->next_to_clean += limit - count; + mac->rx->next_to_clean = n; pasemi_mac_replenish_rx_ring(mac->netdev, limit-count); spin_unlock(&mac->rx->lock); @@ -579,7 +577,6 @@ static int pasemi_mac_clean_tx(struct pasemi_mac *mac) { int i; struct pasemi_mac_buffer *info; - struct pas_dma_xct_descr *dp; unsigned int start, count, limit; unsigned int total_count; unsigned long flags; @@ -595,29 +592,28 @@ restart: count = 0; - for (i = start; i < limit; i++) { - dp = &TX_DESC(mac, i); - - if ((dp->mactx & XCT_MACTX_E) || + for (i = start; i < limit; i += 2) { + u64 mactx = TX_RING(mac, i); + if ((mactx & XCT_MACTX_E) || (*mac->tx_status & PAS_STATUS_ERROR)) - pasemi_mac_tx_error(mac, dp->mactx); + pasemi_mac_tx_error(mac, mactx); - if (unlikely(dp->mactx & XCT_MACTX_O)) + if (unlikely(mactx & XCT_MACTX_O)) /* Not yet transmitted */ break; - info = &TX_DESC_INFO(mac, i); + info = &TX_RING_INFO(mac, i+1); skbs[count] = info->skb; dmas[count] = info->dma; - info->skb = NULL; info->dma = 0; - dp->mactx = 0; - dp->ptr = 0; + TX_RING(mac, i) = 0; + TX_RING(mac, i+1) = 0; + count++; } - mac->tx->next_to_clean += count; + mac->tx->next_to_clean += count * 2; spin_unlock_irqrestore(&mac->tx->lock, flags); netif_wake_queue(mac->netdev); @@ -1001,8 +997,6 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev) { struct pasemi_mac *mac = netdev_priv(dev); struct pasemi_mac_txring *txring; - struct pasemi_mac_buffer *info; - struct pas_dma_xct_descr *dp; u64 dflags, mactx, ptr; dma_addr_t map; unsigned long flags; @@ -1038,13 +1032,13 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev) spin_lock_irqsave(&txring->lock, flags); - if (RING_AVAIL(txring) <= 1) { + if (RING_AVAIL(txring) <= 2) { spin_unlock_irqrestore(&txring->lock, flags); pasemi_mac_clean_tx(mac); pasemi_mac_restart_tx_intr(mac); spin_lock_irqsave(&txring->lock, flags); - if (RING_AVAIL(txring) <= 1) { + if (RING_AVAIL(txring) <= 2) { /* Still no room -- stop the queue and wait for tx * intr when there's room. */ @@ -1053,15 +1047,14 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev) } } - dp = &TX_DESC(mac, txring->next_to_fill); - info = &TX_DESC_INFO(mac, txring->next_to_fill); + TX_RING(mac, txring->next_to_fill) = mactx; + TX_RING(mac, txring->next_to_fill+1) = ptr; + + TX_RING_INFO(mac, txring->next_to_fill+1).dma = map; + TX_RING_INFO(mac, txring->next_to_fill+1).skb = skb; - dp->mactx = mactx; - dp->ptr = ptr; - info->dma = map; - info->skb = skb; + txring->next_to_fill += 2; - txring->next_to_fill++; dev->stats.tx_packets++; dev->stats.tx_bytes += skb->len; diff --git a/drivers/net/pasemi_mac.h b/drivers/net/pasemi_mac.h index c52cfcb6c4c..5a896aa87a9 100644 --- a/drivers/net/pasemi_mac.h +++ b/drivers/net/pasemi_mac.h @@ -28,25 +28,25 @@ struct pasemi_mac_txring { spinlock_t lock; - struct pas_dma_xct_descr *desc; + u64 *ring; dma_addr_t dma; unsigned int size; unsigned int next_to_fill; unsigned int next_to_clean; - struct pasemi_mac_buffer *desc_info; + struct pasemi_mac_buffer *ring_info; char irq_name[10]; /* "eth%d tx" */ }; struct pasemi_mac_rxring { spinlock_t lock; - struct pas_dma_xct_descr *desc; /* RX channel descriptor ring */ + u64 *ring; /* RX channel descriptor ring */ dma_addr_t dma; u64 *buffers; /* RX interface buffer ring */ dma_addr_t buf_dma; unsigned int size; unsigned int next_to_fill; unsigned int next_to_clean; - struct pasemi_mac_buffer *desc_info; + struct pasemi_mac_buffer *ring_info; char irq_name[10]; /* "eth%d rx" */ }; @@ -88,7 +88,7 @@ struct pasemi_mac { char phy_id[BUS_ID_SIZE]; }; -/* Software status descriptor (desc_info) */ +/* Software status descriptor (ring_info) */ struct pasemi_mac_buffer { struct sk_buff *skb; dma_addr_t dma; @@ -101,20 +101,7 @@ struct pasdma_status { u64 tx_sta[20]; }; -/* descriptor structure */ -struct pas_dma_xct_descr { - union { - u64 mactx; - u64 macrx; - }; - union { - u64 ptr; - u64 rxb; - }; -}; - /* MAC CFG register offsets */ - enum { PAS_MAC_CFG_PCFG = 0x80, PAS_MAC_CFG_TXP = 0x98, -- cgit v1.2.3-70-g09d2 From ad3c20d1ab586884f1815c315e3f303a8b8a7d7d Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Tue, 2 Oct 2007 16:26:13 -0500 Subject: pasemi_mac: implement sg support pasemi_mac: implement sg support Implement SG support for pasemi_mac Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik --- drivers/net/pasemi_mac.c | 163 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 117 insertions(+), 46 deletions(-) (limited to 'drivers') diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index c2a3524a541..5eb5e47120d 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -160,6 +160,30 @@ static int pasemi_get_mac_addr(struct pasemi_mac *mac) return 0; } +static int pasemi_mac_unmap_tx_skb(struct pasemi_mac *mac, + struct sk_buff *skb, + dma_addr_t *dmas) +{ + int f; + int nfrags = skb_shinfo(skb)->nr_frags; + + pci_unmap_single(mac->dma_pdev, dmas[0], skb_headlen(skb), + PCI_DMA_TODEVICE); + + for (f = 0; f < nfrags; f++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[f]; + + pci_unmap_page(mac->dma_pdev, dmas[f+1], frag->size, + PCI_DMA_TODEVICE); + } + dev_kfree_skb_irq(skb); + + /* Freed descriptor slot + main SKB ptr + nfrags additional ptrs, + * aligned up to a power of 2 + */ + return (nfrags + 3) & ~1; +} + static int pasemi_mac_setup_rx_resources(struct net_device *dev) { struct pasemi_mac_rxring *ring; @@ -300,24 +324,24 @@ out_ring: static void pasemi_mac_free_tx_resources(struct net_device *dev) { struct pasemi_mac *mac = netdev_priv(dev); - unsigned int i; + unsigned int i, j; struct pasemi_mac_buffer *info; + dma_addr_t dmas[MAX_SKB_FRAGS+1]; + int freed; - for (i = 0; i < TX_RING_SIZE; i += 2) { + for (i = 0; i < TX_RING_SIZE; i += freed) { info = &TX_RING_INFO(mac, i+1); if (info->dma && info->skb) { - pci_unmap_single(mac->dma_pdev, - info->dma, - info->skb->len, - PCI_DMA_TODEVICE); - dev_kfree_skb_any(info->skb); - } - TX_RING(mac, i) = 0; - TX_RING(mac, i+1) = 0; - info->dma = 0; - info->skb = NULL; + for (j = 0; j <= skb_shinfo(info->skb)->nr_frags; j++) + dmas[j] = TX_RING_INFO(mac, i+1+j).dma; + freed = pasemi_mac_unmap_tx_skb(mac, info->skb, dmas); + } else + freed = 2; } + for (i = 0; i < TX_RING_SIZE; i++) + TX_RING(mac, i) = 0; + dma_free_coherent(&mac->dma_pdev->dev, TX_RING_SIZE * sizeof(u64), mac->tx->ring, mac->tx->dma); @@ -573,27 +597,34 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) return count; } +/* Can't make this too large or we blow the kernel stack limits */ +#define TX_CLEAN_BATCHSIZE (128/MAX_SKB_FRAGS) + static int pasemi_mac_clean_tx(struct pasemi_mac *mac) { - int i; + int i, j; struct pasemi_mac_buffer *info; - unsigned int start, count, limit; + unsigned int start, descr_count, buf_count, limit; unsigned int total_count; unsigned long flags; - struct sk_buff *skbs[32]; - dma_addr_t dmas[32]; + struct sk_buff *skbs[TX_CLEAN_BATCHSIZE]; + dma_addr_t dmas[TX_CLEAN_BATCHSIZE][MAX_SKB_FRAGS+1]; total_count = 0; + limit = TX_CLEAN_BATCHSIZE; restart: spin_lock_irqsave(&mac->tx->lock, flags); start = mac->tx->next_to_clean; - limit = min(mac->tx->next_to_fill, start+32); - count = 0; + buf_count = 0; + descr_count = 0; - for (i = start; i < limit; i += 2) { + for (i = start; + descr_count < limit && i < mac->tx->next_to_fill; + i += buf_count) { u64 mactx = TX_RING(mac, i); + if ((mactx & XCT_MACTX_E) || (*mac->tx_status & PAS_STATUS_ERROR)) pasemi_mac_tx_error(mac, mactx); @@ -603,30 +634,38 @@ restart: break; info = &TX_RING_INFO(mac, i+1); - skbs[count] = info->skb; - dmas[count] = info->dma; + skbs[descr_count] = info->skb; + + buf_count = 2 + skb_shinfo(info->skb)->nr_frags; + for (j = 0; j <= skb_shinfo(info->skb)->nr_frags; j++) + dmas[descr_count][j] = TX_RING_INFO(mac, i+1+j).dma; + info->dma = 0; TX_RING(mac, i) = 0; TX_RING(mac, i+1) = 0; + TX_RING_INFO(mac, i+1).skb = 0; + TX_RING_INFO(mac, i+1).dma = 0; - - count++; + /* Since we always fill with an even number of entries, make + * sure we skip any unused one at the end as well. + */ + if (buf_count & 1) + buf_count++; + descr_count++; } - mac->tx->next_to_clean += count * 2; + mac->tx->next_to_clean = i; + spin_unlock_irqrestore(&mac->tx->lock, flags); netif_wake_queue(mac->netdev); - for (i = 0; i < count; i++) { - pci_unmap_single(mac->dma_pdev, dmas[i], - skbs[i]->len, PCI_DMA_TODEVICE); - dev_kfree_skb_irq(skbs[i]); - } + for (i = 0; i < descr_count; i++) + pasemi_mac_unmap_tx_skb(mac, skbs[i], dmas[i]); - total_count += count; + total_count += descr_count; /* If the batch was full, try to clean more */ - if (count == 32) + if (descr_count == limit) goto restart; return total_count; @@ -997,9 +1036,11 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev) { struct pasemi_mac *mac = netdev_priv(dev); struct pasemi_mac_txring *txring; - u64 dflags, mactx, ptr; - dma_addr_t map; + u64 dflags, mactx; + dma_addr_t map[MAX_SKB_FRAGS+1]; + unsigned int map_size[MAX_SKB_FRAGS+1]; unsigned long flags; + int i, nfrags; dflags = XCT_MACTX_O | XCT_MACTX_ST | XCT_MACTX_SS | XCT_MACTX_CRC_PAD; @@ -1020,25 +1061,40 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev) } } - map = pci_map_single(mac->dma_pdev, skb->data, skb->len, PCI_DMA_TODEVICE); + nfrags = skb_shinfo(skb)->nr_frags; + + map[0] = pci_map_single(mac->dma_pdev, skb->data, skb_headlen(skb), + PCI_DMA_TODEVICE); + map_size[0] = skb_headlen(skb); + if (dma_mapping_error(map[0])) + goto out_err_nolock; + + for (i = 0; i < nfrags; i++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - if (dma_mapping_error(map)) - return NETDEV_TX_BUSY; + map[i+1] = pci_map_page(mac->dma_pdev, frag->page, + frag->page_offset, frag->size, + PCI_DMA_TODEVICE); + map_size[i+1] = frag->size; + if (dma_mapping_error(map[i+1])) { + nfrags = i; + goto out_err_nolock; + } + } mactx = dflags | XCT_MACTX_LLEN(skb->len); - ptr = XCT_PTR_LEN(skb->len) | XCT_PTR_ADDR(map); txring = mac->tx; spin_lock_irqsave(&txring->lock, flags); - if (RING_AVAIL(txring) <= 2) { + if (RING_AVAIL(txring) <= nfrags+3) { spin_unlock_irqrestore(&txring->lock, flags); pasemi_mac_clean_tx(mac); pasemi_mac_restart_tx_intr(mac); spin_lock_irqsave(&txring->lock, flags); - if (RING_AVAIL(txring) <= 2) { + if (RING_AVAIL(txring) <= nfrags+3) { /* Still no room -- stop the queue and wait for tx * intr when there's room. */ @@ -1048,25 +1104,40 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev) } TX_RING(mac, txring->next_to_fill) = mactx; - TX_RING(mac, txring->next_to_fill+1) = ptr; + txring->next_to_fill++; + TX_RING_INFO(mac, txring->next_to_fill).skb = skb; + for (i = 0; i <= nfrags; i++) { + TX_RING(mac, txring->next_to_fill+i) = + XCT_PTR_LEN(map_size[i]) | XCT_PTR_ADDR(map[i]); + TX_RING_INFO(mac, txring->next_to_fill+i).dma = map[i]; + } + + /* We have to add an even number of 8-byte entries to the ring + * even if the last one is unused. That means always an odd number + * of pointers + one mactx descriptor. + */ + if (nfrags & 1) + nfrags++; - TX_RING_INFO(mac, txring->next_to_fill+1).dma = map; - TX_RING_INFO(mac, txring->next_to_fill+1).skb = skb; + txring->next_to_fill += nfrags + 1; - txring->next_to_fill += 2; dev->stats.tx_packets++; dev->stats.tx_bytes += skb->len; spin_unlock_irqrestore(&txring->lock, flags); - write_dma_reg(mac, PAS_DMA_TXCHAN_INCR(mac->dma_txch), 1); + write_dma_reg(mac, PAS_DMA_TXCHAN_INCR(mac->dma_txch), (nfrags+2) >> 1); return NETDEV_TX_OK; out_err: spin_unlock_irqrestore(&txring->lock, flags); - pci_unmap_single(mac->dma_pdev, map, skb->len, PCI_DMA_TODEVICE); +out_err_nolock: + while (nfrags--) + pci_unmap_single(mac->dma_pdev, map[nfrags], map_size[nfrags], + PCI_DMA_TODEVICE); + return NETDEV_TX_BUSY; } @@ -1202,7 +1273,7 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netif_napi_add(dev, &mac->napi, pasemi_mac_poll, 64); - dev->features = NETIF_F_HW_CSUM | NETIF_F_LLTX; + dev->features = NETIF_F_HW_CSUM | NETIF_F_LLTX | NETIF_F_SG; /* These should come out of the device tree eventually */ mac->dma_txch = index; -- cgit v1.2.3-70-g09d2 From 9a50bebda95745d312c69d3bb6d788067cbefb84 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Tue, 2 Oct 2007 16:26:30 -0500 Subject: pasemi_mac: workaround for erratum 5971 pasemi_mac: workaround for erratum 5971 Implement workarounds for erratum 5971, where L2 hints aren't considered properly unless the way hint is enabled on the interface. Since L2 isn't setup to dedicate a way to headers, we need to reset the packet count by hand so it won't run out of credits. Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik --- drivers/net/pasemi_mac.c | 9 ++++++++- drivers/net/pasemi_mac.h | 8 ++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 5eb5e47120d..c538c66d4b4 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -239,7 +239,9 @@ static int pasemi_mac_setup_rx_resources(struct net_device *dev) PAS_DMA_RXINT_BASEU_SIZ(RX_RING_SIZE >> 3)); write_dma_reg(mac, PAS_DMA_RXINT_CFG(mac->dma_if), - PAS_DMA_RXINT_CFG_DHL(2)); + PAS_DMA_RXINT_CFG_DHL(3) | + PAS_DMA_RXINT_CFG_L2 | + PAS_DMA_RXINT_CFG_LW); ring->next_to_fill = 0; ring->next_to_clean = 0; @@ -589,6 +591,11 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) n += 2; } + if (n > RX_RING_SIZE) { + /* Errata 5971 workaround: L2 target of headers */ + write_iob_reg(mac, PAS_IOB_COM_PKTHDRCNT, 0); + n &= (RX_RING_SIZE-1); + } mac->rx->next_to_clean = n; pasemi_mac_replenish_rx_ring(mac->netdev, limit-count); diff --git a/drivers/net/pasemi_mac.h b/drivers/net/pasemi_mac.h index 5a896aa87a9..db3393674ae 100644 --- a/drivers/net/pasemi_mac.h +++ b/drivers/net/pasemi_mac.h @@ -210,6 +210,8 @@ enum { #define PAS_DMA_RXINT_CFG_DHL_S 24 #define PAS_DMA_RXINT_CFG_DHL(x) (((x) << PAS_DMA_RXINT_CFG_DHL_S) & \ PAS_DMA_RXINT_CFG_DHL_M) +#define PAS_DMA_RXINT_CFG_LW 0x00200000 +#define PAS_DMA_RXINT_CFG_L2 0x00100000 #define PAS_DMA_RXINT_CFG_WIF 0x00000002 #define PAS_DMA_RXINT_CFG_WIL 0x00000001 @@ -315,6 +317,12 @@ enum { #define PAS_STATUS_SOFT 0x4000000000000000ull #define PAS_STATUS_INT 0x8000000000000000ull +#define PAS_IOB_COM_PKTHDRCNT 0x120 +#define PAS_IOB_COM_PKTHDRCNT_PKTHDR1_M 0x0fff0000 +#define PAS_IOB_COM_PKTHDRCNT_PKTHDR1_S 16 +#define PAS_IOB_COM_PKTHDRCNT_PKTHDR0_M 0x00000fff +#define PAS_IOB_COM_PKTHDRCNT_PKTHDR0_S 0 + #define PAS_IOB_DMA_RXCH_CFG(i) (0x1100 + (i)*4) #define PAS_IOB_DMA_RXCH_CFG_CNTTH_M 0x00000fff #define PAS_IOB_DMA_RXCH_CFG_CNTTH_S 0 -- cgit v1.2.3-70-g09d2 From 8dc121a4b620090e594945fd36f878836fc5a14a Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Tue, 2 Oct 2007 16:26:53 -0500 Subject: pasemi_mac: add local skb alignment pasemi_mac: add local skb alignment Add local SKB alignment to pasemi_mac, since ppc64 in general has it at 0 because of design flaws in some of the IBM server bridge chips. However, for PWRficient doing the unaligned copies is more expensive than doing unaligned DMA so make sure the data is aligned instead. Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik --- drivers/net/pasemi_mac.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index c538c66d4b4..b3994f5d2d2 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -37,6 +37,12 @@ #include "pasemi_mac.h" +/* We have our own align, since ppc64 in general has it at 0 because + * of design flaws in some of the server bridge chips. However, for + * PWRficient doing the unaligned copies is more expensive than doing + * unaligned DMA, so make sure the data is aligned instead. + */ +#define LOCAL_SKB_ALIGN 2 /* TODO list * @@ -409,13 +415,16 @@ static void pasemi_mac_replenish_rx_ring(struct net_device *dev, int limit) /* skb might still be in there for recycle on short receives */ if (info->skb) skb = info->skb; - else + else { skb = dev_alloc_skb(BUF_SIZE); + skb_reserve(skb, LOCAL_SKB_ALIGN); + } if (unlikely(!skb)) break; - dma = pci_map_single(mac->dma_pdev, skb->data, BUF_SIZE, + dma = pci_map_single(mac->dma_pdev, skb->data, + BUF_SIZE - LOCAL_SKB_ALIGN, PCI_DMA_FROMDEVICE); if (unlikely(dma_mapping_error(dma))) { @@ -553,10 +562,12 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) len = (macrx & XCT_MACRX_LLEN_M) >> XCT_MACRX_LLEN_S; if (len < 256) { - struct sk_buff *new_skb = - netdev_alloc_skb(mac->netdev, len + NET_IP_ALIGN); + struct sk_buff *new_skb; + + new_skb = netdev_alloc_skb(mac->netdev, + len + LOCAL_SKB_ALIGN); if (new_skb) { - skb_reserve(new_skb, NET_IP_ALIGN); + skb_reserve(new_skb, LOCAL_SKB_ALIGN); memcpy(new_skb->data, skb->data, len); /* save the skb in buffer_info as good */ skb = new_skb; -- cgit v1.2.3-70-g09d2 From ad5da10a64bdca1ed39b25946727a1ce2659f3d4 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Tue, 2 Oct 2007 16:27:15 -0500 Subject: pasemi_mac: further performance tweaks pasemi_mac: further performance tweaks Misc driver tweaks for pasemi_mac: * Increase ring size (really needed mostly on 10G) * Take out an unneeded barrier * Move around a few prefetches and reorder a few calls * Don't try to clean on full tx buffer, just let things take their course and stop the queue directly * Avoid filling on the same line as the interface is working on to reduce cache line bouncing * Avoid unneeded clearing of software state (and make the interface shutdown code handle it) * Fix up some of the tx ring wrap logic. Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik --- drivers/net/pasemi_mac.c | 92 +++++++++++++++++++++++++----------------------- 1 file changed, 47 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index b3994f5d2d2..4a451f8c6f4 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -56,8 +56,8 @@ /* Must be a power of two */ -#define RX_RING_SIZE 512 -#define TX_RING_SIZE 512 +#define RX_RING_SIZE 4096 +#define TX_RING_SIZE 4096 #define DEFAULT_MSG_ENABLE \ (NETIF_MSG_DRV | \ @@ -336,8 +336,16 @@ static void pasemi_mac_free_tx_resources(struct net_device *dev) struct pasemi_mac_buffer *info; dma_addr_t dmas[MAX_SKB_FRAGS+1]; int freed; + int start, limit; - for (i = 0; i < TX_RING_SIZE; i += freed) { + start = mac->tx->next_to_clean; + limit = mac->tx->next_to_fill; + + /* Compensate for when fill has wrapped and clean has not */ + if (start > limit) + limit += TX_RING_SIZE; + + for (i = start; i < limit; i += freed) { info = &TX_RING_INFO(mac, i+1); if (info->dma && info->skb) { for (j = 0; j <= skb_shinfo(info->skb)->nr_frags; j++) @@ -520,9 +528,6 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) n = mac->rx->next_to_clean; for (count = limit; count; count--) { - - rmb(); - macrx = RX_RING(mac, n); if ((macrx & XCT_MACRX_E) || @@ -550,14 +555,10 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) break; } - prefetchw(info); - skb = info->skb; - prefetchw(skb); - info->dma = 0; - pci_unmap_single(mac->dma_pdev, dma, skb->len, - PCI_DMA_FROMDEVICE); + prefetch(skb); + prefetch(&skb->data_len); len = (macrx & XCT_MACRX_LLEN_M) >> XCT_MACRX_LLEN_S; @@ -576,10 +577,9 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) } else info->skb = NULL; - /* Need to zero it out since hardware doesn't, since the - * replenish loop uses it to tell when it's done. - */ - RX_BUFF(mac, i) = 0; + pci_unmap_single(mac->dma_pdev, dma, len, PCI_DMA_FROMDEVICE); + + info->dma = 0; skb_put(skb, len); @@ -599,6 +599,11 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) RX_RING(mac, n) = 0; RX_RING(mac, n+1) = 0; + /* Need to zero it out since hardware doesn't, since the + * replenish loop uses it to tell when it's done. + */ + RX_BUFF(mac, i) = 0; + n += 2; } @@ -621,27 +626,33 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) static int pasemi_mac_clean_tx(struct pasemi_mac *mac) { int i, j; - struct pasemi_mac_buffer *info; - unsigned int start, descr_count, buf_count, limit; + unsigned int start, descr_count, buf_count, batch_limit; + unsigned int ring_limit; unsigned int total_count; unsigned long flags; struct sk_buff *skbs[TX_CLEAN_BATCHSIZE]; dma_addr_t dmas[TX_CLEAN_BATCHSIZE][MAX_SKB_FRAGS+1]; total_count = 0; - limit = TX_CLEAN_BATCHSIZE; + batch_limit = TX_CLEAN_BATCHSIZE; restart: spin_lock_irqsave(&mac->tx->lock, flags); start = mac->tx->next_to_clean; + ring_limit = mac->tx->next_to_fill; + + /* Compensate for when fill has wrapped but clean has not */ + if (start > ring_limit) + ring_limit += TX_RING_SIZE; buf_count = 0; descr_count = 0; for (i = start; - descr_count < limit && i < mac->tx->next_to_fill; + descr_count < batch_limit && i < ring_limit; i += buf_count) { u64 mactx = TX_RING(mac, i); + struct sk_buff *skb; if ((mactx & XCT_MACTX_E) || (*mac->tx_status & PAS_STATUS_ERROR)) @@ -651,19 +662,15 @@ restart: /* Not yet transmitted */ break; - info = &TX_RING_INFO(mac, i+1); - skbs[descr_count] = info->skb; + skb = TX_RING_INFO(mac, i+1).skb; + skbs[descr_count] = skb; - buf_count = 2 + skb_shinfo(info->skb)->nr_frags; - for (j = 0; j <= skb_shinfo(info->skb)->nr_frags; j++) + buf_count = 2 + skb_shinfo(skb)->nr_frags; + for (j = 0; j <= skb_shinfo(skb)->nr_frags; j++) dmas[descr_count][j] = TX_RING_INFO(mac, i+1+j).dma; - - info->dma = 0; TX_RING(mac, i) = 0; TX_RING(mac, i+1) = 0; - TX_RING_INFO(mac, i+1).skb = 0; - TX_RING_INFO(mac, i+1).dma = 0; /* Since we always fill with an even number of entries, make * sure we skip any unused one at the end as well. @@ -672,7 +679,7 @@ restart: buf_count++; descr_count++; } - mac->tx->next_to_clean = i; + mac->tx->next_to_clean = i & (TX_RING_SIZE-1); spin_unlock_irqrestore(&mac->tx->lock, flags); netif_wake_queue(mac->netdev); @@ -683,7 +690,7 @@ restart: total_count += descr_count; /* If the batch was full, try to clean more */ - if (descr_count == limit) + if (descr_count == batch_limit) goto restart; return total_count; @@ -1106,19 +1113,14 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev) spin_lock_irqsave(&txring->lock, flags); - if (RING_AVAIL(txring) <= nfrags+3) { - spin_unlock_irqrestore(&txring->lock, flags); - pasemi_mac_clean_tx(mac); - pasemi_mac_restart_tx_intr(mac); - spin_lock_irqsave(&txring->lock, flags); - - if (RING_AVAIL(txring) <= nfrags+3) { - /* Still no room -- stop the queue and wait for tx - * intr when there's room. - */ - netif_stop_queue(dev); - goto out_err; - } + /* Avoid stepping on the same cache line that the DMA controller + * is currently about to send, so leave at least 8 words available. + * Total free space needed is mactx + fragments + 8 + */ + if (RING_AVAIL(txring) < nfrags + 10) { + /* no room -- stop the queue and wait for tx intr */ + netif_stop_queue(dev); + goto out_err; } TX_RING(mac, txring->next_to_fill) = mactx; @@ -1137,8 +1139,8 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev) if (nfrags & 1) nfrags++; - txring->next_to_fill += nfrags + 1; - + txring->next_to_fill = (txring->next_to_fill + nfrags + 1) & + (TX_RING_SIZE-1); dev->stats.tx_packets++; dev->stats.tx_bytes += skb->len; -- cgit v1.2.3-70-g09d2 From 7ddeae2c6ceed7f786344731dda27d4277957780 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Tue, 2 Oct 2007 16:27:28 -0500 Subject: pasemi_mac: update todo list pasemi_mac: update todo list Remove some stale todo items that have been taken care of. Add a couple of upcoming ones. Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik --- drivers/net/pasemi_mac.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 4a451f8c6f4..ef1ebb4b8af 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -46,12 +46,10 @@ /* TODO list * - * - Get rid of pci_{read,write}_config(), map registers with ioremap - * for performance - * - PHY support * - Multicast support * - Large MTU support - * - Other performance improvements + * - SW LRO + * - Multiqueue RX/TX */ -- cgit v1.2.3-70-g09d2 From 9e81d331f2ec65695e4366ce592e14f9700bae8b Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Tue, 2 Oct 2007 16:27:39 -0500 Subject: pasemi_mac: clear out old errors on interface open pasemi_mac: clear out old errors on interface open Clear out any pending errors when an interface is brought up. Since the bits are sticky, they might be from interface shutdown time after firmware has used it, etc. Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik --- drivers/net/pasemi_mac.c | 57 +++++++++++++++++++++++++++++++++++++----------- drivers/net/pasemi_mac.h | 7 ++++++ 2 files changed, 51 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index ef1ebb4b8af..967ff8c96b0 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -903,16 +903,27 @@ static int pasemi_mac_open(struct net_device *dev) /* enable rx if */ write_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if), - PAS_DMA_RXINT_RCMDSTA_EN); + PAS_DMA_RXINT_RCMDSTA_EN | + PAS_DMA_RXINT_RCMDSTA_DROPS_M | + PAS_DMA_RXINT_RCMDSTA_BP | + PAS_DMA_RXINT_RCMDSTA_OO | + PAS_DMA_RXINT_RCMDSTA_BT); /* enable rx channel */ write_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch), PAS_DMA_RXCHAN_CCMDSTA_EN | - PAS_DMA_RXCHAN_CCMDSTA_DU); + PAS_DMA_RXCHAN_CCMDSTA_DU | + PAS_DMA_RXCHAN_CCMDSTA_OD | + PAS_DMA_RXCHAN_CCMDSTA_FD | + PAS_DMA_RXCHAN_CCMDSTA_DT); /* enable tx channel */ write_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch), - PAS_DMA_TXCHAN_TCMDSTA_EN); + PAS_DMA_TXCHAN_TCMDSTA_EN | + PAS_DMA_TXCHAN_TCMDSTA_SZ | + PAS_DMA_TXCHAN_TCMDSTA_DB | + PAS_DMA_TXCHAN_TCMDSTA_DE | + PAS_DMA_TXCHAN_TCMDSTA_DA); pasemi_mac_replenish_rx_ring(dev, RX_RING_SIZE); @@ -987,7 +998,7 @@ out_rx_resources: static int pasemi_mac_close(struct net_device *dev) { struct pasemi_mac *mac = netdev_priv(dev); - unsigned int stat; + unsigned int sta; int retries; if (mac->phydev) { @@ -998,6 +1009,26 @@ static int pasemi_mac_close(struct net_device *dev) netif_stop_queue(dev); napi_disable(&mac->napi); + sta = read_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if)); + if (sta & (PAS_DMA_RXINT_RCMDSTA_BP | + PAS_DMA_RXINT_RCMDSTA_OO | + PAS_DMA_RXINT_RCMDSTA_BT)) + printk(KERN_DEBUG "pasemi_mac: rcmdsta error: 0x%08x\n", sta); + + sta = read_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch)); + if (sta & (PAS_DMA_RXCHAN_CCMDSTA_DU | + PAS_DMA_RXCHAN_CCMDSTA_OD | + PAS_DMA_RXCHAN_CCMDSTA_FD | + PAS_DMA_RXCHAN_CCMDSTA_DT)) + printk(KERN_DEBUG "pasemi_mac: ccmdsta error: 0x%08x\n", sta); + + sta = read_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch)); + if (sta & (PAS_DMA_TXCHAN_TCMDSTA_SZ | + PAS_DMA_TXCHAN_TCMDSTA_DB | + PAS_DMA_TXCHAN_TCMDSTA_DE | + PAS_DMA_TXCHAN_TCMDSTA_DA)) + printk(KERN_DEBUG "pasemi_mac: tcmdsta error: 0x%08x\n", sta); + /* Clean out any pending buffers */ pasemi_mac_clean_tx(mac); pasemi_mac_clean_rx(mac, RX_RING_SIZE); @@ -1008,33 +1039,33 @@ static int pasemi_mac_close(struct net_device *dev) write_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch), PAS_DMA_RXCHAN_CCMDSTA_ST); for (retries = 0; retries < MAX_RETRIES; retries++) { - stat = read_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch)); - if (!(stat & PAS_DMA_TXCHAN_TCMDSTA_ACT)) + sta = read_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch)); + if (!(sta & PAS_DMA_TXCHAN_TCMDSTA_ACT)) break; cond_resched(); } - if (stat & PAS_DMA_TXCHAN_TCMDSTA_ACT) + if (sta & PAS_DMA_TXCHAN_TCMDSTA_ACT) dev_err(&mac->dma_pdev->dev, "Failed to stop tx channel\n"); for (retries = 0; retries < MAX_RETRIES; retries++) { - stat = read_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch)); - if (!(stat & PAS_DMA_RXCHAN_CCMDSTA_ACT)) + sta = read_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch)); + if (!(sta & PAS_DMA_RXCHAN_CCMDSTA_ACT)) break; cond_resched(); } - if (stat & PAS_DMA_RXCHAN_CCMDSTA_ACT) + if (sta & PAS_DMA_RXCHAN_CCMDSTA_ACT) dev_err(&mac->dma_pdev->dev, "Failed to stop rx channel\n"); for (retries = 0; retries < MAX_RETRIES; retries++) { - stat = read_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if)); - if (!(stat & PAS_DMA_RXINT_RCMDSTA_ACT)) + sta = read_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if)); + if (!(sta & PAS_DMA_RXINT_RCMDSTA_ACT)) break; cond_resched(); } - if (stat & PAS_DMA_RXINT_RCMDSTA_ACT) + if (sta & PAS_DMA_RXINT_RCMDSTA_ACT) dev_err(&mac->dma_pdev->dev, "Failed to stop rx interface\n"); /* Then, disable the channel. This must be done separately from diff --git a/drivers/net/pasemi_mac.h b/drivers/net/pasemi_mac.h index db3393674ae..0bb3c487478 100644 --- a/drivers/net/pasemi_mac.h +++ b/drivers/net/pasemi_mac.h @@ -241,6 +241,10 @@ enum { #define PAS_DMA_TXCHAN_TCMDSTA_EN 0x00000001 /* Enabled */ #define PAS_DMA_TXCHAN_TCMDSTA_ST 0x00000002 /* Stop interface */ #define PAS_DMA_TXCHAN_TCMDSTA_ACT 0x00010000 /* Active */ +#define PAS_DMA_TXCHAN_TCMDSTA_SZ 0x00000800 +#define PAS_DMA_TXCHAN_TCMDSTA_DB 0x00000400 +#define PAS_DMA_TXCHAN_TCMDSTA_DE 0x00000200 +#define PAS_DMA_TXCHAN_TCMDSTA_DA 0x00000100 #define PAS_DMA_TXCHAN_CFG(c) (0x304+(c)*_PAS_DMA_TXCHAN_STRIDE) #define PAS_DMA_TXCHAN_CFG_TY_IFACE 0x00000000 /* Type = interface */ #define PAS_DMA_TXCHAN_CFG_TATTR_M 0x0000003c @@ -283,6 +287,9 @@ enum { #define PAS_DMA_RXCHAN_CCMDSTA_ST 0x00000002 /* Stop interface */ #define PAS_DMA_RXCHAN_CCMDSTA_ACT 0x00010000 /* Active */ #define PAS_DMA_RXCHAN_CCMDSTA_DU 0x00020000 +#define PAS_DMA_RXCHAN_CCMDSTA_OD 0x00002000 +#define PAS_DMA_RXCHAN_CCMDSTA_FD 0x00001000 +#define PAS_DMA_RXCHAN_CCMDSTA_DT 0x00000800 #define PAS_DMA_RXCHAN_CFG(c) (0x804+(c)*_PAS_DMA_RXCHAN_STRIDE) #define PAS_DMA_RXCHAN_CFG_HBU_M 0x00000380 #define PAS_DMA_RXCHAN_CFG_HBU_S 7 -- cgit v1.2.3-70-g09d2 From b5254eee7994ba0a44ba7386cb66c2ce2f30fcc6 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Tue, 2 Oct 2007 16:27:57 -0500 Subject: pasemi_mac: use buffer index pointer in clean_rx() pasemi_mac: use buffer index pointer in clean_rx() Use the new features in B0 for buffer ring index on the receive side. This means we no longer have to search in the ring for where the buffer came from. Also cleanup the RX cleaning side a little, while I was at it. Note: Pre-B0 hardware is no longer supported, and needs a pile of other workarounds that are not being submitted for mainline inclusion. So the fact that this breaks old hardware is not a problem at this time. Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik --- drivers/net/pasemi_mac.c | 60 ++++++++++++++++++++++++++---------------------- drivers/net/pasemi_mac.h | 21 +++++++++++++---- 2 files changed, 50 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 967ff8c96b0..31ad2b9093a 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -243,9 +243,9 @@ static int pasemi_mac_setup_rx_resources(struct net_device *dev) PAS_DMA_RXINT_BASEU_SIZ(RX_RING_SIZE >> 3)); write_dma_reg(mac, PAS_DMA_RXINT_CFG(mac->dma_if), - PAS_DMA_RXINT_CFG_DHL(3) | - PAS_DMA_RXINT_CFG_L2 | - PAS_DMA_RXINT_CFG_LW); + PAS_DMA_RXINT_CFG_DHL(3) | PAS_DMA_RXINT_CFG_L2 | + PAS_DMA_RXINT_CFG_LW | PAS_DMA_RXINT_CFG_RBP | + PAS_DMA_RXINT_CFG_HEN); ring->next_to_fill = 0; ring->next_to_clean = 0; @@ -402,13 +402,12 @@ static void pasemi_mac_free_rx_resources(struct net_device *dev) static void pasemi_mac_replenish_rx_ring(struct net_device *dev, int limit) { struct pasemi_mac *mac = netdev_priv(dev); - int start = mac->rx->next_to_fill; - unsigned int fill, count; + int fill, count; if (limit <= 0) return; - fill = start; + fill = mac->rx->next_to_fill; for (count = 0; count < limit; count++) { struct pasemi_mac_buffer *info = &RX_RING_INFO(mac, fill); u64 *buff = &RX_BUFF(mac, fill); @@ -446,10 +445,10 @@ static void pasemi_mac_replenish_rx_ring(struct net_device *dev, int limit) wmb(); - write_dma_reg(mac, PAS_DMA_RXCHAN_INCR(mac->dma_rxch), count); write_dma_reg(mac, PAS_DMA_RXINT_INCR(mac->dma_if), count); - mac->rx->next_to_fill += count; + mac->rx->next_to_fill = (mac->rx->next_to_fill + count) & + (RX_RING_SIZE - 1); } static void pasemi_mac_restart_rx_intr(struct pasemi_mac *mac) @@ -517,15 +516,19 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) int count; struct pasemi_mac_buffer *info; struct sk_buff *skb; - unsigned int i, len; + unsigned int len; u64 macrx; dma_addr_t dma; + int buf_index; + u64 eval; spin_lock(&mac->rx->lock); n = mac->rx->next_to_clean; - for (count = limit; count; count--) { + prefetch(RX_RING(mac, n)); + + for (count = 0; count < limit; count++) { macrx = RX_RING(mac, n); if ((macrx & XCT_MACRX_E) || @@ -537,21 +540,14 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) info = NULL; - /* We have to scan for our skb since there's no way - * to back-map them from the descriptor, and if we - * have several receive channels then they might not - * show up in the same order as they were put on the - * interface ring. - */ + BUG_ON(!(macrx & XCT_MACRX_RR_8BRES)); - dma = (RX_RING(mac, n+1) & XCT_PTR_ADDR_M); - for (i = mac->rx->next_to_fill; - i < (mac->rx->next_to_fill + RX_RING_SIZE); - i++) { - info = &RX_RING_INFO(mac, i); - if (info->dma == dma) - break; - } + eval = (RX_RING(mac, n+1) & XCT_RXRES_8B_EVAL_M) >> + XCT_RXRES_8B_EVAL_S; + buf_index = eval-1; + + dma = (RX_RING(mac, n+2) & XCT_PTR_ADDR_M); + info = &RX_RING_INFO(mac, buf_index); skb = info->skb; @@ -600,9 +596,9 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) /* Need to zero it out since hardware doesn't, since the * replenish loop uses it to tell when it's done. */ - RX_BUFF(mac, i) = 0; + RX_BUFF(mac, buf_index) = 0; - n += 2; + n += 4; } if (n > RX_RING_SIZE) { @@ -610,8 +606,16 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) write_iob_reg(mac, PAS_IOB_COM_PKTHDRCNT, 0); n &= (RX_RING_SIZE-1); } + mac->rx->next_to_clean = n; - pasemi_mac_replenish_rx_ring(mac->netdev, limit-count); + + /* Increase is in number of 16-byte entries, and since each descriptor + * with an 8BRES takes up 3x8 bytes (padded to 4x8), increase with + * count*2. + */ + write_dma_reg(mac, PAS_DMA_RXCHAN_INCR(mac->dma_rxch), count << 1); + + pasemi_mac_replenish_rx_ring(mac->netdev, count); spin_unlock(&mac->rx->lock); @@ -927,6 +931,8 @@ static int pasemi_mac_open(struct net_device *dev) pasemi_mac_replenish_rx_ring(dev, RX_RING_SIZE); + write_dma_reg(mac, PAS_DMA_RXCHAN_INCR(mac->dma_rxch), RX_RING_SIZE>>1); + flags = PAS_MAC_CFG_PCFG_S1 | PAS_MAC_CFG_PCFG_PE | PAS_MAC_CFG_PCFG_PR | PAS_MAC_CFG_PCFG_CE; diff --git a/drivers/net/pasemi_mac.h b/drivers/net/pasemi_mac.h index 0bb3c487478..1a120408cf3 100644 --- a/drivers/net/pasemi_mac.h +++ b/drivers/net/pasemi_mac.h @@ -206,12 +206,15 @@ enum { #define PAS_DMA_RXINT_RCMDSTA_DROPS_M 0xfffe0000 #define PAS_DMA_RXINT_RCMDSTA_DROPS_S 17 #define PAS_DMA_RXINT_CFG(i) (0x204+(i)*_PAS_DMA_RXINT_STRIDE) +#define PAS_DMA_RXINT_CFG_RBP 0x80000000 +#define PAS_DMA_RXINT_CFG_ITRR 0x40000000 #define PAS_DMA_RXINT_CFG_DHL_M 0x07000000 #define PAS_DMA_RXINT_CFG_DHL_S 24 #define PAS_DMA_RXINT_CFG_DHL(x) (((x) << PAS_DMA_RXINT_CFG_DHL_S) & \ PAS_DMA_RXINT_CFG_DHL_M) #define PAS_DMA_RXINT_CFG_LW 0x00200000 #define PAS_DMA_RXINT_CFG_L2 0x00100000 +#define PAS_DMA_RXINT_CFG_HEN 0x00080000 #define PAS_DMA_RXINT_CFG_WIF 0x00000002 #define PAS_DMA_RXINT_CFG_WIL 0x00000001 @@ -425,10 +428,9 @@ enum { /* Receive descriptor fields */ #define XCT_MACRX_T 0x8000000000000000ull #define XCT_MACRX_ST 0x4000000000000000ull -#define XCT_MACRX_NORES 0x0000000000000000ull -#define XCT_MACRX_8BRES 0x1000000000000000ull -#define XCT_MACRX_24BRES 0x2000000000000000ull -#define XCT_MACRX_40BRES 0x3000000000000000ull +#define XCT_MACRX_RR_M 0x3000000000000000ull +#define XCT_MACRX_RR_NORES 0x0000000000000000ull +#define XCT_MACRX_RR_8BRES 0x1000000000000000ull #define XCT_MACRX_O 0x0400000000000000ull #define XCT_MACRX_E 0x0200000000000000ull #define XCT_MACRX_FF 0x0100000000000000ull @@ -476,6 +478,17 @@ enum { #define XCT_PTR_ADDR(x) ((((long)(x)) << XCT_PTR_ADDR_S) & \ XCT_PTR_ADDR_M) +/* Receive interface 8byte result fields */ +#define XCT_RXRES_8B_L4O_M 0xff00000000000000ull +#define XCT_RXRES_8B_L4O_S 56 +#define XCT_RXRES_8B_RULE_M 0x00ffff0000000000ull +#define XCT_RXRES_8B_RULE_S 40 +#define XCT_RXRES_8B_EVAL_M 0x000000ffff000000ull +#define XCT_RXRES_8B_EVAL_S 24 +#define XCT_RXRES_8B_HTYPE_M 0x0000000000f00000ull +#define XCT_RXRES_8B_HASH_M 0x00000000000fffffull +#define XCT_RXRES_8B_HASH_S 0 + /* Receive interface buffer fields */ #define XCT_RXB_LEN_M 0x0ffff00000000000ull #define XCT_RXB_LEN_S 44 -- cgit v1.2.3-70-g09d2 From 1dad939ddbbd8d64e1edc7799df00a9e591b4197 Mon Sep 17 00:00:00 2001 From: trem Date: Tue, 2 Oct 2007 14:04:38 -0700 Subject: ipg.c doesn't compile with with CONFIG_HIGHMEM64G I've tried to compile 2.6.23-rc8-mm2, but it fails on ipg.c with the error : ERROR: "__udivdi3" [drivers/net/ipg.ko] undefined! I've instigated a bit, and I've found this code in ipg.c : static void ipg_nic_txfree(struct net_device *dev) { struct ipg_nic_private *sp = netdev_priv(dev); void __iomem *ioaddr = sp->ioaddr; const unsigned int curr = ipg_r32(TFD_LIST_PTR_0) - (sp->txd_map / sizeof(struct ipg_tx)) - 1; unsigned int released, pending; sp->txd_map is an u64 because : dma_addr_t txd_map; And in asm-i386/types.h, I see : #ifdef CONFIG_HIGHMEM64G typedef u64 dma_addr_t; #else typedef u32 dma_addr_t; #endif I my config, I use CONFIG_HIGHMEM64G sizeof(struct ipg_tx) is an u32 So the div failed on i386 because of u64 / u32. [akpm@linux-foundation.org: cleanups] Cc: Sorbica Shieh Cc: Jesse Huang Cc: Jeff Garzik Cc: "David S. Miller" Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/ipg.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ipg.c b/drivers/net/ipg.c index dfdc96fcade..59898ce54dc 100644 --- a/drivers/net/ipg.c +++ b/drivers/net/ipg.c @@ -25,6 +25,8 @@ #include #include +#include + #define IPG_RX_RING_BYTES (sizeof(struct ipg_rx) * IPG_RFDLIST_LENGTH) #define IPG_TX_RING_BYTES (sizeof(struct ipg_tx) * IPG_TFDLIST_LENGTH) #define IPG_RESET_MASK \ @@ -836,10 +838,14 @@ static void ipg_nic_txfree(struct net_device *dev) { struct ipg_nic_private *sp = netdev_priv(dev); void __iomem *ioaddr = sp->ioaddr; - const unsigned int curr = ipg_r32(TFD_LIST_PTR_0) - - (sp->txd_map / sizeof(struct ipg_tx)) - 1; + unsigned int curr; + u64 txd_map; unsigned int released, pending; + txd_map = (u64)sp->txd_map; + curr = ipg_r32(TFD_LIST_PTR_0) - + do_div(txd_map, sizeof(struct ipg_tx)) - 1; + IPG_DEBUG_MSG("_nic_txfree\n"); pending = sp->tx_current - sp->tx_dirty; -- cgit v1.2.3-70-g09d2 From 07c2c76e27e629fb5c9a539e249906802866abb8 Mon Sep 17 00:00:00 2001 From: "vbarshak@ru.mvista.com" Date: Tue, 2 Oct 2007 16:01:07 +0400 Subject: Fix typo in new EMAC driver. Fix an obvious typo in emac_xmit_finish. Signed-off-by: Valentine Barshak Signed-off-by: Jeff Garzik --- drivers/net/ibm_newemac/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c index 653bfdc291e..ce127b9cafa 100644 --- a/drivers/net/ibm_newemac/core.c +++ b/drivers/net/ibm_newemac/core.c @@ -1232,9 +1232,9 @@ static inline int emac_xmit_finish(struct emac_instance *dev, int len) * instead */ if (emac_has_feature(dev, EMAC_FTR_EMAC4)) - out_be32(&p->tmr0, EMAC_TMR0_XMIT); - else out_be32(&p->tmr0, EMAC4_TMR0_XMIT); + else + out_be32(&p->tmr0, EMAC_TMR0_XMIT); if (unlikely(++dev->tx_cnt == NUM_TX_BUFF)) { netif_stop_queue(ndev); -- cgit v1.2.3-70-g09d2 From 9ddf7774b9d760dc3fa4d5ae7d7fd92d4c02150b Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 3 Oct 2007 13:52:23 -0400 Subject: drivers/net/qla3xxx: trim trailing whitespace Also, hopefully, change the file permissions to 0644. Signed-off-by: Jeff Garzik --- drivers/net/qla3xxx.c | 128 +++++++++++++++++++++++++------------------------- drivers/net/qla3xxx.h | 6 +-- 2 files changed, 67 insertions(+), 67 deletions(-) mode change 100755 => 100644 drivers/net/qla3xxx.c mode change 100755 => 100644 drivers/net/qla3xxx.h (limited to 'drivers') diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c old mode 100755 new mode 100644 index 48069ece4e5..30adf726743 --- a/drivers/net/qla3xxx.c +++ b/drivers/net/qla3xxx.c @@ -81,7 +81,7 @@ typedef enum { } PHY_DEVICE_et; typedef struct { - PHY_DEVICE_et phyDevice; + PHY_DEVICE_et phyDevice; u32 phyIdOUI; u16 phyIdModel; char *name; @@ -330,7 +330,7 @@ static void ql_release_to_lrg_buf_free_list(struct ql3_adapter *qdev, PCI_DMA_FROMDEVICE); err = pci_dma_mapping_error(map); if(err) { - printk(KERN_ERR "%s: PCI mapping failed with error: %d\n", + printk(KERN_ERR "%s: PCI mapping failed with error: %d\n", qdev->ndev->name, err); dev_kfree_skb(lrg_buf_cb->skb); lrg_buf_cb->skb = NULL; @@ -884,14 +884,14 @@ static void ql_petbi_start_neg_ex(struct ql3_adapter *qdev) u16 reg; /* Enable Auto-negotiation sense */ - ql_mii_read_reg_ex(qdev, PETBI_TBI_CTRL, ®, + ql_mii_read_reg_ex(qdev, PETBI_TBI_CTRL, ®, PHYAddr[qdev->mac_index]); reg |= PETBI_TBI_AUTO_SENSE; - ql_mii_write_reg_ex(qdev, PETBI_TBI_CTRL, reg, + ql_mii_write_reg_ex(qdev, PETBI_TBI_CTRL, reg, PHYAddr[qdev->mac_index]); ql_mii_write_reg_ex(qdev, PETBI_NEG_ADVER, - PETBI_NEG_PAUSE | PETBI_NEG_DUPLEX, + PETBI_NEG_PAUSE | PETBI_NEG_DUPLEX, PHYAddr[qdev->mac_index]); ql_mii_write_reg_ex(qdev, PETBI_CONTROL_REG, @@ -945,7 +945,7 @@ static void phyAgereSpecificInit(struct ql3_adapter *qdev, u32 miiAddr) ql_mii_write_reg_ex(qdev, 0x10, 0x2806, miiAddr); /* Write new PHYAD w/bit 5 set */ ql_mii_write_reg_ex(qdev, 0x11, 0x0020 | (PHYAddr[qdev->mac_index] >> 8), miiAddr); - /* + /* * Disable diagnostic mode bit 2 = 0 * Power up device bit 11 = 0 * Link up (on) and activity (blink) @@ -955,18 +955,18 @@ static void phyAgereSpecificInit(struct ql3_adapter *qdev, u32 miiAddr) ql_mii_write_reg(qdev, 0x1c, 0xfaf0); } -static PHY_DEVICE_et getPhyType (struct ql3_adapter *qdev, +static PHY_DEVICE_et getPhyType (struct ql3_adapter *qdev, u16 phyIdReg0, u16 phyIdReg1) { PHY_DEVICE_et result = PHY_TYPE_UNKNOWN; - u32 oui; + u32 oui; u16 model; - int i; + int i; if (phyIdReg0 == 0xffff) { return result; } - + if (phyIdReg1 == 0xffff) { return result; } @@ -984,7 +984,7 @@ static PHY_DEVICE_et getPhyType (struct ql3_adapter *qdev, printk(KERN_INFO "%s: Phy: %s\n", qdev->ndev->name, PHY_DEVICES[i].name); - + break; } } @@ -1033,7 +1033,7 @@ static int ql_is_full_dup(struct ql3_adapter *qdev) { if (ql_mii_read_reg(qdev, 0x1A, ®)) return 0; - + return ((reg & 0x0080) && (reg & 0x1000)) != 0; } case PHY_VITESSE_VSC8211: @@ -1082,19 +1082,19 @@ static int PHY_Setup(struct ql3_adapter *qdev) /* Check if we have a Agere PHY */ if ((reg1 == 0xffff) || (reg2 == 0xffff)) { - /* Determine which MII address we should be using + /* Determine which MII address we should be using determined by the index of the card */ if (qdev->mac_index == 0) { miiAddr = MII_AGERE_ADDR_1; } else { miiAddr = MII_AGERE_ADDR_2; } - + err =ql_mii_read_reg_ex(qdev, PHY_ID_0_REG, ®1, miiAddr); if(err != 0) { printk(KERN_ERR "%s: Could not read from reg PHY_ID_0_REG after Agere detected\n", qdev->ndev->name); - return err; + return err; } err = ql_mii_read_reg_ex(qdev, PHY_ID_1_REG, ®2, miiAddr); @@ -1103,9 +1103,9 @@ static int PHY_Setup(struct ql3_adapter *qdev) qdev->ndev->name); return err; } - + /* We need to remember to initialize the Agere PHY */ - agereAddrChangeNeeded = true; + agereAddrChangeNeeded = true; } /* Determine the particular PHY we have on board to apply @@ -1114,7 +1114,7 @@ static int PHY_Setup(struct ql3_adapter *qdev) if ((qdev->phyType == PHY_AGERE_ET1011C) && agereAddrChangeNeeded) { /* need this here so address gets changed */ - phyAgereSpecificInit(qdev, miiAddr); + phyAgereSpecificInit(qdev, miiAddr); } else if (qdev->phyType == PHY_TYPE_UNKNOWN) { printk(KERN_ERR "%s: PHY is unknown\n", qdev->ndev->name); return -EIO; @@ -1427,7 +1427,7 @@ static int ql_this_adapter_controls_port(struct ql3_adapter *qdev) static void ql_phy_reset_ex(struct ql3_adapter *qdev) { - ql_mii_write_reg_ex(qdev, CONTROL_REG, PHY_CTRL_SOFT_RESET, + ql_mii_write_reg_ex(qdev, CONTROL_REG, PHY_CTRL_SOFT_RESET, PHYAddr[qdev->mac_index]); } @@ -1438,7 +1438,7 @@ static void ql_phy_start_neg_ex(struct ql3_adapter *qdev) if(qdev->phyType == PHY_AGERE_ET1011C) { /* turn off external loopback */ - ql_mii_write_reg(qdev, 0x13, 0x0000); + ql_mii_write_reg(qdev, 0x13, 0x0000); } if(qdev->mac_index == 0) @@ -1452,23 +1452,23 @@ static void ql_phy_start_neg_ex(struct ql3_adapter *qdev) portConfiguration = PORT_CONFIG_DEFAULT; /* Set the 1000 advertisements */ - ql_mii_read_reg_ex(qdev, PHY_GIG_CONTROL, ®, + ql_mii_read_reg_ex(qdev, PHY_GIG_CONTROL, ®, PHYAddr[qdev->mac_index]); reg &= ~PHY_GIG_ALL_PARAMS; - if(portConfiguration & + if(portConfiguration & PORT_CONFIG_FULL_DUPLEX_ENABLED & PORT_CONFIG_1000MB_SPEED) { reg |= PHY_GIG_ADV_1000F; } - - if(portConfiguration & + + if(portConfiguration & PORT_CONFIG_HALF_DUPLEX_ENABLED & PORT_CONFIG_1000MB_SPEED) { reg |= PHY_GIG_ADV_1000H; } - ql_mii_write_reg_ex(qdev, PHY_GIG_CONTROL, reg, + ql_mii_write_reg_ex(qdev, PHY_GIG_CONTROL, reg, PHYAddr[qdev->mac_index]); /* Set the 10/100 & pause negotiation advertisements */ @@ -1482,7 +1482,7 @@ static void ql_phy_start_neg_ex(struct ql3_adapter *qdev) if(portConfiguration & PORT_CONFIG_FULL_DUPLEX_ENABLED) { if(portConfiguration & PORT_CONFIG_100MB_SPEED) reg |= PHY_NEG_ADV_100F; - + if(portConfiguration & PORT_CONFIG_10MB_SPEED) reg |= PHY_NEG_ADV_10F; } @@ -1490,22 +1490,22 @@ static void ql_phy_start_neg_ex(struct ql3_adapter *qdev) if(portConfiguration & PORT_CONFIG_HALF_DUPLEX_ENABLED) { if(portConfiguration & PORT_CONFIG_100MB_SPEED) reg |= PHY_NEG_ADV_100H; - + if(portConfiguration & PORT_CONFIG_10MB_SPEED) reg |= PHY_NEG_ADV_10H; } if(portConfiguration & PORT_CONFIG_1000MB_SPEED) { - reg |= 1; + reg |= 1; } - ql_mii_write_reg_ex(qdev, PHY_NEG_ADVER, reg, + ql_mii_write_reg_ex(qdev, PHY_NEG_ADVER, reg, PHYAddr[qdev->mac_index]); ql_mii_read_reg_ex(qdev, CONTROL_REG, ®, PHYAddr[qdev->mac_index]); - - ql_mii_write_reg_ex(qdev, CONTROL_REG, + + ql_mii_write_reg_ex(qdev, CONTROL_REG, reg | PHY_CTRL_RESTART_NEG | PHY_CTRL_AUTO_NEG, PHYAddr[qdev->mac_index]); } @@ -1660,7 +1660,7 @@ static void ql_link_state_machine(struct ql3_adapter *qdev) "%s: Reset in progress, skip processing link " "state.\n", qdev->ndev->name); - spin_unlock_irqrestore(&qdev->hw_lock, hw_flags); + spin_unlock_irqrestore(&qdev->hw_lock, hw_flags); return; } @@ -1752,7 +1752,7 @@ static int ql_mii_setup(struct ql3_adapter *qdev) return -1; if (qdev->device_id == QL3032_DEVICE_ID) - ql_write_page0_reg(qdev, + ql_write_page0_reg(qdev, &port_regs->macMIIMgmtControlReg, 0x0f00000); /* Divide 125MHz clock by 28 to meet PHY timing requirements */ @@ -1936,7 +1936,7 @@ static int ql_populate_free_queue(struct ql3_adapter *qdev) err = pci_dma_mapping_error(map); if(err) { - printk(KERN_ERR "%s: PCI mapping failed with error: %d\n", + printk(KERN_ERR "%s: PCI mapping failed with error: %d\n", qdev->ndev->name, err); dev_kfree_skb(lrg_buf_cb->skb); lrg_buf_cb->skb = NULL; @@ -2044,7 +2044,7 @@ static void ql_process_mac_tx_intr(struct ql3_adapter *qdev, if(mac_rsp->flags & OB_MAC_IOCB_RSP_S) { printk(KERN_WARNING "Frame short but, frame was padded and sent.\n"); } - + tx_cb = &qdev->tx_buf[mac_rsp->transaction_id]; /* Check the transmit response flags for any errors */ @@ -2108,13 +2108,13 @@ static struct ql_rcv_buf_cb *ql_get_lbuf(struct ql3_adapter *qdev) /* * The difference between 3022 and 3032 for inbound completions: - * 3022 uses two buffers per completion. The first buffer contains - * (some) header info, the second the remainder of the headers plus - * the data. For this chip we reserve some space at the top of the - * receive buffer so that the header info in buffer one can be - * prepended to the buffer two. Buffer two is the sent up while + * 3022 uses two buffers per completion. The first buffer contains + * (some) header info, the second the remainder of the headers plus + * the data. For this chip we reserve some space at the top of the + * receive buffer so that the header info in buffer one can be + * prepended to the buffer two. Buffer two is the sent up while * buffer one is returned to the hardware to be reused. - * 3032 receives all of it's data and headers in one buffer for a + * 3032 receives all of it's data and headers in one buffer for a * simpler process. 3032 also supports checksum verification as * can be seen in ql_process_macip_rx_intr(). */ @@ -2205,13 +2205,13 @@ static void ql_process_macip_rx_intr(struct ql3_adapter *qdev, skb_push(skb2, size), size); } else { u16 checksum = le16_to_cpu(ib_ip_rsp_ptr->checksum); - if (checksum & - (IB_IP_IOCB_RSP_3032_ICE | - IB_IP_IOCB_RSP_3032_CE)) { + if (checksum & + (IB_IP_IOCB_RSP_3032_ICE | + IB_IP_IOCB_RSP_3032_CE)) { printk(KERN_ERR "%s: Bad checksum for this %s packet, checksum = %x.\n", __func__, - ((checksum & + ((checksum & IB_IP_IOCB_RSP_3032_TCP) ? "TCP" : "UDP"),checksum); } else if ((checksum & IB_IP_IOCB_RSP_3032_TCP) || @@ -2394,12 +2394,12 @@ static irqreturn_t ql3xxx_isr(int irq, void *dev_id) } /* - * Get the total number of segments needed for the + * Get the total number of segments needed for the * given number of fragments. This is necessary because * outbound address lists (OAL) will be used when more than - * two frags are given. Each address list has 5 addr/len + * two frags are given. Each address list has 5 addr/len * pairs. The 5th pair in each AOL is used to point to - * the next AOL if more frags are coming. + * the next AOL if more frags are coming. * That is why the frags:segment count ratio is not linear. */ static int ql_get_seg_count(struct ql3_adapter *qdev, @@ -2476,12 +2476,12 @@ static int ql_send_map(struct ql3_adapter *qdev, err = pci_dma_mapping_error(map); if(err) { - printk(KERN_ERR "%s: PCI mapping failed with error: %d\n", + printk(KERN_ERR "%s: PCI mapping failed with error: %d\n", qdev->ndev->name, err); return NETDEV_TX_BUSY; } - + oal_entry = (struct oal_entry *)&mac_iocb_ptr->buf_addr0_low; oal_entry->dma_lo = cpu_to_le32(LS_64BITS(map)); oal_entry->dma_hi = cpu_to_le32(MS_64BITS(map)); @@ -2511,7 +2511,7 @@ static int ql_send_map(struct ql3_adapter *qdev, err = pci_dma_mapping_error(map); if(err) { - printk(KERN_ERR "%s: PCI mapping outbound address list with error: %d\n", + printk(KERN_ERR "%s: PCI mapping outbound address list with error: %d\n", qdev->ndev->name, err); goto map_error; } @@ -2537,7 +2537,7 @@ static int ql_send_map(struct ql3_adapter *qdev, err = pci_dma_mapping_error(map); if(err) { - printk(KERN_ERR "%s: PCI mapping frags failed with error: %d\n", + printk(KERN_ERR "%s: PCI mapping frags failed with error: %d\n", qdev->ndev->name, err); goto map_error; } @@ -2558,10 +2558,10 @@ static int ql_send_map(struct ql3_adapter *qdev, map_error: /* A PCI mapping failed and now we will need to back out - * We need to traverse through the oal's and associated pages which + * We need to traverse through the oal's and associated pages which * have been mapped and now we must unmap them to clean up properly */ - + seg = 1; oal_entry = (struct oal_entry *)&mac_iocb_ptr->buf_addr0_low; oal = tx_cb->oal; @@ -2599,11 +2599,11 @@ map_error: * The difference between 3022 and 3032 sends: * 3022 only supports a simple single segment transmission. * 3032 supports checksumming and scatter/gather lists (fragments). - * The 3032 supports sglists by using the 3 addr/len pairs (ALP) - * in the IOCB plus a chain of outbound address lists (OAL) that - * each contain 5 ALPs. The last ALP of the IOCB (3rd) or OAL (5th) - * will used to point to an OAL when more ALP entries are required. - * The IOCB is always the top of the chain followed by one or more + * The 3032 supports sglists by using the 3 addr/len pairs (ALP) + * in the IOCB plus a chain of outbound address lists (OAL) that + * each contain 5 ALPs. The last ALP of the IOCB (3rd) or OAL (5th) + * will used to point to an OAL when more ALP entries are required. + * The IOCB is always the top of the chain followed by one or more * OALs (when necessary). */ static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev) @@ -2617,14 +2617,14 @@ static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev) if (unlikely(atomic_read(&qdev->tx_count) < 2)) { return NETDEV_TX_BUSY; } - + tx_cb = &qdev->tx_buf[qdev->req_producer_index] ; if((tx_cb->seg_count = ql_get_seg_count(qdev, (skb_shinfo(skb)->nr_frags))) == -1) { printk(KERN_ERR PFX"%s: invalid segment count!\n",__func__); return NETDEV_TX_OK; } - + mac_iocb_ptr = tx_cb->queue_entry; memset((void *)mac_iocb_ptr, 0, sizeof(struct ob_mac_iocb_req)); mac_iocb_ptr->opcode = qdev->mac_ob_opcode; @@ -2636,12 +2636,12 @@ static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev) if (qdev->device_id == QL3032_DEVICE_ID && skb->ip_summed == CHECKSUM_PARTIAL) ql_hw_csum_setup(skb, mac_iocb_ptr); - + if(ql_send_map(qdev,mac_iocb_ptr,tx_cb,skb) != NETDEV_TX_OK) { printk(KERN_ERR PFX"%s: Could not map the segments!\n",__func__); return NETDEV_TX_BUSY; } - + wmb(); qdev->req_producer_index++; if (qdev->req_producer_index == NUM_REQ_Q_ENTRIES) @@ -2739,7 +2739,7 @@ static int ql_alloc_buffer_queues(struct ql3_adapter *qdev) "%s: qdev->lrg_buf alloc failed.\n", qdev->ndev->name); return -ENOMEM; } - + qdev->lrg_buf_q_alloc_virt_addr = pci_alloc_consistent(qdev->pdev, qdev->lrg_buf_q_alloc_size, diff --git a/drivers/net/qla3xxx.h b/drivers/net/qla3xxx.h old mode 100755 new mode 100644 index 483840f7fc1..fbcb0b94963 --- a/drivers/net/qla3xxx.h +++ b/drivers/net/qla3xxx.h @@ -556,7 +556,7 @@ enum { IP_ADDR_INDEX_REG_FUNC_3_SEC = 0x0007, IP_ADDR_INDEX_REG_6 = 0x0008, IP_ADDR_INDEX_REG_OFFSET_MASK = 0x0030, - IP_ADDR_INDEX_REG_E = 0x0040, + IP_ADDR_INDEX_REG_E = 0x0040, }; enum { QL3032_PORT_CONTROL_DS = 0x0001, @@ -1112,7 +1112,7 @@ struct ql_rcv_buf_cb { * OAL has 5 entries: * 1 thru 4 point to frags * fifth points to next oal. - */ + */ #define MAX_OAL_CNT ((MAX_SKB_FRAGS-1)/4 + 1) struct oal_entry { @@ -1137,7 +1137,7 @@ struct ql_tx_buf_cb { struct ob_mac_iocb_req *queue_entry ; int seg_count; struct oal *oal; - struct map_list map[MAX_SKB_FRAGS+1]; + struct map_list map[MAX_SKB_FRAGS+1]; }; /* definitions for type field */ -- cgit v1.2.3-70-g09d2 From af289e803fdf2fcd19cf4a57c3c896dba146c756 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 3 Oct 2007 13:03:54 -0500 Subject: pasemi_mac: enable iommu support pasemi_mac: enable iommu support Enable IOMMU support for pasemi_mac, but avoid using it on non-partitioned systems for performance reasons. The user can override this by selecting the PPC_PASEMI_IOMMU_DMA_FORCE configuration option. Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik --- arch/powerpc/platforms/pasemi/Kconfig | 10 +++++++ arch/powerpc/platforms/pasemi/iommu.c | 15 +++++++---- drivers/net/pasemi_mac.c | 50 ++++++++++++++++++++++++++--------- drivers/net/pasemi_mac.h | 8 ++++-- 4 files changed, 63 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/arch/powerpc/platforms/pasemi/Kconfig b/arch/powerpc/platforms/pasemi/Kconfig index 95cd90fd81c..e95261ef6f9 100644 --- a/arch/powerpc/platforms/pasemi/Kconfig +++ b/arch/powerpc/platforms/pasemi/Kconfig @@ -18,6 +18,16 @@ config PPC_PASEMI_IOMMU help IOMMU support for PA6T-1682M +config PPC_PASEMI_IOMMU_DMA_FORCE + bool "Force DMA engine to use IOMMU" + depends on PPC_PASEMI_IOMMU + help + This option forces the use of the IOMMU also for the + DMA engine. Otherwise the kernel will use it only when + running under a hypervisor. + + If in doubt, say "N". + config PPC_PASEMI_MDIO depends on PHYLIB tristate "MDIO support via GPIO" diff --git a/arch/powerpc/platforms/pasemi/iommu.c b/arch/powerpc/platforms/pasemi/iommu.c index 9014d55c717..a1111b5c6cb 100644 --- a/arch/powerpc/platforms/pasemi/iommu.c +++ b/arch/powerpc/platforms/pasemi/iommu.c @@ -25,6 +25,7 @@ #include #include #include +#include #define IOBMAP_PAGE_SHIFT 12 @@ -175,13 +176,17 @@ static void pci_dma_dev_setup_pasemi(struct pci_dev *dev) { pr_debug("pci_dma_dev_setup, dev %p (%s)\n", dev, pci_name(dev)); - /* DMA device is untranslated, but all other PCI-e goes through - * the IOMMU +#if !defined(CONFIG_PPC_PASEMI_IOMMU_DMA_FORCE) + /* For non-LPAR environment, don't translate anything for the DMA + * engine. The exception to this is if the user has enabled + * CONFIG_PPC_PASEMI_IOMMU_DMA_FORCE at build time. */ - if (dev->vendor == 0x1959 && dev->device == 0xa007) + if (dev->vendor == 0x1959 && dev->device == 0xa007 && + !firmware_has_feature(FW_FEATURE_LPAR)) dev->dev.archdata.dma_ops = &dma_direct_ops; - else - dev->dev.archdata.dma_data = &iommu_table_iobmap; +#endif + + dev->dev.archdata.dma_data = &iommu_table_iobmap; } static void pci_dma_bus_setup_null(struct pci_bus *b) { } diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 31ad2b9093a..9f9a421c99b 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -34,6 +34,7 @@ #include #include +#include #include "pasemi_mac.h" @@ -89,6 +90,15 @@ MODULE_PARM_DESC(debug, "PA Semi MAC bitmapped debugging message enable value"); static struct pasdma_status *dma_status; +static int translation_enabled(void) +{ +#if defined(CONFIG_PPC_PASEMI_IOMMU_DMA_FORCE) + return 1; +#else + return firmware_has_feature(FW_FEATURE_LPAR); +#endif +} + static void write_iob_reg(struct pasemi_mac *mac, unsigned int reg, unsigned int val) { @@ -193,6 +203,7 @@ static int pasemi_mac_setup_rx_resources(struct net_device *dev) struct pasemi_mac_rxring *ring; struct pasemi_mac *mac = netdev_priv(dev); int chan_id = mac->dma_rxch; + unsigned int cfg; ring = kzalloc(sizeof(*ring), GFP_KERNEL); @@ -232,20 +243,28 @@ static int pasemi_mac_setup_rx_resources(struct net_device *dev) PAS_DMA_RXCHAN_BASEU_BRBH(ring->dma >> 32) | PAS_DMA_RXCHAN_BASEU_SIZ(RX_RING_SIZE >> 3)); - write_dma_reg(mac, PAS_DMA_RXCHAN_CFG(chan_id), - PAS_DMA_RXCHAN_CFG_HBU(2)); + cfg = PAS_DMA_RXCHAN_CFG_HBU(2); + + if (translation_enabled()) + cfg |= PAS_DMA_RXCHAN_CFG_CTR; + + write_dma_reg(mac, PAS_DMA_RXCHAN_CFG(chan_id), cfg); write_dma_reg(mac, PAS_DMA_RXINT_BASEL(mac->dma_if), - PAS_DMA_RXINT_BASEL_BRBL(__pa(ring->buffers))); + PAS_DMA_RXINT_BASEL_BRBL(ring->buf_dma)); write_dma_reg(mac, PAS_DMA_RXINT_BASEU(mac->dma_if), - PAS_DMA_RXINT_BASEU_BRBH(__pa(ring->buffers) >> 32) | + PAS_DMA_RXINT_BASEU_BRBH(ring->buf_dma >> 32) | PAS_DMA_RXINT_BASEU_SIZ(RX_RING_SIZE >> 3)); - write_dma_reg(mac, PAS_DMA_RXINT_CFG(mac->dma_if), - PAS_DMA_RXINT_CFG_DHL(3) | PAS_DMA_RXINT_CFG_L2 | - PAS_DMA_RXINT_CFG_LW | PAS_DMA_RXINT_CFG_RBP | - PAS_DMA_RXINT_CFG_HEN); + cfg = PAS_DMA_RXINT_CFG_DHL(3) | PAS_DMA_RXINT_CFG_L2 | + PAS_DMA_RXINT_CFG_LW | PAS_DMA_RXINT_CFG_RBP | + PAS_DMA_RXINT_CFG_HEN; + + if (translation_enabled()) + cfg |= PAS_DMA_RXINT_CFG_ITRR | PAS_DMA_RXINT_CFG_ITR; + + write_dma_reg(mac, PAS_DMA_RXINT_CFG(mac->dma_if), cfg); ring->next_to_fill = 0; ring->next_to_clean = 0; @@ -275,6 +294,7 @@ static int pasemi_mac_setup_tx_resources(struct net_device *dev) u32 val; int chan_id = mac->dma_txch; struct pasemi_mac_txring *ring; + unsigned int cfg; ring = kzalloc(sizeof(*ring), GFP_KERNEL); if (!ring) @@ -304,11 +324,15 @@ static int pasemi_mac_setup_tx_resources(struct net_device *dev) write_dma_reg(mac, PAS_DMA_TXCHAN_BASEU(chan_id), val); - write_dma_reg(mac, PAS_DMA_TXCHAN_CFG(chan_id), - PAS_DMA_TXCHAN_CFG_TY_IFACE | - PAS_DMA_TXCHAN_CFG_TATTR(mac->dma_if) | - PAS_DMA_TXCHAN_CFG_UP | - PAS_DMA_TXCHAN_CFG_WT(2)); + cfg = PAS_DMA_TXCHAN_CFG_TY_IFACE | + PAS_DMA_TXCHAN_CFG_TATTR(mac->dma_if) | + PAS_DMA_TXCHAN_CFG_UP | + PAS_DMA_TXCHAN_CFG_WT(2); + + if (translation_enabled()) + cfg |= PAS_DMA_TXCHAN_CFG_TRD | PAS_DMA_TXCHAN_CFG_TRR; + + write_dma_reg(mac, PAS_DMA_TXCHAN_CFG(chan_id), cfg); ring->next_to_fill = 0; ring->next_to_clean = 0; diff --git a/drivers/net/pasemi_mac.h b/drivers/net/pasemi_mac.h index 1a120408cf3..60368df7263 100644 --- a/drivers/net/pasemi_mac.h +++ b/drivers/net/pasemi_mac.h @@ -212,6 +212,7 @@ enum { #define PAS_DMA_RXINT_CFG_DHL_S 24 #define PAS_DMA_RXINT_CFG_DHL(x) (((x) << PAS_DMA_RXINT_CFG_DHL_S) & \ PAS_DMA_RXINT_CFG_DHL_M) +#define PAS_DMA_RXINT_CFG_ITR 0x00400000 #define PAS_DMA_RXINT_CFG_LW 0x00200000 #define PAS_DMA_RXINT_CFG_L2 0x00100000 #define PAS_DMA_RXINT_CFG_HEN 0x00080000 @@ -258,9 +259,11 @@ enum { #define PAS_DMA_TXCHAN_CFG_WT_S 6 #define PAS_DMA_TXCHAN_CFG_WT(x) (((x) << PAS_DMA_TXCHAN_CFG_WT_S) & \ PAS_DMA_TXCHAN_CFG_WT_M) -#define PAS_DMA_TXCHAN_CFG_CF 0x00001000 /* Clean first line */ -#define PAS_DMA_TXCHAN_CFG_CL 0x00002000 /* Clean last line */ +#define PAS_DMA_TXCHAN_CFG_TRD 0x00010000 /* translate data */ +#define PAS_DMA_TXCHAN_CFG_TRR 0x00008000 /* translate rings */ #define PAS_DMA_TXCHAN_CFG_UP 0x00004000 /* update tx descr when sent */ +#define PAS_DMA_TXCHAN_CFG_CL 0x00002000 /* Clean last line */ +#define PAS_DMA_TXCHAN_CFG_CF 0x00001000 /* Clean first line */ #define PAS_DMA_TXCHAN_INCR(c) (0x310+(c)*_PAS_DMA_TXCHAN_STRIDE) #define PAS_DMA_TXCHAN_BASEL(c) (0x318+(c)*_PAS_DMA_TXCHAN_STRIDE) #define PAS_DMA_TXCHAN_BASEL_BRBL_M 0xffffffc0 @@ -294,6 +297,7 @@ enum { #define PAS_DMA_RXCHAN_CCMDSTA_FD 0x00001000 #define PAS_DMA_RXCHAN_CCMDSTA_DT 0x00000800 #define PAS_DMA_RXCHAN_CFG(c) (0x804+(c)*_PAS_DMA_RXCHAN_STRIDE) +#define PAS_DMA_RXCHAN_CFG_CTR 0x00000400 #define PAS_DMA_RXCHAN_CFG_HBU_M 0x00000380 #define PAS_DMA_RXCHAN_CFG_HBU_S 7 #define PAS_DMA_RXCHAN_CFG_HBU(x) (((x) << PAS_DMA_RXCHAN_CFG_HBU_S) & \ -- cgit v1.2.3-70-g09d2 From a3138df9f20e726c517f8df7387b5d83f5df5566 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 9 Oct 2007 01:54:01 -0700 Subject: [NIU]: Add Sun Neptune ethernet driver. With cleanup suggestions and bugs spotted by Stephen Hemminger, Ingo Oeser, Matheos Worku, and Oliver Hartkopp. Signed-off-by: David S. Miller --- drivers/net/Kconfig | 7 + drivers/net/Makefile | 1 + drivers/net/niu.c | 7939 ++++++++++++++++++++++++++++++++++++++++++++++++++ drivers/net/niu.h | 3222 ++++++++++++++++++++ 4 files changed, 11169 insertions(+) create mode 100644 drivers/net/niu.c create mode 100644 drivers/net/niu.h (limited to 'drivers') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 0e48b294200..9c635a237a9 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2594,6 +2594,13 @@ config NETXEN_NIC help This enables the support for NetXen's Gigabit Ethernet card. +config NIU + tristate "Sun Neptune 10Gbit Ethernet support" + depends on PCI + help + This enables support for cards based upon Sun's + Neptune chipset. + config PASEMI_MAC tristate "PA Semi 1/10Gbit MAC" depends on PPC64 && PCI diff --git a/drivers/net/Makefile b/drivers/net/Makefile index eb5c655e26d..d2e0f35da42 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -241,3 +241,4 @@ obj-$(CONFIG_NETCONSOLE) += netconsole.o obj-$(CONFIG_FS_ENET) += fs_enet/ obj-$(CONFIG_NETXEN_NIC) += netxen/ +obj-$(CONFIG_NIU) += niu.o diff --git a/drivers/net/niu.c b/drivers/net/niu.c new file mode 100644 index 00000000000..43bfe7e6b6f --- /dev/null +++ b/drivers/net/niu.c @@ -0,0 +1,7939 @@ +/* niu.c: Neptune ethernet driver. + * + * Copyright (C) 2007 David S. Miller (davem@davemloft.net) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef CONFIG_SPARC64 +#include +#endif + +#include "niu.h" + +#define DRV_MODULE_NAME "niu" +#define PFX DRV_MODULE_NAME ": " +#define DRV_MODULE_VERSION "0.5" +#define DRV_MODULE_RELDATE "October 5, 2007" + +static char version[] __devinitdata = + DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; + +MODULE_AUTHOR("David S. Miller (davem@davemloft.net)"); +MODULE_DESCRIPTION("NIU ethernet driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_MODULE_VERSION); + +#ifndef DMA_44BIT_MASK +#define DMA_44BIT_MASK 0x00000fffffffffffULL +#endif + +#ifndef readq +static u64 readq(void __iomem *reg) +{ + return (((u64)readl(reg + 0x4UL) << 32) | + (u64)readl(reg)); +} + +static void writeq(u64 val, void __iomem *reg) +{ + writel(val & 0xffffffff, reg); + writel(val >> 32, reg + 0x4UL); +} +#endif + +static struct pci_device_id niu_pci_tbl[] = { + {PCI_DEVICE(PCI_VENDOR_ID_SUN, 0xabcd)}, + {} +}; + +MODULE_DEVICE_TABLE(pci, niu_pci_tbl); + +#define NIU_TX_TIMEOUT (5 * HZ) + +#define nr64(reg) readq(np->regs + (reg)) +#define nw64(reg, val) writeq((val), np->regs + (reg)) + +#define nr64_mac(reg) readq(np->mac_regs + (reg)) +#define nw64_mac(reg, val) writeq((val), np->mac_regs + (reg)) + +#define nr64_ipp(reg) readq(np->regs + np->ipp_off + (reg)) +#define nw64_ipp(reg, val) writeq((val), np->regs + np->ipp_off + (reg)) + +#define nr64_pcs(reg) readq(np->regs + np->pcs_off + (reg)) +#define nw64_pcs(reg, val) writeq((val), np->regs + np->pcs_off + (reg)) + +#define nr64_xpcs(reg) readq(np->regs + np->xpcs_off + (reg)) +#define nw64_xpcs(reg, val) writeq((val), np->regs + np->xpcs_off + (reg)) + +#define NIU_MSG_DEFAULT (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK) + +static int niu_debug; +static int debug = -1; +module_param(debug, int, 0); +MODULE_PARM_DESC(debug, "NIU debug level"); + +#define niudbg(TYPE, f, a...) \ +do { if ((np)->msg_enable & NETIF_MSG_##TYPE) \ + printk(KERN_DEBUG PFX f, ## a); \ +} while (0) + +#define niuinfo(TYPE, f, a...) \ +do { if ((np)->msg_enable & NETIF_MSG_##TYPE) \ + printk(KERN_INFO PFX f, ## a); \ +} while (0) + +#define niuwarn(TYPE, f, a...) \ +do { if ((np)->msg_enable & NETIF_MSG_##TYPE) \ + printk(KERN_WARNING PFX f, ## a); \ +} while (0) + +#define niu_lock_parent(np, flags) \ + spin_lock_irqsave(&np->parent->lock, flags) +#define niu_unlock_parent(np, flags) \ + spin_unlock_irqrestore(&np->parent->lock, flags) + +static int __niu_wait_bits_clear_mac(struct niu *np, unsigned long reg, + u64 bits, int limit, int delay) +{ + while (--limit >= 0) { + u64 val = nr64_mac(reg); + + if (!(val & bits)) + break; + udelay(delay); + } + if (limit < 0) + return -ENODEV; + return 0; +} + +static int __niu_set_and_wait_clear_mac(struct niu *np, unsigned long reg, + u64 bits, int limit, int delay, + const char *reg_name) +{ + int err; + + nw64_mac(reg, bits); + err = __niu_wait_bits_clear_mac(np, reg, bits, limit, delay); + if (err) + dev_err(np->device, PFX "%s: bits (%llx) of register %s " + "would not clear, val[%llx]\n", + np->dev->name, (unsigned long long) bits, reg_name, + (unsigned long long) nr64_mac(reg)); + return err; +} + +#define niu_set_and_wait_clear_mac(NP, REG, BITS, LIMIT, DELAY, REG_NAME) \ +({ BUILD_BUG_ON(LIMIT <= 0 || DELAY < 0); \ + __niu_set_and_wait_clear_mac(NP, REG, BITS, LIMIT, DELAY, REG_NAME); \ +}) + +static int __niu_wait_bits_clear_ipp(struct niu *np, unsigned long reg, + u64 bits, int limit, int delay) +{ + while (--limit >= 0) { + u64 val = nr64_ipp(reg); + + if (!(val & bits)) + break; + udelay(delay); + } + if (limit < 0) + return -ENODEV; + return 0; +} + +static int __niu_set_and_wait_clear_ipp(struct niu *np, unsigned long reg, + u64 bits, int limit, int delay, + const char *reg_name) +{ + int err; + u64 val; + + val = nr64_ipp(reg); + val |= bits; + nw64_ipp(reg, val); + + err = __niu_wait_bits_clear_ipp(np, reg, bits, limit, delay); + if (err) + dev_err(np->device, PFX "%s: bits (%llx) of register %s " + "would not clear, val[%llx]\n", + np->dev->name, (unsigned long long) bits, reg_name, + (unsigned long long) nr64_ipp(reg)); + return err; +} + +#define niu_set_and_wait_clear_ipp(NP, REG, BITS, LIMIT, DELAY, REG_NAME) \ +({ BUILD_BUG_ON(LIMIT <= 0 || DELAY < 0); \ + __niu_set_and_wait_clear_ipp(NP, REG, BITS, LIMIT, DELAY, REG_NAME); \ +}) + +static int __niu_wait_bits_clear(struct niu *np, unsigned long reg, + u64 bits, int limit, int delay) +{ + while (--limit >= 0) { + u64 val = nr64(reg); + + if (!(val & bits)) + break; + udelay(delay); + } + if (limit < 0) + return -ENODEV; + return 0; +} + +#define niu_wait_bits_clear(NP, REG, BITS, LIMIT, DELAY) \ +({ BUILD_BUG_ON(LIMIT <= 0 || DELAY < 0); \ + __niu_wait_bits_clear(NP, REG, BITS, LIMIT, DELAY); \ +}) + +static int __niu_set_and_wait_clear(struct niu *np, unsigned long reg, + u64 bits, int limit, int delay, + const char *reg_name) +{ + int err; + + nw64(reg, bits); + err = __niu_wait_bits_clear(np, reg, bits, limit, delay); + if (err) + dev_err(np->device, PFX "%s: bits (%llx) of register %s " + "would not clear, val[%llx]\n", + np->dev->name, (unsigned long long) bits, reg_name, + (unsigned long long) nr64(reg)); + return err; +} + +#define niu_set_and_wait_clear(NP, REG, BITS, LIMIT, DELAY, REG_NAME) \ +({ BUILD_BUG_ON(LIMIT <= 0 || DELAY < 0); \ + __niu_set_and_wait_clear(NP, REG, BITS, LIMIT, DELAY, REG_NAME); \ +}) + +static void niu_ldg_rearm(struct niu *np, struct niu_ldg *lp, int on) +{ + u64 val = (u64) lp->timer; + + if (on) + val |= LDG_IMGMT_ARM; + + nw64(LDG_IMGMT(lp->ldg_num), val); +} + +static int niu_ldn_irq_enable(struct niu *np, int ldn, int on) +{ + unsigned long mask_reg, bits; + u64 val; + + if (ldn < 0 || ldn > LDN_MAX) + return -EINVAL; + + if (ldn < 64) { + mask_reg = LD_IM0(ldn); + bits = LD_IM0_MASK; + } else { + mask_reg = LD_IM1(ldn - 64); + bits = LD_IM1_MASK; + } + + val = nr64(mask_reg); + if (on) + val &= ~bits; + else + val |= bits; + nw64(mask_reg, val); + + return 0; +} + +static int niu_enable_ldn_in_ldg(struct niu *np, struct niu_ldg *lp, int on) +{ + struct niu_parent *parent = np->parent; + int i; + + for (i = 0; i <= LDN_MAX; i++) { + int err; + + if (parent->ldg_map[i] != lp->ldg_num) + continue; + + err = niu_ldn_irq_enable(np, i, on); + if (err) + return err; + } + return 0; +} + +static int niu_enable_interrupts(struct niu *np, int on) +{ + int i; + + for (i = 0; i < np->num_ldg; i++) { + struct niu_ldg *lp = &np->ldg[i]; + int err; + + err = niu_enable_ldn_in_ldg(np, lp, on); + if (err) + return err; + } + for (i = 0; i < np->num_ldg; i++) + niu_ldg_rearm(np, &np->ldg[i], on); + + return 0; +} + +static u32 phy_encode(u32 type, int port) +{ + return (type << (port * 2)); +} + +static u32 phy_decode(u32 val, int port) +{ + return (val >> (port * 2)) & PORT_TYPE_MASK; +} + +static int mdio_wait(struct niu *np) +{ + int limit = 1000; + u64 val; + + while (--limit > 0) { + val = nr64(MIF_FRAME_OUTPUT); + if ((val >> MIF_FRAME_OUTPUT_TA_SHIFT) & 0x1) + return val & MIF_FRAME_OUTPUT_DATA; + + udelay(10); + } + + return -ENODEV; +} + +static int mdio_read(struct niu *np, int port, int dev, int reg) +{ + int err; + + nw64(MIF_FRAME_OUTPUT, MDIO_ADDR_OP(port, dev, reg)); + err = mdio_wait(np); + if (err < 0) + return err; + + nw64(MIF_FRAME_OUTPUT, MDIO_READ_OP(port, dev)); + return mdio_wait(np); +} + +static int mdio_write(struct niu *np, int port, int dev, int reg, int data) +{ + int err; + + nw64(MIF_FRAME_OUTPUT, MDIO_ADDR_OP(port, dev, reg)); + err = mdio_wait(np); + if (err < 0) + return err; + + nw64(MIF_FRAME_OUTPUT, MDIO_WRITE_OP(port, dev, data)); + err = mdio_wait(np); + if (err < 0) + return err; + + return 0; +} + +static int mii_read(struct niu *np, int port, int reg) +{ + nw64(MIF_FRAME_OUTPUT, MII_READ_OP(port, reg)); + return mdio_wait(np); +} + +static int mii_write(struct niu *np, int port, int reg, int data) +{ + int err; + + nw64(MIF_FRAME_OUTPUT, MII_WRITE_OP(port, reg, data)); + err = mdio_wait(np); + if (err < 0) + return err; + + return 0; +} + +static int esr2_set_tx_cfg(struct niu *np, unsigned long channel, u32 val) +{ + int err; + + err = mdio_write(np, np->port, NIU_ESR2_DEV_ADDR, + ESR2_TI_PLL_TX_CFG_L(channel), + val & 0xffff); + if (!err) + err = mdio_write(np, np->port, NIU_ESR2_DEV_ADDR, + ESR2_TI_PLL_TX_CFG_H(channel), + val >> 16); + return err; +} + +static int esr2_set_rx_cfg(struct niu *np, unsigned long channel, u32 val) +{ + int err; + + err = mdio_write(np, np->port, NIU_ESR2_DEV_ADDR, + ESR2_TI_PLL_RX_CFG_L(channel), + val & 0xffff); + if (!err) + err = mdio_write(np, np->port, NIU_ESR2_DEV_ADDR, + ESR2_TI_PLL_RX_CFG_H(channel), + val >> 16); + return err; +} + +/* Mode is always 10G fiber. */ +static int serdes_init_niu(struct niu *np) +{ + struct niu_link_config *lp = &np->link_config; + u32 tx_cfg, rx_cfg; + unsigned long i; + + tx_cfg = (PLL_TX_CFG_ENTX | PLL_TX_CFG_SWING_1375MV); + rx_cfg = (PLL_RX_CFG_ENRX | PLL_RX_CFG_TERM_0P8VDDT | + PLL_RX_CFG_ALIGN_ENA | PLL_RX_CFG_LOS_LTHRESH | + PLL_RX_CFG_EQ_LP_ADAPTIVE); + + if (lp->loopback_mode == LOOPBACK_PHY) { + u16 test_cfg = PLL_TEST_CFG_LOOPBACK_CML_DIS; + + mdio_write(np, np->port, NIU_ESR2_DEV_ADDR, + ESR2_TI_PLL_TEST_CFG_L, test_cfg); + + tx_cfg |= PLL_TX_CFG_ENTEST; + rx_cfg |= PLL_RX_CFG_ENTEST; + } + + /* Initialize all 4 lanes of the SERDES. */ + for (i = 0; i < 4; i++) { + int err = esr2_set_tx_cfg(np, i, tx_cfg); + if (err) + return err; + } + + for (i = 0; i < 4; i++) { + int err = esr2_set_rx_cfg(np, i, rx_cfg); + if (err) + return err; + } + + return 0; +} + +static int esr_read_rxtx_ctrl(struct niu *np, unsigned long chan, u32 *val) +{ + int err; + + err = mdio_read(np, np->port, NIU_ESR_DEV_ADDR, ESR_RXTX_CTRL_L(chan)); + if (err >= 0) { + *val = (err & 0xffff); + err = mdio_read(np, np->port, NIU_ESR_DEV_ADDR, + ESR_RXTX_CTRL_H(chan)); + if (err >= 0) + *val |= ((err & 0xffff) << 16); + err = 0; + } + return err; +} + +static int esr_read_glue0(struct niu *np, unsigned long chan, u32 *val) +{ + int err; + + err = mdio_read(np, np->port, NIU_ESR_DEV_ADDR, + ESR_GLUE_CTRL0_L(chan)); + if (err >= 0) { + *val = (err & 0xffff); + err = mdio_read(np, np->port, NIU_ESR_DEV_ADDR, + ESR_GLUE_CTRL0_H(chan)); + if (err >= 0) { + *val |= ((err & 0xffff) << 16); + err = 0; + } + } + return err; +} + +static int esr_read_reset(struct niu *np, u32 *val) +{ + int err; + + err = mdio_read(np, np->port, NIU_ESR_DEV_ADDR, + ESR_RXTX_RESET_CTRL_L); + if (err >= 0) { + *val = (err & 0xffff); + err = mdio_read(np, np->port, NIU_ESR_DEV_ADDR, + ESR_RXTX_RESET_CTRL_H); + if (err >= 0) { + *val |= ((err & 0xffff) << 16); + err = 0; + } + } + return err; +} + +static int esr_write_rxtx_ctrl(struct niu *np, unsigned long chan, u32 val) +{ + int err; + + err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR, + ESR_RXTX_CTRL_L(chan), val & 0xffff); + if (!err) + err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR, + ESR_RXTX_CTRL_H(chan), (val >> 16)); + return err; +} + +static int esr_write_glue0(struct niu *np, unsigned long chan, u32 val) +{ + int err; + + err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR, + ESR_GLUE_CTRL0_L(chan), val & 0xffff); + if (!err) + err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR, + ESR_GLUE_CTRL0_H(chan), (val >> 16)); + return err; +} + +static int esr_reset(struct niu *np) +{ + u32 reset; + int err; + + err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR, + ESR_RXTX_RESET_CTRL_L, 0x0000); + if (err) + return err; + err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR, + ESR_RXTX_RESET_CTRL_H, 0xffff); + if (err) + return err; + udelay(200); + + err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR, + ESR_RXTX_RESET_CTRL_L, 0xffff); + if (err) + return err; + udelay(200); + + err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR, + ESR_RXTX_RESET_CTRL_H, 0x0000); + if (err) + return err; + udelay(200); + + err = esr_read_reset(np, &reset); + if (err) + return err; + if (reset != 0) { + dev_err(np->device, PFX "Port %u ESR_RESET " + "did not clear [%08x]\n", + np->port, reset); + return -ENODEV; + } + + return 0; +} + +static int serdes_init_10g(struct niu *np) +{ + struct niu_link_config *lp = &np->link_config; + unsigned long ctrl_reg, test_cfg_reg, i; + u64 ctrl_val, test_cfg_val, sig, mask, val; + int err; + + switch (np->port) { + case 0: + ctrl_reg = ENET_SERDES_0_CTRL_CFG; + test_cfg_reg = ENET_SERDES_0_TEST_CFG; + break; + case 1: + ctrl_reg = ENET_SERDES_1_CTRL_CFG; + test_cfg_reg = ENET_SERDES_1_TEST_CFG; + break; + + default: + return -EINVAL; + } + ctrl_val = (ENET_SERDES_CTRL_SDET_0 | + ENET_SERDES_CTRL_SDET_1 | + ENET_SERDES_CTRL_SDET_2 | + ENET_SERDES_CTRL_SDET_3 | + (0x5 << ENET_SERDES_CTRL_EMPH_0_SHIFT) | + (0x5 << ENET_SERDES_CTRL_EMPH_1_SHIFT) | + (0x5 << ENET_SERDES_CTRL_EMPH_2_SHIFT) | + (0x5 << ENET_SERDES_CTRL_EMPH_3_SHIFT) | + (0x1 << ENET_SERDES_CTRL_LADJ_0_SHIFT) | + (0x1 << ENET_SERDES_CTRL_LADJ_1_SHIFT) | + (0x1 << ENET_SERDES_CTRL_LADJ_2_SHIFT) | + (0x1 << ENET_SERDES_CTRL_LADJ_3_SHIFT)); + test_cfg_val = 0; + + if (lp->loopback_mode == LOOPBACK_PHY) { + test_cfg_val |= ((ENET_TEST_MD_PAD_LOOPBACK << + ENET_SERDES_TEST_MD_0_SHIFT) | + (ENET_TEST_MD_PAD_LOOPBACK << + ENET_SERDES_TEST_MD_1_SHIFT) | + (ENET_TEST_MD_PAD_LOOPBACK << + ENET_SERDES_TEST_MD_2_SHIFT) | + (ENET_TEST_MD_PAD_LOOPBACK << + ENET_SERDES_TEST_MD_3_SHIFT)); + } + + nw64(ctrl_reg, ctrl_val); + nw64(test_cfg_reg, test_cfg_val); + + /* Initialize all 4 lanes of the SERDES. */ + for (i = 0; i < 4; i++) { + u32 rxtx_ctrl, glue0; + + err = esr_read_rxtx_ctrl(np, i, &rxtx_ctrl); + if (err) + return err; + err = esr_read_glue0(np, i, &glue0); + if (err) + return err; + + rxtx_ctrl &= ~(ESR_RXTX_CTRL_VMUXLO); + rxtx_ctrl |= (ESR_RXTX_CTRL_ENSTRETCH | + (2 << ESR_RXTX_CTRL_VMUXLO_SHIFT)); + + glue0 &= ~(ESR_GLUE_CTRL0_SRATE | + ESR_GLUE_CTRL0_THCNT | + ESR_GLUE_CTRL0_BLTIME); + glue0 |= (ESR_GLUE_CTRL0_RXLOSENAB | + (0xf << ESR_GLUE_CTRL0_SRATE_SHIFT) | + (0xff << ESR_GLUE_CTRL0_THCNT_SHIFT) | + (BLTIME_300_CYCLES << + ESR_GLUE_CTRL0_BLTIME_SHIFT)); + + err = esr_write_rxtx_ctrl(np, i, rxtx_ctrl); + if (err) + return err; + err = esr_write_glue0(np, i, glue0); + if (err) + return err; + } + + err = esr_reset(np); + if (err) + return err; + + sig = nr64(ESR_INT_SIGNALS); + switch (np->port) { + case 0: + mask = ESR_INT_SIGNALS_P0_BITS; + val = (ESR_INT_SRDY0_P0 | + ESR_INT_DET0_P0 | + ESR_INT_XSRDY_P0 | + ESR_INT_XDP_P0_CH3 | + ESR_INT_XDP_P0_CH2 | + ESR_INT_XDP_P0_CH1 | + ESR_INT_XDP_P0_CH0); + break; + + case 1: + mask = ESR_INT_SIGNALS_P1_BITS; + val = (ESR_INT_SRDY0_P1 | + ESR_INT_DET0_P1 | + ESR_INT_XSRDY_P1 | + ESR_INT_XDP_P1_CH3 | + ESR_INT_XDP_P1_CH2 | + ESR_INT_XDP_P1_CH1 | + ESR_INT_XDP_P1_CH0); + break; + + default: + return -EINVAL; + } + + if ((sig & mask) != val) { + dev_err(np->device, PFX "Port %u signal bits [%08x] are not " + "[%08x]\n", np->port, (int) (sig & mask), (int) val); + return -ENODEV; + } + + return 0; +} + +static int serdes_init_1g(struct niu *np) +{ + u64 val; + + val = nr64(ENET_SERDES_1_PLL_CFG); + val &= ~ENET_SERDES_PLL_FBDIV2; + switch (np->port) { + case 0: + val |= ENET_SERDES_PLL_HRATE0; + break; + case 1: + val |= ENET_SERDES_PLL_HRATE1; + break; + case 2: + val |= ENET_SERDES_PLL_HRATE2; + break; + case 3: + val |= ENET_SERDES_PLL_HRATE3; + break; + default: + return -EINVAL; + } + nw64(ENET_SERDES_1_PLL_CFG, val); + + return 0; +} + +static int bcm8704_reset(struct niu *np) +{ + int err, limit; + + err = mdio_read(np, np->phy_addr, + BCM8704_PHYXS_DEV_ADDR, MII_BMCR); + if (err < 0) + return err; + err |= BMCR_RESET; + err = mdio_write(np, np->phy_addr, BCM8704_PHYXS_DEV_ADDR, + MII_BMCR, err); + if (err) + return err; + + limit = 1000; + while (--limit >= 0) { + err = mdio_read(np, np->phy_addr, + BCM8704_PHYXS_DEV_ADDR, MII_BMCR); + if (err < 0) + return err; + if (!(err & BMCR_RESET)) + break; + } + if (limit < 0) { + dev_err(np->device, PFX "Port %u PHY will not reset " + "(bmcr=%04x)\n", np->port, (err & 0xffff)); + return -ENODEV; + } + return 0; +} + +/* When written, certain PHY registers need to be read back twice + * in order for the bits to settle properly. + */ +static int bcm8704_user_dev3_readback(struct niu *np, int reg) +{ + int err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR, reg); + if (err < 0) + return err; + err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR, reg); + if (err < 0) + return err; + return 0; +} + +static int bcm8704_init_user_dev3(struct niu *np) +{ + int err; + + err = mdio_write(np, np->phy_addr, + BCM8704_USER_DEV3_ADDR, BCM8704_USER_CONTROL, + (USER_CONTROL_OPTXRST_LVL | + USER_CONTROL_OPBIASFLT_LVL | + USER_CONTROL_OBTMPFLT_LVL | + USER_CONTROL_OPPRFLT_LVL | + USER_CONTROL_OPTXFLT_LVL | + USER_CONTROL_OPRXLOS_LVL | + USER_CONTROL_OPRXFLT_LVL | + USER_CONTROL_OPTXON_LVL | + (0x3f << USER_CONTROL_RES1_SHIFT))); + if (err) + return err; + + err = mdio_write(np, np->phy_addr, + BCM8704_USER_DEV3_ADDR, BCM8704_USER_PMD_TX_CONTROL, + (USER_PMD_TX_CTL_XFP_CLKEN | + (1 << USER_PMD_TX_CTL_TX_DAC_TXD_SH) | + (2 << USER_PMD_TX_CTL_TX_DAC_TXCK_SH) | + USER_PMD_TX_CTL_TSCK_LPWREN)); + if (err) + return err; + + err = bcm8704_user_dev3_readback(np, BCM8704_USER_CONTROL); + if (err) + return err; + err = bcm8704_user_dev3_readback(np, BCM8704_USER_PMD_TX_CONTROL); + if (err) + return err; + + err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR, + BCM8704_USER_OPT_DIGITAL_CTRL); + if (err < 0) + return err; + err &= ~USER_ODIG_CTRL_GPIOS; + err |= (0x3 << USER_ODIG_CTRL_GPIOS_SHIFT); + err = mdio_write(np, np->phy_addr, BCM8704_USER_DEV3_ADDR, + BCM8704_USER_OPT_DIGITAL_CTRL, err); + if (err) + return err; + + mdelay(1000); + + return 0; +} + +static int xcvr_init_10g(struct niu *np) +{ + struct niu_link_config *lp = &np->link_config; + u16 analog_stat0, tx_alarm_status; + int err; + u64 val; + + val = nr64_mac(XMAC_CONFIG); + val &= ~XMAC_CONFIG_LED_POLARITY; + val |= XMAC_CONFIG_FORCE_LED_ON; + nw64_mac(XMAC_CONFIG, val); + + /* XXX shared resource, lock parent XXX */ + val = nr64(MIF_CONFIG); + val |= MIF_CONFIG_INDIRECT_MODE; + nw64(MIF_CONFIG, val); + + err = bcm8704_reset(np); + if (err) + return err; + + err = bcm8704_init_user_dev3(np); + if (err) + return err; + + err = mdio_read(np, np->phy_addr, BCM8704_PCS_DEV_ADDR, + MII_BMCR); + if (err < 0) + return err; + err &= ~BMCR_LOOPBACK; + + if (lp->loopback_mode == LOOPBACK_MAC) + err |= BMCR_LOOPBACK; + + err = mdio_write(np, np->phy_addr, BCM8704_PCS_DEV_ADDR, + MII_BMCR, err); + if (err) + return err; + +#if 1 + err = mdio_read(np, np->phy_addr, BCM8704_PMA_PMD_DEV_ADDR, + MII_STAT1000); + if (err < 0) + return err; + pr_info(PFX "Port %u PMA_PMD(MII_STAT1000) [%04x]\n", + np->port, err); + + err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR, 0x20); + if (err < 0) + return err; + pr_info(PFX "Port %u USER_DEV3(0x20) [%04x]\n", + np->port, err); + + err = mdio_read(np, np->phy_addr, BCM8704_PHYXS_DEV_ADDR, + MII_NWAYTEST); + if (err < 0) + return err; + pr_info(PFX "Port %u PHYXS(MII_NWAYTEST) [%04x]\n", + np->port, err); +#endif + + /* XXX dig this out it might not be so useful XXX */ + err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR, + BCM8704_USER_ANALOG_STATUS0); + if (err < 0) + return err; + err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR, + BCM8704_USER_ANALOG_STATUS0); + if (err < 0) + return err; + analog_stat0 = err; + + err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR, + BCM8704_USER_TX_ALARM_STATUS); + if (err < 0) + return err; + err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR, + BCM8704_USER_TX_ALARM_STATUS); + if (err < 0) + return err; + tx_alarm_status = err; + + if (analog_stat0 != 0x03fc) { + if ((analog_stat0 == 0x43bc) && (tx_alarm_status != 0)) { + pr_info(PFX "Port %u cable not connected " + "or bad cable.\n", np->port); + } else if (analog_stat0 == 0x639c) { + pr_info(PFX "Port %u optical module is bad " + "or missing.\n", np->port); + } + } + + return 0; +} + +static int mii_reset(struct niu *np) +{ + int limit, err; + + err = mii_write(np, np->phy_addr, MII_BMCR, BMCR_RESET); + if (err) + return err; + + limit = 1000; + while (--limit >= 0) { + udelay(500); + err = mii_read(np, np->phy_addr, MII_BMCR); + if (err < 0) + return err; + if (!(err & BMCR_RESET)) + break; + } + if (limit < 0) { + dev_err(np->device, PFX "Port %u MII would not reset, " + "bmcr[%04x]\n", np->port, err); + return -ENODEV; + } + + return 0; +} + +static int mii_init_common(struct niu *np) +{ + struct niu_link_config *lp = &np->link_config; + u16 bmcr, bmsr, adv, estat; + int err; + + err = mii_reset(np); + if (err) + return err; + + err = mii_read(np, np->phy_addr, MII_BMSR); + if (err < 0) + return err; + bmsr = err; + + estat = 0; + if (bmsr & BMSR_ESTATEN) { + err = mii_read(np, np->phy_addr, MII_ESTATUS); + if (err < 0) + return err; + estat = err; + } + + bmcr = 0; + err = mii_write(np, np->phy_addr, MII_BMCR, bmcr); + if (err) + return err; + + if (lp->loopback_mode == LOOPBACK_MAC) { + bmcr |= BMCR_LOOPBACK; + if (lp->active_speed == SPEED_1000) + bmcr |= BMCR_SPEED1000; + if (lp->active_duplex == DUPLEX_FULL) + bmcr |= BMCR_FULLDPLX; + } + + if (lp->loopback_mode == LOOPBACK_PHY) { + u16 aux; + + aux = (BCM5464R_AUX_CTL_EXT_LB | + BCM5464R_AUX_CTL_WRITE_1); + err = mii_write(np, np->phy_addr, BCM5464R_AUX_CTL, aux); + if (err) + return err; + } + + /* XXX configurable XXX */ + /* XXX for now don't advertise half-duplex or asym pause... XXX */ + adv = ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP; + if (bmsr & BMSR_10FULL) + adv |= ADVERTISE_10FULL; + if (bmsr & BMSR_100FULL) + adv |= ADVERTISE_100FULL; + err = mii_write(np, np->phy_addr, MII_ADVERTISE, adv); + if (err) + return err; + + if (bmsr & BMSR_ESTATEN) { + u16 ctrl1000 = 0; + + if (estat & ESTATUS_1000_TFULL) + ctrl1000 |= ADVERTISE_1000FULL; + err = mii_write(np, np->phy_addr, MII_CTRL1000, ctrl1000); + if (err) + return err; + } + bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART); + + err = mii_write(np, np->phy_addr, MII_BMCR, bmcr); + if (err) + return err; + + err = mii_read(np, np->phy_addr, MII_BMCR); + if (err < 0) + return err; + err = mii_read(np, np->phy_addr, MII_BMSR); + if (err < 0) + return err; +#if 0 + pr_info(PFX "Port %u after MII init bmcr[%04x] bmsr[%04x]\n", + np->port, bmcr, bmsr); +#endif + + return 0; +} + +static int xcvr_init_1g(struct niu *np) +{ + u64 val; + + /* XXX shared resource, lock parent XXX */ + val = nr64(MIF_CONFIG); + val &= ~MIF_CONFIG_INDIRECT_MODE; + nw64(MIF_CONFIG, val); + + return mii_init_common(np); +} + +static int niu_xcvr_init(struct niu *np) +{ + const struct niu_phy_ops *ops = np->phy_ops; + int err; + + err = 0; + if (ops->xcvr_init) + err = ops->xcvr_init(np); + + return err; +} + +static int niu_serdes_init(struct niu *np) +{ + const struct niu_phy_ops *ops = np->phy_ops; + int err; + + err = 0; + if (ops->serdes_init) + err = ops->serdes_init(np); + + return err; +} + +static void niu_init_xif(struct niu *); + +static int niu_link_status_common(struct niu *np, int link_up) +{ + struct niu_link_config *lp = &np->link_config; + struct net_device *dev = np->dev; + unsigned long flags; + + if (!netif_carrier_ok(dev) && link_up) { + niuinfo(LINK, "%s: Link is up at %s, %s duplex\n", + dev->name, + (lp->active_speed == SPEED_10000 ? + "10Gb/sec" : + (lp->active_speed == SPEED_1000 ? + "1Gb/sec" : + (lp->active_speed == SPEED_100 ? + "100Mbit/sec" : "10Mbit/sec"))), + (lp->active_duplex == DUPLEX_FULL ? + "full" : "half")); + + spin_lock_irqsave(&np->lock, flags); + niu_init_xif(np); + spin_unlock_irqrestore(&np->lock, flags); + + netif_carrier_on(dev); + } else if (netif_carrier_ok(dev) && !link_up) { + niuwarn(LINK, "%s: Link is down\n", dev->name); + netif_carrier_off(dev); + } + + return 0; +} + +static int link_status_10g(struct niu *np, int *link_up_p) +{ + unsigned long flags; + int err, link_up; + + link_up = 0; + + spin_lock_irqsave(&np->lock, flags); + + err = -EINVAL; + if (np->link_config.loopback_mode != LOOPBACK_DISABLED) + goto out; + + err = mdio_read(np, np->phy_addr, BCM8704_PMA_PMD_DEV_ADDR, + BCM8704_PMD_RCV_SIGDET); + if (err < 0) + goto out; + if (!(err & PMD_RCV_SIGDET_GLOBAL)) { + err = 0; + goto out; + } + + err = mdio_read(np, np->phy_addr, BCM8704_PCS_DEV_ADDR, + BCM8704_PCS_10G_R_STATUS); + if (err < 0) + goto out; + if (!(err & PCS_10G_R_STATUS_BLK_LOCK)) { + err = 0; + goto out; + } + + err = mdio_read(np, np->phy_addr, BCM8704_PHYXS_DEV_ADDR, + BCM8704_PHYXS_XGXS_LANE_STAT); + if (err < 0) + goto out; + + if (err != (PHYXS_XGXS_LANE_STAT_ALINGED | + PHYXS_XGXS_LANE_STAT_MAGIC | + PHYXS_XGXS_LANE_STAT_LANE3 | + PHYXS_XGXS_LANE_STAT_LANE2 | + PHYXS_XGXS_LANE_STAT_LANE1 | + PHYXS_XGXS_LANE_STAT_LANE0)) { + err = 0; + goto out; + } + + link_up = 1; + np->link_config.active_speed = SPEED_10000; + np->link_config.active_duplex = DUPLEX_FULL; + err = 0; + +out: + spin_unlock_irqrestore(&np->lock, flags); + + *link_up_p = link_up; + return err; +} + +static int link_status_1g(struct niu *np, int *link_up_p) +{ + u16 current_speed, bmsr; + unsigned long flags; + u8 current_duplex; + int err, link_up; + + link_up = 0; + current_speed = SPEED_INVALID; + current_duplex = DUPLEX_INVALID; + + spin_lock_irqsave(&np->lock, flags); + + err = -EINVAL; + if (np->link_config.loopback_mode != LOOPBACK_DISABLED) + goto out; + + err = mii_read(np, np->phy_addr, MII_BMSR); + if (err < 0) + goto out; + + bmsr = err; + if (bmsr & BMSR_LSTATUS) { + u16 adv, lpa, common, estat; + + err = mii_read(np, np->phy_addr, MII_ADVERTISE); + if (err < 0) + goto out; + adv = err; + + err = mii_read(np, np->phy_addr, MII_LPA); + if (err < 0) + goto out; + lpa = err; + + common = adv & lpa; + + err = mii_read(np, np->phy_addr, MII_ESTATUS); + if (err < 0) + goto out; + estat = err; + + link_up = 1; + if (estat & (ESTATUS_1000_TFULL | ESTATUS_1000_THALF)) { + current_speed = SPEED_1000; + if (estat & ESTATUS_1000_TFULL) + current_duplex = DUPLEX_FULL; + else + current_duplex = DUPLEX_HALF; + } else { + if (common & ADVERTISE_100BASE4) { + current_speed = SPEED_100; + current_duplex = DUPLEX_HALF; + } else if (common & ADVERTISE_100FULL) { + current_speed = SPEED_100; + current_duplex = DUPLEX_FULL; + } else if (common & ADVERTISE_100HALF) { + current_speed = SPEED_100; + current_duplex = DUPLEX_HALF; + } else if (common & ADVERTISE_10FULL) { + current_speed = SPEED_10; + current_duplex = DUPLEX_FULL; + } else if (common & ADVERTISE_10HALF) { + current_speed = SPEED_10; + current_duplex = DUPLEX_HALF; + } else + link_up = 0; + } + } + err = 0; + +out: + spin_unlock_irqrestore(&np->lock, flags); + + *link_up_p = link_up; + return err; +} + +static int niu_link_status(struct niu *np, int *link_up_p) +{ + const struct niu_phy_ops *ops = np->phy_ops; + int err; + + err = 0; + if (ops->link_status) + err = ops->link_status(np, link_up_p); + + return err; +} + +static void niu_timer(unsigned long __opaque) +{ + struct niu *np = (struct niu *) __opaque; + unsigned long off; + int err, link_up; + + err = niu_link_status(np, &link_up); + if (!err) + niu_link_status_common(np, link_up); + + if (netif_carrier_ok(np->dev)) + off = 5 * HZ; + else + off = 1 * HZ; + np->timer.expires = jiffies + off; + + add_timer(&np->timer); +} + +static const struct niu_phy_ops phy_ops_10g_fiber_niu = { + .serdes_init = serdes_init_niu, + .xcvr_init = xcvr_init_10g, + .link_status = link_status_10g, +}; + +static const struct niu_phy_ops phy_ops_10g_fiber = { + .serdes_init = serdes_init_10g, + .xcvr_init = xcvr_init_10g, + .link_status = link_status_10g, +}; + +static const struct niu_phy_ops phy_ops_10g_copper = { + .serdes_init = serdes_init_10g, + .link_status = link_status_10g, /* XXX */ +}; + +static const struct niu_phy_ops phy_ops_1g_fiber = { + .serdes_init = serdes_init_1g, + .xcvr_init = xcvr_init_1g, + .link_status = link_status_1g, +}; + +static const struct niu_phy_ops phy_ops_1g_copper = { + .xcvr_init = xcvr_init_1g, + .link_status = link_status_1g, +}; + +struct niu_phy_template { + const struct niu_phy_ops *ops; + u32 phy_addr_base; +}; + +static const struct niu_phy_template phy_template_niu = { + .ops = &phy_ops_10g_fiber_niu, + .phy_addr_base = 16, +}; + +static const struct niu_phy_template phy_template_10g_fiber = { + .ops = &phy_ops_10g_fiber, + .phy_addr_base = 8, +}; + +static const struct niu_phy_template phy_template_10g_copper = { + .ops = &phy_ops_10g_copper, + .phy_addr_base = 10, +}; + +static const struct niu_phy_template phy_template_1g_fiber = { + .ops = &phy_ops_1g_fiber, + .phy_addr_base = 0, +}; + +static const struct niu_phy_template phy_template_1g_copper = { + .ops = &phy_ops_1g_copper, + .phy_addr_base = 0, +}; + +static int niu_determine_phy_disposition(struct niu *np) +{ + struct niu_parent *parent = np->parent; + u8 plat_type = parent->plat_type; + const struct niu_phy_template *tp; + u32 phy_addr_off = 0; + + if (plat_type == PLAT_TYPE_NIU) { + tp = &phy_template_niu; + phy_addr_off += np->port; + } else { + switch (np->flags & (NIU_FLAGS_10G | NIU_FLAGS_FIBER)) { + case 0: + /* 1G copper */ + tp = &phy_template_1g_copper; + if (plat_type == PLAT_TYPE_VF_P0) + phy_addr_off = 10; + else if (plat_type == PLAT_TYPE_VF_P1) + phy_addr_off = 26; + + phy_addr_off += (np->port ^ 0x3); + break; + + case NIU_FLAGS_10G: + /* 10G copper */ + tp = &phy_template_1g_copper; + break; + + case NIU_FLAGS_FIBER: + /* 1G fiber */ + tp = &phy_template_1g_fiber; + break; + + case NIU_FLAGS_10G | NIU_FLAGS_FIBER: + /* 10G fiber */ + tp = &phy_template_10g_fiber; + if (plat_type == PLAT_TYPE_VF_P0 || + plat_type == PLAT_TYPE_VF_P1) + phy_addr_off = 8; + phy_addr_off += np->port; + break; + + default: + return -EINVAL; + } + } + + np->phy_ops = tp->ops; + np->phy_addr = tp->phy_addr_base + phy_addr_off; + + return 0; +} + +static int niu_init_link(struct niu *np) +{ + struct niu_parent *parent = np->parent; + int err, ignore; + + if (parent->plat_type == PLAT_TYPE_NIU) { + err = niu_xcvr_init(np); + if (err) + return err; + msleep(200); + } + err = niu_serdes_init(np); + if (err) + return err; + msleep(200); + err = niu_xcvr_init(np); + if (!err) + niu_link_status(np, &ignore); + return 0; +} + +static void niu_set_primary_mac(struct niu *np, unsigned char *addr) +{ + u16 reg0 = addr[4] << 8 | addr[5]; + u16 reg1 = addr[2] << 8 | addr[3]; + u16 reg2 = addr[0] << 8 | addr[1]; + + if (np->flags & NIU_FLAGS_XMAC) { + nw64_mac(XMAC_ADDR0, reg0); + nw64_mac(XMAC_ADDR1, reg1); + nw64_mac(XMAC_ADDR2, reg2); + } else { + nw64_mac(BMAC_ADDR0, reg0); + nw64_mac(BMAC_ADDR1, reg1); + nw64_mac(BMAC_ADDR2, reg2); + } +} + +static int niu_num_alt_addr(struct niu *np) +{ + if (np->flags & NIU_FLAGS_XMAC) + return XMAC_NUM_ALT_ADDR; + else + return BMAC_NUM_ALT_ADDR; +} + +static int niu_set_alt_mac(struct niu *np, int index, unsigned char *addr) +{ + u16 reg0 = addr[4] << 8 | addr[5]; + u16 reg1 = addr[2] << 8 | addr[3]; + u16 reg2 = addr[0] << 8 | addr[1]; + + if (index >= niu_num_alt_addr(np)) + return -EINVAL; + + if (np->flags & NIU_FLAGS_XMAC) { + nw64_mac(XMAC_ALT_ADDR0(index), reg0); + nw64_mac(XMAC_ALT_ADDR1(index), reg1); + nw64_mac(XMAC_ALT_ADDR2(index), reg2); + } else { + nw64_mac(BMAC_ALT_ADDR0(index), reg0); + nw64_mac(BMAC_ALT_ADDR1(index), reg1); + nw64_mac(BMAC_ALT_ADDR2(index), reg2); + } + + return 0; +} + +static int niu_enable_alt_mac(struct niu *np, int index, int on) +{ + unsigned long reg; + u64 val, mask; + + if (index >= niu_num_alt_addr(np)) + return -EINVAL; + + if (np->flags & NIU_FLAGS_XMAC) + reg = XMAC_ADDR_CMPEN; + else + reg = BMAC_ADDR_CMPEN; + + mask = 1 << index; + + val = nr64_mac(reg); + if (on) + val |= mask; + else + val &= ~mask; + nw64_mac(reg, val); + + return 0; +} + +static void __set_rdc_table_num_hw(struct niu *np, unsigned long reg, + int num, int mac_pref) +{ + u64 val = nr64_mac(reg); + val &= ~(HOST_INFO_MACRDCTBLN | HOST_INFO_MPR); + val |= num; + if (mac_pref) + val |= HOST_INFO_MPR; + nw64_mac(reg, val); +} + +static int __set_rdc_table_num(struct niu *np, + int xmac_index, int bmac_index, + int rdc_table_num, int mac_pref) +{ + unsigned long reg; + + if (rdc_table_num & ~HOST_INFO_MACRDCTBLN) + return -EINVAL; + if (np->flags & NIU_FLAGS_XMAC) + reg = XMAC_HOST_INFO(xmac_index); + else + reg = BMAC_HOST_INFO(bmac_index); + __set_rdc_table_num_hw(np, reg, rdc_table_num, mac_pref); + return 0; +} + +static int niu_set_primary_mac_rdc_table(struct niu *np, int table_num, + int mac_pref) +{ + return __set_rdc_table_num(np, 17, 0, table_num, mac_pref); +} + +static int niu_set_multicast_mac_rdc_table(struct niu *np, int table_num, + int mac_pref) +{ + return __set_rdc_table_num(np, 16, 8, table_num, mac_pref); +} + +static int niu_set_alt_mac_rdc_table(struct niu *np, int idx, + int table_num, int mac_pref) +{ + if (idx >= niu_num_alt_addr(np)) + return -EINVAL; + return __set_rdc_table_num(np, idx, idx + 1, table_num, mac_pref); +} + +static u64 vlan_entry_set_parity(u64 reg_val) +{ + u64 port01_mask; + u64 port23_mask; + + port01_mask = 0x00ff; + port23_mask = 0xff00; + + if (hweight64(reg_val & port01_mask) & 1) + reg_val |= ENET_VLAN_TBL_PARITY0; + else + reg_val &= ~ENET_VLAN_TBL_PARITY0; + + if (hweight64(reg_val & port23_mask) & 1) + reg_val |= ENET_VLAN_TBL_PARITY1; + else + reg_val &= ~ENET_VLAN_TBL_PARITY1; + + return reg_val; +} + +static void vlan_tbl_write(struct niu *np, unsigned long index, + int port, int vpr, int rdc_table) +{ + u64 reg_val = nr64(ENET_VLAN_TBL(index)); + + reg_val &= ~((ENET_VLAN_TBL_VPR | + ENET_VLAN_TBL_VLANRDCTBLN) << + ENET_VLAN_TBL_SHIFT(port)); + if (vpr) + reg_val |= (ENET_VLAN_TBL_VPR << + ENET_VLAN_TBL_SHIFT(port)); + reg_val |= (rdc_table << ENET_VLAN_TBL_SHIFT(port)); + + reg_val = vlan_entry_set_parity(reg_val); + + nw64(ENET_VLAN_TBL(index), reg_val); +} + +static void vlan_tbl_clear(struct niu *np) +{ + int i; + + for (i = 0; i < ENET_VLAN_TBL_NUM_ENTRIES; i++) + nw64(ENET_VLAN_TBL(i), 0); +} + +static int tcam_wait_bit(struct niu *np, u64 bit) +{ + int limit = 1000; + + while (--limit > 0) { + if (nr64(TCAM_CTL) & bit) + break; + udelay(1); + } + if (limit < 0) + return -ENODEV; + + return 0; +} + +static int tcam_flush(struct niu *np, int index) +{ + nw64(TCAM_KEY_0, 0x00); + nw64(TCAM_KEY_MASK_0, 0xff); + nw64(TCAM_CTL, (TCAM_CTL_RWC_TCAM_WRITE | index)); + + return tcam_wait_bit(np, TCAM_CTL_STAT); +} + +#if 0 +static int tcam_read(struct niu *np, int index, + u64 *key, u64 *mask) +{ + int err; + + nw64(TCAM_CTL, (TCAM_CTL_RWC_TCAM_READ | index)); + err = tcam_wait_bit(np, TCAM_CTL_STAT); + if (!err) { + key[0] = nr64(TCAM_KEY_0); + key[1] = nr64(TCAM_KEY_1); + key[2] = nr64(TCAM_KEY_2); + key[3] = nr64(TCAM_KEY_3); + mask[0] = nr64(TCAM_KEY_MASK_0); + mask[1] = nr64(TCAM_KEY_MASK_1); + mask[2] = nr64(TCAM_KEY_MASK_2); + mask[3] = nr64(TCAM_KEY_MASK_3); + } + return err; +} +#endif + +static int tcam_write(struct niu *np, int index, + u64 *key, u64 *mask) +{ + nw64(TCAM_KEY_0, key[0]); + nw64(TCAM_KEY_1, key[1]); + nw64(TCAM_KEY_2, key[2]); + nw64(TCAM_KEY_3, key[3]); + nw64(TCAM_KEY_MASK_0, mask[0]); + nw64(TCAM_KEY_MASK_1, mask[1]); + nw64(TCAM_KEY_MASK_2, mask[2]); + nw64(TCAM_KEY_MASK_3, mask[3]); + nw64(TCAM_CTL, (TCAM_CTL_RWC_TCAM_WRITE | index)); + + return tcam_wait_bit(np, TCAM_CTL_STAT); +} + +#if 0 +static int tcam_assoc_read(struct niu *np, int index, u64 *data) +{ + int err; + + nw64(TCAM_CTL, (TCAM_CTL_RWC_RAM_READ | index)); + err = tcam_wait_bit(np, TCAM_CTL_STAT); + if (!err) + *data = nr64(TCAM_KEY_1); + + return err; +} +#endif + +static int tcam_assoc_write(struct niu *np, int index, u64 assoc_data) +{ + nw64(TCAM_KEY_1, assoc_data); + nw64(TCAM_CTL, (TCAM_CTL_RWC_RAM_WRITE | index)); + + return tcam_wait_bit(np, TCAM_CTL_STAT); +} + +static void tcam_enable(struct niu *np, int on) +{ + u64 val = nr64(FFLP_CFG_1); + + if (on) + val &= ~FFLP_CFG_1_TCAM_DIS; + else + val |= FFLP_CFG_1_TCAM_DIS; + nw64(FFLP_CFG_1, val); +} + +static void tcam_set_lat_and_ratio(struct niu *np, u64 latency, u64 ratio) +{ + u64 val = nr64(FFLP_CFG_1); + + val &= ~(FFLP_CFG_1_FFLPINITDONE | + FFLP_CFG_1_CAMLAT | + FFLP_CFG_1_CAMRATIO); + val |= (latency << FFLP_CFG_1_CAMLAT_SHIFT); + val |= (ratio << FFLP_CFG_1_CAMRATIO_SHIFT); + nw64(FFLP_CFG_1, val); + + val = nr64(FFLP_CFG_1); + val |= FFLP_CFG_1_FFLPINITDONE; + nw64(FFLP_CFG_1, val); +} + +static int tcam_user_eth_class_enable(struct niu *np, unsigned long class, + int on) +{ + unsigned long reg; + u64 val; + + if (class < CLASS_CODE_ETHERTYPE1 || + class > CLASS_CODE_ETHERTYPE2) + return -EINVAL; + + reg = L2_CLS(class - CLASS_CODE_ETHERTYPE1); + val = nr64(reg); + if (on) + val |= L2_CLS_VLD; + else + val &= ~L2_CLS_VLD; + nw64(reg, val); + + return 0; +} + +#if 0 +static int tcam_user_eth_class_set(struct niu *np, unsigned long class, + u64 ether_type) +{ + unsigned long reg; + u64 val; + + if (class < CLASS_CODE_ETHERTYPE1 || + class > CLASS_CODE_ETHERTYPE2 || + (ether_type & ~(u64)0xffff) != 0) + return -EINVAL; + + reg = L2_CLS(class - CLASS_CODE_ETHERTYPE1); + val = nr64(reg); + val &= ~L2_CLS_ETYPE; + val |= (ether_type << L2_CLS_ETYPE_SHIFT); + nw64(reg, val); + + return 0; +} +#endif + +static int tcam_user_ip_class_enable(struct niu *np, unsigned long class, + int on) +{ + unsigned long reg; + u64 val; + + if (class < CLASS_CODE_USER_PROG1 || + class > CLASS_CODE_USER_PROG4) + return -EINVAL; + + reg = L3_CLS(class - CLASS_CODE_USER_PROG1); + val = nr64(reg); + if (on) + val |= L3_CLS_VALID; + else + val &= ~L3_CLS_VALID; + nw64(reg, val); + + return 0; +} + +#if 0 +static int tcam_user_ip_class_set(struct niu *np, unsigned long class, + int ipv6, u64 protocol_id, + u64 tos_mask, u64 tos_val) +{ + unsigned long reg; + u64 val; + + if (class < CLASS_CODE_USER_PROG1 || + class > CLASS_CODE_USER_PROG4 || + (protocol_id & ~(u64)0xff) != 0 || + (tos_mask & ~(u64)0xff) != 0 || + (tos_val & ~(u64)0xff) != 0) + return -EINVAL; + + reg = L3_CLS(class - CLASS_CODE_USER_PROG1); + val = nr64(reg); + val &= ~(L3_CLS_IPVER | L3_CLS_PID | + L3_CLS_TOSMASK | L3_CLS_TOS); + if (ipv6) + val |= L3_CLS_IPVER; + val |= (protocol_id << L3_CLS_PID_SHIFT); + val |= (tos_mask << L3_CLS_TOSMASK_SHIFT); + val |= (tos_val << L3_CLS_TOS_SHIFT); + nw64(reg, val); + + return 0; +} +#endif + +static int tcam_early_init(struct niu *np) +{ + unsigned long i; + int err; + + tcam_enable(np, 0); + tcam_set_lat_and_ratio(np, + DEFAULT_TCAM_LATENCY, + DEFAULT_TCAM_ACCESS_RATIO); + for (i = CLASS_CODE_ETHERTYPE1; i <= CLASS_CODE_ETHERTYPE2; i++) { + err = tcam_user_eth_class_enable(np, i, 0); + if (err) + return err; + } + for (i = CLASS_CODE_USER_PROG1; i <= CLASS_CODE_USER_PROG4; i++) { + err = tcam_user_ip_class_enable(np, i, 0); + if (err) + return err; + } + + return 0; +} + +static int tcam_flush_all(struct niu *np) +{ + unsigned long i; + + for (i = 0; i < np->parent->tcam_num_entries; i++) { + int err = tcam_flush(np, i); + if (err) + return err; + } + return 0; +} + +static u64 hash_addr_regval(unsigned long index, unsigned long num_entries) +{ + return ((u64)index | (num_entries == 1 ? + HASH_TBL_ADDR_AUTOINC : 0)); +} + +#if 0 +static int hash_read(struct niu *np, unsigned long partition, + unsigned long index, unsigned long num_entries, + u64 *data) +{ + u64 val = hash_addr_regval(index, num_entries); + unsigned long i; + + if (partition >= FCRAM_NUM_PARTITIONS || + index + num_entries > FCRAM_SIZE) + return -EINVAL; + + nw64(HASH_TBL_ADDR(partition), val); + for (i = 0; i < num_entries; i++) + data[i] = nr64(HASH_TBL_DATA(partition)); + + return 0; +} +#endif + +static int hash_write(struct niu *np, unsigned long partition, + unsigned long index, unsigned long num_entries, + u64 *data) +{ + u64 val = hash_addr_regval(index, num_entries); + unsigned long i; + + if (partition >= FCRAM_NUM_PARTITIONS || + index + (num_entries * 8) > FCRAM_SIZE) + return -EINVAL; + + nw64(HASH_TBL_ADDR(partition), val); + for (i = 0; i < num_entries; i++) + nw64(HASH_TBL_DATA(partition), data[i]); + + return 0; +} + +static void fflp_reset(struct niu *np) +{ + u64 val; + + nw64(FFLP_CFG_1, FFLP_CFG_1_PIO_FIO_RST); + udelay(10); + nw64(FFLP_CFG_1, 0); + + val = FFLP_CFG_1_FCRAMOUTDR_NORMAL | FFLP_CFG_1_FFLPINITDONE; + nw64(FFLP_CFG_1, val); +} + +static void fflp_set_timings(struct niu *np) +{ + u64 val = nr64(FFLP_CFG_1); + + val &= ~FFLP_CFG_1_FFLPINITDONE; + val |= (DEFAULT_FCRAMRATIO << FFLP_CFG_1_FCRAMRATIO_SHIFT); + nw64(FFLP_CFG_1, val); + + val = nr64(FFLP_CFG_1); + val |= FFLP_CFG_1_FFLPINITDONE; + nw64(FFLP_CFG_1, val); + + val = nr64(FCRAM_REF_TMR); + val &= ~(FCRAM_REF_TMR_MAX | FCRAM_REF_TMR_MIN); + val |= (DEFAULT_FCRAM_REFRESH_MAX << FCRAM_REF_TMR_MAX_SHIFT); + val |= (DEFAULT_FCRAM_REFRESH_MIN << FCRAM_REF_TMR_MIN_SHIFT); + nw64(FCRAM_REF_TMR, val); +} + +static int fflp_set_partition(struct niu *np, u64 partition, + u64 mask, u64 base, int enable) +{ + unsigned long reg; + u64 val; + + if (partition >= FCRAM_NUM_PARTITIONS || + (mask & ~(u64)0x1f) != 0 || + (base & ~(u64)0x1f) != 0) + return -EINVAL; + + reg = FLW_PRT_SEL(partition); + + val = nr64(reg); + val &= ~(FLW_PRT_SEL_EXT | FLW_PRT_SEL_MASK | FLW_PRT_SEL_BASE); + val |= (mask << FLW_PRT_SEL_MASK_SHIFT); + val |= (base << FLW_PRT_SEL_BASE_SHIFT); + if (enable) + val |= FLW_PRT_SEL_EXT; + nw64(reg, val); + + return 0; +} + +static int fflp_disable_all_partitions(struct niu *np) +{ + unsigned long i; + + for (i = 0; i < FCRAM_NUM_PARTITIONS; i++) { + int err = fflp_set_partition(np, 0, 0, 0, 0); + if (err) + return err; + } + return 0; +} + +static void fflp_llcsnap_enable(struct niu *np, int on) +{ + u64 val = nr64(FFLP_CFG_1); + + if (on) + val |= FFLP_CFG_1_LLCSNAP; + else + val &= ~FFLP_CFG_1_LLCSNAP; + nw64(FFLP_CFG_1, val); +} + +static void fflp_errors_enable(struct niu *np, int on) +{ + u64 val = nr64(FFLP_CFG_1); + + if (on) + val &= ~FFLP_CFG_1_ERRORDIS; + else + val |= FFLP_CFG_1_ERRORDIS; + nw64(FFLP_CFG_1, val); +} + +static int fflp_hash_clear(struct niu *np) +{ + struct fcram_hash_ipv4 ent; + unsigned long i; + + /* IPV4 hash entry with valid bit clear, rest is don't care. */ + memset(&ent, 0, sizeof(ent)); + ent.header = HASH_HEADER_EXT; + + for (i = 0; i < FCRAM_SIZE; i += sizeof(ent)) { + int err = hash_write(np, 0, i, 1, (u64 *) &ent); + if (err) + return err; + } + return 0; +} + +static int fflp_early_init(struct niu *np) +{ + struct niu_parent *parent; + unsigned long flags; + int err; + + niu_lock_parent(np, flags); + + parent = np->parent; + err = 0; + if (!(parent->flags & PARENT_FLGS_CLS_HWINIT)) { + niudbg(PROBE, "fflp_early_init: Initting hw on port %u\n", + np->port); + if (np->parent->plat_type != PLAT_TYPE_NIU) { + fflp_reset(np); + fflp_set_timings(np); + err = fflp_disable_all_partitions(np); + if (err) { + niudbg(PROBE, "fflp_disable_all_partitions " + "failed, err=%d\n", err); + goto out; + } + } + + err = tcam_early_init(np); + if (err) { + niudbg(PROBE, "tcam_early_init failed, err=%d\n", + err); + goto out; + } + fflp_llcsnap_enable(np, 1); + fflp_errors_enable(np, 0); + nw64(H1POLY, 0); + nw64(H2POLY, 0); + + err = tcam_flush_all(np); + if (err) { + niudbg(PROBE, "tcam_flush_all failed, err=%d\n", + err); + goto out; + } + if (np->parent->plat_type != PLAT_TYPE_NIU) { + err = fflp_hash_clear(np); + if (err) { + niudbg(PROBE, "fflp_hash_clear failed, " + "err=%d\n", err); + goto out; + } + } + + vlan_tbl_clear(np); + + niudbg(PROBE, "fflp_early_init: Success\n"); + parent->flags |= PARENT_FLGS_CLS_HWINIT; + } +out: + niu_unlock_parent(np, flags); + return err; +} + +static int niu_set_flow_key(struct niu *np, unsigned long class_code, u64 key) +{ + if (class_code < CLASS_CODE_USER_PROG1 || + class_code > CLASS_CODE_SCTP_IPV6) + return -EINVAL; + + nw64(FLOW_KEY(class_code - CLASS_CODE_USER_PROG1), key); + return 0; +} + +static int niu_set_tcam_key(struct niu *np, unsigned long class_code, u64 key) +{ + if (class_code < CLASS_CODE_USER_PROG1 || + class_code > CLASS_CODE_SCTP_IPV6) + return -EINVAL; + + nw64(TCAM_KEY(class_code - CLASS_CODE_USER_PROG1), key); + return 0; +} + +static void niu_rx_skb_append(struct sk_buff *skb, struct page *page, + u32 offset, u32 size) +{ + int i = skb_shinfo(skb)->nr_frags; + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + + frag->page = page; + frag->page_offset = offset; + frag->size = size; + + skb->len += size; + skb->data_len += size; + skb->truesize += size; + + skb_shinfo(skb)->nr_frags = i + 1; +} + +static unsigned int niu_hash_rxaddr(struct rx_ring_info *rp, u64 a) +{ + a >>= PAGE_SHIFT; + a ^= (a >> ilog2(MAX_RBR_RING_SIZE)); + + return (a & (MAX_RBR_RING_SIZE - 1)); +} + +static struct page *niu_find_rxpage(struct rx_ring_info *rp, u64 addr, + struct page ***link) +{ + unsigned int h = niu_hash_rxaddr(rp, addr); + struct page *p, **pp; + + addr &= PAGE_MASK; + pp = &rp->rxhash[h]; + for (; (p = *pp) != NULL; pp = (struct page **) &p->mapping) { + if (p->index == addr) { + *link = pp; + break; + } + } + + return p; +} + +static void niu_hash_page(struct rx_ring_info *rp, struct page *page, u64 base) +{ + unsigned int h = niu_hash_rxaddr(rp, base); + + page->index = base; + page->mapping = (struct address_space *) rp->rxhash[h]; + rp->rxhash[h] = page; +} + +static int niu_rbr_add_page(struct niu *np, struct rx_ring_info *rp, + gfp_t mask, int start_index) +{ + struct page *page; + u64 addr; + int i; + + page = alloc_page(mask); + if (!page) + return -ENOMEM; + + addr = np->ops->map_page(np->device, page, 0, + PAGE_SIZE, DMA_FROM_DEVICE); + + niu_hash_page(rp, page, addr); + if (rp->rbr_blocks_per_page > 1) + atomic_add(rp->rbr_blocks_per_page - 1, + &compound_head(page)->_count); + + for (i = 0; i < rp->rbr_blocks_per_page; i++) { + __le32 *rbr = &rp->rbr[start_index + i]; + + *rbr = cpu_to_le32(addr >> RBR_DESCR_ADDR_SHIFT); + addr += rp->rbr_block_size; + } + + return 0; +} + +static void niu_rbr_refill(struct niu *np, struct rx_ring_info *rp, gfp_t mask) +{ + int index = rp->rbr_index; + + rp->rbr_pending++; + if ((rp->rbr_pending % rp->rbr_blocks_per_page) == 0) { + int err = niu_rbr_add_page(np, rp, mask, index); + + if (unlikely(err)) { + rp->rbr_pending--; + return; + } + + rp->rbr_index += rp->rbr_blocks_per_page; + BUG_ON(rp->rbr_index > rp->rbr_table_size); + if (rp->rbr_index == rp->rbr_table_size) + rp->rbr_index = 0; + + if (rp->rbr_pending >= rp->rbr_kick_thresh) { + nw64(RBR_KICK(rp->rx_channel), rp->rbr_pending); + rp->rbr_pending = 0; + } + } +} + +static int niu_rx_pkt_ignore(struct niu *np, struct rx_ring_info *rp) +{ + unsigned int index = rp->rcr_index; + int num_rcr = 0; + + rp->rx_dropped++; + while (1) { + struct page *page, **link; + u64 addr, val; + u32 rcr_size; + + num_rcr++; + + val = le64_to_cpup(&rp->rcr[index]); + addr = (val & RCR_ENTRY_PKT_BUF_ADDR) << + RCR_ENTRY_PKT_BUF_ADDR_SHIFT; + page = niu_find_rxpage(rp, addr, &link); + + rcr_size = rp->rbr_sizes[(val & RCR_ENTRY_PKTBUFSZ) >> + RCR_ENTRY_PKTBUFSZ_SHIFT]; + if ((page->index + PAGE_SIZE) - rcr_size == addr) { + *link = (struct page *) page->mapping; + np->ops->unmap_page(np->device, page->index, + PAGE_SIZE, DMA_FROM_DEVICE); + page->index = 0; + page->mapping = NULL; + __free_page(page); + rp->rbr_refill_pending++; + } + + index = NEXT_RCR(rp, index); + if (!(val & RCR_ENTRY_MULTI)) + break; + + } + rp->rcr_index = index; + + return num_rcr; +} + +static int niu_process_rx_pkt(struct niu *np, struct rx_ring_info *rp) +{ + unsigned int index = rp->rcr_index; + struct sk_buff *skb; + int len, num_rcr; + + skb = netdev_alloc_skb(np->dev, RX_SKB_ALLOC_SIZE); + if (unlikely(!skb)) + return niu_rx_pkt_ignore(np, rp); + + num_rcr = 0; + while (1) { + struct page *page, **link; + u32 rcr_size, append_size; + u64 addr, val, off; + + num_rcr++; + + val = le64_to_cpup(&rp->rcr[index]); + + len = (val & RCR_ENTRY_L2_LEN) >> + RCR_ENTRY_L2_LEN_SHIFT; + len -= ETH_FCS_LEN; + + addr = (val & RCR_ENTRY_PKT_BUF_ADDR) << + RCR_ENTRY_PKT_BUF_ADDR_SHIFT; + page = niu_find_rxpage(rp, addr, &link); + + rcr_size = rp->rbr_sizes[(val & RCR_ENTRY_PKTBUFSZ) >> + RCR_ENTRY_PKTBUFSZ_SHIFT]; + + off = addr & ~PAGE_MASK; + append_size = rcr_size; + if (num_rcr == 1) { + int ptype; + + off += 2; + append_size -= 2; + + ptype = (val >> RCR_ENTRY_PKT_TYPE_SHIFT); + if ((ptype == RCR_PKT_TYPE_TCP || + ptype == RCR_PKT_TYPE_UDP) && + !(val & (RCR_ENTRY_NOPORT | + RCR_ENTRY_ERROR))) + skb->ip_summed = CHECKSUM_UNNECESSARY; + else + skb->ip_summed = CHECKSUM_NONE; + } + if (!(val & RCR_ENTRY_MULTI)) + append_size = len - skb->len; + + niu_rx_skb_append(skb, page, off, append_size); + if ((page->index + rp->rbr_block_size) - rcr_size == addr) { + *link = (struct page *) page->mapping; + np->ops->unmap_page(np->device, page->index, + PAGE_SIZE, DMA_FROM_DEVICE); + page->index = 0; + page->mapping = NULL; + rp->rbr_refill_pending++; + } else + get_page(page); + + index = NEXT_RCR(rp, index); + if (!(val & RCR_ENTRY_MULTI)) + break; + + } + rp->rcr_index = index; + + skb_reserve(skb, NET_IP_ALIGN); + __pskb_pull_tail(skb, min(len, NIU_RXPULL_MAX)); + + rp->rx_packets++; + rp->rx_bytes += skb->len; + + skb->protocol = eth_type_trans(skb, np->dev); + netif_receive_skb(skb); + + return num_rcr; +} + +static int niu_rbr_fill(struct niu *np, struct rx_ring_info *rp, gfp_t mask) +{ + int blocks_per_page = rp->rbr_blocks_per_page; + int err, index = rp->rbr_index; + + err = 0; + while (index < (rp->rbr_table_size - blocks_per_page)) { + err = niu_rbr_add_page(np, rp, mask, index); + if (err) + break; + + index += blocks_per_page; + } + + rp->rbr_index = index; + return err; +} + +static void niu_rbr_free(struct niu *np, struct rx_ring_info *rp) +{ + int i; + + for (i = 0; i < MAX_RBR_RING_SIZE; i++) { + struct page *page; + + page = rp->rxhash[i]; + while (page) { + struct page *next = (struct page *) page->mapping; + u64 base = page->index; + + np->ops->unmap_page(np->device, base, PAGE_SIZE, + DMA_FROM_DEVICE); + page->index = 0; + page->mapping = NULL; + + __free_page(page); + + page = next; + } + } + + for (i = 0; i < rp->rbr_table_size; i++) + rp->rbr[i] = cpu_to_le32(0); + rp->rbr_index = 0; +} + +static int release_tx_packet(struct niu *np, struct tx_ring_info *rp, int idx) +{ + struct tx_buff_info *tb = &rp->tx_buffs[idx]; + struct sk_buff *skb = tb->skb; + struct tx_pkt_hdr *tp; + u64 tx_flags; + int i, len; + + tp = (struct tx_pkt_hdr *) skb->data; + tx_flags = le64_to_cpup(&tp->flags); + + rp->tx_packets++; + rp->tx_bytes += (((tx_flags & TXHDR_LEN) >> TXHDR_LEN_SHIFT) - + ((tx_flags & TXHDR_PAD) / 2)); + + len = skb_headlen(skb); + np->ops->unmap_single(np->device, tb->mapping, + len, DMA_TO_DEVICE); + + if (le64_to_cpu(rp->descr[idx]) & TX_DESC_MARK) + rp->mark_pending--; + + tb->skb = NULL; + do { + idx = NEXT_TX(rp, idx); + len -= MAX_TX_DESC_LEN; + } while (len > 0); + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + tb = &rp->tx_buffs[idx]; + BUG_ON(tb->skb != NULL); + np->ops->unmap_page(np->device, tb->mapping, + skb_shinfo(skb)->frags[i].size, + DMA_TO_DEVICE); + idx = NEXT_TX(rp, idx); + } + + dev_kfree_skb(skb); + + return idx; +} + +#define NIU_TX_WAKEUP_THRESH(rp) ((rp)->pending / 4) + +static void niu_tx_work(struct niu *np, struct tx_ring_info *rp) +{ + u16 pkt_cnt, tmp; + int cons; + u64 cs; + + cs = rp->tx_cs; + if (unlikely(!(cs & (TX_CS_MK | TX_CS_MMK)))) + goto out; + + tmp = pkt_cnt = (cs & TX_CS_PKT_CNT) >> TX_CS_PKT_CNT_SHIFT; + pkt_cnt = (pkt_cnt - rp->last_pkt_cnt) & + (TX_CS_PKT_CNT >> TX_CS_PKT_CNT_SHIFT); + + rp->last_pkt_cnt = tmp; + + cons = rp->cons; + + niudbg(TX_DONE, "%s: niu_tx_work() pkt_cnt[%u] cons[%d]\n", + np->dev->name, pkt_cnt, cons); + + while (pkt_cnt--) + cons = release_tx_packet(np, rp, cons); + + rp->cons = cons; + smp_mb(); + +out: + if (unlikely(netif_queue_stopped(np->dev) && + (niu_tx_avail(rp) > NIU_TX_WAKEUP_THRESH(rp)))) { + netif_tx_lock(np->dev); + if (netif_queue_stopped(np->dev) && + (niu_tx_avail(rp) > NIU_TX_WAKEUP_THRESH(rp))) + netif_wake_queue(np->dev); + netif_tx_unlock(np->dev); + } +} + +static int niu_rx_work(struct niu *np, struct rx_ring_info *rp, int budget) +{ + int qlen, rcr_done = 0, work_done = 0; + struct rxdma_mailbox *mbox = rp->mbox; + u64 stat; + +#if 1 + stat = nr64(RX_DMA_CTL_STAT(rp->rx_channel)); + qlen = nr64(RCRSTAT_A(rp->rx_channel)) & RCRSTAT_A_QLEN; +#else + stat = le64_to_cpup(&mbox->rx_dma_ctl_stat); + qlen = (le64_to_cpup(&mbox->rcrstat_a) & RCRSTAT_A_QLEN); +#endif + mbox->rx_dma_ctl_stat = 0; + mbox->rcrstat_a = 0; + + niudbg(RX_STATUS, "%s: niu_rx_work(chan[%d]), stat[%llx] qlen=%d\n", + np->dev->name, rp->rx_channel, (unsigned long long) stat, qlen); + + rcr_done = work_done = 0; + qlen = min(qlen, budget); + while (work_done < qlen) { + rcr_done += niu_process_rx_pkt(np, rp); + work_done++; + } + + if (rp->rbr_refill_pending >= rp->rbr_kick_thresh) { + unsigned int i; + + for (i = 0; i < rp->rbr_refill_pending; i++) + niu_rbr_refill(np, rp, GFP_ATOMIC); + rp->rbr_refill_pending = 0; + } + + stat = (RX_DMA_CTL_STAT_MEX | + ((u64)work_done << RX_DMA_CTL_STAT_PKTREAD_SHIFT) | + ((u64)rcr_done << RX_DMA_CTL_STAT_PTRREAD_SHIFT)); + + nw64(RX_DMA_CTL_STAT(rp->rx_channel), stat); + + return work_done; +} + +static int niu_poll_core(struct niu *np, struct niu_ldg *lp, int budget) +{ + u64 v0 = lp->v0; + u32 tx_vec = (v0 >> 32); + u32 rx_vec = (v0 & 0xffffffff); + int i, work_done = 0; + + niudbg(INTR, "%s: niu_poll_core() v0[%016llx]\n", + np->dev->name, (unsigned long long) v0); + + for (i = 0; i < np->num_tx_rings; i++) { + struct tx_ring_info *rp = &np->tx_rings[i]; + if (tx_vec & (1 << rp->tx_channel)) + niu_tx_work(np, rp); + nw64(LD_IM0(LDN_TXDMA(rp->tx_channel)), 0); + } + + for (i = 0; i < np->num_rx_rings; i++) { + struct rx_ring_info *rp = &np->rx_rings[i]; + + if (rx_vec & (1 << rp->rx_channel)) { + int this_work_done; + + this_work_done = niu_rx_work(np, rp, + budget); + + budget -= this_work_done; + work_done += this_work_done; + } + nw64(LD_IM0(LDN_RXDMA(rp->rx_channel)), 0); + } + + return work_done; +} + +static int niu_poll(struct napi_struct *napi, int budget) +{ + struct niu_ldg *lp = container_of(napi, struct niu_ldg, napi); + struct niu *np = lp->np; + int work_done; + + work_done = niu_poll_core(np, lp, budget); + + if (work_done < budget) { + netif_rx_complete(np->dev, napi); + niu_ldg_rearm(np, lp, 1); + } + return work_done; +} + +static void niu_log_rxchan_errors(struct niu *np, struct rx_ring_info *rp, + u64 stat) +{ + dev_err(np->device, PFX "%s: RX channel %u errors ( ", + np->dev->name, rp->rx_channel); + + if (stat & RX_DMA_CTL_STAT_RBR_TMOUT) + printk("RBR_TMOUT "); + if (stat & RX_DMA_CTL_STAT_RSP_CNT_ERR) + printk("RSP_CNT "); + if (stat & RX_DMA_CTL_STAT_BYTE_EN_BUS) + printk("BYTE_EN_BUS "); + if (stat & RX_DMA_CTL_STAT_RSP_DAT_ERR) + printk("RSP_DAT "); + if (stat & RX_DMA_CTL_STAT_RCR_ACK_ERR) + printk("RCR_ACK "); + if (stat & RX_DMA_CTL_STAT_RCR_SHA_PAR) + printk("RCR_SHA_PAR "); + if (stat & RX_DMA_CTL_STAT_RBR_PRE_PAR) + printk("RBR_PRE_PAR "); + if (stat & RX_DMA_CTL_STAT_CONFIG_ERR) + printk("CONFIG "); + if (stat & RX_DMA_CTL_STAT_RCRINCON) + printk("RCRINCON "); + if (stat & RX_DMA_CTL_STAT_RCRFULL) + printk("RCRFULL "); + if (stat & RX_DMA_CTL_STAT_RBRFULL) + printk("RBRFULL "); + if (stat & RX_DMA_CTL_STAT_RBRLOGPAGE) + printk("RBRLOGPAGE "); + if (stat & RX_DMA_CTL_STAT_CFIGLOGPAGE) + printk("CFIGLOGPAGE "); + if (stat & RX_DMA_CTL_STAT_DC_FIFO_ERR) + printk("DC_FIDO "); + + printk(")\n"); +} + +static int niu_rx_error(struct niu *np, struct rx_ring_info *rp) +{ + u64 stat = nr64(RX_DMA_CTL_STAT(rp->rx_channel)); + int err = 0; + + dev_err(np->device, PFX "%s: RX channel %u error, stat[%llx]\n", + np->dev->name, rp->rx_channel, (unsigned long long) stat); + + niu_log_rxchan_errors(np, rp, stat); + + if (stat & (RX_DMA_CTL_STAT_CHAN_FATAL | + RX_DMA_CTL_STAT_PORT_FATAL)) + err = -EINVAL; + + nw64(RX_DMA_CTL_STAT(rp->rx_channel), + stat & RX_DMA_CTL_WRITE_CLEAR_ERRS); + + return err; +} + +static void niu_log_txchan_errors(struct niu *np, struct tx_ring_info *rp, + u64 cs) +{ + dev_err(np->device, PFX "%s: TX channel %u errors ( ", + np->dev->name, rp->tx_channel); + + if (cs & TX_CS_MBOX_ERR) + printk("MBOX "); + if (cs & TX_CS_PKT_SIZE_ERR) + printk("PKT_SIZE "); + if (cs & TX_CS_TX_RING_OFLOW) + printk("TX_RING_OFLOW "); + if (cs & TX_CS_PREF_BUF_PAR_ERR) + printk("PREF_BUF_PAR "); + if (cs & TX_CS_NACK_PREF) + printk("NACK_PREF "); + if (cs & TX_CS_NACK_PKT_RD) + printk("NACK_PKT_RD "); + if (cs & TX_CS_CONF_PART_ERR) + printk("CONF_PART "); + if (cs & TX_CS_PKT_PRT_ERR) + printk("PKT_PTR "); + + printk(")\n"); +} + +static int niu_tx_error(struct niu *np, struct tx_ring_info *rp) +{ + u64 cs, logh, logl; + + cs = nr64(TX_CS(rp->tx_channel)); + logh = nr64(TX_RNG_ERR_LOGH(rp->tx_channel)); + logl = nr64(TX_RNG_ERR_LOGL(rp->tx_channel)); + + dev_err(np->device, PFX "%s: TX channel %u error, " + "cs[%llx] logh[%llx] logl[%llx]\n", + np->dev->name, rp->tx_channel, + (unsigned long long) cs, + (unsigned long long) logh, + (unsigned long long) logl); + + niu_log_txchan_errors(np, rp, cs); + + return -ENODEV; +} + +static int niu_mif_interrupt(struct niu *np) +{ + u64 mif_status = nr64(MIF_STATUS); + int phy_mdint = 0; + + if (np->flags & NIU_FLAGS_XMAC) { + u64 xrxmac_stat = nr64_mac(XRXMAC_STATUS); + + if (xrxmac_stat & XRXMAC_STATUS_PHY_MDINT) + phy_mdint = 1; + } + + dev_err(np->device, PFX "%s: MIF interrupt, " + "stat[%llx] phy_mdint(%d)\n", + np->dev->name, (unsigned long long) mif_status, phy_mdint); + + return -ENODEV; +} + +static void niu_xmac_interrupt(struct niu *np) +{ + struct niu_xmac_stats *mp = &np->mac_stats.xmac; + u64 val; + + val = nr64_mac(XTXMAC_STATUS); + if (val & XTXMAC_STATUS_FRAME_CNT_EXP) + mp->tx_frames += TXMAC_FRM_CNT_COUNT; + if (val & XTXMAC_STATUS_BYTE_CNT_EXP) + mp->tx_bytes += TXMAC_BYTE_CNT_COUNT; + if (val & XTXMAC_STATUS_TXFIFO_XFR_ERR) + mp->tx_fifo_errors++; + if (val & XTXMAC_STATUS_TXMAC_OFLOW) + mp->tx_overflow_errors++; + if (val & XTXMAC_STATUS_MAX_PSIZE_ERR) + mp->tx_max_pkt_size_errors++; + if (val & XTXMAC_STATUS_TXMAC_UFLOW) + mp->tx_underflow_errors++; + + val = nr64_mac(XRXMAC_STATUS); + if (val & XRXMAC_STATUS_LCL_FLT_STATUS) + mp->rx_local_faults++; + if (val & XRXMAC_STATUS_RFLT_DET) + mp->rx_remote_faults++; + if (val & XRXMAC_STATUS_LFLT_CNT_EXP) + mp->rx_link_faults += LINK_FAULT_CNT_COUNT; + if (val & XRXMAC_STATUS_ALIGNERR_CNT_EXP) + mp->rx_align_errors += RXMAC_ALIGN_ERR_CNT_COUNT; + if (val & XRXMAC_STATUS_RXFRAG_CNT_EXP) + mp->rx_frags += RXMAC_FRAG_CNT_COUNT; + if (val & XRXMAC_STATUS_RXMULTF_CNT_EXP) + mp->rx_mcasts += RXMAC_MC_FRM_CNT_COUNT; + if (val & XRXMAC_STATUS_RXBCAST_CNT_EXP) + mp->rx_bcasts += RXMAC_BC_FRM_CNT_COUNT; + if (val & XRXMAC_STATUS_RXBCAST_CNT_EXP) + mp->rx_bcasts += RXMAC_BC_FRM_CNT_COUNT; + if (val & XRXMAC_STATUS_RXHIST1_CNT_EXP) + mp->rx_hist_cnt1 += RXMAC_HIST_CNT1_COUNT; + if (val & XRXMAC_STATUS_RXHIST2_CNT_EXP) + mp->rx_hist_cnt2 += RXMAC_HIST_CNT2_COUNT; + if (val & XRXMAC_STATUS_RXHIST3_CNT_EXP) + mp->rx_hist_cnt3 += RXMAC_HIST_CNT3_COUNT; + if (val & XRXMAC_STATUS_RXHIST4_CNT_EXP) + mp->rx_hist_cnt4 += RXMAC_HIST_CNT4_COUNT; + if (val & XRXMAC_STATUS_RXHIST5_CNT_EXP) + mp->rx_hist_cnt5 += RXMAC_HIST_CNT5_COUNT; + if (val & XRXMAC_STATUS_RXHIST6_CNT_EXP) + mp->rx_hist_cnt6 += RXMAC_HIST_CNT6_COUNT; + if (val & XRXMAC_STATUS_RXHIST7_CNT_EXP) + mp->rx_hist_cnt7 += RXMAC_HIST_CNT7_COUNT; + if (val & XRXMAC_STAT_MSK_RXOCTET_CNT_EXP) + mp->rx_octets += RXMAC_BT_CNT_COUNT; + if (val & XRXMAC_STATUS_CVIOLERR_CNT_EXP) + mp->rx_code_violations += RXMAC_CD_VIO_CNT_COUNT; + if (val & XRXMAC_STATUS_LENERR_CNT_EXP) + mp->rx_len_errors += RXMAC_MPSZER_CNT_COUNT; + if (val & XRXMAC_STATUS_CRCERR_CNT_EXP) + mp->rx_crc_errors += RXMAC_CRC_ER_CNT_COUNT; + if (val & XRXMAC_STATUS_RXUFLOW) + mp->rx_underflows++; + if (val & XRXMAC_STATUS_RXOFLOW) + mp->rx_overflows++; + + val = nr64_mac(XMAC_FC_STAT); + if (val & XMAC_FC_STAT_TX_MAC_NPAUSE) + mp->pause_off_state++; + if (val & XMAC_FC_STAT_TX_MAC_PAUSE) + mp->pause_on_state++; + if (val & XMAC_FC_STAT_RX_MAC_RPAUSE) + mp->pause_received++; +} + +static void niu_bmac_interrupt(struct niu *np) +{ + struct niu_bmac_stats *mp = &np->mac_stats.bmac; + u64 val; + + val = nr64_mac(BTXMAC_STATUS); + if (val & BTXMAC_STATUS_UNDERRUN) + mp->tx_underflow_errors++; + if (val & BTXMAC_STATUS_MAX_PKT_ERR) + mp->tx_max_pkt_size_errors++; + if (val & BTXMAC_STATUS_BYTE_CNT_EXP) + mp->tx_bytes += BTXMAC_BYTE_CNT_COUNT; + if (val & BTXMAC_STATUS_FRAME_CNT_EXP) + mp->tx_frames += BTXMAC_FRM_CNT_COUNT; + + val = nr64_mac(BRXMAC_STATUS); + if (val & BRXMAC_STATUS_OVERFLOW) + mp->rx_overflows++; + if (val & BRXMAC_STATUS_FRAME_CNT_EXP) + mp->rx_frames += BRXMAC_FRAME_CNT_COUNT; + if (val & BRXMAC_STATUS_ALIGN_ERR_EXP) + mp->rx_align_errors += BRXMAC_ALIGN_ERR_CNT_COUNT; + if (val & BRXMAC_STATUS_CRC_ERR_EXP) + mp->rx_crc_errors += BRXMAC_ALIGN_ERR_CNT_COUNT; + if (val & BRXMAC_STATUS_LEN_ERR_EXP) + mp->rx_len_errors += BRXMAC_CODE_VIOL_ERR_CNT_COUNT; + + val = nr64_mac(BMAC_CTRL_STATUS); + if (val & BMAC_CTRL_STATUS_NOPAUSE) + mp->pause_off_state++; + if (val & BMAC_CTRL_STATUS_PAUSE) + mp->pause_on_state++; + if (val & BMAC_CTRL_STATUS_PAUSE_RECV) + mp->pause_received++; +} + +static int niu_mac_interrupt(struct niu *np) +{ + if (np->flags & NIU_FLAGS_XMAC) + niu_xmac_interrupt(np); + else + niu_bmac_interrupt(np); + + return 0; +} + +static void niu_log_device_error(struct niu *np, u64 stat) +{ + dev_err(np->device, PFX "%s: Core device errors ( ", + np->dev->name); + + if (stat & SYS_ERR_MASK_META2) + printk("META2 "); + if (stat & SYS_ERR_MASK_META1) + printk("META1 "); + if (stat & SYS_ERR_MASK_PEU) + printk("PEU "); + if (stat & SYS_ERR_MASK_TXC) + printk("TXC "); + if (stat & SYS_ERR_MASK_RDMC) + printk("RDMC "); + if (stat & SYS_ERR_MASK_TDMC) + printk("TDMC "); + if (stat & SYS_ERR_MASK_ZCP) + printk("ZCP "); + if (stat & SYS_ERR_MASK_FFLP) + printk("FFLP "); + if (stat & SYS_ERR_MASK_IPP) + printk("IPP "); + if (stat & SYS_ERR_MASK_MAC) + printk("MAC "); + if (stat & SYS_ERR_MASK_SMX) + printk("SMX "); + + printk(")\n"); +} + +static int niu_device_error(struct niu *np) +{ + u64 stat = nr64(SYS_ERR_STAT); + + dev_err(np->device, PFX "%s: Core device error, stat[%llx]\n", + np->dev->name, (unsigned long long) stat); + + niu_log_device_error(np, stat); + + return -ENODEV; +} + +static int niu_slowpath_interrupt(struct niu *np, struct niu_ldg *lp) +{ + u64 v0 = lp->v0; + u64 v1 = lp->v1; + u64 v2 = lp->v2; + int i, err = 0; + + if (v1 & 0x00000000ffffffffULL) { + u32 rx_vec = (v1 & 0xffffffff); + + for (i = 0; i < np->num_rx_rings; i++) { + struct rx_ring_info *rp = &np->rx_rings[i]; + + if (rx_vec & (1 << rp->rx_channel)) { + int r = niu_rx_error(np, rp); + if (r) + err = r; + } + } + } + if (v1 & 0x7fffffff00000000ULL) { + u32 tx_vec = (v1 >> 32) & 0x7fffffff; + + for (i = 0; i < np->num_tx_rings; i++) { + struct tx_ring_info *rp = &np->tx_rings[i]; + + if (tx_vec & (1 << rp->tx_channel)) { + int r = niu_tx_error(np, rp); + if (r) + err = r; + } + } + } + if ((v0 | v1) & 0x8000000000000000ULL) { + int r = niu_mif_interrupt(np); + if (r) + err = r; + } + if (v2) { + if (v2 & 0x01ef) { + int r = niu_mac_interrupt(np); + if (r) + err = r; + } + if (v2 & 0x0210) { + int r = niu_device_error(np); + if (r) + err = r; + } + } + + if (err) + niu_enable_interrupts(np, 0); + + return -EINVAL; +} + +static void niu_rxchan_intr(struct niu *np, struct rx_ring_info *rp, + int ldn) +{ + struct rxdma_mailbox *mbox = rp->mbox; + u64 stat_write, stat = le64_to_cpup(&mbox->rx_dma_ctl_stat); + + stat_write = (RX_DMA_CTL_STAT_RCRTHRES | + RX_DMA_CTL_STAT_RCRTO); + nw64(RX_DMA_CTL_STAT(rp->rx_channel), stat_write); + + niudbg(INTR, "%s: rxchan_intr stat[%llx]\n", + np->dev->name, (unsigned long long) stat); +} + +static void niu_txchan_intr(struct niu *np, struct tx_ring_info *rp, + int ldn) +{ + rp->tx_cs = nr64(TX_CS(rp->tx_channel)); + + niudbg(INTR, "%s: txchan_intr cs[%llx]\n", + np->dev->name, (unsigned long long) rp->tx_cs); +} + +static void __niu_fastpath_interrupt(struct niu *np, int ldg, u64 v0) +{ + struct niu_parent *parent = np->parent; + u32 rx_vec, tx_vec; + int i; + + tx_vec = (v0 >> 32); + rx_vec = (v0 & 0xffffffff); + + for (i = 0; i < np->num_rx_rings; i++) { + struct rx_ring_info *rp = &np->rx_rings[i]; + int ldn = LDN_RXDMA(rp->rx_channel); + + if (parent->ldg_map[ldn] != ldg) + continue; + + nw64(LD_IM0(ldn), LD_IM0_MASK); + if (rx_vec & (1 << rp->rx_channel)) + niu_rxchan_intr(np, rp, ldn); + } + + for (i = 0; i < np->num_tx_rings; i++) { + struct tx_ring_info *rp = &np->tx_rings[i]; + int ldn = LDN_TXDMA(rp->tx_channel); + + if (parent->ldg_map[ldn] != ldg) + continue; + + nw64(LD_IM0(ldn), LD_IM0_MASK); + if (tx_vec & (1 << rp->tx_channel)) + niu_txchan_intr(np, rp, ldn); + } +} + +static void niu_schedule_napi(struct niu *np, struct niu_ldg *lp, + u64 v0, u64 v1, u64 v2) +{ + if (likely(netif_rx_schedule_prep(np->dev, &lp->napi))) { + lp->v0 = v0; + lp->v1 = v1; + lp->v2 = v2; + __niu_fastpath_interrupt(np, lp->ldg_num, v0); + __netif_rx_schedule(np->dev, &lp->napi); + } +} + +static irqreturn_t niu_interrupt(int irq, void *dev_id) +{ + struct niu_ldg *lp = dev_id; + struct niu *np = lp->np; + int ldg = lp->ldg_num; + unsigned long flags; + u64 v0, v1, v2; + + if (netif_msg_intr(np)) + printk(KERN_DEBUG PFX "niu_interrupt() ldg[%p](%d) ", + lp, ldg); + + spin_lock_irqsave(&np->lock, flags); + + v0 = nr64(LDSV0(ldg)); + v1 = nr64(LDSV1(ldg)); + v2 = nr64(LDSV2(ldg)); + + if (netif_msg_intr(np)) + printk("v0[%llx] v1[%llx] v2[%llx]\n", + (unsigned long long) v0, + (unsigned long long) v1, + (unsigned long long) v2); + + if (unlikely(!v0 && !v1 && !v2)) { + spin_unlock_irqrestore(&np->lock, flags); + return IRQ_NONE; + } + + if (unlikely((v0 & ((u64)1 << LDN_MIF)) || v1 || v2)) { + int err = niu_slowpath_interrupt(np, lp); + if (err) + goto out; + } + if (likely(v0 & ~((u64)1 << LDN_MIF))) + niu_schedule_napi(np, lp, v0, v1, v2); + else + niu_ldg_rearm(np, lp, 1); +out: + spin_unlock_irqrestore(&np->lock, flags); + + return IRQ_HANDLED; +} + +static void niu_free_rx_ring_info(struct niu *np, struct rx_ring_info *rp) +{ + if (rp->mbox) { + np->ops->free_coherent(np->device, + sizeof(struct rxdma_mailbox), + rp->mbox, rp->mbox_dma); + rp->mbox = NULL; + } + if (rp->rcr) { + np->ops->free_coherent(np->device, + MAX_RCR_RING_SIZE * sizeof(__le64), + rp->rcr, rp->rcr_dma); + rp->rcr = NULL; + rp->rcr_table_size = 0; + rp->rcr_index = 0; + } + if (rp->rbr) { + niu_rbr_free(np, rp); + + np->ops->free_coherent(np->device, + MAX_RBR_RING_SIZE * sizeof(__le32), + rp->rbr, rp->rbr_dma); + rp->rbr = NULL; + rp->rbr_table_size = 0; + rp->rbr_index = 0; + } + kfree(rp->rxhash); + rp->rxhash = NULL; +} + +static void niu_free_tx_ring_info(struct niu *np, struct tx_ring_info *rp) +{ + if (rp->mbox) { + np->ops->free_coherent(np->device, + sizeof(struct txdma_mailbox), + rp->mbox, rp->mbox_dma); + rp->mbox = NULL; + } + if (rp->descr) { + int i; + + for (i = 0; i < MAX_TX_RING_SIZE; i++) { + if (rp->tx_buffs[i].skb) + (void) release_tx_packet(np, rp, i); + } + + np->ops->free_coherent(np->device, + MAX_TX_RING_SIZE * sizeof(__le64), + rp->descr, rp->descr_dma); + rp->descr = NULL; + rp->pending = 0; + rp->prod = 0; + rp->cons = 0; + rp->wrap_bit = 0; + } +} + +static void niu_free_channels(struct niu *np) +{ + int i; + + if (np->rx_rings) { + for (i = 0; i < np->num_rx_rings; i++) { + struct rx_ring_info *rp = &np->rx_rings[i]; + + niu_free_rx_ring_info(np, rp); + } + kfree(np->rx_rings); + np->rx_rings = NULL; + np->num_rx_rings = 0; + } + + if (np->tx_rings) { + for (i = 0; i < np->num_tx_rings; i++) { + struct tx_ring_info *rp = &np->tx_rings[i]; + + niu_free_tx_ring_info(np, rp); + } + kfree(np->tx_rings); + np->tx_rings = NULL; + np->num_tx_rings = 0; + } +} + +static int niu_alloc_rx_ring_info(struct niu *np, + struct rx_ring_info *rp) +{ + BUILD_BUG_ON(sizeof(struct rxdma_mailbox) != 64); + + rp->rxhash = kzalloc(MAX_RBR_RING_SIZE * sizeof(struct page *), + GFP_KERNEL); + if (!rp->rxhash) + return -ENOMEM; + + rp->mbox = np->ops->alloc_coherent(np->device, + sizeof(struct rxdma_mailbox), + &rp->mbox_dma, GFP_KERNEL); + if (!rp->mbox) + return -ENOMEM; + if ((unsigned long)rp->mbox & (64UL - 1)) { + dev_err(np->device, PFX "%s: Coherent alloc gives misaligned " + "RXDMA mailbox %p\n", np->dev->name, rp->mbox); + return -EINVAL; + } + + rp->rcr = np->ops->alloc_coherent(np->device, + MAX_RCR_RING_SIZE * sizeof(__le64), + &rp->rcr_dma, GFP_KERNEL); + if (!rp->rcr) + return -ENOMEM; + if ((unsigned long)rp->rcr & (64UL - 1)) { + dev_err(np->device, PFX "%s: Coherent alloc gives misaligned " + "RXDMA RCR table %p\n", np->dev->name, rp->rcr); + return -EINVAL; + } + rp->rcr_table_size = MAX_RCR_RING_SIZE; + rp->rcr_index = 0; + + rp->rbr = np->ops->alloc_coherent(np->device, + MAX_RBR_RING_SIZE * sizeof(__le32), + &rp->rbr_dma, GFP_KERNEL); + if (!rp->rbr) + return -ENOMEM; + if ((unsigned long)rp->rbr & (64UL - 1)) { + dev_err(np->device, PFX "%s: Coherent alloc gives misaligned " + "RXDMA RBR table %p\n", np->dev->name, rp->rbr); + return -EINVAL; + } + rp->rbr_table_size = MAX_RBR_RING_SIZE; + rp->rbr_index = 0; + rp->rbr_pending = 0; + + return 0; +} + +static void niu_set_max_burst(struct niu *np, struct tx_ring_info *rp) +{ + int mtu = np->dev->mtu; + + /* These values are recommended by the HW designers for fair + * utilization of DRR amongst the rings. + */ + rp->max_burst = mtu + 32; + if (rp->max_burst > 4096) + rp->max_burst = 4096; +} + +static int niu_alloc_tx_ring_info(struct niu *np, + struct tx_ring_info *rp) +{ + BUILD_BUG_ON(sizeof(struct txdma_mailbox) != 64); + + rp->mbox = np->ops->alloc_coherent(np->device, + sizeof(struct txdma_mailbox), + &rp->mbox_dma, GFP_KERNEL); + if (!rp->mbox) + return -ENOMEM; + if ((unsigned long)rp->mbox & (64UL - 1)) { + dev_err(np->device, PFX "%s: Coherent alloc gives misaligned " + "TXDMA mailbox %p\n", np->dev->name, rp->mbox); + return -EINVAL; + } + + rp->descr = np->ops->alloc_coherent(np->device, + MAX_TX_RING_SIZE * sizeof(__le64), + &rp->descr_dma, GFP_KERNEL); + if (!rp->descr) + return -ENOMEM; + if ((unsigned long)rp->descr & (64UL - 1)) { + dev_err(np->device, PFX "%s: Coherent alloc gives misaligned " + "TXDMA descr table %p\n", np->dev->name, rp->descr); + return -EINVAL; + } + + rp->pending = MAX_TX_RING_SIZE; + rp->prod = 0; + rp->cons = 0; + rp->wrap_bit = 0; + + /* XXX make these configurable... XXX */ + rp->mark_freq = rp->pending / 4; + + niu_set_max_burst(np, rp); + + return 0; +} + +static void niu_size_rbr(struct niu *np, struct rx_ring_info *rp) +{ + u16 bs; + + switch (PAGE_SIZE) { + case 4 * 1024: + case 8 * 1024: + case 16 * 1024: + case 32 * 1024: + rp->rbr_block_size = PAGE_SIZE; + rp->rbr_blocks_per_page = 1; + break; + + default: + if (PAGE_SIZE % (32 * 1024) == 0) + bs = 32 * 1024; + else if (PAGE_SIZE % (16 * 1024) == 0) + bs = 16 * 1024; + else if (PAGE_SIZE % (8 * 1024) == 0) + bs = 8 * 1024; + else if (PAGE_SIZE % (4 * 1024) == 0) + bs = 4 * 1024; + else + BUG(); + rp->rbr_block_size = bs; + rp->rbr_blocks_per_page = PAGE_SIZE / bs; + } + + rp->rbr_sizes[0] = 256; + rp->rbr_sizes[1] = 1024; + if (np->dev->mtu > ETH_DATA_LEN) { + switch (PAGE_SIZE) { + case 4 * 1024: + rp->rbr_sizes[2] = 4096; + break; + + default: + rp->rbr_sizes[2] = 8192; + break; + } + } else { + rp->rbr_sizes[2] = 2048; + } + rp->rbr_sizes[3] = rp->rbr_block_size; +} + +static int niu_alloc_channels(struct niu *np) +{ + struct niu_parent *parent = np->parent; + int first_rx_channel, first_tx_channel; + int i, port, err; + + port = np->port; + first_rx_channel = first_tx_channel = 0; + for (i = 0; i < port; i++) { + first_rx_channel += parent->rxchan_per_port[i]; + first_tx_channel += parent->txchan_per_port[i]; + } + + np->num_rx_rings = parent->rxchan_per_port[port]; + np->num_tx_rings = parent->txchan_per_port[port]; + + np->rx_rings = kzalloc(np->num_rx_rings * sizeof(struct rx_ring_info), + GFP_KERNEL); + err = -ENOMEM; + if (!np->rx_rings) + goto out_err; + + for (i = 0; i < np->num_rx_rings; i++) { + struct rx_ring_info *rp = &np->rx_rings[i]; + + rp->np = np; + rp->rx_channel = first_rx_channel + i; + + err = niu_alloc_rx_ring_info(np, rp); + if (err) + goto out_err; + + niu_size_rbr(np, rp); + + /* XXX better defaults, configurable, etc... XXX */ + rp->nonsyn_window = 64; + rp->nonsyn_threshold = rp->rcr_table_size - 64; + rp->syn_window = 64; + rp->syn_threshold = rp->rcr_table_size - 64; + rp->rcr_pkt_threshold = 16; + rp->rcr_timeout = 8; + rp->rbr_kick_thresh = RBR_REFILL_MIN; + if (rp->rbr_kick_thresh < rp->rbr_blocks_per_page) + rp->rbr_kick_thresh = rp->rbr_blocks_per_page; + + err = niu_rbr_fill(np, rp, GFP_KERNEL); + if (err) + return err; + } + + np->tx_rings = kzalloc(np->num_tx_rings * sizeof(struct tx_ring_info), + GFP_KERNEL); + err = -ENOMEM; + if (!np->tx_rings) + goto out_err; + + for (i = 0; i < np->num_tx_rings; i++) { + struct tx_ring_info *rp = &np->tx_rings[i]; + + rp->np = np; + rp->tx_channel = first_tx_channel + i; + + err = niu_alloc_tx_ring_info(np, rp); + if (err) + goto out_err; + } + + return 0; + +out_err: + niu_free_channels(np); + return err; +} + +static int niu_tx_cs_sng_poll(struct niu *np, int channel) +{ + int limit = 1000; + + while (--limit > 0) { + u64 val = nr64(TX_CS(channel)); + if (val & TX_CS_SNG_STATE) + return 0; + } + return -ENODEV; +} + +static int niu_tx_channel_stop(struct niu *np, int channel) +{ + u64 val = nr64(TX_CS(channel)); + + val |= TX_CS_STOP_N_GO; + nw64(TX_CS(channel), val); + + return niu_tx_cs_sng_poll(np, channel); +} + +static int niu_tx_cs_reset_poll(struct niu *np, int channel) +{ + int limit = 1000; + + while (--limit > 0) { + u64 val = nr64(TX_CS(channel)); + if (!(val & TX_CS_RST)) + return 0; + } + return -ENODEV; +} + +static int niu_tx_channel_reset(struct niu *np, int channel) +{ + u64 val = nr64(TX_CS(channel)); + int err; + + val |= TX_CS_RST; + nw64(TX_CS(channel), val); + + err = niu_tx_cs_reset_poll(np, channel); + if (!err) + nw64(TX_RING_KICK(channel), 0); + + return err; +} + +static int niu_tx_channel_lpage_init(struct niu *np, int channel) +{ + u64 val; + + nw64(TX_LOG_MASK1(channel), 0); + nw64(TX_LOG_VAL1(channel), 0); + nw64(TX_LOG_MASK2(channel), 0); + nw64(TX_LOG_VAL2(channel), 0); + nw64(TX_LOG_PAGE_RELO1(channel), 0); + nw64(TX_LOG_PAGE_RELO2(channel), 0); + nw64(TX_LOG_PAGE_HDL(channel), 0); + + val = (u64)np->port << TX_LOG_PAGE_VLD_FUNC_SHIFT; + val |= (TX_LOG_PAGE_VLD_PAGE0 | TX_LOG_PAGE_VLD_PAGE1); + nw64(TX_LOG_PAGE_VLD(channel), val); + + /* XXX TXDMA 32bit mode? XXX */ + + return 0; +} + +static void niu_txc_enable_port(struct niu *np, int on) +{ + unsigned long flags; + u64 val, mask; + + niu_lock_parent(np, flags); + val = nr64(TXC_CONTROL); + mask = (u64)1 << np->port; + if (on) { + val |= TXC_CONTROL_ENABLE | mask; + } else { + val &= ~mask; + if ((val & ~TXC_CONTROL_ENABLE) == 0) + val &= ~TXC_CONTROL_ENABLE; + } + nw64(TXC_CONTROL, val); + niu_unlock_parent(np, flags); +} + +static void niu_txc_set_imask(struct niu *np, u64 imask) +{ + unsigned long flags; + u64 val; + + niu_lock_parent(np, flags); + val = nr64(TXC_INT_MASK); + val &= ~TXC_INT_MASK_VAL(np->port); + val |= (imask << TXC_INT_MASK_VAL_SHIFT(np->port)); + niu_unlock_parent(np, flags); +} + +static void niu_txc_port_dma_enable(struct niu *np, int on) +{ + u64 val = 0; + + if (on) { + int i; + + for (i = 0; i < np->num_tx_rings; i++) + val |= (1 << np->tx_rings[i].tx_channel); + } + nw64(TXC_PORT_DMA(np->port), val); +} + +static int niu_init_one_tx_channel(struct niu *np, struct tx_ring_info *rp) +{ + int err, channel = rp->tx_channel; + u64 val, ring_len; + + err = niu_tx_channel_stop(np, channel); + if (err) + return err; + + err = niu_tx_channel_reset(np, channel); + if (err) + return err; + + err = niu_tx_channel_lpage_init(np, channel); + if (err) + return err; + + nw64(TXC_DMA_MAX(channel), rp->max_burst); + nw64(TX_ENT_MSK(channel), 0); + + if (rp->descr_dma & ~(TX_RNG_CFIG_STADDR_BASE | + TX_RNG_CFIG_STADDR)) { + dev_err(np->device, PFX "%s: TX ring channel %d " + "DMA addr (%llx) is not aligned.\n", + np->dev->name, channel, + (unsigned long long) rp->descr_dma); + return -EINVAL; + } + + /* The length field in TX_RNG_CFIG is measured in 64-byte + * blocks. rp->pending is the number of TX descriptors in + * our ring, 8 bytes each, thus we divide by 8 bytes more + * to get the proper value the chip wants. + */ + ring_len = (rp->pending / 8); + + val = ((ring_len << TX_RNG_CFIG_LEN_SHIFT) | + rp->descr_dma); + nw64(TX_RNG_CFIG(channel), val); + + if (((rp->mbox_dma >> 32) & ~TXDMA_MBH_MBADDR) || + ((u32)rp->mbox_dma & ~TXDMA_MBL_MBADDR)) { + dev_err(np->device, PFX "%s: TX ring channel %d " + "MBOX addr (%llx) is has illegal bits.\n", + np->dev->name, channel, + (unsigned long long) rp->mbox_dma); + return -EINVAL; + } + nw64(TXDMA_MBH(channel), rp->mbox_dma >> 32); + nw64(TXDMA_MBL(channel), rp->mbox_dma & TXDMA_MBL_MBADDR); + + nw64(TX_CS(channel), 0); + + rp->last_pkt_cnt = 0; + + return 0; +} + +static void niu_init_rdc_groups(struct niu *np) +{ + struct niu_rdc_tables *tp = &np->parent->rdc_group_cfg[np->port]; + int i, first_table_num = tp->first_table_num; + + for (i = 0; i < tp->num_tables; i++) { + struct rdc_table *tbl = &tp->tables[i]; + int this_table = first_table_num + i; + int slot; + + for (slot = 0; slot < NIU_RDC_TABLE_SLOTS; slot++) + nw64(RDC_TBL(this_table, slot), + tbl->rxdma_channel[slot]); + } + + nw64(DEF_RDC(np->port), np->parent->rdc_default[np->port]); +} + +static void niu_init_drr_weight(struct niu *np) +{ + int type = phy_decode(np->parent->port_phy, np->port); + u64 val; + + switch (type) { + case PORT_TYPE_10G: + val = PT_DRR_WEIGHT_DEFAULT_10G; + break; + + case PORT_TYPE_1G: + default: + val = PT_DRR_WEIGHT_DEFAULT_1G; + break; + } + nw64(PT_DRR_WT(np->port), val); +} + +static int niu_init_hostinfo(struct niu *np) +{ + struct niu_parent *parent = np->parent; + struct niu_rdc_tables *tp = &parent->rdc_group_cfg[np->port]; + int i, err, num_alt = niu_num_alt_addr(np); + int first_rdc_table = tp->first_table_num; + + err = niu_set_primary_mac_rdc_table(np, first_rdc_table, 1); + if (err) + return err; + + err = niu_set_multicast_mac_rdc_table(np, first_rdc_table, 1); + if (err) + return err; + + for (i = 0; i < num_alt; i++) { + err = niu_set_alt_mac_rdc_table(np, i, first_rdc_table, 1); + if (err) + return err; + } + + return 0; +} + +static int niu_rx_channel_reset(struct niu *np, int channel) +{ + return niu_set_and_wait_clear(np, RXDMA_CFIG1(channel), + RXDMA_CFIG1_RST, 1000, 10, + "RXDMA_CFIG1"); +} + +static int niu_rx_channel_lpage_init(struct niu *np, int channel) +{ + u64 val; + + nw64(RX_LOG_MASK1(channel), 0); + nw64(RX_LOG_VAL1(channel), 0); + nw64(RX_LOG_MASK2(channel), 0); + nw64(RX_LOG_VAL2(channel), 0); + nw64(RX_LOG_PAGE_RELO1(channel), 0); + nw64(RX_LOG_PAGE_RELO2(channel), 0); + nw64(RX_LOG_PAGE_HDL(channel), 0); + + val = (u64)np->port << RX_LOG_PAGE_VLD_FUNC_SHIFT; + val |= (RX_LOG_PAGE_VLD_PAGE0 | RX_LOG_PAGE_VLD_PAGE1); + nw64(RX_LOG_PAGE_VLD(channel), val); + + return 0; +} + +static void niu_rx_channel_wred_init(struct niu *np, struct rx_ring_info *rp) +{ + u64 val; + + val = (((u64)rp->nonsyn_window << RDC_RED_PARA_WIN_SHIFT) | + ((u64)rp->nonsyn_threshold << RDC_RED_PARA_THRE_SHIFT) | + ((u64)rp->syn_window << RDC_RED_PARA_WIN_SYN_SHIFT) | + ((u64)rp->syn_threshold << RDC_RED_PARA_THRE_SYN_SHIFT)); + nw64(RDC_RED_PARA(rp->rx_channel), val); +} + +static int niu_compute_rbr_cfig_b(struct rx_ring_info *rp, u64 *ret) +{ + u64 val = 0; + + switch (rp->rbr_block_size) { + case 4 * 1024: + val |= (RBR_BLKSIZE_4K << RBR_CFIG_B_BLKSIZE_SHIFT); + break; + case 8 * 1024: + val |= (RBR_BLKSIZE_8K << RBR_CFIG_B_BLKSIZE_SHIFT); + break; + case 16 * 1024: + val |= (RBR_BLKSIZE_16K << RBR_CFIG_B_BLKSIZE_SHIFT); + break; + case 32 * 1024: + val |= (RBR_BLKSIZE_32K << RBR_CFIG_B_BLKSIZE_SHIFT); + break; + default: + return -EINVAL; + } + val |= RBR_CFIG_B_VLD2; + switch (rp->rbr_sizes[2]) { + case 2 * 1024: + val |= (RBR_BUFSZ2_2K << RBR_CFIG_B_BUFSZ2_SHIFT); + break; + case 4 * 1024: + val |= (RBR_BUFSZ2_4K << RBR_CFIG_B_BUFSZ2_SHIFT); + break; + case 8 * 1024: + val |= (RBR_BUFSZ2_8K << RBR_CFIG_B_BUFSZ2_SHIFT); + break; + case 16 * 1024: + val |= (RBR_BUFSZ2_16K << RBR_CFIG_B_BUFSZ2_SHIFT); + break; + + default: + return -EINVAL; + } + val |= RBR_CFIG_B_VLD1; + switch (rp->rbr_sizes[1]) { + case 1 * 1024: + val |= (RBR_BUFSZ1_1K << RBR_CFIG_B_BUFSZ1_SHIFT); + break; + case 2 * 1024: + val |= (RBR_BUFSZ1_2K << RBR_CFIG_B_BUFSZ1_SHIFT); + break; + case 4 * 1024: + val |= (RBR_BUFSZ1_4K << RBR_CFIG_B_BUFSZ1_SHIFT); + break; + case 8 * 1024: + val |= (RBR_BUFSZ1_8K << RBR_CFIG_B_BUFSZ1_SHIFT); + break; + + default: + return -EINVAL; + } + val |= RBR_CFIG_B_VLD0; + switch (rp->rbr_sizes[0]) { + case 256: + val |= (RBR_BUFSZ0_256 << RBR_CFIG_B_BUFSZ0_SHIFT); + break; + case 512: + val |= (RBR_BUFSZ0_512 << RBR_CFIG_B_BUFSZ0_SHIFT); + break; + case 1 * 1024: + val |= (RBR_BUFSZ0_1K << RBR_CFIG_B_BUFSZ0_SHIFT); + break; + case 2 * 1024: + val |= (RBR_BUFSZ0_2K << RBR_CFIG_B_BUFSZ0_SHIFT); + break; + + default: + return -EINVAL; + } + + *ret = val; + return 0; +} + +static int niu_enable_rx_channel(struct niu *np, int channel, int on) +{ + u64 val = nr64(RXDMA_CFIG1(channel)); + int limit; + + if (on) + val |= RXDMA_CFIG1_EN; + else + val &= ~RXDMA_CFIG1_EN; + nw64(RXDMA_CFIG1(channel), val); + + limit = 1000; + while (--limit > 0) { + if (nr64(RXDMA_CFIG1(channel)) & RXDMA_CFIG1_QST) + break; + udelay(10); + } + if (limit <= 0) + return -ENODEV; + return 0; +} + +static int niu_init_one_rx_channel(struct niu *np, struct rx_ring_info *rp) +{ + int err, channel = rp->rx_channel; + u64 val; + + err = niu_rx_channel_reset(np, channel); + if (err) + return err; + + err = niu_rx_channel_lpage_init(np, channel); + if (err) + return err; + + niu_rx_channel_wred_init(np, rp); + + nw64(RX_DMA_ENT_MSK(channel), RX_DMA_ENT_MSK_RBR_EMPTY); + nw64(RX_DMA_CTL_STAT(channel), + (RX_DMA_CTL_STAT_MEX | + RX_DMA_CTL_STAT_RCRTHRES | + RX_DMA_CTL_STAT_RCRTO | + RX_DMA_CTL_STAT_RBR_EMPTY)); + nw64(RXDMA_CFIG1(channel), rp->mbox_dma >> 32); + nw64(RXDMA_CFIG2(channel), (rp->mbox_dma & 0x00000000ffffffc0)); + nw64(RBR_CFIG_A(channel), + ((u64)rp->rbr_table_size << RBR_CFIG_A_LEN_SHIFT) | + (rp->rbr_dma & (RBR_CFIG_A_STADDR_BASE | RBR_CFIG_A_STADDR))); + err = niu_compute_rbr_cfig_b(rp, &val); + if (err) + return err; + nw64(RBR_CFIG_B(channel), val); + nw64(RCRCFIG_A(channel), + ((u64)rp->rcr_table_size << RCRCFIG_A_LEN_SHIFT) | + (rp->rcr_dma & (RCRCFIG_A_STADDR_BASE | RCRCFIG_A_STADDR))); + nw64(RCRCFIG_B(channel), + ((u64)rp->rcr_pkt_threshold << RCRCFIG_B_PTHRES_SHIFT) | + RCRCFIG_B_ENTOUT | + ((u64)rp->rcr_timeout << RCRCFIG_B_TIMEOUT_SHIFT)); + + err = niu_enable_rx_channel(np, channel, 1); + if (err) + return err; + + nw64(RBR_KICK(channel), rp->rbr_index); + + val = nr64(RX_DMA_CTL_STAT(channel)); + val |= RX_DMA_CTL_STAT_RBR_EMPTY; + nw64(RX_DMA_CTL_STAT(channel), val); + + return 0; +} + +static int niu_init_rx_channels(struct niu *np) +{ + unsigned long flags; + u64 seed = jiffies_64; + int err, i; + + niu_lock_parent(np, flags); + nw64(RX_DMA_CK_DIV, np->parent->rxdma_clock_divider); + nw64(RED_RAN_INIT, RED_RAN_INIT_OPMODE | (seed & RED_RAN_INIT_VAL)); + niu_unlock_parent(np, flags); + + /* XXX RXDMA 32bit mode? XXX */ + + niu_init_rdc_groups(np); + niu_init_drr_weight(np); + + err = niu_init_hostinfo(np); + if (err) + return err; + + for (i = 0; i < np->num_rx_rings; i++) { + struct rx_ring_info *rp = &np->rx_rings[i]; + + err = niu_init_one_rx_channel(np, rp); + if (err) + return err; + } + + return 0; +} + +static int niu_set_ip_frag_rule(struct niu *np) +{ + struct niu_parent *parent = np->parent; + struct niu_classifier *cp = &np->clas; + struct niu_tcam_entry *tp; + int index, err; + + /* XXX fix this allocation scheme XXX */ + index = cp->tcam_index; + tp = &parent->tcam[index]; + + /* Note that the noport bit is the same in both ipv4 and + * ipv6 format TCAM entries. + */ + memset(tp, 0, sizeof(*tp)); + tp->key[1] = TCAM_V4KEY1_NOPORT; + tp->key_mask[1] = TCAM_V4KEY1_NOPORT; + tp->assoc_data = (TCAM_ASSOCDATA_TRES_USE_OFFSET | + ((u64)0 << TCAM_ASSOCDATA_OFFSET_SHIFT)); + err = tcam_write(np, index, tp->key, tp->key_mask); + if (err) + return err; + err = tcam_assoc_write(np, index, tp->assoc_data); + if (err) + return err; + + return 0; +} + +static int niu_init_classifier_hw(struct niu *np) +{ + struct niu_parent *parent = np->parent; + struct niu_classifier *cp = &np->clas; + int i, err; + + nw64(H1POLY, cp->h1_init); + nw64(H2POLY, cp->h2_init); + + err = niu_init_hostinfo(np); + if (err) + return err; + + for (i = 0; i < ENET_VLAN_TBL_NUM_ENTRIES; i++) { + struct niu_vlan_rdc *vp = &cp->vlan_mappings[i]; + + vlan_tbl_write(np, i, np->port, + vp->vlan_pref, vp->rdc_num); + } + + for (i = 0; i < cp->num_alt_mac_mappings; i++) { + struct niu_altmac_rdc *ap = &cp->alt_mac_mappings[i]; + + err = niu_set_alt_mac_rdc_table(np, ap->alt_mac_num, + ap->rdc_num, ap->mac_pref); + if (err) + return err; + } + + for (i = CLASS_CODE_USER_PROG1; i <= CLASS_CODE_SCTP_IPV6; i++) { + int index = i - CLASS_CODE_USER_PROG1; + + err = niu_set_tcam_key(np, i, parent->tcam_key[index]); + if (err) + return err; + err = niu_set_flow_key(np, i, parent->flow_key[index]); + if (err) + return err; + } + + err = niu_set_ip_frag_rule(np); + if (err) + return err; + + tcam_enable(np, 1); + + return 0; +} + +static int niu_zcp_write(struct niu *np, int index, u64 *data) +{ + nw64(ZCP_RAM_DATA0, data[0]); + nw64(ZCP_RAM_DATA1, data[1]); + nw64(ZCP_RAM_DATA2, data[2]); + nw64(ZCP_RAM_DATA3, data[3]); + nw64(ZCP_RAM_DATA4, data[4]); + nw64(ZCP_RAM_BE, ZCP_RAM_BE_VAL); + nw64(ZCP_RAM_ACC, + (ZCP_RAM_ACC_WRITE | + (0 << ZCP_RAM_ACC_ZFCID_SHIFT) | + (ZCP_RAM_SEL_CFIFO(np->port) << ZCP_RAM_ACC_RAM_SEL_SHIFT))); + + return niu_wait_bits_clear(np, ZCP_RAM_ACC, ZCP_RAM_ACC_BUSY, + 1000, 100); +} + +static int niu_zcp_read(struct niu *np, int index, u64 *data) +{ + int err; + + err = niu_wait_bits_clear(np, ZCP_RAM_ACC, ZCP_RAM_ACC_BUSY, + 1000, 100); + if (err) { + dev_err(np->device, PFX "%s: ZCP read busy won't clear, " + "ZCP_RAM_ACC[%llx]\n", np->dev->name, + (unsigned long long) nr64(ZCP_RAM_ACC)); + return err; + } + + nw64(ZCP_RAM_ACC, + (ZCP_RAM_ACC_READ | + (0 << ZCP_RAM_ACC_ZFCID_SHIFT) | + (ZCP_RAM_SEL_CFIFO(np->port) << ZCP_RAM_ACC_RAM_SEL_SHIFT))); + + err = niu_wait_bits_clear(np, ZCP_RAM_ACC, ZCP_RAM_ACC_BUSY, + 1000, 100); + if (err) { + dev_err(np->device, PFX "%s: ZCP read busy2 won't clear, " + "ZCP_RAM_ACC[%llx]\n", np->dev->name, + (unsigned long long) nr64(ZCP_RAM_ACC)); + return err; + } + + data[0] = nr64(ZCP_RAM_DATA0); + data[1] = nr64(ZCP_RAM_DATA1); + data[2] = nr64(ZCP_RAM_DATA2); + data[3] = nr64(ZCP_RAM_DATA3); + data[4] = nr64(ZCP_RAM_DATA4); + + return 0; +} + +static void niu_zcp_cfifo_reset(struct niu *np) +{ + u64 val = nr64(RESET_CFIFO); + + val |= RESET_CFIFO_RST(np->port); + nw64(RESET_CFIFO, val); + udelay(10); + + val &= ~RESET_CFIFO_RST(np->port); + nw64(RESET_CFIFO, val); +} + +static int niu_init_zcp(struct niu *np) +{ + u64 data[5], rbuf[5]; + int i, max, err; + + if (np->parent->plat_type != PLAT_TYPE_NIU) { + if (np->port == 0 || np->port == 1) + max = ATLAS_P0_P1_CFIFO_ENTRIES; + else + max = ATLAS_P2_P3_CFIFO_ENTRIES; + } else + max = NIU_CFIFO_ENTRIES; + + data[0] = 0; + data[1] = 0; + data[2] = 0; + data[3] = 0; + data[4] = 0; + + for (i = 0; i < max; i++) { + err = niu_zcp_write(np, i, data); + if (err) + return err; + err = niu_zcp_read(np, i, rbuf); + if (err) + return err; + } + + niu_zcp_cfifo_reset(np); + nw64(CFIFO_ECC(np->port), 0); + nw64(ZCP_INT_STAT, ZCP_INT_STAT_ALL); + (void) nr64(ZCP_INT_STAT); + nw64(ZCP_INT_MASK, ZCP_INT_MASK_ALL); + + return 0; +} + +static void niu_ipp_write(struct niu *np, int index, u64 *data) +{ + u64 val = nr64_ipp(IPP_CFIG); + + nw64_ipp(IPP_CFIG, val | IPP_CFIG_DFIFO_PIO_W); + nw64_ipp(IPP_DFIFO_WR_PTR, index); + nw64_ipp(IPP_DFIFO_WR0, data[0]); + nw64_ipp(IPP_DFIFO_WR1, data[1]); + nw64_ipp(IPP_DFIFO_WR2, data[2]); + nw64_ipp(IPP_DFIFO_WR3, data[3]); + nw64_ipp(IPP_DFIFO_WR4, data[4]); + nw64_ipp(IPP_CFIG, val & ~IPP_CFIG_DFIFO_PIO_W); +} + +static void niu_ipp_read(struct niu *np, int index, u64 *data) +{ + nw64_ipp(IPP_DFIFO_RD_PTR, index); + data[0] = nr64_ipp(IPP_DFIFO_RD0); + data[1] = nr64_ipp(IPP_DFIFO_RD1); + data[2] = nr64_ipp(IPP_DFIFO_RD2); + data[3] = nr64_ipp(IPP_DFIFO_RD3); + data[4] = nr64_ipp(IPP_DFIFO_RD4); +} + +static int niu_ipp_reset(struct niu *np) +{ + return niu_set_and_wait_clear_ipp(np, IPP_CFIG, IPP_CFIG_SOFT_RST, + 1000, 100, "IPP_CFIG"); +} + +static int niu_init_ipp(struct niu *np) +{ + u64 data[5], rbuf[5], val; + int i, max, err; + + if (np->parent->plat_type != PLAT_TYPE_NIU) { + if (np->port == 0 || np->port == 1) + max = ATLAS_P0_P1_DFIFO_ENTRIES; + else + max = ATLAS_P2_P3_DFIFO_ENTRIES; + } else + max = NIU_DFIFO_ENTRIES; + + data[0] = 0; + data[1] = 0; + data[2] = 0; + data[3] = 0; + data[4] = 0; + + for (i = 0; i < max; i++) { + niu_ipp_write(np, i, data); + niu_ipp_read(np, i, rbuf); + } + + (void) nr64_ipp(IPP_INT_STAT); + (void) nr64_ipp(IPP_INT_STAT); + + err = niu_ipp_reset(np); + if (err) + return err; + + (void) nr64_ipp(IPP_PKT_DIS); + (void) nr64_ipp(IPP_BAD_CS_CNT); + (void) nr64_ipp(IPP_ECC); + + (void) nr64_ipp(IPP_INT_STAT); + + nw64_ipp(IPP_MSK, ~IPP_MSK_ALL); + + val = nr64_ipp(IPP_CFIG); + val &= ~IPP_CFIG_IP_MAX_PKT; + val |= (IPP_CFIG_IPP_ENABLE | + IPP_CFIG_DFIFO_ECC_EN | + IPP_CFIG_DROP_BAD_CRC | + IPP_CFIG_CKSUM_EN | + (0x1ffff << IPP_CFIG_IP_MAX_PKT_SHIFT)); + nw64_ipp(IPP_CFIG, val); + + return 0; +} + +static void niu_init_xif_xmac(struct niu *np) +{ + struct niu_link_config *lp = &np->link_config; + u64 val; + + val = nr64_mac(XMAC_CONFIG); + + if ((np->flags & NIU_FLAGS_10G) != 0 && + (np->flags & NIU_FLAGS_FIBER) != 0) { + if (netif_carrier_ok(np->dev)) { + val |= XMAC_CONFIG_LED_POLARITY; + val &= ~XMAC_CONFIG_FORCE_LED_ON; + } else { + val |= XMAC_CONFIG_FORCE_LED_ON; + val &= ~XMAC_CONFIG_LED_POLARITY; + } + } + + val &= ~XMAC_CONFIG_SEL_POR_CLK_SRC; + + val |= XMAC_CONFIG_TX_OUTPUT_EN; + + if (lp->loopback_mode == LOOPBACK_MAC) { + val &= ~XMAC_CONFIG_SEL_POR_CLK_SRC; + val |= XMAC_CONFIG_LOOPBACK; + } else { + val &= ~XMAC_CONFIG_LOOPBACK; + } + + if (np->flags & NIU_FLAGS_10G) { + val &= ~XMAC_CONFIG_LFS_DISABLE; + } else { + val |= XMAC_CONFIG_LFS_DISABLE; + if (!(np->flags & NIU_FLAGS_FIBER)) + val |= XMAC_CONFIG_1G_PCS_BYPASS; + else + val &= ~XMAC_CONFIG_1G_PCS_BYPASS; + } + + val &= ~XMAC_CONFIG_10G_XPCS_BYPASS; + + if (lp->active_speed == SPEED_100) + val |= XMAC_CONFIG_SEL_CLK_25MHZ; + else + val &= ~XMAC_CONFIG_SEL_CLK_25MHZ; + + nw64_mac(XMAC_CONFIG, val); + + val = nr64_mac(XMAC_CONFIG); + val &= ~XMAC_CONFIG_MODE_MASK; + if (np->flags & NIU_FLAGS_10G) { + val |= XMAC_CONFIG_MODE_XGMII; + } else { + if (lp->active_speed == SPEED_100) + val |= XMAC_CONFIG_MODE_MII; + else + val |= XMAC_CONFIG_MODE_GMII; + } + + nw64_mac(XMAC_CONFIG, val); +} + +static void niu_init_xif_bmac(struct niu *np) +{ + struct niu_link_config *lp = &np->link_config; + u64 val; + + val = BMAC_XIF_CONFIG_TX_OUTPUT_EN; + + if (lp->loopback_mode == LOOPBACK_MAC) + val |= BMAC_XIF_CONFIG_MII_LOOPBACK; + else + val &= ~BMAC_XIF_CONFIG_MII_LOOPBACK; + + if (lp->active_speed == SPEED_1000) + val |= BMAC_XIF_CONFIG_GMII_MODE; + else + val &= ~BMAC_XIF_CONFIG_GMII_MODE; + + val &= ~(BMAC_XIF_CONFIG_LINK_LED | + BMAC_XIF_CONFIG_LED_POLARITY); + + if (!(np->flags & NIU_FLAGS_10G) && + !(np->flags & NIU_FLAGS_FIBER) && + lp->active_speed == SPEED_100) + val |= BMAC_XIF_CONFIG_25MHZ_CLOCK; + else + val &= ~BMAC_XIF_CONFIG_25MHZ_CLOCK; + + nw64_mac(BMAC_XIF_CONFIG, val); +} + +static void niu_init_xif(struct niu *np) +{ + if (np->flags & NIU_FLAGS_XMAC) + niu_init_xif_xmac(np); + else + niu_init_xif_bmac(np); +} + +static void niu_pcs_mii_reset(struct niu *np) +{ + u64 val = nr64_pcs(PCS_MII_CTL); + val |= PCS_MII_CTL_RST; + nw64_pcs(PCS_MII_CTL, val); +} + +static void niu_xpcs_reset(struct niu *np) +{ + u64 val = nr64_xpcs(XPCS_CONTROL1); + val |= XPCS_CONTROL1_RESET; + nw64_xpcs(XPCS_CONTROL1, val); +} + +static int niu_init_pcs(struct niu *np) +{ + struct niu_link_config *lp = &np->link_config; + u64 val; + + switch (np->flags & (NIU_FLAGS_10G | NIU_FLAGS_FIBER)) { + case NIU_FLAGS_FIBER: + /* 1G fiber */ + nw64_pcs(PCS_CONF, PCS_CONF_MASK | PCS_CONF_ENABLE); + nw64_pcs(PCS_DPATH_MODE, 0); + niu_pcs_mii_reset(np); + break; + + case NIU_FLAGS_10G: + case NIU_FLAGS_10G | NIU_FLAGS_FIBER: + if (!(np->flags & NIU_FLAGS_XMAC)) + return -EINVAL; + + /* 10G copper or fiber */ + val = nr64_mac(XMAC_CONFIG); + val &= ~XMAC_CONFIG_10G_XPCS_BYPASS; + nw64_mac(XMAC_CONFIG, val); + + niu_xpcs_reset(np); + + val = nr64_xpcs(XPCS_CONTROL1); + if (lp->loopback_mode == LOOPBACK_PHY) + val |= XPCS_CONTROL1_LOOPBACK; + else + val &= ~XPCS_CONTROL1_LOOPBACK; + nw64_xpcs(XPCS_CONTROL1, val); + + nw64_xpcs(XPCS_DESKEW_ERR_CNT, 0); + (void) nr64_xpcs(XPCS_SYMERR_CNT01); + (void) nr64_xpcs(XPCS_SYMERR_CNT23); + break; + + case 0: + /* 1G copper */ + nw64_pcs(PCS_DPATH_MODE, PCS_DPATH_MODE_MII); + niu_pcs_mii_reset(np); + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int niu_reset_tx_xmac(struct niu *np) +{ + return niu_set_and_wait_clear_mac(np, XTXMAC_SW_RST, + (XTXMAC_SW_RST_REG_RS | + XTXMAC_SW_RST_SOFT_RST), + 1000, 100, "XTXMAC_SW_RST"); +} + +static int niu_reset_tx_bmac(struct niu *np) +{ + int limit; + + nw64_mac(BTXMAC_SW_RST, BTXMAC_SW_RST_RESET); + limit = 1000; + while (--limit >= 0) { + if (!(nr64_mac(BTXMAC_SW_RST) & BTXMAC_SW_RST_RESET)) + break; + udelay(100); + } + if (limit < 0) { + dev_err(np->device, PFX "Port %u TX BMAC would not reset, " + "BTXMAC_SW_RST[%llx]\n", + np->port, + (unsigned long long) nr64_mac(BTXMAC_SW_RST)); + return -ENODEV; + } + + return 0; +} + +static int niu_reset_tx_mac(struct niu *np) +{ + if (np->flags & NIU_FLAGS_XMAC) + return niu_reset_tx_xmac(np); + else + return niu_reset_tx_bmac(np); +} + +static void niu_init_tx_xmac(struct niu *np, u64 min, u64 max) +{ + u64 val; + + val = nr64_mac(XMAC_MIN); + val &= ~(XMAC_MIN_TX_MIN_PKT_SIZE | + XMAC_MIN_RX_MIN_PKT_SIZE); + val |= (min << XMAC_MIN_RX_MIN_PKT_SIZE_SHFT); + val |= (min << XMAC_MIN_TX_MIN_PKT_SIZE_SHFT); + nw64_mac(XMAC_MIN, val); + + nw64_mac(XMAC_MAX, max); + + nw64_mac(XTXMAC_STAT_MSK, ~(u64)0); + + val = nr64_mac(XMAC_IPG); + if (np->flags & NIU_FLAGS_10G) { + val &= ~XMAC_IPG_IPG_XGMII; + val |= (IPG_12_15_XGMII << XMAC_IPG_IPG_XGMII_SHIFT); + } else { + val &= ~XMAC_IPG_IPG_MII_GMII; + val |= (IPG_12_MII_GMII << XMAC_IPG_IPG_MII_GMII_SHIFT); + } + nw64_mac(XMAC_IPG, val); + + val = nr64_mac(XMAC_CONFIG); + val &= ~(XMAC_CONFIG_ALWAYS_NO_CRC | + XMAC_CONFIG_STRETCH_MODE | + XMAC_CONFIG_VAR_MIN_IPG_EN | + XMAC_CONFIG_TX_ENABLE); + nw64_mac(XMAC_CONFIG, val); + + nw64_mac(TXMAC_FRM_CNT, 0); + nw64_mac(TXMAC_BYTE_CNT, 0); +} + +static void niu_init_tx_bmac(struct niu *np, u64 min, u64 max) +{ + u64 val; + + nw64_mac(BMAC_MIN_FRAME, min); + nw64_mac(BMAC_MAX_FRAME, max); + + nw64_mac(BTXMAC_STATUS_MASK, ~(u64)0); + nw64_mac(BMAC_CTRL_TYPE, 0x8808); + nw64_mac(BMAC_PREAMBLE_SIZE, 7); + + val = nr64_mac(BTXMAC_CONFIG); + val &= ~(BTXMAC_CONFIG_FCS_DISABLE | + BTXMAC_CONFIG_ENABLE); + nw64_mac(BTXMAC_CONFIG, val); +} + +static void niu_init_tx_mac(struct niu *np) +{ + u64 min, max; + + min = 64; + if (np->dev->mtu > ETH_DATA_LEN) + max = 9216; + else + max = 1522; + + /* The XMAC_MIN register only accepts values for TX min which + * have the low 3 bits cleared. + */ + BUILD_BUG_ON(min & 0x7); + + if (np->flags & NIU_FLAGS_XMAC) + niu_init_tx_xmac(np, min, max); + else + niu_init_tx_bmac(np, min, max); +} + +static int niu_reset_rx_xmac(struct niu *np) +{ + int limit; + + nw64_mac(XRXMAC_SW_RST, + XRXMAC_SW_RST_REG_RS | XRXMAC_SW_RST_SOFT_RST); + limit = 1000; + while (--limit >= 0) { + if (!(nr64_mac(XRXMAC_SW_RST) & (XRXMAC_SW_RST_REG_RS | + XRXMAC_SW_RST_SOFT_RST))) + break; + udelay(100); + } + if (limit < 0) { + dev_err(np->device, PFX "Port %u RX XMAC would not reset, " + "XRXMAC_SW_RST[%llx]\n", + np->port, + (unsigned long long) nr64_mac(XRXMAC_SW_RST)); + return -ENODEV; + } + + return 0; +} + +static int niu_reset_rx_bmac(struct niu *np) +{ + int limit; + + nw64_mac(BRXMAC_SW_RST, BRXMAC_SW_RST_RESET); + limit = 1000; + while (--limit >= 0) { + if (!(nr64_mac(BRXMAC_SW_RST) & BRXMAC_SW_RST_RESET)) + break; + udelay(100); + } + if (limit < 0) { + dev_err(np->device, PFX "Port %u RX BMAC would not reset, " + "BRXMAC_SW_RST[%llx]\n", + np->port, + (unsigned long long) nr64_mac(BRXMAC_SW_RST)); + return -ENODEV; + } + + return 0; +} + +static int niu_reset_rx_mac(struct niu *np) +{ + if (np->flags & NIU_FLAGS_XMAC) + return niu_reset_rx_xmac(np); + else + return niu_reset_rx_bmac(np); +} + +static void niu_init_rx_xmac(struct niu *np) +{ + struct niu_parent *parent = np->parent; + struct niu_rdc_tables *tp = &parent->rdc_group_cfg[np->port]; + int first_rdc_table = tp->first_table_num; + unsigned long i; + u64 val; + + nw64_mac(XMAC_ADD_FILT0, 0); + nw64_mac(XMAC_ADD_FILT1, 0); + nw64_mac(XMAC_ADD_FILT2, 0); + nw64_mac(XMAC_ADD_FILT12_MASK, 0); + nw64_mac(XMAC_ADD_FILT00_MASK, 0); + for (i = 0; i < MAC_NUM_HASH; i++) + nw64_mac(XMAC_HASH_TBL(i), 0); + nw64_mac(XRXMAC_STAT_MSK, ~(u64)0); + niu_set_primary_mac_rdc_table(np, first_rdc_table, 1); + niu_set_multicast_mac_rdc_table(np, first_rdc_table, 1); + + val = nr64_mac(XMAC_CONFIG); + val &= ~(XMAC_CONFIG_RX_MAC_ENABLE | + XMAC_CONFIG_PROMISCUOUS | + XMAC_CONFIG_PROMISC_GROUP | + XMAC_CONFIG_ERR_CHK_DIS | + XMAC_CONFIG_RX_CRC_CHK_DIS | + XMAC_CONFIG_RESERVED_MULTICAST | + XMAC_CONFIG_RX_CODEV_CHK_DIS | + XMAC_CONFIG_ADDR_FILTER_EN | + XMAC_CONFIG_RCV_PAUSE_ENABLE | + XMAC_CONFIG_STRIP_CRC | + XMAC_CONFIG_PASS_FLOW_CTRL | + XMAC_CONFIG_MAC2IPP_PKT_CNT_EN); + val |= (XMAC_CONFIG_HASH_FILTER_EN); + nw64_mac(XMAC_CONFIG, val); + + nw64_mac(RXMAC_BT_CNT, 0); + nw64_mac(RXMAC_BC_FRM_CNT, 0); + nw64_mac(RXMAC_MC_FRM_CNT, 0); + nw64_mac(RXMAC_FRAG_CNT, 0); + nw64_mac(RXMAC_HIST_CNT1, 0); + nw64_mac(RXMAC_HIST_CNT2, 0); + nw64_mac(RXMAC_HIST_CNT3, 0); + nw64_mac(RXMAC_HIST_CNT4, 0); + nw64_mac(RXMAC_HIST_CNT5, 0); + nw64_mac(RXMAC_HIST_CNT6, 0); + nw64_mac(RXMAC_HIST_CNT7, 0); + nw64_mac(RXMAC_MPSZER_CNT, 0); + nw64_mac(RXMAC_CRC_ER_CNT, 0); + nw64_mac(RXMAC_CD_VIO_CNT, 0); + nw64_mac(LINK_FAULT_CNT, 0); +} + +static void niu_init_rx_bmac(struct niu *np) +{ + struct niu_parent *parent = np->parent; + struct niu_rdc_tables *tp = &parent->rdc_group_cfg[np->port]; + int first_rdc_table = tp->first_table_num; + unsigned long i; + u64 val; + + nw64_mac(BMAC_ADD_FILT0, 0); + nw64_mac(BMAC_ADD_FILT1, 0); + nw64_mac(BMAC_ADD_FILT2, 0); + nw64_mac(BMAC_ADD_FILT12_MASK, 0); + nw64_mac(BMAC_ADD_FILT00_MASK, 0); + for (i = 0; i < MAC_NUM_HASH; i++) + nw64_mac(BMAC_HASH_TBL(i), 0); + niu_set_primary_mac_rdc_table(np, first_rdc_table, 1); + niu_set_multicast_mac_rdc_table(np, first_rdc_table, 1); + nw64_mac(BRXMAC_STATUS_MASK, ~(u64)0); + + val = nr64_mac(BRXMAC_CONFIG); + val &= ~(BRXMAC_CONFIG_ENABLE | + BRXMAC_CONFIG_STRIP_PAD | + BRXMAC_CONFIG_STRIP_FCS | + BRXMAC_CONFIG_PROMISC | + BRXMAC_CONFIG_PROMISC_GRP | + BRXMAC_CONFIG_ADDR_FILT_EN | + BRXMAC_CONFIG_DISCARD_DIS); + val |= (BRXMAC_CONFIG_HASH_FILT_EN); + nw64_mac(BRXMAC_CONFIG, val); + + val = nr64_mac(BMAC_ADDR_CMPEN); + val |= BMAC_ADDR_CMPEN_EN0; + nw64_mac(BMAC_ADDR_CMPEN, val); +} + +static void niu_init_rx_mac(struct niu *np) +{ + niu_set_primary_mac(np, np->dev->dev_addr); + + if (np->flags & NIU_FLAGS_XMAC) + niu_init_rx_xmac(np); + else + niu_init_rx_bmac(np); +} + +static void niu_enable_tx_xmac(struct niu *np, int on) +{ + u64 val = nr64_mac(XMAC_CONFIG); + + if (on) + val |= XMAC_CONFIG_TX_ENABLE; + else + val &= ~XMAC_CONFIG_TX_ENABLE; + nw64_mac(XMAC_CONFIG, val); +} + +static void niu_enable_tx_bmac(struct niu *np, int on) +{ + u64 val = nr64_mac(BTXMAC_CONFIG); + + if (on) + val |= BTXMAC_CONFIG_ENABLE; + else + val &= ~BTXMAC_CONFIG_ENABLE; + nw64_mac(BTXMAC_CONFIG, val); +} + +static void niu_enable_tx_mac(struct niu *np, int on) +{ + if (np->flags & NIU_FLAGS_XMAC) + niu_enable_tx_xmac(np, on); + else + niu_enable_tx_bmac(np, on); +} + +static void niu_enable_rx_xmac(struct niu *np, int on) +{ + u64 val = nr64_mac(XMAC_CONFIG); + + val &= ~(XMAC_CONFIG_HASH_FILTER_EN | + XMAC_CONFIG_PROMISCUOUS); + + if (np->flags & NIU_FLAGS_MCAST) + val |= XMAC_CONFIG_HASH_FILTER_EN; + if (np->flags & NIU_FLAGS_PROMISC) + val |= XMAC_CONFIG_PROMISCUOUS; + + if (on) + val |= XMAC_CONFIG_RX_MAC_ENABLE; + else + val &= ~XMAC_CONFIG_RX_MAC_ENABLE; + nw64_mac(XMAC_CONFIG, val); +} + +static void niu_enable_rx_bmac(struct niu *np, int on) +{ + u64 val = nr64_mac(BRXMAC_CONFIG); + + val &= ~(BRXMAC_CONFIG_HASH_FILT_EN | + BRXMAC_CONFIG_PROMISC); + + if (np->flags & NIU_FLAGS_MCAST) + val |= BRXMAC_CONFIG_HASH_FILT_EN; + if (np->flags & NIU_FLAGS_PROMISC) + val |= BRXMAC_CONFIG_PROMISC; + + if (on) + val |= BRXMAC_CONFIG_ENABLE; + else + val &= ~BRXMAC_CONFIG_ENABLE; + nw64_mac(BRXMAC_CONFIG, val); +} + +static void niu_enable_rx_mac(struct niu *np, int on) +{ + if (np->flags & NIU_FLAGS_XMAC) + niu_enable_rx_xmac(np, on); + else + niu_enable_rx_bmac(np, on); +} + +static int niu_init_mac(struct niu *np) +{ + int err; + + niu_init_xif(np); + err = niu_init_pcs(np); + if (err) + return err; + + err = niu_reset_tx_mac(np); + if (err) + return err; + niu_init_tx_mac(np); + err = niu_reset_rx_mac(np); + if (err) + return err; + niu_init_rx_mac(np); + + /* This looks hookey but the RX MAC reset we just did will + * undo some of the state we setup in niu_init_tx_mac() so we + * have to call it again. In particular, the RX MAC reset will + * set the XMAC_MAX register back to it's default value. + */ + niu_init_tx_mac(np); + niu_enable_tx_mac(np, 1); + + niu_enable_rx_mac(np, 1); + + return 0; +} + +static void niu_stop_one_tx_channel(struct niu *np, struct tx_ring_info *rp) +{ + (void) niu_tx_channel_stop(np, rp->tx_channel); +} + +static void niu_stop_tx_channels(struct niu *np) +{ + int i; + + for (i = 0; i < np->num_tx_rings; i++) { + struct tx_ring_info *rp = &np->tx_rings[i]; + + niu_stop_one_tx_channel(np, rp); + } +} + +static void niu_reset_one_tx_channel(struct niu *np, struct tx_ring_info *rp) +{ + (void) niu_tx_channel_reset(np, rp->tx_channel); +} + +static void niu_reset_tx_channels(struct niu *np) +{ + int i; + + for (i = 0; i < np->num_tx_rings; i++) { + struct tx_ring_info *rp = &np->tx_rings[i]; + + niu_reset_one_tx_channel(np, rp); + } +} + +static void niu_stop_one_rx_channel(struct niu *np, struct rx_ring_info *rp) +{ + (void) niu_enable_rx_channel(np, rp->rx_channel, 0); +} + +static void niu_stop_rx_channels(struct niu *np) +{ + int i; + + for (i = 0; i < np->num_rx_rings; i++) { + struct rx_ring_info *rp = &np->rx_rings[i]; + + niu_stop_one_rx_channel(np, rp); + } +} + +static void niu_reset_one_rx_channel(struct niu *np, struct rx_ring_info *rp) +{ + int channel = rp->rx_channel; + + (void) niu_rx_channel_reset(np, channel); + nw64(RX_DMA_ENT_MSK(channel), RX_DMA_ENT_MSK_ALL); + nw64(RX_DMA_CTL_STAT(channel), 0); + (void) niu_enable_rx_channel(np, channel, 0); +} + +static void niu_reset_rx_channels(struct niu *np) +{ + int i; + + for (i = 0; i < np->num_rx_rings; i++) { + struct rx_ring_info *rp = &np->rx_rings[i]; + + niu_reset_one_rx_channel(np, rp); + } +} + +static void niu_disable_ipp(struct niu *np) +{ + u64 rd, wr, val; + int limit; + + rd = nr64_ipp(IPP_DFIFO_RD_PTR); + wr = nr64_ipp(IPP_DFIFO_WR_PTR); + limit = 100; + while (--limit >= 0 && (rd != wr)) { + rd = nr64_ipp(IPP_DFIFO_RD_PTR); + wr = nr64_ipp(IPP_DFIFO_WR_PTR); + } + if (limit < 0 && + (rd != 0 && wr != 1)) { + dev_err(np->device, PFX "%s: IPP would not quiesce, " + "rd_ptr[%llx] wr_ptr[%llx]\n", + np->dev->name, + (unsigned long long) nr64_ipp(IPP_DFIFO_RD_PTR), + (unsigned long long) nr64_ipp(IPP_DFIFO_WR_PTR)); + } + + val = nr64_ipp(IPP_CFIG); + val &= ~(IPP_CFIG_IPP_ENABLE | + IPP_CFIG_DFIFO_ECC_EN | + IPP_CFIG_DROP_BAD_CRC | + IPP_CFIG_CKSUM_EN); + nw64_ipp(IPP_CFIG, val); + + (void) niu_ipp_reset(np); +} + +static int niu_init_hw(struct niu *np) +{ + int i, err; + + niudbg(IFUP, "%s: Initialize TXC\n", np->dev->name); + niu_txc_enable_port(np, 1); + niu_txc_port_dma_enable(np, 1); + niu_txc_set_imask(np, 0); + + niudbg(IFUP, "%s: Initialize TX channels\n", np->dev->name); + for (i = 0; i < np->num_tx_rings; i++) { + struct tx_ring_info *rp = &np->tx_rings[i]; + + err = niu_init_one_tx_channel(np, rp); + if (err) + return err; + } + + niudbg(IFUP, "%s: Initialize RX channels\n", np->dev->name); + err = niu_init_rx_channels(np); + if (err) + goto out_uninit_tx_channels; + + niudbg(IFUP, "%s: Initialize classifier\n", np->dev->name); + err = niu_init_classifier_hw(np); + if (err) + goto out_uninit_rx_channels; + + niudbg(IFUP, "%s: Initialize ZCP\n", np->dev->name); + err = niu_init_zcp(np); + if (err) + goto out_uninit_rx_channels; + + niudbg(IFUP, "%s: Initialize IPP\n", np->dev->name); + err = niu_init_ipp(np); + if (err) + goto out_uninit_rx_channels; + + niudbg(IFUP, "%s: Initialize MAC\n", np->dev->name); + err = niu_init_mac(np); + if (err) + goto out_uninit_ipp; + + return 0; + +out_uninit_ipp: + niudbg(IFUP, "%s: Uninit IPP\n", np->dev->name); + niu_disable_ipp(np); + +out_uninit_rx_channels: + niudbg(IFUP, "%s: Uninit RX channels\n", np->dev->name); + niu_stop_rx_channels(np); + niu_reset_rx_channels(np); + +out_uninit_tx_channels: + niudbg(IFUP, "%s: Uninit TX channels\n", np->dev->name); + niu_stop_tx_channels(np); + niu_reset_tx_channels(np); + + return err; +} + +static void niu_stop_hw(struct niu *np) +{ + niudbg(IFDOWN, "%s: Disable interrupts\n", np->dev->name); + niu_enable_interrupts(np, 0); + + niudbg(IFDOWN, "%s: Disable RX MAC\n", np->dev->name); + niu_enable_rx_mac(np, 0); + + niudbg(IFDOWN, "%s: Disable IPP\n", np->dev->name); + niu_disable_ipp(np); + + niudbg(IFDOWN, "%s: Stop TX channels\n", np->dev->name); + niu_stop_tx_channels(np); + + niudbg(IFDOWN, "%s: Stop RX channels\n", np->dev->name); + niu_stop_rx_channels(np); + + niudbg(IFDOWN, "%s: Reset TX channels\n", np->dev->name); + niu_reset_tx_channels(np); + + niudbg(IFDOWN, "%s: Reset RX channels\n", np->dev->name); + niu_reset_rx_channels(np); +} + +static int niu_request_irq(struct niu *np) +{ + int i, j, err; + + err = 0; + for (i = 0; i < np->num_ldg; i++) { + struct niu_ldg *lp = &np->ldg[i]; + + err = request_irq(lp->irq, niu_interrupt, + IRQF_SHARED | IRQF_SAMPLE_RANDOM, + np->dev->name, lp); + if (err) + goto out_free_irqs; + + } + + return 0; + +out_free_irqs: + for (j = 0; j < i; j++) { + struct niu_ldg *lp = &np->ldg[j]; + + free_irq(lp->irq, lp); + } + return err; +} + +static void niu_free_irq(struct niu *np) +{ + int i; + + for (i = 0; i < np->num_ldg; i++) { + struct niu_ldg *lp = &np->ldg[i]; + + free_irq(lp->irq, lp); + } +} + +static void niu_enable_napi(struct niu *np) +{ + int i; + + for (i = 0; i < np->num_ldg; i++) + napi_enable(&np->ldg[i].napi); +} + +static void niu_disable_napi(struct niu *np) +{ + int i; + + for (i = 0; i < np->num_ldg; i++) + napi_disable(&np->ldg[i].napi); +} + +static int niu_open(struct net_device *dev) +{ + struct niu *np = netdev_priv(dev); + int err; + + netif_carrier_off(dev); + + err = niu_alloc_channels(np); + if (err) + goto out_err; + + err = niu_enable_interrupts(np, 0); + if (err) + goto out_free_channels; + + err = niu_request_irq(np); + if (err) + goto out_free_channels; + + niu_enable_napi(np); + + spin_lock_irq(&np->lock); + + err = niu_init_hw(np); + if (!err) { + init_timer(&np->timer); + np->timer.expires = jiffies + HZ; + np->timer.data = (unsigned long) np; + np->timer.function = niu_timer; + + err = niu_enable_interrupts(np, 1); + if (err) + niu_stop_hw(np); + } + + spin_unlock_irq(&np->lock); + + if (err) { + niu_disable_napi(np); + goto out_free_irq; + } + + netif_start_queue(dev); + + if (np->link_config.loopback_mode != LOOPBACK_DISABLED) + netif_carrier_on(dev); + + add_timer(&np->timer); + + return 0; + +out_free_irq: + niu_free_irq(np); + +out_free_channels: + niu_free_channels(np); + +out_err: + return err; +} + +static void niu_full_shutdown(struct niu *np, struct net_device *dev) +{ + cancel_work_sync(&np->reset_task); + + niu_disable_napi(np); + netif_stop_queue(dev); + + del_timer_sync(&np->timer); + + spin_lock_irq(&np->lock); + + niu_stop_hw(np); + + spin_unlock_irq(&np->lock); +} + +static int niu_close(struct net_device *dev) +{ + struct niu *np = netdev_priv(dev); + + niu_full_shutdown(np, dev); + + niu_free_irq(np); + + niu_free_channels(np); + + return 0; +} + +static void niu_sync_xmac_stats(struct niu *np) +{ + struct niu_xmac_stats *mp = &np->mac_stats.xmac; + + mp->tx_frames += nr64_mac(TXMAC_FRM_CNT); + mp->tx_bytes += nr64_mac(TXMAC_BYTE_CNT); + + mp->rx_link_faults += nr64_mac(LINK_FAULT_CNT); + mp->rx_align_errors += nr64_mac(RXMAC_ALIGN_ERR_CNT); + mp->rx_frags += nr64_mac(RXMAC_FRAG_CNT); + mp->rx_mcasts += nr64_mac(RXMAC_MC_FRM_CNT); + mp->rx_bcasts += nr64_mac(RXMAC_BC_FRM_CNT); + mp->rx_hist_cnt1 += nr64_mac(RXMAC_HIST_CNT1); + mp->rx_hist_cnt2 += nr64_mac(RXMAC_HIST_CNT2); + mp->rx_hist_cnt3 += nr64_mac(RXMAC_HIST_CNT3); + mp->rx_hist_cnt4 += nr64_mac(RXMAC_HIST_CNT4); + mp->rx_hist_cnt5 += nr64_mac(RXMAC_HIST_CNT5); + mp->rx_hist_cnt6 += nr64_mac(RXMAC_HIST_CNT6); + mp->rx_hist_cnt7 += nr64_mac(RXMAC_HIST_CNT7); + mp->rx_octets += nr64_mac(RXMAC_BT_CNT); + mp->rx_code_violations += nr64_mac(RXMAC_CD_VIO_CNT); + mp->rx_len_errors += nr64_mac(RXMAC_MPSZER_CNT); + mp->rx_crc_errors += nr64_mac(RXMAC_CRC_ER_CNT); +} + +static void niu_sync_bmac_stats(struct niu *np) +{ + struct niu_bmac_stats *mp = &np->mac_stats.bmac; + + mp->tx_bytes += nr64_mac(BTXMAC_BYTE_CNT); + mp->tx_frames += nr64_mac(BTXMAC_FRM_CNT); + + mp->rx_frames += nr64_mac(BRXMAC_FRAME_CNT); + mp->rx_align_errors += nr64_mac(BRXMAC_ALIGN_ERR_CNT); + mp->rx_crc_errors += nr64_mac(BRXMAC_ALIGN_ERR_CNT); + mp->rx_len_errors += nr64_mac(BRXMAC_CODE_VIOL_ERR_CNT); +} + +static void niu_sync_mac_stats(struct niu *np) +{ + if (np->flags & NIU_FLAGS_XMAC) + niu_sync_xmac_stats(np); + else + niu_sync_bmac_stats(np); +} + +static void niu_get_rx_stats(struct niu *np) +{ + unsigned long pkts, dropped, errors, bytes; + int i; + + pkts = dropped = errors = bytes = 0; + for (i = 0; i < np->num_rx_rings; i++) { + struct rx_ring_info *rp = &np->rx_rings[i]; + + pkts += rp->rx_packets; + bytes += rp->rx_bytes; + dropped += rp->rx_dropped; + errors += rp->rx_errors; + } + np->net_stats.rx_packets = pkts; + np->net_stats.rx_bytes = bytes; + np->net_stats.rx_dropped = dropped; + np->net_stats.rx_errors = errors; +} + +static void niu_get_tx_stats(struct niu *np) +{ + unsigned long pkts, errors, bytes; + int i; + + pkts = errors = bytes = 0; + for (i = 0; i < np->num_tx_rings; i++) { + struct tx_ring_info *rp = &np->tx_rings[i]; + + pkts += rp->tx_packets; + bytes += rp->tx_bytes; + errors += rp->tx_errors; + } + np->net_stats.tx_packets = pkts; + np->net_stats.tx_bytes = bytes; + np->net_stats.tx_errors = errors; +} + +static struct net_device_stats *niu_get_stats(struct net_device *dev) +{ + struct niu *np = netdev_priv(dev); + + niu_get_rx_stats(np); + niu_get_tx_stats(np); + + return &np->net_stats; +} + +static void niu_load_hash_xmac(struct niu *np, u16 *hash) +{ + int i; + + for (i = 0; i < 16; i++) + nw64_mac(XMAC_HASH_TBL(i), hash[i]); +} + +static void niu_load_hash_bmac(struct niu *np, u16 *hash) +{ + int i; + + for (i = 0; i < 16; i++) + nw64_mac(BMAC_HASH_TBL(i), hash[i]); +} + +static void niu_load_hash(struct niu *np, u16 *hash) +{ + if (np->flags & NIU_FLAGS_XMAC) + niu_load_hash_xmac(np, hash); + else + niu_load_hash_bmac(np, hash); +} + +static void niu_set_rx_mode(struct net_device *dev) +{ + struct niu *np = netdev_priv(dev); + int i, alt_cnt, err; + struct dev_addr_list *addr; + unsigned long flags; + u16 hash[16] = { 0, }; + + spin_lock_irqsave(&np->lock, flags); + niu_enable_rx_mac(np, 0); + + np->flags &= ~(NIU_FLAGS_MCAST | NIU_FLAGS_PROMISC); + if (dev->flags & IFF_PROMISC) + np->flags |= NIU_FLAGS_PROMISC; + if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 0)) + np->flags |= NIU_FLAGS_MCAST; + + alt_cnt = dev->uc_count; + if (alt_cnt > niu_num_alt_addr(np)) { + alt_cnt = 0; + np->flags |= NIU_FLAGS_PROMISC; + } + + if (alt_cnt) { + int index = 0; + + for (addr = dev->uc_list; addr; addr = addr->next) { + err = niu_set_alt_mac(np, index, + addr->da_addr); + if (err) + printk(KERN_WARNING PFX "%s: Error %d " + "adding alt mac %d\n", + dev->name, err, index); + err = niu_enable_alt_mac(np, index, 1); + if (err) + printk(KERN_WARNING PFX "%s: Error %d " + "enabling alt mac %d\n", + dev->name, err, index); + + index++; + } + } else { + for (i = 0; i < niu_num_alt_addr(np); i++) { + err = niu_enable_alt_mac(np, i, 0); + if (err) + printk(KERN_WARNING PFX "%s: Error %d " + "disabling alt mac %d\n", + dev->name, err, i); + } + } + if (dev->flags & IFF_ALLMULTI) { + for (i = 0; i < 16; i++) + hash[i] = 0xffff; + } else if (dev->mc_count > 0) { + for (addr = dev->mc_list; addr; addr = addr->next) { + u32 crc = ether_crc_le(ETH_ALEN, addr->da_addr); + + crc >>= 24; + hash[crc >> 4] |= (1 << (15 - (crc & 0xf))); + } + } + + if (np->flags & NIU_FLAGS_MCAST) + niu_load_hash(np, hash); + + niu_enable_rx_mac(np, 1); + spin_unlock_irqrestore(&np->lock, flags); +} + +static int niu_set_mac_addr(struct net_device *dev, void *p) +{ + struct niu *np = netdev_priv(dev); + struct sockaddr *addr = p; + unsigned long flags; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EINVAL; + + memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); + + if (!netif_running(dev)) + return 0; + + spin_lock_irqsave(&np->lock, flags); + niu_enable_rx_mac(np, 0); + niu_set_primary_mac(np, dev->dev_addr); + niu_enable_rx_mac(np, 1); + spin_unlock_irqrestore(&np->lock, flags); + + return 0; +} + +static int niu_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + return -EOPNOTSUPP; +} + +static void niu_netif_stop(struct niu *np) +{ + np->dev->trans_start = jiffies; /* prevent tx timeout */ + + niu_disable_napi(np); + + netif_tx_disable(np->dev); +} + +static void niu_netif_start(struct niu *np) +{ + /* NOTE: unconditional netif_wake_queue is only appropriate + * so long as all callers are assured to have free tx slots + * (such as after niu_init_hw). + */ + netif_wake_queue(np->dev); + + niu_enable_napi(np); + + niu_enable_interrupts(np, 1); +} + +static void niu_reset_task(struct work_struct *work) +{ + struct niu *np = container_of(work, struct niu, reset_task); + unsigned long flags; + int err; + + spin_lock_irqsave(&np->lock, flags); + if (!netif_running(np->dev)) { + spin_unlock_irqrestore(&np->lock, flags); + return; + } + + spin_unlock_irqrestore(&np->lock, flags); + + del_timer_sync(&np->timer); + + niu_netif_stop(np); + + spin_lock_irqsave(&np->lock, flags); + + niu_stop_hw(np); + + err = niu_init_hw(np); + if (!err) { + np->timer.expires = jiffies + HZ; + add_timer(&np->timer); + niu_netif_start(np); + } + + spin_unlock_irqrestore(&np->lock, flags); +} + +static void niu_tx_timeout(struct net_device *dev) +{ + struct niu *np = netdev_priv(dev); + + dev_err(np->device, PFX "%s: Transmit timed out, resetting\n", + dev->name); + + schedule_work(&np->reset_task); +} + +static void niu_set_txd(struct tx_ring_info *rp, int index, + u64 mapping, u64 len, u64 mark, + u64 n_frags) +{ + __le64 *desc = &rp->descr[index]; + + *desc = cpu_to_le64(mark | + (n_frags << TX_DESC_NUM_PTR_SHIFT) | + (len << TX_DESC_TR_LEN_SHIFT) | + (mapping & TX_DESC_SAD)); +} + +static u64 niu_compute_tx_flags(struct sk_buff *skb, struct ethhdr *ehdr, + u64 pad_bytes, u64 len) +{ + u16 eth_proto, eth_proto_inner; + u64 csum_bits, l3off, ihl, ret; + u8 ip_proto; + int ipv6; + + eth_proto = be16_to_cpu(ehdr->h_proto); + eth_proto_inner = eth_proto; + if (eth_proto == ETH_P_8021Q) { + struct vlan_ethhdr *vp = (struct vlan_ethhdr *) ehdr; + __be16 val = vp->h_vlan_encapsulated_proto; + + eth_proto_inner = be16_to_cpu(val); + } + + ipv6 = ihl = 0; + switch (skb->protocol) { + case __constant_htons(ETH_P_IP): + ip_proto = ip_hdr(skb)->protocol; + ihl = ip_hdr(skb)->ihl; + break; + case __constant_htons(ETH_P_IPV6): + ip_proto = ipv6_hdr(skb)->nexthdr; + ihl = (40 >> 2); + ipv6 = 1; + break; + default: + ip_proto = ihl = 0; + break; + } + + csum_bits = TXHDR_CSUM_NONE; + if (skb->ip_summed == CHECKSUM_PARTIAL) { + u64 start, stuff; + + csum_bits = (ip_proto == IPPROTO_TCP ? + TXHDR_CSUM_TCP : + (ip_proto == IPPROTO_UDP ? + TXHDR_CSUM_UDP : TXHDR_CSUM_SCTP)); + + start = skb_transport_offset(skb) - + (pad_bytes + sizeof(struct tx_pkt_hdr)); + stuff = start + skb->csum_offset; + + csum_bits |= (start / 2) << TXHDR_L4START_SHIFT; + csum_bits |= (stuff / 2) << TXHDR_L4STUFF_SHIFT; + } + + l3off = skb_network_offset(skb) - + (pad_bytes + sizeof(struct tx_pkt_hdr)); + + ret = (((pad_bytes / 2) << TXHDR_PAD_SHIFT) | + (len << TXHDR_LEN_SHIFT) | + ((l3off / 2) << TXHDR_L3START_SHIFT) | + (ihl << TXHDR_IHL_SHIFT) | + ((eth_proto_inner < 1536) ? TXHDR_LLC : 0) | + ((eth_proto == ETH_P_8021Q) ? TXHDR_VLAN : 0) | + (ipv6 ? TXHDR_IP_VER : 0) | + csum_bits); + + return ret; +} + +static struct tx_ring_info *tx_ring_select(struct niu *np, struct sk_buff *skb) +{ + return &np->tx_rings[0]; +} + +static int niu_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct niu *np = netdev_priv(dev); + unsigned long align, headroom; + struct tx_ring_info *rp; + struct tx_pkt_hdr *tp; + unsigned int len, nfg; + struct ethhdr *ehdr; + int prod, i, tlen; + u64 mapping, mrk; + + rp = tx_ring_select(np, skb); + + if (niu_tx_avail(rp) <= (skb_shinfo(skb)->nr_frags + 1)) { + netif_stop_queue(dev); + dev_err(np->device, PFX "%s: BUG! Tx ring full when " + "queue awake!\n", dev->name); + rp->tx_errors++; + return NETDEV_TX_BUSY; + } + + if (skb->len < ETH_ZLEN) { + unsigned int pad_bytes = ETH_ZLEN - skb->len; + + if (skb_pad(skb, pad_bytes)) + goto out; + skb_put(skb, pad_bytes); + } + + len = sizeof(struct tx_pkt_hdr) + 15; + if (skb_headroom(skb) < len) { + struct sk_buff *skb_new; + + skb_new = skb_realloc_headroom(skb, len); + if (!skb_new) { + rp->tx_errors++; + goto out_drop; + } + kfree_skb(skb); + skb = skb_new; + } + + align = ((unsigned long) skb->data & (16 - 1)); + headroom = align + sizeof(struct tx_pkt_hdr); + + ehdr = (struct ethhdr *) skb->data; + tp = (struct tx_pkt_hdr *) skb_push(skb, headroom); + + len = skb->len - sizeof(struct tx_pkt_hdr); + tp->flags = cpu_to_le64(niu_compute_tx_flags(skb, ehdr, align, len)); + tp->resv = 0; + + len = skb_headlen(skb); + mapping = np->ops->map_single(np->device, skb->data, + len, DMA_TO_DEVICE); + + prod = rp->prod; + + rp->tx_buffs[prod].skb = skb; + rp->tx_buffs[prod].mapping = mapping; + + mrk = TX_DESC_SOP; + if (++rp->mark_counter == rp->mark_freq) { + rp->mark_counter = 0; + mrk |= TX_DESC_MARK; + rp->mark_pending++; + } + + tlen = len; + nfg = skb_shinfo(skb)->nr_frags; + while (tlen > 0) { + tlen -= MAX_TX_DESC_LEN; + nfg++; + } + + while (len > 0) { + unsigned int this_len = len; + + if (this_len > MAX_TX_DESC_LEN) + this_len = MAX_TX_DESC_LEN; + + niu_set_txd(rp, prod, mapping, this_len, mrk, nfg); + mrk = nfg = 0; + + prod = NEXT_TX(rp, prod); + mapping += this_len; + len -= this_len; + } + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + + len = frag->size; + mapping = np->ops->map_page(np->device, frag->page, + frag->page_offset, len, + DMA_TO_DEVICE); + + rp->tx_buffs[prod].skb = NULL; + rp->tx_buffs[prod].mapping = mapping; + + niu_set_txd(rp, prod, mapping, len, 0, 0); + + prod = NEXT_TX(rp, prod); + } + + if (prod < rp->prod) + rp->wrap_bit ^= TX_RING_KICK_WRAP; + rp->prod = prod; + + nw64(TX_RING_KICK(rp->tx_channel), rp->wrap_bit | (prod << 3)); + + if (unlikely(niu_tx_avail(rp) <= (MAX_SKB_FRAGS + 1))) { + netif_stop_queue(dev); + if (niu_tx_avail(rp) > NIU_TX_WAKEUP_THRESH(rp)) + netif_wake_queue(dev); + } + + dev->trans_start = jiffies; + +out: + return NETDEV_TX_OK; + +out_drop: + rp->tx_errors++; + kfree_skb(skb); + goto out; +} + +static int niu_change_mtu(struct net_device *dev, int new_mtu) +{ + struct niu *np = netdev_priv(dev); + int err, orig_jumbo, new_jumbo; + + if (new_mtu < 68 || new_mtu > NIU_MAX_MTU) + return -EINVAL; + + orig_jumbo = (dev->mtu > ETH_DATA_LEN); + new_jumbo = (new_mtu > ETH_DATA_LEN); + + dev->mtu = new_mtu; + + if (!netif_running(dev) || + (orig_jumbo == new_jumbo)) + return 0; + + niu_full_shutdown(np, dev); + + niu_free_channels(np); + + niu_enable_napi(np); + + err = niu_alloc_channels(np); + if (err) + return err; + + spin_lock_irq(&np->lock); + + err = niu_init_hw(np); + if (!err) { + init_timer(&np->timer); + np->timer.expires = jiffies + HZ; + np->timer.data = (unsigned long) np; + np->timer.function = niu_timer; + + err = niu_enable_interrupts(np, 1); + if (err) + niu_stop_hw(np); + } + + spin_unlock_irq(&np->lock); + + if (!err) { + netif_start_queue(dev); + if (np->link_config.loopback_mode != LOOPBACK_DISABLED) + netif_carrier_on(dev); + + add_timer(&np->timer); + } + + return err; +} + +static void niu_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + struct niu *np = netdev_priv(dev); + struct niu_vpd *vpd = &np->vpd; + + strcpy(info->driver, DRV_MODULE_NAME); + strcpy(info->version, DRV_MODULE_VERSION); + sprintf(info->fw_version, "%d.%d", + vpd->fcode_major, vpd->fcode_minor); + if (np->parent->plat_type != PLAT_TYPE_NIU) + strcpy(info->bus_info, pci_name(np->pdev)); +} + +static int niu_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct niu *np = netdev_priv(dev); + struct niu_link_config *lp; + + lp = &np->link_config; + + memset(cmd, 0, sizeof(*cmd)); + cmd->phy_address = np->phy_addr; + cmd->supported = lp->supported; + cmd->advertising = lp->advertising; + cmd->autoneg = lp->autoneg; + cmd->speed = lp->active_speed; + cmd->duplex = lp->active_duplex; + + return 0; +} + +static int niu_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + return -EINVAL; +} + +static u32 niu_get_msglevel(struct net_device *dev) +{ + struct niu *np = netdev_priv(dev); + return np->msg_enable; +} + +static void niu_set_msglevel(struct net_device *dev, u32 value) +{ + struct niu *np = netdev_priv(dev); + np->msg_enable = value; +} + +static int niu_get_eeprom_len(struct net_device *dev) +{ + struct niu *np = netdev_priv(dev); + + return np->eeprom_len; +} + +static int niu_get_eeprom(struct net_device *dev, + struct ethtool_eeprom *eeprom, u8 *data) +{ + struct niu *np = netdev_priv(dev); + u32 offset, len, val; + + offset = eeprom->offset; + len = eeprom->len; + + if (offset + len < offset) + return -EINVAL; + if (offset >= np->eeprom_len) + return -EINVAL; + if (offset + len > np->eeprom_len) + len = eeprom->len = np->eeprom_len - offset; + + if (offset & 3) { + u32 b_offset, b_count; + + b_offset = offset & 3; + b_count = 4 - b_offset; + if (b_count > len) + b_count = len; + + val = nr64(ESPC_NCR((offset - b_offset) / 4)); + memcpy(data, ((char *)&val) + b_offset, b_count); + data += b_count; + len -= b_count; + offset += b_count; + } + while (len >= 4) { + val = nr64(ESPC_NCR(offset / 4)); + memcpy(data, &val, 4); + data += 4; + len -= 4; + offset += 4; + } + if (len) { + val = nr64(ESPC_NCR(offset / 4)); + memcpy(data, &val, len); + } + return 0; +} + +static const struct { + const char string[ETH_GSTRING_LEN]; +} niu_xmac_stat_keys[] = { + { "tx_frames" }, + { "tx_bytes" }, + { "tx_fifo_errors" }, + { "tx_overflow_errors" }, + { "tx_max_pkt_size_errors" }, + { "tx_underflow_errors" }, + { "rx_local_faults" }, + { "rx_remote_faults" }, + { "rx_link_faults" }, + { "rx_align_errors" }, + { "rx_frags" }, + { "rx_mcasts" }, + { "rx_bcasts" }, + { "rx_hist_cnt1" }, + { "rx_hist_cnt2" }, + { "rx_hist_cnt3" }, + { "rx_hist_cnt4" }, + { "rx_hist_cnt5" }, + { "rx_hist_cnt6" }, + { "rx_hist_cnt7" }, + { "rx_octets" }, + { "rx_code_violations" }, + { "rx_len_errors" }, + { "rx_crc_errors" }, + { "rx_underflows" }, + { "rx_overflows" }, + { "pause_off_state" }, + { "pause_on_state" }, + { "pause_received" }, +}; + +#define NUM_XMAC_STAT_KEYS ARRAY_SIZE(niu_xmac_stat_keys) + +static const struct { + const char string[ETH_GSTRING_LEN]; +} niu_bmac_stat_keys[] = { + { "tx_underflow_errors" }, + { "tx_max_pkt_size_errors" }, + { "tx_bytes" }, + { "tx_frames" }, + { "rx_overflows" }, + { "rx_frames" }, + { "rx_align_errors" }, + { "rx_crc_errors" }, + { "rx_len_errors" }, + { "pause_off_state" }, + { "pause_on_state" }, + { "pause_received" }, +}; + +#define NUM_BMAC_STAT_KEYS ARRAY_SIZE(niu_bmac_stat_keys) + +static const struct { + const char string[ETH_GSTRING_LEN]; +} niu_rxchan_stat_keys[] = { + { "rx_channel" }, + { "rx_packets" }, + { "rx_bytes" }, + { "rx_dropped" }, + { "rx_errors" }, +}; + +#define NUM_RXCHAN_STAT_KEYS ARRAY_SIZE(niu_rxchan_stat_keys) + +static const struct { + const char string[ETH_GSTRING_LEN]; +} niu_txchan_stat_keys[] = { + { "tx_channel" }, + { "tx_packets" }, + { "tx_bytes" }, + { "tx_errors" }, +}; + +#define NUM_TXCHAN_STAT_KEYS ARRAY_SIZE(niu_txchan_stat_keys) + +static void niu_get_strings(struct net_device *dev, u32 stringset, u8 *data) +{ + struct niu *np = netdev_priv(dev); + int i; + + if (stringset != ETH_SS_STATS) + return; + + if (np->flags & NIU_FLAGS_XMAC) { + memcpy(data, niu_xmac_stat_keys, + sizeof(niu_xmac_stat_keys)); + data += sizeof(niu_xmac_stat_keys); + } else { + memcpy(data, niu_bmac_stat_keys, + sizeof(niu_bmac_stat_keys)); + data += sizeof(niu_bmac_stat_keys); + } + for (i = 0; i < np->num_rx_rings; i++) { + memcpy(data, niu_rxchan_stat_keys, + sizeof(niu_rxchan_stat_keys)); + data += sizeof(niu_rxchan_stat_keys); + } + for (i = 0; i < np->num_tx_rings; i++) { + memcpy(data, niu_txchan_stat_keys, + sizeof(niu_txchan_stat_keys)); + data += sizeof(niu_txchan_stat_keys); + } +} + +static int niu_get_stats_count(struct net_device *dev) +{ + struct niu *np = netdev_priv(dev); + + return ((np->flags & NIU_FLAGS_XMAC ? + NUM_XMAC_STAT_KEYS : + NUM_BMAC_STAT_KEYS) + + (np->num_rx_rings * NUM_RXCHAN_STAT_KEYS) + + (np->num_tx_rings * NUM_TXCHAN_STAT_KEYS)); +} + +static void niu_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, u64 *data) +{ + struct niu *np = netdev_priv(dev); + int i; + + niu_sync_mac_stats(np); + if (np->flags & NIU_FLAGS_XMAC) { + memcpy(data, &np->mac_stats.xmac, + sizeof(struct niu_xmac_stats)); + data += (sizeof(struct niu_xmac_stats) / sizeof(u64)); + } else { + memcpy(data, &np->mac_stats.bmac, + sizeof(struct niu_bmac_stats)); + data += (sizeof(struct niu_bmac_stats) / sizeof(u64)); + } + for (i = 0; i < np->num_rx_rings; i++) { + struct rx_ring_info *rp = &np->rx_rings[i]; + + data[0] = rp->rx_channel; + data[1] = rp->rx_packets; + data[2] = rp->rx_bytes; + data[3] = rp->rx_dropped; + data[4] = rp->rx_errors; + data += 5; + } + for (i = 0; i < np->num_tx_rings; i++) { + struct tx_ring_info *rp = &np->tx_rings[i]; + + data[0] = rp->tx_channel; + data[1] = rp->tx_packets; + data[2] = rp->tx_bytes; + data[3] = rp->tx_errors; + data += 4; + } +} + +static u64 niu_led_state_save(struct niu *np) +{ + if (np->flags & NIU_FLAGS_XMAC) + return nr64_mac(XMAC_CONFIG); + else + return nr64_mac(BMAC_XIF_CONFIG); +} + +static void niu_led_state_restore(struct niu *np, u64 val) +{ + if (np->flags & NIU_FLAGS_XMAC) + nw64_mac(XMAC_CONFIG, val); + else + nw64_mac(BMAC_XIF_CONFIG, val); +} + +static void niu_force_led(struct niu *np, int on) +{ + u64 val, reg, bit; + + if (np->flags & NIU_FLAGS_XMAC) { + reg = XMAC_CONFIG; + bit = XMAC_CONFIG_FORCE_LED_ON; + } else { + reg = BMAC_XIF_CONFIG; + bit = BMAC_XIF_CONFIG_LINK_LED; + } + + val = nr64_mac(reg); + if (on) + val |= bit; + else + val &= ~bit; + nw64_mac(reg, val); +} + +static int niu_phys_id(struct net_device *dev, u32 data) +{ + struct niu *np = netdev_priv(dev); + u64 orig_led_state; + int i; + + if (!netif_running(dev)) + return -EAGAIN; + + if (data == 0) + data = 2; + + orig_led_state = niu_led_state_save(np); + for (i = 0; i < (data * 2); i++) { + int on = ((i % 2) == 0); + + niu_force_led(np, on); + + if (msleep_interruptible(500)) + break; + } + niu_led_state_restore(np, orig_led_state); + + return 0; +} + +static const struct ethtool_ops niu_ethtool_ops = { + .get_drvinfo = niu_get_drvinfo, + .get_link = ethtool_op_get_link, + .get_msglevel = niu_get_msglevel, + .set_msglevel = niu_set_msglevel, + .get_eeprom_len = niu_get_eeprom_len, + .get_eeprom = niu_get_eeprom, + .get_settings = niu_get_settings, + .set_settings = niu_set_settings, + .get_strings = niu_get_strings, + .get_stats_count = niu_get_stats_count, + .get_ethtool_stats = niu_get_ethtool_stats, + .phys_id = niu_phys_id, +}; + +static int niu_ldg_assign_ldn(struct niu *np, struct niu_parent *parent, + int ldg, int ldn) +{ + if (ldg < NIU_LDG_MIN || ldg > NIU_LDG_MAX) + return -EINVAL; + if (ldn < 0 || ldn > LDN_MAX) + return -EINVAL; + + parent->ldg_map[ldn] = ldg; + + if (np->parent->plat_type == PLAT_TYPE_NIU) { + /* On N2 NIU, the ldn-->ldg assignments are setup and fixed by + * the firmware, and we're not supposed to change them. + * Validate the mapping, because if it's wrong we probably + * won't get any interrupts and that's painful to debug. + */ + if (nr64(LDG_NUM(ldn)) != ldg) { + dev_err(np->device, PFX "Port %u, mis-matched " + "LDG assignment " + "for ldn %d, should be %d is %llu\n", + np->port, ldn, ldg, + (unsigned long long) nr64(LDG_NUM(ldn))); + return -EINVAL; + } + } else + nw64(LDG_NUM(ldn), ldg); + + return 0; +} + +static int niu_set_ldg_timer_res(struct niu *np, int res) +{ + if (res < 0 || res > LDG_TIMER_RES_VAL) + return -EINVAL; + + + nw64(LDG_TIMER_RES, res); + + return 0; +} + +static int niu_set_ldg_sid(struct niu *np, int ldg, int func, int vector) +{ + if ((ldg < NIU_LDG_MIN || ldg > NIU_LDG_MAX) || + (func < 0 || func > 3) || + (vector < 0 || vector > 0x1f)) + return -EINVAL; + + nw64(SID(ldg), (func << SID_FUNC_SHIFT) | vector); + + return 0; +} + +static int __devinit niu_pci_eeprom_read(struct niu *np, u32 addr) +{ + u64 frame, frame_base = (ESPC_PIO_STAT_READ_START | + (addr << ESPC_PIO_STAT_ADDR_SHIFT)); + int limit; + + if (addr > (ESPC_PIO_STAT_ADDR >> ESPC_PIO_STAT_ADDR_SHIFT)) + return -EINVAL; + + frame = frame_base; + nw64(ESPC_PIO_STAT, frame); + limit = 64; + do { + udelay(5); + frame = nr64(ESPC_PIO_STAT); + if (frame & ESPC_PIO_STAT_READ_END) + break; + } while (limit--); + if (!(frame & ESPC_PIO_STAT_READ_END)) { + dev_err(np->device, PFX "EEPROM read timeout frame[%llx]\n", + (unsigned long long) frame); + return -ENODEV; + } + + frame = frame_base; + nw64(ESPC_PIO_STAT, frame); + limit = 64; + do { + udelay(5); + frame = nr64(ESPC_PIO_STAT); + if (frame & ESPC_PIO_STAT_READ_END) + break; + } while (limit--); + if (!(frame & ESPC_PIO_STAT_READ_END)) { + dev_err(np->device, PFX "EEPROM read timeout frame[%llx]\n", + (unsigned long long) frame); + return -ENODEV; + } + + frame = nr64(ESPC_PIO_STAT); + return (frame & ESPC_PIO_STAT_DATA) >> ESPC_PIO_STAT_DATA_SHIFT; +} + +static int __devinit niu_pci_eeprom_read16(struct niu *np, u32 off) +{ + int err = niu_pci_eeprom_read(np, off); + u16 val; + + if (err < 0) + return err; + val = (err << 8); + err = niu_pci_eeprom_read(np, off + 1); + if (err < 0) + return err; + val |= (err & 0xff); + + return val; +} + +static int __devinit niu_pci_eeprom_read16_swp(struct niu *np, u32 off) +{ + int err = niu_pci_eeprom_read(np, off); + u16 val; + + if (err < 0) + return err; + + val = (err & 0xff); + err = niu_pci_eeprom_read(np, off + 1); + if (err < 0) + return err; + + val |= (err & 0xff) << 8; + + return val; +} + +static int __devinit niu_pci_vpd_get_propname(struct niu *np, + u32 off, + char *namebuf, + int namebuf_len) +{ + int i; + + for (i = 0; i < namebuf_len; i++) { + int err = niu_pci_eeprom_read(np, off + i); + if (err < 0) + return err; + *namebuf++ = err; + if (!err) + break; + } + if (i >= namebuf_len) + return -EINVAL; + + return i + 1; +} + +static void __devinit niu_vpd_parse_version(struct niu *np) +{ + struct niu_vpd *vpd = &np->vpd; + int len = strlen(vpd->version) + 1; + const char *s = vpd->version; + int i; + + for (i = 0; i < len - 5; i++) { + if (!strncmp(s + i, "FCode ", 5)) + break; + } + if (i >= len - 5) + return; + + s += i + 5; + sscanf(s, "%d.%d", &vpd->fcode_major, &vpd->fcode_minor); + + niudbg(PROBE, "VPD_SCAN: FCODE major(%d) minor(%d)\n", + vpd->fcode_major, vpd->fcode_minor); + if (vpd->fcode_major > NIU_VPD_MIN_MAJOR || + (vpd->fcode_major == NIU_VPD_MIN_MAJOR && + vpd->fcode_minor >= NIU_VPD_MIN_MINOR)) + np->flags |= NIU_FLAGS_VPD_VALID; +} + +/* ESPC_PIO_EN_ENABLE must be set */ +static int __devinit niu_pci_vpd_scan_props(struct niu *np, + u32 start, u32 end) +{ + unsigned int found_mask = 0; +#define FOUND_MASK_MODEL 0x00000001 +#define FOUND_MASK_BMODEL 0x00000002 +#define FOUND_MASK_VERS 0x00000004 +#define FOUND_MASK_MAC 0x00000008 +#define FOUND_MASK_NMAC 0x00000010 +#define FOUND_MASK_PHY 0x00000020 +#define FOUND_MASK_ALL 0x0000003f + + niudbg(PROBE, "VPD_SCAN: start[%x] end[%x]\n", + start, end); + while (start < end) { + int len, err, instance, type, prop_len; + char namebuf[64]; + u8 *prop_buf; + int max_len; + + if (found_mask == FOUND_MASK_ALL) { + niu_vpd_parse_version(np); + return 1; + } + + err = niu_pci_eeprom_read(np, start + 2); + if (err < 0) + return err; + len = err; + start += 3; + + instance = niu_pci_eeprom_read(np, start); + type = niu_pci_eeprom_read(np, start + 3); + prop_len = niu_pci_eeprom_read(np, start + 4); + err = niu_pci_vpd_get_propname(np, start + 5, namebuf, 64); + if (err < 0) + return err; + + prop_buf = NULL; + max_len = 0; + if (!strcmp(namebuf, "model")) { + prop_buf = np->vpd.model; + max_len = NIU_VPD_MODEL_MAX; + found_mask |= FOUND_MASK_MODEL; + } else if (!strcmp(namebuf, "board-model")) { + prop_buf = np->vpd.board_model; + max_len = NIU_VPD_BD_MODEL_MAX; + found_mask |= FOUND_MASK_BMODEL; + } else if (!strcmp(namebuf, "version")) { + prop_buf = np->vpd.version; + max_len = NIU_VPD_VERSION_MAX; + found_mask |= FOUND_MASK_VERS; + } else if (!strcmp(namebuf, "local-mac-address")) { + prop_buf = np->vpd.local_mac; + max_len = ETH_ALEN; + found_mask |= FOUND_MASK_MAC; + } else if (!strcmp(namebuf, "num-mac-addresses")) { + prop_buf = &np->vpd.mac_num; + max_len = 1; + found_mask |= FOUND_MASK_NMAC; + } else if (!strcmp(namebuf, "phy-type")) { + prop_buf = np->vpd.phy_type; + max_len = NIU_VPD_PHY_TYPE_MAX; + found_mask |= FOUND_MASK_PHY; + } + + if (max_len && prop_len > max_len) { + dev_err(np->device, PFX "Property '%s' length (%d) is " + "too long.\n", namebuf, prop_len); + return -EINVAL; + } + + if (prop_buf) { + u32 off = start + 5 + err; + int i; + + niudbg(PROBE, "VPD_SCAN: Reading in property [%s] " + "len[%d]\n", namebuf, prop_len); + for (i = 0; i < prop_len; i++) + *prop_buf++ = niu_pci_eeprom_read(np, off + i); + } + + start += len; + } + + return 0; +} + +/* ESPC_PIO_EN_ENABLE must be set */ +static void __devinit niu_pci_vpd_fetch(struct niu *np, u32 start) +{ + u32 offset; + int err; + + err = niu_pci_eeprom_read16_swp(np, start + 1); + if (err < 0) + return; + + offset = err + 3; + + while (start + offset < ESPC_EEPROM_SIZE) { + u32 here = start + offset; + u32 end; + + err = niu_pci_eeprom_read(np, here); + if (err != 0x90) + return; + + err = niu_pci_eeprom_read16_swp(np, here + 1); + if (err < 0) + return; + + here = start + offset + 3; + end = start + offset + err; + + offset += err; + + err = niu_pci_vpd_scan_props(np, here, end); + if (err < 0 || err == 1) + return; + } +} + +/* ESPC_PIO_EN_ENABLE must be set */ +static u32 __devinit niu_pci_vpd_offset(struct niu *np) +{ + u32 start = 0, end = ESPC_EEPROM_SIZE, ret; + int err; + + while (start < end) { + ret = start; + + /* ROM header signature? */ + err = niu_pci_eeprom_read16(np, start + 0); + if (err != 0x55aa) + return 0; + + /* Apply offset to PCI data structure. */ + err = niu_pci_eeprom_read16(np, start + 23); + if (err < 0) + return 0; + start += err; + + /* Check for "PCIR" signature. */ + err = niu_pci_eeprom_read16(np, start + 0); + if (err != 0x5043) + return 0; + err = niu_pci_eeprom_read16(np, start + 2); + if (err != 0x4952) + return 0; + + /* Check for OBP image type. */ + err = niu_pci_eeprom_read(np, start + 20); + if (err < 0) + return 0; + if (err != 0x01) { + err = niu_pci_eeprom_read(np, ret + 2); + if (err < 0) + return 0; + + start = ret + (err * 512); + continue; + } + + err = niu_pci_eeprom_read16_swp(np, start + 8); + if (err < 0) + return err; + ret += err; + + err = niu_pci_eeprom_read(np, ret + 0); + if (err != 0x82) + return 0; + + return ret; + } + + return 0; +} + +static int __devinit niu_phy_type_prop_decode(struct niu *np, + const char *phy_prop) +{ + if (!strcmp(phy_prop, "mif")) { + /* 1G copper, MII */ + np->flags &= ~(NIU_FLAGS_FIBER | + NIU_FLAGS_10G); + np->mac_xcvr = MAC_XCVR_MII; + } else if (!strcmp(phy_prop, "xgf")) { + /* 10G fiber, XPCS */ + np->flags |= (NIU_FLAGS_10G | + NIU_FLAGS_FIBER); + np->mac_xcvr = MAC_XCVR_XPCS; + } else if (!strcmp(phy_prop, "pcs")) { + /* 1G fiber, PCS */ + np->flags &= ~NIU_FLAGS_10G; + np->flags |= NIU_FLAGS_FIBER; + np->mac_xcvr = MAC_XCVR_PCS; + } else if (!strcmp(phy_prop, "xgc")) { + /* 10G copper, XPCS */ + np->flags |= NIU_FLAGS_10G; + np->flags &= ~NIU_FLAGS_FIBER; + np->mac_xcvr = MAC_XCVR_XPCS; + } else { + return -EINVAL; + } + return 0; +} + +static void __devinit niu_pci_vpd_validate(struct niu *np) +{ + struct net_device *dev = np->dev; + struct niu_vpd *vpd = &np->vpd; + u8 val8; + + if (!is_valid_ether_addr(&vpd->local_mac[0])) { + dev_err(np->device, PFX "VPD MAC invalid, " + "falling back to SPROM.\n"); + + np->flags &= ~NIU_FLAGS_VPD_VALID; + return; + } + + if (niu_phy_type_prop_decode(np, np->vpd.phy_type)) { + dev_err(np->device, PFX "Illegal phy string [%s].\n", + np->vpd.phy_type); + dev_err(np->device, PFX "Falling back to SPROM.\n"); + np->flags &= ~NIU_FLAGS_VPD_VALID; + return; + } + + memcpy(dev->perm_addr, vpd->local_mac, ETH_ALEN); + + val8 = dev->perm_addr[5]; + dev->perm_addr[5] += np->port; + if (dev->perm_addr[5] < val8) + dev->perm_addr[4]++; + + memcpy(dev->dev_addr, dev->perm_addr, dev->addr_len); +} + +static int __devinit niu_pci_probe_sprom(struct niu *np) +{ + struct net_device *dev = np->dev; + int len, i; + u64 val, sum; + u8 val8; + + val = (nr64(ESPC_VER_IMGSZ) & ESPC_VER_IMGSZ_IMGSZ); + val >>= ESPC_VER_IMGSZ_IMGSZ_SHIFT; + len = val / 4; + + np->eeprom_len = len; + + niudbg(PROBE, "SPROM: Image size %llu\n", (unsigned long long) val); + + sum = 0; + for (i = 0; i < len; i++) { + val = nr64(ESPC_NCR(i)); + sum += (val >> 0) & 0xff; + sum += (val >> 8) & 0xff; + sum += (val >> 16) & 0xff; + sum += (val >> 24) & 0xff; + } + niudbg(PROBE, "SPROM: Checksum %x\n", (int)(sum & 0xff)); + if ((sum & 0xff) != 0xab) { + dev_err(np->device, PFX "Bad SPROM checksum " + "(%x, should be 0xab)\n", (int) (sum & 0xff)); + return -EINVAL; + } + + val = nr64(ESPC_PHY_TYPE); + switch (np->port) { + case 0: + val = (val & ESPC_PHY_TYPE_PORT0) >> + ESPC_PHY_TYPE_PORT0_SHIFT; + break; + case 1: + val = (val & ESPC_PHY_TYPE_PORT1) >> + ESPC_PHY_TYPE_PORT1_SHIFT; + break; + case 2: + val = (val & ESPC_PHY_TYPE_PORT2) >> + ESPC_PHY_TYPE_PORT2_SHIFT; + break; + case 3: + val = (val & ESPC_PHY_TYPE_PORT3) >> + ESPC_PHY_TYPE_PORT3_SHIFT; + break; + default: + dev_err(np->device, PFX "Bogus port number %u\n", + np->port); + return -EINVAL; + } + niudbg(PROBE, "SPROM: PHY type %llx\n", (unsigned long long) val); + + switch (val) { + case ESPC_PHY_TYPE_1G_COPPER: + /* 1G copper, MII */ + np->flags &= ~(NIU_FLAGS_FIBER | + NIU_FLAGS_10G); + np->mac_xcvr = MAC_XCVR_MII; + break; + + case ESPC_PHY_TYPE_1G_FIBER: + /* 1G fiber, PCS */ + np->flags &= ~NIU_FLAGS_10G; + np->flags |= NIU_FLAGS_FIBER; + np->mac_xcvr = MAC_XCVR_PCS; + break; + + case ESPC_PHY_TYPE_10G_COPPER: + /* 10G copper, XPCS */ + np->flags |= NIU_FLAGS_10G; + np->flags &= ~NIU_FLAGS_FIBER; + np->mac_xcvr = MAC_XCVR_XPCS; + break; + + case ESPC_PHY_TYPE_10G_FIBER: + /* 10G fiber, XPCS */ + np->flags |= (NIU_FLAGS_10G | + NIU_FLAGS_FIBER); + np->mac_xcvr = MAC_XCVR_XPCS; + break; + + default: + dev_err(np->device, PFX "Bogus SPROM phy type %llu\n", + (unsigned long long) val); + return -EINVAL; + } + + val = nr64(ESPC_MAC_ADDR0); + niudbg(PROBE, "SPROM: MAC_ADDR0[%08llx]\n", + (unsigned long long) val); + dev->perm_addr[0] = (val >> 0) & 0xff; + dev->perm_addr[1] = (val >> 8) & 0xff; + dev->perm_addr[2] = (val >> 16) & 0xff; + dev->perm_addr[3] = (val >> 24) & 0xff; + + val = nr64(ESPC_MAC_ADDR1); + niudbg(PROBE, "SPROM: MAC_ADDR1[%08llx]\n", + (unsigned long long) val); + dev->perm_addr[4] = (val >> 0) & 0xff; + dev->perm_addr[5] = (val >> 8) & 0xff; + + if (!is_valid_ether_addr(&dev->perm_addr[0])) { + dev_err(np->device, PFX "SPROM MAC address invalid\n"); + dev_err(np->device, PFX "[ \n"); + for (i = 0; i < 6; i++) + printk("%02x ", dev->perm_addr[i]); + printk("]\n"); + return -EINVAL; + } + + val8 = dev->perm_addr[5]; + dev->perm_addr[5] += np->port; + if (dev->perm_addr[5] < val8) + dev->perm_addr[4]++; + + memcpy(dev->dev_addr, dev->perm_addr, dev->addr_len); + + val = nr64(ESPC_MOD_STR_LEN); + niudbg(PROBE, "SPROM: MOD_STR_LEN[%llu]\n", + (unsigned long long) val); + if (val > 8 * 4) + return -EINVAL; + + for (i = 0; i < val; i += 4) { + u64 tmp = nr64(ESPC_NCR(5 + (i / 4))); + + np->vpd.model[i + 3] = (tmp >> 0) & 0xff; + np->vpd.model[i + 2] = (tmp >> 8) & 0xff; + np->vpd.model[i + 1] = (tmp >> 16) & 0xff; + np->vpd.model[i + 0] = (tmp >> 24) & 0xff; + } + np->vpd.model[val] = '\0'; + + val = nr64(ESPC_BD_MOD_STR_LEN); + niudbg(PROBE, "SPROM: BD_MOD_STR_LEN[%llu]\n", + (unsigned long long) val); + if (val > 4 * 4) + return -EINVAL; + + for (i = 0; i < val; i += 4) { + u64 tmp = nr64(ESPC_NCR(14 + (i / 4))); + + np->vpd.board_model[i + 3] = (tmp >> 0) & 0xff; + np->vpd.board_model[i + 2] = (tmp >> 8) & 0xff; + np->vpd.board_model[i + 1] = (tmp >> 16) & 0xff; + np->vpd.board_model[i + 0] = (tmp >> 24) & 0xff; + } + np->vpd.board_model[val] = '\0'; + + np->vpd.mac_num = + nr64(ESPC_NUM_PORTS_MACS) & ESPC_NUM_PORTS_MACS_VAL; + niudbg(PROBE, "SPROM: NUM_PORTS_MACS[%d]\n", + np->vpd.mac_num); + + return 0; +} + +static int __devinit niu_get_and_validate_port(struct niu *np) +{ + struct niu_parent *parent = np->parent; + + if (np->port <= 1) + np->flags |= NIU_FLAGS_XMAC; + + if (!parent->num_ports) { + if (parent->plat_type == PLAT_TYPE_NIU) { + parent->num_ports = 2; + } else { + parent->num_ports = nr64(ESPC_NUM_PORTS_MACS) & + ESPC_NUM_PORTS_MACS_VAL; + + if (!parent->num_ports) + parent->num_ports = 4; + } + } + + niudbg(PROBE, "niu_get_and_validate_port: port[%d] num_ports[%d]\n", + np->port, parent->num_ports); + if (np->port >= parent->num_ports) + return -ENODEV; + + return 0; +} + +static int __devinit phy_record(struct niu_parent *parent, + struct phy_probe_info *p, + int dev_id_1, int dev_id_2, u8 phy_port, + int type) +{ + u32 id = (dev_id_1 << 16) | dev_id_2; + u8 idx; + + if (dev_id_1 < 0 || dev_id_2 < 0) + return 0; + if (type == PHY_TYPE_PMA_PMD || type == PHY_TYPE_PCS) { + if ((id & NIU_PHY_ID_MASK) != NIU_PHY_ID_BCM8704) + return 0; + } else { + if ((id & NIU_PHY_ID_MASK) != NIU_PHY_ID_BCM5464R) + return 0; + } + + pr_info("niu%d: Found PHY %08x type %s at phy_port %u\n", + parent->index, id, + (type == PHY_TYPE_PMA_PMD ? + "PMA/PMD" : + (type == PHY_TYPE_PCS ? + "PCS" : "MII")), + phy_port); + + if (p->cur[type] >= NIU_MAX_PORTS) { + printk(KERN_ERR PFX "Too many PHY ports.\n"); + return -EINVAL; + } + idx = p->cur[type]; + p->phy_id[type][idx] = id; + p->phy_port[type][idx] = phy_port; + p->cur[type] = idx + 1; + return 0; +} + +static int __devinit port_has_10g(struct phy_probe_info *p, int port) +{ + int i; + + for (i = 0; i < p->cur[PHY_TYPE_PMA_PMD]; i++) { + if (p->phy_port[PHY_TYPE_PMA_PMD][i] == port) + return 1; + } + for (i = 0; i < p->cur[PHY_TYPE_PCS]; i++) { + if (p->phy_port[PHY_TYPE_PCS][i] == port) + return 1; + } + + return 0; +} + +static int __devinit count_10g_ports(struct phy_probe_info *p, int *lowest) +{ + int port, cnt; + + cnt = 0; + *lowest = 32; + for (port = 8; port < 32; port++) { + if (port_has_10g(p, port)) { + if (!cnt) + *lowest = port; + cnt++; + } + } + + return cnt; +} + +static int __devinit count_1g_ports(struct phy_probe_info *p, int *lowest) +{ + *lowest = 32; + if (p->cur[PHY_TYPE_MII]) + *lowest = p->phy_port[PHY_TYPE_MII][0]; + + return p->cur[PHY_TYPE_MII]; +} + +static void __devinit niu_n2_divide_channels(struct niu_parent *parent) +{ + int num_ports = parent->num_ports; + int i; + + for (i = 0; i < num_ports; i++) { + parent->rxchan_per_port[i] = (16 / num_ports); + parent->txchan_per_port[i] = (16 / num_ports); + + pr_info(PFX "niu%d: Port %u [%u RX chans] " + "[%u TX chans]\n", + parent->index, i, + parent->rxchan_per_port[i], + parent->txchan_per_port[i]); + } +} + +static void __devinit niu_divide_channels(struct niu_parent *parent, + int num_10g, int num_1g) +{ + int num_ports = parent->num_ports; + int rx_chans_per_10g, rx_chans_per_1g; + int tx_chans_per_10g, tx_chans_per_1g; + int i, tot_rx, tot_tx; + + if (!num_10g || !num_1g) { + rx_chans_per_10g = rx_chans_per_1g = + (NIU_NUM_RXCHAN / num_ports); + tx_chans_per_10g = tx_chans_per_1g = + (NIU_NUM_TXCHAN / num_ports); + } else { + rx_chans_per_1g = NIU_NUM_RXCHAN / 8; + rx_chans_per_10g = (NIU_NUM_RXCHAN - + (rx_chans_per_1g * num_1g)) / + num_10g; + + tx_chans_per_1g = NIU_NUM_TXCHAN / 6; + tx_chans_per_10g = (NIU_NUM_TXCHAN - + (tx_chans_per_1g * num_1g)) / + num_10g; + } + + tot_rx = tot_tx = 0; + for (i = 0; i < num_ports; i++) { + int type = phy_decode(parent->port_phy, i); + + if (type == PORT_TYPE_10G) { + parent->rxchan_per_port[i] = rx_chans_per_10g; + parent->txchan_per_port[i] = tx_chans_per_10g; + } else { + parent->rxchan_per_port[i] = rx_chans_per_1g; + parent->txchan_per_port[i] = tx_chans_per_1g; + } + pr_info(PFX "niu%d: Port %u [%u RX chans] " + "[%u TX chans]\n", + parent->index, i, + parent->rxchan_per_port[i], + parent->txchan_per_port[i]); + tot_rx += parent->rxchan_per_port[i]; + tot_tx += parent->txchan_per_port[i]; + } + + if (tot_rx > NIU_NUM_RXCHAN) { + printk(KERN_ERR PFX "niu%d: Too many RX channels (%d), " + "resetting to one per port.\n", + parent->index, tot_rx); + for (i = 0; i < num_ports; i++) + parent->rxchan_per_port[i] = 1; + } + if (tot_tx > NIU_NUM_TXCHAN) { + printk(KERN_ERR PFX "niu%d: Too many TX channels (%d), " + "resetting to one per port.\n", + parent->index, tot_tx); + for (i = 0; i < num_ports; i++) + parent->txchan_per_port[i] = 1; + } + if (tot_rx < NIU_NUM_RXCHAN || tot_tx < NIU_NUM_TXCHAN) { + printk(KERN_WARNING PFX "niu%d: Driver bug, wasted channels, " + "RX[%d] TX[%d]\n", + parent->index, tot_rx, tot_tx); + } +} + +static void __devinit niu_divide_rdc_groups(struct niu_parent *parent, + int num_10g, int num_1g) +{ + int i, num_ports = parent->num_ports; + int rdc_group, rdc_groups_per_port; + int rdc_channel_base; + + rdc_group = 0; + rdc_groups_per_port = NIU_NUM_RDC_TABLES / num_ports; + + rdc_channel_base = 0; + + for (i = 0; i < num_ports; i++) { + struct niu_rdc_tables *tp = &parent->rdc_group_cfg[i]; + int grp, num_channels = parent->rxchan_per_port[i]; + int this_channel_offset; + + tp->first_table_num = rdc_group; + tp->num_tables = rdc_groups_per_port; + this_channel_offset = 0; + for (grp = 0; grp < tp->num_tables; grp++) { + struct rdc_table *rt = &tp->tables[grp]; + int slot; + + pr_info(PFX "niu%d: Port %d RDC tbl(%d) [ ", + parent->index, i, tp->first_table_num + grp); + for (slot = 0; slot < NIU_RDC_TABLE_SLOTS; slot++) { + rt->rxdma_channel[slot] = + rdc_channel_base + this_channel_offset; + + printk("%d ", rt->rxdma_channel[slot]); + + if (++this_channel_offset == num_channels) + this_channel_offset = 0; + } + printk("]\n"); + } + + parent->rdc_default[i] = rdc_channel_base; + + rdc_channel_base += num_channels; + rdc_group += rdc_groups_per_port; + } +} + +static int __devinit fill_phy_probe_info(struct niu *np, + struct niu_parent *parent, + struct phy_probe_info *info) +{ + unsigned long flags; + int port, err; + + memset(info, 0, sizeof(*info)); + + /* Port 0 to 7 are reserved for onboard Serdes, probe the rest. */ + niu_lock_parent(np, flags); + err = 0; + for (port = 8; port < 32; port++) { + int dev_id_1, dev_id_2; + + dev_id_1 = mdio_read(np, port, + NIU_PMA_PMD_DEV_ADDR, MII_PHYSID1); + dev_id_2 = mdio_read(np, port, + NIU_PMA_PMD_DEV_ADDR, MII_PHYSID2); + err = phy_record(parent, info, dev_id_1, dev_id_2, port, + PHY_TYPE_PMA_PMD); + if (err) + break; + dev_id_1 = mdio_read(np, port, + NIU_PCS_DEV_ADDR, MII_PHYSID1); + dev_id_2 = mdio_read(np, port, + NIU_PCS_DEV_ADDR, MII_PHYSID2); + err = phy_record(parent, info, dev_id_1, dev_id_2, port, + PHY_TYPE_PCS); + if (err) + break; + dev_id_1 = mii_read(np, port, MII_PHYSID1); + dev_id_2 = mii_read(np, port, MII_PHYSID2); + err = phy_record(parent, info, dev_id_1, dev_id_2, port, + PHY_TYPE_MII); + if (err) + break; + } + niu_unlock_parent(np, flags); + + return err; +} + +static int __devinit walk_phys(struct niu *np, struct niu_parent *parent) +{ + struct phy_probe_info *info = &parent->phy_probe_info; + int lowest_10g, lowest_1g; + int num_10g, num_1g; + u32 val; + int err; + + err = fill_phy_probe_info(np, parent, info); + if (err) + return err; + + num_10g = count_10g_ports(info, &lowest_10g); + num_1g = count_1g_ports(info, &lowest_1g); + + switch ((num_10g << 4) | num_1g) { + case 0x24: + if (lowest_1g == 10) + parent->plat_type = PLAT_TYPE_VF_P0; + else if (lowest_1g == 26) + parent->plat_type = PLAT_TYPE_VF_P1; + else + goto unknown_vg_1g_port; + + /* fallthru */ + case 0x22: + val = (phy_encode(PORT_TYPE_10G, 0) | + phy_encode(PORT_TYPE_10G, 1) | + phy_encode(PORT_TYPE_1G, 2) | + phy_encode(PORT_TYPE_1G, 3)); + break; + + case 0x20: + val = (phy_encode(PORT_TYPE_10G, 0) | + phy_encode(PORT_TYPE_10G, 1)); + break; + + case 0x10: + val = phy_encode(PORT_TYPE_10G, np->port); + break; + + case 0x14: + if (lowest_1g == 10) + parent->plat_type = PLAT_TYPE_VF_P0; + else if (lowest_1g == 26) + parent->plat_type = PLAT_TYPE_VF_P1; + else + goto unknown_vg_1g_port; + + /* fallthru */ + case 0x13: + if ((lowest_10g & 0x7) == 0) + val = (phy_encode(PORT_TYPE_10G, 0) | + phy_encode(PORT_TYPE_1G, 1) | + phy_encode(PORT_TYPE_1G, 2) | + phy_encode(PORT_TYPE_1G, 3)); + else + val = (phy_encode(PORT_TYPE_1G, 0) | + phy_encode(PORT_TYPE_10G, 1) | + phy_encode(PORT_TYPE_1G, 2) | + phy_encode(PORT_TYPE_1G, 3)); + break; + + case 0x04: + if (lowest_1g == 10) + parent->plat_type = PLAT_TYPE_VF_P0; + else if (lowest_1g == 26) + parent->plat_type = PLAT_TYPE_VF_P1; + else + goto unknown_vg_1g_port; + + val = (phy_encode(PORT_TYPE_1G, 0) | + phy_encode(PORT_TYPE_1G, 1) | + phy_encode(PORT_TYPE_1G, 2) | + phy_encode(PORT_TYPE_1G, 3)); + break; + + default: + printk(KERN_ERR PFX "Unsupported port config " + "10G[%d] 1G[%d]\n", + num_10g, num_1g); + return -EINVAL; + } + + parent->port_phy = val; + + if (parent->plat_type == PLAT_TYPE_NIU) + niu_n2_divide_channels(parent); + else + niu_divide_channels(parent, num_10g, num_1g); + + niu_divide_rdc_groups(parent, num_10g, num_1g); + + return 0; + +unknown_vg_1g_port: + printk(KERN_ERR PFX "Cannot identify platform type, 1gport=%d\n", + lowest_1g); + return -EINVAL; +} + +static int __devinit niu_probe_ports(struct niu *np) +{ + struct niu_parent *parent = np->parent; + int err, i; + + niudbg(PROBE, "niu_probe_ports(): port_phy[%08x]\n", + parent->port_phy); + + if (parent->port_phy == PORT_PHY_UNKNOWN) { + err = walk_phys(np, parent); + if (err) + return err; + + niu_set_ldg_timer_res(np, 2); + for (i = 0; i <= LDN_MAX; i++) + niu_ldn_irq_enable(np, i, 0); + } + + if (parent->port_phy == PORT_PHY_INVALID) + return -EINVAL; + + return 0; +} + +static int __devinit niu_classifier_swstate_init(struct niu *np) +{ + struct niu_classifier *cp = &np->clas; + + niudbg(PROBE, "niu_classifier_swstate_init: num_tcam(%d)\n", + np->parent->tcam_num_entries); + + cp->tcam_index = (u16) np->port; + cp->h1_init = 0xffffffff; + cp->h2_init = 0xffff; + + return fflp_early_init(np); +} + +static void __devinit niu_link_config_init(struct niu *np) +{ + struct niu_link_config *lp = &np->link_config; + + lp->advertising = (ADVERTISED_10baseT_Half | + ADVERTISED_10baseT_Full | + ADVERTISED_100baseT_Half | + ADVERTISED_100baseT_Full | + ADVERTISED_1000baseT_Half | + ADVERTISED_1000baseT_Full | + ADVERTISED_10000baseT_Full | + ADVERTISED_Autoneg); + lp->speed = lp->active_speed = SPEED_INVALID; + lp->duplex = lp->active_duplex = DUPLEX_INVALID; +#if 0 + lp->loopback_mode = LOOPBACK_MAC; + lp->active_speed = SPEED_10000; + lp->active_duplex = DUPLEX_FULL; +#else + lp->loopback_mode = LOOPBACK_DISABLED; +#endif +} + +static int __devinit niu_init_mac_ipp_pcs_base(struct niu *np) +{ + switch (np->port) { + case 0: + np->mac_regs = np->regs + XMAC_PORT0_OFF; + np->ipp_off = 0x00000; + np->pcs_off = 0x04000; + np->xpcs_off = 0x02000; + break; + + case 1: + np->mac_regs = np->regs + XMAC_PORT1_OFF; + np->ipp_off = 0x08000; + np->pcs_off = 0x0a000; + np->xpcs_off = 0x08000; + break; + + case 2: + np->mac_regs = np->regs + BMAC_PORT2_OFF; + np->ipp_off = 0x04000; + np->pcs_off = 0x0e000; + np->xpcs_off = ~0UL; + break; + + case 3: + np->mac_regs = np->regs + BMAC_PORT3_OFF; + np->ipp_off = 0x0c000; + np->pcs_off = 0x12000; + np->xpcs_off = ~0UL; + break; + + default: + dev_err(np->device, PFX "Port %u is invalid, cannot " + "compute MAC block offset.\n", np->port); + return -EINVAL; + } + + return 0; +} + +static void __devinit niu_try_msix(struct niu *np, u8 *ldg_num_map) +{ + struct msix_entry msi_vec[NIU_NUM_LDG]; + struct niu_parent *parent = np->parent; + struct pci_dev *pdev = np->pdev; + int i, num_irqs, err; + u8 first_ldg; + + first_ldg = (NIU_NUM_LDG / parent->num_ports) * np->port; + for (i = 0; i < (NIU_NUM_LDG / parent->num_ports); i++) + ldg_num_map[i] = first_ldg + i; + + num_irqs = (parent->rxchan_per_port[np->port] + + parent->txchan_per_port[np->port] + + (np->port == 0 ? 3 : 1)); + BUG_ON(num_irqs > (NIU_NUM_LDG / parent->num_ports)); + +retry: + for (i = 0; i < num_irqs; i++) { + msi_vec[i].vector = 0; + msi_vec[i].entry = i; + } + + err = pci_enable_msix(pdev, msi_vec, num_irqs); + if (err < 0) { + np->flags &= ~NIU_FLAGS_MSIX; + return; + } + if (err > 0) { + num_irqs = err; + goto retry; + } + + np->flags |= NIU_FLAGS_MSIX; + for (i = 0; i < num_irqs; i++) + np->ldg[i].irq = msi_vec[i].vector; + np->num_ldg = num_irqs; +} + +static int __devinit niu_n2_irq_init(struct niu *np, u8 *ldg_num_map) +{ +#ifdef CONFIG_SPARC64 + struct of_device *op = np->op; + const u32 *int_prop; + int i; + + int_prop = of_get_property(op->node, "interrupts", NULL); + if (!int_prop) + return -ENODEV; + + for (i = 0; i < op->num_irqs; i++) { + ldg_num_map[i] = int_prop[i]; + np->ldg[i].irq = op->irqs[i]; + } + + np->num_ldg = op->num_irqs; + + return 0; +#else + return -EINVAL; +#endif +} + +static int __devinit niu_ldg_init(struct niu *np) +{ + struct niu_parent *parent = np->parent; + u8 ldg_num_map[NIU_NUM_LDG]; + int first_chan, num_chan; + int i, err, ldg_rotor; + u8 port; + + np->num_ldg = 1; + np->ldg[0].irq = np->dev->irq; + if (parent->plat_type == PLAT_TYPE_NIU) { + err = niu_n2_irq_init(np, ldg_num_map); + if (err) + return err; + } else + niu_try_msix(np, ldg_num_map); + + port = np->port; + for (i = 0; i < np->num_ldg; i++) { + struct niu_ldg *lp = &np->ldg[i]; + + netif_napi_add(np->dev, &lp->napi, niu_poll, 64); + + lp->np = np; + lp->ldg_num = ldg_num_map[i]; + lp->timer = 2; /* XXX */ + + /* On N2 NIU the firmware has setup the SID mappings so they go + * to the correct values that will route the LDG to the proper + * interrupt in the NCU interrupt table. + */ + if (np->parent->plat_type != PLAT_TYPE_NIU) { + err = niu_set_ldg_sid(np, lp->ldg_num, port, i); + if (err) + return err; + } + } + + /* We adopt the LDG assignment ordering used by the N2 NIU + * 'interrupt' properties because that simplifies a lot of + * things. This ordering is: + * + * MAC + * MIF (if port zero) + * SYSERR (if port zero) + * RX channels + * TX channels + */ + + ldg_rotor = 0; + + err = niu_ldg_assign_ldn(np, parent, ldg_num_map[ldg_rotor], + LDN_MAC(port)); + if (err) + return err; + + ldg_rotor++; + if (ldg_rotor == np->num_ldg) + ldg_rotor = 0; + + if (port == 0) { + err = niu_ldg_assign_ldn(np, parent, + ldg_num_map[ldg_rotor], + LDN_MIF); + if (err) + return err; + + ldg_rotor++; + if (ldg_rotor == np->num_ldg) + ldg_rotor = 0; + + err = niu_ldg_assign_ldn(np, parent, + ldg_num_map[ldg_rotor], + LDN_DEVICE_ERROR); + if (err) + return err; + + ldg_rotor++; + if (ldg_rotor == np->num_ldg) + ldg_rotor = 0; + + } + + first_chan = 0; + for (i = 0; i < port; i++) + first_chan += parent->rxchan_per_port[port]; + num_chan = parent->rxchan_per_port[port]; + + for (i = first_chan; i < (first_chan + num_chan); i++) { + err = niu_ldg_assign_ldn(np, parent, + ldg_num_map[ldg_rotor], + LDN_RXDMA(i)); + if (err) + return err; + ldg_rotor++; + if (ldg_rotor == np->num_ldg) + ldg_rotor = 0; + } + + first_chan = 0; + for (i = 0; i < port; i++) + first_chan += parent->txchan_per_port[port]; + num_chan = parent->txchan_per_port[port]; + for (i = first_chan; i < (first_chan + num_chan); i++) { + err = niu_ldg_assign_ldn(np, parent, + ldg_num_map[ldg_rotor], + LDN_TXDMA(i)); + if (err) + return err; + ldg_rotor++; + if (ldg_rotor == np->num_ldg) + ldg_rotor = 0; + } + + return 0; +} + +static void __devexit niu_ldg_free(struct niu *np) +{ + if (np->flags & NIU_FLAGS_MSIX) + pci_disable_msix(np->pdev); +} + +static int __devinit niu_get_of_props(struct niu *np) +{ +#ifdef CONFIG_SPARC64 + struct net_device *dev = np->dev; + struct device_node *dp; + const char *phy_type; + const u8 *mac_addr; + int prop_len; + + if (np->parent->plat_type == PLAT_TYPE_NIU) + dp = np->op->node; + else + dp = pci_device_to_OF_node(np->pdev); + + phy_type = of_get_property(dp, "phy-type", &prop_len); + if (!phy_type) { + dev_err(np->device, PFX "%s: OF node lacks " + "phy-type property\n", + dp->full_name); + return -EINVAL; + } + + if (!strcmp(phy_type, "none")) + return -ENODEV; + + strcpy(np->vpd.phy_type, phy_type); + + if (niu_phy_type_prop_decode(np, np->vpd.phy_type)) { + dev_err(np->device, PFX "%s: Illegal phy string [%s].\n", + dp->full_name, np->vpd.phy_type); + return -EINVAL; + } + + mac_addr = of_get_property(dp, "local-mac-address", &prop_len); + if (!mac_addr) { + dev_err(np->device, PFX "%s: OF node lacks " + "local-mac-address property\n", + dp->full_name); + return -EINVAL; + } + if (prop_len != dev->addr_len) { + dev_err(np->device, PFX "%s: OF MAC address prop len (%d) " + "is wrong.\n", + dp->full_name, prop_len); + } + memcpy(dev->perm_addr, mac_addr, dev->addr_len); + if (!is_valid_ether_addr(&dev->perm_addr[0])) { + int i; + + dev_err(np->device, PFX "%s: OF MAC address is invalid\n", + dp->full_name); + dev_err(np->device, PFX "%s: [ \n", + dp->full_name); + for (i = 0; i < 6; i++) + printk("%02x ", dev->perm_addr[i]); + printk("]\n"); + return -EINVAL; + } + + memcpy(dev->dev_addr, dev->perm_addr, dev->addr_len); + + return 0; +#else + return -EINVAL; +#endif +} + +static int __devinit niu_get_invariants(struct niu *np) +{ + int err, have_props; + u32 offset; + + err = niu_get_of_props(np); + if (err == -ENODEV) + return err; + + have_props = !err; + + err = niu_get_and_validate_port(np); + if (err) + return err; + + err = niu_init_mac_ipp_pcs_base(np); + if (err) + return err; + + if (!have_props) { + if (np->parent->plat_type == PLAT_TYPE_NIU) + return -EINVAL; + + nw64(ESPC_PIO_EN, ESPC_PIO_EN_ENABLE); + offset = niu_pci_vpd_offset(np); + niudbg(PROBE, "niu_get_invariants: VPD offset [%08x]\n", + offset); + if (offset) + niu_pci_vpd_fetch(np, offset); + nw64(ESPC_PIO_EN, 0); + + if (np->flags & NIU_FLAGS_VPD_VALID) + niu_pci_vpd_validate(np); + + if (!(np->flags & NIU_FLAGS_VPD_VALID)) { + err = niu_pci_probe_sprom(np); + if (err) + return err; + } + } + + err = niu_probe_ports(np); + if (err) + return err; + + niu_ldg_init(np); + + niu_classifier_swstate_init(np); + niu_link_config_init(np); + + err = niu_determine_phy_disposition(np); + if (!err) + err = niu_init_link(np); + + return err; +} + +static LIST_HEAD(niu_parent_list); +static DEFINE_MUTEX(niu_parent_lock); +static int niu_parent_index; + +static ssize_t show_port_phy(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct platform_device *plat_dev = to_platform_device(dev); + struct niu_parent *p = plat_dev->dev.platform_data; + u32 port_phy = p->port_phy; + char *orig_buf = buf; + int i; + + if (port_phy == PORT_PHY_UNKNOWN || + port_phy == PORT_PHY_INVALID) + return 0; + + for (i = 0; i < p->num_ports; i++) { + const char *type_str; + int type; + + type = phy_decode(port_phy, i); + if (type == PORT_TYPE_10G) + type_str = "10G"; + else + type_str = "1G"; + buf += sprintf(buf, + (i == 0) ? "%s" : " %s", + type_str); + } + buf += sprintf(buf, "\n"); + return buf - orig_buf; +} + +static ssize_t show_plat_type(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct platform_device *plat_dev = to_platform_device(dev); + struct niu_parent *p = plat_dev->dev.platform_data; + const char *type_str; + + switch (p->plat_type) { + case PLAT_TYPE_ATLAS: + type_str = "atlas"; + break; + case PLAT_TYPE_NIU: + type_str = "niu"; + break; + case PLAT_TYPE_VF_P0: + type_str = "vf_p0"; + break; + case PLAT_TYPE_VF_P1: + type_str = "vf_p1"; + break; + default: + type_str = "unknown"; + break; + } + + return sprintf(buf, "%s\n", type_str); +} + +static ssize_t __show_chan_per_port(struct device *dev, + struct device_attribute *attr, char *buf, + int rx) +{ + struct platform_device *plat_dev = to_platform_device(dev); + struct niu_parent *p = plat_dev->dev.platform_data; + char *orig_buf = buf; + u8 *arr; + int i; + + arr = (rx ? p->rxchan_per_port : p->txchan_per_port); + + for (i = 0; i < p->num_ports; i++) { + buf += sprintf(buf, + (i == 0) ? "%d" : " %d", + arr[i]); + } + buf += sprintf(buf, "\n"); + + return buf - orig_buf; +} + +static ssize_t show_rxchan_per_port(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return __show_chan_per_port(dev, attr, buf, 1); +} + +static ssize_t show_txchan_per_port(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return __show_chan_per_port(dev, attr, buf, 1); +} + +static ssize_t show_num_ports(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct platform_device *plat_dev = to_platform_device(dev); + struct niu_parent *p = plat_dev->dev.platform_data; + + return sprintf(buf, "%d\n", p->num_ports); +} + +static struct device_attribute niu_parent_attributes[] = { + __ATTR(port_phy, S_IRUGO, show_port_phy, NULL), + __ATTR(plat_type, S_IRUGO, show_plat_type, NULL), + __ATTR(rxchan_per_port, S_IRUGO, show_rxchan_per_port, NULL), + __ATTR(txchan_per_port, S_IRUGO, show_txchan_per_port, NULL), + __ATTR(num_ports, S_IRUGO, show_num_ports, NULL), + {} +}; + +static struct niu_parent * __devinit niu_new_parent(struct niu *np, + union niu_parent_id *id, + u8 ptype) +{ + struct platform_device *plat_dev; + struct niu_parent *p; + int i; + + niudbg(PROBE, "niu_new_parent: Creating new parent.\n"); + + plat_dev = platform_device_register_simple("niu", niu_parent_index, + NULL, 0); + if (!plat_dev) + return NULL; + + for (i = 0; attr_name(niu_parent_attributes[i]); i++) { + int err = device_create_file(&plat_dev->dev, + &niu_parent_attributes[i]); + if (err) + goto fail_unregister; + } + + p = kzalloc(sizeof(*p), GFP_KERNEL); + if (!p) + goto fail_unregister; + + p->index = niu_parent_index++; + + plat_dev->dev.platform_data = p; + p->plat_dev = plat_dev; + + memcpy(&p->id, id, sizeof(*id)); + p->plat_type = ptype; + INIT_LIST_HEAD(&p->list); + atomic_set(&p->refcnt, 0); + list_add(&p->list, &niu_parent_list); + spin_lock_init(&p->lock); + + p->rxdma_clock_divider = 7500; + + p->tcam_num_entries = NIU_PCI_TCAM_ENTRIES; + if (p->plat_type == PLAT_TYPE_NIU) + p->tcam_num_entries = NIU_NONPCI_TCAM_ENTRIES; + + for (i = CLASS_CODE_USER_PROG1; i <= CLASS_CODE_SCTP_IPV6; i++) { + int index = i - CLASS_CODE_USER_PROG1; + + p->tcam_key[index] = TCAM_KEY_TSEL; + p->flow_key[index] = (FLOW_KEY_IPSA | + FLOW_KEY_IPDA | + FLOW_KEY_PROTO | + (FLOW_KEY_L4_BYTE12 << + FLOW_KEY_L4_0_SHIFT) | + (FLOW_KEY_L4_BYTE12 << + FLOW_KEY_L4_1_SHIFT)); + } + + for (i = 0; i < LDN_MAX + 1; i++) + p->ldg_map[i] = LDG_INVALID; + + return p; + +fail_unregister: + platform_device_unregister(plat_dev); + return NULL; +} + +static struct niu_parent * __devinit niu_get_parent(struct niu *np, + union niu_parent_id *id, + u8 ptype) +{ + struct niu_parent *p, *tmp; + int port = np->port; + + niudbg(PROBE, "niu_get_parent: platform_type[%u] port[%u]\n", + ptype, port); + + mutex_lock(&niu_parent_lock); + p = NULL; + list_for_each_entry(tmp, &niu_parent_list, list) { + if (!memcmp(id, &tmp->id, sizeof(*id))) { + p = tmp; + break; + } + } + if (!p) + p = niu_new_parent(np, id, ptype); + + if (p) { + char port_name[6]; + int err; + + sprintf(port_name, "port%d", port); + err = sysfs_create_link(&p->plat_dev->dev.kobj, + &np->device->kobj, + port_name); + if (!err) { + p->ports[port] = np; + atomic_inc(&p->refcnt); + } + } + mutex_unlock(&niu_parent_lock); + + return p; +} + +static void niu_put_parent(struct niu *np) +{ + struct niu_parent *p = np->parent; + u8 port = np->port; + char port_name[6]; + + BUG_ON(!p || p->ports[port] != np); + + niudbg(PROBE, "niu_put_parent: port[%u]\n", port); + + sprintf(port_name, "port%d", port); + + mutex_lock(&niu_parent_lock); + + sysfs_remove_link(&p->plat_dev->dev.kobj, port_name); + + p->ports[port] = NULL; + np->parent = NULL; + + if (atomic_dec_and_test(&p->refcnt)) { + list_del(&p->list); + platform_device_unregister(p->plat_dev); + } + + mutex_unlock(&niu_parent_lock); +} + +static void *niu_pci_alloc_coherent(struct device *dev, size_t size, + u64 *handle, gfp_t flag) +{ + dma_addr_t dh; + void *ret; + + ret = dma_alloc_coherent(dev, size, &dh, flag); + if (ret) + *handle = dh; + return ret; +} + +static void niu_pci_free_coherent(struct device *dev, size_t size, + void *cpu_addr, u64 handle) +{ + dma_free_coherent(dev, size, cpu_addr, handle); +} + +static u64 niu_pci_map_page(struct device *dev, struct page *page, + unsigned long offset, size_t size, + enum dma_data_direction direction) +{ + return dma_map_page(dev, page, offset, size, direction); +} + +static void niu_pci_unmap_page(struct device *dev, u64 dma_address, + size_t size, enum dma_data_direction direction) +{ + return dma_unmap_page(dev, dma_address, size, direction); +} + +static u64 niu_pci_map_single(struct device *dev, void *cpu_addr, + size_t size, + enum dma_data_direction direction) +{ + return dma_map_single(dev, cpu_addr, size, direction); +} + +static void niu_pci_unmap_single(struct device *dev, u64 dma_address, + size_t size, + enum dma_data_direction direction) +{ + dma_unmap_single(dev, dma_address, size, direction); +} + +static const struct niu_ops niu_pci_ops = { + .alloc_coherent = niu_pci_alloc_coherent, + .free_coherent = niu_pci_free_coherent, + .map_page = niu_pci_map_page, + .unmap_page = niu_pci_unmap_page, + .map_single = niu_pci_map_single, + .unmap_single = niu_pci_unmap_single, +}; + +static void __devinit niu_driver_version(void) +{ + static int niu_version_printed; + + if (niu_version_printed++ == 0) + pr_info("%s", version); +} + +static struct net_device * __devinit niu_alloc_and_init( + struct device *gen_dev, struct pci_dev *pdev, + struct of_device *op, const struct niu_ops *ops, + u8 port) +{ + struct net_device *dev = alloc_etherdev(sizeof(struct niu)); + struct niu *np; + + if (!dev) { + dev_err(gen_dev, PFX "Etherdev alloc failed, aborting.\n"); + return NULL; + } + + SET_NETDEV_DEV(dev, gen_dev); + + np = netdev_priv(dev); + np->dev = dev; + np->pdev = pdev; + np->op = op; + np->device = gen_dev; + np->ops = ops; + + np->msg_enable = niu_debug; + + spin_lock_init(&np->lock); + INIT_WORK(&np->reset_task, niu_reset_task); + + np->port = port; + + return dev; +} + +static void __devinit niu_assign_netdev_ops(struct net_device *dev) +{ + dev->open = niu_open; + dev->stop = niu_close; + dev->get_stats = niu_get_stats; + dev->set_multicast_list = niu_set_rx_mode; + dev->set_mac_address = niu_set_mac_addr; + dev->do_ioctl = niu_ioctl; + dev->tx_timeout = niu_tx_timeout; + dev->hard_start_xmit = niu_start_xmit; + dev->ethtool_ops = &niu_ethtool_ops; + dev->watchdog_timeo = NIU_TX_TIMEOUT; + dev->change_mtu = niu_change_mtu; +} + +static void __devinit niu_device_announce(struct niu *np) +{ + struct net_device *dev = np->dev; + int i; + + pr_info("%s: NIU Ethernet ", dev->name); + for (i = 0; i < 6; i++) + printk("%2.2x%c", dev->dev_addr[i], + i == 5 ? '\n' : ':'); + + pr_info("%s: Port type[%s] mode[%s:%s] XCVR[%s] phy[%s]\n", + dev->name, + (np->flags & NIU_FLAGS_XMAC ? "XMAC" : "BMAC"), + (np->flags & NIU_FLAGS_10G ? "10G" : "1G"), + (np->flags & NIU_FLAGS_FIBER ? "FIBER" : "COPPER"), + (np->mac_xcvr == MAC_XCVR_MII ? "MII" : + (np->mac_xcvr == MAC_XCVR_PCS ? "PCS" : "XPCS")), + np->vpd.phy_type); +} + +static int __devinit niu_pci_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + unsigned long niureg_base, niureg_len; + union niu_parent_id parent_id; + struct net_device *dev; + struct niu *np; + int err, pos; + u64 dma_mask; + u16 val16; + + niu_driver_version(); + + err = pci_enable_device(pdev); + if (err) { + dev_err(&pdev->dev, PFX "Cannot enable PCI device, " + "aborting.\n"); + return err; + } + + if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) || + !(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) { + dev_err(&pdev->dev, PFX "Cannot find proper PCI device " + "base addresses, aborting.\n"); + err = -ENODEV; + goto err_out_disable_pdev; + } + + err = pci_request_regions(pdev, DRV_MODULE_NAME); + if (err) { + dev_err(&pdev->dev, PFX "Cannot obtain PCI resources, " + "aborting.\n"); + goto err_out_disable_pdev; + } + + pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); + if (pos <= 0) { + dev_err(&pdev->dev, PFX "Cannot find PCI Express capability, " + "aborting.\n"); + goto err_out_free_res; + } + + dev = niu_alloc_and_init(&pdev->dev, pdev, NULL, + &niu_pci_ops, PCI_FUNC(pdev->devfn)); + if (!dev) { + err = -ENOMEM; + goto err_out_free_res; + } + np = netdev_priv(dev); + + memset(&parent_id, 0, sizeof(parent_id)); + parent_id.pci.domain = pci_domain_nr(pdev->bus); + parent_id.pci.bus = pdev->bus->number; + parent_id.pci.device = PCI_SLOT(pdev->devfn); + + np->parent = niu_get_parent(np, &parent_id, + PLAT_TYPE_ATLAS); + if (!np->parent) { + err = -ENOMEM; + goto err_out_free_dev; + } + + pci_read_config_word(pdev, pos + PCI_EXP_DEVCTL, &val16); + val16 &= ~PCI_EXP_DEVCTL_NOSNOOP_EN; + val16 |= (PCI_EXP_DEVCTL_CERE | + PCI_EXP_DEVCTL_NFERE | + PCI_EXP_DEVCTL_FERE | + PCI_EXP_DEVCTL_URRE | + PCI_EXP_DEVCTL_RELAX_EN); + pci_write_config_word(pdev, pos + PCI_EXP_DEVCTL, val16); + + dma_mask = DMA_44BIT_MASK; + err = pci_set_dma_mask(pdev, dma_mask); + if (!err) { + dev->features |= NETIF_F_HIGHDMA; + err = pci_set_consistent_dma_mask(pdev, dma_mask); + if (err) { + dev_err(&pdev->dev, PFX "Unable to obtain 44 bit " + "DMA for consistent allocations, " + "aborting.\n"); + goto err_out_release_parent; + } + } + if (err || dma_mask == DMA_32BIT_MASK) { + err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (err) { + dev_err(&pdev->dev, PFX "No usable DMA configuration, " + "aborting.\n"); + goto err_out_release_parent; + } + } + + dev->features |= (NETIF_F_SG | NETIF_F_HW_CSUM); + + niureg_base = pci_resource_start(pdev, 0); + niureg_len = pci_resource_len(pdev, 0); + + np->regs = ioremap_nocache(niureg_base, niureg_len); + if (!np->regs) { + dev_err(&pdev->dev, PFX "Cannot map device registers, " + "aborting.\n"); + err = -ENOMEM; + goto err_out_release_parent; + } + + pci_set_master(pdev); + pci_save_state(pdev); + + dev->irq = pdev->irq; + + niu_assign_netdev_ops(dev); + + err = niu_get_invariants(np); + if (err) { + if (err != -ENODEV) + dev_err(&pdev->dev, PFX "Problem fetching invariants " + "of chip, aborting.\n"); + goto err_out_iounmap; + } + + err = register_netdev(dev); + if (err) { + dev_err(&pdev->dev, PFX "Cannot register net device, " + "aborting.\n"); + goto err_out_iounmap; + } + + pci_set_drvdata(pdev, dev); + + niu_device_announce(np); + + return 0; + +err_out_iounmap: + if (np->regs) { + iounmap(np->regs); + np->regs = NULL; + } + +err_out_release_parent: + niu_put_parent(np); + +err_out_free_dev: + free_netdev(dev); + +err_out_free_res: + pci_release_regions(pdev); + +err_out_disable_pdev: + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + + return err; +} + +static void __devexit niu_pci_remove_one(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + + if (dev) { + struct niu *np = netdev_priv(dev); + + unregister_netdev(dev); + if (np->regs) { + iounmap(np->regs); + np->regs = NULL; + } + + niu_ldg_free(np); + + niu_put_parent(np); + + free_netdev(dev); + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + } +} + +static int niu_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct niu *np = netdev_priv(dev); + unsigned long flags; + + if (!netif_running(dev)) + return 0; + + flush_scheduled_work(); + niu_netif_stop(np); + + del_timer_sync(&np->timer); + + spin_lock_irqsave(&np->lock, flags); + niu_enable_interrupts(np, 0); + spin_unlock_irqrestore(&np->lock, flags); + + netif_device_detach(dev); + + spin_lock_irqsave(&np->lock, flags); + niu_stop_hw(np); + spin_unlock_irqrestore(&np->lock, flags); + + pci_save_state(pdev); + + return 0; +} + +static int niu_resume(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct niu *np = netdev_priv(dev); + unsigned long flags; + int err; + + if (!netif_running(dev)) + return 0; + + pci_restore_state(pdev); + + netif_device_attach(dev); + + spin_lock_irqsave(&np->lock, flags); + + err = niu_init_hw(np); + if (!err) { + np->timer.expires = jiffies + HZ; + add_timer(&np->timer); + niu_netif_start(np); + } + + spin_unlock_irqrestore(&np->lock, flags); + + return err; +} + +static struct pci_driver niu_pci_driver = { + .name = DRV_MODULE_NAME, + .id_table = niu_pci_tbl, + .probe = niu_pci_init_one, + .remove = __devexit_p(niu_pci_remove_one), + .suspend = niu_suspend, + .resume = niu_resume, +}; + +#ifdef CONFIG_SPARC64 +static void *niu_phys_alloc_coherent(struct device *dev, size_t size, + u64 *dma_addr, gfp_t flag) +{ + unsigned long order = get_order(size); + unsigned long page = __get_free_pages(flag, order); + + if (page == 0UL) + return NULL; + memset((char *)page, 0, PAGE_SIZE << order); + *dma_addr = __pa(page); + + return (void *) page; +} + +static void niu_phys_free_coherent(struct device *dev, size_t size, + void *cpu_addr, u64 handle) +{ + unsigned long order = get_order(size); + + free_pages((unsigned long) cpu_addr, order); +} + +static u64 niu_phys_map_page(struct device *dev, struct page *page, + unsigned long offset, size_t size, + enum dma_data_direction direction) +{ + return page_to_phys(page) + offset; +} + +static void niu_phys_unmap_page(struct device *dev, u64 dma_address, + size_t size, enum dma_data_direction direction) +{ + /* Nothing to do. */ +} + +static u64 niu_phys_map_single(struct device *dev, void *cpu_addr, + size_t size, + enum dma_data_direction direction) +{ + return __pa(cpu_addr); +} + +static void niu_phys_unmap_single(struct device *dev, u64 dma_address, + size_t size, + enum dma_data_direction direction) +{ + /* Nothing to do. */ +} + +static const struct niu_ops niu_phys_ops = { + .alloc_coherent = niu_phys_alloc_coherent, + .free_coherent = niu_phys_free_coherent, + .map_page = niu_phys_map_page, + .unmap_page = niu_phys_unmap_page, + .map_single = niu_phys_map_single, + .unmap_single = niu_phys_unmap_single, +}; + +static unsigned long res_size(struct resource *r) +{ + return r->end - r->start + 1UL; +} + +static int __devinit niu_of_probe(struct of_device *op, + const struct of_device_id *match) +{ + union niu_parent_id parent_id; + struct net_device *dev; + struct niu *np; + const u32 *reg; + int err; + + niu_driver_version(); + + reg = of_get_property(op->node, "reg", NULL); + if (!reg) { + dev_err(&op->dev, PFX "%s: No 'reg' property, aborting.\n", + op->node->full_name); + return -ENODEV; + } + + dev = niu_alloc_and_init(&op->dev, NULL, op, + &niu_phys_ops, reg[0] & 0x1); + if (!dev) { + err = -ENOMEM; + goto err_out; + } + np = netdev_priv(dev); + + memset(&parent_id, 0, sizeof(parent_id)); + parent_id.of = of_get_parent(op->node); + + np->parent = niu_get_parent(np, &parent_id, + PLAT_TYPE_NIU); + if (!np->parent) { + err = -ENOMEM; + goto err_out_free_dev; + } + + dev->features |= (NETIF_F_SG | NETIF_F_HW_CSUM); + + np->regs = of_ioremap(&op->resource[1], 0, + res_size(&op->resource[1]), + "niu regs"); + if (!np->regs) { + dev_err(&op->dev, PFX "Cannot map device registers, " + "aborting.\n"); + err = -ENOMEM; + goto err_out_release_parent; + } + + np->vir_regs_1 = of_ioremap(&op->resource[2], 0, + res_size(&op->resource[2]), + "niu vregs-1"); + if (!np->vir_regs_1) { + dev_err(&op->dev, PFX "Cannot map device vir registers 1, " + "aborting.\n"); + err = -ENOMEM; + goto err_out_iounmap; + } + + np->vir_regs_2 = of_ioremap(&op->resource[3], 0, + res_size(&op->resource[3]), + "niu vregs-2"); + if (!np->vir_regs_2) { + dev_err(&op->dev, PFX "Cannot map device vir registers 2, " + "aborting.\n"); + err = -ENOMEM; + goto err_out_iounmap; + } + + niu_assign_netdev_ops(dev); + + err = niu_get_invariants(np); + if (err) { + if (err != -ENODEV) + dev_err(&op->dev, PFX "Problem fetching invariants " + "of chip, aborting.\n"); + goto err_out_iounmap; + } + + err = register_netdev(dev); + if (err) { + dev_err(&op->dev, PFX "Cannot register net device, " + "aborting.\n"); + goto err_out_iounmap; + } + + dev_set_drvdata(&op->dev, dev); + + niu_device_announce(np); + + return 0; + +err_out_iounmap: + if (np->vir_regs_1) { + of_iounmap(&op->resource[2], np->vir_regs_1, + res_size(&op->resource[2])); + np->vir_regs_1 = NULL; + } + + if (np->vir_regs_2) { + of_iounmap(&op->resource[3], np->vir_regs_2, + res_size(&op->resource[3])); + np->vir_regs_2 = NULL; + } + + if (np->regs) { + of_iounmap(&op->resource[1], np->regs, + res_size(&op->resource[1])); + np->regs = NULL; + } + +err_out_release_parent: + niu_put_parent(np); + +err_out_free_dev: + free_netdev(dev); + +err_out: + return err; +} + +static int __devexit niu_of_remove(struct of_device *op) +{ + struct net_device *dev = dev_get_drvdata(&op->dev); + + if (dev) { + struct niu *np = netdev_priv(dev); + + unregister_netdev(dev); + + if (np->vir_regs_1) { + of_iounmap(&op->resource[2], np->vir_regs_1, + res_size(&op->resource[2])); + np->vir_regs_1 = NULL; + } + + if (np->vir_regs_2) { + of_iounmap(&op->resource[3], np->vir_regs_2, + res_size(&op->resource[3])); + np->vir_regs_2 = NULL; + } + + if (np->regs) { + of_iounmap(&op->resource[1], np->regs, + res_size(&op->resource[1])); + np->regs = NULL; + } + + niu_ldg_free(np); + + niu_put_parent(np); + + free_netdev(dev); + dev_set_drvdata(&op->dev, NULL); + } + return 0; +} + +static struct of_device_id niu_match[] = { + { + .name = "network", + .compatible = "SUNW,niusl", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, niu_match); + +static struct of_platform_driver niu_of_driver = { + .name = "niu", + .match_table = niu_match, + .probe = niu_of_probe, + .remove = __devexit_p(niu_of_remove), +}; + +#endif /* CONFIG_SPARC64 */ + +static int __init niu_init(void) +{ + int err = 0; + + BUILD_BUG_ON((PAGE_SIZE < 4 * 1024) || + ((PAGE_SIZE > 32 * 1024) && + ((PAGE_SIZE % (32 * 1024)) != 0 && + (PAGE_SIZE % (16 * 1024)) != 0 && + (PAGE_SIZE % (8 * 1024)) != 0 && + (PAGE_SIZE % (4 * 1024)) != 0))); + + niu_debug = netif_msg_init(debug, NIU_MSG_DEFAULT); + +#ifdef CONFIG_SPARC64 + err = of_register_driver(&niu_of_driver, &of_bus_type); +#endif + + if (!err) { + err = pci_register_driver(&niu_pci_driver); +#ifdef CONFIG_SPARC64 + if (err) + of_unregister_driver(&niu_of_driver); +#endif + } + + return err; +} + +static void __exit niu_exit(void) +{ + pci_unregister_driver(&niu_pci_driver); +#ifdef CONFIG_SPARC64 + of_unregister_driver(&niu_of_driver); +#endif +} + +module_init(niu_init); +module_exit(niu_exit); diff --git a/drivers/net/niu.h b/drivers/net/niu.h new file mode 100644 index 00000000000..10e3f111b6d --- /dev/null +++ b/drivers/net/niu.h @@ -0,0 +1,3222 @@ +/* niu.h: Definitions for Neptune ethernet driver. + * + * Copyright (C) 2007 David S. Miller (davem@davemloft.net) + */ + +#ifndef _NIU_H +#define _NIU_H + +#define PIO 0x000000UL +#define FZC_PIO 0x080000UL +#define FZC_MAC 0x180000UL +#define FZC_IPP 0x280000UL +#define FFLP 0x300000UL +#define FZC_FFLP 0x380000UL +#define PIO_VADDR 0x400000UL +#define ZCP 0x500000UL +#define FZC_ZCP 0x580000UL +#define DMC 0x600000UL +#define FZC_DMC 0x680000UL +#define TXC 0x700000UL +#define FZC_TXC 0x780000UL +#define PIO_LDSV 0x800000UL +#define PIO_PIO_LDGIM 0x900000UL +#define PIO_IMASK0 0xa00000UL +#define PIO_IMASK1 0xb00000UL +#define FZC_PROM 0xc80000UL +#define FZC_PIM 0xd80000UL + +#define LDSV0(LDG) (PIO_LDSV + 0x00000UL + (LDG) * 0x2000UL) +#define LDSV1(LDG) (PIO_LDSV + 0x00008UL + (LDG) * 0x2000UL) +#define LDSV2(LDG) (PIO_LDSV + 0x00010UL + (LDG) * 0x2000UL) + +#define LDG_IMGMT(LDG) (PIO_LDSV + 0x00018UL + (LDG) * 0x2000UL) +#define LDG_IMGMT_ARM 0x0000000080000000ULL +#define LDG_IMGMT_TIMER 0x000000000000003fULL + +#define LD_IM0(IDX) (PIO_IMASK0 + 0x00000UL + (IDX) * 0x2000UL) +#define LD_IM0_MASK 0x0000000000000003ULL + +#define LD_IM1(IDX) (PIO_IMASK1 + 0x00000UL + (IDX) * 0x2000UL) +#define LD_IM1_MASK 0x0000000000000003ULL + +#define LDG_TIMER_RES (FZC_PIO + 0x00008UL) +#define LDG_TIMER_RES_VAL 0x00000000000fffffULL + +#define DIRTY_TID_CTL (FZC_PIO + 0x00010UL) +#define DIRTY_TID_CTL_NPTHRED 0x00000000003f0000ULL +#define DIRTY_TID_CTL_RDTHRED 0x00000000000003f0ULL +#define DIRTY_TID_CTL_DTIDCLR 0x0000000000000002ULL +#define DIRTY_TID_CTL_DTIDENAB 0x0000000000000001ULL + +#define DIRTY_TID_STAT (FZC_PIO + 0x00018UL) +#define DIRTY_TID_STAT_NPWSTAT 0x0000000000003f00ULL +#define DIRTY_TID_STAT_RDSTAT 0x000000000000003fULL + +#define RST_CTL (FZC_PIO + 0x00038UL) +#define RST_CTL_MAC_RST3 0x0000000000400000ULL +#define RST_CTL_MAC_RST2 0x0000000000200000ULL +#define RST_CTL_MAC_RST1 0x0000000000100000ULL +#define RST_CTL_MAC_RST0 0x0000000000080000ULL +#define RST_CTL_ACK_TO_EN 0x0000000000000800ULL +#define RST_CTL_ACK_TO_VAL 0x00000000000007feULL + +#define SMX_CFIG_DAT (FZC_PIO + 0x00040UL) +#define SMX_CFIG_DAT_RAS_DET 0x0000000080000000ULL +#define SMX_CFIG_DAT_RAS_INJ 0x0000000040000000ULL +#define SMX_CFIG_DAT_XACT_TO 0x000000000fffffffULL + +#define SMX_INT_STAT (FZC_PIO + 0x00048UL) +#define SMX_INT_STAT_STAT 0x00000000ffffffffULL + +#define SMX_CTL (FZC_PIO + 0x00050UL) +#define SMX_CTL_CTL 0x00000000ffffffffULL + +#define SMX_DBG_VEC (FZC_PIO + 0x00058UL) +#define SMX_DBG_VEC_VEC 0x00000000ffffffffULL + +#define PIO_DBG_SEL (FZC_PIO + 0x00060UL) +#define PIO_DBG_SEL_SEL 0x000000000000003fULL + +#define PIO_TRAIN_VEC (FZC_PIO + 0x00068UL) +#define PIO_TRAIN_VEC_VEC 0x00000000ffffffffULL + +#define PIO_ARB_CTL (FZC_PIO + 0x00070UL) +#define PIO_ARB_CTL_CTL 0x00000000ffffffffULL + +#define PIO_ARB_DBG_VEC (FZC_PIO + 0x00078UL) +#define PIO_ARB_DBG_VEC_VEC 0x00000000ffffffffULL + +#define SYS_ERR_MASK (FZC_PIO + 0x00090UL) +#define SYS_ERR_MASK_META2 0x0000000000000400ULL +#define SYS_ERR_MASK_META1 0x0000000000000200ULL +#define SYS_ERR_MASK_PEU 0x0000000000000100ULL +#define SYS_ERR_MASK_TXC 0x0000000000000080ULL +#define SYS_ERR_MASK_RDMC 0x0000000000000040ULL +#define SYS_ERR_MASK_TDMC 0x0000000000000020ULL +#define SYS_ERR_MASK_ZCP 0x0000000000000010ULL +#define SYS_ERR_MASK_FFLP 0x0000000000000008ULL +#define SYS_ERR_MASK_IPP 0x0000000000000004ULL +#define SYS_ERR_MASK_MAC 0x0000000000000002ULL +#define SYS_ERR_MASK_SMX 0x0000000000000001ULL + +#define SYS_ERR_STAT (FZC_PIO + 0x00098UL) +#define SYS_ERR_STAT_META2 0x0000000000000400ULL +#define SYS_ERR_STAT_META1 0x0000000000000200ULL +#define SYS_ERR_STAT_PEU 0x0000000000000100ULL +#define SYS_ERR_STAT_TXC 0x0000000000000080ULL +#define SYS_ERR_STAT_RDMC 0x0000000000000040ULL +#define SYS_ERR_STAT_TDMC 0x0000000000000020ULL +#define SYS_ERR_STAT_ZCP 0x0000000000000010ULL +#define SYS_ERR_STAT_FFLP 0x0000000000000008ULL +#define SYS_ERR_STAT_IPP 0x0000000000000004ULL +#define SYS_ERR_STAT_MAC 0x0000000000000002ULL +#define SYS_ERR_STAT_SMX 0x0000000000000001ULL + +#define SID(LDG) (FZC_PIO + 0x10200UL + (LDG) * 8UL) +#define SID_FUNC 0x0000000000000060ULL +#define SID_FUNC_SHIFT 5 +#define SID_VECTOR 0x000000000000001fULL +#define SID_VECTOR_SHIFT 0 + +#define LDG_NUM(LDN) (FZC_PIO + 0x20000UL + (LDN) * 8UL) + +#define XMAC_PORT0_OFF (FZC_MAC + 0x000000) +#define XMAC_PORT1_OFF (FZC_MAC + 0x006000) +#define BMAC_PORT2_OFF (FZC_MAC + 0x00c000) +#define BMAC_PORT3_OFF (FZC_MAC + 0x010000) + +/* XMAC registers, offset from np->mac_regs */ + +#define XTXMAC_SW_RST 0x00000UL +#define XTXMAC_SW_RST_REG_RS 0x0000000000000002ULL +#define XTXMAC_SW_RST_SOFT_RST 0x0000000000000001ULL + +#define XRXMAC_SW_RST 0x00008UL +#define XRXMAC_SW_RST_REG_RS 0x0000000000000002ULL +#define XRXMAC_SW_RST_SOFT_RST 0x0000000000000001ULL + +#define XTXMAC_STATUS 0x00020UL +#define XTXMAC_STATUS_FRAME_CNT_EXP 0x0000000000000800ULL +#define XTXMAC_STATUS_BYTE_CNT_EXP 0x0000000000000400ULL +#define XTXMAC_STATUS_TXFIFO_XFR_ERR 0x0000000000000010ULL +#define XTXMAC_STATUS_TXMAC_OFLOW 0x0000000000000008ULL +#define XTXMAC_STATUS_MAX_PSIZE_ERR 0x0000000000000004ULL +#define XTXMAC_STATUS_TXMAC_UFLOW 0x0000000000000002ULL +#define XTXMAC_STATUS_FRAME_XMITED 0x0000000000000001ULL + +#define XRXMAC_STATUS 0x00028UL +#define XRXMAC_STATUS_RXHIST7_CNT_EXP 0x0000000000100000ULL +#define XRXMAC_STATUS_LCL_FLT_STATUS 0x0000000000080000ULL +#define XRXMAC_STATUS_RFLT_DET 0x0000000000040000ULL +#define XRXMAC_STATUS_LFLT_CNT_EXP 0x0000000000020000ULL +#define XRXMAC_STATUS_PHY_MDINT 0x0000000000010000ULL +#define XRXMAC_STATUS_ALIGNERR_CNT_EXP 0x0000000000010000ULL +#define XRXMAC_STATUS_RXFRAG_CNT_EXP 0x0000000000008000ULL +#define XRXMAC_STATUS_RXMULTF_CNT_EXP 0x0000000000004000ULL +#define XRXMAC_STATUS_RXBCAST_CNT_EXP 0x0000000000002000ULL +#define XRXMAC_STATUS_RXHIST6_CNT_EXP 0x0000000000001000ULL +#define XRXMAC_STATUS_RXHIST5_CNT_EXP 0x0000000000000800ULL +#define XRXMAC_STATUS_RXHIST4_CNT_EXP 0x0000000000000400ULL +#define XRXMAC_STATUS_RXHIST3_CNT_EXP 0x0000000000000200ULL +#define XRXMAC_STATUS_RXHIST2_CNT_EXP 0x0000000000000100ULL +#define XRXMAC_STATUS_RXHIST1_CNT_EXP 0x0000000000000080ULL +#define XRXMAC_STATUS_RXOCTET_CNT_EXP 0x0000000000000040ULL +#define XRXMAC_STATUS_CVIOLERR_CNT_EXP 0x0000000000000020ULL +#define XRXMAC_STATUS_LENERR_CNT_EXP 0x0000000000000010ULL +#define XRXMAC_STATUS_CRCERR_CNT_EXP 0x0000000000000008ULL +#define XRXMAC_STATUS_RXUFLOW 0x0000000000000004ULL +#define XRXMAC_STATUS_RXOFLOW 0x0000000000000002ULL +#define XRXMAC_STATUS_FRAME_RCVD 0x0000000000000001ULL + +#define XMAC_FC_STAT 0x00030UL +#define XMAC_FC_STAT_RX_RCV_PAUSE_TIME 0x00000000ffff0000ULL +#define XMAC_FC_STAT_TX_MAC_NPAUSE 0x0000000000000004ULL +#define XMAC_FC_STAT_TX_MAC_PAUSE 0x0000000000000002ULL +#define XMAC_FC_STAT_RX_MAC_RPAUSE 0x0000000000000001ULL + +#define XTXMAC_STAT_MSK 0x00040UL +#define XTXMAC_STAT_MSK_FRAME_CNT_EXP 0x0000000000000800ULL +#define XTXMAC_STAT_MSK_BYTE_CNT_EXP 0x0000000000000400ULL +#define XTXMAC_STAT_MSK_TXFIFO_XFR_ERR 0x0000000000000010ULL +#define XTXMAC_STAT_MSK_TXMAC_OFLOW 0x0000000000000008ULL +#define XTXMAC_STAT_MSK_MAX_PSIZE_ERR 0x0000000000000004ULL +#define XTXMAC_STAT_MSK_TXMAC_UFLOW 0x0000000000000002ULL +#define XTXMAC_STAT_MSK_FRAME_XMITED 0x0000000000000001ULL + +#define XRXMAC_STAT_MSK 0x00048UL +#define XRXMAC_STAT_MSK_LCL_FLT_STAT_MSK 0x0000000000080000ULL +#define XRXMAC_STAT_MSK_RFLT_DET 0x0000000000040000ULL +#define XRXMAC_STAT_MSK_LFLT_CNT_EXP 0x0000000000020000ULL +#define XRXMAC_STAT_MSK_PHY_MDINT 0x0000000000010000ULL +#define XRXMAC_STAT_MSK_RXFRAG_CNT_EXP 0x0000000000008000ULL +#define XRXMAC_STAT_MSK_RXMULTF_CNT_EXP 0x0000000000004000ULL +#define XRXMAC_STAT_MSK_RXBCAST_CNT_EXP 0x0000000000002000ULL +#define XRXMAC_STAT_MSK_RXHIST6_CNT_EXP 0x0000000000001000ULL +#define XRXMAC_STAT_MSK_RXHIST5_CNT_EXP 0x0000000000000800ULL +#define XRXMAC_STAT_MSK_RXHIST4_CNT_EXP 0x0000000000000400ULL +#define XRXMAC_STAT_MSK_RXHIST3_CNT_EXP 0x0000000000000200ULL +#define XRXMAC_STAT_MSK_RXHIST2_CNT_EXP 0x0000000000000100ULL +#define XRXMAC_STAT_MSK_RXHIST1_CNT_EXP 0x0000000000000080ULL +#define XRXMAC_STAT_MSK_RXOCTET_CNT_EXP 0x0000000000000040ULL +#define XRXMAC_STAT_MSK_CVIOLERR_CNT_EXP 0x0000000000000020ULL +#define XRXMAC_STAT_MSK_LENERR_CNT_EXP 0x0000000000000010ULL +#define XRXMAC_STAT_MSK_CRCERR_CNT_EXP 0x0000000000000008ULL +#define XRXMAC_STAT_MSK_RXUFLOW_CNT_EXP 0x0000000000000004ULL +#define XRXMAC_STAT_MSK_RXOFLOW_CNT_EXP 0x0000000000000002ULL +#define XRXMAC_STAT_MSK_FRAME_RCVD 0x0000000000000001ULL + +#define XMAC_FC_MSK 0x00050UL +#define XMAC_FC_MSK_TX_MAC_NPAUSE 0x0000000000000004ULL +#define XMAC_FC_MSK_TX_MAC_PAUSE 0x0000000000000002ULL +#define XMAC_FC_MSK_RX_MAC_RPAUSE 0x0000000000000001ULL + +#define XMAC_CONFIG 0x00060UL +#define XMAC_CONFIG_SEL_CLK_25MHZ 0x0000000080000000ULL +#define XMAC_CONFIG_1G_PCS_BYPASS 0x0000000040000000ULL +#define XMAC_CONFIG_10G_XPCS_BYPASS 0x0000000020000000ULL +#define XMAC_CONFIG_MODE_MASK 0x0000000018000000ULL +#define XMAC_CONFIG_MODE_XGMII 0x0000000000000000ULL +#define XMAC_CONFIG_MODE_GMII 0x0000000008000000ULL +#define XMAC_CONFIG_MODE_MII 0x0000000010000000ULL +#define XMAC_CONFIG_LFS_DISABLE 0x0000000004000000ULL +#define XMAC_CONFIG_LOOPBACK 0x0000000002000000ULL +#define XMAC_CONFIG_TX_OUTPUT_EN 0x0000000001000000ULL +#define XMAC_CONFIG_SEL_POR_CLK_SRC 0x0000000000800000ULL +#define XMAC_CONFIG_LED_POLARITY 0x0000000000400000ULL +#define XMAC_CONFIG_FORCE_LED_ON 0x0000000000200000ULL +#define XMAC_CONFIG_PASS_FLOW_CTRL 0x0000000000100000ULL +#define XMAC_CONFIG_RCV_PAUSE_ENABLE 0x0000000000080000ULL +#define XMAC_CONFIG_MAC2IPP_PKT_CNT_EN 0x0000000000040000ULL +#define XMAC_CONFIG_STRIP_CRC 0x0000000000020000ULL +#define XMAC_CONFIG_ADDR_FILTER_EN 0x0000000000010000ULL +#define XMAC_CONFIG_HASH_FILTER_EN 0x0000000000008000ULL +#define XMAC_CONFIG_RX_CODEV_CHK_DIS 0x0000000000004000ULL +#define XMAC_CONFIG_RESERVED_MULTICAST 0x0000000000002000ULL +#define XMAC_CONFIG_RX_CRC_CHK_DIS 0x0000000000001000ULL +#define XMAC_CONFIG_ERR_CHK_DIS 0x0000000000000800ULL +#define XMAC_CONFIG_PROMISC_GROUP 0x0000000000000400ULL +#define XMAC_CONFIG_PROMISCUOUS 0x0000000000000200ULL +#define XMAC_CONFIG_RX_MAC_ENABLE 0x0000000000000100ULL +#define XMAC_CONFIG_WARNING_MSG_EN 0x0000000000000080ULL +#define XMAC_CONFIG_ALWAYS_NO_CRC 0x0000000000000008ULL +#define XMAC_CONFIG_VAR_MIN_IPG_EN 0x0000000000000004ULL +#define XMAC_CONFIG_STRETCH_MODE 0x0000000000000002ULL +#define XMAC_CONFIG_TX_ENABLE 0x0000000000000001ULL + +#define XMAC_IPG 0x00080UL +#define XMAC_IPG_STRETCH_CONST 0x0000000000e00000ULL +#define XMAC_IPG_STRETCH_CONST_SHIFT 21 +#define XMAC_IPG_STRETCH_RATIO 0x00000000001f0000ULL +#define XMAC_IPG_STRETCH_RATIO_SHIFT 16 +#define XMAC_IPG_IPG_MII_GMII 0x000000000000ff00ULL +#define XMAC_IPG_IPG_MII_GMII_SHIFT 8 +#define XMAC_IPG_IPG_XGMII 0x0000000000000007ULL +#define XMAC_IPG_IPG_XGMII_SHIFT 0 + +#define IPG_12_15_XGMII 3 +#define IPG_16_19_XGMII 4 +#define IPG_20_23_XGMII 5 +#define IPG_12_MII_GMII 10 +#define IPG_13_MII_GMII 11 +#define IPG_14_MII_GMII 12 +#define IPG_15_MII_GMII 13 +#define IPG_16_MII_GMII 14 + +#define XMAC_MIN 0x00088UL +#define XMAC_MIN_RX_MIN_PKT_SIZE 0x000000003ff00000ULL +#define XMAC_MIN_RX_MIN_PKT_SIZE_SHFT 20 +#define XMAC_MIN_SLOT_TIME 0x000000000003fc00ULL +#define XMAC_MIN_SLOT_TIME_SHFT 10 +#define XMAC_MIN_TX_MIN_PKT_SIZE 0x00000000000003ffULL +#define XMAC_MIN_TX_MIN_PKT_SIZE_SHFT 0 + +#define XMAC_MAX 0x00090UL +#define XMAC_MAX_FRAME_SIZE 0x0000000000003fffULL +#define XMAC_MAX_FRAME_SIZE_SHFT 0 + +#define XMAC_ADDR0 0x000a0UL +#define XMAC_ADDR0_ADDR0 0x000000000000ffffULL + +#define XMAC_ADDR1 0x000a8UL +#define XMAC_ADDR1_ADDR1 0x000000000000ffffULL + +#define XMAC_ADDR2 0x000b0UL +#define XMAC_ADDR2_ADDR2 0x000000000000ffffULL + +#define XMAC_ADDR_CMPEN 0x00208UL +#define XMAC_ADDR_CMPEN_EN15 0x0000000000008000ULL +#define XMAC_ADDR_CMPEN_EN14 0x0000000000004000ULL +#define XMAC_ADDR_CMPEN_EN13 0x0000000000002000ULL +#define XMAC_ADDR_CMPEN_EN12 0x0000000000001000ULL +#define XMAC_ADDR_CMPEN_EN11 0x0000000000000800ULL +#define XMAC_ADDR_CMPEN_EN10 0x0000000000000400ULL +#define XMAC_ADDR_CMPEN_EN9 0x0000000000000200ULL +#define XMAC_ADDR_CMPEN_EN8 0x0000000000000100ULL +#define XMAC_ADDR_CMPEN_EN7 0x0000000000000080ULL +#define XMAC_ADDR_CMPEN_EN6 0x0000000000000040ULL +#define XMAC_ADDR_CMPEN_EN5 0x0000000000000020ULL +#define XMAC_ADDR_CMPEN_EN4 0x0000000000000010ULL +#define XMAC_ADDR_CMPEN_EN3 0x0000000000000008ULL +#define XMAC_ADDR_CMPEN_EN2 0x0000000000000004ULL +#define XMAC_ADDR_CMPEN_EN1 0x0000000000000002ULL +#define XMAC_ADDR_CMPEN_EN0 0x0000000000000001ULL + +#define XMAC_NUM_ALT_ADDR 16 + +#define XMAC_ALT_ADDR0(NUM) (0x00218UL + (NUM)*0x18UL) +#define XMAC_ALT_ADDR0_ADDR0 0x000000000000ffffULL + +#define XMAC_ALT_ADDR1(NUM) (0x00220UL + (NUM)*0x18UL) +#define XMAC_ALT_ADDR1_ADDR1 0x000000000000ffffULL + +#define XMAC_ALT_ADDR2(NUM) (0x00228UL + (NUM)*0x18UL) +#define XMAC_ALT_ADDR2_ADDR2 0x000000000000ffffULL + +#define XMAC_ADD_FILT0 0x00818UL +#define XMAC_ADD_FILT0_FILT0 0x000000000000ffffULL + +#define XMAC_ADD_FILT1 0x00820UL +#define XMAC_ADD_FILT1_FILT1 0x000000000000ffffULL + +#define XMAC_ADD_FILT2 0x00828UL +#define XMAC_ADD_FILT2_FILT2 0x000000000000ffffULL + +#define XMAC_ADD_FILT12_MASK 0x00830UL +#define XMAC_ADD_FILT12_MASK_VAL 0x00000000000000ffULL + +#define XMAC_ADD_FILT00_MASK 0x00838UL +#define XMAC_ADD_FILT00_MASK_VAL 0x000000000000ffffULL + +#define XMAC_HASH_TBL(NUM) (0x00840UL + (NUM) * 0x8UL) +#define XMAC_HASH_TBL_VAL 0x000000000000ffffULL + +#define XMAC_NUM_HOST_INFO 20 + +#define XMAC_HOST_INFO(NUM) (0x00900UL + (NUM) * 0x8UL) + +#define XMAC_PA_DATA0 0x00b80UL +#define XMAC_PA_DATA0_VAL 0x00000000ffffffffULL + +#define XMAC_PA_DATA1 0x00b88UL +#define XMAC_PA_DATA1_VAL 0x00000000ffffffffULL + +#define XMAC_DEBUG_SEL 0x00b90UL +#define XMAC_DEBUG_SEL_XMAC 0x0000000000000078ULL +#define XMAC_DEBUG_SEL_MAC 0x0000000000000007ULL + +#define XMAC_TRAIN_VEC 0x00b98UL +#define XMAC_TRAIN_VEC_VAL 0x00000000ffffffffULL + +#define RXMAC_BT_CNT 0x00100UL +#define RXMAC_BT_CNT_COUNT 0x00000000ffffffffULL + +#define RXMAC_BC_FRM_CNT 0x00108UL +#define RXMAC_BC_FRM_CNT_COUNT 0x00000000001fffffULL + +#define RXMAC_MC_FRM_CNT 0x00110UL +#define RXMAC_MC_FRM_CNT_COUNT 0x00000000001fffffULL + +#define RXMAC_FRAG_CNT 0x00118UL +#define RXMAC_FRAG_CNT_COUNT 0x00000000001fffffULL + +#define RXMAC_HIST_CNT1 0x00120UL +#define RXMAC_HIST_CNT1_COUNT 0x00000000001fffffULL + +#define RXMAC_HIST_CNT2 0x00128UL +#define RXMAC_HIST_CNT2_COUNT 0x00000000001fffffULL + +#define RXMAC_HIST_CNT3 0x00130UL +#define RXMAC_HIST_CNT3_COUNT 0x00000000000fffffULL + +#define RXMAC_HIST_CNT4 0x00138UL +#define RXMAC_HIST_CNT4_COUNT 0x000000000007ffffULL + +#define RXMAC_HIST_CNT5 0x00140UL +#define RXMAC_HIST_CNT5_COUNT 0x000000000003ffffULL + +#define RXMAC_HIST_CNT6 0x00148UL +#define RXMAC_HIST_CNT6_COUNT 0x000000000000ffffULL + +#define RXMAC_MPSZER_CNT 0x00150UL +#define RXMAC_MPSZER_CNT_COUNT 0x00000000000000ffULL + +#define RXMAC_CRC_ER_CNT 0x00158UL +#define RXMAC_CRC_ER_CNT_COUNT 0x00000000000000ffULL + +#define RXMAC_CD_VIO_CNT 0x00160UL +#define RXMAC_CD_VIO_CNT_COUNT 0x00000000000000ffULL + +#define RXMAC_ALIGN_ERR_CNT 0x00168UL +#define RXMAC_ALIGN_ERR_CNT_COUNT 0x00000000000000ffULL + +#define TXMAC_FRM_CNT 0x00170UL +#define TXMAC_FRM_CNT_COUNT 0x00000000ffffffffULL + +#define TXMAC_BYTE_CNT 0x00178UL +#define TXMAC_BYTE_CNT_COUNT 0x00000000ffffffffULL + +#define LINK_FAULT_CNT 0x00180UL +#define LINK_FAULT_CNT_COUNT 0x00000000000000ffULL + +#define RXMAC_HIST_CNT7 0x00188UL +#define RXMAC_HIST_CNT7_COUNT 0x0000000007ffffffULL + +#define XMAC_SM_REG 0x001a8UL +#define XMAC_SM_REG_STATE 0x00000000ffffffffULL + +#define XMAC_INTER1 0x001b0UL +#define XMAC_INTERN1_SIGNALS1 0x00000000ffffffffULL + +#define XMAC_INTER2 0x001b8UL +#define XMAC_INTERN2_SIGNALS2 0x00000000ffffffffULL + +/* BMAC registers, offset from np->mac_regs */ + +#define BTXMAC_SW_RST 0x00000UL +#define BTXMAC_SW_RST_RESET 0x0000000000000001ULL + +#define BRXMAC_SW_RST 0x00008UL +#define BRXMAC_SW_RST_RESET 0x0000000000000001ULL + +#define BMAC_SEND_PAUSE 0x00010UL +#define BMAC_SEND_PAUSE_SEND 0x0000000000010000ULL +#define BMAC_SEND_PAUSE_TIME 0x000000000000ffffULL + +#define BTXMAC_STATUS 0x00020UL +#define BTXMAC_STATUS_XMIT 0x0000000000000001ULL +#define BTXMAC_STATUS_UNDERRUN 0x0000000000000002ULL +#define BTXMAC_STATUS_MAX_PKT_ERR 0x0000000000000004ULL +#define BTXMAC_STATUS_BYTE_CNT_EXP 0x0000000000000400ULL +#define BTXMAC_STATUS_FRAME_CNT_EXP 0x0000000000000800ULL + +#define BRXMAC_STATUS 0x00028UL +#define BRXMAC_STATUS_RX_PKT 0x0000000000000001ULL +#define BRXMAC_STATUS_OVERFLOW 0x0000000000000002ULL +#define BRXMAC_STATUS_FRAME_CNT_EXP 0x0000000000000004ULL +#define BRXMAC_STATUS_ALIGN_ERR_EXP 0x0000000000000008ULL +#define BRXMAC_STATUS_CRC_ERR_EXP 0x0000000000000010ULL +#define BRXMAC_STATUS_LEN_ERR_EXP 0x0000000000000020ULL + +#define BMAC_CTRL_STATUS 0x00030UL +#define BMAC_CTRL_STATUS_PAUSE_RECV 0x0000000000000001ULL +#define BMAC_CTRL_STATUS_PAUSE 0x0000000000000002ULL +#define BMAC_CTRL_STATUS_NOPAUSE 0x0000000000000004ULL +#define BMAC_CTRL_STATUS_TIME 0x00000000ffff0000ULL +#define BMAC_CTRL_STATUS_TIME_SHIFT 16 + +#define BTXMAC_STATUS_MASK 0x00040UL +#define BRXMAC_STATUS_MASK 0x00048UL +#define BMAC_CTRL_STATUS_MASK 0x00050UL + +#define BTXMAC_CONFIG 0x00060UL +#define BTXMAC_CONFIG_ENABLE 0x0000000000000001ULL +#define BTXMAC_CONFIG_FCS_DISABLE 0x0000000000000002ULL + +#define BRXMAC_CONFIG 0x00068UL +#define BRXMAC_CONFIG_DISCARD_DIS 0x0000000000000080ULL +#define BRXMAC_CONFIG_ADDR_FILT_EN 0x0000000000000040ULL +#define BRXMAC_CONFIG_HASH_FILT_EN 0x0000000000000020ULL +#define BRXMAC_CONFIG_PROMISC_GRP 0x0000000000000010ULL +#define BRXMAC_CONFIG_PROMISC 0x0000000000000008ULL +#define BRXMAC_CONFIG_STRIP_FCS 0x0000000000000004ULL +#define BRXMAC_CONFIG_STRIP_PAD 0x0000000000000002ULL +#define BRXMAC_CONFIG_ENABLE 0x0000000000000001ULL + +#define BMAC_CTRL_CONFIG 0x00070UL +#define BMAC_CTRL_CONFIG_TX_PAUSE_EN 0x0000000000000001ULL +#define BMAC_CTRL_CONFIG_RX_PAUSE_EN 0x0000000000000002ULL +#define BMAC_CTRL_CONFIG_PASS_CTRL 0x0000000000000004ULL + +#define BMAC_XIF_CONFIG 0x00078UL +#define BMAC_XIF_CONFIG_TX_OUTPUT_EN 0x0000000000000001ULL +#define BMAC_XIF_CONFIG_MII_LOOPBACK 0x0000000000000002ULL +#define BMAC_XIF_CONFIG_GMII_MODE 0x0000000000000008ULL +#define BMAC_XIF_CONFIG_LINK_LED 0x0000000000000020ULL +#define BMAC_XIF_CONFIG_LED_POLARITY 0x0000000000000040ULL +#define BMAC_XIF_CONFIG_25MHZ_CLOCK 0x0000000000000080ULL + +#define BMAC_MIN_FRAME 0x000a0UL +#define BMAC_MIN_FRAME_VAL 0x00000000000003ffULL + +#define BMAC_MAX_FRAME 0x000a8UL +#define BMAC_MAX_FRAME_MAX_BURST 0x000000003fff0000ULL +#define BMAC_MAX_FRAME_MAX_BURST_SHIFT 16 +#define BMAC_MAX_FRAME_MAX_FRAME 0x0000000000003fffULL +#define BMAC_MAX_FRAME_MAX_FRAME_SHIFT 0 + +#define BMAC_PREAMBLE_SIZE 0x000b0UL +#define BMAC_PREAMBLE_SIZE_VAL 0x00000000000003ffULL + +#define BMAC_CTRL_TYPE 0x000c8UL + +#define BMAC_ADDR0 0x00100UL +#define BMAC_ADDR0_ADDR0 0x000000000000ffffULL + +#define BMAC_ADDR1 0x00108UL +#define BMAC_ADDR1_ADDR1 0x000000000000ffffULL + +#define BMAC_ADDR2 0x00110UL +#define BMAC_ADDR2_ADDR2 0x000000000000ffffULL + +#define BMAC_NUM_ALT_ADDR 7 + +#define BMAC_ALT_ADDR0(NUM) (0x00118UL + (NUM)*0x18UL) +#define BMAC_ALT_ADDR0_ADDR0 0x000000000000ffffULL + +#define BMAC_ALT_ADDR1(NUM) (0x00120UL + (NUM)*0x18UL) +#define BMAC_ALT_ADDR1_ADDR1 0x000000000000ffffULL + +#define BMAC_ALT_ADDR2(NUM) (0x00128UL + (NUM)*0x18UL) +#define BMAC_ALT_ADDR2_ADDR2 0x000000000000ffffULL + +#define BMAC_FC_ADDR0 0x00268UL +#define BMAC_FC_ADDR0_ADDR0 0x000000000000ffffULL + +#define BMAC_FC_ADDR1 0x00270UL +#define BMAC_FC_ADDR1_ADDR1 0x000000000000ffffULL + +#define BMAC_FC_ADDR2 0x00278UL +#define BMAC_FC_ADDR2_ADDR2 0x000000000000ffffULL + +#define BMAC_ADD_FILT0 0x00298UL +#define BMAC_ADD_FILT0_FILT0 0x000000000000ffffULL + +#define BMAC_ADD_FILT1 0x002a0UL +#define BMAC_ADD_FILT1_FILT1 0x000000000000ffffULL + +#define BMAC_ADD_FILT2 0x002a8UL +#define BMAC_ADD_FILT2_FILT2 0x000000000000ffffULL + +#define BMAC_ADD_FILT12_MASK 0x002b0UL +#define BMAC_ADD_FILT12_MASK_VAL 0x00000000000000ffULL + +#define BMAC_ADD_FILT00_MASK 0x002b8UL +#define BMAC_ADD_FILT00_MASK_VAL 0x000000000000ffffULL + +#define BMAC_HASH_TBL(NUM) (0x002c0UL + (NUM) * 0x8UL) +#define BMAC_HASH_TBL_VAL 0x000000000000ffffULL + +#define BRXMAC_FRAME_CNT 0x00370 +#define BRXMAC_FRAME_CNT_COUNT 0x000000000000ffffULL + +#define BRXMAC_MAX_LEN_ERR_CNT 0x00378 + +#define BRXMAC_ALIGN_ERR_CNT 0x00380 +#define BRXMAC_ALIGN_ERR_CNT_COUNT 0x000000000000ffffULL + +#define BRXMAC_CRC_ERR_CNT 0x00388 +#define BRXMAC_ALIGN_ERR_CNT_COUNT 0x000000000000ffffULL + +#define BRXMAC_CODE_VIOL_ERR_CNT 0x00390 +#define BRXMAC_CODE_VIOL_ERR_CNT_COUNT 0x000000000000ffffULL + +#define BMAC_STATE_MACHINE 0x003a0 + +#define BMAC_ADDR_CMPEN 0x003f8UL +#define BMAC_ADDR_CMPEN_EN15 0x0000000000008000ULL +#define BMAC_ADDR_CMPEN_EN14 0x0000000000004000ULL +#define BMAC_ADDR_CMPEN_EN13 0x0000000000002000ULL +#define BMAC_ADDR_CMPEN_EN12 0x0000000000001000ULL +#define BMAC_ADDR_CMPEN_EN11 0x0000000000000800ULL +#define BMAC_ADDR_CMPEN_EN10 0x0000000000000400ULL +#define BMAC_ADDR_CMPEN_EN9 0x0000000000000200ULL +#define BMAC_ADDR_CMPEN_EN8 0x0000000000000100ULL +#define BMAC_ADDR_CMPEN_EN7 0x0000000000000080ULL +#define BMAC_ADDR_CMPEN_EN6 0x0000000000000040ULL +#define BMAC_ADDR_CMPEN_EN5 0x0000000000000020ULL +#define BMAC_ADDR_CMPEN_EN4 0x0000000000000010ULL +#define BMAC_ADDR_CMPEN_EN3 0x0000000000000008ULL +#define BMAC_ADDR_CMPEN_EN2 0x0000000000000004ULL +#define BMAC_ADDR_CMPEN_EN1 0x0000000000000002ULL +#define BMAC_ADDR_CMPEN_EN0 0x0000000000000001ULL + +#define BMAC_NUM_HOST_INFO 9 + +#define BMAC_HOST_INFO(NUM) (0x00400UL + (NUM) * 0x8UL) + +#define BTXMAC_BYTE_CNT 0x00448UL +#define BTXMAC_BYTE_CNT_COUNT 0x00000000ffffffffULL + +#define BTXMAC_FRM_CNT 0x00450UL +#define BTXMAC_FRM_CNT_COUNT 0x00000000ffffffffULL + +#define BRXMAC_BYTE_CNT 0x00458UL +#define BRXMAC_BYTE_CNT_COUNT 0x00000000ffffffffULL + +#define HOST_INFO_MPR 0x0000000000000100ULL +#define HOST_INFO_MACRDCTBLN 0x0000000000000007ULL + +/* XPCS registers, offset from np->regs + np->xpcs_off */ + +#define XPCS_CONTROL1 (FZC_MAC + 0x00000UL) +#define XPCS_CONTROL1_RESET 0x0000000000008000ULL +#define XPCS_CONTROL1_LOOPBACK 0x0000000000004000ULL +#define XPCS_CONTROL1_SPEED_SELECT3 0x0000000000002000ULL +#define XPCS_CONTROL1_CSR_LOW_PWR 0x0000000000000800ULL +#define XPCS_CONTROL1_CSR_SPEED1 0x0000000000000040ULL +#define XPCS_CONTROL1_CSR_SPEED0 0x000000000000003cULL + +#define XPCS_STATUS1 (FZC_MAC + 0x00008UL) +#define XPCS_STATUS1_CSR_FAULT 0x0000000000000080ULL +#define XPCS_STATUS1_CSR_RXLNK_STAT 0x0000000000000004ULL +#define XPCS_STATUS1_CSR_LPWR_ABLE 0x0000000000000002ULL + +#define XPCS_DEVICE_IDENTIFIER (FZC_MAC + 0x00010UL) +#define XPCS_DEVICE_IDENTIFIER_VAL 0x00000000ffffffffULL + +#define XPCS_SPEED_ABILITY (FZC_MAC + 0x00018UL) +#define XPCS_SPEED_ABILITY_10GIG 0x0000000000000001ULL + +#define XPCS_DEV_IN_PKG (FZC_MAC + 0x00020UL) +#define XPCS_DEV_IN_PKG_CSR_VEND2 0x0000000080000000ULL +#define XPCS_DEV_IN_PKG_CSR_VEND1 0x0000000040000000ULL +#define XPCS_DEV_IN_PKG_DTE_XS 0x0000000000000020ULL +#define XPCS_DEV_IN_PKG_PHY_XS 0x0000000000000010ULL +#define XPCS_DEV_IN_PKG_PCS 0x0000000000000008ULL +#define XPCS_DEV_IN_PKG_WIS 0x0000000000000004ULL +#define XPCS_DEV_IN_PKG_PMD_PMA 0x0000000000000002ULL +#define XPCS_DEV_IN_PKG_CLS22 0x0000000000000001ULL + +#define XPCS_CONTROL2 (FZC_MAC + 0x00028UL) +#define XPCS_CONTROL2_CSR_PSC_SEL 0x0000000000000003ULL + +#define XPCS_STATUS2 (FZC_MAC + 0x00030UL) +#define XPCS_STATUS2_CSR_DEV_PRES 0x000000000000c000ULL +#define XPCS_STATUS2_CSR_TX_FAULT 0x0000000000000800ULL +#define XPCS_STATUS2_CSR_RCV_FAULT 0x0000000000000400ULL +#define XPCS_STATUS2_TEN_GBASE_W 0x0000000000000004ULL +#define XPCS_STATUS2_TEN_GBASE_X 0x0000000000000002ULL +#define XPCS_STATUS2_TEN_GBASE_R 0x0000000000000001ULL + +#define XPCS_PKG_ID (FZC_MAC + 0x00038UL) +#define XPCS_PKG_ID_VAL 0x00000000ffffffffULL + +#define XPCS_STATUS(IDX) (FZC_MAC + 0x00040UL) +#define XPCS_STATUS_CSR_LANE_ALIGN 0x0000000000001000ULL +#define XPCS_STATUS_CSR_PATTEST_CAP 0x0000000000000800ULL +#define XPCS_STATUS_CSR_LANE3_SYNC 0x0000000000000008ULL +#define XPCS_STATUS_CSR_LANE2_SYNC 0x0000000000000004ULL +#define XPCS_STATUS_CSR_LANE1_SYNC 0x0000000000000002ULL +#define XPCS_STATUS_CSR_LANE0_SYNC 0x0000000000000001ULL + +#define XPCS_TEST_CONTROL (FZC_MAC + 0x00048UL) +#define XPCS_TEST_CONTROL_TXTST_EN 0x0000000000000004ULL +#define XPCS_TEST_CONTROL_TPAT_SEL 0x0000000000000003ULL + +#define XPCS_CFG_VENDOR1 (FZC_MAC + 0x00050UL) +#define XPCS_CFG_VENDOR1_DBG_IOTST 0x0000000000000080ULL +#define XPCS_CFG_VENDOR1_DBG_SEL 0x0000000000000078ULL +#define XPCS_CFG_VENDOR1_BYPASS_DET 0x0000000000000004ULL +#define XPCS_CFG_VENDOR1_TXBUF_EN 0x0000000000000002ULL +#define XPCS_CFG_VENDOR1_XPCS_EN 0x0000000000000001ULL + +#define XPCS_DIAG_VENDOR2 (FZC_MAC + 0x00058UL) +#define XPCS_DIAG_VENDOR2_SSM_LANE3 0x0000000001e00000ULL +#define XPCS_DIAG_VENDOR2_SSM_LANE2 0x00000000001e0000ULL +#define XPCS_DIAG_VENDOR2_SSM_LANE1 0x000000000001e000ULL +#define XPCS_DIAG_VENDOR2_SSM_LANE0 0x0000000000001e00ULL +#define XPCS_DIAG_VENDOR2_EBUF_SM 0x00000000000001feULL +#define XPCS_DIAG_VENDOR2_RCV_SM 0x0000000000000001ULL + +#define XPCS_MASK1 (FZC_MAC + 0x00060UL) +#define XPCS_MASK1_FAULT_MASK 0x0000000000000080ULL +#define XPCS_MASK1_RXALIGN_STAT_MSK 0x0000000000000004ULL + +#define XPCS_PKT_COUNT (FZC_MAC + 0x00068UL) +#define XPCS_PKT_COUNT_TX 0x00000000ffff0000ULL +#define XPCS_PKT_COUNT_RX 0x000000000000ffffULL + +#define XPCS_TX_SM (FZC_MAC + 0x00070UL) +#define XPCS_TX_SM_VAL 0x000000000000000fULL + +#define XPCS_DESKEW_ERR_CNT (FZC_MAC + 0x00078UL) +#define XPCS_DESKEW_ERR_CNT_VAL 0x00000000000000ffULL + +#define XPCS_SYMERR_CNT01 (FZC_MAC + 0x00080UL) +#define XPCS_SYMERR_CNT01_LANE1 0x00000000ffff0000ULL +#define XPCS_SYMERR_CNT01_LANE0 0x000000000000ffffULL + +#define XPCS_SYMERR_CNT23 (FZC_MAC + 0x00088UL) +#define XPCS_SYMERR_CNT23_LANE3 0x00000000ffff0000ULL +#define XPCS_SYMERR_CNT23_LANE2 0x000000000000ffffULL + +#define XPCS_TRAINING_VECTOR (FZC_MAC + 0x00090UL) +#define XPCS_TRAINING_VECTOR_VAL 0x00000000ffffffffULL + +/* PCS registers, offset from np->regs + np->pcs_off */ + +#define PCS_MII_CTL (FZC_MAC + 0x00000UL) +#define PCS_MII_CTL_RST 0x0000000000008000ULL +#define PCS_MII_CTL_10_100_SPEED 0x0000000000002000ULL +#define PCS_MII_AUTONEG_EN 0x0000000000001000ULL +#define PCS_MII_PWR_DOWN 0x0000000000000800ULL +#define PCS_MII_ISOLATE 0x0000000000000400ULL +#define PCS_MII_AUTONEG_RESTART 0x0000000000000200ULL +#define PCS_MII_DUPLEX 0x0000000000000100ULL +#define PCS_MII_COLL_TEST 0x0000000000000080ULL +#define PCS_MII_1000MB_SPEED 0x0000000000000040ULL + +#define PCS_MII_STAT (FZC_MAC + 0x00008UL) +#define PCS_MII_STAT_EXT_STATUS 0x0000000000000100ULL +#define PCS_MII_STAT_AUTONEG_DONE 0x0000000000000020ULL +#define PCS_MII_STAT_REMOTE_FAULT 0x0000000000000010ULL +#define PCS_MII_STAT_AUTONEG_ABLE 0x0000000000000008ULL +#define PCS_MII_STAT_LINK_STATUS 0x0000000000000004ULL +#define PCS_MII_STAT_JABBER_DET 0x0000000000000002ULL +#define PCS_MII_STAT_EXT_CAP 0x0000000000000001ULL + +#define PCS_MII_ADV (FZC_MAC + 0x00010UL) +#define PCS_MII_ADV_NEXT_PAGE 0x0000000000008000ULL +#define PCS_MII_ADV_ACK 0x0000000000004000ULL +#define PCS_MII_ADV_REMOTE_FAULT 0x0000000000003000ULL +#define PCS_MII_ADV_ASM_DIR 0x0000000000000100ULL +#define PCS_MII_ADV_PAUSE 0x0000000000000080ULL +#define PCS_MII_ADV_HALF_DUPLEX 0x0000000000000040ULL +#define PCS_MII_ADV_FULL_DUPLEX 0x0000000000000020ULL + +#define PCS_MII_PARTNER (FZC_MAC + 0x00018UL) +#define PCS_MII_PARTNER_NEXT_PAGE 0x0000000000008000ULL +#define PCS_MII_PARTNER_ACK 0x0000000000004000ULL +#define PCS_MII_PARTNER_REMOTE_FAULT 0x0000000000002000ULL +#define PCS_MII_PARTNER_PAUSE 0x0000000000000180ULL +#define PCS_MII_PARTNER_HALF_DUPLEX 0x0000000000000040ULL +#define PCS_MII_PARTNER_FULL_DUPLEX 0x0000000000000020ULL + +#define PCS_CONF (FZC_MAC + 0x00020UL) +#define PCS_CONF_MASK 0x0000000000000040ULL +#define PCS_CONF_10MS_TMR_OVERRIDE 0x0000000000000020ULL +#define PCS_CONF_JITTER_STUDY 0x0000000000000018ULL +#define PCS_CONF_SIGDET_ACTIVE_LOW 0x0000000000000004ULL +#define PCS_CONF_SIGDET_OVERRIDE 0x0000000000000002ULL +#define PCS_CONF_ENABLE 0x0000000000000001ULL + +#define PCS_STATE (FZC_MAC + 0x00028UL) +#define PCS_STATE_D_PARTNER_FAIL 0x0000000020000000ULL +#define PCS_STATE_D_WAIT_C_CODES_ACK 0x0000000010000000ULL +#define PCS_STATE_D_SYNC_LOSS 0x0000000008000000ULL +#define PCS_STATE_D_NO_GOOD_C_CODES 0x0000000004000000ULL +#define PCS_STATE_D_SERDES 0x0000000002000000ULL +#define PCS_STATE_D_BREAKLINK_C_CODES 0x0000000001000000ULL +#define PCS_STATE_L_SIGDET 0x0000000000400000ULL +#define PCS_STATE_L_SYNC_LOSS 0x0000000000200000ULL +#define PCS_STATE_L_C_CODES 0x0000000000100000ULL +#define PCS_STATE_LINK_CFG_STATE 0x000000000001e000ULL +#define PCS_STATE_SEQ_DET_STATE 0x0000000000001800ULL +#define PCS_STATE_WORD_SYNC_STATE 0x0000000000000700ULL +#define PCS_STATE_NO_IDLE 0x000000000000000fULL + +#define PCS_INTERRUPT (FZC_MAC + 0x00030UL) +#define PCS_INTERRUPT_LSTATUS 0x0000000000000004ULL + +#define PCS_DPATH_MODE (FZC_MAC + 0x000a0UL) +#define PCS_DPATH_MODE_PCS 0x0000000000000000ULL +#define PCS_DPATH_MODE_MII 0x0000000000000002ULL +#define PCS_DPATH_MODE_LINKUP_F_ENAB 0x0000000000000001ULL + +#define PCS_PKT_CNT (FZC_MAC + 0x000c0UL) +#define PCS_PKT_CNT_RX 0x0000000007ff0000ULL +#define PCS_PKT_CNT_TX 0x00000000000007ffULL + +#define MIF_BB_MDC (FZC_MAC + 0x16000UL) +#define MIF_BB_MDC_CLK 0x0000000000000001ULL + +#define MIF_BB_MDO (FZC_MAC + 0x16008UL) +#define MIF_BB_MDO_DAT 0x0000000000000001ULL + +#define MIF_BB_MDO_EN (FZC_MAC + 0x16010UL) +#define MIF_BB_MDO_EN_VAL 0x0000000000000001ULL + +#define MIF_FRAME_OUTPUT (FZC_MAC + 0x16018UL) +#define MIF_FRAME_OUTPUT_ST 0x00000000c0000000ULL +#define MIF_FRAME_OUTPUT_ST_SHIFT 30 +#define MIF_FRAME_OUTPUT_OP_ADDR 0x0000000000000000ULL +#define MIF_FRAME_OUTPUT_OP_WRITE 0x0000000010000000ULL +#define MIF_FRAME_OUTPUT_OP_READ_INC 0x0000000020000000ULL +#define MIF_FRAME_OUTPUT_OP_READ 0x0000000030000000ULL +#define MIF_FRAME_OUTPUT_OP_SHIFT 28 +#define MIF_FRAME_OUTPUT_PORT 0x000000000f800000ULL +#define MIF_FRAME_OUTPUT_PORT_SHIFT 23 +#define MIF_FRAME_OUTPUT_REG 0x00000000007c0000ULL +#define MIF_FRAME_OUTPUT_REG_SHIFT 18 +#define MIF_FRAME_OUTPUT_TA 0x0000000000030000ULL +#define MIF_FRAME_OUTPUT_TA_SHIFT 16 +#define MIF_FRAME_OUTPUT_DATA 0x000000000000ffffULL +#define MIF_FRAME_OUTPUT_DATA_SHIFT 0 + +#define MDIO_ADDR_OP(port, dev, reg) \ + ((0 << MIF_FRAME_OUTPUT_ST_SHIFT) | \ + MIF_FRAME_OUTPUT_OP_ADDR | \ + (port << MIF_FRAME_OUTPUT_PORT_SHIFT) | \ + (dev << MIF_FRAME_OUTPUT_REG_SHIFT) | \ + (0x2 << MIF_FRAME_OUTPUT_TA_SHIFT) | \ + (reg << MIF_FRAME_OUTPUT_DATA_SHIFT)) + +#define MDIO_READ_OP(port, dev) \ + ((0 << MIF_FRAME_OUTPUT_ST_SHIFT) | \ + MIF_FRAME_OUTPUT_OP_READ | \ + (port << MIF_FRAME_OUTPUT_PORT_SHIFT) | \ + (dev << MIF_FRAME_OUTPUT_REG_SHIFT) | \ + (0x2 << MIF_FRAME_OUTPUT_TA_SHIFT)) + +#define MDIO_WRITE_OP(port, dev, data) \ + ((0 << MIF_FRAME_OUTPUT_ST_SHIFT) | \ + MIF_FRAME_OUTPUT_OP_WRITE | \ + (port << MIF_FRAME_OUTPUT_PORT_SHIFT) | \ + (dev << MIF_FRAME_OUTPUT_REG_SHIFT) | \ + (0x2 << MIF_FRAME_OUTPUT_TA_SHIFT) | \ + (data << MIF_FRAME_OUTPUT_DATA_SHIFT)) + +#define MII_READ_OP(port, reg) \ + ((1 << MIF_FRAME_OUTPUT_ST_SHIFT) | \ + (2 << MIF_FRAME_OUTPUT_OP_SHIFT) | \ + (port << MIF_FRAME_OUTPUT_PORT_SHIFT) | \ + (reg << MIF_FRAME_OUTPUT_REG_SHIFT) | \ + (0x2 << MIF_FRAME_OUTPUT_TA_SHIFT)) + +#define MII_WRITE_OP(port, reg, data) \ + ((1 << MIF_FRAME_OUTPUT_ST_SHIFT) | \ + (1 << MIF_FRAME_OUTPUT_OP_SHIFT) | \ + (port << MIF_FRAME_OUTPUT_PORT_SHIFT) | \ + (reg << MIF_FRAME_OUTPUT_REG_SHIFT) | \ + (0x2 << MIF_FRAME_OUTPUT_TA_SHIFT) | \ + (data << MIF_FRAME_OUTPUT_DATA_SHIFT)) + +#define MIF_CONFIG (FZC_MAC + 0x16020UL) +#define MIF_CONFIG_ATCA_GE 0x0000000000010000ULL +#define MIF_CONFIG_INDIRECT_MODE 0x0000000000008000ULL +#define MIF_CONFIG_POLL_PRT_PHYADDR 0x0000000000003c00ULL +#define MIF_CONFIG_POLL_DEV_REG_ADDR 0x00000000000003e0ULL +#define MIF_CONFIG_BB_MODE 0x0000000000000010ULL +#define MIF_CONFIG_POLL_EN 0x0000000000000008ULL +#define MIF_CONFIG_BB_SER_SEL 0x0000000000000006ULL +#define MIF_CONFIG_MANUAL_MODE 0x0000000000000001ULL + +#define MIF_POLL_STATUS (FZC_MAC + 0x16028UL) +#define MIF_POLL_STATUS_DATA 0x00000000ffff0000ULL +#define MIF_POLL_STATUS_STAT 0x000000000000ffffULL + +#define MIF_POLL_MASK (FZC_MAC + 0x16030UL) +#define MIF_POLL_MASK_VAL 0x000000000000ffffULL + +#define MIF_SM (FZC_MAC + 0x16038UL) +#define MIF_SM_PORT_ADDR 0x00000000001f0000ULL +#define MIF_SM_MDI_1 0x0000000000004000ULL +#define MIF_SM_MDI_0 0x0000000000002400ULL +#define MIF_SM_MDCLK 0x0000000000001000ULL +#define MIF_SM_MDO_EN 0x0000000000000800ULL +#define MIF_SM_MDO 0x0000000000000400ULL +#define MIF_SM_MDI 0x0000000000000200ULL +#define MIF_SM_CTL 0x00000000000001c0ULL +#define MIF_SM_EX 0x000000000000003fULL + +#define MIF_STATUS (FZC_MAC + 0x16040UL) +#define MIF_STATUS_MDINT1 0x0000000000000020ULL +#define MIF_STATUS_MDINT0 0x0000000000000010ULL + +#define MIF_MASK (FZC_MAC + 0x16048UL) +#define MIF_MASK_MDINT1 0x0000000000000020ULL +#define MIF_MASK_MDINT0 0x0000000000000010ULL +#define MIF_MASK_PEU_ERR 0x0000000000000008ULL +#define MIF_MASK_YC 0x0000000000000004ULL +#define MIF_MASK_XGE_ERR0 0x0000000000000002ULL +#define MIF_MASK_MIF_INIT_DONE 0x0000000000000001ULL + +#define ENET_SERDES_RESET (FZC_MAC + 0x14000UL) +#define ENET_SERDES_RESET_1 0x0000000000000002ULL +#define ENET_SERDES_RESET_0 0x0000000000000001ULL + +#define ENET_SERDES_CFG (FZC_MAC + 0x14008UL) +#define ENET_SERDES_BE_LOOPBACK 0x0000000000000002ULL +#define ENET_SERDES_CFG_FORCE_RDY 0x0000000000000001ULL + +#define ENET_SERDES_0_PLL_CFG (FZC_MAC + 0x14010UL) +#define ENET_SERDES_PLL_FBDIV0 0x0000000000000001ULL +#define ENET_SERDES_PLL_FBDIV1 0x0000000000000002ULL +#define ENET_SERDES_PLL_FBDIV2 0x0000000000000004ULL +#define ENET_SERDES_PLL_HRATE0 0x0000000000000008ULL +#define ENET_SERDES_PLL_HRATE1 0x0000000000000010ULL +#define ENET_SERDES_PLL_HRATE2 0x0000000000000020ULL +#define ENET_SERDES_PLL_HRATE3 0x0000000000000040ULL + +#define ENET_SERDES_0_CTRL_CFG (FZC_MAC + 0x14018UL) +#define ENET_SERDES_CTRL_SDET_0 0x0000000000000001ULL +#define ENET_SERDES_CTRL_SDET_1 0x0000000000000002ULL +#define ENET_SERDES_CTRL_SDET_2 0x0000000000000004ULL +#define ENET_SERDES_CTRL_SDET_3 0x0000000000000008ULL +#define ENET_SERDES_CTRL_EMPH_0 0x0000000000000070ULL +#define ENET_SERDES_CTRL_EMPH_0_SHIFT 4 +#define ENET_SERDES_CTRL_EMPH_1 0x0000000000000380ULL +#define ENET_SERDES_CTRL_EMPH_1_SHIFT 7 +#define ENET_SERDES_CTRL_EMPH_2 0x0000000000001c00ULL +#define ENET_SERDES_CTRL_EMPH_2_SHIFT 10 +#define ENET_SERDES_CTRL_EMPH_3 0x000000000000e000ULL +#define ENET_SERDES_CTRL_EMPH_3_SHIFT 13 +#define ENET_SERDES_CTRL_LADJ_0 0x0000000000070000ULL +#define ENET_SERDES_CTRL_LADJ_0_SHIFT 16 +#define ENET_SERDES_CTRL_LADJ_1 0x0000000000380000ULL +#define ENET_SERDES_CTRL_LADJ_1_SHIFT 19 +#define ENET_SERDES_CTRL_LADJ_2 0x0000000001c00000ULL +#define ENET_SERDES_CTRL_LADJ_2_SHIFT 22 +#define ENET_SERDES_CTRL_LADJ_3 0x000000000e000000ULL +#define ENET_SERDES_CTRL_LADJ_3_SHIFT 25 +#define ENET_SERDES_CTRL_RXITERM_0 0x0000000010000000ULL +#define ENET_SERDES_CTRL_RXITERM_1 0x0000000020000000ULL +#define ENET_SERDES_CTRL_RXITERM_2 0x0000000040000000ULL +#define ENET_SERDES_CTRL_RXITERM_3 0x0000000080000000ULL + +#define ENET_SERDES_0_TEST_CFG (FZC_MAC + 0x14020UL) +#define ENET_SERDES_TEST_MD_0 0x0000000000000003ULL +#define ENET_SERDES_TEST_MD_0_SHIFT 0 +#define ENET_SERDES_TEST_MD_1 0x000000000000000cULL +#define ENET_SERDES_TEST_MD_1_SHIFT 2 +#define ENET_SERDES_TEST_MD_2 0x0000000000000030ULL +#define ENET_SERDES_TEST_MD_2_SHIFT 4 +#define ENET_SERDES_TEST_MD_3 0x00000000000000c0ULL +#define ENET_SERDES_TEST_MD_3_SHIFT 6 + +#define ENET_TEST_MD_NO_LOOPBACK 0x0 +#define ENET_TEST_MD_EWRAP 0x1 +#define ENET_TEST_MD_PAD_LOOPBACK 0x2 +#define ENET_TEST_MD_REV_LOOPBACK 0x3 + +#define ENET_SERDES_1_PLL_CFG (FZC_MAC + 0x14028UL) +#define ENET_SERDES_1_CTRL_CFG (FZC_MAC + 0x14030UL) +#define ENET_SERDES_1_TEST_CFG (FZC_MAC + 0x14038UL) + +#define ENET_RGMII_CFG_REG (FZC_MAC + 0x14040UL) + +#define ESR_INT_SIGNALS (FZC_MAC + 0x14800UL) +#define ESR_INT_SIGNALS_ALL 0x00000000ffffffffULL +#define ESR_INT_SIGNALS_P0_BITS 0x0000000033e0000fULL +#define ESR_INT_SIGNALS_P1_BITS 0x000000000c1f00f0ULL +#define ESR_INT_SRDY0_P0 0x0000000020000000ULL +#define ESR_INT_DET0_P0 0x0000000010000000ULL +#define ESR_INT_SRDY0_P1 0x0000000008000000ULL +#define ESR_INT_DET0_P1 0x0000000004000000ULL +#define ESR_INT_XSRDY_P0 0x0000000002000000ULL +#define ESR_INT_XDP_P0_CH3 0x0000000001000000ULL +#define ESR_INT_XDP_P0_CH2 0x0000000000800000ULL +#define ESR_INT_XDP_P0_CH1 0x0000000000400000ULL +#define ESR_INT_XDP_P0_CH0 0x0000000000200000ULL +#define ESR_INT_XSRDY_P1 0x0000000000100000ULL +#define ESR_INT_XDP_P1_CH3 0x0000000000080000ULL +#define ESR_INT_XDP_P1_CH2 0x0000000000040000ULL +#define ESR_INT_XDP_P1_CH1 0x0000000000020000ULL +#define ESR_INT_XDP_P1_CH0 0x0000000000010000ULL +#define ESR_INT_SLOSS_P1_CH3 0x0000000000000080ULL +#define ESR_INT_SLOSS_P1_CH2 0x0000000000000040ULL +#define ESR_INT_SLOSS_P1_CH1 0x0000000000000020ULL +#define ESR_INT_SLOSS_P1_CH0 0x0000000000000010ULL +#define ESR_INT_SLOSS_P0_CH3 0x0000000000000008ULL +#define ESR_INT_SLOSS_P0_CH2 0x0000000000000004ULL +#define ESR_INT_SLOSS_P0_CH1 0x0000000000000002ULL +#define ESR_INT_SLOSS_P0_CH0 0x0000000000000001ULL + +#define ESR_DEBUG_SEL (FZC_MAC + 0x14808UL) +#define ESR_DEBUG_SEL_VAL 0x000000000000003fULL + +/* SerDes registers behind MIF */ +#define NIU_ESR_DEV_ADDR 0x1e +#define ESR_BASE 0x0000 + +#define ESR_RXTX_COMM_CTRL_L (ESR_BASE + 0x0000) +#define ESR_RXTX_COMM_CTRL_H (ESR_BASE + 0x0001) + +#define ESR_RXTX_RESET_CTRL_L (ESR_BASE + 0x0002) +#define ESR_RXTX_RESET_CTRL_H (ESR_BASE + 0x0003) + +#define ESR_RX_POWER_CTRL_L (ESR_BASE + 0x0004) +#define ESR_RX_POWER_CTRL_H (ESR_BASE + 0x0005) + +#define ESR_TX_POWER_CTRL_L (ESR_BASE + 0x0006) +#define ESR_TX_POWER_CTRL_H (ESR_BASE + 0x0007) + +#define ESR_MISC_POWER_CTRL_L (ESR_BASE + 0x0008) +#define ESR_MISC_POWER_CTRL_H (ESR_BASE + 0x0009) + +#define ESR_RXTX_CTRL_L(CHAN) (ESR_BASE + 0x0080 + (CHAN) * 0x10) +#define ESR_RXTX_CTRL_H(CHAN) (ESR_BASE + 0x0081 + (CHAN) * 0x10) +#define ESR_RXTX_CTRL_BIASCNTL 0x80000000 +#define ESR_RXTX_CTRL_RESV1 0x7c000000 +#define ESR_RXTX_CTRL_TDENFIFO 0x02000000 +#define ESR_RXTX_CTRL_TDWS20 0x01000000 +#define ESR_RXTX_CTRL_VMUXLO 0x00c00000 +#define ESR_RXTX_CTRL_VMUXLO_SHIFT 22 +#define ESR_RXTX_CTRL_VPULSELO 0x00300000 +#define ESR_RXTX_CTRL_VPULSELO_SHIFT 20 +#define ESR_RXTX_CTRL_RESV2 0x000f0000 +#define ESR_RXTX_CTRL_RESV3 0x0000c000 +#define ESR_RXTX_CTRL_RXPRESWIN 0x00003000 +#define ESR_RXTX_CTRL_RXPRESWIN_SHIFT 12 +#define ESR_RXTX_CTRL_RESV4 0x00000800 +#define ESR_RXTX_CTRL_RISEFALL 0x00000700 +#define ESR_RXTX_CTRL_RISEFALL_SHIFT 8 +#define ESR_RXTX_CTRL_RESV5 0x000000fe +#define ESR_RXTX_CTRL_ENSTRETCH 0x00000001 + +#define ESR_RXTX_TUNING_L(CHAN) (ESR_BASE + 0x0082 + (CHAN) * 0x10) +#define ESR_RXTX_TUNING_H(CHAN) (ESR_BASE + 0x0083 + (CHAN) * 0x10) + +#define ESR_RX_SYNCCHAR_L(CHAN) (ESR_BASE + 0x0084 + (CHAN) * 0x10) +#define ESR_RX_SYNCCHAR_H(CHAN) (ESR_BASE + 0x0085 + (CHAN) * 0x10) + +#define ESR_RXTX_TEST_L(CHAN) (ESR_BASE + 0x0086 + (CHAN) * 0x10) +#define ESR_RXTX_TEST_H(CHAN) (ESR_BASE + 0x0087 + (CHAN) * 0x10) + +#define ESR_GLUE_CTRL0_L(CHAN) (ESR_BASE + 0x0088 + (CHAN) * 0x10) +#define ESR_GLUE_CTRL0_H(CHAN) (ESR_BASE + 0x0089 + (CHAN) * 0x10) +#define ESR_GLUE_CTRL0_RESV1 0xf8000000 +#define ESR_GLUE_CTRL0_BLTIME 0x07000000 +#define ESR_GLUE_CTRL0_BLTIME_SHIFT 24 +#define ESR_GLUE_CTRL0_RESV2 0x00ff0000 +#define ESR_GLUE_CTRL0_RXLOS_TEST 0x00008000 +#define ESR_GLUE_CTRL0_RESV3 0x00004000 +#define ESR_GLUE_CTRL0_RXLOSENAB 0x00002000 +#define ESR_GLUE_CTRL0_FASTRESYNC 0x00001000 +#define ESR_GLUE_CTRL0_SRATE 0x00000f00 +#define ESR_GLUE_CTRL0_SRATE_SHIFT 8 +#define ESR_GLUE_CTRL0_THCNT 0x000000ff +#define ESR_GLUE_CTRL0_THCNT_SHIFT 0 + +#define BLTIME_64_CYCLES 0 +#define BLTIME_128_CYCLES 1 +#define BLTIME_256_CYCLES 2 +#define BLTIME_300_CYCLES 3 +#define BLTIME_384_CYCLES 4 +#define BLTIME_512_CYCLES 5 +#define BLTIME_1024_CYCLES 6 +#define BLTIME_2048_CYCLES 7 + +#define ESR_GLUE_CTRL1_L(CHAN) (ESR_BASE + 0x008a + (CHAN) * 0x10) +#define ESR_GLUE_CTRL1_H(CHAN) (ESR_BASE + 0x008b + (CHAN) * 0x10) +#define ESR_RXTX_TUNING1_L(CHAN) (ESR_BASE + 0x00c2 + (CHAN) * 0x10) +#define ESR_RXTX_TUNING1_H(CHAN) (ESR_BASE + 0x00c2 + (CHAN) * 0x10) +#define ESR_RXTX_TUNING2_L(CHAN) (ESR_BASE + 0x0102 + (CHAN) * 0x10) +#define ESR_RXTX_TUNING2_H(CHAN) (ESR_BASE + 0x0102 + (CHAN) * 0x10) +#define ESR_RXTX_TUNING3_L(CHAN) (ESR_BASE + 0x0142 + (CHAN) * 0x10) +#define ESR_RXTX_TUNING3_H(CHAN) (ESR_BASE + 0x0142 + (CHAN) * 0x10) + +#define NIU_ESR2_DEV_ADDR 0x1e +#define ESR2_BASE 0x8000 + +#define ESR2_TI_PLL_CFG_L (ESR2_BASE + 0x000) +#define ESR2_TI_PLL_CFG_H (ESR2_BASE + 0x001) +#define PLL_CFG_STD 0x00000c00 +#define PLL_CFG_STD_SHIFT 10 +#define PLL_CFG_LD 0x00000300 +#define PLL_CFG_LD_SHIFT 8 +#define PLL_CFG_MPY 0x0000001e +#define PLL_CFG_MPY_SHIFT 1 +#define PLL_CFG_ENPLL 0x00000001 + +#define ESR2_TI_PLL_STS_L (ESR2_BASE + 0x002) +#define ESR2_TI_PLL_STS_H (ESR2_BASE + 0x003) +#define PLL_STS_LOCK 0x00000001 + +#define ESR2_TI_PLL_TEST_CFG_L (ESR2_BASE + 0x004) +#define ESR2_TI_PLL_TEST_CFG_H (ESR2_BASE + 0x005) +#define PLL_TEST_INVPATT 0x00004000 +#define PLL_TEST_RATE 0x00003000 +#define PLL_TEST_RATE_SHIFT 12 +#define PLL_TEST_CFG_ENBSAC 0x00000400 +#define PLL_TEST_CFG_ENBSRX 0x00000200 +#define PLL_TEST_CFG_ENBSTX 0x00000100 +#define PLL_TEST_CFG_LOOPBACK_PAD 0x00000040 +#define PLL_TEST_CFG_LOOPBACK_CML_DIS 0x00000080 +#define PLL_TEST_CFG_LOOPBACK_CML_EN 0x000000c0 +#define PLL_TEST_CFG_CLKBYP 0x00000030 +#define PLL_TEST_CFG_CLKBYP_SHIFT 4 +#define PLL_TEST_CFG_EN_RXPATT 0x00000008 +#define PLL_TEST_CFG_EN_TXPATT 0x00000004 +#define PLL_TEST_CFG_TPATT 0x00000003 +#define PLL_TEST_CFG_TPATT_SHIFT 0 + +#define ESR2_TI_PLL_TX_CFG_L(CHAN) (ESR2_BASE + 0x100 + (CHAN) * 4) +#define ESR2_TI_PLL_TX_CFG_H(CHAN) (ESR2_BASE + 0x101 + (CHAN) * 4) +#define PLL_TX_CFG_RDTCT 0x00600000 +#define PLL_TX_CFG_RDTCT_SHIFT 21 +#define PLL_TX_CFG_ENIDL 0x00100000 +#define PLL_TX_CFG_BSTX 0x00020000 +#define PLL_TX_CFG_ENFTP 0x00010000 +#define PLL_TX_CFG_DE 0x0000f000 +#define PLL_TX_CFG_DE_SHIFT 12 +#define PLL_TX_CFG_SWING_125MV 0x00000000 +#define PLL_TX_CFG_SWING_250MV 0x00000200 +#define PLL_TX_CFG_SWING_500MV 0x00000400 +#define PLL_TX_CFG_SWING_625MV 0x00000600 +#define PLL_TX_CFG_SWING_750MV 0x00000800 +#define PLL_TX_CFG_SWING_1000MV 0x00000a00 +#define PLL_TX_CFG_SWING_1250MV 0x00000c00 +#define PLL_TX_CFG_SWING_1375MV 0x00000e00 +#define PLL_TX_CFG_CM 0x00000100 +#define PLL_TX_CFG_INVPAIR 0x00000080 +#define PLL_TX_CFG_RATE 0x00000060 +#define PLL_TX_CFG_RATE_SHIFT 5 +#define PLL_TX_CFG_BUSWIDTH 0x0000001c +#define PLL_TX_CFG_BUSWIDTH_SHIFT 2 +#define PLL_TX_CFG_ENTEST 0x00000002 +#define PLL_TX_CFG_ENTX 0x00000001 + +#define ESR2_TI_PLL_TX_STS_L(CHAN) (ESR2_BASE + 0x102 + (CHAN) * 4) +#define ESR2_TI_PLL_TX_STS_H(CHAN) (ESR2_BASE + 0x103 + (CHAN) * 4) +#define PLL_TX_STS_RDTCTIP 0x00000002 +#define PLL_TX_STS_TESTFAIL 0x00000001 + +#define ESR2_TI_PLL_RX_CFG_L(CHAN) (ESR2_BASE + 0x120 + (CHAN) * 4) +#define ESR2_TI_PLL_RX_CFG_H(CHAN) (ESR2_BASE + 0x121 + (CHAN) * 4) +#define PLL_RX_CFG_BSINRXN 0x02000000 +#define PLL_RX_CFG_BSINRXP 0x01000000 +#define PLL_RX_CFG_EQ_MAX_LF 0x00000000 +#define PLL_RX_CFG_EQ_LP_ADAPTIVE 0x00080000 +#define PLL_RX_CFG_EQ_LP_1084MHZ 0x00400000 +#define PLL_RX_CFG_EQ_LP_805MHZ 0x00480000 +#define PLL_RX_CFG_EQ_LP_573MHZ 0x00500000 +#define PLL_RX_CFG_EQ_LP_402MHZ 0x00580000 +#define PLL_RX_CFG_EQ_LP_304MHZ 0x00600000 +#define PLL_RX_CFG_EQ_LP_216MHZ 0x00680000 +#define PLL_RX_CFG_EQ_LP_156MHZ 0x00700000 +#define PLL_RX_CFG_EQ_LP_135MHZ 0x00780000 +#define PLL_RX_CFG_EQ_SHIFT 19 +#define PLL_RX_CFG_CDR 0x00070000 +#define PLL_RX_CFG_CDR_SHIFT 16 +#define PLL_RX_CFG_LOS_DIS 0x00000000 +#define PLL_RX_CFG_LOS_HTHRESH 0x00004000 +#define PLL_RX_CFG_LOS_LTHRESH 0x00008000 +#define PLL_RX_CFG_ALIGN_DIS 0x00000000 +#define PLL_RX_CFG_ALIGN_ENA 0x00001000 +#define PLL_RX_CFG_ALIGN_JOG 0x00002000 +#define PLL_RX_CFG_TERM_VDDT 0x00000000 +#define PLL_RX_CFG_TERM_0P8VDDT 0x00000100 +#define PLL_RX_CFG_TERM_FLOAT 0x00000300 +#define PLL_RX_CFG_INVPAIR 0x00000080 +#define PLL_RX_CFG_RATE 0x00000060 +#define PLL_RX_CFG_RATE_SHIFT 5 +#define PLL_RX_CFG_BUSWIDTH 0x0000001c +#define PLL_RX_CFG_BUSWIDTH_SHIFT 2 +#define PLL_RX_CFG_ENTEST 0x00000002 +#define PLL_RX_CFG_ENRX 0x00000001 + +#define ESR2_TI_PLL_RX_STS_L(CHAN) (ESR2_BASE + 0x122 + (CHAN) * 4) +#define ESR2_TI_PLL_RX_STS_H(CHAN) (ESR2_BASE + 0x123 + (CHAN) * 4) +#define PLL_RX_STS_CRCIDTCT 0x00000200 +#define PLL_RX_STS_CWDTCT 0x00000100 +#define PLL_RX_STS_BSRXN 0x00000020 +#define PLL_RX_STS_BSRXP 0x00000010 +#define PLL_RX_STS_LOSDTCT 0x00000008 +#define PLL_RX_STS_ODDCG 0x00000004 +#define PLL_RX_STS_SYNC 0x00000002 +#define PLL_RX_STS_TESTFAIL 0x00000001 + +#define ENET_VLAN_TBL(IDX) (FZC_FFLP + 0x00000UL + (IDX) * 8UL) +#define ENET_VLAN_TBL_PARITY1 0x0000000000020000ULL +#define ENET_VLAN_TBL_PARITY0 0x0000000000010000ULL +#define ENET_VLAN_TBL_VPR 0x0000000000000008ULL +#define ENET_VLAN_TBL_VLANRDCTBLN 0x0000000000000007ULL +#define ENET_VLAN_TBL_SHIFT(PORT) ((PORT) * 4) + +#define ENET_VLAN_TBL_NUM_ENTRIES 4096 + +#define FFLP_VLAN_PAR_ERR (FZC_FFLP + 0x0800UL) +#define FFLP_VLAN_PAR_ERR_ERR 0x0000000080000000ULL +#define FFLP_VLAN_PAR_ERR_M_ERR 0x0000000040000000ULL +#define FFLP_VLAN_PAR_ERR_ADDR 0x000000003ffc0000ULL +#define FFLP_VLAN_PAR_ERR_DATA 0x000000000003ffffULL + +#define L2_CLS(IDX) (FZC_FFLP + 0x20000UL + (IDX) * 8UL) +#define L2_CLS_VLD 0x0000000000010000ULL +#define L2_CLS_ETYPE 0x000000000000ffffULL +#define L2_CLS_ETYPE_SHIFT 0 + +#define L3_CLS(IDX) (FZC_FFLP + 0x20010UL + (IDX) * 8UL) +#define L3_CLS_VALID 0x0000000002000000ULL +#define L3_CLS_IPVER 0x0000000001000000ULL +#define L3_CLS_PID 0x0000000000ff0000ULL +#define L3_CLS_PID_SHIFT 16 +#define L3_CLS_TOSMASK 0x000000000000ff00ULL +#define L3_CLS_TOSMASK_SHIFT 8 +#define L3_CLS_TOS 0x00000000000000ffULL +#define L3_CLS_TOS_SHIFT 0 + +#define TCAM_KEY(IDX) (FZC_FFLP + 0x20030UL + (IDX) * 8UL) +#define TCAM_KEY_DISC 0x0000000000000008ULL +#define TCAM_KEY_TSEL 0x0000000000000004ULL +#define TCAM_KEY_IPADDR 0x0000000000000001ULL + +#define TCAM_KEY_0 (FZC_FFLP + 0x20090UL) +#define TCAM_KEY_0_KEY 0x00000000000000ffULL /* bits 192-199 */ + +#define TCAM_KEY_1 (FZC_FFLP + 0x20098UL) +#define TCAM_KEY_1_KEY 0xffffffffffffffffULL /* bits 128-191 */ + +#define TCAM_KEY_2 (FZC_FFLP + 0x200a0UL) +#define TCAM_KEY_2_KEY 0xffffffffffffffffULL /* bits 64-127 */ + +#define TCAM_KEY_3 (FZC_FFLP + 0x200a8UL) +#define TCAM_KEY_3_KEY 0xffffffffffffffffULL /* bits 0-63 */ + +#define TCAM_KEY_MASK_0 (FZC_FFLP + 0x200b0UL) +#define TCAM_KEY_MASK_0_KEY_SEL 0x00000000000000ffULL /* bits 192-199 */ + +#define TCAM_KEY_MASK_1 (FZC_FFLP + 0x200b8UL) +#define TCAM_KEY_MASK_1_KEY_SEL 0xffffffffffffffffULL /* bits 128-191 */ + +#define TCAM_KEY_MASK_2 (FZC_FFLP + 0x200c0UL) +#define TCAM_KEY_MASK_2_KEY_SEL 0xffffffffffffffffULL /* bits 64-127 */ + +#define TCAM_KEY_MASK_3 (FZC_FFLP + 0x200c8UL) +#define TCAM_KEY_MASK_3_KEY_SEL 0xffffffffffffffffULL /* bits 0-63 */ + +#define TCAM_CTL (FZC_FFLP + 0x200d0UL) +#define TCAM_CTL_RWC 0x00000000001c0000ULL +#define TCAM_CTL_RWC_TCAM_WRITE 0x0000000000000000ULL +#define TCAM_CTL_RWC_TCAM_READ 0x0000000000040000ULL +#define TCAM_CTL_RWC_TCAM_COMPARE 0x0000000000080000ULL +#define TCAM_CTL_RWC_RAM_WRITE 0x0000000000100000ULL +#define TCAM_CTL_RWC_RAM_READ 0x0000000000140000ULL +#define TCAM_CTL_STAT 0x0000000000020000ULL +#define TCAM_CTL_MATCH 0x0000000000010000ULL +#define TCAM_CTL_LOC 0x00000000000003ffULL + +#define TCAM_ERR (FZC_FFLP + 0x200d8UL) +#define TCAM_ERR_ERR 0x0000000080000000ULL +#define TCAM_ERR_P_ECC 0x0000000040000000ULL +#define TCAM_ERR_MULT 0x0000000020000000ULL +#define TCAM_ERR_ADDR 0x0000000000ff0000ULL +#define TCAM_ERR_SYNDROME 0x000000000000ffffULL + +#define HASH_LOOKUP_ERR_LOG1 (FZC_FFLP + 0x200e0UL) +#define HASH_LOOKUP_ERR_LOG1_ERR 0x0000000000000008ULL +#define HASH_LOOKUP_ERR_LOG1_MULT_LK 0x0000000000000004ULL +#define HASH_LOOKUP_ERR_LOG1_CU 0x0000000000000002ULL +#define HASH_LOOKUP_ERR_LOG1_MULT_BIT 0x0000000000000001ULL + +#define HASH_LOOKUP_ERR_LOG2 (FZC_FFLP + 0x200e8UL) +#define HASH_LOOKUP_ERR_LOG2_H1 0x000000007ffff800ULL +#define HASH_LOOKUP_ERR_LOG2_SUBAREA 0x0000000000000700ULL +#define HASH_LOOKUP_ERR_LOG2_SYNDROME 0x00000000000000ffULL + +#define FFLP_CFG_1 (FZC_FFLP + 0x20100UL) +#define FFLP_CFG_1_TCAM_DIS 0x0000000004000000ULL +#define FFLP_CFG_1_PIO_DBG_SEL 0x0000000003800000ULL +#define FFLP_CFG_1_PIO_FIO_RST 0x0000000000400000ULL +#define FFLP_CFG_1_PIO_FIO_LAT 0x0000000000300000ULL +#define FFLP_CFG_1_CAMLAT 0x00000000000f0000ULL +#define FFLP_CFG_1_CAMLAT_SHIFT 16 +#define FFLP_CFG_1_CAMRATIO 0x000000000000f000ULL +#define FFLP_CFG_1_CAMRATIO_SHIFT 12 +#define FFLP_CFG_1_FCRAMRATIO 0x0000000000000f00ULL +#define FFLP_CFG_1_FCRAMRATIO_SHIFT 8 +#define FFLP_CFG_1_FCRAMOUTDR_MASK 0x00000000000000f0ULL +#define FFLP_CFG_1_FCRAMOUTDR_NORMAL 0x0000000000000000ULL +#define FFLP_CFG_1_FCRAMOUTDR_STRONG 0x0000000000000050ULL +#define FFLP_CFG_1_FCRAMOUTDR_WEAK 0x00000000000000a0ULL +#define FFLP_CFG_1_FCRAMQS 0x0000000000000008ULL +#define FFLP_CFG_1_ERRORDIS 0x0000000000000004ULL +#define FFLP_CFG_1_FFLPINITDONE 0x0000000000000002ULL +#define FFLP_CFG_1_LLCSNAP 0x0000000000000001ULL + +#define DEFAULT_FCRAMRATIO 10 + +#define DEFAULT_TCAM_LATENCY 4 +#define DEFAULT_TCAM_ACCESS_RATIO 10 + +#define TCP_CFLAG_MSK (FZC_FFLP + 0x20108UL) +#define TCP_CFLAG_MSK_MASK 0x0000000000000fffULL + +#define FCRAM_REF_TMR (FZC_FFLP + 0x20110UL) +#define FCRAM_REF_TMR_MAX 0x00000000ffff0000ULL +#define FCRAM_REF_TMR_MAX_SHIFT 16 +#define FCRAM_REF_TMR_MIN 0x000000000000ffffULL +#define FCRAM_REF_TMR_MIN_SHIFT 0 + +#define DEFAULT_FCRAM_REFRESH_MAX 512 +#define DEFAULT_FCRAM_REFRESH_MIN 512 + +#define FCRAM_FIO_ADDR (FZC_FFLP + 0x20118UL) +#define FCRAM_FIO_ADDR_ADDR 0x00000000000000ffULL + +#define FCRAM_FIO_DAT (FZC_FFLP + 0x20120UL) +#define FCRAM_FIO_DAT_DATA 0x000000000000ffffULL + +#define FCRAM_ERR_TST0 (FZC_FFLP + 0x20128UL) +#define FCRAM_ERR_TST0_SYND 0x00000000000000ffULL + +#define FCRAM_ERR_TST1 (FZC_FFLP + 0x20130UL) +#define FCRAM_ERR_TST1_DAT 0x00000000ffffffffULL + +#define FCRAM_ERR_TST2 (FZC_FFLP + 0x20138UL) +#define FCRAM_ERR_TST2_DAT 0x00000000ffffffffULL + +#define FFLP_ERR_MASK (FZC_FFLP + 0x20140UL) +#define FFLP_ERR_MASK_HSH_TBL_DAT 0x00000000000007f8ULL +#define FFLP_ERR_MASK_HSH_TBL_LKUP 0x0000000000000004ULL +#define FFLP_ERR_MASK_TCAM 0x0000000000000002ULL +#define FFLP_ERR_MASK_VLAN 0x0000000000000001ULL + +#define FFLP_DBG_TRAIN_VCT (FZC_FFLP + 0x20148UL) +#define FFLP_DBG_TRAIN_VCT_VECTOR 0x00000000ffffffffULL + +#define FCRAM_PHY_RD_LAT (FZC_FFLP + 0x20150UL) +#define FCRAM_PHY_RD_LAT_LAT 0x00000000000000ffULL + +/* Ethernet TCAM format */ +#define TCAM_ETHKEY0_RESV1 0xffffffffffffff00ULL +#define TCAM_ETHKEY0_CLASS_CODE 0x00000000000000f8ULL +#define TCAM_ETHKEY0_CLASS_CODE_SHIFT 3 +#define TCAM_ETHKEY0_RESV2 0x0000000000000007ULL +#define TCAM_ETHKEY1_FRAME_BYTE0_7(NUM) (0xff << ((7 - NUM) * 8)) +#define TCAM_ETHKEY2_FRAME_BYTE8 0xff00000000000000ULL +#define TCAM_ETHKEY2_FRAME_BYTE8_SHIFT 56 +#define TCAM_ETHKEY2_FRAME_BYTE9 0x00ff000000000000ULL +#define TCAM_ETHKEY2_FRAME_BYTE9_SHIFT 48 +#define TCAM_ETHKEY2_FRAME_BYTE10 0x0000ff0000000000ULL +#define TCAM_ETHKEY2_FRAME_BYTE10_SHIFT 40 +#define TCAM_ETHKEY2_FRAME_RESV 0x000000ffffffffffULL +#define TCAM_ETHKEY3_FRAME_RESV 0xffffffffffffffffULL + +/* IPV4 TCAM format */ +#define TCAM_V4KEY0_RESV1 0xffffffffffffff00ULL +#define TCAM_V4KEY0_CLASS_CODE 0x00000000000000f8ULL +#define TCAM_V4KEY0_CLASS_CODE_SHIFT 3 +#define TCAM_V4KEY0_RESV2 0x0000000000000007ULL +#define TCAM_V4KEY1_L2RDCNUM 0xf800000000000000ULL +#define TCAM_V4KEY1_L2RDCNUM_SHIFT 59 +#define TCAM_V4KEY1_NOPORT 0x0400000000000000ULL +#define TCAM_V4KEY1_RESV 0x03ffffffffffffffULL +#define TCAM_V4KEY2_RESV 0xffff000000000000ULL +#define TCAM_V4KEY2_TOS 0x0000ff0000000000ULL +#define TCAM_V4KEY2_TOS_SHIFT 40 +#define TCAM_V4KEY2_PROTO 0x000000ff00000000ULL +#define TCAM_V4KEY2_PROTO_SHIFT 32 +#define TCAM_V4KEY2_PORT_SPI 0x00000000ffffffffULL +#define TCAM_V4KEY2_PORT_SPI_SHIFT 0 +#define TCAM_V4KEY3_SADDR 0xffffffff00000000ULL +#define TCAM_V4KEY3_SADDR_SHIFT 32 +#define TCAM_V4KEY3_DADDR 0x00000000ffffffffULL +#define TCAM_V4KEY3_DADDR_SHIFT 0 + +/* IPV6 TCAM format */ +#define TCAM_V6KEY0_RESV1 0xffffffffffffff00ULL +#define TCAM_V6KEY0_CLASS_CODE 0x00000000000000f8ULL +#define TCAM_V6KEY0_CLASS_CODE_SHIFT 3 +#define TCAM_V6KEY0_RESV2 0x0000000000000007ULL +#define TCAM_V6KEY1_L2RDCNUM 0xf800000000000000ULL +#define TCAM_V6KEY1_L2RDCNUM_SHIFT 59 +#define TCAM_V6KEY1_NOPORT 0x0400000000000000ULL +#define TCAM_V6KEY1_RESV 0x03ff000000000000ULL +#define TCAM_V6KEY1_TOS 0x0000ff0000000000ULL +#define TCAM_V6KEY1_TOS_SHIFT 40 +#define TCAM_V6KEY1_NEXT_HDR 0x000000ff00000000ULL +#define TCAM_V6KEY1_NEXT_HDR_SHIFT 32 +#define TCAM_V6KEY1_PORT_SPI 0x00000000ffffffffULL +#define TCAM_V6KEY1_PORT_SPI_SHIFT 0 +#define TCAM_V6KEY2_ADDR_HIGH 0xffffffffffffffffULL +#define TCAM_V6KEY3_ADDR_LOW 0xffffffffffffffffULL + +#define TCAM_ASSOCDATA_SYNDROME 0x000003fffc000000ULL +#define TCAM_ASSOCDATA_SYNDROME_SHIFT 26 +#define TCAM_ASSOCDATA_ZFID 0x0000000003ffc000ULL +#define TCAM_ASSOCDATA_ZFID_SHIFT 14 +#define TCAM_ASSOCDATA_V4_ECC_OK 0x0000000000002000ULL +#define TCAM_ASSOCDATA_DISC 0x0000000000001000ULL +#define TCAM_ASSOCDATA_TRES_MASK 0x0000000000000c00ULL +#define TCAM_ASSOCDATA_TRES_USE_L2RDC 0x0000000000000000ULL +#define TCAM_ASSOCDATA_TRES_USE_OFFSET 0x0000000000000400ULL +#define TCAM_ASSOCDATA_TRES_OVR_RDC 0x0000000000000800ULL +#define TCAM_ASSOCDATA_TRES_OVR_RDC_OFF 0x0000000000000c00ULL +#define TCAM_ASSOCDATA_RDCTBL 0x0000000000000380ULL +#define TCAM_ASSOCDATA_RDCTBL_SHIFT 7 +#define TCAM_ASSOCDATA_OFFSET 0x000000000000007cULL +#define TCAM_ASSOCDATA_OFFSET_SHIFT 2 +#define TCAM_ASSOCDATA_ZFVLD 0x0000000000000002ULL +#define TCAM_ASSOCDATA_AGE 0x0000000000000001ULL + +#define FLOW_KEY(IDX) (FZC_FFLP + 0x40000UL + (IDX) * 8UL) +#define FLOW_KEY_PORT 0x0000000000000200ULL +#define FLOW_KEY_L2DA 0x0000000000000100ULL +#define FLOW_KEY_VLAN 0x0000000000000080ULL +#define FLOW_KEY_IPSA 0x0000000000000040ULL +#define FLOW_KEY_IPDA 0x0000000000000020ULL +#define FLOW_KEY_PROTO 0x0000000000000010ULL +#define FLOW_KEY_L4_0 0x000000000000000cULL +#define FLOW_KEY_L4_0_SHIFT 2 +#define FLOW_KEY_L4_1 0x0000000000000003ULL +#define FLOW_KEY_L4_1_SHIFT 0 + +#define FLOW_KEY_L4_NONE 0x0 +#define FLOW_KEY_L4_RESV 0x1 +#define FLOW_KEY_L4_BYTE12 0x2 +#define FLOW_KEY_L4_BYTE56 0x3 + +#define H1POLY (FZC_FFLP + 0x40060UL) +#define H1POLY_INITVAL 0x00000000ffffffffULL + +#define H2POLY (FZC_FFLP + 0x40068UL) +#define H2POLY_INITVAL 0x000000000000ffffULL + +#define FLW_PRT_SEL(IDX) (FZC_FFLP + 0x40070UL + (IDX) * 8UL) +#define FLW_PRT_SEL_EXT 0x0000000000010000ULL +#define FLW_PRT_SEL_MASK 0x0000000000001f00ULL +#define FLW_PRT_SEL_MASK_SHIFT 8 +#define FLW_PRT_SEL_BASE 0x000000000000001fULL +#define FLW_PRT_SEL_BASE_SHIFT 0 + +#define HASH_TBL_ADDR(IDX) (FFLP + 0x00000UL + (IDX) * 8192UL) +#define HASH_TBL_ADDR_AUTOINC 0x0000000000800000ULL +#define HASH_TBL_ADDR_ADDR 0x00000000007fffffULL + +#define HASH_TBL_DATA(IDX) (FFLP + 0x00008UL + (IDX) * 8192UL) +#define HASH_TBL_DATA_DATA 0xffffffffffffffffULL + +/* FCRAM hash table entries are up to 8 64-bit words in size. + * The layout of each entry is determined by the settings in the + * first word, which is the header. + * + * The indexing is controllable per partition (there is one partition + * per RDC group, thus a total of eight) using the BASE and MASK fields + * of FLW_PRT_SEL above. + */ +#define FCRAM_SIZE 0x800000 +#define FCRAM_NUM_PARTITIONS 8 + +/* Generic HASH entry header, used for all non-optimized formats. */ +#define HASH_HEADER_FMT 0x8000000000000000ULL +#define HASH_HEADER_EXT 0x4000000000000000ULL +#define HASH_HEADER_VALID 0x2000000000000000ULL +#define HASH_HEADER_RESVD 0x1000000000000000ULL +#define HASH_HEADER_L2_DADDR 0x0ffffffffffff000ULL +#define HASH_HEADER_L2_DADDR_SHIFT 12 +#define HASH_HEADER_VLAN 0x0000000000000fffULL +#define HASH_HEADER_VLAN_SHIFT 0 + +/* Optimized format, just a header with a special layout defined below. + * Set FMT and EXT both to zero to indicate this layout is being used. + */ +#define HASH_OPT_HEADER_FMT 0x8000000000000000ULL +#define HASH_OPT_HEADER_EXT 0x4000000000000000ULL +#define HASH_OPT_HEADER_VALID 0x2000000000000000ULL +#define HASH_OPT_HEADER_RDCOFF 0x1f00000000000000ULL +#define HASH_OPT_HEADER_RDCOFF_SHIFT 56 +#define HASH_OPT_HEADER_HASH2 0x00ffff0000000000ULL +#define HASH_OPT_HEADER_HASH2_SHIFT 40 +#define HASH_OPT_HEADER_RESVD 0x000000ff00000000ULL +#define HASH_OPT_HEADER_USERINFO 0x00000000ffffffffULL +#define HASH_OPT_HEADER_USERINFO_SHIFT 0 + +/* Port and protocol word used for ipv4 and ipv6 layouts. */ +#define HASH_PORT_DPORT 0xffff000000000000ULL +#define HASH_PORT_DPORT_SHIFT 48 +#define HASH_PORT_SPORT 0x0000ffff00000000ULL +#define HASH_PORT_SPORT_SHIFT 32 +#define HASH_PORT_PROTO 0x00000000ff000000ULL +#define HASH_PORT_PROTO_SHIFT 24 +#define HASH_PORT_PORT_OFF 0x0000000000c00000ULL +#define HASH_PORT_PORT_OFF_SHIFT 22 +#define HASH_PORT_PORT_RESV 0x00000000003fffffULL + +/* Action word used for ipv4 and ipv6 layouts. */ +#define HASH_ACTION_RESV1 0xe000000000000000ULL +#define HASH_ACTION_RDCOFF 0x1f00000000000000ULL +#define HASH_ACTION_RDCOFF_SHIFT 56 +#define HASH_ACTION_ZFVALID 0x0080000000000000ULL +#define HASH_ACTION_RESV2 0x0070000000000000ULL +#define HASH_ACTION_ZFID 0x000fff0000000000ULL +#define HASH_ACTION_ZFID_SHIFT 40 +#define HASH_ACTION_RESV3 0x000000ff00000000ULL +#define HASH_ACTION_USERINFO 0x00000000ffffffffULL +#define HASH_ACTION_USERINFO_SHIFT 0 + +/* IPV4 address word. Addresses are in network endian. */ +#define HASH_IP4ADDR_SADDR 0xffffffff00000000ULL +#define HASH_IP4ADDR_SADDR_SHIFT 32 +#define HASH_IP4ADDR_DADDR 0x00000000ffffffffULL +#define HASH_IP4ADDR_DADDR_SHIFT 0 + +/* IPV6 address layout is 4 words, first two are saddr, next two + * are daddr. Addresses are in network endian. + */ + +struct fcram_hash_opt { + u64 header; +}; + +/* EXT=1, FMT=0 */ +struct fcram_hash_ipv4 { + u64 header; + u64 addrs; + u64 ports; + u64 action; +}; + +/* EXT=1, FMT=1 */ +struct fcram_hash_ipv6 { + u64 header; + u64 addrs[4]; + u64 ports; + u64 action; +}; + +#define HASH_TBL_DATA_LOG(IDX) (FFLP + 0x00010UL + (IDX) * 8192UL) +#define HASH_TBL_DATA_LOG_ERR 0x0000000080000000ULL +#define HASH_TBL_DATA_LOG_ADDR 0x000000007fffff00ULL +#define HASH_TBL_DATA_LOG_SYNDROME 0x00000000000000ffULL + +#define RX_DMA_CK_DIV (FZC_DMC + 0x00000UL) +#define RX_DMA_CK_DIV_CNT 0x000000000000ffffULL + +#define DEF_RDC(IDX) (FZC_DMC + 0x00008UL + (IDX) * 0x8UL) +#define DEF_RDC_VAL 0x000000000000001fULL + +#define PT_DRR_WT(IDX) (FZC_DMC + 0x00028UL + (IDX) * 0x8UL) +#define PT_DRR_WT_VAL 0x000000000000ffffULL + +#define PT_DRR_WEIGHT_DEFAULT_10G 0x0400 +#define PT_DRR_WEIGHT_DEFAULT_1G 0x0066 + +#define PT_USE(IDX) (FZC_DMC + 0x00048UL + (IDX) * 0x8UL) +#define PT_USE_CNT 0x00000000000fffffULL + +#define RED_RAN_INIT (FZC_DMC + 0x00068UL) +#define RED_RAN_INIT_OPMODE 0x0000000000010000ULL +#define RED_RAN_INIT_VAL 0x000000000000ffffULL + +#define RX_ADDR_MD (FZC_DMC + 0x00070UL) +#define RX_ADDR_MD_DBG_PT_MUX_SEL 0x000000000000000cULL +#define RX_ADDR_MD_RAM_ACC 0x0000000000000002ULL +#define RX_ADDR_MD_MODE32 0x0000000000000001ULL + +#define RDMC_PRE_PAR_ERR (FZC_DMC + 0x00078UL) +#define RDMC_PRE_PAR_ERR_ERR 0x0000000000008000ULL +#define RDMC_PRE_PAR_ERR_MERR 0x0000000000004000ULL +#define RDMC_PRE_PAR_ERR_ADDR 0x00000000000000ffULL + +#define RDMC_SHA_PAR_ERR (FZC_DMC + 0x00080UL) +#define RDMC_SHA_PAR_ERR_ERR 0x0000000000008000ULL +#define RDMC_SHA_PAR_ERR_MERR 0x0000000000004000ULL +#define RDMC_SHA_PAR_ERR_ADDR 0x00000000000000ffULL + +#define RDMC_MEM_ADDR (FZC_DMC + 0x00088UL) +#define RDMC_MEM_ADDR_PRE_SHAD 0x0000000000000100ULL +#define RDMC_MEM_ADDR_ADDR 0x00000000000000ffULL + +#define RDMC_MEM_DAT0 (FZC_DMC + 0x00090UL) +#define RDMC_MEM_DAT0_DATA 0x00000000ffffffffULL /* bits 31:0 */ + +#define RDMC_MEM_DAT1 (FZC_DMC + 0x00098UL) +#define RDMC_MEM_DAT1_DATA 0x00000000ffffffffULL /* bits 63:32 */ + +#define RDMC_MEM_DAT2 (FZC_DMC + 0x000a0UL) +#define RDMC_MEM_DAT2_DATA 0x00000000ffffffffULL /* bits 95:64 */ + +#define RDMC_MEM_DAT3 (FZC_DMC + 0x000a8UL) +#define RDMC_MEM_DAT3_DATA 0x00000000ffffffffULL /* bits 127:96 */ + +#define RDMC_MEM_DAT4 (FZC_DMC + 0x000b0UL) +#define RDMC_MEM_DAT4_DATA 0x00000000000fffffULL /* bits 147:128 */ + +#define RX_CTL_DAT_FIFO_STAT (FZC_DMC + 0x000b8UL) +#define RX_CTL_DAT_FIFO_STAT_ID_MISMATCH 0x0000000000000100ULL +#define RX_CTL_DAT_FIFO_STAT_ZCP_EOP_ERR 0x00000000000000f0ULL +#define RX_CTL_DAT_FIFO_STAT_IPP_EOP_ERR 0x000000000000000fULL + +#define RX_CTL_DAT_FIFO_MASK (FZC_DMC + 0x000c0UL) +#define RX_CTL_DAT_FIFO_MASK_ID_MISMATCH 0x0000000000000100ULL +#define RX_CTL_DAT_FIFO_MASK_ZCP_EOP_ERR 0x00000000000000f0ULL +#define RX_CTL_DAT_FIFO_MASK_IPP_EOP_ERR 0x000000000000000fULL + +#define RDMC_TRAINING_VECTOR (FZC_DMC + 0x000c8UL) +#define RDMC_TRAINING_VECTOR_TRAINING_VECTOR 0x00000000ffffffffULL + +#define RX_CTL_DAT_FIFO_STAT_DBG (FZC_DMC + 0x000d0UL) +#define RX_CTL_DAT_FIFO_STAT_DBG_ID_MISMATCH 0x0000000000000100ULL +#define RX_CTL_DAT_FIFO_STAT_DBG_ZCP_EOP_ERR 0x00000000000000f0ULL +#define RX_CTL_DAT_FIFO_STAT_DBG_IPP_EOP_ERR 0x000000000000000fULL + +#define RDC_TBL(TBL,SLOT) (FZC_ZCP + 0x10000UL + \ + (TBL) * (8UL * 16UL) + \ + (SLOT) * 8UL) +#define RDC_TBL_RDC 0x000000000000000fULL + +#define RX_LOG_PAGE_VLD(IDX) (FZC_DMC + 0x20000UL + (IDX) * 0x40UL) +#define RX_LOG_PAGE_VLD_FUNC 0x000000000000000cULL +#define RX_LOG_PAGE_VLD_FUNC_SHIFT 2 +#define RX_LOG_PAGE_VLD_PAGE1 0x0000000000000002ULL +#define RX_LOG_PAGE_VLD_PAGE0 0x0000000000000001ULL + +#define RX_LOG_MASK1(IDX) (FZC_DMC + 0x20008UL + (IDX) * 0x40UL) +#define RX_LOG_MASK1_MASK 0x00000000ffffffffULL + +#define RX_LOG_VAL1(IDX) (FZC_DMC + 0x20010UL + (IDX) * 0x40UL) +#define RX_LOG_VAL1_VALUE 0x00000000ffffffffULL + +#define RX_LOG_MASK2(IDX) (FZC_DMC + 0x20018UL + (IDX) * 0x40UL) +#define RX_LOG_MASK2_MASK 0x00000000ffffffffULL + +#define RX_LOG_VAL2(IDX) (FZC_DMC + 0x20020UL + (IDX) * 0x40UL) +#define RX_LOG_VAL2_VALUE 0x00000000ffffffffULL + +#define RX_LOG_PAGE_RELO1(IDX) (FZC_DMC + 0x20028UL + (IDX) * 0x40UL) +#define RX_LOG_PAGE_RELO1_RELO 0x00000000ffffffffULL + +#define RX_LOG_PAGE_RELO2(IDX) (FZC_DMC + 0x20030UL + (IDX) * 0x40UL) +#define RX_LOG_PAGE_RELO2_RELO 0x00000000ffffffffULL + +#define RX_LOG_PAGE_HDL(IDX) (FZC_DMC + 0x20038UL + (IDX) * 0x40UL) +#define RX_LOG_PAGE_HDL_HANDLE 0x00000000000fffffULL + +#define TX_LOG_PAGE_VLD(IDX) (FZC_DMC + 0x40000UL + (IDX) * 0x200UL) +#define TX_LOG_PAGE_VLD_FUNC 0x000000000000000cULL +#define TX_LOG_PAGE_VLD_FUNC_SHIFT 2 +#define TX_LOG_PAGE_VLD_PAGE1 0x0000000000000002ULL +#define TX_LOG_PAGE_VLD_PAGE0 0x0000000000000001ULL + +#define TX_LOG_MASK1(IDX) (FZC_DMC + 0x40008UL + (IDX) * 0x200UL) +#define TX_LOG_MASK1_MASK 0x00000000ffffffffULL + +#define TX_LOG_VAL1(IDX) (FZC_DMC + 0x40010UL + (IDX) * 0x200UL) +#define TX_LOG_VAL1_VALUE 0x00000000ffffffffULL + +#define TX_LOG_MASK2(IDX) (FZC_DMC + 0x40018UL + (IDX) * 0x200UL) +#define TX_LOG_MASK2_MASK 0x00000000ffffffffULL + +#define TX_LOG_VAL2(IDX) (FZC_DMC + 0x40020UL + (IDX) * 0x200UL) +#define TX_LOG_VAL2_VALUE 0x00000000ffffffffULL + +#define TX_LOG_PAGE_RELO1(IDX) (FZC_DMC + 0x40028UL + (IDX) * 0x200UL) +#define TX_LOG_PAGE_RELO1_RELO 0x00000000ffffffffULL + +#define TX_LOG_PAGE_RELO2(IDX) (FZC_DMC + 0x40030UL + (IDX) * 0x200UL) +#define TX_LOG_PAGE_RELO2_RELO 0x00000000ffffffffULL + +#define TX_LOG_PAGE_HDL(IDX) (FZC_DMC + 0x40038UL + (IDX) * 0x200UL) +#define TX_LOG_PAGE_HDL_HANDLE 0x00000000000fffffULL + +#define TX_ADDR_MD (FZC_DMC + 0x45000UL) +#define TX_ADDR_MD_MODE32 0x0000000000000001ULL + +#define RDC_RED_PARA(IDX) (FZC_DMC + 0x30000UL + (IDX) * 0x40UL) +#define RDC_RED_PARA_THRE_SYN 0x00000000fff00000ULL +#define RDC_RED_PARA_THRE_SYN_SHIFT 20 +#define RDC_RED_PARA_WIN_SYN 0x00000000000f0000ULL +#define RDC_RED_PARA_WIN_SYN_SHIFT 16 +#define RDC_RED_PARA_THRE 0x000000000000fff0ULL +#define RDC_RED_PARA_THRE_SHIFT 4 +#define RDC_RED_PARA_WIN 0x000000000000000fULL +#define RDC_RED_PARA_WIN_SHIFT 0 + +#define RED_DIS_CNT(IDX) (FZC_DMC + 0x30008UL + (IDX) * 0x40UL) +#define RED_DIS_CNT_OFLOW 0x0000000000010000ULL +#define RED_DIS_CNT_COUNT 0x000000000000ffffULL + +#define IPP_CFIG (FZC_IPP + 0x00000UL) +#define IPP_CFIG_SOFT_RST 0x0000000080000000ULL +#define IPP_CFIG_IP_MAX_PKT 0x0000000001ffff00ULL +#define IPP_CFIG_IP_MAX_PKT_SHIFT 8 +#define IPP_CFIG_FFLP_CS_PIO_W 0x0000000000000080ULL +#define IPP_CFIG_PFIFO_PIO_W 0x0000000000000040ULL +#define IPP_CFIG_DFIFO_PIO_W 0x0000000000000020ULL +#define IPP_CFIG_CKSUM_EN 0x0000000000000010ULL +#define IPP_CFIG_DROP_BAD_CRC 0x0000000000000008ULL +#define IPP_CFIG_DFIFO_ECC_EN 0x0000000000000004ULL +#define IPP_CFIG_DEBUG_BUS_OUT_EN 0x0000000000000002ULL +#define IPP_CFIG_IPP_ENABLE 0x0000000000000001ULL + +#define IPP_PKT_DIS (FZC_IPP + 0x00020UL) +#define IPP_PKT_DIS_COUNT 0x0000000000003fffULL + +#define IPP_BAD_CS_CNT (FZC_IPP + 0x00028UL) +#define IPP_BAD_CS_CNT_COUNT 0x0000000000003fffULL + +#define IPP_ECC (FZC_IPP + 0x00030UL) +#define IPP_ECC_COUNT 0x00000000000000ffULL + +#define IPP_INT_STAT (FZC_IPP + 0x00040UL) +#define IPP_INT_STAT_SOP_MISS 0x0000000080000000ULL +#define IPP_INT_STAT_EOP_MISS 0x0000000040000000ULL +#define IPP_INT_STAT_DFIFO_UE 0x0000000030000000ULL +#define IPP_INT_STAT_DFIFO_CE 0x000000000c000000ULL +#define IPP_INT_STAT_DFIFO_ECC 0x0000000003000000ULL +#define IPP_INT_STAT_DFIFO_ECC_IDX 0x00000000007ff000ULL +#define IPP_INT_STAT_PFIFO_PERR 0x0000000000000800ULL +#define IPP_INT_STAT_ECC_ERR_MAX 0x0000000000000400ULL +#define IPP_INT_STAT_PFIFO_ERR_IDX 0x00000000000003f0ULL +#define IPP_INT_STAT_PFIFO_OVER 0x0000000000000008ULL +#define IPP_INT_STAT_PFIFO_UND 0x0000000000000004ULL +#define IPP_INT_STAT_BAD_CS_MX 0x0000000000000002ULL +#define IPP_INT_STAT_PKT_DIS_MX 0x0000000000000001ULL +#define IPP_INT_STAT_ALL 0x00000000ff7fffffULL + +#define IPP_MSK (FZC_IPP + 0x00048UL) +#define IPP_MSK_ECC_ERR_MX 0x0000000000000080ULL +#define IPP_MSK_DFIFO_EOP_SOP 0x0000000000000040ULL +#define IPP_MSK_DFIFO_UC 0x0000000000000020ULL +#define IPP_MSK_PFIFO_PAR 0x0000000000000010ULL +#define IPP_MSK_PFIFO_OVER 0x0000000000000008ULL +#define IPP_MSK_PFIFO_UND 0x0000000000000004ULL +#define IPP_MSK_BAD_CS 0x0000000000000002ULL +#define IPP_MSK_PKT_DIS_CNT 0x0000000000000001ULL +#define IPP_MSK_ALL 0x00000000000000ffULL + +#define IPP_PFIFO_RD0 (FZC_IPP + 0x00060UL) +#define IPP_PFIFO_RD0_DATA 0x00000000ffffffffULL /* bits 31:0 */ + +#define IPP_PFIFO_RD1 (FZC_IPP + 0x00068UL) +#define IPP_PFIFO_RD1_DATA 0x00000000ffffffffULL /* bits 63:32 */ + +#define IPP_PFIFO_RD2 (FZC_IPP + 0x00070UL) +#define IPP_PFIFO_RD2_DATA 0x00000000ffffffffULL /* bits 95:64 */ + +#define IPP_PFIFO_RD3 (FZC_IPP + 0x00078UL) +#define IPP_PFIFO_RD3_DATA 0x00000000ffffffffULL /* bits 127:96 */ + +#define IPP_PFIFO_RD4 (FZC_IPP + 0x00080UL) +#define IPP_PFIFO_RD4_DATA 0x00000000ffffffffULL /* bits 145:128 */ + +#define IPP_PFIFO_WR0 (FZC_IPP + 0x00088UL) +#define IPP_PFIFO_WR0_DATA 0x00000000ffffffffULL /* bits 31:0 */ + +#define IPP_PFIFO_WR1 (FZC_IPP + 0x00090UL) +#define IPP_PFIFO_WR1_DATA 0x00000000ffffffffULL /* bits 63:32 */ + +#define IPP_PFIFO_WR2 (FZC_IPP + 0x00098UL) +#define IPP_PFIFO_WR2_DATA 0x00000000ffffffffULL /* bits 95:64 */ + +#define IPP_PFIFO_WR3 (FZC_IPP + 0x000a0UL) +#define IPP_PFIFO_WR3_DATA 0x00000000ffffffffULL /* bits 127:96 */ + +#define IPP_PFIFO_WR4 (FZC_IPP + 0x000a8UL) +#define IPP_PFIFO_WR4_DATA 0x00000000ffffffffULL /* bits 145:128 */ + +#define IPP_PFIFO_RD_PTR (FZC_IPP + 0x000b0UL) +#define IPP_PFIFO_RD_PTR_PTR 0x000000000000003fULL + +#define IPP_PFIFO_WR_PTR (FZC_IPP + 0x000b8UL) +#define IPP_PFIFO_WR_PTR_PTR 0x000000000000007fULL + +#define IPP_DFIFO_RD0 (FZC_IPP + 0x000c0UL) +#define IPP_DFIFO_RD0_DATA 0x00000000ffffffffULL /* bits 31:0 */ + +#define IPP_DFIFO_RD1 (FZC_IPP + 0x000c8UL) +#define IPP_DFIFO_RD1_DATA 0x00000000ffffffffULL /* bits 63:32 */ + +#define IPP_DFIFO_RD2 (FZC_IPP + 0x000d0UL) +#define IPP_DFIFO_RD2_DATA 0x00000000ffffffffULL /* bits 95:64 */ + +#define IPP_DFIFO_RD3 (FZC_IPP + 0x000d8UL) +#define IPP_DFIFO_RD3_DATA 0x00000000ffffffffULL /* bits 127:96 */ + +#define IPP_DFIFO_RD4 (FZC_IPP + 0x000e0UL) +#define IPP_DFIFO_RD4_DATA 0x00000000ffffffffULL /* bits 145:128 */ + +#define IPP_DFIFO_WR0 (FZC_IPP + 0x000e8UL) +#define IPP_DFIFO_WR0_DATA 0x00000000ffffffffULL /* bits 31:0 */ + +#define IPP_DFIFO_WR1 (FZC_IPP + 0x000f0UL) +#define IPP_DFIFO_WR1_DATA 0x00000000ffffffffULL /* bits 63:32 */ + +#define IPP_DFIFO_WR2 (FZC_IPP + 0x000f8UL) +#define IPP_DFIFO_WR2_DATA 0x00000000ffffffffULL /* bits 95:64 */ + +#define IPP_DFIFO_WR3 (FZC_IPP + 0x00100UL) +#define IPP_DFIFO_WR3_DATA 0x00000000ffffffffULL /* bits 127:96 */ + +#define IPP_DFIFO_WR4 (FZC_IPP + 0x00108UL) +#define IPP_DFIFO_WR4_DATA 0x00000000ffffffffULL /* bits 145:128 */ + +#define IPP_DFIFO_RD_PTR (FZC_IPP + 0x00110UL) +#define IPP_DFIFO_RD_PTR_PTR 0x0000000000000fffULL + +#define IPP_DFIFO_WR_PTR (FZC_IPP + 0x00118UL) +#define IPP_DFIFO_WR_PTR_PTR 0x0000000000000fffULL + +#define IPP_SM (FZC_IPP + 0x00120UL) +#define IPP_SM_SM 0x00000000ffffffffULL + +#define IPP_CS_STAT (FZC_IPP + 0x00128UL) +#define IPP_CS_STAT_BCYC_CNT 0x00000000ff000000ULL +#define IPP_CS_STAT_IP_LEN 0x0000000000fff000ULL +#define IPP_CS_STAT_CS_FAIL 0x0000000000000800ULL +#define IPP_CS_STAT_TERM 0x0000000000000400ULL +#define IPP_CS_STAT_BAD_NUM 0x0000000000000200ULL +#define IPP_CS_STAT_CS_STATE 0x00000000000001ffULL + +#define IPP_FFLP_CS_INFO (FZC_IPP + 0x00130UL) +#define IPP_FFLP_CS_INFO_PKT_ID 0x0000000000003c00ULL +#define IPP_FFLP_CS_INFO_L4_PROTO 0x0000000000000300ULL +#define IPP_FFLP_CS_INFO_V4_HD_LEN 0x00000000000000f0ULL +#define IPP_FFLP_CS_INFO_L3_VER 0x000000000000000cULL +#define IPP_FFLP_CS_INFO_L2_OP 0x0000000000000003ULL + +#define IPP_DBG_SEL (FZC_IPP + 0x00138UL) +#define IPP_DBG_SEL_SEL 0x000000000000000fULL + +#define IPP_DFIFO_ECC_SYND (FZC_IPP + 0x00140UL) +#define IPP_DFIFO_ECC_SYND_SYND 0x000000000000ffffULL + +#define IPP_DFIFO_EOP_RD_PTR (FZC_IPP + 0x00148UL) +#define IPP_DFIFO_EOP_RD_PTR_PTR 0x0000000000000fffULL + +#define IPP_ECC_CTL (FZC_IPP + 0x00150UL) +#define IPP_ECC_CTL_DIS_DBL 0x0000000080000000ULL +#define IPP_ECC_CTL_COR_DBL 0x0000000000020000ULL +#define IPP_ECC_CTL_COR_SNG 0x0000000000010000ULL +#define IPP_ECC_CTL_COR_ALL 0x0000000000000400ULL +#define IPP_ECC_CTL_COR_1 0x0000000000000100ULL +#define IPP_ECC_CTL_COR_LST 0x0000000000000004ULL +#define IPP_ECC_CTL_COR_SND 0x0000000000000002ULL +#define IPP_ECC_CTL_COR_FSR 0x0000000000000001ULL + +#define NIU_DFIFO_ENTRIES 1024 +#define ATLAS_P0_P1_DFIFO_ENTRIES 2048 +#define ATLAS_P2_P3_DFIFO_ENTRIES 1024 + +#define ZCP_CFIG (FZC_ZCP + 0x00000UL) +#define ZCP_CFIG_ZCP_32BIT_MODE 0x0000000001000000ULL +#define ZCP_CFIG_ZCP_DEBUG_SEL 0x0000000000ff0000ULL +#define ZCP_CFIG_DMA_TH 0x000000000000ffe0ULL +#define ZCP_CFIG_ECC_CHK_DIS 0x0000000000000010ULL +#define ZCP_CFIG_PAR_CHK_DIS 0x0000000000000008ULL +#define ZCP_CFIG_DIS_BUFF_RSP_IF 0x0000000000000004ULL +#define ZCP_CFIG_DIS_BUFF_REQ_IF 0x0000000000000002ULL +#define ZCP_CFIG_ZC_ENABLE 0x0000000000000001ULL + +#define ZCP_INT_STAT (FZC_ZCP + 0x00008UL) +#define ZCP_INT_STAT_RRFIFO_UNDERRUN 0x0000000000008000ULL +#define ZCP_INT_STAT_RRFIFO_OVERRUN 0x0000000000004000ULL +#define ZCP_INT_STAT_RSPFIFO_UNCOR_ERR 0x0000000000001000ULL +#define ZCP_INT_STAT_BUFFER_OVERFLOW 0x0000000000000800ULL +#define ZCP_INT_STAT_STAT_TBL_PERR 0x0000000000000400ULL +#define ZCP_INT_STAT_DYN_TBL_PERR 0x0000000000000200ULL +#define ZCP_INT_STAT_BUF_TBL_PERR 0x0000000000000100ULL +#define ZCP_INT_STAT_TT_PROGRAM_ERR 0x0000000000000080ULL +#define ZCP_INT_STAT_RSP_TT_INDEX_ERR 0x0000000000000040ULL +#define ZCP_INT_STAT_SLV_TT_INDEX_ERR 0x0000000000000020ULL +#define ZCP_INT_STAT_ZCP_TT_INDEX_ERR 0x0000000000000010ULL +#define ZCP_INT_STAT_CFIFO_ECC3 0x0000000000000008ULL +#define ZCP_INT_STAT_CFIFO_ECC2 0x0000000000000004ULL +#define ZCP_INT_STAT_CFIFO_ECC1 0x0000000000000002ULL +#define ZCP_INT_STAT_CFIFO_ECC0 0x0000000000000001ULL +#define ZCP_INT_STAT_ALL 0x000000000000ffffULL + +#define ZCP_INT_MASK (FZC_ZCP + 0x00010UL) +#define ZCP_INT_MASK_RRFIFO_UNDERRUN 0x0000000000008000ULL +#define ZCP_INT_MASK_RRFIFO_OVERRUN 0x0000000000004000ULL +#define ZCP_INT_MASK_LOJ 0x0000000000002000ULL +#define ZCP_INT_MASK_RSPFIFO_UNCOR_ERR 0x0000000000001000ULL +#define ZCP_INT_MASK_BUFFER_OVERFLOW 0x0000000000000800ULL +#define ZCP_INT_MASK_STAT_TBL_PERR 0x0000000000000400ULL +#define ZCP_INT_MASK_DYN_TBL_PERR 0x0000000000000200ULL +#define ZCP_INT_MASK_BUF_TBL_PERR 0x0000000000000100ULL +#define ZCP_INT_MASK_TT_PROGRAM_ERR 0x0000000000000080ULL +#define ZCP_INT_MASK_RSP_TT_INDEX_ERR 0x0000000000000040ULL +#define ZCP_INT_MASK_SLV_TT_INDEX_ERR 0x0000000000000020ULL +#define ZCP_INT_MASK_ZCP_TT_INDEX_ERR 0x0000000000000010ULL +#define ZCP_INT_MASK_CFIFO_ECC3 0x0000000000000008ULL +#define ZCP_INT_MASK_CFIFO_ECC2 0x0000000000000004ULL +#define ZCP_INT_MASK_CFIFO_ECC1 0x0000000000000002ULL +#define ZCP_INT_MASK_CFIFO_ECC0 0x0000000000000001ULL +#define ZCP_INT_MASK_ALL 0x000000000000ffffULL + +#define BAM4BUF (FZC_ZCP + 0x00018UL) +#define BAM4BUF_LOJ 0x0000000080000000ULL +#define BAM4BUF_EN_CK 0x0000000040000000ULL +#define BAM4BUF_IDX_END0 0x000000003ff00000ULL +#define BAM4BUF_IDX_ST0 0x00000000000ffc00ULL +#define BAM4BUF_OFFSET0 0x00000000000003ffULL + +#define BAM8BUF (FZC_ZCP + 0x00020UL) +#define BAM8BUF_LOJ 0x0000000080000000ULL +#define BAM8BUF_EN_CK 0x0000000040000000ULL +#define BAM8BUF_IDX_END1 0x000000003ff00000ULL +#define BAM8BUF_IDX_ST1 0x00000000000ffc00ULL +#define BAM8BUF_OFFSET1 0x00000000000003ffULL + +#define BAM16BUF (FZC_ZCP + 0x00028UL) +#define BAM16BUF_LOJ 0x0000000080000000ULL +#define BAM16BUF_EN_CK 0x0000000040000000ULL +#define BAM16BUF_IDX_END2 0x000000003ff00000ULL +#define BAM16BUF_IDX_ST2 0x00000000000ffc00ULL +#define BAM16BUF_OFFSET2 0x00000000000003ffULL + +#define BAM32BUF (FZC_ZCP + 0x00030UL) +#define BAM32BUF_LOJ 0x0000000080000000ULL +#define BAM32BUF_EN_CK 0x0000000040000000ULL +#define BAM32BUF_IDX_END3 0x000000003ff00000ULL +#define BAM32BUF_IDX_ST3 0x00000000000ffc00ULL +#define BAM32BUF_OFFSET3 0x00000000000003ffULL + +#define DST4BUF (FZC_ZCP + 0x00038UL) +#define DST4BUF_DS_OFFSET0 0x00000000000003ffULL + +#define DST8BUF (FZC_ZCP + 0x00040UL) +#define DST8BUF_DS_OFFSET1 0x00000000000003ffULL + +#define DST16BUF (FZC_ZCP + 0x00048UL) +#define DST16BUF_DS_OFFSET2 0x00000000000003ffULL + +#define DST32BUF (FZC_ZCP + 0x00050UL) +#define DST32BUF_DS_OFFSET3 0x00000000000003ffULL + +#define ZCP_RAM_DATA0 (FZC_ZCP + 0x00058UL) +#define ZCP_RAM_DATA0_DAT0 0x00000000ffffffffULL + +#define ZCP_RAM_DATA1 (FZC_ZCP + 0x00060UL) +#define ZCP_RAM_DAT10_DAT1 0x00000000ffffffffULL + +#define ZCP_RAM_DATA2 (FZC_ZCP + 0x00068UL) +#define ZCP_RAM_DATA2_DAT2 0x00000000ffffffffULL + +#define ZCP_RAM_DATA3 (FZC_ZCP + 0x00070UL) +#define ZCP_RAM_DATA3_DAT3 0x00000000ffffffffULL + +#define ZCP_RAM_DATA4 (FZC_ZCP + 0x00078UL) +#define ZCP_RAM_DATA4_DAT4 0x00000000000000ffULL + +#define ZCP_RAM_BE (FZC_ZCP + 0x00080UL) +#define ZCP_RAM_BE_VAL 0x000000000001ffffULL + +#define ZCP_RAM_ACC (FZC_ZCP + 0x00088UL) +#define ZCP_RAM_ACC_BUSY 0x0000000080000000ULL +#define ZCP_RAM_ACC_READ 0x0000000040000000ULL +#define ZCP_RAM_ACC_WRITE 0x0000000000000000ULL +#define ZCP_RAM_ACC_LOJ 0x0000000020000000ULL +#define ZCP_RAM_ACC_ZFCID 0x000000001ffe0000ULL +#define ZCP_RAM_ACC_ZFCID_SHIFT 17 +#define ZCP_RAM_ACC_RAM_SEL 0x000000000001f000ULL +#define ZCP_RAM_ACC_RAM_SEL_SHIFT 12 +#define ZCP_RAM_ACC_CFIFOADDR 0x0000000000000fffULL +#define ZCP_RAM_ACC_CFIFOADDR_SHIFT 0 + +#define ZCP_RAM_SEL_BAM(INDEX) (0x00 + (INDEX)) +#define ZCP_RAM_SEL_TT_STATIC 0x08 +#define ZCP_RAM_SEL_TT_DYNAMIC 0x09 +#define ZCP_RAM_SEL_CFIFO(PORT) (0x10 + (PORT)) + +#define NIU_CFIFO_ENTRIES 1024 +#define ATLAS_P0_P1_CFIFO_ENTRIES 2048 +#define ATLAS_P2_P3_CFIFO_ENTRIES 1024 + +#define CHK_BIT_DATA (FZC_ZCP + 0x00090UL) +#define CHK_BIT_DATA_DATA 0x000000000000ffffULL + +#define RESET_CFIFO (FZC_ZCP + 0x00098UL) +#define RESET_CFIFO_RST(PORT) (0x1 << (PORT)) + +#define CFIFO_ECC(PORT) (FZC_ZCP + 0x000a0UL + (PORT) * 8UL) +#define CFIFO_ECC_DIS_DBLBIT_ERR 0x0000000080000000ULL +#define CFIFO_ECC_DBLBIT_ERR 0x0000000000020000ULL +#define CFIFO_ECC_SINGLEBIT_ERR 0x0000000000010000ULL +#define CFIFO_ECC_ALL_PKT 0x0000000000000400ULL +#define CFIFO_ECC_LAST_LINE 0x0000000000000004ULL +#define CFIFO_ECC_2ND_LINE 0x0000000000000002ULL +#define CFIFO_ECC_1ST_LINE 0x0000000000000001ULL + +#define ZCP_TRAINING_VECTOR (FZC_ZCP + 0x000c0UL) +#define ZCP_TRAINING_VECTOR_VECTOR 0x00000000ffffffffULL + +#define ZCP_STATE_MACHINE (FZC_ZCP + 0x000c8UL) +#define ZCP_STATE_MACHINE_SM 0x00000000ffffffffULL + +/* Same bits as ZCP_INT_STAT */ +#define ZCP_INT_STAT_TEST (FZC_ZCP + 0x00108UL) + +#define RXDMA_CFIG1(IDX) (DMC + 0x00000UL + (IDX) * 0x200UL) +#define RXDMA_CFIG1_EN 0x0000000080000000ULL +#define RXDMA_CFIG1_RST 0x0000000040000000ULL +#define RXDMA_CFIG1_QST 0x0000000020000000ULL +#define RXDMA_CFIG1_MBADDR_H 0x0000000000000fffULL /* mboxaddr 43:32 */ + +#define RXDMA_CFIG2(IDX) (DMC + 0x00008UL + (IDX) * 0x200UL) +#define RXDMA_CFIG2_MBADDR_L 0x00000000ffffffc0ULL /* mboxaddr 31:6 */ +#define RXDMA_CFIG2_OFFSET 0x0000000000000006ULL +#define RXDMA_CFIG2_OFFSET_SHIFT 1 +#define RXDMA_CFIG2_FULL_HDR 0x0000000000000001ULL + +#define RBR_CFIG_A(IDX) (DMC + 0x00010UL + (IDX) * 0x200UL) +#define RBR_CFIG_A_LEN 0xffff000000000000ULL +#define RBR_CFIG_A_LEN_SHIFT 48 +#define RBR_CFIG_A_STADDR_BASE 0x00000ffffffc0000ULL +#define RBR_CFIG_A_STADDR 0x000000000003ffc0ULL + +#define RBR_CFIG_B(IDX) (DMC + 0x00018UL + (IDX) * 0x200UL) +#define RBR_CFIG_B_BLKSIZE 0x0000000003000000ULL +#define RBR_CFIG_B_BLKSIZE_SHIFT 24 +#define RBR_CFIG_B_VLD2 0x0000000000800000ULL +#define RBR_CFIG_B_BUFSZ2 0x0000000000030000ULL +#define RBR_CFIG_B_BUFSZ2_SHIFT 16 +#define RBR_CFIG_B_VLD1 0x0000000000008000ULL +#define RBR_CFIG_B_BUFSZ1 0x0000000000000300ULL +#define RBR_CFIG_B_BUFSZ1_SHIFT 8 +#define RBR_CFIG_B_VLD0 0x0000000000000080ULL +#define RBR_CFIG_B_BUFSZ0 0x0000000000000003ULL +#define RBR_CFIG_B_BUFSZ0_SHIFT 0 + +#define RBR_BLKSIZE_4K 0x0 +#define RBR_BLKSIZE_8K 0x1 +#define RBR_BLKSIZE_16K 0x2 +#define RBR_BLKSIZE_32K 0x3 +#define RBR_BUFSZ2_2K 0x0 +#define RBR_BUFSZ2_4K 0x1 +#define RBR_BUFSZ2_8K 0x2 +#define RBR_BUFSZ2_16K 0x3 +#define RBR_BUFSZ1_1K 0x0 +#define RBR_BUFSZ1_2K 0x1 +#define RBR_BUFSZ1_4K 0x2 +#define RBR_BUFSZ1_8K 0x3 +#define RBR_BUFSZ0_256 0x0 +#define RBR_BUFSZ0_512 0x1 +#define RBR_BUFSZ0_1K 0x2 +#define RBR_BUFSZ0_2K 0x3 + +#define RBR_KICK(IDX) (DMC + 0x00020UL + (IDX) * 0x200UL) +#define RBR_KICK_BKADD 0x000000000000ffffULL + +#define RBR_STAT(IDX) (DMC + 0x00028UL + (IDX) * 0x200UL) +#define RBR_STAT_QLEN 0x000000000000ffffULL + +#define RBR_HDH(IDX) (DMC + 0x00030UL + (IDX) * 0x200UL) +#define RBR_HDH_HEAD_H 0x0000000000000fffULL + +#define RBR_HDL(IDX) (DMC + 0x00038UL + (IDX) * 0x200UL) +#define RBR_HDL_HEAD_L 0x00000000fffffffcULL + +#define RCRCFIG_A(IDX) (DMC + 0x00040UL + (IDX) * 0x200UL) +#define RCRCFIG_A_LEN 0xffff000000000000ULL +#define RCRCFIG_A_LEN_SHIFT 48 +#define RCRCFIG_A_STADDR_BASE 0x00000ffffff80000ULL +#define RCRCFIG_A_STADDR 0x000000000007ffc0ULL + +#define RCRCFIG_B(IDX) (DMC + 0x00048UL + (IDX) * 0x200UL) +#define RCRCFIG_B_PTHRES 0x00000000ffff0000ULL +#define RCRCFIG_B_PTHRES_SHIFT 16 +#define RCRCFIG_B_ENTOUT 0x0000000000008000ULL +#define RCRCFIG_B_TIMEOUT 0x000000000000003fULL +#define RCRCFIG_B_TIMEOUT_SHIFT 0 + +#define RCRSTAT_A(IDX) (DMC + 0x00050UL + (IDX) * 0x200UL) +#define RCRSTAT_A_QLEN 0x000000000000ffffULL + +#define RCRSTAT_B(IDX) (DMC + 0x00058UL + (IDX) * 0x200UL) +#define RCRSTAT_B_TIPTR_H 0x0000000000000fffULL + +#define RCRSTAT_C(IDX) (DMC + 0x00060UL + (IDX) * 0x200UL) +#define RCRSTAT_C_TIPTR_L 0x00000000fffffff8ULL + +#define RX_DMA_CTL_STAT(IDX) (DMC + 0x00070UL + (IDX) * 0x200UL) +#define RX_DMA_CTL_STAT_RBR_TMOUT 0x0020000000000000ULL +#define RX_DMA_CTL_STAT_RSP_CNT_ERR 0x0010000000000000ULL +#define RX_DMA_CTL_STAT_BYTE_EN_BUS 0x0008000000000000ULL +#define RX_DMA_CTL_STAT_RSP_DAT_ERR 0x0004000000000000ULL +#define RX_DMA_CTL_STAT_RCR_ACK_ERR 0x0002000000000000ULL +#define RX_DMA_CTL_STAT_DC_FIFO_ERR 0x0001000000000000ULL +#define RX_DMA_CTL_STAT_MEX 0x0000800000000000ULL +#define RX_DMA_CTL_STAT_RCRTHRES 0x0000400000000000ULL +#define RX_DMA_CTL_STAT_RCRTO 0x0000200000000000ULL +#define RX_DMA_CTL_STAT_RCR_SHA_PAR 0x0000100000000000ULL +#define RX_DMA_CTL_STAT_RBR_PRE_PAR 0x0000080000000000ULL +#define RX_DMA_CTL_STAT_PORT_DROP_PKT 0x0000040000000000ULL +#define RX_DMA_CTL_STAT_WRED_DROP 0x0000020000000000ULL +#define RX_DMA_CTL_STAT_RBR_PRE_EMTY 0x0000010000000000ULL +#define RX_DMA_CTL_STAT_RCRSHADOW_FULL 0x0000008000000000ULL +#define RX_DMA_CTL_STAT_CONFIG_ERR 0x0000004000000000ULL +#define RX_DMA_CTL_STAT_RCRINCON 0x0000002000000000ULL +#define RX_DMA_CTL_STAT_RCRFULL 0x0000001000000000ULL +#define RX_DMA_CTL_STAT_RBR_EMPTY 0x0000000800000000ULL +#define RX_DMA_CTL_STAT_RBRFULL 0x0000000400000000ULL +#define RX_DMA_CTL_STAT_RBRLOGPAGE 0x0000000200000000ULL +#define RX_DMA_CTL_STAT_CFIGLOGPAGE 0x0000000100000000ULL +#define RX_DMA_CTL_STAT_PTRREAD 0x00000000ffff0000ULL +#define RX_DMA_CTL_STAT_PTRREAD_SHIFT 16 +#define RX_DMA_CTL_STAT_PKTREAD 0x000000000000ffffULL +#define RX_DMA_CTL_STAT_PKTREAD_SHIFT 0 + +#define RX_DMA_CTL_STAT_CHAN_FATAL (RX_DMA_CTL_STAT_RBR_TMOUT | \ + RX_DMA_CTL_STAT_RSP_CNT_ERR | \ + RX_DMA_CTL_STAT_BYTE_EN_BUS | \ + RX_DMA_CTL_STAT_RSP_DAT_ERR | \ + RX_DMA_CTL_STAT_RCR_ACK_ERR | \ + RX_DMA_CTL_STAT_RCR_SHA_PAR | \ + RX_DMA_CTL_STAT_RBR_PRE_PAR | \ + RX_DMA_CTL_STAT_CONFIG_ERR | \ + RX_DMA_CTL_STAT_RCRINCON | \ + RX_DMA_CTL_STAT_RCRFULL | \ + RX_DMA_CTL_STAT_RBRFULL | \ + RX_DMA_CTL_STAT_RBRLOGPAGE | \ + RX_DMA_CTL_STAT_CFIGLOGPAGE) + +#define RX_DMA_CTL_STAT_PORT_FATAL (RX_DMA_CTL_STAT_DC_FIFO_ERR) + +#define RX_DMA_CTL_WRITE_CLEAR_ERRS (RX_DMA_CTL_STAT_RBR_EMPTY | \ + RX_DMA_CTL_STAT_RCRSHADOW_FULL | \ + RX_DMA_CTL_STAT_RBR_PRE_EMTY | \ + RX_DMA_CTL_STAT_WRED_DROP | \ + RX_DMA_CTL_STAT_PORT_DROP_PKT | \ + RX_DMA_CTL_STAT_RCRTO | \ + RX_DMA_CTL_STAT_RCRTHRES | \ + RX_DMA_CTL_STAT_DC_FIFO_ERR) + +#define RCR_FLSH(IDX) (DMC + 0x00078UL + (IDX) * 0x200UL) +#define RCR_FLSH_FLSH 0x0000000000000001ULL + +#define RXMISC(IDX) (DMC + 0x00090UL + (IDX) * 0x200UL) +#define RXMISC_OFLOW 0x0000000000010000ULL +#define RXMISC_COUNT 0x000000000000ffffULL + +#define RX_DMA_CTL_STAT_DBG(IDX) (DMC + 0x00098UL + (IDX) * 0x200UL) +#define RX_DMA_CTL_STAT_DBG_RBR_TMOUT 0x0020000000000000ULL +#define RX_DMA_CTL_STAT_DBG_RSP_CNT_ERR 0x0010000000000000ULL +#define RX_DMA_CTL_STAT_DBG_BYTE_EN_BUS 0x0008000000000000ULL +#define RX_DMA_CTL_STAT_DBG_RSP_DAT_ERR 0x0004000000000000ULL +#define RX_DMA_CTL_STAT_DBG_RCR_ACK_ERR 0x0002000000000000ULL +#define RX_DMA_CTL_STAT_DBG_DC_FIFO_ERR 0x0001000000000000ULL +#define RX_DMA_CTL_STAT_DBG_MEX 0x0000800000000000ULL +#define RX_DMA_CTL_STAT_DBG_RCRTHRES 0x0000400000000000ULL +#define RX_DMA_CTL_STAT_DBG_RCRTO 0x0000200000000000ULL +#define RX_DMA_CTL_STAT_DBG_RCR_SHA_PAR 0x0000100000000000ULL +#define RX_DMA_CTL_STAT_DBG_RBR_PRE_PAR 0x0000080000000000ULL +#define RX_DMA_CTL_STAT_DBG_PORT_DROP_PKT 0x0000040000000000ULL +#define RX_DMA_CTL_STAT_DBG_WRED_DROP 0x0000020000000000ULL +#define RX_DMA_CTL_STAT_DBG_RBR_PRE_EMTY 0x0000010000000000ULL +#define RX_DMA_CTL_STAT_DBG_RCRSHADOW_FULL 0x0000008000000000ULL +#define RX_DMA_CTL_STAT_DBG_CONFIG_ERR 0x0000004000000000ULL +#define RX_DMA_CTL_STAT_DBG_RCRINCON 0x0000002000000000ULL +#define RX_DMA_CTL_STAT_DBG_RCRFULL 0x0000001000000000ULL +#define RX_DMA_CTL_STAT_DBG_RBR_EMPTY 0x0000000800000000ULL +#define RX_DMA_CTL_STAT_DBG_RBRFULL 0x0000000400000000ULL +#define RX_DMA_CTL_STAT_DBG_RBRLOGPAGE 0x0000000200000000ULL +#define RX_DMA_CTL_STAT_DBG_CFIGLOGPAGE 0x0000000100000000ULL +#define RX_DMA_CTL_STAT_DBG_PTRREAD 0x00000000ffff0000ULL +#define RX_DMA_CTL_STAT_DBG_PKTREAD 0x000000000000ffffULL + +#define RX_DMA_ENT_MSK(IDX) (DMC + 0x00068UL + (IDX) * 0x200UL) +#define RX_DMA_ENT_MSK_RBR_TMOUT 0x0000000000200000ULL +#define RX_DMA_ENT_MSK_RSP_CNT_ERR 0x0000000000100000ULL +#define RX_DMA_ENT_MSK_BYTE_EN_BUS 0x0000000000080000ULL +#define RX_DMA_ENT_MSK_RSP_DAT_ERR 0x0000000000040000ULL +#define RX_DMA_ENT_MSK_RCR_ACK_ERR 0x0000000000020000ULL +#define RX_DMA_ENT_MSK_DC_FIFO_ERR 0x0000000000010000ULL +#define RX_DMA_ENT_MSK_RCRTHRES 0x0000000000004000ULL +#define RX_DMA_ENT_MSK_RCRTO 0x0000000000002000ULL +#define RX_DMA_ENT_MSK_RCR_SHA_PAR 0x0000000000001000ULL +#define RX_DMA_ENT_MSK_RBR_PRE_PAR 0x0000000000000800ULL +#define RX_DMA_ENT_MSK_PORT_DROP_PKT 0x0000000000000400ULL +#define RX_DMA_ENT_MSK_WRED_DROP 0x0000000000000200ULL +#define RX_DMA_ENT_MSK_RBR_PRE_EMTY 0x0000000000000100ULL +#define RX_DMA_ENT_MSK_RCR_SHADOW_FULL 0x0000000000000080ULL +#define RX_DMA_ENT_MSK_CONFIG_ERR 0x0000000000000040ULL +#define RX_DMA_ENT_MSK_RCRINCON 0x0000000000000020ULL +#define RX_DMA_ENT_MSK_RCRFULL 0x0000000000000010ULL +#define RX_DMA_ENT_MSK_RBR_EMPTY 0x0000000000000008ULL +#define RX_DMA_ENT_MSK_RBRFULL 0x0000000000000004ULL +#define RX_DMA_ENT_MSK_RBRLOGPAGE 0x0000000000000002ULL +#define RX_DMA_ENT_MSK_CFIGLOGPAGE 0x0000000000000001ULL +#define RX_DMA_ENT_MSK_ALL 0x00000000003f7fffULL + +#define TX_RNG_CFIG(IDX) (DMC + 0x40000UL + (IDX) * 0x200UL) +#define TX_RNG_CFIG_LEN 0x1fff000000000000ULL +#define TX_RNG_CFIG_LEN_SHIFT 48 +#define TX_RNG_CFIG_STADDR_BASE 0x00000ffffff80000ULL +#define TX_RNG_CFIG_STADDR 0x000000000007ffc0ULL + +#define TX_RING_HDL(IDX) (DMC + 0x40010UL + (IDX) * 0x200UL) +#define TX_RING_HDL_WRAP 0x0000000000080000ULL +#define TX_RING_HDL_HEAD 0x000000000007fff8ULL +#define TX_RING_HDL_HEAD_SHIFT 3 + +#define TX_RING_KICK(IDX) (DMC + 0x40018UL + (IDX) * 0x200UL) +#define TX_RING_KICK_WRAP 0x0000000000080000ULL +#define TX_RING_KICK_TAIL 0x000000000007fff8ULL + +#define TX_ENT_MSK(IDX) (DMC + 0x40020UL + (IDX) * 0x200UL) +#define TX_ENT_MSK_MK 0x0000000000008000ULL +#define TX_ENT_MSK_MBOX_ERR 0x0000000000000080ULL +#define TX_ENT_MSK_PKT_SIZE_ERR 0x0000000000000040ULL +#define TX_ENT_MSK_TX_RING_OFLOW 0x0000000000000020ULL +#define TX_ENT_MSK_PREF_BUF_ECC_ERR 0x0000000000000010ULL +#define TX_ENT_MSK_NACK_PREF 0x0000000000000008ULL +#define TX_ENT_MSK_NACK_PKT_RD 0x0000000000000004ULL +#define TX_ENT_MSK_CONF_PART_ERR 0x0000000000000002ULL +#define TX_ENT_MSK_PKT_PRT_ERR 0x0000000000000001ULL + +#define TX_CS(IDX) (DMC + 0x40028UL + (IDX)*0x200UL) +#define TX_CS_PKT_CNT 0x0fff000000000000ULL +#define TX_CS_PKT_CNT_SHIFT 48 +#define TX_CS_LASTMARK 0x00000fff00000000ULL +#define TX_CS_LASTMARK_SHIFT 32 +#define TX_CS_RST 0x0000000080000000ULL +#define TX_CS_RST_STATE 0x0000000040000000ULL +#define TX_CS_MB 0x0000000020000000ULL +#define TX_CS_STOP_N_GO 0x0000000010000000ULL +#define TX_CS_SNG_STATE 0x0000000008000000ULL +#define TX_CS_MK 0x0000000000008000ULL +#define TX_CS_MMK 0x0000000000004000ULL +#define TX_CS_MBOX_ERR 0x0000000000000080ULL +#define TX_CS_PKT_SIZE_ERR 0x0000000000000040ULL +#define TX_CS_TX_RING_OFLOW 0x0000000000000020ULL +#define TX_CS_PREF_BUF_PAR_ERR 0x0000000000000010ULL +#define TX_CS_NACK_PREF 0x0000000000000008ULL +#define TX_CS_NACK_PKT_RD 0x0000000000000004ULL +#define TX_CS_CONF_PART_ERR 0x0000000000000002ULL +#define TX_CS_PKT_PRT_ERR 0x0000000000000001ULL + +#define TXDMA_MBH(IDX) (DMC + 0x40030UL + (IDX) * 0x200UL) +#define TXDMA_MBH_MBADDR 0x0000000000000fffULL + +#define TXDMA_MBL(IDX) (DMC + 0x40038UL + (IDX) * 0x200UL) +#define TXDMA_MBL_MBADDR 0x00000000ffffffc0ULL + +#define TX_DMA_PRE_ST(IDX) (DMC + 0x40040UL + (IDX) * 0x200UL) +#define TX_DMA_PRE_ST_SHADOW_HD 0x000000000007ffffULL + +#define TX_RNG_ERR_LOGH(IDX) (DMC + 0x40048UL + (IDX) * 0x200UL) +#define TX_RNG_ERR_LOGH_ERR 0x0000000080000000ULL +#define TX_RNG_ERR_LOGH_MERR 0x0000000040000000ULL +#define TX_RNG_ERR_LOGH_ERRCODE 0x0000000038000000ULL +#define TX_RNG_ERR_LOGH_ERRADDR 0x0000000000000fffULL + +#define TX_RNG_ERR_LOGL(IDX) (DMC + 0x40050UL + (IDX) * 0x200UL) +#define TX_RNG_ERR_LOGL_ERRADDR 0x00000000ffffffffULL + +#define TDMC_INTR_DBG(IDX) (DMC + 0x40060UL + (IDX) * 0x200UL) +#define TDMC_INTR_DBG_MK 0x0000000000008000ULL +#define TDMC_INTR_DBG_MBOX_ERR 0x0000000000000080ULL +#define TDMC_INTR_DBG_PKT_SIZE_ERR 0x0000000000000040ULL +#define TDMC_INTR_DBG_TX_RING_OFLOW 0x0000000000000020ULL +#define TDMC_INTR_DBG_PREF_BUF_PAR_ERR 0x0000000000000010ULL +#define TDMC_INTR_DBG_NACK_PREF 0x0000000000000008ULL +#define TDMC_INTR_DBG_NACK_PKT_RD 0x0000000000000004ULL +#define TDMC_INTR_DBG_CONF_PART_ERR 0x0000000000000002ULL +#define TDMC_INTR_DBG_PKT_PART_ERR 0x0000000000000001ULL + +#define TX_CS_DBG(IDX) (DMC + 0x40068UL + (IDX) * 0x200UL) +#define TX_CS_DBG_PKT_CNT 0x0fff000000000000ULL + +#define TDMC_INJ_PAR_ERR(IDX) (DMC + 0x45040UL + (IDX) * 0x200UL) +#define TDMC_INJ_PAR_ERR_VAL 0x000000000000ffffULL + +#define TDMC_DBG_SEL(IDX) (DMC + 0x45080UL + (IDX) * 0x200UL) +#define TDMC_DBG_SEL_DBG_SEL 0x000000000000003fULL + +#define TDMC_TRAINING_VECTOR(IDX) (DMC + 0x45088UL + (IDX) * 0x200UL) +#define TDMC_TRAINING_VECTOR_VEC 0x00000000ffffffffULL + +#define TXC_DMA_MAX(CHAN) (FZC_TXC + 0x00000UL + (CHAN)*0x1000UL) +#define TXC_DMA_MAX_LEN(CHAN) (FZC_TXC + 0x00008UL + (CHAN)*0x1000UL) + +#define TXC_CONTROL (FZC_TXC + 0x20000UL) +#define TXC_CONTROL_ENABLE 0x0000000000000010ULL +#define TXC_CONTROL_PORT_ENABLE(X) (1 << (X)) + +#define TXC_TRAINING_VEC (FZC_TXC + 0x20008UL) +#define TXC_TRAINING_VEC_MASK 0x00000000ffffffffULL + +#define TXC_DEBUG (FZC_TXC + 0x20010UL) +#define TXC_DEBUG_SELECT 0x000000000000003fULL + +#define TXC_MAX_REORDER (FZC_TXC + 0x20018UL) +#define TXC_MAX_REORDER_PORT3 0x000000000f000000ULL +#define TXC_MAX_REORDER_PORT2 0x00000000000f0000ULL +#define TXC_MAX_REORDER_PORT1 0x0000000000000f00ULL +#define TXC_MAX_REORDER_PORT0 0x000000000000000fULL + +#define TXC_PORT_CTL(PORT) (FZC_TXC + 0x20020UL + (PORT)*0x100UL) +#define TXC_PORT_CTL_CLR_ALL_STAT 0x0000000000000001ULL + +#define TXC_PKT_STUFFED(PORT) (FZC_TXC + 0x20030UL + (PORT)*0x100UL) +#define TXC_PKT_STUFFED_PP_REORDER 0x00000000ffff0000ULL +#define TXC_PKT_STUFFED_PP_PACKETASSY 0x000000000000ffffULL + +#define TXC_PKT_XMIT(PORT) (FZC_TXC + 0x20038UL + (PORT)*0x100UL) +#define TXC_PKT_XMIT_BYTES 0x00000000ffff0000ULL +#define TXC_PKT_XMIT_PKTS 0x000000000000ffffULL + +#define TXC_ROECC_CTL(PORT) (FZC_TXC + 0x20040UL + (PORT)*0x100UL) +#define TXC_ROECC_CTL_DISABLE_UE 0x0000000080000000ULL +#define TXC_ROECC_CTL_DBL_BIT_ERR 0x0000000000020000ULL +#define TXC_ROECC_CTL_SNGL_BIT_ERR 0x0000000000010000ULL +#define TXC_ROECC_CTL_ALL_PKTS 0x0000000000000400ULL +#define TXC_ROECC_CTL_ALT_PKTS 0x0000000000000200ULL +#define TXC_ROECC_CTL_ONE_PKT_ONLY 0x0000000000000100ULL +#define TXC_ROECC_CTL_LST_PKT_LINE 0x0000000000000004ULL +#define TXC_ROECC_CTL_2ND_PKT_LINE 0x0000000000000002ULL +#define TXC_ROECC_CTL_1ST_PKT_LINE 0x0000000000000001ULL + +#define TXC_ROECC_ST(PORT) (FZC_TXC + 0x20048UL + (PORT)*0x100UL) +#define TXC_ROECC_CLR_ST 0x0000000080000000ULL +#define TXC_ROECC_CE 0x0000000000020000ULL +#define TXC_ROECC_UE 0x0000000000010000ULL +#define TXC_ROECC_ST_ECC_ADDR 0x00000000000003ffULL + +#define TXC_RO_DATA0(PORT) (FZC_TXC + 0x20050UL + (PORT)*0x100UL) +#define TXC_RO_DATA0_DATA0 0x00000000ffffffffULL /* bits 31:0 */ + +#define TXC_RO_DATA1(PORT) (FZC_TXC + 0x20058UL + (PORT)*0x100UL) +#define TXC_RO_DATA1_DATA1 0x00000000ffffffffULL /* bits 63:32 */ + +#define TXC_RO_DATA2(PORT) (FZC_TXC + 0x20060UL + (PORT)*0x100UL) +#define TXC_RO_DATA2_DATA2 0x00000000ffffffffULL /* bits 95:64 */ + +#define TXC_RO_DATA3(PORT) (FZC_TXC + 0x20068UL + (PORT)*0x100UL) +#define TXC_RO_DATA3_DATA3 0x00000000ffffffffULL /* bits 127:96 */ + +#define TXC_RO_DATA4(PORT) (FZC_TXC + 0x20070UL + (PORT)*0x100UL) +#define TXC_RO_DATA4_DATA4 0x0000000000ffffffULL /* bits 151:128 */ + +#define TXC_SFECC_CTL(PORT) (FZC_TXC + 0x20078UL + (PORT)*0x100UL) +#define TXC_SFECC_CTL_DISABLE_UE 0x0000000080000000ULL +#define TXC_SFECC_CTL_DBL_BIT_ERR 0x0000000000020000ULL +#define TXC_SFECC_CTL_SNGL_BIT_ERR 0x0000000000010000ULL +#define TXC_SFECC_CTL_ALL_PKTS 0x0000000000000400ULL +#define TXC_SFECC_CTL_ALT_PKTS 0x0000000000000200ULL +#define TXC_SFECC_CTL_ONE_PKT_ONLY 0x0000000000000100ULL +#define TXC_SFECC_CTL_LST_PKT_LINE 0x0000000000000004ULL +#define TXC_SFECC_CTL_2ND_PKT_LINE 0x0000000000000002ULL +#define TXC_SFECC_CTL_1ST_PKT_LINE 0x0000000000000001ULL + +#define TXC_SFECC_ST(PORT) (FZC_TXC + 0x20080UL + (PORT)*0x100UL) +#define TXC_SFECC_ST_CLR_ST 0x0000000080000000ULL +#define TXC_SFECC_ST_CE 0x0000000000020000ULL +#define TXC_SFECC_ST_UE 0x0000000000010000ULL +#define TXC_SFECC_ST_ECC_ADDR 0x00000000000003ffULL + +#define TXC_SF_DATA0(PORT) (FZC_TXC + 0x20088UL + (PORT)*0x100UL) +#define TXC_SF_DATA0_DATA0 0x00000000ffffffffULL /* bits 31:0 */ + +#define TXC_SF_DATA1(PORT) (FZC_TXC + 0x20090UL + (PORT)*0x100UL) +#define TXC_SF_DATA1_DATA1 0x00000000ffffffffULL /* bits 63:32 */ + +#define TXC_SF_DATA2(PORT) (FZC_TXC + 0x20098UL + (PORT)*0x100UL) +#define TXC_SF_DATA2_DATA2 0x00000000ffffffffULL /* bits 95:64 */ + +#define TXC_SF_DATA3(PORT) (FZC_TXC + 0x200a0UL + (PORT)*0x100UL) +#define TXC_SF_DATA3_DATA3 0x00000000ffffffffULL /* bits 127:96 */ + +#define TXC_SF_DATA4(PORT) (FZC_TXC + 0x200a8UL + (PORT)*0x100UL) +#define TXC_SF_DATA4_DATA4 0x0000000000ffffffULL /* bits 151:128 */ + +#define TXC_RO_TIDS(PORT) (FZC_TXC + 0x200b0UL + (PORT)*0x100UL) +#define TXC_RO_TIDS_IN_USE 0x00000000ffffffffULL + +#define TXC_RO_STATE0(PORT) (FZC_TXC + 0x200b8UL + (PORT)*0x100UL) +#define TXC_RO_STATE0_DUPLICATE_TID 0x00000000ffffffffULL + +#define TXC_RO_STATE1(PORT) (FZC_TXC + 0x200c0UL + (PORT)*0x100UL) +#define TXC_RO_STATE1_UNUSED_TID 0x00000000ffffffffULL + +#define TXC_RO_STATE2(PORT) (FZC_TXC + 0x200c8UL + (PORT)*0x100UL) +#define TXC_RO_STATE2_TRANS_TIMEOUT 0x00000000ffffffffULL + +#define TXC_RO_STATE3(PORT) (FZC_TXC + 0x200d0UL + (PORT)*0x100UL) +#define TXC_RO_STATE3_ENAB_SPC_WMARK 0x0000000080000000ULL +#define TXC_RO_STATE3_RO_SPC_WMARK 0x000000007fe00000ULL +#define TXC_RO_STATE3_ROFIFO_SPC_AVAIL 0x00000000001ff800ULL +#define TXC_RO_STATE3_ENAB_RO_WMARK 0x0000000000000100ULL +#define TXC_RO_STATE3_HIGH_RO_USED 0x00000000000000f0ULL +#define TXC_RO_STATE3_NUM_RO_USED 0x000000000000000fULL + +#define TXC_RO_CTL(PORT) (FZC_TXC + 0x200d8UL + (PORT)*0x100UL) +#define TXC_RO_CTL_CLR_FAIL_STATE 0x0000000080000000ULL +#define TXC_RO_CTL_RO_ADDR 0x000000000f000000ULL +#define TXC_RO_CTL_ADDR_FAILED 0x0000000000400000ULL +#define TXC_RO_CTL_DMA_FAILED 0x0000000000200000ULL +#define TXC_RO_CTL_LEN_FAILED 0x0000000000100000ULL +#define TXC_RO_CTL_CAPT_ADDR_FAILED 0x0000000000040000ULL +#define TXC_RO_CTL_CAPT_DMA_FAILED 0x0000000000020000ULL +#define TXC_RO_CTL_CAPT_LEN_FAILED 0x0000000000010000ULL +#define TXC_RO_CTL_RO_STATE_RD_DONE 0x0000000000000080ULL +#define TXC_RO_CTL_RO_STATE_WR_DONE 0x0000000000000040ULL +#define TXC_RO_CTL_RO_STATE_RD 0x0000000000000020ULL +#define TXC_RO_CTL_RO_STATE_WR 0x0000000000000010ULL +#define TXC_RO_CTL_RO_STATE_ADDR 0x000000000000000fULL + +#define TXC_RO_ST_DATA0(PORT) (FZC_TXC + 0x200e0UL + (PORT)*0x100UL) +#define TXC_RO_ST_DATA0_DATA0 0x00000000ffffffffULL + +#define TXC_RO_ST_DATA1(PORT) (FZC_TXC + 0x200e8UL + (PORT)*0x100UL) +#define TXC_RO_ST_DATA1_DATA1 0x00000000ffffffffULL + +#define TXC_RO_ST_DATA2(PORT) (FZC_TXC + 0x200f0UL + (PORT)*0x100UL) +#define TXC_RO_ST_DATA2_DATA2 0x00000000ffffffffULL + +#define TXC_RO_ST_DATA3(PORT) (FZC_TXC + 0x200f8UL + (PORT)*0x100UL) +#define TXC_RO_ST_DATA3_DATA3 0x00000000ffffffffULL + +#define TXC_PORT_PACKET_REQ(PORT) (FZC_TXC + 0x20100UL + (PORT)*0x100UL) +#define TXC_PORT_PACKET_REQ_GATHER_REQ 0x00000000f0000000ULL +#define TXC_PORT_PACKET_REQ_PKT_REQ 0x000000000fff0000ULL +#define TXC_PORT_PACKET_REQ_PERR_ABRT 0x000000000000ffffULL + + /* bits are same as TXC_INT_STAT */ +#define TXC_INT_STAT_DBG (FZC_TXC + 0x20420UL) + +#define TXC_INT_STAT (FZC_TXC + 0x20428UL) +#define TXC_INT_STAT_VAL_SHIFT(PORT) ((PORT) * 8) +#define TXC_INT_STAT_VAL(PORT) (0x3f << TXC_INT_STAT_VAL_SHIFT(PORT)) +#define TXC_INT_STAT_SF_CE(PORT) (0x01 << TXC_INT_STAT_VAL_SHIFT(PORT)) +#define TXC_INT_STAT_SF_UE(PORT) (0x02 << TXC_INT_STAT_VAL_SHIFT(PORT)) +#define TXC_INT_STAT_RO_CE(PORT) (0x04 << TXC_INT_STAT_VAL_SHIFT(PORT)) +#define TXC_INT_STAT_RO_UE(PORT) (0x08 << TXC_INT_STAT_VAL_SHIFT(PORT)) +#define TXC_INT_STAT_REORDER_ERR(PORT) (0x10 << TXC_INT_STAT_VAL_SHIFT(PORT)) +#define TXC_INT_STAT_PKTASM_DEAD(PORT) (0x20 << TXC_INT_STAT_VAL_SHIFT(PORT)) + +#define TXC_INT_MASK (FZC_TXC + 0x20430UL) +#define TXC_INT_MASK_VAL_SHIFT(PORT) ((PORT) * 8) +#define TXC_INT_MASK_VAL(PORT) (0x3f << TXC_INT_STAT_VAL_SHIFT(PORT)) + +#define TXC_INT_MASK_SF_CE 0x01 +#define TXC_INT_MASK_SF_UE 0x02 +#define TXC_INT_MASK_RO_CE 0x04 +#define TXC_INT_MASK_RO_UE 0x08 +#define TXC_INT_MASK_REORDER_ERR 0x10 +#define TXC_INT_MASK_PKTASM_DEAD 0x20 +#define TXC_INT_MASK_ALL 0x3f + +#define TXC_PORT_DMA(IDX) (FZC_TXC + 0x20028UL + (IDX)*0x100UL) + +#define ESPC_PIO_EN (FZC_PROM + 0x40000UL) +#define ESPC_PIO_EN_ENABLE 0x0000000000000001ULL + +#define ESPC_PIO_STAT (FZC_PROM + 0x40008UL) +#define ESPC_PIO_STAT_READ_START 0x0000000080000000ULL +#define ESPC_PIO_STAT_READ_END 0x0000000040000000ULL +#define ESPC_PIO_STAT_WRITE_INIT 0x0000000020000000ULL +#define ESPC_PIO_STAT_WRITE_END 0x0000000010000000ULL +#define ESPC_PIO_STAT_ADDR 0x0000000003ffff00ULL +#define ESPC_PIO_STAT_ADDR_SHIFT 8 +#define ESPC_PIO_STAT_DATA 0x00000000000000ffULL +#define ESPC_PIO_STAT_DATA_SHIFT 0 + +#define ESPC_NCR(IDX) (FZC_PROM + 0x40020UL + (IDX)*0x8UL) +#define ESPC_NCR_VAL 0x00000000ffffffffULL + +#define ESPC_MAC_ADDR0 ESPC_NCR(0) +#define ESPC_MAC_ADDR1 ESPC_NCR(1) +#define ESPC_NUM_PORTS_MACS ESPC_NCR(2) +#define ESPC_NUM_PORTS_MACS_VAL 0x00000000000000ffULL +#define ESPC_MOD_STR_LEN ESPC_NCR(4) +#define ESPC_MOD_STR_1 ESPC_NCR(5) +#define ESPC_MOD_STR_2 ESPC_NCR(6) +#define ESPC_MOD_STR_3 ESPC_NCR(7) +#define ESPC_MOD_STR_4 ESPC_NCR(8) +#define ESPC_MOD_STR_5 ESPC_NCR(9) +#define ESPC_MOD_STR_6 ESPC_NCR(10) +#define ESPC_MOD_STR_7 ESPC_NCR(11) +#define ESPC_MOD_STR_8 ESPC_NCR(12) +#define ESPC_BD_MOD_STR_LEN ESPC_NCR(13) +#define ESPC_BD_MOD_STR_1 ESPC_NCR(14) +#define ESPC_BD_MOD_STR_2 ESPC_NCR(15) +#define ESPC_BD_MOD_STR_3 ESPC_NCR(16) +#define ESPC_BD_MOD_STR_4 ESPC_NCR(17) + +#define ESPC_PHY_TYPE ESPC_NCR(18) +#define ESPC_PHY_TYPE_PORT0 0x00000000ff000000ULL +#define ESPC_PHY_TYPE_PORT0_SHIFT 24 +#define ESPC_PHY_TYPE_PORT1 0x0000000000ff0000ULL +#define ESPC_PHY_TYPE_PORT1_SHIFT 16 +#define ESPC_PHY_TYPE_PORT2 0x000000000000ff00ULL +#define ESPC_PHY_TYPE_PORT2_SHIFT 8 +#define ESPC_PHY_TYPE_PORT3 0x00000000000000ffULL +#define ESPC_PHY_TYPE_PORT3_SHIFT 0 + +#define ESPC_PHY_TYPE_1G_COPPER 3 +#define ESPC_PHY_TYPE_1G_FIBER 2 +#define ESPC_PHY_TYPE_10G_COPPER 1 +#define ESPC_PHY_TYPE_10G_FIBER 0 + +#define ESPC_MAX_FM_SZ ESPC_NCR(19) + +#define ESPC_INTR_NUM ESPC_NCR(20) +#define ESPC_INTR_NUM_PORT0 0x00000000ff000000ULL +#define ESPC_INTR_NUM_PORT1 0x0000000000ff0000ULL +#define ESPC_INTR_NUM_PORT2 0x000000000000ff00ULL +#define ESPC_INTR_NUM_PORT3 0x00000000000000ffULL + +#define ESPC_VER_IMGSZ ESPC_NCR(21) +#define ESPC_VER_IMGSZ_IMGSZ 0x00000000ffff0000ULL +#define ESPC_VER_IMGSZ_IMGSZ_SHIFT 16 +#define ESPC_VER_IMGSZ_VER 0x000000000000ffffULL +#define ESPC_VER_IMGSZ_VER_SHIFT 0 + +#define ESPC_CHKSUM ESPC_NCR(22) +#define ESPC_CHKSUM_SUM 0x00000000000000ffULL + +#define ESPC_EEPROM_SIZE 0x100000 + +#define CLASS_CODE_UNRECOG 0x00 +#define CLASS_CODE_DUMMY1 0x01 +#define CLASS_CODE_ETHERTYPE1 0x02 +#define CLASS_CODE_ETHERTYPE2 0x03 +#define CLASS_CODE_USER_PROG1 0x04 +#define CLASS_CODE_USER_PROG2 0x05 +#define CLASS_CODE_USER_PROG3 0x06 +#define CLASS_CODE_USER_PROG4 0x07 +#define CLASS_CODE_TCP_IPV4 0x08 +#define CLASS_CODE_UDP_IPV4 0x09 +#define CLASS_CODE_AH_ESP_IPV4 0x0a +#define CLASS_CODE_SCTP_IPV4 0x0b +#define CLASS_CODE_TCP_IPV6 0x0c +#define CLASS_CODE_UDP_IPV6 0x0d +#define CLASS_CODE_AH_ESP_IPV6 0x0e +#define CLASS_CODE_SCTP_IPV6 0x0f +#define CLASS_CODE_ARP 0x10 +#define CLASS_CODE_RARP 0x11 +#define CLASS_CODE_DUMMY2 0x12 +#define CLASS_CODE_DUMMY3 0x13 +#define CLASS_CODE_DUMMY4 0x14 +#define CLASS_CODE_DUMMY5 0x15 +#define CLASS_CODE_DUMMY6 0x16 +#define CLASS_CODE_DUMMY7 0x17 +#define CLASS_CODE_DUMMY8 0x18 +#define CLASS_CODE_DUMMY9 0x19 +#define CLASS_CODE_DUMMY10 0x1a +#define CLASS_CODE_DUMMY11 0x1b +#define CLASS_CODE_DUMMY12 0x1c +#define CLASS_CODE_DUMMY13 0x1d +#define CLASS_CODE_DUMMY14 0x1e +#define CLASS_CODE_DUMMY15 0x1f + +/* Logical devices and device groups */ +#define LDN_RXDMA(CHAN) (0 + (CHAN)) +#define LDN_RESV1(OFF) (16 + (OFF)) +#define LDN_TXDMA(CHAN) (32 + (CHAN)) +#define LDN_RESV2(OFF) (56 + (OFF)) +#define LDN_MIF 63 +#define LDN_MAC(PORT) (64 + (PORT)) +#define LDN_DEVICE_ERROR 68 +#define LDN_MAX LDN_DEVICE_ERROR + +#define NIU_LDG_MIN 0 +#define NIU_LDG_MAX 63 +#define NIU_NUM_LDG 64 +#define LDG_INVALID 0xff + +/* PHY stuff */ +#define NIU_PMA_PMD_DEV_ADDR 1 +#define NIU_PCS_DEV_ADDR 3 + +#define NIU_PHY_ID_MASK 0xfffff0f0 +#define NIU_PHY_ID_BCM8704 0x00206030 +#define NIU_PHY_ID_BCM5464R 0x002060b0 + +#define BCM8704_PMA_PMD_DEV_ADDR 1 +#define BCM8704_PCS_DEV_ADDR 2 +#define BCM8704_USER_DEV3_ADDR 3 +#define BCM8704_PHYXS_DEV_ADDR 4 +#define BCM8704_USER_DEV4_ADDR 4 + +#define BCM8704_PMD_RCV_SIGDET 0x000a +#define PMD_RCV_SIGDET_LANE3 0x0010 +#define PMD_RCV_SIGDET_LANE2 0x0008 +#define PMD_RCV_SIGDET_LANE1 0x0004 +#define PMD_RCV_SIGDET_LANE0 0x0002 +#define PMD_RCV_SIGDET_GLOBAL 0x0001 + +#define BCM8704_PCS_10G_R_STATUS 0x0020 +#define PCS_10G_R_STATUS_LINKSTAT 0x1000 +#define PCS_10G_R_STATUS_PRBS31_ABLE 0x0004 +#define PCS_10G_R_STATUS_HI_BER 0x0002 +#define PCS_10G_R_STATUS_BLK_LOCK 0x0001 + +#define BCM8704_USER_CONTROL 0xc800 +#define USER_CONTROL_OPTXENB_LVL 0x8000 +#define USER_CONTROL_OPTXRST_LVL 0x4000 +#define USER_CONTROL_OPBIASFLT_LVL 0x2000 +#define USER_CONTROL_OBTMPFLT_LVL 0x1000 +#define USER_CONTROL_OPPRFLT_LVL 0x0800 +#define USER_CONTROL_OPTXFLT_LVL 0x0400 +#define USER_CONTROL_OPRXLOS_LVL 0x0200 +#define USER_CONTROL_OPRXFLT_LVL 0x0100 +#define USER_CONTROL_OPTXON_LVL 0x0080 +#define USER_CONTROL_RES1 0x007f +#define USER_CONTROL_RES1_SHIFT 0 + +#define BCM8704_USER_ANALOG_CLK 0xc801 +#define BCM8704_USER_PMD_RX_CONTROL 0xc802 + +#define BCM8704_USER_PMD_TX_CONTROL 0xc803 +#define USER_PMD_TX_CTL_RES1 0xfe00 +#define USER_PMD_TX_CTL_XFP_CLKEN 0x0100 +#define USER_PMD_TX_CTL_TX_DAC_TXD 0x00c0 +#define USER_PMD_TX_CTL_TX_DAC_TXD_SH 6 +#define USER_PMD_TX_CTL_TX_DAC_TXCK 0x0030 +#define USER_PMD_TX_CTL_TX_DAC_TXCK_SH 4 +#define USER_PMD_TX_CTL_TSD_LPWREN 0x0008 +#define USER_PMD_TX_CTL_TSCK_LPWREN 0x0004 +#define USER_PMD_TX_CTL_CMU_LPWREN 0x0002 +#define USER_PMD_TX_CTL_SFIFORST 0x0001 + +#define BCM8704_USER_ANALOG_STATUS0 0xc804 +#define BCM8704_USER_OPT_DIGITAL_CTRL 0xc808 +#define BCM8704_USER_TX_ALARM_STATUS 0x9004 + +#define USER_ODIG_CTRL_FMODE 0x8000 +#define USER_ODIG_CTRL_TX_PDOWN 0x4000 +#define USER_ODIG_CTRL_RX_PDOWN 0x2000 +#define USER_ODIG_CTRL_EFILT_EN 0x1000 +#define USER_ODIG_CTRL_OPT_RST 0x0800 +#define USER_ODIG_CTRL_PCS_TIB 0x0400 +#define USER_ODIG_CTRL_PCS_RI 0x0200 +#define USER_ODIG_CTRL_RESV1 0x0180 +#define USER_ODIG_CTRL_GPIOS 0x0060 +#define USER_ODIG_CTRL_GPIOS_SHIFT 5 +#define USER_ODIG_CTRL_RESV2 0x0010 +#define USER_ODIG_CTRL_LB_ERR_DIS 0x0008 +#define USER_ODIG_CTRL_RESV3 0x0006 +#define USER_ODIG_CTRL_TXONOFF_PD_DIS 0x0001 + +#define BCM8704_PHYXS_XGXS_LANE_STAT 0x0018 +#define PHYXS_XGXS_LANE_STAT_ALINGED 0x1000 +#define PHYXS_XGXS_LANE_STAT_PATTEST 0x0800 +#define PHYXS_XGXS_LANE_STAT_MAGIC 0x0400 +#define PHYXS_XGXS_LANE_STAT_LANE3 0x0008 +#define PHYXS_XGXS_LANE_STAT_LANE2 0x0004 +#define PHYXS_XGXS_LANE_STAT_LANE1 0x0002 +#define PHYXS_XGXS_LANE_STAT_LANE0 0x0001 + +#define BCM5464R_AUX_CTL 24 +#define BCM5464R_AUX_CTL_EXT_LB 0x8000 +#define BCM5464R_AUX_CTL_EXT_PLEN 0x4000 +#define BCM5464R_AUX_CTL_ER1000 0x3000 +#define BCM5464R_AUX_CTL_ER1000_SHIFT 12 +#define BCM5464R_AUX_CTL_RESV1 0x0800 +#define BCM5464R_AUX_CTL_WRITE_1 0x0400 +#define BCM5464R_AUX_CTL_RESV2 0x0300 +#define BCM5464R_AUX_CTL_PRESP_DIS 0x0080 +#define BCM5464R_AUX_CTL_RESV3 0x0040 +#define BCM5464R_AUX_CTL_ER100 0x0030 +#define BCM5464R_AUX_CTL_ER100_SHIFT 4 +#define BCM5464R_AUX_CTL_DIAG_MODE 0x0008 +#define BCM5464R_AUX_CTL_SR_SEL 0x0007 +#define BCM5464R_AUX_CTL_SR_SEL_SHIFT 0 + +#define BCM5464R_CTRL1000_AS_MASTER 0x0800 +#define BCM5464R_CTRL1000_ENABLE_AS_MASTER 0x1000 + +#define RCR_ENTRY_MULTI 0x8000000000000000ULL +#define RCR_ENTRY_PKT_TYPE 0x6000000000000000ULL +#define RCR_ENTRY_PKT_TYPE_SHIFT 61 +#define RCR_ENTRY_ZERO_COPY 0x1000000000000000ULL +#define RCR_ENTRY_NOPORT 0x0800000000000000ULL +#define RCR_ENTRY_PROMISC 0x0400000000000000ULL +#define RCR_ENTRY_ERROR 0x0380000000000000ULL +#define RCR_ENTRY_DCF_ERR 0x0040000000000000ULL +#define RCR_ENTRY_L2_LEN 0x003fff0000000000ULL +#define RCR_ENTRY_L2_LEN_SHIFT 40 +#define RCR_ENTRY_PKTBUFSZ 0x000000c000000000ULL +#define RCR_ENTRY_PKTBUFSZ_SHIFT 38 +#define RCR_ENTRY_PKT_BUF_ADDR 0x0000003fffffffffULL /* bits 43:6 */ +#define RCR_ENTRY_PKT_BUF_ADDR_SHIFT 6 + +#define RCR_PKT_TYPE_OTHER 0x0 +#define RCR_PKT_TYPE_TCP 0x1 +#define RCR_PKT_TYPE_UDP 0x2 +#define RCR_PKT_TYPE_SCTP 0x3 + +#define NIU_RXPULL_MAX ETH_HLEN + +struct rx_pkt_hdr0 { +#if defined(__LITTLE_ENDIAN_BITFIELD) + u8 inputport:2, + maccheck:1, + class:4; + u8 vlan:1, + llcsnap:1, + noport:1, + badip:1, + tcamhit:1, + tres:2, + tzfvld:1; +#elif defined(__BIG_ENDIAN_BITFIELD) + u8 class:4, + maccheck:1, + inputport:2; + u8 tzfvld:1, + tres:2, + tcamhit:1, + badip:1, + noport:1, + llcsnap:1, + vlan:1; +#endif +}; + +struct rx_pkt_hdr1 { + u8 hwrsvd1; + u8 tcammatch; +#if defined(__LITTLE_ENDIAN_BITFIELD) + u8 hwrsvd2:2, + hashit:1, + exact:1, + hzfvld:1, + hashsidx:3; +#elif defined(__BIG_ENDIAN_BITFIELD) + u8 hashsidx:3, + hzfvld:1, + exact:1, + hashit:1, + hwrsvd2:2; +#endif + u8 zcrsvd; + + /* Bits 11:8 of zero copy flow ID. */ +#if defined(__LITTLE_ENDIAN_BITFIELD) + u8 hwrsvd3:4, zflowid0:4; +#elif defined(__BIG_ENDIAN_BITFIELD) + u8 zflowid0:4, hwrsvd3:4; +#endif + + /* Bits 7:0 of zero copy flow ID. */ + u8 zflowid1; + + /* Bits 15:8 of hash value, H2. */ + u8 hashval2_0; + + /* Bits 7:0 of hash value, H2. */ + u8 hashval2_1; + + /* Bits 19:16 of hash value, H1. */ +#if defined(__LITTLE_ENDIAN_BITFIELD) + u8 hwrsvd4:4, hashval1_0:4; +#elif defined(__BIG_ENDIAN_BITFIELD) + u8 hashval1_0:4, hwrsvd4:4; +#endif + + /* Bits 15:8 of hash value, H1. */ + u8 hashval1_1; + + /* Bits 7:0 of hash value, H1. */ + u8 hashval1_2; + + u8 usrdata_0; /* Bits 39:32 of user data. */ + u8 usrdata_1; /* Bits 31:24 of user data. */ + u8 usrdata_2; /* Bits 23:16 of user data. */ + u8 usrdata_3; /* Bits 15:8 of user data. */ + u8 usrdata_4; /* Bits 7:0 of user data. */ +}; + +struct tx_dma_mbox { + u64 tx_dma_pre_st; + u64 tx_cs; + u64 tx_ring_kick; + u64 tx_ring_hdl; + u64 resv1; + u32 tx_rng_err_logl; + u32 tx_rng_err_logh; + u64 resv2; + u64 resv3; +}; + +struct tx_pkt_hdr { + __le64 flags; +#define TXHDR_PAD 0x0000000000000007ULL +#define TXHDR_PAD_SHIFT 0 +#define TXHDR_LEN 0x000000003fff0000ULL +#define TXHDR_LEN_SHIFT 16 +#define TXHDR_L4STUFF 0x0000003f00000000ULL +#define TXHDR_L4STUFF_SHIFT 32 +#define TXHDR_L4START 0x00003f0000000000ULL +#define TXHDR_L4START_SHIFT 40 +#define TXHDR_L3START 0x000f000000000000ULL +#define TXHDR_L3START_SHIFT 48 +#define TXHDR_IHL 0x00f0000000000000ULL +#define TXHDR_IHL_SHIFT 52 +#define TXHDR_VLAN 0x0100000000000000ULL +#define TXHDR_LLC 0x0200000000000000ULL +#define TXHDR_IP_VER 0x2000000000000000ULL +#define TXHDR_CSUM_NONE 0x0000000000000000ULL +#define TXHDR_CSUM_TCP 0x4000000000000000ULL +#define TXHDR_CSUM_UDP 0x8000000000000000ULL +#define TXHDR_CSUM_SCTP 0xc000000000000000ULL + __le64 resv; +}; + +#define TX_DESC_SOP 0x8000000000000000ULL +#define TX_DESC_MARK 0x4000000000000000ULL +#define TX_DESC_NUM_PTR 0x3c00000000000000ULL +#define TX_DESC_NUM_PTR_SHIFT 58 +#define TX_DESC_TR_LEN 0x01fff00000000000ULL +#define TX_DESC_TR_LEN_SHIFT 44 +#define TX_DESC_SAD 0x00000fffffffffffULL +#define TX_DESC_SAD_SHIFT 0 + +struct tx_buff_info { + struct sk_buff *skb; + u64 mapping; +}; + +struct txdma_mailbox { + __le64 tx_dma_pre_st; + __le64 tx_cs; + __le64 tx_ring_kick; + __le64 tx_ring_hdl; + __le64 resv1; + __le32 tx_rng_err_logl; + __le32 tx_rng_err_logh; + __le64 resv2[2]; +} __attribute__((aligned(64))); + +#define MAX_TX_RING_SIZE 256 +#define MAX_TX_DESC_LEN 4076 + +struct tx_ring_info { + struct tx_buff_info tx_buffs[MAX_TX_RING_SIZE]; + struct niu *np; + u64 tx_cs; + int pending; + int prod; + int cons; + int wrap_bit; + u16 last_pkt_cnt; + u16 tx_channel; + u16 mark_counter; + u16 mark_freq; + u16 mark_pending; + u16 __pad; + struct txdma_mailbox *mbox; + __le64 *descr; + + u64 tx_packets; + u64 tx_bytes; + u64 tx_errors; + + u64 mbox_dma; + u64 descr_dma; + int max_burst; +}; + +#define NEXT_TX(tp, index) \ + (((index) + 1) < (tp)->pending ? ((index) + 1) : 0) + +static inline u32 niu_tx_avail(struct tx_ring_info *tp) +{ + return (tp->pending - + ((tp->prod - tp->cons) & (MAX_TX_RING_SIZE - 1))); +} + +struct rxdma_mailbox { + __le64 rx_dma_ctl_stat; + __le64 rbr_stat; + __le32 rbr_hdl; + __le32 rbr_hdh; + __le64 resv1; + __le32 rcrstat_c; + __le32 rcrstat_b; + __le64 rcrstat_a; + __le64 resv2[2]; +} __attribute__((aligned(64))); + +#define MAX_RBR_RING_SIZE 128 +#define MAX_RCR_RING_SIZE (MAX_RBR_RING_SIZE * 2) + +#define RBR_REFILL_MIN 16 + +#define RX_SKB_ALLOC_SIZE 128 + NET_IP_ALIGN + +struct rx_ring_info { + struct niu *np; + int rx_channel; + u16 rbr_block_size; + u16 rbr_blocks_per_page; + u16 rbr_sizes[4]; + unsigned int rcr_index; + unsigned int rcr_table_size; + unsigned int rbr_index; + unsigned int rbr_pending; + unsigned int rbr_refill_pending; + unsigned int rbr_kick_thresh; + unsigned int rbr_table_size; + struct page **rxhash; + struct rxdma_mailbox *mbox; + __le64 *rcr; + __le32 *rbr; +#define RBR_DESCR_ADDR_SHIFT 12 + + u64 rx_packets; + u64 rx_bytes; + u64 rx_dropped; + u64 rx_errors; + + u64 mbox_dma; + u64 rcr_dma; + u64 rbr_dma; + + /* WRED */ + int nonsyn_window; + int nonsyn_threshold; + int syn_window; + int syn_threshold; + + /* interrupt mitigation */ + int rcr_pkt_threshold; + int rcr_timeout; +}; + +#define NEXT_RCR(rp, index) \ + (((index) + 1) < (rp)->rcr_table_size ? ((index) + 1) : 0) +#define NEXT_RBR(rp, index) \ + (((index) + 1) < (rp)->rbr_table_size ? ((index) + 1) : 0) + +#define NIU_MAX_PORTS 4 +#define NIU_NUM_RXCHAN 16 +#define NIU_NUM_TXCHAN 24 +#define MAC_NUM_HASH 16 + +#define NIU_MAX_MTU 9216 + +#define NIU_VPD_MIN_MAJOR 3 +#define NIU_VPD_MIN_MINOR 4 + +#define NIU_VPD_MODEL_MAX 32 +#define NIU_VPD_BD_MODEL_MAX 16 +#define NIU_VPD_VERSION_MAX 64 +#define NIU_VPD_PHY_TYPE_MAX 8 + +struct niu_vpd { + char model[NIU_VPD_MODEL_MAX]; + char board_model[NIU_VPD_BD_MODEL_MAX]; + char version[NIU_VPD_VERSION_MAX]; + char phy_type[NIU_VPD_PHY_TYPE_MAX]; + u8 mac_num; + u8 __pad; + u8 local_mac[6]; + int fcode_major; + int fcode_minor; +}; + +struct niu_altmac_rdc { + u8 alt_mac_num; + u8 rdc_num; + u8 mac_pref; +}; + +struct niu_vlan_rdc { + u8 rdc_num; + u8 vlan_pref; +}; + +struct niu_classifier { + struct niu_altmac_rdc alt_mac_mappings[16]; + struct niu_vlan_rdc vlan_mappings[ENET_VLAN_TBL_NUM_ENTRIES]; + + u16 tcam_index; + u16 num_alt_mac_mappings; + + u32 h1_init; + u16 h2_init; +}; + +#define NIU_NUM_RDC_TABLES 8 +#define NIU_RDC_TABLE_SLOTS 16 + +struct rdc_table { + u8 rxdma_channel[NIU_RDC_TABLE_SLOTS]; +}; + +struct niu_rdc_tables { + struct rdc_table tables[NIU_NUM_RDC_TABLES]; + int first_table_num; + int num_tables; +}; + +#define PHY_TYPE_PMA_PMD 0 +#define PHY_TYPE_PCS 1 +#define PHY_TYPE_MII 2 +#define PHY_TYPE_MAX 3 + +struct phy_probe_info { + u32 phy_id[PHY_TYPE_MAX][NIU_MAX_PORTS]; + u8 phy_port[PHY_TYPE_MAX][NIU_MAX_PORTS]; + u8 cur[PHY_TYPE_MAX]; + + struct device_attribute phy_port_attrs[PHY_TYPE_MAX * NIU_MAX_PORTS]; + struct device_attribute phy_type_attrs[PHY_TYPE_MAX * NIU_MAX_PORTS]; + struct device_attribute phy_id_attrs[PHY_TYPE_MAX * NIU_MAX_PORTS]; +}; + +struct niu_tcam_entry { + u64 key[4]; + u64 key_mask[4]; + u64 assoc_data; +}; + +struct device_node; +union niu_parent_id { + struct { + int domain; + int bus; + int device; + } pci; + struct device_node *of; +}; + +struct niu; +struct niu_parent { + struct platform_device *plat_dev; + int index; + + union niu_parent_id id; + + struct niu *ports[NIU_MAX_PORTS]; + + atomic_t refcnt; + struct list_head list; + + spinlock_t lock; + + u32 flags; +#define PARENT_FLGS_CLS_HWINIT 0x00000001 + + u32 port_phy; +#define PORT_PHY_UNKNOWN 0x00000000 +#define PORT_PHY_INVALID 0xffffffff +#define PORT_TYPE_10G 0x01 +#define PORT_TYPE_1G 0x02 +#define PORT_TYPE_MASK 0x03 + + u8 rxchan_per_port[NIU_MAX_PORTS]; + u8 txchan_per_port[NIU_MAX_PORTS]; + + struct niu_rdc_tables rdc_group_cfg[NIU_MAX_PORTS]; + u8 rdc_default[NIU_MAX_PORTS]; + + u8 ldg_map[LDN_MAX + 1]; + + u8 plat_type; +#define PLAT_TYPE_INVALID 0x00 +#define PLAT_TYPE_ATLAS 0x01 +#define PLAT_TYPE_NIU 0x02 +#define PLAT_TYPE_VF_P0 0x03 +#define PLAT_TYPE_VF_P1 0x04 + + u8 num_ports; + + u16 tcam_num_entries; +#define NIU_PCI_TCAM_ENTRIES 256 +#define NIU_NONPCI_TCAM_ENTRIES 128 +#define NIU_TCAM_ENTRIES_MAX 256 + + int rxdma_clock_divider; + + struct phy_probe_info phy_probe_info; + + struct niu_tcam_entry tcam[NIU_TCAM_ENTRIES_MAX]; + u64 l2_cls[2]; + u64 l3_cls[4]; + u64 tcam_key[12]; + u64 flow_key[12]; +}; + +struct niu_ops { + void *(*alloc_coherent)(struct device *dev, size_t size, + u64 *handle, gfp_t flag); + void (*free_coherent)(struct device *dev, size_t size, + void *cpu_addr, u64 handle); + u64 (*map_page)(struct device *dev, struct page *page, + unsigned long offset, size_t size, + enum dma_data_direction direction); + void (*unmap_page)(struct device *dev, u64 dma_address, + size_t size, enum dma_data_direction direction); + u64 (*map_single)(struct device *dev, void *cpu_addr, + size_t size, + enum dma_data_direction direction); + void (*unmap_single)(struct device *dev, u64 dma_address, + size_t size, enum dma_data_direction direction); +}; + +struct niu_link_config { + /* Describes what we're trying to get. */ + u32 advertising; + u32 supported; + u16 speed; + u8 duplex; + u8 autoneg; + + /* Describes what we actually have. */ + u16 active_speed; + u8 active_duplex; +#define SPEED_INVALID 0xffff +#define DUPLEX_INVALID 0xff +#define AUTONEG_INVALID 0xff + + u8 loopback_mode; +#define LOOPBACK_DISABLED 0x00 +#define LOOPBACK_PHY 0x01 +#define LOOPBACK_MAC 0x02 +}; + +struct niu_ldg { + struct napi_struct napi; + struct niu *np; + u8 ldg_num; + u8 timer; + u64 v0, v1, v2; + unsigned int irq; +}; + +struct niu_xmac_stats { + u64 tx_frames; + u64 tx_bytes; + u64 tx_fifo_errors; + u64 tx_overflow_errors; + u64 tx_max_pkt_size_errors; + u64 tx_underflow_errors; + + u64 rx_local_faults; + u64 rx_remote_faults; + u64 rx_link_faults; + u64 rx_align_errors; + u64 rx_frags; + u64 rx_mcasts; + u64 rx_bcasts; + u64 rx_hist_cnt1; + u64 rx_hist_cnt2; + u64 rx_hist_cnt3; + u64 rx_hist_cnt4; + u64 rx_hist_cnt5; + u64 rx_hist_cnt6; + u64 rx_hist_cnt7; + u64 rx_octets; + u64 rx_code_violations; + u64 rx_len_errors; + u64 rx_crc_errors; + u64 rx_underflows; + u64 rx_overflows; + + u64 pause_off_state; + u64 pause_on_state; + u64 pause_received; +}; + +struct niu_bmac_stats { + u64 tx_underflow_errors; + u64 tx_max_pkt_size_errors; + u64 tx_bytes; + u64 tx_frames; + + u64 rx_overflows; + u64 rx_frames; + u64 rx_align_errors; + u64 rx_crc_errors; + u64 rx_len_errors; + + u64 pause_off_state; + u64 pause_on_state; + u64 pause_received; +}; + +union niu_mac_stats { + struct niu_xmac_stats xmac; + struct niu_bmac_stats bmac; +}; + +struct niu_phy_ops { + int (*serdes_init)(struct niu *np); + int (*xcvr_init)(struct niu *np); + int (*link_status)(struct niu *np, int *); +}; + +struct of_device; +struct niu { + void __iomem *regs; + struct net_device *dev; + struct pci_dev *pdev; + struct device *device; + struct niu_parent *parent; + + u32 flags; +#define NIU_FLAGS_MSIX 0x00400000 /* MSI-X in use */ +#define NIU_FLAGS_MCAST 0x00200000 /* multicast filter enabled */ +#define NIU_FLAGS_PROMISC 0x00100000 /* PROMISC enabled */ +#define NIU_FLAGS_VPD_VALID 0x00080000 /* VPD has valid version */ +#define NIU_FLAGS_10G 0x00040000 /* 0=1G 1=10G */ +#define NIU_FLAGS_FIBER 0x00020000 /* 0=COPPER 1=FIBER */ +#define NIU_FLAGS_XMAC 0x00010000 /* 0=BMAC 1=XMAC */ + + u32 msg_enable; + + /* Protects hw programming, and ring state. */ + spinlock_t lock; + + const struct niu_ops *ops; + struct net_device_stats net_stats; + union niu_mac_stats mac_stats; + + struct rx_ring_info *rx_rings; + struct tx_ring_info *tx_rings; + int num_rx_rings; + int num_tx_rings; + + struct niu_ldg ldg[NIU_NUM_LDG]; + int num_ldg; + + void __iomem *mac_regs; + unsigned long ipp_off; + unsigned long pcs_off; + unsigned long xpcs_off; + + struct timer_list timer; + const struct niu_phy_ops *phy_ops; + int phy_addr; + + struct niu_link_config link_config; + + struct work_struct reset_task; + + u8 port; + u8 mac_xcvr; +#define MAC_XCVR_MII 1 +#define MAC_XCVR_PCS 2 +#define MAC_XCVR_XPCS 3 + + struct niu_classifier clas; + + struct niu_vpd vpd; + u32 eeprom_len; + + struct of_device *op; + void __iomem *vir_regs_1; + void __iomem *vir_regs_2; +}; + +#endif /* _NIU_H */ -- cgit v1.2.3-70-g09d2 From bc4b2b497aa61c79e3f3444237a4003a254ea565 Mon Sep 17 00:00:00 2001 From: "Klaus D. Wacker" Date: Fri, 5 Oct 2007 16:45:44 +0200 Subject: qeth: HiperSockets layer-3 interface drop non IPv4 or non IPv6 packets HiperSockets infrastructure (layer-3 mode) supports only IPv4 or IPv6 packets. Sending other packet types disturbs TCP/IP on z/VM, which issues messages about invalid packets. Qeth send routine will detect packet type on sending over a HiperSockets interface (in layer-3 mode) and drop non IP packets. The error and drop count of the interface is incremented. Signed-off-by: Klaus D. Wacker Signed-off-by: Ursula Braun Signed-off-by: Jeff Garzik --- drivers/s390/net/qeth_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index 778ddfb9907..b41a53816e9 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c @@ -4719,8 +4719,8 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb) rc = qeth_do_send_packet(card, queue, new_skb, hdr, elements_needed, ctx); else { - if ((skb->protocol == htons(ETH_P_ARP)) && - (card->dev->flags & IFF_NOARP)) { + if ((!card->options.layer2) && + (ipv == 0)) { __qeth_free_new_skb(skb, new_skb); return -EPERM; } -- cgit v1.2.3-70-g09d2 From 6570ebc4f57ad0761104f769576ae5652d9b8d64 Mon Sep 17 00:00:00 2001 From: Frank Blaschka Date: Fri, 5 Oct 2007 16:45:45 +0200 Subject: qeth: EDDP does not work on large MTUs Fix filling the qdio buffers in EDDP mode. Signed-off-by: Frank Blaschka Signed-off-by: Ursula Braun Signed-off-by: Jeff Garzik --- drivers/s390/net/qeth_eddp.c | 16 +++++++++------- drivers/s390/net/qeth_main.c | 3 ++- 2 files changed, 11 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/net/qeth_eddp.c b/drivers/s390/net/qeth_eddp.c index 70108fb1690..e3c268cfbff 100644 --- a/drivers/s390/net/qeth_eddp.c +++ b/drivers/s390/net/qeth_eddp.c @@ -159,13 +159,15 @@ qeth_eddp_fill_buffer(struct qeth_qdio_out_q *queue, buffer = buf->buffer; /* fill one skb into buffer */ for (i = 0; i < ctx->elements_per_skb; ++i){ - buffer->element[buf->next_element_to_fill].addr = - ctx->elements[element].addr; - buffer->element[buf->next_element_to_fill].length = - ctx->elements[element].length; - buffer->element[buf->next_element_to_fill].flags = - ctx->elements[element].flags; - buf->next_element_to_fill++; + if (ctx->elements[element].length != 0) { + buffer->element[buf->next_element_to_fill]. + addr = ctx->elements[element].addr; + buffer->element[buf->next_element_to_fill]. + length = ctx->elements[element].length; + buffer->element[buf->next_element_to_fill]. + flags = ctx->elements[element].flags; + buf->next_element_to_fill++; + } element++; elements--; } diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index b41a53816e9..fe6164795ed 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c @@ -4508,7 +4508,8 @@ qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue, /* check if we have enough elements (including following * free buffers) to handle eddp context */ if (qeth_eddp_check_buffers_for_context(queue,ctx) < 0){ - printk("eddp tx_dropped 1\n"); + if (net_ratelimit()) + PRINT_WARN("eddp tx_dropped 1\n"); rc = -EBUSY; goto out; } -- cgit v1.2.3-70-g09d2 From d8fae9c2f2642ffe411424ed2e4677f959168152 Mon Sep 17 00:00:00 2001 From: Ursula Braun Date: Fri, 5 Oct 2007 16:45:46 +0200 Subject: qeth: avoid duplicate deletion of multicast addresses if qeth_set_multicast_list() is performed on 2 CPUs in parallel, card->ip_list may end corrupted. Solution: In function __qeth_delete_all_mc() remove card->ip_list entry before invoking qeth_deregister_addr_entry(). Thus a 2nd invocation of qeth_set_multicast_list() cannot try to remove the same entry twice. Signed-off-by Ursula Braun Signed-off-by: Jeff Garzik --- drivers/s390/net/qeth_main.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index fe6164795ed..6d7b79e2ba9 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c @@ -823,14 +823,15 @@ __qeth_delete_all_mc(struct qeth_card *card, unsigned long *flags) again: list_for_each_entry_safe(addr, tmp, &card->ip_list, entry) { if (addr->is_multicast) { + list_del(&addr->entry); spin_unlock_irqrestore(&card->ip_lock, *flags); rc = qeth_deregister_addr_entry(card, addr); spin_lock_irqsave(&card->ip_lock, *flags); if (!rc) { - list_del(&addr->entry); kfree(addr); goto again; - } + } else + list_add(&addr->entry, &card->ip_list); } } } -- cgit v1.2.3-70-g09d2 From 59579da329b22bcddc5da0c22c61d6dc1f9eb96a Mon Sep 17 00:00:00 2001 From: "Klaus D. Wacker" Date: Fri, 5 Oct 2007 16:45:47 +0200 Subject: lcs: Channel errors drive lcs_recovery which leads to kernel panic. When the lcs irq routine detects channel failures it drives device recovery. After this event the device is no longer usable for shutdown requests, because the lcs_irq routine may get wrong channel status information. In such a case the lcs_irq routine marks the channel in 'error' state. The channel state comes back to 'running' after restarting the channels. Signed-off-by: Klaus D. Wacker Signed-off-by: Ursula Braun Signed-off-by: Jeff Garzik --- drivers/s390/net/lcs.c | 11 ++++++++--- drivers/s390/net/lcs.h | 1 + 2 files changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index e4b11afbbc9..0fd663b23d7 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -1400,11 +1400,14 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) PRINT_WARN("check on device %s, dstat=0x%X, cstat=0x%X \n", cdev->dev.bus_id, dstat, cstat); if (rc) { - lcs_schedule_recovery(card); - wake_up(&card->wait_q); - return; + channel->state = LCS_CH_STATE_ERROR; } } + if (channel->state == LCS_CH_STATE_ERROR) { + lcs_schedule_recovery(card); + wake_up(&card->wait_q); + return; + } /* How far in the ccw chain have we processed? */ if ((channel->state != LCS_CH_STATE_INIT) && (irb->scsw.fctl & SCSW_FCTL_START_FUNC)) { @@ -1708,6 +1711,8 @@ lcs_stopcard(struct lcs_card *card) if (card->read.state != LCS_CH_STATE_STOPPED && card->write.state != LCS_CH_STATE_STOPPED && + card->read.state != LCS_CH_STATE_ERROR && + card->write.state != LCS_CH_STATE_ERROR && card->state == DEV_STATE_UP) { lcs_clear_multicast_list(card); rc = lcs_send_stoplan(card,LCS_INITIATOR_TCPIP); diff --git a/drivers/s390/net/lcs.h b/drivers/s390/net/lcs.h index 0e1e4a0a88f..8976fb0b070 100644 --- a/drivers/s390/net/lcs.h +++ b/drivers/s390/net/lcs.h @@ -138,6 +138,7 @@ enum lcs_channel_states { LCS_CH_STATE_RUNNING, LCS_CH_STATE_SUSPENDED, LCS_CH_STATE_CLEARED, + LCS_CH_STATE_ERROR, }; /** -- cgit v1.2.3-70-g09d2 From 28692ec45e58f40a998beb155fe1c0d3e1167485 Mon Sep 17 00:00:00 2001 From: Ursula Braun Date: Fri, 5 Oct 2007 16:45:48 +0200 Subject: qeth: discard inbound packets with unknown header id Debugging statements are added for inbound packets with unknown header id. Those packets are discarded and no longer processed as osn-packets. Signed-off-by: Ursula Braun Signed-off-by: Jeff Garzik --- drivers/s390/net/qeth_main.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index 6d7b79e2ba9..c67e7dfd56c 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c @@ -2702,10 +2702,15 @@ qeth_process_inbound_buffer(struct qeth_card *card, qeth_layer2_rebuild_skb(card, skb, hdr); else if (hdr->hdr.l3.id == QETH_HEADER_TYPE_LAYER3) vlan_tag = qeth_rebuild_skb(card, skb, hdr); - else { /*in case of OSN*/ + else if (hdr->hdr.osn.id == QETH_HEADER_TYPE_OSN) { skb_push(skb, sizeof(struct qeth_hdr)); skb_copy_to_linear_data(skb, hdr, sizeof(struct qeth_hdr)); + } else { /* unknown header type */ + dev_kfree_skb_any(skb); + QETH_DBF_TEXT(trace, 3, "inbunkno"); + QETH_DBF_HEX(control, 3, hdr, QETH_DBF_CONTROL_LEN); + continue; } /* is device UP ? */ if (!(card->dev->flags & IFF_UP)){ -- cgit v1.2.3-70-g09d2 From 589c085f2734537dce4a8b59a1d49006479e33d1 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Thu, 4 Oct 2007 11:38:43 -0700 Subject: e1000e: fix debugging printout code A small bug crawled in the -DDEBUG enabled code. Fix this to properly call the backreference device name. Signed-off-by: Auke Kok Signed-off-by: Jeff Garzik --- drivers/net/e1000e/hw.h | 2 +- drivers/net/e1000e/netdev.c | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/e1000e/hw.h b/drivers/net/e1000e/hw.h index 848217a3825..aa82f1afb7f 100644 --- a/drivers/net/e1000e/hw.h +++ b/drivers/net/e1000e/hw.h @@ -852,7 +852,7 @@ struct e1000_hw { #ifdef DEBUG #define hw_dbg(hw, format, arg...) \ - printk(KERN_DEBUG, "%s: " format, e1000_get_hw_dev_name(hw), ##arg); + printk(KERN_DEBUG, "%s: " format, e1000e_get_hw_dev_name(hw), ##arg); #else static inline int __attribute__ ((format (printf, 2, 3))) hw_dbg(struct e1000_hw *hw, const char *format, ...) diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 4a21d7df174..3a0bb2afe38 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -66,9 +66,7 @@ static const struct e1000_info *e1000_info_tbl[] = { **/ char *e1000e_get_hw_dev_name(struct e1000_hw *hw) { - struct e1000_adapter *adapter = hw->back; - struct net_device *netdev = adapter->netdev; - return netdev->name; + return hw->adapter->netdev->name; } #endif -- cgit v1.2.3-70-g09d2 From 8658251dc3fed54b09991a2c5e0a7084755157d7 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Thu, 4 Oct 2007 15:00:08 -0700 Subject: e1000e: Fix ethtool register test code A merge/cleanup code accidentally dropped 8254x code in and removed 8257x code here. Undo this mistake and use the pci-e relevant register test similar as to what is in e1000. Signed-off-by: Auke Kok Signed-off-by: Jeff Garzik --- drivers/net/e1000e/ethtool.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c index 3423f33769b..2e8218fb057 100644 --- a/drivers/net/e1000e/ethtool.c +++ b/drivers/net/e1000e/ethtool.c @@ -784,10 +784,16 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data) REG_SET_AND_CHECK(E1000_RCTL, before, 0x003FFFFB); REG_SET_AND_CHECK(E1000_TCTL, 0xFFFFFFFF, 0x00000000); - REG_SET_AND_CHECK(E1000_RCTL, 0xFFFFFFFF, 0x01FFFFFF); - REG_PATTERN_TEST(E1000_RDBAL, 0xFFFFF000, 0xFFFFFFFF); - REG_PATTERN_TEST(E1000_TXCW, 0x0000FFFF, 0x0000FFFF); - REG_PATTERN_TEST(E1000_TDBAL, 0xFFFFF000, 0xFFFFFFFF); + REG_SET_AND_CHECK(E1000_RCTL, before, 0xFFFFFFFF); + REG_PATTERN_TEST(E1000_RDBAL, 0xFFFFFFF0, 0xFFFFFFFF); + if ((mac->type != e1000_ich8lan) && + (mac->type != e1000_ich9lan)) + REG_PATTERN_TEST(E1000_TXCW, 0xC000FFFF, 0x0000FFFF); + REG_PATTERN_TEST(E1000_TDBAL, 0xFFFFFFF0, 0xFFFFFFFF); + REG_PATTERN_TEST(E1000_TIDV, 0x0000FFFF, 0x0000FFFF); + for (i = 0; i < mac->rar_entry_count; i++) + REG_PATTERN_TEST_ARRAY(E1000_RA, ((i << 1) + 1), + 0x8003FFFF, 0xFFFFFFFF); for (i = 0; i < mac->mta_reg_count; i++) REG_PATTERN_TEST_ARRAY(E1000_MTA, i, 0xFFFFFFFF, 0xFFFFFFFF); -- cgit v1.2.3-70-g09d2 From 9974a356b204833b32173210ca25edfdc24dcdd5 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Sun, 7 Oct 2007 23:27:28 -0700 Subject: [TG3]: Walk PCI capability lists. Newer tg3 devices shuffle around the registers in PCI configuration space. This patch changes the way the driver accesses the PCI capabilities registers. Hardcoded register locations are replaced with offsets from pci_find_capability() return values. Signed-off-by: Matt Carlson Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 48 +++++++++++++++++++++++++++++++++++------------- drivers/net/tg3.h | 28 ++-------------------------- include/linux/pci_regs.h | 13 +++++++++++++ 3 files changed, 50 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index d4ac6e9ef6d..4f9fbe268ec 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -4865,9 +4865,15 @@ static void tg3_restore_pci_state(struct tg3 *tp) pci_write_config_dword(tp->pdev, TG3PCI_COMMAND, tp->pci_cmd); /* Make sure PCI-X relaxed ordering bit is clear. */ - pci_read_config_dword(tp->pdev, TG3PCI_X_CAPS, &val); - val &= ~PCIX_CAPS_RELAXED_ORDERING; - pci_write_config_dword(tp->pdev, TG3PCI_X_CAPS, val); + if (tp->pcix_cap) { + u16 pcix_cmd; + + pci_read_config_word(tp->pdev, tp->pcix_cap + PCI_X_CMD, + &pcix_cmd); + pcix_cmd &= ~PCI_X_CMD_ERO; + pci_write_config_word(tp->pdev, tp->pcix_cap + PCI_X_CMD, + pcix_cmd); + } if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) { @@ -6574,16 +6580,20 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32_f(WDMAC_MODE, val); udelay(40); - if ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) != 0) { - val = tr32(TG3PCI_X_CAPS); + if (tp->tg3_flags & TG3_FLAG_PCIX_MODE) { + u16 pcix_cmd; + + pci_read_config_word(tp->pdev, tp->pcix_cap + PCI_X_CMD, + &pcix_cmd); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) { - val &= ~PCIX_CAPS_BURST_MASK; - val |= (PCIX_CAPS_MAX_BURST_CPIOB << PCIX_CAPS_BURST_SHIFT); + pcix_cmd &= ~PCI_X_CMD_MAX_READ; + pcix_cmd |= PCI_X_CMD_READ_2K; } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) { - val &= ~(PCIX_CAPS_SPLIT_MASK | PCIX_CAPS_BURST_MASK); - val |= (PCIX_CAPS_MAX_BURST_CPIOB << PCIX_CAPS_BURST_SHIFT); + pcix_cmd &= ~(PCI_X_CMD_MAX_SPLIT | PCI_X_CMD_MAX_READ); + pcix_cmd |= PCI_X_CMD_READ_2K; } - tw32(TG3PCI_X_CAPS, val); + pci_write_config_word(tp->pdev, tp->pcix_cap + PCI_X_CMD, + pcix_cmd); } tw32_f(RDMAC_MODE, rdmac_mode); @@ -10712,10 +10722,20 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) cacheline_sz_reg); } + if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) || + (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) { + tp->pcix_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_PCIX); + if (!tp->pcix_cap) { + printk(KERN_ERR PFX "Cannot find PCI-X " + "capability, aborting.\n"); + return -EIO; + } + } + pci_read_config_dword(tp->pdev, TG3PCI_PCISTATE, &pci_state_reg); - if ((pci_state_reg & PCISTATE_CONV_PCI_MODE) == 0) { + if (tp->pcix_cap && (pci_state_reg & PCISTATE_CONV_PCI_MODE) == 0) { tp->tg3_flags |= TG3_FLAG_PCIX_MODE; /* If this is a 5700 BX chipset, and we are in PCI-X @@ -10733,11 +10753,13 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) * space registers clobbered due to this bug. * So explicitly force the chip into D0 here. */ - pci_read_config_dword(tp->pdev, TG3PCI_PM_CTRL_STAT, + pci_read_config_dword(tp->pdev, + tp->pm_cap + PCI_PM_CTRL, &pm_reg); pm_reg &= ~PCI_PM_CTRL_STATE_MASK; pm_reg |= PCI_PM_CTRL_PME_ENABLE | 0 /* D0 */; - pci_write_config_dword(tp->pdev, TG3PCI_PM_CTRL_STAT, + pci_write_config_dword(tp->pdev, + tp->pm_cap + PCI_PM_CTRL, pm_reg); /* Also, force SERR#/PERR# in PCI command. */ diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index a6a23bbcdfe..c4f845dd1e8 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -57,32 +57,7 @@ #define TG3PCI_IRQ_PIN 0x0000003d #define TG3PCI_MIN_GNT 0x0000003e #define TG3PCI_MAX_LAT 0x0000003f -#define TG3PCI_X_CAPS 0x00000040 -#define PCIX_CAPS_RELAXED_ORDERING 0x00020000 -#define PCIX_CAPS_SPLIT_MASK 0x00700000 -#define PCIX_CAPS_SPLIT_SHIFT 20 -#define PCIX_CAPS_BURST_MASK 0x000c0000 -#define PCIX_CAPS_BURST_SHIFT 18 -#define PCIX_CAPS_MAX_BURST_CPIOB 2 -#define TG3PCI_PM_CAP_PTR 0x00000041 -#define TG3PCI_X_COMMAND 0x00000042 -#define TG3PCI_X_STATUS 0x00000044 -#define TG3PCI_PM_CAP_ID 0x00000048 -#define TG3PCI_VPD_CAP_PTR 0x00000049 -#define TG3PCI_PM_CAPS 0x0000004a -#define TG3PCI_PM_CTRL_STAT 0x0000004c -#define TG3PCI_BR_SUPP_EXT 0x0000004e -#define TG3PCI_PM_DATA 0x0000004f -#define TG3PCI_VPD_CAP_ID 0x00000050 -#define TG3PCI_MSI_CAP_PTR 0x00000051 -#define TG3PCI_VPD_ADDR_FLAG 0x00000052 -#define VPD_ADDR_FLAG_WRITE 0x00008000 -#define TG3PCI_VPD_DATA 0x00000054 -#define TG3PCI_MSI_CAP_ID 0x00000058 -#define TG3PCI_NXT_CAP_PTR 0x00000059 -#define TG3PCI_MSI_CTRL 0x0000005a -#define TG3PCI_MSI_ADDR_LOW 0x0000005c -#define TG3PCI_MSI_ADDR_HIGH 0x00000060 +/* 0x40 --> 0x64 unused */ #define TG3PCI_MSI_DATA 0x00000064 /* 0x66 --> 0x68 unused */ #define TG3PCI_MISC_HOST_CTRL 0x00000068 @@ -2318,6 +2293,7 @@ struct tg3 { int pm_cap; int msi_cap; + int pcix_cap; /* PHY info */ u32 phy_id; diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h index 495d368390e..423d592c55d 100644 --- a/include/linux/pci_regs.h +++ b/include/linux/pci_regs.h @@ -316,7 +316,20 @@ #define PCI_X_CMD 2 /* Modes & Features */ #define PCI_X_CMD_DPERR_E 0x0001 /* Data Parity Error Recovery Enable */ #define PCI_X_CMD_ERO 0x0002 /* Enable Relaxed Ordering */ +#define PCI_X_CMD_READ_512 0x0000 /* 512 byte maximum read byte count */ +#define PCI_X_CMD_READ_1K 0x0004 /* 1Kbyte maximum read byte count */ +#define PCI_X_CMD_READ_2K 0x0008 /* 2Kbyte maximum read byte count */ +#define PCI_X_CMD_READ_4K 0x000c /* 4Kbyte maximum read byte count */ #define PCI_X_CMD_MAX_READ 0x000c /* Max Memory Read Byte Count */ + /* Max # of outstanding split transactions */ +#define PCI_X_CMD_SPLIT_1 0x0000 /* Max 1 */ +#define PCI_X_CMD_SPLIT_2 0x0010 /* Max 2 */ +#define PCI_X_CMD_SPLIT_3 0x0020 /* Max 3 */ +#define PCI_X_CMD_SPLIT_4 0x0030 /* Max 4 */ +#define PCI_X_CMD_SPLIT_8 0x0040 /* Max 8 */ +#define PCI_X_CMD_SPLIT_12 0x0050 /* Max 12 */ +#define PCI_X_CMD_SPLIT_16 0x0060 /* Max 16 */ +#define PCI_X_CMD_SPLIT_32 0x0070 /* Max 32 */ #define PCI_X_CMD_MAX_SPLIT 0x0070 /* Max Outstanding Split Transactions */ #define PCI_X_CMD_VERSION(x) (((x) >> 12) & 3) /* Version */ #define PCI_X_STATUS 4 /* PCI-X capabilities */ -- cgit v1.2.3-70-g09d2 From 795d01c523dd9f22acc70fe86ed30e605e00024d Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Sun, 7 Oct 2007 23:28:17 -0700 Subject: [TG3]: ASIC decoding and basic CPMU support. Newer products change the way the ASIC revision is obtained. This patch implements how the driver will extract the revision number. This patch also adds preliminary CPMU support. CPMU stands for Central Power Management Unit. The CPMU's role is to put the chip into lower power states when the operating conditions allow it. Signed-off-by: Matt Carlson Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 21 ++++++++++++++++----- drivers/net/tg3.h | 9 ++++++--- 2 files changed, 22 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 4f9fbe268ec..482b7df5524 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -595,7 +595,8 @@ static void tg3_switch_clocks(struct tg3 *tp) u32 clock_ctrl = tr32(TG3PCI_CLOCK_CTRL); u32 orig_clock_ctrl; - if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) + if ((tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) || + (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) return; orig_clock_ctrl = clock_ctrl; @@ -1400,6 +1401,7 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) tw32_wait_f(TG3PCI_CLOCK_CTRL, base_val | CLOCK_CTRL_ALTCLK | CLOCK_CTRL_PWRDOWN_PLL133, 40); } else if ((tp->tg3_flags2 & TG3_FLG2_5780_CLASS) || + (tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) || (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)) { /* do nothing */ } else if (!((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) && @@ -6147,11 +6149,13 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) /* This works around an issue with Athlon chipsets on * B3 tigon3 silicon. This bit has no effect on any * other revision. But do not set this on PCI Express - * chips. + * chips and don't even touch the clocks if the CPMU is present. */ - if (!(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS)) - tp->pci_clock_ctrl |= CLOCK_CTRL_DELAY_PCI_GRANT; - tw32_f(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl); + if (!(tp->tg3_flags & TG3_FLAG_CPMU_PRESENT)) { + if (!(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS)) + tp->pci_clock_ctrl |= CLOCK_CTRL_DELAY_PCI_GRANT; + tw32_f(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl); + } if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 && (tp->tg3_flags & TG3_FLAG_PCIX_MODE)) { @@ -10527,6 +10531,13 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->pci_chip_rev_id = (misc_ctrl_reg >> MISC_HOST_CTRL_CHIPREV_SHIFT); + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_USE_PROD_ID_REG) { + u32 prod_id_asic_rev; + + pci_read_config_dword(tp->pdev, TG3PCI_PRODID_ASICREV, + &prod_id_asic_rev); + tp->pci_chip_rev_id = prod_id_asic_rev & PROD_ID_ASIC_REV_MASK; + } /* Wrong chip ID in 5752 A0. This code can be removed later * as A0 is not in production. diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index c4f845dd1e8..79ce68cf836 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -121,6 +121,7 @@ #define ASIC_REV_5755 0x0a #define ASIC_REV_5787 0x0b #define ASIC_REV_5906 0x0c +#define ASIC_REV_USE_PROD_ID_REG 0x0f #define GET_CHIP_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 8) #define CHIPREV_5700_AX 0x70 #define CHIPREV_5700_BX 0x71 @@ -214,7 +215,9 @@ #define TG3PCI_DUAL_MAC_CTRL 0x000000b8 #define DUAL_MAC_CTRL_CH_MASK 0x00000003 #define DUAL_MAC_CTRL_ID 0x00000004 -/* 0xbc --> 0x100 unused */ +#define TG3PCI_PRODID_ASICREV 0x000000bc +#define PROD_ID_ASIC_REV_MASK 0x0fffffff +/* 0xc0 --> 0x100 unused */ /* 0x100 --> 0x200 unused */ @@ -2213,7 +2216,7 @@ struct tg3 { #define TG3_FLAG_JUMBO_RING_ENABLE 0x00800000 #define TG3_FLAG_10_100_ONLY 0x01000000 #define TG3_FLAG_PAUSE_AUTONEG 0x02000000 - +#define TG3_FLAG_CPMU_PRESENT 0x04000000 #define TG3_FLAG_40BIT_DMA_BUG 0x08000000 #define TG3_FLAG_BROKEN_CHECKSUMS 0x10000000 #define TG3_FLAG_SUPPORT_MSI 0x20000000 @@ -2285,7 +2288,7 @@ struct tg3 { u32 pwrmgmt_thresh; /* PCI block */ - u16 pci_chip_rev_id; + u32 pci_chip_rev_id; u8 pci_cacheline_sz; u8 pci_lat_timer; u8 pci_hdr_type; -- cgit v1.2.3-70-g09d2 From d30cdd28fba556143a4bb0d1a6097ebcc2891477 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Sun, 7 Oct 2007 23:28:35 -0700 Subject: [TG3]: Add 5784 and 5764 support. This patch adds the support for 5784 and 5764 devices. Signed-off-by: Matt Carlson Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 53 +++++++++++++++++++++++++++++++++++++++---------- drivers/net/tg3.h | 14 ++++++++++++- include/linux/pci_ids.h | 2 ++ 3 files changed, 57 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 482b7df5524..2378ea3f357 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -198,6 +198,8 @@ static struct pci_device_id tg3_pci_tbl[] = { {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5781)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5906)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5906M)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5784)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5764)}, {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX)}, {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9MXX)}, {PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000)}, @@ -4921,7 +4923,8 @@ static int tg3_chip_reset(struct tg3 *tp) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784) tw32(GRC_FASTBOOT_PC, 0); /* @@ -6146,6 +6149,12 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tg3_write_sig_legacy(tp, RESET_KIND_INIT); + if (tp->pci_chip_rev_id == CHIPREV_ID_5784_A0) { + val = tr32(TG3_CPMU_CTRL); + val &= ~(CPMU_CTRL_LINK_AWARE_MODE | CPMU_CTRL_LINK_IDLE_MODE); + tw32(TG3_CPMU_CTRL, val); + } + /* This works around an issue with Athlon chipsets on * B3 tigon3 silicon. This bit has no effect on any * other revision. But do not set this on PCI Express @@ -6180,10 +6189,12 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) if (err) return err; - /* This value is determined during the probe time DMA - * engine test, tg3_test_dma. - */ - tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl); + if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784) { + /* This value is determined during the probe time DMA + * engine test, tg3_test_dma. + */ + tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl); + } tp->grc_mode &= ~(GRC_MODE_HOST_SENDBDS | GRC_MODE_4X_NIC_SEND_RINGS | @@ -6417,6 +6428,11 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) RDMAC_MODE_FIFOURUN_ENAB | RDMAC_MODE_FIFOOREAD_ENAB | RDMAC_MODE_LNGREAD_ENAB); + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784) + rdmac_mode |= RDMAC_MODE_BD_SBD_CRPT_ENAB | + RDMAC_MODE_MBUF_RBD_CRPT_ENAB | + RDMAC_MODE_MBUF_SBD_CRPT_ENAB; + /* If statement applies to 5705 and 5750 PCI devices only */ if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 && tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) || @@ -6578,7 +6594,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) /* Enable host coalescing bug fix */ if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755) || - (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)) + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) || + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784)) val |= (1 << 29); tw32_f(WDMAC_MODE, val); @@ -8353,7 +8370,8 @@ static int tg3_set_tx_csum(struct net_device *dev, u32 data) } if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784) ethtool_op_set_tx_ipv6_csum(dev, data); else ethtool_op_set_tx_csum(dev, data); @@ -8849,7 +8867,8 @@ static int tg3_test_memory(struct tg3 *tp) if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) { if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784) mem_tbl = mem_tbl_5755; else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) mem_tbl = mem_tbl_5906; @@ -9600,7 +9619,8 @@ static void __devinit tg3_nvram_init(struct tg3 *tp) tg3_get_5752_nvram_info(tp); else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755) tg3_get_5755_nvram_info(tp); - else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) + else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784) tg3_get_5787_nvram_info(tp); else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) tg3_get_5906_nvram_info(tp); @@ -9913,6 +9933,7 @@ static int tg3_nvram_write_block_buffered(struct tg3 *tp, u32 offset, u32 len, if ((GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752) && (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5755) && (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787) && + (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784) && (tp->nvram_jedecnum == JEDEC_ST) && (nvram_cmd & NVRAM_CMD_FIRST)) { @@ -10657,6 +10678,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 || (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) tp->tg3_flags2 |= TG3_FLG2_5750_PLUS; @@ -10676,6 +10698,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { tp->tg3_flags2 |= TG3_FLG2_HW_TSO_2; tp->tg3_flags2 |= TG3_FLG2_1SHOT_MSI; @@ -10693,6 +10716,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752 && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5755 && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787 && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784 && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906) tp->tg3_flags2 |= TG3_FLG2_JUMBO_CAPABLE; @@ -10868,6 +10892,9 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) */ tg3_get_eeprom_hw_cfg(tp); + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784) + tp->tg3_flags |= TG3_FLAG_CPMU_PRESENT; + /* Set up tp->grc_local_ctrl before calling tg3_set_power_state(). * GPIO1 driven high will bring 5700's external PHY out of reset. * It is also used as eeprom write protect on LOMs. @@ -10934,7 +10961,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) { if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) { + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784) { if (tp->pdev->device != PCI_DEVICE_ID_TIGON3_5756 && tp->pdev->device != PCI_DEVICE_ID_TIGON3_5722) tp->tg3_flags2 |= TG3_FLG2_PHY_JITTER_BUG; @@ -11077,6 +11105,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) */ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) tp->dev->hard_start_xmit = tg3_start_xmit; else @@ -11698,6 +11727,7 @@ static char * __devinit tg3_phy_string(struct tg3 *tp) case PHY_ID_BCM5780: return "5780"; case PHY_ID_BCM5755: return "5755"; case PHY_ID_BCM5787: return "5787"; + case PHY_ID_BCM5784: return "5784"; case PHY_ID_BCM5756: return "5722/5756"; case PHY_ID_BCM5906: return "5906"; case PHY_ID_BCM8002: return "8002/serdes"; @@ -12042,7 +12072,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, if ((tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS) == 0) { dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784) dev->features |= NETIF_F_IPV6_CSUM; tp->tg3_flags |= TG3_FLAG_RX_CHECKSUMS; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 79ce68cf836..d8e829f6fcb 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -108,6 +108,7 @@ #define CHIPREV_ID_5752_A1 0x6001 #define CHIPREV_ID_5714_A2 0x9002 #define CHIPREV_ID_5906_A1 0xc001 +#define CHIPREV_ID_5784_A0 0x5784000 #define GET_ASIC_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 12) #define ASIC_REV_5700 0x07 #define ASIC_REV_5701 0x00 @@ -122,6 +123,7 @@ #define ASIC_REV_5787 0x0b #define ASIC_REV_5906 0x0c #define ASIC_REV_USE_PROD_ID_REG 0x0f +#define ASIC_REV_5784 0x5784 #define GET_CHIP_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 8) #define CHIPREV_5700_AX 0x70 #define CHIPREV_5700_BX 0x71 @@ -843,7 +845,13 @@ #define RCVLSC_MODE_ATTN_ENABLE 0x00000004 #define RCVLSC_STATUS 0x00003404 #define RCVLSC_STATUS_ERROR_ATTN 0x00000004 -/* 0x3408 --> 0x3800 unused */ +/* 0x3408 --> 0x3600 unused */ + +/* CPMU registers */ +#define TG3_CPMU_CTRL 0x00003600 +#define CPMU_CTRL_LINK_IDLE_MODE 0x00000200 +#define CPMU_CTRL_LINK_AWARE_MODE 0x00000400 +/* 0x3604 --> 0x3800 unused */ /* Mbuf cluster free registers */ #define MBFREE_MODE 0x00003800 @@ -1023,7 +1031,10 @@ #define RDMAC_MODE_FIFOOREAD_ENAB 0x00000100 #define RDMAC_MODE_LNGREAD_ENAB 0x00000200 #define RDMAC_MODE_SPLIT_ENABLE 0x00000800 +#define RDMAC_MODE_BD_SBD_CRPT_ENAB 0x00000800 #define RDMAC_MODE_SPLIT_RESET 0x00001000 +#define RDMAC_MODE_MBUF_RBD_CRPT_ENAB 0x00001000 +#define RDMAC_MODE_MBUF_SBD_CRPT_ENAB 0x00002000 #define RDMAC_MODE_FIFO_SIZE_128 0x00020000 #define RDMAC_MODE_FIFO_LONG_BURST 0x00030000 #define RDMAC_STATUS 0x00004804 @@ -2315,6 +2326,7 @@ struct tg3 { #define PHY_ID_BCM5755 0xbc050cc0 #define PHY_ID_BCM5787 0xbc050ce0 #define PHY_ID_BCM5756 0xbc050ed0 +#define PHY_ID_BCM5784 0xbc050fa0 #define PHY_ID_BCM5906 0xdc00ac40 #define PHY_ID_BCM8002 0x60010140 #define PHY_ID_INVALID 0xffffffff diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 9ebc2c70c5d..6f5fa39c829 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1950,8 +1950,10 @@ #define PCI_DEVICE_ID_TIGON3_5751M 0x167d #define PCI_DEVICE_ID_TIGON3_5751F 0x167e #define PCI_DEVICE_ID_TIGON3_5787F 0x167f +#define PCI_DEVICE_ID_TIGON3_5764 0x1684 #define PCI_DEVICE_ID_TIGON3_5787M 0x1693 #define PCI_DEVICE_ID_TIGON3_5782 0x1696 +#define PCI_DEVICE_ID_TIGON3_5784 0x1698 #define PCI_DEVICE_ID_TIGON3_5786 0x169a #define PCI_DEVICE_ID_TIGON3_5787 0x169b #define PCI_DEVICE_ID_TIGON3_5788 0x169c -- cgit v1.2.3-70-g09d2 From 182f6ed5188ccb46d1c54c3334943a54110d0118 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sun, 7 Oct 2007 23:29:06 -0700 Subject: [TG3]: Update version to 3.82. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 2378ea3f357..b1e5660baf4 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -64,8 +64,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.81" -#define DRV_MODULE_RELDATE "September 5, 2007" +#define DRV_MODULE_VERSION "3.82" +#define DRV_MODULE_RELDATE "October 5, 2007" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 -- cgit v1.2.3-70-g09d2 From 630e499724bda4ecb62b1f6652656e886f04197f Mon Sep 17 00:00:00 2001 From: Alex Villacís Lasso Date: Mon, 8 Oct 2007 01:07:28 -0700 Subject: [IRDA]: Oops fix for ksdazzle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes a kernel oops triggered by the ksdazzle SIR driver. We need more space for input frames, and 2048 should be plenty of it. Signed-off-by: Alex Villacís Lasso Signed-off-by: Samuel Ortiz Signed-off-by: David S. Miller --- drivers/net/irda/ksdazzle-sir.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/irda/ksdazzle-sir.c b/drivers/net/irda/ksdazzle-sir.c index af60f2435a3..d01a28593ce 100644 --- a/drivers/net/irda/ksdazzle-sir.c +++ b/drivers/net/irda/ksdazzle-sir.c @@ -1,7 +1,7 @@ /***************************************************************************** * * Filename: ksdazzle.c -* Version: 0.1.1 +* Version: 0.1.2 * Description: Irda KingSun Dazzle USB Dongle * Status: Experimental * Author: Alex Villacís Lasso @@ -113,6 +113,7 @@ MODULE_DEVICE_TABLE(usb, dongles); #define KINGSUN_REQ_SEND 0x09 #define KINGSUN_SND_FIFO_SIZE 2048 /* Max packet we can send */ +#define KINGSUN_RCV_MAX 2048 /* Max transfer we can receive */ struct ksdazzle_speedparams { __le32 baudrate; /* baud rate, little endian */ @@ -150,7 +151,7 @@ struct ksdazzle_cb { __u8 tx_payload[8]; struct urb *rx_urb; - __u8 rx_payload[8]; + __u8 *rx_buf; iobuff_t rx_unwrap_buff; struct usb_ctrlrequest *speed_setuprequest; @@ -440,7 +441,8 @@ static int ksdazzle_net_open(struct net_device *netdev) /* Start reception. */ usb_fill_int_urb(kingsun->rx_urb, kingsun->usbdev, usb_rcvintpipe(kingsun->usbdev, kingsun->ep_in), - kingsun->rx_payload, 8, ksdazzle_rcv_irq, kingsun, 1); + kingsun->rx_buf, KINGSUN_RCV_MAX, ksdazzle_rcv_irq, + kingsun, 1); kingsun->rx_urb->status = 0; err = usb_submit_urb(kingsun->rx_urb, GFP_KERNEL); if (err) { @@ -641,6 +643,7 @@ static int ksdazzle_probe(struct usb_interface *intf, kingsun->tx_buf_clear_sent = 0; kingsun->rx_urb = NULL; + kingsun->rx_buf = NULL; kingsun->rx_unwrap_buff.in_frame = FALSE; kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME; kingsun->rx_unwrap_buff.skb = NULL; @@ -651,6 +654,11 @@ static int ksdazzle_probe(struct usb_interface *intf, kingsun->speed_urb = NULL; kingsun->speedparams.baudrate = 0; + /* Allocate input buffer */ + kingsun->rx_buf = kmalloc(KINGSUN_RCV_MAX, GFP_KERNEL); + if (!kingsun->rx_buf) + goto free_mem; + /* Allocate output buffer */ kingsun->tx_buf_clear = kmalloc(KINGSUN_SND_FIFO_SIZE, GFP_KERNEL); if (!kingsun->tx_buf_clear) @@ -714,6 +722,7 @@ static int ksdazzle_probe(struct usb_interface *intf, free_mem: kfree(kingsun->speed_setuprequest); kfree(kingsun->tx_buf_clear); + kfree(kingsun->rx_buf); free_netdev(net); err_out1: return ret; @@ -746,6 +755,7 @@ static void ksdazzle_disconnect(struct usb_interface *intf) kfree(kingsun->speed_setuprequest); kfree(kingsun->tx_buf_clear); + kfree(kingsun->rx_buf); free_netdev(kingsun->netdev); usb_set_intfdata(intf, NULL); -- cgit v1.2.3-70-g09d2 From 405d8e5cbbe5aca20cc745046b70831bfc5e4a8f Mon Sep 17 00:00:00 2001 From: Andy Gospodarek Date: Mon, 8 Oct 2007 01:08:47 -0700 Subject: [TG3]: Fix ethtool autonegotiate flags. I recently noticed that when calling: # ethtool -s eth0 autoneg on on a 5722 (though I'm sure it's not specific to that card) that subsequent checks of the cards status looked like this: # ethtool eth0 Settings for eth0: Supported ports: [ MII ] Supported link modes: 10baseT/Half 10baseT/Full 100baseT/Half 100baseT/Full 1000baseT/Half 1000baseT/Full Supports auto-negotiation: Yes Advertised link modes: 10baseT/Half 10baseT/Full 100baseT/Half 100baseT/Full 1000baseT/Half 1000baseT/Full Advertised auto-negotiation: No <---- This seems odd?!? Speed: 1000Mb/s Duplex: Full Port: Twisted Pair PHYAD: 1 Transceiver: internal Auto-negotiation: on Supports Wake-on: g Wake-on: d Current message level: 0x000000ff (255) Link detected: yes I noticed that the following commit: commit 3600d918d870456ea8e7bb9d47f327de5c20f3d6 Author: Michael Chan Date: Thu Dec 7 00:21:48 2006 -0800 [TG3]: Allow partial speed advertisement. Honor the advertisement bitmask from ethtool. We used to always advertise the full capability when autoneg was set to on. changed things around so that ethtool speed settings were strictly followed. Unfortunately ethtool doesn't seem to set ADVERTISED_Autoneg in the advertising field (and maybe it shouldn't have to). I'd vote that it should be fixed there, but it should also be added here just in case someone using ethtool ioctls in their own application gets what they want. Adding that flag in tg3_set_settings seemed like the most logical place since the driver works fine on boot. This is just an issue when re-enabling autonegotiation, so we should probably nip it there. Signed-off-by: Andy Gospodarek Acked-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index b1e5660baf4..1e0c9e0dc39 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -8101,7 +8101,8 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) tp->link_config.autoneg = cmd->autoneg; if (cmd->autoneg == AUTONEG_ENABLE) { - tp->link_config.advertising = cmd->advertising; + tp->link_config.advertising = (cmd->advertising | + ADVERTISED_Autoneg); tp->link_config.speed = SPEED_INVALID; tp->link_config.duplex = DUPLEX_INVALID; } else { -- cgit v1.2.3-70-g09d2 From d62a38d1ab350f787e4941e42a3d3e97971e38f5 Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Mon, 8 Oct 2007 20:37:11 -0700 Subject: [ISDN]: Change I4L to use alloc_netdev(). Signed-off-by: Karsten Keil Signed-off-by: David S. Miller --- drivers/isdn/i4l/isdn_net.c | 169 +++++++++++++++++++++++--------------------- drivers/isdn/i4l/isdn_ppp.c | 6 +- include/linux/isdn.h | 2 +- 3 files changed, 92 insertions(+), 85 deletions(-) (limited to 'drivers') diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c index 54546604656..7c9cb7e19f2 100644 --- a/drivers/isdn/i4l/isdn_net.c +++ b/drivers/isdn/i4l/isdn_net.c @@ -77,7 +77,7 @@ static __inline__ int isdn_net_device_started(isdn_net_dev *n) if (lp->master) dev = lp->master; else - dev = &n->dev; + dev = n->dev; return netif_running(dev); } @@ -90,7 +90,7 @@ static __inline__ void isdn_net_device_wake_queue(isdn_net_local *lp) if (lp->master) netif_wake_queue(lp->master); else - netif_wake_queue(&lp->netdev->dev); + netif_wake_queue(lp->netdev->dev); } /* @@ -102,7 +102,7 @@ static __inline__ void isdn_net_device_stop_queue(isdn_net_local *lp) if (lp->master) netif_stop_queue(lp->master); else - netif_stop_queue(&lp->netdev->dev); + netif_stop_queue(lp->netdev->dev); } /* @@ -287,7 +287,7 @@ isdn_net_unbind_channel(isdn_net_local * lp) BEWARE! This chunk of code cannot be called from hardware interrupt handler. I hope it is true. --ANK */ - qdisc_reset(lp->netdev->dev.qdisc); + qdisc_reset(lp->netdev->dev->qdisc); } lp->dialstate = 0; dev->rx_netdev[isdn_dc2minor(lp->isdn_device, lp->isdn_channel)] = NULL; @@ -345,27 +345,27 @@ isdn_net_autohup(void) l->chargetime += l->chargeint; if (time_after(jiffies, l->chargetime + l->chargeint - 2 * HZ)) if (l->outgoing || l->hupflags & ISDN_INHUP) - isdn_net_hangup(&p->dev); + isdn_net_hangup(p->dev); } else if (l->outgoing) { if (l->hupflags & ISDN_CHARGEHUP) { if (l->hupflags & ISDN_WAITCHARGE) { printk(KERN_DEBUG "isdn_net: Hupflags of %s are %X\n", l->name, l->hupflags); - isdn_net_hangup(&p->dev); + isdn_net_hangup(p->dev); } else if (time_after(jiffies, l->chargetime + l->chargeint)) { printk(KERN_DEBUG "isdn_net: %s: chtime = %lu, chint = %d\n", l->name, l->chargetime, l->chargeint); - isdn_net_hangup(&p->dev); + isdn_net_hangup(p->dev); } } else - isdn_net_hangup(&p->dev); + isdn_net_hangup(p->dev); } else if (l->hupflags & ISDN_INHUP) - isdn_net_hangup(&p->dev); + isdn_net_hangup(p->dev); } if(dev->global_flags & ISDN_GLOBAL_STOPPED || (ISDN_NET_DIALMODE(*l) == ISDN_NET_DM_OFF)) { - isdn_net_hangup(&p->dev); + isdn_net_hangup(p->dev); break; } } @@ -579,7 +579,7 @@ isdn_net_dial(void) if (!lp->dial) { printk(KERN_WARNING "%s: phone number deleted?\n", lp->name); - isdn_net_hangup(&p->dev); + isdn_net_hangup(p->dev); break; } anymore = 1; @@ -616,8 +616,8 @@ isdn_net_dial(void) s = "dial suppressed: isdn system stopped"; else s = "dial suppressed: dialmode `off'"; - isdn_net_unreachable(&p->dev, NULL, s); - isdn_net_hangup(&p->dev); + isdn_net_unreachable(p->dev, NULL, s); + isdn_net_hangup(p->dev); break; } cmd.driver = lp->isdn_device; @@ -633,7 +633,7 @@ isdn_net_dial(void) if (!lp->dial) { printk(KERN_WARNING "%s: phone number deleted?\n", lp->name); - isdn_net_hangup(&p->dev); + isdn_net_hangup(p->dev); break; } if (!strncmp(lp->dial->num, "LEASED", strlen("LEASED"))) { @@ -644,8 +644,8 @@ isdn_net_dial(void) if (time_after(jiffies, lp->dialstarted + lp->dialtimeout)) { lp->dialwait_timer = jiffies + lp->dialwait; lp->dialstarted = 0; - isdn_net_unreachable(&p->dev, NULL, "dial: timed out"); - isdn_net_hangup(&p->dev); + isdn_net_unreachable(p->dev, NULL, "dial: timed out"); + isdn_net_hangup(p->dev); break; } @@ -674,9 +674,9 @@ isdn_net_dial(void) if (lp->dialtimeout == 0) { lp->dialwait_timer = jiffies + lp->dialwait; lp->dialstarted = 0; - isdn_net_unreachable(&p->dev, NULL, "dial: tried all numbers dialmax times"); + isdn_net_unreachable(p->dev, NULL, "dial: tried all numbers dialmax times"); } - isdn_net_hangup(&p->dev); + isdn_net_hangup(p->dev); break; } } @@ -758,7 +758,7 @@ isdn_net_dial(void) cmd.arg = lp->isdn_channel + (lp->l3_proto << 8); isdn_command(&cmd); if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT15) - isdn_net_hangup(&p->dev); + isdn_net_hangup(p->dev); else { anymore = 1; lp->dialstate++; @@ -781,7 +781,7 @@ isdn_net_dial(void) printk(KERN_DEBUG "dialtimer4: %d\n", lp->dtimer); #endif if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10) - isdn_net_hangup(&p->dev); + isdn_net_hangup(p->dev); else anymore = 1; break; @@ -1618,7 +1618,7 @@ isdn_net_ciscohdlck_slarp_send_reply(isdn_net_local *lp) __be32 addr = 0; /* local ipv4 address */ __be32 mask = 0; /* local netmask */ - if ((in_dev = lp->netdev->dev.ip_ptr) != NULL) { + if ((in_dev = lp->netdev->dev->ip_ptr) != NULL) { /* take primary(first) address of interface */ struct in_ifaddr *ifa = in_dev->ifa_list; if (ifa != NULL) { @@ -1866,7 +1866,7 @@ isdn_net_rcv_skb(int idx, struct sk_buff *skb) isdn_net_local *lp = p->local; if ((lp->flags & ISDN_NET_CONNECTED) && (!lp->dialstate)) { - isdn_net_receive(&p->dev, skb); + isdn_net_receive(p->dev, skb); return 1; } } @@ -2506,6 +2506,42 @@ isdn_net_force_dial(char *name) return (isdn_net_force_dial_lp(p->local)); } +/* + * Helper for alloc_netdev() + */ +static void _isdn_setup(struct net_device *dev) +{ + isdn_net_local *lp = dev->priv; + + dev->flags = IFF_NOARP | IFF_POINTOPOINT; + lp->p_encap = ISDN_NET_ENCAP_RAWIP; + lp->magic = ISDN_NET_MAGIC; + lp->last = lp; + lp->next = lp; + lp->isdn_device = -1; + lp->isdn_channel = -1; + lp->pre_device = -1; + lp->pre_channel = -1; + lp->exclusive = -1; + lp->ppp_slot = -1; + lp->pppbind = -1; + skb_queue_head_init(&lp->super_tx_queue); + lp->l2_proto = ISDN_PROTO_L2_X75I; + lp->l3_proto = ISDN_PROTO_L3_TRANS; + lp->triggercps = 6000; + lp->slavedelay = 10 * HZ; + lp->hupflags = ISDN_INHUP; /* Do hangup even on incoming calls */ + lp->onhtime = 10; /* Default hangup-time for saving costs */ + lp->dialmax = 1; + /* Hangup before Callback, manual dial */ + lp->flags = ISDN_NET_CBHUP | ISDN_NET_DM_MANUAL; + lp->cbdelay = 25; /* Wait 5 secs before Callback */ + lp->dialtimeout = -1; /* Infinite Dial-Timeout */ + lp->dialwait = 5 * HZ; /* Wait 5 sec. after failed dial */ + lp->dialstarted = 0; /* Jiffies of last dial-start */ + lp->dialwait_timer = 0; /* Jiffies of earliest next dial-start */ +} + /* * Allocate a new network-interface and initialize its data structures. */ @@ -2519,23 +2555,21 @@ isdn_net_new(char *name, struct net_device *master) printk(KERN_WARNING "isdn_net: interface %s already exists\n", name); return NULL; } + if (name == NULL) + name = " "; if (!(netdev = kzalloc(sizeof(isdn_net_dev), GFP_KERNEL))) { printk(KERN_WARNING "isdn_net: Could not allocate net-device\n"); return NULL; } - if (!(netdev->local = kzalloc(sizeof(isdn_net_local), GFP_KERNEL))) { - printk(KERN_WARNING "isdn_net: Could not allocate device locals\n"); + netdev->dev = alloc_netdev(sizeof(isdn_net_local), name, _isdn_setup); + if (!netdev->dev) { + printk(KERN_WARNING "isdn_net: Could not allocate network device\n"); kfree(netdev); return NULL; } - if (name == NULL) - strcpy(netdev->local->name, " "); - else - strcpy(netdev->local->name, name); - strcpy(netdev->dev.name, netdev->local->name); - netdev->dev.priv = netdev->local; - netdev->dev.init = isdn_net_init; - netdev->local->p_encap = ISDN_NET_ENCAP_RAWIP; + netdev->local = netdev->dev->priv; + strcpy(netdev->local->name, netdev->dev->name); + netdev->dev->init = isdn_net_init; if (master) { /* Device shall be a slave */ struct net_device *p = (((isdn_net_local *) master->priv)->slave); @@ -2547,60 +2581,33 @@ isdn_net_new(char *name, struct net_device *master) q = p; p = (((isdn_net_local *) p->priv)->slave); } - ((isdn_net_local *) q->priv)->slave = &(netdev->dev); + ((isdn_net_local *) q->priv)->slave = netdev->dev; } else { /* Device shall be a master */ /* * Watchdog timer (currently) for master only. */ - netdev->dev.tx_timeout = isdn_net_tx_timeout; - netdev->dev.watchdog_timeo = ISDN_NET_TX_TIMEOUT; - if (register_netdev(&netdev->dev) != 0) { + netdev->dev->tx_timeout = isdn_net_tx_timeout; + netdev->dev->watchdog_timeo = ISDN_NET_TX_TIMEOUT; + if (register_netdev(netdev->dev) != 0) { printk(KERN_WARNING "isdn_net: Could not register net-device\n"); - kfree(netdev->local); + free_netdev(netdev->dev); kfree(netdev); return NULL; } } - netdev->local->magic = ISDN_NET_MAGIC; - netdev->queue = netdev->local; spin_lock_init(&netdev->queue_lock); - netdev->local->last = netdev->local; netdev->local->netdev = netdev; - netdev->local->next = netdev->local; INIT_WORK(&netdev->local->tqueue, isdn_net_softint); spin_lock_init(&netdev->local->xmit_lock); - netdev->local->isdn_device = -1; - netdev->local->isdn_channel = -1; - netdev->local->pre_device = -1; - netdev->local->pre_channel = -1; - netdev->local->exclusive = -1; - netdev->local->ppp_slot = -1; - netdev->local->pppbind = -1; - skb_queue_head_init(&netdev->local->super_tx_queue); - netdev->local->l2_proto = ISDN_PROTO_L2_X75I; - netdev->local->l3_proto = ISDN_PROTO_L3_TRANS; - netdev->local->triggercps = 6000; - netdev->local->slavedelay = 10 * HZ; - netdev->local->hupflags = ISDN_INHUP; /* Do hangup even on incoming calls */ - netdev->local->onhtime = 10; /* Default hangup-time for saving costs - of those who forget configuring this */ - netdev->local->dialmax = 1; - netdev->local->flags = ISDN_NET_CBHUP | ISDN_NET_DM_MANUAL; /* Hangup before Callback, manual dial */ - netdev->local->cbdelay = 25; /* Wait 5 secs before Callback */ - netdev->local->dialtimeout = -1; /* Infinite Dial-Timeout */ - netdev->local->dialwait = 5 * HZ; /* Wait 5 sec. after failed dial */ - netdev->local->dialstarted = 0; /* Jiffies of last dial-start */ - netdev->local->dialwait_timer = 0; /* Jiffies of earliest next dial-start */ - /* Put into to netdev-chain */ netdev->next = (void *) dev->netdev; dev->netdev = netdev; - return netdev->dev.name; + return netdev->dev->name; } char * @@ -2625,7 +2632,7 @@ isdn_net_newslave(char *parm) /* Master must not be started yet */ if (isdn_net_device_started(n)) return NULL; - return (isdn_net_new(newname, &(n->dev))); + return (isdn_net_new(newname, n->dev)); } return NULL; } @@ -2694,9 +2701,9 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg) lp->name); return -EINVAL; #else - p->dev.type = ARPHRD_PPP; /* change ARP type */ - p->dev.addr_len = 0; - p->dev.do_ioctl = isdn_ppp_dev_ioctl; + p->dev->type = ARPHRD_PPP; /* change ARP type */ + p->dev->addr_len = 0; + p->dev->do_ioctl = isdn_ppp_dev_ioctl; #endif break; case ISDN_NET_ENCAP_X25IFACE: @@ -2705,12 +2712,12 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg) p->local->name); return -EINVAL; #else - p->dev.type = ARPHRD_X25; /* change ARP type */ - p->dev.addr_len = 0; + p->dev->type = ARPHRD_X25; /* change ARP type */ + p->dev->addr_len = 0; #endif break; case ISDN_NET_ENCAP_CISCOHDLCK: - p->dev.do_ioctl = isdn_ciscohdlck_dev_ioctl; + p->dev->do_ioctl = isdn_ciscohdlck_dev_ioctl; break; default: if( cfg->p_encap >= 0 && @@ -2837,14 +2844,14 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg) } if (cfg->p_encap != lp->p_encap) { if (cfg->p_encap == ISDN_NET_ENCAP_RAWIP) { - p->dev.header_ops = NULL; - p->dev.flags = IFF_NOARP|IFF_POINTOPOINT; + p->dev->header_ops = NULL; + p->dev->flags = IFF_NOARP|IFF_POINTOPOINT; } else { - p->dev.header_ops = &isdn_header_ops; + p->dev->header_ops = &isdn_header_ops; if (cfg->p_encap == ISDN_NET_ENCAP_ETHER) - p->dev.flags = IFF_BROADCAST | IFF_MULTICAST; + p->dev->flags = IFF_BROADCAST | IFF_MULTICAST; else - p->dev.flags = IFF_NOARP|IFF_POINTOPOINT; + p->dev->flags = IFF_NOARP|IFF_POINTOPOINT; } } lp->p_encap = cfg->p_encap; @@ -3064,7 +3071,7 @@ isdn_net_force_hangup(char *name) isdn_net_hangup(q); q = (((isdn_net_local *) q->priv)->slave); } - isdn_net_hangup(&p->dev); + isdn_net_hangup(p->dev); return 0; } return -ENODEV; @@ -3092,11 +3099,11 @@ isdn_net_realrm(isdn_net_dev * p, isdn_net_dev * q) isdn_unexclusive_channel(p->local->pre_device, p->local->pre_channel); if (p->local->master) { /* It's a slave-device, so update master's slave-pointer if necessary */ - if (((isdn_net_local *) (p->local->master->priv))->slave == &p->dev) + if (((isdn_net_local *) (p->local->master->priv))->slave == p->dev) ((isdn_net_local *) (p->local->master->priv))->slave = p->local->slave; } else { /* Unregister only if it's a master-device */ - unregister_netdev(&p->dev); + unregister_netdev(p->dev); } /* Unlink device from chain */ spin_lock_irqsave(&dev->lock, flags); @@ -3124,7 +3131,7 @@ isdn_net_realrm(isdn_net_dev * p, isdn_net_dev * q) /* If no more net-devices remain, disable auto-hangup timer */ if (dev->netdev == NULL) isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 0); - kfree(p->local); + free_netdev(p->dev); kfree(p); return 0; diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c index 387392cb3d6..0e5e59f8434 100644 --- a/drivers/isdn/i4l/isdn_ppp.c +++ b/drivers/isdn/i4l/isdn_ppp.c @@ -360,7 +360,7 @@ isdn_ppp_release(int min, struct file *file) * isdn_ppp_free() sets is->lp to NULL and lp->ppp_slot to -1 * removing the IPPP_CONNECT flag omits calling of isdn_ppp_wakeup_daemon() */ - isdn_net_hangup(&p->dev); + isdn_net_hangup(p->dev); } for (i = 0; i < NUM_RCV_BUFFS; i++) { kfree(is->rq[i].buf); @@ -531,7 +531,7 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg) if (lp) { /* OK .. we are ready to send buffers */ is->pppcfg = val; /* isdn_ppp_xmit test for SC_ENABLE_IP !!! */ - netif_wake_queue(&lp->netdev->dev); + netif_wake_queue(lp->netdev->dev); break; } } @@ -1023,7 +1023,7 @@ void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buf static void isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb, int proto) { - struct net_device *dev = &net_dev->dev; + struct net_device *dev = net_dev->dev; struct ippp_struct *is, *mis; isdn_net_local *mlp = NULL; int slot; diff --git a/include/linux/isdn.h b/include/linux/isdn.h index a6fb366748b..ad09506554a 100644 --- a/include/linux/isdn.h +++ b/include/linux/isdn.h @@ -382,7 +382,7 @@ typedef struct isdn_net_dev_s { online */ spinlock_t queue_lock; /* lock to protect queue */ void *next; /* Pointer to next isdn-interface */ - struct net_device dev; /* interface to upper levels */ + struct net_device *dev; /* interface to upper levels */ #ifdef CONFIG_ISDN_PPP ippp_bundle * pb; /* pointer to the common bundle structure * with the per-bundle data */ -- cgit v1.2.3-70-g09d2 From 4665079cbb2a3e17de82f2ab2940b9f97f37d65e Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 8 Oct 2007 20:38:39 -0700 Subject: [NETNS]: Move some code into __init section when CONFIG_NET_NS=n With the net namespaces many code leaved the __init section, thus making the kernel occupy more memory than it did before. Since we have a config option that prohibits the namespace creation, the functions that initialize/finalize some netns stuff are simply not needed and can be freed after the boot. Currently, this is almost not noticeable, since few calls are no longer in __init, but when the namespaces will be merged it will be possible to free more code. I propose to use the __net_init, __net_exit and __net_initdata "attributes" for functions/variables that are not used if the CONFIG_NET_NS is not set to save more space in memory. The exiting functions cannot just reside in the __exit section, as noticed by David, since the init section will have references on it and the compilation will fail due to modpost checks. These references can exist, since the init namespace never dies and the exit callbacks are never called. So I introduce the __exit_refok attribute just like it is already done with the __init_refok. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- drivers/net/loopback.c | 6 +++--- fs/proc/proc_net.c | 8 ++++---- include/linux/init.h | 1 + include/net/net_namespace.h | 9 +++++++++ net/core/dev.c | 16 ++++++++-------- net/core/dev_mcast.c | 6 +++--- net/netlink/af_netlink.c | 6 +++--- scripts/mod/modpost.c | 1 + 8 files changed, 32 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index d6997aec45d..be25aa33971 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -250,7 +250,7 @@ static void loopback_setup(struct net_device *dev) } /* Setup and register the loopback device. */ -static int loopback_net_init(struct net *net) +static __net_init int loopback_net_init(struct net *net) { struct net_device *dev; int err; @@ -278,14 +278,14 @@ out_free_netdev: goto out; } -static void loopback_net_exit(struct net *net) +static __net_exit void loopback_net_exit(struct net *net) { struct net_device *dev = net->loopback_dev; unregister_netdev(dev); } -static struct pernet_operations loopback_net_ops = { +static struct pernet_operations __net_initdata loopback_net_ops = { .init = loopback_net_init, .exit = loopback_net_exit, }; diff --git a/fs/proc/proc_net.c b/fs/proc/proc_net.c index 85cc8e8bb86..2e91fb756e9 100644 --- a/fs/proc/proc_net.c +++ b/fs/proc/proc_net.c @@ -140,7 +140,7 @@ static struct inode_operations proc_net_dir_inode_operations = { .setattr = proc_net_setattr, }; -static int proc_net_ns_init(struct net *net) +static __net_init int proc_net_ns_init(struct net *net) { struct proc_dir_entry *root, *netd, *net_statd; int err; @@ -178,19 +178,19 @@ free_root: goto out; } -static void proc_net_ns_exit(struct net *net) +static __net_exit void proc_net_ns_exit(struct net *net) { remove_proc_entry("stat", net->proc_net); remove_proc_entry("net", net->proc_net_root); kfree(net->proc_net_root); } -struct pernet_operations proc_net_ns_ops = { +struct pernet_operations __net_initdata proc_net_ns_ops = { .init = proc_net_ns_init, .exit = proc_net_ns_exit, }; -int proc_net_init(void) +int __init proc_net_init(void) { proc_net_shadow = proc_mkdir("net", NULL); proc_net_shadow->proc_iops = &proc_net_dir_inode_operations; diff --git a/include/linux/init.h b/include/linux/init.h index 74b1f43bf98..f8d9d0b5cff 100644 --- a/include/linux/init.h +++ b/include/linux/init.h @@ -57,6 +57,7 @@ * The markers follow same syntax rules as __init / __initdata. */ #define __init_refok noinline __attribute__ ((__section__ (".text.init.refok"))) #define __initdata_refok __attribute__ ((__section__ (".data.init.refok"))) +#define __exit_refok noinline __attribute__ ((__section__ (".exit.text.refok"))) #ifdef MODULE #define __exit __attribute__ ((__section__(".exit.text"))) __cold diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 934c840b594..93aa87d3280 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -99,6 +99,15 @@ static inline void release_net(struct net *net) #define for_each_net(VAR) \ list_for_each_entry(VAR, &net_namespace_list, list) +#ifdef CONFIG_NET_NS +#define __net_init +#define __net_exit +#define __net_initdata +#else +#define __net_init __init +#define __net_exit __exit_refok +#define __net_initdata __initdata +#endif struct pernet_operations { struct list_head list; diff --git a/net/core/dev.c b/net/core/dev.c index 1aa07047826..e7e728aea9f 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2611,7 +2611,7 @@ static const struct file_operations ptype_seq_fops = { }; -static int dev_proc_net_init(struct net *net) +static int __net_init dev_proc_net_init(struct net *net) { int rc = -ENOMEM; @@ -2636,7 +2636,7 @@ out_dev: goto out; } -static void dev_proc_net_exit(struct net *net) +static void __net_exit dev_proc_net_exit(struct net *net) { wext_proc_exit(net); @@ -2645,7 +2645,7 @@ static void dev_proc_net_exit(struct net *net) proc_net_remove(net, "dev"); } -static struct pernet_operations dev_proc_ops = { +static struct pernet_operations __net_initdata dev_proc_ops = { .init = dev_proc_net_init, .exit = dev_proc_net_exit, }; @@ -4278,7 +4278,7 @@ static struct hlist_head *netdev_create_hash(void) } /* Initialize per network namespace state */ -static int netdev_init(struct net *net) +static int __net_init netdev_init(struct net *net) { INIT_LIST_HEAD(&net->dev_base_head); rwlock_init(&dev_base_lock); @@ -4299,18 +4299,18 @@ err_name: return -ENOMEM; } -static void netdev_exit(struct net *net) +static void __net_exit netdev_exit(struct net *net) { kfree(net->dev_name_head); kfree(net->dev_index_head); } -static struct pernet_operations netdev_net_ops = { +static struct pernet_operations __net_initdata netdev_net_ops = { .init = netdev_init, .exit = netdev_exit, }; -static void default_device_exit(struct net *net) +static void __net_exit default_device_exit(struct net *net) { struct net_device *dev, *next; /* @@ -4336,7 +4336,7 @@ static void default_device_exit(struct net *net) rtnl_unlock(); } -static struct pernet_operations default_device_ops = { +static struct pernet_operations __net_initdata default_device_ops = { .exit = default_device_exit, }; diff --git a/net/core/dev_mcast.c b/net/core/dev_mcast.c index 896b0ca5aed..15241cf48af 100644 --- a/net/core/dev_mcast.c +++ b/net/core/dev_mcast.c @@ -273,19 +273,19 @@ static const struct file_operations dev_mc_seq_fops = { #endif -static int dev_mc_net_init(struct net *net) +static int __net_init dev_mc_net_init(struct net *net) { if (!proc_net_fops_create(net, "dev_mcast", 0, &dev_mc_seq_fops)) return -ENOMEM; return 0; } -static void dev_mc_net_exit(struct net *net) +static void __net_exit dev_mc_net_exit(struct net *net) { proc_net_remove(net, "dev_mcast"); } -static struct pernet_operations dev_mc_net_ops = { +static struct pernet_operations __net_initdata dev_mc_net_ops = { .init = dev_mc_net_init, .exit = dev_mc_net_exit, }; diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 46eb5ea1fbd..3ef32825da7 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1924,7 +1924,7 @@ static struct net_proto_family netlink_family_ops = { .owner = THIS_MODULE, /* for consistency 8) */ }; -static int netlink_net_init(struct net *net) +static int __net_init netlink_net_init(struct net *net) { #ifdef CONFIG_PROC_FS if (!proc_net_fops_create(net, "netlink", 0, &netlink_seq_fops)) @@ -1933,14 +1933,14 @@ static int netlink_net_init(struct net *net) return 0; } -static void netlink_net_exit(struct net *net) +static void __net_exit netlink_net_exit(struct net *net) { #ifdef CONFIG_PROC_FS proc_net_remove(net, "netlink"); #endif } -static struct pernet_operations netlink_net_ops = { +static struct pernet_operations __net_initdata netlink_net_ops = { .init = netlink_net_init, .exit = netlink_net_exit, }; diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 6c145d6e89d..0a4051fbd34 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -709,6 +709,7 @@ static int secref_whitelist(const char *modname, const char *tosec, /* Check for pattern 0 */ if ((strncmp(fromsec, ".text.init.refok", strlen(".text.init.refok")) == 0) || + (strncmp(fromsec, ".exit.text.refok", strlen(".exit.text.refok")) == 0) || (strncmp(fromsec, ".data.init.refok", strlen(".data.init.refok")) == 0)) return 1; -- cgit v1.2.3-70-g09d2 From 46232d29f4088d87cdc2ee94cc911aadbdf00d32 Mon Sep 17 00:00:00 2001 From: Stefan Lippers-Hollmann Date: Fri, 5 Oct 2007 23:42:51 +0200 Subject: [PATCH] hostap_cs: Add device ID for Telekom T-Sinus 111card This adds the PCMCIA device ID for the Deutsche Telekom T-Sinus 111card to hostap_cs. $ /sbin/lspcmcia -v [...] Socket 0 Device 0: [hostap_cs] (bus ID: 0.0) Configuration: state: on Product Name: T-Sinus 111card 2.0.0 Identification: manf_id: 0x01bf card_id: 0x3301 function: 6 (network) prod_id(1): "T-Sinus" (0x8c389dc1) prod_id(2): "111card" (0x6a23ac17) prod_id(3): --- (---) prod_id(4): "2.0.0" (0x92b9effb) Signed-off-by: Stefan Lippers-Hollmann Signed-off-by: John W. Linville --- drivers/net/wireless/hostap/hostap_cs.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c index f9cf22bda42..2f8ea077a9e 100644 --- a/drivers/net/wireless/hostap/hostap_cs.c +++ b/drivers/net/wireless/hostap/hostap_cs.c @@ -822,6 +822,7 @@ static struct pcmcia_device_id hostap_cs_ids[] = { PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777), PCMCIA_DEVICE_MANF_CARD(0x0126, 0x8000), PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002), + PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x3301), PCMCIA_DEVICE_MANF_CARD(0x0250, 0x0002), PCMCIA_DEVICE_MANF_CARD(0x026f, 0x030b), PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1612), -- cgit v1.2.3-70-g09d2 From 61ef6062801b5ee8dcf18a90789713fbed249f1b Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Sun, 7 Oct 2007 16:24:26 +0100 Subject: [PATCH] zd1211rw: Add ID for TalkTalk SNU5630NS/05 Tested by Su-Jong You zd1211b chip 0471:1237 v4810 high 00-12-bf AL2230_RF pa0 g--N Signed-off-by: Daniel Drake Signed-off-by: John W. Linville --- drivers/net/wireless/zd1211rw/zd_usb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index 721d737e8d2..b0684f96576 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -76,6 +76,7 @@ static struct usb_device_id usb_ids[] = { { USB_DEVICE(0x129b, 0x1667), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x0cde, 0x001a), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x0586, 0x340a), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x0471, 0x1237), .driver_info = DEVICE_ZD1211B }, /* "Driverless" devices that need ejecting */ { USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER }, { USB_DEVICE(0x0ace, 0x20ff), .driver_info = DEVICE_INSTALLER }, -- cgit v1.2.3-70-g09d2 From 04dd9d39b48636d2698049304fdfb9ca59a88b54 Mon Sep 17 00:00:00 2001 From: Marcin Juszkiewicz Date: Sun, 7 Oct 2007 20:51:08 +0200 Subject: [PATCH] Add Linksys card to HostAP driver Socket 1: product info: "The Linksys Group, Inc.", "Wireless Network CF Card", "ISL37300P", "RevA" manfid: 0x0274, 0x3301 Signed-off-by: Marcin Juszkiewicz Signed-off-by: John W. Linville --- drivers/net/wireless/hostap/hostap_cs.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c index 2f8ea077a9e..877d3bdd37a 100644 --- a/drivers/net/wireless/hostap/hostap_cs.c +++ b/drivers/net/wireless/hostap/hostap_cs.c @@ -890,6 +890,10 @@ static struct pcmcia_device_id hostap_cs_ids[] = { PCMCIA_DEVICE_PROD_ID123( "corega", "WL PCCL-11", "ISL37300P", 0xa21501a, 0x59868926, 0xc9049a39), + PCMCIA_DEVICE_PROD_ID1234( + "The Linksys Group, Inc.", "Wireless Network CF Card", "ISL37300P", + "RevA", + 0xa5f472c2, 0x9c05598d, 0xc9049a39, 0x57a66194), PCMCIA_DEVICE_NULL }; MODULE_DEVICE_TABLE(pcmcia, hostap_cs_ids); -- cgit v1.2.3-70-g09d2 From 0b5316769774d1dc2fdd702e095f9e6992af269a Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 9 Oct 2007 13:55:24 -0400 Subject: [PATCH] ipw2200: batch non-user-requested scan result notifications ipw2200 makes extensive use of background scanning when unassociated or down. Unfortunately, the firmware sends scan completed events many times per second, which the driver pushes directly up to userspace. This needlessly wakes up processes listening for wireless events many times per second. Batch together scan completed events for non-user-requested scans and send them up to userspace every 4 seconds. Scan completed events resulting from an SIOCSIWSCAN call are pushed up without delay. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2200.c | 56 ++++++++++++++++++++++++++++++++++-------- drivers/net/wireless/ipw2200.h | 3 +++ 2 files changed, 49 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 2119a79dcc8..feb8fcbab2d 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -1740,8 +1740,10 @@ static int ipw_radio_kill_sw(struct ipw_priv *priv, int disable_radio) if (disable_radio) { priv->status |= STATUS_RF_KILL_SW; - if (priv->workqueue) + if (priv->workqueue) { cancel_delayed_work(&priv->request_scan); + cancel_delayed_work(&priv->scan_event); + } queue_work(priv->workqueue, &priv->down); } else { priv->status &= ~STATUS_RF_KILL_SW; @@ -1992,6 +1994,7 @@ static void ipw_irq_tasklet(struct ipw_priv *priv) wake_up_interruptible(&priv->wait_command_queue); priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING); cancel_delayed_work(&priv->request_scan); + cancel_delayed_work(&priv->scan_event); schedule_work(&priv->link_down); queue_delayed_work(priv->workqueue, &priv->rf_kill, 2 * HZ); handled |= IPW_INTA_BIT_RF_KILL_DONE; @@ -4343,6 +4346,37 @@ static void ipw_handle_missed_beacon(struct ipw_priv *priv, IPW_DEBUG_NOTIF("Missed beacon: %d\n", missed_count); } +static void ipw_scan_event(struct work_struct *work) +{ + union iwreq_data wrqu; + + struct ipw_priv *priv = + container_of(work, struct ipw_priv, scan_event.work); + + wrqu.data.length = 0; + wrqu.data.flags = 0; + wireless_send_event(priv->net_dev, SIOCGIWSCAN, &wrqu, NULL); +} + +static void handle_scan_event(struct ipw_priv *priv) +{ + /* Only userspace-requested scan completion events go out immediately */ + if (!priv->user_requested_scan) { + if (!delayed_work_pending(&priv->scan_event)) + queue_delayed_work(priv->workqueue, &priv->scan_event, + round_jiffies(msecs_to_jiffies(4000))); + } else { + union iwreq_data wrqu; + + priv->user_requested_scan = 0; + cancel_delayed_work(&priv->scan_event); + + wrqu.data.length = 0; + wrqu.data.flags = 0; + wireless_send_event(priv->net_dev, SIOCGIWSCAN, &wrqu, NULL); + } +} + /** * Handle host notification packet. * Called from interrupt routine @@ -4705,14 +4739,8 @@ static void ipw_rx_notification(struct ipw_priv *priv, * on how the scan was initiated. User space can just * sync on periodic scan to get fresh data... * Jean II */ - if (x->status == SCAN_COMPLETED_STATUS_COMPLETE) { - union iwreq_data wrqu; - - wrqu.data.length = 0; - wrqu.data.flags = 0; - wireless_send_event(priv->net_dev, SIOCGIWSCAN, - &wrqu, NULL); - } + if (x->status == SCAN_COMPLETED_STATUS_COMPLETE) + handle_scan_event(priv); break; } @@ -9490,6 +9518,10 @@ static int ipw_wx_set_scan(struct net_device *dev, struct ipw_priv *priv = ieee80211_priv(dev); struct iw_scan_req *req = (struct iw_scan_req *)extra; + mutex_lock(&priv->mutex); + priv->user_requested_scan = 1; + mutex_unlock(&priv->mutex); + if (wrqu->data.length == sizeof(struct iw_scan_req)) { if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { ipw_request_direct_scan(priv, req->essid, @@ -10668,6 +10700,7 @@ static void ipw_link_up(struct ipw_priv *priv) } cancel_delayed_work(&priv->request_scan); + cancel_delayed_work(&priv->scan_event); ipw_reset_stats(priv); /* Ensure the rate is updated immediately */ priv->last_rate = ipw_get_current_rate(priv); @@ -10705,7 +10738,8 @@ static void ipw_link_down(struct ipw_priv *priv) if (!(priv->status & STATUS_EXIT_PENDING)) { /* Queue up another scan... */ queue_delayed_work(priv->workqueue, &priv->request_scan, 0); - } + } else + cancel_delayed_work(&priv->scan_event); } static void ipw_bg_link_down(struct work_struct *work) @@ -10735,6 +10769,7 @@ static int ipw_setup_deferred_work(struct ipw_priv *priv) INIT_WORK(&priv->up, ipw_bg_up); INIT_WORK(&priv->down, ipw_bg_down); INIT_DELAYED_WORK(&priv->request_scan, ipw_request_scan); + INIT_DELAYED_WORK(&priv->scan_event, ipw_scan_event); INIT_WORK(&priv->request_passive_scan, ipw_request_passive_scan); INIT_DELAYED_WORK(&priv->gather_stats, ipw_bg_gather_stats); INIT_WORK(&priv->abort_scan, ipw_bg_abort_scan); @@ -11766,6 +11801,7 @@ static void ipw_pci_remove(struct pci_dev *pdev) cancel_delayed_work(&priv->adhoc_check); cancel_delayed_work(&priv->gather_stats); cancel_delayed_work(&priv->request_scan); + cancel_delayed_work(&priv->scan_event); cancel_delayed_work(&priv->rf_kill); cancel_delayed_work(&priv->scan_check); destroy_workqueue(priv->workqueue); diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index 9c973b96bb4..bec8e37a173 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h @@ -1287,6 +1287,8 @@ struct ipw_priv { struct iw_public_data wireless_data; + int user_requested_scan; + struct workqueue_struct *workqueue; struct delayed_work adhoc_check; @@ -1295,6 +1297,7 @@ struct ipw_priv { struct work_struct system_config; struct work_struct rx_replenish; struct delayed_work request_scan; + struct delayed_work scan_event; struct work_struct request_passive_scan; struct work_struct adapter_restart; struct delayed_work rf_kill; -- cgit v1.2.3-70-g09d2 From c3cf60a97fa4258599d308c74e2ee7c502b72e2a Mon Sep 17 00:00:00 2001 From: Michael Wu Date: Thu, 4 Oct 2007 00:04:07 -0400 Subject: [PATCH] rtl8187: Add device ID for HP wireless print kit usb dongle This adds the device ID for the HP wireless print kit usb dongle. Thanks to Thierry Merle for the patch to the original rtl8187 driver. Signed-off-by: Michael Wu Signed-off-by: John W. Linville --- drivers/net/wireless/rtl8187_dev.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index b0a92f543da..0ef887dd286 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c @@ -36,6 +36,8 @@ static struct usb_device_id rtl8187_table[] __devinitdata = { /* Netgear */ {USB_DEVICE(0x0846, 0x6100)}, {USB_DEVICE(0x0846, 0x6a00)}, + /* HP */ + {USB_DEVICE(0x03f0, 0xca02)}, {} }; -- cgit v1.2.3-70-g09d2 From c109810318ef4d37e495f740e624b1a15b7a0818 Mon Sep 17 00:00:00 2001 From: Martti Huttunen Date: Thu, 4 Oct 2007 00:06:00 -0400 Subject: [PATCH] p54usb: Add device ID for Linksys WUSB54AG Add the device ID for Linksys WUSB54AG. Signed-off-by: Michael Wu Signed-off-by: John W. Linville --- drivers/net/wireless/p54usb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/p54usb.c b/drivers/net/wireless/p54usb.c index 7446c39ce5d..755482a5a93 100644 --- a/drivers/net/wireless/p54usb.c +++ b/drivers/net/wireless/p54usb.c @@ -62,6 +62,7 @@ static struct usb_device_id p54u_table[] __devinitdata = { {USB_DEVICE(0x0cde, 0x0008)}, /* Sagem XG703A */ {USB_DEVICE(0x0d8e, 0x3762)}, /* DLink DWL-G120 Cohiba */ {USB_DEVICE(0x09aa, 0x1000)}, /* Spinnaker Proto board */ + {USB_DEVICE(0x13B1, 0x000C)}, /* Linksys WUSB54AG */ {USB_DEVICE(0x1435, 0x0427)}, /* Inventel UR054G */ {USB_DEVICE(0x2001, 0x3704)}, /* DLink DWL-G122 rev A2 */ {USB_DEVICE(0x413c, 0x8102)}, /* Spinnaker DUT */ -- cgit v1.2.3-70-g09d2 From 4abee4bbd771ce42b9a0a19be11264721aa0e3ed Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 6 Oct 2007 14:11:46 +0200 Subject: [PATCH] rt2x00: Remove duplicate code in MAC & BSSID handling The various drivers contained duplicate code to handle the MAC and BSSID initialization correctly. This moves the address copy to little endian variables to rt2x00config. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 30 +++++++------------------- drivers/net/wireless/rt2x00/rt2500pci.c | 30 +++++++------------------- drivers/net/wireless/rt2x00/rt2500usb.c | 30 +++++++------------------- drivers/net/wireless/rt2x00/rt2x00.h | 4 ++-- drivers/net/wireless/rt2x00/rt2x00config.c | 32 ++++++++++++++++++++++++++-- drivers/net/wireless/rt2x00/rt61pci.c | 34 +++++++++--------------------- drivers/net/wireless/rt2x00/rt73usb.c | 34 +++++++++--------------------- 7 files changed, 76 insertions(+), 118 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index faa47111a57..7b2a85ade13 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -249,32 +249,18 @@ static int rt2400pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) /* * Configuration handlers. */ -static void rt2400pci_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *addr) +static void rt2400pci_config_mac_addr(struct rt2x00_dev *rt2x00dev, + __le32 *mac) { - __le32 reg[2]; - - memset(®, 0, sizeof(reg)); - memcpy(®, addr, ETH_ALEN); - - /* - * The MAC address is passed to us as an array of bytes, - * that array is little endian, so no need for byte ordering. - */ - rt2x00pci_register_multiwrite(rt2x00dev, CSR3, ®, sizeof(reg)); + rt2x00pci_register_multiwrite(rt2x00dev, CSR3, mac, + (2 * sizeof(__le32))); } -static void rt2400pci_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) +static void rt2400pci_config_bssid(struct rt2x00_dev *rt2x00dev, + __le32 *bssid) { - __le32 reg[2]; - - memset(®, 0, sizeof(reg)); - memcpy(®, bssid, ETH_ALEN); - - /* - * The BSSID is passed to us as an array of bytes, - * that array is little endian, so no need for byte ordering. - */ - rt2x00pci_register_multiwrite(rt2x00dev, CSR5, ®, sizeof(reg)); + rt2x00pci_register_multiwrite(rt2x00dev, CSR5, bssid, + (2 * sizeof(__le32))); } static void rt2400pci_config_type(struct rt2x00_dev *rt2x00dev, int type) diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 842da900d7c..63a7b3cdf0c 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -249,32 +249,18 @@ static int rt2500pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) /* * Configuration handlers. */ -static void rt2500pci_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *addr) +static void rt2500pci_config_mac_addr(struct rt2x00_dev *rt2x00dev, + __le32 *mac) { - __le32 reg[2]; - - memset(®, 0, sizeof(reg)); - memcpy(®, addr, ETH_ALEN); - - /* - * The MAC address is passed to us as an array of bytes, - * that array is little endian, so no need for byte ordering. - */ - rt2x00pci_register_multiwrite(rt2x00dev, CSR3, ®, sizeof(reg)); + rt2x00pci_register_multiwrite(rt2x00dev, CSR3, mac, + (2 * sizeof(__le32))); } -static void rt2500pci_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) +static void rt2500pci_config_bssid(struct rt2x00_dev *rt2x00dev, + __le32 *bssid) { - __le32 reg[2]; - - memset(®, 0, sizeof(reg)); - memcpy(®, bssid, ETH_ALEN); - - /* - * The BSSID is passed to us as an array of bytes, - * that array is little endian, so no need for byte ordering. - */ - rt2x00pci_register_multiwrite(rt2x00dev, CSR5, ®, sizeof(reg)); + rt2x00pci_register_multiwrite(rt2x00dev, CSR5, bssid, + (2 * sizeof(__le32))); } static void rt2500pci_config_type(struct rt2x00_dev *rt2x00dev, const int type) diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 7aacc7b5c1b..973f653ecfc 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -254,32 +254,18 @@ static const struct rt2x00debug rt2500usb_rt2x00debug = { /* * Configuration handlers. */ -static void rt2500usb_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *addr) +static void rt2500usb_config_mac_addr(struct rt2x00_dev *rt2x00dev, + __le32 *mac) { - __le16 reg[3]; - - memset(®, 0, sizeof(reg)); - memcpy(®, addr, ETH_ALEN); - - /* - * The MAC address is passed to us as an array of bytes, - * that array is little endian, so no need for byte ordering. - */ - rt2500usb_register_multiwrite(rt2x00dev, MAC_CSR2, ®, sizeof(reg)); + rt2500usb_register_multiwrite(rt2x00dev, MAC_CSR2, &mac, + (3 * sizeof(__le16))); } -static void rt2500usb_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) +static void rt2500usb_config_bssid(struct rt2x00_dev *rt2x00dev, + __le32 *bssid) { - __le16 reg[3]; - - memset(®, 0, sizeof(reg)); - memcpy(®, bssid, ETH_ALEN); - - /* - * The BSSID is passed to us as an array of bytes, - * that array is little endian, so no need for byte ordering. - */ - rt2500usb_register_multiwrite(rt2x00dev, MAC_CSR5, ®, sizeof(reg)); + rt2500usb_register_multiwrite(rt2x00dev, MAC_CSR5, bssid, + (3 * sizeof(__le16))); } static void rt2500usb_config_type(struct rt2x00_dev *rt2x00dev, const int type) diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 6262d4e47c5..5d30ca6680b 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -408,8 +408,8 @@ struct rt2x00lib_ops { /* * Configuration handlers. */ - void (*config_mac_addr) (struct rt2x00_dev *rt2x00dev, u8 *mac); - void (*config_bssid) (struct rt2x00_dev *rt2x00dev, u8 *bssid); + void (*config_mac_addr) (struct rt2x00_dev *rt2x00dev, __le32 *mac); + void (*config_bssid) (struct rt2x00_dev *rt2x00dev, __le32 *bssid); void (*config_packet_filter) (struct rt2x00_dev *rt2x00dev, const unsigned int filter); void (*config_type) (struct rt2x00_dev *rt2x00dev, const int type); diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index 13b510687bc..aeeaa0c1424 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -34,16 +34,44 @@ #include "rt2x00.h" #include "rt2x00lib.h" + +/* + * The MAC and BSSID addressess are simple array of bytes, + * these arrays are little endian, so when sending the addressess + * to the drivers, copy the it into a endian-signed variable. + * + * Note that all devices (except rt2500usb) have 32 bits + * register word sizes. This means that whatever variable we + * pass _must_ be a multiple of 32 bits. Otherwise the device + * might not accept what we are sending to it. + * This will also make it easier for the driver to write + * the data to the device. + * + * Also note that when NULL is passed as address the + * we will send 00:00:00:00:00 to the device to clear the address. + * This will prevent the device being confused when it wants + * to ACK frames or consideres itself associated. + */ void rt2x00lib_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *mac) { + __le32 reg[2]; + + memset(®, 0, sizeof(reg)); if (mac) - rt2x00dev->ops->lib->config_mac_addr(rt2x00dev, mac); + memcpy(®, mac, ETH_ALEN); + + rt2x00dev->ops->lib->config_mac_addr(rt2x00dev, ®[0]); } void rt2x00lib_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) { + __le32 reg[2]; + + memset(®, 0, sizeof(reg)); if (bssid) - rt2x00dev->ops->lib->config_bssid(rt2x00dev, bssid); + memcpy(®, bssid, ETH_ALEN); + + rt2x00dev->ops->lib->config_bssid(rt2x00dev, ®[0]); } void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, int type) diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 6aa517645b6..5d31ced1114 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -274,42 +274,28 @@ static int rt61pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) /* * Configuration handlers. */ -static void rt61pci_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *addr) +static void rt61pci_config_mac_addr(struct rt2x00_dev *rt2x00dev, __le32 *mac) { - __le32 reg[2]; u32 tmp; - memset(®, 0, sizeof(reg)); - memcpy(®, addr, ETH_ALEN); - - tmp = le32_to_cpu(reg[1]); + tmp = le32_to_cpu(mac[1]); rt2x00_set_field32(&tmp, MAC_CSR3_UNICAST_TO_ME_MASK, 0xff); - reg[1] = cpu_to_le32(tmp); + mac[1] = cpu_to_le32(tmp); - /* - * The MAC address is passed to us as an array of bytes, - * that array is little endian, so no need for byte ordering. - */ - rt2x00pci_register_multiwrite(rt2x00dev, MAC_CSR2, ®, sizeof(reg)); + rt2x00pci_register_multiwrite(rt2x00dev, MAC_CSR2, mac, + (2 * sizeof(__le32))); } -static void rt61pci_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) +static void rt61pci_config_bssid(struct rt2x00_dev *rt2x00dev, __le32 *bssid) { - __le32 reg[2]; u32 tmp; - memset(®, 0, sizeof(reg)); - memcpy(®, bssid, ETH_ALEN); - - tmp = le32_to_cpu(reg[1]); + tmp = le32_to_cpu(bssid[1]); rt2x00_set_field32(&tmp, MAC_CSR5_BSS_ID_MASK, 3); - reg[1] = cpu_to_le32(tmp); + bssid[1] = cpu_to_le32(tmp); - /* - * The BSSID is passed to us as an array of bytes, - * that array is little endian, so no need for byte ordering. - */ - rt2x00pci_register_multiwrite(rt2x00dev, MAC_CSR4, ®, sizeof(reg)); + rt2x00pci_register_multiwrite(rt2x00dev, MAC_CSR4, bssid, + (2 * sizeof(__le32))); } static void rt61pci_config_type(struct rt2x00_dev *rt2x00dev, const int type) diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index ffed3ec5fb9..5fa697bfaa1 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -255,42 +255,28 @@ static const struct rt2x00debug rt73usb_rt2x00debug = { /* * Configuration handlers. */ -static void rt73usb_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *addr) +static void rt73usb_config_mac_addr(struct rt2x00_dev *rt2x00dev, __le32 *mac) { - __le32 reg[2]; u32 tmp; - memset(®, 0, sizeof(reg)); - memcpy(®, addr, ETH_ALEN); - - tmp = le32_to_cpu(reg[1]); + tmp = le32_to_cpu(mac[1]); rt2x00_set_field32(&tmp, MAC_CSR3_UNICAST_TO_ME_MASK, 0xff); - reg[1] = cpu_to_le32(tmp); + mac[1] = cpu_to_le32(tmp); - /* - * The MAC address is passed to us as an array of bytes, - * that array is little endian, so no need for byte ordering. - */ - rt73usb_register_multiwrite(rt2x00dev, MAC_CSR2, ®, sizeof(reg)); + rt73usb_register_multiwrite(rt2x00dev, MAC_CSR2, mac, + (2 * sizeof(__le32))); } -static void rt73usb_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) +static void rt73usb_config_bssid(struct rt2x00_dev *rt2x00dev, __le32 *bssid) { - __le32 reg[2]; u32 tmp; - memset(®, 0, sizeof(reg)); - memcpy(®, bssid, ETH_ALEN); - - tmp = le32_to_cpu(reg[1]); + tmp = le32_to_cpu(bssid[1]); rt2x00_set_field32(&tmp, MAC_CSR5_BSS_ID_MASK, 3); - reg[1] = cpu_to_le32(tmp); + bssid[1] = cpu_to_le32(tmp); - /* - * The BSSID is passed to us as an array of bytes, - * that array is little endian, so no need for byte ordering. - */ - rt73usb_register_multiwrite(rt2x00dev, MAC_CSR4, ®, sizeof(reg)); + rt73usb_register_multiwrite(rt2x00dev, MAC_CSR4, bssid, + (2 * sizeof(__le32))); } static void rt73usb_config_type(struct rt2x00_dev *rt2x00dev, const int type) -- cgit v1.2.3-70-g09d2 From 3a84732a5c9758a4bd59088787cac23508ef8b62 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 6 Oct 2007 14:12:13 +0200 Subject: [PATCH] rt2x00: Remove radio check from rt2x00lib_toggle_rx Don't check if the radio is enabled in rt2x00lib_toggle_rx, this is required since the link tuner should be disabled when shutting down the device. The remaining calls inside the rt2x00lib_toggle_rx handler should deliver no problems when called while the radio is done. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00dev.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 0216096c88c..b6a5c348112 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -164,9 +164,6 @@ void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, int enable) { enum dev_state state = enable ? STATE_RADIO_RX_ON : STATE_RADIO_RX_OFF; - if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) - return; - /* * When we are disabling the RX, we should also stop the link tuner. */ -- cgit v1.2.3-70-g09d2 From 6d7f9877a66a3abe0b04b63d1de4659919e21a92 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 6 Oct 2007 14:12:42 +0200 Subject: [PATCH] rt2x00: Store "STARTED" state during suspend Store the started state into a new flag DEVICE_STARTED_SUSPEND and set this when suspending while the device was started. We can't check for is_interface_present() since only mac80211 knows if there are monitor interfaces present. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00.h | 1 + drivers/net/wireless/rt2x00/rt2x00dev.c | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 5d30ca6680b..d280d0ec904 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -508,6 +508,7 @@ struct rt2x00_dev { #define CONFIG_EXTERNAL_LNA_BG 13 #define CONFIG_DOUBLE_ANTENNA 14 #define CONFIG_DISABLE_LINK_TUNING 15 +#define DEVICE_STARTED_SUSPEND 16 /* * Chipset identification. diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index b6a5c348112..f25475318c9 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -1088,12 +1088,13 @@ int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev, pm_message_t state) */ if (!test_bit(DEVICE_STARTED, &rt2x00dev->flags)) goto exit; + __set_bit(DEVICE_STARTED_SUSPEND, &rt2x00dev->flags); /* * Disable radio and unitialize all items * that must be recreated on resume. */ - rt2x00lib_disable_radio(rt2x00dev); + rt2x00mac_stop(rt2x00dev->hw); rt2x00lib_uninitialize(rt2x00dev); rt2x00debug_deregister(rt2x00dev); @@ -1123,9 +1124,9 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) rt2x00debug_register(rt2x00dev); /* - * Only continue if mac80211 has open interfaces. + * Only continue if mac80211 had open interfaces. */ - if (!test_bit(DEVICE_STARTED, &rt2x00dev->flags)) + if (!__test_and_clear_bit(DEVICE_STARTED_SUSPEND, &rt2x00dev->flags)) return 0; /* -- cgit v1.2.3-70-g09d2 From 483272f5ee968b25172b80bd2d27e37fef1dcc3a Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 6 Oct 2007 14:13:06 +0200 Subject: [PATCH] rt2x00: Move rt2x00dev flags into enumeration By putting the flags into a enumeration we can make it easier maintable since we don't have to assign numbers for each flag. This makes it easier to insert and remove flags. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00.h | 49 ++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index d280d0ec904..82dfcd95bb2 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -440,6 +440,39 @@ struct rt2x00_ops { #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ }; +/* + * rt2x00 device flags + */ +enum rt2x00_flags { + /* + * Device state flags + */ + DEVICE_PRESENT, + DEVICE_REGISTERED_HW, + DEVICE_INITIALIZED, + DEVICE_STARTED, + DEVICE_STARTED_SUSPEND, + DEVICE_ENABLED_RADIO, + DEVICE_ENABLED_RADIO_HW, + + /* + * Driver features + */ + DRIVER_REQUIRE_FIRMWARE, + DRIVER_REQUIRE_BEACON_RING, + + /* + * Driver configuration + */ + CONFIG_SUPPORT_HW_BUTTON, + CONFIG_FRAME_TYPE, + CONFIG_RF_SEQUENCE, + CONFIG_EXTERNAL_LNA_A, + CONFIG_EXTERNAL_LNA_BG, + CONFIG_DOUBLE_ANTENNA, + CONFIG_DISABLE_LINK_TUNING, +}; + /* * rt2x00 device structure. */ @@ -493,22 +526,6 @@ struct rt2x00_dev { * of the device capabilities are stored. */ unsigned long flags; -#define DEVICE_PRESENT 1 -#define DEVICE_REGISTERED_HW 2 -#define DEVICE_INITIALIZED 3 -#define DEVICE_STARTED 4 -#define DEVICE_ENABLED_RADIO 5 -#define DEVICE_ENABLED_RADIO_HW 6 -#define DRIVER_REQUIRE_FIRMWARE 7 -#define DRIVER_REQUIRE_BEACON_RING 8 -#define CONFIG_SUPPORT_HW_BUTTON 9 -#define CONFIG_FRAME_TYPE 10 -#define CONFIG_RF_SEQUENCE 11 -#define CONFIG_EXTERNAL_LNA_A 12 -#define CONFIG_EXTERNAL_LNA_BG 13 -#define CONFIG_DOUBLE_ANTENNA 14 -#define CONFIG_DISABLE_LINK_TUNING 15 -#define DEVICE_STARTED_SUSPEND 16 /* * Chipset identification. -- cgit v1.2.3-70-g09d2 From 5886d0dbf5b4226c6b6c8c44c555c5dd83c67b02 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 6 Oct 2007 14:13:38 +0200 Subject: [PATCH] rt2x00: Don't use changed_flags inside configure_packet_filter We shouldn't use changed_flags when configuring the packet filter, we work directly with the total_flags which is safe enough since we already check if something has changed after we applied our packet filtering flag rules. Also make sure that when the packet filter is scheduled, the rt2x00dev->interface.filter is cleared to make sure the drivers will update the packet filter instead of failing at the check: *total_flags == rt2x00dev->interface.filter Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 4 ++-- drivers/net/wireless/rt2x00/rt2500pci.c | 4 ++-- drivers/net/wireless/rt2x00/rt2500usb.c | 4 ++-- drivers/net/wireless/rt2x00/rt2x00.h | 2 -- drivers/net/wireless/rt2x00/rt2x00dev.c | 13 ++++++++++--- drivers/net/wireless/rt2x00/rt61pci.c | 4 ++-- drivers/net/wireless/rt2x00/rt73usb.c | 4 ++-- 7 files changed, 20 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 7b2a85ade13..e3cac0f26d7 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1497,8 +1497,8 @@ static void rt2400pci_configure_filter(struct ieee80211_hw *hw, * - Some filters are set based on interface type. */ *total_flags |= FIF_ALLMULTI; - if (changed_flags & FIF_OTHER_BSS || - changed_flags & FIF_PROMISC_IN_BSS) + if (*total_flags & FIF_OTHER_BSS || + *total_flags & FIF_PROMISC_IN_BSS) *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS; if (is_interface_type(intf, IEEE80211_IF_TYPE_AP)) *total_flags |= FIF_PROMISC_IN_BSS; diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 63a7b3cdf0c..5d982316b85 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1830,8 +1830,8 @@ static void rt2500pci_configure_filter(struct ieee80211_hw *hw, */ if (mc_count) *total_flags |= FIF_ALLMULTI; - if (changed_flags & FIF_OTHER_BSS || - changed_flags & FIF_PROMISC_IN_BSS) + if (*total_flags & FIF_OTHER_BSS || + *total_flags & FIF_PROMISC_IN_BSS) *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS; if (is_interface_type(intf, IEEE80211_IF_TYPE_AP)) *total_flags |= FIF_PROMISC_IN_BSS; diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 973f653ecfc..3dbd381f142 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1602,8 +1602,8 @@ static void rt2500usb_configure_filter(struct ieee80211_hw *hw, */ if (mc_count) *total_flags |= FIF_ALLMULTI; - if (changed_flags & FIF_OTHER_BSS || - changed_flags & FIF_PROMISC_IN_BSS) + if (*total_flags & FIF_OTHER_BSS || + *total_flags & FIF_PROMISC_IN_BSS) *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS; if (is_interface_type(intf, IEEE80211_IF_TYPE_AP)) *total_flags |= FIF_PROMISC_IN_BSS; diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 82dfcd95bb2..9bb5fb964a2 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -410,8 +410,6 @@ struct rt2x00lib_ops { */ void (*config_mac_addr) (struct rt2x00_dev *rt2x00dev, __le32 *mac); void (*config_bssid) (struct rt2x00_dev *rt2x00dev, __le32 *bssid); - void (*config_packet_filter) (struct rt2x00_dev *rt2x00dev, - const unsigned int filter); void (*config_type) (struct rt2x00_dev *rt2x00dev, const int type); void (*config) (struct rt2x00_dev *rt2x00dev, const unsigned int flags, struct ieee80211_conf *conf); diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index f25475318c9..1e07c3938cb 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -276,11 +276,18 @@ static void rt2x00lib_packetfilter_scheduled(struct work_struct *work) { struct rt2x00_dev *rt2x00dev = container_of(work, struct rt2x00_dev, filter_work); + unsigned int filter = rt2x00dev->interface.filter; + + /* + * Since we had stored the filter inside interface.filter, + * we should now clear that field. Otherwise the driver will + * assume nothing has changed (*total_flags will be compared + * to interface.filter to determine if any action is required). + */ + rt2x00dev->interface.filter = 0; rt2x00dev->ops->hw->configure_filter(rt2x00dev->hw, - rt2x00dev->interface.filter, - &rt2x00dev->interface.filter, - 0, NULL); + filter, &filter, 0, NULL); } /* diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 5d31ced1114..588b22b1641 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2389,8 +2389,8 @@ static void rt61pci_configure_filter(struct ieee80211_hw *hw, */ if (mc_count) *total_flags |= FIF_ALLMULTI; - if (changed_flags & FIF_OTHER_BSS || - changed_flags & FIF_PROMISC_IN_BSS) + if (*total_flags & FIF_OTHER_BSS || + *total_flags & FIF_PROMISC_IN_BSS) *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS; if (is_interface_type(intf, IEEE80211_IF_TYPE_AP)) *total_flags |= FIF_PROMISC_IN_BSS; diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 5fa697bfaa1..6d1635b5cd0 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1856,8 +1856,8 @@ static void rt73usb_configure_filter(struct ieee80211_hw *hw, */ if (mc_count) *total_flags |= FIF_ALLMULTI; - if (changed_flags & FIF_OTHER_BSS || - changed_flags & FIF_PROMISC_IN_BSS) + if (*total_flags & FIF_OTHER_BSS || + *total_flags & FIF_PROMISC_IN_BSS) *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS; if (is_interface_type(intf, IEEE80211_IF_TYPE_AP)) *total_flags |= FIF_PROMISC_IN_BSS; -- cgit v1.2.3-70-g09d2 From 81873e9ccd5731ca77027bdb32b34904e7af25d0 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 6 Oct 2007 14:14:06 +0200 Subject: [PATCH] rt2x00: Fix rfkill handling As reported by Modestas Vainius, enabling rkfill in 1 driver and disabling it in a second could cause a NULL pointer exception when the rfkill-disabled driver still sets the CONFIG_SUPPORT_HW_BUTTON flag. Furthermore, rfkill expects the timeout as a value in milliseconds instead of jiffies. Also increase the timeout to a second, since this 250ms would be overkill. Also the flag DEVICE_ENABLED_RADIO_HW is causing problems for devices which do not support the hardware button while rfkill is enabled in the driver. To remidy this we should inverse the flag and its meaning, rename the flag to DEVICE_DISABLED_RADIO_HW this means that by default the radio is enabled by the hardware button (if present) and can only be disabled explicitely. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 6 ++++-- drivers/net/wireless/rt2x00/rt2500pci.c | 6 ++++-- drivers/net/wireless/rt2x00/rt2x00.h | 2 +- drivers/net/wireless/rt2x00/rt2x00dev.c | 3 +-- drivers/net/wireless/rt2x00/rt2x00lib.h | 10 ++-------- drivers/net/wireless/rt2x00/rt2x00rfkill.c | 4 ++-- drivers/net/wireless/rt2x00/rt61pci.c | 6 ++++-- 7 files changed, 18 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index e3cac0f26d7..28999ffaba2 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -244,6 +244,8 @@ static int rt2400pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) rt2x00pci_register_read(rt2x00dev, GPIOCSR, ®); return rt2x00_get_field32(reg, GPIOCSR_BIT0); } +#else +#define rt2400pci_rfkill_poll NULL #endif /* CONFIG_RT2400PCI_RFKILL */ /* @@ -1359,8 +1361,10 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Detect if this device has an hardware controlled radio. */ +#ifdef CONFIG_RT2400PCI_RFKILL if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); +#endif /* CONFIG_RT2400PCI_RFKILL */ /* * Check if the BBP tuning should be enabled. @@ -1625,9 +1629,7 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = { .initialize = rt2x00pci_initialize, .uninitialize = rt2x00pci_uninitialize, .set_device_state = rt2400pci_set_device_state, -#ifdef CONFIG_RT2400PCI_RFKILL .rfkill_poll = rt2400pci_rfkill_poll, -#endif /* CONFIG_RT2400PCI_RFKILL */ .link_stats = rt2400pci_link_stats, .reset_tuner = rt2400pci_reset_tuner, .link_tuner = rt2400pci_link_tuner, diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 5d982316b85..9d9b4377a6f 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -244,6 +244,8 @@ static int rt2500pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) rt2x00pci_register_read(rt2x00dev, GPIOCSR, ®); return rt2x00_get_field32(reg, GPIOCSR_BIT0); } +#else +#define rt2500pci_rfkill_poll NULL #endif /* CONFIG_RT2500PCI_RFKILL */ /* @@ -1530,8 +1532,10 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Detect if this device has an hardware controlled radio. */ +#ifdef CONFIG_RT2500PCI_RFKILL if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); +#endif /* CONFIG_RT2500PCI_RFKILL */ /* * Check if the BBP tuning should be enabled. @@ -1937,9 +1941,7 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = { .initialize = rt2x00pci_initialize, .uninitialize = rt2x00pci_uninitialize, .set_device_state = rt2500pci_set_device_state, -#ifdef CONFIG_RT2500PCI_RFKILL .rfkill_poll = rt2500pci_rfkill_poll, -#endif /* CONFIG_RT2500PCI_RFKILL */ .link_stats = rt2500pci_link_stats, .reset_tuner = rt2500pci_reset_tuner, .link_tuner = rt2500pci_link_tuner, diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 9bb5fb964a2..235e5ad2190 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -451,7 +451,7 @@ enum rt2x00_flags { DEVICE_STARTED, DEVICE_STARTED_SUSPEND, DEVICE_ENABLED_RADIO, - DEVICE_ENABLED_RADIO_HW, + DEVICE_DISABLED_RADIO_HW, /* * Driver features diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 1e07c3938cb..6dc4f63aef0 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -104,8 +104,7 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev) * And check if the hardware button has been disabled. */ if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) || - (test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags) && - !test_bit(DEVICE_ENABLED_RADIO_HW, &rt2x00dev->flags))) + test_bit(DEVICE_DISABLED_RADIO_HW, &rt2x00dev->flags)) return 0; /* diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index 6dd92eb2b22..0ab39cad3cc 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -28,9 +28,10 @@ /* * Interval defines + * Both the link tuner as the rfkill will be called once per second. */ #define LINK_TUNE_INTERVAL ( round_jiffies(HZ) ) -#define RFKILL_POLL_INTERVAL ( HZ / 4 ) +#define RFKILL_POLL_INTERVAL ( 1000 ) /* * Radio control handlers. @@ -98,13 +99,6 @@ void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev); #else static inline int rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev) { - /* - * Force enable this flag, this will assure that - * devices with a hardware button but without rfkill support - * can still use their hardware. - */ - __set_bit(DEVICE_ENABLED_RADIO_HW, &rt2x00dev->flags); - return 0; } diff --git a/drivers/net/wireless/rt2x00/rt2x00rfkill.c b/drivers/net/wireless/rt2x00/rt2x00rfkill.c index 06af01451cd..a0f8b8e0a24 100644 --- a/drivers/net/wireless/rt2x00/rt2x00rfkill.c +++ b/drivers/net/wireless/rt2x00/rt2x00rfkill.c @@ -52,11 +52,11 @@ static int rt2x00rfkill_toggle_radio(void *data, enum rfkill_state state) if (state == RFKILL_STATE_ON) { INFO(rt2x00dev, "Hardware button pressed, enabling radio.\n"); - __set_bit(DEVICE_ENABLED_RADIO_HW, &rt2x00dev->flags); + __clear_bit(DEVICE_DISABLED_RADIO_HW, &rt2x00dev->flags); retval = rt2x00lib_enable_radio(rt2x00dev); } else if (state == RFKILL_STATE_OFF) { INFO(rt2x00dev, "Hardware button pressed, disabling radio.\n"); - __clear_bit(DEVICE_ENABLED_RADIO_HW, &rt2x00dev->flags); + __set_bit(DEVICE_DISABLED_RADIO_HW, &rt2x00dev->flags); rt2x00lib_disable_radio(rt2x00dev); } diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 588b22b1641..1c3937a3f9d 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -269,6 +269,8 @@ static int rt61pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) rt2x00pci_register_read(rt2x00dev, MAC_CSR13, ®); return rt2x00_get_field32(reg, MAC_CSR13_BIT5);; } +#else +#define rt61pci_rfkill_poll NULL #endif /* CONFIG_RT61PCI_RFKILL */ /* @@ -2090,8 +2092,10 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Detect if this device has an hardware controlled radio. */ +#ifdef CONFIG_RT61PCI_RFKILL if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); +#endif /* CONFIG_RT61PCI_RFKILL */ /* * Read frequency offset and RF programming sequence. @@ -2531,9 +2535,7 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = { .initialize = rt2x00pci_initialize, .uninitialize = rt2x00pci_uninitialize, .set_device_state = rt61pci_set_device_state, -#ifdef CONFIG_RT61PCI_RFKILL .rfkill_poll = rt61pci_rfkill_poll, -#endif /* CONFIG_RT61PCI_RFKILL */ .link_stats = rt61pci_link_stats, .reset_tuner = rt61pci_reset_tuner, .link_tuner = rt61pci_link_tuner, -- cgit v1.2.3-70-g09d2 From feb24691e3e87a740caec4568be1a202db786f20 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 6 Oct 2007 14:14:29 +0200 Subject: [PATCH] rt2x00: Move TSF sync values into rt2x00config All drivers use the same values for TSF sync, this will move the value determination into rt2x00config.c, and the definition for the values to rt2x00reg.h Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 12 +++--------- drivers/net/wireless/rt2x00/rt2500pci.c | 12 +++--------- drivers/net/wireless/rt2x00/rt2500usb.c | 14 ++++---------- drivers/net/wireless/rt2x00/rt2x00.h | 3 ++- drivers/net/wireless/rt2x00/rt2x00config.c | 20 +++++++++++++++++--- drivers/net/wireless/rt2x00/rt2x00lib.h | 2 +- drivers/net/wireless/rt2x00/rt2x00reg.h | 9 +++++++++ drivers/net/wireless/rt2x00/rt61pci.c | 12 +++--------- drivers/net/wireless/rt2x00/rt73usb.c | 12 +++--------- 9 files changed, 45 insertions(+), 51 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 28999ffaba2..0e345659f42 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -265,9 +265,9 @@ static void rt2400pci_config_bssid(struct rt2x00_dev *rt2x00dev, (2 * sizeof(__le32))); } -static void rt2400pci_config_type(struct rt2x00_dev *rt2x00dev, int type) +static void rt2400pci_config_type(struct rt2x00_dev *rt2x00dev, const int type, + const int tsf_sync) { - struct interface *intf = &rt2x00dev->interface; u32 reg; rt2x00pci_register_write(rt2x00dev, CSR14, 0); @@ -287,13 +287,7 @@ static void rt2400pci_config_type(struct rt2x00_dev *rt2x00dev, int type) rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); rt2x00_set_field32(®, CSR14_TBCN, 1); rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); - if (is_interface_type(intf, IEEE80211_IF_TYPE_IBSS) || - is_interface_type(intf, IEEE80211_IF_TYPE_AP)) - rt2x00_set_field32(®, CSR14_TSF_SYNC, 2); - else if (is_interface_type(intf, IEEE80211_IF_TYPE_STA)) - rt2x00_set_field32(®, CSR14_TSF_SYNC, 1); - else - rt2x00_set_field32(®, CSR14_TSF_SYNC, 0); + rt2x00_set_field32(®, CSR14_TSF_SYNC, tsf_sync); rt2x00pci_register_write(rt2x00dev, CSR14, reg); } diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 9d9b4377a6f..fa8669f5c96 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -265,9 +265,9 @@ static void rt2500pci_config_bssid(struct rt2x00_dev *rt2x00dev, (2 * sizeof(__le32))); } -static void rt2500pci_config_type(struct rt2x00_dev *rt2x00dev, const int type) +static void rt2500pci_config_type(struct rt2x00_dev *rt2x00dev, const int type, + const int tsf_sync) { - struct interface *intf = &rt2x00dev->interface; u32 reg; rt2x00pci_register_write(rt2x00dev, CSR14, 0); @@ -291,13 +291,7 @@ static void rt2500pci_config_type(struct rt2x00_dev *rt2x00dev, const int type) rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); rt2x00_set_field32(®, CSR14_TBCN, 1); rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); - if (is_interface_type(intf, IEEE80211_IF_TYPE_IBSS) || - is_interface_type(intf, IEEE80211_IF_TYPE_AP)) - rt2x00_set_field32(®, CSR14_TSF_SYNC, 2); - else if (is_interface_type(intf, IEEE80211_IF_TYPE_STA)) - rt2x00_set_field32(®, CSR14_TSF_SYNC, 1); - else - rt2x00_set_field32(®, CSR14_TSF_SYNC, 0); + rt2x00_set_field32(®, CSR14_TSF_SYNC, tsf_sync); rt2x00pci_register_write(rt2x00dev, CSR14, reg); } diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 3dbd381f142..6d5444b58e6 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -268,9 +268,9 @@ static void rt2500usb_config_bssid(struct rt2x00_dev *rt2x00dev, (3 * sizeof(__le16))); } -static void rt2500usb_config_type(struct rt2x00_dev *rt2x00dev, const int type) +static void rt2500usb_config_type(struct rt2x00_dev *rt2x00dev, const int type, + const int tsf_sync) { - struct interface *intf = &rt2x00dev->interface; u16 reg; rt2500usb_register_write(rt2x00dev, TXRX_CSR19, 0); @@ -281,7 +281,7 @@ static void rt2500usb_config_type(struct rt2x00_dev *rt2x00dev, const int type) rt2500usb_register_read(rt2x00dev, TXRX_CSR20, ®); rt2x00_set_field16(®, TXRX_CSR20_OFFSET, (PREAMBLE + get_duration(IEEE80211_HEADER, 2)) >> 6); - if (is_interface_type(intf, IEEE80211_IF_TYPE_STA)) + if (type == IEEE80211_IF_TYPE_STA) rt2x00_set_field16(®, TXRX_CSR20_BCN_EXPECT_WINDOW, 0); else rt2x00_set_field16(®, TXRX_CSR20_BCN_EXPECT_WINDOW, 2); @@ -298,13 +298,7 @@ static void rt2500usb_config_type(struct rt2x00_dev *rt2x00dev, const int type) rt2x00_set_field16(®, TXRX_CSR19_TSF_COUNT, 1); rt2x00_set_field16(®, TXRX_CSR19_TBCN, 1); rt2x00_set_field16(®, TXRX_CSR19_BEACON_GEN, 0); - if (is_interface_type(intf, IEEE80211_IF_TYPE_IBSS) || - is_interface_type(intf, IEEE80211_IF_TYPE_AP)) - rt2x00_set_field16(®, TXRX_CSR19_TSF_SYNC, 2); - else if (is_interface_type(intf, IEEE80211_IF_TYPE_STA)) - rt2x00_set_field16(®, TXRX_CSR19_TSF_SYNC, 1); - else - rt2x00_set_field16(®, TXRX_CSR19_TSF_SYNC, 0); + rt2x00_set_field16(®, TXRX_CSR19_TSF_SYNC, tsf_sync); rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg); } diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 235e5ad2190..27bec6ec33d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -410,7 +410,8 @@ struct rt2x00lib_ops { */ void (*config_mac_addr) (struct rt2x00_dev *rt2x00dev, __le32 *mac); void (*config_bssid) (struct rt2x00_dev *rt2x00dev, __le32 *bssid); - void (*config_type) (struct rt2x00_dev *rt2x00dev, const int type); + void (*config_type) (struct rt2x00_dev *rt2x00dev, const int type, + const int tsf_sync); void (*config) (struct rt2x00_dev *rt2x00dev, const unsigned int flags, struct ieee80211_conf *conf); #define CONFIG_UPDATE_PHYMODE ( 1 << 1 ) diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index aeeaa0c1424..f8e87aa8633 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -74,10 +74,24 @@ void rt2x00lib_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) rt2x00dev->ops->lib->config_bssid(rt2x00dev, ®[0]); } -void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, int type) +void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, const int type) { - if (type != INVALID_INTERFACE) - rt2x00dev->ops->lib->config_type(rt2x00dev, type); + int tsf_sync; + + switch (type) { + case IEEE80211_IF_TYPE_IBSS: + case IEEE80211_IF_TYPE_AP: + tsf_sync = TSF_SYNC_BEACON; + break; + case IEEE80211_IF_TYPE_STA: + tsf_sync = TSF_SYNC_INFRA; + break; + default: + tsf_sync = TSF_SYNC_NONE; + break; + } + + rt2x00dev->ops->lib->config_type(rt2x00dev, type, tsf_sync); } void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index 0ab39cad3cc..29ca932d77a 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -52,7 +52,7 @@ void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev); */ void rt2x00lib_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *mac); void rt2x00lib_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid); -void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, int type); +void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, const int type); void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, struct ieee80211_conf *conf, const int force_config); diff --git a/drivers/net/wireless/rt2x00/rt2x00reg.h b/drivers/net/wireless/rt2x00/rt2x00reg.h index 7927d5f7bcc..838421216da 100644 --- a/drivers/net/wireless/rt2x00/rt2x00reg.h +++ b/drivers/net/wireless/rt2x00/rt2x00reg.h @@ -58,6 +58,15 @@ enum led_mode { LED_MODE_ALPHA = 4, }; +/* + * TSF sync values + */ +enum tsf_sync { + TSF_SYNC_NONE = 0, + TSF_SYNC_INFRA = 1, + TSF_SYNC_BEACON = 2, +}; + /* * Device states */ diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 1c3937a3f9d..1c0789f2a41 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -300,9 +300,9 @@ static void rt61pci_config_bssid(struct rt2x00_dev *rt2x00dev, __le32 *bssid) (2 * sizeof(__le32))); } -static void rt61pci_config_type(struct rt2x00_dev *rt2x00dev, const int type) +static void rt61pci_config_type(struct rt2x00_dev *rt2x00dev, const int type, + const int tsf_sync) { - struct interface *intf = &rt2x00dev->interface; u32 reg; /* @@ -324,13 +324,7 @@ static void rt61pci_config_type(struct rt2x00_dev *rt2x00dev, const int type) rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); - if (is_interface_type(intf, IEEE80211_IF_TYPE_IBSS) || - is_interface_type(intf, IEEE80211_IF_TYPE_AP)) - rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 2); - else if (is_interface_type(intf, IEEE80211_IF_TYPE_STA)) - rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 1); - else - rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 0); + rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, tsf_sync); rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); } diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 6d1635b5cd0..919cca593bc 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -279,9 +279,9 @@ static void rt73usb_config_bssid(struct rt2x00_dev *rt2x00dev, __le32 *bssid) (2 * sizeof(__le32))); } -static void rt73usb_config_type(struct rt2x00_dev *rt2x00dev, const int type) +static void rt73usb_config_type(struct rt2x00_dev *rt2x00dev, const int type, + const int tsf_sync) { - struct interface *intf = &rt2x00dev->interface; u32 reg; /* @@ -303,13 +303,7 @@ static void rt73usb_config_type(struct rt2x00_dev *rt2x00dev, const int type) rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); - if (is_interface_type(intf, IEEE80211_IF_TYPE_IBSS) || - is_interface_type(intf, IEEE80211_IF_TYPE_AP)) - rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 2); - else if (is_interface_type(intf, IEEE80211_IF_TYPE_STA)) - rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 1); - else - rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 0); + rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, tsf_sync); rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg); } -- cgit v1.2.3-70-g09d2 From a137e202b0e47bca301d2315cca5c08140409ed7 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 6 Oct 2007 14:14:58 +0200 Subject: [PATCH] rt2x00: get_duration expects values in 100kbs get_duration expects all speeds to be passed in 100kbs, this means that passing 2 is incorrect and should be raised to 20 Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 2 +- drivers/net/wireless/rt2x00/rt2500pci.c | 2 +- drivers/net/wireless/rt2x00/rt2500usb.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 0e345659f42..bfab5a165b7 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -277,7 +277,7 @@ static void rt2400pci_config_type(struct rt2x00_dev *rt2x00dev, const int type, */ rt2x00pci_register_read(rt2x00dev, BCNCSR1, ®); rt2x00_set_field32(®, BCNCSR1_PRELOAD, - PREAMBLE + get_duration(IEEE80211_HEADER, 2)); + PREAMBLE + get_duration(IEEE80211_HEADER, 20)); rt2x00pci_register_write(rt2x00dev, BCNCSR1, reg); /* diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index fa8669f5c96..c8c6a848be9 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -277,7 +277,7 @@ static void rt2500pci_config_type(struct rt2x00_dev *rt2x00dev, const int type, */ rt2x00pci_register_read(rt2x00dev, BCNCSR1, ®); rt2x00_set_field32(®, BCNCSR1_PRELOAD, - PREAMBLE + get_duration(IEEE80211_HEADER, 2)); + PREAMBLE + get_duration(IEEE80211_HEADER, 20)); rt2x00_set_field32(®, BCNCSR1_BEACON_CWMIN, rt2x00lib_get_ring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON) diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 6d5444b58e6..c70c677b3f7 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -280,7 +280,7 @@ static void rt2500usb_config_type(struct rt2x00_dev *rt2x00dev, const int type, */ rt2500usb_register_read(rt2x00dev, TXRX_CSR20, ®); rt2x00_set_field16(®, TXRX_CSR20_OFFSET, - (PREAMBLE + get_duration(IEEE80211_HEADER, 2)) >> 6); + (PREAMBLE + get_duration(IEEE80211_HEADER, 20)) >> 6); if (type == IEEE80211_IF_TYPE_STA) rt2x00_set_field16(®, TXRX_CSR20_BCN_EXPECT_WINDOW, 0); else -- cgit v1.2.3-70-g09d2 From 9ee8f57e0adfd929759fee1ec6a7900ae6851bc5 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 6 Oct 2007 14:15:20 +0200 Subject: [PATCH] rt2x00: Cut lines down to 80 characters rt61pci contained 1 line of 88 characters width, this needs to be cut down. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt61pci.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 1c0789f2a41..8011523962a 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2497,7 +2497,8 @@ static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, * Write entire beacon with descriptor to register, * and kick the beacon generator. */ - rt2x00pci_register_multiwrite(rt2x00dev, HW_BEACON_BASE0, skb->data, skb->len); + rt2x00pci_register_multiwrite(rt2x00dev, HW_BEACON_BASE0, + skb->data, skb->len); rt61pci_kick_tx_queue(rt2x00dev, IEEE80211_TX_QUEUE_BEACON); return 0; -- cgit v1.2.3-70-g09d2 From dd9fa2d21aebbb618318954867c5dfe3751328be Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 6 Oct 2007 14:15:46 +0200 Subject: [PATCH] rt2x00: Add get_tx_data_len callback function The TX datalen must always be converted to a value rt73 and rt2500usb understand. Both require to use a different size then skb->len. First off this is required because the descriptor must be added, but the second is because the value must be a multiple of either 2 or 4, and it should not be a multiple of the USB packetmax Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2500usb.c | 32 +++++++++++++++++++++----------- drivers/net/wireless/rt2x00/rt2x00.h | 2 ++ drivers/net/wireless/rt2x00/rt2x00usb.c | 29 +++++++++++++++++------------ drivers/net/wireless/rt2x00/rt73usb.c | 16 ++++++++++++++++ 4 files changed, 56 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index c70c677b3f7..f536ff1b5c4 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1057,6 +1057,21 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_desc_write(txd, 0, word); } +static int rt2500usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev, + int maxpacket, struct sk_buff *skb) +{ + int length; + + /* + * The length _must_ be a multiple of 2, + * but it must _not_ be a multiple of the USB packet size. + */ + length = roundup(skb->len, 2); + length += (2 * !(length % maxpacket)); + + return length; +} + /* * TX data initialization */ @@ -1653,6 +1668,8 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw, rt2x00lib_get_ring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON); struct data_entry *beacon; struct data_entry *guardian; + int pipe = usb_sndbulkpipe(usb_dev, 1); + int max_packet = usb_maxpacket(usb_dev, pipe, 1); int length; /* @@ -1679,16 +1696,9 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw, ring->desc_size), skb->len - ring->desc_size, control); - /* - * Length passed to usb_fill_urb cannot be an odd number, - * so add 1 byte to make it even. - */ - length = skb->len; - if (length % 2) - length++; + length = rt2500usb_get_tx_data_len(rt2x00dev, max_packet, skb); - usb_fill_bulk_urb(beacon->priv, usb_dev, - usb_sndbulkpipe(usb_dev, 1), + usb_fill_bulk_urb(beacon->priv, usb_dev, pipe, skb->data, length, rt2500usb_beacondone, beacon); beacon->skb = skb; @@ -1699,8 +1709,7 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw, * the 'flags' field we are not using for beacons. */ guardian->flags = 0; - usb_fill_bulk_urb(guardian->priv, usb_dev, - usb_sndbulkpipe(usb_dev, 1), + usb_fill_bulk_urb(guardian->priv, usb_dev, pipe, &guardian->flags, 1, rt2500usb_beacondone, guardian); /* @@ -1741,6 +1750,7 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = { .link_tuner = rt2500usb_link_tuner, .write_tx_desc = rt2500usb_write_tx_desc, .write_tx_data = rt2x00usb_write_tx_data, + .get_tx_data_len = rt2500usb_get_tx_data_len, .kick_tx_queue = rt2500usb_kick_tx_queue, .fill_rxdone = rt2500usb_fill_rxdone, .config_mac_addr = rt2500usb_config_mac_addr, diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 27bec6ec33d..a392e2a9d08 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -396,6 +396,8 @@ struct rt2x00lib_ops { int (*write_tx_data) (struct rt2x00_dev *rt2x00dev, struct data_ring *ring, struct sk_buff *skb, struct ieee80211_tx_control *control); + int (*get_tx_data_len) (struct rt2x00_dev *rt2x00dev, int maxpacket, + struct sk_buff *skb); void (*kick_tx_queue) (struct rt2x00_dev *rt2x00dev, unsigned int queue); diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 66e47615f2a..73cc726c404 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -157,9 +157,10 @@ int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev, { struct usb_device *usb_dev = interface_to_usbdev(rt2x00dev_usb(rt2x00dev)); - struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data; struct data_entry *entry = rt2x00_get_data_entry(ring); - u32 length = skb->len; + int pipe = usb_sndbulkpipe(usb_dev, 1); + int max_packet = usb_maxpacket(usb_dev, pipe, 1); + u32 length; if (rt2x00_ring_full(ring)) { ieee80211_stop_queue(rt2x00dev->hw, control->queue); @@ -178,25 +179,29 @@ int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev, /* * Add the descriptor in front of the skb. */ - skb_push(skb, rt2x00dev->hw->extra_tx_headroom); - memset(skb->data, 0x00, rt2x00dev->hw->extra_tx_headroom); + skb_push(skb, ring->desc_size); + memset(skb->data, 0, ring->desc_size); rt2x00lib_write_tx_desc(rt2x00dev, (struct data_desc *)skb->data, - ieee80211hdr, length, control); + (struct ieee80211_hdr *)(skb->data + + ring->desc_size), + skb->len - ring->desc_size, control); memcpy(&entry->tx_status.control, control, sizeof(*control)); entry->skb = skb; /* - * Length passed to usb_fill_urb cannot be an odd number, - * so add 1 byte to make it even. + * USB devices cannot blindly pass the skb->len as the + * length of the data to usb_fill_bulk_urb. Pass the skb + * to the driver to determine what the length should be. */ - length += rt2x00dev->hw->extra_tx_headroom; - if (length % 2) - length++; + length = rt2x00dev->ops->lib->get_tx_data_len(rt2x00dev, + max_packet, skb); + /* + * Initialize URB and send the frame to the device. + */ __set_bit(ENTRY_OWNER_NIC, &entry->flags); - usb_fill_bulk_urb(entry->priv, usb_dev, - usb_sndbulkpipe(usb_dev, 1), + usb_fill_bulk_urb(entry->priv, usb_dev, pipe, skb->data, length, rt2x00usb_interrupt_txdone, entry); usb_submit_urb(entry->priv, GFP_ATOMIC); diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 919cca593bc..4a78ca79c94 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1286,6 +1286,21 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_desc_write(txd, 0, word); } +static int rt73usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev, + int maxpacket, struct sk_buff *skb) +{ + int length; + + /* + * The length _must_ be a multiple of 4, + * but it must _not_ be a multiple of the USB packet size. + */ + length = roundup(skb->len, 4); + length += (4 * !(length % maxpacket)); + + return length; +} + /* * TX data initialization */ @@ -2012,6 +2027,7 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = { .link_tuner = rt73usb_link_tuner, .write_tx_desc = rt73usb_write_tx_desc, .write_tx_data = rt2x00usb_write_tx_data, + .get_tx_data_len = rt73usb_get_tx_data_len, .kick_tx_queue = rt73usb_kick_tx_queue, .fill_rxdone = rt73usb_fill_rxdone, .config_mac_addr = rt73usb_config_mac_addr, -- cgit v1.2.3-70-g09d2 From 5cbf830e137d1b6057cb6b553a8ebbb7d1b9343f Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 6 Oct 2007 14:16:09 +0200 Subject: [PATCH] rt2x00: Pass dev_state to rt2x00lib_toggle_rx Directly pass a value from the enum dev_state with rt2x00lib_toggle_rx, this will save us a ? : statement, and it is clearer then passing a 1 0 argument. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00dev.c | 13 ++++++------- drivers/net/wireless/rt2x00/rt2x00lib.h | 2 +- drivers/net/wireless/rt2x00/rt2x00mac.c | 4 ++-- 3 files changed, 9 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 6dc4f63aef0..e1410486917 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -120,7 +120,7 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev) /* * Enable RX. */ - rt2x00lib_toggle_rx(rt2x00dev, 1); + rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON); /* * Start the TX queues. @@ -151,7 +151,7 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev) /* * Disable RX. */ - rt2x00lib_toggle_rx(rt2x00dev, 0); + rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF); /* * Disable radio. @@ -159,14 +159,12 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev) rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_RADIO_OFF); } -void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, int enable) +void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, enum dev_state state) { - enum dev_state state = enable ? STATE_RADIO_RX_ON : STATE_RADIO_RX_OFF; - /* * When we are disabling the RX, we should also stop the link tuner. */ - if (!enable) + if (state == STATE_RADIO_RX_OFF) rt2x00lib_stop_link_tuner(rt2x00dev); rt2x00dev->ops->lib->set_device_state(rt2x00dev, state); @@ -174,7 +172,8 @@ void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, int enable) /* * When we are enabling the RX, we should also start the link tuner. */ - if (enable && is_interface_present(&rt2x00dev->interface)) + if (state == STATE_RADIO_RX_ON && + is_interface_present(&rt2x00dev->interface)) rt2x00lib_start_link_tuner(rt2x00dev); } diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index 29ca932d77a..298faa9d3f6 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -38,7 +38,7 @@ */ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev); void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev); -void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, int enable); +void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, enum dev_state state); void rt2x00lib_reset_link_tuner(struct rt2x00_dev *rt2x00dev); /* diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index e98d013a189..f519d739684 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -272,7 +272,7 @@ int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) if (!conf->radio_enabled) rt2x00lib_disable_radio(rt2x00dev); else - rt2x00lib_toggle_rx(rt2x00dev, 0); + rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF); } rt2x00lib_config(rt2x00dev, conf, 0); @@ -281,7 +281,7 @@ int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) * Reenable RX only if the radio should be on. */ if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) - rt2x00lib_toggle_rx(rt2x00dev, 1); + rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON); else if (conf->radio_enabled) return rt2x00lib_enable_radio(rt2x00dev); -- cgit v1.2.3-70-g09d2 From 4f5af6eb3d17f8e343597ea99d97eb2f2905b2fb Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 6 Oct 2007 14:16:30 +0200 Subject: [PATCH] rt2x00: Small optimizations Make some small optimizations by removing some simple if-statements. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2500usb.c | 6 ++---- drivers/net/wireless/rt2x00/rt61pci.c | 6 ++---- drivers/net/wireless/rt2x00/rt73usb.c | 19 +++++++++---------- 3 files changed, 13 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index f536ff1b5c4..ef8dffbdffe 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -326,10 +326,8 @@ static void rt2500usb_config_rate(struct rt2x00_dev *rt2x00dev, const int rate) rt2500usb_register_write(rt2x00dev, TXRX_CSR1, reg); rt2500usb_register_read(rt2x00dev, TXRX_CSR10, ®); - if (preamble == SHORT_PREAMBLE) - rt2x00_set_field16(®, TXRX_CSR10_AUTORESPOND_PREAMBLE, 1); - else - rt2x00_set_field16(®, TXRX_CSR10_AUTORESPOND_PREAMBLE, 0); + rt2x00_set_field16(®, TXRX_CSR10_AUTORESPOND_PREAMBLE, + (preamble == SHORT_PREAMBLE)); rt2500usb_register_write(rt2x00dev, TXRX_CSR10, reg); } diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 8011523962a..cd22817cced 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -357,10 +357,8 @@ static void rt61pci_config_rate(struct rt2x00_dev *rt2x00dev, const int rate) rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, ®); - if (preamble == SHORT_PREAMBLE) - rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, 1); - else - rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, 0); + rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, + (preamble == SHORT_PREAMBLE)); rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg); } diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 4a78ca79c94..9e1bf4d77e1 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -195,12 +195,13 @@ rf_write: reg = 0; rt2x00_set_field32(®, PHY_CSR4_VALUE, value); - if (rt2x00_rf(&rt2x00dev->chip, RF5225) || - rt2x00_rf(&rt2x00dev->chip, RF2527)) - rt2x00_set_field32(®, PHY_CSR4_NUMBER_OF_BITS, 21); - else - rt2x00_set_field32(®, PHY_CSR4_NUMBER_OF_BITS, 20); - + /* + * RF5225 and RF2527 contain 21 bits per RF register value, + * all others contain 20 bits. + */ + rt2x00_set_field32(®, PHY_CSR4_NUMBER_OF_BITS, + 20 + !!(rt2x00_rf(&rt2x00dev->chip, RF5225) || + rt2x00_rf(&rt2x00dev->chip, RF2527))); rt2x00_set_field32(®, PHY_CSR4_IF_SELECT, 0); rt2x00_set_field32(®, PHY_CSR4_BUSY, 1); @@ -331,10 +332,8 @@ static void rt73usb_config_rate(struct rt2x00_dev *rt2x00dev, const int rate) rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg); rt73usb_register_read(rt2x00dev, TXRX_CSR4, ®); - if (preamble == SHORT_PREAMBLE) - rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, 1); - else - rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, 0); + rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, + (preamble == SHORT_PREAMBLE)); rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg); } -- cgit v1.2.3-70-g09d2 From 5c58ee51ff8c0aca74c225e0263bc5dd2b917781 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 6 Oct 2007 13:34:52 +0200 Subject: [PATCH] rt2x00: Reorganize configuration handler Reorganize configuration handling by creating a extra structure which contains precalculated values based on the mac80211 values which are usefull for all individual drivers. This also fixes the preamble configuration problem, up untill now preamble was never configured since by default the rate->val value was used when changing the mode. Now rate->val will only be used to set the basic rate mask. The preamble configuration will now be done correctly through the erp_ie_changed callback function. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 132 +++++++++++--------------- drivers/net/wireless/rt2x00/rt2500pci.c | 147 ++++++++++++----------------- drivers/net/wireless/rt2x00/rt2500usb.c | 112 +++++++++------------- drivers/net/wireless/rt2x00/rt2x00.h | 32 ++++++- drivers/net/wireless/rt2x00/rt2x00config.c | 61 +++++++++++- drivers/net/wireless/rt2x00/rt2x00dev.c | 13 +++ drivers/net/wireless/rt2x00/rt2x00mac.c | 34 +++++++ drivers/net/wireless/rt2x00/rt61pci.c | 101 ++++++-------------- drivers/net/wireless/rt2x00/rt73usb.c | 103 +++++++------------- 9 files changed, 358 insertions(+), 377 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index bfab5a165b7..31c1dd27162 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -291,90 +291,67 @@ static void rt2400pci_config_type(struct rt2x00_dev *rt2x00dev, const int type, rt2x00pci_register_write(rt2x00dev, CSR14, reg); } -static void rt2400pci_config_rate(struct rt2x00_dev *rt2x00dev, const int rate) +static void rt2400pci_config_preamble(struct rt2x00_dev *rt2x00dev, + const int short_preamble, + const int ack_timeout, + const int ack_consume_time) { - struct ieee80211_conf *conf = &rt2x00dev->hw->conf; + int preamble_mask; u32 reg; - u32 preamble; - u16 value; - - if (DEVICE_GET_RATE_FIELD(rate, PREAMBLE)) - preamble = SHORT_PREAMBLE; - else - preamble = PREAMBLE; - reg = DEVICE_GET_RATE_FIELD(rate, RATEMASK) & DEV_BASIC_RATEMASK; - rt2x00pci_register_write(rt2x00dev, ARCSR1, reg); + /* + * When short preamble is enabled, we should set bit 0x08 + */ + preamble_mask = short_preamble << 3; rt2x00pci_register_read(rt2x00dev, TXCSR1, ®); - value = ((conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) ? - SHORT_DIFS : DIFS) + - PLCP + preamble + get_duration(ACK_SIZE, 10); - rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, value); - value = SIFS + PLCP + preamble + get_duration(ACK_SIZE, 10); - rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME, value); + rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, ack_timeout); + rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME, ack_consume_time); rt2x00pci_register_write(rt2x00dev, TXCSR1, reg); - preamble = DEVICE_GET_RATE_FIELD(rate, PREAMBLE) ? 0x08 : 0x00; - rt2x00pci_register_read(rt2x00dev, ARCSR2, ®); - rt2x00_set_field32(®, ARCSR2_SIGNAL, 0x00 | preamble); + rt2x00_set_field32(®, ARCSR2_SIGNAL, 0x00 | preamble_mask); rt2x00_set_field32(®, ARCSR2_SERVICE, 0x04); rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 10)); rt2x00pci_register_write(rt2x00dev, ARCSR2, reg); rt2x00pci_register_read(rt2x00dev, ARCSR3, ®); - rt2x00_set_field32(®, ARCSR3_SIGNAL, 0x01 | preamble); + rt2x00_set_field32(®, ARCSR3_SIGNAL, 0x01 | preamble_mask); rt2x00_set_field32(®, ARCSR3_SERVICE, 0x04); rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 20)); rt2x00pci_register_write(rt2x00dev, ARCSR3, reg); rt2x00pci_register_read(rt2x00dev, ARCSR4, ®); - rt2x00_set_field32(®, ARCSR4_SIGNAL, 0x02 | preamble); + rt2x00_set_field32(®, ARCSR4_SIGNAL, 0x02 | preamble_mask); rt2x00_set_field32(®, ARCSR4_SERVICE, 0x04); rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 55)); rt2x00pci_register_write(rt2x00dev, ARCSR4, reg); rt2x00pci_register_read(rt2x00dev, ARCSR5, ®); - rt2x00_set_field32(®, ARCSR5_SIGNAL, 0x03 | preamble); + rt2x00_set_field32(®, ARCSR5_SIGNAL, 0x03 | preamble_mask); rt2x00_set_field32(®, ARCSR5_SERVICE, 0x84); rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 110)); rt2x00pci_register_write(rt2x00dev, ARCSR5, reg); } static void rt2400pci_config_phymode(struct rt2x00_dev *rt2x00dev, - const int phymode) + const int basic_rate_mask) { - struct ieee80211_hw_mode *mode; - struct ieee80211_rate *rate; - - rt2x00dev->curr_hwmode = HWMODE_B; - - mode = &rt2x00dev->hwmodes[rt2x00dev->curr_hwmode]; - rate = &mode->rates[mode->num_rates - 1]; - - rt2400pci_config_rate(rt2x00dev, rate->val2); + rt2x00pci_register_write(rt2x00dev, ARCSR1, basic_rate_mask); } static void rt2400pci_config_channel(struct rt2x00_dev *rt2x00dev, - const int index, const int channel) + struct rf_channel *rf) { - struct rf_channel reg; - - /* - * Fill rf_reg structure. - */ - memcpy(®, &rt2x00dev->spec.channels[index], sizeof(reg)); - /* * Switch on tuning bits. */ - rt2x00_set_field32(®.rf1, RF1_TUNER, 1); - rt2x00_set_field32(®.rf3, RF3_TUNER, 1); + rt2x00_set_field32(&rf->rf1, RF1_TUNER, 1); + rt2x00_set_field32(&rf->rf3, RF3_TUNER, 1); - rt2400pci_rf_write(rt2x00dev, 1, reg.rf1); - rt2400pci_rf_write(rt2x00dev, 2, reg.rf2); - rt2400pci_rf_write(rt2x00dev, 3, reg.rf3); + rt2400pci_rf_write(rt2x00dev, 1, rf->rf1); + rt2400pci_rf_write(rt2x00dev, 2, rf->rf2); + rt2400pci_rf_write(rt2x00dev, 3, rf->rf3); /* * RF2420 chipset don't need any additional actions. @@ -387,31 +364,31 @@ static void rt2400pci_config_channel(struct rt2x00_dev *rt2x00dev, * reference clock rate to activate auto_tune. * After that we set the value back to the correct channel. */ - rt2400pci_rf_write(rt2x00dev, 1, reg.rf1); + rt2400pci_rf_write(rt2x00dev, 1, rf->rf1); rt2400pci_rf_write(rt2x00dev, 2, 0x000c2a32); - rt2400pci_rf_write(rt2x00dev, 3, reg.rf3); + rt2400pci_rf_write(rt2x00dev, 3, rf->rf3); msleep(1); - rt2400pci_rf_write(rt2x00dev, 1, reg.rf1); - rt2400pci_rf_write(rt2x00dev, 2, reg.rf2); - rt2400pci_rf_write(rt2x00dev, 3, reg.rf3); + rt2400pci_rf_write(rt2x00dev, 1, rf->rf1); + rt2400pci_rf_write(rt2x00dev, 2, rf->rf2); + rt2400pci_rf_write(rt2x00dev, 3, rf->rf3); msleep(1); /* * Switch off tuning bits. */ - rt2x00_set_field32(®.rf1, RF1_TUNER, 0); - rt2x00_set_field32(®.rf3, RF3_TUNER, 0); + rt2x00_set_field32(&rf->rf1, RF1_TUNER, 0); + rt2x00_set_field32(&rf->rf3, RF3_TUNER, 0); - rt2400pci_rf_write(rt2x00dev, 1, reg.rf1); - rt2400pci_rf_write(rt2x00dev, 3, reg.rf3); + rt2400pci_rf_write(rt2x00dev, 1, rf->rf1); + rt2400pci_rf_write(rt2x00dev, 3, rf->rf3); /* * Clear false CRC during channel switch. */ - rt2x00pci_register_read(rt2x00dev, CNT0, ®.rf1); + rt2x00pci_register_read(rt2x00dev, CNT0, &rf->rf1); } static void rt2400pci_config_txpower(struct rt2x00_dev *rt2x00dev, int txpower) @@ -465,25 +442,22 @@ static void rt2400pci_config_antenna(struct rt2x00_dev *rt2x00dev, } static void rt2400pci_config_duration(struct rt2x00_dev *rt2x00dev, - int short_slot_time, int beacon_int) + struct rt2x00lib_conf *libconf) { u32 reg; rt2x00pci_register_read(rt2x00dev, CSR11, ®); - rt2x00_set_field32(®, CSR11_SLOT_TIME, - short_slot_time ? SHORT_SLOT_TIME : SLOT_TIME); + rt2x00_set_field32(®, CSR11_SLOT_TIME, libconf->slot_time); rt2x00pci_register_write(rt2x00dev, CSR11, reg); rt2x00pci_register_read(rt2x00dev, CSR18, ®); - rt2x00_set_field32(®, CSR18_SIFS, SIFS); - rt2x00_set_field32(®, CSR18_PIFS, - short_slot_time ? SHORT_PIFS : PIFS); + rt2x00_set_field32(®, CSR18_SIFS, libconf->sifs); + rt2x00_set_field32(®, CSR18_PIFS, libconf->pifs); rt2x00pci_register_write(rt2x00dev, CSR18, reg); rt2x00pci_register_read(rt2x00dev, CSR19, ®); - rt2x00_set_field32(®, CSR19_DIFS, - short_slot_time ? SHORT_DIFS : DIFS); - rt2x00_set_field32(®, CSR19_EIFS, EIFS); + rt2x00_set_field32(®, CSR19_DIFS, libconf->difs); + rt2x00_set_field32(®, CSR19_EIFS, libconf->eifs); rt2x00pci_register_write(rt2x00dev, CSR19, reg); rt2x00pci_register_read(rt2x00dev, TXCSR1, ®); @@ -492,30 +466,30 @@ static void rt2400pci_config_duration(struct rt2x00_dev *rt2x00dev, rt2x00pci_register_write(rt2x00dev, TXCSR1, reg); rt2x00pci_register_read(rt2x00dev, CSR12, ®); - rt2x00_set_field32(®, CSR12_BEACON_INTERVAL, beacon_int * 16); - rt2x00_set_field32(®, CSR12_CFP_MAX_DURATION, beacon_int * 16); + rt2x00_set_field32(®, CSR12_BEACON_INTERVAL, + libconf->conf->beacon_int * 16); + rt2x00_set_field32(®, CSR12_CFP_MAX_DURATION, + libconf->conf->beacon_int * 16); rt2x00pci_register_write(rt2x00dev, CSR12, reg); } static void rt2400pci_config(struct rt2x00_dev *rt2x00dev, const unsigned int flags, - struct ieee80211_conf *conf) + struct rt2x00lib_conf *libconf) { - int short_slot_time = conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME; - if (flags & CONFIG_UPDATE_PHYMODE) - rt2400pci_config_phymode(rt2x00dev, conf->phymode); + rt2400pci_config_phymode(rt2x00dev, libconf->basic_rates); if (flags & CONFIG_UPDATE_CHANNEL) - rt2400pci_config_channel(rt2x00dev, conf->channel_val, - conf->channel); + rt2400pci_config_channel(rt2x00dev, &libconf->rf); if (flags & CONFIG_UPDATE_TXPOWER) - rt2400pci_config_txpower(rt2x00dev, conf->power_level); + rt2400pci_config_txpower(rt2x00dev, + libconf->conf->power_level); if (flags & CONFIG_UPDATE_ANTENNA) - rt2400pci_config_antenna(rt2x00dev, conf->antenna_sel_tx, - conf->antenna_sel_rx); + rt2400pci_config_antenna(rt2x00dev, + libconf->conf->antenna_sel_tx, + libconf->conf->antenna_sel_rx); if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT)) - rt2400pci_config_duration(rt2x00dev, short_slot_time, - conf->beacon_int); + rt2400pci_config_duration(rt2x00dev, libconf); } static void rt2400pci_config_cw(struct rt2x00_dev *rt2x00dev, @@ -1609,6 +1583,7 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = { .configure_filter = rt2400pci_configure_filter, .get_stats = rt2x00mac_get_stats, .set_retry_limit = rt2400pci_set_retry_limit, + .erp_ie_changed = rt2x00mac_erp_ie_changed, .conf_tx = rt2400pci_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, .get_tsf = rt2400pci_get_tsf, @@ -1634,6 +1609,7 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = { .config_mac_addr = rt2400pci_config_mac_addr, .config_bssid = rt2400pci_config_bssid, .config_type = rt2400pci_config_type, + .config_preamble = rt2400pci_config_preamble, .config = rt2400pci_config, }; diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index c8c6a848be9..ff2d63267b1 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -295,100 +295,72 @@ static void rt2500pci_config_type(struct rt2x00_dev *rt2x00dev, const int type, rt2x00pci_register_write(rt2x00dev, CSR14, reg); } -static void rt2500pci_config_rate(struct rt2x00_dev *rt2x00dev, const int rate) +static void rt2500pci_config_preamble(struct rt2x00_dev *rt2x00dev, + const int short_preamble, + const int ack_timeout, + const int ack_consume_time) { - struct ieee80211_conf *conf = &rt2x00dev->hw->conf; + int preamble_mask; u32 reg; - u32 preamble; - u16 value; - - if (DEVICE_GET_RATE_FIELD(rate, PREAMBLE)) - preamble = SHORT_PREAMBLE; - else - preamble = PREAMBLE; - reg = DEVICE_GET_RATE_FIELD(rate, RATEMASK) & DEV_BASIC_RATEMASK; - rt2x00pci_register_write(rt2x00dev, ARCSR1, reg); + /* + * When short preamble is enabled, we should set bit 0x08 + */ + preamble_mask = short_preamble << 3; rt2x00pci_register_read(rt2x00dev, TXCSR1, ®); - value = ((conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) ? - SHORT_DIFS : DIFS) + - PLCP + preamble + get_duration(ACK_SIZE, 10); - rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, value); - value = SIFS + PLCP + preamble + get_duration(ACK_SIZE, 10); - rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME, value); + rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, ack_timeout); + rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME, ack_consume_time); rt2x00pci_register_write(rt2x00dev, TXCSR1, reg); - preamble = DEVICE_GET_RATE_FIELD(rate, PREAMBLE) ? 0x08 : 0x00; - rt2x00pci_register_read(rt2x00dev, ARCSR2, ®); - rt2x00_set_field32(®, ARCSR2_SIGNAL, 0x00 | preamble); + rt2x00_set_field32(®, ARCSR2_SIGNAL, 0x00 | preamble_mask); rt2x00_set_field32(®, ARCSR2_SERVICE, 0x04); rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 10)); rt2x00pci_register_write(rt2x00dev, ARCSR2, reg); rt2x00pci_register_read(rt2x00dev, ARCSR3, ®); - rt2x00_set_field32(®, ARCSR3_SIGNAL, 0x01 | preamble); + rt2x00_set_field32(®, ARCSR3_SIGNAL, 0x01 | preamble_mask); rt2x00_set_field32(®, ARCSR3_SERVICE, 0x04); rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 20)); rt2x00pci_register_write(rt2x00dev, ARCSR3, reg); rt2x00pci_register_read(rt2x00dev, ARCSR4, ®); - rt2x00_set_field32(®, ARCSR4_SIGNAL, 0x02 | preamble); + rt2x00_set_field32(®, ARCSR4_SIGNAL, 0x02 | preamble_mask); rt2x00_set_field32(®, ARCSR4_SERVICE, 0x04); rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 55)); rt2x00pci_register_write(rt2x00dev, ARCSR4, reg); rt2x00pci_register_read(rt2x00dev, ARCSR5, ®); - rt2x00_set_field32(®, ARCSR5_SIGNAL, 0x03 | preamble); + rt2x00_set_field32(®, ARCSR5_SIGNAL, 0x03 | preamble_mask); rt2x00_set_field32(®, ARCSR5_SERVICE, 0x84); rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 110)); rt2x00pci_register_write(rt2x00dev, ARCSR5, reg); } static void rt2500pci_config_phymode(struct rt2x00_dev *rt2x00dev, - const int phymode) + const int basic_rate_mask) { - struct ieee80211_hw_mode *mode; - struct ieee80211_rate *rate; - - if (phymode == MODE_IEEE80211A) - rt2x00dev->curr_hwmode = HWMODE_A; - else if (phymode == MODE_IEEE80211B) - rt2x00dev->curr_hwmode = HWMODE_B; - else - rt2x00dev->curr_hwmode = HWMODE_G; - - mode = &rt2x00dev->hwmodes[rt2x00dev->curr_hwmode]; - rate = &mode->rates[mode->num_rates - 1]; - - rt2500pci_config_rate(rt2x00dev, rate->val2); + rt2x00pci_register_write(rt2x00dev, ARCSR1, basic_rate_mask); } static void rt2500pci_config_channel(struct rt2x00_dev *rt2x00dev, - const int index, const int channel, - const int txpower) + struct rf_channel *rf, const int txpower) { - struct rf_channel reg; u8 r70; - /* - * Fill rf_reg structure. - */ - memcpy(®, &rt2x00dev->spec.channels[index], sizeof(reg)); - /* * Set TXpower. */ - rt2x00_set_field32(®.rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); + rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); /* * Switch on tuning bits. * For RT2523 devices we do not need to update the R1 register. */ if (!rt2x00_rf(&rt2x00dev->chip, RF2523)) - rt2x00_set_field32(®.rf1, RF1_TUNER, 1); - rt2x00_set_field32(®.rf3, RF3_TUNER, 1); + rt2x00_set_field32(&rf->rf1, RF1_TUNER, 1); + rt2x00_set_field32(&rf->rf3, RF3_TUNER, 1); /* * For RT2525 we should first set the channel to half band higher. @@ -401,24 +373,24 @@ static void rt2500pci_config_channel(struct rt2x00_dev *rt2x00dev, 0x00080d2e, 0x00080d3a }; - rt2500pci_rf_write(rt2x00dev, 1, reg.rf1); - rt2500pci_rf_write(rt2x00dev, 2, vals[channel - 1]); - rt2500pci_rf_write(rt2x00dev, 3, reg.rf3); - if (reg.rf4) - rt2500pci_rf_write(rt2x00dev, 4, reg.rf4); + rt2500pci_rf_write(rt2x00dev, 1, rf->rf1); + rt2500pci_rf_write(rt2x00dev, 2, vals[rf->channel - 1]); + rt2500pci_rf_write(rt2x00dev, 3, rf->rf3); + if (rf->rf4) + rt2500pci_rf_write(rt2x00dev, 4, rf->rf4); } - rt2500pci_rf_write(rt2x00dev, 1, reg.rf1); - rt2500pci_rf_write(rt2x00dev, 2, reg.rf2); - rt2500pci_rf_write(rt2x00dev, 3, reg.rf3); - if (reg.rf4) - rt2500pci_rf_write(rt2x00dev, 4, reg.rf4); + rt2500pci_rf_write(rt2x00dev, 1, rf->rf1); + rt2500pci_rf_write(rt2x00dev, 2, rf->rf2); + rt2500pci_rf_write(rt2x00dev, 3, rf->rf3); + if (rf->rf4) + rt2500pci_rf_write(rt2x00dev, 4, rf->rf4); /* * Channel 14 requires the Japan filter bit to be set. */ r70 = 0x46; - rt2x00_set_field8(&r70, BBP_R70_JAPAN_FILTER, channel == 14); + rt2x00_set_field8(&r70, BBP_R70_JAPAN_FILTER, rf->channel == 14); rt2500pci_bbp_write(rt2x00dev, 70, r70); msleep(1); @@ -428,17 +400,17 @@ static void rt2500pci_config_channel(struct rt2x00_dev *rt2x00dev, * For RT2523 devices we do not need to update the R1 register. */ if (!rt2x00_rf(&rt2x00dev->chip, RF2523)) { - rt2x00_set_field32(®.rf1, RF1_TUNER, 0); - rt2500pci_rf_write(rt2x00dev, 1, reg.rf1); + rt2x00_set_field32(&rf->rf1, RF1_TUNER, 0); + rt2500pci_rf_write(rt2x00dev, 1, rf->rf1); } - rt2x00_set_field32(®.rf3, RF3_TUNER, 0); - rt2500pci_rf_write(rt2x00dev, 3, reg.rf3); + rt2x00_set_field32(&rf->rf3, RF3_TUNER, 0); + rt2500pci_rf_write(rt2x00dev, 3, rf->rf3); /* * Clear false CRC during channel switch. */ - rt2x00pci_register_read(rt2x00dev, CNT0, ®.rf1); + rt2x00pci_register_read(rt2x00dev, CNT0, &rf->rf1); } static void rt2500pci_config_txpower(struct rt2x00_dev *rt2x00dev, @@ -525,26 +497,22 @@ static void rt2500pci_config_antenna(struct rt2x00_dev *rt2x00dev, } static void rt2500pci_config_duration(struct rt2x00_dev *rt2x00dev, - const int short_slot_time, - const int beacon_int) + struct rt2x00lib_conf *libconf) { u32 reg; rt2x00pci_register_read(rt2x00dev, CSR11, ®); - rt2x00_set_field32(®, CSR11_SLOT_TIME, - short_slot_time ? SHORT_SLOT_TIME : SLOT_TIME); + rt2x00_set_field32(®, CSR11_SLOT_TIME, libconf->slot_time); rt2x00pci_register_write(rt2x00dev, CSR11, reg); rt2x00pci_register_read(rt2x00dev, CSR18, ®); - rt2x00_set_field32(®, CSR18_SIFS, SIFS); - rt2x00_set_field32(®, CSR18_PIFS, - short_slot_time ? SHORT_PIFS : PIFS); + rt2x00_set_field32(®, CSR18_SIFS, libconf->sifs); + rt2x00_set_field32(®, CSR18_PIFS, libconf->pifs); rt2x00pci_register_write(rt2x00dev, CSR18, reg); rt2x00pci_register_read(rt2x00dev, CSR19, ®); - rt2x00_set_field32(®, CSR19_DIFS, - short_slot_time ? SHORT_DIFS : DIFS); - rt2x00_set_field32(®, CSR19_EIFS, EIFS); + rt2x00_set_field32(®, CSR19_DIFS, libconf->difs); + rt2x00_set_field32(®, CSR19_EIFS, libconf->eifs); rt2x00pci_register_write(rt2x00dev, CSR19, reg); rt2x00pci_register_read(rt2x00dev, TXCSR1, ®); @@ -553,30 +521,31 @@ static void rt2500pci_config_duration(struct rt2x00_dev *rt2x00dev, rt2x00pci_register_write(rt2x00dev, TXCSR1, reg); rt2x00pci_register_read(rt2x00dev, CSR12, ®); - rt2x00_set_field32(®, CSR12_BEACON_INTERVAL, beacon_int * 16); - rt2x00_set_field32(®, CSR12_CFP_MAX_DURATION, beacon_int * 16); + rt2x00_set_field32(®, CSR12_BEACON_INTERVAL, + libconf->conf->beacon_int * 16); + rt2x00_set_field32(®, CSR12_CFP_MAX_DURATION, + libconf->conf->beacon_int * 16); rt2x00pci_register_write(rt2x00dev, CSR12, reg); } static void rt2500pci_config(struct rt2x00_dev *rt2x00dev, const unsigned int flags, - struct ieee80211_conf *conf) + struct rt2x00lib_conf *libconf) { - int short_slot_time = conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME; - if (flags & CONFIG_UPDATE_PHYMODE) - rt2500pci_config_phymode(rt2x00dev, conf->phymode); + rt2500pci_config_phymode(rt2x00dev, libconf->basic_rates); if (flags & CONFIG_UPDATE_CHANNEL) - rt2500pci_config_channel(rt2x00dev, conf->channel_val, - conf->channel, conf->power_level); + rt2500pci_config_channel(rt2x00dev, &libconf->rf, + libconf->conf->power_level); if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL)) - rt2500pci_config_txpower(rt2x00dev, conf->power_level); + rt2500pci_config_txpower(rt2x00dev, + libconf->conf->power_level); if (flags & CONFIG_UPDATE_ANTENNA) - rt2500pci_config_antenna(rt2x00dev, conf->antenna_sel_tx, - conf->antenna_sel_rx); + rt2500pci_config_antenna(rt2x00dev, + libconf->conf->antenna_sel_tx, + libconf->conf->antenna_sel_rx); if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT)) - rt2500pci_config_duration(rt2x00dev, short_slot_time, - conf->beacon_int); + rt2500pci_config_duration(rt2x00dev, libconf); } /* @@ -1921,6 +1890,7 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = { .configure_filter = rt2500pci_configure_filter, .get_stats = rt2x00mac_get_stats, .set_retry_limit = rt2500pci_set_retry_limit, + .erp_ie_changed = rt2x00mac_erp_ie_changed, .conf_tx = rt2x00mac_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, .get_tsf = rt2500pci_get_tsf, @@ -1946,6 +1916,7 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = { .config_mac_addr = rt2500pci_config_mac_addr, .config_bssid = rt2500pci_config_bssid, .config_type = rt2500pci_config_type, + .config_preamble = rt2500pci_config_preamble, .config = rt2500pci_config, }; diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index ef8dffbdffe..45f8f744a12 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -302,54 +302,39 @@ static void rt2500usb_config_type(struct rt2x00_dev *rt2x00dev, const int type, rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg); } -static void rt2500usb_config_rate(struct rt2x00_dev *rt2x00dev, const int rate) +static void rt2500usb_config_preamble(struct rt2x00_dev *rt2x00dev, + const int short_preamble, + const int ack_timeout, + const int ack_consume_time) { - struct ieee80211_conf *conf = &rt2x00dev->hw->conf; u16 reg; - u16 value; - u16 preamble; - - if (DEVICE_GET_RATE_FIELD(rate, PREAMBLE)) - preamble = SHORT_PREAMBLE; - else - preamble = PREAMBLE; - reg = DEVICE_GET_RATE_FIELD(rate, RATEMASK) & DEV_BASIC_RATEMASK; - - rt2500usb_register_write(rt2x00dev, TXRX_CSR11, reg); + /* + * When in atomic context, reschedule and let rt2x00lib + * call this function again. + */ + if (in_atomic()) { + queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->config_work); + return; + } rt2500usb_register_read(rt2x00dev, TXRX_CSR1, ®); - value = ((conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) ? - SHORT_DIFS : DIFS) + - PLCP + preamble + get_duration(ACK_SIZE, 10); - rt2x00_set_field16(®, TXRX_CSR1_ACK_TIMEOUT, value); + rt2x00_set_field16(®, TXRX_CSR1_ACK_TIMEOUT, ack_timeout); rt2500usb_register_write(rt2x00dev, TXRX_CSR1, reg); rt2500usb_register_read(rt2x00dev, TXRX_CSR10, ®); rt2x00_set_field16(®, TXRX_CSR10_AUTORESPOND_PREAMBLE, - (preamble == SHORT_PREAMBLE)); + !!short_preamble); rt2500usb_register_write(rt2x00dev, TXRX_CSR10, reg); } static void rt2500usb_config_phymode(struct rt2x00_dev *rt2x00dev, - const int phymode) + const int phymode, + const int basic_rate_mask) { - struct ieee80211_hw_mode *mode; - struct ieee80211_rate *rate; + rt2500usb_register_write(rt2x00dev, TXRX_CSR11, basic_rate_mask); - if (phymode == MODE_IEEE80211A) - rt2x00dev->curr_hwmode = HWMODE_A; - else if (phymode == MODE_IEEE80211B) - rt2x00dev->curr_hwmode = HWMODE_B; - else - rt2x00dev->curr_hwmode = HWMODE_G; - - mode = &rt2x00dev->hwmodes[rt2x00dev->curr_hwmode]; - rate = &mode->rates[mode->num_rates - 1]; - - rt2500usb_config_rate(rt2x00dev, rate->val2); - - if (phymode == MODE_IEEE80211B) { + if (phymode == HWMODE_B) { rt2500usb_register_write(rt2x00dev, MAC_CSR11, 0x000b); rt2500usb_register_write(rt2x00dev, MAC_CSR12, 0x0040); } else { @@ -359,20 +344,12 @@ static void rt2500usb_config_phymode(struct rt2x00_dev *rt2x00dev, } static void rt2500usb_config_channel(struct rt2x00_dev *rt2x00dev, - const int index, const int channel, - const int txpower) + struct rf_channel *rf, const int txpower) { - struct rf_channel reg; - - /* - * Fill rf_reg structure. - */ - memcpy(®, &rt2x00dev->spec.channels[index], sizeof(reg)); - /* * Set TXpower. */ - rt2x00_set_field32(®.rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); + rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); /* * For RT2525E we should first set the channel to half band higher. @@ -385,16 +362,16 @@ static void rt2500usb_config_channel(struct rt2x00_dev *rt2x00dev, 0x00000902, 0x00000906 }; - rt2500usb_rf_write(rt2x00dev, 2, vals[channel - 1]); - if (reg.rf4) - rt2500usb_rf_write(rt2x00dev, 4, reg.rf4); + rt2500usb_rf_write(rt2x00dev, 2, vals[rf->channel - 1]); + if (rf->rf4) + rt2500usb_rf_write(rt2x00dev, 4, rf->rf4); } - rt2500usb_rf_write(rt2x00dev, 1, reg.rf1); - rt2500usb_rf_write(rt2x00dev, 2, reg.rf2); - rt2500usb_rf_write(rt2x00dev, 3, reg.rf3); - if (reg.rf4) - rt2500usb_rf_write(rt2x00dev, 4, reg.rf4); + rt2500usb_rf_write(rt2x00dev, 1, rf->rf1); + rt2500usb_rf_write(rt2x00dev, 2, rf->rf2); + rt2500usb_rf_write(rt2x00dev, 3, rf->rf3); + if (rf->rf4) + rt2500usb_rf_write(rt2x00dev, 4, rf->rf4); } static void rt2500usb_config_txpower(struct rt2x00_dev *rt2x00dev, @@ -484,38 +461,37 @@ static void rt2500usb_config_antenna(struct rt2x00_dev *rt2x00dev, } static void rt2500usb_config_duration(struct rt2x00_dev *rt2x00dev, - const int short_slot_time, - const int beacon_int) + struct rt2x00lib_conf *libconf) { u16 reg; - rt2500usb_register_write(rt2x00dev, MAC_CSR10, - short_slot_time ? SHORT_SLOT_TIME : SLOT_TIME); + rt2500usb_register_write(rt2x00dev, MAC_CSR10, libconf->slot_time); rt2500usb_register_read(rt2x00dev, TXRX_CSR18, ®); - rt2x00_set_field16(®, TXRX_CSR18_INTERVAL, beacon_int * 4); + rt2x00_set_field16(®, TXRX_CSR18_INTERVAL, + libconf->conf->beacon_int * 4); rt2500usb_register_write(rt2x00dev, TXRX_CSR18, reg); } static void rt2500usb_config(struct rt2x00_dev *rt2x00dev, const unsigned int flags, - struct ieee80211_conf *conf) + struct rt2x00lib_conf *libconf) { - int short_slot_time = conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME; - if (flags & CONFIG_UPDATE_PHYMODE) - rt2500usb_config_phymode(rt2x00dev, conf->phymode); + rt2500usb_config_phymode(rt2x00dev, libconf->phymode, + libconf->basic_rates); if (flags & CONFIG_UPDATE_CHANNEL) - rt2500usb_config_channel(rt2x00dev, conf->channel_val, - conf->channel, conf->power_level); + rt2500usb_config_channel(rt2x00dev, &libconf->rf, + libconf->conf->power_level); if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL)) - rt2500usb_config_txpower(rt2x00dev, conf->power_level); + rt2500usb_config_txpower(rt2x00dev, + libconf->conf->power_level); if (flags & CONFIG_UPDATE_ANTENNA) - rt2500usb_config_antenna(rt2x00dev, conf->antenna_sel_tx, - conf->antenna_sel_rx); + rt2500usb_config_antenna(rt2x00dev, + libconf->conf->antenna_sel_tx, + libconf->conf->antenna_sel_rx); if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT)) - rt2500usb_config_duration(rt2x00dev, short_slot_time, - conf->beacon_int); + rt2500usb_config_duration(rt2x00dev, libconf); } /* @@ -1733,6 +1709,7 @@ static const struct ieee80211_ops rt2500usb_mac80211_ops = { .config_interface = rt2x00mac_config_interface, .configure_filter = rt2500usb_configure_filter, .get_stats = rt2x00mac_get_stats, + .erp_ie_changed = rt2x00mac_erp_ie_changed, .conf_tx = rt2x00mac_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, .beacon_update = rt2500usb_beacon_update, @@ -1754,6 +1731,7 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = { .config_mac_addr = rt2500usb_config_mac_addr, .config_bssid = rt2500usb_config_bssid, .config_type = rt2500usb_config_type, + .config_preamble = rt2500usb_config_preamble, .config = rt2500usb_config, }; diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index a392e2a9d08..aabbe425470 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -351,6 +351,28 @@ struct hw_mode_spec { const struct rf_channel *channels; }; +/* + * Configuration structure wrapper around the + * mac80211 configuration structure. + * When mac80211 configures the driver, rt2x00lib + * can precalculate values which are equal for all + * rt2x00 drivers. Those values can be stored in here. + */ +struct rt2x00lib_conf { + struct ieee80211_conf *conf; + struct rf_channel rf; + + int phymode; + + int basic_rates; + int slot_time; + + short sifs; + short pifs; + short difs; + short eifs; +}; + /* * rt2x00lib callback functions. */ @@ -414,8 +436,12 @@ struct rt2x00lib_ops { void (*config_bssid) (struct rt2x00_dev *rt2x00dev, __le32 *bssid); void (*config_type) (struct rt2x00_dev *rt2x00dev, const int type, const int tsf_sync); + void (*config_preamble) (struct rt2x00_dev *rt2x00dev, + const int short_preamble, + const int ack_timeout, + const int ack_consume_time); void (*config) (struct rt2x00_dev *rt2x00dev, const unsigned int flags, - struct ieee80211_conf *conf); + struct rt2x00lib_conf *libconf); #define CONFIG_UPDATE_PHYMODE ( 1 << 1 ) #define CONFIG_UPDATE_CHANNEL ( 1 << 2 ) #define CONFIG_UPDATE_TXPOWER ( 1 << 3 ) @@ -472,6 +498,7 @@ enum rt2x00_flags { CONFIG_EXTERNAL_LNA_BG, CONFIG_DOUBLE_ANTENNA, CONFIG_DISABLE_LINK_TUNING, + CONFIG_SHORT_PREAMBLE, }; /* @@ -612,6 +639,7 @@ struct rt2x00_dev { */ struct work_struct beacon_work; struct work_struct filter_work; + struct work_struct config_work; /* * Data ring arrays for RX, TX and Beacon. @@ -792,6 +820,8 @@ int rt2x00mac_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats); int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw, struct ieee80211_tx_queue_stats *stats); +void rt2x00mac_erp_ie_changed(struct ieee80211_hw *hw, u8 changes, + int cts_protection, int preamble); int rt2x00mac_conf_tx(struct ieee80211_hw *hw, int queue, const struct ieee80211_tx_queue_params *params); diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index f8e87aa8633..12914cf7156 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -97,7 +97,11 @@ void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, const int type) void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, struct ieee80211_conf *conf, const int force_config) { + struct rt2x00lib_conf libconf; + struct ieee80211_hw_mode *mode; + struct ieee80211_rate *rate; int flags = 0; + int short_slot_time; /* * In some situations we want to force all configurations @@ -128,8 +132,62 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, flags |= CONFIG_UPDATE_SLOT_TIME; flags |= CONFIG_UPDATE_BEACON_INT; + /* + * We have determined what options should be updated, + * now precalculate device configuration values depending + * on what configuration options need to be updated. + */ config: - rt2x00dev->ops->lib->config(rt2x00dev, flags, conf); + memset(&libconf, 0, sizeof(libconf)); + + if (flags & CONFIG_UPDATE_PHYMODE) { + switch (conf->phymode) { + case MODE_IEEE80211A: + libconf.phymode = HWMODE_A; + break; + case MODE_IEEE80211B: + libconf.phymode = HWMODE_B; + break; + case MODE_IEEE80211G: + libconf.phymode = HWMODE_G; + break; + default: + ERROR(rt2x00dev, + "Attempt to configure unsupported mode (%d)" + "Defaulting to 802.11b", conf->phymode); + libconf.phymode = HWMODE_B; + } + + mode = &rt2x00dev->hwmodes[libconf.phymode]; + rate = &mode->rates[mode->num_rates - 1]; + + libconf.basic_rates = + DEVICE_GET_RATE_FIELD(rate->val, RATEMASK) & DEV_BASIC_RATEMASK; + } + + if (flags & CONFIG_UPDATE_CHANNEL) { + memcpy(&libconf.rf, + &rt2x00dev->spec.channels[conf->channel_val], + sizeof(libconf.rf)); + } + + if (flags & CONFIG_UPDATE_SLOT_TIME) { + short_slot_time = conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME; + + libconf.slot_time = + short_slot_time ? SHORT_SLOT_TIME : SLOT_TIME; + libconf.sifs = SIFS; + libconf.pifs = short_slot_time ? SHORT_PIFS : PIFS; + libconf.difs = short_slot_time ? SHORT_DIFS : DIFS; + libconf.eifs = EIFS; + } + + libconf.conf = conf; + + /* + * Start configuration. + */ + rt2x00dev->ops->lib->config(rt2x00dev, flags, &libconf); /* * Some configuration changes affect the link quality @@ -138,6 +196,7 @@ config: if (flags & (CONFIG_UPDATE_CHANNEL | CONFIG_UPDATE_ANTENNA)) rt2x00lib_reset_link_tuner(rt2x00dev); + rt2x00dev->curr_hwmode = libconf.phymode; rt2x00dev->rx_status.phymode = conf->phymode; rt2x00dev->rx_status.freq = conf->freq; rt2x00dev->rx_status.channel = conf->channel; diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index e1410486917..bb6f46cfbb9 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -142,6 +142,8 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev) cancel_work_sync(&rt2x00dev->beacon_work); if (work_pending(&rt2x00dev->filter_work)) cancel_work_sync(&rt2x00dev->filter_work); + if (work_pending(&rt2x00dev->config_work)) + cancel_work_sync(&rt2x00dev->config_work); /* * Stop the TX queues. @@ -288,6 +290,16 @@ static void rt2x00lib_packetfilter_scheduled(struct work_struct *work) filter, &filter, 0, NULL); } +static void rt2x00lib_configuration_scheduled(struct work_struct *work) +{ + struct rt2x00_dev *rt2x00dev = + container_of(work, struct rt2x00_dev, config_work); + int preamble = !test_bit(CONFIG_SHORT_PREAMBLE, &rt2x00dev->flags); + + rt2x00mac_erp_ie_changed(rt2x00dev->hw, + IEEE80211_ERP_CHANGE_PREAMBLE, 0, preamble); +} + /* * Interrupt context handlers. */ @@ -990,6 +1002,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) */ INIT_WORK(&rt2x00dev->beacon_work, rt2x00lib_beacondone_scheduled); INIT_WORK(&rt2x00dev->filter_work, rt2x00lib_packetfilter_scheduled); + INIT_WORK(&rt2x00dev->config_work, rt2x00lib_configuration_scheduled); INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00lib_link_tuner); /* diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index f519d739684..4a6a0bd01ff 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -365,6 +365,40 @@ int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw, } EXPORT_SYMBOL_GPL(rt2x00mac_get_tx_stats); +void rt2x00mac_erp_ie_changed(struct ieee80211_hw *hw, u8 changes, + int cts_protection, int preamble) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + int short_preamble; + int ack_timeout; + int ack_consume_time; + int difs; + + /* + * We only support changing preamble mode. + */ + if (!(changes & IEEE80211_ERP_CHANGE_PREAMBLE)) + return; + + short_preamble = !preamble; + preamble = !!(preamble) ? PREAMBLE : SHORT_PREAMBLE; + + difs = (hw->conf.flags & IEEE80211_CONF_SHORT_SLOT_TIME) ? + SHORT_DIFS : DIFS; + ack_timeout = difs + PLCP + preamble + get_duration(ACK_SIZE, 10); + + ack_consume_time = SIFS + PLCP + preamble + get_duration(ACK_SIZE, 10); + + if (short_preamble) + __set_bit(CONFIG_SHORT_PREAMBLE, &rt2x00dev->flags); + else + __clear_bit(CONFIG_SHORT_PREAMBLE, &rt2x00dev->flags); + + rt2x00dev->ops->lib->config_preamble(rt2x00dev, short_preamble, + ack_timeout, ack_consume_time); +} +EXPORT_SYMBOL_GPL(rt2x00mac_erp_ie_changed); + int rt2x00mac_conf_tx(struct ieee80211_hw *hw, int queue, const struct ieee80211_tx_queue_params *params) { diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index cd22817cced..1a869a5cbe9 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -328,62 +328,31 @@ static void rt61pci_config_type(struct rt2x00_dev *rt2x00dev, const int type, rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); } -static void rt61pci_config_rate(struct rt2x00_dev *rt2x00dev, const int rate) +static void rt61pci_config_preamble(struct rt2x00_dev *rt2x00dev, + const int short_preamble, + const int ack_timeout, + const int ack_consume_time) { - struct ieee80211_conf *conf = &rt2x00dev->hw->conf; u32 reg; - u32 value; - u32 preamble; - - if (DEVICE_GET_RATE_FIELD(rate, PREAMBLE)) - preamble = SHORT_PREAMBLE; - else - preamble = PREAMBLE; - - /* - * Extract the allowed ratemask from the device specific rate value, - * We need to set TXRX_CSR5 to the basic rate mask so we need to mask - * off the non-basic rates. - */ - reg = DEVICE_GET_RATE_FIELD(rate, RATEMASK) & DEV_BASIC_RATEMASK; - - rt2x00pci_register_write(rt2x00dev, TXRX_CSR5, reg); rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®); - value = ((conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) ? - SHORT_DIFS : DIFS) + - PLCP + preamble + get_duration(ACK_SIZE, 10); - rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, value); + rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, ack_timeout); rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, ®); rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, - (preamble == SHORT_PREAMBLE)); + !!short_preamble); rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg); } static void rt61pci_config_phymode(struct rt2x00_dev *rt2x00dev, - const int phymode) + const int basic_rate_mask) { - struct ieee80211_hw_mode *mode; - struct ieee80211_rate *rate; - - if (phymode == MODE_IEEE80211A) - rt2x00dev->curr_hwmode = HWMODE_A; - else if (phymode == MODE_IEEE80211B) - rt2x00dev->curr_hwmode = HWMODE_B; - else - rt2x00dev->curr_hwmode = HWMODE_G; - - mode = &rt2x00dev->hwmodes[rt2x00dev->curr_hwmode]; - rate = &mode->rates[mode->num_rates - 1]; - - rt61pci_config_rate(rt2x00dev, rate->val2); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR5, basic_rate_mask); } -static void rt61pci_config_lock_channel(struct rt2x00_dev *rt2x00dev, - struct rf_channel *rf, - const int txpower) +static void rt61pci_config_channel(struct rt2x00_dev *rt2x00dev, + struct rf_channel *rf, const int txpower) { u8 r3; u8 r94; @@ -428,20 +397,6 @@ static void rt61pci_config_lock_channel(struct rt2x00_dev *rt2x00dev, msleep(1); } -static void rt61pci_config_channel(struct rt2x00_dev *rt2x00dev, - const int index, const int channel, - const int txpower) -{ - struct rf_channel rf; - - /* - * Fill rf_reg structure. - */ - memcpy(&rf, &rt2x00dev->spec.channels[index], sizeof(rf)); - - rt61pci_config_lock_channel(rt2x00dev, &rf, txpower); -} - static void rt61pci_config_txpower(struct rt2x00_dev *rt2x00dev, const int txpower) { @@ -452,7 +407,7 @@ static void rt61pci_config_txpower(struct rt2x00_dev *rt2x00dev, rt2x00_rf_read(rt2x00dev, 3, &rf.rf3); rt2x00_rf_read(rt2x00dev, 4, &rf.rf4); - rt61pci_config_lock_channel(rt2x00dev, &rf, txpower); + rt61pci_config_channel(rt2x00dev, &rf, txpower); } static void rt61pci_config_antenna_5x(struct rt2x00_dev *rt2x00dev, @@ -714,20 +669,18 @@ static void rt61pci_config_antenna(struct rt2x00_dev *rt2x00dev, } static void rt61pci_config_duration(struct rt2x00_dev *rt2x00dev, - const int short_slot_time, - const int beacon_int) + struct rt2x00lib_conf *libconf) { u32 reg; rt2x00pci_register_read(rt2x00dev, MAC_CSR9, ®); - rt2x00_set_field32(®, MAC_CSR9_SLOT_TIME, - short_slot_time ? SHORT_SLOT_TIME : SLOT_TIME); + rt2x00_set_field32(®, MAC_CSR9_SLOT_TIME, libconf->slot_time); rt2x00pci_register_write(rt2x00dev, MAC_CSR9, reg); rt2x00pci_register_read(rt2x00dev, MAC_CSR8, ®); - rt2x00_set_field32(®, MAC_CSR8_SIFS, SIFS); + rt2x00_set_field32(®, MAC_CSR8_SIFS, libconf->sifs); rt2x00_set_field32(®, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3); - rt2x00_set_field32(®, MAC_CSR8_EIFS, EIFS); + rt2x00_set_field32(®, MAC_CSR8_EIFS, libconf->eifs); rt2x00pci_register_write(rt2x00dev, MAC_CSR8, reg); rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®); @@ -739,29 +692,27 @@ static void rt61pci_config_duration(struct rt2x00_dev *rt2x00dev, rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg); rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®); - rt2x00_set_field32(®, TXRX_CSR9_BEACON_INTERVAL, beacon_int * 16); + rt2x00_set_field32(®, TXRX_CSR9_BEACON_INTERVAL, + libconf->conf->beacon_int * 16); rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); } static void rt61pci_config(struct rt2x00_dev *rt2x00dev, const unsigned int flags, - struct ieee80211_conf *conf) + struct rt2x00lib_conf *libconf) { - int short_slot_time = conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME; - if (flags & CONFIG_UPDATE_PHYMODE) - rt61pci_config_phymode(rt2x00dev, conf->phymode); + rt61pci_config_phymode(rt2x00dev, libconf->basic_rates); if (flags & CONFIG_UPDATE_CHANNEL) - rt61pci_config_channel(rt2x00dev, conf->channel_val, - conf->channel, conf->power_level); + rt61pci_config_channel(rt2x00dev, &libconf->rf, + libconf->conf->power_level); if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL)) - rt61pci_config_txpower(rt2x00dev, conf->power_level); + rt61pci_config_txpower(rt2x00dev, libconf->conf->power_level); if (flags & CONFIG_UPDATE_ANTENNA) - rt61pci_config_antenna(rt2x00dev, conf->antenna_sel_tx, - conf->antenna_sel_rx); + rt61pci_config_antenna(rt2x00dev, libconf->conf->antenna_sel_tx, + libconf->conf->antenna_sel_rx); if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT)) - rt61pci_config_duration(rt2x00dev, short_slot_time, - conf->beacon_int); + rt61pci_config_duration(rt2x00dev, libconf); } /* @@ -2513,6 +2464,7 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = { .configure_filter = rt61pci_configure_filter, .get_stats = rt2x00mac_get_stats, .set_retry_limit = rt61pci_set_retry_limit, + .erp_ie_changed = rt2x00mac_erp_ie_changed, .conf_tx = rt2x00mac_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, .get_tsf = rt61pci_get_tsf, @@ -2539,6 +2491,7 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = { .config_mac_addr = rt61pci_config_mac_addr, .config_bssid = rt61pci_config_bssid, .config_type = rt61pci_config_type, + .config_preamble = rt61pci_config_preamble, .config = rt61pci_config, }; diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 9e1bf4d77e1..984117fe1f5 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -308,57 +308,40 @@ static void rt73usb_config_type(struct rt2x00_dev *rt2x00dev, const int type, rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg); } -static void rt73usb_config_rate(struct rt2x00_dev *rt2x00dev, const int rate) +static void rt73usb_config_preamble(struct rt2x00_dev *rt2x00dev, + const int short_preamble, + const int ack_timeout, + const int ack_consume_time) { - struct ieee80211_conf *conf = &rt2x00dev->hw->conf; u32 reg; - u32 value; - u32 preamble; - if (DEVICE_GET_RATE_FIELD(rate, PREAMBLE)) - preamble = SHORT_PREAMBLE; - else - preamble = PREAMBLE; - - reg = DEVICE_GET_RATE_FIELD(rate, RATEMASK) & DEV_BASIC_RATEMASK; - - rt73usb_register_write(rt2x00dev, TXRX_CSR5, reg); + /* + * When in atomic context, reschedule and let rt2x00lib + * call this function again. + */ + if (in_atomic()) { + queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->config_work); + return; + } rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); - value = ((conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) ? - SHORT_DIFS : DIFS) + - PLCP + preamble + get_duration(ACK_SIZE, 10); - rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, value); + rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, ack_timeout); rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg); rt73usb_register_read(rt2x00dev, TXRX_CSR4, ®); rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, - (preamble == SHORT_PREAMBLE)); + !!short_preamble); rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg); } static void rt73usb_config_phymode(struct rt2x00_dev *rt2x00dev, - const int phymode) + const int basic_rate_mask) { - struct ieee80211_hw_mode *mode; - struct ieee80211_rate *rate; - - if (phymode == MODE_IEEE80211A) - rt2x00dev->curr_hwmode = HWMODE_A; - else if (phymode == MODE_IEEE80211B) - rt2x00dev->curr_hwmode = HWMODE_B; - else - rt2x00dev->curr_hwmode = HWMODE_G; - - mode = &rt2x00dev->hwmodes[rt2x00dev->curr_hwmode]; - rate = &mode->rates[mode->num_rates - 1]; - - rt73usb_config_rate(rt2x00dev, rate->val2); + rt73usb_register_write(rt2x00dev, TXRX_CSR5, basic_rate_mask); } -static void rt73usb_config_lock_channel(struct rt2x00_dev *rt2x00dev, - struct rf_channel *rf, - const int txpower) +static void rt73usb_config_channel(struct rt2x00_dev *rt2x00dev, + struct rf_channel *rf, const int txpower) { u8 r3; u8 r94; @@ -399,20 +382,6 @@ static void rt73usb_config_lock_channel(struct rt2x00_dev *rt2x00dev, udelay(10); } -static void rt73usb_config_channel(struct rt2x00_dev *rt2x00dev, - const int index, const int channel, - const int txpower) -{ - struct rf_channel rf; - - /* - * Fill rf_reg structure. - */ - memcpy(&rf, &rt2x00dev->spec.channels[index], sizeof(rf)); - - rt73usb_config_lock_channel(rt2x00dev, &rf, txpower); -} - static void rt73usb_config_txpower(struct rt2x00_dev *rt2x00dev, const int txpower) { @@ -423,7 +392,7 @@ static void rt73usb_config_txpower(struct rt2x00_dev *rt2x00dev, rt2x00_rf_read(rt2x00dev, 3, &rf.rf3); rt2x00_rf_read(rt2x00dev, 4, &rf.rf4); - rt73usb_config_lock_channel(rt2x00dev, &rf, txpower); + rt73usb_config_channel(rt2x00dev, &rf, txpower); } static void rt73usb_config_antenna_5x(struct rt2x00_dev *rt2x00dev, @@ -577,20 +546,18 @@ static void rt73usb_config_antenna(struct rt2x00_dev *rt2x00dev, } static void rt73usb_config_duration(struct rt2x00_dev *rt2x00dev, - const int short_slot_time, - const int beacon_int) + struct rt2x00lib_conf *libconf) { u32 reg; rt73usb_register_read(rt2x00dev, MAC_CSR9, ®); - rt2x00_set_field32(®, MAC_CSR9_SLOT_TIME, - short_slot_time ? SHORT_SLOT_TIME : SLOT_TIME); + rt2x00_set_field32(®, MAC_CSR9_SLOT_TIME, libconf->slot_time); rt73usb_register_write(rt2x00dev, MAC_CSR9, reg); rt73usb_register_read(rt2x00dev, MAC_CSR8, ®); - rt2x00_set_field32(®, MAC_CSR8_SIFS, SIFS); + rt2x00_set_field32(®, MAC_CSR8_SIFS, libconf->sifs); rt2x00_set_field32(®, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3); - rt2x00_set_field32(®, MAC_CSR8_EIFS, EIFS); + rt2x00_set_field32(®, MAC_CSR8_EIFS, libconf->eifs); rt73usb_register_write(rt2x00dev, MAC_CSR8, reg); rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); @@ -602,29 +569,27 @@ static void rt73usb_config_duration(struct rt2x00_dev *rt2x00dev, rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg); rt73usb_register_read(rt2x00dev, TXRX_CSR9, ®); - rt2x00_set_field32(®, TXRX_CSR9_BEACON_INTERVAL, beacon_int * 16); + rt2x00_set_field32(®, TXRX_CSR9_BEACON_INTERVAL, + libconf->conf->beacon_int * 16); rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg); } static void rt73usb_config(struct rt2x00_dev *rt2x00dev, const unsigned int flags, - struct ieee80211_conf *conf) + struct rt2x00lib_conf *libconf) { - int short_slot_time = conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME; - if (flags & CONFIG_UPDATE_PHYMODE) - rt73usb_config_phymode(rt2x00dev, conf->phymode); + rt73usb_config_phymode(rt2x00dev, libconf->basic_rates); if (flags & CONFIG_UPDATE_CHANNEL) - rt73usb_config_channel(rt2x00dev, conf->channel_val, - conf->channel, conf->power_level); + rt73usb_config_channel(rt2x00dev, &libconf->rf, + libconf->conf->power_level); if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL)) - rt73usb_config_txpower(rt2x00dev, conf->power_level); + rt73usb_config_txpower(rt2x00dev, libconf->conf->power_level); if (flags & CONFIG_UPDATE_ANTENNA) - rt73usb_config_antenna(rt2x00dev, conf->antenna_sel_tx, - conf->antenna_sel_rx); + rt73usb_config_antenna(rt2x00dev, libconf->conf->antenna_sel_tx, + libconf->conf->antenna_sel_rx); if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT)) - rt73usb_config_duration(rt2x00dev, short_slot_time, - conf->beacon_int); + rt73usb_config_duration(rt2x00dev, libconf); } /* @@ -2002,6 +1967,7 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = { .configure_filter = rt73usb_configure_filter, .get_stats = rt2x00mac_get_stats, .set_retry_limit = rt73usb_set_retry_limit, + .erp_ie_changed = rt2x00mac_erp_ie_changed, .conf_tx = rt2x00mac_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, #if 0 @@ -2032,6 +1998,7 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = { .config_mac_addr = rt73usb_config_mac_addr, .config_bssid = rt73usb_config_bssid, .config_type = rt73usb_config_type, + .config_preamble = rt73usb_config_preamble, .config = rt73usb_config, }; -- cgit v1.2.3-70-g09d2 From 37894473fb0d07e1e015781f7ae1b9b1762d49be Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 6 Oct 2007 14:18:00 +0200 Subject: [PATCH] rt2x00: Clean disabling of rt73usb_get_tsf By defining rt73usb_get_tsf to NULL we only have 1 location that needs to be edited when rt73usb_get_tsf can be enabled again. This also reduces the number of #ifdefs in the code which is also a "good thing" Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt73usb.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 984117fe1f5..67a1e3750d4 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1910,6 +1910,8 @@ static u64 rt73usb_get_tsf(struct ieee80211_hw *hw) return tsf; } +#else +#define rt73usb_get_tsf NULL #endif static void rt73usb_reset_tsf(struct ieee80211_hw *hw) @@ -1970,12 +1972,7 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = { .erp_ie_changed = rt2x00mac_erp_ie_changed, .conf_tx = rt2x00mac_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, -#if 0 -/* - * See comment at the rt73usb_get_tsf function. - */ .get_tsf = rt73usb_get_tsf, -#endif .reset_tsf = rt73usb_reset_tsf, .beacon_update = rt73usb_beacon_update, }; -- cgit v1.2.3-70-g09d2 From c22eb87b5723b3d66665ca2ffa87428e0e489b16 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 6 Oct 2007 14:18:22 +0200 Subject: [PATCH] rt2x00: Allways memset memory obtained from skb_push() When skb_push() is used we should memset the memory before usage. This will prevent bugs which could occur when the data is treated as TX descriptor. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2500usb.c | 2 ++ drivers/net/wireless/rt2x00/rt61pci.c | 2 ++ drivers/net/wireless/rt2x00/rt73usb.c | 2 ++ 3 files changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 45f8f744a12..7cdc80a122b 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1665,6 +1665,8 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw, * First we create the beacon. */ skb_push(skb, ring->desc_size); + memset(skb->data, 0, ring->desc_size); + rt2x00lib_write_tx_desc(rt2x00dev, (struct data_desc *)skb->data, (struct ieee80211_hdr *)(skb->data + ring->desc_size), diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 1a869a5cbe9..01dbef19d65 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2437,6 +2437,8 @@ static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, * First we create the beacon. */ skb_push(skb, TXD_DESC_SIZE); + memset(skb->data, 0, TXD_DESC_SIZE); + rt2x00lib_write_tx_desc(rt2x00dev, (struct data_desc *)skb->data, (struct ieee80211_hdr *)(skb->data + TXD_DESC_SIZE), diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 67a1e3750d4..3e42759473c 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1939,6 +1939,8 @@ static int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, * First we create the beacon. */ skb_push(skb, TXD_DESC_SIZE); + memset(skb->data, 0, TXD_DESC_SIZE); + rt2x00lib_write_tx_desc(rt2x00dev, (struct data_desc *)skb->data, (struct ieee80211_hdr *)(skb->data + TXD_DESC_SIZE), -- cgit v1.2.3-70-g09d2 From 515ea2492cfc93233ba31402d1992a435aa78f37 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 6 Oct 2007 14:18:41 +0200 Subject: [PATCH] rt2x00: Release 2.0.10 Version bump Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index aabbe425470..9845e584b73 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -42,7 +42,7 @@ * Module information. * DRV_NAME should be set within the individual module source files. */ -#define DRV_VERSION "2.0.9" +#define DRV_VERSION "2.0.10" #define DRV_PROJECT "http://rt2x00.serialmonkey.com" /* -- cgit v1.2.3-70-g09d2 From 2bcde51d095490c223bb4ade351cb7981c367934 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 3 Oct 2007 10:37:45 -0400 Subject: [PATCH] libertas: problems setting wpa keys The 88w8385 chip, using SDIO interface and firmware release 5.0.11p0, has problems when both unicast and multicast WPA keys are set in one command. This patch ensures the keys are set independently. The original author of this patch is Marc Pignat Signed-off-by: Marc Pignat Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/assoc.c | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index 2c6ddb1f007..b61b176e9d0 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -374,15 +374,40 @@ static int assoc_helper_wpa_keys(wlan_private *priv, struct assoc_request * assoc_req) { int ret = 0; + unsigned int flags = assoc_req->flags; lbs_deb_enter(LBS_DEB_ASSOC); - ret = libertas_prepare_and_send_command(priv, - CMD_802_11_KEY_MATERIAL, - CMD_ACT_SET, - CMD_OPTION_WAITFORRSP, - 0, assoc_req); + /* Work around older firmware bug where WPA unicast and multicast + * keys must be set independently. Seen in SDIO parts with firmware + * version 5.0.11p0. + */ + if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) { + clear_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags); + ret = libertas_prepare_and_send_command(priv, + CMD_802_11_KEY_MATERIAL, + CMD_ACT_SET, + CMD_OPTION_WAITFORRSP, + 0, assoc_req); + assoc_req->flags = flags; + } + + if (ret) + goto out; + + if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) { + clear_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags); + + ret = libertas_prepare_and_send_command(priv, + CMD_802_11_KEY_MATERIAL, + CMD_ACT_SET, + CMD_OPTION_WAITFORRSP, + 0, assoc_req); + assoc_req->flags = flags; + } + +out: lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); return ret; } -- cgit v1.2.3-70-g09d2 From 6470a89de90167cc1ff8a0312197ca422f5fe35f Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Mon, 8 Oct 2007 11:07:27 +0200 Subject: [PATCH] libertas: fix u8 constant Don't write constants that are (per documentation and struct) u8 as 0x0001, use 0x01 instead. Also remove an useless cast. Signed-off-by: Holger Schurig Acked-By: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 4 ++-- drivers/net/wireless/libertas/host.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 33dbed09fc7..1cbbd96fdbd 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -181,13 +181,13 @@ static int wlan_cmd_802_11_set_wep(wlan_private * priv, switch (pkey->len) { case KEY_LEN_WEP_40: - wep->keytype[i] = (u8)CMD_TYPE_WEP_40_BIT; + wep->keytype[i] = CMD_TYPE_WEP_40_BIT; memmove(&wep->keymaterial[i], pkey->key, pkey->len); lbs_deb_cmd("SET_WEP: add key %d (40 bit)\n", i); break; case KEY_LEN_WEP_104: - wep->keytype[i] = (u8)CMD_TYPE_WEP_104_BIT; + wep->keytype[i] = CMD_TYPE_WEP_104_BIT; memmove(&wep->keymaterial[i], pkey->key, pkey->len); lbs_deb_cmd("SET_WEP: add key %d (104 bit)\n", i); diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index 68fa11b3a2d..b37ddbca969 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -138,8 +138,8 @@ #define CMD_ACT_REMOVE 0x0004 #define CMD_ACT_USE_DEFAULT 0x0008 -#define CMD_TYPE_WEP_40_BIT 0x0001 -#define CMD_TYPE_WEP_104_BIT 0x0002 +#define CMD_TYPE_WEP_40_BIT 0x01 +#define CMD_TYPE_WEP_104_BIT 0x02 #define CMD_NUM_OF_WEP_KEYS 4 -- cgit v1.2.3-70-g09d2 From d8b0fb51ef1563c631d26cb649a5479b5cc4899c Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 8 Oct 2007 09:43:02 +0200 Subject: [PATCH] libertas link error due to gcc `smartness' Some versions of gcc replace strstr() calls with a single-character `needle' parameter by strchr() behind our back. This causes a link error if strchr() is defined as an inline function in (e.g. on m68k): | drivers/built-in.o: In function `libertas_parse_chan': | linux/drivers/net/wireless/libertas/debugfs.c:209: undefined reference to `strchr' | drivers/built-in.o: In function `libertas_parse_ssid': | linux/drivers/net/wireless/libertas/debugfs.c:260: undefined reference to `strchr' Avoid this by explicitly calling strchr() instead. Also include , because this file calls lots of str*() routines. Signed-off-by: Geert Uytterhoeven Acked-By: Holger Schurig Acked-By: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/debugfs.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c index cb00b080409..0bda0b51191 100644 --- a/drivers/net/wireless/libertas/debugfs.c +++ b/drivers/net/wireless/libertas/debugfs.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include "dev.h" @@ -205,7 +206,7 @@ static int libertas_parse_chan(char *buf, size_t count, if (!start) return -EINVAL; start += 5; - end = strstr(start, " "); + end = strchr(start, ' '); if (!end) end = buf + count; hold = kzalloc((end - start)+1, GFP_KERNEL); @@ -256,7 +257,7 @@ static void libertas_parse_ssid(char *buf, size_t count, if (!hold) return; hold += 5; - end = strstr(hold, " "); + end = strchr(hold, ' '); if (!end) end = buf + count - 1; -- cgit v1.2.3-70-g09d2 From 8b17d7234c7039b668739e1868f3d5544d79a4c0 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Mon, 8 Oct 2007 11:09:30 +0200 Subject: [PATCH] libertas: fix a debug statement Fix a debug statement Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmdresp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index fe70e30b1f3..8f90892ea22 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -148,7 +148,7 @@ static int wlan_ret_reg_access(wlan_private * priv, ret = -1; } - lbs_deb_enter_args(LBS_DEB_CMD, "ret %d", ret); + lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; } -- cgit v1.2.3-70-g09d2 From 314a886f08d689cdcf10bd8e4777a3d9f483bb53 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Mon, 8 Oct 2007 12:20:04 +0200 Subject: [PATCH] libertas: fix "warning: Using plain integer as NULL pointer" sparse warnings This fixes three "warning: Using plain integer as NULL pointer" sparse warnings. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/scan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index fab93d8fe9c..dcce354e904 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -578,7 +578,7 @@ static int wlan_scan_channel_list(wlan_private * priv, lbs_deb_enter(LBS_DEB_ASSOC); - if (pscancfgout == 0 || pchantlvout == 0 || pscanchanlist == 0) { + if (!pscancfgout || !pchantlvout || !pscanchanlist) { lbs_deb_scan("Scan: Null detect: %p, %p, %p\n", pscancfgout, pchantlvout, pscanchanlist); return -1; -- cgit v1.2.3-70-g09d2 From e56188ac4163cb276b7650949c1e8e20fb2f9c73 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Tue, 9 Oct 2007 14:15:19 +0200 Subject: [PATCH] libertas: clean up scan debug messages * make scan debug output cleaner * change some LBS_DEB_ASSOC messages to LBS_DEB_SCAN, which is more correct * move helper functions together * print function return value in the tracing code at one central location Signed-off-by: Holger Schurig Acked-By: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/join.c | 2 - drivers/net/wireless/libertas/scan.c | 221 ++++++++++++++++++++++++----------- 2 files changed, 155 insertions(+), 68 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c index 8dcff00574f..dc24a05c944 100644 --- a/drivers/net/wireless/libertas/join.c +++ b/drivers/net/wireless/libertas/join.c @@ -800,8 +800,6 @@ int libertas_ret_80211_associate(wlan_private * priv, netif_wake_queue(priv->mesh_dev); } - lbs_deb_join("ASSOC_RESP: Associated \n"); - memcpy(wrqu.ap_addr.sa_data, adapter->curbssparams.bssid, ETH_ALEN); wrqu.ap_addr.sa_family = ARPHRD_ETHER; wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index dcce354e904..ad1e67d984c 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -65,6 +65,15 @@ static const u8 zeromac[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; static const u8 bcastmac[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + + + +/*********************************************************************/ +/* */ +/* Misc helper functions */ +/* */ +/*********************************************************************/ + static inline void clear_bss_descriptor (struct bss_descriptor * bss) { /* Don't blow away ->list, just BSS data */ @@ -165,7 +174,7 @@ static int is_network_compatible(wlan_adapter * adapter, { int matched = 0; - lbs_deb_enter(LBS_DEB_ASSOC); + lbs_deb_enter(LBS_DEB_SCAN); if (bss->mode != mode) goto done; @@ -214,13 +223,41 @@ static int is_network_compatible(wlan_adapter * adapter, (bss->capability & WLAN_CAPABILITY_PRIVACY)); done: - lbs_deb_leave(LBS_DEB_SCAN); + lbs_deb_leave_args(LBS_DEB_SCAN, "matched: %d", matched); return matched; } +/** + * @brief Compare two SSIDs + * + * @param ssid1 A pointer to ssid to compare + * @param ssid2 A pointer to ssid to compare + * + * @return 0--ssid is same, otherwise is different + */ +int libertas_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len) +{ + if (ssid1_len != ssid2_len) + return -1; + + return memcmp(ssid1, ssid2, ssid1_len); +} + + + + +/*********************************************************************/ +/* */ +/* Main scanning support */ +/* */ +/*********************************************************************/ + + /** * @brief Create a channel list for the driver to scan based on region info * + * Only used from wlan_scan_setup_scan_config() + * * Use the driver region/band information to construct a comprehensive list * of channels to scan. This routine is used for any scan that is not * provided a specific channel list to scan. @@ -248,6 +285,8 @@ static void wlan_scan_create_channel_list(wlan_private * priv, int nextchan; u8 scantype; + lbs_deb_enter_args(LBS_DEB_SCAN, "filteredscan %d", filteredscan); + chanidx = 0; /* Set the default scan type to the user specified type, will later @@ -384,6 +423,8 @@ wlan_scan_setup_scan_config(wlan_private * priv, int channel; int radiotype; + lbs_deb_enter(LBS_DEB_SCAN); + pscancfgout = kzalloc(MAX_SCAN_CFG_ALLOC, GFP_KERNEL); if (pscancfgout == NULL) goto out; @@ -481,13 +522,12 @@ wlan_scan_setup_scan_config(wlan_private * priv, if (!puserscanin || !puserscanin->chanlist[0].channumber) { /* Create a default channel scan list */ - lbs_deb_scan("Scan: Creating full region channel list\n"); + lbs_deb_scan("creating full region channel list\n"); wlan_scan_create_channel_list(priv, pscanchanlist, *pfilteredscan); goto out; } - lbs_deb_scan("Scan: Using supplied channel list\n"); for (chanidx = 0; chanidx < WLAN_IOCTL_USER_SCAN_CHAN_MAX && puserscanin->chanlist[chanidx].channumber; chanidx++) { @@ -529,7 +569,7 @@ wlan_scan_setup_scan_config(wlan_private * priv, (puserscanin->chanlist[0].channumber == priv->adapter->curbssparams.channel)) { *pscancurrentonly = 1; - lbs_deb_scan("Scan: Scanning current channel only"); + lbs_deb_scan("scanning current channel only"); } out: @@ -539,6 +579,8 @@ out: /** * @brief Construct and send multiple scan config commands to the firmware * + * Only used from wlan_scan_networks() + * * Previous routines have created a wlan_scan_cmd_config with any requested * TLVs. This function splits the channel TLV into maxchanperscan lists * and sends the portion of the channel TLV along with the other TLVs @@ -576,12 +618,14 @@ static int wlan_scan_channel_list(wlan_private * priv, int scanned = 0; union iwreq_data wrqu; - lbs_deb_enter(LBS_DEB_ASSOC); + lbs_deb_enter_args(LBS_DEB_SCAN, "maxchanperscan %d, filteredscan %d, " + "full_scan %d", maxchanperscan, filteredscan, full_scan); if (!pscancfgout || !pchantlvout || !pscanchanlist) { - lbs_deb_scan("Scan: Null detect: %p, %p, %p\n", - pscancfgout, pchantlvout, pscanchanlist); - return -1; + lbs_deb_scan("pscancfgout, pchantlvout or " + "pscanchanlist is NULL\n"); + ret = -1; + goto out; } pchantlvout->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); @@ -613,9 +657,10 @@ static int wlan_scan_channel_list(wlan_private * priv, while (tlvidx < maxchanperscan && ptmpchan->channumber && !doneearly && scanned < 2) { - lbs_deb_scan("Scan: Chan(%3d), Radio(%d), mode(%d,%d), " - "Dur(%d)\n", - ptmpchan->channumber, ptmpchan->radiotype, + lbs_deb_scan("channel %d, radio %d, passive %d, " + "dischanflt %d, maxscantime %d\n", + ptmpchan->channumber, + ptmpchan->radiotype, ptmpchan->chanscanmode.passivescan, ptmpchan->chanscanmode.disablechanfilt, ptmpchan->maxscantime); @@ -700,20 +745,25 @@ done: wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL); } +out: lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret); return ret; } -static void -clear_selected_scan_list_entries(wlan_adapter * adapter, - const struct wlan_ioctl_user_scan_cfg * scan_cfg) +/* + * Only used from wlan_scan_networks() +*/ +static void clear_selected_scan_list_entries(wlan_adapter *adapter, + const struct wlan_ioctl_user_scan_cfg *scan_cfg) { - struct bss_descriptor * bss; - struct bss_descriptor * safe; + struct bss_descriptor *bss; + struct bss_descriptor *safe; u32 clear_ssid_flag = 0, clear_bssid_flag = 0; + lbs_deb_enter(LBS_DEB_SCAN); + if (!scan_cfg) - return; + goto out; if (scan_cfg->clear_ssid && scan_cfg->ssid_len) clear_ssid_flag = 1; @@ -725,7 +775,7 @@ clear_selected_scan_list_entries(wlan_adapter * adapter, } if (!clear_ssid_flag && !clear_bssid_flag) - return; + goto out; mutex_lock(&adapter->lock); list_for_each_entry_safe (bss, safe, &adapter->network_list, list) { @@ -748,12 +798,16 @@ clear_selected_scan_list_entries(wlan_adapter * adapter, } } mutex_unlock(&adapter->lock); +out: + lbs_deb_leave(LBS_DEB_SCAN); } /** * @brief Internal function used to start a scan based on an input config * + * Also used from debugfs + * * Use the input user scan configuration information when provided in * order to send the appropriate scan commands to firmware to populate or * update the internal driver scan table @@ -761,6 +815,7 @@ clear_selected_scan_list_entries(wlan_adapter * adapter, * @param priv A pointer to wlan_private structure * @param puserscanin Pointer to the input configuration for the requested * scan. + * @param full_scan ??? * * @return 0 or < 0 if error */ @@ -782,7 +837,7 @@ int wlan_scan_networks(wlan_private * priv, DECLARE_MAC_BUF(mac); #endif - lbs_deb_enter(LBS_DEB_SCAN); + lbs_deb_enter_args(LBS_DEB_SCAN, "full_scan %d", full_scan); /* Cancel any partial outstanding partial scans if this scan * is a full scan. @@ -833,8 +888,9 @@ int wlan_scan_networks(wlan_private * priv, #ifdef CONFIG_LIBERTAS_DEBUG /* Dump the scan table */ mutex_lock(&adapter->lock); + lbs_deb_scan("The scan table contains:\n"); list_for_each_entry (iter_bss, &adapter->network_list, list) { - lbs_deb_scan("Scan:(%02d) %s, RSSI[%03d], SSID[%s]\n", + lbs_deb_scan("scan %02d, %s, RSSI, %d, SSID '%s'\n", i++, print_mac(mac, iter_bss->bssid), (s32) iter_bss->rssi, escape_essid(iter_bss->ssid, iter_bss->ssid_len)); } @@ -886,7 +942,7 @@ static int libertas_process_bss(struct bss_descriptor * bss, u16 beaconsize = 0; int ret; - lbs_deb_enter(LBS_DEB_ASSOC); + lbs_deb_enter(LBS_DEB_SCAN); if (*bytesleft >= sizeof(beaconsize)) { /* Extract & convert beacon size from the command buffer */ @@ -898,7 +954,8 @@ static int libertas_process_bss(struct bss_descriptor * bss, if (beaconsize == 0 || beaconsize > *bytesleft) { *pbeaconinfo += *bytesleft; *bytesleft = 0; - return -1; + ret = -1; + goto done; } /* Initialize the current working beacon pointer for this BSS iteration */ @@ -915,7 +972,8 @@ static int libertas_process_bss(struct bss_descriptor * bss, if ((end - pos) < 12) { lbs_deb_scan("process_bss: Not enough bytes left\n"); - return -1; + ret = -1; + goto done; } /* @@ -1090,39 +1148,27 @@ done: return ret; } -/** - * @brief Compare two SSIDs - * - * @param ssid1 A pointer to ssid to compare - * @param ssid2 A pointer to ssid to compare - * - * @return 0--ssid is same, otherwise is different - */ -int libertas_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len) -{ - if (ssid1_len != ssid2_len) - return -1; - - return memcmp(ssid1, ssid2, ssid1_len); -} - /** * @brief This function finds a specific compatible BSSID in the scan list * + * Used in association code + * * @param adapter A pointer to wlan_adapter * @param bssid BSSID to find in the scan list * @param mode Network mode: Infrastructure or IBSS * * @return index in BSSID list, or error return code (< 0) */ -struct bss_descriptor * libertas_find_bssid_in_list(wlan_adapter * adapter, +struct bss_descriptor *libertas_find_bssid_in_list(wlan_adapter * adapter, u8 * bssid, u8 mode) { struct bss_descriptor * iter_bss; struct bss_descriptor * found_bss = NULL; + lbs_deb_enter(LBS_DEB_SCAN); + if (!bssid) - return NULL; + goto out; lbs_deb_hex(LBS_DEB_SCAN, "looking for", bssid, ETH_ALEN); @@ -1149,12 +1195,16 @@ struct bss_descriptor * libertas_find_bssid_in_list(wlan_adapter * adapter, } mutex_unlock(&adapter->lock); +out: + lbs_deb_leave_args(LBS_DEB_SCAN, "found_bss %p", found_bss); return found_bss; } /** * @brief This function finds ssid in ssid list. * + * Used in association code + * * @param adapter A pointer to wlan_adapter * @param ssid SSID to find in the list * @param bssid BSSID to qualify the SSID selection (if provided) @@ -1171,6 +1221,8 @@ struct bss_descriptor * libertas_find_ssid_in_list(wlan_adapter * adapter, struct bss_descriptor * found_bss = NULL; struct bss_descriptor * tmp_oldest = NULL; + lbs_deb_enter(LBS_DEB_SCAN); + mutex_lock(&adapter->lock); list_for_each_entry (iter_bss, &adapter->network_list, list) { @@ -1215,6 +1267,7 @@ struct bss_descriptor * libertas_find_ssid_in_list(wlan_adapter * adapter, out: mutex_unlock(&adapter->lock); + lbs_deb_leave_args(LBS_DEB_SCAN, "found_bss %p", found_bss); return found_bss; } @@ -1235,6 +1288,8 @@ static struct bss_descriptor * libertas_find_best_ssid_in_list(wlan_adapter * ad struct bss_descriptor * iter_bss; struct bss_descriptor * best_bss = NULL; + lbs_deb_enter(LBS_DEB_SCAN); + mutex_lock(&adapter->lock); list_for_each_entry (iter_bss, &adapter->network_list, list) { @@ -1259,12 +1314,15 @@ static struct bss_descriptor * libertas_find_best_ssid_in_list(wlan_adapter * ad } mutex_unlock(&adapter->lock); + lbs_deb_leave_args(LBS_DEB_SCAN, "best_bss %p", best_bss); return best_bss; } /** * @brief Find the AP with specific ssid in the scan list * + * Used from association worker. + * * @param priv A pointer to wlan_private structure * @param pSSID A pointer to AP's ssid * @@ -1277,11 +1335,11 @@ int libertas_find_best_network_ssid(wlan_private * priv, int ret = -1; struct bss_descriptor * found; - lbs_deb_enter(LBS_DEB_ASSOC); + lbs_deb_enter(LBS_DEB_SCAN); wlan_scan_networks(priv, NULL, 1); if (adapter->surpriseremoved) - return -1; + goto out; wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending); @@ -1293,6 +1351,7 @@ int libertas_find_best_network_ssid(wlan_private * priv, ret = 0; } +out: lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret); return ret; } @@ -1327,10 +1386,17 @@ int libertas_set_scan(struct net_device *dev, struct iw_request_info *info, return 0; } + /** * @brief Send a scan command for all available channels filtered on a spec * + * Used in association code and from debugfs + * * @param priv A pointer to wlan_private structure + * @param ssid A pointer to the SSID to scan for + * @param ssid_len Length of the SSID + * @param clear_ssid Should existing scan results with this SSID + * be cleared? * @param prequestedssid A pointer to AP's ssid * @param keeppreviousscan Flag used to save/clear scan table before scan * @@ -1343,7 +1409,8 @@ int libertas_send_specific_ssid_scan(wlan_private * priv, struct wlan_ioctl_user_scan_cfg scancfg; int ret = 0; - lbs_deb_enter(LBS_DEB_ASSOC); + lbs_deb_enter_args(LBS_DEB_SCAN, "SSID '%s', clear %d", + escape_essid(ssid, ssid_len), clear_ssid); if (!ssid_len) goto out; @@ -1354,15 +1421,26 @@ int libertas_send_specific_ssid_scan(wlan_private * priv, scancfg.clear_ssid = clear_ssid; wlan_scan_networks(priv, &scancfg, 1); - if (adapter->surpriseremoved) - return -1; + if (adapter->surpriseremoved) { + ret = -1; + goto out; + } wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending); out: - lbs_deb_leave(LBS_DEB_ASSOC); + lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret); return ret; } + + + +/*********************************************************************/ +/* */ +/* Support for Wireless Extensions */ +/* */ +/*********************************************************************/ + #define MAX_CUSTOM_LEN 64 static inline char *libertas_translate_scan(wlan_private *priv, @@ -1379,10 +1457,13 @@ static inline char *libertas_translate_scan(wlan_private *priv, #define RSSI_DIFF ((u8)(PERFECT_RSSI - WORST_RSSI)) u8 rssi; + lbs_deb_enter(LBS_DEB_SCAN); + cfp = libertas_find_cfp_by_band_and_channel(adapter, 0, bss->channel); if (!cfp) { lbs_deb_scan("Invalid channel number %d\n", bss->channel); - return NULL; + start = NULL; + goto out; } /* First entry *MUST* be the AP BSSID */ @@ -1510,11 +1591,13 @@ static inline char *libertas_translate_scan(wlan_private *priv, start = iwe_stream_add_point(start, stop, &iwe, custom); } +out: + lbs_deb_leave_args(LBS_DEB_SCAN, "start %p", start); return start; } /** - * @brief Retrieve the scan table entries via wireless tools IOCTL call + * @brief Handle Retrieve scan table ioctl * * @param dev A pointer to net_device structure * @param info A pointer to iw_request_info structure @@ -1535,7 +1618,7 @@ int libertas_get_scan(struct net_device *dev, struct iw_request_info *info, struct bss_descriptor * iter_bss; struct bss_descriptor * safe; - lbs_deb_enter(LBS_DEB_ASSOC); + lbs_deb_enter(LBS_DEB_SCAN); /* Update RSSI if current BSS is a locally created ad-hoc BSS */ if ((adapter->mode == IW_MODE_ADHOC) && adapter->adhoccreate) { @@ -1577,19 +1660,27 @@ int libertas_get_scan(struct net_device *dev, struct iw_request_info *info, dwrq->length = (ev - extra); dwrq->flags = 0; - lbs_deb_leave(LBS_DEB_ASSOC); + lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", err); return err; } + + + +/*********************************************************************/ +/* */ +/* Command execution */ +/* */ +/*********************************************************************/ + + /** * @brief Prepare a scan command to be sent to the firmware * - * Use the wlan_scan_cmd_config sent to the command processing module in - * the libertas_prepare_and_send_command to configure a cmd_ds_802_11_scan command - * struct to send to firmware. + * Called from libertas_prepare_and_send_command() in cmd.c * - * The fixed fields specifying the BSS type and BSSID filters as well as a - * variable number/length of TLVs are sent in the command to firmware. + * Sends a fixed lenght data part (specifying the BSS type and BSSID filters) + * as well as a variable number/length of TLVs to the firmware. * * @param priv A pointer to wlan_private structure * @param cmd A pointer to cmd_ds_command structure to be sent to @@ -1598,18 +1689,14 @@ int libertas_get_scan(struct net_device *dev, struct iw_request_info *info, * to set the fields/TLVs for the command sent to firmware * * @return 0 or -1 - * - * @sa wlan_scan_create_channel_list */ int libertas_cmd_80211_scan(wlan_private * priv, struct cmd_ds_command *cmd, void *pdata_buf) { struct cmd_ds_802_11_scan *pscan = &cmd->params.scan; - struct wlan_scan_cmd_config *pscancfg; - - lbs_deb_enter(LBS_DEB_ASSOC); + struct wlan_scan_cmd_config *pscancfg = pdata_buf; - pscancfg = pdata_buf; + lbs_deb_enter(LBS_DEB_SCAN); /* Set fixed field variables in scan command */ pscan->bsstype = pscancfg->bsstype; @@ -1622,11 +1709,11 @@ int libertas_cmd_80211_scan(wlan_private * priv, cmd->size = cpu_to_le16(sizeof(pscan->bsstype) + ETH_ALEN + pscancfg->tlvbufferlen + S_DS_GEN); - lbs_deb_scan("SCAN_CMD: command=%x, size=%x, seqnum=%x\n", + lbs_deb_scan("SCAN_CMD: command 0x%04x, size %d, seqnum %d\n", le16_to_cpu(cmd->command), le16_to_cpu(cmd->size), le16_to_cpu(cmd->seqnum)); - lbs_deb_leave(LBS_DEB_ASSOC); + lbs_deb_leave(LBS_DEB_SCAN); return 0; } @@ -1645,6 +1732,8 @@ static inline int is_same_network(struct bss_descriptor *src, /** * @brief This function handles the command response of scan * + * Called from handle_cmd_response() in cmdrespc. + * * The response buffer for the scan command has the following * memory layout: * @@ -1679,7 +1768,7 @@ int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp) int tlvbufsize; int ret; - lbs_deb_enter(LBS_DEB_ASSOC); + lbs_deb_enter(LBS_DEB_SCAN); /* Prune old entries from scan table */ list_for_each_entry_safe (iter_bss, safe, &adapter->network_list, list) { -- cgit v1.2.3-70-g09d2 From cc32613792b9789cebb40240a56bd4a7675b86fc Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Tue, 9 Oct 2007 14:30:10 +0200 Subject: [PATCH] libertas: remove one superfluous include This makes scripts/checkincludes.pl happy. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/if_usb.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index 8a3c70e5407..cb59f46ed12 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -15,7 +15,6 @@ #include "defs.h" #include "dev.h" #include "if_usb.h" -#include "decl.h" #define MESSAGE_HEADER_LEN 4 -- cgit v1.2.3-70-g09d2 From 04799fae8ecb42b2c687fa85fe32ff79ea0e9dc9 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Tue, 9 Oct 2007 15:04:14 +0200 Subject: [PATCH] libertas: let get nick return what set nick has set Make the get-nickname wireless extension actually work. Before this patch, I could do "iwconfig eth1 nick BLAH" but "iwconfig eth1" would have still showed "MRVL-USB8388" to me. Hey, and that was wrong anyway, I'm on a CF card, not on USB :-) Signed-off-by: Holger Schurig Acked-By: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/wext.c | 34 +++++++--------------------------- 1 file changed, 7 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 0b2103e0af5..c6f5aa3cb46 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -237,37 +237,16 @@ static int wlan_set_nick(struct net_device *dev, struct iw_request_info *info, static int wlan_get_nick(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - const char *cp; - char comm[6] = { "COMM-" }; - char mrvl[6] = { "MRVL-" }; - int cnt; + wlan_private *priv = dev->priv; + wlan_adapter *adapter = priv->adapter; lbs_deb_enter(LBS_DEB_WEXT); - /* - * Nick Name is not used internally in this mode, - * therefore return something useful instead. Jean II - */ - - strcpy(extra, mrvl); - - cp = strstr(libertas_driver_version, comm); - if (cp == libertas_driver_version) //skip leading "COMM-" - cp = libertas_driver_version + strlen(comm); - else - cp = libertas_driver_version; + dwrq->length = strlen(adapter->nodename); + memcpy(extra, adapter->nodename, dwrq->length); + extra[dwrq->length] = '\0'; - cnt = strlen(mrvl); - extra += cnt; - while (cnt < 16 && (*cp != '-')) { - *extra++ = toupper(*cp++); - cnt++; - } - - /* - * Push it out ! - */ - dwrq->length = cnt; + dwrq->flags = 1; /* active */ lbs_deb_leave(LBS_DEB_WEXT); return 0; @@ -297,6 +276,7 @@ static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info, lbs_deb_leave(LBS_DEB_WEXT); return 0; } + static int wlan_set_rts(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { -- cgit v1.2.3-70-g09d2 From 6d1e3aa7bd47faacc08fdda8f58896bfd13ad90a Mon Sep 17 00:00:00 2001 From: Krishna Kumar Date: Fri, 5 Oct 2007 14:15:16 -0700 Subject: e1000: Simple optimizations in e1000_xmit_frame Some simple optimizations in e1000_xmit_frame. Signed-off-by: Krishna Kumar Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000_main.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 10505de00bc..047263830e6 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -3261,14 +3261,13 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) unsigned int first, max_per_txd = E1000_MAX_DATA_PER_TXD; unsigned int max_txd_pwr = E1000_MAX_TXD_PWR; unsigned int tx_flags = 0; - unsigned int len = skb->len; + unsigned int len = skb->len - skb->data_len; unsigned long flags; - unsigned int nr_frags = 0; - unsigned int mss = 0; + unsigned int nr_frags; + unsigned int mss; int count = 0; int tso; unsigned int f; - len -= skb->data_len; /* This goes back to the question of how to logically map a tx queue * to a flow. Right now, performance is impacted slightly negatively @@ -3302,7 +3301,7 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) * points to just header, pull a few bytes of payload from * frags into skb->data */ hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); - if (skb->data_len && (hdr_len == (skb->len - skb->data_len))) { + if (skb->data_len && hdr_len == len) { switch (adapter->hw.mac_type) { unsigned int pull_size; case e1000_82544: -- cgit v1.2.3-70-g09d2 From 4e6c709c5ab886be0ddbc96c4f96534e55920e68 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Fri, 5 Oct 2007 14:15:23 -0700 Subject: e1000e: Simple optimizations in e1000_xmit_frame After an e1000 patch from Krishna Kumar . Signed-off-by: Auke Kok Signed-off-by: Jeff Garzik --- drivers/net/e1000e/netdev.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 3a0bb2afe38..600538bc932 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -3424,14 +3424,13 @@ static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) unsigned int max_per_txd = E1000_MAX_PER_TXD; unsigned int max_txd_pwr = E1000_MAX_TXD_PWR; unsigned int tx_flags = 0; - unsigned int len = skb->len; + unsigned int len = skb->len - skb->data_len; unsigned long irq_flags; - unsigned int nr_frags = 0; - unsigned int mss = 0; + unsigned int nr_frags; + unsigned int mss; int count = 0; int tso; unsigned int f; - len -= skb->data_len; if (test_bit(__E1000_DOWN, &adapter->state)) { dev_kfree_skb_any(skb); @@ -3459,7 +3458,7 @@ static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) * points to just header, pull a few bytes of payload from * frags into skb->data */ hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); - if (skb->data_len && (hdr_len == (skb->len - skb->data_len))) { + if (skb->data_len && (hdr_len == len)) { unsigned int pull_size; pull_size = min((unsigned int)4, skb->data_len); -- cgit v1.2.3-70-g09d2 From 309af40b5f4c2065c9a5f74a360ad3d3b0c9c9cd Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Fri, 5 Oct 2007 15:22:02 -0700 Subject: e1000e: restore flow control settings properly After a cable unplug the forced flow control settings were lost accidentally and the flow control settings fell back to the default EEPROM determined values. This breaks for people who want to run without fc enabled - after a cable reset the driver would refuse to run with fc disabled. Signed-off-by: Auke Kok Signed-off-by: Jeff Garzik --- drivers/net/e1000e/ethtool.c | 1 + drivers/net/e1000e/lib.c | 12 +++++++++--- drivers/net/e1000e/netdev.c | 1 + 3 files changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c index 2e8218fb057..b7a7e2ae5e1 100644 --- a/drivers/net/e1000e/ethtool.c +++ b/drivers/net/e1000e/ethtool.c @@ -301,6 +301,7 @@ static int e1000_set_pauseparam(struct net_device *netdev, hw->mac.original_fc = hw->mac.fc; if (adapter->fc_autoneg == AUTONEG_ENABLE) { + hw->mac.fc = e1000_fc_default; if (netif_running(adapter->netdev)) { e1000e_down(adapter); e1000e_up(adapter); diff --git a/drivers/net/e1000e/lib.c b/drivers/net/e1000e/lib.c index 3bbfe605e11..0bdeca30c75 100644 --- a/drivers/net/e1000e/lib.c +++ b/drivers/net/e1000e/lib.c @@ -639,9 +639,15 @@ s32 e1000e_setup_link(struct e1000_hw *hw) if (e1000_check_reset_block(hw)) return 0; - ret_val = e1000_set_default_fc_generic(hw); - if (ret_val) - return ret_val; + /* + * If flow control is set to default, set flow control based on + * the EEPROM flow control settings. + */ + if (mac->fc == e1000_fc_default) { + ret_val = e1000_set_default_fc_generic(hw); + if (ret_val) + return ret_val; + } /* We want to save off the original Flow Control configuration just * in case we get disconnected and then reconnected into a different diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 600538bc932..033e124d1c1 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -4195,6 +4195,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev, /* Initialize link parameters. User can change them with ethtool */ adapter->hw.mac.autoneg = 1; + adapter->fc_autoneg = 1; adapter->hw.mac.original_fc = e1000_fc_default; adapter->hw.mac.fc = e1000_fc_default; adapter->hw.phy.autoneg_advertised = 0x2f; -- cgit v1.2.3-70-g09d2 From 43b7c451a03fe5f615710e26e8e2a3dd70eaa5b1 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 5 Oct 2007 12:39:21 -0700 Subject: s2io: sparse warnings fix (rev2) Fix warnings from sparse checker about shadowed definition and improperly formatted ethtool_strings. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/s2io.c | 97 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 50 insertions(+), 47 deletions(-) (limited to 'drivers') diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 203cc1e87de..22e4054d4fc 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -38,7 +38,7 @@ * Tx descriptors that can be associated with each corresponding FIFO. * intr_type: This defines the type of interrupt. The values can be 0(INTA), * 2(MSI_X). Default value is '2(MSI_X)' - * lro: Specifies whether to enable Large Receive Offload (LRO) or not. + * lro_enable: Specifies whether to enable Large Receive Offload (LRO) or not. * Possible values '1' for enable '0' for disable. Default is '0' * lro_max_pkts: This parameter defines maximum number of packets can be * aggregated as a single large packet @@ -276,46 +276,46 @@ static char ethtool_driver_stats_keys[][ETH_GSTRING_LEN] = { {"ring_5_full_cnt"}, {"ring_6_full_cnt"}, {"ring_7_full_cnt"}, - ("alarm_transceiver_temp_high"), - ("alarm_transceiver_temp_low"), - ("alarm_laser_bias_current_high"), - ("alarm_laser_bias_current_low"), - ("alarm_laser_output_power_high"), - ("alarm_laser_output_power_low"), - ("warn_transceiver_temp_high"), - ("warn_transceiver_temp_low"), - ("warn_laser_bias_current_high"), - ("warn_laser_bias_current_low"), - ("warn_laser_output_power_high"), - ("warn_laser_output_power_low"), - ("lro_aggregated_pkts"), - ("lro_flush_both_count"), - ("lro_out_of_sequence_pkts"), - ("lro_flush_due_to_max_pkts"), - ("lro_avg_aggr_pkts"), - ("mem_alloc_fail_cnt"), - ("pci_map_fail_cnt"), - ("watchdog_timer_cnt"), - ("mem_allocated"), - ("mem_freed"), - ("link_up_cnt"), - ("link_down_cnt"), - ("link_up_time"), - ("link_down_time"), - ("tx_tcode_buf_abort_cnt"), - ("tx_tcode_desc_abort_cnt"), - ("tx_tcode_parity_err_cnt"), - ("tx_tcode_link_loss_cnt"), - ("tx_tcode_list_proc_err_cnt"), - ("rx_tcode_parity_err_cnt"), - ("rx_tcode_abort_cnt"), - ("rx_tcode_parity_abort_cnt"), - ("rx_tcode_rda_fail_cnt"), - ("rx_tcode_unkn_prot_cnt"), - ("rx_tcode_fcs_err_cnt"), - ("rx_tcode_buf_size_err_cnt"), - ("rx_tcode_rxd_corrupt_cnt"), - ("rx_tcode_unkn_err_cnt"), + {"alarm_transceiver_temp_high"}, + {"alarm_transceiver_temp_low"}, + {"alarm_laser_bias_current_high"}, + {"alarm_laser_bias_current_low"}, + {"alarm_laser_output_power_high"}, + {"alarm_laser_output_power_low"}, + {"warn_transceiver_temp_high"}, + {"warn_transceiver_temp_low"}, + {"warn_laser_bias_current_high"}, + {"warn_laser_bias_current_low"}, + {"warn_laser_output_power_high"}, + {"warn_laser_output_power_low"}, + {"lro_aggregated_pkts"}, + {"lro_flush_both_count"}, + {"lro_out_of_sequence_pkts"}, + {"lro_flush_due_to_max_pkts"}, + {"lro_avg_aggr_pkts"}, + {"mem_alloc_fail_cnt"}, + {"pci_map_fail_cnt"}, + {"watchdog_timer_cnt"}, + {"mem_allocated"}, + {"mem_freed"}, + {"link_up_cnt"}, + {"link_down_cnt"}, + {"link_up_time"}, + {"link_down_time"}, + {"tx_tcode_buf_abort_cnt"}, + {"tx_tcode_desc_abort_cnt"}, + {"tx_tcode_parity_err_cnt"}, + {"tx_tcode_link_loss_cnt"}, + {"tx_tcode_list_proc_err_cnt"}, + {"rx_tcode_parity_err_cnt"}, + {"rx_tcode_abort_cnt"}, + {"rx_tcode_parity_abort_cnt"}, + {"rx_tcode_rda_fail_cnt"}, + {"rx_tcode_unkn_prot_cnt"}, + {"rx_tcode_fcs_err_cnt"}, + {"rx_tcode_buf_size_err_cnt"}, + {"rx_tcode_rxd_corrupt_cnt"}, + {"rx_tcode_unkn_err_cnt"}, {"tda_err_cnt"}, {"pfc_err_cnt"}, {"pcc_err_cnt"}, @@ -468,7 +468,9 @@ S2IO_PARM_INT(rxsync_frequency, 3); /* Interrupt type. Values can be 0(INTA), 2(MSI_X) */ S2IO_PARM_INT(intr_type, 2); /* Large receive offload feature */ -S2IO_PARM_INT(lro, 0); +static unsigned int lro_enable; +module_param_named(lro, lro_enable, uint, 0); + /* Max pkts to be aggregated by LRO at one time. If not specified, * aggregation happens until we hit max IP pkt size(64K) */ @@ -1759,7 +1761,7 @@ static void do_s2io_write_bits(u64 value, int flag, void __iomem *addr) writeq(temp64, addr); } -void en_dis_err_alarms(struct s2io_nic *nic, u16 mask, int flag) +static void en_dis_err_alarms(struct s2io_nic *nic, u16 mask, int flag) { struct XENA_dev_config __iomem *bar0 = nic->bar0; register u64 gen_int_mask = 0; @@ -4228,7 +4230,7 @@ static void s2io_txpic_intr_handle(struct s2io_nic *sp) * 1 - if alarm bit set * 0 - if alarm bit is not set */ -int do_s2io_chk_alarm_bit(u64 value, void __iomem * addr, +static int do_s2io_chk_alarm_bit(u64 value, void __iomem * addr, unsigned long long *cnt) { u64 val64; @@ -7135,7 +7137,8 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp) int ret = 0; ret = s2io_club_tcp_session(skb->data, &tcp, - &tcp_len, &lro, rxdp, sp); + &tcp_len, &lro, + rxdp, sp); switch (ret) { case 3: /* Begin anew */ lro->parent = skb; @@ -7451,7 +7454,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) else sp->device_type = XFRAME_I_DEVICE; - sp->lro = lro; + sp->lro = lro_enable; /* Initialize some PCI/PCI-X fields of the NIC. */ s2io_init_pci(sp); @@ -7798,7 +7801,7 @@ static void __devexit s2io_rem_nic(struct pci_dev *pdev) * the module loadable parameters and initializes PCI configuration space. */ -int __init s2io_starter(void) +static int __init s2io_starter(void) { return pci_register_driver(&s2io_driver); } -- cgit v1.2.3-70-g09d2 From ddfce6bb43c6bf1c9956e7a65ce1b2e19a156bd2 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 5 Oct 2007 17:19:47 -0700 Subject: network drivers: sparse warning fixes Fix some of the easy warnings in network device drivers. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/acenic.c | 37 +++++++++++++++++++------------------ drivers/net/atl1/atl1_main.c | 5 +++-- drivers/net/dl2k.c | 8 ++++---- drivers/net/e100.c | 2 +- drivers/net/hamachi.c | 3 +-- drivers/net/natsemi.c | 6 +++--- drivers/net/tehuti.c | 4 +--- 7 files changed, 32 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c index 2c2ed6dc98b..6c192650d34 100644 --- a/drivers/net/acenic.c +++ b/drivers/net/acenic.c @@ -406,7 +406,7 @@ MODULE_DEVICE_TABLE(pci, acenic_pci_tbl); #define DEF_STAT (2 * TICKS_PER_SEC) -static int link[ACE_MAX_MOD_PARMS]; +static int link_state[ACE_MAX_MOD_PARMS]; static int trace[ACE_MAX_MOD_PARMS]; static int tx_coal_tick[ACE_MAX_MOD_PARMS]; static int rx_coal_tick[ACE_MAX_MOD_PARMS]; @@ -419,7 +419,7 @@ MODULE_AUTHOR("Jes Sorensen "); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("AceNIC/3C985/GA620 Gigabit Ethernet driver"); -module_param_array(link, int, NULL, 0); +module_param_array_named(link, link_state, int, NULL, 0); module_param_array(trace, int, NULL, 0); module_param_array(tx_coal_tick, int, NULL, 0); module_param_array(max_tx_desc, int, NULL, 0); @@ -987,27 +987,27 @@ static int __devinit ace_init(struct net_device *dev) mac1 = 0; for(i = 0; i < 4; i++) { - int tmp; + int t; mac1 = mac1 << 8; - tmp = read_eeprom_byte(dev, 0x8c+i); - if (tmp < 0) { + t = read_eeprom_byte(dev, 0x8c+i); + if (t < 0) { ecode = -EIO; goto init_error; } else - mac1 |= (tmp & 0xff); + mac1 |= (t & 0xff); } mac2 = 0; for(i = 4; i < 8; i++) { - int tmp; + int t; mac2 = mac2 << 8; - tmp = read_eeprom_byte(dev, 0x8c+i); - if (tmp < 0) { + t = read_eeprom_byte(dev, 0x8c+i); + if (t < 0) { ecode = -EIO; goto init_error; } else - mac2 |= (tmp & 0xff); + mac2 |= (t & 0xff); } writel(mac1, ®s->MacAddrHi); @@ -1305,10 +1305,10 @@ static int __devinit ace_init(struct net_device *dev) writel(TX_RING_BASE, ®s->WinBase); if (ACE_IS_TIGON_I(ap)) { - ap->tx_ring = (struct tx_desc *) regs->Window; + ap->tx_ring = (__force struct tx_desc *) regs->Window; for (i = 0; i < (TIGON_I_TX_RING_ENTRIES * sizeof(struct tx_desc)) / sizeof(u32); i++) - writel(0, (void __iomem *)ap->tx_ring + i * 4); + writel(0, (__force void __iomem *)ap->tx_ring + i * 4); set_aceaddr(&info->tx_ctrl.rngptr, TX_RING_BASE); } else { @@ -1394,8 +1394,8 @@ static int __devinit ace_init(struct net_device *dev) /* * Override link default parameters */ - if ((board_idx >= 0) && link[board_idx]) { - int option = link[board_idx]; + if ((board_idx >= 0) && link_state[board_idx]) { + int option = link_state[board_idx]; tmp = LNK_ENABLE; @@ -2383,8 +2383,9 @@ static int ace_close(struct net_device *dev) if (mapping) { if (ACE_IS_TIGON_I(ap)) { - struct tx_desc __iomem *tx - = (struct tx_desc __iomem *) &ap->tx_ring[i]; + /* NB: TIGON_1 is special, tx_ring is in io space */ + struct tx_desc __iomem *tx; + tx = (__force struct tx_desc __iomem *) &ap->tx_ring[i]; writel(0, &tx->addr.addrhi); writel(0, &tx->addr.addrlo); writel(0, &tx->flagsize); @@ -2444,7 +2445,7 @@ ace_load_tx_bd(struct ace_private *ap, struct tx_desc *desc, u64 addr, #endif if (ACE_IS_TIGON_I(ap)) { - struct tx_desc __iomem *io = (struct tx_desc __iomem *) desc; + struct tx_desc __iomem *io = (__force struct tx_desc __iomem *) desc; writel(addr >> 32, &io->addr.addrhi); writel(addr & 0xffffffff, &io->addr.addrlo); writel(flagsize, &io->flagsize); @@ -2936,7 +2937,7 @@ static void __devinit ace_clear(struct ace_regs __iomem *regs, u32 dest, int siz * This operation requires the NIC to be halted and is performed with * interrupts disabled and with the spinlock hold. */ -int __devinit ace_load_firmware(struct net_device *dev) +static int __devinit ace_load_firmware(struct net_device *dev) { struct ace_private *ap = netdev_priv(dev); struct ace_regs __iomem *regs = ap->regs; diff --git a/drivers/net/atl1/atl1_main.c b/drivers/net/atl1/atl1_main.c index 4c728f1169c..35b0a7dd4ef 100644 --- a/drivers/net/atl1/atl1_main.c +++ b/drivers/net/atl1/atl1_main.c @@ -1367,7 +1367,6 @@ rrd_ok: if (count) { u32 tpd_next_to_use; u32 rfd_next_to_use; - u32 rrd_next_to_clean; spin_lock(&adapter->mb_lock); @@ -1512,7 +1511,7 @@ static void atl1_tx_map(struct atl1_adapter *adapter, struct sk_buff *skb, unsigned int f; u16 tpd_next_to_use; u16 proto_hdr_len; - u16 i, m, len12; + u16 len12; first_buf_len -= skb->data_len; nr_frags = skb_shinfo(skb)->nr_frags; @@ -1536,6 +1535,8 @@ static void atl1_tx_map(struct atl1_adapter *adapter, struct sk_buff *skb, tpd_next_to_use = 0; if (first_buf_len > proto_hdr_len) { + int i, m; + len12 = first_buf_len - proto_hdr_len; m = (len12 + ATL1_MAX_TX_BUF_LEN - 1) / ATL1_MAX_TX_BUF_LEN; diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c index e91b7096838..5066beb2e7b 100644 --- a/drivers/net/dl2k.c +++ b/drivers/net/dl2k.c @@ -290,7 +290,7 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent) return err; } -int +static int find_miiphy (struct net_device *dev) { int i, phy_found = 0; @@ -314,7 +314,7 @@ find_miiphy (struct net_device *dev) return 0; } -int +static int parse_eeprom (struct net_device *dev) { int i, j; @@ -1096,7 +1096,7 @@ clear_stats (struct net_device *dev) } -int +static int change_mtu (struct net_device *dev, int new_mtu) { struct netdev_private *np = netdev_priv(dev); @@ -1331,7 +1331,7 @@ rio_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) #define EEP_BUSY 0x8000 /* Read the EEPROM word */ /* We use I/O instruction to read/write eeprom to avoid fail on some machines */ -int +static int read_eeprom (long ioaddr, int eep_addr) { int i = 1000; diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 7bd96040268..64f35e20fd4 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -1990,7 +1990,7 @@ static int e100_poll(struct napi_struct *napi, int budget) { struct nic *nic = container_of(napi, struct nic, napi); struct net_device *netdev = nic->netdev; - int work_done = 0; + unsigned int work_done = 0; int tx_cleaned; e100_rx_clean(nic, &work_done, budget); diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c index 015ed3a4057..ed407c85708 100644 --- a/drivers/net/hamachi.c +++ b/drivers/net/hamachi.c @@ -1017,7 +1017,7 @@ static inline int hamachi_tx(struct net_device *dev) break; /* Free the original skb. */ skb = hmp->tx_skbuff[entry]; - if (skb != 0) { + if (skb) { pci_unmap_single(hmp->pci_dev, hmp->tx_ring[entry].addr, skb->len, PCI_DMA_TODEVICE); @@ -1069,7 +1069,6 @@ static void hamachi_tx_timeout(struct net_device *dev) " resetting...\n", dev->name, (int)readw(ioaddr + TxStatus)); { - int i; printk(KERN_DEBUG " Rx ring %p: ", hmp->rx_ring); for (i = 0; i < RX_RING_SIZE; i++) printk(" %8.8x", (unsigned int)hmp->rx_ring[i].status_n_length); diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index ea38da6d31f..322d1697400 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -1615,7 +1615,7 @@ static void do_cable_magic(struct net_device *dev) * (these values all come from National) */ if (!(data & 0x80) || ((data >= 0xd8) && (data <= 0xff))) { - struct netdev_private *np = netdev_priv(dev); + np = netdev_priv(dev); /* the bug has been triggered - fix the coefficient */ writew(TSTDAT_FIXED, ioaddr + TSTDAT); @@ -2502,8 +2502,8 @@ static void __set_rx_mode(struct net_device *dev) memset(mc_filter, 0, sizeof(mc_filter)); for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) { - int i = (ether_crc(ETH_ALEN, mclist->dmi_addr) >> 23) & 0x1ff; - mc_filter[i/8] |= (1 << (i & 0x07)); + int b = (ether_crc(ETH_ALEN, mclist->dmi_addr) >> 23) & 0x1ff; + mc_filter[b/8] |= (1 << (b & 0x07)); } rx_mode = RxFilterEnable | AcceptBroadcast | AcceptMulticast | AcceptMyPhys; diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c index 24834317735..8d04654f0c5 100644 --- a/drivers/net/tehuti.c +++ b/drivers/net/tehuti.c @@ -750,7 +750,6 @@ bdx_vlan_rx_register(struct net_device *ndev, struct vlan_group *grp) */ static int bdx_change_mtu(struct net_device *ndev, int new_mtu) { - BDX_ASSERT(ndev == 0); ENTER; if (new_mtu == ndev->mtu) @@ -1002,7 +1001,7 @@ static inline void bdx_rxdb_free_elem(struct rxdb *db, int n) static int bdx_rx_init(struct bdx_priv *priv) { ENTER; - BDX_ASSERT(priv == 0); + if (bdx_fifo_init(priv, &priv->rxd_fifo0.m, priv->rxd_size, regRXD_CFG0_0, regRXD_CFG1_0, regRXD_RPTR_0, regRXD_WPTR_0)) @@ -1747,7 +1746,6 @@ static void bdx_tx_cleanup(struct bdx_priv *priv) tx_level -= db->rptr->len; /* '-' koz len is negative */ /* now should come skb pointer - free it */ - BDX_ASSERT(db->rptr->addr.skb == 0); dev_kfree_skb_irq(db->rptr->addr.skb); bdx_tx_db_inc_rptr(db); } -- cgit v1.2.3-70-g09d2 From 3bf76b81608479a10077bd6b55972d40db782067 Mon Sep 17 00:00:00 2001 From: Jan-Bernd Themann Date: Mon, 8 Oct 2007 16:01:33 +0200 Subject: ehea: use kernel event queue eHEA recovery and DLPAR functions are called seldomly. The eHEA workqueues are replaced by the kernel event queue. Signed-off-by: Jan-Bernd Themann Signed-off-by: Jeff Garzik --- drivers/net/ehea/ehea.h | 3 +-- drivers/net/ehea/ehea_main.c | 28 ++++++++-------------------- drivers/net/ehea/ehea_qmr.c | 3 +-- 3 files changed, 10 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h index 30220894b01..ac21526b6de 100644 --- a/drivers/net/ehea/ehea.h +++ b/drivers/net/ehea/ehea.h @@ -40,7 +40,7 @@ #include #define DRV_NAME "ehea" -#define DRV_VERSION "EHEA_0077" +#define DRV_VERSION "EHEA_0078" /* eHEA capability flags */ #define DLPAR_PORT_ADD_REM 1 @@ -391,7 +391,6 @@ struct ehea_adapter { struct ibmebus_dev *ebus_dev; struct ehea_port *port[EHEA_MAX_PORTS]; struct ehea_eq *neq; /* notification event queue */ - struct workqueue_struct *ehea_wq; struct tasklet_struct neq_tasklet; struct ehea_mr mr; u32 pd; /* protection domain */ diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 5bc0a1530eb..2ba57e6ace4 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -94,7 +94,6 @@ MODULE_PARM_DESC(use_lro, " Large Receive Offload, 1: enable, 0: disable, " static int port_name_cnt = 0; static LIST_HEAD(adapter_list); u64 ehea_driver_flags = 0; -struct workqueue_struct *ehea_driver_wq; struct work_struct ehea_rereg_mr_task; struct semaphore dlpar_mem_lock; @@ -421,7 +420,7 @@ static int ehea_treat_poll_error(struct ehea_port_res *pr, int rq, if (cqe->status & EHEA_CQE_STAT_FAT_ERR_MASK) { ehea_error("Critical receive error. Resetting port."); - queue_work(pr->port->adapter->ehea_wq, &pr->port->reset_task); + schedule_work(&pr->port->reset_task); return 1; } @@ -596,8 +595,7 @@ static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota) ehea_error("Send Completion Error: Resetting port"); if (netif_msg_tx_err(pr->port)) ehea_dump(cqe, sizeof(*cqe), "Send CQE"); - queue_work(pr->port->adapter->ehea_wq, - &pr->port->reset_task); + schedule_work(&pr->port->reset_task); break; } @@ -716,7 +714,7 @@ static irqreturn_t ehea_qp_aff_irq_handler(int irq, void *param) eqe = ehea_poll_eq(port->qp_eq); } - queue_work(port->adapter->ehea_wq, &port->reset_task); + schedule_work(&port->reset_task); return IRQ_HANDLED; } @@ -2395,7 +2393,7 @@ static int ehea_stop(struct net_device *dev) if (netif_msg_ifdown(port)) ehea_info("disabling port %s", dev->name); - flush_workqueue(port->adapter->ehea_wq); + flush_scheduled_work(); down(&port->port_lock); netif_stop_queue(dev); ret = ehea_down(dev); @@ -2710,7 +2708,7 @@ static void ehea_tx_watchdog(struct net_device *dev) if (netif_carrier_ok(dev) && !test_bit(__EHEA_STOP_XFER, &ehea_driver_flags)) - queue_work(port->adapter->ehea_wq, &port->reset_task); + schedule_work(&port->reset_task); } int ehea_sense_adapter_attr(struct ehea_adapter *adapter) @@ -3243,15 +3241,9 @@ static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev, goto out_kill_eq; } - adapter->ehea_wq = create_workqueue("ehea_wq"); - if (!adapter->ehea_wq) { - ret = -EIO; - goto out_free_irq; - } - ret = ehea_create_device_sysfs(dev); if (ret) - goto out_kill_wq; + goto out_free_irq; ret = ehea_setup_ports(adapter); if (ret) { @@ -3265,9 +3257,6 @@ static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev, out_rem_dev_sysfs: ehea_remove_device_sysfs(dev); -out_kill_wq: - destroy_workqueue(adapter->ehea_wq); - out_free_irq: ibmebus_free_irq(NULL, adapter->neq->attr.ist1, adapter); @@ -3293,7 +3282,7 @@ static int __devexit ehea_remove(struct ibmebus_dev *dev) ehea_remove_device_sysfs(dev); - destroy_workqueue(adapter->ehea_wq); + flush_scheduled_work(); ibmebus_free_irq(NULL, adapter->neq->attr.ist1, adapter); tasklet_kill(&adapter->neq_tasklet); @@ -3351,7 +3340,6 @@ int __init ehea_module_init(void) printk(KERN_INFO "IBM eHEA ethernet device driver (Release %s)\n", DRV_VERSION); - ehea_driver_wq = create_workqueue("ehea_driver_wq"); INIT_WORK(&ehea_rereg_mr_task, ehea_rereg_mrs); sema_init(&dlpar_mem_lock, 1); @@ -3385,7 +3373,7 @@ out: static void __exit ehea_module_exit(void) { - destroy_workqueue(ehea_driver_wq); + flush_scheduled_work(); driver_remove_file(&ehea_driver.driver, &driver_attr_capabilities); ibmebus_unregister_driver(&ehea_driver); ehea_destroy_busmap(); diff --git a/drivers/net/ehea/ehea_qmr.c b/drivers/net/ehea/ehea_qmr.c index 329a25248d7..83b76432b41 100644 --- a/drivers/net/ehea/ehea_qmr.c +++ b/drivers/net/ehea/ehea_qmr.c @@ -34,7 +34,6 @@ struct ehea_busmap ehea_bmap = { 0, 0, NULL }; extern u64 ehea_driver_flags; -extern struct workqueue_struct *ehea_driver_wq; extern struct work_struct ehea_rereg_mr_task; @@ -618,7 +617,7 @@ u64 ehea_map_vaddr(void *caddr) if (unlikely(mapped_addr == -1)) if (!test_and_set_bit(__EHEA_STOP_XFER, &ehea_driver_flags)) - queue_work(ehea_driver_wq, &ehea_rereg_mr_task); + schedule_work(&ehea_rereg_mr_task); return mapped_addr; } -- cgit v1.2.3-70-g09d2 From 33a85aa1c915c2f114bdac9b6d1ec00cc0fbc485 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 8 Oct 2007 16:19:10 -0700 Subject: chelsio: sparse warning fixes (old cxgb2) Fix problems detected by sparse: 1. whole chunk of MAC code was for defined and never used 2. hook for running ext intr in workqueue wasn't being used Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/chelsio/Makefile | 2 +- drivers/net/chelsio/common.h | 1 + drivers/net/chelsio/mac.c | 368 ------------------------------------------- drivers/net/chelsio/subr.c | 2 +- 4 files changed, 3 insertions(+), 370 deletions(-) delete mode 100644 drivers/net/chelsio/mac.c (limited to 'drivers') diff --git a/drivers/net/chelsio/Makefile b/drivers/net/chelsio/Makefile index 743ad8b41b5..57a4b262fd3 100644 --- a/drivers/net/chelsio/Makefile +++ b/drivers/net/chelsio/Makefile @@ -4,6 +4,6 @@ obj-$(CONFIG_CHELSIO_T1) += cxgb.o -cxgb-$(CONFIG_CHELSIO_T1_1G) += mac.o mv88e1xxx.o vsc7326.o +cxgb-$(CONFIG_CHELSIO_T1_1G) += mv88e1xxx.o vsc7326.o cxgb-objs := cxgb2.o espi.o tp.o pm3393.o sge.o subr.o \ mv88x201x.o my3126.o $(cxgb-y) diff --git a/drivers/net/chelsio/common.h b/drivers/net/chelsio/common.h index b5de4452cf2..846ca5383d3 100644 --- a/drivers/net/chelsio/common.h +++ b/drivers/net/chelsio/common.h @@ -372,6 +372,7 @@ extern void t1_interrupts_enable(adapter_t *adapter); extern void t1_interrupts_disable(adapter_t *adapter); extern void t1_interrupts_clear(adapter_t *adapter); extern int t1_elmer0_ext_intr_handler(adapter_t *adapter); +extern void t1_elmer0_ext_intr(adapter_t *adapter); extern int t1_slow_intr_handler(adapter_t *adapter); extern int t1_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc); diff --git a/drivers/net/chelsio/mac.c b/drivers/net/chelsio/mac.c deleted file mode 100644 index 1d972825eac..00000000000 --- a/drivers/net/chelsio/mac.c +++ /dev/null @@ -1,368 +0,0 @@ -/* $Date: 2005/10/22 00:42:59 $ $RCSfile: mac.c,v $ $Revision: 1.32 $ */ -#include "gmac.h" -#include "regs.h" -#include "fpga_defs.h" - -#define MAC_CSR_INTERFACE_GMII 0x0 -#define MAC_CSR_INTERFACE_TBI 0x1 -#define MAC_CSR_INTERFACE_MII 0x2 -#define MAC_CSR_INTERFACE_RMII 0x3 - -/* Chelsio's MAC statistics. */ -struct mac_statistics { - - /* Transmit */ - u32 TxFramesTransmittedOK; - u32 TxReserved1; - u32 TxReserved2; - u32 TxOctetsTransmittedOK; - u32 TxFramesWithDeferredXmissions; - u32 TxLateCollisions; - u32 TxFramesAbortedDueToXSCollisions; - u32 TxFramesLostDueToIntMACXmitError; - u32 TxReserved3; - u32 TxMulticastFrameXmittedOK; - u32 TxBroadcastFramesXmittedOK; - u32 TxFramesWithExcessiveDeferral; - u32 TxPAUSEMACCtrlFramesTransmitted; - - /* Receive */ - u32 RxFramesReceivedOK; - u32 RxFrameCheckSequenceErrors; - u32 RxAlignmentErrors; - u32 RxOctetsReceivedOK; - u32 RxFramesLostDueToIntMACRcvError; - u32 RxMulticastFramesReceivedOK; - u32 RxBroadcastFramesReceivedOK; - u32 RxInRangeLengthErrors; - u32 RxTxOutOfRangeLengthField; - u32 RxFrameTooLongErrors; - u32 RxPAUSEMACCtrlFramesReceived; -}; - -static int static_aPorts[] = { - FPGA_GMAC_INTERRUPT_PORT0, - FPGA_GMAC_INTERRUPT_PORT1, - FPGA_GMAC_INTERRUPT_PORT2, - FPGA_GMAC_INTERRUPT_PORT3 -}; - -struct _cmac_instance { - u32 index; -}; - -static int mac_intr_enable(struct cmac *mac) -{ - u32 mac_intr; - - if (t1_is_asic(mac->adapter)) { - /* ASIC */ - - /* We don't use the on chip MAC for ASIC products. */ - } else { - /* FPGA */ - - /* Set parent gmac interrupt. */ - mac_intr = readl(mac->adapter->regs + A_PL_ENABLE); - mac_intr |= FPGA_PCIX_INTERRUPT_GMAC; - writel(mac_intr, mac->adapter->regs + A_PL_ENABLE); - - mac_intr = readl(mac->adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_ENABLE); - mac_intr |= static_aPorts[mac->instance->index]; - writel(mac_intr, - mac->adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_ENABLE); - } - - return 0; -} - -static int mac_intr_disable(struct cmac *mac) -{ - u32 mac_intr; - - if (t1_is_asic(mac->adapter)) { - /* ASIC */ - - /* We don't use the on chip MAC for ASIC products. */ - } else { - /* FPGA */ - - /* Set parent gmac interrupt. */ - mac_intr = readl(mac->adapter->regs + A_PL_ENABLE); - mac_intr &= ~FPGA_PCIX_INTERRUPT_GMAC; - writel(mac_intr, mac->adapter->regs + A_PL_ENABLE); - - mac_intr = readl(mac->adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_ENABLE); - mac_intr &= ~(static_aPorts[mac->instance->index]); - writel(mac_intr, - mac->adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_ENABLE); - } - - return 0; -} - -static int mac_intr_clear(struct cmac *mac) -{ - u32 mac_intr; - - if (t1_is_asic(mac->adapter)) { - /* ASIC */ - - /* We don't use the on chip MAC for ASIC products. */ - } else { - /* FPGA */ - - /* Set parent gmac interrupt. */ - writel(FPGA_PCIX_INTERRUPT_GMAC, - mac->adapter->regs + A_PL_CAUSE); - mac_intr = readl(mac->adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_CAUSE); - mac_intr |= (static_aPorts[mac->instance->index]); - writel(mac_intr, - mac->adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_CAUSE); - } - - return 0; -} - -static int mac_get_address(struct cmac *mac, u8 addr[6]) -{ - u32 data32_lo, data32_hi; - - data32_lo = readl(mac->adapter->regs - + MAC_REG_IDLO(mac->instance->index)); - data32_hi = readl(mac->adapter->regs - + MAC_REG_IDHI(mac->instance->index)); - - addr[0] = (u8) ((data32_hi >> 8) & 0xFF); - addr[1] = (u8) ((data32_hi) & 0xFF); - addr[2] = (u8) ((data32_lo >> 24) & 0xFF); - addr[3] = (u8) ((data32_lo >> 16) & 0xFF); - addr[4] = (u8) ((data32_lo >> 8) & 0xFF); - addr[5] = (u8) ((data32_lo) & 0xFF); - return 0; -} - -static int mac_reset(struct cmac *mac) -{ - u32 data32; - int mac_in_reset, time_out = 100; - int idx = mac->instance->index; - - data32 = readl(mac->adapter->regs + MAC_REG_CSR(idx)); - writel(data32 | F_MAC_RESET, - mac->adapter->regs + MAC_REG_CSR(idx)); - - do { - data32 = readl(mac->adapter->regs + MAC_REG_CSR(idx)); - - mac_in_reset = data32 & F_MAC_RESET; - if (mac_in_reset) - udelay(1); - } while (mac_in_reset && --time_out); - - if (mac_in_reset) { - CH_ERR("%s: MAC %d reset timed out\n", - mac->adapter->name, idx); - return 2; - } - - return 0; -} - -static int mac_set_rx_mode(struct cmac *mac, struct t1_rx_mode *rm) -{ - u32 val; - - val = readl(mac->adapter->regs - + MAC_REG_CSR(mac->instance->index)); - val &= ~(F_MAC_PROMISC | F_MAC_MC_ENABLE); - val |= V_MAC_PROMISC(t1_rx_mode_promisc(rm) != 0); - val |= V_MAC_MC_ENABLE(t1_rx_mode_allmulti(rm) != 0); - writel(val, - mac->adapter->regs + MAC_REG_CSR(mac->instance->index)); - - return 0; -} - -static int mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, - int fc) -{ - u32 data32; - - data32 = readl(mac->adapter->regs - + MAC_REG_CSR(mac->instance->index)); - data32 &= ~(F_MAC_HALF_DUPLEX | V_MAC_SPEED(M_MAC_SPEED) | - V_INTERFACE(M_INTERFACE) | F_MAC_TX_PAUSE_ENABLE | - F_MAC_RX_PAUSE_ENABLE); - - switch (speed) { - case SPEED_10: - case SPEED_100: - data32 |= V_INTERFACE(MAC_CSR_INTERFACE_MII); - data32 |= V_MAC_SPEED(speed == SPEED_10 ? 0 : 1); - break; - case SPEED_1000: - data32 |= V_INTERFACE(MAC_CSR_INTERFACE_GMII); - data32 |= V_MAC_SPEED(2); - break; - } - - if (duplex >= 0) - data32 |= V_MAC_HALF_DUPLEX(duplex == DUPLEX_HALF); - - if (fc >= 0) { - data32 |= V_MAC_RX_PAUSE_ENABLE((fc & PAUSE_RX) != 0); - data32 |= V_MAC_TX_PAUSE_ENABLE((fc & PAUSE_TX) != 0); - } - - writel(data32, - mac->adapter->regs + MAC_REG_CSR(mac->instance->index)); - return 0; -} - -static int mac_enable(struct cmac *mac, int which) -{ - u32 val; - - val = readl(mac->adapter->regs - + MAC_REG_CSR(mac->instance->index)); - if (which & MAC_DIRECTION_RX) - val |= F_MAC_RX_ENABLE; - if (which & MAC_DIRECTION_TX) - val |= F_MAC_TX_ENABLE; - writel(val, - mac->adapter->regs + MAC_REG_CSR(mac->instance->index)); - return 0; -} - -static int mac_disable(struct cmac *mac, int which) -{ - u32 val; - - val = readl(mac->adapter->regs - + MAC_REG_CSR(mac->instance->index)); - if (which & MAC_DIRECTION_RX) - val &= ~F_MAC_RX_ENABLE; - if (which & MAC_DIRECTION_TX) - val &= ~F_MAC_TX_ENABLE; - writel(val, - mac->adapter->regs + MAC_REG_CSR(mac->instance->index)); - return 0; -} - -#if 0 -static int mac_set_ifs(struct cmac *mac, u32 mode) -{ - t1_write_reg_4(mac->adapter, - MAC_REG_IFS(mac->instance->index), - mode); - return 0; -} - -static int mac_enable_isl(struct cmac *mac) -{ - u32 data32 = readl(mac->adapter->regs - + MAC_REG_CSR(mac->instance->index)); - data32 |= F_MAC_RX_ENABLE | F_MAC_TX_ENABLE; - t1_write_reg_4(mac->adapter, - MAC_REG_CSR(mac->instance->index), - data32); - return 0; -} -#endif - -static int mac_set_mtu(struct cmac *mac, int mtu) -{ - if (mtu > 9600) - return -EINVAL; - writel(mtu + ETH_HLEN + VLAN_HLEN, - mac->adapter->regs + MAC_REG_LARGEFRAMELENGTH(mac->instance->index)); - - return 0; -} - -static const struct cmac_statistics *mac_update_statistics(struct cmac *mac, - int flag) -{ - struct mac_statistics st; - u32 *p = (u32 *) & st, i; - - writel(0, - mac->adapter->regs + MAC_REG_RMCNT(mac->instance->index)); - - for (i = 0; i < sizeof(st) / sizeof(u32); i++) - *p++ = readl(mac->adapter->regs - + MAC_REG_RMDATA(mac->instance->index)); - - /* XXX convert stats */ - return &mac->stats; -} - -static void mac_destroy(struct cmac *mac) -{ - kfree(mac); -} - -static struct cmac_ops chelsio_mac_ops = { - .destroy = mac_destroy, - .reset = mac_reset, - .interrupt_enable = mac_intr_enable, - .interrupt_disable = mac_intr_disable, - .interrupt_clear = mac_intr_clear, - .enable = mac_enable, - .disable = mac_disable, - .set_mtu = mac_set_mtu, - .set_rx_mode = mac_set_rx_mode, - .set_speed_duplex_fc = mac_set_speed_duplex_fc, - .macaddress_get = mac_get_address, - .statistics_update = mac_update_statistics, -}; - -static struct cmac *mac_create(adapter_t *adapter, int index) -{ - struct cmac *mac; - u32 data32; - - if (index >= 4) - return NULL; - - mac = kzalloc(sizeof(*mac) + sizeof(cmac_instance), GFP_KERNEL); - if (!mac) - return NULL; - - mac->ops = &chelsio_mac_ops; - mac->instance = (cmac_instance *) (mac + 1); - - mac->instance->index = index; - mac->adapter = adapter; - - data32 = readl(adapter->regs + MAC_REG_CSR(mac->instance->index)); - data32 &= ~(F_MAC_RESET | F_MAC_PROMISC | F_MAC_PROMISC | - F_MAC_LB_ENABLE | F_MAC_RX_ENABLE | F_MAC_TX_ENABLE); - data32 |= F_MAC_JUMBO_ENABLE; - writel(data32, adapter->regs + MAC_REG_CSR(mac->instance->index)); - - /* Initialize the random backoff seed. */ - data32 = 0x55aa + (3 * index); - writel(data32, - adapter->regs + MAC_REG_GMRANDBACKOFFSEED(mac->instance->index)); - - /* Check to see if the mac address needs to be set manually. */ - data32 = readl(adapter->regs + MAC_REG_IDLO(mac->instance->index)); - if (data32 == 0 || data32 == 0xffffffff) { - /* - * Add a default MAC address if we can't read one. - */ - writel(0x43FFFFFF - index, - adapter->regs + MAC_REG_IDLO(mac->instance->index)); - writel(0x0007, - adapter->regs + MAC_REG_IDHI(mac->instance->index)); - } - - (void) mac_set_mtu(mac, 1500); - return mac; -} - -const struct gmac t1_chelsio_mac_ops = { - .create = mac_create -}; diff --git a/drivers/net/chelsio/subr.c b/drivers/net/chelsio/subr.c index 7de9a611e1f..dc50151bed8 100644 --- a/drivers/net/chelsio/subr.c +++ b/drivers/net/chelsio/subr.c @@ -884,7 +884,7 @@ static int asic_slow_intr(adapter_t *adapter) if (cause & F_PL_INTR_PCIX) t1_pci_intr_handler(adapter); if (cause & F_PL_INTR_EXT) - t1_elmer0_ext_intr_handler(adapter); + t1_elmer0_ext_intr(adapter); /* Clear the interrupts just processed. */ writel(cause, adapter->regs + A_PL_CAUSE); -- cgit v1.2.3-70-g09d2 From 9265fabf0d4c3d0a52e169d4b9149d52fd91db69 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 8 Oct 2007 16:22:29 -0700 Subject: cxgb3 sparse warning fixes Fix warnings from sparse related to shadowed variables and routines that should be declared static. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/cxgb3/cxgb3_main.c | 4 +--- drivers/net/cxgb3/cxgb3_offload.c | 44 +++++++++++++++++++-------------------- drivers/net/cxgb3/sge.c | 6 +++--- drivers/net/cxgb3/t3_hw.c | 8 +++---- drivers/net/cxgb3/xgmac.c | 2 +- 5 files changed, 31 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index e22d0653105..61ffc925eae 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -740,7 +740,7 @@ static inline char t3rev2char(struct adapter *adapter) return rev; } -int update_tpsram(struct adapter *adap) +static int update_tpsram(struct adapter *adap) { const struct firmware *tpsram; char buf[64]; @@ -1769,7 +1769,6 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr) } case CHELSIO_SET_QSET_NUM:{ struct ch_reg edata; - struct port_info *pi = netdev_priv(dev); unsigned int i, first_qset = 0, other_qsets = 0; if (!capable(CAP_NET_ADMIN)) @@ -1801,7 +1800,6 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr) } case CHELSIO_GET_QSET_NUM:{ struct ch_reg edata; - struct port_info *pi = netdev_priv(dev); edata.cmd = CHELSIO_GET_QSET_NUM; edata.val = pi->nqsets; diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c index 1c8eec38bde..bd25421bc12 100644 --- a/drivers/net/cxgb3/cxgb3_offload.c +++ b/drivers/net/cxgb3/cxgb3_offload.c @@ -222,32 +222,32 @@ static int cxgb_rdma_ctl(struct adapter *adapter, unsigned int req, void *data) int ret = 0; switch (req) { - case RDMA_GET_PARAMS:{ - struct rdma_info *req = data; + case RDMA_GET_PARAMS: { + struct rdma_info *rdma = data; struct pci_dev *pdev = adapter->pdev; - req->udbell_physbase = pci_resource_start(pdev, 2); - req->udbell_len = pci_resource_len(pdev, 2); - req->tpt_base = + rdma->udbell_physbase = pci_resource_start(pdev, 2); + rdma->udbell_len = pci_resource_len(pdev, 2); + rdma->tpt_base = t3_read_reg(adapter, A_ULPTX_TPT_LLIMIT); - req->tpt_top = t3_read_reg(adapter, A_ULPTX_TPT_ULIMIT); - req->pbl_base = + rdma->tpt_top = t3_read_reg(adapter, A_ULPTX_TPT_ULIMIT); + rdma->pbl_base = t3_read_reg(adapter, A_ULPTX_PBL_LLIMIT); - req->pbl_top = t3_read_reg(adapter, A_ULPTX_PBL_ULIMIT); - req->rqt_base = t3_read_reg(adapter, A_ULPRX_RQ_LLIMIT); - req->rqt_top = t3_read_reg(adapter, A_ULPRX_RQ_ULIMIT); - req->kdb_addr = adapter->regs + A_SG_KDOORBELL; - req->pdev = pdev; + rdma->pbl_top = t3_read_reg(adapter, A_ULPTX_PBL_ULIMIT); + rdma->rqt_base = t3_read_reg(adapter, A_ULPRX_RQ_LLIMIT); + rdma->rqt_top = t3_read_reg(adapter, A_ULPRX_RQ_ULIMIT); + rdma->kdb_addr = adapter->regs + A_SG_KDOORBELL; + rdma->pdev = pdev; break; } case RDMA_CQ_OP:{ unsigned long flags; - struct rdma_cq_op *req = data; + struct rdma_cq_op *rdma = data; /* may be called in any context */ spin_lock_irqsave(&adapter->sge.reg_lock, flags); - ret = t3_sge_cqcntxt_op(adapter, req->id, req->op, - req->credits); + ret = t3_sge_cqcntxt_op(adapter, rdma->id, rdma->op, + rdma->credits); spin_unlock_irqrestore(&adapter->sge.reg_lock, flags); break; } @@ -274,15 +274,15 @@ static int cxgb_rdma_ctl(struct adapter *adapter, unsigned int req, void *data) break; } case RDMA_CQ_SETUP:{ - struct rdma_cq_setup *req = data; + struct rdma_cq_setup *rdma = data; spin_lock_irq(&adapter->sge.reg_lock); ret = - t3_sge_init_cqcntxt(adapter, req->id, - req->base_addr, req->size, + t3_sge_init_cqcntxt(adapter, rdma->id, + rdma->base_addr, rdma->size, ASYNC_NOTIF_RSPQ, - req->ovfl_mode, req->credits, - req->credit_thres); + rdma->ovfl_mode, rdma->credits, + rdma->credit_thres); spin_unlock_irq(&adapter->sge.reg_lock); break; } @@ -292,13 +292,13 @@ static int cxgb_rdma_ctl(struct adapter *adapter, unsigned int req, void *data) spin_unlock_irq(&adapter->sge.reg_lock); break; case RDMA_CTRL_QP_SETUP:{ - struct rdma_ctrlqp_setup *req = data; + struct rdma_ctrlqp_setup *rdma = data; spin_lock_irq(&adapter->sge.reg_lock); ret = t3_sge_init_ecntxt(adapter, FW_RI_SGEEC_START, 0, SGE_CNTXT_RDMA, ASYNC_NOTIF_RSPQ, - req->base_addr, req->size, + rdma->base_addr, rdma->size, FW_RI_TID_START, 1, 0); spin_unlock_irq(&adapter->sge.reg_lock); break; diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c index 77f3ec5ff8a..994b5d6404d 100644 --- a/drivers/net/cxgb3/sge.c +++ b/drivers/net/cxgb3/sge.c @@ -544,7 +544,7 @@ static void *alloc_ring(struct pci_dev *pdev, size_t nelem, size_t elem_size, * as HW contexts, packet buffers, and descriptor rings. Traffic to the * queue set must be quiesced prior to calling this. */ -void t3_free_qset(struct adapter *adapter, struct sge_qset *q) +static void t3_free_qset(struct adapter *adapter, struct sge_qset *q) { int i; struct pci_dev *pdev = adapter->pdev; @@ -2215,7 +2215,7 @@ irqreturn_t t3_sge_intr_msix(int irq, void *cookie) * The MSI-X interrupt handler for an SGE response queue for the NAPI case * (i.e., response queue serviced by NAPI polling). */ -irqreturn_t t3_sge_intr_msix_napi(int irq, void *cookie) +static irqreturn_t t3_sge_intr_msix_napi(int irq, void *cookie) { struct sge_qset *qs = cookie; struct sge_rspq *q = &qs->rspq; @@ -2284,7 +2284,7 @@ static int rspq_check_napi(struct sge_qset *qs) * one SGE response queue per port in this mode and protect all response * queues with queue 0's lock. */ -irqreturn_t t3_intr_msi_napi(int irq, void *cookie) +static irqreturn_t t3_intr_msi_napi(int irq, void *cookie) { int new_packets; struct adapter *adap = cookie; diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c index 05832932144..d4ee00d3221 100644 --- a/drivers/net/cxgb3/t3_hw.c +++ b/drivers/net/cxgb3/t3_hw.c @@ -119,9 +119,9 @@ void t3_set_reg_field(struct adapter *adapter, unsigned int addr, u32 mask, * Reads registers that are accessed indirectly through an address/data * register pair. */ -void t3_read_indirect(struct adapter *adap, unsigned int addr_reg, - unsigned int data_reg, u32 *vals, unsigned int nregs, - unsigned int start_idx) +static void t3_read_indirect(struct adapter *adap, unsigned int addr_reg, + unsigned int data_reg, u32 *vals, + unsigned int nregs, unsigned int start_idx) { while (nregs--) { t3_write_reg(adap, addr_reg, start_idx); @@ -3407,7 +3407,7 @@ void early_hw_init(struct adapter *adapter, const struct adapter_info *ai) * Older PCIe cards lose their config space during reset, PCI-X * ones don't. */ -int t3_reset_adapter(struct adapter *adapter) +static int t3_reset_adapter(struct adapter *adapter) { int i, save_and_restore_pcie = adapter->params.rev < T3_REV_B2 && is_pcie(adapter); diff --git a/drivers/net/cxgb3/xgmac.c b/drivers/net/cxgb3/xgmac.c index bcb5bc4e649..eeb766aeced 100644 --- a/drivers/net/cxgb3/xgmac.c +++ b/drivers/net/cxgb3/xgmac.c @@ -142,7 +142,7 @@ int t3_mac_reset(struct cmac *mac) return 0; } -int t3b2_mac_reset(struct cmac *mac) +static int t3b2_mac_reset(struct cmac *mac) { struct adapter *adap = mac->adapter; unsigned int oft = mac->offset; -- cgit v1.2.3-70-g09d2 From f2cade13371f3ca80c5479c284e6455c681c8a0c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 9 Oct 2007 22:57:39 +0100 Subject: natsemi: Use NATSEMI_TIMER_FREQ consistently The natsemi driver has a define NATSEMI_TIMER_FREQ which looks like it controls the normal frequency of the chip poll timer but in fact only takes effect for the first run of the timer. Adjust the value of the define to match that used by the timer and use the define consistently. Signed-off-by: Mark Brown Signed-off-by: Jeff Garzik --- drivers/net/natsemi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index 322d1697400..527f9dcc7f6 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -108,7 +108,7 @@ static int full_duplex[MAX_UNITS]; #define TX_TIMEOUT (2*HZ) #define NATSEMI_HW_TIMEOUT 400 -#define NATSEMI_TIMER_FREQ 3*HZ +#define NATSEMI_TIMER_FREQ 5*HZ #define NATSEMI_PG0_NREGS 64 #define NATSEMI_RFDR_NREGS 8 #define NATSEMI_PG1_NREGS 4 @@ -1798,7 +1798,7 @@ static void netdev_timer(unsigned long data) struct net_device *dev = (struct net_device *)data; struct netdev_private *np = netdev_priv(dev); void __iomem * ioaddr = ns_ioaddr(dev); - int next_tick = 5*HZ; + int next_tick = NATSEMI_TIMER_FREQ; if (netif_msg_timer(np)) { /* DO NOT read the IntrStatus register, -- cgit v1.2.3-70-g09d2 From 9153f66a5b8e63c61374df4e6a4cbd0056e45178 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 9 Oct 2007 15:46:13 -0700 Subject: IPoIB: Fix unused variable warning The conversion to use netdevice internal stats left an unused variable in ipoib_neigh_free(), since there's no longer any reason to get netdev_priv() in order to increment dropped packets. Delete the unused priv variable. Signed-off-by: Roland Dreier Signed-off-by: Jeff Garzik --- drivers/infiniband/ulp/ipoib/ipoib_main.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 6b1b4b2ec5b..855c9deca8b 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -854,7 +854,6 @@ struct ipoib_neigh *ipoib_neigh_alloc(struct neighbour *neighbour) void ipoib_neigh_free(struct net_device *dev, struct ipoib_neigh *neigh) { - struct ipoib_dev_priv *priv = netdev_priv(dev); struct sk_buff *skb; *to_ipoib_neigh(neigh->neighbour) = NULL; while ((skb = __skb_dequeue(&neigh->queue))) { -- cgit v1.2.3-70-g09d2 From bfe13f54f5028cff034e3b6247e9f433908f4f4f Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 9 Oct 2007 15:47:37 -0700 Subject: ibm_emac: Convert to use napi_struct independent of struct net_device Commit da3dedd9 ("[NET]: Make NAPI polling independent of struct net_device objects.") changed the interface to NAPI polling. Fix up the ibm_emac driver so that it works with this new interface. This is actually a nice cleanup because ibm_emac is one of the drivers that wants to have multiple NAPI structures for a single net_device. Tested with the internal MAC of a PowerPC 440SPe SoC with an AMCC 'Yucca' evaluation board. Signed-off-by: Roland Dreier Signed-off-by: Jeff Garzik --- drivers/net/ibm_emac/ibm_emac_mal.c | 48 +++++++++++++------------------------ drivers/net/ibm_emac/ibm_emac_mal.h | 2 +- include/linux/netdevice.h | 10 ++++++++ 3 files changed, 28 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ibm_emac/ibm_emac_mal.c b/drivers/net/ibm_emac/ibm_emac_mal.c index cabd9846a5e..4e49e8c4f87 100644 --- a/drivers/net/ibm_emac/ibm_emac_mal.c +++ b/drivers/net/ibm_emac/ibm_emac_mal.c @@ -207,10 +207,10 @@ static irqreturn_t mal_serr(int irq, void *dev_instance) static inline void mal_schedule_poll(struct ibm_ocp_mal *mal) { - if (likely(netif_rx_schedule_prep(&mal->poll_dev))) { + if (likely(napi_schedule_prep(&mal->napi))) { MAL_DBG2("%d: schedule_poll" NL, mal->def->index); mal_disable_eob_irq(mal); - __netif_rx_schedule(&mal->poll_dev); + __napi_schedule(&mal->napi); } else MAL_DBG2("%d: already in poll" NL, mal->def->index); } @@ -273,11 +273,11 @@ static irqreturn_t mal_rxde(int irq, void *dev_instance) return IRQ_HANDLED; } -static int mal_poll(struct net_device *ndev, int *budget) +static int mal_poll(struct napi_struct *napi, int budget) { - struct ibm_ocp_mal *mal = ndev->priv; + struct ibm_ocp_mal *mal = container_of(napi, struct ibm_ocp_mal, napi); struct list_head *l; - int rx_work_limit = min(ndev->quota, *budget), received = 0, done; + int received = 0; MAL_DBG2("%d: poll(%d) %d ->" NL, mal->def->index, *budget, rx_work_limit); @@ -295,38 +295,34 @@ static int mal_poll(struct net_device *ndev, int *budget) list_for_each(l, &mal->poll_list) { struct mal_commac *mc = list_entry(l, struct mal_commac, poll_list); - int n = mc->ops->poll_rx(mc->dev, rx_work_limit); + int n = mc->ops->poll_rx(mc->dev, budget); if (n) { received += n; - rx_work_limit -= n; - if (rx_work_limit <= 0) { - done = 0; + budget -= n; + if (budget <= 0) goto more_work; // XXX What if this is the last one ? - } } } /* We need to disable IRQs to protect from RXDE IRQ here */ local_irq_disable(); - __netif_rx_complete(ndev); + __napi_complete(napi); mal_enable_eob_irq(mal); local_irq_enable(); - done = 1; - /* Check for "rotting" packet(s) */ list_for_each(l, &mal->poll_list) { struct mal_commac *mc = list_entry(l, struct mal_commac, poll_list); if (unlikely(mc->ops->peek_rx(mc->dev) || mc->rx_stopped)) { MAL_DBG2("%d: rotting packet" NL, mal->def->index); - if (netif_rx_reschedule(ndev, received)) + if (napi_reschedule(napi)) mal_disable_eob_irq(mal); else MAL_DBG2("%d: already in poll list" NL, mal->def->index); - if (rx_work_limit > 0) + if (budget > 0) goto again; else goto more_work; @@ -335,12 +331,8 @@ static int mal_poll(struct net_device *ndev, int *budget) } more_work: - ndev->quota -= received; - *budget -= received; - - MAL_DBG2("%d: poll() %d <- %d" NL, mal->def->index, *budget, - done ? 0 : 1); - return done ? 0 : 1; + MAL_DBG2("%d: poll() %d <- %d" NL, mal->def->index, budget, received); + return received; } static void mal_reset(struct ibm_ocp_mal *mal) @@ -425,11 +417,8 @@ static int __init mal_probe(struct ocp_device *ocpdev) mal->def = ocpdev->def; INIT_LIST_HEAD(&mal->poll_list); - set_bit(__LINK_STATE_START, &mal->poll_dev.state); - mal->poll_dev.weight = CONFIG_IBM_EMAC_POLL_WEIGHT; - mal->poll_dev.poll = mal_poll; - mal->poll_dev.priv = mal; - atomic_set(&mal->poll_dev.refcnt, 1); + mal->napi.weight = CONFIG_IBM_EMAC_POLL_WEIGHT; + mal->napi.poll = mal_poll; INIT_LIST_HEAD(&mal->list); @@ -520,11 +509,8 @@ static void __exit mal_remove(struct ocp_device *ocpdev) MAL_DBG("%d: remove" NL, mal->def->index); - /* Syncronize with scheduled polling, - stolen from net/core/dev.c:dev_close() - */ - clear_bit(__LINK_STATE_START, &mal->poll_dev.state); - netif_poll_disable(&mal->poll_dev); + /* Synchronize with scheduled polling */ + napi_disable(&mal->napi); if (!list_empty(&mal->list)) { /* This is *very* bad */ diff --git a/drivers/net/ibm_emac/ibm_emac_mal.h b/drivers/net/ibm_emac/ibm_emac_mal.h index 64bc338acc6..8f54d621994 100644 --- a/drivers/net/ibm_emac/ibm_emac_mal.h +++ b/drivers/net/ibm_emac/ibm_emac_mal.h @@ -195,7 +195,7 @@ struct ibm_ocp_mal { dcr_host_t dcrhost; struct list_head poll_list; - struct net_device poll_dev; + struct napi_struct napi; struct list_head list; u32 tx_chan_mask; diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 91cd3f3db50..4848c7afa4e 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -349,6 +349,16 @@ static inline void napi_schedule(struct napi_struct *n) __napi_schedule(n); } +/* Try to reschedule poll. Called by dev->poll() after napi_complete(). */ +static inline int napi_reschedule(struct napi_struct *napi) +{ + if (napi_schedule_prep(napi)) { + __napi_schedule(napi); + return 1; + } + return 0; +} + /** * napi_complete - NAPI processing complete * @n: napi context -- cgit v1.2.3-70-g09d2 From 61ba5b3c14b4956493d1180e0a860e941108393e Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 9 Oct 2007 15:47:59 -0700 Subject: ibm_new_emac: Nuke SET_MODULE_OWNER() use Signed-off-by: Roland Dreier Signed-off-by: Jeff Garzik --- drivers/net/ibm_newemac/core.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c index ce127b9cafa..8ea50096187 100644 --- a/drivers/net/ibm_newemac/core.c +++ b/drivers/net/ibm_newemac/core.c @@ -2549,7 +2549,6 @@ static int __devinit emac_probe(struct of_device *ofdev, dev->ndev = ndev; dev->ofdev = ofdev; dev->blist = blist; - SET_MODULE_OWNER(ndev); SET_NETDEV_DEV(ndev, &ofdev->dev); /* Initialize some embedded data structures */ -- cgit v1.2.3-70-g09d2 From 59e90b2d22500f2e9cc635793562154abc8f4621 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 9 Oct 2007 15:48:56 -0700 Subject: ibm_emac: Convert to use napi_struct independent of struct net_device Commit da3dedd9 ("[NET]: Make NAPI polling independent of struct net_device objects.") changed the interface to NAPI polling. Fix up the ibm_newemac driver so that it works with this new interface. This is actually a nice cleanup because ibm_newemac is one of the drivers that wants to have multiple NAPI structures for a single net_device. Compile-tested only as I don't have a system that uses the ibm_newemac driver. This conversion the conversion for the ibm_emac driver that was tested on real PowerPC 440SPe hardware. Signed-off-by: Roland Dreier Signed-off-by: Jeff Garzik --- drivers/net/ibm_newemac/mal.c | 55 +++++++++++++++---------------------------- drivers/net/ibm_newemac/mal.h | 2 +- 2 files changed, 20 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ibm_newemac/mal.c b/drivers/net/ibm_newemac/mal.c index c4335b7d308..58854117b1a 100644 --- a/drivers/net/ibm_newemac/mal.c +++ b/drivers/net/ibm_newemac/mal.c @@ -235,10 +235,10 @@ static irqreturn_t mal_serr(int irq, void *dev_instance) static inline void mal_schedule_poll(struct mal_instance *mal) { - if (likely(netif_rx_schedule_prep(&mal->poll_dev))) { + if (likely(napi_schedule_prep(&mal->napi))) { MAL_DBG2(mal, "schedule_poll" NL); mal_disable_eob_irq(mal); - __netif_rx_schedule(&mal->poll_dev); + __napi_schedule(&mal->napi); } else MAL_DBG2(mal, "already in poll" NL); } @@ -318,8 +318,7 @@ void mal_poll_disable(struct mal_instance *mal, struct mal_commac *commac) msleep(1); /* Synchronize with the MAL NAPI poller. */ - while (test_bit(__LINK_STATE_RX_SCHED, &mal->poll_dev.state)) - msleep(1); + napi_disable(&mal->napi); } void mal_poll_enable(struct mal_instance *mal, struct mal_commac *commac) @@ -330,11 +329,11 @@ void mal_poll_enable(struct mal_instance *mal, struct mal_commac *commac) // XXX might want to kick a poll now... } -static int mal_poll(struct net_device *ndev, int *budget) +static int mal_poll(struct napi_struct *napi, int budget) { - struct mal_instance *mal = netdev_priv(ndev); + struct mal_instance *mal = container_of(napi, struct mal_instance, napi); struct list_head *l; - int rx_work_limit = min(ndev->quota, *budget), received = 0, done; + int received = 0; unsigned long flags; MAL_DBG2(mal, "poll(%d) %d ->" NL, *budget, @@ -358,26 +357,21 @@ static int mal_poll(struct net_device *ndev, int *budget) int n; if (unlikely(test_bit(MAL_COMMAC_POLL_DISABLED, &mc->flags))) continue; - n = mc->ops->poll_rx(mc->dev, rx_work_limit); + n = mc->ops->poll_rx(mc->dev, budget); if (n) { received += n; - rx_work_limit -= n; - if (rx_work_limit <= 0) { - done = 0; - // XXX What if this is the last one ? - goto more_work; - } + budget -= n; + if (budget <= 0) + goto more_work; // XXX What if this is the last one ? } } /* We need to disable IRQs to protect from RXDE IRQ here */ spin_lock_irqsave(&mal->lock, flags); - __netif_rx_complete(ndev); + __napi_complete(napi); mal_enable_eob_irq(mal); spin_unlock_irqrestore(&mal->lock, flags); - done = 1; - /* Check for "rotting" packet(s) */ list_for_each(l, &mal->poll_list) { struct mal_commac *mc = @@ -387,12 +381,12 @@ static int mal_poll(struct net_device *ndev, int *budget) if (unlikely(mc->ops->peek_rx(mc->dev) || test_bit(MAL_COMMAC_RX_STOPPED, &mc->flags))) { MAL_DBG2(mal, "rotting packet" NL); - if (netif_rx_reschedule(ndev, received)) + if (napi_reschedule(napi)) mal_disable_eob_irq(mal); else MAL_DBG2(mal, "already in poll list" NL); - if (rx_work_limit > 0) + if (budget > 0) goto again; else goto more_work; @@ -401,13 +395,8 @@ static int mal_poll(struct net_device *ndev, int *budget) } more_work: - ndev->quota -= received; - *budget -= received; - - MAL_DBG2(mal, "poll() %d <- %d" NL, *budget, - done ? 0 : 1); - - return done ? 0 : 1; + MAL_DBG2(mal, "poll() %d <- %d" NL, budget, received); + return received; } static void mal_reset(struct mal_instance *mal) @@ -538,11 +527,8 @@ static int __devinit mal_probe(struct of_device *ofdev, } INIT_LIST_HEAD(&mal->poll_list); - set_bit(__LINK_STATE_START, &mal->poll_dev.state); - mal->poll_dev.weight = CONFIG_IBM_NEW_EMAC_POLL_WEIGHT; - mal->poll_dev.poll = mal_poll; - mal->poll_dev.priv = mal; - atomic_set(&mal->poll_dev.refcnt, 1); + mal->napi.weight = CONFIG_IBM_NEW_EMAC_POLL_WEIGHT; + mal->napi.poll = mal_poll; INIT_LIST_HEAD(&mal->list); spin_lock_init(&mal->lock); @@ -653,11 +639,8 @@ static int __devexit mal_remove(struct of_device *ofdev) MAL_DBG(mal, "remove" NL); - /* Syncronize with scheduled polling, - stolen from net/core/dev.c:dev_close() - */ - clear_bit(__LINK_STATE_START, &mal->poll_dev.state); - netif_poll_disable(&mal->poll_dev); + /* Synchronize with scheduled polling */ + napi_disable(&mal->napi); if (!list_empty(&mal->list)) { /* This is *very* bad */ diff --git a/drivers/net/ibm_newemac/mal.h b/drivers/net/ibm_newemac/mal.h index 57b69dc32e9..cb1a16d589f 100644 --- a/drivers/net/ibm_newemac/mal.h +++ b/drivers/net/ibm_newemac/mal.h @@ -197,7 +197,7 @@ struct mal_instance { int serr_irq; /* MAL System Error IRQ */ struct list_head poll_list; - struct net_device poll_dev; + struct napi_struct napi; struct list_head list; u32 tx_chan_mask; -- cgit v1.2.3-70-g09d2 From 44db25ca127281036817f861593389d7cfe950f5 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 17 Jul 2007 20:33:16 +0800 Subject: [CRYPTO] drivers/Kconfig: Remove "default m"s Hardware drivers shouldn't default to m. Signed-off-by: Adrian Bunk Signed-off-by: Herbert Xu --- drivers/crypto/Kconfig | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index c0fc4aeb859..5fd6688a444 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -14,7 +14,6 @@ config CRYPTO_DEV_PADLOCK tristate "Support for VIA PadLock ACE" depends on X86_32 select CRYPTO_ALGAPI - default m help Some VIA processors come with an integrated crypto engine (so called VIA PadLock ACE, Advanced Cryptography Engine) @@ -28,7 +27,6 @@ config CRYPTO_DEV_PADLOCK_AES tristate "PadLock driver for AES algorithm" depends on CRYPTO_DEV_PADLOCK select CRYPTO_BLKCIPHER - default m help Use VIA PadLock for AES algorithm. @@ -42,7 +40,6 @@ config CRYPTO_DEV_PADLOCK_SHA depends on CRYPTO_DEV_PADLOCK select CRYPTO_SHA1 select CRYPTO_SHA256 - default m help Use VIA PadLock for SHA1/SHA256 algorithms. @@ -58,7 +55,6 @@ config CRYPTO_DEV_GEODE depends on X86_32 && PCI select CRYPTO_ALGAPI select CRYPTO_BLKCIPHER - default m help Say 'Y' here to use the AMD Geode LX processor on-board AES engine for the CryptoAPI AES algorithm. @@ -70,7 +66,6 @@ config ZCRYPT tristate "Support for PCI-attached cryptographic adapters" depends on S390 select ZCRYPT_MONOLITHIC if ZCRYPT="y" - default "m" help Select this option if you want to use a PCI-attached cryptographic adapter like: -- cgit v1.2.3-70-g09d2 From f8246af005d56b73f4f04304fc5b6fd9878af4ef Mon Sep 17 00:00:00 2001 From: Sebastian Siewior Date: Fri, 5 Oct 2007 16:52:01 +0800 Subject: [CRYPTO] aes: Rename aes to aes-generic Loading the crypto algorithm by the alias instead of by module directly has the advantage that all possible implementations of this algorithm are loaded automatically and the crypto API can choose the best one depending on its priority. Additionally it ensures that the generic implementation as well as the HW driver (if available) is loaded in case the HW driver needs the generic version as fallback in corner cases. Signed-off-by: Sebastian Siewior Signed-off-by: Herbert Xu --- arch/s390/crypto/aes_s390.c | 2 +- crypto/Makefile | 2 +- crypto/aes.c | 456 ------------------------------------------- crypto/aes_generic.c | 456 +++++++++++++++++++++++++++++++++++++++++++ drivers/crypto/geode-aes.c | 1 + drivers/crypto/padlock-aes.c | 4 +- 6 files changed, 461 insertions(+), 460 deletions(-) delete mode 100644 crypto/aes.c create mode 100644 crypto/aes_generic.c (limited to 'drivers') diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c index 3660ca6a330..512669691ad 100644 --- a/arch/s390/crypto/aes_s390.c +++ b/arch/s390/crypto/aes_s390.c @@ -7,7 +7,7 @@ * Copyright IBM Corp. 2005,2007 * Author(s): Jan Glauber (jang@de.ibm.com) * - * Derived from "crypto/aes.c" + * Derived from "crypto/aes_generic.c" * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free diff --git a/crypto/Makefile b/crypto/Makefile index a624cbc188f..b6ef5e4f1ab 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -39,7 +39,7 @@ obj-$(CONFIG_CRYPTO_BLOWFISH) += blowfish.o obj-$(CONFIG_CRYPTO_TWOFISH) += twofish.o obj-$(CONFIG_CRYPTO_TWOFISH_COMMON) += twofish_common.o obj-$(CONFIG_CRYPTO_SERPENT) += serpent.o -obj-$(CONFIG_CRYPTO_AES) += aes.o +obj-$(CONFIG_CRYPTO_AES) += aes_generic.o obj-$(CONFIG_CRYPTO_CAMELLIA) += camellia.o obj-$(CONFIG_CRYPTO_CAST5) += cast5.o obj-$(CONFIG_CRYPTO_CAST6) += cast6.o diff --git a/crypto/aes.c b/crypto/aes.c deleted file mode 100644 index e2440773878..00000000000 --- a/crypto/aes.c +++ /dev/null @@ -1,456 +0,0 @@ -/* - * Cryptographic API. - * - * AES Cipher Algorithm. - * - * Based on Brian Gladman's code. - * - * Linux developers: - * Alexander Kjeldaas - * Herbert Valerio Riedel - * Kyle McMartin - * Adam J. Richter (conversion to 2.5 API). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * --------------------------------------------------------------------------- - * Copyright (c) 2002, Dr Brian Gladman , Worcester, UK. - * All rights reserved. - * - * LICENSE TERMS - * - * The free distribution and use of this software in both source and binary - * form is allowed (with or without changes) provided that: - * - * 1. distributions of this source code include the above copyright - * notice, this list of conditions and the following disclaimer; - * - * 2. distributions in binary form include the above copyright - * notice, this list of conditions and the following disclaimer - * in the documentation and/or other associated materials; - * - * 3. the copyright holder's name is not used to endorse products - * built using this software without specific written permission. - * - * ALTERNATIVELY, provided that this notice is retained in full, this product - * may be distributed under the terms of the GNU General Public License (GPL), - * in which case the provisions of the GPL apply INSTEAD OF those given above. - * - * DISCLAIMER - * - * This software is provided 'as is' with no explicit or implied warranties - * in respect of its properties, including, but not limited to, correctness - * and/or fitness for purpose. - * --------------------------------------------------------------------------- - */ - -/* Some changes from the Gladman version: - s/RIJNDAEL(e_key)/E_KEY/g - s/RIJNDAEL(d_key)/D_KEY/g -*/ - -#include -#include -#include -#include -#include -#include - -#define AES_MIN_KEY_SIZE 16 -#define AES_MAX_KEY_SIZE 32 - -#define AES_BLOCK_SIZE 16 - -/* - * #define byte(x, nr) ((unsigned char)((x) >> (nr*8))) - */ -static inline u8 -byte(const u32 x, const unsigned n) -{ - return x >> (n << 3); -} - -struct aes_ctx { - int key_length; - u32 buf[120]; -}; - -#define E_KEY (&ctx->buf[0]) -#define D_KEY (&ctx->buf[60]) - -static u8 pow_tab[256] __initdata; -static u8 log_tab[256] __initdata; -static u8 sbx_tab[256] __initdata; -static u8 isb_tab[256] __initdata; -static u32 rco_tab[10]; -static u32 ft_tab[4][256]; -static u32 it_tab[4][256]; - -static u32 fl_tab[4][256]; -static u32 il_tab[4][256]; - -static inline u8 __init -f_mult (u8 a, u8 b) -{ - u8 aa = log_tab[a], cc = aa + log_tab[b]; - - return pow_tab[cc + (cc < aa ? 1 : 0)]; -} - -#define ff_mult(a,b) (a && b ? f_mult(a, b) : 0) - -#define f_rn(bo, bi, n, k) \ - bo[n] = ft_tab[0][byte(bi[n],0)] ^ \ - ft_tab[1][byte(bi[(n + 1) & 3],1)] ^ \ - ft_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ - ft_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n) - -#define i_rn(bo, bi, n, k) \ - bo[n] = it_tab[0][byte(bi[n],0)] ^ \ - it_tab[1][byte(bi[(n + 3) & 3],1)] ^ \ - it_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ - it_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n) - -#define ls_box(x) \ - ( fl_tab[0][byte(x, 0)] ^ \ - fl_tab[1][byte(x, 1)] ^ \ - fl_tab[2][byte(x, 2)] ^ \ - fl_tab[3][byte(x, 3)] ) - -#define f_rl(bo, bi, n, k) \ - bo[n] = fl_tab[0][byte(bi[n],0)] ^ \ - fl_tab[1][byte(bi[(n + 1) & 3],1)] ^ \ - fl_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ - fl_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n) - -#define i_rl(bo, bi, n, k) \ - bo[n] = il_tab[0][byte(bi[n],0)] ^ \ - il_tab[1][byte(bi[(n + 3) & 3],1)] ^ \ - il_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ - il_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n) - -static void __init -gen_tabs (void) -{ - u32 i, t; - u8 p, q; - - /* log and power tables for GF(2**8) finite field with - 0x011b as modular polynomial - the simplest primitive - root is 0x03, used here to generate the tables */ - - for (i = 0, p = 1; i < 256; ++i) { - pow_tab[i] = (u8) p; - log_tab[p] = (u8) i; - - p ^= (p << 1) ^ (p & 0x80 ? 0x01b : 0); - } - - log_tab[1] = 0; - - for (i = 0, p = 1; i < 10; ++i) { - rco_tab[i] = p; - - p = (p << 1) ^ (p & 0x80 ? 0x01b : 0); - } - - for (i = 0; i < 256; ++i) { - p = (i ? pow_tab[255 - log_tab[i]] : 0); - q = ((p >> 7) | (p << 1)) ^ ((p >> 6) | (p << 2)); - p ^= 0x63 ^ q ^ ((q >> 6) | (q << 2)); - sbx_tab[i] = p; - isb_tab[p] = (u8) i; - } - - for (i = 0; i < 256; ++i) { - p = sbx_tab[i]; - - t = p; - fl_tab[0][i] = t; - fl_tab[1][i] = rol32(t, 8); - fl_tab[2][i] = rol32(t, 16); - fl_tab[3][i] = rol32(t, 24); - - t = ((u32) ff_mult (2, p)) | - ((u32) p << 8) | - ((u32) p << 16) | ((u32) ff_mult (3, p) << 24); - - ft_tab[0][i] = t; - ft_tab[1][i] = rol32(t, 8); - ft_tab[2][i] = rol32(t, 16); - ft_tab[3][i] = rol32(t, 24); - - p = isb_tab[i]; - - t = p; - il_tab[0][i] = t; - il_tab[1][i] = rol32(t, 8); - il_tab[2][i] = rol32(t, 16); - il_tab[3][i] = rol32(t, 24); - - t = ((u32) ff_mult (14, p)) | - ((u32) ff_mult (9, p) << 8) | - ((u32) ff_mult (13, p) << 16) | - ((u32) ff_mult (11, p) << 24); - - it_tab[0][i] = t; - it_tab[1][i] = rol32(t, 8); - it_tab[2][i] = rol32(t, 16); - it_tab[3][i] = rol32(t, 24); - } -} - -#define star_x(x) (((x) & 0x7f7f7f7f) << 1) ^ ((((x) & 0x80808080) >> 7) * 0x1b) - -#define imix_col(y,x) \ - u = star_x(x); \ - v = star_x(u); \ - w = star_x(v); \ - t = w ^ (x); \ - (y) = u ^ v ^ w; \ - (y) ^= ror32(u ^ t, 8) ^ \ - ror32(v ^ t, 16) ^ \ - ror32(t,24) - -/* initialise the key schedule from the user supplied key */ - -#define loop4(i) \ -{ t = ror32(t, 8); t = ls_box(t) ^ rco_tab[i]; \ - t ^= E_KEY[4 * i]; E_KEY[4 * i + 4] = t; \ - t ^= E_KEY[4 * i + 1]; E_KEY[4 * i + 5] = t; \ - t ^= E_KEY[4 * i + 2]; E_KEY[4 * i + 6] = t; \ - t ^= E_KEY[4 * i + 3]; E_KEY[4 * i + 7] = t; \ -} - -#define loop6(i) \ -{ t = ror32(t, 8); t = ls_box(t) ^ rco_tab[i]; \ - t ^= E_KEY[6 * i]; E_KEY[6 * i + 6] = t; \ - t ^= E_KEY[6 * i + 1]; E_KEY[6 * i + 7] = t; \ - t ^= E_KEY[6 * i + 2]; E_KEY[6 * i + 8] = t; \ - t ^= E_KEY[6 * i + 3]; E_KEY[6 * i + 9] = t; \ - t ^= E_KEY[6 * i + 4]; E_KEY[6 * i + 10] = t; \ - t ^= E_KEY[6 * i + 5]; E_KEY[6 * i + 11] = t; \ -} - -#define loop8(i) \ -{ t = ror32(t, 8); ; t = ls_box(t) ^ rco_tab[i]; \ - t ^= E_KEY[8 * i]; E_KEY[8 * i + 8] = t; \ - t ^= E_KEY[8 * i + 1]; E_KEY[8 * i + 9] = t; \ - t ^= E_KEY[8 * i + 2]; E_KEY[8 * i + 10] = t; \ - t ^= E_KEY[8 * i + 3]; E_KEY[8 * i + 11] = t; \ - t = E_KEY[8 * i + 4] ^ ls_box(t); \ - E_KEY[8 * i + 12] = t; \ - t ^= E_KEY[8 * i + 5]; E_KEY[8 * i + 13] = t; \ - t ^= E_KEY[8 * i + 6]; E_KEY[8 * i + 14] = t; \ - t ^= E_KEY[8 * i + 7]; E_KEY[8 * i + 15] = t; \ -} - -static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, - unsigned int key_len) -{ - struct aes_ctx *ctx = crypto_tfm_ctx(tfm); - const __le32 *key = (const __le32 *)in_key; - u32 *flags = &tfm->crt_flags; - u32 i, t, u, v, w; - - if (key_len % 8) { - *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; - return -EINVAL; - } - - ctx->key_length = key_len; - - E_KEY[0] = le32_to_cpu(key[0]); - E_KEY[1] = le32_to_cpu(key[1]); - E_KEY[2] = le32_to_cpu(key[2]); - E_KEY[3] = le32_to_cpu(key[3]); - - switch (key_len) { - case 16: - t = E_KEY[3]; - for (i = 0; i < 10; ++i) - loop4 (i); - break; - - case 24: - E_KEY[4] = le32_to_cpu(key[4]); - t = E_KEY[5] = le32_to_cpu(key[5]); - for (i = 0; i < 8; ++i) - loop6 (i); - break; - - case 32: - E_KEY[4] = le32_to_cpu(key[4]); - E_KEY[5] = le32_to_cpu(key[5]); - E_KEY[6] = le32_to_cpu(key[6]); - t = E_KEY[7] = le32_to_cpu(key[7]); - for (i = 0; i < 7; ++i) - loop8 (i); - break; - } - - D_KEY[0] = E_KEY[0]; - D_KEY[1] = E_KEY[1]; - D_KEY[2] = E_KEY[2]; - D_KEY[3] = E_KEY[3]; - - for (i = 4; i < key_len + 24; ++i) { - imix_col (D_KEY[i], E_KEY[i]); - } - - return 0; -} - -/* encrypt a block of text */ - -#define f_nround(bo, bi, k) \ - f_rn(bo, bi, 0, k); \ - f_rn(bo, bi, 1, k); \ - f_rn(bo, bi, 2, k); \ - f_rn(bo, bi, 3, k); \ - k += 4 - -#define f_lround(bo, bi, k) \ - f_rl(bo, bi, 0, k); \ - f_rl(bo, bi, 1, k); \ - f_rl(bo, bi, 2, k); \ - f_rl(bo, bi, 3, k) - -static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) -{ - const struct aes_ctx *ctx = crypto_tfm_ctx(tfm); - const __le32 *src = (const __le32 *)in; - __le32 *dst = (__le32 *)out; - u32 b0[4], b1[4]; - const u32 *kp = E_KEY + 4; - - b0[0] = le32_to_cpu(src[0]) ^ E_KEY[0]; - b0[1] = le32_to_cpu(src[1]) ^ E_KEY[1]; - b0[2] = le32_to_cpu(src[2]) ^ E_KEY[2]; - b0[3] = le32_to_cpu(src[3]) ^ E_KEY[3]; - - if (ctx->key_length > 24) { - f_nround (b1, b0, kp); - f_nround (b0, b1, kp); - } - - if (ctx->key_length > 16) { - f_nround (b1, b0, kp); - f_nround (b0, b1, kp); - } - - f_nround (b1, b0, kp); - f_nround (b0, b1, kp); - f_nround (b1, b0, kp); - f_nround (b0, b1, kp); - f_nround (b1, b0, kp); - f_nround (b0, b1, kp); - f_nround (b1, b0, kp); - f_nround (b0, b1, kp); - f_nround (b1, b0, kp); - f_lround (b0, b1, kp); - - dst[0] = cpu_to_le32(b0[0]); - dst[1] = cpu_to_le32(b0[1]); - dst[2] = cpu_to_le32(b0[2]); - dst[3] = cpu_to_le32(b0[3]); -} - -/* decrypt a block of text */ - -#define i_nround(bo, bi, k) \ - i_rn(bo, bi, 0, k); \ - i_rn(bo, bi, 1, k); \ - i_rn(bo, bi, 2, k); \ - i_rn(bo, bi, 3, k); \ - k -= 4 - -#define i_lround(bo, bi, k) \ - i_rl(bo, bi, 0, k); \ - i_rl(bo, bi, 1, k); \ - i_rl(bo, bi, 2, k); \ - i_rl(bo, bi, 3, k) - -static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) -{ - const struct aes_ctx *ctx = crypto_tfm_ctx(tfm); - const __le32 *src = (const __le32 *)in; - __le32 *dst = (__le32 *)out; - u32 b0[4], b1[4]; - const int key_len = ctx->key_length; - const u32 *kp = D_KEY + key_len + 20; - - b0[0] = le32_to_cpu(src[0]) ^ E_KEY[key_len + 24]; - b0[1] = le32_to_cpu(src[1]) ^ E_KEY[key_len + 25]; - b0[2] = le32_to_cpu(src[2]) ^ E_KEY[key_len + 26]; - b0[3] = le32_to_cpu(src[3]) ^ E_KEY[key_len + 27]; - - if (key_len > 24) { - i_nround (b1, b0, kp); - i_nround (b0, b1, kp); - } - - if (key_len > 16) { - i_nround (b1, b0, kp); - i_nround (b0, b1, kp); - } - - i_nround (b1, b0, kp); - i_nround (b0, b1, kp); - i_nround (b1, b0, kp); - i_nround (b0, b1, kp); - i_nround (b1, b0, kp); - i_nround (b0, b1, kp); - i_nround (b1, b0, kp); - i_nround (b0, b1, kp); - i_nround (b1, b0, kp); - i_lround (b0, b1, kp); - - dst[0] = cpu_to_le32(b0[0]); - dst[1] = cpu_to_le32(b0[1]); - dst[2] = cpu_to_le32(b0[2]); - dst[3] = cpu_to_le32(b0[3]); -} - - -static struct crypto_alg aes_alg = { - .cra_name = "aes", - .cra_driver_name = "aes-generic", - .cra_priority = 100, - .cra_flags = CRYPTO_ALG_TYPE_CIPHER, - .cra_blocksize = AES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct aes_ctx), - .cra_alignmask = 3, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(aes_alg.cra_list), - .cra_u = { - .cipher = { - .cia_min_keysize = AES_MIN_KEY_SIZE, - .cia_max_keysize = AES_MAX_KEY_SIZE, - .cia_setkey = aes_set_key, - .cia_encrypt = aes_encrypt, - .cia_decrypt = aes_decrypt - } - } -}; - -static int __init aes_init(void) -{ - gen_tabs(); - return crypto_register_alg(&aes_alg); -} - -static void __exit aes_fini(void) -{ - crypto_unregister_alg(&aes_alg); -} - -module_init(aes_init); -module_exit(aes_fini); - -MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm"); -MODULE_LICENSE("Dual BSD/GPL"); - diff --git a/crypto/aes_generic.c b/crypto/aes_generic.c new file mode 100644 index 00000000000..9401dca85e8 --- /dev/null +++ b/crypto/aes_generic.c @@ -0,0 +1,456 @@ +/* + * Cryptographic API. + * + * AES Cipher Algorithm. + * + * Based on Brian Gladman's code. + * + * Linux developers: + * Alexander Kjeldaas + * Herbert Valerio Riedel + * Kyle McMartin + * Adam J. Richter (conversion to 2.5 API). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * --------------------------------------------------------------------------- + * Copyright (c) 2002, Dr Brian Gladman , Worcester, UK. + * All rights reserved. + * + * LICENSE TERMS + * + * The free distribution and use of this software in both source and binary + * form is allowed (with or without changes) provided that: + * + * 1. distributions of this source code include the above copyright + * notice, this list of conditions and the following disclaimer; + * + * 2. distributions in binary form include the above copyright + * notice, this list of conditions and the following disclaimer + * in the documentation and/or other associated materials; + * + * 3. the copyright holder's name is not used to endorse products + * built using this software without specific written permission. + * + * ALTERNATIVELY, provided that this notice is retained in full, this product + * may be distributed under the terms of the GNU General Public License (GPL), + * in which case the provisions of the GPL apply INSTEAD OF those given above. + * + * DISCLAIMER + * + * This software is provided 'as is' with no explicit or implied warranties + * in respect of its properties, including, but not limited to, correctness + * and/or fitness for purpose. + * --------------------------------------------------------------------------- + */ + +/* Some changes from the Gladman version: + s/RIJNDAEL(e_key)/E_KEY/g + s/RIJNDAEL(d_key)/D_KEY/g +*/ + +#include +#include +#include +#include +#include +#include + +#define AES_MIN_KEY_SIZE 16 +#define AES_MAX_KEY_SIZE 32 + +#define AES_BLOCK_SIZE 16 + +/* + * #define byte(x, nr) ((unsigned char)((x) >> (nr*8))) + */ +static inline u8 +byte(const u32 x, const unsigned n) +{ + return x >> (n << 3); +} + +struct aes_ctx { + int key_length; + u32 buf[120]; +}; + +#define E_KEY (&ctx->buf[0]) +#define D_KEY (&ctx->buf[60]) + +static u8 pow_tab[256] __initdata; +static u8 log_tab[256] __initdata; +static u8 sbx_tab[256] __initdata; +static u8 isb_tab[256] __initdata; +static u32 rco_tab[10]; +static u32 ft_tab[4][256]; +static u32 it_tab[4][256]; + +static u32 fl_tab[4][256]; +static u32 il_tab[4][256]; + +static inline u8 __init +f_mult (u8 a, u8 b) +{ + u8 aa = log_tab[a], cc = aa + log_tab[b]; + + return pow_tab[cc + (cc < aa ? 1 : 0)]; +} + +#define ff_mult(a,b) (a && b ? f_mult(a, b) : 0) + +#define f_rn(bo, bi, n, k) \ + bo[n] = ft_tab[0][byte(bi[n],0)] ^ \ + ft_tab[1][byte(bi[(n + 1) & 3],1)] ^ \ + ft_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ + ft_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n) + +#define i_rn(bo, bi, n, k) \ + bo[n] = it_tab[0][byte(bi[n],0)] ^ \ + it_tab[1][byte(bi[(n + 3) & 3],1)] ^ \ + it_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ + it_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n) + +#define ls_box(x) \ + ( fl_tab[0][byte(x, 0)] ^ \ + fl_tab[1][byte(x, 1)] ^ \ + fl_tab[2][byte(x, 2)] ^ \ + fl_tab[3][byte(x, 3)] ) + +#define f_rl(bo, bi, n, k) \ + bo[n] = fl_tab[0][byte(bi[n],0)] ^ \ + fl_tab[1][byte(bi[(n + 1) & 3],1)] ^ \ + fl_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ + fl_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n) + +#define i_rl(bo, bi, n, k) \ + bo[n] = il_tab[0][byte(bi[n],0)] ^ \ + il_tab[1][byte(bi[(n + 3) & 3],1)] ^ \ + il_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ + il_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n) + +static void __init +gen_tabs (void) +{ + u32 i, t; + u8 p, q; + + /* log and power tables for GF(2**8) finite field with + 0x011b as modular polynomial - the simplest primitive + root is 0x03, used here to generate the tables */ + + for (i = 0, p = 1; i < 256; ++i) { + pow_tab[i] = (u8) p; + log_tab[p] = (u8) i; + + p ^= (p << 1) ^ (p & 0x80 ? 0x01b : 0); + } + + log_tab[1] = 0; + + for (i = 0, p = 1; i < 10; ++i) { + rco_tab[i] = p; + + p = (p << 1) ^ (p & 0x80 ? 0x01b : 0); + } + + for (i = 0; i < 256; ++i) { + p = (i ? pow_tab[255 - log_tab[i]] : 0); + q = ((p >> 7) | (p << 1)) ^ ((p >> 6) | (p << 2)); + p ^= 0x63 ^ q ^ ((q >> 6) | (q << 2)); + sbx_tab[i] = p; + isb_tab[p] = (u8) i; + } + + for (i = 0; i < 256; ++i) { + p = sbx_tab[i]; + + t = p; + fl_tab[0][i] = t; + fl_tab[1][i] = rol32(t, 8); + fl_tab[2][i] = rol32(t, 16); + fl_tab[3][i] = rol32(t, 24); + + t = ((u32) ff_mult (2, p)) | + ((u32) p << 8) | + ((u32) p << 16) | ((u32) ff_mult (3, p) << 24); + + ft_tab[0][i] = t; + ft_tab[1][i] = rol32(t, 8); + ft_tab[2][i] = rol32(t, 16); + ft_tab[3][i] = rol32(t, 24); + + p = isb_tab[i]; + + t = p; + il_tab[0][i] = t; + il_tab[1][i] = rol32(t, 8); + il_tab[2][i] = rol32(t, 16); + il_tab[3][i] = rol32(t, 24); + + t = ((u32) ff_mult (14, p)) | + ((u32) ff_mult (9, p) << 8) | + ((u32) ff_mult (13, p) << 16) | + ((u32) ff_mult (11, p) << 24); + + it_tab[0][i] = t; + it_tab[1][i] = rol32(t, 8); + it_tab[2][i] = rol32(t, 16); + it_tab[3][i] = rol32(t, 24); + } +} + +#define star_x(x) (((x) & 0x7f7f7f7f) << 1) ^ ((((x) & 0x80808080) >> 7) * 0x1b) + +#define imix_col(y,x) \ + u = star_x(x); \ + v = star_x(u); \ + w = star_x(v); \ + t = w ^ (x); \ + (y) = u ^ v ^ w; \ + (y) ^= ror32(u ^ t, 8) ^ \ + ror32(v ^ t, 16) ^ \ + ror32(t,24) + +/* initialise the key schedule from the user supplied key */ + +#define loop4(i) \ +{ t = ror32(t, 8); t = ls_box(t) ^ rco_tab[i]; \ + t ^= E_KEY[4 * i]; E_KEY[4 * i + 4] = t; \ + t ^= E_KEY[4 * i + 1]; E_KEY[4 * i + 5] = t; \ + t ^= E_KEY[4 * i + 2]; E_KEY[4 * i + 6] = t; \ + t ^= E_KEY[4 * i + 3]; E_KEY[4 * i + 7] = t; \ +} + +#define loop6(i) \ +{ t = ror32(t, 8); t = ls_box(t) ^ rco_tab[i]; \ + t ^= E_KEY[6 * i]; E_KEY[6 * i + 6] = t; \ + t ^= E_KEY[6 * i + 1]; E_KEY[6 * i + 7] = t; \ + t ^= E_KEY[6 * i + 2]; E_KEY[6 * i + 8] = t; \ + t ^= E_KEY[6 * i + 3]; E_KEY[6 * i + 9] = t; \ + t ^= E_KEY[6 * i + 4]; E_KEY[6 * i + 10] = t; \ + t ^= E_KEY[6 * i + 5]; E_KEY[6 * i + 11] = t; \ +} + +#define loop8(i) \ +{ t = ror32(t, 8); ; t = ls_box(t) ^ rco_tab[i]; \ + t ^= E_KEY[8 * i]; E_KEY[8 * i + 8] = t; \ + t ^= E_KEY[8 * i + 1]; E_KEY[8 * i + 9] = t; \ + t ^= E_KEY[8 * i + 2]; E_KEY[8 * i + 10] = t; \ + t ^= E_KEY[8 * i + 3]; E_KEY[8 * i + 11] = t; \ + t = E_KEY[8 * i + 4] ^ ls_box(t); \ + E_KEY[8 * i + 12] = t; \ + t ^= E_KEY[8 * i + 5]; E_KEY[8 * i + 13] = t; \ + t ^= E_KEY[8 * i + 6]; E_KEY[8 * i + 14] = t; \ + t ^= E_KEY[8 * i + 7]; E_KEY[8 * i + 15] = t; \ +} + +static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, + unsigned int key_len) +{ + struct aes_ctx *ctx = crypto_tfm_ctx(tfm); + const __le32 *key = (const __le32 *)in_key; + u32 *flags = &tfm->crt_flags; + u32 i, t, u, v, w; + + if (key_len % 8) { + *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; + return -EINVAL; + } + + ctx->key_length = key_len; + + E_KEY[0] = le32_to_cpu(key[0]); + E_KEY[1] = le32_to_cpu(key[1]); + E_KEY[2] = le32_to_cpu(key[2]); + E_KEY[3] = le32_to_cpu(key[3]); + + switch (key_len) { + case 16: + t = E_KEY[3]; + for (i = 0; i < 10; ++i) + loop4 (i); + break; + + case 24: + E_KEY[4] = le32_to_cpu(key[4]); + t = E_KEY[5] = le32_to_cpu(key[5]); + for (i = 0; i < 8; ++i) + loop6 (i); + break; + + case 32: + E_KEY[4] = le32_to_cpu(key[4]); + E_KEY[5] = le32_to_cpu(key[5]); + E_KEY[6] = le32_to_cpu(key[6]); + t = E_KEY[7] = le32_to_cpu(key[7]); + for (i = 0; i < 7; ++i) + loop8 (i); + break; + } + + D_KEY[0] = E_KEY[0]; + D_KEY[1] = E_KEY[1]; + D_KEY[2] = E_KEY[2]; + D_KEY[3] = E_KEY[3]; + + for (i = 4; i < key_len + 24; ++i) { + imix_col (D_KEY[i], E_KEY[i]); + } + + return 0; +} + +/* encrypt a block of text */ + +#define f_nround(bo, bi, k) \ + f_rn(bo, bi, 0, k); \ + f_rn(bo, bi, 1, k); \ + f_rn(bo, bi, 2, k); \ + f_rn(bo, bi, 3, k); \ + k += 4 + +#define f_lround(bo, bi, k) \ + f_rl(bo, bi, 0, k); \ + f_rl(bo, bi, 1, k); \ + f_rl(bo, bi, 2, k); \ + f_rl(bo, bi, 3, k) + +static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) +{ + const struct aes_ctx *ctx = crypto_tfm_ctx(tfm); + const __le32 *src = (const __le32 *)in; + __le32 *dst = (__le32 *)out; + u32 b0[4], b1[4]; + const u32 *kp = E_KEY + 4; + + b0[0] = le32_to_cpu(src[0]) ^ E_KEY[0]; + b0[1] = le32_to_cpu(src[1]) ^ E_KEY[1]; + b0[2] = le32_to_cpu(src[2]) ^ E_KEY[2]; + b0[3] = le32_to_cpu(src[3]) ^ E_KEY[3]; + + if (ctx->key_length > 24) { + f_nround (b1, b0, kp); + f_nround (b0, b1, kp); + } + + if (ctx->key_length > 16) { + f_nround (b1, b0, kp); + f_nround (b0, b1, kp); + } + + f_nround (b1, b0, kp); + f_nround (b0, b1, kp); + f_nround (b1, b0, kp); + f_nround (b0, b1, kp); + f_nround (b1, b0, kp); + f_nround (b0, b1, kp); + f_nround (b1, b0, kp); + f_nround (b0, b1, kp); + f_nround (b1, b0, kp); + f_lround (b0, b1, kp); + + dst[0] = cpu_to_le32(b0[0]); + dst[1] = cpu_to_le32(b0[1]); + dst[2] = cpu_to_le32(b0[2]); + dst[3] = cpu_to_le32(b0[3]); +} + +/* decrypt a block of text */ + +#define i_nround(bo, bi, k) \ + i_rn(bo, bi, 0, k); \ + i_rn(bo, bi, 1, k); \ + i_rn(bo, bi, 2, k); \ + i_rn(bo, bi, 3, k); \ + k -= 4 + +#define i_lround(bo, bi, k) \ + i_rl(bo, bi, 0, k); \ + i_rl(bo, bi, 1, k); \ + i_rl(bo, bi, 2, k); \ + i_rl(bo, bi, 3, k) + +static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) +{ + const struct aes_ctx *ctx = crypto_tfm_ctx(tfm); + const __le32 *src = (const __le32 *)in; + __le32 *dst = (__le32 *)out; + u32 b0[4], b1[4]; + const int key_len = ctx->key_length; + const u32 *kp = D_KEY + key_len + 20; + + b0[0] = le32_to_cpu(src[0]) ^ E_KEY[key_len + 24]; + b0[1] = le32_to_cpu(src[1]) ^ E_KEY[key_len + 25]; + b0[2] = le32_to_cpu(src[2]) ^ E_KEY[key_len + 26]; + b0[3] = le32_to_cpu(src[3]) ^ E_KEY[key_len + 27]; + + if (key_len > 24) { + i_nround (b1, b0, kp); + i_nround (b0, b1, kp); + } + + if (key_len > 16) { + i_nround (b1, b0, kp); + i_nround (b0, b1, kp); + } + + i_nround (b1, b0, kp); + i_nround (b0, b1, kp); + i_nround (b1, b0, kp); + i_nround (b0, b1, kp); + i_nround (b1, b0, kp); + i_nround (b0, b1, kp); + i_nround (b1, b0, kp); + i_nround (b0, b1, kp); + i_nround (b1, b0, kp); + i_lround (b0, b1, kp); + + dst[0] = cpu_to_le32(b0[0]); + dst[1] = cpu_to_le32(b0[1]); + dst[2] = cpu_to_le32(b0[2]); + dst[3] = cpu_to_le32(b0[3]); +} + + +static struct crypto_alg aes_alg = { + .cra_name = "aes", + .cra_driver_name = "aes-generic", + .cra_priority = 100, + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct aes_ctx), + .cra_alignmask = 3, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(aes_alg.cra_list), + .cra_u = { + .cipher = { + .cia_min_keysize = AES_MIN_KEY_SIZE, + .cia_max_keysize = AES_MAX_KEY_SIZE, + .cia_setkey = aes_set_key, + .cia_encrypt = aes_encrypt, + .cia_decrypt = aes_decrypt + } + } +}; + +static int __init aes_init(void) +{ + gen_tabs(); + return crypto_register_alg(&aes_alg); +} + +static void __exit aes_fini(void) +{ + crypto_unregister_alg(&aes_alg); +} + +module_init(aes_init); +module_exit(aes_fini); + +MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_ALIAS("aes"); diff --git a/drivers/crypto/geode-aes.c b/drivers/crypto/geode-aes.c index 6a86958b577..f9a34abbf4f 100644 --- a/drivers/crypto/geode-aes.c +++ b/drivers/crypto/geode-aes.c @@ -473,6 +473,7 @@ geode_aes_exit(void) MODULE_AUTHOR("Advanced Micro Devices, Inc."); MODULE_DESCRIPTION("Geode LX Hardware AES driver"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("aes"); module_init(geode_aes_init); module_exit(geode_aes_exit); diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c index d4501dc7e65..abbcff0762b 100644 --- a/drivers/crypto/padlock-aes.c +++ b/drivers/crypto/padlock-aes.c @@ -5,7 +5,7 @@ * * Copyright (c) 2004 Michal Ludvig * - * Key expansion routine taken from crypto/aes.c + * Key expansion routine taken from crypto/aes_generic.c * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -660,4 +660,4 @@ MODULE_DESCRIPTION("VIA PadLock AES algorithm support"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Michal Ludvig"); -MODULE_ALIAS("aes-padlock"); +MODULE_ALIAS("aes"); -- cgit v1.2.3-70-g09d2 From ad5d27899fdbe7a66e57fdf1af883dbd7ff88dac Mon Sep 17 00:00:00 2001 From: Sebastian Siewior Date: Mon, 8 Oct 2007 11:45:10 +0800 Subject: [CRYPTO] sha: Load the SHA[1|256] module by an alias Loading the crypto algorithm by the alias instead of by module directly has the advantage that all possible implementations of this algorithm are loaded automatically and the crypto API can choose the best one depending on its priority. Additionally it ensures that the generic implementation as well as the HW driver (if available) is loaded in case the HW driver needs the generic version as fallback in corner cases. Also remove the probe for sha1 in padlock's init code. Quote from Herbert: The probe is actually pointless since we can always probe when the algorithm is actually used which does not lead to dead-locks like this. Signed-off-by: Sebastian Siewior Signed-off-by: Herbert Xu --- arch/s390/crypto/sha1_s390.c | 2 +- arch/s390/crypto/sha256_s390.c | 2 +- crypto/Makefile | 4 +- crypto/sha1.c | 142 ----------------- crypto/sha1_generic.c | 142 +++++++++++++++++ crypto/sha256.c | 342 ----------------------------------------- crypto/sha256_generic.c | 342 +++++++++++++++++++++++++++++++++++++++++ drivers/crypto/padlock-sha.c | 17 +- 8 files changed, 490 insertions(+), 503 deletions(-) delete mode 100644 crypto/sha1.c create mode 100644 crypto/sha1_generic.c delete mode 100644 crypto/sha256.c create mode 100644 crypto/sha256_generic.c (limited to 'drivers') diff --git a/arch/s390/crypto/sha1_s390.c b/arch/s390/crypto/sha1_s390.c index af4460ec381..8ebd3cd6bd1 100644 --- a/arch/s390/crypto/sha1_s390.c +++ b/arch/s390/crypto/sha1_s390.c @@ -12,7 +12,7 @@ * Author(s): Thomas Spatzier * Jan Glauber (jan.glauber@de.ibm.com) * - * Derived from "crypto/sha1.c" + * Derived from "crypto/sha1_generic.c" * Copyright (c) Alan Smithee. * Copyright (c) Andrew McDonald * Copyright (c) Jean-Francois Dive diff --git a/arch/s390/crypto/sha256_s390.c b/arch/s390/crypto/sha256_s390.c index 2ced3330bce..c728bd0ae1e 100644 --- a/arch/s390/crypto/sha256_s390.c +++ b/arch/s390/crypto/sha256_s390.c @@ -7,7 +7,7 @@ * Copyright IBM Corp. 2005,2007 * Author(s): Jan Glauber (jang@de.ibm.com) * - * Derived from "crypto/sha256.c" + * Derived from "crypto/sha256_generic.c" * and "arch/s390/crypto/sha1_s390.c" * * This program is free software; you can redistribute it and/or modify it diff --git a/crypto/Makefile b/crypto/Makefile index b6ef5e4f1ab..43c2a0dc993 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -21,8 +21,8 @@ obj-$(CONFIG_CRYPTO_XCBC) += xcbc.o obj-$(CONFIG_CRYPTO_NULL) += crypto_null.o obj-$(CONFIG_CRYPTO_MD4) += md4.o obj-$(CONFIG_CRYPTO_MD5) += md5.o -obj-$(CONFIG_CRYPTO_SHA1) += sha1.o -obj-$(CONFIG_CRYPTO_SHA256) += sha256.o +obj-$(CONFIG_CRYPTO_SHA1) += sha1_generic.o +obj-$(CONFIG_CRYPTO_SHA256) += sha256_generic.o obj-$(CONFIG_CRYPTO_SHA512) += sha512.o obj-$(CONFIG_CRYPTO_WP512) += wp512.o obj-$(CONFIG_CRYPTO_TGR192) += tgr192.o diff --git a/crypto/sha1.c b/crypto/sha1.c deleted file mode 100644 index 1bba551e5b4..00000000000 --- a/crypto/sha1.c +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Cryptographic API. - * - * SHA1 Secure Hash Algorithm. - * - * Derived from cryptoapi implementation, adapted for in-place - * scatterlist interface. - * - * Copyright (c) Alan Smithee. - * Copyright (c) Andrew McDonald - * Copyright (c) Jean-Francois Dive - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ -#include -#include -#include -#include -#include -#include -#include -#include - -#define SHA1_DIGEST_SIZE 20 -#define SHA1_HMAC_BLOCK_SIZE 64 - -struct sha1_ctx { - u64 count; - u32 state[5]; - u8 buffer[64]; -}; - -static void sha1_init(struct crypto_tfm *tfm) -{ - struct sha1_ctx *sctx = crypto_tfm_ctx(tfm); - static const struct sha1_ctx initstate = { - 0, - { 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 }, - { 0, } - }; - - *sctx = initstate; -} - -static void sha1_update(struct crypto_tfm *tfm, const u8 *data, - unsigned int len) -{ - struct sha1_ctx *sctx = crypto_tfm_ctx(tfm); - unsigned int partial, done; - const u8 *src; - - partial = sctx->count & 0x3f; - sctx->count += len; - done = 0; - src = data; - - if ((partial + len) > 63) { - u32 temp[SHA_WORKSPACE_WORDS]; - - if (partial) { - done = -partial; - memcpy(sctx->buffer + partial, data, done + 64); - src = sctx->buffer; - } - - do { - sha_transform(sctx->state, src, temp); - done += 64; - src = data + done; - } while (done + 63 < len); - - memset(temp, 0, sizeof(temp)); - partial = 0; - } - memcpy(sctx->buffer + partial, src, len - done); -} - - -/* Add padding and return the message digest. */ -static void sha1_final(struct crypto_tfm *tfm, u8 *out) -{ - struct sha1_ctx *sctx = crypto_tfm_ctx(tfm); - __be32 *dst = (__be32 *)out; - u32 i, index, padlen; - __be64 bits; - static const u8 padding[64] = { 0x80, }; - - bits = cpu_to_be64(sctx->count << 3); - - /* Pad out to 56 mod 64 */ - index = sctx->count & 0x3f; - padlen = (index < 56) ? (56 - index) : ((64+56) - index); - sha1_update(tfm, padding, padlen); - - /* Append length */ - sha1_update(tfm, (const u8 *)&bits, sizeof(bits)); - - /* Store state in digest */ - for (i = 0; i < 5; i++) - dst[i] = cpu_to_be32(sctx->state[i]); - - /* Wipe context */ - memset(sctx, 0, sizeof *sctx); -} - -static struct crypto_alg alg = { - .cra_name = "sha1", - .cra_driver_name= "sha1-generic", - .cra_flags = CRYPTO_ALG_TYPE_DIGEST, - .cra_blocksize = SHA1_HMAC_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct sha1_ctx), - .cra_module = THIS_MODULE, - .cra_alignmask = 3, - .cra_list = LIST_HEAD_INIT(alg.cra_list), - .cra_u = { .digest = { - .dia_digestsize = SHA1_DIGEST_SIZE, - .dia_init = sha1_init, - .dia_update = sha1_update, - .dia_final = sha1_final } } -}; - -static int __init init(void) -{ - return crypto_register_alg(&alg); -} - -static void __exit fini(void) -{ - crypto_unregister_alg(&alg); -} - -module_init(init); -module_exit(fini); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("SHA1 Secure Hash Algorithm"); - -MODULE_ALIAS("sha1-generic"); diff --git a/crypto/sha1_generic.c b/crypto/sha1_generic.c new file mode 100644 index 00000000000..70364dd5c45 --- /dev/null +++ b/crypto/sha1_generic.c @@ -0,0 +1,142 @@ +/* + * Cryptographic API. + * + * SHA1 Secure Hash Algorithm. + * + * Derived from cryptoapi implementation, adapted for in-place + * scatterlist interface. + * + * Copyright (c) Alan Smithee. + * Copyright (c) Andrew McDonald + * Copyright (c) Jean-Francois Dive + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#define SHA1_DIGEST_SIZE 20 +#define SHA1_HMAC_BLOCK_SIZE 64 + +struct sha1_ctx { + u64 count; + u32 state[5]; + u8 buffer[64]; +}; + +static void sha1_init(struct crypto_tfm *tfm) +{ + struct sha1_ctx *sctx = crypto_tfm_ctx(tfm); + static const struct sha1_ctx initstate = { + 0, + { 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 }, + { 0, } + }; + + *sctx = initstate; +} + +static void sha1_update(struct crypto_tfm *tfm, const u8 *data, + unsigned int len) +{ + struct sha1_ctx *sctx = crypto_tfm_ctx(tfm); + unsigned int partial, done; + const u8 *src; + + partial = sctx->count & 0x3f; + sctx->count += len; + done = 0; + src = data; + + if ((partial + len) > 63) { + u32 temp[SHA_WORKSPACE_WORDS]; + + if (partial) { + done = -partial; + memcpy(sctx->buffer + partial, data, done + 64); + src = sctx->buffer; + } + + do { + sha_transform(sctx->state, src, temp); + done += 64; + src = data + done; + } while (done + 63 < len); + + memset(temp, 0, sizeof(temp)); + partial = 0; + } + memcpy(sctx->buffer + partial, src, len - done); +} + + +/* Add padding and return the message digest. */ +static void sha1_final(struct crypto_tfm *tfm, u8 *out) +{ + struct sha1_ctx *sctx = crypto_tfm_ctx(tfm); + __be32 *dst = (__be32 *)out; + u32 i, index, padlen; + __be64 bits; + static const u8 padding[64] = { 0x80, }; + + bits = cpu_to_be64(sctx->count << 3); + + /* Pad out to 56 mod 64 */ + index = sctx->count & 0x3f; + padlen = (index < 56) ? (56 - index) : ((64+56) - index); + sha1_update(tfm, padding, padlen); + + /* Append length */ + sha1_update(tfm, (const u8 *)&bits, sizeof(bits)); + + /* Store state in digest */ + for (i = 0; i < 5; i++) + dst[i] = cpu_to_be32(sctx->state[i]); + + /* Wipe context */ + memset(sctx, 0, sizeof *sctx); +} + +static struct crypto_alg alg = { + .cra_name = "sha1", + .cra_driver_name= "sha1-generic", + .cra_flags = CRYPTO_ALG_TYPE_DIGEST, + .cra_blocksize = SHA1_HMAC_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct sha1_ctx), + .cra_module = THIS_MODULE, + .cra_alignmask = 3, + .cra_list = LIST_HEAD_INIT(alg.cra_list), + .cra_u = { .digest = { + .dia_digestsize = SHA1_DIGEST_SIZE, + .dia_init = sha1_init, + .dia_update = sha1_update, + .dia_final = sha1_final } } +}; + +static int __init init(void) +{ + return crypto_register_alg(&alg); +} + +static void __exit fini(void) +{ + crypto_unregister_alg(&alg); +} + +module_init(init); +module_exit(fini); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SHA1 Secure Hash Algorithm"); + +MODULE_ALIAS("sha1"); diff --git a/crypto/sha256.c b/crypto/sha256.c deleted file mode 100644 index 716195bb54f..00000000000 --- a/crypto/sha256.c +++ /dev/null @@ -1,342 +0,0 @@ -/* - * Cryptographic API. - * - * SHA-256, as specified in - * http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf - * - * SHA-256 code by Jean-Luc Cooke . - * - * Copyright (c) Jean-Luc Cooke - * Copyright (c) Andrew McDonald - * Copyright (c) 2002 James Morris - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ -#include -#include -#include -#include -#include -#include -#include - -#define SHA256_DIGEST_SIZE 32 -#define SHA256_HMAC_BLOCK_SIZE 64 - -struct sha256_ctx { - u32 count[2]; - u32 state[8]; - u8 buf[128]; -}; - -static inline u32 Ch(u32 x, u32 y, u32 z) -{ - return z ^ (x & (y ^ z)); -} - -static inline u32 Maj(u32 x, u32 y, u32 z) -{ - return (x & y) | (z & (x | y)); -} - -#define e0(x) (ror32(x, 2) ^ ror32(x,13) ^ ror32(x,22)) -#define e1(x) (ror32(x, 6) ^ ror32(x,11) ^ ror32(x,25)) -#define s0(x) (ror32(x, 7) ^ ror32(x,18) ^ (x >> 3)) -#define s1(x) (ror32(x,17) ^ ror32(x,19) ^ (x >> 10)) - -#define H0 0x6a09e667 -#define H1 0xbb67ae85 -#define H2 0x3c6ef372 -#define H3 0xa54ff53a -#define H4 0x510e527f -#define H5 0x9b05688c -#define H6 0x1f83d9ab -#define H7 0x5be0cd19 - -static inline void LOAD_OP(int I, u32 *W, const u8 *input) -{ - W[I] = __be32_to_cpu( ((__be32*)(input))[I] ); -} - -static inline void BLEND_OP(int I, u32 *W) -{ - W[I] = s1(W[I-2]) + W[I-7] + s0(W[I-15]) + W[I-16]; -} - -static void sha256_transform(u32 *state, const u8 *input) -{ - u32 a, b, c, d, e, f, g, h, t1, t2; - u32 W[64]; - int i; - - /* load the input */ - for (i = 0; i < 16; i++) - LOAD_OP(i, W, input); - - /* now blend */ - for (i = 16; i < 64; i++) - BLEND_OP(i, W); - - /* load the state into our registers */ - a=state[0]; b=state[1]; c=state[2]; d=state[3]; - e=state[4]; f=state[5]; g=state[6]; h=state[7]; - - /* now iterate */ - t1 = h + e1(e) + Ch(e,f,g) + 0x428a2f98 + W[ 0]; - t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; - t1 = g + e1(d) + Ch(d,e,f) + 0x71374491 + W[ 1]; - t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; - t1 = f + e1(c) + Ch(c,d,e) + 0xb5c0fbcf + W[ 2]; - t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; - t1 = e + e1(b) + Ch(b,c,d) + 0xe9b5dba5 + W[ 3]; - t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; - t1 = d + e1(a) + Ch(a,b,c) + 0x3956c25b + W[ 4]; - t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; - t1 = c + e1(h) + Ch(h,a,b) + 0x59f111f1 + W[ 5]; - t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; - t1 = b + e1(g) + Ch(g,h,a) + 0x923f82a4 + W[ 6]; - t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; - t1 = a + e1(f) + Ch(f,g,h) + 0xab1c5ed5 + W[ 7]; - t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; - - t1 = h + e1(e) + Ch(e,f,g) + 0xd807aa98 + W[ 8]; - t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; - t1 = g + e1(d) + Ch(d,e,f) + 0x12835b01 + W[ 9]; - t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; - t1 = f + e1(c) + Ch(c,d,e) + 0x243185be + W[10]; - t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; - t1 = e + e1(b) + Ch(b,c,d) + 0x550c7dc3 + W[11]; - t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; - t1 = d + e1(a) + Ch(a,b,c) + 0x72be5d74 + W[12]; - t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; - t1 = c + e1(h) + Ch(h,a,b) + 0x80deb1fe + W[13]; - t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; - t1 = b + e1(g) + Ch(g,h,a) + 0x9bdc06a7 + W[14]; - t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; - t1 = a + e1(f) + Ch(f,g,h) + 0xc19bf174 + W[15]; - t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; - - t1 = h + e1(e) + Ch(e,f,g) + 0xe49b69c1 + W[16]; - t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; - t1 = g + e1(d) + Ch(d,e,f) + 0xefbe4786 + W[17]; - t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; - t1 = f + e1(c) + Ch(c,d,e) + 0x0fc19dc6 + W[18]; - t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; - t1 = e + e1(b) + Ch(b,c,d) + 0x240ca1cc + W[19]; - t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; - t1 = d + e1(a) + Ch(a,b,c) + 0x2de92c6f + W[20]; - t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; - t1 = c + e1(h) + Ch(h,a,b) + 0x4a7484aa + W[21]; - t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; - t1 = b + e1(g) + Ch(g,h,a) + 0x5cb0a9dc + W[22]; - t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; - t1 = a + e1(f) + Ch(f,g,h) + 0x76f988da + W[23]; - t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; - - t1 = h + e1(e) + Ch(e,f,g) + 0x983e5152 + W[24]; - t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; - t1 = g + e1(d) + Ch(d,e,f) + 0xa831c66d + W[25]; - t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; - t1 = f + e1(c) + Ch(c,d,e) + 0xb00327c8 + W[26]; - t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; - t1 = e + e1(b) + Ch(b,c,d) + 0xbf597fc7 + W[27]; - t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; - t1 = d + e1(a) + Ch(a,b,c) + 0xc6e00bf3 + W[28]; - t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; - t1 = c + e1(h) + Ch(h,a,b) + 0xd5a79147 + W[29]; - t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; - t1 = b + e1(g) + Ch(g,h,a) + 0x06ca6351 + W[30]; - t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; - t1 = a + e1(f) + Ch(f,g,h) + 0x14292967 + W[31]; - t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; - - t1 = h + e1(e) + Ch(e,f,g) + 0x27b70a85 + W[32]; - t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; - t1 = g + e1(d) + Ch(d,e,f) + 0x2e1b2138 + W[33]; - t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; - t1 = f + e1(c) + Ch(c,d,e) + 0x4d2c6dfc + W[34]; - t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; - t1 = e + e1(b) + Ch(b,c,d) + 0x53380d13 + W[35]; - t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; - t1 = d + e1(a) + Ch(a,b,c) + 0x650a7354 + W[36]; - t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; - t1 = c + e1(h) + Ch(h,a,b) + 0x766a0abb + W[37]; - t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; - t1 = b + e1(g) + Ch(g,h,a) + 0x81c2c92e + W[38]; - t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; - t1 = a + e1(f) + Ch(f,g,h) + 0x92722c85 + W[39]; - t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; - - t1 = h + e1(e) + Ch(e,f,g) + 0xa2bfe8a1 + W[40]; - t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; - t1 = g + e1(d) + Ch(d,e,f) + 0xa81a664b + W[41]; - t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; - t1 = f + e1(c) + Ch(c,d,e) + 0xc24b8b70 + W[42]; - t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; - t1 = e + e1(b) + Ch(b,c,d) + 0xc76c51a3 + W[43]; - t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; - t1 = d + e1(a) + Ch(a,b,c) + 0xd192e819 + W[44]; - t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; - t1 = c + e1(h) + Ch(h,a,b) + 0xd6990624 + W[45]; - t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; - t1 = b + e1(g) + Ch(g,h,a) + 0xf40e3585 + W[46]; - t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; - t1 = a + e1(f) + Ch(f,g,h) + 0x106aa070 + W[47]; - t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; - - t1 = h + e1(e) + Ch(e,f,g) + 0x19a4c116 + W[48]; - t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; - t1 = g + e1(d) + Ch(d,e,f) + 0x1e376c08 + W[49]; - t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; - t1 = f + e1(c) + Ch(c,d,e) + 0x2748774c + W[50]; - t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; - t1 = e + e1(b) + Ch(b,c,d) + 0x34b0bcb5 + W[51]; - t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; - t1 = d + e1(a) + Ch(a,b,c) + 0x391c0cb3 + W[52]; - t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; - t1 = c + e1(h) + Ch(h,a,b) + 0x4ed8aa4a + W[53]; - t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; - t1 = b + e1(g) + Ch(g,h,a) + 0x5b9cca4f + W[54]; - t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; - t1 = a + e1(f) + Ch(f,g,h) + 0x682e6ff3 + W[55]; - t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; - - t1 = h + e1(e) + Ch(e,f,g) + 0x748f82ee + W[56]; - t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; - t1 = g + e1(d) + Ch(d,e,f) + 0x78a5636f + W[57]; - t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; - t1 = f + e1(c) + Ch(c,d,e) + 0x84c87814 + W[58]; - t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; - t1 = e + e1(b) + Ch(b,c,d) + 0x8cc70208 + W[59]; - t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; - t1 = d + e1(a) + Ch(a,b,c) + 0x90befffa + W[60]; - t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; - t1 = c + e1(h) + Ch(h,a,b) + 0xa4506ceb + W[61]; - t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; - t1 = b + e1(g) + Ch(g,h,a) + 0xbef9a3f7 + W[62]; - t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; - t1 = a + e1(f) + Ch(f,g,h) + 0xc67178f2 + W[63]; - t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; - - state[0] += a; state[1] += b; state[2] += c; state[3] += d; - state[4] += e; state[5] += f; state[6] += g; state[7] += h; - - /* clear any sensitive info... */ - a = b = c = d = e = f = g = h = t1 = t2 = 0; - memset(W, 0, 64 * sizeof(u32)); -} - -static void sha256_init(struct crypto_tfm *tfm) -{ - struct sha256_ctx *sctx = crypto_tfm_ctx(tfm); - sctx->state[0] = H0; - sctx->state[1] = H1; - sctx->state[2] = H2; - sctx->state[3] = H3; - sctx->state[4] = H4; - sctx->state[5] = H5; - sctx->state[6] = H6; - sctx->state[7] = H7; - sctx->count[0] = sctx->count[1] = 0; -} - -static void sha256_update(struct crypto_tfm *tfm, const u8 *data, - unsigned int len) -{ - struct sha256_ctx *sctx = crypto_tfm_ctx(tfm); - unsigned int i, index, part_len; - - /* Compute number of bytes mod 128 */ - index = (unsigned int)((sctx->count[0] >> 3) & 0x3f); - - /* Update number of bits */ - if ((sctx->count[0] += (len << 3)) < (len << 3)) { - sctx->count[1]++; - sctx->count[1] += (len >> 29); - } - - part_len = 64 - index; - - /* Transform as many times as possible. */ - if (len >= part_len) { - memcpy(&sctx->buf[index], data, part_len); - sha256_transform(sctx->state, sctx->buf); - - for (i = part_len; i + 63 < len; i += 64) - sha256_transform(sctx->state, &data[i]); - index = 0; - } else { - i = 0; - } - - /* Buffer remaining input */ - memcpy(&sctx->buf[index], &data[i], len-i); -} - -static void sha256_final(struct crypto_tfm *tfm, u8 *out) -{ - struct sha256_ctx *sctx = crypto_tfm_ctx(tfm); - __be32 *dst = (__be32 *)out; - __be32 bits[2]; - unsigned int index, pad_len; - int i; - static const u8 padding[64] = { 0x80, }; - - /* Save number of bits */ - bits[1] = cpu_to_be32(sctx->count[0]); - bits[0] = cpu_to_be32(sctx->count[1]); - - /* Pad out to 56 mod 64. */ - index = (sctx->count[0] >> 3) & 0x3f; - pad_len = (index < 56) ? (56 - index) : ((64+56) - index); - sha256_update(tfm, padding, pad_len); - - /* Append length (before padding) */ - sha256_update(tfm, (const u8 *)bits, sizeof(bits)); - - /* Store state in digest */ - for (i = 0; i < 8; i++) - dst[i] = cpu_to_be32(sctx->state[i]); - - /* Zeroize sensitive information. */ - memset(sctx, 0, sizeof(*sctx)); -} - - -static struct crypto_alg alg = { - .cra_name = "sha256", - .cra_driver_name= "sha256-generic", - .cra_flags = CRYPTO_ALG_TYPE_DIGEST, - .cra_blocksize = SHA256_HMAC_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct sha256_ctx), - .cra_module = THIS_MODULE, - .cra_alignmask = 3, - .cra_list = LIST_HEAD_INIT(alg.cra_list), - .cra_u = { .digest = { - .dia_digestsize = SHA256_DIGEST_SIZE, - .dia_init = sha256_init, - .dia_update = sha256_update, - .dia_final = sha256_final } } -}; - -static int __init init(void) -{ - return crypto_register_alg(&alg); -} - -static void __exit fini(void) -{ - crypto_unregister_alg(&alg); -} - -module_init(init); -module_exit(fini); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("SHA256 Secure Hash Algorithm"); - -MODULE_ALIAS("sha256-generic"); diff --git a/crypto/sha256_generic.c b/crypto/sha256_generic.c new file mode 100644 index 00000000000..74bf2f95f4e --- /dev/null +++ b/crypto/sha256_generic.c @@ -0,0 +1,342 @@ +/* + * Cryptographic API. + * + * SHA-256, as specified in + * http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf + * + * SHA-256 code by Jean-Luc Cooke . + * + * Copyright (c) Jean-Luc Cooke + * Copyright (c) Andrew McDonald + * Copyright (c) 2002 James Morris + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ +#include +#include +#include +#include +#include +#include +#include + +#define SHA256_DIGEST_SIZE 32 +#define SHA256_HMAC_BLOCK_SIZE 64 + +struct sha256_ctx { + u32 count[2]; + u32 state[8]; + u8 buf[128]; +}; + +static inline u32 Ch(u32 x, u32 y, u32 z) +{ + return z ^ (x & (y ^ z)); +} + +static inline u32 Maj(u32 x, u32 y, u32 z) +{ + return (x & y) | (z & (x | y)); +} + +#define e0(x) (ror32(x, 2) ^ ror32(x,13) ^ ror32(x,22)) +#define e1(x) (ror32(x, 6) ^ ror32(x,11) ^ ror32(x,25)) +#define s0(x) (ror32(x, 7) ^ ror32(x,18) ^ (x >> 3)) +#define s1(x) (ror32(x,17) ^ ror32(x,19) ^ (x >> 10)) + +#define H0 0x6a09e667 +#define H1 0xbb67ae85 +#define H2 0x3c6ef372 +#define H3 0xa54ff53a +#define H4 0x510e527f +#define H5 0x9b05688c +#define H6 0x1f83d9ab +#define H7 0x5be0cd19 + +static inline void LOAD_OP(int I, u32 *W, const u8 *input) +{ + W[I] = __be32_to_cpu( ((__be32*)(input))[I] ); +} + +static inline void BLEND_OP(int I, u32 *W) +{ + W[I] = s1(W[I-2]) + W[I-7] + s0(W[I-15]) + W[I-16]; +} + +static void sha256_transform(u32 *state, const u8 *input) +{ + u32 a, b, c, d, e, f, g, h, t1, t2; + u32 W[64]; + int i; + + /* load the input */ + for (i = 0; i < 16; i++) + LOAD_OP(i, W, input); + + /* now blend */ + for (i = 16; i < 64; i++) + BLEND_OP(i, W); + + /* load the state into our registers */ + a=state[0]; b=state[1]; c=state[2]; d=state[3]; + e=state[4]; f=state[5]; g=state[6]; h=state[7]; + + /* now iterate */ + t1 = h + e1(e) + Ch(e,f,g) + 0x428a2f98 + W[ 0]; + t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; + t1 = g + e1(d) + Ch(d,e,f) + 0x71374491 + W[ 1]; + t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; + t1 = f + e1(c) + Ch(c,d,e) + 0xb5c0fbcf + W[ 2]; + t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; + t1 = e + e1(b) + Ch(b,c,d) + 0xe9b5dba5 + W[ 3]; + t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; + t1 = d + e1(a) + Ch(a,b,c) + 0x3956c25b + W[ 4]; + t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; + t1 = c + e1(h) + Ch(h,a,b) + 0x59f111f1 + W[ 5]; + t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; + t1 = b + e1(g) + Ch(g,h,a) + 0x923f82a4 + W[ 6]; + t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; + t1 = a + e1(f) + Ch(f,g,h) + 0xab1c5ed5 + W[ 7]; + t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; + + t1 = h + e1(e) + Ch(e,f,g) + 0xd807aa98 + W[ 8]; + t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; + t1 = g + e1(d) + Ch(d,e,f) + 0x12835b01 + W[ 9]; + t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; + t1 = f + e1(c) + Ch(c,d,e) + 0x243185be + W[10]; + t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; + t1 = e + e1(b) + Ch(b,c,d) + 0x550c7dc3 + W[11]; + t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; + t1 = d + e1(a) + Ch(a,b,c) + 0x72be5d74 + W[12]; + t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; + t1 = c + e1(h) + Ch(h,a,b) + 0x80deb1fe + W[13]; + t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; + t1 = b + e1(g) + Ch(g,h,a) + 0x9bdc06a7 + W[14]; + t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; + t1 = a + e1(f) + Ch(f,g,h) + 0xc19bf174 + W[15]; + t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; + + t1 = h + e1(e) + Ch(e,f,g) + 0xe49b69c1 + W[16]; + t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; + t1 = g + e1(d) + Ch(d,e,f) + 0xefbe4786 + W[17]; + t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; + t1 = f + e1(c) + Ch(c,d,e) + 0x0fc19dc6 + W[18]; + t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; + t1 = e + e1(b) + Ch(b,c,d) + 0x240ca1cc + W[19]; + t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; + t1 = d + e1(a) + Ch(a,b,c) + 0x2de92c6f + W[20]; + t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; + t1 = c + e1(h) + Ch(h,a,b) + 0x4a7484aa + W[21]; + t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; + t1 = b + e1(g) + Ch(g,h,a) + 0x5cb0a9dc + W[22]; + t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; + t1 = a + e1(f) + Ch(f,g,h) + 0x76f988da + W[23]; + t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; + + t1 = h + e1(e) + Ch(e,f,g) + 0x983e5152 + W[24]; + t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; + t1 = g + e1(d) + Ch(d,e,f) + 0xa831c66d + W[25]; + t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; + t1 = f + e1(c) + Ch(c,d,e) + 0xb00327c8 + W[26]; + t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; + t1 = e + e1(b) + Ch(b,c,d) + 0xbf597fc7 + W[27]; + t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; + t1 = d + e1(a) + Ch(a,b,c) + 0xc6e00bf3 + W[28]; + t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; + t1 = c + e1(h) + Ch(h,a,b) + 0xd5a79147 + W[29]; + t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; + t1 = b + e1(g) + Ch(g,h,a) + 0x06ca6351 + W[30]; + t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; + t1 = a + e1(f) + Ch(f,g,h) + 0x14292967 + W[31]; + t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; + + t1 = h + e1(e) + Ch(e,f,g) + 0x27b70a85 + W[32]; + t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; + t1 = g + e1(d) + Ch(d,e,f) + 0x2e1b2138 + W[33]; + t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; + t1 = f + e1(c) + Ch(c,d,e) + 0x4d2c6dfc + W[34]; + t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; + t1 = e + e1(b) + Ch(b,c,d) + 0x53380d13 + W[35]; + t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; + t1 = d + e1(a) + Ch(a,b,c) + 0x650a7354 + W[36]; + t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; + t1 = c + e1(h) + Ch(h,a,b) + 0x766a0abb + W[37]; + t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; + t1 = b + e1(g) + Ch(g,h,a) + 0x81c2c92e + W[38]; + t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; + t1 = a + e1(f) + Ch(f,g,h) + 0x92722c85 + W[39]; + t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; + + t1 = h + e1(e) + Ch(e,f,g) + 0xa2bfe8a1 + W[40]; + t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; + t1 = g + e1(d) + Ch(d,e,f) + 0xa81a664b + W[41]; + t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; + t1 = f + e1(c) + Ch(c,d,e) + 0xc24b8b70 + W[42]; + t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; + t1 = e + e1(b) + Ch(b,c,d) + 0xc76c51a3 + W[43]; + t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; + t1 = d + e1(a) + Ch(a,b,c) + 0xd192e819 + W[44]; + t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; + t1 = c + e1(h) + Ch(h,a,b) + 0xd6990624 + W[45]; + t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; + t1 = b + e1(g) + Ch(g,h,a) + 0xf40e3585 + W[46]; + t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; + t1 = a + e1(f) + Ch(f,g,h) + 0x106aa070 + W[47]; + t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; + + t1 = h + e1(e) + Ch(e,f,g) + 0x19a4c116 + W[48]; + t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; + t1 = g + e1(d) + Ch(d,e,f) + 0x1e376c08 + W[49]; + t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; + t1 = f + e1(c) + Ch(c,d,e) + 0x2748774c + W[50]; + t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; + t1 = e + e1(b) + Ch(b,c,d) + 0x34b0bcb5 + W[51]; + t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; + t1 = d + e1(a) + Ch(a,b,c) + 0x391c0cb3 + W[52]; + t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; + t1 = c + e1(h) + Ch(h,a,b) + 0x4ed8aa4a + W[53]; + t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; + t1 = b + e1(g) + Ch(g,h,a) + 0x5b9cca4f + W[54]; + t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; + t1 = a + e1(f) + Ch(f,g,h) + 0x682e6ff3 + W[55]; + t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; + + t1 = h + e1(e) + Ch(e,f,g) + 0x748f82ee + W[56]; + t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; + t1 = g + e1(d) + Ch(d,e,f) + 0x78a5636f + W[57]; + t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; + t1 = f + e1(c) + Ch(c,d,e) + 0x84c87814 + W[58]; + t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; + t1 = e + e1(b) + Ch(b,c,d) + 0x8cc70208 + W[59]; + t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; + t1 = d + e1(a) + Ch(a,b,c) + 0x90befffa + W[60]; + t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; + t1 = c + e1(h) + Ch(h,a,b) + 0xa4506ceb + W[61]; + t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; + t1 = b + e1(g) + Ch(g,h,a) + 0xbef9a3f7 + W[62]; + t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; + t1 = a + e1(f) + Ch(f,g,h) + 0xc67178f2 + W[63]; + t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; + + state[0] += a; state[1] += b; state[2] += c; state[3] += d; + state[4] += e; state[5] += f; state[6] += g; state[7] += h; + + /* clear any sensitive info... */ + a = b = c = d = e = f = g = h = t1 = t2 = 0; + memset(W, 0, 64 * sizeof(u32)); +} + +static void sha256_init(struct crypto_tfm *tfm) +{ + struct sha256_ctx *sctx = crypto_tfm_ctx(tfm); + sctx->state[0] = H0; + sctx->state[1] = H1; + sctx->state[2] = H2; + sctx->state[3] = H3; + sctx->state[4] = H4; + sctx->state[5] = H5; + sctx->state[6] = H6; + sctx->state[7] = H7; + sctx->count[0] = sctx->count[1] = 0; +} + +static void sha256_update(struct crypto_tfm *tfm, const u8 *data, + unsigned int len) +{ + struct sha256_ctx *sctx = crypto_tfm_ctx(tfm); + unsigned int i, index, part_len; + + /* Compute number of bytes mod 128 */ + index = (unsigned int)((sctx->count[0] >> 3) & 0x3f); + + /* Update number of bits */ + if ((sctx->count[0] += (len << 3)) < (len << 3)) { + sctx->count[1]++; + sctx->count[1] += (len >> 29); + } + + part_len = 64 - index; + + /* Transform as many times as possible. */ + if (len >= part_len) { + memcpy(&sctx->buf[index], data, part_len); + sha256_transform(sctx->state, sctx->buf); + + for (i = part_len; i + 63 < len; i += 64) + sha256_transform(sctx->state, &data[i]); + index = 0; + } else { + i = 0; + } + + /* Buffer remaining input */ + memcpy(&sctx->buf[index], &data[i], len-i); +} + +static void sha256_final(struct crypto_tfm *tfm, u8 *out) +{ + struct sha256_ctx *sctx = crypto_tfm_ctx(tfm); + __be32 *dst = (__be32 *)out; + __be32 bits[2]; + unsigned int index, pad_len; + int i; + static const u8 padding[64] = { 0x80, }; + + /* Save number of bits */ + bits[1] = cpu_to_be32(sctx->count[0]); + bits[0] = cpu_to_be32(sctx->count[1]); + + /* Pad out to 56 mod 64. */ + index = (sctx->count[0] >> 3) & 0x3f; + pad_len = (index < 56) ? (56 - index) : ((64+56) - index); + sha256_update(tfm, padding, pad_len); + + /* Append length (before padding) */ + sha256_update(tfm, (const u8 *)bits, sizeof(bits)); + + /* Store state in digest */ + for (i = 0; i < 8; i++) + dst[i] = cpu_to_be32(sctx->state[i]); + + /* Zeroize sensitive information. */ + memset(sctx, 0, sizeof(*sctx)); +} + + +static struct crypto_alg alg = { + .cra_name = "sha256", + .cra_driver_name= "sha256-generic", + .cra_flags = CRYPTO_ALG_TYPE_DIGEST, + .cra_blocksize = SHA256_HMAC_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct sha256_ctx), + .cra_module = THIS_MODULE, + .cra_alignmask = 3, + .cra_list = LIST_HEAD_INIT(alg.cra_list), + .cra_u = { .digest = { + .dia_digestsize = SHA256_DIGEST_SIZE, + .dia_init = sha256_init, + .dia_update = sha256_update, + .dia_final = sha256_final } } +}; + +static int __init init(void) +{ + return crypto_register_alg(&alg); +} + +static void __exit fini(void) +{ + crypto_unregister_alg(&alg); +} + +module_init(init); +module_exit(fini); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SHA256 Secure Hash Algorithm"); + +MODULE_ALIAS("sha256"); diff --git a/drivers/crypto/padlock-sha.c b/drivers/crypto/padlock-sha.c index a781fd23b60..f3857bbbfae 100644 --- a/drivers/crypto/padlock-sha.c +++ b/drivers/crypto/padlock-sha.c @@ -253,19 +253,6 @@ static struct crypto_alg sha256_alg = { } }; -static void __init padlock_sha_check_fallbacks(void) -{ - if (!crypto_has_hash("sha1", 0, CRYPTO_ALG_ASYNC | - CRYPTO_ALG_NEED_FALLBACK)) - printk(KERN_WARNING PFX - "Couldn't load fallback module for sha1.\n"); - - if (!crypto_has_hash("sha256", 0, CRYPTO_ALG_ASYNC | - CRYPTO_ALG_NEED_FALLBACK)) - printk(KERN_WARNING PFX - "Couldn't load fallback module for sha256.\n"); -} - static int __init padlock_init(void) { int rc = -ENODEV; @@ -280,8 +267,6 @@ static int __init padlock_init(void) return -ENODEV; } - padlock_sha_check_fallbacks(); - rc = crypto_register_alg(&sha1_alg); if (rc) goto out; @@ -314,5 +299,7 @@ MODULE_DESCRIPTION("VIA PadLock SHA1/SHA256 algorithms support."); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Michal Ludvig"); +MODULE_ALIAS("sha1"); +MODULE_ALIAS("sha256"); MODULE_ALIAS("sha1-padlock"); MODULE_ALIAS("sha256-padlock"); -- cgit v1.2.3-70-g09d2 From 5265eeb2b036835021591173ac64e624baaff55c Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Tue, 9 Oct 2007 22:43:13 +0800 Subject: [CRYPTO] sha: Add header file for SHA definitions There are currently several SHA implementations that all define their own initialization vectors and size values. Since this values are idential move them to a header file under include/crypto. Signed-off-by: Jan Glauber Signed-off-by: Herbert Xu --- arch/s390/crypto/sha1_s390.c | 14 ++++------ arch/s390/crypto/sha256_s390.c | 20 ++++++-------- crypto/sha1_generic.c | 8 ++---- crypto/sha256_generic.c | 31 +++++++-------------- crypto/sha512.c | 63 +++++++++++++----------------------------- drivers/crypto/padlock-sha.c | 36 +++++++++++------------- include/crypto/sha.h | 53 +++++++++++++++++++++++++++++++++++ 7 files changed, 116 insertions(+), 109 deletions(-) create mode 100644 include/crypto/sha.h (limited to 'drivers') diff --git a/arch/s390/crypto/sha1_s390.c b/arch/s390/crypto/sha1_s390.c index 8ebd3cd6bd1..5a834f6578a 100644 --- a/arch/s390/crypto/sha1_s390.c +++ b/arch/s390/crypto/sha1_s390.c @@ -26,12 +26,10 @@ #include #include #include +#include #include "crypt_s390.h" -#define SHA1_DIGEST_SIZE 20 -#define SHA1_BLOCK_SIZE 64 - struct s390_sha1_ctx { u64 count; /* message length */ u32 state[5]; @@ -42,11 +40,11 @@ static void sha1_init(struct crypto_tfm *tfm) { struct s390_sha1_ctx *sctx = crypto_tfm_ctx(tfm); - sctx->state[0] = 0x67452301; - sctx->state[1] = 0xEFCDAB89; - sctx->state[2] = 0x98BADCFE; - sctx->state[3] = 0x10325476; - sctx->state[4] = 0xC3D2E1F0; + sctx->state[0] = SHA1_H0; + sctx->state[1] = SHA1_H1; + sctx->state[2] = SHA1_H2; + sctx->state[3] = SHA1_H3; + sctx->state[4] = SHA1_H4; sctx->count = 0; } diff --git a/arch/s390/crypto/sha256_s390.c b/arch/s390/crypto/sha256_s390.c index c728bd0ae1e..ccf8633c4f6 100644 --- a/arch/s390/crypto/sha256_s390.c +++ b/arch/s390/crypto/sha256_s390.c @@ -19,12 +19,10 @@ #include #include #include +#include #include "crypt_s390.h" -#define SHA256_DIGEST_SIZE 32 -#define SHA256_BLOCK_SIZE 64 - struct s390_sha256_ctx { u64 count; /* message length */ u32 state[8]; @@ -35,14 +33,14 @@ static void sha256_init(struct crypto_tfm *tfm) { struct s390_sha256_ctx *sctx = crypto_tfm_ctx(tfm); - sctx->state[0] = 0x6a09e667; - sctx->state[1] = 0xbb67ae85; - sctx->state[2] = 0x3c6ef372; - sctx->state[3] = 0xa54ff53a; - sctx->state[4] = 0x510e527f; - sctx->state[5] = 0x9b05688c; - sctx->state[6] = 0x1f83d9ab; - sctx->state[7] = 0x5be0cd19; + sctx->state[0] = SHA256_H0; + sctx->state[1] = SHA256_H1; + sctx->state[2] = SHA256_H2; + sctx->state[3] = SHA256_H3; + sctx->state[4] = SHA256_H4; + sctx->state[5] = SHA256_H5; + sctx->state[6] = SHA256_H6; + sctx->state[7] = SHA256_H7; sctx->count = 0; } diff --git a/crypto/sha1_generic.c b/crypto/sha1_generic.c index 70364dd5c45..48a3c3e0bf5 100644 --- a/crypto/sha1_generic.c +++ b/crypto/sha1_generic.c @@ -22,12 +22,10 @@ #include #include #include +#include #include #include -#define SHA1_DIGEST_SIZE 20 -#define SHA1_HMAC_BLOCK_SIZE 64 - struct sha1_ctx { u64 count; u32 state[5]; @@ -39,7 +37,7 @@ static void sha1_init(struct crypto_tfm *tfm) struct sha1_ctx *sctx = crypto_tfm_ctx(tfm); static const struct sha1_ctx initstate = { 0, - { 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 }, + { SHA1_H0, SHA1_H1, SHA1_H2, SHA1_H3, SHA1_H4 }, { 0, } }; @@ -111,7 +109,7 @@ static struct crypto_alg alg = { .cra_name = "sha1", .cra_driver_name= "sha1-generic", .cra_flags = CRYPTO_ALG_TYPE_DIGEST, - .cra_blocksize = SHA1_HMAC_BLOCK_SIZE, + .cra_blocksize = SHA1_BLOCK_SIZE, .cra_ctxsize = sizeof(struct sha1_ctx), .cra_module = THIS_MODULE, .cra_alignmask = 3, diff --git a/crypto/sha256_generic.c b/crypto/sha256_generic.c index 74bf2f95f4e..5f4332edcf6 100644 --- a/crypto/sha256_generic.c +++ b/crypto/sha256_generic.c @@ -21,12 +21,10 @@ #include #include #include +#include #include #include -#define SHA256_DIGEST_SIZE 32 -#define SHA256_HMAC_BLOCK_SIZE 64 - struct sha256_ctx { u32 count[2]; u32 state[8]; @@ -48,15 +46,6 @@ static inline u32 Maj(u32 x, u32 y, u32 z) #define s0(x) (ror32(x, 7) ^ ror32(x,18) ^ (x >> 3)) #define s1(x) (ror32(x,17) ^ ror32(x,19) ^ (x >> 10)) -#define H0 0x6a09e667 -#define H1 0xbb67ae85 -#define H2 0x3c6ef372 -#define H3 0xa54ff53a -#define H4 0x510e527f -#define H5 0x9b05688c -#define H6 0x1f83d9ab -#define H7 0x5be0cd19 - static inline void LOAD_OP(int I, u32 *W, const u8 *input) { W[I] = __be32_to_cpu( ((__be32*)(input))[I] ); @@ -233,14 +222,14 @@ static void sha256_transform(u32 *state, const u8 *input) static void sha256_init(struct crypto_tfm *tfm) { struct sha256_ctx *sctx = crypto_tfm_ctx(tfm); - sctx->state[0] = H0; - sctx->state[1] = H1; - sctx->state[2] = H2; - sctx->state[3] = H3; - sctx->state[4] = H4; - sctx->state[5] = H5; - sctx->state[6] = H6; - sctx->state[7] = H7; + sctx->state[0] = SHA256_H0; + sctx->state[1] = SHA256_H1; + sctx->state[2] = SHA256_H2; + sctx->state[3] = SHA256_H3; + sctx->state[4] = SHA256_H4; + sctx->state[5] = SHA256_H5; + sctx->state[6] = SHA256_H6; + sctx->state[7] = SHA256_H7; sctx->count[0] = sctx->count[1] = 0; } @@ -311,7 +300,7 @@ static struct crypto_alg alg = { .cra_name = "sha256", .cra_driver_name= "sha256-generic", .cra_flags = CRYPTO_ALG_TYPE_DIGEST, - .cra_blocksize = SHA256_HMAC_BLOCK_SIZE, + .cra_blocksize = SHA256_BLOCK_SIZE, .cra_ctxsize = sizeof(struct sha256_ctx), .cra_module = THIS_MODULE, .cra_alignmask = 3, diff --git a/crypto/sha512.c b/crypto/sha512.c index 15eab9db9be..e736596ca57 100644 --- a/crypto/sha512.c +++ b/crypto/sha512.c @@ -13,20 +13,15 @@ #include #include - #include #include #include #include +#include #include #include -#define SHA384_DIGEST_SIZE 48 -#define SHA512_DIGEST_SIZE 64 -#define SHA384_HMAC_BLOCK_SIZE 128 -#define SHA512_HMAC_BLOCK_SIZE 128 - struct sha512_ctx { u64 state[8]; u32 count[4]; @@ -84,26 +79,6 @@ static const u64 sha512_K[80] = { #define s0(x) (RORu64(x, 1) ^ RORu64(x, 8) ^ (x >> 7)) #define s1(x) (RORu64(x,19) ^ RORu64(x,61) ^ (x >> 6)) -/* H* initial state for SHA-512 */ -#define H0 0x6a09e667f3bcc908ULL -#define H1 0xbb67ae8584caa73bULL -#define H2 0x3c6ef372fe94f82bULL -#define H3 0xa54ff53a5f1d36f1ULL -#define H4 0x510e527fade682d1ULL -#define H5 0x9b05688c2b3e6c1fULL -#define H6 0x1f83d9abfb41bd6bULL -#define H7 0x5be0cd19137e2179ULL - -/* H'* initial state for SHA-384 */ -#define HP0 0xcbbb9d5dc1059ed8ULL -#define HP1 0x629a292a367cd507ULL -#define HP2 0x9159015a3070dd17ULL -#define HP3 0x152fecd8f70e5939ULL -#define HP4 0x67332667ffc00b31ULL -#define HP5 0x8eb44a8768581511ULL -#define HP6 0xdb0c2e0d64f98fa7ULL -#define HP7 0x47b5481dbefa4fa4ULL - static inline void LOAD_OP(int I, u64 *W, const u8 *input) { W[I] = __be64_to_cpu( ((__be64*)(input))[I] ); @@ -164,14 +139,14 @@ static void sha512_init(struct crypto_tfm *tfm) { struct sha512_ctx *sctx = crypto_tfm_ctx(tfm); - sctx->state[0] = H0; - sctx->state[1] = H1; - sctx->state[2] = H2; - sctx->state[3] = H3; - sctx->state[4] = H4; - sctx->state[5] = H5; - sctx->state[6] = H6; - sctx->state[7] = H7; + sctx->state[0] = SHA512_H0; + sctx->state[1] = SHA512_H1; + sctx->state[2] = SHA512_H2; + sctx->state[3] = SHA512_H3; + sctx->state[4] = SHA512_H4; + sctx->state[5] = SHA512_H5; + sctx->state[6] = SHA512_H6; + sctx->state[7] = SHA512_H7; sctx->count[0] = sctx->count[1] = sctx->count[2] = sctx->count[3] = 0; } @@ -179,14 +154,14 @@ static void sha384_init(struct crypto_tfm *tfm) { struct sha512_ctx *sctx = crypto_tfm_ctx(tfm); - sctx->state[0] = HP0; - sctx->state[1] = HP1; - sctx->state[2] = HP2; - sctx->state[3] = HP3; - sctx->state[4] = HP4; - sctx->state[5] = HP5; - sctx->state[6] = HP6; - sctx->state[7] = HP7; + sctx->state[0] = SHA384_H0; + sctx->state[1] = SHA384_H1; + sctx->state[2] = SHA384_H2; + sctx->state[3] = SHA384_H3; + sctx->state[4] = SHA384_H4; + sctx->state[5] = SHA384_H5; + sctx->state[6] = SHA384_H6; + sctx->state[7] = SHA384_H7; sctx->count[0] = sctx->count[1] = sctx->count[2] = sctx->count[3] = 0; } @@ -275,7 +250,7 @@ static void sha384_final(struct crypto_tfm *tfm, u8 *hash) static struct crypto_alg sha512 = { .cra_name = "sha512", .cra_flags = CRYPTO_ALG_TYPE_DIGEST, - .cra_blocksize = SHA512_HMAC_BLOCK_SIZE, + .cra_blocksize = SHA512_BLOCK_SIZE, .cra_ctxsize = sizeof(struct sha512_ctx), .cra_module = THIS_MODULE, .cra_alignmask = 3, @@ -291,7 +266,7 @@ static struct crypto_alg sha512 = { static struct crypto_alg sha384 = { .cra_name = "sha384", .cra_flags = CRYPTO_ALG_TYPE_DIGEST, - .cra_blocksize = SHA384_HMAC_BLOCK_SIZE, + .cra_blocksize = SHA384_BLOCK_SIZE, .cra_ctxsize = sizeof(struct sha512_ctx), .cra_alignmask = 3, .cra_module = THIS_MODULE, diff --git a/drivers/crypto/padlock-sha.c b/drivers/crypto/padlock-sha.c index f3857bbbfae..4e8de162fc1 100644 --- a/drivers/crypto/padlock-sha.c +++ b/drivers/crypto/padlock-sha.c @@ -13,6 +13,7 @@ */ #include +#include #include #include #include @@ -24,12 +25,7 @@ #include "padlock.h" #define SHA1_DEFAULT_FALLBACK "sha1-generic" -#define SHA1_DIGEST_SIZE 20 -#define SHA1_HMAC_BLOCK_SIZE 64 - #define SHA256_DEFAULT_FALLBACK "sha256-generic" -#define SHA256_DIGEST_SIZE 32 -#define SHA256_HMAC_BLOCK_SIZE 64 struct padlock_sha_ctx { char *data; @@ -107,11 +103,11 @@ static void padlock_do_sha1(const char *in, char *out, int count) char buf[128+16]; char *result = NEAREST_ALIGNED(buf); - ((uint32_t *)result)[0] = 0x67452301; - ((uint32_t *)result)[1] = 0xEFCDAB89; - ((uint32_t *)result)[2] = 0x98BADCFE; - ((uint32_t *)result)[3] = 0x10325476; - ((uint32_t *)result)[4] = 0xC3D2E1F0; + ((uint32_t *)result)[0] = SHA1_H0; + ((uint32_t *)result)[1] = SHA1_H1; + ((uint32_t *)result)[2] = SHA1_H2; + ((uint32_t *)result)[3] = SHA1_H3; + ((uint32_t *)result)[4] = SHA1_H4; asm volatile (".byte 0xf3,0x0f,0xa6,0xc8" /* rep xsha1 */ : "+S"(in), "+D"(result) @@ -128,14 +124,14 @@ static void padlock_do_sha256(const char *in, char *out, int count) char buf[128+16]; char *result = NEAREST_ALIGNED(buf); - ((uint32_t *)result)[0] = 0x6A09E667; - ((uint32_t *)result)[1] = 0xBB67AE85; - ((uint32_t *)result)[2] = 0x3C6EF372; - ((uint32_t *)result)[3] = 0xA54FF53A; - ((uint32_t *)result)[4] = 0x510E527F; - ((uint32_t *)result)[5] = 0x9B05688C; - ((uint32_t *)result)[6] = 0x1F83D9AB; - ((uint32_t *)result)[7] = 0x5BE0CD19; + ((uint32_t *)result)[0] = SHA256_H0; + ((uint32_t *)result)[1] = SHA256_H1; + ((uint32_t *)result)[2] = SHA256_H2; + ((uint32_t *)result)[3] = SHA256_H3; + ((uint32_t *)result)[4] = SHA256_H4; + ((uint32_t *)result)[5] = SHA256_H5; + ((uint32_t *)result)[6] = SHA256_H6; + ((uint32_t *)result)[7] = SHA256_H7; asm volatile (".byte 0xf3,0x0f,0xa6,0xd0" /* rep xsha256 */ : "+S"(in), "+D"(result) @@ -215,7 +211,7 @@ static struct crypto_alg sha1_alg = { .cra_priority = PADLOCK_CRA_PRIORITY, .cra_flags = CRYPTO_ALG_TYPE_DIGEST | CRYPTO_ALG_NEED_FALLBACK, - .cra_blocksize = SHA1_HMAC_BLOCK_SIZE, + .cra_blocksize = SHA1_BLOCK_SIZE, .cra_ctxsize = sizeof(struct padlock_sha_ctx), .cra_module = THIS_MODULE, .cra_list = LIST_HEAD_INIT(sha1_alg.cra_list), @@ -237,7 +233,7 @@ static struct crypto_alg sha256_alg = { .cra_priority = PADLOCK_CRA_PRIORITY, .cra_flags = CRYPTO_ALG_TYPE_DIGEST | CRYPTO_ALG_NEED_FALLBACK, - .cra_blocksize = SHA256_HMAC_BLOCK_SIZE, + .cra_blocksize = SHA256_BLOCK_SIZE, .cra_ctxsize = sizeof(struct padlock_sha_ctx), .cra_module = THIS_MODULE, .cra_list = LIST_HEAD_INIT(sha256_alg.cra_list), diff --git a/include/crypto/sha.h b/include/crypto/sha.h new file mode 100644 index 00000000000..0686e1f7a24 --- /dev/null +++ b/include/crypto/sha.h @@ -0,0 +1,53 @@ +/* + * Common values for SHA algorithms + */ + +#ifndef _CRYPTO_SHA_H +#define _CRYPTO_SHA_H + +#define SHA1_DIGEST_SIZE 20 +#define SHA1_BLOCK_SIZE 64 + +#define SHA256_DIGEST_SIZE 32 +#define SHA256_BLOCK_SIZE 64 + +#define SHA384_DIGEST_SIZE 48 +#define SHA384_BLOCK_SIZE 128 + +#define SHA512_DIGEST_SIZE 64 +#define SHA512_BLOCK_SIZE 128 + +#define SHA1_H0 0x67452301UL +#define SHA1_H1 0xefcdab89UL +#define SHA1_H2 0x98badcfeUL +#define SHA1_H3 0x10325476UL +#define SHA1_H4 0xc3d2e1f0UL + +#define SHA256_H0 0x6a09e667UL +#define SHA256_H1 0xbb67ae85UL +#define SHA256_H2 0x3c6ef372UL +#define SHA256_H3 0xa54ff53aUL +#define SHA256_H4 0x510e527fUL +#define SHA256_H5 0x9b05688cUL +#define SHA256_H6 0x1f83d9abUL +#define SHA256_H7 0x5be0cd19UL + +#define SHA384_H0 0xcbbb9d5dc1059ed8ULL +#define SHA384_H1 0x629a292a367cd507ULL +#define SHA384_H2 0x9159015a3070dd17ULL +#define SHA384_H3 0x152fecd8f70e5939ULL +#define SHA384_H4 0x67332667ffc00b31ULL +#define SHA384_H5 0x8eb44a8768581511ULL +#define SHA384_H6 0xdb0c2e0d64f98fa7ULL +#define SHA384_H7 0x47b5481dbefa4fa4ULL + +#define SHA512_H0 0x6a09e667f3bcc908ULL +#define SHA512_H1 0xbb67ae8584caa73bULL +#define SHA512_H2 0x3c6ef372fe94f82bULL +#define SHA512_H3 0xa54ff53a5f1d36f1ULL +#define SHA512_H4 0x510e527fade682d1ULL +#define SHA512_H5 0x9b05688c2b3e6c1fULL +#define SHA512_H6 0x1f83d9abfb41bd6bULL +#define SHA512_H7 0x5be0cd19137e2179ULL + +#endif -- cgit v1.2.3-70-g09d2 From 489310a440e606512b1fd79d8562d1da6b715448 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Wed, 10 Oct 2007 16:16:31 -0700 Subject: [BNX2]: Fix remote PHY media detection problems. The remote PHY media type and link status can change between ->probe() and ->open(). For correct operation, we need to get the new status again during ->open(). The ethtool link test and loopback test are also fixed to work with remote PHY. PHY loopback is simply skipped when remote PHY is present. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 0e4928c751f..21493e0cbd4 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -3776,12 +3776,6 @@ bnx2_init_remote_phy(struct bnx2 *bp) return; if (val & BNX2_FW_CAP_REMOTE_PHY_CAPABLE) { - if (netif_running(bp->dev)) { - val = BNX2_DRV_ACK_CAP_SIGNATURE | - BNX2_FW_CAP_REMOTE_PHY_CAPABLE; - REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_ACK_CAP_MB, - val); - } bp->phy_flags |= REMOTE_PHY_CAP_FLAG; val = REG_RD_IND(bp, bp->shmem_base + BNX2_LINK_STATUS); @@ -3789,6 +3783,22 @@ bnx2_init_remote_phy(struct bnx2 *bp) bp->phy_port = PORT_FIBRE; else bp->phy_port = PORT_TP; + + if (netif_running(bp->dev)) { + u32 sig; + + if (val & BNX2_LINK_STATUS_LINK_UP) { + bp->link_up = 1; + netif_carrier_on(bp->dev); + } else { + bp->link_up = 0; + netif_carrier_off(bp->dev); + } + sig = BNX2_DRV_ACK_CAP_SIGNATURE | + BNX2_FW_CAP_REMOTE_PHY_CAPABLE; + REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_ACK_CAP_MB, + sig); + } } } @@ -3797,6 +3807,7 @@ bnx2_reset_chip(struct bnx2 *bp, u32 reset_code) { u32 val; int i, rc = 0; + u8 old_port; /* Wait for the current PCI transaction to complete before * issuing a reset. */ @@ -3875,8 +3886,9 @@ bnx2_reset_chip(struct bnx2 *bp, u32 reset_code) return rc; spin_lock_bh(&bp->phy_lock); + old_port = bp->phy_port; bnx2_init_remote_phy(bp); - if (bp->phy_flags & REMOTE_PHY_CAP_FLAG) + if ((bp->phy_flags & REMOTE_PHY_CAP_FLAG) && old_port != bp->phy_port) bnx2_set_default_remote_link(bp); spin_unlock_bh(&bp->phy_lock); @@ -4565,6 +4577,9 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode) bnx2_set_mac_loopback(bp); } else if (loopback_mode == BNX2_PHY_LOOPBACK) { + if (bp->phy_flags & REMOTE_PHY_CAP_FLAG) + return 0; + bp->loopback = PHY_LOOPBACK; bnx2_set_phy_loopback(bp); } @@ -4733,6 +4748,11 @@ bnx2_test_link(struct bnx2 *bp) { u32 bmsr; + if (bp->phy_flags & REMOTE_PHY_CAP_FLAG) { + if (bp->link_up) + return 0; + return -ENODEV; + } spin_lock_bh(&bp->phy_lock); bnx2_enable_bmsr1(bp); bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr); -- cgit v1.2.3-70-g09d2 From 846f5c622fe033520c775cc2c40c06f3e2adea85 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Wed, 10 Oct 2007 16:16:51 -0700 Subject: [BNX2]: Fix default WoL setting. Change the default WoL setting to match the NVRAM's setting. It always defaulted to WoL disabled before and caused a lot of confusion for users. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 20 ++++++++++++++------ drivers/net/bnx2.h | 1 + 2 files changed, 15 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 21493e0cbd4..574d043cdfc 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -6569,8 +6569,11 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) if (i != 2) bp->fw_version[j++] = '.'; } - if (REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_FEATURE) & - BNX2_PORT_FEATURE_ASF_ENABLED) { + reg = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_FEATURE); + if (reg & BNX2_PORT_FEATURE_WOL_ENABLED) + bp->wol = 1; + + if (reg & BNX2_PORT_FEATURE_ASF_ENABLED) { bp->flags |= ASF_ENABLE_FLAG; for (i = 0; i < 30; i++) { @@ -6640,11 +6643,14 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) bp->phy_port = PORT_TP; if (bp->phy_flags & PHY_SERDES_FLAG) { bp->phy_port = PORT_FIBRE; - bp->flags |= NO_WOL_FLAG; + reg = REG_RD_IND(bp, bp->shmem_base + + BNX2_SHARED_HW_CFG_CONFIG); + if (!(reg & BNX2_SHARED_HW_CFG_GIG_LINK_ON_VAUX)) { + bp->flags |= NO_WOL_FLAG; + bp->wol = 0; + } if (CHIP_NUM(bp) != CHIP_NUM_5706) { bp->phy_addr = 2; - reg = REG_RD_IND(bp, bp->shmem_base + - BNX2_SHARED_HW_CFG_CONFIG); if (reg & BNX2_SHARED_HW_CFG_PHY_2_5G) bp->phy_flags |= PHY_2_5G_CAPABLE_FLAG; } @@ -6659,8 +6665,10 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) if ((CHIP_ID(bp) == CHIP_ID_5708_A0) || (CHIP_ID(bp) == CHIP_ID_5708_B0) || - (CHIP_ID(bp) == CHIP_ID_5708_B1)) + (CHIP_ID(bp) == CHIP_ID_5708_B1)) { bp->flags |= NO_WOL_FLAG; + bp->wol = 0; + } if (CHIP_ID(bp) == CHIP_ID_5706_A0) { bp->tx_quick_cons_trip_int = diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h index 56c190fc6de..1dce0d1a258 100644 --- a/drivers/net/bnx2.h +++ b/drivers/net/bnx2.h @@ -6908,6 +6908,7 @@ struct fw_info { #define BNX2_SHARED_HW_CFG_LED_MODE_MAC 0 #define BNX2_SHARED_HW_CFG_LED_MODE_GPHY1 0x100 #define BNX2_SHARED_HW_CFG_LED_MODE_GPHY2 0x200 +#define BNX2_SHARED_HW_CFG_GIG_LINK_ON_VAUX 0x8000 #define BNX2_SHARED_HW_CFG_CONFIG2 0x00000040 #define BNX2_SHARED_HW_CFG2_NVM_SIZE_MASK 0x00fff000 -- cgit v1.2.3-70-g09d2 From 32d1316b91424423d7b44944f18cdaca268f3db2 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Wed, 10 Oct 2007 16:17:11 -0700 Subject: [BNX2]: Update version to 1.6.7. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 574d043cdfc..bbfbdafb4ae 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -56,8 +56,8 @@ #define DRV_MODULE_NAME "bnx2" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "1.6.6" -#define DRV_MODULE_RELDATE "October 2, 2007" +#define DRV_MODULE_VERSION "1.6.7" +#define DRV_MODULE_RELDATE "October 10, 2007" #define RUN_AT(x) (jiffies + (x)) -- cgit v1.2.3-70-g09d2 From 227b60f5102cda4e4ab792b526a59c8cb20cd9f8 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 10 Oct 2007 17:30:46 -0700 Subject: [INET]: local port range robustness Expansion of original idea from Denis V. Lunev Add robustness and locking to the local_port_range sysctl. 1. Enforce that low < high when setting. 2. Use seqlock to ensure atomic update. The locking might seem like overkill, but there are cases where sysadmin might want to change value in the middle of a DoS attack. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/infiniband/core/cma.c | 22 ++++++------ include/net/ip.h | 3 +- net/ipv4/inet_connection_sock.c | 22 +++++++++--- net/ipv4/inet_hashtables.c | 13 ++++--- net/ipv4/sysctl_net_ipv4.c | 75 ++++++++++++++++++++++++++++++++++++++--- net/ipv4/tcp_ipv4.c | 1 - net/ipv4/udp.c | 6 ++-- net/ipv6/inet6_hashtables.c | 12 +++---- net/sctp/socket.c | 11 +++--- security/selinux/hooks.c | 39 +++++++++++---------- 10 files changed, 146 insertions(+), 58 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 9ffb9987450..2e641b255db 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -1866,13 +1866,14 @@ err1: static int cma_alloc_any_port(struct idr *ps, struct rdma_id_private *id_priv) { struct rdma_bind_list *bind_list; - int port, ret; + int port, ret, low, high; bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL); if (!bind_list) return -ENOMEM; retry: + /* FIXME: add proper port randomization per like inet_csk_get_port */ do { ret = idr_get_new_above(ps, bind_list, next_port, &port); } while ((ret == -EAGAIN) && idr_pre_get(ps, GFP_KERNEL)); @@ -1880,18 +1881,19 @@ retry: if (ret) goto err1; - if (port > sysctl_local_port_range[1]) { - if (next_port != sysctl_local_port_range[0]) { + inet_get_local_port_range(&low, &high); + if (port > high) { + if (next_port != low) { idr_remove(ps, port); - next_port = sysctl_local_port_range[0]; + next_port = low; goto retry; } ret = -EADDRNOTAVAIL; goto err2; } - if (port == sysctl_local_port_range[1]) - next_port = sysctl_local_port_range[0]; + if (port == high) + next_port = low; else next_port = port + 1; @@ -2769,12 +2771,12 @@ static void cma_remove_one(struct ib_device *device) static int cma_init(void) { - int ret; + int ret, low, high; get_random_bytes(&next_port, sizeof next_port); - next_port = ((unsigned int) next_port % - (sysctl_local_port_range[1] - sysctl_local_port_range[0])) + - sysctl_local_port_range[0]; + inet_get_local_port_range(&low, &high); + next_port = ((unsigned int) next_port % (high - low)) + low; + cma_wq = create_singlethread_workqueue("rdma_cm"); if (!cma_wq) return -ENOMEM; diff --git a/include/net/ip.h b/include/net/ip.h index abf2820a112..3af3ed9d320 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -171,7 +171,8 @@ extern unsigned long snmp_fold_field(void *mib[], int offt); extern int snmp_mib_init(void *ptr[2], size_t mibsize, size_t mibalign); extern void snmp_mib_free(void *ptr[2]); -extern int sysctl_local_port_range[2]; +extern void inet_get_local_port_range(int *low, int *high); + extern int sysctl_ip_default_ttl; extern int sysctl_ip_nonlocal_bind; diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index fbe7714f21d..3cef12835c4 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -33,6 +33,19 @@ EXPORT_SYMBOL(inet_csk_timer_bug_msg); * This array holds the first and last local port number. */ int sysctl_local_port_range[2] = { 32768, 61000 }; +DEFINE_SEQLOCK(sysctl_port_range_lock); + +void inet_get_local_port_range(int *low, int *high) +{ + unsigned seq; + do { + seq = read_seqbegin(&sysctl_port_range_lock); + + *low = sysctl_local_port_range[0]; + *high = sysctl_local_port_range[1]; + } while (read_seqretry(&sysctl_port_range_lock, seq)); +} +EXPORT_SYMBOL(inet_get_local_port_range); int inet_csk_bind_conflict(const struct sock *sk, const struct inet_bind_bucket *tb) @@ -77,10 +90,11 @@ int inet_csk_get_port(struct inet_hashinfo *hashinfo, local_bh_disable(); if (!snum) { - int low = sysctl_local_port_range[0]; - int high = sysctl_local_port_range[1]; - int remaining = (high - low) + 1; - int rover = net_random() % (high - low) + low; + int remaining, rover, low, high; + + inet_get_local_port_range(&low, &high); + remaining = high - low; + rover = net_random() % remaining + low; do { head = &hashinfo->bhash[inet_bhashfn(rover, hashinfo->bhash_size)]; diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c index fb662621c54..fac6398e436 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c @@ -279,19 +279,18 @@ int inet_hash_connect(struct inet_timewait_death_row *death_row, int ret; if (!snum) { - int low = sysctl_local_port_range[0]; - int high = sysctl_local_port_range[1]; - int range = high - low; - int i; - int port; + int i, remaining, low, high, port; static u32 hint; u32 offset = hint + inet_sk_port_offset(sk); struct hlist_node *node; struct inet_timewait_sock *tw = NULL; + inet_get_local_port_range(&low, &high); + remaining = high - low; + local_bh_disable(); - for (i = 1; i <= range; i++) { - port = low + (i + offset) % range; + for (i = 1; i <= remaining; i++) { + port = low + (i + offset) % remaining; head = &hinfo->bhash[inet_bhashfn(port, hinfo->bhash_size)]; spin_lock(&head->lock); diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 53ef0f4bbda..eb286abcf5d 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -89,6 +90,74 @@ static int ipv4_sysctl_forward_strategy(ctl_table *table, return 1; } +extern seqlock_t sysctl_port_range_lock; +extern int sysctl_local_port_range[2]; + +/* Update system visible IP port range */ +static void set_local_port_range(int range[2]) +{ + write_seqlock(&sysctl_port_range_lock); + sysctl_local_port_range[0] = range[0]; + sysctl_local_port_range[1] = range[1]; + write_sequnlock(&sysctl_port_range_lock); +} + +/* Validate changes from /proc interface. */ +static int ipv4_local_port_range(ctl_table *table, int write, struct file *filp, + void __user *buffer, + size_t *lenp, loff_t *ppos) +{ + int ret; + int range[2] = { sysctl_local_port_range[0], + sysctl_local_port_range[1] }; + ctl_table tmp = { + .data = &range, + .maxlen = sizeof(range), + .mode = table->mode, + .extra1 = &ip_local_port_range_min, + .extra2 = &ip_local_port_range_max, + }; + + ret = proc_dointvec_minmax(&tmp, write, filp, buffer, lenp, ppos); + + if (write && ret == 0) { + if (range[1] <= range[0]) + ret = -EINVAL; + else + set_local_port_range(range); + } + + return ret; +} + +/* Validate changes from sysctl interface. */ +static int ipv4_sysctl_local_port_range(ctl_table *table, int __user *name, + int nlen, void __user *oldval, + size_t __user *oldlenp, + void __user *newval, size_t newlen) +{ + int ret; + int range[2] = { sysctl_local_port_range[0], + sysctl_local_port_range[1] }; + ctl_table tmp = { + .data = &range, + .maxlen = sizeof(range), + .mode = table->mode, + .extra1 = &ip_local_port_range_min, + .extra2 = &ip_local_port_range_max, + }; + + ret = sysctl_intvec(&tmp, name, nlen, oldval, oldlenp, newval, newlen); + if (ret == 0 && newval && newlen) { + if (range[1] <= range[0]) + ret = -EINVAL; + else + set_local_port_range(range); + } + return ret; +} + + static int proc_tcp_congestion_control(ctl_table *ctl, int write, struct file * filp, void __user *buffer, size_t *lenp, loff_t *ppos) { @@ -427,10 +496,8 @@ ctl_table ipv4_table[] = { .data = &sysctl_local_port_range, .maxlen = sizeof(sysctl_local_port_range), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, - .extra1 = ip_local_port_range_min, - .extra2 = ip_local_port_range_max + .proc_handler = &ipv4_local_port_range, + .strategy = &ipv4_sysctl_local_port_range, }, { .ctl_name = NET_IPV4_ICMP_ECHO_IGNORE_ALL, diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 8855e640e95..38cf73a5673 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -2470,6 +2470,5 @@ EXPORT_SYMBOL(tcp_v4_syn_recv_sock); EXPORT_SYMBOL(tcp_proc_register); EXPORT_SYMBOL(tcp_proc_unregister); #endif -EXPORT_SYMBOL(sysctl_local_port_range); EXPORT_SYMBOL(sysctl_tcp_low_latency); diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index ef4d901ee9a..cb9fc58efb2 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -147,11 +147,11 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum, write_lock_bh(&udp_hash_lock); if (!snum) { - int i; - int low = sysctl_local_port_range[0]; - int high = sysctl_local_port_range[1]; + int i, low, high; unsigned rover, best, best_size_so_far; + inet_get_local_port_range(&low, &high); + best_size_so_far = UINT_MAX; best = rover = net_random() % (high - low) + low; diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c index ae6b0e7eb48..1c2c2765543 100644 --- a/net/ipv6/inet6_hashtables.c +++ b/net/ipv6/inet6_hashtables.c @@ -254,18 +254,18 @@ int inet6_hash_connect(struct inet_timewait_death_row *death_row, int ret; if (snum == 0) { - const int low = sysctl_local_port_range[0]; - const int high = sysctl_local_port_range[1]; - const int range = high - low; - int i, port; + int i, port, low, high, remaining; static u32 hint; const u32 offset = hint + inet6_sk_port_offset(sk); struct hlist_node *node; struct inet_timewait_sock *tw = NULL; + inet_get_local_port_range(&low, &high); + remaining = high - low; + local_bh_disable(); - for (i = 1; i <= range; i++) { - port = low + (i + offset) % range; + for (i = 1; i <= remaining; i++) { + port = low + (i + offset) % remaining; head = &hinfo->bhash[inet_bhashfn(port, hinfo->bhash_size)]; spin_lock(&head->lock); diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 7cd58ef84ed..9c6a4b5f626 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -5315,11 +5315,12 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr) if (snum == 0) { /* Search for an available port. */ - unsigned int low = sysctl_local_port_range[0]; - unsigned int high = sysctl_local_port_range[1]; - unsigned int remaining = (high - low) + 1; - unsigned int rover = net_random() % remaining + low; - int index; + int low, high, remaining, index; + unsigned int rover; + + inet_get_local_port_range(&low, &high); + remaining = (high - low) + 1; + rover = net_random() % remaining + low; do { rover++; diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 0753b20e23f..3c3fff33d1c 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -47,7 +47,7 @@ #include #include #include -#include /* for sysctl_local_port_range[] */ +#include /* for local_port_range[] */ #include /* struct or_callable used in sock_rcv_skb */ #include #include @@ -3232,8 +3232,6 @@ static int selinux_socket_post_create(struct socket *sock, int family, /* Range of port numbers used to automatically bind. Need to determine whether we should perform a name_bind permission check between the socket and the port number. */ -#define ip_local_port_range_0 sysctl_local_port_range[0] -#define ip_local_port_range_1 sysctl_local_port_range[1] static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen) { @@ -3276,20 +3274,27 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in addrp = (char *)&addr6->sin6_addr.s6_addr; } - if (snum&&(snum < max(PROT_SOCK,ip_local_port_range_0) || - snum > ip_local_port_range_1)) { - err = security_port_sid(sk->sk_family, sk->sk_type, - sk->sk_protocol, snum, &sid); - if (err) - goto out; - AVC_AUDIT_DATA_INIT(&ad,NET); - ad.u.net.sport = htons(snum); - ad.u.net.family = family; - err = avc_has_perm(isec->sid, sid, - isec->sclass, - SOCKET__NAME_BIND, &ad); - if (err) - goto out; + if (snum) { + int low, high; + + inet_get_local_port_range(&low, &high); + + if (snum < max(PROT_SOCK, low) || snum > high) { + err = security_port_sid(sk->sk_family, + sk->sk_type, + sk->sk_protocol, snum, + &sid); + if (err) + goto out; + AVC_AUDIT_DATA_INIT(&ad,NET); + ad.u.net.sport = htons(snum); + ad.u.net.family = family; + err = avc_has_perm(isec->sid, sid, + isec->sclass, + SOCKET__NAME_BIND, &ad); + if (err) + goto out; + } } switch(isec->sclass) { -- cgit v1.2.3-70-g09d2 From 6b91fa02796292c322b20572188c74c1ef5bb02b Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Wed, 10 Oct 2007 18:01:09 -0700 Subject: [TG3]: Add new 5761 NVRAM decode routines This patch adds a new 5761-specific NVRAM strapping decode routine. Signed-off-by: Matt Carlson Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ drivers/net/tg3.h | 25 ++++++++++++++++-- 2 files changed, 102 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 1e0c9e0dc39..3200c9c5ff5 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -9581,6 +9581,81 @@ static void __devinit tg3_get_5787_nvram_info(struct tg3 *tp) } } +static void __devinit tg3_get_5761_nvram_info(struct tg3 *tp) +{ + u32 nvcfg1, protect = 0; + + nvcfg1 = tr32(NVRAM_CFG1); + + /* NVRAM protection for TPM */ + if (nvcfg1 & (1 << 27)) { + tp->tg3_flags2 |= TG3_FLG2_PROTECTED_NVRAM; + protect = 1; + } + + nvcfg1 &= NVRAM_CFG1_5752VENDOR_MASK; + switch (nvcfg1) { + case FLASH_5761VENDOR_ATMEL_ADB021D: + case FLASH_5761VENDOR_ATMEL_ADB041D: + case FLASH_5761VENDOR_ATMEL_ADB081D: + case FLASH_5761VENDOR_ATMEL_ADB161D: + case FLASH_5761VENDOR_ATMEL_MDB021D: + case FLASH_5761VENDOR_ATMEL_MDB041D: + case FLASH_5761VENDOR_ATMEL_MDB081D: + case FLASH_5761VENDOR_ATMEL_MDB161D: + tp->nvram_jedecnum = JEDEC_ATMEL; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tp->tg3_flags2 |= TG3_FLG2_FLASH; + tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS; + tp->nvram_pagesize = 256; + break; + case FLASH_5761VENDOR_ST_A_M45PE20: + case FLASH_5761VENDOR_ST_A_M45PE40: + case FLASH_5761VENDOR_ST_A_M45PE80: + case FLASH_5761VENDOR_ST_A_M45PE16: + case FLASH_5761VENDOR_ST_M_M45PE20: + case FLASH_5761VENDOR_ST_M_M45PE40: + case FLASH_5761VENDOR_ST_M_M45PE80: + case FLASH_5761VENDOR_ST_M_M45PE16: + tp->nvram_jedecnum = JEDEC_ST; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tp->tg3_flags2 |= TG3_FLG2_FLASH; + tp->nvram_pagesize = 256; + break; + } + + if (protect) { + tp->nvram_size = tr32(NVRAM_ADDR_LOCKOUT); + } else { + switch (nvcfg1) { + case FLASH_5761VENDOR_ATMEL_ADB161D: + case FLASH_5761VENDOR_ATMEL_MDB161D: + case FLASH_5761VENDOR_ST_A_M45PE16: + case FLASH_5761VENDOR_ST_M_M45PE16: + tp->nvram_size = 0x100000; + break; + case FLASH_5761VENDOR_ATMEL_ADB081D: + case FLASH_5761VENDOR_ATMEL_MDB081D: + case FLASH_5761VENDOR_ST_A_M45PE80: + case FLASH_5761VENDOR_ST_M_M45PE80: + tp->nvram_size = 0x80000; + break; + case FLASH_5761VENDOR_ATMEL_ADB041D: + case FLASH_5761VENDOR_ATMEL_MDB041D: + case FLASH_5761VENDOR_ST_A_M45PE40: + case FLASH_5761VENDOR_ST_M_M45PE40: + tp->nvram_size = 0x40000; + break; + case FLASH_5761VENDOR_ATMEL_ADB021D: + case FLASH_5761VENDOR_ATMEL_MDB021D: + case FLASH_5761VENDOR_ST_A_M45PE20: + case FLASH_5761VENDOR_ST_M_M45PE20: + tp->nvram_size = 0x20000; + break; + } + } +} + static void __devinit tg3_get_5906_nvram_info(struct tg3 *tp) { tp->nvram_jedecnum = JEDEC_ATMEL; @@ -9623,6 +9698,8 @@ static void __devinit tg3_nvram_init(struct tg3 *tp) else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784) tg3_get_5787_nvram_info(tp); + else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) + tg3_get_5761_nvram_info(tp); else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) tg3_get_5906_nvram_info(tp); else @@ -9700,6 +9777,7 @@ static u32 tg3_nvram_phys_addr(struct tg3 *tp, u32 addr) if ((tp->tg3_flags & TG3_FLAG_NVRAM) && (tp->tg3_flags & TG3_FLAG_NVRAM_BUFFERED) && (tp->tg3_flags2 & TG3_FLG2_FLASH) && + !(tp->tg3_flags3 & TG3_FLG3_NO_NVRAM_ADDR_TRANS) && (tp->nvram_jedecnum == JEDEC_ATMEL)) addr = ((addr / tp->nvram_pagesize) << @@ -9714,6 +9792,7 @@ static u32 tg3_nvram_logical_addr(struct tg3 *tp, u32 addr) if ((tp->tg3_flags & TG3_FLAG_NVRAM) && (tp->tg3_flags & TG3_FLAG_NVRAM_BUFFERED) && (tp->tg3_flags2 & TG3_FLG2_FLASH) && + !(tp->tg3_flags3 & TG3_FLG3_NO_NVRAM_ADDR_TRANS) && (tp->nvram_jedecnum == JEDEC_ATMEL)) addr = ((addr >> ATMEL_AT45DB0X1B_PAGE_POS) * diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index d8e829f6fcb..88d08f3ede0 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -124,6 +124,7 @@ #define ASIC_REV_5906 0x0c #define ASIC_REV_USE_PROD_ID_REG 0x0f #define ASIC_REV_5784 0x5784 +#define ASIC_REV_5761 0x5761 #define GET_CHIP_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 8) #define CHIPREV_5700_AX 0x70 #define CHIPREV_5700_BX 0x71 @@ -1463,6 +1464,22 @@ #define FLASH_5787VENDOR_ATMEL_EEPROM_376KHZ 0x03000002 #define FLASH_5787VENDOR_MICRO_EEPROM_64KHZ 0x03000000 #define FLASH_5787VENDOR_MICRO_EEPROM_376KHZ 0x02000000 +#define FLASH_5761VENDOR_ATMEL_MDB021D 0x00800003 +#define FLASH_5761VENDOR_ATMEL_MDB041D 0x00800000 +#define FLASH_5761VENDOR_ATMEL_MDB081D 0x00800002 +#define FLASH_5761VENDOR_ATMEL_MDB161D 0x00800001 +#define FLASH_5761VENDOR_ATMEL_ADB021D 0x00000003 +#define FLASH_5761VENDOR_ATMEL_ADB041D 0x00000000 +#define FLASH_5761VENDOR_ATMEL_ADB081D 0x00000002 +#define FLASH_5761VENDOR_ATMEL_ADB161D 0x00000001 +#define FLASH_5761VENDOR_ST_M_M45PE20 0x02800001 +#define FLASH_5761VENDOR_ST_M_M45PE40 0x02800000 +#define FLASH_5761VENDOR_ST_M_M45PE80 0x02800002 +#define FLASH_5761VENDOR_ST_M_M45PE16 0x02800003 +#define FLASH_5761VENDOR_ST_A_M45PE20 0x02000001 +#define FLASH_5761VENDOR_ST_A_M45PE40 0x02000000 +#define FLASH_5761VENDOR_ST_A_M45PE80 0x02000002 +#define FLASH_5761VENDOR_ST_A_M45PE16 0x02000003 #define NVRAM_CFG1_5752PAGE_SIZE_MASK 0x70000000 #define FLASH_5752PAGE_SIZE_256 0x00000000 #define FLASH_5752PAGE_SIZE_512 0x10000000 @@ -1493,9 +1510,11 @@ #define ACCESS_ENABLE 0x00000001 #define ACCESS_WR_ENABLE 0x00000002 #define NVRAM_WRITE1 0x00007028 -/* 0x702c --> 0x7400 unused */ +/* 0x702c unused */ + +#define NVRAM_ADDR_LOCKOUT 0x00007030 +/* 0x7034 --> 0x7c00 unused */ -/* 0x7400 --> 0x7c00 unused */ #define PCIE_TRANSACTION_CFG 0x00007c04 #define PCIE_TRANS_CFG_1SHOT_MSI 0x20000000 #define PCIE_TRANS_CFG_LOM 0x00000020 @@ -2269,6 +2288,8 @@ struct tg3 { #define TG3_FLG2_PHY_JITTER_BUG 0x20000000 #define TG3_FLG2_NO_FWARE_REPORTED 0x40000000 #define TG3_FLG2_PHY_ADJUST_TRIM 0x80000000 + u32 tg3_flags3; +#define TG3_FLG3_NO_NVRAM_ADDR_TRANS 0x00000001 struct timer_list timer; u16 timer_counter; -- cgit v1.2.3-70-g09d2 From 0d3031d9e674cddd4c09731123ad252294cdf15f Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Wed, 10 Oct 2007 18:02:43 -0700 Subject: [TG3]: Add 5761 APE support This patch adds support for the new APE block, present in 5761 chips. APE stands for Application Processing Engine. The primary function of the APE is to process manageability traffic, such as ASF. Signed-off-by: Matt Carlson Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 232 +++++++++++++++++++++++++++++++++++++++++++++++++++++- drivers/net/tg3.h | 46 +++++++++++ 2 files changed, 274 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 3200c9c5ff5..5b6c1b286e9 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -314,6 +314,16 @@ static u32 tg3_read32(struct tg3 *tp, u32 off) return (readl(tp->regs + off)); } +static void tg3_ape_write32(struct tg3 *tp, u32 off, u32 val) +{ + writel(val, tp->aperegs + off); +} + +static u32 tg3_ape_read32(struct tg3 *tp, u32 off) +{ + return (readl(tp->aperegs + off)); +} + static void tg3_write_indirect_reg32(struct tg3 *tp, u32 off, u32 val) { unsigned long flags; @@ -500,6 +510,73 @@ static void tg3_read_mem(struct tg3 *tp, u32 off, u32 *val) spin_unlock_irqrestore(&tp->indirect_lock, flags); } +static void tg3_ape_lock_init(struct tg3 *tp) +{ + int i; + + /* Make sure the driver hasn't any stale locks. */ + for (i = 0; i < 8; i++) + tg3_ape_write32(tp, TG3_APE_LOCK_GRANT + 4 * i, + APE_LOCK_GRANT_DRIVER); +} + +static int tg3_ape_lock(struct tg3 *tp, int locknum) +{ + int i, off; + int ret = 0; + u32 status; + + if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) + return 0; + + switch (locknum) { + case TG3_APE_LOCK_MEM: + break; + default: + return -EINVAL; + } + + off = 4 * locknum; + + tg3_ape_write32(tp, TG3_APE_LOCK_REQ + off, APE_LOCK_REQ_DRIVER); + + /* Wait for up to 1 millisecond to acquire lock. */ + for (i = 0; i < 100; i++) { + status = tg3_ape_read32(tp, TG3_APE_LOCK_GRANT + off); + if (status == APE_LOCK_GRANT_DRIVER) + break; + udelay(10); + } + + if (status != APE_LOCK_GRANT_DRIVER) { + /* Revoke the lock request. */ + tg3_ape_write32(tp, TG3_APE_LOCK_GRANT + off, + APE_LOCK_GRANT_DRIVER); + + ret = -EBUSY; + } + + return ret; +} + +static void tg3_ape_unlock(struct tg3 *tp, int locknum) +{ + int off; + + if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) + return; + + switch (locknum) { + case TG3_APE_LOCK_MEM: + break; + default: + return; + } + + off = 4 * locknum; + tg3_ape_write32(tp, TG3_APE_LOCK_GRANT + off, APE_LOCK_GRANT_DRIVER); +} + static void tg3_disable_ints(struct tg3 *tp) { tw32(TG3PCI_MISC_HOST_CTRL, @@ -1448,7 +1525,8 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) } if (!(tp->tg3_flags & TG3_FLAG_WOL_ENABLE) && - !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) + !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF) && + !(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) tg3_power_down_phy(tp); tg3_frob_aux_power(tp); @@ -4726,6 +4804,80 @@ static void tg3_disable_nvram_access(struct tg3 *tp) } } +static void tg3_ape_send_event(struct tg3 *tp, u32 event) +{ + int i; + u32 apedata; + + apedata = tg3_ape_read32(tp, TG3_APE_SEG_SIG); + if (apedata != APE_SEG_SIG_MAGIC) + return; + + apedata = tg3_ape_read32(tp, TG3_APE_FW_STATUS); + if (apedata != APE_FW_STATUS_READY) + return; + + /* Wait for up to 1 millisecond for APE to service previous event. */ + for (i = 0; i < 10; i++) { + if (tg3_ape_lock(tp, TG3_APE_LOCK_MEM)) + return; + + apedata = tg3_ape_read32(tp, TG3_APE_EVENT_STATUS); + + if (!(apedata & APE_EVENT_STATUS_EVENT_PENDING)) + tg3_ape_write32(tp, TG3_APE_EVENT_STATUS, + event | APE_EVENT_STATUS_EVENT_PENDING); + + tg3_ape_unlock(tp, TG3_APE_LOCK_MEM); + + if (!(apedata & APE_EVENT_STATUS_EVENT_PENDING)) + break; + + udelay(100); + } + + if (!(apedata & APE_EVENT_STATUS_EVENT_PENDING)) + tg3_ape_write32(tp, TG3_APE_EVENT, APE_EVENT_1); +} + +static void tg3_ape_driver_state_change(struct tg3 *tp, int kind) +{ + u32 event; + u32 apedata; + + if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) + return; + + switch (kind) { + case RESET_KIND_INIT: + tg3_ape_write32(tp, TG3_APE_HOST_SEG_SIG, + APE_HOST_SEG_SIG_MAGIC); + tg3_ape_write32(tp, TG3_APE_HOST_SEG_LEN, + APE_HOST_SEG_LEN_MAGIC); + apedata = tg3_ape_read32(tp, TG3_APE_HOST_INIT_COUNT); + tg3_ape_write32(tp, TG3_APE_HOST_INIT_COUNT, ++apedata); + tg3_ape_write32(tp, TG3_APE_HOST_DRIVER_ID, + APE_HOST_DRIVER_ID_MAGIC); + tg3_ape_write32(tp, TG3_APE_HOST_BEHAVIOR, + APE_HOST_BEHAV_NO_PHYLOCK); + + event = APE_EVENT_STATUS_STATE_START; + break; + case RESET_KIND_SHUTDOWN: + event = APE_EVENT_STATUS_STATE_UNLOAD; + break; + case RESET_KIND_SUSPEND: + event = APE_EVENT_STATUS_STATE_SUSPEND; + break; + default: + return; + } + + event |= APE_EVENT_STATUS_DRIVER_EVNT | APE_EVENT_STATUS_STATE_CHNGE; + + tg3_ape_send_event(tp, event); +} + /* tp->lock is held. */ static void tg3_write_sig_pre_reset(struct tg3 *tp, int kind) { @@ -4753,6 +4905,10 @@ static void tg3_write_sig_pre_reset(struct tg3 *tp, int kind) break; }; } + + if (kind == RESET_KIND_INIT || + kind == RESET_KIND_SUSPEND) + tg3_ape_driver_state_change(tp, kind); } /* tp->lock is held. */ @@ -4774,6 +4930,9 @@ static void tg3_write_sig_post_reset(struct tg3 *tp, int kind) break; }; } + + if (kind == RESET_KIND_SHUTDOWN) + tg3_ape_driver_state_change(tp, kind); } /* tp->lock is held. */ @@ -4864,6 +5023,10 @@ static void tg3_restore_pci_state(struct tg3 *tp) if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 && (tp->tg3_flags & TG3_FLAG_PCIX_MODE)) val |= PCISTATE_RETRY_SAME_DMA; + /* Allow reads and writes to the APE register and memory space. */ + if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) + val |= PCISTATE_ALLOW_APE_CTLSPC_WR | + PCISTATE_ALLOW_APE_SHMEM_WR; pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, val); pci_write_config_dword(tp->pdev, TG3PCI_COMMAND, tp->pci_cmd); @@ -5092,7 +5255,8 @@ static int tg3_chip_reset(struct tg3 *tp) /* tp->lock is held. */ static void tg3_stop_fw(struct tg3 *tp) { - if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) { + if ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) && + !(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) { u32 val; int i; @@ -6173,6 +6337,16 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32(TG3PCI_PCISTATE, val); } + if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) { + /* Allow reads and writes to the + * APE register and memory space. + */ + val = tr32(TG3PCI_PCISTATE); + val |= PCISTATE_ALLOW_APE_CTLSPC_WR | + PCISTATE_ALLOW_APE_SHMEM_WR; + tw32(TG3PCI_PCISTATE, val); + } + if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5704_BX) { /* Enable some hw fixes. */ val = tr32(TG3PCI_MSI_DATA); @@ -6780,6 +6954,10 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) break; }; + /* Write our heartbeat update interval to APE. */ + tg3_ape_write32(tp, TG3_APE_HOST_HEARTBEAT_INT_MS, + APE_HOST_HEARTBEAT_INT_DISABLE); + tg3_write_sig_post_reset(tp, RESET_KIND_INIT); return 0; @@ -10302,6 +10480,8 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) tp->tg3_flags2 |= TG3_FLG2_ASF_NEW_HANDSHAKE; } + if (nic_cfg & NIC_SRAM_DATA_CFG_APE_ENABLE) + tp->tg3_flags3 |= TG3_FLG3_ENABLE_APE; if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES && !(nic_cfg & NIC_SRAM_DATA_CFG_FIBER_WOL)) tp->tg3_flags &= ~TG3_FLAG_WOL_CAP; @@ -10334,7 +10514,8 @@ static int __devinit tg3_phy_probe(struct tg3 *tp) * firwmare access to the PHY hardware. */ err = 0; - if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) { + if ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) || + (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) { hw_phy_id = hw_phy_id_masked = PHY_ID_INVALID; } else { /* Now read the physical PHY_ID from the chip and verify @@ -10381,6 +10562,7 @@ static int __devinit tg3_phy_probe(struct tg3 *tp) } if (!(tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) && + !(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) && !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) { u32 bmsr, adv_reg, tg3_ctrl, mask; @@ -10972,6 +11154,16 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) */ tg3_get_eeprom_hw_cfg(tp); + if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) { + /* Allow reads and writes to the + * APE register and memory space. + */ + pci_state_reg |= PCISTATE_ALLOW_APE_CTLSPC_WR | + PCISTATE_ALLOW_APE_SHMEM_WR; + pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, + pci_state_reg); + } + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784) tp->tg3_flags |= TG3_FLAG_CPMU_PRESENT; @@ -12165,13 +12357,35 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, tg3_init_coal(tp); + if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) { + if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) { + printk(KERN_ERR PFX "Cannot find proper PCI device " + "base address for APE, aborting.\n"); + err = -ENODEV; + goto err_out_iounmap; + } + + tg3reg_base = pci_resource_start(pdev, 2); + tg3reg_len = pci_resource_len(pdev, 2); + + tp->aperegs = ioremap_nocache(tg3reg_base, tg3reg_len); + if (tp->aperegs == 0UL) { + printk(KERN_ERR PFX "Cannot map APE registers, " + "aborting.\n"); + err = -ENOMEM; + goto err_out_iounmap; + } + + tg3_ape_lock_init(tp); + } + pci_set_drvdata(pdev, dev); err = register_netdev(dev); if (err) { printk(KERN_ERR PFX "Cannot register net device, " "aborting.\n"); - goto err_out_iounmap; + goto err_out_apeunmap; } printk(KERN_INFO "%s: Tigon3 [partno(%s) rev %04x PHY(%s)] (%s) %s Ethernet ", @@ -12204,6 +12418,12 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, return 0; +err_out_apeunmap: + if (tp->aperegs) { + iounmap(tp->aperegs); + tp->aperegs = NULL; + } + err_out_iounmap: if (tp->regs) { iounmap(tp->regs); @@ -12231,6 +12451,10 @@ static void __devexit tg3_remove_one(struct pci_dev *pdev) flush_scheduled_work(); unregister_netdev(dev); + if (tp->aperegs) { + iounmap(tp->aperegs); + tp->aperegs = NULL; + } if (tp->regs) { iounmap(tp->regs); tp->regs = NULL; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 88d08f3ede0..632c2f084c5 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -192,6 +192,8 @@ #define PCISTATE_ROM_RETRY_ENABLE 0x00000040 #define PCISTATE_FLAT_VIEW 0x00000100 #define PCISTATE_RETRY_SAME_DMA 0x00002000 +#define PCISTATE_ALLOW_APE_CTLSPC_WR 0x00010000 +#define PCISTATE_ALLOW_APE_SHMEM_WR 0x00020000 #define TG3PCI_CLOCK_CTRL 0x00000074 #define CLOCK_CTRL_CORECLK_DISABLE 0x00000200 #define CLOCK_CTRL_RXCLK_DISABLE 0x00000400 @@ -1560,6 +1562,7 @@ #define NIC_SRAM_DATA_CFG_MINI_PCI 0x00001000 #define NIC_SRAM_DATA_CFG_FIBER_WOL 0x00004000 #define NIC_SRAM_DATA_CFG_NO_GPIO2 0x00100000 +#define NIC_SRAM_DATA_CFG_APE_ENABLE 0x00200000 #define NIC_SRAM_DATA_VER 0x00000b5c #define NIC_SRAM_DATA_VER_SHIFT 16 @@ -1688,6 +1691,47 @@ #define MII_TG3_TEST1_TRIM_EN 0x0010 #define MII_TG3_TEST1_CRC_EN 0x8000 +/* APE registers. Accessible through BAR1 */ +#define TG3_APE_EVENT 0x000c +#define APE_EVENT_1 0x00000001 +#define TG3_APE_LOCK_REQ 0x002c +#define APE_LOCK_REQ_DRIVER 0x00001000 +#define TG3_APE_LOCK_GRANT 0x004c +#define APE_LOCK_GRANT_DRIVER 0x00001000 +#define TG3_APE_SEG_SIG 0x4000 +#define APE_SEG_SIG_MAGIC 0x41504521 + +/* APE shared memory. Accessible through BAR1 */ +#define TG3_APE_FW_STATUS 0x400c +#define APE_FW_STATUS_READY 0x00000100 +#define TG3_APE_HOST_SEG_SIG 0x4200 +#define APE_HOST_SEG_SIG_MAGIC 0x484f5354 +#define TG3_APE_HOST_SEG_LEN 0x4204 +#define APE_HOST_SEG_LEN_MAGIC 0x0000001c +#define TG3_APE_HOST_INIT_COUNT 0x4208 +#define TG3_APE_HOST_DRIVER_ID 0x420c +#define APE_HOST_DRIVER_ID_MAGIC 0xf0035100 +#define TG3_APE_HOST_BEHAVIOR 0x4210 +#define APE_HOST_BEHAV_NO_PHYLOCK 0x00000001 +#define TG3_APE_HOST_HEARTBEAT_INT_MS 0x4214 +#define APE_HOST_HEARTBEAT_INT_DISABLE 0 +#define APE_HOST_HEARTBEAT_INT_5SEC 5000 +#define TG3_APE_HOST_HEARTBEAT_COUNT 0x4218 + +#define TG3_APE_EVENT_STATUS 0x4300 + +#define APE_EVENT_STATUS_DRIVER_EVNT 0x00000010 +#define APE_EVENT_STATUS_STATE_CHNGE 0x00000500 +#define APE_EVENT_STATUS_STATE_START 0x00010000 +#define APE_EVENT_STATUS_STATE_UNLOAD 0x00020000 +#define APE_EVENT_STATUS_STATE_WOL 0x00030000 +#define APE_EVENT_STATUS_STATE_SUSPEND 0x00040000 +#define APE_EVENT_STATUS_EVENT_PENDING 0x80000000 + +/* APE convenience enumerations. */ +#define TG3_APE_LOCK_MEM 4 + + /* There are two ways to manage the TX descriptors on the tigon3. * Either the descriptors are in host DMA'able memory, or they * exist only in the cards on-chip SRAM. All 16 send bds are under @@ -2163,6 +2207,7 @@ struct tg3 { void (*write32_mbox) (struct tg3 *, u32, u32); void __iomem *regs; + void __iomem *aperegs; struct net_device *dev; struct pci_dev *pdev; @@ -2290,6 +2335,7 @@ struct tg3 { #define TG3_FLG2_PHY_ADJUST_TRIM 0x80000000 u32 tg3_flags3; #define TG3_FLG3_NO_NVRAM_ADDR_TRANS 0x00000001 +#define TG3_FLG3_ENABLE_APE 0x00000002 struct timer_list timer; u16 timer_counter; -- cgit v1.2.3-70-g09d2 From 9936bcf68a7e4d33f080bba9ee03d156c75c91ee Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Wed, 10 Oct 2007 18:03:07 -0700 Subject: [TG3]: Add 5761 support This patch adds rest of the miscellaneous code required to support the 5761. Signed-off-by: Matt Carlson Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 86 +++++++++++++++++++++++++++++++++++++++++-------- drivers/net/tg3.h | 14 ++++++-- include/linux/pci_ids.h | 2 ++ 3 files changed, 87 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 5b6c1b286e9..65aeca8e514 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -200,6 +200,8 @@ static struct pci_device_id tg3_pci_tbl[] = { {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5906M)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5784)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5764)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5761)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5761E)}, {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX)}, {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9MXX)}, {PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000)}, @@ -5087,7 +5089,8 @@ static int tg3_chip_reset(struct tg3 *tp) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) tw32(GRC_FASTBOOT_PC, 0); /* @@ -6363,7 +6366,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) if (err) return err; - if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784) { + if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784 && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761) { /* This value is determined during the probe time DMA * engine test, tg3_test_dma. */ @@ -6769,7 +6773,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) /* Enable host coalescing bug fix */ if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755) || (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) || - (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784)) + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784) || + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)) val |= (1 << 29); tw32_f(WDMAC_MODE, val); @@ -6797,7 +6802,13 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32(RCVDCC_MODE, RCVDCC_MODE_ENABLE | RCVDCC_MODE_ATTN_ENABLE); if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) tw32(MBFREE_MODE, MBFREE_MODE_ENABLE); - tw32(SNDDATAC_MODE, SNDDATAC_MODE_ENABLE); + + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) + tw32(SNDDATAC_MODE, + SNDDATAC_MODE_ENABLE | SNDDATAC_MODE_CDELAY); + else + tw32(SNDDATAC_MODE, SNDDATAC_MODE_ENABLE); + tw32(SNDBDC_MODE, SNDBDC_MODE_ENABLE | SNDBDC_MODE_ATTN_ENABLE); tw32(RCVBDI_MODE, RCVBDI_MODE_ENABLE | RCVBDI_MODE_RCB_ATTN_ENAB); tw32(RCVDBDI_MODE, RCVDBDI_MODE_ENABLE | RCVDBDI_MODE_INV_RING_SZ); @@ -6824,7 +6835,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) udelay(100); tp->rx_mode = RX_MODE_ENABLE; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) tp->rx_mode |= RX_MODE_IPV6_CSUM_ENABLE; tw32_f(MAC_RX_MODE, tp->rx_mode); @@ -8368,10 +8380,12 @@ static int tg3_set_tso(struct net_device *dev, u32 value) } if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) && (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)) { - if (value) + if (value) { dev->features |= NETIF_F_TSO6; - else - dev->features &= ~NETIF_F_TSO6; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) + dev->features |= NETIF_F_TSO_ECN; + } else + dev->features &= ~(NETIF_F_TSO6 | NETIF_F_TSO_ECN); } return ethtool_op_set_tso(dev, value); } @@ -8550,7 +8564,8 @@ static int tg3_set_tx_csum(struct net_device *dev, u32 data) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) ethtool_op_set_tx_ipv6_csum(dev, data); else ethtool_op_set_tx_csum(dev, data); @@ -9047,7 +9062,8 @@ static int tg3_test_memory(struct tg3 *tp) if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) { if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) mem_tbl = mem_tbl_5755; else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) mem_tbl = mem_tbl_5906; @@ -9244,6 +9260,7 @@ out: static int tg3_test_loopback(struct tg3 *tp) { int err = 0; + u32 cpmuctrl = 0; if (!netif_running(tp->dev)) return TG3_LOOPBACK_FAILED; @@ -9252,8 +9269,40 @@ static int tg3_test_loopback(struct tg3 *tp) if (err) return TG3_LOOPBACK_FAILED; + if (tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) { + int i; + u32 status; + + tw32(TG3_CPMU_MUTEX_REQ, CPMU_MUTEX_REQ_DRIVER); + + /* Wait for up to 40 microseconds to acquire lock. */ + for (i = 0; i < 4; i++) { + status = tr32(TG3_CPMU_MUTEX_GNT); + if (status == CPMU_MUTEX_GNT_DRIVER) + break; + udelay(10); + } + + if (status != CPMU_MUTEX_GNT_DRIVER) + return TG3_LOOPBACK_FAILED; + + cpmuctrl = tr32(TG3_CPMU_CTRL); + + /* Turn off power management based on link speed. */ + tw32(TG3_CPMU_CTRL, + cpmuctrl & ~CPMU_CTRL_LINK_SPEED_MODE); + } + if (tg3_run_loopback(tp, TG3_MAC_LOOPBACK)) err |= TG3_MAC_LOOPBACK_FAILED; + + if (tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) { + tw32(TG3_CPMU_CTRL, cpmuctrl); + + /* Release the mutex */ + tw32(TG3_CPMU_MUTEX_GNT, CPMU_MUTEX_GNT_DRIVER); + } + if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) { if (tg3_run_loopback(tp, TG3_PHY_LOOPBACK)) err |= TG3_PHY_LOOPBACK_FAILED; @@ -10192,6 +10241,7 @@ static int tg3_nvram_write_block_buffered(struct tg3 *tp, u32 offset, u32 len, (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5755) && (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787) && (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784) && + (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761) && (tp->nvram_jedecnum == JEDEC_ST) && (nvram_cmd & NVRAM_CMD_FIRST)) { @@ -10941,6 +10991,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 || (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) tp->tg3_flags2 |= TG3_FLG2_5750_PLUS; @@ -10961,6 +11012,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { tp->tg3_flags2 |= TG3_FLG2_HW_TSO_2; tp->tg3_flags2 |= TG3_FLG2_1SHOT_MSI; @@ -10979,6 +11031,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5755 && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787 && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784 && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761 && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906) tp->tg3_flags2 |= TG3_FLG2_JUMBO_CAPABLE; @@ -11164,7 +11217,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) pci_state_reg); } - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) tp->tg3_flags |= TG3_FLAG_CPMU_PRESENT; /* Set up tp->grc_local_ctrl before calling tg3_set_power_state(). @@ -11234,7 +11288,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) { if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784) { + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) { if (tp->pdev->device != PCI_DEVICE_ID_TIGON3_5756 && tp->pdev->device != PCI_DEVICE_ID_TIGON3_5722) tp->tg3_flags2 |= TG3_FLG2_PHY_JITTER_BUG; @@ -11378,6 +11433,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) tp->dev->hard_start_xmit = tg3_start_xmit; else @@ -12002,6 +12058,7 @@ static char * __devinit tg3_phy_string(struct tg3 *tp) case PHY_ID_BCM5784: return "5784"; case PHY_ID_BCM5756: return "5722/5756"; case PHY_ID_BCM5906: return "5906"; + case PHY_ID_BCM5761: return "5761"; case PHY_ID_BCM8002: return "8002/serdes"; case 0: return "serdes"; default: return "unknown"; @@ -12304,6 +12361,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) && (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)) dev->features |= NETIF_F_TSO6; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) + dev->features |= NETIF_F_TSO_ECN; } @@ -12345,7 +12404,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) dev->features |= NETIF_F_IPV6_CSUM; tp->tg3_flags |= TG3_FLAG_RX_CHECKSUMS; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 632c2f084c5..d1f5fa394ea 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -666,6 +666,7 @@ #define SNDDATAC_MODE 0x00001000 #define SNDDATAC_MODE_RESET 0x00000001 #define SNDDATAC_MODE_ENABLE 0x00000002 +#define SNDDATAC_MODE_CDELAY 0x00000010 /* 0x1004 --> 0x1400 unused */ /* Send BD ring selector */ @@ -854,7 +855,14 @@ #define TG3_CPMU_CTRL 0x00003600 #define CPMU_CTRL_LINK_IDLE_MODE 0x00000200 #define CPMU_CTRL_LINK_AWARE_MODE 0x00000400 -/* 0x3604 --> 0x3800 unused */ +#define CPMU_CTRL_LINK_SPEED_MODE 0x00004000 +/* 0x3604 --> 0x365c unused */ + +#define TG3_CPMU_MUTEX_REQ 0x0000365c +#define CPMU_MUTEX_REQ_DRIVER 0x00001000 +#define TG3_CPMU_MUTEX_GNT 0x00003660 +#define CPMU_MUTEX_GNT_DRIVER 0x00001000 +/* 0x3664 --> 0x3800 unused */ /* Mbuf cluster free registers */ #define MBFREE_MODE 0x00003800 @@ -2394,6 +2402,7 @@ struct tg3 { #define PHY_ID_BCM5787 0xbc050ce0 #define PHY_ID_BCM5756 0xbc050ed0 #define PHY_ID_BCM5784 0xbc050fa0 +#define PHY_ID_BCM5761 0xbc050fd0 #define PHY_ID_BCM5906 0xdc00ac40 #define PHY_ID_BCM8002 0x60010140 #define PHY_ID_INVALID 0xffffffff @@ -2423,7 +2432,8 @@ struct tg3 { (X) == PHY_ID_BCM5752 || (X) == PHY_ID_BCM5714 || \ (X) == PHY_ID_BCM5780 || (X) == PHY_ID_BCM5787 || \ (X) == PHY_ID_BCM5755 || (X) == PHY_ID_BCM5756 || \ - (X) == PHY_ID_BCM5906 || (X) == PHY_ID_BCM8002) + (X) == PHY_ID_BCM5906 || (X) == PHY_ID_BCM5761 || \ + (X) == PHY_ID_BCM8002) struct tg3_hw_stats *hw_stats; dma_addr_t stats_mapping; diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 6f5fa39c829..27363bf2979 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1950,6 +1950,8 @@ #define PCI_DEVICE_ID_TIGON3_5751M 0x167d #define PCI_DEVICE_ID_TIGON3_5751F 0x167e #define PCI_DEVICE_ID_TIGON3_5787F 0x167f +#define PCI_DEVICE_ID_TIGON3_5761E 0x1680 +#define PCI_DEVICE_ID_TIGON3_5761 0x1681 #define PCI_DEVICE_ID_TIGON3_5764 0x1684 #define PCI_DEVICE_ID_TIGON3_5787M 0x1693 #define PCI_DEVICE_ID_TIGON3_5782 0x1696 -- cgit v1.2.3-70-g09d2 From 0527ba358aa7594731e627842d493ae7f009dd57 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Wed, 10 Oct 2007 18:03:30 -0700 Subject: [TG3]: WOL defaults This patch enables WOL by default if out-of-box WOL is enabled in the NVRAM. Signed-off-by: Matt Carlson Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 15 +++++++++------ drivers/net/tg3.h | 2 ++ 2 files changed, 11 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 65aeca8e514..0eec84382b5 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -10412,8 +10412,12 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) tp->tg3_flags &= ~TG3_FLAG_EEPROM_WRITE_PROT; tp->tg3_flags2 |= TG3_FLG2_IS_NIC; } - if (tr32(VCPU_CFGSHDW) & VCPU_CFGSHDW_ASPM_DBNC) + val = tr32(VCPU_CFGSHDW); + if (val & VCPU_CFGSHDW_ASPM_DBNC) tp->tg3_flags |= TG3_FLAG_ASPM_WORKAROUND; + if ((val & VCPU_CFGSHDW_WOL_ENABLE) && + (val & VCPU_CFGSHDW_WOL_MAGPKT)) + tp->tg3_flags |= TG3_FLAG_WOL_ENABLE; return; } @@ -10536,6 +10540,10 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) !(nic_cfg & NIC_SRAM_DATA_CFG_FIBER_WOL)) tp->tg3_flags &= ~TG3_FLAG_WOL_CAP; + if (tp->tg3_flags & TG3_FLAG_WOL_CAP && + nic_cfg & NIC_SRAM_DATA_CFG_WOL_ENABLE) + tp->tg3_flags |= TG3_FLAG_WOL_ENABLE; + if (cfg2 & (1 << 17)) tp->tg3_flags2 |= TG3_FLG2_CAPACITIVE_COUPLING; @@ -11454,11 +11462,6 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755) tp->rx_std_max_post = 8; - /* By default, disable wake-on-lan. User can change this - * using ETHTOOL_SWOL. - */ - tp->tg3_flags &= ~TG3_FLAG_WOL_ENABLE; - if (tp->tg3_flags & TG3_FLAG_ASPM_WORKAROUND) tp->pwrmgmt_thresh = tr32(PCIE_PWR_MGMT_THRESH) & PCIE_PWR_MGMT_L1_THRESH_MSK; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index d1f5fa394ea..6dbdad2b8f8 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -1151,6 +1151,8 @@ #define VCPU_STATUS_DRV_RESET 0x08000000 #define VCPU_CFGSHDW 0x00005104 +#define VCPU_CFGSHDW_WOL_ENABLE 0x00000001 +#define VCPU_CFGSHDW_WOL_MAGPKT 0x00000004 #define VCPU_CFGSHDW_ASPM_DBNC 0x00001000 /* Mailboxes */ -- cgit v1.2.3-70-g09d2 From 414c66e00e9fb4572e38bd14e6cc570eae8c5a61 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Wed, 10 Oct 2007 18:03:56 -0700 Subject: [TG3]: Update version to 3.83 Update to version 3.83. Signed-off-by: Matt Carlson Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 0eec84382b5..d2b30fb0b31 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -64,8 +64,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.82" -#define DRV_MODULE_RELDATE "October 5, 2007" +#define DRV_MODULE_VERSION "3.83" +#define DRV_MODULE_RELDATE "October 10, 2007" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 -- cgit v1.2.3-70-g09d2 From cd40b7d3983c708aabe3d3008ec64ffce56d33b0 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Wed, 10 Oct 2007 21:15:29 -0700 Subject: [NET]: make netlink user -> kernel interface synchronious This patch make processing netlink user -> kernel messages synchronious. This change was inspired by the talk with Alexey Kuznetsov about current netlink messages processing. He says that he was badly wrong when introduced asynchronious user -> kernel communication. The call netlink_unicast is the only path to send message to the kernel netlink socket. But, unfortunately, it is also used to send data to the user. Before this change the user message has been attached to the socket queue and sk->sk_data_ready was called. The process has been blocked until all pending messages were processed. The bad thing is that this processing may occur in the arbitrary process context. This patch changes nlk->data_ready callback to get 1 skb and force packet processing right in the netlink_unicast. Kernel -> user path in netlink_unicast remains untouched. EINTR processing for in netlink_run_queue was changed. It forces rtnl_lock drop, but the process remains in the cycle until the message will be fully processed. So, there is no need to use this kludges now. Signed-off-by: Denis V. Lunev Acked-by: Alexey Kuznetsov Signed-off-by: David S. Miller --- drivers/connector/connector.c | 14 +--- drivers/scsi/scsi_netlink.c | 25 +----- drivers/scsi/scsi_transport_iscsi.c | 82 +++++++++---------- fs/ecryptfs/netlink.c | 14 +--- include/linux/connector.h | 2 +- include/linux/netlink.h | 2 +- include/net/netlink.h | 6 +- kernel/audit.c | 12 +-- net/core/rtnetlink.c | 12 +-- net/decnet/netfilter/dn_rtmsg.c | 14 +--- net/ipv4/fib_frontend.c | 9 ++- net/ipv4/inet_diag.c | 12 +-- net/ipv4/netfilter/ip_queue.c | 17 +--- net/ipv6/netfilter/ip6_queue.c | 19 ++--- net/netfilter/nfnetlink.c | 12 +-- net/netlink/af_netlink.c | 152 +++++++++++------------------------- net/netlink/genetlink.c | 12 +-- net/xfrm/xfrm_user.c | 13 +-- 18 files changed, 130 insertions(+), 299 deletions(-) (limited to 'drivers') diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c index 569070997cc..0e328d387af 100644 --- a/drivers/connector/connector.c +++ b/drivers/connector/connector.c @@ -234,18 +234,6 @@ out: kfree_skb(__skb); } -/* - * Netlink socket input callback - dequeues the skbs and calls the - * main netlink receiving function. - */ -static void cn_input(struct sock *sk, int len) -{ - struct sk_buff *skb; - - while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) - cn_rx_skb(skb); -} - /* * Notification routing. * @@ -442,7 +430,7 @@ static int __devinit cn_init(void) struct cn_dev *dev = &cdev; int err; - dev->input = cn_input; + dev->input = cn_rx_skb; dev->id.idx = cn_idx; dev->id.val = cn_val; diff --git a/drivers/scsi/scsi_netlink.c b/drivers/scsi/scsi_netlink.c index 163acf6ad2d..40579edca10 100644 --- a/drivers/scsi/scsi_netlink.c +++ b/drivers/scsi/scsi_netlink.c @@ -64,7 +64,7 @@ scsi_nl_rcv_msg(struct sk_buff *skb) if (nlh->nlmsg_type != SCSI_TRANSPORT_MSG) { err = -EBADMSG; - goto next_msg; + return; } hdr = NLMSG_DATA(nlh); @@ -98,27 +98,6 @@ next_msg: } -/** - * scsi_nl_rcv_msg - - * Receive handler for a socket. Extracts a received message buffer from - * the socket, and starts message processing. - * - * @sk: socket - * @len: unused - * - **/ -static void -scsi_nl_rcv(struct sock *sk, int len) -{ - struct sk_buff *skb; - - while ((skb = skb_dequeue(&sk->sk_receive_queue))) { - scsi_nl_rcv_msg(skb); - kfree_skb(skb); - } -} - - /** * scsi_nl_rcv_event - * Event handler for a netlink socket. @@ -168,7 +147,7 @@ scsi_netlink_init(void) } scsi_nl_sock = netlink_kernel_create(&init_net, NETLINK_SCSITRANSPORT, - SCSI_NL_GRP_CNT, scsi_nl_rcv, NULL, + SCSI_NL_GRP_CNT, scsi_nl_rcv_msg, NULL, THIS_MODULE); if (!scsi_nl_sock) { printk(KERN_ERR "%s: register of recieve handler failed\n", diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 4916f01230d..5428d15f23c 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -1097,61 +1097,49 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) } /* - * Get message from skb (based on rtnetlink_rcv_skb). Each message is - * processed by iscsi_if_recv_msg. Malformed skbs with wrong lengths or - * invalid creds are discarded silently. + * Get message from skb. Each message is processed by iscsi_if_recv_msg. + * Malformed skbs with wrong lengths or invalid creds are not processed. */ static void -iscsi_if_rx(struct sock *sk, int len) +iscsi_if_rx(struct sk_buff *skb) { - struct sk_buff *skb; - mutex_lock(&rx_queue_mutex); - while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { - if (NETLINK_CREDS(skb)->uid) { - skb_pull(skb, skb->len); - goto free_skb; + while (skb->len >= NLMSG_SPACE(0)) { + int err; + uint32_t rlen; + struct nlmsghdr *nlh; + struct iscsi_uevent *ev; + + nlh = nlmsg_hdr(skb); + if (nlh->nlmsg_len < sizeof(*nlh) || + skb->len < nlh->nlmsg_len) { + break; } - while (skb->len >= NLMSG_SPACE(0)) { - int err; - uint32_t rlen; - struct nlmsghdr *nlh; - struct iscsi_uevent *ev; + ev = NLMSG_DATA(nlh); + rlen = NLMSG_ALIGN(nlh->nlmsg_len); + if (rlen > skb->len) + rlen = skb->len; - nlh = nlmsg_hdr(skb); - if (nlh->nlmsg_len < sizeof(*nlh) || - skb->len < nlh->nlmsg_len) { - break; - } - - ev = NLMSG_DATA(nlh); - rlen = NLMSG_ALIGN(nlh->nlmsg_len); - if (rlen > skb->len) - rlen = skb->len; - - err = iscsi_if_recv_msg(skb, nlh); - if (err) { - ev->type = ISCSI_KEVENT_IF_ERROR; - ev->iferror = err; - } - do { - /* - * special case for GET_STATS: - * on success - sending reply and stats from - * inside of if_recv_msg(), - * on error - fall through. - */ - if (ev->type == ISCSI_UEVENT_GET_STATS && !err) - break; - err = iscsi_if_send_reply( - NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq, - nlh->nlmsg_type, 0, 0, ev, sizeof(*ev)); - } while (err < 0 && err != -ECONNREFUSED); - skb_pull(skb, rlen); + err = iscsi_if_recv_msg(skb, nlh); + if (err) { + ev->type = ISCSI_KEVENT_IF_ERROR; + ev->iferror = err; } -free_skb: - kfree_skb(skb); + do { + /* + * special case for GET_STATS: + * on success - sending reply and stats from + * inside of if_recv_msg(), + * on error - fall through. + */ + if (ev->type == ISCSI_UEVENT_GET_STATS && !err) + break; + err = iscsi_if_send_reply( + NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq, + nlh->nlmsg_type, 0, 0, ev, sizeof(*ev)); + } while (err < 0 && err != -ECONNREFUSED); + skb_pull(skb, rlen); } mutex_unlock(&rx_queue_mutex); } diff --git a/fs/ecryptfs/netlink.c b/fs/ecryptfs/netlink.c index 056519cd92b..9aa345121e0 100644 --- a/fs/ecryptfs/netlink.c +++ b/fs/ecryptfs/netlink.c @@ -165,22 +165,10 @@ static int ecryptfs_process_nl_quit(struct sk_buff *skb) * it to its desired netlink context element and wake up the process * that is waiting for a response. */ -static void ecryptfs_receive_nl_message(struct sock *sk, int len) +static void ecryptfs_receive_nl_message(struct sk_buff *skb) { - struct sk_buff *skb; struct nlmsghdr *nlh; - int rc = 0; /* skb_recv_datagram requires this */ -receive: - skb = skb_recv_datagram(sk, 0, 0, &rc); - if (rc == -EINTR) - goto receive; - else if (rc < 0) { - ecryptfs_printk(KERN_ERR, "Error occurred while " - "receiving eCryptfs netlink message; " - "rc = [%d]\n", rc); - return; - } nlh = nlmsg_hdr(skb); if (!NLMSG_OK(nlh, skb->len)) { ecryptfs_printk(KERN_ERR, "Received corrupt netlink " diff --git a/include/linux/connector.h b/include/linux/connector.h index 10eb56b2940..b62f823e90c 100644 --- a/include/linux/connector.h +++ b/include/linux/connector.h @@ -153,7 +153,7 @@ struct cn_dev { u32 seq, groups; struct sock *nls; - void (*input) (struct sock * sk, int len); + void (*input) (struct sk_buff *skb); struct cn_queue_dev *cbdev; }; diff --git a/include/linux/netlink.h b/include/linux/netlink.h index 7b552b6c2c1..7c1f3b1d2ee 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -175,7 +175,7 @@ struct netlink_skb_parms extern struct sock *netlink_kernel_create(struct net *net, int unit,unsigned int groups, - void (*input)(struct sock *sk, int len), + void (*input)(struct sk_buff *skb), struct mutex *cb_mutex, struct module *module); extern int netlink_change_ngroups(struct sock *sk, unsigned int groups); diff --git a/include/net/netlink.h b/include/net/netlink.h index 1afd3e837d2..9298218c07f 100644 --- a/include/net/netlink.h +++ b/include/net/netlink.h @@ -220,9 +220,9 @@ struct nl_info { u32 pid; }; -extern unsigned int netlink_run_queue(struct sock *sk, unsigned int qlen, - int (*cb)(struct sk_buff *, - struct nlmsghdr *)); +extern int netlink_rcv_skb(struct sk_buff *skb, + int (*cb)(struct sk_buff *, + struct nlmsghdr *)); extern int nlmsg_notify(struct sock *sk, struct sk_buff *skb, u32 pid, unsigned int group, int report, gfp_t flags); diff --git a/kernel/audit.c b/kernel/audit.c index f3c390f6c0b..2924251a654 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -847,18 +847,10 @@ static void audit_receive_skb(struct sk_buff *skb) } /* Receive messages from netlink socket. */ -static void audit_receive(struct sock *sk, int length) +static void audit_receive(struct sk_buff *skb) { - struct sk_buff *skb; - unsigned int qlen; - mutex_lock(&audit_cmd_mutex); - - for (qlen = skb_queue_len(&sk->sk_receive_queue); qlen; qlen--) { - skb = skb_dequeue(&sk->sk_receive_queue); - audit_receive_skb(skb); - kfree_skb(skb); - } + audit_receive_skb(skb); mutex_unlock(&audit_cmd_mutex); } diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 471d2d9f8ea..1072d16696c 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1312,15 +1312,11 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) return doit(skb, nlh, (void *)&rta_buf[0]); } -static void rtnetlink_rcv(struct sock *sk, int len) +static void rtnetlink_rcv(struct sk_buff *skb) { - unsigned int qlen = 0; - - do { - rtnl_lock(); - qlen = netlink_run_queue(sk, qlen, &rtnetlink_rcv_msg); - rtnl_unlock(); - } while (qlen); + rtnl_lock(); + netlink_rcv_skb(skb, &rtnetlink_rcv_msg); + rtnl_unlock(); } static int rtnetlink_event(struct notifier_block *this, unsigned long event, void *ptr) diff --git a/net/decnet/netfilter/dn_rtmsg.c b/net/decnet/netfilter/dn_rtmsg.c index ebb38feb4df..f7fba7721e6 100644 --- a/net/decnet/netfilter/dn_rtmsg.c +++ b/net/decnet/netfilter/dn_rtmsg.c @@ -115,17 +115,6 @@ static inline void dnrmg_receive_user_skb(struct sk_buff *skb) RCV_SKB_FAIL(-EINVAL); } -static void dnrmg_receive_user_sk(struct sock *sk, int len) -{ - struct sk_buff *skb; - unsigned int qlen = skb_queue_len(&sk->sk_receive_queue); - - for (; qlen && (skb = skb_dequeue(&sk->sk_receive_queue)); qlen--) { - dnrmg_receive_user_skb(skb); - kfree_skb(skb); - } -} - static struct nf_hook_ops dnrmg_ops = { .hook = dnrmg_hook, .pf = PF_DECnet, @@ -139,7 +128,8 @@ static int __init dn_rtmsg_init(void) dnrmg = netlink_kernel_create(&init_net, NETLINK_DNRTMSG, DNRNG_NLGRP_MAX, - dnrmg_receive_user_sk, NULL, THIS_MODULE); + dnrmg_receive_user_skb, + NULL, THIS_MODULE); if (dnrmg == NULL) { printk(KERN_ERR "dn_rtmsg: Cannot create netlink socket"); return -ENOMEM; diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index f823ca34cb1..a5cba234960 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -62,6 +62,9 @@ static struct hlist_head fib_table_hash[FIB_TABLE_HASHSZ]; #define FIB_TABLE_HASHSZ 256 static struct hlist_head fib_table_hash[FIB_TABLE_HASHSZ]; +static struct sock *fibnl = NULL; + + struct fib_table *fib_new_table(u32 id) { struct fib_table *tb; @@ -811,13 +814,13 @@ static void nl_fib_input(struct sock *sk, int len) pid = NETLINK_CB(skb).pid; /* pid of sending process */ NETLINK_CB(skb).pid = 0; /* from kernel */ NETLINK_CB(skb).dst_group = 0; /* unicast */ - netlink_unicast(sk, skb, pid, MSG_DONTWAIT); + netlink_unicast(fibnl, skb, pid, MSG_DONTWAIT); } static void nl_fib_lookup_init(void) { - netlink_kernel_create(&init_net, NETLINK_FIB_LOOKUP, 0, nl_fib_input, - NULL, THIS_MODULE); + fibnl = netlink_kernel_create(&init_net, NETLINK_FIB_LOOKUP, 0, + nl_fib_input, NULL, THIS_MODULE); } static void fib_disable_ip(struct net_device *dev, int force) diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index b04a6ee5a9a..7eb83ebed2e 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c @@ -839,15 +839,11 @@ static int inet_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) static DEFINE_MUTEX(inet_diag_mutex); -static void inet_diag_rcv(struct sock *sk, int len) +static void inet_diag_rcv(struct sk_buff *skb) { - unsigned int qlen = 0; - - do { - mutex_lock(&inet_diag_mutex); - qlen = netlink_run_queue(sk, qlen, &inet_diag_rcv_msg); - mutex_unlock(&inet_diag_mutex); - } while (qlen); + mutex_lock(&inet_diag_mutex); + netlink_rcv_skb(skb, &inet_diag_rcv_msg); + mutex_unlock(&inet_diag_mutex); } static DEFINE_SPINLOCK(inet_diag_register_lock); diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index aaa3f5c5676..23cbfc7c80f 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c @@ -475,7 +475,7 @@ ipq_dev_drop(int ifindex) #define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0) static inline void -ipq_rcv_skb(struct sk_buff *skb) +__ipq_rcv_skb(struct sk_buff *skb) { int status, type, pid, flags, nlmsglen, skblen; struct nlmsghdr *nlh; @@ -533,19 +533,10 @@ ipq_rcv_skb(struct sk_buff *skb) } static void -ipq_rcv_sk(struct sock *sk, int len) +ipq_rcv_skb(struct sk_buff *skb) { - struct sk_buff *skb; - unsigned int qlen; - mutex_lock(&ipqnl_mutex); - - for (qlen = skb_queue_len(&sk->sk_receive_queue); qlen; qlen--) { - skb = skb_dequeue(&sk->sk_receive_queue); - ipq_rcv_skb(skb); - kfree_skb(skb); - } - + __ipq_rcv_skb(skb); mutex_unlock(&ipqnl_mutex); } @@ -670,7 +661,7 @@ static int __init ip_queue_init(void) netlink_register_notifier(&ipq_nl_notifier); ipqnl = netlink_kernel_create(&init_net, NETLINK_FIREWALL, 0, - ipq_rcv_sk, NULL, THIS_MODULE); + ipq_rcv_skb, NULL, THIS_MODULE); if (ipqnl == NULL) { printk(KERN_ERR "ip_queue: failed to create netlink socket\n"); goto cleanup_netlink_notifier; diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index c75f467a8f5..0473145ac53 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c @@ -464,7 +464,7 @@ ipq_dev_drop(int ifindex) #define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0) static inline void -ipq_rcv_skb(struct sk_buff *skb) +__ipq_rcv_skb(struct sk_buff *skb) { int status, type, pid, flags, nlmsglen, skblen; struct nlmsghdr *nlh; @@ -522,19 +522,10 @@ ipq_rcv_skb(struct sk_buff *skb) } static void -ipq_rcv_sk(struct sock *sk, int len) +ipq_rcv_skb(struct sk_buff *skb) { - struct sk_buff *skb; - unsigned int qlen; - mutex_lock(&ipqnl_mutex); - - for (qlen = skb_queue_len(&sk->sk_receive_queue); qlen; qlen--) { - skb = skb_dequeue(&sk->sk_receive_queue); - ipq_rcv_skb(skb); - kfree_skb(skb); - } - + __ipq_rcv_skb(skb); mutex_unlock(&ipqnl_mutex); } @@ -658,8 +649,8 @@ static int __init ip6_queue_init(void) struct proc_dir_entry *proc; netlink_register_notifier(&ipq_nl_notifier); - ipqnl = netlink_kernel_create(&init_net, NETLINK_IP6_FW, 0, ipq_rcv_sk, - NULL, THIS_MODULE); + ipqnl = netlink_kernel_create(&init_net, NETLINK_IP6_FW, 0, + ipq_rcv_skb, NULL, THIS_MODULE); if (ipqnl == NULL) { printk(KERN_ERR "ip6_queue: failed to create netlink socket\n"); goto cleanup_netlink_notifier; diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c index 99775af19ff..2128542995f 100644 --- a/net/netfilter/nfnetlink.c +++ b/net/netfilter/nfnetlink.c @@ -169,15 +169,11 @@ static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) } } -static void nfnetlink_rcv(struct sock *sk, int len) +static void nfnetlink_rcv(struct sk_buff *skb) { - unsigned int qlen = 0; - - do { - nfnl_lock(); - qlen = netlink_run_queue(sk, qlen, nfnetlink_rcv_msg); - nfnl_unlock(); - } while (qlen); + nfnl_lock(); + netlink_rcv_skb(skb, &nfnetlink_rcv_msg); + nfnl_unlock(); } static void __exit nfnetlink_exit(void) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 4ce7dcbcb6e..c776bcd9f82 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -80,7 +80,7 @@ struct netlink_sock { struct netlink_callback *cb; struct mutex *cb_mutex; struct mutex cb_def_mutex; - void (*data_ready)(struct sock *sk, int bytes); + void (*netlink_rcv)(struct sk_buff *skb); struct module *module; }; @@ -127,7 +127,6 @@ static DECLARE_WAIT_QUEUE_HEAD(nl_table_wait); static int netlink_dump(struct sock *sk); static void netlink_destroy_callback(struct netlink_callback *cb); -static void netlink_queue_skip(struct nlmsghdr *nlh, struct sk_buff *skb); static DEFINE_RWLOCK(nl_table_lock); static atomic_t nl_table_users = ATOMIC_INIT(0); @@ -709,21 +708,17 @@ static void netlink_overrun(struct sock *sk) static struct sock *netlink_getsockbypid(struct sock *ssk, u32 pid) { - int protocol = ssk->sk_protocol; - struct net *net; struct sock *sock; struct netlink_sock *nlk; - net = ssk->sk_net; - sock = netlink_lookup(net, protocol, pid); + sock = netlink_lookup(ssk->sk_net, ssk->sk_protocol, pid); if (!sock) return ERR_PTR(-ECONNREFUSED); /* Don't bother queuing skb if kernel socket has no input function */ nlk = nlk_sk(sock); - if ((netlink_is_kernel(sock) && !nlk->data_ready) || - (sock->sk_state == NETLINK_CONNECTED && - nlk->dst_pid != nlk_sk(ssk)->pid)) { + if (sock->sk_state == NETLINK_CONNECTED && + nlk->dst_pid != nlk_sk(ssk)->pid) { sock_put(sock); return ERR_PTR(-ECONNREFUSED); } @@ -837,7 +832,34 @@ static inline struct sk_buff *netlink_trim(struct sk_buff *skb, return skb; } -int netlink_unicast(struct sock *ssk, struct sk_buff *skb, u32 pid, int nonblock) +static inline void netlink_rcv_wake(struct sock *sk) +{ + struct netlink_sock *nlk = nlk_sk(sk); + + if (skb_queue_empty(&sk->sk_receive_queue)) + clear_bit(0, &nlk->state); + if (!test_bit(0, &nlk->state)) + wake_up_interruptible(&nlk->wait); +} + +static inline int netlink_unicast_kernel(struct sock *sk, struct sk_buff *skb) +{ + int ret; + struct netlink_sock *nlk = nlk_sk(sk); + + ret = -ECONNREFUSED; + if (nlk->netlink_rcv != NULL) { + ret = skb->len; + skb_set_owner_r(skb, sk); + nlk->netlink_rcv(skb); + } + kfree_skb(skb); + sock_put(sk); + return ret; +} + +int netlink_unicast(struct sock *ssk, struct sk_buff *skb, + u32 pid, int nonblock) { struct sock *sk; int err; @@ -852,6 +874,9 @@ retry: kfree_skb(skb); return PTR_ERR(sk); } + if (netlink_is_kernel(sk)) + return netlink_unicast_kernel(sk, skb); + err = netlink_attachskb(sk, skb, nonblock, timeo, ssk); if (err == 1) goto retry; @@ -1151,16 +1176,6 @@ static void netlink_cmsg_recv_pktinfo(struct msghdr *msg, struct sk_buff *skb) put_cmsg(msg, SOL_NETLINK, NETLINK_PKTINFO, sizeof(info), &info); } -static inline void netlink_rcv_wake(struct sock *sk) -{ - struct netlink_sock *nlk = nlk_sk(sk); - - if (skb_queue_empty(&sk->sk_receive_queue)) - clear_bit(0, &nlk->state); - if (!test_bit(0, &nlk->state)) - wake_up_interruptible(&nlk->wait); -} - static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock, struct msghdr *msg, size_t len) { @@ -1308,11 +1323,7 @@ out: static void netlink_data_ready(struct sock *sk, int len) { - struct netlink_sock *nlk = nlk_sk(sk); - - if (nlk->data_ready) - nlk->data_ready(sk, len); - netlink_rcv_wake(sk); + BUG(); } /* @@ -1323,7 +1334,7 @@ static void netlink_data_ready(struct sock *sk, int len) struct sock * netlink_kernel_create(struct net *net, int unit, unsigned int groups, - void (*input)(struct sock *sk, int len), + void (*input)(struct sk_buff *skb), struct mutex *cb_mutex, struct module *module) { struct socket *sock; @@ -1352,7 +1363,7 @@ netlink_kernel_create(struct net *net, int unit, unsigned int groups, sk = sock->sk; sk->sk_data_ready = netlink_data_ready; if (input) - nlk_sk(sk)->data_ready = input; + nlk_sk(sk)->netlink_rcv = input; if (netlink_insert(sk, net, 0)) goto out_sock_release; @@ -1552,12 +1563,7 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, netlink_dump(sk); sock_put(sk); - - /* We successfully started a dump, by returning -EINTR we - * signal the queue mangement to interrupt processing of - * any netlink messages so userspace gets a chance to read - * the results. */ - return -EINTR; + return 0; } void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err) @@ -1594,13 +1600,15 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err) netlink_unicast(in_skb->sk, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT); } -static int netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *, +int netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *, struct nlmsghdr *)) { struct nlmsghdr *nlh; int err; while (skb->len >= nlmsg_total_size(0)) { + int msglen; + nlh = nlmsg_hdr(skb); err = 0; @@ -1616,85 +1624,19 @@ static int netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *, goto skip; err = cb(skb, nlh); - if (err == -EINTR) { - /* Not an error, but we interrupt processing */ - netlink_queue_skip(nlh, skb); - return err; - } skip: if (nlh->nlmsg_flags & NLM_F_ACK || err) netlink_ack(skb, nlh, err); - netlink_queue_skip(nlh, skb); + msglen = NLMSG_ALIGN(nlh->nlmsg_len); + if (msglen > skb->len) + msglen = skb->len; + skb_pull(skb, msglen); } return 0; } -/** - * nelink_run_queue - Process netlink receive queue. - * @sk: Netlink socket containing the queue - * @qlen: Initial queue length - * @cb: Callback function invoked for each netlink message found - * - * Processes as much as there was in the queue upon entry and invokes - * a callback function for each netlink message found. The callback - * function may refuse a message by returning a negative error code - * but setting the error pointer to 0 in which case this function - * returns with a qlen != 0. - * - * qlen must be initialized to 0 before the initial entry, afterwards - * the function may be called repeatedly until the returned qlen is 0. - * - * The callback function may return -EINTR to signal that processing - * of netlink messages shall be interrupted. In this case the message - * currently being processed will NOT be requeued onto the receive - * queue. - */ -unsigned int netlink_run_queue(struct sock *sk, unsigned int qlen, - int (*cb)(struct sk_buff *, struct nlmsghdr *)) -{ - struct sk_buff *skb; - - if (!qlen || qlen > skb_queue_len(&sk->sk_receive_queue)) - qlen = skb_queue_len(&sk->sk_receive_queue); - - for (; qlen; qlen--) { - skb = skb_dequeue(&sk->sk_receive_queue); - if (netlink_rcv_skb(skb, cb)) { - if (skb->len) - skb_queue_head(&sk->sk_receive_queue, skb); - else { - kfree_skb(skb); - qlen--; - } - break; - } - - kfree_skb(skb); - } - - return qlen; -} - -/** - * netlink_queue_skip - Skip netlink message while processing queue. - * @nlh: Netlink message to be skipped - * @skb: Socket buffer containing the netlink messages. - * - * Pulls the given netlink message off the socket buffer so the next - * call to netlink_queue_run() will not reconsider the message. - */ -static void netlink_queue_skip(struct nlmsghdr *nlh, struct sk_buff *skb) -{ - int msglen = NLMSG_ALIGN(nlh->nlmsg_len); - - if (msglen > skb->len) - msglen = skb->len; - - skb_pull(skb, msglen); -} - /** * nlmsg_notify - send a notification netlink message * @sk: netlink socket to use @@ -1998,7 +1940,7 @@ panic: core_initcall(netlink_proto_init); EXPORT_SYMBOL(netlink_ack); -EXPORT_SYMBOL(netlink_run_queue); +EXPORT_SYMBOL(netlink_rcv_skb); EXPORT_SYMBOL(netlink_broadcast); EXPORT_SYMBOL(netlink_dump_start); EXPORT_SYMBOL(netlink_kernel_create); diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index 3f1104dc128..150579a2146 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -470,15 +470,11 @@ static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) return ops->doit(skb, &info); } -static void genl_rcv(struct sock *sk, int len) +static void genl_rcv(struct sk_buff *skb) { - unsigned int qlen = 0; - - do { - genl_lock(); - qlen = netlink_run_queue(sk, qlen, genl_rcv_msg); - genl_unlock(); - } while (qlen && genl_sock && genl_sock->sk_receive_queue.qlen); + genl_lock(); + netlink_rcv_skb(skb, &genl_rcv_msg); + genl_unlock(); } /************************************************************************** diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 5238f6a8dfa..d41588d101d 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -1895,16 +1895,11 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) return link->doit(skb, nlh, attrs); } -static void xfrm_netlink_rcv(struct sock *sk, int len) +static void xfrm_netlink_rcv(struct sk_buff *skb) { - unsigned int qlen = 0; - - do { - mutex_lock(&xfrm_cfg_mutex); - qlen = netlink_run_queue(sk, qlen, &xfrm_user_rcv_msg); - mutex_unlock(&xfrm_cfg_mutex); - - } while (qlen); + mutex_lock(&xfrm_cfg_mutex); + netlink_rcv_skb(skb, &xfrm_user_rcv_msg); + mutex_unlock(&xfrm_cfg_mutex); } static inline size_t xfrm_expire_msgsize(void) -- cgit v1.2.3-70-g09d2 From fb9aa6f1d4a1e11e66a680460b2c2b2b10b62f79 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 11 Oct 2007 11:16:36 +0200 Subject: i386: move pci Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/i386/Makefile | 2 +- arch/i386/pci/Makefile | 5 - arch/i386/pci/Makefile_32 | 14 - arch/i386/pci/acpi.c | 90 --- arch/i386/pci/common.c | 480 --------------- arch/i386/pci/direct.c | 302 ---------- arch/i386/pci/early.c | 59 -- arch/i386/pci/fixup.c | 446 -------------- arch/i386/pci/i386.c | 315 ---------- arch/i386/pci/init.c | 37 -- arch/i386/pci/irq.c | 1173 ------------------------------------- arch/i386/pci/legacy.c | 56 -- arch/i386/pci/mmconfig-shared.c | 315 ---------- arch/i386/pci/mmconfig_32.c | 148 ----- arch/i386/pci/numa.c | 135 ----- arch/i386/pci/pcbios.c | 492 ---------------- arch/i386/pci/pci.h | 149 ----- arch/i386/pci/visws.c | 111 ---- arch/x86/pci/Makefile | 5 + arch/x86/pci/Makefile_32 | 14 + arch/x86/pci/acpi.c | 90 +++ arch/x86/pci/common.c | 480 +++++++++++++++ arch/x86/pci/direct.c | 302 ++++++++++ arch/x86/pci/early.c | 59 ++ arch/x86/pci/fixup.c | 446 ++++++++++++++ arch/x86/pci/i386.c | 315 ++++++++++ arch/x86/pci/init.c | 37 ++ arch/x86/pci/irq.c | 1173 +++++++++++++++++++++++++++++++++++++ arch/x86/pci/legacy.c | 56 ++ arch/x86/pci/mmconfig-shared.c | 315 ++++++++++ arch/x86/pci/mmconfig_32.c | 148 +++++ arch/x86/pci/numa.c | 135 +++++ arch/x86/pci/pcbios.c | 492 ++++++++++++++++ arch/x86/pci/pci.h | 149 +++++ arch/x86/pci/visws.c | 111 ++++ arch/x86_64/pci/Makefile | 2 +- arch/x86_64/pci/Makefile_64 | 22 +- drivers/pci/hotplug/cpqphp_core.c | 2 +- drivers/pci/hotplug/cpqphp_pci.c | 2 +- drivers/pci/hotplug/ibmphp_core.c | 2 +- 40 files changed, 4343 insertions(+), 4343 deletions(-) delete mode 100644 arch/i386/pci/Makefile delete mode 100644 arch/i386/pci/Makefile_32 delete mode 100644 arch/i386/pci/acpi.c delete mode 100644 arch/i386/pci/common.c delete mode 100644 arch/i386/pci/direct.c delete mode 100644 arch/i386/pci/early.c delete mode 100644 arch/i386/pci/fixup.c delete mode 100644 arch/i386/pci/i386.c delete mode 100644 arch/i386/pci/init.c delete mode 100644 arch/i386/pci/irq.c delete mode 100644 arch/i386/pci/legacy.c delete mode 100644 arch/i386/pci/mmconfig-shared.c delete mode 100644 arch/i386/pci/mmconfig_32.c delete mode 100644 arch/i386/pci/numa.c delete mode 100644 arch/i386/pci/pcbios.c delete mode 100644 arch/i386/pci/pci.h delete mode 100644 arch/i386/pci/visws.c create mode 100644 arch/x86/pci/Makefile create mode 100644 arch/x86/pci/Makefile_32 create mode 100644 arch/x86/pci/acpi.c create mode 100644 arch/x86/pci/common.c create mode 100644 arch/x86/pci/direct.c create mode 100644 arch/x86/pci/early.c create mode 100644 arch/x86/pci/fixup.c create mode 100644 arch/x86/pci/i386.c create mode 100644 arch/x86/pci/init.c create mode 100644 arch/x86/pci/irq.c create mode 100644 arch/x86/pci/legacy.c create mode 100644 arch/x86/pci/mmconfig-shared.c create mode 100644 arch/x86/pci/mmconfig_32.c create mode 100644 arch/x86/pci/numa.c create mode 100644 arch/x86/pci/pcbios.c create mode 100644 arch/x86/pci/pci.h create mode 100644 arch/x86/pci/visws.c (limited to 'drivers') diff --git a/arch/i386/Makefile b/arch/i386/Makefile index da64799484a..87c959d5f35 100644 --- a/arch/i386/Makefile +++ b/arch/i386/Makefile @@ -107,7 +107,7 @@ core-y += arch/i386/kernel/ \ $(mcore-y)/ \ arch/x86/crypto/ drivers-$(CONFIG_MATH_EMULATION) += arch/x86/math-emu/ -drivers-$(CONFIG_PCI) += arch/i386/pci/ +drivers-$(CONFIG_PCI) += arch/x86/pci/ # must be linked after kernel/ drivers-$(CONFIG_OPROFILE) += arch/i386/oprofile/ drivers-$(CONFIG_PM) += arch/x86/power/ diff --git a/arch/i386/pci/Makefile b/arch/i386/pci/Makefile deleted file mode 100644 index d04d8f976d1..00000000000 --- a/arch/i386/pci/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -ifeq ($(CONFIG_X86_32),y) -include ${srctree}/arch/i386/pci/Makefile_32 -else -include ${srctree}/arch/x86_64/pci/Makefile_64 -endif diff --git a/arch/i386/pci/Makefile_32 b/arch/i386/pci/Makefile_32 deleted file mode 100644 index cdd6828b5ab..00000000000 --- a/arch/i386/pci/Makefile_32 +++ /dev/null @@ -1,14 +0,0 @@ -obj-y := i386.o init.o - -obj-$(CONFIG_PCI_BIOS) += pcbios.o -obj-$(CONFIG_PCI_MMCONFIG) += mmconfig_32.o direct.o mmconfig-shared.o -obj-$(CONFIG_PCI_DIRECT) += direct.o - -pci-y := fixup.o -pci-$(CONFIG_ACPI) += acpi.o -pci-y += legacy.o irq.o - -pci-$(CONFIG_X86_VISWS) := visws.o fixup.o -pci-$(CONFIG_X86_NUMAQ) := numa.o irq.o - -obj-y += $(pci-y) common.o early.o diff --git a/arch/i386/pci/acpi.c b/arch/i386/pci/acpi.c deleted file mode 100644 index bc8a44bddaa..00000000000 --- a/arch/i386/pci/acpi.c +++ /dev/null @@ -1,90 +0,0 @@ -#include -#include -#include -#include -#include -#include "pci.h" - -struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int domain, int busnum) -{ - struct pci_bus *bus; - struct pci_sysdata *sd; - int pxm; - - /* Allocate per-root-bus (not per bus) arch-specific data. - * TODO: leak; this memory is never freed. - * It's arguable whether it's worth the trouble to care. - */ - sd = kzalloc(sizeof(*sd), GFP_KERNEL); - if (!sd) { - printk(KERN_ERR "PCI: OOM, not probing PCI bus %02x\n", busnum); - return NULL; - } - - if (domain != 0) { - printk(KERN_WARNING "PCI: Multiple domains not supported\n"); - kfree(sd); - return NULL; - } - - sd->node = -1; - - pxm = acpi_get_pxm(device->handle); -#ifdef CONFIG_ACPI_NUMA - if (pxm >= 0) - sd->node = pxm_to_node(pxm); -#endif - - bus = pci_scan_bus_parented(NULL, busnum, &pci_root_ops, sd); - if (!bus) - kfree(sd); - -#ifdef CONFIG_ACPI_NUMA - if (bus != NULL) { - if (pxm >= 0) { - printk("bus %d -> pxm %d -> node %d\n", - busnum, pxm, sd->node); - } - } -#endif - - return bus; -} - -extern int pci_routeirq; -static int __init pci_acpi_init(void) -{ - struct pci_dev *dev = NULL; - - if (pcibios_scanned) - return 0; - - if (acpi_noirq) - return 0; - - printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n"); - acpi_irq_penalty_init(); - pcibios_scanned++; - pcibios_enable_irq = acpi_pci_irq_enable; - pcibios_disable_irq = acpi_pci_irq_disable; - - if (pci_routeirq) { - /* - * PCI IRQ routing is set up by pci_enable_device(), but we - * also do it here in case there are still broken drivers that - * don't use pci_enable_device(). - */ - printk(KERN_INFO "PCI: Routing PCI interrupts for all devices because \"pci=routeirq\" specified\n"); - for_each_pci_dev(dev) - acpi_pci_irq_enable(dev); - } else - printk(KERN_INFO "PCI: If a device doesn't work, try \"pci=routeirq\". If it helps, post a report\n"); - -#ifdef CONFIG_X86_IO_APIC - if (acpi_ioapic) - print_IO_APIC(); -#endif - - return 0; -} -subsys_initcall(pci_acpi_init); diff --git a/arch/i386/pci/common.c b/arch/i386/pci/common.c deleted file mode 100644 index ebc6f3c6634..00000000000 --- a/arch/i386/pci/common.c +++ /dev/null @@ -1,480 +0,0 @@ -/* - * Low-Level PCI Support for PC - * - * (c) 1999--2000 Martin Mares - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "pci.h" - -unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 | - PCI_PROBE_MMCONF; - -static int pci_bf_sort; -int pci_routeirq; -int pcibios_last_bus = -1; -unsigned long pirq_table_addr; -struct pci_bus *pci_root_bus; -struct pci_raw_ops *raw_pci_ops; - -static int pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) -{ - return raw_pci_ops->read(0, bus->number, devfn, where, size, value); -} - -static int pci_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) -{ - return raw_pci_ops->write(0, bus->number, devfn, where, size, value); -} - -struct pci_ops pci_root_ops = { - .read = pci_read, - .write = pci_write, -}; - -/* - * legacy, numa, and acpi all want to call pcibios_scan_root - * from their initcalls. This flag prevents that. - */ -int pcibios_scanned; - -/* - * This interrupt-safe spinlock protects all accesses to PCI - * configuration space. - */ -DEFINE_SPINLOCK(pci_config_lock); - -/* - * Several buggy motherboards address only 16 devices and mirror - * them to next 16 IDs. We try to detect this `feature' on all - * primary buses (those containing host bridges as they are - * expected to be unique) and remove the ghost devices. - */ - -static void __devinit pcibios_fixup_ghosts(struct pci_bus *b) -{ - struct list_head *ln, *mn; - struct pci_dev *d, *e; - int mirror = PCI_DEVFN(16,0); - int seen_host_bridge = 0; - int i; - - DBG("PCI: Scanning for ghost devices on bus %d\n", b->number); - list_for_each(ln, &b->devices) { - d = pci_dev_b(ln); - if ((d->class >> 8) == PCI_CLASS_BRIDGE_HOST) - seen_host_bridge++; - for (mn=ln->next; mn != &b->devices; mn=mn->next) { - e = pci_dev_b(mn); - if (e->devfn != d->devfn + mirror || - e->vendor != d->vendor || - e->device != d->device || - e->class != d->class) - continue; - for(i=0; iresource[i].start != d->resource[i].start || - e->resource[i].end != d->resource[i].end || - e->resource[i].flags != d->resource[i].flags) - continue; - break; - } - if (mn == &b->devices) - return; - } - if (!seen_host_bridge) - return; - printk(KERN_WARNING "PCI: Ignoring ghost devices on bus %02x\n", b->number); - - ln = &b->devices; - while (ln->next != &b->devices) { - d = pci_dev_b(ln->next); - if (d->devfn >= mirror) { - list_del(&d->global_list); - list_del(&d->bus_list); - kfree(d); - } else - ln = ln->next; - } -} - -/* - * Called after each bus is probed, but before its children - * are examined. - */ - -void __devinit pcibios_fixup_bus(struct pci_bus *b) -{ - pcibios_fixup_ghosts(b); - pci_read_bridge_bases(b); -} - -/* - * Only use DMI information to set this if nothing was passed - * on the kernel command line (which was parsed earlier). - */ - -static int __devinit set_bf_sort(struct dmi_system_id *d) -{ - if (pci_bf_sort == pci_bf_sort_default) { - pci_bf_sort = pci_dmi_bf; - printk(KERN_INFO "PCI: %s detected, enabling pci=bfsort.\n", d->ident); - } - return 0; -} - -/* - * Enable renumbering of PCI bus# ranges to reach all PCI busses (Cardbus) - */ -#ifdef __i386__ -static int __devinit assign_all_busses(struct dmi_system_id *d) -{ - pci_probe |= PCI_ASSIGN_ALL_BUSSES; - printk(KERN_INFO "%s detected: enabling PCI bus# renumbering" - " (pci=assign-busses)\n", d->ident); - return 0; -} -#endif - -static struct dmi_system_id __devinitdata pciprobe_dmi_table[] = { -#ifdef __i386__ -/* - * Laptops which need pci=assign-busses to see Cardbus cards - */ - { - .callback = assign_all_busses, - .ident = "Samsung X20 Laptop", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Samsung Electronics"), - DMI_MATCH(DMI_PRODUCT_NAME, "SX20S"), - }, - }, -#endif /* __i386__ */ - { - .callback = set_bf_sort, - .ident = "Dell PowerEdge 1950", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell"), - DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1950"), - }, - }, - { - .callback = set_bf_sort, - .ident = "Dell PowerEdge 1955", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell"), - DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1955"), - }, - }, - { - .callback = set_bf_sort, - .ident = "Dell PowerEdge 2900", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell"), - DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2900"), - }, - }, - { - .callback = set_bf_sort, - .ident = "Dell PowerEdge 2950", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell"), - DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2950"), - }, - }, - { - .callback = set_bf_sort, - .ident = "Dell PowerEdge R900", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell"), - DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge R900"), - }, - }, - { - .callback = set_bf_sort, - .ident = "HP ProLiant BL20p G3", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "HP"), - DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL20p G3"), - }, - }, - { - .callback = set_bf_sort, - .ident = "HP ProLiant BL20p G4", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "HP"), - DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL20p G4"), - }, - }, - { - .callback = set_bf_sort, - .ident = "HP ProLiant BL30p G1", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "HP"), - DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL30p G1"), - }, - }, - { - .callback = set_bf_sort, - .ident = "HP ProLiant BL25p G1", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "HP"), - DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL25p G1"), - }, - }, - { - .callback = set_bf_sort, - .ident = "HP ProLiant BL35p G1", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "HP"), - DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL35p G1"), - }, - }, - { - .callback = set_bf_sort, - .ident = "HP ProLiant BL45p G1", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "HP"), - DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL45p G1"), - }, - }, - { - .callback = set_bf_sort, - .ident = "HP ProLiant BL45p G2", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "HP"), - DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL45p G2"), - }, - }, - { - .callback = set_bf_sort, - .ident = "HP ProLiant BL460c G1", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "HP"), - DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL460c G1"), - }, - }, - { - .callback = set_bf_sort, - .ident = "HP ProLiant BL465c G1", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "HP"), - DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL465c G1"), - }, - }, - { - .callback = set_bf_sort, - .ident = "HP ProLiant BL480c G1", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "HP"), - DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL480c G1"), - }, - }, - { - .callback = set_bf_sort, - .ident = "HP ProLiant BL685c G1", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "HP"), - DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL685c G1"), - }, - }, - {} -}; - -struct pci_bus * __devinit pcibios_scan_root(int busnum) -{ - struct pci_bus *bus = NULL; - struct pci_sysdata *sd; - - dmi_check_system(pciprobe_dmi_table); - - while ((bus = pci_find_next_bus(bus)) != NULL) { - if (bus->number == busnum) { - /* Already scanned */ - return bus; - } - } - - /* Allocate per-root-bus (not per bus) arch-specific data. - * TODO: leak; this memory is never freed. - * It's arguable whether it's worth the trouble to care. - */ - sd = kzalloc(sizeof(*sd), GFP_KERNEL); - if (!sd) { - printk(KERN_ERR "PCI: OOM, not probing PCI bus %02x\n", busnum); - return NULL; - } - - printk(KERN_DEBUG "PCI: Probing PCI hardware (bus %02x)\n", busnum); - - return pci_scan_bus_parented(NULL, busnum, &pci_root_ops, sd); -} - -extern u8 pci_cache_line_size; - -static int __init pcibios_init(void) -{ - struct cpuinfo_x86 *c = &boot_cpu_data; - - if (!raw_pci_ops) { - printk(KERN_WARNING "PCI: System does not support PCI\n"); - return 0; - } - - /* - * Assume PCI cacheline size of 32 bytes for all x86s except K7/K8 - * and P4. It's also good for 386/486s (which actually have 16) - * as quite a few PCI devices do not support smaller values. - */ - pci_cache_line_size = 32 >> 2; - if (c->x86 >= 6 && c->x86_vendor == X86_VENDOR_AMD) - pci_cache_line_size = 64 >> 2; /* K7 & K8 */ - else if (c->x86 > 6 && c->x86_vendor == X86_VENDOR_INTEL) - pci_cache_line_size = 128 >> 2; /* P4 */ - - pcibios_resource_survey(); - - if (pci_bf_sort >= pci_force_bf) - pci_sort_breadthfirst(); -#ifdef CONFIG_PCI_BIOS - if ((pci_probe & PCI_BIOS_SORT) && !(pci_probe & PCI_NO_SORT)) - pcibios_sort(); -#endif - return 0; -} - -subsys_initcall(pcibios_init); - -char * __devinit pcibios_setup(char *str) -{ - if (!strcmp(str, "off")) { - pci_probe = 0; - return NULL; - } else if (!strcmp(str, "bfsort")) { - pci_bf_sort = pci_force_bf; - return NULL; - } else if (!strcmp(str, "nobfsort")) { - pci_bf_sort = pci_force_nobf; - return NULL; - } -#ifdef CONFIG_PCI_BIOS - else if (!strcmp(str, "bios")) { - pci_probe = PCI_PROBE_BIOS; - return NULL; - } else if (!strcmp(str, "nobios")) { - pci_probe &= ~PCI_PROBE_BIOS; - return NULL; - } else if (!strcmp(str, "nosort")) { - pci_probe |= PCI_NO_SORT; - return NULL; - } else if (!strcmp(str, "biosirq")) { - pci_probe |= PCI_BIOS_IRQ_SCAN; - return NULL; - } else if (!strncmp(str, "pirqaddr=", 9)) { - pirq_table_addr = simple_strtoul(str+9, NULL, 0); - return NULL; - } -#endif -#ifdef CONFIG_PCI_DIRECT - else if (!strcmp(str, "conf1")) { - pci_probe = PCI_PROBE_CONF1 | PCI_NO_CHECKS; - return NULL; - } - else if (!strcmp(str, "conf2")) { - pci_probe = PCI_PROBE_CONF2 | PCI_NO_CHECKS; - return NULL; - } -#endif -#ifdef CONFIG_PCI_MMCONFIG - else if (!strcmp(str, "nommconf")) { - pci_probe &= ~PCI_PROBE_MMCONF; - return NULL; - } -#endif - else if (!strcmp(str, "noacpi")) { - acpi_noirq_set(); - return NULL; - } - else if (!strcmp(str, "noearly")) { - pci_probe |= PCI_PROBE_NOEARLY; - return NULL; - } -#ifndef CONFIG_X86_VISWS - else if (!strcmp(str, "usepirqmask")) { - pci_probe |= PCI_USE_PIRQ_MASK; - return NULL; - } else if (!strncmp(str, "irqmask=", 8)) { - pcibios_irq_mask = simple_strtol(str+8, NULL, 0); - return NULL; - } else if (!strncmp(str, "lastbus=", 8)) { - pcibios_last_bus = simple_strtol(str+8, NULL, 0); - return NULL; - } -#endif - else if (!strcmp(str, "rom")) { - pci_probe |= PCI_ASSIGN_ROMS; - return NULL; - } else if (!strcmp(str, "assign-busses")) { - pci_probe |= PCI_ASSIGN_ALL_BUSSES; - return NULL; - } else if (!strcmp(str, "routeirq")) { - pci_routeirq = 1; - return NULL; - } - return str; -} - -unsigned int pcibios_assign_all_busses(void) -{ - return (pci_probe & PCI_ASSIGN_ALL_BUSSES) ? 1 : 0; -} - -int pcibios_enable_device(struct pci_dev *dev, int mask) -{ - int err; - - if ((err = pcibios_enable_resources(dev, mask)) < 0) - return err; - - if (!dev->msi_enabled) - return pcibios_enable_irq(dev); - return 0; -} - -void pcibios_disable_device (struct pci_dev *dev) -{ - if (!dev->msi_enabled && pcibios_disable_irq) - pcibios_disable_irq(dev); -} - -struct pci_bus *pci_scan_bus_with_sysdata(int busno) -{ - struct pci_bus *bus = NULL; - struct pci_sysdata *sd; - - /* - * Allocate per-root-bus (not per bus) arch-specific data. - * TODO: leak; this memory is never freed. - * It's arguable whether it's worth the trouble to care. - */ - sd = kzalloc(sizeof(*sd), GFP_KERNEL); - if (!sd) { - printk(KERN_ERR "PCI: OOM, skipping PCI bus %02x\n", busno); - return NULL; - } - sd->node = -1; - bus = pci_scan_bus(busno, &pci_root_ops, sd); - if (!bus) - kfree(sd); - - return bus; -} diff --git a/arch/i386/pci/direct.c b/arch/i386/pci/direct.c deleted file mode 100644 index 431c9a51b15..00000000000 --- a/arch/i386/pci/direct.c +++ /dev/null @@ -1,302 +0,0 @@ -/* - * direct.c - Low-level direct PCI config space access - */ - -#include -#include -#include -#include "pci.h" - -/* - * Functions for accessing PCI configuration space with type 1 accesses - */ - -#define PCI_CONF1_ADDRESS(bus, devfn, reg) \ - (0x80000000 | (bus << 16) | (devfn << 8) | (reg & ~3)) - -int pci_conf1_read(unsigned int seg, unsigned int bus, - unsigned int devfn, int reg, int len, u32 *value) -{ - unsigned long flags; - - if ((bus > 255) || (devfn > 255) || (reg > 255)) { - *value = -1; - return -EINVAL; - } - - spin_lock_irqsave(&pci_config_lock, flags); - - outl(PCI_CONF1_ADDRESS(bus, devfn, reg), 0xCF8); - - switch (len) { - case 1: - *value = inb(0xCFC + (reg & 3)); - break; - case 2: - *value = inw(0xCFC + (reg & 2)); - break; - case 4: - *value = inl(0xCFC); - break; - } - - spin_unlock_irqrestore(&pci_config_lock, flags); - - return 0; -} - -int pci_conf1_write(unsigned int seg, unsigned int bus, - unsigned int devfn, int reg, int len, u32 value) -{ - unsigned long flags; - - if ((bus > 255) || (devfn > 255) || (reg > 255)) - return -EINVAL; - - spin_lock_irqsave(&pci_config_lock, flags); - - outl(PCI_CONF1_ADDRESS(bus, devfn, reg), 0xCF8); - - switch (len) { - case 1: - outb((u8)value, 0xCFC + (reg & 3)); - break; - case 2: - outw((u16)value, 0xCFC + (reg & 2)); - break; - case 4: - outl((u32)value, 0xCFC); - break; - } - - spin_unlock_irqrestore(&pci_config_lock, flags); - - return 0; -} - -#undef PCI_CONF1_ADDRESS - -struct pci_raw_ops pci_direct_conf1 = { - .read = pci_conf1_read, - .write = pci_conf1_write, -}; - - -/* - * Functions for accessing PCI configuration space with type 2 accesses - */ - -#define PCI_CONF2_ADDRESS(dev, reg) (u16)(0xC000 | (dev << 8) | reg) - -static int pci_conf2_read(unsigned int seg, unsigned int bus, - unsigned int devfn, int reg, int len, u32 *value) -{ - unsigned long flags; - int dev, fn; - - if ((bus > 255) || (devfn > 255) || (reg > 255)) { - *value = -1; - return -EINVAL; - } - - dev = PCI_SLOT(devfn); - fn = PCI_FUNC(devfn); - - if (dev & 0x10) - return PCIBIOS_DEVICE_NOT_FOUND; - - spin_lock_irqsave(&pci_config_lock, flags); - - outb((u8)(0xF0 | (fn << 1)), 0xCF8); - outb((u8)bus, 0xCFA); - - switch (len) { - case 1: - *value = inb(PCI_CONF2_ADDRESS(dev, reg)); - break; - case 2: - *value = inw(PCI_CONF2_ADDRESS(dev, reg)); - break; - case 4: - *value = inl(PCI_CONF2_ADDRESS(dev, reg)); - break; - } - - outb(0, 0xCF8); - - spin_unlock_irqrestore(&pci_config_lock, flags); - - return 0; -} - -static int pci_conf2_write(unsigned int seg, unsigned int bus, - unsigned int devfn, int reg, int len, u32 value) -{ - unsigned long flags; - int dev, fn; - - if ((bus > 255) || (devfn > 255) || (reg > 255)) - return -EINVAL; - - dev = PCI_SLOT(devfn); - fn = PCI_FUNC(devfn); - - if (dev & 0x10) - return PCIBIOS_DEVICE_NOT_FOUND; - - spin_lock_irqsave(&pci_config_lock, flags); - - outb((u8)(0xF0 | (fn << 1)), 0xCF8); - outb((u8)bus, 0xCFA); - - switch (len) { - case 1: - outb((u8)value, PCI_CONF2_ADDRESS(dev, reg)); - break; - case 2: - outw((u16)value, PCI_CONF2_ADDRESS(dev, reg)); - break; - case 4: - outl((u32)value, PCI_CONF2_ADDRESS(dev, reg)); - break; - } - - outb(0, 0xCF8); - - spin_unlock_irqrestore(&pci_config_lock, flags); - - return 0; -} - -#undef PCI_CONF2_ADDRESS - -static struct pci_raw_ops pci_direct_conf2 = { - .read = pci_conf2_read, - .write = pci_conf2_write, -}; - - -/* - * Before we decide to use direct hardware access mechanisms, we try to do some - * trivial checks to ensure it at least _seems_ to be working -- we just test - * whether bus 00 contains a host bridge (this is similar to checking - * techniques used in XFree86, but ours should be more reliable since we - * attempt to make use of direct access hints provided by the PCI BIOS). - * - * This should be close to trivial, but it isn't, because there are buggy - * chipsets (yes, you guessed it, by Intel and Compaq) that have no class ID. - */ -static int __init pci_sanity_check(struct pci_raw_ops *o) -{ - u32 x = 0; - int devfn; - - if (pci_probe & PCI_NO_CHECKS) - return 1; - /* Assume Type 1 works for newer systems. - This handles machines that don't have anything on PCI Bus 0. */ - if (dmi_get_year(DMI_BIOS_DATE) >= 2001) - return 1; - - for (devfn = 0; devfn < 0x100; devfn++) { - if (o->read(0, 0, devfn, PCI_CLASS_DEVICE, 2, &x)) - continue; - if (x == PCI_CLASS_BRIDGE_HOST || x == PCI_CLASS_DISPLAY_VGA) - return 1; - - if (o->read(0, 0, devfn, PCI_VENDOR_ID, 2, &x)) - continue; - if (x == PCI_VENDOR_ID_INTEL || x == PCI_VENDOR_ID_COMPAQ) - return 1; - } - - DBG(KERN_WARNING "PCI: Sanity check failed\n"); - return 0; -} - -static int __init pci_check_type1(void) -{ - unsigned long flags; - unsigned int tmp; - int works = 0; - - local_irq_save(flags); - - outb(0x01, 0xCFB); - tmp = inl(0xCF8); - outl(0x80000000, 0xCF8); - if (inl(0xCF8) == 0x80000000 && pci_sanity_check(&pci_direct_conf1)) { - works = 1; - } - outl(tmp, 0xCF8); - local_irq_restore(flags); - - return works; -} - -static int __init pci_check_type2(void) -{ - unsigned long flags; - int works = 0; - - local_irq_save(flags); - - outb(0x00, 0xCFB); - outb(0x00, 0xCF8); - outb(0x00, 0xCFA); - if (inb(0xCF8) == 0x00 && inb(0xCFA) == 0x00 && - pci_sanity_check(&pci_direct_conf2)) { - works = 1; - } - - local_irq_restore(flags); - - return works; -} - -void __init pci_direct_init(int type) -{ - if (type == 0) - return; - printk(KERN_INFO "PCI: Using configuration type %d\n", type); - if (type == 1) - raw_pci_ops = &pci_direct_conf1; - else - raw_pci_ops = &pci_direct_conf2; -} - -int __init pci_direct_probe(void) -{ - struct resource *region, *region2; - - if ((pci_probe & PCI_PROBE_CONF1) == 0) - goto type2; - region = request_region(0xCF8, 8, "PCI conf1"); - if (!region) - goto type2; - - if (pci_check_type1()) - return 1; - release_resource(region); - - type2: - if ((pci_probe & PCI_PROBE_CONF2) == 0) - return 0; - region = request_region(0xCF8, 4, "PCI conf2"); - if (!region) - return 0; - region2 = request_region(0xC000, 0x1000, "PCI conf2"); - if (!region2) - goto fail2; - - if (pci_check_type2()) { - printk(KERN_INFO "PCI: Using configuration type 2\n"); - raw_pci_ops = &pci_direct_conf2; - return 2; - } - - release_resource(region2); - fail2: - release_resource(region); - return 0; -} diff --git a/arch/i386/pci/early.c b/arch/i386/pci/early.c deleted file mode 100644 index 42df4b6606d..00000000000 --- a/arch/i386/pci/early.c +++ /dev/null @@ -1,59 +0,0 @@ -#include -#include -#include -#include -#include "pci.h" - -/* Direct PCI access. This is used for PCI accesses in early boot before - the PCI subsystem works. */ - -#define PDprintk(x...) - -u32 read_pci_config(u8 bus, u8 slot, u8 func, u8 offset) -{ - u32 v; - outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8); - v = inl(0xcfc); - if (v != 0xffffffff) - PDprintk("%x reading 4 from %x: %x\n", slot, offset, v); - return v; -} - -u8 read_pci_config_byte(u8 bus, u8 slot, u8 func, u8 offset) -{ - u8 v; - outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8); - v = inb(0xcfc + (offset&3)); - PDprintk("%x reading 1 from %x: %x\n", slot, offset, v); - return v; -} - -u16 read_pci_config_16(u8 bus, u8 slot, u8 func, u8 offset) -{ - u16 v; - outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8); - v = inw(0xcfc + (offset&2)); - PDprintk("%x reading 2 from %x: %x\n", slot, offset, v); - return v; -} - -void write_pci_config(u8 bus, u8 slot, u8 func, u8 offset, - u32 val) -{ - PDprintk("%x writing to %x: %x\n", slot, offset, val); - outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8); - outl(val, 0xcfc); -} - -void write_pci_config_byte(u8 bus, u8 slot, u8 func, u8 offset, u8 val) -{ - PDprintk("%x writing to %x: %x\n", slot, offset, val); - outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8); - outb(val, 0xcfc); -} - -int early_pci_allowed(void) -{ - return (pci_probe & (PCI_PROBE_CONF1|PCI_PROBE_NOEARLY)) == - PCI_PROBE_CONF1; -} diff --git a/arch/i386/pci/fixup.c b/arch/i386/pci/fixup.c deleted file mode 100644 index c82cbf4c722..00000000000 --- a/arch/i386/pci/fixup.c +++ /dev/null @@ -1,446 +0,0 @@ -/* - * Exceptions for specific devices. Usually work-arounds for fatal design flaws. - */ - -#include -#include -#include -#include -#include "pci.h" - - -static void __devinit pci_fixup_i450nx(struct pci_dev *d) -{ - /* - * i450NX -- Find and scan all secondary buses on all PXB's. - */ - int pxb, reg; - u8 busno, suba, subb; - - printk(KERN_WARNING "PCI: Searching for i450NX host bridges on %s\n", pci_name(d)); - reg = 0xd0; - for(pxb=0; pxb<2; pxb++) { - pci_read_config_byte(d, reg++, &busno); - pci_read_config_byte(d, reg++, &suba); - pci_read_config_byte(d, reg++, &subb); - DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb); - if (busno) - pci_scan_bus_with_sysdata(busno); /* Bus A */ - if (suba < subb) - pci_scan_bus_with_sysdata(suba+1); /* Bus B */ - } - pcibios_last_bus = -1; -} -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_fixup_i450nx); - -static void __devinit pci_fixup_i450gx(struct pci_dev *d) -{ - /* - * i450GX and i450KX -- Find and scan all secondary buses. - * (called separately for each PCI bridge found) - */ - u8 busno; - pci_read_config_byte(d, 0x4a, &busno); - printk(KERN_INFO "PCI: i440KX/GX host bridge %s: secondary bus %02x\n", pci_name(d), busno); - pci_scan_bus_with_sysdata(busno); - pcibios_last_bus = -1; -} -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454GX, pci_fixup_i450gx); - -static void __devinit pci_fixup_umc_ide(struct pci_dev *d) -{ - /* - * UM8886BF IDE controller sets region type bits incorrectly, - * therefore they look like memory despite of them being I/O. - */ - int i; - - printk(KERN_WARNING "PCI: Fixing base address flags for device %s\n", pci_name(d)); - for(i=0; i<4; i++) - d->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO; -} -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF, pci_fixup_umc_ide); - -static void __devinit pci_fixup_ncr53c810(struct pci_dev *d) -{ - /* - * NCR 53C810 returns class code 0 (at least on some systems). - * Fix class to be PCI_CLASS_STORAGE_SCSI - */ - if (!d->class) { - printk(KERN_WARNING "PCI: fixing NCR 53C810 class code for %s\n", pci_name(d)); - d->class = PCI_CLASS_STORAGE_SCSI << 8; - } -} -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C810, pci_fixup_ncr53c810); - -static void __devinit pci_fixup_latency(struct pci_dev *d) -{ - /* - * SiS 5597 and 5598 chipsets require latency timer set to - * at most 32 to avoid lockups. - */ - DBG("PCI: Setting max latency to 32\n"); - pcibios_max_latency = 32; -} -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, pci_fixup_latency); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5598, pci_fixup_latency); - -static void __devinit pci_fixup_piix4_acpi(struct pci_dev *d) -{ - /* - * PIIX4 ACPI device: hardwired IRQ9 - */ - d->irq = 9; -} -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, pci_fixup_piix4_acpi); - -/* - * Addresses issues with problems in the memory write queue timer in - * certain VIA Northbridges. This bugfix is per VIA's specifications, - * except for the KL133/KM133: clearing bit 5 on those Northbridges seems - * to trigger a bug in its integrated ProSavage video card, which - * causes screen corruption. We only clear bits 6 and 7 for that chipset, - * until VIA can provide us with definitive information on why screen - * corruption occurs, and what exactly those bits do. - * - * VIA 8363,8622,8361 Northbridges: - * - bits 5, 6, 7 at offset 0x55 need to be turned off - * VIA 8367 (KT266x) Northbridges: - * - bits 5, 6, 7 at offset 0x95 need to be turned off - * VIA 8363 rev 0x81/0x84 (KL133/KM133) Northbridges: - * - bits 6, 7 at offset 0x55 need to be turned off - */ - -#define VIA_8363_KL133_REVISION_ID 0x81 -#define VIA_8363_KM133_REVISION_ID 0x84 - -static void pci_fixup_via_northbridge_bug(struct pci_dev *d) -{ - u8 v; - int where = 0x55; - int mask = 0x1f; /* clear bits 5, 6, 7 by default */ - - if (d->device == PCI_DEVICE_ID_VIA_8367_0) { - /* fix pci bus latency issues resulted by NB bios error - it appears on bug free^Wreduced kt266x's bios forces - NB latency to zero */ - pci_write_config_byte(d, PCI_LATENCY_TIMER, 0); - - where = 0x95; /* the memory write queue timer register is - different for the KT266x's: 0x95 not 0x55 */ - } else if (d->device == PCI_DEVICE_ID_VIA_8363_0 && - (d->revision == VIA_8363_KL133_REVISION_ID || - d->revision == VIA_8363_KM133_REVISION_ID)) { - mask = 0x3f; /* clear only bits 6 and 7; clearing bit 5 - causes screen corruption on the KL133/KM133 */ - } - - pci_read_config_byte(d, where, &v); - if (v & ~mask) { - printk(KERN_WARNING "Disabling VIA memory write queue (PCI ID %04x, rev %02x): [%02x] %02x & %02x -> %02x\n", \ - d->device, d->revision, where, v, mask, v & mask); - v &= mask; - pci_write_config_byte(d, where, v); - } -} -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, pci_fixup_via_northbridge_bug); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8622, pci_fixup_via_northbridge_bug); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8361, pci_fixup_via_northbridge_bug); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8367_0, pci_fixup_via_northbridge_bug); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, pci_fixup_via_northbridge_bug); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8622, pci_fixup_via_northbridge_bug); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8361, pci_fixup_via_northbridge_bug); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8367_0, pci_fixup_via_northbridge_bug); - -/* - * For some reasons Intel decided that certain parts of their - * 815, 845 and some other chipsets must look like PCI-to-PCI bridges - * while they are obviously not. The 82801 family (AA, AB, BAM/CAM, - * BA/CA/DB and E) PCI bridges are actually HUB-to-PCI ones, according - * to Intel terminology. These devices do forward all addresses from - * system to PCI bus no matter what are their window settings, so they are - * "transparent" (or subtractive decoding) from programmers point of view. - */ -static void __devinit pci_fixup_transparent_bridge(struct pci_dev *dev) -{ - if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI && - (dev->device & 0xff00) == 0x2400) - dev->transparent = 1; -} -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_fixup_transparent_bridge); - -/* - * Fixup for C1 Halt Disconnect problem on nForce2 systems. - * - * From information provided by "Allen Martin" : - * - * A hang is caused when the CPU generates a very fast CONNECT/HALT cycle - * sequence. Workaround is to set the SYSTEM_IDLE_TIMEOUT to 80 ns. - * This allows the state-machine and timer to return to a proper state within - * 80 ns of the CONNECT and probe appearing together. Since the CPU will not - * issue another HALT within 80 ns of the initial HALT, the failure condition - * is avoided. - */ -static void pci_fixup_nforce2(struct pci_dev *dev) -{ - u32 val; - - /* - * Chip Old value New value - * C17 0x1F0FFF01 0x1F01FF01 - * C18D 0x9F0FFF01 0x9F01FF01 - * - * Northbridge chip version may be determined by - * reading the PCI revision ID (0xC1 or greater is C18D). - */ - pci_read_config_dword(dev, 0x6c, &val); - - /* - * Apply fixup if needed, but don't touch disconnect state - */ - if ((val & 0x00FF0000) != 0x00010000) { - printk(KERN_WARNING "PCI: nForce2 C1 Halt Disconnect fixup\n"); - pci_write_config_dword(dev, 0x6c, (val & 0xFF00FFFF) | 0x00010000); - } -} -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2, pci_fixup_nforce2); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2, pci_fixup_nforce2); - -/* Max PCI Express root ports */ -#define MAX_PCIEROOT 6 -static int quirk_aspm_offset[MAX_PCIEROOT << 3]; - -#define GET_INDEX(a, b) ((((a) - PCI_DEVICE_ID_INTEL_MCH_PA) << 3) + ((b) & 7)) - -static int quirk_pcie_aspm_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) -{ - return raw_pci_ops->read(0, bus->number, devfn, where, size, value); -} - -/* - * Replace the original pci bus ops for write with a new one that will filter - * the request to insure ASPM cannot be enabled. - */ -static int quirk_pcie_aspm_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) -{ - u8 offset; - - offset = quirk_aspm_offset[GET_INDEX(bus->self->device, devfn)]; - - if ((offset) && (where == offset)) - value = value & 0xfffffffc; - - return raw_pci_ops->write(0, bus->number, devfn, where, size, value); -} - -static struct pci_ops quirk_pcie_aspm_ops = { - .read = quirk_pcie_aspm_read, - .write = quirk_pcie_aspm_write, -}; - -/* - * Prevents PCI Express ASPM (Active State Power Management) being enabled. - * - * Save the register offset, where the ASPM control bits are located, - * for each PCI Express device that is in the device list of - * the root port in an array for fast indexing. Replace the bus ops - * with the modified one. - */ -static void pcie_rootport_aspm_quirk(struct pci_dev *pdev) -{ - int cap_base, i; - struct pci_bus *pbus; - struct pci_dev *dev; - - if ((pbus = pdev->subordinate) == NULL) - return; - - /* - * Check if the DID of pdev matches one of the six root ports. This - * check is needed in the case this function is called directly by the - * hot-plug driver. - */ - if ((pdev->device < PCI_DEVICE_ID_INTEL_MCH_PA) || - (pdev->device > PCI_DEVICE_ID_INTEL_MCH_PC1)) - return; - - if (list_empty(&pbus->devices)) { - /* - * If no device is attached to the root port at power-up or - * after hot-remove, the pbus->devices is empty and this code - * will set the offsets to zero and the bus ops to parent's bus - * ops, which is unmodified. - */ - for (i= GET_INDEX(pdev->device, 0); i <= GET_INDEX(pdev->device, 7); ++i) - quirk_aspm_offset[i] = 0; - - pbus->ops = pbus->parent->ops; - } else { - /* - * If devices are attached to the root port at power-up or - * after hot-add, the code loops through the device list of - * each root port to save the register offsets and replace the - * bus ops. - */ - list_for_each_entry(dev, &pbus->devices, bus_list) { - /* There are 0 to 8 devices attached to this bus */ - cap_base = pci_find_capability(dev, PCI_CAP_ID_EXP); - quirk_aspm_offset[GET_INDEX(pdev->device, dev->devfn)]= cap_base + 0x10; - } - pbus->ops = &quirk_pcie_aspm_ops; - } -} -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PA, pcie_rootport_aspm_quirk ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PA1, pcie_rootport_aspm_quirk ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PB, pcie_rootport_aspm_quirk ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PB1, pcie_rootport_aspm_quirk ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PC, pcie_rootport_aspm_quirk ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PC1, pcie_rootport_aspm_quirk ); - -/* - * Fixup to mark boot BIOS video selected by BIOS before it changes - * - * From information provided by "Jon Smirl" - * - * The standard boot ROM sequence for an x86 machine uses the BIOS - * to select an initial video card for boot display. This boot video - * card will have it's BIOS copied to C0000 in system RAM. - * IORESOURCE_ROM_SHADOW is used to associate the boot video - * card with this copy. On laptops this copy has to be used since - * the main ROM may be compressed or combined with another image. - * See pci_map_rom() for use of this flag. IORESOURCE_ROM_SHADOW - * is marked here since the boot video device will be the only enabled - * video device at this point. - */ - -static void __devinit pci_fixup_video(struct pci_dev *pdev) -{ - struct pci_dev *bridge; - struct pci_bus *bus; - u16 config; - - if ((pdev->class >> 8) != PCI_CLASS_DISPLAY_VGA) - return; - - /* Is VGA routed to us? */ - bus = pdev->bus; - while (bus) { - bridge = bus->self; - - /* - * From information provided by - * "David Miller" - * The bridge control register is valid for PCI header - * type BRIDGE, or CARDBUS. Host to PCI controllers use - * PCI header type NORMAL. - */ - if (bridge - &&((bridge->hdr_type == PCI_HEADER_TYPE_BRIDGE) - ||(bridge->hdr_type == PCI_HEADER_TYPE_CARDBUS))) { - pci_read_config_word(bridge, PCI_BRIDGE_CONTROL, - &config); - if (!(config & PCI_BRIDGE_CTL_VGA)) - return; - } - bus = bus->parent; - } - pci_read_config_word(pdev, PCI_COMMAND, &config); - if (config & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) { - pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_SHADOW; - printk(KERN_DEBUG "Boot video device is %s\n", pci_name(pdev)); - } -} -DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_video); - -/* - * Some Toshiba laptops need extra code to enable their TI TSB43AB22/A. - * - * We pretend to bring them out of full D3 state, and restore the proper - * IRQ, PCI cache line size, and BARs, otherwise the device won't function - * properly. In some cases, the device will generate an interrupt on - * the wrong IRQ line, causing any devices sharing the line it's - * *supposed* to use to be disabled by the kernel's IRQ debug code. - */ -static u16 toshiba_line_size; - -static struct dmi_system_id __devinitdata toshiba_ohci1394_dmi_table[] = { - { - .ident = "Toshiba PS5 based laptop", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), - DMI_MATCH(DMI_PRODUCT_VERSION, "PS5"), - }, - }, - { - .ident = "Toshiba PSM4 based laptop", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), - DMI_MATCH(DMI_PRODUCT_VERSION, "PSM4"), - }, - }, - { - .ident = "Toshiba A40 based laptop", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), - DMI_MATCH(DMI_PRODUCT_VERSION, "PSA40U"), - }, - }, - { } -}; - -static void __devinit pci_pre_fixup_toshiba_ohci1394(struct pci_dev *dev) -{ - if (!dmi_check_system(toshiba_ohci1394_dmi_table)) - return; /* only applies to certain Toshibas (so far) */ - - dev->current_state = PCI_D3cold; - pci_read_config_word(dev, PCI_CACHE_LINE_SIZE, &toshiba_line_size); -} -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TI, 0x8032, - pci_pre_fixup_toshiba_ohci1394); - -static void __devinit pci_post_fixup_toshiba_ohci1394(struct pci_dev *dev) -{ - if (!dmi_check_system(toshiba_ohci1394_dmi_table)) - return; /* only applies to certain Toshibas (so far) */ - - /* Restore config space on Toshiba laptops */ - pci_write_config_word(dev, PCI_CACHE_LINE_SIZE, toshiba_line_size); - pci_read_config_byte(dev, PCI_INTERRUPT_LINE, (u8 *)&dev->irq); - pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, - pci_resource_start(dev, 0)); - pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, - pci_resource_start(dev, 1)); -} -DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_TI, 0x8032, - pci_post_fixup_toshiba_ohci1394); - - -/* - * Prevent the BIOS trapping accesses to the Cyrix CS5530A video device - * configuration space. - */ -static void pci_early_fixup_cyrix_5530(struct pci_dev *dev) -{ - u8 r; - /* clear 'F4 Video Configuration Trap' bit */ - pci_read_config_byte(dev, 0x42, &r); - r &= 0xfd; - pci_write_config_byte(dev, 0x42, r); -} -DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_LEGACY, - pci_early_fixup_cyrix_5530); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_LEGACY, - pci_early_fixup_cyrix_5530); - -/* - * Siemens Nixdorf AG FSC Multiprocessor Interrupt Controller: - * prevent update of the BAR0, which doesn't look like a normal BAR. - */ -static void __devinit pci_siemens_interrupt_controller(struct pci_dev *dev) -{ - dev->resource[0].flags |= IORESOURCE_PCI_FIXED; -} -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SIEMENS, 0x0015, - pci_siemens_interrupt_controller); diff --git a/arch/i386/pci/i386.c b/arch/i386/pci/i386.c deleted file mode 100644 index bcd2f94b732..00000000000 --- a/arch/i386/pci/i386.c +++ /dev/null @@ -1,315 +0,0 @@ -/* - * Low-Level PCI Access for i386 machines - * - * Copyright 1993, 1994 Drew Eckhardt - * Visionary Computing - * (Unix and Linux consulting and custom programming) - * Drew@Colorado.EDU - * +1 (303) 786-7975 - * - * Drew's work was sponsored by: - * iX Multiuser Multitasking Magazine - * Hannover, Germany - * hm@ix.de - * - * Copyright 1997--2000 Martin Mares - * - * For more information, please consult the following manuals (look at - * http://www.pcisig.com/ for how to get them): - * - * PCI BIOS Specification - * PCI Local Bus Specification - * PCI to PCI Bridge Specification - * PCI System Design Guide - * - */ - -#include -#include -#include -#include -#include -#include - -#include "pci.h" - -/* - * We need to avoid collisions with `mirrored' VGA ports - * and other strange ISA hardware, so we always want the - * addresses to be allocated in the 0x000-0x0ff region - * modulo 0x400. - * - * Why? Because some silly external IO cards only decode - * the low 10 bits of the IO address. The 0x00-0xff region - * is reserved for motherboard devices that decode all 16 - * bits, so it's ok to allocate at, say, 0x2800-0x28ff, - * but we want to try to avoid allocating at 0x2900-0x2bff - * which might have be mirrored at 0x0100-0x03ff.. - */ -void -pcibios_align_resource(void *data, struct resource *res, - resource_size_t size, resource_size_t align) -{ - if (res->flags & IORESOURCE_IO) { - resource_size_t start = res->start; - - if (start & 0x300) { - start = (start + 0x3ff) & ~0x3ff; - res->start = start; - } - } -} - - -/* - * Handle resources of PCI devices. If the world were perfect, we could - * just allocate all the resource regions and do nothing more. It isn't. - * On the other hand, we cannot just re-allocate all devices, as it would - * require us to know lots of host bridge internals. So we attempt to - * keep as much of the original configuration as possible, but tweak it - * when it's found to be wrong. - * - * Known BIOS problems we have to work around: - * - I/O or memory regions not configured - * - regions configured, but not enabled in the command register - * - bogus I/O addresses above 64K used - * - expansion ROMs left enabled (this may sound harmless, but given - * the fact the PCI specs explicitly allow address decoders to be - * shared between expansion ROMs and other resource regions, it's - * at least dangerous) - * - * Our solution: - * (1) Allocate resources for all buses behind PCI-to-PCI bridges. - * This gives us fixed barriers on where we can allocate. - * (2) Allocate resources for all enabled devices. If there is - * a collision, just mark the resource as unallocated. Also - * disable expansion ROMs during this step. - * (3) Try to allocate resources for disabled devices. If the - * resources were assigned correctly, everything goes well, - * if they weren't, they won't disturb allocation of other - * resources. - * (4) Assign new addresses to resources which were either - * not configured at all or misconfigured. If explicitly - * requested by the user, configure expansion ROM address - * as well. - */ - -static void __init pcibios_allocate_bus_resources(struct list_head *bus_list) -{ - struct pci_bus *bus; - struct pci_dev *dev; - int idx; - struct resource *r, *pr; - - /* Depth-First Search on bus tree */ - list_for_each_entry(bus, bus_list, node) { - if ((dev = bus->self)) { - for (idx = PCI_BRIDGE_RESOURCES; - idx < PCI_NUM_RESOURCES; idx++) { - r = &dev->resource[idx]; - if (!r->flags) - continue; - pr = pci_find_parent_resource(dev, r); - if (!r->start || !pr || - request_resource(pr, r) < 0) { - printk(KERN_ERR "PCI: Cannot allocate " - "resource region %d " - "of bridge %s\n", - idx, pci_name(dev)); - /* - * Something is wrong with the region. - * Invalidate the resource to prevent - * child resource allocations in this - * range. - */ - r->flags = 0; - } - } - } - pcibios_allocate_bus_resources(&bus->children); - } -} - -static void __init pcibios_allocate_resources(int pass) -{ - struct pci_dev *dev = NULL; - int idx, disabled; - u16 command; - struct resource *r, *pr; - - for_each_pci_dev(dev) { - pci_read_config_word(dev, PCI_COMMAND, &command); - for (idx = 0; idx < PCI_ROM_RESOURCE; idx++) { - r = &dev->resource[idx]; - if (r->parent) /* Already allocated */ - continue; - if (!r->start) /* Address not assigned at all */ - continue; - if (r->flags & IORESOURCE_IO) - disabled = !(command & PCI_COMMAND_IO); - else - disabled = !(command & PCI_COMMAND_MEMORY); - if (pass == disabled) { - DBG("PCI: Resource %08lx-%08lx " - "(f=%lx, d=%d, p=%d)\n", - r->start, r->end, r->flags, disabled, pass); - pr = pci_find_parent_resource(dev, r); - if (!pr || request_resource(pr, r) < 0) { - printk(KERN_ERR "PCI: Cannot allocate " - "resource region %d " - "of device %s\n", - idx, pci_name(dev)); - /* We'll assign a new address later */ - r->end -= r->start; - r->start = 0; - } - } - } - if (!pass) { - r = &dev->resource[PCI_ROM_RESOURCE]; - if (r->flags & IORESOURCE_ROM_ENABLE) { - /* Turn the ROM off, leave the resource region, - * but keep it unregistered. */ - u32 reg; - DBG("PCI: Switching off ROM of %s\n", - pci_name(dev)); - r->flags &= ~IORESOURCE_ROM_ENABLE; - pci_read_config_dword(dev, - dev->rom_base_reg, ®); - pci_write_config_dword(dev, dev->rom_base_reg, - reg & ~PCI_ROM_ADDRESS_ENABLE); - } - } - } -} - -static int __init pcibios_assign_resources(void) -{ - struct pci_dev *dev = NULL; - struct resource *r, *pr; - - if (!(pci_probe & PCI_ASSIGN_ROMS)) { - /* - * Try to use BIOS settings for ROMs, otherwise let - * pci_assign_unassigned_resources() allocate the new - * addresses. - */ - for_each_pci_dev(dev) { - r = &dev->resource[PCI_ROM_RESOURCE]; - if (!r->flags || !r->start) - continue; - pr = pci_find_parent_resource(dev, r); - if (!pr || request_resource(pr, r) < 0) { - r->end -= r->start; - r->start = 0; - } - } - } - - pci_assign_unassigned_resources(); - - return 0; -} - -void __init pcibios_resource_survey(void) -{ - DBG("PCI: Allocating resources\n"); - pcibios_allocate_bus_resources(&pci_root_buses); - pcibios_allocate_resources(0); - pcibios_allocate_resources(1); -} - -/** - * called in fs_initcall (one below subsys_initcall), - * give a chance for motherboard reserve resources - */ -fs_initcall(pcibios_assign_resources); - -int pcibios_enable_resources(struct pci_dev *dev, int mask) -{ - u16 cmd, old_cmd; - int idx; - struct resource *r; - - pci_read_config_word(dev, PCI_COMMAND, &cmd); - old_cmd = cmd; - for (idx = 0; idx < PCI_NUM_RESOURCES; idx++) { - /* Only set up the requested stuff */ - if (!(mask & (1 << idx))) - continue; - - r = &dev->resource[idx]; - if (!(r->flags & (IORESOURCE_IO | IORESOURCE_MEM))) - continue; - if ((idx == PCI_ROM_RESOURCE) && - (!(r->flags & IORESOURCE_ROM_ENABLE))) - continue; - if (!r->start && r->end) { - printk(KERN_ERR "PCI: Device %s not available " - "because of resource %d collisions\n", - pci_name(dev), idx); - return -EINVAL; - } - if (r->flags & IORESOURCE_IO) - cmd |= PCI_COMMAND_IO; - if (r->flags & IORESOURCE_MEM) - cmd |= PCI_COMMAND_MEMORY; - } - if (cmd != old_cmd) { - printk("PCI: Enabling device %s (%04x -> %04x)\n", - pci_name(dev), old_cmd, cmd); - pci_write_config_word(dev, PCI_COMMAND, cmd); - } - return 0; -} - -/* - * If we set up a device for bus mastering, we need to check the latency - * timer as certain crappy BIOSes forget to set it properly. - */ -unsigned int pcibios_max_latency = 255; - -void pcibios_set_master(struct pci_dev *dev) -{ - u8 lat; - pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); - if (lat < 16) - lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency; - else if (lat > pcibios_max_latency) - lat = pcibios_max_latency; - else - return; - printk(KERN_DEBUG "PCI: Setting latency timer of device %s to %d\n", - pci_name(dev), lat); - pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat); -} - -int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, - enum pci_mmap_state mmap_state, int write_combine) -{ - unsigned long prot; - - /* I/O space cannot be accessed via normal processor loads and - * stores on this platform. - */ - if (mmap_state == pci_mmap_io) - return -EINVAL; - - /* Leave vm_pgoff as-is, the PCI space address is the physical - * address on this platform. - */ - prot = pgprot_val(vma->vm_page_prot); - if (boot_cpu_data.x86 > 3) - prot |= _PAGE_PCD | _PAGE_PWT; - vma->vm_page_prot = __pgprot(prot); - - /* Write-combine setting is ignored, it is changed via the mtrr - * interfaces on this platform. - */ - if (io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, - vma->vm_end - vma->vm_start, - vma->vm_page_prot)) - return -EAGAIN; - - return 0; -} diff --git a/arch/i386/pci/init.c b/arch/i386/pci/init.c deleted file mode 100644 index 3de9f9ba2da..00000000000 --- a/arch/i386/pci/init.c +++ /dev/null @@ -1,37 +0,0 @@ -#include -#include -#include "pci.h" - -/* arch_initcall has too random ordering, so call the initializers - in the right sequence from here. */ -static __init int pci_access_init(void) -{ - int type __maybe_unused = 0; - -#ifdef CONFIG_PCI_DIRECT - type = pci_direct_probe(); -#endif -#ifdef CONFIG_PCI_MMCONFIG - pci_mmcfg_init(type); -#endif - if (raw_pci_ops) - return 0; -#ifdef CONFIG_PCI_BIOS - pci_pcbios_init(); -#endif - /* - * don't check for raw_pci_ops here because we want pcbios as last - * fallback, yet it's needed to run first to set pcibios_last_bus - * in case legacy PCI probing is used. otherwise detecting peer busses - * fails. - */ -#ifdef CONFIG_PCI_DIRECT - pci_direct_init(type); -#endif - if (!raw_pci_ops) - printk(KERN_ERR - "PCI: Fatal: No config space access function found\n"); - - return 0; -} -arch_initcall(pci_access_init); diff --git a/arch/i386/pci/irq.c b/arch/i386/pci/irq.c deleted file mode 100644 index 8434f2323b8..00000000000 --- a/arch/i386/pci/irq.c +++ /dev/null @@ -1,1173 +0,0 @@ -/* - * Low-Level PCI Support for PC -- Routing of Interrupts - * - * (c) 1999--2000 Martin Mares - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "pci.h" - -#define PIRQ_SIGNATURE (('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24)) -#define PIRQ_VERSION 0x0100 - -static int broken_hp_bios_irq9; -static int acer_tm360_irqrouting; - -static struct irq_routing_table *pirq_table; - -static int pirq_enable_irq(struct pci_dev *dev); - -/* - * Never use: 0, 1, 2 (timer, keyboard, and cascade) - * Avoid using: 13, 14 and 15 (FP error and IDE). - * Penalize: 3, 4, 6, 7, 12 (known ISA uses: serial, floppy, parallel and mouse) - */ -unsigned int pcibios_irq_mask = 0xfff8; - -static int pirq_penalty[16] = { - 1000000, 1000000, 1000000, 1000, 1000, 0, 1000, 1000, - 0, 0, 0, 0, 1000, 100000, 100000, 100000 -}; - -struct irq_router { - char *name; - u16 vendor, device; - int (*get)(struct pci_dev *router, struct pci_dev *dev, int pirq); - int (*set)(struct pci_dev *router, struct pci_dev *dev, int pirq, int new); -}; - -struct irq_router_handler { - u16 vendor; - int (*probe)(struct irq_router *r, struct pci_dev *router, u16 device); -}; - -int (*pcibios_enable_irq)(struct pci_dev *dev) = NULL; -void (*pcibios_disable_irq)(struct pci_dev *dev) = NULL; - -/* - * Check passed address for the PCI IRQ Routing Table signature - * and perform checksum verification. - */ - -static inline struct irq_routing_table * pirq_check_routing_table(u8 *addr) -{ - struct irq_routing_table *rt; - int i; - u8 sum; - - rt = (struct irq_routing_table *) addr; - if (rt->signature != PIRQ_SIGNATURE || - rt->version != PIRQ_VERSION || - rt->size % 16 || - rt->size < sizeof(struct irq_routing_table)) - return NULL; - sum = 0; - for (i=0; i < rt->size; i++) - sum += addr[i]; - if (!sum) { - DBG(KERN_DEBUG "PCI: Interrupt Routing Table found at 0x%p\n", rt); - return rt; - } - return NULL; -} - - - -/* - * Search 0xf0000 -- 0xfffff for the PCI IRQ Routing Table. - */ - -static struct irq_routing_table * __init pirq_find_routing_table(void) -{ - u8 *addr; - struct irq_routing_table *rt; - - if (pirq_table_addr) { - rt = pirq_check_routing_table((u8 *) __va(pirq_table_addr)); - if (rt) - return rt; - printk(KERN_WARNING "PCI: PIRQ table NOT found at pirqaddr\n"); - } - for(addr = (u8 *) __va(0xf0000); addr < (u8 *) __va(0x100000); addr += 16) { - rt = pirq_check_routing_table(addr); - if (rt) - return rt; - } - return NULL; -} - -/* - * If we have a IRQ routing table, use it to search for peer host - * bridges. It's a gross hack, but since there are no other known - * ways how to get a list of buses, we have to go this way. - */ - -static void __init pirq_peer_trick(void) -{ - struct irq_routing_table *rt = pirq_table; - u8 busmap[256]; - int i; - struct irq_info *e; - - memset(busmap, 0, sizeof(busmap)); - for(i=0; i < (rt->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info); i++) { - e = &rt->slots[i]; -#ifdef DEBUG - { - int j; - DBG(KERN_DEBUG "%02x:%02x slot=%02x", e->bus, e->devfn/8, e->slot); - for(j=0; j<4; j++) - DBG(" %d:%02x/%04x", j, e->irq[j].link, e->irq[j].bitmap); - DBG("\n"); - } -#endif - busmap[e->bus] = 1; - } - for(i = 1; i < 256; i++) { - if (!busmap[i] || pci_find_bus(0, i)) - continue; - if (pci_scan_bus_with_sysdata(i)) - printk(KERN_INFO "PCI: Discovered primary peer " - "bus %02x [IRQ]\n", i); - } - pcibios_last_bus = -1; -} - -/* - * Code for querying and setting of IRQ routes on various interrupt routers. - */ - -void eisa_set_level_irq(unsigned int irq) -{ - unsigned char mask = 1 << (irq & 7); - unsigned int port = 0x4d0 + (irq >> 3); - unsigned char val; - static u16 eisa_irq_mask; - - if (irq >= 16 || (1 << irq) & eisa_irq_mask) - return; - - eisa_irq_mask |= (1 << irq); - printk(KERN_DEBUG "PCI: setting IRQ %u as level-triggered\n", irq); - val = inb(port); - if (!(val & mask)) { - DBG(KERN_DEBUG " -> edge"); - outb(val | mask, port); - } -} - -/* - * Common IRQ routing practice: nybbles in config space, - * offset by some magic constant. - */ -static unsigned int read_config_nybble(struct pci_dev *router, unsigned offset, unsigned nr) -{ - u8 x; - unsigned reg = offset + (nr >> 1); - - pci_read_config_byte(router, reg, &x); - return (nr & 1) ? (x >> 4) : (x & 0xf); -} - -static void write_config_nybble(struct pci_dev *router, unsigned offset, unsigned nr, unsigned int val) -{ - u8 x; - unsigned reg = offset + (nr >> 1); - - pci_read_config_byte(router, reg, &x); - x = (nr & 1) ? ((x & 0x0f) | (val << 4)) : ((x & 0xf0) | val); - pci_write_config_byte(router, reg, x); -} - -/* - * ALI pirq entries are damn ugly, and completely undocumented. - * This has been figured out from pirq tables, and it's not a pretty - * picture. - */ -static int pirq_ali_get(struct pci_dev *router, struct pci_dev *dev, int pirq) -{ - static const unsigned char irqmap[16] = { 0, 9, 3, 10, 4, 5, 7, 6, 1, 11, 0, 12, 0, 14, 0, 15 }; - - return irqmap[read_config_nybble(router, 0x48, pirq-1)]; -} - -static int pirq_ali_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) -{ - static const unsigned char irqmap[16] = { 0, 8, 0, 2, 4, 5, 7, 6, 0, 1, 3, 9, 11, 0, 13, 15 }; - unsigned int val = irqmap[irq]; - - if (val) { - write_config_nybble(router, 0x48, pirq-1, val); - return 1; - } - return 0; -} - -/* - * The Intel PIIX4 pirq rules are fairly simple: "pirq" is - * just a pointer to the config space. - */ -static int pirq_piix_get(struct pci_dev *router, struct pci_dev *dev, int pirq) -{ - u8 x; - - pci_read_config_byte(router, pirq, &x); - return (x < 16) ? x : 0; -} - -static int pirq_piix_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) -{ - pci_write_config_byte(router, pirq, irq); - return 1; -} - -/* - * The VIA pirq rules are nibble-based, like ALI, - * but without the ugly irq number munging. - * However, PIRQD is in the upper instead of lower 4 bits. - */ -static int pirq_via_get(struct pci_dev *router, struct pci_dev *dev, int pirq) -{ - return read_config_nybble(router, 0x55, pirq == 4 ? 5 : pirq); -} - -static int pirq_via_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) -{ - write_config_nybble(router, 0x55, pirq == 4 ? 5 : pirq, irq); - return 1; -} - -/* - * The VIA pirq rules are nibble-based, like ALI, - * but without the ugly irq number munging. - * However, for 82C586, nibble map is different . - */ -static int pirq_via586_get(struct pci_dev *router, struct pci_dev *dev, int pirq) -{ - static const unsigned int pirqmap[5] = { 3, 2, 5, 1, 1 }; - return read_config_nybble(router, 0x55, pirqmap[pirq-1]); -} - -static int pirq_via586_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) -{ - static const unsigned int pirqmap[5] = { 3, 2, 5, 1, 1 }; - write_config_nybble(router, 0x55, pirqmap[pirq-1], irq); - return 1; -} - -/* - * ITE 8330G pirq rules are nibble-based - * FIXME: pirqmap may be { 1, 0, 3, 2 }, - * 2+3 are both mapped to irq 9 on my system - */ -static int pirq_ite_get(struct pci_dev *router, struct pci_dev *dev, int pirq) -{ - static const unsigned char pirqmap[4] = { 1, 0, 2, 3 }; - return read_config_nybble(router,0x43, pirqmap[pirq-1]); -} - -static int pirq_ite_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) -{ - static const unsigned char pirqmap[4] = { 1, 0, 2, 3 }; - write_config_nybble(router, 0x43, pirqmap[pirq-1], irq); - return 1; -} - -/* - * OPTI: high four bits are nibble pointer.. - * I wonder what the low bits do? - */ -static int pirq_opti_get(struct pci_dev *router, struct pci_dev *dev, int pirq) -{ - return read_config_nybble(router, 0xb8, pirq >> 4); -} - -static int pirq_opti_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) -{ - write_config_nybble(router, 0xb8, pirq >> 4, irq); - return 1; -} - -/* - * Cyrix: nibble offset 0x5C - * 0x5C bits 7:4 is INTB bits 3:0 is INTA - * 0x5D bits 7:4 is INTD bits 3:0 is INTC - */ -static int pirq_cyrix_get(struct pci_dev *router, struct pci_dev *dev, int pirq) -{ - return read_config_nybble(router, 0x5C, (pirq-1)^1); -} - -static int pirq_cyrix_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) -{ - write_config_nybble(router, 0x5C, (pirq-1)^1, irq); - return 1; -} - -/* - * PIRQ routing for SiS 85C503 router used in several SiS chipsets. - * We have to deal with the following issues here: - * - vendors have different ideas about the meaning of link values - * - some onboard devices (integrated in the chipset) have special - * links and are thus routed differently (i.e. not via PCI INTA-INTD) - * - different revision of the router have a different layout for - * the routing registers, particularly for the onchip devices - * - * For all routing registers the common thing is we have one byte - * per routeable link which is defined as: - * bit 7 IRQ mapping enabled (0) or disabled (1) - * bits [6:4] reserved (sometimes used for onchip devices) - * bits [3:0] IRQ to map to - * allowed: 3-7, 9-12, 14-15 - * reserved: 0, 1, 2, 8, 13 - * - * The config-space registers located at 0x41/0x42/0x43/0x44 are - * always used to route the normal PCI INT A/B/C/D respectively. - * Apparently there are systems implementing PCI routing table using - * link values 0x01-0x04 and others using 0x41-0x44 for PCI INTA..D. - * We try our best to handle both link mappings. - * - * Currently (2003-05-21) it appears most SiS chipsets follow the - * definition of routing registers from the SiS-5595 southbridge. - * According to the SiS 5595 datasheets the revision id's of the - * router (ISA-bridge) should be 0x01 or 0xb0. - * - * Furthermore we've also seen lspci dumps with revision 0x00 and 0xb1. - * Looks like these are used in a number of SiS 5xx/6xx/7xx chipsets. - * They seem to work with the current routing code. However there is - * some concern because of the two USB-OHCI HCs (original SiS 5595 - * had only one). YMMV. - * - * Onchip routing for router rev-id 0x01/0xb0 and probably 0x00/0xb1: - * - * 0x61: IDEIRQ: - * bits [6:5] must be written 01 - * bit 4 channel-select primary (0), secondary (1) - * - * 0x62: USBIRQ: - * bit 6 OHCI function disabled (0), enabled (1) - * - * 0x6a: ACPI/SCI IRQ: bits 4-6 reserved - * - * 0x7e: Data Acq. Module IRQ - bits 4-6 reserved - * - * We support USBIRQ (in addition to INTA-INTD) and keep the - * IDE, ACPI and DAQ routing untouched as set by the BIOS. - * - * Currently the only reported exception is the new SiS 65x chipset - * which includes the SiS 69x southbridge. Here we have the 85C503 - * router revision 0x04 and there are changes in the register layout - * mostly related to the different USB HCs with USB 2.0 support. - * - * Onchip routing for router rev-id 0x04 (try-and-error observation) - * - * 0x60/0x61/0x62/0x63: 1xEHCI and 3xOHCI (companion) USB-HCs - * bit 6-4 are probably unused, not like 5595 - */ - -#define PIRQ_SIS_IRQ_MASK 0x0f -#define PIRQ_SIS_IRQ_DISABLE 0x80 -#define PIRQ_SIS_USB_ENABLE 0x40 - -static int pirq_sis_get(struct pci_dev *router, struct pci_dev *dev, int pirq) -{ - u8 x; - int reg; - - reg = pirq; - if (reg >= 0x01 && reg <= 0x04) - reg += 0x40; - pci_read_config_byte(router, reg, &x); - return (x & PIRQ_SIS_IRQ_DISABLE) ? 0 : (x & PIRQ_SIS_IRQ_MASK); -} - -static int pirq_sis_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) -{ - u8 x; - int reg; - - reg = pirq; - if (reg >= 0x01 && reg <= 0x04) - reg += 0x40; - pci_read_config_byte(router, reg, &x); - x &= ~(PIRQ_SIS_IRQ_MASK | PIRQ_SIS_IRQ_DISABLE); - x |= irq ? irq: PIRQ_SIS_IRQ_DISABLE; - pci_write_config_byte(router, reg, x); - return 1; -} - - -/* - * VLSI: nibble offset 0x74 - educated guess due to routing table and - * config space of VLSI 82C534 PCI-bridge/router (1004:0102) - * Tested on HP OmniBook 800 covering PIRQ 1, 2, 4, 8 for onboard - * devices, PIRQ 3 for non-pci(!) soundchip and (untested) PIRQ 6 - * for the busbridge to the docking station. - */ - -static int pirq_vlsi_get(struct pci_dev *router, struct pci_dev *dev, int pirq) -{ - if (pirq > 8) { - printk(KERN_INFO "VLSI router pirq escape (%d)\n", pirq); - return 0; - } - return read_config_nybble(router, 0x74, pirq-1); -} - -static int pirq_vlsi_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) -{ - if (pirq > 8) { - printk(KERN_INFO "VLSI router pirq escape (%d)\n", pirq); - return 0; - } - write_config_nybble(router, 0x74, pirq-1, irq); - return 1; -} - -/* - * ServerWorks: PCI interrupts mapped to system IRQ lines through Index - * and Redirect I/O registers (0x0c00 and 0x0c01). The Index register - * format is (PCIIRQ## | 0x10), e.g.: PCIIRQ10=0x1a. The Redirect - * register is a straight binary coding of desired PIC IRQ (low nibble). - * - * The 'link' value in the PIRQ table is already in the correct format - * for the Index register. There are some special index values: - * 0x00 for ACPI (SCI), 0x01 for USB, 0x02 for IDE0, 0x04 for IDE1, - * and 0x03 for SMBus. - */ -static int pirq_serverworks_get(struct pci_dev *router, struct pci_dev *dev, int pirq) -{ - outb_p(pirq, 0xc00); - return inb(0xc01) & 0xf; -} - -static int pirq_serverworks_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) -{ - outb_p(pirq, 0xc00); - outb_p(irq, 0xc01); - return 1; -} - -/* Support for AMD756 PCI IRQ Routing - * Jhon H. Caicedo - * Jun/21/2001 0.2.0 Release, fixed to use "nybble" functions... (jhcaiced) - * Jun/19/2001 Alpha Release 0.1.0 (jhcaiced) - * The AMD756 pirq rules are nibble-based - * offset 0x56 0-3 PIRQA 4-7 PIRQB - * offset 0x57 0-3 PIRQC 4-7 PIRQD - */ -static int pirq_amd756_get(struct pci_dev *router, struct pci_dev *dev, int pirq) -{ - u8 irq; - irq = 0; - if (pirq <= 4) - { - irq = read_config_nybble(router, 0x56, pirq - 1); - } - printk(KERN_INFO "AMD756: dev %04x:%04x, router pirq : %d get irq : %2d\n", - dev->vendor, dev->device, pirq, irq); - return irq; -} - -static int pirq_amd756_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) -{ - printk(KERN_INFO "AMD756: dev %04x:%04x, router pirq : %d SET irq : %2d\n", - dev->vendor, dev->device, pirq, irq); - if (pirq <= 4) - { - write_config_nybble(router, 0x56, pirq - 1, irq); - } - return 1; -} - -#ifdef CONFIG_PCI_BIOS - -static int pirq_bios_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) -{ - struct pci_dev *bridge; - int pin = pci_get_interrupt_pin(dev, &bridge); - return pcibios_set_irq_routing(bridge, pin, irq); -} - -#endif - -static __init int intel_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) -{ - static struct pci_device_id __initdata pirq_440gx[] = { - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443GX_0) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443GX_2) }, - { }, - }; - - /* 440GX has a proprietary PIRQ router -- don't use it */ - if (pci_dev_present(pirq_440gx)) - return 0; - - switch(device) - { - case PCI_DEVICE_ID_INTEL_82371FB_0: - case PCI_DEVICE_ID_INTEL_82371SB_0: - case PCI_DEVICE_ID_INTEL_82371AB_0: - case PCI_DEVICE_ID_INTEL_82371MX: - case PCI_DEVICE_ID_INTEL_82443MX_0: - case PCI_DEVICE_ID_INTEL_82801AA_0: - case PCI_DEVICE_ID_INTEL_82801AB_0: - case PCI_DEVICE_ID_INTEL_82801BA_0: - case PCI_DEVICE_ID_INTEL_82801BA_10: - case PCI_DEVICE_ID_INTEL_82801CA_0: - case PCI_DEVICE_ID_INTEL_82801CA_12: - case PCI_DEVICE_ID_INTEL_82801DB_0: - case PCI_DEVICE_ID_INTEL_82801E_0: - case PCI_DEVICE_ID_INTEL_82801EB_0: - case PCI_DEVICE_ID_INTEL_ESB_1: - case PCI_DEVICE_ID_INTEL_ICH6_0: - case PCI_DEVICE_ID_INTEL_ICH6_1: - case PCI_DEVICE_ID_INTEL_ICH7_0: - case PCI_DEVICE_ID_INTEL_ICH7_1: - case PCI_DEVICE_ID_INTEL_ICH7_30: - case PCI_DEVICE_ID_INTEL_ICH7_31: - case PCI_DEVICE_ID_INTEL_ESB2_0: - case PCI_DEVICE_ID_INTEL_ICH8_0: - case PCI_DEVICE_ID_INTEL_ICH8_1: - case PCI_DEVICE_ID_INTEL_ICH8_2: - case PCI_DEVICE_ID_INTEL_ICH8_3: - case PCI_DEVICE_ID_INTEL_ICH8_4: - case PCI_DEVICE_ID_INTEL_ICH9_0: - case PCI_DEVICE_ID_INTEL_ICH9_1: - case PCI_DEVICE_ID_INTEL_ICH9_2: - case PCI_DEVICE_ID_INTEL_ICH9_3: - case PCI_DEVICE_ID_INTEL_ICH9_4: - case PCI_DEVICE_ID_INTEL_ICH9_5: - case PCI_DEVICE_ID_INTEL_TOLAPAI_0: - r->name = "PIIX/ICH"; - r->get = pirq_piix_get; - r->set = pirq_piix_set; - return 1; - } - return 0; -} - -static __init int via_router_probe(struct irq_router *r, - struct pci_dev *router, u16 device) -{ - /* FIXME: We should move some of the quirk fixup stuff here */ - - /* - * work arounds for some buggy BIOSes - */ - if (device == PCI_DEVICE_ID_VIA_82C586_0) { - switch(router->device) { - case PCI_DEVICE_ID_VIA_82C686: - /* - * Asus k7m bios wrongly reports 82C686A - * as 586-compatible - */ - device = PCI_DEVICE_ID_VIA_82C686; - break; - case PCI_DEVICE_ID_VIA_8235: - /** - * Asus a7v-x bios wrongly reports 8235 - * as 586-compatible - */ - device = PCI_DEVICE_ID_VIA_8235; - break; - } - } - - switch(device) { - case PCI_DEVICE_ID_VIA_82C586_0: - r->name = "VIA"; - r->get = pirq_via586_get; - r->set = pirq_via586_set; - return 1; - case PCI_DEVICE_ID_VIA_82C596: - case PCI_DEVICE_ID_VIA_82C686: - case PCI_DEVICE_ID_VIA_8231: - case PCI_DEVICE_ID_VIA_8233A: - case PCI_DEVICE_ID_VIA_8235: - case PCI_DEVICE_ID_VIA_8237: - /* FIXME: add new ones for 8233/5 */ - r->name = "VIA"; - r->get = pirq_via_get; - r->set = pirq_via_set; - return 1; - } - return 0; -} - -static __init int vlsi_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) -{ - switch(device) - { - case PCI_DEVICE_ID_VLSI_82C534: - r->name = "VLSI 82C534"; - r->get = pirq_vlsi_get; - r->set = pirq_vlsi_set; - return 1; - } - return 0; -} - - -static __init int serverworks_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) -{ - switch(device) - { - case PCI_DEVICE_ID_SERVERWORKS_OSB4: - case PCI_DEVICE_ID_SERVERWORKS_CSB5: - r->name = "ServerWorks"; - r->get = pirq_serverworks_get; - r->set = pirq_serverworks_set; - return 1; - } - return 0; -} - -static __init int sis_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) -{ - if (device != PCI_DEVICE_ID_SI_503) - return 0; - - r->name = "SIS"; - r->get = pirq_sis_get; - r->set = pirq_sis_set; - return 1; -} - -static __init int cyrix_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) -{ - switch(device) - { - case PCI_DEVICE_ID_CYRIX_5520: - r->name = "NatSemi"; - r->get = pirq_cyrix_get; - r->set = pirq_cyrix_set; - return 1; - } - return 0; -} - -static __init int opti_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) -{ - switch(device) - { - case PCI_DEVICE_ID_OPTI_82C700: - r->name = "OPTI"; - r->get = pirq_opti_get; - r->set = pirq_opti_set; - return 1; - } - return 0; -} - -static __init int ite_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) -{ - switch(device) - { - case PCI_DEVICE_ID_ITE_IT8330G_0: - r->name = "ITE"; - r->get = pirq_ite_get; - r->set = pirq_ite_set; - return 1; - } - return 0; -} - -static __init int ali_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) -{ - switch(device) - { - case PCI_DEVICE_ID_AL_M1533: - case PCI_DEVICE_ID_AL_M1563: - printk(KERN_DEBUG "PCI: Using ALI IRQ Router\n"); - r->name = "ALI"; - r->get = pirq_ali_get; - r->set = pirq_ali_set; - return 1; - } - return 0; -} - -static __init int amd_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) -{ - switch(device) - { - case PCI_DEVICE_ID_AMD_VIPER_740B: - r->name = "AMD756"; - break; - case PCI_DEVICE_ID_AMD_VIPER_7413: - r->name = "AMD766"; - break; - case PCI_DEVICE_ID_AMD_VIPER_7443: - r->name = "AMD768"; - break; - default: - return 0; - } - r->get = pirq_amd756_get; - r->set = pirq_amd756_set; - return 1; -} - -static __initdata struct irq_router_handler pirq_routers[] = { - { PCI_VENDOR_ID_INTEL, intel_router_probe }, - { PCI_VENDOR_ID_AL, ali_router_probe }, - { PCI_VENDOR_ID_ITE, ite_router_probe }, - { PCI_VENDOR_ID_VIA, via_router_probe }, - { PCI_VENDOR_ID_OPTI, opti_router_probe }, - { PCI_VENDOR_ID_SI, sis_router_probe }, - { PCI_VENDOR_ID_CYRIX, cyrix_router_probe }, - { PCI_VENDOR_ID_VLSI, vlsi_router_probe }, - { PCI_VENDOR_ID_SERVERWORKS, serverworks_router_probe }, - { PCI_VENDOR_ID_AMD, amd_router_probe }, - /* Someone with docs needs to add the ATI Radeon IGP */ - { 0, NULL } -}; -static struct irq_router pirq_router; -static struct pci_dev *pirq_router_dev; - - -/* - * FIXME: should we have an option to say "generic for - * chipset" ? - */ - -static void __init pirq_find_router(struct irq_router *r) -{ - struct irq_routing_table *rt = pirq_table; - struct irq_router_handler *h; - -#ifdef CONFIG_PCI_BIOS - if (!rt->signature) { - printk(KERN_INFO "PCI: Using BIOS for IRQ routing\n"); - r->set = pirq_bios_set; - r->name = "BIOS"; - return; - } -#endif - - /* Default unless a driver reloads it */ - r->name = "default"; - r->get = NULL; - r->set = NULL; - - DBG(KERN_DEBUG "PCI: Attempting to find IRQ router for %04x:%04x\n", - rt->rtr_vendor, rt->rtr_device); - - pirq_router_dev = pci_get_bus_and_slot(rt->rtr_bus, rt->rtr_devfn); - if (!pirq_router_dev) { - DBG(KERN_DEBUG "PCI: Interrupt router not found at " - "%02x:%02x\n", rt->rtr_bus, rt->rtr_devfn); - return; - } - - for( h = pirq_routers; h->vendor; h++) { - /* First look for a router match */ - if (rt->rtr_vendor == h->vendor && h->probe(r, pirq_router_dev, rt->rtr_device)) - break; - /* Fall back to a device match */ - if (pirq_router_dev->vendor == h->vendor && h->probe(r, pirq_router_dev, pirq_router_dev->device)) - break; - } - printk(KERN_INFO "PCI: Using IRQ router %s [%04x/%04x] at %s\n", - pirq_router.name, - pirq_router_dev->vendor, - pirq_router_dev->device, - pci_name(pirq_router_dev)); - - /* The device remains referenced for the kernel lifetime */ -} - -static struct irq_info *pirq_get_info(struct pci_dev *dev) -{ - struct irq_routing_table *rt = pirq_table; - int entries = (rt->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info); - struct irq_info *info; - - for (info = rt->slots; entries--; info++) - if (info->bus == dev->bus->number && PCI_SLOT(info->devfn) == PCI_SLOT(dev->devfn)) - return info; - return NULL; -} - -static int pcibios_lookup_irq(struct pci_dev *dev, int assign) -{ - u8 pin; - struct irq_info *info; - int i, pirq, newirq; - int irq = 0; - u32 mask; - struct irq_router *r = &pirq_router; - struct pci_dev *dev2 = NULL; - char *msg = NULL; - - /* Find IRQ pin */ - pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); - if (!pin) { - DBG(KERN_DEBUG " -> no interrupt pin\n"); - return 0; - } - pin = pin - 1; - - /* Find IRQ routing entry */ - - if (!pirq_table) - return 0; - - DBG(KERN_DEBUG "IRQ for %s[%c]", pci_name(dev), 'A' + pin); - info = pirq_get_info(dev); - if (!info) { - DBG(" -> not found in routing table\n" KERN_DEBUG); - return 0; - } - pirq = info->irq[pin].link; - mask = info->irq[pin].bitmap; - if (!pirq) { - DBG(" -> not routed\n" KERN_DEBUG); - return 0; - } - DBG(" -> PIRQ %02x, mask %04x, excl %04x", pirq, mask, pirq_table->exclusive_irqs); - mask &= pcibios_irq_mask; - - /* Work around broken HP Pavilion Notebooks which assign USB to - IRQ 9 even though it is actually wired to IRQ 11 */ - - if (broken_hp_bios_irq9 && pirq == 0x59 && dev->irq == 9) { - dev->irq = 11; - pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 11); - r->set(pirq_router_dev, dev, pirq, 11); - } - - /* same for Acer Travelmate 360, but with CB and irq 11 -> 10 */ - if (acer_tm360_irqrouting && dev->irq == 11 && dev->vendor == PCI_VENDOR_ID_O2) { - pirq = 0x68; - mask = 0x400; - dev->irq = r->get(pirq_router_dev, dev, pirq); - pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); - } - - /* - * Find the best IRQ to assign: use the one - * reported by the device if possible. - */ - newirq = dev->irq; - if (newirq && !((1 << newirq) & mask)) { - if ( pci_probe & PCI_USE_PIRQ_MASK) newirq = 0; - else printk("\n" KERN_WARNING - "PCI: IRQ %i for device %s doesn't match PIRQ mask " - "- try pci=usepirqmask\n" KERN_DEBUG, newirq, - pci_name(dev)); - } - if (!newirq && assign) { - for (i = 0; i < 16; i++) { - if (!(mask & (1 << i))) - continue; - if (pirq_penalty[i] < pirq_penalty[newirq] && can_request_irq(i, IRQF_SHARED)) - newirq = i; - } - } - DBG(" -> newirq=%d", newirq); - - /* Check if it is hardcoded */ - if ((pirq & 0xf0) == 0xf0) { - irq = pirq & 0xf; - DBG(" -> hardcoded IRQ %d\n", irq); - msg = "Hardcoded"; - } else if ( r->get && (irq = r->get(pirq_router_dev, dev, pirq)) && \ - ((!(pci_probe & PCI_USE_PIRQ_MASK)) || ((1 << irq) & mask)) ) { - DBG(" -> got IRQ %d\n", irq); - msg = "Found"; - eisa_set_level_irq(irq); - } else if (newirq && r->set && (dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) { - DBG(" -> assigning IRQ %d", newirq); - if (r->set(pirq_router_dev, dev, pirq, newirq)) { - eisa_set_level_irq(newirq); - DBG(" ... OK\n"); - msg = "Assigned"; - irq = newirq; - } - } - - if (!irq) { - DBG(" ... failed\n"); - if (newirq && mask == (1 << newirq)) { - msg = "Guessed"; - irq = newirq; - } else - return 0; - } - printk(KERN_INFO "PCI: %s IRQ %d for device %s\n", msg, irq, pci_name(dev)); - - /* Update IRQ for all devices with the same pirq value */ - while ((dev2 = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev2)) != NULL) { - pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin); - if (!pin) - continue; - pin--; - info = pirq_get_info(dev2); - if (!info) - continue; - if (info->irq[pin].link == pirq) { - /* We refuse to override the dev->irq information. Give a warning! */ - if ( dev2->irq && dev2->irq != irq && \ - (!(pci_probe & PCI_USE_PIRQ_MASK) || \ - ((1 << dev2->irq) & mask)) ) { -#ifndef CONFIG_PCI_MSI - printk(KERN_INFO "IRQ routing conflict for %s, have irq %d, want irq %d\n", - pci_name(dev2), dev2->irq, irq); -#endif - continue; - } - dev2->irq = irq; - pirq_penalty[irq]++; - if (dev != dev2) - printk(KERN_INFO "PCI: Sharing IRQ %d with %s\n", irq, pci_name(dev2)); - } - } - return 1; -} - -static void __init pcibios_fixup_irqs(void) -{ - struct pci_dev *dev = NULL; - u8 pin; - - DBG(KERN_DEBUG "PCI: IRQ fixup\n"); - while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { - /* - * If the BIOS has set an out of range IRQ number, just ignore it. - * Also keep track of which IRQ's are already in use. - */ - if (dev->irq >= 16) { - DBG(KERN_DEBUG "%s: ignoring bogus IRQ %d\n", pci_name(dev), dev->irq); - dev->irq = 0; - } - /* If the IRQ is already assigned to a PCI device, ignore its ISA use penalty */ - if (pirq_penalty[dev->irq] >= 100 && pirq_penalty[dev->irq] < 100000) - pirq_penalty[dev->irq] = 0; - pirq_penalty[dev->irq]++; - } - - dev = NULL; - while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { - pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); -#ifdef CONFIG_X86_IO_APIC - /* - * Recalculate IRQ numbers if we use the I/O APIC. - */ - if (io_apic_assign_pci_irqs) - { - int irq; - - if (pin) { - pin--; /* interrupt pins are numbered starting from 1 */ - irq = IO_APIC_get_PCI_irq_vector(dev->bus->number, PCI_SLOT(dev->devfn), pin); - /* - * Busses behind bridges are typically not listed in the MP-table. - * In this case we have to look up the IRQ based on the parent bus, - * parent slot, and pin number. The SMP code detects such bridged - * busses itself so we should get into this branch reliably. - */ - if (irq < 0 && dev->bus->parent) { /* go back to the bridge */ - struct pci_dev * bridge = dev->bus->self; - - pin = (pin + PCI_SLOT(dev->devfn)) % 4; - irq = IO_APIC_get_PCI_irq_vector(bridge->bus->number, - PCI_SLOT(bridge->devfn), pin); - if (irq >= 0) - printk(KERN_WARNING "PCI: using PPB %s[%c] to get irq %d\n", - pci_name(bridge), 'A' + pin, irq); - } - if (irq >= 0) { - printk(KERN_INFO "PCI->APIC IRQ transform: %s[%c] -> IRQ %d\n", - pci_name(dev), 'A' + pin, irq); - dev->irq = irq; - } - } - } -#endif - /* - * Still no IRQ? Try to lookup one... - */ - if (pin && !dev->irq) - pcibios_lookup_irq(dev, 0); - } -} - -/* - * Work around broken HP Pavilion Notebooks which assign USB to - * IRQ 9 even though it is actually wired to IRQ 11 - */ -static int __init fix_broken_hp_bios_irq9(struct dmi_system_id *d) -{ - if (!broken_hp_bios_irq9) { - broken_hp_bios_irq9 = 1; - printk(KERN_INFO "%s detected - fixing broken IRQ routing\n", d->ident); - } - return 0; -} - -/* - * Work around broken Acer TravelMate 360 Notebooks which assign - * Cardbus to IRQ 11 even though it is actually wired to IRQ 10 - */ -static int __init fix_acer_tm360_irqrouting(struct dmi_system_id *d) -{ - if (!acer_tm360_irqrouting) { - acer_tm360_irqrouting = 1; - printk(KERN_INFO "%s detected - fixing broken IRQ routing\n", d->ident); - } - return 0; -} - -static struct dmi_system_id __initdata pciirq_dmi_table[] = { - { - .callback = fix_broken_hp_bios_irq9, - .ident = "HP Pavilion N5400 Series Laptop", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), - DMI_MATCH(DMI_BIOS_VERSION, "GE.M1.03"), - DMI_MATCH(DMI_PRODUCT_VERSION, "HP Pavilion Notebook Model GE"), - DMI_MATCH(DMI_BOARD_VERSION, "OmniBook N32N-736"), - }, - }, - { - .callback = fix_acer_tm360_irqrouting, - .ident = "Acer TravelMate 36x Laptop", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"), - }, - }, - { } -}; - -static int __init pcibios_irq_init(void) -{ - DBG(KERN_DEBUG "PCI: IRQ init\n"); - - if (pcibios_enable_irq || raw_pci_ops == NULL) - return 0; - - dmi_check_system(pciirq_dmi_table); - - pirq_table = pirq_find_routing_table(); - -#ifdef CONFIG_PCI_BIOS - if (!pirq_table && (pci_probe & PCI_BIOS_IRQ_SCAN)) - pirq_table = pcibios_get_irq_routing_table(); -#endif - if (pirq_table) { - pirq_peer_trick(); - pirq_find_router(&pirq_router); - if (pirq_table->exclusive_irqs) { - int i; - for (i=0; i<16; i++) - if (!(pirq_table->exclusive_irqs & (1 << i))) - pirq_penalty[i] += 100; - } - /* If we're using the I/O APIC, avoid using the PCI IRQ routing table */ - if (io_apic_assign_pci_irqs) - pirq_table = NULL; - } - - pcibios_enable_irq = pirq_enable_irq; - - pcibios_fixup_irqs(); - return 0; -} - -subsys_initcall(pcibios_irq_init); - - -static void pirq_penalize_isa_irq(int irq, int active) -{ - /* - * If any ISAPnP device reports an IRQ in its list of possible - * IRQ's, we try to avoid assigning it to PCI devices. - */ - if (irq < 16) { - if (active) - pirq_penalty[irq] += 1000; - else - pirq_penalty[irq] += 100; - } -} - -void pcibios_penalize_isa_irq(int irq, int active) -{ -#ifdef CONFIG_ACPI - if (!acpi_noirq) - acpi_penalize_isa_irq(irq, active); - else -#endif - pirq_penalize_isa_irq(irq, active); -} - -static int pirq_enable_irq(struct pci_dev *dev) -{ - u8 pin; - struct pci_dev *temp_dev; - - pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); - if (pin && !pcibios_lookup_irq(dev, 1) && !dev->irq) { - char *msg = ""; - - pin--; /* interrupt pins are numbered starting from 1 */ - - if (io_apic_assign_pci_irqs) { - int irq; - - irq = IO_APIC_get_PCI_irq_vector(dev->bus->number, PCI_SLOT(dev->devfn), pin); - /* - * Busses behind bridges are typically not listed in the MP-table. - * In this case we have to look up the IRQ based on the parent bus, - * parent slot, and pin number. The SMP code detects such bridged - * busses itself so we should get into this branch reliably. - */ - temp_dev = dev; - while (irq < 0 && dev->bus->parent) { /* go back to the bridge */ - struct pci_dev * bridge = dev->bus->self; - - pin = (pin + PCI_SLOT(dev->devfn)) % 4; - irq = IO_APIC_get_PCI_irq_vector(bridge->bus->number, - PCI_SLOT(bridge->devfn), pin); - if (irq >= 0) - printk(KERN_WARNING "PCI: using PPB %s[%c] to get irq %d\n", - pci_name(bridge), 'A' + pin, irq); - dev = bridge; - } - dev = temp_dev; - if (irq >= 0) { - printk(KERN_INFO "PCI->APIC IRQ transform: %s[%c] -> IRQ %d\n", - pci_name(dev), 'A' + pin, irq); - dev->irq = irq; - return 0; - } else - msg = " Probably buggy MP table."; - } else if (pci_probe & PCI_BIOS_IRQ_SCAN) - msg = ""; - else - msg = " Please try using pci=biosirq."; - - /* With IDE legacy devices the IRQ lookup failure is not a problem.. */ - if (dev->class >> 8 == PCI_CLASS_STORAGE_IDE && !(dev->class & 0x5)) - return 0; - - printk(KERN_WARNING "PCI: No IRQ known for interrupt pin %c of device %s.%s\n", - 'A' + pin, pci_name(dev), msg); - } - return 0; -} diff --git a/arch/i386/pci/legacy.c b/arch/i386/pci/legacy.c deleted file mode 100644 index 5565d7016b7..00000000000 --- a/arch/i386/pci/legacy.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * legacy.c - traditional, old school PCI bus probing - */ -#include -#include -#include "pci.h" - -/* - * Discover remaining PCI buses in case there are peer host bridges. - * We use the number of last PCI bus provided by the PCI BIOS. - */ -static void __devinit pcibios_fixup_peer_bridges(void) -{ - int n, devfn; - - if (pcibios_last_bus <= 0 || pcibios_last_bus >= 0xff) - return; - DBG("PCI: Peer bridge fixup\n"); - - for (n=0; n <= pcibios_last_bus; n++) { - u32 l; - if (pci_find_bus(0, n)) - continue; - for (devfn = 0; devfn < 256; devfn += 8) { - if (!raw_pci_ops->read(0, n, devfn, PCI_VENDOR_ID, 2, &l) && - l != 0x0000 && l != 0xffff) { - DBG("Found device at %02x:%02x [%04x]\n", n, devfn, l); - printk(KERN_INFO "PCI: Discovered peer bus %02x\n", n); - pci_scan_bus_with_sysdata(n); - break; - } - } - } -} - -static int __init pci_legacy_init(void) -{ - if (!raw_pci_ops) { - printk("PCI: System does not support PCI\n"); - return 0; - } - - if (pcibios_scanned++) - return 0; - - printk("PCI: Probing PCI hardware\n"); - pci_root_bus = pcibios_scan_root(0); - if (pci_root_bus) - pci_bus_add_devices(pci_root_bus); - - pcibios_fixup_peer_bridges(); - - return 0; -} - -subsys_initcall(pci_legacy_init); diff --git a/arch/i386/pci/mmconfig-shared.c b/arch/i386/pci/mmconfig-shared.c deleted file mode 100644 index 4df637e34f8..00000000000 --- a/arch/i386/pci/mmconfig-shared.c +++ /dev/null @@ -1,315 +0,0 @@ -/* - * mmconfig-shared.c - Low-level direct PCI config space access via - * MMCONFIG - common code between i386 and x86-64. - * - * This code does: - * - known chipset handling - * - ACPI decoding and validation - * - * Per-architecture code takes care of the mappings and accesses - * themselves. - */ - -#include -#include -#include -#include -#include - -#include "pci.h" - -/* aperture is up to 256MB but BIOS may reserve less */ -#define MMCONFIG_APER_MIN (2 * 1024*1024) -#define MMCONFIG_APER_MAX (256 * 1024*1024) - -DECLARE_BITMAP(pci_mmcfg_fallback_slots, 32*PCI_MMCFG_MAX_CHECK_BUS); - -/* Indicate if the mmcfg resources have been placed into the resource table. */ -static int __initdata pci_mmcfg_resources_inserted; - -/* K8 systems have some devices (typically in the builtin northbridge) - that are only accessible using type1 - Normally this can be expressed in the MCFG by not listing them - and assigning suitable _SEGs, but this isn't implemented in some BIOS. - Instead try to discover all devices on bus 0 that are unreachable using MM - and fallback for them. */ -static void __init unreachable_devices(void) -{ - int i, bus; - /* Use the max bus number from ACPI here? */ - for (bus = 0; bus < PCI_MMCFG_MAX_CHECK_BUS; bus++) { - for (i = 0; i < 32; i++) { - unsigned int devfn = PCI_DEVFN(i, 0); - u32 val1, val2; - - pci_conf1_read(0, bus, devfn, 0, 4, &val1); - if (val1 == 0xffffffff) - continue; - - if (pci_mmcfg_arch_reachable(0, bus, devfn)) { - raw_pci_ops->read(0, bus, devfn, 0, 4, &val2); - if (val1 == val2) - continue; - } - set_bit(i + 32 * bus, pci_mmcfg_fallback_slots); - printk(KERN_NOTICE "PCI: No mmconfig possible on device" - " %02x:%02x\n", bus, i); - } - } -} - -static const char __init *pci_mmcfg_e7520(void) -{ - u32 win; - pci_conf1_read(0, 0, PCI_DEVFN(0,0), 0xce, 2, &win); - - win = win & 0xf000; - if(win == 0x0000 || win == 0xf000) - pci_mmcfg_config_num = 0; - else { - pci_mmcfg_config_num = 1; - pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]), GFP_KERNEL); - if (!pci_mmcfg_config) - return NULL; - pci_mmcfg_config[0].address = win << 16; - pci_mmcfg_config[0].pci_segment = 0; - pci_mmcfg_config[0].start_bus_number = 0; - pci_mmcfg_config[0].end_bus_number = 255; - } - - return "Intel Corporation E7520 Memory Controller Hub"; -} - -static const char __init *pci_mmcfg_intel_945(void) -{ - u32 pciexbar, mask = 0, len = 0; - - pci_mmcfg_config_num = 1; - - pci_conf1_read(0, 0, PCI_DEVFN(0,0), 0x48, 4, &pciexbar); - - /* Enable bit */ - if (!(pciexbar & 1)) - pci_mmcfg_config_num = 0; - - /* Size bits */ - switch ((pciexbar >> 1) & 3) { - case 0: - mask = 0xf0000000U; - len = 0x10000000U; - break; - case 1: - mask = 0xf8000000U; - len = 0x08000000U; - break; - case 2: - mask = 0xfc000000U; - len = 0x04000000U; - break; - default: - pci_mmcfg_config_num = 0; - } - - /* Errata #2, things break when not aligned on a 256Mb boundary */ - /* Can only happen in 64M/128M mode */ - - if ((pciexbar & mask) & 0x0fffffffU) - pci_mmcfg_config_num = 0; - - /* Don't hit the APIC registers and their friends */ - if ((pciexbar & mask) >= 0xf0000000U) - pci_mmcfg_config_num = 0; - - if (pci_mmcfg_config_num) { - pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]), GFP_KERNEL); - if (!pci_mmcfg_config) - return NULL; - pci_mmcfg_config[0].address = pciexbar & mask; - pci_mmcfg_config[0].pci_segment = 0; - pci_mmcfg_config[0].start_bus_number = 0; - pci_mmcfg_config[0].end_bus_number = (len >> 20) - 1; - } - - return "Intel Corporation 945G/GZ/P/PL Express Memory Controller Hub"; -} - -struct pci_mmcfg_hostbridge_probe { - u32 vendor; - u32 device; - const char *(*probe)(void); -}; - -static struct pci_mmcfg_hostbridge_probe pci_mmcfg_probes[] __initdata = { - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, pci_mmcfg_e7520 }, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82945G_HB, pci_mmcfg_intel_945 }, -}; - -static int __init pci_mmcfg_check_hostbridge(void) -{ - u32 l; - u16 vendor, device; - int i; - const char *name; - - pci_conf1_read(0, 0, PCI_DEVFN(0,0), 0, 4, &l); - vendor = l & 0xffff; - device = (l >> 16) & 0xffff; - - pci_mmcfg_config_num = 0; - pci_mmcfg_config = NULL; - name = NULL; - - for (i = 0; !name && i < ARRAY_SIZE(pci_mmcfg_probes); i++) { - if (pci_mmcfg_probes[i].vendor == vendor && - pci_mmcfg_probes[i].device == device) - name = pci_mmcfg_probes[i].probe(); - } - - if (name) { - printk(KERN_INFO "PCI: Found %s %s MMCONFIG support.\n", - name, pci_mmcfg_config_num ? "with" : "without"); - } - - return name != NULL; -} - -static void __init pci_mmcfg_insert_resources(unsigned long resource_flags) -{ -#define PCI_MMCFG_RESOURCE_NAME_LEN 19 - int i; - struct resource *res; - char *names; - unsigned num_buses; - - res = kcalloc(PCI_MMCFG_RESOURCE_NAME_LEN + sizeof(*res), - pci_mmcfg_config_num, GFP_KERNEL); - if (!res) { - printk(KERN_ERR "PCI: Unable to allocate MMCONFIG resources\n"); - return; - } - - names = (void *)&res[pci_mmcfg_config_num]; - for (i = 0; i < pci_mmcfg_config_num; i++, res++) { - struct acpi_mcfg_allocation *cfg = &pci_mmcfg_config[i]; - num_buses = cfg->end_bus_number - cfg->start_bus_number + 1; - res->name = names; - snprintf(names, PCI_MMCFG_RESOURCE_NAME_LEN, "PCI MMCONFIG %u", - cfg->pci_segment); - res->start = cfg->address; - res->end = res->start + (num_buses << 20) - 1; - res->flags = IORESOURCE_MEM | resource_flags; - insert_resource(&iomem_resource, res); - names += PCI_MMCFG_RESOURCE_NAME_LEN; - } - - /* Mark that the resources have been inserted. */ - pci_mmcfg_resources_inserted = 1; -} - -static void __init pci_mmcfg_reject_broken(int type) -{ - typeof(pci_mmcfg_config[0]) *cfg; - - if ((pci_mmcfg_config_num == 0) || - (pci_mmcfg_config == NULL) || - (pci_mmcfg_config[0].address == 0)) - return; - - cfg = &pci_mmcfg_config[0]; - - /* - * Handle more broken MCFG tables on Asus etc. - * They only contain a single entry for bus 0-0. - */ - if (pci_mmcfg_config_num == 1 && - cfg->pci_segment == 0 && - (cfg->start_bus_number | cfg->end_bus_number) == 0) { - printk(KERN_ERR "PCI: start and end of bus number is 0. " - "Rejected as broken MCFG.\n"); - goto reject; - } - - /* - * Only do this check when type 1 works. If it doesn't work - * assume we run on a Mac and always use MCFG - */ - if (type == 1 && !e820_all_mapped(cfg->address, - cfg->address + MMCONFIG_APER_MIN, - E820_RESERVED)) { - printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %Lx is not" - " E820-reserved\n", cfg->address); - goto reject; - } - return; - -reject: - printk(KERN_ERR "PCI: Not using MMCONFIG.\n"); - kfree(pci_mmcfg_config); - pci_mmcfg_config = NULL; - pci_mmcfg_config_num = 0; -} - -void __init pci_mmcfg_init(int type) -{ - int known_bridge = 0; - - if ((pci_probe & PCI_PROBE_MMCONF) == 0) - return; - - if (type == 1 && pci_mmcfg_check_hostbridge()) - known_bridge = 1; - - if (!known_bridge) { - acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg); - pci_mmcfg_reject_broken(type); - } - - if ((pci_mmcfg_config_num == 0) || - (pci_mmcfg_config == NULL) || - (pci_mmcfg_config[0].address == 0)) - return; - - if (pci_mmcfg_arch_init()) { - if (type == 1) - unreachable_devices(); - if (known_bridge) - pci_mmcfg_insert_resources(IORESOURCE_BUSY); - pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF; - } else { - /* - * Signal not to attempt to insert mmcfg resources because - * the architecture mmcfg setup could not initialize. - */ - pci_mmcfg_resources_inserted = 1; - } -} - -static int __init pci_mmcfg_late_insert_resources(void) -{ - /* - * If resources are already inserted or we are not using MMCONFIG, - * don't insert the resources. - */ - if ((pci_mmcfg_resources_inserted == 1) || - (pci_probe & PCI_PROBE_MMCONF) == 0 || - (pci_mmcfg_config_num == 0) || - (pci_mmcfg_config == NULL) || - (pci_mmcfg_config[0].address == 0)) - return 1; - - /* - * Attempt to insert the mmcfg resources but not with the busy flag - * marked so it won't cause request errors when __request_region is - * called. - */ - pci_mmcfg_insert_resources(0); - - return 0; -} - -/* - * Perform MMCONFIG resource insertion after PCI initialization to allow for - * misprogrammed MCFG tables that state larger sizes but actually conflict - * with other system resources. - */ -late_initcall(pci_mmcfg_late_insert_resources); diff --git a/arch/i386/pci/mmconfig_32.c b/arch/i386/pci/mmconfig_32.c deleted file mode 100644 index 1bf5816d34c..00000000000 --- a/arch/i386/pci/mmconfig_32.c +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (C) 2004 Matthew Wilcox - * Copyright (C) 2004 Intel Corp. - * - * This code is released under the GNU General Public License version 2. - */ - -/* - * mmconfig.c - Low-level direct PCI config space access via MMCONFIG - */ - -#include -#include -#include -#include -#include "pci.h" - -/* Assume systems with more busses have correct MCFG */ -#define mmcfg_virt_addr ((void __iomem *) fix_to_virt(FIX_PCIE_MCFG)) - -/* The base address of the last MMCONFIG device accessed */ -static u32 mmcfg_last_accessed_device; -static int mmcfg_last_accessed_cpu; - -/* - * Functions for accessing PCI configuration space with MMCONFIG accesses - */ -static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn) -{ - struct acpi_mcfg_allocation *cfg; - int cfg_num; - - if (seg == 0 && bus < PCI_MMCFG_MAX_CHECK_BUS && - test_bit(PCI_SLOT(devfn) + 32*bus, pci_mmcfg_fallback_slots)) - return 0; - - for (cfg_num = 0; cfg_num < pci_mmcfg_config_num; cfg_num++) { - cfg = &pci_mmcfg_config[cfg_num]; - if (cfg->pci_segment == seg && - (cfg->start_bus_number <= bus) && - (cfg->end_bus_number >= bus)) - return cfg->address; - } - - /* Fall back to type 0 */ - return 0; -} - -/* - * This is always called under pci_config_lock - */ -static void pci_exp_set_dev_base(unsigned int base, int bus, int devfn) -{ - u32 dev_base = base | (bus << 20) | (devfn << 12); - int cpu = smp_processor_id(); - if (dev_base != mmcfg_last_accessed_device || - cpu != mmcfg_last_accessed_cpu) { - mmcfg_last_accessed_device = dev_base; - mmcfg_last_accessed_cpu = cpu; - set_fixmap_nocache(FIX_PCIE_MCFG, dev_base); - } -} - -static int pci_mmcfg_read(unsigned int seg, unsigned int bus, - unsigned int devfn, int reg, int len, u32 *value) -{ - unsigned long flags; - u32 base; - - if ((bus > 255) || (devfn > 255) || (reg > 4095)) { - *value = -1; - return -EINVAL; - } - - base = get_base_addr(seg, bus, devfn); - if (!base) - return pci_conf1_read(seg,bus,devfn,reg,len,value); - - spin_lock_irqsave(&pci_config_lock, flags); - - pci_exp_set_dev_base(base, bus, devfn); - - switch (len) { - case 1: - *value = mmio_config_readb(mmcfg_virt_addr + reg); - break; - case 2: - *value = mmio_config_readw(mmcfg_virt_addr + reg); - break; - case 4: - *value = mmio_config_readl(mmcfg_virt_addr + reg); - break; - } - spin_unlock_irqrestore(&pci_config_lock, flags); - - return 0; -} - -static int pci_mmcfg_write(unsigned int seg, unsigned int bus, - unsigned int devfn, int reg, int len, u32 value) -{ - unsigned long flags; - u32 base; - - if ((bus > 255) || (devfn > 255) || (reg > 4095)) - return -EINVAL; - - base = get_base_addr(seg, bus, devfn); - if (!base) - return pci_conf1_write(seg,bus,devfn,reg,len,value); - - spin_lock_irqsave(&pci_config_lock, flags); - - pci_exp_set_dev_base(base, bus, devfn); - - switch (len) { - case 1: - mmio_config_writeb(mmcfg_virt_addr + reg, value); - break; - case 2: - mmio_config_writew(mmcfg_virt_addr + reg, value); - break; - case 4: - mmio_config_writel(mmcfg_virt_addr + reg, value); - break; - } - spin_unlock_irqrestore(&pci_config_lock, flags); - - return 0; -} - -static struct pci_raw_ops pci_mmcfg = { - .read = pci_mmcfg_read, - .write = pci_mmcfg_write, -}; - -int __init pci_mmcfg_arch_reachable(unsigned int seg, unsigned int bus, - unsigned int devfn) -{ - return get_base_addr(seg, bus, devfn) != 0; -} - -int __init pci_mmcfg_arch_init(void) -{ - printk(KERN_INFO "PCI: Using MMCONFIG\n"); - raw_pci_ops = &pci_mmcfg; - return 1; -} diff --git a/arch/i386/pci/numa.c b/arch/i386/pci/numa.c deleted file mode 100644 index f5f165f69e0..00000000000 --- a/arch/i386/pci/numa.c +++ /dev/null @@ -1,135 +0,0 @@ -/* - * numa.c - Low-level PCI access for NUMA-Q machines - */ - -#include -#include -#include -#include "pci.h" - -#define BUS2QUAD(global) (mp_bus_id_to_node[global]) -#define BUS2LOCAL(global) (mp_bus_id_to_local[global]) -#define QUADLOCAL2BUS(quad,local) (quad_local_to_mp_bus_id[quad][local]) - -#define PCI_CONF1_MQ_ADDRESS(bus, devfn, reg) \ - (0x80000000 | (BUS2LOCAL(bus) << 16) | (devfn << 8) | (reg & ~3)) - -static int pci_conf1_mq_read(unsigned int seg, unsigned int bus, - unsigned int devfn, int reg, int len, u32 *value) -{ - unsigned long flags; - - if (!value || (bus >= MAX_MP_BUSSES) || (devfn > 255) || (reg > 255)) - return -EINVAL; - - spin_lock_irqsave(&pci_config_lock, flags); - - outl_quad(PCI_CONF1_MQ_ADDRESS(bus, devfn, reg), 0xCF8, BUS2QUAD(bus)); - - switch (len) { - case 1: - *value = inb_quad(0xCFC + (reg & 3), BUS2QUAD(bus)); - break; - case 2: - *value = inw_quad(0xCFC + (reg & 2), BUS2QUAD(bus)); - break; - case 4: - *value = inl_quad(0xCFC, BUS2QUAD(bus)); - break; - } - - spin_unlock_irqrestore(&pci_config_lock, flags); - - return 0; -} - -static int pci_conf1_mq_write(unsigned int seg, unsigned int bus, - unsigned int devfn, int reg, int len, u32 value) -{ - unsigned long flags; - - if ((bus >= MAX_MP_BUSSES) || (devfn > 255) || (reg > 255)) - return -EINVAL; - - spin_lock_irqsave(&pci_config_lock, flags); - - outl_quad(PCI_CONF1_MQ_ADDRESS(bus, devfn, reg), 0xCF8, BUS2QUAD(bus)); - - switch (len) { - case 1: - outb_quad((u8)value, 0xCFC + (reg & 3), BUS2QUAD(bus)); - break; - case 2: - outw_quad((u16)value, 0xCFC + (reg & 2), BUS2QUAD(bus)); - break; - case 4: - outl_quad((u32)value, 0xCFC, BUS2QUAD(bus)); - break; - } - - spin_unlock_irqrestore(&pci_config_lock, flags); - - return 0; -} - -#undef PCI_CONF1_MQ_ADDRESS - -static struct pci_raw_ops pci_direct_conf1_mq = { - .read = pci_conf1_mq_read, - .write = pci_conf1_mq_write -}; - - -static void __devinit pci_fixup_i450nx(struct pci_dev *d) -{ - /* - * i450NX -- Find and scan all secondary buses on all PXB's. - */ - int pxb, reg; - u8 busno, suba, subb; - int quad = BUS2QUAD(d->bus->number); - - printk("PCI: Searching for i450NX host bridges on %s\n", pci_name(d)); - reg = 0xd0; - for(pxb=0; pxb<2; pxb++) { - pci_read_config_byte(d, reg++, &busno); - pci_read_config_byte(d, reg++, &suba); - pci_read_config_byte(d, reg++, &subb); - DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb); - if (busno) { - /* Bus A */ - pci_scan_bus_with_sysdata(QUADLOCAL2BUS(quad, busno)); - } - if (suba < subb) { - /* Bus B */ - pci_scan_bus_with_sysdata(QUADLOCAL2BUS(quad, suba+1)); - } - } - pcibios_last_bus = -1; -} -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_fixup_i450nx); - -static int __init pci_numa_init(void) -{ - int quad; - - raw_pci_ops = &pci_direct_conf1_mq; - - if (pcibios_scanned++) - return 0; - - pci_root_bus = pcibios_scan_root(0); - if (pci_root_bus) - pci_bus_add_devices(pci_root_bus); - if (num_online_nodes() > 1) - for_each_online_node(quad) { - if (quad == 0) - continue; - printk("Scanning PCI bus %d for quad %d\n", - QUADLOCAL2BUS(quad,0), quad); - pci_scan_bus_with_sysdata(QUADLOCAL2BUS(quad, 0)); - } - return 0; -} - -subsys_initcall(pci_numa_init); diff --git a/arch/i386/pci/pcbios.c b/arch/i386/pci/pcbios.c deleted file mode 100644 index 10ac8c316c4..00000000000 --- a/arch/i386/pci/pcbios.c +++ /dev/null @@ -1,492 +0,0 @@ -/* - * BIOS32 and PCI BIOS handling. - */ - -#include -#include -#include -#include -#include "pci.h" -#include "pci-functions.h" - - -/* BIOS32 signature: "_32_" */ -#define BIOS32_SIGNATURE (('_' << 0) + ('3' << 8) + ('2' << 16) + ('_' << 24)) - -/* PCI signature: "PCI " */ -#define PCI_SIGNATURE (('P' << 0) + ('C' << 8) + ('I' << 16) + (' ' << 24)) - -/* PCI service signature: "$PCI" */ -#define PCI_SERVICE (('$' << 0) + ('P' << 8) + ('C' << 16) + ('I' << 24)) - -/* PCI BIOS hardware mechanism flags */ -#define PCIBIOS_HW_TYPE1 0x01 -#define PCIBIOS_HW_TYPE2 0x02 -#define PCIBIOS_HW_TYPE1_SPEC 0x10 -#define PCIBIOS_HW_TYPE2_SPEC 0x20 - -/* - * This is the standard structure used to identify the entry point - * to the BIOS32 Service Directory, as documented in - * Standard BIOS 32-bit Service Directory Proposal - * Revision 0.4 May 24, 1993 - * Phoenix Technologies Ltd. - * Norwood, MA - * and the PCI BIOS specification. - */ - -union bios32 { - struct { - unsigned long signature; /* _32_ */ - unsigned long entry; /* 32 bit physical address */ - unsigned char revision; /* Revision level, 0 */ - unsigned char length; /* Length in paragraphs should be 01 */ - unsigned char checksum; /* All bytes must add up to zero */ - unsigned char reserved[5]; /* Must be zero */ - } fields; - char chars[16]; -}; - -/* - * Physical address of the service directory. I don't know if we're - * allowed to have more than one of these or not, so just in case - * we'll make pcibios_present() take a memory start parameter and store - * the array there. - */ - -static struct { - unsigned long address; - unsigned short segment; -} bios32_indirect = { 0, __KERNEL_CS }; - -/* - * Returns the entry point for the given service, NULL on error - */ - -static unsigned long bios32_service(unsigned long service) -{ - unsigned char return_code; /* %al */ - unsigned long address; /* %ebx */ - unsigned long length; /* %ecx */ - unsigned long entry; /* %edx */ - unsigned long flags; - - local_irq_save(flags); - __asm__("lcall *(%%edi); cld" - : "=a" (return_code), - "=b" (address), - "=c" (length), - "=d" (entry) - : "0" (service), - "1" (0), - "D" (&bios32_indirect)); - local_irq_restore(flags); - - switch (return_code) { - case 0: - return address + entry; - case 0x80: /* Not present */ - printk(KERN_WARNING "bios32_service(0x%lx): not present\n", service); - return 0; - default: /* Shouldn't happen */ - printk(KERN_WARNING "bios32_service(0x%lx): returned 0x%x -- BIOS bug!\n", - service, return_code); - return 0; - } -} - -static struct { - unsigned long address; - unsigned short segment; -} pci_indirect = { 0, __KERNEL_CS }; - -static int pci_bios_present; - -static int __devinit check_pcibios(void) -{ - u32 signature, eax, ebx, ecx; - u8 status, major_ver, minor_ver, hw_mech; - unsigned long flags, pcibios_entry; - - if ((pcibios_entry = bios32_service(PCI_SERVICE))) { - pci_indirect.address = pcibios_entry + PAGE_OFFSET; - - local_irq_save(flags); - __asm__( - "lcall *(%%edi); cld\n\t" - "jc 1f\n\t" - "xor %%ah, %%ah\n" - "1:" - : "=d" (signature), - "=a" (eax), - "=b" (ebx), - "=c" (ecx) - : "1" (PCIBIOS_PCI_BIOS_PRESENT), - "D" (&pci_indirect) - : "memory"); - local_irq_restore(flags); - - status = (eax >> 8) & 0xff; - hw_mech = eax & 0xff; - major_ver = (ebx >> 8) & 0xff; - minor_ver = ebx & 0xff; - if (pcibios_last_bus < 0) - pcibios_last_bus = ecx & 0xff; - DBG("PCI: BIOS probe returned s=%02x hw=%02x ver=%02x.%02x l=%02x\n", - status, hw_mech, major_ver, minor_ver, pcibios_last_bus); - if (status || signature != PCI_SIGNATURE) { - printk (KERN_ERR "PCI: BIOS BUG #%x[%08x] found\n", - status, signature); - return 0; - } - printk(KERN_INFO "PCI: PCI BIOS revision %x.%02x entry at 0x%lx, last bus=%d\n", - major_ver, minor_ver, pcibios_entry, pcibios_last_bus); -#ifdef CONFIG_PCI_DIRECT - if (!(hw_mech & PCIBIOS_HW_TYPE1)) - pci_probe &= ~PCI_PROBE_CONF1; - if (!(hw_mech & PCIBIOS_HW_TYPE2)) - pci_probe &= ~PCI_PROBE_CONF2; -#endif - return 1; - } - return 0; -} - -static int __devinit pci_bios_find_device (unsigned short vendor, unsigned short device_id, - unsigned short index, unsigned char *bus, unsigned char *device_fn) -{ - unsigned short bx; - unsigned short ret; - - __asm__("lcall *(%%edi); cld\n\t" - "jc 1f\n\t" - "xor %%ah, %%ah\n" - "1:" - : "=b" (bx), - "=a" (ret) - : "1" (PCIBIOS_FIND_PCI_DEVICE), - "c" (device_id), - "d" (vendor), - "S" ((int) index), - "D" (&pci_indirect)); - *bus = (bx >> 8) & 0xff; - *device_fn = bx & 0xff; - return (int) (ret & 0xff00) >> 8; -} - -static int pci_bios_read(unsigned int seg, unsigned int bus, - unsigned int devfn, int reg, int len, u32 *value) -{ - unsigned long result = 0; - unsigned long flags; - unsigned long bx = (bus << 8) | devfn; - - if (!value || (bus > 255) || (devfn > 255) || (reg > 255)) - return -EINVAL; - - spin_lock_irqsave(&pci_config_lock, flags); - - switch (len) { - case 1: - __asm__("lcall *(%%esi); cld\n\t" - "jc 1f\n\t" - "xor %%ah, %%ah\n" - "1:" - : "=c" (*value), - "=a" (result) - : "1" (PCIBIOS_READ_CONFIG_BYTE), - "b" (bx), - "D" ((long)reg), - "S" (&pci_indirect)); - break; - case 2: - __asm__("lcall *(%%esi); cld\n\t" - "jc 1f\n\t" - "xor %%ah, %%ah\n" - "1:" - : "=c" (*value), - "=a" (result) - : "1" (PCIBIOS_READ_CONFIG_WORD), - "b" (bx), - "D" ((long)reg), - "S" (&pci_indirect)); - break; - case 4: - __asm__("lcall *(%%esi); cld\n\t" - "jc 1f\n\t" - "xor %%ah, %%ah\n" - "1:" - : "=c" (*value), - "=a" (result) - : "1" (PCIBIOS_READ_CONFIG_DWORD), - "b" (bx), - "D" ((long)reg), - "S" (&pci_indirect)); - break; - } - - spin_unlock_irqrestore(&pci_config_lock, flags); - - return (int)((result & 0xff00) >> 8); -} - -static int pci_bios_write(unsigned int seg, unsigned int bus, - unsigned int devfn, int reg, int len, u32 value) -{ - unsigned long result = 0; - unsigned long flags; - unsigned long bx = (bus << 8) | devfn; - - if ((bus > 255) || (devfn > 255) || (reg > 255)) - return -EINVAL; - - spin_lock_irqsave(&pci_config_lock, flags); - - switch (len) { - case 1: - __asm__("lcall *(%%esi); cld\n\t" - "jc 1f\n\t" - "xor %%ah, %%ah\n" - "1:" - : "=a" (result) - : "0" (PCIBIOS_WRITE_CONFIG_BYTE), - "c" (value), - "b" (bx), - "D" ((long)reg), - "S" (&pci_indirect)); - break; - case 2: - __asm__("lcall *(%%esi); cld\n\t" - "jc 1f\n\t" - "xor %%ah, %%ah\n" - "1:" - : "=a" (result) - : "0" (PCIBIOS_WRITE_CONFIG_WORD), - "c" (value), - "b" (bx), - "D" ((long)reg), - "S" (&pci_indirect)); - break; - case 4: - __asm__("lcall *(%%esi); cld\n\t" - "jc 1f\n\t" - "xor %%ah, %%ah\n" - "1:" - : "=a" (result) - : "0" (PCIBIOS_WRITE_CONFIG_DWORD), - "c" (value), - "b" (bx), - "D" ((long)reg), - "S" (&pci_indirect)); - break; - } - - spin_unlock_irqrestore(&pci_config_lock, flags); - - return (int)((result & 0xff00) >> 8); -} - - -/* - * Function table for BIOS32 access - */ - -static struct pci_raw_ops pci_bios_access = { - .read = pci_bios_read, - .write = pci_bios_write -}; - -/* - * Try to find PCI BIOS. - */ - -static struct pci_raw_ops * __devinit pci_find_bios(void) -{ - union bios32 *check; - unsigned char sum; - int i, length; - - /* - * Follow the standard procedure for locating the BIOS32 Service - * directory by scanning the permissible address range from - * 0xe0000 through 0xfffff for a valid BIOS32 structure. - */ - - for (check = (union bios32 *) __va(0xe0000); - check <= (union bios32 *) __va(0xffff0); - ++check) { - long sig; - if (probe_kernel_address(&check->fields.signature, sig)) - continue; - - if (check->fields.signature != BIOS32_SIGNATURE) - continue; - length = check->fields.length * 16; - if (!length) - continue; - sum = 0; - for (i = 0; i < length ; ++i) - sum += check->chars[i]; - if (sum != 0) - continue; - if (check->fields.revision != 0) { - printk("PCI: unsupported BIOS32 revision %d at 0x%p\n", - check->fields.revision, check); - continue; - } - DBG("PCI: BIOS32 Service Directory structure at 0x%p\n", check); - if (check->fields.entry >= 0x100000) { - printk("PCI: BIOS32 entry (0x%p) in high memory, " - "cannot use.\n", check); - return NULL; - } else { - unsigned long bios32_entry = check->fields.entry; - DBG("PCI: BIOS32 Service Directory entry at 0x%lx\n", - bios32_entry); - bios32_indirect.address = bios32_entry + PAGE_OFFSET; - if (check_pcibios()) - return &pci_bios_access; - } - break; /* Hopefully more than one BIOS32 cannot happen... */ - } - - return NULL; -} - -/* - * Sort the device list according to PCI BIOS. Nasty hack, but since some - * fool forgot to define the `correct' device order in the PCI BIOS specs - * and we want to be (possibly bug-to-bug ;-]) compatible with older kernels - * which used BIOS ordering, we are bound to do this... - */ - -void __devinit pcibios_sort(void) -{ - LIST_HEAD(sorted_devices); - struct list_head *ln; - struct pci_dev *dev, *d; - int idx, found; - unsigned char bus, devfn; - - DBG("PCI: Sorting device list...\n"); - while (!list_empty(&pci_devices)) { - ln = pci_devices.next; - dev = pci_dev_g(ln); - idx = found = 0; - while (pci_bios_find_device(dev->vendor, dev->device, idx, &bus, &devfn) == PCIBIOS_SUCCESSFUL) { - idx++; - list_for_each(ln, &pci_devices) { - d = pci_dev_g(ln); - if (d->bus->number == bus && d->devfn == devfn) { - list_move_tail(&d->global_list, &sorted_devices); - if (d == dev) - found = 1; - break; - } - } - if (ln == &pci_devices) { - printk(KERN_WARNING "PCI: BIOS reporting unknown device %02x:%02x\n", bus, devfn); - /* - * We must not continue scanning as several buggy BIOSes - * return garbage after the last device. Grr. - */ - break; - } - } - if (!found) { - printk(KERN_WARNING "PCI: Device %s not found by BIOS\n", - pci_name(dev)); - list_move_tail(&dev->global_list, &sorted_devices); - } - } - list_splice(&sorted_devices, &pci_devices); -} - -/* - * BIOS Functions for IRQ Routing - */ - -struct irq_routing_options { - u16 size; - struct irq_info *table; - u16 segment; -} __attribute__((packed)); - -struct irq_routing_table * pcibios_get_irq_routing_table(void) -{ - struct irq_routing_options opt; - struct irq_routing_table *rt = NULL; - int ret, map; - unsigned long page; - - if (!pci_bios_present) - return NULL; - page = __get_free_page(GFP_KERNEL); - if (!page) - return NULL; - opt.table = (struct irq_info *) page; - opt.size = PAGE_SIZE; - opt.segment = __KERNEL_DS; - - DBG("PCI: Fetching IRQ routing table... "); - __asm__("push %%es\n\t" - "push %%ds\n\t" - "pop %%es\n\t" - "lcall *(%%esi); cld\n\t" - "pop %%es\n\t" - "jc 1f\n\t" - "xor %%ah, %%ah\n" - "1:" - : "=a" (ret), - "=b" (map), - "=m" (opt) - : "0" (PCIBIOS_GET_ROUTING_OPTIONS), - "1" (0), - "D" ((long) &opt), - "S" (&pci_indirect), - "m" (opt) - : "memory"); - DBG("OK ret=%d, size=%d, map=%x\n", ret, opt.size, map); - if (ret & 0xff00) - printk(KERN_ERR "PCI: Error %02x when fetching IRQ routing table.\n", (ret >> 8) & 0xff); - else if (opt.size) { - rt = kmalloc(sizeof(struct irq_routing_table) + opt.size, GFP_KERNEL); - if (rt) { - memset(rt, 0, sizeof(struct irq_routing_table)); - rt->size = opt.size + sizeof(struct irq_routing_table); - rt->exclusive_irqs = map; - memcpy(rt->slots, (void *) page, opt.size); - printk(KERN_INFO "PCI: Using BIOS Interrupt Routing Table\n"); - } - } - free_page(page); - return rt; -} -EXPORT_SYMBOL(pcibios_get_irq_routing_table); - -int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq) -{ - int ret; - - __asm__("lcall *(%%esi); cld\n\t" - "jc 1f\n\t" - "xor %%ah, %%ah\n" - "1:" - : "=a" (ret) - : "0" (PCIBIOS_SET_PCI_HW_INT), - "b" ((dev->bus->number << 8) | dev->devfn), - "c" ((irq << 8) | (pin + 10)), - "S" (&pci_indirect)); - return !(ret & 0xff00); -} -EXPORT_SYMBOL(pcibios_set_irq_routing); - -void __init pci_pcbios_init(void) -{ - if ((pci_probe & PCI_PROBE_BIOS) - && ((raw_pci_ops = pci_find_bios()))) { - pci_probe |= PCI_BIOS_SORT; - pci_bios_present = 1; - } -} - diff --git a/arch/i386/pci/pci.h b/arch/i386/pci/pci.h deleted file mode 100644 index 8c66f275756..00000000000 --- a/arch/i386/pci/pci.h +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Low-Level PCI Access for i386 machines. - * - * (c) 1999 Martin Mares - */ - -#undef DEBUG - -#ifdef DEBUG -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif - -#define PCI_PROBE_BIOS 0x0001 -#define PCI_PROBE_CONF1 0x0002 -#define PCI_PROBE_CONF2 0x0004 -#define PCI_PROBE_MMCONF 0x0008 -#define PCI_PROBE_MASK 0x000f -#define PCI_PROBE_NOEARLY 0x0010 - -#define PCI_NO_SORT 0x0100 -#define PCI_BIOS_SORT 0x0200 -#define PCI_NO_CHECKS 0x0400 -#define PCI_USE_PIRQ_MASK 0x0800 -#define PCI_ASSIGN_ROMS 0x1000 -#define PCI_BIOS_IRQ_SCAN 0x2000 -#define PCI_ASSIGN_ALL_BUSSES 0x4000 - -extern unsigned int pci_probe; -extern unsigned long pirq_table_addr; - -enum pci_bf_sort_state { - pci_bf_sort_default, - pci_force_nobf, - pci_force_bf, - pci_dmi_bf, -}; - -/* pci-i386.c */ - -extern unsigned int pcibios_max_latency; - -void pcibios_resource_survey(void); -int pcibios_enable_resources(struct pci_dev *, int); - -/* pci-pc.c */ - -extern int pcibios_last_bus; -extern struct pci_bus *pci_root_bus; -extern struct pci_ops pci_root_ops; - -/* pci-irq.c */ - -struct irq_info { - u8 bus, devfn; /* Bus, device and function */ - struct { - u8 link; /* IRQ line ID, chipset dependent, 0=not routed */ - u16 bitmap; /* Available IRQs */ - } __attribute__((packed)) irq[4]; - u8 slot; /* Slot number, 0=onboard */ - u8 rfu; -} __attribute__((packed)); - -struct irq_routing_table { - u32 signature; /* PIRQ_SIGNATURE should be here */ - u16 version; /* PIRQ_VERSION */ - u16 size; /* Table size in bytes */ - u8 rtr_bus, rtr_devfn; /* Where the interrupt router lies */ - u16 exclusive_irqs; /* IRQs devoted exclusively to PCI usage */ - u16 rtr_vendor, rtr_device; /* Vendor and device ID of interrupt router */ - u32 miniport_data; /* Crap */ - u8 rfu[11]; - u8 checksum; /* Modulo 256 checksum must give zero */ - struct irq_info slots[0]; -} __attribute__((packed)); - -extern unsigned int pcibios_irq_mask; - -extern int pcibios_scanned; -extern spinlock_t pci_config_lock; - -extern int (*pcibios_enable_irq)(struct pci_dev *dev); -extern void (*pcibios_disable_irq)(struct pci_dev *dev); - -extern int pci_conf1_write(unsigned int seg, unsigned int bus, - unsigned int devfn, int reg, int len, u32 value); -extern int pci_conf1_read(unsigned int seg, unsigned int bus, - unsigned int devfn, int reg, int len, u32 *value); - -extern int pci_direct_probe(void); -extern void pci_direct_init(int type); -extern void pci_pcbios_init(void); -extern void pci_mmcfg_init(int type); -extern void pcibios_sort(void); - -/* pci-mmconfig.c */ - -/* Verify the first 16 busses. We assume that systems with more busses - get MCFG right. */ -#define PCI_MMCFG_MAX_CHECK_BUS 16 -extern DECLARE_BITMAP(pci_mmcfg_fallback_slots, 32*PCI_MMCFG_MAX_CHECK_BUS); - -extern int __init pci_mmcfg_arch_reachable(unsigned int seg, unsigned int bus, - unsigned int devfn); -extern int __init pci_mmcfg_arch_init(void); - -/* - * AMD Fam10h CPUs are buggy, and cannot access MMIO config space - * on their northbrige except through the * %eax register. As such, you MUST - * NOT use normal IOMEM accesses, you need to only use the magic mmio-config - * accessor functions. - * In fact just use pci_config_*, nothing else please. - */ -static inline unsigned char mmio_config_readb(void __iomem *pos) -{ - u8 val; - asm volatile("movb (%1),%%al" : "=a" (val) : "r" (pos)); - return val; -} - -static inline unsigned short mmio_config_readw(void __iomem *pos) -{ - u16 val; - asm volatile("movw (%1),%%ax" : "=a" (val) : "r" (pos)); - return val; -} - -static inline unsigned int mmio_config_readl(void __iomem *pos) -{ - u32 val; - asm volatile("movl (%1),%%eax" : "=a" (val) : "r" (pos)); - return val; -} - -static inline void mmio_config_writeb(void __iomem *pos, u8 val) -{ - asm volatile("movb %%al,(%1)" :: "a" (val), "r" (pos) : "memory"); -} - -static inline void mmio_config_writew(void __iomem *pos, u16 val) -{ - asm volatile("movw %%ax,(%1)" :: "a" (val), "r" (pos) : "memory"); -} - -static inline void mmio_config_writel(void __iomem *pos, u32 val) -{ - asm volatile("movl %%eax,(%1)" :: "a" (val), "r" (pos) : "memory"); -} diff --git a/arch/i386/pci/visws.c b/arch/i386/pci/visws.c deleted file mode 100644 index 8ecb1c72259..00000000000 --- a/arch/i386/pci/visws.c +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Low-Level PCI Support for SGI Visual Workstation - * - * (c) 1999--2000 Martin Mares - */ - -#include -#include -#include - -#include "cobalt.h" -#include "lithium.h" - -#include "pci.h" - - -extern struct pci_raw_ops pci_direct_conf1; - -static int pci_visws_enable_irq(struct pci_dev *dev) { return 0; } -static void pci_visws_disable_irq(struct pci_dev *dev) { } - -int (*pcibios_enable_irq)(struct pci_dev *dev) = &pci_visws_enable_irq; -void (*pcibios_disable_irq)(struct pci_dev *dev) = &pci_visws_disable_irq; - -void __init pcibios_penalize_isa_irq(int irq, int active) {} - - -unsigned int pci_bus0, pci_bus1; - -static inline u8 bridge_swizzle(u8 pin, u8 slot) -{ - return (((pin - 1) + slot) % 4) + 1; -} - -static u8 __init visws_swizzle(struct pci_dev *dev, u8 *pinp) -{ - u8 pin = *pinp; - - while (dev->bus->self) { /* Move up the chain of bridges. */ - pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)); - dev = dev->bus->self; - } - *pinp = pin; - - return PCI_SLOT(dev->devfn); -} - -static int __init visws_map_irq(struct pci_dev *dev, u8 slot, u8 pin) -{ - int irq, bus = dev->bus->number; - - pin--; - - /* Nothing useful at PIIX4 pin 1 */ - if (bus == pci_bus0 && slot == 4 && pin == 0) - return -1; - - /* PIIX4 USB is on Bus 0, Slot 4, Line 3 */ - if (bus == pci_bus0 && slot == 4 && pin == 3) { - irq = CO_IRQ(CO_APIC_PIIX4_USB); - goto out; - } - - /* First pin spread down 1 APIC entry per slot */ - if (pin == 0) { - irq = CO_IRQ((bus == pci_bus0 ? CO_APIC_PCIB_BASE0 : - CO_APIC_PCIA_BASE0) + slot); - goto out; - } - - /* lines 1,2,3 from any slot is shared in this twirly pattern */ - if (bus == pci_bus1) { - /* lines 1-3 from devices 0 1 rotate over 2 apic entries */ - irq = CO_IRQ(CO_APIC_PCIA_BASE123 + ((slot + (pin - 1)) % 2)); - } else { /* bus == pci_bus0 */ - /* lines 1-3 from devices 0-3 rotate over 3 apic entries */ - if (slot == 0) - slot = 3; /* same pattern */ - irq = CO_IRQ(CO_APIC_PCIA_BASE123 + ((3 - slot) + (pin - 1) % 3)); - } -out: - printk(KERN_DEBUG "PCI: Bus %d Slot %d Line %d -> IRQ %d\n", bus, slot, pin, irq); - return irq; -} - -void __init pcibios_update_irq(struct pci_dev *dev, int irq) -{ - pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); -} - -static int __init pcibios_init(void) -{ - /* The VISWS supports configuration access type 1 only */ - pci_probe = (pci_probe | PCI_PROBE_CONF1) & - ~(PCI_PROBE_BIOS | PCI_PROBE_CONF2); - - pci_bus0 = li_pcib_read16(LI_PCI_BUSNUM) & 0xff; - pci_bus1 = li_pcia_read16(LI_PCI_BUSNUM) & 0xff; - - printk(KERN_INFO "PCI: Lithium bridge A bus: %u, " - "bridge B (PIIX4) bus: %u\n", pci_bus1, pci_bus0); - - raw_pci_ops = &pci_direct_conf1; - pci_scan_bus_with_sysdata(pci_bus0); - pci_scan_bus_with_sysdata(pci_bus1); - pci_fixup_irqs(visws_swizzle, visws_map_irq); - pcibios_resource_survey(); - return 0; -} - -subsys_initcall(pcibios_init); diff --git a/arch/x86/pci/Makefile b/arch/x86/pci/Makefile new file mode 100644 index 00000000000..b3e54c45d40 --- /dev/null +++ b/arch/x86/pci/Makefile @@ -0,0 +1,5 @@ +ifeq ($(CONFIG_X86_32),y) +include ${srctree}/arch/x86/pci/Makefile_32 +else +include ${srctree}/arch/x86_64/pci/Makefile_64 +endif diff --git a/arch/x86/pci/Makefile_32 b/arch/x86/pci/Makefile_32 new file mode 100644 index 00000000000..cdd6828b5ab --- /dev/null +++ b/arch/x86/pci/Makefile_32 @@ -0,0 +1,14 @@ +obj-y := i386.o init.o + +obj-$(CONFIG_PCI_BIOS) += pcbios.o +obj-$(CONFIG_PCI_MMCONFIG) += mmconfig_32.o direct.o mmconfig-shared.o +obj-$(CONFIG_PCI_DIRECT) += direct.o + +pci-y := fixup.o +pci-$(CONFIG_ACPI) += acpi.o +pci-y += legacy.o irq.o + +pci-$(CONFIG_X86_VISWS) := visws.o fixup.o +pci-$(CONFIG_X86_NUMAQ) := numa.o irq.o + +obj-y += $(pci-y) common.o early.o diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c new file mode 100644 index 00000000000..bc8a44bddaa --- /dev/null +++ b/arch/x86/pci/acpi.c @@ -0,0 +1,90 @@ +#include +#include +#include +#include +#include +#include "pci.h" + +struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int domain, int busnum) +{ + struct pci_bus *bus; + struct pci_sysdata *sd; + int pxm; + + /* Allocate per-root-bus (not per bus) arch-specific data. + * TODO: leak; this memory is never freed. + * It's arguable whether it's worth the trouble to care. + */ + sd = kzalloc(sizeof(*sd), GFP_KERNEL); + if (!sd) { + printk(KERN_ERR "PCI: OOM, not probing PCI bus %02x\n", busnum); + return NULL; + } + + if (domain != 0) { + printk(KERN_WARNING "PCI: Multiple domains not supported\n"); + kfree(sd); + return NULL; + } + + sd->node = -1; + + pxm = acpi_get_pxm(device->handle); +#ifdef CONFIG_ACPI_NUMA + if (pxm >= 0) + sd->node = pxm_to_node(pxm); +#endif + + bus = pci_scan_bus_parented(NULL, busnum, &pci_root_ops, sd); + if (!bus) + kfree(sd); + +#ifdef CONFIG_ACPI_NUMA + if (bus != NULL) { + if (pxm >= 0) { + printk("bus %d -> pxm %d -> node %d\n", + busnum, pxm, sd->node); + } + } +#endif + + return bus; +} + +extern int pci_routeirq; +static int __init pci_acpi_init(void) +{ + struct pci_dev *dev = NULL; + + if (pcibios_scanned) + return 0; + + if (acpi_noirq) + return 0; + + printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n"); + acpi_irq_penalty_init(); + pcibios_scanned++; + pcibios_enable_irq = acpi_pci_irq_enable; + pcibios_disable_irq = acpi_pci_irq_disable; + + if (pci_routeirq) { + /* + * PCI IRQ routing is set up by pci_enable_device(), but we + * also do it here in case there are still broken drivers that + * don't use pci_enable_device(). + */ + printk(KERN_INFO "PCI: Routing PCI interrupts for all devices because \"pci=routeirq\" specified\n"); + for_each_pci_dev(dev) + acpi_pci_irq_enable(dev); + } else + printk(KERN_INFO "PCI: If a device doesn't work, try \"pci=routeirq\". If it helps, post a report\n"); + +#ifdef CONFIG_X86_IO_APIC + if (acpi_ioapic) + print_IO_APIC(); +#endif + + return 0; +} +subsys_initcall(pci_acpi_init); diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c new file mode 100644 index 00000000000..ebc6f3c6634 --- /dev/null +++ b/arch/x86/pci/common.c @@ -0,0 +1,480 @@ +/* + * Low-Level PCI Support for PC + * + * (c) 1999--2000 Martin Mares + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "pci.h" + +unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 | + PCI_PROBE_MMCONF; + +static int pci_bf_sort; +int pci_routeirq; +int pcibios_last_bus = -1; +unsigned long pirq_table_addr; +struct pci_bus *pci_root_bus; +struct pci_raw_ops *raw_pci_ops; + +static int pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) +{ + return raw_pci_ops->read(0, bus->number, devfn, where, size, value); +} + +static int pci_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) +{ + return raw_pci_ops->write(0, bus->number, devfn, where, size, value); +} + +struct pci_ops pci_root_ops = { + .read = pci_read, + .write = pci_write, +}; + +/* + * legacy, numa, and acpi all want to call pcibios_scan_root + * from their initcalls. This flag prevents that. + */ +int pcibios_scanned; + +/* + * This interrupt-safe spinlock protects all accesses to PCI + * configuration space. + */ +DEFINE_SPINLOCK(pci_config_lock); + +/* + * Several buggy motherboards address only 16 devices and mirror + * them to next 16 IDs. We try to detect this `feature' on all + * primary buses (those containing host bridges as they are + * expected to be unique) and remove the ghost devices. + */ + +static void __devinit pcibios_fixup_ghosts(struct pci_bus *b) +{ + struct list_head *ln, *mn; + struct pci_dev *d, *e; + int mirror = PCI_DEVFN(16,0); + int seen_host_bridge = 0; + int i; + + DBG("PCI: Scanning for ghost devices on bus %d\n", b->number); + list_for_each(ln, &b->devices) { + d = pci_dev_b(ln); + if ((d->class >> 8) == PCI_CLASS_BRIDGE_HOST) + seen_host_bridge++; + for (mn=ln->next; mn != &b->devices; mn=mn->next) { + e = pci_dev_b(mn); + if (e->devfn != d->devfn + mirror || + e->vendor != d->vendor || + e->device != d->device || + e->class != d->class) + continue; + for(i=0; iresource[i].start != d->resource[i].start || + e->resource[i].end != d->resource[i].end || + e->resource[i].flags != d->resource[i].flags) + continue; + break; + } + if (mn == &b->devices) + return; + } + if (!seen_host_bridge) + return; + printk(KERN_WARNING "PCI: Ignoring ghost devices on bus %02x\n", b->number); + + ln = &b->devices; + while (ln->next != &b->devices) { + d = pci_dev_b(ln->next); + if (d->devfn >= mirror) { + list_del(&d->global_list); + list_del(&d->bus_list); + kfree(d); + } else + ln = ln->next; + } +} + +/* + * Called after each bus is probed, but before its children + * are examined. + */ + +void __devinit pcibios_fixup_bus(struct pci_bus *b) +{ + pcibios_fixup_ghosts(b); + pci_read_bridge_bases(b); +} + +/* + * Only use DMI information to set this if nothing was passed + * on the kernel command line (which was parsed earlier). + */ + +static int __devinit set_bf_sort(struct dmi_system_id *d) +{ + if (pci_bf_sort == pci_bf_sort_default) { + pci_bf_sort = pci_dmi_bf; + printk(KERN_INFO "PCI: %s detected, enabling pci=bfsort.\n", d->ident); + } + return 0; +} + +/* + * Enable renumbering of PCI bus# ranges to reach all PCI busses (Cardbus) + */ +#ifdef __i386__ +static int __devinit assign_all_busses(struct dmi_system_id *d) +{ + pci_probe |= PCI_ASSIGN_ALL_BUSSES; + printk(KERN_INFO "%s detected: enabling PCI bus# renumbering" + " (pci=assign-busses)\n", d->ident); + return 0; +} +#endif + +static struct dmi_system_id __devinitdata pciprobe_dmi_table[] = { +#ifdef __i386__ +/* + * Laptops which need pci=assign-busses to see Cardbus cards + */ + { + .callback = assign_all_busses, + .ident = "Samsung X20 Laptop", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Samsung Electronics"), + DMI_MATCH(DMI_PRODUCT_NAME, "SX20S"), + }, + }, +#endif /* __i386__ */ + { + .callback = set_bf_sort, + .ident = "Dell PowerEdge 1950", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell"), + DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1950"), + }, + }, + { + .callback = set_bf_sort, + .ident = "Dell PowerEdge 1955", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell"), + DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1955"), + }, + }, + { + .callback = set_bf_sort, + .ident = "Dell PowerEdge 2900", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell"), + DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2900"), + }, + }, + { + .callback = set_bf_sort, + .ident = "Dell PowerEdge 2950", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell"), + DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2950"), + }, + }, + { + .callback = set_bf_sort, + .ident = "Dell PowerEdge R900", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell"), + DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge R900"), + }, + }, + { + .callback = set_bf_sort, + .ident = "HP ProLiant BL20p G3", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL20p G3"), + }, + }, + { + .callback = set_bf_sort, + .ident = "HP ProLiant BL20p G4", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL20p G4"), + }, + }, + { + .callback = set_bf_sort, + .ident = "HP ProLiant BL30p G1", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL30p G1"), + }, + }, + { + .callback = set_bf_sort, + .ident = "HP ProLiant BL25p G1", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL25p G1"), + }, + }, + { + .callback = set_bf_sort, + .ident = "HP ProLiant BL35p G1", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL35p G1"), + }, + }, + { + .callback = set_bf_sort, + .ident = "HP ProLiant BL45p G1", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL45p G1"), + }, + }, + { + .callback = set_bf_sort, + .ident = "HP ProLiant BL45p G2", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL45p G2"), + }, + }, + { + .callback = set_bf_sort, + .ident = "HP ProLiant BL460c G1", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL460c G1"), + }, + }, + { + .callback = set_bf_sort, + .ident = "HP ProLiant BL465c G1", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL465c G1"), + }, + }, + { + .callback = set_bf_sort, + .ident = "HP ProLiant BL480c G1", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL480c G1"), + }, + }, + { + .callback = set_bf_sort, + .ident = "HP ProLiant BL685c G1", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL685c G1"), + }, + }, + {} +}; + +struct pci_bus * __devinit pcibios_scan_root(int busnum) +{ + struct pci_bus *bus = NULL; + struct pci_sysdata *sd; + + dmi_check_system(pciprobe_dmi_table); + + while ((bus = pci_find_next_bus(bus)) != NULL) { + if (bus->number == busnum) { + /* Already scanned */ + return bus; + } + } + + /* Allocate per-root-bus (not per bus) arch-specific data. + * TODO: leak; this memory is never freed. + * It's arguable whether it's worth the trouble to care. + */ + sd = kzalloc(sizeof(*sd), GFP_KERNEL); + if (!sd) { + printk(KERN_ERR "PCI: OOM, not probing PCI bus %02x\n", busnum); + return NULL; + } + + printk(KERN_DEBUG "PCI: Probing PCI hardware (bus %02x)\n", busnum); + + return pci_scan_bus_parented(NULL, busnum, &pci_root_ops, sd); +} + +extern u8 pci_cache_line_size; + +static int __init pcibios_init(void) +{ + struct cpuinfo_x86 *c = &boot_cpu_data; + + if (!raw_pci_ops) { + printk(KERN_WARNING "PCI: System does not support PCI\n"); + return 0; + } + + /* + * Assume PCI cacheline size of 32 bytes for all x86s except K7/K8 + * and P4. It's also good for 386/486s (which actually have 16) + * as quite a few PCI devices do not support smaller values. + */ + pci_cache_line_size = 32 >> 2; + if (c->x86 >= 6 && c->x86_vendor == X86_VENDOR_AMD) + pci_cache_line_size = 64 >> 2; /* K7 & K8 */ + else if (c->x86 > 6 && c->x86_vendor == X86_VENDOR_INTEL) + pci_cache_line_size = 128 >> 2; /* P4 */ + + pcibios_resource_survey(); + + if (pci_bf_sort >= pci_force_bf) + pci_sort_breadthfirst(); +#ifdef CONFIG_PCI_BIOS + if ((pci_probe & PCI_BIOS_SORT) && !(pci_probe & PCI_NO_SORT)) + pcibios_sort(); +#endif + return 0; +} + +subsys_initcall(pcibios_init); + +char * __devinit pcibios_setup(char *str) +{ + if (!strcmp(str, "off")) { + pci_probe = 0; + return NULL; + } else if (!strcmp(str, "bfsort")) { + pci_bf_sort = pci_force_bf; + return NULL; + } else if (!strcmp(str, "nobfsort")) { + pci_bf_sort = pci_force_nobf; + return NULL; + } +#ifdef CONFIG_PCI_BIOS + else if (!strcmp(str, "bios")) { + pci_probe = PCI_PROBE_BIOS; + return NULL; + } else if (!strcmp(str, "nobios")) { + pci_probe &= ~PCI_PROBE_BIOS; + return NULL; + } else if (!strcmp(str, "nosort")) { + pci_probe |= PCI_NO_SORT; + return NULL; + } else if (!strcmp(str, "biosirq")) { + pci_probe |= PCI_BIOS_IRQ_SCAN; + return NULL; + } else if (!strncmp(str, "pirqaddr=", 9)) { + pirq_table_addr = simple_strtoul(str+9, NULL, 0); + return NULL; + } +#endif +#ifdef CONFIG_PCI_DIRECT + else if (!strcmp(str, "conf1")) { + pci_probe = PCI_PROBE_CONF1 | PCI_NO_CHECKS; + return NULL; + } + else if (!strcmp(str, "conf2")) { + pci_probe = PCI_PROBE_CONF2 | PCI_NO_CHECKS; + return NULL; + } +#endif +#ifdef CONFIG_PCI_MMCONFIG + else if (!strcmp(str, "nommconf")) { + pci_probe &= ~PCI_PROBE_MMCONF; + return NULL; + } +#endif + else if (!strcmp(str, "noacpi")) { + acpi_noirq_set(); + return NULL; + } + else if (!strcmp(str, "noearly")) { + pci_probe |= PCI_PROBE_NOEARLY; + return NULL; + } +#ifndef CONFIG_X86_VISWS + else if (!strcmp(str, "usepirqmask")) { + pci_probe |= PCI_USE_PIRQ_MASK; + return NULL; + } else if (!strncmp(str, "irqmask=", 8)) { + pcibios_irq_mask = simple_strtol(str+8, NULL, 0); + return NULL; + } else if (!strncmp(str, "lastbus=", 8)) { + pcibios_last_bus = simple_strtol(str+8, NULL, 0); + return NULL; + } +#endif + else if (!strcmp(str, "rom")) { + pci_probe |= PCI_ASSIGN_ROMS; + return NULL; + } else if (!strcmp(str, "assign-busses")) { + pci_probe |= PCI_ASSIGN_ALL_BUSSES; + return NULL; + } else if (!strcmp(str, "routeirq")) { + pci_routeirq = 1; + return NULL; + } + return str; +} + +unsigned int pcibios_assign_all_busses(void) +{ + return (pci_probe & PCI_ASSIGN_ALL_BUSSES) ? 1 : 0; +} + +int pcibios_enable_device(struct pci_dev *dev, int mask) +{ + int err; + + if ((err = pcibios_enable_resources(dev, mask)) < 0) + return err; + + if (!dev->msi_enabled) + return pcibios_enable_irq(dev); + return 0; +} + +void pcibios_disable_device (struct pci_dev *dev) +{ + if (!dev->msi_enabled && pcibios_disable_irq) + pcibios_disable_irq(dev); +} + +struct pci_bus *pci_scan_bus_with_sysdata(int busno) +{ + struct pci_bus *bus = NULL; + struct pci_sysdata *sd; + + /* + * Allocate per-root-bus (not per bus) arch-specific data. + * TODO: leak; this memory is never freed. + * It's arguable whether it's worth the trouble to care. + */ + sd = kzalloc(sizeof(*sd), GFP_KERNEL); + if (!sd) { + printk(KERN_ERR "PCI: OOM, skipping PCI bus %02x\n", busno); + return NULL; + } + sd->node = -1; + bus = pci_scan_bus(busno, &pci_root_ops, sd); + if (!bus) + kfree(sd); + + return bus; +} diff --git a/arch/x86/pci/direct.c b/arch/x86/pci/direct.c new file mode 100644 index 00000000000..431c9a51b15 --- /dev/null +++ b/arch/x86/pci/direct.c @@ -0,0 +1,302 @@ +/* + * direct.c - Low-level direct PCI config space access + */ + +#include +#include +#include +#include "pci.h" + +/* + * Functions for accessing PCI configuration space with type 1 accesses + */ + +#define PCI_CONF1_ADDRESS(bus, devfn, reg) \ + (0x80000000 | (bus << 16) | (devfn << 8) | (reg & ~3)) + +int pci_conf1_read(unsigned int seg, unsigned int bus, + unsigned int devfn, int reg, int len, u32 *value) +{ + unsigned long flags; + + if ((bus > 255) || (devfn > 255) || (reg > 255)) { + *value = -1; + return -EINVAL; + } + + spin_lock_irqsave(&pci_config_lock, flags); + + outl(PCI_CONF1_ADDRESS(bus, devfn, reg), 0xCF8); + + switch (len) { + case 1: + *value = inb(0xCFC + (reg & 3)); + break; + case 2: + *value = inw(0xCFC + (reg & 2)); + break; + case 4: + *value = inl(0xCFC); + break; + } + + spin_unlock_irqrestore(&pci_config_lock, flags); + + return 0; +} + +int pci_conf1_write(unsigned int seg, unsigned int bus, + unsigned int devfn, int reg, int len, u32 value) +{ + unsigned long flags; + + if ((bus > 255) || (devfn > 255) || (reg > 255)) + return -EINVAL; + + spin_lock_irqsave(&pci_config_lock, flags); + + outl(PCI_CONF1_ADDRESS(bus, devfn, reg), 0xCF8); + + switch (len) { + case 1: + outb((u8)value, 0xCFC + (reg & 3)); + break; + case 2: + outw((u16)value, 0xCFC + (reg & 2)); + break; + case 4: + outl((u32)value, 0xCFC); + break; + } + + spin_unlock_irqrestore(&pci_config_lock, flags); + + return 0; +} + +#undef PCI_CONF1_ADDRESS + +struct pci_raw_ops pci_direct_conf1 = { + .read = pci_conf1_read, + .write = pci_conf1_write, +}; + + +/* + * Functions for accessing PCI configuration space with type 2 accesses + */ + +#define PCI_CONF2_ADDRESS(dev, reg) (u16)(0xC000 | (dev << 8) | reg) + +static int pci_conf2_read(unsigned int seg, unsigned int bus, + unsigned int devfn, int reg, int len, u32 *value) +{ + unsigned long flags; + int dev, fn; + + if ((bus > 255) || (devfn > 255) || (reg > 255)) { + *value = -1; + return -EINVAL; + } + + dev = PCI_SLOT(devfn); + fn = PCI_FUNC(devfn); + + if (dev & 0x10) + return PCIBIOS_DEVICE_NOT_FOUND; + + spin_lock_irqsave(&pci_config_lock, flags); + + outb((u8)(0xF0 | (fn << 1)), 0xCF8); + outb((u8)bus, 0xCFA); + + switch (len) { + case 1: + *value = inb(PCI_CONF2_ADDRESS(dev, reg)); + break; + case 2: + *value = inw(PCI_CONF2_ADDRESS(dev, reg)); + break; + case 4: + *value = inl(PCI_CONF2_ADDRESS(dev, reg)); + break; + } + + outb(0, 0xCF8); + + spin_unlock_irqrestore(&pci_config_lock, flags); + + return 0; +} + +static int pci_conf2_write(unsigned int seg, unsigned int bus, + unsigned int devfn, int reg, int len, u32 value) +{ + unsigned long flags; + int dev, fn; + + if ((bus > 255) || (devfn > 255) || (reg > 255)) + return -EINVAL; + + dev = PCI_SLOT(devfn); + fn = PCI_FUNC(devfn); + + if (dev & 0x10) + return PCIBIOS_DEVICE_NOT_FOUND; + + spin_lock_irqsave(&pci_config_lock, flags); + + outb((u8)(0xF0 | (fn << 1)), 0xCF8); + outb((u8)bus, 0xCFA); + + switch (len) { + case 1: + outb((u8)value, PCI_CONF2_ADDRESS(dev, reg)); + break; + case 2: + outw((u16)value, PCI_CONF2_ADDRESS(dev, reg)); + break; + case 4: + outl((u32)value, PCI_CONF2_ADDRESS(dev, reg)); + break; + } + + outb(0, 0xCF8); + + spin_unlock_irqrestore(&pci_config_lock, flags); + + return 0; +} + +#undef PCI_CONF2_ADDRESS + +static struct pci_raw_ops pci_direct_conf2 = { + .read = pci_conf2_read, + .write = pci_conf2_write, +}; + + +/* + * Before we decide to use direct hardware access mechanisms, we try to do some + * trivial checks to ensure it at least _seems_ to be working -- we just test + * whether bus 00 contains a host bridge (this is similar to checking + * techniques used in XFree86, but ours should be more reliable since we + * attempt to make use of direct access hints provided by the PCI BIOS). + * + * This should be close to trivial, but it isn't, because there are buggy + * chipsets (yes, you guessed it, by Intel and Compaq) that have no class ID. + */ +static int __init pci_sanity_check(struct pci_raw_ops *o) +{ + u32 x = 0; + int devfn; + + if (pci_probe & PCI_NO_CHECKS) + return 1; + /* Assume Type 1 works for newer systems. + This handles machines that don't have anything on PCI Bus 0. */ + if (dmi_get_year(DMI_BIOS_DATE) >= 2001) + return 1; + + for (devfn = 0; devfn < 0x100; devfn++) { + if (o->read(0, 0, devfn, PCI_CLASS_DEVICE, 2, &x)) + continue; + if (x == PCI_CLASS_BRIDGE_HOST || x == PCI_CLASS_DISPLAY_VGA) + return 1; + + if (o->read(0, 0, devfn, PCI_VENDOR_ID, 2, &x)) + continue; + if (x == PCI_VENDOR_ID_INTEL || x == PCI_VENDOR_ID_COMPAQ) + return 1; + } + + DBG(KERN_WARNING "PCI: Sanity check failed\n"); + return 0; +} + +static int __init pci_check_type1(void) +{ + unsigned long flags; + unsigned int tmp; + int works = 0; + + local_irq_save(flags); + + outb(0x01, 0xCFB); + tmp = inl(0xCF8); + outl(0x80000000, 0xCF8); + if (inl(0xCF8) == 0x80000000 && pci_sanity_check(&pci_direct_conf1)) { + works = 1; + } + outl(tmp, 0xCF8); + local_irq_restore(flags); + + return works; +} + +static int __init pci_check_type2(void) +{ + unsigned long flags; + int works = 0; + + local_irq_save(flags); + + outb(0x00, 0xCFB); + outb(0x00, 0xCF8); + outb(0x00, 0xCFA); + if (inb(0xCF8) == 0x00 && inb(0xCFA) == 0x00 && + pci_sanity_check(&pci_direct_conf2)) { + works = 1; + } + + local_irq_restore(flags); + + return works; +} + +void __init pci_direct_init(int type) +{ + if (type == 0) + return; + printk(KERN_INFO "PCI: Using configuration type %d\n", type); + if (type == 1) + raw_pci_ops = &pci_direct_conf1; + else + raw_pci_ops = &pci_direct_conf2; +} + +int __init pci_direct_probe(void) +{ + struct resource *region, *region2; + + if ((pci_probe & PCI_PROBE_CONF1) == 0) + goto type2; + region = request_region(0xCF8, 8, "PCI conf1"); + if (!region) + goto type2; + + if (pci_check_type1()) + return 1; + release_resource(region); + + type2: + if ((pci_probe & PCI_PROBE_CONF2) == 0) + return 0; + region = request_region(0xCF8, 4, "PCI conf2"); + if (!region) + return 0; + region2 = request_region(0xC000, 0x1000, "PCI conf2"); + if (!region2) + goto fail2; + + if (pci_check_type2()) { + printk(KERN_INFO "PCI: Using configuration type 2\n"); + raw_pci_ops = &pci_direct_conf2; + return 2; + } + + release_resource(region2); + fail2: + release_resource(region); + return 0; +} diff --git a/arch/x86/pci/early.c b/arch/x86/pci/early.c new file mode 100644 index 00000000000..42df4b6606d --- /dev/null +++ b/arch/x86/pci/early.c @@ -0,0 +1,59 @@ +#include +#include +#include +#include +#include "pci.h" + +/* Direct PCI access. This is used for PCI accesses in early boot before + the PCI subsystem works. */ + +#define PDprintk(x...) + +u32 read_pci_config(u8 bus, u8 slot, u8 func, u8 offset) +{ + u32 v; + outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8); + v = inl(0xcfc); + if (v != 0xffffffff) + PDprintk("%x reading 4 from %x: %x\n", slot, offset, v); + return v; +} + +u8 read_pci_config_byte(u8 bus, u8 slot, u8 func, u8 offset) +{ + u8 v; + outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8); + v = inb(0xcfc + (offset&3)); + PDprintk("%x reading 1 from %x: %x\n", slot, offset, v); + return v; +} + +u16 read_pci_config_16(u8 bus, u8 slot, u8 func, u8 offset) +{ + u16 v; + outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8); + v = inw(0xcfc + (offset&2)); + PDprintk("%x reading 2 from %x: %x\n", slot, offset, v); + return v; +} + +void write_pci_config(u8 bus, u8 slot, u8 func, u8 offset, + u32 val) +{ + PDprintk("%x writing to %x: %x\n", slot, offset, val); + outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8); + outl(val, 0xcfc); +} + +void write_pci_config_byte(u8 bus, u8 slot, u8 func, u8 offset, u8 val) +{ + PDprintk("%x writing to %x: %x\n", slot, offset, val); + outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8); + outb(val, 0xcfc); +} + +int early_pci_allowed(void) +{ + return (pci_probe & (PCI_PROBE_CONF1|PCI_PROBE_NOEARLY)) == + PCI_PROBE_CONF1; +} diff --git a/arch/x86/pci/fixup.c b/arch/x86/pci/fixup.c new file mode 100644 index 00000000000..c82cbf4c722 --- /dev/null +++ b/arch/x86/pci/fixup.c @@ -0,0 +1,446 @@ +/* + * Exceptions for specific devices. Usually work-arounds for fatal design flaws. + */ + +#include +#include +#include +#include +#include "pci.h" + + +static void __devinit pci_fixup_i450nx(struct pci_dev *d) +{ + /* + * i450NX -- Find and scan all secondary buses on all PXB's. + */ + int pxb, reg; + u8 busno, suba, subb; + + printk(KERN_WARNING "PCI: Searching for i450NX host bridges on %s\n", pci_name(d)); + reg = 0xd0; + for(pxb=0; pxb<2; pxb++) { + pci_read_config_byte(d, reg++, &busno); + pci_read_config_byte(d, reg++, &suba); + pci_read_config_byte(d, reg++, &subb); + DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb); + if (busno) + pci_scan_bus_with_sysdata(busno); /* Bus A */ + if (suba < subb) + pci_scan_bus_with_sysdata(suba+1); /* Bus B */ + } + pcibios_last_bus = -1; +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_fixup_i450nx); + +static void __devinit pci_fixup_i450gx(struct pci_dev *d) +{ + /* + * i450GX and i450KX -- Find and scan all secondary buses. + * (called separately for each PCI bridge found) + */ + u8 busno; + pci_read_config_byte(d, 0x4a, &busno); + printk(KERN_INFO "PCI: i440KX/GX host bridge %s: secondary bus %02x\n", pci_name(d), busno); + pci_scan_bus_with_sysdata(busno); + pcibios_last_bus = -1; +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454GX, pci_fixup_i450gx); + +static void __devinit pci_fixup_umc_ide(struct pci_dev *d) +{ + /* + * UM8886BF IDE controller sets region type bits incorrectly, + * therefore they look like memory despite of them being I/O. + */ + int i; + + printk(KERN_WARNING "PCI: Fixing base address flags for device %s\n", pci_name(d)); + for(i=0; i<4; i++) + d->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO; +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF, pci_fixup_umc_ide); + +static void __devinit pci_fixup_ncr53c810(struct pci_dev *d) +{ + /* + * NCR 53C810 returns class code 0 (at least on some systems). + * Fix class to be PCI_CLASS_STORAGE_SCSI + */ + if (!d->class) { + printk(KERN_WARNING "PCI: fixing NCR 53C810 class code for %s\n", pci_name(d)); + d->class = PCI_CLASS_STORAGE_SCSI << 8; + } +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C810, pci_fixup_ncr53c810); + +static void __devinit pci_fixup_latency(struct pci_dev *d) +{ + /* + * SiS 5597 and 5598 chipsets require latency timer set to + * at most 32 to avoid lockups. + */ + DBG("PCI: Setting max latency to 32\n"); + pcibios_max_latency = 32; +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, pci_fixup_latency); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5598, pci_fixup_latency); + +static void __devinit pci_fixup_piix4_acpi(struct pci_dev *d) +{ + /* + * PIIX4 ACPI device: hardwired IRQ9 + */ + d->irq = 9; +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, pci_fixup_piix4_acpi); + +/* + * Addresses issues with problems in the memory write queue timer in + * certain VIA Northbridges. This bugfix is per VIA's specifications, + * except for the KL133/KM133: clearing bit 5 on those Northbridges seems + * to trigger a bug in its integrated ProSavage video card, which + * causes screen corruption. We only clear bits 6 and 7 for that chipset, + * until VIA can provide us with definitive information on why screen + * corruption occurs, and what exactly those bits do. + * + * VIA 8363,8622,8361 Northbridges: + * - bits 5, 6, 7 at offset 0x55 need to be turned off + * VIA 8367 (KT266x) Northbridges: + * - bits 5, 6, 7 at offset 0x95 need to be turned off + * VIA 8363 rev 0x81/0x84 (KL133/KM133) Northbridges: + * - bits 6, 7 at offset 0x55 need to be turned off + */ + +#define VIA_8363_KL133_REVISION_ID 0x81 +#define VIA_8363_KM133_REVISION_ID 0x84 + +static void pci_fixup_via_northbridge_bug(struct pci_dev *d) +{ + u8 v; + int where = 0x55; + int mask = 0x1f; /* clear bits 5, 6, 7 by default */ + + if (d->device == PCI_DEVICE_ID_VIA_8367_0) { + /* fix pci bus latency issues resulted by NB bios error + it appears on bug free^Wreduced kt266x's bios forces + NB latency to zero */ + pci_write_config_byte(d, PCI_LATENCY_TIMER, 0); + + where = 0x95; /* the memory write queue timer register is + different for the KT266x's: 0x95 not 0x55 */ + } else if (d->device == PCI_DEVICE_ID_VIA_8363_0 && + (d->revision == VIA_8363_KL133_REVISION_ID || + d->revision == VIA_8363_KM133_REVISION_ID)) { + mask = 0x3f; /* clear only bits 6 and 7; clearing bit 5 + causes screen corruption on the KL133/KM133 */ + } + + pci_read_config_byte(d, where, &v); + if (v & ~mask) { + printk(KERN_WARNING "Disabling VIA memory write queue (PCI ID %04x, rev %02x): [%02x] %02x & %02x -> %02x\n", \ + d->device, d->revision, where, v, mask, v & mask); + v &= mask; + pci_write_config_byte(d, where, v); + } +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, pci_fixup_via_northbridge_bug); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8622, pci_fixup_via_northbridge_bug); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8361, pci_fixup_via_northbridge_bug); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8367_0, pci_fixup_via_northbridge_bug); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, pci_fixup_via_northbridge_bug); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8622, pci_fixup_via_northbridge_bug); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8361, pci_fixup_via_northbridge_bug); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8367_0, pci_fixup_via_northbridge_bug); + +/* + * For some reasons Intel decided that certain parts of their + * 815, 845 and some other chipsets must look like PCI-to-PCI bridges + * while they are obviously not. The 82801 family (AA, AB, BAM/CAM, + * BA/CA/DB and E) PCI bridges are actually HUB-to-PCI ones, according + * to Intel terminology. These devices do forward all addresses from + * system to PCI bus no matter what are their window settings, so they are + * "transparent" (or subtractive decoding) from programmers point of view. + */ +static void __devinit pci_fixup_transparent_bridge(struct pci_dev *dev) +{ + if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI && + (dev->device & 0xff00) == 0x2400) + dev->transparent = 1; +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_fixup_transparent_bridge); + +/* + * Fixup for C1 Halt Disconnect problem on nForce2 systems. + * + * From information provided by "Allen Martin" : + * + * A hang is caused when the CPU generates a very fast CONNECT/HALT cycle + * sequence. Workaround is to set the SYSTEM_IDLE_TIMEOUT to 80 ns. + * This allows the state-machine and timer to return to a proper state within + * 80 ns of the CONNECT and probe appearing together. Since the CPU will not + * issue another HALT within 80 ns of the initial HALT, the failure condition + * is avoided. + */ +static void pci_fixup_nforce2(struct pci_dev *dev) +{ + u32 val; + + /* + * Chip Old value New value + * C17 0x1F0FFF01 0x1F01FF01 + * C18D 0x9F0FFF01 0x9F01FF01 + * + * Northbridge chip version may be determined by + * reading the PCI revision ID (0xC1 or greater is C18D). + */ + pci_read_config_dword(dev, 0x6c, &val); + + /* + * Apply fixup if needed, but don't touch disconnect state + */ + if ((val & 0x00FF0000) != 0x00010000) { + printk(KERN_WARNING "PCI: nForce2 C1 Halt Disconnect fixup\n"); + pci_write_config_dword(dev, 0x6c, (val & 0xFF00FFFF) | 0x00010000); + } +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2, pci_fixup_nforce2); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2, pci_fixup_nforce2); + +/* Max PCI Express root ports */ +#define MAX_PCIEROOT 6 +static int quirk_aspm_offset[MAX_PCIEROOT << 3]; + +#define GET_INDEX(a, b) ((((a) - PCI_DEVICE_ID_INTEL_MCH_PA) << 3) + ((b) & 7)) + +static int quirk_pcie_aspm_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) +{ + return raw_pci_ops->read(0, bus->number, devfn, where, size, value); +} + +/* + * Replace the original pci bus ops for write with a new one that will filter + * the request to insure ASPM cannot be enabled. + */ +static int quirk_pcie_aspm_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) +{ + u8 offset; + + offset = quirk_aspm_offset[GET_INDEX(bus->self->device, devfn)]; + + if ((offset) && (where == offset)) + value = value & 0xfffffffc; + + return raw_pci_ops->write(0, bus->number, devfn, where, size, value); +} + +static struct pci_ops quirk_pcie_aspm_ops = { + .read = quirk_pcie_aspm_read, + .write = quirk_pcie_aspm_write, +}; + +/* + * Prevents PCI Express ASPM (Active State Power Management) being enabled. + * + * Save the register offset, where the ASPM control bits are located, + * for each PCI Express device that is in the device list of + * the root port in an array for fast indexing. Replace the bus ops + * with the modified one. + */ +static void pcie_rootport_aspm_quirk(struct pci_dev *pdev) +{ + int cap_base, i; + struct pci_bus *pbus; + struct pci_dev *dev; + + if ((pbus = pdev->subordinate) == NULL) + return; + + /* + * Check if the DID of pdev matches one of the six root ports. This + * check is needed in the case this function is called directly by the + * hot-plug driver. + */ + if ((pdev->device < PCI_DEVICE_ID_INTEL_MCH_PA) || + (pdev->device > PCI_DEVICE_ID_INTEL_MCH_PC1)) + return; + + if (list_empty(&pbus->devices)) { + /* + * If no device is attached to the root port at power-up or + * after hot-remove, the pbus->devices is empty and this code + * will set the offsets to zero and the bus ops to parent's bus + * ops, which is unmodified. + */ + for (i= GET_INDEX(pdev->device, 0); i <= GET_INDEX(pdev->device, 7); ++i) + quirk_aspm_offset[i] = 0; + + pbus->ops = pbus->parent->ops; + } else { + /* + * If devices are attached to the root port at power-up or + * after hot-add, the code loops through the device list of + * each root port to save the register offsets and replace the + * bus ops. + */ + list_for_each_entry(dev, &pbus->devices, bus_list) { + /* There are 0 to 8 devices attached to this bus */ + cap_base = pci_find_capability(dev, PCI_CAP_ID_EXP); + quirk_aspm_offset[GET_INDEX(pdev->device, dev->devfn)]= cap_base + 0x10; + } + pbus->ops = &quirk_pcie_aspm_ops; + } +} +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PA, pcie_rootport_aspm_quirk ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PA1, pcie_rootport_aspm_quirk ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PB, pcie_rootport_aspm_quirk ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PB1, pcie_rootport_aspm_quirk ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PC, pcie_rootport_aspm_quirk ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PC1, pcie_rootport_aspm_quirk ); + +/* + * Fixup to mark boot BIOS video selected by BIOS before it changes + * + * From information provided by "Jon Smirl" + * + * The standard boot ROM sequence for an x86 machine uses the BIOS + * to select an initial video card for boot display. This boot video + * card will have it's BIOS copied to C0000 in system RAM. + * IORESOURCE_ROM_SHADOW is used to associate the boot video + * card with this copy. On laptops this copy has to be used since + * the main ROM may be compressed or combined with another image. + * See pci_map_rom() for use of this flag. IORESOURCE_ROM_SHADOW + * is marked here since the boot video device will be the only enabled + * video device at this point. + */ + +static void __devinit pci_fixup_video(struct pci_dev *pdev) +{ + struct pci_dev *bridge; + struct pci_bus *bus; + u16 config; + + if ((pdev->class >> 8) != PCI_CLASS_DISPLAY_VGA) + return; + + /* Is VGA routed to us? */ + bus = pdev->bus; + while (bus) { + bridge = bus->self; + + /* + * From information provided by + * "David Miller" + * The bridge control register is valid for PCI header + * type BRIDGE, or CARDBUS. Host to PCI controllers use + * PCI header type NORMAL. + */ + if (bridge + &&((bridge->hdr_type == PCI_HEADER_TYPE_BRIDGE) + ||(bridge->hdr_type == PCI_HEADER_TYPE_CARDBUS))) { + pci_read_config_word(bridge, PCI_BRIDGE_CONTROL, + &config); + if (!(config & PCI_BRIDGE_CTL_VGA)) + return; + } + bus = bus->parent; + } + pci_read_config_word(pdev, PCI_COMMAND, &config); + if (config & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) { + pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_SHADOW; + printk(KERN_DEBUG "Boot video device is %s\n", pci_name(pdev)); + } +} +DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_video); + +/* + * Some Toshiba laptops need extra code to enable their TI TSB43AB22/A. + * + * We pretend to bring them out of full D3 state, and restore the proper + * IRQ, PCI cache line size, and BARs, otherwise the device won't function + * properly. In some cases, the device will generate an interrupt on + * the wrong IRQ line, causing any devices sharing the line it's + * *supposed* to use to be disabled by the kernel's IRQ debug code. + */ +static u16 toshiba_line_size; + +static struct dmi_system_id __devinitdata toshiba_ohci1394_dmi_table[] = { + { + .ident = "Toshiba PS5 based laptop", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_VERSION, "PS5"), + }, + }, + { + .ident = "Toshiba PSM4 based laptop", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_VERSION, "PSM4"), + }, + }, + { + .ident = "Toshiba A40 based laptop", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_VERSION, "PSA40U"), + }, + }, + { } +}; + +static void __devinit pci_pre_fixup_toshiba_ohci1394(struct pci_dev *dev) +{ + if (!dmi_check_system(toshiba_ohci1394_dmi_table)) + return; /* only applies to certain Toshibas (so far) */ + + dev->current_state = PCI_D3cold; + pci_read_config_word(dev, PCI_CACHE_LINE_SIZE, &toshiba_line_size); +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TI, 0x8032, + pci_pre_fixup_toshiba_ohci1394); + +static void __devinit pci_post_fixup_toshiba_ohci1394(struct pci_dev *dev) +{ + if (!dmi_check_system(toshiba_ohci1394_dmi_table)) + return; /* only applies to certain Toshibas (so far) */ + + /* Restore config space on Toshiba laptops */ + pci_write_config_word(dev, PCI_CACHE_LINE_SIZE, toshiba_line_size); + pci_read_config_byte(dev, PCI_INTERRUPT_LINE, (u8 *)&dev->irq); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, + pci_resource_start(dev, 0)); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, + pci_resource_start(dev, 1)); +} +DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_TI, 0x8032, + pci_post_fixup_toshiba_ohci1394); + + +/* + * Prevent the BIOS trapping accesses to the Cyrix CS5530A video device + * configuration space. + */ +static void pci_early_fixup_cyrix_5530(struct pci_dev *dev) +{ + u8 r; + /* clear 'F4 Video Configuration Trap' bit */ + pci_read_config_byte(dev, 0x42, &r); + r &= 0xfd; + pci_write_config_byte(dev, 0x42, r); +} +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_LEGACY, + pci_early_fixup_cyrix_5530); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_LEGACY, + pci_early_fixup_cyrix_5530); + +/* + * Siemens Nixdorf AG FSC Multiprocessor Interrupt Controller: + * prevent update of the BAR0, which doesn't look like a normal BAR. + */ +static void __devinit pci_siemens_interrupt_controller(struct pci_dev *dev) +{ + dev->resource[0].flags |= IORESOURCE_PCI_FIXED; +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SIEMENS, 0x0015, + pci_siemens_interrupt_controller); diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c new file mode 100644 index 00000000000..bcd2f94b732 --- /dev/null +++ b/arch/x86/pci/i386.c @@ -0,0 +1,315 @@ +/* + * Low-Level PCI Access for i386 machines + * + * Copyright 1993, 1994 Drew Eckhardt + * Visionary Computing + * (Unix and Linux consulting and custom programming) + * Drew@Colorado.EDU + * +1 (303) 786-7975 + * + * Drew's work was sponsored by: + * iX Multiuser Multitasking Magazine + * Hannover, Germany + * hm@ix.de + * + * Copyright 1997--2000 Martin Mares + * + * For more information, please consult the following manuals (look at + * http://www.pcisig.com/ for how to get them): + * + * PCI BIOS Specification + * PCI Local Bus Specification + * PCI to PCI Bridge Specification + * PCI System Design Guide + * + */ + +#include +#include +#include +#include +#include +#include + +#include "pci.h" + +/* + * We need to avoid collisions with `mirrored' VGA ports + * and other strange ISA hardware, so we always want the + * addresses to be allocated in the 0x000-0x0ff region + * modulo 0x400. + * + * Why? Because some silly external IO cards only decode + * the low 10 bits of the IO address. The 0x00-0xff region + * is reserved for motherboard devices that decode all 16 + * bits, so it's ok to allocate at, say, 0x2800-0x28ff, + * but we want to try to avoid allocating at 0x2900-0x2bff + * which might have be mirrored at 0x0100-0x03ff.. + */ +void +pcibios_align_resource(void *data, struct resource *res, + resource_size_t size, resource_size_t align) +{ + if (res->flags & IORESOURCE_IO) { + resource_size_t start = res->start; + + if (start & 0x300) { + start = (start + 0x3ff) & ~0x3ff; + res->start = start; + } + } +} + + +/* + * Handle resources of PCI devices. If the world were perfect, we could + * just allocate all the resource regions and do nothing more. It isn't. + * On the other hand, we cannot just re-allocate all devices, as it would + * require us to know lots of host bridge internals. So we attempt to + * keep as much of the original configuration as possible, but tweak it + * when it's found to be wrong. + * + * Known BIOS problems we have to work around: + * - I/O or memory regions not configured + * - regions configured, but not enabled in the command register + * - bogus I/O addresses above 64K used + * - expansion ROMs left enabled (this may sound harmless, but given + * the fact the PCI specs explicitly allow address decoders to be + * shared between expansion ROMs and other resource regions, it's + * at least dangerous) + * + * Our solution: + * (1) Allocate resources for all buses behind PCI-to-PCI bridges. + * This gives us fixed barriers on where we can allocate. + * (2) Allocate resources for all enabled devices. If there is + * a collision, just mark the resource as unallocated. Also + * disable expansion ROMs during this step. + * (3) Try to allocate resources for disabled devices. If the + * resources were assigned correctly, everything goes well, + * if they weren't, they won't disturb allocation of other + * resources. + * (4) Assign new addresses to resources which were either + * not configured at all or misconfigured. If explicitly + * requested by the user, configure expansion ROM address + * as well. + */ + +static void __init pcibios_allocate_bus_resources(struct list_head *bus_list) +{ + struct pci_bus *bus; + struct pci_dev *dev; + int idx; + struct resource *r, *pr; + + /* Depth-First Search on bus tree */ + list_for_each_entry(bus, bus_list, node) { + if ((dev = bus->self)) { + for (idx = PCI_BRIDGE_RESOURCES; + idx < PCI_NUM_RESOURCES; idx++) { + r = &dev->resource[idx]; + if (!r->flags) + continue; + pr = pci_find_parent_resource(dev, r); + if (!r->start || !pr || + request_resource(pr, r) < 0) { + printk(KERN_ERR "PCI: Cannot allocate " + "resource region %d " + "of bridge %s\n", + idx, pci_name(dev)); + /* + * Something is wrong with the region. + * Invalidate the resource to prevent + * child resource allocations in this + * range. + */ + r->flags = 0; + } + } + } + pcibios_allocate_bus_resources(&bus->children); + } +} + +static void __init pcibios_allocate_resources(int pass) +{ + struct pci_dev *dev = NULL; + int idx, disabled; + u16 command; + struct resource *r, *pr; + + for_each_pci_dev(dev) { + pci_read_config_word(dev, PCI_COMMAND, &command); + for (idx = 0; idx < PCI_ROM_RESOURCE; idx++) { + r = &dev->resource[idx]; + if (r->parent) /* Already allocated */ + continue; + if (!r->start) /* Address not assigned at all */ + continue; + if (r->flags & IORESOURCE_IO) + disabled = !(command & PCI_COMMAND_IO); + else + disabled = !(command & PCI_COMMAND_MEMORY); + if (pass == disabled) { + DBG("PCI: Resource %08lx-%08lx " + "(f=%lx, d=%d, p=%d)\n", + r->start, r->end, r->flags, disabled, pass); + pr = pci_find_parent_resource(dev, r); + if (!pr || request_resource(pr, r) < 0) { + printk(KERN_ERR "PCI: Cannot allocate " + "resource region %d " + "of device %s\n", + idx, pci_name(dev)); + /* We'll assign a new address later */ + r->end -= r->start; + r->start = 0; + } + } + } + if (!pass) { + r = &dev->resource[PCI_ROM_RESOURCE]; + if (r->flags & IORESOURCE_ROM_ENABLE) { + /* Turn the ROM off, leave the resource region, + * but keep it unregistered. */ + u32 reg; + DBG("PCI: Switching off ROM of %s\n", + pci_name(dev)); + r->flags &= ~IORESOURCE_ROM_ENABLE; + pci_read_config_dword(dev, + dev->rom_base_reg, ®); + pci_write_config_dword(dev, dev->rom_base_reg, + reg & ~PCI_ROM_ADDRESS_ENABLE); + } + } + } +} + +static int __init pcibios_assign_resources(void) +{ + struct pci_dev *dev = NULL; + struct resource *r, *pr; + + if (!(pci_probe & PCI_ASSIGN_ROMS)) { + /* + * Try to use BIOS settings for ROMs, otherwise let + * pci_assign_unassigned_resources() allocate the new + * addresses. + */ + for_each_pci_dev(dev) { + r = &dev->resource[PCI_ROM_RESOURCE]; + if (!r->flags || !r->start) + continue; + pr = pci_find_parent_resource(dev, r); + if (!pr || request_resource(pr, r) < 0) { + r->end -= r->start; + r->start = 0; + } + } + } + + pci_assign_unassigned_resources(); + + return 0; +} + +void __init pcibios_resource_survey(void) +{ + DBG("PCI: Allocating resources\n"); + pcibios_allocate_bus_resources(&pci_root_buses); + pcibios_allocate_resources(0); + pcibios_allocate_resources(1); +} + +/** + * called in fs_initcall (one below subsys_initcall), + * give a chance for motherboard reserve resources + */ +fs_initcall(pcibios_assign_resources); + +int pcibios_enable_resources(struct pci_dev *dev, int mask) +{ + u16 cmd, old_cmd; + int idx; + struct resource *r; + + pci_read_config_word(dev, PCI_COMMAND, &cmd); + old_cmd = cmd; + for (idx = 0; idx < PCI_NUM_RESOURCES; idx++) { + /* Only set up the requested stuff */ + if (!(mask & (1 << idx))) + continue; + + r = &dev->resource[idx]; + if (!(r->flags & (IORESOURCE_IO | IORESOURCE_MEM))) + continue; + if ((idx == PCI_ROM_RESOURCE) && + (!(r->flags & IORESOURCE_ROM_ENABLE))) + continue; + if (!r->start && r->end) { + printk(KERN_ERR "PCI: Device %s not available " + "because of resource %d collisions\n", + pci_name(dev), idx); + return -EINVAL; + } + if (r->flags & IORESOURCE_IO) + cmd |= PCI_COMMAND_IO; + if (r->flags & IORESOURCE_MEM) + cmd |= PCI_COMMAND_MEMORY; + } + if (cmd != old_cmd) { + printk("PCI: Enabling device %s (%04x -> %04x)\n", + pci_name(dev), old_cmd, cmd); + pci_write_config_word(dev, PCI_COMMAND, cmd); + } + return 0; +} + +/* + * If we set up a device for bus mastering, we need to check the latency + * timer as certain crappy BIOSes forget to set it properly. + */ +unsigned int pcibios_max_latency = 255; + +void pcibios_set_master(struct pci_dev *dev) +{ + u8 lat; + pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); + if (lat < 16) + lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency; + else if (lat > pcibios_max_latency) + lat = pcibios_max_latency; + else + return; + printk(KERN_DEBUG "PCI: Setting latency timer of device %s to %d\n", + pci_name(dev), lat); + pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat); +} + +int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, + enum pci_mmap_state mmap_state, int write_combine) +{ + unsigned long prot; + + /* I/O space cannot be accessed via normal processor loads and + * stores on this platform. + */ + if (mmap_state == pci_mmap_io) + return -EINVAL; + + /* Leave vm_pgoff as-is, the PCI space address is the physical + * address on this platform. + */ + prot = pgprot_val(vma->vm_page_prot); + if (boot_cpu_data.x86 > 3) + prot |= _PAGE_PCD | _PAGE_PWT; + vma->vm_page_prot = __pgprot(prot); + + /* Write-combine setting is ignored, it is changed via the mtrr + * interfaces on this platform. + */ + if (io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, + vma->vm_end - vma->vm_start, + vma->vm_page_prot)) + return -EAGAIN; + + return 0; +} diff --git a/arch/x86/pci/init.c b/arch/x86/pci/init.c new file mode 100644 index 00000000000..3de9f9ba2da --- /dev/null +++ b/arch/x86/pci/init.c @@ -0,0 +1,37 @@ +#include +#include +#include "pci.h" + +/* arch_initcall has too random ordering, so call the initializers + in the right sequence from here. */ +static __init int pci_access_init(void) +{ + int type __maybe_unused = 0; + +#ifdef CONFIG_PCI_DIRECT + type = pci_direct_probe(); +#endif +#ifdef CONFIG_PCI_MMCONFIG + pci_mmcfg_init(type); +#endif + if (raw_pci_ops) + return 0; +#ifdef CONFIG_PCI_BIOS + pci_pcbios_init(); +#endif + /* + * don't check for raw_pci_ops here because we want pcbios as last + * fallback, yet it's needed to run first to set pcibios_last_bus + * in case legacy PCI probing is used. otherwise detecting peer busses + * fails. + */ +#ifdef CONFIG_PCI_DIRECT + pci_direct_init(type); +#endif + if (!raw_pci_ops) + printk(KERN_ERR + "PCI: Fatal: No config space access function found\n"); + + return 0; +} +arch_initcall(pci_access_init); diff --git a/arch/x86/pci/irq.c b/arch/x86/pci/irq.c new file mode 100644 index 00000000000..8434f2323b8 --- /dev/null +++ b/arch/x86/pci/irq.c @@ -0,0 +1,1173 @@ +/* + * Low-Level PCI Support for PC -- Routing of Interrupts + * + * (c) 1999--2000 Martin Mares + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pci.h" + +#define PIRQ_SIGNATURE (('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24)) +#define PIRQ_VERSION 0x0100 + +static int broken_hp_bios_irq9; +static int acer_tm360_irqrouting; + +static struct irq_routing_table *pirq_table; + +static int pirq_enable_irq(struct pci_dev *dev); + +/* + * Never use: 0, 1, 2 (timer, keyboard, and cascade) + * Avoid using: 13, 14 and 15 (FP error and IDE). + * Penalize: 3, 4, 6, 7, 12 (known ISA uses: serial, floppy, parallel and mouse) + */ +unsigned int pcibios_irq_mask = 0xfff8; + +static int pirq_penalty[16] = { + 1000000, 1000000, 1000000, 1000, 1000, 0, 1000, 1000, + 0, 0, 0, 0, 1000, 100000, 100000, 100000 +}; + +struct irq_router { + char *name; + u16 vendor, device; + int (*get)(struct pci_dev *router, struct pci_dev *dev, int pirq); + int (*set)(struct pci_dev *router, struct pci_dev *dev, int pirq, int new); +}; + +struct irq_router_handler { + u16 vendor; + int (*probe)(struct irq_router *r, struct pci_dev *router, u16 device); +}; + +int (*pcibios_enable_irq)(struct pci_dev *dev) = NULL; +void (*pcibios_disable_irq)(struct pci_dev *dev) = NULL; + +/* + * Check passed address for the PCI IRQ Routing Table signature + * and perform checksum verification. + */ + +static inline struct irq_routing_table * pirq_check_routing_table(u8 *addr) +{ + struct irq_routing_table *rt; + int i; + u8 sum; + + rt = (struct irq_routing_table *) addr; + if (rt->signature != PIRQ_SIGNATURE || + rt->version != PIRQ_VERSION || + rt->size % 16 || + rt->size < sizeof(struct irq_routing_table)) + return NULL; + sum = 0; + for (i=0; i < rt->size; i++) + sum += addr[i]; + if (!sum) { + DBG(KERN_DEBUG "PCI: Interrupt Routing Table found at 0x%p\n", rt); + return rt; + } + return NULL; +} + + + +/* + * Search 0xf0000 -- 0xfffff for the PCI IRQ Routing Table. + */ + +static struct irq_routing_table * __init pirq_find_routing_table(void) +{ + u8 *addr; + struct irq_routing_table *rt; + + if (pirq_table_addr) { + rt = pirq_check_routing_table((u8 *) __va(pirq_table_addr)); + if (rt) + return rt; + printk(KERN_WARNING "PCI: PIRQ table NOT found at pirqaddr\n"); + } + for(addr = (u8 *) __va(0xf0000); addr < (u8 *) __va(0x100000); addr += 16) { + rt = pirq_check_routing_table(addr); + if (rt) + return rt; + } + return NULL; +} + +/* + * If we have a IRQ routing table, use it to search for peer host + * bridges. It's a gross hack, but since there are no other known + * ways how to get a list of buses, we have to go this way. + */ + +static void __init pirq_peer_trick(void) +{ + struct irq_routing_table *rt = pirq_table; + u8 busmap[256]; + int i; + struct irq_info *e; + + memset(busmap, 0, sizeof(busmap)); + for(i=0; i < (rt->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info); i++) { + e = &rt->slots[i]; +#ifdef DEBUG + { + int j; + DBG(KERN_DEBUG "%02x:%02x slot=%02x", e->bus, e->devfn/8, e->slot); + for(j=0; j<4; j++) + DBG(" %d:%02x/%04x", j, e->irq[j].link, e->irq[j].bitmap); + DBG("\n"); + } +#endif + busmap[e->bus] = 1; + } + for(i = 1; i < 256; i++) { + if (!busmap[i] || pci_find_bus(0, i)) + continue; + if (pci_scan_bus_with_sysdata(i)) + printk(KERN_INFO "PCI: Discovered primary peer " + "bus %02x [IRQ]\n", i); + } + pcibios_last_bus = -1; +} + +/* + * Code for querying and setting of IRQ routes on various interrupt routers. + */ + +void eisa_set_level_irq(unsigned int irq) +{ + unsigned char mask = 1 << (irq & 7); + unsigned int port = 0x4d0 + (irq >> 3); + unsigned char val; + static u16 eisa_irq_mask; + + if (irq >= 16 || (1 << irq) & eisa_irq_mask) + return; + + eisa_irq_mask |= (1 << irq); + printk(KERN_DEBUG "PCI: setting IRQ %u as level-triggered\n", irq); + val = inb(port); + if (!(val & mask)) { + DBG(KERN_DEBUG " -> edge"); + outb(val | mask, port); + } +} + +/* + * Common IRQ routing practice: nybbles in config space, + * offset by some magic constant. + */ +static unsigned int read_config_nybble(struct pci_dev *router, unsigned offset, unsigned nr) +{ + u8 x; + unsigned reg = offset + (nr >> 1); + + pci_read_config_byte(router, reg, &x); + return (nr & 1) ? (x >> 4) : (x & 0xf); +} + +static void write_config_nybble(struct pci_dev *router, unsigned offset, unsigned nr, unsigned int val) +{ + u8 x; + unsigned reg = offset + (nr >> 1); + + pci_read_config_byte(router, reg, &x); + x = (nr & 1) ? ((x & 0x0f) | (val << 4)) : ((x & 0xf0) | val); + pci_write_config_byte(router, reg, x); +} + +/* + * ALI pirq entries are damn ugly, and completely undocumented. + * This has been figured out from pirq tables, and it's not a pretty + * picture. + */ +static int pirq_ali_get(struct pci_dev *router, struct pci_dev *dev, int pirq) +{ + static const unsigned char irqmap[16] = { 0, 9, 3, 10, 4, 5, 7, 6, 1, 11, 0, 12, 0, 14, 0, 15 }; + + return irqmap[read_config_nybble(router, 0x48, pirq-1)]; +} + +static int pirq_ali_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) +{ + static const unsigned char irqmap[16] = { 0, 8, 0, 2, 4, 5, 7, 6, 0, 1, 3, 9, 11, 0, 13, 15 }; + unsigned int val = irqmap[irq]; + + if (val) { + write_config_nybble(router, 0x48, pirq-1, val); + return 1; + } + return 0; +} + +/* + * The Intel PIIX4 pirq rules are fairly simple: "pirq" is + * just a pointer to the config space. + */ +static int pirq_piix_get(struct pci_dev *router, struct pci_dev *dev, int pirq) +{ + u8 x; + + pci_read_config_byte(router, pirq, &x); + return (x < 16) ? x : 0; +} + +static int pirq_piix_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) +{ + pci_write_config_byte(router, pirq, irq); + return 1; +} + +/* + * The VIA pirq rules are nibble-based, like ALI, + * but without the ugly irq number munging. + * However, PIRQD is in the upper instead of lower 4 bits. + */ +static int pirq_via_get(struct pci_dev *router, struct pci_dev *dev, int pirq) +{ + return read_config_nybble(router, 0x55, pirq == 4 ? 5 : pirq); +} + +static int pirq_via_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) +{ + write_config_nybble(router, 0x55, pirq == 4 ? 5 : pirq, irq); + return 1; +} + +/* + * The VIA pirq rules are nibble-based, like ALI, + * but without the ugly irq number munging. + * However, for 82C586, nibble map is different . + */ +static int pirq_via586_get(struct pci_dev *router, struct pci_dev *dev, int pirq) +{ + static const unsigned int pirqmap[5] = { 3, 2, 5, 1, 1 }; + return read_config_nybble(router, 0x55, pirqmap[pirq-1]); +} + +static int pirq_via586_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) +{ + static const unsigned int pirqmap[5] = { 3, 2, 5, 1, 1 }; + write_config_nybble(router, 0x55, pirqmap[pirq-1], irq); + return 1; +} + +/* + * ITE 8330G pirq rules are nibble-based + * FIXME: pirqmap may be { 1, 0, 3, 2 }, + * 2+3 are both mapped to irq 9 on my system + */ +static int pirq_ite_get(struct pci_dev *router, struct pci_dev *dev, int pirq) +{ + static const unsigned char pirqmap[4] = { 1, 0, 2, 3 }; + return read_config_nybble(router,0x43, pirqmap[pirq-1]); +} + +static int pirq_ite_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) +{ + static const unsigned char pirqmap[4] = { 1, 0, 2, 3 }; + write_config_nybble(router, 0x43, pirqmap[pirq-1], irq); + return 1; +} + +/* + * OPTI: high four bits are nibble pointer.. + * I wonder what the low bits do? + */ +static int pirq_opti_get(struct pci_dev *router, struct pci_dev *dev, int pirq) +{ + return read_config_nybble(router, 0xb8, pirq >> 4); +} + +static int pirq_opti_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) +{ + write_config_nybble(router, 0xb8, pirq >> 4, irq); + return 1; +} + +/* + * Cyrix: nibble offset 0x5C + * 0x5C bits 7:4 is INTB bits 3:0 is INTA + * 0x5D bits 7:4 is INTD bits 3:0 is INTC + */ +static int pirq_cyrix_get(struct pci_dev *router, struct pci_dev *dev, int pirq) +{ + return read_config_nybble(router, 0x5C, (pirq-1)^1); +} + +static int pirq_cyrix_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) +{ + write_config_nybble(router, 0x5C, (pirq-1)^1, irq); + return 1; +} + +/* + * PIRQ routing for SiS 85C503 router used in several SiS chipsets. + * We have to deal with the following issues here: + * - vendors have different ideas about the meaning of link values + * - some onboard devices (integrated in the chipset) have special + * links and are thus routed differently (i.e. not via PCI INTA-INTD) + * - different revision of the router have a different layout for + * the routing registers, particularly for the onchip devices + * + * For all routing registers the common thing is we have one byte + * per routeable link which is defined as: + * bit 7 IRQ mapping enabled (0) or disabled (1) + * bits [6:4] reserved (sometimes used for onchip devices) + * bits [3:0] IRQ to map to + * allowed: 3-7, 9-12, 14-15 + * reserved: 0, 1, 2, 8, 13 + * + * The config-space registers located at 0x41/0x42/0x43/0x44 are + * always used to route the normal PCI INT A/B/C/D respectively. + * Apparently there are systems implementing PCI routing table using + * link values 0x01-0x04 and others using 0x41-0x44 for PCI INTA..D. + * We try our best to handle both link mappings. + * + * Currently (2003-05-21) it appears most SiS chipsets follow the + * definition of routing registers from the SiS-5595 southbridge. + * According to the SiS 5595 datasheets the revision id's of the + * router (ISA-bridge) should be 0x01 or 0xb0. + * + * Furthermore we've also seen lspci dumps with revision 0x00 and 0xb1. + * Looks like these are used in a number of SiS 5xx/6xx/7xx chipsets. + * They seem to work with the current routing code. However there is + * some concern because of the two USB-OHCI HCs (original SiS 5595 + * had only one). YMMV. + * + * Onchip routing for router rev-id 0x01/0xb0 and probably 0x00/0xb1: + * + * 0x61: IDEIRQ: + * bits [6:5] must be written 01 + * bit 4 channel-select primary (0), secondary (1) + * + * 0x62: USBIRQ: + * bit 6 OHCI function disabled (0), enabled (1) + * + * 0x6a: ACPI/SCI IRQ: bits 4-6 reserved + * + * 0x7e: Data Acq. Module IRQ - bits 4-6 reserved + * + * We support USBIRQ (in addition to INTA-INTD) and keep the + * IDE, ACPI and DAQ routing untouched as set by the BIOS. + * + * Currently the only reported exception is the new SiS 65x chipset + * which includes the SiS 69x southbridge. Here we have the 85C503 + * router revision 0x04 and there are changes in the register layout + * mostly related to the different USB HCs with USB 2.0 support. + * + * Onchip routing for router rev-id 0x04 (try-and-error observation) + * + * 0x60/0x61/0x62/0x63: 1xEHCI and 3xOHCI (companion) USB-HCs + * bit 6-4 are probably unused, not like 5595 + */ + +#define PIRQ_SIS_IRQ_MASK 0x0f +#define PIRQ_SIS_IRQ_DISABLE 0x80 +#define PIRQ_SIS_USB_ENABLE 0x40 + +static int pirq_sis_get(struct pci_dev *router, struct pci_dev *dev, int pirq) +{ + u8 x; + int reg; + + reg = pirq; + if (reg >= 0x01 && reg <= 0x04) + reg += 0x40; + pci_read_config_byte(router, reg, &x); + return (x & PIRQ_SIS_IRQ_DISABLE) ? 0 : (x & PIRQ_SIS_IRQ_MASK); +} + +static int pirq_sis_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) +{ + u8 x; + int reg; + + reg = pirq; + if (reg >= 0x01 && reg <= 0x04) + reg += 0x40; + pci_read_config_byte(router, reg, &x); + x &= ~(PIRQ_SIS_IRQ_MASK | PIRQ_SIS_IRQ_DISABLE); + x |= irq ? irq: PIRQ_SIS_IRQ_DISABLE; + pci_write_config_byte(router, reg, x); + return 1; +} + + +/* + * VLSI: nibble offset 0x74 - educated guess due to routing table and + * config space of VLSI 82C534 PCI-bridge/router (1004:0102) + * Tested on HP OmniBook 800 covering PIRQ 1, 2, 4, 8 for onboard + * devices, PIRQ 3 for non-pci(!) soundchip and (untested) PIRQ 6 + * for the busbridge to the docking station. + */ + +static int pirq_vlsi_get(struct pci_dev *router, struct pci_dev *dev, int pirq) +{ + if (pirq > 8) { + printk(KERN_INFO "VLSI router pirq escape (%d)\n", pirq); + return 0; + } + return read_config_nybble(router, 0x74, pirq-1); +} + +static int pirq_vlsi_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) +{ + if (pirq > 8) { + printk(KERN_INFO "VLSI router pirq escape (%d)\n", pirq); + return 0; + } + write_config_nybble(router, 0x74, pirq-1, irq); + return 1; +} + +/* + * ServerWorks: PCI interrupts mapped to system IRQ lines through Index + * and Redirect I/O registers (0x0c00 and 0x0c01). The Index register + * format is (PCIIRQ## | 0x10), e.g.: PCIIRQ10=0x1a. The Redirect + * register is a straight binary coding of desired PIC IRQ (low nibble). + * + * The 'link' value in the PIRQ table is already in the correct format + * for the Index register. There are some special index values: + * 0x00 for ACPI (SCI), 0x01 for USB, 0x02 for IDE0, 0x04 for IDE1, + * and 0x03 for SMBus. + */ +static int pirq_serverworks_get(struct pci_dev *router, struct pci_dev *dev, int pirq) +{ + outb_p(pirq, 0xc00); + return inb(0xc01) & 0xf; +} + +static int pirq_serverworks_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) +{ + outb_p(pirq, 0xc00); + outb_p(irq, 0xc01); + return 1; +} + +/* Support for AMD756 PCI IRQ Routing + * Jhon H. Caicedo + * Jun/21/2001 0.2.0 Release, fixed to use "nybble" functions... (jhcaiced) + * Jun/19/2001 Alpha Release 0.1.0 (jhcaiced) + * The AMD756 pirq rules are nibble-based + * offset 0x56 0-3 PIRQA 4-7 PIRQB + * offset 0x57 0-3 PIRQC 4-7 PIRQD + */ +static int pirq_amd756_get(struct pci_dev *router, struct pci_dev *dev, int pirq) +{ + u8 irq; + irq = 0; + if (pirq <= 4) + { + irq = read_config_nybble(router, 0x56, pirq - 1); + } + printk(KERN_INFO "AMD756: dev %04x:%04x, router pirq : %d get irq : %2d\n", + dev->vendor, dev->device, pirq, irq); + return irq; +} + +static int pirq_amd756_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) +{ + printk(KERN_INFO "AMD756: dev %04x:%04x, router pirq : %d SET irq : %2d\n", + dev->vendor, dev->device, pirq, irq); + if (pirq <= 4) + { + write_config_nybble(router, 0x56, pirq - 1, irq); + } + return 1; +} + +#ifdef CONFIG_PCI_BIOS + +static int pirq_bios_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) +{ + struct pci_dev *bridge; + int pin = pci_get_interrupt_pin(dev, &bridge); + return pcibios_set_irq_routing(bridge, pin, irq); +} + +#endif + +static __init int intel_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) +{ + static struct pci_device_id __initdata pirq_440gx[] = { + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443GX_0) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443GX_2) }, + { }, + }; + + /* 440GX has a proprietary PIRQ router -- don't use it */ + if (pci_dev_present(pirq_440gx)) + return 0; + + switch(device) + { + case PCI_DEVICE_ID_INTEL_82371FB_0: + case PCI_DEVICE_ID_INTEL_82371SB_0: + case PCI_DEVICE_ID_INTEL_82371AB_0: + case PCI_DEVICE_ID_INTEL_82371MX: + case PCI_DEVICE_ID_INTEL_82443MX_0: + case PCI_DEVICE_ID_INTEL_82801AA_0: + case PCI_DEVICE_ID_INTEL_82801AB_0: + case PCI_DEVICE_ID_INTEL_82801BA_0: + case PCI_DEVICE_ID_INTEL_82801BA_10: + case PCI_DEVICE_ID_INTEL_82801CA_0: + case PCI_DEVICE_ID_INTEL_82801CA_12: + case PCI_DEVICE_ID_INTEL_82801DB_0: + case PCI_DEVICE_ID_INTEL_82801E_0: + case PCI_DEVICE_ID_INTEL_82801EB_0: + case PCI_DEVICE_ID_INTEL_ESB_1: + case PCI_DEVICE_ID_INTEL_ICH6_0: + case PCI_DEVICE_ID_INTEL_ICH6_1: + case PCI_DEVICE_ID_INTEL_ICH7_0: + case PCI_DEVICE_ID_INTEL_ICH7_1: + case PCI_DEVICE_ID_INTEL_ICH7_30: + case PCI_DEVICE_ID_INTEL_ICH7_31: + case PCI_DEVICE_ID_INTEL_ESB2_0: + case PCI_DEVICE_ID_INTEL_ICH8_0: + case PCI_DEVICE_ID_INTEL_ICH8_1: + case PCI_DEVICE_ID_INTEL_ICH8_2: + case PCI_DEVICE_ID_INTEL_ICH8_3: + case PCI_DEVICE_ID_INTEL_ICH8_4: + case PCI_DEVICE_ID_INTEL_ICH9_0: + case PCI_DEVICE_ID_INTEL_ICH9_1: + case PCI_DEVICE_ID_INTEL_ICH9_2: + case PCI_DEVICE_ID_INTEL_ICH9_3: + case PCI_DEVICE_ID_INTEL_ICH9_4: + case PCI_DEVICE_ID_INTEL_ICH9_5: + case PCI_DEVICE_ID_INTEL_TOLAPAI_0: + r->name = "PIIX/ICH"; + r->get = pirq_piix_get; + r->set = pirq_piix_set; + return 1; + } + return 0; +} + +static __init int via_router_probe(struct irq_router *r, + struct pci_dev *router, u16 device) +{ + /* FIXME: We should move some of the quirk fixup stuff here */ + + /* + * work arounds for some buggy BIOSes + */ + if (device == PCI_DEVICE_ID_VIA_82C586_0) { + switch(router->device) { + case PCI_DEVICE_ID_VIA_82C686: + /* + * Asus k7m bios wrongly reports 82C686A + * as 586-compatible + */ + device = PCI_DEVICE_ID_VIA_82C686; + break; + case PCI_DEVICE_ID_VIA_8235: + /** + * Asus a7v-x bios wrongly reports 8235 + * as 586-compatible + */ + device = PCI_DEVICE_ID_VIA_8235; + break; + } + } + + switch(device) { + case PCI_DEVICE_ID_VIA_82C586_0: + r->name = "VIA"; + r->get = pirq_via586_get; + r->set = pirq_via586_set; + return 1; + case PCI_DEVICE_ID_VIA_82C596: + case PCI_DEVICE_ID_VIA_82C686: + case PCI_DEVICE_ID_VIA_8231: + case PCI_DEVICE_ID_VIA_8233A: + case PCI_DEVICE_ID_VIA_8235: + case PCI_DEVICE_ID_VIA_8237: + /* FIXME: add new ones for 8233/5 */ + r->name = "VIA"; + r->get = pirq_via_get; + r->set = pirq_via_set; + return 1; + } + return 0; +} + +static __init int vlsi_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) +{ + switch(device) + { + case PCI_DEVICE_ID_VLSI_82C534: + r->name = "VLSI 82C534"; + r->get = pirq_vlsi_get; + r->set = pirq_vlsi_set; + return 1; + } + return 0; +} + + +static __init int serverworks_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) +{ + switch(device) + { + case PCI_DEVICE_ID_SERVERWORKS_OSB4: + case PCI_DEVICE_ID_SERVERWORKS_CSB5: + r->name = "ServerWorks"; + r->get = pirq_serverworks_get; + r->set = pirq_serverworks_set; + return 1; + } + return 0; +} + +static __init int sis_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) +{ + if (device != PCI_DEVICE_ID_SI_503) + return 0; + + r->name = "SIS"; + r->get = pirq_sis_get; + r->set = pirq_sis_set; + return 1; +} + +static __init int cyrix_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) +{ + switch(device) + { + case PCI_DEVICE_ID_CYRIX_5520: + r->name = "NatSemi"; + r->get = pirq_cyrix_get; + r->set = pirq_cyrix_set; + return 1; + } + return 0; +} + +static __init int opti_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) +{ + switch(device) + { + case PCI_DEVICE_ID_OPTI_82C700: + r->name = "OPTI"; + r->get = pirq_opti_get; + r->set = pirq_opti_set; + return 1; + } + return 0; +} + +static __init int ite_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) +{ + switch(device) + { + case PCI_DEVICE_ID_ITE_IT8330G_0: + r->name = "ITE"; + r->get = pirq_ite_get; + r->set = pirq_ite_set; + return 1; + } + return 0; +} + +static __init int ali_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) +{ + switch(device) + { + case PCI_DEVICE_ID_AL_M1533: + case PCI_DEVICE_ID_AL_M1563: + printk(KERN_DEBUG "PCI: Using ALI IRQ Router\n"); + r->name = "ALI"; + r->get = pirq_ali_get; + r->set = pirq_ali_set; + return 1; + } + return 0; +} + +static __init int amd_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) +{ + switch(device) + { + case PCI_DEVICE_ID_AMD_VIPER_740B: + r->name = "AMD756"; + break; + case PCI_DEVICE_ID_AMD_VIPER_7413: + r->name = "AMD766"; + break; + case PCI_DEVICE_ID_AMD_VIPER_7443: + r->name = "AMD768"; + break; + default: + return 0; + } + r->get = pirq_amd756_get; + r->set = pirq_amd756_set; + return 1; +} + +static __initdata struct irq_router_handler pirq_routers[] = { + { PCI_VENDOR_ID_INTEL, intel_router_probe }, + { PCI_VENDOR_ID_AL, ali_router_probe }, + { PCI_VENDOR_ID_ITE, ite_router_probe }, + { PCI_VENDOR_ID_VIA, via_router_probe }, + { PCI_VENDOR_ID_OPTI, opti_router_probe }, + { PCI_VENDOR_ID_SI, sis_router_probe }, + { PCI_VENDOR_ID_CYRIX, cyrix_router_probe }, + { PCI_VENDOR_ID_VLSI, vlsi_router_probe }, + { PCI_VENDOR_ID_SERVERWORKS, serverworks_router_probe }, + { PCI_VENDOR_ID_AMD, amd_router_probe }, + /* Someone with docs needs to add the ATI Radeon IGP */ + { 0, NULL } +}; +static struct irq_router pirq_router; +static struct pci_dev *pirq_router_dev; + + +/* + * FIXME: should we have an option to say "generic for + * chipset" ? + */ + +static void __init pirq_find_router(struct irq_router *r) +{ + struct irq_routing_table *rt = pirq_table; + struct irq_router_handler *h; + +#ifdef CONFIG_PCI_BIOS + if (!rt->signature) { + printk(KERN_INFO "PCI: Using BIOS for IRQ routing\n"); + r->set = pirq_bios_set; + r->name = "BIOS"; + return; + } +#endif + + /* Default unless a driver reloads it */ + r->name = "default"; + r->get = NULL; + r->set = NULL; + + DBG(KERN_DEBUG "PCI: Attempting to find IRQ router for %04x:%04x\n", + rt->rtr_vendor, rt->rtr_device); + + pirq_router_dev = pci_get_bus_and_slot(rt->rtr_bus, rt->rtr_devfn); + if (!pirq_router_dev) { + DBG(KERN_DEBUG "PCI: Interrupt router not found at " + "%02x:%02x\n", rt->rtr_bus, rt->rtr_devfn); + return; + } + + for( h = pirq_routers; h->vendor; h++) { + /* First look for a router match */ + if (rt->rtr_vendor == h->vendor && h->probe(r, pirq_router_dev, rt->rtr_device)) + break; + /* Fall back to a device match */ + if (pirq_router_dev->vendor == h->vendor && h->probe(r, pirq_router_dev, pirq_router_dev->device)) + break; + } + printk(KERN_INFO "PCI: Using IRQ router %s [%04x/%04x] at %s\n", + pirq_router.name, + pirq_router_dev->vendor, + pirq_router_dev->device, + pci_name(pirq_router_dev)); + + /* The device remains referenced for the kernel lifetime */ +} + +static struct irq_info *pirq_get_info(struct pci_dev *dev) +{ + struct irq_routing_table *rt = pirq_table; + int entries = (rt->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info); + struct irq_info *info; + + for (info = rt->slots; entries--; info++) + if (info->bus == dev->bus->number && PCI_SLOT(info->devfn) == PCI_SLOT(dev->devfn)) + return info; + return NULL; +} + +static int pcibios_lookup_irq(struct pci_dev *dev, int assign) +{ + u8 pin; + struct irq_info *info; + int i, pirq, newirq; + int irq = 0; + u32 mask; + struct irq_router *r = &pirq_router; + struct pci_dev *dev2 = NULL; + char *msg = NULL; + + /* Find IRQ pin */ + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); + if (!pin) { + DBG(KERN_DEBUG " -> no interrupt pin\n"); + return 0; + } + pin = pin - 1; + + /* Find IRQ routing entry */ + + if (!pirq_table) + return 0; + + DBG(KERN_DEBUG "IRQ for %s[%c]", pci_name(dev), 'A' + pin); + info = pirq_get_info(dev); + if (!info) { + DBG(" -> not found in routing table\n" KERN_DEBUG); + return 0; + } + pirq = info->irq[pin].link; + mask = info->irq[pin].bitmap; + if (!pirq) { + DBG(" -> not routed\n" KERN_DEBUG); + return 0; + } + DBG(" -> PIRQ %02x, mask %04x, excl %04x", pirq, mask, pirq_table->exclusive_irqs); + mask &= pcibios_irq_mask; + + /* Work around broken HP Pavilion Notebooks which assign USB to + IRQ 9 even though it is actually wired to IRQ 11 */ + + if (broken_hp_bios_irq9 && pirq == 0x59 && dev->irq == 9) { + dev->irq = 11; + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 11); + r->set(pirq_router_dev, dev, pirq, 11); + } + + /* same for Acer Travelmate 360, but with CB and irq 11 -> 10 */ + if (acer_tm360_irqrouting && dev->irq == 11 && dev->vendor == PCI_VENDOR_ID_O2) { + pirq = 0x68; + mask = 0x400; + dev->irq = r->get(pirq_router_dev, dev, pirq); + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); + } + + /* + * Find the best IRQ to assign: use the one + * reported by the device if possible. + */ + newirq = dev->irq; + if (newirq && !((1 << newirq) & mask)) { + if ( pci_probe & PCI_USE_PIRQ_MASK) newirq = 0; + else printk("\n" KERN_WARNING + "PCI: IRQ %i for device %s doesn't match PIRQ mask " + "- try pci=usepirqmask\n" KERN_DEBUG, newirq, + pci_name(dev)); + } + if (!newirq && assign) { + for (i = 0; i < 16; i++) { + if (!(mask & (1 << i))) + continue; + if (pirq_penalty[i] < pirq_penalty[newirq] && can_request_irq(i, IRQF_SHARED)) + newirq = i; + } + } + DBG(" -> newirq=%d", newirq); + + /* Check if it is hardcoded */ + if ((pirq & 0xf0) == 0xf0) { + irq = pirq & 0xf; + DBG(" -> hardcoded IRQ %d\n", irq); + msg = "Hardcoded"; + } else if ( r->get && (irq = r->get(pirq_router_dev, dev, pirq)) && \ + ((!(pci_probe & PCI_USE_PIRQ_MASK)) || ((1 << irq) & mask)) ) { + DBG(" -> got IRQ %d\n", irq); + msg = "Found"; + eisa_set_level_irq(irq); + } else if (newirq && r->set && (dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) { + DBG(" -> assigning IRQ %d", newirq); + if (r->set(pirq_router_dev, dev, pirq, newirq)) { + eisa_set_level_irq(newirq); + DBG(" ... OK\n"); + msg = "Assigned"; + irq = newirq; + } + } + + if (!irq) { + DBG(" ... failed\n"); + if (newirq && mask == (1 << newirq)) { + msg = "Guessed"; + irq = newirq; + } else + return 0; + } + printk(KERN_INFO "PCI: %s IRQ %d for device %s\n", msg, irq, pci_name(dev)); + + /* Update IRQ for all devices with the same pirq value */ + while ((dev2 = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev2)) != NULL) { + pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin); + if (!pin) + continue; + pin--; + info = pirq_get_info(dev2); + if (!info) + continue; + if (info->irq[pin].link == pirq) { + /* We refuse to override the dev->irq information. Give a warning! */ + if ( dev2->irq && dev2->irq != irq && \ + (!(pci_probe & PCI_USE_PIRQ_MASK) || \ + ((1 << dev2->irq) & mask)) ) { +#ifndef CONFIG_PCI_MSI + printk(KERN_INFO "IRQ routing conflict for %s, have irq %d, want irq %d\n", + pci_name(dev2), dev2->irq, irq); +#endif + continue; + } + dev2->irq = irq; + pirq_penalty[irq]++; + if (dev != dev2) + printk(KERN_INFO "PCI: Sharing IRQ %d with %s\n", irq, pci_name(dev2)); + } + } + return 1; +} + +static void __init pcibios_fixup_irqs(void) +{ + struct pci_dev *dev = NULL; + u8 pin; + + DBG(KERN_DEBUG "PCI: IRQ fixup\n"); + while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { + /* + * If the BIOS has set an out of range IRQ number, just ignore it. + * Also keep track of which IRQ's are already in use. + */ + if (dev->irq >= 16) { + DBG(KERN_DEBUG "%s: ignoring bogus IRQ %d\n", pci_name(dev), dev->irq); + dev->irq = 0; + } + /* If the IRQ is already assigned to a PCI device, ignore its ISA use penalty */ + if (pirq_penalty[dev->irq] >= 100 && pirq_penalty[dev->irq] < 100000) + pirq_penalty[dev->irq] = 0; + pirq_penalty[dev->irq]++; + } + + dev = NULL; + while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); +#ifdef CONFIG_X86_IO_APIC + /* + * Recalculate IRQ numbers if we use the I/O APIC. + */ + if (io_apic_assign_pci_irqs) + { + int irq; + + if (pin) { + pin--; /* interrupt pins are numbered starting from 1 */ + irq = IO_APIC_get_PCI_irq_vector(dev->bus->number, PCI_SLOT(dev->devfn), pin); + /* + * Busses behind bridges are typically not listed in the MP-table. + * In this case we have to look up the IRQ based on the parent bus, + * parent slot, and pin number. The SMP code detects such bridged + * busses itself so we should get into this branch reliably. + */ + if (irq < 0 && dev->bus->parent) { /* go back to the bridge */ + struct pci_dev * bridge = dev->bus->self; + + pin = (pin + PCI_SLOT(dev->devfn)) % 4; + irq = IO_APIC_get_PCI_irq_vector(bridge->bus->number, + PCI_SLOT(bridge->devfn), pin); + if (irq >= 0) + printk(KERN_WARNING "PCI: using PPB %s[%c] to get irq %d\n", + pci_name(bridge), 'A' + pin, irq); + } + if (irq >= 0) { + printk(KERN_INFO "PCI->APIC IRQ transform: %s[%c] -> IRQ %d\n", + pci_name(dev), 'A' + pin, irq); + dev->irq = irq; + } + } + } +#endif + /* + * Still no IRQ? Try to lookup one... + */ + if (pin && !dev->irq) + pcibios_lookup_irq(dev, 0); + } +} + +/* + * Work around broken HP Pavilion Notebooks which assign USB to + * IRQ 9 even though it is actually wired to IRQ 11 + */ +static int __init fix_broken_hp_bios_irq9(struct dmi_system_id *d) +{ + if (!broken_hp_bios_irq9) { + broken_hp_bios_irq9 = 1; + printk(KERN_INFO "%s detected - fixing broken IRQ routing\n", d->ident); + } + return 0; +} + +/* + * Work around broken Acer TravelMate 360 Notebooks which assign + * Cardbus to IRQ 11 even though it is actually wired to IRQ 10 + */ +static int __init fix_acer_tm360_irqrouting(struct dmi_system_id *d) +{ + if (!acer_tm360_irqrouting) { + acer_tm360_irqrouting = 1; + printk(KERN_INFO "%s detected - fixing broken IRQ routing\n", d->ident); + } + return 0; +} + +static struct dmi_system_id __initdata pciirq_dmi_table[] = { + { + .callback = fix_broken_hp_bios_irq9, + .ident = "HP Pavilion N5400 Series Laptop", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_BIOS_VERSION, "GE.M1.03"), + DMI_MATCH(DMI_PRODUCT_VERSION, "HP Pavilion Notebook Model GE"), + DMI_MATCH(DMI_BOARD_VERSION, "OmniBook N32N-736"), + }, + }, + { + .callback = fix_acer_tm360_irqrouting, + .ident = "Acer TravelMate 36x Laptop", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"), + }, + }, + { } +}; + +static int __init pcibios_irq_init(void) +{ + DBG(KERN_DEBUG "PCI: IRQ init\n"); + + if (pcibios_enable_irq || raw_pci_ops == NULL) + return 0; + + dmi_check_system(pciirq_dmi_table); + + pirq_table = pirq_find_routing_table(); + +#ifdef CONFIG_PCI_BIOS + if (!pirq_table && (pci_probe & PCI_BIOS_IRQ_SCAN)) + pirq_table = pcibios_get_irq_routing_table(); +#endif + if (pirq_table) { + pirq_peer_trick(); + pirq_find_router(&pirq_router); + if (pirq_table->exclusive_irqs) { + int i; + for (i=0; i<16; i++) + if (!(pirq_table->exclusive_irqs & (1 << i))) + pirq_penalty[i] += 100; + } + /* If we're using the I/O APIC, avoid using the PCI IRQ routing table */ + if (io_apic_assign_pci_irqs) + pirq_table = NULL; + } + + pcibios_enable_irq = pirq_enable_irq; + + pcibios_fixup_irqs(); + return 0; +} + +subsys_initcall(pcibios_irq_init); + + +static void pirq_penalize_isa_irq(int irq, int active) +{ + /* + * If any ISAPnP device reports an IRQ in its list of possible + * IRQ's, we try to avoid assigning it to PCI devices. + */ + if (irq < 16) { + if (active) + pirq_penalty[irq] += 1000; + else + pirq_penalty[irq] += 100; + } +} + +void pcibios_penalize_isa_irq(int irq, int active) +{ +#ifdef CONFIG_ACPI + if (!acpi_noirq) + acpi_penalize_isa_irq(irq, active); + else +#endif + pirq_penalize_isa_irq(irq, active); +} + +static int pirq_enable_irq(struct pci_dev *dev) +{ + u8 pin; + struct pci_dev *temp_dev; + + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); + if (pin && !pcibios_lookup_irq(dev, 1) && !dev->irq) { + char *msg = ""; + + pin--; /* interrupt pins are numbered starting from 1 */ + + if (io_apic_assign_pci_irqs) { + int irq; + + irq = IO_APIC_get_PCI_irq_vector(dev->bus->number, PCI_SLOT(dev->devfn), pin); + /* + * Busses behind bridges are typically not listed in the MP-table. + * In this case we have to look up the IRQ based on the parent bus, + * parent slot, and pin number. The SMP code detects such bridged + * busses itself so we should get into this branch reliably. + */ + temp_dev = dev; + while (irq < 0 && dev->bus->parent) { /* go back to the bridge */ + struct pci_dev * bridge = dev->bus->self; + + pin = (pin + PCI_SLOT(dev->devfn)) % 4; + irq = IO_APIC_get_PCI_irq_vector(bridge->bus->number, + PCI_SLOT(bridge->devfn), pin); + if (irq >= 0) + printk(KERN_WARNING "PCI: using PPB %s[%c] to get irq %d\n", + pci_name(bridge), 'A' + pin, irq); + dev = bridge; + } + dev = temp_dev; + if (irq >= 0) { + printk(KERN_INFO "PCI->APIC IRQ transform: %s[%c] -> IRQ %d\n", + pci_name(dev), 'A' + pin, irq); + dev->irq = irq; + return 0; + } else + msg = " Probably buggy MP table."; + } else if (pci_probe & PCI_BIOS_IRQ_SCAN) + msg = ""; + else + msg = " Please try using pci=biosirq."; + + /* With IDE legacy devices the IRQ lookup failure is not a problem.. */ + if (dev->class >> 8 == PCI_CLASS_STORAGE_IDE && !(dev->class & 0x5)) + return 0; + + printk(KERN_WARNING "PCI: No IRQ known for interrupt pin %c of device %s.%s\n", + 'A' + pin, pci_name(dev), msg); + } + return 0; +} diff --git a/arch/x86/pci/legacy.c b/arch/x86/pci/legacy.c new file mode 100644 index 00000000000..5565d7016b7 --- /dev/null +++ b/arch/x86/pci/legacy.c @@ -0,0 +1,56 @@ +/* + * legacy.c - traditional, old school PCI bus probing + */ +#include +#include +#include "pci.h" + +/* + * Discover remaining PCI buses in case there are peer host bridges. + * We use the number of last PCI bus provided by the PCI BIOS. + */ +static void __devinit pcibios_fixup_peer_bridges(void) +{ + int n, devfn; + + if (pcibios_last_bus <= 0 || pcibios_last_bus >= 0xff) + return; + DBG("PCI: Peer bridge fixup\n"); + + for (n=0; n <= pcibios_last_bus; n++) { + u32 l; + if (pci_find_bus(0, n)) + continue; + for (devfn = 0; devfn < 256; devfn += 8) { + if (!raw_pci_ops->read(0, n, devfn, PCI_VENDOR_ID, 2, &l) && + l != 0x0000 && l != 0xffff) { + DBG("Found device at %02x:%02x [%04x]\n", n, devfn, l); + printk(KERN_INFO "PCI: Discovered peer bus %02x\n", n); + pci_scan_bus_with_sysdata(n); + break; + } + } + } +} + +static int __init pci_legacy_init(void) +{ + if (!raw_pci_ops) { + printk("PCI: System does not support PCI\n"); + return 0; + } + + if (pcibios_scanned++) + return 0; + + printk("PCI: Probing PCI hardware\n"); + pci_root_bus = pcibios_scan_root(0); + if (pci_root_bus) + pci_bus_add_devices(pci_root_bus); + + pcibios_fixup_peer_bridges(); + + return 0; +} + +subsys_initcall(pci_legacy_init); diff --git a/arch/x86/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c new file mode 100644 index 00000000000..4df637e34f8 --- /dev/null +++ b/arch/x86/pci/mmconfig-shared.c @@ -0,0 +1,315 @@ +/* + * mmconfig-shared.c - Low-level direct PCI config space access via + * MMCONFIG - common code between i386 and x86-64. + * + * This code does: + * - known chipset handling + * - ACPI decoding and validation + * + * Per-architecture code takes care of the mappings and accesses + * themselves. + */ + +#include +#include +#include +#include +#include + +#include "pci.h" + +/* aperture is up to 256MB but BIOS may reserve less */ +#define MMCONFIG_APER_MIN (2 * 1024*1024) +#define MMCONFIG_APER_MAX (256 * 1024*1024) + +DECLARE_BITMAP(pci_mmcfg_fallback_slots, 32*PCI_MMCFG_MAX_CHECK_BUS); + +/* Indicate if the mmcfg resources have been placed into the resource table. */ +static int __initdata pci_mmcfg_resources_inserted; + +/* K8 systems have some devices (typically in the builtin northbridge) + that are only accessible using type1 + Normally this can be expressed in the MCFG by not listing them + and assigning suitable _SEGs, but this isn't implemented in some BIOS. + Instead try to discover all devices on bus 0 that are unreachable using MM + and fallback for them. */ +static void __init unreachable_devices(void) +{ + int i, bus; + /* Use the max bus number from ACPI here? */ + for (bus = 0; bus < PCI_MMCFG_MAX_CHECK_BUS; bus++) { + for (i = 0; i < 32; i++) { + unsigned int devfn = PCI_DEVFN(i, 0); + u32 val1, val2; + + pci_conf1_read(0, bus, devfn, 0, 4, &val1); + if (val1 == 0xffffffff) + continue; + + if (pci_mmcfg_arch_reachable(0, bus, devfn)) { + raw_pci_ops->read(0, bus, devfn, 0, 4, &val2); + if (val1 == val2) + continue; + } + set_bit(i + 32 * bus, pci_mmcfg_fallback_slots); + printk(KERN_NOTICE "PCI: No mmconfig possible on device" + " %02x:%02x\n", bus, i); + } + } +} + +static const char __init *pci_mmcfg_e7520(void) +{ + u32 win; + pci_conf1_read(0, 0, PCI_DEVFN(0,0), 0xce, 2, &win); + + win = win & 0xf000; + if(win == 0x0000 || win == 0xf000) + pci_mmcfg_config_num = 0; + else { + pci_mmcfg_config_num = 1; + pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]), GFP_KERNEL); + if (!pci_mmcfg_config) + return NULL; + pci_mmcfg_config[0].address = win << 16; + pci_mmcfg_config[0].pci_segment = 0; + pci_mmcfg_config[0].start_bus_number = 0; + pci_mmcfg_config[0].end_bus_number = 255; + } + + return "Intel Corporation E7520 Memory Controller Hub"; +} + +static const char __init *pci_mmcfg_intel_945(void) +{ + u32 pciexbar, mask = 0, len = 0; + + pci_mmcfg_config_num = 1; + + pci_conf1_read(0, 0, PCI_DEVFN(0,0), 0x48, 4, &pciexbar); + + /* Enable bit */ + if (!(pciexbar & 1)) + pci_mmcfg_config_num = 0; + + /* Size bits */ + switch ((pciexbar >> 1) & 3) { + case 0: + mask = 0xf0000000U; + len = 0x10000000U; + break; + case 1: + mask = 0xf8000000U; + len = 0x08000000U; + break; + case 2: + mask = 0xfc000000U; + len = 0x04000000U; + break; + default: + pci_mmcfg_config_num = 0; + } + + /* Errata #2, things break when not aligned on a 256Mb boundary */ + /* Can only happen in 64M/128M mode */ + + if ((pciexbar & mask) & 0x0fffffffU) + pci_mmcfg_config_num = 0; + + /* Don't hit the APIC registers and their friends */ + if ((pciexbar & mask) >= 0xf0000000U) + pci_mmcfg_config_num = 0; + + if (pci_mmcfg_config_num) { + pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]), GFP_KERNEL); + if (!pci_mmcfg_config) + return NULL; + pci_mmcfg_config[0].address = pciexbar & mask; + pci_mmcfg_config[0].pci_segment = 0; + pci_mmcfg_config[0].start_bus_number = 0; + pci_mmcfg_config[0].end_bus_number = (len >> 20) - 1; + } + + return "Intel Corporation 945G/GZ/P/PL Express Memory Controller Hub"; +} + +struct pci_mmcfg_hostbridge_probe { + u32 vendor; + u32 device; + const char *(*probe)(void); +}; + +static struct pci_mmcfg_hostbridge_probe pci_mmcfg_probes[] __initdata = { + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, pci_mmcfg_e7520 }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82945G_HB, pci_mmcfg_intel_945 }, +}; + +static int __init pci_mmcfg_check_hostbridge(void) +{ + u32 l; + u16 vendor, device; + int i; + const char *name; + + pci_conf1_read(0, 0, PCI_DEVFN(0,0), 0, 4, &l); + vendor = l & 0xffff; + device = (l >> 16) & 0xffff; + + pci_mmcfg_config_num = 0; + pci_mmcfg_config = NULL; + name = NULL; + + for (i = 0; !name && i < ARRAY_SIZE(pci_mmcfg_probes); i++) { + if (pci_mmcfg_probes[i].vendor == vendor && + pci_mmcfg_probes[i].device == device) + name = pci_mmcfg_probes[i].probe(); + } + + if (name) { + printk(KERN_INFO "PCI: Found %s %s MMCONFIG support.\n", + name, pci_mmcfg_config_num ? "with" : "without"); + } + + return name != NULL; +} + +static void __init pci_mmcfg_insert_resources(unsigned long resource_flags) +{ +#define PCI_MMCFG_RESOURCE_NAME_LEN 19 + int i; + struct resource *res; + char *names; + unsigned num_buses; + + res = kcalloc(PCI_MMCFG_RESOURCE_NAME_LEN + sizeof(*res), + pci_mmcfg_config_num, GFP_KERNEL); + if (!res) { + printk(KERN_ERR "PCI: Unable to allocate MMCONFIG resources\n"); + return; + } + + names = (void *)&res[pci_mmcfg_config_num]; + for (i = 0; i < pci_mmcfg_config_num; i++, res++) { + struct acpi_mcfg_allocation *cfg = &pci_mmcfg_config[i]; + num_buses = cfg->end_bus_number - cfg->start_bus_number + 1; + res->name = names; + snprintf(names, PCI_MMCFG_RESOURCE_NAME_LEN, "PCI MMCONFIG %u", + cfg->pci_segment); + res->start = cfg->address; + res->end = res->start + (num_buses << 20) - 1; + res->flags = IORESOURCE_MEM | resource_flags; + insert_resource(&iomem_resource, res); + names += PCI_MMCFG_RESOURCE_NAME_LEN; + } + + /* Mark that the resources have been inserted. */ + pci_mmcfg_resources_inserted = 1; +} + +static void __init pci_mmcfg_reject_broken(int type) +{ + typeof(pci_mmcfg_config[0]) *cfg; + + if ((pci_mmcfg_config_num == 0) || + (pci_mmcfg_config == NULL) || + (pci_mmcfg_config[0].address == 0)) + return; + + cfg = &pci_mmcfg_config[0]; + + /* + * Handle more broken MCFG tables on Asus etc. + * They only contain a single entry for bus 0-0. + */ + if (pci_mmcfg_config_num == 1 && + cfg->pci_segment == 0 && + (cfg->start_bus_number | cfg->end_bus_number) == 0) { + printk(KERN_ERR "PCI: start and end of bus number is 0. " + "Rejected as broken MCFG.\n"); + goto reject; + } + + /* + * Only do this check when type 1 works. If it doesn't work + * assume we run on a Mac and always use MCFG + */ + if (type == 1 && !e820_all_mapped(cfg->address, + cfg->address + MMCONFIG_APER_MIN, + E820_RESERVED)) { + printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %Lx is not" + " E820-reserved\n", cfg->address); + goto reject; + } + return; + +reject: + printk(KERN_ERR "PCI: Not using MMCONFIG.\n"); + kfree(pci_mmcfg_config); + pci_mmcfg_config = NULL; + pci_mmcfg_config_num = 0; +} + +void __init pci_mmcfg_init(int type) +{ + int known_bridge = 0; + + if ((pci_probe & PCI_PROBE_MMCONF) == 0) + return; + + if (type == 1 && pci_mmcfg_check_hostbridge()) + known_bridge = 1; + + if (!known_bridge) { + acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg); + pci_mmcfg_reject_broken(type); + } + + if ((pci_mmcfg_config_num == 0) || + (pci_mmcfg_config == NULL) || + (pci_mmcfg_config[0].address == 0)) + return; + + if (pci_mmcfg_arch_init()) { + if (type == 1) + unreachable_devices(); + if (known_bridge) + pci_mmcfg_insert_resources(IORESOURCE_BUSY); + pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF; + } else { + /* + * Signal not to attempt to insert mmcfg resources because + * the architecture mmcfg setup could not initialize. + */ + pci_mmcfg_resources_inserted = 1; + } +} + +static int __init pci_mmcfg_late_insert_resources(void) +{ + /* + * If resources are already inserted or we are not using MMCONFIG, + * don't insert the resources. + */ + if ((pci_mmcfg_resources_inserted == 1) || + (pci_probe & PCI_PROBE_MMCONF) == 0 || + (pci_mmcfg_config_num == 0) || + (pci_mmcfg_config == NULL) || + (pci_mmcfg_config[0].address == 0)) + return 1; + + /* + * Attempt to insert the mmcfg resources but not with the busy flag + * marked so it won't cause request errors when __request_region is + * called. + */ + pci_mmcfg_insert_resources(0); + + return 0; +} + +/* + * Perform MMCONFIG resource insertion after PCI initialization to allow for + * misprogrammed MCFG tables that state larger sizes but actually conflict + * with other system resources. + */ +late_initcall(pci_mmcfg_late_insert_resources); diff --git a/arch/x86/pci/mmconfig_32.c b/arch/x86/pci/mmconfig_32.c new file mode 100644 index 00000000000..1bf5816d34c --- /dev/null +++ b/arch/x86/pci/mmconfig_32.c @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2004 Matthew Wilcox + * Copyright (C) 2004 Intel Corp. + * + * This code is released under the GNU General Public License version 2. + */ + +/* + * mmconfig.c - Low-level direct PCI config space access via MMCONFIG + */ + +#include +#include +#include +#include +#include "pci.h" + +/* Assume systems with more busses have correct MCFG */ +#define mmcfg_virt_addr ((void __iomem *) fix_to_virt(FIX_PCIE_MCFG)) + +/* The base address of the last MMCONFIG device accessed */ +static u32 mmcfg_last_accessed_device; +static int mmcfg_last_accessed_cpu; + +/* + * Functions for accessing PCI configuration space with MMCONFIG accesses + */ +static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn) +{ + struct acpi_mcfg_allocation *cfg; + int cfg_num; + + if (seg == 0 && bus < PCI_MMCFG_MAX_CHECK_BUS && + test_bit(PCI_SLOT(devfn) + 32*bus, pci_mmcfg_fallback_slots)) + return 0; + + for (cfg_num = 0; cfg_num < pci_mmcfg_config_num; cfg_num++) { + cfg = &pci_mmcfg_config[cfg_num]; + if (cfg->pci_segment == seg && + (cfg->start_bus_number <= bus) && + (cfg->end_bus_number >= bus)) + return cfg->address; + } + + /* Fall back to type 0 */ + return 0; +} + +/* + * This is always called under pci_config_lock + */ +static void pci_exp_set_dev_base(unsigned int base, int bus, int devfn) +{ + u32 dev_base = base | (bus << 20) | (devfn << 12); + int cpu = smp_processor_id(); + if (dev_base != mmcfg_last_accessed_device || + cpu != mmcfg_last_accessed_cpu) { + mmcfg_last_accessed_device = dev_base; + mmcfg_last_accessed_cpu = cpu; + set_fixmap_nocache(FIX_PCIE_MCFG, dev_base); + } +} + +static int pci_mmcfg_read(unsigned int seg, unsigned int bus, + unsigned int devfn, int reg, int len, u32 *value) +{ + unsigned long flags; + u32 base; + + if ((bus > 255) || (devfn > 255) || (reg > 4095)) { + *value = -1; + return -EINVAL; + } + + base = get_base_addr(seg, bus, devfn); + if (!base) + return pci_conf1_read(seg,bus,devfn,reg,len,value); + + spin_lock_irqsave(&pci_config_lock, flags); + + pci_exp_set_dev_base(base, bus, devfn); + + switch (len) { + case 1: + *value = mmio_config_readb(mmcfg_virt_addr + reg); + break; + case 2: + *value = mmio_config_readw(mmcfg_virt_addr + reg); + break; + case 4: + *value = mmio_config_readl(mmcfg_virt_addr + reg); + break; + } + spin_unlock_irqrestore(&pci_config_lock, flags); + + return 0; +} + +static int pci_mmcfg_write(unsigned int seg, unsigned int bus, + unsigned int devfn, int reg, int len, u32 value) +{ + unsigned long flags; + u32 base; + + if ((bus > 255) || (devfn > 255) || (reg > 4095)) + return -EINVAL; + + base = get_base_addr(seg, bus, devfn); + if (!base) + return pci_conf1_write(seg,bus,devfn,reg,len,value); + + spin_lock_irqsave(&pci_config_lock, flags); + + pci_exp_set_dev_base(base, bus, devfn); + + switch (len) { + case 1: + mmio_config_writeb(mmcfg_virt_addr + reg, value); + break; + case 2: + mmio_config_writew(mmcfg_virt_addr + reg, value); + break; + case 4: + mmio_config_writel(mmcfg_virt_addr + reg, value); + break; + } + spin_unlock_irqrestore(&pci_config_lock, flags); + + return 0; +} + +static struct pci_raw_ops pci_mmcfg = { + .read = pci_mmcfg_read, + .write = pci_mmcfg_write, +}; + +int __init pci_mmcfg_arch_reachable(unsigned int seg, unsigned int bus, + unsigned int devfn) +{ + return get_base_addr(seg, bus, devfn) != 0; +} + +int __init pci_mmcfg_arch_init(void) +{ + printk(KERN_INFO "PCI: Using MMCONFIG\n"); + raw_pci_ops = &pci_mmcfg; + return 1; +} diff --git a/arch/x86/pci/numa.c b/arch/x86/pci/numa.c new file mode 100644 index 00000000000..f5f165f69e0 --- /dev/null +++ b/arch/x86/pci/numa.c @@ -0,0 +1,135 @@ +/* + * numa.c - Low-level PCI access for NUMA-Q machines + */ + +#include +#include +#include +#include "pci.h" + +#define BUS2QUAD(global) (mp_bus_id_to_node[global]) +#define BUS2LOCAL(global) (mp_bus_id_to_local[global]) +#define QUADLOCAL2BUS(quad,local) (quad_local_to_mp_bus_id[quad][local]) + +#define PCI_CONF1_MQ_ADDRESS(bus, devfn, reg) \ + (0x80000000 | (BUS2LOCAL(bus) << 16) | (devfn << 8) | (reg & ~3)) + +static int pci_conf1_mq_read(unsigned int seg, unsigned int bus, + unsigned int devfn, int reg, int len, u32 *value) +{ + unsigned long flags; + + if (!value || (bus >= MAX_MP_BUSSES) || (devfn > 255) || (reg > 255)) + return -EINVAL; + + spin_lock_irqsave(&pci_config_lock, flags); + + outl_quad(PCI_CONF1_MQ_ADDRESS(bus, devfn, reg), 0xCF8, BUS2QUAD(bus)); + + switch (len) { + case 1: + *value = inb_quad(0xCFC + (reg & 3), BUS2QUAD(bus)); + break; + case 2: + *value = inw_quad(0xCFC + (reg & 2), BUS2QUAD(bus)); + break; + case 4: + *value = inl_quad(0xCFC, BUS2QUAD(bus)); + break; + } + + spin_unlock_irqrestore(&pci_config_lock, flags); + + return 0; +} + +static int pci_conf1_mq_write(unsigned int seg, unsigned int bus, + unsigned int devfn, int reg, int len, u32 value) +{ + unsigned long flags; + + if ((bus >= MAX_MP_BUSSES) || (devfn > 255) || (reg > 255)) + return -EINVAL; + + spin_lock_irqsave(&pci_config_lock, flags); + + outl_quad(PCI_CONF1_MQ_ADDRESS(bus, devfn, reg), 0xCF8, BUS2QUAD(bus)); + + switch (len) { + case 1: + outb_quad((u8)value, 0xCFC + (reg & 3), BUS2QUAD(bus)); + break; + case 2: + outw_quad((u16)value, 0xCFC + (reg & 2), BUS2QUAD(bus)); + break; + case 4: + outl_quad((u32)value, 0xCFC, BUS2QUAD(bus)); + break; + } + + spin_unlock_irqrestore(&pci_config_lock, flags); + + return 0; +} + +#undef PCI_CONF1_MQ_ADDRESS + +static struct pci_raw_ops pci_direct_conf1_mq = { + .read = pci_conf1_mq_read, + .write = pci_conf1_mq_write +}; + + +static void __devinit pci_fixup_i450nx(struct pci_dev *d) +{ + /* + * i450NX -- Find and scan all secondary buses on all PXB's. + */ + int pxb, reg; + u8 busno, suba, subb; + int quad = BUS2QUAD(d->bus->number); + + printk("PCI: Searching for i450NX host bridges on %s\n", pci_name(d)); + reg = 0xd0; + for(pxb=0; pxb<2; pxb++) { + pci_read_config_byte(d, reg++, &busno); + pci_read_config_byte(d, reg++, &suba); + pci_read_config_byte(d, reg++, &subb); + DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb); + if (busno) { + /* Bus A */ + pci_scan_bus_with_sysdata(QUADLOCAL2BUS(quad, busno)); + } + if (suba < subb) { + /* Bus B */ + pci_scan_bus_with_sysdata(QUADLOCAL2BUS(quad, suba+1)); + } + } + pcibios_last_bus = -1; +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_fixup_i450nx); + +static int __init pci_numa_init(void) +{ + int quad; + + raw_pci_ops = &pci_direct_conf1_mq; + + if (pcibios_scanned++) + return 0; + + pci_root_bus = pcibios_scan_root(0); + if (pci_root_bus) + pci_bus_add_devices(pci_root_bus); + if (num_online_nodes() > 1) + for_each_online_node(quad) { + if (quad == 0) + continue; + printk("Scanning PCI bus %d for quad %d\n", + QUADLOCAL2BUS(quad,0), quad); + pci_scan_bus_with_sysdata(QUADLOCAL2BUS(quad, 0)); + } + return 0; +} + +subsys_initcall(pci_numa_init); diff --git a/arch/x86/pci/pcbios.c b/arch/x86/pci/pcbios.c new file mode 100644 index 00000000000..10ac8c316c4 --- /dev/null +++ b/arch/x86/pci/pcbios.c @@ -0,0 +1,492 @@ +/* + * BIOS32 and PCI BIOS handling. + */ + +#include +#include +#include +#include +#include "pci.h" +#include "pci-functions.h" + + +/* BIOS32 signature: "_32_" */ +#define BIOS32_SIGNATURE (('_' << 0) + ('3' << 8) + ('2' << 16) + ('_' << 24)) + +/* PCI signature: "PCI " */ +#define PCI_SIGNATURE (('P' << 0) + ('C' << 8) + ('I' << 16) + (' ' << 24)) + +/* PCI service signature: "$PCI" */ +#define PCI_SERVICE (('$' << 0) + ('P' << 8) + ('C' << 16) + ('I' << 24)) + +/* PCI BIOS hardware mechanism flags */ +#define PCIBIOS_HW_TYPE1 0x01 +#define PCIBIOS_HW_TYPE2 0x02 +#define PCIBIOS_HW_TYPE1_SPEC 0x10 +#define PCIBIOS_HW_TYPE2_SPEC 0x20 + +/* + * This is the standard structure used to identify the entry point + * to the BIOS32 Service Directory, as documented in + * Standard BIOS 32-bit Service Directory Proposal + * Revision 0.4 May 24, 1993 + * Phoenix Technologies Ltd. + * Norwood, MA + * and the PCI BIOS specification. + */ + +union bios32 { + struct { + unsigned long signature; /* _32_ */ + unsigned long entry; /* 32 bit physical address */ + unsigned char revision; /* Revision level, 0 */ + unsigned char length; /* Length in paragraphs should be 01 */ + unsigned char checksum; /* All bytes must add up to zero */ + unsigned char reserved[5]; /* Must be zero */ + } fields; + char chars[16]; +}; + +/* + * Physical address of the service directory. I don't know if we're + * allowed to have more than one of these or not, so just in case + * we'll make pcibios_present() take a memory start parameter and store + * the array there. + */ + +static struct { + unsigned long address; + unsigned short segment; +} bios32_indirect = { 0, __KERNEL_CS }; + +/* + * Returns the entry point for the given service, NULL on error + */ + +static unsigned long bios32_service(unsigned long service) +{ + unsigned char return_code; /* %al */ + unsigned long address; /* %ebx */ + unsigned long length; /* %ecx */ + unsigned long entry; /* %edx */ + unsigned long flags; + + local_irq_save(flags); + __asm__("lcall *(%%edi); cld" + : "=a" (return_code), + "=b" (address), + "=c" (length), + "=d" (entry) + : "0" (service), + "1" (0), + "D" (&bios32_indirect)); + local_irq_restore(flags); + + switch (return_code) { + case 0: + return address + entry; + case 0x80: /* Not present */ + printk(KERN_WARNING "bios32_service(0x%lx): not present\n", service); + return 0; + default: /* Shouldn't happen */ + printk(KERN_WARNING "bios32_service(0x%lx): returned 0x%x -- BIOS bug!\n", + service, return_code); + return 0; + } +} + +static struct { + unsigned long address; + unsigned short segment; +} pci_indirect = { 0, __KERNEL_CS }; + +static int pci_bios_present; + +static int __devinit check_pcibios(void) +{ + u32 signature, eax, ebx, ecx; + u8 status, major_ver, minor_ver, hw_mech; + unsigned long flags, pcibios_entry; + + if ((pcibios_entry = bios32_service(PCI_SERVICE))) { + pci_indirect.address = pcibios_entry + PAGE_OFFSET; + + local_irq_save(flags); + __asm__( + "lcall *(%%edi); cld\n\t" + "jc 1f\n\t" + "xor %%ah, %%ah\n" + "1:" + : "=d" (signature), + "=a" (eax), + "=b" (ebx), + "=c" (ecx) + : "1" (PCIBIOS_PCI_BIOS_PRESENT), + "D" (&pci_indirect) + : "memory"); + local_irq_restore(flags); + + status = (eax >> 8) & 0xff; + hw_mech = eax & 0xff; + major_ver = (ebx >> 8) & 0xff; + minor_ver = ebx & 0xff; + if (pcibios_last_bus < 0) + pcibios_last_bus = ecx & 0xff; + DBG("PCI: BIOS probe returned s=%02x hw=%02x ver=%02x.%02x l=%02x\n", + status, hw_mech, major_ver, minor_ver, pcibios_last_bus); + if (status || signature != PCI_SIGNATURE) { + printk (KERN_ERR "PCI: BIOS BUG #%x[%08x] found\n", + status, signature); + return 0; + } + printk(KERN_INFO "PCI: PCI BIOS revision %x.%02x entry at 0x%lx, last bus=%d\n", + major_ver, minor_ver, pcibios_entry, pcibios_last_bus); +#ifdef CONFIG_PCI_DIRECT + if (!(hw_mech & PCIBIOS_HW_TYPE1)) + pci_probe &= ~PCI_PROBE_CONF1; + if (!(hw_mech & PCIBIOS_HW_TYPE2)) + pci_probe &= ~PCI_PROBE_CONF2; +#endif + return 1; + } + return 0; +} + +static int __devinit pci_bios_find_device (unsigned short vendor, unsigned short device_id, + unsigned short index, unsigned char *bus, unsigned char *device_fn) +{ + unsigned short bx; + unsigned short ret; + + __asm__("lcall *(%%edi); cld\n\t" + "jc 1f\n\t" + "xor %%ah, %%ah\n" + "1:" + : "=b" (bx), + "=a" (ret) + : "1" (PCIBIOS_FIND_PCI_DEVICE), + "c" (device_id), + "d" (vendor), + "S" ((int) index), + "D" (&pci_indirect)); + *bus = (bx >> 8) & 0xff; + *device_fn = bx & 0xff; + return (int) (ret & 0xff00) >> 8; +} + +static int pci_bios_read(unsigned int seg, unsigned int bus, + unsigned int devfn, int reg, int len, u32 *value) +{ + unsigned long result = 0; + unsigned long flags; + unsigned long bx = (bus << 8) | devfn; + + if (!value || (bus > 255) || (devfn > 255) || (reg > 255)) + return -EINVAL; + + spin_lock_irqsave(&pci_config_lock, flags); + + switch (len) { + case 1: + __asm__("lcall *(%%esi); cld\n\t" + "jc 1f\n\t" + "xor %%ah, %%ah\n" + "1:" + : "=c" (*value), + "=a" (result) + : "1" (PCIBIOS_READ_CONFIG_BYTE), + "b" (bx), + "D" ((long)reg), + "S" (&pci_indirect)); + break; + case 2: + __asm__("lcall *(%%esi); cld\n\t" + "jc 1f\n\t" + "xor %%ah, %%ah\n" + "1:" + : "=c" (*value), + "=a" (result) + : "1" (PCIBIOS_READ_CONFIG_WORD), + "b" (bx), + "D" ((long)reg), + "S" (&pci_indirect)); + break; + case 4: + __asm__("lcall *(%%esi); cld\n\t" + "jc 1f\n\t" + "xor %%ah, %%ah\n" + "1:" + : "=c" (*value), + "=a" (result) + : "1" (PCIBIOS_READ_CONFIG_DWORD), + "b" (bx), + "D" ((long)reg), + "S" (&pci_indirect)); + break; + } + + spin_unlock_irqrestore(&pci_config_lock, flags); + + return (int)((result & 0xff00) >> 8); +} + +static int pci_bios_write(unsigned int seg, unsigned int bus, + unsigned int devfn, int reg, int len, u32 value) +{ + unsigned long result = 0; + unsigned long flags; + unsigned long bx = (bus << 8) | devfn; + + if ((bus > 255) || (devfn > 255) || (reg > 255)) + return -EINVAL; + + spin_lock_irqsave(&pci_config_lock, flags); + + switch (len) { + case 1: + __asm__("lcall *(%%esi); cld\n\t" + "jc 1f\n\t" + "xor %%ah, %%ah\n" + "1:" + : "=a" (result) + : "0" (PCIBIOS_WRITE_CONFIG_BYTE), + "c" (value), + "b" (bx), + "D" ((long)reg), + "S" (&pci_indirect)); + break; + case 2: + __asm__("lcall *(%%esi); cld\n\t" + "jc 1f\n\t" + "xor %%ah, %%ah\n" + "1:" + : "=a" (result) + : "0" (PCIBIOS_WRITE_CONFIG_WORD), + "c" (value), + "b" (bx), + "D" ((long)reg), + "S" (&pci_indirect)); + break; + case 4: + __asm__("lcall *(%%esi); cld\n\t" + "jc 1f\n\t" + "xor %%ah, %%ah\n" + "1:" + : "=a" (result) + : "0" (PCIBIOS_WRITE_CONFIG_DWORD), + "c" (value), + "b" (bx), + "D" ((long)reg), + "S" (&pci_indirect)); + break; + } + + spin_unlock_irqrestore(&pci_config_lock, flags); + + return (int)((result & 0xff00) >> 8); +} + + +/* + * Function table for BIOS32 access + */ + +static struct pci_raw_ops pci_bios_access = { + .read = pci_bios_read, + .write = pci_bios_write +}; + +/* + * Try to find PCI BIOS. + */ + +static struct pci_raw_ops * __devinit pci_find_bios(void) +{ + union bios32 *check; + unsigned char sum; + int i, length; + + /* + * Follow the standard procedure for locating the BIOS32 Service + * directory by scanning the permissible address range from + * 0xe0000 through 0xfffff for a valid BIOS32 structure. + */ + + for (check = (union bios32 *) __va(0xe0000); + check <= (union bios32 *) __va(0xffff0); + ++check) { + long sig; + if (probe_kernel_address(&check->fields.signature, sig)) + continue; + + if (check->fields.signature != BIOS32_SIGNATURE) + continue; + length = check->fields.length * 16; + if (!length) + continue; + sum = 0; + for (i = 0; i < length ; ++i) + sum += check->chars[i]; + if (sum != 0) + continue; + if (check->fields.revision != 0) { + printk("PCI: unsupported BIOS32 revision %d at 0x%p\n", + check->fields.revision, check); + continue; + } + DBG("PCI: BIOS32 Service Directory structure at 0x%p\n", check); + if (check->fields.entry >= 0x100000) { + printk("PCI: BIOS32 entry (0x%p) in high memory, " + "cannot use.\n", check); + return NULL; + } else { + unsigned long bios32_entry = check->fields.entry; + DBG("PCI: BIOS32 Service Directory entry at 0x%lx\n", + bios32_entry); + bios32_indirect.address = bios32_entry + PAGE_OFFSET; + if (check_pcibios()) + return &pci_bios_access; + } + break; /* Hopefully more than one BIOS32 cannot happen... */ + } + + return NULL; +} + +/* + * Sort the device list according to PCI BIOS. Nasty hack, but since some + * fool forgot to define the `correct' device order in the PCI BIOS specs + * and we want to be (possibly bug-to-bug ;-]) compatible with older kernels + * which used BIOS ordering, we are bound to do this... + */ + +void __devinit pcibios_sort(void) +{ + LIST_HEAD(sorted_devices); + struct list_head *ln; + struct pci_dev *dev, *d; + int idx, found; + unsigned char bus, devfn; + + DBG("PCI: Sorting device list...\n"); + while (!list_empty(&pci_devices)) { + ln = pci_devices.next; + dev = pci_dev_g(ln); + idx = found = 0; + while (pci_bios_find_device(dev->vendor, dev->device, idx, &bus, &devfn) == PCIBIOS_SUCCESSFUL) { + idx++; + list_for_each(ln, &pci_devices) { + d = pci_dev_g(ln); + if (d->bus->number == bus && d->devfn == devfn) { + list_move_tail(&d->global_list, &sorted_devices); + if (d == dev) + found = 1; + break; + } + } + if (ln == &pci_devices) { + printk(KERN_WARNING "PCI: BIOS reporting unknown device %02x:%02x\n", bus, devfn); + /* + * We must not continue scanning as several buggy BIOSes + * return garbage after the last device. Grr. + */ + break; + } + } + if (!found) { + printk(KERN_WARNING "PCI: Device %s not found by BIOS\n", + pci_name(dev)); + list_move_tail(&dev->global_list, &sorted_devices); + } + } + list_splice(&sorted_devices, &pci_devices); +} + +/* + * BIOS Functions for IRQ Routing + */ + +struct irq_routing_options { + u16 size; + struct irq_info *table; + u16 segment; +} __attribute__((packed)); + +struct irq_routing_table * pcibios_get_irq_routing_table(void) +{ + struct irq_routing_options opt; + struct irq_routing_table *rt = NULL; + int ret, map; + unsigned long page; + + if (!pci_bios_present) + return NULL; + page = __get_free_page(GFP_KERNEL); + if (!page) + return NULL; + opt.table = (struct irq_info *) page; + opt.size = PAGE_SIZE; + opt.segment = __KERNEL_DS; + + DBG("PCI: Fetching IRQ routing table... "); + __asm__("push %%es\n\t" + "push %%ds\n\t" + "pop %%es\n\t" + "lcall *(%%esi); cld\n\t" + "pop %%es\n\t" + "jc 1f\n\t" + "xor %%ah, %%ah\n" + "1:" + : "=a" (ret), + "=b" (map), + "=m" (opt) + : "0" (PCIBIOS_GET_ROUTING_OPTIONS), + "1" (0), + "D" ((long) &opt), + "S" (&pci_indirect), + "m" (opt) + : "memory"); + DBG("OK ret=%d, size=%d, map=%x\n", ret, opt.size, map); + if (ret & 0xff00) + printk(KERN_ERR "PCI: Error %02x when fetching IRQ routing table.\n", (ret >> 8) & 0xff); + else if (opt.size) { + rt = kmalloc(sizeof(struct irq_routing_table) + opt.size, GFP_KERNEL); + if (rt) { + memset(rt, 0, sizeof(struct irq_routing_table)); + rt->size = opt.size + sizeof(struct irq_routing_table); + rt->exclusive_irqs = map; + memcpy(rt->slots, (void *) page, opt.size); + printk(KERN_INFO "PCI: Using BIOS Interrupt Routing Table\n"); + } + } + free_page(page); + return rt; +} +EXPORT_SYMBOL(pcibios_get_irq_routing_table); + +int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq) +{ + int ret; + + __asm__("lcall *(%%esi); cld\n\t" + "jc 1f\n\t" + "xor %%ah, %%ah\n" + "1:" + : "=a" (ret) + : "0" (PCIBIOS_SET_PCI_HW_INT), + "b" ((dev->bus->number << 8) | dev->devfn), + "c" ((irq << 8) | (pin + 10)), + "S" (&pci_indirect)); + return !(ret & 0xff00); +} +EXPORT_SYMBOL(pcibios_set_irq_routing); + +void __init pci_pcbios_init(void) +{ + if ((pci_probe & PCI_PROBE_BIOS) + && ((raw_pci_ops = pci_find_bios()))) { + pci_probe |= PCI_BIOS_SORT; + pci_bios_present = 1; + } +} + diff --git a/arch/x86/pci/pci.h b/arch/x86/pci/pci.h new file mode 100644 index 00000000000..8c66f275756 --- /dev/null +++ b/arch/x86/pci/pci.h @@ -0,0 +1,149 @@ +/* + * Low-Level PCI Access for i386 machines. + * + * (c) 1999 Martin Mares + */ + +#undef DEBUG + +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +#define PCI_PROBE_BIOS 0x0001 +#define PCI_PROBE_CONF1 0x0002 +#define PCI_PROBE_CONF2 0x0004 +#define PCI_PROBE_MMCONF 0x0008 +#define PCI_PROBE_MASK 0x000f +#define PCI_PROBE_NOEARLY 0x0010 + +#define PCI_NO_SORT 0x0100 +#define PCI_BIOS_SORT 0x0200 +#define PCI_NO_CHECKS 0x0400 +#define PCI_USE_PIRQ_MASK 0x0800 +#define PCI_ASSIGN_ROMS 0x1000 +#define PCI_BIOS_IRQ_SCAN 0x2000 +#define PCI_ASSIGN_ALL_BUSSES 0x4000 + +extern unsigned int pci_probe; +extern unsigned long pirq_table_addr; + +enum pci_bf_sort_state { + pci_bf_sort_default, + pci_force_nobf, + pci_force_bf, + pci_dmi_bf, +}; + +/* pci-i386.c */ + +extern unsigned int pcibios_max_latency; + +void pcibios_resource_survey(void); +int pcibios_enable_resources(struct pci_dev *, int); + +/* pci-pc.c */ + +extern int pcibios_last_bus; +extern struct pci_bus *pci_root_bus; +extern struct pci_ops pci_root_ops; + +/* pci-irq.c */ + +struct irq_info { + u8 bus, devfn; /* Bus, device and function */ + struct { + u8 link; /* IRQ line ID, chipset dependent, 0=not routed */ + u16 bitmap; /* Available IRQs */ + } __attribute__((packed)) irq[4]; + u8 slot; /* Slot number, 0=onboard */ + u8 rfu; +} __attribute__((packed)); + +struct irq_routing_table { + u32 signature; /* PIRQ_SIGNATURE should be here */ + u16 version; /* PIRQ_VERSION */ + u16 size; /* Table size in bytes */ + u8 rtr_bus, rtr_devfn; /* Where the interrupt router lies */ + u16 exclusive_irqs; /* IRQs devoted exclusively to PCI usage */ + u16 rtr_vendor, rtr_device; /* Vendor and device ID of interrupt router */ + u32 miniport_data; /* Crap */ + u8 rfu[11]; + u8 checksum; /* Modulo 256 checksum must give zero */ + struct irq_info slots[0]; +} __attribute__((packed)); + +extern unsigned int pcibios_irq_mask; + +extern int pcibios_scanned; +extern spinlock_t pci_config_lock; + +extern int (*pcibios_enable_irq)(struct pci_dev *dev); +extern void (*pcibios_disable_irq)(struct pci_dev *dev); + +extern int pci_conf1_write(unsigned int seg, unsigned int bus, + unsigned int devfn, int reg, int len, u32 value); +extern int pci_conf1_read(unsigned int seg, unsigned int bus, + unsigned int devfn, int reg, int len, u32 *value); + +extern int pci_direct_probe(void); +extern void pci_direct_init(int type); +extern void pci_pcbios_init(void); +extern void pci_mmcfg_init(int type); +extern void pcibios_sort(void); + +/* pci-mmconfig.c */ + +/* Verify the first 16 busses. We assume that systems with more busses + get MCFG right. */ +#define PCI_MMCFG_MAX_CHECK_BUS 16 +extern DECLARE_BITMAP(pci_mmcfg_fallback_slots, 32*PCI_MMCFG_MAX_CHECK_BUS); + +extern int __init pci_mmcfg_arch_reachable(unsigned int seg, unsigned int bus, + unsigned int devfn); +extern int __init pci_mmcfg_arch_init(void); + +/* + * AMD Fam10h CPUs are buggy, and cannot access MMIO config space + * on their northbrige except through the * %eax register. As such, you MUST + * NOT use normal IOMEM accesses, you need to only use the magic mmio-config + * accessor functions. + * In fact just use pci_config_*, nothing else please. + */ +static inline unsigned char mmio_config_readb(void __iomem *pos) +{ + u8 val; + asm volatile("movb (%1),%%al" : "=a" (val) : "r" (pos)); + return val; +} + +static inline unsigned short mmio_config_readw(void __iomem *pos) +{ + u16 val; + asm volatile("movw (%1),%%ax" : "=a" (val) : "r" (pos)); + return val; +} + +static inline unsigned int mmio_config_readl(void __iomem *pos) +{ + u32 val; + asm volatile("movl (%1),%%eax" : "=a" (val) : "r" (pos)); + return val; +} + +static inline void mmio_config_writeb(void __iomem *pos, u8 val) +{ + asm volatile("movb %%al,(%1)" :: "a" (val), "r" (pos) : "memory"); +} + +static inline void mmio_config_writew(void __iomem *pos, u16 val) +{ + asm volatile("movw %%ax,(%1)" :: "a" (val), "r" (pos) : "memory"); +} + +static inline void mmio_config_writel(void __iomem *pos, u32 val) +{ + asm volatile("movl %%eax,(%1)" :: "a" (val), "r" (pos) : "memory"); +} diff --git a/arch/x86/pci/visws.c b/arch/x86/pci/visws.c new file mode 100644 index 00000000000..8ecb1c72259 --- /dev/null +++ b/arch/x86/pci/visws.c @@ -0,0 +1,111 @@ +/* + * Low-Level PCI Support for SGI Visual Workstation + * + * (c) 1999--2000 Martin Mares + */ + +#include +#include +#include + +#include "cobalt.h" +#include "lithium.h" + +#include "pci.h" + + +extern struct pci_raw_ops pci_direct_conf1; + +static int pci_visws_enable_irq(struct pci_dev *dev) { return 0; } +static void pci_visws_disable_irq(struct pci_dev *dev) { } + +int (*pcibios_enable_irq)(struct pci_dev *dev) = &pci_visws_enable_irq; +void (*pcibios_disable_irq)(struct pci_dev *dev) = &pci_visws_disable_irq; + +void __init pcibios_penalize_isa_irq(int irq, int active) {} + + +unsigned int pci_bus0, pci_bus1; + +static inline u8 bridge_swizzle(u8 pin, u8 slot) +{ + return (((pin - 1) + slot) % 4) + 1; +} + +static u8 __init visws_swizzle(struct pci_dev *dev, u8 *pinp) +{ + u8 pin = *pinp; + + while (dev->bus->self) { /* Move up the chain of bridges. */ + pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)); + dev = dev->bus->self; + } + *pinp = pin; + + return PCI_SLOT(dev->devfn); +} + +static int __init visws_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + int irq, bus = dev->bus->number; + + pin--; + + /* Nothing useful at PIIX4 pin 1 */ + if (bus == pci_bus0 && slot == 4 && pin == 0) + return -1; + + /* PIIX4 USB is on Bus 0, Slot 4, Line 3 */ + if (bus == pci_bus0 && slot == 4 && pin == 3) { + irq = CO_IRQ(CO_APIC_PIIX4_USB); + goto out; + } + + /* First pin spread down 1 APIC entry per slot */ + if (pin == 0) { + irq = CO_IRQ((bus == pci_bus0 ? CO_APIC_PCIB_BASE0 : + CO_APIC_PCIA_BASE0) + slot); + goto out; + } + + /* lines 1,2,3 from any slot is shared in this twirly pattern */ + if (bus == pci_bus1) { + /* lines 1-3 from devices 0 1 rotate over 2 apic entries */ + irq = CO_IRQ(CO_APIC_PCIA_BASE123 + ((slot + (pin - 1)) % 2)); + } else { /* bus == pci_bus0 */ + /* lines 1-3 from devices 0-3 rotate over 3 apic entries */ + if (slot == 0) + slot = 3; /* same pattern */ + irq = CO_IRQ(CO_APIC_PCIA_BASE123 + ((3 - slot) + (pin - 1) % 3)); + } +out: + printk(KERN_DEBUG "PCI: Bus %d Slot %d Line %d -> IRQ %d\n", bus, slot, pin, irq); + return irq; +} + +void __init pcibios_update_irq(struct pci_dev *dev, int irq) +{ + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); +} + +static int __init pcibios_init(void) +{ + /* The VISWS supports configuration access type 1 only */ + pci_probe = (pci_probe | PCI_PROBE_CONF1) & + ~(PCI_PROBE_BIOS | PCI_PROBE_CONF2); + + pci_bus0 = li_pcib_read16(LI_PCI_BUSNUM) & 0xff; + pci_bus1 = li_pcia_read16(LI_PCI_BUSNUM) & 0xff; + + printk(KERN_INFO "PCI: Lithium bridge A bus: %u, " + "bridge B (PIIX4) bus: %u\n", pci_bus1, pci_bus0); + + raw_pci_ops = &pci_direct_conf1; + pci_scan_bus_with_sysdata(pci_bus0); + pci_scan_bus_with_sysdata(pci_bus1); + pci_fixup_irqs(visws_swizzle, visws_map_irq); + pcibios_resource_survey(); + return 0; +} + +subsys_initcall(pcibios_init); diff --git a/arch/x86_64/pci/Makefile b/arch/x86_64/pci/Makefile index d04d8f976d1..b3e54c45d40 100644 --- a/arch/x86_64/pci/Makefile +++ b/arch/x86_64/pci/Makefile @@ -1,5 +1,5 @@ ifeq ($(CONFIG_X86_32),y) -include ${srctree}/arch/i386/pci/Makefile_32 +include ${srctree}/arch/x86/pci/Makefile_32 else include ${srctree}/arch/x86_64/pci/Makefile_64 endif diff --git a/arch/x86_64/pci/Makefile_64 b/arch/x86_64/pci/Makefile_64 index 77b1b9abedc..79b618b9e9d 100644 --- a/arch/x86_64/pci/Makefile_64 +++ b/arch/x86_64/pci/Makefile_64 @@ -3,7 +3,7 @@ # # Reuse the i386 PCI subsystem # -EXTRA_CFLAGS += -Iarch/i386/pci +EXTRA_CFLAGS += -Iarch/x86/pci obj-y := i386.o obj-$(CONFIG_PCI_DIRECT)+= direct.o @@ -15,13 +15,13 @@ obj-$(CONFIG_PCI_MMCONFIG) += mmconfig_64.o direct.o mmconfig-shared.o obj-$(CONFIG_NUMA) += k8-bus_64.o -direct-y += ../../i386/pci/direct.o -acpi-y += ../../i386/pci/acpi.o -legacy-y += ../../i386/pci/legacy.o -irq-y += ../../i386/pci/irq.o -common-y += ../../i386/pci/common.o -fixup-y += ../../i386/pci/fixup.o -i386-y += ../../i386/pci/i386.o -init-y += ../../i386/pci/init.o -early-y += ../../i386/pci/early.o -mmconfig-shared-y += ../../i386/pci/mmconfig-shared.o +direct-y += ../../x86/pci/direct.o +acpi-y += ../../x86/pci/acpi.o +legacy-y += ../../x86/pci/legacy.o +irq-y += ../../x86/pci/irq.o +common-y += ../../x86/pci/common.o +fixup-y += ../../x86/pci/fixup.o +i386-y += ../../x86/pci/i386.o +init-y += ../../x86/pci/init.o +early-y += ../../x86/pci/early.o +mmconfig-shared-y += ../../x86/pci/mmconfig-shared.o diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c index d590a99930f..2305cc450a4 100644 --- a/drivers/pci/hotplug/cpqphp_core.c +++ b/drivers/pci/hotplug/cpqphp_core.c @@ -45,7 +45,7 @@ #include "cpqphp.h" #include "cpqphp_nvram.h" -#include "../../../arch/i386/pci/pci.h" /* horrible hack showing how processor dependent we are... */ +#include "../../../arch/x86/pci/pci.h" /* horrible hack showing how processor dependent we are... */ /* Global variables */ diff --git a/drivers/pci/hotplug/cpqphp_pci.c b/drivers/pci/hotplug/cpqphp_pci.c index fc7c74d7259..3f6cd20e95d 100644 --- a/drivers/pci/hotplug/cpqphp_pci.c +++ b/drivers/pci/hotplug/cpqphp_pci.c @@ -37,7 +37,7 @@ #include "../pci.h" #include "cpqphp.h" #include "cpqphp_nvram.h" -#include "../../../arch/i386/pci/pci.h" /* horrible hack showing how processor dependent we are... */ +#include "../../../arch/x86/pci/pci.h" /* horrible hack showing how processor dependent we are... */ u8 cpqhp_nic_irq; diff --git a/drivers/pci/hotplug/ibmphp_core.c b/drivers/pci/hotplug/ibmphp_core.c index 0316eeaaeb2..a90c28d0c69 100644 --- a/drivers/pci/hotplug/ibmphp_core.c +++ b/drivers/pci/hotplug/ibmphp_core.c @@ -35,7 +35,7 @@ #include #include #include "../pci.h" -#include "../../../arch/i386/pci/pci.h" /* for struct irq_routing_table */ +#include "../../../arch/x86/pci/pci.h" /* for struct irq_routing_table */ #include "ibmphp.h" #define attn_on(sl) ibmphp_hpc_writeslot (sl, HPC_SLOT_ATTNON) -- cgit v1.2.3-70-g09d2 From d71fce6b932d83e0a1caa49dfa5a536fd50f07c9 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 11 Oct 2007 02:44:23 -0700 Subject: [QETH]: fix qeth_main.c drivers/s390/net/qeth_main.c: In function 'qeth_hard_header_parse': drivers/s390/net/qeth_main.c:6584: error: 'dev' undeclared (first use in this function) drivers/s390/net/qeth_main.c:6584: error: (Each undeclared identifier is reported only once drivers/s390/net/qeth_main.c:6584: error: for each function it appears in.) Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/s390/net/qeth_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index c67e7dfd56c..a2d08c9ba3c 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c @@ -6580,11 +6580,12 @@ qeth_hard_header_parse(const struct sk_buff *skb, unsigned char *haddr) { const struct qeth_card *card; const struct ethhdr *eth; + struct net_device *dev = skb->dev; if (dev->type != ARPHRD_IEEE802_TR) return 0; - card = qeth_get_card_from_dev(skb->dev); + card = qeth_get_card_from_dev(dev); if (card->options.layer2) goto haveheader; #ifdef CONFIG_QETH_IPV6 -- cgit v1.2.3-70-g09d2 From 73be7d5267774b8fef1d83ebffc070cd090c4398 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 11 Oct 2007 14:50:55 +1000 Subject: [POWERPC] iSeries: Simplify viocd initialisation We don't need to keep a lump of dma coherent memory around for the life of the module. Signed-off-by: Stephen Rothwell Acked-by: Jens Axboe Signed-off-by: Paul Mackerras --- drivers/cdrom/viocd.c | 37 +++++++++++++------------------------ 1 file changed, 13 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c index e51550db157..b88fdebe77f 100644 --- a/drivers/cdrom/viocd.c +++ b/drivers/cdrom/viocd.c @@ -136,17 +136,12 @@ struct cdrom_info { char type[4]; char model[3]; }; -/* - * This needs to be allocated since it is passed to the - * Hypervisor and we may be a module. - */ -static struct cdrom_info *viocd_unitinfo; -static dma_addr_t unitinfo_dmaaddr; struct disk_info { struct gendisk *viocd_disk; struct cdrom_device_info viocd_info; struct device *dev; + struct cdrom_info unitinfo; }; static struct disk_info viocd_diskinfo[VIOCD_MAX_CD]; @@ -164,9 +159,9 @@ static int proc_viocd_show(struct seq_file *m, void *v) for (i = 0; i < viocd_numdev; i++) { seq_printf(m, "viocd device %d is iSeries resource %10.10s" "type %4.4s, model %3.3s\n", - i, viocd_unitinfo[i].rsrcname, - viocd_unitinfo[i].type, - viocd_unitinfo[i].model); + i, viocd_diskinfo[i].unitinfo.rsrcname, + viocd_diskinfo[i].unitinfo.type, + viocd_diskinfo[i].unitinfo.model); } return 0; } @@ -222,6 +217,8 @@ static void __init get_viocd_info(void) HvLpEvent_Rc hvrc; int i; struct viocd_waitevent we; + struct cdrom_info *viocd_unitinfo; + dma_addr_t unitinfo_dmaaddr; viocd_unitinfo = dma_alloc_coherent(iSeries_vio_dev, sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, @@ -259,16 +256,15 @@ static void __init get_viocd_info(void) goto error_ret; } - for (i = 0; (i < VIOCD_MAX_CD) && viocd_unitinfo[i].rsrcname[0]; i++) + for (i = 0; (i < VIOCD_MAX_CD) && viocd_unitinfo[i].rsrcname[0]; i++) { + viocd_diskinfo[viocd_numdev].unitinfo = viocd_unitinfo[i]; viocd_numdev++; + } error_ret: - if (viocd_numdev == 0) { - dma_free_coherent(iSeries_vio_dev, - sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, - viocd_unitinfo, unitinfo_dmaaddr); - viocd_unitinfo = NULL; - } + dma_free_coherent(iSeries_vio_dev, + sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, + viocd_unitinfo, unitinfo_dmaaddr); } static int viocd_open(struct cdrom_device_info *cdi, int purpose) @@ -674,7 +670,7 @@ static int viocd_probe(struct vio_dev *vdev, const struct vio_device_id *id) d = &viocd_diskinfo[deviceno]; c = &d->viocd_info; - ci = &viocd_unitinfo[deviceno]; + ci = &d->unitinfo; c->ops = &viocd_dops; c->speed = 4; @@ -816,9 +812,6 @@ static int __init viocd_init(void) return 0; out_free_info: - dma_free_coherent(iSeries_vio_dev, - sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, - viocd_unitinfo, unitinfo_dmaaddr); vio_clearHandler(viomajorsubtype_cdio); viopath_close(viopath_hostLp, viomajorsubtype_cdio, MAX_CD_REQ + 2); out_unregister: @@ -830,10 +823,6 @@ static void __exit viocd_exit(void) { remove_proc_entry("iSeries/viocd", NULL); vio_unregister_driver(&viocd_driver); - if (viocd_unitinfo != NULL) - dma_free_coherent(iSeries_vio_dev, - sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, - viocd_unitinfo, unitinfo_dmaaddr); viopath_close(viopath_hostLp, viomajorsubtype_cdio, MAX_CD_REQ + 2); vio_clearHandler(viomajorsubtype_cdio); unregister_blkdev(VIOCD_MAJOR, VIOCD_DEVICE); -- cgit v1.2.3-70-g09d2 From 1670b2b2716b98541765da94be1332ad5c314b7a Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 11 Oct 2007 14:53:32 +1000 Subject: [POWERPC] Remove iSeries_vio_dev It was only being used to carry around dma_iommu_ops and vio_iommu_table which we can use directly instead. This also means that vio_bus_device doesn't need to refer to them either. Signed-off-by: Stephen Rothwell Acked-by: Jens Axboe Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/vio.c | 7 +------ arch/powerpc/platforms/iseries/iommu.c | 30 +++++++++++++++++++++++++++++ arch/powerpc/platforms/iseries/mf.c | 23 +++++++++------------- arch/powerpc/platforms/iseries/viopath.c | 6 ++---- drivers/cdrom/viocd.c | 5 ++--- drivers/char/viotape.c | 7 +++---- include/asm-powerpc/iseries/hv_call_event.h | 10 ++++++++++ include/asm-powerpc/iseries/vio.h | 4 ---- 8 files changed, 57 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c index fd631d4d160..eaf7f6992a2 100644 --- a/arch/powerpc/kernel/vio.c +++ b/arch/powerpc/kernel/vio.c @@ -49,11 +49,8 @@ static struct vio_dev vio_bus_device = { /* fake "parent" device */ }; #ifdef CONFIG_PPC_ISERIES -struct device *iSeries_vio_dev = &vio_bus_device.dev; -EXPORT_SYMBOL(iSeries_vio_dev); - static struct iommu_table veth_iommu_table; -static struct iommu_table vio_iommu_table; +struct iommu_table vio_iommu_table; static void __init iommu_vio_init(void) { @@ -66,8 +63,6 @@ static void __init iommu_vio_init(void) printk("Virtual Bus VETH TCE table failed.\n"); if (!iommu_init_table(&vio_iommu_table, -1)) printk("Virtual Bus VIO TCE table failed.\n"); - vio_bus_device.dev.archdata.dma_ops = &dma_iommu_ops; - vio_bus_device.dev.archdata.dma_data = &vio_iommu_table; } #else static void __init iommu_vio_init(void) diff --git a/arch/powerpc/platforms/iseries/iommu.c b/arch/powerpc/platforms/iseries/iommu.c index 3b6a9666c2c..3281f10bbd1 100644 --- a/arch/powerpc/platforms/iseries/iommu.c +++ b/arch/powerpc/platforms/iseries/iommu.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -36,6 +37,7 @@ #include #include #include +#include #include static void tce_build_iSeries(struct iommu_table *tbl, long index, long npages, @@ -189,6 +191,34 @@ void iommu_devnode_init_iSeries(struct pci_dev *pdev, struct device_node *dn) } #endif +extern struct iommu_table vio_iommu_table; + +void *iseries_hv_alloc(size_t size, dma_addr_t *dma_handle, gfp_t flag) +{ + return iommu_alloc_coherent(&vio_iommu_table, size, dma_handle, + DMA_32BIT_MASK, flag, -1); +} +EXPORT_SYMBOL_GPL(iseries_hv_alloc); + +void iseries_hv_free(size_t size, void *vaddr, dma_addr_t dma_handle) +{ + iommu_free_coherent(&vio_iommu_table, size, vaddr, dma_handle); +} +EXPORT_SYMBOL_GPL(iseries_hv_free); + +dma_addr_t iseries_hv_map(void *vaddr, size_t size, + enum dma_data_direction direction) +{ + return iommu_map_single(&vio_iommu_table, vaddr, size, + DMA_32BIT_MASK, direction); +} + +void iseries_hv_unmap(dma_addr_t dma_handle, size_t size, + enum dma_data_direction direction) +{ + iommu_unmap_single(&vio_iommu_table, dma_handle, size, direction); +} + void iommu_init_early_iSeries(void) { ppc_md.tce_build = tce_build_iSeries; diff --git a/arch/powerpc/platforms/iseries/mf.c b/arch/powerpc/platforms/iseries/mf.c index b1187d95e3b..c0f2433bc16 100644 --- a/arch/powerpc/platforms/iseries/mf.c +++ b/arch/powerpc/platforms/iseries/mf.c @@ -39,9 +39,9 @@ #include #include #include -#include #include #include +#include #include #include "setup.h" @@ -870,8 +870,7 @@ static int proc_mf_dump_cmdline(char *page, char **start, off_t off, if ((off + count) > 256) count = 256 - off; - dma_addr = dma_map_single(iSeries_vio_dev, page, off + count, - DMA_FROM_DEVICE); + dma_addr = iseries_hv_map(page, off + count, DMA_FROM_DEVICE); if (dma_mapping_error(dma_addr)) return -ENOMEM; memset(page, 0, off + count); @@ -883,8 +882,7 @@ static int proc_mf_dump_cmdline(char *page, char **start, off_t off, vsp_cmd.sub_data.kern.length = off + count; mb(); rc = signal_vsp_instruction(&vsp_cmd); - dma_unmap_single(iSeries_vio_dev, dma_addr, off + count, - DMA_FROM_DEVICE); + iseries_hv_unmap(dma_addr, off + count, DMA_FROM_DEVICE); if (rc) return rc; if (vsp_cmd.result_code != 0) @@ -919,8 +917,7 @@ static int mf_getVmlinuxChunk(char *buffer, int *size, int offset, u64 side) int len = *size; dma_addr_t dma_addr; - dma_addr = dma_map_single(iSeries_vio_dev, buffer, len, - DMA_FROM_DEVICE); + dma_addr = iseries_hv_map(buffer, len, DMA_FROM_DEVICE); memset(buffer, 0, len); memset(&vsp_cmd, 0, sizeof(vsp_cmd)); vsp_cmd.cmd = 32; @@ -938,7 +935,7 @@ static int mf_getVmlinuxChunk(char *buffer, int *size, int offset, u64 side) rc = -ENOMEM; } - dma_unmap_single(iSeries_vio_dev, dma_addr, len, DMA_FROM_DEVICE); + iseries_hv_unmap(dma_addr, len, DMA_FROM_DEVICE); return rc; } @@ -1149,8 +1146,7 @@ static int proc_mf_change_cmdline(struct file *file, const char __user *buffer, goto out; dma_addr = 0; - page = dma_alloc_coherent(iSeries_vio_dev, count, &dma_addr, - GFP_ATOMIC); + page = iseries_hv_alloc(count, &dma_addr, GFP_ATOMIC); ret = -ENOMEM; if (page == NULL) goto out; @@ -1170,7 +1166,7 @@ static int proc_mf_change_cmdline(struct file *file, const char __user *buffer, ret = count; out_free: - dma_free_coherent(iSeries_vio_dev, count, page, dma_addr); + iseries_hv_free(count, page, dma_addr); out: return ret; } @@ -1190,8 +1186,7 @@ static ssize_t proc_mf_change_vmlinux(struct file *file, goto out; dma_addr = 0; - page = dma_alloc_coherent(iSeries_vio_dev, count, &dma_addr, - GFP_ATOMIC); + page = iseries_hv_alloc(count, &dma_addr, GFP_ATOMIC); rc = -ENOMEM; if (page == NULL) { printk(KERN_ERR "mf.c: couldn't allocate memory to set vmlinux chunk\n"); @@ -1219,7 +1214,7 @@ static ssize_t proc_mf_change_vmlinux(struct file *file, *ppos += count; rc = count; out_free: - dma_free_coherent(iSeries_vio_dev, count, page, dma_addr); + iseries_hv_free(count, page, dma_addr); out: return rc; } diff --git a/arch/powerpc/platforms/iseries/viopath.c b/arch/powerpc/platforms/iseries/viopath.c index 45f2fe39c87..df23331eb25 100644 --- a/arch/powerpc/platforms/iseries/viopath.c +++ b/arch/powerpc/platforms/iseries/viopath.c @@ -124,8 +124,7 @@ static int proc_viopath_show(struct seq_file *m, void *v) if (!buf) return 0; - handle = dma_map_single(iSeries_vio_dev, buf, HW_PAGE_SIZE, - DMA_FROM_DEVICE); + handle = iseries_hv_map(buf, HW_PAGE_SIZE, DMA_FROM_DEVICE); hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, HvLpEvent_Type_VirtualIo, @@ -146,8 +145,7 @@ static int proc_viopath_show(struct seq_file *m, void *v) buf[HW_PAGE_SIZE-1] = '\0'; seq_printf(m, "%s", buf); - dma_unmap_single(iSeries_vio_dev, handle, HW_PAGE_SIZE, - DMA_FROM_DEVICE); + iseries_hv_unmap(handle, HW_PAGE_SIZE, DMA_FROM_DEVICE); kfree(buf); seq_printf(m, "AVAILABLE_VETH=%x\n", vlanMap); diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c index b88fdebe77f..c081e5400ce 100644 --- a/drivers/cdrom/viocd.c +++ b/drivers/cdrom/viocd.c @@ -220,7 +220,7 @@ static void __init get_viocd_info(void) struct cdrom_info *viocd_unitinfo; dma_addr_t unitinfo_dmaaddr; - viocd_unitinfo = dma_alloc_coherent(iSeries_vio_dev, + viocd_unitinfo = iseries_hv_alloc( sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, &unitinfo_dmaaddr, GFP_ATOMIC); if (viocd_unitinfo == NULL) { @@ -262,8 +262,7 @@ static void __init get_viocd_info(void) } error_ret: - dma_free_coherent(iSeries_vio_dev, - sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, + iseries_hv_free(sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, viocd_unitinfo, unitinfo_dmaaddr); } diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c index e12275df6ea..064c0919521 100644 --- a/drivers/char/viotape.c +++ b/drivers/char/viotape.c @@ -392,8 +392,8 @@ static int get_viotape_info(void) if (op == NULL) return -ENOMEM; - viotape_unitinfo = dma_alloc_coherent(iSeries_vio_dev, len, - &viotape_unitinfo_token, GFP_ATOMIC); + viotape_unitinfo = iseries_hv_alloc(len, &viotape_unitinfo_token, + GFP_ATOMIC); if (viotape_unitinfo == NULL) { free_op_struct(op); return -ENOMEM; @@ -1103,8 +1103,7 @@ static void __exit viotap_exit(void) class_destroy(tape_class); unregister_chrdev(VIOTAPE_MAJOR, "viotape"); if (viotape_unitinfo) - dma_free_coherent(iSeries_vio_dev, - sizeof(viotape_unitinfo[0]) * VIOTAPE_MAX_TAPE, + iseries_hv_free(sizeof(viotape_unitinfo[0]) * VIOTAPE_MAX_TAPE, viotape_unitinfo, viotape_unitinfo_token); viopath_close(viopath_hostLp, viomajorsubtype_tape, VIOTAPE_MAXREQ + 2); vio_clearHandler(viomajorsubtype_tape); diff --git a/include/asm-powerpc/iseries/hv_call_event.h b/include/asm-powerpc/iseries/hv_call_event.h index 4cec4762076..cc029d388e1 100644 --- a/include/asm-powerpc/iseries/hv_call_event.h +++ b/include/asm-powerpc/iseries/hv_call_event.h @@ -21,6 +21,9 @@ #ifndef _ASM_POWERPC_ISERIES_HV_CALL_EVENT_H #define _ASM_POWERPC_ISERIES_HV_CALL_EVENT_H +#include +#include + #include #include #include @@ -113,6 +116,13 @@ static inline HvLpEvent_Rc HvCallEvent_signalLpEventFast(HvLpIndex targetLp, eventData3, eventData4, eventData5); } +extern void *iseries_hv_alloc(size_t size, dma_addr_t *dma_handle, gfp_t flag); +extern void iseries_hv_free(size_t size, void *vaddr, dma_addr_t dma_handle); +extern dma_addr_t iseries_hv_map(void *vaddr, size_t size, + enum dma_data_direction direction); +extern void iseries_hv_unmap(dma_addr_t dma_handle, size_t size, + enum dma_data_direction direction); + static inline HvLpEvent_Rc HvCallEvent_ackLpEvent(struct HvLpEvent *event) { return HvCall1(HvCallEventAckLpEvent, virt_to_abs(event)); diff --git a/include/asm-powerpc/iseries/vio.h b/include/asm-powerpc/iseries/vio.h index 7a95d296abd..5a5cd0f0c09 100644 --- a/include/asm-powerpc/iseries/vio.h +++ b/include/asm-powerpc/iseries/vio.h @@ -150,8 +150,4 @@ enum viochar_rc { viochar_rc_ebusy = 1 }; -struct device; - -extern struct device *iSeries_vio_dev; - #endif /* _ASM_POWERPC_ISERIES_VIO_H */ -- cgit v1.2.3-70-g09d2 From b833b481c10cf591b15cc674948cc514e55d3b94 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 11 Oct 2007 14:57:26 +1000 Subject: [POWERPC] iSeries: Move detection of virtual cdroms Now we will only have entries in the device tree for the actual existing devices (including their OS/400 properties). This way viocd.c gets all the information about the devices from the device tree. Signed-off-by: Stephen Rothwell Acked-by: Jens Axboe Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/vio.c | 3 - arch/powerpc/platforms/iseries/Makefile | 2 +- arch/powerpc/platforms/iseries/dt.c | 4 - arch/powerpc/platforms/iseries/vio.c | 317 ++++++++++++++++++++++++++++++++ drivers/cdrom/viocd.c | 116 ++---------- include/asm-powerpc/iseries/vio.h | 24 +++ 6 files changed, 361 insertions(+), 105 deletions(-) create mode 100644 arch/powerpc/platforms/iseries/vio.c (limited to 'drivers') diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c index b7c9e44ef18..cb22a3557c4 100644 --- a/arch/powerpc/kernel/vio.c +++ b/arch/powerpc/kernel/vio.c @@ -247,9 +247,6 @@ static int __init vio_bus_init(void) int err; struct device_node *node_vroot; - if (firmware_has_feature(FW_FEATURE_ISERIES)) - iommu_vio_init(); - err = bus_register(&vio_bus_type); if (err) { printk(KERN_ERR "failed to register VIO bus\n"); diff --git a/arch/powerpc/platforms/iseries/Makefile b/arch/powerpc/platforms/iseries/Makefile index 60db509638f..a65f1b44abf 100644 --- a/arch/powerpc/platforms/iseries/Makefile +++ b/arch/powerpc/platforms/iseries/Makefile @@ -7,7 +7,7 @@ obj-y += hvlog.o hvlpconfig.o lpardata.o setup.o dt_mod.o mf.o lpevents.o \ hvcall.o proc.o htab.o iommu.o misc.o irq.o obj-$(CONFIG_PCI) += pci.o vpdinfo.o obj-$(CONFIG_SMP) += smp.o -obj-$(CONFIG_VIOPATH) += viopath.o +obj-$(CONFIG_VIOPATH) += viopath.o vio.o obj-$(CONFIG_MODULES) += ksyms.o quiet_cmd_dt_strings = DT_STR $@ diff --git a/arch/powerpc/platforms/iseries/dt.c b/arch/powerpc/platforms/iseries/dt.c index 9e8a334a518..84fcee15eb2 100644 --- a/arch/powerpc/platforms/iseries/dt.c +++ b/arch/powerpc/platforms/iseries/dt.c @@ -381,10 +381,6 @@ static void __init dt_vdevices(struct iseries_flat_dt *dt) dt_do_vdevice(dt, "viodasd", reg, i, device_type_block, "IBM,iSeries-viodasd", 1); reg += HVMAXARCHITECTEDVIRTUALDISKS; - - for (i = 0; i < HVMAXARCHITECTEDVIRTUALCDROMS; i++) - dt_do_vdevice(dt, "viocd", reg, i, device_type_block, - "IBM,iSeries-viocd", 1); reg += HVMAXARCHITECTEDVIRTUALCDROMS; for (i = 0; i < HVMAXARCHITECTEDVIRTUALTAPES; i++) diff --git a/arch/powerpc/platforms/iseries/vio.c b/arch/powerpc/platforms/iseries/vio.c new file mode 100644 index 00000000000..f61a97441c3 --- /dev/null +++ b/arch/powerpc/platforms/iseries/vio.c @@ -0,0 +1,317 @@ +/* + * Legacy iSeries specific vio initialisation + * that needs to be built in (not a module). + * + * © Copyright 2007 IBM Corporation + * Author: Stephen Rothwell + * Some parts collected from various other files + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define FIRST_VTY 0 +#define NUM_VTYS 1 +#define FIRST_VSCSI (FIRST_VTY + NUM_VTYS) +#define NUM_VSCSIS 1 +#define FIRST_VLAN (FIRST_VSCSI + NUM_VSCSIS) +#define NUM_VLANS HVMAXARCHITECTEDVIRTUALLANS +#define FIRST_VIODASD (FIRST_VLAN + NUM_VLANS) +#define NUM_VIODASDS HVMAXARCHITECTEDVIRTUALDISKS +#define FIRST_VIOCD (FIRST_VIODASD + NUM_VIODASDS) +#define NUM_VIOCDS HVMAXARCHITECTEDVIRTUALCDROMS +#define FIRST_VIOTAPE (FIRST_VIOCD + NUM_VIOCDS) +#define NUM_VIOTAPES HVMAXARCHITECTEDVIRTUALTAPES + +static struct property * __init new_property(const char *name, int length, + const void *value) +{ + struct property *np = kzalloc(sizeof(*np) + strlen(name) + 1 + length, + GFP_KERNEL); + + if (!np) + return NULL; + np->name = (char *)(np + 1); + np->value = np->name + strlen(name) + 1; + strcpy(np->name, name); + memcpy(np->value, value, length); + np->length = length; + return np; +} + +static void __init free_property(struct property *np) +{ + kfree(np); +} + +static struct device_node * __init new_node(const char *path, + struct device_node *parent) +{ + struct device_node *np = kzalloc(sizeof(*np), GFP_KERNEL); + + if (!np) + return NULL; + np->full_name = kmalloc(strlen(path) + 1, GFP_KERNEL); + if (!np->full_name) { + kfree(np); + return NULL; + } + strcpy(np->full_name, path); + of_node_set_flag(np, OF_DYNAMIC); + kref_init(&np->kref); + np->parent = of_node_get(parent); + return np; +} + +static void __init free_node(struct device_node *np) +{ + struct property *next; + struct property *prop; + + next = np->properties; + while (next) { + prop = next; + next = prop->next; + free_property(prop); + } + of_node_put(np->parent); + kfree(np->full_name); + kfree(np); +} + +static int __init add_string_property(struct device_node *np, const char *name, + const char *value) +{ + struct property *nprop = new_property(name, strlen(value) + 1, value); + + if (!nprop) + return 0; + prom_add_property(np, nprop); + return 1; +} + +static int __init add_raw_property(struct device_node *np, const char *name, + int length, const void *value) +{ + struct property *nprop = new_property(name, length, value); + + if (!nprop) + return 0; + prom_add_property(np, nprop); + return 1; +} + +struct viocd_waitevent { + struct completion com; + int rc; + u16 sub_result; +}; + +struct cdrom_info { + char rsrcname[10]; + char type[4]; + char model[3]; +}; + +static void __init handle_cd_event(struct HvLpEvent *event) +{ + struct viocdlpevent *bevent; + struct viocd_waitevent *pwe; + + if (!event) + /* Notification that a partition went away! */ + return; + + /* First, we should NEVER get an int here...only acks */ + if (hvlpevent_is_int(event)) { + printk(KERN_WARNING "handle_cd_event: got an unexpected int\n"); + if (hvlpevent_need_ack(event)) { + event->xRc = HvLpEvent_Rc_InvalidSubtype; + HvCallEvent_ackLpEvent(event); + } + return; + } + + bevent = (struct viocdlpevent *)event; + + switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) { + case viocdgetinfo: + pwe = (struct viocd_waitevent *)event->xCorrelationToken; + pwe->rc = event->xRc; + pwe->sub_result = bevent->sub_result; + complete(&pwe->com); + break; + + default: + printk(KERN_WARNING "handle_cd_event: " + "message with unexpected subtype %0x04X!\n", + event->xSubtype & VIOMINOR_SUBTYPE_MASK); + if (hvlpevent_need_ack(event)) { + event->xRc = HvLpEvent_Rc_InvalidSubtype; + HvCallEvent_ackLpEvent(event); + } + } +} + +static void __init get_viocd_info(struct device_node *vio_root) +{ + HvLpEvent_Rc hvrc; + u32 unit; + struct viocd_waitevent we; + struct cdrom_info *unitinfo; + dma_addr_t unitinfo_dmaaddr; + int ret; + + ret = viopath_open(viopath_hostLp, viomajorsubtype_cdio, 2); + if (ret) { + printk(KERN_WARNING + "get_viocd_info: error opening path to host partition %d\n", + viopath_hostLp); + return; + } + + /* Initialize our request handler */ + vio_setHandler(viomajorsubtype_cdio, handle_cd_event); + + unitinfo = iseries_hv_alloc( + sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS, + &unitinfo_dmaaddr, GFP_ATOMIC); + if (!unitinfo) { + printk(KERN_WARNING + "get_viocd_info: error allocating unitinfo\n"); + goto clear_handler; + } + + memset(unitinfo, 0, sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS); + + init_completion(&we.com); + + hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_cdio | viocdgetinfo, + HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst(viopath_hostLp), + viopath_targetinst(viopath_hostLp), + (u64)&we, VIOVERSION << 16, unitinfo_dmaaddr, 0, + sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS, 0); + if (hvrc != HvLpEvent_Rc_Good) { + printk(KERN_WARNING + "get_viocd_info: cdrom error sending event. rc %d\n", + (int)hvrc); + goto hv_free; + } + + wait_for_completion(&we.com); + + if (we.rc) { + printk(KERN_WARNING "get_viocd_info: bad rc %d:0x%04X\n", + we.rc, we.sub_result); + goto hv_free; + } + + for (unit = 0; (unit < HVMAXARCHITECTEDVIRTUALCDROMS) && + unitinfo[unit].rsrcname[0]; unit++) { + struct device_node *np; + char name[64]; + u32 reg = FIRST_VIOCD + unit; + + snprintf(name, sizeof(name), "/vdevice/viocd@%08x", reg); + np = new_node(name, vio_root); + if (!np) + goto hv_free; + if (!add_string_property(np, "name", "viocd") || + !add_string_property(np, "device_type", "block") || + !add_string_property(np, "compatible", + "IBM,iSeries-viocd") || + !add_raw_property(np, "reg", sizeof(reg), ®) || + !add_raw_property(np, "linux,unit_address", + sizeof(unit), &unit) || + !add_raw_property(np, "linux,vio_rsrcname", + sizeof(unitinfo[unit].rsrcname), + unitinfo[unit].rsrcname) || + !add_raw_property(np, "linux,vio_type", + sizeof(unitinfo[unit].type), + unitinfo[unit].type) || + !add_raw_property(np, "linux,vio_model", + sizeof(unitinfo[unit].model), + unitinfo[unit].model)) + goto node_free; + np->name = of_get_property(np, "name", NULL); + np->type = of_get_property(np, "device_type", NULL); + of_attach_node(np); +#ifdef CONFIG_PROC_DEVICETREE + if (vio_root->pde) { + struct proc_dir_entry *ent; + + ent = proc_mkdir(strrchr(np->full_name, '/') + 1, + vio_root->pde); + if (ent) + proc_device_tree_add_node(np, ent); + } +#endif + continue; + + node_free: + free_node(np); + break; + } + + hv_free: + iseries_hv_free(sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS, + unitinfo, unitinfo_dmaaddr); + clear_handler: + vio_clearHandler(viomajorsubtype_cdio); + viopath_close(viopath_hostLp, viomajorsubtype_cdio, 2); +} + +static int __init iseries_vio_init(void) +{ + struct device_node *vio_root; + + if (!firmware_has_feature(FW_FEATURE_ISERIES)) + return -ENODEV; + + iommu_vio_init(); + + vio_root = of_find_node_by_path("/vdevice"); + if (!vio_root) + return -ENODEV; + + if (viopath_hostLp == HvLpIndexInvalid) { + vio_set_hostlp(); + /* If we don't have a host, bail out */ + if (viopath_hostLp == HvLpIndexInvalid) + goto put_node; + } + + get_viocd_info(vio_root); + + return 0; + + put_node: + of_node_put(vio_root); + return -ENODEV; +} +arch_initcall(iseries_vio_init); diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c index c081e5400ce..880b5dce3a6 100644 --- a/drivers/cdrom/viocd.c +++ b/drivers/cdrom/viocd.c @@ -56,30 +56,6 @@ #define VIOCD_KERN_WARNING KERN_WARNING "viocd: " #define VIOCD_KERN_INFO KERN_INFO "viocd: " -struct viocdlpevent { - struct HvLpEvent event; - u32 reserved; - u16 version; - u16 sub_result; - u16 disk; - u16 flags; - u32 token; - u64 offset; /* On open, max number of disks */ - u64 len; /* On open, size of the disk */ - u32 block_size; /* Only set on open */ - u32 media_size; /* Only set on open */ -}; - -enum viocdsubtype { - viocdopen = 0x0001, - viocdclose = 0x0002, - viocdread = 0x0003, - viocdwrite = 0x0004, - viocdlockdoor = 0x0005, - viocdgetinfo = 0x0006, - viocdcheck = 0x0007 -}; - /* * Should probably make this a module parameter....sigh */ @@ -131,17 +107,13 @@ static struct capability_entry capability_table[] __initdata = { /* These are our internal structures for keeping track of devices */ static int viocd_numdev; -struct cdrom_info { - char rsrcname[10]; - char type[4]; - char model[3]; -}; - struct disk_info { struct gendisk *viocd_disk; struct cdrom_device_info viocd_info; struct device *dev; - struct cdrom_info unitinfo; + const char *rsrcname; + const char *type; + const char *model; }; static struct disk_info viocd_diskinfo[VIOCD_MAX_CD]; @@ -159,9 +131,9 @@ static int proc_viocd_show(struct seq_file *m, void *v) for (i = 0; i < viocd_numdev; i++) { seq_printf(m, "viocd device %d is iSeries resource %10.10s" "type %4.4s, model %3.3s\n", - i, viocd_diskinfo[i].unitinfo.rsrcname, - viocd_diskinfo[i].unitinfo.type, - viocd_diskinfo[i].unitinfo.model); + i, viocd_diskinfo[i].rsrcname, + viocd_diskinfo[i].type, + viocd_diskinfo[i].model); } return 0; } @@ -211,61 +183,6 @@ struct block_device_operations viocd_fops = { .media_changed = viocd_blk_media_changed, }; -/* Get info on CD devices from OS/400 */ -static void __init get_viocd_info(void) -{ - HvLpEvent_Rc hvrc; - int i; - struct viocd_waitevent we; - struct cdrom_info *viocd_unitinfo; - dma_addr_t unitinfo_dmaaddr; - - viocd_unitinfo = iseries_hv_alloc( - sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, - &unitinfo_dmaaddr, GFP_ATOMIC); - if (viocd_unitinfo == NULL) { - printk(VIOCD_KERN_WARNING "error allocating unitinfo\n"); - return; - } - - memset(viocd_unitinfo, 0, sizeof(*viocd_unitinfo) * VIOCD_MAX_CD); - - init_completion(&we.com); - - hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, - HvLpEvent_Type_VirtualIo, - viomajorsubtype_cdio | viocdgetinfo, - HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, - viopath_sourceinst(viopath_hostLp), - viopath_targetinst(viopath_hostLp), - (u64)&we, VIOVERSION << 16, unitinfo_dmaaddr, 0, - sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, 0); - if (hvrc != HvLpEvent_Rc_Good) { - printk(VIOCD_KERN_WARNING "cdrom error sending event. rc %d\n", - (int)hvrc); - goto error_ret; - } - - wait_for_completion(&we.com); - - if (we.rc) { - const struct vio_error_entry *err = - vio_lookup_rc(viocd_err_table, we.sub_result); - printk(VIOCD_KERN_WARNING "bad rc %d:0x%04X on getinfo: %s\n", - we.rc, we.sub_result, err->msg); - goto error_ret; - } - - for (i = 0; (i < VIOCD_MAX_CD) && viocd_unitinfo[i].rsrcname[0]; i++) { - viocd_diskinfo[viocd_numdev].unitinfo = viocd_unitinfo[i]; - viocd_numdev++; - } - -error_ret: - iseries_hv_free(sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, - viocd_unitinfo, unitinfo_dmaaddr); -} - static int viocd_open(struct cdrom_device_info *cdi, int purpose) { struct disk_info *diskinfo = cdi->handle; @@ -576,7 +493,6 @@ static void vio_handle_cd_event(struct HvLpEvent *event) bevent->block_size / 512); } /* FALLTHROUGH !! */ - case viocdgetinfo: case viocdlockdoor: pwe = (struct viocd_waitevent *)event->xCorrelationToken; return_complete: @@ -660,22 +576,30 @@ static int viocd_probe(struct vio_dev *vdev, const struct vio_device_id *id) int deviceno; struct disk_info *d; struct cdrom_device_info *c; - struct cdrom_info *ci; struct request_queue *q; + struct device_node *node = vdev->dev.archdata.of_node; deviceno = vdev->unit_address; - if (deviceno >= viocd_numdev) + if (deviceno > VIOCD_MAX_CD) return -ENODEV; + if (!node) + return -ENODEV; + + if (deviceno >= viocd_numdev) + viocd_numdev = deviceno + 1; d = &viocd_diskinfo[deviceno]; + d->rsrcname = of_get_property(node, "linux,vio_rsrcname", NULL); + d->type = of_get_property(node, "linux,vio_type", NULL); + d->model = of_get_property(node, "linux,vio_model", NULL); + c = &d->viocd_info; - ci = &d->unitinfo; c->ops = &viocd_dops; c->speed = 4; c->capacity = 1; c->handle = d; - c->mask = ~find_capability(ci->type); + c->mask = ~find_capability(d->type); sprintf(c->name, VIOCD_DEVICE "%c", 'a' + deviceno); if (register_cdrom(c) != 0) { @@ -685,7 +609,7 @@ static int viocd_probe(struct vio_dev *vdev, const struct vio_device_id *id) } printk(VIOCD_KERN_INFO "cd %s is iSeries resource %10.10s " "type %4.4s, model %3.3s\n", - c->name, ci->rsrcname, ci->type, ci->model); + c->name, d->rsrcname, d->type, d->model); q = blk_init_queue(do_viocd_request, &viocd_reqlock); if (q == NULL) { printk(VIOCD_KERN_WARNING "Cannot allocate queue for %s!\n", @@ -794,8 +718,6 @@ static int __init viocd_init(void) /* Initialize our request handler */ vio_setHandler(viomajorsubtype_cdio, vio_handle_cd_event); - get_viocd_info(); - spin_lock_init(&viocd_reqlock); ret = vio_register_driver(&viocd_driver); diff --git a/include/asm-powerpc/iseries/vio.h b/include/asm-powerpc/iseries/vio.h index 5a5cd0f0c09..e5a405b8d46 100644 --- a/include/asm-powerpc/iseries/vio.h +++ b/include/asm-powerpc/iseries/vio.h @@ -51,6 +51,30 @@ */ #define VIO_MAX_SUBTYPES 8 +struct viocdlpevent { + struct HvLpEvent event; + u32 reserved; + u16 version; + u16 sub_result; + u16 disk; + u16 flags; + u32 token; + u64 offset; /* On open, max number of disks */ + u64 len; /* On open, size of the disk */ + u32 block_size; /* Only set on open */ + u32 media_size; /* Only set on open */ +}; + +enum viocdsubtype { + viocdopen = 0x0001, + viocdclose = 0x0002, + viocdread = 0x0003, + viocdwrite = 0x0004, + viocdlockdoor = 0x0005, + viocdgetinfo = 0x0006, + viocdcheck = 0x0007 +}; + /* * Each subtype can register a handler to process their events. * The handler must have this interface. -- cgit v1.2.3-70-g09d2 From 7465ce0db310d2fa29f721da7e3aacd1dad7090f Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 11 Oct 2007 14:58:31 +1000 Subject: [POWERPC] iSeries: Move detection of virtual tapes Now we will only have entries in the device tree for the actual existing devices (including their OS/400 properties). This way viotape.c gets all the information about the devices from the device tree. Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/iseries/dt.c | 7 -- arch/powerpc/platforms/iseries/vio.c | 149 +++++++++++++++++++++++++++++++---- drivers/char/viotape.c | 124 +++++------------------------ include/asm-powerpc/iseries/vio.h | 41 ++++++++++ 4 files changed, 192 insertions(+), 129 deletions(-) (limited to 'drivers') diff --git a/arch/powerpc/platforms/iseries/dt.c b/arch/powerpc/platforms/iseries/dt.c index 84fcee15eb2..2e4ad6b3450 100644 --- a/arch/powerpc/platforms/iseries/dt.c +++ b/arch/powerpc/platforms/iseries/dt.c @@ -73,7 +73,6 @@ static char __initdata device_type_memory[] = "memory"; static char __initdata device_type_serial[] = "serial"; static char __initdata device_type_network[] = "network"; static char __initdata device_type_block[] = "block"; -static char __initdata device_type_byte[] = "byte"; static char __initdata device_type_pci[] = "pci"; static char __initdata device_type_vdevice[] = "vdevice"; static char __initdata device_type_vscsi[] = "vscsi"; @@ -380,12 +379,6 @@ static void __init dt_vdevices(struct iseries_flat_dt *dt) for (i = 0; i < HVMAXARCHITECTEDVIRTUALDISKS; i++) dt_do_vdevice(dt, "viodasd", reg, i, device_type_block, "IBM,iSeries-viodasd", 1); - reg += HVMAXARCHITECTEDVIRTUALDISKS; - reg += HVMAXARCHITECTEDVIRTUALCDROMS; - - for (i = 0; i < HVMAXARCHITECTEDVIRTUALTAPES; i++) - dt_do_vdevice(dt, "viotape", reg, i, device_type_byte, - "IBM,iSeries-viotape", 1); dt_end_node(dt); } diff --git a/arch/powerpc/platforms/iseries/vio.c b/arch/powerpc/platforms/iseries/vio.c index f61a97441c3..a4cc990a26a 100644 --- a/arch/powerpc/platforms/iseries/vio.c +++ b/arch/powerpc/platforms/iseries/vio.c @@ -45,6 +45,18 @@ #define FIRST_VIOTAPE (FIRST_VIOCD + NUM_VIOCDS) #define NUM_VIOTAPES HVMAXARCHITECTEDVIRTUALTAPES +struct vio_waitevent { + struct completion com; + int rc; + u16 sub_result; +}; + +struct vio_resource { + char rsrcname[10]; + char type[4]; + char model[3]; +}; + static struct property * __init new_property(const char *name, int length, const void *value) { @@ -123,22 +135,10 @@ static int __init add_raw_property(struct device_node *np, const char *name, return 1; } -struct viocd_waitevent { - struct completion com; - int rc; - u16 sub_result; -}; - -struct cdrom_info { - char rsrcname[10]; - char type[4]; - char model[3]; -}; - static void __init handle_cd_event(struct HvLpEvent *event) { struct viocdlpevent *bevent; - struct viocd_waitevent *pwe; + struct vio_waitevent *pwe; if (!event) /* Notification that a partition went away! */ @@ -158,7 +158,7 @@ static void __init handle_cd_event(struct HvLpEvent *event) switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) { case viocdgetinfo: - pwe = (struct viocd_waitevent *)event->xCorrelationToken; + pwe = (struct vio_waitevent *)event->xCorrelationToken; pwe->rc = event->xRc; pwe->sub_result = bevent->sub_result; complete(&pwe->com); @@ -179,8 +179,8 @@ static void __init get_viocd_info(struct device_node *vio_root) { HvLpEvent_Rc hvrc; u32 unit; - struct viocd_waitevent we; - struct cdrom_info *unitinfo; + struct vio_waitevent we; + struct vio_resource *unitinfo; dma_addr_t unitinfo_dmaaddr; int ret; @@ -286,6 +286,122 @@ static void __init get_viocd_info(struct device_node *vio_root) viopath_close(viopath_hostLp, viomajorsubtype_cdio, 2); } +/* Handle interrupt events for tape */ +static void __init handle_tape_event(struct HvLpEvent *event) +{ + struct vio_waitevent *we; + struct viotapelpevent *tevent = (struct viotapelpevent *)event; + + if (event == NULL) + /* Notification that a partition went away! */ + return; + + we = (struct vio_waitevent *)event->xCorrelationToken; + switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) { + case viotapegetinfo: + we->rc = tevent->sub_type_result; + complete(&we->com); + break; + default: + printk(KERN_WARNING "handle_tape_event: weird ack\n"); + } +} + +static void __init get_viotape_info(struct device_node *vio_root) +{ + HvLpEvent_Rc hvrc; + u32 unit; + struct vio_resource *unitinfo; + dma_addr_t unitinfo_dmaaddr; + size_t len = sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALTAPES; + struct vio_waitevent we; + int ret; + + ret = viopath_open(viopath_hostLp, viomajorsubtype_tape, 2); + if (ret) { + printk(KERN_WARNING "get_viotape_info: " + "error on viopath_open to hostlp %d\n", ret); + return; + } + + vio_setHandler(viomajorsubtype_tape, handle_tape_event); + + unitinfo = iseries_hv_alloc(len, &unitinfo_dmaaddr, GFP_ATOMIC); + if (!unitinfo) + goto clear_handler; + + memset(unitinfo, 0, len); + + hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_tape | viotapegetinfo, + HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst(viopath_hostLp), + viopath_targetinst(viopath_hostLp), + (u64)(unsigned long)&we, VIOVERSION << 16, + unitinfo_dmaaddr, len, 0, 0); + if (hvrc != HvLpEvent_Rc_Good) { + printk(KERN_WARNING "get_viotape_info: hv error on op %d\n", + (int)hvrc); + goto hv_free; + } + + wait_for_completion(&we.com); + + for (unit = 0; (unit < HVMAXARCHITECTEDVIRTUALTAPES) && + unitinfo[unit].rsrcname[0]; unit++) { + struct device_node *np; + char name[64]; + u32 reg = FIRST_VIOTAPE + unit; + + snprintf(name, sizeof(name), "/vdevice/viotape@%08x", reg); + np = new_node(name, vio_root); + if (!np) + goto hv_free; + if (!add_string_property(np, "name", "viotape") || + !add_string_property(np, "device_type", "byte") || + !add_string_property(np, "compatible", + "IBM,iSeries-viotape") || + !add_raw_property(np, "reg", sizeof(reg), ®) || + !add_raw_property(np, "linux,unit_address", + sizeof(unit), &unit) || + !add_raw_property(np, "linux,vio_rsrcname", + sizeof(unitinfo[unit].rsrcname), + unitinfo[unit].rsrcname) || + !add_raw_property(np, "linux,vio_type", + sizeof(unitinfo[unit].type), + unitinfo[unit].type) || + !add_raw_property(np, "linux,vio_model", + sizeof(unitinfo[unit].model), + unitinfo[unit].model)) + goto node_free; + np->name = of_get_property(np, "name", NULL); + np->type = of_get_property(np, "device_type", NULL); + of_attach_node(np); +#ifdef CONFIG_PROC_DEVICETREE + if (vio_root->pde) { + struct proc_dir_entry *ent; + + ent = proc_mkdir(strrchr(np->full_name, '/') + 1, + vio_root->pde); + if (ent) + proc_device_tree_add_node(np, ent); + } +#endif + continue; + + node_free: + free_node(np); + break; + } + + hv_free: + iseries_hv_free(len, unitinfo, unitinfo_dmaaddr); + clear_handler: + vio_clearHandler(viomajorsubtype_tape); + viopath_close(viopath_hostLp, viomajorsubtype_tape, 2); +} + static int __init iseries_vio_init(void) { struct device_node *vio_root; @@ -307,6 +423,7 @@ static int __init iseries_vio_init(void) } get_viocd_info(vio_root); + get_viotape_info(vio_root); return 0; diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c index 064c0919521..f1d60f0cef8 100644 --- a/drivers/char/viotape.c +++ b/drivers/char/viotape.c @@ -92,47 +92,6 @@ struct viot_devinfo_struct { #define VIOTAPOP_SETPART 14 #define VIOTAPOP_UNLOAD 15 -struct viotapelpevent { - struct HvLpEvent event; - u32 reserved; - u16 version; - u16 sub_type_result; - u16 tape; - u16 flags; - u32 token; - u64 len; - union { - struct { - u32 tape_op; - u32 count; - } op; - struct { - u32 type; - u32 resid; - u32 dsreg; - u32 gstat; - u32 erreg; - u32 file_no; - u32 block_no; - } get_status; - struct { - u32 block_no; - } get_pos; - } u; -}; - -enum viotapesubtype { - viotapeopen = 0x0001, - viotapeclose = 0x0002, - viotaperead = 0x0003, - viotapewrite = 0x0004, - viotapegetinfo = 0x0005, - viotapeop = 0x0006, - viotapegetpos = 0x0007, - viotapesetpos = 0x0008, - viotapegetstatus = 0x0009 -}; - enum viotaperc { viotape_InvalidRange = 0x0601, viotape_InvalidToken = 0x0602, @@ -223,14 +182,11 @@ static const struct vio_error_entry viotape_err_table[] = { #define VIOT_WRITING 2 /* Our info on the tapes */ -struct tape_descr { - char rsrcname[10]; - char type[4]; - char model[3]; -}; - -static struct tape_descr *viotape_unitinfo; -static dma_addr_t viotape_unitinfo_token; +static struct { + const char *rsrcname; + const char *type; + const char *model; +} viotape_unitinfo[VIOTAPE_MAX_TAPE]; static struct mtget viomtget[VIOTAPE_MAX_TAPE]; @@ -381,53 +337,6 @@ int tape_rc_to_errno(int tape_rc, char *operation, int tapeno) return -err->errno; } -/* Get info on all tapes from OS/400 */ -static int get_viotape_info(void) -{ - HvLpEvent_Rc hvrc; - int i; - size_t len = sizeof(*viotape_unitinfo) * VIOTAPE_MAX_TAPE; - struct op_struct *op = get_op_struct(); - - if (op == NULL) - return -ENOMEM; - - viotape_unitinfo = iseries_hv_alloc(len, &viotape_unitinfo_token, - GFP_ATOMIC); - if (viotape_unitinfo == NULL) { - free_op_struct(op); - return -ENOMEM; - } - - memset(viotape_unitinfo, 0, len); - - hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, - HvLpEvent_Type_VirtualIo, - viomajorsubtype_tape | viotapegetinfo, - HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, - viopath_sourceinst(viopath_hostLp), - viopath_targetinst(viopath_hostLp), - (u64) (unsigned long) op, VIOVERSION << 16, - viotape_unitinfo_token, len, 0, 0); - if (hvrc != HvLpEvent_Rc_Good) { - printk(VIOTAPE_KERN_WARN "hv error on op %d\n", - (int)hvrc); - free_op_struct(op); - return -EIO; - } - - wait_for_completion(&op->com); - - free_op_struct(op); - - for (i = 0; - ((i < VIOTAPE_MAX_TAPE) && (viotape_unitinfo[i].rsrcname[0])); - i++) - viotape_numdev++; - return 0; -} - - /* Write */ static ssize_t viotap_write(struct file *file, const char *buf, size_t count, loff_t * ppos) @@ -899,7 +808,6 @@ static void vioHandleTapeEvent(struct HvLpEvent *event) tapeminor = event->xSubtype & VIOMINOR_SUBTYPE_MASK; op = (struct op_struct *)event->xCorrelationToken; switch (tapeminor) { - case viotapegetinfo: case viotapeopen: case viotapeclose: op->rc = tevent->sub_type_result; @@ -942,11 +850,23 @@ static int viotape_probe(struct vio_dev *vdev, const struct vio_device_id *id) { int i = vdev->unit_address; int j; + struct device_node *node = vdev->dev.archdata.of_node; - if (i >= viotape_numdev) + if (i > VIOTAPE_MAX_TAPE) + return -ENODEV; + if (!node) return -ENODEV; + if (i >= viotape_numdev) + viotape_numdev = i + 1; + tape_device[i] = &vdev->dev; + viotape_unitinfo[i].rsrcname = of_get_property(node, + "linux,vio_rsrcname", NULL); + viotape_unitinfo[i].type = of_get_property(node, "linux,vio_type", + NULL); + viotape_unitinfo[i].model = of_get_property(node, "linux,vio_model", + NULL); state[i].cur_part = 0; for (j = 0; j < MAX_PARTITIONS; ++j) @@ -1044,11 +964,6 @@ int __init viotap_init(void) goto unreg_chrdev; } - if ((ret = get_viotape_info()) < 0) { - printk(VIOTAPE_KERN_WARN "Unable to obtain virtual device information"); - goto unreg_class; - } - ret = vio_register_driver(&viotape_driver); if (ret) goto unreg_class; @@ -1102,9 +1017,6 @@ static void __exit viotap_exit(void) vio_unregister_driver(&viotape_driver); class_destroy(tape_class); unregister_chrdev(VIOTAPE_MAJOR, "viotape"); - if (viotape_unitinfo) - iseries_hv_free(sizeof(viotape_unitinfo[0]) * VIOTAPE_MAX_TAPE, - viotape_unitinfo, viotape_unitinfo_token); viopath_close(viopath_hostLp, viomajorsubtype_tape, VIOTAPE_MAXREQ + 2); vio_clearHandler(viomajorsubtype_tape); clear_op_struct_pool(); diff --git a/include/asm-powerpc/iseries/vio.h b/include/asm-powerpc/iseries/vio.h index e5a405b8d46..2555dfd6fac 100644 --- a/include/asm-powerpc/iseries/vio.h +++ b/include/asm-powerpc/iseries/vio.h @@ -75,6 +75,47 @@ enum viocdsubtype { viocdcheck = 0x0007 }; +struct viotapelpevent { + struct HvLpEvent event; + u32 reserved; + u16 version; + u16 sub_type_result; + u16 tape; + u16 flags; + u32 token; + u64 len; + union { + struct { + u32 tape_op; + u32 count; + } op; + struct { + u32 type; + u32 resid; + u32 dsreg; + u32 gstat; + u32 erreg; + u32 file_no; + u32 block_no; + } get_status; + struct { + u32 block_no; + } get_pos; + } u; +}; + +enum viotapesubtype { + viotapeopen = 0x0001, + viotapeclose = 0x0002, + viotaperead = 0x0003, + viotapewrite = 0x0004, + viotapegetinfo = 0x0005, + viotapeop = 0x0006, + viotapegetpos = 0x0007, + viotapesetpos = 0x0008, + viotapegetstatus = 0x0009 +}; + /* * Each subtype can register a handler to process their events. * The handler must have this interface. -- cgit v1.2.3-70-g09d2 From 8251b4c481bca72568e9c1042ea11189838e5f6d Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 11 Oct 2007 14:59:54 +1000 Subject: [POWERPC] iSeries: Move viodasd probing This way we only have entries in the device tree for disks that actually exist. A slight complication is that disks may be attached to LPARs at runtime. Signed-off-by: Stephen Rothwell Acked-by: Jens Axboe Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/iseries/dt.c | 6 - arch/powerpc/platforms/iseries/vio.c | 301 ++++++++++++++++++++++++----------- drivers/block/viodasd.c | 77 +++------ include/asm-powerpc/iseries/vio.h | 47 ++++++ 4 files changed, 282 insertions(+), 149 deletions(-) (limited to 'drivers') diff --git a/arch/powerpc/platforms/iseries/dt.c b/arch/powerpc/platforms/iseries/dt.c index 2e4ad6b3450..4543c4bc3a5 100644 --- a/arch/powerpc/platforms/iseries/dt.c +++ b/arch/powerpc/platforms/iseries/dt.c @@ -72,7 +72,6 @@ static char __initdata device_type_cpu[] = "cpu"; static char __initdata device_type_memory[] = "memory"; static char __initdata device_type_serial[] = "serial"; static char __initdata device_type_network[] = "network"; -static char __initdata device_type_block[] = "block"; static char __initdata device_type_pci[] = "pci"; static char __initdata device_type_vdevice[] = "vdevice"; static char __initdata device_type_vscsi[] = "vscsi"; @@ -374,11 +373,6 @@ static void __init dt_vdevices(struct iseries_flat_dt *dt) dt_end_node(dt); } - reg += HVMAXARCHITECTEDVIRTUALLANS; - - for (i = 0; i < HVMAXARCHITECTEDVIRTUALDISKS; i++) - dt_do_vdevice(dt, "viodasd", reg, i, device_type_block, - "IBM,iSeries-viodasd", 1); dt_end_node(dt); } diff --git a/arch/powerpc/platforms/iseries/vio.c b/arch/powerpc/platforms/iseries/vio.c index a4cc990a26a..910b00b4703 100644 --- a/arch/powerpc/platforms/iseries/vio.c +++ b/arch/powerpc/platforms/iseries/vio.c @@ -25,8 +25,10 @@ #include #include #include +#include #include +#include #include #include #include @@ -57,7 +59,7 @@ struct vio_resource { char model[3]; }; -static struct property * __init new_property(const char *name, int length, +static struct property *new_property(const char *name, int length, const void *value) { struct property *np = kzalloc(sizeof(*np) + strlen(name) + 1 + length, @@ -78,7 +80,7 @@ static void __init free_property(struct property *np) kfree(np); } -static struct device_node * __init new_node(const char *path, +static struct device_node *new_node(const char *path, struct device_node *parent) { struct device_node *np = kzalloc(sizeof(*np), GFP_KERNEL); @@ -97,7 +99,7 @@ static struct device_node * __init new_node(const char *path, return np; } -static void __init free_node(struct device_node *np) +static void free_node(struct device_node *np) { struct property *next; struct property *prop; @@ -113,7 +115,7 @@ static void __init free_node(struct device_node *np) kfree(np); } -static int __init add_string_property(struct device_node *np, const char *name, +static int add_string_property(struct device_node *np, const char *name, const char *value) { struct property *nprop = new_property(name, strlen(value) + 1, value); @@ -124,7 +126,7 @@ static int __init add_string_property(struct device_node *np, const char *name, return 1; } -static int __init add_raw_property(struct device_node *np, const char *name, +static int add_raw_property(struct device_node *np, const char *name, int length, const void *value) { struct property *nprop = new_property(name, length, value); @@ -135,6 +137,201 @@ static int __init add_raw_property(struct device_node *np, const char *name, return 1; } +static struct device_node *do_device_node(struct device_node *parent, + const char *name, u32 reg, u32 unit, const char *type, + const char *compat, struct vio_resource *res) +{ + struct device_node *np; + char path[32]; + + snprintf(path, sizeof(path), "/vdevice/%s@%08x", name, reg); + np = new_node(path, parent); + if (!np) + return NULL; + if (!add_string_property(np, "name", name) || + !add_string_property(np, "device_type", type) || + !add_string_property(np, "compatible", compat) || + !add_raw_property(np, "reg", sizeof(reg), ®) || + !add_raw_property(np, "linux,unit_address", + sizeof(unit), &unit)) { + goto node_free; + } + if (res) { + if (!add_raw_property(np, "linux,vio_rsrcname", + sizeof(res->rsrcname), res->rsrcname) || + !add_raw_property(np, "linux,vio_type", + sizeof(res->type), res->type) || + !add_raw_property(np, "linux,vio_model", + sizeof(res->model), res->model)) + goto node_free; + } + np->name = of_get_property(np, "name", NULL); + np->type = of_get_property(np, "device_type", NULL); + of_attach_node(np); +#ifdef CONFIG_PROC_DEVICETREE + if (parent->pde) { + struct proc_dir_entry *ent; + + ent = proc_mkdir(strrchr(np->full_name, '/') + 1, parent->pde); + if (ent) + proc_device_tree_add_node(np, ent); + } +#endif + return np; + + node_free: + free_node(np); + return NULL; +} + +/* + * This is here so that we can dynamically add viodasd + * devices without exposing all the above infrastructure. + */ +struct vio_dev *vio_create_viodasd(u32 unit) +{ + struct device_node *vio_root; + struct device_node *np; + struct vio_dev *vdev = NULL; + + vio_root = of_find_node_by_path("/vdevice"); + if (!vio_root) + return NULL; + np = do_device_node(vio_root, "viodasd", FIRST_VIODASD + unit, unit, + "block", "IBM,iSeries-viodasd", NULL); + of_node_put(vio_root); + if (np) { + vdev = vio_register_device_node(np); + if (!vdev) + free_node(np); + } + return vdev; +} +EXPORT_SYMBOL_GPL(vio_create_viodasd); + +static void __init handle_block_event(struct HvLpEvent *event) +{ + struct vioblocklpevent *bevent = (struct vioblocklpevent *)event; + struct vio_waitevent *pwe; + + if (event == NULL) + /* Notification that a partition went away! */ + return; + /* First, we should NEVER get an int here...only acks */ + if (hvlpevent_is_int(event)) { + printk(KERN_WARNING "handle_viod_request: " + "Yikes! got an int in viodasd event handler!\n"); + if (hvlpevent_need_ack(event)) { + event->xRc = HvLpEvent_Rc_InvalidSubtype; + HvCallEvent_ackLpEvent(event); + } + return; + } + + switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) { + case vioblockopen: + /* + * Handle a response to an open request. We get all the + * disk information in the response, so update it. The + * correlation token contains a pointer to a waitevent + * structure that has a completion in it. update the + * return code in the waitevent structure and post the + * completion to wake up the guy who sent the request + */ + pwe = (struct vio_waitevent *)event->xCorrelationToken; + pwe->rc = event->xRc; + pwe->sub_result = bevent->sub_result; + complete(&pwe->com); + break; + case vioblockclose: + break; + default: + printk(KERN_WARNING "handle_viod_request: unexpected subtype!"); + if (hvlpevent_need_ack(event)) { + event->xRc = HvLpEvent_Rc_InvalidSubtype; + HvCallEvent_ackLpEvent(event); + } + } +} + +static void __init probe_disk(struct device_node *vio_root, u32 unit) +{ + HvLpEvent_Rc hvrc; + struct vio_waitevent we; + u16 flags = 0; + +retry: + init_completion(&we.com); + + /* Send the open event to OS/400 */ + hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_blockio | vioblockopen, + HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst(viopath_hostLp), + viopath_targetinst(viopath_hostLp), + (u64)(unsigned long)&we, VIOVERSION << 16, + ((u64)unit << 48) | ((u64)flags<< 32), + 0, 0, 0); + if (hvrc != 0) { + printk(KERN_WARNING "probe_disk: bad rc on HV open %d\n", + (int)hvrc); + return; + } + + wait_for_completion(&we.com); + + if (we.rc != 0) { + if (flags != 0) + return; + /* try again with read only flag set */ + flags = vioblockflags_ro; + goto retry; + } + + /* Send the close event to OS/400. We DON'T expect a response */ + hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_blockio | vioblockclose, + HvLpEvent_AckInd_NoAck, HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst(viopath_hostLp), + viopath_targetinst(viopath_hostLp), + 0, VIOVERSION << 16, + ((u64)unit << 48) | ((u64)flags << 32), + 0, 0, 0); + if (hvrc != 0) { + printk(KERN_WARNING "probe_disk: " + "bad rc sending event to OS/400 %d\n", (int)hvrc); + return; + } + + do_device_node(vio_root, "viodasd", FIRST_VIODASD + unit, unit, + "block", "IBM,iSeries-viodasd", NULL); +} + +static void __init get_viodasd_info(struct device_node *vio_root) +{ + int rc; + u32 unit; + + rc = viopath_open(viopath_hostLp, viomajorsubtype_blockio, 2); + if (rc) { + printk(KERN_WARNING "get_viodasd_info: " + "error opening path to host partition %d\n", + viopath_hostLp); + return; + } + + /* Initialize our request handler */ + vio_setHandler(viomajorsubtype_blockio, handle_block_event); + + for (unit = 0; unit < HVMAXARCHITECTEDVIRTUALDISKS; unit++) + probe_disk(vio_root, unit); + + vio_clearHandler(viomajorsubtype_blockio); + viopath_close(viopath_hostLp, viomajorsubtype_blockio, 2); +} + static void __init handle_cd_event(struct HvLpEvent *event) { struct viocdlpevent *bevent; @@ -233,49 +430,9 @@ static void __init get_viocd_info(struct device_node *vio_root) for (unit = 0; (unit < HVMAXARCHITECTEDVIRTUALCDROMS) && unitinfo[unit].rsrcname[0]; unit++) { - struct device_node *np; - char name[64]; - u32 reg = FIRST_VIOCD + unit; - - snprintf(name, sizeof(name), "/vdevice/viocd@%08x", reg); - np = new_node(name, vio_root); - if (!np) - goto hv_free; - if (!add_string_property(np, "name", "viocd") || - !add_string_property(np, "device_type", "block") || - !add_string_property(np, "compatible", - "IBM,iSeries-viocd") || - !add_raw_property(np, "reg", sizeof(reg), ®) || - !add_raw_property(np, "linux,unit_address", - sizeof(unit), &unit) || - !add_raw_property(np, "linux,vio_rsrcname", - sizeof(unitinfo[unit].rsrcname), - unitinfo[unit].rsrcname) || - !add_raw_property(np, "linux,vio_type", - sizeof(unitinfo[unit].type), - unitinfo[unit].type) || - !add_raw_property(np, "linux,vio_model", - sizeof(unitinfo[unit].model), - unitinfo[unit].model)) - goto node_free; - np->name = of_get_property(np, "name", NULL); - np->type = of_get_property(np, "device_type", NULL); - of_attach_node(np); -#ifdef CONFIG_PROC_DEVICETREE - if (vio_root->pde) { - struct proc_dir_entry *ent; - - ent = proc_mkdir(strrchr(np->full_name, '/') + 1, - vio_root->pde); - if (ent) - proc_device_tree_add_node(np, ent); - } -#endif - continue; - - node_free: - free_node(np); - break; + if (!do_device_node(vio_root, "viocd", FIRST_VIOCD + unit, unit, + "block", "IBM,iSeries-viocd", &unitinfo[unit])) + break; } hv_free: @@ -350,49 +507,10 @@ static void __init get_viotape_info(struct device_node *vio_root) for (unit = 0; (unit < HVMAXARCHITECTEDVIRTUALTAPES) && unitinfo[unit].rsrcname[0]; unit++) { - struct device_node *np; - char name[64]; - u32 reg = FIRST_VIOTAPE + unit; - - snprintf(name, sizeof(name), "/vdevice/viotape@%08x", reg); - np = new_node(name, vio_root); - if (!np) - goto hv_free; - if (!add_string_property(np, "name", "viotape") || - !add_string_property(np, "device_type", "byte") || - !add_string_property(np, "compatible", - "IBM,iSeries-viotape") || - !add_raw_property(np, "reg", sizeof(reg), ®) || - !add_raw_property(np, "linux,unit_address", - sizeof(unit), &unit) || - !add_raw_property(np, "linux,vio_rsrcname", - sizeof(unitinfo[unit].rsrcname), - unitinfo[unit].rsrcname) || - !add_raw_property(np, "linux,vio_type", - sizeof(unitinfo[unit].type), - unitinfo[unit].type) || - !add_raw_property(np, "linux,vio_model", - sizeof(unitinfo[unit].model), - unitinfo[unit].model)) - goto node_free; - np->name = of_get_property(np, "name", NULL); - np->type = of_get_property(np, "device_type", NULL); - of_attach_node(np); -#ifdef CONFIG_PROC_DEVICETREE - if (vio_root->pde) { - struct proc_dir_entry *ent; - - ent = proc_mkdir(strrchr(np->full_name, '/') + 1, - vio_root->pde); - if (ent) - proc_device_tree_add_node(np, ent); - } -#endif - continue; - - node_free: - free_node(np); - break; + if (!do_device_node(vio_root, "viotape", FIRST_VIOTAPE + unit, + unit, "byte", "IBM,iSeries-viotape", + &unitinfo[unit])) + break; } hv_free: @@ -422,6 +540,7 @@ static int __init iseries_vio_init(void) goto put_node; } + get_viodasd_info(vio_root); get_viocd_info(vio_root); get_viotape_info(vio_root); diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c index af3969a9c96..e824b672e05 100644 --- a/drivers/block/viodasd.c +++ b/drivers/block/viodasd.c @@ -74,53 +74,9 @@ enum { static DEFINE_SPINLOCK(viodasd_spinlock); #define VIOMAXREQ 16 -#define VIOMAXBLOCKDMA 12 #define DEVICE_NO(cell) ((struct viodasd_device *)(cell) - &viodasd_devices[0]) -struct open_data { - u64 disk_size; - u16 max_disk; - u16 cylinders; - u16 tracks; - u16 sectors; - u16 bytes_per_sector; -}; - -struct rw_data { - u64 offset; - struct { - u32 token; - u32 reserved; - u64 len; - } dma_info[VIOMAXBLOCKDMA]; -}; - -struct vioblocklpevent { - struct HvLpEvent event; - u32 reserved; - u16 version; - u16 sub_result; - u16 disk; - u16 flags; - union { - struct open_data open_data; - struct rw_data rw_data; - u64 changed; - } u; -}; - -#define vioblockflags_ro 0x0001 - -enum vioblocksubtype { - vioblockopen = 0x0001, - vioblockclose = 0x0002, - vioblockread = 0x0003, - vioblockwrite = 0x0004, - vioblockflush = 0x0005, - vioblockcheck = 0x0007 -}; - struct viodasd_waitevent { struct completion com; int rc; @@ -429,7 +385,7 @@ static void do_viodasd_request(struct request_queue *q) * Probe a single disk and fill in the viodasd_device structure * for it. */ -static void probe_disk(struct viodasd_device *d) +static int probe_disk(struct viodasd_device *d) { HvLpEvent_Rc hvrc; struct viodasd_waitevent we; @@ -453,14 +409,14 @@ retry: 0, 0, 0); if (hvrc != 0) { printk(VIOD_KERN_WARNING "bad rc on HV open %d\n", (int)hvrc); - return; + return 0; } wait_for_completion(&we.com); if (we.rc != 0) { if (flags != 0) - return; + return 0; /* try again with read only flag set */ flags = vioblockflags_ro; goto retry; @@ -490,15 +446,32 @@ retry: if (hvrc != 0) { printk(VIOD_KERN_WARNING "bad rc sending event to OS/400 %d\n", (int)hvrc); - return; + return 0; } + + if (d->dev == NULL) { + /* this is when we reprobe for new disks */ + if (vio_create_viodasd(dev_no) == NULL) { + printk(VIOD_KERN_WARNING + "cannot allocate virtual device for disk %d\n", + dev_no); + return 0; + } + /* + * The vio_create_viodasd will have recursed into this + * routine with d->dev set to the new vio device and + * will finish the setup of the disk below. + */ + return 1; + } + /* create the request queue for the disk */ spin_lock_init(&d->q_lock); q = blk_init_queue(do_viodasd_request, &d->q_lock); if (q == NULL) { printk(VIOD_KERN_WARNING "cannot allocate queue for disk %d\n", dev_no); - return; + return 0; } g = alloc_disk(1 << PARTITION_SHIFT); if (g == NULL) { @@ -506,7 +479,7 @@ retry: "cannot allocate disk structure for disk %d\n", dev_no); blk_cleanup_queue(q); - return; + return 0; } d->disk = g; @@ -538,6 +511,7 @@ retry: /* register us in the global list */ add_disk(g); + return 1; } /* returns the total number of scatterlist elements converted */ @@ -718,8 +692,7 @@ static int viodasd_probe(struct vio_dev *vdev, const struct vio_device_id *id) struct viodasd_device *d = &viodasd_devices[vdev->unit_address]; d->dev = &vdev->dev; - probe_disk(d); - if (d->disk == NULL) + if (!probe_disk(d)) return -ENODEV; return 0; } diff --git a/include/asm-powerpc/iseries/vio.h b/include/asm-powerpc/iseries/vio.h index 2555dfd6fac..f9ac0d00b95 100644 --- a/include/asm-powerpc/iseries/vio.h +++ b/include/asm-powerpc/iseries/vio.h @@ -51,6 +51,51 @@ */ #define VIO_MAX_SUBTYPES 8 +#define VIOMAXBLOCKDMA 12 + +struct open_data { + u64 disk_size; + u16 max_disk; + u16 cylinders; + u16 tracks; + u16 sectors; + u16 bytes_per_sector; +}; + +struct rw_data { + u64 offset; + struct { + u32 token; + u32 reserved; + u64 len; + } dma_info[VIOMAXBLOCKDMA]; +}; + +struct vioblocklpevent { + struct HvLpEvent event; + u32 reserved; + u16 version; + u16 sub_result; + u16 disk; + u16 flags; + union { + struct open_data open_data; + struct rw_data rw_data; + u64 changed; + } u; +}; + +#define vioblockflags_ro 0x0001 + +enum vioblocksubtype { + vioblockopen = 0x0001, + vioblockclose = 0x0002, + vioblockread = 0x0003, + vioblockwrite = 0x0004, + vioblockflush = 0x0005, + vioblockcheck = 0x0007 +}; + struct viocdlpevent { struct HvLpEvent event; u32 reserved; @@ -133,6 +178,8 @@ extern void vio_set_hostlp(void); extern void *vio_get_event_buffer(int subtype); extern void vio_free_event_buffer(int subtype, void *buffer); +extern struct vio_dev *vio_create_viodasd(u32 unit); + extern HvLpIndex viopath_hostLp; extern HvLpIndex viopath_ourLp; -- cgit v1.2.3-70-g09d2 From 019a5f56ec195aceadada18aaaad0f67294bdaef Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Thu, 11 Oct 2007 01:06:03 -0400 Subject: mmc: don't use weight32() Using weight32() to determine if a value is a power of 2 is a rather heavi weight solution. The classic idiom is (x & (x - 1)) == 0, but the kernel already provide a is_power_of_2 function for it. Signed-off-by: Nicolas Pitre Signed-off-by: Pierre Ossman --- drivers/mmc/host/mmci.c | 3 ++- drivers/mmc/host/tifm_sd.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 4a72772f4fe..d0eb0a2abf4 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -391,7 +392,7 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq) WARN_ON(host->mrq != NULL); - if (mrq->data && (hweight32(mrq->data->blksz) > 1)) { + if (mrq->data && !is_power_of_2(mrq->data->blksz)) { printk(KERN_ERR "%s: Unsupported block size (%d bytes)\n", mmc_hostname(mmc), mrq->data->blksz); mrq->cmd->error = -EINVAL; diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c index 951392d2ce3..9b904795eb7 100644 --- a/drivers/mmc/host/tifm_sd.c +++ b/drivers/mmc/host/tifm_sd.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #define DRIVER_NAME "tifm_sd" @@ -637,7 +638,7 @@ static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq) goto err_out; } - if (mrq->data && (hweight32(mrq->data->blksz) > 1)) { + if (mrq->data && !is_power_of_2(mrq->data->blksz)) { printk(KERN_ERR "%s: Unsupported block size (%d bytes)\n", sock->dev.bus_id, mrq->data->blksz); mrq->cmd->error = -EINVAL; -- cgit v1.2.3-70-g09d2 From f3b6b6cd00d294d50e1c3eee85964c69d898de45 Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Fri, 21 Sep 2007 00:02:47 +0100 Subject: leds: Rename leds-cobalt driver The leds-cobalt driver only supports the Coable Qube series (not included in Cobalt Raq series). Rename the driver and update Kconfig/Makefile. Signed-off-by: Yoichi Yuasa Acked-by: Florian Fainelli Signed-off-by: Richard Purdie --- drivers/leds/Kconfig | 6 +++--- drivers/leds/Makefile | 2 +- drivers/leds/leds-cobalt-qube.c | 43 +++++++++++++++++++++++++++++++++++++++++ drivers/leds/leds-cobalt.c | 43 ----------------------------------------- 4 files changed, 47 insertions(+), 47 deletions(-) create mode 100644 drivers/leds/leds-cobalt-qube.c delete mode 100644 drivers/leds/leds-cobalt.c (limited to 'drivers') diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 4468cb3a8d2..9b79bcd9bf1 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -87,11 +87,11 @@ config LEDS_H1940 help This option enables support for the LEDs on the h1940. -config LEDS_COBALT - tristate "LED Support for Cobalt Server front LED" +config LEDS_COBALT_QUBE + tristate "LED Support for the Cobalt Qube series front LED" depends on LEDS_CLASS && MIPS_COBALT help - This option enables support for the front LED on Cobalt Server + This option enables support for the front LED on Cobalt Qube series config LEDS_GPIO tristate "LED Support for GPIO connected LEDs" diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index f8995c9bc2e..9b2684a2088 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -15,7 +15,7 @@ obj-$(CONFIG_LEDS_AMS_DELTA) += leds-ams-delta.o obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o obj-$(CONFIG_LEDS_WRAP) += leds-wrap.o obj-$(CONFIG_LEDS_H1940) += leds-h1940.o -obj-$(CONFIG_LEDS_COBALT) += leds-cobalt.o +obj-$(CONFIG_LEDS_COBALT_QUBE) += leds-cobalt-qube.o obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o # LED Triggers diff --git a/drivers/leds/leds-cobalt-qube.c b/drivers/leds/leds-cobalt-qube.c new file mode 100644 index 00000000000..d16439ce5da --- /dev/null +++ b/drivers/leds/leds-cobalt-qube.c @@ -0,0 +1,43 @@ +/* + * Copyright 2006 - Florian Fainelli + * + * Control the Cobalt Qube/RaQ front LED + */ + +#include +#include +#include +#include +#include +#include + +static void cobalt_led_set(struct led_classdev *led_cdev, enum led_brightness brightness) +{ + if (brightness) + COBALT_LED_PORT = COBALT_LED_BAR_LEFT | COBALT_LED_BAR_RIGHT; + else + COBALT_LED_PORT = 0; +} + +static struct led_classdev cobalt_led = { + .name = "cobalt-front-led", + .brightness_set = cobalt_led_set, + .default_trigger = "ide-disk", +}; + +static int __init cobalt_led_init(void) +{ + return led_classdev_register(NULL, &cobalt_led); +} + +static void __exit cobalt_led_exit(void) +{ + led_classdev_unregister(&cobalt_led); +} + +module_init(cobalt_led_init); +module_exit(cobalt_led_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Front LED support for Cobalt Server"); +MODULE_AUTHOR("Florian Fainelli "); diff --git a/drivers/leds/leds-cobalt.c b/drivers/leds/leds-cobalt.c deleted file mode 100644 index d16439ce5da..00000000000 --- a/drivers/leds/leds-cobalt.c +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2006 - Florian Fainelli - * - * Control the Cobalt Qube/RaQ front LED - */ - -#include -#include -#include -#include -#include -#include - -static void cobalt_led_set(struct led_classdev *led_cdev, enum led_brightness brightness) -{ - if (brightness) - COBALT_LED_PORT = COBALT_LED_BAR_LEFT | COBALT_LED_BAR_RIGHT; - else - COBALT_LED_PORT = 0; -} - -static struct led_classdev cobalt_led = { - .name = "cobalt-front-led", - .brightness_set = cobalt_led_set, - .default_trigger = "ide-disk", -}; - -static int __init cobalt_led_init(void) -{ - return led_classdev_register(NULL, &cobalt_led); -} - -static void __exit cobalt_led_exit(void) -{ - led_classdev_unregister(&cobalt_led); -} - -module_init(cobalt_led_init); -module_exit(cobalt_led_exit); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Front LED support for Cobalt Server"); -MODULE_AUTHOR("Florian Fainelli "); -- cgit v1.2.3-70-g09d2 From 97da7aaf46fedcf1a38a88e5ffc2c40df23e8013 Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Thu, 27 Sep 2007 17:51:05 +0900 Subject: leds: Add Cobalt Raq series LEDs support Add Cobalt Raq series LEDs support. Signed-off-by: Yoichi Yuasa Acked-by: Ralf Baechle Signed-off-by: Richard Purdie --- drivers/leds/Kconfig | 7 +++ drivers/leds/Makefile | 1 + drivers/leds/leds-cobalt-raq.c | 138 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 146 insertions(+) create mode 100644 drivers/leds/leds-cobalt-raq.c (limited to 'drivers') diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 9b79bcd9bf1..3cb23210b91 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -93,6 +93,13 @@ config LEDS_COBALT_QUBE help This option enables support for the front LED on Cobalt Qube series +config LEDS_COBALT_RAQ + bool "LED Support for the Cobalt Raq series" + depends on LEDS_CLASS && MIPS_COBALT + select LEDS_TRIGGERS + help + This option enables support for the Cobalt Raq series LEDs. + config LEDS_GPIO tristate "LED Support for GPIO connected LEDs" depends on LEDS_CLASS && GENERIC_GPIO diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index 9b2684a2088..d2ca1abbc3d 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o obj-$(CONFIG_LEDS_WRAP) += leds-wrap.o obj-$(CONFIG_LEDS_H1940) += leds-h1940.o obj-$(CONFIG_LEDS_COBALT_QUBE) += leds-cobalt-qube.o +obj-$(CONFIG_LEDS_COBALT_RAQ) += leds-cobalt-raq.o obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o # LED Triggers diff --git a/drivers/leds/leds-cobalt-raq.c b/drivers/leds/leds-cobalt-raq.c new file mode 100644 index 00000000000..6ebfff341e6 --- /dev/null +++ b/drivers/leds/leds-cobalt-raq.c @@ -0,0 +1,138 @@ +/* + * LEDs driver for the Cobalt Raq series. + * + * Copyright (C) 2007 Yoichi Yuasa + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include +#include +#include +#include +#include +#include +#include + +#define LED_WEB 0x04 +#define LED_POWER_OFF 0x08 + +static void __iomem *led_port; +static u8 led_value; +static DEFINE_SPINLOCK(led_value_lock); + +static void raq_web_led_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + unsigned long flags; + + spin_lock_irqsave(&led_value_lock, flags); + + if (brightness) + led_value |= LED_WEB; + else + led_value &= ~LED_WEB; + writeb(led_value, led_port); + + spin_unlock_irqrestore(&led_value_lock, flags); +} + +static struct led_classdev raq_web_led = { + .name = "raq-web", + .brightness_set = raq_web_led_set, +}; + +static void raq_power_off_led_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + unsigned long flags; + + spin_lock_irqsave(&led_value_lock, flags); + + if (brightness) + led_value |= LED_POWER_OFF; + else + led_value &= ~LED_POWER_OFF; + writeb(led_value, led_port); + + spin_unlock_irqrestore(&led_value_lock, flags); +} + +static struct led_classdev raq_power_off_led = { + .name = "raq-power-off", + .brightness_set = raq_power_off_led_set, + .default_trigger = "power-off", +}; + +static int __devinit cobalt_raq_led_probe(struct platform_device *pdev) +{ + struct resource *res; + int retval; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -EBUSY; + + led_port = ioremap(res->start, res->end - res->start + 1); + if (!led_port) + return -ENOMEM; + + retval = led_classdev_register(&pdev->dev, &raq_power_off_led); + if (retval) + goto err_iounmap; + + retval = led_classdev_register(&pdev->dev, &raq_web_led); + if (retval) + goto err_unregister; + + return 0; + +err_unregister: + led_classdev_unregister(&raq_power_off_led); + +err_iounmap: + iounmap(led_port); + led_port = NULL; + + return retval; +} + +static int __devexit cobalt_raq_led_remove(struct platform_device *pdev) +{ + led_classdev_unregister(&raq_power_off_led); + led_classdev_unregister(&raq_web_led); + + if (led_port) { + iounmap(led_port); + led_port = NULL; + } + + return 0; +} + +static struct platform_driver cobalt_raq_led_driver = { + .probe = cobalt_raq_led_probe, + .remove = __devexit_p(cobalt_raq_led_remove), + .driver = { + .name = "cobalt-raq-leds", + .owner = THIS_MODULE, + }, +}; + +static int __init cobalt_raq_led_init(void) +{ + return platform_driver_register(&cobalt_raq_led_driver); +} + +module_init(cobalt_raq_led_init); -- cgit v1.2.3-70-g09d2 From 4276fd7349bfd4f557d9777100fdcf1140771b4e Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Thu, 27 Sep 2007 17:51:17 +0900 Subject: leds: Update Cobalt Qube series front LED support Update Cobalt Qube series front LED support. Signed-off-by: Yoichi Yuasa Acked-by: Ralf Baechle Signed-off-by: Richard Purdie --- drivers/leds/leds-cobalt-qube.c | 95 +++++++++++++++++++++++++++++++++-------- 1 file changed, 77 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/leds/leds-cobalt-qube.c b/drivers/leds/leds-cobalt-qube.c index d16439ce5da..d2b54b53d80 100644 --- a/drivers/leds/leds-cobalt-qube.c +++ b/drivers/leds/leds-cobalt-qube.c @@ -3,40 +3,99 @@ * * Control the Cobalt Qube/RaQ front LED */ - +#include +#include +#include +#include #include +#include #include -#include -#include -#include -#include -static void cobalt_led_set(struct led_classdev *led_cdev, enum led_brightness brightness) +#define LED_FRONT_LEFT 0x01 +#define LED_FRONT_RIGHT 0x02 + +static void __iomem *led_port; +static u8 led_value; + +static void qube_front_led_set(struct led_classdev *led_cdev, + enum led_brightness brightness) { if (brightness) - COBALT_LED_PORT = COBALT_LED_BAR_LEFT | COBALT_LED_BAR_RIGHT; + led_value = LED_FRONT_LEFT | LED_FRONT_RIGHT; else - COBALT_LED_PORT = 0; + led_value = ~(LED_FRONT_LEFT | LED_FRONT_RIGHT); + writeb(led_value, led_port); +} + +static struct led_classdev qube_front_led = { + .name = "qube-front", + .brightness = LED_FULL, + .brightness_set = qube_front_led_set, + .default_trigger = "ide-disk", +}; + +static int __devinit cobalt_qube_led_probe(struct platform_device *pdev) +{ + struct resource *res; + int retval; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -EBUSY; + + led_port = ioremap(res->start, res->end - res->start + 1); + if (!led_port) + return -ENOMEM; + + led_value = LED_FRONT_LEFT | LED_FRONT_RIGHT; + writeb(led_value, led_port); + + retval = led_classdev_register(&pdev->dev, &qube_front_led); + if (retval) + goto err_iounmap; + + return 0; + +err_iounmap: + iounmap(led_port); + led_port = NULL; + + return retval; +} + +static int __devexit cobalt_qube_led_remove(struct platform_device *pdev) +{ + led_classdev_unregister(&qube_front_led); + + if (led_port) { + iounmap(led_port); + led_port = NULL; + } + + return 0; } -static struct led_classdev cobalt_led = { - .name = "cobalt-front-led", - .brightness_set = cobalt_led_set, - .default_trigger = "ide-disk", +static struct platform_driver cobalt_qube_led_driver = { + .probe = cobalt_qube_led_probe, + .remove = __devexit_p(cobalt_qube_led_remove), + .driver = { + .name = "cobalt-qube-leds", + .owner = THIS_MODULE, + }, }; -static int __init cobalt_led_init(void) +static int __init cobalt_qube_led_init(void) { - return led_classdev_register(NULL, &cobalt_led); + return platform_driver_register(&cobalt_qube_led_driver); } -static void __exit cobalt_led_exit(void) +static void __exit cobalt_qube_led_exit(void) { - led_classdev_unregister(&cobalt_led); + platform_driver_unregister(&cobalt_qube_led_driver); } -module_init(cobalt_led_init); -module_exit(cobalt_led_exit); +module_init(cobalt_qube_led_init); +module_exit(cobalt_qube_led_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Front LED support for Cobalt Server"); -- cgit v1.2.3-70-g09d2 From 0ad90efde278866a4ba7510e6e1fbd9626da1689 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sat, 11 Aug 2007 10:27:19 +0100 Subject: backlight/leds: Make two structs static This patch makes two needlessly global structs static. Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Richard Purdie --- drivers/video/backlight/backlight.c | 2 +- drivers/video/backlight/lcd.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c index b26de8cf311..4840fe217e4 100644 --- a/drivers/video/backlight/backlight.c +++ b/drivers/video/backlight/backlight.c @@ -164,7 +164,7 @@ static ssize_t backlight_show_actual_brightness(struct device *dev, return rc; } -struct class *backlight_class; +static struct class *backlight_class; static void bl_device_release(struct device *dev) { diff --git a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c index 6f652c65fae..299fd318dd4 100644 --- a/drivers/video/backlight/lcd.c +++ b/drivers/video/backlight/lcd.c @@ -149,7 +149,7 @@ static ssize_t lcd_show_max_contrast(struct device *dev, return sprintf(buf, "%d\n", ld->props.max_contrast); } -struct class *lcd_class; +static struct class *lcd_class; static void lcd_device_release(struct device *dev) { -- cgit v1.2.3-70-g09d2 From 0b75f2dfa2a67012ff6996b322117e1d7e45abe1 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Sat, 11 Aug 2007 10:29:59 +0100 Subject: backlight: Fix cr_bllcd allocations and error paths After fixing the too small memory allocation in cr_backlight_probe() from drivers/video/backlight/cr_bllcd.c (commit e3bbb3f05339de438faf54124f25c92e6fe4ac2e) I noticed that the Coverity checker also thought there were a few memory leaks in there. I took a closer look and confirmed that there were indeed several leaks. At the start of the function we allocate storage for a 'struct cr_panel' and store the pointer in a variable named 'crp'. Then we call pci_get_device() and pci_read_config_byte() and if either of them fail we return without freeing the memory allocated for the 'struct cr_panel'. These two leaks are easy to fix since we don't even use 'crp' for anything up to this point, so I simply moved the allocation further down in the function so it only happens just before we actually need it. A bit further down we call backlight_device_register() and store the result in 'crp->cr_backlight_device'. In case of error we return 'crp->cr_backlight_device' from the function, thus leaking 'crp' itself. The same thing happens with the call to lcd_device_register(). To fix these two leaks I declare two new pointers to hold the return values, so that in case of error we can return the pointer (as before) but without leaking 'crp'. This version of the patch also adds missing backlight_device_unregister() / lcd_device_unregister() / pci_dev_put() calls to error paths. Thanks to Richard Purdie for noticing. Signed-off-by: Jesper Juhl Signed-off-by: Andrew Morton Signed-off-by: Richard Purdie --- drivers/video/backlight/cr_bllcd.c | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/video/backlight/cr_bllcd.c b/drivers/video/backlight/cr_bllcd.c index b7904da51b2..92e201e81fb 100644 --- a/drivers/video/backlight/cr_bllcd.c +++ b/drivers/video/backlight/cr_bllcd.c @@ -171,13 +171,11 @@ static struct lcd_ops cr_lcd_ops = { static int cr_backlight_probe(struct platform_device *pdev) { + struct backlight_device *bdp; + struct lcd_device *ldp; struct cr_panel *crp; u8 dev_en; - crp = kzalloc(sizeof(*crp), GFP_KERNEL); - if (crp == NULL) - return -ENOMEM; - lpc_dev = pci_get_device(PCI_VENDOR_ID_INTEL, CRVML_DEVICE_LPC, NULL); if (!lpc_dev) { @@ -193,27 +191,34 @@ static int cr_backlight_probe(struct platform_device *pdev) return -ENODEV; } - crp->cr_backlight_device = backlight_device_register("cr-backlight", - &pdev->dev, NULL, - &cr_backlight_ops); - if (IS_ERR(crp->cr_backlight_device)) { + bdp = backlight_device_register("cr-backlight", + &pdev->dev, NULL, &cr_backlight_ops); + if (IS_ERR(bdp)) { pci_dev_put(lpc_dev); - return PTR_ERR(crp->cr_backlight_device); + return PTR_ERR(bdp); } - crp->cr_lcd_device = lcd_device_register("cr-lcd", - &pdev->dev, NULL, - &cr_lcd_ops); - - if (IS_ERR(crp->cr_lcd_device)) { + ldp = lcd_device_register("cr-lcd", &pdev->dev, NULL, &cr_lcd_ops); + if (IS_ERR(ldp)) { + backlight_device_unregister(bdp); pci_dev_put(lpc_dev); - return PTR_ERR(crp->cr_backlight_device); + return PTR_ERR(bdp); } pci_read_config_dword(lpc_dev, CRVML_REG_GPIOBAR, &gpio_bar); gpio_bar &= ~0x3F; + crp = kzalloc(sizeof(*crp), GFP_KERNEL); + if (!crp) { + lcd_device_unregister(ldp); + backlight_device_unregister(bdp); + pci_dev_put(lpc_dev); + return -ENOMEM; + } + + crp->cr_backlight_device = bdp; + crp->cr_lcd_device = ldp; crp->cr_backlight_device->props.power = FB_BLANK_UNBLANK; crp->cr_backlight_device->props.brightness = 0; crp->cr_backlight_device->props.max_brightness = 0; -- cgit v1.2.3-70-g09d2 From 18f65c793a5106b9f99822ef248e71582db03386 Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Sun, 2 Sep 2007 23:15:49 +0100 Subject: backlight: Add Samsung LTV350QV LCD driver This patch adds support for powering on and off the Samsung LTV350QV LCD panel via SPI. The driver responds to framebuffer power management, it powers off the panel on reboot/halt/poweroff. It can also be controlled through sysfs. The panel is powered up when the module is loaded, and off when the module is unloaded. Verified on AVR32 STK1000. Signed-off-by: Haavard Skinnemoen Signed-off-by: David Brownell Signed-off-by: Richard Purdie --- drivers/video/backlight/Kconfig | 12 ++ drivers/video/backlight/Makefile | 2 + drivers/video/backlight/ltv350qv.c | 330 +++++++++++++++++++++++++++++++++++++ drivers/video/backlight/ltv350qv.h | 95 +++++++++++ 4 files changed, 439 insertions(+) create mode 100644 drivers/video/backlight/ltv350qv.c create mode 100644 drivers/video/backlight/ltv350qv.h (limited to 'drivers') diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index 2580f5fa248..b6f936a0918 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -24,6 +24,18 @@ config LCD_CLASS_DEVICE To have support for your specific LCD panel you will have to select the proper drivers which depend on this option. +config LCD_LTV350QV + tristate "Samsung LTV350QV LCD Panel" + depends on LCD_CLASS_DEVICE && SPI_MASTER + default n + help + If you have a Samsung LTV350QV LCD panel, say y to include a + power control driver for it. The panel starts up in power + off state, so you need this driver in order to see any + output. + + The LTV350QV panel is present on all ATSTK1000 boards. + # # Backlight # diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index c6e2266f63e..965a78b1811 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -1,6 +1,8 @@ # Backlight & LCD drivers obj-$(CONFIG_LCD_CLASS_DEVICE) += lcd.o +obj-$(CONFIG_LCD_LTV350QV) += ltv350qv.o + obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o obj-$(CONFIG_BACKLIGHT_CORGI) += corgi_bl.o obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o diff --git a/drivers/video/backlight/ltv350qv.c b/drivers/video/backlight/ltv350qv.c new file mode 100644 index 00000000000..2eb206bf73e --- /dev/null +++ b/drivers/video/backlight/ltv350qv.c @@ -0,0 +1,330 @@ +/* + * Power control for Samsung LTV350QV Quarter VGA LCD Panel + * + * Copyright (C) 2006, 2007 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include + +#include "ltv350qv.h" + +#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL) + +struct ltv350qv { + struct spi_device *spi; + u8 *buffer; + int power; + struct lcd_device *ld; +}; + +/* + * The power-on and power-off sequences are taken from the + * LTV350QV-F04 data sheet from Samsung. The register definitions are + * taken from the S6F2002 command list also from Samsung. Both + * documents are distributed with the AVR32 Linux BSP CD from Atmel. + * + * There's still some voodoo going on here, but it's a lot better than + * in the first incarnation of the driver where all we had was the raw + * numbers from the initialization sequence. + */ +static int ltv350qv_write_reg(struct ltv350qv *lcd, u8 reg, u16 val) +{ + struct spi_message msg; + struct spi_transfer index_xfer = { + .len = 3, + .cs_change = 1, + }; + struct spi_transfer value_xfer = { + .len = 3, + }; + + spi_message_init(&msg); + + /* register index */ + lcd->buffer[0] = LTV_OPC_INDEX; + lcd->buffer[1] = 0x00; + lcd->buffer[2] = reg & 0x7f; + index_xfer.tx_buf = lcd->buffer; + spi_message_add_tail(&index_xfer, &msg); + + /* register value */ + lcd->buffer[4] = LTV_OPC_DATA; + lcd->buffer[5] = val >> 8; + lcd->buffer[6] = val; + value_xfer.tx_buf = lcd->buffer + 4; + spi_message_add_tail(&value_xfer, &msg); + + return spi_sync(lcd->spi, &msg); +} + +/* The comments are taken straight from the data sheet */ +static int ltv350qv_power_on(struct ltv350qv *lcd) +{ + int ret; + + /* Power On Reset Display off State */ + if (ltv350qv_write_reg(lcd, LTV_PWRCTL1, 0x0000)) + goto err; + msleep(15); + + /* Power Setting Function 1 */ + if (ltv350qv_write_reg(lcd, LTV_PWRCTL1, LTV_VCOM_DISABLE)) + goto err; + if (ltv350qv_write_reg(lcd, LTV_PWRCTL2, LTV_VCOML_ENABLE)) + goto err_power1; + + /* Power Setting Function 2 */ + if (ltv350qv_write_reg(lcd, LTV_PWRCTL1, + LTV_VCOM_DISABLE | LTV_DRIVE_CURRENT(5) + | LTV_SUPPLY_CURRENT(5))) + goto err_power2; + + msleep(55); + + /* Instruction Setting */ + ret = ltv350qv_write_reg(lcd, LTV_IFCTL, + LTV_NMD | LTV_REV | LTV_NL(0x1d)); + ret |= ltv350qv_write_reg(lcd, LTV_DATACTL, + LTV_DS_SAME | LTV_CHS_480 + | LTV_DF_RGB | LTV_RGB_BGR); + ret |= ltv350qv_write_reg(lcd, LTV_ENTRY_MODE, + LTV_VSPL_ACTIVE_LOW + | LTV_HSPL_ACTIVE_LOW + | LTV_DPL_SAMPLE_RISING + | LTV_EPL_ACTIVE_LOW + | LTV_SS_RIGHT_TO_LEFT); + ret |= ltv350qv_write_reg(lcd, LTV_GATECTL1, LTV_CLW(3)); + ret |= ltv350qv_write_reg(lcd, LTV_GATECTL2, + LTV_NW_INV_1LINE | LTV_FWI(3)); + ret |= ltv350qv_write_reg(lcd, LTV_VBP, 0x000a); + ret |= ltv350qv_write_reg(lcd, LTV_HBP, 0x0021); + ret |= ltv350qv_write_reg(lcd, LTV_SOTCTL, LTV_SDT(3) | LTV_EQ(0)); + ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(0), 0x0103); + ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(1), 0x0301); + ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(2), 0x1f0f); + ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(3), 0x1f0f); + ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(4), 0x0707); + ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(5), 0x0307); + ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(6), 0x0707); + ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(7), 0x0000); + ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(8), 0x0004); + ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(9), 0x0000); + if (ret) + goto err_settings; + + /* Wait more than 2 frames */ + msleep(20); + + /* Display On Sequence */ + ret = ltv350qv_write_reg(lcd, LTV_PWRCTL1, + LTV_VCOM_DISABLE | LTV_VCOMOUT_ENABLE + | LTV_POWER_ON | LTV_DRIVE_CURRENT(5) + | LTV_SUPPLY_CURRENT(5)); + ret |= ltv350qv_write_reg(lcd, LTV_GATECTL2, + LTV_NW_INV_1LINE | LTV_DSC | LTV_FWI(3)); + if (ret) + goto err_disp_on; + + /* Display should now be ON. Phew. */ + return 0; + +err_disp_on: + /* + * Try to recover. Error handling probably isn't very useful + * at this point, just make a best effort to switch the panel + * off. + */ + ltv350qv_write_reg(lcd, LTV_PWRCTL1, + LTV_VCOM_DISABLE | LTV_DRIVE_CURRENT(5) + | LTV_SUPPLY_CURRENT(5)); + ltv350qv_write_reg(lcd, LTV_GATECTL2, + LTV_NW_INV_1LINE | LTV_FWI(3)); +err_settings: +err_power2: +err_power1: + ltv350qv_write_reg(lcd, LTV_PWRCTL2, 0x0000); + msleep(1); +err: + ltv350qv_write_reg(lcd, LTV_PWRCTL1, LTV_VCOM_DISABLE); + return -EIO; +} + +static int ltv350qv_power_off(struct ltv350qv *lcd) +{ + int ret; + + /* Display Off Sequence */ + ret = ltv350qv_write_reg(lcd, LTV_PWRCTL1, + LTV_VCOM_DISABLE + | LTV_DRIVE_CURRENT(5) + | LTV_SUPPLY_CURRENT(5)); + ret |= ltv350qv_write_reg(lcd, LTV_GATECTL2, + LTV_NW_INV_1LINE | LTV_FWI(3)); + + /* Power down setting 1 */ + ret |= ltv350qv_write_reg(lcd, LTV_PWRCTL2, 0x0000); + + /* Wait at least 1 ms */ + msleep(1); + + /* Power down setting 2 */ + ret |= ltv350qv_write_reg(lcd, LTV_PWRCTL1, LTV_VCOM_DISABLE); + + /* + * No point in trying to recover here. If we can't switch the + * panel off, what are we supposed to do other than inform the + * user about the failure? + */ + if (ret) + return -EIO; + + /* Display power should now be OFF */ + return 0; +} + +static int ltv350qv_power(struct ltv350qv *lcd, int power) +{ + int ret = 0; + + if (POWER_IS_ON(power) && !POWER_IS_ON(lcd->power)) + ret = ltv350qv_power_on(lcd); + else if (!POWER_IS_ON(power) && POWER_IS_ON(lcd->power)) + ret = ltv350qv_power_off(lcd); + + if (!ret) + lcd->power = power; + + return ret; +} + +static int ltv350qv_set_power(struct lcd_device *ld, int power) +{ + struct ltv350qv *lcd = lcd_get_data(ld); + + return ltv350qv_power(lcd, power); +} + +static int ltv350qv_get_power(struct lcd_device *ld) +{ + struct ltv350qv *lcd = lcd_get_data(ld); + + return lcd->power; +} + +static struct lcd_ops ltv_ops = { + .get_power = ltv350qv_get_power, + .set_power = ltv350qv_set_power, +}; + +static int __devinit ltv350qv_probe(struct spi_device *spi) +{ + struct ltv350qv *lcd; + struct lcd_device *ld; + int ret; + + lcd = kzalloc(sizeof(struct ltv350qv), GFP_KERNEL); + if (!lcd) + return -ENOMEM; + + lcd->spi = spi; + lcd->power = FB_BLANK_POWERDOWN; + lcd->buffer = kzalloc(8, GFP_KERNEL); + + ld = lcd_device_register("ltv350qv", &spi->dev, lcd, <v_ops); + if (IS_ERR(ld)) { + ret = PTR_ERR(ld); + goto out_free_lcd; + } + lcd->ld = ld; + + ret = ltv350qv_power(lcd, FB_BLANK_UNBLANK); + if (ret) + goto out_unregister; + + dev_set_drvdata(&spi->dev, lcd); + + return 0; + +out_unregister: + lcd_device_unregister(ld); +out_free_lcd: + kfree(lcd); + return ret; +} + +static int __devexit ltv350qv_remove(struct spi_device *spi) +{ + struct ltv350qv *lcd = dev_get_drvdata(&spi->dev); + + ltv350qv_power(lcd, FB_BLANK_POWERDOWN); + lcd_device_unregister(lcd->ld); + kfree(lcd); + + return 0; +} + +#ifdef CONFIG_PM +static int ltv350qv_suspend(struct spi_device *spi, pm_message_t state) +{ + struct ltv350qv *lcd = dev_get_drvdata(&spi->dev); + + return ltv350qv_power(lcd, FB_BLANK_POWERDOWN); +} + +static int ltv350qv_resume(struct spi_device *spi) +{ + struct ltv350qv *lcd = dev_get_drvdata(&spi->dev); + + return ltv350qv_power(lcd, FB_BLANK_UNBLANK); +} +#else +#define ltv350qv_suspend NULL +#define ltv350qv_resume NULL +#endif + +/* Power down all displays on reboot, poweroff or halt */ +static void ltv350qv_shutdown(struct spi_device *spi) +{ + struct ltv350qv *lcd = dev_get_drvdata(&spi->dev); + + ltv350qv_power(lcd, FB_BLANK_POWERDOWN); +} + +static struct spi_driver ltv350qv_driver = { + .driver = { + .name = "ltv350qv", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + + .probe = ltv350qv_probe, + .remove = __devexit_p(ltv350qv_remove), + .shutdown = ltv350qv_shutdown, + .suspend = ltv350qv_suspend, + .resume = ltv350qv_resume, +}; + +static int __init ltv350qv_init(void) +{ + return spi_register_driver(<v350qv_driver); +} + +static void __exit ltv350qv_exit(void) +{ + spi_unregister_driver(<v350qv_driver); +} +module_init(ltv350qv_init); +module_exit(ltv350qv_exit); + +MODULE_AUTHOR("Haavard Skinnemoen "); +MODULE_DESCRIPTION("Samsung LTV350QV LCD Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/backlight/ltv350qv.h b/drivers/video/backlight/ltv350qv.h new file mode 100644 index 00000000000..189112e3fc7 --- /dev/null +++ b/drivers/video/backlight/ltv350qv.h @@ -0,0 +1,95 @@ +/* + * Register definitions for Samsung LTV350QV Quarter VGA LCD Panel + * + * Copyright (C) 2006, 2007 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __LTV350QV_H +#define __LTV350QV_H + +#define LTV_OPC_INDEX 0x74 +#define LTV_OPC_DATA 0x76 + +#define LTV_ID 0x00 /* ID Read */ +#define LTV_IFCTL 0x01 /* Display Interface Control */ +#define LTV_DATACTL 0x02 /* Display Data Control */ +#define LTV_ENTRY_MODE 0x03 /* Entry Mode */ +#define LTV_GATECTL1 0x04 /* Gate Control 1 */ +#define LTV_GATECTL2 0x05 /* Gate Control 2 */ +#define LTV_VBP 0x06 /* Vertical Back Porch */ +#define LTV_HBP 0x07 /* Horizontal Back Porch */ +#define LTV_SOTCTL 0x08 /* Source Output Timing Control */ +#define LTV_PWRCTL1 0x09 /* Power Control 1 */ +#define LTV_PWRCTL2 0x0a /* Power Control 2 */ +#define LTV_GAMMA(x) (0x10 + (x)) /* Gamma control */ + +/* Bit definitions for LTV_IFCTL */ +#define LTV_IM (1 << 15) +#define LTV_NMD (1 << 14) +#define LTV_SSMD (1 << 13) +#define LTV_REV (1 << 7) +#define LTV_NL(x) (((x) & 0x001f) << 0) + +/* Bit definitions for LTV_DATACTL */ +#define LTV_DS_SAME (0 << 12) +#define LTV_DS_D_TO_S (1 << 12) +#define LTV_DS_S_TO_D (2 << 12) +#define LTV_CHS_384 (0 << 9) +#define LTV_CHS_480 (1 << 9) +#define LTV_CHS_492 (2 << 9) +#define LTV_DF_RGB (0 << 6) +#define LTV_DF_RGBX (1 << 6) +#define LTV_DF_XRGB (2 << 6) +#define LTV_RGB_RGB (0 << 2) +#define LTV_RGB_BGR (1 << 2) +#define LTV_RGB_GRB (2 << 2) +#define LTV_RGB_RBG (3 << 2) + +/* Bit definitions for LTV_ENTRY_MODE */ +#define LTV_VSPL_ACTIVE_LOW (0 << 15) +#define LTV_VSPL_ACTIVE_HIGH (1 << 15) +#define LTV_HSPL_ACTIVE_LOW (0 << 14) +#define LTV_HSPL_ACTIVE_HIGH (1 << 14) +#define LTV_DPL_SAMPLE_RISING (0 << 13) +#define LTV_DPL_SAMPLE_FALLING (1 << 13) +#define LTV_EPL_ACTIVE_LOW (0 << 12) +#define LTV_EPL_ACTIVE_HIGH (1 << 12) +#define LTV_SS_LEFT_TO_RIGHT (0 << 8) +#define LTV_SS_RIGHT_TO_LEFT (1 << 8) +#define LTV_STB (1 << 1) + +/* Bit definitions for LTV_GATECTL1 */ +#define LTV_CLW(x) (((x) & 0x0007) << 12) +#define LTV_GAON (1 << 5) +#define LTV_SDR (1 << 3) + +/* Bit definitions for LTV_GATECTL2 */ +#define LTV_NW_INV_FRAME (0 << 14) +#define LTV_NW_INV_1LINE (1 << 14) +#define LTV_NW_INV_2LINE (2 << 14) +#define LTV_DSC (1 << 12) +#define LTV_GIF (1 << 8) +#define LTV_FHN (1 << 7) +#define LTV_FTI(x) (((x) & 0x0003) << 4) +#define LTV_FWI(x) (((x) & 0x0003) << 0) + +/* Bit definitions for LTV_SOTCTL */ +#define LTV_SDT(x) (((x) & 0x0007) << 10) +#define LTV_EQ(x) (((x) & 0x0007) << 2) + +/* Bit definitions for LTV_PWRCTL1 */ +#define LTV_VCOM_DISABLE (1 << 14) +#define LTV_VCOMOUT_ENABLE (1 << 11) +#define LTV_POWER_ON (1 << 9) +#define LTV_DRIVE_CURRENT(x) (((x) & 0x0007) << 4) /* 0=off, 5=max */ +#define LTV_SUPPLY_CURRENT(x) (((x) & 0x0007) << 0) /* 0=off, 5=max */ + +/* Bit definitions for LTV_PWRCTL2 */ +#define LTV_VCOML_ENABLE (1 << 13) +#define LTV_VCOML_VOLTAGE(x) (((x) & 0x001f) << 8) /* 0=1V, 31=-1V */ +#define LTV_VCOMH_VOLTAGE(x) (((x) & 0x001f) << 0) /* 0=3V, 31=4.5V */ + +#endif /* __LTV350QV_H */ -- cgit v1.2.3-70-g09d2 From c3f8f65046127f471d0b6193a1923185b354c011 Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Mon, 3 Sep 2007 00:27:00 +0100 Subject: backlight: Convert corgi backlight driver into a more generic driver Convert the corgi backlight driver to a more generic version so it can be reused by other code rather than being Zaurus/PXA specific. Signed-off-by: Richard Purdie --- arch/arm/mach-pxa/corgi.c | 18 ++++++++++++++++-- arch/arm/mach-pxa/spitz.c | 18 ++++++++++++++++-- drivers/video/backlight/Kconfig | 11 ++++++----- drivers/video/backlight/corgi_bl.c | 22 ++++++++++------------ include/asm-arm/arch-pxa/sharpsl.h | 6 ------ include/linux/backlight.h | 9 +++++++++ 6 files changed, 57 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c index aab27297b3c..2363cc64fe0 100644 --- a/arch/arm/mach-pxa/corgi.c +++ b/arch/arm/mach-pxa/corgi.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -142,15 +143,28 @@ struct corgissp_machinfo corgi_ssp_machinfo = { /* * Corgi Backlight Device */ -static struct corgibl_machinfo corgi_bl_machinfo = { +static void corgi_bl_kick_battery(void) +{ + void (*kick_batt)(void); + + kick_batt = symbol_get(sharpsl_battery_kick); + if (kick_batt) { + kick_batt(); + symbol_put(sharpsl_battery_kick); + } +} + +static struct generic_bl_info corgi_bl_machinfo = { + .name = "corgi-bl", .max_intensity = 0x2f, .default_intensity = 0x1f, .limit_mask = 0x0b, .set_bl_intensity = corgi_bl_set_intensity, + .kick_battery = corgi_bl_kick_battery, }; static struct platform_device corgibl_device = { - .name = "corgi-bl", + .name = "generic-bl", .dev = { .parent = &corgifb_device.dev, .platform_data = &corgi_bl_machinfo, diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c index bae47e145de..2d78199d24a 100644 --- a/arch/arm/mach-pxa/spitz.c +++ b/arch/arm/mach-pxa/spitz.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -222,14 +223,27 @@ struct corgissp_machinfo spitz_ssp_machinfo = { /* * Spitz Backlight Device */ -static struct corgibl_machinfo spitz_bl_machinfo = { +static void spitz_bl_kick_battery(void) +{ + void (*kick_batt)(void); + + kick_batt = symbol_get(sharpsl_battery_kick); + if (kick_batt) { + kick_batt(); + symbol_put(sharpsl_battery_kick); + } +} + +static struct generic_bl_info spitz_bl_machinfo = { + .name = "corgi-bl", .default_intensity = 0x1f, .limit_mask = 0x0b, .max_intensity = 0x2f, + .kick_battery = spitz_bl_kick_battery, }; static struct platform_device spitzbl_device = { - .name = "corgi-bl", + .name = "generic-bl", .dev = { .platform_data = &spitz_bl_machinfo, }, diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index b6f936a0918..9609a6c676b 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -51,12 +51,13 @@ config BACKLIGHT_CLASS_DEVICE select the proper drivers which depend on this option. config BACKLIGHT_CORGI - tristate "Sharp Corgi Backlight Driver (SL Series)" - depends on BACKLIGHT_CLASS_DEVICE && PXA_SHARPSL - default y + tristate "Generic (aka Sharp Corgi) Backlight Driver" + depends on BACKLIGHT_CLASS_DEVICE + default n help - If you have a Sharp Zaurus SL-C7xx, SL-Cxx00 or SL-6000x say y to enable the - backlight driver. + Say y to enable the generic platform backlight driver previously + known as the Corgi backlight driver. If you have a Sharp Zaurus + SL-C7xx, SL-Cxx00 or SL-6000x say y. Most users can say n. config BACKLIGHT_LOCOMO tristate "Sharp LOCOMO LCD/Backlight Driver" diff --git a/drivers/video/backlight/corgi_bl.c b/drivers/video/backlight/corgi_bl.c index ce00e18a4e5..4d4d037e3ec 100644 --- a/drivers/video/backlight/corgi_bl.c +++ b/drivers/video/backlight/corgi_bl.c @@ -18,13 +18,11 @@ #include #include #include -#include -#include static int corgibl_intensity; static struct backlight_properties corgibl_data; static struct backlight_device *corgi_backlight_device; -static struct corgibl_machinfo *bl_machinfo; +static struct generic_bl_info *bl_machinfo; static unsigned long corgibl_flags; #define CORGIBL_SUSPENDED 0x01 @@ -32,7 +30,6 @@ static unsigned long corgibl_flags; static int corgibl_send_intensity(struct backlight_device *bd) { - void (*corgi_kick_batt)(void); int intensity = bd->props.brightness; if (bd->props.power != FB_BLANK_UNBLANK) @@ -48,11 +45,8 @@ static int corgibl_send_intensity(struct backlight_device *bd) corgibl_intensity = intensity; - corgi_kick_batt = symbol_get(sharpsl_battery_kick); - if (corgi_kick_batt) { - corgi_kick_batt(); - symbol_put(sharpsl_battery_kick); - } + if (bl_machinfo->kick_battery) + bl_machinfo->kick_battery(); return 0; } @@ -107,13 +101,17 @@ static struct backlight_ops corgibl_ops = { static int corgibl_probe(struct platform_device *pdev) { - struct corgibl_machinfo *machinfo = pdev->dev.platform_data; + struct generic_bl_info *machinfo = pdev->dev.platform_data; + const char *name = "generic-bl"; bl_machinfo = machinfo; if (!machinfo->limit_mask) machinfo->limit_mask = -1; - corgi_backlight_device = backlight_device_register ("corgi-bl", + if (machinfo->name) + name = machinfo->name; + + corgi_backlight_device = backlight_device_register (name, &pdev->dev, NULL, &corgibl_ops); if (IS_ERR (corgi_backlight_device)) return PTR_ERR (corgi_backlight_device); @@ -149,7 +147,7 @@ static struct platform_driver corgibl_driver = { .suspend = corgibl_suspend, .resume = corgibl_resume, .driver = { - .name = "corgi-bl", + .name = "generic-bl", }, }; diff --git a/include/asm-arm/arch-pxa/sharpsl.h b/include/asm-arm/arch-pxa/sharpsl.h index 94cb4982af8..2b0fe773213 100644 --- a/include/asm-arm/arch-pxa/sharpsl.h +++ b/include/asm-arm/arch-pxa/sharpsl.h @@ -25,12 +25,6 @@ struct corgits_machinfo { /* * SharpSL Backlight */ -struct corgibl_machinfo { - int max_intensity; - int default_intensity; - int limit_mask; - void (*set_bl_intensity)(int intensity); -}; extern void corgibl_limit_intensity(int limit); diff --git a/include/linux/backlight.h b/include/linux/backlight.h index c897c7b0385..1ee9488ca2e 100644 --- a/include/linux/backlight.h +++ b/include/linux/backlight.h @@ -92,4 +92,13 @@ static inline void * bl_get_data(struct backlight_device *bl_dev) return dev_get_drvdata(&bl_dev->dev); } +struct generic_bl_info { + const char *name; + int max_intensity; + int default_intensity; + int limit_mask; + void (*set_bl_intensity)(int intensity); + void (*kick_battery)(void); +}; + #endif -- cgit v1.2.3-70-g09d2 From 7cfa7168f7a7730abf1aa2af4a7596d24edd4c21 Mon Sep 17 00:00:00 2001 From: Shane Huang Date: Thu, 11 Oct 2007 23:53:58 +0200 Subject: atiixp: SB700 contains more than one IDE channel SB700 supports one physical IDE channel, but SB700 SATA controller supports combined mode. When the SATA combined mode is enabled, two SATA ports (port4 and port5) share one IDE channel from IDE controller, and PATA will share the other IDE channel. Our previous patch adding SB700 IDE device ID only supports one IDE channel, which contains bug. The attached patch fixes the bug. Signed-off-by: "Shane Huang" Acked-by: Sergei Shtylyov Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/atiixp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ide/pci/atiixp.c b/drivers/ide/pci/atiixp.c index 1725aa402d9..679eb92b892 100644 --- a/drivers/ide/pci/atiixp.c +++ b/drivers/ide/pci/atiixp.c @@ -325,7 +325,7 @@ static struct pci_device_id atiixp_pci_tbl[] = { { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP300_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP700_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP700_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { 0, }, }; MODULE_DEVICE_TABLE(pci, atiixp_pci_tbl); -- cgit v1.2.3-70-g09d2 From b4e44369a380c1836d0983c2a5011099b7b26eb1 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Thu, 11 Oct 2007 23:53:58 +0200 Subject: hpt366: MWDMA filter for SATA cards (take 2) The Marvell bridge chips used on HighPoint SATA cards do not seem to support the MWDMA modes (at least that could be seen in their so-called drivers :-), so the driver needs to account for this -- to achieve this: - add mdma_filter() method from the original patch by Bartlomiej Zolnierkiewicz with his consent; - install the method for all chips to only return empty mask if a SATA drive is detected on HPT372{AN]/374 chips... Signed-off-by: Sergei Shtylyov Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/ide-dma.c | 9 +++++++-- drivers/ide/ide.c | 1 + drivers/ide/pci/hpt366.c | 23 +++++++++++++++++++++-- include/linux/ide.h | 1 + 4 files changed, 30 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c index ff644a5e12c..097d6e9865b 100644 --- a/drivers/ide/ide-dma.c +++ b/drivers/ide/ide-dma.c @@ -673,8 +673,13 @@ static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base) mask &= 0x07; break; case XFER_MW_DMA_0: - if (id->field_valid & 2) - mask = id->dma_mword & hwif->mwdma_mask; + if ((id->field_valid & 2) == 0) + break; + if (hwif->mdma_filter) + mask = hwif->mdma_filter(drive); + else + mask = hwif->mwdma_mask; + mask &= id->dma_mword; break; case XFER_SW_DMA_0: if (id->field_valid & 2) { diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 5e88a060df0..de54306789a 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -398,6 +398,7 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif) hwif->tuneproc = tmp_hwif->tuneproc; hwif->speedproc = tmp_hwif->speedproc; + hwif->mdma_filter = tmp_hwif->mdma_filter; hwif->udma_filter = tmp_hwif->udma_filter; hwif->selectproc = tmp_hwif->selectproc; hwif->reset_poll = tmp_hwif->reset_poll; diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c index 39f1c89f7c8..3d8d6b2ee41 100644 --- a/drivers/ide/pci/hpt366.c +++ b/drivers/ide/pci/hpt366.c @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/pci/hpt366.c Version 1.12 Aug 19, 2007 + * linux/drivers/ide/pci/hpt366.c Version 1.13 Sep 29, 2007 * * Copyright (C) 1999-2003 Andre Hedrick * Portions Copyright (C) 2001 Sun Microsystems, Inc. @@ -114,7 +114,7 @@ * unify HPT36x/37x timing setup code and the speedproc handlers by joining * the register setting lists into the table indexed by the clock selected * - set the correct hwif->ultra_mask for each individual chip - * - add UltraDMA mode filtering for the HPT37[24] based SATA cards + * - add Ultra and MW DMA mode filtering for the HPT37[24] based SATA cards * Sergei Shtylyov, or */ @@ -562,6 +562,24 @@ static u8 hpt3xx_udma_filter(ide_drive_t *drive) return check_in_drive_list(drive, bad_ata33) ? 0x00 : mask; } +static u8 hpt3xx_mdma_filter(ide_drive_t *drive) +{ + ide_hwif_t *hwif = HWIF(drive); + struct hpt_info *info = pci_get_drvdata(hwif->pci_dev); + + switch (info->chip_type) { + case HPT372 : + case HPT372A: + case HPT372N: + case HPT374 : + if (ide_dev_is_sata(drive->id)) + return 0x00; + /* Fall thru */ + default: + return 0x07; + } +} + static u32 get_speed_setting(u8 speed, struct hpt_info *info) { int i; @@ -1257,6 +1275,7 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif) hwif->busproc = &hpt3xx_busproc; hwif->udma_filter = &hpt3xx_udma_filter; + hwif->mdma_filter = &hpt3xx_mdma_filter; /* * HPT3xxN chips have some complications: diff --git a/include/linux/ide.h b/include/linux/ide.h index b9f66c10caa..0665428356d 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -723,6 +723,7 @@ typedef struct hwif_s { /* driver soft-power interface */ int (*busproc)(ide_drive_t *, int); #endif + u8 (*mdma_filter)(ide_drive_t *); u8 (*udma_filter)(ide_drive_t *); void (*ata_input_data)(ide_drive_t *, void *, u32); -- cgit v1.2.3-70-g09d2 From 8cb1f567f4c0a2fde9cbf77c2af888a28cab3423 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Thu, 11 Oct 2007 23:53:58 +0200 Subject: ide: Platform IDE driver This is now very similar to pata_platform.c, they both use same platform data structure and same resources. To achieve that, byte_lanes_swapping platform data variable and platform specified iops removed from that driver. It's fine, since those were never used anyway. pata_platform and ide_platform are carrying same driver names, to easily switch between these drivers, without need to touch platform code. Bart: - build fix from Andrew Morton Signed-off-by: Anton Vorontsov Signed-off-by: Vitaly Bordug Cc: Sergei Shtylyov Acked-by: Alan Cox Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/Kconfig | 8 ++ drivers/ide/legacy/Makefile | 2 + drivers/ide/legacy/ide_platform.c | 182 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 192 insertions(+) create mode 100644 drivers/ide/legacy/ide_platform.c (limited to 'drivers') diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index 4200251ff63..75b2737510a 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -308,6 +308,14 @@ config IDE_GENERIC help If unsure, say N. +config BLK_DEV_PLATFORM + tristate "Platform driver for IDE interfaces" + help + This is the platform IDE driver, used mostly for Memory Mapped + IDE devices, like Compact Flashes running in True IDE mode. + + If unsure, say N. + config BLK_DEV_CMD640 bool "CMD640 chipset bugfix/support" depends on X86 diff --git a/drivers/ide/legacy/Makefile b/drivers/ide/legacy/Makefile index c7971061767..409822349f1 100644 --- a/drivers/ide/legacy/Makefile +++ b/drivers/ide/legacy/Makefile @@ -7,6 +7,8 @@ obj-$(CONFIG_BLK_DEV_UMC8672) += umc8672.o obj-$(CONFIG_BLK_DEV_IDECS) += ide-cs.o +obj-$(CONFIG_BLK_DEV_PLATFORM) += ide_platform.o + # Last of all obj-$(CONFIG_BLK_DEV_HD) += hd.o diff --git a/drivers/ide/legacy/ide_platform.c b/drivers/ide/legacy/ide_platform.c new file mode 100644 index 00000000000..ccfb9893a46 --- /dev/null +++ b/drivers/ide/legacy/ide_platform.c @@ -0,0 +1,182 @@ +/* + * Platform IDE driver + * + * Copyright (C) 2007 MontaVista Software + * + * Maintainer: Kumar Gala + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct { + void __iomem *plat_ide_mapbase; + void __iomem *plat_ide_alt_mapbase; + ide_hwif_t *hwif; + int index; +} hwif_prop; + +static ide_hwif_t *__devinit plat_ide_locate_hwif(void __iomem *base, + void __iomem *ctrl, struct pata_platform_info *pdata, int irq, + int mmio) +{ + unsigned long port = (unsigned long)base; + ide_hwif_t *hwif; + int index, i; + + for (index = 0; index < MAX_HWIFS; ++index) { + hwif = ide_hwifs + index; + if (hwif->io_ports[IDE_DATA_OFFSET] == port) + goto found; + } + + for (index = 0; index < MAX_HWIFS; ++index) { + hwif = ide_hwifs + index; + if (hwif->io_ports[IDE_DATA_OFFSET] == 0) + goto found; + } + + return NULL; + +found: + + hwif->hw.io_ports[IDE_DATA_OFFSET] = port; + + port += (1 << pdata->ioport_shift); + for (i = IDE_ERROR_OFFSET; i <= IDE_STATUS_OFFSET; + i++, port += (1 << pdata->ioport_shift)) + hwif->hw.io_ports[i] = port; + + hwif->hw.io_ports[IDE_CONTROL_OFFSET] = (unsigned long)ctrl; + + memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->hw.io_ports)); + hwif->hw.irq = hwif->irq = irq; + + hwif->hw.dma = NO_DMA; + hwif->hw.chipset = ide_generic; + + if (mmio) { + hwif->mmio = 1; + default_hwif_mmiops(hwif); + } + + hwif_prop.hwif = hwif; + hwif_prop.index = index; + + return hwif; +} + +static int __devinit plat_ide_probe(struct platform_device *pdev) +{ + struct resource *res_base, *res_alt, *res_irq; + ide_hwif_t *hwif; + struct pata_platform_info *pdata; + int ret = 0; + int mmio = 0; + + pdata = pdev->dev.platform_data; + + /* get a pointer to the register memory */ + res_base = platform_get_resource(pdev, IORESOURCE_IO, 0); + res_alt = platform_get_resource(pdev, IORESOURCE_IO, 1); + + if (!res_base || !res_alt) { + res_base = platform_get_resource(pdev, IORESOURCE_MEM, 0); + res_alt = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!res_base || !res_alt) { + ret = -ENOMEM; + goto out; + } + mmio = 1; + } + + res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res_irq) { + ret = -EINVAL; + goto out; + } + + if (mmio) { + hwif_prop.plat_ide_mapbase = devm_ioremap(&pdev->dev, + res_base->start, res_base->end - res_base->start + 1); + hwif_prop.plat_ide_alt_mapbase = devm_ioremap(&pdev->dev, + res_alt->start, res_alt->end - res_alt->start + 1); + } else { + hwif_prop.plat_ide_mapbase = devm_ioport_map(&pdev->dev, + res_base->start, res_base->end - res_base->start + 1); + hwif_prop.plat_ide_alt_mapbase = devm_ioport_map(&pdev->dev, + res_alt->start, res_alt->end - res_alt->start + 1); + } + + hwif = plat_ide_locate_hwif(hwif_prop.plat_ide_mapbase, + hwif_prop.plat_ide_alt_mapbase, pdata, res_irq->start, mmio); + + if (!hwif) { + ret = -ENODEV; + goto out; + } + hwif->gendev.parent = &pdev->dev; + hwif->noprobe = 0; + + probe_hwif_init(hwif); + + platform_set_drvdata(pdev, hwif); + ide_proc_register_port(hwif); + + return 0; + +out: + return ret; +} + +static int __devexit plat_ide_remove(struct platform_device *pdev) +{ + ide_hwif_t *hwif = pdev->dev.driver_data; + + if (hwif != hwif_prop.hwif) { + dev_printk(KERN_DEBUG, &pdev->dev, "%s: hwif value error", + pdev->name); + } else { + ide_unregister(hwif_prop.index); + hwif_prop.index = 0; + hwif_prop.hwif = NULL; + } + + return 0; +} + +static struct platform_driver platform_ide_driver = { + .driver = { + .name = "pata_platform", + }, + .probe = plat_ide_probe, + .remove = __devexit_p(plat_ide_remove), +}; + +static int __init platform_ide_init(void) +{ + return platform_driver_register(&platform_ide_driver); +} + +static void __exit platform_ide_exit(void) +{ + platform_driver_unregister(&platform_ide_driver); +} + +MODULE_DESCRIPTION("Platform IDE driver"); +MODULE_LICENSE("GPL"); + +module_init(platform_ide_init); +module_exit(platform_ide_exit); -- cgit v1.2.3-70-g09d2 From 5e32132befa5d2cefadf3141fee0bbb40cd11f0e Mon Sep 17 00:00:00 2001 From: Shaohua Li Date: Thu, 11 Oct 2007 23:53:58 +0200 Subject: ide: hook ACPI _PSx method to IDE power on/off ACPI spec defines the sequence of IDE power on/off: Powering down: Call _GTM. Power down drive (calls _PS3 method and turns off power planes). Powering up: Power up drive (calls _PS0 method if present and turns on power planes). Call _STM passing info from _GTM (possibly modified), with ID data from each drive. Initialize the channel. May modify the results of _GTF. For each drive: Call _GTF. Execute task file (possibly modified). This patch adds the missed _PS0/_PS3 methods call. Signed-off-by: Shaohua Li Acked-by: Len Brown Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/acpi/bus.c | 4 +++- drivers/ide/ide-acpi.c | 42 ++++++++++++++++++++++++++++++++++++++++++ drivers/ide/ide.c | 14 ++++++++++++-- include/linux/ide.h | 2 ++ 4 files changed, 59 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 9ba778a2b48..feab124d8e0 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -262,10 +262,12 @@ int acpi_bus_set_power(acpi_handle handle, int state) printk(KERN_WARNING PREFIX "Transitioning device [%s] to D%d\n", device->pnp.bus_id, state); - else + else { + device->power.state = state; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] transitioned to D%d\n", device->pnp.bus_id, state)); + } return result; } diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c index 17aea65d7dd..6bff81a58bf 100644 --- a/drivers/ide/ide-acpi.c +++ b/drivers/ide/ide-acpi.c @@ -611,6 +611,46 @@ void ide_acpi_push_timing(ide_hwif_t *hwif) } EXPORT_SYMBOL_GPL(ide_acpi_push_timing); +/** + * ide_acpi_set_state - set the channel power state + * @hwif: target IDE interface + * @on: state, on/off + * + * This function executes the _PS0/_PS3 ACPI method to set the power state. + * ACPI spec requires _PS0 when IDE power on and _PS3 when power off + */ +void ide_acpi_set_state(ide_hwif_t *hwif, int on) +{ + int unit; + + if (ide_noacpi) + return; + + DEBPRINT("ENTER:\n"); + + if (!hwif->acpidata) { + DEBPRINT("no ACPI data for %s\n", hwif->name); + return; + } + /* channel first and then drives for power on and verse versa for power off */ + if (on) + acpi_bus_set_power(hwif->acpidata->obj_handle, ACPI_STATE_D0); + for (unit = 0; unit < MAX_DRIVES; ++unit) { + ide_drive_t *drive = &hwif->drives[unit]; + + if (!drive->acpidata->obj_handle) + drive->acpidata->obj_handle = ide_acpi_drive_get_handle(drive); + + if (drive->acpidata->obj_handle && drive->present) { + acpi_bus_set_power(drive->acpidata->obj_handle, + on? ACPI_STATE_D0: ACPI_STATE_D3); + } + } + if (!on) + acpi_bus_set_power(hwif->acpidata->obj_handle, ACPI_STATE_D3); +} +EXPORT_SYMBOL_GPL(ide_acpi_set_state); + /** * ide_acpi_init - initialize the ACPI link for an IDE interface * @hwif: target IDE interface (channel) @@ -679,6 +719,8 @@ void ide_acpi_init(ide_hwif_t *hwif) return; } + /* ACPI _PS0 before _STM */ + ide_acpi_set_state(hwif, 1); /* * ACPI requires us to call _STM on startup */ diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index de54306789a..9fdc1fe1b29 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -915,6 +915,7 @@ static int generic_ide_suspend(struct device *dev, pm_message_t mesg) struct request rq; struct request_pm_state rqpm; ide_task_t args; + int ret; /* Call ACPI _GTM only once */ if (!(drive->dn % 2)) @@ -931,7 +932,14 @@ static int generic_ide_suspend(struct device *dev, pm_message_t mesg) mesg.event = PM_EVENT_FREEZE; rqpm.pm_state = mesg.event; - return ide_do_drive_cmd(drive, &rq, ide_wait); + ret = ide_do_drive_cmd(drive, &rq, ide_wait); + /* only call ACPI _PS3 after both drivers are suspended */ + if (!ret && (((drive->dn % 2) && hwif->drives[0].present + && hwif->drives[1].present) + || !hwif->drives[0].present + || !hwif->drives[1].present)) + ide_acpi_set_state(hwif, 0); + return ret; } static int generic_ide_resume(struct device *dev) @@ -944,8 +952,10 @@ static int generic_ide_resume(struct device *dev) int err; /* Call ACPI _STM only once */ - if (!(drive->dn % 2)) + if (!(drive->dn % 2)) { + ide_acpi_set_state(hwif, 1); ide_acpi_push_timing(hwif); + } ide_acpi_exec_tfs(drive); diff --git a/include/linux/ide.h b/include/linux/ide.h index 0665428356d..80ea946282d 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -1338,11 +1338,13 @@ extern int ide_acpi_exec_tfs(ide_drive_t *drive); extern void ide_acpi_get_timing(ide_hwif_t *hwif); extern void ide_acpi_push_timing(ide_hwif_t *hwif); extern void ide_acpi_init(ide_hwif_t *hwif); +extern void ide_acpi_set_state(ide_hwif_t *hwif, int on); #else static inline int ide_acpi_exec_tfs(ide_drive_t *drive) { return 0; } static inline void ide_acpi_get_timing(ide_hwif_t *hwif) { ; } static inline void ide_acpi_push_timing(ide_hwif_t *hwif) { ; } static inline void ide_acpi_init(ide_hwif_t *hwif) { ; } +static inline void ide_acpi_set_state(ide_hwif_t *hwif, int on) {} #endif extern int ide_hwif_request_regions(ide_hwif_t *hwif); -- cgit v1.2.3-70-g09d2 From 07047935795917f21dc532c0c17811213cbc2e97 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Thu, 11 Oct 2007 23:53:58 +0200 Subject: pdc202xx_new: switch to using pci_get_slot() (take 2) Switch to using pci_get_slot() in init_setup_pdc20270() to get to the mate chip behind DC21150 bridge as there's no need for the driver itself to walk the list of the PCI devices (and the driver didn't check the bus # of the found device). While at it, make it emit warning about IRQ # being fixed up (just like hpt366.c does) and "beautify" this whole function as well as init_setup_pdc20276()... Signed-off-by: Sergei Shtylyov Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/pdc202xx_new.c | 60 ++++++++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c index 7b0e479c355..7c5544d10b9 100644 --- a/drivers/ide/pci/pdc202xx_new.c +++ b/drivers/ide/pci/pdc202xx_new.c @@ -524,44 +524,52 @@ static int __devinit init_setup_pdcnew(struct pci_dev *dev, ide_pci_device_t *d) return ide_setup_pci_device(dev, d); } -static int __devinit init_setup_pdc20270(struct pci_dev *dev, - ide_pci_device_t *d) +static int __devinit init_setup_pdc20270(struct pci_dev *dev, ide_pci_device_t *d) { - struct pci_dev *findev = NULL; - int ret; + struct pci_dev *bridge = dev->bus->self; + + if (bridge != NULL && + bridge->vendor == PCI_VENDOR_ID_DEC && + bridge->device == PCI_DEVICE_ID_DEC_21150) { + struct pci_dev *dev2; - if ((dev->bus->self && - dev->bus->self->vendor == PCI_VENDOR_ID_DEC) && - (dev->bus->self->device == PCI_DEVICE_ID_DEC_21150)) { if (PCI_SLOT(dev->devfn) & 2) return -ENODEV; - while ((findev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, findev)) != NULL) { - if ((findev->vendor == dev->vendor) && - (findev->device == dev->device) && - (PCI_SLOT(findev->devfn) & 2)) { - if (findev->irq != dev->irq) { - findev->irq = dev->irq; - } - ret = ide_setup_pci_devices(dev, findev, d); - if (ret < 0) - pci_dev_put(findev); - return ret; + dev2 = pci_get_slot(dev->bus, PCI_DEVFN(PCI_SLOT(dev->devfn) + 2, + PCI_FUNC(dev->devfn))); + if (dev2 != NULL && + dev2->vendor == dev->vendor && + dev2->device == dev->device) { + int ret; + + if (dev2->irq != dev->irq) { + dev2->irq = dev->irq; + + printk(KERN_WARNING "%s: PCI config space " + "interrupt fixed.\n", d->name); } + + ret = ide_setup_pci_devices(dev, dev2, d); + if (ret < 0) + pci_dev_put(dev2); + return ret; } } return ide_setup_pci_device(dev, d); } -static int __devinit init_setup_pdc20276(struct pci_dev *dev, - ide_pci_device_t *d) +static int __devinit init_setup_pdc20276(struct pci_dev *dev, ide_pci_device_t *d) { - if ((dev->bus->self) && - (dev->bus->self->vendor == PCI_VENDOR_ID_INTEL) && - ((dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960) || - (dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960RM))) { - printk(KERN_INFO "ide: Skipping Promise PDC20276 " - "attached to I2O RAID controller.\n"); + struct pci_dev *bridge = dev->bus->self; + + if (bridge != NULL && + bridge->vendor == PCI_VENDOR_ID_INTEL && + (bridge->device == PCI_DEVICE_ID_INTEL_I960 || + bridge->device == PCI_DEVICE_ID_INTEL_I960RM)) { + + printk(KERN_INFO "%s: attached to I2O RAID controller, " + "skipping.\n", d->name); return -ENODEV; } return ide_setup_pci_device(dev, d); -- cgit v1.2.3-70-g09d2 From bda7970c27b1033de0afa737cd8e5abf9c55c3d2 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 11 Oct 2007 23:53:59 +0200 Subject: ide: make jmicron match vendor and device class PATA part of all current JMB controllers behave the same way and JMicron confirms that all future ones will stay compatible. Matching vendor and device class is enough. For backward compatibility, jmicron still needs to match 361,3,5,6,8 DIDs regardless of device class if libata is not configured but won't need further DID update from this point. Bart: cosmetic fixes to jmicron_chipset Signed-off-by: Tejun Heo Cc: Ethan Hsiao Cc: Justin Tsai Cc: Alan Cox Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/jmicron.c | 65 ++++++++++++++++++----------------------------- 1 file changed, 25 insertions(+), 40 deletions(-) (limited to 'drivers') diff --git a/drivers/ide/pci/jmicron.c b/drivers/ide/pci/jmicron.c index 65a0ff352b9..17490d25575 100644 --- a/drivers/ide/pci/jmicron.c +++ b/drivers/ide/pci/jmicron.c @@ -160,22 +160,13 @@ fallback: return; } -#define DECLARE_JMB_DEV(name_str) \ - { \ - .name = name_str, \ - .init_hwif = init_hwif_jmicron, \ - .autodma = AUTODMA, \ - .bootable = ON_BOARD, \ - .enablebits = { {0x40, 1, 1}, {0x40, 0x10, 0x10} }, \ - .pio_mask = ATA_PIO5, \ - } - -static ide_pci_device_t jmicron_chipsets[] __devinitdata = { - /* 0 */ DECLARE_JMB_DEV("JMB361"), - /* 1 */ DECLARE_JMB_DEV("JMB363"), - /* 2 */ DECLARE_JMB_DEV("JMB365"), - /* 3 */ DECLARE_JMB_DEV("JMB366"), - /* 4 */ DECLARE_JMB_DEV("JMB368"), +static ide_pci_device_t jmicron_chipset __devinitdata = { + .name = "JMB", + .init_hwif = init_hwif_jmicron, + .autodma = AUTODMA, + .bootable = ON_BOARD, + .enablebits = { { 0x40, 0x01, 0x01 }, { 0x40, 0x10, 0x10 } }, + .pio_mask = ATA_PIO5, }; /** @@ -189,35 +180,29 @@ static ide_pci_device_t jmicron_chipsets[] __devinitdata = { static int __devinit jmicron_init_one(struct pci_dev *dev, const struct pci_device_id *id) { - ide_setup_pci_device(dev, &jmicron_chipsets[id->driver_data]); + ide_setup_pci_device(dev, &jmicron_chipset); return 0; } -/* If libata is configured, jmicron PCI quirk will configure it such - * that the SATA ports are in AHCI function while the PATA ports are - * in a separate IDE function. In such cases, match device class and - * attach only to IDE. If libata isn't configured, keep the old - * behavior for backward compatibility. +/* All JMB PATA controllers have and will continue to have the same + * interface. Matching vendor and device class is enough for all + * current and future controllers if the controller is programmed + * properly. + * + * If libata is configured, jmicron PCI quirk programs the controller + * into the correct mode. If libata isn't configured, match known + * device IDs too to maintain backward compatibility. */ -#if defined(CONFIG_ATA) || defined(CONFIG_ATA_MODULE) -#define JMB_CLASS PCI_CLASS_STORAGE_IDE << 8 -#define JMB_CLASS_MASK 0xffff00 -#else -#define JMB_CLASS 0 -#define JMB_CLASS_MASK 0 -#endif - static struct pci_device_id jmicron_pci_tbl[] = { - { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB361, - PCI_ANY_ID, PCI_ANY_ID, JMB_CLASS, JMB_CLASS_MASK, 0}, - { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB363, - PCI_ANY_ID, PCI_ANY_ID, JMB_CLASS, JMB_CLASS_MASK, 1}, - { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB365, - PCI_ANY_ID, PCI_ANY_ID, JMB_CLASS, JMB_CLASS_MASK, 2}, - { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB366, - PCI_ANY_ID, PCI_ANY_ID, JMB_CLASS, JMB_CLASS_MASK, 3}, - { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB368, - PCI_ANY_ID, PCI_ANY_ID, JMB_CLASS, JMB_CLASS_MASK, 4}, +#if !defined(CONFIG_ATA) && !defined(CONFIG_ATA_MODULE) + { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB361) }, + { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB363) }, + { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB365) }, + { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB366) }, + { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB368) }, +#endif + { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 0 }, { 0, }, }; -- cgit v1.2.3-70-g09d2 From 851dd33bcf23655eede62730c029e4f608f4084f Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Thu, 11 Oct 2007 23:53:59 +0200 Subject: ide: call udma_filter() before resorting to the UltraDMA mask Give the udma_filter() method call precedence over using the mode masks. Signed-off-by: Sergei Shtylyov Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/ide-dma.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c index 097d6e9865b..f073ea35da0 100644 --- a/drivers/ide/ide-dma.c +++ b/drivers/ide/ide-dma.c @@ -664,10 +664,11 @@ static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base) if ((id->field_valid & 4) == 0) break; - mask = id->dma_ultra & hwif->ultra_mask; - if (hwif->udma_filter) - mask &= hwif->udma_filter(drive); + mask = hwif->udma_filter(drive); + else + mask = hwif->ultra_mask; + mask &= id->dma_ultra; if ((mask & 0x78) && (eighty_ninty_three(drive) == 0)) mask &= 0x07; -- cgit v1.2.3-70-g09d2 From a8028fcb485522c0d7de9c5423812de9224b37c9 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Thu, 11 Oct 2007 23:53:59 +0200 Subject: ide: add missing ide_rate_filter() calls to ->speedproc()-s * Fix icside, cris-ide, au1xxx-ide, amd74xx, via82cxxx and pmac host drivers to use ide_rate_filter(). This results in the following modes (from user requests) being clipped down: - invalid modes (values 0x46-0xFF) [ for all hosts ] - unsupported by a host UDMA modes [ for hosts which support UDMA] - all UDMA modes and MWDMA3-4 modes [ for hosts which don't support UDMA ] - invalid modes (values 0x25-0x39) [ for hosts which don't support UDMA ] * Host driver specific changes in behavior: icside: - no change cris-ide - clip unsupported UDMA3-6 modes down - fix BUG() on trying to set unsupported UDMA3-6 modes au1xxx-ide/pmac - clip unsupported UDMA modes down amd74xx/via82cxxx - clip unsupported UDMA modes down - fix random PIO timings being set for unsupported/invalid modes - fix unsupported/invalid modes being set on the device * While at it remove no longer needed checks from pmac.c driver. Acked-by: Sergei Shtylyov Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/arm/icside.c | 3 +-- drivers/ide/cris/ide-cris.c | 2 ++ drivers/ide/mips/au1xxx-ide.c | 2 ++ drivers/ide/pci/amd74xx.c | 2 ++ drivers/ide/pci/via82cxxx.c | 2 ++ drivers/ide/ppc/pmac.c | 10 ++-------- 6 files changed, 11 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/ide/arm/icside.c b/drivers/ide/arm/icside.c index 8a9b98fcb66..28f910b5aa5 100644 --- a/drivers/ide/arm/icside.c +++ b/drivers/ide/arm/icside.c @@ -255,8 +255,7 @@ static int icside_set_speed(ide_drive_t *drive, u8 xfer_mode) /* * Limit the transfer speed to MW_DMA_2. */ - if (xfer_mode > XFER_MW_DMA_2) - xfer_mode = XFER_MW_DMA_2; + xfer_mode = ide_rate_filter(drive, xfer_mode); switch (xfer_mode) { case XFER_MW_DMA_2: diff --git a/drivers/ide/cris/ide-cris.c b/drivers/ide/cris/ide-cris.c index 04636f7eaae..e08782ac88e 100644 --- a/drivers/ide/cris/ide-cris.c +++ b/drivers/ide/cris/ide-cris.c @@ -726,6 +726,8 @@ static int speed_cris_ide(ide_drive_t *drive, u8 speed) { int cyc = 0, dvs = 0, strobe = 0, hold = 0; + speed = ide_rate_filter(drive, speed); + if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) { tune_cris_ide(drive, speed - XFER_PIO_0); return ide_config_drive_speed(drive, speed); diff --git a/drivers/ide/mips/au1xxx-ide.c b/drivers/ide/mips/au1xxx-ide.c index 2ba6a054b86..0d5e4c67fa5 100644 --- a/drivers/ide/mips/au1xxx-ide.c +++ b/drivers/ide/mips/au1xxx-ide.c @@ -180,6 +180,8 @@ static int auide_tune_chipset (ide_drive_t *drive, u8 speed) int mem_sttime; int mem_stcfg; + speed = ide_rate_filter(drive, speed); + mem_sttime = 0; mem_stcfg = au_readl(MEM_STCFG2); diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c index 06c15a6a3e7..3c0bb1e7951 100644 --- a/drivers/ide/pci/amd74xx.c +++ b/drivers/ide/pci/amd74xx.c @@ -240,6 +240,8 @@ static int amd_set_drive(ide_drive_t *drive, u8 speed) struct ide_timing t, p; int T, UT; + speed = ide_rate_filter(drive, speed); + if (speed != XFER_PIO_SLOW) ide_config_drive_speed(drive, speed); diff --git a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c index a7be7795e6a..ec9ad6e0e1f 100644 --- a/drivers/ide/pci/via82cxxx.c +++ b/drivers/ide/pci/via82cxxx.c @@ -165,6 +165,8 @@ static int via_set_drive(ide_drive_t *drive, u8 speed) struct ide_timing t, p; unsigned int T, UT; + speed = ide_rate_filter(drive, speed); + if (speed != XFER_PIO_SLOW) ide_config_drive_speed(drive, speed); diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c index 2fb047b898a..222adcb5482 100644 --- a/drivers/ide/ppc/pmac.c +++ b/drivers/ide/ppc/pmac.c @@ -928,6 +928,8 @@ pmac_ide_tune_chipset (ide_drive_t *drive, byte speed) pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data; u32 *timings, *timings2; + speed = ide_rate_filter(drive, speed); + if (pmif == NULL) return 1; @@ -937,17 +939,9 @@ pmac_ide_tune_chipset (ide_drive_t *drive, byte speed) switch(speed) { #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC case XFER_UDMA_6: - if (pmif->kind != controller_sh_ata6) - return 1; case XFER_UDMA_5: - if (pmif->kind != controller_un_ata6 && - pmif->kind != controller_k2_ata6 && - pmif->kind != controller_sh_ata6) - return 1; case XFER_UDMA_4: case XFER_UDMA_3: - if (drive->hwif->cbl != ATA_CBL_PATA80) - return 1; case XFER_UDMA_2: case XFER_UDMA_1: case XFER_UDMA_0: -- cgit v1.2.3-70-g09d2 From 7670df73fba373d19471a2ebedb3302ea0607be0 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Thu, 11 Oct 2007 23:53:59 +0200 Subject: ide: mode limiting fixes for user requested speed changes * Add an extra argument to ide_max_dma_mode() for passing requested transfer mode. Use it as an upper limit when finding the best DMA for device/host. * Rename ide_max_dma_mode() to ide_find_dma_mode() and at the same time add ide_max_dma_mode() wrapper which passes XFER_UDMA_6 as a requested mode to ide_find_dma_mode(). Also add inline ide_find_dma_mode() version for CONFIG_BLK_DEV_IDEDMA=n case. * Pass requested transfer mode from ide_find_dma_mode() to ide_get_mode_mask() to avoid false warning from eighty_ninty_three(). * Use ide_find_dma_mode() to limit the user requested transfer mode in ide_rate_filter(). Also limit the requested mode by host max PIO mode. Above changes make ide_rate_filter() to: * Clip desired transfer mode down if it is invalid (values 0x0F, 0x13-0x19 and 0x25-0x39, values > 0x46 were already clipped down, same for values 0x25-0x39 but iff UDMA was not supported by the host). * Clip desired transfer mode down if it is currently unsupported by IDE core (PIO6 and MWDMA3-4, the latter were already clipped down but iff UDMA was not supported by the host). * Clip desired transfer mode down according to the host capabilities (UDMA modes were already clipped down but MWDMA/SWDMA/PIO weren't, also ->atapi_dma flag was not respected). * Clip desired transfer mode down according to the device capabilities (except PIO modes for now which require mode work) - shouldn't be a problem since ide_set_xfer_rate() is called _after_ device has accepted given transfer mode. and also result in a number of host driver specific bugfixes: * icside - clip unsupported PIO5 mode down - fix unsupported/invalid modes being set in drive->current_speed * ide-cris - clip unsupported PIO5 and SWDMA0-2 modes down - clip DMA modes down for ATAPI devices - fix BUG() on unsupported/invalid modes * au1xxx-ide - clip unsupported PIO5, SWDMA0-2 and MWDMA0-2 (if BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA=n) modes down * aec62xx - clip unsupported PIO5 and SWDMA0-2 modes down - clip DMA modes down for ATAPI devices - fix 0x00 being programmed as PIO timing for unsupported/invalid modes - fix unsupported/invalid modes being set on the device * alim15x3 - clip DMA modes down for ATAPI devices (chipset revision == 0x20 only) - fix theoretical OOPS for 0x0F mode - fix unsupported/invalid modes being set on the device * amd74xx - clip unsupported SWDMA0-2 (on COBRA_7401 revs <= 7) modes down - fix random PIO timings being set for unsupported/invalid modes - fix unsupported/invalid modes being set on the device * atiixp - clip unsupported PIO5 and SWDMA0-2 modes down - fix cached MWDMA mode being cleared for unsupported/invalid modes - fix PIO{0,2} timings being programmed for unsupported/invalid modes - fix theoretical OOPS for PIO5-6 and 0x0F modes - fix unsupported/invalid modes being set on the device * cmd64x - clip unsupported SWDMA0-2 modes down * cs5530 - clip unsupported PIO5 and SWDMA0-2 modes down - fix unsupported/invalid modes being set on the device - fix BUG() on unsupported/invalid modes (which happened if the device accepted the setting) * cs5535 - clip unsupported PIO5 and SWDMA0-2 modes down - fix unsupported/invalid modes being set on the device - fix theoretical OOPS for PIO5-6 and 0x0F modes * hpt34x - clip DMA modes down for ATAPI devices - fix invalid timings being programmed for unsupported/invalid modes - fix unsupported/invalid modes being set on the device * hpt366 - clip unsupported PIO5 and SWDMA0-2 modes down - fix PIO0 timings being programmed for unsupported/invalid modes - fix DMA timings being cleared for MWDMA3-4 and 0x25-0x39 modes - fix unsupported/invalid modes being set on the device * it8213 - clip unsupported PIO5, SWDMA0-1 and MWDMA0 modes down * it821x - clip unsupported PIO5 and SWDMA0-2 modes down - clip DMA modes down for ATAPI devices (chipset in smart mode and revision 0x10 in pass-through mode) * jmicron - clip unsupported SWDMA0-2 modes down - fix unsupported/invalid modes being set on the device * pdc202xx_new - clip unsupported PIO5 and SWDMA0-2 modes down - fix unsupported/invalid modes being set on the device * pdc202xx_old - clip unsupported PIO5 mode down - fix incorrect timings being set for unsupported/invalid modes - fix unsupported/invalid modes being set on the device * piix - clip unsupported PIO5, SWDMA0-1 and MWDMA0 modes down * sc1200 - clip unsupported PIO5 and SWDMA0-2 modes down - fix unsupported/invalid modes being set on the device - fix BUG() on unsupported/invalid modes (which happened if the device accepted the setting) * scc_pata - clip unsupported PIO5, SWDMA0-2 and MWDMA0-2 modes down * serverworks - clip unsupported PIO5 and SWDMA0-2 modes down - fix DMA/UDMA timings/settings being cleared for unsupported/invalid modes - fix unsupported/invalid modes being set on the device * siimage - clip unsupported PIO5 and SWDMA0-2 modes down - clip DMA modes down for ATAPI devices (SATA chipsets) * sis5513 - clip unsupported PIO5 mode down - fix BUG() on unsupported/invalid modes * sl82c105 - clip unsupported SWDMA0-2 modes down * slc90e66 - clip unsupported PIO5, SWDMA0-1 and MWDMA0 modes down * tc86c001 - clip unsupported PIO5 and SWDMA0-2 modes down - fix PIO0 timings being programmed for PIO5/0x0F/SWDMA0-2/0x13-0x19 modes - fix invalid 0x00 DMA timing being programmed for MWDMA3-4/0x25-0x39 modes - fix unsupported/invalid modes being set on the device * triflex - clip unsupported PIO5 mode down * via82cxxx - fix random PIO timings being set for unsupported/invalid modes - fix unsupported/invalid modes being set on the device * pmac - clip unsupported PIO5 and SWDMA0-2 modes down * cmd640/ht6560b - clip DMA modes down (if CONFIG_BLK_DEV_IDEDMA=y) - fix PIO5 being clipped to PIO4 (if CONFIG_BLK_DEV_IDEDMA=n) * opti621 - clip DMA modes down (if CONFIG_BLK_DEV_IDEDMA=y) - clip unsupported PIO4 to PIO3 (if CONFIG_BLK_DEV_IDEDMA=n) While at it: * Use ide_rate_filter() in cs5520.c::cs5520_tune_chipset(). * Remove no longer needed checks from hpt366.c::hpt3{6,7}x_tune_chipset(). Acked-by: Sergei Shtylyov Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/ide-dma.c | 32 +++++++++++++++++++++----------- drivers/ide/ide-lib.c | 29 ++++++++--------------------- drivers/ide/pci/cs5520.c | 2 +- drivers/ide/pci/hpt366.c | 8 -------- include/linux/ide.h | 10 +++++++++- 5 files changed, 39 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c index f073ea35da0..6000c08f51b 100644 --- a/drivers/ide/ide-dma.c +++ b/drivers/ide/ide-dma.c @@ -653,7 +653,7 @@ static const u8 xfer_mode_bases[] = { XFER_SW_DMA_0, }; -static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base) +static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base, u8 req_mode) { struct hd_driveid *id = drive->id; ide_hwif_t *hwif = drive->hwif; @@ -670,8 +670,13 @@ static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base) mask = hwif->ultra_mask; mask &= id->dma_ultra; - if ((mask & 0x78) && (eighty_ninty_three(drive) == 0)) - mask &= 0x07; + /* + * avoid false cable warning from eighty_ninty_three() + */ + if (req_mode > XFER_UDMA_2) { + if ((mask & 0x78) && (eighty_ninty_three(drive) == 0)) + mask &= 0x07; + } break; case XFER_MW_DMA_0: if ((id->field_valid & 2) == 0) @@ -709,15 +714,18 @@ static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base) } /** - * ide_max_dma_mode - compute DMA speed + * ide_find_dma_mode - compute DMA speed * @drive: IDE device + * @req_mode: requested mode + * + * Checks the drive/host capabilities and finds the speed to use for + * the DMA transfer. The speed is then limited by the requested mode. * - * Checks the drive capabilities and returns the speed to use - * for the DMA transfer. Returns 0 if the drive is incapable - * of DMA transfers. + * Returns 0 if the drive/host combination is incapable of DMA transfers + * or if the requested mode is not a DMA mode. */ -u8 ide_max_dma_mode(ide_drive_t *drive) +u8 ide_find_dma_mode(ide_drive_t *drive, u8 req_mode) { ide_hwif_t *hwif = drive->hwif; unsigned int mask; @@ -728,7 +736,9 @@ u8 ide_max_dma_mode(ide_drive_t *drive) return 0; for (i = 0; i < ARRAY_SIZE(xfer_mode_bases); i++) { - mask = ide_get_mode_mask(drive, xfer_mode_bases[i]); + if (req_mode < xfer_mode_bases[i]) + continue; + mask = ide_get_mode_mask(drive, xfer_mode_bases[i], req_mode); x = fls(mask) - 1; if (x >= 0) { mode = xfer_mode_bases[i] + x; @@ -738,10 +748,10 @@ u8 ide_max_dma_mode(ide_drive_t *drive) printk(KERN_DEBUG "%s: selected mode 0x%x\n", drive->name, mode); - return mode; + return min(mode, req_mode); } -EXPORT_SYMBOL_GPL(ide_max_dma_mode); +EXPORT_SYMBOL_GPL(ide_find_dma_mode); int ide_tune_dma(ide_drive_t *drive) { diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c index 92a6c7bcf52..41a128f5211 100644 --- a/drivers/ide/ide-lib.c +++ b/drivers/ide/ide-lib.c @@ -76,37 +76,24 @@ EXPORT_SYMBOL(ide_xfer_verbose); * Given the available transfer modes this function returns * the best available speed at or below the speed requested. * - * FIXME: filter also PIO/SWDMA/MWDMA modes + * TODO: check device PIO capabilities */ u8 ide_rate_filter(ide_drive_t *drive, u8 speed) { -#ifdef CONFIG_BLK_DEV_IDEDMA ide_hwif_t *hwif = drive->hwif; - u8 mask = hwif->ultra_mask, mode = XFER_MW_DMA_2; - - if (hwif->udma_filter) - mask = hwif->udma_filter(drive); - - /* - * TODO: speed > XFER_UDMA_2 extra check is needed to avoid false - * cable warning from eighty_ninty_three(), moving ide_rate_filter() - * calls from ->speedproc to core code will make this hack go away - */ - if (speed > XFER_UDMA_2) { - if ((mask & 0x78) && (eighty_ninty_three(drive) == 0)) - mask &= 0x07; - } + u8 mode = ide_find_dma_mode(drive, speed); - if (mask) - mode = fls(mask) - 1 + XFER_UDMA_0; + if (mode == 0) { + if (hwif->pio_mask) + mode = fls(hwif->pio_mask) - 1 + XFER_PIO_0; + else + mode = XFER_PIO_4; + } // printk("%s: mode 0x%02x, speed 0x%02x\n", __FUNCTION__, mode, speed); return min(speed, mode); -#else /* !CONFIG_BLK_DEV_IDEDMA */ - return min(speed, (u8)XFER_PIO_4); -#endif /* CONFIG_BLK_DEV_IDEDMA */ } EXPORT_SYMBOL(ide_rate_filter); diff --git a/drivers/ide/pci/cs5520.c b/drivers/ide/pci/cs5520.c index b89e8165687..507981042c8 100644 --- a/drivers/ide/pci/cs5520.c +++ b/drivers/ide/pci/cs5520.c @@ -70,7 +70,7 @@ static int cs5520_tune_chipset(ide_drive_t *drive, u8 xferspeed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *pdev = hwif->pci_dev; - u8 speed = min((u8)XFER_PIO_4, xferspeed); + u8 speed = ide_rate_filter(drive, xferspeed); int pio = speed; u8 reg; int controller = drive->dn > 1 ? 1 : 0; diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c index 3d8d6b2ee41..18c8ad091eb 100644 --- a/drivers/ide/pci/hpt366.c +++ b/drivers/ide/pci/hpt366.c @@ -610,10 +610,6 @@ static int hpt36x_tune_chipset(ide_drive_t *drive, u8 xferspeed) u32 old_itr = 0; u32 itr_mask, new_itr; - /* TODO: move this to ide_rate_filter() [ check ->atapi_dma ] */ - if (drive->media != ide_disk) - speed = min_t(u8, speed, XFER_PIO_4); - itr_mask = speed < XFER_MW_DMA_0 ? 0x30070000 : (speed < XFER_UDMA_0 ? 0xc0070000 : 0xc03800ff); @@ -642,10 +638,6 @@ static int hpt37x_tune_chipset(ide_drive_t *drive, u8 xferspeed) u32 old_itr = 0; u32 itr_mask, new_itr; - /* TODO: move this to ide_rate_filter() [ check ->atapi_dma ] */ - if (drive->media != ide_disk) - speed = min_t(u8, speed, XFER_PIO_4); - itr_mask = speed < XFER_MW_DMA_0 ? 0x303c0000 : (speed < XFER_UDMA_0 ? 0xc03c0000 : 0xc1c001ff); diff --git a/include/linux/ide.h b/include/linux/ide.h index 80ea946282d..a3f9c216615 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -1296,7 +1296,14 @@ int ide_in_drive_list(struct hd_driveid *, const struct drive_list_entry *); #ifdef CONFIG_BLK_DEV_IDEDMA int __ide_dma_bad_drive(ide_drive_t *); int __ide_dma_good_drive(ide_drive_t *); -u8 ide_max_dma_mode(ide_drive_t *); + +u8 ide_find_dma_mode(ide_drive_t *, u8); + +static inline u8 ide_max_dma_mode(ide_drive_t *drive) +{ + return ide_find_dma_mode(drive, XFER_UDMA_6); +} + int ide_tune_dma(ide_drive_t *); void ide_dma_off(ide_drive_t *); void ide_dma_verbose(ide_drive_t *); @@ -1322,6 +1329,7 @@ extern void ide_dma_timeout(ide_drive_t *); #endif /* CONFIG_BLK_DEV_IDEDMA_PCI */ #else +static inline u8 ide_find_dma_mode(ide_drive_t *drive, u8 speed) { return 0; } static inline u8 ide_max_dma_mode(ide_drive_t *drive) { return 0; } static inline int ide_tune_dma(ide_drive_t *drive) { return 0; } static inline void ide_dma_off(ide_drive_t *drive) { ; } -- cgit v1.2.3-70-g09d2 From 3160d5416f39da9d9221fec7cb9d64399b706bbc Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Thu, 11 Oct 2007 23:53:59 +0200 Subject: sis5513: add ->udma_filter method for chipset_family >= ATA_133 * Add sis5513_ata133_udma_filter() for chipset_family >= ATA_133, use it to filter UDMA6 mode if ATA133 bit is disabled. * Remove no longer needed UDMA6 limiting logic from sis5513_tune_chipset(). * Bump driver version. There should be no functionality changes caused by this patch. Acked-by: Sergei Shtylyov Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/sis5513.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c index 26f24802d3e..1da037f1394 100644 --- a/drivers/ide/pci/sis5513.c +++ b/drivers/ide/pci/sis5513.c @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/pci/sis5513.c Version 0.25 Jun 10, 2007 + * linux/drivers/ide/pci/sis5513.c Version 0.26 Jul 7, 2007 * * Copyright (C) 1999-2000 Andre Hedrick * Copyright (C) 2002 Lionel Bouton , Maintainer @@ -582,9 +582,6 @@ static int sis5513_tune_chipset (ide_drive_t *drive, u8 xferspeed) regdw |= (unsigned long)cycle_time_value[ATA_133][speed-XFER_UDMA_0] << 4; regdw |= (unsigned long)cvs_time_value[ATA_133][speed-XFER_UDMA_0] << 8; } else { - /* if ATA133 disable, we should not set speed above UDMA5 */ - if (speed > XFER_UDMA_5) - speed = XFER_UDMA_5; regdw |= (unsigned long)cycle_time_value[ATA_100][speed-XFER_UDMA_0] << 4; regdw |= (unsigned long)cvs_time_value[ATA_100][speed-XFER_UDMA_0] << 8; } @@ -640,6 +637,20 @@ static int sis5513_config_xfer_rate(ide_drive_t *drive) return -1; } +static u8 sis5513_ata133_udma_filter(ide_drive_t *drive) +{ + struct pci_dev *dev = drive->hwif->pci_dev; + int drive_pci; + u32 reg54 = 0, regdw = 0; + + pci_read_config_dword(dev, 0x54, ®54); + drive_pci = ((reg54 & 0x40000000) ? 0x70 : 0x40) + drive->dn * 4; + pci_read_config_dword(dev, drive_pci, ®dw); + + /* if ATA133 disable, we should not set speed above UDMA5 */ + return (regdw & 0x08) ? ATA_UDMA6 : ATA_UDMA5; +} + /* Chip detection and general config */ static unsigned int __devinit init_chipset_sis5513 (struct pci_dev *dev, const char *name) { @@ -847,6 +858,9 @@ static void __devinit init_hwif_sis5513 (ide_hwif_t *hwif) hwif->tuneproc = &sis5513_tuneproc; hwif->speedproc = &sis5513_tune_chipset; + if (chipset_family >= ATA_133) + hwif->udma_filter = sis5513_ata133_udma_filter; + if (!(hwif->dma_base)) { hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; -- cgit v1.2.3-70-g09d2 From f212ff28f08e4ddcef9f25b13463c45cc4204a0c Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Thu, 11 Oct 2007 23:53:59 +0200 Subject: ide: move ide_rate_filter() calls to the upper layer (take 2) * Move ide_rate_filter() calls from host drivers to IDE core. * Make ide_rate_filter() static. * Make 'speed' argument of ->speedproc const. v2: * Fix it8213_tune_chipset() comment. There should be no functionality changes caused by this patch. Acked-by: Sergei Shtylyov Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/arm/icside.c | 7 +------ drivers/ide/cris/ide-cris.c | 4 +--- drivers/ide/ide-lib.c | 17 ++++++++--------- drivers/ide/mips/au1xxx-ide.c | 4 +--- drivers/ide/pci/aec62xx.c | 6 ++---- drivers/ide/pci/alim15x3.c | 7 +++---- drivers/ide/pci/amd74xx.c | 4 +--- drivers/ide/pci/atiixp.c | 8 +++----- drivers/ide/pci/cmd64x.c | 4 +--- drivers/ide/pci/cs5520.c | 5 ++--- drivers/ide/pci/cs5530.c | 4 +--- drivers/ide/pci/cs5535.c | 3 +-- drivers/ide/pci/hpt34x.c | 3 +-- drivers/ide/pci/hpt366.c | 6 ++---- drivers/ide/pci/it8213.c | 10 +++------- drivers/ide/pci/it821x.c | 10 +++------- drivers/ide/pci/jmicron.c | 9 +++------ drivers/ide/pci/pdc202xx_new.c | 4 +--- drivers/ide/pci/pdc202xx_old.c | 3 +-- drivers/ide/pci/piix.c | 7 +++---- drivers/ide/pci/sc1200.c | 4 +--- drivers/ide/pci/scc_pata.c | 5 ++--- drivers/ide/pci/serverworks.c | 3 +-- drivers/ide/pci/siimage.c | 11 ++++------- drivers/ide/pci/sis5513.c | 7 ++----- drivers/ide/pci/sl82c105.c | 4 +--- drivers/ide/pci/slc90e66.c | 3 +-- drivers/ide/pci/tc86c001.c | 4 +--- drivers/ide/pci/triflex.c | 3 +-- drivers/ide/pci/via82cxxx.c | 4 +--- drivers/ide/ppc/pmac.c | 6 +----- include/linux/ide.h | 3 +-- 32 files changed, 59 insertions(+), 123 deletions(-) (limited to 'drivers') diff --git a/drivers/ide/arm/icside.c b/drivers/ide/arm/icside.c index 28f910b5aa5..99a27f2dc03 100644 --- a/drivers/ide/arm/icside.c +++ b/drivers/ide/arm/icside.c @@ -248,15 +248,10 @@ static void icside_build_sglist(ide_drive_t *drive, struct request *rq) * MW1 80 50 50 150 C * MW2 70 25 25 120 C */ -static int icside_set_speed(ide_drive_t *drive, u8 xfer_mode) +static int icside_set_speed(ide_drive_t *drive, const u8 xfer_mode) { int on = 0, cycle_time = 0, use_dma_info = 0; - /* - * Limit the transfer speed to MW_DMA_2. - */ - xfer_mode = ide_rate_filter(drive, xfer_mode); - switch (xfer_mode) { case XFER_MW_DMA_2: cycle_time = 250; diff --git a/drivers/ide/cris/ide-cris.c b/drivers/ide/cris/ide-cris.c index e08782ac88e..67cec8916fc 100644 --- a/drivers/ide/cris/ide-cris.c +++ b/drivers/ide/cris/ide-cris.c @@ -722,12 +722,10 @@ static void tune_cris_ide(ide_drive_t *drive, u8 pio) (void)ide_config_drive_speed(drive, XFER_PIO_0 + pio); } -static int speed_cris_ide(ide_drive_t *drive, u8 speed) +static int speed_cris_ide(ide_drive_t *drive, const u8 speed) { int cyc = 0, dvs = 0, strobe = 0, hold = 0; - speed = ide_rate_filter(drive, speed); - if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) { tune_cris_ide(drive, speed - XFER_PIO_0); return ide_config_drive_speed(drive, speed); diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c index 41a128f5211..95761884954 100644 --- a/drivers/ide/ide-lib.c +++ b/drivers/ide/ide-lib.c @@ -79,7 +79,7 @@ EXPORT_SYMBOL(ide_xfer_verbose); * TODO: check device PIO capabilities */ -u8 ide_rate_filter(ide_drive_t *drive, u8 speed) +static u8 ide_rate_filter(ide_drive_t *drive, u8 speed) { ide_hwif_t *hwif = drive->hwif; u8 mode = ide_find_dma_mode(drive, speed); @@ -96,8 +96,6 @@ u8 ide_rate_filter(ide_drive_t *drive, u8 speed) return min(speed, mode); } -EXPORT_SYMBOL(ide_rate_filter); - int ide_use_fast_pio(ide_drive_t *drive) { struct hd_driveid *id = drive->id; @@ -364,13 +362,14 @@ void ide_toggle_bounce(ide_drive_t *drive, int on) int ide_set_xfer_rate(ide_drive_t *drive, u8 rate) { -#ifndef CONFIG_BLK_DEV_IDEDMA - rate = min(rate, (u8) XFER_PIO_4); -#endif - if(HWIF(drive)->speedproc) - return HWIF(drive)->speedproc(drive, rate); - else + ide_hwif_t *hwif = drive->hwif; + + if (hwif->speedproc == NULL) return -1; + + rate = ide_rate_filter(drive, rate); + + return hwif->speedproc(drive, rate); } static void ide_dump_opcode(ide_drive_t *drive) diff --git a/drivers/ide/mips/au1xxx-ide.c b/drivers/ide/mips/au1xxx-ide.c index 0d5e4c67fa5..b04db9ff193 100644 --- a/drivers/ide/mips/au1xxx-ide.c +++ b/drivers/ide/mips/au1xxx-ide.c @@ -175,13 +175,11 @@ static void auide_tune_drive(ide_drive_t *drive, byte pio) ide_config_drive_speed(drive, speed); } -static int auide_tune_chipset (ide_drive_t *drive, u8 speed) +static int auide_tune_chipset(ide_drive_t *drive, const u8 speed) { int mem_sttime; int mem_stcfg; - speed = ide_rate_filter(drive, speed); - mem_sttime = 0; mem_stcfg = au_readl(MEM_STCFG2); diff --git a/drivers/ide/pci/aec62xx.c b/drivers/ide/pci/aec62xx.c index 74432830abf..a827ea2ab98 100644 --- a/drivers/ide/pci/aec62xx.c +++ b/drivers/ide/pci/aec62xx.c @@ -87,12 +87,11 @@ static u8 pci_bus_clock_list_ultra (u8 speed, struct chipset_bus_clock_list_entr return chipset_table->ultra_settings; } -static int aec6210_tune_chipset (ide_drive_t *drive, u8 xferspeed) +static int aec6210_tune_chipset(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; u16 d_conf = 0; - u8 speed = ide_rate_filter(drive, xferspeed); u8 ultra = 0, ultra_conf = 0; u8 tmp0 = 0, tmp1 = 0, tmp2 = 0; unsigned long flags; @@ -115,11 +114,10 @@ static int aec6210_tune_chipset (ide_drive_t *drive, u8 xferspeed) return(ide_config_drive_speed(drive, speed)); } -static int aec6260_tune_chipset (ide_drive_t *drive, u8 xferspeed) +static int aec6260_tune_chipset(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; - u8 speed = ide_rate_filter(drive, xferspeed); u8 unit = (drive->select.b.unit & 0x01); u8 tmp1 = 0, tmp2 = 0; u8 ultra = 0, drive_conf = 0, ultra_conf = 0; diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c index 11ecb618007..37ecd726aa4 100644 --- a/drivers/ide/pci/alim15x3.c +++ b/drivers/ide/pci/alim15x3.c @@ -409,17 +409,16 @@ static u8 ali_udma_filter(ide_drive_t *drive) /** * ali15x3_tune_chipset - set up chipset/drive for new speed * @drive: drive to configure for - * @xferspeed: desired speed + * @speed: desired speed * * Configure the hardware for the desired IDE transfer mode. * We also do the needed drive configuration through helpers */ - -static int ali15x3_tune_chipset (ide_drive_t *drive, u8 xferspeed) + +static int ali15x3_tune_chipset(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; - u8 speed = ide_rate_filter(drive, xferspeed); u8 speed1 = speed; u8 unit = (drive->select.b.unit & 0x01); u8 tmpbyte = 0x00; diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c index 3c0bb1e7951..9abbde3c798 100644 --- a/drivers/ide/pci/amd74xx.c +++ b/drivers/ide/pci/amd74xx.c @@ -234,14 +234,12 @@ static void amd_set_speed(struct pci_dev *dev, unsigned char dn, struct ide_timi * by upper layers. */ -static int amd_set_drive(ide_drive_t *drive, u8 speed) +static int amd_set_drive(ide_drive_t *drive, const u8 speed) { ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1); struct ide_timing t, p; int T, UT; - speed = ide_rate_filter(drive, speed); - if (speed != XFER_PIO_SLOW) ide_config_drive_speed(drive, speed); diff --git a/drivers/ide/pci/atiixp.c b/drivers/ide/pci/atiixp.c index 679eb92b892..e05e8829850 100644 --- a/drivers/ide/pci/atiixp.c +++ b/drivers/ide/pci/atiixp.c @@ -163,23 +163,21 @@ static void atiixp_tuneproc(ide_drive_t *drive, u8 pio) /** * atiixp_tune_chipset - tune a ATIIXP interface * @drive: IDE drive to tune - * @xferspeed: speed to configure + * @speed: speed to configure * * Set a ATIIXP interface channel to the desired speeds. This involves * requires the right timing data into the ATIIXP configuration space * then setting the drive parameters appropriately */ -static int atiixp_speedproc(ide_drive_t *drive, u8 xferspeed) +static int atiixp_speedproc(ide_drive_t *drive, const u8 speed) { struct pci_dev *dev = drive->hwif->pci_dev; unsigned long flags; int timing_shift = (drive->dn & 2) ? 16 : 0 + (drive->dn & 1) ? 0 : 8; u32 tmp32; u16 tmp16; - u8 speed, pio; - - speed = ide_rate_filter(drive, xferspeed); + u8 pio; if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) { atiixp_tune_pio(drive, speed - XFER_PIO_0); diff --git a/drivers/ide/pci/cmd64x.c b/drivers/ide/pci/cmd64x.c index 0e3b5de26e6..5fe50a234ce 100644 --- a/drivers/ide/pci/cmd64x.c +++ b/drivers/ide/pci/cmd64x.c @@ -288,15 +288,13 @@ static void cmd64x_tune_drive (ide_drive_t *drive, u8 pio) (void) ide_config_drive_speed(drive, XFER_PIO_0 + pio); } -static int cmd64x_tune_chipset (ide_drive_t *drive, u8 speed) +static int cmd64x_tune_chipset(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; u8 unit = drive->dn & 0x01; u8 regU = 0, pciU = hwif->channel ? UDIDETCR1 : UDIDETCR0; - speed = ide_rate_filter(drive, speed); - if (speed >= XFER_SW_DMA_0) { (void) pci_read_config_byte(dev, pciU, ®U); regU &= ~(unit ? 0xCA : 0x35); diff --git a/drivers/ide/pci/cs5520.c b/drivers/ide/pci/cs5520.c index 507981042c8..af67438328a 100644 --- a/drivers/ide/pci/cs5520.c +++ b/drivers/ide/pci/cs5520.c @@ -66,16 +66,15 @@ static struct pio_clocks cs5520_pio_clocks[]={ {1, 2, 1} }; -static int cs5520_tune_chipset(ide_drive_t *drive, u8 xferspeed) +static int cs5520_tune_chipset(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *pdev = hwif->pci_dev; - u8 speed = ide_rate_filter(drive, xferspeed); int pio = speed; u8 reg; int controller = drive->dn > 1 ? 1 : 0; int error; - + switch(speed) { case XFER_PIO_4: diff --git a/drivers/ide/pci/cs5530.c b/drivers/ide/pci/cs5530.c index e5949b1d3fb..518f430c152 100644 --- a/drivers/ide/pci/cs5530.c +++ b/drivers/ide/pci/cs5530.c @@ -143,13 +143,11 @@ static int cs5530_config_dma(ide_drive_t *drive) return 1; } -static int cs5530_tune_chipset(ide_drive_t *drive, u8 mode) +static int cs5530_tune_chipset(ide_drive_t *drive, const u8 mode) { unsigned long basereg; unsigned int reg, timings = 0; - mode = ide_rate_filter(drive, mode); - /* * Tell the drive to switch to the new mode; abort on failure. */ diff --git a/drivers/ide/pci/cs5535.c b/drivers/ide/pci/cs5535.c index 082ca7da2cb..bc00e7b6215 100644 --- a/drivers/ide/pci/cs5535.c +++ b/drivers/ide/pci/cs5535.c @@ -75,7 +75,7 @@ static unsigned int cs5535_udma_timings[5] = * * cs5535_set_speed() configures the chipset to a new speed. */ -static void cs5535_set_speed(ide_drive_t *drive, u8 speed) +static void cs5535_set_speed(ide_drive_t *drive, const u8 speed) { u32 reg = 0, dummy; @@ -141,7 +141,6 @@ static void cs5535_set_speed(ide_drive_t *drive, u8 speed) */ static int cs5535_set_drive(ide_drive_t *drive, u8 speed) { - speed = ide_rate_filter(drive, speed); ide_config_drive_speed(drive, speed); cs5535_set_speed(drive, speed); diff --git a/drivers/ide/pci/hpt34x.c b/drivers/ide/pci/hpt34x.c index cb8fe5643d3..ba982d66ff7 100644 --- a/drivers/ide/pci/hpt34x.c +++ b/drivers/ide/pci/hpt34x.c @@ -43,10 +43,9 @@ #define HPT343_DEBUG_DRIVE_INFO 0 -static int hpt34x_tune_chipset (ide_drive_t *drive, u8 xferspeed) +static int hpt34x_tune_chipset(ide_drive_t *drive, const u8 speed) { struct pci_dev *dev = HWIF(drive)->pci_dev; - u8 speed = ide_rate_filter(drive, xferspeed); u32 reg1= 0, tmp1 = 0, reg2 = 0, tmp2 = 0; u8 hi_speed, lo_speed; diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c index 18c8ad091eb..67127ac3a14 100644 --- a/drivers/ide/pci/hpt366.c +++ b/drivers/ide/pci/hpt366.c @@ -600,12 +600,11 @@ static u32 get_speed_setting(u8 speed, struct hpt_info *info) return (*info->settings)[i]; } -static int hpt36x_tune_chipset(ide_drive_t *drive, u8 xferspeed) +static int hpt36x_tune_chipset(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; struct hpt_info *info = pci_get_drvdata(dev); - u8 speed = ide_rate_filter(drive, xferspeed); u8 itr_addr = drive->dn ? 0x44 : 0x40; u32 old_itr = 0; u32 itr_mask, new_itr; @@ -628,12 +627,11 @@ static int hpt36x_tune_chipset(ide_drive_t *drive, u8 xferspeed) return ide_config_drive_speed(drive, speed); } -static int hpt37x_tune_chipset(ide_drive_t *drive, u8 xferspeed) +static int hpt37x_tune_chipset(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; struct hpt_info *info = pci_get_drvdata(dev); - u8 speed = ide_rate_filter(drive, xferspeed); u8 itr_addr = 0x40 + (drive->dn * 4); u32 old_itr = 0; u32 itr_mask, new_itr; diff --git a/drivers/ide/pci/it8213.c b/drivers/ide/pci/it8213.c index 70b3245dbf6..6fa955749ae 100644 --- a/drivers/ide/pci/it8213.c +++ b/drivers/ide/pci/it8213.c @@ -115,20 +115,16 @@ static void it8213_tuneproc(ide_drive_t *drive, u8 pio) /** * it8213_tune_chipset - set controller timings * @drive: Drive to set up - * @xferspeed: speed we want to achieve + * @speed: speed we want to achieve * - * Tune the ITE chipset for the desired mode. If we can't achieve - * the desired mode then tune for a lower one, but ultimately - * make the thing work. + * Tune the ITE chipset for the desired mode. */ -static int it8213_tune_chipset (ide_drive_t *drive, u8 xferspeed) +static int it8213_tune_chipset(ide_drive_t *drive, const u8 speed) { - ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; u8 maslave = 0x40; - u8 speed = ide_rate_filter(drive, xferspeed); int a_speed = 3 << (drive->dn * 4); int u_flag = 1 << drive->dn; int v_flag = 0x01 << drive->dn; diff --git a/drivers/ide/pci/it821x.c b/drivers/ide/pci/it821x.c index 9286c99e2ff..a756e61bcb3 100644 --- a/drivers/ide/pci/it821x.c +++ b/drivers/ide/pci/it821x.c @@ -405,23 +405,19 @@ static int it821x_dma_end(ide_drive_t *drive) return ret; } - /** * it821x_tune_chipset - set controller timings * @drive: Drive to set up - * @xferspeed: speed we want to achieve + * @speed: speed we want to achieve * - * Tune the ITE chipset for the desired mode. If we can't achieve - * the desired mode then tune for a lower one, but ultimately - * make the thing work. + * Tune the ITE chipset for the desired mode. */ -static int it821x_tune_chipset (ide_drive_t *drive, byte xferspeed) +static int it821x_tune_chipset(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = drive->hwif; struct it821x_dev *itdev = ide_get_hwifdata(hwif); - u8 speed = ide_rate_filter(drive, xferspeed); switch (speed) { case XFER_PIO_4: diff --git a/drivers/ide/pci/jmicron.c b/drivers/ide/pci/jmicron.c index 17490d25575..7bac87fb481 100644 --- a/drivers/ide/pci/jmicron.c +++ b/drivers/ide/pci/jmicron.c @@ -92,17 +92,14 @@ static void jmicron_tuneproc(ide_drive_t *drive, u8 pio) /** * jmicron_tune_chipset - set controller timings * @drive: Drive to set up - * @xferspeed: speed we want to achieve + * @speed: speed we want to achieve * * As the JMicron snoops for timings all we actually need to do is - * make sure we don't set an invalid mode. We do need to honour - * the cable detect here. + * set the transfer mode on the device. */ -static int jmicron_tune_chipset (ide_drive_t *drive, byte xferspeed) +static int jmicron_tune_chipset(ide_drive_t *drive, const u8 speed) { - u8 speed = ide_rate_filter(drive, xferspeed); - return ide_config_drive_speed(drive, speed); } diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c index 7c5544d10b9..3787194a224 100644 --- a/drivers/ide/pci/pdc202xx_new.c +++ b/drivers/ide/pci/pdc202xx_new.c @@ -146,14 +146,12 @@ static struct udma_timing { { 0x1a, 0x01, 0xcb }, /* UDMA mode 6 */ }; -static int pdcnew_tune_chipset(ide_drive_t *drive, u8 speed) +static int pdcnew_tune_chipset(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); u8 adj = (drive->dn & 1) ? 0x08 : 0x00; int err; - speed = ide_rate_filter(drive, speed); - /* * Issue SETFEATURES_XFER to the drive first. PDC202xx hardware will * automatically set the timing registers based on 100 MHz PLL output. diff --git a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c index e19a891171c..e7a5e3014c0 100644 --- a/drivers/ide/pci/pdc202xx_old.c +++ b/drivers/ide/pci/pdc202xx_old.c @@ -63,12 +63,11 @@ static const char *pdc_quirk_drives[] = { static void pdc_old_disable_66MHz_clock(ide_hwif_t *); -static int pdc202xx_tune_chipset (ide_drive_t *drive, u8 xferspeed) +static int pdc202xx_tune_chipset(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; u8 drive_pci = 0x60 + (drive->dn << 2); - u8 speed = ide_rate_filter(drive, xferspeed); u8 AP = 0, BP = 0, CP = 0; u8 TA = 0, TB = 0, TC = 0; diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c index 5cfa9378bbb..b66f9d1411b 100644 --- a/drivers/ide/pci/piix.c +++ b/drivers/ide/pci/piix.c @@ -221,19 +221,18 @@ static void piix_tune_drive (ide_drive_t *drive, u8 pio) /** * piix_tune_chipset - tune a PIIX interface * @drive: IDE drive to tune - * @xferspeed: speed to configure + * @speed: speed to configure * * Set a PIIX interface channel to the desired speeds. This involves * requires the right timing data into the PIIX configuration space * then setting the drive parameters appropriately */ - -static int piix_tune_chipset (ide_drive_t *drive, u8 xferspeed) + +static int piix_tune_chipset(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; u8 maslave = hwif->channel ? 0x42 : 0x40; - u8 speed = ide_rate_filter(drive, xferspeed); int a_speed = 3 << (drive->dn * 4); int u_flag = 1 << drive->dn; int v_flag = 0x01 << drive->dn; diff --git a/drivers/ide/pci/sc1200.c b/drivers/ide/pci/sc1200.c index 9bdc9694d50..059071cd2d4 100644 --- a/drivers/ide/pci/sc1200.c +++ b/drivers/ide/pci/sc1200.c @@ -138,7 +138,7 @@ out: return mask; } -static int sc1200_tune_chipset(ide_drive_t *drive, u8 mode) +static int sc1200_tune_chipset(ide_drive_t *drive, const u8 mode) { ide_hwif_t *hwif = HWIF(drive); int unit = drive->select.b.unit; @@ -146,8 +146,6 @@ static int sc1200_tune_chipset(ide_drive_t *drive, u8 mode) unsigned short pci_clock; unsigned int basereg = hwif->channel ? 0x50 : 0x40; - mode = ide_rate_filter(drive, mode); - /* * Tell the drive to switch to the new mode; abort on failure. */ diff --git a/drivers/ide/pci/scc_pata.c b/drivers/ide/pci/scc_pata.c index eeb0a6d434a..a19687caf65 100644 --- a/drivers/ide/pci/scc_pata.c +++ b/drivers/ide/pci/scc_pata.c @@ -231,16 +231,15 @@ static void scc_tuneproc(ide_drive_t *drive, u8 pio) /** * scc_tune_chipset - tune a drive DMA mode * @drive: Drive to set up - * @xferspeed: speed we want to achieve + * @speed: speed we want to achieve * * Load the timing settings for this device mode into the * controller. */ -static int scc_tune_chipset(ide_drive_t *drive, byte xferspeed) +static int scc_tune_chipset(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); - u8 speed = ide_rate_filter(drive, xferspeed); struct scc_ports *ports = ide_get_hwifdata(hwif); unsigned long ctl_base = ports->ctl; unsigned long cckctrl_port = ctl_base + 0xff0; diff --git a/drivers/ide/pci/serverworks.c b/drivers/ide/pci/serverworks.c index 9fead2e7d4c..b51133bb58a 100644 --- a/drivers/ide/pci/serverworks.c +++ b/drivers/ide/pci/serverworks.c @@ -145,7 +145,7 @@ static void svwks_tune_pio(ide_drive_t *drive, const u8 pio) } } -static int svwks_tune_chipset (ide_drive_t *drive, u8 xferspeed) +static int svwks_tune_chipset(ide_drive_t *drive, const u8 speed) { static const u8 udma_modes[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 }; static const u8 dma_modes[] = { 0x77, 0x21, 0x20 }; @@ -153,7 +153,6 @@ static int svwks_tune_chipset (ide_drive_t *drive, u8 xferspeed) ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; - u8 speed = ide_rate_filter(drive, xferspeed); u8 unit = (drive->select.b.unit & 0x01); u8 ultra_enable = 0, ultra_timing = 0, dma_timing = 0; diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c index 50f6d172ef7..4c1f3bc7e17 100644 --- a/drivers/ide/pci/siimage.c +++ b/drivers/ide/pci/siimage.c @@ -229,14 +229,12 @@ static void sil_tuneproc(ide_drive_t *drive, u8 pio) /** * siimage_tune_chipset - set controller timings * @drive: Drive to set up - * @xferspeed: speed we want to achieve + * @speed: speed we want to achieve * - * Tune the SII chipset for the desired mode. If we can't achieve - * the desired mode then tune for a lower one, but ultimately - * make the thing work. + * Tune the SII chipset for the desired mode. */ - -static int siimage_tune_chipset (ide_drive_t *drive, byte xferspeed) + +static int siimage_tune_chipset(ide_drive_t *drive, const u8 speed) { u8 ultra6[] = { 0x0F, 0x0B, 0x07, 0x05, 0x03, 0x02, 0x01 }; u8 ultra5[] = { 0x0C, 0x07, 0x05, 0x04, 0x02, 0x01 }; @@ -245,7 +243,6 @@ static int siimage_tune_chipset (ide_drive_t *drive, byte xferspeed) ide_hwif_t *hwif = HWIF(drive); u16 ultra = 0, multi = 0; u8 mode = 0, unit = drive->select.b.unit; - u8 speed = ide_rate_filter(drive, xferspeed); unsigned long base = (unsigned long)hwif->hwif_data; u8 scsc = 0, addr_mask = ((hwif->channel) ? ((hwif->mmio) ? 0xF4 : 0x84) : diff --git a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c index 1da037f1394..fed582b4b32 100644 --- a/drivers/ide/pci/sis5513.c +++ b/drivers/ide/pci/sis5513.c @@ -531,15 +531,12 @@ static void sis5513_tuneproc(ide_drive_t *drive, u8 pio) (void)sis5513_tune_drive(drive, pio); } -static int sis5513_tune_chipset (ide_drive_t *drive, u8 xferspeed) +static int sis5513_tune_chipset(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; - - u8 drive_pci, reg, speed; u32 regdw; - - speed = ide_rate_filter(drive, xferspeed); + u8 drive_pci, reg; /* See config_art_rwp_pio for drive pci config registers */ drive_pci = 0x40; diff --git a/drivers/ide/pci/sl82c105.c b/drivers/ide/pci/sl82c105.c index 0947cab0059..9f425b0b572 100644 --- a/drivers/ide/pci/sl82c105.c +++ b/drivers/ide/pci/sl82c105.c @@ -113,7 +113,7 @@ static u8 sl82c105_tune_pio(ide_drive_t *drive, u8 pio) /* * Configure the drive and chipset for a new transfer speed. */ -static int sl82c105_tune_chipset(ide_drive_t *drive, u8 speed) +static int sl82c105_tune_chipset(ide_drive_t *drive, const u8 speed) { static u16 mwdma_timings[] = {0x0707, 0x0201, 0x0200}; u16 drv_ctrl; @@ -121,8 +121,6 @@ static int sl82c105_tune_chipset(ide_drive_t *drive, u8 speed) DBG(("sl82c105_tune_chipset(drive:%s, speed:%s)\n", drive->name, ide_xfer_verbose(speed))); - speed = ide_rate_filter(drive, speed); - switch (speed) { case XFER_MW_DMA_2: case XFER_MW_DMA_1: diff --git a/drivers/ide/pci/slc90e66.c b/drivers/ide/pci/slc90e66.c index 628b0664f57..cc935356507 100644 --- a/drivers/ide/pci/slc90e66.c +++ b/drivers/ide/pci/slc90e66.c @@ -102,12 +102,11 @@ static void slc90e66_tune_drive (ide_drive_t *drive, u8 pio) (void) ide_config_drive_speed(drive, XFER_PIO_0 + pio); } -static int slc90e66_tune_chipset (ide_drive_t *drive, u8 xferspeed) +static int slc90e66_tune_chipset(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; u8 maslave = hwif->channel ? 0x42 : 0x40; - u8 speed = ide_rate_filter(drive, xferspeed); int sitre = 0, a_speed = 7 << (drive->dn * 4); int u_speed = 0, u_flag = 1 << drive->dn; u16 reg4042, reg44, reg48, reg4a; diff --git a/drivers/ide/pci/tc86c001.c b/drivers/ide/pci/tc86c001.c index ec79bacc30c..e5425772622 100644 --- a/drivers/ide/pci/tc86c001.c +++ b/drivers/ide/pci/tc86c001.c @@ -13,14 +13,12 @@ #include #include -static int tc86c001_tune_chipset(ide_drive_t *drive, u8 speed) +static int tc86c001_tune_chipset(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); unsigned long scr_port = hwif->config_data + (drive->dn ? 0x02 : 0x00); u16 mode, scr = hwif->INW(scr_port); - speed = ide_rate_filter(drive, speed); - switch (speed) { case XFER_UDMA_4: mode = 0x00c0; break; case XFER_UDMA_3: mode = 0x00b0; break; diff --git a/drivers/ide/pci/triflex.c b/drivers/ide/pci/triflex.c index 098692a6d61..47cf89be4df 100644 --- a/drivers/ide/pci/triflex.c +++ b/drivers/ide/pci/triflex.c @@ -40,7 +40,7 @@ #include #include -static int triflex_tune_chipset(ide_drive_t *drive, u8 xferspeed) +static int triflex_tune_chipset(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; @@ -48,7 +48,6 @@ static int triflex_tune_chipset(ide_drive_t *drive, u8 xferspeed) u16 timing = 0; u32 triflex_timings = 0; u8 unit = (drive->select.b.unit & 0x01); - u8 speed = ide_rate_filter(drive, xferspeed); pci_read_config_dword(dev, channel_offset, &triflex_timings); diff --git a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c index ec9ad6e0e1f..e3bf9073633 100644 --- a/drivers/ide/pci/via82cxxx.c +++ b/drivers/ide/pci/via82cxxx.c @@ -158,15 +158,13 @@ static void via_set_speed(ide_hwif_t *hwif, u8 dn, struct ide_timing *timing) * by upper layers. */ -static int via_set_drive(ide_drive_t *drive, u8 speed) +static int via_set_drive(ide_drive_t *drive, const u8 speed) { ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1); struct via82cxxx_dev *vdev = pci_get_drvdata(drive->hwif->pci_dev); struct ide_timing t, p; unsigned int T, UT; - speed = ide_rate_filter(drive, speed); - if (speed != XFER_PIO_SLOW) ide_config_drive_speed(drive, speed); diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c index 222adcb5482..284bb7c39b8 100644 --- a/drivers/ide/ppc/pmac.c +++ b/drivers/ide/ppc/pmac.c @@ -411,7 +411,6 @@ kauai_lookup_timing(struct kauai_timing* table, int cycle_time) static void pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif); static int pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq); -static int pmac_ide_tune_chipset(ide_drive_t *drive, u8 speed); static void pmac_ide_tuneproc(ide_drive_t *drive, u8 pio); static void pmac_ide_selectproc(ide_drive_t *drive); static void pmac_ide_kauai_selectproc(ide_drive_t *drive); @@ -920,16 +919,13 @@ set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2, * our dedicated function is more precise as it uses the drive provided * cycle time value. We should probably fix this one to deal with that too... */ -static int -pmac_ide_tune_chipset (ide_drive_t *drive, byte speed) +static int pmac_ide_tune_chipset(ide_drive_t *drive, const u8 speed) { int unit = (drive->select.b.unit & 0x01); int ret = 0; pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data; u32 *timings, *timings2; - speed = ide_rate_filter(drive, speed); - if (pmif == NULL) return 1; diff --git a/include/linux/ide.h b/include/linux/ide.h index a3f9c216615..81736cb7ef3 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -705,7 +705,7 @@ typedef struct hwif_s { /* routine to tune PIO mode for drives */ void (*tuneproc)(ide_drive_t *, u8); /* routine to retune DMA modes for drives */ - int (*speedproc)(ide_drive_t *, u8); + int (*speedproc)(ide_drive_t *, const u8); /* tweaks hardware to select drive */ void (*selectproc)(ide_drive_t *); /* chipset polling based on hba specifics */ @@ -1378,7 +1378,6 @@ static inline void ide_set_hwifdata (ide_hwif_t * hwif, void *data) } /* ide-lib.c */ -u8 ide_rate_filter(ide_drive_t *, u8); extern char *ide_xfer_verbose(u8 xfer_rate); extern void ide_toggle_bounce(ide_drive_t *drive, int on); extern int ide_set_xfer_rate(ide_drive_t *drive, u8 rate); -- cgit v1.2.3-70-g09d2 From 842c19ad6fc0dbd9ac9d2f8527466201802934cf Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Thu, 11 Oct 2007 23:54:00 +0200 Subject: ide: Kconfig face-lift * Convert config options for PCI host drivers to select BLK_DEV_IDEPCI. * Same for BLK_DEV_IDEDMA_PCI and PCI DMA host drivers, also make this config option select BLK_DEV_IDEPCI. * Remove no longer needed help for BLK_DEV_IDEPCI and BLK_DEV_IDEDMA_PCI. * Remove redundant IDE_CHIPSETS config option. As a result of this patch users have now three less config options to worry about and can just select host drivers that they need (IDE config menu is "flatter"). Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/Kconfig | 102 ++++++++++++++++++++++++++-------------------------- 1 file changed, 52 insertions(+), 50 deletions(-) (limited to 'drivers') diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index 75b2737510a..aa0e0c9f74c 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -359,17 +359,16 @@ config BLK_DEV_IDEPNP would like the kernel to automatically detect and activate it, say Y here. +if PCI + +comment "PCI IDE chipsets support" + config BLK_DEV_IDEPCI - bool "PCI IDE chipset support" if PCI - default BLK_DEV_IDEDMA_PMAC if PPC_PMAC && BLK_DEV_IDEDMA_PMAC - help - Say Y here for PCI systems which use IDE drive(s). - This option helps the IDE driver to automatically detect and - configure all PCI-based IDE interfaces in your system. + bool config IDEPCI_SHARE_IRQ bool "Sharing PCI IDE interrupts support" - depends on PCI && BLK_DEV_IDEPCI + depends on BLK_DEV_IDEPCI help Some ATA/IDE chipsets have hardware support which allows for sharing a single IRQ with other cards. To enable support for @@ -379,11 +378,11 @@ config IDEPCI_SHARE_IRQ If unsure, say N. config IDEPCI_PCIBUS_ORDER - def_bool PCI && BLK_DEV_IDE=y && BLK_DEV_IDEPCI + def_bool BLK_DEV_IDE=y && BLK_DEV_IDEPCI config BLK_DEV_OFFBOARD bool "Boot off-board chipsets first support" - depends on PCI && BLK_DEV_IDEPCI + depends on BLK_DEV_IDEPCI help Normally, IDE controllers built into the motherboard (on-board controllers) are assigned to ide0 and ide1 while those on add-in PCI @@ -406,21 +405,23 @@ config BLK_DEV_OFFBOARD config BLK_DEV_GENERIC tristate "Generic PCI IDE Chipset Support" - depends on BLK_DEV_IDEPCI + select BLK_DEV_IDEPCI help This option provides generic support for various PCI IDE Chipsets which otherwise might not be supported. config BLK_DEV_OPTI621 tristate "OPTi 82C621 chipset enhanced support (EXPERIMENTAL)" - depends on PCI && BLK_DEV_IDEPCI && EXPERIMENTAL + depends on EXPERIMENTAL + select BLK_DEV_IDEPCI help This is a driver for the OPTi 82C621 EIDE controller. Please read the comments at the top of . config BLK_DEV_RZ1000 tristate "RZ1000 chipset bugfix/support" - depends on PCI && BLK_DEV_IDEPCI && X86 + depends on X86 + select BLK_DEV_IDEPCI help The PC-Technologies RZ1000 IDE chip is used on many common 486 and Pentium motherboards, usually along with the "Neptune" chipset. @@ -431,35 +432,21 @@ config BLK_DEV_RZ1000 things will operate 100% reliably. config BLK_DEV_IDEDMA_PCI - bool "Generic PCI bus-master DMA support" - depends on PCI && BLK_DEV_IDEPCI - ---help--- - If your PCI system uses IDE drive(s) (as opposed to SCSI, say) and - is capable of bus-master DMA operation (most Pentium PCI systems), - you will want to say Y here to reduce CPU overhead. You can then use - the "hdparm" utility to enable DMA for drives for which it was not - enabled automatically. By default, DMA is not enabled automatically - for these drives, but you can change that by saying Y to the - following question "Use DMA by default when available". You can get - the latest version of the hdparm utility from - . - - Read the comments at the beginning of - and the file for more information. - - It is safe to say Y to this question. - -if BLK_DEV_IDEDMA_PCI + bool + select BLK_DEV_IDEPCI config BLK_DEV_IDEDMA_FORCED bool "Force enable legacy 2.0.X HOSTS to use DMA" + depends on BLK_DEV_IDEDMA_PCI help This is an old piece of lost code from Linux 2.0 Kernels. Generally say N here. +# TODO: remove it config IDEDMA_ONLYDISK bool "Enable DMA only for disks " + depends on BLK_DEV_IDEDMA_PCI help This is used if you know your ATAPI Devices are going to fail DMA Transfers. @@ -468,6 +455,7 @@ config IDEDMA_ONLYDISK config BLK_DEV_AEC62XX tristate "AEC62XX chipset support" + select BLK_DEV_IDEDMA_PCI help This driver adds explicit support for Acard AEC62xx (Artop ATP8xx) IDE controllers. This allows the kernel to change PIO, DMA and UDMA @@ -475,6 +463,7 @@ config BLK_DEV_AEC62XX config BLK_DEV_ALI15X3 tristate "ALI M15x3 chipset support" + select BLK_DEV_IDEDMA_PCI help This driver ensures (U)DMA support for ALI 1533, 1543 and 1543C onboard chipsets. It also tests for Simplex mode and enables @@ -503,6 +492,7 @@ config WDC_ALI15X3 config BLK_DEV_AMD74XX tristate "AMD and nVidia IDE support" + select BLK_DEV_IDEDMA_PCI help This driver adds explicit support for AMD-7xx and AMD-8111 chips and also for the nVidia nForce chip. This allows the kernel to @@ -512,6 +502,7 @@ config BLK_DEV_AMD74XX config BLK_DEV_ATIIXP tristate "ATI IXP chipset IDE support" depends on X86 + select BLK_DEV_IDEDMA_PCI help This driver adds explicit support for ATI IXP chipset. This allows the kernel to change PIO, DMA and UDMA speeds @@ -521,18 +512,21 @@ config BLK_DEV_ATIIXP config BLK_DEV_CMD64X tristate "CMD64{3|6|8|9} chipset support" + select BLK_DEV_IDEDMA_PCI help Say Y here if you have an IDE controller which uses any of these chipsets: CMD643, CMD646, or CMD648. config BLK_DEV_TRIFLEX tristate "Compaq Triflex IDE support" + select BLK_DEV_IDEDMA_PCI help Say Y here if you have a Compaq Triflex IDE controller, such as those commonly found on Compaq Pentium-Pro systems config BLK_DEV_CY82C693 tristate "CY82C693 chipset support" + select BLK_DEV_IDEDMA_PCI help This driver adds detection and support for the CY82C693 chipset used on Digital's PC-Alpha 164SX boards. @@ -543,6 +537,7 @@ config BLK_DEV_CY82C693 config BLK_DEV_CS5520 tristate "Cyrix CS5510/20 MediaGX chipset support (VERY EXPERIMENTAL)" depends on EXPERIMENTAL + select BLK_DEV_IDEDMA_PCI help Include support for PIO tuning and virtual DMA on the Cyrix MediaGX 5510/5520 chipset. This will automatically be detected and @@ -552,6 +547,7 @@ config BLK_DEV_CS5520 config BLK_DEV_CS5530 tristate "Cyrix/National Semiconductor CS5530 MediaGX chipset support" + select BLK_DEV_IDEDMA_PCI help Include support for UDMA on the Cyrix MediaGX 5530 chipset. This will automatically be detected and configured if found. @@ -561,6 +557,7 @@ config BLK_DEV_CS5530 config BLK_DEV_CS5535 tristate "AMD CS5535 chipset support" depends on X86 && !X86_64 + select BLK_DEV_IDEDMA_PCI help Include support for UDMA on the NSC/AMD CS5535 companion chipset. This will automatically be detected and configured if found. @@ -569,6 +566,7 @@ config BLK_DEV_CS5535 config BLK_DEV_HPT34X tristate "HPT34X chipset support" + select BLK_DEV_IDEDMA_PCI help This driver adds up to 4 more EIDE devices sharing a single interrupt. The HPT343 chipset in its current form is a non-bootable @@ -589,7 +587,8 @@ config HPT34X_AUTODMA config BLK_DEV_HPT366 tristate "HPT36X/37X chipset support" - ---help--- + select BLK_DEV_IDEDMA_PCI + help HPT366 is an Ultra DMA chipset for ATA-66. HPT368 is an Ultra DMA chipset for ATA-66 RAID Based. HPT370 is an Ultra DMA chipset for ATA-100. @@ -613,18 +612,21 @@ config BLK_DEV_HPT366 config BLK_DEV_JMICRON tristate "JMicron JMB36x support" + select BLK_DEV_IDEDMA_PCI help Basic support for the JMicron ATA controllers. For full support use the libata drivers. config BLK_DEV_SC1200 tristate "National SCx200 chipset support" + select BLK_DEV_IDEDMA_PCI help This driver adds support for the built in IDE on the National SCx200 series of embedded x86 "Geode" systems config BLK_DEV_PIIX tristate "Intel PIIXn chipsets support" + select BLK_DEV_IDEDMA_PCI help This driver adds explicit support for Intel PIIX and ICH chips and also for the Efar Victory66 (slc90e66) chip. This allows @@ -633,17 +635,20 @@ config BLK_DEV_PIIX config BLK_DEV_IT8213 tristate "IT8213 IDE support" + select BLK_DEV_IDEDMA_PCI help This driver adds support for the ITE 8213 IDE controller. config BLK_DEV_IT821X tristate "IT821X IDE support" + select BLK_DEV_IDEDMA_PCI help This driver adds support for the ITE 8211 IDE controller and the IT 8212 IDE RAID controller in both RAID and pass-through mode. config BLK_DEV_NS87415 tristate "NS87415 chipset support" + select BLK_DEV_IDEDMA_PCI help This driver adds detection and support for the NS87415 chip (used mainly on SPARC64 and PA-RISC machines). @@ -652,6 +657,7 @@ config BLK_DEV_NS87415 config BLK_DEV_PDC202XX_OLD tristate "PROMISE PDC202{46|62|65|67} support" + select BLK_DEV_IDEDMA_PCI help Promise Ultra33 or PDC20246 Promise Ultra66 or PDC20262 @@ -693,9 +699,11 @@ config PDC202XX_BURST config BLK_DEV_PDC202XX_NEW tristate "PROMISE PDC202{68|69|70|71|75|76|77} support" + select BLK_DEV_IDEDMA_PCI config BLK_DEV_SVWKS tristate "ServerWorks OSB4/CSB5/CSB6 chipsets support" + select BLK_DEV_IDEDMA_PCI help This driver adds PIO/(U)DMA support for the ServerWorks OSB4/CSB5 chipsets. @@ -704,6 +712,7 @@ config BLK_DEV_SGIIOC4 tristate "Silicon Graphics IOC4 chipset ATA/ATAPI support" depends on (IA64_SGI_SN2 || IA64_GENERIC) && SGI_IOC4 select IDEPCI_SHARE_IRQ + select BLK_DEV_IDEDMA_PCI help This driver adds PIO & MultiMode DMA-2 support for the SGI IOC4 chipset, which has one channel and can support two devices. @@ -711,6 +720,7 @@ config BLK_DEV_SGIIOC4 config BLK_DEV_SIIMAGE tristate "Silicon Image chipset support" + select BLK_DEV_IDEDMA_PCI help This driver adds PIO/(U)DMA support for the SI CMD680 and SII 3112 (Serial ATA) chips. @@ -718,7 +728,8 @@ config BLK_DEV_SIIMAGE config BLK_DEV_SIS5513 tristate "SiS5513 chipset support" depends on X86 - ---help--- + select BLK_DEV_IDEDMA_PCI + help This driver ensures (U)DMA support for SIS5513 chipset family based mainboards. @@ -737,6 +748,7 @@ config BLK_DEV_SIS5513 config BLK_DEV_SL82C105 tristate "Winbond SL82c105 support" depends on (PPC || ARM) + select BLK_DEV_IDEDMA_PCI help If you have a Winbond SL82c105 IDE controller, say Y here to enable special configuration for this chip. This is common on various CHRP @@ -744,6 +756,7 @@ config BLK_DEV_SL82C105 config BLK_DEV_SLC90E66 tristate "SLC90E66 chipset support" + select BLK_DEV_IDEDMA_PCI help This driver ensures (U)DMA support for Victory66 SouthBridges for SMsC with Intel NorthBridges. This is an Ultra66 based chipset. @@ -759,6 +772,7 @@ config BLK_DEV_SLC90E66 config BLK_DEV_TRM290 tristate "Tekram TRM290 chipset support" + select BLK_DEV_IDEDMA_PCI help This driver adds support for bus master DMA transfers using the Tekram TRM290 PCI IDE chip. Volunteers are @@ -767,6 +781,7 @@ config BLK_DEV_TRM290 config BLK_DEV_VIA82CXXX tristate "VIA82CXXX chipset support" + select BLK_DEV_IDEDMA_PCI help This driver adds explicit support for VIA BusMastering IDE chips. This allows the kernel to change PIO, DMA and UDMA speeds and to @@ -774,12 +789,14 @@ config BLK_DEV_VIA82CXXX config BLK_DEV_TC86C001 tristate "Toshiba TC86C001 support" + select BLK_DEV_IDEDMA_PCI help This driver adds support for Toshiba TC86C001 GOKU-S chip. config BLK_DEV_CELLEB tristate "Toshiba's Cell Reference Set IDE support" depends on PPC_CELLEB + select BLK_DEV_IDEDMA_PCI help This driver provides support for the built-in IDE controller on Toshiba Cell Reference Board. @@ -993,24 +1010,9 @@ config IDE_EXT_DIRECT endchoice # no isa -> no vlb -config IDE_CHIPSETS - bool "Other IDE chipset support" - depends on ISA - ---help--- - Say Y here if you want to include enhanced support for various IDE - interface chipsets used on motherboards and add-on cards. You can - then pick your particular IDE chip from among the following options. - This enhanced support may be necessary for Linux to be able to - access the 3rd/4th drives in some systems. It may also enable - setting of higher speed I/O rates to improve system performance with - these chipsets. Most of these also require special kernel boot - parameters to actually turn on the support at runtime; you can find - a list of these in the file . - - People with SCSI-only systems can say N here. - -if IDE_CHIPSETS +if ISA +comment "Other IDE chipsets support" comment "Note: most of these also require special kernel boot parameters" config BLK_DEV_4DRIVES -- cgit v1.2.3-70-g09d2 From 26bcb879c03254545a19c6700fe5bcef6f21e7b1 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Thu, 11 Oct 2007 23:54:00 +0200 Subject: ide: add ide_set{_max}_pio() (take 4) * Add IDE_HFLAG_ABUSE_{PREFETCH,FAST_DEVSEL,DMA_MODES} flags and set them in ht6560, cmd640, cmd64x and sc1200 host drivers. * Add set_pio_mode_abuse() for checking if host driver has a non-standard ->tuneproc() implementation and use it in do_special(). * Add ide_set_pio() for setting PIO mode (it uses hwif->pio_mask to find the maximum PIO mode supported by the host), also add ide_set_max_pio() wrapper for ide_set_pio() to use for auto-tuning. Convert users of ->tuneproc to use ide_set{_max}_pio() where possible. This leaves only do_special(), set_using_pio(), ide_hwif_restore() and ide_set_pio() as a direct users of ->tuneproc. * Remove no longer needed ide_get_best_pio_mode() calls and printk-s reporting PIO mode selected from ->tuneproc implementations. * Rename ->tuneproc hook to ->set_pio_mode and make 'pio' argument const. * Remove stale comment from ide_config_drive_speed(). v2: * Fix "ata_" prefix (Noticed by Jeff). v3: * Minor cleanups/fixups per Sergei's suggestions. v4: * Fix compile problem in drivers/ide/pci/cmd640.c (Noticed by Andrew Morton). * Improve some ->set_pio_mode comments. Reviewed-by: Sergei Shtylyov Cc: Jeff Garzik Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/cris/ide-cris.c | 8 +++--- drivers/ide/ide-io.c | 39 ++++++++++++++++++++++++--- drivers/ide/ide-iops.c | 6 ----- drivers/ide/ide-lib.c | 29 ++++++++++++++++++++ drivers/ide/ide-probe.c | 6 ++--- drivers/ide/ide.c | 5 ++-- drivers/ide/legacy/ali14xx.c | 10 +++---- drivers/ide/legacy/dtc2278.c | 6 ++--- drivers/ide/legacy/ht6560b.c | 11 ++++---- drivers/ide/legacy/qd65xx.c | 60 +++++++++++++++++++++++------------------- drivers/ide/legacy/umc8672.c | 7 +++-- drivers/ide/mips/au1xxx-ide.c | 12 +++------ drivers/ide/pci/aec62xx.c | 7 +++-- drivers/ide/pci/alim15x3.c | 32 +++++++++------------- drivers/ide/pci/amd74xx.c | 14 ++++------ drivers/ide/pci/atiixp.c | 7 +++-- drivers/ide/pci/cmd640.c | 35 ++++++++++++------------ drivers/ide/pci/cmd64x.c | 39 +++++++++++++-------------- drivers/ide/pci/cs5520.c | 11 ++++---- drivers/ide/pci/cs5530.c | 15 +++++------ drivers/ide/pci/cs5535.c | 16 +++++------ drivers/ide/pci/cy82c693.c | 20 ++------------ drivers/ide/pci/hpt34x.c | 7 +++-- drivers/ide/pci/hpt366.c | 7 +++-- drivers/ide/pci/it8213.c | 7 +++-- drivers/ide/pci/it821x.c | 7 +++-- drivers/ide/pci/jmicron.c | 7 +++-- drivers/ide/pci/opti621.c | 19 ++++++------- drivers/ide/pci/pdc202xx_new.c | 8 +++--- drivers/ide/pci/pdc202xx_old.c | 14 +++++----- drivers/ide/pci/piix.c | 21 ++++++++------- drivers/ide/pci/sc1200.c | 14 +++++----- drivers/ide/pci/scc_pata.c | 7 +++-- drivers/ide/pci/serverworks.c | 7 +++-- drivers/ide/pci/sgiioc4.c | 2 +- drivers/ide/pci/siimage.c | 7 +++-- drivers/ide/pci/sis5513.c | 11 ++++---- drivers/ide/pci/sl82c105.c | 17 ++++-------- drivers/ide/pci/slc90e66.c | 7 +++-- drivers/ide/pci/tc86c001.c | 7 +++-- drivers/ide/pci/triflex.c | 9 +++---- drivers/ide/pci/via82cxxx.c | 17 +++++------- drivers/ide/ppc/mpc8xx.c | 21 +++------------ drivers/ide/ppc/pmac.c | 8 +++--- include/linux/ide.h | 18 ++++++++++--- 45 files changed, 318 insertions(+), 326 deletions(-) (limited to 'drivers') diff --git a/drivers/ide/cris/ide-cris.c b/drivers/ide/cris/ide-cris.c index 67cec8916fc..7c90218e931 100644 --- a/drivers/ide/cris/ide-cris.c +++ b/drivers/ide/cris/ide-cris.c @@ -680,12 +680,10 @@ static void cris_dma_off(ide_drive_t *drive) { } -static void tune_cris_ide(ide_drive_t *drive, u8 pio) +static void cris_set_pio_mode(ide_drive_t *drive, const u8 pio) { int setup, strobe, hold; - pio = ide_get_best_pio_mode(drive, pio, 4); - switch(pio) { case 0: @@ -727,7 +725,7 @@ static int speed_cris_ide(ide_drive_t *drive, const u8 speed) int cyc = 0, dvs = 0, strobe = 0, hold = 0; if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) { - tune_cris_ide(drive, speed - XFER_PIO_0); + cris_set_pio_mode(drive, speed - XFER_PIO_0); return ide_config_drive_speed(drive, speed); } @@ -797,7 +795,7 @@ init_e100_ide (void) ide_register_hw(&hw, 1, &hwif); hwif->mmio = 1; hwif->chipset = ide_etrax100; - hwif->tuneproc = &tune_cris_ide; + hwif->set_pio_mode = &cris_set_pio_mode; hwif->speedproc = &speed_cris_ide; hwif->ata_input_data = &cris_ide_input_data; hwif->ata_output_data = &cris_ide_output_data; diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index aa9f5f0b1e6..9560a8f4a86 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -201,8 +201,7 @@ static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request * return do_rw_taskfile(drive, args); case idedisk_pm_restore_pio: /* Resume step 1 (restore PIO) */ - if (drive->hwif->tuneproc != NULL) - drive->hwif->tuneproc(drive, 255); + ide_set_max_pio(drive); /* * skip idedisk_pm_idle for ATAPI devices */ @@ -788,6 +787,30 @@ static ide_startstop_t ide_disk_special(ide_drive_t *drive) return ide_started; } +/* + * handle HDIO_SET_PIO_MODE ioctl abusers here, eventually it will go away + */ +static int set_pio_mode_abuse(ide_hwif_t *hwif, u8 req_pio) +{ + switch (req_pio) { + case 202: + case 201: + case 200: + case 102: + case 101: + case 100: + return (hwif->host_flags & IDE_HFLAG_ABUSE_DMA_MODES) ? 1 : 0; + case 9: + case 8: + return (hwif->host_flags & IDE_HFLAG_ABUSE_PREFETCH) ? 1 : 0; + case 7: + case 6: + return (hwif->host_flags & IDE_HFLAG_ABUSE_FAST_DEVSEL) ? 1 : 0; + default: + return 0; + } +} + /** * do_special - issue some special commands * @drive: drive the command is for @@ -805,9 +828,17 @@ static ide_startstop_t do_special (ide_drive_t *drive) printk("%s: do_special: 0x%02x\n", drive->name, s->all); #endif if (s->b.set_tune) { + ide_hwif_t *hwif = drive->hwif; + u8 req_pio = drive->tune_req; + s->b.set_tune = 0; - if (HWIF(drive)->tuneproc != NULL) - HWIF(drive)->tuneproc(drive, drive->tune_req); + + if (set_pio_mode_abuse(drive->hwif, req_pio)) { + if (hwif->set_pio_mode) + hwif->set_pio_mode(drive, req_pio); + } else + ide_set_pio(drive, req_pio); + return ide_stopped; } else { if (drive->media == ide_disk) diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c index 646a54e233d..cf0678b6116 100644 --- a/drivers/ide/ide-iops.c +++ b/drivers/ide/ide-iops.c @@ -780,12 +780,6 @@ int ide_driveid_update (ide_drive_t *drive) /* * Similar to ide_wait_stat(), except it never calls ide_error internally. - * This is a kludge to handle the new ide_config_drive_speed() function, - * and should not otherwise be used anywhere. Eventually, the tuneproc's - * should be updated to return ide_startstop_t, in which case we can get - * rid of this abomination again. :) -ml - * - * It is gone.......... * * const char *msg == consider adding for verbose errors. */ diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c index 95761884954..8400b1b4aa1 100644 --- a/drivers/ide/ide-lib.c +++ b/drivers/ide/ide-lib.c @@ -325,6 +325,35 @@ u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode) EXPORT_SYMBOL_GPL(ide_get_best_pio_mode); +/* req_pio == "255" for auto-tune */ +void ide_set_pio(ide_drive_t *drive, u8 req_pio) +{ + ide_hwif_t *hwif = drive->hwif; + u8 host_pio, pio; + + if (hwif->set_pio_mode == NULL) + return; + + BUG_ON(hwif->pio_mask == 0x00); + + host_pio = fls(hwif->pio_mask) - 1; + + pio = ide_get_best_pio_mode(drive, req_pio, host_pio); + + /* + * TODO: + * - report device max PIO mode + * - check req_pio != 255 against device max PIO mode + */ + printk(KERN_DEBUG "%s: host max PIO%d wanted PIO%d%s selected PIO%d\n", + drive->name, host_pio, req_pio, + req_pio == 255 ? "(auto-tune)" : "", pio); + + hwif->set_pio_mode(drive, pio); +} + +EXPORT_SYMBOL_GPL(ide_set_pio); + /** * ide_toggle_bounce - handle bounce buffering * @drive: drive to update diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 3a2a9a338fd..b4c9f63a385 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -827,10 +827,8 @@ static void probe_hwif(ide_hwif_t *hwif, void (*fixup)(ide_hwif_t *hwif)) ide_drive_t *drive = &hwif->drives[unit]; if (drive->present) { - if (hwif->tuneproc != NULL && - drive->autotune == IDE_TUNE_AUTO) - /* auto-tune PIO mode */ - hwif->tuneproc(drive, 255); + if (drive->autotune == IDE_TUNE_AUTO) + ide_set_max_pio(drive); if (drive->autotune != IDE_TUNE_DEFAULT && drive->autotune != IDE_TUNE_AUTO) diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 9fdc1fe1b29..e96212ce572 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -396,7 +396,7 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif) hwif->cds = tmp_hwif->cds; #endif - hwif->tuneproc = tmp_hwif->tuneproc; + hwif->set_pio_mode = tmp_hwif->set_pio_mode; hwif->speedproc = tmp_hwif->speedproc; hwif->mdma_filter = tmp_hwif->mdma_filter; hwif->udma_filter = tmp_hwif->udma_filter; @@ -867,8 +867,9 @@ int set_pio_mode(ide_drive_t *drive, int arg) if (arg < 0 || arg > 255) return -EINVAL; - if (!HWIF(drive)->tuneproc) + if (drive->hwif->set_pio_mode == NULL) return -ENOSYS; + if (drive->special.b.set_tune) return -EBUSY; ide_init_drive_cmd(&rq); diff --git a/drivers/ide/legacy/ali14xx.c b/drivers/ide/legacy/ali14xx.c index 9b9c4761cb7..2f0ef9b4403 100644 --- a/drivers/ide/legacy/ali14xx.c +++ b/drivers/ide/legacy/ali14xx.c @@ -68,8 +68,6 @@ static RegInitializer initData[] __initdata = { {0x35, 0x03}, {0x00, 0x00} }; -#define ALI_MAX_PIO 4 - /* timing parameter registers for each drive */ static struct { u8 reg1, reg2, reg3, reg4; } regTab[4] = { {0x03, 0x26, 0x04, 0x27}, /* drive 0 */ @@ -109,7 +107,7 @@ static void outReg (u8 data, u8 reg) * This function computes timing parameters * and sets controller registers accordingly. */ -static void ali14xx_tune_drive (ide_drive_t *drive, u8 pio) +static void ali14xx_set_pio_mode(ide_drive_t *drive, const u8 pio) { int driveNum; int time1, time2; @@ -117,8 +115,6 @@ static void ali14xx_tune_drive (ide_drive_t *drive, u8 pio) unsigned long flags; int bus_speed = system_bus_clock(); - pio = ide_get_best_pio_mode(drive, pio, ALI_MAX_PIO); - /* calculate timing, according to PIO mode */ time1 = ide_pio_cycle_time(drive, pio); time2 = ide_pio_timings[pio].active_time; @@ -212,12 +208,12 @@ static int __init ali14xx_probe(void) hwif->chipset = ide_ali14xx; hwif->pio_mask = ATA_PIO4; - hwif->tuneproc = &ali14xx_tune_drive; + hwif->set_pio_mode = &ali14xx_set_pio_mode; hwif->mate = mate; mate->chipset = ide_ali14xx; mate->pio_mask = ATA_PIO4; - mate->tuneproc = &ali14xx_tune_drive; + mate->set_pio_mode = &ali14xx_set_pio_mode; mate->mate = hwif; mate->channel = 1; diff --git a/drivers/ide/legacy/dtc2278.c b/drivers/ide/legacy/dtc2278.c index 6c01d951d07..f1652125486 100644 --- a/drivers/ide/legacy/dtc2278.c +++ b/drivers/ide/legacy/dtc2278.c @@ -67,12 +67,10 @@ static void sub22 (char b, char c) } } -static void tune_dtc2278 (ide_drive_t *drive, u8 pio) +static void dtc2278_set_pio_mode(ide_drive_t *drive, const u8 pio) { unsigned long flags; - pio = ide_get_best_pio_mode(drive, pio, 4); - if (pio >= 3) { spin_lock_irqsave(&ide_lock, flags); /* @@ -124,7 +122,7 @@ static int __init dtc2278_probe(void) hwif->serialized = 1; hwif->chipset = ide_dtc2278; hwif->pio_mask = ATA_PIO4; - hwif->tuneproc = &tune_dtc2278; + hwif->set_pio_mode = &dtc2278_set_pio_mode; hwif->drives[0].no_unmask = 1; hwif->drives[1].no_unmask = 1; hwif->mate = mate; diff --git a/drivers/ide/legacy/ht6560b.c b/drivers/ide/legacy/ht6560b.c index bfaa2025173..2e5a9cc5c0f 100644 --- a/drivers/ide/legacy/ht6560b.c +++ b/drivers/ide/legacy/ht6560b.c @@ -199,7 +199,7 @@ static int __init try_to_init_ht6560b(void) return 1; } -static u8 ht_pio2timings(ide_drive_t *drive, u8 pio) +static u8 ht_pio2timings(ide_drive_t *drive, const u8 pio) { int active_time, recovery_time; int active_cycles, recovery_cycles; @@ -208,7 +208,6 @@ static u8 ht_pio2timings(ide_drive_t *drive, u8 pio) if (pio) { unsigned int cycle_time; - pio = ide_get_best_pio_mode(drive, pio, 5); cycle_time = ide_pio_cycle_time(drive, pio); /* @@ -277,7 +276,7 @@ static void ht_set_prefetch(ide_drive_t *drive, u8 state) #endif } -static void tune_ht6560b (ide_drive_t *drive, u8 pio) +static void ht6560b_set_pio_mode(ide_drive_t *drive, const u8 pio) { unsigned long flags; u8 timing; @@ -333,15 +332,17 @@ int __init ht6560b_init(void) hwif->chipset = ide_ht6560b; hwif->selectproc = &ht6560b_selectproc; + hwif->host_flags = IDE_HFLAG_ABUSE_PREFETCH; hwif->pio_mask = ATA_PIO5; - hwif->tuneproc = &tune_ht6560b; + hwif->set_pio_mode = &ht6560b_set_pio_mode; hwif->serialized = 1; /* is this needed? */ hwif->mate = mate; mate->chipset = ide_ht6560b; mate->selectproc = &ht6560b_selectproc; + mate->host_flags = IDE_HFLAG_ABUSE_PREFETCH; mate->pio_mask = ATA_PIO5; - mate->tuneproc = &tune_ht6560b; + mate->set_pio_mode = &ht6560b_set_pio_mode; mate->serialized = 1; /* is this needed? */ mate->mate = hwif; mate->channel = 1; diff --git a/drivers/ide/legacy/qd65xx.c b/drivers/ide/legacy/qd65xx.c index 8b87a424094..0c81d2d0b94 100644 --- a/drivers/ide/legacy/qd65xx.c +++ b/drivers/ide/legacy/qd65xx.c @@ -224,15 +224,14 @@ static void qd_set_timing (ide_drive_t *drive, u8 timing) printk(KERN_DEBUG "%s: %#x\n", drive->name, timing); } -/* - * qd6500_tune_drive - */ - -static void qd6500_tune_drive (ide_drive_t *drive, u8 pio) +static void qd6500_set_pio_mode(ide_drive_t *drive, const u8 pio) { int active_time = 175; int recovery_time = 415; /* worst case values from the dos driver */ + /* + * FIXME: use "pio" value + */ if (drive->id && !qd_find_disk_type(drive, &active_time, &recovery_time) && drive->id->tPIO && (drive->id->field_valid & 0x02) && drive->id->eide_pio >= 240) { @@ -246,11 +245,7 @@ static void qd6500_tune_drive (ide_drive_t *drive, u8 pio) qd_set_timing(drive, qd6500_compute_timing(HWIF(drive), active_time, recovery_time)); } -/* - * qd6580_tune_drive - */ - -static void qd6580_tune_drive (ide_drive_t *drive, u8 pio) +static void qd6580_set_pio_mode(ide_drive_t *drive, const u8 pio) { int base = HWIF(drive)->select_data; unsigned int cycle_time; @@ -258,7 +253,6 @@ static void qd6580_tune_drive (ide_drive_t *drive, u8 pio) int recovery_time = 415; /* worst case values from the dos driver */ if (drive->id && !qd_find_disk_type(drive, &active_time, &recovery_time)) { - pio = ide_get_best_pio_mode(drive, pio, 4); cycle_time = ide_pio_cycle_time(drive, pio); switch (pio) { @@ -335,8 +329,7 @@ static int __init qd_testreg(int port) */ static void __init qd_setup(ide_hwif_t *hwif, int base, int config, - unsigned int data0, unsigned int data1, - void (*tuneproc) (ide_drive_t *, u8 pio)) + unsigned int data0, unsigned int data1) { hwif->chipset = ide_qd65xx; hwif->channel = hwif->index; @@ -347,8 +340,6 @@ static void __init qd_setup(ide_hwif_t *hwif, int base, int config, hwif->drives[0].io_32bit = hwif->drives[1].io_32bit = 1; hwif->pio_mask = ATA_PIO4; - hwif->tuneproc = tuneproc; - probe_hwif_init(hwif); } /* @@ -361,7 +352,7 @@ static void __exit qd_unsetup(ide_hwif_t *hwif) { u8 config = hwif->config_data; int base = hwif->select_data; - void *tuneproc = (void *) hwif->tuneproc; + void *set_pio_mode = (void *)hwif->set_pio_mode; if (hwif->chipset != ide_qd65xx) return; @@ -369,12 +360,12 @@ static void __exit qd_unsetup(ide_hwif_t *hwif) printk(KERN_NOTICE "%s: back to defaults\n", hwif->name); hwif->selectproc = NULL; - hwif->tuneproc = NULL; + hwif->set_pio_mode = NULL; - if (tuneproc == (void *) qd6500_tune_drive) { + if (set_pio_mode == (void *)qd6500_set_pio_mode) { // will do it for both qd_write_reg(QD6500_DEF_DATA, QD_TIMREG(&hwif->drives[0])); - } else if (tuneproc == (void *) qd6580_tune_drive) { + } else if (set_pio_mode == (void *)qd6580_set_pio_mode) { if (QD_CONTROL(hwif) & QD_CONTR_SEC_DISABLED) { qd_write_reg(QD6580_DEF_DATA, QD_TIMREG(&hwif->drives[0])); qd_write_reg(QD6580_DEF_DATA2, QD_TIMREG(&hwif->drives[1])); @@ -424,8 +415,11 @@ static int __init qd_probe(int base) return 1; } - qd_setup(hwif, base, config, QD6500_DEF_DATA, QD6500_DEF_DATA, - &qd6500_tune_drive); + qd_setup(hwif, base, config, QD6500_DEF_DATA, QD6500_DEF_DATA); + + hwif->set_pio_mode = &qd6500_set_pio_mode; + + probe_hwif_init(hwif); ide_proc_register_port(hwif); @@ -455,8 +449,12 @@ static int __init qd_probe(int base) printk(KERN_INFO "%s: qd6580: single IDE board\n", hwif->name); qd_setup(hwif, base, config | (control << 8), - QD6580_DEF_DATA, QD6580_DEF_DATA2, - &qd6580_tune_drive); + QD6580_DEF_DATA, QD6580_DEF_DATA2); + + hwif->set_pio_mode = &qd6580_set_pio_mode; + + probe_hwif_init(hwif); + qd_write_reg(QD_DEF_CONTR,QD_CONTROL_PORT); ide_proc_register_port(hwif); @@ -472,11 +470,19 @@ static int __init qd_probe(int base) hwif->name, mate->name); qd_setup(hwif, base, config | (control << 8), - QD6580_DEF_DATA, QD6580_DEF_DATA, - &qd6580_tune_drive); + QD6580_DEF_DATA, QD6580_DEF_DATA); + + hwif->set_pio_mode = &qd6580_set_pio_mode; + + probe_hwif_init(hwif); + qd_setup(mate, base, config | (control << 8), - QD6580_DEF_DATA2, QD6580_DEF_DATA2, - &qd6580_tune_drive); + QD6580_DEF_DATA2, QD6580_DEF_DATA2); + + mate->set_pio_mode = &qd6580_set_pio_mode; + + probe_hwif_init(mate); + qd_write_reg(QD_DEF_CONTR,QD_CONTROL_PORT); ide_proc_register_port(hwif); diff --git a/drivers/ide/legacy/umc8672.c b/drivers/ide/legacy/umc8672.c index d2862e638bc..1151c92dd53 100644 --- a/drivers/ide/legacy/umc8672.c +++ b/drivers/ide/legacy/umc8672.c @@ -105,12 +105,11 @@ static void umc_set_speeds (u8 speeds[]) speeds[0], speeds[1], speeds[2], speeds[3]); } -static void tune_umc (ide_drive_t *drive, u8 pio) +static void umc_set_pio_mode(ide_drive_t *drive, const u8 pio) { unsigned long flags; ide_hwgroup_t *hwgroup = ide_hwifs[HWIF(drive)->index^1].hwgroup; - pio = ide_get_best_pio_mode(drive, pio, 4); printk("%s: setting umc8672 to PIO mode%d (speed %d)\n", drive->name, pio, pio_to_umc[pio]); spin_lock_irqsave(&ide_lock, flags); @@ -150,12 +149,12 @@ static int __init umc8672_probe(void) hwif->chipset = ide_umc8672; hwif->pio_mask = ATA_PIO4; - hwif->tuneproc = &tune_umc; + hwif->set_pio_mode = &umc_set_pio_mode; hwif->mate = mate; mate->chipset = ide_umc8672; mate->pio_mask = ATA_PIO4; - mate->tuneproc = &tune_umc; + mate->set_pio_mode = &umc_set_pio_mode; mate->mate = hwif; mate->channel = 1; diff --git a/drivers/ide/mips/au1xxx-ide.c b/drivers/ide/mips/au1xxx-ide.c index b04db9ff193..670cb748481 100644 --- a/drivers/ide/mips/au1xxx-ide.c +++ b/drivers/ide/mips/au1xxx-ide.c @@ -99,18 +99,12 @@ void auide_outsw(unsigned long port, void *addr, u32 count) #endif -static void auide_tune_drive(ide_drive_t *drive, byte pio) +static void au1xxx_set_pio_mode(ide_drive_t *drive, const u8 pio) { int mem_sttime; int mem_stcfg; u8 speed; - /* get the best pio mode for the drive */ - pio = ide_get_best_pio_mode(drive, pio, 4); - - printk(KERN_INFO "%s: setting Au1XXX IDE to PIO mode%d\n", - drive->name, pio); - mem_sttime = 0; mem_stcfg = au_readl(MEM_STCFG2); @@ -184,7 +178,7 @@ static int auide_tune_chipset(ide_drive_t *drive, const u8 speed) mem_stcfg = au_readl(MEM_STCFG2); if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) { - auide_tune_drive(drive, speed - XFER_PIO_0); + au1xxx_set_pio_mode(drive, speed - XFER_PIO_0); return 0; } @@ -712,7 +706,7 @@ static int au_ide_probe(struct device *dev) hwif->OUTSW = auide_outsw; #endif - hwif->tuneproc = &auide_tune_drive; + hwif->set_pio_mode = &au1xxx_set_pio_mode; hwif->speedproc = &auide_tune_chipset; #ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA diff --git a/drivers/ide/pci/aec62xx.c b/drivers/ide/pci/aec62xx.c index a827ea2ab98..0d5f62c5dfa 100644 --- a/drivers/ide/pci/aec62xx.c +++ b/drivers/ide/pci/aec62xx.c @@ -138,9 +138,8 @@ static int aec6260_tune_chipset(ide_drive_t *drive, const u8 speed) return(ide_config_drive_speed(drive, speed)); } -static void aec62xx_tune_drive (ide_drive_t *drive, u8 pio) +static void aec_set_pio_mode(ide_drive_t *drive, const u8 pio) { - pio = ide_get_best_pio_mode(drive, pio, 4); (void) HWIF(drive)->speedproc(drive, pio + XFER_PIO_0); } @@ -150,7 +149,7 @@ static int aec62xx_config_drive_xfer_rate (ide_drive_t *drive) return 0; if (ide_use_fast_pio(drive)) - aec62xx_tune_drive(drive, 255); + ide_set_max_pio(drive); return -1; } @@ -201,7 +200,7 @@ static void __devinit init_hwif_aec62xx(ide_hwif_t *hwif) u8 reg54 = 0, mask = hwif->channel ? 0xf0 : 0x0f; unsigned long flags; - hwif->tuneproc = &aec62xx_tune_drive; + hwif->set_pio_mode = &aec_set_pio_mode; if (dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) { if(hwif->mate) diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c index 37ecd726aa4..005402ab748 100644 --- a/drivers/ide/pci/alim15x3.c +++ b/drivers/ide/pci/alim15x3.c @@ -283,17 +283,14 @@ static int ali_get_info (char *buffer, char **addr, off_t offset, int count) #endif /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_IDE_PROC_FS) */ /** - * ali15x3_tune_pio - set up chipset for PIO mode - * @drive: drive to tune - * @pio: desired mode - * - * Select the best PIO mode for the drive in question. - * Then program the controller for this mode. + * ali_tune_pio - set host controller for PIO mode + * @drive: drive + * @pio: PIO mode number * - * Returns the PIO mode programmed. + * Program the controller for the given PIO mode. */ - -static u8 ali15x3_tune_pio (ide_drive_t *drive, u8 pio) + +static void ali_tune_pio(ide_drive_t *drive, const u8 pio) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; @@ -306,7 +303,6 @@ static u8 ali15x3_tune_pio (ide_drive_t *drive, u8 pio) u8 cd_dma_fifo = 0; int unit = drive->select.b.unit & 1; - pio = ide_get_best_pio_mode(drive, pio, 5); s_time = ide_pio_timings[pio].setup_time; a_time = ide_pio_timings[pio].active_time; if ((s_clc = (s_time * bus_speed + 999) / 1000) >= 8) @@ -359,22 +355,20 @@ static u8 ali15x3_tune_pio (ide_drive_t *drive, u8 pio) * { 25, 70, 25 }, PIO Mode 4 with IORDY ns * { 20, 50, 30 } PIO Mode 5 with IORDY (nonstandard) */ - - return pio; } /** - * ali15x3_tune_drive - set up drive for PIO mode + * ali_set_pio_mode - set up drive for PIO mode * @drive: drive to tune * @pio: desired mode * - * Program the controller with the best PIO timing for the given drive. + * Program the controller with the desired PIO timing for the given drive. * Then set up the drive itself. */ -static void ali15x3_tune_drive (ide_drive_t *drive, u8 pio) +static void ali_set_pio_mode(ide_drive_t *drive, const u8 pio) { - pio = ali15x3_tune_pio(drive, pio); + ali_tune_pio(drive, pio); (void) ide_config_drive_speed(drive, XFER_PIO_0 + pio); } @@ -437,7 +431,7 @@ static int ali15x3_tune_chipset(ide_drive_t *drive, const u8 speed) pci_write_config_byte(dev, m5229_udma, tmpbyte); if (speed < XFER_SW_DMA_0) - (void) ali15x3_tune_pio(drive, speed - XFER_PIO_0); + ali_tune_pio(drive, speed - XFER_PIO_0); } else { pci_read_config_byte(dev, m5229_udma, &tmpbyte); tmpbyte &= (0x0f << ((1-unit) << 2)); @@ -470,7 +464,7 @@ static int ali15x3_config_drive_for_dma(ide_drive_t *drive) if (ide_tune_dma(drive)) return 0; - ali15x3_tune_drive(drive, 255); + ide_set_max_pio(drive); return -1; } @@ -700,7 +694,7 @@ static u8 __devinit ata66_ali15x3(ide_hwif_t *hwif) static void __devinit init_hwif_common_ali15x3 (ide_hwif_t *hwif) { hwif->autodma = 0; - hwif->tuneproc = &ali15x3_tune_drive; + hwif->set_pio_mode = &ali_set_pio_mode; hwif->speedproc = &ali15x3_tune_chipset; hwif->udma_filter = &ali_udma_filter; diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c index 9abbde3c798..1088ba86cd1 100644 --- a/drivers/ide/pci/amd74xx.c +++ b/drivers/ide/pci/amd74xx.c @@ -266,16 +266,12 @@ static int amd_set_drive(ide_drive_t *drive, const u8 speed) } /* - * amd74xx_tune_drive() is a callback from upper layers for - * PIO-only tuning. + * amd_set_pio_mode() is a callback from upper layers for PIO-only tuning. */ -static void amd74xx_tune_drive(ide_drive_t *drive, u8 pio) +static void amd_set_pio_mode(ide_drive_t *drive, const u8 pio) { - if (pio == 255) - pio = ide_get_best_pio_mode(drive, 255, 5); - - amd_set_drive(drive, XFER_PIO_0 + min_t(byte, pio, 5)); + amd_set_drive(drive, XFER_PIO_0 + pio); } static int amd74xx_ide_dma_check(ide_drive_t *drive) @@ -283,7 +279,7 @@ static int amd74xx_ide_dma_check(ide_drive_t *drive) u8 speed = ide_max_dma_mode(drive); if (speed == 0) { - amd74xx_tune_drive(drive, 255); + ide_set_max_pio(drive); return -1; } @@ -409,7 +405,7 @@ static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif) hwif->autodma = 0; - hwif->tuneproc = &amd74xx_tune_drive; + hwif->set_pio_mode = &amd_set_pio_mode; hwif->speedproc = &amd_set_drive; for (i = 0; i < 2; i++) { diff --git a/drivers/ide/pci/atiixp.c b/drivers/ide/pci/atiixp.c index e05e8829850..b9f66f53f9a 100644 --- a/drivers/ide/pci/atiixp.c +++ b/drivers/ide/pci/atiixp.c @@ -153,9 +153,8 @@ static void atiixp_tune_pio(ide_drive_t *drive, u8 pio) spin_unlock_irqrestore(&atiixp_lock, flags); } -static void atiixp_tuneproc(ide_drive_t *drive, u8 pio) +static void atiixp_set_pio_mode(ide_drive_t *drive, const u8 pio) { - pio = ide_get_best_pio_mode(drive, pio, 4); atiixp_tune_pio(drive, pio); (void)ide_config_drive_speed(drive, XFER_PIO_0 + pio); } @@ -231,7 +230,7 @@ static int atiixp_dma_check(ide_drive_t *drive) return 0; if (ide_use_fast_pio(drive)) - atiixp_tuneproc(drive, 255); + ide_set_max_pio(drive); return -1; } @@ -254,7 +253,7 @@ static void __devinit init_hwif_atiixp(ide_hwif_t *hwif) hwif->irq = ch ? 15 : 14; hwif->autodma = 0; - hwif->tuneproc = &atiixp_tuneproc; + hwif->set_pio_mode = &atiixp_set_pio_mode; hwif->speedproc = &atiixp_speedproc; hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; diff --git a/drivers/ide/pci/cmd640.c b/drivers/ide/pci/cmd640.c index 9689494efa2..f369645e4d1 100644 --- a/drivers/ide/pci/cmd640.c +++ b/drivers/ide/pci/cmd640.c @@ -628,45 +628,40 @@ static void cmd640_set_mode (unsigned int index, u8 pio_mode, unsigned int cycle program_drive_counts (index); } -/* - * Drive PIO mode selection: - */ -static void cmd640_tune_drive (ide_drive_t *drive, u8 mode_wanted) +static void cmd640_set_pio_mode(ide_drive_t *drive, const u8 pio) { unsigned int index = 0, cycle_time; u8 b; while (drive != cmd_drives[index]) { if (++index > 3) { - printk("%s: bad news in cmd640_tune_drive\n", drive->name); + printk(KERN_ERR "%s: bad news in %s\n", + drive->name, __FUNCTION__); return; } } - switch (mode_wanted) { + switch (pio) { case 6: /* set fast-devsel off */ case 7: /* set fast-devsel on */ - mode_wanted &= 1; b = get_cmd640_reg(CNTRL) & ~0x27; - if (mode_wanted) + if (pio & 1) b |= 0x27; put_cmd640_reg(CNTRL, b); - printk("%s: %sabled cmd640 fast host timing (devsel)\n", drive->name, mode_wanted ? "en" : "dis"); + printk("%s: %sabled cmd640 fast host timing (devsel)\n", drive->name, (pio & 1) ? "en" : "dis"); return; case 8: /* set prefetch off */ case 9: /* set prefetch on */ - mode_wanted &= 1; - set_prefetch_mode(index, mode_wanted); - printk("%s: %sabled cmd640 prefetch\n", drive->name, mode_wanted ? "en" : "dis"); + set_prefetch_mode(index, pio & 1); + printk("%s: %sabled cmd640 prefetch\n", drive->name, (pio & 1) ? "en" : "dis"); return; } - mode_wanted = ide_get_best_pio_mode(drive, mode_wanted, 5); - cycle_time = ide_pio_cycle_time(drive, mode_wanted); - cmd640_set_mode(index, mode_wanted, cycle_time); + cycle_time = ide_pio_cycle_time(drive, pio); + cmd640_set_mode(index, pio, cycle_time); printk("%s: selected cmd640 PIO mode%d (%dns)", - drive->name, mode_wanted, cycle_time); + drive->name, pio, cycle_time); display_clocks(index); } @@ -766,8 +761,10 @@ int __init ide_probe_for_cmd640x (void) cmd_hwif0->name, 'a' + cmd640_chip_version - 1, bus_type, cfr); cmd_hwif0->chipset = ide_cmd640; #ifdef CONFIG_BLK_DEV_CMD640_ENHANCED + cmd_hwif0->host_flags = IDE_HFLAG_ABUSE_PREFETCH | + IDE_HFLAG_ABUSE_FAST_DEVSEL; cmd_hwif0->pio_mask = ATA_PIO5; - cmd_hwif0->tuneproc = &cmd640_tune_drive; + cmd_hwif0->set_pio_mode = &cmd640_set_pio_mode; #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */ /* @@ -822,8 +819,10 @@ int __init ide_probe_for_cmd640x (void) cmd_hwif1->mate = cmd_hwif0; cmd_hwif1->channel = 1; #ifdef CONFIG_BLK_DEV_CMD640_ENHANCED + cmd_hwif1->host_flags = IDE_HFLAG_ABUSE_PREFETCH | + IDE_HFLAG_ABUSE_FAST_DEVSEL; cmd_hwif1->pio_mask = ATA_PIO5; - cmd_hwif1->tuneproc = &cmd640_tune_drive; + cmd_hwif1->set_pio_mode = &cmd640_set_pio_mode; #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */ } printk(KERN_INFO "%s: %sserialized, secondary interface %s\n", cmd_hwif1->name, diff --git a/drivers/ide/pci/cmd64x.c b/drivers/ide/pci/cmd64x.c index 5fe50a234ce..85f5e42eb83 100644 --- a/drivers/ide/pci/cmd64x.c +++ b/drivers/ide/pci/cmd64x.c @@ -214,28 +214,25 @@ static void program_cycle_times (ide_drive_t *drive, int cycle_time, int active_ } /* - * This routine selects drive's best PIO mode and writes into the chipset - * registers setup/active/recovery timings. + * This routine writes into the chipset registers + * PIO setup/active/recovery timings. */ -static u8 cmd64x_tune_pio (ide_drive_t *drive, u8 mode_wanted) +static void cmd64x_tune_pio(ide_drive_t *drive, const u8 pio) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; unsigned int cycle_time; - u8 pio_mode, setup_count, arttim = 0; + u8 setup_count, arttim = 0; + static const u8 setup_values[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0}; static const u8 arttim_regs[4] = {ARTTIM0, ARTTIM1, ARTTIM23, ARTTIM23}; - pio_mode = ide_get_best_pio_mode(drive, mode_wanted, 5); - cycle_time = ide_pio_cycle_time(drive, pio_mode); - - cmdprintk("%s: PIO mode wanted %d, selected %d (%d ns)\n", - drive->name, mode_wanted, pio_mode, cycle_time); + cycle_time = ide_pio_cycle_time(drive, pio); program_cycle_times(drive, cycle_time, - ide_pio_timings[pio_mode].active_time); + ide_pio_timings[pio].active_time); - setup_count = quantize_timing(ide_pio_timings[pio_mode].setup_time, + setup_count = quantize_timing(ide_pio_timings[pio].setup_time, 1000 / system_bus_clock()); /* @@ -266,16 +263,14 @@ static u8 cmd64x_tune_pio (ide_drive_t *drive, u8 mode_wanted) arttim |= setup_values[setup_count]; (void) pci_write_config_byte(dev, arttim_regs[drive->dn], arttim); cmdprintk("Write 0x%02x to reg 0x%x\n", arttim, arttim_regs[drive->dn]); - - return pio_mode; } /* * Attempts to set drive's PIO mode. - * Special cases are 8: prefetch off, 9: prefetch on (both never worked), - * and 255: auto-select best mode (used at boot time). + * Special cases are 8: prefetch off, 9: prefetch on (both never worked) */ -static void cmd64x_tune_drive (ide_drive_t *drive, u8 pio) + +static void cmd64x_set_pio_mode(ide_drive_t *drive, const u8 pio) { /* * Filter out the prefetch control values @@ -284,7 +279,7 @@ static void cmd64x_tune_drive (ide_drive_t *drive, u8 pio) if (pio == 8 || pio == 9) return; - pio = cmd64x_tune_pio(drive, pio); + cmd64x_tune_pio(drive, pio); (void) ide_config_drive_speed(drive, XFER_PIO_0 + pio); } @@ -334,7 +329,7 @@ static int cmd64x_tune_chipset(ide_drive_t *drive, const u8 speed) case XFER_PIO_2: case XFER_PIO_1: case XFER_PIO_0: - (void) cmd64x_tune_pio(drive, speed - XFER_PIO_0); + cmd64x_tune_pio(drive, speed - XFER_PIO_0); break; default: return 1; @@ -352,7 +347,7 @@ static int cmd64x_config_drive_for_dma (ide_drive_t *drive) return 0; if (ide_use_fast_pio(drive)) - cmd64x_tune_drive(drive, 255); + ide_set_max_pio(drive); return -1; } @@ -536,7 +531,7 @@ static void __devinit init_hwif_cmd64x(ide_hwif_t *hwif) pci_read_config_byte(dev, PCI_REVISION_ID, &rev); - hwif->tuneproc = &cmd64x_tune_drive; + hwif->set_pio_mode = &cmd64x_set_pio_mode; hwif->speedproc = &cmd64x_tune_chipset; hwif->drives[0].autotune = hwif->drives[1].autotune = 1; @@ -620,6 +615,7 @@ static ide_pci_device_t cmd64x_chipsets[] __devinitdata = { .autodma = AUTODMA, .enablebits = {{0x00,0x00,0x00}, {0x51,0x08,0x08}}, .bootable = ON_BOARD, + .host_flags = IDE_HFLAG_ABUSE_PREFETCH, .pio_mask = ATA_PIO5, .udma_mask = 0x00, /* no udma */ },{ /* 1 */ @@ -630,6 +626,7 @@ static ide_pci_device_t cmd64x_chipsets[] __devinitdata = { .autodma = AUTODMA, .enablebits = {{0x51,0x04,0x04}, {0x51,0x08,0x08}}, .bootable = ON_BOARD, + .host_flags = IDE_HFLAG_ABUSE_PREFETCH, .pio_mask = ATA_PIO5, .udma_mask = 0x07, /* udma0-2 */ },{ /* 2 */ @@ -640,6 +637,7 @@ static ide_pci_device_t cmd64x_chipsets[] __devinitdata = { .autodma = AUTODMA, .enablebits = {{0x51,0x04,0x04}, {0x51,0x08,0x08}}, .bootable = ON_BOARD, + .host_flags = IDE_HFLAG_ABUSE_PREFETCH, .pio_mask = ATA_PIO5, .udma_mask = 0x1f, /* udma0-4 */ },{ /* 3 */ @@ -650,6 +648,7 @@ static ide_pci_device_t cmd64x_chipsets[] __devinitdata = { .autodma = AUTODMA, .enablebits = {{0x51,0x04,0x04}, {0x51,0x08,0x08}}, .bootable = ON_BOARD, + .host_flags = IDE_HFLAG_ABUSE_PREFETCH, .pio_mask = ATA_PIO5, .udma_mask = 0x3f, /* udma0-5 */ } diff --git a/drivers/ide/pci/cs5520.c b/drivers/ide/pci/cs5520.c index af67438328a..a73c318ff08 100644 --- a/drivers/ide/pci/cs5520.c +++ b/drivers/ide/pci/cs5520.c @@ -122,17 +122,16 @@ static int cs5520_tune_chipset(ide_drive_t *drive, const u8 speed) return error; } - -static void cs5520_tune_drive(ide_drive_t *drive, u8 pio) + +static void cs5520_set_pio_mode(ide_drive_t *drive, const u8 pio) { - pio = ide_get_best_pio_mode(drive, pio, 4); - cs5520_tune_chipset(drive, (XFER_PIO_0 + pio)); + cs5520_tune_chipset(drive, XFER_PIO_0 + pio); } static int cs5520_config_drive_xfer_rate(ide_drive_t *drive) { /* Tune the drive for PIO modes up to PIO 4 */ - cs5520_tune_drive(drive, 255); + ide_set_max_pio(drive); /* Then tell the core to use DMA operations */ return 0; @@ -164,7 +163,7 @@ static int cs5520_dma_on(ide_drive_t *drive) static void __devinit init_hwif_cs5520(ide_hwif_t *hwif) { - hwif->tuneproc = &cs5520_tune_drive; + hwif->set_pio_mode = &cs5520_set_pio_mode; hwif->speedproc = &cs5520_tune_chipset; hwif->ide_dma_check = &cs5520_config_drive_xfer_rate; hwif->ide_dma_on = &cs5520_dma_on; diff --git a/drivers/ide/pci/cs5530.c b/drivers/ide/pci/cs5530.c index 518f430c152..1588a323c5d 100644 --- a/drivers/ide/pci/cs5530.c +++ b/drivers/ide/pci/cs5530.c @@ -71,19 +71,18 @@ static void cs5530_tunepio(ide_drive_t *drive, u8 pio) } /** - * cs5530_tuneproc - select/set PIO modes + * cs5530_set_pio_mode - set PIO mode + * @drive: drive + * @pio: PIO mode number * - * cs5530_tuneproc() handles selection/setting of PIO modes - * for both the chipset and drive. + * Handles setting of PIO mode for both the chipset and drive. * - * The ide_init_cs5530() routine guarantees that all drives + * The init_hwif_cs5530() routine guarantees that all drives * will have valid default PIO timings set up before we get here. */ -static void cs5530_tuneproc (ide_drive_t *drive, u8 pio) /* pio=255 means "autotune" */ +static void cs5530_set_pio_mode(ide_drive_t *drive, const u8 pio) { - pio = ide_get_best_pio_mode(drive, pio, 4); - if (cs5530_set_xfer_mode(drive, XFER_PIO_0 + pio) == 0) cs5530_tunepio(drive, pio); } @@ -306,7 +305,7 @@ static void __devinit init_hwif_cs5530 (ide_hwif_t *hwif) if (hwif->mate) hwif->serialized = hwif->mate->serialized = 1; - hwif->tuneproc = &cs5530_tuneproc; + hwif->set_pio_mode = &cs5530_set_pio_mode; hwif->speedproc = &cs5530_tune_chipset; basereg = CS5530_BASEREG(hwif); diff --git a/drivers/ide/pci/cs5535.c b/drivers/ide/pci/cs5535.c index bc00e7b6215..383b7eccbcb 100644 --- a/drivers/ide/pci/cs5535.c +++ b/drivers/ide/pci/cs5535.c @@ -147,16 +147,16 @@ static int cs5535_set_drive(ide_drive_t *drive, u8 speed) return 0; } -/**** - * cs5535_tuneproc - PIO setup - * @drive: drive to set up - * @pio: mode to use (255 for 'best possible') +/** + * cs5535_set_pio_mode - PIO setup + * @drive: drive + * @pio: PIO mode number * * A callback from the upper layers for PIO-only tuning. */ -static void cs5535_tuneproc(ide_drive_t *drive, u8 pio) + +static void cs5535_set_pio_mode(ide_drive_t *drive, const u8 pio) { - pio = ide_get_best_pio_mode(drive, pio, 4); ide_config_drive_speed(drive, XFER_PIO_0 + pio); cs5535_set_speed(drive, XFER_PIO_0 + pio); } @@ -169,7 +169,7 @@ static int cs5535_dma_check(ide_drive_t *drive) return 0; if (ide_use_fast_pio(drive)) - cs5535_tuneproc(drive, 255); + ide_set_max_pio(drive); return -1; } @@ -198,7 +198,7 @@ static void __devinit init_hwif_cs5535(ide_hwif_t *hwif) hwif->autodma = 0; - hwif->tuneproc = &cs5535_tuneproc; + hwif->set_pio_mode = &cs5535_set_pio_mode; hwif->speedproc = &cs5535_set_drive; hwif->ide_dma_check = &cs5535_dma_check; diff --git a/drivers/ide/pci/cy82c693.c b/drivers/ide/pci/cy82c693.c index daa36fcbc8e..dc278025d31 100644 --- a/drivers/ide/pci/cy82c693.c +++ b/drivers/ide/pci/cy82c693.c @@ -97,9 +97,6 @@ #define CY82_INDEX_CHANNEL1 0x31 #define CY82_INDEX_TIMEOUT 0x32 -/* the max PIO mode - from datasheet */ -#define CY82C693_MAX_PIO 4 - /* the min and max PCI bus speed in MHz - from datasheet */ #define CY82C963_MIN_BUS_SPEED 25 #define CY82C963_MAX_BUS_SPEED 33 @@ -148,9 +145,6 @@ static void compute_clocks (u8 pio, pio_clocks_t *p_pclk) * so you can play with the idebus=xx parameter */ - if (pio > CY82C693_MAX_PIO) - pio = CY82C693_MAX_PIO; - /* let's calc the address setup time clocks */ p_pclk->address_time = (u8)calc_clk(ide_pio_timings[pio].setup_time, bus_speed); @@ -269,10 +263,7 @@ static int cy82c693_ide_dma_on (ide_drive_t *drive) return __ide_dma_on(drive); } -/* - * tune ide drive - set PIO mode - */ -static void cy82c693_tune_drive (ide_drive_t *drive, u8 pio) +static void cy82c693_set_pio_mode(ide_drive_t *drive, const u8 pio) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; @@ -329,13 +320,6 @@ static void cy82c693_tune_drive (ide_drive_t *drive, u8 pio) addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8); #endif /* CY82C693_DEBUG_LOGS */ - /* first let's calc the pio modes */ - pio = ide_get_best_pio_mode(drive, pio, CY82C693_MAX_PIO); - -#if CY82C693_DEBUG_INFO - printk (KERN_INFO "%s: Selected PIO mode %d\n", drive->name, pio); -#endif /* CY82C693_DEBUG_INFO */ - /* let's calc the values for this PIO mode */ compute_clocks(pio, &pclk); @@ -447,7 +431,7 @@ static void __devinit init_hwif_cy82c693(ide_hwif_t *hwif) hwif->autodma = 0; hwif->chipset = ide_cy82c693; - hwif->tuneproc = &cy82c693_tune_drive; + hwif->set_pio_mode = &cy82c693_set_pio_mode; if (!hwif->dma_base) { hwif->drives[0].autotune = 1; diff --git a/drivers/ide/pci/hpt34x.c b/drivers/ide/pci/hpt34x.c index ba982d66ff7..a1bb10188fe 100644 --- a/drivers/ide/pci/hpt34x.c +++ b/drivers/ide/pci/hpt34x.c @@ -77,9 +77,8 @@ static int hpt34x_tune_chipset(ide_drive_t *drive, const u8 speed) return(ide_config_drive_speed(drive, speed)); } -static void hpt34x_tune_drive (ide_drive_t *drive, u8 pio) +static void hpt34x_set_pio_mode(ide_drive_t *drive, const u8 pio) { - pio = ide_get_best_pio_mode(drive, pio, 5); (void) hpt34x_tune_chipset(drive, (XFER_PIO_0 + pio)); } @@ -91,7 +90,7 @@ static int hpt34x_config_drive_xfer_rate (ide_drive_t *drive) return -1; if (ide_use_fast_pio(drive)) - hpt34x_tune_drive(drive, 255); + ide_set_max_pio(drive); return -1; } @@ -145,7 +144,7 @@ static void __devinit init_hwif_hpt34x(ide_hwif_t *hwif) hwif->autodma = 0; - hwif->tuneproc = &hpt34x_tune_drive; + hwif->set_pio_mode = &hpt34x_set_pio_mode; hwif->speedproc = &hpt34x_tune_chipset; hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c index 67127ac3a14..0e7d3b60d43 100644 --- a/drivers/ide/pci/hpt366.c +++ b/drivers/ide/pci/hpt366.c @@ -662,9 +662,8 @@ static int hpt3xx_tune_chipset(ide_drive_t *drive, u8 speed) return hpt36x_tune_chipset(drive, speed); } -static void hpt3xx_tune_drive(ide_drive_t *drive, u8 pio) +static void hpt3xx_set_pio_mode(ide_drive_t *drive, const u8 pio) { - pio = ide_get_best_pio_mode(drive, pio, 4); (void) hpt3xx_tune_chipset (drive, XFER_PIO_0 + pio); } @@ -726,7 +725,7 @@ static int hpt366_config_drive_xfer_rate(ide_drive_t *drive) return 0; if (ide_use_fast_pio(drive)) - hpt3xx_tune_drive(drive, 255); + ide_set_max_pio(drive); return -1; } @@ -1257,7 +1256,7 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif) /* Cache the channel's MISC. control registers' offset */ hwif->select_data = hwif->channel ? 0x54 : 0x50; - hwif->tuneproc = &hpt3xx_tune_drive; + hwif->set_pio_mode = &hpt3xx_set_pio_mode; hwif->speedproc = &hpt3xx_tune_chipset; hwif->quirkproc = &hpt3xx_quirkproc; hwif->intrproc = &hpt3xx_intrproc; diff --git a/drivers/ide/pci/it8213.c b/drivers/ide/pci/it8213.c index 6fa955749ae..d07771e06b2 100644 --- a/drivers/ide/pci/it8213.c +++ b/drivers/ide/pci/it8213.c @@ -105,9 +105,8 @@ static void it8213_tune_pio(ide_drive_t *drive, const u8 pio) spin_unlock_irqrestore(&tune_lock, flags); } -static void it8213_tuneproc(ide_drive_t *drive, u8 pio) +static void it8213_set_pio_mode(ide_drive_t *drive, const u8 pio) { - pio = ide_get_best_pio_mode(drive, pio, 4); it8213_tune_pio(drive, pio); ide_config_drive_speed(drive, XFER_PIO_0 + pio); } @@ -212,7 +211,7 @@ static int it8213_config_drive_for_dma (ide_drive_t *drive) if (ide_tune_dma(drive)) return 0; - it8213_tuneproc(drive, 255); + ide_set_max_pio(drive); return -1; } @@ -231,7 +230,7 @@ static void __devinit init_hwif_it8213(ide_hwif_t *hwif) u8 reg42h = 0; hwif->speedproc = &it8213_tune_chipset; - hwif->tuneproc = &it8213_tuneproc; + hwif->set_pio_mode = &it8213_set_pio_mode; hwif->autodma = 0; diff --git a/drivers/ide/pci/it821x.c b/drivers/ide/pci/it821x.c index a756e61bcb3..0cce4a7f5e4 100644 --- a/drivers/ide/pci/it821x.c +++ b/drivers/ide/pci/it821x.c @@ -274,9 +274,8 @@ static int it821x_tunepio(ide_drive_t *drive, u8 set_pio) return ide_config_drive_speed(drive, XFER_PIO_0 + set_pio); } -static void it821x_tuneproc(ide_drive_t *drive, u8 pio) +static void it821x_set_pio_mode(ide_drive_t *drive, const u8 pio) { - pio = ide_get_best_pio_mode(drive, pio, 4); (void)it821x_tunepio(drive, pio); } @@ -473,7 +472,7 @@ static int it821x_config_drive_for_dma (ide_drive_t *drive) if (ide_tune_dma(drive)) return 0; - it821x_tuneproc(drive, 255); + ide_set_max_pio(drive); return -1; } @@ -640,7 +639,7 @@ static void __devinit init_hwif_it821x(ide_hwif_t *hwif) } hwif->speedproc = &it821x_tune_chipset; - hwif->tuneproc = &it821x_tuneproc; + hwif->set_pio_mode = &it821x_set_pio_mode; /* MWDMA/PIO clock switching for pass through mode */ if(!idev->smart) { diff --git a/drivers/ide/pci/jmicron.c b/drivers/ide/pci/jmicron.c index 7bac87fb481..d379fbaf674 100644 --- a/drivers/ide/pci/jmicron.c +++ b/drivers/ide/pci/jmicron.c @@ -83,9 +83,8 @@ static u8 __devinit ata66_jmicron(ide_hwif_t *hwif) return ATA_CBL_PATA80; } -static void jmicron_tuneproc(ide_drive_t *drive, u8 pio) +static void jmicron_set_pio_mode(ide_drive_t *drive, const u8 pio) { - pio = ide_get_best_pio_mode(drive, pio, 5); ide_config_drive_speed(drive, XFER_PIO_0 + pio); } @@ -116,7 +115,7 @@ static int jmicron_config_drive_for_dma (ide_drive_t *drive) if (ide_tune_dma(drive)) return 0; - jmicron_tuneproc(drive, 255); + ide_set_max_pio(drive); return -1; } @@ -131,7 +130,7 @@ static int jmicron_config_drive_for_dma (ide_drive_t *drive) static void __devinit init_hwif_jmicron(ide_hwif_t *hwif) { hwif->speedproc = &jmicron_tune_chipset; - hwif->tuneproc = &jmicron_tuneproc; + hwif->set_pio_mode = &jmicron_set_pio_mode; hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; diff --git a/drivers/ide/pci/opti621.c b/drivers/ide/pci/opti621.c index 3a2bb272351..9fa06393469 100644 --- a/drivers/ide/pci/opti621.c +++ b/drivers/ide/pci/opti621.c @@ -47,7 +47,7 @@ * The main problem with OPTi is that some timings for master * and slave must be the same. For example, if you have master * PIO 3 and slave PIO 0, driver have to set some timings of - * master for PIO 0. Second problem is that opti621_tune_drive + * master for PIO 0. Second problem is that opti621_set_pio_mode * got only one drive to set, but have to set both drives. * This is solved in compute_pios. If you don't set * the second drive, compute_pios use ide_get_best_pio_mode @@ -103,7 +103,7 @@ #include -#define OPTI621_MAX_PIO 3 +//#define OPTI621_MAX_PIO 3 /* In fact, I do not have any PIO 4 drive * (address: 25 ns, data: 70 ns, recovery: 35 ns), * but OPTi 82C621 is programmable and it can do (minimal values): @@ -136,8 +136,8 @@ static int reg_base; #define PIO_NOT_EXIST 254 #define PIO_DONT_KNOW 255 -/* there are stored pio numbers from other calls of opti621_tune_drive */ -static void compute_pios(ide_drive_t *drive, u8 pio) +/* there are stored pio numbers from other calls of opti621_set_pio_mode */ +static void compute_pios(ide_drive_t *drive, const u8 pio) /* Store values into drive->drive_data * second_contr - 0 for primary controller, 1 for secondary * slave_drive - 0 -> pio is for master, 1 -> pio is for slave @@ -147,12 +147,13 @@ static void compute_pios(ide_drive_t *drive, u8 pio) int d; ide_hwif_t *hwif = HWIF(drive); - drive->drive_data = ide_get_best_pio_mode(drive, pio, OPTI621_MAX_PIO); + drive->drive_data = pio; + for (d = 0; d < 2; ++d) { drive = &hwif->drives[d]; if (drive->present) { if (drive->drive_data == PIO_DONT_KNOW) - drive->drive_data = ide_get_best_pio_mode(drive, 255, OPTI621_MAX_PIO); + drive->drive_data = ide_get_best_pio_mode(drive, 255, 3); #ifdef OPTI621_DEBUG printk("%s: Selected PIO mode %d\n", drive->name, drive->drive_data); @@ -240,8 +241,7 @@ static void compute_clocks(int pio, pio_clocks_t *clks) } -/* Main tune procedure, called from tuneproc. */ -static void opti621_tune_drive (ide_drive_t *drive, u8 pio) +static void opti621_set_pio_mode(ide_drive_t *drive, const u8 pio) { /* primary and secondary drives share some registers, * so we have to program both drives @@ -331,7 +331,8 @@ static void __devinit init_hwif_opti621 (ide_hwif_t *hwif) hwif->autodma = 0; hwif->drives[0].drive_data = PIO_DONT_KNOW; hwif->drives[1].drive_data = PIO_DONT_KNOW; - hwif->tuneproc = &opti621_tune_drive; + + hwif->set_pio_mode = &opti621_set_pio_mode; if (!(hwif->dma_base)) return; diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c index 3787194a224..5fb1eedc819 100644 --- a/drivers/ide/pci/pdc202xx_new.c +++ b/drivers/ide/pci/pdc202xx_new.c @@ -215,9 +215,8 @@ static int pdcnew_tune_chipset(ide_drive_t *drive, const u8 speed) return err; } -static void pdcnew_tune_drive(ide_drive_t *drive, u8 pio) +static void pdcnew_set_pio_mode(ide_drive_t *drive, const u8 pio) { - pio = ide_get_best_pio_mode(drive, pio, 4); (void)pdcnew_tune_chipset(drive, XFER_PIO_0 + pio); } @@ -237,7 +236,7 @@ static int pdcnew_config_drive_xfer_rate(ide_drive_t *drive) return 0; if (ide_use_fast_pio(drive)) - pdcnew_tune_drive(drive, 255); + ide_set_max_pio(drive); return -1; } @@ -490,7 +489,8 @@ static void __devinit init_hwif_pdc202new(ide_hwif_t *hwif) { hwif->autodma = 0; - hwif->tuneproc = &pdcnew_tune_drive; + hwif->set_pio_mode = &pdcnew_set_pio_mode; + hwif->quirkproc = &pdcnew_quirkproc; hwif->speedproc = &pdcnew_tune_chipset; hwif->resetproc = &pdcnew_reset; diff --git a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c index e7a5e3014c0..b578307fad5 100644 --- a/drivers/ide/pci/pdc202xx_old.c +++ b/drivers/ide/pci/pdc202xx_old.c @@ -142,9 +142,8 @@ static int pdc202xx_tune_chipset(ide_drive_t *drive, const u8 speed) return ide_config_drive_speed(drive, speed); } -static void pdc202xx_tune_drive(ide_drive_t *drive, u8 pio) +static void pdc202xx_set_pio_mode(ide_drive_t *drive, const u8 pio) { - pio = ide_get_best_pio_mode(drive, pio, 4); pdc202xx_tune_chipset(drive, XFER_PIO_0 + pio); } @@ -190,7 +189,7 @@ static int pdc202xx_config_drive_xfer_rate (ide_drive_t *drive) return 0; if (ide_use_fast_pio(drive)) - pdc202xx_tune_drive(drive, 255); + ide_set_max_pio(drive); return -1; } @@ -306,10 +305,11 @@ static void pdc202xx_reset (ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); ide_hwif_t *mate = hwif->mate; - + pdc202xx_reset_host(hwif); pdc202xx_reset_host(mate); - pdc202xx_tune_drive(drive, 255); + + ide_set_max_pio(drive); } static unsigned int __devinit init_chipset_pdc202xx(struct pci_dev *dev, @@ -328,7 +328,9 @@ static void __devinit init_hwif_pdc202xx(ide_hwif_t *hwif) hwif->rqsize = 256; hwif->autodma = 0; - hwif->tuneproc = &pdc202xx_tune_drive; + + hwif->set_pio_mode = &pdc202xx_set_pio_mode; + hwif->quirkproc = &pdc202xx_quirkproc; if (hwif->pci_dev->device != PCI_DEVICE_ID_PROMISE_20246) diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c index b66f9d1411b..07492d71c60 100644 --- a/drivers/ide/pci/piix.c +++ b/drivers/ide/pci/piix.c @@ -17,11 +17,11 @@ * 41 * 43 * - * | PIO 0 | c0 | 80 | 0 | piix_tune_drive(drive, 0); - * | PIO 2 | SW2 | d0 | 90 | 4 | piix_tune_drive(drive, 2); - * | PIO 3 | MW1 | e1 | a1 | 9 | piix_tune_drive(drive, 3); - * | PIO 4 | MW2 | e3 | a3 | b | piix_tune_drive(drive, 4); - * + * | PIO 0 | c0 | 80 | 0 | + * | PIO 2 | SW2 | d0 | 90 | 4 | + * | PIO 3 | MW1 | e1 | a1 | 9 | + * | PIO 4 | MW2 | e3 | a3 | b | + * * sitre = word40 & 0x4000; primary * sitre = word42 & 0x4000; secondary * @@ -204,16 +204,16 @@ static void piix_tune_pio (ide_drive_t *drive, u8 pio) } /** - * piix_tune_drive - tune a drive attached to PIIX + * piix_set_pio_mode - set PIO mode * @drive: drive to tune * @pio: desired PIO mode * * Set the drive's PIO mode (might be useful if drive is not registered * in CMOS for any reason). */ -static void piix_tune_drive (ide_drive_t *drive, u8 pio) + +static void piix_set_pio_mode(ide_drive_t *drive, const u8 pio) { - pio = ide_get_best_pio_mode(drive, pio, 4); piix_tune_pio(drive, pio); (void) ide_config_drive_speed(drive, XFER_PIO_0 + pio); } @@ -317,7 +317,7 @@ static int piix_config_drive_xfer_rate (ide_drive_t *drive) return 0; if (ide_use_fast_pio(drive)) - piix_tune_drive(drive, 255); + ide_set_max_pio(drive); return -1; } @@ -454,7 +454,8 @@ static void __devinit init_hwif_piix(ide_hwif_t *hwif) } hwif->autodma = 0; - hwif->tuneproc = &piix_tune_drive; + + hwif->set_pio_mode = &piix_set_pio_mode; hwif->speedproc = &piix_tune_chipset; hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; diff --git a/drivers/ide/pci/sc1200.c b/drivers/ide/pci/sc1200.c index 059071cd2d4..f9f5ed90657 100644 --- a/drivers/ide/pci/sc1200.c +++ b/drivers/ide/pci/sc1200.c @@ -272,19 +272,20 @@ static int sc1200_ide_dma_end (ide_drive_t *drive) } /* - * sc1200_tuneproc() handles selection/setting of PIO modes + * sc1200_set_pio_mode() handles setting of PIO modes * for both the chipset and drive. * * All existing BIOSs for this chipset guarantee that all drives * will have valid default PIO timings set up before we get here. */ -static void sc1200_tuneproc (ide_drive_t *drive, byte pio) /* mode=255 means "autotune" */ + +static void sc1200_set_pio_mode(ide_drive_t *drive, const u8 pio) { ide_hwif_t *hwif = HWIF(drive); int mode = -1; /* - * bad abuse of ->tuneproc interface + * bad abuse of ->set_pio_mode interface */ switch (pio) { case 200: mode = XFER_UDMA_0; break; @@ -302,9 +303,6 @@ static void sc1200_tuneproc (ide_drive_t *drive, byte pio) /* mode=255 means "au return; } - pio = ide_get_best_pio_mode(drive, pio, 4); - printk("SC1200: %s: setting PIO mode%d\n", drive->name, pio); - if (sc1200_set_xfer_mode(drive, XFER_PIO_0 + pio) == 0) sc1200_tunepio(drive, pio); } @@ -420,7 +418,8 @@ static void __devinit init_hwif_sc1200 (ide_hwif_t *hwif) hwif->ide_dma_end = &sc1200_ide_dma_end; if (!noautodma) hwif->autodma = 1; - hwif->tuneproc = &sc1200_tuneproc; + + hwif->set_pio_mode = &sc1200_set_pio_mode; hwif->speedproc = &sc1200_tune_chipset; } hwif->atapi_dma = 1; @@ -436,6 +435,7 @@ static ide_pci_device_t sc1200_chipset __devinitdata = { .init_hwif = init_hwif_sc1200, .autodma = AUTODMA, .bootable = ON_BOARD, + .host_flags = IDE_HFLAG_ABUSE_DMA_MODES, .pio_mask = ATA_PIO4, }; diff --git a/drivers/ide/pci/scc_pata.c b/drivers/ide/pci/scc_pata.c index a19687caf65..3505d57eda1 100644 --- a/drivers/ide/pci/scc_pata.c +++ b/drivers/ide/pci/scc_pata.c @@ -221,9 +221,8 @@ static void scc_tune_pio(ide_drive_t *drive, const u8 pio) out_be32((void __iomem *)pioct_port, reg); } -static void scc_tuneproc(ide_drive_t *drive, u8 pio) +static void scc_set_pio_mode(ide_drive_t *drive, const u8 pio) { - pio = ide_get_best_pio_mode(drive, pio, 4); scc_tune_pio(drive, pio); ide_config_drive_speed(drive, XFER_PIO_0 + pio); } @@ -316,7 +315,7 @@ static int scc_config_drive_for_dma(ide_drive_t *drive) return 0; if (ide_use_fast_pio(drive)) - scc_tuneproc(drive, 255); + ide_set_max_pio(drive); return -1; } @@ -717,7 +716,7 @@ static void __devinit init_hwif_scc(ide_hwif_t *hwif) hwif->dma_setup = scc_dma_setup; hwif->ide_dma_end = scc_ide_dma_end; hwif->speedproc = scc_tune_chipset; - hwif->tuneproc = scc_tuneproc; + hwif->set_pio_mode = scc_set_pio_mode; hwif->ide_dma_check = scc_config_drive_for_dma; hwif->ide_dma_test_irq = scc_dma_test_irq; hwif->udma_filter = scc_udma_filter; diff --git a/drivers/ide/pci/serverworks.c b/drivers/ide/pci/serverworks.c index b51133bb58a..f4e08abf0fe 100644 --- a/drivers/ide/pci/serverworks.c +++ b/drivers/ide/pci/serverworks.c @@ -202,9 +202,8 @@ static int svwks_tune_chipset(ide_drive_t *drive, const u8 speed) return (ide_config_drive_speed(drive, speed)); } -static void svwks_tune_drive (ide_drive_t *drive, u8 pio) +static void svwks_set_pio_mode(ide_drive_t *drive, const u8 pio) { - pio = ide_get_best_pio_mode(drive, pio, 4); svwks_tune_pio(drive, pio); (void)ide_config_drive_speed(drive, XFER_PIO_0 + pio); } @@ -217,7 +216,7 @@ static int svwks_config_drive_xfer_rate (ide_drive_t *drive) return 0; if (ide_use_fast_pio(drive)) - svwks_tune_drive(drive, 255); + ide_set_max_pio(drive); return -1; } @@ -389,7 +388,7 @@ static void __devinit init_hwif_svwks (ide_hwif_t *hwif) if (!hwif->irq) hwif->irq = hwif->channel ? 15 : 14; - hwif->tuneproc = &svwks_tune_drive; + hwif->set_pio_mode = &svwks_set_pio_mode; hwif->speedproc = &svwks_tune_chipset; hwif->udma_filter = &svwks_udma_filter; diff --git a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c index 57145767c3d..38f63d19c3b 100644 --- a/drivers/ide/pci/sgiioc4.c +++ b/drivers/ide/pci/sgiioc4.c @@ -587,7 +587,7 @@ ide_init_sgiioc4(ide_hwif_t * hwif) hwif->mwdma_mask = 0x2; /* Multimode-2 DMA */ hwif->swdma_mask = 0x2; hwif->pio_mask = 0x00; - hwif->tuneproc = NULL; /* Sets timing for PIO mode */ + hwif->set_pio_mode = NULL; /* Sets timing for PIO mode */ hwif->speedproc = NULL; /* Sets timing for DMA &/or PIO modes */ hwif->selectproc = NULL;/* Use the default routine to select drive */ hwif->reset_poll = NULL;/* No HBA specific reset_poll needed */ diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c index 4c1f3bc7e17..e07c991d91b 100644 --- a/drivers/ide/pci/siimage.c +++ b/drivers/ide/pci/siimage.c @@ -219,9 +219,8 @@ static void sil_tune_pio(ide_drive_t *drive, u8 pio) } } -static void sil_tuneproc(ide_drive_t *drive, u8 pio) +static void sil_set_pio_mode(ide_drive_t *drive, const u8 pio) { - pio = ide_get_best_pio_mode(drive, pio, 4); sil_tune_pio(drive, pio); (void)ide_config_drive_speed(drive, XFER_PIO_0 + pio); } @@ -328,7 +327,7 @@ static int siimage_config_drive_for_dma (ide_drive_t *drive) return 0; if (ide_use_fast_pio(drive)) - sil_tuneproc(drive, 255); + ide_set_max_pio(drive); return -1; } @@ -899,7 +898,7 @@ static void __devinit init_hwif_siimage(ide_hwif_t *hwif) hwif->resetproc = &siimage_reset; hwif->speedproc = &siimage_tune_chipset; - hwif->tuneproc = &sil_tuneproc; + hwif->set_pio_mode = &sil_set_pio_mode; hwif->reset_poll = &siimage_reset_poll; hwif->pre_reset = &siimage_pre_reset; hwif->udma_filter = &sil_udma_filter; diff --git a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c index fed582b4b32..7455bf357ed 100644 --- a/drivers/ide/pci/sis5513.c +++ b/drivers/ide/pci/sis5513.c @@ -519,14 +519,13 @@ static void config_art_rwp_pio (ide_drive_t *drive, u8 pio) } } -static int sis5513_tune_drive(ide_drive_t *drive, u8 pio) +static int sis5513_tune_drive(ide_drive_t *drive, const u8 pio) { - pio = ide_get_best_pio_mode(drive, pio, 4); config_art_rwp_pio(drive, pio); return ide_config_drive_speed(drive, XFER_PIO_0 + pio); } -static void sis5513_tuneproc(ide_drive_t *drive, u8 pio) +static void sis_set_pio_mode(ide_drive_t *drive, const u8 pio) { (void)sis5513_tune_drive(drive, pio); } @@ -621,7 +620,7 @@ static int sis5513_config_xfer_rate(ide_drive_t *drive) /* * TODO: always set PIO mode and remove this */ - sis5513_tuneproc(drive, 255); + ide_set_max_pio(drive); drive->init_speed = 0; @@ -629,7 +628,7 @@ static int sis5513_config_xfer_rate(ide_drive_t *drive) return 0; if (ide_use_fast_pio(drive)) - sis5513_tuneproc(drive, 255); + ide_set_max_pio(drive); return -1; } @@ -852,7 +851,7 @@ static void __devinit init_hwif_sis5513 (ide_hwif_t *hwif) if (!hwif->irq) hwif->irq = hwif->channel ? 15 : 14; - hwif->tuneproc = &sis5513_tuneproc; + hwif->set_pio_mode = &sis_set_pio_mode; hwif->speedproc = &sis5513_tune_chipset; if (chipset_family >= ATA_133) diff --git a/drivers/ide/pci/sl82c105.c b/drivers/ide/pci/sl82c105.c index 9f425b0b572..131e91ca1d8 100644 --- a/drivers/ide/pci/sl82c105.c +++ b/drivers/ide/pci/sl82c105.c @@ -75,16 +75,12 @@ static unsigned int get_pio_timings(ide_drive_t *drive, u8 pio) /* * Configure the chipset for PIO mode. */ -static u8 sl82c105_tune_pio(ide_drive_t *drive, u8 pio) +static void sl82c105_tune_pio(ide_drive_t *drive, const u8 pio) { struct pci_dev *dev = HWIF(drive)->pci_dev; int reg = 0x44 + drive->dn * 4; u16 drv_ctrl; - DBG(("sl82c105_tune_pio(drive:%s, pio:%u)\n", drive->name, pio)); - - pio = ide_get_best_pio_mode(drive, pio, 5); - drv_ctrl = get_pio_timings(drive, pio); /* @@ -106,8 +102,6 @@ static u8 sl82c105_tune_pio(ide_drive_t *drive, u8 pio) printk(KERN_DEBUG "%s: selected %s (%dns) (%04X)\n", drive->name, ide_xfer_verbose(pio + XFER_PIO_0), ide_pio_cycle_time(drive, pio), drv_ctrl); - - return pio; } /* @@ -151,7 +145,7 @@ static int sl82c105_tune_chipset(ide_drive_t *drive, const u8 speed) case XFER_PIO_2: case XFER_PIO_1: case XFER_PIO_0: - (void) sl82c105_tune_pio(drive, speed - XFER_PIO_0); + sl82c105_tune_pio(drive, speed - XFER_PIO_0); break; default: return -1; @@ -325,11 +319,10 @@ static void sl82c105_resetproc(ide_drive_t *drive) * We only deal with PIO mode here - DMA mode 'using_dma' is not * initialised at the point that this function is called. */ -static void sl82c105_tune_drive(ide_drive_t *drive, u8 pio) +static void sl82c105_set_pio_mode(ide_drive_t *drive, const u8 pio) { - DBG(("sl82c105_tune_drive(drive:%s, pio:%u)\n", drive->name, pio)); + sl82c105_tune_pio(drive, pio); - pio = sl82c105_tune_pio(drive, pio); (void) ide_config_drive_speed(drive, XFER_PIO_0 + pio); } @@ -397,7 +390,7 @@ static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif) DBG(("init_hwif_sl82c105(hwif: ide%d)\n", hwif->index)); - hwif->tuneproc = &sl82c105_tune_drive; + hwif->set_pio_mode = &sl82c105_set_pio_mode; hwif->speedproc = &sl82c105_tune_chipset; hwif->selectproc = &sl82c105_selectproc; hwif->resetproc = &sl82c105_resetproc; diff --git a/drivers/ide/pci/slc90e66.c b/drivers/ide/pci/slc90e66.c index cc935356507..214d396fc31 100644 --- a/drivers/ide/pci/slc90e66.c +++ b/drivers/ide/pci/slc90e66.c @@ -95,9 +95,8 @@ static void slc90e66_tune_pio (ide_drive_t *drive, u8 pio) spin_unlock_irqrestore(&ide_lock, flags); } -static void slc90e66_tune_drive (ide_drive_t *drive, u8 pio) +static void slc90e66_set_pio_mode(ide_drive_t *drive, const u8 pio) { - pio = ide_get_best_pio_mode(drive, pio, 4); slc90e66_tune_pio(drive, pio); (void) ide_config_drive_speed(drive, XFER_PIO_0 + pio); } @@ -166,7 +165,7 @@ static int slc90e66_config_drive_xfer_rate (ide_drive_t *drive) return 0; if (ide_use_fast_pio(drive)) - slc90e66_tune_drive(drive, 255); + ide_set_max_pio(drive); return -1; } @@ -182,7 +181,7 @@ static void __devinit init_hwif_slc90e66 (ide_hwif_t *hwif) hwif->irq = hwif->channel ? 15 : 14; hwif->speedproc = &slc90e66_tune_chipset; - hwif->tuneproc = &slc90e66_tune_drive; + hwif->set_pio_mode = &slc90e66_set_pio_mode; pci_read_config_byte(hwif->pci_dev, 0x47, ®47); diff --git a/drivers/ide/pci/tc86c001.c b/drivers/ide/pci/tc86c001.c index e5425772622..e23b9cfb6eb 100644 --- a/drivers/ide/pci/tc86c001.c +++ b/drivers/ide/pci/tc86c001.c @@ -43,9 +43,8 @@ static int tc86c001_tune_chipset(ide_drive_t *drive, const u8 speed) return ide_config_drive_speed(drive, speed); } -static void tc86c001_tune_drive(ide_drive_t *drive, u8 pio) +static void tc86c001_set_pio_mode(ide_drive_t *drive, const u8 pio) { - pio = ide_get_best_pio_mode(drive, pio, 4); (void) tc86c001_tune_chipset(drive, XFER_PIO_0 + pio); } @@ -171,7 +170,7 @@ static int tc86c001_config_drive_xfer_rate(ide_drive_t *drive) return 0; if (ide_use_fast_pio(drive)) - tc86c001_tune_drive(drive, 255); + ide_set_max_pio(drive); return -1; } @@ -193,7 +192,7 @@ static void __devinit init_hwif_tc86c001(ide_hwif_t *hwif) /* Store the system control register base for convenience... */ hwif->config_data = sc_base; - hwif->tuneproc = &tc86c001_tune_drive; + hwif->set_pio_mode = &tc86c001_set_pio_mode; hwif->speedproc = &tc86c001_tune_chipset; hwif->busproc = &tc86c001_busproc; diff --git a/drivers/ide/pci/triflex.c b/drivers/ide/pci/triflex.c index 47cf89be4df..c3ff066eea5 100644 --- a/drivers/ide/pci/triflex.c +++ b/drivers/ide/pci/triflex.c @@ -93,10 +93,9 @@ static int triflex_tune_chipset(ide_drive_t *drive, const u8 speed) return (ide_config_drive_speed(drive, speed)); } -static void triflex_tune_drive(ide_drive_t *drive, u8 pio) +static void triflex_set_pio_mode(ide_drive_t *drive, const u8 pio) { - int use_pio = ide_get_best_pio_mode(drive, pio, 4); - (void) triflex_tune_chipset(drive, (XFER_PIO_0 + use_pio)); + (void)triflex_tune_chipset(drive, XFER_PIO_0 + pio); } static int triflex_config_drive_xfer_rate(ide_drive_t *drive) @@ -104,14 +103,14 @@ static int triflex_config_drive_xfer_rate(ide_drive_t *drive) if (ide_tune_dma(drive)) return 0; - triflex_tune_drive(drive, 255); + ide_set_max_pio(drive); return -1; } static void __devinit init_hwif_triflex(ide_hwif_t *hwif) { - hwif->tuneproc = &triflex_tune_drive; + hwif->set_pio_mode = &triflex_set_pio_mode; hwif->speedproc = &triflex_tune_chipset; if (hwif->dma_base == 0) diff --git a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c index e3bf9073633..2fc4f8835f1 100644 --- a/drivers/ide/pci/via82cxxx.c +++ b/drivers/ide/pci/via82cxxx.c @@ -195,19 +195,16 @@ static int via_set_drive(ide_drive_t *drive, const u8 speed) } /** - * via82cxxx_tune_drive - PIO setup - * @drive: drive to set up - * @pio: mode to use (255 for 'best possible') + * via_set_pio_mode - PIO setup + * @drive: drive + * @pio: PIO mode number * * A callback from the upper layers for PIO-only tuning. */ -static void via82cxxx_tune_drive(ide_drive_t *drive, u8 pio) +static void via_set_pio_mode(ide_drive_t *drive, const u8 pio) { - if (pio == 255) - pio = ide_get_best_pio_mode(drive, 255, 5); - - via_set_drive(drive, XFER_PIO_0 + min_t(u8, pio, 5)); + via_set_drive(drive, XFER_PIO_0 + pio); } /** @@ -223,7 +220,7 @@ static int via82cxxx_ide_dma_check (ide_drive_t *drive) u8 speed = ide_max_dma_mode(drive); if (speed == 0) { - via82cxxx_tune_drive(drive, 255); + ide_set_max_pio(drive); return -1; } @@ -465,7 +462,7 @@ static void __devinit init_hwif_via82cxxx(ide_hwif_t *hwif) hwif->autodma = 0; - hwif->tuneproc = &via82cxxx_tune_drive; + hwif->set_pio_mode = &via_set_pio_mode; hwif->speedproc = &via_set_drive; diff --git a/drivers/ide/ppc/mpc8xx.c b/drivers/ide/ppc/mpc8xx.c index dab79afa9b2..df2e92034f5 100644 --- a/drivers/ide/ppc/mpc8xx.c +++ b/drivers/ide/ppc/mpc8xx.c @@ -45,7 +45,7 @@ static void print_funcid (int func); static int check_ide_device (unsigned long base); static void ide_interrupt_ack (void *dev); -static void m8xx_ide_tuneproc(ide_drive_t *drive, u8 pio); +static void m8xx_ide_set_pio_mode(ide_drive_t *drive, const u8 pio); typedef struct ide_ioport_desc { unsigned long base_off; /* Offset to PCMCIA memory */ @@ -314,9 +314,8 @@ m8xx_ide_init_hwif_ports(hw_regs_t *hw, unsigned long data_port, #endif /* CONFIG_IDE_8xx_PCCARD */ } - /* register routine to tune PIO mode */ ide_hwifs[data_port].pio_mask = ATA_PIO4; - ide_hwifs[data_port].tuneproc = m8xx_ide_tuneproc; + ide_hwifs[data_port].set_pio_mode = m8xx_ide_set_pio_mode; hw->ack_intr = (ide_ack_intr_t *) ide_interrupt_ack; /* Enable Harddisk Interrupt, @@ -401,9 +400,8 @@ void m8xx_ide_init_hwif_ports (hw_regs_t *hw, *irq = ioport_dsc[data_port].irq; } - /* register routine to tune PIO mode */ ide_hwifs[data_port].pio_mask = ATA_PIO4; - ide_hwifs[data_port].tuneproc = m8xx_ide_tuneproc; + ide_hwifs[data_port].set_pio_mode = m8xx_ide_set_pio_mode; hw->ack_intr = (ide_ack_intr_t *) ide_interrupt_ack; /* Enable Harddisk Interrupt, @@ -427,24 +425,13 @@ void m8xx_ide_init_hwif_ports (hw_regs_t *hw, #define PCMCIA_SL(t) ((t==32) ? 0 : ((t & 0x1F)<<7)) /* Strobe Length */ #endif - /* Calculate PIO timings */ -static void -m8xx_ide_tuneproc(ide_drive_t *drive, u8 pio) +static void m8xx_ide_set_pio_mode(ide_drive_t *drive, const u8 pio) { #if defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT) volatile pcmconf8xx_t *pcmp; ulong timing, mask, reg; -#endif - - pio = ide_get_best_pio_mode(drive, pio, 4); -#if 1 - printk("%s[%d] %s: best PIO mode: %d\n", - __FILE__,__LINE__,__FUNCTION__, pio); -#endif - -#if defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT) pcmp = (pcmconf8xx_t *)(&(((immap_t *)IMAP_ADDR)->im_pcmcia)); mask = ~(PCMCIA_SHT(0xFF) | PCMCIA_SST(0xFF) | PCMCIA_SL(0xFF)); diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c index 284bb7c39b8..beafdf3c112 100644 --- a/drivers/ide/ppc/pmac.c +++ b/drivers/ide/ppc/pmac.c @@ -411,7 +411,6 @@ kauai_lookup_timing(struct kauai_timing* table, int cycle_time) static void pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif); static int pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq); -static void pmac_ide_tuneproc(ide_drive_t *drive, u8 pio); static void pmac_ide_selectproc(ide_drive_t *drive); static void pmac_ide_kauai_selectproc(ide_drive_t *drive); @@ -615,7 +614,7 @@ out: * Old tuning functions (called on hdparm -p), sets up drive PIO timings */ static void -pmac_ide_tuneproc(ide_drive_t *drive, u8 pio) +pmac_ide_set_pio_mode(ide_drive_t *drive, const u8 pio) { u32 *timings; unsigned accessTicks, recTicks; @@ -629,7 +628,6 @@ pmac_ide_tuneproc(ide_drive_t *drive, u8 pio) /* which drive is it ? */ timings = &pmif->timings[drive->select.b.unit & 0x01]; - pio = ide_get_best_pio_mode(drive, pio, 4); cycle_time = ide_pio_cycle_time(drive, pio); switch (pmif->kind) { @@ -966,7 +964,7 @@ static int pmac_ide_tune_chipset(ide_drive_t *drive, const u8 speed) case XFER_PIO_2: case XFER_PIO_1: case XFER_PIO_0: - pmac_ide_tuneproc(drive, speed & 0x07); + pmac_ide_set_pio_mode(drive, speed & 0x07); break; default: ret = 1; @@ -1241,7 +1239,7 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif) hwif->drives[0].unmask = 1; hwif->drives[1].unmask = 1; hwif->pio_mask = ATA_PIO4; - hwif->tuneproc = pmac_ide_tuneproc; + hwif->set_pio_mode = pmac_ide_set_pio_mode; if (pmif->kind == controller_un_ata6 || pmif->kind == controller_k2_ata6 || pmif->kind == controller_sh_ata6) diff --git a/include/linux/ide.h b/include/linux/ide.h index 81736cb7ef3..85d448b4abe 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -634,7 +634,7 @@ typedef struct ide_drive_s { unsigned int bios_cyl; /* BIOS/fdisk/LILO number of cyls */ unsigned int cyl; /* "real" number of cyls */ - unsigned int drive_data; /* use by tuneproc/selectproc */ + unsigned int drive_data; /* used by set_pio_mode/selectproc */ unsigned int failures; /* current failure count */ unsigned int max_failures; /* maximum allowed failure count */ u64 probed_capacity;/* initial reported media capacity (ide-cd only currently) */ @@ -702,8 +702,8 @@ typedef struct hwif_s { #if 0 ide_hwif_ops_t *hwifops; #else - /* routine to tune PIO mode for drives */ - void (*tuneproc)(ide_drive_t *, u8); + /* routine to set PIO mode for drives */ + void (*set_pio_mode)(ide_drive_t *, const u8); /* routine to retune DMA modes for drives */ int (*speedproc)(ide_drive_t *, const u8); /* tweaks hardware to select drive */ @@ -1256,6 +1256,12 @@ enum { IDE_HFLAG_PIO_NO_BLACKLIST = (1 << 2), /* don't use conservative PIO "downgrade" */ IDE_HFLAG_PIO_NO_DOWNGRADE = (1 << 3), + /* use PIO8/9 for prefetch off/on */ + IDE_HFLAG_ABUSE_PREFETCH = (1 << 4), + /* use PIO6/7 for fast-devsel off/on */ + IDE_HFLAG_ABUSE_FAST_DEVSEL = (1 << 5), + /* use 100-102 and 200-202 PIO values to set DMA modes */ + IDE_HFLAG_ABUSE_DMA_MODES = (1 << 6), }; typedef struct ide_pci_device_s { @@ -1414,6 +1420,12 @@ unsigned int ide_pio_cycle_time(ide_drive_t *, u8); u8 ide_get_best_pio_mode(ide_drive_t *, u8, u8); extern const ide_pio_timings_t ide_pio_timings[6]; +void ide_set_pio(ide_drive_t *, u8); + +static inline void ide_set_max_pio(ide_drive_t *drive) +{ + ide_set_pio(drive, 255); +} extern spinlock_t ide_lock; extern struct mutex ide_cfg_mtx; -- cgit v1.2.3-70-g09d2 From 55f17e8da1f02ce0a36303a3f266c45045004cf5 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Thu, 11 Oct 2007 23:54:00 +0200 Subject: amd74xx/via82cxxx: use ide_tune_dma() * Use ide_tune_dma() in amd74xx/via82cxxx driver, this fixes following bugs: - DMA capability bit not being checked on the device - DMA blacklist not being checked - DMA mode being programmed even if drive->autodma == 0 (thus possibly destroying PIO timings) * Bump driver version. Acked-by: Sergei Shtylyov Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/amd74xx.c | 15 ++++----------- drivers/ide/pci/via82cxxx.c | 15 ++++----------- 2 files changed, 8 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c index 1088ba86cd1..513205e52ad 100644 --- a/drivers/ide/pci/amd74xx.c +++ b/drivers/ide/pci/amd74xx.c @@ -1,5 +1,5 @@ /* - * Version 2.21 + * Version 2.22 * * AMD 755/756/766/8111 and nVidia nForce/2/2s/3/3s/CK804/MCP04 * IDE driver for Linux. @@ -276,18 +276,11 @@ static void amd_set_pio_mode(ide_drive_t *drive, const u8 pio) static int amd74xx_ide_dma_check(ide_drive_t *drive) { - u8 speed = ide_max_dma_mode(drive); - - if (speed == 0) { - ide_set_max_pio(drive); - return -1; - } - - amd_set_drive(drive, speed); - - if (drive->autodma) + if (ide_tune_dma(drive)) return 0; + ide_set_max_pio(drive); + return -1; } diff --git a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c index 2fc4f8835f1..3611ca6b13b 100644 --- a/drivers/ide/pci/via82cxxx.c +++ b/drivers/ide/pci/via82cxxx.c @@ -1,6 +1,6 @@ /* * - * Version 3.47 + * Version 3.48 * * VIA IDE driver for Linux. Supported southbridges: * @@ -217,18 +217,11 @@ static void via_set_pio_mode(ide_drive_t *drive, const u8 pio) static int via82cxxx_ide_dma_check (ide_drive_t *drive) { - u8 speed = ide_max_dma_mode(drive); - - if (speed == 0) { - ide_set_max_pio(drive); - return -1; - } - - via_set_drive(drive, speed); - - if (drive->autodma) + if (ide_tune_dma(drive)) return 0; + ide_set_max_pio(drive); + return -1; } -- cgit v1.2.3-70-g09d2 From ca1997c1f35891b9e5d6c71ac587f97216886194 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Thu, 11 Oct 2007 23:54:00 +0200 Subject: sgiioc4: use ide_tune_dma() * Add DRV_NAME define and use it instead of sgiioc4_chipset.name. * Remove no longer needed sgiioc4_chipset. * Remove needless clearing of ->atapi_dma from ide_dma_sgiioc4(). * Fix ide_dma_sgiioc4() to return success/failure. Check return value in sgiioc4_ide_setup_pci_device() and set hwif->autodma accordingly. Also add missing setting of drive->autodma. * Add sgiioc4_speedproc() (implementation of ->speedproc method). * Fix ->mwdma_mask (MWDMA2 mask is 0x04 not 0x02) and remove incorrect ->swdma_mask. Also remove needless initialization of ->ultra_mask. * Use ide_tune_dma() in sgiioc4_ide_dma_check(), this fixes following bugs: - DMA capability bit not being checked on the device - DMA blacklist not being checked - MWDMA2 mode support by device not being checked Acked-by: Sergei Shtylyov Signed-off-by: Jeremy Higdon Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/sgiioc4.c | 86 +++++++++++++++++++++++------------------------ 1 file changed, 43 insertions(+), 43 deletions(-) (limited to 'drivers') diff --git a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c index 38f63d19c3b..c292e1de1d5 100644 --- a/drivers/ide/pci/sgiioc4.c +++ b/drivers/ide/pci/sgiioc4.c @@ -34,6 +34,8 @@ #include +#define DRV_NAME "SGIIOC4" + /* IOC4 Specific Definitions */ #define IOC4_CMD_OFFSET 0x100 #define IOC4_CTRL_OFFSET 0x120 @@ -289,15 +291,26 @@ static void sgiioc4_dma_off_quietly(ide_drive_t *drive) drive->hwif->dma_host_off(drive); } +static int sgiioc4_speedproc(ide_drive_t *drive, const u8 speed) +{ + if (speed != XFER_MW_DMA_2) + return 1; + + return ide_config_drive_speed(drive, speed); +} + static int sgiioc4_ide_dma_check(ide_drive_t *drive) { - /* FIXME: check for available DMA modes */ - if (ide_config_drive_speed(drive, XFER_MW_DMA_2) != 0) { - printk(KERN_WARNING "%s: couldn't set MWDMA2 mode, " - "using PIO instead\n", drive->name); - return -1; - } else + if (ide_tune_dma(drive)) return 0; + + /* + * ->set_pio_mode is not implemented currently + * so this is just for the completness + */ + ide_set_max_pio(drive); + + return -1; } /* returns 1 if dma irq issued, 0 otherwise */ @@ -353,7 +366,7 @@ sgiioc4_INB(unsigned long port) } /* Creates a dma map for the scatter-gather list entries */ -static void __devinit +static int __devinit ide_dma_sgiioc4(ide_hwif_t * hwif, unsigned long dma_base) { void __iomem *virt_dma_base; @@ -369,7 +382,7 @@ ide_dma_sgiioc4(ide_hwif_t * hwif, unsigned long dma_base) "ALREADY in use\n", __FUNCTION__, hwif->name, (void *) dma_base, (void *) dma_base + num_ports - 1); - goto dma_alloc_failure; + return -1; } virt_dma_base = ioremap(dma_base, num_ports); @@ -395,7 +408,7 @@ ide_dma_sgiioc4(ide_hwif_t * hwif, unsigned long dma_base) if (pad) { ide_set_hwifdata(hwif, pad); - return; + return 0; } pci_free_consistent(hwif->pci_dev, @@ -413,10 +426,7 @@ dma_pci_alloc_failure: dma_remap_failure: release_mem_region(dma_base, num_ports); -dma_alloc_failure: - /* Disable DMA because we couldnot allocate any DMA maps */ - hwif->autodma = 0; - hwif->atapi_dma = 0; + return -1; } /* Initializes the IOC4 DMA Engine */ @@ -581,14 +591,11 @@ static void __devinit ide_init_sgiioc4(ide_hwif_t * hwif) { hwif->mmio = 1; - hwif->autodma = 1; hwif->atapi_dma = 1; - hwif->ultra_mask = 0x0; /* Disable Ultra DMA */ - hwif->mwdma_mask = 0x2; /* Multimode-2 DMA */ - hwif->swdma_mask = 0x2; + hwif->mwdma_mask = 0x04; hwif->pio_mask = 0x00; hwif->set_pio_mode = NULL; /* Sets timing for PIO mode */ - hwif->speedproc = NULL; /* Sets timing for DMA &/or PIO modes */ + hwif->speedproc = &sgiioc4_speedproc; hwif->selectproc = NULL;/* Use the default routine to select drive */ hwif->reset_poll = NULL;/* No HBA specific reset_poll needed */ hwif->pre_reset = NULL; /* No HBA specific pre_set needed */ @@ -615,7 +622,7 @@ ide_init_sgiioc4(ide_hwif_t * hwif) } static int __devinit -sgiioc4_ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t * d) +sgiioc4_ide_setup_pci_device(struct pci_dev *dev) { unsigned long cmd_base, dma_base, irqport; unsigned long bar0, cmd_phys_base, ctl; @@ -632,7 +639,8 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t * d) break; } if (h == MAX_HWIFS) { - printk(KERN_ERR "%s: too many IDE interfaces, no room in table\n", d->name); + printk(KERN_ERR "%s: too many IDE interfaces, no room in table\n", + DRV_NAME); return -ENOMEM; } @@ -641,7 +649,7 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t * d) virt_base = ioremap(bar0, pci_resource_len(dev, 0)); if (virt_base == NULL) { printk(KERN_ERR "%s: Unable to remap BAR 0 address: 0x%lx\n", - d->name, bar0); + DRV_NAME, bar0); return -ENOMEM; } cmd_base = (unsigned long) virt_base + IOC4_CMD_OFFSET; @@ -672,7 +680,6 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t * d) hwif->chipset = ide_pci; hwif->pci_dev = dev; hwif->channel = 0; /* Single Channel chip */ - hwif->cds = (struct ide_pci_device_s *) d; hwif->gendev.parent = &dev->dev;/* setup proper ancestral information */ /* The IOC4 uses MMIO rather than Port IO. */ @@ -683,11 +690,14 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t * d) ide_init_sgiioc4(hwif); - if (dma_base) - ide_dma_sgiioc4(hwif, dma_base); - else + hwif->autodma = 0; + + if (dma_base && ide_dma_sgiioc4(hwif, dma_base) == 0) { + hwif->autodma = 1; + hwif->drives[1].autodma = hwif->drives[0].autodma = 1; + } else printk(KERN_INFO "%s: %s Bus-Master DMA disabled\n", - hwif->name, d->name); + hwif->name, DRV_NAME); if (probe_hwif_init(hwif)) return -EIO; @@ -699,7 +709,7 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t * d) } static unsigned int __devinit -pci_init_sgiioc4(struct pci_dev *dev, ide_pci_device_t * d) +pci_init_sgiioc4(struct pci_dev *dev) { unsigned int class_rev; int ret; @@ -707,30 +717,20 @@ pci_init_sgiioc4(struct pci_dev *dev, ide_pci_device_t * d) pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); class_rev &= 0xff; printk(KERN_INFO "%s: IDE controller at PCI slot %s, revision %d\n", - d->name, pci_name(dev), class_rev); + DRV_NAME, pci_name(dev), class_rev); if (class_rev < IOC4_SUPPORTED_FIRMWARE_REV) { printk(KERN_ERR "Skipping %s IDE controller in slot %s: " - "firmware is obsolete - please upgrade to revision" - "46 or higher\n", d->name, pci_name(dev)); + "firmware is obsolete - please upgrade to " + "revision46 or higher\n", + DRV_NAME, pci_name(dev)); ret = -EAGAIN; goto out; } - ret = sgiioc4_ide_setup_pci_device(dev, d); + ret = sgiioc4_ide_setup_pci_device(dev); out: return ret; } -static ide_pci_device_t sgiioc4_chipset __devinitdata = { - /* Channel 0 */ - .name = "SGIIOC4", - .init_hwif = ide_init_sgiioc4, - .init_dma = ide_dma_sgiioc4, - .autodma = AUTODMA, - /* SGI IOC4 doesn't have enablebits. */ - .bootable = ON_BOARD, - .host_flags = IDE_HFLAG_SINGLE, -}; - int ioc4_ide_attach_one(struct ioc4_driver_data *idd) { @@ -740,7 +740,7 @@ ioc4_ide_attach_one(struct ioc4_driver_data *idd) if (idd->idd_variant == IOC4_VARIANT_PCI_RT) return 0; - return pci_init_sgiioc4(idd->idd_pdev, &sgiioc4_chipset); + return pci_init_sgiioc4(idd->idd_pdev); } static struct ioc4_submodule ioc4_ide_submodule = { -- cgit v1.2.3-70-g09d2 From f44ae58a273b1b051122784a159ad608b7205afd Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Thu, 11 Oct 2007 23:54:00 +0200 Subject: icside: fix ->speedproc to return on unsupported modes (take 5) * All other implementations of ->speedproc return zero on success and non-zero on failure. Currently it doesn't matter for icside host driver and isn't a bug per se since: - ide_set_xfer_rate() return value is ignored by all IDE core users - icside doesn't (yet!) use ide_tune_dma() in icside_dma_check() but sooner or later we will need to fix anyway - so lets do it now. * icside_set_speed() happily accepts unsupported transfer modes which results in drive->drive_data being set to the maximum value (480) and drive->current_speed being set to the unsupported transfer mode. Fix it. v2: * The initial version of the patch was broken because it didn't take into the account (the different from usual) return values of icside_set_speed() (Noticed by Russell). v3: * Remove no longer needed initialization/checking of cycle_time (Noticed by Sergei). * No need to set drive->drive_data if DMA is not going to be used (Noticed by Sergei). * Remove incorrect setting of drive->current_speed (Noticed by Sergei). * Move ide_config_drive_speed() at the end of icside_set_speed(). v4: * If DMA mode is not found in icside_dma_check() then just return "-1" and don't call icside_set_speed() (v3 got it wrong and "1" was returned instead). v5: * Return "-1"/"0" in icside_set_speed() instead of icside_dma_check() return value (just like it was before this patch). Cc: Russell King Cc: Sergei Shtylyov Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/arm/icside.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/ide/arm/icside.c b/drivers/ide/arm/icside.c index 99a27f2dc03..7912a471f10 100644 --- a/drivers/ide/arm/icside.c +++ b/drivers/ide/arm/icside.c @@ -250,7 +250,7 @@ static void icside_build_sglist(ide_drive_t *drive, struct request *rq) */ static int icside_set_speed(ide_drive_t *drive, const u8 xfer_mode) { - int on = 0, cycle_time = 0, use_dma_info = 0; + int cycle_time, use_dma_info = 0; switch (xfer_mode) { case XFER_MW_DMA_2: @@ -272,6 +272,8 @@ static int icside_set_speed(ide_drive_t *drive, const u8 xfer_mode) case XFER_SW_DMA_0: cycle_time = 480; break; + default: + return 1; } /* @@ -283,17 +285,10 @@ static int icside_set_speed(ide_drive_t *drive, const u8 xfer_mode) drive->drive_data = cycle_time; - if (cycle_time && ide_config_drive_speed(drive, xfer_mode) == 0) - on = 1; - else - drive->drive_data = 480; - printk("%s: %s selected (peak %dMB/s)\n", drive->name, ide_xfer_verbose(xfer_mode), 2000 / drive->drive_data); - drive->current_speed = xfer_mode; - - return on; + return ide_config_drive_speed(drive, xfer_mode); } static void icside_dma_host_off(ide_drive_t *drive) @@ -320,8 +315,7 @@ static int icside_dma_check(ide_drive_t *drive) { struct hd_driveid *id = drive->id; ide_hwif_t *hwif = HWIF(drive); - int xfer_mode = XFER_PIO_2; - int on; + int xfer_mode = 0; if (!(id->capability & 1) || !hwif->autodma) goto out; @@ -350,9 +344,10 @@ static int icside_dma_check(ide_drive_t *drive) } out: - on = icside_set_speed(drive, xfer_mode); + if (xfer_mode == 0) + return -1; - return on ? 0 : -1; + return icside_set_speed(drive, xfer_mode) ? -1 : 0; } static int icside_dma_end(ide_drive_t *drive) -- cgit v1.2.3-70-g09d2 From c15d5d43e6eed180e275f1db296eab5560a1bf59 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Thu, 11 Oct 2007 23:54:01 +0200 Subject: ide-pmac: PIO mode setup fixes (take 3) * Add { 0, 0 } entry to {kauai,shasta}_pio_timings[] so kauai_lookup_timing() always returns a valid PIO timing (fixes PIO timing not being set for devices with minimum PIO cycle <= 120ns). * Add setting transfer mode on the device to pmac_ide_set_pio_mode(). * Fix pmac_ide_set_pio() to always program chipset for given PIO timing instead of only when the device we want to program PIO timing for is the currently selected one. * Now that pmac_ide_set_pio() is fixed there is no need to set transfer mode on the device and program chipset for PIO in pmac_ide_tune_chipset() (returning 0 == success is not entirely correct but is OK for now since the upper layers are only checking ->speedproc return value for DMA modes). v2: * s/speed/XFER_PIO_0 + pio/ in pmac_ide_set_pio_mode() so it actually compiles. * Removal of kauai_lookup_timing() return value checking went to separate patch. v3: * Use XFER_PIO_0 not XFER_PIO. (Noticed by Ben) Cc: Benjamin Herrenschmidt Cc: Sergei Shtylyov Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/ppc/pmac.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c index beafdf3c112..4da251882cc 100644 --- a/drivers/ide/ppc/pmac.c +++ b/drivers/ide/ppc/pmac.c @@ -6,6 +6,7 @@ * for doing DMA. * * Copyright (C) 1998-2003 Paul Mackerras & Ben. Herrenschmidt + * Copyright (C) 2007 Bartlomiej Zolnierkiewicz * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -311,7 +312,8 @@ static struct kauai_timing kauai_pio_timings[] = { 240 , 0x0800038b }, { 239 , 0x0800030c }, { 180 , 0x05000249 }, - { 120 , 0x04000148 } + { 120 , 0x04000148 }, + { 0 , 0 }, }; static struct kauai_timing kauai_mdma_timings[] = @@ -351,7 +353,8 @@ static struct kauai_timing shasta_pio_timings[] = { 240 , 0x040003cd }, { 239 , 0x040003cd }, { 180 , 0x0400028b }, - { 120 , 0x0400010a } + { 120 , 0x0400010a }, + { 0 , 0 }, }; static struct kauai_timing shasta_mdma_timings[] = @@ -695,8 +698,10 @@ pmac_ide_set_pio_mode(ide_drive_t *drive, const u8 pio) drive->name, pio, *timings); #endif - if (drive->select.all == HWIF(drive)->INB(IDE_SELECT_REG)) - pmac_ide_do_update_timings(drive); + if (pmac_ide_do_setfeature(drive, XFER_PIO_0 + pio)) + return; + + pmac_ide_do_update_timings(drive); } #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC @@ -965,7 +970,7 @@ static int pmac_ide_tune_chipset(ide_drive_t *drive, const u8 speed) case XFER_PIO_1: case XFER_PIO_0: pmac_ide_set_pio_mode(drive, speed & 0x07); - break; + return 0; default: ret = 1; } -- cgit v1.2.3-70-g09d2 From fabe1510568acd5194f630dbbcf77a34610d7e9e Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Thu, 11 Oct 2007 23:54:01 +0200 Subject: sc1200: remove redundant warning message from sc1200_tune_chipset() ide_config_drive_speed() called by sc1200_set_xfer_mode() already gives a meaningful warning message in case of failure. Acked-by: Sergei Shtylyov Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/sc1200.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/ide/pci/sc1200.c b/drivers/ide/pci/sc1200.c index f9f5ed90657..d46627eced9 100644 --- a/drivers/ide/pci/sc1200.c +++ b/drivers/ide/pci/sc1200.c @@ -149,10 +149,8 @@ static int sc1200_tune_chipset(ide_drive_t *drive, const u8 mode) /* * Tell the drive to switch to the new mode; abort on failure. */ - if (sc1200_set_xfer_mode(drive, mode)) { - printk("SC1200: set xfer mode failure\n"); + if (sc1200_set_xfer_mode(drive, mode)) return 1; /* failure */ - } switch (mode) { case XFER_PIO_4: -- cgit v1.2.3-70-g09d2 From 326d72f437b0a9216290ad8f10817e1e363fd813 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Thu, 11 Oct 2007 23:54:01 +0200 Subject: cs5520: don't enable VDMA in ->speedproc There is no need to do it in cs5520_tune_chipset() (->speedproc method) since it is correctly handled by cs5520_dma_on() (->ide_dma_on method). Acked-by: Sergei Shtylyov Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/cs5520.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/ide/pci/cs5520.c b/drivers/ide/pci/cs5520.c index a73c318ff08..e6af534a719 100644 --- a/drivers/ide/pci/cs5520.c +++ b/drivers/ide/pci/cs5520.c @@ -73,7 +73,6 @@ static int cs5520_tune_chipset(ide_drive_t *drive, const u8 speed) int pio = speed; u8 reg; int controller = drive->dn > 1 ? 1 : 0; - int error; switch(speed) { @@ -114,14 +113,9 @@ static int cs5520_tune_chipset(ide_drive_t *drive, const u8 speed) reg = inb(hwif->dma_base + 0x02 + 8*controller); reg |= 1<<((drive->dn&1)+5); outb(reg, hwif->dma_base + 0x02 + 8*controller); - - error = ide_config_drive_speed(drive, speed); - /* ATAPI is harder so leave it for now */ - if(!error && drive->media == ide_disk) - error = hwif->ide_dma_on(drive); - return error; -} + return ide_config_drive_speed(drive, speed); +} static void cs5520_set_pio_mode(ide_drive_t *drive, const u8 pio) { @@ -177,7 +171,8 @@ static void __devinit init_hwif_cs5520(ide_hwif_t *hwif) hwif->drives[1].autotune = 1; return; } - + + /* ATAPI is harder so leave it for now */ hwif->atapi_dma = 0; hwif->ultra_mask = 0; hwif->swdma_mask = 0; -- cgit v1.2.3-70-g09d2 From ffe5415c3d6138aff412af7e455b3df4d53c0aa0 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Thu, 11 Oct 2007 23:54:01 +0200 Subject: siimage: fix ->set_pio_mode method to select PIO data transfer * Remember to select PIO data transfer (with IORDY monitored) in sil_tune_pio() (->set_pio_mode method) so the controller is always programmed correctly for PIO transfers (this is important if DMA is not going to be used). * Don't set DMA/UDMA timings for PIO modes in siimage_tune_chipset(). * Bump driver version. Acked-by: Sergei Shtylyov Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/siimage.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c index e07c991d91b..c526c70d65a 100644 --- a/drivers/ide/pci/siimage.c +++ b/drivers/ide/pci/siimage.c @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/pci/siimage.c Version 1.15 Jun 29 2007 + * linux/drivers/ide/pci/siimage.c Version 1.16 Jul 13 2007 * * Copyright (C) 2001-2002 Andre Hedrick * Copyright (C) 2003 Red Hat @@ -185,7 +185,12 @@ static void sil_tune_pio(ide_drive_t *drive, u8 pio) u16 speedp = 0; unsigned long addr = siimage_seldev(drive, 0x04); unsigned long tfaddr = siimage_selreg(hwif, 0x02); + unsigned long base = (unsigned long)hwif->hwif_data; u8 tf_pio = pio; + u8 addr_mask = hwif->channel ? (hwif->mmio ? 0xF4 : 0x84) + : (hwif->mmio ? 0xB4 : 0x80); + u8 mode = 0; + u8 unit = drive->select.b.unit; /* trim *taskfile* PIO to the slowest of the master/slave */ if (pair->present) { @@ -207,6 +212,11 @@ static void sil_tune_pio(ide_drive_t *drive, u8 pio) hwif->OUTW(hwif->INW(tfaddr-2)|0x200, tfaddr-2); else hwif->OUTW(hwif->INW(tfaddr-2)&~0x200, tfaddr-2); + + mode = hwif->INB(base + addr_mask); + mode &= ~(unit ? 0x30 : 0x03); + mode |= (unit ? 0x10 : 0x01); + hwif->OUTB(mode, base + addr_mask); } else { pci_write_config_word(hwif->pci_dev, addr, speedp); pci_write_config_word(hwif->pci_dev, tfaddr, speedt); @@ -216,6 +226,11 @@ static void sil_tune_pio(ide_drive_t *drive, u8 pio) if (pio > 2) speedp |= 0x200; pci_write_config_word(hwif->pci_dev, tfaddr-2, speedp); + + pci_read_config_byte(hwif->pci_dev, addr_mask, &mode); + mode &= ~(unit ? 0x30 : 0x03); + mode |= (unit ? 0x10 : 0x01); + pci_write_config_byte(hwif->pci_dev, addr_mask, mode); } } @@ -275,8 +290,7 @@ static int siimage_tune_chipset(ide_drive_t *drive, const u8 speed) case XFER_PIO_1: case XFER_PIO_0: sil_tune_pio(drive, speed - XFER_PIO_0); - mode |= ((unit) ? 0x10 : 0x01); - break; + return ide_config_drive_speed(drive, speed); case XFER_MW_DMA_2: case XFER_MW_DMA_1: case XFER_MW_DMA_0: -- cgit v1.2.3-70-g09d2 From a6fe837ed63aa812bea029a24b7aafc72ba8de88 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Thu, 11 Oct 2007 23:54:01 +0200 Subject: alim15x3: PIO mode setup fixes * Return failure in ->speedproc method for unsupported/invalid transfer modes passed from user-space (fixes theoretical OOPS in ali_tune_pio() and/or setting random PIO timings on host controller + disabling UDMA bit + setting unsupported/invalid transfer mode on the device). * Don't disable UDMA bit when programming PIO modes. * Add FIXME about DMA timings never being set. * Bump driver version. Acked-by: Sergei Shtylyov Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/alim15x3.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c index 005402ab748..f15c8879d2c 100644 --- a/drivers/ide/pci/alim15x3.c +++ b/drivers/ide/pci/alim15x3.c @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/pci/alim15x3.c Version 0.25 Jun 9 2007 + * linux/drivers/ide/pci/alim15x3.c Version 0.26 Jul 14 2007 * * Copyright (C) 1998-2000 Michel Aubry, Maintainer * Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer @@ -418,6 +418,14 @@ static int ali15x3_tune_chipset(ide_drive_t *drive, const u8 speed) u8 tmpbyte = 0x00; int m5229_udma = (hwif->channel) ? 0x57 : 0x56; + if (speed < XFER_PIO_0) + return 1; + + if (speed >= XFER_PIO_0 && speed <= XFER_PIO_5) { + ali_tune_pio(drive, speed - XFER_PIO_0); + return ide_config_drive_speed(drive, speed); + } + if (speed == XFER_UDMA_6) speed1 = 0x47; @@ -430,8 +438,9 @@ static int ali15x3_tune_chipset(ide_drive_t *drive, const u8 speed) tmpbyte &= ultra_enable; pci_write_config_byte(dev, m5229_udma, tmpbyte); - if (speed < XFER_SW_DMA_0) - ali_tune_pio(drive, speed - XFER_PIO_0); + /* + * FIXME: Oh, my... DMA timings are never set. + */ } else { pci_read_config_byte(dev, m5229_udma, &tmpbyte); tmpbyte &= (0x0f << ((1-unit) << 2)); -- cgit v1.2.3-70-g09d2 From 90986028c98be10807bb6f48e883f33fa20e5499 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Thu, 11 Oct 2007 23:54:01 +0200 Subject: it8213/piix/slc90e66: don't change DMA settings when programming PIO Acked-by: Sergei Shtylyov Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/it8213.c | 16 ++++++---------- drivers/ide/pci/piix.c | 17 +++++++---------- drivers/ide/pci/slc90e66.c | 17 +++++++---------- 3 files changed, 20 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/ide/pci/it8213.c b/drivers/ide/pci/it8213.c index d07771e06b2..24ef091ec5b 100644 --- a/drivers/ide/pci/it8213.c +++ b/drivers/ide/pci/it8213.c @@ -132,6 +132,11 @@ static int it8213_tune_chipset(ide_drive_t *drive, const u8 speed) u16 reg4042, reg4a; u8 reg48, reg54, reg55; + if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) { + it8213_tune_pio(drive, speed - XFER_PIO_0); + return ide_config_drive_speed(drive, speed); + } + pci_read_config_word(dev, maslave, ®4042); pci_read_config_byte(dev, 0x48, ®48); pci_read_config_word(dev, 0x4a, ®4a); @@ -151,12 +156,6 @@ static int it8213_tune_chipset(ide_drive_t *drive, const u8 speed) case XFER_MW_DMA_1: case XFER_SW_DMA_2: break; - case XFER_PIO_4: - case XFER_PIO_3: - case XFER_PIO_2: - case XFER_PIO_1: - case XFER_PIO_0: - break; default: return -1; } @@ -188,10 +187,7 @@ static int it8213_tune_chipset(ide_drive_t *drive, const u8 speed) pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); } - if (speed > XFER_PIO_4) - it8213_tune_pio(drive, it8213_dma_2_pio(speed)); - else - it8213_tune_pio(drive, speed - XFER_PIO_0); + it8213_tune_pio(drive, it8213_dma_2_pio(speed)); return ide_config_drive_speed(drive, speed); } diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c index 07492d71c60..860b929f6e5 100644 --- a/drivers/ide/pci/piix.c +++ b/drivers/ide/pci/piix.c @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/pci/piix.c Version 0.51 Jul 6, 2007 + * linux/drivers/ide/pci/piix.c Version 0.52 Jul 14, 2007 * * Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer * Copyright (C) 1998-2000 Andre Hedrick @@ -242,6 +242,11 @@ static int piix_tune_chipset(ide_drive_t *drive, const u8 speed) u16 reg4042, reg4a; u8 reg48, reg54, reg55; + if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) { + piix_tune_pio(drive, speed - XFER_PIO_0); + return ide_config_drive_speed(drive, speed); + } + pci_read_config_word(dev, maslave, ®4042); sitre = (reg4042 & 0x4000) ? 1 : 0; pci_read_config_byte(dev, 0x48, ®48); @@ -259,11 +264,6 @@ static int piix_tune_chipset(ide_drive_t *drive, const u8 speed) case XFER_MW_DMA_2: case XFER_MW_DMA_1: case XFER_SW_DMA_2: break; - case XFER_PIO_4: - case XFER_PIO_3: - case XFER_PIO_2: - case XFER_PIO_1: - case XFER_PIO_0: break; default: return -1; } @@ -293,10 +293,7 @@ static int piix_tune_chipset(ide_drive_t *drive, const u8 speed) pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); } - if (speed > XFER_PIO_4) - piix_tune_pio(drive, piix_dma_2_pio(speed)); - else - piix_tune_pio(drive, speed - XFER_PIO_0); + piix_tune_pio(drive, piix_dma_2_pio(speed)); return ide_config_drive_speed(drive, speed); } diff --git a/drivers/ide/pci/slc90e66.c b/drivers/ide/pci/slc90e66.c index 214d396fc31..967b939e9d2 100644 --- a/drivers/ide/pci/slc90e66.c +++ b/drivers/ide/pci/slc90e66.c @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/pci/slc90e66.c Version 0.15 Jul 6, 2007 + * linux/drivers/ide/pci/slc90e66.c Version 0.16 Jul 14, 2007 * * Copyright (C) 2000-2002 Andre Hedrick * Copyright (C) 2006-2007 MontaVista Software, Inc. @@ -110,6 +110,11 @@ static int slc90e66_tune_chipset(ide_drive_t *drive, const u8 speed) int u_speed = 0, u_flag = 1 << drive->dn; u16 reg4042, reg44, reg48, reg4a; + if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) { + slc90e66_tune_pio(drive, speed - XFER_PIO_0); + return ide_config_drive_speed(drive, speed); + } + pci_read_config_word(dev, maslave, ®4042); sitre = (reg4042 & 0x4000) ? 1 : 0; pci_read_config_word(dev, 0x44, ®44); @@ -125,11 +130,6 @@ static int slc90e66_tune_chipset(ide_drive_t *drive, const u8 speed) case XFER_MW_DMA_2: case XFER_MW_DMA_1: case XFER_SW_DMA_2: break; - case XFER_PIO_4: - case XFER_PIO_3: - case XFER_PIO_2: - case XFER_PIO_1: - case XFER_PIO_0: break; default: return -1; } @@ -149,10 +149,7 @@ static int slc90e66_tune_chipset(ide_drive_t *drive, const u8 speed) pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); } - if (speed > XFER_PIO_4) - slc90e66_tune_pio(drive, slc90e66_dma_2_pio(speed)); - else - slc90e66_tune_pio(drive, speed - XFER_PIO_0); + slc90e66_tune_pio(drive, slc90e66_dma_2_pio(speed)); return ide_config_drive_speed(drive, speed); } -- cgit v1.2.3-70-g09d2 From 0d3be723cb6432e384267d0fe83ee0bae5e17846 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Thu, 11 Oct 2007 23:54:01 +0200 Subject: sis5513: don't change UDMA settings when programming PIO Acked-by: Sergei Shtylyov Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/sis5513.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c index 7455bf357ed..3a8cb1468a7 100644 --- a/drivers/ide/pci/sis5513.c +++ b/drivers/ide/pci/sis5513.c @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/pci/sis5513.c Version 0.26 Jul 7, 2007 + * linux/drivers/ide/pci/sis5513.c Version 0.27 Jul 14, 2007 * * Copyright (C) 1999-2000 Andre Hedrick * Copyright (C) 2002 Lionel Bouton , Maintainer @@ -537,6 +537,9 @@ static int sis5513_tune_chipset(ide_drive_t *drive, const u8 speed) u32 regdw; u8 drive_pci, reg; + if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) + return sis5513_tune_drive(drive, speed - XFER_PIO_0); + /* See config_art_rwp_pio for drive pci config registers */ drive_pci = 0x40; if (chipset_family >= ATA_133) { @@ -601,12 +604,6 @@ static int sis5513_tune_chipset(ide_drive_t *drive, const u8 speed) case XFER_SW_DMA_1: case XFER_SW_DMA_0: break; - case XFER_PIO_4: - case XFER_PIO_3: - case XFER_PIO_2: - case XFER_PIO_1: - case XFER_PIO_0: - return sis5513_tune_drive(drive, speed - XFER_PIO_0); default: BUG(); break; -- cgit v1.2.3-70-g09d2 From 8f4dd2e42637fd61a6366d2cace69091926eaa15 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Thu, 11 Oct 2007 23:54:02 +0200 Subject: ide: use only ->set_pio_mode method for programming PIO modes (take 2) Use ->set_pio_mode method to program PIO modes in ide_set_xfer_rate() (the only place which used ->speedproc to program PIO modes) and remove handling of PIO modes from all ->speedproc implementations. v2: * Fix pmac_ide_tune_chipset() comment. There should be no functionality changes caused by this patch. Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/cris/ide-cris.c | 5 ----- drivers/ide/ide-lib.c | 12 ++++++++++++ drivers/ide/mips/au1xxx-ide.c | 5 ----- drivers/ide/pci/alim15x3.c | 5 ----- drivers/ide/pci/atiixp.c | 5 ----- drivers/ide/pci/cmd64x.c | 8 -------- drivers/ide/pci/cs5520.c | 36 ++++++++++++++---------------------- drivers/ide/pci/cs5530.c | 7 ------- drivers/ide/pci/it8213.c | 5 ----- drivers/ide/pci/it821x.c | 9 --------- drivers/ide/pci/piix.c | 5 ----- drivers/ide/pci/sc1200.c | 10 ---------- drivers/ide/pci/scc_pata.c | 7 ------- drivers/ide/pci/serverworks.c | 5 ----- drivers/ide/pci/siimage.c | 7 ------- drivers/ide/pci/sis5513.c | 12 ++---------- drivers/ide/pci/sl82c105.c | 8 -------- drivers/ide/pci/slc90e66.c | 5 ----- drivers/ide/ppc/pmac.c | 9 +-------- 19 files changed, 29 insertions(+), 136 deletions(-) (limited to 'drivers') diff --git a/drivers/ide/cris/ide-cris.c b/drivers/ide/cris/ide-cris.c index 7c90218e931..4bb42b30bfc 100644 --- a/drivers/ide/cris/ide-cris.c +++ b/drivers/ide/cris/ide-cris.c @@ -724,11 +724,6 @@ static int speed_cris_ide(ide_drive_t *drive, const u8 speed) { int cyc = 0, dvs = 0, strobe = 0, hold = 0; - if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) { - cris_set_pio_mode(drive, speed - XFER_PIO_0); - return ide_config_drive_speed(drive, speed); - } - switch(speed) { case XFER_UDMA_0: diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c index 8400b1b4aa1..d97390c0543 100644 --- a/drivers/ide/ide-lib.c +++ b/drivers/ide/ide-lib.c @@ -398,6 +398,18 @@ int ide_set_xfer_rate(ide_drive_t *drive, u8 rate) rate = ide_rate_filter(drive, rate); + if (rate >= XFER_PIO_0 && rate <= XFER_PIO_5) { + if (hwif->set_pio_mode) + hwif->set_pio_mode(drive, rate - XFER_PIO_0); + + /* + * FIXME: this is incorrect to return zero here but + * since all users of ide_set_xfer_rate() ignore + * the return value it is not a problem currently + */ + return 0; + } + return hwif->speedproc(drive, rate); } diff --git a/drivers/ide/mips/au1xxx-ide.c b/drivers/ide/mips/au1xxx-ide.c index 670cb748481..85819ae2060 100644 --- a/drivers/ide/mips/au1xxx-ide.c +++ b/drivers/ide/mips/au1xxx-ide.c @@ -177,11 +177,6 @@ static int auide_tune_chipset(ide_drive_t *drive, const u8 speed) mem_sttime = 0; mem_stcfg = au_readl(MEM_STCFG2); - if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) { - au1xxx_set_pio_mode(drive, speed - XFER_PIO_0); - return 0; - } - switch(speed) { #ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA case XFER_MW_DMA_2: diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c index f15c8879d2c..80013d2bb03 100644 --- a/drivers/ide/pci/alim15x3.c +++ b/drivers/ide/pci/alim15x3.c @@ -421,11 +421,6 @@ static int ali15x3_tune_chipset(ide_drive_t *drive, const u8 speed) if (speed < XFER_PIO_0) return 1; - if (speed >= XFER_PIO_0 && speed <= XFER_PIO_5) { - ali_tune_pio(drive, speed - XFER_PIO_0); - return ide_config_drive_speed(drive, speed); - } - if (speed == XFER_UDMA_6) speed1 = 0x47; diff --git a/drivers/ide/pci/atiixp.c b/drivers/ide/pci/atiixp.c index b9f66f53f9a..178876a3afc 100644 --- a/drivers/ide/pci/atiixp.c +++ b/drivers/ide/pci/atiixp.c @@ -178,11 +178,6 @@ static int atiixp_speedproc(ide_drive_t *drive, const u8 speed) u16 tmp16; u8 pio; - if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) { - atiixp_tune_pio(drive, speed - XFER_PIO_0); - return ide_config_drive_speed(drive, speed); - } - spin_lock_irqsave(&atiixp_lock, flags); save_mdma_mode[drive->dn] = 0; diff --git a/drivers/ide/pci/cmd64x.c b/drivers/ide/pci/cmd64x.c index 85f5e42eb83..0b568c60f92 100644 --- a/drivers/ide/pci/cmd64x.c +++ b/drivers/ide/pci/cmd64x.c @@ -323,14 +323,6 @@ static int cmd64x_tune_chipset(ide_drive_t *drive, const u8 speed) case XFER_MW_DMA_0: program_cycle_times(drive, 480, 215); break; - case XFER_PIO_5: - case XFER_PIO_4: - case XFER_PIO_3: - case XFER_PIO_2: - case XFER_PIO_1: - case XFER_PIO_0: - cmd64x_tune_pio(drive, speed - XFER_PIO_0); - break; default: return 1; } diff --git a/drivers/ide/pci/cs5520.c b/drivers/ide/pci/cs5520.c index e6af534a719..1217d2a747f 100644 --- a/drivers/ide/pci/cs5520.c +++ b/drivers/ide/pci/cs5520.c @@ -66,30 +66,13 @@ static struct pio_clocks cs5520_pio_clocks[]={ {1, 2, 1} }; -static int cs5520_tune_chipset(ide_drive_t *drive, const u8 speed) +static void cs5520_set_pio_mode(ide_drive_t *drive, const u8 pio) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *pdev = hwif->pci_dev; - int pio = speed; - u8 reg; int controller = drive->dn > 1 ? 1 : 0; + u8 reg; - switch(speed) - { - case XFER_PIO_4: - case XFER_PIO_3: - case XFER_PIO_2: - case XFER_PIO_1: - case XFER_PIO_0: - pio -= XFER_PIO_0; - break; - default: - pio = 0; - printk(KERN_ERR "cs55x0: bad ide timing.\n"); - } - - printk("PIO clocking = %d\n", pio); - /* FIXME: if DMA = 1 do we need to set the DMA bit here ? */ /* 8bit CAT/CRT - 8bit command timing for channel */ @@ -114,12 +97,21 @@ static int cs5520_tune_chipset(ide_drive_t *drive, const u8 speed) reg |= 1<<((drive->dn&1)+5); outb(reg, hwif->dma_base + 0x02 + 8*controller); - return ide_config_drive_speed(drive, speed); + (void)ide_config_drive_speed(drive, XFER_PIO_0 + pio); } -static void cs5520_set_pio_mode(ide_drive_t *drive, const u8 pio) +static int cs5520_tune_chipset(ide_drive_t *drive, const u8 speed) { - cs5520_tune_chipset(drive, XFER_PIO_0 + pio); + printk(KERN_ERR "cs55x0: bad ide timing.\n"); + + cs5520_set_pio_mode(drive, 0); + + /* + * FIXME: this is incorrect to return zero here but + * since all users of ide_set_xfer_rate() ignore + * the return value it is not a problem currently + */ + return 0; } static int cs5520_config_drive_xfer_rate(ide_drive_t *drive) diff --git a/drivers/ide/pci/cs5530.c b/drivers/ide/pci/cs5530.c index 1588a323c5d..741507b4cd9 100644 --- a/drivers/ide/pci/cs5530.c +++ b/drivers/ide/pci/cs5530.c @@ -163,13 +163,6 @@ static int cs5530_tune_chipset(ide_drive_t *drive, const u8 mode) case XFER_MW_DMA_0: timings = 0x00077771; break; case XFER_MW_DMA_1: timings = 0x00012121; break; case XFER_MW_DMA_2: timings = 0x00002020; break; - case XFER_PIO_4: - case XFER_PIO_3: - case XFER_PIO_2: - case XFER_PIO_1: - case XFER_PIO_0: - cs5530_tunepio(drive, mode - XFER_PIO_0); - return 0; default: BUG(); break; diff --git a/drivers/ide/pci/it8213.c b/drivers/ide/pci/it8213.c index 24ef091ec5b..76e91ff9420 100644 --- a/drivers/ide/pci/it8213.c +++ b/drivers/ide/pci/it8213.c @@ -132,11 +132,6 @@ static int it8213_tune_chipset(ide_drive_t *drive, const u8 speed) u16 reg4042, reg4a; u8 reg48, reg54, reg55; - if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) { - it8213_tune_pio(drive, speed - XFER_PIO_0); - return ide_config_drive_speed(drive, speed); - } - pci_read_config_word(dev, maslave, ®4042); pci_read_config_byte(dev, 0x48, ®48); pci_read_config_word(dev, 0x4a, ®4a); diff --git a/drivers/ide/pci/it821x.c b/drivers/ide/pci/it821x.c index 0cce4a7f5e4..758a98230cc 100644 --- a/drivers/ide/pci/it821x.c +++ b/drivers/ide/pci/it821x.c @@ -418,15 +418,6 @@ static int it821x_tune_chipset(ide_drive_t *drive, const u8 speed) ide_hwif_t *hwif = drive->hwif; struct it821x_dev *itdev = ide_get_hwifdata(hwif); - switch (speed) { - case XFER_PIO_4: - case XFER_PIO_3: - case XFER_PIO_2: - case XFER_PIO_1: - case XFER_PIO_0: - return it821x_tunepio(drive, speed - XFER_PIO_0); - } - if (itdev->smart == 0) { switch (speed) { /* MWDMA tuning is really hard because our MWDMA and PIO diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c index 860b929f6e5..fd8214a7ab9 100644 --- a/drivers/ide/pci/piix.c +++ b/drivers/ide/pci/piix.c @@ -242,11 +242,6 @@ static int piix_tune_chipset(ide_drive_t *drive, const u8 speed) u16 reg4042, reg4a; u8 reg48, reg54, reg55; - if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) { - piix_tune_pio(drive, speed - XFER_PIO_0); - return ide_config_drive_speed(drive, speed); - } - pci_read_config_word(dev, maslave, ®4042); sitre = (reg4042 & 0x4000) ? 1 : 0; pci_read_config_byte(dev, 0x48, ®48); diff --git a/drivers/ide/pci/sc1200.c b/drivers/ide/pci/sc1200.c index d46627eced9..79ecab68948 100644 --- a/drivers/ide/pci/sc1200.c +++ b/drivers/ide/pci/sc1200.c @@ -152,16 +152,6 @@ static int sc1200_tune_chipset(ide_drive_t *drive, const u8 mode) if (sc1200_set_xfer_mode(drive, mode)) return 1; /* failure */ - switch (mode) { - case XFER_PIO_4: - case XFER_PIO_3: - case XFER_PIO_2: - case XFER_PIO_1: - case XFER_PIO_0: - sc1200_tunepio(drive, mode - XFER_PIO_0); - return 0; - } - pci_clock = sc1200_get_pci_clock(); /* diff --git a/drivers/ide/pci/scc_pata.c b/drivers/ide/pci/scc_pata.c index 3505d57eda1..66a526e0ece 100644 --- a/drivers/ide/pci/scc_pata.c +++ b/drivers/ide/pci/scc_pata.c @@ -270,13 +270,6 @@ static int scc_tune_chipset(ide_drive_t *drive, const u8 speed) case XFER_UDMA_0: idx = speed - XFER_UDMA_0; break; - case XFER_PIO_4: - case XFER_PIO_3: - case XFER_PIO_2: - case XFER_PIO_1: - case XFER_PIO_0: - scc_tune_pio(drive, speed - XFER_PIO_0); - return ide_config_drive_speed(drive, speed); default: return 1; } diff --git a/drivers/ide/pci/serverworks.c b/drivers/ide/pci/serverworks.c index f4e08abf0fe..0351cf21042 100644 --- a/drivers/ide/pci/serverworks.c +++ b/drivers/ide/pci/serverworks.c @@ -157,11 +157,6 @@ static int svwks_tune_chipset(ide_drive_t *drive, const u8 speed) u8 ultra_enable = 0, ultra_timing = 0, dma_timing = 0; - if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) { - svwks_tune_pio(drive, speed - XFER_PIO_0); - return ide_config_drive_speed(drive, speed); - } - /* If we are about to put a disk into UDMA mode we screwed up. Our code assumes we never _ever_ do this on an OSB4 */ diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c index c526c70d65a..5d1e5e52a04 100644 --- a/drivers/ide/pci/siimage.c +++ b/drivers/ide/pci/siimage.c @@ -284,13 +284,6 @@ static int siimage_tune_chipset(ide_drive_t *drive, const u8 speed) scsc = is_sata(hwif) ? 1 : scsc; switch(speed) { - case XFER_PIO_4: - case XFER_PIO_3: - case XFER_PIO_2: - case XFER_PIO_1: - case XFER_PIO_0: - sil_tune_pio(drive, speed - XFER_PIO_0); - return ide_config_drive_speed(drive, speed); case XFER_MW_DMA_2: case XFER_MW_DMA_1: case XFER_MW_DMA_0: diff --git a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c index 3a8cb1468a7..3e18899de63 100644 --- a/drivers/ide/pci/sis5513.c +++ b/drivers/ide/pci/sis5513.c @@ -519,15 +519,10 @@ static void config_art_rwp_pio (ide_drive_t *drive, u8 pio) } } -static int sis5513_tune_drive(ide_drive_t *drive, const u8 pio) -{ - config_art_rwp_pio(drive, pio); - return ide_config_drive_speed(drive, XFER_PIO_0 + pio); -} - static void sis_set_pio_mode(ide_drive_t *drive, const u8 pio) { - (void)sis5513_tune_drive(drive, pio); + config_art_rwp_pio(drive, pio); + (void)ide_config_drive_speed(drive, XFER_PIO_0 + pio); } static int sis5513_tune_chipset(ide_drive_t *drive, const u8 speed) @@ -537,9 +532,6 @@ static int sis5513_tune_chipset(ide_drive_t *drive, const u8 speed) u32 regdw; u8 drive_pci, reg; - if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) - return sis5513_tune_drive(drive, speed - XFER_PIO_0); - /* See config_art_rwp_pio for drive pci config registers */ drive_pci = 0x40; if (chipset_family >= ATA_133) { diff --git a/drivers/ide/pci/sl82c105.c b/drivers/ide/pci/sl82c105.c index 131e91ca1d8..f492318ba79 100644 --- a/drivers/ide/pci/sl82c105.c +++ b/drivers/ide/pci/sl82c105.c @@ -139,14 +139,6 @@ static int sl82c105_tune_chipset(ide_drive_t *drive, const u8 speed) pci_write_config_word(dev, reg, drv_ctrl); } break; - case XFER_PIO_5: - case XFER_PIO_4: - case XFER_PIO_3: - case XFER_PIO_2: - case XFER_PIO_1: - case XFER_PIO_0: - sl82c105_tune_pio(drive, speed - XFER_PIO_0); - break; default: return -1; } diff --git a/drivers/ide/pci/slc90e66.c b/drivers/ide/pci/slc90e66.c index 967b939e9d2..ae8e9132457 100644 --- a/drivers/ide/pci/slc90e66.c +++ b/drivers/ide/pci/slc90e66.c @@ -110,11 +110,6 @@ static int slc90e66_tune_chipset(ide_drive_t *drive, const u8 speed) int u_speed = 0, u_flag = 1 << drive->dn; u16 reg4042, reg44, reg48, reg4a; - if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) { - slc90e66_tune_pio(drive, speed - XFER_PIO_0); - return ide_config_drive_speed(drive, speed); - } - pci_read_config_word(dev, maslave, ®4042); sitre = (reg4042 & 0x4000) ? 1 : 0; pci_read_config_word(dev, 0x44, ®44); diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c index 4da251882cc..f759a539786 100644 --- a/drivers/ide/ppc/pmac.c +++ b/drivers/ide/ppc/pmac.c @@ -917,7 +917,7 @@ set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2, /* * Speedproc. This function is called by the core to set any of the standard - * timing (PIO, MDMA or UDMA) to both the drive and the controller. + * DMA timing (MDMA or UDMA) to both the drive and the controller. * You may notice we don't use this function on normal "dma check" operation, * our dedicated function is more precise as it uses the drive provided * cycle time value. We should probably fix this one to deal with that too... @@ -964,13 +964,6 @@ static int pmac_ide_tune_chipset(ide_drive_t *drive, const u8 speed) case XFER_SW_DMA_0: return 1; #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ - case XFER_PIO_4: - case XFER_PIO_3: - case XFER_PIO_2: - case XFER_PIO_1: - case XFER_PIO_0: - pmac_ide_set_pio_mode(drive, speed & 0x07); - return 0; default: ret = 1; } -- cgit v1.2.3-70-g09d2 From 6f535763165331bb91277d7519b507fed22034e5 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 11 Oct 2007 18:08:29 -0700 Subject: [NET]: Fix NAPI completion handling in some drivers. In order for the list handling in net_rx_action() to be correct, drivers must follow certain rules as stated by this comment in net_rx_action(): /* Drivers must not modify the NAPI state if they * consume the entire weight. In such cases this code * still "owns" the NAPI instance and therefore can * move the instance around on the list at-will. */ A few drivers do not do this because they mix the budget checks with reading hardware state, resulting in crashes like the one reported by takano@axe-inc.co.jp. BNX2 and TG3 are taken care of here, SKY2 fix is from Stephen Hemminger. Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 52 +++++++++++++++++++++++++++++++-------------------- drivers/net/sky2.c | 17 +++++++++++++---- drivers/net/tg3.c | 55 ++++++++++++++++++++++++++++++++++++------------------ 3 files changed, 82 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index bbfbdafb4ae..d68accea380 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -2633,15 +2633,11 @@ bnx2_has_work(struct bnx2 *bp) return 0; } -static int -bnx2_poll(struct napi_struct *napi, int budget) +static int bnx2_poll_work(struct bnx2 *bp, int work_done, int budget) { - struct bnx2 *bp = container_of(napi, struct bnx2, napi); - struct net_device *dev = bp->dev; struct status_block *sblk = bp->status_blk; u32 status_attn_bits = sblk->status_attn_bits; u32 status_attn_bits_ack = sblk->status_attn_bits_ack; - int work_done = 0; if ((status_attn_bits & STATUS_ATTN_EVENTS) != (status_attn_bits_ack & STATUS_ATTN_EVENTS)) { @@ -2660,27 +2656,43 @@ bnx2_poll(struct napi_struct *napi, int budget) bnx2_tx_int(bp); if (bp->status_blk->status_rx_quick_consumer_index0 != bp->hw_rx_cons) - work_done = bnx2_rx_int(bp, budget); + work_done += bnx2_rx_int(bp, budget - work_done); - bp->last_status_idx = bp->status_blk->status_idx; - rmb(); + return work_done; +} + +static int bnx2_poll(struct napi_struct *napi, int budget) +{ + struct bnx2 *bp = container_of(napi, struct bnx2, napi); + int work_done = 0; + + while (1) { + work_done = bnx2_poll_work(bp, work_done, budget); - if (!bnx2_has_work(bp)) { - netif_rx_complete(dev, napi); - if (likely(bp->flags & USING_MSI_FLAG)) { + if (unlikely(work_done >= budget)) + break; + + if (likely(!bnx2_has_work(bp))) { + bp->last_status_idx = bp->status_blk->status_idx; + rmb(); + + netif_rx_complete(bp->dev, napi); + if (likely(bp->flags & USING_MSI_FLAG)) { + REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, + BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | + bp->last_status_idx); + return 0; + } REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | + BNX2_PCICFG_INT_ACK_CMD_MASK_INT | bp->last_status_idx); - return 0; - } - REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, - BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | - BNX2_PCICFG_INT_ACK_CMD_MASK_INT | - bp->last_status_idx); - REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, - BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | - bp->last_status_idx); + REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, + BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | + bp->last_status_idx); + break; + } } return work_done; diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index fe0e7560d23..4e569fa0f96 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -2606,7 +2606,7 @@ static int sky2_poll(struct napi_struct *napi, int work_limit) { struct sky2_hw *hw = container_of(napi, struct sky2_hw, napi); u32 status = sky2_read32(hw, B0_Y2_SP_EISR); - int work_done; + int work_done = 0; if (unlikely(status & Y2_IS_ERROR)) sky2_err_intr(hw, status); @@ -2617,10 +2617,16 @@ static int sky2_poll(struct napi_struct *napi, int work_limit) if (status & Y2_IS_IRQ_PHY2) sky2_phy_intr(hw, 1); - work_done = sky2_status_intr(hw, work_limit); + for(;;) { + work_done += sky2_status_intr(hw, work_limit); + + if (work_done >= work_limit) + break; + + /* More work? */ + if (hw->st_idx != sky2_read16(hw, STAT_PUT_IDX)) + continue; - /* More work? */ - if (hw->st_idx == sky2_read16(hw, STAT_PUT_IDX)) { /* Bug/Errata workaround? * Need to kick the TX irq moderation timer. */ @@ -2631,7 +2637,10 @@ static int sky2_poll(struct napi_struct *napi, int work_limit) napi_complete(napi); sky2_read32(hw, B0_Y2_SP_LISR); + break; + } + return work_done; } diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index d2b30fb0b31..a402b5c0189 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -3555,12 +3555,9 @@ next_pkt_nopost: return received; } -static int tg3_poll(struct napi_struct *napi, int budget) +static int tg3_poll_work(struct tg3 *tp, int work_done, int budget) { - struct tg3 *tp = container_of(napi, struct tg3, napi); - struct net_device *netdev = tp->dev; struct tg3_hw_status *sblk = tp->hw_status; - int work_done = 0; /* handle link change and other phy events */ if (!(tp->tg3_flags & @@ -3578,11 +3575,8 @@ static int tg3_poll(struct napi_struct *napi, int budget) /* run TX completion thread */ if (sblk->idx[0].tx_consumer != tp->tx_cons) { tg3_tx(tp); - if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING)) { - netif_rx_complete(netdev, napi); - schedule_work(&tp->reset_task); + if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING)) return 0; - } } /* run RX thread, within the bounds set by NAPI. @@ -3590,21 +3584,46 @@ static int tg3_poll(struct napi_struct *napi, int budget) * code synchronizes with tg3->napi.poll() */ if (sblk->idx[0].rx_producer != tp->rx_rcb_ptr) - work_done = tg3_rx(tp, budget); + work_done += tg3_rx(tp, budget - work_done); - if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) { - tp->last_tag = sblk->status_tag; - rmb(); - } else - sblk->status &= ~SD_STATUS_UPDATED; + return work_done; +} - /* if no more work, tell net stack and NIC we're done */ - if (!tg3_has_work(tp)) { - netif_rx_complete(netdev, napi); - tg3_restart_ints(tp); +static int tg3_poll(struct napi_struct *napi, int budget) +{ + struct tg3 *tp = container_of(napi, struct tg3, napi); + int work_done = 0; + + while (1) { + work_done = tg3_poll_work(tp, work_done, budget); + + if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING)) + goto tx_recovery; + + if (unlikely(work_done >= budget)) + break; + + if (likely(!tg3_has_work(tp))) { + struct tg3_hw_status *sblk = tp->hw_status; + + if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) { + tp->last_tag = sblk->status_tag; + rmb(); + } else + sblk->status &= ~SD_STATUS_UPDATED; + + netif_rx_complete(tp->dev, napi); + tg3_restart_ints(tp); + break; + } } return work_done; + +tx_recovery: + netif_rx_complete(tp->dev, napi); + schedule_work(&tp->reset_task); + return 0; } static void tg3_irq_quiesce(struct tg3 *tp) -- cgit v1.2.3-70-g09d2 From 266918303226cceac7eca38ced30f15f277bd89c Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 11 Oct 2007 18:31:13 -0700 Subject: [SKY2]: status polling loop (post merge) Handle the corner case where budget is exhausted correctly. And save unnecessary read of index register. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 41 +++++++++++++++++------------------------ 1 file changed, 17 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 4e569fa0f96..0a320346541 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -2245,15 +2245,13 @@ static inline void sky2_tx_done(struct net_device *dev, u16 last) } /* Process status response ring */ -static int sky2_status_intr(struct sky2_hw *hw, int to_do) +static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx) { int work_done = 0; unsigned rx[2] = { 0, 0 }; - u16 hwidx = sky2_read16(hw, STAT_PUT_IDX); rmb(); - - while (hw->st_idx != hwidx) { + do { struct sky2_port *sky2; struct sky2_status_le *le = hw->st_le + hw->st_idx; unsigned port = le->css & CSS_LINK_BIT; @@ -2364,7 +2362,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do) printk(KERN_WARNING PFX "unknown status opcode 0x%x\n", le->opcode); } - } + } while (hw->st_idx != idx); /* Fully processed status ring so clear irq */ sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ); @@ -2607,6 +2605,7 @@ static int sky2_poll(struct napi_struct *napi, int work_limit) struct sky2_hw *hw = container_of(napi, struct sky2_hw, napi); u32 status = sky2_read32(hw, B0_Y2_SP_EISR); int work_done = 0; + u16 idx; if (unlikely(status & Y2_IS_ERROR)) sky2_err_intr(hw, status); @@ -2617,29 +2616,23 @@ static int sky2_poll(struct napi_struct *napi, int work_limit) if (status & Y2_IS_IRQ_PHY2) sky2_phy_intr(hw, 1); - for(;;) { - work_done += sky2_status_intr(hw, work_limit); + while ((idx = sky2_read16(hw, STAT_PUT_IDX)) != hw->st_idx) { + work_done += sky2_status_intr(hw, work_limit - work_done, idx); if (work_done >= work_limit) - break; - - /* More work? */ - if (hw->st_idx != sky2_read16(hw, STAT_PUT_IDX)) - continue; - - /* Bug/Errata workaround? - * Need to kick the TX irq moderation timer. - */ - if (sky2_read8(hw, STAT_TX_TIMER_CTRL) == TIM_START) { - sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_STOP); - sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_START); - } - - napi_complete(napi); - sky2_read32(hw, B0_Y2_SP_LISR); - break; + goto done; + } + /* Bug/Errata workaround? + * Need to kick the TX irq moderation timer. + */ + if (sky2_read8(hw, STAT_TX_TIMER_CTRL) == TIM_START) { + sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_STOP); + sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_START); } + napi_complete(napi); + sky2_read32(hw, B0_Y2_SP_LISR); +done: return work_done; } -- cgit v1.2.3-70-g09d2 From 01ba1e9d26fcd29f3ad4f3a5bcf40c0fbc40ee81 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 11 Oct 2007 04:31:46 +1000 Subject: [POWERPC] XilinxFB: Use pdata to pass around framebuffer parameters The call to xilinxfb_assign is getting unwieldy when adding features to the Xilinx framebuffer driver. Change xilinxfb_assign() to accept a pointer to a xilinxfb_platform_data structure to prepare for adding additition configuration options. Signed-off-by: Grant Likely Signed-off-by: Paul Mackerras --- drivers/video/xilinxfb.c | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index dec602c2307..b3b57f4a35a 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c @@ -83,6 +83,12 @@ #define PALETTE_ENTRIES_NO 16 /* passed to fb_alloc_cmap() */ +/* + * Default xilinxfb configuration + */ +static struct xilinxfb_platform_data xilinx_fb_default_pdata = { +}; + /* * Here are the default fb_fix_screeninfo and fb_var_screeninfo structures */ @@ -207,7 +213,7 @@ static struct fb_ops xilinxfb_ops = */ static int xilinxfb_assign(struct device *dev, unsigned long physaddr, - int width_mm, int height_mm, int rotate) + struct xilinxfb_platform_data *pdata) { struct xilinxfb_drvdata *drvdata; int rc; @@ -253,7 +259,7 @@ static int xilinxfb_assign(struct device *dev, unsigned long physaddr, /* Turn on the display */ drvdata->reg_ctrl_default = REG_CTRL_ENABLE; - if (rotate) + if (pdata->rotate_screen) drvdata->reg_ctrl_default |= REG_CTRL_ROTATE; xilinx_fb_out_be32(drvdata, REG_CTRL, drvdata->reg_ctrl_default); @@ -267,8 +273,8 @@ static int xilinxfb_assign(struct device *dev, unsigned long physaddr, drvdata->info.flags = FBINFO_DEFAULT; drvdata->info.var = xilinx_fb_var; - xilinx_fb_var.height = height_mm; - xilinx_fb_var.width = width_mm; + xilinx_fb_var.height = pdata->screen_height_mm; + xilinx_fb_var.width = pdata->screen_width_mm; /* Allocate a colour map */ rc = fb_alloc_cmap(&drvdata->info.cmap, PALETTE_ENTRIES_NO, 0); @@ -349,9 +355,6 @@ xilinxfb_platform_probe(struct platform_device *pdev) { struct xilinxfb_platform_data *pdata; struct resource *res; - int width_mm = 0; - int height_mm = 0; - int rotate = 0; /* Find the registers address */ res = platform_get_resource(pdev, IORESOURCE_IO, 0); @@ -361,15 +364,12 @@ xilinxfb_platform_probe(struct platform_device *pdev) } /* If a pdata structure is provided, then extract the parameters */ - pdata = pdev->dev.platform_data; - if (pdata) { - height_mm = pdata->screen_height_mm; - width_mm = pdata->screen_width_mm; - rotate = pdata->rotate_screen ? 1 : 0; - } + if (pdev->dev.platform_data) + pdata = pdev->dev.platform_data; + else + pdata = &xilinx_fb_default_pdata; - return xilinxfb_assign(&pdev->dev, res->start, width_mm, height_mm, - rotate); + return xilinxfb_assign(&pdev->dev, res->start, pdata); } static int @@ -398,9 +398,12 @@ xilinxfb_of_probe(struct of_device *op, const struct of_device_id *match) { struct resource res; const u32 *prop; - int width = 0, height = 0, rotate = 0; + struct xilinxfb_platform_data pdata; int size, rc; + /* Copy with the default pdata (not a ptr reference!) */ + pdata = xilinx_fb_default_pdata; + dev_dbg(&op->dev, "xilinxfb_of_probe(%p, %p)\n", op, match); rc = of_address_to_resource(op->node, 0, &res); @@ -411,14 +414,14 @@ xilinxfb_of_probe(struct of_device *op, const struct of_device_id *match) prop = of_get_property(op->node, "display-number", &size); if ((prop) && (size >= sizeof(u32)*2)) { - width = prop[0]; - height = prop[1]; + pdata.screen_width_mm = prop[0]; + pdata.screen_height_mm = prop[1]; } if (of_find_property(op->node, "rotate-display", NULL)) - rotate = 1; + pdata.rotate_screen = 1; - return xilinxfb_assign(&op->dev, res.start, width, height, rotate); + return xilinxfb_assign(&op->dev, res.start, &pdata); } static int __devexit xilinxfb_of_remove(struct of_device *op) -- cgit v1.2.3-70-g09d2 From b4d6a7268fc754eefb196cabc0ccfa2e97022af2 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 11 Oct 2007 04:31:51 +1000 Subject: [POWERPC] XilinxFB: Add support for custom screen resolution Some custom implementations of the xilinx fb can use resolutions other than 640x480. This patch allows the resolution to be specified in the device tree or the xilinx_platform_data structure. Signed-off-by: Grant Likely Signed-off-by: Paul Mackerras --- drivers/video/xilinxfb.c | 71 ++++++++++++++++++++++++++++++------------------ include/linux/xilinxfb.h | 6 ++-- 2 files changed, 49 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index b3b57f4a35a..c6174125f52 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c @@ -70,12 +70,6 @@ */ #define BYTES_PER_PIXEL 4 #define BITS_PER_PIXEL (BYTES_PER_PIXEL * 8) -#define XRES 640 -#define YRES 480 -#define XRES_VIRTUAL 1024 -#define YRES_VIRTUAL YRES -#define LINE_LENGTH (XRES_VIRTUAL * BYTES_PER_PIXEL) -#define FB_SIZE (YRES_VIRTUAL * LINE_LENGTH) #define RED_SHIFT 16 #define GREEN_SHIFT 8 @@ -87,6 +81,10 @@ * Default xilinxfb configuration */ static struct xilinxfb_platform_data xilinx_fb_default_pdata = { + .xres = 640, + .yres = 480, + .xvirt = 1024, + .yvirt = 480; }; /* @@ -96,17 +94,10 @@ static struct fb_fix_screeninfo xilinx_fb_fix = { .id = "Xilinx", .type = FB_TYPE_PACKED_PIXELS, .visual = FB_VISUAL_TRUECOLOR, - .smem_len = FB_SIZE, - .line_length = LINE_LENGTH, .accel = FB_ACCEL_NONE }; static struct fb_var_screeninfo xilinx_fb_var = { - .xres = XRES, - .yres = YRES, - .xres_virtual = XRES_VIRTUAL, - .yres_virtual = YRES_VIRTUAL, - .bits_per_pixel = BITS_PER_PIXEL, .red = { RED_SHIFT, 8, 0 }, @@ -217,6 +208,7 @@ static int xilinxfb_assign(struct device *dev, unsigned long physaddr, { struct xilinxfb_drvdata *drvdata; int rc; + int fbsize = pdata->xvirt * pdata->yvirt * BYTES_PER_PIXEL; /* Allocate the driver data region */ drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL); @@ -243,7 +235,7 @@ static int xilinxfb_assign(struct device *dev, unsigned long physaddr, } /* Allocate the framebuffer memory */ - drvdata->fb_virt = dma_alloc_coherent(dev, PAGE_ALIGN(FB_SIZE), + drvdata->fb_virt = dma_alloc_coherent(dev, PAGE_ALIGN(fbsize), &drvdata->fb_phys, GFP_KERNEL); if (!drvdata->fb_virt) { dev_err(dev, "Could not allocate frame buffer memory\n"); @@ -252,7 +244,7 @@ static int xilinxfb_assign(struct device *dev, unsigned long physaddr, } /* Clear (turn to black) the framebuffer */ - memset_io((void __iomem *)drvdata->fb_virt, 0, FB_SIZE); + memset_io((void __iomem *)drvdata->fb_virt, 0, fbsize); /* Tell the hardware where the frame buffer is */ xilinx_fb_out_be32(drvdata, REG_FB_ADDR, drvdata->fb_phys); @@ -269,12 +261,18 @@ static int xilinxfb_assign(struct device *dev, unsigned long physaddr, drvdata->info.fbops = &xilinxfb_ops; drvdata->info.fix = xilinx_fb_fix; drvdata->info.fix.smem_start = drvdata->fb_phys; + drvdata->info.fix.smem_len = fbsize; + drvdata->info.fix.line_length = pdata->xvirt * BYTES_PER_PIXEL; + drvdata->info.pseudo_palette = drvdata->pseudo_palette; drvdata->info.flags = FBINFO_DEFAULT; drvdata->info.var = xilinx_fb_var; - - xilinx_fb_var.height = pdata->screen_height_mm; - xilinx_fb_var.width = pdata->screen_width_mm; + drvdata->info.var.height = pdata->screen_height_mm; + drvdata->info.var.width = pdata->screen_width_mm; + drvdata->info.var.xres = pdata->xres; + drvdata->info.var.yres = pdata->yres; + drvdata->info.var.xres_virtual = pdata->xvirt; + drvdata->info.var.yres_virtual = pdata->yvirt; /* Allocate a colour map */ rc = fb_alloc_cmap(&drvdata->info.cmap, PALETTE_ENTRIES_NO, 0); @@ -294,14 +292,15 @@ static int xilinxfb_assign(struct device *dev, unsigned long physaddr, /* Put a banner in the log (for DEBUG) */ dev_dbg(dev, "regs: phys=%lx, virt=%p\n", physaddr, drvdata->regs); dev_dbg(dev, "fb: phys=%p, virt=%p, size=%x\n", - (void*)drvdata->fb_phys, drvdata->fb_virt, FB_SIZE); + (void*)drvdata->fb_phys, drvdata->fb_virt, fbsize); + return 0; /* success */ err_regfb: fb_dealloc_cmap(&drvdata->info.cmap); err_cmap: - dma_free_coherent(dev, PAGE_ALIGN(FB_SIZE), drvdata->fb_virt, + dma_free_coherent(dev, PAGE_ALIGN(fbsize), drvdata->fb_virt, drvdata->fb_phys); /* Turn off the display */ xilinx_fb_out_be32(drvdata, REG_CTRL, 0); @@ -331,8 +330,8 @@ static int xilinxfb_release(struct device *dev) fb_dealloc_cmap(&drvdata->info.cmap); - dma_free_coherent(dev, PAGE_ALIGN(FB_SIZE), drvdata->fb_virt, - drvdata->fb_phys); + dma_free_coherent(dev, PAGE_ALIGN(drvdata->info.fix.smem_len), + drvdata->fb_virt, drvdata->fb_phys); /* Turn off the display */ xilinx_fb_out_be32(drvdata, REG_CTRL, 0); @@ -364,10 +363,18 @@ xilinxfb_platform_probe(struct platform_device *pdev) } /* If a pdata structure is provided, then extract the parameters */ - if (pdev->dev.platform_data) + pdata = &xilinx_fb_default_pdata; + if (pdev->dev.platform_data) { pdata = pdev->dev.platform_data; - else - pdata = &xilinx_fb_default_pdata; + if (!pdata->xres) + pdata->xres = xilinx_fb_default_pdata.xres; + if (!pdata->yres) + pdata->yres = xilinx_fb_default_pdata.yres; + if (!pdata->xvirt) + pdata->xvirt = xilinx_fb_default_pdata.xvirt; + if (!pdata->yvirt) + pdata->yvirt = xilinx_fb_default_pdata.yvirt; + } return xilinxfb_assign(&pdev->dev, res->start, pdata); } @@ -412,12 +419,24 @@ xilinxfb_of_probe(struct of_device *op, const struct of_device_id *match) return rc; } - prop = of_get_property(op->node, "display-number", &size); + prop = of_get_property(op->node, "phys-size", &size); if ((prop) && (size >= sizeof(u32)*2)) { pdata.screen_width_mm = prop[0]; pdata.screen_height_mm = prop[1]; } + prop = of_get_property(op->node, "resolution", &size); + if ((prop) && (size >= sizeof(u32)*2)) { + pdata.xres = prop[0]; + pdata.yres = prop[1]; + } + + prop = of_get_property(op->node, "virtual-resolution", &size); + if ((prop) && (size >= sizeof(u32)*2)) { + pdata.xvirt = prop[0]; + pdata.yvirt = prop[1]; + } + if (of_find_property(op->node, "rotate-display", NULL)) pdata.rotate_screen = 1; diff --git a/include/linux/xilinxfb.h b/include/linux/xilinxfb.h index 9ad984d22c3..199a1eedf22 100644 --- a/include/linux/xilinxfb.h +++ b/include/linux/xilinxfb.h @@ -15,9 +15,11 @@ /* ML300/403 reference design framebuffer driver platform data struct */ struct xilinxfb_platform_data { - u32 rotate_screen; - u32 screen_height_mm; + u32 rotate_screen; /* Flag to rotate display 180 degrees */ + u32 screen_height_mm; /* Physical dimentions of screen in mm */ u32 screen_width_mm; + u32 xres, yres; /* resolution of screen in pixels */ + u32 xvirt, yvirt; /* resolution of memory buffer */ }; #endif /* __XILINXFB_H__ */ -- cgit v1.2.3-70-g09d2 From 287e5d6fcccfa38b953cebe307e1ddfd32363355 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 11 Oct 2007 04:31:56 +1000 Subject: [POWERPC] XilinxFB: Allow fixed framebuffer base address Allow a fixed framebuffer address to be assigned to the framebuffer device instead of allocating the framebuffer from the consistent memory pool. Signed-off-by: Grant Likely Signed-off-by: Paul Mackerras --- drivers/video/xilinxfb.c | 22 ++++++++++++++++------ include/linux/xilinxfb.h | 5 +++++ 2 files changed, 21 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index c6174125f52..6ef99b2d13c 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c @@ -117,6 +117,7 @@ struct xilinxfb_drvdata { void *fb_virt; /* virt. address of the frame buffer */ dma_addr_t fb_phys; /* phys. address of the frame buffer */ + int fb_alloced; /* Flag, was the fb memory alloced? */ u32 reg_ctrl_default; @@ -235,8 +236,15 @@ static int xilinxfb_assign(struct device *dev, unsigned long physaddr, } /* Allocate the framebuffer memory */ - drvdata->fb_virt = dma_alloc_coherent(dev, PAGE_ALIGN(fbsize), - &drvdata->fb_phys, GFP_KERNEL); + if (pdata->fb_phys) { + drvdata->fb_phys = pdata->fb_phys; + drvdata->fb_virt = ioremap(pdata->fb_phys, fbsize); + } else { + drvdata->fb_alloced = 1; + drvdata->fb_virt = dma_alloc_coherent(dev, PAGE_ALIGN(fbsize), + &drvdata->fb_phys, GFP_KERNEL); + } + if (!drvdata->fb_virt) { dev_err(dev, "Could not allocate frame buffer memory\n"); rc = -ENOMEM; @@ -300,8 +308,9 @@ err_regfb: fb_dealloc_cmap(&drvdata->info.cmap); err_cmap: - dma_free_coherent(dev, PAGE_ALIGN(fbsize), drvdata->fb_virt, - drvdata->fb_phys); + if (drvdata->fb_alloced) + dma_free_coherent(dev, PAGE_ALIGN(fbsize), drvdata->fb_virt, + drvdata->fb_phys); /* Turn off the display */ xilinx_fb_out_be32(drvdata, REG_CTRL, 0); @@ -330,8 +339,9 @@ static int xilinxfb_release(struct device *dev) fb_dealloc_cmap(&drvdata->info.cmap); - dma_free_coherent(dev, PAGE_ALIGN(drvdata->info.fix.smem_len), - drvdata->fb_virt, drvdata->fb_phys); + if (drvdata->fb_alloced) + dma_free_coherent(dev, PAGE_ALIGN(drvdata->info.fix.smem_len), + drvdata->fb_virt, drvdata->fb_phys); /* Turn off the display */ xilinx_fb_out_be32(drvdata, REG_CTRL, 0); diff --git a/include/linux/xilinxfb.h b/include/linux/xilinxfb.h index 199a1eedf22..f2463f559fb 100644 --- a/include/linux/xilinxfb.h +++ b/include/linux/xilinxfb.h @@ -20,6 +20,11 @@ struct xilinxfb_platform_data { u32 screen_width_mm; u32 xres, yres; /* resolution of screen in pixels */ u32 xvirt, yvirt; /* resolution of memory buffer */ + + /* Physical address of framebuffer memory; If non-zero, driver + * will use provided memory address instead of allocating one from + * the consistent pool. */ + u32 fb_phys; }; #endif /* __XILINXFB_H__ */ -- cgit v1.2.3-70-g09d2 From 6c08772e49622e90d39903e7ff0be1a0f463ac86 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Fri, 12 Oct 2007 00:16:23 -0400 Subject: [libata] sata_mv: more S/G fixes * corruption fix: we only want the lower 16 bits of length (0 == 64kb) * ditto: the upper layer sets max-phys-segments to LIBATA_MAX_PRD, so we must reset it to own hw-specific length. * delete unused mv_fill_sg() return value Signed-off-by: Jeff Garzik --- drivers/ata/sata_mv.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index cb7dec97fee..d9832e234e4 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -69,10 +69,11 @@ #include #include #include +#include #include #define DRV_NAME "sata_mv" -#define DRV_VERSION "1.0" +#define DRV_VERSION "1.01" enum { /* BAR's are enumerated in terms of pci_resource_start() terms */ @@ -420,6 +421,7 @@ static void mv_error_handler(struct ata_port *ap); static void mv_post_int_cmd(struct ata_queued_cmd *qc); static void mv_eh_freeze(struct ata_port *ap); static void mv_eh_thaw(struct ata_port *ap); +static int mv_slave_config(struct scsi_device *sdev); static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); static void mv5_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio, @@ -457,7 +459,7 @@ static struct scsi_host_template mv5_sht = { .use_clustering = 1, .proc_name = DRV_NAME, .dma_boundary = MV_DMA_BOUNDARY, - .slave_configure = ata_scsi_slave_config, + .slave_configure = mv_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, }; @@ -475,7 +477,7 @@ static struct scsi_host_template mv6_sht = { .use_clustering = 1, .proc_name = DRV_NAME, .dma_boundary = MV_DMA_BOUNDARY, - .slave_configure = ata_scsi_slave_config, + .slave_configure = mv_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, }; @@ -763,6 +765,17 @@ static void mv_irq_clear(struct ata_port *ap) { } +static int mv_slave_config(struct scsi_device *sdev) +{ + int rc = ata_scsi_slave_config(sdev); + if (rc) + return rc; + + blk_queue_max_phys_segments(sdev->request_queue, MV_MAX_SG_CT / 2); + + return 0; /* scsi layer doesn't check return value, sigh */ +} + static void mv_set_edma_ptrs(void __iomem *port_mmio, struct mv_host_priv *hpriv, struct mv_port_priv *pp) @@ -1130,10 +1143,9 @@ static void mv_port_stop(struct ata_port *ap) * LOCKING: * Inherited from caller. */ -static unsigned int mv_fill_sg(struct ata_queued_cmd *qc) +static void mv_fill_sg(struct ata_queued_cmd *qc) { struct mv_port_priv *pp = qc->ap->private_data; - unsigned int n_sg = 0; struct scatterlist *sg; struct mv_sg *mv_sg; @@ -1151,7 +1163,7 @@ static unsigned int mv_fill_sg(struct ata_queued_cmd *qc) mv_sg->addr = cpu_to_le32(addr & 0xffffffff); mv_sg->addr_hi = cpu_to_le32((addr >> 16) >> 16); - mv_sg->flags_size = cpu_to_le32(len); + mv_sg->flags_size = cpu_to_le32(len & 0xffff); sg_len -= len; addr += len; @@ -1160,12 +1172,9 @@ static unsigned int mv_fill_sg(struct ata_queued_cmd *qc) mv_sg->flags_size |= cpu_to_le32(EPRD_FLAG_END_OF_TBL); mv_sg++; - n_sg++; } } - - return n_sg; } static inline void mv_crqb_pack_cmd(__le16 *cmdw, u8 data, u8 addr, unsigned last) -- cgit v1.2.3-70-g09d2 From 295b54c4902c52cd00d7c837d50a86e39e26caec Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 11 Oct 2007 19:47:22 -0700 Subject: [SKY2]: ethtool register reserved area blackout Make sure and not dump reserved areas of device space. Touching some of these causes machine check exceptions on boards like D-Link DGE-550SX. Coding note, used a complex switch statement rather than bitmap because it is easier to relate the block values to the documentation rather than looking at a encoded bitmask. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 53 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 0a320346541..4832f640372 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -3569,20 +3569,64 @@ static void sky2_get_regs(struct net_device *dev, struct ethtool_regs *regs, { const struct sky2_port *sky2 = netdev_priv(dev); const void __iomem *io = sky2->hw->regs; + unsigned int b; regs->version = 1; - memset(p, 0, regs->len); - memcpy_fromio(p, io, B3_RAM_ADDR); - - /* skip diagnostic ram region */ - memcpy_fromio(p + B3_RI_WTO_R1, io + B3_RI_WTO_R1, 0x2000 - B3_RI_WTO_R1); + for (b = 0; b < 128; b++) { + /* This complicated switch statement is to make sure and + * only access regions that are unreserved. + * Some blocks are only valid on dual port cards. + * and block 3 has some special diagnostic registers that + * are poison. + */ + switch (b) { + case 3: + /* skip diagnostic ram region */ + memcpy_fromio(p + 0x10, io + 0x10, 128 - 0x10); + break; - /* copy GMAC registers */ - memcpy_fromio(p + BASE_GMAC_1, io + BASE_GMAC_1, 0x1000); - if (sky2->hw->ports > 1) - memcpy_fromio(p + BASE_GMAC_2, io + BASE_GMAC_2, 0x1000); + /* dual port cards only */ + case 5: /* Tx Arbiter 2 */ + case 9: /* RX2 */ + case 14 ... 15: /* TX2 */ + case 17: case 19: /* Ram Buffer 2 */ + case 22 ... 23: /* Tx Ram Buffer 2 */ + case 25: /* Rx MAC Fifo 1 */ + case 27: /* Tx MAC Fifo 2 */ + case 31: /* GPHY 2 */ + case 40 ... 47: /* Pattern Ram 2 */ + case 52: case 54: /* TCP Segmentation 2 */ + case 112 ... 116: /* GMAC 2 */ + if (sky2->hw->ports == 1) + goto reserved; + /* fall through */ + case 0: /* Control */ + case 2: /* Mac address */ + case 4: /* Tx Arbiter 1 */ + case 7: /* PCI express reg */ + case 8: /* RX1 */ + case 12 ... 13: /* TX1 */ + case 16: case 18:/* Rx Ram Buffer 1 */ + case 20 ... 21: /* Tx Ram Buffer 1 */ + case 24: /* Rx MAC Fifo 1 */ + case 26: /* Tx MAC Fifo 1 */ + case 28 ... 29: /* Descriptor and status unit */ + case 30: /* GPHY 1*/ + case 32 ... 39: /* Pattern Ram 1 */ + case 48: case 50: /* TCP Segmentation 1 */ + case 56 ... 60: /* PCI space */ + case 80 ... 84: /* GMAC 1 */ + memcpy_fromio(p, io, 128); + break; + default: +reserved: + memset(p, 0, 128); + } + p += 128; + io += 128; + } } /* In order to do Jumbo packets on these chips, need to turn off the -- cgit v1.2.3-70-g09d2 From ff35164e72648e0bf0b10ec4410c195e8607e88b Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 11 Oct 2007 19:47:44 -0700 Subject: [SKY2]: fix power settings on Yukon XL Make sure PCI register for PHY power gets set correctly. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 4832f640372..c9ee8a2c24b 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -606,20 +606,19 @@ static void sky2_phy_power(struct sky2_hw *hw, unsigned port, int onoff) { struct pci_dev *pdev = hw->pdev; u32 reg1; - static const u32 phy_power[] - = { PCI_Y2_PHY1_POWD, PCI_Y2_PHY2_POWD }; - - /* looks like this XL is back asswards .. */ - if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1) - onoff = !onoff; + static const u32 phy_power[] = { PCI_Y2_PHY1_POWD, PCI_Y2_PHY2_POWD }; + static const u32 coma_mode[] = { PCI_Y2_PHY1_COMA, PCI_Y2_PHY2_COMA }; pci_read_config_dword(pdev, PCI_DEV_REG1, ®1); + /* Turn on/off phy power saving */ if (onoff) - /* Turn off phy power saving */ reg1 &= ~phy_power[port]; else reg1 |= phy_power[port]; + if (onoff && hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1) + reg1 |= coma_mode[port]; + pci_write_config_dword(pdev, PCI_DEV_REG1, reg1); pci_read_config_dword(pdev, PCI_DEV_REG1, ®1); -- cgit v1.2.3-70-g09d2 From df3fe1f318b226453b8dc48622c2b6eb78d75dbb Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 11 Oct 2007 19:48:04 -0700 Subject: [SKY2]: fiber advertise bits initialization (trivial) Put initialization in sequential order (same as other constants). Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index c9ee8a2c24b..55cda58bf59 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -296,10 +296,10 @@ static const u16 copper_fc_adv[] = { /* flow control to advertise bits when using 1000BaseX */ static const u16 fiber_fc_adv[] = { - [FC_BOTH] = PHY_M_P_BOTH_MD_X, + [FC_NONE] = PHY_M_P_NO_PAUSE_X, [FC_TX] = PHY_M_P_ASYM_MD_X, [FC_RX] = PHY_M_P_SYM_MD_X, - [FC_NONE] = PHY_M_P_NO_PAUSE_X, + [FC_BOTH] = PHY_M_P_BOTH_MD_X, }; /* flow control to GMA disable bits */ -- cgit v1.2.3-70-g09d2 From 7138a0f591b0aac3b9117e68db46903606a97b0c Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 11 Oct 2007 19:48:22 -0700 Subject: [SKY2]: use netdevice stats struct Use builtin statistics structure from net device. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 33 +++++++++++++-------------------- drivers/net/sky2.h | 2 -- 2 files changed, 13 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 55cda58bf59..93655efae50 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1635,8 +1635,8 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done) printk(KERN_DEBUG "%s: tx done %u\n", dev->name, idx); - sky2->net_stats.tx_packets++; - sky2->net_stats.tx_bytes += re->skb->len; + dev->stats.tx_packets++; + dev->stats.tx_bytes += re->skb->len; dev_kfree_skb_any(re->skb); sky2->tx_next = RING_NEXT(idx, TX_RING_SIZE); @@ -2204,16 +2204,16 @@ resubmit: len_error: /* Truncation of overlength packets causes PHY length to not match MAC length */ - ++sky2->net_stats.rx_length_errors; + ++dev->stats.rx_length_errors; if (netif_msg_rx_err(sky2) && net_ratelimit()) pr_info(PFX "%s: rx length error: status %#x length %d\n", dev->name, status, length); goto resubmit; error: - ++sky2->net_stats.rx_errors; + ++dev->stats.rx_errors; if (status & GMR_FS_RX_FF_OV) { - sky2->net_stats.rx_over_errors++; + dev->stats.rx_over_errors++; goto resubmit; } @@ -2222,11 +2222,11 @@ error: dev->name, status, length); if (status & (GMR_FS_LONG_ERR | GMR_FS_UN_SIZE)) - sky2->net_stats.rx_length_errors++; + dev->stats.rx_length_errors++; if (status & GMR_FS_FRAGMENT) - sky2->net_stats.rx_frame_errors++; + dev->stats.rx_frame_errors++; if (status & GMR_FS_CRC_ERR) - sky2->net_stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; goto resubmit; } @@ -2271,7 +2271,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx) ++rx[port]; skb = sky2_receive(dev, length, status); if (unlikely(!skb)) { - sky2->net_stats.rx_dropped++; + dev->stats.rx_dropped++; break; } @@ -2286,8 +2286,8 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx) } skb->protocol = eth_type_trans(skb, dev); - sky2->net_stats.rx_packets++; - sky2->net_stats.rx_bytes += skb->len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += skb->len; dev->last_rx = jiffies; #ifdef SKY2_VLAN_TAG_USED @@ -2478,12 +2478,12 @@ static void sky2_mac_intr(struct sky2_hw *hw, unsigned port) gma_read16(hw, port, GM_TX_IRQ_SRC); if (status & GM_IS_RX_FF_OR) { - ++sky2->net_stats.rx_fifo_errors; + ++dev->stats.rx_fifo_errors; sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_CLI_RX_FO); } if (status & GM_IS_TX_FF_UR) { - ++sky2->net_stats.tx_fifo_errors; + ++dev->stats.tx_fifo_errors; sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_CLI_TX_FU); } } @@ -3222,12 +3222,6 @@ static void sky2_get_strings(struct net_device *dev, u32 stringset, u8 * data) } } -static struct net_device_stats *sky2_get_stats(struct net_device *dev) -{ - struct sky2_port *sky2 = netdev_priv(dev); - return &sky2->net_stats; -} - static int sky2_set_mac_address(struct net_device *dev, void *p) { struct sky2_port *sky2 = netdev_priv(dev); @@ -3977,7 +3971,6 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, dev->stop = sky2_down; dev->do_ioctl = sky2_ioctl; dev->hard_start_xmit = sky2_xmit_frame; - dev->get_stats = sky2_get_stats; dev->set_multicast_list = sky2_set_multicast; dev->set_mac_address = sky2_set_mac_address; dev->change_mtu = sky2_change_mtu; diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index f4a3c2f403e..49ee264064a 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -2031,8 +2031,6 @@ struct sky2_port { #ifdef CONFIG_SKY2_DEBUG struct dentry *debugfs; #endif - struct net_device_stats net_stats; - }; struct sky2_hw { -- cgit v1.2.3-70-g09d2 From a7b850eaa1110b1fcdc09fdfe89e792828e9b7aa Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 11 Oct 2007 19:48:40 -0700 Subject: [SKY2]: version 1.19 Update version to keep track of new changes. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 93655efae50..68f728f0b60 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -52,7 +52,7 @@ #include "sky2.h" #define DRV_NAME "sky2" -#define DRV_VERSION "1.18" +#define DRV_VERSION "1.19" #define PFX DRV_NAME " " /* -- cgit v1.2.3-70-g09d2 From 9ce768ead83216d394175c0a0d72bc527648c7d0 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Thu, 11 Oct 2007 19:49:11 -0700 Subject: [TG3]: Fix APE induced regression This patch fixes a bug caused by the recent APE support added for 5761 devices. Signed-off-by: Matt Carlson Signed-off-by: David S. Miller --- drivers/net/tg3.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index a402b5c0189..e795c33b982 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -6985,9 +6985,10 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) break; }; - /* Write our heartbeat update interval to APE. */ - tg3_ape_write32(tp, TG3_APE_HOST_HEARTBEAT_INT_MS, - APE_HOST_HEARTBEAT_INT_DISABLE); + if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) + /* Write our heartbeat update interval to APE. */ + tg3_ape_write32(tp, TG3_APE_HOST_HEARTBEAT_INT_MS, + APE_HOST_HEARTBEAT_INT_DISABLE); tg3_write_sig_post_reset(tp, RESET_KIND_INIT); -- cgit v1.2.3-70-g09d2 From 4fd7ab5949edfdf99be0ceef206c9d0b7f186318 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 12 Oct 2007 01:39:50 -0700 Subject: [TG3]: Refine napi poll loop. Need to read and store sblk->status_tag before checking for more work. The status tag is later written back to the hardware when enabling interrupts to acknowledge how much work has been processed. If the order is reversed, we can end up acknowledging work we haven't processed. When we detect tx error, it is more correct to return the rx work_done so far instead of 0. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index e795c33b982..30b1cca8144 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -3576,7 +3576,7 @@ static int tg3_poll_work(struct tg3 *tp, int work_done, int budget) if (sblk->idx[0].tx_consumer != tp->tx_cons) { tg3_tx(tp); if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING)) - return 0; + return work_done; } /* run RX thread, within the bounds set by NAPI. @@ -3593,6 +3593,7 @@ static int tg3_poll(struct napi_struct *napi, int budget) { struct tg3 *tp = container_of(napi, struct tg3, napi); int work_done = 0; + struct tg3_hw_status *sblk = tp->hw_status; while (1) { work_done = tg3_poll_work(tp, work_done, budget); @@ -3603,15 +3604,17 @@ static int tg3_poll(struct napi_struct *napi, int budget) if (unlikely(work_done >= budget)) break; - if (likely(!tg3_has_work(tp))) { - struct tg3_hw_status *sblk = tp->hw_status; - - if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) { - tp->last_tag = sblk->status_tag; - rmb(); - } else - sblk->status &= ~SD_STATUS_UPDATED; + if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) { + /* tp->last_tag is used in tg3_restart_ints() below + * to tell the hw how much work has been processed, + * so we must read it before checking for more work. + */ + tp->last_tag = sblk->status_tag; + rmb(); + } else + sblk->status &= ~SD_STATUS_UPDATED; + if (likely(!tg3_has_work(tp))) { netif_rx_complete(tp->dev, napi); tg3_restart_ints(tp); break; @@ -3621,9 +3624,10 @@ static int tg3_poll(struct napi_struct *napi, int budget) return work_done; tx_recovery: + /* work_done is guaranteed to be less than budget. */ netif_rx_complete(tp->dev, napi); schedule_work(&tp->reset_task); - return 0; + return work_done; } static void tg3_irq_quiesce(struct tg3 *tp) -- cgit v1.2.3-70-g09d2 From 6dee6421581d3484e9a01d403dbf158161942db6 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 12 Oct 2007 01:40:38 -0700 Subject: [BNX2]: Refine napi poll loop. Need to read and store sblk->status_idx before checking for more work. The status idx is later written back to the hardware when enabling interrupts to acknowledge how much work has been processed. If the order is reversed, we can end up acknowledging work we haven't processed. When completing bnx2_poll(), we should always break out of the while loop and return work_done instead of returning 0. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index d68accea380..78ed633ceb8 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -2652,10 +2652,10 @@ static int bnx2_poll_work(struct bnx2 *bp, int work_done, int budget) REG_RD(bp, BNX2_HC_COMMAND); } - if (bp->status_blk->status_tx_quick_consumer_index0 != bp->hw_tx_cons) + if (sblk->status_tx_quick_consumer_index0 != bp->hw_tx_cons) bnx2_tx_int(bp); - if (bp->status_blk->status_rx_quick_consumer_index0 != bp->hw_rx_cons) + if (sblk->status_rx_quick_consumer_index0 != bp->hw_rx_cons) work_done += bnx2_rx_int(bp, budget - work_done); return work_done; @@ -2665,6 +2665,7 @@ static int bnx2_poll(struct napi_struct *napi, int budget) { struct bnx2 *bp = container_of(napi, struct bnx2, napi); int work_done = 0; + struct status_block *sblk = bp->status_blk; while (1) { work_done = bnx2_poll_work(bp, work_done, budget); @@ -2672,16 +2673,19 @@ static int bnx2_poll(struct napi_struct *napi, int budget) if (unlikely(work_done >= budget)) break; + /* bp->last_status_idx is used below to tell the hw how + * much work has been processed, so we must read it before + * checking for more work. + */ + bp->last_status_idx = sblk->status_idx; + rmb(); if (likely(!bnx2_has_work(bp))) { - bp->last_status_idx = bp->status_blk->status_idx; - rmb(); - netif_rx_complete(bp->dev, napi); if (likely(bp->flags & USING_MSI_FLAG)) { REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | bp->last_status_idx); - return 0; + break; } REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | -- cgit v1.2.3-70-g09d2 From 60cc5147ae07b3b0f7592a611fa20169f7dd02cc Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 2 Aug 2007 18:51:14 -0400 Subject: [ISDN] hysdn: convert to PCI hotplug API Signed-off-by: Jeff Garzik --- drivers/isdn/hysdn/hysdn_init.c | 274 +++++++++++++++++++--------------------- 1 file changed, 130 insertions(+), 144 deletions(-) (limited to 'drivers') diff --git a/drivers/isdn/hysdn/hysdn_init.c b/drivers/isdn/hysdn/hysdn_init.c index 9e01748a176..b7cc5c2f08c 100644 --- a/drivers/isdn/hysdn/hysdn_init.c +++ b/drivers/isdn/hysdn/hysdn_init.c @@ -20,10 +20,15 @@ #include "hysdn_defs.h" static struct pci_device_id hysdn_pci_tbl[] = { - {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_METRO}, - {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2}, - {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_ERGO}, - {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO}, + { PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, + PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_METRO, 0, 0, BD_METRO }, + { PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, + PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2, 0, 0, BD_CHAMP2 }, + { PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, + PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_ERGO, 0, 0, BD_ERGO }, + { PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, + PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO, 0, 0, BD_ERGO }, + { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(pci, hysdn_pci_tbl); @@ -34,128 +39,7 @@ MODULE_LICENSE("GPL"); static char *hysdn_init_revision = "$Revision: 1.6.6.6 $"; static int cardmax; /* number of found cards */ hysdn_card *card_root = NULL; /* pointer to first card */ - -/**********************************************/ -/* table assigning PCI-sub ids to board types */ -/* the last entry contains all 0 */ -/**********************************************/ -static struct { - unsigned short subid; /* PCI sub id */ - unsigned char cardtyp; /* card type assigned */ -} pci_subid_map[] = { - - { - PCI_SUBDEVICE_ID_HYPERCOPE_METRO, BD_METRO - }, - { - PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2, BD_CHAMP2 - }, - { - PCI_SUBDEVICE_ID_HYPERCOPE_ERGO, BD_ERGO - }, - { - PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO, BD_ERGO - }, - { - 0, 0 - } /* terminating entry */ -}; - - -/*********************************************************************/ -/* search_cards searches for available cards in the pci config data. */ -/* If a card is found, the card structure is allocated and the cards */ -/* ressources are reserved. cardmax is incremented. */ -/*********************************************************************/ -static void -search_cards(void) -{ - struct pci_dev *akt_pcidev = NULL; - hysdn_card *card, *card_last; - int i; - - card_root = NULL; - card_last = NULL; - while ((akt_pcidev = pci_find_device(PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, - akt_pcidev)) != NULL) { - if (pci_enable_device(akt_pcidev)) - continue; - - if (!(card = kzalloc(sizeof(hysdn_card), GFP_KERNEL))) { - printk(KERN_ERR "HYSDN: unable to alloc device mem \n"); - return; - } - card->myid = cardmax; /* set own id */ - card->bus = akt_pcidev->bus->number; - card->devfn = akt_pcidev->devfn; /* slot + function */ - card->subsysid = akt_pcidev->subsystem_device; - card->irq = akt_pcidev->irq; - card->iobase = pci_resource_start(akt_pcidev, PCI_REG_PLX_IO_BASE); - card->plxbase = pci_resource_start(akt_pcidev, PCI_REG_PLX_MEM_BASE); - card->membase = pci_resource_start(akt_pcidev, PCI_REG_MEMORY_BASE); - card->brdtype = BD_NONE; /* unknown */ - card->debug_flags = DEF_DEB_FLAGS; /* set default debug */ - card->faxchans = 0; /* default no fax channels */ - card->bchans = 2; /* and 2 b-channels */ - for (i = 0; pci_subid_map[i].subid; i++) - if (pci_subid_map[i].subid == card->subsysid) { - card->brdtype = pci_subid_map[i].cardtyp; - break; - } - if (card->brdtype != BD_NONE) { - if (ergo_inithardware(card)) { - printk(KERN_WARNING "HYSDN: card at io 0x%04x already in use\n", card->iobase); - kfree(card); - continue; - } - } else { - printk(KERN_WARNING "HYSDN: unknown card id 0x%04x\n", card->subsysid); - kfree(card); /* release mem */ - continue; - } - cardmax++; - card->next = NULL; /*end of chain */ - if (card_last) - card_last->next = card; /* pointer to next card */ - else - card_root = card; - card_last = card; /* new chain end */ - } /* device found */ -} /* search_cards */ - -/************************************************************************************/ -/* free_resources frees the acquired PCI resources and returns the allocated memory */ -/************************************************************************************/ -static void -free_resources(void) -{ - hysdn_card *card; - - while (card_root) { - card = card_root; - if (card->releasehardware) - card->releasehardware(card); /* free all hardware resources */ - card_root = card_root->next; /* remove card from chain */ - kfree(card); /* return mem */ - - } /* while card_root */ -} /* free_resources */ - -/**************************************************************************/ -/* stop_cards disables (hardware resets) all cards and disables interrupt */ -/**************************************************************************/ -static void -stop_cards(void) -{ - hysdn_card *card; - - card = card_root; /* first in chain */ - while (card) { - if (card->stopcard) - card->stopcard(card); - card = card->next; /* remove card from chain */ - } /* while card */ -} /* stop_cards */ +static hysdn_card *card_last = NULL; /* pointer to first card */ /****************************************************************************/ @@ -191,31 +75,138 @@ hysdn_getrev(const char *revision) /* and the module is added to the list in /proc/modules, otherwise an error */ /* is assumed and the module will not be kept in memory. */ /****************************************************************************/ + +static int __devinit hysdn_pci_init_one(struct pci_dev *akt_pcidev, + const struct pci_device_id *ent) +{ + hysdn_card *card; + int rc; + + rc = pci_enable_device(akt_pcidev); + if (rc) + return rc; + + if (!(card = kzalloc(sizeof(hysdn_card), GFP_KERNEL))) { + printk(KERN_ERR "HYSDN: unable to alloc device mem \n"); + rc = -ENOMEM; + goto err_out; + } + card->myid = cardmax; /* set own id */ + card->bus = akt_pcidev->bus->number; + card->devfn = akt_pcidev->devfn; /* slot + function */ + card->subsysid = akt_pcidev->subsystem_device; + card->irq = akt_pcidev->irq; + card->iobase = pci_resource_start(akt_pcidev, PCI_REG_PLX_IO_BASE); + card->plxbase = pci_resource_start(akt_pcidev, PCI_REG_PLX_MEM_BASE); + card->membase = pci_resource_start(akt_pcidev, PCI_REG_MEMORY_BASE); + card->brdtype = BD_NONE; /* unknown */ + card->debug_flags = DEF_DEB_FLAGS; /* set default debug */ + card->faxchans = 0; /* default no fax channels */ + card->bchans = 2; /* and 2 b-channels */ + card->brdtype = ent->driver_data; + + if (ergo_inithardware(card)) { + printk(KERN_WARNING "HYSDN: card at io 0x%04x already in use\n", card->iobase); + rc = -EBUSY; + goto err_out_card; + } + + cardmax++; + card->next = NULL; /*end of chain */ + if (card_last) + card_last->next = card; /* pointer to next card */ + else + card_root = card; + card_last = card; /* new chain end */ + + pci_set_drvdata(akt_pcidev, card); + return 0; + +err_out_card: + kfree(card); +err_out: + pci_disable_device(akt_pcidev); + return rc; +} + +static void __devexit hysdn_pci_remove_one(struct pci_dev *akt_pcidev) +{ + hysdn_card *card = pci_get_drvdata(akt_pcidev); + + pci_set_drvdata(akt_pcidev, NULL); + + if (card->stopcard) + card->stopcard(card); + +#ifdef CONFIG_HYSDN_CAPI + hycapi_capi_release(card); +#endif + + if (card->releasehardware) + card->releasehardware(card); /* free all hardware resources */ + + if (card == card_root) { + card_root = card_root->next; + if (!card_root) + card_last = NULL; + } else { + hysdn_card *tmp = card_root; + while (tmp) { + if (tmp->next == card) + tmp->next = card->next; + card_last = tmp; + tmp = tmp->next; + } + } + + kfree(card); + pci_disable_device(akt_pcidev); +} + +static struct pci_driver hysdn_pci_driver = { + .name = "hysdn", + .id_table = hysdn_pci_tbl, + .probe = hysdn_pci_init_one, + .remove = __devexit_p(hysdn_pci_remove_one), +}; + +static int hysdn_have_procfs; + static int __init hysdn_init(void) { char tmp[50]; + int rc; strcpy(tmp, hysdn_init_revision); printk(KERN_NOTICE "HYSDN: module Rev: %s loaded\n", hysdn_getrev(tmp)); strcpy(tmp, hysdn_net_revision); printk(KERN_NOTICE "HYSDN: network interface Rev: %s \n", hysdn_getrev(tmp)); - search_cards(); + + rc = pci_register_driver(&hysdn_pci_driver); + if (rc) + return rc; + printk(KERN_INFO "HYSDN: %d card(s) found.\n", cardmax); - if (hysdn_procconf_init()) { - free_resources(); /* proc file_sys not created */ - return (-1); - } + if (!hysdn_procconf_init()) + hysdn_have_procfs = 1; + #ifdef CONFIG_HYSDN_CAPI if(cardmax > 0) { if(hycapi_init()) { printk(KERN_ERR "HYCAPI: init failed\n"); - return(-1); + + if (hysdn_have_procfs) + hysdn_procconf_release(); + + pci_unregister_driver(&hysdn_pci_driver); + return -ESPIPE; } } #endif /* CONFIG_HYSDN_CAPI */ - return (0); /* no error */ + + return 0; /* no error */ } /* init_module */ @@ -230,20 +221,15 @@ hysdn_init(void) static void __exit hysdn_exit(void) { + if (hysdn_have_procfs) + hysdn_procconf_release(); + + pci_unregister_driver(&hysdn_pci_driver); + #ifdef CONFIG_HYSDN_CAPI - hysdn_card *card; -#endif /* CONFIG_HYSDN_CAPI */ - stop_cards(); -#ifdef CONFIG_HYSDN_CAPI - card = card_root; /* first in chain */ - while (card) { - hycapi_capi_release(card); - card = card->next; /* remove card from chain */ - } /* while card */ hycapi_cleanup(); #endif /* CONFIG_HYSDN_CAPI */ - hysdn_procconf_release(); - free_resources(); + printk(KERN_NOTICE "HYSDN: module unloaded\n"); } /* cleanup_module */ -- cgit v1.2.3-70-g09d2 From bfc7c89f068bbbc2c48588385529d15c6feef802 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 2 Aug 2007 16:56:22 -0400 Subject: [ISDN] Remove CONFIG_PCI ifdefs from 100% PCI source code Signed-off-by: Jeff Garzik --- drivers/isdn/hisax/bkm_a8.c | 8 -------- drivers/isdn/hisax/telespci.c | 8 ++------ drivers/isdn/hisax/w6692.c | 7 +------ 3 files changed, 3 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/isdn/hisax/bkm_a8.c b/drivers/isdn/hisax/bkm_a8.c index 6339bb443f6..99ef3b43fcd 100644 --- a/drivers/isdn/hisax/bkm_a8.c +++ b/drivers/isdn/hisax/bkm_a8.c @@ -20,8 +20,6 @@ #include #include "bkm_ax.h" -#ifdef CONFIG_PCI - #define ATTEMPT_PCI_REMAPPING /* Required for PLX rev 1 */ extern const char *CardType[]; @@ -279,12 +277,9 @@ static u_char pci_bus __devinitdata = 0; static u_char pci_device_fn __devinitdata = 0; static u_char pci_irq __devinitdata = 0; -#endif /* CONFIG_PCI */ - int __devinit setup_sct_quadro(struct IsdnCard *card) { -#ifdef CONFIG_PCI struct IsdnCardState *cs = card->cs; char tmp[64]; u_int found = 0; @@ -442,7 +437,4 @@ setup_sct_quadro(struct IsdnCard *card) sct_quadro_subtypes[cs->subtyp], readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ID)); return (1); -#else - printk(KERN_ERR "HiSax: bkm_a8 only supported on PCI Systems\n"); -#endif /* CONFIG_PCI */ } diff --git a/drivers/isdn/hisax/telespci.c b/drivers/isdn/hisax/telespci.c index d09f6d033f1..4393003ae16 100644 --- a/drivers/isdn/hisax/telespci.c +++ b/drivers/isdn/hisax/telespci.c @@ -295,11 +295,12 @@ setup_telespci(struct IsdnCard *card) #ifdef __BIG_ENDIAN #error "not running on big endian machines now" #endif + strcpy(tmp, telespci_revision); printk(KERN_INFO "HiSax: Teles/PCI driver Rev. %s\n", HiSax_getrev(tmp)); if (cs->typ != ISDN_CTYPE_TELESPCI) return (0); -#ifdef CONFIG_PCI + if ((dev_tel = pci_find_device (PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36120, dev_tel))) { if (pci_enable_device(dev_tel)) return(0); @@ -317,11 +318,6 @@ setup_telespci(struct IsdnCard *card) printk(KERN_WARNING "TelesPCI: No PCI card found\n"); return(0); } -#else - printk(KERN_WARNING "HiSax: Teles/PCI and NO_PCI_BIOS\n"); - printk(KERN_WARNING "HiSax: Teles/PCI unable to config\n"); - return (0); -#endif /* CONFIG_PCI */ /* Initialize Zoran PCI controller */ writel(0x00000000, cs->hw.teles0.membase + 0x28); diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c index 3aeceaf9769..39129b94f8b 100644 --- a/drivers/isdn/hisax/w6692.c +++ b/drivers/isdn/hisax/w6692.c @@ -1009,7 +1009,7 @@ setup_w6692(struct IsdnCard *card) printk(KERN_INFO "HiSax: W6692 driver Rev. %s\n", HiSax_getrev(tmp)); if (cs->typ != ISDN_CTYPE_W6692) return (0); -#ifdef CONFIG_PCI + while (id_list[id_idx].vendor_id) { dev_w6692 = pci_find_device(id_list[id_idx].vendor_id, id_list[id_idx].device_id, @@ -1061,11 +1061,6 @@ setup_w6692(struct IsdnCard *card) cs->hw.w6692.iobase + 255); return (0); } -#else - printk(KERN_WARNING "HiSax: W6692 and NO_PCI_BIOS\n"); - printk(KERN_WARNING "HiSax: W6692 unable to config\n"); - return (0); -#endif /* CONFIG_PCI */ printk(KERN_INFO "HiSax: %s config irq:%d I/O:%x\n", -- cgit v1.2.3-70-g09d2 From 2fbde4c0923f53bca9975a46059b5c481a3551ba Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 3 Oct 2007 15:23:49 -0400 Subject: [ISDN] HiSax avm_pci: split setup into three smaller functions Preparation for new ISA/PNP/PCI APIs. Just code movement, and the glue to call the new functions. Signed-off-by: Jeff Garzik --- drivers/isdn/hisax/avm_pci.c | 224 ++++++++++++++++++++++++++----------------- 1 file changed, 136 insertions(+), 88 deletions(-) (limited to 'drivers') diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c index b04a178e502..f8b79783c8b 100644 --- a/drivers/isdn/hisax/avm_pci.c +++ b/drivers/isdn/hisax/avm_pci.c @@ -20,7 +20,6 @@ #include #include -extern const char *CardType[]; static const char *avm_pci_rev = "$Revision: 1.29.2.4 $"; #define AVM_FRITZ_PCI 1 @@ -726,100 +725,15 @@ AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg) return(0); } -#ifdef CONFIG_PCI -static struct pci_dev *dev_avm __devinitdata = NULL; -#endif -#ifdef __ISAPNP__ -static struct pnp_card *pnp_avm_c __devinitdata = NULL; -#endif - -int __devinit -setup_avm_pcipnp(struct IsdnCard *card) +static int __devinit avm_setup_rest(struct IsdnCardState *cs) { u_int val, ver; - struct IsdnCardState *cs = card->cs; - char tmp[64]; - strcpy(tmp, avm_pci_rev); - printk(KERN_INFO "HiSax: AVM PCI driver Rev. %s\n", HiSax_getrev(tmp)); - if (cs->typ != ISDN_CTYPE_FRITZPCI) - return (0); - if (card->para[1]) { - /* old manual method */ - cs->hw.avm.cfg_reg = card->para[1]; - cs->irq = card->para[0]; - cs->subtyp = AVM_FRITZ_PNP; - goto ready; - } -#ifdef __ISAPNP__ - if (isapnp_present()) { - struct pnp_dev *pnp_avm_d = NULL; - if ((pnp_avm_c = pnp_find_card( - ISAPNP_VENDOR('A', 'V', 'M'), - ISAPNP_FUNCTION(0x0900), pnp_avm_c))) { - if ((pnp_avm_d = pnp_find_dev(pnp_avm_c, - ISAPNP_VENDOR('A', 'V', 'M'), - ISAPNP_FUNCTION(0x0900), pnp_avm_d))) { - int err; - - pnp_disable_dev(pnp_avm_d); - err = pnp_activate_dev(pnp_avm_d); - if (err<0) { - printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __FUNCTION__, err); - return(0); - } - cs->hw.avm.cfg_reg = - pnp_port_start(pnp_avm_d, 0); - cs->irq = pnp_irq(pnp_avm_d, 0); - if (!cs->irq) { - printk(KERN_ERR "FritzPnP:No IRQ\n"); - return(0); - } - if (!cs->hw.avm.cfg_reg) { - printk(KERN_ERR "FritzPnP:No IO address\n"); - return(0); - } - cs->subtyp = AVM_FRITZ_PNP; - goto ready; - } - } - } else { - printk(KERN_INFO "FritzPnP: no ISA PnP present\n"); - } -#endif -#ifdef CONFIG_PCI - if ((dev_avm = pci_find_device(PCI_VENDOR_ID_AVM, - PCI_DEVICE_ID_AVM_A1, dev_avm))) { - if (pci_enable_device(dev_avm)) - return(0); - cs->irq = dev_avm->irq; - if (!cs->irq) { - printk(KERN_ERR "FritzPCI: No IRQ for PCI card found\n"); - return(0); - } - cs->hw.avm.cfg_reg = pci_resource_start(dev_avm, 1); - if (!cs->hw.avm.cfg_reg) { - printk(KERN_ERR "FritzPCI: No IO-Adr for PCI card found\n"); - return(0); - } - cs->subtyp = AVM_FRITZ_PCI; - } else { - printk(KERN_WARNING "FritzPCI: No PCI card found\n"); - return(0); - } - cs->irq_flags |= IRQF_SHARED; -#else - printk(KERN_WARNING "FritzPCI: NO_PCI_BIOS\n"); - return (0); -#endif /* CONFIG_PCI */ -ready: cs->hw.avm.isac = cs->hw.avm.cfg_reg + 0x10; if (!request_region(cs->hw.avm.cfg_reg, 32, (cs->subtyp == AVM_FRITZ_PCI) ? "avm PCI" : "avm PnP")) { printk(KERN_WARNING - "HiSax: %s config port %x-%x already in use\n", - CardType[card->typ], + "HiSax: Fritz!PCI/PNP config port %x-%x already in use\n", cs->hw.avm.cfg_reg, cs->hw.avm.cfg_reg + 31); return (0); @@ -860,3 +774,137 @@ ready: ISACVersion(cs, (cs->subtyp == AVM_FRITZ_PCI) ? "AVM PCI:" : "AVM PnP:"); return (1); } + +#ifndef __ISAPNP__ + +static int __devinit avm_pnp_setup(struct IsdnCardState *cs) +{ + return(1); /* no-op: success */ +} + +#else + +static struct pnp_card *pnp_avm_c __devinitdata = NULL; + +static int __devinit avm_pnp_setup(struct IsdnCardState *cs) +{ + struct pnp_dev *pnp_avm_d = NULL; + + if (!isapnp_present()) + return(1); /* no-op: success */ + + if ((pnp_avm_c = pnp_find_card( + ISAPNP_VENDOR('A', 'V', 'M'), + ISAPNP_FUNCTION(0x0900), pnp_avm_c))) { + if ((pnp_avm_d = pnp_find_dev(pnp_avm_c, + ISAPNP_VENDOR('A', 'V', 'M'), + ISAPNP_FUNCTION(0x0900), pnp_avm_d))) { + int err; + + pnp_disable_dev(pnp_avm_d); + err = pnp_activate_dev(pnp_avm_d); + if (err<0) { + printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", + __FUNCTION__, err); + return(0); + } + cs->hw.avm.cfg_reg = + pnp_port_start(pnp_avm_d, 0); + cs->irq = pnp_irq(pnp_avm_d, 0); + if (!cs->irq) { + printk(KERN_ERR "FritzPnP:No IRQ\n"); + return(0); + } + if (!cs->hw.avm.cfg_reg) { + printk(KERN_ERR "FritzPnP:No IO address\n"); + return(0); + } + cs->subtyp = AVM_FRITZ_PNP; + + return (2); /* goto 'ready' label */ + } + } + + return (1); +} + +#endif /* __ISAPNP__ */ + +#ifndef CONFIG_PCI + +static int __devinit avm_pci_setup(struct IsdnCardState *cs) +{ + return(1); /* no-op: success */ +} + +#else + +static struct pci_dev *dev_avm __devinitdata = NULL; + +static int __devinit avm_pci_setup(struct IsdnCardState *cs) +{ + if ((dev_avm = pci_find_device(PCI_VENDOR_ID_AVM, + PCI_DEVICE_ID_AVM_A1, dev_avm))) { + + if (pci_enable_device(dev_avm)) + return(0); + + cs->irq = dev_avm->irq; + if (!cs->irq) { + printk(KERN_ERR "FritzPCI: No IRQ for PCI card found\n"); + return(0); + } + + cs->hw.avm.cfg_reg = pci_resource_start(dev_avm, 1); + if (!cs->hw.avm.cfg_reg) { + printk(KERN_ERR "FritzPCI: No IO-Adr for PCI card found\n"); + return(0); + } + + cs->subtyp = AVM_FRITZ_PCI; + } else { + printk(KERN_WARNING "FritzPCI: No PCI card found\n"); + return(0); + } + + cs->irq_flags |= IRQF_SHARED; + + return (1); +} + +#endif /* CONFIG_PCI */ + +int __devinit +setup_avm_pcipnp(struct IsdnCard *card) +{ + struct IsdnCardState *cs = card->cs; + char tmp[64]; + int rc; + + strcpy(tmp, avm_pci_rev); + printk(KERN_INFO "HiSax: AVM PCI driver Rev. %s\n", HiSax_getrev(tmp)); + + if (cs->typ != ISDN_CTYPE_FRITZPCI) + return (0); + + if (card->para[1]) { + /* old manual method */ + cs->hw.avm.cfg_reg = card->para[1]; + cs->irq = card->para[0]; + cs->subtyp = AVM_FRITZ_PNP; + goto ready; + } + + rc = avm_pnp_setup(cs); + if (rc < 1) + return (0); + if (rc == 2) + goto ready; + + rc = avm_pci_setup(cs); + if (rc < 1) + return (0); + +ready: + return avm_setup_rest(cs); +} -- cgit v1.2.3-70-g09d2 From 1e5d82e18b7204545737a5ef96bc34180a8df844 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 3 Oct 2007 15:27:22 -0400 Subject: [ISDN] HiSax elsa: split huge setup function into four smaller functions Prep for hotplug API conversion. Just code movement (+glue). Signed-off-by: Jeff Garzik --- drivers/isdn/hisax/elsa.c | 494 ++++++++++++++++++++++++++-------------------- 1 file changed, 278 insertions(+), 216 deletions(-) (limited to 'drivers') diff --git a/drivers/isdn/hisax/elsa.c b/drivers/isdn/hisax/elsa.c index fab3e4ea059..0c1351b2384 100644 --- a/drivers/isdn/hisax/elsa.c +++ b/drivers/isdn/hisax/elsa.c @@ -30,8 +30,6 @@ #include #include -extern const char *CardType[]; - static const char *Elsa_revision = "$Revision: 2.32.2.4 $"; static const char *Elsa_Types[] = {"None", "PC", "PCC-8", "PCC-16", "PCF", "PCF-Pro", @@ -832,8 +830,75 @@ probe_elsa(struct IsdnCardState *cs) return (CARD_portlist[i]); } -static struct pci_dev *dev_qs1000 __devinitdata = NULL; -static struct pci_dev *dev_qs3000 __devinitdata = NULL; +static int __devinit +setup_elsa_isa(struct IsdnCard *card) +{ + struct IsdnCardState *cs = card->cs; + u_char val; + + cs->hw.elsa.base = card->para[0]; + printk(KERN_INFO "Elsa: Microlink IO probing\n"); + if (cs->hw.elsa.base) { + if (!(cs->subtyp = probe_elsa_adr(cs->hw.elsa.base, + cs->typ))) { + printk(KERN_WARNING + "Elsa: no Elsa Microlink at %#lx\n", + cs->hw.elsa.base); + return (0); + } + } else + cs->hw.elsa.base = probe_elsa(cs); + + if (!cs->hw.elsa.base) { + printk(KERN_WARNING + "No Elsa Microlink found\n"); + return (0); + } + + cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG; + cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL; + cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE; + cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC; + cs->hw.elsa.itac = cs->hw.elsa.base + ELSA_ITAC; + cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX; + cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ; + cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER; + val = bytein(cs->hw.elsa.cfg); + if (cs->subtyp == ELSA_PC) { + const u_char CARD_IrqTab[8] = + {7, 3, 5, 9, 0, 0, 0, 0}; + cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PC) >> 2]; + } else if (cs->subtyp == ELSA_PCC8) { + const u_char CARD_IrqTab[8] = + {7, 3, 5, 9, 0, 0, 0, 0}; + cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PCC8) >> 4]; + } else { + const u_char CARD_IrqTab[8] = + {15, 10, 15, 3, 11, 5, 11, 9}; + cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX) >> 3]; + } + val = bytein(cs->hw.elsa.ale) & ELSA_HW_RELEASE; + if (val < 3) + val |= 8; + val += 'A' - 3; + if (val == 'B' || val == 'C') + val ^= 1; + if ((cs->subtyp == ELSA_PCFPRO) && (val = 'G')) + val = 'C'; + printk(KERN_INFO + "Elsa: %s found at %#lx Rev.:%c IRQ %d\n", + Elsa_Types[cs->subtyp], + cs->hw.elsa.base, + val, cs->irq); + val = bytein(cs->hw.elsa.ale) & ELSA_S0_POWER_BAD; + if (val) { + printk(KERN_WARNING + "Elsa: Microlink S0 bus power bad\n"); + cs->hw.elsa.status |= ELSA_BAD_PWR; + } + + return (1); +} #ifdef __ISAPNP__ static struct isapnp_device_id elsa_ids[] __devinitdata = { @@ -848,233 +913,194 @@ static struct isapnp_device_id elsa_ids[] __devinitdata = { static struct isapnp_device_id *ipid __devinitdata = &elsa_ids[0]; static struct pnp_card *pnp_c __devinitdata = NULL; -#endif +#endif /* __ISAPNP__ */ -int __devinit -setup_elsa(struct IsdnCard *card) +static int __devinit +setup_elsa_isapnp(struct IsdnCard *card) { - int bytecnt; - u_char val; struct IsdnCardState *cs = card->cs; - char tmp[64]; - strcpy(tmp, Elsa_revision); - printk(KERN_INFO "HiSax: Elsa driver Rev. %s\n", HiSax_getrev(tmp)); - cs->hw.elsa.ctrl_reg = 0; - cs->hw.elsa.status = 0; - cs->hw.elsa.MFlag = 0; - cs->subtyp = 0; - if (cs->typ == ISDN_CTYPE_ELSA) { - cs->hw.elsa.base = card->para[0]; - printk(KERN_INFO "Elsa: Microlink IO probing\n"); - if (cs->hw.elsa.base) { - if (!(cs->subtyp = probe_elsa_adr(cs->hw.elsa.base, - cs->typ))) { - printk(KERN_WARNING - "Elsa: no Elsa Microlink at %#lx\n", - cs->hw.elsa.base); - return (0); - } - } else - cs->hw.elsa.base = probe_elsa(cs); - if (cs->hw.elsa.base) { - cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG; - cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL; - cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE; - cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC; - cs->hw.elsa.itac = cs->hw.elsa.base + ELSA_ITAC; - cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX; - cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ; - cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER; - val = bytein(cs->hw.elsa.cfg); - if (cs->subtyp == ELSA_PC) { - const u_char CARD_IrqTab[8] = - {7, 3, 5, 9, 0, 0, 0, 0}; - cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PC) >> 2]; - } else if (cs->subtyp == ELSA_PCC8) { - const u_char CARD_IrqTab[8] = - {7, 3, 5, 9, 0, 0, 0, 0}; - cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PCC8) >> 4]; - } else { - const u_char CARD_IrqTab[8] = - {15, 10, 15, 3, 11, 5, 11, 9}; - cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX) >> 3]; - } - val = bytein(cs->hw.elsa.ale) & ELSA_HW_RELEASE; - if (val < 3) - val |= 8; - val += 'A' - 3; - if (val == 'B' || val == 'C') - val ^= 1; - if ((cs->subtyp == ELSA_PCFPRO) && (val = 'G')) - val = 'C'; - printk(KERN_INFO - "Elsa: %s found at %#lx Rev.:%c IRQ %d\n", - Elsa_Types[cs->subtyp], - cs->hw.elsa.base, - val, cs->irq); - val = bytein(cs->hw.elsa.ale) & ELSA_S0_POWER_BAD; - if (val) { - printk(KERN_WARNING - "Elsa: Microlink S0 bus power bad\n"); - cs->hw.elsa.status |= ELSA_BAD_PWR; - } - } else { - printk(KERN_WARNING - "No Elsa Microlink found\n"); - return (0); - } - } else if (cs->typ == ISDN_CTYPE_ELSA_PNP) { #ifdef __ISAPNP__ - if (!card->para[1] && isapnp_present()) { - struct pnp_dev *pnp_d; - while(ipid->card_vendor) { - if ((pnp_c = pnp_find_card(ipid->card_vendor, - ipid->card_device, pnp_c))) { - pnp_d = NULL; - if ((pnp_d = pnp_find_dev(pnp_c, - ipid->vendor, ipid->function, pnp_d))) { - int err; - - printk(KERN_INFO "HiSax: %s detected\n", - (char *)ipid->driver_data); + if (!card->para[1] && isapnp_present()) { + struct pnp_dev *pnp_d; + while(ipid->card_vendor) { + if ((pnp_c = pnp_find_card(ipid->card_vendor, + ipid->card_device, pnp_c))) { + pnp_d = NULL; + if ((pnp_d = pnp_find_dev(pnp_c, + ipid->vendor, ipid->function, pnp_d))) { + int err; + + printk(KERN_INFO "HiSax: %s detected\n", + (char *)ipid->driver_data); + pnp_disable_dev(pnp_d); + err = pnp_activate_dev(pnp_d); + if (err<0) { + printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", + __FUNCTION__, err); + return(0); + } + card->para[1] = pnp_port_start(pnp_d, 0); + card->para[0] = pnp_irq(pnp_d, 0); + + if (!card->para[0] || !card->para[1]) { + printk(KERN_ERR "Elsa PnP:some resources are missing %ld/%lx\n", + card->para[0], card->para[1]); pnp_disable_dev(pnp_d); - err = pnp_activate_dev(pnp_d); - if (err<0) { - printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __FUNCTION__, err); - return(0); - } - card->para[1] = pnp_port_start(pnp_d, 0); - card->para[0] = pnp_irq(pnp_d, 0); - - if (!card->para[0] || !card->para[1]) { - printk(KERN_ERR "Elsa PnP:some resources are missing %ld/%lx\n", - card->para[0], card->para[1]); - pnp_disable_dev(pnp_d); - return(0); - } - if (ipid->function == ISAPNP_FUNCTION(0x133)) - cs->subtyp = ELSA_QS1000; - else - cs->subtyp = ELSA_QS3000; - break; - } else { - printk(KERN_ERR "Elsa PnP: PnP error card found, no device\n"); return(0); } + if (ipid->function == ISAPNP_FUNCTION(0x133)) + cs->subtyp = ELSA_QS1000; + else + cs->subtyp = ELSA_QS3000; + break; + } else { + printk(KERN_ERR "Elsa PnP: PnP error card found, no device\n"); + return(0); } - ipid++; - pnp_c=NULL; - } - if (!ipid->card_vendor) { - printk(KERN_INFO "Elsa PnP: no ISAPnP card found\n"); - return(0); } + ipid++; + pnp_c=NULL; + } + if (!ipid->card_vendor) { + printk(KERN_INFO "Elsa PnP: no ISAPnP card found\n"); + return(0); } -#endif - if (card->para[1] && card->para[0]) { - cs->hw.elsa.base = card->para[1]; - cs->irq = card->para[0]; - if (!cs->subtyp) - cs->subtyp = ELSA_QS1000; - } else { - printk(KERN_ERR "Elsa PnP: no parameter\n"); - } - cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG; - cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE; - cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC; - cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX; - cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ; - cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER; - cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL; - printk(KERN_INFO - "Elsa: %s defined at %#lx IRQ %d\n", - Elsa_Types[cs->subtyp], - cs->hw.elsa.base, - cs->irq); - } else if (cs->typ == ISDN_CTYPE_ELSA_PCMCIA) { + } +#endif /* __ISAPNP__ */ + + if (card->para[1] && card->para[0]) { cs->hw.elsa.base = card->para[1]; cs->irq = card->para[0]; - val = readreg(cs->hw.elsa.base + 0, cs->hw.elsa.base + 2, IPAC_ID); - if ((val == 1) || (val == 2)) { /* IPAC version 1.1/1.2 */ - cs->subtyp = ELSA_PCMCIA_IPAC; - cs->hw.elsa.ale = cs->hw.elsa.base + 0; - cs->hw.elsa.isac = cs->hw.elsa.base + 2; - cs->hw.elsa.hscx = cs->hw.elsa.base + 2; - test_and_set_bit(HW_IPAC, &cs->HW_Flags); - } else { - cs->subtyp = ELSA_PCMCIA; - cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE_PCM; - cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC_PCM; - cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX; - } - cs->hw.elsa.timer = 0; - cs->hw.elsa.trig = 0; - cs->hw.elsa.ctrl = 0; - cs->irq_flags |= IRQF_SHARED; - printk(KERN_INFO - "Elsa: %s defined at %#lx IRQ %d\n", - Elsa_Types[cs->subtyp], - cs->hw.elsa.base, - cs->irq); - } else if (cs->typ == ISDN_CTYPE_ELSA_PCI) { + if (!cs->subtyp) + cs->subtyp = ELSA_QS1000; + } else { + printk(KERN_ERR "Elsa PnP: no parameter\n"); + } + cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG; + cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE; + cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC; + cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX; + cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ; + cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER; + cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL; + printk(KERN_INFO + "Elsa: %s defined at %#lx IRQ %d\n", + Elsa_Types[cs->subtyp], + cs->hw.elsa.base, + cs->irq); + + return (1); +} + +static void __devinit +setup_elsa_pcmcia(struct IsdnCard *card) +{ + struct IsdnCardState *cs = card->cs; + u_char val; + + cs->hw.elsa.base = card->para[1]; + cs->irq = card->para[0]; + val = readreg(cs->hw.elsa.base + 0, cs->hw.elsa.base + 2, IPAC_ID); + if ((val == 1) || (val == 2)) { /* IPAC version 1.1/1.2 */ + cs->subtyp = ELSA_PCMCIA_IPAC; + cs->hw.elsa.ale = cs->hw.elsa.base + 0; + cs->hw.elsa.isac = cs->hw.elsa.base + 2; + cs->hw.elsa.hscx = cs->hw.elsa.base + 2; + test_and_set_bit(HW_IPAC, &cs->HW_Flags); + } else { + cs->subtyp = ELSA_PCMCIA; + cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE_PCM; + cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC_PCM; + cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX; + } + cs->hw.elsa.timer = 0; + cs->hw.elsa.trig = 0; + cs->hw.elsa.ctrl = 0; + cs->irq_flags |= IRQF_SHARED; + printk(KERN_INFO + "Elsa: %s defined at %#lx IRQ %d\n", + Elsa_Types[cs->subtyp], + cs->hw.elsa.base, + cs->irq); +} + #ifdef CONFIG_PCI - cs->subtyp = 0; - if ((dev_qs1000 = pci_find_device(PCI_VENDOR_ID_ELSA, - PCI_DEVICE_ID_ELSA_MICROLINK, dev_qs1000))) { - if (pci_enable_device(dev_qs1000)) - return(0); - cs->subtyp = ELSA_QS1000PCI; - cs->irq = dev_qs1000->irq; - cs->hw.elsa.cfg = pci_resource_start(dev_qs1000, 1); - cs->hw.elsa.base = pci_resource_start(dev_qs1000, 3); - } else if ((dev_qs3000 = pci_find_device(PCI_VENDOR_ID_ELSA, - PCI_DEVICE_ID_ELSA_QS3000, dev_qs3000))) { - if (pci_enable_device(dev_qs3000)) - return(0); - cs->subtyp = ELSA_QS3000PCI; - cs->irq = dev_qs3000->irq; - cs->hw.elsa.cfg = pci_resource_start(dev_qs3000, 1); - cs->hw.elsa.base = pci_resource_start(dev_qs3000, 3); - } else { - printk(KERN_WARNING "Elsa: No PCI card found\n"); +static struct pci_dev *dev_qs1000 __devinitdata = NULL; +static struct pci_dev *dev_qs3000 __devinitdata = NULL; + +static int __devinit +setup_elsa_pci(struct IsdnCard *card) +{ + struct IsdnCardState *cs = card->cs; + + cs->subtyp = 0; + if ((dev_qs1000 = pci_find_device(PCI_VENDOR_ID_ELSA, + PCI_DEVICE_ID_ELSA_MICROLINK, dev_qs1000))) { + if (pci_enable_device(dev_qs1000)) return(0); - } - if (!cs->irq) { - printk(KERN_WARNING "Elsa: No IRQ for PCI card found\n"); + cs->subtyp = ELSA_QS1000PCI; + cs->irq = dev_qs1000->irq; + cs->hw.elsa.cfg = pci_resource_start(dev_qs1000, 1); + cs->hw.elsa.base = pci_resource_start(dev_qs1000, 3); + } else if ((dev_qs3000 = pci_find_device(PCI_VENDOR_ID_ELSA, + PCI_DEVICE_ID_ELSA_QS3000, dev_qs3000))) { + if (pci_enable_device(dev_qs3000)) return(0); - } + cs->subtyp = ELSA_QS3000PCI; + cs->irq = dev_qs3000->irq; + cs->hw.elsa.cfg = pci_resource_start(dev_qs3000, 1); + cs->hw.elsa.base = pci_resource_start(dev_qs3000, 3); + } else { + printk(KERN_WARNING "Elsa: No PCI card found\n"); + return(0); + } + if (!cs->irq) { + printk(KERN_WARNING "Elsa: No IRQ for PCI card found\n"); + return(0); + } + + if (!(cs->hw.elsa.base && cs->hw.elsa.cfg)) { + printk(KERN_WARNING "Elsa: No IO-Adr for PCI card found\n"); + return(0); + } + if ((cs->hw.elsa.cfg & 0xff) || (cs->hw.elsa.base & 0xf)) { + printk(KERN_WARNING "Elsa: You may have a wrong PCI bios\n"); + printk(KERN_WARNING "Elsa: If your system hangs now, read\n"); + printk(KERN_WARNING "Elsa: Documentation/isdn/README.HiSax\n"); + } + cs->hw.elsa.ale = cs->hw.elsa.base; + cs->hw.elsa.isac = cs->hw.elsa.base +1; + cs->hw.elsa.hscx = cs->hw.elsa.base +1; + test_and_set_bit(HW_IPAC, &cs->HW_Flags); + cs->hw.elsa.timer = 0; + cs->hw.elsa.trig = 0; + cs->irq_flags |= IRQF_SHARED; + printk(KERN_INFO + "Elsa: %s defined at %#lx/0x%x IRQ %d\n", + Elsa_Types[cs->subtyp], + cs->hw.elsa.base, + cs->hw.elsa.cfg, + cs->irq); + + return (1); +} - if (!(cs->hw.elsa.base && cs->hw.elsa.cfg)) { - printk(KERN_WARNING "Elsa: No IO-Adr for PCI card found\n"); - return(0); - } - if ((cs->hw.elsa.cfg & 0xff) || (cs->hw.elsa.base & 0xf)) { - printk(KERN_WARNING "Elsa: You may have a wrong PCI bios\n"); - printk(KERN_WARNING "Elsa: If your system hangs now, read\n"); - printk(KERN_WARNING "Elsa: Documentation/isdn/README.HiSax\n"); - } - cs->hw.elsa.ale = cs->hw.elsa.base; - cs->hw.elsa.isac = cs->hw.elsa.base +1; - cs->hw.elsa.hscx = cs->hw.elsa.base +1; - test_and_set_bit(HW_IPAC, &cs->HW_Flags); - cs->hw.elsa.timer = 0; - cs->hw.elsa.trig = 0; - cs->irq_flags |= IRQF_SHARED; - printk(KERN_INFO - "Elsa: %s defined at %#lx/0x%x IRQ %d\n", - Elsa_Types[cs->subtyp], - cs->hw.elsa.base, - cs->hw.elsa.cfg, - cs->irq); #else - printk(KERN_WARNING "Elsa: Elsa PCI and NO_PCI_BIOS\n"); - printk(KERN_WARNING "Elsa: unable to config Elsa PCI\n"); - return (0); + +static void __devinit +setup_elsa_pci(struct IsdnCard *card) +{ + return (1); +} #endif /* CONFIG_PCI */ - } else - return (0); + +static int __devinit +setup_elsa_common(struct IsdnCard *card) +{ + struct IsdnCardState *cs = card->cs; + u_char val; + int bytecnt; switch (cs->subtyp) { case ELSA_PC: @@ -1104,8 +1130,7 @@ setup_elsa(struct IsdnCard *card) here, it would fail. */ if (cs->typ != ISDN_CTYPE_ELSA_PCMCIA && !request_region(cs->hw.elsa.base, bytecnt, "elsa isdn")) { printk(KERN_WARNING - "HiSax: %s config port %#lx-%#lx already in use\n", - CardType[card->typ], + "HiSax: ELSA config port %#lx-%#lx already in use\n", cs->hw.elsa.base, cs->hw.elsa.base + bytecnt); return (0); @@ -1113,8 +1138,7 @@ setup_elsa(struct IsdnCard *card) if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI)) { if (!request_region(cs->hw.elsa.cfg, 0x80, "elsa isdn pci")) { printk(KERN_WARNING - "HiSax: %s pci port %x-%x already in use\n", - CardType[card->typ], + "HiSax: ELSA pci port %x-%x already in use\n", cs->hw.elsa.cfg, cs->hw.elsa.cfg + 0x80); release_region(cs->hw.elsa.base, bytecnt); @@ -1186,3 +1210,41 @@ setup_elsa(struct IsdnCard *card) } return (1); } + +int __devinit +setup_elsa(struct IsdnCard *card) +{ + int rc; + struct IsdnCardState *cs = card->cs; + char tmp[64]; + + strcpy(tmp, Elsa_revision); + printk(KERN_INFO "HiSax: Elsa driver Rev. %s\n", HiSax_getrev(tmp)); + cs->hw.elsa.ctrl_reg = 0; + cs->hw.elsa.status = 0; + cs->hw.elsa.MFlag = 0; + cs->subtyp = 0; + + if (cs->typ == ISDN_CTYPE_ELSA) { + rc = setup_elsa_isa(card); + if (!rc) + return (0); + + } else if (cs->typ == ISDN_CTYPE_ELSA_PNP) { + rc = setup_elsa_isapnp(card); + if (!rc) + return (0); + + } else if (cs->typ == ISDN_CTYPE_ELSA_PCMCIA) + setup_elsa_pcmcia(card); + + else if (cs->typ == ISDN_CTYPE_ELSA_PCI) { + rc = setup_elsa_pci(card); + if (!rc) + return (0); + + } else + return (0); + + return setup_elsa_common(card); +} -- cgit v1.2.3-70-g09d2 From 7da0d9801bd52a1d5e58eae85a3b9508b4a11ffb Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 3 Oct 2007 15:37:40 -0400 Subject: [ISDN] HiSax sedlbauer: move ISAPNP and PCI code into functions of their own Prep for hotplug API conversion. Just code movement (+glue). Signed-off-by: Jeff Garzik --- drivers/isdn/hisax/sedlbauer.c | 276 +++++++++++++++++++++++------------------ 1 file changed, 157 insertions(+), 119 deletions(-) (limited to 'drivers') diff --git a/drivers/isdn/hisax/sedlbauer.c b/drivers/isdn/hisax/sedlbauer.c index ad06f3cc60f..03dfc32166a 100644 --- a/drivers/isdn/hisax/sedlbauer.c +++ b/drivers/isdn/hisax/sedlbauer.c @@ -518,8 +518,6 @@ Sedl_card_msg(struct IsdnCardState *cs, int mt, void *arg) return(0); } -static struct pci_dev *dev_sedl __devinitdata = NULL; - #ifdef __ISAPNP__ static struct isapnp_device_id sedl_ids[] __devinitdata = { { ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x01), @@ -533,15 +531,158 @@ static struct isapnp_device_id sedl_ids[] __devinitdata = { static struct isapnp_device_id *ipid __devinitdata = &sedl_ids[0]; static struct pnp_card *pnp_c __devinitdata = NULL; -#endif + +static int __devinit +setup_sedlbauer_isapnp(struct IsdnCard *card, int *bytecnt) +{ + struct IsdnCardState *cs = card->cs; + struct pnp_dev *pnp_d; + + if (!isapnp_present()) + return -1; + + while(ipid->card_vendor) { + if ((pnp_c = pnp_find_card(ipid->card_vendor, + ipid->card_device, pnp_c))) { + pnp_d = NULL; + if ((pnp_d = pnp_find_dev(pnp_c, + ipid->vendor, ipid->function, pnp_d))) { + int err; + + printk(KERN_INFO "HiSax: %s detected\n", + (char *)ipid->driver_data); + pnp_disable_dev(pnp_d); + err = pnp_activate_dev(pnp_d); + if (err<0) { + printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", + __FUNCTION__, err); + return(0); + } + card->para[1] = pnp_port_start(pnp_d, 0); + card->para[0] = pnp_irq(pnp_d, 0); + + if (!card->para[0] || !card->para[1]) { + printk(KERN_ERR "Sedlbauer PnP:some resources are missing %ld/%lx\n", + card->para[0], card->para[1]); + pnp_disable_dev(pnp_d); + return(0); + } + cs->hw.sedl.cfg_reg = card->para[1]; + cs->irq = card->para[0]; + if (ipid->function == ISAPNP_FUNCTION(0x2)) { + cs->subtyp = SEDL_SPEED_FAX; + cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; + *bytecnt = 16; + } else { + cs->subtyp = SEDL_SPEED_CARD_WIN; + cs->hw.sedl.chip = SEDL_CHIP_TEST; + } + + return (1); + } else { + printk(KERN_ERR "Sedlbauer PnP: PnP error card found, no device\n"); + return(0); + } + } + ipid++; + pnp_c = NULL; + } + + printk(KERN_INFO "Sedlbauer PnP: no ISAPnP card found\n"); + return -1; +} +#else + +static int __devinit +setup_sedlbauer_isapnp(struct IsdnCard *card, int *bytecnt) +{ + return -1; +} +#endif /* __ISAPNP__ */ + +#ifdef CONFIG_PCI +static struct pci_dev *dev_sedl __devinitdata = NULL; + +static int __devinit +setup_sedlbauer_pci(struct IsdnCard *card) +{ + struct IsdnCardState *cs = card->cs; + u16 sub_vendor_id, sub_id; + + if ((dev_sedl = pci_find_device(PCI_VENDOR_ID_TIGERJET, + PCI_DEVICE_ID_TIGERJET_100, dev_sedl))) { + if (pci_enable_device(dev_sedl)) + return(0); + cs->irq = dev_sedl->irq; + if (!cs->irq) { + printk(KERN_WARNING "Sedlbauer: No IRQ for PCI card found\n"); + return(0); + } + cs->hw.sedl.cfg_reg = pci_resource_start(dev_sedl, 0); + } else { + printk(KERN_WARNING "Sedlbauer: No PCI card found\n"); + return(0); + } + cs->irq_flags |= IRQF_SHARED; + cs->hw.sedl.bus = SEDL_BUS_PCI; + sub_vendor_id = dev_sedl->subsystem_vendor; + sub_id = dev_sedl->subsystem_device; + printk(KERN_INFO "Sedlbauer: PCI subvendor:%x subid %x\n", + sub_vendor_id, sub_id); + printk(KERN_INFO "Sedlbauer: PCI base adr %#x\n", + cs->hw.sedl.cfg_reg); + if (sub_id != PCI_SUB_ID_SEDLBAUER) { + printk(KERN_ERR "Sedlbauer: unknown sub id %#x\n", sub_id); + return(0); + } + if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PYRAMID) { + cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; + cs->subtyp = SEDL_SPEEDFAX_PYRAMID; + } else if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PCI) { + cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; + cs->subtyp = SEDL_SPEEDFAX_PCI; + } else if (sub_vendor_id == PCI_SUBVENDOR_HST_SAPHIR3) { + cs->hw.sedl.chip = SEDL_CHIP_IPAC; + cs->subtyp = HST_SAPHIR3; + } else if (sub_vendor_id == PCI_SUBVENDOR_SEDLBAUER_PCI) { + cs->hw.sedl.chip = SEDL_CHIP_IPAC; + cs->subtyp = SEDL_SPEED_PCI; + } else { + printk(KERN_ERR "Sedlbauer: unknown sub vendor id %#x\n", + sub_vendor_id); + return(0); + } + + cs->hw.sedl.reset_on = SEDL_ISAR_PCI_ISAR_RESET_ON; + cs->hw.sedl.reset_off = SEDL_ISAR_PCI_ISAR_RESET_OFF; + byteout(cs->hw.sedl.cfg_reg, 0xff); + byteout(cs->hw.sedl.cfg_reg, 0x00); + byteout(cs->hw.sedl.cfg_reg+ 2, 0xdd); + byteout(cs->hw.sedl.cfg_reg+ 5, 0); /* disable all IRQ */ + byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_on); + mdelay(2); + byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off); + mdelay(10); + + return (1); +} + +#else + +static int __devinit +setup_sedlbauer_pci(struct IsdnCard *card) +{ + return (1); +} + +#endif /* CONFIG_PCI */ int __devinit setup_sedlbauer(struct IsdnCard *card) { - int bytecnt, ver, val; + int bytecnt = 8, ver, val, rc; struct IsdnCardState *cs = card->cs; char tmp[64]; - u16 sub_vendor_id, sub_id; strcpy(tmp, Sedlbauer_revision); printk(KERN_INFO "HiSax: Sedlbauer driver Rev. %s\n", HiSax_getrev(tmp)); @@ -569,124 +710,21 @@ setup_sedlbauer(struct IsdnCard *card) bytecnt = 16; } } else { -#ifdef __ISAPNP__ - if (isapnp_present()) { - struct pnp_dev *pnp_d; - while(ipid->card_vendor) { - if ((pnp_c = pnp_find_card(ipid->card_vendor, - ipid->card_device, pnp_c))) { - pnp_d = NULL; - if ((pnp_d = pnp_find_dev(pnp_c, - ipid->vendor, ipid->function, pnp_d))) { - int err; - - printk(KERN_INFO "HiSax: %s detected\n", - (char *)ipid->driver_data); - pnp_disable_dev(pnp_d); - err = pnp_activate_dev(pnp_d); - if (err<0) { - printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __FUNCTION__, err); - return(0); - } - card->para[1] = pnp_port_start(pnp_d, 0); - card->para[0] = pnp_irq(pnp_d, 0); - - if (!card->para[0] || !card->para[1]) { - printk(KERN_ERR "Sedlbauer PnP:some resources are missing %ld/%lx\n", - card->para[0], card->para[1]); - pnp_disable_dev(pnp_d); - return(0); - } - cs->hw.sedl.cfg_reg = card->para[1]; - cs->irq = card->para[0]; - if (ipid->function == ISAPNP_FUNCTION(0x2)) { - cs->subtyp = SEDL_SPEED_FAX; - cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; - bytecnt = 16; - } else { - cs->subtyp = SEDL_SPEED_CARD_WIN; - cs->hw.sedl.chip = SEDL_CHIP_TEST; - } - goto ready; - } else { - printk(KERN_ERR "Sedlbauer PnP: PnP error card found, no device\n"); - return(0); - } - } - ipid++; - pnp_c = NULL; - } - if (!ipid->card_vendor) { - printk(KERN_INFO "Sedlbauer PnP: no ISAPnP card found\n"); - } - } -#endif -/* Probe for Sedlbauer speed pci */ -#ifdef CONFIG_PCI - if ((dev_sedl = pci_find_device(PCI_VENDOR_ID_TIGERJET, - PCI_DEVICE_ID_TIGERJET_100, dev_sedl))) { - if (pci_enable_device(dev_sedl)) - return(0); - cs->irq = dev_sedl->irq; - if (!cs->irq) { - printk(KERN_WARNING "Sedlbauer: No IRQ for PCI card found\n"); - return(0); - } - cs->hw.sedl.cfg_reg = pci_resource_start(dev_sedl, 0); - } else { - printk(KERN_WARNING "Sedlbauer: No PCI card found\n"); - return(0); - } - cs->irq_flags |= IRQF_SHARED; - cs->hw.sedl.bus = SEDL_BUS_PCI; - sub_vendor_id = dev_sedl->subsystem_vendor; - sub_id = dev_sedl->subsystem_device; - printk(KERN_INFO "Sedlbauer: PCI subvendor:%x subid %x\n", - sub_vendor_id, sub_id); - printk(KERN_INFO "Sedlbauer: PCI base adr %#x\n", - cs->hw.sedl.cfg_reg); - if (sub_id != PCI_SUB_ID_SEDLBAUER) { - printk(KERN_ERR "Sedlbauer: unknown sub id %#x\n", sub_id); - return(0); - } - if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PYRAMID) { - cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; - cs->subtyp = SEDL_SPEEDFAX_PYRAMID; - } else if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PCI) { - cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; - cs->subtyp = SEDL_SPEEDFAX_PCI; - } else if (sub_vendor_id == PCI_SUBVENDOR_HST_SAPHIR3) { - cs->hw.sedl.chip = SEDL_CHIP_IPAC; - cs->subtyp = HST_SAPHIR3; - } else if (sub_vendor_id == PCI_SUBVENDOR_SEDLBAUER_PCI) { - cs->hw.sedl.chip = SEDL_CHIP_IPAC; - cs->subtyp = SEDL_SPEED_PCI; - } else { - printk(KERN_ERR "Sedlbauer: unknown sub vendor id %#x\n", - sub_vendor_id); - return(0); - } + rc = setup_sedlbauer_isapnp(card, &bytecnt); + if (!rc) + return (0); + if (rc > 0) + goto ready; + + /* Probe for Sedlbauer speed pci */ + rc = setup_sedlbauer_pci(card); + if (!rc) + return (0); + bytecnt = 256; - cs->hw.sedl.reset_on = SEDL_ISAR_PCI_ISAR_RESET_ON; - cs->hw.sedl.reset_off = SEDL_ISAR_PCI_ISAR_RESET_OFF; - byteout(cs->hw.sedl.cfg_reg, 0xff); - byteout(cs->hw.sedl.cfg_reg, 0x00); - byteout(cs->hw.sedl.cfg_reg+ 2, 0xdd); - byteout(cs->hw.sedl.cfg_reg+ 5, 0); /* disable all IRQ */ - byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_on); - mdelay(2); - byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off); - mdelay(10); -#else - printk(KERN_WARNING "Sedlbauer: NO_PCI_BIOS\n"); - return (0); -#endif /* CONFIG_PCI */ } -#ifdef __ISAPNP__ ready: -#endif /* In case of the sedlbauer pcmcia card, this region is in use, * reserved for us by the card manager. So we do not check it -- cgit v1.2.3-70-g09d2 From 4b5a9b3d8e857249f2670f4419ce764be02e11db Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 3 Oct 2007 15:47:00 -0400 Subject: [ISDN] HiSax diva: split setup into three smaller functions Just code movement, and the glue to call the new functions. Preparation for hotplug APIs. Signed-off-by: Jeff Garzik --- drivers/isdn/hisax/diva.c | 513 ++++++++++++++++++++++++++-------------------- 1 file changed, 294 insertions(+), 219 deletions(-) (limited to 'drivers') diff --git a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c index 6eebeb441bf..82674507874 100644 --- a/drivers/isdn/hisax/diva.c +++ b/drivers/isdn/hisax/diva.c @@ -25,8 +25,6 @@ #include #include -extern const char *CardType[]; - static const char *Diva_revision = "$Revision: 1.33.2.6 $"; #define byteout(addr,val) outb(val,addr) @@ -906,225 +904,15 @@ Diva_card_msg(struct IsdnCardState *cs, int mt, void *arg) return(0); } -static struct pci_dev *dev_diva __devinitdata = NULL; -static struct pci_dev *dev_diva_u __devinitdata = NULL; -static struct pci_dev *dev_diva201 __devinitdata = NULL; -static struct pci_dev *dev_diva202 __devinitdata = NULL; - -#ifdef __ISAPNP__ -static struct isapnp_device_id diva_ids[] __devinitdata = { - { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51), - ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51), - (unsigned long) "Diva picola" }, - { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51), - ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x51), - (unsigned long) "Diva picola" }, - { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71), - ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71), - (unsigned long) "Diva 2.0" }, - { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71), - ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x71), - (unsigned long) "Diva 2.0" }, - { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1), - ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1), - (unsigned long) "Diva 2.01" }, - { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1), - ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0xA1), - (unsigned long) "Diva 2.01" }, - { 0, } -}; - -static struct isapnp_device_id *ipid __devinitdata = &diva_ids[0]; -static struct pnp_card *pnp_c __devinitdata = NULL; -#endif - - -int __devinit -setup_diva(struct IsdnCard *card) +static int __devinit setup_diva_common(struct IsdnCardState *cs) { - int bytecnt = 8; + int bytecnt; u_char val; - struct IsdnCardState *cs = card->cs; - char tmp[64]; - - strcpy(tmp, Diva_revision); - printk(KERN_INFO "HiSax: Eicon.Diehl Diva driver Rev. %s\n", HiSax_getrev(tmp)); - if (cs->typ != ISDN_CTYPE_DIEHLDIVA) - return(0); - cs->hw.diva.status = 0; - if (card->para[1]) { - cs->hw.diva.ctrl_reg = 0; - cs->hw.diva.cfg_reg = card->para[1]; - val = readreg(cs->hw.diva.cfg_reg + DIVA_IPAC_ADR, - cs->hw.diva.cfg_reg + DIVA_IPAC_DATA, IPAC_ID); - printk(KERN_INFO "Diva: IPAC version %x\n", val); - if ((val == 1) || (val==2)) { - cs->subtyp = DIVA_IPAC_ISA; - cs->hw.diva.ctrl = 0; - cs->hw.diva.isac = card->para[1] + DIVA_IPAC_DATA; - cs->hw.diva.hscx = card->para[1] + DIVA_IPAC_DATA; - cs->hw.diva.isac_adr = card->para[1] + DIVA_IPAC_ADR; - cs->hw.diva.hscx_adr = card->para[1] + DIVA_IPAC_ADR; - test_and_set_bit(HW_IPAC, &cs->HW_Flags); - } else { - cs->subtyp = DIVA_ISA; - cs->hw.diva.ctrl = card->para[1] + DIVA_ISA_CTRL; - cs->hw.diva.isac = card->para[1] + DIVA_ISA_ISAC_DATA; - cs->hw.diva.hscx = card->para[1] + DIVA_HSCX_DATA; - cs->hw.diva.isac_adr = card->para[1] + DIVA_ISA_ISAC_ADR; - cs->hw.diva.hscx_adr = card->para[1] + DIVA_HSCX_ADR; - } - cs->irq = card->para[0]; - } else { -#ifdef __ISAPNP__ - if (isapnp_present()) { - struct pnp_dev *pnp_d; - while(ipid->card_vendor) { - if ((pnp_c = pnp_find_card(ipid->card_vendor, - ipid->card_device, pnp_c))) { - pnp_d = NULL; - if ((pnp_d = pnp_find_dev(pnp_c, - ipid->vendor, ipid->function, pnp_d))) { - int err; - - printk(KERN_INFO "HiSax: %s detected\n", - (char *)ipid->driver_data); - pnp_disable_dev(pnp_d); - err = pnp_activate_dev(pnp_d); - if (err<0) { - printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __FUNCTION__, err); - return(0); - } - card->para[1] = pnp_port_start(pnp_d, 0); - card->para[0] = pnp_irq(pnp_d, 0); - if (!card->para[0] || !card->para[1]) { - printk(KERN_ERR "Diva PnP:some resources are missing %ld/%lx\n", - card->para[0], card->para[1]); - pnp_disable_dev(pnp_d); - return(0); - } - cs->hw.diva.cfg_reg = card->para[1]; - cs->irq = card->para[0]; - if (ipid->function == ISAPNP_FUNCTION(0xA1)) { - cs->subtyp = DIVA_IPAC_ISA; - cs->hw.diva.ctrl = 0; - cs->hw.diva.isac = - card->para[1] + DIVA_IPAC_DATA; - cs->hw.diva.hscx = - card->para[1] + DIVA_IPAC_DATA; - cs->hw.diva.isac_adr = - card->para[1] + DIVA_IPAC_ADR; - cs->hw.diva.hscx_adr = - card->para[1] + DIVA_IPAC_ADR; - test_and_set_bit(HW_IPAC, &cs->HW_Flags); - } else { - cs->subtyp = DIVA_ISA; - cs->hw.diva.ctrl = - card->para[1] + DIVA_ISA_CTRL; - cs->hw.diva.isac = - card->para[1] + DIVA_ISA_ISAC_DATA; - cs->hw.diva.hscx = - card->para[1] + DIVA_HSCX_DATA; - cs->hw.diva.isac_adr = - card->para[1] + DIVA_ISA_ISAC_ADR; - cs->hw.diva.hscx_adr = - card->para[1] + DIVA_HSCX_ADR; - } - goto ready; - } else { - printk(KERN_ERR "Diva PnP: PnP error card found, no device\n"); - return(0); - } - } - ipid++; - pnp_c=NULL; - } - if (!ipid->card_vendor) { - printk(KERN_INFO "Diva PnP: no ISAPnP card found\n"); - } - } -#endif -#ifdef CONFIG_PCI - cs->subtyp = 0; - if ((dev_diva = pci_find_device(PCI_VENDOR_ID_EICON, - PCI_DEVICE_ID_EICON_DIVA20, dev_diva))) { - if (pci_enable_device(dev_diva)) - return(0); - cs->subtyp = DIVA_PCI; - cs->irq = dev_diva->irq; - cs->hw.diva.cfg_reg = pci_resource_start(dev_diva, 2); - } else if ((dev_diva_u = pci_find_device(PCI_VENDOR_ID_EICON, - PCI_DEVICE_ID_EICON_DIVA20_U, dev_diva_u))) { - if (pci_enable_device(dev_diva_u)) - return(0); - cs->subtyp = DIVA_PCI; - cs->irq = dev_diva_u->irq; - cs->hw.diva.cfg_reg = pci_resource_start(dev_diva_u, 2); - } else if ((dev_diva201 = pci_find_device(PCI_VENDOR_ID_EICON, - PCI_DEVICE_ID_EICON_DIVA201, dev_diva201))) { - if (pci_enable_device(dev_diva201)) - return(0); - cs->subtyp = DIVA_IPAC_PCI; - cs->irq = dev_diva201->irq; - cs->hw.diva.pci_cfg = - (ulong) ioremap(pci_resource_start(dev_diva201, 0), 4096); - cs->hw.diva.cfg_reg = - (ulong) ioremap(pci_resource_start(dev_diva201, 1), 4096); - } else if ((dev_diva202 = pci_find_device(PCI_VENDOR_ID_EICON, - PCI_DEVICE_ID_EICON_DIVA202, dev_diva202))) { - if (pci_enable_device(dev_diva202)) - return(0); - cs->subtyp = DIVA_IPACX_PCI; - cs->irq = dev_diva202->irq; - cs->hw.diva.pci_cfg = - (ulong) ioremap(pci_resource_start(dev_diva202, 0), 4096); - cs->hw.diva.cfg_reg = - (ulong) ioremap(pci_resource_start(dev_diva202, 1), 4096); - } else { - printk(KERN_WARNING "Diva: No PCI card found\n"); - return(0); - } - - if (!cs->irq) { - printk(KERN_WARNING "Diva: No IRQ for PCI card found\n"); - iounmap_diva(cs); - return(0); - } - - if (!cs->hw.diva.cfg_reg) { - printk(KERN_WARNING "Diva: No IO-Adr for PCI card found\n"); - iounmap_diva(cs); - return(0); - } - cs->irq_flags |= IRQF_SHARED; -#else - printk(KERN_WARNING "Diva: cfgreg 0 and NO_PCI_BIOS\n"); - printk(KERN_WARNING "Diva: unable to config DIVA PCI\n"); - return (0); -#endif /* CONFIG_PCI */ - if ((cs->subtyp == DIVA_IPAC_PCI) || - (cs->subtyp == DIVA_IPACX_PCI) ) { - cs->hw.diva.ctrl = 0; - cs->hw.diva.isac = 0; - cs->hw.diva.hscx = 0; - cs->hw.diva.isac_adr = 0; - cs->hw.diva.hscx_adr = 0; - test_and_set_bit(HW_IPAC, &cs->HW_Flags); - bytecnt = 0; - } else { - cs->hw.diva.ctrl = cs->hw.diva.cfg_reg + DIVA_PCI_CTRL; - cs->hw.diva.isac = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_DATA; - cs->hw.diva.hscx = cs->hw.diva.cfg_reg + DIVA_HSCX_DATA; - cs->hw.diva.isac_adr = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_ADR; - cs->hw.diva.hscx_adr = cs->hw.diva.cfg_reg + DIVA_HSCX_ADR; - bytecnt = 32; - } - } -#ifdef __ISAPNP__ -ready: -#endif + if ((cs->subtyp == DIVA_ISA) || (cs->subtyp == DIVA_IPAC_ISA)) + bytecnt = 8; + else + bytecnt = 32; printk(KERN_INFO "Diva: %s card configured at %#lx IRQ %d\n", @@ -1145,7 +933,7 @@ ready: if (!request_region(cs->hw.diva.cfg_reg, bytecnt, "diva isdn")) { printk(KERN_WARNING "HiSax: %s config port %lx-%lx already in use\n", - CardType[card->typ], + "diva", cs->hw.diva.cfg_reg, cs->hw.diva.cfg_reg + bytecnt); iounmap_diva(cs); @@ -1206,3 +994,290 @@ ready: } return (1); } + +#ifdef CONFIG_ISA + +static int __devinit setup_diva_isa(struct IsdnCard *card) +{ + struct IsdnCardState *cs = card->cs; + u_char val; + + if (!card->para[1]) + return (-1); /* card not found; continue search */ + + cs->hw.diva.ctrl_reg = 0; + cs->hw.diva.cfg_reg = card->para[1]; + val = readreg(cs->hw.diva.cfg_reg + DIVA_IPAC_ADR, + cs->hw.diva.cfg_reg + DIVA_IPAC_DATA, IPAC_ID); + printk(KERN_INFO "Diva: IPAC version %x\n", val); + if ((val == 1) || (val==2)) { + cs->subtyp = DIVA_IPAC_ISA; + cs->hw.diva.ctrl = 0; + cs->hw.diva.isac = card->para[1] + DIVA_IPAC_DATA; + cs->hw.diva.hscx = card->para[1] + DIVA_IPAC_DATA; + cs->hw.diva.isac_adr = card->para[1] + DIVA_IPAC_ADR; + cs->hw.diva.hscx_adr = card->para[1] + DIVA_IPAC_ADR; + test_and_set_bit(HW_IPAC, &cs->HW_Flags); + } else { + cs->subtyp = DIVA_ISA; + cs->hw.diva.ctrl = card->para[1] + DIVA_ISA_CTRL; + cs->hw.diva.isac = card->para[1] + DIVA_ISA_ISAC_DATA; + cs->hw.diva.hscx = card->para[1] + DIVA_HSCX_DATA; + cs->hw.diva.isac_adr = card->para[1] + DIVA_ISA_ISAC_ADR; + cs->hw.diva.hscx_adr = card->para[1] + DIVA_HSCX_ADR; + } + cs->irq = card->para[0]; + + return (1); /* card found */ +} + +#else /* if !CONFIG_ISA */ + +static int __devinit setup_diva_isa(struct IsdnCard *card) +{ + return (-1); /* card not found; continue search */ +} + +#endif /* CONFIG_ISA */ + +#ifdef __ISAPNP__ +static struct isapnp_device_id diva_ids[] __devinitdata = { + { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51), + ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51), + (unsigned long) "Diva picola" }, + { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51), + ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x51), + (unsigned long) "Diva picola" }, + { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71), + ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71), + (unsigned long) "Diva 2.0" }, + { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71), + ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x71), + (unsigned long) "Diva 2.0" }, + { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1), + ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1), + (unsigned long) "Diva 2.01" }, + { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1), + ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0xA1), + (unsigned long) "Diva 2.01" }, + { 0, } +}; + +static struct isapnp_device_id *ipid __devinitdata = &diva_ids[0]; +static struct pnp_card *pnp_c __devinitdata = NULL; + +static int __devinit setup_diva_isapnp(struct IsdnCard *card) +{ + struct IsdnCardState *cs = card->cs; + struct pnp_dev *pnp_d; + + if (!isapnp_present()) + return (-1); /* card not found; continue search */ + + while(ipid->card_vendor) { + if ((pnp_c = pnp_find_card(ipid->card_vendor, + ipid->card_device, pnp_c))) { + pnp_d = NULL; + if ((pnp_d = pnp_find_dev(pnp_c, + ipid->vendor, ipid->function, pnp_d))) { + int err; + + printk(KERN_INFO "HiSax: %s detected\n", + (char *)ipid->driver_data); + pnp_disable_dev(pnp_d); + err = pnp_activate_dev(pnp_d); + if (err<0) { + printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", + __FUNCTION__, err); + return(0); + } + card->para[1] = pnp_port_start(pnp_d, 0); + card->para[0] = pnp_irq(pnp_d, 0); + if (!card->para[0] || !card->para[1]) { + printk(KERN_ERR "Diva PnP:some resources are missing %ld/%lx\n", + card->para[0], card->para[1]); + pnp_disable_dev(pnp_d); + return(0); + } + cs->hw.diva.cfg_reg = card->para[1]; + cs->irq = card->para[0]; + if (ipid->function == ISAPNP_FUNCTION(0xA1)) { + cs->subtyp = DIVA_IPAC_ISA; + cs->hw.diva.ctrl = 0; + cs->hw.diva.isac = + card->para[1] + DIVA_IPAC_DATA; + cs->hw.diva.hscx = + card->para[1] + DIVA_IPAC_DATA; + cs->hw.diva.isac_adr = + card->para[1] + DIVA_IPAC_ADR; + cs->hw.diva.hscx_adr = + card->para[1] + DIVA_IPAC_ADR; + test_and_set_bit(HW_IPAC, &cs->HW_Flags); + } else { + cs->subtyp = DIVA_ISA; + cs->hw.diva.ctrl = + card->para[1] + DIVA_ISA_CTRL; + cs->hw.diva.isac = + card->para[1] + DIVA_ISA_ISAC_DATA; + cs->hw.diva.hscx = + card->para[1] + DIVA_HSCX_DATA; + cs->hw.diva.isac_adr = + card->para[1] + DIVA_ISA_ISAC_ADR; + cs->hw.diva.hscx_adr = + card->para[1] + DIVA_HSCX_ADR; + } + return (1); /* card found */ + } else { + printk(KERN_ERR "Diva PnP: PnP error card found, no device\n"); + return(0); + } + } + ipid++; + pnp_c=NULL; + } + + return (-1); /* card not found; continue search */ +} + +#else /* if !ISAPNP */ + +static int __devinit setup_diva_isapnp(struct IsdnCard *card) +{ + return (-1); /* card not found; continue search */ +} + +#endif /* ISAPNP */ + +#ifdef CONFIG_PCI +static struct pci_dev *dev_diva __devinitdata = NULL; +static struct pci_dev *dev_diva_u __devinitdata = NULL; +static struct pci_dev *dev_diva201 __devinitdata = NULL; +static struct pci_dev *dev_diva202 __devinitdata = NULL; + +static int __devinit setup_diva_pci(struct IsdnCard *card) +{ + struct IsdnCardState *cs = card->cs; + + cs->subtyp = 0; + if ((dev_diva = pci_find_device(PCI_VENDOR_ID_EICON, + PCI_DEVICE_ID_EICON_DIVA20, dev_diva))) { + if (pci_enable_device(dev_diva)) + return(0); + cs->subtyp = DIVA_PCI; + cs->irq = dev_diva->irq; + cs->hw.diva.cfg_reg = pci_resource_start(dev_diva, 2); + } else if ((dev_diva_u = pci_find_device(PCI_VENDOR_ID_EICON, + PCI_DEVICE_ID_EICON_DIVA20_U, dev_diva_u))) { + if (pci_enable_device(dev_diva_u)) + return(0); + cs->subtyp = DIVA_PCI; + cs->irq = dev_diva_u->irq; + cs->hw.diva.cfg_reg = pci_resource_start(dev_diva_u, 2); + } else if ((dev_diva201 = pci_find_device(PCI_VENDOR_ID_EICON, + PCI_DEVICE_ID_EICON_DIVA201, dev_diva201))) { + if (pci_enable_device(dev_diva201)) + return(0); + cs->subtyp = DIVA_IPAC_PCI; + cs->irq = dev_diva201->irq; + cs->hw.diva.pci_cfg = + (ulong) ioremap(pci_resource_start(dev_diva201, 0), 4096); + cs->hw.diva.cfg_reg = + (ulong) ioremap(pci_resource_start(dev_diva201, 1), 4096); + } else if ((dev_diva202 = pci_find_device(PCI_VENDOR_ID_EICON, + PCI_DEVICE_ID_EICON_DIVA202, dev_diva202))) { + if (pci_enable_device(dev_diva202)) + return(0); + cs->subtyp = DIVA_IPACX_PCI; + cs->irq = dev_diva202->irq; + cs->hw.diva.pci_cfg = + (ulong) ioremap(pci_resource_start(dev_diva202, 0), 4096); + cs->hw.diva.cfg_reg = + (ulong) ioremap(pci_resource_start(dev_diva202, 1), 4096); + } else { + return (-1); /* card not found; continue search */ + } + + if (!cs->irq) { + printk(KERN_WARNING "Diva: No IRQ for PCI card found\n"); + iounmap_diva(cs); + return(0); + } + + if (!cs->hw.diva.cfg_reg) { + printk(KERN_WARNING "Diva: No IO-Adr for PCI card found\n"); + iounmap_diva(cs); + return(0); + } + cs->irq_flags |= IRQF_SHARED; + + if ((cs->subtyp == DIVA_IPAC_PCI) || + (cs->subtyp == DIVA_IPACX_PCI) ) { + cs->hw.diva.ctrl = 0; + cs->hw.diva.isac = 0; + cs->hw.diva.hscx = 0; + cs->hw.diva.isac_adr = 0; + cs->hw.diva.hscx_adr = 0; + test_and_set_bit(HW_IPAC, &cs->HW_Flags); + } else { + cs->hw.diva.ctrl = cs->hw.diva.cfg_reg + DIVA_PCI_CTRL; + cs->hw.diva.isac = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_DATA; + cs->hw.diva.hscx = cs->hw.diva.cfg_reg + DIVA_HSCX_DATA; + cs->hw.diva.isac_adr = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_ADR; + cs->hw.diva.hscx_adr = cs->hw.diva.cfg_reg + DIVA_HSCX_ADR; + } + + return (1); /* card found */ +} + +#else /* if !CONFIG_PCI */ + +static int __devinit setup_diva_pci(struct IsdnCard *card) +{ + return (-1); /* card not found; continue search */ +} + +#endif /* CONFIG_PCI */ + +int __devinit +setup_diva(struct IsdnCard *card) +{ + int rc, have_card = 0; + struct IsdnCardState *cs = card->cs; + char tmp[64]; + + strcpy(tmp, Diva_revision); + printk(KERN_INFO "HiSax: Eicon.Diehl Diva driver Rev. %s\n", HiSax_getrev(tmp)); + if (cs->typ != ISDN_CTYPE_DIEHLDIVA) + return(0); + cs->hw.diva.status = 0; + + rc = setup_diva_isa(card); + if (!rc) + return rc; + if (rc > 0) { + have_card = 1; + goto ready; + } + + rc = setup_diva_isapnp(card); + if (!rc) + return rc; + if (rc > 0) { + have_card = 1; + goto ready; + } + + rc = setup_diva_pci(card); + if (!rc) + return rc; + if (rc > 0) + have_card = 1; + +ready: + if (!have_card) { + printk(KERN_WARNING "Diva: No ISA, ISAPNP or PCI card found\n"); + return(0); + } + + return setup_diva_common(card->cs); +} -- cgit v1.2.3-70-g09d2 From 7c9f4e3aaae020fc674f52393cbac1bdb648bf90 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Fri, 12 Oct 2007 16:11:13 +0200 Subject: [S390] cio: rename css to channel_subsystems Rename css[] to channel_subsystems[] to avoid name clashes. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky Signed-off-by: Heiko Carstens --- drivers/s390/cio/chp.c | 14 ++++----- drivers/s390/cio/css.c | 69 ++++++++++++++++++++++++------------------- drivers/s390/cio/css.h | 2 +- drivers/s390/cio/device_fsm.c | 3 +- 4 files changed, 49 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c index 920dd71e643..8ce4ff95cc9 100644 --- a/drivers/s390/cio/chp.c +++ b/drivers/s390/cio/chp.c @@ -55,7 +55,7 @@ static wait_queue_head_t cfg_wait_queue; /* Return channel_path struct for given chpid. */ static inline struct channel_path *chpid_to_chp(struct chp_id chpid) { - return css[chpid.cssid]->chps[chpid.id]; + return channel_subsystems[chpid.cssid]->chps[chpid.id]; } /* Set vary state for given chpid. */ @@ -395,7 +395,7 @@ int chp_new(struct chp_id chpid) /* fill in status, etc. */ chp->chpid = chpid; chp->state = 1; - chp->dev.parent = &css[chpid.cssid]->device; + chp->dev.parent = &channel_subsystems[chpid.cssid]->device; chp->dev.release = chp_release; snprintf(chp->dev.bus_id, BUS_ID_SIZE, "chp%x.%02x", chpid.cssid, chpid.id); @@ -430,18 +430,18 @@ int chp_new(struct chp_id chpid) device_unregister(&chp->dev); goto out_free; } - mutex_lock(&css[chpid.cssid]->mutex); - if (css[chpid.cssid]->cm_enabled) { + mutex_lock(&channel_subsystems[chpid.cssid]->mutex); + if (channel_subsystems[chpid.cssid]->cm_enabled) { ret = chp_add_cmg_attr(chp); if (ret) { sysfs_remove_group(&chp->dev.kobj, &chp_attr_group); device_unregister(&chp->dev); - mutex_unlock(&css[chpid.cssid]->mutex); + mutex_unlock(&channel_subsystems[chpid.cssid]->mutex); goto out_free; } } - css[chpid.cssid]->chps[chpid.id] = chp; - mutex_unlock(&css[chpid.cssid]->mutex); + channel_subsystems[chpid.cssid]->chps[chpid.id] = chp; + mutex_unlock(&channel_subsystems[chpid.cssid]->mutex); return ret; out_free: kfree(chp); diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 5635e656c1a..08f6e7b6c99 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -27,7 +27,7 @@ int css_init_done = 0; static int need_reprobe = 0; static int max_ssid = 0; -struct channel_subsystem *css[__MAX_CSSID + 1]; +struct channel_subsystem *channel_subsystems[__MAX_CSSID + 1]; int css_characteristics_avail = 0; @@ -177,7 +177,7 @@ static int css_register_subchannel(struct subchannel *sch) int ret; /* Initialize the subchannel structure */ - sch->dev.parent = &css[0]->device; + sch->dev.parent = &channel_subsystems[0]->device; sch->dev.bus = &css_bus_type; sch->dev.release = &css_subchannel_release; sch->dev.groups = subch_attr_groups; @@ -606,27 +606,29 @@ static int __init setup_css(int nr) { u32 tod_high; int ret; + struct channel_subsystem *css; - memset(css[nr], 0, sizeof(struct channel_subsystem)); - css[nr]->pseudo_subchannel = - kzalloc(sizeof(*css[nr]->pseudo_subchannel), GFP_KERNEL); - if (!css[nr]->pseudo_subchannel) + css = channel_subsystems[nr]; + memset(css, 0, sizeof(struct channel_subsystem)); + css->pseudo_subchannel = + kzalloc(sizeof(*css->pseudo_subchannel), GFP_KERNEL); + if (!css->pseudo_subchannel) return -ENOMEM; - css[nr]->pseudo_subchannel->dev.parent = &css[nr]->device; - css[nr]->pseudo_subchannel->dev.release = css_subchannel_release; - sprintf(css[nr]->pseudo_subchannel->dev.bus_id, "defunct"); - ret = cio_create_sch_lock(css[nr]->pseudo_subchannel); + css->pseudo_subchannel->dev.parent = &css->device; + css->pseudo_subchannel->dev.release = css_subchannel_release; + sprintf(css->pseudo_subchannel->dev.bus_id, "defunct"); + ret = cio_create_sch_lock(css->pseudo_subchannel); if (ret) { - kfree(css[nr]->pseudo_subchannel); + kfree(css->pseudo_subchannel); return ret; } - mutex_init(&css[nr]->mutex); - css[nr]->valid = 1; - css[nr]->cssid = nr; - sprintf(css[nr]->device.bus_id, "css%x", nr); - css[nr]->device.release = channel_subsystem_release; + mutex_init(&css->mutex); + css->valid = 1; + css->cssid = nr; + sprintf(css->device.bus_id, "css%x", nr); + css->device.release = channel_subsystem_release; tod_high = (u32) (get_clock() >> 32); - css_generate_pgid(css[nr], tod_high); + css_generate_pgid(css, tod_high); return 0; } @@ -670,25 +672,28 @@ init_channel_subsystem (void) } /* Setup css structure. */ for (i = 0; i <= __MAX_CSSID; i++) { - css[i] = kmalloc(sizeof(struct channel_subsystem), GFP_KERNEL); - if (!css[i]) { + struct channel_subsystem *css; + + css = kmalloc(sizeof(struct channel_subsystem), GFP_KERNEL); + if (!css) { ret = -ENOMEM; goto out_unregister; } + channel_subsystems[i] = css; ret = setup_css(i); if (ret) goto out_free; - ret = device_register(&css[i]->device); + ret = device_register(&css->device); if (ret) goto out_free_all; if (css_characteristics_avail && css_chsc_characteristics.secm) { - ret = device_create_file(&css[i]->device, + ret = device_create_file(&css->device, &dev_attr_cm_enable); if (ret) goto out_device; } - ret = device_register(&css[i]->pseudo_subchannel->dev); + ret = device_register(&css->pseudo_subchannel->dev); if (ret) goto out_file; } @@ -699,22 +704,26 @@ init_channel_subsystem (void) for_each_subchannel(__init_channel_subsystem, NULL); return 0; out_file: - device_remove_file(&css[i]->device, &dev_attr_cm_enable); + device_remove_file(&channel_subsystems[i]->device, + &dev_attr_cm_enable); out_device: - device_unregister(&css[i]->device); + device_unregister(&channel_subsystems[i]->device); out_free_all: - kfree(css[i]->pseudo_subchannel->lock); - kfree(css[i]->pseudo_subchannel); + kfree(channel_subsystems[i]->pseudo_subchannel->lock); + kfree(channel_subsystems[i]->pseudo_subchannel); out_free: - kfree(css[i]); + kfree(channel_subsystems[i]); out_unregister: while (i > 0) { + struct channel_subsystem *css; + i--; - device_unregister(&css[i]->pseudo_subchannel->dev); + css = channel_subsystems[i]; + device_unregister(&css->pseudo_subchannel->dev); if (css_characteristics_avail && css_chsc_characteristics.secm) - device_remove_file(&css[i]->device, + device_remove_file(&css->device, &dev_attr_cm_enable); - device_unregister(&css[i]->device); + device_unregister(&css->device); } out_bus: bus_unregister(&css_bus_type); diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h index 5d65e83ca66..f290c5c0f27 100644 --- a/drivers/s390/cio/css.h +++ b/drivers/s390/cio/css.h @@ -167,7 +167,7 @@ struct channel_subsystem { #define to_css(dev) container_of(dev, struct channel_subsystem, device) extern struct bus_type css_bus_type; -extern struct channel_subsystem *css[]; +extern struct channel_subsystem *channel_subsystems[]; /* Some helper functions for disconnected state. */ int device_is_disconnected(struct subchannel *); diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index 8633dc53769..f772ef0a4f2 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -446,7 +446,8 @@ static void __ccw_device_get_common_pgid(struct ccw_device *cdev) if (cdev->private->pgid[last].inf.ps.state1 == SNID_STATE1_RESET) /* No previous pgid found */ - memcpy(&cdev->private->pgid[0], &css[0]->global_pgid, + memcpy(&cdev->private->pgid[0], + &channel_subsystems[0]->global_pgid, sizeof(struct pgid)); else /* Use existing pgid */ -- cgit v1.2.3-70-g09d2 From fbf9772b8e7917f85f35913b30788c74ea34cad5 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Fri, 12 Oct 2007 16:11:14 +0200 Subject: [S390] cio: remove subchannel_add_files() subchannel_add_files() no longer exists, remove from header. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky Signed-off-by: Heiko Carstens --- drivers/s390/cio/css.h | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h index f290c5c0f27..81215ef3243 100644 --- a/drivers/s390/cio/css.h +++ b/drivers/s390/cio/css.h @@ -191,6 +191,5 @@ int sch_is_pseudo_sch(struct subchannel *); extern struct workqueue_struct *slow_path_wq; -int subchannel_add_files (struct device *); extern struct attribute_group *subch_attr_groups[]; #endif -- cgit v1.2.3-70-g09d2 From fc5019c5c7067bcea1e49fe9cd5190285f0c8927 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Fri, 12 Oct 2007 16:11:15 +0200 Subject: [S390] cio: Fix some coding style issues in cmf. Fix some formatting and correct a comment. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky Signed-off-by: Heiko Carstens --- drivers/s390/cio/cmf.c | 141 +++++++++++++++++++++++++++---------------------- include/asm-s390/cmb.h | 8 +-- 2 files changed, 81 insertions(+), 68 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c index 34a796913b0..ff1e442d4b0 100644 --- a/drivers/s390/cio/cmf.c +++ b/drivers/s390/cio/cmf.c @@ -45,7 +45,8 @@ #include "ioasm.h" #include "chsc.h" -/* parameter to enable cmf during boot, possible uses are: +/* + * parameter to enable cmf during boot, possible uses are: * "s390cmf" -- enable cmf and allocate 2 MB of ram so measuring can be * used on any subchannel * "s390cmf=" -- enable cmf and allocate enough memory to measure @@ -84,6 +85,7 @@ enum cmb_format { CMF_EXTENDED, CMF_AUTODETECT = -1, }; + /** * format - actual format for all measurement blocks * @@ -111,13 +113,13 @@ module_param(format, bool, 0444); * @align: align an allocated block so that the hardware can use it */ struct cmb_operations { - int (*alloc) (struct ccw_device*); - void(*free) (struct ccw_device*); - int (*set) (struct ccw_device*, u32); - u64 (*read) (struct ccw_device*, int); - int (*readall)(struct ccw_device*, struct cmbdata *); - void (*reset) (struct ccw_device*); - void * (*align) (void *); + int (*alloc) (struct ccw_device *); + void (*free) (struct ccw_device *); + int (*set) (struct ccw_device *, u32); + u64 (*read) (struct ccw_device *, int); + int (*readall)(struct ccw_device *, struct cmbdata *); + void (*reset) (struct ccw_device *); + void *(*align) (void *); struct attribute_group *attr_group; }; @@ -130,9 +132,11 @@ struct cmb_data { unsigned long long last_update; /* when last_block was updated */ }; -/* our user interface is designed in terms of nanoseconds, +/* + * Our user interface is designed in terms of nanoseconds, * while the hardware measures total times in its own - * unit.*/ + * unit. + */ static inline u64 time_to_nsec(u32 value) { return ((u64)value) * 128000ull; @@ -159,12 +163,13 @@ static inline u64 time_to_avg_nsec(u32 value, u32 count) return ret; } -/* activate or deactivate the channel monitor. When area is NULL, +/* + * Activate or deactivate the channel monitor. When area is NULL, * the monitor is deactivated. The channel monitor needs to * be active in order to measure subchannels, which also need - * to be enabled. */ -static inline void -cmf_activate(void *area, unsigned int onoff) + * to be enabled. + */ +static inline void cmf_activate(void *area, unsigned int onoff) { register void * __gpr2 asm("2"); register long __gpr1 asm("1"); @@ -175,8 +180,8 @@ cmf_activate(void *area, unsigned int onoff) asm("schm" : : "d" (__gpr2), "d" (__gpr1) ); } -static int -set_schib(struct ccw_device *cdev, u32 mme, int mbfc, unsigned long address) +static int set_schib(struct ccw_device *cdev, u32 mme, int mbfc, + unsigned long address) { int ret; int retry; @@ -484,15 +489,14 @@ static struct cmb_area cmb_area = { /* ****** old style CMB handling ********/ -/** int maxchannels - * +/* * Basic channel measurement blocks are allocated in one contiguous * block of memory, which can not be moved as long as any channel * is active. Therefore, a maximum number of subchannels needs to * be defined somewhere. This is a module parameter, defaulting to * a resonable value of 1024, or 32 kb of memory. * Current kernels don't allow kmalloc with more than 128kb, so the - * maximum is 4096 + * maximum is 4096. */ module_param_named(maxchannels, cmb_area.num_channels, uint, 0444); @@ -516,8 +520,9 @@ struct cmb { u32 reserved[2]; }; -/* insert a single device into the cmb_area list - * called with cmb_area.lock held from alloc_cmb +/* + * Insert a single device into the cmb_area list. + * Called with cmb_area.lock held from alloc_cmb. */ static int alloc_cmb_single(struct ccw_device *cdev, struct cmb_data *cmb_data) @@ -532,9 +537,11 @@ static int alloc_cmb_single(struct ccw_device *cdev, goto out; } - /* find first unused cmb in cmb_area.mem. - * this is a little tricky: cmb_area.list - * remains sorted by ->cmb->hw_data pointers */ + /* + * Find first unused cmb in cmb_area.mem. + * This is a little tricky: cmb_area.list + * remains sorted by ->cmb->hw_data pointers. + */ cmb = cmb_area.mem; list_for_each_entry(node, &cmb_area.list, cmb_list) { struct cmb_data *data; @@ -558,8 +565,7 @@ out: return ret; } -static int -alloc_cmb (struct ccw_device *cdev) +static int alloc_cmb(struct ccw_device *cdev) { int ret; struct cmb *mem; @@ -670,7 +676,7 @@ static int set_cmb(struct ccw_device *cdev, u32 mme) return set_schib_wait(cdev, mme, 0, offset); } -static u64 read_cmb (struct ccw_device *cdev, int index) +static u64 read_cmb(struct ccw_device *cdev, int index) { struct cmb *cmb; u32 val; @@ -720,7 +726,7 @@ out: return ret; } -static int readall_cmb (struct ccw_device *cdev, struct cmbdata *data) +static int readall_cmb(struct ccw_device *cdev, struct cmbdata *data) { struct cmb *cmb; struct cmb_data *cmb_data; @@ -816,10 +822,12 @@ struct cmbe { u32 reserved[7]; }; -/* kmalloc only guarantees 8 byte alignment, but we need cmbe +/* + * kmalloc only guarantees 8 byte alignment, but we need cmbe * pointers to be naturally aligned. Make sure to allocate - * enough space for two cmbes */ -static inline struct cmbe* cmbe_align(struct cmbe *c) + * enough space for two cmbes. + */ +static inline struct cmbe *cmbe_align(struct cmbe *c) { unsigned long addr; addr = ((unsigned long)c + sizeof (struct cmbe) - sizeof(long)) & @@ -827,7 +835,7 @@ static inline struct cmbe* cmbe_align(struct cmbe *c) return (struct cmbe*)addr; } -static int alloc_cmbe (struct ccw_device *cdev) +static int alloc_cmbe(struct ccw_device *cdev) { struct cmbe *cmbe; struct cmb_data *cmb_data; @@ -873,7 +881,7 @@ out_free: return ret; } -static void free_cmbe (struct ccw_device *cdev) +static void free_cmbe(struct ccw_device *cdev) { struct cmb_data *cmb_data; @@ -912,7 +920,7 @@ static int set_cmbe(struct ccw_device *cdev, u32 mme) } -static u64 read_cmbe (struct ccw_device *cdev, int index) +static u64 read_cmbe(struct ccw_device *cdev, int index) { struct cmbe *cmb; struct cmb_data *cmb_data; @@ -970,7 +978,7 @@ out: return ret; } -static int readall_cmbe (struct ccw_device *cdev, struct cmbdata *data) +static int readall_cmbe(struct ccw_device *cdev, struct cmbdata *data) { struct cmbe *cmb; struct cmb_data *cmb_data; @@ -1049,15 +1057,15 @@ static struct cmb_operations cmbops_extended = { }; -static ssize_t -cmb_show_attr(struct device *dev, char *buf, enum cmb_index idx) +static ssize_t cmb_show_attr(struct device *dev, char *buf, enum cmb_index idx) { return sprintf(buf, "%lld\n", (unsigned long long) cmf_read(to_ccwdev(dev), idx)); } -static ssize_t -cmb_show_avg_sample_interval(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t cmb_show_avg_sample_interval(struct device *dev, + struct device_attribute *attr, + char *buf) { struct ccw_device *cdev; long interval; @@ -1079,8 +1087,9 @@ cmb_show_avg_sample_interval(struct device *dev, struct device_attribute *attr, return sprintf(buf, "%ld\n", interval); } -static ssize_t -cmb_show_avg_utilization(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t cmb_show_avg_utilization(struct device *dev, + struct device_attribute *attr, + char *buf) { struct cmbdata data; u64 utilization; @@ -1112,14 +1121,16 @@ cmb_show_avg_utilization(struct device *dev, struct device_attribute *attr, char } #define cmf_attr(name) \ -static ssize_t show_ ## name (struct device * dev, struct device_attribute *attr, char * buf) \ -{ return cmb_show_attr((dev), buf, cmb_ ## name); } \ -static DEVICE_ATTR(name, 0444, show_ ## name, NULL); +static ssize_t show_##name(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ return cmb_show_attr((dev), buf, cmb_##name); } \ +static DEVICE_ATTR(name, 0444, show_##name, NULL); #define cmf_attr_avg(name) \ -static ssize_t show_avg_ ## name (struct device * dev, struct device_attribute *attr, char * buf) \ -{ return cmb_show_attr((dev), buf, cmb_ ## name); } \ -static DEVICE_ATTR(avg_ ## name, 0444, show_avg_ ## name, NULL); +static ssize_t show_avg_##name(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ return cmb_show_attr((dev), buf, cmb_##name); } \ +static DEVICE_ATTR(avg_##name, 0444, show_avg_##name, NULL); cmf_attr(ssch_rsch_count); cmf_attr(sample_count); @@ -1131,7 +1142,8 @@ cmf_attr_avg(device_active_only_time); cmf_attr_avg(device_busy_time); cmf_attr_avg(initial_command_response_time); -static DEVICE_ATTR(avg_sample_interval, 0444, cmb_show_avg_sample_interval, NULL); +static DEVICE_ATTR(avg_sample_interval, 0444, cmb_show_avg_sample_interval, + NULL); static DEVICE_ATTR(avg_utilization, 0444, cmb_show_avg_utilization, NULL); static struct attribute *cmf_attributes[] = { @@ -1172,12 +1184,16 @@ static struct attribute_group cmf_attr_group_ext = { .attrs = cmf_attributes_ext, }; -static ssize_t cmb_enable_show(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t cmb_enable_show(struct device *dev, + struct device_attribute *attr, + char *buf) { return sprintf(buf, "%d\n", to_ccwdev(dev)->private->cmb ? 1 : 0); } -static ssize_t cmb_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t c) +static ssize_t cmb_enable_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t c) { struct ccw_device *cdev; int ret; @@ -1203,8 +1219,7 @@ static ssize_t cmb_enable_store(struct device *dev, struct device_attribute *att DEVICE_ATTR(cmb_enable, 0644, cmb_enable_show, cmb_enable_store); /* enable_cmf/disable_cmf: module interface for cmf (de)activation */ -int -enable_cmf(struct ccw_device *cdev) +int enable_cmf(struct ccw_device *cdev) { int ret; @@ -1225,8 +1240,7 @@ enable_cmf(struct ccw_device *cdev) return ret; } -int -disable_cmf(struct ccw_device *cdev) +int disable_cmf(struct ccw_device *cdev) { int ret; @@ -1238,14 +1252,12 @@ disable_cmf(struct ccw_device *cdev) return ret; } -u64 -cmf_read(struct ccw_device *cdev, int index) +u64 cmf_read(struct ccw_device *cdev, int index) { return cmbops->read(cdev, index); } -int -cmf_readall(struct ccw_device *cdev, struct cmbdata *data) +int cmf_readall(struct ccw_device *cdev, struct cmbdata *data) { return cmbops->readall(cdev, data); } @@ -1257,15 +1269,16 @@ int cmf_reenable(struct ccw_device *cdev) return cmbops->set(cdev, 2); } -static int __init -init_cmf(void) +static int __init init_cmf(void) { char *format_string; char *detect_string = "parameter"; - /* We cannot really autoprobe this. If the user did not give a parameter, - see if we are running on z990 or up, otherwise fall back to basic mode. */ - + /* + * If the user did not give a parameter, see if we are running on a + * machine supporting extended measurement blocks, otherwise fall back + * to basic mode. + */ if (format == CMF_AUTODETECT) { if (!css_characteristics_avail || !css_general_characteristics.ext_mb) { @@ -1284,7 +1297,7 @@ init_cmf(void) cmbops = &cmbops_basic; break; case CMF_EXTENDED: - format_string = "extended"; + format_string = "extended"; cmbops = &cmbops_extended; break; default: diff --git a/include/asm-s390/cmb.h b/include/asm-s390/cmb.h index 021e7c3223e..2e84eebaf8f 100644 --- a/include/asm-s390/cmb.h +++ b/include/asm-s390/cmb.h @@ -41,11 +41,11 @@ struct cmbdata { }; /* enable channel measurement */ -#define BIODASDCMFENABLE _IO(DASD_IOCTL_LETTER,32) +#define BIODASDCMFENABLE _IO(DASD_IOCTL_LETTER, 32) /* enable channel measurement */ -#define BIODASDCMFDISABLE _IO(DASD_IOCTL_LETTER,33) +#define BIODASDCMFDISABLE _IO(DASD_IOCTL_LETTER, 33) /* read channel measurement data */ -#define BIODASDREADALLCMB _IOWR(DASD_IOCTL_LETTER,33,struct cmbdata) +#define BIODASDREADALLCMB _IOWR(DASD_IOCTL_LETTER, 33, struct cmbdata) #ifdef __KERNEL__ struct ccw_device; @@ -87,7 +87,7 @@ extern u64 cmf_read(struct ccw_device *cdev, int index); * Context: * any **/ -extern int cmf_readall(struct ccw_device *cdev, struct cmbdata*data); +extern int cmf_readall(struct ccw_device *cdev, struct cmbdata *data); #endif /* __KERNEL__ */ #endif /* S390_CMB_H */ -- cgit v1.2.3-70-g09d2 From c02087162af5d8880ff2d688999d71e1bfa16f2f Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Fri, 12 Oct 2007 16:11:16 +0200 Subject: [S390] cio: Kerneldoc comments for cmf. - Fix existing kerneldoc-style comments. - Move descriptions of functions from cmb.h to cmf.c. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky Signed-off-by: Heiko Carstens --- drivers/s390/cio/cmf.c | 87 ++++++++++++++++++++++++++++++++++++++++++-------- include/asm-s390/cmb.h | 65 +++++++++---------------------------- 2 files changed, 89 insertions(+), 63 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c index ff1e442d4b0..6ef0ab89547 100644 --- a/drivers/s390/cio/cmf.c +++ b/drivers/s390/cio/cmf.c @@ -74,19 +74,20 @@ enum cmb_index { * enum cmb_format - types of supported measurement block formats * * @CMF_BASIC: traditional channel measurement blocks supported - * by all machines that we run on + * by all machines that we run on * @CMF_EXTENDED: improved format that was introduced with the z990 - * machine - * @CMF_AUTODETECT: default: use extended format when running on a z990 - * or later machine, otherwise fall back to basic format - **/ + * machine + * @CMF_AUTODETECT: default: use extended format when running on a machine + * supporting extended format, otherwise fall back to + * basic format + */ enum cmb_format { CMF_BASIC, CMF_EXTENDED, CMF_AUTODETECT = -1, }; -/** +/* * format - actual format for all measurement blocks * * The format module parameter can be set to a value of 0 (zero) @@ -107,6 +108,7 @@ module_param(format, bool, 0444); * either with the help of a special pool or with kmalloc * @free: free memory allocated with @alloc * @set: enable or disable measurement + * @read: read a measurement entry at an index * @readall: read a measurement block in a common format * @reset: clear the data in the associated measurement block and * reset its time stamp @@ -120,7 +122,7 @@ struct cmb_operations { int (*readall)(struct ccw_device *, struct cmbdata *); void (*reset) (struct ccw_device *); void *(*align) (void *); - +/* private: */ struct attribute_group *attr_group; }; static struct cmb_operations *cmbops; @@ -471,6 +473,7 @@ static void cmf_generic_reset(struct ccw_device *cdev) * * @mem: pointer to CMBs (only in basic measurement mode) * @list: contains a linked list of all subchannels + * @num_channels: number of channels to be measured * @lock: protect concurrent access to @mem and @list */ struct cmb_area { @@ -503,10 +506,20 @@ module_param_named(maxchannels, cmb_area.num_channels, uint, 0444); /** * struct cmb - basic channel measurement block + * @ssch_rsch_count: number of ssch and rsch + * @sample_count: number of samples + * @device_connect_time: time of device connect + * @function_pending_time: time of function pending + * @device_disconnect_time: time of device disconnect + * @control_unit_queuing_time: time of control unit queuing + * @device_active_only_time: time of device active only + * @reserved: unused in basic measurement mode + * + * The measurement block as used by the hardware. The fields are described + * further in z/Architecture Principles of Operation, chapter 17. * - * cmb as used by the hardware the fields are described in z/Architecture - * Principles of Operation, chapter 17. - * The area to be a contiguous array and may not be reallocated or freed. + * The cmb area made up from these blocks must be a contiguous array and may + * not be reallocated or freed. * Only one cmb area can be present in the system. */ struct cmb { @@ -804,9 +817,20 @@ static struct cmb_operations cmbops_basic = { /** * struct cmbe - extended channel measurement block + * @ssch_rsch_count: number of ssch and rsch + * @sample_count: number of samples + * @device_connect_time: time of device connect + * @function_pending_time: time of function pending + * @device_disconnect_time: time of device disconnect + * @control_unit_queuing_time: time of control unit queuing + * @device_active_only_time: time of device active only + * @device_busy_time: time of device busy + * @initial_command_response_time: initial command response time + * @reserved: unused * - * cmb as used by the hardware, may be in any 64 bit physical location, - * the fields are described in z/Architecture Principles of Operation, + * The measurement block as used by the hardware. May be in any 64 bit physical + * location. + * The fields are described further in z/Architecture Principles of Operation, * third edition, chapter 17. */ struct cmbe { @@ -1218,7 +1242,15 @@ static ssize_t cmb_enable_store(struct device *dev, DEVICE_ATTR(cmb_enable, 0644, cmb_enable_show, cmb_enable_store); -/* enable_cmf/disable_cmf: module interface for cmf (de)activation */ +/** + * enable_cmf() - switch on the channel measurement for a specific device + * @cdev: The ccw device to be enabled + * + * Returns %0 for success or a negative error value. + * + * Context: + * non-atomic + */ int enable_cmf(struct ccw_device *cdev) { int ret; @@ -1240,6 +1272,15 @@ int enable_cmf(struct ccw_device *cdev) return ret; } +/** + * disable_cmf() - switch off the channel measurement for a specific device + * @cdev: The ccw device to be disabled + * + * Returns %0 for success or a negative error value. + * + * Context: + * non-atomic + */ int disable_cmf(struct ccw_device *cdev) { int ret; @@ -1252,11 +1293,31 @@ int disable_cmf(struct ccw_device *cdev) return ret; } +/** + * cmf_read() - read one value from the current channel measurement block + * @cdev: the channel to be read + * @index: the index of the value to be read + * + * Returns the value read or %0 if the value cannot be read. + * + * Context: + * any + */ u64 cmf_read(struct ccw_device *cdev, int index) { return cmbops->read(cdev, index); } +/** + * cmf_readall() - read the current channel measurement block + * @cdev: the channel to be read + * @data: a pointer to a data block that will be filled + * + * Returns %0 on success, a negative error value otherwise. + * + * Context: + * any + */ int cmf_readall(struct ccw_device *cdev, struct cmbdata *data) { return cmbops->readall(cdev, data); diff --git a/include/asm-s390/cmb.h b/include/asm-s390/cmb.h index 2e84eebaf8f..50196857d27 100644 --- a/include/asm-s390/cmb.h +++ b/include/asm-s390/cmb.h @@ -1,29 +1,29 @@ #ifndef S390_CMB_H #define S390_CMB_H /** - * struct cmbdata -- channel measurement block data for user space + * struct cmbdata - channel measurement block data for user space + * @size: size of the stored data + * @elapsed_time: time since last sampling + * @ssch_rsch_count: number of ssch and rsch + * @sample_count: number of samples + * @device_connect_time: time of device connect + * @function_pending_time: time of function pending + * @device_disconnect_time: time of device disconnect + * @control_unit_queuing_time: time of control unit queuing + * @device_active_only_time: time of device active only + * @device_busy_time: time of device busy (ext. format) + * @initial_command_response_time: initial command response time (ext. format) * - * @size: size of the stored data - * @ssch_rsch_count: XXX - * @sample_count: - * @device_connect_time: - * @function_pending_time: - * @device_disconnect_time: - * @control_unit_queuing_time: - * @device_active_only_time: - * @device_busy_time: - * @initial_command_response_time: - * - * all values are stored as 64 bit for simplicity, especially + * All values are stored as 64 bit for simplicity, especially * in 32 bit emulation mode. All time values are normalized to * nanoseconds. * Currently, two formats are known, which differ by the size of * this structure, i.e. the last two members are only set when * the extended channel measurement facility (first shipped in * z990 machines) is activated. - * Potentially, more fields could be added, which results in a + * Potentially, more fields could be added, which would result in a * new ioctl number. - **/ + */ struct cmbdata { __u64 size; __u64 elapsed_time; @@ -49,44 +49,9 @@ struct cmbdata { #ifdef __KERNEL__ struct ccw_device; -/** - * enable_cmf() - switch on the channel measurement for a specific device - * @cdev: The ccw device to be enabled - * returns 0 for success or a negative error value. - * - * Context: - * non-atomic - **/ extern int enable_cmf(struct ccw_device *cdev); - -/** - * disable_cmf() - switch off the channel measurement for a specific device - * @cdev: The ccw device to be disabled - * returns 0 for success or a negative error value. - * - * Context: - * non-atomic - **/ extern int disable_cmf(struct ccw_device *cdev); - -/** - * cmf_read() - read one value from the current channel measurement block - * @cmf: the channel to be read - * @index: the name of the value that is read - * - * Context: - * any - **/ - extern u64 cmf_read(struct ccw_device *cdev, int index); -/** - * cmf_readall() - read one value from the current channel measurement block - * @cmf: the channel to be read - * @data: a pointer to a data block that will be filled - * - * Context: - * any - **/ extern int cmf_readall(struct ccw_device *cdev, struct cmbdata *data); #endif /* __KERNEL__ */ -- cgit v1.2.3-70-g09d2 From b2ffd8e9a76ec90bd4a509f3d092e35978c568a3 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Fri, 12 Oct 2007 16:11:17 +0200 Subject: [S390] cio: Add docbook comments. Comment a bunch of function in docbook style and convert existing comments on structures to docbook. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky Signed-off-by: Heiko Carstens --- drivers/s390/cio/ccwgroup.c | 67 +++++++--- drivers/s390/cio/device.c | 64 ++++++++-- drivers/s390/cio/device_ops.c | 241 ++++++++++++++++++++++++++++++----- include/asm-s390/ccwdev.h | 75 +++++------ include/asm-s390/ccwgroup.h | 32 ++++- include/asm-s390/cio.h | 288 +++++++++++++++++++++++++++++------------- 6 files changed, 575 insertions(+), 192 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index b0a18f5176a..9c3b9ea1e66 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -152,16 +152,24 @@ __ccwgroup_create_symlinks(struct ccwgroup_device *gdev) return 0; } -/* - * try to add a new ccwgroup device for one driver - * argc and argv[] are a list of bus_id's of devices - * belonging to the driver. +/** + * ccwgroup_create() - create and register a ccw group device + * @root: parent device for the new device + * @creator_id: identifier of creating driver + * @cdrv: ccw driver of slave devices + * @argc: number of slave devices + * @argv: bus ids of slave devices + * + * Create and register a new ccw group device as a child of @root. Slave + * devices are obtained from the list of bus ids given in @argv[] and must all + * belong to @cdrv. + * Returns: + * %0 on success and an error code on failure. + * Context: + * non-atomic */ -int -ccwgroup_create(struct device *root, - unsigned int creator_id, - struct ccw_driver *cdrv, - int argc, char *argv[]) +int ccwgroup_create(struct device *root, unsigned int creator_id, + struct ccw_driver *cdrv, int argc, char *argv[]) { struct ccwgroup_device *gdev; int i; @@ -390,8 +398,13 @@ static struct bus_type ccwgroup_bus_type = { .remove = ccwgroup_remove, }; -int -ccwgroup_driver_register (struct ccwgroup_driver *cdriver) +/** + * ccwgroup_driver_register() - register a ccw group driver + * @cdriver: driver to be registered + * + * This function is mainly a wrapper around driver_register(). + */ +int ccwgroup_driver_register(struct ccwgroup_driver *cdriver) { /* register our new driver with the core */ cdriver->driver.bus = &ccwgroup_bus_type; @@ -406,8 +419,13 @@ __ccwgroup_match_all(struct device *dev, void *data) return 1; } -void -ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver) +/** + * ccwgroup_driver_unregister() - deregister a ccw group driver + * @cdriver: driver to be deregistered + * + * This function is mainly a wrapper around driver_unregister(). + */ +void ccwgroup_driver_unregister(struct ccwgroup_driver *cdriver) { struct device *dev; @@ -427,8 +445,16 @@ ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver) driver_unregister(&cdriver->driver); } -int -ccwgroup_probe_ccwdev(struct ccw_device *cdev) +/** + * ccwgroup_probe_ccwdev() - probe function for slave devices + * @cdev: ccw device to be probed + * + * This is a dummy probe function for ccw devices that are slave devices in + * a ccw group device. + * Returns: + * always %0 + */ +int ccwgroup_probe_ccwdev(struct ccw_device *cdev) { return 0; } @@ -452,8 +478,15 @@ __ccwgroup_get_gdev_by_cdev(struct ccw_device *cdev) return NULL; } -void -ccwgroup_remove_ccwdev(struct ccw_device *cdev) +/** + * ccwgroup_remove_ccwdev() - remove function for slave devices + * @cdev: ccw device to be removed + * + * This is a remove function for ccw devices that are slave devices in a ccw + * group device. It sets the ccw device offline and also deregisters the + * embedding ccw group device. + */ +void ccwgroup_remove_ccwdev(struct ccw_device *cdev) { struct ccwgroup_device *gdev; diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index e44d92eac8e..3943a4fde22 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -357,8 +357,18 @@ ccw_device_remove_disconnected(struct ccw_device *cdev) cdev->private->dev_id.devno); } -int -ccw_device_set_offline(struct ccw_device *cdev) +/** + * ccw_device_set_offline() - disable a ccw device for I/O + * @cdev: target ccw device + * + * This function calls the driver's set_offline() function for @cdev, if + * given, and then disables @cdev. + * Returns: + * %0 on success and a negative error value on failure. + * Context: + * enabled, ccw device lock not held + */ +int ccw_device_set_offline(struct ccw_device *cdev) { int ret; @@ -396,8 +406,19 @@ ccw_device_set_offline(struct ccw_device *cdev) return ret; } -int -ccw_device_set_online(struct ccw_device *cdev) +/** + * ccw_device_set_online() - enable a ccw device for I/O + * @cdev: target ccw device + * + * This function first enables @cdev and then calls the driver's set_online() + * function for @cdev, if given. If set_online() returns an error, @cdev is + * disabled again. + * Returns: + * %0 on success and a negative error value on failure. + * Context: + * enabled, ccw device lock not held + */ +int ccw_device_set_online(struct ccw_device *cdev) { int ret; @@ -1326,8 +1347,19 @@ __ccwdev_check_busid(struct device *dev, void *id) } -struct ccw_device * -get_ccwdev_by_busid(struct ccw_driver *cdrv, const char *bus_id) +/** + * get_ccwdev_by_busid() - obtain device from a bus id + * @cdrv: driver the device is owned by + * @bus_id: bus id of the device to be searched + * + * This function searches all devices owned by @cdrv for a device with a bus + * id matching @bus_id. + * Returns: + * If a match is found, its reference count of the found device is increased + * and it is returned; else %NULL is returned. + */ +struct ccw_device *get_ccwdev_by_busid(struct ccw_driver *cdrv, + const char *bus_id) { struct device *dev; struct device_driver *drv; @@ -1409,8 +1441,15 @@ struct bus_type ccw_bus_type = { .remove = ccw_device_remove, }; -int -ccw_driver_register (struct ccw_driver *cdriver) +/** + * ccw_driver_register() - register a ccw driver + * @cdriver: driver to be registered + * + * This function is mainly a wrapper around driver_register(). + * Returns: + * %0 on success and a negative error value on failure. + */ +int ccw_driver_register(struct ccw_driver *cdriver) { struct device_driver *drv = &cdriver->driver; @@ -1420,8 +1459,13 @@ ccw_driver_register (struct ccw_driver *cdriver) return driver_register(drv); } -void -ccw_driver_unregister (struct ccw_driver *cdriver) +/** + * ccw_driver_unregister() - deregister a ccw driver + * @cdriver: driver to be deregistered + * + * This function is mainly a wrapper around driver_unregister(). + */ +void ccw_driver_unregister(struct ccw_driver *cdriver) { driver_unregister(&cdriver->driver); } diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c index 14eba854b15..7fd2dadc329 100644 --- a/drivers/s390/cio/device_ops.c +++ b/drivers/s390/cio/device_ops.c @@ -25,6 +25,16 @@ #include "device.h" #include "chp.h" +/** + * ccw_device_set_options_mask() - set some options and unset the rest + * @cdev: device for which the options are to be set + * @flags: options to be set + * + * All flags specified in @flags are set, all flags not specified in @flags + * are cleared. + * Returns: + * %0 on success, -%EINVAL on an invalid flag combination. + */ int ccw_device_set_options_mask(struct ccw_device *cdev, unsigned long flags) { /* @@ -40,6 +50,15 @@ int ccw_device_set_options_mask(struct ccw_device *cdev, unsigned long flags) return 0; } +/** + * ccw_device_set_options() - set some options + * @cdev: device for which the options are to be set + * @flags: options to be set + * + * All flags specified in @flags are set, the remainder is left untouched. + * Returns: + * %0 on success, -%EINVAL if an invalid flag combination would ensue. + */ int ccw_device_set_options(struct ccw_device *cdev, unsigned long flags) { /* @@ -59,6 +78,13 @@ int ccw_device_set_options(struct ccw_device *cdev, unsigned long flags) return 0; } +/** + * ccw_device_clear_options() - clear some options + * @cdev: device for which the options are to be cleared + * @flags: options to be cleared + * + * All flags specified in @flags are cleared, the remainder is left untouched. + */ void ccw_device_clear_options(struct ccw_device *cdev, unsigned long flags) { cdev->private->options.fast &= (flags & CCWDEV_EARLY_NOTIFICATION) == 0; @@ -67,8 +93,22 @@ void ccw_device_clear_options(struct ccw_device *cdev, unsigned long flags) cdev->private->options.force &= (flags & CCWDEV_ALLOW_FORCE) == 0; } -int -ccw_device_clear(struct ccw_device *cdev, unsigned long intparm) +/** + * ccw_device_clear() - terminate I/O request processing + * @cdev: target ccw device + * @intparm: interruption parameter; value is only used if no I/O is + * outstanding, otherwise the intparm associated with the I/O request + * is returned + * + * ccw_device_clear() calls csch on @cdev's subchannel. + * Returns: + * %0 on success, + * -%ENODEV on device not operational, + * -%EINVAL on invalid device state. + * Context: + * Interrupts disabled, ccw device lock held + */ +int ccw_device_clear(struct ccw_device *cdev, unsigned long intparm) { struct subchannel *sch; int ret; @@ -89,10 +129,33 @@ ccw_device_clear(struct ccw_device *cdev, unsigned long intparm) return ret; } -int -ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, - unsigned long intparm, __u8 lpm, __u8 key, - unsigned long flags) +/** + * ccw_device_start_key() - start a s390 channel program with key + * @cdev: target ccw device + * @cpa: logical start address of channel program + * @intparm: user specific interruption parameter; will be presented back to + * @cdev's interrupt handler. Allows a device driver to associate + * the interrupt with a particular I/O request. + * @lpm: defines the channel path to be used for a specific I/O request. A + * value of 0 will make cio use the opm. + * @key: storage key to be used for the I/O + * @flags: additional flags; defines the action to be performed for I/O + * processing. + * + * Start a S/390 channel program. When the interrupt arrives, the + * IRQ handler is called, either immediately, delayed (dev-end missing, + * or sense required) or never (no IRQ handler registered). + * Returns: + * %0, if the operation was successful; + * -%EBUSY, if the device is busy, or status pending; + * -%EACCES, if no path specified in @lpm is operational; + * -%ENODEV, if the device is not operational. + * Context: + * Interrupts disabled, ccw device lock held + */ +int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, + unsigned long intparm, __u8 lpm, __u8 key, + unsigned long flags) { struct subchannel *sch; int ret; @@ -135,11 +198,38 @@ ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, return ret; } - -int -ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa, - unsigned long intparm, __u8 lpm, __u8 key, - unsigned long flags, int expires) +/** + * ccw_device_start_timeout_key() - start a s390 channel program with timeout and key + * @cdev: target ccw device + * @cpa: logical start address of channel program + * @intparm: user specific interruption parameter; will be presented back to + * @cdev's interrupt handler. Allows a device driver to associate + * the interrupt with a particular I/O request. + * @lpm: defines the channel path to be used for a specific I/O request. A + * value of 0 will make cio use the opm. + * @key: storage key to be used for the I/O + * @flags: additional flags; defines the action to be performed for I/O + * processing. + * @expires: timeout value in jiffies + * + * Start a S/390 channel program. When the interrupt arrives, the + * IRQ handler is called, either immediately, delayed (dev-end missing, + * or sense required) or never (no IRQ handler registered). + * This function notifies the device driver if the channel program has not + * completed during the time specified by @expires. If a timeout occurs, the + * channel program is terminated via xsch, hsch or csch, and the device's + * interrupt handler will be called with an irb containing ERR_PTR(-%ETIMEDOUT). + * Returns: + * %0, if the operation was successful; + * -%EBUSY, if the device is busy, or status pending; + * -%EACCES, if no path specified in @lpm is operational; + * -%ENODEV, if the device is not operational. + * Context: + * Interrupts disabled, ccw device lock held + */ +int ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa, + unsigned long intparm, __u8 lpm, __u8 key, + unsigned long flags, int expires) { int ret; @@ -152,18 +242,67 @@ ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa, return ret; } -int -ccw_device_start(struct ccw_device *cdev, struct ccw1 *cpa, - unsigned long intparm, __u8 lpm, unsigned long flags) +/** + * ccw_device_start() - start a s390 channel program + * @cdev: target ccw device + * @cpa: logical start address of channel program + * @intparm: user specific interruption parameter; will be presented back to + * @cdev's interrupt handler. Allows a device driver to associate + * the interrupt with a particular I/O request. + * @lpm: defines the channel path to be used for a specific I/O request. A + * value of 0 will make cio use the opm. + * @flags: additional flags; defines the action to be performed for I/O + * processing. + * + * Start a S/390 channel program. When the interrupt arrives, the + * IRQ handler is called, either immediately, delayed (dev-end missing, + * or sense required) or never (no IRQ handler registered). + * Returns: + * %0, if the operation was successful; + * -%EBUSY, if the device is busy, or status pending; + * -%EACCES, if no path specified in @lpm is operational; + * -%ENODEV, if the device is not operational. + * Context: + * Interrupts disabled, ccw device lock held + */ +int ccw_device_start(struct ccw_device *cdev, struct ccw1 *cpa, + unsigned long intparm, __u8 lpm, unsigned long flags) { return ccw_device_start_key(cdev, cpa, intparm, lpm, PAGE_DEFAULT_KEY, flags); } -int -ccw_device_start_timeout(struct ccw_device *cdev, struct ccw1 *cpa, - unsigned long intparm, __u8 lpm, unsigned long flags, - int expires) +/** + * ccw_device_start_timeout() - start a s390 channel program with timeout + * @cdev: target ccw device + * @cpa: logical start address of channel program + * @intparm: user specific interruption parameter; will be presented back to + * @cdev's interrupt handler. Allows a device driver to associate + * the interrupt with a particular I/O request. + * @lpm: defines the channel path to be used for a specific I/O request. A + * value of 0 will make cio use the opm. + * @flags: additional flags; defines the action to be performed for I/O + * processing. + * @expires: timeout value in jiffies + * + * Start a S/390 channel program. When the interrupt arrives, the + * IRQ handler is called, either immediately, delayed (dev-end missing, + * or sense required) or never (no IRQ handler registered). + * This function notifies the device driver if the channel program has not + * completed during the time specified by @expires. If a timeout occurs, the + * channel program is terminated via xsch, hsch or csch, and the device's + * interrupt handler will be called with an irb containing ERR_PTR(-%ETIMEDOUT). + * Returns: + * %0, if the operation was successful; + * -%EBUSY, if the device is busy, or status pending; + * -%EACCES, if no path specified in @lpm is operational; + * -%ENODEV, if the device is not operational. + * Context: + * Interrupts disabled, ccw device lock held + */ +int ccw_device_start_timeout(struct ccw_device *cdev, struct ccw1 *cpa, + unsigned long intparm, __u8 lpm, + unsigned long flags, int expires) { return ccw_device_start_timeout_key(cdev, cpa, intparm, lpm, PAGE_DEFAULT_KEY, flags, @@ -171,8 +310,23 @@ ccw_device_start_timeout(struct ccw_device *cdev, struct ccw1 *cpa, } -int -ccw_device_halt(struct ccw_device *cdev, unsigned long intparm) +/** + * ccw_device_halt() - halt I/O request processing + * @cdev: target ccw device + * @intparm: interruption parameter; value is only used if no I/O is + * outstanding, otherwise the intparm associated with the I/O request + * is returned + * + * ccw_device_halt() calls hsch on @cdev's subchannel. + * Returns: + * %0 on success, + * -%ENODEV on device not operational, + * -%EINVAL on invalid device state, + * -%EBUSY on device busy or interrupt pending. + * Context: + * Interrupts disabled, ccw device lock held + */ +int ccw_device_halt(struct ccw_device *cdev, unsigned long intparm) { struct subchannel *sch; int ret; @@ -193,8 +347,20 @@ ccw_device_halt(struct ccw_device *cdev, unsigned long intparm) return ret; } -int -ccw_device_resume(struct ccw_device *cdev) +/** + * ccw_device_resume() - resume channel program execution + * @cdev: target ccw device + * + * ccw_device_resume() calls rsch on @cdev's subchannel. + * Returns: + * %0 on success, + * -%ENODEV on device not operational, + * -%EINVAL on invalid device state, + * -%EBUSY on device busy or interrupt pending. + * Context: + * Interrupts disabled, ccw device lock held + */ +int ccw_device_resume(struct ccw_device *cdev) { struct subchannel *sch; @@ -260,11 +426,21 @@ ccw_device_call_handler(struct ccw_device *cdev) return 1; } -/* - * Search for CIW command in extended sense data. +/** + * ccw_device_get_ciw() - Search for CIW command in extended sense data. + * @cdev: ccw device to inspect + * @ct: command type to look for + * + * During SenseID, command information words (CIWs) describing special + * commands available to the device may have been stored in the extended + * sense data. This function searches for CIWs of a specified command + * type in the extended sense data. + * Returns: + * %NULL if no extended sense data has been stored or if no CIW of the + * specified command type could be found, + * else a pointer to the CIW of the specified command type. */ -struct ciw * -ccw_device_get_ciw(struct ccw_device *cdev, __u32 ct) +struct ciw *ccw_device_get_ciw(struct ccw_device *cdev, __u32 ct) { int ciw_cnt; @@ -276,8 +452,14 @@ ccw_device_get_ciw(struct ccw_device *cdev, __u32 ct) return NULL; } -__u8 -ccw_device_get_path_mask(struct ccw_device *cdev) +/** + * ccw_device_get_path_mask() - get currently available paths + * @cdev: ccw device to be queried + * Returns: + * %0 if no subchannel for the device is available, + * else the mask of currently available paths for the ccw device's subchannel. + */ +__u8 ccw_device_get_path_mask(struct ccw_device *cdev) { struct subchannel *sch; @@ -357,8 +539,7 @@ out_unlock: return ret; } -void * -ccw_device_get_chp_desc(struct ccw_device *cdev, int chp_no) +void *ccw_device_get_chp_desc(struct ccw_device *cdev, int chp_no) { struct subchannel *sch; struct chp_id chpid; diff --git a/include/asm-s390/ccwdev.h b/include/asm-s390/ccwdev.h index 1aeda27d5a8..8e961aa4b39 100644 --- a/include/asm-s390/ccwdev.h +++ b/include/asm-s390/ccwdev.h @@ -67,36 +67,53 @@ ccw_device_id_match(const struct ccw_device_id *array, return NULL; } -/* The struct ccw device is our replacement for the globally accessible - * ioinfo array. ioinfo will mutate into a subchannel device later. +/** + * struct ccw_device - channel attached device + * @ccwlock: pointer to device lock + * @id: id of this device + * @drv: ccw driver for this device + * @dev: embedded device structure + * @online: online status of device + * @handler: interrupt handler * - * Reference: Documentation/s390/driver-model.txt */ + * @handler is a member of the device rather than the driver since a driver + * can have different interrupt handlers for different ccw devices + * (multi-subchannel drivers). + */ struct ccw_device { spinlock_t *ccwlock; +/* private: */ struct ccw_device_private *private; /* cio private information */ - struct ccw_device_id id; /* id of this device, driver_info is - set by ccw_find_driver */ - struct ccw_driver *drv; /* */ - struct device dev; /* */ +/* public: */ + struct ccw_device_id id; + struct ccw_driver *drv; + struct device dev; int online; - /* This is sick, but a driver can have different interrupt handlers - for different ccw_devices (multi-subchannel drivers)... */ void (*handler) (struct ccw_device *, unsigned long, struct irb *); }; -/* Each ccw driver registers with the ccw root bus */ +/** + * struct ccw driver - device driver for channel attached devices + * @owner: owning module + * @ids: ids supported by this driver + * @probe: function called on probe + * @remove: function called on remove + * @set_online: called when setting device online + * @set_offline: called when setting device offline + * @notify: notify driver of device state changes + * @driver: embedded device driver structure + * @name: device driver name + */ struct ccw_driver { - struct module *owner; /* for automatic MOD_INC_USE_COUNT */ - struct ccw_device_id *ids; /* probe driver with these devs */ - int (*probe) (struct ccw_device *); /* ask driver to probe dev */ + struct module *owner; + struct ccw_device_id *ids; + int (*probe) (struct ccw_device *); void (*remove) (struct ccw_device *); - /* device is no longer available */ int (*set_online) (struct ccw_device *); int (*set_offline) (struct ccw_device *); int (*notify) (struct ccw_device *, int); - struct device_driver driver; /* higher level structure, don't init - this from your driver */ + struct device_driver driver; char *name; }; @@ -124,36 +141,10 @@ extern void ccw_device_clear_options(struct ccw_device *, unsigned long); /* Allow forced onlining of boxed devices. */ #define CCWDEV_ALLOW_FORCE 0x0008 -/* - * ccw_device_start() - * - * Start a S/390 channel program. When the interrupt arrives, the - * IRQ handler is called, either immediately, delayed (dev-end missing, - * or sense required) or never (no IRQ handler registered). - * Depending on the action taken, ccw_device_start() returns: - * 0 - Success - * -EBUSY - Device busy, or status pending - * -ENODEV - Device not operational - * -EINVAL - Device invalid for operation - */ extern int ccw_device_start(struct ccw_device *, struct ccw1 *, unsigned long, __u8, unsigned long); -/* - * ccw_device_start_timeout() - * - * This function notifies the device driver if the channel program has not - * completed during the specified time. If a timeout occurs, the channel - * program is terminated via xsch(), hsch() or csch(). - */ extern int ccw_device_start_timeout(struct ccw_device *, struct ccw1 *, unsigned long, __u8, unsigned long, int); -/* - * ccw_device_start_key() - * ccw_device_start_key_timeout() - * - * Same as ccw_device_start() and ccw_device_start_timeout(), except a - * storage key != default key can be provided for the I/O. - */ extern int ccw_device_start_key(struct ccw_device *, struct ccw1 *, unsigned long, __u8, __u8, unsigned long); extern int ccw_device_start_timeout_key(struct ccw_device *, struct ccw1 *, diff --git a/include/asm-s390/ccwgroup.h b/include/asm-s390/ccwgroup.h index 925b3ddfa14..7109c7cab87 100644 --- a/include/asm-s390/ccwgroup.h +++ b/include/asm-s390/ccwgroup.h @@ -4,19 +4,41 @@ struct ccw_device; struct ccw_driver; +/** + * struct ccwgroup_device - ccw group device + * @creator_id: unique number of the driver + * @state: online/offline state + * @count: number of attached slave devices + * @dev: embedded device structure + * @cdev: variable number of slave devices, allocated as needed + */ struct ccwgroup_device { - unsigned long creator_id; /* unique number of the driver */ + unsigned long creator_id; enum { CCWGROUP_OFFLINE, CCWGROUP_ONLINE, } state; +/* private: */ atomic_t onoff; struct mutex reg_mutex; - unsigned int count; /* number of attached slave devices */ - struct device dev; /* master device */ - struct ccw_device *cdev[0]; /* variable number, allocate as needed */ +/* public: */ + unsigned int count; + struct device dev; + struct ccw_device *cdev[0]; }; +/** + * struct ccwgroup_driver - driver for ccw group devices + * @owner: driver owner + * @name: driver name + * @max_slaves: maximum number of slave devices + * @driver_id: unique id + * @probe: function called on probe + * @remove: function called on remove + * @set_online: function called when device is set online + * @set_offline: function called when device is set offline + * @driver: embedded driver structure + */ struct ccwgroup_driver { struct module *owner; char *name; @@ -28,7 +50,7 @@ struct ccwgroup_driver { int (*set_online) (struct ccwgroup_device *); int (*set_offline) (struct ccwgroup_device *); - struct device_driver driver; /* this driver */ + struct device_driver driver; }; extern int ccwgroup_driver_register (struct ccwgroup_driver *cdriver); diff --git a/include/asm-s390/cio.h b/include/asm-s390/cio.h index 1982fb34416..2f08c16e44a 100644 --- a/include/asm-s390/cio.h +++ b/include/asm-s390/cio.h @@ -15,30 +15,50 @@ #define LPM_ANYPATH 0xff #define __MAX_CSSID 0 -/* - * subchannel status word +/** + * struct scsw - subchannel status word + * @key: subchannel key + * @sctl: suspend control + * @eswf: esw format + * @cc: deferred condition code + * @fmt: format + * @pfch: prefetch + * @isic: initial-status interruption control + * @alcc: adress-limit checking control + * @ssi: supress-suspended interruption + * @zcc: zero condition code + * @ectl: extended control + * @pno: path not operational + * @res: reserved + * @fctl: function control + * @actl: activity control + * @stctl: status control + * @cpa: channel program address + * @dstat: device status + * @cstat: subchannel status + * @count: residual count */ struct scsw { - __u32 key : 4; /* subchannel key */ - __u32 sctl : 1; /* suspend control */ - __u32 eswf : 1; /* ESW format */ - __u32 cc : 2; /* deferred condition code */ - __u32 fmt : 1; /* format */ - __u32 pfch : 1; /* prefetch */ - __u32 isic : 1; /* initial-status interruption control */ - __u32 alcc : 1; /* address-limit checking control */ - __u32 ssi : 1; /* supress-suspended interruption */ - __u32 zcc : 1; /* zero condition code */ - __u32 ectl : 1; /* extended control */ - __u32 pno : 1; /* path not operational */ - __u32 res : 1; /* reserved */ - __u32 fctl : 3; /* function control */ - __u32 actl : 7; /* activity control */ - __u32 stctl : 5; /* status control */ - __u32 cpa; /* channel program address */ - __u32 dstat : 8; /* device status */ - __u32 cstat : 8; /* subchannel status */ - __u32 count : 16; /* residual count */ + __u32 key : 4; + __u32 sctl : 1; + __u32 eswf : 1; + __u32 cc : 2; + __u32 fmt : 1; + __u32 pfch : 1; + __u32 isic : 1; + __u32 alcc : 1; + __u32 ssi : 1; + __u32 zcc : 1; + __u32 ectl : 1; + __u32 pno : 1; + __u32 res : 1; + __u32 fctl : 3; + __u32 actl : 7; + __u32 stctl : 5; + __u32 cpa; + __u32 dstat : 8; + __u32 cstat : 8; + __u32 count : 16; } __attribute__ ((packed)); #define SCSW_FCTL_CLEAR_FUNC 0x1 @@ -110,11 +130,22 @@ struct scsw { #define SNS2_ENV_DATA_PRESENT 0x10 #define SNS2_INPRECISE_END 0x04 +/** + * struct ccw1 - channel command word + * @cmd_code: command code + * @flags: flags, like IDA adressing, etc. + * @count: byte count + * @cda: data address + * + * The ccw is the basic structure to build channel programs that perform + * operations with the device or the control unit. Only Format-1 channel + * command words are supported. + */ struct ccw1 { - __u8 cmd_code; /* command code */ - __u8 flags; /* flags, like IDA addressing, etc. */ - __u16 count; /* byte count */ - __u32 cda; /* data address */ + __u8 cmd_code; + __u8 flags; + __u16 count; + __u32 cda; } __attribute__ ((packed,aligned(8))); #define CCW_FLAG_DC 0x80 @@ -140,102 +171,162 @@ struct ccw1 { #define SENSE_MAX_COUNT 0x20 +/** + * struct erw - extended report word + * @res0: reserved + * @auth: authorization check + * @pvrf: path-verification-required flag + * @cpt: channel-path timeout + * @fsavf: failing storage address validity flag + * @cons: concurrent sense + * @scavf: secondary ccw address validity flag + * @fsaf: failing storage address format + * @scnt: sense count, if @cons == %1 + * @res16: reserved + */ struct erw { - __u32 res0 : 3; /* reserved */ - __u32 auth : 1; /* Authorization check */ - __u32 pvrf : 1; /* path-verification-required flag */ - __u32 cpt : 1; /* channel-path timeout */ - __u32 fsavf : 1; /* Failing storage address validity flag */ - __u32 cons : 1; /* concurrent-sense */ - __u32 scavf : 1; /* Secondary ccw address validity flag */ - __u32 fsaf : 1; /* Failing storage address format */ - __u32 scnt : 6; /* sense count if cons == 1 */ - __u32 res16 : 16; /* reserved */ + __u32 res0 : 3; + __u32 auth : 1; + __u32 pvrf : 1; + __u32 cpt : 1; + __u32 fsavf : 1; + __u32 cons : 1; + __u32 scavf : 1; + __u32 fsaf : 1; + __u32 scnt : 6; + __u32 res16 : 16; } __attribute__ ((packed)); -/* - * subchannel logout area +/** + * struct sublog - subchannel logout area + * @res0: reserved + * @esf: extended status flags + * @lpum: last path used mask + * @arep: ancillary report + * @fvf: field-validity flags + * @sacc: storage access code + * @termc: termination code + * @devsc: device-status check + * @serr: secondary error + * @ioerr: i/o-error alert + * @seqc: sequence code */ struct sublog { - __u32 res0 : 1; /* reserved */ - __u32 esf : 7; /* extended status flags */ - __u32 lpum : 8; /* last path used mask */ - __u32 arep : 1; /* ancillary report */ - __u32 fvf : 5; /* field-validity flags */ - __u32 sacc : 2; /* storage access code */ - __u32 termc : 2; /* termination code */ - __u32 devsc : 1; /* device-status check */ - __u32 serr : 1; /* secondary error */ - __u32 ioerr : 1; /* i/o-error alert */ - __u32 seqc : 3; /* sequence code */ + __u32 res0 : 1; + __u32 esf : 7; + __u32 lpum : 8; + __u32 arep : 1; + __u32 fvf : 5; + __u32 sacc : 2; + __u32 termc : 2; + __u32 devsc : 1; + __u32 serr : 1; + __u32 ioerr : 1; + __u32 seqc : 3; } __attribute__ ((packed)); -/* - * Format 0 Extended Status Word (ESW) +/** + * struct esw0 - Format 0 Extended Status Word (ESW) + * @sublog: subchannel logout + * @erw: extended report word + * @faddr: failing storage address + * @saddr: secondary ccw address */ struct esw0 { - struct sublog sublog; /* subchannel logout */ - struct erw erw; /* extended report word */ - __u32 faddr[2]; /* failing storage address */ - __u32 saddr; /* secondary ccw address */ + struct sublog sublog; + struct erw erw; + __u32 faddr[2]; + __u32 saddr; } __attribute__ ((packed)); -/* - * Format 1 Extended Status Word (ESW) +/** + * struct esw1 - Format 1 Extended Status Word (ESW) + * @zero0: reserved zeros + * @lpum: last path used mask + * @zero16: reserved zeros + * @erw: extended report word + * @zeros: three fullwords of zeros */ struct esw1 { - __u8 zero0; /* reserved zeros */ - __u8 lpum; /* last path used mask */ - __u16 zero16; /* reserved zeros */ - struct erw erw; /* extended report word */ - __u32 zeros[3]; /* 2 fullwords of zeros */ + __u8 zero0; + __u8 lpum; + __u16 zero16; + struct erw erw; + __u32 zeros[3]; } __attribute__ ((packed)); -/* - * Format 2 Extended Status Word (ESW) +/** + * struct esw2 - Format 2 Extended Status Word (ESW) + * @zero0: reserved zeros + * @lpum: last path used mask + * @dcti: device-connect-time interval + * @erw: extended report word + * @zeros: three fullwords of zeros */ struct esw2 { - __u8 zero0; /* reserved zeros */ - __u8 lpum; /* last path used mask */ - __u16 dcti; /* device-connect-time interval */ - struct erw erw; /* extended report word */ - __u32 zeros[3]; /* 2 fullwords of zeros */ + __u8 zero0; + __u8 lpum; + __u16 dcti; + struct erw erw; + __u32 zeros[3]; } __attribute__ ((packed)); -/* - * Format 3 Extended Status Word (ESW) +/** + * struct esw3 - Format 3 Extended Status Word (ESW) + * @zero0: reserved zeros + * @lpum: last path used mask + * @res: reserved + * @erw: extended report word + * @zeros: three fullwords of zeros */ struct esw3 { - __u8 zero0; /* reserved zeros */ - __u8 lpum; /* last path used mask */ - __u16 res; /* reserved */ - struct erw erw; /* extended report word */ - __u32 zeros[3]; /* 2 fullwords of zeros */ + __u8 zero0; + __u8 lpum; + __u16 res; + struct erw erw; + __u32 zeros[3]; } __attribute__ ((packed)); -/* - * interruption response block +/** + * struct irb - interruption response block + * @scsw: subchannel status word + * @esw: extened status word, 4 formats + * @ecw: extended control word + * + * The irb that is handed to the device driver when an interrupt occurs. For + * solicited interrupts, the common I/O layer already performs checks whether + * a field is valid; a field not being valid is always passed as %0. + * If a unit check occured, @ecw may contain sense data; this is retrieved + * by the common I/O layer itself if the device doesn't support concurrent + * sense (so that the device driver never needs to perform basic sene itself). + * For unsolicited interrupts, the irb is passed as-is (expect for sense data, + * if applicable). */ struct irb { - struct scsw scsw; /* subchannel status word */ - union { /* extended status word, 4 formats */ + struct scsw scsw; + union { struct esw0 esw0; struct esw1 esw1; struct esw2 esw2; struct esw3 esw3; } esw; - __u8 ecw[32]; /* extended control word */ + __u8 ecw[32]; } __attribute__ ((packed,aligned(4))); -/* - * command information word (CIW) layout +/** + * struct ciw - command information word (CIW) layout + * @et: entry type + * @reserved: reserved bits + * @ct: command type + * @cmd: command code + * @count: command count */ struct ciw { - __u32 et : 2; /* entry type */ - __u32 reserved : 2; /* reserved */ - __u32 ct : 4; /* command type */ - __u32 cmd : 8; /* command */ - __u32 count : 16; /* coun */ + __u32 et : 2; + __u32 reserved : 2; + __u32 ct : 4; + __u32 cmd : 8; + __u32 count : 16; } __attribute__ ((packed)); #define CIW_TYPE_RCD 0x0 /* read configuration data */ @@ -258,11 +349,32 @@ struct ciw { /* Sick revalidation of device. */ #define CIO_REVALIDATE 0x0008 +/** + * struct ccw_dev_id - unique identifier for ccw devices + * @ssid: subchannel set id + * @devno: device number + * + * This structure is not directly based on any hardware structure. The + * hardware identifies a device by its device number and its subchannel, + * which is in turn identified by its id. In order to get a unique identifier + * for ccw devices across subchannel sets, @struct ccw_dev_id has been + * introduced. + */ struct ccw_dev_id { u8 ssid; u16 devno; }; +/** + * ccw_device_id_is_equal() - compare two ccw_dev_ids + * @dev_id1: a ccw_dev_id + * @dev_id2: another ccw_dev_id + * Returns: + * %1 if the two structures are equal field-by-field, + * %0 if not. + * Context: + * any + */ static inline int ccw_dev_id_is_equal(struct ccw_dev_id *dev_id1, struct ccw_dev_id *dev_id2) { -- cgit v1.2.3-70-g09d2 From a0ea22c3d912de6044f83b07dcc26ee006106139 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Fri, 12 Oct 2007 16:11:19 +0200 Subject: [S390] cio: Minor style fixes. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/chp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c index 8ce4ff95cc9..3d49919a451 100644 --- a/drivers/s390/cio/chp.c +++ b/drivers/s390/cio/chp.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include @@ -86,7 +86,7 @@ u8 chp_get_sch_opm(struct subchannel *sch) opm = 0; chp_id_init(&chpid); - for (i=0; i < 8; i++) { + for (i = 0; i < 8; i++) { opm <<= 1; chpid.id = sch->schib.pmcw.chpid[i]; if (chp_get_status(chpid) != 0) @@ -118,7 +118,7 @@ static int s390_vary_chpid(struct chp_id chpid, int on) sprintf(dbf_text, on?"varyon%x.%02x":"varyoff%x.%02x", chpid.cssid, chpid.id); - CIO_TRACE_EVENT( 2, dbf_text); + CIO_TRACE_EVENT(2, dbf_text); status = chp_get_status(chpid); if (!on && !status) { @@ -353,7 +353,7 @@ static ssize_t chp_shared_show(struct device *dev, static DEVICE_ATTR(shared, 0444, chp_shared_show, NULL); -static struct attribute * chp_attrs[] = { +static struct attribute *chp_attrs[] = { &dev_attr_status.attr, &dev_attr_configure.attr, &dev_attr_type.attr, -- cgit v1.2.3-70-g09d2 From a55360df406cca797ac07d722688dd7ec29bf46e Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Fri, 12 Oct 2007 16:11:20 +0200 Subject: [S390] cio: Disable channel path measurements on shutdown/reboot. Make sure channel path measurements are disabled via a reboot notifier since we cannot rely on userspace to disable it again after enabling it. This is 1. clean and 2. makes sure that channel path measurements do not stay enabled after a reboot not involving a subsystem reset (which would lead to the channel subsystem scribbling onto random memory). Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/css.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'drivers') diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 08f6e7b6c99..5d83dd47146 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "css.h" #include "cio.h" @@ -632,6 +633,29 @@ static int __init setup_css(int nr) return 0; } +static int css_reboot_event(struct notifier_block *this, + unsigned long event, + void *ptr) +{ + int ret, i; + + ret = NOTIFY_DONE; + for (i = 0; i <= __MAX_CSSID; i++) { + struct channel_subsystem *css; + + css = channel_subsystems[i]; + if (css->cm_enabled) + if (chsc_secm(css, 0)) + ret = NOTIFY_BAD; + } + + return ret; +} + +static struct notifier_block css_reboot_notifier = { + .notifier_call = css_reboot_event, +}; + /* * Now that the driver core is running, we can setup our channel subsystem. * The struct subchannel's are created during probing (except for the @@ -697,12 +721,17 @@ init_channel_subsystem (void) if (ret) goto out_file; } + ret = register_reboot_notifier(&css_reboot_notifier); + if (ret) + goto out_pseudo; css_init_done = 1; ctl_set_bit(6, 28); for_each_subchannel(__init_channel_subsystem, NULL); return 0; +out_pseudo: + device_unregister(&channel_subsystems[i]->pseudo_subchannel->dev); out_file: device_remove_file(&channel_subsystems[i]->device, &dev_attr_cm_enable); -- cgit v1.2.3-70-g09d2 From 958974fb596ad037fb571cf2899f783764a83e1a Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Fri, 12 Oct 2007 16:11:21 +0200 Subject: [S390] cio: Introduce ccw_bus_type.shutdown. Introduce a shutdown method for the ccw bus that calls the driver specific shutdown method in struct ccw_driver. Switch zfcp to the new ccw_driver shutdown method. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/device.c | 10 ++++++++++ drivers/s390/scsi/zfcp_ccw.c | 10 ++++------ include/asm-s390/ccwdev.h | 2 ++ 3 files changed, 16 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 3943a4fde22..7fb271c60c2 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -1433,12 +1433,22 @@ ccw_device_remove (struct device *dev) return 0; } +static void ccw_device_shutdown(struct device *dev) +{ + struct ccw_device *cdev; + + cdev = to_ccwdev(dev); + if (cdev->drv && cdev->drv->shutdown) + cdev->drv->shutdown(cdev); +} + struct bus_type ccw_bus_type = { .name = "ccw", .match = ccw_bus_match, .uevent = ccw_uevent, .probe = ccw_device_probe, .remove = ccw_device_remove, + .shutdown = ccw_device_shutdown, }; /** diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c index 1c8f71a5985..c0d1c0eb320 100644 --- a/drivers/s390/scsi/zfcp_ccw.c +++ b/drivers/s390/scsi/zfcp_ccw.c @@ -28,7 +28,7 @@ static void zfcp_ccw_remove(struct ccw_device *); static int zfcp_ccw_set_online(struct ccw_device *); static int zfcp_ccw_set_offline(struct ccw_device *); static int zfcp_ccw_notify(struct ccw_device *, int); -static void zfcp_ccw_shutdown(struct device *); +static void zfcp_ccw_shutdown(struct ccw_device *); static struct ccw_device_id zfcp_ccw_device_id[] = { {CCW_DEVICE_DEVTYPE(ZFCP_CONTROL_UNIT_TYPE, @@ -51,9 +51,7 @@ static struct ccw_driver zfcp_ccw_driver = { .set_online = zfcp_ccw_set_online, .set_offline = zfcp_ccw_set_offline, .notify = zfcp_ccw_notify, - .driver = { - .shutdown = zfcp_ccw_shutdown, - }, + .shutdown = zfcp_ccw_shutdown, }; MODULE_DEVICE_TABLE(ccw, zfcp_ccw_device_id); @@ -277,12 +275,12 @@ zfcp_ccw_register(void) * Makes sure that QDIO queues are down when the system gets stopped. */ static void -zfcp_ccw_shutdown(struct device *dev) +zfcp_ccw_shutdown(struct ccw_device *cdev) { struct zfcp_adapter *adapter; down(&zfcp_data.config_sema); - adapter = dev_get_drvdata(dev); + adapter = dev_get_drvdata(&cdev->dev); zfcp_erp_adapter_shutdown(adapter, 0); zfcp_erp_wait(adapter); up(&zfcp_data.config_sema); diff --git a/include/asm-s390/ccwdev.h b/include/asm-s390/ccwdev.h index 8e961aa4b39..066aa70518c 100644 --- a/include/asm-s390/ccwdev.h +++ b/include/asm-s390/ccwdev.h @@ -102,6 +102,7 @@ struct ccw_device { * @set_online: called when setting device online * @set_offline: called when setting device offline * @notify: notify driver of device state changes + * @shutdown: called at device shutdown * @driver: embedded device driver structure * @name: device driver name */ @@ -113,6 +114,7 @@ struct ccw_driver { int (*set_online) (struct ccw_device *); int (*set_offline) (struct ccw_device *); int (*notify) (struct ccw_device *, int); + void (*shutdown) (struct ccw_device *); struct device_driver driver; char *name; }; -- cgit v1.2.3-70-g09d2 From 1842f2b1847155805f9cc8c834ef4272198b272b Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Fri, 12 Oct 2007 16:11:22 +0200 Subject: [S390] cio: Disable channel measurements (cmf) on shutdown/reboot. Disable channel measurements for all ccw devices via the ccw bus's shutdown method. Clear residual cmf related information that may be in the schib when setting up a new subchannel. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/cio.c | 5 +++++ drivers/s390/cio/device.c | 2 ++ 2 files changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index f2708d65be5..46905345159 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -619,6 +619,11 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid) sch->schib.pmcw.ena = 0; if ((sch->lpm & (sch->lpm - 1)) != 0) sch->schib.pmcw.mp = 1; /* multipath mode */ + /* clean up possible residual cmf stuff */ + sch->schib.pmcw.mme = 0; + sch->schib.pmcw.mbfc = 0; + sch->schib.pmcw.mbi = 0; + sch->schib.mba = 0; return 0; out: if (!cio_is_console(schid)) diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 7fb271c60c2..eea9b1de0af 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -21,6 +21,7 @@ #include #include #include /* HZ */ +#include #include "cio.h" #include "cio_debug.h" @@ -1440,6 +1441,7 @@ static void ccw_device_shutdown(struct device *dev) cdev = to_ccwdev(dev); if (cdev->drv && cdev->drv->shutdown) cdev->drv->shutdown(cdev); + disable_cmf(cdev); } struct bus_type ccw_bus_type = { -- cgit v1.2.3-70-g09d2 From e103178658f07131fee4e643596982b604cc63a9 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Fri, 12 Oct 2007 16:11:23 +0200 Subject: [S390] cio: Fix device attributes for early devices. Don't forget to set dev->groups for early ccw devices like the console device so the default attributes are created. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/device.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index eea9b1de0af..c96380db013 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -1123,6 +1123,7 @@ io_subchannel_probe (struct subchannel *sch) * device, e.g. the console. */ cdev = sch->dev.driver_data; + cdev->dev.groups = ccwdev_attr_groups; device_initialize(&cdev->dev); ccw_device_register(cdev); /* -- cgit v1.2.3-70-g09d2 From 3f4cf6e72f9f6a0b046b32881acc4f829f3aaa46 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Fri, 12 Oct 2007 16:11:26 +0200 Subject: [S390] cio: Avoid machine check vs. not operational races. There was the possibilty that an action like ccw_device_set_offline() triggered by a device gone machine check might trigger a not oper event. Unfortunately, this could lead to the situation that we tried to unregister a subchannel twice: Once from the slow path evaluation, and once via the not oper event. Fix this by always using the same mechanism (css_schedule_eval()) for triggering the unregister. This makes sure that unregistration will only be done once. As an added bonus, it also simplyfies the code. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/device.c | 3 +- drivers/s390/cio/device.h | 1 - drivers/s390/cio/device_fsm.c | 144 ++++++------------------------------------ 3 files changed, 21 insertions(+), 127 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index c96380db013..39f02b48e4c 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -969,8 +969,7 @@ out: wake_up(&ccw_device_init_wq); } -void -ccw_device_call_sch_unregister(struct work_struct *work) +static void ccw_device_call_sch_unregister(struct work_struct *work) { struct ccw_device_private *priv; struct ccw_device *cdev; diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h index b66338b7657..0d408960043 100644 --- a/drivers/s390/cio/device.h +++ b/drivers/s390/cio/device.h @@ -80,7 +80,6 @@ void io_subchannel_recog_done(struct ccw_device *cdev); int ccw_device_cancel_halt_clear(struct ccw_device *); void ccw_device_do_unreg_rereg(struct work_struct *); -void ccw_device_call_sch_unregister(struct work_struct *); void ccw_device_move_to_orphanage(struct work_struct *); int ccw_device_is_orphan(struct ccw_device *); diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index f772ef0a4f2..8867443b806 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -544,51 +544,6 @@ ccw_device_recog_timeout(struct ccw_device *cdev, enum dev_event dev_event) } -static void -ccw_device_nopath_notify(struct work_struct *work) -{ - struct ccw_device_private *priv; - struct ccw_device *cdev; - struct subchannel *sch; - int ret; - unsigned long flags; - - priv = container_of(work, struct ccw_device_private, kick_work); - cdev = priv->cdev; - spin_lock_irqsave(cdev->ccwlock, flags); - sch = to_subchannel(cdev->dev.parent); - /* Extra sanity. */ - if (sch->lpm) - goto out_unlock; - if (sch->driver && sch->driver->notify) { - spin_unlock_irqrestore(cdev->ccwlock, flags); - ret = sch->driver->notify(&sch->dev, CIO_NO_PATH); - spin_lock_irqsave(cdev->ccwlock, flags); - } else - ret = 0; - if (!ret) { - if (get_device(&sch->dev)) { - /* Driver doesn't want to keep device. */ - cio_disable_subchannel(sch); - if (get_device(&cdev->dev)) { - PREPARE_WORK(&cdev->private->kick_work, - ccw_device_call_sch_unregister); - queue_work(ccw_device_work, - &cdev->private->kick_work); - } else - put_device(&sch->dev); - } - } else { - cio_disable_subchannel(sch); - ccw_device_set_timeout(cdev, 0); - cdev->private->flags.fake_irb = 0; - cdev->private->state = DEV_STATE_DISCONNECTED; - wake_up(&cdev->private->wait_q); - } -out_unlock: - spin_unlock_irqrestore(cdev->ccwlock, flags); -} - void ccw_device_verify_done(struct ccw_device *cdev, int err) { @@ -632,12 +587,9 @@ ccw_device_verify_done(struct ccw_device *cdev, int err) default: /* Reset oper notify indication after verify error. */ cdev->private->flags.donotify = 0; - if (cdev->online) { - PREPARE_WORK(&cdev->private->kick_work, - ccw_device_nopath_notify); - queue_work(ccw_device_notify_work, - &cdev->private->kick_work); - } else + if (cdev->online) + dev_fsm_event(cdev, DEV_EVENT_NOTOPER); + else ccw_device_done(cdev, DEV_STATE_NOT_OPER); break; } @@ -691,11 +643,7 @@ ccw_device_disband_done(struct ccw_device *cdev, int err) break; default: cdev->private->flags.donotify = 0; - if (get_device(&cdev->dev)) { - PREPARE_WORK(&cdev->private->kick_work, - ccw_device_call_sch_unregister); - queue_work(ccw_device_work, &cdev->private->kick_work); - } + dev_fsm_event(cdev, DEV_EVENT_NOTOPER); ccw_device_done(cdev, DEV_STATE_NOT_OPER); break; } @@ -766,59 +714,16 @@ ccw_device_recog_notoper(struct ccw_device *cdev, enum dev_event dev_event) } /* - * Handle not operational event while offline. + * Handle not operational event in non-special state. */ -static void -ccw_device_offline_notoper(struct ccw_device *cdev, enum dev_event dev_event) +static void ccw_device_generic_notoper(struct ccw_device *cdev, + enum dev_event dev_event) { struct subchannel *sch; cdev->private->state = DEV_STATE_NOT_OPER; sch = to_subchannel(cdev->dev.parent); - if (get_device(&cdev->dev)) { - PREPARE_WORK(&cdev->private->kick_work, - ccw_device_call_sch_unregister); - queue_work(ccw_device_work, &cdev->private->kick_work); - } - wake_up(&cdev->private->wait_q); -} - -/* - * Handle not operational event while online. - */ -static void -ccw_device_online_notoper(struct ccw_device *cdev, enum dev_event dev_event) -{ - struct subchannel *sch; - int ret; - - sch = to_subchannel(cdev->dev.parent); - if (sch->driver->notify) { - spin_unlock_irq(cdev->ccwlock); - ret = sch->driver->notify(&sch->dev, - sch->lpm ? CIO_GONE : CIO_NO_PATH); - spin_lock_irq(cdev->ccwlock); - } else - ret = 0; - if (ret) { - ccw_device_set_timeout(cdev, 0); - cdev->private->flags.fake_irb = 0; - cdev->private->state = DEV_STATE_DISCONNECTED; - wake_up(&cdev->private->wait_q); - return; - } - cdev->private->state = DEV_STATE_NOT_OPER; - cio_disable_subchannel(sch); - if (sch->schib.scsw.actl != 0) { - // FIXME: not-oper indication to device driver ? - ccw_device_call_handler(cdev); - } - if (get_device(&cdev->dev)) { - PREPARE_WORK(&cdev->private->kick_work, - ccw_device_call_sch_unregister); - queue_work(ccw_device_work, &cdev->private->kick_work); - } - wake_up(&cdev->private->wait_q); + css_schedule_eval(sch->schid); } /* @@ -916,18 +821,9 @@ ccw_device_online_timeout(struct ccw_device *cdev, enum dev_event dev_event) cdev->private->state = DEV_STATE_TIMEOUT_KILL; return; } - if (ret == -ENODEV) { - struct subchannel *sch; - - sch = to_subchannel(cdev->dev.parent); - if (!sch->lpm) { - PREPARE_WORK(&cdev->private->kick_work, - ccw_device_nopath_notify); - queue_work(ccw_device_notify_work, - &cdev->private->kick_work); - } else - dev_fsm_event(cdev, DEV_EVENT_NOTOPER); - } else if (cdev->handler) + if (ret == -ENODEV) + dev_fsm_event(cdev, DEV_EVENT_NOTOPER); + else if (cdev->handler) cdev->handler(cdev, cdev->private->intparm, ERR_PTR(-ETIMEDOUT)); } @@ -1234,7 +1130,7 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = { [DEV_EVENT_VERIFY] = ccw_device_nop, }, [DEV_STATE_SENSE_PGID] = { - [DEV_EVENT_NOTOPER] = ccw_device_online_notoper, + [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, [DEV_EVENT_INTERRUPT] = ccw_device_sense_pgid_irq, [DEV_EVENT_TIMEOUT] = ccw_device_onoff_timeout, [DEV_EVENT_VERIFY] = ccw_device_nop, @@ -1246,50 +1142,50 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = { [DEV_EVENT_VERIFY] = ccw_device_nop, }, [DEV_STATE_OFFLINE] = { - [DEV_EVENT_NOTOPER] = ccw_device_offline_notoper, + [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, [DEV_EVENT_INTERRUPT] = ccw_device_offline_irq, [DEV_EVENT_TIMEOUT] = ccw_device_nop, [DEV_EVENT_VERIFY] = ccw_device_nop, }, [DEV_STATE_VERIFY] = { - [DEV_EVENT_NOTOPER] = ccw_device_online_notoper, + [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, [DEV_EVENT_INTERRUPT] = ccw_device_verify_irq, [DEV_EVENT_TIMEOUT] = ccw_device_onoff_timeout, [DEV_EVENT_VERIFY] = ccw_device_delay_verify, }, [DEV_STATE_ONLINE] = { - [DEV_EVENT_NOTOPER] = ccw_device_online_notoper, + [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, [DEV_EVENT_INTERRUPT] = ccw_device_irq, [DEV_EVENT_TIMEOUT] = ccw_device_online_timeout, [DEV_EVENT_VERIFY] = ccw_device_online_verify, }, [DEV_STATE_W4SENSE] = { - [DEV_EVENT_NOTOPER] = ccw_device_online_notoper, + [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, [DEV_EVENT_INTERRUPT] = ccw_device_w4sense, [DEV_EVENT_TIMEOUT] = ccw_device_nop, [DEV_EVENT_VERIFY] = ccw_device_online_verify, }, [DEV_STATE_DISBAND_PGID] = { - [DEV_EVENT_NOTOPER] = ccw_device_online_notoper, + [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, [DEV_EVENT_INTERRUPT] = ccw_device_disband_irq, [DEV_EVENT_TIMEOUT] = ccw_device_onoff_timeout, [DEV_EVENT_VERIFY] = ccw_device_nop, }, [DEV_STATE_BOXED] = { - [DEV_EVENT_NOTOPER] = ccw_device_offline_notoper, + [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, [DEV_EVENT_INTERRUPT] = ccw_device_stlck_done, [DEV_EVENT_TIMEOUT] = ccw_device_stlck_done, [DEV_EVENT_VERIFY] = ccw_device_nop, }, /* states to wait for i/o completion before doing something */ [DEV_STATE_CLEAR_VERIFY] = { - [DEV_EVENT_NOTOPER] = ccw_device_online_notoper, + [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, [DEV_EVENT_INTERRUPT] = ccw_device_clear_verify, [DEV_EVENT_TIMEOUT] = ccw_device_nop, [DEV_EVENT_VERIFY] = ccw_device_nop, }, [DEV_STATE_TIMEOUT_KILL] = { - [DEV_EVENT_NOTOPER] = ccw_device_online_notoper, + [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, [DEV_EVENT_INTERRUPT] = ccw_device_killing_irq, [DEV_EVENT_TIMEOUT] = ccw_device_killing_timeout, [DEV_EVENT_VERIFY] = ccw_device_nop, //FIXME -- cgit v1.2.3-70-g09d2 From 731475c92ed587ac0e112c49b47b12de8d0ab609 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 12 Oct 2007 16:11:27 +0200 Subject: [S390] zcrypt: make init/exit functions static. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/zcrypt_mono.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/crypto/zcrypt_mono.c b/drivers/s390/crypto/zcrypt_mono.c index 2a9349ad68b..44253fdd413 100644 --- a/drivers/s390/crypto/zcrypt_mono.c +++ b/drivers/s390/crypto/zcrypt_mono.c @@ -45,7 +45,7 @@ /** * The module initialization code. */ -int __init zcrypt_init(void) +static int __init zcrypt_init(void) { int rc; @@ -86,7 +86,7 @@ out: /** * The module termination code. */ -void __exit zcrypt_exit(void) +static void __exit zcrypt_exit(void) { zcrypt_cex2a_exit(); zcrypt_pcixcc_exit(); -- cgit v1.2.3-70-g09d2 From 16db63fda0c63de7a7feb59c6ca59ce7e2670ffb Mon Sep 17 00:00:00 2001 From: Ralph Wuerthner Date: Fri, 12 Oct 2007 16:11:28 +0200 Subject: [S390] zcrypt: remove duplicated struct CPRBX definition Signed-off-by: Ralph Wuerthner --- drivers/s390/crypto/zcrypt_pcixcc.c | 2 +- drivers/s390/crypto/zcrypt_pcixcc.h | 45 ------------------------------------- include/asm-s390/zcrypt.h | 4 ++-- 3 files changed, 3 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c index 64948788d30..c28369260c2 100644 --- a/drivers/s390/crypto/zcrypt_pcixcc.c +++ b/drivers/s390/crypto/zcrypt_pcixcc.c @@ -277,7 +277,7 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev, }; struct { struct type6_hdr hdr; - struct ica_CPRBX cprbx; + struct CPRBX cprbx; } __attribute__((packed)) *msg = ap_msg->message; int rcblen = CEIL4(xcRB->request_control_blk_length); diff --git a/drivers/s390/crypto/zcrypt_pcixcc.h b/drivers/s390/crypto/zcrypt_pcixcc.h index a78ff307fd1..8cb7d7a6973 100644 --- a/drivers/s390/crypto/zcrypt_pcixcc.h +++ b/drivers/s390/crypto/zcrypt_pcixcc.h @@ -28,51 +28,6 @@ #ifndef _ZCRYPT_PCIXCC_H_ #define _ZCRYPT_PCIXCC_H_ -/** - * CPRBX - * Note that all shorts and ints are big-endian. - * All pointer fields are 16 bytes long, and mean nothing. - * - * A request CPRB is followed by a request_parameter_block. - * - * The request (or reply) parameter block is organized thus: - * function code - * VUD block - * key block - */ -struct CPRBX { - unsigned short cprb_len; /* CPRB length 220 */ - unsigned char cprb_ver_id; /* CPRB version id. 0x02 */ - unsigned char pad_000[3]; /* Alignment pad bytes */ - unsigned char func_id[2]; /* function id 0x5432 */ - unsigned char cprb_flags[4]; /* Flags */ - unsigned int req_parml; /* request parameter buffer len */ - unsigned int req_datal; /* request data buffer */ - unsigned int rpl_msgbl; /* reply message block length */ - unsigned int rpld_parml; /* replied parameter block len */ - unsigned int rpl_datal; /* reply data block len */ - unsigned int rpld_datal; /* replied data block len */ - unsigned int req_extbl; /* request extension block len */ - unsigned char pad_001[4]; /* reserved */ - unsigned int rpld_extbl; /* replied extension block len */ - unsigned char req_parmb[16]; /* request parm block 'address' */ - unsigned char req_datab[16]; /* request data block 'address' */ - unsigned char rpl_parmb[16]; /* reply parm block 'address' */ - unsigned char rpl_datab[16]; /* reply data block 'address' */ - unsigned char req_extb[16]; /* request extension block 'addr'*/ - unsigned char rpl_extb[16]; /* reply extension block 'addres'*/ - unsigned short ccp_rtcode; /* server return code */ - unsigned short ccp_rscode; /* server reason code */ - unsigned int mac_data_len; /* Mac Data Length */ - unsigned char logon_id[8]; /* Logon Identifier */ - unsigned char mac_value[8]; /* Mac Value */ - unsigned char mac_content_flgs;/* Mac content flag byte */ - unsigned char pad_002; /* Alignment */ - unsigned short domain; /* Domain */ - unsigned char pad_003[12]; /* Domain masks */ - unsigned char pad_004[36]; /* reserved */ -} __attribute__((packed)); - int zcrypt_pcixcc_init(void); void zcrypt_pcixcc_exit(void); diff --git a/include/asm-s390/zcrypt.h b/include/asm-s390/zcrypt.h index b90e55888a5..a5dada61775 100644 --- a/include/asm-s390/zcrypt.h +++ b/include/asm-s390/zcrypt.h @@ -91,7 +91,7 @@ struct ica_rsa_modexpo_crt { * VUD block * key block */ -struct ica_CPRBX { +struct CPRBX { unsigned short cprb_len; /* CPRB length 220 */ unsigned char cprb_ver_id; /* CPRB version id. 0x02 */ unsigned char pad_000[3]; /* Alignment pad bytes */ @@ -130,7 +130,7 @@ struct ica_CPRBX { unsigned char cntrl_domain[4];/* Control domain */ unsigned char S390enf_mask[4];/* S/390 enforcement mask */ unsigned char pad_004[36]; /* reserved */ -}; +} __attribute__((packed)); /** * xcRB -- cgit v1.2.3-70-g09d2 From 39aa7cf612cc4e7f688c18f04c35afb51c57472e Mon Sep 17 00:00:00 2001 From: Ralph Wuerthner Date: Fri, 12 Oct 2007 16:11:29 +0200 Subject: [S390] zcrypt: fix ap_reset_domain() Resetting of a all queues within a domain requires that a domain must be selected first. Signed-off-by: Ralph Wuerthner Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/ap_bus.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 90bd2201451..d334b0f7a1e 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -1231,8 +1231,9 @@ static void ap_reset_domain(void) { int i; - for (i = 0; i < AP_DEVICES; i++) - ap_reset_queue(AP_MKQID(i, ap_domain_index)); + if (ap_domain_index != -1) + for (i = 0; i < AP_DEVICES; i++) + ap_reset_queue(AP_MKQID(i, ap_domain_index)); } static void ap_reset_all(void) -- cgit v1.2.3-70-g09d2 From 2af48080e100d66db8f086af70a70713a953a83d Mon Sep 17 00:00:00 2001 From: Ralph Wuerthner Date: Fri, 12 Oct 2007 16:11:30 +0200 Subject: [S390] zcrypt: fix PCIXCC/CEX2C error recovery Symptom: zcrypt fails by setting all PCIXCC/CEX2C cards offline for a certain type of invalid keys. Problem: zcrypt does not handle rc=12/rs=769 request responses correctly Solution: modify convert_type86_ica() to handle these error codes correctly Signed-off-by: Ralph Wuerthner Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/zcrypt_pcixcc.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c index c28369260c2..70b9ddc8cf9 100644 --- a/drivers/s390/crypto/zcrypt_pcixcc.c +++ b/drivers/s390/crypto/zcrypt_pcixcc.c @@ -432,14 +432,17 @@ static int convert_type86_ica(struct zcrypt_device *zdev, } if (service_rc == 8 && service_rs == 770) { PDEBUG("Invalid key length on PCIXCC/CEX2C\n"); - zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD; - return -EAGAIN; + return -EINVAL; } if (service_rc == 8 && service_rs == 783) { PDEBUG("Extended bitlengths not enabled on PCIXCC/CEX2C\n"); zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD; return -EAGAIN; } + if (service_rc == 12 && service_rs == 769) { + PDEBUG("Invalid key on PCIXCC/CEX2C\n"); + return -EINVAL; + } PRINTK("Unknown service rc/rs (PCIXCC/CEX2C): %d/%d\n", service_rc, service_rs); zdev->online = 0; -- cgit v1.2.3-70-g09d2 From 364c85584e030f7cfc25e9d27ca893dee6f4bf8e Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 12 Oct 2007 16:11:35 +0200 Subject: [S390] Get rid of a bunch of sparse warnings again. Also removes a bunch of ^L in drivers/s390/cio/cmf.c Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/audit.c | 7 +------ arch/s390/kernel/audit.h | 15 +++++++++++++++ arch/s390/kernel/compat_audit.c | 1 + drivers/s390/char/con3270.c | 3 +-- drivers/s390/char/sclp.c | 5 ++--- drivers/s390/char/tty3270.c | 9 ++++++--- drivers/s390/char/tty3270.h | 16 ++++++++++++++++ drivers/s390/cio/chp.c | 8 ++++++-- drivers/s390/cio/cmf.c | 4 +--- drivers/s390/scsi/zfcp_dbf.c | 10 +++++----- drivers/s390/scsi/zfcp_erp.c | 18 ++++++++---------- 11 files changed, 62 insertions(+), 34 deletions(-) create mode 100644 arch/s390/kernel/audit.h create mode 100644 drivers/s390/char/tty3270.h (limited to 'drivers') diff --git a/arch/s390/kernel/audit.c b/arch/s390/kernel/audit.c index d1c76fe10f2..f4932c22ebe 100644 --- a/arch/s390/kernel/audit.c +++ b/arch/s390/kernel/audit.c @@ -2,6 +2,7 @@ #include #include #include +#include "audit.h" static unsigned dir_class[] = { #include @@ -40,7 +41,6 @@ int audit_classify_arch(int arch) int audit_classify_syscall(int abi, unsigned syscall) { #ifdef CONFIG_COMPAT - extern int s390_classify_syscall(unsigned); if (abi == AUDIT_ARCH_S390) return s390_classify_syscall(syscall); #endif @@ -61,11 +61,6 @@ int audit_classify_syscall(int abi, unsigned syscall) static int __init audit_classes_init(void) { #ifdef CONFIG_COMPAT - extern __u32 s390_dir_class[]; - extern __u32 s390_write_class[]; - extern __u32 s390_read_class[]; - extern __u32 s390_chattr_class[]; - extern __u32 s390_signal_class[]; audit_register_class(AUDIT_CLASS_WRITE_32, s390_write_class); audit_register_class(AUDIT_CLASS_READ_32, s390_read_class); audit_register_class(AUDIT_CLASS_DIR_WRITE_32, s390_dir_class); diff --git a/arch/s390/kernel/audit.h b/arch/s390/kernel/audit.h new file mode 100644 index 00000000000..12b56f4b5a7 --- /dev/null +++ b/arch/s390/kernel/audit.h @@ -0,0 +1,15 @@ +#ifndef __ARCH_S390_KERNEL_AUDIT_H +#define __ARCH_S390_KERNEL_AUDIT_H + +#include + +#ifdef CONFIG_COMPAT +extern int s390_classify_syscall(unsigned); +extern __u32 s390_dir_class[]; +extern __u32 s390_write_class[]; +extern __u32 s390_read_class[]; +extern __u32 s390_chattr_class[]; +extern __u32 s390_signal_class[]; +#endif /* CONFIG_COMPAT */ + +#endif /* __ARCH_S390_KERNEL_AUDIT_H */ diff --git a/arch/s390/kernel/compat_audit.c b/arch/s390/kernel/compat_audit.c index 0569f5126e4..d6487bf879e 100644 --- a/arch/s390/kernel/compat_audit.c +++ b/arch/s390/kernel/compat_audit.c @@ -1,5 +1,6 @@ #undef __s390x__ #include +#include "audit.h" unsigned s390_dir_class[] = { #include diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c index fd3479119eb..0b040557db0 100644 --- a/drivers/s390/char/con3270.c +++ b/drivers/s390/char/con3270.c @@ -22,6 +22,7 @@ #include #include "raw3270.h" +#include "tty3270.h" #include "ctrlchar.h" #define CON3270_OUTPUT_BUFFER_SIZE 1024 @@ -507,8 +508,6 @@ con3270_write(struct console *co, const char *str, unsigned int count) spin_unlock_irqrestore(&cp->view.lock,flags); } -extern struct tty_driver *tty3270_driver; - static struct tty_driver * con3270_device(struct console *c, int *index) { diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index fa62e694405..25629b92dec 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c @@ -93,6 +93,7 @@ static volatile enum sclp_mask_state_t { #define SCLP_RETRY_INTERVAL 30 static void sclp_process_queue(void); +static void __sclp_make_read_req(void); static int sclp_init_mask(int calculate); static int sclp_init(void); @@ -115,7 +116,6 @@ sclp_service_call(sclp_cmdw_t command, void *sccb) return 0; } -static inline void __sclp_make_read_req(void); static void __sclp_queue_read_req(void) @@ -318,8 +318,7 @@ sclp_read_cb(struct sclp_req *req, void *data) } /* Prepare read event data request. Called while sclp_lock is locked. */ -static inline void -__sclp_make_read_req(void) +static void __sclp_make_read_req(void) { struct sccb_header *sccb; diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c index bc33068b9ce..70b1980a08b 100644 --- a/drivers/s390/char/tty3270.c +++ b/drivers/s390/char/tty3270.c @@ -25,8 +25,8 @@ #include #include - #include "raw3270.h" +#include "tty3270.h" #include "keyboard.h" #define TTY3270_CHAR_BUF_SIZE 256 @@ -1338,8 +1338,11 @@ tty3270_getpar(struct tty3270 *tp, int ix) static void tty3270_goto_xy(struct tty3270 *tp, int cx, int cy) { - tp->cx = min_t(int, tp->view.cols - 1, max_t(int, 0, cx)); - cy = min_t(int, tp->view.rows - 3, max_t(int, 0, cy)); + int max_cx = max(0, cx); + int max_cy = max(0, cy); + + tp->cx = min_t(int, tp->view.cols - 1, max_cx); + cy = min_t(int, tp->view.rows - 3, max_cy); if (cy != tp->cy) { tty3270_convert_line(tp, tp->cy); tp->cy = cy; diff --git a/drivers/s390/char/tty3270.h b/drivers/s390/char/tty3270.h new file mode 100644 index 00000000000..799da57f039 --- /dev/null +++ b/drivers/s390/char/tty3270.h @@ -0,0 +1,16 @@ +/* + * drivers/s390/char/tty3270.h + * + * Copyright IBM Corp. 2007 + * + */ + +#ifndef __DRIVERS_S390_CHAR_TTY3270_H +#define __DRIVERS_S390_CHAR_TTY3270_H + +#include +#include + +extern struct tty_driver *tty3270_driver; + +#endif /* __DRIVERS_S390_CHAR_TTY3270_H */ diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c index 3d49919a451..42c1f4659ad 100644 --- a/drivers/s390/cio/chp.c +++ b/drivers/s390/cio/chp.c @@ -140,9 +140,11 @@ static ssize_t chp_measurement_chars_read(struct kobject *kobj, char *buf, loff_t off, size_t count) { struct channel_path *chp; + struct device *device; unsigned int size; - chp = to_channelpath(container_of(kobj, struct device, kobj)); + device = container_of(kobj, struct device, kobj); + chp = to_channelpath(device); if (!chp->cmg_chars) return 0; @@ -193,9 +195,11 @@ static ssize_t chp_measurement_read(struct kobject *kobj, { struct channel_path *chp; struct channel_subsystem *css; + struct device *device; unsigned int size; - chp = to_channelpath(container_of(kobj, struct device, kobj)); + device = container_of(kobj, struct device, kobj); + chp = to_channelpath(device); css = to_css(chp->dev.parent); size = sizeof(struct cmg_entry); diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c index 6ef0ab89547..b960f66843e 100644 --- a/drivers/s390/cio/cmf.c +++ b/drivers/s390/cio/cmf.c @@ -489,7 +489,6 @@ static struct cmb_area cmb_area = { .num_channels = 1024, }; - /* ****** old style CMB handling ********/ /* @@ -812,7 +811,7 @@ static struct cmb_operations cmbops_basic = { .align = align_cmb, .attr_group = &cmf_attr_group, }; - + /* ******** extended cmb handling ********/ /** @@ -1079,7 +1078,6 @@ static struct cmb_operations cmbops_extended = { .align = align_cmbe, .attr_group = &cmf_attr_group_ext, }; - static ssize_t cmb_show_attr(struct device *dev, char *buf, enum cmb_index idx) { diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 5f3212440f6..ffa3bf75694 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -19,8 +19,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include +#include #include "zfcp_ext.h" static u32 dbfsize = 4; @@ -35,17 +35,17 @@ static int zfcp_dbf_stck(char *out_buf, const char *label, unsigned long long stck) { unsigned long long sec; - struct timespec xtime; + struct timespec dbftime; int len = 0; stck -= 0x8126d60e46000000LL - (0x3c26700LL * 1000000 * 4096); sec = stck >> 12; do_div(sec, 1000000); - xtime.tv_sec = sec; + dbftime.tv_sec = sec; stck -= (sec * 1000000) << 12; - xtime.tv_nsec = ((stck * 1000) >> 12); + dbftime.tv_nsec = ((stck * 1000) >> 12); len += sprintf(out_buf + len, "%-24s%011lu:%06lu\n", - label, xtime.tv_sec, xtime.tv_nsec); + label, dbftime.tv_sec, dbftime.tv_nsec); return len; } diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index d8cd75ce2d9..16b4418ab25 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -54,7 +54,7 @@ static int zfcp_erp_strategy_check_adapter(struct zfcp_adapter *, int); static int zfcp_erp_strategy_statechange(int, u32, struct zfcp_adapter *, struct zfcp_port *, struct zfcp_unit *, int); -static inline int zfcp_erp_strategy_statechange_detected(atomic_t *, u32); +static int zfcp_erp_strategy_statechange_detected(atomic_t *, u32); static int zfcp_erp_strategy_followup_actions(int, struct zfcp_adapter *, struct zfcp_port *, struct zfcp_unit *, int); @@ -106,8 +106,8 @@ static void zfcp_erp_action_cleanup(int, struct zfcp_adapter *, static void zfcp_erp_action_ready(struct zfcp_erp_action *); static int zfcp_erp_action_exists(struct zfcp_erp_action *); -static inline void zfcp_erp_action_to_ready(struct zfcp_erp_action *); -static inline void zfcp_erp_action_to_running(struct zfcp_erp_action *); +static void zfcp_erp_action_to_ready(struct zfcp_erp_action *); +static void zfcp_erp_action_to_running(struct zfcp_erp_action *); static void zfcp_erp_memwait_handler(unsigned long); @@ -952,7 +952,7 @@ zfcp_erp_memwait_handler(unsigned long data) * action gets an appropriate flag and will be processed * accordingly */ -void zfcp_erp_timeout_handler(unsigned long data) +static void zfcp_erp_timeout_handler(unsigned long data) { struct zfcp_erp_action *erp_action = (struct zfcp_erp_action *) data; struct zfcp_adapter *adapter = erp_action->adapter; @@ -1491,7 +1491,7 @@ zfcp_erp_strategy_statechange(int action, return retval; } -static inline int +static int zfcp_erp_strategy_statechange_detected(atomic_t * target_status, u32 erp_status) { return @@ -2001,7 +2001,7 @@ zfcp_erp_adapter_strategy_generic(struct zfcp_erp_action *erp_action, int close) * returns: 0 - successful setup * !0 - failed setup */ -int +static int zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *erp_action) { int retval; @@ -3248,8 +3248,7 @@ static void zfcp_erp_action_dismiss_unit(struct zfcp_unit *unit) zfcp_erp_action_dismiss(&unit->erp_action); } -static inline void -zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action) +static void zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action) { struct zfcp_adapter *adapter = erp_action->adapter; @@ -3258,8 +3257,7 @@ zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action) list_move(&erp_action->list, &erp_action->adapter->erp_running_head); } -static inline void -zfcp_erp_action_to_ready(struct zfcp_erp_action *erp_action) +static void zfcp_erp_action_to_ready(struct zfcp_erp_action *erp_action) { struct zfcp_adapter *adapter = erp_action->adapter; -- cgit v1.2.3-70-g09d2 From b18a2db416088ad54a4bfb59c0b932be383aee83 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 12 Oct 2007 16:11:38 +0200 Subject: [S390] qdio: dont cast function pointers and use them to call functions. According to C99 6.3.2.3 it's undefined what happens if a converted pointer is used to call a function whose type is not compatible with the pointed-to type. That's what the qdio code is doing, so fix it. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/qdio.c | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c index d8d479876ec..151636cc8f2 100644 --- a/drivers/s390/cio/qdio.c +++ b/drivers/s390/cio/qdio.c @@ -1024,9 +1024,9 @@ __qdio_outbound_processing(struct qdio_q *q) } static void -qdio_outbound_processing(struct qdio_q *q) +qdio_outbound_processing(unsigned long q) { - __qdio_outbound_processing(q); + __qdio_outbound_processing((struct qdio_q *) q); } /************************* INBOUND ROUTINES *******************************/ @@ -1449,9 +1449,10 @@ out: } static void -tiqdio_inbound_processing(struct qdio_q *q) +tiqdio_inbound_processing(unsigned long q) { - __tiqdio_inbound_processing(q, atomic_read(&spare_indicator_usecount)); + __tiqdio_inbound_processing((struct qdio_q *) q, + atomic_read(&spare_indicator_usecount)); } static void @@ -1494,9 +1495,9 @@ again: } static void -qdio_inbound_processing(struct qdio_q *q) +qdio_inbound_processing(unsigned long q) { - __qdio_inbound_processing(q); + __qdio_inbound_processing((struct qdio_q *) q); } /************************* MAIN ROUTINES *******************************/ @@ -1760,12 +1761,15 @@ qdio_fill_qs(struct qdio_irq *irq_ptr, struct ccw_device *cdev, q->handler=input_handler; q->dev_st_chg_ind=irq_ptr->dev_st_chg_ind; - q->tasklet.data=(unsigned long)q; /* q->is_thinint_q isn't valid at this time, but - * irq_ptr->is_thinint_irq is */ - q->tasklet.func=(void(*)(unsigned long)) - ((irq_ptr->is_thinint_irq)?&tiqdio_inbound_processing: - &qdio_inbound_processing); + * irq_ptr->is_thinint_irq is + */ + if (irq_ptr->is_thinint_irq) + tasklet_init(&q->tasklet, tiqdio_inbound_processing, + (unsigned long) q); + else + tasklet_init(&q->tasklet, qdio_inbound_processing, + (unsigned long) q); /* actually this is not used for inbound queues. yet. */ atomic_set(&q->busy_siga_counter,0); @@ -1836,13 +1840,10 @@ qdio_fill_qs(struct qdio_irq *irq_ptr, struct ccw_device *cdev, q->last_move_ftc=0; q->handler=output_handler; - q->tasklet.data=(unsigned long)q; - q->tasklet.func=(void(*)(unsigned long)) - &qdio_outbound_processing; - q->timer.function=(void(*)(unsigned long)) - &qdio_outbound_processing; - q->timer.data = (long)q; - init_timer(&q->timer); + tasklet_init(&q->tasklet, qdio_outbound_processing, + (unsigned long) q); + setup_timer(&q->timer, qdio_outbound_processing, + (unsigned long) q); atomic_set(&q->busy_siga_counter,0); q->timing.busy_start=0; -- cgit v1.2.3-70-g09d2 From e108cebb21316714de43767e242316c784471740 Mon Sep 17 00:00:00 2001 From: vignesh babu Date: Fri, 12 Oct 2007 16:11:39 +0200 Subject: [S390] is_power_of_2 in drivers/s390/block/dasd_int.h Replacing n & (n - 1) for power of 2 check by is_power_of_2(n) Signed-off-by: vignesh babu Signed-off-by: Martin Schwidefsky Signed-off-by: Heiko Carstens --- drivers/s390/block/dasd_int.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index aeda5268244..d427daeef51 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -53,6 +53,7 @@ #include #include #include +#include #include #include #include @@ -456,7 +457,7 @@ dasd_free_chunk(struct list_head *chunk_list, void *mem) static inline int dasd_check_blocksize(int bsize) { - if (bsize < 512 || bsize > 4096 || (bsize & (bsize - 1)) != 0) + if (bsize < 512 || bsize > 4096 || !is_power_of_2(bsize)) return -EMEDIUMTYPE; return 0; } -- cgit v1.2.3-70-g09d2 From c622498e5c82217cda7f661eebbabdaad0814659 Mon Sep 17 00:00:00 2001 From: Ursula Braun Date: Fri, 12 Oct 2007 16:11:40 +0200 Subject: [S390] qdio: change QDIO performance_stats error message priority Signed-off-by: Ursula Braun Signed-off-by: Martin Schwidefsky Signed-off-by: Heiko Carstens --- drivers/s390/cio/qdio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c index 151636cc8f2..40a3208c7cf 100644 --- a/drivers/s390/cio/qdio.c +++ b/drivers/s390/cio/qdio.c @@ -3727,7 +3727,7 @@ qdio_performance_stats_store(struct bus_type *bus, const char *buf, size_t count #endif /* CONFIG_64BIT */ } } else { - QDIO_PRINT_WARN("QDIO performance_stats: write 0 or 1 to this file!\n"); + QDIO_PRINT_ERR("QDIO performance_stats: write 0 or 1 to this file!\n"); return -EINVAL; } return count; -- cgit v1.2.3-70-g09d2 From cebe0fe70fbf033a1a6b7c5c8b79eb13060a4ab7 Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Fri, 12 Oct 2007 16:11:43 +0200 Subject: [S390] Remove obsolete recommendation for 8M ramdisk size. Signed-off-by: Robert P. J. Day Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/block/Kconfig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 4245b7f80a4..ca4d7f0d09b 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -361,8 +361,7 @@ config BLK_DEV_RAM_SIZE default "4096" help The default value is 4096 kilobytes. Only change this if you know - what are you doing. If you are using IBM S/390, then set this to - 8192. + what are you doing. config BLK_DEV_RAM_BLOCKSIZE int "Default RAM disk block size (bytes)" -- cgit v1.2.3-70-g09d2 From 53a0868cb4d77dcba8e95e1033361ffdb6e510e2 Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Fri, 12 Oct 2007 16:11:44 +0200 Subject: [S390] zcore: fix inline assembly in memcpy_real() memcpy_real uses the mvcle instruction. This instruction alters all used registers (source, destination and 2 x count). Therefore we have to flag those registers as input/output registers (+d). In addition to that, we have to specify, that we read from memory designated by "src" and write to memory designated by "dest". Signed-off-by: Michael Holzheu Signed-off-by: Martin Schwidefsky --- drivers/s390/char/zcore.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c index 3712ede1672..7073daf7798 100644 --- a/drivers/s390/char/zcore.c +++ b/drivers/s390/char/zcore.c @@ -141,15 +141,16 @@ static int memcpy_real(void *dest, unsigned long src, size_t count) if (count == 0) return 0; - flags = __raw_local_irq_stnsm(0xf8); /* switch to real mode */ + flags = __raw_local_irq_stnsm(0xf8UL); /* switch to real mode */ asm volatile ( "0: mvcle %1,%2,0x0\n" "1: jo 0b\n" " lhi %0,0x0\n" "2:\n" EX_TABLE(1b,2b) - : "+d" (rc) - : "d" (_dest), "d" (_src), "d" (_len1), "d" (_len2) + : "+d" (rc), "+d" (_dest), "+d" (_src), "+d" (_len1), + "+d" (_len2), "=m" (*((long*)dest)) + : "m" (*((long*)src)) : "cc", "memory"); __raw_local_irq_ssm(flags); -- cgit v1.2.3-70-g09d2 From 1b9fd76e30368489b561db5794b3831bcc28c8bc Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Fri, 12 Oct 2007 16:11:47 +0200 Subject: [S390] tape: Fix medium state handling Currently there are situations, where the tape medium state (loaded, unloaded, unknown) is not set correctly. The reason is that the medium association field is used to determine the medium state. This not always leads to correct results. To fix that we use another field of the medium sense data instead. Signed-off-by: Michael Holzheu Signed-off-by: Martin Schwidefsky --- drivers/s390/char/tape_3590.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c index 9f244c591ee..da25f8e2415 100644 --- a/drivers/s390/char/tape_3590.c +++ b/drivers/s390/char/tape_3590.c @@ -708,16 +708,22 @@ static void tape_3590_med_state_set(struct tape_device *device, c_info = &TAPE_3590_CRYPT_INFO(device); - if (sense->masst == MSENSE_UNASSOCIATED) { + DBF_EVENT(6, "medium state: %x:%x\n", sense->macst, sense->masst); + switch (sense->macst) { + case 0x04: + case 0x05: + case 0x06: tape_med_state_set(device, MS_UNLOADED); TAPE_3590_CRYPT_INFO(device).medium_status = 0; return; - } - if (sense->masst != MSENSE_ASSOCIATED_MOUNT) { - PRINT_ERR("Unknown medium state: %x\n", sense->masst); + case 0x08: + case 0x09: + tape_med_state_set(device, MS_LOADED); + break; + default: + tape_med_state_set(device, MS_UNKNOWN); return; } - tape_med_state_set(device, MS_LOADED); c_info->medium_status |= TAPE390_MEDIUM_LOADED_MASK; if (sense->flags & MSENSE_CRYPT_MASK) { PRINT_INFO("Medium is encrypted (%04x)\n", sense->flags); @@ -835,15 +841,17 @@ tape_3590_unsolicited_irq(struct tape_device *device, struct irb *irb) /* Probably result of halt ssch */ return TAPE_IO_PENDING; else if (irb->scsw.dstat == 0x85) - /* Device Ready -> check medium state */ - tape_3590_schedule_work(device, TO_MSEN); - else if (irb->scsw.dstat & DEV_STAT_ATTENTION) + /* Device Ready */ + DBF_EVENT(3, "unsol.irq! tape ready: %08x\n", device->cdev_id); + else if (irb->scsw.dstat & DEV_STAT_ATTENTION) { tape_3590_schedule_work(device, TO_READ_ATTMSG); - else { + } else { DBF_EVENT(3, "unsol.irq! dev end: %08x\n", device->cdev_id); PRINT_WARN("Unsolicited IRQ (Device End) caught.\n"); tape_dump_sense(device, NULL, irb); } + /* check medium state */ + tape_3590_schedule_work(device, TO_MSEN); return TAPE_IO_SUCCESS; } -- cgit v1.2.3-70-g09d2 From 2b12f996c992334f65f6d9e0a3e731ec049fdad3 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 12 Oct 2007 16:11:48 +0200 Subject: [S390] vmwatchdog: fix broken inline assembly. Constraint for err is wrong since it is preinitialized and the code relies on it in case of an exception. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/char/vmwatchdog.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/char/vmwatchdog.c b/drivers/s390/char/vmwatchdog.c index 680b9b58b80..6f40facb1c4 100644 --- a/drivers/s390/char/vmwatchdog.c +++ b/drivers/s390/char/vmwatchdog.c @@ -66,8 +66,8 @@ static int __diag288(enum vmwdt_func func, unsigned int timeout, "0: la %0,0\n" "1:\n" EX_TABLE(0b,1b) - : "=d" (err) : "d"(__func), "d"(__timeout), - "d"(__cmdp), "d"(__cmdl), "0" (-EINVAL) : "1", "cc"); + : "+d" (err) : "d"(__func), "d"(__timeout), + "d"(__cmdp), "d"(__cmdl) : "1", "cc"); return err; } -- cgit v1.2.3-70-g09d2 From a2e53801971edbdaac4411760d893b8b65646987 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Fri, 12 Oct 2007 16:11:52 +0200 Subject: [S390] 3215: Handle special console device. The early console device is special as it already has all needed data set and raw3215[0] allocated from con3215_init(). Therefore, it needs special treatment in the probe function so it can be matched with the 3215 driver which is already owning it. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky --- drivers/s390/char/con3215.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 6000bdee408..0e1f35c9ed9 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -667,6 +667,9 @@ raw3215_probe (struct ccw_device *cdev) struct raw3215_info *raw; int line; + /* Console is special. */ + if (raw3215[0] && (cdev->dev.driver_data == raw3215[0])) + return 0; raw = kmalloc(sizeof(struct raw3215_info) + RAW3215_INBUF_SIZE, GFP_KERNEL|GFP_DMA); if (raw == NULL) -- cgit v1.2.3-70-g09d2 From 1462222b76a09a24b240563a51d5f9fbea8bd3e1 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Fri, 12 Oct 2007 16:11:53 +0200 Subject: [S390] xpram: fix bio_end{_,}io typo Signed-off-by: Martin Schwidefsky --- drivers/s390/block/xpram.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c index 0fbacc8b106..f231bc21b1c 100644 --- a/drivers/s390/block/xpram.c +++ b/drivers/s390/block/xpram.c @@ -230,7 +230,7 @@ static int xpram_make_request(struct request_queue *q, struct bio *bio) } } set_bit(BIO_UPTODATE, &bio->bi_flags); - bio_end_io(bio, 0); + bio_endio(bio, 0); return 0; fail: bio_io_error(bio); -- cgit v1.2.3-70-g09d2 From 640fdb504941fa2b9f6f274716fc9f97f2bf6bff Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Fri, 3 Aug 2007 11:10:07 -0400 Subject: [libata] pdc_adma: convert to new exception handling (EH) framework Signed-off-by: Jeff Garzik --- drivers/ata/pdc_adma.c | 82 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 67 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c index 5c79271401a..c95c1bf7df3 100644 --- a/drivers/ata/pdc_adma.c +++ b/drivers/ata/pdc_adma.c @@ -92,6 +92,8 @@ enum { /* CPB bits */ cDONE = (1 << 0), + cATERR = (1 << 3), + cVLD = (1 << 0), cDAT = (1 << 2), cIEN = (1 << 3), @@ -131,14 +133,15 @@ static int adma_ata_init_one (struct pci_dev *pdev, static int adma_port_start(struct ata_port *ap); static void adma_host_stop(struct ata_host *host); static void adma_port_stop(struct ata_port *ap); -static void adma_phy_reset(struct ata_port *ap); static void adma_qc_prep(struct ata_queued_cmd *qc); static unsigned int adma_qc_issue(struct ata_queued_cmd *qc); static int adma_check_atapi_dma(struct ata_queued_cmd *qc); static void adma_bmdma_stop(struct ata_queued_cmd *qc); static u8 adma_bmdma_status(struct ata_port *ap); static void adma_irq_clear(struct ata_port *ap); -static void adma_eng_timeout(struct ata_port *ap); +static void adma_freeze(struct ata_port *ap); +static void adma_thaw(struct ata_port *ap); +static void adma_error_handler(struct ata_port *ap); static struct scsi_host_template adma_ata_sht = { .module = THIS_MODULE, @@ -165,12 +168,13 @@ static const struct ata_port_operations adma_ata_ops = { .exec_command = ata_exec_command, .check_status = ata_check_status, .dev_select = ata_std_dev_select, - .phy_reset = adma_phy_reset, .check_atapi_dma = adma_check_atapi_dma, .data_xfer = ata_data_xfer, .qc_prep = adma_qc_prep, .qc_issue = adma_qc_issue, - .eng_timeout = adma_eng_timeout, + .freeze = adma_freeze, + .thaw = adma_thaw, + .error_handler = adma_error_handler, .irq_clear = adma_irq_clear, .irq_on = ata_irq_on, .irq_ack = ata_irq_ack, @@ -184,7 +188,7 @@ static const struct ata_port_operations adma_ata_ops = { static struct ata_port_info adma_port_info[] = { /* board_1841_idx */ { - .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | ATA_FLAG_PIO_POLLING, .pio_mask = 0x10, /* pio4 */ @@ -273,24 +277,41 @@ static inline void adma_enter_reg_mode(struct ata_port *ap) readb(chan + ADMA_STATUS); /* flush */ } -static void adma_phy_reset(struct ata_port *ap) +static void adma_freeze(struct ata_port *ap) { - struct adma_port_priv *pp = ap->private_data; + void __iomem *chan = ADMA_PORT_REGS(ap); + + /* mask/clear ATA interrupts */ + writeb(ATA_NIEN, ap->ioaddr.ctl_addr); + ata_check_status(ap); + + /* reset ADMA to idle state */ + writew(aPIOMD4 | aNIEN | aRSTADM, chan + ADMA_CONTROL); + udelay(2); + writew(aPIOMD4 | aNIEN, chan + ADMA_CONTROL); + udelay(2); +} - pp->state = adma_state_idle; +static void adma_thaw(struct ata_port *ap) +{ adma_reinit_engine(ap); - ata_port_probe(ap); - ata_bus_reset(ap); } -static void adma_eng_timeout(struct ata_port *ap) +static int adma_prereset(struct ata_port *ap, unsigned long deadline) { struct adma_port_priv *pp = ap->private_data; if (pp->state != adma_state_idle) /* healthy paranoia */ pp->state = adma_state_mmio; adma_reinit_engine(ap); - ata_eng_timeout(ap); + + return ata_std_prereset(ap, deadline); +} + +static void adma_error_handler(struct ata_port *ap) +{ + ata_do_eh(ap, adma_prereset, ata_std_softreset, NULL, + ata_std_postreset); } static int adma_fill_sg(struct ata_queued_cmd *qc) @@ -466,12 +487,31 @@ static inline unsigned int adma_intr_pkt(struct ata_host *host) continue; qc = ata_qc_from_tag(ap, ap->active_tag); if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) { - if ((status & (aPERR | aPSD | aUIRQ))) + if (status & aPERR) + qc->err_mask |= AC_ERR_HOST_BUS; + else if ((status & (aPSD | aUIRQ))) qc->err_mask |= AC_ERR_OTHER; + + if (pp->pkt[0] & cATERR) + qc->err_mask |= AC_ERR_DEV; else if (pp->pkt[0] != cDONE) qc->err_mask |= AC_ERR_OTHER; - ata_qc_complete(qc); + if (!qc->err_mask) + ata_qc_complete(qc); + else { + struct ata_eh_info *ehi = &ap->eh_info; + ata_ehi_clear_desc(ehi); + ata_ehi_push_desc(ehi, + "ADMA-status 0x%02X", status); + ata_ehi_push_desc(ehi, + "pkt[0] 0x%02X", pp->pkt[0]); + + if (qc->err_mask == AC_ERR_DEV) + ata_port_abort(ap); + else + ata_port_freeze(ap); + } } } return handled; @@ -502,7 +542,19 @@ static inline unsigned int adma_intr_mmio(struct ata_host *host) /* complete taskfile transaction */ pp->state = adma_state_idle; qc->err_mask |= ac_err_mask(status); - ata_qc_complete(qc); + if (!qc->err_mask) + ata_qc_complete(qc); + else { + struct ata_eh_info *ehi = &ap->eh_info; + ata_ehi_clear_desc(ehi); + ata_ehi_push_desc(ehi, + "status 0x%02X", status); + + if (qc->err_mask == AC_ERR_DEV) + ata_port_abort(ap); + else + ata_port_freeze(ap); + } handled = 1; } } -- cgit v1.2.3-70-g09d2 From 9af5c9c97dc9d599281778864c72b385f0c63341 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 6 Aug 2007 18:36:22 +0900 Subject: libata-link: introduce ata_link Introduce ata_link. It abstracts PHY and sits between ata_port and ata_device. This new level of abstraction is necessary to support SATA Port Multiplier, which basically adds a bunch of links (PHYs) to a ATA host port. Fields related to command execution, spd_limit and EH are per-link and thus moved to ata_link. This patch only defines the host link. Multiple link handling will be added later. Also, a lot of ap->link derefences are added but many of them will be removed as each part is converted to deal directly with ata_link instead of ata_port. This patch introduces no behavior change. Signed-off-by: Tejun Heo Cc: James Bottomley Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 18 ++--- drivers/ata/ata_generic.c | 2 +- drivers/ata/libata-acpi.c | 21 +++--- drivers/ata/libata-core.c | 157 ++++++++++++++++++++++-------------------- drivers/ata/libata-eh.c | 100 ++++++++++++++------------- drivers/ata/libata-scsi.c | 41 +++++------ drivers/ata/libata-sff.c | 4 +- drivers/ata/pata_it821x.c | 4 +- drivers/ata/pata_ixp4xx_cf.c | 4 +- drivers/ata/pata_legacy.c | 4 +- drivers/ata/pata_optidma.c | 4 +- drivers/ata/pata_pcmcia.c | 4 +- drivers/ata/pata_pdc2027x.c | 2 +- drivers/ata/pata_platform.c | 2 +- drivers/ata/pata_qdi.c | 2 +- drivers/ata/pata_rz1000.c | 2 +- drivers/ata/pata_scc.c | 2 +- drivers/ata/pata_sis.c | 2 +- drivers/ata/pata_winbond.c | 2 +- drivers/ata/pdc_adma.c | 9 +-- drivers/ata/sata_inic162x.c | 7 +- drivers/ata/sata_mv.c | 14 ++-- drivers/ata/sata_nv.c | 26 +++---- drivers/ata/sata_promise.c | 6 +- drivers/ata/sata_qstor.c | 4 +- drivers/ata/sata_sil.c | 14 ++-- drivers/ata/sata_sil24.c | 14 ++-- drivers/ata/sata_sx4.c | 4 +- drivers/ata/sata_via.c | 2 +- drivers/ata/sata_vsc.c | 2 +- drivers/scsi/ipr.c | 6 +- drivers/scsi/libsas/sas_ata.c | 10 +-- include/linux/libata.h | 40 +++++++---- 33 files changed, 280 insertions(+), 255 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index c16820325d7..c72fa468a69 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1064,7 +1064,7 @@ static int ahci_do_softreset(struct ata_port *ap, unsigned int *class, ata_port_printk(ap, KERN_WARNING, "failed to reset engine (errno=%d)", rc); - ata_tf_init(ap->device, &tf); + ata_tf_init(ap->link.device, &tf); /* issue the first D2H Register FIS */ msecs = 0; @@ -1132,7 +1132,7 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class, ahci_stop_engine(ap); /* clear D2H reception area to properly wait for D2H FIS */ - ata_tf_init(ap->device, &tf); + ata_tf_init(ap->link.device, &tf); tf.command = 0x80; ata_tf_to_fis(&tf, 0, 0, d2h_fis); @@ -1159,7 +1159,7 @@ static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class, ahci_stop_engine(ap); - rc = sata_port_hardreset(ap, sata_ehc_deb_timing(&ap->eh_context), + rc = sata_port_hardreset(ap, sata_ehc_deb_timing(&ap->link.eh_context), deadline); /* vt8251 needs SError cleared for the port to operate */ @@ -1278,7 +1278,7 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc) static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) { struct ahci_port_priv *pp = ap->private_data; - struct ata_eh_info *ehi = &ap->eh_info; + struct ata_eh_info *ehi = &ap->link.eh_info; unsigned int err_mask = 0, action = 0; struct ata_queued_cmd *qc; u32 serror; @@ -1332,7 +1332,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) ehi->serror |= serror; ehi->action |= action; - qc = ata_qc_from_tag(ap, ap->active_tag); + qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc) qc->err_mask |= err_mask; else @@ -1347,7 +1347,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) static void ahci_port_intr(struct ata_port *ap) { void __iomem *port_mmio = ap->ioaddr.cmd_addr; - struct ata_eh_info *ehi = &ap->eh_info; + struct ata_eh_info *ehi = &ap->link.eh_info; struct ahci_port_priv *pp = ap->private_data; u32 status, qc_active; int rc, known_irq = 0; @@ -1360,7 +1360,7 @@ static void ahci_port_intr(struct ata_port *ap) return; } - if (ap->sactive) + if (ap->link.sactive) qc_active = readl(port_mmio + PORT_SCR_ACT); else qc_active = readl(port_mmio + PORT_CMD_ISSUE); @@ -1380,7 +1380,7 @@ static void ahci_port_intr(struct ata_port *ap) /* if !NCQ, ignore. No modern ATA device has broken HSM * implementation for non-NCQ commands. */ - if (!ap->sactive) + if (!ap->link.sactive) return; if (status & PORT_IRQ_D2H_REG_FIS) { @@ -1433,7 +1433,7 @@ static void ahci_port_intr(struct ata_port *ap) if (!known_irq) ata_port_printk(ap, KERN_INFO, "spurious interrupt " "(irq_stat 0x%x active_tag 0x%x sactive 0x%x)\n", - status, ap->active_tag, ap->sactive); + status, ap->link.active_tag, ap->link.sactive); } static void ahci_irq_clear(struct ata_port *ap) diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c index 94546695472..b5e390ff5bd 100644 --- a/drivers/ata/ata_generic.c +++ b/drivers/ata/ata_generic.c @@ -53,7 +53,7 @@ static int generic_set_mode(struct ata_port *ap, struct ata_device **unused) dma_enabled = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->device[i]; + struct ata_device *dev = &ap->link.device[i]; if (ata_dev_enabled(dev)) { /* We don't really care */ dev->pio_mode = XFER_PIO_0; diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index c059f78ad94..0023ac4ff49 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -44,7 +44,8 @@ static void ata_acpi_associate_sata_port(struct ata_port *ap) { acpi_integer adr = SATA_ADR(ap->port_no, NO_PORT_MULT); - ap->device->acpi_handle = acpi_get_child(ap->host->acpi_handle, adr); + ap->link.device->acpi_handle = + acpi_get_child(ap->host->acpi_handle, adr); } static void ata_acpi_associate_ide_port(struct ata_port *ap) @@ -60,7 +61,7 @@ static void ata_acpi_associate_ide_port(struct ata_port *ap) max_devices++; for (i = 0; i < max_devices; i++) { - struct ata_device *dev = &ap->device[i]; + struct ata_device *dev = &ap->link.device[i]; dev->acpi_handle = acpi_get_child(ap->acpi_handle, i); } @@ -182,10 +183,10 @@ static int ata_acpi_stm(const struct ata_port *ap, struct ata_acpi_gtm *stm) /* Buffers for id may need byteswapping ? */ in_params[1].type = ACPI_TYPE_BUFFER; in_params[1].buffer.length = 512; - in_params[1].buffer.pointer = (u8 *)ap->device[0].id; + in_params[1].buffer.pointer = (u8 *)ap->link.device[0].id; in_params[2].type = ACPI_TYPE_BUFFER; in_params[2].buffer.length = 512; - in_params[2].buffer.pointer = (u8 *)ap->device[1].id; + in_params[2].buffer.pointer = (u8 *)ap->link.device[1].id; input.count = 3; input.pointer = in_params; @@ -226,7 +227,7 @@ static int ata_acpi_stm(const struct ata_port *ap, struct ata_acpi_gtm *stm) static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf, void **ptr_to_free) { - struct ata_port *ap = dev->ap; + struct ata_port *ap = dev->link->ap; acpi_status status; struct acpi_buffer output; union acpi_object *out_obj; @@ -320,7 +321,7 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf, static int taskfile_load_raw(struct ata_device *dev, const struct ata_acpi_gtf *gtf) { - struct ata_port *ap = dev->ap; + struct ata_port *ap = dev->link->ap; struct ata_taskfile tf, rtf; unsigned int err_mask; @@ -424,7 +425,7 @@ static int ata_acpi_exec_tfs(struct ata_device *dev) */ static int ata_acpi_push_id(struct ata_device *dev) { - struct ata_port *ap = dev->ap; + struct ata_port *ap = dev->link->ap; int err; acpi_status status; struct acpi_object_list input; @@ -519,7 +520,7 @@ void ata_acpi_on_resume(struct ata_port *ap) /* schedule _GTF */ for (i = 0; i < ATA_MAX_DEVICES; i++) - ap->device[i].flags |= ATA_DFLAG_ACPI_PENDING; + ap->link.device[i].flags |= ATA_DFLAG_ACPI_PENDING; } /** @@ -538,8 +539,8 @@ void ata_acpi_on_resume(struct ata_port *ap) */ int ata_acpi_on_devcfg(struct ata_device *dev) { - struct ata_port *ap = dev->ap; - struct ata_eh_context *ehc = &ap->eh_context; + struct ata_port *ap = dev->link->ap; + struct ata_eh_context *ehc = &ap->link.eh_context; int acpi_sata = ap->flags & ATA_FLAG_ACPI_SATA; int rc; diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 772be09b468..dd2de485124 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -235,7 +235,7 @@ static int ata_rwcmd_protocol(struct ata_taskfile *tf, struct ata_device *dev) if (dev->flags & ATA_DFLAG_PIO) { tf->protocol = ATA_PROT_PIO; index = dev->multi_count ? 0 : 8; - } else if (lba48 && (dev->ap->flags & ATA_FLAG_PIO_LBA48)) { + } else if (lba48 && (dev->link->ap->flags & ATA_FLAG_PIO_LBA48)) { /* Unable to use DMA due to host limitation */ tf->protocol = ATA_PROT_PIO; index = dev->multi_count ? 0 : 8; @@ -604,7 +604,7 @@ static const char *sata_spd_string(unsigned int spd) void ata_dev_disable(struct ata_device *dev) { if (ata_dev_enabled(dev)) { - if (ata_msg_drv(dev->ap)) + if (ata_msg_drv(dev->link->ap)) ata_dev_printk(dev, KERN_WARNING, "disabled\n"); ata_down_xfermask_limit(dev, ATA_DNXFER_FORCE_PIO0 | ATA_DNXFER_QUIET); @@ -735,7 +735,7 @@ ata_dev_try_classify(struct ata_port *ap, unsigned int device, u8 *r_err) /* see if device passed diags: if master then continue and warn later */ if (err == 0 && device == 0) /* diagnostic fail : do nothing _YET_ */ - ap->device[device].horkage |= ATA_HORKAGE_DIAGNOSTIC; + ap->link.device[device].horkage |= ATA_HORKAGE_DIAGNOSTIC; else if (err == 1) /* do nothing */ ; else if ((device == 0) && (err == 0x81)) @@ -1150,7 +1150,7 @@ void ata_dev_select(struct ata_port *ap, unsigned int device, ap->ops->dev_select(ap, device); if (wait) { - if (can_sleep && ap->device[device].class == ATA_DEV_ATAPI) + if (can_sleep && ap->link.device[device].class == ATA_DEV_ATAPI) msleep(150); ata_wait_idle(ap); } @@ -1346,7 +1346,8 @@ unsigned ata_exec_internal_sg(struct ata_device *dev, int dma_dir, struct scatterlist *sg, unsigned int n_elem) { - struct ata_port *ap = dev->ap; + struct ata_link *link = dev->link; + struct ata_port *ap = link->ap; u8 command = tf->command; struct ata_queued_cmd *qc; unsigned int tag, preempted_tag; @@ -1386,11 +1387,11 @@ unsigned ata_exec_internal_sg(struct ata_device *dev, qc->dev = dev; ata_qc_reinit(qc); - preempted_tag = ap->active_tag; - preempted_sactive = ap->sactive; + preempted_tag = link->active_tag; + preempted_sactive = link->sactive; preempted_qc_active = ap->qc_active; - ap->active_tag = ATA_TAG_POISON; - ap->sactive = 0; + link->active_tag = ATA_TAG_POISON; + link->sactive = 0; ap->qc_active = 0; /* prepare & issue qc */ @@ -1467,8 +1468,8 @@ unsigned ata_exec_internal_sg(struct ata_device *dev, err_mask = qc->err_mask; ata_qc_free(qc); - ap->active_tag = preempted_tag; - ap->sactive = preempted_sactive; + link->active_tag = preempted_tag; + link->sactive = preempted_sactive; ap->qc_active = preempted_qc_active; /* XXX - Some LLDDs (sata_mv) disable port on command failure. @@ -1566,7 +1567,7 @@ unsigned int ata_pio_need_iordy(const struct ata_device *adev) { /* Controller doesn't support IORDY. Probably a pointless check as the caller should know this */ - if (adev->ap->flags & ATA_FLAG_NO_IORDY) + if (adev->link->ap->flags & ATA_FLAG_NO_IORDY) return 0; /* PIO3 and higher it is mandatory */ if (adev->pio_mode > XFER_PIO_2) @@ -1622,7 +1623,7 @@ static u32 ata_pio_mask_no_iordy(const struct ata_device *adev) int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, unsigned int flags, u16 *id) { - struct ata_port *ap = dev->ap; + struct ata_port *ap = dev->link->ap; unsigned int class = *p_class; struct ata_taskfile tf; unsigned int err_mask = 0; @@ -1774,13 +1775,14 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, static inline u8 ata_dev_knobble(struct ata_device *dev) { - return ((dev->ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(dev->id))); + struct ata_port *ap = dev->link->ap; + return ((ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(dev->id))); } static void ata_dev_config_ncq(struct ata_device *dev, char *desc, size_t desc_sz) { - struct ata_port *ap = dev->ap; + struct ata_port *ap = dev->link->ap; int hdepth = 0, ddepth = ata_id_queue_depth(dev->id); if (!ata_id_has_ncq(dev->id)) { @@ -1817,8 +1819,8 @@ static void ata_dev_config_ncq(struct ata_device *dev, */ int ata_dev_configure(struct ata_device *dev) { - struct ata_port *ap = dev->ap; - struct ata_eh_context *ehc = &ap->eh_context; + struct ata_port *ap = dev->link->ap; + struct ata_eh_context *ehc = &dev->link->eh_context; int print_info = ehc->i.flags & ATA_EHI_PRINTINFO; const u16 *id = dev->id; unsigned int xfer_mask; @@ -2116,7 +2118,7 @@ int ata_bus_probe(struct ata_port *ap) ap->ops->phy_reset(ap); for (i = 0; i < ATA_MAX_DEVICES; i++) { - dev = &ap->device[i]; + dev = &ap->link.device[i]; if (!(ap->flags & ATA_FLAG_DISABLED) && dev->class != ATA_DEV_UNKNOWN) @@ -2133,14 +2135,14 @@ int ata_bus_probe(struct ata_port *ap) state is undefined. Record the mode */ for (i = 0; i < ATA_MAX_DEVICES; i++) - ap->device[i].pio_mode = XFER_PIO_0; + ap->link.device[i].pio_mode = XFER_PIO_0; /* read IDENTIFY page and configure devices. We have to do the identify specific sequence bass-ackwards so that PDIAG- is released by the slave device */ for (i = ATA_MAX_DEVICES - 1; i >= 0; i--) { - dev = &ap->device[i]; + dev = &ap->link.device[i]; if (tries[i]) dev->class = classes[i]; @@ -2162,13 +2164,13 @@ int ata_bus_probe(struct ata_port *ap) this in the normal order so that the user doesn't get confused */ for(i = 0; i < ATA_MAX_DEVICES; i++) { - dev = &ap->device[i]; + dev = &ap->link.device[i]; if (!ata_dev_enabled(dev)) continue; - ap->eh_context.i.flags |= ATA_EHI_PRINTINFO; + ap->link.eh_context.i.flags |= ATA_EHI_PRINTINFO; rc = ata_dev_configure(dev); - ap->eh_context.i.flags &= ~ATA_EHI_PRINTINFO; + ap->link.eh_context.i.flags &= ~ATA_EHI_PRINTINFO; if (rc) goto fail; } @@ -2179,7 +2181,7 @@ int ata_bus_probe(struct ata_port *ap) goto fail; for (i = 0; i < ATA_MAX_DEVICES; i++) - if (ata_dev_enabled(&ap->device[i])) + if (ata_dev_enabled(&ap->link.device[i])) return 0; /* no device present, disable port */ @@ -2344,8 +2346,8 @@ void sata_phy_reset(struct ata_port *ap) struct ata_device *ata_dev_pair(struct ata_device *adev) { - struct ata_port *ap = adev->ap; - struct ata_device *pair = &ap->device[1 - adev->devno]; + struct ata_link *link = adev->link; + struct ata_device *pair = &link->device[1 - adev->devno]; if (!ata_dev_enabled(pair)) return NULL; return pair; @@ -2366,8 +2368,8 @@ struct ata_device *ata_dev_pair(struct ata_device *adev) void ata_port_disable(struct ata_port *ap) { - ap->device[0].class = ATA_DEV_NONE; - ap->device[1].class = ATA_DEV_NONE; + ap->link.device[0].class = ATA_DEV_NONE; + ap->link.device[1].class = ATA_DEV_NONE; ap->flags |= ATA_FLAG_DISABLED; } @@ -2400,9 +2402,9 @@ int sata_down_spd_limit(struct ata_port *ap) if (rc == 0) spd = (sstatus >> 4) & 0xf; else - spd = ap->sata_spd; + spd = ap->link.sata_spd; - mask = ap->sata_spd_limit; + mask = ap->link.sata_spd_limit; if (mask <= 1) return -EINVAL; @@ -2422,7 +2424,7 @@ int sata_down_spd_limit(struct ata_port *ap) if (!mask) return -EINVAL; - ap->sata_spd_limit = mask; + ap->link.sata_spd_limit = mask; ata_port_printk(ap, KERN_WARNING, "limiting SATA link speed to %s\n", sata_spd_string(fls(mask))); @@ -2434,10 +2436,10 @@ static int __sata_set_spd_needed(struct ata_port *ap, u32 *scontrol) { u32 spd, limit; - if (ap->sata_spd_limit == UINT_MAX) + if (ap->link.sata_spd_limit == UINT_MAX) limit = 0; else - limit = fls(ap->sata_spd_limit); + limit = fls(ap->link.sata_spd_limit); spd = (*scontrol >> 4) & 0xf; *scontrol = (*scontrol & ~0xf0) | ((limit & 0xf) << 4); @@ -2450,7 +2452,7 @@ static int __sata_set_spd_needed(struct ata_port *ap, u32 *scontrol) * @ap: Port in question * * Test whether the spd limit in SControl matches - * @ap->sata_spd_limit. This function is used to determine + * @ap->link.sata_spd_limit. This function is used to determine * whether hardreset is necessary to apply SATA spd * configuration. * @@ -2749,7 +2751,7 @@ int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel) static int ata_dev_set_mode(struct ata_device *dev) { - struct ata_eh_context *ehc = &dev->ap->eh_context; + struct ata_eh_context *ehc = &dev->link->eh_context; unsigned int err_mask; int rc; @@ -2809,7 +2811,7 @@ int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) for (i = 0; i < ATA_MAX_DEVICES; i++) { unsigned int pio_mask, dma_mask; - dev = &ap->device[i]; + dev = &ap->link.device[i]; if (!ata_dev_enabled(dev)) continue; @@ -2830,7 +2832,7 @@ int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) /* step 2: always set host PIO timings */ for (i = 0; i < ATA_MAX_DEVICES; i++) { - dev = &ap->device[i]; + dev = &ap->link.device[i]; if (!ata_dev_enabled(dev)) continue; @@ -2848,7 +2850,7 @@ int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) /* step 3: set host DMA timings */ for (i = 0; i < ATA_MAX_DEVICES; i++) { - dev = &ap->device[i]; + dev = &ap->link.device[i]; if (!ata_dev_enabled(dev) || !dev->dma_mode) continue; @@ -2861,7 +2863,7 @@ int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) /* step 4: update devices' xfer mode */ for (i = 0; i < ATA_MAX_DEVICES; i++) { - dev = &ap->device[i]; + dev = &ap->link.device[i]; /* don't update suspended devices' xfer mode */ if (!ata_dev_enabled(dev)) @@ -3142,6 +3144,7 @@ static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask, void ata_bus_reset(struct ata_port *ap) { + struct ata_device *device = ap->link.device; struct ata_ioports *ioaddr = &ap->ioaddr; unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS; u8 err; @@ -3177,19 +3180,19 @@ void ata_bus_reset(struct ata_port *ap) /* * determine by signature whether we have ATA or ATAPI devices */ - ap->device[0].class = ata_dev_try_classify(ap, 0, &err); + device[0].class = ata_dev_try_classify(ap, 0, &err); if ((slave_possible) && (err != 0x81)) - ap->device[1].class = ata_dev_try_classify(ap, 1, &err); + device[1].class = ata_dev_try_classify(ap, 1, &err); /* is double-select really necessary? */ - if (ap->device[1].class != ATA_DEV_NONE) + if (device[1].class != ATA_DEV_NONE) ap->ops->dev_select(ap, 1); - if (ap->device[0].class != ATA_DEV_NONE) + if (device[0].class != ATA_DEV_NONE) ap->ops->dev_select(ap, 0); /* if no devices were detected, disable this port */ - if ((ap->device[0].class == ATA_DEV_NONE) && - (ap->device[1].class == ATA_DEV_NONE)) + if ((device[0].class == ATA_DEV_NONE) && + (device[1].class == ATA_DEV_NONE)) goto err_out; if (ap->flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST)) { @@ -3331,7 +3334,7 @@ int sata_phy_resume(struct ata_port *ap, const unsigned long *params, */ int ata_std_prereset(struct ata_port *ap, unsigned long deadline) { - struct ata_eh_context *ehc = &ap->eh_context; + struct ata_eh_context *ehc = &ap->link.eh_context; const unsigned long *timing = sata_ehc_deb_timing(ehc); int rc; @@ -3503,7 +3506,7 @@ int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing, int sata_std_hardreset(struct ata_port *ap, unsigned int *class, unsigned long deadline) { - const unsigned long *timing = sata_ehc_deb_timing(&ap->eh_context); + const unsigned long *timing = sata_ehc_deb_timing(&ap->link.eh_context); int rc; DPRINTK("ENTER\n"); @@ -3652,7 +3655,7 @@ static int ata_dev_same_device(struct ata_device *dev, unsigned int new_class, int ata_dev_reread_id(struct ata_device *dev, unsigned int readid_flags) { unsigned int class = dev->class; - u16 *id = (void *)dev->ap->sector_buf; + u16 *id = (void *)dev->link->ap->sector_buf; int rc; /* read ID data */ @@ -3837,7 +3840,7 @@ static int ata_dma_blacklisted(const struct ata_device *dev) * DMA blacklist those ATAPI devices with CDB-intr (and use PIO) * if the LLDD handles only interrupts in the HSM_ST_LAST state. */ - if ((dev->ap->flags & ATA_FLAG_PIO_POLLING) && + if ((dev->link->ap->flags & ATA_FLAG_PIO_POLLING) && (dev->flags & ATA_DFLAG_CDB_INTR)) return 1; return (dev->horkage & ATA_HORKAGE_NODMA) ? 1 : 0; @@ -3857,7 +3860,8 @@ static int ata_dma_blacklisted(const struct ata_device *dev) */ static void ata_dev_xfermask(struct ata_device *dev) { - struct ata_port *ap = dev->ap; + struct ata_link *link = dev->link; + struct ata_port *ap = link->ap; struct ata_host *host = ap->host; unsigned long xfer_mask; @@ -4482,7 +4486,7 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words) void ata_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data) { - struct ata_port *ap = adev->ap; + struct ata_port *ap = adev->link->ap; unsigned int words = buflen >> 1; /* Transfer multiple of 2 bytes */ @@ -5188,7 +5192,7 @@ static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap) struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev) { - struct ata_port *ap = dev->ap; + struct ata_port *ap = dev->link->ap; struct ata_queued_cmd *qc; qc = ata_qc_new(ap); @@ -5231,6 +5235,7 @@ void ata_qc_free(struct ata_queued_cmd *qc) void __ata_qc_complete(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; + struct ata_link *link = qc->dev->link; WARN_ON(qc == NULL); /* ata_qc_from_tag _might_ return NULL */ WARN_ON(!(qc->flags & ATA_QCFLAG_ACTIVE)); @@ -5240,9 +5245,9 @@ void __ata_qc_complete(struct ata_queued_cmd *qc) /* command should be marked inactive atomically with qc completion */ if (qc->tf.protocol == ATA_PROT_NCQ) - ap->sactive &= ~(1 << qc->tag); + link->sactive &= ~(1 << qc->tag); else - ap->active_tag = ATA_TAG_POISON; + link->active_tag = ATA_TAG_POISON; /* atapi: mark qc as inactive to prevent the interrupt handler * from completing the command twice later, before the error handler @@ -5411,19 +5416,20 @@ static inline int ata_should_dma_map(struct ata_queued_cmd *qc) void ata_qc_issue(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; + struct ata_link *link = qc->dev->link; /* Make sure only one non-NCQ command is outstanding. The * check is skipped for old EH because it reuses active qc to * request ATAPI sense. */ - WARN_ON(ap->ops->error_handler && ata_tag_valid(ap->active_tag)); + WARN_ON(ap->ops->error_handler && ata_tag_valid(link->active_tag)); if (qc->tf.protocol == ATA_PROT_NCQ) { - WARN_ON(ap->sactive & (1 << qc->tag)); - ap->sactive |= 1 << qc->tag; + WARN_ON(link->sactive & (1 << qc->tag)); + link->sactive |= 1 << qc->tag; } else { - WARN_ON(ap->sactive); - ap->active_tag = qc->tag; + WARN_ON(link->sactive); + link->active_tag = qc->tag; } qc->flags |= ATA_QCFLAG_ACTIVE; @@ -5606,7 +5612,7 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) inline unsigned int ata_host_intr (struct ata_port *ap, struct ata_queued_cmd *qc) { - struct ata_eh_info *ehi = &ap->eh_info; + struct ata_eh_info *ehi = &ap->link.eh_info; u8 status, host_stat = 0; VPRINTK("ata%u: protocol %d task_state %d\n", @@ -5721,7 +5727,7 @@ irqreturn_t ata_interrupt (int irq, void *dev_instance) !(ap->flags & ATA_FLAG_DISABLED)) { struct ata_queued_cmd *qc; - qc = ata_qc_from_tag(ap, ap->active_tag); + qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)) && (qc->flags & ATA_QCFLAG_ACTIVE)) handled |= ata_host_intr(ap, qc); @@ -5921,8 +5927,8 @@ static int ata_host_request_pm(struct ata_host *host, pm_message_t mesg, } ap->pflags |= ATA_PFLAG_PM_PENDING; - ap->eh_info.action |= action; - ap->eh_info.flags |= ehi_flags; + ap->link.eh_info.action |= action; + ap->link.eh_info.flags |= ehi_flags; ata_port_schedule_eh(ap); @@ -6026,12 +6032,13 @@ int ata_port_start(struct ata_port *ap) */ void ata_dev_init(struct ata_device *dev) { - struct ata_port *ap = dev->ap; + struct ata_link *link = dev->link; + struct ata_port *ap = link->ap; unsigned long flags; /* SATA spd limit is bound to the first device */ - ap->sata_spd_limit = ap->hw_sata_spd_limit; - ap->sata_spd = 0; + link->sata_spd_limit = link->hw_sata_spd_limit; + link->sata_spd = 0; /* High bits of dev->flags are used to record warm plug * requests which occur asynchronously. Synchronize using @@ -6080,8 +6087,8 @@ struct ata_port *ata_port_alloc(struct ata_host *host) ap->host = host; ap->dev = host->dev; - ap->hw_sata_spd_limit = UINT_MAX; - ap->active_tag = ATA_TAG_POISON; + ap->link.hw_sata_spd_limit = UINT_MAX; + ap->link.active_tag = ATA_TAG_POISON; ap->last_ctl = 0xFF; #if defined(ATA_VERBOSE_DEBUG) @@ -6104,9 +6111,11 @@ struct ata_port *ata_port_alloc(struct ata_host *host) ap->cbl = ATA_CBL_NONE; + ap->link.ap = ap; + for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->device[i]; - dev->ap = ap; + struct ata_device *dev = &ap->link.device[i]; + dev->link = &ap->link; dev->devno = i; ata_dev_init(dev); } @@ -6402,9 +6411,9 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) if (sata_scr_read(ap, SCR_CONTROL, &scontrol) == 0) { int spd = (scontrol >> 4) & 0xf; if (spd) - ap->hw_sata_spd_limit &= (1 << spd) - 1; + ap->link.hw_sata_spd_limit &= (1 << spd) - 1; } - ap->sata_spd_limit = ap->hw_sata_spd_limit; + ap->link.sata_spd_limit = ap->link.hw_sata_spd_limit; /* report the secondary IRQ for second channel legacy */ irq_line = host->irq; @@ -6436,7 +6445,7 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) /* probe */ if (ap->ops->error_handler) { - struct ata_eh_info *ehi = &ap->eh_info; + struct ata_eh_info *ehi = &ap->link.eh_info; unsigned long flags; ata_port_probe(ap); @@ -6560,7 +6569,7 @@ void ata_port_detach(struct ata_port *ap) spin_lock_irqsave(ap->lock, flags); for (i = 0; i < ATA_MAX_DEVICES; i++) - ata_dev_disable(&ap->device[i]); + ata_dev_disable(&ap->link.device[i]); spin_unlock_irqrestore(ap->lock, flags); diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index ac6ceed4bb6..e2681f56ed4 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -195,7 +195,7 @@ static int ata_ering_map(struct ata_ering *ering, static unsigned int ata_eh_dev_action(struct ata_device *dev) { - struct ata_eh_context *ehc = &dev->ap->eh_context; + struct ata_eh_context *ehc = &dev->link->eh_context; return ehc->i.action | ehc->i.dev_action[dev->devno]; } @@ -261,7 +261,7 @@ enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd) ret = EH_HANDLED; spin_lock_irqsave(ap->lock, flags); - qc = ata_qc_from_tag(ap, ap->active_tag); + qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc) { WARN_ON(qc->scsicmd != cmd); qc->flags |= ATA_QCFLAG_EH_SCHEDULED; @@ -371,9 +371,9 @@ void ata_scsi_error(struct Scsi_Host *host) /* fetch & clear EH info */ spin_lock_irqsave(ap->lock, flags); - memset(&ap->eh_context, 0, sizeof(ap->eh_context)); - ap->eh_context.i = ap->eh_info; - memset(&ap->eh_info, 0, sizeof(ap->eh_info)); + memset(&ap->link.eh_context, 0, sizeof(ap->link.eh_context)); + ap->link.eh_context.i = ap->link.eh_info; + memset(&ap->link.eh_info, 0, sizeof(ap->link.eh_info)); ap->pflags |= ATA_PFLAG_EH_IN_PROGRESS; ap->pflags &= ~ATA_PFLAG_EH_PENDING; @@ -409,7 +409,7 @@ void ata_scsi_error(struct Scsi_Host *host) } /* this run is complete, make sure EH info is clear */ - memset(&ap->eh_info, 0, sizeof(ap->eh_info)); + memset(&ap->link.eh_info, 0, sizeof(ap->link.eh_info)); /* Clear host_eh_scheduled while holding ap->lock such * that if exception occurs after this point but @@ -420,7 +420,7 @@ void ata_scsi_error(struct Scsi_Host *host) spin_unlock_irqrestore(ap->lock, flags); } else { - WARN_ON(ata_qc_from_tag(ap, ap->active_tag) == NULL); + WARN_ON(ata_qc_from_tag(ap, ap->link.active_tag) == NULL); ap->ops->eng_timeout(ap); } @@ -575,7 +575,7 @@ void ata_eng_timeout(struct ata_port *ap) { DPRINTK("ENTER\n"); - ata_qc_timeout(ata_qc_from_tag(ap, ap->active_tag)); + ata_qc_timeout(ata_qc_from_tag(ap, ap->link.active_tag)); DPRINTK("EXIT\n"); } @@ -922,7 +922,7 @@ void ata_eh_qc_retry(struct ata_queued_cmd *qc) */ static void ata_eh_detach_dev(struct ata_device *dev) { - struct ata_port *ap = dev->ap; + struct ata_port *ap = dev->link->ap; unsigned long flags; ata_dev_disable(dev); @@ -937,8 +937,8 @@ static void ata_eh_detach_dev(struct ata_device *dev) } /* clear per-dev EH actions */ - ata_eh_clear_action(dev, &ap->eh_info, ATA_EH_PERDEV_MASK); - ata_eh_clear_action(dev, &ap->eh_context.i, ATA_EH_PERDEV_MASK); + ata_eh_clear_action(dev, &dev->link->eh_info, ATA_EH_PERDEV_MASK); + ata_eh_clear_action(dev, &dev->link->eh_context.i, ATA_EH_PERDEV_MASK); spin_unlock_irqrestore(ap->lock, flags); } @@ -950,8 +950,8 @@ static void ata_eh_detach_dev(struct ata_device *dev) * @action: action about to be performed * * Called just before performing EH actions to clear related bits - * in @ap->eh_info such that eh actions are not unnecessarily - * repeated. + * in @ap->link.eh_info such that eh actions are not + * unnecessarily repeated. * * LOCKING: * None. @@ -960,8 +960,8 @@ static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev, unsigned int action) { unsigned long flags; - struct ata_eh_info *ehi = &ap->eh_info; - struct ata_eh_context *ehc = &ap->eh_context; + struct ata_eh_info *ehi = &ap->link.eh_info; + struct ata_eh_context *ehc = &ap->link.eh_context; spin_lock_irqsave(ap->lock, flags); @@ -993,7 +993,7 @@ static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev, * @action: action just completed * * Called right after performing EH actions to clear related bits - * in @ap->eh_context. + * in @ap->link.eh_context. * * LOCKING: * None. @@ -1001,13 +1001,15 @@ static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev, static void ata_eh_done(struct ata_port *ap, struct ata_device *dev, unsigned int action) { + struct ata_eh_context *ehc = &ap->link.eh_context; + /* if reset is complete, clear all reset actions & reset modifier */ if (action & ATA_EH_RESET_MASK) { action |= ATA_EH_RESET_MASK; - ap->eh_context.i.flags &= ~ATA_EHI_RESET_MODIFIER_MASK; + ehc->i.flags &= ~ATA_EHI_RESET_MODIFIER_MASK; } - ata_eh_clear_action(dev, &ap->eh_context.i, action); + ata_eh_clear_action(dev, &ehc->i, action); } /** @@ -1101,7 +1103,7 @@ static unsigned int ata_read_log_page(struct ata_device *dev, static int ata_eh_read_log_10h(struct ata_device *dev, int *tag, struct ata_taskfile *tf) { - u8 *buf = dev->ap->sector_buf; + u8 *buf = dev->link->ap->sector_buf; unsigned int err_mask; u8 csum; int i; @@ -1155,7 +1157,7 @@ static unsigned int atapi_eh_request_sense(struct ata_queued_cmd *qc) { struct ata_device *dev = qc->dev; unsigned char *sense_buf = qc->scsicmd->sense_buffer; - struct ata_port *ap = dev->ap; + struct ata_port *ap = dev->link->ap; struct ata_taskfile tf; u8 cdb[ATAPI_CDB_LEN]; @@ -1206,7 +1208,7 @@ static unsigned int atapi_eh_request_sense(struct ata_queued_cmd *qc) */ static void ata_eh_analyze_serror(struct ata_port *ap) { - struct ata_eh_context *ehc = &ap->eh_context; + struct ata_eh_context *ehc = &ap->link.eh_context; u32 serror = ehc->i.serror; unsigned int err_mask = 0, action = 0; @@ -1248,8 +1250,8 @@ static void ata_eh_analyze_serror(struct ata_port *ap) */ static void ata_eh_analyze_ncq_error(struct ata_port *ap) { - struct ata_eh_context *ehc = &ap->eh_context; - struct ata_device *dev = ap->device; + struct ata_eh_context *ehc = &ap->link.eh_context; + struct ata_device *dev = ap->link.device; struct ata_queued_cmd *qc; struct ata_taskfile tf; int tag, rc; @@ -1259,7 +1261,7 @@ static void ata_eh_analyze_ncq_error(struct ata_port *ap) return; /* is it NCQ device error? */ - if (!ap->sactive || !(ehc->i.err_mask & AC_ERR_DEV)) + if (!ap->link.sactive || !(ehc->i.err_mask & AC_ERR_DEV)) return; /* has LLDD analyzed already? */ @@ -1281,7 +1283,7 @@ static void ata_eh_analyze_ncq_error(struct ata_port *ap) return; } - if (!(ap->sactive & (1 << tag))) { + if (!(ap->link.sactive & (1 << tag))) { ata_port_printk(ap, KERN_ERR, "log page 10h reported " "inactive tag %d\n", tag); return; @@ -1497,7 +1499,7 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, int is_io, /* speed down? */ if (verdict & ATA_EH_SPDN_SPEED_DOWN) { /* speed down SATA link speed if possible */ - if (sata_down_spd_limit(dev->ap) == 0) { + if (sata_down_spd_limit(dev->link->ap) == 0) { action |= ATA_EH_HARDRESET; goto done; } @@ -1528,7 +1530,7 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, int is_io, * SATA. Consider it only for PATA. */ if ((verdict & ATA_EH_SPDN_FALLBACK_TO_PIO) && (dev->spdn_cnt >= 2) && - (dev->ap->cbl != ATA_CBL_SATA) && + (dev->link->ap->cbl != ATA_CBL_SATA) && (dev->xfer_shift != ATA_SHIFT_PIO)) { if (ata_down_xfermask_limit(dev, ATA_DNXFER_FORCE_PIO) == 0) { dev->spdn_cnt = 0; @@ -1557,7 +1559,7 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, int is_io, */ static void ata_eh_autopsy(struct ata_port *ap) { - struct ata_eh_context *ehc = &ap->eh_context; + struct ata_eh_context *ehc = &ap->link.eh_context; unsigned int all_err_mask = 0; int tag, is_io = 0; u32 serror; @@ -1656,7 +1658,7 @@ static void ata_eh_autopsy(struct ata_port *ap) */ static void ata_eh_report(struct ata_port *ap) { - struct ata_eh_context *ehc = &ap->eh_context; + struct ata_eh_context *ehc = &ap->link.eh_context; const char *frozen, *desc; int tag, nr_failed = 0; @@ -1685,15 +1687,15 @@ static void ata_eh_report(struct ata_port *ap) if (ehc->i.dev) { ata_dev_printk(ehc->i.dev, KERN_ERR, "exception Emask 0x%x " "SAct 0x%x SErr 0x%x action 0x%x%s\n", - ehc->i.err_mask, ap->sactive, ehc->i.serror, - ehc->i.action, frozen); + ehc->i.err_mask, ap->link.sactive, + ehc->i.serror, ehc->i.action, frozen); if (desc) ata_dev_printk(ehc->i.dev, KERN_ERR, "%s\n", desc); } else { ata_port_printk(ap, KERN_ERR, "exception Emask 0x%x " "SAct 0x%x SErr 0x%x action 0x%x%s\n", - ehc->i.err_mask, ap->sactive, ehc->i.serror, - ehc->i.action, frozen); + ehc->i.err_mask, ap->link.sactive, + ehc->i.serror, ehc->i.action, frozen); if (desc) ata_port_printk(ap, KERN_ERR, "%s\n", desc); } @@ -1775,7 +1777,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, ata_prereset_fn_t prereset, ata_reset_fn_t softreset, ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) { - struct ata_eh_context *ehc = &ap->eh_context; + struct ata_eh_context *ehc = &ap->link.eh_context; unsigned int *classes = ehc->classes; int verbose = !(ehc->i.flags & ATA_EHI_QUIET); int try = 0; @@ -1804,7 +1806,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, if (rc == -ENOENT) { ata_port_printk(ap, KERN_DEBUG, "port disabled. ignoring.\n"); - ap->eh_context.i.action &= ~ATA_EH_RESET_MASK; + ehc->i.action &= ~ATA_EH_RESET_MASK; for (i = 0; i < ATA_MAX_DEVICES; i++) classes[i] = ATA_DEV_NONE; @@ -1907,11 +1909,11 @@ static int ata_eh_reset(struct ata_port *ap, int classify, * controller state is undefined. Record the mode. */ for (i = 0; i < ATA_MAX_DEVICES; i++) - ap->device[i].pio_mode = XFER_PIO_0; + ap->link.device[i].pio_mode = XFER_PIO_0; /* record current link speed */ if (sata_scr_read(ap, SCR_STATUS, &sstatus) == 0) - ap->sata_spd = (sstatus >> 4) & 0xf; + ap->link.sata_spd = (sstatus >> 4) & 0xf; if (postreset) postreset(ap, classes); @@ -1929,7 +1931,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, static int ata_eh_revalidate_and_attach(struct ata_port *ap, struct ata_device **r_failed_dev) { - struct ata_eh_context *ehc = &ap->eh_context; + struct ata_eh_context *ehc = &ap->link.eh_context; struct ata_device *dev; unsigned int new_mask = 0; unsigned long flags; @@ -1944,7 +1946,7 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, for (i = ATA_MAX_DEVICES - 1; i >= 0; i--) { unsigned int action, readid_flags = 0; - dev = &ap->device[i]; + dev = &ap->link.device[i]; action = ata_eh_dev_action(dev); if (ehc->i.flags & ATA_EHI_DID_RESET) @@ -2004,7 +2006,7 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, * device detection messages backwards. */ for (i = 0; i < ATA_MAX_DEVICES; i++) { - dev = &ap->device[i]; + dev = &ap->link.device[i]; if (!(new_mask & (1 << i))) continue; @@ -2036,7 +2038,7 @@ static int ata_port_nr_enabled(struct ata_port *ap) int i, cnt = 0; for (i = 0; i < ATA_MAX_DEVICES; i++) - if (ata_dev_enabled(&ap->device[i])) + if (ata_dev_enabled(&ap->link.device[i])) cnt++; return cnt; } @@ -2046,14 +2048,14 @@ static int ata_port_nr_vacant(struct ata_port *ap) int i, cnt = 0; for (i = 0; i < ATA_MAX_DEVICES; i++) - if (ap->device[i].class == ATA_DEV_UNKNOWN) + if (ap->link.device[i].class == ATA_DEV_UNKNOWN) cnt++; return cnt; } static int ata_eh_skip_recovery(struct ata_port *ap) { - struct ata_eh_context *ehc = &ap->eh_context; + struct ata_eh_context *ehc = &ap->link.eh_context; int i; /* thaw frozen port, resume link and recover failed devices */ @@ -2063,7 +2065,7 @@ static int ata_eh_skip_recovery(struct ata_port *ap) /* skip if class codes for all vacant slots are ATA_DEV_NONE */ for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->device[i]; + struct ata_device *dev = &ap->link.device[i]; if (dev->class == ATA_DEV_UNKNOWN && ehc->classes[dev->devno] != ATA_DEV_NONE) @@ -2075,8 +2077,8 @@ static int ata_eh_skip_recovery(struct ata_port *ap) static void ata_eh_handle_dev_fail(struct ata_device *dev, int err) { - struct ata_port *ap = dev->ap; - struct ata_eh_context *ehc = &ap->eh_context; + struct ata_port *ap = dev->link->ap; + struct ata_eh_context *ehc = &dev->link->eh_context; ehc->tries[dev->devno]--; @@ -2149,7 +2151,7 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, ata_reset_fn_t softreset, ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) { - struct ata_eh_context *ehc = &ap->eh_context; + struct ata_eh_context *ehc = &ap->link.eh_context; struct ata_device *dev; int i, rc; @@ -2157,7 +2159,7 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, /* prep for recovery */ for (i = 0; i < ATA_MAX_DEVICES; i++) { - dev = &ap->device[i]; + dev = &ap->link.device[i]; ehc->tries[dev->devno] = ATA_EH_DEV_TRIES; @@ -2240,7 +2242,7 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, out: if (rc) { for (i = 0; i < ATA_MAX_DEVICES; i++) - ata_dev_disable(&ap->device[i]); + ata_dev_disable(&ap->link.device[i]); } DPRINTK("EXIT, rc=%d\n", rc); diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index e83647651b3..ec0e2638200 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1368,14 +1368,14 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) case ATA_CMD_SET_FEATURES: if ((qc->tf.feature == SETFEATURES_WC_ON) || (qc->tf.feature == SETFEATURES_WC_OFF)) { - ap->eh_info.action |= ATA_EH_REVALIDATE; + ap->link.eh_info.action |= ATA_EH_REVALIDATE; ata_port_schedule_eh(ap); } break; case ATA_CMD_INIT_DEV_PARAMS: /* CHS translation changed */ case ATA_CMD_SET_MULTI: /* multi_count changed */ - ap->eh_info.action |= ATA_EH_REVALIDATE; + ap->link.eh_info.action |= ATA_EH_REVALIDATE; ata_port_schedule_eh(ap); break; } @@ -1439,14 +1439,14 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) */ static int ata_scmd_need_defer(struct ata_device *dev, int is_io) { - struct ata_port *ap = dev->ap; + struct ata_link *link = dev->link; int is_ncq = is_io && ata_ncq_enabled(dev); if (is_ncq) { - if (!ata_tag_valid(ap->active_tag)) + if (!ata_tag_valid(link->active_tag)) return 0; } else { - if (!ata_tag_valid(ap->active_tag) && !ap->sactive) + if (!ata_tag_valid(link->active_tag) && !link->sactive) return 0; } return 1; @@ -2426,7 +2426,7 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc) static struct ata_device * ata_find_dev(struct ata_port *ap, int id) { if (likely(id < ATA_MAX_DEVICES)) - return &ap->device[id]; + return &ap->link.device[id]; return NULL; } @@ -2458,7 +2458,7 @@ static int ata_scsi_dev_enabled(struct ata_device *dev) if (unlikely(!ata_dev_enabled(dev))) return 0; - if (!atapi_enabled || (dev->ap->flags & ATA_FLAG_NO_ATAPI)) { + if (!atapi_enabled || (dev->link->ap->flags & ATA_FLAG_NO_ATAPI)) { if (unlikely(dev->class == ATA_DEV_ATAPI)) { ata_dev_printk(dev, KERN_WARNING, "WARNING: ATAPI is %s, device ignored.\n", @@ -2961,7 +2961,7 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync) for (i = 0; i < ATA_MAX_DEVICES; i++) { struct scsi_device *sdev; - dev = &ap->device[i]; + dev = &ap->link.device[i]; if (!ata_dev_enabled(dev) || dev->sdev) continue; @@ -2978,7 +2978,7 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync) * whether all devices are attached. */ for (i = 0; i < ATA_MAX_DEVICES; i++) { - dev = &ap->device[i]; + dev = &ap->link.device[i]; if (ata_dev_enabled(dev) && !dev->sdev) break; } @@ -3049,7 +3049,7 @@ int ata_scsi_offline_dev(struct ata_device *dev) */ static void ata_scsi_remove_dev(struct ata_device *dev) { - struct ata_port *ap = dev->ap; + struct ata_port *ap = dev->link->ap; struct scsi_device *sdev; unsigned long flags; @@ -3123,7 +3123,7 @@ void ata_scsi_hotplug(struct work_struct *work) /* unplug detached devices */ for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->device[i]; + struct ata_device *dev = &ap->link.device[i]; unsigned long flags; if (!(dev->flags & ATA_DFLAG_DETACHED)) @@ -3162,6 +3162,7 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel, unsigned int id, unsigned int lun) { struct ata_port *ap = ata_shost_to_port(shost); + struct ata_eh_info *ehi = &ap->link.eh_info; unsigned long flags; int rc = 0; @@ -3175,15 +3176,15 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel, spin_lock_irqsave(ap->lock, flags); if (id == SCAN_WILD_CARD) { - ap->eh_info.probe_mask |= (1 << ATA_MAX_DEVICES) - 1; - ap->eh_info.action |= ATA_EH_SOFTRESET; + ehi->probe_mask |= (1 << ATA_MAX_DEVICES) - 1; + ehi->action |= ATA_EH_SOFTRESET; } else { struct ata_device *dev = ata_find_dev(ap, id); if (dev) { - ap->eh_info.probe_mask |= 1 << dev->devno; - ap->eh_info.action |= ATA_EH_SOFTRESET; - ap->eh_info.flags |= ATA_EHI_RESUME_LINK; + ehi->probe_mask |= 1 << dev->devno; + ehi->action |= ATA_EH_SOFTRESET; + ehi->flags |= ATA_EHI_RESUME_LINK; } else rc = -EINVAL; } @@ -3220,7 +3221,7 @@ void ata_scsi_dev_rescan(struct work_struct *work) spin_lock_irqsave(ap->lock, flags); for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->device[i]; + struct ata_device *dev = &ap->link.device[i]; struct scsi_device *sdev = dev->sdev; if (!ata_dev_enabled(dev) || !sdev) @@ -3359,7 +3360,7 @@ EXPORT_SYMBOL_GPL(ata_sas_port_destroy); int ata_sas_slave_configure(struct scsi_device *sdev, struct ata_port *ap) { ata_scsi_sdev_config(sdev); - ata_scsi_dev_config(sdev, ap->device); + ata_scsi_dev_config(sdev, ap->link.device); return 0; } EXPORT_SYMBOL_GPL(ata_sas_slave_configure); @@ -3382,8 +3383,8 @@ int ata_sas_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), ata_scsi_dump_cdb(ap, cmd); - if (likely(ata_scsi_dev_enabled(ap->device))) - rc = __ata_scsi_queuecmd(cmd, done, ap->device); + if (likely(ata_scsi_dev_enabled(ap->link.device))) + rc = __ata_scsi_queuecmd(cmd, done, ap->link.device); else { cmd->result = (DID_BAD_TARGET << 16); done(cmd); diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 8023167bbbe..2100cd61ed6 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -445,7 +445,7 @@ void ata_bmdma_drive_eh(struct ata_port *ap, ata_prereset_fn_t prereset, unsigned long flags; int thaw = 0; - qc = __ata_qc_from_tag(ap, ap->active_tag); + qc = __ata_qc_from_tag(ap, ap->link.active_tag); if (qc && !(qc->flags & ATA_QCFLAG_FAILED)) qc = NULL; @@ -909,7 +909,7 @@ unsigned long ata_pci_default_filter(struct ata_device *adev, unsigned long xfer /* Filter out DMA modes if the device has been configured by the BIOS as PIO only */ - if (adev->ap->ioaddr.bmdma_addr == 0) + if (adev->link->ap->ioaddr.bmdma_addr == 0) xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA); return xfer_mask; } diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c index 5d8b91e70ec..ece1a28f0a4 100644 --- a/drivers/ata/pata_it821x.c +++ b/drivers/ata/pata_it821x.c @@ -391,7 +391,7 @@ static void it821x_passthru_dev_select(struct ata_port *ap, { struct it821x_dev *itdev = ap->private_data; if (itdev && device != itdev->last_device) { - struct ata_device *adev = &ap->device[device]; + struct ata_device *adev = &ap->link.device[device]; it821x_program(ap, adev, itdev->pio[adev->devno]); itdev->last_device = device; } @@ -464,7 +464,7 @@ static int it821x_smart_set_mode(struct ata_port *ap, struct ata_device **unused int i; for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->device[i]; + struct ata_device *dev = &ap->link.device[i]; if (ata_dev_enabled(dev)) { /* We don't really care */ dev->pio_mode = XFER_PIO_0; diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c index 5dea3584c6c..3e2b8ce5fa3 100644 --- a/drivers/ata/pata_ixp4xx_cf.c +++ b/drivers/ata/pata_ixp4xx_cf.c @@ -31,7 +31,7 @@ static int ixp4xx_set_mode(struct ata_port *ap, struct ata_device **error) int i; for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->device[i]; + struct ata_device *dev = &ap->link.device[i]; if (ata_dev_enabled(dev)) { ata_dev_printk(dev, KERN_INFO, "configured for PIO0\n"); dev->pio_mode = XFER_PIO_0; @@ -49,7 +49,7 @@ static void ixp4xx_mmio_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int i; unsigned int words = buflen >> 1; u16 *buf16 = (u16 *) buf; - struct ata_port *ap = adev->ap; + struct ata_port *ap = adev->link->ap; void __iomem *mmio = ap->ioaddr.data_addr; struct ixp4xx_pata_data *data = ap->host->dev->platform_data; diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c index edffc25d2d3..4bcc0ae8d10 100644 --- a/drivers/ata/pata_legacy.c +++ b/drivers/ata/pata_legacy.c @@ -112,7 +112,7 @@ static int legacy_set_mode(struct ata_port *ap, struct ata_device **unused) int i; for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->device[i]; + struct ata_device *dev = &ap->link.device[i]; if (ata_dev_enabled(dev)) { ata_dev_printk(dev, KERN_INFO, "configured for PIO\n"); dev->pio_mode = XFER_PIO_0; @@ -256,7 +256,7 @@ static void pdc20230_set_piomode(struct ata_port *ap, struct ata_device *adev) static void pdc_data_xfer_vlb(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data) { - struct ata_port *ap = adev->ap; + struct ata_port *ap = adev->link->ap; int slop = buflen & 3; unsigned long flags; diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c index f89bdfde16d..f8234d7fd82 100644 --- a/drivers/ata/pata_optidma.c +++ b/drivers/ata/pata_optidma.c @@ -340,8 +340,8 @@ static int optidma_set_mode(struct ata_port *ap, struct ata_device **r_failed) pci_read_config_byte(pdev, 0x43, &r); r &= (0x0F << nybble); - r |= (optidma_make_bits43(&ap->device[0]) + - (optidma_make_bits43(&ap->device[0]) << 2)) << nybble; + r |= (optidma_make_bits43(&ap->link.device[0]) + + (optidma_make_bits43(&ap->link.device[0]) << 2)) << nybble; pci_write_config_byte(pdev, 0x43, r); } return rc; diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c index 0f2b027624d..890f649ddcc 100644 --- a/drivers/ata/pata_pcmcia.c +++ b/drivers/ata/pata_pcmcia.c @@ -67,8 +67,8 @@ struct ata_pcmcia_info { static int pcmcia_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) { - struct ata_device *master = &ap->device[0]; - struct ata_device *slave = &ap->device[1]; + struct ata_device *master = &ap->link.device[0]; + struct ata_device *slave = &ap->link.device[1]; if (!ata_dev_enabled(master) || !ata_dev_enabled(slave)) return ata_do_set_mode(ap, r_failed_dev); diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c index bb64a986e8f..fa780509a1d 100644 --- a/drivers/ata/pata_pdc2027x.c +++ b/drivers/ata/pata_pdc2027x.c @@ -486,7 +486,7 @@ static int pdc2027x_set_mode(struct ata_port *ap, struct ata_device **r_failed) return i; for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->device[i]; + struct ata_device *dev = &ap->link.device[i]; if (ata_dev_enabled(dev)) { diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c index 5086d03f2d7..e89656bffa8 100644 --- a/drivers/ata/pata_platform.c +++ b/drivers/ata/pata_platform.c @@ -35,7 +35,7 @@ static int pata_platform_set_mode(struct ata_port *ap, struct ata_device **unuse int i; for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->device[i]; + struct ata_device *dev = &ap->link.device[i]; if (ata_dev_enabled(dev)) { /* We don't really care */ diff --git a/drivers/ata/pata_qdi.c b/drivers/ata/pata_qdi.c index 1998c19e874..ec2206e820a 100644 --- a/drivers/ata/pata_qdi.c +++ b/drivers/ata/pata_qdi.c @@ -126,7 +126,7 @@ static unsigned int qdi_qc_issue_prot(struct ata_queued_cmd *qc) static void qdi_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data) { - struct ata_port *ap = adev->ap; + struct ata_port *ap = adev->link->ap; int slop = buflen & 3; if (ata_id_has_dword_io(adev->id)) { diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c index 7632fcb070c..57363c0ce06 100644 --- a/drivers/ata/pata_rz1000.c +++ b/drivers/ata/pata_rz1000.c @@ -39,7 +39,7 @@ static int rz1000_set_mode(struct ata_port *ap, struct ata_device **unused) int i; for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->device[i]; + struct ata_device *dev = &ap->link.device[i]; if (ata_dev_enabled(dev)) { /* We don't really care */ dev->pio_mode = XFER_PIO_0; diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c index 2d048ef25a5..aab068fbb7b 100644 --- a/drivers/ata/pata_scc.c +++ b/drivers/ata/pata_scc.c @@ -785,7 +785,7 @@ static u8 scc_bmdma_status (struct ata_port *ap) static void scc_data_xfer (struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data) { - struct ata_port *ap = adev->ap; + struct ata_port *ap = adev->link->ap; unsigned int words = buflen >> 1; unsigned int i; u16 *buf16 = (u16 *) buf; diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c index cce2834b2b6..9d6f81d52e1 100644 --- a/drivers/ata/pata_sis.c +++ b/drivers/ata/pata_sis.c @@ -84,7 +84,7 @@ static int sis_short_ata40(struct pci_dev *dev) static int sis_old_port_base(struct ata_device *adev) { - return 0x40 + (4 * adev->ap->port_no) + (2 * adev->devno); + return 0x40 + (4 * adev->link->ap->port_no) + (2 * adev->devno); } /** diff --git a/drivers/ata/pata_winbond.c b/drivers/ata/pata_winbond.c index 83abfeca405..c3757033007 100644 --- a/drivers/ata/pata_winbond.c +++ b/drivers/ata/pata_winbond.c @@ -94,7 +94,7 @@ static void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev) static void winbond_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data) { - struct ata_port *ap = adev->ap; + struct ata_port *ap = adev->link->ap; int slop = buflen & 3; if (ata_id_has_dword_io(adev->id)) { diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c index c95c1bf7df3..064a3b50560 100644 --- a/drivers/ata/pdc_adma.c +++ b/drivers/ata/pdc_adma.c @@ -485,7 +485,7 @@ static inline unsigned int adma_intr_pkt(struct ata_host *host) pp = ap->private_data; if (!pp || pp->state != adma_state_pkt) continue; - qc = ata_qc_from_tag(ap, ap->active_tag); + qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) { if (status & aPERR) qc->err_mask |= AC_ERR_HOST_BUS; @@ -500,7 +500,7 @@ static inline unsigned int adma_intr_pkt(struct ata_host *host) if (!qc->err_mask) ata_qc_complete(qc); else { - struct ata_eh_info *ehi = &ap->eh_info; + struct ata_eh_info *ehi = &ap->link.eh_info; ata_ehi_clear_desc(ehi); ata_ehi_push_desc(ehi, "ADMA-status 0x%02X", status); @@ -529,7 +529,7 @@ static inline unsigned int adma_intr_mmio(struct ata_host *host) struct adma_port_priv *pp = ap->private_data; if (!pp || pp->state != adma_state_mmio) continue; - qc = ata_qc_from_tag(ap, ap->active_tag); + qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) { /* check main status, clearing INTRQ */ @@ -545,7 +545,8 @@ static inline unsigned int adma_intr_mmio(struct ata_host *host) if (!qc->err_mask) ata_qc_complete(qc); else { - struct ata_eh_info *ehi = &ap->eh_info; + struct ata_eh_info *ehi = + &ap->link.eh_info; ata_ehi_clear_desc(ehi); ata_ehi_push_desc(ehi, "status 0x%02X", status); diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c index fdbed8ecdfc..3c0ef7a2f2f 100644 --- a/drivers/ata/sata_inic162x.c +++ b/drivers/ata/sata_inic162x.c @@ -285,7 +285,7 @@ static void inic_irq_clear(struct ata_port *ap) static void inic_host_intr(struct ata_port *ap) { void __iomem *port_base = inic_port_base(ap); - struct ata_eh_info *ehi = &ap->eh_info; + struct ata_eh_info *ehi = &ap->link.eh_info; u8 irq_stat; /* fetch and clear irq */ @@ -293,7 +293,8 @@ static void inic_host_intr(struct ata_port *ap) writeb(irq_stat, port_base + PORT_IRQ_STAT); if (likely(!(irq_stat & PIRQ_ERR))) { - struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag); + struct ata_queued_cmd *qc = + ata_qc_from_tag(ap, ap->link.active_tag); if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) { ata_chk_status(ap); /* clear ATA interrupt */ @@ -421,7 +422,7 @@ static int inic_hardreset(struct ata_port *ap, unsigned int *class, { void __iomem *port_base = inic_port_base(ap); void __iomem *idma_ctl = port_base + PORT_IDMA_CTL; - const unsigned long *timing = sata_ehc_deb_timing(&ap->eh_context); + const unsigned long *timing = sata_ehc_deb_timing(&ap->link.eh_context); u16 val; int rc; diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index d9832e234e4..246e7c5fdce 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -1415,7 +1415,7 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc) struct mv_host_priv *hpriv = ap->host->private_data; unsigned int edma_enabled = (pp->pp_flags & MV_PP_FLAG_EDMA_EN); unsigned int action = 0, err_mask = 0; - struct ata_eh_info *ehi = &ap->eh_info; + struct ata_eh_info *ehi = &ap->link.eh_info; ata_ehi_clear_desc(ehi); @@ -1508,7 +1508,7 @@ static void mv_intr_pio(struct ata_port *ap) return; /* get active ATA command */ - qc = ata_qc_from_tag(ap, ap->active_tag); + qc = ata_qc_from_tag(ap, ap->link.active_tag); if (unlikely(!qc)) /* no active tag */ return; if (qc->tf.flags & ATA_TFLAG_POLLING) /* polling; we don't own qc */ @@ -1543,7 +1543,7 @@ static void mv_intr_edma(struct ata_port *ap) /* 50xx: get active ATA command */ if (IS_GEN_I(hpriv)) - tag = ap->active_tag; + tag = ap->link.active_tag; /* Gen II/IIE: get active ATA command via tag, to enable * support for queueing. this works transparently for @@ -1646,7 +1646,7 @@ static void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc) if (unlikely(have_err_bits)) { struct ata_queued_cmd *qc; - qc = ata_qc_from_tag(ap, ap->active_tag); + qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc && (qc->tf.flags & ATA_TFLAG_POLLING)) continue; @@ -1688,14 +1688,14 @@ static void mv_pci_error(struct ata_host *host, void __iomem *mmio) for (i = 0; i < host->n_ports; i++) { ap = host->ports[i]; if (!ata_port_offline(ap)) { - ehi = &ap->eh_info; + ehi = &ap->link.eh_info; ata_ehi_clear_desc(ehi); if (!printed++) ata_ehi_push_desc(ehi, "PCI err cause 0x%08x", err_cause); err_mask = AC_ERR_HOST_BUS; ehi->action = ATA_EH_HARDRESET; - qc = ata_qc_from_tag(ap, ap->active_tag); + qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc) qc->err_mask |= err_mask; else @@ -2269,7 +2269,7 @@ comreset_retry: static int mv_prereset(struct ata_port *ap, unsigned long deadline) { struct mv_port_priv *pp = ap->private_data; - struct ata_eh_context *ehc = &ap->eh_context; + struct ata_eh_context *ehc = &ap->link.eh_context; int rc; rc = mv_stop_dma(ap); diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index 40dc7313985..df4d50dcffb 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -594,7 +594,7 @@ static int nv_adma_slave_config(struct scsi_device *sdev) /* Not a proper libata device, ignore */ return rc; - if (ap->device[sdev->id].class == ATA_DEV_ATAPI) { + if (ap->link.device[sdev->id].class == ATA_DEV_ATAPI) { /* * NVIDIA reports that ADMA mode does not support ATAPI commands. * Therefore ATAPI commands are sent through the legacy interface. @@ -711,7 +711,7 @@ static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err) flags & (NV_CPB_RESP_ATA_ERR | NV_CPB_RESP_CMD_ERR | NV_CPB_RESP_CPB_ERR)))) { - struct ata_eh_info *ehi = &ap->eh_info; + struct ata_eh_info *ehi = &ap->link.eh_info; int freeze = 0; ata_ehi_clear_desc(ehi); @@ -747,7 +747,7 @@ static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err) DPRINTK("Completing qc from tag %d\n",cpb_num); ata_qc_complete(qc); } else { - struct ata_eh_info *ehi = &ap->eh_info; + struct ata_eh_info *ehi = &ap->link.eh_info; /* Notifier bits set without a command may indicate the drive is misbehaving. Raise host state machine violation on this condition. */ @@ -764,7 +764,7 @@ static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err) static int nv_host_intr(struct ata_port *ap, u8 irq_stat) { - struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag); + struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->link.active_tag); /* freeze if hotplugged */ if (unlikely(irq_stat & (NV_INT_ADDED | NV_INT_REMOVED))) { @@ -817,7 +817,7 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance) if (pp->flags & NV_ADMA_PORT_REGISTER_MODE) { u8 irq_stat = readb(host->iomap[NV_MMIO_BAR] + NV_INT_STATUS_CK804) >> (NV_INT_PORT_SHIFT * i); - if(ata_tag_valid(ap->active_tag)) + if(ata_tag_valid(ap->link.active_tag)) /** NV_INT_DEV indication seems unreliable at times at least in ADMA mode. Force it on always when a command is active, to prevent losing interrupts. */ @@ -852,7 +852,7 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance) NV_ADMA_STAT_HOTUNPLUG | NV_ADMA_STAT_TIMEOUT | NV_ADMA_STAT_SERROR))) { - struct ata_eh_info *ehi = &ap->eh_info; + struct ata_eh_info *ehi = &ap->link.eh_info; ata_ehi_clear_desc(ehi); __ata_ehi_push_desc(ehi, "ADMA status 0x%08x: ", status ); @@ -879,10 +879,10 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance) u32 check_commands; int pos, error = 0; - if(ata_tag_valid(ap->active_tag)) - check_commands = 1 << ap->active_tag; + if(ata_tag_valid(ap->link.active_tag)) + check_commands = 1 << ap->link.active_tag; else - check_commands = ap->sactive; + check_commands = ap->link.sactive; /** Check CPBs for completed commands */ while ((pos = ffs(check_commands)) && !error) { @@ -1333,7 +1333,7 @@ static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance) !(ap->flags & ATA_FLAG_DISABLED)) { struct ata_queued_cmd *qc; - qc = ata_qc_from_tag(ap, ap->active_tag); + qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) handled += ata_host_intr(ap, qc); else @@ -1485,7 +1485,7 @@ static void nv_adma_error_handler(struct ata_port *ap) int i; u16 tmp; - if(ata_tag_valid(ap->active_tag) || ap->sactive) { + if(ata_tag_valid(ap->link.active_tag) || ap->link.sactive) { u32 notifier = readl(mmio + NV_ADMA_NOTIFIER); u32 notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR); u32 gen_ctl = readl(pp->gen_block + NV_ADMA_GEN_CTL); @@ -1501,8 +1501,8 @@ static void nv_adma_error_handler(struct ata_port *ap) for( i=0;icpb[i]; - if( (ata_tag_valid(ap->active_tag) && i == ap->active_tag) || - ap->sactive & (1 << i) ) + if( (ata_tag_valid(ap->link.active_tag) && i == ap->link.active_tag) || + ap->link.sactive & (1 << i) ) ata_port_printk(ap, KERN_ERR, "CPB %d: ctl_flags 0x%x, resp_flags 0x%x\n", i, cpb->ctl_flags, cpb->resp_flags); diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c index 25698cf0dce..620d0675d18 100644 --- a/drivers/ata/sata_promise.c +++ b/drivers/ata/sata_promise.c @@ -626,7 +626,7 @@ static void pdc_post_internal_cmd(struct ata_queued_cmd *qc) static void pdc_error_intr(struct ata_port *ap, struct ata_queued_cmd *qc, u32 port_status, u32 err_mask) { - struct ata_eh_info *ehi = &ap->eh_info; + struct ata_eh_info *ehi = &ap->link.eh_info; unsigned int ac_err_mask = 0; ata_ehi_clear_desc(ehi); @@ -773,7 +773,7 @@ static irqreturn_t pdc_interrupt (int irq, void *dev_instance) tmp = hotplug_status & (0x11 << ata_no); if (tmp && ap && !(ap->flags & ATA_FLAG_DISABLED)) { - struct ata_eh_info *ehi = &ap->eh_info; + struct ata_eh_info *ehi = &ap->link.eh_info; ata_ehi_clear_desc(ehi); ata_ehi_hotplugged(ehi); ata_ehi_push_desc(ehi, "hotplug_status %#x", tmp); @@ -788,7 +788,7 @@ static irqreturn_t pdc_interrupt (int irq, void *dev_instance) !(ap->flags & ATA_FLAG_DISABLED)) { struct ata_queued_cmd *qc; - qc = ata_qc_from_tag(ap, ap->active_tag); + qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) handled += pdc_host_intr(ap, qc); } diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c index 5e1dfdda698..ef1ad69c26e 100644 --- a/drivers/ata/sata_qstor.c +++ b/drivers/ata/sata_qstor.c @@ -404,7 +404,7 @@ static inline unsigned int qs_intr_pkt(struct ata_host *host) struct qs_port_priv *pp = ap->private_data; if (!pp || pp->state != qs_state_pkt) continue; - qc = ata_qc_from_tag(ap, ap->active_tag); + qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) { switch (sHST) { case 0: /* successful CPB */ @@ -437,7 +437,7 @@ static inline unsigned int qs_intr_mmio(struct ata_host *host) struct qs_port_priv *pp = ap->private_data; if (!pp || pp->state != qs_state_mmio) continue; - qc = ata_qc_from_tag(ap, ap->active_tag); + qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) { /* check main status, clearing INTRQ */ diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index 8c72e714b45..2ddbe4cc71e 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -312,7 +312,7 @@ static int sil_set_mode (struct ata_port *ap, struct ata_device **r_failed) return rc; for (i = 0; i < 2; i++) { - dev = &ap->device[i]; + dev = &ap->link.device[i]; if (!ata_dev_enabled(dev)) dev_mode[i] = 0; /* PIO0/1/2 */ else if (dev->flags & ATA_DFLAG_PIO) @@ -374,8 +374,8 @@ static int sil_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val) static void sil_host_intr(struct ata_port *ap, u32 bmdma2) { - struct ata_eh_info *ehi = &ap->eh_info; - struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag); + struct ata_eh_info *ehi = &ap->link.eh_info; + struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->link.active_tag); u8 status; if (unlikely(bmdma2 & SIL_DMA_SATA_IRQ)) { @@ -394,8 +394,8 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2) * repeat probing needlessly. */ if (!(ap->pflags & ATA_PFLAG_FROZEN)) { - ata_ehi_hotplugged(&ap->eh_info); - ap->eh_info.serror |= serror; + ata_ehi_hotplugged(&ap->link.eh_info); + ap->link.eh_info.serror |= serror; } goto freeze; @@ -562,8 +562,8 @@ static void sil_thaw(struct ata_port *ap) */ static void sil_dev_config(struct ata_device *dev) { - struct ata_port *ap = dev->ap; - int print_info = ap->eh_context.i.flags & ATA_EHI_PRINTINFO; + struct ata_port *ap = dev->link->ap; + int print_info = ap->link.eh_context.i.flags & ATA_EHI_PRINTINFO; unsigned int n, quirks = 0; unsigned char model_num[ATA_ID_PROD_LEN + 1]; diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index 233e8869339..2d8334e7921 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -456,7 +456,7 @@ static int sil24_tag(int tag) static void sil24_dev_config(struct ata_device *dev) { - void __iomem *port = dev->ap->ioaddr.cmd_addr; + void __iomem *port = dev->link->ap->ioaddr.cmd_addr; if (dev->cdb_len == 16) writel(PORT_CS_CDB16, port + PORT_CTRL_STAT); @@ -609,7 +609,7 @@ static int sil24_do_softreset(struct ata_port *ap, unsigned int *class, if (time_after(deadline, jiffies)) timeout_msec = jiffies_to_msecs(deadline - jiffies); - ata_tf_init(ap->device, &tf); /* doesn't really matter */ + ata_tf_init(ap->link.device, &tf); /* doesn't really matter */ rc = sil24_exec_polled_cmd(ap, pmp, &tf, 0, PRB_CTRL_SRST, timeout_msec); if (rc == -EBUSY) { @@ -804,7 +804,7 @@ static void sil24_error_intr(struct ata_port *ap) { void __iomem *port = ap->ioaddr.cmd_addr; struct sil24_port_priv *pp = ap->private_data; - struct ata_eh_info *ehi = &ap->eh_info; + struct ata_eh_info *ehi = &ap->link.eh_info; int freeze = 0; u32 irq_stat; @@ -856,7 +856,7 @@ static void sil24_error_intr(struct ata_port *ap) } /* record error info */ - qc = ata_qc_from_tag(ap, ap->active_tag); + qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc) { sil24_read_tf(ap, qc->tag, &pp->tf); qc->err_mask |= err_mask; @@ -910,7 +910,7 @@ static inline void sil24_host_intr(struct ata_port *ap) if (rc > 0) return; if (rc < 0) { - struct ata_eh_info *ehi = &ap->eh_info; + struct ata_eh_info *ehi = &ap->link.eh_info; ehi->err_mask |= AC_ERR_HSM; ehi->action |= ATA_EH_SOFTRESET; ata_port_freeze(ap); @@ -921,7 +921,7 @@ static inline void sil24_host_intr(struct ata_port *ap) if (!(ap->flags & SIL24_FLAG_PCIX_IRQ_WOC) && ata_ratelimit()) ata_port_printk(ap, KERN_INFO, "spurious interrupt " "(slot_stat 0x%x active_tag %d sactive 0x%x)\n", - slot_stat, ap->active_tag, ap->sactive); + slot_stat, ap->link.active_tag, ap->link.sactive); } static irqreturn_t sil24_interrupt(int irq, void *dev_instance) @@ -963,7 +963,7 @@ static irqreturn_t sil24_interrupt(int irq, void *dev_instance) static void sil24_error_handler(struct ata_port *ap) { - struct ata_eh_context *ehc = &ap->eh_context; + struct ata_eh_context *ehc = &ap->link.eh_context; if (sil24_init_port(ap)) { ata_eh_freeze_port(ap); diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c index 97aefdd87be..12691f09193 100644 --- a/drivers/ata/sata_sx4.c +++ b/drivers/ata/sata_sx4.c @@ -854,7 +854,7 @@ static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance) !(ap->flags & ATA_FLAG_DISABLED)) { struct ata_queued_cmd *qc; - qc = ata_qc_from_tag(ap, ap->active_tag); + qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) handled += pdc20621_host_intr(ap, qc, (i > 4), mmio_base); @@ -881,7 +881,7 @@ static void pdc_eng_timeout(struct ata_port *ap) spin_lock_irqsave(&host->lock, flags); - qc = ata_qc_from_tag(ap, ap->active_tag); + qc = ata_qc_from_tag(ap, ap->link.active_tag); switch (qc->tf.protocol) { case ATA_PROT_DMA: diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index 57fd30de8f0..78a6833af71 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c @@ -296,7 +296,7 @@ static void svia_noop_freeze(struct ata_port *ap) */ static int vt6420_prereset(struct ata_port *ap, unsigned long deadline) { - struct ata_eh_context *ehc = &ap->eh_context; + struct ata_eh_context *ehc = &ap->link.eh_context; unsigned long timeout = jiffies + (HZ * 5); u32 sstatus, scontrol; int online; diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c index 1920915dfa2..9586b8b51ce 100644 --- a/drivers/ata/sata_vsc.c +++ b/drivers/ata/sata_vsc.c @@ -240,7 +240,7 @@ static void vsc_port_intr(u8 port_status, struct ata_port *ap) return; } - qc = ata_qc_from_tag(ap, ap->active_tag); + qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc && likely(!(qc->tf.flags & ATA_TFLAG_POLLING))) handled = ata_host_intr(ap, qc); diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index f142eafb6fc..affd77aafb2 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -4988,14 +4988,14 @@ static void ipr_ata_phy_reset(struct ata_port *ap) switch(res->cfgte.proto) { case IPR_PROTO_SATA: case IPR_PROTO_SAS_STP: - ap->device[0].class = ATA_DEV_ATA; + ap->link.device[0].class = ATA_DEV_ATA; break; case IPR_PROTO_SATA_ATAPI: case IPR_PROTO_SAS_STP_ATAPI: - ap->device[0].class = ATA_DEV_ATAPI; + ap->link.device[0].class = ATA_DEV_ATAPI; break; default: - ap->device[0].class = ATA_DEV_UNKNOWN; + ap->link.device[0].class = ATA_DEV_UNKNOWN; ap->ops->port_disable(ap); break; }; diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index 5e573efcf0a..1d6503d85f0 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -249,17 +249,17 @@ static void sas_ata_phy_reset(struct ata_port *ap) switch (dev->sata_dev.command_set) { case ATA_COMMAND_SET: SAS_DPRINTK("%s: Found ATA device.\n", __FUNCTION__); - ap->device[0].class = ATA_DEV_ATA; + ap->link.device[0].class = ATA_DEV_ATA; break; case ATAPI_COMMAND_SET: SAS_DPRINTK("%s: Found ATAPI device.\n", __FUNCTION__); - ap->device[0].class = ATA_DEV_ATAPI; + ap->link.device[0].class = ATA_DEV_ATAPI; break; default: SAS_DPRINTK("%s: Unknown SATA command set: %d.\n", __FUNCTION__, dev->sata_dev.command_set); - ap->device[0].class = ATA_DEV_UNKNOWN; + ap->link.device[0].class = ATA_DEV_UNKNOWN; break; } @@ -317,7 +317,7 @@ static int sas_ata_scr_write(struct ata_port *ap, unsigned int sc_reg_in, dev->sata_dev.serror = val; break; case SCR_ACTIVE: - dev->sata_dev.ap->sactive = val; + dev->sata_dev.ap->link.sactive = val; break; default: return -EINVAL; @@ -342,7 +342,7 @@ static int sas_ata_scr_read(struct ata_port *ap, unsigned int sc_reg_in, *val = dev->sata_dev.serror; return 0; case SCR_ACTIVE: - *val = dev->sata_dev.ap->sactive; + *val = dev->sata_dev.ap->link.sactive; return 0; default: return -EINVAL; diff --git a/include/linux/libata.h b/include/linux/libata.h index a67bb9075e9..ca4493125fa 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -436,7 +436,7 @@ struct ata_ering { }; struct ata_device { - struct ata_port *ap; + struct ata_link *link; unsigned int devno; /* 0 or 1 */ unsigned long flags; /* ATA_DFLAG_xxx */ unsigned int horkage; /* List of broken features */ @@ -510,6 +510,24 @@ struct ata_acpi_gtm { u32 flags; } __packed; +struct ata_link { + struct ata_port *ap; + + unsigned int active_tag; /* active tag on this link */ + u32 sactive; /* active NCQ commands */ + + unsigned int hw_sata_spd_limit; + unsigned int sata_spd_limit; + unsigned int sata_spd; /* current SATA PHY speed */ + + /* record runtime error info, protected by host_set lock */ + struct ata_eh_info eh_info; + /* EH context */ + struct ata_eh_context eh_context; + + struct ata_device device[ATA_MAX_DEVICES]; +}; + struct ata_port { struct Scsi_Host *scsi_host; /* our co-allocated scsi host */ const struct ata_port_operations *ops; @@ -533,23 +551,12 @@ struct ata_port { unsigned int mwdma_mask; unsigned int udma_mask; unsigned int cbl; /* cable type; ATA_CBL_xxx */ - unsigned int hw_sata_spd_limit; - unsigned int sata_spd_limit; /* SATA PHY speed limit */ - unsigned int sata_spd; /* current SATA PHY speed */ - - /* record runtime error info, protected by host lock */ - struct ata_eh_info eh_info; - /* EH context owned by EH */ - struct ata_eh_context eh_context; - - struct ata_device device[ATA_MAX_DEVICES]; struct ata_queued_cmd qcmd[ATA_MAX_QUEUE]; unsigned long qc_allocated; unsigned int qc_active; - unsigned int active_tag; - u32 sactive; + struct ata_link link; /* host default link */ struct ata_port_stats stats; struct ata_host *host; @@ -912,8 +919,11 @@ extern void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset, #define ata_port_printk(ap, lv, fmt, args...) \ printk(lv"ata%u: "fmt, (ap)->print_id , ##args) +#define ata_link_printk(link, lv, fmt, args...) \ + printk(lv"ata%u: "fmt, (link)->ap->print_id , ##args) + #define ata_dev_printk(dev, lv, fmt, args...) \ - printk(lv"ata%u.%02u: "fmt, (dev)->ap->print_id, (dev)->devno , ##args) + printk(lv"ata%u.%02u: "fmt, (dev)->link->ap->print_id, (dev)->devno , ##args) /* * ata_eh_info helpers @@ -1149,7 +1159,7 @@ static inline void ata_tf_init(struct ata_device *dev, struct ata_taskfile *tf) { memset(tf, 0, sizeof(*tf)); - tf->ctl = dev->ap->ctl; + tf->ctl = dev->link->ap->ctl; if (dev->devno == 0) tf->device = ATA_DEVICE_OBS; else -- cgit v1.2.3-70-g09d2 From f58229f8060055b08b34008ea08f31de1e2f003c Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 6 Aug 2007 18:36:23 +0900 Subject: libata-link: implement and use link/device iterators Multiple links and different number of devices per link should be considered to iterate over links and devices. This patch implements and uses link and device iterators - ata_port_for_each_link() and ata_link_for_each_dev() - and ata_link_max_devices(). This change makes a lot of functions iterate over only possible devices instead of from dev 0 to dev ATA_MAX_DEVICES. All such changes have been examined and nothing should be broken. While at it, add a separating comment before device helpers to distinguish them better from link helpers and others. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ata_generic.c | 7 ++- drivers/ata/libata-acpi.c | 6 +-- drivers/ata/libata-core.c | 58 +++++++++------------ drivers/ata/libata-eh.c | 117 ++++++++++++++++++++++--------------------- drivers/ata/libata-scsi.c | 26 ++++------ drivers/ata/pata_it821x.c | 5 +- drivers/ata/pata_ixp4xx_cf.c | 5 +- drivers/ata/pata_legacy.c | 5 +- drivers/ata/pata_pdc2027x.c | 13 +++-- drivers/ata/pata_platform.c | 6 +-- drivers/ata/pata_rz1000.c | 5 +- drivers/ata/sata_sil.c | 12 ++--- include/linux/libata.h | 17 +++++-- 13 files changed, 134 insertions(+), 148 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c index b5e390ff5bd..44328a16075 100644 --- a/drivers/ata/ata_generic.c +++ b/drivers/ata/ata_generic.c @@ -46,21 +46,20 @@ static int generic_set_mode(struct ata_port *ap, struct ata_device **unused) { int dma_enabled = 0; - int i; + struct ata_device *dev; /* Bits 5 and 6 indicate if DMA is active on master/slave */ if (ap->ioaddr.bmdma_addr) dma_enabled = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); - for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->link.device[i]; + ata_link_for_each_dev(dev, &ap->link) { if (ata_dev_enabled(dev)) { /* We don't really care */ dev->pio_mode = XFER_PIO_0; dev->dma_mode = XFER_MW_DMA_0; /* We do need the right mode information for DMA or PIO and this comes from the current configuration flags */ - if (dma_enabled & (1 << (5 + i))) { + if (dma_enabled & (1 << (5 + dev->devno))) { ata_id_to_dma_mode(dev, XFER_MW_DMA_0); dev->flags &= ~ATA_DFLAG_PIO; } else { diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index 0023ac4ff49..43af2e06d44 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -509,7 +509,7 @@ int ata_acpi_on_suspend(struct ata_port *ap) */ void ata_acpi_on_resume(struct ata_port *ap) { - int i; + struct ata_device *dev; if (ap->acpi_handle && (ap->pflags & ATA_PFLAG_GTM_VALID)) { BUG_ON(ap->flags & ATA_FLAG_ACPI_SATA); @@ -519,8 +519,8 @@ void ata_acpi_on_resume(struct ata_port *ap) } /* schedule _GTF */ - for (i = 0; i < ATA_MAX_DEVICES; i++) - ap->link.device[i].flags |= ATA_DFLAG_ACPI_PENDING; + ata_link_for_each_dev(dev, &ap->link) + dev->flags |= ATA_DFLAG_ACPI_PENDING; } /** diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index dd2de485124..f30c4771b3a 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2105,21 +2105,19 @@ int ata_bus_probe(struct ata_port *ap) { unsigned int classes[ATA_MAX_DEVICES]; int tries[ATA_MAX_DEVICES]; - int i, rc; + int rc; struct ata_device *dev; ata_port_probe(ap); - for (i = 0; i < ATA_MAX_DEVICES; i++) - tries[i] = ATA_PROBE_MAX_TRIES; + ata_link_for_each_dev(dev, &ap->link) + tries[dev->devno] = ATA_PROBE_MAX_TRIES; retry: /* reset and determine device classes */ ap->ops->phy_reset(ap); - for (i = 0; i < ATA_MAX_DEVICES; i++) { - dev = &ap->link.device[i]; - + ata_link_for_each_dev(dev, &ap->link) { if (!(ap->flags & ATA_FLAG_DISABLED) && dev->class != ATA_DEV_UNKNOWN) classes[dev->devno] = dev->class; @@ -2134,18 +2132,16 @@ int ata_bus_probe(struct ata_port *ap) /* after the reset the device state is PIO 0 and the controller state is undefined. Record the mode */ - for (i = 0; i < ATA_MAX_DEVICES; i++) - ap->link.device[i].pio_mode = XFER_PIO_0; + ata_link_for_each_dev(dev, &ap->link) + dev->pio_mode = XFER_PIO_0; /* read IDENTIFY page and configure devices. We have to do the identify specific sequence bass-ackwards so that PDIAG- is released by the slave device */ - for (i = ATA_MAX_DEVICES - 1; i >= 0; i--) { - dev = &ap->link.device[i]; - - if (tries[i]) - dev->class = classes[i]; + ata_link_for_each_dev(dev, &ap->link) { + if (tries[dev->devno]) + dev->class = classes[dev->devno]; if (!ata_dev_enabled(dev)) continue; @@ -2163,8 +2159,7 @@ int ata_bus_probe(struct ata_port *ap) /* After the identify sequence we can now set up the devices. We do this in the normal order so that the user doesn't get confused */ - for(i = 0; i < ATA_MAX_DEVICES; i++) { - dev = &ap->link.device[i]; + ata_link_for_each_dev(dev, &ap->link) { if (!ata_dev_enabled(dev)) continue; @@ -2180,8 +2175,8 @@ int ata_bus_probe(struct ata_port *ap) if (rc) goto fail; - for (i = 0; i < ATA_MAX_DEVICES; i++) - if (ata_dev_enabled(&ap->link.device[i])) + ata_link_for_each_dev(dev, &ap->link) + if (ata_dev_enabled(dev)) return 0; /* no device present, disable port */ @@ -2803,16 +2798,14 @@ static int ata_dev_set_mode(struct ata_device *dev) int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) { + struct ata_link *link = &ap->link; struct ata_device *dev; - int i, rc = 0, used_dma = 0, found = 0; - + int rc = 0, used_dma = 0, found = 0; /* step 1: calculate xfer_mask */ - for (i = 0; i < ATA_MAX_DEVICES; i++) { + ata_link_for_each_dev(dev, link) { unsigned int pio_mask, dma_mask; - dev = &ap->link.device[i]; - if (!ata_dev_enabled(dev)) continue; @@ -2831,8 +2824,7 @@ int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) goto out; /* step 2: always set host PIO timings */ - for (i = 0; i < ATA_MAX_DEVICES; i++) { - dev = &ap->link.device[i]; + ata_link_for_each_dev(dev, link) { if (!ata_dev_enabled(dev)) continue; @@ -2849,9 +2841,7 @@ int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) } /* step 3: set host DMA timings */ - for (i = 0; i < ATA_MAX_DEVICES; i++) { - dev = &ap->link.device[i]; - + ata_link_for_each_dev(dev, link) { if (!ata_dev_enabled(dev) || !dev->dma_mode) continue; @@ -2862,9 +2852,7 @@ int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) } /* step 4: update devices' xfer mode */ - for (i = 0; i < ATA_MAX_DEVICES; i++) { - dev = &ap->link.device[i]; - + ata_link_for_each_dev(dev, link) { /* don't update suspended devices' xfer mode */ if (!ata_dev_enabled(dev)) continue; @@ -6113,6 +6101,7 @@ struct ata_port *ata_port_alloc(struct ata_host *host) ap->link.ap = ap; + /* can't use iterator, ap isn't initialized yet */ for (i = 0; i < ATA_MAX_DEVICES; i++) { struct ata_device *dev = &ap->link.device[i]; dev->link = &ap->link; @@ -6453,7 +6442,8 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) /* kick EH for boot probing */ spin_lock_irqsave(ap->lock, flags); - ehi->probe_mask = (1 << ATA_MAX_DEVICES) - 1; + ehi->probe_mask = + (1 << ata_link_max_devices(&ap->link)) - 1; ehi->action |= ATA_EH_SOFTRESET; ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET; @@ -6551,7 +6541,7 @@ int ata_host_activate(struct ata_host *host, int irq, void ata_port_detach(struct ata_port *ap) { unsigned long flags; - int i; + struct ata_device *dev; if (!ap->ops->error_handler) goto skip_eh; @@ -6568,8 +6558,8 @@ void ata_port_detach(struct ata_port *ap) */ spin_lock_irqsave(ap->lock, flags); - for (i = 0; i < ATA_MAX_DEVICES; i++) - ata_dev_disable(&ap->link.device[i]); + ata_link_for_each_dev(dev, &ap->link) + ata_dev_disable(dev); spin_unlock_irqrestore(ap->lock, flags); diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index e2681f56ed4..8c37ec0bbf6 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -200,23 +200,24 @@ static unsigned int ata_eh_dev_action(struct ata_device *dev) return ehc->i.action | ehc->i.dev_action[dev->devno]; } -static void ata_eh_clear_action(struct ata_device *dev, +static void ata_eh_clear_action(struct ata_link *link, struct ata_device *dev, struct ata_eh_info *ehi, unsigned int action) { - int i; + struct ata_device *tdev; if (!dev) { ehi->action &= ~action; - for (i = 0; i < ATA_MAX_DEVICES; i++) - ehi->dev_action[i] &= ~action; + ata_link_for_each_dev(tdev, link) + ehi->dev_action[tdev->devno] &= ~action; } else { /* doesn't make sense for port-wide EH actions */ WARN_ON(!(action & ATA_EH_PERDEV_MASK)); /* break ehi->action into ehi->dev_action */ if (ehi->action & action) { - for (i = 0; i < ATA_MAX_DEVICES; i++) - ehi->dev_action[i] |= ehi->action & action; + ata_link_for_each_dev(tdev, link) + ehi->dev_action[tdev->devno] |= + ehi->action & action; ehi->action &= ~action; } @@ -922,7 +923,8 @@ void ata_eh_qc_retry(struct ata_queued_cmd *qc) */ static void ata_eh_detach_dev(struct ata_device *dev) { - struct ata_port *ap = dev->link->ap; + struct ata_link *link = dev->link; + struct ata_port *ap = link->ap; unsigned long flags; ata_dev_disable(dev); @@ -937,8 +939,8 @@ static void ata_eh_detach_dev(struct ata_device *dev) } /* clear per-dev EH actions */ - ata_eh_clear_action(dev, &dev->link->eh_info, ATA_EH_PERDEV_MASK); - ata_eh_clear_action(dev, &dev->link->eh_context.i, ATA_EH_PERDEV_MASK); + ata_eh_clear_action(link, dev, &link->eh_info, ATA_EH_PERDEV_MASK); + ata_eh_clear_action(link, dev, &link->eh_context.i, ATA_EH_PERDEV_MASK); spin_unlock_irqrestore(ap->lock, flags); } @@ -978,7 +980,7 @@ static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev, ehi->flags &= ~ATA_EHI_RESET_MODIFIER_MASK; } - ata_eh_clear_action(dev, ehi, action); + ata_eh_clear_action(&ap->link, dev, ehi, action); if (!(ehc->i.flags & ATA_EHI_QUIET)) ap->pflags |= ATA_PFLAG_RECOVERED; @@ -1009,7 +1011,7 @@ static void ata_eh_done(struct ata_port *ap, struct ata_device *dev, ehc->i.flags &= ~ATA_EHI_RESET_MODIFIER_MASK; } - ata_eh_clear_action(dev, &ehc->i, action); + ata_eh_clear_action(&ap->link, dev, &ehc->i, action); } /** @@ -1736,10 +1738,11 @@ static void ata_eh_report(struct ata_port *ap) static int ata_do_reset(struct ata_port *ap, ata_reset_fn_t reset, unsigned int *classes, unsigned long deadline) { - int i, rc; + struct ata_device *dev; + int rc; - for (i = 0; i < ATA_MAX_DEVICES; i++) - classes[i] = ATA_DEV_UNKNOWN; + ata_link_for_each_dev(dev, &ap->link) + classes[dev->devno] = ATA_DEV_UNKNOWN; rc = reset(ap, classes, deadline); if (rc) @@ -1749,14 +1752,16 @@ static int ata_do_reset(struct ata_port *ap, ata_reset_fn_t reset, * is complete and convert all ATA_DEV_UNKNOWN to * ATA_DEV_NONE. */ - for (i = 0; i < ATA_MAX_DEVICES; i++) - if (classes[i] != ATA_DEV_UNKNOWN) + ata_link_for_each_dev(dev, &ap->link) + if (classes[dev->devno] != ATA_DEV_UNKNOWN) break; - if (i < ATA_MAX_DEVICES) - for (i = 0; i < ATA_MAX_DEVICES; i++) - if (classes[i] == ATA_DEV_UNKNOWN) - classes[i] = ATA_DEV_NONE; + if (dev) { + ata_link_for_each_dev(dev, &ap->link) { + if (classes[dev->devno] == ATA_DEV_UNKNOWN) + classes[dev->devno] = ATA_DEV_NONE; + } + } return 0; } @@ -1781,10 +1786,11 @@ static int ata_eh_reset(struct ata_port *ap, int classify, unsigned int *classes = ehc->classes; int verbose = !(ehc->i.flags & ATA_EHI_QUIET); int try = 0; + struct ata_device *dev; unsigned long deadline; unsigned int action; ata_reset_fn_t reset; - int i, rc; + int rc; /* about to reset */ ata_eh_about_to_do(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK); @@ -1808,8 +1814,8 @@ static int ata_eh_reset(struct ata_port *ap, int classify, "port disabled. ignoring.\n"); ehc->i.action &= ~ATA_EH_RESET_MASK; - for (i = 0; i < ATA_MAX_DEVICES; i++) - classes[i] = ATA_DEV_NONE; + ata_link_for_each_dev(dev, &ap->link) + classes[dev->devno] = ATA_DEV_NONE; rc = 0; } else @@ -1826,8 +1832,8 @@ static int ata_eh_reset(struct ata_port *ap, int classify, reset = softreset; else { /* prereset told us not to reset, bang classes and return */ - for (i = 0; i < ATA_MAX_DEVICES; i++) - classes[i] = ATA_DEV_NONE; + ata_link_for_each_dev(dev, &ap->link) + classes[dev->devno] = ATA_DEV_NONE; rc = 0; goto out; } @@ -1908,8 +1914,8 @@ static int ata_eh_reset(struct ata_port *ap, int classify, /* After the reset, the device state is PIO 0 and the * controller state is undefined. Record the mode. */ - for (i = 0; i < ATA_MAX_DEVICES; i++) - ap->link.device[i].pio_mode = XFER_PIO_0; + ata_link_for_each_dev(dev, &ap->link) + dev->pio_mode = XFER_PIO_0; /* record current link speed */ if (sata_scr_read(ap, SCR_STATUS, &sstatus) == 0) @@ -1935,7 +1941,7 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, struct ata_device *dev; unsigned int new_mask = 0; unsigned long flags; - int i, rc = 0; + int rc = 0; DPRINTK("ENTER\n"); @@ -1943,11 +1949,9 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, * be done backwards such that PDIAG- is released by the slave * device before the master device is identified. */ - for (i = ATA_MAX_DEVICES - 1; i >= 0; i--) { - unsigned int action, readid_flags = 0; - - dev = &ap->link.device[i]; - action = ata_eh_dev_action(dev); + ata_link_for_each_dev_reverse(dev, &ap->link) { + unsigned int action = ata_eh_dev_action(dev); + unsigned int readid_flags = 0; if (ehc->i.flags & ATA_EHI_DID_RESET) readid_flags |= ATA_READID_POSTRESET; @@ -1981,7 +1985,7 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, dev->id); switch (rc) { case 0: - new_mask |= 1 << i; + new_mask |= 1 << dev->devno; break; case -ENOENT: /* IDENTIFY was issued to non-existent @@ -2005,10 +2009,8 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, /* Configure new devices forward such that user doesn't see * device detection messages backwards. */ - for (i = 0; i < ATA_MAX_DEVICES; i++) { - dev = &ap->link.device[i]; - - if (!(new_mask & (1 << i))) + ata_link_for_each_dev(dev, &ap->link) { + if (!(new_mask & (1 << dev->devno))) continue; ehc->i.flags |= ATA_EHI_PRINTINFO; @@ -2035,20 +2037,22 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, static int ata_port_nr_enabled(struct ata_port *ap) { - int i, cnt = 0; + struct ata_device *dev; + int cnt = 0; - for (i = 0; i < ATA_MAX_DEVICES; i++) - if (ata_dev_enabled(&ap->link.device[i])) + ata_link_for_each_dev(dev, &ap->link) + if (ata_dev_enabled(dev)) cnt++; return cnt; } static int ata_port_nr_vacant(struct ata_port *ap) { - int i, cnt = 0; + struct ata_device *dev; + int cnt = 0; - for (i = 0; i < ATA_MAX_DEVICES; i++) - if (ap->link.device[i].class == ATA_DEV_UNKNOWN) + ata_link_for_each_dev(dev, &ap->link) + if (dev->class == ATA_DEV_UNKNOWN) cnt++; return cnt; } @@ -2056,7 +2060,7 @@ static int ata_port_nr_vacant(struct ata_port *ap) static int ata_eh_skip_recovery(struct ata_port *ap) { struct ata_eh_context *ehc = &ap->link.eh_context; - int i; + struct ata_device *dev; /* thaw frozen port, resume link and recover failed devices */ if ((ap->pflags & ATA_PFLAG_FROZEN) || @@ -2064,9 +2068,7 @@ static int ata_eh_skip_recovery(struct ata_port *ap) return 0; /* skip if class codes for all vacant slots are ATA_DEV_NONE */ - for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->link.device[i]; - + ata_link_for_each_dev(dev, &ap->link) { if (dev->class == ATA_DEV_UNKNOWN && ehc->classes[dev->devno] != ATA_DEV_NONE) return 0; @@ -2153,19 +2155,18 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, { struct ata_eh_context *ehc = &ap->link.eh_context; struct ata_device *dev; - int i, rc; + int rc; DPRINTK("ENTER\n"); /* prep for recovery */ - for (i = 0; i < ATA_MAX_DEVICES; i++) { - dev = &ap->link.device[i]; - + ata_link_for_each_dev(dev, &ap->link) { ehc->tries[dev->devno] = ATA_EH_DEV_TRIES; /* collect port action mask recorded in dev actions */ - ehc->i.action |= ehc->i.dev_action[i] & ~ATA_EH_PERDEV_MASK; - ehc->i.dev_action[i] &= ATA_EH_PERDEV_MASK; + ehc->i.action |= + ehc->i.dev_action[dev->devno] & ~ATA_EH_PERDEV_MASK; + ehc->i.dev_action[dev->devno] &= ATA_EH_PERDEV_MASK; /* process hotplug request */ if (dev->flags & ATA_DFLAG_DETACH) @@ -2192,8 +2193,8 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, if (ata_eh_skip_recovery(ap)) ehc->i.action = 0; - for (i = 0; i < ATA_MAX_DEVICES; i++) - ehc->classes[i] = ATA_DEV_UNKNOWN; + ata_link_for_each_dev(dev, &ap->link) + ehc->classes[dev->devno] = ATA_DEV_UNKNOWN; /* reset */ if (ehc->i.action & ATA_EH_RESET_MASK) { @@ -2241,8 +2242,8 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, out: if (rc) { - for (i = 0; i < ATA_MAX_DEVICES; i++) - ata_dev_disable(&ap->link.device[i]); + ata_link_for_each_dev(dev, &ap->link); + ata_dev_disable(dev); } DPRINTK("EXIT, rc=%d\n", rc); diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index ec0e2638200..3d6d5f73799 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -2425,7 +2425,7 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc) static struct ata_device * ata_find_dev(struct ata_port *ap, int id) { - if (likely(id < ATA_MAX_DEVICES)) + if (likely(id < ata_link_max_devices(&ap->link))) return &ap->link.device[id]; return NULL; } @@ -2952,21 +2952,18 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync) int tries = 5; struct ata_device *last_failed_dev = NULL; struct ata_device *dev; - unsigned int i; if (ap->flags & ATA_FLAG_DISABLED) return; repeat: - for (i = 0; i < ATA_MAX_DEVICES; i++) { + ata_link_for_each_dev(dev, &ap->link) { struct scsi_device *sdev; - dev = &ap->link.device[i]; - if (!ata_dev_enabled(dev) || dev->sdev) continue; - sdev = __scsi_add_device(ap->scsi_host, 0, i, 0, NULL); + sdev = __scsi_add_device(ap->scsi_host, 0, dev->devno, 0, NULL); if (!IS_ERR(sdev)) { dev->sdev = sdev; scsi_device_put(sdev); @@ -2977,12 +2974,11 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync) * failure occurred, scan would have failed silently. Check * whether all devices are attached. */ - for (i = 0; i < ATA_MAX_DEVICES; i++) { - dev = &ap->link.device[i]; + ata_link_for_each_dev(dev, &ap->link) { if (ata_dev_enabled(dev) && !dev->sdev) break; } - if (i == ATA_MAX_DEVICES) + if (!dev) return; /* we're missing some SCSI devices */ @@ -3112,7 +3108,7 @@ void ata_scsi_hotplug(struct work_struct *work) { struct ata_port *ap = container_of(work, struct ata_port, hotplug_task.work); - int i; + struct ata_device *dev; if (ap->pflags & ATA_PFLAG_UNLOADING) { DPRINTK("ENTER/EXIT - unloading\n"); @@ -3122,8 +3118,7 @@ void ata_scsi_hotplug(struct work_struct *work) DPRINTK("ENTER\n"); /* unplug detached devices */ - for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->link.device[i]; + ata_link_for_each_dev(dev, &ap->link) { unsigned long flags; if (!(dev->flags & ATA_DFLAG_DETACHED)) @@ -3176,7 +3171,7 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel, spin_lock_irqsave(ap->lock, flags); if (id == SCAN_WILD_CARD) { - ehi->probe_mask |= (1 << ATA_MAX_DEVICES) - 1; + ehi->probe_mask |= (1 << ata_link_max_devices(&ap->link)) - 1; ehi->action |= ATA_EH_SOFTRESET; } else { struct ata_device *dev = ata_find_dev(ap, id); @@ -3215,13 +3210,12 @@ void ata_scsi_dev_rescan(struct work_struct *work) { struct ata_port *ap = container_of(work, struct ata_port, scsi_rescan_task); + struct ata_device *dev; unsigned long flags; - unsigned int i; spin_lock_irqsave(ap->lock, flags); - for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->link.device[i]; + ata_link_for_each_dev(dev, &ap->link) { struct scsi_device *sdev = dev->sdev; if (!ata_dev_enabled(dev) || !sdev) diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c index ece1a28f0a4..088eb1d2376 100644 --- a/drivers/ata/pata_it821x.c +++ b/drivers/ata/pata_it821x.c @@ -461,10 +461,9 @@ static unsigned int it821x_passthru_qc_issue_prot(struct ata_queued_cmd *qc) static int it821x_smart_set_mode(struct ata_port *ap, struct ata_device **unused) { - int i; + struct ata_device *dev; - for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->link.device[i]; + ata_link_for_each_dev(dev, &ap->link) { if (ata_dev_enabled(dev)) { /* We don't really care */ dev->pio_mode = XFER_PIO_0; diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c index 3e2b8ce5fa3..7db315a9baa 100644 --- a/drivers/ata/pata_ixp4xx_cf.c +++ b/drivers/ata/pata_ixp4xx_cf.c @@ -28,10 +28,9 @@ static int ixp4xx_set_mode(struct ata_port *ap, struct ata_device **error) { - int i; + struct ata_device *dev; - for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->link.device[i]; + ata_link_for_each_dev(dev, &ap->link) { if (ata_dev_enabled(dev)) { ata_dev_printk(dev, KERN_INFO, "configured for PIO0\n"); dev->pio_mode = XFER_PIO_0; diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c index 4bcc0ae8d10..9d92843b033 100644 --- a/drivers/ata/pata_legacy.c +++ b/drivers/ata/pata_legacy.c @@ -109,10 +109,9 @@ static int iordy_mask = 0xFFFFFFFF; /* Use iordy if available */ static int legacy_set_mode(struct ata_port *ap, struct ata_device **unused) { - int i; + struct ata_device *dev; - for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->link.device[i]; + ata_link_for_each_dev(dev, &ap->link) { if (ata_dev_enabled(dev)) { ata_dev_printk(dev, KERN_INFO, "configured for PIO\n"); dev->pio_mode = XFER_PIO_0; diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c index fa780509a1d..83c90cabc7f 100644 --- a/drivers/ata/pata_pdc2027x.c +++ b/drivers/ata/pata_pdc2027x.c @@ -479,15 +479,14 @@ static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev) */ static int pdc2027x_set_mode(struct ata_port *ap, struct ata_device **r_failed) { - int i; - - i = ata_do_set_mode(ap, r_failed); - if (i < 0) - return i; + struct ata_device *dev; + int rc; - for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->link.device[i]; + rc = ata_do_set_mode(ap, r_failed); + if (rc < 0) + return rc; + ata_link_for_each_dev(dev, &ap->link) { if (ata_dev_enabled(dev)) { pdc2027x_set_piomode(ap, dev); diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c index e89656bffa8..ee1605bfc29 100644 --- a/drivers/ata/pata_platform.c +++ b/drivers/ata/pata_platform.c @@ -32,11 +32,9 @@ static int pio_mask = 1; */ static int pata_platform_set_mode(struct ata_port *ap, struct ata_device **unused) { - int i; - - for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->link.device[i]; + struct ata_device *dev; + ata_link_for_each_dev(dev, &ap->link) { if (ata_dev_enabled(dev)) { /* We don't really care */ dev->pio_mode = dev->xfer_mode = XFER_PIO_0; diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c index 57363c0ce06..300b3d5de81 100644 --- a/drivers/ata/pata_rz1000.c +++ b/drivers/ata/pata_rz1000.c @@ -36,10 +36,9 @@ static int rz1000_set_mode(struct ata_port *ap, struct ata_device **unused) { - int i; + struct ata_device *dev; - for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->link.device[i]; + ata_link_for_each_dev(dev, &ap->link) { if (ata_dev_enabled(dev)) { /* We don't really care */ dev->pio_mode = XFER_PIO_0; diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index 2ddbe4cc71e..4c9295a49a4 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -303,22 +303,20 @@ static int sil_set_mode (struct ata_port *ap, struct ata_device **r_failed) struct ata_device *dev; void __iomem *mmio_base = host->iomap[SIL_MMIO_BAR]; void __iomem *addr = mmio_base + sil_port[ap->port_no].xfer_mode; - u32 tmp, dev_mode[2]; - unsigned int i; + u32 tmp, dev_mode[2] = { }; int rc; rc = ata_do_set_mode(ap, r_failed); if (rc) return rc; - for (i = 0; i < 2; i++) { - dev = &ap->link.device[i]; + ata_link_for_each_dev(dev, &ap->link) { if (!ata_dev_enabled(dev)) - dev_mode[i] = 0; /* PIO0/1/2 */ + dev_mode[dev->devno] = 0; /* PIO0/1/2 */ else if (dev->flags & ATA_DFLAG_PIO) - dev_mode[i] = 1; /* PIO3/4 */ + dev_mode[dev->devno] = 1; /* PIO3/4 */ else - dev_mode[i] = 3; /* UDMA */ + dev_mode[dev->devno] = 3; /* UDMA */ /* value 2 indicates MDMA */ } diff --git a/include/linux/libata.h b/include/linux/libata.h index ca4493125fa..62fa8cf677a 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -1030,15 +1030,26 @@ static inline unsigned int ata_dev_absent(const struct ata_device *dev) } /* - * port helpers + * link helpers */ -static inline int ata_port_max_devices(const struct ata_port *ap) +static inline int ata_link_max_devices(const struct ata_link *link) { - if (ap->flags & ATA_FLAG_SLAVE_POSS) + if (link->ap->flags & ATA_FLAG_SLAVE_POSS) return 2; return 1; } +#define ata_port_for_each_link(lk, ap) \ + for ((lk) = &(ap)->link; (lk); (lk) = NULL) + +#define ata_link_for_each_dev(dev, link) \ + for ((dev) = (link)->device; \ + (dev) < (link)->device + ata_link_max_devices(link) || ((dev) = NULL); \ + (dev)++) + +#define ata_link_for_each_dev_reverse(dev, link) \ + for ((dev) = (link)->device + ata_link_max_devices(link) - 1; \ + (dev) >= (link)->device || ((dev) = NULL); (dev)--) static inline u8 ata_chk_status(struct ata_port *ap) { -- cgit v1.2.3-70-g09d2 From 936fd7328657884d5a69a55666c74a55aa83ca27 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 6 Aug 2007 18:36:23 +0900 Subject: libata-link: linkify PHY-related functions Make the following PHY-related functions to deal with ata_link instead of ata_port. * sata_print_link_status() * sata_down_spd_limit() * ata_set_sata_spd_limit() and friends * sata_link_debounce/resume() * sata_scr_valid/read/write/write_flush() * ata_link_on/offline() This patch introduces no behavior change. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 4 +- drivers/ata/libata-core.c | 227 +++++++++++++++++++++++--------------------- drivers/ata/libata-eh.c | 31 +++--- drivers/ata/libata-sff.c | 2 +- drivers/ata/libata.h | 4 +- drivers/ata/pata_scc.c | 2 +- drivers/ata/sata_inic162x.c | 4 +- drivers/ata/sata_mv.c | 26 ++--- drivers/ata/sata_promise.c | 4 +- drivers/ata/sata_sil24.c | 10 +- include/linux/libata.h | 24 ++--- 11 files changed, 177 insertions(+), 161 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index c72fa468a69..6e5f69a3a0c 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1052,7 +1052,7 @@ static int ahci_do_softreset(struct ata_port *ap, unsigned int *class, DPRINTK("ENTER\n"); - if (ata_port_offline(ap)) { + if (ata_link_offline(&ap->link)) { DPRINTK("PHY reports no device\n"); *class = ATA_DEV_NONE; return 0; @@ -1140,7 +1140,7 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class, ahci_start_engine(ap); - if (rc == 0 && ata_port_online(ap)) + if (rc == 0 && ata_link_online(&ap->link)) *class = ahci_dev_classify(ap); if (*class == ATA_DEV_UNKNOWN) *class = ATA_DEV_NONE; diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index f30c4771b3a..6f99dee6b6d 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2201,7 +2201,7 @@ int ata_bus_probe(struct ata_port *ap) /* This is the last chance, better to slow * down than lose it. */ - sata_down_spd_limit(ap); + sata_down_spd_limit(&ap->link); ata_down_xfermask_limit(dev, ATA_DNXFER_PIO); } } @@ -2230,28 +2230,28 @@ void ata_port_probe(struct ata_port *ap) /** * sata_print_link_status - Print SATA link status - * @ap: SATA port to printk link status about + * @link: SATA link to printk link status about * * This function prints link speed and status of a SATA link. * * LOCKING: * None. */ -void sata_print_link_status(struct ata_port *ap) +void sata_print_link_status(struct ata_link *link) { u32 sstatus, scontrol, tmp; - if (sata_scr_read(ap, SCR_STATUS, &sstatus)) + if (sata_scr_read(link, SCR_STATUS, &sstatus)) return; - sata_scr_read(ap, SCR_CONTROL, &scontrol); + sata_scr_read(link, SCR_CONTROL, &scontrol); - if (ata_port_online(ap)) { + if (ata_link_online(link)) { tmp = (sstatus >> 4) & 0xf; - ata_port_printk(ap, KERN_INFO, + ata_link_printk(link, KERN_INFO, "SATA link up %s (SStatus %X SControl %X)\n", sata_spd_string(tmp), sstatus, scontrol); } else { - ata_port_printk(ap, KERN_INFO, + ata_link_printk(link, KERN_INFO, "SATA link down (SStatus %X SControl %X)\n", sstatus, scontrol); } @@ -2271,32 +2271,33 @@ void sata_print_link_status(struct ata_port *ap) */ void __sata_phy_reset(struct ata_port *ap) { - u32 sstatus; + struct ata_link *link = &ap->link; unsigned long timeout = jiffies + (HZ * 5); + u32 sstatus; if (ap->flags & ATA_FLAG_SATA_RESET) { /* issue phy wake/reset */ - sata_scr_write_flush(ap, SCR_CONTROL, 0x301); + sata_scr_write_flush(link, SCR_CONTROL, 0x301); /* Couldn't find anything in SATA I/II specs, but * AHCI-1.1 10.4.2 says at least 1 ms. */ mdelay(1); } /* phy wake/clear reset */ - sata_scr_write_flush(ap, SCR_CONTROL, 0x300); + sata_scr_write_flush(link, SCR_CONTROL, 0x300); /* wait for phy to become ready, if necessary */ do { msleep(200); - sata_scr_read(ap, SCR_STATUS, &sstatus); + sata_scr_read(link, SCR_STATUS, &sstatus); if ((sstatus & 0xf) != 1) break; } while (time_before(jiffies, timeout)); /* print link status */ - sata_print_link_status(ap); + sata_print_link_status(link); /* TODO: phy layer with polling, timeouts, etc. */ - if (!ata_port_offline(ap)) + if (!ata_link_offline(link)) ata_port_probe(ap); else ata_port_disable(ap); @@ -2370,9 +2371,9 @@ void ata_port_disable(struct ata_port *ap) /** * sata_down_spd_limit - adjust SATA spd limit downward - * @ap: Port to adjust SATA spd limit for + * @link: Link to adjust SATA spd limit for * - * Adjust SATA spd limit of @ap downward. Note that this + * Adjust SATA spd limit of @link downward. Note that this * function only adjusts the limit. The change must be applied * using sata_set_spd(). * @@ -2382,24 +2383,24 @@ void ata_port_disable(struct ata_port *ap) * RETURNS: * 0 on success, negative errno on failure */ -int sata_down_spd_limit(struct ata_port *ap) +int sata_down_spd_limit(struct ata_link *link) { u32 sstatus, spd, mask; int rc, highbit; - if (!sata_scr_valid(ap)) + if (!sata_scr_valid(link)) return -EOPNOTSUPP; /* If SCR can be read, use it to determine the current SPD. - * If not, use cached value in ap->sata_spd. + * If not, use cached value in link->sata_spd. */ - rc = sata_scr_read(ap, SCR_STATUS, &sstatus); + rc = sata_scr_read(link, SCR_STATUS, &sstatus); if (rc == 0) spd = (sstatus >> 4) & 0xf; else - spd = ap->link.sata_spd; + spd = link->sata_spd; - mask = ap->link.sata_spd_limit; + mask = link->sata_spd_limit; if (mask <= 1) return -EINVAL; @@ -2419,22 +2420,22 @@ int sata_down_spd_limit(struct ata_port *ap) if (!mask) return -EINVAL; - ap->link.sata_spd_limit = mask; + link->sata_spd_limit = mask; - ata_port_printk(ap, KERN_WARNING, "limiting SATA link speed to %s\n", + ata_link_printk(link, KERN_WARNING, "limiting SATA link speed to %s\n", sata_spd_string(fls(mask))); return 0; } -static int __sata_set_spd_needed(struct ata_port *ap, u32 *scontrol) +static int __sata_set_spd_needed(struct ata_link *link, u32 *scontrol) { u32 spd, limit; - if (ap->link.sata_spd_limit == UINT_MAX) + if (link->sata_spd_limit == UINT_MAX) limit = 0; else - limit = fls(ap->link.sata_spd_limit); + limit = fls(link->sata_spd_limit); spd = (*scontrol >> 4) & 0xf; *scontrol = (*scontrol & ~0xf0) | ((limit & 0xf) << 4); @@ -2444,10 +2445,10 @@ static int __sata_set_spd_needed(struct ata_port *ap, u32 *scontrol) /** * sata_set_spd_needed - is SATA spd configuration needed - * @ap: Port in question + * @link: Link in question * * Test whether the spd limit in SControl matches - * @ap->link.sata_spd_limit. This function is used to determine + * @link->sata_spd_limit. This function is used to determine * whether hardreset is necessary to apply SATA spd * configuration. * @@ -2457,21 +2458,21 @@ static int __sata_set_spd_needed(struct ata_port *ap, u32 *scontrol) * RETURNS: * 1 if SATA spd configuration is needed, 0 otherwise. */ -int sata_set_spd_needed(struct ata_port *ap) +int sata_set_spd_needed(struct ata_link *link) { u32 scontrol; - if (sata_scr_read(ap, SCR_CONTROL, &scontrol)) + if (sata_scr_read(link, SCR_CONTROL, &scontrol)) return 0; - return __sata_set_spd_needed(ap, &scontrol); + return __sata_set_spd_needed(link, &scontrol); } /** * sata_set_spd - set SATA spd according to spd limit - * @ap: Port to set SATA spd for + * @link: Link to set SATA spd for * - * Set SATA spd of @ap according to sata_spd_limit. + * Set SATA spd of @link according to sata_spd_limit. * * LOCKING: * Inherited from caller. @@ -2480,18 +2481,18 @@ int sata_set_spd_needed(struct ata_port *ap) * 0 if spd doesn't need to be changed, 1 if spd has been * changed. Negative errno if SCR registers are inaccessible. */ -int sata_set_spd(struct ata_port *ap) +int sata_set_spd(struct ata_link *link) { u32 scontrol; int rc; - if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol))) + if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol))) return rc; - if (!__sata_set_spd_needed(ap, &scontrol)) + if (!__sata_set_spd_needed(link, &scontrol)) return 0; - if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol))) + if ((rc = sata_scr_write(link, SCR_CONTROL, scontrol))) return rc; return 1; @@ -2997,7 +2998,7 @@ int ata_wait_ready(struct ata_port *ap, unsigned long deadline) if (!(status & ATA_BUSY)) return 0; - if (!ata_port_online(ap) && status == 0xff) + if (!ata_link_online(&ap->link) && status == 0xff) return -ENODEV; if (time_after(now, deadline)) return -EBUSY; @@ -3199,12 +3200,12 @@ err_out: } /** - * sata_phy_debounce - debounce SATA phy status - * @ap: ATA port to debounce SATA phy status for + * sata_link_debounce - debounce SATA phy status + * @link: ATA link to debounce SATA phy status for * @params: timing parameters { interval, duratinon, timeout } in msec * @deadline: deadline jiffies for the operation * - * Make sure SStatus of @ap reaches stable state, determined by +* Make sure SStatus of @link reaches stable state, determined by * holding the same value where DET is not 1 for @duration polled * every @interval, before @timeout. Timeout constraints the * beginning of the stable state. Because DET gets stuck at 1 on @@ -3220,8 +3221,8 @@ err_out: * RETURNS: * 0 on success, -errno on failure. */ -int sata_phy_debounce(struct ata_port *ap, const unsigned long *params, - unsigned long deadline) +int sata_link_debounce(struct ata_link *link, const unsigned long *params, + unsigned long deadline) { unsigned long interval_msec = params[0]; unsigned long duration = msecs_to_jiffies(params[1]); @@ -3233,7 +3234,7 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params, if (time_before(t, deadline)) deadline = t; - if ((rc = sata_scr_read(ap, SCR_STATUS, &cur))) + if ((rc = sata_scr_read(link, SCR_STATUS, &cur))) return rc; cur &= 0xf; @@ -3242,7 +3243,7 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params, while (1) { msleep(interval_msec); - if ((rc = sata_scr_read(ap, SCR_STATUS, &cur))) + if ((rc = sata_scr_read(link, SCR_STATUS, &cur))) return rc; cur &= 0xf; @@ -3268,12 +3269,12 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params, } /** - * sata_phy_resume - resume SATA phy - * @ap: ATA port to resume SATA phy for + * sata_link_resume - resume SATA link + * @link: ATA link to resume SATA * @params: timing parameters { interval, duratinon, timeout } in msec * @deadline: deadline jiffies for the operation * - * Resume SATA phy of @ap and debounce it. + * Resume SATA phy @link and debounce it. * * LOCKING: * Kernel thread context (may sleep) @@ -3281,18 +3282,18 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params, * RETURNS: * 0 on success, -errno on failure. */ -int sata_phy_resume(struct ata_port *ap, const unsigned long *params, - unsigned long deadline) +int sata_link_resume(struct ata_link *link, const unsigned long *params, + unsigned long deadline) { u32 scontrol; int rc; - if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol))) + if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol))) return rc; scontrol = (scontrol & 0x0f0) | 0x300; - if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol))) + if ((rc = sata_scr_write(link, SCR_CONTROL, scontrol))) return rc; /* Some PHYs react badly if SStatus is pounded immediately @@ -3300,7 +3301,7 @@ int sata_phy_resume(struct ata_port *ap, const unsigned long *params, */ msleep(200); - return sata_phy_debounce(ap, params, deadline); + return sata_link_debounce(link, params, deadline); } /** @@ -3322,7 +3323,8 @@ int sata_phy_resume(struct ata_port *ap, const unsigned long *params, */ int ata_std_prereset(struct ata_port *ap, unsigned long deadline) { - struct ata_eh_context *ehc = &ap->link.eh_context; + struct ata_link *link = &ap->link; + struct ata_eh_context *ehc = &link->eh_context; const unsigned long *timing = sata_ehc_deb_timing(ehc); int rc; @@ -3335,9 +3337,9 @@ int ata_std_prereset(struct ata_port *ap, unsigned long deadline) if (ehc->i.action & ATA_EH_HARDRESET) return 0; - /* if SATA, resume phy */ + /* if SATA, resume link */ if (ap->flags & ATA_FLAG_SATA) { - rc = sata_phy_resume(ap, timing, deadline); + rc = sata_link_resume(link, timing, deadline); /* whine about phy resume failure but proceed */ if (rc && rc != -EOPNOTSUPP) ata_port_printk(ap, KERN_WARNING, "failed to resume " @@ -3347,7 +3349,7 @@ int ata_std_prereset(struct ata_port *ap, unsigned long deadline) /* Wait for !BSY if the controller can wait for the first D2H * Reg FIS and we don't know that no device is attached. */ - if (!(ap->flags & ATA_FLAG_SKIP_D2H_BSY) && !ata_port_offline(ap)) { + if (!(ap->flags & ATA_FLAG_SKIP_D2H_BSY) && !ata_link_offline(link)) { rc = ata_wait_ready(ap, deadline); if (rc && rc != -ENODEV) { ata_port_printk(ap, KERN_WARNING, "device not ready " @@ -3376,6 +3378,7 @@ int ata_std_prereset(struct ata_port *ap, unsigned long deadline) int ata_std_softreset(struct ata_port *ap, unsigned int *classes, unsigned long deadline) { + struct ata_link *link = &ap->link; unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS; unsigned int devmask = 0; int rc; @@ -3383,7 +3386,7 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes, DPRINTK("ENTER\n"); - if (ata_port_offline(ap)) { + if (ata_link_offline(link)) { classes[0] = ATA_DEV_NONE; goto out; } @@ -3401,7 +3404,7 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes, DPRINTK("about to softreset, devmask=%x\n", devmask); rc = ata_bus_softreset(ap, devmask, deadline); /* if link is occupied, -ENODEV too is an error */ - if (rc && (rc != -ENODEV || sata_scr_valid(ap))) { + if (rc && (rc != -ENODEV || sata_scr_valid(link))) { ata_port_printk(ap, KERN_ERR, "SRST failed (errno=%d)\n", rc); return rc; } @@ -3433,35 +3436,36 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes, int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing, unsigned long deadline) { + struct ata_link *link = &ap->link; u32 scontrol; int rc; DPRINTK("ENTER\n"); - if (sata_set_spd_needed(ap)) { + if (sata_set_spd_needed(link)) { /* SATA spec says nothing about how to reconfigure * spd. To be on the safe side, turn off phy during * reconfiguration. This works for at least ICH7 AHCI * and Sil3124. */ - if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol))) + if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol))) goto out; scontrol = (scontrol & 0x0f0) | 0x304; - if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol))) + if ((rc = sata_scr_write(link, SCR_CONTROL, scontrol))) goto out; - sata_set_spd(ap); + sata_set_spd(link); } /* issue phy wake/reset */ - if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol))) + if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol))) goto out; scontrol = (scontrol & 0x0f0) | 0x301; - if ((rc = sata_scr_write_flush(ap, SCR_CONTROL, scontrol))) + if ((rc = sata_scr_write_flush(link, SCR_CONTROL, scontrol))) goto out; /* Couldn't find anything in SATA I/II specs, but AHCI-1.1 @@ -3469,8 +3473,8 @@ int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing, */ msleep(1); - /* bring phy back */ - rc = sata_phy_resume(ap, timing, deadline); + /* bring link back */ + rc = sata_link_resume(link, timing, deadline); out: DPRINTK("EXIT, rc=%d\n", rc); return rc; @@ -3494,7 +3498,8 @@ int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing, int sata_std_hardreset(struct ata_port *ap, unsigned int *class, unsigned long deadline) { - const unsigned long *timing = sata_ehc_deb_timing(&ap->link.eh_context); + struct ata_link *link = &ap->link; + const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); int rc; DPRINTK("ENTER\n"); @@ -3508,7 +3513,7 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class, } /* TODO: phy layer with polling, timeouts, etc. */ - if (ata_port_offline(ap)) { + if (ata_link_offline(link)) { *class = ATA_DEV_NONE; DPRINTK("EXIT, link offline\n"); return 0; @@ -3547,16 +3552,17 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class, */ void ata_std_postreset(struct ata_port *ap, unsigned int *classes) { + struct ata_link *link = &ap->link; u32 serror; DPRINTK("ENTER\n"); /* print link status */ - sata_print_link_status(ap); + sata_print_link_status(link); /* clear SError */ - if (sata_scr_read(ap, SCR_ERROR, &serror) == 0) - sata_scr_write(ap, SCR_ERROR, serror); + if (sata_scr_read(link, SCR_ERROR, &serror) == 0) + sata_scr_write(link, SCR_ERROR, serror); /* is double-select really necessary? */ if (classes[0] != ATA_DEV_NONE) @@ -5729,9 +5735,9 @@ irqreturn_t ata_interrupt (int irq, void *dev_instance) /** * sata_scr_valid - test whether SCRs are accessible - * @ap: ATA port to test SCR accessibility for + * @link: ATA link to test SCR accessibility for * - * Test whether SCRs are accessible for @ap. + * Test whether SCRs are accessible for @link. * * LOCKING: * None. @@ -5739,18 +5745,20 @@ irqreturn_t ata_interrupt (int irq, void *dev_instance) * RETURNS: * 1 if SCRs are accessible, 0 otherwise. */ -int sata_scr_valid(struct ata_port *ap) +int sata_scr_valid(struct ata_link *link) { + struct ata_port *ap = link->ap; + return (ap->flags & ATA_FLAG_SATA) && ap->ops->scr_read; } /** * sata_scr_read - read SCR register of the specified port - * @ap: ATA port to read SCR for + * @link: ATA link to read SCR for * @reg: SCR to read * @val: Place to store read value * - * Read SCR register @reg of @ap into *@val. This function is + * Read SCR register @reg of @link into *@val. This function is * guaranteed to succeed if the cable type of the port is SATA * and the port implements ->scr_read. * @@ -5760,20 +5768,22 @@ int sata_scr_valid(struct ata_port *ap) * RETURNS: * 0 on success, negative errno on failure. */ -int sata_scr_read(struct ata_port *ap, int reg, u32 *val) +int sata_scr_read(struct ata_link *link, int reg, u32 *val) { - if (sata_scr_valid(ap)) + struct ata_port *ap = link->ap; + + if (sata_scr_valid(link)) return ap->ops->scr_read(ap, reg, val); return -EOPNOTSUPP; } /** * sata_scr_write - write SCR register of the specified port - * @ap: ATA port to write SCR for + * @link: ATA link to write SCR for * @reg: SCR to write * @val: value to write * - * Write @val to SCR register @reg of @ap. This function is + * Write @val to SCR register @reg of @link. This function is * guaranteed to succeed if the cable type of the port is SATA * and the port implements ->scr_read. * @@ -5783,16 +5793,18 @@ int sata_scr_read(struct ata_port *ap, int reg, u32 *val) * RETURNS: * 0 on success, negative errno on failure. */ -int sata_scr_write(struct ata_port *ap, int reg, u32 val) +int sata_scr_write(struct ata_link *link, int reg, u32 val) { - if (sata_scr_valid(ap)) + struct ata_port *ap = link->ap; + + if (sata_scr_valid(link)) return ap->ops->scr_write(ap, reg, val); return -EOPNOTSUPP; } /** * sata_scr_write_flush - write SCR register of the specified port and flush - * @ap: ATA port to write SCR for + * @link: ATA link to write SCR for * @reg: SCR to write * @val: value to write * @@ -5805,11 +5817,12 @@ int sata_scr_write(struct ata_port *ap, int reg, u32 val) * RETURNS: * 0 on success, negative errno on failure. */ -int sata_scr_write_flush(struct ata_port *ap, int reg, u32 val) +int sata_scr_write_flush(struct ata_link *link, int reg, u32 val) { + struct ata_port *ap = link->ap; int rc; - if (sata_scr_valid(ap)) { + if (sata_scr_valid(link)) { rc = ap->ops->scr_write(ap, reg, val); if (rc == 0) rc = ap->ops->scr_read(ap, reg, &val); @@ -5819,12 +5832,12 @@ int sata_scr_write_flush(struct ata_port *ap, int reg, u32 val) } /** - * ata_port_online - test whether the given port is online - * @ap: ATA port to test + * ata_link_online - test whether the given link is online + * @link: ATA link to test * - * Test whether @ap is online. Note that this function returns 0 - * if online status of @ap cannot be obtained, so - * ata_port_online(ap) != !ata_port_offline(ap). + * Test whether @link is online. Note that this function returns + * 0 if online status of @link cannot be obtained, so + * ata_link_online(link) != !ata_link_offline(link). * * LOCKING: * None. @@ -5832,22 +5845,23 @@ int sata_scr_write_flush(struct ata_port *ap, int reg, u32 val) * RETURNS: * 1 if the port online status is available and online. */ -int ata_port_online(struct ata_port *ap) +int ata_link_online(struct ata_link *link) { u32 sstatus; - if (!sata_scr_read(ap, SCR_STATUS, &sstatus) && (sstatus & 0xf) == 0x3) + if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0 && + (sstatus & 0xf) == 0x3) return 1; return 0; } /** - * ata_port_offline - test whether the given port is offline - * @ap: ATA port to test + * ata_link_offline - test whether the given link is offline + * @link: ATA link to test * - * Test whether @ap is offline. Note that this function returns - * 0 if offline status of @ap cannot be obtained, so - * ata_port_online(ap) != !ata_port_offline(ap). + * Test whether @link is offline. Note that this function + * returns 0 if offline status of @link cannot be obtained, so + * ata_link_online(link) != !ata_link_offline(link). * * LOCKING: * None. @@ -5855,11 +5869,12 @@ int ata_port_online(struct ata_port *ap) * RETURNS: * 1 if the port offline status is available and offline. */ -int ata_port_offline(struct ata_port *ap) +int ata_link_offline(struct ata_link *link) { u32 sstatus; - if (!sata_scr_read(ap, SCR_STATUS, &sstatus) && (sstatus & 0xf) != 0x3) + if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0 && + (sstatus & 0xf) != 0x3) return 1; return 0; } @@ -6397,7 +6412,7 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) ap->cbl = ATA_CBL_SATA; /* init sata_spd_limit to the current value */ - if (sata_scr_read(ap, SCR_CONTROL, &scontrol) == 0) { + if (sata_scr_read(&ap->link, SCR_CONTROL, &scontrol) == 0) { int spd = (scontrol >> 4) & 0xf; if (spd) ap->link.hw_sata_spd_limit &= (1 << spd) - 1; @@ -6924,8 +6939,8 @@ EXPORT_SYMBOL_GPL(ata_bmdma_post_internal_cmd); EXPORT_SYMBOL_GPL(ata_port_probe); EXPORT_SYMBOL_GPL(ata_dev_disable); EXPORT_SYMBOL_GPL(sata_set_spd); -EXPORT_SYMBOL_GPL(sata_phy_debounce); -EXPORT_SYMBOL_GPL(sata_phy_resume); +EXPORT_SYMBOL_GPL(sata_link_debounce); +EXPORT_SYMBOL_GPL(sata_link_resume); EXPORT_SYMBOL_GPL(sata_phy_reset); EXPORT_SYMBOL_GPL(__sata_phy_reset); EXPORT_SYMBOL_GPL(ata_bus_reset); @@ -6952,8 +6967,8 @@ EXPORT_SYMBOL_GPL(sata_scr_valid); EXPORT_SYMBOL_GPL(sata_scr_read); EXPORT_SYMBOL_GPL(sata_scr_write); EXPORT_SYMBOL_GPL(sata_scr_write_flush); -EXPORT_SYMBOL_GPL(ata_port_online); -EXPORT_SYMBOL_GPL(ata_port_offline); +EXPORT_SYMBOL_GPL(ata_link_online); +EXPORT_SYMBOL_GPL(ata_link_offline); #ifdef CONFIG_PM EXPORT_SYMBOL_GPL(ata_host_suspend); EXPORT_SYMBOL_GPL(ata_host_resume); diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 8c37ec0bbf6..48ca68b3979 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1501,7 +1501,7 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, int is_io, /* speed down? */ if (verdict & ATA_EH_SPDN_SPEED_DOWN) { /* speed down SATA link speed if possible */ - if (sata_down_spd_limit(dev->link->ap) == 0) { + if (sata_down_spd_limit(dev->link) == 0) { action |= ATA_EH_HARDRESET; goto done; } @@ -1561,7 +1561,8 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, int is_io, */ static void ata_eh_autopsy(struct ata_port *ap) { - struct ata_eh_context *ehc = &ap->link.eh_context; + struct ata_link *link = &ap->link; + struct ata_eh_context *ehc = &link->eh_context; unsigned int all_err_mask = 0; int tag, is_io = 0; u32 serror; @@ -1573,7 +1574,7 @@ static void ata_eh_autopsy(struct ata_port *ap) return; /* obtain and analyze SError */ - rc = sata_scr_read(ap, SCR_ERROR, &serror); + rc = sata_scr_read(link, SCR_ERROR, &serror); if (rc == 0) { ehc->i.serror |= serror; ata_eh_analyze_serror(ap); @@ -1782,7 +1783,8 @@ static int ata_eh_reset(struct ata_port *ap, int classify, ata_prereset_fn_t prereset, ata_reset_fn_t softreset, ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) { - struct ata_eh_context *ehc = &ap->link.eh_context; + struct ata_link *link = &ap->link; + struct ata_eh_context *ehc = &link->eh_context; unsigned int *classes = ehc->classes; int verbose = !(ehc->i.flags & ATA_EHI_QUIET); int try = 0; @@ -1800,7 +1802,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, */ action = ehc->i.action; ehc->i.action &= ~ATA_EH_RESET_MASK; - if (softreset && (!hardreset || (!sata_set_spd_needed(ap) && + if (softreset && (!hardreset || (!sata_set_spd_needed(link) && !(action & ATA_EH_HARDRESET)))) ehc->i.action |= ATA_EH_SOFTRESET; else @@ -1814,7 +1816,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, "port disabled. ignoring.\n"); ehc->i.action &= ~ATA_EH_RESET_MASK; - ata_link_for_each_dev(dev, &ap->link) + ata_link_for_each_dev(dev, link) classes[dev->devno] = ATA_DEV_NONE; rc = 0; @@ -1832,7 +1834,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, reset = softreset; else { /* prereset told us not to reset, bang classes and return */ - ata_link_for_each_dev(dev, &ap->link) + ata_link_for_each_dev(dev, link) classes[dev->devno] = ATA_DEV_NONE; rc = 0; goto out; @@ -1902,7 +1904,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, if (rc == -EPIPE || try == ARRAY_SIZE(ata_eh_reset_timeouts) - 1) - sata_down_spd_limit(ap); + sata_down_spd_limit(link); if (hardreset) reset = hardreset; goto retry; @@ -1914,12 +1916,12 @@ static int ata_eh_reset(struct ata_port *ap, int classify, /* After the reset, the device state is PIO 0 and the * controller state is undefined. Record the mode. */ - ata_link_for_each_dev(dev, &ap->link) + ata_link_for_each_dev(dev, link) dev->pio_mode = XFER_PIO_0; /* record current link speed */ - if (sata_scr_read(ap, SCR_STATUS, &sstatus) == 0) - ap->link.sata_spd = (sstatus >> 4) & 0xf; + if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0) + link->sata_spd = (sstatus >> 4) & 0xf; if (postreset) postreset(ap, classes); @@ -1957,7 +1959,7 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, readid_flags |= ATA_READID_POSTRESET; if ((action & ATA_EH_REVALIDATE) && ata_dev_enabled(dev)) { - if (ata_port_offline(ap)) { + if (ata_link_offline(&ap->link)) { rc = -EIO; goto err; } @@ -2079,7 +2081,6 @@ static int ata_eh_skip_recovery(struct ata_port *ap) static void ata_eh_handle_dev_fail(struct ata_device *dev, int err) { - struct ata_port *ap = dev->link->ap; struct ata_eh_context *ehc = &dev->link->eh_context; ehc->tries[dev->devno]--; @@ -2096,7 +2097,7 @@ static void ata_eh_handle_dev_fail(struct ata_device *dev, int err) /* This is the last chance, better to slow * down than lose it. */ - sata_down_spd_limit(ap); + sata_down_spd_limit(dev->link); ata_down_xfermask_limit(dev, ATA_DNXFER_PIO); } } @@ -2106,7 +2107,7 @@ static void ata_eh_handle_dev_fail(struct ata_device *dev, int err) ata_dev_disable(dev); /* detach if offline */ - if (ata_port_offline(ap)) + if (ata_link_offline(dev->link)) ata_eh_detach_dev(dev); /* probe if requested */ diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 2100cd61ed6..dd528dbd9cc 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -500,7 +500,7 @@ void ata_bmdma_error_handler(struct ata_port *ap) ata_reset_fn_t hardreset; hardreset = NULL; - if (sata_scr_valid(ap)) + if (sata_scr_valid(&ap->link)) hardreset = sata_std_hardreset; ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, hardreset, diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 564cd234c80..700843a9f30 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -78,8 +78,8 @@ extern int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, extern int ata_dev_reread_id(struct ata_device *dev, unsigned int readid_flags); extern int ata_dev_revalidate(struct ata_device *dev, unsigned int readid_flags); extern int ata_dev_configure(struct ata_device *dev); -extern int sata_down_spd_limit(struct ata_port *ap); -extern int sata_set_spd_needed(struct ata_port *ap); +extern int sata_down_spd_limit(struct ata_link *link); +extern int sata_set_spd_needed(struct ata_link *link); extern int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel); extern int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev); extern void ata_sg_clean(struct ata_queued_cmd *qc); diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c index aab068fbb7b..63fe99a10cd 100644 --- a/drivers/ata/pata_scc.c +++ b/drivers/ata/pata_scc.c @@ -612,7 +612,7 @@ static int scc_std_softreset (struct ata_port *ap, unsigned int *classes, DPRINTK("ENTER\n"); - if (ata_port_offline(ap)) { + if (ata_link_offline(&ap->link)) { classes[0] = ATA_DEV_NONE; goto out; } diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c index 3c0ef7a2f2f..f2b1bea934b 100644 --- a/drivers/ata/sata_inic162x.c +++ b/drivers/ata/sata_inic162x.c @@ -435,7 +435,7 @@ static int inic_hardreset(struct ata_port *ap, unsigned int *class, msleep(1); writew(val & ~IDMA_CTL_RST_ATA, idma_ctl); - rc = sata_phy_resume(ap, timing, deadline); + rc = sata_link_resume(&ap->link, timing, deadline); if (rc) { ata_port_printk(ap, KERN_WARNING, "failed to resume " "link after reset (errno=%d)\n", rc); @@ -443,7 +443,7 @@ static int inic_hardreset(struct ata_port *ap, unsigned int *class, } *class = ATA_DEV_NONE; - if (ata_port_online(ap)) { + if (ata_link_online(&ap->link)) { struct ata_taskfile tf; /* wait a while before checking status */ diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 246e7c5fdce..8e63c60adaf 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -1423,8 +1423,8 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc) /* just a guess: do we need to do this? should we * expand this, and do it in all cases? */ - sata_scr_read(ap, SCR_ERROR, &serr); - sata_scr_write_flush(ap, SCR_ERROR, serr); + sata_scr_read(&ap->link, SCR_ERROR, &serr); + sata_scr_write_flush(&ap->link, SCR_ERROR, serr); } edma_err_cause = readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS); @@ -1468,8 +1468,8 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc) } if (edma_err_cause & EDMA_ERR_SERR) { - sata_scr_read(ap, SCR_ERROR, &serr); - sata_scr_write_flush(ap, SCR_ERROR, serr); + sata_scr_read(&ap->link, SCR_ERROR, &serr); + sata_scr_write_flush(&ap->link, SCR_ERROR, serr); err_mask = AC_ERR_ATA_BUS; action |= ATA_EH_HARDRESET; } @@ -1687,7 +1687,7 @@ static void mv_pci_error(struct ata_host *host, void __iomem *mmio) for (i = 0; i < host->n_ports; i++) { ap = host->ports[i]; - if (!ata_port_offline(ap)) { + if (!ata_link_offline(&ap->link)) { ehi = &ap->link.eh_info; ata_ehi_clear_desc(ehi); if (!printed++) @@ -2198,14 +2198,14 @@ static void mv_phy_reset(struct ata_port *ap, unsigned int *class, /* Issue COMRESET via SControl */ comreset_retry: - sata_scr_write_flush(ap, SCR_CONTROL, 0x301); + sata_scr_write_flush(&ap->link, SCR_CONTROL, 0x301); msleep(1); - sata_scr_write_flush(ap, SCR_CONTROL, 0x300); + sata_scr_write_flush(&ap->link, SCR_CONTROL, 0x300); msleep(20); do { - sata_scr_read(ap, SCR_STATUS, &sstatus); + sata_scr_read(&ap->link, SCR_STATUS, &sstatus); if (((sstatus & 0x3) == 3) || ((sstatus & 0x3) == 0)) break; @@ -2230,7 +2230,7 @@ comreset_retry: } #endif - if (ata_port_offline(ap)) { + if (ata_link_offline(&ap->link)) { *class = ATA_DEV_NONE; return; } @@ -2285,7 +2285,7 @@ static int mv_prereset(struct ata_port *ap, unsigned long deadline) if (ehc->i.action & ATA_EH_HARDRESET) return 0; - if (ata_port_online(ap)) + if (ata_link_online(&ap->link)) rc = ata_wait_ready(ap, deadline); else rc = -ENODEV; @@ -2313,11 +2313,11 @@ static void mv_postreset(struct ata_port *ap, unsigned int *classes) u32 serr; /* print link status */ - sata_print_link_status(ap); + sata_print_link_status(&ap->link); /* clear SError */ - sata_scr_read(ap, SCR_ERROR, &serr); - sata_scr_write_flush(ap, SCR_ERROR, serr); + sata_scr_read(&ap->link, SCR_ERROR, &serr); + sata_scr_write_flush(&ap->link, SCR_ERROR, serr); /* bail out if no device is present */ if (classes[0] == ATA_DEV_NONE && classes[1] == ATA_DEV_NONE) { diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c index 620d0675d18..c7238ce8354 100644 --- a/drivers/ata/sata_promise.c +++ b/drivers/ata/sata_promise.c @@ -475,7 +475,7 @@ static void pdc_atapi_pkt(struct ata_queued_cmd *qc) buf32[2] = 0; /* no next-packet */ /* select drive */ - if (sata_scr_valid(ap)) { + if (sata_scr_valid(&ap->link)) { dev_sel = PDC_DEVICE_SATA; } else { dev_sel = ATA_DEVICE_OBS; @@ -643,7 +643,7 @@ static void pdc_error_intr(struct ata_port *ap, struct ata_queued_cmd *qc, | PDC_PCI_SYS_ERR | PDC1_PCI_PARITY_ERR)) ac_err_mask |= AC_ERR_HOST_BUS; - if (sata_scr_valid(ap)) { + if (sata_scr_valid(&ap->link)) { u32 serror; pdc_sata_scr_read(ap, SCR_ERROR, &serror); diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index 2d8334e7921..0cd40d5215f 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -593,7 +593,7 @@ static int sil24_do_softreset(struct ata_port *ap, unsigned int *class, DPRINTK("ENTER\n"); - if (ata_port_offline(ap)) { + if (ata_link_offline(&ap->link)) { DPRINTK("PHY reports no device\n"); *class = ATA_DEV_NONE; goto out; @@ -650,10 +650,10 @@ static int sil24_hardreset(struct ata_port *ap, unsigned int *class, u32 tmp; /* sil24 does the right thing(tm) without any protection */ - sata_set_spd(ap); + sata_set_spd(&ap->link); tout_msec = 100; - if (ata_port_online(ap)) + if (ata_link_online(&ap->link)) tout_msec = 5000; writel(PORT_CS_DEV_RST, port + PORT_CTRL_STAT); @@ -663,14 +663,14 @@ static int sil24_hardreset(struct ata_port *ap, unsigned int *class, /* SStatus oscillates between zero and valid status after * DEV_RST, debounce it. */ - rc = sata_phy_debounce(ap, sata_deb_timing_long, deadline); + rc = sata_link_debounce(&ap->link, sata_deb_timing_long, deadline); if (rc) { reason = "PHY debouncing failed"; goto err; } if (tmp & PORT_CS_DEV_RST) { - if (ata_port_offline(ap)) + if (ata_link_offline(&ap->link)) return 0; reason = "link not ready"; goto err; diff --git a/include/linux/libata.h b/include/linux/libata.h index 62fa8cf677a..e7882ba63e7 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -696,16 +696,16 @@ static inline int ata_port_is_dummy(struct ata_port *ap) return ap->ops == &ata_dummy_port_ops; } -extern void sata_print_link_status(struct ata_port *ap); +extern void sata_print_link_status(struct ata_link *link); extern void ata_port_probe(struct ata_port *); extern void __sata_phy_reset(struct ata_port *ap); extern void sata_phy_reset(struct ata_port *ap); extern void ata_bus_reset(struct ata_port *ap); -extern int sata_set_spd(struct ata_port *ap); -extern int sata_phy_debounce(struct ata_port *ap, const unsigned long *param, - unsigned long deadline); -extern int sata_phy_resume(struct ata_port *ap, const unsigned long *param, - unsigned long deadline); +extern int sata_set_spd(struct ata_link *link); +extern int sata_link_debounce(struct ata_link *link, + const unsigned long *params, unsigned long deadline); +extern int sata_link_resume(struct ata_link *link, const unsigned long *params, + unsigned long deadline); extern int ata_std_prereset(struct ata_port *ap, unsigned long deadline); extern int ata_std_softreset(struct ata_port *ap, unsigned int *classes, unsigned long deadline); @@ -753,12 +753,12 @@ extern int ata_sas_slave_configure(struct scsi_device *, struct ata_port *); extern int ata_sas_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), struct ata_port *ap); extern unsigned int ata_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc); -extern int sata_scr_valid(struct ata_port *ap); -extern int sata_scr_read(struct ata_port *ap, int reg, u32 *val); -extern int sata_scr_write(struct ata_port *ap, int reg, u32 val); -extern int sata_scr_write_flush(struct ata_port *ap, int reg, u32 val); -extern int ata_port_online(struct ata_port *ap); -extern int ata_port_offline(struct ata_port *ap); +extern int sata_scr_valid(struct ata_link *link); +extern int sata_scr_read(struct ata_link *link, int reg, u32 *val); +extern int sata_scr_write(struct ata_link *link, int reg, u32 val); +extern int sata_scr_write_flush(struct ata_link *link, int reg, u32 val); +extern int ata_link_online(struct ata_link *link); +extern int ata_link_offline(struct ata_link *link); #ifdef CONFIG_PM extern int ata_host_suspend(struct ata_host *host, pm_message_t mesg); extern void ata_host_resume(struct ata_host *host); -- cgit v1.2.3-70-g09d2 From 955e57dfde4ff75e4d7329ac7a3d645b16015309 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 6 Aug 2007 18:36:23 +0900 Subject: libata-link: linkify EH action helpers Make ata_eh_about_to_do() and ata_eh_done() deal with ata_link instead of ata_port. This patch introduces no behavior change. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-eh.c | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 48ca68b3979..fc4b6413b19 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -947,23 +947,24 @@ static void ata_eh_detach_dev(struct ata_device *dev) /** * ata_eh_about_to_do - about to perform eh_action - * @ap: target ATA port + * @link: target ATA link * @dev: target ATA dev for per-dev action (can be NULL) * @action: action about to be performed * * Called just before performing EH actions to clear related bits - * in @ap->link.eh_info such that eh actions are not - * unnecessarily repeated. + * in @link->eh_info such that eh actions are not unnecessarily + * repeated. * * LOCKING: * None. */ -static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev, +static void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev, unsigned int action) { + struct ata_port *ap = link->ap; + struct ata_eh_info *ehi = &link->eh_info; + struct ata_eh_context *ehc = &link->eh_context; unsigned long flags; - struct ata_eh_info *ehi = &ap->link.eh_info; - struct ata_eh_context *ehc = &ap->link.eh_context; spin_lock_irqsave(ap->lock, flags); @@ -980,7 +981,7 @@ static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev, ehi->flags &= ~ATA_EHI_RESET_MODIFIER_MASK; } - ata_eh_clear_action(&ap->link, dev, ehi, action); + ata_eh_clear_action(link, dev, ehi, action); if (!(ehc->i.flags & ATA_EHI_QUIET)) ap->pflags |= ATA_PFLAG_RECOVERED; @@ -990,20 +991,20 @@ static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev, /** * ata_eh_done - EH action complete - * @ap: target ATA port +* @ap: target ATA port * @dev: target ATA dev for per-dev action (can be NULL) * @action: action just completed * * Called right after performing EH actions to clear related bits - * in @ap->link.eh_context. + * in @link->eh_context. * * LOCKING: * None. */ -static void ata_eh_done(struct ata_port *ap, struct ata_device *dev, +static void ata_eh_done(struct ata_link *link, struct ata_device *dev, unsigned int action) { - struct ata_eh_context *ehc = &ap->link.eh_context; + struct ata_eh_context *ehc = &link->eh_context; /* if reset is complete, clear all reset actions & reset modifier */ if (action & ATA_EH_RESET_MASK) { @@ -1011,7 +1012,7 @@ static void ata_eh_done(struct ata_port *ap, struct ata_device *dev, ehc->i.flags &= ~ATA_EHI_RESET_MODIFIER_MASK; } - ata_eh_clear_action(&ap->link, dev, &ehc->i, action); + ata_eh_clear_action(link, dev, &ehc->i, action); } /** @@ -1795,7 +1796,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, int rc; /* about to reset */ - ata_eh_about_to_do(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK); + ata_eh_about_to_do(link, NULL, ehc->i.action & ATA_EH_RESET_MASK); /* Determine which reset to use and record in ehc->i.action. * prereset() may examine and modify it. @@ -1877,7 +1878,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, goto out; } - ata_eh_about_to_do(ap, NULL, ATA_EH_RESET_MASK); + ata_eh_about_to_do(link, NULL, ATA_EH_RESET_MASK); rc = ata_do_reset(ap, reset, classes, deadline); if (rc == 0 && classify && @@ -1927,7 +1928,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, postreset(ap, classes); /* reset successful, schedule revalidation */ - ata_eh_done(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK); + ata_eh_done(link, NULL, ehc->i.action & ATA_EH_RESET_MASK); ehc->i.action |= ATA_EH_REVALIDATE; } out: @@ -1964,12 +1965,12 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, goto err; } - ata_eh_about_to_do(ap, dev, ATA_EH_REVALIDATE); + ata_eh_about_to_do(&ap->link, dev, ATA_EH_REVALIDATE); rc = ata_dev_revalidate(dev, readid_flags); if (rc) goto err; - ata_eh_done(ap, dev, ATA_EH_REVALIDATE); + ata_eh_done(&ap->link, dev, ATA_EH_REVALIDATE); /* Configuration may have changed, reconfigure * transfer mode. -- cgit v1.2.3-70-g09d2 From cc0680a580b5be81a1ca321b58f8e9b80b5c1052 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 6 Aug 2007 18:36:23 +0900 Subject: libata-link: linkify reset Make reset methods and related functions deal with ata_link instead of ata_port. * ata_do_reset() * ata_eh_reset() * all prereset/reset/postreset methods and related functions This patch introduces no behavior change. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 34 +++++++++++++++++-------------- drivers/ata/ata_piix.c | 7 ++++--- drivers/ata/libata-core.c | 49 ++++++++++++++++++++++----------------------- drivers/ata/libata-eh.c | 35 ++++++++++++++++---------------- drivers/ata/pata_amd.c | 16 ++++++++------- drivers/ata/pata_artop.c | 12 ++++++----- drivers/ata/pata_atiixp.c | 5 +++-- drivers/ata/pata_efar.c | 7 ++++--- drivers/ata/pata_hpt37x.c | 12 ++++++----- drivers/ata/pata_hpt3x2n.c | 7 ++++--- drivers/ata/pata_it8213.c | 7 ++++--- drivers/ata/pata_jmicron.c | 8 ++++---- drivers/ata/pata_marvell.c | 7 ++++--- drivers/ata/pata_mpiix.c | 5 +++-- drivers/ata/pata_ns87410.c | 7 ++++--- drivers/ata/pata_oldpiix.c | 7 ++++--- drivers/ata/pata_opti.c | 7 ++++--- drivers/ata/pata_optidma.c | 7 ++++--- drivers/ata/pata_pdc2027x.c | 8 ++++---- drivers/ata/pata_sil680.c | 7 ++++--- drivers/ata/pata_sis.c | 7 ++++--- drivers/ata/pata_sl82c105.c | 7 ++++--- drivers/ata/pata_triflex.c | 7 ++++--- drivers/ata/pata_via.c | 5 +++-- drivers/ata/sata_inic162x.c | 13 ++++++------ drivers/ata/sata_mv.c | 19 ++++++++++-------- drivers/ata/sata_nv.c | 4 ++-- drivers/ata/sata_sil24.c | 26 +++++++++++++----------- drivers/ata/sata_via.c | 5 +++-- drivers/scsi/ipr.c | 8 ++++---- include/linux/libata.h | 19 +++++++++--------- 31 files changed, 203 insertions(+), 171 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 6e5f69a3a0c..e38ae12d014 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1042,9 +1042,10 @@ static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp, return 0; } -static int ahci_do_softreset(struct ata_port *ap, unsigned int *class, +static int ahci_do_softreset(struct ata_link *link, unsigned int *class, int pmp, unsigned long deadline) { + struct ata_port *ap = link->ap; const char *reason = NULL; unsigned long now, msecs; struct ata_taskfile tf; @@ -1052,7 +1053,7 @@ static int ahci_do_softreset(struct ata_port *ap, unsigned int *class, DPRINTK("ENTER\n"); - if (ata_link_offline(&ap->link)) { + if (ata_link_offline(link)) { DPRINTK("PHY reports no device\n"); *class = ATA_DEV_NONE; return 0; @@ -1061,10 +1062,10 @@ static int ahci_do_softreset(struct ata_port *ap, unsigned int *class, /* prepare for SRST (AHCI-1.1 10.4.1) */ rc = ahci_kick_engine(ap, 1); if (rc) - ata_port_printk(ap, KERN_WARNING, + ata_link_printk(link, KERN_WARNING, "failed to reset engine (errno=%d)", rc); - ata_tf_init(ap->link.device, &tf); + ata_tf_init(link->device, &tf); /* issue the first D2H Register FIS */ msecs = 0; @@ -1109,19 +1110,20 @@ static int ahci_do_softreset(struct ata_port *ap, unsigned int *class, return 0; fail: - ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason); + ata_link_printk(link, KERN_ERR, "softreset failed (%s)\n", reason); return rc; } -static int ahci_softreset(struct ata_port *ap, unsigned int *class, +static int ahci_softreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { - return ahci_do_softreset(ap, class, 0, deadline); + return ahci_do_softreset(link, class, 0, deadline); } -static int ahci_hardreset(struct ata_port *ap, unsigned int *class, +static int ahci_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { + struct ata_port *ap = link->ap; struct ahci_port_priv *pp = ap->private_data; u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; struct ata_taskfile tf; @@ -1132,15 +1134,15 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class, ahci_stop_engine(ap); /* clear D2H reception area to properly wait for D2H FIS */ - ata_tf_init(ap->link.device, &tf); + ata_tf_init(link->device, &tf); tf.command = 0x80; ata_tf_to_fis(&tf, 0, 0, d2h_fis); - rc = sata_std_hardreset(ap, class, deadline); + rc = sata_std_hardreset(link, class, deadline); ahci_start_engine(ap); - if (rc == 0 && ata_link_online(&ap->link)) + if (rc == 0 && ata_link_online(link)) *class = ahci_dev_classify(ap); if (*class == ATA_DEV_UNKNOWN) *class = ATA_DEV_NONE; @@ -1149,9 +1151,10 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class, return rc; } -static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class, +static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { + struct ata_port *ap = link->ap; u32 serror; int rc; @@ -1159,7 +1162,7 @@ static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class, ahci_stop_engine(ap); - rc = sata_port_hardreset(ap, sata_ehc_deb_timing(&ap->link.eh_context), + rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context), deadline); /* vt8251 needs SError cleared for the port to operate */ @@ -1176,12 +1179,13 @@ static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class, return rc ?: -EAGAIN; } -static void ahci_postreset(struct ata_port *ap, unsigned int *class) +static void ahci_postreset(struct ata_link *link, unsigned int *class) { + struct ata_port *ap = link->ap; void __iomem *port_mmio = ahci_port_base(ap); u32 new_tmp, tmp; - ata_std_postreset(ap, class); + ata_std_postreset(link, class); /* Make sure port's ATAPI bit is set appropriately */ new_tmp = tmp = readl(port_mmio + PORT_CMD); diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 92c2d5082be..03fe493026e 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -657,19 +657,20 @@ static int ich_pata_cable_detect(struct ata_port *ap) /** * piix_pata_prereset - prereset for PATA host controller - * @ap: Target port + * @link: Target link * @deadline: deadline jiffies for the operation * * LOCKING: * None (inherited from caller). */ -static int piix_pata_prereset(struct ata_port *ap, unsigned long deadline) +static int piix_pata_prereset(struct ata_link *link, unsigned long deadline) { + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } static void piix_pata_error_handler(struct ata_port *ap) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 6f99dee6b6d..73f66f4e1ee 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -3306,10 +3306,10 @@ int sata_link_resume(struct ata_link *link, const unsigned long *params, /** * ata_std_prereset - prepare for reset - * @ap: ATA port to be reset + * @link: ATA link to be reset * @deadline: deadline jiffies for the operation * - * @ap is about to be reset. Initialize it. Failure from + * @link is about to be reset. Initialize it. Failure from * prereset makes libata abort whole reset sequence and give up * that port, so prereset should be best-effort. It does its * best to prepare for reset sequence but if things go wrong, it @@ -3321,9 +3321,9 @@ int sata_link_resume(struct ata_link *link, const unsigned long *params, * RETURNS: * 0 on success, -errno otherwise. */ -int ata_std_prereset(struct ata_port *ap, unsigned long deadline) +int ata_std_prereset(struct ata_link *link, unsigned long deadline) { - struct ata_link *link = &ap->link; + struct ata_port *ap = link->ap; struct ata_eh_context *ehc = &link->eh_context; const unsigned long *timing = sata_ehc_deb_timing(ehc); int rc; @@ -3342,7 +3342,7 @@ int ata_std_prereset(struct ata_port *ap, unsigned long deadline) rc = sata_link_resume(link, timing, deadline); /* whine about phy resume failure but proceed */ if (rc && rc != -EOPNOTSUPP) - ata_port_printk(ap, KERN_WARNING, "failed to resume " + ata_link_printk(link, KERN_WARNING, "failed to resume " "link for reset (errno=%d)\n", rc); } @@ -3352,7 +3352,7 @@ int ata_std_prereset(struct ata_port *ap, unsigned long deadline) if (!(ap->flags & ATA_FLAG_SKIP_D2H_BSY) && !ata_link_offline(link)) { rc = ata_wait_ready(ap, deadline); if (rc && rc != -ENODEV) { - ata_port_printk(ap, KERN_WARNING, "device not ready " + ata_link_printk(link, KERN_WARNING, "device not ready " "(errno=%d), forcing hardreset\n", rc); ehc->i.action |= ATA_EH_HARDRESET; } @@ -3363,7 +3363,7 @@ int ata_std_prereset(struct ata_port *ap, unsigned long deadline) /** * ata_std_softreset - reset host port via ATA SRST - * @ap: port to reset + * @link: ATA link to reset * @classes: resulting classes of attached devices * @deadline: deadline jiffies for the operation * @@ -3375,10 +3375,10 @@ int ata_std_prereset(struct ata_port *ap, unsigned long deadline) * RETURNS: * 0 on success, -errno otherwise. */ -int ata_std_softreset(struct ata_port *ap, unsigned int *classes, +int ata_std_softreset(struct ata_link *link, unsigned int *classes, unsigned long deadline) { - struct ata_link *link = &ap->link; + struct ata_port *ap = link->ap; unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS; unsigned int devmask = 0; int rc; @@ -3405,7 +3405,7 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes, rc = ata_bus_softreset(ap, devmask, deadline); /* if link is occupied, -ENODEV too is an error */ if (rc && (rc != -ENODEV || sata_scr_valid(link))) { - ata_port_printk(ap, KERN_ERR, "SRST failed (errno=%d)\n", rc); + ata_link_printk(link, KERN_ERR, "SRST failed (errno=%d)\n", rc); return rc; } @@ -3420,12 +3420,12 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes, } /** - * sata_port_hardreset - reset port via SATA phy reset - * @ap: port to reset + * sata_link_hardreset - reset link via SATA phy reset + * @link: link to reset * @timing: timing parameters { interval, duratinon, timeout } in msec * @deadline: deadline jiffies for the operation * - * SATA phy-reset host port using DET bits of SControl register. + * SATA phy-reset @link using DET bits of SControl register. * * LOCKING: * Kernel thread context (may sleep) @@ -3433,10 +3433,9 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes, * RETURNS: * 0 on success, -errno otherwise. */ -int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing, +int sata_link_hardreset(struct ata_link *link, const unsigned long *timing, unsigned long deadline) { - struct ata_link *link = &ap->link; u32 scontrol; int rc; @@ -3482,7 +3481,7 @@ int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing, /** * sata_std_hardreset - reset host port via SATA phy reset - * @ap: port to reset + * @link: link to reset * @class: resulting class of attached device * @deadline: deadline jiffies for the operation * @@ -3495,19 +3494,19 @@ int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing, * RETURNS: * 0 on success, -errno otherwise. */ -int sata_std_hardreset(struct ata_port *ap, unsigned int *class, +int sata_std_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { - struct ata_link *link = &ap->link; + struct ata_port *ap = link->ap; const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); int rc; DPRINTK("ENTER\n"); /* do hardreset */ - rc = sata_port_hardreset(ap, timing, deadline); + rc = sata_link_hardreset(link, timing, deadline); if (rc) { - ata_port_printk(ap, KERN_ERR, + ata_link_printk(link, KERN_ERR, "COMRESET failed (errno=%d)\n", rc); return rc; } @@ -3525,7 +3524,7 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class, rc = ata_wait_ready(ap, deadline); /* link occupied, -ENODEV too is an error */ if (rc) { - ata_port_printk(ap, KERN_ERR, + ata_link_printk(link, KERN_ERR, "COMRESET failed (errno=%d)\n", rc); return rc; } @@ -3540,7 +3539,7 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class, /** * ata_std_postreset - standard postreset callback - * @ap: the target ata_port + * @link: the target ata_link * @classes: classes of attached devices * * This function is invoked after a successful reset. Note that @@ -3550,9 +3549,9 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class, * LOCKING: * Kernel thread context (may sleep) */ -void ata_std_postreset(struct ata_port *ap, unsigned int *classes) +void ata_std_postreset(struct ata_link *link, unsigned int *classes) { - struct ata_link *link = &ap->link; + struct ata_port *ap = link->ap; u32 serror; DPRINTK("ENTER\n"); @@ -6946,7 +6945,7 @@ EXPORT_SYMBOL_GPL(__sata_phy_reset); EXPORT_SYMBOL_GPL(ata_bus_reset); EXPORT_SYMBOL_GPL(ata_std_prereset); EXPORT_SYMBOL_GPL(ata_std_softreset); -EXPORT_SYMBOL_GPL(sata_port_hardreset); +EXPORT_SYMBOL_GPL(sata_link_hardreset); EXPORT_SYMBOL_GPL(sata_std_hardreset); EXPORT_SYMBOL_GPL(ata_std_postreset); EXPORT_SYMBOL_GPL(ata_dev_classify); diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index fc4b6413b19..0a9ce34a0e6 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1737,16 +1737,16 @@ static void ata_eh_report(struct ata_port *ap) } } -static int ata_do_reset(struct ata_port *ap, ata_reset_fn_t reset, +static int ata_do_reset(struct ata_link *link, ata_reset_fn_t reset, unsigned int *classes, unsigned long deadline) { struct ata_device *dev; int rc; - ata_link_for_each_dev(dev, &ap->link) + ata_link_for_each_dev(dev, link) classes[dev->devno] = ATA_DEV_UNKNOWN; - rc = reset(ap, classes, deadline); + rc = reset(link, classes, deadline); if (rc) return rc; @@ -1754,12 +1754,12 @@ static int ata_do_reset(struct ata_port *ap, ata_reset_fn_t reset, * is complete and convert all ATA_DEV_UNKNOWN to * ATA_DEV_NONE. */ - ata_link_for_each_dev(dev, &ap->link) + ata_link_for_each_dev(dev, link) if (classes[dev->devno] != ATA_DEV_UNKNOWN) break; if (dev) { - ata_link_for_each_dev(dev, &ap->link) { + ata_link_for_each_dev(dev, link) { if (classes[dev->devno] == ATA_DEV_UNKNOWN) classes[dev->devno] = ATA_DEV_NONE; } @@ -1780,11 +1780,10 @@ static int ata_eh_followup_srst_needed(int rc, int classify, return 0; } -static int ata_eh_reset(struct ata_port *ap, int classify, +static int ata_eh_reset(struct ata_link *link, int classify, ata_prereset_fn_t prereset, ata_reset_fn_t softreset, ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) { - struct ata_link *link = &ap->link; struct ata_eh_context *ehc = &link->eh_context; unsigned int *classes = ehc->classes; int verbose = !(ehc->i.flags & ATA_EHI_QUIET); @@ -1810,10 +1809,10 @@ static int ata_eh_reset(struct ata_port *ap, int classify, ehc->i.action |= ATA_EH_HARDRESET; if (prereset) { - rc = prereset(ap, jiffies + ATA_EH_PRERESET_TIMEOUT); + rc = prereset(link, jiffies + ATA_EH_PRERESET_TIMEOUT); if (rc) { if (rc == -ENOENT) { - ata_port_printk(ap, KERN_DEBUG, + ata_link_printk(link, KERN_DEBUG, "port disabled. ignoring.\n"); ehc->i.action &= ~ATA_EH_RESET_MASK; @@ -1822,7 +1821,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, rc = 0; } else - ata_port_printk(ap, KERN_ERR, + ata_link_printk(link, KERN_ERR, "prereset failed (errno=%d)\n", rc); goto out; } @@ -1854,7 +1853,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, /* shut up during boot probing */ if (verbose) - ata_port_printk(ap, KERN_INFO, "%s resetting port\n", + ata_link_printk(link, KERN_INFO, "%s resetting link\n", reset == softreset ? "soft" : "hard"); /* mark that this EH session started with reset */ @@ -1863,7 +1862,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, else ehc->i.flags |= ATA_EHI_DID_SOFTRESET; - rc = ata_do_reset(ap, reset, classes, deadline); + rc = ata_do_reset(link, reset, classes, deadline); if (reset == hardreset && ata_eh_followup_srst_needed(rc, classify, classes)) { @@ -1871,7 +1870,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, reset = softreset; if (!reset) { - ata_port_printk(ap, KERN_ERR, + ata_link_printk(link, KERN_ERR, "follow-up softreset required " "but no softreset avaliable\n"); rc = -EINVAL; @@ -1879,11 +1878,11 @@ static int ata_eh_reset(struct ata_port *ap, int classify, } ata_eh_about_to_do(link, NULL, ATA_EH_RESET_MASK); - rc = ata_do_reset(ap, reset, classes, deadline); + rc = ata_do_reset(link, reset, classes, deadline); if (rc == 0 && classify && classes[0] == ATA_DEV_UNKNOWN) { - ata_port_printk(ap, KERN_ERR, + ata_link_printk(link, KERN_ERR, "classification failed\n"); rc = -EINVAL; goto out; @@ -1896,7 +1895,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, if (time_before(now, deadline)) { unsigned long delta = deadline - jiffies; - ata_port_printk(ap, KERN_WARNING, "reset failed " + ata_link_printk(link, KERN_WARNING, "reset failed " "(errno=%d), retrying in %u secs\n", rc, (jiffies_to_msecs(delta) + 999) / 1000); @@ -1925,7 +1924,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, link->sata_spd = (sstatus >> 4) & 0xf; if (postreset) - postreset(ap, classes); + postreset(link, classes); /* reset successful, schedule revalidation */ ata_eh_done(link, NULL, ehc->i.action & ATA_EH_RESET_MASK); @@ -2202,7 +2201,7 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, if (ehc->i.action & ATA_EH_RESET_MASK) { ata_eh_freeze_port(ap); - rc = ata_eh_reset(ap, ata_port_nr_vacant(ap), prereset, + rc = ata_eh_reset(&ap->link, ata_port_nr_vacant(ap), prereset, softreset, hardreset, postreset); if (rc) { ata_port_printk(ap, KERN_ERR, diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c index 04048fcf630..d0cebe16a8e 100644 --- a/drivers/ata/pata_amd.c +++ b/drivers/ata/pata_amd.c @@ -119,27 +119,28 @@ static void timing_setup(struct ata_port *ap, struct ata_device *adev, int offse } /** - * amd_probe_init - perform reset handling - * @ap: ATA port + * amd_pre_reset - perform reset handling + * @link: ATA link * @deadline: deadline jiffies for the operation * * Reset sequence checking enable bits to see which ports are * active. */ -static int amd_pre_reset(struct ata_port *ap, unsigned long deadline) +static int amd_pre_reset(struct ata_link *link, unsigned long deadline) { static const struct pci_bits amd_enable_bits[] = { { 0x40, 1, 0x02, 0x02 }, { 0x40, 1, 0x01, 0x01 } }; + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); if (!pci_test_config_bits(pdev, &amd_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } static void amd_error_handler(struct ata_port *ap) @@ -221,25 +222,26 @@ static void amd133_set_dmamode(struct ata_port *ap, struct ata_device *adev) /** * nv_probe_init - cable detection - * @ap: ATA port + * @lin: ATA link * * Perform cable detection. The BIOS stores this in PCI config * space for us. */ -static int nv_pre_reset(struct ata_port *ap, unsigned long deadline) +static int nv_pre_reset(struct ata_link *link, unsigned long deadline) { static const struct pci_bits nv_enable_bits[] = { { 0x50, 1, 0x02, 0x02 }, { 0x50, 1, 0x01, 0x01 } }; + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); if (!pci_test_config_bits(pdev, &nv_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } static void nv_error_handler(struct ata_port *ap) diff --git a/drivers/ata/pata_artop.c b/drivers/ata/pata_artop.c index b5352ebecef..361f2fca7e5 100644 --- a/drivers/ata/pata_artop.c +++ b/drivers/ata/pata_artop.c @@ -40,8 +40,9 @@ static int clock = 0; -static int artop6210_pre_reset(struct ata_port *ap, unsigned long deadline) +static int artop6210_pre_reset(struct ata_link *link, unsigned long deadline) { + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); const struct pci_bits artop_enable_bits[] = { { 0x4AU, 1U, 0x02UL, 0x02UL }, /* port 0 */ @@ -51,7 +52,7 @@ static int artop6210_pre_reset(struct ata_port *ap, unsigned long deadline) if (!pci_test_config_bits(pdev, &artop_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } /** @@ -71,27 +72,28 @@ static void artop6210_error_handler(struct ata_port *ap) /** * artop6260_pre_reset - check for 40/80 pin - * @ap: Port + * @link: link * @deadline: deadline jiffies for the operation * * The ARTOP hardware reports the cable detect bits in register 0x49. * Nothing complicated needed here. */ -static int artop6260_pre_reset(struct ata_port *ap, unsigned long deadline) +static int artop6260_pre_reset(struct ata_link *link, unsigned long deadline) { static const struct pci_bits artop_enable_bits[] = { { 0x4AU, 1U, 0x02UL, 0x02UL }, /* port 0 */ { 0x4AU, 1U, 0x04UL, 0x04UL }, /* port 1 */ }; + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); /* Odd numbered device ids are the units with enable bits (the -R cards) */ if (pdev->device % 1 && !pci_test_config_bits(pdev, &artop_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } /** diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c index 86f85a2cab7..656f4d0a572 100644 --- a/drivers/ata/pata_atiixp.c +++ b/drivers/ata/pata_atiixp.c @@ -33,8 +33,9 @@ enum { ATIIXP_IDE_UDMA_MODE = 0x56 }; -static int atiixp_pre_reset(struct ata_port *ap, unsigned long deadline) +static int atiixp_pre_reset(struct ata_link *link, unsigned long deadline) { + struct ata_port *ap = link->ap; static const struct pci_bits atiixp_enable_bits[] = { { 0x48, 1, 0x01, 0x00 }, { 0x48, 1, 0x08, 0x00 } @@ -44,7 +45,7 @@ static int atiixp_pre_reset(struct ata_port *ap, unsigned long deadline) if (!pci_test_config_bits(pdev, &atiixp_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } static void atiixp_error_handler(struct ata_port *ap) diff --git a/drivers/ata/pata_efar.c b/drivers/ata/pata_efar.c index c8ba59c5611..9f6fae6e38b 100644 --- a/drivers/ata/pata_efar.c +++ b/drivers/ata/pata_efar.c @@ -26,25 +26,26 @@ /** * efar_pre_reset - Enable bits - * @ap: Port + * @link: ATA link * @deadline: deadline jiffies for the operation * * Perform cable detection for the EFAR ATA interface. This is * different to the PIIX arrangement */ -static int efar_pre_reset(struct ata_port *ap, unsigned long deadline) +static int efar_pre_reset(struct ata_link *link, unsigned long deadline) { static const struct pci_bits efar_enable_bits[] = { { 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */ { 0x43U, 1U, 0x80UL, 0x80UL }, /* port 1 */ }; + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); if (!pci_test_config_bits(pdev, &efar_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } /** diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c index c5ddd937dbf..1a4d0ad68d1 100644 --- a/drivers/ata/pata_hpt37x.c +++ b/drivers/ata/pata_hpt37x.c @@ -304,15 +304,16 @@ static unsigned long hpt370a_filter(struct ata_device *adev, unsigned long mask) /** * hpt37x_pre_reset - reset the hpt37x bus - * @ap: ATA port to reset + * @link: ATA link to reset * @deadline: deadline jiffies for the operation * * Perform the initial reset handling for the 370/372 and 374 func 0 */ -static int hpt37x_pre_reset(struct ata_port *ap, unsigned long deadline) +static int hpt37x_pre_reset(struct ata_link *link, unsigned long deadline) { u8 scr2, ata66; + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); static const struct pci_bits hpt37x_enable_bits[] = { { 0x50, 1, 0x04, 0x04 }, @@ -337,7 +338,7 @@ static int hpt37x_pre_reset(struct ata_port *ap, unsigned long deadline) pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37); udelay(100); - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } /** @@ -352,7 +353,7 @@ static void hpt37x_error_handler(struct ata_port *ap) ata_bmdma_drive_eh(ap, hpt37x_pre_reset, ata_std_softreset, NULL, ata_std_postreset); } -static int hpt374_pre_reset(struct ata_port *ap, unsigned long deadline) +static int hpt374_pre_reset(struct ata_link *link, unsigned long deadline) { static const struct pci_bits hpt37x_enable_bits[] = { { 0x50, 1, 0x04, 0x04 }, @@ -360,6 +361,7 @@ static int hpt374_pre_reset(struct ata_port *ap, unsigned long deadline) }; u16 mcr3, mcr6; u8 ata66; + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); if (!pci_test_config_bits(pdev, &hpt37x_enable_bits[ap->port_no])) @@ -387,7 +389,7 @@ static int hpt374_pre_reset(struct ata_port *ap, unsigned long deadline) pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37); udelay(100); - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } /** diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c index f8f234bfc8c..739a89180eb 100644 --- a/drivers/ata/pata_hpt3x2n.c +++ b/drivers/ata/pata_hpt3x2n.c @@ -141,21 +141,22 @@ static int hpt3x2n_cable_detect(struct ata_port *ap) /** * hpt3x2n_pre_reset - reset the hpt3x2n bus - * @ap: ATA port to reset + * @link: ATA link to reset * @deadline: deadline jiffies for the operation * * Perform the initial reset handling for the 3x2n series controllers. * Reset the hardware and state machine, */ -static int hpt3xn_pre_reset(struct ata_port *ap, unsigned long deadline) +static int hpt3xn_pre_reset(struct ata_link *link, unsigned long deadline) { + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); /* Reset the state machine */ pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37); udelay(100); - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } /** diff --git a/drivers/ata/pata_it8213.c b/drivers/ata/pata_it8213.c index b8af55e8915..1daf1e19bdf 100644 --- a/drivers/ata/pata_it8213.c +++ b/drivers/ata/pata_it8213.c @@ -23,23 +23,24 @@ /** * it8213_pre_reset - check for 40/80 pin - * @ap: Port + * @link: link * @deadline: deadline jiffies for the operation * * Filter out ports by the enable bits before doing the normal reset * and probe. */ -static int it8213_pre_reset(struct ata_port *ap, unsigned long deadline) +static int it8213_pre_reset(struct ata_link *link, unsigned long deadline) { static const struct pci_bits it8213_enable_bits[] = { { 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */ }; + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); if (!pci_test_config_bits(pdev, &it8213_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } /** diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c index 4d67f238eee..1619b86b74a 100644 --- a/drivers/ata/pata_jmicron.c +++ b/drivers/ata/pata_jmicron.c @@ -29,7 +29,7 @@ typedef enum { /** * jmicron_pre_reset - check for 40/80 pin - * @ap: Port + * @link: ATA link * @deadline: deadline jiffies for the operation * * Perform the PATA port setup we need. @@ -39,9 +39,9 @@ typedef enum { * and setup here. We assume that has been done by init_one and the * BIOS. */ - -static int jmicron_pre_reset(struct ata_port *ap, unsigned long deadline) +static int jmicron_pre_reset(struct ata_link *link, unsigned long deadline) { + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); u32 control; u32 control5; @@ -103,7 +103,7 @@ static int jmicron_pre_reset(struct ata_port *ap, unsigned long deadline) ap->cbl = ATA_CBL_SATA; break; } - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } /** diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c index b45506f1ef7..b4dd18f3fa5 100644 --- a/drivers/ata/pata_marvell.c +++ b/drivers/ata/pata_marvell.c @@ -24,14 +24,15 @@ /** * marvell_pre_reset - check for 40/80 pin - * @ap: Port + * @link: link * @deadline: deadline jiffies for the operation * * Perform the PATA port setup we need. */ -static int marvell_pre_reset(struct ata_port *ap, unsigned long deadline) +static int marvell_pre_reset(struct ata_link *link, unsigned long deadline) { + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); u32 devices; void __iomem *barp; @@ -54,7 +55,7 @@ static int marvell_pre_reset(struct ata_port *ap, unsigned long deadline) (!(devices & 0x10))) /* PATA enable ? */ return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } static int marvell_cable_detect(struct ata_port *ap) diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c index 4ea42838297..36c964b9e7d 100644 --- a/drivers/ata/pata_mpiix.c +++ b/drivers/ata/pata_mpiix.c @@ -46,15 +46,16 @@ enum { SECONDARY = (1 << 14) }; -static int mpiix_pre_reset(struct ata_port *ap, unsigned long deadline) +static int mpiix_pre_reset(struct ata_link *link, unsigned long deadline) { + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); static const struct pci_bits mpiix_enable_bits = { 0x6D, 1, 0x80, 0x80 }; if (!pci_test_config_bits(pdev, &mpiix_enable_bits)) return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } /** diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c index 2f5d714ebfc..65a21772771 100644 --- a/drivers/ata/pata_ns87410.c +++ b/drivers/ata/pata_ns87410.c @@ -32,14 +32,15 @@ /** * ns87410_pre_reset - probe begin - * @ap: ATA port + * @link: ATA link * @deadline: deadline jiffies for the operation * * Check enabled ports */ -static int ns87410_pre_reset(struct ata_port *ap, unsigned long deadline) +static int ns87410_pre_reset(struct ata_link *link, unsigned long deadline) { + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); static const struct pci_bits ns87410_enable_bits[] = { { 0x43, 1, 0x08, 0x08 }, @@ -49,7 +50,7 @@ static int ns87410_pre_reset(struct ata_port *ap, unsigned long deadline) if (!pci_test_config_bits(pdev, &ns87410_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } /** diff --git a/drivers/ata/pata_oldpiix.c b/drivers/ata/pata_oldpiix.c index 091a70a0ef1..5b2c86fe9fc 100644 --- a/drivers/ata/pata_oldpiix.c +++ b/drivers/ata/pata_oldpiix.c @@ -29,14 +29,15 @@ /** * oldpiix_pre_reset - probe begin - * @ap: ATA port + * @link: ATA link * @deadline: deadline jiffies for the operation * * Set up cable type and use generic probe init */ -static int oldpiix_pre_reset(struct ata_port *ap, unsigned long deadline) +static int oldpiix_pre_reset(struct ata_link *link, unsigned long deadline) { + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); static const struct pci_bits oldpiix_enable_bits[] = { { 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */ @@ -46,7 +47,7 @@ static int oldpiix_pre_reset(struct ata_port *ap, unsigned long deadline) if (!pci_test_config_bits(pdev, &oldpiix_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } /** diff --git a/drivers/ata/pata_opti.c b/drivers/ata/pata_opti.c index 458bf67f766..5770c7755a6 100644 --- a/drivers/ata/pata_opti.c +++ b/drivers/ata/pata_opti.c @@ -46,14 +46,15 @@ enum { /** * opti_pre_reset - probe begin - * @ap: ATA port + * @link: ATA link * @deadline: deadline jiffies for the operation * * Set up cable type and use generic probe init */ -static int opti_pre_reset(struct ata_port *ap, unsigned long deadline) +static int opti_pre_reset(struct ata_link *link, unsigned long deadline) { + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); static const struct pci_bits opti_enable_bits[] = { { 0x45, 1, 0x80, 0x00 }, @@ -63,7 +64,7 @@ static int opti_pre_reset(struct ata_port *ap, unsigned long deadline) if (!pci_test_config_bits(pdev, &opti_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } /** diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c index f8234d7fd82..39fcba80007 100644 --- a/drivers/ata/pata_optidma.c +++ b/drivers/ata/pata_optidma.c @@ -47,14 +47,15 @@ static int pci_clock; /* 0 = 33 1 = 25 */ /** * optidma_pre_reset - probe begin - * @ap: ATA port + * @link: ATA link * @deadline: deadline jiffies for the operation * * Set up cable type and use generic probe init */ -static int optidma_pre_reset(struct ata_port *ap, unsigned long deadline) +static int optidma_pre_reset(struct ata_link *link, unsigned long deadline) { + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); static const struct pci_bits optidma_enable_bits = { 0x40, 1, 0x08, 0x00 @@ -63,7 +64,7 @@ static int optidma_pre_reset(struct ata_port *ap, unsigned long deadline) if (ap->port_no && !pci_test_config_bits(pdev, &optidma_enable_bits)) return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } /** diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c index 83c90cabc7f..ba39efbe540 100644 --- a/drivers/ata/pata_pdc2027x.c +++ b/drivers/ata/pata_pdc2027x.c @@ -300,7 +300,7 @@ static inline int pdc2027x_port_enabled(struct ata_port *ap) /** * pdc2027x_prereset - prereset for PATA host controller - * @ap: Target port + * @link: Target link * @deadline: deadline jiffies for the operation * * Probeinit including cable detection. @@ -309,12 +309,12 @@ static inline int pdc2027x_port_enabled(struct ata_port *ap) * None (inherited from caller). */ -static int pdc2027x_prereset(struct ata_port *ap, unsigned long deadline) +static int pdc2027x_prereset(struct ata_link *link, unsigned long deadline) { /* Check whether port enabled */ - if (!pdc2027x_port_enabled(ap)) + if (!pdc2027x_port_enabled(link->ap)) return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } /** diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c index 40395804a66..45515a22d85 100644 --- a/drivers/ata/pata_sil680.c +++ b/drivers/ata/pata_sil680.c @@ -95,15 +95,16 @@ static int sil680_cable_detect(struct ata_port *ap) { /** * sil680_bus_reset - reset the SIL680 bus - * @ap: ATA port to reset + * @link: ATA link to reset * @deadline: deadline jiffies for the operation * * Perform the SIL680 housekeeping when doing an ATA bus reset */ -static int sil680_bus_reset(struct ata_port *ap,unsigned int *classes, +static int sil680_bus_reset(struct ata_link *link, unsigned int *classes, unsigned long deadline) { + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); unsigned long addr = sil680_selreg(ap, 0); u8 reset; @@ -112,7 +113,7 @@ static int sil680_bus_reset(struct ata_port *ap,unsigned int *classes, pci_write_config_byte(pdev, addr, reset | 0x03); udelay(25); pci_write_config_byte(pdev, addr, reset); - return ata_std_softreset(ap, classes, deadline); + return ata_std_softreset(link, classes, deadline); } static void sil680_error_handler(struct ata_port *ap) diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c index 9d6f81d52e1..b72227676f0 100644 --- a/drivers/ata/pata_sis.c +++ b/drivers/ata/pata_sis.c @@ -133,19 +133,20 @@ static int sis_66_cable_detect(struct ata_port *ap) /** * sis_pre_reset - probe begin - * @ap: ATA port + * @link: ATA link * @deadline: deadline jiffies for the operation * * Set up cable type and use generic probe init */ -static int sis_pre_reset(struct ata_port *ap, unsigned long deadline) +static int sis_pre_reset(struct ata_link *link, unsigned long deadline) { static const struct pci_bits sis_enable_bits[] = { { 0x4aU, 1U, 0x02UL, 0x02UL }, /* port 0 */ { 0x4aU, 1U, 0x04UL, 0x04UL }, /* port 1 */ }; + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); if (!pci_test_config_bits(pdev, &sis_enable_bits[ap->port_no])) @@ -154,7 +155,7 @@ static int sis_pre_reset(struct ata_port *ap, unsigned long deadline) /* Clear the FIFO settings. We can't enable the FIFO until we know we are poking at a disk */ pci_write_config_byte(pdev, 0x4B, 0); - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c index c0f43bb2595..375c3705dc4 100644 --- a/drivers/ata/pata_sl82c105.c +++ b/drivers/ata/pata_sl82c105.c @@ -43,23 +43,24 @@ enum { /** * sl82c105_pre_reset - probe begin - * @ap: ATA port + * @link: ATA link * @deadline: deadline jiffies for the operation * * Set up cable type and use generic probe init */ -static int sl82c105_pre_reset(struct ata_port *ap, unsigned long deadline) +static int sl82c105_pre_reset(struct ata_link *link, unsigned long deadline) { static const struct pci_bits sl82c105_enable_bits[] = { { 0x40, 1, 0x01, 0x01 }, { 0x40, 1, 0x10, 0x10 } }; + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); if (ap->port_no && !pci_test_config_bits(pdev, &sl82c105_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c index af21f443db6..bc4b6f6be96 100644 --- a/drivers/ata/pata_triflex.c +++ b/drivers/ata/pata_triflex.c @@ -47,25 +47,26 @@ /** * triflex_prereset - probe begin - * @ap: ATA port + * @link: ATA link * @deadline: deadline jiffies for the operation * * Set up cable type and use generic probe init */ -static int triflex_prereset(struct ata_port *ap, unsigned long deadline) +static int triflex_prereset(struct ata_link *link, unsigned long deadline) { static const struct pci_bits triflex_enable_bits[] = { { 0x80, 1, 0x01, 0x01 }, { 0x80, 1, 0x02, 0x02 } }; + struct ata_port *ap = link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); if (!pci_test_config_bits(pdev, &triflex_enable_bits[ap->port_no])) return -ENOENT; - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index f143db4559e..b612808a319 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -187,8 +187,9 @@ static int via_cable_detect(struct ata_port *ap) { return ATA_CBL_PATA40; } -static int via_pre_reset(struct ata_port *ap, unsigned long deadline) +static int via_pre_reset(struct ata_link *link, unsigned long deadline) { + struct ata_port *ap = link->ap; const struct via_isa_bridge *config = ap->host->private_data; if (!(config->flags & VIA_NO_ENABLES)) { @@ -201,7 +202,7 @@ static int via_pre_reset(struct ata_port *ap, unsigned long deadline) return -ENOENT; } - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c index f2b1bea934b..95caba0f910 100644 --- a/drivers/ata/sata_inic162x.c +++ b/drivers/ata/sata_inic162x.c @@ -417,12 +417,13 @@ static void inic_thaw(struct ata_port *ap) * SRST and SControl hardreset don't give valid signature on this * controller. Only controller specific hardreset mechanism works. */ -static int inic_hardreset(struct ata_port *ap, unsigned int *class, +static int inic_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { + struct ata_port *ap = link->ap; void __iomem *port_base = inic_port_base(ap); void __iomem *idma_ctl = port_base + PORT_IDMA_CTL; - const unsigned long *timing = sata_ehc_deb_timing(&ap->link.eh_context); + const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); u16 val; int rc; @@ -435,15 +436,15 @@ static int inic_hardreset(struct ata_port *ap, unsigned int *class, msleep(1); writew(val & ~IDMA_CTL_RST_ATA, idma_ctl); - rc = sata_link_resume(&ap->link, timing, deadline); + rc = sata_link_resume(link, timing, deadline); if (rc) { - ata_port_printk(ap, KERN_WARNING, "failed to resume " + ata_link_printk(link, KERN_WARNING, "failed to resume " "link after reset (errno=%d)\n", rc); return rc; } *class = ATA_DEV_NONE; - if (ata_link_online(&ap->link)) { + if (ata_link_online(link)) { struct ata_taskfile tf; /* wait a while before checking status */ @@ -452,7 +453,7 @@ static int inic_hardreset(struct ata_port *ap, unsigned int *class, rc = ata_wait_ready(ap, deadline); /* link occupied, -ENODEV too is an error */ if (rc) { - ata_port_printk(ap, KERN_WARNING, "device not ready " + ata_link_printk(link, KERN_WARNING, "device not ready " "after hardreset (errno=%d)\n", rc); return rc; } diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 8e63c60adaf..56784ce1054 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -2266,10 +2266,11 @@ comreset_retry: VPRINTK("EXIT\n"); } -static int mv_prereset(struct ata_port *ap, unsigned long deadline) +static int mv_prereset(struct ata_link *link, unsigned long deadline) { + struct ata_port *ap = link->ap; struct mv_port_priv *pp = ap->private_data; - struct ata_eh_context *ehc = &ap->link.eh_context; + struct ata_eh_context *ehc = &link->eh_context; int rc; rc = mv_stop_dma(ap); @@ -2285,7 +2286,7 @@ static int mv_prereset(struct ata_port *ap, unsigned long deadline) if (ehc->i.action & ATA_EH_HARDRESET) return 0; - if (ata_link_online(&ap->link)) + if (ata_link_online(link)) rc = ata_wait_ready(ap, deadline); else rc = -ENODEV; @@ -2293,9 +2294,10 @@ static int mv_prereset(struct ata_port *ap, unsigned long deadline) return rc; } -static int mv_hardreset(struct ata_port *ap, unsigned int *class, +static int mv_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { + struct ata_port *ap = link->ap; struct mv_host_priv *hpriv = ap->host->private_data; void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR]; @@ -2308,16 +2310,17 @@ static int mv_hardreset(struct ata_port *ap, unsigned int *class, return 0; } -static void mv_postreset(struct ata_port *ap, unsigned int *classes) +static void mv_postreset(struct ata_link *link, unsigned int *classes) { + struct ata_port *ap = link->ap; u32 serr; /* print link status */ - sata_print_link_status(&ap->link); + sata_print_link_status(link); /* clear SError */ - sata_scr_read(&ap->link, SCR_ERROR, &serr); - sata_scr_write_flush(&ap->link, SCR_ERROR, serr); + sata_scr_read(link, SCR_ERROR, &serr); + sata_scr_write_flush(link, SCR_ERROR, serr); /* bail out if no device is present */ if (classes[0] == ATA_DEV_NONE && classes[1] == ATA_DEV_NONE) { diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index df4d50dcffb..67ba0f75f1e 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -1459,7 +1459,7 @@ static void nv_ck804_thaw(struct ata_port *ap) writeb(mask, mmio_base + NV_INT_ENABLE_CK804); } -static int nv_hardreset(struct ata_port *ap, unsigned int *class, +static int nv_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { unsigned int dummy; @@ -1468,7 +1468,7 @@ static int nv_hardreset(struct ata_port *ap, unsigned int *class, * some controllers. Don't classify on hardreset. For more * info, see http://bugme.osdl.org/show_bug.cgi?id=3352 */ - return sata_std_hardreset(ap, &dummy, deadline); + return sata_std_hardreset(link, &dummy, deadline); } static void nv_error_handler(struct ata_port *ap) diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index 0cd40d5215f..869e414d7ed 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -583,9 +583,10 @@ static int sil24_exec_polled_cmd(struct ata_port *ap, int pmp, return rc; } -static int sil24_do_softreset(struct ata_port *ap, unsigned int *class, +static int sil24_do_softreset(struct ata_link *link, unsigned int *class, int pmp, unsigned long deadline) { + struct ata_port *ap = link->ap; unsigned long timeout_msec = 0; struct ata_taskfile tf; const char *reason; @@ -593,7 +594,7 @@ static int sil24_do_softreset(struct ata_port *ap, unsigned int *class, DPRINTK("ENTER\n"); - if (ata_link_offline(&ap->link)) { + if (ata_link_offline(link)) { DPRINTK("PHY reports no device\n"); *class = ATA_DEV_NONE; goto out; @@ -609,7 +610,7 @@ static int sil24_do_softreset(struct ata_port *ap, unsigned int *class, if (time_after(deadline, jiffies)) timeout_msec = jiffies_to_msecs(deadline - jiffies); - ata_tf_init(ap->link.device, &tf); /* doesn't really matter */ + ata_tf_init(link->device, &tf); /* doesn't really matter */ rc = sil24_exec_polled_cmd(ap, pmp, &tf, 0, PRB_CTRL_SRST, timeout_msec); if (rc == -EBUSY) { @@ -631,29 +632,30 @@ static int sil24_do_softreset(struct ata_port *ap, unsigned int *class, return 0; err: - ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason); + ata_link_printk(link, KERN_ERR, "softreset failed (%s)\n", reason); return -EIO; } -static int sil24_softreset(struct ata_port *ap, unsigned int *class, +static int sil24_softreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { - return sil24_do_softreset(ap, class, 0, deadline); + return sil24_do_softreset(link, class, 0, deadline); } -static int sil24_hardreset(struct ata_port *ap, unsigned int *class, +static int sil24_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { + struct ata_port *ap = link->ap; void __iomem *port = ap->ioaddr.cmd_addr; const char *reason; int tout_msec, rc; u32 tmp; /* sil24 does the right thing(tm) without any protection */ - sata_set_spd(&ap->link); + sata_set_spd(link); tout_msec = 100; - if (ata_link_online(&ap->link)) + if (ata_link_online(link)) tout_msec = 5000; writel(PORT_CS_DEV_RST, port + PORT_CTRL_STAT); @@ -663,14 +665,14 @@ static int sil24_hardreset(struct ata_port *ap, unsigned int *class, /* SStatus oscillates between zero and valid status after * DEV_RST, debounce it. */ - rc = sata_link_debounce(&ap->link, sata_deb_timing_long, deadline); + rc = sata_link_debounce(link, sata_deb_timing_long, deadline); if (rc) { reason = "PHY debouncing failed"; goto err; } if (tmp & PORT_CS_DEV_RST) { - if (ata_link_offline(&ap->link)) + if (ata_link_offline(link)) return 0; reason = "link not ready"; goto err; @@ -685,7 +687,7 @@ static int sil24_hardreset(struct ata_port *ap, unsigned int *class, return -EAGAIN; err: - ata_port_printk(ap, KERN_ERR, "hardreset failed (%s)\n", reason); + ata_link_printk(link, KERN_ERR, "hardreset failed (%s)\n", reason); return -EIO; } diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index 78a6833af71..690280660b8 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c @@ -276,7 +276,7 @@ static void svia_noop_freeze(struct ata_port *ap) /** * vt6420_prereset - prereset for vt6420 - * @ap: target ATA port + * @link: target ATA link * @deadline: deadline jiffies for the operation * * SCR registers on vt6420 are pieces of shit and may hang the @@ -294,8 +294,9 @@ static void svia_noop_freeze(struct ata_port *ap) * RETURNS: * 0 on success, -errno otherwise. */ -static int vt6420_prereset(struct ata_port *ap, unsigned long deadline) +static int vt6420_prereset(struct ata_link *link, unsigned long deadline) { + struct ata_port *ap = link->ap; struct ata_eh_context *ehc = &ap->link.eh_context; unsigned long timeout = jiffies + (HZ * 5); u32 sstatus, scontrol; diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index affd77aafb2..9350fbf39f7 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -3829,18 +3829,18 @@ static int ipr_device_reset(struct ipr_ioa_cfg *ioa_cfg, /** * ipr_sata_reset - Reset the SATA port - * @ap: SATA port to reset + * @link: SATA link to reset * @classes: class of the attached device * - * This function issues a SATA phy reset to the affected ATA port. + * This function issues a SATA phy reset to the affected ATA link. * * Return value: * 0 on success / non-zero on failure **/ -static int ipr_sata_reset(struct ata_port *ap, unsigned int *classes, +static int ipr_sata_reset(struct ata_link *link, unsigned int *classes, unsigned long deadline) { - struct ipr_sata_port *sata_port = ap->private_data; + struct ipr_sata_port *sata_port = link->ap->private_data; struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg; struct ipr_resource_entry *res; unsigned long lock_flags = 0; diff --git a/include/linux/libata.h b/include/linux/libata.h index e7882ba63e7..25444dafae5 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -333,14 +333,15 @@ enum ata_completion_errors { struct scsi_device; struct ata_port_operations; struct ata_port; +struct ata_link; struct ata_queued_cmd; /* typedefs */ typedef void (*ata_qc_cb_t) (struct ata_queued_cmd *qc); -typedef int (*ata_prereset_fn_t)(struct ata_port *ap, unsigned long deadline); -typedef int (*ata_reset_fn_t)(struct ata_port *ap, unsigned int *classes, +typedef int (*ata_prereset_fn_t)(struct ata_link *link, unsigned long deadline); +typedef int (*ata_reset_fn_t)(struct ata_link *link, unsigned int *classes, unsigned long deadline); -typedef void (*ata_postreset_fn_t)(struct ata_port *ap, unsigned int *classes); +typedef void (*ata_postreset_fn_t)(struct ata_link *link, unsigned int *classes); struct ata_ioports { void __iomem *cmd_addr; @@ -706,14 +707,14 @@ extern int sata_link_debounce(struct ata_link *link, const unsigned long *params, unsigned long deadline); extern int sata_link_resume(struct ata_link *link, const unsigned long *params, unsigned long deadline); -extern int ata_std_prereset(struct ata_port *ap, unsigned long deadline); -extern int ata_std_softreset(struct ata_port *ap, unsigned int *classes, +extern int ata_std_prereset(struct ata_link *link, unsigned long deadline); +extern int ata_std_softreset(struct ata_link *link, unsigned int *classes, unsigned long deadline); -extern int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing, - unsigned long deadline); -extern int sata_std_hardreset(struct ata_port *ap, unsigned int *class, +extern int sata_link_hardreset(struct ata_link *link, + const unsigned long *timing, unsigned long deadline); +extern int sata_std_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline); -extern void ata_std_postreset(struct ata_port *ap, unsigned int *classes); +extern void ata_std_postreset(struct ata_link *link, unsigned int *classes); extern void ata_port_disable(struct ata_port *); extern void ata_std_ports(struct ata_ioports *ioaddr); #ifdef CONFIG_PCI -- cgit v1.2.3-70-g09d2 From 0260731f0187840e272bfa10d3ba0f3e417976f5 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 6 Aug 2007 18:36:23 +0900 Subject: libata-link: linkify config/EH related functions Make the following functions deal with ata_link instead of ata_port. * ata_set_mode() * ata_eh_autopsy() and related functions * ata_eh_report() and related functions * suspend/resume related functions * ata_eh_recover() and related functions Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ata_generic.c | 7 +-- drivers/ata/libata-core.c | 18 ++++--- drivers/ata/libata-eh.c | 121 ++++++++++++++++++++++--------------------- drivers/ata/libata.h | 2 +- drivers/ata/pata_it821x.c | 6 +-- drivers/ata/pata_ixp4xx_cf.c | 4 +- drivers/ata/pata_legacy.c | 6 +-- drivers/ata/pata_optidma.c | 11 ++-- drivers/ata/pata_pcmcia.c | 12 ++--- drivers/ata/pata_pdc2027x.c | 11 ++-- drivers/ata/pata_platform.c | 4 +- drivers/ata/pata_rz1000.c | 6 +-- drivers/ata/pdc_adma.c | 5 +- drivers/ata/sata_sil.c | 16 +++--- include/linux/libata.h | 4 +- 15 files changed, 122 insertions(+), 111 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c index 44328a16075..e390ad47c8e 100644 --- a/drivers/ata/ata_generic.c +++ b/drivers/ata/ata_generic.c @@ -34,7 +34,7 @@ /** * generic_set_mode - mode setting - * @ap: interface to set up + * @link: link to set up * @unused: returned device on error * * Use a non standard set_mode function. We don't want to be tuned. @@ -43,8 +43,9 @@ * and respect them. */ -static int generic_set_mode(struct ata_port *ap, struct ata_device **unused) +static int generic_set_mode(struct ata_link *link, struct ata_device **unused) { + struct ata_port *ap = link->ap; int dma_enabled = 0; struct ata_device *dev; @@ -52,7 +53,7 @@ static int generic_set_mode(struct ata_port *ap, struct ata_device **unused) if (ap->ioaddr.bmdma_addr) dma_enabled = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); - ata_link_for_each_dev(dev, &ap->link) { + ata_link_for_each_dev(dev, link) { if (ata_dev_enabled(dev)) { /* We don't really care */ dev->pio_mode = XFER_PIO_0; diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 73f66f4e1ee..944f54457c8 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2171,7 +2171,7 @@ int ata_bus_probe(struct ata_port *ap) } /* configure transfer mode */ - rc = ata_set_mode(ap, &dev); + rc = ata_set_mode(&ap->link, &dev); if (rc) goto fail; @@ -2782,7 +2782,7 @@ static int ata_dev_set_mode(struct ata_device *dev) /** * ata_do_set_mode - Program timings and issue SET FEATURES - XFER - * @ap: port on which timings will be programmed + * @link: link on which timings will be programmed * @r_failed_dev: out paramter for failed device * * Standard implementation of the function used to tune and set @@ -2797,9 +2797,9 @@ static int ata_dev_set_mode(struct ata_device *dev) * 0 on success, negative errno otherwise */ -int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) +int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev) { - struct ata_link *link = &ap->link; + struct ata_port *ap = link->ap; struct ata_device *dev; int rc = 0, used_dma = 0, found = 0; @@ -2877,7 +2877,7 @@ int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) /** * ata_set_mode - Program timings and issue SET FEATURES - XFER - * @ap: port on which timings will be programmed + * @link: link on which timings will be programmed * @r_failed_dev: out paramter for failed device * * Set ATA device disk transfer mode (PIO3, UDMA6, etc.). If @@ -2890,12 +2890,14 @@ int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) * RETURNS: * 0 on success, negative errno otherwise */ -int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) +int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev) { + struct ata_port *ap = link->ap; + /* has private set_mode? */ if (ap->ops->set_mode) - return ap->ops->set_mode(ap, r_failed_dev); - return ata_do_set_mode(ap, r_failed_dev); + return ap->ops->set_mode(link, r_failed_dev); + return ata_do_set_mode(link, r_failed_dev); } /** diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 0a9ce34a0e6..733aa761f3e 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1201,7 +1201,7 @@ static unsigned int atapi_eh_request_sense(struct ata_queued_cmd *qc) /** * ata_eh_analyze_serror - analyze SError for a failed port - * @ap: ATA port to analyze SError for + * @link: ATA link to analyze SError for * * Analyze SError if available and further determine cause of * failure. @@ -1209,9 +1209,9 @@ static unsigned int atapi_eh_request_sense(struct ata_queued_cmd *qc) * LOCKING: * None. */ -static void ata_eh_analyze_serror(struct ata_port *ap) +static void ata_eh_analyze_serror(struct ata_link *link) { - struct ata_eh_context *ehc = &ap->link.eh_context; + struct ata_eh_context *ehc = &link->eh_context; u32 serror = ehc->i.serror; unsigned int err_mask = 0, action = 0; @@ -1241,7 +1241,7 @@ static void ata_eh_analyze_serror(struct ata_port *ap) /** * ata_eh_analyze_ncq_error - analyze NCQ error - * @ap: ATA port to analyze NCQ error for + * @link: ATA link to analyze NCQ error for * * Read log page 10h, determine the offending qc and acquire * error status TF. For NCQ device errors, all LLDDs have to do @@ -1251,10 +1251,11 @@ static void ata_eh_analyze_serror(struct ata_port *ap) * LOCKING: * Kernel thread context (may sleep). */ -static void ata_eh_analyze_ncq_error(struct ata_port *ap) +static void ata_eh_analyze_ncq_error(struct ata_link *link) { - struct ata_eh_context *ehc = &ap->link.eh_context; - struct ata_device *dev = ap->link.device; + struct ata_port *ap = link->ap; + struct ata_eh_context *ehc = &link->eh_context; + struct ata_device *dev = link->device; struct ata_queued_cmd *qc; struct ata_taskfile tf; int tag, rc; @@ -1264,7 +1265,7 @@ static void ata_eh_analyze_ncq_error(struct ata_port *ap) return; /* is it NCQ device error? */ - if (!ap->link.sactive || !(ehc->i.err_mask & AC_ERR_DEV)) + if (!link->sactive || !(ehc->i.err_mask & AC_ERR_DEV)) return; /* has LLDD analyzed already? */ @@ -1281,13 +1282,13 @@ static void ata_eh_analyze_ncq_error(struct ata_port *ap) /* okay, this error is ours */ rc = ata_eh_read_log_10h(dev, &tag, &tf); if (rc) { - ata_port_printk(ap, KERN_ERR, "failed to read log page 10h " + ata_link_printk(link, KERN_ERR, "failed to read log page 10h " "(errno=%d)\n", rc); return; } - if (!(ap->link.sactive & (1 << tag))) { - ata_port_printk(ap, KERN_ERR, "log page 10h reported " + if (!(link->sactive & (1 << tag))) { + ata_link_printk(link, KERN_ERR, "log page 10h reported " "inactive tag %d\n", tag); return; } @@ -1551,18 +1552,18 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, int is_io, /** * ata_eh_autopsy - analyze error and determine recovery action - * @ap: ATA port to perform autopsy on + * @link: ATA link to perform autopsy on * - * Analyze why @ap failed and determine which recovery action is - * needed. This function also sets more detailed AC_ERR_* values - * and fills sense data for ATAPI CHECK SENSE. + * Analyze why @link failed and determine which recovery actions + * are needed. This function also sets more detailed AC_ERR_* + * values and fills sense data for ATAPI CHECK SENSE. * * LOCKING: * Kernel thread context (may sleep). */ -static void ata_eh_autopsy(struct ata_port *ap) +static void ata_eh_autopsy(struct ata_link *link) { - struct ata_link *link = &ap->link; + struct ata_port *ap = link->ap; struct ata_eh_context *ehc = &link->eh_context; unsigned int all_err_mask = 0; int tag, is_io = 0; @@ -1578,7 +1579,7 @@ static void ata_eh_autopsy(struct ata_port *ap) rc = sata_scr_read(link, SCR_ERROR, &serror); if (rc == 0) { ehc->i.serror |= serror; - ata_eh_analyze_serror(ap); + ata_eh_analyze_serror(link); } else if (rc != -EOPNOTSUPP) { /* SError read failed, force hardreset and probing */ ata_ehi_schedule_probe(&ehc->i); @@ -1587,7 +1588,7 @@ static void ata_eh_autopsy(struct ata_port *ap) } /* analyze NCQ failure */ - ata_eh_analyze_ncq_error(ap); + ata_eh_analyze_ncq_error(link); /* any real error trumps AC_ERR_OTHER */ if (ehc->i.err_mask & ~AC_ERR_OTHER) @@ -1598,7 +1599,7 @@ static void ata_eh_autopsy(struct ata_port *ap) for (tag = 0; tag < ATA_MAX_QUEUE; tag++) { struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag); - if (!(qc->flags & ATA_QCFLAG_FAILED)) + if (!(qc->flags & ATA_QCFLAG_FAILED) || qc->dev->link != link) continue; /* inherit upper level err_mask */ @@ -1653,16 +1654,17 @@ static void ata_eh_autopsy(struct ata_port *ap) /** * ata_eh_report - report error handling to user - * @ap: ATA port EH is going on + * @link: ATA link EH is going on * * Report EH to user. * * LOCKING: * None. */ -static void ata_eh_report(struct ata_port *ap) +static void ata_eh_report(struct ata_link *link) { - struct ata_eh_context *ehc = &ap->link.eh_context; + struct ata_port *ap = link->ap; + struct ata_eh_context *ehc = &link->eh_context; const char *frozen, *desc; int tag, nr_failed = 0; @@ -1673,7 +1675,7 @@ static void ata_eh_report(struct ata_port *ap) for (tag = 0; tag < ATA_MAX_QUEUE; tag++) { struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag); - if (!(qc->flags & ATA_QCFLAG_FAILED)) + if (!(qc->flags & ATA_QCFLAG_FAILED) || qc->dev->link != link) continue; if (qc->flags & ATA_QCFLAG_SENSE_VALID && !qc->err_mask) continue; @@ -1691,17 +1693,17 @@ static void ata_eh_report(struct ata_port *ap) if (ehc->i.dev) { ata_dev_printk(ehc->i.dev, KERN_ERR, "exception Emask 0x%x " "SAct 0x%x SErr 0x%x action 0x%x%s\n", - ehc->i.err_mask, ap->link.sactive, + ehc->i.err_mask, link->sactive, ehc->i.serror, ehc->i.action, frozen); if (desc) ata_dev_printk(ehc->i.dev, KERN_ERR, "%s\n", desc); } else { - ata_port_printk(ap, KERN_ERR, "exception Emask 0x%x " + ata_link_printk(link, KERN_ERR, "exception Emask 0x%x " "SAct 0x%x SErr 0x%x action 0x%x%s\n", - ehc->i.err_mask, ap->link.sactive, + ehc->i.err_mask, link->sactive, ehc->i.serror, ehc->i.action, frozen); if (desc) - ata_port_printk(ap, KERN_ERR, "%s\n", desc); + ata_link_printk(link, KERN_ERR, "%s\n", desc); } for (tag = 0; tag < ATA_MAX_QUEUE; tag++) { @@ -1714,7 +1716,8 @@ static void ata_eh_report(struct ata_port *ap) struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag); struct ata_taskfile *cmd = &qc->tf, *res = &qc->result_tf; - if (!(qc->flags & ATA_QCFLAG_FAILED) || !qc->err_mask) + if (!(qc->flags & ATA_QCFLAG_FAILED) || + qc->dev->link != link || !qc->err_mask) continue; ata_dev_printk(qc->dev, KERN_ERR, @@ -1936,10 +1939,11 @@ static int ata_eh_reset(struct ata_link *link, int classify, return rc; } -static int ata_eh_revalidate_and_attach(struct ata_port *ap, +static int ata_eh_revalidate_and_attach(struct ata_link *link, struct ata_device **r_failed_dev) { - struct ata_eh_context *ehc = &ap->link.eh_context; + struct ata_port *ap = link->ap; + struct ata_eh_context *ehc = &link->eh_context; struct ata_device *dev; unsigned int new_mask = 0; unsigned long flags; @@ -1951,7 +1955,7 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, * be done backwards such that PDIAG- is released by the slave * device before the master device is identified. */ - ata_link_for_each_dev_reverse(dev, &ap->link) { + ata_link_for_each_dev_reverse(dev, link) { unsigned int action = ata_eh_dev_action(dev); unsigned int readid_flags = 0; @@ -1959,17 +1963,17 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, readid_flags |= ATA_READID_POSTRESET; if ((action & ATA_EH_REVALIDATE) && ata_dev_enabled(dev)) { - if (ata_link_offline(&ap->link)) { + if (ata_link_offline(link)) { rc = -EIO; goto err; } - ata_eh_about_to_do(&ap->link, dev, ATA_EH_REVALIDATE); + ata_eh_about_to_do(link, dev, ATA_EH_REVALIDATE); rc = ata_dev_revalidate(dev, readid_flags); if (rc) goto err; - ata_eh_done(&ap->link, dev, ATA_EH_REVALIDATE); + ata_eh_done(link, dev, ATA_EH_REVALIDATE); /* Configuration may have changed, reconfigure * transfer mode. @@ -2011,7 +2015,7 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, /* Configure new devices forward such that user doesn't see * device detection messages backwards. */ - ata_link_for_each_dev(dev, &ap->link) { + ata_link_for_each_dev(dev, link) { if (!(new_mask & (1 << dev->devno))) continue; @@ -2037,40 +2041,40 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, return rc; } -static int ata_port_nr_enabled(struct ata_port *ap) +static int ata_link_nr_enabled(struct ata_link *link) { struct ata_device *dev; int cnt = 0; - ata_link_for_each_dev(dev, &ap->link) + ata_link_for_each_dev(dev, link) if (ata_dev_enabled(dev)) cnt++; return cnt; } -static int ata_port_nr_vacant(struct ata_port *ap) +static int ata_link_nr_vacant(struct ata_link *link) { struct ata_device *dev; int cnt = 0; - ata_link_for_each_dev(dev, &ap->link) + ata_link_for_each_dev(dev, link) if (dev->class == ATA_DEV_UNKNOWN) cnt++; return cnt; } -static int ata_eh_skip_recovery(struct ata_port *ap) +static int ata_eh_skip_recovery(struct ata_link *link) { - struct ata_eh_context *ehc = &ap->link.eh_context; + struct ata_eh_context *ehc = &link->eh_context; struct ata_device *dev; /* thaw frozen port, resume link and recover failed devices */ - if ((ap->pflags & ATA_PFLAG_FROZEN) || - (ehc->i.flags & ATA_EHI_RESUME_LINK) || ata_port_nr_enabled(ap)) + if ((link->ap->pflags & ATA_PFLAG_FROZEN) || + (ehc->i.flags & ATA_EHI_RESUME_LINK) || ata_link_nr_enabled(link)) return 0; /* skip if class codes for all vacant slots are ATA_DEV_NONE */ - ata_link_for_each_dev(dev, &ap->link) { + ata_link_for_each_dev(dev, link) { if (dev->class == ATA_DEV_UNKNOWN && ehc->classes[dev->devno] != ATA_DEV_NONE) return 0; @@ -2154,14 +2158,15 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, ata_reset_fn_t softreset, ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) { - struct ata_eh_context *ehc = &ap->link.eh_context; + struct ata_link *link = &ap->link; + struct ata_eh_context *ehc = &link->eh_context; struct ata_device *dev; int rc; DPRINTK("ENTER\n"); /* prep for recovery */ - ata_link_for_each_dev(dev, &ap->link) { + ata_link_for_each_dev(dev, link) { ehc->tries[dev->devno] = ATA_EH_DEV_TRIES; /* collect port action mask recorded in dev actions */ @@ -2191,20 +2196,20 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, goto out; /* skip EH if possible. */ - if (ata_eh_skip_recovery(ap)) + if (ata_eh_skip_recovery(link)) ehc->i.action = 0; - ata_link_for_each_dev(dev, &ap->link) + ata_link_for_each_dev(dev, link) ehc->classes[dev->devno] = ATA_DEV_UNKNOWN; /* reset */ if (ehc->i.action & ATA_EH_RESET_MASK) { ata_eh_freeze_port(ap); - rc = ata_eh_reset(&ap->link, ata_port_nr_vacant(ap), prereset, + rc = ata_eh_reset(link, ata_link_nr_vacant(link), prereset, softreset, hardreset, postreset); if (rc) { - ata_port_printk(ap, KERN_ERR, + ata_link_printk(link, KERN_ERR, "reset failed, giving up\n"); goto out; } @@ -2213,13 +2218,13 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, } /* revalidate existing devices and attach new ones */ - rc = ata_eh_revalidate_and_attach(ap, &dev); + rc = ata_eh_revalidate_and_attach(link, &dev); if (rc) goto dev_fail; /* configure transfer mode if necessary */ if (ehc->i.flags & ATA_EHI_SETMODE) { - rc = ata_set_mode(ap, &dev); + rc = ata_set_mode(link, &dev); if (rc) goto dev_fail; ehc->i.flags &= ~ATA_EHI_SETMODE; @@ -2230,8 +2235,8 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, dev_fail: ata_eh_handle_dev_fail(dev, rc); - if (ata_port_nr_enabled(ap)) { - ata_port_printk(ap, KERN_WARNING, "failed to recover some " + if (ata_link_nr_enabled(link)) { + ata_link_printk(link, KERN_WARNING, "failed to recover some " "devices, retrying in 5 secs\n"); ssleep(5); } else { @@ -2243,7 +2248,7 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, out: if (rc) { - ata_link_for_each_dev(dev, &ap->link); + ata_link_for_each_dev(dev, link); ata_dev_disable(dev); } @@ -2310,8 +2315,8 @@ void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset, ata_reset_fn_t softreset, ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) { - ata_eh_autopsy(ap); - ata_eh_report(ap); + ata_eh_autopsy(&ap->link); + ata_eh_report(&ap->link); ata_eh_recover(ap, prereset, softreset, hardreset, postreset); ata_eh_finish(ap); } diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 700843a9f30..6d85edefa7c 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -81,7 +81,7 @@ extern int ata_dev_configure(struct ata_device *dev); extern int sata_down_spd_limit(struct ata_link *link); extern int sata_set_spd_needed(struct ata_link *link); extern int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel); -extern int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev); +extern int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev); extern void ata_sg_clean(struct ata_queued_cmd *qc); extern void ata_qc_free(struct ata_queued_cmd *qc); extern void ata_qc_issue(struct ata_queued_cmd *qc); diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c index 088eb1d2376..f32d9b7ab49 100644 --- a/drivers/ata/pata_it821x.c +++ b/drivers/ata/pata_it821x.c @@ -450,7 +450,7 @@ static unsigned int it821x_passthru_qc_issue_prot(struct ata_queued_cmd *qc) /** * it821x_smart_set_mode - mode setting - * @ap: interface to set up + * @link: interface to set up * @unused: device that failed (error only) * * Use a non standard set_mode function. We don't want to be tuned. @@ -459,11 +459,11 @@ static unsigned int it821x_passthru_qc_issue_prot(struct ata_queued_cmd *qc) * and respect them. */ -static int it821x_smart_set_mode(struct ata_port *ap, struct ata_device **unused) +static int it821x_smart_set_mode(struct ata_link *link, struct ata_device **unused) { struct ata_device *dev; - ata_link_for_each_dev(dev, &ap->link) { + ata_link_for_each_dev(dev, link) { if (ata_dev_enabled(dev)) { /* We don't really care */ dev->pio_mode = XFER_PIO_0; diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c index 7db315a9baa..6bf1709508a 100644 --- a/drivers/ata/pata_ixp4xx_cf.c +++ b/drivers/ata/pata_ixp4xx_cf.c @@ -26,11 +26,11 @@ #define DRV_NAME "pata_ixp4xx_cf" #define DRV_VERSION "0.2" -static int ixp4xx_set_mode(struct ata_port *ap, struct ata_device **error) +static int ixp4xx_set_mode(struct ata_link *link, struct ata_device **error) { struct ata_device *dev; - ata_link_for_each_dev(dev, &ap->link) { + ata_link_for_each_dev(dev, link) { if (ata_dev_enabled(dev)) { ata_dev_printk(dev, KERN_INFO, "configured for PIO0\n"); dev->pio_mode = XFER_PIO_0; diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c index 9d92843b033..cfb2bc86a1d 100644 --- a/drivers/ata/pata_legacy.c +++ b/drivers/ata/pata_legacy.c @@ -96,7 +96,7 @@ static int iordy_mask = 0xFFFFFFFF; /* Use iordy if available */ /** * legacy_set_mode - mode setting - * @ap: IDE interface + * @link: IDE link * @unused: Device that failed when error is returned * * Use a non standard set_mode function. We don't want to be tuned. @@ -107,11 +107,11 @@ static int iordy_mask = 0xFFFFFFFF; /* Use iordy if available */ * expand on this as per hdparm in the base kernel. */ -static int legacy_set_mode(struct ata_port *ap, struct ata_device **unused) +static int legacy_set_mode(struct ata_link *link, struct ata_device **unused) { struct ata_device *dev; - ata_link_for_each_dev(dev, &ap->link) { + ata_link_for_each_dev(dev, link) { if (ata_dev_enabled(dev)) { ata_dev_printk(dev, KERN_INFO, "configured for PIO\n"); dev->pio_mode = XFER_PIO_0; diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c index 39fcba80007..09ef725afd9 100644 --- a/drivers/ata/pata_optidma.c +++ b/drivers/ata/pata_optidma.c @@ -324,25 +324,26 @@ static u8 optidma_make_bits43(struct ata_device *adev) /** * optidma_set_mode - mode setup - * @ap: port to set up + * @link: link to set up * * Use the standard setup to tune the chipset and then finalise the * configuration by writing the nibble of extra bits of data into * the chip. */ -static int optidma_set_mode(struct ata_port *ap, struct ata_device **r_failed) +static int optidma_set_mode(struct ata_link *link, struct ata_device **r_failed) { + struct ata_port *ap = link->ap; u8 r; int nybble = 4 * ap->port_no; struct pci_dev *pdev = to_pci_dev(ap->host->dev); - int rc = ata_do_set_mode(ap, r_failed); + int rc = ata_do_set_mode(link, r_failed); if (rc == 0) { pci_read_config_byte(pdev, 0x43, &r); r &= (0x0F << nybble); - r |= (optidma_make_bits43(&ap->link.device[0]) + - (optidma_make_bits43(&ap->link.device[0]) << 2)) << nybble; + r |= (optidma_make_bits43(&link->device[0]) + + (optidma_make_bits43(&link->device[0]) << 2)) << nybble; pci_write_config_byte(pdev, 0x43, r); } return rc; diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c index 890f649ddcc..9bfe12ac851 100644 --- a/drivers/ata/pata_pcmcia.c +++ b/drivers/ata/pata_pcmcia.c @@ -56,7 +56,7 @@ struct ata_pcmcia_info { /** * pcmcia_set_mode - PCMCIA specific mode setup - * @ap: Port + * @link: link * @r_failed_dev: Return pointer for failed device * * Perform the tuning and setup of the devices and timings, which @@ -65,13 +65,13 @@ struct ata_pcmcia_info { * decode, which alas is embarrassingly common in the PC world */ -static int pcmcia_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) +static int pcmcia_set_mode(struct ata_link *link, struct ata_device **r_failed_dev) { - struct ata_device *master = &ap->link.device[0]; - struct ata_device *slave = &ap->link.device[1]; + struct ata_device *master = &link->device[0]; + struct ata_device *slave = &link->device[1]; if (!ata_dev_enabled(master) || !ata_dev_enabled(slave)) - return ata_do_set_mode(ap, r_failed_dev); + return ata_do_set_mode(link, r_failed_dev); if (memcmp(master->id + ATA_ID_FW_REV, slave->id + ATA_ID_FW_REV, ATA_ID_FW_REV_LEN + ATA_ID_PROD_LEN) == 0) @@ -84,7 +84,7 @@ static int pcmcia_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev ata_dev_disable(slave); } } - return ata_do_set_mode(ap, r_failed_dev); + return ata_do_set_mode(link, r_failed_dev); } static struct scsi_host_template pcmcia_sht = { diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c index ba39efbe540..db069d7515b 100644 --- a/drivers/ata/pata_pdc2027x.c +++ b/drivers/ata/pata_pdc2027x.c @@ -69,7 +69,7 @@ static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev); static int pdc2027x_check_atapi_dma(struct ata_queued_cmd *qc); static unsigned long pdc2027x_mode_filter(struct ata_device *adev, unsigned long mask); static int pdc2027x_cable_detect(struct ata_port *ap); -static int pdc2027x_set_mode(struct ata_port *ap, struct ata_device **r_failed); +static int pdc2027x_set_mode(struct ata_link *link, struct ata_device **r_failed); /* * ATA Timing Tables based on 133MHz controller clock. @@ -470,23 +470,24 @@ static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev) /** * pdc2027x_set_mode - Set the timing registers back to correct values. - * @ap: Port to configure + * @link: link to configure * @r_failed: Returned device for failure * * The pdc2027x hardware will look at "SET FEATURES" and change the timing registers * automatically. The values set by the hardware might be incorrect, under 133Mhz PLL. * This function overwrites the possibly incorrect values set by the hardware to be correct. */ -static int pdc2027x_set_mode(struct ata_port *ap, struct ata_device **r_failed) +static int pdc2027x_set_mode(struct ata_link *link, struct ata_device **r_failed) { + struct ata_port *ap = link->ap; struct ata_device *dev; int rc; - rc = ata_do_set_mode(ap, r_failed); + rc = ata_do_set_mode(link, r_failed); if (rc < 0) return rc; - ata_link_for_each_dev(dev, &ap->link) { + ata_link_for_each_dev(dev, link) { if (ata_dev_enabled(dev)) { pdc2027x_set_piomode(ap, dev); diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c index ee1605bfc29..37e5158391d 100644 --- a/drivers/ata/pata_platform.c +++ b/drivers/ata/pata_platform.c @@ -30,11 +30,11 @@ static int pio_mask = 1; * Provide our own set_mode() as we don't want to change anything that has * already been configured.. */ -static int pata_platform_set_mode(struct ata_port *ap, struct ata_device **unused) +static int pata_platform_set_mode(struct ata_link *link, struct ata_device **unused) { struct ata_device *dev; - ata_link_for_each_dev(dev, &ap->link) { + ata_link_for_each_dev(dev, link) { if (ata_dev_enabled(dev)) { /* We don't really care */ dev->pio_mode = dev->xfer_mode = XFER_PIO_0; diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c index 300b3d5de81..de3698cf3b8 100644 --- a/drivers/ata/pata_rz1000.c +++ b/drivers/ata/pata_rz1000.c @@ -26,7 +26,7 @@ /** * rz1000_set_mode - mode setting function - * @ap: ATA interface + * @link: ATA link * @unused: returned device on set_mode failure * * Use a non standard set_mode function. We don't want to be tuned. We @@ -34,11 +34,11 @@ * whacked out. */ -static int rz1000_set_mode(struct ata_port *ap, struct ata_device **unused) +static int rz1000_set_mode(struct ata_link *link, struct ata_device **unused) { struct ata_device *dev; - ata_link_for_each_dev(dev, &ap->link) { + ata_link_for_each_dev(dev, link) { if (ata_dev_enabled(dev)) { /* We don't really care */ dev->pio_mode = XFER_PIO_0; diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c index 064a3b50560..304c19b9b0f 100644 --- a/drivers/ata/pdc_adma.c +++ b/drivers/ata/pdc_adma.c @@ -297,15 +297,16 @@ static void adma_thaw(struct ata_port *ap) adma_reinit_engine(ap); } -static int adma_prereset(struct ata_port *ap, unsigned long deadline) +static int adma_prereset(struct ata_link *link, unsigned long deadline) { + struct ata_port *ap = link->ap; struct adma_port_priv *pp = ap->private_data; if (pp->state != adma_state_idle) /* healthy paranoia */ pp->state = adma_state_mmio; adma_reinit_engine(ap); - return ata_std_prereset(ap, deadline); + return ata_std_prereset(link, deadline); } static void adma_error_handler(struct ata_port *ap) diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index 4c9295a49a4..5cd3eb83e4a 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -117,7 +117,7 @@ static int sil_pci_device_resume(struct pci_dev *pdev); static void sil_dev_config(struct ata_device *dev); static int sil_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val); static int sil_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val); -static int sil_set_mode (struct ata_port *ap, struct ata_device **r_failed); +static int sil_set_mode(struct ata_link *link, struct ata_device **r_failed); static void sil_freeze(struct ata_port *ap); static void sil_thaw(struct ata_port *ap); @@ -290,27 +290,27 @@ static unsigned char sil_get_device_cache_line(struct pci_dev *pdev) /** * sil_set_mode - wrap set_mode functions - * @ap: port to set up + * @link: link to set up * @r_failed: returned device when we fail * * Wrap the libata method for device setup as after the setup we need * to inspect the results and do some configuration work */ -static int sil_set_mode (struct ata_port *ap, struct ata_device **r_failed) +static int sil_set_mode(struct ata_link *link, struct ata_device **r_failed) { - struct ata_host *host = ap->host; - struct ata_device *dev; - void __iomem *mmio_base = host->iomap[SIL_MMIO_BAR]; + struct ata_port *ap = link->ap; + void __iomem *mmio_base = ap->host->iomap[SIL_MMIO_BAR]; void __iomem *addr = mmio_base + sil_port[ap->port_no].xfer_mode; + struct ata_device *dev; u32 tmp, dev_mode[2] = { }; int rc; - rc = ata_do_set_mode(ap, r_failed); + rc = ata_do_set_mode(link, r_failed); if (rc) return rc; - ata_link_for_each_dev(dev, &ap->link) { + ata_link_for_each_dev(dev, link) { if (!ata_dev_enabled(dev)) dev_mode[dev->devno] = 0; /* PIO0/1/2 */ else if (dev->flags & ATA_DFLAG_PIO) diff --git a/include/linux/libata.h b/include/linux/libata.h index 25444dafae5..0f86d9be78a 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -607,7 +607,7 @@ struct ata_port_operations { void (*dev_select)(struct ata_port *ap, unsigned int device); void (*phy_reset) (struct ata_port *ap); /* obsolete */ - int (*set_mode) (struct ata_port *ap, struct ata_device **r_failed_dev); + int (*set_mode) (struct ata_link *link, struct ata_device **r_failed_dev); int (*cable_detect) (struct ata_port *ap); @@ -838,7 +838,7 @@ extern void ata_scsi_slave_destroy(struct scsi_device *sdev); extern int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth); extern struct ata_device *ata_dev_pair(struct ata_device *adev); -extern int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev); +extern int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev); extern u8 ata_irq_on(struct ata_port *ap); extern u8 ata_dummy_irq_on(struct ata_port *ap); extern u8 ata_irq_ack(struct ata_port *ap, unsigned int chk_drq); -- cgit v1.2.3-70-g09d2 From 0c88758b5a6325428aaadab619886242db20ceae Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 6 Aug 2007 18:36:23 +0900 Subject: libata-link: make two port flags HRST_TO_RESUME and SKIP_D2H_BSY link flags HRST_TO_RESUME and SKIP_D2H_BSY are link attributes. Move them to ata_link->flags. This will allow host and PMP links to have different attributes. ata_port_info->link_flags is added and used by LLDs to specify these flags during initialization. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 16 ++++++++++------ drivers/ata/libata-core.c | 5 +++-- drivers/ata/sata_nv.c | 14 +++++++------- drivers/ata/sata_sil.c | 7 ++++++- drivers/ata/sata_sil24.c | 7 +++++-- include/linux/libata.h | 11 ++++++++--- 6 files changed, 39 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index e38ae12d014..483733783cf 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -178,8 +178,8 @@ enum { AHCI_FLAG_COMMON = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | - ATA_FLAG_SKIP_D2H_BSY | ATA_FLAG_ACPI_SATA, + AHCI_LFLAG_COMMON = ATA_LFLAG_SKIP_D2H_BSY, }; struct ahci_cmd_hdr { @@ -333,6 +333,7 @@ static const struct ata_port_info ahci_port_info[] = { /* board_ahci */ { .flags = AHCI_FLAG_COMMON, + .link_flags = AHCI_LFLAG_COMMON, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, .port_ops = &ahci_ops, @@ -340,14 +341,15 @@ static const struct ata_port_info ahci_port_info[] = { /* board_ahci_pi */ { .flags = AHCI_FLAG_COMMON | AHCI_FLAG_HONOR_PI, + .link_flags = AHCI_LFLAG_COMMON, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, .port_ops = &ahci_ops, }, /* board_ahci_vt8251 */ { - .flags = AHCI_FLAG_COMMON | ATA_FLAG_HRST_TO_RESUME | - AHCI_FLAG_NO_NCQ, + .flags = AHCI_FLAG_COMMON | AHCI_FLAG_NO_NCQ, + .link_flags = AHCI_LFLAG_COMMON | ATA_LFLAG_HRST_TO_RESUME, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, .port_ops = &ahci_vt8251_ops, @@ -355,6 +357,7 @@ static const struct ata_port_info ahci_port_info[] = { /* board_ahci_ign_iferr */ { .flags = AHCI_FLAG_COMMON | AHCI_FLAG_IGN_IRQ_IF_ERR, + .link_flags = AHCI_LFLAG_COMMON, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, .port_ops = &ahci_ops, @@ -364,6 +367,7 @@ static const struct ata_port_info ahci_port_info[] = { .flags = AHCI_FLAG_COMMON | AHCI_FLAG_IGN_SERR_INTERNAL | AHCI_FLAG_32BIT_ONLY, + .link_flags = AHCI_LFLAG_COMMON, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, .port_ops = &ahci_ops, @@ -373,9 +377,9 @@ static const struct ata_port_info ahci_port_info[] = { .sht = &ahci_sht, .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | - ATA_FLAG_SKIP_D2H_BSY | AHCI_FLAG_HONOR_PI | - AHCI_FLAG_NO_NCQ | AHCI_FLAG_NO_MSI | - AHCI_FLAG_MV_PATA, + AHCI_FLAG_HONOR_PI | AHCI_FLAG_NO_NCQ | + AHCI_FLAG_NO_MSI | AHCI_FLAG_MV_PATA, + .link_flags = AHCI_LFLAG_COMMON, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, .port_ops = &ahci_ops, diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 944f54457c8..2be30c7a222 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -3332,7 +3332,7 @@ int ata_std_prereset(struct ata_link *link, unsigned long deadline) /* handle link resume */ if ((ehc->i.flags & ATA_EHI_RESUME_LINK) && - (ap->flags & ATA_FLAG_HRST_TO_RESUME)) + (link->flags & ATA_LFLAG_HRST_TO_RESUME)) ehc->i.action |= ATA_EH_HARDRESET; /* if we're about to do hardreset, nothing more to do */ @@ -3351,7 +3351,7 @@ int ata_std_prereset(struct ata_link *link, unsigned long deadline) /* Wait for !BSY if the controller can wait for the first D2H * Reg FIS and we don't know that no device is attached. */ - if (!(ap->flags & ATA_FLAG_SKIP_D2H_BSY) && !ata_link_offline(link)) { + if (!(link->flags & ATA_LFLAG_SKIP_D2H_BSY) && !ata_link_offline(link)) { rc = ata_wait_ready(ap, deadline); if (rc && rc != -ENODEV) { ata_link_printk(link, KERN_WARNING, "device not ready " @@ -6269,6 +6269,7 @@ struct ata_host *ata_host_alloc_pinfo(struct device *dev, ap->mwdma_mask = pi->mwdma_mask; ap->udma_mask = pi->udma_mask; ap->flags |= pi->flags; + ap->link.flags |= pi->link_flags; ap->ops = pi->port_ops; if (!host->ops && (pi->port_ops != &ata_dummy_port_ops)) diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index 67ba0f75f1e..884d9f05e6c 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -455,8 +455,8 @@ static const struct ata_port_info nv_port_info[] = { /* generic */ { .sht = &nv_sht, - .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_HRST_TO_RESUME, + .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, + .link_flags = ATA_LFLAG_HRST_TO_RESUME, .pio_mask = NV_PIO_MASK, .mwdma_mask = NV_MWDMA_MASK, .udma_mask = NV_UDMA_MASK, @@ -466,8 +466,8 @@ static const struct ata_port_info nv_port_info[] = { /* nforce2/3 */ { .sht = &nv_sht, - .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_HRST_TO_RESUME, + .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, + .link_flags = ATA_LFLAG_HRST_TO_RESUME, .pio_mask = NV_PIO_MASK, .mwdma_mask = NV_MWDMA_MASK, .udma_mask = NV_UDMA_MASK, @@ -477,8 +477,8 @@ static const struct ata_port_info nv_port_info[] = { /* ck804 */ { .sht = &nv_sht, - .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_HRST_TO_RESUME, + .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, + .link_flags = ATA_LFLAG_HRST_TO_RESUME, .pio_mask = NV_PIO_MASK, .mwdma_mask = NV_MWDMA_MASK, .udma_mask = NV_UDMA_MASK, @@ -489,8 +489,8 @@ static const struct ata_port_info nv_port_info[] = { { .sht = &nv_adma_sht, .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_HRST_TO_RESUME | ATA_FLAG_MMIO | ATA_FLAG_NCQ, + .link_flags = ATA_LFLAG_HRST_TO_RESUME, .pio_mask = NV_PIO_MASK, .mwdma_mask = NV_MWDMA_MASK, .udma_mask = NV_UDMA_MASK, diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index 5cd3eb83e4a..802d679dc99 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -59,7 +59,8 @@ enum { SIL_FLAG_MOD15WRITE = (1 << 30), SIL_DFL_PORT_FLAGS = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_MMIO | ATA_FLAG_HRST_TO_RESUME, + ATA_FLAG_MMIO, + SIL_DFL_LINK_FLAGS = ATA_LFLAG_HRST_TO_RESUME, /* * Controller IDs @@ -216,6 +217,7 @@ static const struct ata_port_info sil_port_info[] = { /* sil_3112 */ { .flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_MOD15WRITE, + .link_flags = SIL_DFL_LINK_FLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA5, @@ -225,6 +227,7 @@ static const struct ata_port_info sil_port_info[] = { { .flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_MOD15WRITE | SIL_FLAG_NO_SATA_IRQ, + .link_flags = SIL_DFL_LINK_FLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA5, @@ -233,6 +236,7 @@ static const struct ata_port_info sil_port_info[] = { /* sil_3512 */ { .flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT, + .link_flags = SIL_DFL_LINK_FLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA5, @@ -241,6 +245,7 @@ static const struct ata_port_info sil_port_info[] = { /* sil_3114 */ { .flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT, + .link_flags = SIL_DFL_LINK_FLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA5, diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index 869e414d7ed..e2cccc7f435 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -237,8 +237,8 @@ enum { /* host flags */ SIL24_COMMON_FLAGS = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | - ATA_FLAG_NCQ | ATA_FLAG_SKIP_D2H_BSY | - ATA_FLAG_ACPI_SATA, + ATA_FLAG_NCQ | ATA_FLAG_ACPI_SATA, + SIL24_COMMON_LFLAGS = ATA_LFLAG_SKIP_D2H_BSY, SIL24_FLAG_PCIX_IRQ_WOC = (1 << 24), /* IRQ loss errata on PCI-X */ IRQ_STAT_4PORTS = 0xf, @@ -424,6 +424,7 @@ static const struct ata_port_info sil24_port_info[] = { { .flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(4) | SIL24_FLAG_PCIX_IRQ_WOC, + .link_flags = SIL24_COMMON_LFLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA5, /* udma0-5 */ @@ -432,6 +433,7 @@ static const struct ata_port_info sil24_port_info[] = { /* sil_3132 */ { .flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(2), + .link_flags = SIL24_COMMON_LFLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA5, /* udma0-5 */ @@ -440,6 +442,7 @@ static const struct ata_port_info sil24_port_info[] = { /* sil_3131/sil_3531 */ { .flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(1), + .link_flags = SIL24_COMMON_LFLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA5, /* udma0-5 */ diff --git a/include/linux/libata.h b/include/linux/libata.h index 0f86d9be78a..74ced08d598 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -156,6 +156,11 @@ enum { ATA_DEV_ATAPI_UNSUP = 4, /* ATAPI device (unsupported) */ ATA_DEV_NONE = 5, /* no device */ + /* struct ata_link flags */ + ATA_LFLAG_HRST_TO_RESUME = (1 << 0), /* hardreset to resume link */ + ATA_LFLAG_SKIP_D2H_BSY = (1 << 1), /* can't wait for the first D2H + * Register FIS clearing BSY */ + /* struct ata_port flags */ ATA_FLAG_SLAVE_POSS = (1 << 0), /* host supports slave dev */ /* (doesn't imply presence) */ @@ -170,9 +175,6 @@ enum { ATA_FLAG_PIO_POLLING = (1 << 9), /* use polling PIO if LLD * doesn't handle PIO interrupts */ ATA_FLAG_NCQ = (1 << 10), /* host supports NCQ */ - ATA_FLAG_HRST_TO_RESUME = (1 << 11), /* hardreset to resume phy */ - ATA_FLAG_SKIP_D2H_BSY = (1 << 12), /* can't wait for the first D2H - * Register FIS clearing BSY */ ATA_FLAG_DEBUGMSG = (1 << 13), ATA_FLAG_IGN_SIMPLEX = (1 << 15), /* ignore SIMPLEX */ ATA_FLAG_NO_IORDY = (1 << 16), /* controller lacks iordy */ @@ -517,6 +519,8 @@ struct ata_link { unsigned int active_tag; /* active tag on this link */ u32 sactive; /* active NCQ commands */ + unsigned int flags; /* ATA_LFLAG_xxx */ + unsigned int hw_sata_spd_limit; unsigned int sata_spd_limit; unsigned int sata_spd; /* current SATA PHY speed */ @@ -654,6 +658,7 @@ struct ata_port_operations { struct ata_port_info { struct scsi_host_template *sht; unsigned long flags; + unsigned long link_flags; unsigned long pio_mask; unsigned long mwdma_mask; unsigned long udma_mask; -- cgit v1.2.3-70-g09d2 From 4fb37a25b976e8d1b34461330b3f2c6d9b94c133 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 6 Aug 2007 18:36:23 +0900 Subject: libata-link: separate out link initialization functions Separate out link initialization into ata_link_init() and ata_link_init_sata_spd(). Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 84 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 64 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 2be30c7a222..3da642bd2ee 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -6060,6 +6060,68 @@ void ata_dev_init(struct ata_device *dev) dev->udma_mask = UINT_MAX; } +/** + * ata_link_init - Initialize an ata_link structure + * @ap: ATA port link is attached to + * @link: Link structure to initialize + * + * Initialize @link. + * + * LOCKING: + * Kernel thread context (may sleep) + */ +static void ata_link_init(struct ata_port *ap, struct ata_link *link) +{ + int i; + + /* clear everything except for devices */ + memset(link, 0, offsetof(struct ata_link, device[0])); + + link->ap = ap; + link->active_tag = ATA_TAG_POISON; + link->hw_sata_spd_limit = UINT_MAX; + + /* can't use iterator, ap isn't initialized yet */ + for (i = 0; i < ATA_MAX_DEVICES; i++) { + struct ata_device *dev = &link->device[i]; + + dev->link = link; + dev->devno = dev - link->device; + ata_dev_init(dev); + } +} + +/** + * sata_link_init_spd - Initialize link->sata_spd_limit + * @link: Link to configure sata_spd_limit for + * + * Initialize @link->[hw_]sata_spd_limit to the currently + * configured value. + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno on failure. + */ +static int sata_link_init_spd(struct ata_link *link) +{ + u32 scontrol, spd; + int rc; + + rc = sata_scr_read(link, SCR_CONTROL, &scontrol); + if (rc) + return rc; + + spd = (scontrol >> 4) & 0xf; + if (spd) + link->hw_sata_spd_limit &= (1 << spd) - 1; + + link->sata_spd_limit = link->hw_sata_spd_limit; + + return 0; +} + /** * ata_port_alloc - allocate and initialize basic ATA port resources * @host: ATA host this allocated port belongs to @@ -6075,7 +6137,6 @@ void ata_dev_init(struct ata_device *dev) struct ata_port *ata_port_alloc(struct ata_host *host) { struct ata_port *ap; - unsigned int i; DPRINTK("ENTER\n"); @@ -6090,9 +6151,6 @@ struct ata_port *ata_port_alloc(struct ata_host *host) ap->ctl = ATA_DEVCTL_OBS; ap->host = host; ap->dev = host->dev; - - ap->link.hw_sata_spd_limit = UINT_MAX; - ap->link.active_tag = ATA_TAG_POISON; ap->last_ctl = 0xFF; #if defined(ATA_VERBOSE_DEBUG) @@ -6115,15 +6173,7 @@ struct ata_port *ata_port_alloc(struct ata_host *host) ap->cbl = ATA_CBL_NONE; - ap->link.ap = ap; - - /* can't use iterator, ap isn't initialized yet */ - for (i = 0; i < ATA_MAX_DEVICES; i++) { - struct ata_device *dev = &ap->link.device[i]; - dev->link = &ap->link; - dev->devno = i; - ata_dev_init(dev); - } + ata_link_init(ap, &ap->link); #ifdef ATA_IRQ_TRAP ap->stats.unhandled_irq = 1; @@ -6406,7 +6456,6 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) for (i = 0; i < host->n_ports; i++) { struct ata_port *ap = host->ports[i]; int irq_line; - u32 scontrol; unsigned long xfer_mask; /* set SATA cable type if still unset */ @@ -6414,12 +6463,7 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) ap->cbl = ATA_CBL_SATA; /* init sata_spd_limit to the current value */ - if (sata_scr_read(&ap->link, SCR_CONTROL, &scontrol) == 0) { - int spd = (scontrol >> 4) & 0xf; - if (spd) - ap->link.hw_sata_spd_limit &= (1 << spd) - 1; - } - ap->link.sata_spd_limit = ap->link.hw_sata_spd_limit; + sata_link_init_spd(&ap->link); /* report the secondary IRQ for second channel legacy */ irq_line = host->irq; -- cgit v1.2.3-70-g09d2 From dbd826168d6267a26cf20cd233f6730f8d8047d6 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 6 Aug 2007 18:36:23 +0900 Subject: libata-link: implement ata_link_abort() Implement ata_link_abort(). Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 1 + drivers/ata/libata-eh.c | 50 ++++++++++++++++++++++++++++++++++------------- include/linux/libata.h | 1 + 3 files changed, 38 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 3da642bd2ee..dcae590cc9b 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -7050,6 +7050,7 @@ EXPORT_SYMBOL_GPL(ata_ehi_push_desc); EXPORT_SYMBOL_GPL(ata_ehi_clear_desc); EXPORT_SYMBOL_GPL(ata_eng_timeout); EXPORT_SYMBOL_GPL(ata_port_schedule_eh); +EXPORT_SYMBOL_GPL(ata_link_abort); EXPORT_SYMBOL_GPL(ata_port_abort); EXPORT_SYMBOL_GPL(ata_port_freeze); EXPORT_SYMBOL_GPL(ata_eh_freeze_port); diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 733aa761f3e..eb4c0593b40 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -719,19 +719,7 @@ void ata_port_schedule_eh(struct ata_port *ap) DPRINTK("port EH scheduled\n"); } -/** - * ata_port_abort - abort all qc's on the port - * @ap: ATA port to abort qc's for - * - * Abort all active qc's of @ap and schedule EH. - * - * LOCKING: - * spin_lock_irqsave(host lock) - * - * RETURNS: - * Number of aborted qc's. - */ -int ata_port_abort(struct ata_port *ap) +static int ata_do_link_abort(struct ata_port *ap, struct ata_link *link) { int tag, nr_aborted = 0; @@ -743,7 +731,7 @@ int ata_port_abort(struct ata_port *ap) for (tag = 0; tag < ATA_MAX_QUEUE; tag++) { struct ata_queued_cmd *qc = ata_qc_from_tag(ap, tag); - if (qc) { + if (qc && (!link || qc->dev->link == link)) { qc->flags |= ATA_QCFLAG_FAILED; ata_qc_complete(qc); nr_aborted++; @@ -756,6 +744,40 @@ int ata_port_abort(struct ata_port *ap) return nr_aborted; } +/** + * ata_link_abort - abort all qc's on the link + * @link: ATA link to abort qc's for + * + * Abort all active qc's active on @link and schedule EH. + * + * LOCKING: + * spin_lock_irqsave(host lock) + * + * RETURNS: + * Number of aborted qc's. + */ +int ata_link_abort(struct ata_link *link) +{ + return ata_do_link_abort(link->ap, link); +} + +/** + * ata_port_abort - abort all qc's on the port + * @ap: ATA port to abort qc's for + * + * Abort all active qc's of @ap and schedule EH. + * + * LOCKING: + * spin_lock_irqsave(host_set lock) + * + * RETURNS: + * Number of aborted qc's. + */ +int ata_port_abort(struct ata_port *ap) +{ + return ata_do_link_abort(ap, NULL); +} + /** * __ata_port_freeze - freeze port * @ap: ATA port to freeze diff --git a/include/linux/libata.h b/include/linux/libata.h index 74ced08d598..bfa15578999 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -906,6 +906,7 @@ extern unsigned long ata_pci_default_filter(struct ata_device *, unsigned long); extern void ata_eng_timeout(struct ata_port *ap); extern void ata_port_schedule_eh(struct ata_port *ap); +extern int ata_link_abort(struct ata_link *link); extern int ata_port_abort(struct ata_port *ap); extern int ata_port_freeze(struct ata_port *ap); -- cgit v1.2.3-70-g09d2 From 8989805d6d176aa32c0e9a68a536aa4c8ef5231c Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 6 Aug 2007 18:36:23 +0900 Subject: libata-link: add PMP links Add link->pmp, ap->nr_pmp_links, ap->pmp_link[], and implement/update link helpers. printk helpers are updated such that port and link are identifed as 'ataP:' if no PMP is attached, while device is identified as 'ataP.DD:'. If PMP is attached, they become 'ataP:', 'ataP.LL:' and 'ataP.LL' - ie. link and device are identified their PMP number. If PPM is attached (ap->nr_pmp_links != 0), ata_for_each_link() iterates over PMP links, while __ata_for_each_link() iterates over the host link + PMP links. If PMP is not attached (ap->nr_pmp_links == 0), both iterate over only the host link. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 6 ++++-- include/linux/libata.h | 53 +++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 51 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index dcae590cc9b..af9c0ab600d 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -6064,13 +6064,14 @@ void ata_dev_init(struct ata_device *dev) * ata_link_init - Initialize an ata_link structure * @ap: ATA port link is attached to * @link: Link structure to initialize + * @pmp: Port multiplier port number * * Initialize @link. * * LOCKING: * Kernel thread context (may sleep) */ -static void ata_link_init(struct ata_port *ap, struct ata_link *link) +static void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp) { int i; @@ -6078,6 +6079,7 @@ static void ata_link_init(struct ata_port *ap, struct ata_link *link) memset(link, 0, offsetof(struct ata_link, device[0])); link->ap = ap; + link->pmp = pmp; link->active_tag = ATA_TAG_POISON; link->hw_sata_spd_limit = UINT_MAX; @@ -6173,7 +6175,7 @@ struct ata_port *ata_port_alloc(struct ata_host *host) ap->cbl = ATA_CBL_NONE; - ata_link_init(ap, &ap->link); + ata_link_init(ap, &ap->link, 0); #ifdef ATA_IRQ_TRAP ap->stats.unhandled_irq = 1; diff --git a/include/linux/libata.h b/include/linux/libata.h index bfa15578999..7a1793bd237 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -515,6 +515,7 @@ struct ata_acpi_gtm { struct ata_link { struct ata_port *ap; + int pmp; /* port multiplier port # */ unsigned int active_tag; /* active tag on this link */ u32 sactive; /* active NCQ commands */ @@ -563,6 +564,9 @@ struct ata_port { struct ata_link link; /* host default link */ + int nr_pmp_links; /* nr of available PMP links */ + struct ata_link *pmp_link; /* array of PMP links */ + struct ata_port_stats stats; struct ata_host *host; struct device *dev; @@ -926,11 +930,17 @@ extern void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset, #define ata_port_printk(ap, lv, fmt, args...) \ printk(lv"ata%u: "fmt, (ap)->print_id , ##args) -#define ata_link_printk(link, lv, fmt, args...) \ - printk(lv"ata%u: "fmt, (link)->ap->print_id , ##args) +#define ata_link_printk(link, lv, fmt, args...) do { \ + if ((link)->ap->nr_pmp_links) \ + printk(lv"ata%u.%02u: "fmt, (link)->ap->print_id, \ + (link)->pmp , ##args); \ + else \ + printk(lv"ata%u: "fmt, (link)->ap->print_id , ##args); \ + } while(0) #define ata_dev_printk(dev, lv, fmt, args...) \ - printk(lv"ata%u.%02u: "fmt, (dev)->link->ap->print_id, (dev)->devno , ##args) + printk(lv"ata%u.%02u: "fmt, (dev)->link->ap->print_id, \ + (dev)->link->pmp + (dev)->devno , ##args) /* * ata_eh_info helpers @@ -1039,15 +1049,46 @@ static inline unsigned int ata_dev_absent(const struct ata_device *dev) /* * link helpers */ +static inline int ata_is_host_link(const struct ata_link *link) +{ + return link == &link->ap->link; +} + static inline int ata_link_max_devices(const struct ata_link *link) { - if (link->ap->flags & ATA_FLAG_SLAVE_POSS) + if (ata_is_host_link(link) && link->ap->flags & ATA_FLAG_SLAVE_POSS) return 2; return 1; } -#define ata_port_for_each_link(lk, ap) \ - for ((lk) = &(ap)->link; (lk); (lk) = NULL) +static inline struct ata_link *ata_port_first_link(struct ata_port *ap) +{ + if (ap->nr_pmp_links) + return ap->pmp_link; + return &ap->link; +} + +static inline struct ata_link *ata_port_next_link(struct ata_link *link) +{ + struct ata_port *ap = link->ap; + + if (link == &ap->link) { + if (!ap->nr_pmp_links) + return NULL; + return ap->pmp_link; + } + + if (++link - ap->pmp_link < ap->nr_pmp_links) + return link; + return NULL; +} + +#define __ata_port_for_each_link(lk, ap) \ + for ((lk) = &(ap)->link; (lk); (lk) = ata_port_next_link(lk)) + +#define ata_port_for_each_link(link, ap) \ + for ((link) = ata_port_first_link(ap); (link); \ + (link) = ata_port_next_link(link)) #define ata_link_for_each_dev(dev, link) \ for ((dev) = (link)->device; \ -- cgit v1.2.3-70-g09d2 From cf1b86c8ab41fe2b2a2eb59c9a2ea9a7e463653a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 6 Aug 2007 18:36:23 +0900 Subject: libata-link: update ata_scsi_error() to handle PMP links Update ata_scsi_error() to handle PMP links. As error conditions can occur on both host and PMP links, __ata_port_for_each_link() is used. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-eh.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index eb4c0593b40..45eb932c393 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -363,6 +363,8 @@ void ata_scsi_error(struct Scsi_Host *host) repeat: /* invoke error handler */ if (ap->ops->error_handler) { + struct ata_link *link; + /* kill fast drain timer */ del_timer_sync(&ap->fastdrain_timer); @@ -372,9 +374,11 @@ void ata_scsi_error(struct Scsi_Host *host) /* fetch & clear EH info */ spin_lock_irqsave(ap->lock, flags); - memset(&ap->link.eh_context, 0, sizeof(ap->link.eh_context)); - ap->link.eh_context.i = ap->link.eh_info; - memset(&ap->link.eh_info, 0, sizeof(ap->link.eh_info)); + __ata_port_for_each_link(link, ap) { + memset(&link->eh_context, 0, sizeof(link->eh_context)); + link->eh_context.i = link->eh_info; + memset(&link->eh_info, 0, sizeof(link->eh_info)); + } ap->pflags |= ATA_PFLAG_EH_IN_PROGRESS; ap->pflags &= ~ATA_PFLAG_EH_PENDING; @@ -410,7 +414,8 @@ void ata_scsi_error(struct Scsi_Host *host) } /* this run is complete, make sure EH info is clear */ - memset(&ap->link.eh_info, 0, sizeof(ap->link.eh_info)); + __ata_port_for_each_link(link, ap) + memset(&link->eh_info, 0, sizeof(link->eh_info)); /* Clear host_eh_scheduled while holding ap->lock such * that if exception occurs after this point but -- cgit v1.2.3-70-g09d2 From 9b1e2658faf3f3095a96558c333b333c0e29dbc0 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 6 Aug 2007 18:36:24 +0900 Subject: libata-link: update EH to deal with PMP links Update ata_eh_autopsy(), ata_eh_report(), ata_eh_revalidate_and_attach() and ata_eh_recover() to deal with PMP links. ata_eh_autopsy() and ata_eh_report() updates are straightforward. They just repeat the same operation over all configured links. The only change to ata_eh_revalidate_and_attach() is avoiding calling ->cable_select() on non-host ports. ata_eh_recover() update is more complex as it first processes all resets and then performs the rest. This is necessary as thawing with some links in unknown state can be dangerous. ehi->action is cleared on successful recovery of a link to avoid repeating recovery due to failures in other links. ata_eh_recover() iterates over only PMP links if PMP is attached, and, on failure, the failing link is returned in @failed_link instead of disabling devices directly. These are to integrate ata_eh_recover() into PMP EH later. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-eh.c | 228 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 158 insertions(+), 70 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 45eb932c393..2ddc2ed9c29 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1578,8 +1578,8 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, int is_io, } /** - * ata_eh_autopsy - analyze error and determine recovery action - * @link: ATA link to perform autopsy on + * ata_eh_link_autopsy - analyze error and determine recovery action + * @link: host link to perform autopsy on * * Analyze why @link failed and determine which recovery actions * are needed. This function also sets more detailed AC_ERR_* @@ -1588,7 +1588,7 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, int is_io, * LOCKING: * Kernel thread context (may sleep). */ -static void ata_eh_autopsy(struct ata_link *link) +static void ata_eh_link_autopsy(struct ata_link *link) { struct ata_port *ap = link->ap; struct ata_eh_context *ehc = &link->eh_context; @@ -1680,7 +1680,25 @@ static void ata_eh_autopsy(struct ata_link *link) } /** - * ata_eh_report - report error handling to user + * ata_eh_autopsy - analyze error and determine recovery action + * @ap: host port to perform autopsy on + * + * Analyze all links of @ap and determine why they failed and + * which recovery actions are needed. + * + * LOCKING: + * Kernel thread context (may sleep). + */ +static void ata_eh_autopsy(struct ata_port *ap) +{ + struct ata_link *link; + + __ata_port_for_each_link(link, ap) + ata_eh_link_autopsy(link); +} + +/** + * ata_eh_link_report - report error handling to user * @link: ATA link EH is going on * * Report EH to user. @@ -1688,7 +1706,7 @@ static void ata_eh_autopsy(struct ata_link *link) * LOCKING: * None. */ -static void ata_eh_report(struct ata_link *link) +static void ata_eh_link_report(struct ata_link *link) { struct ata_port *ap = link->ap; struct ata_eh_context *ehc = &link->eh_context; @@ -1767,6 +1785,23 @@ static void ata_eh_report(struct ata_link *link) } } +/** + * ata_eh_report - report error handling to user + * @ap: ATA port to report EH about + * + * Report EH to user. + * + * LOCKING: + * None. + */ +static void ata_eh_report(struct ata_port *ap) +{ + struct ata_link *link; + + __ata_port_for_each_link(link, ap) + ata_eh_link_report(link); +} + static int ata_do_reset(struct ata_link *link, ata_reset_fn_t reset, unsigned int *classes, unsigned long deadline) { @@ -2036,7 +2071,8 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link, } /* PDIAG- should have been released, ask cable type if post-reset */ - if ((ehc->i.flags & ATA_EHI_DID_RESET) && ap->ops->cable_detect) + if (ata_is_host_link(link) && ap->ops->cable_detect && + (ehc->i.flags & ATA_EHI_DID_RESET)) ap->cbl = ap->ops->cable_detect(ap); /* Configure new devices forward such that user doesn't see @@ -2110,7 +2146,7 @@ static int ata_eh_skip_recovery(struct ata_link *link) return 1; } -static void ata_eh_handle_dev_fail(struct ata_device *dev, int err) +static int ata_eh_handle_dev_fail(struct ata_device *dev, int err) { struct ata_eh_context *ehc = &dev->link->eh_context; @@ -2151,12 +2187,16 @@ static void ata_eh_handle_dev_fail(struct ata_device *dev, int err) ehc->did_probe_mask |= (1 << dev->devno); ehc->i.action |= ATA_EH_SOFTRESET; } + + return 1; } else { /* soft didn't work? be haaaaard */ if (ehc->i.flags & ATA_EHI_DID_RESET) ehc->i.action |= ATA_EH_HARDRESET; else ehc->i.action |= ATA_EH_SOFTRESET; + + return 0; } } @@ -2167,12 +2207,13 @@ static void ata_eh_handle_dev_fail(struct ata_device *dev, int err) * @softreset: softreset method (can be NULL) * @hardreset: hardreset method (can be NULL) * @postreset: postreset method (can be NULL) + * @r_failed_link: out parameter for failed link * * This is the alpha and omega, eum and yang, heart and soul of * libata exception handling. On entry, actions required to - * recover the port and hotplug requests are recorded in - * eh_context. This function executes all the operations with - * appropriate retrials and fallbacks to resurrect failed + * recover each link and hotplug requests are recorded in the + * link's eh_context. This function executes all the operations + * with appropriate retrials and fallbacks to resurrect failed * devices, detach goners and greet newcomers. * * LOCKING: @@ -2183,102 +2224,139 @@ static void ata_eh_handle_dev_fail(struct ata_device *dev, int err) */ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, ata_reset_fn_t softreset, ata_reset_fn_t hardreset, - ata_postreset_fn_t postreset) + ata_postreset_fn_t postreset, + struct ata_link **r_failed_link) { - struct ata_link *link = &ap->link; - struct ata_eh_context *ehc = &link->eh_context; + struct ata_link *link; struct ata_device *dev; - int rc; + int nr_failed_devs, nr_disabled_devs; + int reset, rc; DPRINTK("ENTER\n"); /* prep for recovery */ - ata_link_for_each_dev(dev, link) { - ehc->tries[dev->devno] = ATA_EH_DEV_TRIES; + ata_port_for_each_link(link, ap) { + struct ata_eh_context *ehc = &link->eh_context; - /* collect port action mask recorded in dev actions */ - ehc->i.action |= - ehc->i.dev_action[dev->devno] & ~ATA_EH_PERDEV_MASK; - ehc->i.dev_action[dev->devno] &= ATA_EH_PERDEV_MASK; - - /* process hotplug request */ - if (dev->flags & ATA_DFLAG_DETACH) - ata_eh_detach_dev(dev); + ata_link_for_each_dev(dev, link) { + ehc->tries[dev->devno] = ATA_EH_DEV_TRIES; - if (!ata_dev_enabled(dev) && - ((ehc->i.probe_mask & (1 << dev->devno)) && - !(ehc->did_probe_mask & (1 << dev->devno)))) { - ata_eh_detach_dev(dev); - ata_dev_init(dev); - ehc->did_probe_mask |= (1 << dev->devno); - ehc->i.action |= ATA_EH_SOFTRESET; + /* collect port action mask recorded in dev actions */ + ehc->i.action |= ehc->i.dev_action[dev->devno] & + ~ATA_EH_PERDEV_MASK; + ehc->i.dev_action[dev->devno] &= ATA_EH_PERDEV_MASK; + + /* process hotplug request */ + if (dev->flags & ATA_DFLAG_DETACH) + ata_eh_detach_dev(dev); + + if (!ata_dev_enabled(dev) && + ((ehc->i.probe_mask & (1 << dev->devno)) && + !(ehc->did_probe_mask & (1 << dev->devno)))) { + ata_eh_detach_dev(dev); + ata_dev_init(dev); + ehc->did_probe_mask |= (1 << dev->devno); + ehc->i.action |= ATA_EH_SOFTRESET; + } } } retry: rc = 0; + nr_failed_devs = 0; + nr_disabled_devs = 0; + reset = 0; /* if UNLOADING, finish immediately */ if (ap->pflags & ATA_PFLAG_UNLOADING) goto out; - /* skip EH if possible. */ - if (ata_eh_skip_recovery(link)) - ehc->i.action = 0; + /* prep for EH */ + ata_port_for_each_link(link, ap) { + struct ata_eh_context *ehc = &link->eh_context; - ata_link_for_each_dev(dev, link) - ehc->classes[dev->devno] = ATA_DEV_UNKNOWN; + /* skip EH if possible. */ + if (ata_eh_skip_recovery(link)) + ehc->i.action = 0; + + /* do we need to reset? */ + if (ehc->i.action & ATA_EH_RESET_MASK) + reset = 1; + + ata_link_for_each_dev(dev, link) + ehc->classes[dev->devno] = ATA_DEV_UNKNOWN; + } /* reset */ - if (ehc->i.action & ATA_EH_RESET_MASK) { + if (reset) { ata_eh_freeze_port(ap); - rc = ata_eh_reset(link, ata_link_nr_vacant(link), prereset, - softreset, hardreset, postreset); - if (rc) { - ata_link_printk(link, KERN_ERR, - "reset failed, giving up\n"); - goto out; + ata_port_for_each_link(link, ap) { + struct ata_eh_context *ehc = &link->eh_context; + + if (!(ehc->i.action & ATA_EH_RESET_MASK)) + continue; + + rc = ata_eh_reset(link, ata_link_nr_vacant(link), + prereset, softreset, hardreset, + postreset); + if (rc) { + ata_link_printk(link, KERN_ERR, + "reset failed, giving up\n"); + goto out; + } } ata_eh_thaw_port(ap); } - /* revalidate existing devices and attach new ones */ - rc = ata_eh_revalidate_and_attach(link, &dev); - if (rc) - goto dev_fail; + /* the rest */ + ata_port_for_each_link(link, ap) { + struct ata_eh_context *ehc = &link->eh_context; - /* configure transfer mode if necessary */ - if (ehc->i.flags & ATA_EHI_SETMODE) { - rc = ata_set_mode(link, &dev); + /* revalidate existing devices and attach new ones */ + rc = ata_eh_revalidate_and_attach(link, &dev); if (rc) goto dev_fail; - ehc->i.flags &= ~ATA_EHI_SETMODE; - } - goto out; + /* configure transfer mode if necessary */ + if (ehc->i.flags & ATA_EHI_SETMODE) { + rc = ata_set_mode(link, &dev); + if (rc) + goto dev_fail; + ehc->i.flags &= ~ATA_EHI_SETMODE; + } + + /* this link is okay now */ + ehc->i.flags = 0; + continue; - dev_fail: - ata_eh_handle_dev_fail(dev, rc); + dev_fail: + nr_failed_devs++; + if (ata_eh_handle_dev_fail(dev, rc)) + nr_disabled_devs++; - if (ata_link_nr_enabled(link)) { - ata_link_printk(link, KERN_WARNING, "failed to recover some " - "devices, retrying in 5 secs\n"); - ssleep(5); - } else { - /* no device left, repeat fast */ - msleep(500); + if (ap->pflags & ATA_PFLAG_FROZEN) + break; } - goto retry; + if (nr_failed_devs) { + if (nr_failed_devs != nr_disabled_devs) { + ata_port_printk(ap, KERN_WARNING, "failed to recover " + "some devices, retrying in 5 secs\n"); + ssleep(5); + } else { + /* no device left to recover, repeat fast */ + msleep(500); + } - out: - if (rc) { - ata_link_for_each_dev(dev, link); - ata_dev_disable(dev); + goto retry; } + out: + if (rc && r_failed_link) + *r_failed_link = link; + DPRINTK("EXIT, rc=%d\n", rc); return rc; } @@ -2342,9 +2420,19 @@ void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset, ata_reset_fn_t softreset, ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) { - ata_eh_autopsy(&ap->link); - ata_eh_report(&ap->link); - ata_eh_recover(ap, prereset, softreset, hardreset, postreset); + struct ata_device *dev; + int rc; + + ata_eh_autopsy(ap); + ata_eh_report(ap); + + rc = ata_eh_recover(ap, prereset, softreset, hardreset, postreset, + NULL); + if (rc) { + ata_link_for_each_dev(dev, &ap->link) + ata_dev_disable(dev); + } + ata_eh_finish(ap); } -- cgit v1.2.3-70-g09d2 From 41bda9c98035dd3589b02cbc1de02f71d2faf9c8 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 6 Aug 2007 18:36:24 +0900 Subject: libata-link: update hotplug to handle PMP links Update hotplug to handle PMP links. When PMP is attached, the PMP number corresponds to C of SCSI H:C:I:L. While at it, change argument to ata_find_dev() to @devno from @id to avoid confusion with SCSI device ID. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 7 +- drivers/ata/libata-scsi.c | 159 +++++++++++++++++++++++++++++++--------------- 2 files changed, 114 insertions(+), 52 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index af9c0ab600d..14f299278f1 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -6604,6 +6604,7 @@ int ata_host_activate(struct ata_host *host, int irq, void ata_port_detach(struct ata_port *ap) { unsigned long flags; + struct ata_link *link; struct ata_device *dev; if (!ap->ops->error_handler) @@ -6621,8 +6622,10 @@ void ata_port_detach(struct ata_port *ap) */ spin_lock_irqsave(ap->lock, flags); - ata_link_for_each_dev(dev, &ap->link) - ata_dev_disable(dev); + ata_port_for_each_link(link, ap) { + ata_link_for_each_dev(dev, link) + ata_dev_disable(dev); + } spin_unlock_irqrestore(ap->lock, flags); diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 3d6d5f73799..58051ee40f1 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -2423,21 +2423,36 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc) return 0; } -static struct ata_device * ata_find_dev(struct ata_port *ap, int id) +static struct ata_device * ata_find_dev(struct ata_port *ap, int devno) { - if (likely(id < ata_link_max_devices(&ap->link))) - return &ap->link.device[id]; + if (ap->nr_pmp_links == 0) { + if (likely(devno < ata_link_max_devices(&ap->link))) + return &ap->link.device[devno]; + } else { + if (likely(devno < ap->nr_pmp_links)) + return &ap->pmp_link[devno].device[0]; + } + return NULL; } static struct ata_device * __ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev) { + int devno; + /* skip commands not addressed to targets we simulate */ - if (unlikely(scsidev->channel || scsidev->lun)) - return NULL; + if (ap->nr_pmp_links == 0) { + if (unlikely(scsidev->channel || scsidev->lun)) + return NULL; + devno = scsidev->id; + } else { + if (unlikely(scsidev->id || scsidev->lun)) + return NULL; + devno = scsidev->channel; + } - return ata_find_dev(ap, scsidev->id); + return ata_find_dev(ap, devno); } /** @@ -2951,22 +2966,32 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync) { int tries = 5; struct ata_device *last_failed_dev = NULL; + struct ata_link *link; struct ata_device *dev; if (ap->flags & ATA_FLAG_DISABLED) return; repeat: - ata_link_for_each_dev(dev, &ap->link) { - struct scsi_device *sdev; + ata_port_for_each_link(link, ap) { + ata_link_for_each_dev(dev, link) { + struct scsi_device *sdev; + int channel = 0, id = 0; - if (!ata_dev_enabled(dev) || dev->sdev) - continue; + if (!ata_dev_enabled(dev) || dev->sdev) + continue; - sdev = __scsi_add_device(ap->scsi_host, 0, dev->devno, 0, NULL); - if (!IS_ERR(sdev)) { - dev->sdev = sdev; - scsi_device_put(sdev); + if (ata_is_host_link(link)) + id = dev->devno; + else + channel = link->pmp; + + sdev = __scsi_add_device(ap->scsi_host, channel, id, 0, + NULL); + if (!IS_ERR(sdev)) { + dev->sdev = sdev; + scsi_device_put(sdev); + } } } @@ -2974,11 +2999,14 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync) * failure occurred, scan would have failed silently. Check * whether all devices are attached. */ - ata_link_for_each_dev(dev, &ap->link) { - if (ata_dev_enabled(dev) && !dev->sdev) - break; + ata_port_for_each_link(link, ap) { + ata_link_for_each_dev(dev, link) { + if (ata_dev_enabled(dev) && !dev->sdev) + goto exit_loop; + } } - if (!dev) + exit_loop: + if (!link) return; /* we're missing some SCSI devices */ @@ -3092,6 +3120,25 @@ static void ata_scsi_remove_dev(struct ata_device *dev) } } +static void ata_scsi_handle_link_detach(struct ata_link *link) +{ + struct ata_port *ap = link->ap; + struct ata_device *dev; + + ata_link_for_each_dev(dev, link) { + unsigned long flags; + + if (!(dev->flags & ATA_DFLAG_DETACHED)) + continue; + + spin_lock_irqsave(ap->lock, flags); + dev->flags &= ~ATA_DFLAG_DETACHED; + spin_unlock_irqrestore(ap->lock, flags); + + ata_scsi_remove_dev(dev); + } +} + /** * ata_scsi_hotplug - SCSI part of hotplug * @work: Pointer to ATA port to perform SCSI hotplug on @@ -3108,7 +3155,7 @@ void ata_scsi_hotplug(struct work_struct *work) { struct ata_port *ap = container_of(work, struct ata_port, hotplug_task.work); - struct ata_device *dev; + int i; if (ap->pflags & ATA_PFLAG_UNLOADING) { DPRINTK("ENTER/EXIT - unloading\n"); @@ -3117,19 +3164,14 @@ void ata_scsi_hotplug(struct work_struct *work) DPRINTK("ENTER\n"); - /* unplug detached devices */ - ata_link_for_each_dev(dev, &ap->link) { - unsigned long flags; - - if (!(dev->flags & ATA_DFLAG_DETACHED)) - continue; - - spin_lock_irqsave(ap->lock, flags); - dev->flags &= ~ATA_DFLAG_DETACHED; - spin_unlock_irqrestore(ap->lock, flags); - - ata_scsi_remove_dev(dev); - } + /* Unplug detached devices. We cannot use link iterator here + * because PMP links have to be scanned even if PMP is + * currently not attached. Iterate manually. + */ + ata_scsi_handle_link_detach(&ap->link); + if (ap->pmp_link) + for (i = 0; i < SATA_PMP_MAX_PORTS; i++) + ata_scsi_handle_link_detach(&ap->pmp_link[i]); /* scan for new ones */ ata_scsi_scan_host(ap, 0); @@ -3157,26 +3199,40 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel, unsigned int id, unsigned int lun) { struct ata_port *ap = ata_shost_to_port(shost); - struct ata_eh_info *ehi = &ap->link.eh_info; unsigned long flags; - int rc = 0; + int devno, rc = 0; if (!ap->ops->error_handler) return -EOPNOTSUPP; - if ((channel != SCAN_WILD_CARD && channel != 0) || - (lun != SCAN_WILD_CARD && lun != 0)) + if (lun != SCAN_WILD_CARD && lun) return -EINVAL; + if (ap->nr_pmp_links == 0) { + if (channel != SCAN_WILD_CARD && channel) + return -EINVAL; + devno = id; + } else { + if (id != SCAN_WILD_CARD && id) + return -EINVAL; + devno = channel; + } + spin_lock_irqsave(ap->lock, flags); - if (id == SCAN_WILD_CARD) { - ehi->probe_mask |= (1 << ata_link_max_devices(&ap->link)) - 1; - ehi->action |= ATA_EH_SOFTRESET; + if (devno == SCAN_WILD_CARD) { + struct ata_link *link; + + ata_port_for_each_link(link, ap) { + struct ata_eh_info *ehi = &link->eh_info; + ehi->probe_mask |= (1 << ata_link_max_devices(link)) - 1; + ehi->action |= ATA_EH_SOFTRESET; + } } else { - struct ata_device *dev = ata_find_dev(ap, id); + struct ata_device *dev = ata_find_dev(ap, devno); if (dev) { + struct ata_eh_info *ehi = &dev->link->eh_info; ehi->probe_mask |= 1 << dev->devno; ehi->action |= ATA_EH_SOFTRESET; ehi->flags |= ATA_EHI_RESUME_LINK; @@ -3210,23 +3266,26 @@ void ata_scsi_dev_rescan(struct work_struct *work) { struct ata_port *ap = container_of(work, struct ata_port, scsi_rescan_task); + struct ata_link *link; struct ata_device *dev; unsigned long flags; spin_lock_irqsave(ap->lock, flags); - ata_link_for_each_dev(dev, &ap->link) { - struct scsi_device *sdev = dev->sdev; + ata_port_for_each_link(link, ap) { + ata_link_for_each_dev(dev, link) { + struct scsi_device *sdev = dev->sdev; - if (!ata_dev_enabled(dev) || !sdev) - continue; - if (scsi_device_get(sdev)) - continue; + if (!ata_dev_enabled(dev) || !sdev) + continue; + if (scsi_device_get(sdev)) + continue; - spin_unlock_irqrestore(ap->lock, flags); - scsi_rescan_device(&(sdev->sdev_gendev)); - scsi_device_put(sdev); - spin_lock_irqsave(ap->lock, flags); + spin_unlock_irqrestore(ap->lock, flags); + scsi_rescan_device(&(sdev->sdev_gendev)); + scsi_device_put(sdev); + spin_lock_irqsave(ap->lock, flags); + } } spin_unlock_irqrestore(ap->lock, flags); -- cgit v1.2.3-70-g09d2 From e3667ebf857ba744b5211c90d46f6a17dd9a2479 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 6 Aug 2007 18:36:24 +0900 Subject: libata-link: update Power Management to handle PMP links Update Power Management to consider PMP links. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 14f299278f1..8a79b976f08 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -5912,6 +5912,7 @@ static int ata_host_request_pm(struct ata_host *host, pm_message_t mesg, for (i = 0; i < host->n_ports; i++) { struct ata_port *ap = host->ports[i]; + struct ata_link *link; /* Previous resume operation might still be in * progress. Wait for PM_PENDING to clear. @@ -5931,8 +5932,10 @@ static int ata_host_request_pm(struct ata_host *host, pm_message_t mesg, } ap->pflags |= ATA_PFLAG_PM_PENDING; - ap->link.eh_info.action |= action; - ap->link.eh_info.flags |= ehi_flags; + __ata_port_for_each_link(link, ap) { + link->eh_info.action |= action; + link->eh_info.flags |= ehi_flags; + } ata_port_schedule_eh(ap); -- cgit v1.2.3-70-g09d2 From 0bc2a79a2002e3cc1b514c100b6c576983da6a90 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 31 Jul 2007 14:01:48 +0100 Subject: libata: Correct IORDY handling Debugging a report of a problem with an ancient solid state disk showed up some problems in the IORDY handling 1. We check the wrong bit to see if the device has IORDY 2. Even then some ancient creaking piles of crap don't support SETXFER at all. The cases it fixes are obscure and the risk of side effects is slight but possible. This also moves us slightly closer to supporting original MFM/RLL disks with libata. Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 6 +++++- include/linux/ata.h | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 8a79b976f08..02425e401a6 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2759,7 +2759,11 @@ static int ata_dev_set_mode(struct ata_device *dev) /* Old CFA may refuse this command, which is just fine */ if (dev->xfer_shift == ATA_SHIFT_PIO && ata_id_is_cfa(dev->id)) err_mask &= ~AC_ERR_DEV; - + /* Some very old devices and some bad newer ones fail any kind of + SET_XFERMODE request but support PIO0-2 timings and no IORDY */ + if (dev->xfer_shift == ATA_SHIFT_PIO && !ata_id_has_iordy(dev->id) && + dev->pio_mode <= XFER_PIO_2) + err_mask &= ~AC_ERR_DEV; if (err_mask) { ata_dev_printk(dev, KERN_ERR, "failed to set xfermode " "(err_mask=0x%x)\n", err_mask); diff --git a/include/linux/ata.h b/include/linux/ata.h index c043c1ccf1c..40c7af05fdb 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -358,7 +358,7 @@ struct ata_taskfile { #define ata_id_removeable(id) ((id)[0] & (1 << 7)) #define ata_id_has_dword_io(id) ((id)[50] & (1 << 0)) #define ata_id_iordy_disable(id) ((id)[49] & (1 << 10)) -#define ata_id_has_iordy(id) ((id)[49] & (1 << 9)) +#define ata_id_has_iordy(id) ((id)[49] & (1 << 11)) #define ata_id_u32(id,n) \ (((u32) (id)[(n) + 1] << 16) | ((u32) (id)[(n)])) #define ata_id_u64(id,n) \ -- cgit v1.2.3-70-g09d2 From 4cc980b34b2a25f600576dcd11de388bc44e1ebd Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Wed, 15 Aug 2007 03:19:45 -0400 Subject: libata: move ata_altstatus() to pio data xfer functions Move ata_altstatus() out from ata_hsm_move() to the pio data xfer functions like ata_pio_sectors() and atapi_pio_bytes() where it makes more sense. Signed-off-by: Albert Lee Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 02425e401a6..fc067937063 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4614,6 +4614,8 @@ static void ata_pio_sectors(struct ata_queued_cmd *qc) ata_pio_sector(qc); } else ata_pio_sector(qc); + + ata_altstatus(qc->ap); /* flush */ } /** @@ -4788,6 +4790,7 @@ static void atapi_pio_bytes(struct ata_queued_cmd *qc) VPRINTK("ata%u: xfering %d bytes\n", ap->print_id, bytes); __atapi_pio_bytes(qc, bytes); + ata_altstatus(ap); /* flush */ return; @@ -4959,7 +4962,6 @@ fsm_start: */ ap->hsm_task_state = HSM_ST; ata_pio_sectors(qc); - ata_altstatus(ap); /* flush */ } else /* send CDB */ atapi_send_cdb(ap, qc); @@ -5040,7 +5042,6 @@ fsm_start: if (!(qc->tf.flags & ATA_TFLAG_WRITE)) { ata_pio_sectors(qc); - ata_altstatus(ap); status = ata_wait_idle(ap); } @@ -5060,13 +5061,11 @@ fsm_start: if (ap->hsm_task_state == HSM_ST_LAST && (!(qc->tf.flags & ATA_TFLAG_WRITE))) { /* all data read */ - ata_altstatus(ap); status = ata_wait_idle(ap); goto fsm_start; } } - ata_altstatus(ap); /* flush */ poll_next = 1; break; -- cgit v1.2.3-70-g09d2 From baf4fdfaaf5cb9f4fb1c341c8cef60a64e580582 Mon Sep 17 00:00:00 2001 From: Mark Lord Date: Wed, 8 Aug 2007 01:08:45 +0900 Subject: libata: add support for ATA_16 on ATAPI Add support for issuing ATA_16 passthru commands to ATAPI devices managed by libata. It requires the previous CDB length fix patch. A boot/module parameter, "atapi_passthru16=0" can be used to globally disable this feature, if ever desired. tj: restructured __ata_scsi_queuecmd() according to Jeff's suggestion. Signed-off-by: Mark Lord Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 4 ++++ drivers/ata/libata-scsi.c | 52 ++++++++++++++++++++++++++++++++--------------- drivers/ata/libata.h | 1 + 3 files changed, 41 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index fc067937063..75ccf46972d 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -86,6 +86,10 @@ int atapi_dmadir = 0; module_param(atapi_dmadir, int, 0444); MODULE_PARM_DESC(atapi_dmadir, "Enable ATAPI DMADIR bridge support (0=off, 1=on)"); +int atapi_passthru16 = 1; +module_param(atapi_passthru16, int, 0444); +MODULE_PARM_DESC(atapi_passthru16, "Enable ATA_16 passthru for ATAPI devices; on by default (0=off, 1=on)"); + int libata_fua = 0; module_param_named(fua, libata_fua, int, 0444); MODULE_PARM_DESC(fua, "FUA support (0=off, 1=on)"); diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 58051ee40f1..7d66c986a54 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -2761,28 +2761,48 @@ static inline int __ata_scsi_queuecmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *), struct ata_device *dev) { + u8 scsi_op = scmd->cmnd[0]; + ata_xlat_func_t xlat_func; int rc = 0; - if (unlikely(!scmd->cmd_len || scmd->cmd_len > dev->cdb_len)) { - DPRINTK("bad CDB len=%u, max=%u\n", - scmd->cmd_len, dev->cdb_len); - scmd->result = DID_ERROR << 16; - done(scmd); - return 0; - } - if (dev->class == ATA_DEV_ATA) { - ata_xlat_func_t xlat_func = ata_get_xlat_func(dev, - scmd->cmnd[0]); + if (unlikely(!scmd->cmd_len || scmd->cmd_len > dev->cdb_len)) + goto bad_cdb_len; - if (xlat_func) - rc = ata_scsi_translate(dev, scmd, done, xlat_func); - else - ata_scsi_simulate(dev, scmd, done); - } else - rc = ata_scsi_translate(dev, scmd, done, atapi_xlat); + xlat_func = ata_get_xlat_func(dev, scsi_op); + } else { + if (unlikely(!scmd->cmd_len)) + goto bad_cdb_len; + + xlat_func = NULL; + if (likely((scsi_op != ATA_16) || !atapi_passthru16)) { + /* relay SCSI command to ATAPI device */ + if (unlikely(scmd->cmd_len > dev->cdb_len)) + goto bad_cdb_len; + + xlat_func = atapi_xlat; + } else { + /* ATA_16 passthru, treat as an ATA command */ + if (unlikely(scmd->cmd_len > 16)) + goto bad_cdb_len; + + xlat_func = ata_get_xlat_func(dev, scsi_op); + } + } + + if (xlat_func) + rc = ata_scsi_translate(dev, scmd, done, xlat_func); + else + ata_scsi_simulate(dev, scmd, done); return rc; + + bad_cdb_len: + DPRINTK("bad CDB len=%u, scsi_op=0x%02x, max=%u\n", + scmd->cmd_len, scsi_op, dev->cdb_len); + scmd->result = DID_ERROR << 16; + done(scmd); + return 0; } /** diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 6d85edefa7c..11f64a43b38 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -56,6 +56,7 @@ extern unsigned int ata_print_id; extern struct workqueue_struct *ata_aux_wq; extern int atapi_enabled; extern int atapi_dmadir; +extern int atapi_passthru16; extern int libata_fua; extern int libata_noacpi; extern struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev); -- cgit v1.2.3-70-g09d2 From 50a99018787aa1aed812e09ad5b27647475656a0 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 8 Aug 2007 14:27:00 +0100 Subject: libata-core: Document some limits/assumptions about ID_ATA Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 75ccf46972d..d2141a04fff 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -1618,6 +1618,9 @@ static u32 ata_pio_mask_no_iordy(const struct ata_device *adev) * devices. This function also issues ATA_CMD_INIT_DEV_PARAMS * for pre-ATA4 drives. * + * FIXME: ATA_CMD_ID_ATA is optional for early drives and right + * now we abort if we hit that case. + * * LOCKING: * Kernel thread context (may sleep) * @@ -1745,10 +1748,13 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, /* * The exact sequence expected by certain pre-ATA4 drives is: * SRST RESET - * IDENTIFY - * INITIALIZE DEVICE PARAMETERS + * IDENTIFY (optional in early ATA) + * INITIALIZE DEVICE PARAMETERS (later IDE and ATA) * anything else.. * Some drives were very specific about that exact sequence. + * + * Note that ATA4 says lba is mandatory so the second check + * shoud never trigger. */ if (ata_id_major_version(id) < 4 || !ata_id_has_lba(id)) { err_mask = ata_dev_init_params(dev, id[3], id[6]); -- cgit v1.2.3-70-g09d2 From 4f34337b1f6f7c1e0f2e3c938eb9eadd340593fe Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 8 Aug 2007 14:30:31 +0100 Subject: libata: Note that our cache flush code needs fixing up Remembered this while doing auditing and code review versus the specs Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index d2141a04fff..c0f3c78a2be 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -5906,6 +5906,10 @@ int ata_flush_cache(struct ata_device *dev) else cmd = ATA_CMD_FLUSH; + /* This is wrong. On a failed flush we get back the LBA of the lost + sector and we should (assuming it wasn't aborted as unknown) issue + a further flush command to continue the writeback until it + does not error */ err_mask = ata_do_simple_cmd(dev, cmd); if (err_mask) { ata_dev_printk(dev, KERN_ERR, "failed to flush cache\n"); -- cgit v1.2.3-70-g09d2 From 05d1efffdc9bf84311bb1a3c2e3db55b544ca119 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 10 Aug 2007 13:59:49 -0700 Subject: pata_cmd64x: Set up MWDMA modes properly Set the MWDMA timing by updating the correct registers. Split the PIO path as this is mostly shared code. Wants testing. Signed-off-by: Alan Cox Tested-by: Mikael Pettersson Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/ata/pata_cmd64x.c | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c index e34b632487d..922902a1b4a 100644 --- a/drivers/ata/pata_cmd64x.c +++ b/drivers/ata/pata_cmd64x.c @@ -31,7 +31,7 @@ #include #define DRV_NAME "pata_cmd64x" -#define DRV_VERSION "0.2.4" +#define DRV_VERSION "0.2.5" /* * CMD64x specific registers definition. @@ -88,14 +88,15 @@ static int cmd648_cable_detect(struct ata_port *ap) } /** - * cmd64x_set_piomode - set initial PIO mode data + * cmd64x_set_piomode - set PIO and MWDMA timing * @ap: ATA interface * @adev: ATA device + * @mode: mode * - * Called to do the PIO mode setup. + * Called to do the PIO and MWDMA mode setup. */ -static void cmd64x_set_piomode(struct ata_port *ap, struct ata_device *adev) +static void cmd64x_set_timing(struct ata_port *ap, struct ata_device *adev, u8 mode) { struct pci_dev *pdev = to_pci_dev(ap->host->dev); struct ata_timing t; @@ -117,8 +118,9 @@ static void cmd64x_set_piomode(struct ata_port *ap, struct ata_device *adev) int arttim = arttim_port[ap->port_no][adev->devno]; int drwtim = drwtim_port[ap->port_no][adev->devno]; - - if (ata_timing_compute(adev, adev->pio_mode, &t, T, 0) < 0) { + /* ata_timing_compute is smart and will produce timings for MWDMA + that don't violate the drives PIO capabilities. */ + if (ata_timing_compute(adev, mode, &t, T, 0) < 0) { printk(KERN_ERR DRV_NAME ": mode computation failed.\n"); return; } @@ -167,6 +169,20 @@ static void cmd64x_set_piomode(struct ata_port *ap, struct ata_device *adev) pci_write_config_byte(pdev, drwtim, (t.active << 4) | t.recover); } +/** + * cmd64x_set_piomode - set initial PIO mode data + * @ap: ATA interface + * @adev: ATA device + * + * Used when configuring the devices ot set the PIO timings. All the + * actual work is done by the PIO/MWDMA setting helper + */ + +static void cmd64x_set_piomode(struct ata_port *ap, struct ata_device *adev) +{ + cmd64x_set_timing(ap, adev, adev->pio_mode); +} + /** * cmd64x_set_dmamode - set initial DMA mode data * @ap: ATA interface @@ -180,9 +196,6 @@ static void cmd64x_set_dmamode(struct ata_port *ap, struct ata_device *adev) static const u8 udma_data[] = { 0x30, 0x20, 0x10, 0x20, 0x10, 0x00 }; - static const u8 mwdma_data[] = { - 0x30, 0x20, 0x10 - }; struct pci_dev *pdev = to_pci_dev(ap->host->dev); u8 regU, regD; @@ -208,8 +221,10 @@ static void cmd64x_set_dmamode(struct ata_port *ap, struct ata_device *adev) regU |= 1 << adev->devno; /* UDMA on */ if (adev->dma_mode > 2) /* 15nS timing */ regU |= 4 << adev->devno; - } else - regD |= mwdma_data[adev->dma_mode - XFER_MW_DMA_0] << shift; + } else { + regU &= ~ (1 << adev->devno); /* UDMA off */ + cmd64x_set_timing(ap, adev, adev->dma_mode); + } regD |= 0x20 << adev->devno; -- cgit v1.2.3-70-g09d2 From 9f45cbd3f0fc597530aaf85cad7fe52cd63f1fd8 Mon Sep 17 00:00:00 2001 From: Kristen Carlson Accardi Date: Wed, 15 Aug 2007 03:57:11 -0400 Subject: [libata] check for SATA async notify support Check to see if an ATAPI device supports Asynchronous Notification. If so, enable it, if the host controller supports AN. Signed-off-by: Kristen Carlson Accardi Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++ include/linux/ata.h | 9 ++++++++ include/linux/libata.h | 2 ++ 3 files changed, 64 insertions(+) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index c0f3c78a2be..9f87f7ddd48 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -70,6 +70,7 @@ const unsigned long sata_deb_timing_long[] = { 100, 2000, 5000 }; static unsigned int ata_dev_init_params(struct ata_device *dev, u16 heads, u16 sectors); static unsigned int ata_dev_set_xfermode(struct ata_device *dev); +static unsigned int ata_dev_set_AN(struct ata_device *dev, u8 enable); static void ata_dev_xfermask(struct ata_device *dev); static unsigned long ata_dev_blacklisted(const struct ata_device *dev); @@ -1987,6 +1988,22 @@ int ata_dev_configure(struct ata_device *dev) } dev->cdb_len = (unsigned int) rc; + /* + * check to see if this ATAPI device supports + * Asynchronous Notification + */ + if ((ap->flags & ATA_FLAG_AN) && ata_id_has_AN(id)) { + int err; + /* issue SET feature command to turn this on */ + err = ata_dev_set_AN(dev, SETFEATURES_SATA_ENABLE); + if (err) + ata_dev_printk(dev, KERN_ERR, + "unable to set AN, err %x\n", + err); + else + dev->flags |= ATA_DFLAG_AN; + } + if (ata_id_cdb_intr(dev->id)) { dev->flags |= ATA_DFLAG_CDB_INTR; cdb_intr_string = ", CDB intr"; @@ -3974,6 +3991,42 @@ static unsigned int ata_dev_set_xfermode(struct ata_device *dev) return err_mask; } +/** + * ata_dev_set_AN - Issue SET FEATURES - SATA FEATURES + * @dev: Device to which command will be sent + * @enable: Whether to enable or disable the feature + * + * Issue SET FEATURES - SATA FEATURES command to device @dev + * on port @ap with sector count set to indicate Asynchronous + * Notification feature + * + * LOCKING: + * PCI/etc. bus probe sem. + * + * RETURNS: + * 0 on success, AC_ERR_* mask otherwise. + */ +static unsigned int ata_dev_set_AN(struct ata_device *dev, u8 enable) +{ + struct ata_taskfile tf; + unsigned int err_mask; + + /* set up set-features taskfile */ + DPRINTK("set features - SATA features\n"); + + ata_tf_init(dev, &tf); + tf.command = ATA_CMD_SET_FEATURES; + tf.feature = enable; + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf.protocol = ATA_PROT_NODATA; + tf.nsect = SATA_AN; + + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); + + DPRINTK("EXIT, err_mask=%x\n", err_mask); + return err_mask; +} + /** * ata_dev_init_params - Issue INIT DEV PARAMS command * @dev: Device to which command will be sent diff --git a/include/linux/ata.h b/include/linux/ata.h index 40c7af05fdb..fba8e145983 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -230,6 +230,12 @@ enum { SETFEATURES_SPINUP = 0x07, /* Spin-up drive */ + SETFEATURES_SATA_ENABLE = 0x10, /* Enable use of SATA feature */ + SETFEATURES_SATA_DISABLE = 0x90, /* Disable use of SATA feature */ + + /* SETFEATURE Sector counts for SATA features */ + SATA_AN = 0x05, /* Asynchronous Notification */ + /* ATAPI stuff */ ATAPI_PKT_DMA = (1 << 0), ATAPI_DMADIR = (1 << 2), /* ATAPI data dir: @@ -357,6 +363,9 @@ struct ata_taskfile { #define ata_id_queue_depth(id) (((id)[75] & 0x1f) + 1) #define ata_id_removeable(id) ((id)[0] & (1 << 7)) #define ata_id_has_dword_io(id) ((id)[50] & (1 << 0)) +#define ata_id_has_AN(id) \ + ( (((id)[76] != 0x0000) && ((id)[76] != 0xffff)) && \ + ((id)[78] & (1 << 5)) ) #define ata_id_iordy_disable(id) ((id)[49] & (1 << 10)) #define ata_id_has_iordy(id) ((id)[49] & (1 << 11)) #define ata_id_u32(id,n) \ diff --git a/include/linux/libata.h b/include/linux/libata.h index 7a1793bd237..6dd5b437210 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -139,6 +139,7 @@ enum { ATA_DFLAG_FLUSH_EXT = (1 << 4), /* do FLUSH_EXT instead of FLUSH */ ATA_DFLAG_ACPI_PENDING = (1 << 5), /* ACPI resume action pending */ ATA_DFLAG_ACPI_FAILED = (1 << 6), /* ACPI on devcfg has failed */ + ATA_DFLAG_AN = (1 << 7), /* device supports AN */ ATA_DFLAG_CFG_MASK = (1 << 8) - 1, ATA_DFLAG_PIO = (1 << 8), /* device limited to PIO mode */ @@ -179,6 +180,7 @@ enum { ATA_FLAG_IGN_SIMPLEX = (1 << 15), /* ignore SIMPLEX */ ATA_FLAG_NO_IORDY = (1 << 16), /* controller lacks iordy */ ATA_FLAG_ACPI_SATA = (1 << 17), /* need native SATA ACPI layout */ + ATA_FLAG_AN = (1 << 18), /* controller supports AN */ /* The following flag belongs to ap->pflags but is kept in * ap->flags because it's referenced in many LLDs and will be -- cgit v1.2.3-70-g09d2 From 2f2949680ad89d606db838340b17c30216c0bb0f Mon Sep 17 00:00:00 2001 From: Kristen Carlson Accardi Date: Wed, 15 Aug 2007 04:11:25 -0400 Subject: [libata] ahci: send event when AN received When we get an SDB FIS with the 'N' bit set, we should send an event to user space to indicate that there has been a media change. This will be done via the scsi device. Signed-off-by: Kristen Carlson Accardi Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 24 ++++++++++++++++++++++++ drivers/ata/libata-scsi.c | 18 ++++++++++++++++++ include/linux/libata.h | 1 + 3 files changed, 43 insertions(+) (limited to 'drivers') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 483733783cf..d52b73ab795 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1368,6 +1368,30 @@ static void ahci_port_intr(struct ata_port *ap) return; } + if (status & PORT_IRQ_SDB_FIS) { + /* + * if this is an ATAPI device with AN turned on, + * then we should interrogate the device to + * determine the cause of the interrupt + * + * for AN - this we should check the SDB FIS + * and find the I and N bits set + */ + const __le32 *f = pp->rx_fis + RX_FIS_SDB; + u32 f0 = le32_to_cpu(f[0]); + + /* check the 'N' bit in word 0 of the FIS */ + if (f0 & (1 << 15)) { + int port_addr = ((f0 & 0x00000f00) >> 8); + struct ata_device *adev; + if (port_addr < ATA_MAX_DEVICES) { + adev = &ap->link.device[port_addr]; + if (adev->flags & ATA_DFLAG_AN) + ata_scsi_media_change_notify(adev); + } + } + } + if (ap->link.sactive) qc_active = readl(port_mmio + PORT_SCR_ACT); else diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 7d66c986a54..f0f586b56c2 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -3159,6 +3159,24 @@ static void ata_scsi_handle_link_detach(struct ata_link *link) } } +/** + * ata_scsi_media_change_notify - send media change event + * @atadev: Pointer to the disk device with media change event + * + * Tell the block layer to send a media change notification + * event. + * + * LOCKING: + * interrupt context, may not sleep. + */ +void ata_scsi_media_change_notify(struct ata_device *atadev) +{ +#ifdef OTHER_AN_PATCHES_HAVE_BEEN_APPLIED + scsi_device_event_notify(atadev->sdev, SDEV_MEDIA_CHANGE); +#endif +} +EXPORT_SYMBOL_GPL(ata_scsi_media_change_notify); + /** * ata_scsi_hotplug - SCSI part of hotplug * @work: Pointer to ATA port to perform SCSI hotplug on diff --git a/include/linux/libata.h b/include/linux/libata.h index 6dd5b437210..d98e8b50e20 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -755,6 +755,7 @@ extern void ata_host_init(struct ata_host *, struct device *, extern int ata_scsi_detect(struct scsi_host_template *sht); extern int ata_scsi_ioctl(struct scsi_device *dev, int cmd, void __user *arg); extern int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)); +extern void ata_scsi_media_change_notify(struct ata_device *atadev); extern void ata_sas_port_destroy(struct ata_port *); extern struct ata_port *ata_sas_port_alloc(struct ata_host *, struct ata_port_info *, struct Scsi_Host *); -- cgit v1.2.3-70-g09d2 From a738492501eaf6e266acc53a064552b3fcc706b2 Mon Sep 17 00:00:00 2001 From: Kristen Carlson Accardi Date: Thu, 9 Aug 2007 14:23:41 -0700 Subject: ahci: Store interrupt value Use a stored value for which interrupts to enable. Changing this allows us to selectively turn off certain interrupts later and have them stay off. Signed-off-by: Kristen Carlson Accardi Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index d52b73ab795..baf7d056219 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -175,6 +175,7 @@ enum { AHCI_FLAG_32BIT_ONLY = (1 << 28), /* force 32bit */ AHCI_FLAG_MV_PATA = (1 << 29), /* PATA port */ AHCI_FLAG_NO_MSI = (1 << 30), /* no PCI MSI */ + AHCI_FLAG_NO_HOTPLUG = (1 << 31), /* ignore PxSERR.DIAG.N */ AHCI_FLAG_COMMON = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | @@ -215,6 +216,7 @@ struct ahci_port_priv { unsigned int ncq_saw_d2h:1; unsigned int ncq_saw_dmas:1; unsigned int ncq_saw_sdb:1; + u32 intr_mask; /* interrupts to enable */ }; static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val); @@ -1552,6 +1554,7 @@ static void ahci_thaw(struct ata_port *ap) void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; void __iomem *port_mmio = ahci_port_base(ap); u32 tmp; + struct ahci_port_priv *pp = ap->private_data; /* clear IRQ */ tmp = readl(port_mmio + PORT_IRQ_STAT); @@ -1559,7 +1562,7 @@ static void ahci_thaw(struct ata_port *ap) writel(1 << ap->port_no, mmio + HOST_IRQ_STAT); /* turn IRQ back on */ - writel(DEF_PORT_IRQ, port_mmio + PORT_IRQ_MASK); + writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); } static void ahci_error_handler(struct ata_port *ap) @@ -1713,6 +1716,12 @@ static int ahci_port_start(struct ata_port *ap) pp->cmd_tbl = mem; pp->cmd_tbl_dma = mem_dma; + /* + * Save off initial list of interrupts to be enabled. + * This could be changed later + */ + pp->intr_mask = DEF_PORT_IRQ; + ap->private_data = pp; /* engage engines, captain */ -- cgit v1.2.3-70-g09d2 From 2eb829e934abb10db36ddaacd82603c3cdd98b6d Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Fri, 10 Aug 2007 13:59:51 -0700 Subject: ata_piix: disallow UDMA 133 on ICH5 & ICH7 There is another outstanding issue with ata_piix.c. Intel has never officially supported anything faster than PATA 100MB/s. But, the ata_piix.c driver "define" the ICH5 & ICH7 as UDMA6 (aka 133MB/s) capable. [ Well, no one has probably noticed it before, because there is bug in do_pata_set_dmamode... Just look at libata_atapiix_enable_real_udma133.patch and you'll see what wrong with it. ] Here are Intel's datasheets for the affected chipsets: ICH5 Datasheet: http://www.intel.com/design/chipsets/datashts/252516.htm (See note on page 183: "... the ICH5 supports reads at the maximum rate of 100MB/s.") ICH7 Datasheet: http://www.intel.com/design/chipsets/datashts/307013.htm (See first note on page 190: "... the ICH7 supports reads at the maximum rate of 100MB/s.") They are two different ways to deal with it: - Either - 1. replace all ich_pata_133 with ich_pata_100. (libata_atapiix_disable_udma6.diff - diff from 2.6.22 ) - Or - 2. keep all ich_pata_133 and fix the bug in "do_pata_set_dmamode". (libata_atapiix_enable_real_udma133.patch - diff from 2.6.22) If there are any concerns about the safety of the patch patch: http://lkml.org/lkml/2007/7/6/292 (It was already tested by an Intel employee, but I guess a bit more user input is necessary here... ) This patch implements 1. Cc: Alan Cox Cc: Jeff Garzik Cc: Tejun Heo Signed-off-by: Christian Lamparter Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/ata/ata_piix.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 03fe493026e..4b66b9e9638 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -123,7 +123,7 @@ enum { ich_pata_33 = 1, /* ICH up to UDMA 33 only */ ich_pata_66 = 2, /* ICH up to 66 Mhz */ ich_pata_100 = 3, /* ICH up to UDMA 100 */ - ich_pata_133 = 4, /* ICH up to UDMA 133 */ + /* ICH up to UDMA 133 is not supported */ ich5_sata = 5, ich6_sata = 6, ich6_sata_ahci = 7, @@ -199,7 +199,7 @@ static const struct pci_device_id piix_pci_tbl[] = { { 0x8086, 0x24CA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, { 0x8086, 0x24CB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, /* Intel ICH5 */ - { 0x8086, 0x24DB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_133 }, + { 0x8086, 0x24DB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, /* C-ICH (i810E2) */ { 0x8086, 0x245B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, /* ESB (855GME/875P + 6300ESB) UDMA 100 */ @@ -207,7 +207,7 @@ static const struct pci_device_id piix_pci_tbl[] = { /* ICH6 (and 6) (i915) UDMA 100 */ { 0x8086, 0x266F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, /* ICH7/7-R (i945, i975) UDMA 100*/ - { 0x8086, 0x27DF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_133 }, + { 0x8086, 0x27DF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, { 0x8086, 0x269E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, /* ICH8 Mobile PATA Controller */ { 0x8086, 0x2850, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, @@ -505,7 +505,7 @@ static struct ata_port_info piix_port_info[] = { .port_ops = &ich_pata_ops, }, - /* ich_pata_133: 4 ICH with full UDMA6 */ + /* ich_pata_133: 4 - Not supported - */ { .sht = &piix_sht, .flags = PIIX_PATA_FLAGS | PIIX_FLAG_CHECKINTR, -- cgit v1.2.3-70-g09d2 From b8773531cc54c1ed10c8ec301353ee6b53b601a5 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Fri, 10 Aug 2007 13:59:33 -0700 Subject: libata-add-irq_flags-to-struct-pata_platform_info-fix Remove unneeded, undesirable cast of void*. Cc: Jeff Garzik Cc: Sonic Zhang Cc: Tejun Heo Cc: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/ata/pata_platform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c index 37e5158391d..9dc628931e9 100644 --- a/drivers/ata/pata_platform.c +++ b/drivers/ata/pata_platform.c @@ -207,7 +207,7 @@ static int __devinit pata_platform_probe(struct platform_device *pdev) ap->ioaddr.altstatus_addr = ap->ioaddr.ctl_addr; - pp_info = (struct pata_platform_info *)(pdev->dev.platform_data); + pp_info = pdev->dev.platform_data; pata_platform_setup_port(&ap->ioaddr, pp_info); /* activate */ -- cgit v1.2.3-70-g09d2 From 6d32d30f55020d766388df7515f771f68c973033 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 15 Aug 2007 05:38:46 -0400 Subject: [libata] Remove ->irq_ack() hook, and ata_dummy_irq_on() * ->irq_ack() is redundant to what the irq handler already performs... chk-status + irq-clear. Furthermore, it is only called in one place, when screaming-irq-debugging is enabled, so we don't want to bother with a hook just for that. * ata_dummy_irq_on() is only ever used in drivers that have no callpath reaching ->irq_on(). Remove .irq_on hook from those drivers, and the now-unused ata_dummy_irq_on() Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 4 ---- drivers/ata/ata_generic.c | 1 - drivers/ata/ata_piix.c | 3 --- drivers/ata/libata-core.c | 6 ++---- drivers/ata/libata-sff.c | 40 ---------------------------------------- drivers/ata/pata_ali.c | 4 ---- drivers/ata/pata_amd.c | 6 ------ drivers/ata/pata_artop.c | 2 -- drivers/ata/pata_atiixp.c | 1 - drivers/ata/pata_cmd640.c | 1 - drivers/ata/pata_cmd64x.c | 3 --- drivers/ata/pata_cs5520.c | 1 - drivers/ata/pata_cs5530.c | 1 - drivers/ata/pata_cs5535.c | 1 - drivers/ata/pata_cypress.c | 1 - drivers/ata/pata_efar.c | 1 - drivers/ata/pata_hpt366.c | 1 - drivers/ata/pata_hpt37x.c | 4 ---- drivers/ata/pata_hpt3x2n.c | 1 - drivers/ata/pata_hpt3x3.c | 1 - drivers/ata/pata_icside.c | 18 ------------------ drivers/ata/pata_isapnp.c | 1 - drivers/ata/pata_it8213.c | 1 - drivers/ata/pata_it821x.c | 2 -- drivers/ata/pata_ixp4xx_cf.c | 1 - drivers/ata/pata_jmicron.c | 1 - drivers/ata/pata_legacy.c | 7 ------- drivers/ata/pata_marvell.c | 1 - drivers/ata/pata_mpc52xx.c | 1 - drivers/ata/pata_mpiix.c | 1 - drivers/ata/pata_netcell.c | 1 - drivers/ata/pata_ns87410.c | 1 - drivers/ata/pata_oldpiix.c | 1 - drivers/ata/pata_opti.c | 1 - drivers/ata/pata_optidma.c | 2 -- drivers/ata/pata_pcmcia.c | 1 - drivers/ata/pata_pdc2027x.c | 2 -- drivers/ata/pata_pdc202xx_old.c | 2 -- drivers/ata/pata_platform.c | 1 - drivers/ata/pata_qdi.c | 2 -- drivers/ata/pata_radisys.c | 1 - drivers/ata/pata_rz1000.c | 1 - drivers/ata/pata_sc1200.c | 1 - drivers/ata/pata_scc.c | 33 --------------------------------- drivers/ata/pata_serverworks.c | 2 -- drivers/ata/pata_sil680.c | 1 - drivers/ata/pata_sis.c | 6 ------ drivers/ata/pata_sl82c105.c | 1 - drivers/ata/pata_triflex.c | 1 - drivers/ata/pata_via.c | 2 -- drivers/ata/pata_winbond.c | 1 - drivers/ata/pdc_adma.c | 1 - drivers/ata/sata_inic162x.c | 1 - drivers/ata/sata_mv.c | 3 --- drivers/ata/sata_nv.c | 4 ---- drivers/ata/sata_promise.c | 3 --- drivers/ata/sata_qstor.c | 1 - drivers/ata/sata_sil.c | 1 - drivers/ata/sata_sil24.c | 2 -- drivers/ata/sata_sis.c | 1 - drivers/ata/sata_svw.c | 1 - drivers/ata/sata_sx4.c | 1 - drivers/ata/sata_uli.c | 1 - drivers/ata/sata_via.c | 3 --- drivers/ata/sata_vsc.c | 1 - include/linux/libata.h | 4 ---- 66 files changed, 2 insertions(+), 207 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index baf7d056219..c888c966a02 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -276,8 +276,6 @@ static const struct ata_port_operations ahci_ops = { .qc_issue = ahci_qc_issue, .irq_clear = ahci_irq_clear, - .irq_on = ata_dummy_irq_on, - .irq_ack = ata_dummy_irq_ack, .scr_read = ahci_scr_read, .scr_write = ahci_scr_write, @@ -310,8 +308,6 @@ static const struct ata_port_operations ahci_vt8251_ops = { .qc_issue = ahci_qc_issue, .irq_clear = ahci_irq_clear, - .irq_on = ata_dummy_irq_on, - .irq_ack = ata_dummy_irq_ack, .scr_read = ahci_scr_read, .scr_write = ahci_scr_write, diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c index e390ad47c8e..6ec1bbc4fcc 100644 --- a/drivers/ata/ata_generic.c +++ b/drivers/ata/ata_generic.c @@ -121,7 +121,6 @@ static struct ata_port_operations generic_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 4b66b9e9638..68bc0ae671c 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -318,7 +318,6 @@ static const struct ata_port_operations piix_pata_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -352,7 +351,6 @@ static const struct ata_port_operations ich_pata_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -382,7 +380,6 @@ static const struct ata_port_operations piix_sata_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 9f87f7ddd48..4f8b8d210cf 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -5747,7 +5747,8 @@ idle_irq: #ifdef ATA_IRQ_TRAP if ((ap->stats.idle_irq % 1000) == 0) { - ap->ops->irq_ack(ap, 0); /* debug trap */ + ata_chk_status(ap); + ap->ops->irq_clear(ap); ata_port_printk(ap, KERN_WARNING, "irq trap\n"); return 1; } @@ -7137,9 +7138,6 @@ EXPORT_SYMBOL_GPL(ata_eh_qc_complete); EXPORT_SYMBOL_GPL(ata_eh_qc_retry); EXPORT_SYMBOL_GPL(ata_do_eh); EXPORT_SYMBOL_GPL(ata_irq_on); -EXPORT_SYMBOL_GPL(ata_dummy_irq_on); -EXPORT_SYMBOL_GPL(ata_irq_ack); -EXPORT_SYMBOL_GPL(ata_dummy_irq_ack); EXPORT_SYMBOL_GPL(ata_dev_try_classify); EXPORT_SYMBOL_GPL(ata_cable_40wire); diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index dd528dbd9cc..ccef99a0337 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -64,46 +64,6 @@ u8 ata_irq_on(struct ata_port *ap) return tmp; } -u8 ata_dummy_irq_on (struct ata_port *ap) { return 0; } - -/** - * ata_irq_ack - Acknowledge a device interrupt. - * @ap: Port on which interrupts are enabled. - * - * Wait up to 10 ms for legacy IDE device to become idle (BUSY - * or BUSY+DRQ clear). Obtain dma status and port status from - * device. Clear the interrupt. Return port status. - * - * LOCKING: - */ - -u8 ata_irq_ack(struct ata_port *ap, unsigned int chk_drq) -{ - unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY; - u8 host_stat = 0, post_stat = 0, status; - - status = ata_busy_wait(ap, bits, 1000); - if (status & bits) - if (ata_msg_err(ap)) - printk(KERN_ERR "abnormal status 0x%X\n", status); - - if (ap->ioaddr.bmdma_addr) { - /* get controller status; clear intr, err bits */ - host_stat = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); - iowrite8(host_stat | ATA_DMA_INTR | ATA_DMA_ERR, - ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); - - post_stat = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); - } - if (ata_msg_intr(ap)) - printk(KERN_INFO "%s: irq ack: host_stat 0x%X, new host_stat 0x%X, drv_stat 0x%X\n", - __FUNCTION__, - host_stat, post_stat, status); - return status; -} - -u8 ata_dummy_irq_ack(struct ata_port *ap, unsigned int chk_drq) { return 0; } - /** * ata_tf_load - send taskfile registers to host controller * @ap: Port to which output is sent diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c index 32a10c99c06..9436c496392 100644 --- a/drivers/ata/pata_ali.c +++ b/drivers/ata/pata_ali.c @@ -327,7 +327,6 @@ static struct ata_port_operations ali_early_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -369,7 +368,6 @@ static struct ata_port_operations ali_20_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -408,7 +406,6 @@ static struct ata_port_operations ali_c2_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -446,7 +443,6 @@ static struct ata_port_operations ali_c5_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c index d0cebe16a8e..46f829c838b 100644 --- a/drivers/ata/pata_amd.c +++ b/drivers/ata/pata_amd.c @@ -358,7 +358,6 @@ static struct ata_port_operations amd33_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -393,7 +392,6 @@ static struct ata_port_operations amd66_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -428,7 +426,6 @@ static struct ata_port_operations amd100_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -463,7 +460,6 @@ static struct ata_port_operations amd133_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -498,7 +494,6 @@ static struct ata_port_operations nv100_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -533,7 +528,6 @@ static struct ata_port_operations nv133_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_artop.c b/drivers/ata/pata_artop.c index 361f2fca7e5..8c864353596 100644 --- a/drivers/ata/pata_artop.c +++ b/drivers/ata/pata_artop.c @@ -361,7 +361,6 @@ static const struct ata_port_operations artop6210_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -394,7 +393,6 @@ static const struct ata_port_operations artop6260_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c index 656f4d0a572..f2bfdeb4402 100644 --- a/drivers/ata/pata_atiixp.c +++ b/drivers/ata/pata_atiixp.c @@ -262,7 +262,6 @@ static struct ata_port_operations atiixp_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_cmd640.c b/drivers/ata/pata_cmd640.c index 0feb5ae8c48..a292ed97246 100644 --- a/drivers/ata/pata_cmd640.c +++ b/drivers/ata/pata_cmd640.c @@ -213,7 +213,6 @@ static struct ata_port_operations cmd640_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = cmd640_port_start, }; diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c index 922902a1b4a..d308c464464 100644 --- a/drivers/ata/pata_cmd64x.c +++ b/drivers/ata/pata_cmd64x.c @@ -313,7 +313,6 @@ static struct ata_port_operations cmd64x_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -348,7 +347,6 @@ static struct ata_port_operations cmd646r1_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -383,7 +381,6 @@ static struct ata_port_operations cmd648_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c index e2459088cdc..300dcff949e 100644 --- a/drivers/ata/pata_cs5520.c +++ b/drivers/ata/pata_cs5520.c @@ -184,7 +184,6 @@ static struct ata_port_operations cs5520_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c index eaaea848b64..2b770072f39 100644 --- a/drivers/ata/pata_cs5530.c +++ b/drivers/ata/pata_cs5530.c @@ -209,7 +209,6 @@ static struct ata_port_operations cs5530_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_cs5535.c b/drivers/ata/pata_cs5535.c index 360b6f32e17..94b1a9caf3c 100644 --- a/drivers/ata/pata_cs5535.c +++ b/drivers/ata/pata_cs5535.c @@ -206,7 +206,6 @@ static struct ata_port_operations cs5535_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_cypress.c b/drivers/ata/pata_cypress.c index 6cbc8778bf4..8c439a9bb5d 100644 --- a/drivers/ata/pata_cypress.c +++ b/drivers/ata/pata_cypress.c @@ -158,7 +158,6 @@ static struct ata_port_operations cy82c693_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_efar.c b/drivers/ata/pata_efar.c index 9f6fae6e38b..4d646ffb257 100644 --- a/drivers/ata/pata_efar.c +++ b/drivers/ata/pata_efar.c @@ -279,7 +279,6 @@ static const struct ata_port_operations efar_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c index 6f7d34ad19e..508d1cab52d 100644 --- a/drivers/ata/pata_hpt366.c +++ b/drivers/ata/pata_hpt366.c @@ -342,7 +342,6 @@ static struct ata_port_operations hpt366_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c index 1a4d0ad68d1..896e6e31c67 100644 --- a/drivers/ata/pata_hpt37x.c +++ b/drivers/ata/pata_hpt37x.c @@ -673,7 +673,6 @@ static struct ata_port_operations hpt370_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -712,7 +711,6 @@ static struct ata_port_operations hpt370a_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -752,7 +750,6 @@ static struct ata_port_operations hpt372_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -792,7 +789,6 @@ static struct ata_port_operations hpt374_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c index 739a89180eb..2b7f099ac78 100644 --- a/drivers/ata/pata_hpt3x2n.c +++ b/drivers/ata/pata_hpt3x2n.c @@ -391,7 +391,6 @@ static struct ata_port_operations hpt3x2n_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_hpt3x3.c b/drivers/ata/pata_hpt3x3.c index be0f05efac6..a2f81f40d7a 100644 --- a/drivers/ata/pata_hpt3x3.c +++ b/drivers/ata/pata_hpt3x3.c @@ -153,7 +153,6 @@ static struct ata_port_operations hpt3x3_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_icside.c b/drivers/ata/pata_icside.c index 64a711776c4..ffcccfc0b9d 100644 --- a/drivers/ata/pata_icside.c +++ b/drivers/ata/pata_icside.c @@ -357,23 +357,6 @@ static void pata_icside_error_handler(struct ata_port *ap) pata_icside_postreset); } -static u8 pata_icside_irq_ack(struct ata_port *ap, unsigned int chk_drq) -{ - unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY; - u8 status; - - status = ata_busy_wait(ap, bits, 1000); - if (status & bits) - if (ata_msg_err(ap)) - printk(KERN_ERR "abnormal status 0x%X\n", status); - - if (ata_msg_intr(ap)) - printk(KERN_INFO "%s: irq ack: drv_stat 0x%X\n", - __FUNCTION__, status); - - return status; -} - static struct ata_port_operations pata_icside_port_ops = { .port_disable = ata_port_disable, @@ -403,7 +386,6 @@ static struct ata_port_operations pata_icside_port_ops = { .irq_clear = ata_dummy_noret, .irq_on = ata_irq_on, - .irq_ack = pata_icside_irq_ack, .port_start = pata_icside_port_start, diff --git a/drivers/ata/pata_isapnp.c b/drivers/ata/pata_isapnp.c index 9e553c54203..b8d6d5c4353 100644 --- a/drivers/ata/pata_isapnp.c +++ b/drivers/ata/pata_isapnp.c @@ -58,7 +58,6 @@ static struct ata_port_operations isapnp_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_it8213.c b/drivers/ata/pata_it8213.c index 1daf1e19bdf..8aae9d7171c 100644 --- a/drivers/ata/pata_it8213.c +++ b/drivers/ata/pata_it8213.c @@ -289,7 +289,6 @@ static const struct ata_port_operations it8213_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c index f32d9b7ab49..0179b29c515 100644 --- a/drivers/ata/pata_it821x.c +++ b/drivers/ata/pata_it821x.c @@ -650,7 +650,6 @@ static struct ata_port_operations it821x_smart_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = it821x_port_start, }; @@ -687,7 +686,6 @@ static struct ata_port_operations it821x_passthru_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_handler = ata_interrupt, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = it821x_port_start, }; diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c index 6bf1709508a..ce1f9b17ad3 100644 --- a/drivers/ata/pata_ixp4xx_cf.c +++ b/drivers/ata/pata_ixp4xx_cf.c @@ -127,7 +127,6 @@ static struct ata_port_operations ixp4xx_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_dummy_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c index 1619b86b74a..26f84063859 100644 --- a/drivers/ata/pata_jmicron.c +++ b/drivers/ata/pata_jmicron.c @@ -168,7 +168,6 @@ static const struct ata_port_operations jmicron_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, /* Generic PATA PCI ATA helpers */ .port_start = ata_port_start, diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c index cfb2bc86a1d..6529d34f037 100644 --- a/drivers/ata/pata_legacy.c +++ b/drivers/ata/pata_legacy.c @@ -171,7 +171,6 @@ static struct ata_port_operations simple_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -200,7 +199,6 @@ static struct ata_port_operations legacy_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -316,7 +314,6 @@ static struct ata_port_operations pdc20230_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -372,7 +369,6 @@ static struct ata_port_operations ht6560a_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -439,7 +435,6 @@ static struct ata_port_operations ht6560b_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -561,7 +556,6 @@ static struct ata_port_operations opti82c611a_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -695,7 +689,6 @@ static struct ata_port_operations opti82c46x_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c index b4dd18f3fa5..021d9d9218b 100644 --- a/drivers/ata/pata_marvell.c +++ b/drivers/ata/pata_marvell.c @@ -139,7 +139,6 @@ static const struct ata_port_operations marvell_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, /* Generic PATA PCI ATA helpers */ .port_start = ata_port_start, diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c index 099f4cdc4cd..6e3fac2fedc 100644 --- a/drivers/ata/pata_mpc52xx.c +++ b/drivers/ata/pata_mpc52xx.c @@ -299,7 +299,6 @@ static struct ata_port_operations mpc52xx_ata_port_ops = { .data_xfer = ata_data_xfer, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c index 36c964b9e7d..8a82fcd4fa3 100644 --- a/drivers/ata/pata_mpiix.c +++ b/drivers/ata/pata_mpiix.c @@ -190,7 +190,6 @@ static struct ata_port_operations mpiix_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_netcell.c b/drivers/ata/pata_netcell.c index 40eb574828b..2d64c58482f 100644 --- a/drivers/ata/pata_netcell.c +++ b/drivers/ata/pata_netcell.c @@ -68,7 +68,6 @@ static const struct ata_port_operations netcell_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, /* Generic PATA PCI ATA helpers */ .port_start = ata_port_start, diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c index 65a21772771..00a763c67f9 100644 --- a/drivers/ata/pata_ns87410.c +++ b/drivers/ata/pata_ns87410.c @@ -185,7 +185,6 @@ static struct ata_port_operations ns87410_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_oldpiix.c b/drivers/ata/pata_oldpiix.c index 5b2c86fe9fc..851dae96001 100644 --- a/drivers/ata/pata_oldpiix.c +++ b/drivers/ata/pata_oldpiix.c @@ -266,7 +266,6 @@ static const struct ata_port_operations oldpiix_pata_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_opti.c b/drivers/ata/pata_opti.c index 5770c7755a6..0ab300cda9b 100644 --- a/drivers/ata/pata_opti.c +++ b/drivers/ata/pata_opti.c @@ -210,7 +210,6 @@ static struct ata_port_operations opti_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c index 09ef725afd9..51c49283fb3 100644 --- a/drivers/ata/pata_optidma.c +++ b/drivers/ata/pata_optidma.c @@ -398,7 +398,6 @@ static struct ata_port_operations optidma_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -434,7 +433,6 @@ static struct ata_port_operations optiplus_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c index 9bfe12ac851..f2167729c3d 100644 --- a/drivers/ata/pata_pcmcia.c +++ b/drivers/ata/pata_pcmcia.c @@ -127,7 +127,6 @@ static struct ata_port_operations pcmcia_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_sff_port_start, }; diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c index db069d7515b..7c6df320c83 100644 --- a/drivers/ata/pata_pdc2027x.c +++ b/drivers/ata/pata_pdc2027x.c @@ -173,7 +173,6 @@ static struct ata_port_operations pdc2027x_pata100_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -208,7 +207,6 @@ static struct ata_port_operations pdc2027x_pata133_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c index 92447bed5e7..b03b3387245 100644 --- a/drivers/ata/pata_pdc202xx_old.c +++ b/drivers/ata/pata_pdc202xx_old.c @@ -275,7 +275,6 @@ static struct ata_port_operations pdc2024x_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -310,7 +309,6 @@ static struct ata_port_operations pdc2026x_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c index 9dc628931e9..a616616706d 100644 --- a/drivers/ata/pata_platform.c +++ b/drivers/ata/pata_platform.c @@ -89,7 +89,6 @@ static struct ata_port_operations pata_platform_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_dummy_ret0, }; diff --git a/drivers/ata/pata_qdi.c b/drivers/ata/pata_qdi.c index ec2206e820a..ade5a442166 100644 --- a/drivers/ata/pata_qdi.c +++ b/drivers/ata/pata_qdi.c @@ -192,7 +192,6 @@ static struct ata_port_operations qdi6500_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -220,7 +219,6 @@ static struct ata_port_operations qdi6580_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_radisys.c b/drivers/ata/pata_radisys.c index 7d1aabed422..66b9a341931 100644 --- a/drivers/ata/pata_radisys.c +++ b/drivers/ata/pata_radisys.c @@ -231,7 +231,6 @@ static const struct ata_port_operations radisys_pata_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c index de3698cf3b8..98784647c7e 100644 --- a/drivers/ata/pata_rz1000.c +++ b/drivers/ata/pata_rz1000.c @@ -99,7 +99,6 @@ static struct ata_port_operations rz1000_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_sc1200.c b/drivers/ata/pata_sc1200.c index 5edf67b1f3b..61edff4a5c6 100644 --- a/drivers/ata/pata_sc1200.c +++ b/drivers/ata/pata_sc1200.c @@ -227,7 +227,6 @@ static struct ata_port_operations sc1200_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c index 63fe99a10cd..95f04b81352 100644 --- a/drivers/ata/pata_scc.c +++ b/drivers/ata/pata_scc.c @@ -838,38 +838,6 @@ static u8 scc_irq_on (struct ata_port *ap) return tmp; } -/** - * scc_irq_ack - Acknowledge a device interrupt. - * @ap: Port on which interrupts are enabled. - * - * Note: Original code is ata_irq_ack(). - */ - -static u8 scc_irq_ack (struct ata_port *ap, unsigned int chk_drq) -{ - unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY; - u8 host_stat, post_stat, status; - - status = ata_busy_wait(ap, bits, 1000); - if (status & bits) - if (ata_msg_err(ap)) - printk(KERN_ERR "abnormal status 0x%X\n", status); - - /* get controller status; clear intr, err bits */ - host_stat = in_be32(ap->ioaddr.bmdma_addr + SCC_DMA_STATUS); - out_be32(ap->ioaddr.bmdma_addr + SCC_DMA_STATUS, - host_stat | ATA_DMA_INTR | ATA_DMA_ERR); - - post_stat = in_be32(ap->ioaddr.bmdma_addr + SCC_DMA_STATUS); - - if (ata_msg_intr(ap)) - printk(KERN_INFO "%s: irq ack: host_stat 0x%X, new host_stat 0x%X, drv_stat 0x%X\n", - __FUNCTION__, - host_stat, post_stat, status); - - return status; -} - /** * scc_bmdma_freeze - Freeze BMDMA controller port * @ap: port to freeze @@ -1047,7 +1015,6 @@ static const struct ata_port_operations scc_pata_ops = { .irq_clear = scc_bmdma_irq_clear, .irq_on = scc_irq_on, - .irq_ack = scc_irq_ack, .port_start = scc_port_start, .port_stop = scc_port_stop, diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c index 0faf99c8f13..c87cd67f415 100644 --- a/drivers/ata/pata_serverworks.c +++ b/drivers/ata/pata_serverworks.c @@ -348,7 +348,6 @@ static struct ata_port_operations serverworks_osb4_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -384,7 +383,6 @@ static struct ata_port_operations serverworks_csb_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c index 45515a22d85..c5abf661654 100644 --- a/drivers/ata/pata_sil680.c +++ b/drivers/ata/pata_sil680.c @@ -267,7 +267,6 @@ static struct ata_port_operations sil680_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c index b72227676f0..72850667d37 100644 --- a/drivers/ata/pata_sis.c +++ b/drivers/ata/pata_sis.c @@ -559,7 +559,6 @@ static const struct ata_port_operations sis_133_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -593,7 +592,6 @@ static const struct ata_port_operations sis_133_for_sata_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -627,7 +625,6 @@ static const struct ata_port_operations sis_133_early_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -661,7 +658,6 @@ static const struct ata_port_operations sis_100_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -695,7 +691,6 @@ static const struct ata_port_operations sis_66_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -729,7 +724,6 @@ static const struct ata_port_operations sis_old_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c index 375c3705dc4..1c50c191e4b 100644 --- a/drivers/ata/pata_sl82c105.c +++ b/drivers/ata/pata_sl82c105.c @@ -254,7 +254,6 @@ static struct ata_port_operations sl82c105_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c index bc4b6f6be96..2a55eed45ad 100644 --- a/drivers/ata/pata_triflex.c +++ b/drivers/ata/pata_triflex.c @@ -227,7 +227,6 @@ static struct ata_port_operations triflex_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index b612808a319..4ddcae8b8c9 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -375,7 +375,6 @@ static struct ata_port_operations via_port_ops = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -411,7 +410,6 @@ static struct ata_port_operations via_port_ops_noirq = { .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pata_winbond.c b/drivers/ata/pata_winbond.c index c3757033007..c1647da5554 100644 --- a/drivers/ata/pata_winbond.c +++ b/drivers/ata/pata_winbond.c @@ -160,7 +160,6 @@ static struct ata_port_operations winbond_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c index 304c19b9b0f..7dd7361289c 100644 --- a/drivers/ata/pdc_adma.c +++ b/drivers/ata/pdc_adma.c @@ -177,7 +177,6 @@ static const struct ata_port_operations adma_ata_ops = { .error_handler = adma_error_handler, .irq_clear = adma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = adma_port_start, .port_stop = adma_port_stop, .host_stop = adma_host_stop, diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c index 95caba0f910..d6a3e286c79 100644 --- a/drivers/ata/sata_inic162x.c +++ b/drivers/ata/sata_inic162x.c @@ -569,7 +569,6 @@ static struct ata_port_operations inic_port_ops = { .irq_clear = inic_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .qc_prep = ata_qc_prep, .qc_issue = inic_qc_issue, diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 56784ce1054..393fc655f8c 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -499,7 +499,6 @@ static const struct ata_port_operations mv5_ops = { .irq_clear = mv_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .error_handler = mv_error_handler, .post_internal_cmd = mv_post_int_cmd, @@ -530,7 +529,6 @@ static const struct ata_port_operations mv6_ops = { .irq_clear = mv_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .error_handler = mv_error_handler, .post_internal_cmd = mv_post_int_cmd, @@ -561,7 +559,6 @@ static const struct ata_port_operations mv_iie_ops = { .irq_clear = mv_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .error_handler = mv_error_handler, .post_internal_cmd = mv_post_int_cmd, diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index 884d9f05e6c..88ecca6343e 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -359,7 +359,6 @@ static const struct ata_port_operations nv_generic_ops = { .data_xfer = ata_data_xfer, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .scr_read = nv_scr_read, .scr_write = nv_scr_write, .port_start = ata_port_start, @@ -385,7 +384,6 @@ static const struct ata_port_operations nv_nf2_ops = { .data_xfer = ata_data_xfer, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .scr_read = nv_scr_read, .scr_write = nv_scr_write, .port_start = ata_port_start, @@ -411,7 +409,6 @@ static const struct ata_port_operations nv_ck804_ops = { .data_xfer = ata_data_xfer, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .scr_read = nv_scr_read, .scr_write = nv_scr_write, .port_start = ata_port_start, @@ -439,7 +436,6 @@ static const struct ata_port_operations nv_adma_ops = { .data_xfer = ata_data_xfer, .irq_clear = nv_adma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .scr_read = nv_scr_read, .scr_write = nv_scr_write, .port_start = nv_adma_port_start, diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c index c7238ce8354..37d737b442b 100644 --- a/drivers/ata/sata_promise.c +++ b/drivers/ata/sata_promise.c @@ -185,7 +185,6 @@ static const struct ata_port_operations pdc_sata_ops = { .data_xfer = ata_data_xfer, .irq_clear = pdc_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .scr_read = pdc_sata_scr_read, .scr_write = pdc_sata_scr_write, @@ -212,7 +211,6 @@ static const struct ata_port_operations pdc_old_sata_ops = { .data_xfer = ata_data_xfer, .irq_clear = pdc_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .scr_read = pdc_sata_scr_read, .scr_write = pdc_sata_scr_write, @@ -238,7 +236,6 @@ static const struct ata_port_operations pdc_pata_ops = { .data_xfer = ata_data_xfer, .irq_clear = pdc_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = pdc_common_port_start, }; diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c index ef1ad69c26e..5a60ab72ecb 100644 --- a/drivers/ata/sata_qstor.c +++ b/drivers/ata/sata_qstor.c @@ -159,7 +159,6 @@ static const struct ata_port_operations qs_ata_ops = { .eng_timeout = qs_eng_timeout, .irq_clear = qs_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .scr_read = qs_scr_read, .scr_write = qs_scr_write, .port_start = qs_port_start, diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index 802d679dc99..1930e7cf143 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -207,7 +207,6 @@ static const struct ata_port_operations sil_ops = { .post_internal_cmd = ata_bmdma_post_internal_cmd, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .scr_read = sil_scr_read, .scr_write = sil_scr_write, .port_start = ata_port_start, diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index e2cccc7f435..961b3f201a3 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -398,8 +398,6 @@ static const struct ata_port_operations sil24_ops = { .qc_issue = sil24_qc_issue, .irq_clear = sil24_irq_clear, - .irq_on = ata_dummy_irq_on, - .irq_ack = ata_dummy_irq_ack, .scr_read = sil24_scr_read, .scr_write = sil24_scr_write, diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c index 41c1d6e8f1f..691017eddbb 100644 --- a/drivers/ata/sata_sis.c +++ b/drivers/ata/sata_sis.c @@ -123,7 +123,6 @@ static const struct ata_port_operations sis_ops = { .post_internal_cmd = ata_bmdma_post_internal_cmd, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .scr_read = sis_scr_read, .scr_write = sis_scr_write, .port_start = ata_port_start, diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c index d9678e7bc3a..006a720da40 100644 --- a/drivers/ata/sata_svw.c +++ b/drivers/ata/sata_svw.c @@ -349,7 +349,6 @@ static const struct ata_port_operations k2_sata_ops = { .post_internal_cmd = ata_bmdma_post_internal_cmd, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .scr_read = k2_sata_scr_read, .scr_write = k2_sata_scr_write, .port_start = ata_port_start, diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c index 12691f09193..d5cbd16629a 100644 --- a/drivers/ata/sata_sx4.c +++ b/drivers/ata/sata_sx4.c @@ -267,7 +267,6 @@ static const struct ata_port_operations pdc_20621_ops = { .eng_timeout = pdc_eng_timeout, .irq_clear = pdc20621_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = pdc_port_start, }; diff --git a/drivers/ata/sata_uli.c b/drivers/ata/sata_uli.c index e6b8b45279a..d4514e2149b 100644 --- a/drivers/ata/sata_uli.c +++ b/drivers/ata/sata_uli.c @@ -117,7 +117,6 @@ static const struct ata_port_operations uli_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .scr_read = uli_scr_read, .scr_write = uli_scr_write, diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index 690280660b8..4b25c3ef986 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c @@ -146,7 +146,6 @@ static const struct ata_port_operations vt6420_sata_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -180,7 +179,6 @@ static const struct ata_port_operations vt6421_pata_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .port_start = ata_port_start, }; @@ -211,7 +209,6 @@ static const struct ata_port_operations vt6421_sata_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .scr_read = svia_scr_read, .scr_write = svia_scr_write, diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c index 9586b8b51ce..55fb2e0b369 100644 --- a/drivers/ata/sata_vsc.c +++ b/drivers/ata/sata_vsc.c @@ -336,7 +336,6 @@ static const struct ata_port_operations vsc_sata_ops = { .post_internal_cmd = ata_bmdma_post_internal_cmd, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .irq_ack = ata_irq_ack, .scr_read = vsc_sata_scr_read, .scr_write = vsc_sata_scr_write, .port_start = ata_port_start, diff --git a/include/linux/libata.h b/include/linux/libata.h index b89d191ceb2..9295cd541ff 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -644,7 +644,6 @@ struct ata_port_operations { irq_handler_t irq_handler; void (*irq_clear) (struct ata_port *); u8 (*irq_on) (struct ata_port *); - u8 (*irq_ack) (struct ata_port *ap, unsigned int chk_drq); int (*scr_read) (struct ata_port *ap, unsigned int sc_reg, u32 *val); int (*scr_write) (struct ata_port *ap, unsigned int sc_reg, u32 val); @@ -852,9 +851,6 @@ extern int ata_scsi_change_queue_depth(struct scsi_device *sdev, extern struct ata_device *ata_dev_pair(struct ata_device *adev); extern int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev); extern u8 ata_irq_on(struct ata_port *ap); -extern u8 ata_dummy_irq_on(struct ata_port *ap); -extern u8 ata_irq_ack(struct ata_port *ap, unsigned int chk_drq); -extern u8 ata_dummy_irq_ack(struct ata_port *ap, unsigned int chk_drq); extern int ata_cable_40wire(struct ata_port *ap); extern int ata_cable_80wire(struct ata_port *ap); -- cgit v1.2.3-70-g09d2 From e1ddb4b6a2c9b2c72991eb8640ef2f50691ac502 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Thu, 16 Aug 2007 02:33:36 -0400 Subject: [libata] add ACPI cable detect API Combined from two Alan Cox patches: 1) libata: ACPI checks for 80wire cable We can use the ACPI mode information with several drivers as a hint to cable type. If the ACPI mode set by the BIOS is faster than UDMA33 then we know the BIOS thinks there are 80wire cables. If it doesn't set such a mode or it has no ACPI method then we get no further information and can rely on existing approaches Introduce the function headers needed. Null it out for non ACPI boxes Signed-off-by: Alan Cox 2) libata: ACPI checks for 80wire cable Provide actual methods for checking if the ACPI support thinks the cable is 80wire, or doesn't know Signed-off-by: Alan Cox Combined into a single changeset and Signed-off-by: Jeff Garzik --- drivers/ata/libata-acpi.c | 38 ++++++++++++++++++++++++++++++++++++++ include/linux/libata.h | 6 ++++++ 2 files changed, 44 insertions(+) (limited to 'drivers') diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index 43af2e06d44..dc9842ec6f0 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -296,6 +296,44 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf, return rc; } +/** + * ata_acpi_cbl_80wire - Check for 80 wire cable + * @ap: Port to check + * + * Return 1 if the ACPI mode data for this port indicates the BIOS selected + * an 80wire mode. + */ + +int ata_acpi_cbl_80wire(struct ata_port *ap) +{ + struct ata_acpi_gtm gtm; + int valid = 0; + + /* No _GTM data, no information */ + if (ata_acpi_gtm(ap, >m) < 0) + return 0; + + /* Split timing, DMA enabled */ + if ((gtm.flags & 0x11) == 0x11 && gtm.drive[0].dma < 55) + valid |= 1; + if ((gtm.flags & 0x14) == 0x14 && gtm.drive[1].dma < 55) + valid |= 2; + /* Shared timing, DMA enabled */ + if ((gtm.flags & 0x11) == 0x01 && gtm.drive[0].dma < 55) + valid |= 1; + if ((gtm.flags & 0x14) == 0x04 && gtm.drive[0].dma < 55) + valid |= 2; + + /* Drive check */ + if ((valid & 1) && ata_dev_enabled(&ap->link.device[0])) + return 1; + if ((valid & 2) && ata_dev_enabled(&ap->link.device[1])) + return 1; + return 0; +} + +EXPORT_SYMBOL_GPL(ata_acpi_cbl_80wire); + /** * taskfile_load_raw - send taskfile registers to host controller * @dev: target ATA device diff --git a/include/linux/libata.h b/include/linux/libata.h index 9295cd541ff..382898ef654 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -885,6 +885,12 @@ enum { ATA_TIMING_CYCLE | ATA_TIMING_UDMA, }; +/* libata-acpi.c */ +#ifdef CONFIG_ATA_ACPI +extern int ata_acpi_cbl_80wire(struct ata_port *ap); +#else +static inline int ata_acpi_cbl_80wire(struct ata_port *ap) { return 0; } +#endif #ifdef CONFIG_PCI struct pci_bits { -- cgit v1.2.3-70-g09d2 From e708eb9bc0515f36d77477877e74b6b9056b5879 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Thu, 26 Jul 2007 18:37:28 +0100 Subject: libata pata_amd: ACPI checks for 80wire cable We can make use of this on the pata_amd driver as many Nvidia devices don't have reliable cable detect. Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/pata_amd.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c index 46f829c838b..c95922f8cc5 100644 --- a/drivers/ata/pata_amd.c +++ b/drivers/ata/pata_amd.c @@ -270,6 +270,9 @@ static int nv_cable_detect(struct ata_port *ap) pci_read_config_word(pdev, 0x62 - 2 * ap->port_no, &udma); if ((udma & 0xC4) == 0xC4 || (udma & 0xC400) == 0xC400) cbl = ATA_CBL_PATA80; + /* And a triple check across suspend/resume with ACPI around */ + if (ata_acpi_cbl_80wire(ap)) + cbl = ATA_CBL_PATA80; return cbl; } -- cgit v1.2.3-70-g09d2 From 7d73a363dea186a864f6295bbe842da8044d42cd Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Thu, 26 Jul 2007 18:38:06 +0100 Subject: libata pata_via: ACPI checks for 80wire cable Testing this on the VIA boards fixes several problems with otherwise undetectable SATA bridge chips Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/pata_via.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index 4ddcae8b8c9..f11b87e18aa 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -184,6 +184,9 @@ static int via_cable_detect(struct ata_port *ap) { two drives */ if (ata66 & (0x10100000 >> (16 * ap->port_no))) return ATA_CBL_PATA80; + /* Check with ACPI so we can spot BIOS reported SATA bridges */ + if (ata_acpi_cbl_80wire(ap)) + return ATA_CBL_PATA80; return ATA_CBL_PATA40; } -- cgit v1.2.3-70-g09d2 From ac8869d56d95a8c74403e6f7a47d74fcfcc1b988 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 16 Aug 2007 03:17:03 -0400 Subject: [libata] Remove ->port_disable() hook It was always set to ata_port_disable(). Removed the hook, and replaced the very few ap->ops->port_disable() callsites with direct calls to ata_port_disable(). Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 4 ---- drivers/ata/ata_generic.c | 1 - drivers/ata/ata_piix.c | 4 ---- drivers/ata/libata-core.c | 4 +--- drivers/ata/pata_ali.c | 5 ----- drivers/ata/pata_amd.c | 6 ------ drivers/ata/pata_artop.c | 2 -- drivers/ata/pata_atiixp.c | 1 - drivers/ata/pata_cmd640.c | 1 - drivers/ata/pata_cmd64x.c | 3 --- drivers/ata/pata_cs5520.c | 1 - drivers/ata/pata_cs5530.c | 1 - drivers/ata/pata_cs5535.c | 1 - drivers/ata/pata_cypress.c | 1 - drivers/ata/pata_efar.c | 1 - drivers/ata/pata_hpt366.c | 1 - drivers/ata/pata_hpt37x.c | 4 ---- drivers/ata/pata_hpt3x2n.c | 1 - drivers/ata/pata_hpt3x3.c | 1 - drivers/ata/pata_icside.c | 2 -- drivers/ata/pata_isapnp.c | 1 - drivers/ata/pata_it8213.c | 1 - drivers/ata/pata_it821x.c | 2 -- drivers/ata/pata_ixp4xx_cf.c | 1 - drivers/ata/pata_jmicron.c | 2 -- drivers/ata/pata_legacy.c | 7 ------- drivers/ata/pata_marvell.c | 2 -- drivers/ata/pata_mpc52xx.c | 1 - drivers/ata/pata_mpiix.c | 1 - drivers/ata/pata_netcell.c | 2 -- drivers/ata/pata_ns87410.c | 1 - drivers/ata/pata_oldpiix.c | 1 - drivers/ata/pata_opti.c | 1 - drivers/ata/pata_optidma.c | 2 -- drivers/ata/pata_pcmcia.c | 1 - drivers/ata/pata_pdc2027x.c | 2 -- drivers/ata/pata_pdc202xx_old.c | 2 -- drivers/ata/pata_platform.c | 1 - drivers/ata/pata_qdi.c | 2 -- drivers/ata/pata_radisys.c | 1 - drivers/ata/pata_rz1000.c | 1 - drivers/ata/pata_sc1200.c | 1 - drivers/ata/pata_scc.c | 1 - drivers/ata/pata_serverworks.c | 2 -- drivers/ata/pata_sil680.c | 1 - drivers/ata/pata_sis.c | 6 ------ drivers/ata/pata_sl82c105.c | 1 - drivers/ata/pata_triflex.c | 1 - drivers/ata/pata_via.c | 2 -- drivers/ata/pata_winbond.c | 1 - drivers/ata/pdc_adma.c | 1 - drivers/ata/sata_inic162x.c | 1 - drivers/ata/sata_mv.c | 6 ------ drivers/ata/sata_nv.c | 4 ---- drivers/ata/sata_promise.c | 3 --- drivers/ata/sata_qstor.c | 1 - drivers/ata/sata_sil.c | 1 - drivers/ata/sata_sil24.c | 2 -- drivers/ata/sata_sis.c | 1 - drivers/ata/sata_svw.c | 1 - drivers/ata/sata_sx4.c | 1 - drivers/ata/sata_uli.c | 2 -- drivers/ata/sata_via.c | 6 ------ drivers/ata/sata_vsc.c | 1 - drivers/scsi/ipr.c | 5 ++--- drivers/scsi/libsas/sas_ata.c | 1 - include/linux/libata.h | 2 -- 67 files changed, 3 insertions(+), 132 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index c888c966a02..0d80189d03f 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -264,8 +264,6 @@ static struct scsi_host_template ahci_sht = { }; static const struct ata_port_operations ahci_ops = { - .port_disable = ata_port_disable, - .check_status = ahci_check_status, .check_altstatus = ahci_check_status, .dev_select = ata_noop_dev_select, @@ -296,8 +294,6 @@ static const struct ata_port_operations ahci_ops = { }; static const struct ata_port_operations ahci_vt8251_ops = { - .port_disable = ata_port_disable, - .check_status = ahci_check_status, .check_altstatus = ahci_check_status, .dev_select = ata_noop_dev_select, diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c index 6ec1bbc4fcc..afe71a6e0da 100644 --- a/drivers/ata/ata_generic.c +++ b/drivers/ata/ata_generic.c @@ -95,7 +95,6 @@ static struct scsi_host_template generic_sht = { static struct ata_port_operations generic_port_ops = { .set_mode = generic_set_mode, - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 68bc0ae671c..45e3b60f26d 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -290,7 +290,6 @@ static struct scsi_host_template piix_sht = { }; static const struct ata_port_operations piix_pata_ops = { - .port_disable = ata_port_disable, .set_piomode = piix_set_piomode, .set_dmamode = piix_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -323,7 +322,6 @@ static const struct ata_port_operations piix_pata_ops = { }; static const struct ata_port_operations ich_pata_ops = { - .port_disable = ata_port_disable, .set_piomode = piix_set_piomode, .set_dmamode = ich_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -356,8 +354,6 @@ static const struct ata_port_operations ich_pata_ops = { }; static const struct ata_port_operations piix_sata_ops = { - .port_disable = ata_port_disable, - .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 4f8b8d210cf..43c329544c0 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2208,7 +2208,6 @@ int ata_bus_probe(struct ata_port *ap) /* no device present, disable port */ ata_port_disable(ap); - ap->ops->port_disable(ap); return -ENODEV; fail: @@ -3227,7 +3226,7 @@ void ata_bus_reset(struct ata_port *ap) err_out: ata_port_printk(ap, KERN_ERR, "disabling port\n"); - ap->ops->port_disable(ap); + ata_port_disable(ap); DPRINTK("EXIT\n"); } @@ -6986,7 +6985,6 @@ static unsigned int ata_dummy_qc_issue(struct ata_queued_cmd *qc) } const struct ata_port_operations ata_dummy_port_ops = { - .port_disable = ata_port_disable, .check_status = ata_dummy_check_status, .check_altstatus = ata_dummy_check_status, .dev_select = ata_noop_dev_select, diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c index 9436c496392..7fc11ef0fd2 100644 --- a/drivers/ata/pata_ali.c +++ b/drivers/ata/pata_ali.c @@ -305,7 +305,6 @@ static struct scsi_host_template ali_sht = { */ static struct ata_port_operations ali_early_port_ops = { - .port_disable = ata_port_disable, .set_piomode = ali_set_piomode, .tf_load = ata_tf_load, .tf_read = ata_tf_read, @@ -336,8 +335,6 @@ static struct ata_port_operations ali_early_port_ops = { * detect */ static struct ata_port_operations ali_20_port_ops = { - .port_disable = ata_port_disable, - .set_piomode = ali_set_piomode, .set_dmamode = ali_set_dmamode, .mode_filter = ali_20_filter, @@ -376,7 +373,6 @@ static struct ata_port_operations ali_20_port_ops = { * Port operations for DMA capable ALi with cable detect */ static struct ata_port_operations ali_c2_port_ops = { - .port_disable = ata_port_disable, .set_piomode = ali_set_piomode, .set_dmamode = ali_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -414,7 +410,6 @@ static struct ata_port_operations ali_c2_port_ops = { * Port operations for DMA capable ALi with cable detect and LBA48 */ static struct ata_port_operations ali_c5_port_ops = { - .port_disable = ata_port_disable, .set_piomode = ali_set_piomode, .set_dmamode = ali_set_dmamode, .mode_filter = ata_pci_default_filter, diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c index c95922f8cc5..b1db7ff8edd 100644 --- a/drivers/ata/pata_amd.c +++ b/drivers/ata/pata_amd.c @@ -332,7 +332,6 @@ static struct scsi_host_template amd_sht = { }; static struct ata_port_operations amd33_port_ops = { - .port_disable = ata_port_disable, .set_piomode = amd33_set_piomode, .set_dmamode = amd33_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -366,7 +365,6 @@ static struct ata_port_operations amd33_port_ops = { }; static struct ata_port_operations amd66_port_ops = { - .port_disable = ata_port_disable, .set_piomode = amd66_set_piomode, .set_dmamode = amd66_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -400,7 +398,6 @@ static struct ata_port_operations amd66_port_ops = { }; static struct ata_port_operations amd100_port_ops = { - .port_disable = ata_port_disable, .set_piomode = amd100_set_piomode, .set_dmamode = amd100_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -434,7 +431,6 @@ static struct ata_port_operations amd100_port_ops = { }; static struct ata_port_operations amd133_port_ops = { - .port_disable = ata_port_disable, .set_piomode = amd133_set_piomode, .set_dmamode = amd133_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -468,7 +464,6 @@ static struct ata_port_operations amd133_port_ops = { }; static struct ata_port_operations nv100_port_ops = { - .port_disable = ata_port_disable, .set_piomode = nv100_set_piomode, .set_dmamode = nv100_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -502,7 +497,6 @@ static struct ata_port_operations nv100_port_ops = { }; static struct ata_port_operations nv133_port_ops = { - .port_disable = ata_port_disable, .set_piomode = nv133_set_piomode, .set_dmamode = nv133_set_dmamode, .mode_filter = ata_pci_default_filter, diff --git a/drivers/ata/pata_artop.c b/drivers/ata/pata_artop.c index 8c864353596..1827843cda4 100644 --- a/drivers/ata/pata_artop.c +++ b/drivers/ata/pata_artop.c @@ -332,7 +332,6 @@ static struct scsi_host_template artop_sht = { }; static const struct ata_port_operations artop6210_ops = { - .port_disable = ata_port_disable, .set_piomode = artop6210_set_piomode, .set_dmamode = artop6210_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -366,7 +365,6 @@ static const struct ata_port_operations artop6210_ops = { }; static const struct ata_port_operations artop6260_ops = { - .port_disable = ata_port_disable, .set_piomode = artop6260_set_piomode, .set_dmamode = artop6260_set_dmamode, diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c index f2bfdeb4402..0077ee783d1 100644 --- a/drivers/ata/pata_atiixp.c +++ b/drivers/ata/pata_atiixp.c @@ -233,7 +233,6 @@ static struct scsi_host_template atiixp_sht = { }; static struct ata_port_operations atiixp_port_ops = { - .port_disable = ata_port_disable, .set_piomode = atiixp_set_piomode, .set_dmamode = atiixp_set_dmamode, .mode_filter = ata_pci_default_filter, diff --git a/drivers/ata/pata_cmd640.c b/drivers/ata/pata_cmd640.c index a292ed97246..f09d4fa275c 100644 --- a/drivers/ata/pata_cmd640.c +++ b/drivers/ata/pata_cmd640.c @@ -184,7 +184,6 @@ static struct scsi_host_template cmd640_sht = { }; static struct ata_port_operations cmd640_port_ops = { - .port_disable = ata_port_disable, .set_piomode = cmd640_set_piomode, .mode_filter = ata_pci_default_filter, .tf_load = ata_tf_load, diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c index d308c464464..9e412c26b2a 100644 --- a/drivers/ata/pata_cmd64x.c +++ b/drivers/ata/pata_cmd64x.c @@ -284,7 +284,6 @@ static struct scsi_host_template cmd64x_sht = { }; static struct ata_port_operations cmd64x_port_ops = { - .port_disable = ata_port_disable, .set_piomode = cmd64x_set_piomode, .set_dmamode = cmd64x_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -318,7 +317,6 @@ static struct ata_port_operations cmd64x_port_ops = { }; static struct ata_port_operations cmd646r1_port_ops = { - .port_disable = ata_port_disable, .set_piomode = cmd64x_set_piomode, .set_dmamode = cmd64x_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -352,7 +350,6 @@ static struct ata_port_operations cmd646r1_port_ops = { }; static struct ata_port_operations cmd648_port_ops = { - .port_disable = ata_port_disable, .set_piomode = cmd64x_set_piomode, .set_dmamode = cmd64x_set_dmamode, .mode_filter = ata_pci_default_filter, diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c index 300dcff949e..fe37e3e80f2 100644 --- a/drivers/ata/pata_cs5520.c +++ b/drivers/ata/pata_cs5520.c @@ -158,7 +158,6 @@ static struct scsi_host_template cs5520_sht = { }; static struct ata_port_operations cs5520_port_ops = { - .port_disable = ata_port_disable, .set_piomode = cs5520_set_piomode, .set_dmamode = cs5520_set_dmamode, diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c index 2b770072f39..adeb3acf84c 100644 --- a/drivers/ata/pata_cs5530.c +++ b/drivers/ata/pata_cs5530.c @@ -179,7 +179,6 @@ static struct scsi_host_template cs5530_sht = { }; static struct ata_port_operations cs5530_port_ops = { - .port_disable = ata_port_disable, .set_piomode = cs5530_set_piomode, .set_dmamode = cs5530_set_dmamode, .mode_filter = ata_pci_default_filter, diff --git a/drivers/ata/pata_cs5535.c b/drivers/ata/pata_cs5535.c index 94b1a9caf3c..2c73807da62 100644 --- a/drivers/ata/pata_cs5535.c +++ b/drivers/ata/pata_cs5535.c @@ -176,7 +176,6 @@ static struct scsi_host_template cs5535_sht = { }; static struct ata_port_operations cs5535_port_ops = { - .port_disable = ata_port_disable, .set_piomode = cs5535_set_piomode, .set_dmamode = cs5535_set_dmamode, .mode_filter = ata_pci_default_filter, diff --git a/drivers/ata/pata_cypress.c b/drivers/ata/pata_cypress.c index 8c439a9bb5d..cae44250d81 100644 --- a/drivers/ata/pata_cypress.c +++ b/drivers/ata/pata_cypress.c @@ -128,7 +128,6 @@ static struct scsi_host_template cy82c693_sht = { }; static struct ata_port_operations cy82c693_port_ops = { - .port_disable = ata_port_disable, .set_piomode = cy82c693_set_piomode, .set_dmamode = cy82c693_set_dmamode, .mode_filter = ata_pci_default_filter, diff --git a/drivers/ata/pata_efar.c b/drivers/ata/pata_efar.c index 4d646ffb257..cc418e34e63 100644 --- a/drivers/ata/pata_efar.c +++ b/drivers/ata/pata_efar.c @@ -251,7 +251,6 @@ static struct scsi_host_template efar_sht = { }; static const struct ata_port_operations efar_ops = { - .port_disable = ata_port_disable, .set_piomode = efar_set_piomode, .set_dmamode = efar_set_dmamode, .mode_filter = ata_pci_default_filter, diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c index 508d1cab52d..16cc143460e 100644 --- a/drivers/ata/pata_hpt366.c +++ b/drivers/ata/pata_hpt366.c @@ -312,7 +312,6 @@ static struct scsi_host_template hpt36x_sht = { */ static struct ata_port_operations hpt366_port_ops = { - .port_disable = ata_port_disable, .set_piomode = hpt366_set_piomode, .set_dmamode = hpt366_set_dmamode, .mode_filter = hpt366_filter, diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c index 896e6e31c67..65c0cb21f6a 100644 --- a/drivers/ata/pata_hpt37x.c +++ b/drivers/ata/pata_hpt37x.c @@ -644,7 +644,6 @@ static struct scsi_host_template hpt37x_sht = { */ static struct ata_port_operations hpt370_port_ops = { - .port_disable = ata_port_disable, .set_piomode = hpt370_set_piomode, .set_dmamode = hpt370_set_dmamode, .mode_filter = hpt370_filter, @@ -682,7 +681,6 @@ static struct ata_port_operations hpt370_port_ops = { */ static struct ata_port_operations hpt370a_port_ops = { - .port_disable = ata_port_disable, .set_piomode = hpt370_set_piomode, .set_dmamode = hpt370_set_dmamode, .mode_filter = hpt370a_filter, @@ -721,7 +719,6 @@ static struct ata_port_operations hpt370a_port_ops = { */ static struct ata_port_operations hpt372_port_ops = { - .port_disable = ata_port_disable, .set_piomode = hpt372_set_piomode, .set_dmamode = hpt372_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -760,7 +757,6 @@ static struct ata_port_operations hpt372_port_ops = { */ static struct ata_port_operations hpt374_port_ops = { - .port_disable = ata_port_disable, .set_piomode = hpt372_set_piomode, .set_dmamode = hpt372_set_dmamode, .mode_filter = ata_pci_default_filter, diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c index 2b7f099ac78..5559da7f9db 100644 --- a/drivers/ata/pata_hpt3x2n.c +++ b/drivers/ata/pata_hpt3x2n.c @@ -361,7 +361,6 @@ static struct scsi_host_template hpt3x2n_sht = { */ static struct ata_port_operations hpt3x2n_port_ops = { - .port_disable = ata_port_disable, .set_piomode = hpt3x2n_set_piomode, .set_dmamode = hpt3x2n_set_dmamode, .mode_filter = ata_pci_default_filter, diff --git a/drivers/ata/pata_hpt3x3.c b/drivers/ata/pata_hpt3x3.c index a2f81f40d7a..752394b7265 100644 --- a/drivers/ata/pata_hpt3x3.c +++ b/drivers/ata/pata_hpt3x3.c @@ -120,7 +120,6 @@ static struct scsi_host_template hpt3x3_sht = { }; static struct ata_port_operations hpt3x3_port_ops = { - .port_disable = ata_port_disable, .set_piomode = hpt3x3_set_piomode, #if defined(CONFIG_PATA_HPT3X3_DMA) .set_dmamode = hpt3x3_set_dmamode, diff --git a/drivers/ata/pata_icside.c b/drivers/ata/pata_icside.c index ffcccfc0b9d..4a69328a4c4 100644 --- a/drivers/ata/pata_icside.c +++ b/drivers/ata/pata_icside.c @@ -358,8 +358,6 @@ static void pata_icside_error_handler(struct ata_port *ap) } static struct ata_port_operations pata_icside_port_ops = { - .port_disable = ata_port_disable, - .set_dmamode = pata_icside_set_dmamode, .tf_load = ata_tf_load, diff --git a/drivers/ata/pata_isapnp.c b/drivers/ata/pata_isapnp.c index b8d6d5c4353..1def8c05f34 100644 --- a/drivers/ata/pata_isapnp.c +++ b/drivers/ata/pata_isapnp.c @@ -38,7 +38,6 @@ static struct scsi_host_template isapnp_sht = { }; static struct ata_port_operations isapnp_port_ops = { - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, diff --git a/drivers/ata/pata_it8213.c b/drivers/ata/pata_it8213.c index 8aae9d7171c..cc989ef3042 100644 --- a/drivers/ata/pata_it8213.c +++ b/drivers/ata/pata_it8213.c @@ -261,7 +261,6 @@ static struct scsi_host_template it8213_sht = { }; static const struct ata_port_operations it8213_ops = { - .port_disable = ata_port_disable, .set_piomode = it8213_set_piomode, .set_dmamode = it8213_set_dmamode, .mode_filter = ata_pci_default_filter, diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c index 0179b29c515..4188898a66a 100644 --- a/drivers/ata/pata_it821x.c +++ b/drivers/ata/pata_it821x.c @@ -620,7 +620,6 @@ static struct scsi_host_template it821x_sht = { static struct ata_port_operations it821x_smart_port_ops = { .set_mode = it821x_smart_set_mode, - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .mode_filter = ata_pci_default_filter, @@ -655,7 +654,6 @@ static struct ata_port_operations it821x_smart_port_ops = { }; static struct ata_port_operations it821x_passthru_port_ops = { - .port_disable = ata_port_disable, .set_piomode = it821x_passthru_set_piomode, .set_dmamode = it821x_passthru_set_dmamode, .mode_filter = ata_pci_default_filter, diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c index ce1f9b17ad3..7b0d2fc5748 100644 --- a/drivers/ata/pata_ixp4xx_cf.c +++ b/drivers/ata/pata_ixp4xx_cf.c @@ -107,7 +107,6 @@ static struct ata_port_operations ixp4xx_port_ops = { .set_mode = ixp4xx_set_mode, .mode_filter = ata_pci_default_filter, - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .exec_command = ata_exec_command, diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c index 26f84063859..6d5a81869df 100644 --- a/drivers/ata/pata_jmicron.c +++ b/drivers/ata/pata_jmicron.c @@ -141,8 +141,6 @@ static struct scsi_host_template jmicron_sht = { }; static const struct ata_port_operations jmicron_ops = { - .port_disable = ata_port_disable, - /* Task file is PCI ATA format, use helpers */ .tf_load = ata_tf_load, .tf_read = ata_tf_read, diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c index 6529d34f037..6cae26f4d27 100644 --- a/drivers/ata/pata_legacy.c +++ b/drivers/ata/pata_legacy.c @@ -150,7 +150,6 @@ static struct scsi_host_template legacy_sht = { */ static struct ata_port_operations simple_port_ops = { - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -178,7 +177,6 @@ static struct ata_port_operations simple_port_ops = { static struct ata_port_operations legacy_port_ops = { .set_mode = legacy_set_mode, - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -293,7 +291,6 @@ static void pdc_data_xfer_vlb(struct ata_device *adev, unsigned char *buf, unsig static struct ata_port_operations pdc20230_port_ops = { .set_piomode = pdc20230_set_piomode, - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -348,7 +345,6 @@ static void ht6560a_set_piomode(struct ata_port *ap, struct ata_device *adev) static struct ata_port_operations ht6560a_port_ops = { .set_piomode = ht6560a_set_piomode, - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -414,7 +410,6 @@ static void ht6560b_set_piomode(struct ata_port *ap, struct ata_device *adev) static struct ata_port_operations ht6560b_port_ops = { .set_piomode = ht6560b_set_piomode, - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -535,7 +530,6 @@ static void opti82c611a_set_piomode(struct ata_port *ap, struct ata_device *adev static struct ata_port_operations opti82c611a_port_ops = { .set_piomode = opti82c611a_set_piomode, - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -668,7 +662,6 @@ static unsigned int opti82c46x_qc_issue_prot(struct ata_queued_cmd *qc) static struct ata_port_operations opti82c46x_port_ops = { .set_piomode = opti82c46x_set_piomode, - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c index 021d9d9218b..99d0844c8cb 100644 --- a/drivers/ata/pata_marvell.c +++ b/drivers/ata/pata_marvell.c @@ -111,8 +111,6 @@ static struct scsi_host_template marvell_sht = { }; static const struct ata_port_operations marvell_ops = { - .port_disable = ata_port_disable, - /* Task file is PCI ATA format, use helpers */ .tf_load = ata_tf_load, .tf_read = ata_tf_read, diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c index 6e3fac2fedc..a56694b2833 100644 --- a/drivers/ata/pata_mpc52xx.c +++ b/drivers/ata/pata_mpc52xx.c @@ -283,7 +283,6 @@ static struct scsi_host_template mpc52xx_ata_sht = { }; static struct ata_port_operations mpc52xx_ata_port_ops = { - .port_disable = ata_port_disable, .set_piomode = mpc52xx_ata_set_piomode, .dev_select = mpc52xx_ata_dev_select, .tf_load = ata_tf_load, diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c index 8a82fcd4fa3..b50910938e6 100644 --- a/drivers/ata/pata_mpiix.c +++ b/drivers/ata/pata_mpiix.c @@ -169,7 +169,6 @@ static struct scsi_host_template mpiix_sht = { }; static struct ata_port_operations mpiix_port_ops = { - .port_disable = ata_port_disable, .set_piomode = mpiix_set_piomode, .tf_load = ata_tf_load, diff --git a/drivers/ata/pata_netcell.c b/drivers/ata/pata_netcell.c index 2d64c58482f..b2c3d076754 100644 --- a/drivers/ata/pata_netcell.c +++ b/drivers/ata/pata_netcell.c @@ -40,8 +40,6 @@ static struct scsi_host_template netcell_sht = { }; static const struct ata_port_operations netcell_ops = { - .port_disable = ata_port_disable, - /* Task file is PCI ATA format, use helpers */ .tf_load = ata_tf_load, .tf_read = ata_tf_read, diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c index 00a763c67f9..4b0ddf6ba3b 100644 --- a/drivers/ata/pata_ns87410.c +++ b/drivers/ata/pata_ns87410.c @@ -162,7 +162,6 @@ static struct scsi_host_template ns87410_sht = { }; static struct ata_port_operations ns87410_port_ops = { - .port_disable = ata_port_disable, .set_piomode = ns87410_set_piomode, .tf_load = ata_tf_load, diff --git a/drivers/ata/pata_oldpiix.c b/drivers/ata/pata_oldpiix.c index 851dae96001..ada719ad45a 100644 --- a/drivers/ata/pata_oldpiix.c +++ b/drivers/ata/pata_oldpiix.c @@ -238,7 +238,6 @@ static struct scsi_host_template oldpiix_sht = { }; static const struct ata_port_operations oldpiix_pata_ops = { - .port_disable = ata_port_disable, .set_piomode = oldpiix_set_piomode, .set_dmamode = oldpiix_set_dmamode, .mode_filter = ata_pci_default_filter, diff --git a/drivers/ata/pata_opti.c b/drivers/ata/pata_opti.c index 0ab300cda9b..2a4bfbfbe75 100644 --- a/drivers/ata/pata_opti.c +++ b/drivers/ata/pata_opti.c @@ -183,7 +183,6 @@ static struct scsi_host_template opti_sht = { }; static struct ata_port_operations opti_port_ops = { - .port_disable = ata_port_disable, .set_piomode = opti_set_piomode, .tf_load = ata_tf_load, .tf_read = ata_tf_read, diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c index 51c49283fb3..848ae16f239 100644 --- a/drivers/ata/pata_optidma.c +++ b/drivers/ata/pata_optidma.c @@ -368,7 +368,6 @@ static struct scsi_host_template optidma_sht = { }; static struct ata_port_operations optidma_port_ops = { - .port_disable = ata_port_disable, .set_piomode = optidma_set_pio_mode, .set_dmamode = optidma_set_dma_mode, @@ -403,7 +402,6 @@ static struct ata_port_operations optidma_port_ops = { }; static struct ata_port_operations optiplus_port_ops = { - .port_disable = ata_port_disable, .set_piomode = optiplus_set_pio_mode, .set_dmamode = optiplus_set_dma_mode, diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c index f2167729c3d..5baf531f652 100644 --- a/drivers/ata/pata_pcmcia.c +++ b/drivers/ata/pata_pcmcia.c @@ -107,7 +107,6 @@ static struct scsi_host_template pcmcia_sht = { static struct ata_port_operations pcmcia_port_ops = { .set_mode = pcmcia_set_mode, - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c index 7c6df320c83..5fba36f04ca 100644 --- a/drivers/ata/pata_pdc2027x.c +++ b/drivers/ata/pata_pdc2027x.c @@ -147,7 +147,6 @@ static struct scsi_host_template pdc2027x_sht = { }; static struct ata_port_operations pdc2027x_pata100_ops = { - .port_disable = ata_port_disable, .mode_filter = ata_pci_default_filter, .tf_load = ata_tf_load, @@ -178,7 +177,6 @@ static struct ata_port_operations pdc2027x_pata100_ops = { }; static struct ata_port_operations pdc2027x_pata133_ops = { - .port_disable = ata_port_disable, .set_piomode = pdc2027x_set_piomode, .set_dmamode = pdc2027x_set_dmamode, .set_mode = pdc2027x_set_mode, diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c index b03b3387245..9b7077d5148 100644 --- a/drivers/ata/pata_pdc202xx_old.c +++ b/drivers/ata/pata_pdc202xx_old.c @@ -247,7 +247,6 @@ static struct scsi_host_template pdc202xx_sht = { }; static struct ata_port_operations pdc2024x_port_ops = { - .port_disable = ata_port_disable, .set_piomode = pdc202xx_set_piomode, .set_dmamode = pdc202xx_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -280,7 +279,6 @@ static struct ata_port_operations pdc2024x_port_ops = { }; static struct ata_port_operations pdc2026x_port_ops = { - .port_disable = ata_port_disable, .set_piomode = pdc202xx_set_piomode, .set_dmamode = pdc202xx_set_dmamode, .mode_filter = ata_pci_default_filter, diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c index a616616706d..b04ce5f9841 100644 --- a/drivers/ata/pata_platform.c +++ b/drivers/ata/pata_platform.c @@ -69,7 +69,6 @@ static struct scsi_host_template pata_platform_sht = { static struct ata_port_operations pata_platform_port_ops = { .set_mode = pata_platform_set_mode, - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, diff --git a/drivers/ata/pata_qdi.c b/drivers/ata/pata_qdi.c index ade5a442166..da9ccd23ffc 100644 --- a/drivers/ata/pata_qdi.c +++ b/drivers/ata/pata_qdi.c @@ -170,7 +170,6 @@ static struct scsi_host_template qdi_sht = { }; static struct ata_port_operations qdi6500_port_ops = { - .port_disable = ata_port_disable, .set_piomode = qdi6500_set_piomode, .tf_load = ata_tf_load, @@ -197,7 +196,6 @@ static struct ata_port_operations qdi6500_port_ops = { }; static struct ata_port_operations qdi6580_port_ops = { - .port_disable = ata_port_disable, .set_piomode = qdi6580_set_piomode, .tf_load = ata_tf_load, diff --git a/drivers/ata/pata_radisys.c b/drivers/ata/pata_radisys.c index 66b9a341931..ece2190971c 100644 --- a/drivers/ata/pata_radisys.c +++ b/drivers/ata/pata_radisys.c @@ -203,7 +203,6 @@ static struct scsi_host_template radisys_sht = { }; static const struct ata_port_operations radisys_pata_ops = { - .port_disable = ata_port_disable, .set_piomode = radisys_set_piomode, .set_dmamode = radisys_set_dmamode, .mode_filter = ata_pci_default_filter, diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c index 98784647c7e..5f1a4e180dc 100644 --- a/drivers/ata/pata_rz1000.c +++ b/drivers/ata/pata_rz1000.c @@ -73,7 +73,6 @@ static struct scsi_host_template rz1000_sht = { static struct ata_port_operations rz1000_port_ops = { .set_mode = rz1000_set_mode, - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, diff --git a/drivers/ata/pata_sc1200.c b/drivers/ata/pata_sc1200.c index 61edff4a5c6..6c13754c75a 100644 --- a/drivers/ata/pata_sc1200.c +++ b/drivers/ata/pata_sc1200.c @@ -197,7 +197,6 @@ static struct scsi_host_template sc1200_sht = { }; static struct ata_port_operations sc1200_port_ops = { - .port_disable = ata_port_disable, .set_piomode = sc1200_set_piomode, .set_dmamode = sc1200_set_dmamode, .mode_filter = ata_pci_default_filter, diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c index 95f04b81352..e138343b5d4 100644 --- a/drivers/ata/pata_scc.c +++ b/drivers/ata/pata_scc.c @@ -988,7 +988,6 @@ static struct scsi_host_template scc_sht = { }; static const struct ata_port_operations scc_pata_ops = { - .port_disable = ata_port_disable, .set_piomode = scc_set_piomode, .set_dmamode = scc_set_dmamode, .mode_filter = scc_mode_filter, diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c index c87cd67f415..7c08f25c954 100644 --- a/drivers/ata/pata_serverworks.c +++ b/drivers/ata/pata_serverworks.c @@ -318,7 +318,6 @@ static struct scsi_host_template serverworks_sht = { }; static struct ata_port_operations serverworks_osb4_port_ops = { - .port_disable = ata_port_disable, .set_piomode = serverworks_set_piomode, .set_dmamode = serverworks_set_dmamode, .mode_filter = serverworks_osb4_filter, @@ -353,7 +352,6 @@ static struct ata_port_operations serverworks_osb4_port_ops = { }; static struct ata_port_operations serverworks_csb_port_ops = { - .port_disable = ata_port_disable, .set_piomode = serverworks_set_piomode, .set_dmamode = serverworks_set_dmamode, .mode_filter = serverworks_csb_filter, diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c index c5abf661654..71f206d7b5c 100644 --- a/drivers/ata/pata_sil680.c +++ b/drivers/ata/pata_sil680.c @@ -238,7 +238,6 @@ static struct scsi_host_template sil680_sht = { }; static struct ata_port_operations sil680_port_ops = { - .port_disable = ata_port_disable, .set_piomode = sil680_set_piomode, .set_dmamode = sil680_set_dmamode, .mode_filter = ata_pci_default_filter, diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c index 72850667d37..4ccf09dac8c 100644 --- a/drivers/ata/pata_sis.c +++ b/drivers/ata/pata_sis.c @@ -531,7 +531,6 @@ static struct scsi_host_template sis_sht = { }; static const struct ata_port_operations sis_133_ops = { - .port_disable = ata_port_disable, .set_piomode = sis_133_set_piomode, .set_dmamode = sis_133_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -564,7 +563,6 @@ static const struct ata_port_operations sis_133_ops = { }; static const struct ata_port_operations sis_133_for_sata_ops = { - .port_disable = ata_port_disable, .set_piomode = sis_133_set_piomode, .set_dmamode = sis_133_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -597,7 +595,6 @@ static const struct ata_port_operations sis_133_for_sata_ops = { }; static const struct ata_port_operations sis_133_early_ops = { - .port_disable = ata_port_disable, .set_piomode = sis_100_set_piomode, .set_dmamode = sis_133_early_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -630,7 +627,6 @@ static const struct ata_port_operations sis_133_early_ops = { }; static const struct ata_port_operations sis_100_ops = { - .port_disable = ata_port_disable, .set_piomode = sis_100_set_piomode, .set_dmamode = sis_100_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -663,7 +659,6 @@ static const struct ata_port_operations sis_100_ops = { }; static const struct ata_port_operations sis_66_ops = { - .port_disable = ata_port_disable, .set_piomode = sis_old_set_piomode, .set_dmamode = sis_66_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -696,7 +691,6 @@ static const struct ata_port_operations sis_66_ops = { }; static const struct ata_port_operations sis_old_ops = { - .port_disable = ata_port_disable, .set_piomode = sis_old_set_piomode, .set_dmamode = sis_old_set_dmamode, .mode_filter = ata_pci_default_filter, diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c index 1c50c191e4b..5bd78437e94 100644 --- a/drivers/ata/pata_sl82c105.c +++ b/drivers/ata/pata_sl82c105.c @@ -225,7 +225,6 @@ static struct scsi_host_template sl82c105_sht = { }; static struct ata_port_operations sl82c105_port_ops = { - .port_disable = ata_port_disable, .set_piomode = sl82c105_set_piomode, .mode_filter = ata_pci_default_filter, diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c index 2a55eed45ad..dc20b179e3b 100644 --- a/drivers/ata/pata_triflex.c +++ b/drivers/ata/pata_triflex.c @@ -198,7 +198,6 @@ static struct scsi_host_template triflex_sht = { }; static struct ata_port_operations triflex_port_ops = { - .port_disable = ata_port_disable, .set_piomode = triflex_set_piomode, .mode_filter = ata_pci_default_filter, diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index f11b87e18aa..e1f20e73a61 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -348,7 +348,6 @@ static struct scsi_host_template via_sht = { }; static struct ata_port_operations via_port_ops = { - .port_disable = ata_port_disable, .set_piomode = via_set_piomode, .set_dmamode = via_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -383,7 +382,6 @@ static struct ata_port_operations via_port_ops = { }; static struct ata_port_operations via_port_ops_noirq = { - .port_disable = ata_port_disable, .set_piomode = via_set_piomode, .set_dmamode = via_set_dmamode, .mode_filter = ata_pci_default_filter, diff --git a/drivers/ata/pata_winbond.c b/drivers/ata/pata_winbond.c index c1647da5554..d7555f775d5 100644 --- a/drivers/ata/pata_winbond.c +++ b/drivers/ata/pata_winbond.c @@ -138,7 +138,6 @@ static struct scsi_host_template winbond_sht = { }; static struct ata_port_operations winbond_port_ops = { - .port_disable = ata_port_disable, .set_piomode = winbond_set_piomode, .tf_load = ata_tf_load, diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c index 7dd7361289c..42fd15aaba0 100644 --- a/drivers/ata/pdc_adma.c +++ b/drivers/ata/pdc_adma.c @@ -162,7 +162,6 @@ static struct scsi_host_template adma_ata_sht = { }; static const struct ata_port_operations adma_ata_ops = { - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .exec_command = ata_exec_command, diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c index d6a3e286c79..f0ea0e166c1 100644 --- a/drivers/ata/sata_inic162x.c +++ b/drivers/ata/sata_inic162x.c @@ -552,7 +552,6 @@ static int inic_port_start(struct ata_port *ap) } static struct ata_port_operations inic_port_ops = { - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 393fc655f8c..68c3f22890d 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -483,8 +483,6 @@ static struct scsi_host_template mv6_sht = { }; static const struct ata_port_operations mv5_ops = { - .port_disable = ata_port_disable, - .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -513,8 +511,6 @@ static const struct ata_port_operations mv5_ops = { }; static const struct ata_port_operations mv6_ops = { - .port_disable = ata_port_disable, - .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -543,8 +539,6 @@ static const struct ata_port_operations mv6_ops = { }; static const struct ata_port_operations mv_iie_ops = { - .port_disable = ata_port_disable, - .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index 88ecca6343e..b860f99fc28 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -340,7 +340,6 @@ static struct scsi_host_template nv_adma_sht = { }; static const struct ata_port_operations nv_generic_ops = { - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .exec_command = ata_exec_command, @@ -365,7 +364,6 @@ static const struct ata_port_operations nv_generic_ops = { }; static const struct ata_port_operations nv_nf2_ops = { - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .exec_command = ata_exec_command, @@ -390,7 +388,6 @@ static const struct ata_port_operations nv_nf2_ops = { }; static const struct ata_port_operations nv_ck804_ops = { - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .exec_command = ata_exec_command, @@ -416,7 +413,6 @@ static const struct ata_port_operations nv_ck804_ops = { }; static const struct ata_port_operations nv_adma_ops = { - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = nv_adma_tf_read, .check_atapi_dma = nv_adma_check_atapi_dma, diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c index 37d737b442b..983bff5c4de 100644 --- a/drivers/ata/sata_promise.c +++ b/drivers/ata/sata_promise.c @@ -167,7 +167,6 @@ static struct scsi_host_template pdc_ata_sht = { }; static const struct ata_port_operations pdc_sata_ops = { - .port_disable = ata_port_disable, .tf_load = pdc_tf_load_mmio, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -193,7 +192,6 @@ static const struct ata_port_operations pdc_sata_ops = { /* First-generation chips need a more restrictive ->check_atapi_dma op */ static const struct ata_port_operations pdc_old_sata_ops = { - .port_disable = ata_port_disable, .tf_load = pdc_tf_load_mmio, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -218,7 +216,6 @@ static const struct ata_port_operations pdc_old_sata_ops = { }; static const struct ata_port_operations pdc_pata_ops = { - .port_disable = ata_port_disable, .tf_load = pdc_tf_load_mmio, .tf_read = ata_tf_read, .check_status = ata_check_status, diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c index 5a60ab72ecb..10bf52ca1e1 100644 --- a/drivers/ata/sata_qstor.c +++ b/drivers/ata/sata_qstor.c @@ -145,7 +145,6 @@ static struct scsi_host_template qs_ata_sht = { }; static const struct ata_port_operations qs_ata_ops = { - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index 1930e7cf143..df0ac77fcdd 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -186,7 +186,6 @@ static struct scsi_host_template sil_sht = { }; static const struct ata_port_operations sil_ops = { - .port_disable = ata_port_disable, .dev_config = sil_dev_config, .tf_load = ata_tf_load, .tf_read = ata_tf_read, diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index 961b3f201a3..e0cd31aa800 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -384,8 +384,6 @@ static struct scsi_host_template sil24_sht = { }; static const struct ata_port_operations sil24_ops = { - .port_disable = ata_port_disable, - .dev_config = sil24_dev_config, .check_status = sil24_check_status, diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c index 691017eddbb..8d98a9fb0a4 100644 --- a/drivers/ata/sata_sis.c +++ b/drivers/ata/sata_sis.c @@ -104,7 +104,6 @@ static struct scsi_host_template sis_sht = { }; static const struct ata_port_operations sis_ops = { - .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c index 006a720da40..822cabfec95 100644 --- a/drivers/ata/sata_svw.c +++ b/drivers/ata/sata_svw.c @@ -329,7 +329,6 @@ static struct scsi_host_template k2_sata_sht = { static const struct ata_port_operations k2_sata_ops = { - .port_disable = ata_port_disable, .tf_load = k2_sata_tf_load, .tf_read = k2_sata_tf_read, .check_status = k2_stat_check_status, diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c index d5cbd16629a..b425061dbe8 100644 --- a/drivers/ata/sata_sx4.c +++ b/drivers/ata/sata_sx4.c @@ -254,7 +254,6 @@ static struct scsi_host_template pdc_sata_sht = { }; static const struct ata_port_operations pdc_20621_ops = { - .port_disable = ata_port_disable, .tf_load = pdc_tf_load_mmio, .tf_read = ata_tf_read, .check_status = ata_check_status, diff --git a/drivers/ata/sata_uli.c b/drivers/ata/sata_uli.c index d4514e2149b..6c53a790805 100644 --- a/drivers/ata/sata_uli.c +++ b/drivers/ata/sata_uli.c @@ -94,8 +94,6 @@ static struct scsi_host_template uli_sht = { }; static const struct ata_port_operations uli_ops = { - .port_disable = ata_port_disable, - .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index 4b25c3ef986..25162ec9938 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c @@ -122,8 +122,6 @@ static struct scsi_host_template svia_sht = { }; static const struct ata_port_operations vt6420_sata_ops = { - .port_disable = ata_port_disable, - .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -151,8 +149,6 @@ static const struct ata_port_operations vt6420_sata_ops = { }; static const struct ata_port_operations vt6421_pata_ops = { - .port_disable = ata_port_disable, - .set_piomode = vt6421_set_pio_mode, .set_dmamode = vt6421_set_dma_mode, @@ -184,8 +180,6 @@ static const struct ata_port_operations vt6421_pata_ops = { }; static const struct ata_port_operations vt6421_sata_ops = { - .port_disable = ata_port_disable, - .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c index 55fb2e0b369..b1777c3f6d5 100644 --- a/drivers/ata/sata_vsc.c +++ b/drivers/ata/sata_vsc.c @@ -317,7 +317,6 @@ static struct scsi_host_template vsc_sata_sht = { static const struct ata_port_operations vsc_sata_ops = { - .port_disable = ata_port_disable, .tf_load = vsc_sata_tf_load, .tf_read = vsc_sata_tf_read, .exec_command = ata_exec_command, diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 9350fbf39f7..b41dfb53902 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -4981,7 +4981,7 @@ static void ipr_ata_phy_reset(struct ata_port *ap) rc = ipr_device_reset(ioa_cfg, res); if (rc) { - ap->ops->port_disable(ap); + ata_port_disable(ap); goto out_unlock; } @@ -4996,7 +4996,7 @@ static void ipr_ata_phy_reset(struct ata_port *ap) break; default: ap->link.device[0].class = ATA_DEV_UNKNOWN; - ap->ops->port_disable(ap); + ata_port_disable(ap); break; }; @@ -5262,7 +5262,6 @@ static u8 ipr_ata_check_altstatus(struct ata_port *ap) } static struct ata_port_operations ipr_sata_ops = { - .port_disable = ata_port_disable, .check_status = ipr_ata_check_status, .check_altstatus = ipr_ata_check_altstatus, .dev_select = ata_noop_dev_select, diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index 1d6503d85f0..0829b55c64d 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -350,7 +350,6 @@ static int sas_ata_scr_read(struct ata_port *ap, unsigned int sc_reg_in, } static struct ata_port_operations sas_sata_ops = { - .port_disable = ata_port_disable, .check_status = sas_ata_check_status, .check_altstatus = sas_ata_check_status, .dev_select = ata_noop_dev_select, diff --git a/include/linux/libata.h b/include/linux/libata.h index 382898ef654..e7d163edb4c 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -600,8 +600,6 @@ struct ata_port { }; struct ata_port_operations { - void (*port_disable) (struct ata_port *); - void (*dev_config) (struct ata_device *); void (*set_piomode) (struct ata_port *, struct ata_device *); -- cgit v1.2.3-70-g09d2 From 81ad1837b590775336f68eafcae8dab13a975b3a Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 22 Aug 2007 22:55:41 +0100 Subject: libata: Switch most of the remaining SFF drivers to ata_sff_port_start This avoids allocating DMA buffers if not needed but at the moment is mostly just a neatness item. Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/ata_generic.c | 2 +- drivers/ata/pata_ali.c | 8 ++++---- drivers/ata/pata_amd.c | 12 ++++++------ drivers/ata/pata_artop.c | 4 ++-- drivers/ata/pata_atiixp.c | 2 +- drivers/ata/pata_cmd640.c | 2 +- drivers/ata/pata_cs5520.c | 2 +- drivers/ata/pata_cs5530.c | 2 +- drivers/ata/pata_cs5535.c | 2 +- drivers/ata/pata_cypress.c | 2 +- drivers/ata/pata_efar.c | 2 +- drivers/ata/pata_hpt366.c | 2 +- drivers/ata/pata_hpt37x.c | 8 ++++---- drivers/ata/pata_hpt3x2n.c | 2 +- drivers/ata/pata_hpt3x3.c | 2 +- drivers/ata/pata_isapnp.c | 2 +- drivers/ata/pata_it8213.c | 2 +- drivers/ata/pata_it821x.c | 2 +- drivers/ata/pata_marvell.c | 2 +- drivers/ata/pata_mpiix.c | 2 +- drivers/ata/pata_netcell.c | 2 +- drivers/ata/pata_ns87410.c | 2 +- drivers/ata/pata_oldpiix.c | 2 +- drivers/ata/pata_opti.c | 2 +- drivers/ata/pata_optidma.c | 4 ++-- drivers/ata/pata_pdc2027x.c | 4 ++-- drivers/ata/pata_pdc202xx_old.c | 4 ++-- drivers/ata/pata_qdi.c | 4 ++-- drivers/ata/pata_radisys.c | 2 +- drivers/ata/pata_rz1000.c | 2 +- drivers/ata/pata_sc1200.c | 2 +- drivers/ata/pata_serverworks.c | 4 ++-- drivers/ata/pata_sil680.c | 2 +- drivers/ata/pata_sis.c | 12 ++++++------ drivers/ata/pata_sl82c105.c | 2 +- drivers/ata/pata_triflex.c | 2 +- drivers/ata/pata_via.c | 4 ++-- drivers/ata/pata_winbond.c | 2 +- 38 files changed, 61 insertions(+), 61 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c index afe71a6e0da..90329982bef 100644 --- a/drivers/ata/ata_generic.c +++ b/drivers/ata/ata_generic.c @@ -121,7 +121,7 @@ static struct ata_port_operations generic_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static int all_generic_ide; /* Set to claim all devices */ diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c index 7fc11ef0fd2..364534e7aff 100644 --- a/drivers/ata/pata_ali.c +++ b/drivers/ata/pata_ali.c @@ -327,7 +327,7 @@ static struct ata_port_operations ali_early_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /* @@ -366,7 +366,7 @@ static struct ata_port_operations ali_20_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /* @@ -403,7 +403,7 @@ static struct ata_port_operations ali_c2_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /* @@ -439,7 +439,7 @@ static struct ata_port_operations ali_c5_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c index b1db7ff8edd..c5779ad4abc 100644 --- a/drivers/ata/pata_amd.c +++ b/drivers/ata/pata_amd.c @@ -361,7 +361,7 @@ static struct ata_port_operations amd33_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static struct ata_port_operations amd66_port_ops = { @@ -394,7 +394,7 @@ static struct ata_port_operations amd66_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static struct ata_port_operations amd100_port_ops = { @@ -427,7 +427,7 @@ static struct ata_port_operations amd100_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static struct ata_port_operations amd133_port_ops = { @@ -460,7 +460,7 @@ static struct ata_port_operations amd133_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static struct ata_port_operations nv100_port_ops = { @@ -493,7 +493,7 @@ static struct ata_port_operations nv100_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static struct ata_port_operations nv133_port_ops = { @@ -526,7 +526,7 @@ static struct ata_port_operations nv133_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_artop.c b/drivers/ata/pata_artop.c index 1827843cda4..d4218310327 100644 --- a/drivers/ata/pata_artop.c +++ b/drivers/ata/pata_artop.c @@ -361,7 +361,7 @@ static const struct ata_port_operations artop6210_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static const struct ata_port_operations artop6260_ops = { @@ -392,7 +392,7 @@ static const struct ata_port_operations artop6260_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c index 0077ee783d1..95ed3071a0a 100644 --- a/drivers/ata/pata_atiixp.c +++ b/drivers/ata/pata_atiixp.c @@ -262,7 +262,7 @@ static struct ata_port_operations atiixp_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static int atiixp_init_one(struct pci_dev *dev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_cmd640.c b/drivers/ata/pata_cmd640.c index f09d4fa275c..43d198f9096 100644 --- a/drivers/ata/pata_cmd640.c +++ b/drivers/ata/pata_cmd640.c @@ -153,7 +153,7 @@ static int cmd640_port_start(struct ata_port *ap) struct pci_dev *pdev = to_pci_dev(ap->host->dev); struct cmd640_reg *timing; - int ret = ata_port_start(ap); + int ret = ata_sff_port_start(ap); if (ret < 0) return ret; diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c index fe37e3e80f2..1ae6b6bd856 100644 --- a/drivers/ata/pata_cs5520.c +++ b/drivers/ata/pata_cs5520.c @@ -184,7 +184,7 @@ static struct ata_port_operations cs5520_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c index adeb3acf84c..57e827e4109 100644 --- a/drivers/ata/pata_cs5530.c +++ b/drivers/ata/pata_cs5530.c @@ -209,7 +209,7 @@ static struct ata_port_operations cs5530_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static const struct dmi_system_id palmax_dmi_table[] = { diff --git a/drivers/ata/pata_cs5535.c b/drivers/ata/pata_cs5535.c index 2c73807da62..3578593a882 100644 --- a/drivers/ata/pata_cs5535.c +++ b/drivers/ata/pata_cs5535.c @@ -206,7 +206,7 @@ static struct ata_port_operations cs5535_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /** diff --git a/drivers/ata/pata_cypress.c b/drivers/ata/pata_cypress.c index cae44250d81..fc5f9c4e5d8 100644 --- a/drivers/ata/pata_cypress.c +++ b/drivers/ata/pata_cypress.c @@ -158,7 +158,7 @@ static struct ata_port_operations cy82c693_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static int cy82c693_init_one(struct pci_dev *pdev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_efar.c b/drivers/ata/pata_efar.c index cc418e34e63..043dcd35106 100644 --- a/drivers/ata/pata_efar.c +++ b/drivers/ata/pata_efar.c @@ -279,7 +279,7 @@ static const struct ata_port_operations efar_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c index 16cc143460e..0713872cf65 100644 --- a/drivers/ata/pata_hpt366.c +++ b/drivers/ata/pata_hpt366.c @@ -342,7 +342,7 @@ static struct ata_port_operations hpt366_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /** diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c index 65c0cb21f6a..e61cb1fd57b 100644 --- a/drivers/ata/pata_hpt37x.c +++ b/drivers/ata/pata_hpt37x.c @@ -673,7 +673,7 @@ static struct ata_port_operations hpt370_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /* @@ -710,7 +710,7 @@ static struct ata_port_operations hpt370a_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /* @@ -748,7 +748,7 @@ static struct ata_port_operations hpt372_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /* @@ -786,7 +786,7 @@ static struct ata_port_operations hpt374_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /** diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c index 5559da7f9db..9f1c084f846 100644 --- a/drivers/ata/pata_hpt3x2n.c +++ b/drivers/ata/pata_hpt3x2n.c @@ -391,7 +391,7 @@ static struct ata_port_operations hpt3x2n_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /** diff --git a/drivers/ata/pata_hpt3x3.c b/drivers/ata/pata_hpt3x3.c index 752394b7265..188d2176ec3 100644 --- a/drivers/ata/pata_hpt3x3.c +++ b/drivers/ata/pata_hpt3x3.c @@ -153,7 +153,7 @@ static struct ata_port_operations hpt3x3_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /** diff --git a/drivers/ata/pata_isapnp.c b/drivers/ata/pata_isapnp.c index 1def8c05f34..8ac1e8beaba 100644 --- a/drivers/ata/pata_isapnp.c +++ b/drivers/ata/pata_isapnp.c @@ -58,7 +58,7 @@ static struct ata_port_operations isapnp_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /** diff --git a/drivers/ata/pata_it8213.c b/drivers/ata/pata_it8213.c index cc989ef3042..1eda821e5e3 100644 --- a/drivers/ata/pata_it8213.c +++ b/drivers/ata/pata_it8213.c @@ -289,7 +289,7 @@ static const struct ata_port_operations it8213_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c index 4188898a66a..988ef736b93 100644 --- a/drivers/ata/pata_it821x.c +++ b/drivers/ata/pata_it821x.c @@ -563,7 +563,7 @@ static int it821x_port_start(struct ata_port *ap) struct it821x_dev *itdev; u8 conf; - int ret = ata_port_start(ap); + int ret = ata_sff_port_start(ap); if (ret < 0) return ret; diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c index 99d0844c8cb..9afc8a32b22 100644 --- a/drivers/ata/pata_marvell.c +++ b/drivers/ata/pata_marvell.c @@ -139,7 +139,7 @@ static const struct ata_port_operations marvell_ops = { .irq_on = ata_irq_on, /* Generic PATA PCI ATA helpers */ - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c index b50910938e6..cb78b7bfe14 100644 --- a/drivers/ata/pata_mpiix.c +++ b/drivers/ata/pata_mpiix.c @@ -190,7 +190,7 @@ static struct ata_port_operations mpiix_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_netcell.c b/drivers/ata/pata_netcell.c index b2c3d076754..25c922abd55 100644 --- a/drivers/ata/pata_netcell.c +++ b/drivers/ata/pata_netcell.c @@ -68,7 +68,7 @@ static const struct ata_port_operations netcell_ops = { .irq_on = ata_irq_on, /* Generic PATA PCI ATA helpers */ - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c index 4b0ddf6ba3b..6e8e55745b7 100644 --- a/drivers/ata/pata_ns87410.c +++ b/drivers/ata/pata_ns87410.c @@ -185,7 +185,7 @@ static struct ata_port_operations ns87410_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static int ns87410_init_one(struct pci_dev *dev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_oldpiix.c b/drivers/ata/pata_oldpiix.c index ada719ad45a..3cd5eb2b6c9 100644 --- a/drivers/ata/pata_oldpiix.c +++ b/drivers/ata/pata_oldpiix.c @@ -266,7 +266,7 @@ static const struct ata_port_operations oldpiix_pata_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; diff --git a/drivers/ata/pata_opti.c b/drivers/ata/pata_opti.c index 2a4bfbfbe75..8f79447b615 100644 --- a/drivers/ata/pata_opti.c +++ b/drivers/ata/pata_opti.c @@ -210,7 +210,7 @@ static struct ata_port_operations opti_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static int opti_init_one(struct pci_dev *dev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c index 848ae16f239..6b07b5b4853 100644 --- a/drivers/ata/pata_optidma.c +++ b/drivers/ata/pata_optidma.c @@ -398,7 +398,7 @@ static struct ata_port_operations optidma_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static struct ata_port_operations optiplus_port_ops = { @@ -432,7 +432,7 @@ static struct ata_port_operations optiplus_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /** diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c index 5fba36f04ca..40b070ea85a 100644 --- a/drivers/ata/pata_pdc2027x.c +++ b/drivers/ata/pata_pdc2027x.c @@ -173,7 +173,7 @@ static struct ata_port_operations pdc2027x_pata100_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static struct ata_port_operations pdc2027x_pata133_ops = { @@ -206,7 +206,7 @@ static struct ata_port_operations pdc2027x_pata133_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static struct ata_port_info pdc2027x_port_info[] = { diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c index 9b7077d5148..fd4350029bc 100644 --- a/drivers/ata/pata_pdc202xx_old.c +++ b/drivers/ata/pata_pdc202xx_old.c @@ -275,7 +275,7 @@ static struct ata_port_operations pdc2024x_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static struct ata_port_operations pdc2026x_port_ops = { @@ -308,7 +308,7 @@ static struct ata_port_operations pdc2026x_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static int pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_qdi.c b/drivers/ata/pata_qdi.c index da9ccd23ffc..032fa67acc8 100644 --- a/drivers/ata/pata_qdi.c +++ b/drivers/ata/pata_qdi.c @@ -192,7 +192,7 @@ static struct ata_port_operations qdi6500_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static struct ata_port_operations qdi6580_port_ops = { @@ -218,7 +218,7 @@ static struct ata_port_operations qdi6580_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /** diff --git a/drivers/ata/pata_radisys.c b/drivers/ata/pata_radisys.c index ece2190971c..d5b76497f4a 100644 --- a/drivers/ata/pata_radisys.c +++ b/drivers/ata/pata_radisys.c @@ -231,7 +231,7 @@ static const struct ata_port_operations radisys_pata_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c index 5f1a4e180dc..ba8a31c55ed 100644 --- a/drivers/ata/pata_rz1000.c +++ b/drivers/ata/pata_rz1000.c @@ -99,7 +99,7 @@ static struct ata_port_operations rz1000_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static int rz1000_fifo_disable(struct pci_dev *pdev) diff --git a/drivers/ata/pata_sc1200.c b/drivers/ata/pata_sc1200.c index 6c13754c75a..21ebc485ca4 100644 --- a/drivers/ata/pata_sc1200.c +++ b/drivers/ata/pata_sc1200.c @@ -227,7 +227,7 @@ static struct ata_port_operations sc1200_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /** diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c index 7c08f25c954..df68806df4b 100644 --- a/drivers/ata/pata_serverworks.c +++ b/drivers/ata/pata_serverworks.c @@ -348,7 +348,7 @@ static struct ata_port_operations serverworks_osb4_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static struct ata_port_operations serverworks_csb_port_ops = { @@ -382,7 +382,7 @@ static struct ata_port_operations serverworks_csb_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static int serverworks_fixup_osb4(struct pci_dev *pdev) diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c index 71f206d7b5c..2eb75cd74a9 100644 --- a/drivers/ata/pata_sil680.c +++ b/drivers/ata/pata_sil680.c @@ -267,7 +267,7 @@ static struct ata_port_operations sil680_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /** diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c index 4ccf09dac8c..3b5be77e861 100644 --- a/drivers/ata/pata_sis.c +++ b/drivers/ata/pata_sis.c @@ -559,7 +559,7 @@ static const struct ata_port_operations sis_133_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static const struct ata_port_operations sis_133_for_sata_ops = { @@ -591,7 +591,7 @@ static const struct ata_port_operations sis_133_for_sata_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static const struct ata_port_operations sis_133_early_ops = { @@ -623,7 +623,7 @@ static const struct ata_port_operations sis_133_early_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static const struct ata_port_operations sis_100_ops = { @@ -655,7 +655,7 @@ static const struct ata_port_operations sis_100_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static const struct ata_port_operations sis_66_ops = { @@ -687,7 +687,7 @@ static const struct ata_port_operations sis_66_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static const struct ata_port_operations sis_old_ops = { @@ -719,7 +719,7 @@ static const struct ata_port_operations sis_old_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static const struct ata_port_info sis_info = { diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c index 5bd78437e94..1388cef52c0 100644 --- a/drivers/ata/pata_sl82c105.c +++ b/drivers/ata/pata_sl82c105.c @@ -254,7 +254,7 @@ static struct ata_port_operations sl82c105_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /** diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c index dc20b179e3b..403eafcffe1 100644 --- a/drivers/ata/pata_triflex.c +++ b/drivers/ata/pata_triflex.c @@ -227,7 +227,7 @@ static struct ata_port_operations triflex_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static int triflex_init_one(struct pci_dev *dev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index e1f20e73a61..5d41b6612d7 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -378,7 +378,7 @@ static struct ata_port_operations via_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static struct ata_port_operations via_port_ops_noirq = { @@ -412,7 +412,7 @@ static struct ata_port_operations via_port_ops_noirq = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /** diff --git a/drivers/ata/pata_winbond.c b/drivers/ata/pata_winbond.c index d7555f775d5..553658bacce 100644 --- a/drivers/ata/pata_winbond.c +++ b/drivers/ata/pata_winbond.c @@ -160,7 +160,7 @@ static struct ata_port_operations winbond_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /** -- cgit v1.2.3-70-g09d2 From 614fe29bd91f99cc1c1fbf3274fa918691044f47 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 22 Aug 2007 23:22:45 +0100 Subject: libata: Spot bridge chips If we have a PATA cable with a SATA drive on it then we've found a bridge and we can flip the cable type. This fixes some cable detect problems with SATA bridges on chipsets and misdetected cable types. In theory cable detection and mode limiting is needed if you put a SATA/PATA bridge on a 40 wire cable, but I see no way to deal with that other than to point out its not a good idea anyway. Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 43c329544c0..b81265d1e46 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2183,6 +2183,17 @@ int ata_bus_probe(struct ata_port *ap) if (ap->ops->cable_detect) ap->cbl = ap->ops->cable_detect(ap); + /* We may have SATA bridge glue hiding here irrespective of the + reported cable types and sensed types */ + ata_link_for_each_dev(dev, &ap->link) { + if (!ata_dev_enabled(dev)) + continue; + /* SATA drives indicate we have a bridge. We don't know which + end of the link the bridge is which is a problem */ + if (ata_id_is_sata(dev->id)) + ap->cbl = ATA_CBL_SATA; + } + /* After the identify sequence we can now set up the devices. We do this in the normal order so that the user doesn't get confused */ -- cgit v1.2.3-70-g09d2 From e923090ddd9fef1d4e06dc6c5295e29baced19f3 Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Mon, 20 Aug 2007 16:56:29 +0800 Subject: libata: pata_pdc2027x PLL detection minor cleanup Minor cleanup to remove the unneeded rmb()s per Jeff's advice. Also removed the pll_clock < 0 check since pll_clock now guaranteed to be >= 0 after Mikael's patch. Signed-off-by: Albert Lee Signed-off-by: Jeff Garzik --- drivers/ata/pata_pdc2027x.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c index 40b070ea85a..2141a99e4da 100644 --- a/drivers/ata/pata_pdc2027x.c +++ b/drivers/ata/pata_pdc2027x.c @@ -561,12 +561,10 @@ static long pdc_read_counter(struct ata_host *host) retry: bccrl = readl(mmio_base + PDC_BYTE_COUNT) & 0x7fff; bccrh = readl(mmio_base + PDC_BYTE_COUNT + 0x100) & 0x7fff; - rmb(); /* Read the counter values again for verification */ bccrlv = readl(mmio_base + PDC_BYTE_COUNT) & 0x7fff; bccrhv = readl(mmio_base + PDC_BYTE_COUNT + 0x100) & 0x7fff; - rmb(); counter = (bccrh << 15) | bccrl; @@ -741,9 +739,6 @@ static int pdc_hardware_init(struct ata_host *host, unsigned int board_idx) */ pll_clock = pdc_detect_pll_input_clock(host); - if (pll_clock < 0) /* counter overflow? Try again. */ - pll_clock = pdc_detect_pll_input_clock(host); - dev_printk(KERN_INFO, host->dev, "PLL input clock %ld kHz\n", pll_clock/1000); /* Adjust PLL control register */ -- cgit v1.2.3-70-g09d2 From cbcdd87593a1d85c5c4b259945a3a09eee12814d Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 18 Aug 2007 13:14:55 +0900 Subject: libata: implement and use ata_port_desc() to report port configuration Currently, port configuration reporting has the following problems. * iomapped address is reported instead of raw address * report contains irrelevant fields or lacks necessary fields for non-SFF controllers. * host->irq/irq2 are there just for reporting and hacky. This patch implements and uses ata_port_desc() and ata_port_pbar_desc(). ata_port_desc() is almost identical to ata_ehi_push_desc() except that it takes @ap instead of @ehi, has no locking requirement, can only be used during host initialization and " " is used as separator instead of ", ". ata_port_pbar_desc() is a helper to ease reporting of a PCI BAR or an offsetted address into it. LLD pushes whatever description it wants using the above two functions. The accumulated description is printed on host registration after "[S/P]ATA max MAX_XFERMODE ". SFF init helpers and ata_host_activate() automatically add descriptions for addresses and irq respectively, so only LLDs which isn't standard SFF need to add custom descriptions. In many cases, such controllers need to report different things anyway. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 4 +++ drivers/ata/libata-core.c | 27 ++++++++---------- drivers/ata/libata-eh.c | 67 ++++++++++++++++++++++++++++++++++++++++++++ drivers/ata/libata-sff.c | 23 +++++++++++---- drivers/ata/pata_cs5520.c | 23 +++++++++------ drivers/ata/pata_hpt3x3.c | 6 +++- drivers/ata/pata_icside.c | 19 +++++++++++-- drivers/ata/pata_isapnp.c | 4 +++ drivers/ata/pata_ixp4xx_cf.c | 13 +++++++-- drivers/ata/pata_legacy.c | 2 ++ drivers/ata/pata_mpc52xx.c | 7 +++-- drivers/ata/pata_mpiix.c | 16 +++++++---- drivers/ata/pata_pcmcia.c | 2 ++ drivers/ata/pata_pdc2027x.c | 17 +++++++---- drivers/ata/pata_platform.c | 4 +++ drivers/ata/pata_qdi.c | 5 +++- drivers/ata/pata_scc.c | 3 ++ drivers/ata/pata_winbond.c | 7 +++-- drivers/ata/pdc_adma.c | 13 +++++++-- drivers/ata/sata_inic162x.c | 14 +++++++-- drivers/ata/sata_mv.c | 8 +++++- drivers/ata/sata_promise.c | 11 ++++++-- drivers/ata/sata_qstor.c | 11 ++++++-- drivers/ata/sata_sil.c | 6 +++- drivers/ata/sata_sil24.c | 7 +++-- drivers/ata/sata_svw.c | 12 ++++++-- drivers/ata/sata_sx4.c | 19 ++++++++----- drivers/ata/sata_uli.c | 13 +++++++++ drivers/ata/sata_via.c | 3 ++ drivers/ata/sata_vsc.c | 12 ++++++-- include/linux/libata.h | 12 ++++++-- 31 files changed, 309 insertions(+), 81 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 0d80189d03f..518c5183035 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1887,6 +1887,10 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) struct ata_port *ap = host->ports[i]; void __iomem *port_mmio = ahci_port_base(ap); + ata_port_pbar_desc(ap, AHCI_PCI_BAR, -1, "abar"); + ata_port_pbar_desc(ap, AHCI_PCI_BAR, + 0x100 + ap->port_no * 0x80, "port"); + /* standard SATA port setup */ if (hpriv->port_map & (1 << i)) ap->ioaddr.cmd_addr = port_mmio; diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index b81265d1e46..84d81b26e38 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -6541,7 +6541,6 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) /* set cable, sata_spd_limit and report */ for (i = 0; i < host->n_ports; i++) { struct ata_port *ap = host->ports[i]; - int irq_line; unsigned long xfer_mask; /* set SATA cable type if still unset */ @@ -6551,24 +6550,16 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) /* init sata_spd_limit to the current value */ sata_link_init_spd(&ap->link); - /* report the secondary IRQ for second channel legacy */ - irq_line = host->irq; - if (i == 1 && host->irq2) - irq_line = host->irq2; - + /* print per-port info to dmesg */ xfer_mask = ata_pack_xfermask(ap->pio_mask, ap->mwdma_mask, ap->udma_mask); - /* print per-port info to dmesg */ if (!ata_port_is_dummy(ap)) - ata_port_printk(ap, KERN_INFO, "%cATA max %s cmd 0x%p " - "ctl 0x%p bmdma 0x%p irq %d\n", + ata_port_printk(ap, KERN_INFO, + "%cATA max %s %s\n", (ap->flags & ATA_FLAG_SATA) ? 'S' : 'P', ata_mode_string(xfer_mask), - ap->ioaddr.cmd_addr, - ap->ioaddr.ctl_addr, - ap->ioaddr.bmdma_addr, - irq_line); + ap->link.eh_info.desc); else ata_port_printk(ap, KERN_INFO, "DUMMY\n"); } @@ -6652,7 +6643,7 @@ int ata_host_activate(struct ata_host *host, int irq, irq_handler_t irq_handler, unsigned long irq_flags, struct scsi_host_template *sht) { - int rc; + int i, rc; rc = ata_host_start(host); if (rc) @@ -6663,8 +6654,8 @@ int ata_host_activate(struct ata_host *host, int irq, if (rc) return rc; - /* Used to print device info at probe */ - host->irq = irq; + for (i = 0; i < host->n_ports; i++) + ata_port_desc(host->ports[i], "irq %d", irq); rc = ata_host_register(host, sht); /* if failed, just free the IRQ and leave ports alone */ @@ -7136,6 +7127,10 @@ EXPORT_SYMBOL_GPL(ata_pci_clear_simplex); EXPORT_SYMBOL_GPL(__ata_ehi_push_desc); EXPORT_SYMBOL_GPL(ata_ehi_push_desc); EXPORT_SYMBOL_GPL(ata_ehi_clear_desc); +EXPORT_SYMBOL_GPL(ata_port_desc); +#ifdef CONFIG_PCI +EXPORT_SYMBOL_GPL(ata_port_pbar_desc); +#endif /* CONFIG_PCI */ EXPORT_SYMBOL_GPL(ata_eng_timeout); EXPORT_SYMBOL_GPL(ata_port_schedule_eh); EXPORT_SYMBOL_GPL(ata_link_abort); diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 2ddc2ed9c29..8219e2d7104 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -151,6 +151,73 @@ void ata_ehi_clear_desc(struct ata_eh_info *ehi) ehi->desc_len = 0; } +/** + * ata_port_desc - append port description + * @ap: target ATA port + * @fmt: printf format string + * + * Format string according to @fmt and append it to port + * description. If port description is not empty, " " is added + * in-between. This function is to be used while initializing + * ata_host. The description is printed on host registration. + * + * LOCKING: + * None. + */ +void ata_port_desc(struct ata_port *ap, const char *fmt, ...) +{ + va_list args; + + WARN_ON(!(ap->pflags & ATA_PFLAG_INITIALIZING)); + + if (ap->link.eh_info.desc_len) + __ata_ehi_push_desc(&ap->link.eh_info, " "); + + va_start(args, fmt); + __ata_ehi_pushv_desc(&ap->link.eh_info, fmt, args); + va_end(args); +} + +#ifdef CONFIG_PCI + +/** + * ata_port_pbar_desc - append PCI BAR description + * @ap: target ATA port + * @bar: target PCI BAR + * @offset: offset into PCI BAR + * @name: name of the area + * + * If @offset is negative, this function formats a string which + * contains the name, address, size and type of the BAR and + * appends it to the port description. If @offset is zero or + * positive, only name and offsetted address is appended. + * + * LOCKING: + * None. + */ +void ata_port_pbar_desc(struct ata_port *ap, int bar, ssize_t offset, + const char *name) +{ + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + char *type = ""; + unsigned long long start, len; + + if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM) + type = "m"; + else if (pci_resource_flags(pdev, bar) & IORESOURCE_IO) + type = "i"; + + start = (unsigned long long)pci_resource_start(pdev, bar); + len = (unsigned long long)pci_resource_len(pdev, bar); + + if (offset < 0) + ata_port_desc(ap, "%s %s%llu@0x%llx", name, type, len, start); + else + ata_port_desc(ap, "%s 0x%llx", name, start + offset); +} + +#endif /* CONFIG_PCI */ + static void ata_ering_record(struct ata_ering *ering, int is_io, unsigned int err_mask) { diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index ccef99a0337..026439e05af 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -567,6 +567,9 @@ int ata_pci_init_bmdma(struct ata_host *host) if ((!(ap->flags & ATA_FLAG_IGN_SIMPLEX)) && (ioread8(bmdma + 2) & 0x80)) host->flags |= ATA_HOST_SIMPLEX; + + ata_port_desc(ap, "bmdma 0x%llx", + (unsigned long long)pci_resource_start(pdev, 4) + 8 * i); } return 0; @@ -634,6 +637,10 @@ int ata_pci_init_sff_host(struct ata_host *host) ((unsigned long)iomap[base + 1] | ATA_PCI_CTL_OFS); ata_std_ports(&ap->ioaddr); + ata_port_desc(ap, "cmd 0x%llx ctl 0x%llx", + (unsigned long long)pci_resource_start(pdev, base), + (unsigned long long)pci_resource_start(pdev, base + 1)); + mask |= 1 << i; } @@ -804,24 +811,30 @@ int ata_pci_init_one(struct pci_dev *pdev, IRQF_SHARED, DRV_NAME, host); if (rc) goto err_out; - host->irq = pdev->irq; + + ata_port_desc(host->ports[0], "irq %d", pdev->irq); + ata_port_desc(host->ports[1], "irq %d", pdev->irq); } else { if (!ata_port_is_dummy(host->ports[0])) { - host->irq = ATA_PRIMARY_IRQ(pdev); - rc = devm_request_irq(dev, host->irq, + rc = devm_request_irq(dev, ATA_PRIMARY_IRQ(pdev), pi->port_ops->irq_handler, IRQF_SHARED, DRV_NAME, host); if (rc) goto err_out; + + ata_port_desc(host->ports[0], "irq %d", + ATA_PRIMARY_IRQ(pdev)); } if (!ata_port_is_dummy(host->ports[1])) { - host->irq2 = ATA_SECONDARY_IRQ(pdev); - rc = devm_request_irq(dev, host->irq2, + rc = devm_request_irq(dev, ATA_SECONDARY_IRQ(pdev), pi->port_ops->irq_handler, IRQF_SHARED, DRV_NAME, host); if (rc) goto err_out; + + ata_port_desc(host->ports[1], "irq %d", + ATA_SECONDARY_IRQ(pdev)); } } diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c index 1ae6b6bd856..ff1eb84c7d2 100644 --- a/drivers/ata/pata_cs5520.c +++ b/drivers/ata/pata_cs5520.c @@ -189,6 +189,8 @@ static struct ata_port_operations cs5520_port_ops = { static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_device_id *id) { + static const unsigned int cmd_port[] = { 0x1F0, 0x170 }; + static const unsigned int ctl_port[] = { 0x3F6, 0x376 }; struct ata_port_info pi = { .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, @@ -242,10 +244,10 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi } /* Map IO ports and initialize host accordingly */ - iomap[0] = devm_ioport_map(&pdev->dev, 0x1F0, 8); - iomap[1] = devm_ioport_map(&pdev->dev, 0x3F6, 1); - iomap[2] = devm_ioport_map(&pdev->dev, 0x170, 8); - iomap[3] = devm_ioport_map(&pdev->dev, 0x376, 1); + iomap[0] = devm_ioport_map(&pdev->dev, cmd_port[0], 8); + iomap[1] = devm_ioport_map(&pdev->dev, ctl_port[0], 1); + iomap[2] = devm_ioport_map(&pdev->dev, cmd_port[1], 8); + iomap[3] = devm_ioport_map(&pdev->dev, ctl_port[1], 1); iomap[4] = pcim_iomap(pdev, 2, 0); if (!iomap[0] || !iomap[1] || !iomap[2] || !iomap[3] || !iomap[4]) @@ -258,6 +260,10 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi ioaddr->bmdma_addr = iomap[4]; ata_std_ports(ioaddr); + ata_port_desc(host->ports[0], + "cmd 0x%x ctl 0x%x", cmd_port[0], ctl_port[0]); + ata_port_pbar_desc(host->ports[0], 4, 0, "bmdma"); + ioaddr = &host->ports[1]->ioaddr; ioaddr->cmd_addr = iomap[2]; ioaddr->ctl_addr = iomap[3]; @@ -265,6 +271,10 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi ioaddr->bmdma_addr = iomap[4] + 8; ata_std_ports(ioaddr); + ata_port_desc(host->ports[1], + "cmd 0x%x ctl 0x%x", cmd_port[1], ctl_port[1]); + ata_port_pbar_desc(host->ports[1], 4, 8, "bmdma"); + /* activate the host */ pci_set_master(pdev); rc = ata_host_start(host); @@ -283,10 +293,7 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi if (rc) return rc; - if (i == 0) - host->irq = irq[0]; - else - host->irq2 = irq[1]; + ata_port_desc(ap, "irq %d", irq[i]); } return ata_host_register(host, &cs5520_sht); diff --git a/drivers/ata/pata_hpt3x3.c b/drivers/ata/pata_hpt3x3.c index 188d2176ec3..cb8bdb6887d 100644 --- a/drivers/ata/pata_hpt3x3.c +++ b/drivers/ata/pata_hpt3x3.c @@ -237,7 +237,8 @@ static int hpt3x3_init_one(struct pci_dev *pdev, const struct pci_device_id *id) base = host->iomap[4]; /* Bus mastering base */ for (i = 0; i < host->n_ports; i++) { - struct ata_ioports *ioaddr = &host->ports[i]->ioaddr; + struct ata_port *ap = host->ports[i]; + struct ata_ioports *ioaddr = &ap->ioaddr; ioaddr->cmd_addr = base + offset_cmd[i]; ioaddr->altstatus_addr = @@ -245,6 +246,9 @@ static int hpt3x3_init_one(struct pci_dev *pdev, const struct pci_device_id *id) ioaddr->scr_addr = NULL; ata_std_ports(ioaddr); ioaddr->bmdma_addr = base + 8 * i; + + ata_port_pbar_desc(ap, 4, -1, "ioport"); + ata_port_pbar_desc(ap, 4, offset_cmd[i], "cmd"); } pci_set_master(pdev); return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED, diff --git a/drivers/ata/pata_icside.c b/drivers/ata/pata_icside.c index 4a69328a4c4..be30923566c 100644 --- a/drivers/ata/pata_icside.c +++ b/drivers/ata/pata_icside.c @@ -70,6 +70,8 @@ struct pata_icside_info { unsigned int mwdma_mask; unsigned int nr_ports; const struct portinfo *port[2]; + unsigned long raw_base; + unsigned long raw_ioc_base; }; #define ICS_TYPE_A3IN 0 @@ -392,9 +394,10 @@ static struct ata_port_operations pata_icside_port_ops = { }; static void __devinit -pata_icside_setup_ioaddr(struct ata_ioports *ioaddr, void __iomem *base, +pata_icside_setup_ioaddr(struct ata_port *ap, void __iomem *base, const struct portinfo *info) { + struct ata_ioports *ioaddr = &ap->ioaddr; void __iomem *cmd = base + info->dataoffset; ioaddr->cmd_addr = cmd; @@ -411,6 +414,13 @@ pata_icside_setup_ioaddr(struct ata_ioports *ioaddr, void __iomem *base, ioaddr->ctl_addr = base + info->ctrloffset; ioaddr->altstatus_addr = ioaddr->ctl_addr; + + ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", + info->raw_base + info->dataoffset, + info->raw_base + info->ctrloffset); + + if (info->raw_ioc_base) + ata_port_desc(ap, "iocbase 0x%lx", info->raw_ioc_base); } static int __devinit pata_icside_register_v5(struct pata_icside_info *info) @@ -431,6 +441,8 @@ static int __devinit pata_icside_register_v5(struct pata_icside_info *info) info->nr_ports = 1; info->port[0] = &pata_icside_portinfo_v5; + info->raw_base = ecard_resource_start(ec, ECARD_RES_MEMC); + return 0; } @@ -471,6 +483,9 @@ static int __devinit pata_icside_register_v6(struct pata_icside_info *info) info->port[0] = &pata_icside_portinfo_v6_1; info->port[1] = &pata_icside_portinfo_v6_2; + info->raw_base = ecard_resource_start(ec, ECARD_RES_EASI); + info->raw_ioc_base = ecard_resource_start(ec, ECARD_RES_IOCFAST); + return icside_dma_init(info); } @@ -507,7 +522,7 @@ static int __devinit pata_icside_add_ports(struct pata_icside_info *info) ap->flags |= ATA_FLAG_SLAVE_POSS; ap->ops = &pata_icside_port_ops; - pata_icside_setup_ioaddr(&ap->ioaddr, info->base, info->port[i]); + pata_icside_setup_ioaddr(ap, info->base, info->port[i]); } return ata_host_activate(host, ec->irq, ata_interrupt, 0, diff --git a/drivers/ata/pata_isapnp.c b/drivers/ata/pata_isapnp.c index 8ac1e8beaba..88ab0e1d353 100644 --- a/drivers/ata/pata_isapnp.c +++ b/drivers/ata/pata_isapnp.c @@ -110,6 +110,10 @@ static int isapnp_init_one(struct pnp_dev *idev, const struct pnp_device_id *dev ata_std_ports(&ap->ioaddr); + ata_port_desc(ap, "cmd 0x%llx ctl 0x%llx", + (unsigned long long)pnp_port_start(idev, 0), + (unsigned long long)pnp_port_start(idev, 1)); + /* activate */ return ata_host_activate(host, pnp_irq(idev, 0), ata_interrupt, 0, &isapnp_sht); diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c index 7b0d2fc5748..fcd532afbf2 100644 --- a/drivers/ata/pata_ixp4xx_cf.c +++ b/drivers/ata/pata_ixp4xx_cf.c @@ -131,8 +131,12 @@ static struct ata_port_operations ixp4xx_port_ops = { }; static void ixp4xx_setup_port(struct ata_ioports *ioaddr, - struct ixp4xx_pata_data *data) + struct ixp4xx_pata_data *data, + unsigned long raw_cs0, unsigned long raw_cs1) { + unsigned long raw_cmd = raw_cs0; + unsigned long raw_ctl = raw_cs1 + 0x06; + ioaddr->cmd_addr = data->cs0; ioaddr->altstatus_addr = data->cs1 + 0x06; ioaddr->ctl_addr = data->cs1 + 0x06; @@ -158,7 +162,12 @@ static void ixp4xx_setup_port(struct ata_ioports *ioaddr, *(unsigned long *)&ioaddr->device_addr ^= 0x03; *(unsigned long *)&ioaddr->status_addr ^= 0x03; *(unsigned long *)&ioaddr->command_addr ^= 0x03; + + raw_cmd ^= 0x03; + raw_ctl ^= 0x03; #endif + + ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", raw_cmd, raw_ctl); } static __devinit int ixp4xx_pata_probe(struct platform_device *pdev) @@ -203,7 +212,7 @@ static __devinit int ixp4xx_pata_probe(struct platform_device *pdev) ap->pio_mask = 0x1f; /* PIO4 */ ap->flags |= ATA_FLAG_MMIO | ATA_FLAG_NO_LEGACY | ATA_FLAG_NO_ATAPI; - ixp4xx_setup_port(&ap->ioaddr, data); + ixp4xx_setup_port(ap, data, cs0->start, cs1->start); dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n"); diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c index 6cae26f4d27..7bed8d80638 100644 --- a/drivers/ata/pata_legacy.c +++ b/drivers/ata/pata_legacy.c @@ -799,6 +799,8 @@ static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl ata_std_ports(&ap->ioaddr); ap->private_data = ld; + ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", io, ctrl); + ret = ata_host_activate(host, irq, ata_interrupt, 0, &legacy_sht); if (ret) goto fail; diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c index a56694b2833..412140f0285 100644 --- a/drivers/ata/pata_mpc52xx.c +++ b/drivers/ata/pata_mpc52xx.c @@ -302,7 +302,8 @@ static struct ata_port_operations mpc52xx_ata_port_ops = { }; static int __devinit -mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv) +mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv, + unsigned long raw_ata_regs) { struct ata_host *host; struct ata_port *ap; @@ -336,6 +337,8 @@ mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv) aio->status_addr = &priv->ata_regs->tf_command; aio->command_addr = &priv->ata_regs->tf_command; + ata_port_desc(ap, "ata_regs 0x%lx", raw_ata_regs); + /* activate host */ return ata_host_activate(host, priv->ata_irq, ata_interrupt, 0, &mpc52xx_ata_sht); @@ -432,7 +435,7 @@ mpc52xx_ata_probe(struct of_device *op, const struct of_device_id *match) } /* Register ourselves to libata */ - rv = mpc52xx_ata_init_one(&op->dev, priv); + rv = mpc52xx_ata_init_one(&op->dev, priv, res_mem.start); if (rv) { printk(KERN_ERR DRV_NAME ": " "Error while registering to ATA layer\n"); diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c index cb78b7bfe14..d5483087a3f 100644 --- a/drivers/ata/pata_mpiix.c +++ b/drivers/ata/pata_mpiix.c @@ -201,7 +201,7 @@ static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id) struct ata_port *ap; void __iomem *cmd_addr, *ctl_addr; u16 idetim; - int irq; + int cmd, ctl, irq; if (!printed_version++) dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n"); @@ -209,6 +209,7 @@ static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id) host = ata_host_alloc(&dev->dev, 1); if (!host) return -ENOMEM; + ap = host->ports[0]; /* MPIIX has many functions which can be turned on or off according to other devices present. Make sure IDE is enabled before we try @@ -220,25 +221,28 @@ static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id) /* See if it's primary or secondary channel... */ if (!(idetim & SECONDARY)) { + cmd = 0x1F0; + ctl = 0x3F6; irq = 14; - cmd_addr = devm_ioport_map(&dev->dev, 0x1F0, 8); - ctl_addr = devm_ioport_map(&dev->dev, 0x3F6, 1); } else { + cmd = 0x170; + ctl = 0x376; irq = 15; - cmd_addr = devm_ioport_map(&dev->dev, 0x170, 8); - ctl_addr = devm_ioport_map(&dev->dev, 0x376, 1); } + cmd_addr = devm_ioport_map(&dev->dev, cmd, 8); + ctl_addr = devm_ioport_map(&dev->dev, ctl, 1); if (!cmd_addr || !ctl_addr) return -ENOMEM; + ata_port_desc(ap, "cmd 0x%x ctl 0x%x", cmd, ctl); + /* We do our own plumbing to avoid leaking special cases for whacko ancient hardware into the core code. There are two issues to worry about. #1 The chip is a bridge so if in legacy mode and without BARs set fools the setup. #2 If you pci_disable_device the MPIIX your box goes castors up */ - ap = host->ports[0]; ap->ops = &mpiix_port_ops; ap->pio_mask = 0x1F; ap->flags |= ATA_FLAG_SLAVE_POSS; diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c index 5baf531f652..782ff4ada9d 100644 --- a/drivers/ata/pata_pcmcia.c +++ b/drivers/ata/pata_pcmcia.c @@ -302,6 +302,8 @@ next_entry: ap->ioaddr.ctl_addr = ctl_addr; ata_std_ports(&ap->ioaddr); + ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", io_base, ctl_base); + /* activate */ ret = ata_host_activate(host, pdev->irq.AssignedIRQ, ata_interrupt, IRQF_SHARED, &pcmcia_sht); diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c index 2141a99e4da..f87c800be7f 100644 --- a/drivers/ata/pata_pdc2027x.c +++ b/drivers/ata/pata_pdc2027x.c @@ -782,12 +782,14 @@ static void pdc_ata_setup_port(struct ata_ioports *port, void __iomem *base) static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version; + static const unsigned long cmd_offset[] = { 0x17c0, 0x15c0 }; + static const unsigned long bmdma_offset[] = { 0x1000, 0x1008 }; unsigned int board_idx = (unsigned int) ent->driver_data; const struct ata_port_info *ppi[] = { &pdc2027x_port_info[board_idx], NULL }; struct ata_host *host; void __iomem *mmio_base; - int rc; + int i, rc; if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); @@ -817,10 +819,15 @@ static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_de mmio_base = host->iomap[PDC_MMIO_BAR]; - pdc_ata_setup_port(&host->ports[0]->ioaddr, mmio_base + 0x17c0); - host->ports[0]->ioaddr.bmdma_addr = mmio_base + 0x1000; - pdc_ata_setup_port(&host->ports[1]->ioaddr, mmio_base + 0x15c0); - host->ports[1]->ioaddr.bmdma_addr = mmio_base + 0x1008; + for (i = 0; i < 2; i++) { + struct ata_port *ap = host->ports[i]; + + pdc_ata_setup_port(&ap->ioaddr, mmio_base + cmd_offset[i]); + ap->ioaddr.bmdma_addr = mmio_base + bmdma_offset[i]; + + ata_port_pbar_desc(ap, PDC_MMIO_BAR, -1, "mmio"); + ata_port_pbar_desc(ap, PDC_MMIO_BAR, cmd_offset[i], "cmd"); + } //pci_enable_intx(pdev); diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c index b04ce5f9841..fc72a965643 100644 --- a/drivers/ata/pata_platform.c +++ b/drivers/ata/pata_platform.c @@ -208,6 +208,10 @@ static int __devinit pata_platform_probe(struct platform_device *pdev) pp_info = pdev->dev.platform_data; pata_platform_setup_port(&ap->ioaddr, pp_info); + ata_port_desc(ap, "%s cmd 0x%llx ctl 0x%llx", mmio ? "mmio" : "ioport", + (unsigned long long)io_res->start, + (unsigned long long)ctl_res->start); + /* activate */ return ata_host_activate(host, platform_get_irq(pdev, 0), ata_interrupt, pp_info ? pp_info->irq_flags diff --git a/drivers/ata/pata_qdi.c b/drivers/ata/pata_qdi.c index 032fa67acc8..7d4c696c4cb 100644 --- a/drivers/ata/pata_qdi.c +++ b/drivers/ata/pata_qdi.c @@ -234,6 +234,7 @@ static struct ata_port_operations qdi6580_port_ops = { static __init int qdi_init_one(unsigned long port, int type, unsigned long io, int irq, int fast) { + unsigned long ctl = io + 0x206; struct platform_device *pdev; struct ata_host *host; struct ata_port *ap; @@ -250,7 +251,7 @@ static __init int qdi_init_one(unsigned long port, int type, unsigned long io, i ret = -ENOMEM; io_addr = devm_ioport_map(&pdev->dev, io, 8); - ctl_addr = devm_ioport_map(&pdev->dev, io + 0x206, 1); + ctl_addr = devm_ioport_map(&pdev->dev, ctl, 1); if (!io_addr || !ctl_addr) goto fail; @@ -275,6 +276,8 @@ static __init int qdi_init_one(unsigned long port, int type, unsigned long io, i ap->ioaddr.ctl_addr = ctl_addr; ata_std_ports(&ap->ioaddr); + ata_port_desc(ap, "cmd %lx ctl %lx", io, ctl); + /* * Hook in a private data structure per channel */ diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c index e138343b5d4..2153def3f34 100644 --- a/drivers/ata/pata_scc.c +++ b/drivers/ata/pata_scc.c @@ -1159,6 +1159,9 @@ static int scc_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) return rc; host->iomap = pcim_iomap_table(pdev); + ata_port_pbar_desc(host->ports[0], SCC_CTRL_BAR, -1, "ctrl"); + ata_port_pbar_desc(host->ports[0], SCC_BMID_BAR, -1, "bmid"); + rc = scc_host_init(host); if (rc) return rc; diff --git a/drivers/ata/pata_winbond.c b/drivers/ata/pata_winbond.c index 553658bacce..549cbbe9fd0 100644 --- a/drivers/ata/pata_winbond.c +++ b/drivers/ata/pata_winbond.c @@ -197,6 +197,7 @@ static __init int winbond_init_one(unsigned long port) for (i = 0; i < 2 ; i ++) { unsigned long cmd_port = 0x1F0 - (0x80 * i); + unsigned long ctl_port = cmd_port + 0x206; struct ata_host *host; struct ata_port *ap; void __iomem *cmd_addr, *ctl_addr; @@ -212,14 +213,16 @@ static __init int winbond_init_one(unsigned long port) host = ata_host_alloc(&pdev->dev, 1); if (!host) goto err_unregister; + ap = host->ports[0]; rc = -ENOMEM; cmd_addr = devm_ioport_map(&pdev->dev, cmd_port, 8); - ctl_addr = devm_ioport_map(&pdev->dev, cmd_port + 0x0206, 1); + ctl_addr = devm_ioport_map(&pdev->dev, ctl_port, 1); if (!cmd_addr || !ctl_addr) goto err_unregister; - ap = host->ports[0]; + ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", cmd_port, ctl_port); + ap->ops = &winbond_port_ops; ap->pio_mask = 0x1F; ap->flags |= ATA_FLAG_SLAVE_POSS; diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c index 42fd15aaba0..8d1b03d5bcb 100644 --- a/drivers/ata/pdc_adma.c +++ b/drivers/ata/pdc_adma.c @@ -704,9 +704,16 @@ static int adma_ata_init_one(struct pci_dev *pdev, if (rc) return rc; - for (port_no = 0; port_no < ADMA_PORTS; ++port_no) - adma_ata_setup_port(&host->ports[port_no]->ioaddr, - ADMA_ATA_REGS(mmio_base, port_no)); + for (port_no = 0; port_no < ADMA_PORTS; ++port_no) { + struct ata_port *ap = host->ports[port_no]; + void __iomem *port_base = ADMA_ATA_REGS(mmio_base, port_no); + unsigned int offset = port_base - mmio_base; + + adma_ata_setup_port(&ap->ioaddr, port_base); + + ata_port_pbar_desc(ap, ADMA_MMIO_BAR, -1, "mmio"); + ata_port_pbar_desc(ap, ADMA_MMIO_BAR, offset, "port"); + } /* initialize adapter */ adma_host_init(host, board_idx); diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c index f0ea0e166c1..08595f34b3e 100644 --- a/drivers/ata/sata_inic162x.c +++ b/drivers/ata/sata_inic162x.c @@ -693,16 +693,24 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) host->iomap = iomap = pcim_iomap_table(pdev); for (i = 0; i < NR_PORTS; i++) { - struct ata_ioports *port = &host->ports[i]->ioaddr; - void __iomem *port_base = iomap[MMIO_BAR] + i * PORT_SIZE; + struct ata_port *ap = host->ports[i]; + struct ata_ioports *port = &ap->ioaddr; + unsigned int offset = i * PORT_SIZE; port->cmd_addr = iomap[2 * i]; port->altstatus_addr = port->ctl_addr = (void __iomem *) ((unsigned long)iomap[2 * i + 1] | ATA_PCI_CTL_OFS); - port->scr_addr = port_base + PORT_SCR; + port->scr_addr = iomap[MMIO_BAR] + offset + PORT_SCR; ata_std_ports(port); + + ata_port_pbar_desc(ap, MMIO_BAR, -1, "mmio"); + ata_port_pbar_desc(ap, MMIO_BAR, offset, "port"); + ata_port_desc(ap, "cmd 0x%llx ctl 0x%llx", + (unsigned long long)pci_resource_start(pdev, 2 * i), + (unsigned long long)pci_resource_start(pdev, (2 * i + 1)) | + ATA_PCI_CTL_OFS); } hpriv->cached_hctl = readw(iomap[MMIO_BAR] + HOST_CTL); diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 68c3f22890d..08077efa9af 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -2584,8 +2584,14 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx) } for (port = 0; port < host->n_ports; port++) { + struct ata_port *ap = host->ports[port]; void __iomem *port_mmio = mv_port_base(mmio, port); - mv_port_init(&host->ports[port]->ioaddr, port_mmio); + unsigned int offset = port_mmio - mmio; + + mv_port_init(&ap->ioaddr, port_mmio); + + ata_port_pbar_desc(ap, MV_PRIMARY_BAR, -1, "mmio"); + ata_port_pbar_desc(ap, MV_PRIMARY_BAR, offset, "port"); } for (hc = 0; hc < n_hc; hc++) { diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c index 983bff5c4de..903213153b5 100644 --- a/drivers/ata/sata_promise.c +++ b/drivers/ata/sata_promise.c @@ -1003,10 +1003,15 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e is_sataii_tx4 = pdc_is_sataii_tx4(pi->flags); for (i = 0; i < host->n_ports; i++) { + struct ata_port *ap = host->ports[i]; unsigned int ata_no = pdc_port_no_to_ata_no(i, is_sataii_tx4); - pdc_ata_setup_port(host->ports[i], - base + 0x200 + ata_no * 0x80, - base + 0x400 + ata_no * 0x100); + unsigned int port_offset = 0x200 + ata_no * 0x80; + unsigned int scr_offset = 0x400 + ata_no * 0x100; + + pdc_ata_setup_port(ap, base + port_offset, base + scr_offset); + + ata_port_pbar_desc(ap, PDC_MMIO_BAR, -1, "mmio"); + ata_port_pbar_desc(ap, PDC_MMIO_BAR, port_offset, "port"); } /* initialize adapter */ diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c index 10bf52ca1e1..c4c4cd29eeb 100644 --- a/drivers/ata/sata_qstor.c +++ b/drivers/ata/sata_qstor.c @@ -635,9 +635,14 @@ static int qs_ata_init_one(struct pci_dev *pdev, return rc; for (port_no = 0; port_no < host->n_ports; ++port_no) { - void __iomem *chan = - host->iomap[QS_MMIO_BAR] + (port_no * 0x4000); - qs_ata_setup_port(&host->ports[port_no]->ioaddr, chan); + struct ata_port *ap = host->ports[port_no]; + unsigned int offset = port_no * 0x4000; + void __iomem *chan = host->iomap[QS_MMIO_BAR] + offset; + + qs_ata_setup_port(&ap->ioaddr, chan); + + ata_port_pbar_desc(ap, QS_MMIO_BAR, -1, "mmio"); + ata_port_pbar_desc(ap, QS_MMIO_BAR, offset, "port"); } /* initialize adapter */ diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index df0ac77fcdd..ea3a0ab7e02 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -687,7 +687,8 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) mmio_base = host->iomap[SIL_MMIO_BAR]; for (i = 0; i < host->n_ports; i++) { - struct ata_ioports *ioaddr = &host->ports[i]->ioaddr; + struct ata_port *ap = host->ports[i]; + struct ata_ioports *ioaddr = &ap->ioaddr; ioaddr->cmd_addr = mmio_base + sil_port[i].tf; ioaddr->altstatus_addr = @@ -695,6 +696,9 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) ioaddr->bmdma_addr = mmio_base + sil_port[i].bmdma; ioaddr->scr_addr = mmio_base + sil_port[i].scr; ata_std_ports(ioaddr); + + ata_port_pbar_desc(ap, SIL_MMIO_BAR, -1, "mmio"); + ata_port_pbar_desc(ap, SIL_MMIO_BAR, sil_port[i].tf, "tf"); } /* initialize and activate */ diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index e0cd31aa800..3dcb223117b 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -1119,12 +1119,15 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) host->iomap = iomap; for (i = 0; i < host->n_ports; i++) { - void __iomem *port = iomap[SIL24_PORT_BAR] + i * PORT_REGS_SIZE; + struct ata_port *ap = host->ports[i]; + size_t offset = ap->port_no * PORT_REGS_SIZE; + void __iomem *port = iomap[SIL24_PORT_BAR] + offset; host->ports[i]->ioaddr.cmd_addr = port; host->ports[i]->ioaddr.scr_addr = port + PORT_SCONTROL; - ata_std_ports(&host->ports[i]->ioaddr); + ata_port_pbar_desc(ap, SIL24_HOST_BAR, -1, "host"); + ata_port_pbar_desc(ap, SIL24_PORT_BAR, offset, "port"); } /* configure and activate the device */ diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c index 822cabfec95..12d613c48c1 100644 --- a/drivers/ata/sata_svw.c +++ b/drivers/ata/sata_svw.c @@ -443,9 +443,15 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e /* different controllers have different number of ports - currently 4 or 8 */ /* All ports are on the same function. Multi-function device is no * longer available. This should not be seen in any system. */ - for (i = 0; i < host->n_ports; i++) - k2_sata_setup_port(&host->ports[i]->ioaddr, - mmio_base + i * K2_SATA_PORT_OFFSET); + for (i = 0; i < host->n_ports; i++) { + struct ata_port *ap = host->ports[i]; + unsigned int offset = i * K2_SATA_PORT_OFFSET; + + k2_sata_setup_port(&ap->ioaddr, mmio_base + offset); + + ata_port_pbar_desc(ap, 5, -1, "mmio"); + ata_port_pbar_desc(ap, 5, offset, "port"); + } rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); if (rc) diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c index b425061dbe8..9f9f7b30654 100644 --- a/drivers/ata/sata_sx4.c +++ b/drivers/ata/sata_sx4.c @@ -1381,9 +1381,8 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id * const struct ata_port_info *ppi[] = { &pdc_port_info[ent->driver_data], NULL }; struct ata_host *host; - void __iomem *base; struct pdc_host_priv *hpriv; - int rc; + int i, rc; if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); @@ -1409,11 +1408,17 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id * return rc; host->iomap = pcim_iomap_table(pdev); - base = host->iomap[PDC_MMIO_BAR] + PDC_CHIP0_OFS; - pdc_sata_setup_port(&host->ports[0]->ioaddr, base + 0x200); - pdc_sata_setup_port(&host->ports[1]->ioaddr, base + 0x280); - pdc_sata_setup_port(&host->ports[2]->ioaddr, base + 0x300); - pdc_sata_setup_port(&host->ports[3]->ioaddr, base + 0x380); + for (i = 0; i < 4; i++) { + struct ata_port *ap = host->ports[i]; + void __iomem *base = host->iomap[PDC_MMIO_BAR] + PDC_CHIP0_OFS; + unsigned int offset = 0x200 + i * 0x80; + + pdc_sata_setup_port(&ap->ioaddr, base + offset); + + ata_port_pbar_desc(ap, PDC_MMIO_BAR, -1, "mmio"); + ata_port_pbar_desc(ap, PDC_DIMM_BAR, -1, "dimm"); + ata_port_pbar_desc(ap, PDC_MMIO_BAR, offset, "port"); + } /* configure and activate */ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); diff --git a/drivers/ata/sata_uli.c b/drivers/ata/sata_uli.c index 6c53a790805..d394da085ae 100644 --- a/drivers/ata/sata_uli.c +++ b/drivers/ata/sata_uli.c @@ -239,6 +239,12 @@ static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) hpriv->scr_cfg_addr[2] = ULI5287_BASE + ULI5287_OFFS*4; ata_std_ports(ioaddr); + ata_port_desc(host->ports[2], + "cmd 0x%llx ctl 0x%llx bmdma 0x%llx", + (unsigned long long)pci_resource_start(pdev, 0) + 8, + ((unsigned long long)pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS) + 4, + (unsigned long long)pci_resource_start(pdev, 4) + 16); + ioaddr = &host->ports[3]->ioaddr; ioaddr->cmd_addr = iomap[2] + 8; ioaddr->altstatus_addr = @@ -247,6 +253,13 @@ static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) ioaddr->bmdma_addr = iomap[4] + 24; hpriv->scr_cfg_addr[3] = ULI5287_BASE + ULI5287_OFFS*5; ata_std_ports(ioaddr); + + ata_port_desc(host->ports[2], + "cmd 0x%llx ctl 0x%llx bmdma 0x%llx", + (unsigned long long)pci_resource_start(pdev, 2) + 9, + ((unsigned long long)pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS) + 4, + (unsigned long long)pci_resource_start(pdev, 4) + 24); + break; case uli_5289: diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index 25162ec9938..f0757023ce9 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c @@ -399,6 +399,9 @@ static void vt6421_init_addrs(struct ata_port *ap) ioaddr->scr_addr = vt6421_scr_addr(iomap[5], ap->port_no); ata_std_ports(ioaddr); + + ata_port_pbar_desc(ap, ap->port_no, -1, "port"); + ata_port_pbar_desc(ap, 4, ap->port_no * 8, "bmdma"); } static int vt6420_prepare_host(struct pci_dev *pdev, struct ata_host **r_host) diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c index b1777c3f6d5..0d9be168487 100644 --- a/drivers/ata/sata_vsc.c +++ b/drivers/ata/sata_vsc.c @@ -406,9 +406,15 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d mmio_base = host->iomap[VSC_MMIO_BAR]; - for (i = 0; i < host->n_ports; i++) - vsc_sata_setup_port(&host->ports[i]->ioaddr, - mmio_base + (i + 1) * VSC_SATA_PORT_OFFSET); + for (i = 0; i < host->n_ports; i++) { + struct ata_port *ap = host->ports[i]; + unsigned int offset = (i + 1) * VSC_SATA_PORT_OFFSET; + + vsc_sata_setup_port(&ap->ioaddr, mmio_base + offset); + + ata_port_pbar_desc(ap, VSC_MMIO_BAR, -1, "mmio"); + ata_port_pbar_desc(ap, VSC_MMIO_BAR, offset, "port"); + } /* * Use 32 bit DMA mask, because 64 bit address support is poor. diff --git a/include/linux/libata.h b/include/linux/libata.h index e7d163edb4c..d3defae689c 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -368,8 +368,6 @@ struct ata_ioports { struct ata_host { spinlock_t lock; struct device *dev; - unsigned long irq; - unsigned long irq2; void __iomem * const *iomap; unsigned int n_ports; void *private_data; @@ -968,6 +966,16 @@ static inline void ata_ehi_hotplugged(struct ata_eh_info *ehi) ehi->err_mask |= AC_ERR_ATA_BUS; } +/* + * port description helpers + */ +extern void ata_port_desc(struct ata_port *ap, const char *fmt, ...) + __attribute__ ((format (printf, 2, 3))); +#ifdef CONFIG_PCI +extern void ata_port_pbar_desc(struct ata_port *ap, int bar, ssize_t offset, + const char *name); +#endif + /* * qc helpers */ -- cgit v1.2.3-70-g09d2 From a1e10f7e68a544c80081fee4fa550dc28389f44a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 18 Aug 2007 13:28:49 +0900 Subject: libata: move EH repeat reporting into ata_eh_report() EH is sometimes repeated without any error or action. For example, this happens when probing IDENTIFY fails because of a phantom device. In these cases, all the repeated EH does is making sure there is no unhandled error or pending action and return. This repeation is necessary to avoid losing any event which occurred while EH was in progress. Unfortunately, this dry run causes annonying "EH pending after completion" message. This patch moves the repeat reporting into ata_eh_report() such that it's more compact and skipped on dry runs. Signed-off-by: Tejun Heo Cc: Mikael Pettersson Signed-off-by: Jeff Garzik --- drivers/ata/libata-eh.c | 30 ++++++++++++++++++------------ include/linux/libata.h | 5 +++-- 2 files changed, 21 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 8219e2d7104..daa2f74f73c 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -358,7 +358,7 @@ enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd) void ata_scsi_error(struct Scsi_Host *host) { struct ata_port *ap = ata_shost_to_port(host); - int i, repeat_cnt = ATA_EH_MAX_REPEAT; + int i; unsigned long flags; DPRINTK("ENTER\n"); @@ -424,6 +424,9 @@ void ata_scsi_error(struct Scsi_Host *host) __ata_port_freeze(ap); spin_unlock_irqrestore(ap->lock, flags); + + /* initialize eh_tries */ + ap->eh_tries = ATA_EH_MAX_TRIES; } else spin_unlock_wait(ap->lock); @@ -468,15 +471,12 @@ void ata_scsi_error(struct Scsi_Host *host) spin_lock_irqsave(ap->lock, flags); if (ap->pflags & ATA_PFLAG_EH_PENDING) { - if (--repeat_cnt) { - ata_port_printk(ap, KERN_INFO, - "EH pending after completion, " - "repeating EH (cnt=%d)\n", repeat_cnt); + if (--ap->eh_tries) { spin_unlock_irqrestore(ap->lock, flags); goto repeat; } ata_port_printk(ap, KERN_ERR, "EH pending after %d " - "tries, giving up\n", ATA_EH_MAX_REPEAT); + "tries, giving up\n", ATA_EH_MAX_TRIES); ap->pflags &= ~ATA_PFLAG_EH_PENDING; } @@ -1778,6 +1778,7 @@ static void ata_eh_link_report(struct ata_link *link) struct ata_port *ap = link->ap; struct ata_eh_context *ehc = &link->eh_context; const char *frozen, *desc; + char tries_buf[6]; int tag, nr_failed = 0; desc = NULL; @@ -1802,18 +1803,23 @@ static void ata_eh_link_report(struct ata_link *link) if (ap->pflags & ATA_PFLAG_FROZEN) frozen = " frozen"; + memset(tries_buf, 0, sizeof(tries_buf)); + if (ap->eh_tries < ATA_EH_MAX_TRIES) + snprintf(tries_buf, sizeof(tries_buf) - 1, " t%d", + ap->eh_tries); + if (ehc->i.dev) { ata_dev_printk(ehc->i.dev, KERN_ERR, "exception Emask 0x%x " - "SAct 0x%x SErr 0x%x action 0x%x%s\n", - ehc->i.err_mask, link->sactive, - ehc->i.serror, ehc->i.action, frozen); + "SAct 0x%x SErr 0x%x action 0x%x%s%s\n", + ehc->i.err_mask, link->sactive, ehc->i.serror, + ehc->i.action, frozen, tries_buf); if (desc) ata_dev_printk(ehc->i.dev, KERN_ERR, "%s\n", desc); } else { ata_link_printk(link, KERN_ERR, "exception Emask 0x%x " - "SAct 0x%x SErr 0x%x action 0x%x%s\n", - ehc->i.err_mask, link->sactive, - ehc->i.serror, ehc->i.action, frozen); + "SAct 0x%x SErr 0x%x action 0x%x%s%s\n", + ehc->i.err_mask, link->sactive, ehc->i.serror, + ehc->i.action, frozen, tries_buf); if (desc) ata_link_printk(link, KERN_ERR, "%s\n", desc); } diff --git a/include/linux/libata.h b/include/linux/libata.h index d3defae689c..74e034ea901 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -293,8 +293,8 @@ enum { ATA_EHI_DID_RESET = ATA_EHI_DID_SOFTRESET | ATA_EHI_DID_HARDRESET, ATA_EHI_RESET_MODIFIER_MASK = ATA_EHI_RESUME_LINK, - /* max repeat if error condition is still set after ->error_handler */ - ATA_EH_MAX_REPEAT = 5, + /* max tries if error condition is still set after ->error_handler */ + ATA_EH_MAX_TRIES = 5, /* how hard are we gonna try to probe/recover devices */ ATA_PROBE_MAX_TRIES = 3, @@ -581,6 +581,7 @@ struct ata_port { u32 msg_enable; struct list_head eh_done_q; wait_queue_head_t eh_wait_q; + int eh_tries; pm_message_t pm_mesg; int *pm_result; -- cgit v1.2.3-70-g09d2 From d830d1731fa5906aad20c228ac8b73005b13d468 Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Tue, 21 Aug 2007 13:12:31 +0800 Subject: libata driver for bf548 on chip ATAPI controller. Fix all issues pointed out in Jeff's email. Acked-by: Alan Cox Signed-off-by: Sonic Zhang Signed-off-by: Jeff Garzik --- drivers/ata/Kconfig | 16 + drivers/ata/Makefile | 1 + drivers/ata/pata_bf54x.c | 1627 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1644 insertions(+) create mode 100644 drivers/ata/pata_bf54x.c (limited to 'drivers') diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index d8046a113c3..a427945f0bb 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -596,4 +596,20 @@ config PATA_SCC If unsure, say N. +config PATA_BF54X + tristate "Blackfin 54x ATAPI support" + depends on BF542 || BF548 || BF549 + help + This option enables support for the built-in ATAPI controller on + Blackfin 54x family chips. + + If unsure, say N. + +config PATA_BF54X_DMA + bool "DMA mode" + depends on PATA_BF54X + default y + help + Enable DMA mode for Blackfin ATAPI controller. + endif # ATA diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 8149c68ac2c..c2ecba5f0b4 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -61,6 +61,7 @@ obj-$(CONFIG_PATA_SIS) += pata_sis.o obj-$(CONFIG_PATA_TRIFLEX) += pata_triflex.o obj-$(CONFIG_PATA_IXP4XX_CF) += pata_ixp4xx_cf.o obj-$(CONFIG_PATA_SCC) += pata_scc.o +obj-$(CONFIG_PATA_BF54X) += pata_bf54x.o obj-$(CONFIG_PATA_PLATFORM) += pata_platform.o obj-$(CONFIG_PATA_ICSIDE) += pata_icside.o # Should be last but one libata driver diff --git a/drivers/ata/pata_bf54x.c b/drivers/ata/pata_bf54x.c new file mode 100644 index 00000000000..747549e4563 --- /dev/null +++ b/drivers/ata/pata_bf54x.c @@ -0,0 +1,1627 @@ +/* + * File: drivers/ata/pata_bf54x.c + * Author: Sonic Zhang + * + * Created: + * Description: PATA Driver for blackfin 54x + * + * Modified: + * Copyright 2007 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "pata-bf54x" +#define DRV_VERSION "0.9" + +#define ATA_REG_CTRL 0x0E +#define ATA_REG_ALTSTATUS ATA_REG_CTRL + +/* These are the offset of the controller's registers */ +#define ATAPI_OFFSET_CONTROL 0x00 +#define ATAPI_OFFSET_STATUS 0x04 +#define ATAPI_OFFSET_DEV_ADDR 0x08 +#define ATAPI_OFFSET_DEV_TXBUF 0x0c +#define ATAPI_OFFSET_DEV_RXBUF 0x10 +#define ATAPI_OFFSET_INT_MASK 0x14 +#define ATAPI_OFFSET_INT_STATUS 0x18 +#define ATAPI_OFFSET_XFER_LEN 0x1c +#define ATAPI_OFFSET_LINE_STATUS 0x20 +#define ATAPI_OFFSET_SM_STATE 0x24 +#define ATAPI_OFFSET_TERMINATE 0x28 +#define ATAPI_OFFSET_PIO_TFRCNT 0x2c +#define ATAPI_OFFSET_DMA_TFRCNT 0x30 +#define ATAPI_OFFSET_UMAIN_TFRCNT 0x34 +#define ATAPI_OFFSET_UDMAOUT_TFRCNT 0x38 +#define ATAPI_OFFSET_REG_TIM_0 0x40 +#define ATAPI_OFFSET_PIO_TIM_0 0x44 +#define ATAPI_OFFSET_PIO_TIM_1 0x48 +#define ATAPI_OFFSET_MULTI_TIM_0 0x50 +#define ATAPI_OFFSET_MULTI_TIM_1 0x54 +#define ATAPI_OFFSET_MULTI_TIM_2 0x58 +#define ATAPI_OFFSET_ULTRA_TIM_0 0x60 +#define ATAPI_OFFSET_ULTRA_TIM_1 0x64 +#define ATAPI_OFFSET_ULTRA_TIM_2 0x68 +#define ATAPI_OFFSET_ULTRA_TIM_3 0x6c + + +#define ATAPI_GET_CONTROL(base)\ + bfin_read16(base + ATAPI_OFFSET_CONTROL) +#define ATAPI_SET_CONTROL(base, val)\ + bfin_write16(base + ATAPI_OFFSET_CONTROL, val) +#define ATAPI_GET_STATUS(base)\ + bfin_read16(base + ATAPI_OFFSET_STATUS) +#define ATAPI_GET_DEV_ADDR(base)\ + bfin_read16(base + ATAPI_OFFSET_DEV_ADDR) +#define ATAPI_SET_DEV_ADDR(base, val)\ + bfin_write16(base + ATAPI_OFFSET_DEV_ADDR, val) +#define ATAPI_GET_DEV_TXBUF(base)\ + bfin_read16(base + ATAPI_OFFSET_DEV_TXBUF) +#define ATAPI_SET_DEV_TXBUF(base, val)\ + bfin_write16(base + ATAPI_OFFSET_DEV_TXBUF, val) +#define ATAPI_GET_DEV_RXBUF(base)\ + bfin_read16(base + ATAPI_OFFSET_DEV_RXBUF) +#define ATAPI_SET_DEV_RXBUF(base, val)\ + bfin_write16(base + ATAPI_OFFSET_DEV_RXBUF, val) +#define ATAPI_GET_INT_MASK(base)\ + bfin_read16(base + ATAPI_OFFSET_INT_MASK) +#define ATAPI_SET_INT_MASK(base, val)\ + bfin_write16(base + ATAPI_OFFSET_INT_MASK, val) +#define ATAPI_GET_INT_STATUS(base)\ + bfin_read16(base + ATAPI_OFFSET_INT_STATUS) +#define ATAPI_SET_INT_STATUS(base, val)\ + bfin_write16(base + ATAPI_OFFSET_INT_STATUS, val) +#define ATAPI_GET_XFER_LEN(base)\ + bfin_read16(base + ATAPI_OFFSET_XFER_LEN) +#define ATAPI_SET_XFER_LEN(base, val)\ + bfin_write16(base + ATAPI_OFFSET_XFER_LEN, val) +#define ATAPI_GET_LINE_STATUS(base)\ + bfin_read16(base + ATAPI_OFFSET_LINE_STATUS) +#define ATAPI_GET_SM_STATE(base)\ + bfin_read16(base + ATAPI_OFFSET_SM_STATE) +#define ATAPI_GET_TERMINATE(base)\ + bfin_read16(base + ATAPI_OFFSET_TERMINATE) +#define ATAPI_SET_TERMINATE(base, val)\ + bfin_write16(base + ATAPI_OFFSET_TERMINATE, val) +#define ATAPI_GET_PIO_TFRCNT(base)\ + bfin_read16(base + ATAPI_OFFSET_PIO_TFRCNT) +#define ATAPI_GET_DMA_TFRCNT(base)\ + bfin_read16(base + ATAPI_OFFSET_DMA_TFRCNT) +#define ATAPI_GET_UMAIN_TFRCNT(base)\ + bfin_read16(base + ATAPI_OFFSET_UMAIN_TFRCNT) +#define ATAPI_GET_UDMAOUT_TFRCNT(base)\ + bfin_read16(base + ATAPI_OFFSET_UDMAOUT_TFRCNT) +#define ATAPI_GET_REG_TIM_0(base)\ + bfin_read16(base + ATAPI_OFFSET_REG_TIM_0) +#define ATAPI_SET_REG_TIM_0(base, val)\ + bfin_write16(base + ATAPI_OFFSET_REG_TIM_0, val) +#define ATAPI_GET_PIO_TIM_0(base)\ + bfin_read16(base + ATAPI_OFFSET_PIO_TIM_0) +#define ATAPI_SET_PIO_TIM_0(base, val)\ + bfin_write16(base + ATAPI_OFFSET_PIO_TIM_0, val) +#define ATAPI_GET_PIO_TIM_1(base)\ + bfin_read16(base + ATAPI_OFFSET_PIO_TIM_1) +#define ATAPI_SET_PIO_TIM_1(base, val)\ + bfin_write16(base + ATAPI_OFFSET_PIO_TIM_1, val) +#define ATAPI_GET_MULTI_TIM_0(base)\ + bfin_read16(base + ATAPI_OFFSET_MULTI_TIM_0) +#define ATAPI_SET_MULTI_TIM_0(base, val)\ + bfin_write16(base + ATAPI_OFFSET_MULTI_TIM_0, val) +#define ATAPI_GET_MULTI_TIM_1(base)\ + bfin_read16(base + ATAPI_OFFSET_MULTI_TIM_1) +#define ATAPI_SET_MULTI_TIM_1(base, val)\ + bfin_write16(base + ATAPI_OFFSET_MULTI_TIM_1, val) +#define ATAPI_GET_MULTI_TIM_2(base)\ + bfin_read16(base + ATAPI_OFFSET_MULTI_TIM_2) +#define ATAPI_SET_MULTI_TIM_2(base, val)\ + bfin_write16(base + ATAPI_OFFSET_MULTI_TIM_2, val) +#define ATAPI_GET_ULTRA_TIM_0(base)\ + bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_0) +#define ATAPI_SET_ULTRA_TIM_0(base, val)\ + bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_0, val) +#define ATAPI_GET_ULTRA_TIM_1(base)\ + bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_1) +#define ATAPI_SET_ULTRA_TIM_1(base, val)\ + bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_1, val) +#define ATAPI_GET_ULTRA_TIM_2(base)\ + bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_2) +#define ATAPI_SET_ULTRA_TIM_2(base, val)\ + bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_2, val) +#define ATAPI_GET_ULTRA_TIM_3(base)\ + bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_3) +#define ATAPI_SET_ULTRA_TIM_3(base, val)\ + bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_3, val) + +/** + * PIO Mode - Frequency compatibility + */ +/* mode: 0 1 2 3 4 */ +static const u32 pio_fsclk[] = +{ 33333333, 33333333, 33333333, 33333333, 33333333 }; + +/** + * MDMA Mode - Frequency compatibility + */ +/* mode: 0 1 2 */ +static const u32 mdma_fsclk[] = { 33333333, 33333333, 33333333 }; + +/** + * UDMA Mode - Frequency compatibility + * + * UDMA5 - 100 MB/s - SCLK = 133 MHz + * UDMA4 - 66 MB/s - SCLK >= 80 MHz + * UDMA3 - 44.4 MB/s - SCLK >= 50 MHz + * UDMA2 - 33 MB/s - SCLK >= 40 MHz + */ +/* mode: 0 1 2 3 4 5 */ +static const u32 udma_fsclk[] = +{ 33333333, 33333333, 40000000, 50000000, 80000000, 133333333 }; + +/** + * Register transfer timing table + */ +/* mode: 0 1 2 3 4 */ +/* Cycle Time */ +static const u32 reg_t0min[] = { 600, 383, 330, 180, 120 }; +/* DIOR/DIOW to end cycle */ +static const u32 reg_t2min[] = { 290, 290, 290, 70, 25 }; +/* DIOR/DIOW asserted pulse width */ +static const u32 reg_teocmin[] = { 290, 290, 290, 80, 70 }; + +/** + * PIO timing table + */ +/* mode: 0 1 2 3 4 */ +/* Cycle Time */ +static const u32 pio_t0min[] = { 600, 383, 240, 180, 120 }; +/* Address valid to DIOR/DIORW */ +static const u32 pio_t1min[] = { 70, 50, 30, 30, 25 }; +/* DIOR/DIOW to end cycle */ +static const u32 pio_t2min[] = { 165, 125, 100, 80, 70 }; +/* DIOR/DIOW asserted pulse width */ +static const u32 pio_teocmin[] = { 165, 125, 100, 70, 25 }; +/* DIOW data hold */ +static const u32 pio_t4min[] = { 30, 20, 15, 10, 10 }; + +/* ****************************************************************** + * Multiword DMA timing table + * ****************************************************************** + */ +/* mode: 0 1 2 */ +/* Cycle Time */ +static const u32 mdma_t0min[] = { 480, 150, 120 }; +/* DIOR/DIOW asserted pulse width */ +static const u32 mdma_tdmin[] = { 215, 80, 70 }; +/* DMACK to read data released */ +static const u32 mdma_thmin[] = { 20, 15, 10 }; +/* DIOR/DIOW to DMACK hold */ +static const u32 mdma_tjmin[] = { 20, 5, 5 }; +/* DIOR negated pulse width */ +static const u32 mdma_tkrmin[] = { 50, 50, 25 }; +/* DIOR negated pulse width */ +static const u32 mdma_tkwmin[] = { 215, 50, 25 }; +/* CS[1:0] valid to DIOR/DIOW */ +static const u32 mdma_tmmin[] = { 50, 30, 25 }; +/* DMACK to read data released */ +static const u32 mdma_tzmax[] = { 20, 25, 25 }; + +/** + * Ultra DMA timing table + */ +/* mode: 0 1 2 3 4 5 */ +static const u32 udma_tcycmin[] = { 112, 73, 54, 39, 25, 17 }; +static const u32 udma_tdvsmin[] = { 70, 48, 31, 20, 7, 5 }; +static const u32 udma_tenvmax[] = { 70, 70, 70, 55, 55, 50 }; +static const u32 udma_trpmin[] = { 160, 125, 100, 100, 100, 85 }; +static const u32 udma_tmin[] = { 5, 5, 5, 5, 3, 3 }; + + +static const u32 udma_tmlimin = 20; +static const u32 udma_tzahmin = 20; +static const u32 udma_tenvmin = 20; +static const u32 udma_tackmin = 20; +static const u32 udma_tssmin = 50; + +/** + * + * Function: num_clocks_min + * + * Description: + * calculate number of SCLK cycles to meet minimum timing + */ +static unsigned short num_clocks_min(unsigned long tmin, + unsigned long fsclk) +{ + unsigned long tmp ; + unsigned short result; + + tmp = tmin * (fsclk/1000/1000) / 1000; + result = (unsigned short)tmp; + if ((tmp*1000*1000) < (tmin*(fsclk/1000))) { + result++; + } + + return result; +} + +/** + * bfin_set_piomode - Initialize host controller PATA PIO timings + * @ap: Port whose timings we are configuring + * @adev: um + * + * Set PIO mode for device. + * + * LOCKING: + * None (inherited from caller). + */ + +static void bfin_set_piomode(struct ata_port *ap, struct ata_device *adev) +{ + int mode = adev->pio_mode - XFER_PIO_0; + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + unsigned int fsclk = get_sclk(); + unsigned short teoc_reg, t2_reg, teoc_pio; + unsigned short t4_reg, t2_pio, t1_reg; + unsigned short n0, n6, t6min = 5; + + /* the most restrictive timing value is t6 and tc, the DIOW - data hold + * If one SCLK pulse is longer than this minimum value then register + * transfers cannot be supported at this frequency. + */ + n6 = num_clocks_min(t6min, fsclk); + if (mode >= 0 && mode <= 4 && n6 >= 1) { + pr_debug("set piomode: mode=%d, fsclk=%ud\n", mode, fsclk); + /* calculate the timing values for register transfers. */ + while (mode > 0 && pio_fsclk[mode] > fsclk) + mode--; + + /* DIOR/DIOW to end cycle time */ + t2_reg = num_clocks_min(reg_t2min[mode], fsclk); + /* DIOR/DIOW asserted pulse width */ + teoc_reg = num_clocks_min(reg_teocmin[mode], fsclk); + /* Cycle Time */ + n0 = num_clocks_min(reg_t0min[mode], fsclk); + + /* increase t2 until we meed the minimum cycle length */ + if (t2_reg + teoc_reg < n0) + t2_reg = n0 - teoc_reg; + + /* calculate the timing values for pio transfers. */ + + /* DIOR/DIOW to end cycle time */ + t2_pio = num_clocks_min(pio_t2min[mode], fsclk); + /* DIOR/DIOW asserted pulse width */ + teoc_pio = num_clocks_min(pio_teocmin[mode], fsclk); + /* Cycle Time */ + n0 = num_clocks_min(pio_t0min[mode], fsclk); + + /* increase t2 until we meed the minimum cycle length */ + if (t2_pio + teoc_pio < n0) + t2_pio = n0 - teoc_pio; + + /* Address valid to DIOR/DIORW */ + t1_reg = num_clocks_min(pio_t1min[mode], fsclk); + + /* DIOW data hold */ + t4_reg = num_clocks_min(pio_t4min[mode], fsclk); + + ATAPI_SET_REG_TIM_0(base, (teoc_reg<<8 | t2_reg)); + ATAPI_SET_PIO_TIM_0(base, (t4_reg<<12 | t2_pio<<4 | t1_reg)); + ATAPI_SET_PIO_TIM_1(base, teoc_pio); + if (mode > 2) { + ATAPI_SET_CONTROL(base, + ATAPI_GET_CONTROL(base) | IORDY_EN); + } else { + ATAPI_SET_CONTROL(base, + ATAPI_GET_CONTROL(base) & ~IORDY_EN); + } + + /* Disable host ATAPI PIO interrupts */ + ATAPI_SET_INT_MASK(base, ATAPI_GET_INT_MASK(base) + & ~(PIO_DONE_MASK | HOST_TERM_XFER_MASK)); + SSYNC(); + } +} + +/** + * bfin_set_dmamode - Initialize host controller PATA DMA timings + * @ap: Port whose timings we are configuring + * @adev: um + * @udma: udma mode, 0 - 6 + * + * Set UDMA mode for device. + * + * LOCKING: + * None (inherited from caller). + */ + +static void bfin_set_dmamode(struct ata_port *ap, struct ata_device *adev) +{ + int mode; + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + unsigned long fsclk = get_sclk(); + unsigned short tenv, tack, tcyc_tdvs, tdvs, tmli, tss, trp, tzah; + unsigned short tm, td, tkr, tkw, teoc, th; + unsigned short n0, nf, tfmin = 5; + unsigned short nmin, tcyc; + + mode = adev->dma_mode - XFER_UDMA_0; + if (mode >= 0 && mode <= 5) { + pr_debug("set udmamode: mode=%d\n", mode); + /* the most restrictive timing value is t6 and tc, + * the DIOW - data hold. If one SCLK pulse is longer + * than this minimum value then register + * transfers cannot be supported at this frequency. + */ + while (mode > 0 && udma_fsclk[mode] > fsclk) + mode--; + + nmin = num_clocks_min(udma_tmin[mode], fsclk); + if (nmin >= 1) { + /* calculate the timing values for Ultra DMA. */ + tdvs = num_clocks_min(udma_tdvsmin[mode], fsclk); + tcyc = num_clocks_min(udma_tcycmin[mode], fsclk); + tcyc_tdvs = 2; + + /* increase tcyc - tdvs (tcyc_tdvs) until we meed + * the minimum cycle length + */ + if (tdvs + tcyc_tdvs < tcyc) + tcyc_tdvs = tcyc - tdvs; + + /* Mow assign the values required for the timing + * registers + */ + if (tcyc_tdvs < 2) + tcyc_tdvs = 2; + + if (tdvs < 2) + tdvs = 2; + + tack = num_clocks_min(udma_tackmin, fsclk); + tss = num_clocks_min(udma_tssmin, fsclk); + tmli = num_clocks_min(udma_tmlimin, fsclk); + tzah = num_clocks_min(udma_tzahmin, fsclk); + trp = num_clocks_min(udma_trpmin[mode], fsclk); + tenv = num_clocks_min(udma_tenvmin, fsclk); + if (tenv <= udma_tenvmax[mode]) { + ATAPI_SET_ULTRA_TIM_0(base, (tenv<<8 | tack)); + ATAPI_SET_ULTRA_TIM_1(base, + (tcyc_tdvs<<8 | tdvs)); + ATAPI_SET_ULTRA_TIM_2(base, (tmli<<8 | tss)); + ATAPI_SET_ULTRA_TIM_3(base, (trp<<8 | tzah)); + + /* Enable host ATAPI Untra DMA interrupts */ + ATAPI_SET_INT_MASK(base, + ATAPI_GET_INT_MASK(base) + | UDMAIN_DONE_MASK + | UDMAOUT_DONE_MASK + | UDMAIN_TERM_MASK + | UDMAOUT_TERM_MASK); + } + } + } + + mode = adev->dma_mode - XFER_MW_DMA_0; + if (mode >= 0 && mode <= 2) { + pr_debug("set mdmamode: mode=%d\n", mode); + /* the most restrictive timing value is tf, the DMACK to + * read data released. If one SCLK pulse is longer than + * this maximum value then the MDMA mode + * cannot be supported at this frequency. + */ + while (mode > 0 && mdma_fsclk[mode] > fsclk) + mode--; + + nf = num_clocks_min(tfmin, fsclk); + if (nf >= 1) { + /* calculate the timing values for Multi-word DMA. */ + + /* DIOR/DIOW asserted pulse width */ + td = num_clocks_min(mdma_tdmin[mode], fsclk); + + /* DIOR negated pulse width */ + tkw = num_clocks_min(mdma_tkwmin[mode], fsclk); + + /* Cycle Time */ + n0 = num_clocks_min(mdma_t0min[mode], fsclk); + + /* increase tk until we meed the minimum cycle length */ + if (tkw + td < n0) + tkw = n0 - td; + + /* DIOR negated pulse width - read */ + tkr = num_clocks_min(mdma_tkrmin[mode], fsclk); + /* CS{1:0] valid to DIOR/DIOW */ + tm = num_clocks_min(mdma_tmmin[mode], fsclk); + /* DIOR/DIOW to DMACK hold */ + teoc = num_clocks_min(mdma_tjmin[mode], fsclk); + /* DIOW Data hold */ + th = num_clocks_min(mdma_thmin[mode], fsclk); + + ATAPI_SET_MULTI_TIM_0(base, (tm<<8 | td)); + ATAPI_SET_MULTI_TIM_1(base, (tkr<<8 | tkw)); + ATAPI_SET_MULTI_TIM_2(base, (teoc<<8 | th)); + + /* Enable host ATAPI Multi DMA interrupts */ + ATAPI_SET_INT_MASK(base, ATAPI_GET_INT_MASK(base) + | MULTI_DONE_MASK | MULTI_TERM_MASK); + SSYNC(); + } + } + return; +} + +/** + * + * Function: wait_complete + * + * Description: Waits the interrupt from device + * + */ +static inline void wait_complete(void __iomem *base, unsigned short mask) +{ + unsigned short status; + unsigned int i = 0; + +#define PATA_BF54X_WAIT_TIMEOUT 10000 + + for (i = 0; i < PATA_BF54X_WAIT_TIMEOUT; i++) { + status = ATAPI_GET_INT_STATUS(base) & mask; + if (status) + break; + } + + ATAPI_SET_INT_STATUS(base, mask); +} + +/** + * + * Function: write_atapi_register + * + * Description: Writes to ATA Device Resgister + * + */ + +static void write_atapi_register(void __iomem *base, + unsigned long ata_reg, unsigned short value) +{ + /* Program the ATA_DEV_TXBUF register with write data (to be + * written into the device). + */ + ATAPI_SET_DEV_TXBUF(base, value); + + /* Program the ATA_DEV_ADDR register with address of the + * device register (0x01 to 0x0F). + */ + ATAPI_SET_DEV_ADDR(base, ata_reg); + + /* Program the ATA_CTRL register with dir set to write (1) + */ + ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | XFER_DIR)); + + /* ensure PIO DMA is not set */ + ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~PIO_USE_DMA)); + + /* and start the transfer */ + ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | PIO_START)); + + /* Wait for the interrupt to indicate the end of the transfer. + * (We need to wait on and clear rhe ATA_DEV_INT interrupt status) + */ + wait_complete(base, PIO_DONE_INT); +} + +/** + * + * Function: read_atapi_register + * + *Description: Reads from ATA Device Resgister + * + */ + +static unsigned short read_atapi_register(void __iomem *base, + unsigned long ata_reg) +{ + /* Program the ATA_DEV_ADDR register with address of the + * device register (0x01 to 0x0F). + */ + ATAPI_SET_DEV_ADDR(base, ata_reg); + + /* Program the ATA_CTRL register with dir set to read (0) and + */ + ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~XFER_DIR)); + + /* ensure PIO DMA is not set */ + ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~PIO_USE_DMA)); + + /* and start the transfer */ + ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | PIO_START)); + + /* Wait for the interrupt to indicate the end of the transfer. + * (PIO_DONE interrupt is set and it doesn't seem to matter + * that we don't clear it) + */ + wait_complete(base, PIO_DONE_INT); + + /* Read the ATA_DEV_RXBUF register with write data (to be + * written into the device). + */ + return ATAPI_GET_DEV_RXBUF(base); +} + +/** + * + * Function: write_atapi_register_data + * + * Description: Writes to ATA Device Resgister + * + */ + +static void write_atapi_data(void __iomem *base, + int len, unsigned short *buf) +{ + int i; + + /* Set transfer length to 1 */ + ATAPI_SET_XFER_LEN(base, 1); + + /* Program the ATA_DEV_ADDR register with address of the + * ATA_REG_DATA + */ + ATAPI_SET_DEV_ADDR(base, ATA_REG_DATA); + + /* Program the ATA_CTRL register with dir set to write (1) + */ + ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | XFER_DIR)); + + /* ensure PIO DMA is not set */ + ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~PIO_USE_DMA)); + + for (i = 0; i < len; i++) { + /* Program the ATA_DEV_TXBUF register with write data (to be + * written into the device). + */ + ATAPI_SET_DEV_TXBUF(base, buf[i]); + + /* and start the transfer */ + ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | PIO_START)); + + /* Wait for the interrupt to indicate the end of the transfer. + * (We need to wait on and clear rhe ATA_DEV_INT + * interrupt status) + */ + wait_complete(base, PIO_DONE_INT); + } +} + +/** + * + * Function: read_atapi_register_data + * + * Description: Reads from ATA Device Resgister + * + */ + +static void read_atapi_data(void __iomem *base, + int len, unsigned short *buf) +{ + int i; + + /* Set transfer length to 1 */ + ATAPI_SET_XFER_LEN(base, 1); + + /* Program the ATA_DEV_ADDR register with address of the + * ATA_REG_DATA + */ + ATAPI_SET_DEV_ADDR(base, ATA_REG_DATA); + + /* Program the ATA_CTRL register with dir set to read (0) and + */ + ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~XFER_DIR)); + + /* ensure PIO DMA is not set */ + ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~PIO_USE_DMA)); + + for (i = 0; i < len; i++) { + /* and start the transfer */ + ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | PIO_START)); + + /* Wait for the interrupt to indicate the end of the transfer. + * (PIO_DONE interrupt is set and it doesn't seem to matter + * that we don't clear it) + */ + wait_complete(base, PIO_DONE_INT); + + /* Read the ATA_DEV_RXBUF register with write data (to be + * written into the device). + */ + buf[i] = ATAPI_GET_DEV_RXBUF(base); + } +} + +/** + * bfin_tf_load - send taskfile registers to host controller + * @ap: Port to which output is sent + * @tf: ATA taskfile register set + * + * Note: Original code is ata_tf_load(). + */ + +static void bfin_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) +{ + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; + + if (tf->ctl != ap->last_ctl) { + write_atapi_register(base, ATA_REG_CTRL, tf->ctl); + ap->last_ctl = tf->ctl; + ata_wait_idle(ap); + } + + if (is_addr) { + if (tf->flags & ATA_TFLAG_LBA48) { + write_atapi_register(base, ATA_REG_FEATURE, + tf->hob_feature); + write_atapi_register(base, ATA_REG_NSECT, + tf->hob_nsect); + write_atapi_register(base, ATA_REG_LBAL, tf->hob_lbal); + write_atapi_register(base, ATA_REG_LBAM, tf->hob_lbam); + write_atapi_register(base, ATA_REG_LBAH, tf->hob_lbah); + pr_debug("hob: feat 0x%X nsect 0x%X, lba 0x%X " + "0x%X 0x%X\n", + tf->hob_feature, + tf->hob_nsect, + tf->hob_lbal, + tf->hob_lbam, + tf->hob_lbah); + } + + write_atapi_register(base, ATA_REG_FEATURE, tf->feature); + write_atapi_register(base, ATA_REG_NSECT, tf->nsect); + write_atapi_register(base, ATA_REG_LBAL, tf->lbal); + write_atapi_register(base, ATA_REG_LBAM, tf->lbam); + write_atapi_register(base, ATA_REG_LBAH, tf->lbah); + pr_debug("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n", + tf->feature, + tf->nsect, + tf->lbal, + tf->lbam, + tf->lbah); + } + + if (tf->flags & ATA_TFLAG_DEVICE) { + write_atapi_register(base, ATA_REG_DEVICE, tf->device); + pr_debug("device 0x%X\n", tf->device); + } + + ata_wait_idle(ap); +} + +/** + * bfin_check_status - Read device status reg & clear interrupt + * @ap: port where the device is + * + * Note: Original code is ata_check_status(). + */ + +static u8 bfin_check_status(struct ata_port *ap) +{ + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + return read_atapi_register(base, ATA_REG_STATUS); +} + +/** + * bfin_tf_read - input device's ATA taskfile shadow registers + * @ap: Port from which input is read + * @tf: ATA taskfile register set for storing input + * + * Note: Original code is ata_tf_read(). + */ + +static void bfin_tf_read(struct ata_port *ap, struct ata_taskfile *tf) +{ + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + + tf->command = bfin_check_status(ap); + tf->feature = read_atapi_register(base, ATA_REG_ERR); + tf->nsect = read_atapi_register(base, ATA_REG_NSECT); + tf->lbal = read_atapi_register(base, ATA_REG_LBAL); + tf->lbam = read_atapi_register(base, ATA_REG_LBAM); + tf->lbah = read_atapi_register(base, ATA_REG_LBAH); + tf->device = read_atapi_register(base, ATA_REG_DEVICE); + + if (tf->flags & ATA_TFLAG_LBA48) { + write_atapi_register(base, ATA_REG_CTRL, tf->ctl | ATA_HOB); + tf->hob_feature = read_atapi_register(base, ATA_REG_ERR); + tf->hob_nsect = read_atapi_register(base, ATA_REG_NSECT); + tf->hob_lbal = read_atapi_register(base, ATA_REG_LBAL); + tf->hob_lbam = read_atapi_register(base, ATA_REG_LBAM); + tf->hob_lbah = read_atapi_register(base, ATA_REG_LBAH); + } +} + +/** + * bfin_exec_command - issue ATA command to host controller + * @ap: port to which command is being issued + * @tf: ATA taskfile register set + * + * Note: Original code is ata_exec_command(). + */ + +static void bfin_exec_command(struct ata_port *ap, + const struct ata_taskfile *tf) +{ + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + pr_debug("ata%u: cmd 0x%X\n", ap->print_id, tf->command); + + write_atapi_register(base, ATA_REG_CMD, tf->command); + ata_pause(ap); +} + +/** + * bfin_check_altstatus - Read device alternate status reg + * @ap: port where the device is + */ + +static u8 bfin_check_altstatus(struct ata_port *ap) +{ + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + return read_atapi_register(base, ATA_REG_ALTSTATUS); +} + +/** + * bfin_std_dev_select - Select device 0/1 on ATA bus + * @ap: ATA channel to manipulate + * @device: ATA device (numbered from zero) to select + * + * Note: Original code is ata_std_dev_select(). + */ + +static void bfin_std_dev_select(struct ata_port *ap, unsigned int device) +{ + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + u8 tmp; + + if (device == 0) + tmp = ATA_DEVICE_OBS; + else + tmp = ATA_DEVICE_OBS | ATA_DEV1; + + write_atapi_register(base, ATA_REG_DEVICE, tmp); + ata_pause(ap); +} + +/** + * bfin_bmdma_setup - Set up IDE DMA transaction + * @qc: Info associated with this ATA transaction. + * + * Note: Original code is ata_bmdma_setup(). + */ + +static void bfin_bmdma_setup(struct ata_queued_cmd *qc) +{ + unsigned short config = WDSIZE_16; + struct scatterlist *sg; + + pr_debug("in atapi dma setup\n"); + /* Program the ATA_CTRL register with dir */ + if (qc->tf.flags & ATA_TFLAG_WRITE) { + /* fill the ATAPI DMA controller */ + set_dma_config(CH_ATAPI_TX, config); + set_dma_x_modify(CH_ATAPI_TX, 2); + ata_for_each_sg(sg, qc) { + set_dma_start_addr(CH_ATAPI_TX, sg_dma_address(sg)); + set_dma_x_count(CH_ATAPI_TX, sg_dma_len(sg) >> 1); + } + } else { + config |= WNR; + /* fill the ATAPI DMA controller */ + set_dma_config(CH_ATAPI_RX, config); + set_dma_x_modify(CH_ATAPI_RX, 2); + ata_for_each_sg(sg, qc) { + set_dma_start_addr(CH_ATAPI_RX, sg_dma_address(sg)); + set_dma_x_count(CH_ATAPI_RX, sg_dma_len(sg) >> 1); + } + } +} + +/** + * bfin_bmdma_start - Start an IDE DMA transaction + * @qc: Info associated with this ATA transaction. + * + * Note: Original code is ata_bmdma_start(). + */ + +static void bfin_bmdma_start(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + struct scatterlist *sg; + + pr_debug("in atapi dma start\n"); + if (!(ap->udma_mask || ap->mwdma_mask)) + return; + + /* start ATAPI DMA controller*/ + if (qc->tf.flags & ATA_TFLAG_WRITE) { + /* + * On blackfin arch, uncacheable memory is not + * allocated with flag GFP_DMA. DMA buffer from + * common kenel code should be flushed if WB + * data cache is enabled. Otherwise, this loop + * is an empty loop and optimized out. + */ + ata_for_each_sg(sg, qc) { + flush_dcache_range(sg_dma_address(sg), + sg_dma_address(sg) + sg_dma_len(sg)); + } + enable_dma(CH_ATAPI_TX); + pr_debug("enable udma write\n"); + + /* Send ATA DMA write command */ + bfin_exec_command(ap, &qc->tf); + + /* set ATA DMA write direction */ + ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) + | XFER_DIR)); + } else { + enable_dma(CH_ATAPI_RX); + pr_debug("enable udma read\n"); + + /* Send ATA DMA read command */ + bfin_exec_command(ap, &qc->tf); + + /* set ATA DMA read direction */ + ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) + & ~XFER_DIR)); + } + + /* Reset all transfer count */ + ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) | TFRCNT_RST); + + /* Set transfer length to buffer len */ + ata_for_each_sg(sg, qc) { + ATAPI_SET_XFER_LEN(base, (sg_dma_len(sg) >> 1)); + } + + /* Enable ATA DMA operation*/ + if (ap->udma_mask) + ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) + | ULTRA_START); + else + ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) + | MULTI_START); +} + +/** + * bfin_bmdma_stop - Stop IDE DMA transfer + * @qc: Command we are ending DMA for + */ + +static void bfin_bmdma_stop(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct scatterlist *sg; + + pr_debug("in atapi dma stop\n"); + if (!(ap->udma_mask || ap->mwdma_mask)) + return; + + /* stop ATAPI DMA controller*/ + if (qc->tf.flags & ATA_TFLAG_WRITE) + disable_dma(CH_ATAPI_TX); + else { + disable_dma(CH_ATAPI_RX); + if (ap->hsm_task_state & HSM_ST_LAST) { + /* + * On blackfin arch, uncacheable memory is not + * allocated with flag GFP_DMA. DMA buffer from + * common kenel code should be invalidated if + * data cache is enabled. Otherwise, this loop + * is an empty loop and optimized out. + */ + ata_for_each_sg(sg, qc) { + invalidate_dcache_range( + sg_dma_address(sg), + sg_dma_address(sg) + + sg_dma_len(sg)); + } + } + } +} + +/** + * bfin_devchk - PATA device presence detection + * @ap: ATA channel to examine + * @device: Device to examine (starting at zero) + * + * Note: Original code is ata_devchk(). + */ + +static unsigned int bfin_devchk(struct ata_port *ap, + unsigned int device) +{ + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + u8 nsect, lbal; + + bfin_std_dev_select(ap, device); + + write_atapi_register(base, ATA_REG_NSECT, 0x55); + write_atapi_register(base, ATA_REG_LBAL, 0xaa); + + write_atapi_register(base, ATA_REG_NSECT, 0xaa); + write_atapi_register(base, ATA_REG_LBAL, 0x55); + + write_atapi_register(base, ATA_REG_NSECT, 0x55); + write_atapi_register(base, ATA_REG_LBAL, 0xaa); + + nsect = read_atapi_register(base, ATA_REG_NSECT); + lbal = read_atapi_register(base, ATA_REG_LBAL); + + if ((nsect == 0x55) && (lbal == 0xaa)) + return 1; /* we found a device */ + + return 0; /* nothing found */ +} + +/** + * bfin_bus_post_reset - PATA device post reset + * + * Note: Original code is ata_bus_post_reset(). + */ + +static void bfin_bus_post_reset(struct ata_port *ap, unsigned int devmask) +{ + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + unsigned int dev0 = devmask & (1 << 0); + unsigned int dev1 = devmask & (1 << 1); + unsigned long timeout; + + /* if device 0 was found in ata_devchk, wait for its + * BSY bit to clear + */ + if (dev0) + ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT); + + /* if device 1 was found in ata_devchk, wait for + * register access, then wait for BSY to clear + */ + timeout = jiffies + ATA_TMOUT_BOOT; + while (dev1) { + u8 nsect, lbal; + + bfin_std_dev_select(ap, 1); + nsect = read_atapi_register(base, ATA_REG_NSECT); + lbal = read_atapi_register(base, ATA_REG_LBAL); + if ((nsect == 1) && (lbal == 1)) + break; + if (time_after(jiffies, timeout)) { + dev1 = 0; + break; + } + msleep(50); /* give drive a breather */ + } + if (dev1) + ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT); + + /* is all this really necessary? */ + bfin_std_dev_select(ap, 0); + if (dev1) + bfin_std_dev_select(ap, 1); + if (dev0) + bfin_std_dev_select(ap, 0); +} + +/** + * bfin_bus_softreset - PATA device software reset + * + * Note: Original code is ata_bus_softreset(). + */ + +static unsigned int bfin_bus_softreset(struct ata_port *ap, + unsigned int devmask) +{ + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + + /* software reset. causes dev0 to be selected */ + write_atapi_register(base, ATA_REG_CTRL, ap->ctl); + udelay(20); + write_atapi_register(base, ATA_REG_CTRL, ap->ctl | ATA_SRST); + udelay(20); + write_atapi_register(base, ATA_REG_CTRL, ap->ctl); + + /* spec mandates ">= 2ms" before checking status. + * We wait 150ms, because that was the magic delay used for + * ATAPI devices in Hale Landis's ATADRVR, for the period of time + * between when the ATA command register is written, and then + * status is checked. Because waiting for "a while" before + * checking status is fine, post SRST, we perform this magic + * delay here as well. + * + * Old drivers/ide uses the 2mS rule and then waits for ready + */ + msleep(150); + + /* Before we perform post reset processing we want to see if + * the bus shows 0xFF because the odd clown forgets the D7 + * pulldown resistor. + */ + if (bfin_check_status(ap) == 0xFF) + return 0; + + bfin_bus_post_reset(ap, devmask); + + return 0; +} + +/** + * bfin_std_softreset - reset host port via ATA SRST + * @ap: port to reset + * @classes: resulting classes of attached devices + * + * Note: Original code is ata_std_softreset(). + */ + +static int bfin_std_softreset(struct ata_port *ap, unsigned int *classes, + unsigned long deadline) +{ + unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS; + unsigned int devmask = 0, err_mask; + u8 err; + + if (ata_port_offline(ap)) { + classes[0] = ATA_DEV_NONE; + goto out; + } + + /* determine if device 0/1 are present */ + if (bfin_devchk(ap, 0)) + devmask |= (1 << 0); + if (slave_possible && bfin_devchk(ap, 1)) + devmask |= (1 << 1); + + /* select device 0 again */ + bfin_std_dev_select(ap, 0); + + /* issue bus reset */ + err_mask = bfin_bus_softreset(ap, devmask); + if (err_mask) { + ata_port_printk(ap, KERN_ERR, "SRST failed (err_mask=0x%x)\n", + err_mask); + return -EIO; + } + + /* determine by signature whether we have ATA or ATAPI devices */ + classes[0] = ata_dev_try_classify(ap, 0, &err); + if (slave_possible && err != 0x81) + classes[1] = ata_dev_try_classify(ap, 1, &err); + + out: + return 0; +} + +/** + * bfin_bmdma_status - Read IDE DMA status + * @ap: Port associated with this ATA transaction. + */ + +static unsigned char bfin_bmdma_status(struct ata_port *ap) +{ + unsigned char host_stat = 0; + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + unsigned short int_status = ATAPI_GET_INT_STATUS(base); + + if (ATAPI_GET_STATUS(base) & (MULTI_XFER_ON|ULTRA_XFER_ON)) { + host_stat = ATA_DMA_ACTIVE; + } + if (int_status & (MULTI_DONE_INT|UDMAIN_DONE_INT|UDMAOUT_DONE_INT)) { + host_stat = ATA_DMA_INTR; + } + if (int_status & (MULTI_TERM_INT|UDMAIN_TERM_INT|UDMAOUT_TERM_INT)) { + host_stat = ATA_DMA_ERR; + } + + return host_stat; +} + +/** + * bfin_data_xfer - Transfer data by PIO + * @adev: device for this I/O + * @buf: data buffer + * @buflen: buffer length + * @write_data: read/write + * + * Note: Original code is ata_data_xfer(). + */ + +static void bfin_data_xfer(struct ata_device *adev, unsigned char *buf, + unsigned int buflen, int write_data) +{ + struct ata_port *ap = adev->ap; + unsigned int words = buflen >> 1; + unsigned short *buf16 = (u16 *) buf; + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + + /* Transfer multiple of 2 bytes */ + if (write_data) { + write_atapi_data(base, words, buf16); + } else { + read_atapi_data(base, words, buf16); + } + + /* Transfer trailing 1 byte, if any. */ + if (unlikely(buflen & 0x01)) { + unsigned short align_buf[1] = { 0 }; + unsigned char *trailing_buf = buf + buflen - 1; + + if (write_data) { + memcpy(align_buf, trailing_buf, 1); + write_atapi_data(base, 1, align_buf); + } else { + read_atapi_data(base, 1, align_buf); + memcpy(trailing_buf, align_buf, 1); + } + } +} + +/** + * bfin_irq_clear - Clear ATAPI interrupt. + * @ap: Port associated with this ATA transaction. + * + * Note: Original code is ata_bmdma_irq_clear(). + */ + +static void bfin_irq_clear(struct ata_port *ap) +{ + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + + pr_debug("in atapi irq clear\n"); + ATAPI_SET_INT_STATUS(base, 0x1FF); +} + +/** + * bfin_irq_on - Enable interrupts on a port. + * @ap: Port on which interrupts are enabled. + * + * Note: Original code is ata_irq_on(). + */ + +static unsigned char bfin_irq_on(struct ata_port *ap) +{ + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + u8 tmp; + + pr_debug("in atapi irq on\n"); + ap->ctl &= ~ATA_NIEN; + ap->last_ctl = ap->ctl; + + write_atapi_register(base, ATA_REG_CTRL, ap->ctl); + tmp = ata_wait_idle(ap); + + bfin_irq_clear(ap); + + return tmp; +} + +/** + * bfin_irq_ack - Acknowledge a device interrupt. + * @ap: Port on which interrupts are enabled. + * + * Note: Original code is ata_irq_ack(). + */ + +static unsigned char bfin_irq_ack(struct ata_port *ap, unsigned int chk_drq) +{ + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY; + unsigned char status; + + pr_debug("in atapi irq ack\n"); + status = ata_busy_wait(ap, bits, 1000); + if (status & bits) + if (ata_msg_err(ap)) + dev_err(ap->dev, "abnormal status 0x%X\n", status); + + /* get controller status; clear intr, err bits */ + ATAPI_SET_INT_STATUS(base, ATAPI_GET_INT_STATUS(base)|ATAPI_DEV_INT + | MULTI_DONE_INT | UDMAIN_DONE_INT | UDMAOUT_DONE_INT + | MULTI_TERM_INT | UDMAIN_TERM_INT | UDMAOUT_TERM_INT); + + return bfin_bmdma_status(ap); +} + +/** + * bfin_bmdma_freeze - Freeze DMA controller port + * @ap: port to freeze + * + * Note: Original code is ata_bmdma_freeze(). + */ + +static void bfin_bmdma_freeze(struct ata_port *ap) +{ + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + + pr_debug("in atapi dma freeze\n"); + ap->ctl |= ATA_NIEN; + ap->last_ctl = ap->ctl; + + write_atapi_register(base, ATA_REG_CTRL, ap->ctl); + + /* Under certain circumstances, some controllers raise IRQ on + * ATA_NIEN manipulation. Also, many controllers fail to mask + * previously pending IRQ on ATA_NIEN assertion. Clear it. + */ + ata_chk_status(ap); + + bfin_irq_clear(ap); +} + +/** + * bfin_bmdma_thaw - Thaw DMA controller port + * @ap: port to thaw + * + * Note: Original code is ata_bmdma_thaw(). + */ + +void bfin_bmdma_thaw(struct ata_port *ap) +{ + bfin_check_status(ap); + bfin_irq_clear(ap); + bfin_irq_on(ap); +} + +/** + * bfin_std_postreset - standard postreset callback + * @ap: the target ata_port + * @classes: classes of attached devices + * + * Note: Original code is ata_std_postreset(). + */ + +static void bfin_std_postreset(struct ata_port *ap, unsigned int *classes) +{ + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + + /* re-enable interrupts */ + bfin_irq_on(ap); + + /* is double-select really necessary? */ + if (classes[0] != ATA_DEV_NONE) + bfin_std_dev_select(ap, 1); + if (classes[1] != ATA_DEV_NONE) + bfin_std_dev_select(ap, 0); + + /* bail out if no device is present */ + if (classes[0] == ATA_DEV_NONE && classes[1] == ATA_DEV_NONE) { + return; + } + + /* set up device control */ + write_atapi_register(base, ATA_REG_CTRL, ap->ctl); +} + +/** + * bfin_error_handler - Stock error handler for DMA controller + * @ap: port to handle error for + */ + +static void bfin_error_handler(struct ata_port *ap) +{ + ata_bmdma_drive_eh(ap, ata_std_prereset, bfin_std_softreset, NULL, + bfin_std_postreset); +} + +static void bfin_port_stop(struct ata_port *ap) +{ + pr_debug("in atapi port stop\n"); + if (ap->udma_mask != 0 || ap->mwdma_mask != 0) { + free_dma(CH_ATAPI_RX); + free_dma(CH_ATAPI_TX); + } +} + +static int bfin_port_start(struct ata_port *ap) +{ + pr_debug("in atapi port start\n"); + if (!(ap->udma_mask || ap->mwdma_mask)) + return 0; + + if (request_dma(CH_ATAPI_RX, "BFIN ATAPI RX DMA") >= 0) { + if (request_dma(CH_ATAPI_TX, + "BFIN ATAPI TX DMA") >= 0) + return 0; + + free_dma(CH_ATAPI_RX); + } + + ap->udma_mask = 0; + ap->mwdma_mask = 0; + dev_err(ap->dev, "Unable to request ATAPI DMA!" + " Continue in PIO mode.\n"); + + return 0; +} + +static struct scsi_host_template bfin_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, + .queuecommand = ata_scsi_queuecmd, + .can_queue = ATA_DEF_QUEUE, + .this_id = ATA_SHT_THIS_ID, + .sg_tablesize = SG_NONE, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ATA_SHT_USE_CLUSTERING, + .proc_name = DRV_NAME, + .dma_boundary = ATA_DMA_BOUNDARY, + .slave_configure = ata_scsi_slave_config, + .slave_destroy = ata_scsi_slave_destroy, + .bios_param = ata_std_bios_param, +#ifdef CONFIG_PM + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, +#endif +}; + +static const struct ata_port_operations bfin_pata_ops = { + .port_disable = ata_port_disable, + .set_piomode = bfin_set_piomode, + .set_dmamode = bfin_set_dmamode, + + .tf_load = bfin_tf_load, + .tf_read = bfin_tf_read, + .exec_command = bfin_exec_command, + .check_status = bfin_check_status, + .check_altstatus = bfin_check_altstatus, + .dev_select = bfin_std_dev_select, + + .bmdma_setup = bfin_bmdma_setup, + .bmdma_start = bfin_bmdma_start, + .bmdma_stop = bfin_bmdma_stop, + .bmdma_status = bfin_bmdma_status, + .data_xfer = bfin_data_xfer, + + .qc_prep = ata_noop_qc_prep, + .qc_issue = ata_qc_issue_prot, + + .freeze = bfin_bmdma_freeze, + .thaw = bfin_bmdma_thaw, + .error_handler = bfin_error_handler, + .post_internal_cmd = bfin_bmdma_stop, + + .irq_handler = ata_interrupt, + .irq_clear = bfin_irq_clear, + .irq_on = bfin_irq_on, + .irq_ack = bfin_irq_ack, + + .port_start = bfin_port_start, + .port_stop = bfin_port_stop, +}; + +static struct ata_port_info bfin_port_info[] = { + { + .sht = &bfin_sht, + .flags = ATA_FLAG_SLAVE_POSS + | ATA_FLAG_MMIO + | ATA_FLAG_NO_LEGACY, + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0, +#ifdef CONFIG_PATA_BF54X_DMA + .udma_mask = ATA_UDMA5, +#else + .udma_mask = 0, +#endif + .port_ops = &bfin_pata_ops, + }, +}; + +/** + * bfin_reset_controller - initialize BF54x ATAPI controller. + */ + +static int bfin_reset_controller(struct ata_host *host) +{ + void __iomem *base = (void __iomem *)host->ports[0]->ioaddr.ctl_addr; + int count; + unsigned short status; + + /* Disable all ATAPI interrupts */ + ATAPI_SET_INT_MASK(base, 0); + SSYNC(); + + /* Assert the RESET signal 25us*/ + ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) | DEV_RST); + udelay(30); + + /* Negate the RESET signal for 2ms*/ + ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) & ~DEV_RST); + msleep(2); + + /* Wait on Busy flag to clear */ + count = 10000000; + do { + status = read_atapi_register(base, ATA_REG_STATUS); + } while (count-- && (status & ATA_BUSY)); + + /* Enable only ATAPI Device interrupt */ + ATAPI_SET_INT_MASK(base, 1); + SSYNC(); + + return (!count); +} + +/** + * atapi_io_port - define atapi peripheral port pins. + */ +static unsigned short atapi_io_port[] = { + P_ATAPI_RESET, + P_ATAPI_DIOR, + P_ATAPI_DIOW, + P_ATAPI_CS0, + P_ATAPI_CS1, + P_ATAPI_DMACK, + P_ATAPI_DMARQ, + P_ATAPI_INTRQ, + P_ATAPI_IORDY, + 0 +}; + +/** + * bfin_atapi_probe - attach a bfin atapi interface + * @pdev: platform device + * + * Register a bfin atapi interface. + * + * + * Platform devices are expected to contain 2 resources per port: + * + * - I/O Base (IORESOURCE_IO) + * - IRQ (IORESOURCE_IRQ) + * + */ +static int __devinit bfin_atapi_probe(struct platform_device *pdev) +{ + int board_idx = 0; + struct resource *res; + struct ata_host *host; + const struct ata_port_info *ppi[] = + { &bfin_port_info[board_idx], NULL }; + + /* + * Simple resource validation .. + */ + if (unlikely(pdev->num_resources != 2)) { + dev_err(&pdev->dev, "invalid number of resources\n"); + return -EINVAL; + } + + /* + * Get the register base first + */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) + return -EINVAL; + + /* + * Now that that's out of the way, wire up the port.. + */ + host = ata_host_alloc_pinfo(&pdev->dev, ppi, 1); + if (!host) + return -ENOMEM; + + host->ports[0]->ioaddr.ctl_addr = (void *)res->start; + + if (peripheral_request_list(atapi_io_port, "atapi-io-port")) { + dev_err(&pdev->dev, "Requesting Peripherals faild\n"); + return -EFAULT; + } + + if (bfin_reset_controller(host)) { + peripheral_free_list(atapi_io_port); + dev_err(&pdev->dev, "Fail to reset ATAPI device\n"); + return -EFAULT; + } + + if (ata_host_activate(host, platform_get_irq(pdev, 0), + ata_interrupt, IRQF_SHARED, &bfin_sht) != 0) { + peripheral_free_list(atapi_io_port); + dev_err(&pdev->dev, "Fail to attach ATAPI device\n"); + return -ENODEV; + } + + return 0; +} + +/** + * bfin_atapi_remove - unplug a bfin atapi interface + * @pdev: platform device + * + * A bfin atapi device has been unplugged. Perform the needed + * cleanup. Also called on module unload for any active devices. + */ +static int __devexit bfin_atapi_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct ata_host *host = dev_get_drvdata(dev); + + ata_host_detach(host); + + peripheral_free_list(atapi_io_port); + + return 0; +} + +#ifdef CONFIG_PM +int bfin_atapi_suspend(struct platform_device *pdev, pm_message_t state) +{ + return 0; +} + +int bfin_atapi_resume(struct platform_device *pdev) +{ + return 0; +} +#endif + +static struct platform_driver bfin_atapi_driver = { + .probe = bfin_atapi_probe, + .remove = __devexit_p(bfin_atapi_remove), + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, +#ifdef CONFIG_PM + .suspend = bfin_atapi_suspend, + .resume = bfin_atapi_resume, +#endif + }, +}; + +static int __init bfin_atapi_init(void) +{ + pr_info("register bfin atapi driver\n"); + return platform_driver_register(&bfin_atapi_driver); +} + +static void __exit bfin_atapi_exit(void) +{ + platform_driver_unregister(&bfin_atapi_driver); +} + +module_init(bfin_atapi_init); +module_exit(bfin_atapi_exit); + +MODULE_AUTHOR("Sonic Zhang "); +MODULE_DESCRIPTION("PATA driver for blackfin 54x ATAPI controller"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); -- cgit v1.2.3-70-g09d2 From 7c9ef8e418374aec0a62e64d9b40d457634fd039 Mon Sep 17 00:00:00 2001 From: Kristoffer Nyborg Gregertsen Date: Wed, 8 Aug 2007 16:57:08 +0200 Subject: AVR32 PATA driver Updated and simplified driver. Use only register transfer timing for both data and register transfers. This gives poorer performance in PIO1 and 2, but should not be a problem in PIO3 and 4, correct me if I'm wrong :) The driver works very we'll but I still wonder about the interrupts. I have an interrupt line, that works nicely when POLLING flag is not set. The problem is the number of interrupts that eat away my CPU cycles. When using the POLLING flag there seem to be some interrupts that dosen't get cleared. Furthermore the device dosen't drive INTRQ high, it stays at 2.5 volts and generates a lot of interrupts due to ripple / noise. What to do? Signed-off-by: Kristoffer Nyborg Gregertsen Signed-off-by: Jeff Garzik --- drivers/ata/Kconfig | 9 + drivers/ata/Makefile | 1 + drivers/ata/pata_at32.c | 441 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 451 insertions(+) create mode 100644 drivers/ata/pata_at32.c (limited to 'drivers') diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index a427945f0bb..2cd0e747671 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -199,6 +199,15 @@ config PATA_ARTOP If unsure, say N. +config PATA_AT32 + tristate "Atmel AVR32 PATA support (Experimental)" + depends on AVR32 && PLATFORM_AT32AP && EXPERIMENTAL + help + This option enables support for the IDE devices on the + Atmel AT32AP platform. + + If unsure, say N. + config PATA_ATIIXP tristate "ATI PATA support (Experimental)" depends on PCI && EXPERIMENTAL diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index c2ecba5f0b4..4eb7fb44be3 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_PDC_ADMA) += pdc_adma.o obj-$(CONFIG_PATA_ALI) += pata_ali.o obj-$(CONFIG_PATA_AMD) += pata_amd.o obj-$(CONFIG_PATA_ARTOP) += pata_artop.o +obj-$(CONFIG_PATA_AT32) += pata_at32.o obj-$(CONFIG_PATA_ATIIXP) += pata_atiixp.o obj-$(CONFIG_PATA_CMD640_PCI) += pata_cmd640.o obj-$(CONFIG_PATA_CMD64X) += pata_cmd64x.o diff --git a/drivers/ata/pata_at32.c b/drivers/ata/pata_at32.c new file mode 100644 index 00000000000..bb250a48e27 --- /dev/null +++ b/drivers/ata/pata_at32.c @@ -0,0 +1,441 @@ +/* + * AVR32 SMC/CFC PATA Driver + * + * Copyright (C) 2007 Atmel Norway + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + */ + +#define DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define DRV_NAME "pata_at32" +#define DRV_VERSION "0.0.2" + +/* + * CompactFlash controller memory layout relative to the base address: + * + * Attribute memory: 0000 0000 -> 003f ffff + * Common memory: 0040 0000 -> 007f ffff + * I/O memory: 0080 0000 -> 00bf ffff + * True IDE Mode: 00c0 0000 -> 00df ffff + * Alt IDE Mode: 00e0 0000 -> 00ff ffff + * + * Only True IDE and Alt True IDE mode are needed for this driver. + * + * True IDE mode => CS0 = 0, CS1 = 1 (cmd, error, stat, etc) + * Alt True IDE mode => CS0 = 1, CS1 = 0 (ctl, alt_stat) + */ +#define CF_IDE_OFFSET 0x00c00000 +#define CF_ALT_IDE_OFFSET 0x00e00000 +#define CF_RES_SIZE 2048 + +/* + * Define DEBUG_BUS if you are doing debugging of your own EBI -> PATA + * adaptor with a logic analyzer or similar. + */ +#undef DEBUG_BUS + +/* + * ATA PIO modes + * + * Name | Mb/s | Min cycle time | Mask + * --------+-------+----------------+-------- + * Mode 0 | 3.3 | 600 ns | 0x01 + * Mode 1 | 5.2 | 383 ns | 0x03 + * Mode 2 | 8.3 | 240 ns | 0x07 + * Mode 3 | 11.1 | 180 ns | 0x0f + * Mode 4 | 16.7 | 120 ns | 0x1f + */ +#define PIO_MASK (0x1f) + +/* + * Struct containing private information about device. + */ +struct at32_ide_info { + unsigned int irq; + struct resource res_ide; + struct resource res_alt; + void __iomem *ide_addr; + void __iomem *alt_addr; + unsigned int cs; + struct smc_config smc; +}; + +/* + * Setup SMC for the given ATA timing. + */ +static int pata_at32_setup_timing(struct device *dev, + struct at32_ide_info *info, + const struct ata_timing *timing) +{ + /* These two values are found through testing */ + const int min_recover = 25; + const int ncs_hold = 15; + + struct smc_config *smc = &info->smc; + + int active; + int recover; + + /* Total cycle time */ + smc->read_cycle = timing->cyc8b; + + /* DIOR <= CFIOR timings */ + smc->nrd_setup = timing->setup; + smc->nrd_pulse = timing->act8b; + + /* Compute recover, extend total cycle if needed */ + active = smc->nrd_setup + smc->nrd_pulse; + recover = smc->read_cycle - active; + + if (recover < min_recover) { + smc->read_cycle = active + min_recover; + recover = min_recover; + } + + /* (CS0, CS1, DIR, OE) <= (CFCE1, CFCE2, CFRNW, NCSX) timings */ + smc->ncs_read_setup = 0; + smc->ncs_read_pulse = active + ncs_hold; + + /* Write timings same as read timings */ + smc->write_cycle = smc->read_cycle; + smc->nwe_setup = smc->nrd_setup; + smc->nwe_pulse = smc->nrd_pulse; + smc->ncs_write_setup = smc->ncs_read_setup; + smc->ncs_write_pulse = smc->ncs_read_pulse; + + /* Do some debugging output */ + dev_dbg(dev, "SMC: C=%d S=%d P=%d R=%d NCSS=%d NCSP=%d NCSR=%d\n", + smc->read_cycle, smc->nrd_setup, smc->nrd_pulse, + recover, smc->ncs_read_setup, smc->ncs_read_pulse, + smc->read_cycle - smc->ncs_read_pulse); + + /* Finally, configure the SMC */ + return smc_set_configuration(info->cs, smc); +} + +/* + * Procedures for libATA. + */ +static void pata_at32_set_piomode(struct ata_port *ap, struct ata_device *adev) +{ + struct ata_timing timing; + struct at32_ide_info *info = ap->host->private_data; + + int ret; + + /* Compute ATA timing */ + ret = ata_timing_compute(adev, adev->pio_mode, &timing, 1000, 0); + if (ret) { + dev_warn(ap->dev, "Failed to compute ATA timing %d\n", ret); + return; + } + + /* Setup SMC to ATA timing */ + ret = pata_at32_setup_timing(ap->dev, info, &timing); + if (ret) { + dev_warn(ap->dev, "Failed to setup ATA timing %d\n", ret); + return; + } +} + +static void pata_at32_irq_clear(struct ata_port *ap) +{ + /* No DMA controller yet */ +} + +static struct scsi_host_template at32_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, + .queuecommand = ata_scsi_queuecmd, + .can_queue = ATA_DEF_QUEUE, + .this_id = ATA_SHT_THIS_ID, + .sg_tablesize = LIBATA_MAX_PRD, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ATA_SHT_USE_CLUSTERING, + .proc_name = DRV_NAME, + .dma_boundary = ATA_DMA_BOUNDARY, + .slave_configure = ata_scsi_slave_config, + .slave_destroy = ata_scsi_slave_destroy, + .bios_param = ata_std_bios_param, +}; + +static struct ata_port_operations at32_port_ops = { + .port_disable = ata_port_disable, + .set_piomode = pata_at32_set_piomode, + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .exec_command = ata_exec_command, + .check_status = ata_check_status, + .dev_select = ata_std_dev_select, + + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, + .error_handler = ata_bmdma_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, + .cable_detect = ata_cable_40wire, + + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + + .data_xfer = ata_data_xfer, + + .irq_clear = pata_at32_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, + + .port_start = ata_sff_port_start, +}; + +static int __init pata_at32_init_one(struct device *dev, + struct at32_ide_info *info) +{ + struct ata_host *host; + struct ata_port *ap; + + host = ata_host_alloc(dev, 1); + if (!host) + return -ENOMEM; + + ap = host->ports[0]; + + /* Setup ATA bindings */ + ap->ops = &at32_port_ops; + ap->pio_mask = PIO_MASK; + ap->flags = ATA_FLAG_MMIO | ATA_FLAG_SLAVE_POSS + | ATA_FLAG_PIO_POLLING; + + /* + * Since all 8-bit taskfile transfers has to go on the lower + * byte of the data bus and there is a bug in the SMC that + * makes it impossible to alter the bus width during runtime, + * we need to hardwire the address signals as follows: + * + * A_IDE(2:0) <= A_EBI(3:1) + * + * This makes all addresses on the EBI even, thus all data + * will be on the lower byte of the data bus. All addresses + * used by libATA need to be altered according to this. + */ + ap->ioaddr.altstatus_addr = info->alt_addr + (0x06 << 1); + ap->ioaddr.ctl_addr = info->alt_addr + (0x06 << 1); + + ap->ioaddr.data_addr = info->ide_addr + (ATA_REG_DATA << 1); + ap->ioaddr.error_addr = info->ide_addr + (ATA_REG_ERR << 1); + ap->ioaddr.feature_addr = info->ide_addr + (ATA_REG_FEATURE << 1); + ap->ioaddr.nsect_addr = info->ide_addr + (ATA_REG_NSECT << 1); + ap->ioaddr.lbal_addr = info->ide_addr + (ATA_REG_LBAL << 1); + ap->ioaddr.lbam_addr = info->ide_addr + (ATA_REG_LBAM << 1); + ap->ioaddr.lbah_addr = info->ide_addr + (ATA_REG_LBAH << 1); + ap->ioaddr.device_addr = info->ide_addr + (ATA_REG_DEVICE << 1); + ap->ioaddr.status_addr = info->ide_addr + (ATA_REG_STATUS << 1); + ap->ioaddr.command_addr = info->ide_addr + (ATA_REG_CMD << 1); + + /* Set info as private data of ATA host */ + host->private_data = info; + + /* Register ATA device and return */ + return ata_host_activate(host, info->irq, ata_interrupt, + IRQF_SHARED | IRQF_TRIGGER_RISING, + &at32_sht); +} + +/* + * This function may come in handy for people analyzing their own + * EBI -> PATA adaptors. + */ +#ifdef DEBUG_BUS + +static void __init pata_at32_debug_bus(struct device *dev, + struct at32_ide_info *info) +{ + const int d1 = 0xff; + const int d2 = 0x00; + + int i; + + /* Write 8-bit values (registers) */ + iowrite8(d1, info->alt_addr + (0x06 << 1)); + iowrite8(d2, info->alt_addr + (0x06 << 1)); + + for (i = 0; i < 8; i++) { + iowrite8(d1, info->ide_addr + (i << 1)); + iowrite8(d2, info->ide_addr + (i << 1)); + } + + /* Write 16 bit values (data) */ + iowrite16(d1, info->ide_addr); + iowrite16(d1 << 8, info->ide_addr); + + iowrite16(d1, info->ide_addr); + iowrite16(d1 << 8, info->ide_addr); +} + +#endif + +static int __init pata_at32_probe(struct platform_device *pdev) +{ + const struct ata_timing initial_timing = + {XFER_PIO_0, 70, 290, 240, 600, 165, 150, 600, 0}; + + struct device *dev = &pdev->dev; + struct at32_ide_info *info; + struct ide_platform_data *board = pdev->dev.platform_data; + struct resource *res; + + int irq; + int ret; + + if (!board) + return -ENXIO; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENXIO; + + /* Retrive IRQ */ + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + /* Setup struct containing private infomation */ + info = kzalloc(sizeof(struct at32_ide_info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + memset(info, 0, sizeof(struct at32_ide_info)); + + info->irq = irq; + info->cs = board->cs; + + /* Request memory resources */ + info->res_ide.start = res->start + CF_IDE_OFFSET; + info->res_ide.end = info->res_ide.start + CF_RES_SIZE - 1; + info->res_ide.name = "ide"; + info->res_ide.flags = IORESOURCE_MEM; + + ret = request_resource(res, &info->res_ide); + if (ret) + goto err_req_res_ide; + + info->res_alt.start = res->start + CF_ALT_IDE_OFFSET; + info->res_alt.end = info->res_alt.start + CF_RES_SIZE - 1; + info->res_alt.name = "alt"; + info->res_alt.flags = IORESOURCE_MEM; + + ret = request_resource(res, &info->res_alt); + if (ret) + goto err_req_res_alt; + + /* Setup non-timing elements of SMC */ + info->smc.bus_width = 2; /* 16 bit data bus */ + info->smc.nrd_controlled = 1; /* Sample data on rising edge of NRD */ + info->smc.nwe_controlled = 0; /* Drive data on falling edge of NCS */ + info->smc.nwait_mode = 3; /* NWAIT is in READY mode */ + info->smc.byte_write = 0; /* Byte select access type */ + info->smc.tdf_mode = 0; /* TDF optimization disabled */ + info->smc.tdf_cycles = 0; /* No TDF wait cycles */ + + /* Setup ATA timing */ + ret = pata_at32_setup_timing(dev, info, &initial_timing); + if (ret) + goto err_setup_timing; + + /* Setup ATA addresses */ + ret = -ENOMEM; + info->ide_addr = devm_ioremap(dev, info->res_ide.start, 16); + info->alt_addr = devm_ioremap(dev, info->res_alt.start, 16); + if (!info->ide_addr || !info->alt_addr) + goto err_ioremap; + +#ifdef DEBUG_BUS + pata_at32_debug_bus(dev, info); +#endif + + /* Register ATA device */ + ret = pata_at32_init_one(dev, info); + if (ret) + goto err_ata_device; + + return 0; + + err_ata_device: + err_ioremap: + err_setup_timing: + release_resource(&info->res_alt); + err_req_res_alt: + release_resource(&info->res_ide); + err_req_res_ide: + kfree(info); + + return ret; +} + +static int __exit pata_at32_remove(struct platform_device *pdev) +{ + struct ata_host *host = platform_get_drvdata(pdev); + struct at32_ide_info *info; + + if (!host) + return 0; + + info = host->private_data; + ata_host_detach(host); + + if (!info) + return 0; + + release_resource(&info->res_ide); + release_resource(&info->res_alt); + + kfree(info); + + return 0; +} + +static struct platform_driver pata_at32_driver = { + .remove = __exit_p(pata_at32_remove), + .driver = { + .name = "at32_ide", + .owner = THIS_MODULE, + }, +}; + +static int __init pata_at32_init(void) +{ + return platform_driver_probe(&pata_at32_driver, pata_at32_probe); +} + +static void __exit pata_at32_exit(void) +{ + platform_driver_unregister(&pata_at32_driver); +} + +module_init(pata_at32_init); +module_exit(pata_at32_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("AVR32 SMC/CFC PATA Driver"); +MODULE_AUTHOR("Kristoffer Nyborg Gregertsen "); +MODULE_VERSION(DRV_VERSION); -- cgit v1.2.3-70-g09d2 From ec300d99ef8699a6f383889b8f8c0d0ebadc2a74 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Sat, 1 Sep 2007 07:17:36 -0400 Subject: [libata] ata_piix: Use more-robust form of array initialization Use a form of array init that is less fragile, less sensitive to trivial typos and ordering mismatches. Signed-off-by: Jeff Garzik --- drivers/ata/ata_piix.c | 34 ++++++++++++---------------------- 1 file changed, 12 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 45e3b60f26d..7adb2aa009a 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -123,7 +123,6 @@ enum { ich_pata_33 = 1, /* ICH up to UDMA 33 only */ ich_pata_66 = 2, /* ICH up to 66 Mhz */ ich_pata_100 = 3, /* ICH up to UDMA 100 */ - /* ICH up to UDMA 133 is not supported */ ich5_sata = 5, ich6_sata = 6, ich6_sata_ahci = 7, @@ -459,7 +458,7 @@ static const struct piix_map_db *piix_map_db_table[] = { }; static struct ata_port_info piix_port_info[] = { - /* piix_pata_33: 0: PIIX4 at 33MHz */ + [piix_pata_33] = /* PIIX4 at 33MHz */ { .sht = &piix_sht, .flags = PIIX_PATA_FLAGS, @@ -469,7 +468,7 @@ static struct ata_port_info piix_port_info[] = { .port_ops = &piix_pata_ops, }, - /* ich_pata_33: 1 ICH0 - ICH at 33Mhz*/ + [ich_pata_33] = /* ICH0 - ICH at 33Mhz*/ { .sht = &piix_sht, .flags = PIIX_PATA_FLAGS, @@ -478,7 +477,8 @@ static struct ata_port_info piix_port_info[] = { .udma_mask = ATA_UDMA2, /* UDMA33 */ .port_ops = &ich_pata_ops, }, - /* ich_pata_66: 2 ICH controllers up to 66MHz */ + + [ich_pata_66] = /* ICH controllers up to 66MHz */ { .sht = &piix_sht, .flags = PIIX_PATA_FLAGS, @@ -488,7 +488,7 @@ static struct ata_port_info piix_port_info[] = { .port_ops = &ich_pata_ops, }, - /* ich_pata_100: 3 */ + [ich_pata_100] = { .sht = &piix_sht, .flags = PIIX_PATA_FLAGS | PIIX_FLAG_CHECKINTR, @@ -498,17 +498,7 @@ static struct ata_port_info piix_port_info[] = { .port_ops = &ich_pata_ops, }, - /* ich_pata_133: 4 - Not supported - */ - { - .sht = &piix_sht, - .flags = PIIX_PATA_FLAGS | PIIX_FLAG_CHECKINTR, - .pio_mask = 0x1f, /* pio 0-4 */ - .mwdma_mask = 0x06, /* Check: maybe 0x07 */ - .udma_mask = ATA_UDMA6, /* UDMA133 */ - .port_ops = &ich_pata_ops, - }, - - /* ich5_sata: 5 */ + [ich5_sata] = { .sht = &piix_sht, .flags = PIIX_SATA_FLAGS, @@ -518,7 +508,7 @@ static struct ata_port_info piix_port_info[] = { .port_ops = &piix_sata_ops, }, - /* ich6_sata: 6 */ + [ich6_sata] = { .sht = &piix_sht, .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR, @@ -528,7 +518,7 @@ static struct ata_port_info piix_port_info[] = { .port_ops = &piix_sata_ops, }, - /* ich6_sata_ahci: 7 */ + [ich6_sata_ahci] = { .sht = &piix_sht, .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR | @@ -539,7 +529,7 @@ static struct ata_port_info piix_port_info[] = { .port_ops = &piix_sata_ops, }, - /* ich6m_sata_ahci: 8 */ + [ich6m_sata_ahci] = { .sht = &piix_sht, .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR | @@ -550,7 +540,7 @@ static struct ata_port_info piix_port_info[] = { .port_ops = &piix_sata_ops, }, - /* ich8_sata_ahci: 9 */ + [ich8_sata_ahci] = { .sht = &piix_sht, .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR | @@ -561,7 +551,7 @@ static struct ata_port_info piix_port_info[] = { .port_ops = &piix_sata_ops, }, - /* piix_pata_mwdma: 10: PIIX3 MWDMA only */ + [piix_pata_mwdma] = /* PIIX3 MWDMA only */ { .sht = &piix_sht, .flags = PIIX_PATA_FLAGS, @@ -570,7 +560,7 @@ static struct ata_port_info piix_port_info[] = { .port_ops = &piix_pata_ops, }, - /* tolapai_sata_ahci: 11: */ + [tolapai_sata_ahci] = { .sht = &piix_sht, .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR | -- cgit v1.2.3-70-g09d2 From 539cc7c70c12fbdad4ee11f901cd7a0d7f52b186 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 20 Sep 2007 16:31:47 -0400 Subject: [libata] blacklist Maxtor*BANC* using new wildcard blacklist matching Support the use of '*' in model_num and model_rev entries in ata_device_blacklist[]. Based largely on David Milburn's "libata-core: support wildcard matching in ata_blacklist_entry" patch. Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 84d81b26e38..2b222700d9b 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -3814,16 +3814,11 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { /* http://thread.gmane.org/gmane.linux.ide/14907 */ { "FUJITSU MHT2060BH", NULL, ATA_HORKAGE_NONCQ }, /* NCQ is broken */ - { "Maxtor 6L250S0", "BANC1G10", ATA_HORKAGE_NONCQ }, - { "Maxtor 6B200M0", "BANC1BM0", ATA_HORKAGE_NONCQ }, - { "Maxtor 6B200M0", "BANC1B10", ATA_HORKAGE_NONCQ }, - { "Maxtor 7B250S0", "BANC1B70", ATA_HORKAGE_NONCQ, }, - { "Maxtor 7B300S0", "BANC1B70", ATA_HORKAGE_NONCQ }, + { "Maxtor *", "BANC*", ATA_HORKAGE_NONCQ }, { "Maxtor 7V300F0", "VA111630", ATA_HORKAGE_NONCQ }, { "HITACHI HDS7250SASUN500G 0621KTAWSD", "K2AOAJ0AHITACHI", - ATA_HORKAGE_NONCQ }, - /* NCQ hard hangs device under heavier load, needs hard power cycle */ - { "Maxtor 6B250S0", "BANC1B70", ATA_HORKAGE_NONCQ }, + ATA_HORKAGE_NONCQ }, + /* Blacklist entries taken from Silicon Image 3124/3132 Windows driver .inf file - also several Linux problem reports */ { "HTS541060G9SA00", "MB3OC60D", ATA_HORKAGE_NONCQ, }, @@ -3849,6 +3844,23 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { } }; +int strn_pattern_cmp(const char *patt, const char *name, int wildchar) +{ + const char *p; + int len; + + /* + * check for trailing wildcard: *\0 + */ + p = strchr(patt, wildchar); + if (p && ((*(p + 1)) == 0)) + len = p - patt; + else + len = strlen(name); + + return strncmp(patt, name, len); +} + static unsigned long ata_dev_blacklisted(const struct ata_device *dev) { unsigned char model_num[ATA_ID_PROD_LEN + 1]; @@ -3859,10 +3871,10 @@ static unsigned long ata_dev_blacklisted(const struct ata_device *dev) ata_id_c_string(dev->id, model_rev, ATA_ID_FW_REV, sizeof(model_rev)); while (ad->model_num) { - if (!strcmp(ad->model_num, model_num)) { + if (!strn_pattern_cmp(ad->model_num, model_num, '*')) { if (ad->model_rev == NULL) return ad->horkage; - if (!strcmp(ad->model_rev, model_rev)) + if (!strn_pattern_cmp(ad->model_rev, model_rev, '*')) return ad->horkage; } ad++; -- cgit v1.2.3-70-g09d2 From c645fd34256e8ef4986d3e8acd569890cc421e5d Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Thu, 20 Sep 2007 14:58:48 +0100 Subject: libata: Update experimental tags to reflect reality better Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/Kconfig | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 2cd0e747671..3a737bdce2e 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -192,8 +192,8 @@ config PATA_AMD If unsure, say N. config PATA_ARTOP - tristate "ARTOP 6210/6260 PATA support (Experimental)" - depends on PCI && EXPERIMENTAL + tristate "ARTOP 6210/6260 PATA support" + depends on PCI help This option enables support for ARTOP PATA controllers. @@ -209,8 +209,8 @@ config PATA_AT32 If unsure, say N. config PATA_ATIIXP - tristate "ATI PATA support (Experimental)" - depends on PCI && EXPERIMENTAL + tristate "ATI PATA support" + depends on PCI help This option enables support for the ATI ATA interfaces found on the many ATI chipsets. @@ -228,8 +228,8 @@ config PATA_CMD640_PCI If unsure, say N. config PATA_CMD64X - tristate "CMD64x PATA support (Very Experimental)" - depends on PCI&& EXPERIMENTAL + tristate "CMD64x PATA support" + depends on PCI help This option enables support for the CMD64x series chips except for the CMD640. @@ -291,8 +291,8 @@ config ATA_GENERIC If unsure, say N. config PATA_HPT366 - tristate "HPT 366/368 PATA support (Experimental)" - depends on PCI && EXPERIMENTAL + tristate "HPT 366/368 PATA support" + depends on PCI help This option enables support for the HPT 366 and 368 PATA controllers via the new ATA layer. -- cgit v1.2.3-70-g09d2 From d2a84f47899d1efc24fa610696f7b793692279c7 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Thu, 20 Sep 2007 15:07:12 +0100 Subject: pdc2027x: Switch properly to ioread/iowrite Some iomap functions were still using readl/writel and friends which happens to work on most platforms but is not correct. Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/pata_pdc2027x.c | 56 ++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c index f87c800be7f..3d3f1558cde 100644 --- a/drivers/ata/pata_pdc2027x.c +++ b/drivers/ata/pata_pdc2027x.c @@ -273,7 +273,7 @@ static int pdc2027x_cable_detect(struct ata_port *ap) u32 cgcr; /* check cable detect results */ - cgcr = readl(port_mmio(ap, PDC_GLOBAL_CTL)); + cgcr = ioread32(port_mmio(ap, PDC_GLOBAL_CTL)); if (cgcr & (1 << 26)) goto cbl40; @@ -291,7 +291,7 @@ cbl40: */ static inline int pdc2027x_port_enabled(struct ata_port *ap) { - return readb(port_mmio(ap, PDC_ATA_CTL)) & 0x02; + return ioread8(port_mmio(ap, PDC_ATA_CTL)) & 0x02; } /** @@ -383,16 +383,16 @@ static void pdc2027x_set_piomode(struct ata_port *ap, struct ata_device *adev) /* Set the PIO timing registers using value table for 133MHz */ PDPRINTK("Set pio regs... \n"); - ctcr0 = readl(dev_mmio(ap, adev, PDC_CTCR0)); + ctcr0 = ioread32(dev_mmio(ap, adev, PDC_CTCR0)); ctcr0 &= 0xffff0000; ctcr0 |= pdc2027x_pio_timing_tbl[pio].value0 | (pdc2027x_pio_timing_tbl[pio].value1 << 8); - writel(ctcr0, dev_mmio(ap, adev, PDC_CTCR0)); + iowrite32(ctcr0, dev_mmio(ap, adev, PDC_CTCR0)); - ctcr1 = readl(dev_mmio(ap, adev, PDC_CTCR1)); + ctcr1 = ioread32(dev_mmio(ap, adev, PDC_CTCR1)); ctcr1 &= 0x00ffffff; ctcr1 |= (pdc2027x_pio_timing_tbl[pio].value2 << 24); - writel(ctcr1, dev_mmio(ap, adev, PDC_CTCR1)); + iowrite32(ctcr1, dev_mmio(ap, adev, PDC_CTCR1)); PDPRINTK("Set pio regs done\n"); @@ -426,18 +426,18 @@ static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev) * If tHOLD is '1', the hardware will add half clock for data hold time. * This code segment seems to be no effect. tHOLD will be overwritten below. */ - ctcr1 = readl(dev_mmio(ap, adev, PDC_CTCR1)); - writel(ctcr1 & ~(1 << 7), dev_mmio(ap, adev, PDC_CTCR1)); + ctcr1 = ioread32(dev_mmio(ap, adev, PDC_CTCR1)); + iowrite32(ctcr1 & ~(1 << 7), dev_mmio(ap, adev, PDC_CTCR1)); } PDPRINTK("Set udma regs... \n"); - ctcr1 = readl(dev_mmio(ap, adev, PDC_CTCR1)); + ctcr1 = ioread32(dev_mmio(ap, adev, PDC_CTCR1)); ctcr1 &= 0xff000000; ctcr1 |= pdc2027x_udma_timing_tbl[udma_mode].value0 | (pdc2027x_udma_timing_tbl[udma_mode].value1 << 8) | (pdc2027x_udma_timing_tbl[udma_mode].value2 << 16); - writel(ctcr1, dev_mmio(ap, adev, PDC_CTCR1)); + iowrite32(ctcr1, dev_mmio(ap, adev, PDC_CTCR1)); PDPRINTK("Set udma regs done\n"); @@ -449,13 +449,13 @@ static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev) unsigned int mdma_mode = dma_mode & 0x07; PDPRINTK("Set mdma regs... \n"); - ctcr0 = readl(dev_mmio(ap, adev, PDC_CTCR0)); + ctcr0 = ioread32(dev_mmio(ap, adev, PDC_CTCR0)); ctcr0 &= 0x0000ffff; ctcr0 |= (pdc2027x_mdma_timing_tbl[mdma_mode].value0 << 16) | (pdc2027x_mdma_timing_tbl[mdma_mode].value1 << 24); - writel(ctcr0, dev_mmio(ap, adev, PDC_CTCR0)); + iowrite32(ctcr0, dev_mmio(ap, adev, PDC_CTCR0)); PDPRINTK("Set mdma regs done\n"); PDPRINTK("Set to mdma mode[%u] \n", mdma_mode); @@ -492,9 +492,9 @@ static int pdc2027x_set_mode(struct ata_link *link, struct ata_device **r_failed * Enable prefetch if the device support PIO only. */ if (dev->xfer_shift == ATA_SHIFT_PIO) { - u32 ctcr1 = readl(dev_mmio(ap, dev, PDC_CTCR1)); + u32 ctcr1 = ioread32(dev_mmio(ap, dev, PDC_CTCR1)); ctcr1 |= (1 << 25); - writel(ctcr1, dev_mmio(ap, dev, PDC_CTCR1)); + iowrite32(ctcr1, dev_mmio(ap, dev, PDC_CTCR1)); PDPRINTK("Turn on prefetch\n"); } else { @@ -559,12 +559,12 @@ static long pdc_read_counter(struct ata_host *host) u32 bccrl, bccrh, bccrlv, bccrhv; retry: - bccrl = readl(mmio_base + PDC_BYTE_COUNT) & 0x7fff; - bccrh = readl(mmio_base + PDC_BYTE_COUNT + 0x100) & 0x7fff; + bccrl = ioread32(mmio_base + PDC_BYTE_COUNT) & 0x7fff; + bccrh = ioread32(mmio_base + PDC_BYTE_COUNT + 0x100) & 0x7fff; /* Read the counter values again for verification */ - bccrlv = readl(mmio_base + PDC_BYTE_COUNT) & 0x7fff; - bccrhv = readl(mmio_base + PDC_BYTE_COUNT + 0x100) & 0x7fff; + bccrlv = ioread32(mmio_base + PDC_BYTE_COUNT) & 0x7fff; + bccrhv = ioread32(mmio_base + PDC_BYTE_COUNT + 0x100) & 0x7fff; counter = (bccrh << 15) | bccrl; @@ -613,7 +613,7 @@ static void pdc_adjust_pll(struct ata_host *host, long pll_clock, unsigned int b /* Show the current clock value of PLL control register * (maybe already configured by the firmware) */ - pll_ctl = readw(mmio_base + PDC_PLL_CTL); + pll_ctl = ioread16(mmio_base + PDC_PLL_CTL); PDPRINTK("pll_ctl[%X]\n", pll_ctl); #endif @@ -653,8 +653,8 @@ static void pdc_adjust_pll(struct ata_host *host, long pll_clock, unsigned int b PDPRINTK("Writing pll_ctl[%X]\n", pll_ctl); - writew(pll_ctl, mmio_base + PDC_PLL_CTL); - readw(mmio_base + PDC_PLL_CTL); /* flush */ + iowrite16(pll_ctl, mmio_base + PDC_PLL_CTL); + ioread16(mmio_base + PDC_PLL_CTL); /* flush */ /* Wait the PLL circuit to be stable */ mdelay(30); @@ -664,7 +664,7 @@ static void pdc_adjust_pll(struct ata_host *host, long pll_clock, unsigned int b * Show the current clock value of PLL control register * (maybe configured by the firmware) */ - pll_ctl = readw(mmio_base + PDC_PLL_CTL); + pll_ctl = ioread16(mmio_base + PDC_PLL_CTL); PDPRINTK("pll_ctl[%X]\n", pll_ctl); #endif @@ -687,10 +687,10 @@ static long pdc_detect_pll_input_clock(struct ata_host *host) long pll_clock, usec_elapsed; /* Start the test mode */ - scr = readl(mmio_base + PDC_SYS_CTL); + scr = ioread32(mmio_base + PDC_SYS_CTL); PDPRINTK("scr[%X]\n", scr); - writel(scr | (0x01 << 14), mmio_base + PDC_SYS_CTL); - readl(mmio_base + PDC_SYS_CTL); /* flush */ + iowrite32(scr | (0x01 << 14), mmio_base + PDC_SYS_CTL); + ioread32(mmio_base + PDC_SYS_CTL); /* flush */ /* Read current counter value */ start_count = pdc_read_counter(host); @@ -704,10 +704,10 @@ static long pdc_detect_pll_input_clock(struct ata_host *host) do_gettimeofday(&end_time); /* Stop the test mode */ - scr = readl(mmio_base + PDC_SYS_CTL); + scr = ioread32(mmio_base + PDC_SYS_CTL); PDPRINTK("scr[%X]\n", scr); - writel(scr & ~(0x01 << 14), mmio_base + PDC_SYS_CTL); - readl(mmio_base + PDC_SYS_CTL); /* flush */ + iowrite32(scr & ~(0x01 << 14), mmio_base + PDC_SYS_CTL); + ioread32(mmio_base + PDC_SYS_CTL); /* flush */ /* calculate the input clock in Hz */ usec_elapsed = (end_time.tv_sec - start_time.tv_sec) * 1000000 + -- cgit v1.2.3-70-g09d2 From e10b8c3f5f23188e065b1845ba732570eca007fe Mon Sep 17 00:00:00 2001 From: Boaz Harrosh Date: Tue, 18 Sep 2007 17:46:12 +0200 Subject: libata-scsi: Remove !use_sg code paths This is a minimal patch needed to remove use of !use_sg but it is not a complete clean up of the !use_sg paths. Libata-core still has the qc->flags & ATA_QCFLAG_SG and !qc->n_elem code paths. Perhaps an ata maintainer would have a go at it. - TODO: further cleanup of qc->flags & ATA_QCFLAG_SG and !qc->n_elem code paths in libata-core - TODO: Use scsi_dma_{map,unmap} where applicable. Signed-off-by: Jeff Garzik --- drivers/ata/libata-scsi.c | 31 +++++++++---------------------- 1 file changed, 9 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index f0f586b56c2..598ef1018e1 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -450,13 +450,8 @@ static struct ata_queued_cmd *ata_scsi_qc_new(struct ata_device *dev, qc->scsicmd = cmd; qc->scsidone = done; - if (cmd->use_sg) { - qc->__sg = (struct scatterlist *) cmd->request_buffer; - qc->n_elem = cmd->use_sg; - } else if (cmd->request_bufflen) { - qc->__sg = &qc->sgent; - qc->n_elem = 1; - } + qc->__sg = (struct scatterlist *) cmd->request_buffer; + qc->n_elem = cmd->use_sg; } else { cmd->result = (DID_OK << 16) | (QUEUE_FULL << 1); done(cmd); @@ -1504,11 +1499,7 @@ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd, goto err_did; } - if (cmd->use_sg) - ata_sg_init(qc, cmd->request_buffer, cmd->use_sg); - else - ata_sg_init_one(qc, cmd->request_buffer, - cmd->request_bufflen); + ata_sg_init(qc, cmd->request_buffer, cmd->use_sg); qc->dma_dir = cmd->sc_data_direction; } @@ -1562,15 +1553,14 @@ static unsigned int ata_scsi_rbuf_get(struct scsi_cmnd *cmd, u8 **buf_out) u8 *buf; unsigned int buflen; - if (cmd->use_sg) { - struct scatterlist *sg; + struct scatterlist *sg = (struct scatterlist *) cmd->request_buffer; - sg = (struct scatterlist *) cmd->request_buffer; + if (sg) { buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset; buflen = sg->length; } else { - buf = cmd->request_buffer; - buflen = cmd->request_bufflen; + buf = NULL; + buflen = 0; } *buf_out = buf; @@ -1590,12 +1580,9 @@ static unsigned int ata_scsi_rbuf_get(struct scsi_cmnd *cmd, u8 **buf_out) static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd, u8 *buf) { - if (cmd->use_sg) { - struct scatterlist *sg; - - sg = (struct scatterlist *) cmd->request_buffer; + struct scatterlist *sg = (struct scatterlist *) cmd->request_buffer; + if (sg) kunmap_atomic(buf - sg->offset, KM_IRQ0); - } } /** -- cgit v1.2.3-70-g09d2 From 7120165cf31e989baf7836218ca0a13643074735 Mon Sep 17 00:00:00 2001 From: Boaz Harrosh Date: Tue, 18 Sep 2007 17:48:50 +0200 Subject: libata-scsi: convert to use the data buffer accessors simple search-and-replace of direct scsi_cmnd access to use the data buffer accessors. Signed-off-by: Boaz Harrosh Signed-off-by: Jeff Garzik --- drivers/ata/libata-scsi.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 598ef1018e1..7ad046b7c35 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -450,8 +450,8 @@ static struct ata_queued_cmd *ata_scsi_qc_new(struct ata_device *dev, qc->scsicmd = cmd; qc->scsidone = done; - qc->__sg = (struct scatterlist *) cmd->request_buffer; - qc->n_elem = cmd->use_sg; + qc->__sg = scsi_sglist(cmd); + qc->n_elem = scsi_sg_count(cmd); } else { cmd->result = (DID_OK << 16) | (QUEUE_FULL << 1); done(cmd); @@ -1493,13 +1493,13 @@ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd, /* data is present; dma-map it */ if (cmd->sc_data_direction == DMA_FROM_DEVICE || cmd->sc_data_direction == DMA_TO_DEVICE) { - if (unlikely(cmd->request_bufflen < 1)) { + if (unlikely(scsi_bufflen(cmd) < 1)) { ata_dev_printk(dev, KERN_WARNING, "WARNING: zero len r/w req\n"); goto err_did; } - ata_sg_init(qc, cmd->request_buffer, cmd->use_sg); + ata_sg_init(qc, scsi_sglist(cmd), scsi_sg_count(cmd)); qc->dma_dir = cmd->sc_data_direction; } @@ -1553,7 +1553,7 @@ static unsigned int ata_scsi_rbuf_get(struct scsi_cmnd *cmd, u8 **buf_out) u8 *buf; unsigned int buflen; - struct scatterlist *sg = (struct scatterlist *) cmd->request_buffer; + struct scatterlist *sg = scsi_sglist(cmd); if (sg) { buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset; @@ -1580,7 +1580,7 @@ static unsigned int ata_scsi_rbuf_get(struct scsi_cmnd *cmd, u8 **buf_out) static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd, u8 *buf) { - struct scatterlist *sg = (struct scatterlist *) cmd->request_buffer; + struct scatterlist *sg = scsi_sglist(cmd); if (sg) kunmap_atomic(buf - sg->offset, KM_IRQ0); } @@ -2383,7 +2383,7 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc) } qc->tf.command = ATA_CMD_PACKET; - qc->nbytes = scmd->request_bufflen; + qc->nbytes = scsi_bufflen(scmd); /* check whether ATAPI DMA is safe */ if (!using_pio && ata_check_atapi_dma(qc)) @@ -2633,7 +2633,7 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc) case ATA_CMD_WRITE_LONG_ONCE: if (tf->protocol != ATA_PROT_PIO || tf->nsect != 1) goto invalid_fld; - qc->sect_size = scmd->request_bufflen; + qc->sect_size = scsi_bufflen(scmd); } /* @@ -2663,7 +2663,7 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc) * TODO: find out if we need to do more here to * cover scatter/gather case. */ - qc->nbytes = scmd->request_bufflen; + qc->nbytes = scsi_bufflen(scmd); /* request result TF */ qc->flags |= ATA_QCFLAG_RESULT_TF; -- cgit v1.2.3-70-g09d2 From e2d352af6d8f1734394bc1bcf0afe345cc3ef235 Mon Sep 17 00:00:00 2001 From: Jason Gaston Date: Fri, 7 Sep 2007 17:21:03 -0700 Subject: ata_piix: replace spaces with tabs This patch removes some incorrect formatting spaces and replaces them with tabs. Signed-off-by: Jason Gaston Signed-off-by: Jeff Garzik --- drivers/ata/ata_piix.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 7adb2aa009a..8dc15a6cea7 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -437,15 +437,15 @@ static const struct piix_map_db ich8_map_db = { }; static const struct piix_map_db tolapai_map_db = { - .mask = 0x3, - .port_enable = 0x3, - .map = { - /* PM PS SM SS MAP */ - { P0, NA, P1, NA }, /* 00b */ - { RV, RV, RV, RV }, /* 01b */ - { RV, RV, RV, RV }, /* 10b */ - { RV, RV, RV, RV }, - }, + .mask = 0x3, + .port_enable = 0x3, + .map = { + /* PM PS SM SS MAP */ + { P0, NA, P1, NA }, /* 00b */ + { RV, RV, RV, RV }, /* 01b */ + { RV, RV, RV, RV }, /* 10b */ + { RV, RV, RV, RV }, + }, }; static const struct piix_map_db *piix_map_db_table[] = { -- cgit v1.2.3-70-g09d2 From db6f8759d05d2082f09a45b5674edc0fb5e92b1b Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 3 Sep 2007 12:31:58 +0900 Subject: libata: move ata_id_n_sectors() upward Move ata_id_n_sectors() upward right below ata_id_c_string(). This is to accomodate later changes. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 2b222700d9b..b33aea3638d 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -821,6 +821,21 @@ void ata_id_c_string(const u16 *id, unsigned char *s, *p = '\0'; } +static u64 ata_id_n_sectors(const u16 *id) +{ + if (ata_id_has_lba(id)) { + if (ata_id_has_lba48(id)) + return ata_id_u64(id, 100); + else + return ata_id_u32(id, 60); + } else { + if (ata_id_current_chs_valid(id)) + return ata_id_u32(id, 57); + else + return id[1] * id[3] * id[6]; + } +} + static u64 ata_tf_to_lba48(struct ata_taskfile *tf) { u64 sectors = 0; @@ -1021,21 +1036,6 @@ static u64 ata_hpa_resize(struct ata_device *dev) return sectors; } -static u64 ata_id_n_sectors(const u16 *id) -{ - if (ata_id_has_lba(id)) { - if (ata_id_has_lba48(id)) - return ata_id_u64(id, 100); - else - return ata_id_u32(id, 60); - } else { - if (ata_id_current_chs_valid(id)) - return ata_id_u32(id, 57); - else - return id[1] * id[3] * id[6]; - } -} - /** * ata_id_to_dma_mode - Identify DMA mode from id block * @dev: device to identify -- cgit v1.2.3-70-g09d2 From c728a9149f519cbb9f610962873f4e22ed4a6efd Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 3 Sep 2007 12:32:30 +0900 Subject: libata: clean up read/set native_max address functions Merge ata_read_native_max_addres_ext() into ata_read_native_max_address() and combine ata_set_native_max_address_ext() and ata_set_native_max_address() into ata_set_max_sectors(). * reduce duplicate code * return 0 or -errno depending on error conditions * report if command fails * use ATA_LBA instead of 0x40 This is in preparation of ata_hpa_resize() update. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 174 ++++++++++++++++++++-------------------------- 1 file changed, 77 insertions(+), 97 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index b33aea3638d..c7614bdc0cb 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -863,129 +863,113 @@ static u64 ata_tf_to_lba(struct ata_taskfile *tf) } /** - * ata_read_native_max_address_ext - LBA48 native max query - * @dev: Device to query + * ata_read_native_max_address - Read native max address + * @dev: target device + * @max_sectors: out parameter for the result native max address * - * Perform an LBA48 size query upon the device in question. Return the - * actual LBA48 size or zero if the command fails. - */ - -static u64 ata_read_native_max_address_ext(struct ata_device *dev) -{ - unsigned int err; - struct ata_taskfile tf; - - ata_tf_init(dev, &tf); - - tf.command = ATA_CMD_READ_NATIVE_MAX_EXT; - tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48 | ATA_TFLAG_ISADDR; - tf.protocol |= ATA_PROT_NODATA; - tf.device |= 0x40; - - err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); - if (err) - return 0; - - return ata_tf_to_lba48(&tf); -} - -/** - * ata_read_native_max_address - LBA28 native max query - * @dev: Device to query + * Perform an LBA48 or LBA28 native size query upon the device in + * question. * - * Performa an LBA28 size query upon the device in question. Return the - * actual LBA28 size or zero if the command fails. + * RETURNS: + * 0 on success, -EACCES if command is aborted by the drive. + * -EIO on other errors. */ - -static u64 ata_read_native_max_address(struct ata_device *dev) +static int ata_read_native_max_address(struct ata_device *dev, u64 *max_sectors) { - unsigned int err; + unsigned int err_mask; struct ata_taskfile tf; + int lba48 = ata_id_has_lba48(dev->id); ata_tf_init(dev, &tf); - tf.command = ATA_CMD_READ_NATIVE_MAX; + /* always clear all address registers */ tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR; - tf.protocol |= ATA_PROT_NODATA; - tf.device |= 0x40; - err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); - if (err) - return 0; - - return ata_tf_to_lba(&tf); -} - -/** - * ata_set_native_max_address_ext - LBA48 native max set - * @dev: Device to query - * @new_sectors: new max sectors value to set for the device - * - * Perform an LBA48 size set max upon the device in question. Return the - * actual LBA48 size or zero if the command fails. - */ - -static u64 ata_set_native_max_address_ext(struct ata_device *dev, u64 new_sectors) -{ - unsigned int err; - struct ata_taskfile tf; - - new_sectors--; - - ata_tf_init(dev, &tf); + if (lba48) { + tf.command = ATA_CMD_READ_NATIVE_MAX_EXT; + tf.flags |= ATA_TFLAG_LBA48; + } else + tf.command = ATA_CMD_READ_NATIVE_MAX; - tf.command = ATA_CMD_SET_MAX_EXT; - tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48 | ATA_TFLAG_ISADDR; tf.protocol |= ATA_PROT_NODATA; - tf.device |= 0x40; - - tf.lbal = (new_sectors >> 0) & 0xff; - tf.lbam = (new_sectors >> 8) & 0xff; - tf.lbah = (new_sectors >> 16) & 0xff; + tf.device |= ATA_LBA; - tf.hob_lbal = (new_sectors >> 24) & 0xff; - tf.hob_lbam = (new_sectors >> 32) & 0xff; - tf.hob_lbah = (new_sectors >> 40) & 0xff; + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); + if (err_mask) { + ata_dev_printk(dev, KERN_WARNING, "failed to read native " + "max address (err_mask=0x%x)\n", err_mask); + if (err_mask == AC_ERR_DEV && (tf.feature & ATA_ABORTED)) + return -EACCES; + return -EIO; + } - err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); - if (err) - return 0; + if (lba48) + *max_sectors = ata_tf_to_lba48(&tf); + else + *max_sectors = ata_tf_to_lba(&tf); - return ata_tf_to_lba48(&tf); + return 0; } /** - * ata_set_native_max_address - LBA28 native max set - * @dev: Device to query + * ata_set_max_sectors - Set max sectors + * @dev: target device * @new_sectors: new max sectors value to set for the device + * @res_sectors: result max sectors * - * Perform an LBA28 size set max upon the device in question. Return the - * actual LBA28 size or zero if the command fails. + * Set max sectors of @dev to @new_sectors. + * + * RETURNS: + * 0 on success, -EACCES if command is aborted or denied (due to + * previous non-volatile SET_MAX) by the drive. -EIO on other + * errors. */ - -static u64 ata_set_native_max_address(struct ata_device *dev, u64 new_sectors) +static int ata_set_max_sectors(struct ata_device *dev, u64 new_sectors, + u64 *res_sectors) { - unsigned int err; + unsigned int err_mask; struct ata_taskfile tf; + int lba48 = ata_id_has_lba48(dev->id); new_sectors--; ata_tf_init(dev, &tf); - tf.command = ATA_CMD_SET_MAX; tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR; + + if (lba48) { + tf.command = ATA_CMD_SET_MAX_EXT; + tf.flags |= ATA_TFLAG_LBA48; + + tf.hob_lbal = (new_sectors >> 24) & 0xff; + tf.hob_lbam = (new_sectors >> 32) & 0xff; + tf.hob_lbah = (new_sectors >> 40) & 0xff; + } else + tf.command = ATA_CMD_SET_MAX; + tf.protocol |= ATA_PROT_NODATA; + tf.device |= ATA_LBA; tf.lbal = (new_sectors >> 0) & 0xff; tf.lbam = (new_sectors >> 8) & 0xff; tf.lbah = (new_sectors >> 16) & 0xff; - tf.device |= ((new_sectors >> 24) & 0x0f) | 0x40; - err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); - if (err) - return 0; + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); + if (err_mask) { + ata_dev_printk(dev, KERN_WARNING, "failed to set " + "max address (err_mask=0x%x)\n", err_mask); + if (err_mask == AC_ERR_DEV && + (tf.feature & (ATA_ABORTED | ATA_IDNF))) + return -EACCES; + return -EIO; + } - return ata_tf_to_lba(&tf); + if (lba48) + *res_sectors = ata_tf_to_lba48(&tf); + else + *res_sectors = ata_tf_to_lba(&tf); + + return 0; } /** @@ -1001,11 +985,11 @@ static u64 ata_hpa_resize(struct ata_device *dev) { u64 sectors = dev->n_sectors; u64 hpa_sectors; + int rc; - if (ata_id_has_lba48(dev->id)) - hpa_sectors = ata_read_native_max_address_ext(dev); - else - hpa_sectors = ata_read_native_max_address(dev); + rc = ata_read_native_max_address(dev, &hpa_sectors); + if (rc) + return 0; if (hpa_sectors > sectors) { ata_dev_printk(dev, KERN_INFO, @@ -1015,13 +999,9 @@ static u64 ata_hpa_resize(struct ata_device *dev) (long long)sectors, (long long)hpa_sectors); if (ata_ignore_hpa) { - if (ata_id_has_lba48(dev->id)) - hpa_sectors = ata_set_native_max_address_ext(dev, hpa_sectors); - else - hpa_sectors = ata_set_native_max_address(dev, - hpa_sectors); + rc = ata_set_max_sectors(dev, hpa_sectors, &hpa_sectors); - if (hpa_sectors) { + if (rc == 0) { ata_dev_printk(dev, KERN_INFO, "native size " "increased to %lld sectors\n", (long long)hpa_sectors); -- cgit v1.2.3-70-g09d2 From 05027adccc09401a7e31d5ef51040dc75ab03c22 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 3 Sep 2007 12:32:57 +0900 Subject: libata: remiplement ata_hpa_resize() This patch reimplement ata_hpa_resize() such that... * All HPA related decisions are made inside ata_hpa_resize() proper. ata_hpa_resize() returns 0 if configuration can proceed, -errno if device needs to be reset and reconfigured. * All errors are handled properly. If HPA unlocking isn't requested, HPA handling is disabled automatically to avoid unnecessary device detection failure. * Messages are trimmed. HPA detection message is printed only during initial configuration. HPA unlocked message is printed only during initial configuration or unlocking results in different size. * Instead of using sectors returned in TF of SET_MAX, re-read IDENTIFY data as that's the value the device is going to use. * It's called early during ata_dev_configure() as IDENTIFY data might change after resizing. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 124 +++++++++++++++++++++++++++++++--------------- 1 file changed, 85 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index c7614bdc0cb..b01b5a897dc 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -915,7 +915,6 @@ static int ata_read_native_max_address(struct ata_device *dev, u64 *max_sectors) * ata_set_max_sectors - Set max sectors * @dev: target device * @new_sectors: new max sectors value to set for the device - * @res_sectors: result max sectors * * Set max sectors of @dev to @new_sectors. * @@ -924,8 +923,7 @@ static int ata_read_native_max_address(struct ata_device *dev, u64 *max_sectors) * previous non-volatile SET_MAX) by the drive. -EIO on other * errors. */ -static int ata_set_max_sectors(struct ata_device *dev, u64 new_sectors, - u64 *res_sectors) +static int ata_set_max_sectors(struct ata_device *dev, u64 new_sectors) { unsigned int err_mask; struct ata_taskfile tf; @@ -964,11 +962,6 @@ static int ata_set_max_sectors(struct ata_device *dev, u64 new_sectors, return -EIO; } - if (lba48) - *res_sectors = ata_tf_to_lba48(&tf); - else - *res_sectors = ata_tf_to_lba(&tf); - return 0; } @@ -979,41 +972,93 @@ static int ata_set_max_sectors(struct ata_device *dev, u64 new_sectors, * Read the size of an LBA28 or LBA48 disk with HPA features and resize * it if required to the full size of the media. The caller must check * the drive has the HPA feature set enabled. + * + * RETURNS: + * 0 on success, -errno on failure. */ - -static u64 ata_hpa_resize(struct ata_device *dev) +static int ata_hpa_resize(struct ata_device *dev) { - u64 sectors = dev->n_sectors; - u64 hpa_sectors; + struct ata_eh_context *ehc = &dev->link->eh_context; + int print_info = ehc->i.flags & ATA_EHI_PRINTINFO; + u64 sectors = ata_id_n_sectors(dev->id); + u64 native_sectors; int rc; - rc = ata_read_native_max_address(dev, &hpa_sectors); - if (rc) + /* do we need to do it? */ + if (dev->class != ATA_DEV_ATA || + !ata_id_has_lba(dev->id) || !ata_id_hpa_enabled(dev->id) || + (dev->horkage & ATA_HORKAGE_BROKEN_HPA)) return 0; - if (hpa_sectors > sectors) { - ata_dev_printk(dev, KERN_INFO, - "Host Protected Area detected:\n" - "\tcurrent size: %lld sectors\n" - "\tnative size: %lld sectors\n", - (long long)sectors, (long long)hpa_sectors); - - if (ata_ignore_hpa) { - rc = ata_set_max_sectors(dev, hpa_sectors, &hpa_sectors); - - if (rc == 0) { - ata_dev_printk(dev, KERN_INFO, "native size " - "increased to %lld sectors\n", - (long long)hpa_sectors); - return hpa_sectors; - } + /* read native max address */ + rc = ata_read_native_max_address(dev, &native_sectors); + if (rc) { + /* If HPA isn't going to be unlocked, skip HPA + * resizing from the next try. + */ + if (!ata_ignore_hpa) { + ata_dev_printk(dev, KERN_WARNING, "HPA support seems " + "broken, will skip HPA handling\n"); + dev->horkage |= ATA_HORKAGE_BROKEN_HPA; + + /* we can continue if device aborted the command */ + if (rc == -EACCES) + rc = 0; } - } else if (hpa_sectors < sectors) - ata_dev_printk(dev, KERN_WARNING, "%s 1: hpa sectors (%lld) " - "is smaller than sectors (%lld)\n", __FUNCTION__, - (long long)hpa_sectors, (long long)sectors); - return sectors; + return rc; + } + + /* nothing to do? */ + if (native_sectors <= sectors || !ata_ignore_hpa) { + if (!print_info || native_sectors == sectors) + return 0; + + if (native_sectors > sectors) + ata_dev_printk(dev, KERN_INFO, + "HPA detected: current %llu, native %llu\n", + (unsigned long long)sectors, + (unsigned long long)native_sectors); + else if (native_sectors < sectors) + ata_dev_printk(dev, KERN_WARNING, + "native sectors (%llu) is smaller than " + "sectors (%llu)\n", + (unsigned long long)native_sectors, + (unsigned long long)sectors); + return 0; + } + + /* let's unlock HPA */ + rc = ata_set_max_sectors(dev, native_sectors); + if (rc == -EACCES) { + /* if device aborted the command, skip HPA resizing */ + ata_dev_printk(dev, KERN_WARNING, "device aborted resize " + "(%llu -> %llu), skipping HPA handling\n", + (unsigned long long)sectors, + (unsigned long long)native_sectors); + dev->horkage |= ATA_HORKAGE_BROKEN_HPA; + return 0; + } else if (rc) + return rc; + + /* re-read IDENTIFY data */ + rc = ata_dev_reread_id(dev, 0); + if (rc) { + ata_dev_printk(dev, KERN_ERR, "failed to re-read IDENTIFY " + "data after HPA resizing\n"); + return rc; + } + + if (print_info) { + u64 new_sectors = ata_id_n_sectors(dev->id); + ata_dev_printk(dev, KERN_INFO, + "HPA unlocked: %llu -> %llu, native %llu\n", + (unsigned long long)sectors, + (unsigned long long)new_sectors, + (unsigned long long)native_sectors); + } + + return 0; } /** @@ -1837,6 +1882,11 @@ int ata_dev_configure(struct ata_device *dev) if (rc) return rc; + /* massage HPA, do it early as it might change IDENTIFY data */ + rc = ata_hpa_resize(dev); + if (rc) + return rc; + /* print device capabilities */ if (ata_msg_probe(ap)) ata_dev_printk(dev, KERN_DEBUG, @@ -1904,10 +1954,6 @@ int ata_dev_configure(struct ata_device *dev) dev->flags |= ATA_DFLAG_FLUSH_EXT; } - if (!(dev->horkage & ATA_HORKAGE_BROKEN_HPA) && - ata_id_hpa_enabled(dev->id)) - dev->n_sectors = ata_hpa_resize(dev); - /* config NCQ */ ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc)); -- cgit v1.2.3-70-g09d2 From 7a234aff3d83728fd83cf19df32d3df52566d2ac Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 3 Sep 2007 12:44:57 +0900 Subject: ahci: reimplement port_map handling Reimplement port_map handling such that 1. Non-zero PORTS_IMPL value is always examined and used if consistent with cap.n_ports. 2. When PI and cat.n_ports are inconsistent, honor cap.n_ports and force port_map to be ((1 << cap.n_ports) - 1). 3. There were two separate places dealing with port_map. Unify them to one. As all newer ahci chips seem to get PI correct and older ones usually have zero PI. Controllers with holes in PI are very unlikely to screw up PI, so #2 makes more sense than following inconsistent PI. Without this change, not setting ATA_FLAG_HONOR_PI when it's needed results in weird detection failure. This changed logic should be able to handle all known cases correctly automatically. Verified on ICH6 (reports 0 PI), ICH8 (with holes in port_map), ICH9, JMB360 and JMB363. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 89 ++++++++++++++++++++++++------------------------------ 1 file changed, 39 insertions(+), 50 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 518c5183035..57cc3e73a7e 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -77,11 +77,10 @@ enum { RX_FIS_UNK = 0x60, /* offset of Unknown FIS data */ board_ahci = 0, - board_ahci_pi = 1, - board_ahci_vt8251 = 2, - board_ahci_ign_iferr = 3, - board_ahci_sb600 = 4, - board_ahci_mv = 5, + board_ahci_vt8251 = 1, + board_ahci_ign_iferr = 2, + board_ahci_sb600 = 3, + board_ahci_mv = 4, /* global controller registers */ HOST_CAP = 0x00, /* host capabilities */ @@ -170,7 +169,6 @@ enum { /* ap->flags bits */ AHCI_FLAG_NO_NCQ = (1 << 24), AHCI_FLAG_IGN_IRQ_IF_ERR = (1 << 25), /* ignore IRQ_IF_ERR */ - AHCI_FLAG_HONOR_PI = (1 << 26), /* honor PORTS_IMPL */ AHCI_FLAG_IGN_SERR_INTERNAL = (1 << 27), /* ignore SERR_INTERNAL */ AHCI_FLAG_32BIT_ONLY = (1 << 28), /* force 32bit */ AHCI_FLAG_MV_PATA = (1 << 29), /* PATA port */ @@ -332,14 +330,6 @@ static const struct ata_port_info ahci_port_info[] = { .udma_mask = ATA_UDMA6, .port_ops = &ahci_ops, }, - /* board_ahci_pi */ - { - .flags = AHCI_FLAG_COMMON | AHCI_FLAG_HONOR_PI, - .link_flags = AHCI_LFLAG_COMMON, - .pio_mask = 0x1f, /* pio0-4 */ - .udma_mask = ATA_UDMA6, - .port_ops = &ahci_ops, - }, /* board_ahci_vt8251 */ { .flags = AHCI_FLAG_COMMON | AHCI_FLAG_NO_NCQ, @@ -371,8 +361,8 @@ static const struct ata_port_info ahci_port_info[] = { .sht = &ahci_sht, .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | - AHCI_FLAG_HONOR_PI | AHCI_FLAG_NO_NCQ | - AHCI_FLAG_NO_MSI | AHCI_FLAG_MV_PATA, + AHCI_FLAG_NO_NCQ | AHCI_FLAG_NO_MSI | + AHCI_FLAG_MV_PATA, .link_flags = AHCI_LFLAG_COMMON, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, @@ -392,23 +382,23 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */ { PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */ { PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */ - { PCI_VDEVICE(INTEL, 0x2821), board_ahci_pi }, /* ICH8 */ - { PCI_VDEVICE(INTEL, 0x2822), board_ahci_pi }, /* ICH8 */ - { PCI_VDEVICE(INTEL, 0x2824), board_ahci_pi }, /* ICH8 */ - { PCI_VDEVICE(INTEL, 0x2829), board_ahci_pi }, /* ICH8M */ - { PCI_VDEVICE(INTEL, 0x282a), board_ahci_pi }, /* ICH8M */ - { PCI_VDEVICE(INTEL, 0x2922), board_ahci_pi }, /* ICH9 */ - { PCI_VDEVICE(INTEL, 0x2923), board_ahci_pi }, /* ICH9 */ - { PCI_VDEVICE(INTEL, 0x2924), board_ahci_pi }, /* ICH9 */ - { PCI_VDEVICE(INTEL, 0x2925), board_ahci_pi }, /* ICH9 */ - { PCI_VDEVICE(INTEL, 0x2927), board_ahci_pi }, /* ICH9 */ - { PCI_VDEVICE(INTEL, 0x2929), board_ahci_pi }, /* ICH9M */ - { PCI_VDEVICE(INTEL, 0x292a), board_ahci_pi }, /* ICH9M */ - { PCI_VDEVICE(INTEL, 0x292b), board_ahci_pi }, /* ICH9M */ - { PCI_VDEVICE(INTEL, 0x292c), board_ahci_pi }, /* ICH9M */ - { PCI_VDEVICE(INTEL, 0x292f), board_ahci_pi }, /* ICH9M */ - { PCI_VDEVICE(INTEL, 0x294d), board_ahci_pi }, /* ICH9 */ - { PCI_VDEVICE(INTEL, 0x294e), board_ahci_pi }, /* ICH9M */ + { PCI_VDEVICE(INTEL, 0x2821), board_ahci }, /* ICH8 */ + { PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* ICH8 */ + { PCI_VDEVICE(INTEL, 0x2824), board_ahci }, /* ICH8 */ + { PCI_VDEVICE(INTEL, 0x2829), board_ahci }, /* ICH8M */ + { PCI_VDEVICE(INTEL, 0x282a), board_ahci }, /* ICH8M */ + { PCI_VDEVICE(INTEL, 0x2922), board_ahci }, /* ICH9 */ + { PCI_VDEVICE(INTEL, 0x2923), board_ahci }, /* ICH9 */ + { PCI_VDEVICE(INTEL, 0x2924), board_ahci }, /* ICH9 */ + { PCI_VDEVICE(INTEL, 0x2925), board_ahci }, /* ICH9 */ + { PCI_VDEVICE(INTEL, 0x2927), board_ahci }, /* ICH9 */ + { PCI_VDEVICE(INTEL, 0x2929), board_ahci }, /* ICH9M */ + { PCI_VDEVICE(INTEL, 0x292a), board_ahci }, /* ICH9M */ + { PCI_VDEVICE(INTEL, 0x292b), board_ahci }, /* ICH9M */ + { PCI_VDEVICE(INTEL, 0x292c), board_ahci }, /* ICH9M */ + { PCI_VDEVICE(INTEL, 0x292f), board_ahci }, /* ICH9M */ + { PCI_VDEVICE(INTEL, 0x294d), board_ahci }, /* ICH9 */ + { PCI_VDEVICE(INTEL, 0x294e), board_ahci }, /* ICH9M */ /* JMicron 360/1/3/5/6, match class to avoid IDE function */ { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, @@ -562,16 +552,6 @@ static void ahci_save_initial_config(struct pci_dev *pdev, cap &= ~HOST_CAP_NCQ; } - /* fixup zero port_map */ - if (!port_map) { - port_map = (1 << ahci_nr_ports(cap)) - 1; - dev_printk(KERN_WARNING, &pdev->dev, - "PORTS_IMPL is zero, forcing 0x%x\n", port_map); - - /* write the fixed up value to the PI register */ - hpriv->saved_port_map = port_map; - } - /* * Temporary Marvell 6145 hack: PATA port presence * is asserted through the standard AHCI port @@ -587,7 +567,7 @@ static void ahci_save_initial_config(struct pci_dev *pdev, } /* cross check port_map and cap.n_ports */ - if (pi->flags & AHCI_FLAG_HONOR_PI) { + if (port_map) { u32 tmp_port_map = port_map; int n_ports = ahci_nr_ports(cap); @@ -598,17 +578,26 @@ static void ahci_save_initial_config(struct pci_dev *pdev, } } - /* Whine if inconsistent. No need to update cap. - * port_map is used to determine number of ports. + /* If n_ports and port_map are inconsistent, whine and + * clear port_map and let it be generated from n_ports. */ - if (n_ports || tmp_port_map) + if (n_ports || tmp_port_map) { dev_printk(KERN_WARNING, &pdev->dev, "nr_ports (%u) and implemented port map " - "(0x%x) don't match\n", + "(0x%x) don't match, using nr_ports\n", ahci_nr_ports(cap), port_map); - } else { - /* fabricate port_map from cap.nr_ports */ + port_map = 0; + } + } + + /* fabricate port_map from cap.nr_ports */ + if (!port_map) { port_map = (1 << ahci_nr_ports(cap)) - 1; + dev_printk(KERN_WARNING, &pdev->dev, + "forcing PORTS_IMPL to 0x%x\n", port_map); + + /* write the fixed up value to the PI register */ + hpriv->saved_port_map = port_map; } /* record values to use during operation */ -- cgit v1.2.3-70-g09d2 From 3f19859ee95a38c066a0420eb8a30c76ecd67a42 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 2 Sep 2007 23:23:57 +0900 Subject: libata: update ata_dev_try_classify() arguments Make ata_dev_try_classify() take a pointer to ata_device instead of ata_port/port_number combination for consistency and add @present argument. @present indicates whether the device seems present during reset. It's the result of TF access during softreset and link onlineness during hardreset. @present will be used to improve diagnostic failure handling. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 30 ++++++++++++++++-------------- drivers/ata/pata_scc.c | 6 ++++-- drivers/ata/sata_mv.c | 2 +- include/linux/libata.h | 3 ++- 4 files changed, 23 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index b01b5a897dc..ea8c07b04f2 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -701,8 +701,8 @@ unsigned int ata_dev_classify(const struct ata_taskfile *tf) /** * ata_dev_try_classify - Parse returned ATA device signature - * @ap: ATA channel to examine - * @device: Device to examine (starting at zero) + * @dev: ATA device to classify (starting at zero) + * @present: device seems present * @r_err: Value of error register on completion * * After an event -- SRST, E.D.D., or SATA COMRESET -- occurs, @@ -720,15 +720,15 @@ unsigned int ata_dev_classify(const struct ata_taskfile *tf) * RETURNS: * Device type - %ATA_DEV_ATA, %ATA_DEV_ATAPI or %ATA_DEV_NONE. */ - -unsigned int -ata_dev_try_classify(struct ata_port *ap, unsigned int device, u8 *r_err) +unsigned int ata_dev_try_classify(struct ata_device *dev, int present, + u8 *r_err) { + struct ata_port *ap = dev->link->ap; struct ata_taskfile tf; unsigned int class; u8 err; - ap->ops->dev_select(ap, device); + ap->ops->dev_select(ap, dev->devno); memset(&tf, 0, sizeof(tf)); @@ -738,12 +738,12 @@ ata_dev_try_classify(struct ata_port *ap, unsigned int device, u8 *r_err) *r_err = err; /* see if device passed diags: if master then continue and warn later */ - if (err == 0 && device == 0) + if (err == 0 && dev->devno == 0) /* diagnostic fail : do nothing _YET_ */ - ap->link.device[device].horkage |= ATA_HORKAGE_DIAGNOSTIC; + dev->horkage |= ATA_HORKAGE_DIAGNOSTIC; else if (err == 1) /* do nothing */ ; - else if ((device == 0) && (err == 0x81)) + else if ((dev->devno == 0) && (err == 0x81)) /* do nothing */ ; else return ATA_DEV_NONE; @@ -3238,9 +3238,9 @@ void ata_bus_reset(struct ata_port *ap) /* * determine by signature whether we have ATA or ATAPI devices */ - device[0].class = ata_dev_try_classify(ap, 0, &err); + device[0].class = ata_dev_try_classify(&device[0], dev0, &err); if ((slave_possible) && (err != 0x81)) - device[1].class = ata_dev_try_classify(ap, 1, &err); + device[1].class = ata_dev_try_classify(&device[1], dev1, &err); /* is double-select really necessary? */ if (device[1].class != ATA_DEV_NONE) @@ -3479,9 +3479,11 @@ int ata_std_softreset(struct ata_link *link, unsigned int *classes, } /* determine by signature whether we have ATA or ATAPI devices */ - classes[0] = ata_dev_try_classify(ap, 0, &err); + classes[0] = ata_dev_try_classify(&link->device[0], + devmask & (1 << 0), &err); if (slave_possible && err != 0x81) - classes[1] = ata_dev_try_classify(ap, 1, &err); + classes[1] = ata_dev_try_classify(&link->device[1], + devmask & (1 << 1), &err); out: DPRINTK("EXIT, classes[0]=%u [1]=%u\n", classes[0], classes[1]); @@ -3600,7 +3602,7 @@ int sata_std_hardreset(struct ata_link *link, unsigned int *class, ap->ops->dev_select(ap, 0); /* probably unnecessary */ - *class = ata_dev_try_classify(ap, 0, NULL); + *class = ata_dev_try_classify(link->device, 1, NULL); DPRINTK("EXIT, class=%u\n", *class); return 0; diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c index 2153def3f34..941b72bec83 100644 --- a/drivers/ata/pata_scc.c +++ b/drivers/ata/pata_scc.c @@ -636,9 +636,11 @@ static int scc_std_softreset (struct ata_port *ap, unsigned int *classes, } /* determine by signature whether we have ATA or ATAPI devices */ - classes[0] = ata_dev_try_classify(ap, 0, &err); + classes[0] = ata_dev_try_classify(&ap->link.device[0], + devmask & (1 << 0), &err); if (slave_possible && err != 0x81) - classes[1] = ata_dev_try_classify(ap, 1, &err); + classes[1] = ata_dev_try_classify(&ap->link.device[1], + devmask & (1 << 1), &err); out: DPRINTK("EXIT, classes[0]=%u [1]=%u\n", classes[0], classes[1]); diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 08077efa9af..4df8311968e 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -2248,7 +2248,7 @@ comreset_retry: */ /* finally, read device signature from TF registers */ - *class = ata_dev_try_classify(ap, 0, NULL); + *class = ata_dev_try_classify(ap->link.device, 1, NULL); writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS); diff --git a/include/linux/libata.h b/include/linux/libata.h index 49da62d0c83..3ab2196c651 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -781,7 +781,8 @@ extern void ata_port_queue_task(struct ata_port *ap, work_func_t fn, extern u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val, unsigned long interval_msec, unsigned long timeout_msec); -extern unsigned int ata_dev_try_classify(struct ata_port *, unsigned int, u8 *); +extern unsigned int ata_dev_try_classify(struct ata_device *dev, int present, + u8 *r_err); /* * Default driver ops implementations -- cgit v1.2.3-70-g09d2 From d7fbee050753e153622b5d41bc8bd1cb19cda9b9 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 2 Sep 2007 23:24:48 +0900 Subject: libata: assume ATA_DEV_ATA on diagnostic failure Certain device which reports diagnostic failure also reports invalid device signature. Assume ATA_DEV_ATA on diagnostic failure if reset indicates device presence. This is fix for bugzilla bug 8784. http://bugzilla.kernel.org/show_bug.cgi?id=8784 Signed-off-by: Tejun Heo Acked-by: Alan Cox Cc: Edward Amsden Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index ea8c07b04f2..2116f279458 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -751,10 +751,20 @@ unsigned int ata_dev_try_classify(struct ata_device *dev, int present, /* determine if device is ATA or ATAPI */ class = ata_dev_classify(&tf); - if (class == ATA_DEV_UNKNOWN) - return ATA_DEV_NONE; - if ((class == ATA_DEV_ATA) && (ata_chk_status(ap) == 0)) - return ATA_DEV_NONE; + if (class == ATA_DEV_UNKNOWN) { + /* If the device failed diagnostic, it's likely to + * have reported incorrect device signature too. + * Assume ATA device if the device seems present but + * device signature is invalid with diagnostic + * failure. + */ + if (present && (dev->horkage & ATA_HORKAGE_DIAGNOSTIC)) + class = ATA_DEV_ATA; + else + class = ATA_DEV_NONE; + } else if ((class == ATA_DEV_ATA) && (ata_chk_status(ap) == 0)) + class = ATA_DEV_NONE; + return class; } -- cgit v1.2.3-70-g09d2 From d4155e6f13e931048036976d9fb47b5db53ee7a3 Mon Sep 17 00:00:00 2001 From: Jason Gaston Date: Thu, 20 Sep 2007 17:35:00 -0400 Subject: ahci: RAID mode SATA patch for Intel Tolapai Signed-off-by: Jason Gaston Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 57cc3e73a7e..b721569faaf 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -399,6 +399,8 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0x292f), board_ahci }, /* ICH9M */ { PCI_VDEVICE(INTEL, 0x294d), board_ahci }, /* ICH9 */ { PCI_VDEVICE(INTEL, 0x294e), board_ahci }, /* ICH9M */ + { PCI_VDEVICE(INTEL, 0x502a), board_ahci }, /* Tolapai */ + { PCI_VDEVICE(INTEL, 0x502b), board_ahci }, /* Tolapai */ /* JMicron 360/1/3/5/6, match class to avoid IDE function */ { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, -- cgit v1.2.3-70-g09d2 From ad355b4628a19ba2af30409e13083edda221a5c9 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Fri, 21 Sep 2007 20:38:03 -0400 Subject: [libata] SCSI: support INQUIRY page 89h (ATA info page) Signed-off-by: Jeff Garzik --- drivers/ata/libata-scsi.c | 72 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 68 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 7ad046b7c35..b39966299e7 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1803,6 +1803,61 @@ unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf, return 0; } +/** + * ata_scsiop_inq_89 - Simulate INQUIRY VPD page 89, ATA info + * @args: device IDENTIFY data / SCSI command of interest. + * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. + * @buflen: Response buffer length. + * + * Yields SAT-specified ATA VPD page. + * + * LOCKING: + * spin_lock_irqsave(host lock) + */ + +unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf, + unsigned int buflen) +{ + u8 pbuf[60]; + struct ata_taskfile tf; + unsigned int i; + + if (!buflen) + return 0; + + memset(&pbuf, 0, sizeof(pbuf)); + memset(&tf, 0, sizeof(tf)); + + pbuf[1] = 0x89; /* our page code */ + pbuf[2] = (0x238 >> 8); /* page size fixed at 238h */ + pbuf[3] = (0x238 & 0xff); + + memcpy(&pbuf[8], "ATA ", 8); + ata_id_string(args->id, &pbuf[16], ATA_ID_PROD, 16); + ata_id_string(args->id, &pbuf[32], ATA_ID_FW_REV, 4); + + /* we don't store the ATA device signature, so we fake it */ + + tf.command = ATA_DRDY; /* really, this is Status reg */ + tf.lbal = 0x1; + tf.nsect = 0x1; + + ata_tf_to_fis(&tf, 0, 1, &pbuf[36]); /* TODO: PMP? */ + pbuf[36] = 0x34; /* force D2H Reg FIS (34h) */ + + pbuf[56] = ATA_CMD_ID_ATA; + + i = min(buflen, 60U); + memcpy(rbuf, &pbuf[0], i); + buflen -= i; + + if (!buflen) + return 0; + + memcpy(&rbuf[60], &args->id[0], min(buflen, 512U)); + return 0; +} + /** * ata_scsiop_noop - Command handler that simply returns success. * @args: device IDENTIFY data / SCSI command of interest. @@ -2880,14 +2935,23 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd, ata_scsi_invalid_field(cmd, done); else if ((scsicmd[1] & 1) == 0) /* is EVPD clear? */ ata_scsi_rbuf_fill(&args, ata_scsiop_inq_std); - else if (scsicmd[2] == 0x00) + else switch (scsicmd[2]) { + case 0x00: ata_scsi_rbuf_fill(&args, ata_scsiop_inq_00); - else if (scsicmd[2] == 0x80) + break; + case 0x80: ata_scsi_rbuf_fill(&args, ata_scsiop_inq_80); - else if (scsicmd[2] == 0x83) + break; + case 0x83: ata_scsi_rbuf_fill(&args, ata_scsiop_inq_83); - else + break; + case 0x89: + ata_scsi_rbuf_fill(&args, ata_scsiop_inq_89); + break; + default: ata_scsi_invalid_field(cmd, done); + break; + } break; case MODE_SENSE: -- cgit v1.2.3-70-g09d2 From 453941455218a81eedcea5dbafa38b8815920a8c Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Fri, 21 Sep 2007 06:23:42 -0400 Subject: [libata] Slightly improved no-op REQUEST SENSE, SEND DIAGNOSTIC A few pedantic apps care about missing or lame "mandatory" SCSI commands, so REQUEST SENSE -- as we autosense, R.S. just returns zeroes SEND DIAGNOSTIC -- our default (no-op) self-test succeeds, all other requests for testing fail. Signed-off-by: Jeff Garzik --- drivers/ata/libata-scsi.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index b39966299e7..79550908adc 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -2912,6 +2912,7 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd, { struct ata_scsi_args args; const u8 *scsicmd = cmd->cmnd; + u8 tmp8; args.dev = dev; args.id = dev->id; @@ -2926,7 +2927,6 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd, case SEEK_10: case TEST_UNIT_READY: case FORMAT_UNIT: /* FIXME: correct? */ - case SEND_DIAGNOSTIC: /* FIXME: correct? */ ata_scsi_rbuf_fill(&args, ata_scsiop_noop); break; @@ -2979,8 +2979,19 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd, ata_scsi_rbuf_fill(&args, ata_scsiop_report_luns); break; - /* mandatory commands we haven't implemented yet */ case REQUEST_SENSE: + ata_scsi_set_sense(cmd, 0, 0, 0); + cmd->result = (DRIVER_SENSE << 24); + done(cmd); + break; + + case SEND_DIAGNOSTIC: + tmp8 = scsicmd[1] & ~(1 << 3); + if ((tmp8 == 0x4) && (!scsicmd[3]) && (!scsicmd[4])) + ata_scsi_rbuf_fill(&args, ata_scsiop_noop); + else + ata_scsi_invalid_field(cmd, done); + break; /* all other commands */ default: -- cgit v1.2.3-70-g09d2 From 00bd02027fc4a5cf92a3e538896b3642b40515df Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Fri, 21 Sep 2007 07:26:08 -0400 Subject: [libata] SCSI: improve FORMAT UNIT; minor code cleanups * SAT specifies that FORMAT UNIT should be translated into a series of READ and WRITE commands that zero the ATA device. That is far too cumbersome to bother with. Since we don't actually format the device, the old behavior of always returning success was inaccurate. Change FORMAT UNIT from returning success immediately (old behavior) to always returning an error (new behavior). * Add some comments around SYNCHRONIZE CACHE * Shuffle scsi command code around a bit, so that things are close to alphabetic order. Signed-off-by: Jeff Garzik --- drivers/ata/libata-scsi.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 79550908adc..553488015e4 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -2920,14 +2920,9 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd, args.done = done; switch(scsicmd[0]) { - /* no-op's, complete with success */ - case SYNCHRONIZE_CACHE: - case REZERO_UNIT: - case SEEK_6: - case SEEK_10: - case TEST_UNIT_READY: - case FORMAT_UNIT: /* FIXME: correct? */ - ata_scsi_rbuf_fill(&args, ata_scsiop_noop); + /* TODO: worth improving? */ + case FORMAT_UNIT: + ata_scsi_invalid_field(cmd, done); break; case INQUIRY: @@ -2985,6 +2980,20 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd, done(cmd); break; + /* if we reach this, then writeback caching is disabled, + * turning this into a no-op. + */ + case SYNCHRONIZE_CACHE: + /* fall through */ + + /* no-op's, complete with success */ + case REZERO_UNIT: + case SEEK_6: + case SEEK_10: + case TEST_UNIT_READY: + ata_scsi_rbuf_fill(&args, ata_scsiop_noop); + break; + case SEND_DIAGNOSTIC: tmp8 = scsicmd[1] & ~(1 << 3); if ((tmp8 == 0x4) && (!scsicmd[3]) && (!scsicmd[4])) -- cgit v1.2.3-70-g09d2 From 24f756866676b40446e361c1f87738707161da93 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Fri, 21 Sep 2007 07:54:49 -0400 Subject: [libata] SCSI: clean up R/W recovery mode page Clear ARRE, we don't do auto-reallocation on reads, just on writes. Also, hardcode the size of the array using RW_RECOVERY_MPAGE_LEN, following the style of the surrounding code. Signed-off-by: Jeff Garzik --- drivers/ata/libata-scsi.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 553488015e4..d482b589a18 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -71,11 +71,10 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel, #define ALL_SUB_MPAGES 0xff -static const u8 def_rw_recovery_mpage[] = { +static const u8 def_rw_recovery_mpage[RW_RECOVERY_MPAGE_LEN] = { RW_RECOVERY_MPAGE, RW_RECOVERY_MPAGE_LEN - 2, - (1 << 7) | /* AWRE, sat-r06 say it shall be 0 */ - (1 << 6), /* ARRE (auto read reallocation) */ + (1 << 7), /* AWRE */ 0, /* read retry count */ 0, 0, 0, 0, 0, /* write retry count */ -- cgit v1.2.3-70-g09d2 From c78968bb0f7714ceba1cdfa23714454fc98cefdf Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Fri, 21 Sep 2007 21:03:28 -0400 Subject: [libata] SCSI: simulator version, not device version, belongs in VPD Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 2 -- drivers/ata/libata-scsi.c | 5 +++-- drivers/ata/libata.h | 1 + 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 2116f279458..8d425064ce2 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -59,8 +59,6 @@ #include "libata.h" -#define DRV_VERSION "2.21" /* must be exactly four chars */ - /* debounce timing parameters in msecs { interval, duration, timeout } */ const unsigned long sata_deb_timing_normal[] = { 5, 100, 2000 }; diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index d482b589a18..468d791a303 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1831,8 +1831,9 @@ unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf, pbuf[2] = (0x238 >> 8); /* page size fixed at 238h */ pbuf[3] = (0x238 & 0xff); - memcpy(&pbuf[8], "ATA ", 8); - ata_id_string(args->id, &pbuf[16], ATA_ID_PROD, 16); + memcpy(&pbuf[8], "linux ", 8); + memcpy(&pbuf[16], "libata ", 16); + memcpy(&pbuf[32], DRV_VERSION, 4); ata_id_string(args->id, &pbuf[32], ATA_ID_FW_REV, 4); /* we don't store the ATA device signature, so we fake it */ diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 11f64a43b38..e45f6d5542d 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -29,6 +29,7 @@ #define __LIBATA_H__ #define DRV_NAME "libata" +#define DRV_VERSION "2.21" /* must be exactly four chars */ struct ata_scsi_args { struct ata_device *dev; -- cgit v1.2.3-70-g09d2 From 854c73a2f1c3bcc4aa88c25e208dc597e8efb795 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 23 Sep 2007 13:14:11 +0900 Subject: libata: misc updates for AN Update AN support in preparation of PMP support. * s/ata_id_has_AN/ata_id_has_atapi_AN/ * add AN enabled reporting during configuration * add err_mask to AN configuration failure reporting * update LOCKING comment for ata_scsi_media_change_notify() * check whether ATA dev is attached to SCSI dev ata_scsi_media_change_notify() * set ATA_FLAG_AN in ahci and sata_sil24 Signed-off-by: Tejun Heo Cc: Kriten Carlson Accardi Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 2 +- drivers/ata/libata-core.c | 24 ++++++++++++++---------- drivers/ata/libata-scsi.c | 7 ++++--- drivers/ata/sata_sil24.c | 13 +++++++++++-- include/linux/ata.h | 2 +- 5 files changed, 31 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index b721569faaf..0a6b694f0d3 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -177,7 +177,7 @@ enum { AHCI_FLAG_COMMON = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | - ATA_FLAG_ACPI_SATA, + ATA_FLAG_ACPI_SATA | ATA_FLAG_AN, AHCI_LFLAG_COMMON = ATA_LFLAG_SKIP_D2H_BSY, }; diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 8d425064ce2..1daea1caf3e 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2010,7 +2010,8 @@ int ata_dev_configure(struct ata_device *dev) /* ATAPI-specific feature tests */ else if (dev->class == ATA_DEV_ATAPI) { - char *cdb_intr_string = ""; + const char *cdb_intr_string = ""; + const char *atapi_an_string = ""; rc = atapi_cdb_len(id); if ((rc < 12) || (rc > ATAPI_CDB_LEN)) { @@ -2026,16 +2027,19 @@ int ata_dev_configure(struct ata_device *dev) * check to see if this ATAPI device supports * Asynchronous Notification */ - if ((ap->flags & ATA_FLAG_AN) && ata_id_has_AN(id)) { - int err; + if ((ap->flags & ATA_FLAG_AN) && ata_id_has_atapi_AN(id)) { + unsigned int err_mask; + /* issue SET feature command to turn this on */ - err = ata_dev_set_AN(dev, SETFEATURES_SATA_ENABLE); - if (err) + err_mask = ata_dev_set_AN(dev, SETFEATURES_SATA_ENABLE); + if (err_mask) ata_dev_printk(dev, KERN_ERR, - "unable to set AN, err %x\n", - err); - else + "failed to enable ATAPI AN " + "(err_mask=0x%x)\n", err_mask); + else { dev->flags |= ATA_DFLAG_AN; + atapi_an_string = ", ATAPI AN"; + } } if (ata_id_cdb_intr(dev->id)) { @@ -2046,10 +2050,10 @@ int ata_dev_configure(struct ata_device *dev) /* print device info to dmesg */ if (ata_msg_drv(ap) && print_info) ata_dev_printk(dev, KERN_INFO, - "ATAPI: %s, %s, max %s%s\n", + "ATAPI: %s, %s, max %s%s%s\n", modelbuf, fwrevbuf, ata_mode_string(xfer_mask), - cdb_intr_string); + cdb_intr_string, atapi_an_string); } /* determine max_sectors */ diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 468d791a303..dc274001ddd 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -3238,12 +3238,13 @@ static void ata_scsi_handle_link_detach(struct ata_link *link) * event. * * LOCKING: - * interrupt context, may not sleep. + * spin_lock_irqsave(host lock) */ -void ata_scsi_media_change_notify(struct ata_device *atadev) +void ata_scsi_media_change_notify(struct ata_device *dev) { #ifdef OTHER_AN_PATCHES_HAVE_BEEN_APPLIED - scsi_device_event_notify(atadev->sdev, SDEV_MEDIA_CHANGE); + if (dev->sdev) + scsi_device_event_notify(dev->sdev, SDEV_MEDIA_CHANGE); #endif } EXPORT_SYMBOL_GPL(ata_scsi_media_change_notify); diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index 3dcb223117b..d9c010ab228 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -168,7 +168,7 @@ enum { DEF_PORT_IRQ = PORT_IRQ_COMPLETE | PORT_IRQ_ERROR | PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG | - PORT_IRQ_UNK_FIS, + PORT_IRQ_UNK_FIS | PORT_IRQ_SDB_NOTIFY, /* bits[27:16] are unmasked (raw) */ PORT_IRQ_RAW_SHIFT = 16, @@ -237,7 +237,8 @@ enum { /* host flags */ SIL24_COMMON_FLAGS = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | - ATA_FLAG_NCQ | ATA_FLAG_ACPI_SATA, + ATA_FLAG_NCQ | ATA_FLAG_ACPI_SATA | + ATA_FLAG_AN, SIL24_COMMON_LFLAGS = ATA_LFLAG_SKIP_D2H_BSY, SIL24_FLAG_PCIX_IRQ_WOC = (1 << 24), /* IRQ loss errata on PCI-X */ @@ -818,6 +819,14 @@ static void sil24_error_intr(struct ata_port *ap) ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat); + if (irq_stat & PORT_IRQ_SDB_NOTIFY) { + struct ata_device *dev = ap->link.device; + + ata_ehi_push_desc(ehi, "SDB notify"); + if (dev->flags & ATA_DFLAG_AN) + ata_scsi_media_change_notify(dev); + } + if (irq_stat & (PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG)) { ata_ehi_hotplugged(ehi); ata_ehi_push_desc(ehi, "%s", diff --git a/include/linux/ata.h b/include/linux/ata.h index a749f006387..21f00a0646d 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -353,7 +353,7 @@ struct ata_taskfile { #define ata_id_queue_depth(id) (((id)[75] & 0x1f) + 1) #define ata_id_removeable(id) ((id)[0] & (1 << 7)) #define ata_id_has_dword_io(id) ((id)[48] & (1 << 0)) -#define ata_id_has_AN(id) \ +#define ata_id_has_atapi_AN(id) \ ( (((id)[76] != 0x0000) && ((id)[76] != 0xffff)) && \ ((id)[78] & (1 << 5)) ) #define ata_id_iordy_disable(id) ((id)[49] & (1 << 10)) -- cgit v1.2.3-70-g09d2 From 422c9daa8b5bea09f3393b11a106afd68850b39b Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 23 Sep 2007 13:14:12 +0900 Subject: libata-pmp-prep: add @new_class to ata_dev_revalidate() Consider newly found class code while revalidating. PMP resetting always results in valid class code and issuing PMP commands to ATA/ATAPI device isn't very attractive. Add @new_class to ata_dev_revalidate() and check class code for revalidation. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 15 +++++++++++++-- drivers/ata/libata-eh.c | 3 ++- drivers/ata/libata.h | 3 ++- 3 files changed, 17 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 1daea1caf3e..c046c5e1e5d 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2846,7 +2846,7 @@ static int ata_dev_set_mode(struct ata_device *dev) } ehc->i.flags |= ATA_EHI_POST_SETMODE; - rc = ata_dev_revalidate(dev, 0); + rc = ata_dev_revalidate(dev, ATA_DEV_UNKNOWN, 0); ehc->i.flags &= ~ATA_EHI_POST_SETMODE; if (rc) return rc; @@ -3750,6 +3750,7 @@ int ata_dev_reread_id(struct ata_device *dev, unsigned int readid_flags) /** * ata_dev_revalidate - Revalidate ATA device * @dev: device to revalidate + * @new_class: new class code * @readid_flags: read ID flags * * Re-read IDENTIFY page, make sure @dev is still attached to the @@ -3761,7 +3762,8 @@ int ata_dev_reread_id(struct ata_device *dev, unsigned int readid_flags) * RETURNS: * 0 on success, negative errno otherwise */ -int ata_dev_revalidate(struct ata_device *dev, unsigned int readid_flags) +int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class, + unsigned int readid_flags) { u64 n_sectors = dev->n_sectors; int rc; @@ -3769,6 +3771,15 @@ int ata_dev_revalidate(struct ata_device *dev, unsigned int readid_flags) if (!ata_dev_enabled(dev)) return -ENODEV; + /* fail early if !ATA && !ATAPI to avoid issuing [P]IDENTIFY to PMP */ + if (ata_class_enabled(new_class) && + new_class != ATA_DEV_ATA && new_class != ATA_DEV_ATAPI) { + ata_dev_printk(dev, KERN_INFO, "class mismatch %u != %u\n", + dev->class, new_class); + rc = -ENODEV; + goto fail; + } + /* re-read ID */ rc = ata_dev_reread_id(dev, readid_flags); if (rc) diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index daa2f74f73c..eb087bbc477 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -2104,7 +2104,8 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link, } ata_eh_about_to_do(link, dev, ATA_EH_REVALIDATE); - rc = ata_dev_revalidate(dev, readid_flags); + rc = ata_dev_revalidate(dev, ehc->classes[dev->devno], + readid_flags); if (rc) goto err; diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index e45f6d5542d..d4d369908c0 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -78,7 +78,8 @@ extern unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd); extern int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, unsigned int flags, u16 *id); extern int ata_dev_reread_id(struct ata_device *dev, unsigned int readid_flags); -extern int ata_dev_revalidate(struct ata_device *dev, unsigned int readid_flags); +extern int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class, + unsigned int readid_flags); extern int ata_dev_configure(struct ata_device *dev); extern int sata_down_spd_limit(struct ata_link *link); extern int sata_set_spd_needed(struct ata_link *link); -- cgit v1.2.3-70-g09d2 From fb7fd61454c8681cd2621051a710b78a00369203 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 23 Sep 2007 13:14:12 +0900 Subject: libata-pmp-prep: make a number of functions global to libata Make a number of functions from libata-core.c and libata-eh.c global to libata (drivers/ata/libata.h). These will be used by PMP. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 4 ++-- drivers/ata/libata-eh.c | 31 +++++++++++++++---------------- drivers/ata/libata.h | 17 +++++++++++++++++ 3 files changed, 34 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index c046c5e1e5d..9467c2f6019 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -6218,7 +6218,7 @@ void ata_dev_init(struct ata_device *dev) * LOCKING: * Kernel thread context (may sleep) */ -static void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp) +void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp) { int i; @@ -6253,7 +6253,7 @@ static void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp) * RETURNS: * 0 on success, -errno on failure. */ -static int sata_link_init_spd(struct ata_link *link) +int sata_link_init_spd(struct ata_link *link) { u32 scontrol, spd; int rc; diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index eb087bbc477..1d3b0dccfb0 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -74,7 +74,6 @@ static const unsigned long ata_eh_reset_timeouts[] = { }; static void __ata_port_freeze(struct ata_port *ap); -static void ata_eh_finish(struct ata_port *ap); #ifdef CONFIG_PM static void ata_eh_handle_port_suspend(struct ata_port *ap); static void ata_eh_handle_port_resume(struct ata_port *ap); @@ -1015,7 +1014,7 @@ void ata_eh_qc_retry(struct ata_queued_cmd *qc) * LOCKING: * None. */ -static void ata_eh_detach_dev(struct ata_device *dev) +void ata_eh_detach_dev(struct ata_device *dev) { struct ata_link *link = dev->link; struct ata_port *ap = link->ap; @@ -1052,8 +1051,8 @@ static void ata_eh_detach_dev(struct ata_device *dev) * LOCKING: * None. */ -static void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev, - unsigned int action) +void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev, + unsigned int action) { struct ata_port *ap = link->ap; struct ata_eh_info *ehi = &link->eh_info; @@ -1095,8 +1094,8 @@ static void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev, * LOCKING: * None. */ -static void ata_eh_done(struct ata_link *link, struct ata_device *dev, - unsigned int action) +void ata_eh_done(struct ata_link *link, struct ata_device *dev, + unsigned int action) { struct ata_eh_context *ehc = &link->eh_context; @@ -1756,7 +1755,7 @@ static void ata_eh_link_autopsy(struct ata_link *link) * LOCKING: * Kernel thread context (may sleep). */ -static void ata_eh_autopsy(struct ata_port *ap) +void ata_eh_autopsy(struct ata_port *ap) { struct ata_link *link; @@ -1867,7 +1866,7 @@ static void ata_eh_link_report(struct ata_link *link) * LOCKING: * None. */ -static void ata_eh_report(struct ata_port *ap) +void ata_eh_report(struct ata_port *ap) { struct ata_link *link; @@ -1918,9 +1917,9 @@ static int ata_eh_followup_srst_needed(int rc, int classify, return 0; } -static int ata_eh_reset(struct ata_link *link, int classify, - ata_prereset_fn_t prereset, ata_reset_fn_t softreset, - ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) +int ata_eh_reset(struct ata_link *link, int classify, + ata_prereset_fn_t prereset, ata_reset_fn_t softreset, + ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) { struct ata_eh_context *ehc = &link->eh_context; unsigned int *classes = ehc->classes; @@ -2296,10 +2295,10 @@ static int ata_eh_handle_dev_fail(struct ata_device *dev, int err) * RETURNS: * 0 on success, -errno on failure. */ -static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, - ata_reset_fn_t softreset, ata_reset_fn_t hardreset, - ata_postreset_fn_t postreset, - struct ata_link **r_failed_link) +int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, + ata_reset_fn_t softreset, ata_reset_fn_t hardreset, + ata_postreset_fn_t postreset, + struct ata_link **r_failed_link) { struct ata_link *link; struct ata_device *dev; @@ -2445,7 +2444,7 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, * LOCKING: * None. */ -static void ata_eh_finish(struct ata_port *ap) +void ata_eh_finish(struct ata_port *ap) { int tag; diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index d4d369908c0..0f3e355fdfd 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -95,6 +95,8 @@ extern void ata_dev_select(struct ata_port *ap, unsigned int device, extern void swap_buf_le16(u16 *buf, unsigned int buf_words); extern int ata_flush_cache(struct ata_device *dev); extern void ata_dev_init(struct ata_device *dev); +extern void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp); +extern int sata_link_init_spd(struct ata_link *link); extern int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg); extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg); extern struct ata_port *ata_port_alloc(struct ata_host *host); @@ -156,6 +158,21 @@ extern void ata_scsi_error(struct Scsi_Host *host); extern void ata_port_wait_eh(struct ata_port *ap); extern void ata_eh_fastdrain_timerfn(unsigned long arg); extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc); +extern void ata_eh_detach_dev(struct ata_device *dev); +extern void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev, + unsigned int action); +extern void ata_eh_done(struct ata_link *link, struct ata_device *dev, + unsigned int action); +extern void ata_eh_autopsy(struct ata_port *ap); +extern void ata_eh_report(struct ata_port *ap); +extern int ata_eh_reset(struct ata_link *link, int classify, + ata_prereset_fn_t prereset, ata_reset_fn_t softreset, + ata_reset_fn_t hardreset, ata_postreset_fn_t postreset); +extern int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, + ata_reset_fn_t softreset, ata_reset_fn_t hardreset, + ata_postreset_fn_t postreset, + struct ata_link **r_failed_disk); +extern void ata_eh_finish(struct ata_port *ap); /* libata-sff.c */ extern u8 ata_irq_on(struct ata_port *ap); -- cgit v1.2.3-70-g09d2 From 31cc23b34913bc173680bdc87af79e551bf8cc0d Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 23 Sep 2007 13:14:12 +0900 Subject: libata-pmp-prep: implement ops->qc_defer() Controllers which support PMP have various restrictions on which combinations of commands are allowed to what number of devices concurrently. This patch implements ops->qc_defer() which determines whether a qc can be issued at the moment or should be deferred. If the function returns ATA_DEFER_LINK, the qc will be deferred until a qc completes on the link. If ATA_DEFER_PORT, until a qc completes on any link. The defer conditions are advisory and in general ATA_DEFER_LINK can be considered as lower priority deferring than ATA_DEFER_PORT. ops->qc_defer() replaces fixed ata_scmd_need_defer(). For standard NCQ/non-NCQ exclusion, ata_std_qc_defer() is implemented. ahci and sata_sil24 are converted to use ata_std_qc_defer(). ops->qc_defer() is heavier than the original mechanism because full qc is prepped before determining to defer it, but various information is needed to determine defer conditinos and fully translating a qc is the only way to supply such information in generic manner. IMHO, this shouldn't cause any noticeable performance issues as * for most cases deferring occurs rarely (except for NCQ-aware cmd-switching PMP) * translation itself isn't that expensive * once deferred the command won't be repeated until another command completes which usually is a very long time cpu-wise. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 2 ++ drivers/ata/libata-core.c | 31 ++++++++++++++++++++++++ drivers/ata/libata-scsi.c | 62 ++++++++++++++++++++--------------------------- drivers/ata/sata_nv.c | 1 + drivers/ata/sata_sil24.c | 1 + include/linux/libata.h | 6 +++++ 6 files changed, 67 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 0a6b694f0d3..cf3404467ce 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -268,6 +268,7 @@ static const struct ata_port_operations ahci_ops = { .tf_read = ahci_tf_read, + .qc_defer = ata_std_qc_defer, .qc_prep = ahci_qc_prep, .qc_issue = ahci_qc_issue, @@ -298,6 +299,7 @@ static const struct ata_port_operations ahci_vt8251_ops = { .tf_read = ahci_tf_read, + .qc_defer = ata_std_qc_defer, .qc_prep = ahci_qc_prep, .qc_issue = ahci_qc_issue, diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 9467c2f6019..b666f51da7e 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4345,6 +4345,36 @@ int ata_check_atapi_dma(struct ata_queued_cmd *qc) return 0; } +/** + * ata_std_qc_defer - Check whether a qc needs to be deferred + * @qc: ATA command in question + * + * Non-NCQ commands cannot run with any other command, NCQ or + * not. As upper layer only knows the queue depth, we are + * responsible for maintaining exclusion. This function checks + * whether a new command @qc can be issued. + * + * LOCKING: + * spin_lock_irqsave(host lock) + * + * RETURNS: + * ATA_DEFER_* if deferring is needed, 0 otherwise. + */ +int ata_std_qc_defer(struct ata_queued_cmd *qc) +{ + struct ata_link *link = qc->dev->link; + + if (qc->tf.protocol == ATA_PROT_NCQ) { + if (!ata_tag_valid(link->active_tag)) + return 0; + } else { + if (!ata_tag_valid(link->active_tag) && !link->sactive) + return 0; + } + + return ATA_DEFER_LINK; +} + /** * ata_qc_prep - Prepare taskfile for submission * @qc: Metadata associated with taskfile to be prepared @@ -7111,6 +7141,7 @@ EXPORT_SYMBOL_GPL(ata_interrupt); EXPORT_SYMBOL_GPL(ata_do_set_mode); EXPORT_SYMBOL_GPL(ata_data_xfer); EXPORT_SYMBOL_GPL(ata_data_xfer_noirq); +EXPORT_SYMBOL_GPL(ata_std_qc_defer); EXPORT_SYMBOL_GPL(ata_qc_prep); EXPORT_SYMBOL_GPL(ata_dumb_qc_prep); EXPORT_SYMBOL_GPL(ata_noop_qc_prep); diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index dc274001ddd..8ca2caeed01 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -749,6 +749,13 @@ static void ata_scsi_sdev_config(struct scsi_device *sdev) { sdev->use_10_for_rw = 1; sdev->use_10_for_ms = 1; + + /* Schedule policy is determined by ->qc_defer() callback and + * it needs to see every deferred qc. Set dev_blocked to 1 to + * prevent SCSI midlayer from automatically deferring + * requests. + */ + sdev->max_device_blocked = 1; } static void ata_scsi_dev_config(struct scsi_device *sdev, @@ -1415,37 +1422,6 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) ata_qc_free(qc); } -/** - * ata_scmd_need_defer - Check whether we need to defer scmd - * @dev: ATA device to which the command is addressed - * @is_io: Is the command IO (and thus possibly NCQ)? - * - * NCQ and non-NCQ commands cannot run together. As upper layer - * only knows the queue depth, we are responsible for maintaining - * exclusion. This function checks whether a new command can be - * issued to @dev. - * - * LOCKING: - * spin_lock_irqsave(host lock) - * - * RETURNS: - * 1 if deferring is needed, 0 otherwise. - */ -static int ata_scmd_need_defer(struct ata_device *dev, int is_io) -{ - struct ata_link *link = dev->link; - int is_ncq = is_io && ata_ncq_enabled(dev); - - if (is_ncq) { - if (!ata_tag_valid(link->active_tag)) - return 0; - } else { - if (!ata_tag_valid(link->active_tag) && !link->sactive) - return 0; - } - return 1; -} - /** * ata_scsi_translate - Translate then issue SCSI command to ATA device * @dev: ATA device to which the command is addressed @@ -1477,14 +1453,12 @@ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), ata_xlat_func_t xlat_func) { + struct ata_port *ap = dev->link->ap; struct ata_queued_cmd *qc; - int is_io = xlat_func == ata_scsi_rw_xlat; + int rc; VPRINTK("ENTER\n"); - if (unlikely(ata_scmd_need_defer(dev, is_io))) - goto defer; - qc = ata_scsi_qc_new(dev, cmd, done); if (!qc) goto err_mem; @@ -1508,6 +1482,11 @@ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd, if (xlat_func(qc)) goto early_finish; + if (ap->ops->qc_defer) { + if ((rc = ap->ops->qc_defer(qc))) + goto defer; + } + /* select device, send command to hardware */ ata_qc_issue(qc); @@ -1529,8 +1508,12 @@ err_mem: return 0; defer: + ata_qc_free(qc); DPRINTK("EXIT - defer\n"); - return SCSI_MLQUEUE_DEVICE_BUSY; + if (rc == ATA_DEFER_LINK) + return SCSI_MLQUEUE_DEVICE_BUSY; + else + return SCSI_MLQUEUE_HOST_BUSY; } /** @@ -3034,6 +3017,13 @@ int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht) shost->max_channel = 1; shost->max_cmd_len = 16; + /* Schedule policy is determined by ->qc_defer() + * callback and it needs to see every deferred qc. + * Set host_blocked to 1 to prevent SCSI midlayer from + * automatically deferring requests. + */ + shost->max_host_blocked = 1; + rc = scsi_add_host(ap->scsi_host, ap->host->dev); if (rc) goto err_add; diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index b860f99fc28..40557fe2ffd 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -423,6 +423,7 @@ static const struct ata_port_operations nv_adma_ops = { .bmdma_start = ata_bmdma_start, .bmdma_stop = ata_bmdma_stop, .bmdma_status = ata_bmdma_status, + .qc_defer = ata_std_qc_defer, .qc_prep = nv_adma_qc_prep, .qc_issue = nv_adma_qc_issue, .freeze = nv_adma_freeze, diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index d9c010ab228..9acfce43bde 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -393,6 +393,7 @@ static const struct ata_port_operations sil24_ops = { .tf_read = sil24_tf_read, + .qc_defer = ata_std_qc_defer, .qc_prep = sil24_qc_prep, .qc_issue = sil24_qc_issue, diff --git a/include/linux/libata.h b/include/linux/libata.h index c3820f105ff..b0d4ca0d27b 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -272,6 +272,10 @@ enum { /* ering size */ ATA_ERING_SIZE = 32, + /* return values for ->qc_defer */ + ATA_DEFER_LINK = 1, + ATA_DEFER_PORT = 2, + /* desc_len for ata_eh_info and context */ ATA_EH_DESC_LEN = 80, @@ -639,6 +643,7 @@ struct ata_port_operations { void (*data_xfer) (struct ata_device *, unsigned char *, unsigned int, int); + int (*qc_defer) (struct ata_queued_cmd *qc); void (*qc_prep) (struct ata_queued_cmd *qc); unsigned int (*qc_issue) (struct ata_queued_cmd *qc); @@ -824,6 +829,7 @@ extern void ata_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data); extern void ata_data_xfer_noirq(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data); +extern int ata_std_qc_defer(struct ata_queued_cmd *qc); extern void ata_dumb_qc_prep(struct ata_queued_cmd *qc); extern void ata_qc_prep(struct ata_queued_cmd *qc); extern void ata_noop_qc_prep(struct ata_queued_cmd *qc); -- cgit v1.2.3-70-g09d2 From da917d69d0ea63f5390716cba6e77f490ce96df9 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 23 Sep 2007 13:14:12 +0900 Subject: libata-pmp-prep: implement qc_defer helpers Implement ap->nr_active_links (the number of links with active qcs), ap->excl_link (pointer to link which can be used by ->qc_defer and is cleared when a qc with ATA_QCFLAG_CLEAR_EXCL completes), and ata_link_active(). These can be used by ->qc_defer() to implement proper command exclusion. This set of helpers seem enough for both sil24 (ATAPI exclusion needed) and cmd-switching PMP. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 22 ++++++++++++++++++++-- drivers/ata/libata-eh.c | 5 +++++ include/linux/libata.h | 8 ++++++++ 3 files changed, 33 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index b666f51da7e..376dbd80cc9 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -1390,6 +1390,7 @@ unsigned ata_exec_internal_sg(struct ata_device *dev, struct ata_queued_cmd *qc; unsigned int tag, preempted_tag; u32 preempted_sactive, preempted_qc_active; + int preempted_nr_active_links; DECLARE_COMPLETION_ONSTACK(wait); unsigned long flags; unsigned int err_mask; @@ -1428,9 +1429,11 @@ unsigned ata_exec_internal_sg(struct ata_device *dev, preempted_tag = link->active_tag; preempted_sactive = link->sactive; preempted_qc_active = ap->qc_active; + preempted_nr_active_links = ap->nr_active_links; link->active_tag = ATA_TAG_POISON; link->sactive = 0; ap->qc_active = 0; + ap->nr_active_links = 0; /* prepare & issue qc */ qc->tf = *tf; @@ -1509,6 +1512,7 @@ unsigned ata_exec_internal_sg(struct ata_device *dev, link->active_tag = preempted_tag; link->sactive = preempted_sactive; ap->qc_active = preempted_qc_active; + ap->nr_active_links = preempted_nr_active_links; /* XXX - Some LLDDs (sata_mv) disable port on command failure. * Until those drivers are fixed, we detect the condition @@ -5408,10 +5412,19 @@ void __ata_qc_complete(struct ata_queued_cmd *qc) ata_sg_clean(qc); /* command should be marked inactive atomically with qc completion */ - if (qc->tf.protocol == ATA_PROT_NCQ) + if (qc->tf.protocol == ATA_PROT_NCQ) { link->sactive &= ~(1 << qc->tag); - else + if (!link->sactive) + ap->nr_active_links--; + } else { link->active_tag = ATA_TAG_POISON; + ap->nr_active_links--; + } + + /* clear exclusive status */ + if (unlikely(qc->flags & ATA_QCFLAG_CLEAR_EXCL && + ap->excl_link == link)) + ap->excl_link = NULL; /* atapi: mark qc as inactive to prevent the interrupt handler * from completing the command twice later, before the error handler @@ -5590,9 +5603,14 @@ void ata_qc_issue(struct ata_queued_cmd *qc) if (qc->tf.protocol == ATA_PROT_NCQ) { WARN_ON(link->sactive & (1 << qc->tag)); + + if (!link->sactive) + ap->nr_active_links++; link->sactive |= 1 << qc->tag; } else { WARN_ON(link->sactive); + + ap->nr_active_links++; link->active_tag = qc->tag; } diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 1d3b0dccfb0..5244723952c 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -451,6 +451,7 @@ void ata_scsi_error(struct Scsi_Host *host) ap->pflags |= ATA_PFLAG_EH_IN_PROGRESS; ap->pflags &= ~ATA_PFLAG_EH_PENDING; + ap->excl_link = NULL; /* don't maintain exclusion over EH */ spin_unlock_irqrestore(ap->lock, flags); @@ -2474,6 +2475,10 @@ void ata_eh_finish(struct ata_port *ap) } } } + + /* make sure nr_active_links is zero after EH */ + WARN_ON(ap->nr_active_links); + ap->nr_active_links = 0; } /** diff --git a/include/linux/libata.h b/include/linux/libata.h index b0d4ca0d27b..f9f81fd9329 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -216,6 +216,7 @@ enum { ATA_QCFLAG_DMAMAP = ATA_QCFLAG_SG | ATA_QCFLAG_SINGLE, ATA_QCFLAG_IO = (1 << 3), /* standard IO command */ ATA_QCFLAG_RESULT_TF = (1 << 4), /* result TF requested */ + ATA_QCFLAG_CLEAR_EXCL = (1 << 5), /* clear excl_link on completion */ ATA_QCFLAG_FAILED = (1 << 16), /* cmd failed and is owned by EH */ ATA_QCFLAG_SENSE_VALID = (1 << 17), /* sense data valid */ @@ -579,11 +580,13 @@ struct ata_port { struct ata_queued_cmd qcmd[ATA_MAX_QUEUE]; unsigned long qc_allocated; unsigned int qc_active; + int nr_active_links; /* #links with active qcs */ struct ata_link link; /* host default link */ int nr_pmp_links; /* nr of available PMP links */ struct ata_link *pmp_link; /* array of PMP links */ + struct ata_link *excl_link; /* for PMP qc exclusion */ struct ata_port_stats stats; struct ata_host *host; @@ -1104,6 +1107,11 @@ static inline int ata_link_max_devices(const struct ata_link *link) return 1; } +static inline int ata_link_active(struct ata_link *link) +{ + return ata_tag_valid(link->active_tag) || link->sactive; +} + static inline struct ata_link *ata_port_first_link(struct ata_port *ap) { if (ap->nr_pmp_links) -- cgit v1.2.3-70-g09d2 From ae791c05694d7391ee9261a0450a50f7e95aedfd Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 23 Sep 2007 13:14:12 +0900 Subject: libata-pmp-prep: implement ATA_LFLAG_NO_SRST, ASSUME_ATA and ASSUME_SEMB Some links on some PMPs locks up on SRST and/or report incorrect device signature. Implement ATA_LFLAG_NO_SRST, ASSUME_ATA and ASSUME_SEMB to handle these quirky links. NO_SRST makes EH avoid SRST. ASSUME_ATA and SEMB forces class code to ATA and SEMB_UNSUP respectively. Note that SEMB isn't currently supported yet so the _UNSUP variant is used. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-eh.c | 42 ++++++++++++++++++++++++++++++++---------- include/linux/libata.h | 4 ++++ 2 files changed, 36 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 5244723952c..7be04bd30bf 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1906,14 +1906,18 @@ static int ata_do_reset(struct ata_link *link, ata_reset_fn_t reset, return 0; } -static int ata_eh_followup_srst_needed(int rc, int classify, +static int ata_eh_followup_srst_needed(struct ata_link *link, + int rc, int classify, const unsigned int *classes) { + if (link->flags & ATA_LFLAG_NO_SRST) + return 0; if (rc == -EAGAIN) return 1; if (rc != 0) return 0; - if (classify && classes[0] == ATA_DEV_UNKNOWN) + if (classify && !(link->flags & ATA_LFLAG_ASSUME_CLASS) && + classes[0] == ATA_DEV_UNKNOWN) return 1; return 0; } @@ -1940,7 +1944,8 @@ int ata_eh_reset(struct ata_link *link, int classify, */ action = ehc->i.action; ehc->i.action &= ~ATA_EH_RESET_MASK; - if (softreset && (!hardreset || (!sata_set_spd_needed(link) && + if (softreset && (!hardreset || (!(link->flags & ATA_LFLAG_NO_SRST) && + !sata_set_spd_needed(link) && !(action & ATA_EH_HARDRESET)))) ehc->i.action |= ATA_EH_SOFTRESET; else @@ -2003,7 +2008,7 @@ int ata_eh_reset(struct ata_link *link, int classify, rc = ata_do_reset(link, reset, classes, deadline); if (reset == hardreset && - ata_eh_followup_srst_needed(rc, classify, classes)) { + ata_eh_followup_srst_needed(link, rc, classify, classes)) { /* okay, let's do follow-up softreset */ reset = softreset; @@ -2018,8 +2023,8 @@ int ata_eh_reset(struct ata_link *link, int classify, ata_eh_about_to_do(link, NULL, ATA_EH_RESET_MASK); rc = ata_do_reset(link, reset, classes, deadline); - if (rc == 0 && classify && - classes[0] == ATA_DEV_UNKNOWN) { + if (rc == 0 && classify && classes[0] == ATA_DEV_UNKNOWN && + !(link->flags & ATA_LFLAG_ASSUME_CLASS)) { ata_link_printk(link, KERN_ERR, "classification failed\n"); rc = -EINVAL; @@ -2027,6 +2032,10 @@ int ata_eh_reset(struct ata_link *link, int classify, } } + /* if we skipped follow-up srst, clear rc */ + if (rc == -EAGAIN) + rc = 0; + if (rc && try < ARRAY_SIZE(ata_eh_reset_timeouts)) { unsigned long now = jiffies; @@ -2051,12 +2060,25 @@ int ata_eh_reset(struct ata_link *link, int classify, if (rc == 0) { u32 sstatus; - /* After the reset, the device state is PIO 0 and the - * controller state is undefined. Record the mode. - */ - ata_link_for_each_dev(dev, link) + ata_link_for_each_dev(dev, link) { + /* After the reset, the device state is PIO 0 + * and the controller state is undefined. + * Record the mode. + */ dev->pio_mode = XFER_PIO_0; + if (ata_link_offline(link)) + continue; + + /* apply class override and convert UNKNOWN to NONE */ + if (link->flags & ATA_LFLAG_ASSUME_ATA) + classes[dev->devno] = ATA_DEV_ATA; + else if (link->flags & ATA_LFLAG_ASSUME_SEMB) + classes[dev->devno] = ATA_DEV_SEMB_UNSUP; /* not yet */ + else if (classes[dev->devno] == ATA_DEV_UNKNOWN) + classes[dev->devno] = ATA_DEV_NONE; + } + /* record current link speed */ if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0) link->sata_spd = (sstatus >> 4) & 0xf; diff --git a/include/linux/libata.h b/include/linux/libata.h index f9f81fd9329..6266fffb0eb 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -165,6 +165,10 @@ enum { ATA_LFLAG_HRST_TO_RESUME = (1 << 0), /* hardreset to resume link */ ATA_LFLAG_SKIP_D2H_BSY = (1 << 1), /* can't wait for the first D2H * Register FIS clearing BSY */ + ATA_LFLAG_NO_SRST = (1 << 2), /* avoid softreset */ + ATA_LFLAG_ASSUME_ATA = (1 << 3), /* assume ATA class */ + ATA_LFLAG_ASSUME_SEMB = (1 << 4), /* assume SEMB class */ + ATA_LFLAG_ASSUME_CLASS = ATA_LFLAG_ASSUME_ATA | ATA_LFLAG_ASSUME_SEMB, /* struct ata_port flags */ ATA_FLAG_SLAVE_POSS = (1 << 0), /* host supports slave dev */ -- cgit v1.2.3-70-g09d2 From fd995f7039f1955ccc6b43e1e2d168060b31e4b2 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 23 Sep 2007 13:14:12 +0900 Subject: libata-pmp-prep: implement ATA_LFLAG_NO_RETRY Some PMP links are connected to internal pseudo devices which may come and go depending on situation. There's no reason to try hard to recover them. ATA_LFLAG_NO_RETRY tells EH to not retry if the device attached to the link fails. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-eh.c | 5 ++++- include/linux/libata.h | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 7be04bd30bf..8f8ed4dfb17 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -2335,7 +2335,10 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, struct ata_eh_context *ehc = &link->eh_context; ata_link_for_each_dev(dev, link) { - ehc->tries[dev->devno] = ATA_EH_DEV_TRIES; + if (link->flags & ATA_LFLAG_NO_RETRY) + ehc->tries[dev->devno] = 1; + else + ehc->tries[dev->devno] = ATA_EH_DEV_TRIES; /* collect port action mask recorded in dev actions */ ehc->i.action |= ehc->i.dev_action[dev->devno] & diff --git a/include/linux/libata.h b/include/linux/libata.h index 6266fffb0eb..adeee7397cd 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -169,6 +169,7 @@ enum { ATA_LFLAG_ASSUME_ATA = (1 << 3), /* assume ATA class */ ATA_LFLAG_ASSUME_SEMB = (1 << 4), /* assume SEMB class */ ATA_LFLAG_ASSUME_CLASS = ATA_LFLAG_ASSUME_ATA | ATA_LFLAG_ASSUME_SEMB, + ATA_LFLAG_NO_RETRY = (1 << 5), /* don't retry this link */ /* struct ata_port flags */ ATA_FLAG_SLAVE_POSS = (1 << 0), /* host supports slave dev */ -- cgit v1.2.3-70-g09d2 From f9df58cb27dfd605eced643bb3aa599fe4feeee8 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 23 Sep 2007 13:14:13 +0900 Subject: libata-pmp-prep: implement ATA_LFLAG_DISABLED Implement ATA_LFLAG_DISABLED. The flag indicates the link is disabled due to EH recovery failure. While a link is disabled, no EH action is taken on the link and suspend/resume become noop too. This will be used by PMP links to manage failed links. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-eh.c | 30 +++++++++++++++++++++++++++++- include/linux/libata.h | 3 +++ 2 files changed, 32 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 8f8ed4dfb17..fbbf7916390 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1308,6 +1308,7 @@ static void ata_eh_analyze_serror(struct ata_link *link) struct ata_eh_context *ehc = &link->eh_context; u32 serror = ehc->i.serror; unsigned int err_mask = 0, action = 0; + u32 hotplug_mask; if (serror & SERR_PERSISTENT) { err_mask |= AC_ERR_ATA_BUS; @@ -1326,7 +1327,20 @@ static void ata_eh_analyze_serror(struct ata_link *link) err_mask |= AC_ERR_SYSTEM; action |= ATA_EH_HARDRESET; } - if (serror & (SERR_PHYRDY_CHG | SERR_DEV_XCHG)) + + /* Determine whether a hotplug event has occurred. Both + * SError.N/X are considered hotplug events for enabled or + * host links. For disabled PMP links, only N bit is + * considered as X bit is left at 1 for link plugging. + */ + hotplug_mask = 0; + + if (!(link->flags & ATA_LFLAG_DISABLED) || ata_is_host_link(link)) + hotplug_mask = SERR_PHYRDY_CHG | SERR_DEV_XCHG; + else + hotplug_mask = SERR_PHYRDY_CHG; + + if (serror & hotplug_mask) ata_ehi_hotplugged(&ehc->i); ehc->i.err_mask |= err_mask; @@ -2227,6 +2241,10 @@ static int ata_eh_skip_recovery(struct ata_link *link) struct ata_eh_context *ehc = &link->eh_context; struct ata_device *dev; + /* skip disabled links */ + if (link->flags & ATA_LFLAG_DISABLED) + return 1; + /* thaw frozen port, resume link and recover failed devices */ if ((link->ap->pflags & ATA_PFLAG_FROZEN) || (ehc->i.flags & ATA_EHI_RESUME_LINK) || ata_link_nr_enabled(link)) @@ -2327,6 +2345,7 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, struct ata_device *dev; int nr_failed_devs, nr_disabled_devs; int reset, rc; + unsigned long flags; DPRINTK("ENTER\n"); @@ -2334,6 +2353,15 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, ata_port_for_each_link(link, ap) { struct ata_eh_context *ehc = &link->eh_context; + /* re-enable link? */ + if (ehc->i.action & ATA_EH_ENABLE_LINK) { + ata_eh_about_to_do(link, NULL, ATA_EH_ENABLE_LINK); + spin_lock_irqsave(ap->lock, flags); + link->flags &= ~ATA_LFLAG_DISABLED; + spin_unlock_irqrestore(ap->lock, flags); + ata_eh_done(link, NULL, ATA_EH_ENABLE_LINK); + } + ata_link_for_each_dev(dev, link) { if (link->flags & ATA_LFLAG_NO_RETRY) ehc->tries[dev->devno] = 1; diff --git a/include/linux/libata.h b/include/linux/libata.h index adeee7397cd..2bd1d26c9c8 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -170,6 +170,7 @@ enum { ATA_LFLAG_ASSUME_SEMB = (1 << 4), /* assume SEMB class */ ATA_LFLAG_ASSUME_CLASS = ATA_LFLAG_ASSUME_ATA | ATA_LFLAG_ASSUME_SEMB, ATA_LFLAG_NO_RETRY = (1 << 5), /* don't retry this link */ + ATA_LFLAG_DISABLED = (1 << 6), /* link is disabled */ /* struct ata_port flags */ ATA_FLAG_SLAVE_POSS = (1 << 0), /* host supports slave dev */ @@ -289,6 +290,7 @@ enum { ATA_EH_REVALIDATE = (1 << 0), ATA_EH_SOFTRESET = (1 << 1), ATA_EH_HARDRESET = (1 << 2), + ATA_EH_ENABLE_LINK = (1 << 3), ATA_EH_RESET_MASK = ATA_EH_SOFTRESET | ATA_EH_HARDRESET, ATA_EH_PERDEV_MASK = ATA_EH_REVALIDATE, @@ -999,6 +1001,7 @@ static inline void ata_ehi_hotplugged(struct ata_eh_info *ehi) { ata_ehi_schedule_probe(ehi); ehi->flags |= ATA_EHI_HOTPLUGGED; + ehi->action |= ATA_EH_ENABLE_LINK; ehi->err_mask |= AC_ERR_ATA_BUS; } -- cgit v1.2.3-70-g09d2 From 668108d73bbb1ae85f01db38d6be822fd28ece1f Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 23 Sep 2007 13:14:13 +0900 Subject: libata-pmp-prep: implement EH fast-fail path If PMP itself becomes inaccessible while trying to link a downstream link, spending time to recover the downstream link doesn't make any sense. Make EH skip retry and fail fast if -ERESTART is received. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-eh.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index fbbf7916390..3c31e10caf2 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -2050,7 +2050,7 @@ int ata_eh_reset(struct ata_link *link, int classify, if (rc == -EAGAIN) rc = 0; - if (rc && try < ARRAY_SIZE(ata_eh_reset_timeouts)) { + if (rc && rc != -ERESTART && try < ARRAY_SIZE(ata_eh_reset_timeouts)) { unsigned long now = jiffies; if (time_before(now, deadline)) { -- cgit v1.2.3-70-g09d2 From e31e8531d668c9c4dc7883054788f89805188003 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 23 Sep 2007 13:14:13 +0900 Subject: libata-pmp-prep: implement ATA_HORKAGE_SKIP_PM Some pseudo devices fail PM commands unnecessarily aborting system suspend. Implement ATA_HORKAGE_SKIP_PM which makes libata skip PM commands for these devices. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-scsi.c | 7 +++++++ include/linux/libata.h | 1 + 2 files changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 8ca2caeed01..451f79c6fba 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -944,6 +944,13 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc) goto invalid_fld; /* LOEJ bit set not supported */ if (((cdb[4] >> 4) & 0xf) != 0) goto invalid_fld; /* power conditions not supported */ + + if (qc->dev->horkage & ATA_HORKAGE_SKIP_PM) { + /* the device lacks PM support, finish without doing anything */ + scmd->result = SAM_STAT_GOOD; + return 1; + } + if (cdb[4] & 0x1) { tf->nsect = 1; /* 1 sector, lba=0 */ diff --git a/include/linux/libata.h b/include/linux/libata.h index 2bd1d26c9c8..56b21877111 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -329,6 +329,7 @@ enum { ATA_HORKAGE_NONCQ = (1 << 2), /* Don't use NCQ */ ATA_HORKAGE_MAX_SEC_128 = (1 << 3), /* Limit max sects to 128 */ ATA_HORKAGE_BROKEN_HPA = (1 << 4), /* Broken HPA */ + ATA_HORKAGE_SKIP_PM = (1 << 5), /* Skip PM operations */ }; enum hsm_task_states { -- cgit v1.2.3-70-g09d2 From 7d77b247088fb360aa74bfdd9e19bce1e1987668 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 23 Sep 2007 13:14:13 +0900 Subject: libata-pmp-prep: implement sata_async_notification() AN serves multiple purposes. For ATAPI, it's used for media change notification. For PMP, for downstream PHY status change notification. Implement sata_async_notification() which demultiplexes AN. To avoid unnecessary port events, ATAPI AN is not enabled if PMP is attached but SNTF is not available. Signed-off-by: Tejun Heo Cc: Kriten Carlson Accardi Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 24 +++++----------- drivers/ata/libata-core.c | 13 ++++++--- drivers/ata/libata-eh.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/ata/libata-scsi.c | 1 - drivers/ata/libata.h | 1 + drivers/ata/sata_sil24.c | 5 +--- include/linux/libata.h | 4 +-- 7 files changed, 93 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index cf3404467ce..9f3c591c721 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1356,27 +1356,17 @@ static void ahci_port_intr(struct ata_port *ap) } if (status & PORT_IRQ_SDB_FIS) { - /* - * if this is an ATAPI device with AN turned on, - * then we should interrogate the device to - * determine the cause of the interrupt - * - * for AN - this we should check the SDB FIS - * and find the I and N bits set + /* If the 'N' bit in word 0 of the FIS is set, we just + * received asynchronous notification. Tell libata + * about it. Note that as the SDB FIS itself is + * accessible, SNotification can be emulated by the + * driver but don't bother for the time being. */ const __le32 *f = pp->rx_fis + RX_FIS_SDB; u32 f0 = le32_to_cpu(f[0]); - /* check the 'N' bit in word 0 of the FIS */ - if (f0 & (1 << 15)) { - int port_addr = ((f0 & 0x00000f00) >> 8); - struct ata_device *adev; - if (port_addr < ATA_MAX_DEVICES) { - adev = &ap->link.device[port_addr]; - if (adev->flags & ATA_DFLAG_AN) - ata_scsi_media_change_notify(adev); - } - } + if (f0 & (1 << 15)) + sata_async_notification(ap); } if (ap->link.sactive) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 376dbd80cc9..8b08e7bdd24 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2016,6 +2016,7 @@ int ata_dev_configure(struct ata_device *dev) else if (dev->class == ATA_DEV_ATAPI) { const char *cdb_intr_string = ""; const char *atapi_an_string = ""; + u32 sntf; rc = atapi_cdb_len(id); if ((rc < 12) || (rc > ATAPI_CDB_LEN)) { @@ -2027,11 +2028,14 @@ int ata_dev_configure(struct ata_device *dev) } dev->cdb_len = (unsigned int) rc; - /* - * check to see if this ATAPI device supports - * Asynchronous Notification + /* Enable ATAPI AN if both the host and device have + * the support. If PMP is attached, SNTF is required + * to enable ATAPI AN to discern between PHY status + * changed notifications and ATAPI ANs. */ - if ((ap->flags & ATA_FLAG_AN) && ata_id_has_atapi_AN(id)) { + if ((ap->flags & ATA_FLAG_AN) && ata_id_has_atapi_AN(id) && + (!ap->nr_pmp_links || + sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf) == 0)) { unsigned int err_mask; /* issue SET feature command to turn this on */ @@ -7248,6 +7252,7 @@ EXPORT_SYMBOL_GPL(ata_port_schedule_eh); EXPORT_SYMBOL_GPL(ata_link_abort); EXPORT_SYMBOL_GPL(ata_port_abort); EXPORT_SYMBOL_GPL(ata_port_freeze); +EXPORT_SYMBOL_GPL(sata_async_notification); EXPORT_SYMBOL_GPL(ata_eh_freeze_port); EXPORT_SYMBOL_GPL(ata_eh_thaw_port); EXPORT_SYMBOL_GPL(ata_eh_qc_complete); diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 3c31e10caf2..60186f8ac3a 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -904,6 +904,79 @@ int ata_port_freeze(struct ata_port *ap) return nr_aborted; } +/** + * sata_async_notification - SATA async notification handler + * @ap: ATA port where async notification is received + * + * Handler to be called when async notification via SDB FIS is + * received. This function schedules EH if necessary. + * + * LOCKING: + * spin_lock_irqsave(host lock) + * + * RETURNS: + * 1 if EH is scheduled, 0 otherwise. + */ +int sata_async_notification(struct ata_port *ap) +{ + u32 sntf; + int rc; + + if (!(ap->flags & ATA_FLAG_AN)) + return 0; + + rc = sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf); + if (rc == 0) + sata_scr_write(&ap->link, SCR_NOTIFICATION, sntf); + + if (!ap->nr_pmp_links || rc) { + /* PMP is not attached or SNTF is not available */ + if (!ap->nr_pmp_links) { + /* PMP is not attached. Check whether ATAPI + * AN is configured. If so, notify media + * change. + */ + struct ata_device *dev = ap->link.device; + + if ((dev->class == ATA_DEV_ATAPI) && + (dev->flags & ATA_DFLAG_AN)) + ata_scsi_media_change_notify(dev); + return 0; + } else { + /* PMP is attached but SNTF is not available. + * ATAPI async media change notification is + * not used. The PMP must be reporting PHY + * status change, schedule EH. + */ + ata_port_schedule_eh(ap); + return 1; + } + } else { + /* PMP is attached and SNTF is available */ + struct ata_link *link; + + /* check and notify ATAPI AN */ + ata_port_for_each_link(link, ap) { + if (!(sntf & (1 << link->pmp))) + continue; + + if ((link->device->class == ATA_DEV_ATAPI) && + (link->device->flags & ATA_DFLAG_AN)) + ata_scsi_media_change_notify(link->device); + } + + /* If PMP is reporting that PHY status of some + * downstream ports has changed, schedule EH. + */ + if (sntf & (1 << SATA_PMP_CTRL_PORT)) { + ata_port_schedule_eh(ap); + return 1; + } + + return 0; + } +} + /** * ata_eh_freeze_port - EH helper to freeze port * @ap: ATA port to freeze diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 451f79c6fba..df2e05738f3 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -3244,7 +3244,6 @@ void ata_scsi_media_change_notify(struct ata_device *dev) scsi_device_event_notify(dev->sdev, SDEV_MEDIA_CHANGE); #endif } -EXPORT_SYMBOL_GPL(ata_scsi_media_change_notify); /** * ata_scsi_hotplug - SCSI part of hotplug diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 0f3e355fdfd..ebe22982e80 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -119,6 +119,7 @@ extern int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht); extern void ata_scsi_scan_host(struct ata_port *ap, int sync); extern int ata_scsi_offline_dev(struct ata_device *dev); +extern void ata_scsi_media_change_notify(struct ata_device *dev); extern void ata_scsi_hotplug(struct work_struct *work); extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf, unsigned int buflen); diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index 9acfce43bde..b4f81eb8bbb 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -821,11 +821,8 @@ static void sil24_error_intr(struct ata_port *ap) ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat); if (irq_stat & PORT_IRQ_SDB_NOTIFY) { - struct ata_device *dev = ap->link.device; - ata_ehi_push_desc(ehi, "SDB notify"); - if (dev->flags & ATA_DFLAG_AN) - ata_scsi_media_change_notify(dev); + sata_async_notification(ap); } if (irq_stat & (PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG)) { diff --git a/include/linux/libata.h b/include/linux/libata.h index 56b21877111..cd9c2a28136 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -139,7 +139,7 @@ enum { ATA_DFLAG_FLUSH_EXT = (1 << 4), /* do FLUSH_EXT instead of FLUSH */ ATA_DFLAG_ACPI_PENDING = (1 << 5), /* ACPI resume action pending */ ATA_DFLAG_ACPI_FAILED = (1 << 6), /* ACPI on devcfg has failed */ - ATA_DFLAG_AN = (1 << 7), /* device supports AN */ + ATA_DFLAG_AN = (1 << 7), /* AN configured */ ATA_DFLAG_CFG_MASK = (1 << 12) - 1, ATA_DFLAG_PIO = (1 << 12), /* device limited to PIO mode */ @@ -787,7 +787,6 @@ extern void ata_host_init(struct ata_host *, struct device *, extern int ata_scsi_detect(struct scsi_host_template *sht); extern int ata_scsi_ioctl(struct scsi_device *dev, int cmd, void __user *arg); extern int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)); -extern void ata_scsi_media_change_notify(struct ata_device *atadev); extern void ata_sas_port_destroy(struct ata_port *); extern struct ata_port *ata_sas_port_alloc(struct ata_host *, struct ata_port_info *, struct Scsi_Host *); @@ -953,6 +952,7 @@ extern void ata_port_schedule_eh(struct ata_port *ap); extern int ata_link_abort(struct ata_link *link); extern int ata_port_abort(struct ata_port *ap); extern int ata_port_freeze(struct ata_port *ap); +extern int sata_async_notification(struct ata_port *ap); extern void ata_eh_freeze_port(struct ata_port *ap); extern void ata_eh_thaw_port(struct ata_port *ap); -- cgit v1.2.3-70-g09d2 From 1e582ba4ef6264dd8cb73250ebff767d0624d684 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 21 Sep 2007 20:07:14 +0900 Subject: libata: fix ata_set_max_sectors() In ata_set_max_sectors(), the highest nibble in LBA28 mode was missing. This made drives sized between 8G and 128G with HPA turned on to be resized to under 8G. Fix it. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 8b08e7bdd24..fd4563daacd 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -950,9 +950,12 @@ static int ata_set_max_sectors(struct ata_device *dev, u64 new_sectors) tf.hob_lbal = (new_sectors >> 24) & 0xff; tf.hob_lbam = (new_sectors >> 32) & 0xff; tf.hob_lbah = (new_sectors >> 40) & 0xff; - } else + } else { tf.command = ATA_CMD_SET_MAX; + tf.device |= (new_sectors >> 24) & 0xf; + } + tf.protocol |= ATA_PROT_NODATA; tf.device |= ATA_LBA; -- cgit v1.2.3-70-g09d2 From b6d6c74628767e1bd33c735b3b2ee7b132b4198e Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 21 Sep 2007 17:55:44 +0900 Subject: sata_via: kill SATA_PATA_SHARING register handling The SATA_PATA_SHARING register doesn't have anything to do with the SATA part of the controller. It indicates whether an extern SATA PHY is attached to the PATA part of the controller and if so how it is wired. As the PATA part is driven by pata_via, sata_via has no reason to care about that. Also, pata_via should work fine under all configurations. This patch removes unnecessary attach failures. It seems recent via chipsets are defaulting to different values or are actually connected to SATA PHY triggering this more often. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/sata_via.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index f0757023ce9..1dc9b4f2b2d 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c @@ -57,7 +57,6 @@ enum { SATA_CHAN_ENAB = 0x40, /* SATA channel enable */ SATA_INT_GATE = 0x41, /* SATA interrupt gating */ SATA_NATIVE_MODE = 0x42, /* Native mode enable */ - SATA_PATA_SHARING = 0x49, /* PATA/SATA sharing func ctrl */ PATA_UDMA_TIMING = 0xB3, /* PATA timing for DMA/ cable detect */ PATA_PIO_TIMING = 0xAB, /* PATA timing register */ @@ -68,7 +67,6 @@ enum { NATIVE_MODE_ALL = (1 << 7) | (1 << 6) | (1 << 5) | (1 << 4), SATA_EXT_PHY = (1 << 6), /* 0==use PATA, 1==ext phy */ - SATA_2DEV = (1 << 5), /* SATA is master/slave */ }; static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); @@ -508,7 +506,6 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) struct ata_host *host; int board_id = (int) ent->driver_data; const int *bar_sizes; - u8 tmp8; if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); @@ -517,19 +514,10 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) return rc; - if (board_id == vt6420) { - pci_read_config_byte(pdev, SATA_PATA_SHARING, &tmp8); - if (tmp8 & SATA_2DEV) { - dev_printk(KERN_ERR, &pdev->dev, - "SATA master/slave not supported (0x%x)\n", - (int) tmp8); - return -EIO; - } - + if (board_id == vt6420) bar_sizes = &svia_bar_sizes[0]; - } else { + else bar_sizes = &vt6421_bar_sizes[0]; - } for (i = 0; i < ARRAY_SIZE(svia_bar_sizes); i++) if ((pci_resource_start(pdev, i) == 0) || -- cgit v1.2.3-70-g09d2 From b90fe23bd51c6b1c298159591c833bdd24f55002 Mon Sep 17 00:00:00 2001 From: Satyam Sharma Date: Sat, 22 Sep 2007 08:20:09 +0530 Subject: libata: Fix build failure on ppc64 drivers/ata/pata_scc.c Little fixlets, that the build started erroring / warning about: drivers/ata/pata_scc.c: In function 'scc_bmdma_status': drivers/ata/pata_scc.c:734: error: structure has no member named 'active_tag' drivers/ata/pata_scc.c: In function 'scc_pata_prereset': drivers/ata/pata_scc.c:866: warning: passing arg 1 of 'ata_std_prereset' from incompatible pointer type drivers/ata/pata_scc.c: In function 'scc_error_handler': drivers/ata/pata_scc.c:908: warning: passing arg 2 of 'ata_bmdma_drive_eh' from incompatible pointer type drivers/ata/pata_scc.c:908: warning: passing arg 3 of 'ata_bmdma_drive_eh' from incompatible pointer type drivers/ata/pata_scc.c:908: warning: passing arg 5 of 'ata_bmdma_drive_eh' from incompatible pointer type make[2]: *** [drivers/ata/pata_scc.o] Error 1 Signed-off-by: Satyam Sharma Cc: Alan Cox Cc: Mel Gorman Signed-off-by: Jeff Garzik --- drivers/ata/pata_scc.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c index 941b72bec83..55576138fae 100644 --- a/drivers/ata/pata_scc.c +++ b/drivers/ata/pata_scc.c @@ -603,16 +603,17 @@ static unsigned int scc_bus_softreset(struct ata_port *ap, unsigned int devmask, * Note: Original code is ata_std_softreset(). */ -static int scc_std_softreset (struct ata_port *ap, unsigned int *classes, - unsigned long deadline) +static int scc_std_softreset(struct ata_link *link, unsigned int *classes, + unsigned long deadline) { + struct ata_port *ap = link->ap; unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS; unsigned int devmask = 0, err_mask; u8 err; DPRINTK("ENTER\n"); - if (ata_link_offline(&ap->link)) { + if (ata_link_offline(link)) { classes[0] = ATA_DEV_NONE; goto out; } @@ -703,7 +704,7 @@ static void scc_bmdma_stop (struct ata_queued_cmd *qc) printk(KERN_WARNING "%s: Internal Bus Error\n", DRV_NAME); out_be32(bmid_base + SCC_DMA_INTST, INTSTS_BMSINT); /* TBD: SW reset */ - scc_std_softreset(ap, &classes, deadline); + scc_std_softreset(&ap->link, &classes, deadline); continue; } @@ -742,7 +743,7 @@ static u8 scc_bmdma_status (struct ata_port *ap) void __iomem *mmio = ap->ioaddr.bmdma_addr; u8 host_stat = in_be32(mmio + SCC_DMA_STATUS); u32 int_status = in_be32(mmio + SCC_DMA_INTST); - struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag); + struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->link.active_tag); static int retry = 0; /* return if IOS_SS is cleared */ @@ -871,10 +872,10 @@ static void scc_bmdma_freeze (struct ata_port *ap) * @deadline: deadline jiffies for the operation */ -static int scc_pata_prereset(struct ata_port *ap, unsigned long deadline) +static int scc_pata_prereset(struct ata_link *link, unsigned long deadline) { - ap->cbl = ATA_CBL_PATA80; - return ata_std_prereset(ap, deadline); + link->ap->cbl = ATA_CBL_PATA80; + return ata_std_prereset(link, deadline); } /** @@ -885,8 +886,10 @@ static int scc_pata_prereset(struct ata_port *ap, unsigned long deadline) * Note: Original code is ata_std_postreset(). */ -static void scc_std_postreset (struct ata_port *ap, unsigned int *classes) +static void scc_std_postreset(struct ata_link *link, unsigned int *classes) { + struct ata_port *ap = link->ap; + DPRINTK("ENTER\n"); /* is double-select really necessary? */ -- cgit v1.2.3-70-g09d2 From 3cc3eb1148e4b2dfabf7a1dcf36fd8be1331ca95 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 26 Sep 2007 00:02:41 -0400 Subject: [libata] AHCI: enable AHCI mode, before using AHCI reset AHCI spec says host-reset bit may only be set when the ahci-enable bit is also set. Noticed by Peer Chen Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 9f3c591c721..b615390b6b8 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -827,8 +827,14 @@ static int ahci_reset_controller(struct ata_host *host) void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; u32 tmp; - /* global controller reset */ + /* we must be in AHCI mode, before using anything + * AHCI-specific, such as HOST_RESET. + */ tmp = readl(mmio + HOST_CTL); + if (!(tmp & HOST_AHCI_EN)) + writel(tmp | HOST_AHCI_EN, mmio + HOST_CTL); + + /* global controller reset */ if ((tmp & HOST_RESET) == 0) { writel(tmp | HOST_RESET, mmio + HOST_CTL); readl(mmio + HOST_CTL); /* flush */ -- cgit v1.2.3-70-g09d2 From 21d2c925d3da6aabf9a0b34e95787202379f682a Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 26 Sep 2007 23:02:52 +0100 Subject: pata_atiixp: Audit notes on locking Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/pata_atiixp.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c index 95ed3071a0a..9623f529553 100644 --- a/drivers/ata/pata_atiixp.c +++ b/drivers/ata/pata_atiixp.c @@ -173,6 +173,9 @@ static void atiixp_set_dmamode(struct ata_port *ap, struct ata_device *adev) * * When DMA begins we need to ensure that the UDMA control * register for the channel is correctly set. + * + * Note: The host lock held by the libata layer protects + * us from two channels both trying to set DMA bits at once */ static void atiixp_bmdma_start(struct ata_queued_cmd *qc) @@ -199,6 +202,9 @@ static void atiixp_bmdma_start(struct ata_queued_cmd *qc) * * DMA has completed. Clear the UDMA flag as the next operations will * be PIO ones not UDMA data transfer. + * + * Note: The host lock held by the libata layer protects + * us from two channels both trying to set DMA bits at once */ static void atiixp_bmdma_stop(struct ata_queued_cmd *qc) -- cgit v1.2.3-70-g09d2 From 06b74dd28fa607249c5e41e5f1f6dd1885fe0a0d Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 26 Sep 2007 15:23:17 +0100 Subject: pata_pdc202xx_old MWDMA fixes, and notes I've been doing an audit of this driver to try and find out why we have problems with some Clevo boxes that use it. Didn't get anywhere other than to discover all the bug reporters I have use vmware, which may or may not be chance. In the process however I did find out our MWDMA2 performance was a bit low and code review showed the MWDMA0/2 timings are reversed due to a thinko in the table ordering Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/pata_pdc202xx_old.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c index fd4350029bc..65d951618c6 100644 --- a/drivers/ata/pata_pdc202xx_old.c +++ b/drivers/ata/pata_pdc202xx_old.c @@ -9,7 +9,7 @@ * First cut with LBA48/ATAPI * * TODO: - * Channel interlock/reset on both required + * Channel interlock/reset on both required ? */ #include @@ -22,7 +22,7 @@ #include #define DRV_NAME "pata_pdc202xx_old" -#define DRV_VERSION "0.4.2" +#define DRV_VERSION "0.4.3" static int pdc2026x_cable_detect(struct ata_port *ap) { @@ -106,9 +106,9 @@ static void pdc202xx_set_dmamode(struct ata_port *ap, struct ata_device *adev) { 0x20, 0x01 } }; static u8 mdma_timing[3][2] = { - { 0x60, 0x03 }, - { 0x60, 0x04 }, { 0xe0, 0x0f }, + { 0x60, 0x04 }, + { 0x60, 0x03 }, }; u8 r_bp, r_cp; @@ -139,6 +139,9 @@ static void pdc202xx_set_dmamode(struct ata_port *ap, struct ata_device *adev) * * In UDMA3 or higher we have to clock switch for the duration of the * DMA transfer sequence. + * + * Note: The host lock held by the libata layer protects + * us from two channels both trying to set DMA bits at once */ static void pdc2026x_bmdma_start(struct ata_queued_cmd *qc) @@ -187,6 +190,9 @@ static void pdc2026x_bmdma_start(struct ata_queued_cmd *qc) * * After a DMA completes we need to put the clock back to 33MHz for * PIO timings. + * + * Note: The host lock held by the libata layer protects + * us from two channels both trying to set DMA bits at once */ static void pdc2026x_bmdma_stop(struct ata_queued_cmd *qc) @@ -206,7 +212,6 @@ static void pdc2026x_bmdma_stop(struct ata_queued_cmd *qc) iowrite32(0, atapi_reg); iowrite8(ioread8(clock) & ~sel66, clock); } - /* Check we keep host level locking here */ /* Flip back to 33Mhz for PIO */ if (adev->dma_mode >= XFER_UDMA_2) iowrite8(ioread8(clock) & ~sel66, clock); -- cgit v1.2.3-70-g09d2 From 7f567620ed32bea40a2acc25900c79db4dff96aa Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 28 Sep 2007 06:29:23 -0700 Subject: libata: update spurious NCQ completion blacklist * The firmware version of ST3160812AS is "3.ADJ" no "3.AD". * Add several entries from various sources. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index fd4563daacd..7f424c4b1bb 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -3891,9 +3891,12 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { "HTS541612J9SA00", "SBDIC7JP", ATA_HORKAGE_NONCQ, }, { "Hitachi HTS541616J9SA00", "SB4OC70P", ATA_HORKAGE_NONCQ, }, { "WDC WD740ADFD-00NLR1", NULL, ATA_HORKAGE_NONCQ, }, + { "WDC WD3200AAJS-00RYA0", "12.01B01", ATA_HORKAGE_NONCQ, }, { "FUJITSU MHV2080BH", "00840028", ATA_HORKAGE_NONCQ, }, + { "ST9120822AS", "3.CLF", ATA_HORKAGE_NONCQ, }, { "ST9160821AS", "3.CLF", ATA_HORKAGE_NONCQ, }, - { "ST3160812AS", "3.AD", ATA_HORKAGE_NONCQ, }, + { "ST3160812AS", "3.ADJ", ATA_HORKAGE_NONCQ, }, + { "ST980813AS", "3.ADB", ATA_HORKAGE_NONCQ, }, { "SAMSUNG HD401LJ", "ZZ100-15", ATA_HORKAGE_NONCQ, }, /* devices which puke on READ_NATIVE_MAX */ -- cgit v1.2.3-70-g09d2 From 0b0a43e04ea671adc3cac085ee567d63c9ab3507 Mon Sep 17 00:00:00 2001 From: David Milburn Date: Fri, 28 Sep 2007 14:29:06 -0500 Subject: libata-core: blacklist HITACHI HDS drives using wildcard blacklist matching Blacklist HITACHI HDS7250SASUN500G and HITACHI HDS7225SBSUN250G drives using wildcard matching. Signed-off-by David Milburn Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 7f424c4b1bb..d2880b013c8 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -3878,8 +3878,8 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { /* NCQ is broken */ { "Maxtor *", "BANC*", ATA_HORKAGE_NONCQ }, { "Maxtor 7V300F0", "VA111630", ATA_HORKAGE_NONCQ }, - { "HITACHI HDS7250SASUN500G 0621KTAWSD", "K2AOAJ0AHITACHI", - ATA_HORKAGE_NONCQ }, + { "HITACHI HDS7250SASUN500G*", NULL, ATA_HORKAGE_NONCQ }, + { "HITACHI HDS7225SBSUN250G*", NULL, ATA_HORKAGE_NONCQ }, /* Blacklist entries taken from Silicon Image 3124/3132 Windows driver .inf file - also several Linux problem reports */ -- cgit v1.2.3-70-g09d2 From c4b5b7b6c4423ec4ced4177c87d2da04de324028 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Sat, 29 Sep 2007 02:35:10 -0400 Subject: pata_ns87415: Initial cut at 87415/87560 IDE support Signed-off-by: Alan Cox [plus SuperIO fixes by Kyle McMartin] [plus a cleanup from me] Signed-off-by: Jeff Garzik --- drivers/ata/Kconfig | 9 + drivers/ata/Makefile | 1 + drivers/ata/pata_ns87415.c | 467 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 477 insertions(+) create mode 100644 drivers/ata/pata_ns87415.c (limited to 'drivers') diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 3a737bdce2e..cf960bd1c00 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -441,6 +441,15 @@ config PATA_NS87410 If unsure, say N. +config PATA_NS87415 + tristate "Nat Semi NS87415 PATA support (Experimental)" + depends on PCI && EXPERIMENTAL + help + This option enables support for the National Semiconductor + NS87415 PCI-IDE controller. + + If unsure, say N. + config PATA_OPTI tristate "OPTI621/6215 PATA support (Very Experimental)" depends on PCI && EXPERIMENTAL diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 4eb7fb44be3..56bf13cbd19 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -40,6 +40,7 @@ obj-$(CONFIG_PATA_IT8213) += pata_it8213.o obj-$(CONFIG_PATA_JMICRON) += pata_jmicron.o obj-$(CONFIG_PATA_NETCELL) += pata_netcell.o obj-$(CONFIG_PATA_NS87410) += pata_ns87410.o +obj-$(CONFIG_PATA_NS87415) += pata_ns87415.o obj-$(CONFIG_PATA_OPTI) += pata_opti.o obj-$(CONFIG_PATA_OPTIDMA) += pata_optidma.o obj-$(CONFIG_PATA_MPC52xx) += pata_mpc52xx.o diff --git a/drivers/ata/pata_ns87415.c b/drivers/ata/pata_ns87415.c new file mode 100644 index 00000000000..bb97ef583f9 --- /dev/null +++ b/drivers/ata/pata_ns87415.c @@ -0,0 +1,467 @@ +/* + * pata_ns87415.c - NS87415 (non PARISC) PATA + * + * (C) 2005 Red Hat + * + * This is a fairly generic MWDMA controller. It has some limitations + * as it requires timing reloads on PIO/DMA transitions but it is otherwise + * fairly well designed. + * + * This driver assumes the firmware has left the chip in a valid ST506 + * compliant state, either legacy IRQ 14/15 or native INTA shared. You + * may need to add platform code if your system fails to do this. + * + * The same cell appears in the 87560 controller used by some PARISC + * systems. This has its own special mountain of errata. + * + * TODO: + * Test PARISC SuperIO + * Get someone to test on SPARC + * Implement lazy pio/dma switching for better performance + * 8bit shared timing. + * See if we need to kill the FIFO for ATAPI + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "pata_ns87415" +#define DRV_VERSION "0.0.1" + +/** + * ns87415_set_mode - Initialize host controller mode timings + * @ap: Port whose timings we are configuring + * @adev: Device whose timings we are configuring + * @mode: Mode to set + * + * Program the mode registers for this controller, channel and + * device. Because the chip is quite an old design we have to do this + * for PIO/DMA switches. + * + * LOCKING: + * None (inherited from caller). + */ + +static void ns87415_set_mode(struct ata_port *ap, struct ata_device *adev, u8 mode) +{ + struct pci_dev *dev = to_pci_dev(ap->host->dev); + int unit = 2 * ap->port_no + adev->devno; + int timing = 0x44 + 2 * unit; + unsigned long T = 1000000000 / 33333; /* PCI clocks */ + struct ata_timing t; + u16 clocking; + u8 iordy; + u8 status; + + /* Timing register format is 17 - low nybble read timing with + the high nybble being 16 - x for recovery time in PCI clocks */ + + ata_timing_compute(adev, adev->pio_mode, &t, T, 0); + + clocking = 17 - FIT(t.active, 2, 17); + clocking |= (16 - FIT(t.recover, 1, 16)) << 4; + /* Use the same timing for read and write bytes */ + clocking |= (clocking << 8); + pci_write_config_word(dev, timing, clocking); + + /* Set the IORDY enable versus DMA enable on or off properly */ + pci_read_config_byte(dev, 0x42, &iordy); + iordy &= ~(1 << (4 + unit)); + if (mode >= XFER_MW_DMA_0 || !ata_pio_need_iordy(adev)) + iordy |= (1 << (4 + unit)); + + /* Paranoia: We shouldn't ever get here with busy write buffers + but if so wait */ + + pci_read_config_byte(dev, 0x43, &status); + while (status & 0x03) { + udelay(1); + pci_read_config_byte(dev, 0x43, &status); + } + /* Flip the IORDY/DMA bits now we are sure the write buffers are + clear */ + pci_write_config_byte(dev, 0x42, iordy); + + /* TODO: Set byte 54 command timing to the best 8bit + mode shared by all four devices */ +} + +/** + * ns87415_set_piomode - Initialize host controller PATA PIO timings + * @ap: Port whose timings we are configuring + * @adev: Device to program + * + * Set PIO mode for device, in host controller PCI config space. + * + * LOCKING: + * None (inherited from caller). + */ + +static void ns87415_set_piomode(struct ata_port *ap, struct ata_device *adev) +{ + ns87415_set_mode(ap, adev, adev->pio_mode); +} + +/** + * ns87415_bmdma_setup - Set up DMA + * @qc: Command block + * + * Set up for bus masterng DMA. We have to do this ourselves + * rather than use the helper due to a chip erratum + */ + +static void ns87415_bmdma_setup(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE); + u8 dmactl; + + /* load PRD table addr. */ + mb(); /* make sure PRD table writes are visible to controller */ + iowrite32(ap->prd_dma, ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS); + + /* specify data direction, triple-check start bit is clear */ + dmactl = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD); + dmactl &= ~(ATA_DMA_WR | ATA_DMA_START); + /* Due to an erratum we need to write these bits to the wrong + place - which does save us an I/O bizarrely */ + dmactl |= ATA_DMA_INTR | ATA_DMA_ERR; + if (!rw) + dmactl |= ATA_DMA_WR; + iowrite8(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD); + /* issue r/w command */ + ap->ops->exec_command(ap, &qc->tf); +} + +/** + * ns87415_bmdma_start - Begin DMA transfer + * @qc: Command block + * + * Switch the timings for the chip and set up for a DMA transfer + * before the DMA burst begins. + * + * FIXME: We should do lazy switching on bmdma_start versus + * ata_pio_data_xfer for better performance. + */ + +static void ns87415_bmdma_start(struct ata_queued_cmd *qc) +{ + ns87415_set_mode(qc->ap, qc->dev, qc->dev->dma_mode); + ata_bmdma_start(qc); +} + +/** + * ns87415_bmdma_stop - End DMA transfer + * @qc: Command block + * + * End DMA mode and switch the controller back into PIO mode + */ + +static void ns87415_bmdma_stop(struct ata_queued_cmd *qc) +{ + ata_bmdma_stop(qc); + ns87415_set_mode(qc->ap, qc->dev, qc->dev->pio_mode); +} + +/** + * ns87415_bmdma_irq_clear - Clear interrupt + * @ap: Channel to clear + * + * Erratum: Due to a chip bug regisers 02 and 0A bit 1 and 2 (the + * error bits) are reset by writing to register 00 or 08. + */ + +static void ns87415_bmdma_irq_clear(struct ata_port *ap) +{ + void __iomem *mmio = ap->ioaddr.bmdma_addr; + + if (!mmio) + return; + iowrite8((ioread8(mmio + ATA_DMA_CMD) | ATA_DMA_INTR | ATA_DMA_ERR), + mmio + ATA_DMA_CMD); +} + +/** + * ns87415_check_atapi_dma - ATAPI DMA filter + * @qc: Command block + * + * Disable ATAPI DMA (for now). We may be able to do DMA if we + * kill the prefetching. This isn't clear. + */ + +static int ns87415_check_atapi_dma(struct ata_queued_cmd *qc) +{ + return -EOPNOTSUPP; +} + +#if defined(CONFIG_SUPERIO) + +/* SUPERIO 87560 is a PoS chip that NatSem denies exists. + * Unfortunately, it's built-in on all Astro-based PA-RISC workstations + * which use the integrated NS87514 cell for CD-ROM support. + * i.e we have to support for CD-ROM installs. + * See drivers/parisc/superio.c for more gory details. + * + * Workarounds taken from drivers/ide/pci/ns87415.c + */ + +#include + +/** + * ns87560_read_buggy - workaround buggy Super I/O chip + * @port: Port to read + * + * Work around chipset problems in the 87560 SuperIO chip + */ + +static u8 ns87560_read_buggy(void __iomem *port) +{ + u8 tmp; + int retries = SUPERIO_IDE_MAX_RETRIES; + do { + tmp = ioread8(port); + if (tmp != 0) + return tmp; + udelay(50); + } while(retries-- > 0); + return tmp; +} + +/** + * ns87560_check_status + * @ap: channel to check + * + * Return the status of the channel working around the + * 87560 flaws. + */ + +static u8 ns87560_check_status(struct ata_port *ap) +{ + return ns87560_read_buggy(ap->ioaddr.status_addr); +} + +/** + * ns87560_tf_read - input device's ATA taskfile shadow registers + * @ap: Port from which input is read + * @tf: ATA taskfile register set for storing input + * + * Reads ATA taskfile registers for currently-selected device + * into @tf. Work around the 87560 bugs. + * + * LOCKING: + * Inherited from caller. + */ +void ns87560_tf_read(struct ata_port *ap, struct ata_taskfile *tf) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + + tf->command = ns87560_check_status(ap); + tf->feature = ioread8(ioaddr->error_addr); + tf->nsect = ioread8(ioaddr->nsect_addr); + tf->lbal = ioread8(ioaddr->lbal_addr); + tf->lbam = ioread8(ioaddr->lbam_addr); + tf->lbah = ioread8(ioaddr->lbah_addr); + tf->device = ns87560_read_buggy(ioaddr->device_addr); + + if (tf->flags & ATA_TFLAG_LBA48) { + iowrite8(tf->ctl | ATA_HOB, ioaddr->ctl_addr); + tf->hob_feature = ioread8(ioaddr->error_addr); + tf->hob_nsect = ioread8(ioaddr->nsect_addr); + tf->hob_lbal = ioread8(ioaddr->lbal_addr); + tf->hob_lbam = ioread8(ioaddr->lbam_addr); + tf->hob_lbah = ioread8(ioaddr->lbah_addr); + iowrite8(tf->ctl, ioaddr->ctl_addr); + ap->last_ctl = tf->ctl; + } +} + +/** + * ns87560_bmdma_status + * @ap: channel to check + * + * Return the DMA status of the channel working around the + * 87560 flaws. + */ + +static u8 ns87560_bmdma_status(struct ata_port *ap) +{ + return ns87560_read_buggy(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); +} + +static const struct ata_port_operations ns87560_pata_ops = { + .set_piomode = ns87415_set_piomode, + .mode_filter = ata_pci_default_filter, + + .tf_load = ata_tf_load, + .tf_read = ns87560_tf_read, + .check_status = ns87560_check_status, + .check_atapi_dma = ns87415_check_atapi_dma, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, + + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, + .error_handler = ata_bmdma_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, + .cable_detect = ata_cable_40wire, + + .bmdma_setup = ns87415_bmdma_setup, + .bmdma_start = ns87415_bmdma_start, + .bmdma_stop = ns87415_bmdma_stop, + .bmdma_status = ns87560_bmdma_status, + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + .data_xfer = ata_data_xfer, + + .irq_handler = ata_interrupt, + .irq_clear = ns87415_bmdma_irq_clear, + .irq_on = ata_irq_on, + + .port_start = ata_sff_port_start, +}; + +#endif /* 87560 SuperIO Support */ + + +static const struct ata_port_operations ns87415_pata_ops = { + .set_piomode = ns87415_set_piomode, + .mode_filter = ata_pci_default_filter, + + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .check_atapi_dma = ns87415_check_atapi_dma, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, + + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, + .error_handler = ata_bmdma_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, + .cable_detect = ata_cable_40wire, + + .bmdma_setup = ns87415_bmdma_setup, + .bmdma_start = ns87415_bmdma_start, + .bmdma_stop = ns87415_bmdma_stop, + .bmdma_status = ata_bmdma_status, + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + .data_xfer = ata_data_xfer, + + .irq_handler = ata_interrupt, + .irq_clear = ns87415_bmdma_irq_clear, + .irq_on = ata_irq_on, + + .port_start = ata_sff_port_start, +}; + +static struct scsi_host_template ns87415_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, + .queuecommand = ata_scsi_queuecmd, + .can_queue = ATA_DEF_QUEUE, + .this_id = ATA_SHT_THIS_ID, + .sg_tablesize = LIBATA_MAX_PRD, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ATA_SHT_USE_CLUSTERING, + .proc_name = DRV_NAME, + .dma_boundary = ATA_DMA_BOUNDARY, + .slave_configure = ata_scsi_slave_config, + .slave_destroy = ata_scsi_slave_destroy, + .bios_param = ata_std_bios_param, +}; + + +/** + * ns87415_init_one - Register 87415 ATA PCI device with kernel services + * @pdev: PCI device to register + * @ent: Entry in ns87415_pci_tbl matching with @pdev + * + * Called from kernel PCI layer. We probe for combined mode (sigh), + * and then hand over control to libata, for it to do the rest. + * + * LOCKING: + * Inherited from PCI layer (may sleep). + * + * RETURNS: + * Zero on success, or -ERRNO value. + */ + +static int ns87415_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) +{ + static int printed_version; + static const struct ata_port_info info = { + .sht = &ns87415_sht, + .flags = ATA_FLAG_SLAVE_POSS, + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .port_ops = &ns87415_pata_ops, + }; + const struct ata_port_info *ppi[] = { &info, NULL }; +#if defined(CONFIG_SUPERIO) + static const struct ata_port_info info87560 = { + .sht = &ns87415_sht, + .flags = ATA_FLAG_SLAVE_POSS, + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .port_ops = &ns87560_pata_ops, + }; + + if (PCI_SLOT(pdev->devfn) == 0x0E) + ppi[0] = &info87560; +#endif + if (!printed_version++) + dev_printk(KERN_DEBUG, &pdev->dev, + "version " DRV_VERSION "\n"); + /* Select 512 byte sectors */ + pci_write_config_byte(pdev, 0x55, 0xEE); + /* Select PIO0 8bit clocking */ + pci_write_config_byte(pdev, 0x54, 0xB7); + return ata_pci_init_one(pdev, ppi); +} + +static const struct pci_device_id ns87415_pci_tbl[] = { + { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_87415), }, + + { } /* terminate list */ +}; + +static struct pci_driver ns87415_pci_driver = { + .name = DRV_NAME, + .id_table = ns87415_pci_tbl, + .probe = ns87415_init_one, + .remove = ata_pci_remove_one, +#ifdef CONFIG_PM + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, +#endif +}; + +static int __init ns87415_init(void) +{ + return pci_register_driver(&ns87415_pci_driver); +} + +static void __exit ns87415_exit(void) +{ + pci_unregister_driver(&ns87415_pci_driver); +} + +module_init(ns87415_init); +module_exit(ns87415_exit); + +MODULE_AUTHOR("Alan Cox"); +MODULE_DESCRIPTION("ATA low-level driver for NS87415 controllers"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, ns87415_pci_tbl); +MODULE_VERSION(DRV_VERSION); -- cgit v1.2.3-70-g09d2 From 54174db300ee1bac632d62e4ac37fe02e47d1f18 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Sat, 29 Sep 2007 04:01:43 -0400 Subject: [libata] ata_piix: add HP compaq laptop to short cable list Reported by Andreas Messer. Signed-off-by: Jeff Garzik --- drivers/ata/ata_piix.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 8dc15a6cea7..e783e678acf 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -598,6 +598,7 @@ static const struct ich_laptop ich_laptop[] = { { 0x27DF, 0x0005, 0x0280 }, /* ICH7 on Acer 5602WLMi */ { 0x27DF, 0x1025, 0x0110 }, /* ICH7 on Acer 3682WLMi */ { 0x27DF, 0x1043, 0x1267 }, /* ICH7 on Asus W5F */ + { 0x27DF, 0x103C, 0x30A1 }, /* ICH7 on HP Compaq nc2400 */ { 0x24CA, 0x1025, 0x0061 }, /* ICH4 on ACER Aspire 2023WLMi */ /* end marker */ { 0, } -- cgit v1.2.3-70-g09d2 From 93328e1145c1989d1a214d34ac4e968dea7f7ed7 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Sat, 29 Sep 2007 04:06:48 -0400 Subject: [PATCH] libata: Fix HPA handling regression Restore the support for handling drives that report one sector too many (ie SCSI not ATA style). This worked before the HPA update but was removed in that process. Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 7 ++++++- include/linux/libata.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index d2880b013c8..eb9709864a2 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -915,7 +915,8 @@ static int ata_read_native_max_address(struct ata_device *dev, u64 *max_sectors) *max_sectors = ata_tf_to_lba48(&tf); else *max_sectors = ata_tf_to_lba(&tf); - + if (dev->horkage & ATA_HORKAGE_HPA_SIZE) + (*max_sectors)--; return 0; } @@ -3905,6 +3906,10 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { "WDC WD2500JD-00HBB0", "WD-WMAL71490727", ATA_HORKAGE_BROKEN_HPA }, { "MAXTOR 6L080L4", "A93.0500", ATA_HORKAGE_BROKEN_HPA }, + /* Devices which report 1 sector over size HPA */ + { "ST340823A", NULL, ATA_HORKAGE_HPA_SIZE, }, + { "ST320413A", NULL, ATA_HORKAGE_HPA_SIZE, }, + /* End Marker */ { } }; diff --git a/include/linux/libata.h b/include/linux/libata.h index cd9c2a28136..f9ed198e4fc 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -330,6 +330,7 @@ enum { ATA_HORKAGE_MAX_SEC_128 = (1 << 3), /* Limit max sects to 128 */ ATA_HORKAGE_BROKEN_HPA = (1 << 4), /* Broken HPA */ ATA_HORKAGE_SKIP_PM = (1 << 5), /* Skip PM operations */ + ATA_HORKAGE_HPA_SIZE = (1 << 6), /* native size off by one */ }; enum hsm_task_states { -- cgit v1.2.3-70-g09d2 From 3495de733633d24ee97852080b737b436c110d6e Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 23 Sep 2007 13:19:53 +0900 Subject: libata-pmp: update ata_eh_reset() for PMP PMP always requires SRST to be enabled. Also, hardreset reports classification code from the first device when PMP is attached, not from the PMP. Update ata_eh_reset() such that followup softreset is performed if the controller is PMP capable and the host link is being reset. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-eh.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 60186f8ac3a..687419b6670 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -2003,6 +2003,8 @@ static int ata_eh_followup_srst_needed(struct ata_link *link, return 1; if (rc != 0) return 0; + if ((link->ap->flags & ATA_FLAG_PMP) && ata_is_host_link(link)) + return 1; if (classify && !(link->flags & ATA_LFLAG_ASSUME_CLASS) && classes[0] == ATA_DEV_UNKNOWN) return 1; -- cgit v1.2.3-70-g09d2 From 3af9a77af9e2b72366363864bfcd3d51465ff98a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 23 Sep 2007 13:19:54 +0900 Subject: libata-pmp: implement Port Multiplier support Implement Port Multiplier support. To support PMP, a LLDD has to supply ops->pmp_read() and pmp_write(). If non-null, ->pmp_attach and ->pmp_detach are called on PMP attach and detach, respectively. ->pmp_read/write() can be called while the port is frozen, so they must be implemented by polling. This patch supplies several helpers to ease ->pmp_read/write() implementation. Also, irq_handler and error_handler must be PMP aware. Most of PMP aware EH can be done by calling ata_pmp_do_eh() with appropriate methods. PMP EH uses separate set of reset methods and this patch implements standard prereset, hardreset and postreset methods. This patch only implements PMP support. The next patch will integrate PMP into the reset of libata and thus enable PMP support. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/Makefile | 3 +- drivers/ata/libata-core.c | 11 + drivers/ata/libata-pmp.c | 1182 +++++++++++++++++++++++++++++++++++++++++++++ drivers/ata/libata.h | 5 + include/linux/libata.h | 19 + 5 files changed, 1219 insertions(+), 1 deletion(-) create mode 100644 drivers/ata/libata-pmp.c (limited to 'drivers') diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 56bf13cbd19..7e937519a93 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -71,5 +71,6 @@ obj-$(CONFIG_ATA_GENERIC) += ata_generic.o # Should be last libata driver obj-$(CONFIG_PATA_LEGACY) += pata_legacy.o -libata-objs := libata-core.o libata-scsi.o libata-sff.o libata-eh.o +libata-objs := libata-core.o libata-scsi.o libata-sff.o libata-eh.o \ + libata-pmp.o libata-$(CONFIG_ATA_ACPI) += libata-acpi.o diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index eb9709864a2..9e7f55b7104 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -3865,6 +3865,9 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { "IOMEGA ZIP 250 ATAPI", NULL, ATA_HORKAGE_NODMA }, /* temporary fix */ { "IOMEGA ZIP 250 ATAPI Floppy", NULL, ATA_HORKAGE_NODMA }, + /* Odd clown on sil3726/4726 PMPs */ + { "Config Disk", NULL, ATA_HORKAGE_NODMA | + ATA_HORKAGE_SKIP_PM }, /* Weird ATAPI devices */ { "TORiSAN DVD-ROM DRD-N216", NULL, ATA_HORKAGE_MAX_SEC_128 }, @@ -7251,6 +7254,14 @@ EXPORT_SYMBOL_GPL(ata_pci_default_filter); EXPORT_SYMBOL_GPL(ata_pci_clear_simplex); #endif /* CONFIG_PCI */ +EXPORT_SYMBOL_GPL(sata_pmp_read_init_tf); +EXPORT_SYMBOL_GPL(sata_pmp_read_val); +EXPORT_SYMBOL_GPL(sata_pmp_write_init_tf); +EXPORT_SYMBOL_GPL(sata_pmp_std_prereset); +EXPORT_SYMBOL_GPL(sata_pmp_std_hardreset); +EXPORT_SYMBOL_GPL(sata_pmp_std_postreset); +EXPORT_SYMBOL_GPL(sata_pmp_do_eh); + EXPORT_SYMBOL_GPL(__ata_ehi_push_desc); EXPORT_SYMBOL_GPL(ata_ehi_push_desc); EXPORT_SYMBOL_GPL(ata_ehi_clear_desc); diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c new file mode 100644 index 00000000000..671d171055a --- /dev/null +++ b/drivers/ata/libata-pmp.c @@ -0,0 +1,1182 @@ +/* + * libata-pmp.c - libata port multiplier support + * + * Copyright (c) 2007 SUSE Linux Products GmbH + * Copyright (c) 2007 Tejun Heo + * + * This file is released under the GPLv2. + */ + +#include +#include +#include "libata.h" + +/** + * sata_pmp_read - read PMP register + * @link: link to read PMP register for + * @reg: register to read + * @r_val: resulting value + * + * Wrapper around ap->ops->pmp_read to make it easier to call and + * nomarlize error return value. + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno on failure. + */ +static int sata_pmp_read(struct ata_link *link, int reg, u32 *r_val) +{ + struct ata_port *ap = link->ap; + struct ata_device *pmp_dev = ap->link.device; + int rc; + + might_sleep(); + + rc = ap->ops->pmp_read(pmp_dev, link->pmp, reg, r_val); + if (rc) + rc = -EIO; + return rc; +} + +/** + * sata_pmp_write - write PMP register + * @link: link to write PMP register for + * @reg: register to write + * @r_val: value to write + * + * Wrapper around ap->ops->pmp_write to make it easier to call + * and nomarlize error return value. + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno on failure. + */ +static int sata_pmp_write(struct ata_link *link, int reg, u32 val) +{ + struct ata_port *ap = link->ap; + struct ata_device *pmp_dev = ap->link.device; + int rc; + + might_sleep(); + + rc = ap->ops->pmp_write(pmp_dev, link->pmp, reg, val); + if (rc) + rc = -EIO; + return rc; +} + +/** + * sata_pmp_read_init_tf - initialize TF for PMP read + * @tf: taskfile to initialize + * @dev: PMP dev + * @pmp: port multiplier port number + * @reg: register to read + * + * Initialize @tf for PMP read command. + * + * LOCKING: + * None. + */ +void sata_pmp_read_init_tf(struct ata_taskfile *tf, + struct ata_device *dev, int pmp, int reg) +{ + ata_tf_init(dev, tf); + tf->command = ATA_CMD_PMP_READ; + tf->protocol = ATA_PROT_NODATA; + tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf->feature = reg; + tf->device = pmp; +} + +/** + * sata_pmp_read_val - extract PMP read result from TF + * @tf: target TF + * + * Determine PMP read result from @tf. + * + * LOCKING: + * None. + */ +u32 sata_pmp_read_val(const struct ata_taskfile *tf) +{ + return tf->nsect | tf->lbal << 8 | tf->lbam << 16 | tf->lbah << 24; +} + +/** + * sata_pmp_read_init_tf - initialize TF for PMP write + * @tf: taskfile to initialize + * @dev: PMP dev + * @pmp: port multiplier port number + * @reg: register to read + * @val: value to write + * + * Initialize @tf for PMP write command. + * + * LOCKING: + * None. + */ +void sata_pmp_write_init_tf(struct ata_taskfile *tf, + struct ata_device *dev, int pmp, int reg, u32 val) +{ + ata_tf_init(dev, tf); + tf->command = ATA_CMD_PMP_WRITE; + tf->protocol = ATA_PROT_NODATA; + tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf->feature = reg; + tf->device = pmp; + tf->nsect = val & 0xff; + tf->lbal = (val >> 8) & 0xff; + tf->lbam = (val >> 16) & 0xff; + tf->lbah = (val >> 24) & 0xff; +} + +/** + * sata_pmp_scr_read - read PSCR + * @link: ATA link to read PSCR for + * @reg: PSCR to read + * @r_val: resulting value + * + * Read PSCR @reg into @r_val for @link, to be called from + * ata_scr_read(). + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno on failure. + */ +int sata_pmp_scr_read(struct ata_link *link, int reg, u32 *r_val) +{ + if (reg > SATA_PMP_PSCR_CONTROL) + return -EINVAL; + + return sata_pmp_read(link, reg, r_val); +} + +/** + * sata_pmp_scr_write - write PSCR + * @link: ATA link to write PSCR for + * @reg: PSCR to write + * @val: value to be written + * + * Write @val to PSCR @reg for @link, to be called from + * ata_scr_write() and ata_scr_write_flush(). + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno on failure. + */ +int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val) +{ + if (reg > SATA_PMP_PSCR_CONTROL) + return -EINVAL; + + return sata_pmp_write(link, reg, val); +} + +/** + * sata_pmp_std_prereset - prepare PMP link for reset + * @link: link to be reset + * @deadline: deadline jiffies for the operation + * + * @link is about to be reset. Initialize it. + * + * LOCKING: + * Kernel thread context (may sleep) + * + * RETURNS: + * 0 on success, -errno otherwise. + */ +int sata_pmp_std_prereset(struct ata_link *link, unsigned long deadline) +{ + struct ata_eh_context *ehc = &link->eh_context; + const unsigned long *timing = sata_ehc_deb_timing(ehc); + int rc; + + /* force HRST? */ + if (link->flags & ATA_LFLAG_NO_SRST) + ehc->i.action |= ATA_EH_HARDRESET; + + /* handle link resume */ + if ((ehc->i.flags & ATA_EHI_RESUME_LINK) && + (link->flags & ATA_LFLAG_HRST_TO_RESUME)) + ehc->i.action |= ATA_EH_HARDRESET; + + /* if we're about to do hardreset, nothing more to do */ + if (ehc->i.action & ATA_EH_HARDRESET) + return 0; + + /* resume link */ + rc = sata_link_resume(link, timing, deadline); + if (rc) { + /* phy resume failed */ + ata_link_printk(link, KERN_WARNING, "failed to resume link " + "for reset (errno=%d)\n", rc); + return rc; + } + + /* clear SError bits including .X which blocks the port when set */ + rc = sata_scr_write(link, SCR_ERROR, 0xffffffff); + if (rc) { + ata_link_printk(link, KERN_ERR, + "failed to clear SError (errno=%d)\n", rc); + return rc; + } + + return 0; +} + +/** + * sata_pmp_std_hardreset - standard hardreset method for PMP link + * @link: link to be reset + * @class: resulting class of attached device + * @deadline: deadline jiffies for the operation + * + * Hardreset PMP port @link. Note that this function doesn't + * wait for BSY clearance. There simply isn't a generic way to + * wait the event. Instead, this function return -EAGAIN thus + * telling libata-EH to followup with softreset. + * + * LOCKING: + * Kernel thread context (may sleep) + * + * RETURNS: + * 0 on success, -errno otherwise. + */ +int sata_pmp_std_hardreset(struct ata_link *link, unsigned int *class, + unsigned long deadline) +{ + const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); + u32 tmp; + int rc; + + DPRINTK("ENTER\n"); + + /* do hardreset */ + rc = sata_link_hardreset(link, timing, deadline); + if (rc) { + ata_link_printk(link, KERN_ERR, + "COMRESET failed (errno=%d)\n", rc); + goto out; + } + + /* clear SError bits including .X which blocks the port when set */ + rc = sata_scr_write(link, SCR_ERROR, 0xffffffff); + if (rc) { + ata_link_printk(link, KERN_ERR, "failed to clear SError " + "during hardreset (errno=%d)\n", rc); + goto out; + } + + /* if device is present, follow up with srst to wait for !BSY */ + if (ata_link_online(link)) + rc = -EAGAIN; + out: + /* if SCR isn't accessible, we need to reset the PMP */ + if (rc && rc != -EAGAIN && sata_scr_read(link, SCR_STATUS, &tmp)) + rc = -ERESTART; + + DPRINTK("EXIT, rc=%d\n", rc); + return rc; +} + +/** + * ata_std_postreset - standard postreset method for PMP link + * @link: the target ata_link + * @classes: classes of attached devices + * + * This function is invoked after a successful reset. Note that + * the device might have been reset more than once using + * different reset methods before postreset is invoked. + * + * LOCKING: + * Kernel thread context (may sleep) + */ +void sata_pmp_std_postreset(struct ata_link *link, unsigned int *class) +{ + u32 serror; + + DPRINTK("ENTER\n"); + + /* clear SError */ + if (sata_scr_read(link, SCR_ERROR, &serror) == 0) + sata_scr_write(link, SCR_ERROR, serror); + + /* print link status */ + sata_print_link_status(link); + + DPRINTK("EXIT\n"); +} + +/** + * sata_pmp_read_gscr - read GSCR block of SATA PMP + * @dev: PMP device + * @gscr: buffer to read GSCR block into + * + * Read selected PMP GSCRs from the PMP at @dev. This will serve + * as configuration and identification info for the PMP. + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno on failure. + */ +static int sata_pmp_read_gscr(struct ata_device *dev, u32 *gscr) +{ + static const int gscr_to_read[] = { 0, 1, 2, 32, 33, 64, 96 }; + int i, rc; + + for (i = 0; i < ARRAY_SIZE(gscr_to_read); i++) { + int reg = gscr_to_read[i]; + + rc = sata_pmp_read(dev->link, reg, &gscr[reg]); + if (rc) { + ata_dev_printk(dev, KERN_ERR, "failed to read " + "PMP GSCR[%d] (errno=%d)\n", reg, rc); + return rc; + } + } + + return 0; +} + +static const char *sata_pmp_spec_rev_str(const u32 *gscr) +{ + u32 rev = gscr[SATA_PMP_GSCR_REV]; + + if (rev & (1 << 2)) + return "1.1"; + if (rev & (1 << 1)) + return "1.0"; + return ""; +} + +static int sata_pmp_configure(struct ata_device *dev, int print_info) +{ + struct ata_port *ap = dev->link->ap; + u32 *gscr = dev->gscr; + const char *reason; + int nr_ports, rc; + + nr_ports = sata_pmp_gscr_ports(gscr); + + if (nr_ports <= 0 || nr_ports > SATA_PMP_MAX_PORTS) { + rc = -EINVAL; + reason = "invalid nr_ports"; + goto fail; + } + + if ((ap->flags & ATA_FLAG_AN) && + (gscr[SATA_PMP_GSCR_FEAT] & SATA_PMP_FEAT_NOTIFY)) + dev->flags |= ATA_DFLAG_AN; + + /* monitor SERR_PHYRDY_CHG on fan-out ports */ + rc = sata_pmp_write(dev->link, SATA_PMP_GSCR_ERROR_EN, SERR_PHYRDY_CHG); + if (rc) { + reason = "failed to write GSCR_ERROR_EN"; + goto fail; + } + + /* turn off notification till fan-out ports are reset and configured */ + if (gscr[SATA_PMP_GSCR_FEAT_EN] & SATA_PMP_FEAT_NOTIFY) { + gscr[SATA_PMP_GSCR_FEAT_EN] &= ~SATA_PMP_FEAT_NOTIFY; + + rc = sata_pmp_write(dev->link, SATA_PMP_GSCR_FEAT_EN, + gscr[SATA_PMP_GSCR_FEAT_EN]); + if (rc) { + reason = "failed to write GSCR_FEAT_EN"; + goto fail; + } + } + + if (print_info) { + ata_dev_printk(dev, KERN_INFO, "Port Multiplier %s, " + "0x%04x:0x%04x r%d, %d ports, feat 0x%x/0x%x\n", + sata_pmp_spec_rev_str(gscr), + sata_pmp_gscr_vendor(gscr), + sata_pmp_gscr_devid(gscr), + sata_pmp_gscr_rev(gscr), + nr_ports, gscr[SATA_PMP_GSCR_FEAT_EN], + gscr[SATA_PMP_GSCR_FEAT]); + + if (!(dev->flags & ATA_DFLAG_AN)) + ata_dev_printk(dev, KERN_INFO, + "Asynchronous notification not supported, " + "hotplug won't\n work on fan-out " + "ports. Use warm-plug instead.\n"); + } + + return 0; + + fail: + ata_dev_printk(dev, KERN_ERR, + "failed to configure Port Multiplier (%s)\n", reason); + return rc; +} + +static int sata_pmp_init_links(struct ata_port *ap, int nr_ports) +{ + struct ata_link *pmp_link = ap->pmp_link; + int i; + + if (!pmp_link) { + pmp_link = kzalloc(sizeof(pmp_link[0]) * SATA_PMP_MAX_PORTS, + GFP_NOIO); + if (!pmp_link) + return -ENOMEM; + + for (i = 0; i < SATA_PMP_MAX_PORTS; i++) + ata_link_init(ap, &pmp_link[i], i); + + ap->pmp_link = pmp_link; + } + + for (i = 0; i < nr_ports; i++) { + struct ata_link *link = &pmp_link[i]; + struct ata_eh_context *ehc = &link->eh_context; + + link->flags = 0; + ehc->i.probe_mask |= 1; + ehc->i.action |= ATA_EH_SOFTRESET; + ehc->i.flags |= ATA_EHI_RESUME_LINK; + } + + return 0; +} + +static void sata_pmp_quirks(struct ata_port *ap) +{ + u32 *gscr = ap->link.device->gscr; + u16 vendor = sata_pmp_gscr_vendor(gscr); + u16 devid = sata_pmp_gscr_devid(gscr); + struct ata_link *link; + + if (vendor == 0x1095 && devid == 0x3726) { + /* sil3726 quirks */ + ata_port_for_each_link(link, ap) { + /* SError.N need a kick in the ass to get working */ + link->flags |= ATA_LFLAG_HRST_TO_RESUME; + + /* class code report is unreliable */ + if (link->pmp < 5) + link->flags |= ATA_LFLAG_ASSUME_ATA; + + /* port 5 is for SEMB device and it doesn't like SRST */ + if (link->pmp == 5) + link->flags |= ATA_LFLAG_NO_SRST | + ATA_LFLAG_ASSUME_SEMB; + } + } else if (vendor == 0x1095 && devid == 0x4723) { + /* sil4723 quirks */ + ata_port_for_each_link(link, ap) { + /* SError.N need a kick in the ass to get working */ + link->flags |= ATA_LFLAG_HRST_TO_RESUME; + + /* class code report is unreliable */ + if (link->pmp < 2) + link->flags |= ATA_LFLAG_ASSUME_ATA; + + /* the config device at port 2 locks up on SRST */ + if (link->pmp == 2) + link->flags |= ATA_LFLAG_NO_SRST | + ATA_LFLAG_ASSUME_ATA; + } + } else if (vendor == 0x1095 && devid == 0x4726) { + /* sil4726 quirks */ + ata_port_for_each_link(link, ap) { + /* SError.N need a kick in the ass to get working */ + link->flags |= ATA_LFLAG_HRST_TO_RESUME; + + /* class code report is unreliable */ + if (link->pmp < 5) + link->flags |= ATA_LFLAG_ASSUME_ATA; + + /* The config device, which can be either at + * port 0 or 5, locks up on SRST. + */ + if (link->pmp == 0 || link->pmp == 5) + link->flags |= ATA_LFLAG_NO_SRST | + ATA_LFLAG_ASSUME_ATA; + + /* Port 6 is for SEMB device which doesn't + * like SRST either. + */ + if (link->pmp == 6) + link->flags |= ATA_LFLAG_NO_SRST | + ATA_LFLAG_ASSUME_SEMB; + } + } else if (vendor == 0x1095 && (devid == 0x5723 || devid == 0x5733 || + devid == 0x5734 || devid == 0x5744)) { + /* sil5723/5744 quirks */ + + /* sil5723/5744 has either two or three downstream + * ports depending on operation mode. The last port + * is empty if any actual IO device is available or + * occupied by a pseudo configuration device + * otherwise. Don't try hard to recover it. + */ + ap->pmp_link[ap->nr_pmp_links - 1].flags |= ATA_LFLAG_NO_RETRY; + } else if (vendor == 0x11ab && devid == 0x4140) { + /* Marvell 88SM4140 quirks. Fan-out ports require PHY + * reset to work; other than that, it behaves very + * nicely. + */ + ata_port_for_each_link(link, ap) + link->flags |= ATA_LFLAG_HRST_TO_RESUME; + } +} + +/** + * sata_pmp_attach - attach a SATA PMP device + * @dev: SATA PMP device to attach + * + * Configure and attach SATA PMP device @dev. This function is + * also responsible for allocating and initializing PMP links. + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno on failure. + */ +int sata_pmp_attach(struct ata_device *dev) +{ + struct ata_link *link = dev->link; + struct ata_port *ap = link->ap; + unsigned long flags; + struct ata_link *tlink; + int rc; + + /* is it hanging off the right place? */ + if (!(ap->flags & ATA_FLAG_PMP)) { + ata_dev_printk(dev, KERN_ERR, + "host does not support Port Multiplier\n"); + return -EINVAL; + } + + if (!ata_is_host_link(link)) { + ata_dev_printk(dev, KERN_ERR, + "Port Multipliers cannot be nested\n"); + return -EINVAL; + } + + if (dev->devno) { + ata_dev_printk(dev, KERN_ERR, + "Port Multiplier must be the first device\n"); + return -EINVAL; + } + + WARN_ON(link->pmp != 0); + link->pmp = SATA_PMP_CTRL_PORT; + + /* read GSCR block */ + rc = sata_pmp_read_gscr(dev, dev->gscr); + if (rc) + goto fail; + + /* config PMP */ + rc = sata_pmp_configure(dev, 1); + if (rc) + goto fail; + + rc = sata_pmp_init_links(ap, sata_pmp_gscr_ports(dev->gscr)); + if (rc) { + ata_dev_printk(dev, KERN_INFO, + "failed to initialize PMP links\n"); + goto fail; + } + + /* attach it */ + spin_lock_irqsave(ap->lock, flags); + WARN_ON(ap->nr_pmp_links); + ap->nr_pmp_links = sata_pmp_gscr_ports(dev->gscr); + spin_unlock_irqrestore(ap->lock, flags); + + sata_pmp_quirks(ap); + + if (ap->ops->pmp_attach) + ap->ops->pmp_attach(ap); + + ata_port_for_each_link(tlink, ap) + sata_link_init_spd(tlink); + + return 0; + + fail: + link->pmp = 0; + return rc; +} + +/** + * sata_pmp_detach - detach a SATA PMP device + * @dev: SATA PMP device to detach + * + * Detach SATA PMP device @dev. This function is also + * responsible for deconfiguring PMP links. + * + * LOCKING: + * Kernel thread context (may sleep). + */ +static void sata_pmp_detach(struct ata_device *dev) +{ + struct ata_link *link = dev->link; + struct ata_port *ap = link->ap; + struct ata_link *tlink; + unsigned long flags; + + ata_dev_printk(dev, KERN_INFO, "Port Multiplier detaching\n"); + + WARN_ON(!ata_is_host_link(link) || dev->devno || + link->pmp != SATA_PMP_CTRL_PORT); + + if (ap->ops->pmp_detach) + ap->ops->pmp_detach(ap); + + ata_port_for_each_link(tlink, ap) + ata_eh_detach_dev(tlink->device); + + spin_lock_irqsave(ap->lock, flags); + ap->nr_pmp_links = 0; + link->pmp = 0; + spin_unlock_irqrestore(ap->lock, flags); +} + +/** + * sata_pmp_same_pmp - does new GSCR matches the configured PMP? + * @dev: PMP device to compare against + * @new_gscr: GSCR block of the new device + * + * Compare @new_gscr against @dev and determine whether @dev is + * the PMP described by @new_gscr. + * + * LOCKING: + * None. + * + * RETURNS: + * 1 if @dev matches @new_gscr, 0 otherwise. + */ +static int sata_pmp_same_pmp(struct ata_device *dev, const u32 *new_gscr) +{ + const u32 *old_gscr = dev->gscr; + u16 old_vendor, new_vendor, old_devid, new_devid; + int old_nr_ports, new_nr_ports; + + old_vendor = sata_pmp_gscr_vendor(old_gscr); + new_vendor = sata_pmp_gscr_vendor(new_gscr); + old_devid = sata_pmp_gscr_devid(old_gscr); + new_devid = sata_pmp_gscr_devid(new_gscr); + old_nr_ports = sata_pmp_gscr_ports(old_gscr); + new_nr_ports = sata_pmp_gscr_ports(new_gscr); + + if (old_vendor != new_vendor) { + ata_dev_printk(dev, KERN_INFO, "Port Multiplier " + "vendor mismatch '0x%x' != '0x%x'\n", + old_vendor, new_vendor); + return 0; + } + + if (old_devid != new_devid) { + ata_dev_printk(dev, KERN_INFO, "Port Multiplier " + "device ID mismatch '0x%x' != '0x%x'\n", + old_devid, new_devid); + return 0; + } + + if (old_nr_ports != new_nr_ports) { + ata_dev_printk(dev, KERN_INFO, "Port Multiplier " + "nr_ports mismatch '0x%x' != '0x%x'\n", + old_nr_ports, new_nr_ports); + return 0; + } + + return 1; +} + +/** + * sata_pmp_revalidate - revalidate SATA PMP + * @dev: PMP device to revalidate + * @new_class: new class code + * + * Re-read GSCR block and make sure @dev is still attached to the + * port and properly configured. + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno otherwise. + */ +static int sata_pmp_revalidate(struct ata_device *dev, unsigned int new_class) +{ + struct ata_link *link = dev->link; + struct ata_port *ap = link->ap; + u32 *gscr = (void *)ap->sector_buf; + int rc; + + DPRINTK("ENTER\n"); + + ata_eh_about_to_do(link, NULL, ATA_EH_REVALIDATE); + + if (!ata_dev_enabled(dev)) { + rc = -ENODEV; + goto fail; + } + + /* wrong class? */ + if (ata_class_enabled(new_class) && new_class != ATA_DEV_PMP) { + rc = -ENODEV; + goto fail; + } + + /* read GSCR */ + rc = sata_pmp_read_gscr(dev, gscr); + if (rc) + goto fail; + + /* is the pmp still there? */ + if (!sata_pmp_same_pmp(dev, gscr)) { + rc = -ENODEV; + goto fail; + } + + memcpy(dev->gscr, gscr, sizeof(gscr[0]) * SATA_PMP_GSCR_DWORDS); + + rc = sata_pmp_configure(dev, 0); + if (rc) + goto fail; + + ata_eh_done(link, NULL, ATA_EH_REVALIDATE); + + DPRINTK("EXIT, rc=0\n"); + return 0; + + fail: + ata_dev_printk(dev, KERN_ERR, + "PMP revalidation failed (errno=%d)\n", rc); + DPRINTK("EXIT, rc=%d\n", rc); + return rc; +} + +/** + * sata_pmp_revalidate_quick - revalidate SATA PMP quickly + * @dev: PMP device to revalidate + * + * Make sure the attached PMP is accessible. + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno otherwise. + */ +static int sata_pmp_revalidate_quick(struct ata_device *dev) +{ + u32 prod_id; + int rc; + + rc = sata_pmp_read(dev->link, SATA_PMP_GSCR_PROD_ID, &prod_id); + if (rc) { + ata_dev_printk(dev, KERN_ERR, "failed to read PMP product ID\n"); + return rc; + } + + if (prod_id != dev->gscr[SATA_PMP_GSCR_PROD_ID]) { + ata_dev_printk(dev, KERN_ERR, "PMP product ID mismatch\n"); + /* something weird is going on, request full PMP recovery */ + return -EIO; + } + + return 0; +} + +/** + * sata_pmp_eh_recover_pmp - recover PMP + * @ap: ATA port PMP is attached to + * @prereset: prereset method (can be NULL) + * @softreset: softreset method + * @hardreset: hardreset method + * @postreset: postreset method (can be NULL) + * + * Recover PMP attached to @ap. Recovery procedure is somewhat + * similar to that of ata_eh_recover() except that reset should + * always be performed in hard->soft sequence and recovery + * failure results in PMP detachment. + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno on failure. + */ +static int sata_pmp_eh_recover_pmp(struct ata_port *ap, + ata_prereset_fn_t prereset, ata_reset_fn_t softreset, + ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) +{ + struct ata_link *link = &ap->link; + struct ata_eh_context *ehc = &link->eh_context; + struct ata_device *dev = link->device; + int tries = ATA_EH_PMP_TRIES; + int detach = 0, rc = 0; + int reval_failed = 0; + + DPRINTK("ENTER\n"); + + if (dev->flags & ATA_DFLAG_DETACH) { + detach = 1; + goto fail; + } + + retry: + ehc->classes[0] = ATA_DEV_UNKNOWN; + + if (ehc->i.action & ATA_EH_RESET_MASK) { + struct ata_link *tlink; + + ata_eh_freeze_port(ap); + + /* reset */ + ehc->i.action = ATA_EH_HARDRESET; + rc = ata_eh_reset(link, 0, prereset, softreset, hardreset, + postreset); + if (rc) { + ata_link_printk(link, KERN_ERR, + "failed to reset PMP, giving up\n"); + goto fail; + } + + ata_eh_thaw_port(ap); + + /* PMP is reset, SErrors cannot be trusted, scan all */ + ata_port_for_each_link(tlink, ap) + ata_ehi_schedule_probe(&tlink->eh_context.i); + } + + /* If revalidation is requested, revalidate and reconfigure; + * otherwise, do quick revalidation. + */ + if (ehc->i.action & ATA_EH_REVALIDATE) + rc = sata_pmp_revalidate(dev, ehc->classes[0]); + else + rc = sata_pmp_revalidate_quick(dev); + + if (rc) { + tries--; + + if (rc == -ENODEV) { + ehc->i.probe_mask |= 1; + detach = 1; + /* give it just two more chances */ + tries = min(tries, 2); + } + + if (tries) { + int sleep = ehc->i.flags & ATA_EHI_DID_RESET; + + /* consecutive revalidation failures? speed down */ + if (reval_failed) + sata_down_spd_limit(link); + else + reval_failed = 1; + + ata_dev_printk(dev, KERN_WARNING, + "retrying hardreset%s\n", + sleep ? " in 5 secs" : ""); + if (sleep) + ssleep(5); + ehc->i.action |= ATA_EH_HARDRESET; + goto retry; + } else { + ata_dev_printk(dev, KERN_ERR, "failed to recover PMP " + "after %d tries, giving up\n", + ATA_EH_PMP_TRIES); + goto fail; + } + } + + /* okay, PMP resurrected */ + ehc->i.flags = 0; + + DPRINTK("EXIT, rc=0\n"); + return 0; + + fail: + sata_pmp_detach(dev); + if (detach) + ata_eh_detach_dev(dev); + else + ata_dev_disable(dev); + + DPRINTK("EXIT, rc=%d\n", rc); + return rc; +} + +static int sata_pmp_eh_handle_disabled_links(struct ata_port *ap) +{ + struct ata_link *link; + unsigned long flags; + int rc; + + spin_lock_irqsave(ap->lock, flags); + + ata_port_for_each_link(link, ap) { + if (!(link->flags & ATA_LFLAG_DISABLED)) + continue; + + spin_unlock_irqrestore(ap->lock, flags); + + /* Some PMPs require hardreset sequence to get + * SError.N working. + */ + if ((link->flags & ATA_LFLAG_HRST_TO_RESUME) && + (link->eh_context.i.flags & ATA_EHI_RESUME_LINK)) + sata_link_hardreset(link, sata_deb_timing_normal, + jiffies + ATA_TMOUT_INTERNAL_QUICK); + + /* unconditionally clear SError.N */ + rc = sata_scr_write(link, SCR_ERROR, SERR_PHYRDY_CHG); + if (rc) { + ata_link_printk(link, KERN_ERR, "failed to clear " + "SError.N (errno=%d)\n", rc); + return rc; + } + + spin_lock_irqsave(ap->lock, flags); + } + + spin_unlock_irqrestore(ap->lock, flags); + + return 0; +} + +static int sata_pmp_handle_link_fail(struct ata_link *link, int *link_tries) +{ + struct ata_port *ap = link->ap; + unsigned long flags; + + if (link_tries[link->pmp] && --link_tries[link->pmp]) + return 1; + + /* disable this link */ + if (!(link->flags & ATA_LFLAG_DISABLED)) { + ata_link_printk(link, KERN_WARNING, + "failed to recover link after %d tries, disabling\n", + ATA_EH_PMP_LINK_TRIES); + + spin_lock_irqsave(ap->lock, flags); + link->flags |= ATA_LFLAG_DISABLED; + spin_unlock_irqrestore(ap->lock, flags); + } + + ata_dev_disable(link->device); + link->eh_context.i.action = 0; + + return 0; +} + +/** + * sata_pmp_eh_recover - recover PMP-enabled port + * @ap: ATA port to recover + * @prereset: prereset method (can be NULL) + * @softreset: softreset method + * @hardreset: hardreset method + * @postreset: postreset method (can be NULL) + * @pmp_prereset: PMP prereset method (can be NULL) + * @pmp_softreset: PMP softreset method (can be NULL) + * @pmp_hardreset: PMP hardreset method (can be NULL) + * @pmp_postreset: PMP postreset method (can be NULL) + * + * Drive EH recovery operation for PMP enabled port @ap. This + * function recovers host and PMP ports with proper retrials and + * fallbacks. Actual recovery operations are performed using + * ata_eh_recover() and sata_pmp_eh_recover_pmp(). + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno on failure. + */ +static int sata_pmp_eh_recover(struct ata_port *ap, + ata_prereset_fn_t prereset, ata_reset_fn_t softreset, + ata_reset_fn_t hardreset, ata_postreset_fn_t postreset, + ata_prereset_fn_t pmp_prereset, ata_reset_fn_t pmp_softreset, + ata_reset_fn_t pmp_hardreset, ata_postreset_fn_t pmp_postreset) +{ + int pmp_tries, link_tries[SATA_PMP_MAX_PORTS]; + struct ata_link *pmp_link = &ap->link; + struct ata_device *pmp_dev = pmp_link->device; + struct ata_eh_context *pmp_ehc = &pmp_link->eh_context; + struct ata_link *link; + struct ata_device *dev; + u32 gscr_error, sntf; + int cnt, rc; + + pmp_tries = ATA_EH_PMP_TRIES; + ata_port_for_each_link(link, ap) + link_tries[link->pmp] = ATA_EH_PMP_LINK_TRIES; + + retry: + /* PMP attached? */ + if (!ap->nr_pmp_links) { + rc = ata_eh_recover(ap, prereset, softreset, hardreset, + postreset, NULL); + if (rc) { + ata_link_for_each_dev(dev, &ap->link) + ata_dev_disable(dev); + return rc; + } + + if (pmp_dev->class != ATA_DEV_PMP) + return 0; + + /* new PMP online */ + ata_port_for_each_link(link, ap) + link_tries[link->pmp] = ATA_EH_PMP_LINK_TRIES; + + /* fall through */ + } + + /* recover pmp */ + rc = sata_pmp_eh_recover_pmp(ap, prereset, softreset, hardreset, + postreset); + if (rc) + goto pmp_fail; + + /* handle disabled links */ + rc = sata_pmp_eh_handle_disabled_links(ap); + if (rc) + goto pmp_fail; + + /* recover links */ + rc = ata_eh_recover(ap, pmp_prereset, pmp_softreset, pmp_hardreset, + pmp_postreset, &link); + if (rc) + goto link_fail; + + /* Connection status might have changed while resetting other + * links, check SATA_PMP_GSCR_ERROR before returning. + */ + + /* clear SNotification */ + rc = sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf); + if (rc == 0) + sata_scr_write(&ap->link, SCR_NOTIFICATION, sntf); + + /* enable notification */ + if (pmp_dev->flags & ATA_DFLAG_AN) { + pmp_dev->gscr[SATA_PMP_GSCR_FEAT_EN] |= SATA_PMP_FEAT_NOTIFY; + + rc = sata_pmp_write(pmp_dev->link, SATA_PMP_GSCR_FEAT_EN, + pmp_dev->gscr[SATA_PMP_GSCR_FEAT_EN]); + if (rc) { + ata_dev_printk(pmp_dev, KERN_ERR, + "failed to write PMP_FEAT_EN\n"); + goto pmp_fail; + } + } + + /* check GSCR_ERROR */ + rc = sata_pmp_read(pmp_link, SATA_PMP_GSCR_ERROR, &gscr_error); + if (rc) { + ata_dev_printk(pmp_dev, KERN_ERR, + "failed to read PMP_GSCR_ERROR\n"); + goto pmp_fail; + } + + cnt = 0; + ata_port_for_each_link(link, ap) { + if (!(gscr_error & (1 << link->pmp))) + continue; + + if (sata_pmp_handle_link_fail(link, link_tries)) { + ata_ehi_hotplugged(&link->eh_context.i); + cnt++; + } else { + ata_link_printk(link, KERN_WARNING, + "PHY status changed but maxed out on retries, " + "giving up\n"); + ata_link_printk(link, KERN_WARNING, + "Manully issue scan to resume this link\n"); + } + } + + if (cnt) { + ata_port_printk(ap, KERN_INFO, "PMP SError.N set for some " + "ports, repeating recovery\n"); + goto retry; + } + + return 0; + + link_fail: + if (sata_pmp_handle_link_fail(link, link_tries)) { + pmp_ehc->i.action |= ATA_EH_HARDRESET; + goto retry; + } + + /* fall through */ + pmp_fail: + /* Control always ends up here after detaching PMP. Shut up + * and return if we're unloading. + */ + if (ap->pflags & ATA_PFLAG_UNLOADING) + return rc; + + if (!ap->nr_pmp_links) + goto retry; + + if (--pmp_tries) { + ata_port_printk(ap, KERN_WARNING, + "failed to recover PMP, retrying in 5 secs\n"); + pmp_ehc->i.action |= ATA_EH_HARDRESET; + ssleep(5); + goto retry; + } + + ata_port_printk(ap, KERN_ERR, + "failed to recover PMP after %d tries, giving up\n", + ATA_EH_PMP_TRIES); + sata_pmp_detach(pmp_dev); + ata_dev_disable(pmp_dev); + + return rc; +} + +/** + * sata_pmp_do_eh - do standard error handling for PMP-enabled host + * @ap: host port to handle error for + * @prereset: prereset method (can be NULL) + * @softreset: softreset method + * @hardreset: hardreset method + * @postreset: postreset method (can be NULL) + * @pmp_prereset: PMP prereset method (can be NULL) + * @pmp_softreset: PMP softreset method (can be NULL) + * @pmp_hardreset: PMP hardreset method (can be NULL) + * @pmp_postreset: PMP postreset method (can be NULL) + * + * Perform standard error handling sequence for PMP-enabled host + * @ap. + * + * LOCKING: + * Kernel thread context (may sleep). + */ +void sata_pmp_do_eh(struct ata_port *ap, + ata_prereset_fn_t prereset, ata_reset_fn_t softreset, + ata_reset_fn_t hardreset, ata_postreset_fn_t postreset, + ata_prereset_fn_t pmp_prereset, ata_reset_fn_t pmp_softreset, + ata_reset_fn_t pmp_hardreset, ata_postreset_fn_t pmp_postreset) +{ + ata_eh_autopsy(ap); + ata_eh_report(ap); + sata_pmp_eh_recover(ap, prereset, softreset, hardreset, postreset, + pmp_prereset, pmp_softreset, pmp_hardreset, + pmp_postreset); + ata_eh_finish(ap); +} diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index ebe22982e80..a9b9c9e1e10 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -153,6 +153,11 @@ extern void ata_schedule_scsi_eh(struct Scsi_Host *shost); extern void ata_scsi_dev_rescan(struct work_struct *work); extern int ata_bus_probe(struct ata_port *ap); +/* libata-pmp.c */ +extern int sata_pmp_scr_read(struct ata_link *link, int reg, u32 *val); +extern int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val); +extern int sata_pmp_attach(struct ata_device *dev); + /* libata-eh.c */ extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd); extern void ata_scsi_error(struct Scsi_Host *host); diff --git a/include/linux/libata.h b/include/linux/libata.h index f9ed198e4fc..3cfdb5f6762 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -944,6 +944,25 @@ extern int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bit extern unsigned long ata_pci_default_filter(struct ata_device *, unsigned long); #endif /* CONFIG_PCI */ +/* + * PMP + */ +extern void sata_pmp_read_init_tf(struct ata_taskfile *tf, + struct ata_device *dev, int pmp, int reg); +extern u32 sata_pmp_read_val(const struct ata_taskfile *tf); +extern void sata_pmp_write_init_tf(struct ata_taskfile *tf, + struct ata_device *dev, + int pmp, int reg, u32 val); +extern int sata_pmp_std_prereset(struct ata_link *link, unsigned long deadline); +extern int sata_pmp_std_hardreset(struct ata_link *link, unsigned int *class, + unsigned long deadline); +extern void sata_pmp_std_postreset(struct ata_link *link, unsigned int *class); +extern void sata_pmp_do_eh(struct ata_port *ap, + ata_prereset_fn_t prereset, ata_reset_fn_t softreset, + ata_reset_fn_t hardreset, ata_postreset_fn_t postreset, + ata_prereset_fn_t pmp_prereset, ata_reset_fn_t pmp_softreset, + ata_reset_fn_t pmp_hardreset, ata_postreset_fn_t pmp_postreset); + /* * EH */ -- cgit v1.2.3-70-g09d2 From 633273a3ed1cf37ced90475b0f95cf81deab04f1 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 23 Sep 2007 13:19:54 +0900 Subject: libata-pmp: hook PMP support and enable it Hook PMP support into libata and enable it. Connect SCR and probing functions, and update ata_dev_classify() to detect PMP. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 111 +++++++++++++++++++++++++++++++++------------- drivers/ata/libata-eh.c | 18 ++++++-- drivers/ata/libata.h | 2 +- 3 files changed, 96 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 9e7f55b7104..d3e78d97529 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -670,29 +670,49 @@ static unsigned int ata_devchk(struct ata_port *ap, unsigned int device) * None. * * RETURNS: - * Device type, %ATA_DEV_ATA, %ATA_DEV_ATAPI, or %ATA_DEV_UNKNOWN - * the event of failure. + * Device type, %ATA_DEV_ATA, %ATA_DEV_ATAPI, %ATA_DEV_PMP or + * %ATA_DEV_UNKNOWN the event of failure. */ - unsigned int ata_dev_classify(const struct ata_taskfile *tf) { /* Apple's open source Darwin code hints that some devices only * put a proper signature into the LBA mid/high registers, * So, we only check those. It's sufficient for uniqueness. + * + * ATA/ATAPI-7 (d1532v1r1: Feb. 19, 2003) specified separate + * signatures for ATA and ATAPI devices attached on SerialATA, + * 0x3c/0xc3 and 0x69/0x96 respectively. However, SerialATA + * spec has never mentioned about using different signatures + * for ATA/ATAPI devices. Then, Serial ATA II: Port + * Multiplier specification began to use 0x69/0x96 to identify + * port multpliers and 0x3c/0xc3 to identify SEMB device. + * ATA/ATAPI-7 dropped descriptions about 0x3c/0xc3 and + * 0x69/0x96 shortly and described them as reserved for + * SerialATA. + * + * We follow the current spec and consider that 0x69/0x96 + * identifies a port multiplier and 0x3c/0xc3 a SEMB device. */ - - if (((tf->lbam == 0) && (tf->lbah == 0)) || - ((tf->lbam == 0x3c) && (tf->lbah == 0xc3))) { + if ((tf->lbam == 0) && (tf->lbah == 0)) { DPRINTK("found ATA device by sig\n"); return ATA_DEV_ATA; } - if (((tf->lbam == 0x14) && (tf->lbah == 0xeb)) || - ((tf->lbam == 0x69) && (tf->lbah == 0x96))) { + if ((tf->lbam == 0x14) && (tf->lbah == 0xeb)) { DPRINTK("found ATAPI device by sig\n"); return ATA_DEV_ATAPI; } + if ((tf->lbam == 0x69) && (tf->lbah == 0x96)) { + DPRINTK("found PMP device by sig\n"); + return ATA_DEV_PMP; + } + + if ((tf->lbam == 0x3c) && (tf->lbah == 0xc3)) { + printk("ata: SEMB device ignored\n"); + return ATA_DEV_SEMB_UNSUP; /* not yet */ + } + DPRINTK("unknown device\n"); return ATA_DEV_UNKNOWN; } @@ -3426,6 +3446,12 @@ int ata_std_prereset(struct ata_link *link, unsigned long deadline) (link->flags & ATA_LFLAG_HRST_TO_RESUME)) ehc->i.action |= ATA_EH_HARDRESET; + /* Some PMPs don't work with only SRST, force hardreset if PMP + * is supported. + */ + if (ap->flags & ATA_FLAG_PMP) + ehc->i.action |= ATA_EH_HARDRESET; + /* if we're about to do hardreset, nothing more to do */ if (ehc->i.action & ATA_EH_HARDRESET) return 0; @@ -3616,6 +3642,16 @@ int sata_std_hardreset(struct ata_link *link, unsigned int *class, /* wait a while before checking status, see SRST for more info */ msleep(150); + /* If PMP is supported, we have to do follow-up SRST. Note + * that some PMPs don't send D2H Reg FIS after hardreset at + * all if the first port is empty. Wait for it just for a + * second and request follow-up SRST. + */ + if (ap->flags & ATA_FLAG_PMP) { + ata_wait_ready(ap, jiffies + HZ); + return -EAGAIN; + } + rc = ata_wait_ready(ap, deadline); /* link occupied, -ENODEV too is an error */ if (rc) { @@ -5966,22 +6002,26 @@ int sata_scr_valid(struct ata_link *link) * @val: Place to store read value * * Read SCR register @reg of @link into *@val. This function is - * guaranteed to succeed if the cable type of the port is SATA - * and the port implements ->scr_read. + * guaranteed to succeed if @link is ap->link, the cable type of + * the port is SATA and the port implements ->scr_read. * * LOCKING: - * None. + * None if @link is ap->link. Kernel thread context otherwise. * * RETURNS: * 0 on success, negative errno on failure. */ int sata_scr_read(struct ata_link *link, int reg, u32 *val) { - struct ata_port *ap = link->ap; + if (ata_is_host_link(link)) { + struct ata_port *ap = link->ap; - if (sata_scr_valid(link)) - return ap->ops->scr_read(ap, reg, val); - return -EOPNOTSUPP; + if (sata_scr_valid(link)) + return ap->ops->scr_read(ap, reg, val); + return -EOPNOTSUPP; + } + + return sata_pmp_scr_read(link, reg, val); } /** @@ -5991,22 +6031,26 @@ int sata_scr_read(struct ata_link *link, int reg, u32 *val) * @val: value to write * * Write @val to SCR register @reg of @link. This function is - * guaranteed to succeed if the cable type of the port is SATA - * and the port implements ->scr_read. + * guaranteed to succeed if @link is ap->link, the cable type of + * the port is SATA and the port implements ->scr_read. * * LOCKING: - * None. + * None if @link is ap->link. Kernel thread context otherwise. * * RETURNS: * 0 on success, negative errno on failure. */ int sata_scr_write(struct ata_link *link, int reg, u32 val) { - struct ata_port *ap = link->ap; + if (ata_is_host_link(link)) { + struct ata_port *ap = link->ap; - if (sata_scr_valid(link)) - return ap->ops->scr_write(ap, reg, val); - return -EOPNOTSUPP; + if (sata_scr_valid(link)) + return ap->ops->scr_write(ap, reg, val); + return -EOPNOTSUPP; + } + + return sata_pmp_scr_write(link, reg, val); } /** @@ -6019,23 +6063,27 @@ int sata_scr_write(struct ata_link *link, int reg, u32 val) * function performs flush after writing to the register. * * LOCKING: - * None. + * None if @link is ap->link. Kernel thread context otherwise. * * RETURNS: * 0 on success, negative errno on failure. */ int sata_scr_write_flush(struct ata_link *link, int reg, u32 val) { - struct ata_port *ap = link->ap; - int rc; + if (ata_is_host_link(link)) { + struct ata_port *ap = link->ap; + int rc; - if (sata_scr_valid(link)) { - rc = ap->ops->scr_write(ap, reg, val); - if (rc == 0) - rc = ap->ops->scr_read(ap, reg, &val); - return rc; + if (sata_scr_valid(link)) { + rc = ap->ops->scr_write(ap, reg, val); + if (rc == 0) + rc = ap->ops->scr_read(ap, reg, &val); + return rc; + } + return -EOPNOTSUPP; } - return -EOPNOTSUPP; + + return sata_pmp_scr_write(link, reg, val); } /** @@ -6424,6 +6472,7 @@ static void ata_host_release(struct device *gendev, void *res) if (ap->scsi_host) scsi_host_put(ap->scsi_host); + kfree(ap->pmp_link); kfree(ap); host->ports[i] = NULL; } diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 687419b6670..5f2c0f376f7 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -2209,6 +2209,8 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link, readid_flags |= ATA_READID_POSTRESET; if ((action & ATA_EH_REVALIDATE) && ata_dev_enabled(dev)) { + WARN_ON(dev->class == ATA_DEV_PMP); + if (ata_link_offline(link)) { rc = -EIO; goto err; @@ -2234,8 +2236,11 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link, ata_class_enabled(ehc->classes[dev->devno])) { dev->class = ehc->classes[dev->devno]; - rc = ata_dev_read_id(dev, &dev->class, readid_flags, - dev->id); + if (dev->class == ATA_DEV_PMP) + rc = sata_pmp_attach(dev); + else + rc = ata_dev_read_id(dev, &dev->class, + readid_flags, dev->id); switch (rc) { case 0: new_mask |= 1 << dev->devno; @@ -2264,7 +2269,8 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link, * device detection messages backwards. */ ata_link_for_each_dev(dev, link) { - if (!(new_mask & (1 << dev->devno))) + if (!(new_mask & (1 << dev->devno)) || + dev->class == ATA_DEV_PMP) continue; ehc->i.flags |= ATA_EHI_PRINTINFO; @@ -2521,6 +2527,12 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, if (rc) goto dev_fail; + /* if PMP got attached, return, pmp EH will take care of it */ + if (link->device->class == ATA_DEV_PMP) { + ehc->i.action = 0; + return 0; + } + /* configure transfer mode if necessary */ if (ehc->i.flags & ATA_EHI_SETMODE) { rc = ata_set_mode(link, &dev); diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index a9b9c9e1e10..a44172fd1f5 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -29,7 +29,7 @@ #define __LIBATA_H__ #define DRV_NAME "libata" -#define DRV_VERSION "2.21" /* must be exactly four chars */ +#define DRV_VERSION "3.00" /* must be exactly four chars */ struct ata_scsi_args { struct ata_device *dev; -- cgit v1.2.3-70-g09d2 From d0df8b5d0fb547a3351c2a4b1ded7f7cde5d713a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 23 Sep 2007 13:19:54 +0900 Subject: libata-pmp: extend ACPI support to cover PMP Extend ata_acpi_associate_sata_port() such that it can handle PMP and call it when PMP is attached and detached. Build breakage when !CONFIG_ATA_ACPI was spotted and fixed by Petr Vandrovec. Signed-off-by: Tejun Heo Cc: Petr Vandrovec Signed-off-by: Jeff Garzik --- drivers/ata/libata-acpi.c | 36 ++++++++++++++++++++++++++++++++---- drivers/ata/libata-pmp.c | 4 ++++ drivers/ata/libata.h | 2 ++ 3 files changed, 38 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index dc9842ec6f0..a276c06dda9 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -40,12 +40,40 @@ static int is_pci_dev(struct device *dev) return (dev->bus == &pci_bus_type); } -static void ata_acpi_associate_sata_port(struct ata_port *ap) +/** + * ata_acpi_associate_sata_port - associate SATA port with ACPI objects + * @ap: target SATA port + * + * Look up ACPI objects associated with @ap and initialize acpi_handle + * fields of @ap, the port and devices accordingly. + * + * LOCKING: + * EH context. + * + * RETURNS: + * 0 on success, -errno on failure. + */ +void ata_acpi_associate_sata_port(struct ata_port *ap) { - acpi_integer adr = SATA_ADR(ap->port_no, NO_PORT_MULT); + WARN_ON(!(ap->flags & ATA_FLAG_ACPI_SATA)); + + if (!ap->nr_pmp_links) { + acpi_integer adr = SATA_ADR(ap->port_no, NO_PORT_MULT); + + ap->link.device->acpi_handle = + acpi_get_child(ap->host->acpi_handle, adr); + } else { + struct ata_link *link; + + ap->link.device->acpi_handle = NULL; - ap->link.device->acpi_handle = - acpi_get_child(ap->host->acpi_handle, adr); + ata_port_for_each_link(link, ap) { + acpi_integer adr = SATA_ADR(ap->port_no, link->pmp); + + link->device->acpi_handle = + acpi_get_child(ap->host->acpi_handle, adr); + } + } } static void ata_acpi_associate_ide_port(struct ata_port *ap) diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c index 671d171055a..eeffce636d0 100644 --- a/drivers/ata/libata-pmp.c +++ b/drivers/ata/libata-pmp.c @@ -607,6 +607,8 @@ int sata_pmp_attach(struct ata_device *dev) ata_port_for_each_link(tlink, ap) sata_link_init_spd(tlink); + ata_acpi_associate_sata_port(ap); + return 0; fail: @@ -646,6 +648,8 @@ static void sata_pmp_detach(struct ata_device *dev) ap->nr_pmp_links = 0; link->pmp = 0; spin_unlock_irqrestore(ap->lock, flags); + + ata_acpi_associate_sata_port(ap); } /** diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index a44172fd1f5..f8bd955c5ba 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -103,11 +103,13 @@ extern struct ata_port *ata_port_alloc(struct ata_host *host); /* libata-acpi.c */ #ifdef CONFIG_ATA_ACPI +extern void ata_acpi_associate_sata_port(struct ata_port *ap); extern void ata_acpi_associate(struct ata_host *host); extern int ata_acpi_on_suspend(struct ata_port *ap); extern void ata_acpi_on_resume(struct ata_port *ap); extern int ata_acpi_on_devcfg(struct ata_device *adev); #else +static inline void ata_acpi_associate_sata_port(struct ata_port *ap) { } static inline void ata_acpi_associate(struct ata_host *host) { } static inline int ata_acpi_on_suspend(struct ata_port *ap) { return 0; } static inline void ata_acpi_on_resume(struct ata_port *ap) { } -- cgit v1.2.3-70-g09d2 From 31f88384443b3e0d7e2c9d36a96647b7e82edad3 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 23 Sep 2007 13:19:54 +0900 Subject: libata-pmp: implement qc_defer for command switching PMP support Implement sata_pmp_qc_defer_cmd_switch() - standard qc_defer for command switching PMP support. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 1 + drivers/ata/libata-pmp.c | 30 ++++++++++++++++++++++++++++++ include/linux/libata.h | 1 + 3 files changed, 32 insertions(+) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index d3e78d97529..5532a6564d0 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -7303,6 +7303,7 @@ EXPORT_SYMBOL_GPL(ata_pci_default_filter); EXPORT_SYMBOL_GPL(ata_pci_clear_simplex); #endif /* CONFIG_PCI */ +EXPORT_SYMBOL_GPL(sata_pmp_qc_defer_cmd_switch); EXPORT_SYMBOL_GPL(sata_pmp_read_init_tf); EXPORT_SYMBOL_GPL(sata_pmp_read_val); EXPORT_SYMBOL_GPL(sata_pmp_write_init_tf); diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c index eeffce636d0..f6c4b11336e 100644 --- a/drivers/ata/libata-pmp.c +++ b/drivers/ata/libata-pmp.c @@ -69,6 +69,36 @@ static int sata_pmp_write(struct ata_link *link, int reg, u32 val) return rc; } +/** + * sata_pmp_qc_defer_cmd_switch - qc_defer for command switching PMP + * @qc: ATA command in question + * + * A host which has command switching PMP support cannot issue + * commands to multiple links simultaneously. + * + * LOCKING: + * spin_lock_irqsave(host lock) + * + * RETURNS: + * ATA_DEFER_* if deferring is needed, 0 otherwise. + */ +int sata_pmp_qc_defer_cmd_switch(struct ata_queued_cmd *qc) +{ + struct ata_link *link = qc->dev->link; + struct ata_port *ap = link->ap; + + if (ap->excl_link == NULL || ap->excl_link == link) { + if (ap->nr_active_links == 0 || ata_link_active(link)) { + qc->flags |= ATA_QCFLAG_CLEAR_EXCL; + return ata_std_qc_defer(qc); + } + + ap->excl_link = link; + } + + return ATA_DEFER_PORT; +} + /** * sata_pmp_read_init_tf - initialize TF for PMP read * @tf: taskfile to initialize diff --git a/include/linux/libata.h b/include/linux/libata.h index 3cfdb5f6762..ca296a575c4 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -947,6 +947,7 @@ extern unsigned long ata_pci_default_filter(struct ata_device *, unsigned long); /* * PMP */ +extern int sata_pmp_qc_defer_cmd_switch(struct ata_queued_cmd *qc); extern void sata_pmp_read_init_tf(struct ata_taskfile *tf, struct ata_device *dev, int pmp, int reg); extern u32 sata_pmp_read_val(const struct ata_taskfile *tf); -- cgit v1.2.3-70-g09d2 From 3454dc6922dc550c0d3ccf292c4e227403b10b6e Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 23 Sep 2007 13:19:54 +0900 Subject: sata_sil24: implement PMP support Implement PMP support. sil24 supports full FIS-switching. However, it has a PMP DMA CS errata which requires port-wide resetting if commands are outstanding to three or more devices when an error occurs on one of them. ATAPI commands often result in CHECK SENSE and it's crucial to not reset them before fetching sense data. Unfortunately, ATAPI CHECK SENSE causes a lot of problem if command is outstanding to any other device usually resulting in port-wide reset. So, sata_sil24 implements sil24_qc_defer() which guarantees ATAPI command is run by itself. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/sata_sil24.c | 227 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 206 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index b4f81eb8bbb..03bfbb65c53 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -30,7 +30,7 @@ #include #define DRV_NAME "sata_sil24" -#define DRV_VERSION "1.0" +#define DRV_VERSION "1.1" /* * Port request block (PRB) 32 bytes @@ -238,7 +238,7 @@ enum { SIL24_COMMON_FLAGS = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | ATA_FLAG_NCQ | ATA_FLAG_ACPI_SATA | - ATA_FLAG_AN, + ATA_FLAG_AN | ATA_FLAG_PMP, SIL24_COMMON_LFLAGS = ATA_LFLAG_SKIP_D2H_BSY, SIL24_FLAG_PCIX_IRQ_WOC = (1 << 24), /* IRQ loss errata on PCI-X */ @@ -330,9 +330,14 @@ static u8 sil24_check_status(struct ata_port *ap); static int sil24_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val); static int sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val); static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf); +static int sil24_qc_defer(struct ata_queued_cmd *qc); static void sil24_qc_prep(struct ata_queued_cmd *qc); static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc); static void sil24_irq_clear(struct ata_port *ap); +static void sil24_pmp_attach(struct ata_port *ap); +static void sil24_pmp_detach(struct ata_port *ap); +static int sil24_pmp_read(struct ata_device *dev, int pmp, int reg, u32 *r_val); +static int sil24_pmp_write(struct ata_device *dev, int pmp, int reg, u32 val); static void sil24_freeze(struct ata_port *ap); static void sil24_thaw(struct ata_port *ap); static void sil24_error_handler(struct ata_port *ap); @@ -341,6 +346,7 @@ static int sil24_port_start(struct ata_port *ap); static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); #ifdef CONFIG_PM static int sil24_pci_device_resume(struct pci_dev *pdev); +static int sil24_port_resume(struct ata_port *ap); #endif static const struct pci_device_id sil24_pci_tbl[] = { @@ -393,7 +399,7 @@ static const struct ata_port_operations sil24_ops = { .tf_read = sil24_tf_read, - .qc_defer = ata_std_qc_defer, + .qc_defer = sil24_qc_defer, .qc_prep = sil24_qc_prep, .qc_issue = sil24_qc_issue, @@ -402,12 +408,21 @@ static const struct ata_port_operations sil24_ops = { .scr_read = sil24_scr_read, .scr_write = sil24_scr_write, + .pmp_attach = sil24_pmp_attach, + .pmp_detach = sil24_pmp_detach, + .pmp_read = sil24_pmp_read, + .pmp_write = sil24_pmp_write, + .freeze = sil24_freeze, .thaw = sil24_thaw, .error_handler = sil24_error_handler, .post_internal_cmd = sil24_post_internal_cmd, .port_start = sil24_port_start, + +#ifdef CONFIG_PM + .port_resume = sil24_port_resume, +#endif }; /* @@ -521,11 +536,40 @@ static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf) *tf = pp->tf; } +static void sil24_config_pmp(struct ata_port *ap, int attached) +{ + void __iomem *port = ap->ioaddr.cmd_addr; + + if (attached) + writel(PORT_CS_PMP_EN, port + PORT_CTRL_STAT); + else + writel(PORT_CS_PMP_EN, port + PORT_CTRL_CLR); +} + +static void sil24_clear_pmp(struct ata_port *ap) +{ + void __iomem *port = ap->ioaddr.cmd_addr; + int i; + + writel(PORT_CS_PMP_RESUME, port + PORT_CTRL_CLR); + + for (i = 0; i < SATA_PMP_MAX_PORTS; i++) { + void __iomem *pmp_base = port + PORT_PMP + i * PORT_PMP_SIZE; + + writel(0, pmp_base + PORT_PMP_STATUS); + writel(0, pmp_base + PORT_PMP_QACTIVE); + } +} + static int sil24_init_port(struct ata_port *ap) { void __iomem *port = ap->ioaddr.cmd_addr; u32 tmp; + /* clear PMP error status */ + if (ap->nr_pmp_links) + sil24_clear_pmp(ap); + writel(PORT_CS_INIT, port + PORT_CTRL_STAT); ata_wait_register(port + PORT_CTRL_STAT, PORT_CS_INIT, PORT_CS_INIT, 10, 100); @@ -640,7 +684,7 @@ static int sil24_do_softreset(struct ata_link *link, unsigned int *class, static int sil24_softreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { - return sil24_do_softreset(link, class, 0, deadline); + return sil24_do_softreset(link, class, SATA_PMP_CTRL_PORT, deadline); } static int sil24_hardreset(struct ata_link *link, unsigned int *class, @@ -708,6 +752,38 @@ static inline void sil24_fill_sg(struct ata_queued_cmd *qc, } } +static int sil24_qc_defer(struct ata_queued_cmd *qc) +{ + struct ata_link *link = qc->dev->link; + struct ata_port *ap = link->ap; + u8 prot = qc->tf.protocol; + int is_atapi = (prot == ATA_PROT_ATAPI || + prot == ATA_PROT_ATAPI_NODATA || + prot == ATA_PROT_ATAPI_DMA); + + /* ATAPI commands completing with CHECK_SENSE cause various + * weird problems if other commands are active. PMP DMA CS + * errata doesn't cover all and HSM violation occurs even with + * only one other device active. Always run an ATAPI command + * by itself. + */ + if (unlikely(ap->excl_link)) { + if (link == ap->excl_link) { + if (ap->nr_active_links) + return ATA_DEFER_PORT; + qc->flags |= ATA_QCFLAG_CLEAR_EXCL; + } else + return ATA_DEFER_PORT; + } else if (unlikely(is_atapi)) { + ap->excl_link = link; + if (ap->nr_active_links) + return ATA_DEFER_PORT; + qc->flags |= ATA_QCFLAG_CLEAR_EXCL; + } + + return ata_std_qc_defer(qc); +} + static void sil24_qc_prep(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; @@ -751,7 +827,7 @@ static void sil24_qc_prep(struct ata_queued_cmd *qc) } prb->ctrl = cpu_to_le16(ctrl); - ata_tf_to_fis(&qc->tf, 0, 1, prb->fis); + ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, prb->fis); if (qc->flags & ATA_QCFLAG_DMAMAP) sil24_fill_sg(qc, sge); @@ -780,6 +856,65 @@ static void sil24_irq_clear(struct ata_port *ap) /* unused */ } +static void sil24_pmp_attach(struct ata_port *ap) +{ + sil24_config_pmp(ap, 1); + sil24_init_port(ap); +} + +static void sil24_pmp_detach(struct ata_port *ap) +{ + sil24_init_port(ap); + sil24_config_pmp(ap, 0); +} + +static int sil24_pmp_read(struct ata_device *dev, int pmp, int reg, u32 *r_val) +{ + struct ata_port *ap = dev->link->ap; + struct ata_taskfile tf; + int rc; + + sata_pmp_read_init_tf(&tf, dev, pmp, reg); + rc = sil24_exec_polled_cmd(ap, SATA_PMP_CTRL_PORT, &tf, 1, 0, + SATA_PMP_SCR_TIMEOUT); + if (rc == 0) { + sil24_read_tf(ap, 0, &tf); + *r_val = sata_pmp_read_val(&tf); + } + return rc; +} + +static int sil24_pmp_write(struct ata_device *dev, int pmp, int reg, u32 val) +{ + struct ata_port *ap = dev->link->ap; + struct ata_taskfile tf; + + sata_pmp_write_init_tf(&tf, dev, pmp, reg, val); + return sil24_exec_polled_cmd(ap, SATA_PMP_CTRL_PORT, &tf, 1, 0, + SATA_PMP_SCR_TIMEOUT); +} + +static int sil24_pmp_softreset(struct ata_link *link, unsigned int *class, + unsigned long deadline) +{ + return sil24_do_softreset(link, class, link->pmp, deadline); +} + +static int sil24_pmp_hardreset(struct ata_link *link, unsigned int *class, + unsigned long deadline) +{ + int rc; + + rc = sil24_init_port(link->ap); + if (rc) { + ata_link_printk(link, KERN_ERR, + "hardreset failed (port not ready)\n"); + return rc; + } + + return sata_pmp_std_hardreset(link, class, deadline); +} + static void sil24_freeze(struct ata_port *ap) { void __iomem *port = ap->ioaddr.cmd_addr; @@ -807,8 +942,10 @@ static void sil24_error_intr(struct ata_port *ap) { void __iomem *port = ap->ioaddr.cmd_addr; struct sil24_port_priv *pp = ap->private_data; - struct ata_eh_info *ehi = &ap->link.eh_info; - int freeze = 0; + struct ata_queued_cmd *qc = NULL; + struct ata_link *link; + struct ata_eh_info *ehi; + int abort = 0, freeze = 0; u32 irq_stat; /* on error, we need to clear IRQ explicitly */ @@ -816,6 +953,8 @@ static void sil24_error_intr(struct ata_port *ap) writel(irq_stat, port + PORT_IRQ_STAT); /* first, analyze and record host port events */ + link = &ap->link; + ehi = &link->eh_info; ata_ehi_clear_desc(ehi); ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat); @@ -844,8 +983,43 @@ static void sil24_error_intr(struct ata_port *ap) if (irq_stat & PORT_IRQ_ERROR) { struct sil24_cerr_info *ci = NULL; unsigned int err_mask = 0, action = 0; - struct ata_queued_cmd *qc; - u32 cerr; + u32 context, cerr; + int pmp; + + abort = 1; + + /* DMA Context Switch Failure in Port Multiplier Mode + * errata. If we have active commands to 3 or more + * devices, any error condition on active devices can + * corrupt DMA context switching. + */ + if (ap->nr_active_links >= 3) { + ehi->err_mask |= AC_ERR_OTHER; + ehi->action |= ATA_EH_HARDRESET; + ata_ehi_push_desc(ehi, "PMP DMA CS errata"); + freeze = 1; + } + + /* find out the offending link and qc */ + if (ap->nr_pmp_links) { + context = readl(port + PORT_CONTEXT); + pmp = (context >> 5) & 0xf; + + if (pmp < ap->nr_pmp_links) { + link = &ap->pmp_link[pmp]; + ehi = &link->eh_info; + qc = ata_qc_from_tag(ap, link->active_tag); + + ata_ehi_clear_desc(ehi); + ata_ehi_push_desc(ehi, "irq_stat 0x%08x", + irq_stat); + } else { + err_mask |= AC_ERR_HSM; + action |= ATA_EH_HARDRESET; + freeze = 1; + } + } else + qc = ata_qc_from_tag(ap, link->active_tag); /* analyze CMD_ERR */ cerr = readl(port + PORT_CMD_ERR); @@ -864,7 +1038,6 @@ static void sil24_error_intr(struct ata_port *ap) } /* record error info */ - qc = ata_qc_from_tag(ap, ap->link.active_tag); if (qc) { sil24_read_tf(ap, qc->tag, &pp->tf); qc->err_mask |= err_mask; @@ -872,13 +1045,21 @@ static void sil24_error_intr(struct ata_port *ap) ehi->err_mask |= err_mask; ehi->action |= action; + + /* if PMP, resume */ + if (ap->nr_pmp_links) + writel(PORT_CS_PMP_RESUME, port + PORT_CTRL_STAT); } /* freeze or abort */ if (freeze) ata_port_freeze(ap); - else - ata_port_abort(ap); + else if (abort) { + if (qc) + ata_link_abort(qc->dev->link); + else + ata_port_abort(ap); + } } static void sil24_finish_qc(struct ata_queued_cmd *qc) @@ -971,16 +1152,14 @@ static irqreturn_t sil24_interrupt(int irq, void *dev_instance) static void sil24_error_handler(struct ata_port *ap) { - struct ata_eh_context *ehc = &ap->link.eh_context; - - if (sil24_init_port(ap)) { + if (sil24_init_port(ap)) ata_eh_freeze_port(ap); - ehc->i.action |= ATA_EH_HARDRESET; - } /* perform recovery */ - ata_do_eh(ap, ata_std_prereset, sil24_softreset, sil24_hardreset, - ata_std_postreset); + sata_pmp_do_eh(ap, ata_std_prereset, sil24_softreset, sil24_hardreset, + ata_std_postreset, sata_pmp_std_prereset, + sil24_pmp_softreset, sil24_pmp_hardreset, + sata_pmp_std_postreset); } static void sil24_post_internal_cmd(struct ata_queued_cmd *qc) @@ -988,8 +1167,8 @@ static void sil24_post_internal_cmd(struct ata_queued_cmd *qc) struct ata_port *ap = qc->ap; /* make DMA engine forget about the failed command */ - if (qc->flags & ATA_QCFLAG_FAILED) - sil24_init_port(ap); + if ((qc->flags & ATA_QCFLAG_FAILED) && sil24_init_port(ap)) + ata_eh_freeze_port(ap); } static int sil24_port_start(struct ata_port *ap) @@ -1190,6 +1369,12 @@ static int sil24_pci_device_resume(struct pci_dev *pdev) return 0; } + +static int sil24_port_resume(struct ata_port *ap) +{ + sil24_config_pmp(ap, ap->nr_pmp_links); + return 0; +} #endif static int __init sil24_init(void) -- cgit v1.2.3-70-g09d2 From 238180343eff95697ed71eea137cf61ba3cea6ad Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 23 Sep 2007 13:19:54 +0900 Subject: sata_sil24: implement PORT_RST As DEV_RST (hardreset) sometimes fail to recover the controller (especially after PMP DMA CS errata). In such cases, perform PORT_RST prior to DEV_RST. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/sata_sil24.c | 93 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 70 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index 03bfbb65c53..15b9a80a178 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -323,6 +323,7 @@ struct sil24_port_priv { union sil24_cmd_block *cmd_block; /* 32 cmd blocks */ dma_addr_t cmd_block_dma; /* DMA base addr for them */ struct ata_taskfile tf; /* Cached taskfile registers */ + int do_port_rst; }; static void sil24_dev_config(struct ata_device *dev); @@ -536,6 +537,31 @@ static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf) *tf = pp->tf; } +static void sil24_config_port(struct ata_port *ap) +{ + void __iomem *port = ap->ioaddr.cmd_addr; + + /* configure IRQ WoC */ + if (ap->flags & SIL24_FLAG_PCIX_IRQ_WOC) + writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT); + else + writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR); + + /* zero error counters. */ + writel(0x8000, port + PORT_DECODE_ERR_THRESH); + writel(0x8000, port + PORT_CRC_ERR_THRESH); + writel(0x8000, port + PORT_HSHK_ERR_THRESH); + writel(0x0000, port + PORT_DECODE_ERR_CNT); + writel(0x0000, port + PORT_CRC_ERR_CNT); + writel(0x0000, port + PORT_HSHK_ERR_CNT); + + /* always use 64bit activation */ + writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR); + + /* clear port multiplier enable and resume bits */ + writel(PORT_CS_PMP_EN | PORT_CS_PMP_RESUME, port + PORT_CTRL_CLR); +} + static void sil24_config_pmp(struct ata_port *ap, int attached) { void __iomem *port = ap->ioaddr.cmd_addr; @@ -564,6 +590,7 @@ static void sil24_clear_pmp(struct ata_port *ap) static int sil24_init_port(struct ata_port *ap) { void __iomem *port = ap->ioaddr.cmd_addr; + struct sil24_port_priv *pp = ap->private_data; u32 tmp; /* clear PMP error status */ @@ -576,8 +603,12 @@ static int sil24_init_port(struct ata_port *ap) tmp = ata_wait_register(port + PORT_CTRL_STAT, PORT_CS_RDY, 0, 10, 100); - if ((tmp & (PORT_CS_INIT | PORT_CS_RDY)) != PORT_CS_RDY) + if ((tmp & (PORT_CS_INIT | PORT_CS_RDY)) != PORT_CS_RDY) { + pp->do_port_rst = 1; + ap->link.eh_context.i.action |= ATA_EH_HARDRESET; return -EIO; + } + return 0; } @@ -692,10 +723,34 @@ static int sil24_hardreset(struct ata_link *link, unsigned int *class, { struct ata_port *ap = link->ap; void __iomem *port = ap->ioaddr.cmd_addr; + struct sil24_port_priv *pp = ap->private_data; + int did_port_rst = 0; const char *reason; int tout_msec, rc; u32 tmp; + retry: + /* Sometimes, DEV_RST is not enough to recover the controller. + * This happens often after PM DMA CS errata. + */ + if (pp->do_port_rst) { + ata_port_printk(ap, KERN_WARNING, "controller in dubious " + "state, performing PORT_RST\n"); + + writel(PORT_CS_PORT_RST, port + PORT_CTRL_STAT); + msleep(10); + writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR); + ata_wait_register(port + PORT_CTRL_STAT, PORT_CS_RDY, 0, + 10, 5000); + + /* restore port configuration */ + sil24_config_port(ap); + sil24_config_pmp(ap, ap->nr_pmp_links); + + pp->do_port_rst = 0; + did_port_rst = 1; + } + /* sil24 does the right thing(tm) without any protection */ sata_set_spd(link); @@ -732,6 +787,11 @@ static int sil24_hardreset(struct ata_link *link, unsigned int *class, return -EAGAIN; err: + if (!did_port_rst) { + pp->do_port_rst = 1; + goto retry; + } + ata_link_printk(link, KERN_ERR, "hardreset failed (%s)\n", reason); return -EIO; } @@ -997,6 +1057,7 @@ static void sil24_error_intr(struct ata_port *ap) ehi->err_mask |= AC_ERR_OTHER; ehi->action |= ATA_EH_HARDRESET; ata_ehi_push_desc(ehi, "PMP DMA CS errata"); + pp->do_port_rst = 1; freeze = 1; } @@ -1152,6 +1213,8 @@ static irqreturn_t sil24_interrupt(int irq, void *dev_instance) static void sil24_error_handler(struct ata_port *ap) { + struct sil24_port_priv *pp = ap->private_data; + if (sil24_init_port(ap)) ata_eh_freeze_port(ap); @@ -1160,6 +1223,8 @@ static void sil24_error_handler(struct ata_port *ap) ata_std_postreset, sata_pmp_std_prereset, sil24_pmp_softreset, sil24_pmp_hardreset, sata_pmp_std_postreset); + + pp->do_port_rst = 0; } static void sil24_post_internal_cmd(struct ata_queued_cmd *qc) @@ -1206,7 +1271,6 @@ static int sil24_port_start(struct ata_port *ap) static void sil24_init_controller(struct ata_host *host) { void __iomem *host_base = host->iomap[SIL24_HOST_BAR]; - void __iomem *port_base = host->iomap[SIL24_PORT_BAR]; u32 tmp; int i; @@ -1218,7 +1282,8 @@ static void sil24_init_controller(struct ata_host *host) /* init ports */ for (i = 0; i < host->n_ports; i++) { - void __iomem *port = port_base + i * PORT_REGS_SIZE; + struct ata_port *ap = host->ports[i]; + void __iomem *port = ap->ioaddr.cmd_addr; /* Initial PHY setting */ writel(0x20c, port + PORT_PHY_CFG); @@ -1235,26 +1300,8 @@ static void sil24_init_controller(struct ata_host *host) "failed to clear port RST\n"); } - /* Configure IRQ WoC */ - if (host->ports[0]->flags & SIL24_FLAG_PCIX_IRQ_WOC) - writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT); - else - writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR); - - /* Zero error counters. */ - writel(0x8000, port + PORT_DECODE_ERR_THRESH); - writel(0x8000, port + PORT_CRC_ERR_THRESH); - writel(0x8000, port + PORT_HSHK_ERR_THRESH); - writel(0x0000, port + PORT_DECODE_ERR_CNT); - writel(0x0000, port + PORT_CRC_ERR_CNT); - writel(0x0000, port + PORT_HSHK_ERR_CNT); - - /* Always use 64bit activation */ - writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR); - - /* Clear port multiplier enable and resume bits */ - writel(PORT_CS_PMP_EN | PORT_CS_PMP_RESUME, - port + PORT_CTRL_CLR); + /* configure port */ + sil24_config_port(ap); } /* Turn on interrupts */ -- cgit v1.2.3-70-g09d2 From 7d50b60b5e38f910ad69f0187af00f5d6a8970d4 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 23 Sep 2007 13:19:54 +0900 Subject: ahci: implement PMP support Implement AHCI PMP support. ahci only supports command based switching. Also, for some reason, NCQ over PMP doesn't work now. Other than that, everything works. Tested on ICH9R, JMB360/363 + SIMG3726, 4726 and 5744. Signed-off-by: Tejun Heo Cc: Forrest Zhao Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 220 ++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 174 insertions(+), 46 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index b615390b6b8..b697da483b7 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -46,7 +46,7 @@ #include #define DRV_NAME "ahci" -#define DRV_VERSION "2.3" +#define DRV_VERSION "3.0" enum { @@ -96,6 +96,7 @@ enum { /* HOST_CAP bits */ HOST_CAP_SSC = (1 << 14), /* Slumber capable */ + HOST_CAP_PMP = (1 << 17), /* Port Multiplier support */ HOST_CAP_CLO = (1 << 24), /* Command List Override support */ HOST_CAP_SSS = (1 << 27), /* Staggered Spin-up */ HOST_CAP_SNTF = (1 << 29), /* SNotification register */ @@ -143,7 +144,8 @@ enum { PORT_IRQ_IF_ERR | PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY | - PORT_IRQ_UNK_FIS, + PORT_IRQ_UNK_FIS | + PORT_IRQ_BAD_PMP, PORT_IRQ_ERROR = PORT_IRQ_FREEZE | PORT_IRQ_TF_ERR | PORT_IRQ_HBUS_DATA_ERR, @@ -153,6 +155,7 @@ enum { /* PORT_CMD bits */ PORT_CMD_ATAPI = (1 << 24), /* Device is ATAPI */ + PORT_CMD_PMP = (1 << 17), /* PMP attached */ PORT_CMD_LIST_ON = (1 << 15), /* cmd list DMA engine running */ PORT_CMD_FIS_ON = (1 << 14), /* FIS DMA engine running */ PORT_CMD_FIS_RX = (1 << 4), /* Enable FIS receive DMA engine */ @@ -204,6 +207,7 @@ struct ahci_host_priv { }; struct ahci_port_priv { + struct ata_link *active_link; struct ahci_cmd_hdr *cmd_slot; dma_addr_t cmd_slot_dma; void *cmd_tbl; @@ -229,6 +233,10 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc); static u8 ahci_check_status(struct ata_port *ap); static void ahci_freeze(struct ata_port *ap); static void ahci_thaw(struct ata_port *ap); +static void ahci_pmp_attach(struct ata_port *ap); +static void ahci_pmp_detach(struct ata_port *ap); +static int ahci_pmp_read(struct ata_device *dev, int pmp, int reg, u32 *r_val); +static int ahci_pmp_write(struct ata_device *dev, int pmp, int reg, u32 val); static void ahci_error_handler(struct ata_port *ap); static void ahci_vt8251_error_handler(struct ata_port *ap); static void ahci_post_internal_cmd(struct ata_queued_cmd *qc); @@ -268,7 +276,7 @@ static const struct ata_port_operations ahci_ops = { .tf_read = ahci_tf_read, - .qc_defer = ata_std_qc_defer, + .qc_defer = sata_pmp_qc_defer_cmd_switch, .qc_prep = ahci_qc_prep, .qc_issue = ahci_qc_issue, @@ -283,6 +291,11 @@ static const struct ata_port_operations ahci_ops = { .error_handler = ahci_error_handler, .post_internal_cmd = ahci_post_internal_cmd, + .pmp_attach = ahci_pmp_attach, + .pmp_detach = ahci_pmp_detach, + .pmp_read = ahci_pmp_read, + .pmp_write = ahci_pmp_write, + #ifdef CONFIG_PM .port_suspend = ahci_port_suspend, .port_resume = ahci_port_resume, @@ -299,7 +312,7 @@ static const struct ata_port_operations ahci_vt8251_ops = { .tf_read = ahci_tf_read, - .qc_defer = ata_std_qc_defer, + .qc_defer = sata_pmp_qc_defer_cmd_switch, .qc_prep = ahci_qc_prep, .qc_issue = ahci_qc_issue, @@ -314,6 +327,11 @@ static const struct ata_port_operations ahci_vt8251_ops = { .error_handler = ahci_vt8251_error_handler, .post_internal_cmd = ahci_post_internal_cmd, + .pmp_attach = ahci_pmp_attach, + .pmp_detach = ahci_pmp_detach, + .pmp_read = ahci_pmp_read, + .pmp_write = ahci_pmp_write, + #ifdef CONFIG_PM .port_suspend = ahci_port_suspend, .port_resume = ahci_port_resume, @@ -1114,7 +1132,12 @@ static int ahci_do_softreset(struct ata_link *link, unsigned int *class, static int ahci_softreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { - return ahci_do_softreset(link, class, 0, deadline); + int pmp = 0; + + if (link->ap->flags & ATA_FLAG_PMP) + pmp = SATA_PMP_CTRL_PORT; + + return ahci_do_softreset(link, class, pmp, deadline); } static int ahci_hardreset(struct ata_link *link, unsigned int *class, @@ -1141,7 +1164,7 @@ static int ahci_hardreset(struct ata_link *link, unsigned int *class, if (rc == 0 && ata_link_online(link)) *class = ahci_dev_classify(ap); - if (*class == ATA_DEV_UNKNOWN) + if (rc != -EAGAIN && *class == ATA_DEV_UNKNOWN) *class = ATA_DEV_NONE; DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class); @@ -1196,6 +1219,12 @@ static void ahci_postreset(struct ata_link *link, unsigned int *class) } } +static int ahci_pmp_softreset(struct ata_link *link, unsigned int *class, + unsigned long deadline) +{ + return ahci_do_softreset(link, class, link->pmp, deadline); +} + static u8 ahci_check_status(struct ata_port *ap) { void __iomem *mmio = ap->ioaddr.cmd_addr; @@ -1254,7 +1283,7 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc) */ cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ; - ata_tf_to_fis(&qc->tf, 0, 1, cmd_tbl); + ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, cmd_tbl); if (is_atapi) { memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32); memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len); @@ -1267,7 +1296,7 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc) /* * Fill in command slot information. */ - opts = cmd_fis_len | n_elem << 16; + opts = cmd_fis_len | n_elem << 16 | (qc->dev->link->pmp << 12); if (qc->tf.flags & ATA_TFLAG_WRITE) opts |= AHCI_CMD_WRITE; if (is_atapi) @@ -1279,65 +1308,85 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc) static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) { struct ahci_port_priv *pp = ap->private_data; - struct ata_eh_info *ehi = &ap->link.eh_info; - unsigned int err_mask = 0, action = 0; - struct ata_queued_cmd *qc; + struct ata_eh_info *host_ehi = &ap->link.eh_info; + struct ata_link *link = NULL; + struct ata_queued_cmd *active_qc; + struct ata_eh_info *active_ehi; u32 serror; - ata_ehi_clear_desc(ehi); + /* determine active link */ + ata_port_for_each_link(link, ap) + if (ata_link_active(link)) + break; + if (!link) + link = &ap->link; + + active_qc = ata_qc_from_tag(ap, link->active_tag); + active_ehi = &link->eh_info; + + /* record irq stat */ + ata_ehi_clear_desc(host_ehi); + ata_ehi_push_desc(host_ehi, "irq_stat 0x%08x", irq_stat); /* AHCI needs SError cleared; otherwise, it might lock up */ ahci_scr_read(ap, SCR_ERROR, &serror); ahci_scr_write(ap, SCR_ERROR, serror); - - /* analyze @irq_stat */ - ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat); + host_ehi->serror |= serror; /* some controllers set IRQ_IF_ERR on device errors, ignore it */ if (ap->flags & AHCI_FLAG_IGN_IRQ_IF_ERR) irq_stat &= ~PORT_IRQ_IF_ERR; if (irq_stat & PORT_IRQ_TF_ERR) { - err_mask |= AC_ERR_DEV; + /* If qc is active, charge it; otherwise, the active + * link. There's no active qc on NCQ errors. It will + * be determined by EH by reading log page 10h. + */ + if (active_qc) + active_qc->err_mask |= AC_ERR_DEV; + else + active_ehi->err_mask |= AC_ERR_DEV; + if (ap->flags & AHCI_FLAG_IGN_SERR_INTERNAL) - serror &= ~SERR_INTERNAL; + host_ehi->serror &= ~SERR_INTERNAL; + } + + if (irq_stat & PORT_IRQ_UNK_FIS) { + u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK); + + active_ehi->err_mask |= AC_ERR_HSM; + active_ehi->action |= ATA_EH_SOFTRESET; + ata_ehi_push_desc(active_ehi, + "unknown FIS %08x %08x %08x %08x" , + unk[0], unk[1], unk[2], unk[3]); + } + + if (ap->nr_pmp_links && (irq_stat & PORT_IRQ_BAD_PMP)) { + active_ehi->err_mask |= AC_ERR_HSM; + active_ehi->action |= ATA_EH_SOFTRESET; + ata_ehi_push_desc(active_ehi, "incorrect PMP"); } if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR)) { - err_mask |= AC_ERR_HOST_BUS; - action |= ATA_EH_SOFTRESET; + host_ehi->err_mask |= AC_ERR_HOST_BUS; + host_ehi->action |= ATA_EH_SOFTRESET; + ata_ehi_push_desc(host_ehi, "host bus error"); } if (irq_stat & PORT_IRQ_IF_ERR) { - err_mask |= AC_ERR_ATA_BUS; - action |= ATA_EH_SOFTRESET; - ata_ehi_push_desc(ehi, "interface fatal error"); + host_ehi->err_mask |= AC_ERR_ATA_BUS; + host_ehi->action |= ATA_EH_SOFTRESET; + ata_ehi_push_desc(host_ehi, "interface fatal error"); } if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) { - ata_ehi_hotplugged(ehi); - ata_ehi_push_desc(ehi, "%s", irq_stat & PORT_IRQ_CONNECT ? + ata_ehi_hotplugged(host_ehi); + ata_ehi_push_desc(host_ehi, "%s", + irq_stat & PORT_IRQ_CONNECT ? "connection status changed" : "PHY RDY changed"); } - if (irq_stat & PORT_IRQ_UNK_FIS) { - u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK); - - err_mask |= AC_ERR_HSM; - action |= ATA_EH_SOFTRESET; - ata_ehi_push_desc(ehi, "unknown FIS %08x %08x %08x %08x", - unk[0], unk[1], unk[2], unk[3]); - } - /* okay, let's hand over to EH */ - ehi->serror |= serror; - ehi->action |= action; - - qc = ata_qc_from_tag(ap, ap->link.active_tag); - if (qc) - qc->err_mask |= err_mask; - else - ehi->err_mask |= err_mask; if (irq_stat & PORT_IRQ_FREEZE) ata_port_freeze(ap); @@ -1375,7 +1424,8 @@ static void ahci_port_intr(struct ata_port *ap) sata_async_notification(ap); } - if (ap->link.sactive) + /* pp->active_link is valid iff any command is in flight */ + if (ap->qc_active && pp->active_link->sactive) qc_active = readl(port_mmio + PORT_SCR_ACT); else qc_active = readl(port_mmio + PORT_CMD_ISSUE); @@ -1513,6 +1563,13 @@ static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; void __iomem *port_mmio = ahci_port_base(ap); + struct ahci_port_priv *pp = ap->private_data; + + /* Keep track of the currently active link. It will be used + * in completion path to determine whether NCQ phase is in + * progress. + */ + pp->active_link = qc->dev->link; if (qc->tf.protocol == ATA_PROT_NCQ) writel(1 << qc->tag, port_mmio + PORT_SCR_ACT); @@ -1542,8 +1599,11 @@ static void ahci_thaw(struct ata_port *ap) writel(tmp, port_mmio + PORT_IRQ_STAT); writel(1 << ap->port_no, mmio + HOST_IRQ_STAT); - /* turn IRQ back on */ - writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); + /* turn IRQ back on, ignore BAD_PMP if PMP isn't attached */ + tmp = pp->intr_mask; + if (!ap->nr_pmp_links) + tmp &= ~PORT_IRQ_BAD_PMP; + writel(tmp, port_mmio + PORT_IRQ_MASK); } static void ahci_error_handler(struct ata_port *ap) @@ -1555,8 +1615,10 @@ static void ahci_error_handler(struct ata_port *ap) } /* perform recovery */ - ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_hardreset, - ahci_postreset); + sata_pmp_do_eh(ap, ata_std_prereset, ahci_softreset, + ahci_hardreset, ahci_postreset, + sata_pmp_std_prereset, ahci_pmp_softreset, + sata_pmp_std_hardreset, sata_pmp_std_postreset); } static void ahci_vt8251_error_handler(struct ata_port *ap) @@ -1581,11 +1643,74 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc) ahci_kick_engine(ap, 1); } +static void ahci_pmp_attach(struct ata_port *ap) +{ + void __iomem *port_mmio = ahci_port_base(ap); + u32 cmd; + + cmd = readl(port_mmio + PORT_CMD); + cmd |= PORT_CMD_PMP; + writel(cmd, port_mmio + PORT_CMD); +} + +static void ahci_pmp_detach(struct ata_port *ap) +{ + void __iomem *port_mmio = ahci_port_base(ap); + struct ahci_host_priv *hpriv = ap->host->private_data; + unsigned long flags; + u32 cmd; + + cmd = readl(port_mmio + PORT_CMD); + cmd &= ~PORT_CMD_PMP; + writel(cmd, port_mmio + PORT_CMD); + + if (hpriv->cap & HOST_CAP_NCQ) { + spin_lock_irqsave(ap->lock, flags); + ap->flags |= ATA_FLAG_NCQ; + spin_unlock_irqrestore(ap->lock, flags); + } +} + +static int ahci_pmp_read(struct ata_device *dev, int pmp, int reg, u32 *r_val) +{ + struct ata_port *ap = dev->link->ap; + struct ata_taskfile tf; + int rc; + + ahci_kick_engine(ap, 0); + + sata_pmp_read_init_tf(&tf, dev, pmp, reg); + rc = ahci_exec_polled_cmd(ap, SATA_PMP_CTRL_PORT, &tf, 1, 0, + SATA_PMP_SCR_TIMEOUT); + if (rc == 0) { + ahci_tf_read(ap, &tf); + *r_val = sata_pmp_read_val(&tf); + } + return rc; +} + +static int ahci_pmp_write(struct ata_device *dev, int pmp, int reg, u32 val) +{ + struct ata_port *ap = dev->link->ap; + struct ata_taskfile tf; + + ahci_kick_engine(ap, 0); + + sata_pmp_write_init_tf(&tf, dev, pmp, reg, val); + return ahci_exec_polled_cmd(ap, SATA_PMP_CTRL_PORT, &tf, 1, 0, + SATA_PMP_SCR_TIMEOUT); +} + static int ahci_port_resume(struct ata_port *ap) { ahci_power_up(ap); ahci_start_port(ap); + if (ap->nr_pmp_links) + ahci_pmp_attach(ap); + else + ahci_pmp_detach(ap); + return 0; } @@ -1866,6 +1991,9 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (hpriv->cap & HOST_CAP_NCQ) pi.flags |= ATA_FLAG_NCQ; + if (hpriv->cap & HOST_CAP_PMP) + pi.flags |= ATA_FLAG_PMP; + host = ata_host_alloc_pinfo(&pdev->dev, ppi, fls(hpriv->port_map)); if (!host) return -ENOMEM; -- cgit v1.2.3-70-g09d2 From 417a1a6d3d7abad4c5288135f640e6e38e7a65c5 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 23 Sep 2007 13:19:55 +0900 Subject: ahci: move host flags over to pi.private_data Private pi.flags area is full and we need more private flags. Move host private flags over to pi.private_data. During initialization, these flags are copied to hpriv->flags. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 63 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 35 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index b697da483b7..35ede5c31b9 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -169,14 +169,16 @@ enum { PORT_CMD_ICC_PARTIAL = (0x2 << 28), /* Put i/f in partial state */ PORT_CMD_ICC_SLUMBER = (0x6 << 28), /* Put i/f in slumber state */ + /* hpriv->flags bits */ + AHCI_HFLAG_NO_NCQ = (1 << 0), + AHCI_HFLAG_IGN_IRQ_IF_ERR = (1 << 1), /* ignore IRQ_IF_ERR */ + AHCI_HFLAG_IGN_SERR_INTERNAL = (1 << 2), /* ignore SERR_INTERNAL */ + AHCI_HFLAG_32BIT_ONLY = (1 << 3), /* force 32bit */ + AHCI_HFLAG_MV_PATA = (1 << 4), /* PATA port */ + AHCI_HFLAG_NO_MSI = (1 << 5), /* no PCI MSI */ + /* ap->flags bits */ - AHCI_FLAG_NO_NCQ = (1 << 24), - AHCI_FLAG_IGN_IRQ_IF_ERR = (1 << 25), /* ignore IRQ_IF_ERR */ - AHCI_FLAG_IGN_SERR_INTERNAL = (1 << 27), /* ignore SERR_INTERNAL */ - AHCI_FLAG_32BIT_ONLY = (1 << 28), /* force 32bit */ - AHCI_FLAG_MV_PATA = (1 << 29), /* PATA port */ - AHCI_FLAG_NO_MSI = (1 << 30), /* no PCI MSI */ - AHCI_FLAG_NO_HOTPLUG = (1 << 31), /* ignore PxSERR.DIAG.N */ + AHCI_FLAG_NO_HOTPLUG = (1 << 24), /* ignore PxSERR.DIAG.N */ AHCI_FLAG_COMMON = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | @@ -200,6 +202,7 @@ struct ahci_sg { }; struct ahci_host_priv { + unsigned int flags; /* AHCI_HFLAG_* */ u32 cap; /* cap to use */ u32 port_map; /* port map to use */ u32 saved_cap; /* saved initial cap */ @@ -341,6 +344,8 @@ static const struct ata_port_operations ahci_vt8251_ops = { .port_stop = ahci_port_stop, }; +#define AHCI_HFLAGS(flags) .private_data = (void *)(flags) + static const struct ata_port_info ahci_port_info[] = { /* board_ahci */ { @@ -352,7 +357,8 @@ static const struct ata_port_info ahci_port_info[] = { }, /* board_ahci_vt8251 */ { - .flags = AHCI_FLAG_COMMON | AHCI_FLAG_NO_NCQ, + AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ), + .flags = AHCI_FLAG_COMMON, .link_flags = AHCI_LFLAG_COMMON | ATA_LFLAG_HRST_TO_RESUME, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, @@ -360,7 +366,8 @@ static const struct ata_port_info ahci_port_info[] = { }, /* board_ahci_ign_iferr */ { - .flags = AHCI_FLAG_COMMON | AHCI_FLAG_IGN_IRQ_IF_ERR, + AHCI_HFLAGS (AHCI_HFLAG_IGN_IRQ_IF_ERR), + .flags = AHCI_FLAG_COMMON, .link_flags = AHCI_LFLAG_COMMON, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, @@ -368,9 +375,9 @@ static const struct ata_port_info ahci_port_info[] = { }, /* board_ahci_sb600 */ { - .flags = AHCI_FLAG_COMMON | - AHCI_FLAG_IGN_SERR_INTERNAL | - AHCI_FLAG_32BIT_ONLY, + AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL | + AHCI_HFLAG_32BIT_ONLY), + .flags = AHCI_FLAG_COMMON, .link_flags = AHCI_LFLAG_COMMON, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, @@ -378,11 +385,10 @@ static const struct ata_port_info ahci_port_info[] = { }, /* board_ahci_mv */ { - .sht = &ahci_sht, + AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_MSI | + AHCI_HFLAG_MV_PATA), .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | - AHCI_FLAG_NO_NCQ | AHCI_FLAG_NO_MSI | - AHCI_FLAG_MV_PATA, + ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA, .link_flags = AHCI_LFLAG_COMMON, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, @@ -534,7 +540,6 @@ static inline void __iomem *ahci_port_base(struct ata_port *ap) /** * ahci_save_initial_config - Save and fixup initial config values * @pdev: target PCI device - * @pi: associated ATA port info * @hpriv: host private area to store config values * * Some registers containing configuration info might be setup by @@ -548,7 +553,6 @@ static inline void __iomem *ahci_port_base(struct ata_port *ap) * None. */ static void ahci_save_initial_config(struct pci_dev *pdev, - const struct ata_port_info *pi, struct ahci_host_priv *hpriv) { void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR]; @@ -562,13 +566,13 @@ static void ahci_save_initial_config(struct pci_dev *pdev, hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL); /* some chips have errata preventing 64bit use */ - if ((cap & HOST_CAP_64) && (pi->flags & AHCI_FLAG_32BIT_ONLY)) { + if ((cap & HOST_CAP_64) && (hpriv->flags & AHCI_HFLAG_32BIT_ONLY)) { dev_printk(KERN_INFO, &pdev->dev, "controller can't do 64bit DMA, forcing 32bit\n"); cap &= ~HOST_CAP_64; } - if ((cap & HOST_CAP_NCQ) && (pi->flags & AHCI_FLAG_NO_NCQ)) { + if ((cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_NO_NCQ)) { dev_printk(KERN_INFO, &pdev->dev, "controller can't do NCQ, turning off CAP_NCQ\n"); cap &= ~HOST_CAP_NCQ; @@ -579,7 +583,7 @@ static void ahci_save_initial_config(struct pci_dev *pdev, * is asserted through the standard AHCI port * presence register, as bit 4 (counting from 0) */ - if (pi->flags & AHCI_FLAG_MV_PATA) { + if (hpriv->flags & AHCI_HFLAG_MV_PATA) { dev_printk(KERN_ERR, &pdev->dev, "MV_AHCI HACK: port_map %x -> %x\n", hpriv->port_map, @@ -919,13 +923,14 @@ static void ahci_port_init(struct pci_dev *pdev, struct ata_port *ap, static void ahci_init_controller(struct ata_host *host) { + struct ahci_host_priv *hpriv = host->private_data; struct pci_dev *pdev = to_pci_dev(host->dev); void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; int i; void __iomem *port_mmio; u32 tmp; - if (host->ports[0]->flags & AHCI_FLAG_MV_PATA) { + if (hpriv->flags & AHCI_HFLAG_MV_PATA) { port_mmio = __ahci_port_base(host, 4); writel(0, port_mmio + PORT_IRQ_MASK); @@ -1307,6 +1312,7 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc) static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) { + struct ahci_host_priv *hpriv = ap->host->private_data; struct ahci_port_priv *pp = ap->private_data; struct ata_eh_info *host_ehi = &ap->link.eh_info; struct ata_link *link = NULL; @@ -1334,7 +1340,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) host_ehi->serror |= serror; /* some controllers set IRQ_IF_ERR on device errors, ignore it */ - if (ap->flags & AHCI_FLAG_IGN_IRQ_IF_ERR) + if (hpriv->flags & AHCI_HFLAG_IGN_IRQ_IF_ERR) irq_stat &= ~PORT_IRQ_IF_ERR; if (irq_stat & PORT_IRQ_TF_ERR) { @@ -1347,7 +1353,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) else active_ehi->err_mask |= AC_ERR_DEV; - if (ap->flags & AHCI_FLAG_IGN_SERR_INTERNAL) + if (hpriv->flags & AHCI_HFLAG_IGN_SERR_INTERNAL) host_ehi->serror &= ~SERR_INTERNAL; } @@ -1977,15 +1983,16 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) return rc; - if ((pi.flags & AHCI_FLAG_NO_MSI) || pci_enable_msi(pdev)) - pci_intx(pdev, 1); - hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL); if (!hpriv) return -ENOMEM; + hpriv->flags |= (unsigned long)pi.private_data; + + if ((hpriv->flags & AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev)) + pci_intx(pdev, 1); /* save initial config */ - ahci_save_initial_config(pdev, &pi, hpriv); + ahci_save_initial_config(pdev, hpriv); /* prepare host */ if (hpriv->cap & HOST_CAP_NCQ) -- cgit v1.2.3-70-g09d2 From 6949b9148d3656afc13a2ccc06d13c071ec71bdc Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 23 Sep 2007 13:19:55 +0900 Subject: ahci: implement AHCI_HFLAG_NO_PMP Of course some controllers lie about PMP support. Black list them. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 35ede5c31b9..af7bf267908 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -176,6 +176,7 @@ enum { AHCI_HFLAG_32BIT_ONLY = (1 << 3), /* force 32bit */ AHCI_HFLAG_MV_PATA = (1 << 4), /* PATA port */ AHCI_HFLAG_NO_MSI = (1 << 5), /* no PCI MSI */ + AHCI_HFLAG_NO_PMP = (1 << 6), /* no PMP */ /* ap->flags bits */ AHCI_FLAG_NO_HOTPLUG = (1 << 24), /* ignore PxSERR.DIAG.N */ @@ -357,7 +358,7 @@ static const struct ata_port_info ahci_port_info[] = { }, /* board_ahci_vt8251 */ { - AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ), + AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_PMP), .flags = AHCI_FLAG_COMMON, .link_flags = AHCI_LFLAG_COMMON | ATA_LFLAG_HRST_TO_RESUME, .pio_mask = 0x1f, /* pio0-4 */ @@ -376,7 +377,7 @@ static const struct ata_port_info ahci_port_info[] = { /* board_ahci_sb600 */ { AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL | - AHCI_HFLAG_32BIT_ONLY), + AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_PMP), .flags = AHCI_FLAG_COMMON, .link_flags = AHCI_LFLAG_COMMON, .pio_mask = 0x1f, /* pio0-4 */ @@ -578,6 +579,12 @@ static void ahci_save_initial_config(struct pci_dev *pdev, cap &= ~HOST_CAP_NCQ; } + if ((cap && HOST_CAP_PMP) && (hpriv->flags & AHCI_HFLAG_NO_PMP)) { + dev_printk(KERN_INFO, &pdev->dev, + "controller can't do PMP, turning off CAP_PMP\n"); + cap &= ~HOST_CAP_PMP; + } + /* * Temporary Marvell 6145 hack: PATA port presence * is asserted through the standard AHCI port -- cgit v1.2.3-70-g09d2 From 1333e19434da116bc832e1b8925359d1565fedc9 Mon Sep 17 00:00:00 2001 From: Robert Hancock Date: Tue, 2 Oct 2007 11:22:02 -0400 Subject: libata: add human-readable error value decoding This adds human-readable decoding of the ATA status and error registers (similar to what drivers/ide does) as well as the SATA Serror register to libata error handling output. This prevents the need to pore through standards documents to figure out the meaning of the bits in these registers when looking at error reports. Some bits that drivers/ide decoded are not decoded here, since the bits are either command-dependent or obsolete, and properly parsing them would add too much complexity. Signed-off-by: Robert Hancock [edited slightly to make output a bit more symmetric] Signed-off-by: Jeff Garzik --- drivers/ata/libata-eh.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/ata.h | 9 +++++++++ 2 files changed, 54 insertions(+) (limited to 'drivers') diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 5f2c0f376f7..0bd3898793a 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1911,6 +1911,27 @@ static void ata_eh_link_report(struct ata_link *link) ata_link_printk(link, KERN_ERR, "%s\n", desc); } + if (ehc->i.serror) + ata_port_printk(ap, KERN_ERR, + "SError: { %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s}\n", + ehc->i.serror & SERR_DATA_RECOVERED ? "RecovData " : "", + ehc->i.serror & SERR_COMM_RECOVERED ? "RecovComm " : "", + ehc->i.serror & SERR_DATA ? "UnrecovData " : "", + ehc->i.serror & SERR_PERSISTENT ? "Persist " : "", + ehc->i.serror & SERR_PROTOCOL ? "Proto " : "", + ehc->i.serror & SERR_INTERNAL ? "HostInt " : "", + ehc->i.serror & SERR_PHYRDY_CHG ? "PHYRdyChg " : "", + ehc->i.serror & SERR_PHY_INT_ERR ? "PHYInt " : "", + ehc->i.serror & SERR_COMM_WAKE ? "CommWake " : "", + ehc->i.serror & SERR_10B_8B_ERR ? "10B8B " : "", + ehc->i.serror & SERR_DISPARITY ? "Dispar " : "", + ehc->i.serror & SERR_CRC ? "BadCRC " : "", + ehc->i.serror & SERR_HANDSHAKE ? "Handshk " : "", + ehc->i.serror & SERR_LINK_SEQ_ERR ? "LinkSeq " : "", + ehc->i.serror & SERR_TRANS_ST_ERROR ? "TrStaTrns " : "", + ehc->i.serror & SERR_UNRECOG_FIS ? "UnrecFIS " : "", + ehc->i.serror & SERR_DEV_XCHG ? "DevExch " : "" ); + for (tag = 0; tag < ATA_MAX_QUEUE; tag++) { static const char *dma_str[] = { [DMA_BIDIRECTIONAL] = "bidi", @@ -1942,6 +1963,30 @@ static void ata_eh_link_report(struct ata_link *link) res->hob_lbal, res->hob_lbam, res->hob_lbah, res->device, qc->err_mask, ata_err_string(qc->err_mask), qc->err_mask & AC_ERR_NCQ ? " " : ""); + + if (res->command & (ATA_BUSY | ATA_DRDY | ATA_DF | ATA_DRQ | + ATA_ERR) ) { + if (res->command & ATA_BUSY) + ata_dev_printk(qc->dev, KERN_ERR, + "status: { Busy }\n" ); + else + ata_dev_printk(qc->dev, KERN_ERR, + "status: { %s%s%s%s}\n", + res->command & ATA_DRDY ? "DRDY " : "", + res->command & ATA_DF ? "DF " : "", + res->command & ATA_DRQ ? "DRQ " : "", + res->command & ATA_ERR ? "ERR " : "" ); + } + + if (cmd->command != ATA_CMD_PACKET && + (res->feature & (ATA_ICRC | ATA_UNC | ATA_IDNF | + ATA_ABORTED))) + ata_dev_printk(qc->dev, KERN_ERR, + "error: { %s%s%s%s}\n", + res->feature & ATA_ICRC ? "ICRC " : "", + res->feature & ATA_UNC ? "UNC " : "", + res->feature & ATA_IDNF ? "IDNF " : "", + res->feature & ATA_ABORTED ? "ABRT " : "" ); } } diff --git a/include/linux/ata.h b/include/linux/ata.h index 21f00a0646d..a4f373f8b79 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -287,6 +287,15 @@ enum { SERR_PROTOCOL = (1 << 10), /* protocol violation */ SERR_INTERNAL = (1 << 11), /* host internal error */ SERR_PHYRDY_CHG = (1 << 16), /* PHY RDY changed */ + SERR_PHY_INT_ERR = (1 << 17), /* PHY internal error */ + SERR_COMM_WAKE = (1 << 18), /* Comm wake */ + SERR_10B_8B_ERR = (1 << 19), /* 10b to 8b decode error */ + SERR_DISPARITY = (1 << 20), /* Disparity */ + SERR_CRC = (1 << 21), /* CRC error */ + SERR_HANDSHAKE = (1 << 22), /* Handshake error */ + SERR_LINK_SEQ_ERR = (1 << 23), /* Link sequence error */ + SERR_TRANS_ST_ERROR = (1 << 24), /* Transport state trans. error */ + SERR_UNRECOG_FIS = (1 << 25), /* Unrecognized FIS */ SERR_DEV_XCHG = (1 << 26), /* device exchanged */ /* struct ata_taskfile flags */ -- cgit v1.2.3-70-g09d2 From 7100819f5f9b99eb7c7dd5597f293388a405bf7b Mon Sep 17 00:00:00 2001 From: Peer Chen Date: Mon, 24 Sep 2007 10:16:25 +0800 Subject: ahci: Add MCP79 support to AHCI driver Signed-off-by: Peer Chen Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index af7bf267908..24fb90f58cd 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -491,6 +491,14 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(NVIDIA, 0x0ad9), board_ahci }, /* MCP77 */ { PCI_VDEVICE(NVIDIA, 0x0ada), board_ahci }, /* MCP77 */ { PCI_VDEVICE(NVIDIA, 0x0adb), board_ahci }, /* MCP77 */ + { PCI_VDEVICE(NVIDIA, 0x0ab8), board_ahci }, /* MCP79 */ + { PCI_VDEVICE(NVIDIA, 0x0ab9), board_ahci }, /* MCP79 */ + { PCI_VDEVICE(NVIDIA, 0x0aba), board_ahci }, /* MCP79 */ + { PCI_VDEVICE(NVIDIA, 0x0abb), board_ahci }, /* MCP79 */ + { PCI_VDEVICE(NVIDIA, 0x0abc), board_ahci }, /* MCP79 */ + { PCI_VDEVICE(NVIDIA, 0x0abd), board_ahci }, /* MCP79 */ + { PCI_VDEVICE(NVIDIA, 0x0abe), board_ahci }, /* MCP79 */ + { PCI_VDEVICE(NVIDIA, 0x0abf), board_ahci }, /* MCP79 */ /* SiS */ { PCI_VDEVICE(SI, 0x1184), board_ahci }, /* SiS 966 */ -- cgit v1.2.3-70-g09d2 From b3a706014e56b1356e7b275fd25b833c63175bf0 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 2 Oct 2007 12:38:26 -0400 Subject: libata: Add a drivers/ide style DMA disable This is useful when debugging, handling problem systems, or for distributions just to get the system installed so it can be sorted out later. This is a bit smarter than the old IDE one and lets you do libata.dma=0 Disable all PATA DMA like old IDE libata.dma=1 Disk DMA only libata.dma=2 ATAPI DMA only libata.dma=4 CF DMA only (or combinations thereof - 0,1,3 being the useful ones I suspect) (I've split CF as it seems to be a seperate case of pain and suffering different to the others and caused by assorted PIO wired adapters etc) Signed-off-by: Alan Cox [edited to work on SATA too, changing name from 'pata_dma' to 'dma'] Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 17 +++++++++++++++++ include/linux/libata.h | 6 ++++++ 2 files changed, 23 insertions(+) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 5532a6564d0..1501d63db2c 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -97,6 +97,10 @@ static int ata_ignore_hpa = 0; module_param_named(ignore_hpa, ata_ignore_hpa, int, 0644); MODULE_PARM_DESC(ignore_hpa, "Ignore HPA limit (0=keep BIOS limits, 1=ignore limits, using full disk)"); +static int libata_dma_mask = ATA_DMA_MASK_ATA|ATA_DMA_MASK_ATAPI|ATA_DMA_MASK_CFA; +module_param_named(dma, libata_dma_mask, int, 0444); +MODULE_PARM_DESC(dma, "DMA enable/disable (0x1==ATA, 0x2==ATAPI, 0x4==CF)"); + static int ata_probe_timeout = ATA_TMOUT_INTERNAL / HZ; module_param(ata_probe_timeout, int, 0444); MODULE_PARM_DESC(ata_probe_timeout, "Set ATA probing timeout (seconds)"); @@ -2917,14 +2921,27 @@ int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev) /* step 1: calculate xfer_mask */ ata_link_for_each_dev(dev, link) { unsigned int pio_mask, dma_mask; + unsigned int mode_mask; if (!ata_dev_enabled(dev)) continue; + mode_mask = ATA_DMA_MASK_ATA; + if (dev->class == ATA_DEV_ATAPI) + mode_mask = ATA_DMA_MASK_ATAPI; + else if (ata_id_is_cfa(dev->id)) + mode_mask = ATA_DMA_MASK_CFA; + ata_dev_xfermask(dev); pio_mask = ata_pack_xfermask(dev->pio_mask, 0, 0); dma_mask = ata_pack_xfermask(0, dev->mwdma_mask, dev->udma_mask); + + if (libata_dma_mask & mode_mask) + dma_mask = ata_pack_xfermask(0, dev->mwdma_mask, dev->udma_mask); + else + dma_mask = 0; + dev->pio_mode = ata_xfer_mask2mode(pio_mask); dev->dma_mode = ata_xfer_mask2mode(dma_mask); diff --git a/include/linux/libata.h b/include/linux/libata.h index ca296a575c4..84dfc23b9d3 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -331,6 +331,12 @@ enum { ATA_HORKAGE_BROKEN_HPA = (1 << 4), /* Broken HPA */ ATA_HORKAGE_SKIP_PM = (1 << 5), /* Skip PM operations */ ATA_HORKAGE_HPA_SIZE = (1 << 6), /* native size off by one */ + + /* DMA mask for user DMA control: User visible values; DO NOT + renumber */ + ATA_DMA_MASK_ATA = (1 << 0), /* DMA on ATA Disk */ + ATA_DMA_MASK_ATAPI = (1 << 1), /* DMA on ATAPI */ + ATA_DMA_MASK_CFA = (1 << 2), /* DMA on CF Card */ }; enum hsm_task_states { -- cgit v1.2.3-70-g09d2 From 237d8440cb2b104a3b97fc971a9bce67960bb616 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Wed, 3 Oct 2007 01:24:16 +0100 Subject: libata: Integrate ACPI-based PATA/SATA hotplug - version 5 Modern laptops with hotswap bays still tend to utilise a PATA interface on a SATA bridge, generally with the host controller in some legacy emulation mode rather than AHCI. This means that the existing hotplug code in libata is unable to work. The ACPI specification states that these devices can send notifications when hotswapped, which avoids the need to obtain notification from the controller. This patch uses the existing libata-acpi code and simply registers a notification in order to trigger a rescan whenever the firmware signals an event. Signed-off-by: Matthew Garrett Signed-off-by: Jeff Garzik --- drivers/ata/libata-acpi.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index a276c06dda9..5ebbf16f3af 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "libata.h" #include @@ -95,6 +96,47 @@ static void ata_acpi_associate_ide_port(struct ata_port *ap) } } +static void ata_acpi_handle_hotplug (struct ata_port *ap, struct kobject *kobj, + u32 event) +{ + char event_string[12]; + char *envp[] = { event_string, NULL }; + struct ata_eh_info *ehi = &ap->link.eh_info; + + if (event == 0 || event == 1) { + unsigned long flags; + spin_lock_irqsave(ap->lock, flags); + ata_ehi_clear_desc(ehi); + ata_ehi_push_desc(ehi, "ACPI event"); + ata_ehi_hotplugged(ehi); + ata_port_freeze(ap); + spin_unlock_irqrestore(ap->lock, flags); + } + + if (kobj) { + sprintf(event_string, "BAY_EVENT=%d", event); + kobject_uevent_env(kobj, KOBJ_CHANGE, envp); + } +} + +static void ata_acpi_dev_notify(acpi_handle handle, u32 event, void *data) +{ + struct ata_device *dev = data; + struct kobject *kobj = NULL; + + if (dev->sdev) + kobj = &dev->sdev->sdev_gendev.kobj; + + ata_acpi_handle_hotplug (dev->link->ap, kobj, event); +} + +static void ata_acpi_ap_notify(acpi_handle handle, u32 event, void *data) +{ + struct ata_port *ap = data; + + ata_acpi_handle_hotplug (ap, &ap->dev->kobj, event); +} + /** * ata_acpi_associate - associate ATA host with ACPI objects * @host: target ATA host @@ -110,7 +152,7 @@ static void ata_acpi_associate_ide_port(struct ata_port *ap) */ void ata_acpi_associate(struct ata_host *host) { - int i; + int i, j; if (!is_pci_dev(host->dev) || libata_noacpi) return; @@ -126,6 +168,22 @@ void ata_acpi_associate(struct ata_host *host) ata_acpi_associate_sata_port(ap); else ata_acpi_associate_ide_port(ap); + + if (ap->acpi_handle) + acpi_install_notify_handler (ap->acpi_handle, + ACPI_SYSTEM_NOTIFY, + ata_acpi_ap_notify, + ap); + + for (j = 0; j < ata_link_max_devices(&ap->link); j++) { + struct ata_device *dev = &ap->link.device[j]; + + if (dev->acpi_handle) + acpi_install_notify_handler (dev->acpi_handle, + ACPI_SYSTEM_NOTIFY, + ata_acpi_dev_notify, + dev); + } } } -- cgit v1.2.3-70-g09d2 From 681c80b5d96076f447e8101ac4325c82d8dce508 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 3 Oct 2007 13:23:18 +0100 Subject: libata: correct handling of SRST reset sequences Correct handling of SRST reset sequences. After an SRST it is undefined whether the drive has gone back to PIO0. In order to talk safely we should talk slowly and carefully until we know. Thus when we do the reset if the controller has a pio setup method we call it to flip back to PIO 0 and a known state. After the reset completes the identify will then be done at the safe speed and the drive/controller will pick suitable faster modes and reconfigure the controller to these timings. As a side effect it means we force the controller to PIO 0 as we bring it up which fixes funnies on a few systems where the BIOS firmware leaves us in an interesting choice of modes, or embedded boxes with no firmware which come up in random states. For smart controllers there is nothing to do - they know about this internally. Signed-off-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 1501d63db2c..aecbdad960f 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -3209,6 +3209,8 @@ static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask, unsigned long deadline) { struct ata_ioports *ioaddr = &ap->ioaddr; + struct ata_device *dev; + int i = 0; DPRINTK("ata%u: bus reset via SRST\n", ap->print_id); @@ -3219,6 +3221,25 @@ static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask, udelay(20); /* FIXME: flush */ iowrite8(ap->ctl, ioaddr->ctl_addr); + /* If we issued an SRST then an ATA drive (not ATAPI) + * may have changed configuration and be in PIO0 timing. If + * we did a hard reset (or are coming from power on) this is + * true for ATA or ATAPI. Until we've set a suitable controller + * mode we should not touch the bus as we may be talking too fast. + */ + + ata_link_for_each_dev(dev, &ap->link) + dev->pio_mode = XFER_PIO_0; + + /* If the controller has a pio mode setup function then use + it to set the chipset to rights. Don't touch the DMA setup + as that will be dealt with when revalidating */ + if (ap->ops->set_piomode) { + ata_link_for_each_dev(dev, &ap->link) + if (devmask & (1 << i++)) + ap->ops->set_piomode(ap, dev); + } + /* spec mandates ">= 2ms" before checking status. * We wait 150ms, because that was the magic delay used for * ATAPI devices in Hale Landis's ATADRVR, for the period of time -- cgit v1.2.3-70-g09d2 From 2db78dd302d26d242d3e8e5c4c5024b6c3ea93c2 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 2 Oct 2007 13:53:04 -0700 Subject: libata_scsi: Fix ATAPI transfer lengths Some controller variants snoop the ATAPI length value for Packet transfers to do state machine and FIFO management. Thus we want to set it properly, even for cases where it is otherwise meaningless. Signed-off-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/ata/libata-scsi.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index df2e05738f3..ea53e6a570b 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -2305,8 +2305,8 @@ static void atapi_request_sense(struct ata_queued_cmd *qc) qc->tf.feature |= ATAPI_PKT_DMA; } else { qc->tf.protocol = ATA_PROT_ATAPI; - qc->tf.lbam = (8 * 1024) & 0xff; - qc->tf.lbah = (8 * 1024) >> 8; + qc->tf.lbam = SCSI_SENSE_BUFFERSIZE; + qc->tf.lbah = 0; } qc->nbytes = SCSI_SENSE_BUFFERSIZE; @@ -2415,6 +2415,7 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc) struct ata_device *dev = qc->dev; int using_pio = (dev->flags & ATA_DFLAG_PIO); int nodata = (scmd->sc_data_direction == DMA_NONE); + unsigned int nbytes; memset(qc->cdb, 0, dev->cdb_len); memcpy(qc->cdb, scmd->cmnd, scmd->cmd_len); @@ -2434,14 +2435,20 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc) if (!using_pio && ata_check_atapi_dma(qc)) using_pio = 1; + /* Some controller variants snoop this value for Packet transfers + to do state machine and FIFO management. Thus we want to set it + properly, and for DMA where it is effectively meaningless */ + nbytes = min(qc->nbytes, (unsigned int)63 * 1024); + + qc->tf.lbam = (nbytes & 0xFF); + qc->tf.lbah = (nbytes >> 8); + if (using_pio || nodata) { /* no data, or PIO data xfer */ if (nodata) qc->tf.protocol = ATA_PROT_ATAPI_NODATA; else qc->tf.protocol = ATA_PROT_ATAPI; - qc->tf.lbam = (8 * 1024) & 0xff; - qc->tf.lbah = (8 * 1024) >> 8; } else { /* DMA data xfer */ qc->tf.protocol = ATA_PROT_ATAPI_DMA; @@ -2452,6 +2459,9 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc) qc->tf.feature |= ATAPI_DMADIR; } + + /* FIXME: We need to translate 0x05 READ_BLOCK_LIMITS to a MODE_SENSE + as ATAPI tape drives don't get this right otherwise */ return 0; } -- cgit v1.2.3-70-g09d2 From 6ebe9d8667d3f449350cbc6686cd917ecf1f40dd Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Fri, 5 Oct 2007 16:28:36 -0400 Subject: [libata] Turn on ACPI by default Let's see what explodes. Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index aecbdad960f..64d2c99d15e 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -105,9 +105,9 @@ static int ata_probe_timeout = ATA_TMOUT_INTERNAL / HZ; module_param(ata_probe_timeout, int, 0444); MODULE_PARM_DESC(ata_probe_timeout, "Set ATA probing timeout (seconds)"); -int libata_noacpi = 1; +int libata_noacpi = 0; module_param_named(noacpi, libata_noacpi, int, 0444); -MODULE_PARM_DESC(noacpi, "Disables the use of ACPI in suspend/resume when set"); +MODULE_PARM_DESC(noacpi, "Disables the use of ACPI in probe/suspend/resume when set"); MODULE_AUTHOR("Jeff Garzik"); MODULE_DESCRIPTION("Library module for ATA devices"); -- cgit v1.2.3-70-g09d2 From da6f0ec2d54acf545e784363aa5bad0dafc5ffa8 Mon Sep 17 00:00:00 2001 From: Paolo Ornati Date: Thu, 4 Oct 2007 11:06:56 +0900 Subject: libata: blacklist NCQ on Seagate Barracuda ST380817AS Seagate Barracuda ST380817AS has troubles with NCQ. For example, unpacking a tarball on an XFS filesystem gives this: ata1.00: exception Emask 0x0 SAct 0x1 SErr 0x0 action 0x2 frozen ata1.00: cmd 61/40:00:29:a3:98/00:00:00:00:00/40 tag 0 cdb 0x0 data 32768 out res 40/00:00:00:00:00/00:00:00:00:00/00 Emask 0x4 (timeout) More info here: http://lkml.org/lkml/2007/1/21/76 Blacklist it! Signed-off-by: Paolo Ornati Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 64d2c99d15e..a169ed9849c 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -3958,6 +3958,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { "Maxtor 7V300F0", "VA111630", ATA_HORKAGE_NONCQ }, { "HITACHI HDS7250SASUN500G*", NULL, ATA_HORKAGE_NONCQ }, { "HITACHI HDS7225SBSUN250G*", NULL, ATA_HORKAGE_NONCQ }, + { "ST380817AS", "3.42", ATA_HORKAGE_NONCQ }, /* Blacklist entries taken from Silicon Image 3124/3132 Windows driver .inf file - also several Linux problem reports */ -- cgit v1.2.3-70-g09d2 From 70edb185dbaa8a9ec0d6f3e50bb5698a4e85ded6 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 4 Oct 2007 17:27:59 +0900 Subject: libata: add HDT722516DLA380 to NCQ blacklist HDT722516DLA380 does spurious completion of NCQ commands. Blacklist it. Signed-off-by: Tejun Heo Cc: Frans Pop Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index a169ed9849c..d71f0d05403 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -3968,6 +3968,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { /* Drives which do spurious command completion */ { "HTS541680J9SA00", "SB2IC7EP", ATA_HORKAGE_NONCQ, }, { "HTS541612J9SA00", "SBDIC7JP", ATA_HORKAGE_NONCQ, }, + { "HDT722516DLA380", "V43OA96A", ATA_HORKAGE_NONCQ, }, { "Hitachi HTS541616J9SA00", "SB4OC70P", ATA_HORKAGE_NONCQ, }, { "WDC WD740ADFD-00NLR1", NULL, ATA_HORKAGE_NONCQ, }, { "WDC WD3200AAJS-00RYA0", "12.01B01", ATA_HORKAGE_NONCQ, }, -- cgit v1.2.3-70-g09d2 From badff03df7a005d13ea2ae8ddc2f5ec0cfc049e8 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Thu, 4 Oct 2007 21:28:18 +0100 Subject: libata-core: Expose gtm methods for driver use Talk to the dark side our driver has to, yes. Much misleading is the data. Store it in a structure we do so that it may be parsed. Signed-off-by: Alan Cox -- Whats small, old and shouts phrases out of order across mountains ? Yodla.. Signed-off-by: Jeff Garzik --- drivers/ata/libata-acpi.c | 8 ++++++-- include/linux/libata.h | 2 ++ 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index 5ebbf16f3af..f862e07d92f 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -200,7 +200,7 @@ void ata_acpi_associate(struct ata_host *host) * RETURNS: * 0 on success, -ENOENT if _GTM doesn't exist, -errno on failure. */ -static int ata_acpi_gtm(const struct ata_port *ap, struct ata_acpi_gtm *gtm) +int ata_acpi_gtm(const struct ata_port *ap, struct ata_acpi_gtm *gtm) { struct acpi_buffer output = { .length = ACPI_ALLOCATE_BUFFER }; union acpi_object *out_obj; @@ -244,6 +244,8 @@ static int ata_acpi_gtm(const struct ata_port *ap, struct ata_acpi_gtm *gtm) return rc; } +EXPORT_SYMBOL_GPL(ata_acpi_gtm); + /** * ata_acpi_stm - execute _STM * @ap: target ATA port @@ -257,7 +259,7 @@ static int ata_acpi_gtm(const struct ata_port *ap, struct ata_acpi_gtm *gtm) * RETURNS: * 0 on success, -ENOENT if _STM doesn't exist, -errno on failure. */ -static int ata_acpi_stm(const struct ata_port *ap, struct ata_acpi_gtm *stm) +int ata_acpi_stm(const struct ata_port *ap, struct ata_acpi_gtm *stm) { acpi_status status; struct acpi_object_list input; @@ -289,6 +291,8 @@ static int ata_acpi_stm(const struct ata_port *ap, struct ata_acpi_gtm *stm) return 0; } +EXPORT_SYMBOL_GPL(ata_acpi_stm); + /** * ata_dev_get_GTF - get the drive bootup default taskfile settings * @dev: target ATA device diff --git a/include/linux/libata.h b/include/linux/libata.h index 84dfc23b9d3..751aabc21a3 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -929,6 +929,8 @@ enum { /* libata-acpi.c */ #ifdef CONFIG_ATA_ACPI extern int ata_acpi_cbl_80wire(struct ata_port *ap); +int ata_acpi_stm(const struct ata_port *ap, struct ata_acpi_gtm *stm); +int ata_acpi_gtm(const struct ata_port *ap, struct ata_acpi_gtm *stm); #else static inline int ata_acpi_cbl_80wire(struct ata_port *ap) { return 0; } #endif -- cgit v1.2.3-70-g09d2 From 025621f9a7c0efe1139d43d246136a0f3e8ea675 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Thu, 4 Oct 2007 21:32:58 +0100 Subject: pata_acpi: ACPI driver support On a cable there may be eighty wires or perhaps forty and we learn about its type In the world of ACPI So we call the GTM And we find the the timing rate And we look through it to see If eighty wire it must be Timing lives in ACPI routines ACPI routines, ACPI routines Timing lives in ACPI routines ACPI routes ACPI routines And the drivers last you see Picking up unknown pci ids and the code begins to work Timing lives in ACPI routines ACPI routines, ACPI routines Timing lives in ACPI routines ACPI routes ACPI routines [Full speed ahead, Mr Hacker, full speed ahead] Full speed over here sir! Checking Cable, checking cable Aye aye, 80 wire, Heaven heaven] If we use ACPI (ACPI) Every box (every box) has all we need (has all we need) Cable type (cable type) and mode timing (mode timing) In our ATA (in our ATA) subroutines (subroutines, ha ha) Timing lives in ACPI routines ACPI routines, ACPI routines Timing lives in ACPI routines ACPI routes ACPI routines Timing lives in ACPI routines ACPI routines, ACPI routines Timing lives in ACPI routines ACPI routes ACPI routines Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/Kconfig | 9 ++ drivers/ata/Makefile | 2 + drivers/ata/pata_acpi.c | 395 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 406 insertions(+) create mode 100644 drivers/ata/pata_acpi.c (limited to 'drivers') diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index cf960bd1c00..4672066167e 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -173,6 +173,15 @@ config SATA_INIC162X help This option enables support for Initio 162x Serial ATA. +config PATA_ACPI + tristate "ACPI firmware driver for PATA" + depends on ATA_ACPI + help + This option enables an ACPI method driver which drives + motherboard PATA controller interfaces through the ACPI + firmware in the BIOS. This driver can sometimes handle + otherwise unsupported hardware. + config PATA_ALI tristate "ALi PATA support (Experimental)" depends on PCI && EXPERIMENTAL diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 7e937519a93..2a63645003e 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -66,6 +66,8 @@ obj-$(CONFIG_PATA_SCC) += pata_scc.o obj-$(CONFIG_PATA_BF54X) += pata_bf54x.o obj-$(CONFIG_PATA_PLATFORM) += pata_platform.o obj-$(CONFIG_PATA_ICSIDE) += pata_icside.o +# Should be last but two libata driver +obj-$(CONFIG_PATA_ACPI) += pata_acpi.o # Should be last but one libata driver obj-$(CONFIG_ATA_GENERIC) += ata_generic.o # Should be last libata driver diff --git a/drivers/ata/pata_acpi.c b/drivers/ata/pata_acpi.c new file mode 100644 index 00000000000..5d3920f6fd6 --- /dev/null +++ b/drivers/ata/pata_acpi.c @@ -0,0 +1,395 @@ +/* + * ACPI PATA driver + * + * (c) 2007 Red Hat + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define DRV_NAME "pata_acpi" +#define DRV_VERSION "0.2.3" + +struct pata_acpi { + struct ata_acpi_gtm gtm; + void *last; + unsigned long mask[2]; +}; + +/** + * pacpi_pre_reset - check for 40/80 pin + * @ap: Port + * @deadline: deadline jiffies for the operation + * + * Perform the PATA port setup we need. + */ + +static int pacpi_pre_reset(struct ata_link *link, unsigned long deadline) +{ + struct ata_port *ap = link->ap; + struct pata_acpi *acpi = ap->private_data; + if (ap->acpi_handle == NULL || ata_acpi_gtm(ap, &acpi->gtm) < 0) + return -ENODEV; + + return ata_std_prereset(link, deadline); +} + +/** + * pacpi_cable_detect - cable type detection + * @ap: port to detect + * + * Perform device specific cable detection + */ + +static int pacpi_cable_detect(struct ata_port *ap) +{ + struct pata_acpi *acpi = ap->private_data; + + if ((acpi->mask[0] | acpi->mask[1]) & (0xF8 << ATA_SHIFT_UDMA)) + return ATA_CBL_PATA80; + else + return ATA_CBL_PATA40; +} + +/** + * pacpi_error_handler - Setup and error handler + * @ap: Port to handle + * + * LOCKING: + * None (inherited from caller). + */ + +static void pacpi_error_handler(struct ata_port *ap) +{ + return ata_bmdma_drive_eh(ap, pacpi_pre_reset, ata_std_softreset, + NULL, ata_std_postreset); +} + +/* Welcome to ACPI, bring a bucket */ +static const unsigned int pio_cycle[7] = { + 600, 383, 240, 180, 120, 100, 80 +}; +static const unsigned int mwdma_cycle[5] = { + 480, 150, 120, 100, 80 +}; +static const unsigned int udma_cycle[7] = { + 120, 80, 60, 45, 30, 20, 15 +}; + +/** + * pacpi_discover_modes - filter non ACPI modes + * @adev: ATA device + * @mask: proposed modes + * + * Try the modes available and see which ones the ACPI method will + * set up sensibly. From this we get a mask of ACPI modes we can use + */ + +static unsigned long pacpi_discover_modes(struct ata_port *ap, struct ata_device *adev) +{ + int unit = adev->devno; + struct pata_acpi *acpi = ap->private_data; + int i; + u32 t; + unsigned long mask = (0x7f << ATA_SHIFT_UDMA) | (0x7 << ATA_SHIFT_MWDMA) | (0x1F << ATA_SHIFT_PIO); + + struct ata_acpi_gtm probe; + + probe = acpi->gtm; + + /* We always use the 0 slot for crap hardware */ + if (!(probe.flags & 0x10)) + unit = 0; + + ata_acpi_gtm(ap, &probe); + + /* Start by scanning for PIO modes */ + for (i = 0; i < 7; i++) { + t = probe.drive[unit].pio; + if (t <= pio_cycle[i]) { + mask |= (2 << (ATA_SHIFT_PIO + i)) - 1; + break; + } + } + + /* See if we have MWDMA or UDMA data. We don't bother with MWDMA + if UDMA is availabe as this means the BIOS set UDMA and our + error changedown if it works is UDMA to PIO anyway */ + if (probe.flags & (1 << (2 * unit))) { + /* MWDMA */ + for (i = 0; i < 5; i++) { + t = probe.drive[unit].dma; + if (t <= mwdma_cycle[i]) { + mask |= (2 << (ATA_SHIFT_MWDMA + i)) - 1; + break; + } + } + } else { + /* UDMA */ + for (i = 0; i < 7; i++) { + t = probe.drive[unit].dma; + if (t <= udma_cycle[i]) { + mask |= (2 << (ATA_SHIFT_UDMA + i)) - 1; + break; + } + } + } + if (mask & (0xF8 << ATA_SHIFT_UDMA)) + ap->cbl = ATA_CBL_PATA80; + return mask; +} + +/** + * pacpi_mode_filter - mode filter for ACPI + * @adev: device + * @mask: mask of valid modes + * + * Filter the valid mode list according to our own specific rules, in + * this case the list of discovered valid modes obtained by ACPI probing + */ + +static unsigned long pacpi_mode_filter(struct ata_device *adev, unsigned long mask) +{ + struct pata_acpi *acpi = adev->link->ap->private_data; + return ata_pci_default_filter(adev, mask & acpi->mask[adev->devno]); +} + +/** + * pacpi_set_piomode - set initial PIO mode data + * @ap: ATA interface + * @adev: ATA device + */ + +static void pacpi_set_piomode(struct ata_port *ap, struct ata_device *adev) +{ + int unit = adev->devno; + struct pata_acpi *acpi = ap->private_data; + + if(!(acpi->gtm.flags & 0x10)) + unit = 0; + + /* Now stuff the nS values into the structure */ + acpi->gtm.drive[unit].pio = pio_cycle[adev->pio_mode - XFER_PIO_0]; + ata_acpi_stm(ap, &acpi->gtm); + /* See what mode we actually got */ + ata_acpi_gtm(ap, &acpi->gtm); +} + +/** + * pacpi_set_dmamode - set initial DMA mode data + * @ap: ATA interface + * @adev: ATA device + */ + +static void pacpi_set_dmamode(struct ata_port *ap, struct ata_device *adev) +{ + int unit = adev->devno; + struct pata_acpi *acpi = ap->private_data; + + if(!(acpi->gtm.flags & 0x10)) + unit = 0; + + /* Now stuff the nS values into the structure */ + if (adev->dma_mode >= XFER_UDMA_0) { + acpi->gtm.drive[unit].dma = udma_cycle[adev->dma_mode - XFER_UDMA_0]; + acpi->gtm.flags |= (1 << (2 * unit)); + } else { + acpi->gtm.drive[unit].dma = mwdma_cycle[adev->dma_mode - XFER_MW_DMA_0]; + acpi->gtm.flags &= ~(1 << (2 * unit)); + } + ata_acpi_stm(ap, &acpi->gtm); + /* See what mode we actually got */ + ata_acpi_gtm(ap, &acpi->gtm); +} + +/** + * pacpi_qc_issue_prot - command issue + * @qc: command pending + * + * Called when the libata layer is about to issue a command. We wrap + * this interface so that we can load the correct ATA timings if + * neccessary. + */ + +static unsigned int pacpi_qc_issue_prot(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct ata_device *adev = qc->dev; + struct pata_acpi *acpi = ap->private_data; + + if (acpi->gtm.flags & 0x10) + return ata_qc_issue_prot(qc); + + if (adev != acpi->last) { + pacpi_set_piomode(ap, adev); + if (adev->dma_mode) + pacpi_set_dmamode(ap, adev); + acpi->last = adev; + } + return ata_qc_issue_prot(qc); +} + +/** + * pacpi_port_start - port setup + * @ap: ATA port being set up + * + * Use the port_start hook to maintain private control structures + */ + +static int pacpi_port_start(struct ata_port *ap) +{ + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + struct pata_acpi *acpi; + + int ret; + + if (ap->acpi_handle == NULL) + return -ENODEV; + + acpi = ap->private_data = devm_kzalloc(&pdev->dev, sizeof(struct pata_acpi), GFP_KERNEL); + if (ap->private_data == NULL) + return -ENOMEM; + acpi->mask[0] = pacpi_discover_modes(ap, &ap->link.device[0]); + acpi->mask[1] = pacpi_discover_modes(ap, &ap->link.device[1]); + ret = ata_sff_port_start(ap); + if (ret < 0) + return ret; + + return ret; +} + +static struct scsi_host_template pacpi_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, + .queuecommand = ata_scsi_queuecmd, + .can_queue = ATA_DEF_QUEUE, + .this_id = ATA_SHT_THIS_ID, + .sg_tablesize = LIBATA_MAX_PRD, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ATA_SHT_USE_CLUSTERING, + .proc_name = DRV_NAME, + .dma_boundary = ATA_DMA_BOUNDARY, + .slave_configure = ata_scsi_slave_config, + .slave_destroy = ata_scsi_slave_destroy, + /* Use standard CHS mapping rules */ + .bios_param = ata_std_bios_param, +}; + +static const struct ata_port_operations pacpi_ops = { + .set_piomode = pacpi_set_piomode, + .set_dmamode = pacpi_set_dmamode, + .mode_filter = pacpi_mode_filter, + + /* Task file is PCI ATA format, use helpers */ + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, + + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, + .error_handler = pacpi_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, + .cable_detect = pacpi_cable_detect, + + /* BMDMA handling is PCI ATA format, use helpers */ + .bmdma_setup = ata_bmdma_setup, + .bmdma_start = ata_bmdma_start, + .bmdma_stop = ata_bmdma_stop, + .bmdma_status = ata_bmdma_status, + .qc_prep = ata_qc_prep, + .qc_issue = pacpi_qc_issue_prot, + .data_xfer = ata_data_xfer, + + /* Timeout handling */ + .irq_handler = ata_interrupt, + .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + + /* Generic PATA PCI ATA helpers */ + .port_start = pacpi_port_start, +}; + + +/** + * pacpi_init_one - Register ACPI ATA PCI device with kernel services + * @pdev: PCI device to register + * @ent: Entry in pacpi_pci_tbl matching with @pdev + * + * Called from kernel PCI layer. + * + * LOCKING: + * Inherited from PCI layer (may sleep). + * + * RETURNS: + * Zero on success, or -ERRNO value. + */ + +static int pacpi_init_one (struct pci_dev *pdev, const struct pci_device_id *id) +{ + static const struct ata_port_info info = { + .sht = &pacpi_sht, + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + + .pio_mask = 0x1f, + .mwdma_mask = 0x07, + .udma_mask = 0x7f, + + .port_ops = &pacpi_ops, + }; + const struct ata_port_info *ppi[] = { &info, NULL }; + return ata_pci_init_one(pdev, ppi); +} + +static const struct pci_device_id pacpi_pci_tbl[] = { + { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL, 1}, + { } /* terminate list */ +}; + +static struct pci_driver pacpi_pci_driver = { + .name = DRV_NAME, + .id_table = pacpi_pci_tbl, + .probe = pacpi_init_one, + .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, +}; + +static int __init pacpi_init(void) +{ + return pci_register_driver(&pacpi_pci_driver); +} + +static void __exit pacpi_exit(void) +{ + pci_unregister_driver(&pacpi_pci_driver); +} + +module_init(pacpi_init); +module_exit(pacpi_exit); + +MODULE_AUTHOR("Alan Cox"); +MODULE_DESCRIPTION("SCSI low-level driver for ATA in ACPI mode"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, pacpi_pci_tbl); +MODULE_VERSION(DRV_VERSION); + -- cgit v1.2.3-70-g09d2 From 954bb005c9d5368188ef03ff1d723ff3c0e8ae99 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 5 Oct 2007 08:54:39 +0900 Subject: libata: add ST9160821AS / 3.ALD to NCQ blacklist ST9160821AS / 3.ALD also does spurious NCQ completions. Disable NCQ. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index d71f0d05403..519ce586bd1 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -3975,6 +3975,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { "FUJITSU MHV2080BH", "00840028", ATA_HORKAGE_NONCQ, }, { "ST9120822AS", "3.CLF", ATA_HORKAGE_NONCQ, }, { "ST9160821AS", "3.CLF", ATA_HORKAGE_NONCQ, }, + { "ST9160821AS", "3.ALD", ATA_HORKAGE_NONCQ, }, { "ST3160812AS", "3.ADJ", ATA_HORKAGE_NONCQ, }, { "ST980813AS", "3.ADB", ATA_HORKAGE_NONCQ, }, { "SAMSUNG HD401LJ", "ZZ100-15", ATA_HORKAGE_NONCQ, }, -- cgit v1.2.3-70-g09d2 From a01f48b8e7f5ca1000d662fe205e6fe884e0d132 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 7 Oct 2007 07:04:50 +0900 Subject: pata_jmicron: match vendor and class code only PATA part of all current JMB controllers behave the same way and JMicron confirms that all future ones will stay compatible. Drop device matching and match only vendor and class. Signed-off-by: Tejun Heo Cc: Ethan Hsiao Cc: Justin Tsai Signed-off-by: Jeff Garzik --- drivers/ata/pata_jmicron.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c index 6d5a81869df..225a7223a72 100644 --- a/drivers/ata/pata_jmicron.c +++ b/drivers/ata/pata_jmicron.c @@ -204,17 +204,8 @@ static int jmicron_init_one (struct pci_dev *pdev, const struct pci_device_id *i } static const struct pci_device_id jmicron_pci_tbl[] = { - { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB361, - PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 361 }, - { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB363, - PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 363 }, - { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB365, - PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 365 }, - { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB366, - PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 366 }, - { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB368, - PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 368 }, - + { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 0 }, { } /* terminate list */ }; -- cgit v1.2.3-70-g09d2 From abf6e8ed07213bdd9734be2e42639b79310bd81c Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 9 Oct 2007 14:57:25 +0900 Subject: libata: clear ehi description after initial host report ehi description field is used to carry LLD specific controller description. Sometimes, it's used without clearing before and LLD description gets printed with exception information one more time. Clear after printing. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 519ce586bd1..db760e2dc30 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -6773,13 +6773,14 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) xfer_mask = ata_pack_xfermask(ap->pio_mask, ap->mwdma_mask, ap->udma_mask); - if (!ata_port_is_dummy(ap)) + if (!ata_port_is_dummy(ap)) { ata_port_printk(ap, KERN_INFO, "%cATA max %s %s\n", (ap->flags & ATA_FLAG_SATA) ? 'S' : 'P', ata_mode_string(xfer_mask), ap->link.eh_info.desc); - else + ata_ehi_clear_desc(&ap->link.eh_info); + } else ata_port_printk(ap, KERN_INFO, "DUMMY\n"); } -- cgit v1.2.3-70-g09d2 From 94ff3d54080975686a3c41e73b8926030ee0c31f Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 9 Oct 2007 14:57:56 +0900 Subject: libata: skip suppress reporting if ATA_EHI_QUIET ATA_EHI_NO_AUTOPSY and ATA_EHI_QUIET are used during initial probing to skip exception analysis and reporting. Usually, there's nothing to report but on some allowed but rare corner cases (e.g. phy status changed interrupt when IRQ is enabled on frozen port - this happens if IRQ pending status isn't cleared in the IRQ router or controller) exception messages get printed. Skip reporting if ATA_EHI_QUIET is set. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-eh.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 0bd3898793a..866ac9d5530 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1868,6 +1868,9 @@ static void ata_eh_link_report(struct ata_link *link) char tries_buf[6]; int tag, nr_failed = 0; + if (ehc->i.flags & ATA_EHI_QUIET) + return; + desc = NULL; if (ehc->i.desc[0] != '\0') desc = ehc->i.desc; -- cgit v1.2.3-70-g09d2 From 9073868376ed5fa1f247327ccb2e6f766d5b7eed Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 9 Oct 2007 14:58:33 +0900 Subject: libata: wrap schedule_timeout_uninterruptible() in loop Tasks in uninterruptible sleep might be woken up by unrelated events and should check whether the condition it was waiting for has actually triggered. Wrap schedule_timeout_uninterruptible() in loop to achieve it. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-eh.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 866ac9d5530..8aa61403303 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -2183,7 +2183,8 @@ int ata_eh_reset(struct ata_link *link, int classify, "(errno=%d), retrying in %u secs\n", rc, (jiffies_to_msecs(delta) + 999) / 1000); - schedule_timeout_uninterruptible(delta); + while (delta) + delta = schedule_timeout_uninterruptible(delta); } if (rc == -EPIPE || -- cgit v1.2.3-70-g09d2 From 75da6d2b8f518bec40546bc0b0696a2cebecf6cc Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 9 Oct 2007 14:59:50 +0900 Subject: ahci: kill leftover from enabling NCQ over PMP ahci had problems with NCQ over PMP and NCQ used to be disabled while PMP was attached. After fixing the problem, the temporary NCQ disabling code wasn't removed completely. Kill the remaining piece. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 24fb90f58cd..694eabcb932 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1677,19 +1677,11 @@ static void ahci_pmp_attach(struct ata_port *ap) static void ahci_pmp_detach(struct ata_port *ap) { void __iomem *port_mmio = ahci_port_base(ap); - struct ahci_host_priv *hpriv = ap->host->private_data; - unsigned long flags; u32 cmd; cmd = readl(port_mmio + PORT_CMD); cmd &= ~PORT_CMD_PMP; writel(cmd, port_mmio + PORT_CMD); - - if (hpriv->cap & HOST_CAP_NCQ) { - spin_lock_irqsave(ap->lock, flags); - ap->flags |= ATA_FLAG_NCQ; - spin_unlock_irqrestore(ap->lock, flags); - } } static int ahci_pmp_read(struct ata_device *dev, int pmp, int reg, u32 *r_val) -- cgit v1.2.3-70-g09d2 From 1c954a4d9a9e351fa3509533fd8dd5f3821206cd Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 9 Oct 2007 15:01:37 +0900 Subject: ahci: clean up PORT_IRQ_BAD_PMP enabling Now that we have pp->intr_mask, move PORT_IRQ_BAD_PMP enabling to ahci_pmp_attach/detach() where it belongs. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 694eabcb932..6633c7422fc 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1620,11 +1620,8 @@ static void ahci_thaw(struct ata_port *ap) writel(tmp, port_mmio + PORT_IRQ_STAT); writel(1 << ap->port_no, mmio + HOST_IRQ_STAT); - /* turn IRQ back on, ignore BAD_PMP if PMP isn't attached */ - tmp = pp->intr_mask; - if (!ap->nr_pmp_links) - tmp &= ~PORT_IRQ_BAD_PMP; - writel(tmp, port_mmio + PORT_IRQ_MASK); + /* turn IRQ back on */ + writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); } static void ahci_error_handler(struct ata_port *ap) @@ -1667,21 +1664,29 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc) static void ahci_pmp_attach(struct ata_port *ap) { void __iomem *port_mmio = ahci_port_base(ap); + struct ahci_port_priv *pp = ap->private_data; u32 cmd; cmd = readl(port_mmio + PORT_CMD); cmd |= PORT_CMD_PMP; writel(cmd, port_mmio + PORT_CMD); + + pp->intr_mask |= PORT_IRQ_BAD_PMP; + writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); } static void ahci_pmp_detach(struct ata_port *ap) { void __iomem *port_mmio = ahci_port_base(ap); + struct ahci_port_priv *pp = ap->private_data; u32 cmd; cmd = readl(port_mmio + PORT_CMD); cmd &= ~PORT_CMD_PMP; writel(cmd, port_mmio + PORT_CMD); + + pp->intr_mask &= ~PORT_IRQ_BAD_PMP; + writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); } static int ahci_pmp_read(struct ata_device *dev, int pmp, int reg, u32 *r_val) -- cgit v1.2.3-70-g09d2 From 5f226c6bf78edab023ed1ea679531731d9df92a6 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 9 Oct 2007 15:02:23 +0900 Subject: ahci: fix notification handling Asynchronous notification on ICH9 didn't work because it didn't write AN FIS into the RX area - it only updates SNotification. Also, snooping SDB_FIS RX area is racy against further SDB FIS receptions. Let sata_async_notification() determine using SNTF if it's available and snoop RX area iff SNTF isn't available Signed-off-by: Tejun Heo Cc: Kristen Carlson Accardi Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 6633c7422fc..abfb72aae3d 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1420,6 +1420,7 @@ static void ahci_port_intr(struct ata_port *ap) void __iomem *port_mmio = ap->ioaddr.cmd_addr; struct ata_eh_info *ehi = &ap->link.eh_info; struct ahci_port_priv *pp = ap->private_data; + struct ahci_host_priv *hpriv = ap->host->private_data; u32 status, qc_active; int rc, known_irq = 0; @@ -1432,17 +1433,28 @@ static void ahci_port_intr(struct ata_port *ap) } if (status & PORT_IRQ_SDB_FIS) { - /* If the 'N' bit in word 0 of the FIS is set, we just - * received asynchronous notification. Tell libata - * about it. Note that as the SDB FIS itself is - * accessible, SNotification can be emulated by the - * driver but don't bother for the time being. + /* If SNotification is available, leave notification + * handling to sata_async_notification(). If not, + * emulate it by snooping SDB FIS RX area. + * + * Snooping FIS RX area is probably cheaper than + * poking SNotification but some constrollers which + * implement SNotification, ICH9 for example, don't + * store AN SDB FIS into receive area. */ - const __le32 *f = pp->rx_fis + RX_FIS_SDB; - u32 f0 = le32_to_cpu(f[0]); - - if (f0 & (1 << 15)) + if (hpriv->cap & HOST_CAP_SNTF) sata_async_notification(ap); + else { + /* If the 'N' bit in word 0 of the FIS is set, + * we just received asynchronous notification. + * Tell libata about it. + */ + const __le32 *f = pp->rx_fis + RX_FIS_SDB; + u32 f0 = le32_to_cpu(f[0]); + + if (f0 & (1 << 15)) + sata_async_notification(ap); + } } /* pp->active_link is valid iff any command is in flight */ -- cgit v1.2.3-70-g09d2 From 2b789108fc1dcba22050a7e6e29ae5ebaea427dd Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 9 Oct 2007 15:05:44 +0900 Subject: libata: add @timeout to ata_exec_internal[_sg]() Add @timeout argument to ata_exec_internal[_sg](). If 0, default timeout ata_probe_timeout is used. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-acpi.c | 2 +- drivers/ata/libata-core.c | 32 ++++++++++++++++++++------------ drivers/ata/libata-eh.c | 4 ++-- drivers/ata/libata.h | 5 +++-- 4 files changed, 26 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index f862e07d92f..3f753358904 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -478,7 +478,7 @@ static int taskfile_load_raw(struct ata_device *dev, tf.lbal, tf.lbam, tf.lbah, tf.device); rtf = tf; - err_mask = ata_exec_internal(dev, &rtf, NULL, DMA_NONE, NULL, 0); + err_mask = ata_exec_internal(dev, &rtf, NULL, DMA_NONE, NULL, 0, 0); if (err_mask) { ata_dev_printk(dev, KERN_ERR, "ACPI cmd %02x/%02x:%02x:%02x:%02x:%02x:%02x failed " diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index db760e2dc30..59ebc5d5100 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -926,7 +926,7 @@ static int ata_read_native_max_address(struct ata_device *dev, u64 *max_sectors) tf.protocol |= ATA_PROT_NODATA; tf.device |= ATA_LBA; - err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0); if (err_mask) { ata_dev_printk(dev, KERN_WARNING, "failed to read native " "max address (err_mask=0x%x)\n", err_mask); @@ -988,7 +988,7 @@ static int ata_set_max_sectors(struct ata_device *dev, u64 new_sectors) tf.lbam = (new_sectors >> 8) & 0xff; tf.lbah = (new_sectors >> 16) & 0xff; - err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0); if (err_mask) { ata_dev_printk(dev, KERN_WARNING, "failed to set " "max address (err_mask=0x%x)\n", err_mask); @@ -1394,6 +1394,7 @@ static void ata_qc_complete_internal(struct ata_queued_cmd *qc) * @dma_dir: Data tranfer direction of the command * @sg: sg list for the data buffer of the command * @n_elem: Number of sg entries + * @timeout: Timeout in msecs (0 for default) * * Executes libata internal command with timeout. @tf contains * command on entry and result on return. Timeout and error @@ -1410,7 +1411,7 @@ static void ata_qc_complete_internal(struct ata_queued_cmd *qc) unsigned ata_exec_internal_sg(struct ata_device *dev, struct ata_taskfile *tf, const u8 *cdb, int dma_dir, struct scatterlist *sg, - unsigned int n_elem) + unsigned int n_elem, unsigned long timeout) { struct ata_link *link = dev->link; struct ata_port *ap = link->ap; @@ -1486,7 +1487,10 @@ unsigned ata_exec_internal_sg(struct ata_device *dev, spin_unlock_irqrestore(ap->lock, flags); - rc = wait_for_completion_timeout(&wait, ata_probe_timeout); + if (!timeout) + timeout = ata_probe_timeout * 1000 / HZ; + + rc = wait_for_completion_timeout(&wait, msecs_to_jiffies(timeout)); ata_port_flush_task(ap); @@ -1571,6 +1575,7 @@ unsigned ata_exec_internal_sg(struct ata_device *dev, * @dma_dir: Data tranfer direction of the command * @buf: Data buffer of the command * @buflen: Length of data buffer + * @timeout: Timeout in msecs (0 for default) * * Wrapper around ata_exec_internal_sg() which takes simple * buffer instead of sg list. @@ -1583,7 +1588,8 @@ unsigned ata_exec_internal_sg(struct ata_device *dev, */ unsigned ata_exec_internal(struct ata_device *dev, struct ata_taskfile *tf, const u8 *cdb, - int dma_dir, void *buf, unsigned int buflen) + int dma_dir, void *buf, unsigned int buflen, + unsigned long timeout) { struct scatterlist *psg = NULL, sg; unsigned int n_elem = 0; @@ -1595,7 +1601,8 @@ unsigned ata_exec_internal(struct ata_device *dev, n_elem++; } - return ata_exec_internal_sg(dev, tf, cdb, dma_dir, psg, n_elem); + return ata_exec_internal_sg(dev, tf, cdb, dma_dir, psg, n_elem, + timeout); } /** @@ -1622,7 +1629,7 @@ unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd) tf.flags |= ATA_TFLAG_DEVICE; tf.protocol = ATA_PROT_NODATA; - return ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); + return ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0); } /** @@ -1737,7 +1744,7 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, tf.flags |= ATA_TFLAG_POLLING; err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE, - id, sizeof(id[0]) * ATA_ID_WORDS); + id, sizeof(id[0]) * ATA_ID_WORDS, 0); if (err_mask) { if (err_mask & AC_ERR_NODEV_HINT) { DPRINTK("ata%u.%d: NODEV after polling detection\n", @@ -1796,7 +1803,8 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, tf.feature = SETFEATURES_SPINUP; tf.protocol = ATA_PROT_NODATA; tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; - err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); + err_mask = ata_exec_internal(dev, &tf, NULL, + DMA_NONE, NULL, 0, 0); if (err_mask && id[2] != 0x738c) { rc = -EIO; reason = "SPINUP failed"; @@ -4157,7 +4165,7 @@ static unsigned int ata_dev_set_xfermode(struct ata_device *dev) tf.protocol = ATA_PROT_NODATA; tf.nsect = dev->xfer_mode; - err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0); DPRINTK("EXIT, err_mask=%x\n", err_mask); return err_mask; @@ -4193,7 +4201,7 @@ static unsigned int ata_dev_set_AN(struct ata_device *dev, u8 enable) tf.protocol = ATA_PROT_NODATA; tf.nsect = SATA_AN; - err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0); DPRINTK("EXIT, err_mask=%x\n", err_mask); return err_mask; @@ -4231,7 +4239,7 @@ static unsigned int ata_dev_init_params(struct ata_device *dev, tf.nsect = sectors; tf.device |= (heads - 1) & 0x0f; /* max head = num. of heads - 1 */ - err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0); /* A clean abort indicates an original or just out of spec drive and we should continue as we issue the setup based on the drive reported working geometry */ diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 8aa61403303..c0e9a42e6ae 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1249,7 +1249,7 @@ static unsigned int ata_read_log_page(struct ata_device *dev, tf.protocol = ATA_PROT_PIO; err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE, - buf, sectors * ATA_SECT_SIZE); + buf, sectors * ATA_SECT_SIZE, 0); DPRINTK("EXIT, err_mask=%x\n", err_mask); return err_mask; @@ -1363,7 +1363,7 @@ static unsigned int atapi_eh_request_sense(struct ata_queued_cmd *qc) } return ata_exec_internal(dev, &tf, cdb, DMA_FROM_DEVICE, - sense_buf, SCSI_SENSE_BUFFERSIZE); + sense_buf, SCSI_SENSE_BUFFERSIZE, 0); } /** diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index f8bd955c5ba..90df58a3edc 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -69,11 +69,12 @@ extern void ata_dev_disable(struct ata_device *dev); extern void ata_port_flush_task(struct ata_port *ap); extern unsigned ata_exec_internal(struct ata_device *dev, struct ata_taskfile *tf, const u8 *cdb, - int dma_dir, void *buf, unsigned int buflen); + int dma_dir, void *buf, unsigned int buflen, + unsigned long timeout); extern unsigned ata_exec_internal_sg(struct ata_device *dev, struct ata_taskfile *tf, const u8 *cdb, int dma_dir, struct scatterlist *sg, - unsigned int n_elem); + unsigned int n_elem, unsigned long timeout); extern unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd); extern int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, unsigned int flags, u16 *id); -- cgit v1.2.3-70-g09d2 From afaa5c373d2c49ee4865847031b82f1377f609d0 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 9 Oct 2007 15:06:10 +0900 Subject: libata: implement ATA_PFLAG_RESETTING Implement ATA_PFLAG_RESETTING. This flag is set while reset is in progress. It's set before prereset is called and cleared after reset fails or postreset is finished. This flag itself doesn't have any function. It will be used by LLDs to tell whether reset is in progress if it needs to behave differently during reset. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-eh.c | 11 +++++++++++ include/linux/libata.h | 1 + 2 files changed, 12 insertions(+) (limited to 'drivers') diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index c0e9a42e6ae..1f84e40fa6a 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -2063,6 +2063,7 @@ int ata_eh_reset(struct ata_link *link, int classify, ata_prereset_fn_t prereset, ata_reset_fn_t softreset, ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) { + struct ata_port *ap = link->ap; struct ata_eh_context *ehc = &link->eh_context; unsigned int *classes = ehc->classes; int verbose = !(ehc->i.flags & ATA_EHI_QUIET); @@ -2071,9 +2072,14 @@ int ata_eh_reset(struct ata_link *link, int classify, unsigned long deadline; unsigned int action; ata_reset_fn_t reset; + unsigned long flags; int rc; /* about to reset */ + spin_lock_irqsave(ap->lock, flags); + ap->pflags |= ATA_PFLAG_RESETTING; + spin_unlock_irqrestore(ap->lock, flags); + ata_eh_about_to_do(link, NULL, ehc->i.action & ATA_EH_RESET_MASK); /* Determine which reset to use and record in ehc->i.action. @@ -2231,6 +2237,11 @@ int ata_eh_reset(struct ata_link *link, int classify, out: /* clear hotplug flag */ ehc->i.flags &= ~ATA_EHI_HOTPLUGGED; + + spin_lock_irqsave(ap->lock, flags); + ap->pflags &= ~ATA_PFLAG_RESETTING; + spin_unlock_irqrestore(ap->lock, flags); + return rc; } diff --git a/include/linux/libata.h b/include/linux/libata.h index 751aabc21a3..529af9fbed5 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -210,6 +210,7 @@ enum { ATA_PFLAG_UNLOADING = (1 << 5), /* module is unloading */ ATA_PFLAG_SCSI_HOTPLUG = (1 << 6), /* SCSI hotplug scheduled */ ATA_PFLAG_INITIALIZING = (1 << 7), /* being initialized, don't touch */ + ATA_PFLAG_RESETTING = (1 << 8), /* reset in progress */ ATA_PFLAG_SUSPENDED = (1 << 17), /* port is suspended (power) */ ATA_PFLAG_PM_PENDING = (1 << 18), /* PM operation pending */ -- cgit v1.2.3-70-g09d2 From b06ce3e51e3df4394a584c234f11240b1c6f8d5b Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 9 Oct 2007 15:06:48 +0900 Subject: libata: use ata_exec_internal() for PMP register access PMP registers used to be accessed with dedicated accessors ->pmp_read and ->pmp_write. During reset, those callbacks are called with the port frozen so they should be able to run without depending on interrupt delivery. To achieve this, they were implemented polling. However, as resetting the host port makes the PMP to isolate fan-out ports until SError.X is cleared, resetting fan-out ports while port is frozen doesn't buy much additional safety. This patch updates libata PMP support such that PMP registers are accessed using regular ata_exec_internal() mechanism and kills ->pmp_read/write() callbacks. The following changes are made. * PMP access helpers - sata_pmp_read_init_tf(), sata_pmp_read_val(), sata_pmp_write_init_tf() are folded into sata_pmp_read/write() which are now standalone PMP register access functions. * sata_pmp_read/write() returns err_mask instead of rc. This is consistent with other functions which issue internal commands and allows more detailed error reporting. * ahci interrupt handler is modified to ignore BAD_PMP and spurious/illegal completion IRQs while reset is in progress. These conditions are expected during reset. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 48 +++-------- drivers/ata/libata-core.c | 3 - drivers/ata/libata-eh.c | 17 +++- drivers/ata/libata-pmp.c | 209 ++++++++++++++++++++-------------------------- drivers/ata/sata_sil24.c | 30 ------- include/linux/libata.h | 8 -- 6 files changed, 118 insertions(+), 197 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index abfb72aae3d..10bc3f64c45 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -239,8 +239,6 @@ static void ahci_freeze(struct ata_port *ap); static void ahci_thaw(struct ata_port *ap); static void ahci_pmp_attach(struct ata_port *ap); static void ahci_pmp_detach(struct ata_port *ap); -static int ahci_pmp_read(struct ata_device *dev, int pmp, int reg, u32 *r_val); -static int ahci_pmp_write(struct ata_device *dev, int pmp, int reg, u32 val); static void ahci_error_handler(struct ata_port *ap); static void ahci_vt8251_error_handler(struct ata_port *ap); static void ahci_post_internal_cmd(struct ata_queued_cmd *qc); @@ -297,8 +295,6 @@ static const struct ata_port_operations ahci_ops = { .pmp_attach = ahci_pmp_attach, .pmp_detach = ahci_pmp_detach, - .pmp_read = ahci_pmp_read, - .pmp_write = ahci_pmp_write, #ifdef CONFIG_PM .port_suspend = ahci_port_suspend, @@ -333,8 +329,6 @@ static const struct ata_port_operations ahci_vt8251_ops = { .pmp_attach = ahci_pmp_attach, .pmp_detach = ahci_pmp_detach, - .pmp_read = ahci_pmp_read, - .pmp_write = ahci_pmp_write, #ifdef CONFIG_PM .port_suspend = ahci_port_suspend, @@ -1421,12 +1415,17 @@ static void ahci_port_intr(struct ata_port *ap) struct ata_eh_info *ehi = &ap->link.eh_info; struct ahci_port_priv *pp = ap->private_data; struct ahci_host_priv *hpriv = ap->host->private_data; + int resetting = !!(ap->pflags & ATA_PFLAG_RESETTING); u32 status, qc_active; int rc, known_irq = 0; status = readl(port_mmio + PORT_IRQ_STAT); writel(status, port_mmio + PORT_IRQ_STAT); + /* ignore BAD_PMP while resetting */ + if (unlikely(resetting)) + status &= ~PORT_IRQ_BAD_PMP; + if (unlikely(status & PORT_IRQ_ERROR)) { ahci_error_intr(ap, status); return; @@ -1464,6 +1463,13 @@ static void ahci_port_intr(struct ata_port *ap) qc_active = readl(port_mmio + PORT_CMD_ISSUE); rc = ata_qc_complete_multiple(ap, qc_active, NULL); + + /* If resetting, spurious or invalid completions are expected, + * return unconditionally. + */ + if (resetting) + return; + if (rc > 0) return; if (rc < 0) { @@ -1701,36 +1707,6 @@ static void ahci_pmp_detach(struct ata_port *ap) writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); } -static int ahci_pmp_read(struct ata_device *dev, int pmp, int reg, u32 *r_val) -{ - struct ata_port *ap = dev->link->ap; - struct ata_taskfile tf; - int rc; - - ahci_kick_engine(ap, 0); - - sata_pmp_read_init_tf(&tf, dev, pmp, reg); - rc = ahci_exec_polled_cmd(ap, SATA_PMP_CTRL_PORT, &tf, 1, 0, - SATA_PMP_SCR_TIMEOUT); - if (rc == 0) { - ahci_tf_read(ap, &tf); - *r_val = sata_pmp_read_val(&tf); - } - return rc; -} - -static int ahci_pmp_write(struct ata_device *dev, int pmp, int reg, u32 val) -{ - struct ata_port *ap = dev->link->ap; - struct ata_taskfile tf; - - ahci_kick_engine(ap, 0); - - sata_pmp_write_init_tf(&tf, dev, pmp, reg, val); - return ahci_exec_polled_cmd(ap, SATA_PMP_CTRL_PORT, &tf, 1, 0, - SATA_PMP_SCR_TIMEOUT); -} - static int ahci_port_resume(struct ata_port *ap) { ahci_power_up(ap); diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 59ebc5d5100..ce8ccb434af 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -7354,9 +7354,6 @@ EXPORT_SYMBOL_GPL(ata_pci_clear_simplex); #endif /* CONFIG_PCI */ EXPORT_SYMBOL_GPL(sata_pmp_qc_defer_cmd_switch); -EXPORT_SYMBOL_GPL(sata_pmp_read_init_tf); -EXPORT_SYMBOL_GPL(sata_pmp_read_val); -EXPORT_SYMBOL_GPL(sata_pmp_write_init_tf); EXPORT_SYMBOL_GPL(sata_pmp_std_prereset); EXPORT_SYMBOL_GPL(sata_pmp_std_hardreset); EXPORT_SYMBOL_GPL(sata_pmp_std_postreset); diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 1f84e40fa6a..5a2b2af4d0c 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -2557,7 +2557,11 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, /* reset */ if (reset) { - ata_eh_freeze_port(ap); + /* if PMP is attached, this function only deals with + * downstream links, port should stay thawed. + */ + if (!ap->nr_pmp_links) + ata_eh_freeze_port(ap); ata_port_for_each_link(link, ap) { struct ata_eh_context *ehc = &link->eh_context; @@ -2575,7 +2579,8 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, } } - ata_eh_thaw_port(ap); + if (!ap->nr_pmp_links) + ata_eh_thaw_port(ap); } /* the rest */ @@ -2610,8 +2615,14 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, if (ata_eh_handle_dev_fail(dev, rc)) nr_disabled_devs++; - if (ap->pflags & ATA_PFLAG_FROZEN) + if (ap->pflags & ATA_PFLAG_FROZEN) { + /* PMP reset requires working host port. + * Can't retry if it's frozen. + */ + if (ap->nr_pmp_links) + goto out; break; + } } if (nr_failed_devs) { diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c index f6c4b11336e..c0c4dbcde09 100644 --- a/drivers/ata/libata-pmp.c +++ b/drivers/ata/libata-pmp.c @@ -17,27 +17,35 @@ * @reg: register to read * @r_val: resulting value * - * Wrapper around ap->ops->pmp_read to make it easier to call and - * nomarlize error return value. + * Read PMP register. * * LOCKING: * Kernel thread context (may sleep). * * RETURNS: - * 0 on success, -errno on failure. + * 0 on success, AC_ERR_* mask on failure. */ -static int sata_pmp_read(struct ata_link *link, int reg, u32 *r_val) +static unsigned int sata_pmp_read(struct ata_link *link, int reg, u32 *r_val) { struct ata_port *ap = link->ap; struct ata_device *pmp_dev = ap->link.device; - int rc; - - might_sleep(); - - rc = ap->ops->pmp_read(pmp_dev, link->pmp, reg, r_val); - if (rc) - rc = -EIO; - return rc; + struct ata_taskfile tf; + unsigned int err_mask; + + ata_tf_init(pmp_dev, &tf); + tf.command = ATA_CMD_PMP_READ; + tf.protocol = ATA_PROT_NODATA; + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf.feature = reg; + tf.device = link->pmp; + + err_mask = ata_exec_internal(pmp_dev, &tf, NULL, DMA_NONE, NULL, 0, + SATA_PMP_SCR_TIMEOUT); + if (err_mask) + return err_mask; + + *r_val = tf.nsect | tf.lbal << 8 | tf.lbam << 16 | tf.lbah << 24; + return 0; } /** @@ -46,27 +54,33 @@ static int sata_pmp_read(struct ata_link *link, int reg, u32 *r_val) * @reg: register to write * @r_val: value to write * - * Wrapper around ap->ops->pmp_write to make it easier to call - * and nomarlize error return value. + * Write PMP register. * * LOCKING: * Kernel thread context (may sleep). * * RETURNS: - * 0 on success, -errno on failure. + * 0 on success, AC_ERR_* mask on failure. */ -static int sata_pmp_write(struct ata_link *link, int reg, u32 val) +static unsigned int sata_pmp_write(struct ata_link *link, int reg, u32 val) { struct ata_port *ap = link->ap; struct ata_device *pmp_dev = ap->link.device; - int rc; - - might_sleep(); - - rc = ap->ops->pmp_write(pmp_dev, link->pmp, reg, val); - if (rc) - rc = -EIO; - return rc; + struct ata_taskfile tf; + + ata_tf_init(pmp_dev, &tf); + tf.command = ATA_CMD_PMP_WRITE; + tf.protocol = ATA_PROT_NODATA; + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf.feature = reg; + tf.device = link->pmp; + tf.nsect = val & 0xff; + tf.lbal = (val >> 8) & 0xff; + tf.lbam = (val >> 16) & 0xff; + tf.lbah = (val >> 24) & 0xff; + + return ata_exec_internal(pmp_dev, &tf, NULL, DMA_NONE, NULL, 0, + SATA_PMP_SCR_TIMEOUT); } /** @@ -99,71 +113,6 @@ int sata_pmp_qc_defer_cmd_switch(struct ata_queued_cmd *qc) return ATA_DEFER_PORT; } -/** - * sata_pmp_read_init_tf - initialize TF for PMP read - * @tf: taskfile to initialize - * @dev: PMP dev - * @pmp: port multiplier port number - * @reg: register to read - * - * Initialize @tf for PMP read command. - * - * LOCKING: - * None. - */ -void sata_pmp_read_init_tf(struct ata_taskfile *tf, - struct ata_device *dev, int pmp, int reg) -{ - ata_tf_init(dev, tf); - tf->command = ATA_CMD_PMP_READ; - tf->protocol = ATA_PROT_NODATA; - tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; - tf->feature = reg; - tf->device = pmp; -} - -/** - * sata_pmp_read_val - extract PMP read result from TF - * @tf: target TF - * - * Determine PMP read result from @tf. - * - * LOCKING: - * None. - */ -u32 sata_pmp_read_val(const struct ata_taskfile *tf) -{ - return tf->nsect | tf->lbal << 8 | tf->lbam << 16 | tf->lbah << 24; -} - -/** - * sata_pmp_read_init_tf - initialize TF for PMP write - * @tf: taskfile to initialize - * @dev: PMP dev - * @pmp: port multiplier port number - * @reg: register to read - * @val: value to write - * - * Initialize @tf for PMP write command. - * - * LOCKING: - * None. - */ -void sata_pmp_write_init_tf(struct ata_taskfile *tf, - struct ata_device *dev, int pmp, int reg, u32 val) -{ - ata_tf_init(dev, tf); - tf->command = ATA_CMD_PMP_WRITE; - tf->protocol = ATA_PROT_NODATA; - tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; - tf->feature = reg; - tf->device = pmp; - tf->nsect = val & 0xff; - tf->lbal = (val >> 8) & 0xff; - tf->lbam = (val >> 16) & 0xff; - tf->lbah = (val >> 24) & 0xff; -} - /** * sata_pmp_scr_read - read PSCR * @link: ATA link to read PSCR for @@ -181,10 +130,18 @@ void sata_pmp_write_init_tf(struct ata_taskfile *tf, */ int sata_pmp_scr_read(struct ata_link *link, int reg, u32 *r_val) { + unsigned int err_mask; + if (reg > SATA_PMP_PSCR_CONTROL) return -EINVAL; - return sata_pmp_read(link, reg, r_val); + err_mask = sata_pmp_read(link, reg, r_val); + if (err_mask) { + ata_link_printk(link, KERN_WARNING, "failed to read SCR %d " + "(Emask=0x%x)\n", reg, err_mask); + return -EIO; + } + return 0; } /** @@ -204,10 +161,18 @@ int sata_pmp_scr_read(struct ata_link *link, int reg, u32 *r_val) */ int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val) { + unsigned int err_mask; + if (reg > SATA_PMP_PSCR_CONTROL) return -EINVAL; - return sata_pmp_write(link, reg, val); + err_mask = sata_pmp_write(link, reg, val); + if (err_mask) { + ata_link_printk(link, KERN_WARNING, "failed to write SCR %d " + "(Emask=0x%x)\n", reg, err_mask); + return -EIO; + } + return 0; } /** @@ -361,16 +326,17 @@ void sata_pmp_std_postreset(struct ata_link *link, unsigned int *class) static int sata_pmp_read_gscr(struct ata_device *dev, u32 *gscr) { static const int gscr_to_read[] = { 0, 1, 2, 32, 33, 64, 96 }; - int i, rc; + int i; for (i = 0; i < ARRAY_SIZE(gscr_to_read); i++) { int reg = gscr_to_read[i]; + unsigned int err_mask; - rc = sata_pmp_read(dev->link, reg, &gscr[reg]); - if (rc) { - ata_dev_printk(dev, KERN_ERR, "failed to read " - "PMP GSCR[%d] (errno=%d)\n", reg, rc); - return rc; + err_mask = sata_pmp_read(dev->link, reg, &gscr[reg]); + if (err_mask) { + ata_dev_printk(dev, KERN_ERR, "failed to read PMP " + "GSCR[%d] (Emask=0x%x)\n", reg, err_mask); + return -EIO; } } @@ -392,6 +358,7 @@ static int sata_pmp_configure(struct ata_device *dev, int print_info) { struct ata_port *ap = dev->link->ap; u32 *gscr = dev->gscr; + unsigned int err_mask = 0; const char *reason; int nr_ports, rc; @@ -408,8 +375,10 @@ static int sata_pmp_configure(struct ata_device *dev, int print_info) dev->flags |= ATA_DFLAG_AN; /* monitor SERR_PHYRDY_CHG on fan-out ports */ - rc = sata_pmp_write(dev->link, SATA_PMP_GSCR_ERROR_EN, SERR_PHYRDY_CHG); - if (rc) { + err_mask = sata_pmp_write(dev->link, SATA_PMP_GSCR_ERROR_EN, + SERR_PHYRDY_CHG); + if (err_mask) { + rc = -EIO; reason = "failed to write GSCR_ERROR_EN"; goto fail; } @@ -418,9 +387,10 @@ static int sata_pmp_configure(struct ata_device *dev, int print_info) if (gscr[SATA_PMP_GSCR_FEAT_EN] & SATA_PMP_FEAT_NOTIFY) { gscr[SATA_PMP_GSCR_FEAT_EN] &= ~SATA_PMP_FEAT_NOTIFY; - rc = sata_pmp_write(dev->link, SATA_PMP_GSCR_FEAT_EN, - gscr[SATA_PMP_GSCR_FEAT_EN]); - if (rc) { + err_mask = sata_pmp_write(dev->link, SATA_PMP_GSCR_FEAT_EN, + gscr[SATA_PMP_GSCR_FEAT_EN]); + if (err_mask) { + rc = -EIO; reason = "failed to write GSCR_FEAT_EN"; goto fail; } @@ -447,7 +417,8 @@ static int sata_pmp_configure(struct ata_device *dev, int print_info) fail: ata_dev_printk(dev, KERN_ERR, - "failed to configure Port Multiplier (%s)\n", reason); + "failed to configure Port Multiplier (%s, Emask=0x%x)\n", + reason, err_mask); return rc; } @@ -812,13 +783,14 @@ static int sata_pmp_revalidate(struct ata_device *dev, unsigned int new_class) */ static int sata_pmp_revalidate_quick(struct ata_device *dev) { + unsigned int err_mask; u32 prod_id; - int rc; - rc = sata_pmp_read(dev->link, SATA_PMP_GSCR_PROD_ID, &prod_id); - if (rc) { - ata_dev_printk(dev, KERN_ERR, "failed to read PMP product ID\n"); - return rc; + err_mask = sata_pmp_read(dev->link, SATA_PMP_GSCR_PROD_ID, &prod_id); + if (err_mask) { + ata_dev_printk(dev, KERN_ERR, "failed to read PMP product ID " + "(Emask=0x%x)\n", err_mask); + return -EIO; } if (prod_id != dev->gscr[SATA_PMP_GSCR_PROD_ID]) { @@ -1049,6 +1021,7 @@ static int sata_pmp_eh_recover(struct ata_port *ap, struct ata_eh_context *pmp_ehc = &pmp_link->eh_context; struct ata_link *link; struct ata_device *dev; + unsigned int err_mask; u32 gscr_error, sntf; int cnt, rc; @@ -1107,20 +1080,22 @@ static int sata_pmp_eh_recover(struct ata_port *ap, if (pmp_dev->flags & ATA_DFLAG_AN) { pmp_dev->gscr[SATA_PMP_GSCR_FEAT_EN] |= SATA_PMP_FEAT_NOTIFY; - rc = sata_pmp_write(pmp_dev->link, SATA_PMP_GSCR_FEAT_EN, - pmp_dev->gscr[SATA_PMP_GSCR_FEAT_EN]); - if (rc) { - ata_dev_printk(pmp_dev, KERN_ERR, - "failed to write PMP_FEAT_EN\n"); + err_mask = sata_pmp_write(pmp_dev->link, SATA_PMP_GSCR_FEAT_EN, + pmp_dev->gscr[SATA_PMP_GSCR_FEAT_EN]); + if (err_mask) { + ata_dev_printk(pmp_dev, KERN_ERR, "failed to write " + "PMP_FEAT_EN (Emask=0x%x)\n", err_mask); + rc = -EIO; goto pmp_fail; } } /* check GSCR_ERROR */ - rc = sata_pmp_read(pmp_link, SATA_PMP_GSCR_ERROR, &gscr_error); - if (rc) { - ata_dev_printk(pmp_dev, KERN_ERR, - "failed to read PMP_GSCR_ERROR\n"); + err_mask = sata_pmp_read(pmp_link, SATA_PMP_GSCR_ERROR, &gscr_error); + if (err_mask) { + ata_dev_printk(pmp_dev, KERN_ERR, "failed to read " + "PMP_GSCR_ERROR (Emask=0x%x)\n", err_mask); + rc = -EIO; goto pmp_fail; } diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index 15b9a80a178..b0619278454 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -337,8 +337,6 @@ static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc); static void sil24_irq_clear(struct ata_port *ap); static void sil24_pmp_attach(struct ata_port *ap); static void sil24_pmp_detach(struct ata_port *ap); -static int sil24_pmp_read(struct ata_device *dev, int pmp, int reg, u32 *r_val); -static int sil24_pmp_write(struct ata_device *dev, int pmp, int reg, u32 val); static void sil24_freeze(struct ata_port *ap); static void sil24_thaw(struct ata_port *ap); static void sil24_error_handler(struct ata_port *ap); @@ -411,8 +409,6 @@ static const struct ata_port_operations sil24_ops = { .pmp_attach = sil24_pmp_attach, .pmp_detach = sil24_pmp_detach, - .pmp_read = sil24_pmp_read, - .pmp_write = sil24_pmp_write, .freeze = sil24_freeze, .thaw = sil24_thaw, @@ -928,32 +924,6 @@ static void sil24_pmp_detach(struct ata_port *ap) sil24_config_pmp(ap, 0); } -static int sil24_pmp_read(struct ata_device *dev, int pmp, int reg, u32 *r_val) -{ - struct ata_port *ap = dev->link->ap; - struct ata_taskfile tf; - int rc; - - sata_pmp_read_init_tf(&tf, dev, pmp, reg); - rc = sil24_exec_polled_cmd(ap, SATA_PMP_CTRL_PORT, &tf, 1, 0, - SATA_PMP_SCR_TIMEOUT); - if (rc == 0) { - sil24_read_tf(ap, 0, &tf); - *r_val = sata_pmp_read_val(&tf); - } - return rc; -} - -static int sil24_pmp_write(struct ata_device *dev, int pmp, int reg, u32 val) -{ - struct ata_port *ap = dev->link->ap; - struct ata_taskfile tf; - - sata_pmp_write_init_tf(&tf, dev, pmp, reg, val); - return sil24_exec_polled_cmd(ap, SATA_PMP_CTRL_PORT, &tf, 1, 0, - SATA_PMP_SCR_TIMEOUT); -} - static int sil24_pmp_softreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { diff --git a/include/linux/libata.h b/include/linux/libata.h index 529af9fbed5..2439f1fa47a 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -669,8 +669,6 @@ struct ata_port_operations { /* port multiplier */ void (*pmp_attach) (struct ata_port *ap); void (*pmp_detach) (struct ata_port *ap); - int (*pmp_read) (struct ata_device *dev, int pmp, int reg, u32 *r_val); - int (*pmp_write) (struct ata_device *dev, int pmp, int reg, u32 val); /* Error handlers. ->error_handler overrides ->eng_timeout and * indicates that new-style EH is in place. @@ -957,12 +955,6 @@ extern unsigned long ata_pci_default_filter(struct ata_device *, unsigned long); * PMP */ extern int sata_pmp_qc_defer_cmd_switch(struct ata_queued_cmd *qc); -extern void sata_pmp_read_init_tf(struct ata_taskfile *tf, - struct ata_device *dev, int pmp, int reg); -extern u32 sata_pmp_read_val(const struct ata_taskfile *tf); -extern void sata_pmp_write_init_tf(struct ata_taskfile *tf, - struct ata_device *dev, - int pmp, int reg, u32 val); extern int sata_pmp_std_prereset(struct ata_link *link, unsigned long deadline); extern int sata_pmp_std_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline); -- cgit v1.2.3-70-g09d2 From 2855568b1ee4f58ef2c0a13ddfceb4b0b216b7ed Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 11 Oct 2007 17:12:35 -0400 Subject: [libata] struct pci_dev related cleanups * remove pointless pci_dev_to_dev() wrapper. Just directly reference the embedded struct device like everyone else does. * pata_cs5520: delete cs5520_remove_one(), it was a duplicate of ata_pci_remove_one() * linux/libata.h: don't bother including linux/pci.h, we don't need it. Simply declare 'struct pci_dev' and assume interested parties will include the header, as they should be doing anyway. * linux/libata.h: consolidate all CONFIG_PCI declarations into a single location in the header. Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 2 +- drivers/ata/libata-eh.c | 1 + drivers/ata/pata_cs5520.c | 20 +------------------- include/linux/libata.h | 33 ++++++++++++++------------------- 4 files changed, 17 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index ce8ccb434af..b05384a8c32 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -7007,7 +7007,7 @@ void ata_std_ports(struct ata_ioports *ioaddr) */ void ata_pci_remove_one(struct pci_dev *pdev) { - struct device *dev = pci_dev_to_dev(pdev); + struct device *dev = &pdev->dev; struct ata_host *host = dev_get_drvdata(dev); ata_host_detach(host); diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 5a2b2af4d0c..2eaa39fc65d 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -33,6 +33,7 @@ */ #include +#include #include #include #include diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c index ff1eb84c7d2..33f7f0843f4 100644 --- a/drivers/ata/pata_cs5520.c +++ b/drivers/ata/pata_cs5520.c @@ -299,24 +299,6 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi return ata_host_register(host, &cs5520_sht); } -/** - * cs5520_remove_one - device unload - * @pdev: PCI device being removed - * - * Handle an unplug/unload event for a PCI device. Unload the - * PCI driver but do not use the default handler as we manage - * resources ourself and *MUST NOT* disable the device as it has - * other functions. - */ - -static void __devexit cs5520_remove_one(struct pci_dev *pdev) -{ - struct device *dev = pci_dev_to_dev(pdev); - struct ata_host *host = dev_get_drvdata(dev); - - ata_host_detach(host); -} - #ifdef CONFIG_PM /** * cs5520_reinit_one - device resume @@ -373,7 +355,7 @@ static struct pci_driver cs5520_pci_driver = { .name = DRV_NAME, .id_table = pata_cs5520, .probe = cs5520_init_one, - .remove = cs5520_remove_one, + .remove = ata_pci_remove_one, #ifdef CONFIG_PM .suspend = cs5520_pci_device_suspend, .resume = cs5520_reinit_one, diff --git a/include/linux/libata.h b/include/linux/libata.h index 2439f1fa47a..229a9ff9f92 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -28,7 +28,6 @@ #include #include -#include #include #include #include @@ -107,12 +106,6 @@ static inline u32 ata_msg_init(int dval, int default_msg_enable_bits) /* defines only for the constants which don't work well as enums */ #define ATA_TAG_POISON 0xfafbfcfdU -/* move to PCI layer? */ -static inline struct device *pci_dev_to_dev(struct pci_dev *pdev) -{ - return &pdev->dev; -} - enum { /* various global constants */ LIBATA_MAX_PRD = ATA_MAX_PRD / 2, @@ -766,18 +759,7 @@ extern int sata_std_hardreset(struct ata_link *link, unsigned int *class, extern void ata_std_postreset(struct ata_link *link, unsigned int *classes); extern void ata_port_disable(struct ata_port *); extern void ata_std_ports(struct ata_ioports *ioaddr); -#ifdef CONFIG_PCI -extern int ata_pci_init_one (struct pci_dev *pdev, - const struct ata_port_info * const * ppi); -extern void ata_pci_remove_one (struct pci_dev *pdev); -#ifdef CONFIG_PM -extern void ata_pci_device_do_suspend(struct pci_dev *pdev, pm_message_t mesg); -extern int __must_check ata_pci_device_do_resume(struct pci_dev *pdev); -extern int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg); -extern int ata_pci_device_resume(struct pci_dev *pdev); -#endif -extern int ata_pci_clear_simplex(struct pci_dev *pdev); -#endif /* CONFIG_PCI */ + extern struct ata_host *ata_host_alloc(struct device *dev, int max_ports); extern struct ata_host *ata_host_alloc_pinfo(struct device *dev, const struct ata_port_info * const * ppi, int n_ports); @@ -935,6 +917,19 @@ static inline int ata_acpi_cbl_80wire(struct ata_port *ap) { return 0; } #endif #ifdef CONFIG_PCI +struct pci_dev; + +extern int ata_pci_init_one (struct pci_dev *pdev, + const struct ata_port_info * const * ppi); +extern void ata_pci_remove_one (struct pci_dev *pdev); +#ifdef CONFIG_PM +extern void ata_pci_device_do_suspend(struct pci_dev *pdev, pm_message_t mesg); +extern int __must_check ata_pci_device_do_resume(struct pci_dev *pdev); +extern int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg); +extern int ata_pci_device_resume(struct pci_dev *pdev); +#endif +extern int ata_pci_clear_simplex(struct pci_dev *pdev); + struct pci_bits { unsigned int reg; /* PCI config register to read */ unsigned int width; /* 1 (8 bit), 2 (16 bit), 4 (32 bit) */ -- cgit v1.2.3-70-g09d2 From 77f1fd6ecd04556cbac1ca72e7a284ae313ea538 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 12 Oct 2007 22:48:46 +0200 Subject: mmc: use correct unregister function for led trigger We register a simple trigger so make sure we use the corresponding unregister function. (Also means we get a dummy function when triggers aren't compiled in) Signed-off-by: Pierre Ossman --- drivers/mmc/core/host.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 64fbc9759a3..c65d203a846 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -143,7 +143,7 @@ void mmc_remove_host(struct mmc_host *host) device_del(&host->class_dev); - led_trigger_unregister(host->led); + led_trigger_unregister_simple(host->led); spin_lock(&mmc_host_lock); idr_remove(&mmc_host_idr, host->index); -- cgit v1.2.3-70-g09d2 From 5d5a2989b72847e1f5763420ea31383ca63ebf53 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 12 Oct 2007 23:04:23 +0200 Subject: x86: kill 8253pit.h Useless header file with 32 bit and 64 bit variants. Move the single useful line to the place where it is used. Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Signed-off-by: Arjan van de Ven --- arch/x86/kernel/i8259_32.c | 1 - drivers/input/misc/pcspkr.c | 2 +- include/asm-x86/8253pit.h | 5 ----- include/asm-x86/8253pit_32.h | 12 ------------ include/asm-x86/8253pit_64.h | 10 ---------- include/asm-x86/i8253.h | 4 ---- include/asm-x86/timex_32.h | 6 +++--- include/asm-x86/timex_64.h | 2 +- 8 files changed, 5 insertions(+), 37 deletions(-) delete mode 100644 include/asm-x86/8253pit.h delete mode 100644 include/asm-x86/8253pit_32.h delete mode 100644 include/asm-x86/8253pit_64.h (limited to 'drivers') diff --git a/arch/x86/kernel/i8259_32.c b/arch/x86/kernel/i8259_32.c index 0499cbe9871..679bb33acbf 100644 --- a/arch/x86/kernel/i8259_32.c +++ b/arch/x86/kernel/i8259_32.c @@ -10,7 +10,6 @@ #include #include -#include #include #include #include diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c index 906bf5e8de8..4e2ca6f0ab1 100644 --- a/drivers/input/misc/pcspkr.c +++ b/drivers/input/misc/pcspkr.c @@ -17,7 +17,6 @@ #include #include #include -#include #include MODULE_AUTHOR("Vojtech Pavlik "); @@ -28,6 +27,7 @@ MODULE_LICENSE("GPL"); /* Use the global PIT lock ! */ #include #else +#include static DEFINE_SPINLOCK(i8253_lock); #endif diff --git a/include/asm-x86/8253pit.h b/include/asm-x86/8253pit.h deleted file mode 100644 index d3c2b38a661..00000000000 --- a/include/asm-x86/8253pit.h +++ /dev/null @@ -1,5 +0,0 @@ -#ifdef CONFIG_X86_32 -# include "8253pit_32.h" -#else -# include "8253pit_64.h" -#endif diff --git a/include/asm-x86/8253pit_32.h b/include/asm-x86/8253pit_32.h deleted file mode 100644 index 96c7c3592da..00000000000 --- a/include/asm-x86/8253pit_32.h +++ /dev/null @@ -1,12 +0,0 @@ -/* - * 8253/8254 Programmable Interval Timer - */ - -#ifndef _8253PIT_H -#define _8253PIT_H - -#include - -#define PIT_TICK_RATE CLOCK_TICK_RATE - -#endif diff --git a/include/asm-x86/8253pit_64.h b/include/asm-x86/8253pit_64.h deleted file mode 100644 index 285f78488cc..00000000000 --- a/include/asm-x86/8253pit_64.h +++ /dev/null @@ -1,10 +0,0 @@ -/* - * 8253/8254 Programmable Interval Timer - */ - -#ifndef _8253PIT_H -#define _8253PIT_H - -#define PIT_TICK_RATE 1193182UL - -#endif diff --git a/include/asm-x86/i8253.h b/include/asm-x86/i8253.h index 7eff6fd2747..28cf67da59a 100644 --- a/include/asm-x86/i8253.h +++ b/include/asm-x86/i8253.h @@ -1,10 +1,6 @@ #ifndef __ASM_I8253_H__ #define __ASM_I8253_H__ -#ifdef CONFIG_X86_64 -# include -#endif - /* i8253A PIT registers */ #define PIT_MODE 0x43 #define PIT_CH0 0x40 diff --git a/include/asm-x86/timex_32.h b/include/asm-x86/timex_32.h index 3666044409f..fa8839465bd 100644 --- a/include/asm-x86/timex_32.h +++ b/include/asm-x86/timex_32.h @@ -10,11 +10,11 @@ #include #ifdef CONFIG_X86_ELAN -# define CLOCK_TICK_RATE 1189200 /* AMD Elan has different frequency! */ +# define PIT_TICK_RATE 1189200 /* AMD Elan has different frequency! */ #else -# define CLOCK_TICK_RATE 1193182 /* Underlying HZ */ +# define PIT_TICK_RATE 1193182 /* Underlying HZ */ #endif - +#define CLOCK_TICK_RATE PIT_TICK_RATE extern int read_current_timer(unsigned long *timer_value); #define ARCH_HAS_READ_CURRENT_TIMER 1 diff --git a/include/asm-x86/timex_64.h b/include/asm-x86/timex_64.h index 6ed21f44d30..901bf89ce64 100644 --- a/include/asm-x86/timex_64.h +++ b/include/asm-x86/timex_64.h @@ -6,7 +6,6 @@ #ifndef _ASMx8664_TIMEX_H #define _ASMx8664_TIMEX_H -#include #include #include #include @@ -14,6 +13,7 @@ #include #include +#define PIT_TICK_RATE 1193182UL #define CLOCK_TICK_RATE PIT_TICK_RATE /* Underlying HZ */ extern int read_current_timer(unsigned long *timer_value); -- cgit v1.2.3-70-g09d2 From 43ca7ec96f01bd921e772112729005d4474fdbf4 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 12 Oct 2007 23:04:23 +0200 Subject: ACPI: remove the now unused ifdef code The conversion of x86-64 to clock events makes the #ifdef CONFIG_GENERIC_CLOCKEVENTS n the timer broadcast functions useless. Remove it. Signed-off-by: Thomas Gleixner Cc: john stultz Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Ingo Molnar Signed-off-by: Arjan van de Ven --- drivers/acpi/processor_idle.c | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 1e8287b4f40..1f6fb38de01 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -276,21 +276,12 @@ static void acpi_timer_check_state(int state, struct acpi_processor *pr, static void acpi_propagate_timer_broadcast(struct acpi_processor *pr) { -#ifdef CONFIG_GENERIC_CLOCKEVENTS unsigned long reason; reason = pr->power.timer_broadcast_on_state < INT_MAX ? CLOCK_EVT_NOTIFY_BROADCAST_ON : CLOCK_EVT_NOTIFY_BROADCAST_OFF; clockevents_notify(reason, &pr->id); -#else - cpumask_t mask = cpumask_of_cpu(pr->id); - - if (pr->power.timer_broadcast_on_state < INT_MAX) - on_each_cpu(switch_APIC_timer_to_ipi, &mask, 1, 1); - else - on_each_cpu(switch_ipi_to_APIC_timer, &mask, 1, 1); -#endif } /* Power(C) State timer broadcast control */ @@ -298,8 +289,6 @@ static void acpi_state_timer_broadcast(struct acpi_processor *pr, struct acpi_processor_cx *cx, int broadcast) { -#ifdef CONFIG_GENERIC_CLOCKEVENTS - int state = cx - pr->power.states; if (state >= pr->power.timer_broadcast_on_state) { @@ -309,7 +298,6 @@ static void acpi_state_timer_broadcast(struct acpi_processor *pr, CLOCK_EVT_NOTIFY_BROADCAST_EXIT; clockevents_notify(reason, &pr->id); } -#endif } #else -- cgit v1.2.3-70-g09d2 From 43cc71eed1250755986da4c0f9898f9a635cb3bf Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Sat, 18 Aug 2007 04:40:39 +0200 Subject: platform: prefix MODALIAS with "platform:" Prefix platform modalias strings with "platform:", which modprobe config to blacklist alias resolving if userspace configures it. Send uevents for all platform devices. Add MODULE_ALIAS's to: pxa2xx_pcmcia, ds1742 and pcspkr to trigger module autoloading by userspace. $ modinfo pcspkr alias: platform:pcspkr license: GPL description: PC Speaker beeper driver ... $ modprobe -n -v platform:pcspkr insmod /lib/modules/2.6.23-rc3-g28e8351a-dirty/kernel/drivers/input/misc/pcspkr.ko Signed-off-by: Kay Sievers Cc: David Brownell Cc: Atsushi Nemoto Signed-off-by: Greg Kroah-Hartman --- drivers/base/platform.c | 15 ++------------- drivers/input/misc/pcspkr.c | 1 + drivers/pcmcia/pxa2xx_mainstone.c | 2 +- drivers/pcmcia/pxa2xx_sharpsl.c | 2 +- 4 files changed, 5 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 869ff8c0014..9bfc434d132 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -160,11 +160,6 @@ static void platform_device_release(struct device *dev) * * Create a platform device object which can have other objects attached * to it, and which will have attached objects freed when it is released. - * - * This device will be marked as not supporting hotpluggable drivers; no - * device add/remove uevents will be generated. In the unusual case that - * the device isn't being dynamically allocated as a legacy "probe the - * hardware" driver, infrastructure code should reverse this marking. */ struct platform_device *platform_device_alloc(const char *name, unsigned int id) { @@ -177,12 +172,6 @@ struct platform_device *platform_device_alloc(const char *name, unsigned int id) pa->pdev.id = id; device_initialize(&pa->pdev.dev); pa->pdev.dev.release = platform_device_release; - - /* prevent hotplug "modprobe $(MODALIAS)" from causing trouble in - * legacy probe-the-hardware drivers, which don't properly split - * out device enumeration logic from drivers. - */ - pa->pdev.dev.uevent_suppress = 1; } return pa ? &pa->pdev : NULL; @@ -530,7 +519,7 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *a, char *buf) { struct platform_device *pdev = to_platform_device(dev); - int len = snprintf(buf, PAGE_SIZE, "%s\n", pdev->name); + int len = snprintf(buf, PAGE_SIZE, "platform:%s\n", pdev->name); return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len; } @@ -546,7 +535,7 @@ static int platform_uevent(struct device *dev, char **envp, int num_envp, struct platform_device *pdev = to_platform_device(dev); envp[0] = buffer; - snprintf(buffer, buffer_size, "MODALIAS=%s", pdev->name); + snprintf(buffer, buffer_size, "MODALIAS=platform:%s", pdev->name); return 0; } diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c index 906bf5e8de8..e1a44020ed2 100644 --- a/drivers/input/misc/pcspkr.c +++ b/drivers/input/misc/pcspkr.c @@ -23,6 +23,7 @@ MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("PC Speaker beeper driver"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:pcspkr"); #ifdef CONFIG_X86 /* Use the global PIT lock ! */ diff --git a/drivers/pcmcia/pxa2xx_mainstone.c b/drivers/pcmcia/pxa2xx_mainstone.c index 383107ba4bd..f6722ba0dd1 100644 --- a/drivers/pcmcia/pxa2xx_mainstone.c +++ b/drivers/pcmcia/pxa2xx_mainstone.c @@ -175,7 +175,6 @@ static int __init mst_pcmcia_init(void) if (!mst_pcmcia_device) return -ENOMEM; - mst_pcmcia_device->dev.uevent_suppress = 0; mst_pcmcia_device->dev.platform_data = &mst_pcmcia_ops; ret = platform_device_add(mst_pcmcia_device); @@ -195,3 +194,4 @@ fs_initcall(mst_pcmcia_init); module_exit(mst_pcmcia_exit); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:pxa2xx-pcmcia"); diff --git a/drivers/pcmcia/pxa2xx_sharpsl.c b/drivers/pcmcia/pxa2xx_sharpsl.c index a2daa3f531b..d5c33bd78d6 100644 --- a/drivers/pcmcia/pxa2xx_sharpsl.c +++ b/drivers/pcmcia/pxa2xx_sharpsl.c @@ -261,7 +261,6 @@ static int __init sharpsl_pcmcia_init(void) if (!sharpsl_pcmcia_device) return -ENOMEM; - sharpsl_pcmcia_device->dev.uevent_suppress = 0; sharpsl_pcmcia_device->dev.platform_data = &sharpsl_pcmcia_ops; sharpsl_pcmcia_device->dev.parent = platform_scoop_config->devs[0].dev; @@ -284,3 +283,4 @@ module_exit(sharpsl_pcmcia_exit); MODULE_DESCRIPTION("Sharp SL Series PCMCIA Support"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:pxa2xx-pcmcia"); -- cgit v1.2.3-70-g09d2 From 8380770c842faef3001e44662953d64ad9a93663 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Mon, 30 Jul 2007 02:28:56 +0200 Subject: Driver core: make sysfs uevent-attributes static Attributes do not have an owner(module) anymore, so there is no need to carry the attributes in every single bus instance. Signed-off-by: Kay Sievers Acked-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- drivers/base/bus.c | 21 +++++++++------------ include/linux/device.h | 2 -- 2 files changed, 9 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 61c67526a65..ff850d1b0d9 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -568,32 +568,29 @@ static void remove_bind_files(struct device_driver *drv) driver_remove_file(drv, &driver_attr_unbind); } +static BUS_ATTR(drivers_probe, S_IWUSR, NULL, store_drivers_probe); +static BUS_ATTR(drivers_autoprobe, S_IWUSR | S_IRUGO, + show_drivers_autoprobe, store_drivers_autoprobe); + static int add_probe_files(struct bus_type *bus) { int retval; - bus->drivers_probe_attr.attr.name = "drivers_probe"; - bus->drivers_probe_attr.attr.mode = S_IWUSR; - bus->drivers_probe_attr.store = store_drivers_probe; - retval = bus_create_file(bus, &bus->drivers_probe_attr); + retval = bus_create_file(bus, &bus_attr_drivers_probe); if (retval) goto out; - bus->drivers_autoprobe_attr.attr.name = "drivers_autoprobe"; - bus->drivers_autoprobe_attr.attr.mode = S_IWUSR | S_IRUGO; - bus->drivers_autoprobe_attr.show = show_drivers_autoprobe; - bus->drivers_autoprobe_attr.store = store_drivers_autoprobe; - retval = bus_create_file(bus, &bus->drivers_autoprobe_attr); + retval = bus_create_file(bus, &bus_attr_drivers_autoprobe); if (retval) - bus_remove_file(bus, &bus->drivers_probe_attr); + bus_remove_file(bus, &bus_attr_drivers_probe); out: return retval; } static void remove_probe_files(struct bus_type *bus) { - bus_remove_file(bus, &bus->drivers_autoprobe_attr); - bus_remove_file(bus, &bus->drivers_probe_attr); + bus_remove_file(bus, &bus_attr_drivers_autoprobe); + bus_remove_file(bus, &bus_attr_drivers_probe); } #else static inline int add_bind_files(struct device_driver *drv) { return 0; } diff --git a/include/linux/device.h b/include/linux/device.h index 3a38d1f70cb..5d97ca6d865 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -64,8 +64,6 @@ struct bus_type { struct bus_attribute * bus_attrs; struct device_attribute * dev_attrs; struct driver_attribute * drv_attrs; - struct bus_attribute drivers_autoprobe_attr; - struct bus_attribute drivers_probe_attr; int (*match)(struct device * dev, struct device_driver * drv); int (*uevent)(struct device *dev, char **envp, -- cgit v1.2.3-70-g09d2 From 7eff2e7a8b65c25920207324e56611150eb1cd9a Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Tue, 14 Aug 2007 15:15:12 +0200 Subject: Driver core: change add_uevent_var to use a struct This changes the uevent buffer functions to use a struct instead of a long list of parameters. It does no longer require the caller to do the proper buffer termination and size accounting, which is currently wrong in some places. It fixes a known bug where parts of the uevent environment are overwritten because of wrong index calculations. Many thanks to Mathieu Desnoyers for finding bugs and improving the error handling. Signed-off-by: Kay Sievers Cc: Mathieu Desnoyers Cc: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- arch/ia64/sn/kernel/tiocx.c | 3 +- arch/powerpc/kernel/of_device.c | 37 ++----- arch/powerpc/kernel/vio.c | 16 +-- arch/powerpc/platforms/ps3/system-bus.c | 9 +- block/genhd.c | 35 ++----- drivers/acpi/scan.c | 16 +-- drivers/amba/bus.c | 9 +- drivers/base/class.c | 42 ++------ drivers/base/core.c | 84 +++++----------- drivers/base/firmware_class.c | 11 +- drivers/base/memory.c | 3 +- drivers/base/platform.c | 6 +- drivers/eisa/eisa-bus.c | 9 +- drivers/firewire/fw-device.c | 11 +- drivers/firmware/dmi-id.c | 17 ++-- drivers/i2c/i2c-core.c | 8 +- drivers/ide/ide.c | 17 +--- drivers/ieee1394/nodemgr.c | 17 +--- drivers/infiniband/core/sysfs.c | 9 +- drivers/input/input.c | 62 ++++-------- drivers/input/serio/serio.c | 11 +- drivers/media/video/pvrusb2/pvrusb2-sysfs.c | 4 +- drivers/misc/tifm_core.c | 9 +- drivers/mmc/core/bus.c | 21 ++-- drivers/pci/hotplug.c | 28 ++---- drivers/pci/pci-driver.c | 3 +- drivers/pci/pci.h | 3 +- drivers/pcmcia/cs.c | 10 +- drivers/pcmcia/ds.c | 26 ++--- drivers/power/power_supply.h | 3 +- drivers/power/power_supply_sysfs.c | 17 +--- drivers/s390/cio/ccwgroup.c | 3 +- drivers/s390/cio/device.c | 25 ++--- drivers/s390/crypto/ap_bus.c | 14 +-- drivers/scsi/scsi_sysfs.c | 9 +- drivers/spi/spi.c | 7 +- drivers/usb/core/driver.c | 29 ++---- drivers/usb/core/message.c | 28 ++---- drivers/w1/w1.c | 19 ++-- include/asm-powerpc/of_device.h | 2 +- include/linux/device.h | 15 +-- include/linux/kobject.h | 23 +++-- lib/kobject_uevent.c | 149 ++++++++++++---------------- net/atm/atm_sysfs.c | 7 +- net/core/net-sysfs.c | 14 +-- net/wireless/sysfs.c | 3 +- sound/aoa/soundbus/core.c | 33 ++---- 47 files changed, 300 insertions(+), 636 deletions(-) (limited to 'drivers') diff --git a/arch/ia64/sn/kernel/tiocx.c b/arch/ia64/sn/kernel/tiocx.c index 5a289e4de83..a88eba3314d 100644 --- a/arch/ia64/sn/kernel/tiocx.c +++ b/arch/ia64/sn/kernel/tiocx.c @@ -66,8 +66,7 @@ static int tiocx_match(struct device *dev, struct device_driver *drv) } -static int tiocx_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int tiocx_uevent(struct device *dev, struct kobj_uevent_env *env) { return -ENODEV; } diff --git a/arch/powerpc/kernel/of_device.c b/arch/powerpc/kernel/of_device.c index 89b911e83c0..8f3db32fac8 100644 --- a/arch/powerpc/kernel/of_device.c +++ b/arch/powerpc/kernel/of_device.c @@ -57,26 +57,21 @@ ssize_t of_device_get_modalias(struct of_device *ofdev, return tsize; } -int of_device_uevent(struct device *dev, - char **envp, int num_envp, char *buffer, int buffer_size) +int of_device_uevent(struct device *dev, struct kobj_uevent_env *env) { struct of_device *ofdev; const char *compat; - int i = 0, length = 0, seen = 0, cplen, sl; + int seen = 0, cplen, sl; if (!dev) return -ENODEV; ofdev = to_of_device(dev); - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "OF_NAME=%s", ofdev->node->name)) + if (add_uevent_var(env, "OF_NAME=%s", ofdev->node->name)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "OF_TYPE=%s", ofdev->node->type)) + if (add_uevent_var(env, "OF_TYPE=%s", ofdev->node->type)) return -ENOMEM; /* Since the compatible field can contain pretty much anything @@ -85,9 +80,7 @@ int of_device_uevent(struct device *dev, compat = of_get_property(ofdev->node, "compatible", &cplen); while (compat && *compat && cplen > 0) { - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "OF_COMPATIBLE_%d=%s", seen, compat)) + if (add_uevent_var(env, "OF_COMPATIBLE_%d=%s", seen, compat)) return -ENOMEM; sl = strlen (compat) + 1; @@ -96,25 +89,17 @@ int of_device_uevent(struct device *dev, seen++; } - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "OF_COMPATIBLE_N=%d", seen)) + if (add_uevent_var(env, "OF_COMPATIBLE_N=%d", seen)) return -ENOMEM; /* modalias is trickier, we add it in 2 steps */ - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MODALIAS=")) + if (add_uevent_var(env, "MODALIAS=")) return -ENOMEM; - - sl = of_device_get_modalias(ofdev, &buffer[length-1], - buffer_size-length); - if (sl >= (buffer_size-length)) + sl = of_device_get_modalias(ofdev, &env->buf[env->buflen-1], + sizeof(env->buf) - env->buflen); + if (sl >= (sizeof(env->buf) - env->buflen)) return -ENOMEM; - - length += sl; - - envp[i] = NULL; + env->buflen += sl; return 0; } diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c index cb22a3557c4..19a5656001c 100644 --- a/arch/powerpc/kernel/vio.c +++ b/arch/powerpc/kernel/vio.c @@ -317,30 +317,20 @@ static int vio_bus_match(struct device *dev, struct device_driver *drv) return (ids != NULL) && (vio_match_device(ids, vio_dev) != NULL); } -static int vio_hotplug(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int vio_hotplug(struct device *dev, struct kobj_uevent_env *env) { const struct vio_dev *vio_dev = to_vio_dev(dev); struct device_node *dn; const char *cp; - int length; - - if (!num_envp) - return -ENOMEM; dn = dev->archdata.of_node; if (!dn) return -ENODEV; - cp = of_get_property(dn, "compatible", &length); + cp = of_get_property(dn, "compatible", NULL); if (!cp) return -ENODEV; - envp[0] = buffer; - length = scnprintf(buffer, buffer_size, "MODALIAS=vio:T%sS%s", - vio_dev->type, cp); - if ((buffer_size - length) <= 0) - return -ENOMEM; - envp[1] = NULL; + add_uevent_var(env, "MODALIAS=vio:T%sS%s", vio_dev->type, cp); return 0; } diff --git a/arch/powerpc/platforms/ps3/system-bus.c b/arch/powerpc/platforms/ps3/system-bus.c index 4bb634a17e4..ea0b2c79041 100644 --- a/arch/powerpc/platforms/ps3/system-bus.c +++ b/arch/powerpc/platforms/ps3/system-bus.c @@ -437,18 +437,13 @@ static void ps3_system_bus_shutdown(struct device *_dev) dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__); } -static int ps3_system_bus_uevent(struct device *_dev, char **envp, - int num_envp, char *buffer, int buffer_size) +static int ps3_system_bus_uevent(struct device *_dev, struct kobj_uevent_env *env) { struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); int i = 0, length = 0; - if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, - &length, "MODALIAS=ps3:%d", - dev->match_id)) + if (add_uevent_var(env, "MODALIAS=ps3:%d", dev->match_id)) return -ENOMEM; - - envp[i] = NULL; return 0; } diff --git a/block/genhd.c b/block/genhd.c index 3af1e7a378d..e609996f2e7 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -540,61 +540,42 @@ static int block_uevent_filter(struct kset *kset, struct kobject *kobj) return ((ktype == &ktype_block) || (ktype == &ktype_part)); } -static int block_uevent(struct kset *kset, struct kobject *kobj, char **envp, - int num_envp, char *buffer, int buffer_size) +static int block_uevent(struct kset *kset, struct kobject *kobj, + struct kobj_uevent_env *env) { struct kobj_type *ktype = get_ktype(kobj); struct device *physdev; struct gendisk *disk; struct hd_struct *part; - int length = 0; - int i = 0; if (ktype == &ktype_block) { disk = container_of(kobj, struct gendisk, kobj); - add_uevent_var(envp, num_envp, &i, buffer, buffer_size, - &length, "MINOR=%u", disk->first_minor); + add_uevent_var(env, "MINOR=%u", disk->first_minor); } else if (ktype == &ktype_part) { disk = container_of(kobj->parent, struct gendisk, kobj); part = container_of(kobj, struct hd_struct, kobj); - add_uevent_var(envp, num_envp, &i, buffer, buffer_size, - &length, "MINOR=%u", + add_uevent_var(env, "MINOR=%u", disk->first_minor + part->partno); } else return 0; - add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "MAJOR=%u", disk->major); + add_uevent_var(env, "MAJOR=%u", disk->major); /* add physical device, backing this device */ physdev = disk->driverfs_dev; if (physdev) { char *path = kobject_get_path(&physdev->kobj, GFP_KERNEL); - add_uevent_var(envp, num_envp, &i, buffer, buffer_size, - &length, "PHYSDEVPATH=%s", path); + add_uevent_var(env, "PHYSDEVPATH=%s", path); kfree(path); if (physdev->bus) - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVBUS=%s", - physdev->bus->name); + add_uevent_var(env, "PHYSDEVBUS=%s", physdev->bus->name); if (physdev->driver) - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVDRIVER=%s", - physdev->driver->name); + add_uevent_var(env, physdev->driver->name); } - /* terminate, set to next free slot, shrink available space */ - envp[i] = NULL; - envp = &envp[i]; - num_envp -= i; - buffer = &buffer[length]; - buffer_size -= length; - return 0; } diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 64620d66874..5b4d462117c 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -319,16 +319,18 @@ static int acpi_bus_match(struct device *dev, struct device_driver *drv) return !acpi_match_device_ids(acpi_dev, acpi_drv->ids); } -static int acpi_device_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int acpi_device_uevent(struct device *dev, struct kobj_uevent_env *env) { struct acpi_device *acpi_dev = to_acpi_device(dev); + int len; - strcpy(buffer, "MODALIAS="); - if (create_modalias(acpi_dev, buffer + 9, buffer_size - 9) > 0) { - envp[0] = buffer; - envp[1] = NULL; - } + if (add_uevent_var(env, "MODALIAS=")) + return -ENOMEM; + len = create_modalias(acpi_dev, &env->buf[env->buflen - 1], + sizeof(env->buf) - env->buflen); + if (len >= (sizeof(env->buf) - env->buflen)) + return -ENOMEM; + env->buflen += len; return 0; } diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c index 268e301775f..6b94fb7be5f 100644 --- a/drivers/amba/bus.c +++ b/drivers/amba/bus.c @@ -44,15 +44,12 @@ static int amba_match(struct device *dev, struct device_driver *drv) } #ifdef CONFIG_HOTPLUG -static int amba_uevent(struct device *dev, char **envp, int nr_env, char *buf, int bufsz) +static int amba_uevent(struct device *dev, struct kobj_uevent_env *env) { struct amba_device *pcdev = to_amba_device(dev); - int retval = 0, i = 0, len = 0; + int retval = 0; - retval = add_uevent_var(envp, nr_env, &i, - buf, bufsz, &len, - "AMBA_ID=%08x", pcdev->periphid); - envp[i] = NULL; + retval = add_uevent_var(env, "AMBA_ID=%08x", pcdev->periphid); return retval; } #else diff --git a/drivers/base/class.c b/drivers/base/class.c index 4d2222618b7..ecd6336bffe 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -180,8 +180,7 @@ static void class_device_create_release(struct class_device *class_dev) /* needed to allow these devices to have parent class devices */ static int class_device_create_uevent(struct class_device *class_dev, - char **envp, int num_envp, - char *buffer, int buffer_size) + struct kobj_uevent_env *env) { pr_debug("%s called for %s\n", __FUNCTION__, class_dev->class_id); return 0; @@ -403,64 +402,43 @@ static void remove_deprecated_class_device_links(struct class_device *cd) { } #endif -static int class_uevent(struct kset *kset, struct kobject *kobj, char **envp, - int num_envp, char *buffer, int buffer_size) +static int class_uevent(struct kset *kset, struct kobject *kobj, + struct kobj_uevent_env *env) { struct class_device *class_dev = to_class_dev(kobj); struct device *dev = class_dev->dev; - int i = 0; - int length = 0; int retval = 0; pr_debug("%s - name = %s\n", __FUNCTION__, class_dev->class_id); if (MAJOR(class_dev->devt)) { - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MAJOR=%u", MAJOR(class_dev->devt)); + add_uevent_var(env, "MAJOR=%u", MAJOR(class_dev->devt)); - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MINOR=%u", MINOR(class_dev->devt)); + add_uevent_var(env, "MINOR=%u", MINOR(class_dev->devt)); } if (dev) { const char *path = kobject_get_path(&dev->kobj, GFP_KERNEL); if (path) { - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVPATH=%s", path); + add_uevent_var(env, "PHYSDEVPATH=%s", path); kfree(path); } if (dev->bus) - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVBUS=%s", dev->bus->name); + add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name); if (dev->driver) - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVDRIVER=%s", dev->driver->name); + add_uevent_var(env, "PHYSDEVDRIVER=%s", dev->driver->name); } - /* terminate, set to next free slot, shrink available space */ - envp[i] = NULL; - envp = &envp[i]; - num_envp -= i; - buffer = &buffer[length]; - buffer_size -= length; - if (class_dev->uevent) { /* have the class device specific function add its stuff */ - retval = class_dev->uevent(class_dev, envp, num_envp, - buffer, buffer_size); + retval = class_dev->uevent(class_dev, env); if (retval) pr_debug("class_dev->uevent() returned %d\n", retval); } else if (class_dev->class->uevent) { /* have the class specific function add its stuff */ - retval = class_dev->class->uevent(class_dev, envp, num_envp, - buffer, buffer_size); + retval = class_dev->class->uevent(class_dev, env); if (retval) pr_debug("class->uevent() returned %d\n", retval); } diff --git a/drivers/base/core.c b/drivers/base/core.c index ec86d6fc236..d487c032dc4 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -141,33 +141,23 @@ static const char *dev_uevent_name(struct kset *kset, struct kobject *kobj) return NULL; } -static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp, - int num_envp, char *buffer, int buffer_size) +static int dev_uevent(struct kset *kset, struct kobject *kobj, + struct kobj_uevent_env *env) { struct device *dev = to_dev(kobj); - int i = 0; - int length = 0; int retval = 0; /* add the major/minor if present */ if (MAJOR(dev->devt)) { - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MAJOR=%u", MAJOR(dev->devt)); - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MINOR=%u", MINOR(dev->devt)); + add_uevent_var(env, "MAJOR=%u", MAJOR(dev->devt)); + add_uevent_var(env, "MINOR=%u", MINOR(dev->devt)); } if (dev->type && dev->type->name) - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "DEVTYPE=%s", dev->type->name); + add_uevent_var(env, "DEVTYPE=%s", dev->type->name); if (dev->driver) - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "DRIVER=%s", dev->driver->name); + add_uevent_var(env, "DRIVER=%s", dev->driver->name); #ifdef CONFIG_SYSFS_DEPRECATED if (dev->class) { @@ -181,59 +171,43 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp, path = kobject_get_path(&parent->kobj, GFP_KERNEL); if (path) { - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVPATH=%s", path); + add_uevent_var(env, "PHYSDEVPATH=%s", path); kfree(path); } - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVBUS=%s", parent->bus->name); + add_uevent_var(env, "PHYSDEVBUS=%s", parent->bus->name); if (parent->driver) - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVDRIVER=%s", parent->driver->name); + add_uevent_var(env, "PHYSDEVDRIVER=%s", + parent->driver->name); } } else if (dev->bus) { - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVBUS=%s", dev->bus->name); + add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name); if (dev->driver) - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVDRIVER=%s", dev->driver->name); + add_uevent_var(env, "PHYSDEVDRIVER=%s", dev->driver->name); } #endif - /* terminate, set to next free slot, shrink available space */ - envp[i] = NULL; - envp = &envp[i]; - num_envp -= i; - buffer = &buffer[length]; - buffer_size -= length; - + /* have the bus specific function add its stuff */ if (dev->bus && dev->bus->uevent) { - /* have the bus specific function add its stuff */ - retval = dev->bus->uevent(dev, envp, num_envp, buffer, buffer_size); + retval = dev->bus->uevent(dev, env); if (retval) pr_debug ("%s: bus uevent() returned %d\n", __FUNCTION__, retval); } + /* have the class specific function add its stuff */ if (dev->class && dev->class->dev_uevent) { - /* have the class specific function add its stuff */ - retval = dev->class->dev_uevent(dev, envp, num_envp, buffer, buffer_size); + retval = dev->class->dev_uevent(dev, env); if (retval) pr_debug("%s: class uevent() returned %d\n", __FUNCTION__, retval); } + /* have the device type specific fuction add its stuff */ if (dev->type && dev->type->uevent) { - /* have the device type specific fuction add its stuff */ - retval = dev->type->uevent(dev, envp, num_envp, buffer, buffer_size); + retval = dev->type->uevent(dev, env); if (retval) pr_debug("%s: dev_type uevent() returned %d\n", __FUNCTION__, retval); @@ -253,9 +227,7 @@ static ssize_t show_uevent(struct device *dev, struct device_attribute *attr, { struct kobject *top_kobj; struct kset *kset; - char *envp[32]; - char *data = NULL; - char *pos; + struct kobj_uevent_env *env = NULL; int i; size_t count = 0; int retval; @@ -278,26 +250,20 @@ static ssize_t show_uevent(struct device *dev, struct device_attribute *attr, if (!kset->uevent_ops->filter(kset, &dev->kobj)) goto out; - data = (char *)get_zeroed_page(GFP_KERNEL); - if (!data) + env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL); + if (!env) return -ENOMEM; /* let the kset specific function add its keys */ - pos = data; - memset(envp, 0, sizeof(envp)); - retval = kset->uevent_ops->uevent(kset, &dev->kobj, - envp, ARRAY_SIZE(envp), - pos, PAGE_SIZE); + retval = kset->uevent_ops->uevent(kset, &dev->kobj, env); if (retval) goto out; /* copy keys to file */ - for (i = 0; envp[i]; i++) { - pos = &buf[count]; - count += sprintf(pos, "%s\n", envp[i]); - } + for (i = 0; i < env->envp_idx; i++) + count += sprintf(&buf[count], "%s\n", env->envp[i]); out: - free_page((unsigned long)data); + kfree(env); return count; } diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index b24efd4e3e3..4a1b9bfc547 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -88,19 +88,14 @@ static CLASS_ATTR(timeout, 0644, firmware_timeout_show, firmware_timeout_store); static void fw_dev_release(struct device *dev); -static int firmware_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int firmware_uevent(struct device *dev, struct kobj_uevent_env *env) { struct firmware_priv *fw_priv = dev_get_drvdata(dev); - int i = 0, len = 0; - if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, - "FIRMWARE=%s", fw_priv->fw_id)) + if (add_uevent_var(env, "FIRMWARE=%s", fw_priv->fw_id)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, - "TIMEOUT=%i", loading_timeout)) + if (add_uevent_var(env, "TIMEOUT=%i", loading_timeout)) return -ENOMEM; - envp[i] = NULL; return 0; } diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 74b96795d2f..cb99daeae93 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -34,8 +34,7 @@ static const char *memory_uevent_name(struct kset *kset, struct kobject *kobj) return MEMORY_CLASS_NAME; } -static int memory_uevent(struct kset *kset, struct kobject *kobj, char **envp, - int num_envp, char *buffer, int buffer_size) +static int memory_uevent(struct kset *kset, struct kobj_uevent_env *env) { int retval = 0; diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 9bfc434d132..a2e3910196e 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -529,13 +529,11 @@ static struct device_attribute platform_dev_attrs[] = { __ATTR_NULL, }; -static int platform_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int platform_uevent(struct device *dev, struct kobj_uevent_env *env) { struct platform_device *pdev = to_platform_device(dev); - envp[0] = buffer; - snprintf(buffer, buffer_size, "MODALIAS=platform:%s", pdev->name); + add_uevent_var(env, "MODALIAS=platform:%s", pdev->name); return 0; } diff --git a/drivers/eisa/eisa-bus.c b/drivers/eisa/eisa-bus.c index d944647c82c..4d4a4739390 100644 --- a/drivers/eisa/eisa-bus.c +++ b/drivers/eisa/eisa-bus.c @@ -128,16 +128,11 @@ static int eisa_bus_match (struct device *dev, struct device_driver *drv) return 0; } -static int eisa_bus_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int eisa_bus_uevent(struct device *dev, struct kobj_uevent_env *env) { struct eisa_device *edev = to_eisa_device(dev); - int i = 0; - int length = 0; - add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "MODALIAS=" EISA_DEVICE_MODALIAS_FMT, edev->id.sig); - envp[i] = NULL; + add_uevent_var(env, "MODALIAS=" EISA_DEVICE_MODALIAS_FMT, edev->id.sig); return 0; } diff --git a/drivers/firewire/fw-device.c b/drivers/firewire/fw-device.c index 2b658634163..56681b3b297 100644 --- a/drivers/firewire/fw-device.c +++ b/drivers/firewire/fw-device.c @@ -130,23 +130,16 @@ static int get_modalias(struct fw_unit *unit, char *buffer, size_t buffer_size) } static int -fw_unit_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +fw_unit_uevent(struct device *dev, struct kobj_uevent_env *env) { struct fw_unit *unit = fw_unit(dev); char modalias[64]; - int length = 0; - int i = 0; get_modalias(unit, modalias, sizeof(modalias)); - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MODALIAS=%s", modalias)) + if (add_uevent_var(env, "MODALIAS=%s", modalias)) return -ENOMEM; - envp[i] = NULL; - return 0; } diff --git a/drivers/firmware/dmi-id.c b/drivers/firmware/dmi-id.c index 59c3b5aa89f..2678098d450 100644 --- a/drivers/firmware/dmi-id.c +++ b/drivers/firmware/dmi-id.c @@ -134,14 +134,17 @@ static struct attribute_group* sys_dmi_attribute_groups[] = { NULL }; -static int dmi_dev_uevent(struct device *dev, char **envp, - int num_envp, char *buffer, int buffer_size) +static int dmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env) { - strcpy(buffer, "MODALIAS="); - get_modalias(buffer+9, buffer_size-9); - envp[0] = buffer; - envp[1] = NULL; - + ssize_t len; + + if (add_uevent_var(env, "MODALIAS=")) + return -ENOMEM; + len = get_modalias(&env->buf[env->buflen - 1], + sizeof(env->buf) - env->buflen); + if (len >= (sizeof(env->buf) - env->buflen)) + return -ENOMEM; + env->buflen += len; return 0; } diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index d663e6960d9..910a62de190 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -67,20 +67,16 @@ static int i2c_device_match(struct device *dev, struct device_driver *drv) #ifdef CONFIG_HOTPLUG /* uevent helps with hotplug: modprobe -q $(MODALIAS) */ -static int i2c_device_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int i2c_device_uevent(struct device *dev, struct kobj_uevent_env *env) { struct i2c_client *client = to_i2c_client(dev); - int i = 0, length = 0; /* by definition, legacy drivers can't hotplug */ if (dev->driver || !client->driver_name) return 0; - if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "MODALIAS=%s", client->driver_name)) + if (add_uevent_var(env, "MODALIAS=%s", client->driver_name)) return -ENOMEM; - envp[i] = NULL; dev_dbg(dev, "uevent\n"); return 0; } diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index e96212ce572..a96a8b1b353 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -1663,20 +1663,13 @@ static struct device_attribute ide_dev_attrs[] = { __ATTR_NULL }; -static int ide_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int ide_uevent(struct device *dev, struct kobj_uevent_env *env) { ide_drive_t *drive = to_ide_device(dev); - int i = 0; - int length = 0; - - add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "MEDIA=%s", media_string(drive)); - add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "DRIVENAME=%s", drive->name); - add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "MODALIAS=ide:m-%s", media_string(drive)); - envp[i] = NULL; + + add_uevent_var(env, "MEDIA=%s", media_string(drive)); + add_uevent_var(env, "DRIVENAME=%s", drive->name); + add_uevent_var(env, "MODALIAS=ide:m-%s", media_string(drive)); return 0; } diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c index 2ffd53461db..1939fee616e 100644 --- a/drivers/ieee1394/nodemgr.c +++ b/drivers/ieee1394/nodemgr.c @@ -153,8 +153,7 @@ struct host_info { }; static int nodemgr_bus_match(struct device * dev, struct device_driver * drv); -static int nodemgr_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size); +static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env); static void nodemgr_resume_ne(struct node_entry *ne); static void nodemgr_remove_ne(struct node_entry *ne); static struct node_entry *find_entry_by_guid(u64 guid); @@ -1160,12 +1159,9 @@ static void nodemgr_process_root_directory(struct host_info *hi, struct node_ent #ifdef CONFIG_HOTPLUG -static int nodemgr_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env) { struct unit_directory *ud; - int i = 0; - int length = 0; int retval = 0; /* ieee1394:venNmoNspNverN */ char buf[8 + 1 + 3 + 8 + 2 + 8 + 2 + 8 + 3 + 8 + 1]; @@ -1180,9 +1176,7 @@ static int nodemgr_uevent(struct device *dev, char **envp, int num_envp, #define PUT_ENVP(fmt,val) \ do { \ - retval = add_uevent_var(envp, num_envp, &i, \ - buffer, buffer_size, &length, \ - fmt, val); \ + retval = add_uevent_var(env, fmt, val); \ if (retval) \ return retval; \ } while (0) @@ -1201,15 +1195,12 @@ do { \ #undef PUT_ENVP - envp[i] = NULL; - return 0; } #else -static int nodemgr_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env) { return -ENODEV; } diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c index 70b77ae6742..3d405068132 100644 --- a/drivers/infiniband/core/sysfs.c +++ b/drivers/infiniband/core/sysfs.c @@ -434,21 +434,18 @@ static void ib_device_release(struct class_device *cdev) kfree(dev); } -static int ib_device_uevent(struct class_device *cdev, char **envp, - int num_envp, char *buf, int size) +static int ib_device_uevent(struct class_device *cdev, + struct kobj_uevent_env *env) { struct ib_device *dev = container_of(cdev, struct ib_device, class_dev); - int i = 0, len = 0; - if (add_uevent_var(envp, num_envp, &i, buf, size, &len, - "NAME=%s", dev->name)) + if (add_uevent_var(env, "NAME=%s", dev->name)) return -ENOMEM; /* * It would be nice to pass the node GUID with the event... */ - envp[i] = NULL; return 0; } diff --git a/drivers/input/input.c b/drivers/input/input.c index 5fe75558662..5dc361c954e 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -859,87 +859,66 @@ static void input_dev_release(struct device *device) * Input uevent interface - loading event handlers based on * device bitfields. */ -static int input_add_uevent_bm_var(char **envp, int num_envp, int *cur_index, - char *buffer, int buffer_size, int *cur_len, +static int input_add_uevent_bm_var(struct kobj_uevent_env *env, const char *name, unsigned long *bitmap, int max) { - if (*cur_index >= num_envp - 1) - return -ENOMEM; - - envp[*cur_index] = buffer + *cur_len; + int len; - *cur_len += snprintf(buffer + *cur_len, max(buffer_size - *cur_len, 0), name); - if (*cur_len >= buffer_size) + if (add_uevent_var(env, "%s=", name)) return -ENOMEM; - *cur_len += input_print_bitmap(buffer + *cur_len, - max(buffer_size - *cur_len, 0), - bitmap, max, 0) + 1; - if (*cur_len > buffer_size) + len = input_print_bitmap(&env->buf[env->buflen - 1], + sizeof(env->buf) - env->buflen, + bitmap, max, 0); + if (len >= (sizeof(env->buf) - env->buflen)) return -ENOMEM; - (*cur_index)++; + env->buflen += len; return 0; } -static int input_add_uevent_modalias_var(char **envp, int num_envp, int *cur_index, - char *buffer, int buffer_size, int *cur_len, +static int input_add_uevent_modalias_var(struct kobj_uevent_env *env, struct input_dev *dev) { - if (*cur_index >= num_envp - 1) - return -ENOMEM; - - envp[*cur_index] = buffer + *cur_len; + int len; - *cur_len += snprintf(buffer + *cur_len, max(buffer_size - *cur_len, 0), - "MODALIAS="); - if (*cur_len >= buffer_size) + if (add_uevent_var(env, "MODALIAS=")) return -ENOMEM; - *cur_len += input_print_modalias(buffer + *cur_len, - max(buffer_size - *cur_len, 0), - dev, 0) + 1; - if (*cur_len > buffer_size) + len = input_print_modalias(&env->buf[env->buflen - 1], + sizeof(env->buf) - env->buflen, + dev, 0); + if (len >= (sizeof(env->buf) - env->buflen)) return -ENOMEM; - (*cur_index)++; + env->buflen += len; return 0; } #define INPUT_ADD_HOTPLUG_VAR(fmt, val...) \ do { \ - int err = add_uevent_var(envp, num_envp, &i, \ - buffer, buffer_size, &len, \ - fmt, val); \ + int err = add_uevent_var(env, fmt, val); \ if (err) \ return err; \ } while (0) #define INPUT_ADD_HOTPLUG_BM_VAR(name, bm, max) \ do { \ - int err = input_add_uevent_bm_var(envp, num_envp, &i, \ - buffer, buffer_size, &len, \ - name, bm, max); \ + int err = input_add_uevent_bm_var(env, name, bm, max); \ if (err) \ return err; \ } while (0) #define INPUT_ADD_HOTPLUG_MODALIAS_VAR(dev) \ do { \ - int err = input_add_uevent_modalias_var(envp, \ - num_envp, &i, \ - buffer, buffer_size, &len, \ - dev); \ + int err = input_add_uevent_modalias_var(env, dev); \ if (err) \ return err; \ } while (0) -static int input_dev_uevent(struct device *device, char **envp, - int num_envp, char *buffer, int buffer_size) +static int input_dev_uevent(struct device *device, struct kobj_uevent_env *env) { struct input_dev *dev = to_input_dev(device); - int i = 0; - int len = 0; INPUT_ADD_HOTPLUG_VAR("PRODUCT=%x/%x/%x/%x", dev->id.bustype, dev->id.vendor, @@ -971,7 +950,6 @@ static int input_dev_uevent(struct device *device, char **envp, INPUT_ADD_HOTPLUG_MODALIAS_VAR(dev); - envp[i] = NULL; return 0; } diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 372ca493119..b3bc15acd3f 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -876,18 +876,14 @@ static int serio_bus_match(struct device *dev, struct device_driver *drv) #define SERIO_ADD_UEVENT_VAR(fmt, val...) \ do { \ - int err = add_uevent_var(envp, num_envp, &i, \ - buffer, buffer_size, &len, \ - fmt, val); \ + int err = add_uevent_var(env, fmt, val); \ if (err) \ return err; \ } while (0) -static int serio_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size) +static int serio_uevent(struct device *dev, struct kobj_uevent_env *env) { struct serio *serio; - int i = 0; - int len = 0; if (!dev) return -ENODEV; @@ -900,7 +896,6 @@ static int serio_uevent(struct device *dev, char **envp, int num_envp, char *buf SERIO_ADD_UEVENT_VAR("SERIO_EXTRA=%02x", serio->id.extra); SERIO_ADD_UEVENT_VAR("MODALIAS=serio:ty%02Xpr%02Xid%02Xex%02X", serio->id.type, serio->id.proto, serio->id.id, serio->id.extra); - envp[i] = NULL; return 0; } @@ -908,7 +903,7 @@ static int serio_uevent(struct device *dev, char **envp, int num_envp, char *buf #else -static int serio_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size) +static int serio_uevent(struct device *dev, struct kobj_uevent_env *env) { return -ENODEV; } diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c index 7a78d6b3473..2ee3c3049e8 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c +++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c @@ -905,8 +905,8 @@ struct pvr2_sysfs *pvr2_sysfs_create(struct pvr2_context *mp, } -static int pvr2_sysfs_hotplug(struct device *cd,char **envp, - int numenvp,char *buf,int size) +static int pvr2_sysfs_hotplug(struct device *d, + struct kobj_uevent_env *env) { /* Even though we don't do anything here, we still need this function because sysfs will still try to call it. */ diff --git a/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c index d195fb088f4..8f77949f93d 100644 --- a/drivers/misc/tifm_core.c +++ b/drivers/misc/tifm_core.c @@ -57,16 +57,11 @@ static int tifm_bus_match(struct device *dev, struct device_driver *drv) return 0; } -static int tifm_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int tifm_uevent(struct device *dev, struct kobj_uevent_env *env) { struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev); - int i = 0; - int length = 0; - if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "TIFM_CARD_TYPE=%s", - tifm_media_type_name(sock->type, 1))) + if (add_uevent_var(env, "TIFM_CARD_TYPE=%s", tifm_media_type_name(sock->type, 1))) return -ENOMEM; return 0; diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 8d6f6014870..b0c22cad942 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -58,12 +58,11 @@ static int mmc_bus_match(struct device *dev, struct device_driver *drv) } static int -mmc_bus_uevent(struct device *dev, char **envp, int num_envp, char *buf, - int buf_size) +mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env) { struct mmc_card *card = dev_to_mmc_card(dev); const char *type; - int i = 0, length = 0; + int retval = 0; switch (card->type) { case MMC_TYPE_MMC: @@ -80,20 +79,14 @@ mmc_bus_uevent(struct device *dev, char **envp, int num_envp, char *buf, } if (type) { - if (add_uevent_var(envp, num_envp, &i, - buf, buf_size, &length, - "MMC_TYPE=%s", type)) - return -ENOMEM; + retval = add_uevent_var(env, "MMC_TYPE=%s", type); + if (retval) + return retval; } - if (add_uevent_var(envp, num_envp, &i, - buf, buf_size, &length, - "MMC_NAME=%s", mmc_card_name(card))) - return -ENOMEM; + retval = add_uevent_var(env, "MMC_NAME=%s", mmc_card_name(card)); - envp[i] = NULL; - - return 0; + return retval; } static int mmc_bus_probe(struct device *dev) diff --git a/drivers/pci/hotplug.c b/drivers/pci/hotplug.c index 1c97e7dd130..2b5352a7dff 100644 --- a/drivers/pci/hotplug.c +++ b/drivers/pci/hotplug.c @@ -3,12 +3,9 @@ #include #include "pci.h" -int pci_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +int pci_uevent(struct device *dev, struct kobj_uevent_env *env) { struct pci_dev *pdev; - int i = 0; - int length = 0; if (!dev) return -ENODEV; @@ -17,37 +14,24 @@ int pci_uevent(struct device *dev, char **envp, int num_envp, if (!pdev) return -ENODEV; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PCI_CLASS=%04X", pdev->class)) + if (add_uevent_var(env, "PCI_CLASS=%04X", pdev->class)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PCI_ID=%04X:%04X", pdev->vendor, pdev->device)) + if (add_uevent_var(env, "PCI_ID=%04X:%04X", pdev->vendor, pdev->device)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor, + if (add_uevent_var(env, "PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor, pdev->subsystem_device)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PCI_SLOT_NAME=%s", pci_name(pdev))) + if (add_uevent_var(env, "PCI_SLOT_NAME=%s", pci_name(pdev))) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x", + if (add_uevent_var(env, "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x", pdev->vendor, pdev->device, pdev->subsystem_vendor, pdev->subsystem_device, (u8)(pdev->class >> 16), (u8)(pdev->class >> 8), (u8)(pdev->class))) return -ENOMEM; - - envp[i] = NULL; - return 0; } diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 004bc248727..f61be3abfdc 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -532,8 +532,7 @@ void pci_dev_put(struct pci_dev *dev) } #ifndef CONFIG_HOTPLUG -int pci_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +int pci_uevent(struct device *dev, struct kobj_uevent_env *env) { return -ENODEV; } diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 4c36e80f6d2..b3a7d5b0f93 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -1,7 +1,6 @@ /* Functions internal to the PCI core code */ -extern int pci_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size); +extern int pci_uevent(struct device *dev, struct kobj_uevent_env *env); extern int pci_create_sysfs_dev_files(struct pci_dev *pdev); extern void pci_remove_sysfs_dev_files(struct pci_dev *pdev); extern void pci_cleanup_rom(struct pci_dev *dev); diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index f8b13f0270d..a0aca46ce87 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -907,18 +907,14 @@ int pcmcia_insert_card(struct pcmcia_socket *skt) EXPORT_SYMBOL(pcmcia_insert_card); -static int pcmcia_socket_uevent(struct device *dev, char **envp, - int num_envp, char *buffer, int buffer_size) +static int pcmcia_socket_uevent(struct device *dev, + struct kobj_uevent_env *env) { struct pcmcia_socket *s = container_of(dev, struct pcmcia_socket, dev); - int i = 0, length = 0; - if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, - &length, "SOCKET_NO=%u", s->sock)) + if (add_uevent_var(env, "SOCKET_NO=%u", s->sock)) return -ENOMEM; - envp[i] = NULL; - return 0; } diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index a99607142fc..55baa1f0fcb 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -1064,11 +1064,10 @@ static int pcmcia_bus_match(struct device * dev, struct device_driver * drv) { #ifdef CONFIG_HOTPLUG -static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int pcmcia_bus_uevent(struct device *dev, struct kobj_uevent_env *env) { struct pcmcia_device *p_dev; - int i, length = 0; + int i; u32 hash[4] = { 0, 0, 0, 0}; if (!dev) @@ -1083,23 +1082,13 @@ static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp, hash[i] = crc32(0, p_dev->prod_id[i], strlen(p_dev->prod_id[i])); } - i = 0; - - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "SOCKET_NO=%u", - p_dev->socket->sock)) + if (add_uevent_var(env, "SOCKET_NO=%u", p_dev->socket->sock)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "DEVICE_NO=%02X", - p_dev->device_no)) + if (add_uevent_var(env, "DEVICE_NO=%02X", p_dev->device_no)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MODALIAS=pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X" + if (add_uevent_var(env, "MODALIAS=pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X" "pa%08Xpb%08Xpc%08Xpd%08X", p_dev->has_manf_id ? p_dev->manf_id : 0, p_dev->has_card_id ? p_dev->card_id : 0, @@ -1112,15 +1101,12 @@ static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp, hash[3])) return -ENOMEM; - envp[i] = NULL; - return 0; } #else -static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int pcmcia_bus_uevent(struct device *dev, struct kobj_uevent_env *env) { return -ENODEV; } diff --git a/drivers/power/power_supply.h b/drivers/power/power_supply.h index a9880d468ee..f38ba482be7 100644 --- a/drivers/power/power_supply.h +++ b/drivers/power/power_supply.h @@ -14,8 +14,7 @@ extern int power_supply_create_attrs(struct power_supply *psy); extern void power_supply_remove_attrs(struct power_supply *psy); -extern int power_supply_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size); +extern int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env); #else diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c index de3155b2128..249f61bae63 100644 --- a/drivers/power/power_supply_sysfs.c +++ b/drivers/power/power_supply_sysfs.c @@ -195,11 +195,10 @@ static char *kstruprdup(const char *str, gfp_t gfp) return ret; } -int power_supply_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env) { struct power_supply *psy = dev_get_drvdata(dev); - int i = 0, length = 0, ret = 0, j; + int ret = 0, j; char *prop_buf; char *attrname; @@ -212,8 +211,7 @@ int power_supply_uevent(struct device *dev, char **envp, int num_envp, dev_dbg(dev, "POWER_SUPPLY_NAME=%s\n", psy->name); - ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, - &length, "POWER_SUPPLY_NAME=%s", psy->name); + ret = add_uevent_var(env, "POWER_SUPPLY_NAME=%s", psy->name); if (ret) return ret; @@ -243,9 +241,7 @@ int power_supply_uevent(struct device *dev, char **envp, int num_envp, dev_dbg(dev, "Static prop %s=%s\n", attrname, prop_buf); - ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, - &length, "POWER_SUPPLY_%s=%s", - attrname, prop_buf); + ret = add_uevent_var(env, "POWER_SUPPLY_%s=%s", attrname, prop_buf); kfree(attrname); if (ret) goto out; @@ -282,14 +278,11 @@ int power_supply_uevent(struct device *dev, char **envp, int num_envp, dev_dbg(dev, "prop %s=%s\n", attrname, prop_buf); - ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, - &length, "POWER_SUPPLY_%s=%s", - attrname, prop_buf); + ret = add_uevent_var(env, "POWER_SUPPLY_%s=%s", attrname, prop_buf); kfree(attrname); if (ret) goto out; } - envp[i] = NULL; out: free_page((unsigned long)prop_buf); diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index b0a18f5176a..5d967c43982 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -44,8 +44,7 @@ ccwgroup_bus_match (struct device * dev, struct device_driver * drv) return 0; } static int -ccwgroup_uevent (struct device *dev, char **envp, int num_envp, char *buffer, - int buffer_size) +ccwgroup_uevent (struct device *dev, struct kobj_uevent_env *env) { /* TODO */ return 0; diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index e44d92eac8e..606bb53e9fa 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -78,49 +78,38 @@ static int snprint_alias(char *buf, size_t size, /* Set up environment variables for ccw device uevent. Return 0 on success, * non-zero otherwise. */ -static int ccw_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int ccw_uevent(struct device *dev, struct kobj_uevent_env *env) { struct ccw_device *cdev = to_ccwdev(dev); struct ccw_device_id *id = &(cdev->id); - int i = 0; - int len = 0; int ret; char modalias_buf[30]; /* CU_TYPE= */ - ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, - "CU_TYPE=%04X", id->cu_type); + ret = add_uevent_var(env, "CU_TYPE=%04X", id->cu_type); if (ret) return ret; /* CU_MODEL= */ - ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, - "CU_MODEL=%02X", id->cu_model); + ret = add_uevent_var(env, "CU_MODEL=%02X", id->cu_model); if (ret) return ret; /* The next two can be zero, that's ok for us */ /* DEV_TYPE= */ - ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, - "DEV_TYPE=%04X", id->dev_type); + ret = add_uevent_var(env, "DEV_TYPE=%04X", id->dev_type); if (ret) return ret; /* DEV_MODEL= */ - ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, - "DEV_MODEL=%02X", id->dev_model); + ret = add_uevent_var(env, "DEV_MODEL=%02X", id->dev_model); if (ret) return ret; /* MODALIAS= */ snprint_alias(modalias_buf, sizeof(modalias_buf), id, ""); - ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, - "MODALIAS=%s", modalias_buf); - if (ret) - return ret; - envp[i] = NULL; - return 0; + ret = add_uevent_var(env, "MODALIAS=%s", modalias_buf); + return ret; } struct bus_type ccw_bus_type; diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 90bd2201451..e9971304159 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -458,28 +458,22 @@ static int ap_bus_match(struct device *dev, struct device_driver *drv) * uevent function for AP devices. It sets up a single environment * variable DEV_TYPE which contains the hardware device type. */ -static int ap_uevent (struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int ap_uevent (struct device *dev, struct kobj_uevent_env *env) { struct ap_device *ap_dev = to_ap_dev(dev); - int retval = 0, length = 0, i = 0; + int retval = 0; if (!ap_dev) return -ENODEV; /* Set up DEV_TYPE environment variable. */ - retval = add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "DEV_TYPE=%04X", ap_dev->device_type); + retval = add_uevent_var(env, "DEV_TYPE=%04X", ap_dev->device_type); if (retval) return retval; /* Add MODALIAS= */ - retval = add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MODALIAS=ap:t%02X", ap_dev->device_type); + retval = add_uevent_var(env, "MODALIAS=ap:t%02X", ap_dev->device_type); - envp[i] = NULL; return retval; } diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 34cdce6738a..ede9986d349 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -277,16 +277,11 @@ static int scsi_bus_match(struct device *dev, struct device_driver *gendrv) return (sdp->inq_periph_qual == SCSI_INQ_PQ_CON)? 1: 0; } -static int scsi_bus_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int scsi_bus_uevent(struct device *dev, struct kobj_uevent_env *env) { struct scsi_device *sdev = to_scsi_device(dev); - int i = 0; - int length = 0; - add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "MODALIAS=" SCSI_DEVICE_MODALIAS_FMT, sdev->type); - envp[i] = NULL; + add_uevent_var(env, "MODALIAS=" SCSI_DEVICE_MODALIAS_FMT, sdev->type); return 0; } diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index e84d2159794..bcb8dd5fb0b 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -67,14 +67,11 @@ static int spi_match_device(struct device *dev, struct device_driver *drv) return strncmp(spi->modalias, drv->name, BUS_ID_SIZE) == 0; } -static int spi_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int spi_uevent(struct device *dev, struct kobj_uevent_env *env) { const struct spi_device *spi = to_spi_device(dev); - envp[0] = buffer; - snprintf(buffer, buffer_size, "MODALIAS=%s", spi->modalias); - envp[1] = NULL; + add_uevent_var(env, "MODALIAS=%s", spi->modalias); return 0; } diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 63b1243a913..6273a5197e6 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -576,12 +576,9 @@ static int usb_device_match(struct device *dev, struct device_driver *drv) } #ifdef CONFIG_HOTPLUG -static int usb_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int usb_uevent(struct device *dev, struct kobj_uevent_env *env) { struct usb_device *usb_dev; - int i = 0; - int length = 0; if (!dev) return -ENODEV; @@ -610,51 +607,39 @@ static int usb_uevent(struct device *dev, char **envp, int num_envp, * all the device descriptors we don't tell them about. Or * act as usermode drivers. */ - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "DEVICE=/proc/bus/usb/%03d/%03d", + if (add_uevent_var(env, "DEVICE=/proc/bus/usb/%03d/%03d", usb_dev->bus->busnum, usb_dev->devnum)) return -ENOMEM; #endif /* per-device configurations are common */ - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PRODUCT=%x/%x/%x", + if (add_uevent_var(env, "PRODUCT=%x/%x/%x", le16_to_cpu(usb_dev->descriptor.idVendor), le16_to_cpu(usb_dev->descriptor.idProduct), le16_to_cpu(usb_dev->descriptor.bcdDevice))) return -ENOMEM; /* class-based driver binding models */ - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "TYPE=%d/%d/%d", + if (add_uevent_var(env, "TYPE=%d/%d/%d", usb_dev->descriptor.bDeviceClass, usb_dev->descriptor.bDeviceSubClass, usb_dev->descriptor.bDeviceProtocol)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "BUSNUM=%03d", + if (add_uevent_var(env, "BUSNUM=%03d", usb_dev->bus->busnum)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "DEVNUM=%03d", + if (add_uevent_var(env, "DEVNUM=%03d", usb_dev->devnum)) return -ENOMEM; - envp[i] = NULL; return 0; } #else -static int usb_uevent(struct device *dev, char **envp, - int num_envp, char *buffer, int buffer_size) +static int usb_uevent(struct device *dev, struct kobj_uevent_env *env) { return -ENODEV; } diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index d8f7b089a8f..95a49d8efe7 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1339,14 +1339,11 @@ void usb_release_interface(struct device *dev) } #ifdef CONFIG_HOTPLUG -static int usb_if_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env) { struct usb_device *usb_dev; struct usb_interface *intf; struct usb_host_interface *alt; - int i = 0; - int length = 0; if (!dev) return -ENODEV; @@ -1359,39 +1356,30 @@ static int usb_if_uevent(struct device *dev, char **envp, int num_envp, alt = intf->cur_altsetting; #ifdef CONFIG_USB_DEVICEFS - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "DEVICE=/proc/bus/usb/%03d/%03d", + if (add_uevent_var(env, "DEVICE=/proc/bus/usb/%03d/%03d", usb_dev->bus->busnum, usb_dev->devnum)) return -ENOMEM; #endif - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PRODUCT=%x/%x/%x", + if (add_uevent_var(env, "PRODUCT=%x/%x/%x", le16_to_cpu(usb_dev->descriptor.idVendor), le16_to_cpu(usb_dev->descriptor.idProduct), le16_to_cpu(usb_dev->descriptor.bcdDevice))) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "TYPE=%d/%d/%d", + if (add_uevent_var(env, "TYPE=%d/%d/%d", usb_dev->descriptor.bDeviceClass, usb_dev->descriptor.bDeviceSubClass, usb_dev->descriptor.bDeviceProtocol)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "INTERFACE=%d/%d/%d", + if (add_uevent_var(env, "INTERFACE=%d/%d/%d", alt->desc.bInterfaceClass, alt->desc.bInterfaceSubClass, alt->desc.bInterfaceProtocol)) return -ENOMEM; - if (add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, + if (add_uevent_var(env, "MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X", le16_to_cpu(usb_dev->descriptor.idVendor), le16_to_cpu(usb_dev->descriptor.idProduct), @@ -1404,14 +1392,12 @@ static int usb_if_uevent(struct device *dev, char **envp, int num_envp, alt->desc.bInterfaceProtocol)) return -ENOMEM; - envp[i] = NULL; return 0; } #else -static int usb_if_uevent(struct device *dev, char **envp, - int num_envp, char *buffer, int buffer_size) +static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env) { return -ENODEV; } diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index a593f900eff..070217322c9 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c @@ -197,7 +197,7 @@ static struct w1_family w1_default_family = { .fops = &w1_default_fops, }; -static int w1_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size); +static int w1_uevent(struct device *dev, struct kobj_uevent_env *env); static struct bus_type w1_bus_type = { .name = "w1", @@ -396,13 +396,12 @@ static void w1_destroy_master_attributes(struct w1_master *master) } #ifdef CONFIG_HOTPLUG -static int w1_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int w1_uevent(struct device *dev, struct kobj_uevent_env *env) { struct w1_master *md = NULL; struct w1_slave *sl = NULL; char *event_owner, *name; - int err, cur_index=0, cur_len=0; + int err; if (dev->driver == &w1_master_driver) { md = container_of(dev, struct w1_master, dev); @@ -423,23 +422,19 @@ static int w1_uevent(struct device *dev, char **envp, int num_envp, if (dev->driver != &w1_slave_driver || !sl) return 0; - err = add_uevent_var(envp, num_envp, &cur_index, buffer, buffer_size, - &cur_len, "W1_FID=%02X", sl->reg_num.family); + err = add_uevent_var(env, "W1_FID=%02X", sl->reg_num.family); if (err) return err; - err = add_uevent_var(envp, num_envp, &cur_index, buffer, buffer_size, - &cur_len, "W1_SLAVE_ID=%024LX", - (unsigned long long)sl->reg_num.id); - envp[cur_index] = NULL; + err = add_uevent_var(env, "W1_SLAVE_ID=%024LX", + (unsigned long long)sl->reg_num.id); if (err) return err; return 0; }; #else -static int w1_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int w1_uevent(struct device *dev, struct kobj_uevent_env *env) { return 0; } diff --git a/include/asm-powerpc/of_device.h b/include/asm-powerpc/of_device.h index ec2a8a2c737..93262f2546a 100644 --- a/include/asm-powerpc/of_device.h +++ b/include/asm-powerpc/of_device.h @@ -20,7 +20,7 @@ struct of_device extern ssize_t of_device_get_modalias(struct of_device *ofdev, char *str, ssize_t len); extern int of_device_uevent(struct device *dev, - char **envp, int num_envp, char *buffer, int buffer_size); + struct kobj_uevent_env *env); /* This is just here during the transition */ #include diff --git a/include/linux/device.h b/include/linux/device.h index 5d97ca6d865..2e15822fe40 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -66,8 +66,7 @@ struct bus_type { struct driver_attribute * drv_attrs; int (*match)(struct device * dev, struct device_driver * drv); - int (*uevent)(struct device *dev, char **envp, - int num_envp, char *buffer, int buffer_size); + int (*uevent)(struct device *dev, struct kobj_uevent_env *env); int (*probe)(struct device * dev); int (*remove)(struct device * dev); void (*shutdown)(struct device * dev); @@ -187,10 +186,8 @@ struct class { struct class_device_attribute * class_dev_attrs; struct device_attribute * dev_attrs; - int (*uevent)(struct class_device *dev, char **envp, - int num_envp, char *buffer, int buffer_size); - int (*dev_uevent)(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size); + int (*uevent)(struct class_device *dev, struct kobj_uevent_env *env); + int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env); void (*release)(struct class_device *dev); void (*class_release)(struct class *class); @@ -266,8 +263,7 @@ struct class_device { struct attribute_group ** groups; /* optional groups */ void (*release)(struct class_device *dev); - int (*uevent)(struct class_device *dev, char **envp, - int num_envp, char *buffer, int buffer_size); + int (*uevent)(struct class_device *dev, struct kobj_uevent_env *env); char class_id[BUS_ID_SIZE]; /* unique to this class */ }; @@ -335,8 +331,7 @@ extern void class_device_destroy(struct class *cls, dev_t devt); struct device_type { const char *name; struct attribute_group **groups; - int (*uevent)(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size); + int (*uevent)(struct device *dev, struct kobj_uevent_env *env); void (*release)(struct device *dev); int (*suspend)(struct device * dev, pm_message_t state); int (*resume)(struct device * dev); diff --git a/include/linux/kobject.h b/include/linux/kobject.h index 949706c3362..626bdd3c3dd 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -29,6 +29,8 @@ #define KOBJ_NAME_LEN 20 #define UEVENT_HELPER_PATH_LEN 256 +#define UEVENT_NUM_ENVP 32 /* number of env pointers */ +#define UEVENT_BUFFER_SIZE 2048 /* buffer for the variables */ /* path to the userspace helper executed on an event */ extern char uevent_helper[]; @@ -111,11 +113,18 @@ struct kobj_type { struct attribute ** default_attrs; }; +struct kobj_uevent_env { + char *envp[UEVENT_NUM_ENVP]; + int envp_idx; + char buf[UEVENT_BUFFER_SIZE]; + int buflen; +}; + struct kset_uevent_ops { int (*filter)(struct kset *kset, struct kobject *kobj); const char *(*name)(struct kset *kset, struct kobject *kobj); - int (*uevent)(struct kset *kset, struct kobject *kobj, char **envp, - int num_envp, char *buffer, int buffer_size); + int (*uevent)(struct kset *kset, struct kobject *kobj, + struct kobj_uevent_env *env); }; /* @@ -275,10 +284,8 @@ int kobject_uevent(struct kobject *kobj, enum kobject_action action); int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, char *envp[]); -int add_uevent_var(char **envp, int num_envp, int *cur_index, - char *buffer, int buffer_size, int *cur_len, - const char *format, ...) - __attribute__((format (printf, 7, 8))); +int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...) + __attribute__((format (printf, 2, 3))); #else static inline int kobject_uevent(struct kobject *kobj, enum kobject_action action) { return 0; } @@ -287,9 +294,7 @@ static inline int kobject_uevent_env(struct kobject *kobj, char *envp[]) { return 0; } -static inline int add_uevent_var(char **envp, int num_envp, int *cur_index, - char *buffer, int buffer_size, int *cur_len, - const char *format, ...) +static inline int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...) { return 0; } #endif diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index e06a8dcec0f..7d8aeb30163 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c @@ -22,8 +22,6 @@ #include #include -#define BUFFER_SIZE 2048 /* buffer for the variables */ -#define NUM_ENVP 32 /* number of env pointers */ /* the strings here must match the enum in include/linux/kobject.h */ const char *kobject_actions[] = { @@ -54,31 +52,21 @@ static struct sock *uevent_sock; * corresponding error when it fails. */ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, - char *envp_ext[]) + char *envp_ext[]) { - char **envp; - char *buffer; - char *scratch; - const char *action_string; + struct kobj_uevent_env *env; + const char *action_string = kobject_actions[action]; const char *devpath = NULL; const char *subsystem; struct kobject *top_kobj; struct kset *kset; struct kset_uevent_ops *uevent_ops; u64 seq; - char *seq_buff; int i = 0; int retval = 0; - int j; pr_debug("%s\n", __FUNCTION__); - action_string = kobject_actions[action]; - if (!action_string) { - pr_debug("kobject attempted to send uevent without action_string!\n"); - return -EINVAL; - } - /* search the kset we belong to */ top_kobj = kobj; while (!top_kobj->kset && top_kobj->parent) { @@ -92,7 +80,7 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, kset = top_kobj->kset; uevent_ops = kset->uevent_ops; - /* skip the event, if the filter returns zero. */ + /* skip the event, if the filter returns zero. */ if (uevent_ops && uevent_ops->filter) if (!uevent_ops->filter(kset, kobj)) { pr_debug("kobject filter function caused the event to drop!\n"); @@ -109,18 +97,11 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, return 0; } - /* environment index */ - envp = kzalloc(NUM_ENVP * sizeof (char *), GFP_KERNEL); - if (!envp) + /* environment buffer */ + env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL); + if (!env) return -ENOMEM; - /* environment values */ - buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL); - if (!buffer) { - retval = -ENOMEM; - goto exit; - } - /* complete object path */ devpath = kobject_get_path(kobj, GFP_KERNEL); if (!devpath) { @@ -128,29 +109,29 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, goto exit; } - /* event environemnt for helper process only */ - envp[i++] = "HOME=/"; - envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; - /* default keys */ - scratch = buffer; - envp [i++] = scratch; - scratch += sprintf(scratch, "ACTION=%s", action_string) + 1; - envp [i++] = scratch; - scratch += sprintf (scratch, "DEVPATH=%s", devpath) + 1; - envp [i++] = scratch; - scratch += sprintf(scratch, "SUBSYSTEM=%s", subsystem) + 1; - for (j = 0; envp_ext && envp_ext[j]; j++) - envp[i++] = envp_ext[j]; - /* just reserve the space, overwrite it after kset call has returned */ - envp[i++] = seq_buff = scratch; - scratch += strlen("SEQNUM=18446744073709551616") + 1; + retval = add_uevent_var(env, "ACTION=%s", action_string); + if (retval) + goto exit; + retval = add_uevent_var(env, "DEVPATH=%s", devpath); + if (retval) + goto exit; + retval = add_uevent_var(env, "SUBSYSTEM=%s", subsystem); + if (retval) + goto exit; + + /* keys passed in from the caller */ + if (envp_ext) { + for (i = 0; envp_ext[i]; i++) { + retval = add_uevent_var(env, envp_ext[i]); + if (retval) + goto exit; + } + } /* let the kset specific function add its stuff */ if (uevent_ops && uevent_ops->uevent) { - retval = uevent_ops->uevent(kset, kobj, - &envp[i], NUM_ENVP - i, scratch, - BUFFER_SIZE - (scratch - buffer)); + retval = uevent_ops->uevent(kset, kobj, env); if (retval) { pr_debug ("%s - uevent() returned %d\n", __FUNCTION__, retval); @@ -158,11 +139,13 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, } } - /* we will send an event, request a new sequence number */ + /* we will send an event, so request a new sequence number */ spin_lock(&sequence_lock); seq = ++uevent_seqnum; spin_unlock(&sequence_lock); - sprintf(seq_buff, "SEQNUM=%llu", (unsigned long long)seq); + retval = add_uevent_var(env, "SEQNUM=%llu", (unsigned long long)seq); + if (retval) + goto exit; #if defined(CONFIG_NET) /* send netlink message */ @@ -172,17 +155,19 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, /* allocate message with the maximum possible size */ len = strlen(action_string) + strlen(devpath) + 2; - skb = alloc_skb(len + BUFFER_SIZE, GFP_KERNEL); + skb = alloc_skb(len + env->buflen, GFP_KERNEL); if (skb) { + char *scratch; + /* add header */ scratch = skb_put(skb, len); sprintf(scratch, "%s@%s", action_string, devpath); /* copy keys to our continuous event payload buffer */ - for (i = 2; envp[i]; i++) { - len = strlen(envp[i]) + 1; + for (i = 0; i < env->envp_idx; i++) { + len = strlen(env->envp[i]) + 1; scratch = skb_put(skb, len); - strcpy(scratch, envp[i]); + strcpy(scratch, env->envp[i]); } NETLINK_CB(skb).dst_group = 1; @@ -198,13 +183,19 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, argv [0] = uevent_helper; argv [1] = (char *)subsystem; argv [2] = NULL; - call_usermodehelper (argv[0], argv, envp, UMH_WAIT_EXEC); + retval = add_uevent_var(env, "HOME=/"); + if (retval) + goto exit; + retval = add_uevent_var(env, "PATH=/sbin:/bin:/usr/sbin:/usr/bin"); + if (retval) + goto exit; + + call_usermodehelper (argv[0], argv, env->envp, UMH_WAIT_EXEC); } exit: kfree(devpath); - kfree(buffer); - kfree(envp); + kfree(env); return retval; } @@ -227,52 +218,38 @@ int kobject_uevent(struct kobject *kobj, enum kobject_action action) EXPORT_SYMBOL_GPL(kobject_uevent); /** - * add_uevent_var - helper for creating event variables - * @envp: Pointer to table of environment variables, as passed into - * uevent() method. - * @num_envp: Number of environment variable slots available, as - * passed into uevent() method. - * @cur_index: Pointer to current index into @envp. It should be - * initialized to 0 before the first call to add_uevent_var(), - * and will be incremented on success. - * @buffer: Pointer to buffer for environment variables, as passed - * into uevent() method. - * @buffer_size: Length of @buffer, as passed into uevent() method. - * @cur_len: Pointer to current length of space used in @buffer. - * Should be initialized to 0 before the first call to - * add_uevent_var(), and will be incremented on success. - * @format: Format for creating environment variable (of the form - * "XXX=%x") for snprintf(). + * add_uevent_var - add key value string to the environment buffer + * @env: environment buffer structure + * @format: printf format for the key=value pair * * Returns 0 if environment variable was added successfully or -ENOMEM * if no space was available. */ -int add_uevent_var(char **envp, int num_envp, int *cur_index, - char *buffer, int buffer_size, int *cur_len, - const char *format, ...) +int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...) { va_list args; + int len; - /* - * We check against num_envp - 1 to make sure there is at - * least one slot left after we return, since kobject_uevent() - * needs to set the last slot to NULL. - */ - if (*cur_index >= num_envp - 1) + if (env->envp_idx >= ARRAY_SIZE(env->envp)) { + printk(KERN_ERR "add_uevent_var: too many keys\n"); + WARN_ON(1); return -ENOMEM; - - envp[*cur_index] = buffer + *cur_len; + } va_start(args, format); - *cur_len += vsnprintf(envp[*cur_index], - max(buffer_size - *cur_len, 0), - format, args) + 1; + len = vsnprintf(&env->buf[env->buflen], + sizeof(env->buf) - env->buflen, + format, args); va_end(args); - if (*cur_len > buffer_size) + if (len >= (sizeof(env->buf) - env->buflen)) { + printk(KERN_ERR "add_uevent_var: buffer size too small\n"); + WARN_ON(1); return -ENOMEM; + } - (*cur_index)++; + env->envp[env->envp_idx++] = &env->buf[env->buflen]; + env->buflen += len + 1; return 0; } EXPORT_SYMBOL_GPL(add_uevent_var); diff --git a/net/atm/atm_sysfs.c b/net/atm/atm_sysfs.c index f094a0879c1..9ef07eda2c4 100644 --- a/net/atm/atm_sysfs.c +++ b/net/atm/atm_sysfs.c @@ -105,10 +105,9 @@ static struct class_device_attribute *atm_attrs[] = { NULL }; -static int atm_uevent(struct class_device *cdev, char **envp, int num_envp, char *buf, int size) +static int atm_uevent(struct class_device *cdev, struct kobj_uevent_env *env) { struct atm_dev *adev; - int i = 0, len = 0; if (!cdev) return -ENODEV; @@ -117,11 +116,9 @@ static int atm_uevent(struct class_device *cdev, char **envp, int num_envp, char if (!adev) return -ENODEV; - if (add_uevent_var(envp, num_envp, &i, buf, size, &len, - "NAME=%s%d", adev->type, adev->number)) + if (add_uevent_var(env, "NAME=%s%d", adev->type, adev->number)) return -ENOMEM; - envp[i] = NULL; return 0; } diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 909a03d6c0e..6628e457ddc 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -396,28 +396,22 @@ static struct attribute_group wireless_group = { #endif /* CONFIG_SYSFS */ #ifdef CONFIG_HOTPLUG -static int netdev_uevent(struct device *d, char **envp, - int num_envp, char *buf, int size) +static int netdev_uevent(struct device *d, struct kobj_uevent_env *env) { struct net_device *dev = to_net_dev(d); - int retval, len = 0, i = 0; + int retval; /* pass interface to uevent. */ - retval = add_uevent_var(envp, num_envp, &i, - buf, size, &len, - "INTERFACE=%s", dev->name); + retval = add_uevent_var(env, "INTERFACE=%s", dev->name); if (retval) goto exit; /* pass ifindex to uevent. * ifindex is useful as it won't change (interface name may change) * and is what RtNetlink uses natively. */ - retval = add_uevent_var(envp, num_envp, &i, - buf, size, &len, - "IFINDEX=%d", dev->ifindex); + retval = add_uevent_var(env, "IFINDEX=%d", dev->ifindex); exit: - envp[i] = NULL; return retval; } #endif diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c index 2d5d2255a27..29f820e1825 100644 --- a/net/wireless/sysfs.c +++ b/net/wireless/sysfs.c @@ -53,8 +53,7 @@ static void wiphy_dev_release(struct device *dev) } #ifdef CONFIG_HOTPLUG -static int wiphy_uevent(struct device *dev, char **envp, - int num_envp, char *buf, int size) +static int wiphy_uevent(struct device *dev, struct kobj_uevent_env *env) { /* TODO, we probably need stuff here */ return 0; diff --git a/sound/aoa/soundbus/core.c b/sound/aoa/soundbus/core.c index 64d16391433..f84f3e50578 100644 --- a/sound/aoa/soundbus/core.c +++ b/sound/aoa/soundbus/core.c @@ -56,13 +56,12 @@ static int soundbus_probe(struct device *dev) } -static int soundbus_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int soundbus_uevent(struct device *dev, struct kobj_uevent_env *env) { struct soundbus_dev * soundbus_dev; struct of_device * of; const char *compat; - int retval = 0, i = 0, length = 0; + int retval = 0; int cplen, seen = 0; if (!dev) @@ -75,15 +74,11 @@ static int soundbus_uevent(struct device *dev, char **envp, int num_envp, of = &soundbus_dev->ofdev; /* stuff we want to pass to /sbin/hotplug */ - retval = add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "OF_NAME=%s", of->node->name); + retval = add_uevent_var(env, "OF_NAME=%s", of->node->name); if (retval) return retval; - retval = add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "OF_TYPE=%s", of->node->type); + retval = add_uevent_var(env, "OF_TYPE=%s", of->node->type); if (retval) return retval; @@ -93,27 +88,19 @@ static int soundbus_uevent(struct device *dev, char **envp, int num_envp, compat = of_get_property(of->node, "compatible", &cplen); while (compat && cplen > 0) { - int tmp = length; - retval = add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "OF_COMPATIBLE_%d=%s", seen, compat); + int tmp = env->buflen; + retval = add_uevent_var(env, "OF_COMPATIBLE_%d=%s", seen, compat); if (retval) return retval; - compat += length - tmp; - cplen -= length - tmp; + compat += env->buflen - tmp; + cplen -= env->buflen - tmp; seen += 1; } - retval = add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "OF_COMPATIBLE_N=%d", seen); + retval = add_uevent_var(env, "OF_COMPATIBLE_N=%d", seen); if (retval) return retval; - retval = add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MODALIAS=%s", soundbus_dev->modalias); - - envp[i] = NULL; + retval = add_uevent_var(env, "MODALIAS=%s", soundbus_dev->modalias); return retval; } -- cgit v1.2.3-70-g09d2 From 6a8d8abb6e4497ae4132a9b1f0a956ea501f1c46 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Wed, 15 Aug 2007 15:38:28 +0200 Subject: Driver core: add CONFIG_UEVENT_HELPER_PATH The kernel creates a process for every event that is send, even when there is no binary it could execute. We are needlessly creating around 200-300 failing processes during early bootup, until we have the chance to disable it from userspace. This change allows us to disable /sbin/hotplug entirely, if you want to, by setting UEVENT_HELPER_PATH="" in the kernel config. Signed-off-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/base/Kconfig | 8 ++++++++ lib/kobject_uevent.c | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index 5d6312e3349..d7da109c24f 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -1,5 +1,13 @@ menu "Generic Driver Options" +config UEVENT_HELPER_PATH + string "path to uevent helper" + depends on HOTPLUG + default "/sbin/hotplug" + help + Path to uevent helper program forked by the kernel for + every uevent. + config STANDALONE bool "Select only drivers that don't need compile-time external firmware" if EXPERIMENTAL default y diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index 7d8aeb30163..5ccda460262 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c @@ -35,7 +35,7 @@ const char *kobject_actions[] = { #if defined(CONFIG_HOTPLUG) u64 uevent_seqnum; -char uevent_helper[UEVENT_HELPER_PATH_LEN] = "/sbin/hotplug"; +char uevent_helper[UEVENT_HELPER_PATH_LEN] = CONFIG_UEVENT_HELPER_PATH; static DEFINE_SPINLOCK(sequence_lock); #if defined(CONFIG_NET) static struct sock *uevent_sock; -- cgit v1.2.3-70-g09d2 From d6b05b84edf590ff872de6310ec20d60b5b37dd2 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 12 Sep 2007 15:06:57 -0700 Subject: Driver core: remove subsys_set_kset This macro is only used by the driver core and is held over from when we had subsystems. It is not needed anymore. Signed-off-by: Greg Kroah-Hartman --- drivers/base/bus.c | 3 ++- drivers/base/class.c | 2 +- include/linux/kobject.h | 13 ------------- 3 files changed, 3 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/base/bus.c b/drivers/base/bus.c index ff850d1b0d9..625f7e69452 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -823,7 +823,8 @@ int bus_register(struct bus_type * bus) if (retval) goto out; - subsys_set_kset(bus, bus_subsys); + bus->subsys.kobj.kset = &bus_subsys; + retval = subsystem_register(&bus->subsys); if (retval) goto out; diff --git a/drivers/base/class.c b/drivers/base/class.c index ecd6336bffe..cf9cf666f47 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -149,7 +149,7 @@ int class_register(struct class * cls) if (error) return error; - subsys_set_kset(cls, class_subsys); + cls->subsys.kobj.kset = &class_subsys; error = subsystem_register(&cls->subsys); if (!error) { diff --git a/include/linux/kobject.h b/include/linux/kobject.h index 626bdd3c3dd..0713799fde2 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -241,19 +241,6 @@ extern struct kset hypervisor_subsys; #define kset_set_kset_s(obj,subsys) \ (obj)->kset.kobj.kset = &(subsys) -/** - * subsys_set_kset(obj,subsys) - set kset for subsystem - * @obj: ptr to some object type. - * @_subsys: a subsystem object (not a ptr). - * - * Can be used for any object type with an embedded ->subsys. - * Sets the kset of @obj's kobject to @subsys.kset. This makes - * the object a member of that kset. - */ - -#define subsys_set_kset(obj,_subsys) \ - (obj)->subsys.kobj.kset = &(_subsys) - extern void subsystem_init(struct kset *); extern int __must_check subsystem_register(struct kset *); extern void subsystem_unregister(struct kset *); -- cgit v1.2.3-70-g09d2 From 27f20e5e4e60a7f28010eeb34399fe0cc9a1a235 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 12 Sep 2007 15:06:57 -0700 Subject: Driver core: remove kset_set_kset_s This macro is only used by the driver core and is held over from when we had subsystems. It is not needed anymore. Signed-off-by: Greg Kroah-Hartman --- drivers/base/sys.c | 2 +- include/linux/kobject.h | 14 -------------- 2 files changed, 1 insertion(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/base/sys.c b/drivers/base/sys.c index 18febe26caa..7ad89316782 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c @@ -139,7 +139,7 @@ int sysdev_class_register(struct sysdev_class * cls) kobject_name(&cls->kset.kobj)); INIT_LIST_HEAD(&cls->drivers); cls->kset.kobj.parent = &system_subsys.kobj; - kset_set_kset_s(cls, system_subsys); + cls->kset.kobj.kset = &system_subsys; return kset_register(&cls->kset); } diff --git a/include/linux/kobject.h b/include/linux/kobject.h index 0713799fde2..ee61ef27e79 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -227,20 +227,6 @@ extern struct kset hypervisor_subsys; #define kobj_set_kset_s(obj,subsys) \ (obj)->kobj.kset = &(subsys) -/** - * kset_set_kset_s(obj,subsys) - set kset for embedded kset. - * @obj: ptr to some object type. - * @subsys: a subsystem object (not a ptr). - * - * Can be used for any object type with an embedded ->kset. - * Sets the kset of @obj's embedded kobject (via its embedded - * kset) to @subsys.kset. This makes @obj a member of that - * kset. - */ - -#define kset_set_kset_s(obj,subsys) \ - (obj)->kset.kobj.kset = &(subsys) - extern void subsystem_init(struct kset *); extern int __must_check subsystem_register(struct kset *); extern void subsystem_unregister(struct kset *); -- cgit v1.2.3-70-g09d2 From 6e9d930d167f8957a12a80515f3c417a98296378 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 12 Sep 2007 15:06:57 -0700 Subject: Driver core: remove subsys_put() There are no more subsystems, it's a kset now so remove the function and the only two users, which are in the driver core. Signed-off-by: Greg Kroah-Hartman --- drivers/base/bus.c | 2 +- drivers/base/class.c | 2 +- include/linux/kobject.h | 5 ----- lib/kobject.c | 2 +- 4 files changed, 3 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 625f7e69452..2f775936544 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -734,7 +734,7 @@ struct bus_type *get_bus(struct bus_type *bus) void put_bus(struct bus_type * bus) { - subsys_put(&bus->subsys); + kset_put(&bus->subsys); } diff --git a/drivers/base/class.c b/drivers/base/class.c index cf9cf666f47..50e34132576 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -100,7 +100,7 @@ static struct class *class_get(struct class *cls) static void class_put(struct class * cls) { if (cls) - subsys_put(&cls->subsys); + kset_put(&cls->subsys); } diff --git a/include/linux/kobject.h b/include/linux/kobject.h index ee61ef27e79..45effedff31 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -238,11 +238,6 @@ static inline struct kset *subsys_get(struct kset *s) return NULL; } -static inline void subsys_put(struct kset *s) -{ - kset_put(s); -} - struct subsys_attribute { struct attribute attr; ssize_t (*show)(struct kset *, char *); diff --git a/lib/kobject.c b/lib/kobject.c index 4b08e0ff95c..0aa4e906916 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -681,7 +681,7 @@ int subsys_create_file(struct kset *s, struct subsys_attribute *a) if (subsys_get(s)) { error = sysfs_create_file(&s->kobj, &a->attr); - subsys_put(s); + kset_put(s); } return error; } -- cgit v1.2.3-70-g09d2 From 1ef4cfac01fb5e98900f5bdb2a722aac1daff11b Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 12 Sep 2007 15:06:57 -0700 Subject: Driver core: remove subsys_get() There are no more subsystems, it's a kset now so remove the function and the only two users, which are in the driver core. Signed-off-by: Greg Kroah-Hartman --- drivers/base/bus.c | 2 +- drivers/base/class.c | 2 +- include/linux/kobject.h | 7 ------- lib/kobject.c | 2 +- 4 files changed, 3 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 2f775936544..bc38085dbb1 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -728,7 +728,7 @@ EXPORT_SYMBOL_GPL(device_reprobe); struct bus_type *get_bus(struct bus_type *bus) { - return bus ? container_of(subsys_get(&bus->subsys), + return bus ? container_of(kset_get(&bus->subsys), struct bus_type, subsys) : NULL; } diff --git a/drivers/base/class.c b/drivers/base/class.c index 50e34132576..3e9b04c30fb 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -93,7 +93,7 @@ void class_remove_file(struct class * cls, const struct class_attribute * attr) static struct class *class_get(struct class *cls) { if (cls) - return container_of(subsys_get(&cls->subsys), struct class, subsys); + return container_of(kset_get(&cls->subsys), struct class, subsys); return NULL; } diff --git a/include/linux/kobject.h b/include/linux/kobject.h index 45effedff31..c0fb535d7ac 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -231,13 +231,6 @@ extern void subsystem_init(struct kset *); extern int __must_check subsystem_register(struct kset *); extern void subsystem_unregister(struct kset *); -static inline struct kset *subsys_get(struct kset *s) -{ - if (s) - return kset_get(s); - return NULL; -} - struct subsys_attribute { struct attribute attr; ssize_t (*show)(struct kset *, char *); diff --git a/lib/kobject.c b/lib/kobject.c index 0aa4e906916..1326041213d 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -679,7 +679,7 @@ int subsys_create_file(struct kset *s, struct subsys_attribute *a) if (!s || !a) return -EINVAL; - if (subsys_get(s)) { + if (kset_get(s)) { error = sysfs_create_file(&s->kobj, &a->attr); kset_put(s); } -- cgit v1.2.3-70-g09d2 From fc1ede5888ab8a9b3e7f8567b945beed35222885 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 13 Sep 2007 02:53:13 -0700 Subject: Driver core: remove put_bus() put_bus() should not be globally visable as it is not used by anything other than drivers/base/bus.c. This patch removes the visability of it, and renames it to match all of the other *_put() functions in the kernel. Signed-off-by: Greg Kroah-Hartman --- drivers/base/base.h | 1 - drivers/base/bus.c | 29 ++++++++++++++--------------- 2 files changed, 14 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/base/base.h b/drivers/base/base.h index 47eb02d9f1a..cebc7e75457 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -19,7 +19,6 @@ extern int bus_add_device(struct device * dev); extern void bus_attach_device(struct device * dev); extern void bus_remove_device(struct device * dev); extern struct bus_type *get_bus(struct bus_type * bus); -extern void put_bus(struct bus_type * bus); extern int bus_add_driver(struct device_driver *); extern void bus_remove_driver(struct device_driver *); diff --git a/drivers/base/bus.c b/drivers/base/bus.c index bc38085dbb1..4f53b758ac2 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -30,6 +30,11 @@ static int __must_check bus_rescan_devices_helper(struct device *dev, void *data); +static void bus_put(struct bus_type *bus) +{ + kset_put(&bus->subsys); +} + static ssize_t drv_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) { @@ -124,7 +129,7 @@ int bus_create_file(struct bus_type * bus, struct bus_attribute * attr) int error; if (get_bus(bus)) { error = sysfs_create_file(&bus->subsys.kobj, &attr->attr); - put_bus(bus); + bus_put(bus); } else error = -EINVAL; return error; @@ -134,7 +139,7 @@ void bus_remove_file(struct bus_type * bus, struct bus_attribute * attr) { if (get_bus(bus)) { sysfs_remove_file(&bus->subsys.kobj, &attr->attr); - put_bus(bus); + bus_put(bus); } } @@ -186,7 +191,7 @@ static ssize_t driver_unbind(struct device_driver *drv, err = count; } put_device(dev); - put_bus(bus); + bus_put(bus); return err; } static DRIVER_ATTR(unbind, S_IWUSR, NULL, driver_unbind); @@ -219,7 +224,7 @@ static ssize_t driver_bind(struct device_driver *drv, err = -ENODEV; } put_device(dev); - put_bus(bus); + bus_put(bus); return err; } static DRIVER_ATTR(bind, S_IWUSR, NULL, driver_bind); @@ -459,7 +464,7 @@ out_subsys: out_id: device_remove_attrs(bus, dev); out_put: - put_bus(dev->bus); + bus_put(dev->bus); return error; } @@ -509,7 +514,7 @@ void bus_remove_device(struct device * dev) } pr_debug("bus %s: remove device %s\n", dev->bus->name, dev->bus_id); device_release_driver(dev); - put_bus(dev->bus); + bus_put(dev->bus); } } @@ -646,7 +651,7 @@ int bus_add_driver(struct device_driver *drv) out_unregister: kobject_unregister(&drv->kobj); out_put_bus: - put_bus(bus); + bus_put(bus); return error; } @@ -671,7 +676,7 @@ void bus_remove_driver(struct device_driver * drv) driver_detach(drv); module_remove_driver(drv); kobject_unregister(&drv->kobj); - put_bus(drv->bus); + bus_put(drv->bus); } @@ -732,12 +737,6 @@ struct bus_type *get_bus(struct bus_type *bus) struct bus_type, subsys) : NULL; } -void put_bus(struct bus_type * bus) -{ - kset_put(&bus->subsys); -} - - /** * find_bus - locate bus by name. * @name: name of bus. @@ -874,7 +873,7 @@ out: * @bus: bus. * * Unregister the child subsystems and the bus itself. - * Finally, we call put_bus() to release the refcount + * Finally, we call bus_put() to release the refcount */ void bus_unregister(struct bus_type * bus) { -- cgit v1.2.3-70-g09d2 From 5901d0145c6b9e791bacd049eea11c9db9a3006e Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 13 Sep 2007 02:53:13 -0700 Subject: Driver core: remove get_bus() get_bus() should not be globally visable as it is not used by anything other than drivers/base/bus.c. This patch removes the visability of it, and renames it to match all of the other *_get() functions in the kernel. Signed-off-by: Greg Kroah-Hartman --- drivers/base/base.h | 1 - drivers/base/bus.c | 24 ++++++++++++------------ 2 files changed, 12 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/base/base.h b/drivers/base/base.h index cebc7e75457..10b2fb6c9ce 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -18,7 +18,6 @@ extern int attribute_container_init(void); extern int bus_add_device(struct device * dev); extern void bus_attach_device(struct device * dev); extern void bus_remove_device(struct device * dev); -extern struct bus_type *get_bus(struct bus_type * bus); extern int bus_add_driver(struct device_driver *); extern void bus_remove_driver(struct device_driver *); diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 4f53b758ac2..0a8d075f3e6 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -30,6 +30,12 @@ static int __must_check bus_rescan_devices_helper(struct device *dev, void *data); +static struct bus_type *bus_get(struct bus_type *bus) +{ + return bus ? container_of(kset_get(&bus->subsys), + struct bus_type, subsys) : NULL; +} + static void bus_put(struct bus_type *bus) { kset_put(&bus->subsys); @@ -127,7 +133,7 @@ static struct sysfs_ops bus_sysfs_ops = { int bus_create_file(struct bus_type * bus, struct bus_attribute * attr) { int error; - if (get_bus(bus)) { + if (bus_get(bus)) { error = sysfs_create_file(&bus->subsys.kobj, &attr->attr); bus_put(bus); } else @@ -137,7 +143,7 @@ int bus_create_file(struct bus_type * bus, struct bus_attribute * attr) void bus_remove_file(struct bus_type * bus, struct bus_attribute * attr) { - if (get_bus(bus)) { + if (bus_get(bus)) { sysfs_remove_file(&bus->subsys.kobj, &attr->attr); bus_put(bus); } @@ -177,7 +183,7 @@ static int driver_helper(struct device *dev, void *data) static ssize_t driver_unbind(struct device_driver *drv, const char *buf, size_t count) { - struct bus_type *bus = get_bus(drv->bus); + struct bus_type *bus = bus_get(drv->bus); struct device *dev; int err = -ENODEV; @@ -204,7 +210,7 @@ static DRIVER_ATTR(unbind, S_IWUSR, NULL, driver_unbind); static ssize_t driver_bind(struct device_driver *drv, const char *buf, size_t count) { - struct bus_type *bus = get_bus(drv->bus); + struct bus_type *bus = bus_get(drv->bus); struct device *dev; int err = -ENODEV; @@ -435,7 +441,7 @@ static inline void remove_deprecated_bus_links(struct device *dev) { } */ int bus_add_device(struct device * dev) { - struct bus_type * bus = get_bus(dev->bus); + struct bus_type * bus = bus_get(dev->bus); int error = 0; if (bus) { @@ -611,7 +617,7 @@ static inline void remove_probe_files(struct bus_type *bus) {} */ int bus_add_driver(struct device_driver *drv) { - struct bus_type * bus = get_bus(drv->bus); + struct bus_type * bus = bus_get(drv->bus); int error = 0; if (!bus) @@ -731,12 +737,6 @@ int device_reprobe(struct device *dev) } EXPORT_SYMBOL_GPL(device_reprobe); -struct bus_type *get_bus(struct bus_type *bus) -{ - return bus ? container_of(kset_get(&bus->subsys), - struct bus_type, subsys) : NULL; -} - /** * find_bus - locate bus by name. * @name: name of bus. -- cgit v1.2.3-70-g09d2 From 19c38de88a80913351fcacefdb461cc0b585fa87 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 12 Sep 2007 15:06:57 -0700 Subject: kobjects: fix up improper use of the kobject name field A number of different drivers incorrect access the kobject name field directly. This is not correct as the name might not be in the array. Use the proper accessor function instead. --- block/elevator.c | 2 +- block/ll_rw_blk.c | 2 +- drivers/acpi/bus.c | 2 +- drivers/cpufreq/cpufreq.c | 2 +- drivers/md/md.c | 3 +-- drivers/net/ibmveth.c | 2 +- drivers/pci/setup-irq.c | 2 +- fs/partitions/check.c | 12 +++++++----- fs/sysfs/dir.c | 2 +- net/bridge/br_sysfs_br.c | 2 +- 10 files changed, 16 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/block/elevator.c b/block/elevator.c index c6d153de9fd..b9c518afe1f 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -186,7 +186,7 @@ static elevator_t *elevator_alloc(struct request_queue *q, eq->ops = &e->ops; eq->elevator_type = e; kobject_init(&eq->kobj); - snprintf(eq->kobj.name, KOBJ_NAME_LEN, "%s", "iosched"); + kobject_set_name(&eq->kobj, "%s", "iosched"); eq->kobj.ktype = &elv_ktype; mutex_init(&eq->sysfs_lock); diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index cd9d2c5d91a..d875673e76c 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -1854,7 +1854,7 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id) init_timer(&q->unplug_timer); - snprintf(q->kobj.name, KOBJ_NAME_LEN, "%s", "queue"); + kobject_set_name(&q->kobj, "%s", "queue"); q->kobj.ktype = &queue_ktype; kobject_init(&q->kobj); diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index feab124d8e0..cbfc81579c9 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -194,7 +194,7 @@ int acpi_bus_set_power(acpi_handle handle, int state) if (!device->flags.power_manageable) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device `[%s]' is not power manageable\n", - device->dev.kobj.name)); + kobject_name(&device->dev.kobj))); return -ENODEV; } /* diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 2f6a73c01b7..2ce3de5e84a 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -828,7 +828,7 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) /* prepare interface data */ policy->kobj.parent = &sys_dev->kobj; policy->kobj.ktype = &ktype_cpufreq; - strlcpy(policy->kobj.name, "cpufreq", KOBJ_NAME_LEN); + kobject_set_name(&policy->kobj, "cpufreq"); ret = kobject_register(&policy->kobj); if (ret) { diff --git a/drivers/md/md.c b/drivers/md/md.c index e8f102ea9b0..acf1b81b47c 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -3076,8 +3076,7 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data) mddev->gendisk = disk; mutex_unlock(&disks_mutex); mddev->kobj.parent = &disk->kobj; - mddev->kobj.k_name = NULL; - snprintf(mddev->kobj.name, KOBJ_NAME_LEN, "%s", "md"); + kobject_set_name(&mddev->kobj, "%s", "md"); mddev->kobj.ktype = &md_ktype; if (kobject_register(&mddev->kobj)) printk(KERN_WARNING "md: cannot register %s/md - name in use\n", diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 4ac161e1ca1..7d7758f3ad8 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -1183,7 +1183,7 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ pool_count[i], pool_size[i], pool_active[i]); kobj->parent = &dev->dev.kobj; - sprintf(kobj->name, "pool%d", i); + kobject_set_name(kobj, "pool%d", i); kobj->ktype = &ktype_veth_pool; kobject_register(kobj); } diff --git a/drivers/pci/setup-irq.c b/drivers/pci/setup-irq.c index 568f1877315..05ca2ed9eb5 100644 --- a/drivers/pci/setup-irq.c +++ b/drivers/pci/setup-irq.c @@ -48,7 +48,7 @@ pdev_fixup_irq(struct pci_dev *dev, dev->irq = irq; pr_debug("PCI: fixup irq: (%s) got %d\n", - dev->dev.kobj.name, dev->irq); + kobject_name(&dev->dev.kobj), dev->irq); /* Always tell the device, so the driver knows what is the real IRQ to use; the device does not use it. */ diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 783c57ec07d..722e12e5acc 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c @@ -381,10 +381,12 @@ void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len, p->partno = part; p->policy = disk->policy; - if (isdigit(disk->kobj.name[strlen(disk->kobj.name)-1])) - snprintf(p->kobj.name,KOBJ_NAME_LEN,"%sp%d",disk->kobj.name,part); + if (isdigit(disk->kobj.k_name[strlen(disk->kobj.k_name)-1])) + kobject_set_name(&p->kobj, "%sp%d", + kobject_name(&disk->kobj), part); else - snprintf(p->kobj.name,KOBJ_NAME_LEN,"%s%d",disk->kobj.name,part); + kobject_set_name(&p->kobj, "%s%d", + kobject_name(&disk->kobj),part); p->kobj.parent = &disk->kobj; p->kobj.ktype = &ktype_part; kobject_init(&p->kobj); @@ -477,9 +479,9 @@ void register_disk(struct gendisk *disk) struct hd_struct *p; int err; - strlcpy(disk->kobj.name,disk->disk_name,KOBJ_NAME_LEN); + kobject_set_name(&disk->kobj, "%s", disk->disk_name); /* ewww... some of these buggers have / in name... */ - s = strchr(disk->kobj.name, '/'); + s = strchr(disk->kobj.k_name, '/'); if (s) *s = '!'; if ((err = kobject_add(&disk->kobj))) diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 83e76b3813c..ea33b660ae8 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -1013,7 +1013,7 @@ again: goto again; } - new_dentry = lookup_one_len(kobj->name, new_parent, strlen(kobj->name)); + new_dentry = lookup_one_len(kobject_name(kobj), new_parent, strlen(kobject_name(kobj))); if (IS_ERR(new_dentry)) { error = PTR_ERR(new_dentry); goto out_unlock; diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c index c65f54e0e27..3312e8f2abe 100644 --- a/net/bridge/br_sysfs_br.c +++ b/net/bridge/br_sysfs_br.c @@ -435,7 +435,7 @@ int br_sysfs_addbr(struct net_device *dev) err = kobject_register(&br->ifobj); if (err) { pr_info("%s: can't add kobject (directory) %s/%s\n", - __FUNCTION__, dev->name, br->ifobj.name); + __FUNCTION__, dev->name, kobject_name(&br->ifobj)); goto out3; } return 0; -- cgit v1.2.3-70-g09d2 From 7e7654a92a5a75a350cc3458389bc76273498f6a Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 12 Sep 2007 15:06:57 -0700 Subject: cdev: remove unneeded setting of cdev names struct cdev does not need the kobject name to be set, as it is never used. This patch fixes up the few places it is set. Signed-off-by: Greg Kroah-Hartman Acked-by: Mauro Carvalho Chehab --- block/bsg.c | 5 +---- drivers/char/raw.c | 5 +---- drivers/media/dvb/dvb-core/dvbdev.c | 5 +---- drivers/usb/core/devio.c | 6 ++---- 4 files changed, 5 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/block/bsg.c b/block/bsg.c index ed264682723..b8ddfc66f21 100644 --- a/block/bsg.c +++ b/block/bsg.c @@ -1010,10 +1010,7 @@ unlock: } EXPORT_SYMBOL_GPL(bsg_register_queue); -static struct cdev bsg_cdev = { - .kobj = {.name = "bsg", }, - .owner = THIS_MODULE, -}; +static struct cdev bsg_cdev; static int __init bsg_init(void) { diff --git a/drivers/char/raw.c b/drivers/char/raw.c index 1f0d7c60c94..bbfa0e241cb 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c @@ -255,10 +255,7 @@ static const struct file_operations raw_ctl_fops = { .owner = THIS_MODULE, }; -static struct cdev raw_cdev = { - .kobj = {.name = "raw", }, - .owner = THIS_MODULE, -}; +static struct cdev raw_cdev; static int __init raw_init(void) { diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c index 56231d8edc0..18738faecbb 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.c +++ b/drivers/media/dvb/dvb-core/dvbdev.c @@ -103,10 +103,7 @@ static struct file_operations dvb_device_fops = .open = dvb_device_open, }; -static struct cdev dvb_device_cdev = { - .kobj = {.name = "dvb", }, - .owner = THIS_MODULE, -}; +static struct cdev dvb_device_cdev; int dvb_generic_open(struct inode *inode, struct file *file) { diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 927a181120a..fe98796d2ff 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -1576,6 +1576,7 @@ static unsigned int usbdev_poll(struct file *file, struct poll_table_struct *wai } const struct file_operations usbdev_file_operations = { + .owner = THIS_MODULE, .llseek = usbdev_lseek, .read = usbdev_read, .poll = usbdev_poll, @@ -1625,10 +1626,7 @@ static struct notifier_block usbdev_nb = { }; #endif -static struct cdev usb_device_cdev = { - .kobj = {.name = "usb_device", }, - .owner = THIS_MODULE, -}; +static struct cdev usb_device_cdev; int __init usb_devio_init(void) { -- cgit v1.2.3-70-g09d2 From 34980ca8faebfcce31094eba6ffbb0113950361f Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 12 Sep 2007 15:06:57 -0700 Subject: Drivers: clean up direct setting of the name of a kset A kset should not have its name set directly, so dynamically set the name at runtime. This is needed to remove the static array in the kobject structure which will be changed in a future patch. Signed-off-by: Greg Kroah-Hartman --- drivers/edac/edac_mc_sysfs.c | 3 ++- drivers/pci/hotplug/rpadlpar_sysfs.c | 6 +++--- fs/dlm/lockspace.c | 2 +- fs/gfs2/locking/dlm/sysfs.c | 2 +- fs/gfs2/sys.c | 2 +- fs/ocfs2/cluster/masklog.c | 3 ++- 6 files changed, 10 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index 4a0576bd06f..3706b2bc098 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c @@ -743,7 +743,7 @@ static struct kobj_type ktype_mc_set_attribs = { * /sys/devices/system/edac/mc */ static struct kset mc_kset = { - .kobj = {.name = "mc", .ktype = &ktype_mc_set_attribs }, + .kobj = {.ktype = &ktype_mc_set_attribs }, .ktype = &ktype_mci, }; @@ -1010,6 +1010,7 @@ int edac_sysfs_setup_mc_kset(void) } /* Init the MC's kobject */ + kobject_set_name(&mc_kset.kobj, "mc"); mc_kset.kobj.parent = &edac_class->kset.kobj; /* register the mc_kset */ diff --git a/drivers/pci/hotplug/rpadlpar_sysfs.c b/drivers/pci/hotplug/rpadlpar_sysfs.c index df076064a3e..a080fedf033 100644 --- a/drivers/pci/hotplug/rpadlpar_sysfs.c +++ b/drivers/pci/hotplug/rpadlpar_sysfs.c @@ -129,17 +129,17 @@ struct kobj_type ktype_dlpar_io = { }; struct kset dlpar_io_kset = { - .kobj = {.name = DLPAR_KOBJ_NAME, - .ktype = &ktype_dlpar_io, + .kobj = {.ktype = &ktype_dlpar_io, .parent = &pci_hotplug_slots_subsys.kobj}, .ktype = &ktype_dlpar_io, }; int dlpar_sysfs_init(void) { + kobject_set_name(&dlpar_io_kset.kobj, DLPAR_KOBJ_NAME); if (kset_register(&dlpar_io_kset)) { printk(KERN_ERR "rpadlpar_io: cannot register kset for %s\n", - dlpar_io_kset.kobj.name); + kobject_name(&dlpar_io_kset.kobj)); return -EINVAL; } diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c index 1dc72105ab1..f88f88fdedf 100644 --- a/fs/dlm/lockspace.c +++ b/fs/dlm/lockspace.c @@ -167,7 +167,6 @@ static struct kobj_type dlm_ktype = { }; static struct kset dlm_kset = { - .kobj = {.name = "dlm",}, .ktype = &dlm_ktype, }; @@ -228,6 +227,7 @@ int dlm_lockspace_init(void) INIT_LIST_HEAD(&lslist); spin_lock_init(&lslist_lock); + kobject_set_name(&dlm_kset.kobj, "dlm"); kobj_set_kset_s(&dlm_kset, kernel_subsys); error = kset_register(&dlm_kset); if (error) diff --git a/fs/gfs2/locking/dlm/sysfs.c b/fs/gfs2/locking/dlm/sysfs.c index d9fe3ca40e1..ae9e6a25fe2 100644 --- a/fs/gfs2/locking/dlm/sysfs.c +++ b/fs/gfs2/locking/dlm/sysfs.c @@ -190,7 +190,6 @@ static struct kobj_type gdlm_ktype = { }; static struct kset gdlm_kset = { - .kobj = {.name = "lock_dlm",}, .ktype = &gdlm_ktype, }; @@ -224,6 +223,7 @@ int gdlm_sysfs_init(void) { int error; + kobject_set_name(&gdlm_kset.kobj, "lock_dlm"); kobj_set_kset_s(&gdlm_kset, kernel_subsys); error = kset_register(&gdlm_kset); if (error) diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index c26c21b53c1..640cb6a6fc4 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c @@ -222,7 +222,6 @@ static struct kobj_type gfs2_ktype = { }; static struct kset gfs2_kset = { - .kobj = {.name = "gfs2"}, .ktype = &gfs2_ktype, }; @@ -553,6 +552,7 @@ int gfs2_sys_init(void) { gfs2_sys_margs = NULL; spin_lock_init(&gfs2_sys_margs_lock); + kobject_set_name(&gfs2_kset.kobj, "gfs2"); kobj_set_kset_s(&gfs2_kset, fs_subsys); return kset_register(&gfs2_kset); } diff --git a/fs/ocfs2/cluster/masklog.c b/fs/ocfs2/cluster/masklog.c index e9e042b93db..a4882c8df94 100644 --- a/fs/ocfs2/cluster/masklog.c +++ b/fs/ocfs2/cluster/masklog.c @@ -143,7 +143,7 @@ static struct kobj_type mlog_ktype = { }; static struct kset mlog_kset = { - .kobj = {.name = "logmask", .ktype = &mlog_ktype}, + .kobj = {.ktype = &mlog_ktype}, }; int mlog_sys_init(struct kset *o2cb_subsys) @@ -156,6 +156,7 @@ int mlog_sys_init(struct kset *o2cb_subsys) } mlog_attr_ptrs[i] = NULL; + kobject_set_name(&mlog_kset.kobj, "logmask"); kobj_set_kset_s(&mlog_kset, *o2cb_subsys); return kset_register(&mlog_kset); } -- cgit v1.2.3-70-g09d2 From 6374475661172d508a9b93a2740a3fdc9d899756 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 13 Aug 2007 11:24:33 +0200 Subject: dmi-id: Use dynamic sysfs attributes We can use sysfs attributes with an extra parameter for dmi id attributes. This makes it possible to use the same callback function for all attributes, reducing the binary size significantly (-18% on x86_64.) Signed-off-by: Jean Delvare Acked-by: Lennart Poettering Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/dmi-id.c | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/firmware/dmi-id.c b/drivers/firmware/dmi-id.c index 2678098d450..a7bd87d5289 100644 --- a/drivers/firmware/dmi-id.c +++ b/drivers/firmware/dmi-id.c @@ -13,21 +13,35 @@ #include #include +struct dmi_device_attribute{ + struct device_attribute dev_attr; + int field; +}; +#define to_dmi_dev_attr(_dev_attr) \ + container_of(_dev_attr, struct dmi_device_attribute, dev_attr) + #define DEFINE_DMI_ATTR(_name, _mode, _show) \ static struct device_attribute sys_dmi_##_name##_attr = \ __ATTR(_name, _mode, _show, NULL); -#define DEFINE_DMI_ATTR_WITH_SHOW(_name, _mode, _field) \ -static ssize_t sys_dmi_##_name##_show(struct device *dev, \ - struct device_attribute *attr, \ - char *page) \ -{ \ - ssize_t len; \ - len = scnprintf(page, PAGE_SIZE, "%s\n", dmi_get_system_info(_field)); \ - page[len-1] = '\n'; \ - return len; \ -} \ -DEFINE_DMI_ATTR(_name, _mode, sys_dmi_##_name##_show); +static ssize_t sys_dmi_field_show(struct device *dev, + struct device_attribute *attr, + char *page) +{ + int field = to_dmi_dev_attr(attr)->field; + ssize_t len; + len = scnprintf(page, PAGE_SIZE, "%s\n", dmi_get_system_info(field)); + page[len-1] = '\n'; + return len; +} + +#define DMI_ATTR(_name, _mode, _show, _field) \ + { .dev_attr = __ATTR(_name, _mode, _show, NULL), \ + .field = _field } + +#define DEFINE_DMI_ATTR_WITH_SHOW(_name, _mode, _field) \ +static struct dmi_device_attribute sys_dmi_##_name##_attr = \ + DMI_ATTR(_name, _mode, sys_dmi_field_show, _field); DEFINE_DMI_ATTR_WITH_SHOW(bios_vendor, 0444, DMI_BIOS_VENDOR); DEFINE_DMI_ATTR_WITH_SHOW(bios_version, 0444, DMI_BIOS_VERSION); @@ -160,7 +174,7 @@ static struct device *dmi_dev; #define ADD_DMI_ATTR(_name, _field) \ if (dmi_get_system_info(_field)) \ - sys_dmi_attributes[i++] = & sys_dmi_##_name##_attr.attr; + sys_dmi_attributes[i++] = &sys_dmi_##_name##_attr.dev_attr.attr; extern int dmi_available; -- cgit v1.2.3-70-g09d2 From 34b51f39e23bc9e529830ddf6108381d4bab95a6 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 13 Aug 2007 11:26:26 +0200 Subject: dmi-id: Possible cleanup The DEFINE_DMI_ATTR macro has a single user left so we can expand it for slightly shorter/simpler code. Signed-off-by: Jean Delvare Acked-by: Lennart Poettering Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/dmi-id.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/firmware/dmi-id.c b/drivers/firmware/dmi-id.c index a7bd87d5289..b6e1eb77d14 100644 --- a/drivers/firmware/dmi-id.c +++ b/drivers/firmware/dmi-id.c @@ -20,10 +20,6 @@ struct dmi_device_attribute{ #define to_dmi_dev_attr(_dev_attr) \ container_of(_dev_attr, struct dmi_device_attribute, dev_attr) -#define DEFINE_DMI_ATTR(_name, _mode, _show) \ -static struct device_attribute sys_dmi_##_name##_attr = \ - __ATTR(_name, _mode, _show, NULL); - static ssize_t sys_dmi_field_show(struct device *dev, struct device_attribute *attr, char *page) @@ -135,7 +131,8 @@ static ssize_t sys_dmi_modalias_show(struct device *dev, return r+1; } -DEFINE_DMI_ATTR(modalias, 0444, sys_dmi_modalias_show); +static struct device_attribute sys_dmi_modalias_attr = + __ATTR(modalias, 0444, sys_dmi_modalias_show, NULL); static struct attribute *sys_dmi_attributes[DMI_STRING_MAX+2]; -- cgit v1.2.3-70-g09d2 From 60043428a561a5d431ad479b7ecb79805ed04efc Mon Sep 17 00:00:00 2001 From: "tonyj@suse.de" Date: Tue, 7 Aug 2007 22:28:47 -0700 Subject: Convert from class_device to device for drivers/video Convert from class_device to device for drivers/video. Signed-off-by: Tony Jones Signed-off-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/video.c | 4 ++-- drivers/video/output.c | 29 ++++++++++++++++------------- include/linux/video_output.h | 4 ++-- 3 files changed, 20 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index d05891f1628..b8a2095cb5e 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -316,7 +316,7 @@ static int acpi_video_output_get(struct output_device *od) { unsigned long state; struct acpi_video_device *vd = - (struct acpi_video_device *)class_get_devdata(&od->class_dev); + (struct acpi_video_device *)dev_get_drvdata(&od->dev); acpi_video_device_get_state(vd, &state); return (int)state; } @@ -325,7 +325,7 @@ static int acpi_video_output_set(struct output_device *od) { unsigned long state = od->request_state; struct acpi_video_device *vd= - (struct acpi_video_device *)class_get_devdata(&od->class_dev); + (struct acpi_video_device *)dev_get_drvdata(&od->dev); return acpi_video_device_set_state(vd, state); } diff --git a/drivers/video/output.c b/drivers/video/output.c index 1473f2c892d..f2df5519c9c 100644 --- a/drivers/video/output.c +++ b/drivers/video/output.c @@ -31,7 +31,8 @@ MODULE_DESCRIPTION("Display Output Switcher Lowlevel Control Abstraction"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Luming Yu "); -static ssize_t video_output_show_state(struct class_device *dev,char *buf) +static ssize_t video_output_show_state(struct device *dev, + struct device_attribute *attr, char *buf) { ssize_t ret_size = 0; struct output_device *od = to_output_device(dev); @@ -40,8 +41,9 @@ static ssize_t video_output_show_state(struct class_device *dev,char *buf) return ret_size; } -static ssize_t video_output_store_state(struct class_device *dev, - const char *buf,size_t count) +static ssize_t video_output_store_state(struct device *dev, + struct device_attribute *attr, + const char *buf,size_t count) { char *endp; struct output_device *od = to_output_device(dev); @@ -60,21 +62,22 @@ static ssize_t video_output_store_state(struct class_device *dev, return count; } -static void video_output_class_release(struct class_device *dev) +static void video_output_release(struct device *dev) { struct output_device *od = to_output_device(dev); kfree(od); } -static struct class_device_attribute video_output_attributes[] = { +static struct device_attribute video_output_attributes[] = { __ATTR(state, 0644, video_output_show_state, video_output_store_state), __ATTR_NULL, }; + static struct class video_output_class = { .name = "video_output", - .release = video_output_class_release, - .class_dev_attrs = video_output_attributes, + .dev_release = video_output_release, + .dev_attrs = video_output_attributes, }; struct output_device *video_output_register(const char *name, @@ -91,11 +94,11 @@ struct output_device *video_output_register(const char *name, goto error_return; } new_dev->props = op; - new_dev->class_dev.class = &video_output_class; - new_dev->class_dev.dev = dev; - strlcpy(new_dev->class_dev.class_id,name,KOBJ_NAME_LEN); - class_set_devdata(&new_dev->class_dev,devdata); - ret_code = class_device_register(&new_dev->class_dev); + new_dev->dev.class = &video_output_class; + new_dev->dev.parent = dev; + strlcpy(new_dev->dev.bus_id,name, BUS_ID_SIZE); + dev_set_drvdata(&new_dev->dev, devdata); + ret_code = device_register(&new_dev->dev); if (ret_code) { kfree(new_dev); goto error_return; @@ -111,7 +114,7 @@ void video_output_unregister(struct output_device *dev) { if (!dev) return; - class_device_unregister(&dev->class_dev); + device_unregister(&dev->dev); } EXPORT_SYMBOL(video_output_unregister); diff --git a/include/linux/video_output.h b/include/linux/video_output.h index e63e0c03ee0..2fb46bc9340 100644 --- a/include/linux/video_output.h +++ b/include/linux/video_output.h @@ -31,9 +31,9 @@ struct output_properties { struct output_device { int request_state; struct output_properties *props; - struct class_device class_dev; + struct device dev; }; -#define to_output_device(obj) container_of(obj, struct output_device, class_dev) +#define to_output_device(obj) container_of(obj, struct output_device, dev) struct output_device *video_output_register(const char *name, struct device *dev, void *devdata, -- cgit v1.2.3-70-g09d2 From 07c015e7654821f2dda00dcf152c65b2afd46ac3 Mon Sep 17 00:00:00 2001 From: "tonyj@suse.de" Date: Tue, 7 Aug 2007 22:28:44 -0700 Subject: Convert from class_device to device in drivers/char Convert from class_device to device in drivers/char. Signed-off-by: Tony Jones Signed-off-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/char/dsp56k.c | 4 ++-- drivers/char/ip2/ip2main.c | 12 ++++++------ drivers/char/ipmi/ipmi_devintf.c | 6 +++--- drivers/char/istallion.c | 8 +++----- drivers/char/lp.c | 5 ++--- drivers/char/pcmcia/cm4000_cs.c | 5 ++--- drivers/char/pcmcia/cm4040_cs.c | 5 ++--- drivers/char/snsc.c | 3 +-- drivers/char/stallion.c | 7 +++---- drivers/char/tipar.c | 6 +++--- drivers/char/viotape.c | 10 +++++----- 11 files changed, 32 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c index 9b8278e1f4f..acbfe1c49b4 100644 --- a/drivers/char/dsp56k.c +++ b/drivers/char/dsp56k.c @@ -513,7 +513,7 @@ static int __init dsp56k_init_driver(void) err = PTR_ERR(dsp56k_class); goto out_chrdev; } - class_device_create(dsp56k_class, NULL, MKDEV(DSP56K_MAJOR, 0), NULL, "dsp56k"); + device_create(dsp56k_class, NULL, MKDEV(DSP56K_MAJOR, 0), "dsp56k"); printk(banner); goto out; @@ -527,7 +527,7 @@ module_init(dsp56k_init_driver); static void __exit dsp56k_cleanup_driver(void) { - class_device_destroy(dsp56k_class, MKDEV(DSP56K_MAJOR, 0)); + device_destroy(dsp56k_class, MKDEV(DSP56K_MAJOR, 0)); class_destroy(dsp56k_class); unregister_chrdev(DSP56K_MAJOR, "dsp56k"); } diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c index 8d74b8745e6..bd94d5f9e62 100644 --- a/drivers/char/ip2/ip2main.c +++ b/drivers/char/ip2/ip2main.c @@ -411,8 +411,8 @@ cleanup_module(void) iiResetDelay( i2BoardPtrTable[i] ); /* free io addresses and Tibet */ release_region( ip2config.addr[i], 8 ); - class_device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i)); - class_device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i + 1)); + device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i)); + device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i + 1)); } /* Disable and remove interrupt handler. */ if ( (ip2config.irq[i] > 0) && have_requested_irq(ip2config.irq[i]) ) { @@ -718,12 +718,12 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize) } if ( NULL != ( pB = i2BoardPtrTable[i] ) ) { - class_device_create(ip2_class, NULL, + device_create(ip2_class, NULL, MKDEV(IP2_IPL_MAJOR, 4 * i), - NULL, "ipl%d", i); - class_device_create(ip2_class, NULL, + "ipl%d", i); + device_create(ip2_class, NULL, MKDEV(IP2_IPL_MAJOR, 4 * i + 1), - NULL, "stat%d", i); + "stat%d", i); for ( box = 0; box < ABS_MAX_BOXES; ++box ) { diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c index c2aa44ee6eb..0246a2b8ce4 100644 --- a/drivers/char/ipmi/ipmi_devintf.c +++ b/drivers/char/ipmi/ipmi_devintf.c @@ -865,7 +865,7 @@ static void ipmi_new_smi(int if_num, struct device *device) entry->dev = dev; mutex_lock(®_list_mutex); - class_device_create(ipmi_class, NULL, dev, device, "ipmi%d", if_num); + device_create(ipmi_class, device, dev, "ipmi%d", if_num); list_add(&entry->link, ®_list); mutex_unlock(®_list_mutex); } @@ -883,7 +883,7 @@ static void ipmi_smi_gone(int if_num) break; } } - class_device_destroy(ipmi_class, dev); + device_destroy(ipmi_class, dev); mutex_unlock(®_list_mutex); } @@ -938,7 +938,7 @@ static __exit void cleanup_ipmi(void) mutex_lock(®_list_mutex); list_for_each_entry_safe(entry, entry2, ®_list, link) { list_del(&entry->link); - class_device_destroy(ipmi_class, entry->dev); + device_destroy(ipmi_class, entry->dev); kfree(entry); } mutex_unlock(®_list_mutex); diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c index 3c66f402f9d..1f27be1ec3d 100644 --- a/drivers/char/istallion.c +++ b/drivers/char/istallion.c @@ -4624,9 +4624,8 @@ static int __init istallion_module_init(void) istallion_class = class_create(THIS_MODULE, "staliomem"); for (i = 0; i < 4; i++) - class_device_create(istallion_class, NULL, - MKDEV(STL_SIOMEMMAJOR, i), - NULL, "staliomem%d", i); + device_create(istallion_class, NULL, MKDEV(STL_SIOMEMMAJOR, i), + "staliomem%d", i); return 0; err_deinit: @@ -4659,8 +4658,7 @@ static void __exit istallion_module_exit(void) unregister_chrdev(STL_SIOMEMMAJOR, "staliomem"); for (j = 0; j < 4; j++) - class_device_destroy(istallion_class, MKDEV(STL_SIOMEMMAJOR, - j)); + device_destroy(istallion_class, MKDEV(STL_SIOMEMMAJOR, j)); class_destroy(istallion_class); pci_unregister_driver(&stli_pcidriver); diff --git a/drivers/char/lp.c b/drivers/char/lp.c index 62051f8b091..c59e2a0996c 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -799,8 +799,7 @@ static int lp_register(int nr, struct parport *port) if (reset) lp_reset(nr); - class_device_create(lp_class, NULL, MKDEV(LP_MAJOR, nr), port->dev, - "lp%d", nr); + device_create(lp_class, port->dev, MKDEV(LP_MAJOR, nr), "lp%d", nr); printk(KERN_INFO "lp%d: using %s (%s).\n", nr, port->name, (port->irq == PARPORT_IRQ_NONE)?"polling":"interrupt-driven"); @@ -971,7 +970,7 @@ static void lp_cleanup_module (void) if (lp_table[offset].dev == NULL) continue; parport_unregister_device(lp_table[offset].dev); - class_device_destroy(lp_class, MKDEV(LP_MAJOR, offset)); + device_destroy(lp_class, MKDEV(LP_MAJOR, offset)); } class_destroy(lp_class); } diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c index 4177f6db83e..cc5d77797de 100644 --- a/drivers/char/pcmcia/cm4000_cs.c +++ b/drivers/char/pcmcia/cm4000_cs.c @@ -1863,8 +1863,7 @@ static int cm4000_probe(struct pcmcia_device *link) return ret; } - class_device_create(cmm_class, NULL, MKDEV(major, i), NULL, - "cmm%d", i); + device_create(cmm_class, NULL, MKDEV(major, i), "cmm%d", i); return 0; } @@ -1888,7 +1887,7 @@ static void cm4000_detach(struct pcmcia_device *link) dev_table[devno] = NULL; kfree(dev); - class_device_destroy(cmm_class, MKDEV(major, devno)); + device_destroy(cmm_class, MKDEV(major, devno)); return; } diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c index b24a3e7bbb9..a0b9c8728d5 100644 --- a/drivers/char/pcmcia/cm4040_cs.c +++ b/drivers/char/pcmcia/cm4040_cs.c @@ -642,8 +642,7 @@ static int reader_probe(struct pcmcia_device *link) return ret; } - class_device_create(cmx_class, NULL, MKDEV(major, i), NULL, - "cmx%d", i); + device_create(cmx_class, NULL, MKDEV(major, i), "cmx%d", i); return 0; } @@ -666,7 +665,7 @@ static void reader_detach(struct pcmcia_device *link) dev_table[devno] = NULL; kfree(dev); - class_device_destroy(cmx_class, MKDEV(major, devno)); + device_destroy(cmx_class, MKDEV(major, devno)); return; } diff --git a/drivers/char/snsc.c b/drivers/char/snsc.c index 52753e723ea..b9c1dba6bd0 100644 --- a/drivers/char/snsc.c +++ b/drivers/char/snsc.c @@ -441,8 +441,7 @@ scdrv_init(void) continue; } - class_device_create(snsc_class, NULL, dev, NULL, - "%s", devname); + device_create(snsc_class, NULL, dev, "%s", devname); ia64_sn_irtr_intr_enable(scd->scd_nasid, 0 /*ignored */ , diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c index 4a80b2f864e..45758d5b56e 100644 --- a/drivers/char/stallion.c +++ b/drivers/char/stallion.c @@ -4778,9 +4778,8 @@ static int __init stallion_module_init(void) if (IS_ERR(stallion_class)) printk("STALLION: failed to create class\n"); for (i = 0; i < 4; i++) - class_device_create(stallion_class, NULL, - MKDEV(STL_SIOMEMMAJOR, i), NULL, - "staliomem%d", i); + device_create(stallion_class, NULL, MKDEV(STL_SIOMEMMAJOR, i), + "staliomem%d", i); return 0; err_unrtty: @@ -4816,7 +4815,7 @@ static void __exit stallion_module_exit(void) } for (i = 0; i < 4; i++) - class_device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i)); + device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i)); unregister_chrdev(STL_SIOMEMMAJOR, "staliomem"); class_destroy(stallion_class); diff --git a/drivers/char/tipar.c b/drivers/char/tipar.c index 35b40b99653..cef55c40654 100644 --- a/drivers/char/tipar.c +++ b/drivers/char/tipar.c @@ -441,8 +441,8 @@ tipar_register(int nr, struct parport *port) goto out; } - class_device_create(tipar_class, NULL, MKDEV(TIPAR_MAJOR, - TIPAR_MINOR + nr), port->dev, "par%d", nr); + device_create(tipar_class, port->dev, MKDEV(TIPAR_MAJOR, + TIPAR_MINOR + nr), "par%d", nr); /* Display informations */ pr_info("tipar%d: using %s (%s)\n", nr, port->name, (port->irq == @@ -534,7 +534,7 @@ tipar_cleanup_module(void) if (table[i].dev == NULL) continue; parport_unregister_device(table[i].dev); - class_device_destroy(tipar_class, MKDEV(TIPAR_MAJOR, i)); + device_destroy(tipar_class, MKDEV(TIPAR_MAJOR, i)); } class_destroy(tipar_class); diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c index f1d60f0cef8..db7a731e236 100644 --- a/drivers/char/viotape.c +++ b/drivers/char/viotape.c @@ -871,10 +871,10 @@ static int viotape_probe(struct vio_dev *vdev, const struct vio_device_id *id) state[i].cur_part = 0; for (j = 0; j < MAX_PARTITIONS; ++j) state[i].part_stat_rwi[j] = VIOT_IDLE; - class_device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i), NULL, + device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i), "iseries!vt%d", i); - class_device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i | 0x80), - NULL, "iseries!nvt%d", i); + device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i | 0x80), + "iseries!nvt%d", i); printk(VIOTAPE_KERN_INFO "tape iseries/vt%d is iSeries " "resource %10.10s type %4.4s, model %3.3s\n", i, viotape_unitinfo[i].rsrcname, @@ -886,8 +886,8 @@ static int viotape_remove(struct vio_dev *vdev) { int i = vdev->unit_address; - class_device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i | 0x80)); - class_device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i)); + device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i | 0x80)); + device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i)); return 0; } -- cgit v1.2.3-70-g09d2 From 5c5daf657cb5f963a38413f2852279d7a3843144 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Sun, 12 Aug 2007 20:43:55 +0200 Subject: Driver core: exclude kobject_uevent.c for !CONFIG_HOTPLUG Move uevent specific logic from the core into kobject_uevent.c, which does no longer require to link the unused string array if hotplug is not compiled in. Signed-off-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 18 ++++------------ include/linux/kobject.h | 10 ++++++--- lib/Makefile | 3 ++- lib/kobject_uevent.c | 57 ++++++++++++++++++++++++++++++++++++++----------- 4 files changed, 57 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/base/core.c b/drivers/base/core.c index d487c032dc4..65de221e3bf 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -234,13 +234,11 @@ static ssize_t show_uevent(struct device *dev, struct device_attribute *attr, /* search the kset, the device belongs to */ top_kobj = &dev->kobj; - if (!top_kobj->kset && top_kobj->parent) { - do { - top_kobj = top_kobj->parent; - } while (!top_kobj->kset && top_kobj->parent); - } + while (!top_kobj->kset && top_kobj->parent) + top_kobj = top_kobj->parent; if (!top_kobj->kset) goto out; + kset = top_kobj->kset; if (!kset->uevent_ops || !kset->uevent_ops->uevent) goto out; @@ -270,17 +268,9 @@ out: static ssize_t store_uevent(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - size_t len = count; enum kobject_action action; - if (len && buf[len-1] == '\n') - len--; - - for (action = 0; action < KOBJ_MAX; action++) { - if (strncmp(kobject_actions[action], buf, len) != 0) - continue; - if (kobject_actions[action][len] != '\0') - continue; + if (kobject_action_type(buf, count, &action) == 0) { kobject_uevent(&dev->kobj, action); goto out; } diff --git a/include/linux/kobject.h b/include/linux/kobject.h index 56f5eaf10ea..0777b3f57ae 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -58,9 +58,6 @@ enum kobject_action { KOBJ_MAX }; -/* The list of strings defining the valid kobject actions as specified above */ -extern const char *kobject_actions[]; - struct kobject { const char * k_name; struct kref kref; @@ -241,6 +238,9 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...) __attribute__((format (printf, 2, 3))); + +int kobject_action_type(const char *buf, size_t count, + enum kobject_action *type); #else static inline int kobject_uevent(struct kobject *kobj, enum kobject_action action) { return 0; } @@ -251,6 +251,10 @@ static inline int kobject_uevent_env(struct kobject *kobj, static inline int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...) { return 0; } + +static inline int kobject_action_type(const char *buf, size_t count, + enum kobject_action *type) +{ return -EINVAL; } #endif #endif /* __KERNEL__ */ diff --git a/lib/Makefile b/lib/Makefile index 4f3f3e25650..6c4ea33bb2c 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -10,7 +10,7 @@ lib-y := ctype.o string.o vsprintf.o cmdline.o \ lib-$(CONFIG_MMU) += ioremap.o lib-$(CONFIG_SMP) += cpumask.o -lib-y += kobject.o kref.o kobject_uevent.o klist.o +lib-y += kobject.o kref.o klist.o obj-y += div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \ bust_spinlocks.o hexdump.o kasprintf.o @@ -20,6 +20,7 @@ CFLAGS_kobject.o += -DDEBUG CFLAGS_kobject_uevent.o += -DDEBUG endif +lib-$(CONFIG_HOTPLUG) += kobject_uevent.o obj-$(CONFIG_GENERIC_IOMAP) += iomap.o obj-$(CONFIG_HAS_IOMEM) += iomap_copy.o devres.o obj-$(CONFIG_CHECK_SIGNATURE) += check_signature.o diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index 5ccda460262..a8efb48dca5 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c @@ -23,17 +23,6 @@ #include -/* the strings here must match the enum in include/linux/kobject.h */ -const char *kobject_actions[] = { - "add", - "remove", - "change", - "move", - "online", - "offline", -}; - -#if defined(CONFIG_HOTPLUG) u64 uevent_seqnum; char uevent_helper[UEVENT_HELPER_PATH_LEN] = CONFIG_UEVENT_HELPER_PATH; static DEFINE_SPINLOCK(sequence_lock); @@ -41,6 +30,50 @@ static DEFINE_SPINLOCK(sequence_lock); static struct sock *uevent_sock; #endif +/* the strings here must match the enum in include/linux/kobject.h */ +static const char *kobject_actions[] = { + [KOBJ_ADD] = "add", + [KOBJ_REMOVE] = "remove", + [KOBJ_CHANGE] = "change", + [KOBJ_MOVE] = "move", + [KOBJ_ONLINE] = "online", + [KOBJ_OFFLINE] = "offline", +}; + +/** + * kobject_action_type - translate action string to numeric type + * + * @buf: buffer containing the action string, newline is ignored + * @len: length of buffer + * @type: pointer to the location to store the action type + * + * Returns 0 if the action string was recognized. + */ +int kobject_action_type(const char *buf, size_t count, + enum kobject_action *type) +{ + enum kobject_action action; + int ret = -EINVAL; + + if (count && buf[count-1] == '\n') + count--; + + if (!count) + goto out; + + for (action = 0; action < ARRAY_SIZE(kobject_actions); action++) { + if (strncmp(kobject_actions[action], buf, count) != 0) + continue; + if (kobject_actions[action][count] != '\0') + continue; + *type = action; + ret = 0; + break; + } +out: + return ret; +} + /** * kobject_uevent_env - send an uevent with environmental data * @@ -270,5 +303,3 @@ static int __init kobject_uevent_init(void) postcore_initcall(kobject_uevent_init); #endif - -#endif /* CONFIG_HOTPLUG */ -- cgit v1.2.3-70-g09d2 From 7ac1cf4a87f446c130f7d8a4fe7e519f532a11de Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Sun, 12 Aug 2007 20:43:55 +0200 Subject: Driver core: add uevent file for bus and driver This has been in the SuSE kernels for some time now. Signed-off-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/base/bus.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'drivers') diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 0a8d075f3e6..6768a01e210 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -610,6 +610,17 @@ static inline int add_probe_files(struct bus_type *bus) { return 0; } static inline void remove_probe_files(struct bus_type *bus) {} #endif +static ssize_t driver_uevent_store(struct device_driver *drv, + const char *buf, size_t count) +{ + enum kobject_action action; + + if (kobject_action_type(buf, count, &action) == 0) + kobject_uevent(&drv->kobj, action); + return count; +} +static DRIVER_ATTR(uevent, S_IWUSR, NULL, driver_uevent_store); + /** * bus_add_driver - Add a driver to the bus. * @drv: driver. @@ -640,6 +651,11 @@ int bus_add_driver(struct device_driver *drv) klist_add_tail(&drv->knode_bus, &bus->klist_drivers); module_add_driver(drv->owner, drv); + error = driver_create_file(drv, &driver_attr_uevent); + if (error) { + printk(KERN_ERR "%s: uevent attr (%s) failed\n", + __FUNCTION__, drv->name); + } error = driver_add_attrs(bus, drv); if (error) { /* How the hell do we get out of this pickle? Give up */ @@ -677,6 +693,7 @@ void bus_remove_driver(struct device_driver * drv) remove_bind_files(drv); driver_remove_attrs(drv->bus, drv); + driver_remove_file(drv, &driver_attr_uevent); klist_remove(&drv->knode_bus); pr_debug("bus %s: remove driver %s\n", drv->bus->name, drv->name); driver_detach(drv); @@ -804,6 +821,17 @@ static void klist_devices_put(struct klist_node *n) put_device(dev); } +static ssize_t bus_uevent_store(struct bus_type *bus, + const char *buf, size_t count) +{ + enum kobject_action action; + + if (kobject_action_type(buf, count, &action) == 0) + kobject_uevent(&bus->subsys.kobj, action); + return count; +} +static BUS_ATTR(uevent, S_IWUSR, NULL, bus_uevent_store); + /** * bus_register - register a bus with the system. * @bus: bus. @@ -828,6 +856,10 @@ int bus_register(struct bus_type * bus) if (retval) goto out; + retval = bus_create_file(bus, &bus_attr_uevent); + if (retval) + goto bus_uevent_fail; + kobject_set_name(&bus->devices.kobj, "devices"); bus->devices.kobj.parent = &bus->subsys.kobj; retval = kset_register(&bus->devices); @@ -863,6 +895,8 @@ bus_probe_files_fail: bus_drivers_fail: kset_unregister(&bus->devices); bus_devices_fail: + bus_remove_file(bus, &bus_attr_uevent); +bus_uevent_fail: subsystem_unregister(&bus->subsys); out: return retval; @@ -882,6 +916,7 @@ void bus_unregister(struct bus_type * bus) remove_probe_files(bus); kset_unregister(&bus->drivers); kset_unregister(&bus->devices); + bus_remove_file(bus, &bus_attr_uevent); subsystem_unregister(&bus->subsys); } -- cgit v1.2.3-70-g09d2 From 109f0e93b6b728f03c1eb4af02bc25d71b646c59 Mon Sep 17 00:00:00 2001 From: Markus Rechberger Date: Mon, 13 Aug 2007 19:20:43 +0200 Subject: Fix Firmware class name collision following patch fixes the i2c name collision with i2c-dev. http://mcentral.de/wiki/index.php/Bugtracker#i2c_core_problem This issue has been experienced with em28xx and saa7133 based devices. I discussed that problem with Jean Delvare a while ago and he proposed to add a prefix to the class name. Signed-off-by: Markus Rechberger Acked-by: Marcel Holtmann Signed-off-by: Greg Kroah-Hartman --- drivers/base/firmware_class.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 4a1b9bfc547..0295855a3ee 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -292,8 +292,7 @@ firmware_class_timeout(u_long data) static inline void fw_setup_device_id(struct device *f_dev, struct device *dev) { - /* XXX warning we should watch out for name collisions */ - strlcpy(f_dev->bus_id, dev->bus_id, BUS_ID_SIZE); + snprintf(f_dev->bus_id, BUS_ID_SIZE, "firmware-%s", dev->bus_id); } static int fw_register_device(struct device **dev_p, const char *fw_name, -- cgit v1.2.3-70-g09d2 From b4d1eb2ccecb76bce4c2125c5a3e77753fcfaeb0 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Fri, 10 Aug 2007 13:51:09 -0700 Subject: drivers/base/power/: make 2 functions static suspend_device() and resume_device() can now become static. Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/base/power/power.h | 6 ------ drivers/base/power/resume.c | 2 +- drivers/base/power/suspend.c | 2 +- 3 files changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h index 8ba0830cbc0..49e64dbcce9 100644 --- a/drivers/base/power/power.h +++ b/drivers/base/power/power.h @@ -55,12 +55,6 @@ extern void dpm_sysfs_remove(struct device *); extern void dpm_resume(void); extern void dpm_power_up(void); -extern int resume_device(struct device *); - -/* - * suspend.c - */ -extern int suspend_device(struct device *, pm_message_t); #else /* CONFIG_PM_SLEEP */ diff --git a/drivers/base/power/resume.c b/drivers/base/power/resume.c index 00fd84ae6e6..67948bac993 100644 --- a/drivers/base/power/resume.c +++ b/drivers/base/power/resume.c @@ -20,7 +20,7 @@ * */ -int resume_device(struct device * dev) +static int resume_device(struct device * dev) { int error = 0; diff --git a/drivers/base/power/suspend.c b/drivers/base/power/suspend.c index 26df9b23173..204517afb15 100644 --- a/drivers/base/power/suspend.c +++ b/drivers/base/power/suspend.c @@ -54,7 +54,7 @@ suspend_device_dbg(struct device *dev, pm_message_t state, char *info) * @state: Power state device is entering. */ -int suspend_device(struct device * dev, pm_message_t state) +static int suspend_device(struct device * dev, pm_message_t state) { int error = 0; -- cgit v1.2.3-70-g09d2 From 44b760a825fae65629fb04b1deeab68c6bef5c50 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Sun, 19 Aug 2007 16:51:14 +0900 Subject: sysdev: remove global sysdev drivers list No one uses sysdev_drivers. Because no one calls sysdev_driver_register with NULL class. And it is difficult to imagine that someone want to implement a global sysdev driver which is called with all sys_device on any kind of sysdev_class. So this patch removes global sysdev_drivers list and update comments for this change. Signed-off-by: Akinobu Mita Cc: Tejun Heo Acked-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- drivers/base/sys.c | 71 +++++++++++------------------------------------------- 1 file changed, 14 insertions(+), 57 deletions(-) (limited to 'drivers') diff --git a/drivers/base/sys.c b/drivers/base/sys.c index 7ad89316782..ac7ff6d0c6e 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c @@ -153,25 +153,22 @@ void sysdev_class_unregister(struct sysdev_class * cls) EXPORT_SYMBOL_GPL(sysdev_class_register); EXPORT_SYMBOL_GPL(sysdev_class_unregister); - -static LIST_HEAD(sysdev_drivers); static DEFINE_MUTEX(sysdev_drivers_lock); /** * sysdev_driver_register - Register auxillary driver - * @cls: Device class driver belongs to. + * @cls: Device class driver belongs to. * @drv: Driver. * - * If @cls is valid, then @drv is inserted into @cls->drivers to be + * @drv is inserted into @cls->drivers to be * called on each operation on devices of that class. The refcount * of @cls is incremented. - * Otherwise, @drv is inserted into sysdev_drivers, and called for - * each device. */ -int sysdev_driver_register(struct sysdev_class * cls, - struct sysdev_driver * drv) +int sysdev_driver_register(struct sysdev_class *cls, struct sysdev_driver *drv) { + int err = 0; + mutex_lock(&sysdev_drivers_lock); if (cls && kset_get(&cls->kset)) { list_add_tail(&drv->entry, &cls->drivers); @@ -182,10 +179,13 @@ int sysdev_driver_register(struct sysdev_class * cls, list_for_each_entry(dev, &cls->kset.list, kobj.entry) drv->add(dev); } - } else - list_add_tail(&drv->entry, &sysdev_drivers); + } else { + err = -EINVAL; + printk(KERN_ERR "%s: invalid device class\n", __FUNCTION__); + WARN_ON(1); + } mutex_unlock(&sysdev_drivers_lock); - return 0; + return err; } @@ -251,12 +251,6 @@ int sysdev_register(struct sys_device * sysdev) * code that should have called us. */ - /* Notify global drivers */ - list_for_each_entry(drv, &sysdev_drivers, entry) { - if (drv->add) - drv->add(sysdev); - } - /* Notify class auxillary drivers */ list_for_each_entry(drv, &cls->drivers, entry) { if (drv->add) @@ -272,11 +266,6 @@ void sysdev_unregister(struct sys_device * sysdev) struct sysdev_driver * drv; mutex_lock(&sysdev_drivers_lock); - list_for_each_entry(drv, &sysdev_drivers, entry) { - if (drv->remove) - drv->remove(sysdev); - } - list_for_each_entry(drv, &sysdev->cls->drivers, entry) { if (drv->remove) drv->remove(sysdev); @@ -293,7 +282,7 @@ void sysdev_unregister(struct sys_device * sysdev) * * Loop over each class of system devices, and the devices in each * of those classes. For each device, we call the shutdown method for - * each driver registered for the device - the globals, the auxillaries, + * each driver registered for the device - the auxillaries, * and the class driver. * * Note: The list is iterated in reverse order, so that we shut down @@ -320,13 +309,7 @@ void sysdev_shutdown(void) struct sysdev_driver * drv; pr_debug(" %s\n", kobject_name(&sysdev->kobj)); - /* Call global drivers first. */ - list_for_each_entry(drv, &sysdev_drivers, entry) { - if (drv->shutdown) - drv->shutdown(sysdev); - } - - /* Call auxillary drivers next. */ + /* Call auxillary drivers first */ list_for_each_entry(drv, &cls->drivers, entry) { if (drv->shutdown) drv->shutdown(sysdev); @@ -354,12 +337,6 @@ static void __sysdev_resume(struct sys_device *dev) if (drv->resume) drv->resume(dev); } - - /* Call global drivers. */ - list_for_each_entry(drv, &sysdev_drivers, entry) { - if (drv->resume) - drv->resume(dev); - } } /** @@ -393,16 +370,7 @@ int sysdev_suspend(pm_message_t state) list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) { pr_debug(" %s\n", kobject_name(&sysdev->kobj)); - /* Call global drivers first. */ - list_for_each_entry(drv, &sysdev_drivers, entry) { - if (drv->suspend) { - ret = drv->suspend(sysdev, state); - if (ret) - goto gbl_driver; - } - } - - /* Call auxillary drivers next. */ + /* Call auxillary drivers first */ list_for_each_entry(drv, &cls->drivers, entry) { if (drv->suspend) { ret = drv->suspend(sysdev, state); @@ -436,18 +404,7 @@ aux_driver: if (err_drv->resume) err_drv->resume(sysdev); } - drv = NULL; -gbl_driver: - if (drv) - printk(KERN_ERR "sysdev driver suspend failed for %s\n", - kobject_name(&sysdev->kobj)); - list_for_each_entry(err_drv, &sysdev_drivers, entry) { - if (err_drv == drv) - break; - if (err_drv->resume) - err_drv->resume(sysdev); - } /* resume other sysdevs in current class */ list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) { if (err_dev == sysdev) -- cgit v1.2.3-70-g09d2 From 1359555eb77d240b7c1d7ee75bb07e89e89770e4 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 9 Sep 2007 12:54:16 +0200 Subject: Driver core: Make platform_device.id an int While platform_device.id is a u32, platform_device_add() handles "-1" as a special id value. This has potential for confusion and bugs. Making it an int instead should prevent problems from happening in the future. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/base/platform.c | 7 ++++--- include/linux/platform_device.h | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/base/platform.c b/drivers/base/platform.c index a2e3910196e..fb560924148 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -161,7 +161,7 @@ static void platform_device_release(struct device *dev) * Create a platform device object which can have other objects attached * to it, and which will have attached objects freed when it is released. */ -struct platform_device *platform_device_alloc(const char *name, unsigned int id) +struct platform_device *platform_device_alloc(const char *name, int id) { struct platform_object *pa; @@ -245,7 +245,8 @@ int platform_device_add(struct platform_device *pdev) pdev->dev.bus = &platform_bus_type; if (pdev->id != -1) - snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%u", pdev->name, pdev->id); + snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%d", pdev->name, + pdev->id); else strlcpy(pdev->dev.bus_id, pdev->name, BUS_ID_SIZE); @@ -359,7 +360,7 @@ EXPORT_SYMBOL_GPL(platform_device_unregister); * the Linux driver model. In particular, when such drivers are built * as modules, they can't be "hotplugged". */ -struct platform_device *platform_device_register_simple(char *name, unsigned int id, +struct platform_device *platform_device_register_simple(char *name, int id, struct resource *res, unsigned int num) { struct platform_device *pdev; diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h index 8bbd459eafd..e80804316cd 100644 --- a/include/linux/platform_device.h +++ b/include/linux/platform_device.h @@ -15,7 +15,7 @@ struct platform_device { const char * name; - u32 id; + int id; struct device dev; u32 num_resources; struct resource * resource; @@ -35,9 +35,10 @@ extern struct resource *platform_get_resource_byname(struct platform_device *, u extern int platform_get_irq_byname(struct platform_device *, char *); extern int platform_add_devices(struct platform_device **, int); -extern struct platform_device *platform_device_register_simple(char *, unsigned int, struct resource *, unsigned int); +extern struct platform_device *platform_device_register_simple(char *, int id, + struct resource *, unsigned int); -extern struct platform_device *platform_device_alloc(const char *name, unsigned int id); +extern struct platform_device *platform_device_alloc(const char *name, int id); extern int platform_device_add_resources(struct platform_device *pdev, struct resource *res, unsigned int num); extern int platform_device_add_data(struct platform_device *pdev, const void *data, size_t size); extern int platform_device_add(struct platform_device *pdev); -- cgit v1.2.3-70-g09d2 From dc8c85871c9728c5fddca6854a191fd41eb9438c Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Wed, 15 Aug 2007 12:25:38 +0200 Subject: PTY: add kernel parameter to overwrite legacy pty count Signed-off-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- Documentation/kernel-parameters.txt | 4 ++++ drivers/char/pty.c | 9 +++++++-- include/linux/tty.h | 1 - 3 files changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index a57c1f216b2..bdddd3cd46d 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1430,6 +1430,10 @@ and is between 256 and 4096 characters. It is defined in the file pt. [PARIDE] See Documentation/paride.txt. + pty.legacy_count= + [KNL] Number of legacy pty's. Overwrites compiled-in + default number. + quiet [KNL] Disable most log messages r128= [HW,DRM] diff --git a/drivers/char/pty.c b/drivers/char/pty.c index de14aea34e1..73de77105fe 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c @@ -248,14 +248,19 @@ static int pty_bsd_ioctl(struct tty_struct *tty, struct file *file, return -ENOIOCTLCMD; } +static int legacy_count = CONFIG_LEGACY_PTY_COUNT; +module_param(legacy_count, int, 0); + static void __init legacy_pty_init(void) { + if (legacy_count <= 0) + return; - pty_driver = alloc_tty_driver(NR_PTYS); + pty_driver = alloc_tty_driver(legacy_count); if (!pty_driver) panic("Couldn't allocate pty driver"); - pty_slave_driver = alloc_tty_driver(NR_PTYS); + pty_slave_driver = alloc_tty_driver(legacy_count); if (!pty_slave_driver) panic("Couldn't allocate pty slave driver"); diff --git a/include/linux/tty.h b/include/linux/tty.h index 6570719eafd..60478f6e5dc 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -21,7 +21,6 @@ * (Note: the *_driver.minor_start values 1, 64, 128, 192 are * hardcoded at present.) */ -#define NR_PTYS CONFIG_LEGACY_PTY_COUNT /* Number of legacy ptys */ #define NR_UNIX98_PTY_DEFAULT 4096 /* Default maximum for Unix98 ptys */ #define NR_UNIX98_PTY_MAX (1 << MINORBITS) /* Absolute limit */ #define NR_LDISCS 17 -- cgit v1.2.3-70-g09d2 From 5a7ad7f044941316dc98eda2a087a12a7a50649d Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 20 Sep 2007 16:05:10 +0900 Subject: sysfs: kill sysfs_update_file() sysfs_update_file() depends on inode->i_mtime but sysfs iondes are now reclaimable making the reported modification time unreliable. There's only one user (pci hotplug) of this notification mechanism and it reportedly isn't utilized from userland. Kill sysfs_update_file(). Signed-off-by: Tejun Heo Acked-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/pci_hotplug_core.c | 60 ---------------------------------- fs/sysfs/file.c | 40 ----------------------- include/linux/sysfs.h | 7 ---- 3 files changed, 107 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c index bd433ef6bfc..f0eba534f80 100644 --- a/drivers/pci/hotplug/pci_hotplug_core.c +++ b/drivers/pci/hotplug/pci_hotplug_core.c @@ -694,66 +694,6 @@ int __must_check pci_hp_change_slot_info(struct hotplug_slot *slot, if ((slot == NULL) || (info == NULL)) return -ENODEV; - /* - * check all fields in the info structure, and update timestamps - * for the files referring to the fields that have now changed. - */ - if ((has_power_file(slot) == 0) && - (slot->info->power_status != info->power_status)) { - retval = sysfs_update_file(&slot->kobj, - &hotplug_slot_attr_power.attr); - if (retval) - return retval; - } - - if ((has_attention_file(slot) == 0) && - (slot->info->attention_status != info->attention_status)) { - retval = sysfs_update_file(&slot->kobj, - &hotplug_slot_attr_attention.attr); - if (retval) - return retval; - } - - if ((has_latch_file(slot) == 0) && - (slot->info->latch_status != info->latch_status)) { - retval = sysfs_update_file(&slot->kobj, - &hotplug_slot_attr_latch.attr); - if (retval) - return retval; - } - - if ((has_adapter_file(slot) == 0) && - (slot->info->adapter_status != info->adapter_status)) { - retval = sysfs_update_file(&slot->kobj, - &hotplug_slot_attr_presence.attr); - if (retval) - return retval; - } - - if ((has_address_file(slot) == 0) && - (slot->info->address != info->address)) { - retval = sysfs_update_file(&slot->kobj, - &hotplug_slot_attr_address.attr); - if (retval) - return retval; - } - - if ((has_max_bus_speed_file(slot) == 0) && - (slot->info->max_bus_speed != info->max_bus_speed)) { - retval = sysfs_update_file(&slot->kobj, - &hotplug_slot_attr_max_bus_speed.attr); - if (retval) - return retval; - } - - if ((has_cur_bus_speed_file(slot) == 0) && - (slot->info->cur_bus_speed != info->cur_bus_speed)) { - retval = sysfs_update_file(&slot->kobj, - &hotplug_slot_attr_cur_bus_speed.attr); - if (retval) - return retval; - } - memcpy (slot->info, info, sizeof (struct hotplug_slot_info)); return 0; diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 9fdf8dae0dc..61a8c19df7c 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -3,7 +3,6 @@ */ #include -#include #include #include #include @@ -453,44 +452,6 @@ int sysfs_add_file_to_group(struct kobject *kobj, } EXPORT_SYMBOL_GPL(sysfs_add_file_to_group); - -/** - * sysfs_update_file - update the modified timestamp on an object attribute. - * @kobj: object we're acting for. - * @attr: attribute descriptor. - */ -int sysfs_update_file(struct kobject * kobj, const struct attribute * attr) -{ - struct sysfs_dirent *victim_sd = NULL; - struct dentry *victim = NULL; - int rc; - - rc = -ENOENT; - victim_sd = sysfs_get_dirent(kobj->sd, attr->name); - if (!victim_sd) - goto out; - - mutex_lock(&sysfs_rename_mutex); - victim = sysfs_get_dentry(victim_sd); - mutex_unlock(&sysfs_rename_mutex); - if (IS_ERR(victim)) { - rc = PTR_ERR(victim); - victim = NULL; - goto out; - } - - mutex_lock(&victim->d_inode->i_mutex); - victim->d_inode->i_mtime = CURRENT_TIME; - fsnotify_modify(victim); - mutex_unlock(&victim->d_inode->i_mutex); - rc = 0; - out: - dput(victim); - sysfs_put(victim_sd); - return rc; -} - - /** * sysfs_chmod_file - update the modified mode value on an object attribute. * @kobj: object we're acting for. @@ -641,4 +602,3 @@ EXPORT_SYMBOL_GPL(sysfs_schedule_callback); EXPORT_SYMBOL_GPL(sysfs_create_file); EXPORT_SYMBOL_GPL(sysfs_remove_file); -EXPORT_SYMBOL_GPL(sysfs_update_file); diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index b393bb44962..db5dd2403d0 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -87,8 +87,6 @@ int __must_check sysfs_move_dir(struct kobject *kobj, int __must_check sysfs_create_file(struct kobject *kobj, const struct attribute *attr); -int __must_check sysfs_update_file(struct kobject *kobj, - const struct attribute *attr); int __must_check sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode); void sysfs_remove_file(struct kobject *kobj, const struct attribute *attr); @@ -149,11 +147,6 @@ static inline int sysfs_create_file(struct kobject *kobj, return 0; } -static inline int sysfs_update_file(struct kobject *kobj, - const struct attribute *attr) -{ - return 0; -} static inline int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode) { -- cgit v1.2.3-70-g09d2 From e4bc16621d82ee1fd3685dcbf889a7c49891847b Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 26 Sep 2007 11:12:00 -0700 Subject: driver core: remove subsystem_init() There is only one user of it, and it is only a wrapper for kset_init(). Signed-off-by: Greg Kroah-Hartman --- Documentation/kobject.txt | 1 - drivers/base/class.c | 2 +- include/linux/kobject.h | 1 - lib/kobject.c | 5 ----- 4 files changed, 1 insertion(+), 8 deletions(-) (limited to 'drivers') diff --git a/Documentation/kobject.txt b/Documentation/kobject.txt index 5e7aca26135..ca86a885ad8 100644 --- a/Documentation/kobject.txt +++ b/Documentation/kobject.txt @@ -238,7 +238,6 @@ kobj_set_kset_s(obj,subsys) - Assumes that obj->kobj exists, and is a struct kobject. - Sets the kset of that kobject to the kset . -void subsystem_init(struct kset *s); int subsystem_register(struct kset *s); void subsystem_unregister(struct kset *s); diff --git a/drivers/base/class.c b/drivers/base/class.c index 3e9b04c30fb..5b9cf06eab8 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -861,7 +861,7 @@ int __init classes_init(void) /* ick, this is ugly, the things we go through to keep from showing up * in sysfs... */ - subsystem_init(&class_obj_subsys); + kset_init(&class_obj_subsys); if (!class_obj_subsys.kobj.parent) class_obj_subsys.kobj.parent = &class_obj_subsys.kobj; return 0; diff --git a/include/linux/kobject.h b/include/linux/kobject.h index a8a84fcccbc..05cc5b2ddff 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -217,7 +217,6 @@ extern struct kset hypervisor_subsys; #define kobj_set_kset_s(obj,subsys) \ (obj)->kobj.kset = &(subsys) -extern void subsystem_init(struct kset *); extern int __must_check subsystem_register(struct kset *); extern void subsystem_unregister(struct kset *); diff --git a/lib/kobject.c b/lib/kobject.c index fc6db6b4bfc..b7e0646f797 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -617,11 +617,6 @@ struct kobject * kset_find_obj(struct kset * kset, const char * name) return ret; } -void subsystem_init(struct kset *s) -{ - kset_init(s); -} - int subsystem_register(struct kset *s) { return kset_register(s); -- cgit v1.2.3-70-g09d2 From adc56808f32e15fa0c0fcd5ecb4b30989076ef2b Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 11 Oct 2007 10:47:49 -0600 Subject: Driver core: rename ktype_class This makes it a bit more sane when trying to figure out how to clean up the ktype mess. Based on a larger patch from Kay Sievers Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/base/class.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/base/class.c b/drivers/base/class.c index 5b9cf06eab8..a863bb091e1 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -65,13 +65,13 @@ static struct sysfs_ops class_sysfs_ops = { .store = class_attr_store, }; -static struct kobj_type ktype_class = { +static struct kobj_type class_ktype = { .sysfs_ops = &class_sysfs_ops, .release = class_release, }; /* Hotplug events for classes go to the class_obj subsys */ -static decl_subsys(class, &ktype_class, NULL); +static decl_subsys(class, &class_ktype, NULL); int class_create_file(struct class * cls, const struct class_attribute * attr) @@ -323,7 +323,7 @@ static void class_dev_release(struct kobject * kobj) } } -static struct kobj_type ktype_class_device = { +static struct kobj_type class_device_ktype = { .sysfs_ops = &class_dev_sysfs_ops, .release = class_dev_release, }; @@ -332,7 +332,7 @@ static int class_uevent_filter(struct kset *kset, struct kobject *kobj) { struct kobj_type *ktype = get_ktype(kobj); - if (ktype == &ktype_class_device) { + if (ktype == &class_device_ktype) { struct class_device *class_dev = to_class_dev(kobj); if (class_dev->class) return 1; @@ -452,7 +452,7 @@ static struct kset_uevent_ops class_uevent_ops = { .uevent = class_uevent, }; -static decl_subsys(class_obj, &ktype_class_device, &class_uevent_ops); +static decl_subsys(class_obj, &class_device_ktype, &class_uevent_ops); static int class_device_add_attrs(struct class_device * cd) -- cgit v1.2.3-70-g09d2 From 8f4afc410b8d2be49f34835b6bbe788f50471b02 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 11 Oct 2007 10:47:49 -0600 Subject: Driver core: rename ktype_device This makes it a bit more sane when trying to figure out how to clean up the ktype mess. Based on a larger patch from Kay Sievers Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/base/core.c b/drivers/base/core.c index 65de221e3bf..c1343414d28 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -108,7 +108,7 @@ static void device_release(struct kobject * kobj) } } -static struct kobj_type ktype_device = { +static struct kobj_type device_ktype = { .release = device_release, .sysfs_ops = &dev_sysfs_ops, }; @@ -118,7 +118,7 @@ static int dev_uevent_filter(struct kset *kset, struct kobject *kobj) { struct kobj_type *ktype = get_ktype(kobj); - if (ktype == &ktype_device) { + if (ktype == &device_ktype) { struct device *dev = to_dev(kobj); if (dev->uevent_suppress) return 0; @@ -405,7 +405,7 @@ static struct device_attribute devt_attr = * devices_subsys - structure to be registered with kobject core. */ -decl_subsys(devices, &ktype_device, &device_uevent_ops); +decl_subsys(devices, &device_ktype, &device_uevent_ops); /** -- cgit v1.2.3-70-g09d2 From a1148fb03f3c5d0bb5e6641234c2251a15741361 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 11 Oct 2007 10:47:49 -0600 Subject: Driver core: rename ktype_driver This makes it a bit more sane when trying to figure out how to clean up the ktype mess. Based on a larger patch from Kay Sievers Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/base/bus.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 6768a01e210..9a19b071c57 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -89,7 +89,7 @@ static void driver_release(struct kobject * kobj) */ } -static struct kobj_type ktype_driver = { +static struct kobj_type driver_ktype = { .sysfs_ops = &driver_sysfs_ops, .release = driver_release, }; @@ -868,7 +868,7 @@ int bus_register(struct bus_type * bus) kobject_set_name(&bus->drivers.kobj, "drivers"); bus->drivers.kobj.parent = &bus->subsys.kobj; - bus->drivers.ktype = &ktype_driver; + bus->drivers.ktype = &driver_ktype; retval = kset_register(&bus->drivers); if (retval) goto bus_drivers_fail; -- cgit v1.2.3-70-g09d2 From e89a4116ef345cf10c21f722dd1d8bfa9b7c7d58 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 11 Oct 2007 10:47:49 -0600 Subject: Driver core: rename ktype_edd and ktype_efivar This makes it a bit more sane when trying to figure out how to clean up the ktype mess. Based on a larger patch from Kay Sievers Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/edd.c | 4 ++-- drivers/firmware/efivars.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/firmware/edd.c b/drivers/firmware/edd.c index 0fb730ee1da..6942e065e60 100644 --- a/drivers/firmware/edd.c +++ b/drivers/firmware/edd.c @@ -625,13 +625,13 @@ static void edd_release(struct kobject * kobj) kfree(dev); } -static struct kobj_type ktype_edd = { +static struct kobj_type edd_ktype = { .release = edd_release, .sysfs_ops = &edd_attr_ops, .default_attrs = def_attrs, }; -static decl_subsys(edd,&ktype_edd,NULL); +static decl_subsys(edd, &edd_ktype, NULL); /** diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c index bfd2d67df68..858a7b95933 100644 --- a/drivers/firmware/efivars.c +++ b/drivers/firmware/efivars.c @@ -402,7 +402,7 @@ static struct attribute *def_attrs[] = { NULL, }; -static struct kobj_type ktype_efivar = { +static struct kobj_type efivar_ktype = { .release = efivar_release, .sysfs_ops = &efivar_attr_ops, .default_attrs = def_attrs, @@ -583,7 +583,7 @@ static struct subsys_attribute *efi_subsys_attrs[] = { NULL, /* maybe more in the future? */ }; -static decl_subsys(vars, &ktype_efivar, NULL); +static decl_subsys(vars, &efivar_ktype, NULL); static decl_subsys(efi, NULL, NULL); /* -- cgit v1.2.3-70-g09d2 From cd59abfcc441b2abb4cf2cd62c1eb0f02a60e8dd Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 21 Sep 2007 15:36:56 -0400 Subject: PM: merge device power-management source files This patch (as993) merges the suspend.c and resume.c files in drivers/base/power into main.c, making some public symbols private. Signed-off-by: Alan Stern Acked-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- drivers/base/power/Makefile | 2 +- drivers/base/power/main.c | 344 ++++++++++++++++++++++++++++++++++++++++++- drivers/base/power/power.h | 32 +--- drivers/base/power/resume.c | 149 ------------------- drivers/base/power/suspend.c | 210 -------------------------- 5 files changed, 343 insertions(+), 394 deletions(-) delete mode 100644 drivers/base/power/resume.c delete mode 100644 drivers/base/power/suspend.c (limited to 'drivers') diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile index 9caeaea753a..a803733c839 100644 --- a/drivers/base/power/Makefile +++ b/drivers/base/power/Makefile @@ -1,5 +1,5 @@ obj-y := shutdown.o -obj-$(CONFIG_PM_SLEEP) += main.o suspend.o resume.o sysfs.o +obj-$(CONFIG_PM_SLEEP) += main.o sysfs.o obj-$(CONFIG_PM_TRACE) += trace.o ifeq ($(CONFIG_DEBUG_DRIVER),y) diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index eb9f38d0aa5..0ab4ab21f56 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -20,19 +20,24 @@ */ #include +#include #include +#include +#include +#include "../base.h" #include "power.h" LIST_HEAD(dpm_active); -LIST_HEAD(dpm_off); -LIST_HEAD(dpm_off_irq); +static LIST_HEAD(dpm_off); +static LIST_HEAD(dpm_off_irq); -DEFINE_MUTEX(dpm_mtx); -DEFINE_MUTEX(dpm_list_mtx); +static DEFINE_MUTEX(dpm_mtx); +static DEFINE_MUTEX(dpm_list_mtx); int (*platform_enable_wakeup)(struct device *dev, int is_on); + int device_pm_add(struct device *dev) { int error; @@ -61,3 +66,334 @@ void device_pm_remove(struct device *dev) } +/*------------------------- Resume routines -------------------------*/ + +/** + * resume_device - Restore state for one device. + * @dev: Device. + * + */ + +static int resume_device(struct device * dev) +{ + int error = 0; + + TRACE_DEVICE(dev); + TRACE_RESUME(0); + + down(&dev->sem); + + if (dev->bus && dev->bus->resume) { + dev_dbg(dev,"resuming\n"); + error = dev->bus->resume(dev); + } + + if (!error && dev->type && dev->type->resume) { + dev_dbg(dev,"resuming\n"); + error = dev->type->resume(dev); + } + + if (!error && dev->class && dev->class->resume) { + dev_dbg(dev,"class resume\n"); + error = dev->class->resume(dev); + } + + up(&dev->sem); + + TRACE_RESUME(error); + return error; +} + + +static int resume_device_early(struct device * dev) +{ + int error = 0; + + TRACE_DEVICE(dev); + TRACE_RESUME(0); + if (dev->bus && dev->bus->resume_early) { + dev_dbg(dev,"EARLY resume\n"); + error = dev->bus->resume_early(dev); + } + TRACE_RESUME(error); + return error; +} + +/* + * Resume the devices that have either not gone through + * the late suspend, or that did go through it but also + * went through the early resume + */ +static void dpm_resume(void) +{ + mutex_lock(&dpm_list_mtx); + while(!list_empty(&dpm_off)) { + struct list_head * entry = dpm_off.next; + struct device * dev = to_device(entry); + + get_device(dev); + list_move_tail(entry, &dpm_active); + + mutex_unlock(&dpm_list_mtx); + resume_device(dev); + mutex_lock(&dpm_list_mtx); + put_device(dev); + } + mutex_unlock(&dpm_list_mtx); +} + + +/** + * device_resume - Restore state of each device in system. + * + * Walk the dpm_off list, remove each entry, resume the device, + * then add it to the dpm_active list. + */ + +void device_resume(void) +{ + might_sleep(); + mutex_lock(&dpm_mtx); + dpm_resume(); + mutex_unlock(&dpm_mtx); +} + +EXPORT_SYMBOL_GPL(device_resume); + + +/** + * dpm_power_up - Power on some devices. + * + * Walk the dpm_off_irq list and power each device up. This + * is used for devices that required they be powered down with + * interrupts disabled. As devices are powered on, they are moved + * to the dpm_active list. + * + * Interrupts must be disabled when calling this. + */ + +static void dpm_power_up(void) +{ + while(!list_empty(&dpm_off_irq)) { + struct list_head * entry = dpm_off_irq.next; + struct device * dev = to_device(entry); + + list_move_tail(entry, &dpm_off); + resume_device_early(dev); + } +} + + +/** + * device_power_up - Turn on all devices that need special attention. + * + * Power on system devices then devices that required we shut them down + * with interrupts disabled. + * Called with interrupts disabled. + */ + +void device_power_up(void) +{ + sysdev_resume(); + dpm_power_up(); +} + +EXPORT_SYMBOL_GPL(device_power_up); + + +/*------------------------- Suspend routines -------------------------*/ + +/* + * The entries in the dpm_active list are in a depth first order, simply + * because children are guaranteed to be discovered after parents, and + * are inserted at the back of the list on discovery. + * + * All list on the suspend path are done in reverse order, so we operate + * on the leaves of the device tree (or forests, depending on how you want + * to look at it ;) first. As nodes are removed from the back of the list, + * they are inserted into the front of their destintation lists. + * + * Things are the reverse on the resume path - iterations are done in + * forward order, and nodes are inserted at the back of their destination + * lists. This way, the ancestors will be accessed before their descendents. + */ + +static inline char *suspend_verb(u32 event) +{ + switch (event) { + case PM_EVENT_SUSPEND: return "suspend"; + case PM_EVENT_FREEZE: return "freeze"; + case PM_EVENT_PRETHAW: return "prethaw"; + default: return "(unknown suspend event)"; + } +} + + +static void +suspend_device_dbg(struct device *dev, pm_message_t state, char *info) +{ + dev_dbg(dev, "%s%s%s\n", info, suspend_verb(state.event), + ((state.event == PM_EVENT_SUSPEND) && device_may_wakeup(dev)) ? + ", may wakeup" : ""); +} + +/** + * suspend_device - Save state of one device. + * @dev: Device. + * @state: Power state device is entering. + */ + +static int suspend_device(struct device * dev, pm_message_t state) +{ + int error = 0; + + down(&dev->sem); + if (dev->power.power_state.event) { + dev_dbg(dev, "PM: suspend %d-->%d\n", + dev->power.power_state.event, state.event); + } + + if (dev->class && dev->class->suspend) { + suspend_device_dbg(dev, state, "class "); + error = dev->class->suspend(dev, state); + suspend_report_result(dev->class->suspend, error); + } + + if (!error && dev->type && dev->type->suspend) { + suspend_device_dbg(dev, state, "type "); + error = dev->type->suspend(dev, state); + suspend_report_result(dev->type->suspend, error); + } + + if (!error && dev->bus && dev->bus->suspend) { + suspend_device_dbg(dev, state, ""); + error = dev->bus->suspend(dev, state); + suspend_report_result(dev->bus->suspend, error); + } + up(&dev->sem); + return error; +} + + +/* + * This is called with interrupts off, only a single CPU + * running. We can't acquire a mutex or semaphore (and we don't + * need the protection) + */ +static int suspend_device_late(struct device *dev, pm_message_t state) +{ + int error = 0; + + if (dev->bus && dev->bus->suspend_late) { + suspend_device_dbg(dev, state, "LATE "); + error = dev->bus->suspend_late(dev, state); + suspend_report_result(dev->bus->suspend_late, error); + } + return error; +} + +/** + * device_suspend - Save state and stop all devices in system. + * @state: Power state to put each device in. + * + * Walk the dpm_active list, call ->suspend() for each device, and move + * it to the dpm_off list. + * + * (For historical reasons, if it returns -EAGAIN, that used to mean + * that the device would be called again with interrupts disabled. + * These days, we use the "suspend_late()" callback for that, so we + * print a warning and consider it an error). + * + * If we get a different error, try and back out. + * + * If we hit a failure with any of the devices, call device_resume() + * above to bring the suspended devices back to life. + * + */ + +int device_suspend(pm_message_t state) +{ + int error = 0; + + might_sleep(); + mutex_lock(&dpm_mtx); + mutex_lock(&dpm_list_mtx); + while (!list_empty(&dpm_active) && error == 0) { + struct list_head * entry = dpm_active.prev; + struct device * dev = to_device(entry); + + get_device(dev); + mutex_unlock(&dpm_list_mtx); + + error = suspend_device(dev, state); + + mutex_lock(&dpm_list_mtx); + + /* Check if the device got removed */ + if (!list_empty(&dev->power.entry)) { + /* Move it to the dpm_off list */ + if (!error) + list_move(&dev->power.entry, &dpm_off); + } + if (error) + printk(KERN_ERR "Could not suspend device %s: " + "error %d%s\n", + kobject_name(&dev->kobj), error, + error == -EAGAIN ? " (please convert to suspend_late)" : ""); + put_device(dev); + } + mutex_unlock(&dpm_list_mtx); + if (error) + dpm_resume(); + + mutex_unlock(&dpm_mtx); + return error; +} + +EXPORT_SYMBOL_GPL(device_suspend); + +/** + * device_power_down - Shut down special devices. + * @state: Power state to enter. + * + * Walk the dpm_off_irq list, calling ->power_down() for each device that + * couldn't power down the device with interrupts enabled. When we're + * done, power down system devices. + */ + +int device_power_down(pm_message_t state) +{ + int error = 0; + struct device * dev; + + while (!list_empty(&dpm_off)) { + struct list_head * entry = dpm_off.prev; + + dev = to_device(entry); + error = suspend_device_late(dev, state); + if (error) + goto Error; + list_move(&dev->power.entry, &dpm_off_irq); + } + + error = sysdev_suspend(state); + Done: + return error; + Error: + printk(KERN_ERR "Could not power down device %s: " + "error %d\n", kobject_name(&dev->kobj), error); + dpm_power_up(); + goto Done; +} + +EXPORT_SYMBOL_GPL(device_power_down); + +void __suspend_report_result(const char *function, void *fn, int ret) +{ + if (ret) { + printk(KERN_ERR "%s(): ", function); + print_fn_descriptor_symbol("%s() returns ", (unsigned long)fn); + printk("%d\n", ret); + } +} +EXPORT_SYMBOL_GPL(__suspend_report_result); diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h index 49e64dbcce9..5c4efd493fa 100644 --- a/drivers/base/power/power.h +++ b/drivers/base/power/power.h @@ -11,32 +11,11 @@ extern void device_shutdown(void); * main.c */ -/* - * Used to synchronize global power management operations. - */ -extern struct mutex dpm_mtx; - -/* - * Used to serialize changes to the dpm_* lists. - */ -extern struct mutex dpm_list_mtx; - -/* - * The PM lists. - */ -extern struct list_head dpm_active; -extern struct list_head dpm_off; -extern struct list_head dpm_off_irq; - - -static inline struct dev_pm_info * to_pm_info(struct list_head * entry) -{ - return container_of(entry, struct dev_pm_info, entry); -} +extern struct list_head dpm_active; /* The active device list */ static inline struct device * to_device(struct list_head * entry) { - return container_of(to_pm_info(entry), struct device, power); + return container_of(entry, struct device, power.entry); } extern int device_pm_add(struct device *); @@ -49,13 +28,6 @@ extern void device_pm_remove(struct device *); extern int dpm_sysfs_add(struct device *); extern void dpm_sysfs_remove(struct device *); -/* - * resume.c - */ - -extern void dpm_resume(void); -extern void dpm_power_up(void); - #else /* CONFIG_PM_SLEEP */ diff --git a/drivers/base/power/resume.c b/drivers/base/power/resume.c deleted file mode 100644 index 67948bac993..00000000000 --- a/drivers/base/power/resume.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * resume.c - Functions for waking devices up. - * - * Copyright (c) 2003 Patrick Mochel - * Copyright (c) 2003 Open Source Development Labs - * - * This file is released under the GPLv2 - * - */ - -#include -#include -#include "../base.h" -#include "power.h" - - -/** - * resume_device - Restore state for one device. - * @dev: Device. - * - */ - -static int resume_device(struct device * dev) -{ - int error = 0; - - TRACE_DEVICE(dev); - TRACE_RESUME(0); - - down(&dev->sem); - - if (dev->bus && dev->bus->resume) { - dev_dbg(dev,"resuming\n"); - error = dev->bus->resume(dev); - } - - if (!error && dev->type && dev->type->resume) { - dev_dbg(dev,"resuming\n"); - error = dev->type->resume(dev); - } - - if (!error && dev->class && dev->class->resume) { - dev_dbg(dev,"class resume\n"); - error = dev->class->resume(dev); - } - - up(&dev->sem); - - TRACE_RESUME(error); - return error; -} - - -static int resume_device_early(struct device * dev) -{ - int error = 0; - - TRACE_DEVICE(dev); - TRACE_RESUME(0); - if (dev->bus && dev->bus->resume_early) { - dev_dbg(dev,"EARLY resume\n"); - error = dev->bus->resume_early(dev); - } - TRACE_RESUME(error); - return error; -} - -/* - * Resume the devices that have either not gone through - * the late suspend, or that did go through it but also - * went through the early resume - */ -void dpm_resume(void) -{ - mutex_lock(&dpm_list_mtx); - while(!list_empty(&dpm_off)) { - struct list_head * entry = dpm_off.next; - struct device * dev = to_device(entry); - - get_device(dev); - list_move_tail(entry, &dpm_active); - - mutex_unlock(&dpm_list_mtx); - resume_device(dev); - mutex_lock(&dpm_list_mtx); - put_device(dev); - } - mutex_unlock(&dpm_list_mtx); -} - - -/** - * device_resume - Restore state of each device in system. - * - * Walk the dpm_off list, remove each entry, resume the device, - * then add it to the dpm_active list. - */ - -void device_resume(void) -{ - might_sleep(); - mutex_lock(&dpm_mtx); - dpm_resume(); - mutex_unlock(&dpm_mtx); -} - -EXPORT_SYMBOL_GPL(device_resume); - - -/** - * dpm_power_up - Power on some devices. - * - * Walk the dpm_off_irq list and power each device up. This - * is used for devices that required they be powered down with - * interrupts disabled. As devices are powered on, they are moved - * to the dpm_active list. - * - * Interrupts must be disabled when calling this. - */ - -void dpm_power_up(void) -{ - while(!list_empty(&dpm_off_irq)) { - struct list_head * entry = dpm_off_irq.next; - struct device * dev = to_device(entry); - - list_move_tail(entry, &dpm_off); - resume_device_early(dev); - } -} - - -/** - * device_power_up - Turn on all devices that need special attention. - * - * Power on system devices then devices that required we shut them down - * with interrupts disabled. - * Called with interrupts disabled. - */ - -void device_power_up(void) -{ - sysdev_resume(); - dpm_power_up(); -} - -EXPORT_SYMBOL_GPL(device_power_up); - - diff --git a/drivers/base/power/suspend.c b/drivers/base/power/suspend.c deleted file mode 100644 index 204517afb15..00000000000 --- a/drivers/base/power/suspend.c +++ /dev/null @@ -1,210 +0,0 @@ -/* - * suspend.c - Functions for putting devices to sleep. - * - * Copyright (c) 2003 Patrick Mochel - * Copyright (c) 2003 Open Source Development Labs - * - * This file is released under the GPLv2 - * - */ - -#include -#include -#include -#include "../base.h" -#include "power.h" - -/* - * The entries in the dpm_active list are in a depth first order, simply - * because children are guaranteed to be discovered after parents, and - * are inserted at the back of the list on discovery. - * - * All list on the suspend path are done in reverse order, so we operate - * on the leaves of the device tree (or forests, depending on how you want - * to look at it ;) first. As nodes are removed from the back of the list, - * they are inserted into the front of their destintation lists. - * - * Things are the reverse on the resume path - iterations are done in - * forward order, and nodes are inserted at the back of their destination - * lists. This way, the ancestors will be accessed before their descendents. - */ - -static inline char *suspend_verb(u32 event) -{ - switch (event) { - case PM_EVENT_SUSPEND: return "suspend"; - case PM_EVENT_FREEZE: return "freeze"; - case PM_EVENT_PRETHAW: return "prethaw"; - default: return "(unknown suspend event)"; - } -} - - -static void -suspend_device_dbg(struct device *dev, pm_message_t state, char *info) -{ - dev_dbg(dev, "%s%s%s\n", info, suspend_verb(state.event), - ((state.event == PM_EVENT_SUSPEND) && device_may_wakeup(dev)) ? - ", may wakeup" : ""); -} - -/** - * suspend_device - Save state of one device. - * @dev: Device. - * @state: Power state device is entering. - */ - -static int suspend_device(struct device * dev, pm_message_t state) -{ - int error = 0; - - down(&dev->sem); - if (dev->power.power_state.event) { - dev_dbg(dev, "PM: suspend %d-->%d\n", - dev->power.power_state.event, state.event); - } - - if (dev->class && dev->class->suspend) { - suspend_device_dbg(dev, state, "class "); - error = dev->class->suspend(dev, state); - suspend_report_result(dev->class->suspend, error); - } - - if (!error && dev->type && dev->type->suspend) { - suspend_device_dbg(dev, state, "type "); - error = dev->type->suspend(dev, state); - suspend_report_result(dev->type->suspend, error); - } - - if (!error && dev->bus && dev->bus->suspend) { - suspend_device_dbg(dev, state, ""); - error = dev->bus->suspend(dev, state); - suspend_report_result(dev->bus->suspend, error); - } - up(&dev->sem); - return error; -} - - -/* - * This is called with interrupts off, only a single CPU - * running. We can't acquire a mutex or semaphore (and we don't - * need the protection) - */ -static int suspend_device_late(struct device *dev, pm_message_t state) -{ - int error = 0; - - if (dev->bus && dev->bus->suspend_late) { - suspend_device_dbg(dev, state, "LATE "); - error = dev->bus->suspend_late(dev, state); - suspend_report_result(dev->bus->suspend_late, error); - } - return error; -} - -/** - * device_suspend - Save state and stop all devices in system. - * @state: Power state to put each device in. - * - * Walk the dpm_active list, call ->suspend() for each device, and move - * it to the dpm_off list. - * - * (For historical reasons, if it returns -EAGAIN, that used to mean - * that the device would be called again with interrupts disabled. - * These days, we use the "suspend_late()" callback for that, so we - * print a warning and consider it an error). - * - * If we get a different error, try and back out. - * - * If we hit a failure with any of the devices, call device_resume() - * above to bring the suspended devices back to life. - * - */ - -int device_suspend(pm_message_t state) -{ - int error = 0; - - might_sleep(); - mutex_lock(&dpm_mtx); - mutex_lock(&dpm_list_mtx); - while (!list_empty(&dpm_active) && error == 0) { - struct list_head * entry = dpm_active.prev; - struct device * dev = to_device(entry); - - get_device(dev); - mutex_unlock(&dpm_list_mtx); - - error = suspend_device(dev, state); - - mutex_lock(&dpm_list_mtx); - - /* Check if the device got removed */ - if (!list_empty(&dev->power.entry)) { - /* Move it to the dpm_off list */ - if (!error) - list_move(&dev->power.entry, &dpm_off); - } - if (error) - printk(KERN_ERR "Could not suspend device %s: " - "error %d%s\n", - kobject_name(&dev->kobj), error, - error == -EAGAIN ? " (please convert to suspend_late)" : ""); - put_device(dev); - } - mutex_unlock(&dpm_list_mtx); - if (error) - dpm_resume(); - - mutex_unlock(&dpm_mtx); - return error; -} - -EXPORT_SYMBOL_GPL(device_suspend); - -/** - * device_power_down - Shut down special devices. - * @state: Power state to enter. - * - * Walk the dpm_off_irq list, calling ->power_down() for each device that - * couldn't power down the device with interrupts enabled. When we're - * done, power down system devices. - */ - -int device_power_down(pm_message_t state) -{ - int error = 0; - struct device * dev; - - while (!list_empty(&dpm_off)) { - struct list_head * entry = dpm_off.prev; - - dev = to_device(entry); - error = suspend_device_late(dev, state); - if (error) - goto Error; - list_move(&dev->power.entry, &dpm_off_irq); - } - - error = sysdev_suspend(state); - Done: - return error; - Error: - printk(KERN_ERR "Could not power down device %s: " - "error %d\n", kobject_name(&dev->kobj), error); - dpm_power_up(); - goto Done; -} - -EXPORT_SYMBOL_GPL(device_power_down); - -void __suspend_report_result(const char *function, void *fn, int ret) -{ - if (ret) { - printk(KERN_ERR "%s(): ", function); - print_fn_descriptor_symbol("%s() returns ", (unsigned long)fn); - printk("%d\n", ret); - } -} -EXPORT_SYMBOL_GPL(__suspend_report_result); -- cgit v1.2.3-70-g09d2 From 011db815231f40d4d53531b5d41b82c8dc7c44bf Mon Sep 17 00:00:00 2001 From: Micah Gruber Date: Wed, 5 Sep 2007 13:49:58 +0800 Subject: USB: Remove unneeded pointer intf from speedtch_upload_firmware() This trivial patch removes the unneeded pointer intf returned from usb_ifnum_to_if(), which is never used. The check for NULL can be simply done by if (!usb_ifnum_to_if(usb_dev, 2)). Signed-off-by: Micah Gruber Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/speedtch.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c index eb0615abff6..8b132c4a503 100644 --- a/drivers/usb/atm/speedtch.c +++ b/drivers/usb/atm/speedtch.c @@ -251,7 +251,6 @@ static int speedtch_upload_firmware(struct speedtch_instance_data *instance, { unsigned char *buffer; struct usbatm_data *usbatm = instance->usbatm; - struct usb_interface *intf; struct usb_device *usb_dev = usbatm->usb_dev; int actual_length; int ret = 0; @@ -265,7 +264,7 @@ static int speedtch_upload_firmware(struct speedtch_instance_data *instance, goto out; } - if (!(intf = usb_ifnum_to_if(usb_dev, 2))) { + if (!usb_ifnum_to_if(usb_dev, 2)) { ret = -ENODEV; usb_dbg(usbatm, "%s: interface not found!\n", __func__); goto out_free; -- cgit v1.2.3-70-g09d2 From ca337db6f92a32347172a20b96f6f51b7bb63b7c Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Sat, 21 Jul 2007 17:02:59 +0200 Subject: USB: Clean up duplicate includes in drivers/usb/ This patch cleans up duplicate includes in drivers/usb/ Signed-off-by: Jesper Juhl Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/u132-hcd.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index b88eb3c62c0..598ad098aee 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -51,7 +51,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3-70-g09d2 From 7f477358e2384c54b190cc3b6ce28277050a041b Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Mon, 23 Jul 2007 01:58:15 -0700 Subject: usblp: Implement the ENOSPC convention This patch implements a mode when a printer returns ENOSPC when it runs out of paper. The default remains the same as before. An application which wishes to use this function has to enable it explicitly with an ioctl LPABORT. This is done on a request by our (Fedora) CUPS guy, Tim Waugh. The API is similar enough to the lp0's one that CUPS works with both (but see below), but it's has some differences. Most importantly, the abort mode is persistent in case of lp0: once tunelp was run your cat fill blow up until you reboot or run tunelp again. For usblp, I made it so the abort mode is only in effect as long as device is open. This way you can mix and match CUPS and cat(1) freely and nothing bad happens even if you run out of paper. It is also safer in the face of any unexpected crashes. It has to be noted that mixing LPABORT and O_NONBLOCK is not advised. It probably does not do what you want: instead of returning -ENOSPC it will always return -EAGAIN (because it would otherwise block while waiting for the paper). Applications which use O_NONBLOCK should continue to use LPGETSTATUS like before. Finally, CUPS actually requires patching to take full advantage of this. It has several components; those which invoke LPABORT work, but some of them need the ioctl added. This is completely compatible, you can mix old CUPS and new kernels or vice versa. Signed-off-by: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usblp.c | 65 ++++++++++++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index 5192cd9356d..30d5a1315cc 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -69,7 +69,6 @@ #define USBLP_DEVICE_ID_SIZE 1024 /* ioctls: */ -#define LPGETSTATUS 0x060b /* same as in drivers/char/lp.c */ #define IOCNR_GET_DEVICE_ID 1 #define IOCNR_GET_PROTOCOLS 2 #define IOCNR_SET_PROTOCOL 3 @@ -159,10 +158,12 @@ struct usblp { int wstatus; /* bytes written or error */ int rstatus; /* bytes ready or error */ unsigned int quirks; /* quirks flags */ + unsigned int flags; /* mode flags */ unsigned char used; /* True if open */ unsigned char present; /* True if not disconnected */ unsigned char bidir; /* interface is bidirectional */ unsigned char sleeping; /* interface is suspended */ + unsigned char no_paper; /* Paper Out happened */ unsigned char *device_id_string; /* IEEE 1284 DEVICE ID string (ptr) */ /* first 2 bytes are (big-endian) length */ }; @@ -325,6 +326,7 @@ static void usblp_bulk_write(struct urb *urb) usblp->wstatus = status; else usblp->wstatus = urb->actual_length; + usblp->no_paper = 0; usblp->wcomplete = 1; wake_up(&usblp->wwait); spin_unlock(&usblp->lock); @@ -411,18 +413,10 @@ static int usblp_open(struct inode *inode, struct file *file) goto out; /* - * TODO: need to implement LP_ABORTOPEN + O_NONBLOCK as in drivers/char/lp.c ??? - * This is #if 0-ed because we *don't* want to fail an open - * just because the printer is off-line. + * We do not implement LP_ABORTOPEN/LPABORTOPEN for two reasons: + * - We do not want persistent state which close(2) does not clear + * - It is not used anyway, according to CUPS people */ -#if 0 - if ((retval = usblp_check_status(usblp, 0))) { - retval = retval > 1 ? -EIO : -ENOSPC; - goto out; - } -#else - retval = 0; -#endif retval = usb_autopm_get_interface(intf); if (retval < 0) @@ -463,6 +457,8 @@ static int usblp_release(struct inode *inode, struct file *file) { struct usblp *usblp = file->private_data; + usblp->flags &= ~LP_ABORT; + mutex_lock (&usblp_mutex); usblp->used = 0; if (usblp->present) { @@ -486,7 +482,7 @@ static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait poll_wait(file, &usblp->wwait, wait); spin_lock_irqsave(&usblp->lock, flags); ret = ((!usblp->bidir || !usblp->rcomplete) ? 0 : POLLIN | POLLRDNORM) - | (!usblp->wcomplete ? 0 : POLLOUT | POLLWRNORM); + | ((usblp->no_paper || usblp->wcomplete) ? POLLOUT | POLLWRNORM : 0); spin_unlock_irqrestore(&usblp->lock, flags); return ret; } @@ -675,6 +671,13 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; + case LPABORT: + if (arg) + usblp->flags |= LP_ABORT; + else + usblp->flags &= ~LP_ABORT; + break; + default: retval = -ENOTTY; } @@ -730,6 +733,7 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t if ((rv = usb_submit_urb(writeurb, GFP_KERNEL)) < 0) { usblp->wstatus = 0; spin_lock_irq(&usblp->lock); + usblp->no_paper = 0; usblp->wcomplete = 1; wake_up(&usblp->wwait); spin_unlock_irq(&usblp->lock); @@ -747,12 +751,17 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t /* Presume that it's going to complete well. */ writecount += transfer_length; } + if (rv == -ENOSPC) { + spin_lock_irq(&usblp->lock); + usblp->no_paper = 1; /* Mark for poll(2) */ + spin_unlock_irq(&usblp->lock); + writecount += transfer_length; + } /* Leave URB dangling, to be cleaned on close. */ goto collect_error; } if (usblp->wstatus < 0) { - usblp_check_status(usblp, 0); rv = -EIO; goto collect_error; } @@ -838,32 +847,36 @@ done: * when O_NONBLOCK is set. So, applications setting O_NONBLOCK must use * select(2) or poll(2) to wait for the buffer to drain before closing. * Alternatively, set blocking mode with fcntl and issue a zero-size write. - * - * Old v0.13 code had a non-functional timeout for wait_event(). Someone forgot - * to check the return code for timeout expiration, so it had no effect. - * Apparently, it was intended to check for error conditons, such as out - * of paper. It is going to return when we settle things with CUPS. XXX */ static int usblp_wwait(struct usblp *usblp, int nonblock) { DECLARE_WAITQUEUE(waita, current); int rc; + int err = 0; add_wait_queue(&usblp->wwait, &waita); for (;;) { + set_current_state(TASK_INTERRUPTIBLE); if (mutex_lock_interruptible(&usblp->mut)) { rc = -EINTR; break; } - set_current_state(TASK_INTERRUPTIBLE); - if ((rc = usblp_wtest(usblp, nonblock)) < 0) { - mutex_unlock(&usblp->mut); - break; - } + rc = usblp_wtest(usblp, nonblock); mutex_unlock(&usblp->mut); - if (rc == 0) + if (rc <= 0) break; - schedule(); + + if (usblp->flags & LP_ABORT) { + if (schedule_timeout(msecs_to_jiffies(5000)) == 0) { + err = usblp_check_status(usblp, err); + if (err == 1) { /* Paper out */ + rc = -ENOSPC; + break; + } + } + } else { + schedule(); + } } set_current_state(TASK_RUNNING); remove_wait_queue(&usblp->wwait, &waita); -- cgit v1.2.3-70-g09d2 From e8fa0ce65c58dbb60be279c4e33534650dcacc31 Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Mon, 23 Jul 2007 02:17:49 -0700 Subject: usblp: Make use of URB_FREE_BUFFER Employ the new API URB_FREE_BUFFER that we've got. There was talk of a combined constructor for this case, but apparently it's not happening, so just set the flag explicitly for now. Signed-off-by: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usblp.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index 30d5a1315cc..9696668e575 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -331,9 +331,6 @@ static void usblp_bulk_write(struct urb *urb) wake_up(&usblp->wwait); spin_unlock(&usblp->lock); - /* XXX Use usb_setup_bulk_urb when available. Talk to Marcel. */ - kfree(urb->transfer_buffer); - urb->transfer_buffer = NULL; /* Not refcounted, so to be safe... */ usb_free_urb(urb); } @@ -719,6 +716,7 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t usb_sndbulkpipe(usblp->dev, usblp->protocol[usblp->current_protocol].epwrite->bEndpointAddress), writebuf, transfer_length, usblp_bulk_write, usblp); + writeurb->transfer_flags |= URB_FREE_BUFFER; usb_anchor_urb(writeurb, &usblp->urbs); if (copy_from_user(writebuf, -- cgit v1.2.3-70-g09d2 From 89a0fd18a96eb1f8732714b575073f8a8d69c009 Mon Sep 17 00:00:00 2001 From: Mike Nuss Date: Wed, 1 Aug 2007 13:24:30 -0700 Subject: USB: OHCI handles more ZFMicro quirks The ZF Micro OHCI controller exhibits unexpected behavior that seems to be related to high load. Under certain conditions, the controller will complete a TD, remove it from the endpoint's queue, and fail to add it to the donelist. This causes the endpoint to appear to stop responding. Worse, if the device is removed while in that state, OHCI will hang while waiting for the orphaned TD to complete. The situation is not recoverable without rebooting. This fix enhances the scope of the existing OHCI_QUIRK_ZFMICRO flag: 1. A watchdog routine periodically scans the OHCI structures to check for orphaned TDs. In these cases the TD is taken back from the controller and completed normally. 2. If a device is removed while the endpoint is hung but before the watchdog catches the situation, any outstanding TDs are taken back from the controller in the 'sanitize' phase. The ohci-hcd driver used to print "INTR_SF lossage" in this situation; this changes it to the universally accurate "ED unlink timeout". Other instances of this message presumably have different root causes. Both this Compaq quirk and a NEC quirk are now properly compiled out for non-PCI builds of this driver. Signed-off-by: Mike Nuss Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-hcd.c | 166 +++++++++++++++++++++++++++++++++++++------- drivers/usb/host/ohci-mem.c | 1 - drivers/usb/host/ohci-pci.c | 22 +++++- drivers/usb/host/ohci-q.c | 113 ++++++++++++++++++------------ drivers/usb/host/ohci.h | 26 +++++++ 5 files changed, 253 insertions(+), 75 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 6edf4097d2d..d673cb9c36b 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -81,7 +81,6 @@ static void ohci_dump (struct ohci_hcd *ohci, int verbose); static int ohci_init (struct ohci_hcd *ohci); static void ohci_stop (struct usb_hcd *hcd); static int ohci_restart (struct ohci_hcd *ohci); -static void ohci_quirk_nec_worker (struct work_struct *work); #include "ohci-hub.c" #include "ohci-dbg.c" @@ -314,6 +313,8 @@ rescan: if (!HC_IS_RUNNING (hcd->state)) { sanitize: ed->state = ED_IDLE; + if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT) + ohci->eds_scheduled--; finish_unlinks (ohci, 0); } @@ -321,7 +322,12 @@ sanitize: case ED_UNLINK: /* wait for hw to finish? */ /* major IRQ delivery trouble loses INTR_SF too... */ if (limit-- == 0) { - ohci_warn (ohci, "IRQ INTR_SF lossage\n"); + ohci_warn(ohci, "ED unlink timeout\n"); + if (quirk_zfmicro(ohci)) { + ohci_warn(ohci, "Attempting ZF TD recovery\n"); + ohci->ed_to_check = ed; + ohci->zf_delay = 2; + } goto sanitize; } spin_unlock_irqrestore (&ohci->lock, flags); @@ -379,6 +385,93 @@ ohci_shutdown (struct usb_hcd *hcd) (void) ohci_readl (ohci, &ohci->regs->control); } +static int check_ed(struct ohci_hcd *ohci, struct ed *ed) +{ + return (hc32_to_cpu(ohci, ed->hwINFO) & ED_IN) != 0 + && (hc32_to_cpu(ohci, ed->hwHeadP) & TD_MASK) + == (hc32_to_cpu(ohci, ed->hwTailP) & TD_MASK) + && !list_empty(&ed->td_list); +} + +/* ZF Micro watchdog timer callback. The ZF Micro chipset sometimes completes + * an interrupt TD but neglects to add it to the donelist. On systems with + * this chipset, we need to periodically check the state of the queues to look + * for such "lost" TDs. + */ +static void unlink_watchdog_func(unsigned long _ohci) +{ + long flags; + unsigned max; + unsigned seen_count = 0; + unsigned i; + struct ed **seen = NULL; + struct ohci_hcd *ohci = (struct ohci_hcd *) _ohci; + + spin_lock_irqsave(&ohci->lock, flags); + max = ohci->eds_scheduled; + if (!max) + goto done; + + if (ohci->ed_to_check) + goto out; + + seen = kcalloc(max, sizeof *seen, GFP_ATOMIC); + if (!seen) + goto out; + + for (i = 0; i < NUM_INTS; i++) { + struct ed *ed = ohci->periodic[i]; + + while (ed) { + unsigned temp; + + /* scan this branch of the periodic schedule tree */ + for (temp = 0; temp < seen_count; temp++) { + if (seen[temp] == ed) { + /* we've checked it and what's after */ + ed = NULL; + break; + } + } + if (!ed) + break; + seen[seen_count++] = ed; + if (!check_ed(ohci, ed)) { + ed = ed->ed_next; + continue; + } + + /* HC's TD list is empty, but HCD sees at least one + * TD that's not been sent through the donelist. + */ + ohci->ed_to_check = ed; + ohci->zf_delay = 2; + + /* The HC may wait until the next frame to report the + * TD as done through the donelist and INTR_WDH. (We + * just *assume* it's not a multi-TD interrupt URB; + * those could defer the IRQ more than one frame, using + * DI...) Check again after the next INTR_SF. + */ + ohci_writel(ohci, OHCI_INTR_SF, + &ohci->regs->intrstatus); + ohci_writel(ohci, OHCI_INTR_SF, + &ohci->regs->intrenable); + + /* flush those writes */ + (void) ohci_readl(ohci, &ohci->regs->control); + + goto out; + } + } +out: + kfree(seen); + if (ohci->eds_scheduled) + mod_timer(&ohci->unlink_watchdog, round_jiffies_relative(HZ)); +done: + spin_unlock_irqrestore(&ohci->lock, flags); +} + /*-------------------------------------------------------------------------* * HC functions *-------------------------------------------------------------------------*/ @@ -616,6 +709,15 @@ retry: mdelay ((temp >> 23) & 0x1fe); hcd->state = HC_STATE_RUNNING; + if (quirk_zfmicro(ohci)) { + /* Create timer to watch for bad queue state on ZF Micro */ + setup_timer(&ohci->unlink_watchdog, unlink_watchdog_func, + (unsigned long) ohci); + + ohci->eds_scheduled = 0; + ohci->ed_to_check = NULL; + } + ohci_dump (ohci, 1); return 0; @@ -629,10 +731,11 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); struct ohci_regs __iomem *regs = ohci->regs; - int ints; + int ints; /* we can eliminate a (slow) ohci_readl() - if _only_ WDH caused this irq */ + * if _only_ WDH caused this irq + */ if ((ohci->hcca->done_head != 0) && ! (hc32_to_cpup (ohci, &ohci->hcca->done_head) & 0x01)) { @@ -651,7 +754,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) if (ints & OHCI_INTR_UE) { // e.g. due to PCI Master/Target Abort - if (ohci->flags & OHCI_QUIRK_NEC) { + if (quirk_nec(ohci)) { /* Workaround for a silicon bug in some NEC chips used * in Apple's PowerBooks. Adapted from Darwin code. */ @@ -713,6 +816,31 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) ohci_writel (ohci, OHCI_INTR_WDH, ®s->intrenable); } + if (quirk_zfmicro(ohci) && (ints & OHCI_INTR_SF)) { + spin_lock(&ohci->lock); + if (ohci->ed_to_check) { + struct ed *ed = ohci->ed_to_check; + + if (check_ed(ohci, ed)) { + /* HC thinks the TD list is empty; HCD knows + * at least one TD is outstanding + */ + if (--ohci->zf_delay == 0) { + struct td *td = list_entry( + ed->td_list.next, + struct td, td_list); + ohci_warn(ohci, + "Reclaiming orphan TD %p\n", + td); + takeback_td(ohci, td); + ohci->ed_to_check = NULL; + } + } else + ohci->ed_to_check = NULL; + } + spin_unlock(&ohci->lock); + } + /* could track INTR_SO to reduce available PCI/... bandwidth */ /* handle any pending URB/ED unlinks, leaving INTR_SF enabled @@ -721,7 +849,9 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) spin_lock (&ohci->lock); if (ohci->ed_rm_list) finish_unlinks (ohci, ohci_frame_no(ohci)); - if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list + if ((ints & OHCI_INTR_SF) != 0 + && !ohci->ed_rm_list + && !ohci->ed_to_check && HC_IS_RUNNING(hcd->state)) ohci_writel (ohci, OHCI_INTR_SF, ®s->intrdisable); spin_unlock (&ohci->lock); @@ -751,6 +881,9 @@ static void ohci_stop (struct usb_hcd *hcd) free_irq(hcd->irq, hcd); hcd->irq = -1; + if (quirk_zfmicro(ohci)) + del_timer(&ohci->unlink_watchdog); + remove_debug_files (ohci); ohci_mem_cleanup (ohci); if (ohci->hcca) { @@ -828,27 +961,6 @@ static int ohci_restart (struct ohci_hcd *ohci) /*-------------------------------------------------------------------------*/ -/* NEC workaround */ -static void ohci_quirk_nec_worker(struct work_struct *work) -{ - struct ohci_hcd *ohci = container_of(work, struct ohci_hcd, nec_work); - int status; - - status = ohci_init(ohci); - if (status != 0) { - ohci_err(ohci, "Restarting NEC controller failed " - "in ohci_init, %d\n", status); - return; - } - - status = ohci_restart(ohci); - if (status != 0) - ohci_err(ohci, "Restarting NEC controller failed " - "in ohci_restart, %d\n", status); -} - -/*-------------------------------------------------------------------------*/ - #define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC MODULE_AUTHOR (DRIVER_AUTHOR); diff --git a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c index 450c7b460c5..2f20d3dc895 100644 --- a/drivers/usb/host/ohci-mem.c +++ b/drivers/usb/host/ohci-mem.c @@ -28,7 +28,6 @@ static void ohci_hcd_init (struct ohci_hcd *ohci) ohci->next_statechange = jiffies; spin_lock_init (&ohci->lock); INIT_LIST_HEAD (&ohci->pending); - INIT_WORK (&ohci->nec_work, ohci_quirk_nec_worker); } /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index a5e2eb85d07..d0360f65ebd 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -84,7 +84,7 @@ static int ohci_quirk_zfmicro(struct usb_hcd *hcd) struct ohci_hcd *ohci = hcd_to_ohci (hcd); ohci->flags |= OHCI_QUIRK_ZFMICRO; - ohci_dbg (ohci, "enabled Compaq ZFMicro chipset quirk\n"); + ohci_dbg(ohci, "enabled Compaq ZFMicro chipset quirks\n"); return 0; } @@ -113,11 +113,31 @@ static int ohci_quirk_toshiba_scc(struct usb_hcd *hcd) /* Check for NEC chip and apply quirk for allegedly lost interrupts. */ + +static void ohci_quirk_nec_worker(struct work_struct *work) +{ + struct ohci_hcd *ohci = container_of(work, struct ohci_hcd, nec_work); + int status; + + status = ohci_init(ohci); + if (status != 0) { + ohci_err(ohci, "Restarting NEC controller failed in %s, %d\n", + "ohci_init", status); + return; + } + + status = ohci_restart(ohci); + if (status != 0) + ohci_err(ohci, "Restarting NEC controller failed in %s, %d\n", + "ohci_restart", status); +} + static int ohci_quirk_nec(struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); ohci->flags |= OHCI_QUIRK_NEC; + INIT_WORK(&ohci->nec_work, ohci_quirk_nec_worker); ohci_dbg (ohci, "enabled NEC chipset lost interrupt quirk\n"); return 0; diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index 830a3fe8615..547d39be3eb 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -179,6 +179,10 @@ static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed) ed->ed_prev = NULL; ed->ed_next = NULL; ed->hwNextED = 0; + if (quirk_zfmicro(ohci) + && (ed->type == PIPE_INTERRUPT) + && !(ohci->eds_scheduled++)) + mod_timer(&ohci->unlink_watchdog, round_jiffies_relative(HZ)); wmb (); /* we care about rm_list when setting CLE/BLE in case the HC was at @@ -940,8 +944,12 @@ skip_ed: TD_MASK; /* INTR_WDH may need to clean up first */ - if (td->td_dma != head) - goto skip_ed; + if (td->td_dma != head) { + if (ed == ohci->ed_to_check) + ohci->ed_to_check = NULL; + else + goto skip_ed; + } } } @@ -998,6 +1006,8 @@ rescan_this: /* ED's now officially unlinked, hc doesn't see */ ed->state = ED_IDLE; + if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT) + ohci->eds_scheduled--; ed->hwHeadP &= ~cpu_to_hc32(ohci, ED_H); ed->hwNextED = 0; wmb (); @@ -1021,7 +1031,7 @@ rescan_this: if (ohci->ed_controltail) { command |= OHCI_CLF; - if (ohci->flags & OHCI_QUIRK_ZFMICRO) + if (quirk_zfmicro(ohci)) mdelay(1); if (!(ohci->hc_control & OHCI_CTRL_CLE)) { control |= OHCI_CTRL_CLE; @@ -1031,7 +1041,7 @@ rescan_this: } if (ohci->ed_bulktail) { command |= OHCI_BLF; - if (ohci->flags & OHCI_QUIRK_ZFMICRO) + if (quirk_zfmicro(ohci)) mdelay(1); if (!(ohci->hc_control & OHCI_CTRL_BLE)) { control |= OHCI_CTRL_BLE; @@ -1043,13 +1053,13 @@ rescan_this: /* CLE/BLE to enable, CLF/BLF to (maybe) kickstart */ if (control) { ohci->hc_control |= control; - if (ohci->flags & OHCI_QUIRK_ZFMICRO) + if (quirk_zfmicro(ohci)) mdelay(1); ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); } if (command) { - if (ohci->flags & OHCI_QUIRK_ZFMICRO) + if (quirk_zfmicro(ohci)) mdelay(1); ohci_writel (ohci, command, &ohci->regs->cmdstatus); } @@ -1060,12 +1070,60 @@ rescan_this: /*-------------------------------------------------------------------------*/ +/* + * Used to take back a TD from the host controller. This would normally be + * called from within dl_done_list, however it may be called directly if the + * HC no longer sees the TD and it has not appeared on the donelist (after + * two frames). This bug has been observed on ZF Micro systems. + */ +static void takeback_td(struct ohci_hcd *ohci, struct td *td) +{ + struct urb *urb = td->urb; + urb_priv_t *urb_priv = urb->hcpriv; + struct ed *ed = td->ed; + + /* update URB's length and status from TD */ + td_done(ohci, urb, td); + urb_priv->td_cnt++; + + /* If all this urb's TDs are done, call complete() */ + if (urb_priv->td_cnt == urb_priv->length) + finish_urb(ohci, urb); + + /* clean schedule: unlink EDs that are no longer busy */ + if (list_empty(&ed->td_list)) { + if (ed->state == ED_OPER) + start_ed_unlink(ohci, ed); + + /* ... reenabling halted EDs only after fault cleanup */ + } else if ((ed->hwINFO & cpu_to_hc32(ohci, ED_SKIP | ED_DEQUEUE)) + == cpu_to_hc32(ohci, ED_SKIP)) { + td = list_entry(ed->td_list.next, struct td, td_list); + if (!(td->hwINFO & cpu_to_hc32(ohci, TD_DONE))) { + ed->hwINFO &= ~cpu_to_hc32(ohci, ED_SKIP); + /* ... hc may need waking-up */ + switch (ed->type) { + case PIPE_CONTROL: + ohci_writel(ohci, OHCI_CLF, + &ohci->regs->cmdstatus); + break; + case PIPE_BULK: + ohci_writel(ohci, OHCI_BLF, + &ohci->regs->cmdstatus); + break; + } + } + } +} + /* * Process normal completions (error or success) and clean the schedules. * * This is the main path for handing urbs back to drivers. The only other - * path is finish_unlinks(), which unlinks URBs using ed_rm_list, instead of - * scanning the (re-reversed) donelist as this does. + * normal path is finish_unlinks(), which unlinks URBs using ed_rm_list, + * instead of scanning the (re-reversed) donelist as this does. There's + * an abnormal path too, handling a quirk in some Compaq silicon: URBs + * with TDs that appear to be orphaned are directly reclaimed. */ static void dl_done_list (struct ohci_hcd *ohci) @@ -1074,44 +1132,7 @@ dl_done_list (struct ohci_hcd *ohci) while (td) { struct td *td_next = td->next_dl_td; - struct urb *urb = td->urb; - urb_priv_t *urb_priv = urb->hcpriv; - struct ed *ed = td->ed; - - /* update URB's length and status from TD */ - td_done (ohci, urb, td); - urb_priv->td_cnt++; - - /* If all this urb's TDs are done, call complete() */ - if (urb_priv->td_cnt == urb_priv->length) - finish_urb (ohci, urb); - - /* clean schedule: unlink EDs that are no longer busy */ - if (list_empty (&ed->td_list)) { - if (ed->state == ED_OPER) - start_ed_unlink (ohci, ed); - - /* ... reenabling halted EDs only after fault cleanup */ - } else if ((ed->hwINFO & cpu_to_hc32 (ohci, - ED_SKIP | ED_DEQUEUE)) - == cpu_to_hc32 (ohci, ED_SKIP)) { - td = list_entry (ed->td_list.next, struct td, td_list); - if (!(td->hwINFO & cpu_to_hc32 (ohci, TD_DONE))) { - ed->hwINFO &= ~cpu_to_hc32 (ohci, ED_SKIP); - /* ... hc may need waking-up */ - switch (ed->type) { - case PIPE_CONTROL: - ohci_writel (ohci, OHCI_CLF, - &ohci->regs->cmdstatus); - break; - case PIPE_BULK: - ohci_writel (ohci, OHCI_BLF, - &ohci->regs->cmdstatus); - break; - } - } - } - + takeback_td(ohci, td); td = td_next; } } diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index 4ada43cf138..dd4d5b4dcb6 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -401,8 +401,34 @@ struct ohci_hcd { // there are also chip quirks/bugs in init logic struct work_struct nec_work; /* Worker for NEC quirk */ + + /* Needed for ZF Micro quirk */ + struct timer_list unlink_watchdog; + unsigned eds_scheduled; + struct ed *ed_to_check; + unsigned zf_delay; }; +#ifdef CONFIG_PCI +static inline int quirk_nec(struct ohci_hcd *ohci) +{ + return ohci->flags & OHCI_QUIRK_NEC; +} +static inline int quirk_zfmicro(struct ohci_hcd *ohci) +{ + return ohci->flags & OHCI_QUIRK_ZFMICRO; +} +#else +static inline int quirk_nec(struct ohci_hcd *ohci) +{ + return 0; +} +static inline int quirk_zfmicro(struct ohci_hcd *ohci) +{ + return 0; +} +#endif + /* convert between an hcd pointer and the corresponding ohci_hcd */ static inline struct ohci_hcd *hcd_to_ohci (struct usb_hcd *hcd) { -- cgit v1.2.3-70-g09d2 From 9f705bde6e77c24a3ba737ac45abc0f8e619e92e Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Wed, 1 Aug 2007 18:16:55 -0400 Subject: USB: Remove dead references to "SAFE_SERIAL" CONFIG variables. Remove the references to CONFIG_USBD_SAFE_SERIAL_{VENDOR,PRODUCT}, which aren't defined in any Kconfig file. Signed-off-by: Robert P. J. Day Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/safe_serial.c | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c index 51669b7622b..4e6dcc199be 100644 --- a/drivers/usb/serial/safe_serial.c +++ b/drivers/usb/serial/safe_serial.c @@ -90,18 +90,12 @@ MODULE_AUTHOR (DRIVER_AUTHOR); MODULE_DESCRIPTION (DRIVER_DESC); MODULE_LICENSE("GPL"); -#if defined(CONFIG_USBD_SAFE_SERIAL_VENDOR) && !defined(CONFIG_USBD_SAFE_SERIAL_PRODUCT) -#error "SAFE_SERIAL_VENDOR defined without SAFE_SERIAL_PRODUCT" -#endif - -#if ! defined(CONFIG_USBD_SAFE_SERIAL_VENDOR) static __u16 vendor; // no default static __u16 product; // no default module_param(vendor, ushort, 0); MODULE_PARM_DESC(vendor, "User specified USB idVendor (required)"); module_param(product, ushort, 0); MODULE_PARM_DESC(product, "User specified USB idProduct (required)"); -#endif module_param(debug, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug enabled or not"); @@ -145,11 +139,6 @@ static struct usb_device_id id_table[] = { {MY_USB_DEVICE (0x4dd, 0x8003, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, // Collie {MY_USB_DEVICE (0x4dd, 0x8004, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, // Collie {MY_USB_DEVICE (0x5f9, 0xffff, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, // Sharp tmp -#if defined(CONFIG_USB_SAFE_SERIAL_VENDOR) - {MY_USB_DEVICE - (CONFIG_USB_SAFE_SERIAL_VENDOR, CONFIG_USB_SAFE_SERIAL_PRODUCT, CDC_DEVICE_CLASS, - LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, -#endif // extra null entry for module // vendor/produc parameters {MY_USB_DEVICE (0, 0, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, -- cgit v1.2.3-70-g09d2 From a96173af521a173f45d3a27fa24265081f12e978 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 31 Jul 2007 00:28:22 +0200 Subject: USB: Storage: usbat_check_status(): fix check-after-use The Coverity checker spotted that we have already oops'ed if "us" was NULL. Since "us" can't be NULL in the only caller this patch removes the NULL check. Signed-off-by: Adrian Bunk Signed-off-by: Matthew Dharm Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/shuttle_usbat.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c index 5e27297c017..17ca4d73577 100644 --- a/drivers/usb/storage/shuttle_usbat.c +++ b/drivers/usb/storage/shuttle_usbat.c @@ -190,9 +190,6 @@ static int usbat_check_status(struct us_data *us) unsigned char *reply = us->iobuf; int rc; - if (!us) - return USB_STOR_TRANSPORT_ERROR; - rc = usbat_get_status(us, reply); if (rc != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_FAILED; -- cgit v1.2.3-70-g09d2 From 5b653c79c04c6b152b8dc7d18f8c8a7f77f4b235 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 30 Jul 2007 17:04:37 -0400 Subject: USB: add urb->ep This patch (as943) prepares the way for eliminating urb->pipe by introducing an endpoint pointer into struct urb. For now urb->ep is set by usb_submit_urb() from the pipe value; eventually drivers will set it themselves and we will remove urb->pipe completely. The patch also adds new inline routines to retrieve an endpoint descriptor's number and transfer type, essentially as replacements for usb_pipeendpoint and usb_pipetype. usb_submit_urb(), usb_hcd_submit_urb(), and usb_hcd_unlink_urb() are converted to use the new field and new routines. Other parts of usbcore will be converted in later patches. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 13 ++++------ drivers/usb/core/urb.c | 65 +++++++++++++++++++++++++++----------------------- include/linux/usb.h | 26 ++++++++++++++++++++ 3 files changed, 65 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 42ef1d5f6c8..fb82c500caf 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -962,14 +962,14 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) spin_lock_irqsave(&hcd_urb_list_lock, flags); ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out) [usb_pipeendpoint(urb->pipe)]; - if (unlikely (!ep)) + if (unlikely(ep != urb->ep)) status = -ENOENT; else if (unlikely (urb->reject)) status = -EPERM; else switch (hcd->state) { case HC_STATE_RUNNING: case HC_STATE_RESUMING: - list_add_tail (&urb->urb_list, &ep->urb_list); + list_add_tail (&urb->urb_list, &urb->ep->urb_list); status = 0; break; default: @@ -1022,7 +1022,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) : DMA_TO_DEVICE); } - status = hcd->driver->urb_enqueue (hcd, ep, urb, mem_flags); + status = hcd->driver->urb_enqueue (hcd, urb->ep, urb, mem_flags); done: if (unlikely (status)) { urb_unlink(hcd, urb); @@ -1071,7 +1071,6 @@ unlink1 (struct usb_hcd *hcd, struct urb *urb) */ int usb_hcd_unlink_urb (struct urb *urb, int status) { - struct usb_host_endpoint *ep; struct usb_hcd *hcd = NULL; struct device *sys = NULL; unsigned long flags; @@ -1082,10 +1081,6 @@ int usb_hcd_unlink_urb (struct urb *urb, int status) return -EINVAL; if (!urb->dev || !urb->dev->bus) return -ENODEV; - ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out) - [usb_pipeendpoint(urb->pipe)]; - if (!ep) - return -ENODEV; /* * we contend for urb->status with the hcd core, @@ -1109,7 +1104,7 @@ int usb_hcd_unlink_urb (struct urb *urb, int status) } /* insist the urb is still queued */ - list_for_each(tmp, &ep->urb_list) { + list_for_each(tmp, &urb->ep->urb_list) { if (tmp == &urb->urb_list) break; } diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index be630228461..ff53acb4fab 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -277,9 +277,10 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb); */ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) { - int pipe, temp, max; - struct usb_device *dev; - int is_out; + int xfertype, max; + struct usb_device *dev; + struct usb_host_endpoint *ep; + int is_out; if (!urb || urb->hcpriv || !urb->complete) return -EINVAL; @@ -291,30 +292,34 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) || dev->state == USB_STATE_SUSPENDED) return -EHOSTUNREACH; + /* For now, get the endpoint from the pipe. Eventually drivers + * will be required to set urb->ep directly and we will eliminate + * urb->pipe. + */ + ep = (usb_pipein(urb->pipe) ? dev->ep_in : dev->ep_out) + [usb_pipeendpoint(urb->pipe)]; + if (!ep) + return -ENOENT; + + urb->ep = ep; urb->status = -EINPROGRESS; urb->actual_length = 0; /* Lots of sanity checks, so HCDs can rely on clean data * and don't need to duplicate tests */ - pipe = urb->pipe; - temp = usb_pipetype(pipe); - is_out = usb_pipeout(pipe); + xfertype = usb_endpoint_type(&ep->desc); + is_out = usb_pipeout(urb->pipe); - if (!usb_pipecontrol(pipe) && dev->state < USB_STATE_CONFIGURED) + if (xfertype != USB_ENDPOINT_XFER_CONTROL && + dev->state < USB_STATE_CONFIGURED) return -ENODEV; - /* FIXME there should be a sharable lock protecting us against - * config/altsetting changes and disconnects, kicking in here. - * (here == before maxpacket, and eventually endpoint type, - * checks get made.) - */ - - max = usb_maxpacket(dev, pipe, is_out); + max = le16_to_cpu(ep->desc.wMaxPacketSize); if (max <= 0) { dev_dbg(&dev->dev, "bogus endpoint ep%d%s in %s (bad maxpacket %d)\n", - usb_pipeendpoint(pipe), is_out ? "out" : "in", + usb_endpoint_num(&ep->desc), is_out ? "out" : "in", __FUNCTION__, max); return -EMSGSIZE; } @@ -323,7 +328,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) * but drivers only control those sizes for ISO. * while we're checking, initialize return status. */ - if (temp == PIPE_ISOCHRONOUS) { + if (xfertype == USB_ENDPOINT_XFER_ISOC) { int n, len; /* "high bandwidth" mode, 1-3 packets/uframe? */ @@ -359,19 +364,19 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) /* enforce simple/standard policy */ allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP | URB_NO_INTERRUPT); - switch (temp) { - case PIPE_BULK: + switch (xfertype) { + case USB_ENDPOINT_XFER_BULK: if (is_out) allowed |= URB_ZERO_PACKET; /* FALLTHROUGH */ - case PIPE_CONTROL: + case USB_ENDPOINT_XFER_CONTROL: allowed |= URB_NO_FSBR; /* only affects UHCI */ /* FALLTHROUGH */ default: /* all non-iso endpoints */ if (!is_out) allowed |= URB_SHORT_NOT_OK; break; - case PIPE_ISOCHRONOUS: + case USB_ENDPOINT_XFER_ISOC: allowed |= URB_ISO_ASAP; break; } @@ -393,9 +398,9 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) * supports different values... this uses EHCI/UHCI defaults (and * EHCI can use smaller non-default values). */ - switch (temp) { - case PIPE_ISOCHRONOUS: - case PIPE_INTERRUPT: + switch (xfertype) { + case USB_ENDPOINT_XFER_ISOC: + case USB_ENDPOINT_XFER_INT: /* too small? */ if (urb->interval <= 0) return -EINVAL; @@ -405,29 +410,29 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) // NOTE usb handles 2^15 if (urb->interval > (1024 * 8)) urb->interval = 1024 * 8; - temp = 1024 * 8; + max = 1024 * 8; break; case USB_SPEED_FULL: /* units are frames/msec */ case USB_SPEED_LOW: - if (temp == PIPE_INTERRUPT) { + if (xfertype == USB_ENDPOINT_XFER_INT) { if (urb->interval > 255) return -EINVAL; // NOTE ohci only handles up to 32 - temp = 128; + max = 128; } else { if (urb->interval > 1024) urb->interval = 1024; // NOTE usb and ohci handle up to 2^15 - temp = 1024; + max = 1024; } break; default: return -EINVAL; } /* power of two? */ - while (temp > urb->interval) - temp >>= 1; - urb->interval = temp; + while (max > urb->interval) + max >>= 1; + urb->interval = max; } return usb_hcd_submit_urb(urb, mem_flags); diff --git a/include/linux/usb.h b/include/linux/usb.h index 4f33a58fa9d..105e3e9362d 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -554,6 +554,29 @@ static inline int usb_make_path (struct usb_device *dev, char *buf, /*-------------------------------------------------------------------------*/ +/** + * usb_endpoint_num - get the endpoint's number + * @epd: endpoint to be checked + * + * Returns @epd's number: 0 to 15. + */ +static inline int usb_endpoint_num(const struct usb_endpoint_descriptor *epd) +{ + return epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; +} + +/** + * usb_endpoint_type - get the endpoint's transfer type + * @epd: endpoint to be checked + * + * Returns one of USB_ENDPOINT_XFER_{CONTROL, ISOC, BULK, INT} according + * to @epd's transfer type. + */ +static inline int usb_endpoint_type(const struct usb_endpoint_descriptor *epd) +{ + return epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; +} + /** * usb_endpoint_dir_in - check if the endpoint has IN direction * @epd: endpoint to be checked @@ -1037,6 +1060,8 @@ typedef void (*usb_complete_t)(struct urb *); * @urb_list: For use by current owner of the URB. * @anchor_list: membership in the list of an anchor * @anchor: to anchor URBs to a common mooring + * @ep: Points to the endpoint's data structure. Will eventually + * replace @pipe. * @pipe: Holds endpoint number, direction, type, and more. * Create these values with the eight macros available; * usb_{snd,rcv}TYPEpipe(dev,endpoint), where the TYPE is "ctrl" @@ -1212,6 +1237,7 @@ struct urb struct list_head anchor_list; /* the URB may be anchored by the driver */ struct usb_anchor *anchor; struct usb_device *dev; /* (in) pointer to associated device */ + struct usb_host_endpoint *ep; /* (internal) pointer to endpoint struct */ unsigned int pipe; /* (in) pipe information */ int status; /* (return) non-ISO status */ unsigned int transfer_flags; /* (in) URB_SHORT_NOT_OK | ...*/ -- cgit v1.2.3-70-g09d2 From bdd016ba64d909329cb4bacacc8443901c00e112 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 30 Jul 2007 17:05:22 -0400 Subject: USB: add ep->enable This patch (as944) adds an explicit "enabled" field to the usb_host_endpoint structure and uses it in place of the current mechanism. This is merely a time-space tradeoff; it makes checking whether URBs may be submitted to an endpoint simpler. The existing mechanism is efficient when converting urb->pipe to an endpoint pointer, but it's not so efficient when urb->ep is used instead. As a side effect, the procedure for enabling an endpoint is now a little more complicated. The ad-hoc inline code in usb.c and hub.c for enabling ep0 is now replaced with calls to usb_enable_endpoint, which is no longer static. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 5 +---- drivers/usb/core/hub.c | 2 +- drivers/usb/core/message.c | 20 ++++++++++---------- drivers/usb/core/usb.c | 2 +- drivers/usb/core/usb.h | 2 ++ include/linux/usb.h | 2 ++ 6 files changed, 17 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index fb82c500caf..cc5b1d3c368 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -943,7 +943,6 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) { int status; struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus); - struct usb_host_endpoint *ep; unsigned long flags; if (!hcd) @@ -960,9 +959,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) // FIXME: verify that quiescing hc works right (RH cleans up) spin_lock_irqsave(&hcd_urb_list_lock, flags); - ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out) - [usb_pipeendpoint(urb->pipe)]; - if (unlikely(ep != urb->ep)) + if (unlikely(!urb->ep->enabled)) status = -ENOENT; else if (unlikely (urb->reject)) status = -EPERM; diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index f7b337feb3e..c8a01f66df7 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1999,7 +1999,7 @@ static void ep0_reinit(struct usb_device *udev) { usb_disable_endpoint(udev, 0 + USB_DIR_IN); usb_disable_endpoint(udev, 0 + USB_DIR_OUT); - udev->ep_in[0] = udev->ep_out[0] = &udev->ep0; + usb_enable_endpoint(udev, &udev->ep0); } #define usb_sndaddr0pipe() (PIPE_CONTROL << 30) diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index d8f7b089a8f..0d618647758 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1013,8 +1013,10 @@ void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr) ep = dev->ep_in[epnum]; dev->ep_in[epnum] = NULL; } - if (ep && dev->bus) + if (ep) { + ep->enabled = 0; usb_hcd_endpoint_disable(dev, ep); + } } /** @@ -1096,23 +1098,21 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0) * Resets the endpoint toggle, and sets dev->ep_{in,out} pointers. * For control endpoints, both the input and output sides are handled. */ -static void -usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep) +void usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep) { - unsigned int epaddr = ep->desc.bEndpointAddress; - unsigned int epnum = epaddr & USB_ENDPOINT_NUMBER_MASK; - int is_control; + int epnum = usb_endpoint_num(&ep->desc); + int is_out = usb_endpoint_dir_out(&ep->desc); + int is_control = usb_endpoint_xfer_control(&ep->desc); - is_control = ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - == USB_ENDPOINT_XFER_CONTROL); - if (usb_endpoint_out(epaddr) || is_control) { + if (is_out || is_control) { usb_settoggle(dev, epnum, 1, 0); dev->ep_out[epnum] = ep; } - if (!usb_endpoint_out(epaddr) || is_control) { + if (!is_out || is_control) { usb_settoggle(dev, epnum, 0, 0); dev->ep_in[epnum] = ep; } + ep->enabled = 1; } /* diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 0fee5c66fd6..d3c68d8eafb 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -260,7 +260,7 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE; dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT; /* ep0 maxpacket comes later, from device descriptor */ - dev->ep_in[0] = dev->ep_out[0] = &dev->ep0; + usb_enable_endpoint(dev, &dev->ep0); /* Save readable and stable topology id, distinguishing devices * by location for diagnostics, tools, driver model, etc. The diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index ad5fa0338f4..cde6e52b84f 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -8,6 +8,8 @@ extern int usb_create_ep_files(struct device *parent, struct usb_host_endpoint * struct usb_device *udev); extern void usb_remove_ep_files(struct usb_host_endpoint *endpoint); +extern void usb_enable_endpoint(struct usb_device *dev, + struct usb_host_endpoint *ep); extern void usb_disable_endpoint (struct usb_device *dev, unsigned int epaddr); extern void usb_disable_interface (struct usb_device *dev, struct usb_interface *intf); diff --git a/include/linux/usb.h b/include/linux/usb.h index 105e3e9362d..818a1b4f737 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -52,6 +52,7 @@ struct ep_device; * @ep_dev: ep_device for sysfs info * @extra: descriptors following this endpoint in the configuration * @extralen: how many bytes of "extra" are valid + * @enabled: URBs may be submitted to this endpoint * * USB requests are always queued to a given endpoint, identified by a * descriptor within an active interface in a given USB configuration. @@ -64,6 +65,7 @@ struct usb_host_endpoint { unsigned char *extra; /* Extra descriptors */ int extralen; + int enabled; }; /* host-side wrapper for one interface setting's parsed descriptors */ -- cgit v1.2.3-70-g09d2 From fea3409112a93581db18da4c4332c8bf8d68af6b Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 30 Jul 2007 17:06:16 -0400 Subject: USB: add direction bit to urb->transfer_flags This patch (as945) adds a bit to urb->transfer_flags for recording the direction of the URB. The bit is set/cleared automatically in usb_submit_urb() so drivers don't have to worry about it (although as a result, it isn't valid until the URB has been submitted). Inline routines are added for easily checking an URB's direction. They replace calls to usb_pipein in the DMA-mapping parts of hcd.c. For non-control endpoints, the direction is determined directly from the endpoint descriptor. However control endpoints are bi-directional; for them the direction is determined from the bRequestType byte and the wLength value in the setup packet. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 4 ++-- drivers/usb/core/urb.c | 18 ++++++++++++++++-- include/linux/usb.h | 30 ++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index cc5b1d3c368..bcbaedc897d 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -928,7 +928,7 @@ static void urb_unlink(struct usb_hcd *hcd, struct urb *urb) dma_unmap_single (hcd->self.controller, urb->transfer_dma, urb->transfer_buffer_length, - usb_pipein (urb->pipe) + usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } @@ -1014,7 +1014,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) hcd->self.controller, urb->transfer_buffer, urb->transfer_buffer_length, - usb_pipein (urb->pipe) + usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index ff53acb4fab..1a64a6a850f 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -309,7 +309,21 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) * and don't need to duplicate tests */ xfertype = usb_endpoint_type(&ep->desc); - is_out = usb_pipeout(urb->pipe); + if (xfertype == USB_ENDPOINT_XFER_CONTROL) { + struct usb_ctrlrequest *setup = + (struct usb_ctrlrequest *) urb->setup_packet; + + if (!setup) + return -ENOEXEC; + is_out = !(setup->bRequestType & USB_DIR_IN) || + !setup->wLength; + } else { + is_out = usb_endpoint_dir_out(&ep->desc); + } + + /* Cache the direction for later use */ + urb->transfer_flags = (urb->transfer_flags & ~URB_DIR_MASK) | + (is_out ? URB_DIR_OUT : URB_DIR_IN); if (xfertype != USB_ENDPOINT_XFER_CONTROL && dev->state < USB_STATE_CONFIGURED) @@ -363,7 +377,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) /* enforce simple/standard policy */ allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP | - URB_NO_INTERRUPT); + URB_NO_INTERRUPT | URB_DIR_MASK); switch (xfertype) { case USB_ENDPOINT_XFER_BULK: if (is_out) diff --git a/include/linux/usb.h b/include/linux/usb.h index 818a1b4f737..9d08f5a5ba7 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -1021,6 +1021,8 @@ extern int usb_disabled(void); /* * urb->transfer_flags: + * + * Note: URB_DIR_IN/OUT is automatically set in usb_submit_urb(). */ #define URB_SHORT_NOT_OK 0x0001 /* report short reads as errors */ #define URB_ISO_ASAP 0x0002 /* iso-only, urb->start_frame @@ -1033,6 +1035,10 @@ extern int usb_disabled(void); * needed */ #define URB_FREE_BUFFER 0x0100 /* Free transfer buffer with the URB */ +#define URB_DIR_IN 0x0200 /* Transfer from device to host */ +#define URB_DIR_OUT 0 +#define URB_DIR_MASK URB_DIR_IN + struct usb_iso_packet_descriptor { unsigned int offset; unsigned int length; /* expected length */ @@ -1380,6 +1386,30 @@ extern void usb_unanchor_urb(struct urb *urb); extern int usb_wait_anchor_empty_timeout(struct usb_anchor *anchor, unsigned int timeout); +/** + * usb_urb_dir_in - check if an URB describes an IN transfer + * @urb: URB to be checked + * + * Returns 1 if @urb describes an IN transfer (device-to-host), + * otherwise 0. + */ +static inline int usb_urb_dir_in(struct urb *urb) +{ + return (urb->transfer_flags & URB_DIR_MASK) != URB_DIR_OUT; +} + +/** + * usb_urb_dir_out - check if an URB describes an OUT transfer + * @urb: URB to be checked + * + * Returns 1 if @urb describes an OUT transfer (host-to-device), + * otherwise 0. + */ +static inline int usb_urb_dir_out(struct urb *urb) +{ + return (urb->transfer_flags & URB_DIR_MASK) == URB_DIR_OUT; +} + void *usb_buffer_alloc (struct usb_device *dev, size_t size, gfp_t mem_flags, dma_addr_t *dma); void usb_buffer_free (struct usb_device *dev, size_t size, -- cgit v1.2.3-70-g09d2 From 5e60a16139c2a48b9876b0ff910671eee5fb32ec Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 30 Jul 2007 17:07:21 -0400 Subject: USB: avoid using urb->pipe in usbcore This patch (as946) eliminates many of the uses of urb->pipe in usbcore. Unfortunately there will have to be a significant API change, affecting all USB drivers, before we can remove it entirely. This patch contents itself with changing only the interface to usb_buffer_map_sg() and friends: The pipe argument is replaced with a direction flag. That can be done easily because those routines get used in only one place. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 40 ++++++++++++++++++++++++---------------- drivers/usb/core/message.c | 14 ++++++++------ drivers/usb/core/usb.c | 19 +++++++++---------- include/linux/usb.h | 6 +++--- 4 files changed, 44 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index bcbaedc897d..739c5e0aa3b 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -635,9 +635,9 @@ static int rh_queue_status (struct usb_hcd *hcd, struct urb *urb) static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb) { - if (usb_pipeint (urb->pipe)) + if (usb_endpoint_xfer_int(&urb->ep->desc)) return rh_queue_status (hcd, urb); - if (usb_pipecontrol (urb->pipe)) + if (usb_endpoint_xfer_control(&urb->ep->desc)) return rh_call_control (hcd, urb); return -EINVAL; } @@ -651,7 +651,7 @@ static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) { unsigned long flags; - if (usb_pipeendpoint(urb->pipe) == 0) { /* Control URB */ + if (usb_endpoint_num(&urb->ep->desc) == 0) { /* Control URB */ ; /* Do nothing */ } else { /* Status URB */ @@ -918,7 +918,7 @@ static void urb_unlink(struct usb_hcd *hcd, struct urb *urb) spin_unlock_irqrestore(&hcd_urb_list_lock, flags); if (hcd->self.uses_dma && !is_root_hub(urb->dev)) { - if (usb_pipecontrol (urb->pipe) + if (usb_endpoint_xfer_control(&urb->ep->desc) && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) dma_unmap_single (hcd->self.controller, urb->setup_dma, sizeof (struct usb_ctrlrequest), @@ -1001,7 +1001,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) * unless it uses pio or talks to another transport. */ if (hcd->self.uses_dma) { - if (usb_pipecontrol (urb->pipe) + if (usb_endpoint_xfer_control(&urb->ep->desc) && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) urb->setup_dma = dma_map_single ( hcd->self.controller, @@ -1201,11 +1201,13 @@ rescan: spin_lock(&hcd_urb_list_lock); list_for_each_entry (urb, &ep->urb_list, urb_list) { int tmp; + int is_in; /* the urb may already have been unlinked */ if (urb->status != -EINPROGRESS) continue; usb_get_urb (urb); + is_in = usb_urb_dir_in(urb); spin_unlock(&hcd_urb_list_lock); spin_lock (&urb->lock); @@ -1216,19 +1218,25 @@ rescan: /* kick hcd unless it's already returning this */ if (tmp == -EINPROGRESS) { - tmp = urb->pipe; unlink1 (hcd, urb); dev_dbg (hcd->self.controller, - "shutdown urb %p pipe %08x ep%d%s%s\n", - urb, tmp, usb_pipeendpoint (tmp), - (tmp & USB_DIR_IN) ? "in" : "out", - ({ char *s; \ - switch (usb_pipetype (tmp)) { \ - case PIPE_CONTROL: s = ""; break; \ - case PIPE_BULK: s = "-bulk"; break; \ - case PIPE_INTERRUPT: s = "-intr"; break; \ - default: s = "-iso"; break; \ - }; s;})); + "shutdown urb %p ep%d%s%s\n", + urb, usb_endpoint_num(&ep->desc), + is_in ? "in" : "out", + ({ char *s; + + switch (usb_endpoint_type(&ep->desc)) { + case USB_ENDPOINT_XFER_CONTROL: + s = ""; break; + case USB_ENDPOINT_XFER_BULK: + s = "-bulk"; break; + case USB_ENDPOINT_XFER_INT: + s = "-intr"; break; + default: + s = "-iso"; break; + }; + s; + })); } usb_put_urb (urb); diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 0d618647758..a26a7292b61 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -59,8 +59,8 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length) dev_dbg(&urb->dev->dev, "%s timed out on ep%d%s len=%d/%d\n", current->comm, - usb_pipeendpoint(urb->pipe), - usb_pipein(urb->pipe) ? "in" : "out", + usb_endpoint_num(&urb->ep->desc), + usb_urb_dir_in(urb) ? "in" : "out", urb->actual_length, urb->transfer_buffer_length); } else @@ -250,7 +250,8 @@ static void sg_clean (struct usb_sg_request *io) io->urbs = NULL; } if (io->dev->dev.dma_mask != NULL) - usb_buffer_unmap_sg (io->dev, io->pipe, io->sg, io->nents); + usb_buffer_unmap_sg (io->dev, usb_pipein(io->pipe), + io->sg, io->nents); io->dev = NULL; } @@ -278,8 +279,8 @@ static void sg_complete (struct urb *urb) dev_err (io->dev->bus->controller, "dev %s ep%d%s scatterlist error %d/%d\n", io->dev->devpath, - usb_pipeendpoint (urb->pipe), - usb_pipein (urb->pipe) ? "in" : "out", + usb_endpoint_num(&urb->ep->desc), + usb_urb_dir_in(urb) ? "in" : "out", status, io->status); // BUG (); } @@ -379,7 +380,8 @@ int usb_sg_init ( */ dma = (dev->dev.dma_mask != NULL); if (dma) - io->entries = usb_buffer_map_sg (dev, pipe, sg, nents); + io->entries = usb_buffer_map_sg(dev, usb_pipein(pipe), + sg, nents); else io->entries = nents; diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index d3c68d8eafb..67e2e582e46 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -748,7 +748,7 @@ void usb_buffer_unmap(struct urb *urb) /** * usb_buffer_map_sg - create scatterlist DMA mapping(s) for an endpoint * @dev: device to which the scatterlist will be mapped - * @pipe: endpoint defining the mapping direction + * @is_in: mapping transfer direction * @sg: the scatterlist to map * @nents: the number of entries in the scatterlist * @@ -771,14 +771,13 @@ void usb_buffer_unmap(struct urb *urb) * * Reverse the effect of this call with usb_buffer_unmap_sg(). */ -int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe, +int usb_buffer_map_sg(const struct usb_device *dev, int is_in, struct scatterlist *sg, int nents) { struct usb_bus *bus; struct device *controller; if (!dev - || usb_pipecontrol(pipe) || !(bus = dev->bus) || !(controller = bus->controller) || !controller->dma_mask) @@ -786,7 +785,7 @@ int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe, // FIXME generic api broken like pci, can't report errors return dma_map_sg(controller, sg, nents, - usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); + is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } /* XXX DISABLED, no users currently. If you wish to re-enable this @@ -799,14 +798,14 @@ int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe, /** * usb_buffer_dmasync_sg - synchronize DMA and CPU view of scatterlist buffer(s) * @dev: device to which the scatterlist will be mapped - * @pipe: endpoint defining the mapping direction + * @is_in: mapping transfer direction * @sg: the scatterlist to synchronize * @n_hw_ents: the positive return value from usb_buffer_map_sg * * Use this when you are re-using a scatterlist's data buffers for * another USB request. */ -void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe, +void usb_buffer_dmasync_sg(const struct usb_device *dev, int is_in, struct scatterlist *sg, int n_hw_ents) { struct usb_bus *bus; @@ -819,20 +818,20 @@ void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe, return; dma_sync_sg(controller, sg, n_hw_ents, - usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); + is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } #endif /** * usb_buffer_unmap_sg - free DMA mapping(s) for a scatterlist * @dev: device to which the scatterlist will be mapped - * @pipe: endpoint defining the mapping direction + * @is_in: mapping transfer direction * @sg: the scatterlist to unmap * @n_hw_ents: the positive return value from usb_buffer_map_sg * * Reverses the effect of usb_buffer_map_sg(). */ -void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe, +void usb_buffer_unmap_sg(const struct usb_device *dev, int is_in, struct scatterlist *sg, int n_hw_ents) { struct usb_bus *bus; @@ -845,7 +844,7 @@ void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe, return; dma_unmap_sg(controller, sg, n_hw_ents, - usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); + is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } /* format to disable USB on kernel command line is: nousb */ diff --git a/include/linux/usb.h b/include/linux/usb.h index 9d08f5a5ba7..019ae963a9f 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -1422,13 +1422,13 @@ void usb_buffer_unmap (struct urb *urb); #endif struct scatterlist; -int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe, +int usb_buffer_map_sg(const struct usb_device *dev, int is_in, struct scatterlist *sg, int nents); #if 0 -void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe, +void usb_buffer_dmasync_sg(const struct usb_device *dev, int is_in, struct scatterlist *sg, int n_hw_ents); #endif -void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe, +void usb_buffer_unmap_sg(const struct usb_device *dev, int is_in, struct scatterlist *sg, int n_hw_ents); /*-------------------------------------------------------------------* -- cgit v1.2.3-70-g09d2 From 4326ed0be93574dac5b5e475713015159108bd88 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 30 Jul 2007 17:08:43 -0400 Subject: USB: address-0 handling during device initialization This patch (as947) changes the device initialization and enumeration code in hub.c; now udev->devnum will be set to 0 while the device is being accessed at address 0. Until now this wasn't needed because the address value was passed as part of urb->pipe; without that field the device address must be stored elsewhere. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 21 +++++++++++++-------- drivers/usb/core/urb.c | 4 +--- 2 files changed, 14 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index c8a01f66df7..34be27a6cbb 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1481,6 +1481,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1, case 0: /* TRSTRCY = 10 ms; plus some extra */ msleep(10 + 40); + udev->devnum = 0; /* Device now at address 0 */ /* FALL THROUGH */ case -ENOTCONN: case -ENODEV: @@ -2005,20 +2006,21 @@ static void ep0_reinit(struct usb_device *udev) #define usb_sndaddr0pipe() (PIPE_CONTROL << 30) #define usb_rcvaddr0pipe() ((PIPE_CONTROL << 30) | USB_DIR_IN) -static int hub_set_address(struct usb_device *udev) +static int hub_set_address(struct usb_device *udev, int devnum) { int retval; - if (udev->devnum == 0) + if (devnum <= 1) return -EINVAL; if (udev->state == USB_STATE_ADDRESS) return 0; if (udev->state != USB_STATE_DEFAULT) return -EINVAL; retval = usb_control_msg(udev, usb_sndaddr0pipe(), - USB_REQ_SET_ADDRESS, 0, udev->devnum, 0, + USB_REQ_SET_ADDRESS, 0, devnum, 0, NULL, 0, USB_CTRL_SET_TIMEOUT); if (retval == 0) { + udev->devnum = devnum; /* Device now using proper address */ usb_set_device_state(udev, USB_STATE_ADDRESS); ep0_reinit(udev); } @@ -2045,6 +2047,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, unsigned delay = HUB_SHORT_RESET_TIME; enum usb_device_speed oldspeed = udev->speed; char *speed, *type; + int devnum = udev->devnum; /* root hub ports have a slightly longer reset period * (from USB 2.0 spec, section 7.1.7.5) @@ -2074,7 +2077,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, goto fail; } oldspeed = udev->speed; - + /* USB 2.0 section 5.5.3 talks about ep0 maxpacket ... * it's fixed size except for full speed devices. * For Wireless USB devices, ep0 max packet is always 512 (tho @@ -2115,7 +2118,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, dev_info (&udev->dev, "%s %s speed %sUSB device using %s and address %d\n", (udev->config) ? "reset" : "new", speed, type, - udev->bus->controller->driver->name, udev->devnum); + udev->bus->controller->driver->name, devnum); /* Set up TT records, if needed */ if (hdev->tt) { @@ -2202,7 +2205,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, } for (j = 0; j < SET_ADDRESS_TRIES; ++j) { - retval = hub_set_address(udev); + retval = hub_set_address(udev, devnum); if (retval >= 0) break; msleep(200); @@ -2210,7 +2213,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, if (retval < 0) { dev_err(&udev->dev, "device not accepting address %d, error %d\n", - udev->devnum, retval); + devnum, retval); goto fail; } @@ -2263,8 +2266,10 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, retval = 0; fail: - if (retval) + if (retval) { hub_port_disable(hub, port1, 0); + udev->devnum = devnum; /* for disconnect processing */ + } mutex_unlock(&usb_address0_mutex); return retval; } diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 1a64a6a850f..1acca8696bc 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -284,9 +284,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) if (!urb || urb->hcpriv || !urb->complete) return -EINVAL; - if (!(dev = urb->dev) || - (dev->state < USB_STATE_DEFAULT) || - (!dev->bus) || (dev->devnum <= 0)) + if (!(dev = urb->dev) || dev->state < USB_STATE_DEFAULT) return -ENODEV; if (dev->bus->controller->power.power_state.event != PM_EVENT_ON || dev->state == USB_STATE_SUSPENDED) -- cgit v1.2.3-70-g09d2 From 93cf9b909efb773f74b5d87659d41f957ccbce7e Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 30 Jul 2007 17:09:28 -0400 Subject: USB: avoid urb->pipe in usbfs This patch (as948) removes most of the references to urb->pipe from the usbfs routines in devio.c. The one tricky aspect is in snoop_urb(), which can be called before the URB is submitted and which uses usb_urb_dir_in(). For this to work properly, the URB's direction flag must be set manually in proc_do_submiturb(). The patch also fixes a minor bug; the wValue, wIndex, and wLength fields were snooped in proc_do_submiturb() without conversion from le16 to CPU-byte-ordering. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 69 ++++++++++++++++++++++++++++-------------------- 1 file changed, 41 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 927a181120a..b9f1edd6af5 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -289,10 +289,8 @@ static void snoop_urb(struct urb *urb, void __user *userurb) if (!usbfs_snoop) return; - if (urb->pipe & USB_DIR_IN) - dev_info(&urb->dev->dev, "direction=IN\n"); - else - dev_info(&urb->dev->dev, "direction=OUT\n"); + dev_info(&urb->dev->dev, "direction=%s\n", + usb_urb_dir_in(urb) ? "IN" : "OUT"); dev_info(&urb->dev->dev, "userurb=%p\n", userurb); dev_info(&urb->dev->dev, "transfer_buffer_length=%d\n", urb->transfer_buffer_length); @@ -910,6 +908,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, struct usb_ctrlrequest *dr = NULL; unsigned int u, totlen, isofrmlen; int ret, ifnum = -1; + int is_in; if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_SHORT_NOT_OK| URB_NO_FSBR|URB_ZERO_PACKET)) @@ -924,16 +923,18 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, if ((ret = checkintf(ps, ifnum))) return ret; } - if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0) - ep = ps->dev->ep_in [uurb->endpoint & USB_ENDPOINT_NUMBER_MASK]; - else - ep = ps->dev->ep_out [uurb->endpoint & USB_ENDPOINT_NUMBER_MASK]; + if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0) { + is_in = 1; + ep = ps->dev->ep_in[uurb->endpoint & USB_ENDPOINT_NUMBER_MASK]; + } else { + is_in = 0; + ep = ps->dev->ep_out[uurb->endpoint & USB_ENDPOINT_NUMBER_MASK]; + } if (!ep) return -ENOENT; switch(uurb->type) { case USBDEVFS_URB_TYPE_CONTROL: - if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - != USB_ENDPOINT_XFER_CONTROL) + if (!usb_endpoint_xfer_control(&ep->desc)) return -EINVAL; /* min 8 byte setup packet, max 8 byte setup plus an arbitrary data stage */ if (uurb->buffer_length < 8 || uurb->buffer_length > (8 + MAX_USBFS_BUFFER_SIZE)) @@ -952,23 +953,32 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, kfree(dr); return ret; } - uurb->endpoint = (uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) | (dr->bRequestType & USB_ENDPOINT_DIR_MASK); uurb->number_of_packets = 0; uurb->buffer_length = le16_to_cpup(&dr->wLength); uurb->buffer += 8; - if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) { + if ((dr->bRequestType & USB_DIR_IN) && uurb->buffer_length) { + is_in = 1; + uurb->endpoint |= USB_DIR_IN; + } else { + is_in = 0; + uurb->endpoint &= ~USB_DIR_IN; + } + if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ, + uurb->buffer, uurb->buffer_length)) { kfree(dr); return -EFAULT; } snoop(&ps->dev->dev, "control urb: bRequest=%02x " "bRrequestType=%02x wValue=%04x " "wIndex=%04x wLength=%04x\n", - dr->bRequest, dr->bRequestType, dr->wValue, - dr->wIndex, dr->wLength); + dr->bRequest, dr->bRequestType, + __le16_to_cpup(&dr->wValue), + __le16_to_cpup(&dr->wIndex), + __le16_to_cpup(&dr->wLength)); break; case USBDEVFS_URB_TYPE_BULK: - switch (ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { + switch (usb_endpoint_type(&ep->desc)) { case USB_ENDPOINT_XFER_CONTROL: case USB_ENDPOINT_XFER_ISOC: return -EINVAL; @@ -977,7 +987,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, uurb->number_of_packets = 0; if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE) return -EINVAL; - if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) + if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ, + uurb->buffer, uurb->buffer_length)) return -EFAULT; snoop(&ps->dev->dev, "bulk urb\n"); break; @@ -986,8 +997,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, /* arbitrary limit */ if (uurb->number_of_packets < 1 || uurb->number_of_packets > 128) return -EINVAL; - if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - != USB_ENDPOINT_XFER_ISOC) + if (!usb_endpoint_xfer_isoc(&ep->desc)) return -EINVAL; isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * uurb->number_of_packets; if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL))) @@ -1014,12 +1024,12 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, case USBDEVFS_URB_TYPE_INTERRUPT: uurb->number_of_packets = 0; - if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - != USB_ENDPOINT_XFER_INT) + if (!usb_endpoint_xfer_int(&ep->desc)) return -EINVAL; if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE) return -EINVAL; - if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) + if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ, + uurb->buffer, uurb->buffer_length)) return -EFAULT; snoop(&ps->dev->dev, "interrupt urb\n"); break; @@ -1039,8 +1049,11 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, return -ENOMEM; } as->urb->dev = ps->dev; - as->urb->pipe = (uurb->type << 30) | __create_pipe(ps->dev, uurb->endpoint & 0xf) | (uurb->endpoint & USB_DIR_IN); - as->urb->transfer_flags = uurb->flags; + as->urb->pipe = (uurb->type << 30) | + __create_pipe(ps->dev, uurb->endpoint & 0xf) | + (uurb->endpoint & USB_DIR_IN); + as->urb->transfer_flags = uurb->flags | + (is_in ? URB_DIR_IN : URB_DIR_OUT); as->urb->transfer_buffer_length = uurb->buffer_length; as->urb->setup_packet = (unsigned char*)dr; as->urb->start_frame = uurb->start_frame; @@ -1070,13 +1083,13 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, as->uid = current->uid; as->euid = current->euid; security_task_getsecid(current, &as->secid); - if (!(uurb->endpoint & USB_DIR_IN)) { - if (copy_from_user(as->urb->transfer_buffer, uurb->buffer, as->urb->transfer_buffer_length)) { + if (!is_in) { + if (copy_from_user(as->urb->transfer_buffer, uurb->buffer, + as->urb->transfer_buffer_length)) { free_async(as); return -EFAULT; } } - snoop(&as->urb->dev->dev, "submit urb\n"); snoop_urb(as->urb, as->userurb); async_newpending(as); if ((ret = usb_submit_urb(as->urb, GFP_KERNEL))) { @@ -1126,7 +1139,7 @@ static int processcompl(struct async *as, void __user * __user *arg) if (put_user(urb->error_count, &userurb->error_count)) return -EFAULT; - if (usb_pipeisoc(urb->pipe)) { + if (usb_endpoint_xfer_isoc(&urb->ep->desc)) { for (i = 0; i < urb->number_of_packets; i++) { if (put_user(urb->iso_frame_desc[i].actual_length, &userurb->iso_frame_desc[i].actual_length)) @@ -1240,7 +1253,7 @@ static int processcompl_compat(struct async *as, void __user * __user *arg) if (put_user(urb->error_count, &userurb->error_count)) return -EFAULT; - if (usb_pipeisoc(urb->pipe)) { + if (usb_endpoint_xfer_isoc(&urb->ep->desc)) { for (i = 0; i < urb->number_of_packets; i++) { if (put_user(urb->iso_frame_desc[i].actual_length, &userurb->iso_frame_desc[i].actual_length)) -- cgit v1.2.3-70-g09d2 From 18ea5d00d05fa6300606f0711748016c95fb26dc Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 30 Jul 2007 17:10:36 -0400 Subject: USB: avoid urb->pipe in usbmon This patch (as949) changes the usbmon driver to use the new urb->ep field rather than urb->pipe. Signed-off-by: Alan Stern Cc: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman --- drivers/usb/mon/mon_bin.c | 44 +++++++++++++++++++++++++++-------- drivers/usb/mon/mon_main.c | 4 ++-- drivers/usb/mon/mon_text.c | 58 +++++++++++++++++++++++++--------------------- 3 files changed, 68 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c index c03dfd7a9d3..0b0d77c669d 100644 --- a/drivers/usb/mon/mon_bin.c +++ b/drivers/usb/mon/mon_bin.c @@ -354,7 +354,7 @@ static inline char mon_bin_get_setup(unsigned char *setupb, const struct urb *urb, char ev_type) { - if (!usb_pipecontrol(urb->pipe) || ev_type != 'S') + if (!usb_endpoint_xfer_control(&urb->ep->desc) || ev_type != 'S') return '-'; if (urb->dev->bus->uses_dma && @@ -410,7 +410,7 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, if (length >= rp->b_size/5) length = rp->b_size/5; - if (usb_pipein(urb->pipe)) { + if (usb_urb_dir_in(urb)) { if (ev_type == 'S') { length = 0; data_tag = '<'; @@ -440,10 +440,22 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, */ memset(ep, 0, PKT_SIZE); ep->type = ev_type; - ep->xfer_type = usb_pipetype(urb->pipe); - /* We use the fact that usb_pipein() returns 0x80 */ - ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe); - ep->devnum = usb_pipedevice(urb->pipe); + switch (usb_endpoint_type(&urb->ep->desc)) { + case USB_ENDPOINT_XFER_CONTROL: + ep->xfer_type = PIPE_CONTROL; + break; + case USB_ENDPOINT_XFER_BULK: + ep->xfer_type = PIPE_BULK; + break; + case USB_ENDPOINT_XFER_INT: + ep->xfer_type = PIPE_INTERRUPT; + break; + default: + ep->xfer_type = PIPE_ISOCHRONOUS; + break; + } + ep->epnum = urb->ep->desc.bEndpointAddress; + ep->devnum = urb->dev->devnum; ep->busnum = urb->dev->bus->busnum; ep->id = (unsigned long) urb; ep->ts_sec = ts.tv_sec; @@ -500,10 +512,22 @@ static void mon_bin_error(void *data, struct urb *urb, int error) memset(ep, 0, PKT_SIZE); ep->type = 'E'; - ep->xfer_type = usb_pipetype(urb->pipe); - /* We use the fact that usb_pipein() returns 0x80 */ - ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe); - ep->devnum = usb_pipedevice(urb->pipe); + switch (usb_endpoint_type(&urb->ep->desc)) { + case USB_ENDPOINT_XFER_CONTROL: + ep->xfer_type = PIPE_CONTROL; + break; + case USB_ENDPOINT_XFER_BULK: + ep->xfer_type = PIPE_BULK; + break; + case USB_ENDPOINT_XFER_INT: + ep->xfer_type = PIPE_INTERRUPT; + break; + default: + ep->xfer_type = PIPE_ISOCHRONOUS; + break; + } + ep->epnum = urb->ep->desc.bEndpointAddress; + ep->devnum = urb->dev->devnum; ep->busnum = urb->dev->bus->busnum; ep->id = (unsigned long) urb; ep->status = error; diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c index ce61d8b0fd8..e58f761d060 100644 --- a/drivers/usb/mon/mon_main.c +++ b/drivers/usb/mon/mon_main.c @@ -154,8 +154,8 @@ static void mon_complete(struct usb_bus *ubus, struct urb *urb) * This should not happen. * At this point we do not even know the bus number... */ - printk(KERN_ERR TAG ": Null mon bus in URB, pipe 0x%x\n", - urb->pipe); + printk(KERN_ERR TAG ": Null mon bus in URB, address %p\n", + urb); return; } diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c index 8f27a9e1c36..9d0070ceef5 100644 --- a/drivers/usb/mon/mon_text.c +++ b/drivers/usb/mon/mon_text.c @@ -50,10 +50,12 @@ struct mon_iso_desc { struct mon_event_text { struct list_head e_link; int type; /* submit, complete, etc. */ - unsigned int pipe; /* Pipe */ unsigned long id; /* From pointer, most of the time */ unsigned int tstamp; + int xfertype; int busnum; + int devnum; + int epnum; int length; /* Depends on type: xfer length or act length */ int status; int interval; @@ -61,6 +63,7 @@ struct mon_event_text { int error_count; char setup_flag; char data_flag; + char is_in; int numdesc; /* Full number */ struct mon_iso_desc isodesc[ISODESC_MAX]; unsigned char setup[SETUP_MAX]; @@ -121,7 +124,7 @@ static inline char mon_text_get_setup(struct mon_event_text *ep, struct urb *urb, char ev_type, struct mon_bus *mbus) { - if (!usb_pipecontrol(urb->pipe) || ev_type != 'S') + if (ep->xfertype != USB_ENDPOINT_XFER_CONTROL || ev_type != 'S') return '-'; if (urb->dev->bus->uses_dma && @@ -138,14 +141,12 @@ static inline char mon_text_get_setup(struct mon_event_text *ep, static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb, int len, char ev_type, struct mon_bus *mbus) { - int pipe = urb->pipe; - if (len <= 0) return 'L'; if (len >= DATA_MAX) len = DATA_MAX; - if (usb_pipein(pipe)) { + if (ep->is_in) { if (ev_type != 'C') return '<'; } else { @@ -203,24 +204,28 @@ static void mon_text_event(struct mon_reader_text *rp, struct urb *urb, } ep->type = ev_type; - ep->pipe = urb->pipe; ep->id = (unsigned long) urb; ep->busnum = urb->dev->bus->busnum; + ep->devnum = urb->dev->devnum; + ep->epnum = usb_endpoint_num(&urb->ep->desc); + ep->xfertype = usb_endpoint_type(&urb->ep->desc); + ep->is_in = usb_urb_dir_in(urb); ep->tstamp = stamp; ep->length = (ev_type == 'S') ? urb->transfer_buffer_length : urb->actual_length; /* Collecting status makes debugging sense for submits, too */ ep->status = urb->status; - if (usb_pipeint(urb->pipe)) { + if (ep->xfertype == USB_ENDPOINT_XFER_INT) { ep->interval = urb->interval; - } else if (usb_pipeisoc(urb->pipe)) { + } else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) { ep->interval = urb->interval; ep->start_frame = urb->start_frame; ep->error_count = urb->error_count; } ep->numdesc = urb->number_of_packets; - if (usb_pipeisoc(urb->pipe) && urb->number_of_packets > 0) { + if (ep->xfertype == USB_ENDPOINT_XFER_ISOC && + urb->number_of_packets > 0) { if ((ndesc = urb->number_of_packets) > ISODESC_MAX) ndesc = ISODESC_MAX; fp = urb->iso_frame_desc; @@ -268,9 +273,12 @@ static void mon_text_error(void *data, struct urb *urb, int error) } ep->type = 'E'; - ep->pipe = urb->pipe; ep->id = (unsigned long) urb; ep->busnum = 0; + ep->devnum = urb->dev->devnum; + ep->epnum = usb_endpoint_num(&urb->ep->desc); + ep->xfertype = usb_endpoint_type(&urb->ep->desc); + ep->is_in = usb_urb_dir_in(urb); ep->tstamp = 0; ep->length = 0; ep->status = error; @@ -413,10 +421,10 @@ static ssize_t mon_text_read_u(struct file *file, char __user *buf, mon_text_read_head_u(rp, &ptr, ep); if (ep->type == 'E') { mon_text_read_statset(rp, &ptr, ep); - } else if (usb_pipeisoc(ep->pipe)) { + } else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) { mon_text_read_isostat(rp, &ptr, ep); mon_text_read_isodesc(rp, &ptr, ep); - } else if (usb_pipeint(ep->pipe)) { + } else if (ep->xfertype == USB_ENDPOINT_XFER_INT) { mon_text_read_intstat(rp, &ptr, ep); } else { mon_text_read_statset(rp, &ptr, ep); @@ -468,18 +476,17 @@ static void mon_text_read_head_t(struct mon_reader_text *rp, { char udir, utype; - udir = usb_pipein(ep->pipe) ? 'i' : 'o'; - switch (usb_pipetype(ep->pipe)) { - case PIPE_ISOCHRONOUS: utype = 'Z'; break; - case PIPE_INTERRUPT: utype = 'I'; break; - case PIPE_CONTROL: utype = 'C'; break; + udir = (ep->is_in ? 'i' : 'o'); + switch (ep->xfertype) { + case USB_ENDPOINT_XFER_ISOC: utype = 'Z'; break; + case USB_ENDPOINT_XFER_INT: utype = 'I'; break; + case USB_ENDPOINT_XFER_CONTROL: utype = 'C'; break; default: /* PIPE_BULK */ utype = 'B'; } p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, "%lx %u %c %c%c:%03u:%02u", ep->id, ep->tstamp, ep->type, - utype, udir, - usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe)); + utype, udir, ep->devnum, ep->epnum); } static void mon_text_read_head_u(struct mon_reader_text *rp, @@ -487,18 +494,17 @@ static void mon_text_read_head_u(struct mon_reader_text *rp, { char udir, utype; - udir = usb_pipein(ep->pipe) ? 'i' : 'o'; - switch (usb_pipetype(ep->pipe)) { - case PIPE_ISOCHRONOUS: utype = 'Z'; break; - case PIPE_INTERRUPT: utype = 'I'; break; - case PIPE_CONTROL: utype = 'C'; break; + udir = (ep->is_in ? 'i' : 'o'); + switch (ep->xfertype) { + case USB_ENDPOINT_XFER_ISOC: utype = 'Z'; break; + case USB_ENDPOINT_XFER_INT: utype = 'I'; break; + case USB_ENDPOINT_XFER_CONTROL: utype = 'C'; break; default: /* PIPE_BULK */ utype = 'B'; } p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, "%lx %u %c %c%c:%d:%03u:%u", ep->id, ep->tstamp, ep->type, - utype, udir, - ep->busnum, usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe)); + utype, udir, ep->busnum, ep->devnum, ep->epnum); } static void mon_text_read_statset(struct mon_reader_text *rp, -- cgit v1.2.3-70-g09d2 From d617bc83ff48ebf0df253605529d8b3bef15773a Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 2 Aug 2007 15:04:52 -0400 Subject: USB: cleanup for previous patches This patch (as951) cleans up a few loose ends from earlier patches. Redundant checks for non-NULL urb->dev are removed, as are checks of urb->dev->bus (which can never be NULL). Conversely, a check for non-NULL urb->ep is added to the unlink paths. A homegrown round-down-to-power-of-2 loop is simplified by using the ilog2 routine. The comparison in usb_urb_dir_in() is made more transparent. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 5 ----- drivers/usb/core/urb.c | 13 +++++++------ include/linux/usb.h | 2 +- 3 files changed, 8 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 739c5e0aa3b..47a055a2acf 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1074,11 +1074,6 @@ int usb_hcd_unlink_urb (struct urb *urb, int status) struct list_head *tmp; int retval; - if (!urb) - return -EINVAL; - if (!urb->dev || !urb->dev->bus) - return -ENODEV; - /* * we contend for urb->status with the hcd core, * which changes it while returning the urb. diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 1acca8696bc..19f5f66c273 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include "hcd.h" @@ -441,10 +442,8 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) default: return -EINVAL; } - /* power of two? */ - while (max > urb->interval) - max >>= 1; - urb->interval = max; + /* Round down to a power of 2, no more than max */ + urb->interval = min(max, 1 << ilog2(urb->interval)); } return usb_hcd_submit_urb(urb, mem_flags); @@ -513,8 +512,10 @@ int usb_unlink_urb(struct urb *urb) { if (!urb) return -EINVAL; - if (!(urb->dev && urb->dev->bus)) + if (!urb->dev) return -ENODEV; + if (!urb->ep) + return -EIDRM; return usb_hcd_unlink_urb(urb, -ECONNRESET); } @@ -541,7 +542,7 @@ int usb_unlink_urb(struct urb *urb) void usb_kill_urb(struct urb *urb) { might_sleep(); - if (!(urb && urb->dev && urb->dev->bus)) + if (!(urb && urb->dev && urb->ep)) return; spin_lock_irq(&urb->lock); ++urb->reject; diff --git a/include/linux/usb.h b/include/linux/usb.h index 019ae963a9f..a51f34e8057 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -1395,7 +1395,7 @@ extern int usb_wait_anchor_empty_timeout(struct usb_anchor *anchor, */ static inline int usb_urb_dir_in(struct urb *urb) { - return (urb->transfer_flags & URB_DIR_MASK) != URB_DIR_OUT; + return (urb->transfer_flags & URB_DIR_MASK) == URB_DIR_IN; } /** -- cgit v1.2.3-70-g09d2 From 9439eb94b5c374d5b02699f8897fc43aa3603701 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 2 Aug 2007 15:05:45 -0400 Subject: USB: update spinlock usage for root-hub URBs This patch (as952) adjusts the spinlock usage in the root-hub emulation part of usbcore, to make it match more closely the pattern used by regular host controller drivers. To wit: The private lock (usb_hcd_root_hub_lock) is held throughout the important parts, and it is dropped temporarily without re-enabling interrupts around the call to usb_hcd_giveback_urb(). A nice side effect is that the code now avoids calling local_irq_save(), thereby becoming more RT-friendly. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 52 ++++++++++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 47a055a2acf..f8e7deb03ee 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -356,10 +356,11 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) const u8 *bufp = tbuf; int len = 0; int patch_wakeup = 0; - unsigned long flags; int status = 0; int n; + might_sleep(); + cmd = (struct usb_ctrlrequest *) urb->setup_packet; typeReq = (cmd->bRequestType << 8) | cmd->bRequest; wValue = le16_to_cpu (cmd->wValue); @@ -523,13 +524,21 @@ error: } /* any errors get returned through the urb completion */ - local_irq_save (flags); - spin_lock (&urb->lock); + spin_lock_irq(&hcd_root_hub_lock); + spin_lock(&urb->lock); if (urb->status == -EINPROGRESS) urb->status = status; - spin_unlock (&urb->lock); - usb_hcd_giveback_urb (hcd, urb); - local_irq_restore (flags); + spin_unlock(&urb->lock); + + /* This peculiar use of spinlocks echoes what real HC drivers do. + * Avoiding calls to local_irq_disable/enable makes the code + * RT-friendly. + */ + spin_unlock(&hcd_root_hub_lock); + usb_hcd_giveback_urb(hcd, urb); + spin_lock(&hcd_root_hub_lock); + + spin_unlock_irq(&hcd_root_hub_lock); return 0; } @@ -559,8 +568,7 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd) if (length > 0) { /* try to complete the status urb */ - local_irq_save (flags); - spin_lock(&hcd_root_hub_lock); + spin_lock_irqsave(&hcd_root_hub_lock, flags); urb = hcd->status_urb; if (urb) { spin_lock(&urb->lock); @@ -574,16 +582,16 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd) } else /* urb has been unlinked */ length = 0; spin_unlock(&urb->lock); + + spin_unlock(&hcd_root_hub_lock); + usb_hcd_giveback_urb(hcd, urb); + spin_lock(&hcd_root_hub_lock); } else length = 0; - spin_unlock(&hcd_root_hub_lock); - /* local irqs are always blocked in completions */ - if (length > 0) - usb_hcd_giveback_urb (hcd, urb); - else + if (length <= 0) hcd->poll_pending = 1; - local_irq_restore (flags); + spin_unlock_irqrestore(&hcd_root_hub_lock, flags); } /* The USB 2.0 spec says 256 ms. This is close enough and won't @@ -651,25 +659,23 @@ static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) { unsigned long flags; + spin_lock_irqsave(&hcd_root_hub_lock, flags); if (usb_endpoint_num(&urb->ep->desc) == 0) { /* Control URB */ ; /* Do nothing */ } else { /* Status URB */ if (!hcd->uses_new_polling) del_timer (&hcd->rh_timer); - local_irq_save (flags); - spin_lock (&hcd_root_hub_lock); if (urb == hcd->status_urb) { hcd->status_urb = NULL; urb->hcpriv = NULL; - } else - urb = NULL; /* wasn't fully queued */ - spin_unlock (&hcd_root_hub_lock); - if (urb) - usb_hcd_giveback_urb (hcd, urb); - local_irq_restore (flags); - } + spin_unlock(&hcd_root_hub_lock); + usb_hcd_giveback_urb(hcd, urb); + spin_lock(&hcd_root_hub_lock); + } + } + spin_unlock_irqrestore(&hcd_root_hub_lock, flags); return 0; } -- cgit v1.2.3-70-g09d2 From 9a9bf406df3ce238089d14f4cb41157ca56d8ad3 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 2 Aug 2007 15:06:54 -0400 Subject: USB: separate out endpoint queue management and DMA mapping routines This patch (as953) separates out three key portions from usb_hcd_submit_urb(), usb_hcd_unlink_urb(), and usb_hcd_giveback_urb() and puts them in separate functions of their own. In the next patch, these functions will be called directly by host controller drivers while holding their private spinlocks, which will remove the possibility of some unpleasant races. The code responsible for mapping and unmapping DMA buffers is also placed into a couple of separate subroutines, for the sake of cleanliness and consistency. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 316 ++++++++++++++++++++++++++----------------------- 1 file changed, 166 insertions(+), 150 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index f8e7deb03ee..eb212178826 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -914,99 +914,117 @@ EXPORT_SYMBOL (usb_calc_bus_time); /*-------------------------------------------------------------------------*/ -static void urb_unlink(struct usb_hcd *hcd, struct urb *urb) +static int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb) { - unsigned long flags; + unsigned long flags; + int rc = 0; - /* clear all state linking urb to this dev (and hcd) */ spin_lock_irqsave(&hcd_urb_list_lock, flags); - list_del_init (&urb->urb_list); - spin_unlock_irqrestore(&hcd_urb_list_lock, flags); - if (hcd->self.uses_dma && !is_root_hub(urb->dev)) { - if (usb_endpoint_xfer_control(&urb->ep->desc) - && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) - dma_unmap_single (hcd->self.controller, urb->setup_dma, - sizeof (struct usb_ctrlrequest), - DMA_TO_DEVICE); - if (urb->transfer_buffer_length != 0 - && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) - dma_unmap_single (hcd->self.controller, - urb->transfer_dma, - urb->transfer_buffer_length, - usb_urb_dir_in(urb) - ? DMA_FROM_DEVICE - : DMA_TO_DEVICE); + /* Check that the URB isn't being killed */ + if (unlikely(urb->reject)) { + rc = -EPERM; + goto done; } -} - -/* may be called in any context with a valid urb->dev usecount - * caller surrenders "ownership" of urb - * expects usb_submit_urb() to have sanity checked and conditioned all - * inputs in the urb - */ -int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) -{ - int status; - struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus); - unsigned long flags; - - if (!hcd) - return -ENODEV; - usbmon_urb_submit(&hcd->self, urb); + if (unlikely(!urb->ep->enabled)) { + rc = -ENOENT; + goto done; + } /* - * Atomically queue the urb, first to our records, then to the HCD. - * Access to urb->status is controlled by urb->lock ... changes on - * i/o completion (normal or fault) or unlinking. + * Check the host controller's state and add the URB to the + * endpoint's queue. */ - - // FIXME: verify that quiescing hc works right (RH cleans up) - - spin_lock_irqsave(&hcd_urb_list_lock, flags); - if (unlikely(!urb->ep->enabled)) - status = -ENOENT; - else if (unlikely (urb->reject)) - status = -EPERM; - else switch (hcd->state) { + switch (hcd->state) { case HC_STATE_RUNNING: case HC_STATE_RESUMING: - list_add_tail (&urb->urb_list, &urb->ep->urb_list); - status = 0; + list_add_tail(&urb->urb_list, &urb->ep->urb_list); break; default: - status = -ESHUTDOWN; - break; + rc = -ESHUTDOWN; + goto done; } + done: spin_unlock_irqrestore(&hcd_urb_list_lock, flags); - if (status) { - INIT_LIST_HEAD (&urb->urb_list); - usbmon_urb_submit_error(&hcd->self, urb, status); - return status; + return rc; +} + +static int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb, + int status) +{ + unsigned long flags; + struct list_head *tmp; + int rc = 0; + + /* + * we contend for urb->status with the hcd core, + * which changes it while returning the urb. + * + * Caller guaranteed that the urb pointer hasn't been freed, and + * that it was submitted. But as a rule it can't know whether or + * not it's already been unlinked ... so we respect the reversed + * lock sequence needed for the usb_hcd_giveback_urb() code paths + * (urb lock, then hcd_urb_list_lock) in case some other CPU is now + * unlinking it. + */ + spin_lock_irqsave(&urb->lock, flags); + spin_lock(&hcd_urb_list_lock); + + /* insist the urb is still queued */ + list_for_each(tmp, &urb->ep->urb_list) { + if (tmp == &urb->urb_list) + break; + } + if (tmp != &urb->urb_list) { + rc = -EIDRM; + goto done; } - /* increment urb's reference count as part of giving it to the HCD - * (which now controls it). HCD guarantees that it either returns - * an error or calls giveback(), but not both. + /* Any status except -EINPROGRESS means something already started to + * unlink this URB from the hardware. So there's no more work to do. */ - urb = usb_get_urb (urb); - atomic_inc (&urb->use_count); - - if (is_root_hub(urb->dev)) { - /* NOTE: requirement on hub callers (usbfs and the hub - * driver, for now) that URBs' urb->transfer_buffer be - * valid and usb_buffer_{sync,unmap}() not be needed, since - * they could clobber root hub response data. - */ - status = rh_urb_enqueue (hcd, urb); + if (urb->status != -EINPROGRESS) { + rc = -EBUSY; goto done; } + urb->status = status; + + /* IRQ setup can easily be broken so that USB controllers + * never get completion IRQs ... maybe even the ones we need to + * finish unlinking the initial failed usb_set_address() + * or device descriptor fetch. + */ + if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags) && + !is_root_hub(urb->dev)) { + dev_warn(hcd->self.controller, "Unlink after no-IRQ? " + "Controller is probably using the wrong IRQ.\n"); + set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); + } + + done: + spin_unlock(&hcd_urb_list_lock); + spin_unlock_irqrestore (&urb->lock, flags); + return rc; +} + +static void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb) +{ + unsigned long flags; - /* lower level hcd code should use *_dma exclusively, + /* clear all state linking urb to this dev (and hcd) */ + spin_lock_irqsave(&hcd_urb_list_lock, flags); + list_del_init(&urb->urb_list); + spin_unlock_irqrestore(&hcd_urb_list_lock, flags); +} + +static void map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) +{ + /* Map the URB's buffers for DMA access. + * Lower level HCD code should use *_dma exclusively, * unless it uses pio or talks to another transport. */ - if (hcd->self.uses_dma) { + if (hcd->self.uses_dma && !is_root_hub(urb->dev)) { if (usb_endpoint_xfer_control(&urb->ep->desc) && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) urb->setup_dma = dma_map_single ( @@ -1024,16 +1042,73 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } +} - status = hcd->driver->urb_enqueue (hcd, urb->ep, urb, mem_flags); -done: - if (unlikely (status)) { - urb_unlink(hcd, urb); - atomic_dec (&urb->use_count); - if (urb->reject) - wake_up (&usb_kill_urb_queue); +static void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) +{ + if (hcd->self.uses_dma && !is_root_hub(urb->dev)) { + if (usb_endpoint_xfer_control(&urb->ep->desc) + && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) + dma_unmap_single(hcd->self.controller, urb->setup_dma, + sizeof(struct usb_ctrlrequest), + DMA_TO_DEVICE); + if (urb->transfer_buffer_length != 0 + && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) + dma_unmap_single(hcd->self.controller, + urb->transfer_dma, + urb->transfer_buffer_length, + usb_urb_dir_in(urb) + ? DMA_FROM_DEVICE + : DMA_TO_DEVICE); + } +} + +/*-------------------------------------------------------------------------*/ + +/* may be called in any context with a valid urb->dev usecount + * caller surrenders "ownership" of urb + * expects usb_submit_urb() to have sanity checked and conditioned all + * inputs in the urb + */ +int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) +{ + int status; + struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus); + + /* increment urb's reference count as part of giving it to the HCD + * (which will control it). HCD guarantees that it either returns + * an error or calls giveback(), but not both. + */ + usb_get_urb(urb); + atomic_inc(&urb->use_count); + usbmon_urb_submit(&hcd->self, urb); + + /* NOTE requirements on root-hub callers (usbfs and the hub + * driver, for now): URBs' urb->transfer_buffer must be + * valid and usb_buffer_{sync,unmap}() not be needed, since + * they could clobber root hub response data. Also, control + * URBs must be submitted in process context with interrupts + * enabled. + */ + status = usb_hcd_link_urb_to_ep(hcd, urb); + if (!status) { + map_urb_for_dma(hcd, urb); + if (is_root_hub(urb->dev)) + status = rh_urb_enqueue(hcd, urb); + else + status = hcd->driver->urb_enqueue(hcd, urb->ep, urb, + mem_flags); + } + + if (unlikely(status)) { usbmon_urb_submit_error(&hcd->self, urb, status); - usb_put_urb (urb); + unmap_urb_for_dma(hcd, urb); + usb_hcd_unlink_urb_from_ep(hcd, urb); + INIT_LIST_HEAD(&urb->urb_list); + atomic_dec(&urb->use_count); + if (urb->reject) + wake_up(&usb_kill_urb_queue); + usb_put_urb(urb); } return status; } @@ -1074,78 +1149,20 @@ unlink1 (struct usb_hcd *hcd, struct urb *urb) */ int usb_hcd_unlink_urb (struct urb *urb, int status) { - struct usb_hcd *hcd = NULL; - struct device *sys = NULL; - unsigned long flags; - struct list_head *tmp; - int retval; - - /* - * we contend for urb->status with the hcd core, - * which changes it while returning the urb. - * - * Caller guaranteed that the urb pointer hasn't been freed, and - * that it was submitted. But as a rule it can't know whether or - * not it's already been unlinked ... so we respect the reversed - * lock sequence needed for the usb_hcd_giveback_urb() code paths - * (urb lock, then hcd_urb_list_lock) in case some other CPU is now - * unlinking it. - */ - spin_lock_irqsave (&urb->lock, flags); - spin_lock(&hcd_urb_list_lock); + struct usb_hcd *hcd; + int retval; - sys = &urb->dev->dev; hcd = bus_to_hcd(urb->dev->bus); - if (hcd == NULL) { - retval = -ENODEV; - goto done; - } - - /* insist the urb is still queued */ - list_for_each(tmp, &urb->ep->urb_list) { - if (tmp == &urb->urb_list) - break; - } - if (tmp != &urb->urb_list) { - retval = -EIDRM; - goto done; - } - /* Any status except -EINPROGRESS means something already started to - * unlink this URB from the hardware. So there's no more work to do. - */ - if (urb->status != -EINPROGRESS) { - retval = -EBUSY; - goto done; - } + retval = usb_hcd_check_unlink_urb(hcd, urb, status); + if (!retval) + retval = unlink1(hcd, urb); - /* IRQ setup can easily be broken so that USB controllers - * never get completion IRQs ... maybe even the ones we need to - * finish unlinking the initial failed usb_set_address() - * or device descriptor fetch. - */ - if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags) && - !is_root_hub(urb->dev)) { - dev_warn (hcd->self.controller, "Unlink after no-IRQ? " - "Controller is probably using the wrong IRQ.\n"); - set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); - } - - urb->status = status; - - spin_unlock(&hcd_urb_list_lock); - spin_unlock_irqrestore (&urb->lock, flags); - - retval = unlink1 (hcd, urb); if (retval == 0) retval = -EINPROGRESS; - return retval; - -done: - spin_unlock(&hcd_urb_list_lock); - spin_unlock_irqrestore (&urb->lock, flags); - if (retval != -EIDRM && sys && sys->driver) - dev_dbg (sys, "hcd_unlink_urb %p fail %d\n", urb, retval); + else if (retval != -EIDRM) + dev_dbg(&urb->dev->dev, "hcd_unlink_urb %p fail %d\n", + urb, retval); return retval; } @@ -1165,7 +1182,8 @@ done: */ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb) { - urb_unlink(hcd, urb); + usb_hcd_unlink_urb_from_ep(hcd, urb); + unmap_urb_for_dma(hcd, urb); usbmon_urb_complete (&hcd->self, urb); usb_unanchor_urb(urb); @@ -1194,12 +1212,12 @@ void usb_hcd_endpoint_disable (struct usb_device *udev, struct usb_hcd *hcd; struct urb *urb; + might_sleep(); hcd = bus_to_hcd(udev->bus); - local_irq_disable (); /* ep is already gone from udev->ep_{in,out}[]; no more submits */ rescan: - spin_lock(&hcd_urb_list_lock); + spin_lock_irq(&hcd_urb_list_lock); list_for_each_entry (urb, &ep->urb_list, urb_list) { int tmp; int is_in; @@ -1244,13 +1262,11 @@ rescan: /* list contents may have changed */ goto rescan; } - spin_unlock(&hcd_urb_list_lock); - local_irq_enable (); + spin_unlock_irq(&hcd_urb_list_lock); /* synchronize with the hardware, so old configuration state * clears out immediately (and will be freed). */ - might_sleep (); if (hcd->driver->endpoint_disable) hcd->driver->endpoint_disable (hcd, ep); -- cgit v1.2.3-70-g09d2 From a1d534bb23e5c5c28fb6f6fb48588362df0907e8 Mon Sep 17 00:00:00 2001 From: Nico Erfurth Date: Thu, 2 Aug 2007 22:25:20 +0200 Subject: USB: Add drivers/usb/misc/iowarrior.c to the Makefile This patch adds the new iowarrior module to the Makefile in drivers/usb. Currently the module isn't build unless another driver from usb/misc is selected. Signed-off-by: Nico Erfurth Signed-off-by: Greg Kroah-Hartman --- drivers/usb/Makefile | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index ac49b15fa76..cce216517ca 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_USB_EMI26) += misc/ obj-$(CONFIG_USB_EMI62) += misc/ obj-$(CONFIG_USB_FTDI_ELAN) += misc/ obj-$(CONFIG_USB_IDMOUSE) += misc/ +obj-$(CONFIG_USB_IOWARRIOR) += misc/ obj-$(CONFIG_USB_LCD) += misc/ obj-$(CONFIG_USB_LD) += misc/ obj-$(CONFIG_USB_LED) += misc/ -- cgit v1.2.3-70-g09d2 From a4e3ef5597e26dad006544d38b9ab6ff42382b76 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Wed, 1 Aug 2007 23:58:22 -0700 Subject: USB: gadget: gadget_is_{dualspeed,otg} predicates and cleanup This adds two small inlines to the gadget stack, which will often evaluate to compile-time constants. That can help shrink object code and remove #ifdeffery. - gadget_is_dualspeed(), currently always a compile-time constant (depending on which controller is selected). - gadget_is_otg(), usually a compile time "false", but this is a runtime test if the platform enables OTG (since it's reasonable to populate boards with different USB sockets). It also updates two peripheral controller drivers to use these: - fsl_usb2_udc, mostly OTG-related bugfixes: non-OTG devices must follow the rules about drawing VBUS power, and OTG ones need to reject invalid SET_FEATURE requests. - omap_udc, just scrubbing a bit of #ifdeffery. And also gadgetfs, which lost some #ifdefs and moved to a more standard handling of DEBUG and VERBOSE_DEBUG. The main benefits come from patches which will follow. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/fsl_usb2_udc.c | 9 +++----- drivers/usb/gadget/inode.c | 44 ++++++++++++++++++--------------------- drivers/usb/gadget/omap_udc.c | 10 +++------ include/linux/usb_gadget.h | 33 +++++++++++++++++++++++++++++ 4 files changed, 59 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/fsl_usb2_udc.c b/drivers/usb/gadget/fsl_usb2_udc.c index d57bcfbc08a..89c768e2aed 100644 --- a/drivers/usb/gadget/fsl_usb2_udc.c +++ b/drivers/usb/gadget/fsl_usb2_udc.c @@ -1090,14 +1090,11 @@ static int fsl_vbus_session(struct usb_gadget *gadget, int is_active) */ static int fsl_vbus_draw(struct usb_gadget *gadget, unsigned mA) { -#ifdef CONFIG_USB_OTG struct fsl_udc *udc; udc = container_of(gadget, struct fsl_udc, gadget); - if (udc->transceiver) return otg_set_power(udc->transceiver, mA); -#endif return -ENOTSUPP; } @@ -1321,7 +1318,7 @@ static void setup_received_irq(struct fsl_udc *udc, | USB_TYPE_STANDARD)) { /* Note: The driver has not include OTG support yet. * This will be set when OTG support is added */ - if (!udc->gadget.is_otg) + if (!gadget_is_otg(udc->gadget)) break; else if (setup->bRequest == USB_DEVICE_B_HNP_ENABLE) udc->gadget.b_hnp_enable = 1; @@ -1330,6 +1327,8 @@ static void setup_received_irq(struct fsl_udc *udc, else if (setup->bRequest == USB_DEVICE_A_ALT_HNP_SUPPORT) udc->gadget.a_alt_hnp_support = 1; + else + break; rc = 0; } else break; @@ -1840,10 +1839,8 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) if (!driver || driver != udc_controller->driver || !driver->unbind) return -EINVAL; -#ifdef CONFIG_USB_OTG if (udc_controller->transceiver) (void)otg_set_peripheral(udc_controller->transceiver, 0); -#endif /* stop DR, disable intr */ dr_controller_stop(udc_controller); diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 173004f60fe..129eda5358f 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -20,8 +20,7 @@ */ -// #define DEBUG /* data to help fault diagnosis */ -// #define VERBOSE /* extra debug messages (success too) */ +/* #define VERBOSE_DEBUG */ #include #include @@ -253,7 +252,7 @@ static const char *CHIP; do { } while (0) #endif /* DEBUG */ -#ifdef VERBOSE +#ifdef VERBOSE_DEBUG #define VDEBUG DBG #else #define VDEBUG(dev,fmt,args...) \ @@ -1010,11 +1009,12 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr) /* assume that was SET_CONFIGURATION */ if (dev->current_config) { unsigned power; -#ifdef CONFIG_USB_GADGET_DUALSPEED - if (dev->gadget->speed == USB_SPEED_HIGH) + + if (gadget_is_dualspeed(dev->gadget) + && (dev->gadget->speed + == USB_SPEED_HIGH)) power = dev->hs_config->bMaxPower; else -#endif power = dev->config->bMaxPower; usb_gadget_vbus_draw(dev->gadget, 2 * power); } @@ -1355,24 +1355,21 @@ static int config_buf (struct dev_data *dev, u8 type, unsigned index) { int len; -#ifdef CONFIG_USB_GADGET_DUALSPEED - int hs; -#endif + int hs = 0; /* only one configuration */ if (index > 0) return -EINVAL; -#ifdef CONFIG_USB_GADGET_DUALSPEED - hs = (dev->gadget->speed == USB_SPEED_HIGH); - if (type == USB_DT_OTHER_SPEED_CONFIG) - hs = !hs; + if (gadget_is_dualspeed(dev->gadget)) { + hs = (dev->gadget->speed == USB_SPEED_HIGH); + if (type == USB_DT_OTHER_SPEED_CONFIG) + hs = !hs; + } if (hs) { dev->req->buf = dev->hs_config; len = le16_to_cpu(dev->hs_config->wTotalLength); - } else -#endif - { + } else { dev->req->buf = dev->config; len = le16_to_cpu(dev->config->wTotalLength); } @@ -1393,13 +1390,13 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) spin_lock (&dev->lock); dev->setup_abort = 0; if (dev->state == STATE_DEV_UNCONNECTED) { -#ifdef CONFIG_USB_GADGET_DUALSPEED - if (gadget->speed == USB_SPEED_HIGH && dev->hs_config == NULL) { + if (gadget_is_dualspeed(gadget) + && gadget->speed == USB_SPEED_HIGH + && dev->hs_config == NULL) { spin_unlock(&dev->lock); ERROR (dev, "no high speed config??\n"); return -EINVAL; } -#endif /* CONFIG_USB_GADGET_DUALSPEED */ dev->state = STATE_DEV_CONNECTED; dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket; @@ -1469,13 +1466,12 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) // user mode expected to disable endpoints } else { u8 config, power; -#ifdef CONFIG_USB_GADGET_DUALSPEED - if (gadget->speed == USB_SPEED_HIGH) { + + if (gadget_is_dualspeed(gadget) + && gadget->speed == USB_SPEED_HIGH) { config = dev->hs_config->bConfigurationValue; power = dev->hs_config->bMaxPower; - } else -#endif - { + } else { config = dev->config->bConfigurationValue; power = dev->config->bMaxPower; } diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index 9b0f0925ddd..bf2788dfb32 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -1241,19 +1241,15 @@ static void pullup_enable(struct omap_udc *udc) udc->gadget.dev.parent->power.power_state = PMSG_ON; udc->gadget.dev.power.power_state = PMSG_ON; UDC_SYSCON1_REG |= UDC_PULLUP_EN; -#ifndef CONFIG_USB_OTG - if (!cpu_is_omap15xx()) + if (!gadget_is_otg(udc->gadget) && !cpu_is_omap15xx()) OTG_CTRL_REG |= OTG_BSESSVLD; -#endif UDC_IRQ_EN_REG = UDC_DS_CHG_IE; } static void pullup_disable(struct omap_udc *udc) { -#ifndef CONFIG_USB_OTG - if (!cpu_is_omap15xx()) + if (!gadget_is_otg(udc->gadget) && !cpu_is_omap15xx()) OTG_CTRL_REG &= ~OTG_BSESSVLD; -#endif UDC_IRQ_EN_REG = UDC_DS_CHG_IE; UDC_SYSCON1_REG &= ~UDC_PULLUP_EN; } @@ -1390,7 +1386,7 @@ static void update_otg(struct omap_udc *udc) { u16 devstat; - if (!udc->gadget.is_otg) + if (!gadget_is_otg(udc->gadget)) return; if (OTG_CTRL_REG & OTG_ID) diff --git a/include/linux/usb_gadget.h b/include/linux/usb_gadget.h index ec9732e7fea..5ea611e48ec 100644 --- a/include/linux/usb_gadget.h +++ b/include/linux/usb_gadget.h @@ -479,6 +479,39 @@ static inline void *get_gadget_data (struct usb_gadget *gadget) list_for_each_entry(tmp, &(gadget)->ep_list, ep_list) +/** + * gadget_is_dualspeed - return true iff the hardware handles high speed + * @gadget: controller that might support both high and full speeds + */ +static inline int gadget_is_dualspeed(struct usb_gadget *g) +{ +#ifdef CONFIG_USB_GADGET_DUALSPEED + /* runtime test would check "g->is_dualspeed" ... that might be + * useful to work around hardware bugs, but is mostly pointless + */ + return 1; +#else + return 0; +#endif +} + +/** + * gadget_is_otg - return true iff the hardware is OTG-ready + * @gadget: controller that might have a Mini-AB connector + * + * This is a runtime test, since kernels with a USB-OTG stack sometimes + * run on boards which only have a Mini-B (or Mini-A) connector. + */ +static inline int gadget_is_otg(struct usb_gadget *g) +{ +#ifdef CONFIG_USB_OTG + return g->is_otg; +#else + return 0; +#endif +} + + /** * usb_gadget_frame_number - returns the current frame number * @gadget: controller that reports the frame number -- cgit v1.2.3-70-g09d2 From 0cf4f2de0a0f4100795f38ef894d4910678c74f8 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 2 Aug 2007 00:00:38 -0700 Subject: USB: gadget: ethernet gadget cleanups, shrinkage Clean up the ethernet gadget, using newer APIs and conventions: - gadget_is_dualspeed() and gadget_is_otg() ... #ifdef removal - Remove many now-needless #includes - Use the VERBOSE_DEBUG convention - Minor whitespace fixes. - Fix a warning from "sparse". Surprisingly, this saved about 2K of code (16%) on a fullspeed-only ARMv4 platform. I'm bit puzzled by that (it's so much!), but approve of the result. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/ether.c | 141 +++++++++++++++++---------------------------- 1 file changed, 54 insertions(+), 87 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index f70055473a0..ff244f42723 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -19,41 +19,19 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* #define VERBOSE_DEBUG */ -// #define DEBUG 1 -// #define VERBOSE - -#include #include -#include -#include -#include -#include -#include -#include -#include -#include #include #include -#include #include - -#include -#include -#include -#include -#include -#include +#include +#include #include #include #include -#include -#include -#include -#include - #include "gadget_chips.h" /*-------------------------------------------------------------------------*/ @@ -356,15 +334,15 @@ module_param (qmult, uint, S_IRUGO|S_IWUSR); #define qlen(gadget) \ (DEFAULT_QLEN*((gadget->speed == USB_SPEED_HIGH) ? qmult : 1)) -/* also defer IRQs on highspeed TX */ -#define TX_DELAY qmult - static inline int BITRATE(struct usb_gadget *g) { return (g->speed == USB_SPEED_HIGH) ? HS_BPS : FS_BPS; } #else /* full speed (low speed doesn't do bulk) */ + +#define qmult 1 + #define DEVSPEED USB_SPEED_FULL #define qlen(gadget) DEFAULT_QLEN @@ -390,7 +368,7 @@ static inline int BITRATE(struct usb_gadget *g) do { } while (0) #endif /* DEBUG */ -#ifdef VERBOSE +#ifdef VERBOSE_DEBUG #define VDEBUG DEBUG #else #define VDEBUG(dev,fmt,args...) \ @@ -830,8 +808,6 @@ static const struct usb_descriptor_header *fs_rndis_function [] = { }; #endif -#ifdef CONFIG_USB_GADGET_DUALSPEED - /* * usb 2.0 devices need to expose both high speed and full speed * descriptors, unless they only run at full speed. @@ -934,18 +910,15 @@ static const struct usb_descriptor_header *hs_rndis_function [] = { /* maxpacket and other transfer characteristics vary by speed. */ -#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs)) - -#else - -/* if there's no high speed support, maxpacket doesn't change. */ -#define ep_desc(g,hs,fs) (((void)(g)), (fs)) - -static inline void __init hs_subset_descriptors(void) +static inline struct usb_endpoint_descriptor * +ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs, + struct usb_endpoint_descriptor *fs) { + if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) + return hs; + return fs; } -#endif /* !CONFIG_USB_GADGET_DUALSPEED */ /*-------------------------------------------------------------------------*/ @@ -989,22 +962,19 @@ static struct usb_gadget_strings stringtab = { * complications: class descriptors, and an altsetting. */ static int -config_buf (enum usb_device_speed speed, - u8 *buf, u8 type, - unsigned index, int is_otg) +config_buf(struct usb_gadget *g, u8 *buf, u8 type, unsigned index, int is_otg) { int len; const struct usb_config_descriptor *config; const struct usb_descriptor_header **function; -#ifdef CONFIG_USB_GADGET_DUALSPEED - int hs = (speed == USB_SPEED_HIGH); + int hs = 0; - if (type == USB_DT_OTHER_SPEED_CONFIG) - hs = !hs; + if (gadget_is_dualspeed(g)) { + hs = (g->speed == USB_SPEED_HIGH); + if (type == USB_DT_OTHER_SPEED_CONFIG) + hs = !hs; + } #define which_fn(t) (hs ? hs_ ## t ## _function : fs_ ## t ## _function) -#else -#define which_fn(t) (fs_ ## t ## _function) -#endif if (index >= device_desc.bNumConfigurations) return -EINVAL; @@ -1217,7 +1187,7 @@ eth_set_config (struct eth_dev *dev, unsigned number, gfp_t gfp_flags) if (number) eth_reset_config (dev); usb_gadget_vbus_draw(dev->gadget, - dev->gadget->is_otg ? 8 : 100); + gadget_is_otg(dev->gadget) ? 8 : 100); } else { char *speed; unsigned power; @@ -1399,24 +1369,22 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) value = min (wLength, (u16) sizeof device_desc); memcpy (req->buf, &device_desc, value); break; -#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: - if (!gadget->is_dualspeed) + if (!gadget_is_dualspeed(gadget)) break; value = min (wLength, (u16) sizeof dev_qualifier); memcpy (req->buf, &dev_qualifier, value); break; case USB_DT_OTHER_SPEED_CONFIG: - if (!gadget->is_dualspeed) + if (!gadget_is_dualspeed(gadget)) break; // FALLTHROUGH -#endif /* CONFIG_USB_GADGET_DUALSPEED */ case USB_DT_CONFIG: - value = config_buf (gadget->speed, req->buf, + value = config_buf(gadget, req->buf, wValue >> 8, wValue & 0xff, - gadget->is_otg); + gadget_is_otg(gadget)); if (value >= 0) value = min (wLength, (u16) value); break; @@ -1585,12 +1553,12 @@ done_set_intf: && rndis_control_intf.bInterfaceNumber == wIndex) { u8 *buf; + u32 n; /* return the result */ - buf = rndis_get_next_response (dev->rndis_config, - &value); + buf = rndis_get_next_response(dev->rndis_config, &n); if (buf) { - memcpy (req->buf, buf, value); + memcpy(req->buf, buf, n); req->complete = rndis_response_complete; rndis_free_response(dev->rndis_config, buf); } @@ -2026,12 +1994,11 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net) req->length = length; -#ifdef CONFIG_USB_GADGET_DUALSPEED /* throttle highspeed IRQ rate back slightly */ - req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH) - ? ((atomic_read (&dev->tx_qlen) % TX_DELAY) != 0) - : 0; -#endif + if (gadget_is_dualspeed(dev->gadget)) + req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH) + ? ((atomic_read(&dev->tx_qlen) % qmult) != 0) + : 0; retval = usb_ep_queue (dev->in_ep, req, GFP_ATOMIC); switch (retval) { @@ -2188,8 +2155,7 @@ static int eth_stop (struct net_device *net) } if (rndis_active(dev)) { - rndis_set_param_medium (dev->rndis_config, - NDIS_MEDIUM_802_3, 0); + rndis_set_param_medium(dev->rndis_config, NDIS_MEDIUM_802_3, 0); (void) rndis_signal_disconnect (dev->rndis_config); } @@ -2443,26 +2409,28 @@ autoconf_fail: if (rndis) device_desc.bNumConfigurations = 2; -#ifdef CONFIG_USB_GADGET_DUALSPEED - if (rndis) - dev_qualifier.bNumConfigurations = 2; - else if (!cdc) - dev_qualifier.bDeviceClass = USB_CLASS_VENDOR_SPEC; + if (gadget_is_dualspeed(gadget)) { + if (rndis) + dev_qualifier.bNumConfigurations = 2; + else if (!cdc) + dev_qualifier.bDeviceClass = USB_CLASS_VENDOR_SPEC; - /* assumes ep0 uses the same value for both speeds ... */ - dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0; + /* assumes ep0 uses the same value for both speeds ... */ + dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0; - /* and that all endpoints are dual-speed */ - hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress; - hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress; + /* and that all endpoints are dual-speed */ + hs_source_desc.bEndpointAddress = + fs_source_desc.bEndpointAddress; + hs_sink_desc.bEndpointAddress = + fs_sink_desc.bEndpointAddress; #if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) - if (status_ep) - hs_status_desc.bEndpointAddress = - fs_status_desc.bEndpointAddress; + if (status_ep) + hs_status_desc.bEndpointAddress = + fs_status_desc.bEndpointAddress; #endif -#endif /* DUALSPEED */ + } - if (gadget->is_otg) { + if (gadget_is_otg(gadget)) { otg_descriptor.bmAttributes |= USB_OTG_HNP, eth_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP; eth_config.bMaxPower = 4; @@ -2598,12 +2566,11 @@ fail0: if (rndis_set_param_dev (dev->rndis_config, dev->net, &dev->stats, &dev->cdc_filter)) goto fail0; - if (rndis_set_param_vendor (dev->rndis_config, vendorID, - manufacturer)) + if (rndis_set_param_vendor(dev->rndis_config, vendorID, + manufacturer)) goto fail0; - if (rndis_set_param_medium (dev->rndis_config, - NDIS_MEDIUM_802_3, - 0)) + if (rndis_set_param_medium(dev->rndis_config, + NDIS_MEDIUM_802_3, 0)) goto fail0; INFO (dev, "RNDIS ready\n"); } -- cgit v1.2.3-70-g09d2 From 8c07021635a10c9a4969cbff0f2325a94c860f77 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 2 Aug 2007 00:01:27 -0700 Subject: USB: gadget: gmidi cleanups Clean up the midi gadget, using newer APIs and conventions: - Remove many now-needless #includes - Use the DEBUG (from Kconfig+Makefile) and VERBOSE_DEBUG conventions. - Whitespace fixes There should be no effect on object code size. Signed-off-by: David Brownell Cc: Ben Williamson Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/gmidi.c | 80 +++++++++++++++++++--------------------------- 1 file changed, 32 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c index 1c5aa49d743..d2475755a20 100644 --- a/drivers/usb/gadget/gmidi.c +++ b/drivers/usb/gadget/gmidi.c @@ -18,17 +18,11 @@ * http://www.usb.org/developers/devclass_docs/midi10.pdf */ -#define DEBUG 1 -// #define VERBOSE +/* #define VERBOSE_DEBUG */ -#include #include -#include -#include -#include #include #include -#include #include #include @@ -139,30 +133,16 @@ struct gmidi_device { static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req); -#define xprintk(d,level,fmt,args...) \ - dev_printk(level , &(d)->gadget->dev , fmt , ## args) - -#ifdef DEBUG -#define DBG(dev,fmt,args...) \ - xprintk(dev , KERN_DEBUG , fmt , ## args) -#else -#define DBG(dev,fmt,args...) \ - do { } while (0) -#endif /* DEBUG */ - -#ifdef VERBOSE -#define VDBG DBG -#else -#define VDBG(dev,fmt,args...) \ - do { } while (0) -#endif /* VERBOSE */ - -#define ERROR(dev,fmt,args...) \ - xprintk(dev , KERN_ERR , fmt , ## args) -#define WARN(dev,fmt,args...) \ - xprintk(dev , KERN_WARNING , fmt , ## args) -#define INFO(dev,fmt,args...) \ - xprintk(dev , KERN_INFO , fmt , ## args) +#define DBG(d, fmt, args...) \ + dev_dbg(&(d)->gadget->dev , fmt , ## args) +#define VDBG(d, fmt, args...) \ + dev_vdbg(&(d)->gadget->dev , fmt , ## args) +#define ERROR(d, fmt, args...) \ + dev_err(&(d)->gadget->dev , fmt , ## args) +#define WARN(d, fmt, args...) \ + dev_warn(&(d)->gadget->dev , fmt , ## args) +#define INFO(d, fmt, args...) \ + dev_info(&(d)->gadget->dev , fmt , ## args) static unsigned buflen = 256; @@ -425,7 +405,7 @@ static int config_buf(struct usb_gadget *gadget, return len; } -static struct usb_request* alloc_ep_req(struct usb_ep *ep, unsigned length) +static struct usb_request *alloc_ep_req(struct usb_ep *ep, unsigned length) { struct usb_request *req; @@ -455,7 +435,7 @@ static const uint8_t gmidi_cin_length[] = { * Receives a chunk of MIDI data. */ static void gmidi_read_data(struct usb_ep *ep, int cable, - uint8_t* data, int length) + uint8_t *data, int length) { struct gmidi_device *dev = ep->driver_data; /* cable is ignored, because for now we only have one. */ @@ -541,7 +521,7 @@ static int set_gmidi_config(struct gmidi_device *dev, gfp_t gfp_flags) { int err = 0; struct usb_request *req; - struct usb_ep* ep; + struct usb_ep *ep; unsigned i; err = usb_ep_enable(dev->in_ep, &bulk_in_desc); @@ -628,7 +608,7 @@ gmidi_set_config(struct gmidi_device *dev, unsigned number, gfp_t gfp_flags) if (gadget_is_sa1100(gadget) && dev->config) { /* tx fifo is full, but we can't clear it...*/ - INFO(dev, "can't change configurations\n"); + ERROR(dev, "can't change configurations\n"); return -ESPIPE; } gmidi_reset_config(dev); @@ -843,7 +823,7 @@ static void gmidi_disconnect(struct usb_gadget *gadget) static void /* __init_or_exit */ gmidi_unbind(struct usb_gadget *gadget) { struct gmidi_device *dev = get_gadget_data(gadget); - struct snd_card* card; + struct snd_card *card; DBG(dev, "unbind\n"); @@ -867,12 +847,12 @@ static int gmidi_snd_free(struct snd_device *device) return 0; } -static void gmidi_transmit_packet(struct usb_request* req, uint8_t p0, +static void gmidi_transmit_packet(struct usb_request *req, uint8_t p0, uint8_t p1, uint8_t p2, uint8_t p3) { unsigned length = req->length; + u8 *buf = (u8 *)req->buf + length; - uint8_t* buf = (uint8_t*)req->buf + length; buf[0] = p0; buf[1] = p1; buf[2] = p2; @@ -883,8 +863,8 @@ static void gmidi_transmit_packet(struct usb_request* req, uint8_t p0, /* * Converts MIDI commands to USB MIDI packets. */ -static void gmidi_transmit_byte(struct usb_request* req, - struct gmidi_in_port* port, uint8_t b) +static void gmidi_transmit_byte(struct usb_request *req, + struct gmidi_in_port *port, uint8_t b) { uint8_t p0 = port->cable; @@ -981,10 +961,10 @@ static void gmidi_transmit_byte(struct usb_request* req, } } -static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req) +static void gmidi_transmit(struct gmidi_device *dev, struct usb_request *req) { - struct usb_ep* ep = dev->in_ep; - struct gmidi_in_port* port = &dev->in_port; + struct usb_ep *ep = dev->in_ep; + struct gmidi_in_port *port = &dev->in_port; if (!ep) { return; @@ -1020,14 +1000,14 @@ static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req) static void gmidi_in_tasklet(unsigned long data) { - struct gmidi_device* dev = (struct gmidi_device*)data; + struct gmidi_device *dev = (struct gmidi_device *)data; gmidi_transmit(dev, NULL); } static int gmidi_in_open(struct snd_rawmidi_substream *substream) { - struct gmidi_device* dev = substream->rmidi->private_data; + struct gmidi_device *dev = substream->rmidi->private_data; VDBG(dev, "gmidi_in_open\n"); dev->in_substream = substream; @@ -1037,13 +1017,15 @@ static int gmidi_in_open(struct snd_rawmidi_substream *substream) static int gmidi_in_close(struct snd_rawmidi_substream *substream) { + struct gmidi_device *dev = substream->rmidi->private_data; + VDBG(dev, "gmidi_in_close\n"); return 0; } static void gmidi_in_trigger(struct snd_rawmidi_substream *substream, int up) { - struct gmidi_device* dev = substream->rmidi->private_data; + struct gmidi_device *dev = substream->rmidi->private_data; VDBG(dev, "gmidi_in_trigger %d\n", up); dev->in_port.active = up; @@ -1054,7 +1036,7 @@ static void gmidi_in_trigger(struct snd_rawmidi_substream *substream, int up) static int gmidi_out_open(struct snd_rawmidi_substream *substream) { - struct gmidi_device* dev = substream->rmidi->private_data; + struct gmidi_device *dev = substream->rmidi->private_data; VDBG(dev, "gmidi_out_open\n"); dev->out_substream = substream; @@ -1063,13 +1045,15 @@ static int gmidi_out_open(struct snd_rawmidi_substream *substream) static int gmidi_out_close(struct snd_rawmidi_substream *substream) { + struct gmidi_device *dev = substream->rmidi->private_data; + VDBG(dev, "gmidi_out_close\n"); return 0; } static void gmidi_out_trigger(struct snd_rawmidi_substream *substream, int up) { - struct gmidi_device* dev = substream->rmidi->private_data; + struct gmidi_device *dev = substream->rmidi->private_data; VDBG(dev, "gmidi_out_trigger %d\n", up); if (up) { -- cgit v1.2.3-70-g09d2 From 51a0e85cd9b47e2e6332b40ea486cc1659d8a3ec Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 2 Aug 2007 00:02:47 -0700 Subject: USB: gadget: serial gadget cleanups Clean up the serial gadget, using newer APIs and conventions: - gadget_is_dualspeed() and gadget_is_otg() ... #ifdef removal - Remove many now-needless #includes - Use the DEBUG and VERBOSE_DEBUG conventions; turned up a bug in the original debug messaging - Various whitespace fixes. This gave only a minor object code shrinkage, but the source looks much cleaner in various places. Signed-off-by: David Brownell Cc: Al Borchers Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/serial.c | 166 +++++++++++++++++++------------------------- 1 file changed, 73 insertions(+), 93 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index ce4d2e09633..afdf71f76f7 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -17,30 +17,11 @@ * */ -#include #include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include #include #include #include -#include - -#include -#include -#include -#include -#include -#include #include #include @@ -89,30 +70,29 @@ #define GS_DEFAULT_PARITY USB_CDC_NO_PARITY #define GS_DEFAULT_CHAR_FORMAT USB_CDC_1_STOP_BITS -/* select highspeed/fullspeed, hiding highspeed if not configured */ -#ifdef CONFIG_USB_GADGET_DUALSPEED -#define GS_SPEED_SELECT(is_hs,hs,fs) ((is_hs) ? (hs) : (fs)) -#else -#define GS_SPEED_SELECT(is_hs,hs,fs) (fs) -#endif /* CONFIG_USB_GADGET_DUALSPEED */ +/* maxpacket and other transfer characteristics vary by speed. */ +static inline struct usb_endpoint_descriptor * +choose_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs, + struct usb_endpoint_descriptor *fs) +{ + if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) + return hs; + return fs; +} + /* debug settings */ -#ifdef GS_DEBUG +#ifdef DEBUG static int debug = 1; +#else +#define debug 0 +#endif #define gs_debug(format, arg...) \ do { if (debug) printk(KERN_DEBUG format, ## arg); } while(0) #define gs_debug_level(level, format, arg...) \ do { if (debug>=level) printk(KERN_DEBUG format, ## arg); } while(0) -#else - -#define gs_debug(format, arg...) \ - do { } while(0) -#define gs_debug_level(level, format, arg...) \ - do { } while(0) - -#endif /* GS_DEBUG */ /* Thanks to NetChip Technologies for donating this product ID. * @@ -147,10 +127,10 @@ struct gs_req_entry { /* the port structure holds info for each port, one for each minor number */ struct gs_port { - struct gs_dev *port_dev; /* pointer to device struct */ + struct gs_dev *port_dev; /* pointer to device struct */ struct tty_struct *port_tty; /* pointer to tty struct */ spinlock_t port_lock; - int port_num; + int port_num; int port_open_count; int port_in_use; /* open/close in progress */ wait_queue_head_t port_write_wait;/* waiting to write */ @@ -188,7 +168,7 @@ static void __exit gs_module_exit(void); /* tty driver */ static int gs_open(struct tty_struct *tty, struct file *file); static void gs_close(struct tty_struct *tty, struct file *file); -static int gs_write(struct tty_struct *tty, +static int gs_write(struct tty_struct *tty, const unsigned char *buf, int count); static void gs_put_char(struct tty_struct *tty, unsigned char ch); static void gs_flush_chars(struct tty_struct *tty); @@ -222,7 +202,7 @@ static void gs_setup_complete(struct usb_ep *ep, struct usb_request *req); static void gs_disconnect(struct usb_gadget *gadget); static int gs_set_config(struct gs_dev *dev, unsigned config); static void gs_reset_config(struct gs_dev *dev); -static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed, +static int gs_build_config_buf(u8 *buf, struct usb_gadget *g, u8 type, unsigned int index, int is_otg); static struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len, @@ -415,18 +395,18 @@ static const struct usb_cdc_header_desc gs_header_desc = { }; static const struct usb_cdc_call_mgmt_descriptor gs_call_mgmt_descriptor = { - .bLength = sizeof(gs_call_mgmt_descriptor), - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE, - .bmCapabilities = 0, - .bDataInterface = 1, /* index of data interface */ + .bLength = sizeof(gs_call_mgmt_descriptor), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE, + .bmCapabilities = 0, + .bDataInterface = 1, /* index of data interface */ }; static struct usb_cdc_acm_descriptor gs_acm_descriptor = { - .bLength = sizeof(gs_acm_descriptor), - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_ACM_TYPE, - .bmCapabilities = 0, + .bLength = sizeof(gs_acm_descriptor), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = USB_CDC_ACM_TYPE, + .bmCapabilities = 0, }; static const struct usb_cdc_union_desc gs_union_desc = { @@ -436,7 +416,7 @@ static const struct usb_cdc_union_desc gs_union_desc = { .bMasterInterface0 = 0, /* index of control interface */ .bSlaveInterface0 = 1, /* index of data interface */ }; - + static struct usb_endpoint_descriptor gs_fullspeed_notify_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -482,7 +462,6 @@ static const struct usb_descriptor_header *gs_acm_fullspeed_function[] = { NULL, }; -#ifdef CONFIG_USB_GADGET_DUALSPEED static struct usb_endpoint_descriptor gs_highspeed_notify_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -536,15 +515,13 @@ static const struct usb_descriptor_header *gs_acm_highspeed_function[] = { NULL, }; -#endif /* CONFIG_USB_GADGET_DUALSPEED */ - /* Module */ MODULE_DESCRIPTION(GS_LONG_NAME); MODULE_AUTHOR("Al Borchers"); MODULE_LICENSE("GPL"); -#ifdef GS_DEBUG +#ifdef DEBUG module_param(debug, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(debug, "Enable debugging, 0=off, 1=on"); #endif @@ -915,7 +892,8 @@ static void gs_put_char(struct tty_struct *tty, unsigned char ch) return; } - gs_debug("gs_put_char: (%d,%p) char=0x%x, called from %p, %p, %p\n", port->port_num, tty, ch, __builtin_return_address(0), __builtin_return_address(1), __builtin_return_address(2)); + gs_debug("gs_put_char: (%d,%p) char=0x%x, called from %p\n", + port->port_num, tty, ch, __builtin_return_address(0)); spin_lock_irqsave(&port->port_lock, flags); @@ -1116,7 +1094,11 @@ static int gs_send(struct gs_dev *dev) len = gs_send_packet(dev, req->buf, ep->maxpacket); if (len > 0) { -gs_debug_level(3, "gs_send: len=%d, 0x%2.2x 0x%2.2x 0x%2.2x ...\n", len, *((unsigned char *)req->buf), *((unsigned char *)req->buf+1), *((unsigned char *)req->buf+2)); + gs_debug_level(3, "gs_send: len=%d, 0x%2.2x " + "0x%2.2x 0x%2.2x ...\n", len, + *((unsigned char *)req->buf), + *((unsigned char *)req->buf+1), + *((unsigned char *)req->buf+2)); list_del(&req_entry->re_entry); req->length = len; spin_unlock_irqrestore(&dev->dev_lock, flags); @@ -1269,7 +1251,7 @@ static void gs_read_complete(struct usb_ep *ep, struct usb_request *req) switch(req->status) { case 0: - /* normal completion */ + /* normal completion */ gs_recv_packet(dev, req->buf, req->actual); requeue: req->length = ep->maxpacket; @@ -1406,23 +1388,24 @@ static int __init gs_bind(struct usb_gadget *gadget) ? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC; gs_device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; -#ifdef CONFIG_USB_GADGET_DUALSPEED - gs_qualifier_desc.bDeviceClass = use_acm - ? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC; - /* assume ep0 uses the same packet size for both speeds */ - gs_qualifier_desc.bMaxPacketSize0 = gs_device_desc.bMaxPacketSize0; - /* assume endpoints are dual-speed */ - gs_highspeed_notify_desc.bEndpointAddress = - gs_fullspeed_notify_desc.bEndpointAddress; - gs_highspeed_in_desc.bEndpointAddress = - gs_fullspeed_in_desc.bEndpointAddress; - gs_highspeed_out_desc.bEndpointAddress = - gs_fullspeed_out_desc.bEndpointAddress; -#endif /* CONFIG_USB_GADGET_DUALSPEED */ + if (gadget_is_dualspeed(gadget)) { + gs_qualifier_desc.bDeviceClass = use_acm + ? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC; + /* assume ep0 uses the same packet size for both speeds */ + gs_qualifier_desc.bMaxPacketSize0 = + gs_device_desc.bMaxPacketSize0; + /* assume endpoints are dual-speed */ + gs_highspeed_notify_desc.bEndpointAddress = + gs_fullspeed_notify_desc.bEndpointAddress; + gs_highspeed_in_desc.bEndpointAddress = + gs_fullspeed_in_desc.bEndpointAddress; + gs_highspeed_out_desc.bEndpointAddress = + gs_fullspeed_out_desc.bEndpointAddress; + } usb_gadget_set_selfpowered(gadget); - if (gadget->is_otg) { + if (gadget_is_otg(gadget)) { gs_otg_descriptor.bmAttributes |= USB_OTG_HNP, gs_bulk_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP; gs_acm_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP; @@ -1570,9 +1553,8 @@ static int gs_setup_standard(struct usb_gadget *gadget, memcpy(req->buf, &gs_device_desc, ret); break; -#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: - if (!gadget->is_dualspeed) + if (!gadget_is_dualspeed(gadget)) break; ret = min(wLength, (u16)sizeof(struct usb_qualifier_descriptor)); @@ -1580,14 +1562,13 @@ static int gs_setup_standard(struct usb_gadget *gadget, break; case USB_DT_OTHER_SPEED_CONFIG: - if (!gadget->is_dualspeed) + if (!gadget_is_dualspeed(gadget)) break; /* fall through */ -#endif /* CONFIG_USB_GADGET_DUALSPEED */ case USB_DT_CONFIG: - ret = gs_build_config_buf(req->buf, gadget->speed, + ret = gs_build_config_buf(req->buf, gadget, wValue >> 8, wValue & 0xff, - gadget->is_otg); + gadget_is_otg(gadget)); if (ret >= 0) ret = min(wLength, (u16)ret); break; @@ -1827,8 +1808,7 @@ static int gs_set_config(struct gs_dev *dev, unsigned config) if (EP_NOTIFY_NAME && strcmp(ep->name, EP_NOTIFY_NAME) == 0) { - ep_desc = GS_SPEED_SELECT( - gadget->speed == USB_SPEED_HIGH, + ep_desc = choose_ep_desc(gadget, &gs_highspeed_notify_desc, &gs_fullspeed_notify_desc); ret = usb_ep_enable(ep,ep_desc); @@ -1844,9 +1824,8 @@ static int gs_set_config(struct gs_dev *dev, unsigned config) } else if (strcmp(ep->name, EP_IN_NAME) == 0) { - ep_desc = GS_SPEED_SELECT( - gadget->speed == USB_SPEED_HIGH, - &gs_highspeed_in_desc, + ep_desc = choose_ep_desc(gadget, + &gs_highspeed_in_desc, &gs_fullspeed_in_desc); ret = usb_ep_enable(ep,ep_desc); if (ret == 0) { @@ -1861,8 +1840,7 @@ static int gs_set_config(struct gs_dev *dev, unsigned config) } else if (strcmp(ep->name, EP_OUT_NAME) == 0) { - ep_desc = GS_SPEED_SELECT( - gadget->speed == USB_SPEED_HIGH, + ep_desc = choose_ep_desc(gadget, &gs_highspeed_out_desc, &gs_fullspeed_out_desc); ret = usb_ep_enable(ep,ep_desc); @@ -1981,11 +1959,11 @@ static void gs_reset_config(struct gs_dev *dev) * Builds the config descriptors in the given buffer and returns the * length, or a negative error number. */ -static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed, +static int gs_build_config_buf(u8 *buf, struct usb_gadget *g, u8 type, unsigned int index, int is_otg) { int len; - int high_speed; + int high_speed = 0; const struct usb_config_descriptor *config_desc; const struct usb_descriptor_header **function; @@ -1993,20 +1971,22 @@ static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed, return -EINVAL; /* other speed switches high and full speed */ - high_speed = (speed == USB_SPEED_HIGH); - if (type == USB_DT_OTHER_SPEED_CONFIG) - high_speed = !high_speed; + if (gadget_is_dualspeed(g)) { + high_speed = (g->speed == USB_SPEED_HIGH); + if (type == USB_DT_OTHER_SPEED_CONFIG) + high_speed = !high_speed; + } if (use_acm) { config_desc = &gs_acm_config_desc; - function = GS_SPEED_SELECT(high_speed, - gs_acm_highspeed_function, - gs_acm_fullspeed_function); + function = high_speed + ? gs_acm_highspeed_function + : gs_acm_fullspeed_function; } else { config_desc = &gs_bulk_config_desc; - function = GS_SPEED_SELECT(high_speed, - gs_bulk_highspeed_function, - gs_bulk_fullspeed_function); + function = high_speed + ? gs_bulk_highspeed_function + : gs_bulk_fullspeed_function; } /* for now, don't advertise srp-only devices */ -- cgit v1.2.3-70-g09d2 From 2e806f67cc570d25395469a0ded0df8ffbd4d82f Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 2 Aug 2007 00:03:39 -0700 Subject: USB: gadget: file storage gadget cleanups Clean up the file storage gadget, using newer APIs and conventions: - gadget_is_dualspeed() and gadget_is_otg() ... #ifdef removal - Remove many now-needless #includes - Use the DEBUG (from Kconfig+Makefile) and VERBOSE_DEBUG conventions. - Remove some "sparse" warnings (it still dislikes the __user annotations) This gave only a minor object code shrinkage. Signed-off-by: David Brownell Cc: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/file_storage.c | 118 +++++++++++++++----------------------- 1 file changed, 45 insertions(+), 73 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 965ad7bec7b..0019116ee41 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -217,17 +217,11 @@ */ -#undef DEBUG -#undef VERBOSE +/* #define VERBOSE_DEBUG */ #undef DUMP_MSGS -#include -#include - -#include #include -#include #include #include #include @@ -235,18 +229,10 @@ #include #include #include -#include -#include #include #include #include -#include -#include -#include -#include #include -#include -#include #include #include #include @@ -289,57 +275,51 @@ MODULE_LICENSE("Dual BSD/GPL"); /*-------------------------------------------------------------------------*/ -#define xprintk(f,level,fmt,args...) \ - dev_printk(level , &(f)->gadget->dev , fmt , ## args) #define yprintk(l,level,fmt,args...) \ dev_printk(level , &(l)->dev , fmt , ## args) #ifdef DEBUG -#define DBG(fsg,fmt,args...) \ - xprintk(fsg , KERN_DEBUG , fmt , ## args) #define LDBG(lun,fmt,args...) \ yprintk(lun , KERN_DEBUG , fmt , ## args) #define MDBG(fmt,args...) \ printk(KERN_DEBUG DRIVER_NAME ": " fmt , ## args) #else -#define DBG(fsg,fmt,args...) \ - do { } while (0) #define LDBG(lun,fmt,args...) \ do { } while (0) #define MDBG(fmt,args...) \ do { } while (0) -#undef VERBOSE +#undef VERBOSE_DEBUG #undef DUMP_MSGS #endif /* DEBUG */ -#ifdef VERBOSE -#define VDBG DBG +#ifdef VERBOSE_DEBUG #define VLDBG LDBG #else -#define VDBG(fsg,fmt,args...) \ - do { } while (0) #define VLDBG(lun,fmt,args...) \ do { } while (0) -#endif /* VERBOSE */ +#endif /* VERBOSE_DEBUG */ -#define ERROR(fsg,fmt,args...) \ - xprintk(fsg , KERN_ERR , fmt , ## args) #define LERROR(lun,fmt,args...) \ yprintk(lun , KERN_ERR , fmt , ## args) - -#define WARN(fsg,fmt,args...) \ - xprintk(fsg , KERN_WARNING , fmt , ## args) #define LWARN(lun,fmt,args...) \ yprintk(lun , KERN_WARNING , fmt , ## args) - -#define INFO(fsg,fmt,args...) \ - xprintk(fsg , KERN_INFO , fmt , ## args) #define LINFO(lun,fmt,args...) \ yprintk(lun , KERN_INFO , fmt , ## args) #define MINFO(fmt,args...) \ printk(KERN_INFO DRIVER_NAME ": " fmt , ## args) +#define DBG(d, fmt, args...) \ + dev_dbg(&(d)->gadget->dev , fmt , ## args) +#define VDBG(d, fmt, args...) \ + dev_vdbg(&(d)->gadget->dev , fmt , ## args) +#define ERROR(d, fmt, args...) \ + dev_err(&(d)->gadget->dev , fmt , ## args) +#define WARN(d, fmt, args...) \ + dev_warn(&(d)->gadget->dev , fmt , ## args) +#define INFO(d, fmt, args...) \ + dev_info(&(d)->gadget->dev , fmt , ## args) + /*-------------------------------------------------------------------------*/ @@ -350,8 +330,8 @@ MODULE_LICENSE("Dual BSD/GPL"); static struct { char *file[MAX_LUNS]; int ro[MAX_LUNS]; - int num_filenames; - int num_ros; + unsigned int num_filenames; + unsigned int num_ros; unsigned int nluns; int removable; @@ -950,8 +930,6 @@ static const struct usb_descriptor_header *fs_function[] = { #define FS_FUNCTION_PRE_EP_ENTRIES 2 -#ifdef CONFIG_USB_GADGET_DUALSPEED - /* * USB 2.0 devices need to expose both high speed and full speed * descriptors, unless they only run at full speed. @@ -1014,14 +992,14 @@ static const struct usb_descriptor_header *hs_function[] = { #define HS_FUNCTION_PRE_EP_ENTRIES 2 /* Maxpacket and other transfer characteristics vary by speed. */ -#define ep_desc(g,fs,hs) (((g)->speed==USB_SPEED_HIGH) ? (hs) : (fs)) - -#else - -/* If there's no high speed support, always use the full-speed descriptor. */ -#define ep_desc(g,fs,hs) fs - -#endif /* !CONFIG_USB_GADGET_DUALSPEED */ +static inline struct usb_endpoint_descriptor * +ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs, + struct usb_endpoint_descriptor *hs) +{ + if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) + return hs; + return fs; +} /* The CBI specification limits the serial string to 12 uppercase hexadecimal @@ -1053,26 +1031,22 @@ static struct usb_gadget_strings stringtab = { static int populate_config_buf(struct usb_gadget *gadget, u8 *buf, u8 type, unsigned index) { -#ifdef CONFIG_USB_GADGET_DUALSPEED enum usb_device_speed speed = gadget->speed; -#endif int len; const struct usb_descriptor_header **function; if (index > 0) return -EINVAL; -#ifdef CONFIG_USB_GADGET_DUALSPEED - if (type == USB_DT_OTHER_SPEED_CONFIG) + if (gadget_is_dualspeed(gadget) && type == USB_DT_OTHER_SPEED_CONFIG) speed = (USB_SPEED_FULL + USB_SPEED_HIGH) - speed; - if (speed == USB_SPEED_HIGH) + if (gadget_is_dualspeed(gadget) && speed == USB_SPEED_HIGH) function = hs_function; else -#endif function = fs_function; /* for now, don't advertise srp-only devices */ - if (!gadget->is_otg) + if (!gadget_is_otg(gadget)) function++; len = usb_gadget_config_buf(&config_desc, buf, EP0_BUFSIZE, function); @@ -1394,10 +1368,9 @@ static int standard_setup_req(struct fsg_dev *fsg, value = sizeof device_desc; memcpy(req->buf, &device_desc, value); break; -#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: VDBG(fsg, "get device qualifier\n"); - if (!fsg->gadget->is_dualspeed) + if (!gadget_is_dualspeed(fsg->gadget)) break; value = sizeof dev_qualifier; memcpy(req->buf, &dev_qualifier, value); @@ -1405,15 +1378,12 @@ static int standard_setup_req(struct fsg_dev *fsg, case USB_DT_OTHER_SPEED_CONFIG: VDBG(fsg, "get other-speed config descriptor\n"); - if (!fsg->gadget->is_dualspeed) + if (!gadget_is_dualspeed(fsg->gadget)) break; goto get_config; -#endif case USB_DT_CONFIG: VDBG(fsg, "get configuration descriptor\n"); -#ifdef CONFIG_USB_GADGET_DUALSPEED - get_config: -#endif +get_config: value = populate_config_buf(fsg->gadget, req->buf, w_value >> 8, @@ -3859,7 +3829,7 @@ static int __init fsg_bind(struct usb_gadget *gadget) /* Find out how many LUNs there should be */ i = mod_data.nluns; if (i == 0) - i = max(mod_data.num_filenames, 1); + i = max(mod_data.num_filenames, 1u); if (i > MAX_LUNS) { ERROR(fsg, "invalid number of LUNs: %d\n", i); rc = -EINVAL; @@ -3944,21 +3914,23 @@ static int __init fsg_bind(struct usb_gadget *gadget) intf_desc.bInterfaceProtocol = mod_data.transport_type; fs_function[i + FS_FUNCTION_PRE_EP_ENTRIES] = NULL; -#ifdef CONFIG_USB_GADGET_DUALSPEED - hs_function[i + HS_FUNCTION_PRE_EP_ENTRIES] = NULL; + if (gadget_is_dualspeed(gadget)) { + hs_function[i + HS_FUNCTION_PRE_EP_ENTRIES] = NULL; - /* Assume ep0 uses the same maxpacket value for both speeds */ - dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket; + /* Assume ep0 uses the same maxpacket value for both speeds */ + dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket; - /* Assume that all endpoint addresses are the same for both speeds */ - hs_bulk_in_desc.bEndpointAddress = fs_bulk_in_desc.bEndpointAddress; - hs_bulk_out_desc.bEndpointAddress = fs_bulk_out_desc.bEndpointAddress; - hs_intr_in_desc.bEndpointAddress = fs_intr_in_desc.bEndpointAddress; -#endif + /* Assume endpoint addresses are the same for both speeds */ + hs_bulk_in_desc.bEndpointAddress = + fs_bulk_in_desc.bEndpointAddress; + hs_bulk_out_desc.bEndpointAddress = + fs_bulk_out_desc.bEndpointAddress; + hs_intr_in_desc.bEndpointAddress = + fs_intr_in_desc.bEndpointAddress; + } - if (gadget->is_otg) { + if (gadget_is_otg(gadget)) otg_desc.bmAttributes |= USB_OTG_HNP; - } rc = -ENOMEM; -- cgit v1.2.3-70-g09d2 From ca2bdf4bcc91818f03e009b87c348609c2578d1d Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 2 Aug 2007 12:20:05 -0700 Subject: USB: gadget: gadget zero cleanups Clean up gadget zero, using newer APIs and conventions: - gadget_is_dualspeed() and gadget_is_otg() ... #ifdef removal - Remove many now-needless #includes - Use the VERBOSE_DEBUG convention - Some whitespace fixes. - A few comment updates - Plus a few other small cleanups: don't pass gfp_t around when it's always going to be GFP_ATOMIC, and do static init of serial number. Also go to straight GPL; there's no real point in dual licensing this stuff any more. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/zero.c | 237 +++++++++++++++++++--------------------------- 1 file changed, 96 insertions(+), 141 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index fcfe869acb9..ff540879ce3 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -1,38 +1,22 @@ /* * zero.c -- Gadget Zero, for USB development * - * Copyright (C) 2003-2004 David Brownell + * Copyright (C) 2003-2007 David Brownell * All rights reserved. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") as published by the Free Software - * Foundation, either version 2 of that License or (at your option) any - * later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -57,30 +41,18 @@ * Many drivers will only have one configuration, letting them be much * simpler if they also don't support high speed operation (like this * driver does). + * + * Why is *this* driver using two configurations, rather than setting up + * two interfaces with different functions? To help verify that multiple + * configuration infrastucture is working correctly; also, so that it can + * work with low capability USB controllers without four bulk endpoints. */ -#define DEBUG 1 -// #define VERBOSE +/* #define VERBOSE_DEBUG */ -#include #include -#include -#include -#include -#include -#include -#include -#include -#include #include #include -#include - -#include -#include -#include -#include -#include #include #include @@ -90,7 +62,7 @@ /*-------------------------------------------------------------------------*/ -#define DRIVER_VERSION "St Patrick's Day 2004" +#define DRIVER_VERSION "Lughnasadh, 2007" static const char shortname [] = "zero"; static const char longname [] = "Gadget Zero"; @@ -131,30 +103,16 @@ struct zero_dev { struct timer_list resume; }; -#define xprintk(d,level,fmt,args...) \ - dev_printk(level , &(d)->gadget->dev , fmt , ## args) - -#ifdef DEBUG -#define DBG(dev,fmt,args...) \ - xprintk(dev , KERN_DEBUG , fmt , ## args) -#else -#define DBG(dev,fmt,args...) \ - do { } while (0) -#endif /* DEBUG */ - -#ifdef VERBOSE -#define VDBG DBG -#else -#define VDBG(dev,fmt,args...) \ - do { } while (0) -#endif /* VERBOSE */ - -#define ERROR(dev,fmt,args...) \ - xprintk(dev , KERN_ERR , fmt , ## args) -#define WARN(dev,fmt,args...) \ - xprintk(dev , KERN_WARNING , fmt , ## args) -#define INFO(dev,fmt,args...) \ - xprintk(dev , KERN_INFO , fmt , ## args) +#define DBG(d, fmt, args...) \ + dev_dbg(&(d)->gadget->dev , fmt , ## args) +#define VDBG(d, fmt, args...) \ + dev_vdbg(&(d)->gadget->dev , fmt , ## args) +#define ERROR(d, fmt, args...) \ + dev_err(&(d)->gadget->dev , fmt , ## args) +#define WARN(d, fmt, args...) \ + dev_warn(&(d)->gadget->dev , fmt , ## args) +#define INFO(d, fmt, args...) \ + dev_info(&(d)->gadget->dev , fmt , ## args) /*-------------------------------------------------------------------------*/ @@ -326,8 +284,6 @@ static const struct usb_descriptor_header *fs_loopback_function [] = { NULL, }; -#ifdef CONFIG_USB_GADGET_DUALSPEED - /* * usb 2.0 devices need to expose both high speed and full speed * descriptors, unless they only run at full speed. @@ -383,17 +339,20 @@ static const struct usb_descriptor_header *hs_loopback_function [] = { }; /* maxpacket and other transfer characteristics vary by speed. */ -#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs)) - -#else +static inline struct usb_endpoint_descriptor * +ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs, + struct usb_endpoint_descriptor *fs) +{ + if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) + return hs; + return fs; +} -/* if there's no high speed support, maxpacket doesn't change. */ -#define ep_desc(g,hs,fs) fs +static char manufacturer[50]; -#endif /* !CONFIG_USB_GADGET_DUALSPEED */ +/* default serial number takes at least two packets */ +static char serial[] = "0123456789.0123456789.0123456789"; -static char manufacturer [50]; -static char serial [40]; /* static strings, in UTF-8 */ static struct usb_string strings [] = { @@ -435,30 +394,29 @@ config_buf (struct usb_gadget *gadget, int is_source_sink; int len; const struct usb_descriptor_header **function; -#ifdef CONFIG_USB_GADGET_DUALSPEED - int hs = (gadget->speed == USB_SPEED_HIGH); -#endif + int hs = 0; /* two configurations will always be index 0 and index 1 */ if (index > 1) return -EINVAL; is_source_sink = loopdefault ? (index == 1) : (index == 0); -#ifdef CONFIG_USB_GADGET_DUALSPEED - if (type == USB_DT_OTHER_SPEED_CONFIG) - hs = !hs; + if (gadget_is_dualspeed(gadget)) { + hs = (gadget->speed == USB_SPEED_HIGH); + if (type == USB_DT_OTHER_SPEED_CONFIG) + hs = !hs; + } if (hs) function = is_source_sink ? hs_source_sink_function : hs_loopback_function; else -#endif function = is_source_sink ? fs_source_sink_function : fs_loopback_function; /* for now, don't advertise srp-only devices */ - if (!gadget->is_otg) + if (!gadget_is_otg(gadget)) function++; len = usb_gadget_config_buf (is_source_sink @@ -498,6 +456,19 @@ static void free_ep_req (struct usb_ep *ep, struct usb_request *req) /*-------------------------------------------------------------------------*/ +/* + * SOURCE/SINK FUNCTION ... a primary testing vehicle for USB peripherals, + * this just sinks bulk packets OUT to the peripheral and sources them IN + * to the host, optionally with specific data patterns. + * + * In terms of control messaging, this supports all the standard requests + * plus two that support control-OUT tests. + * + * Note that because this doesn't queue more than one request at a time, + * some other function must be used to test queueing logic. The network + * link (g_ether) is probably the best option for that. + */ + /* optionally require specific source/sink data patterns */ static int @@ -534,12 +505,7 @@ check_read_data ( return 0; } -static void -reinit_write_data ( - struct zero_dev *dev, - struct usb_ep *ep, - struct usb_request *req -) +static void reinit_write_data(struct usb_ep *ep, struct usb_request *req) { unsigned i; u8 *buf = req->buf; @@ -566,16 +532,16 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req) switch (status) { - case 0: /* normal completion? */ + case 0: /* normal completion? */ if (ep == dev->out_ep) { check_read_data (dev, ep, req); memset (req->buf, 0x55, req->length); } else - reinit_write_data (dev, ep, req); + reinit_write_data(ep, req); break; /* this endpoint is normally active while we're configured */ - case -ECONNABORTED: /* hardware forced ep reset */ + case -ECONNABORTED: /* hardware forced ep reset */ case -ECONNRESET: /* request dequeued */ case -ESHUTDOWN: /* disconnect from host */ VDBG (dev, "%s gone (%d), %d/%d\n", ep->name, status, @@ -607,8 +573,7 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req) } } -static struct usb_request * -source_sink_start_ep (struct usb_ep *ep, gfp_t gfp_flags) +static struct usb_request *source_sink_start_ep(struct usb_ep *ep) { struct usb_request *req; int status; @@ -621,11 +586,11 @@ source_sink_start_ep (struct usb_ep *ep, gfp_t gfp_flags) req->complete = source_sink_complete; if (strcmp (ep->name, EP_IN_NAME) == 0) - reinit_write_data (ep->driver_data, ep, req); + reinit_write_data(ep, req); else memset (req->buf, 0x55, req->length); - status = usb_ep_queue (ep, req, gfp_flags); + status = usb_ep_queue(ep, req, GFP_ATOMIC); if (status) { struct zero_dev *dev = ep->driver_data; @@ -637,8 +602,7 @@ source_sink_start_ep (struct usb_ep *ep, gfp_t gfp_flags) return req; } -static int -set_source_sink_config (struct zero_dev *dev, gfp_t gfp_flags) +static int set_source_sink_config(struct zero_dev *dev) { int result = 0; struct usb_ep *ep; @@ -653,8 +617,7 @@ set_source_sink_config (struct zero_dev *dev, gfp_t gfp_flags) result = usb_ep_enable (ep, d); if (result == 0) { ep->driver_data = dev; - if (source_sink_start_ep(ep, gfp_flags) - != NULL) { + if (source_sink_start_ep(ep) != NULL) { dev->in_ep = ep; continue; } @@ -668,8 +631,7 @@ set_source_sink_config (struct zero_dev *dev, gfp_t gfp_flags) result = usb_ep_enable (ep, d); if (result == 0) { ep->driver_data = dev; - if (source_sink_start_ep(ep, gfp_flags) - != NULL) { + if (source_sink_start_ep(ep) != NULL) { dev->out_ep = ep; continue; } @@ -701,7 +663,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req) switch (status) { - case 0: /* normal completion? */ + case 0: /* normal completion? */ if (ep == dev->out_ep) { /* loop this OUT packet back IN to the host */ req->zero = (req->actual < req->length); @@ -735,7 +697,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req) * rely on the hardware driver to clean up on disconnect or * endpoint disable. */ - case -ECONNABORTED: /* hardware forced ep reset */ + case -ECONNABORTED: /* hardware forced ep reset */ case -ECONNRESET: /* request dequeued */ case -ESHUTDOWN: /* disconnect from host */ free_ep_req (ep, req); @@ -743,8 +705,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req) } } -static int -set_loopback_config (struct zero_dev *dev, gfp_t gfp_flags) +static int set_loopback_config(struct zero_dev *dev) { int result = 0; struct usb_ep *ep; @@ -844,8 +805,7 @@ static void zero_reset_config (struct zero_dev *dev) * code can do, perhaps by disallowing more than one configuration or * by limiting configuration choices (like the pxa2xx). */ -static int -zero_set_config (struct zero_dev *dev, unsigned number, gfp_t gfp_flags) +static int zero_set_config(struct zero_dev *dev, unsigned number) { int result = 0; struct usb_gadget *gadget = dev->gadget; @@ -855,17 +815,17 @@ zero_set_config (struct zero_dev *dev, unsigned number, gfp_t gfp_flags) if (gadget_is_sa1100 (gadget) && dev->config) { /* tx fifo is full, but we can't clear it...*/ - INFO (dev, "can't change configurations\n"); + ERROR(dev, "can't change configurations\n"); return -ESPIPE; } zero_reset_config (dev); switch (number) { case CONFIG_SOURCE_SINK: - result = set_source_sink_config (dev, gfp_flags); + result = set_source_sink_config(dev); break; case CONFIG_LOOPBACK: - result = set_loopback_config (dev, gfp_flags); + result = set_loopback_config(dev); break; default: result = -EINVAL; @@ -885,7 +845,7 @@ zero_set_config (struct zero_dev *dev, unsigned number, gfp_t gfp_flags) case USB_SPEED_LOW: speed = "low"; break; case USB_SPEED_FULL: speed = "full"; break; case USB_SPEED_HIGH: speed = "high"; break; - default: speed = "?"; break; + default: speed = "?"; break; } dev->config = number; @@ -938,19 +898,17 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) value = min (w_length, (u16) sizeof device_desc); memcpy (req->buf, &device_desc, value); break; -#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: - if (!gadget->is_dualspeed) + if (!gadget_is_dualspeed(gadget)) break; value = min (w_length, (u16) sizeof dev_qualifier); memcpy (req->buf, &dev_qualifier, value); break; case USB_DT_OTHER_SPEED_CONFIG: - if (!gadget->is_dualspeed) + if (!gadget_is_dualspeed(gadget)) break; // FALLTHROUGH -#endif /* CONFIG_USB_GADGET_DUALSPEED */ case USB_DT_CONFIG: value = config_buf (gadget, req->buf, w_value >> 8, @@ -984,7 +942,7 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) else VDBG (dev, "HNP inactive\n"); spin_lock (&dev->lock); - value = zero_set_config (dev, w_value, GFP_ATOMIC); + value = zero_set_config(dev, w_value); spin_unlock (&dev->lock); break; case USB_REQ_GET_CONFIGURATION: @@ -1013,7 +971,7 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) * use this "reset the config" shortcut. */ zero_reset_config (dev); - zero_set_config (dev, config, GFP_ATOMIC); + zero_set_config(dev, config); value = 0; } spin_unlock (&dev->lock); @@ -1163,7 +1121,7 @@ autoconf_fail: } EP_IN_NAME = ep->name; ep->driver_data = ep; /* claim */ - + ep = usb_ep_autoconfig (gadget, &fs_sink_desc); if (!ep) goto autoconf_fail; @@ -1207,16 +1165,18 @@ autoconf_fail: device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; -#ifdef CONFIG_USB_GADGET_DUALSPEED - /* assume ep0 uses the same value for both speeds ... */ - dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0; + if (gadget_is_dualspeed(gadget)) { + /* assume ep0 uses the same value for both speeds ... */ + dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0; - /* and that all endpoints are dual-speed */ - hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress; - hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress; -#endif + /* and that all endpoints are dual-speed */ + hs_source_desc.bEndpointAddress = + fs_source_desc.bEndpointAddress; + hs_sink_desc.bEndpointAddress = + fs_sink_desc.bEndpointAddress; + } - if (gadget->is_otg) { + if (gadget_is_otg(gadget)) { otg_descriptor.bmAttributes |= USB_OTG_HNP, source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP; loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP; @@ -1294,23 +1254,18 @@ static struct usb_gadget_driver zero_driver = { .suspend = zero_suspend, .resume = zero_resume, - .driver = { + .driver = { .name = (char *) shortname, .owner = THIS_MODULE, }, }; -MODULE_AUTHOR ("David Brownell"); -MODULE_LICENSE ("Dual BSD/GPL"); +MODULE_AUTHOR("David Brownell"); +MODULE_LICENSE("GPL"); static int __init init (void) { - /* a real value would likely come through some id prom - * or module option. this one takes at least two packets. - */ - strlcpy (serial, "0123456789.0123456789.0123456789", sizeof serial); - return usb_gadget_register_driver (&zero_driver); } module_init (init); -- cgit v1.2.3-70-g09d2 From 5234ce1b02ae2574098ebe9839dcf241076a9367 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Tue, 31 Jul 2007 20:33:58 -0700 Subject: usb: add the concept of default authorization to USB hosts This introduces /sys/bus/devices/usb*/authorized_default; it dictates what is going to be the default authorization state for devices connected to the host. User space can set that using the sysfs file. We hook to the root hub instead of to the device controller as it is quite easy to get to it in sysfs from the device structure (device 5-4.3 is usb5) vs. backtracking to the controller device. By default it is set to be 'authorized' (!0) for normal, wired USB devices and 'unauthorized' (0) for Wireless USB devices. As suggested by Adrian Bunk, make authorized_default static Signed-off-by: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++- drivers/usb/core/hcd.h | 7 +++++ 2 files changed, 79 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index eb212178826..875e2476c1f 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -679,6 +679,66 @@ static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) return 0; } + + +/* + * Show & store the current value of authorized_default + */ +static ssize_t usb_host_authorized_default_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct usb_device *rh_usb_dev = to_usb_device(dev); + struct usb_bus *usb_bus = rh_usb_dev->bus; + struct usb_hcd *usb_hcd; + + if (usb_bus == NULL) /* FIXME: not sure if this case is possible */ + return -ENODEV; + usb_hcd = bus_to_hcd(usb_bus); + return snprintf(buf, PAGE_SIZE, "%u\n", usb_hcd->authorized_default); +} + +static ssize_t usb_host_authorized_default_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + ssize_t result; + unsigned val; + struct usb_device *rh_usb_dev = to_usb_device(dev); + struct usb_bus *usb_bus = rh_usb_dev->bus; + struct usb_hcd *usb_hcd; + + if (usb_bus == NULL) /* FIXME: not sure if this case is possible */ + return -ENODEV; + usb_hcd = bus_to_hcd(usb_bus); + result = sscanf(buf, "%u\n", &val); + if (result == 1) { + usb_hcd->authorized_default = val? 1 : 0; + result = size; + } + else + result = -EINVAL; + return result; +} + +static DEVICE_ATTR(authorized_default, 0644, + usb_host_authorized_default_show, + usb_host_authorized_default_store); + + +/* Group all the USB bus attributes */ +static struct attribute *usb_bus_attrs[] = { + &dev_attr_authorized_default.attr, + NULL, +}; + +static struct attribute_group usb_bus_attr_group = { + .name = NULL, /* we want them in the same directory */ + .attrs = usb_bus_attrs, +}; + + + /*-------------------------------------------------------------------------*/ static struct class *usb_host_class; @@ -1542,7 +1602,6 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver, hcd->driver = driver; hcd->product_desc = (driver->product_desc) ? driver->product_desc : "USB Host Controller"; - return hcd; } EXPORT_SYMBOL (usb_create_hcd); @@ -1587,6 +1646,7 @@ int usb_add_hcd(struct usb_hcd *hcd, dev_info(hcd->self.controller, "%s\n", hcd->product_desc); + hcd->authorized_default = hcd->wireless? 0 : 1; set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); /* HC is in reset state, but accessible. Now do the one-time init, @@ -1663,10 +1723,20 @@ int usb_add_hcd(struct usb_hcd *hcd, if ((retval = register_root_hub(hcd)) != 0) goto err_register_root_hub; + retval = sysfs_create_group(&rhdev->dev.kobj, &usb_bus_attr_group); + if (retval < 0) { + printk(KERN_ERR "Cannot register USB bus sysfs attributes: %d\n", + retval); + goto error_create_attr_group; + } if (hcd->uses_new_polling && hcd->poll_rh) usb_hcd_poll_rh_status(hcd); return retval; +error_create_attr_group: + mutex_lock(&usb_bus_list_lock); + usb_disconnect(&hcd->self.root_hub); + mutex_unlock(&usb_bus_list_lock); err_register_root_hub: hcd->driver->stop(hcd); err_hcd_driver_start: @@ -1708,6 +1778,7 @@ void usb_remove_hcd(struct usb_hcd *hcd) cancel_work_sync(&hcd->wakeup_work); #endif + sysfs_remove_group(&hcd->self.root_hub->dev.kobj, &usb_bus_attr_group); mutex_lock(&usb_bus_list_lock); usb_disconnect(&hcd->self.root_hub); mutex_unlock(&usb_bus_list_lock); diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index b5ebb73c233..8683142e70e 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -51,6 +51,12 @@ * * Since "struct usb_bus" is so thin, you can't share much code in it. * This framework is a layer over that, and should be more sharable. + * + * @authorized_default: Specifies if new devices are authorized to + * connect by default or they require explicit + * user space authorization; this bit is settable + * through /sys/class/usb_host/X/authorized_default. + * For the rest is RO, so we don't lock to r/w it. */ /*-------------------------------------------------------------------------*/ @@ -90,6 +96,7 @@ struct usb_hcd { unsigned poll_rh:1; /* poll for rh status? */ unsigned poll_pending:1; /* status has changed? */ unsigned wireless:1; /* Wireless USB HCD */ + unsigned authorized_default:1; int irq; /* irq allocated */ void __iomem *regs; /* device memory/io */ -- cgit v1.2.3-70-g09d2 From eb579f5811ddbc052c8d6b3bba38dd4e5148cf7b Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Tue, 31 Jul 2007 20:33:59 -0700 Subject: usb: cleanup usb_register_bus() and hook up sysfs group This path cleans the exit paths of usb_register_bus() [to use a goto schema], maximum line length (keeping it under ~75). Signed-off-by: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 875e2476c1f..a5a46a55376 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -792,27 +792,23 @@ static void usb_bus_init (struct usb_bus *bus) */ static int usb_register_bus(struct usb_bus *bus) { + int result = -E2BIG; int busnum; mutex_lock(&usb_bus_list_lock); busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1); - if (busnum < USB_MAXBUS) { - set_bit (busnum, busmap.busmap); - bus->busnum = busnum; - } else { + if (busnum >= USB_MAXBUS) { printk (KERN_ERR "%s: too many buses\n", usbcore_name); - mutex_unlock(&usb_bus_list_lock); - return -E2BIG; + goto error_find_busnum; } - + set_bit (busnum, busmap.busmap); + bus->busnum = busnum; bus->class_dev = class_device_create(usb_host_class, NULL, MKDEV(0,0), - bus->controller, "usb_host%d", busnum); - if (IS_ERR(bus->class_dev)) { - clear_bit(busnum, busmap.busmap); - mutex_unlock(&usb_bus_list_lock); - return PTR_ERR(bus->class_dev); - } - + bus->controller, "usb_host%d", + busnum); + result = PTR_ERR(bus->class_dev); + if (IS_ERR(bus->class_dev)) + goto error_create_class_dev; class_set_devdata(bus->class_dev, bus); /* Add it to the local list of buses */ @@ -821,8 +817,15 @@ static int usb_register_bus(struct usb_bus *bus) usb_notify_add_bus(bus); - dev_info (bus->controller, "new USB bus registered, assigned bus number %d\n", bus->busnum); + dev_info (bus->controller, "new USB bus registered, assigned bus " + "number %d\n", bus->busnum); return 0; + +error_create_class_dev: + clear_bit(busnum, busmap.busmap); +error_find_busnum: + mutex_unlock(&usb_bus_list_lock); + return result; } /** -- cgit v1.2.3-70-g09d2 From d7d07255d3f5607802b0af29e11448d18e9ed558 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Tue, 31 Jul 2007 20:34:00 -0700 Subject: usb: initialize authorization and wusb bits in USB devices Signed-off-by: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/usb.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 67e2e582e46..e5ff161776f 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -223,6 +223,15 @@ static void ksuspend_usb_cleanup(void) #endif /* CONFIG_PM */ + +/* Returns 1 if @usb_bus is WUSB, 0 otherwise */ +static unsigned usb_bus_is_wusb(struct usb_bus *bus) +{ + struct usb_hcd *hcd = container_of(bus, struct usb_hcd, self); + return hcd->wireless; +} + + /** * usb_alloc_dev - usb device constructor (usbcore-internal) * @parent: hub to which device is connected; null to allocate a root hub @@ -239,6 +248,8 @@ struct usb_device * usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) { struct usb_device *dev; + struct usb_hcd *usb_hcd = container_of(bus, struct usb_hcd, self); + unsigned root_hub = 0; dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) @@ -275,6 +286,7 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) dev->dev.parent = bus->controller; sprintf(&dev->dev.bus_id[0], "usb%d", bus->busnum); + root_hub = 1; } else { /* match any labeling on the hubs; it's one-based */ if (parent->devpath[0] == '0') @@ -301,6 +313,12 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work); dev->autosuspend_delay = usb_autosuspend_delay * HZ; #endif + if (root_hub) /* Root hub always ok [and always wired] */ + dev->authorized = 1; + else { + dev->authorized = usb_hcd->authorized_default; + dev->wusb = usb_bus_is_wusb(bus)? 1 : 0; + } return dev; } -- cgit v1.2.3-70-g09d2 From 16bbab2966309ae82cda3d378964c56096d4858c Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Tue, 31 Jul 2007 20:34:01 -0700 Subject: usb: usb_set_configuration() obeys authorization Will refuse to configure a non-authorized device. Update: simplified if statement--thanks to Ragner Magalhaes for the heads up. Signed-off-by: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/message.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index a26a7292b61..025ac0bd353 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1483,6 +1483,9 @@ static struct usb_interface_assoc_descriptor *find_iad(struct usb_device *dev, * channels are available independently; and choosing between open * standard device protocols (like CDC) or proprietary ones. * + * Note that a non-authorized device (dev->authorized == 0) will only + * be put in unconfigured mode. + * * Note that USB has an additional level of device configurability, * associated with interfaces. That configurability is accessed using * usb_set_interface(). @@ -1504,7 +1507,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration) struct usb_interface **new_interfaces = NULL; int n, nintf; - if (configuration == -1) + if (dev->authorized == 0 || configuration == -1) configuration = 0; else { for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { -- cgit v1.2.3-70-g09d2 From 1145065cd0434b0fd5cd7c0efe0f1438fb154ed0 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Tue, 31 Jul 2007 20:34:02 -0700 Subject: usb: usb_get_configuration() obeys authorization If called and the device is not authorized to be used, then we don't allow reading the configurations. Signed-off-by: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/config.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index cb69aa1e02e..1a8edcee7f3 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -507,18 +507,30 @@ void usb_destroy_configuration(struct usb_device *dev) } -// hub-only!! ... and only in reset path, or usb_new_device() -// (used by real hubs and virtual root hubs) +/* + * Get the USB config descriptors, cache and parse'em + * + * hub-only!! ... and only in reset path, or usb_new_device() + * (used by real hubs and virtual root hubs) + * + * NOTE: if this is a WUSB device and is not authorized, we skip the + * whole thing. A non-authorized USB device has no + * configurations. + */ int usb_get_configuration(struct usb_device *dev) { struct device *ddev = &dev->dev; int ncfg = dev->descriptor.bNumConfigurations; - int result = -ENOMEM; + int result = 0; unsigned int cfgno, length; unsigned char *buffer; unsigned char *bigbuffer; struct usb_config_descriptor *desc; + cfgno = 0; + if (dev->authorized == 0) /* Not really an error */ + goto out_not_authorized; + result = -ENOMEM; if (ncfg > USB_MAXCONFIG) { dev_warn(ddev, "too many configurations: %d, " "using maximum allowed: %d\n", ncfg, USB_MAXCONFIG); @@ -545,14 +557,15 @@ int usb_get_configuration(struct usb_device *dev) goto err2; desc = (struct usb_config_descriptor *)buffer; - for (cfgno = 0; cfgno < ncfg; cfgno++) { + result = 0; + for (; cfgno < ncfg; cfgno++) { /* We grab just the first descriptor so we know how long * the whole configuration is */ result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, USB_DT_CONFIG_SIZE); if (result < 0) { dev_err(ddev, "unable to read config index %d " - "descriptor/%s\n", cfgno, "start"); + "descriptor/%s: %d\n", cfgno, "start", result); dev_err(ddev, "chopping to %d config(s)\n", cfgno); dev->descriptor.bNumConfigurations = cfgno; break; @@ -599,6 +612,7 @@ int usb_get_configuration(struct usb_device *dev) err: kfree(buffer); +out_not_authorized: dev->descriptor.bNumConfigurations = cfgno; err2: if (result == -ENOMEM) -- cgit v1.2.3-70-g09d2 From 72230abb21349cda54d6cce0d6fd325c023b958e Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Tue, 31 Jul 2007 20:34:03 -0700 Subject: usb: usb_probe_interface() obeys authorization If called and the device is not authorized to be used, it won't configure the interface and print a message saying so. Signed-off-by: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/driver.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 63b1243a913..8da4801bb92 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -202,6 +202,11 @@ static int usb_probe_interface(struct device *dev) intf = to_usb_interface(dev); udev = interface_to_usbdev(intf); + if (udev->authorized == 0) { + dev_err(&intf->dev, "Device is not authorized for usage\n"); + return -ENODEV; + } + id = usb_match_id(intf, driver->id_table); if (!id) id = usb_match_dynamic_id(intf, driver); -- cgit v1.2.3-70-g09d2 From f8a374648b58e5cfa14447eca866aed14a4fbfa8 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Tue, 31 Jul 2007 20:34:04 -0700 Subject: usb: usb_generic_probe() obeys authorization If called and the device is not authorized to be used, then we won't choose a configuration (as they are not a concept that exists for an unauthorized device). However, the device is added to the system. Signed-off-by: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/generic.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index b2fc2b11525..20b095050a1 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -161,17 +161,20 @@ static int generic_probe(struct usb_device *udev) /* Choose and set the configuration. This registers the interfaces * with the driver core and lets interface drivers bind to them. */ - c = choose_configuration(udev); - if (c >= 0) { - err = usb_set_configuration(udev, c); - if (err) { - dev_err(&udev->dev, "can't set config #%d, error %d\n", + if (udev->authorized == 0) + dev_err(&udev->dev, "Device is not authorized for usage\n"); + else { + c = choose_configuration(udev); + if (c >= 0) { + err = usb_set_configuration(udev, c); + if (err) { + dev_err(&udev->dev, "can't set config #%d, error %d\n", c, err); - /* This need not be fatal. The user can try to - * set other configurations. */ + /* This need not be fatal. The user can try to + * set other configurations. */ + } } } - /* USB device state == configured ... usable */ usb_notify_add_device(udev); -- cgit v1.2.3-70-g09d2 From d9d16e8a92e385c9f57d2081b7aa737770a0a829 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Tue, 31 Jul 2007 20:34:05 -0700 Subject: usb: split usb_new_device for clarity and refactoring This patch takes hub.c:usb_new_device() and splits it in three parts: - The actual actions of adding a new device (quirk detection, announcement and autoresume tracking) - Actual discovery and probing of the configuration and interfaces (split into __usb_configure_device()) - Configuration of the On-the-go parameters (split into __usb_configure_device_otg()). The fundamental reasons for doing this split are clarity (smaller functions are easier to maintain) and to allow part of the code to be reused when authorizing devices to connect. When a device is authorized connection, we need to run through the hoops we didn't run when it was connected but not authorized, which is basically parsing the configurations and probing them. usb_configure_device() will do that for us. Signed-off-by: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 136 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 88 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 34be27a6cbb..65d9ea1e6d7 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1220,54 +1220,14 @@ static inline void show_string(struct usb_device *udev, char *id, char *string) #endif /** - * usb_new_device - perform initial device setup (usbcore-internal) + * usb_configure_device_otg - FIXME (usbcore-internal) * @udev: newly addressed device (in ADDRESS state) * - * This is called with devices which have been enumerated, but not yet - * configured. The device descriptor is available, but not descriptors - * for any device configuration. The caller must have locked either - * the parent hub (if udev is a normal device) or else the - * usb_bus_list_lock (if udev is a root hub). The parent's pointer to - * udev has already been installed, but udev is not yet visible through - * sysfs or other filesystem code. - * - * It will return if the device is configured properly or not. Zero if - * the interface was registered with the driver core; else a negative - * errno value. - * - * This call is synchronous, and may not be used in an interrupt context. - * - * Only the hub driver or root-hub registrar should ever call this. + * Do configuration for On-The-Go devices */ -int usb_new_device(struct usb_device *udev) +static int usb_configure_device_otg(struct usb_device *udev) { - int err; - - /* Determine quirks */ - usb_detect_quirks(udev); - - err = usb_get_configuration(udev); - if (err < 0) { - dev_err(&udev->dev, "can't read configurations, error %d\n", - err); - goto fail; - } - - /* read the standard strings and cache them if present */ - udev->product = usb_cache_string(udev, udev->descriptor.iProduct); - udev->manufacturer = usb_cache_string(udev, - udev->descriptor.iManufacturer); - udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber); - - /* Tell the world! */ - dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, " - "SerialNumber=%d\n", - udev->descriptor.iManufacturer, - udev->descriptor.iProduct, - udev->descriptor.iSerialNumber); - show_string(udev, "Product", udev->product); - show_string(udev, "Manufacturer", udev->manufacturer); - show_string(udev, "SerialNumber", udev->serial); + int err = 0; #ifdef CONFIG_USB_OTG /* @@ -1329,8 +1289,82 @@ int usb_new_device(struct usb_device *udev) err = -ENOTSUPP; goto fail; } +fail: #endif + return err; +} + +/** + * usb_configure_device - Detect and probe device intfs/otg (usbcore-internal) + * @udev: newly addressed device (in ADDRESS state) + * + * This is only called by usb_new_device() and usb_authorize_device() + * and FIXME -- all comments that apply to them apply here wrt to + * environment. + * + * If the device is WUSB and not authorized, we don't attempt to read + * the string descriptors, as they will be errored out by the device + * until it has been authorized. + */ +static int usb_configure_device(struct usb_device *udev) +{ + int err; + + if (udev->config == NULL) { + err = usb_get_configuration(udev); + if (err < 0) { + dev_err(&udev->dev, "can't read configurations, error %d\n", + err); + goto fail; + } + } + if (udev->wusb == 1 && udev->authorized == 0) { + udev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL); + udev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL); + udev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL); + } + else { + /* read the standard strings and cache them if present */ + udev->product = usb_cache_string(udev, udev->descriptor.iProduct); + udev->manufacturer = usb_cache_string(udev, + udev->descriptor.iManufacturer); + udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber); + } + err = usb_configure_device_otg(udev); +fail: + return err; +} + + +/** + * usb_new_device - perform initial device setup (usbcore-internal) + * @udev: newly addressed device (in ADDRESS state) + * + * This is called with devices which have been enumerated, but not yet + * configured. The device descriptor is available, but not descriptors + * for any device configuration. The caller must have locked either + * the parent hub (if udev is a normal device) or else the + * usb_bus_list_lock (if udev is a root hub). The parent's pointer to + * udev has already been installed, but udev is not yet visible through + * sysfs or other filesystem code. + * + * It will return if the device is configured properly or not. Zero if + * the interface was registered with the driver core; else a negative + * errno value. + * + * This call is synchronous, and may not be used in an interrupt context. + * + * Only the hub driver or root-hub registrar should ever call this. + */ +int usb_new_device(struct usb_device *udev) +{ + int err; + + usb_detect_quirks(udev); /* Determine quirks */ + err = usb_configure_device(udev); /* detect & probe dev/intfs */ + if (err < 0) + goto fail; /* export the usbdev device-node for libusb */ udev->dev.devt = MKDEV(USB_DEVICE_MAJOR, (((udev->bus->busnum-1) * 128) + (udev->devnum-1))); @@ -1346,17 +1380,23 @@ int usb_new_device(struct usb_device *udev) err = device_add(&udev->dev); if (err) { dev_err(&udev->dev, "can't device_add, error %d\n", err); - if (udev->parent) - usb_autosuspend_device(udev->parent); goto fail; } -exit: + /* Tell the world! */ + dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, " + "SerialNumber=%d\n", + udev->descriptor.iManufacturer, + udev->descriptor.iProduct, + udev->descriptor.iSerialNumber); + show_string(udev, "Product", udev->product); + show_string(udev, "Manufacturer", udev->manufacturer); + show_string(udev, "SerialNumber", udev->serial); return err; fail: usb_set_device_state(udev, USB_STATE_NOTATTACHED); - goto exit; + return err; } static int hub_port_status(struct usb_hub *hub, int port1, -- cgit v1.2.3-70-g09d2 From 93993a0a3e528357ae4b9b0eb82fd4b428ebbf64 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Tue, 31 Jul 2007 20:34:06 -0700 Subject: usb: introduce usb_authorize/deauthorize() These USB API functions will do the full authorization/deauthorization to be used for a device. When authorized we effectively allow a configuration to be set. Reverse that when deauthorized. Effectively this means that we have to clean all the configuration descriptors on deauthorize and reload them when we authorized. We could do without throwing them out for wired devices, but for wireless, we can read them only after authenticating, and thus, when authorizing an authenticated device we would need to read them. So to simplify, always release them on deauthorize(), re-read them on authorize(). Also fix leak reported by Ragner Magalhaes; in usb_deauthorize_device(), bNumConfigurations was being set to zero before the for loop, and thus the different raw descriptors where never being freed. Signed-off-by: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/generic.c | 2 +- drivers/usb/core/hub.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/usb/core/usb.h | 3 ++ 3 files changed, 85 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index 20b095050a1..7b9e1ec718d 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -40,7 +40,7 @@ static int is_activesync(struct usb_interface_descriptor *desc) && desc->bInterfaceProtocol == 1; } -static int choose_configuration(struct usb_device *udev) +int choose_configuration(struct usb_device *udev) { int i; int num_configs; diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 65d9ea1e6d7..f725d9e62b5 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1399,6 +1399,87 @@ fail: return err; } + +/** + * Similar to usb_disconnect() + * + * We share a lock (that we have) with device_del(), so we need to + * defer its call. + */ +int usb_deauthorize_device(struct usb_device *usb_dev) +{ + unsigned cnt; + usb_lock_device(usb_dev); + if (usb_dev->authorized == 0) + goto out_unauthorized; + usb_dev->authorized = 0; + usb_set_configuration(usb_dev, -1); + usb_dev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL); + usb_dev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL); + usb_dev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL); + kfree(usb_dev->config); + usb_dev->config = NULL; + for (cnt = 0; cnt < usb_dev->descriptor.bNumConfigurations; cnt++) + kfree(usb_dev->rawdescriptors[cnt]); + usb_dev->descriptor.bNumConfigurations = 0; + kfree(usb_dev->rawdescriptors); +out_unauthorized: + usb_unlock_device(usb_dev); + return 0; +} + + +int usb_authorize_device(struct usb_device *usb_dev) +{ + int result = 0, c; + usb_lock_device(usb_dev); + if (usb_dev->authorized == 1) + goto out_authorized; + kfree(usb_dev->product); + usb_dev->product = NULL; + kfree(usb_dev->manufacturer); + usb_dev->manufacturer = NULL; + kfree(usb_dev->serial); + usb_dev->serial = NULL; + result = usb_autoresume_device(usb_dev); + if (result < 0) { + dev_err(&usb_dev->dev, + "can't autoresume for authorization: %d\n", result); + goto error_autoresume; + } + result = usb_get_device_descriptor(usb_dev, sizeof(usb_dev->descriptor)); + if (result < 0) { + dev_err(&usb_dev->dev, "can't re-read device descriptor for " + "authorization: %d\n", result); + goto error_device_descriptor; + } + usb_dev->authorized = 1; + result = usb_configure_device(usb_dev); + if (result < 0) + goto error_configure; + /* Choose and set the configuration. This registers the interfaces + * with the driver core and lets interface drivers bind to them. + */ + c = choose_configuration(usb_dev); + if (c >= 0) { + result = usb_set_configuration(usb_dev, c); + if (result) { + dev_err(&usb_dev->dev, + "can't set config #%d, error %d\n", c, result); + /* This need not be fatal. The user can try to + * set other configurations. */ + } + } + dev_info(&usb_dev->dev, "authorized to connect\n"); +error_configure: +error_device_descriptor: +error_autoresume: +out_authorized: + usb_unlock_device(usb_dev); // complements locktree + return result; +} + + static int hub_port_status(struct usb_hub *hub, int port1, u16 *status, u16 *change) { diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index cde6e52b84f..e22ec7f8eb1 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -15,12 +15,15 @@ extern void usb_disable_interface (struct usb_device *dev, struct usb_interface *intf); extern void usb_release_interface_cache(struct kref *ref); extern void usb_disable_device (struct usb_device *dev, int skip_ep0); +extern int usb_deauthorize_device (struct usb_device *); +extern int usb_authorize_device (struct usb_device *); extern void usb_detect_quirks(struct usb_device *udev); extern int usb_get_device_descriptor(struct usb_device *dev, unsigned int size); extern char *usb_cache_string(struct usb_device *udev, int index); extern int usb_set_configuration(struct usb_device *dev, int configuration); +extern int choose_configuration(struct usb_device *udev); extern void usb_kick_khubd(struct usb_device *dev); extern int usb_match_device(struct usb_device *dev, -- cgit v1.2.3-70-g09d2 From e03f2e8a530e0ed46af43093e23a70b7c7215263 Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Tue, 31 Jul 2007 20:34:07 -0700 Subject: usb: hook up device authorization to sysfs Makes it possible to control the authorization of USB devices through sysfs's /sys/usb/devices/*/authorize. Update: per Adrian Bunk's suggestion, make dev_attr_authorized_default static Signed-off-by: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/sysfs.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 2ab222be8fd..e02590297d3 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -413,6 +413,44 @@ usb_descriptor_attr(bDeviceProtocol, "%02x\n") usb_descriptor_attr(bNumConfigurations, "%d\n") usb_descriptor_attr(bMaxPacketSize0, "%d\n") + + +/* show if the device is authorized (1) or not (0) */ +static ssize_t usb_dev_authorized_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct usb_device *usb_dev = to_usb_device(dev); + return snprintf(buf, PAGE_SIZE, "%u\n", usb_dev->authorized); +} + + +/* + * Authorize a device to be used in the system + * + * Writing a 0 deauthorizes the device, writing a 1 authorizes it. + */ +static ssize_t usb_dev_authorized_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + ssize_t result; + struct usb_device *usb_dev = to_usb_device(dev); + unsigned val; + result = sscanf(buf, "%u\n", &val); + if (result != 1) + result = -EINVAL; + else if (val == 0) + result = usb_deauthorize_device(usb_dev); + else + result = usb_authorize_device(usb_dev); + return result < 0? result : size; +} + +static DEVICE_ATTR(authorized, 0644, + usb_dev_authorized_show, usb_dev_authorized_store); + + static struct attribute *dev_attrs[] = { /* current configuration's attributes */ &dev_attr_configuration.attr, @@ -435,6 +473,7 @@ static struct attribute *dev_attrs[] = { &dev_attr_version.attr, &dev_attr_maxchild.attr, &dev_attr_quirks.attr, + &dev_attr_authorized.attr, NULL, }; static struct attribute_group dev_attr_grp = { -- cgit v1.2.3-70-g09d2 From b5ea060f1e19c6a3f409d3472c723da4517547b8 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 2 Aug 2007 22:44:27 -0600 Subject: USB: rename choose_configuration As it is global, give it a usb specific name in the global namespace. Cc: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/generic.c | 4 ++-- drivers/usb/core/hub.c | 2 +- drivers/usb/core/usb.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index 7b9e1ec718d..9148b69785c 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -40,7 +40,7 @@ static int is_activesync(struct usb_interface_descriptor *desc) && desc->bInterfaceProtocol == 1; } -int choose_configuration(struct usb_device *udev) +int usb_choose_configuration(struct usb_device *udev) { int i; int num_configs; @@ -164,7 +164,7 @@ static int generic_probe(struct usb_device *udev) if (udev->authorized == 0) dev_err(&udev->dev, "Device is not authorized for usage\n"); else { - c = choose_configuration(udev); + c = usb_choose_configuration(udev); if (c >= 0) { err = usb_set_configuration(udev, c); if (err) { diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index f725d9e62b5..4c495c4d505 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1460,7 +1460,7 @@ int usb_authorize_device(struct usb_device *usb_dev) /* Choose and set the configuration. This registers the interfaces * with the driver core and lets interface drivers bind to them. */ - c = choose_configuration(usb_dev); + c = usb_choose_configuration(usb_dev); if (c >= 0) { result = usb_set_configuration(usb_dev, c); if (result) { diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index e22ec7f8eb1..c52626c51f7 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -23,7 +23,7 @@ extern int usb_get_device_descriptor(struct usb_device *dev, unsigned int size); extern char *usb_cache_string(struct usb_device *udev, int index); extern int usb_set_configuration(struct usb_device *dev, int configuration); -extern int choose_configuration(struct usb_device *udev); +extern int usb_choose_configuration(struct usb_device *udev); extern void usb_kick_khubd(struct usb_device *dev); extern int usb_match_device(struct usb_device *dev, -- cgit v1.2.3-70-g09d2 From b0e396e3097ce4914c643bc3f0c2fe0098f551eb Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 2 Aug 2007 22:44:27 -0600 Subject: USB: make usb_release_interface static No one else calls it, this makes sparse happy. Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/message.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 025ac0bd353..c905b35d4f8 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1330,7 +1330,7 @@ int usb_reset_configuration(struct usb_device *dev) return 0; } -void usb_release_interface(struct device *dev) +static void usb_release_interface(struct device *dev) { struct usb_interface *intf = to_usb_interface(dev); struct usb_interface_cache *intfc = -- cgit v1.2.3-70-g09d2 From e9df41c5c5899259541dc928872cad4d07b82076 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 8 Aug 2007 11:48:02 -0400 Subject: USB: make HCDs responsible for managing endpoint queues This patch (as954) implements a suggestion of David Brownell's. Now the host controller drivers are responsible for linking and unlinking URBs to/from their endpoint queues. This eliminates the possiblity of strange situations where usbcore thinks an URB is linked but the HCD thinks it isn't. It also means HCDs no longer have to check for URBs being dequeued before they were fully enqueued. In addition to the core changes, this requires changing every host controller driver and the root-hub URB handler. For the most part the required changes are fairly small; drivers have to call usb_hcd_link_urb_to_ep() in their urb_enqueue method, usb_hcd_check_unlink_urb() in their urb_dequeue method, and usb_hcd_unlink_urb_from_ep() before giving URBs back. A few HCDs make matters more complicated by the way they split up the flow of control. In addition some method interfaces get changed. The endpoint argument for urb_enqueue is now redundant so it is removed. The unlink status is required by usb_hcd_check_unlink_urb(), so it has been added to urb_dequeue. Signed-off-by: Alan Stern CC: David Brownell CC: Olav Kongas CC: Tony Olech CC: Yoshihiro Shimoda Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 255 +++++++++++++++++++++------------------- drivers/usb/core/hcd.h | 14 ++- drivers/usb/gadget/dummy_hcd.c | 22 +++- drivers/usb/host/ehci-hcd.c | 14 ++- drivers/usb/host/ehci-q.c | 14 ++- drivers/usb/host/ehci-sched.c | 43 +++++-- drivers/usb/host/isp116x-hcd.c | 31 +++-- drivers/usb/host/ohci-hcd.c | 32 +++-- drivers/usb/host/ohci-q.c | 1 + drivers/usb/host/r8a66597-hcd.c | 37 ++++-- drivers/usb/host/sl811-hcd.c | 26 ++-- drivers/usb/host/u132-hcd.c | 170 +++++++++++++++++++-------- drivers/usb/host/uhci-q.c | 32 ++--- 13 files changed, 420 insertions(+), 271 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index a5a46a55376..a853f63b925 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -356,11 +356,17 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) const u8 *bufp = tbuf; int len = 0; int patch_wakeup = 0; - int status = 0; + int status; int n; might_sleep(); + spin_lock_irq(&hcd_root_hub_lock); + status = usb_hcd_link_urb_to_ep(hcd, urb); + spin_unlock_irq(&hcd_root_hub_lock); + if (status) + return status; + cmd = (struct usb_ctrlrequest *) urb->setup_packet; typeReq = (cmd->bRequestType << 8) | cmd->bRequest; wValue = le16_to_cpu (cmd->wValue); @@ -525,10 +531,9 @@ error: /* any errors get returned through the urb completion */ spin_lock_irq(&hcd_root_hub_lock); - spin_lock(&urb->lock); if (urb->status == -EINPROGRESS) urb->status = status; - spin_unlock(&urb->lock); + usb_hcd_unlink_urb_from_ep(hcd, urb); /* This peculiar use of spinlocks echoes what real HC drivers do. * Avoiding calls to local_irq_disable/enable makes the code @@ -571,26 +576,21 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd) spin_lock_irqsave(&hcd_root_hub_lock, flags); urb = hcd->status_urb; if (urb) { - spin_lock(&urb->lock); - if (urb->status == -EINPROGRESS) { - hcd->poll_pending = 0; - hcd->status_urb = NULL; - urb->status = 0; - urb->hcpriv = NULL; - urb->actual_length = length; - memcpy(urb->transfer_buffer, buffer, length); - } else /* urb has been unlinked */ - length = 0; - spin_unlock(&urb->lock); + hcd->poll_pending = 0; + hcd->status_urb = NULL; + urb->status = 0; + urb->hcpriv = NULL; + urb->actual_length = length; + memcpy(urb->transfer_buffer, buffer, length); + usb_hcd_unlink_urb_from_ep(hcd, urb); spin_unlock(&hcd_root_hub_lock); usb_hcd_giveback_urb(hcd, urb); spin_lock(&hcd_root_hub_lock); - } else + } else { length = 0; - - if (length <= 0) hcd->poll_pending = 1; + } spin_unlock_irqrestore(&hcd_root_hub_lock, flags); } @@ -619,24 +619,26 @@ static int rh_queue_status (struct usb_hcd *hcd, struct urb *urb) int len = 1 + (urb->dev->maxchild / 8); spin_lock_irqsave (&hcd_root_hub_lock, flags); - if (urb->status != -EINPROGRESS) /* already unlinked */ - retval = urb->status; - else if (hcd->status_urb || urb->transfer_buffer_length < len) { + if (hcd->status_urb || urb->transfer_buffer_length < len) { dev_dbg (hcd->self.controller, "not queuing rh status urb\n"); retval = -EINVAL; - } else { - hcd->status_urb = urb; - urb->hcpriv = hcd; /* indicate it's queued */ + goto done; + } - if (!hcd->uses_new_polling) - mod_timer (&hcd->rh_timer, - (jiffies/(HZ/4) + 1) * (HZ/4)); + retval = usb_hcd_link_urb_to_ep(hcd, urb); + if (retval) + goto done; - /* If a status change has already occurred, report it ASAP */ - else if (hcd->poll_pending) - mod_timer (&hcd->rh_timer, jiffies); - retval = 0; - } + hcd->status_urb = urb; + urb->hcpriv = hcd; /* indicate it's queued */ + if (!hcd->uses_new_polling) + mod_timer(&hcd->rh_timer, (jiffies/(HZ/4) + 1) * (HZ/4)); + + /* If a status change has already occurred, report it ASAP */ + else if (hcd->poll_pending) + mod_timer(&hcd->rh_timer, jiffies); + retval = 0; + done: spin_unlock_irqrestore (&hcd_root_hub_lock, flags); return retval; } @@ -655,11 +657,16 @@ static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb) /* Unlinks of root-hub control URBs are legal, but they don't do anything * since these URBs always execute synchronously. */ -static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) +static int usb_rh_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { unsigned long flags; + int rc; spin_lock_irqsave(&hcd_root_hub_lock, flags); + rc = usb_hcd_check_unlink_urb(hcd, urb, status); + if (rc) + goto done; + if (usb_endpoint_num(&urb->ep->desc) == 0) { /* Control URB */ ; /* Do nothing */ @@ -669,14 +676,16 @@ static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) if (urb == hcd->status_urb) { hcd->status_urb = NULL; urb->hcpriv = NULL; + usb_hcd_unlink_urb_from_ep(hcd, urb); spin_unlock(&hcd_root_hub_lock); usb_hcd_giveback_urb(hcd, urb); spin_lock(&hcd_root_hub_lock); } } + done: spin_unlock_irqrestore(&hcd_root_hub_lock, flags); - return 0; + return rc; } @@ -977,12 +986,26 @@ EXPORT_SYMBOL (usb_calc_bus_time); /*-------------------------------------------------------------------------*/ -static int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb) +/** + * usb_hcd_link_urb_to_ep - add an URB to its endpoint queue + * @hcd: host controller to which @urb was submitted + * @urb: URB being submitted + * + * Host controller drivers should call this routine in their enqueue() + * method. The HCD's private spinlock must be held and interrupts must + * be disabled. The actions carried out here are required for URB + * submission, as well as for endpoint shutdown and for usb_kill_urb. + * + * Returns 0 for no error, otherwise a negative error code (in which case + * the enqueue() method must fail). If no error occurs but enqueue() fails + * anyway, it must call usb_hcd_unlink_urb_from_ep() before releasing + * the private spinlock and returning. + */ +int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb) { - unsigned long flags; int rc = 0; - spin_lock_irqsave(&hcd_urb_list_lock, flags); + spin_lock(&hcd_urb_list_lock); /* Check that the URB isn't being killed */ if (unlikely(urb->reject)) { @@ -1009,48 +1032,48 @@ static int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb) goto done; } done: - spin_unlock_irqrestore(&hcd_urb_list_lock, flags); + spin_unlock(&hcd_urb_list_lock); return rc; } +EXPORT_SYMBOL_GPL(usb_hcd_link_urb_to_ep); -static int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb, +/** + * usb_hcd_check_unlink_urb - check whether an URB may be unlinked + * @hcd: host controller to which @urb was submitted + * @urb: URB being checked for unlinkability + * @status: error code to store in @urb if the unlink succeeds + * + * Host controller drivers should call this routine in their dequeue() + * method. The HCD's private spinlock must be held and interrupts must + * be disabled. The actions carried out here are required for making + * sure than an unlink is valid. + * + * Returns 0 for no error, otherwise a negative error code (in which case + * the dequeue() method must fail). The possible error codes are: + * + * -EIDRM: @urb was not submitted or has already completed. + * The completion function may not have been called yet. + * + * -EBUSY: @urb has already been unlinked. + */ +int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb, int status) { - unsigned long flags; struct list_head *tmp; - int rc = 0; - - /* - * we contend for urb->status with the hcd core, - * which changes it while returning the urb. - * - * Caller guaranteed that the urb pointer hasn't been freed, and - * that it was submitted. But as a rule it can't know whether or - * not it's already been unlinked ... so we respect the reversed - * lock sequence needed for the usb_hcd_giveback_urb() code paths - * (urb lock, then hcd_urb_list_lock) in case some other CPU is now - * unlinking it. - */ - spin_lock_irqsave(&urb->lock, flags); - spin_lock(&hcd_urb_list_lock); /* insist the urb is still queued */ list_for_each(tmp, &urb->ep->urb_list) { if (tmp == &urb->urb_list) break; } - if (tmp != &urb->urb_list) { - rc = -EIDRM; - goto done; - } + if (tmp != &urb->urb_list) + return -EIDRM; /* Any status except -EINPROGRESS means something already started to * unlink this URB from the hardware. So there's no more work to do. */ - if (urb->status != -EINPROGRESS) { - rc = -EBUSY; - goto done; - } + if (urb->status != -EINPROGRESS) + return -EBUSY; urb->status = status; /* IRQ setup can easily be broken so that USB controllers @@ -1065,21 +1088,28 @@ static int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb, set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); } - done: - spin_unlock(&hcd_urb_list_lock); - spin_unlock_irqrestore (&urb->lock, flags); - return rc; + return 0; } +EXPORT_SYMBOL_GPL(usb_hcd_check_unlink_urb); -static void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb) +/** + * usb_hcd_unlink_urb_from_ep - remove an URB from its endpoint queue + * @hcd: host controller to which @urb was submitted + * @urb: URB being unlinked + * + * Host controller drivers should call this routine before calling + * usb_hcd_giveback_urb(). The HCD's private spinlock must be held and + * interrupts must be disabled. The actions carried out here are required + * for URB completion. + */ +void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb) { - unsigned long flags; - /* clear all state linking urb to this dev (and hcd) */ - spin_lock_irqsave(&hcd_urb_list_lock, flags); + spin_lock(&hcd_urb_list_lock); list_del_init(&urb->urb_list); - spin_unlock_irqrestore(&hcd_urb_list_lock, flags); + spin_unlock(&hcd_urb_list_lock); } +EXPORT_SYMBOL_GPL(usb_hcd_unlink_urb_from_ep); static void map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) { @@ -1153,20 +1183,15 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) * URBs must be submitted in process context with interrupts * enabled. */ - status = usb_hcd_link_urb_to_ep(hcd, urb); - if (!status) { - map_urb_for_dma(hcd, urb); - if (is_root_hub(urb->dev)) - status = rh_urb_enqueue(hcd, urb); - else - status = hcd->driver->urb_enqueue(hcd, urb->ep, urb, - mem_flags); - } + map_urb_for_dma(hcd, urb); + if (is_root_hub(urb->dev)) + status = rh_urb_enqueue(hcd, urb); + else + status = hcd->driver->urb_enqueue(hcd, urb, mem_flags); if (unlikely(status)) { usbmon_urb_submit_error(&hcd->self, urb, status); unmap_urb_for_dma(hcd, urb); - usb_hcd_unlink_urb_from_ep(hcd, urb); INIT_LIST_HEAD(&urb->urb_list); atomic_dec(&urb->use_count); if (urb->reject) @@ -1183,24 +1208,19 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) * soon as practical. we've already set up the urb's return status, * but we can't know if the callback completed already. */ -static int -unlink1 (struct usb_hcd *hcd, struct urb *urb) +static int unlink1(struct usb_hcd *hcd, struct urb *urb, int status) { int value; if (is_root_hub(urb->dev)) - value = usb_rh_urb_dequeue (hcd, urb); + value = usb_rh_urb_dequeue(hcd, urb, status); else { /* The only reason an HCD might fail this call is if * it has not yet fully queued the urb to begin with. * Such failures should be harmless. */ - value = hcd->driver->urb_dequeue (hcd, urb); + value = hcd->driver->urb_dequeue(hcd, urb, status); } - - if (value != 0) - dev_dbg (hcd->self.controller, "dequeue %p --> %d\n", - urb, value); return value; } @@ -1216,14 +1236,11 @@ int usb_hcd_unlink_urb (struct urb *urb, int status) int retval; hcd = bus_to_hcd(urb->dev->bus); - - retval = usb_hcd_check_unlink_urb(hcd, urb, status); - if (!retval) - retval = unlink1(hcd, urb); + retval = unlink1(hcd, urb, status); if (retval == 0) retval = -EINPROGRESS; - else if (retval != -EIDRM) + else if (retval != -EIDRM && retval != -EBUSY) dev_dbg(&urb->dev->dev, "hcd_unlink_urb %p fail %d\n", urb, retval); return retval; @@ -1245,7 +1262,6 @@ int usb_hcd_unlink_urb (struct urb *urb, int status) */ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb) { - usb_hcd_unlink_urb_from_ep(hcd, urb); unmap_urb_for_dma(hcd, urb); usbmon_urb_complete (&hcd->self, urb); usb_unanchor_urb(urb); @@ -1282,7 +1298,6 @@ void usb_hcd_endpoint_disable (struct usb_device *udev, rescan: spin_lock_irq(&hcd_urb_list_lock); list_for_each_entry (urb, &ep->urb_list, urb_list) { - int tmp; int is_in; /* the urb may already have been unlinked */ @@ -1292,34 +1307,26 @@ rescan: is_in = usb_urb_dir_in(urb); spin_unlock(&hcd_urb_list_lock); - spin_lock (&urb->lock); - tmp = urb->status; - if (tmp == -EINPROGRESS) - urb->status = -ESHUTDOWN; - spin_unlock (&urb->lock); - - /* kick hcd unless it's already returning this */ - if (tmp == -EINPROGRESS) { - unlink1 (hcd, urb); - dev_dbg (hcd->self.controller, - "shutdown urb %p ep%d%s%s\n", - urb, usb_endpoint_num(&ep->desc), - is_in ? "in" : "out", - ({ char *s; - - switch (usb_endpoint_type(&ep->desc)) { - case USB_ENDPOINT_XFER_CONTROL: - s = ""; break; - case USB_ENDPOINT_XFER_BULK: - s = "-bulk"; break; - case USB_ENDPOINT_XFER_INT: - s = "-intr"; break; - default: - s = "-iso"; break; - }; - s; - })); - } + /* kick hcd */ + unlink1(hcd, urb, -ESHUTDOWN); + dev_dbg (hcd->self.controller, + "shutdown urb %p ep%d%s%s\n", + urb, usb_endpoint_num(&ep->desc), + is_in ? "in" : "out", + ({ char *s; + + switch (usb_endpoint_type(&ep->desc)) { + case USB_ENDPOINT_XFER_CONTROL: + s = ""; break; + case USB_ENDPOINT_XFER_BULK: + s = "-bulk"; break; + case USB_ENDPOINT_XFER_INT: + s = "-intr"; break; + default: + s = "-iso"; break; + }; + s; + })); usb_put_urb (urb); /* list contents may have changed */ diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 8683142e70e..745be2566f6 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -189,11 +189,10 @@ struct hc_driver { int (*get_frame_number) (struct usb_hcd *hcd); /* manage i/o requests, device state */ - int (*urb_enqueue) (struct usb_hcd *hcd, - struct usb_host_endpoint *ep, - struct urb *urb, - gfp_t mem_flags); - int (*urb_dequeue) (struct usb_hcd *hcd, struct urb *urb); + int (*urb_enqueue)(struct usb_hcd *hcd, + struct urb *urb, gfp_t mem_flags); + int (*urb_dequeue)(struct usb_hcd *hcd, + struct urb *urb, int status); /* hw synch, freeing endpoint resources that urb_dequeue can't */ void (*endpoint_disable)(struct usb_hcd *hcd, @@ -211,6 +210,11 @@ struct hc_driver { /* Needed only if port-change IRQs are level-triggered */ }; +extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb); +extern int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb, + int status); +extern void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb); + extern int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags); extern int usb_hcd_unlink_urb (struct urb *urb, int status); extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb); diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index d008d1360a7..c441d10c087 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -962,13 +962,13 @@ static struct platform_driver dummy_udc_driver = { static int dummy_urb_enqueue ( struct usb_hcd *hcd, - struct usb_host_endpoint *ep, struct urb *urb, gfp_t mem_flags ) { struct dummy *dum; struct urbp *urbp; unsigned long flags; + int rc; if (!urb->transfer_buffer && urb->transfer_buffer_length) return -EINVAL; @@ -980,6 +980,11 @@ static int dummy_urb_enqueue ( dum = hcd_to_dummy (hcd); spin_lock_irqsave (&dum->lock, flags); + rc = usb_hcd_link_urb_to_ep(hcd, urb); + if (rc) { + kfree(urbp); + goto done; + } if (!dum->udev) { dum->udev = urb->dev; @@ -997,22 +1002,28 @@ static int dummy_urb_enqueue ( mod_timer (&dum->timer, jiffies + 1); spin_unlock_irqrestore (&dum->lock, flags); - return 0; + done: + return rc; } -static int dummy_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) +static int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { struct dummy *dum; unsigned long flags; + int rc; /* giveback happens automatically in timer callback, * so make sure the callback happens */ dum = hcd_to_dummy (hcd); spin_lock_irqsave (&dum->lock, flags); - if (dum->rh_state != DUMMY_RH_RUNNING && !list_empty(&dum->urbp_list)) + + rc = usb_hcd_check_unlink_urb(hcd, urb, status); + if (!rc && dum->rh_state != DUMMY_RH_RUNNING && + !list_empty(&dum->urbp_list)) mod_timer (&dum->timer, jiffies); + spin_unlock_irqrestore (&dum->lock, flags); - return 0; + return rc; } static void maybe_set_status (struct urb *urb, int status) @@ -1511,6 +1522,7 @@ return_urb: if (ep) ep->already_seen = ep->setup_stage = 0; + usb_hcd_unlink_urb_from_ep(dummy_to_hcd(dum), urb); spin_unlock (&dum->lock); usb_hcd_giveback_urb (dummy_to_hcd(dum), urb); spin_lock (&dum->lock); diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 35cdba10411..db00492588b 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -719,7 +719,6 @@ dead: */ static int ehci_urb_enqueue ( struct usb_hcd *hcd, - struct usb_host_endpoint *ep, struct urb *urb, gfp_t mem_flags ) { @@ -734,12 +733,12 @@ static int ehci_urb_enqueue ( default: if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags)) return -ENOMEM; - return submit_async (ehci, ep, urb, &qtd_list, mem_flags); + return submit_async(ehci, urb, &qtd_list, mem_flags); case PIPE_INTERRUPT: if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags)) return -ENOMEM; - return intr_submit (ehci, ep, urb, &qtd_list, mem_flags); + return intr_submit(ehci, urb, &qtd_list, mem_flags); case PIPE_ISOCHRONOUS: if (urb->dev->speed == USB_SPEED_HIGH) @@ -777,13 +776,18 @@ static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) * completions normally happen asynchronously */ -static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) +static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); struct ehci_qh *qh; unsigned long flags; + int rc; spin_lock_irqsave (&ehci->lock, flags); + rc = usb_hcd_check_unlink_urb(hcd, urb, status); + if (rc) + goto done; + switch (usb_pipetype (urb->pipe)) { // case PIPE_CONTROL: // case PIPE_BULK: @@ -838,7 +842,7 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) } done: spin_unlock_irqrestore (&ehci->lock, flags); - return 0; + return rc; } /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 140bfa423e0..1da2de4d34e 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -262,6 +262,7 @@ __acquires(ehci->lock) #endif /* complete() can reenter this HCD */ + usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); spin_unlock (&ehci->lock); usb_hcd_giveback_urb (ehci_to_hcd(ehci), urb); spin_lock (&ehci->lock); @@ -913,7 +914,6 @@ static struct ehci_qh *qh_append_tds ( static int submit_async ( struct ehci_hcd *ehci, - struct usb_host_endpoint *ep, struct urb *urb, struct list_head *qtd_list, gfp_t mem_flags @@ -922,10 +922,10 @@ submit_async ( int epnum; unsigned long flags; struct ehci_qh *qh = NULL; - int rc = 0; + int rc; qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list); - epnum = ep->desc.bEndpointAddress; + epnum = urb->ep->desc.bEndpointAddress; #ifdef EHCI_URB_TRACE ehci_dbg (ehci, @@ -933,7 +933,7 @@ submit_async ( __FUNCTION__, urb->dev->devpath, urb, epnum & 0x0f, (epnum & USB_DIR_IN) ? "in" : "out", urb->transfer_buffer_length, - qtd, ep->hcpriv); + qtd, urb->ep->hcpriv); #endif spin_lock_irqsave (&ehci->lock, flags); @@ -942,9 +942,13 @@ submit_async ( rc = -ESHUTDOWN; goto done; } + rc = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb); + if (unlikely(rc)) + goto done; - qh = qh_append_tds (ehci, urb, qtd_list, epnum, &ep->hcpriv); + qh = qh_append_tds(ehci, urb, qtd_list, epnum, &urb->ep->hcpriv); if (unlikely(qh == NULL)) { + usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); rc = -ENOMEM; goto done; } diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index e682f2342ef..8b267b3fd2b 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -797,7 +797,6 @@ done: static int intr_submit ( struct ehci_hcd *ehci, - struct usb_host_endpoint *ep, struct urb *urb, struct list_head *qtd_list, gfp_t mem_flags @@ -805,23 +804,26 @@ static int intr_submit ( unsigned epnum; unsigned long flags; struct ehci_qh *qh; - int status = 0; + int status; struct list_head empty; /* get endpoint and transfer/schedule data */ - epnum = ep->desc.bEndpointAddress; + epnum = urb->ep->desc.bEndpointAddress; spin_lock_irqsave (&ehci->lock, flags); if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &ehci_to_hcd(ehci)->flags))) { status = -ESHUTDOWN; - goto done; + goto done_not_linked; } + status = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb); + if (unlikely(status)) + goto done_not_linked; /* get qh and force any scheduling errors */ INIT_LIST_HEAD (&empty); - qh = qh_append_tds (ehci, urb, &empty, epnum, &ep->hcpriv); + qh = qh_append_tds(ehci, urb, &empty, epnum, &urb->ep->hcpriv); if (qh == NULL) { status = -ENOMEM; goto done; @@ -832,13 +834,16 @@ static int intr_submit ( } /* then queue the urb's tds to the qh */ - qh = qh_append_tds (ehci, urb, qtd_list, epnum, &ep->hcpriv); + qh = qh_append_tds(ehci, urb, qtd_list, epnum, &urb->ep->hcpriv); BUG_ON (qh == NULL); /* ... update usbfs periodic stats */ ehci_to_hcd(ehci)->self.bandwidth_int_reqs++; done: + if (unlikely(status)) + usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); +done_not_linked: spin_unlock_irqrestore (&ehci->lock, flags); if (status) qtd_list_free (ehci, urb, qtd_list); @@ -1686,12 +1691,19 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb, /* schedule ... need to lock */ spin_lock_irqsave (&ehci->lock, flags); if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, - &ehci_to_hcd(ehci)->flags))) + &ehci_to_hcd(ehci)->flags))) { status = -ESHUTDOWN; - else - status = iso_stream_schedule (ehci, urb, stream); + goto done_not_linked; + } + status = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb); + if (unlikely(status)) + goto done_not_linked; + status = iso_stream_schedule(ehci, urb, stream); if (likely (status == 0)) itd_link_urb (ehci, urb, ehci->periodic_size << 3, stream); + else + usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); +done_not_linked: spin_unlock_irqrestore (&ehci->lock, flags); done: @@ -2049,12 +2061,19 @@ static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb, /* schedule ... need to lock */ spin_lock_irqsave (&ehci->lock, flags); if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, - &ehci_to_hcd(ehci)->flags))) + &ehci_to_hcd(ehci)->flags))) { status = -ESHUTDOWN; - else - status = iso_stream_schedule (ehci, urb, stream); + goto done_not_linked; + } + status = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb); + if (unlikely(status)) + goto done_not_linked; + status = iso_stream_schedule(ehci, urb, stream); if (status == 0) sitd_link_urb (ehci, urb, ehci->periodic_size << 3, stream); + else + usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); +done_not_linked: spin_unlock_irqrestore (&ehci->lock, flags); done: diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index 5c851a36de7..d5027dc75a5 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -290,6 +290,7 @@ __releases(isp116x->lock) __acquires(isp116x->lock) urb_dbg(urb, "Finish"); + usb_hcd_unlink_urb_from_ep(isp116x_to_hcd(isp116x), urb); spin_unlock(&isp116x->lock); usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb); spin_lock(&isp116x->lock); @@ -673,7 +674,7 @@ static int balance(struct isp116x *isp116x, u16 period, u16 load) /*-----------------------------------------------------------------*/ static int isp116x_urb_enqueue(struct usb_hcd *hcd, - struct usb_host_endpoint *hep, struct urb *urb, + struct urb *urb, gfp_t mem_flags) { struct isp116x *isp116x = hcd_to_isp116x(hcd); @@ -682,6 +683,7 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd, int is_out = !usb_pipein(pipe); int type = usb_pipetype(pipe); int epnum = usb_pipeendpoint(pipe); + struct usb_host_endpoint *hep = urb->ep; struct isp116x_ep *ep = NULL; unsigned long flags; int i; @@ -705,7 +707,12 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd, if (!HC_IS_RUNNING(hcd->state)) { kfree(ep); ret = -ENODEV; - goto fail; + goto fail_not_linked; + } + ret = usb_hcd_link_urb_to_ep(hcd, urb); + if (ret) { + kfree(ep); + goto fail_not_linked; } if (hep->hcpriv) @@ -818,6 +825,9 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd, start_atl_transfers(isp116x); fail: + if (ret) + usb_hcd_unlink_urb_from_ep(hcd, urb); + fail_not_linked: spin_unlock_irqrestore(&isp116x->lock, flags); return ret; } @@ -825,20 +835,21 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd, /* Dequeue URBs. */ -static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) +static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, + int status) { struct isp116x *isp116x = hcd_to_isp116x(hcd); struct usb_host_endpoint *hep; struct isp116x_ep *ep, *ep_act; unsigned long flags; + int rc; spin_lock_irqsave(&isp116x->lock, flags); + rc = usb_hcd_check_unlink_urb(hcd, urb, status); + if (rc) + goto done; + hep = urb->hcpriv; - /* URB already unlinked (or never linked)? */ - if (!hep) { - spin_unlock_irqrestore(&isp116x->lock, flags); - return 0; - } ep = hep->hcpriv; WARN_ON(hep != ep->hep); @@ -856,9 +867,9 @@ static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) if (urb) finish_request(isp116x, ep, urb); - + done: spin_unlock_irqrestore(&isp116x->lock, flags); - return 0; + return rc; } static void isp116x_endpoint_disable(struct usb_hcd *hcd, diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index d673cb9c36b..6b06ab69938 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -117,7 +117,6 @@ MODULE_PARM_DESC (no_handshake, "true (not default) disables BIOS handshake"); */ static int ohci_urb_enqueue ( struct usb_hcd *hcd, - struct usb_host_endpoint *ep, struct urb *urb, gfp_t mem_flags ) { @@ -134,7 +133,7 @@ static int ohci_urb_enqueue ( #endif /* every endpoint has a ed, locate and maybe (re)initialize it */ - if (! (ed = ed_get (ohci, ep, urb->dev, pipe, urb->interval))) + if (! (ed = ed_get (ohci, urb->ep, urb->dev, pipe, urb->interval))) return -ENOMEM; /* for the private part of the URB we need the number of TDs (size) */ @@ -199,22 +198,17 @@ static int ohci_urb_enqueue ( retval = -ENODEV; goto fail; } - - /* in case of unlink-during-submit */ - spin_lock (&urb->lock); - if (urb->status != -EINPROGRESS) { - spin_unlock (&urb->lock); - urb->hcpriv = urb_priv; - finish_urb (ohci, urb); - retval = 0; + retval = usb_hcd_link_urb_to_ep(hcd, urb); + if (retval) goto fail; - } /* schedule the ed if needed */ if (ed->state == ED_IDLE) { retval = ed_schedule (ohci, ed); - if (retval < 0) - goto fail0; + if (retval < 0) { + usb_hcd_unlink_urb_from_ep(hcd, urb); + goto fail; + } if (ed->type == PIPE_ISOCHRONOUS) { u16 frame = ohci_frame_no(ohci); @@ -238,8 +232,6 @@ static int ohci_urb_enqueue ( urb->hcpriv = urb_priv; td_submit_urb (ohci, urb); -fail0: - spin_unlock (&urb->lock); fail: if (retval) urb_free_priv (ohci, urb_priv); @@ -253,17 +245,21 @@ fail: * asynchronously, and we might be dealing with an urb that's * partially transferred, or an ED with other urbs being unlinked. */ -static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) +static int ohci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); unsigned long flags; + int rc; #ifdef OHCI_VERBOSE_DEBUG urb_print (urb, "UNLINK", 1); #endif spin_lock_irqsave (&ohci->lock, flags); - if (HC_IS_RUNNING(hcd->state)) { + rc = usb_hcd_check_unlink_urb(hcd, urb, status); + if (rc) { + ; /* Do nothing */ + } else if (HC_IS_RUNNING(hcd->state)) { urb_priv_t *urb_priv; /* Unless an IRQ completed the unlink while it was being @@ -284,7 +280,7 @@ static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) finish_urb (ohci, urb); } spin_unlock_irqrestore (&ohci->lock, flags); - return 0; + return rc; } /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index 547d39be3eb..889c0720743 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -74,6 +74,7 @@ __acquires(ohci->lock) #endif /* urb->complete() can reenter this HCD */ + usb_hcd_unlink_urb_from_ep(ohci_to_hcd(ohci), urb); spin_unlock (&ohci->lock); usb_hcd_giveback_urb (ohci_to_hcd(ohci), urb); spin_lock (&ohci->lock); diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 40a1de4c256..94bb229df3b 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -784,6 +784,9 @@ static void force_dequeue(struct r8a66597 *r8a66597, u16 pipenum, u16 address) if (urb) { urb->status = -ENODEV; urb->hcpriv = NULL; + usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597), + urb); + spin_unlock(&r8a66597->lock); usb_hcd_giveback_urb(r8a66597_to_hcd(r8a66597), urb); spin_lock(&r8a66597->lock); @@ -1131,6 +1134,8 @@ static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td, urb->start_frame = r8a66597_get_frame(hcd); urb->hcpriv = NULL; + usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597), urb); + spin_unlock(&r8a66597->lock); usb_hcd_giveback_urb(hcd, urb); spin_lock(&r8a66597->lock); @@ -1722,21 +1727,25 @@ static struct r8a66597_td *r8a66597_make_td(struct r8a66597 *r8a66597, } static int r8a66597_urb_enqueue(struct usb_hcd *hcd, - struct usb_host_endpoint *hep, struct urb *urb, gfp_t mem_flags) { + struct usb_host_endpoint *hep = urb->ep; struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd); struct r8a66597_td *td = NULL; - int ret = 0, request = 0; + int ret, request = 0; unsigned long flags; spin_lock_irqsave(&r8a66597->lock, flags); if (!get_urb_to_r8a66597_dev(r8a66597, urb)) { ret = -ENODEV; - goto error; + goto error_not_linked; } + ret = usb_hcd_link_urb_to_ep(hcd, urb); + if (ret) + goto error_not_linked; + if (!hep->hcpriv) { hep->hcpriv = kzalloc(sizeof(struct r8a66597_pipe), GFP_ATOMIC); @@ -1761,15 +1770,7 @@ static int r8a66597_urb_enqueue(struct usb_hcd *hcd, if (list_empty(&r8a66597->pipe_queue[td->pipenum])) request = 1; list_add_tail(&td->queue, &r8a66597->pipe_queue[td->pipenum]); - - spin_lock(&urb->lock); - if (urb->status != -EINPROGRESS) { - spin_unlock(&urb->lock); - ret = -EPIPE; - goto error; - } urb->hcpriv = td; - spin_unlock(&urb->lock); if (request) { ret = start_transfer(r8a66597, td); @@ -1781,17 +1782,26 @@ static int r8a66597_urb_enqueue(struct usb_hcd *hcd, set_td_timer(r8a66597, td); error: + if (ret) + usb_hcd_unlink_urb_from_ep(hcd, urb); +error_not_linked: spin_unlock_irqrestore(&r8a66597->lock, flags); return ret; } -static int r8a66597_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) +static int r8a66597_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, + int status) { struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd); struct r8a66597_td *td; unsigned long flags; + int rc; spin_lock_irqsave(&r8a66597->lock, flags); + rc = usb_hcd_check_unlink_urb(hcd, urb, status); + if (rc) + goto done; + if (urb->hcpriv) { td = urb->hcpriv; pipe_stop(r8a66597, td->pipe); @@ -1799,8 +1809,9 @@ static int r8a66597_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) disable_irq_empty(r8a66597, td->pipenum); done(r8a66597, td, td->pipenum, urb); } + done: spin_unlock_irqrestore(&r8a66597->lock, flags); - return 0; + return rc; } static void r8a66597_endpoint_disable(struct usb_hcd *hcd, diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index 4cfa3ff2c99..3d3a63d002c 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -441,6 +441,7 @@ static void finish_request( urb->hcpriv = NULL; spin_unlock(&urb->lock); + usb_hcd_unlink_urb_from_ep(sl811_to_hcd(sl811), urb); spin_unlock(&sl811->lock); usb_hcd_giveback_urb(sl811_to_hcd(sl811), urb); spin_lock(&sl811->lock); @@ -807,7 +808,6 @@ static int balance(struct sl811 *sl811, u16 period, u16 load) static int sl811h_urb_enqueue( struct usb_hcd *hcd, - struct usb_host_endpoint *hep, struct urb *urb, gfp_t mem_flags ) { @@ -820,7 +820,8 @@ static int sl811h_urb_enqueue( struct sl811h_ep *ep = NULL; unsigned long flags; int i; - int retval = 0; + int retval; + struct usb_host_endpoint *hep = urb->ep; #ifdef DISABLE_ISO if (type == PIPE_ISOCHRONOUS) @@ -838,7 +839,12 @@ static int sl811h_urb_enqueue( || !HC_IS_RUNNING(hcd->state)) { retval = -ENODEV; kfree(ep); - goto fail; + goto fail_not_linked; + } + retval = usb_hcd_link_urb_to_ep(hcd, urb); + if (retval) { + kfree(ep); + goto fail_not_linked; } if (hep->hcpriv) { @@ -965,23 +971,27 @@ static int sl811h_urb_enqueue( start_transfer(sl811); sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable); fail: + if (retval) + usb_hcd_unlink_urb_from_ep(hcd, urb); +fail_not_linked: spin_unlock_irqrestore(&sl811->lock, flags); return retval; } -static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) +static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { struct sl811 *sl811 = hcd_to_sl811(hcd); struct usb_host_endpoint *hep; unsigned long flags; struct sl811h_ep *ep; - int retval = 0; + int retval; spin_lock_irqsave(&sl811->lock, flags); - hep = urb->hcpriv; - if (!hep) + retval = usb_hcd_check_unlink_urb(hcd, urb, status); + if (retval) goto fail; + hep = urb->hcpriv; ep = hep->hcpriv; if (ep) { /* finish right away if this urb can't be active ... @@ -1029,8 +1039,8 @@ static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) VDBG("dequeue, urb %p active %s; wait4irq\n", urb, (sl811->active_a == ep) ? "A" : "B"); } else -fail: retval = -EINVAL; + fail: spin_unlock_irqrestore(&sl811->lock, flags); return retval; } diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index 598ad098aee..c87660b5edc 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -521,6 +521,7 @@ static void u132_hcd_giveback_urb(struct u132 *u132, struct u132_endp *endp, urb->status = status; urb->hcpriv = NULL; spin_lock_irqsave(&endp->queue_lock.slock, irqs); + usb_hcd_unlink_urb_from_ep(hcd, urb); endp->queue_next += 1; if (ENDP_QUEUE_SIZE > --endp->queue_size) { endp->active = 0; @@ -561,6 +562,7 @@ static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp, urb->status = status; urb->hcpriv = NULL; spin_lock_irqsave(&endp->queue_lock.slock, irqs); + usb_hcd_unlink_urb_from_ep(hcd, urb); endp->queue_next += 1; if (ENDP_QUEUE_SIZE > --endp->queue_size) { endp->active = 0; @@ -1876,20 +1878,32 @@ static int u132_hcd_reset(struct usb_hcd *hcd) } static int create_endpoint_and_queue_int(struct u132 *u132, - struct u132_udev *udev, struct usb_host_endpoint *hep, struct urb *urb, + struct u132_udev *udev, struct urb *urb, struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address, gfp_t mem_flags) { struct u132_ring *ring; unsigned long irqs; - u8 endp_number = ++u132->num_endpoints; - struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] = - kmalloc(sizeof(struct u132_endp), mem_flags); + int rc; + u8 endp_number; + struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags); + if (!endp) { return -ENOMEM; } + + spin_lock_init(&endp->queue_lock.slock); + spin_lock_irqsave(&endp->queue_lock.slock, irqs); + rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb); + if (rc) { + spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); + kfree(endp); + return rc; + } + + endp_number = ++u132->num_endpoints; + urb->ep->hcpriv = u132->endp[endp_number - 1] = endp; INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler); - spin_lock_init(&endp->queue_lock.slock); INIT_LIST_HEAD(&endp->urb_more); ring = endp->ring = &u132->ring[0]; if (ring->curr_endp) { @@ -1905,7 +1919,7 @@ static int create_endpoint_and_queue_int(struct u132 *u132, endp->delayed = 0; endp->endp_number = endp_number; endp->u132 = u132; - endp->hep = hep; + endp->hep = urb->ep; endp->pipetype = usb_pipetype(urb->pipe); u132_endp_init_kref(u132, endp); if (usb_pipein(urb->pipe)) { @@ -1924,7 +1938,6 @@ static int create_endpoint_and_queue_int(struct u132 *u132, u132_udev_get_kref(u132, udev); } urb->hcpriv = u132; - spin_lock_irqsave(&endp->queue_lock.slock, irqs); endp->delayed = 1; endp->jiffies = jiffies + msecs_to_jiffies(urb->interval); endp->udev_number = address; @@ -1939,8 +1952,8 @@ static int create_endpoint_and_queue_int(struct u132 *u132, return 0; } -static int queue_int_on_old_endpoint(struct u132 *u132, struct u132_udev *udev, - struct usb_host_endpoint *hep, struct urb *urb, +static int queue_int_on_old_endpoint(struct u132 *u132, + struct u132_udev *udev, struct urb *urb, struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr, u8 usb_endp, u8 address) { @@ -1964,21 +1977,33 @@ static int queue_int_on_old_endpoint(struct u132 *u132, struct u132_udev *udev, } static int create_endpoint_and_queue_bulk(struct u132 *u132, - struct u132_udev *udev, struct usb_host_endpoint *hep, struct urb *urb, + struct u132_udev *udev, struct urb *urb, struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address, gfp_t mem_flags) { int ring_number; struct u132_ring *ring; unsigned long irqs; - u8 endp_number = ++u132->num_endpoints; - struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] = - kmalloc(sizeof(struct u132_endp), mem_flags); + int rc; + u8 endp_number; + struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags); + if (!endp) { return -ENOMEM; } + + spin_lock_init(&endp->queue_lock.slock); + spin_lock_irqsave(&endp->queue_lock.slock, irqs); + rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb); + if (rc) { + spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); + kfree(endp); + return rc; + } + + endp_number = ++u132->num_endpoints; + urb->ep->hcpriv = u132->endp[endp_number - 1] = endp; INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler); - spin_lock_init(&endp->queue_lock.slock); INIT_LIST_HEAD(&endp->urb_more); endp->dequeueing = 0; endp->edset_flush = 0; @@ -1986,7 +2011,7 @@ static int create_endpoint_and_queue_bulk(struct u132 *u132, endp->delayed = 0; endp->endp_number = endp_number; endp->u132 = u132; - endp->hep = hep; + endp->hep = urb->ep; endp->pipetype = usb_pipetype(urb->pipe); u132_endp_init_kref(u132, endp); if (usb_pipein(urb->pipe)) { @@ -2015,7 +2040,6 @@ static int create_endpoint_and_queue_bulk(struct u132 *u132, } ring->length += 1; urb->hcpriv = u132; - spin_lock_irqsave(&endp->queue_lock.slock, irqs); endp->udev_number = address; endp->usb_addr = usb_addr; endp->usb_endp = usb_endp; @@ -2029,7 +2053,7 @@ static int create_endpoint_and_queue_bulk(struct u132 *u132, } static int queue_bulk_on_old_endpoint(struct u132 *u132, struct u132_udev *udev, - struct usb_host_endpoint *hep, struct urb *urb, + struct urb *urb, struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr, u8 usb_endp, u8 address) { @@ -2051,19 +2075,32 @@ static int queue_bulk_on_old_endpoint(struct u132 *u132, struct u132_udev *udev, } static int create_endpoint_and_queue_control(struct u132 *u132, - struct usb_host_endpoint *hep, struct urb *urb, + struct urb *urb, struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, gfp_t mem_flags) { struct u132_ring *ring; - u8 endp_number = ++u132->num_endpoints; - struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] = - kmalloc(sizeof(struct u132_endp), mem_flags); + unsigned long irqs; + int rc; + u8 endp_number; + struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags); + if (!endp) { return -ENOMEM; } + + spin_lock_init(&endp->queue_lock.slock); + spin_lock_irqsave(&endp->queue_lock.slock, irqs); + rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb); + if (rc) { + spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); + kfree(endp); + return rc; + } + + endp_number = ++u132->num_endpoints; + urb->ep->hcpriv = u132->endp[endp_number - 1] = endp; INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler); - spin_lock_init(&endp->queue_lock.slock); INIT_LIST_HEAD(&endp->urb_more); ring = endp->ring = &u132->ring[0]; if (ring->curr_endp) { @@ -2079,11 +2116,10 @@ static int create_endpoint_and_queue_control(struct u132 *u132, endp->delayed = 0; endp->endp_number = endp_number; endp->u132 = u132; - endp->hep = hep; + endp->hep = urb->ep; u132_endp_init_kref(u132, endp); u132_endp_get_kref(u132, endp); if (usb_addr == 0) { - unsigned long irqs; u8 address = u132->addr[usb_addr].address; struct u132_udev *udev = &u132->udev[address]; endp->udev_number = address; @@ -2097,7 +2133,6 @@ static int create_endpoint_and_queue_control(struct u132 *u132, udev->endp_number_in[usb_endp] = endp_number; udev->endp_number_out[usb_endp] = endp_number; urb->hcpriv = u132; - spin_lock_irqsave(&endp->queue_lock.slock, irqs); endp->queue_size = 1; endp->queue_last = 0; endp->queue_next = 0; @@ -2106,7 +2141,6 @@ static int create_endpoint_and_queue_control(struct u132 *u132, u132_endp_queue_work(u132, endp, 0); return 0; } else { /*(usb_addr > 0) */ - unsigned long irqs; u8 address = u132->addr[usb_addr].address; struct u132_udev *udev = &u132->udev[address]; endp->udev_number = address; @@ -2120,7 +2154,6 @@ static int create_endpoint_and_queue_control(struct u132 *u132, udev->endp_number_in[usb_endp] = endp_number; udev->endp_number_out[usb_endp] = endp_number; urb->hcpriv = u132; - spin_lock_irqsave(&endp->queue_lock.slock, irqs); endp->queue_size = 1; endp->queue_last = 0; endp->queue_next = 0; @@ -2132,7 +2165,7 @@ static int create_endpoint_and_queue_control(struct u132 *u132, } static int queue_control_on_old_endpoint(struct u132 *u132, - struct usb_host_endpoint *hep, struct urb *urb, + struct urb *urb, struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr, u8 usb_endp) { @@ -2232,8 +2265,8 @@ static int queue_control_on_old_endpoint(struct u132 *u132, } } -static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep, - struct urb *urb, gfp_t mem_flags) +static int u132_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, + gfp_t mem_flags) { struct u132 *u132 = hcd_to_u132(hcd); if (irqs_disabled()) { @@ -2258,16 +2291,24 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep, if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) { u8 address = u132->addr[usb_addr].address; struct u132_udev *udev = &u132->udev[address]; - struct u132_endp *endp = hep->hcpriv; + struct u132_endp *endp = urb->ep->hcpriv; urb->actual_length = 0; if (endp) { unsigned long irqs; int retval; spin_lock_irqsave(&endp->queue_lock.slock, irqs); - retval = queue_int_on_old_endpoint(u132, udev, - hep, urb, usb_dev, endp, usb_addr, - usb_endp, address); + retval = usb_hcd_link_urb_to_ep(hcd, urb); + if (retval == 0) { + retval = queue_int_on_old_endpoint( + u132, udev, urb, + usb_dev, endp, + usb_addr, usb_endp, + address); + if (retval) + usb_hcd_unlink_urb_from_ep( + hcd, urb); + } spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); if (retval) { @@ -2282,8 +2323,8 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep, return -EINVAL; } else { /*(endp == NULL) */ return create_endpoint_and_queue_int(u132, udev, - hep, urb, usb_dev, usb_addr, usb_endp, - address, mem_flags); + urb, usb_dev, usb_addr, + usb_endp, address, mem_flags); } } else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { dev_err(&u132->platform_dev->dev, "the hardware does no" @@ -2292,16 +2333,24 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep, } else if (usb_pipetype(urb->pipe) == PIPE_BULK) { u8 address = u132->addr[usb_addr].address; struct u132_udev *udev = &u132->udev[address]; - struct u132_endp *endp = hep->hcpriv; + struct u132_endp *endp = urb->ep->hcpriv; urb->actual_length = 0; if (endp) { unsigned long irqs; int retval; spin_lock_irqsave(&endp->queue_lock.slock, irqs); - retval = queue_bulk_on_old_endpoint(u132, udev, - hep, urb, usb_dev, endp, usb_addr, - usb_endp, address); + retval = usb_hcd_link_urb_to_ep(hcd, urb); + if (retval == 0) { + retval = queue_bulk_on_old_endpoint( + u132, udev, urb, + usb_dev, endp, + usb_addr, usb_endp, + address); + if (retval) + usb_hcd_unlink_urb_from_ep( + hcd, urb); + } spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); if (retval) { @@ -2314,10 +2363,10 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep, return -EINVAL; } else return create_endpoint_and_queue_bulk(u132, - udev, hep, urb, usb_dev, usb_addr, + udev, urb, usb_dev, usb_addr, usb_endp, address, mem_flags); } else { - struct u132_endp *endp = hep->hcpriv; + struct u132_endp *endp = urb->ep->hcpriv; u16 urb_size = 8; u8 *b = urb->setup_packet; int i = 0; @@ -2340,9 +2389,16 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep, int retval; spin_lock_irqsave(&endp->queue_lock.slock, irqs); - retval = queue_control_on_old_endpoint(u132, - hep, urb, usb_dev, endp, usb_addr, - usb_endp); + retval = usb_hcd_link_urb_to_ep(hcd, urb); + if (retval == 0) { + retval = queue_control_on_old_endpoint( + u132, urb, usb_dev, + endp, usb_addr, + usb_endp); + if (retval) + usb_hcd_unlink_urb_from_ep( + hcd, urb); + } spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); if (retval) { @@ -2355,7 +2411,7 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep, return -EINVAL; } else return create_endpoint_and_queue_control(u132, - hep, urb, usb_dev, usb_addr, usb_endp, + urb, usb_dev, usb_addr, usb_endp, mem_flags); } } @@ -2390,10 +2446,17 @@ static int dequeue_from_overflow_chain(struct u132 *u132, } static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, - struct urb *urb) + struct urb *urb, int status) { unsigned long irqs; + int rc; + spin_lock_irqsave(&endp->queue_lock.slock, irqs); + rc = usb_hcd_check_unlink_urb(u132_to_hcd(u132), urb, status); + if (rc) { + spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); + return rc; + } if (endp->queue_size == 0) { dev_err(&u132->platform_dev->dev, "urb=%p not found in endp[%d]" "=%p ring[%d] %c%c usb_endp=%d usb_addr=%d\n", urb, @@ -2438,6 +2501,8 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, } if (urb_slot) { struct usb_hcd *hcd = u132_to_hcd(u132); + + usb_hcd_unlink_urb_from_ep(hcd, urb); endp->queue_size -= 1; if (list_empty(&endp->urb_more)) { spin_unlock_irqrestore(&endp->queue_lock.slock, @@ -2467,7 +2532,10 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); return -EINVAL; } else { - int retval = dequeue_from_overflow_chain(u132, endp, + int retval; + + usb_hcd_unlink_urb_from_ep(u132_to_hcd(u132), urb); + retval = dequeue_from_overflow_chain(u132, endp, urb); spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); return retval; @@ -2475,7 +2543,7 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, } } -static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) +static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { struct u132 *u132 = hcd_to_u132(hcd); if (u132->going > 2) { @@ -2490,11 +2558,11 @@ static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) if (usb_pipein(urb->pipe)) { u8 endp_number = udev->endp_number_in[usb_endp]; struct u132_endp *endp = u132->endp[endp_number - 1]; - return u132_endp_urb_dequeue(u132, endp, urb); + return u132_endp_urb_dequeue(u132, endp, urb, status); } else { u8 endp_number = udev->endp_number_out[usb_endp]; struct u132_endp *endp = u132->endp[endp_number - 1]; - return u132_endp_urb_dequeue(u132, endp, urb); + return u132_endp_urb_dequeue(u132, endp, urb, status); } } } diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index 3bb908ca38e..bff200cb3d2 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -1376,7 +1376,6 @@ static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb) } static int uhci_urb_enqueue(struct usb_hcd *hcd, - struct usb_host_endpoint *hep, struct urb *urb, gfp_t mem_flags) { int ret; @@ -1387,19 +1386,19 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd, spin_lock_irqsave(&uhci->lock, flags); - ret = urb->status; - if (ret != -EINPROGRESS) /* URB already unlinked! */ - goto done; + ret = usb_hcd_link_urb_to_ep(hcd, urb); + if (ret) + goto done_not_linked; ret = -ENOMEM; urbp = uhci_alloc_urb_priv(uhci, urb); if (!urbp) goto done; - if (hep->hcpriv) - qh = (struct uhci_qh *) hep->hcpriv; + if (urb->ep->hcpriv) + qh = urb->ep->hcpriv; else { - qh = uhci_alloc_qh(uhci, urb->dev, hep); + qh = uhci_alloc_qh(uhci, urb->dev, urb->ep); if (!qh) goto err_no_qh; } @@ -1440,27 +1439,29 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd, err_submit_failed: if (qh->state == QH_STATE_IDLE) uhci_make_qh_idle(uhci, qh); /* Reclaim unused QH */ - err_no_qh: uhci_free_urb_priv(uhci, urbp); - done: + if (ret) + usb_hcd_unlink_urb_from_ep(hcd, urb); +done_not_linked: spin_unlock_irqrestore(&uhci->lock, flags); return ret; } -static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) +static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); unsigned long flags; - struct urb_priv *urbp; struct uhci_qh *qh; + int rc; spin_lock_irqsave(&uhci->lock, flags); - urbp = urb->hcpriv; - if (!urbp) /* URB was never linked! */ + rc = usb_hcd_check_unlink_urb(hcd, urb, status); + if (rc) goto done; - qh = urbp->qh; + + qh = ((struct urb_priv *) urb->hcpriv)->qh; /* Remove Isochronous TDs from the frame list ASAP */ if (qh->type == USB_ENDPOINT_XFER_ISOC) { @@ -1477,7 +1478,7 @@ static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) done: spin_unlock_irqrestore(&uhci->lock, flags); - return 0; + return rc; } /* @@ -1529,6 +1530,7 @@ __acquires(uhci->lock) } uhci_free_urb_priv(uhci, urbp); + usb_hcd_unlink_urb_from_ep(uhci_to_hcd(uhci), urb); spin_unlock(&uhci->lock); usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb); -- cgit v1.2.3-70-g09d2 From d74d4a69dc1cc7ddc0eabb9c9f1e45005e2984eb Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 8 Aug 2007 11:59:18 -0400 Subject: USB: don't touch sysfs stuff when altsetting is unchanged This patch (as955) prevents the interface-related sysfs files and endpoint pseudo-devices from being deleted and recreated when a call to usb_set_interface() specifies the current altsetting. Since the altsetting doesn't get changed, there's no need to do anything. Furthermore, avoiding changes to the endpoint devices will be necessary in the future. This code is called from usb_reset_device(), which gets invoked for reset-resume processing, but upcoming changes to the PM and driver cores will make it impossible to register devices while a suspend/resume transition is in progress. Since we don't need to re-register those endpoint devices anyhow, it's best to skip the whole thing. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/message.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index c905b35d4f8..d638375e22e 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1173,6 +1173,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) struct usb_host_interface *alt; int ret; int manual = 0; + int changed; if (dev->state == USB_STATE_SUSPENDED) return -EHOSTUNREACH; @@ -1212,7 +1213,8 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) */ /* prevent submissions using previous endpoint settings */ - if (device_is_registered(&iface->dev)) + changed = (iface->cur_altsetting != alt); + if (changed && device_is_registered(&iface->dev)) usb_remove_sysfs_intf_files(iface); usb_disable_interface(dev, iface); @@ -1249,7 +1251,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) * (Likewise, EP0 never "halts" on well designed devices.) */ usb_enable_interface(dev, iface); - if (device_is_registered(&iface->dev)) + if (changed && device_is_registered(&iface->dev)) usb_create_sysfs_intf_files(iface); return 0; -- cgit v1.2.3-70-g09d2 From 79a7d9ee1a2e8b8dc44dd217f07496911850ec0e Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 8 Aug 2007 17:10:11 -0400 Subject: USB: cleanups for g_file_storage This patch (as957) makes some minor cleanups to the g_file_storage driver: Update the copyright date and version string; Uniformize the logging macros for the gadget and the LUNs; Remove "inline" markers -- nowadays we rely on the compiler to decide which routines are best inlined; Use the print_hex_dump() library routines; Remove some unnecessary assignments within conditionals and fix some close-brace indenting levels; Fix some column-80 violations. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/file_storage.c | 129 ++++++++++++++++++-------------------- 1 file changed, 62 insertions(+), 67 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 0019116ee41..9998cd7af41 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -1,7 +1,7 @@ /* * file_storage.c -- File-backed USB Storage Gadget, for USB development * - * Copyright (C) 2003-2005 Alan Stern + * Copyright (C) 2003-2007 Alan Stern * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -218,7 +218,7 @@ /* #define VERBOSE_DEBUG */ -#undef DUMP_MSGS +/* #define DUMP_MSGS */ #include @@ -249,7 +249,7 @@ #define DRIVER_DESC "File-backed Storage Gadget" #define DRIVER_NAME "g_file_storage" -#define DRIVER_VERSION "28 November 2005" +#define DRIVER_VERSION "7 August 2007" static const char longname[] = DRIVER_DESC; static const char shortname[] = DRIVER_NAME; @@ -275,12 +275,9 @@ MODULE_LICENSE("Dual BSD/GPL"); /*-------------------------------------------------------------------------*/ -#define yprintk(l,level,fmt,args...) \ - dev_printk(level , &(l)->dev , fmt , ## args) - #ifdef DEBUG #define LDBG(lun,fmt,args...) \ - yprintk(lun , KERN_DEBUG , fmt , ## args) + dev_dbg(&(lun)->dev , fmt , ## args) #define MDBG(fmt,args...) \ printk(KERN_DEBUG DRIVER_NAME ": " fmt , ## args) #else @@ -300,11 +297,11 @@ MODULE_LICENSE("Dual BSD/GPL"); #endif /* VERBOSE_DEBUG */ #define LERROR(lun,fmt,args...) \ - yprintk(lun , KERN_ERR , fmt , ## args) + dev_err(&(lun)->dev , fmt , ## args) #define LWARN(lun,fmt,args...) \ - yprintk(lun , KERN_WARNING , fmt , ## args) + dev_warn(&(lun)->dev , fmt , ## args) #define LINFO(lun,fmt,args...) \ - yprintk(lun , KERN_INFO , fmt , ## args) + dev_info(&(lun)->dev , fmt , ## args) #define MINFO(fmt,args...) \ printk(KERN_INFO DRIVER_NAME ": " fmt , ## args) @@ -558,7 +555,7 @@ struct lun { #define backing_file_is_open(curlun) ((curlun)->filp != NULL) -static inline struct lun *dev_to_lun(struct device *dev) +static struct lun *dev_to_lun(struct device *dev) { return container_of(dev, struct lun, dev); } @@ -691,13 +688,13 @@ struct fsg_dev { typedef void (*fsg_routine_t)(struct fsg_dev *); -static int inline exception_in_progress(struct fsg_dev *fsg) +static int exception_in_progress(struct fsg_dev *fsg) { return (fsg->state > FSG_STATE_IDLE); } /* Make bulk-out requests be divisible by the maxpacket size */ -static void inline set_bulk_out_req_length(struct fsg_dev *fsg, +static void set_bulk_out_req_length(struct fsg_dev *fsg, struct fsg_buffhd *bh, unsigned int length) { unsigned int rem; @@ -723,50 +720,36 @@ static void close_all_backing_files(struct fsg_dev *fsg); static void dump_msg(struct fsg_dev *fsg, const char *label, const u8 *buf, unsigned int length) { - unsigned int start, num, i; - char line[52], *p; - - if (length >= 512) - return; - DBG(fsg, "%s, length %u:\n", label, length); - - start = 0; - while (length > 0) { - num = min(length, 16u); - p = line; - for (i = 0; i < num; ++i) { - if (i == 8) - *p++ = ' '; - sprintf(p, " %02x", buf[i]); - p += 3; - } - *p = 0; - printk(KERN_DEBUG "%6x: %s\n", start, line); - buf += num; - start += num; - length -= num; + if (length < 512) { + DBG(fsg, "%s, length %u:\n", label, length); + print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, + 16, 1, buf, length, 0); } } -static void inline dump_cdb(struct fsg_dev *fsg) +static void dump_cdb(struct fsg_dev *fsg) {} #else -static void inline dump_msg(struct fsg_dev *fsg, const char *label, +static void dump_msg(struct fsg_dev *fsg, const char *label, const u8 *buf, unsigned int length) {} -static void inline dump_cdb(struct fsg_dev *fsg) -{ - int i; - char cmdbuf[3*MAX_COMMAND_SIZE + 1]; +#ifdef VERBOSE_DEBUG - for (i = 0; i < fsg->cmnd_size; ++i) - sprintf(cmdbuf + i*3, " %02x", fsg->cmnd[i]); - VDBG(fsg, "SCSI CDB: %s\n", cmdbuf); +static void dump_cdb(struct fsg_dev *fsg) +{ + print_hex_dump(KERN_DEBUG, "SCSI CDB: ", DUMP_PREFIX_NONE, + 16, 1, fsg->cmnd, fsg->cmnd_size, 0); } +#else + +static void dump_cdb(struct fsg_dev *fsg) +{} + +#endif /* VERBOSE_DEBUG */ #endif /* DUMP_MSGS */ @@ -789,24 +772,24 @@ static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep) /* Routines for unaligned data access */ -static u16 inline get_be16(u8 *buf) +static u16 get_be16(u8 *buf) { return ((u16) buf[0] << 8) | ((u16) buf[1]); } -static u32 inline get_be32(u8 *buf) +static u32 get_be32(u8 *buf) { return ((u32) buf[0] << 24) | ((u32) buf[1] << 16) | ((u32) buf[2] << 8) | ((u32) buf[3]); } -static void inline put_be16(u8 *buf, u16 val) +static void put_be16(u8 *buf, u16 val) { buf[0] = val >> 8; buf[1] = val; } -static void inline put_be32(u8 *buf, u32 val) +static void put_be32(u8 *buf, u32 val) { buf[0] = val >> 24; buf[1] = val >> 16; @@ -992,7 +975,7 @@ static const struct usb_descriptor_header *hs_function[] = { #define HS_FUNCTION_PRE_EP_ENTRIES 2 /* Maxpacket and other transfer characteristics vary by speed. */ -static inline struct usb_endpoint_descriptor * +static struct usb_endpoint_descriptor * ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs, struct usb_endpoint_descriptor *hs) { @@ -1616,7 +1599,8 @@ static int do_read(struct fsg_dev *fsg) /* Wait for the next buffer to become available */ bh = fsg->next_buffhd_to_fill; while (bh->state != BUF_STATE_EMPTY) { - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; } @@ -1855,7 +1839,8 @@ static int do_write(struct fsg_dev *fsg) } /* Wait for something to happen */ - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; } @@ -2339,7 +2324,8 @@ static int pad_with_zeros(struct fsg_dev *fsg) /* Wait for the next buffer to be free */ while (bh->state != BUF_STATE_EMPTY) { - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; } @@ -2399,7 +2385,8 @@ static int throw_away_data(struct fsg_dev *fsg) } /* Otherwise wait for something to happen */ - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; } return 0; @@ -2521,7 +2508,8 @@ static int send_status(struct fsg_dev *fsg) /* Wait for the next buffer to become available */ bh = fsg->next_buffhd_to_fill; while (bh->state != BUF_STATE_EMPTY) { - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; } @@ -2741,9 +2729,10 @@ static int do_scsi_command(struct fsg_dev *fsg) /* Wait for the next buffer to become available for data or status */ bh = fsg->next_buffhd_to_drain = fsg->next_buffhd_to_fill; while (bh->state != BUF_STATE_EMPTY) { - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; - } + } fsg->phase_error = 0; fsg->short_packet_received = 0; @@ -3015,9 +3004,10 @@ static int get_next_command(struct fsg_dev *fsg) /* Wait for the next buffer to become available */ bh = fsg->next_buffhd_to_fill; while (bh->state != BUF_STATE_EMPTY) { - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; - } + } /* Queue a request to read a Bulk-only CBW */ set_bulk_out_req_length(fsg, bh, USB_BULK_CB_WRAP_LEN); @@ -3031,9 +3021,10 @@ static int get_next_command(struct fsg_dev *fsg) /* Wait for the CBW to arrive */ while (bh->state != BUF_STATE_FULL) { - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; - } + } smp_rmb(); rc = received_cbw(fsg, bh); bh->state = BUF_STATE_EMPTY; @@ -3042,9 +3033,10 @@ static int get_next_command(struct fsg_dev *fsg) /* Wait for the next command to arrive */ while (fsg->cbbuf_cmnd_size == 0) { - if ((rc = sleep_thread(fsg)) != 0) + rc = sleep_thread(fsg); + if (rc) return rc; - } + } /* Is the previous status interrupt request still busy? * The host is allowed to skip reading the status, @@ -3565,7 +3557,8 @@ static ssize_t show_ro(struct device *dev, struct device_attribute *attr, char * return sprintf(buf, "%d\n", curlun->ro); } -static ssize_t show_file(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_file(struct device *dev, struct device_attribute *attr, + char *buf) { struct lun *curlun = dev_to_lun(dev); struct fsg_dev *fsg = dev_get_drvdata(dev); @@ -3574,8 +3567,8 @@ static ssize_t show_file(struct device *dev, struct device_attribute *attr, char down_read(&fsg->filesem); if (backing_file_is_open(curlun)) { // Get the complete pathname - p = d_path(curlun->filp->f_path.dentry, curlun->filp->f_path.mnt, - buf, PAGE_SIZE - 1); + p = d_path(curlun->filp->f_path.dentry, + curlun->filp->f_path.mnt, buf, PAGE_SIZE - 1); if (IS_ERR(p)) rc = PTR_ERR(p); else { @@ -3593,7 +3586,8 @@ static ssize_t show_file(struct device *dev, struct device_attribute *attr, char } -static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t store_ro(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { ssize_t rc = count; struct lun *curlun = dev_to_lun(dev); @@ -3617,7 +3611,8 @@ static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const return rc; } -static ssize_t store_file(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t store_file(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct lun *curlun = dev_to_lun(dev); struct fsg_dev *fsg = dev_get_drvdata(dev); -- cgit v1.2.3-70-g09d2 From ed86d97068c7d53561d3e9b59db6c6b11f6091c7 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 10 Aug 2007 09:34:24 -0400 Subject: USB: SisUSB2VGA: Whitespace Cleanups This patches clean some trailing whitespaces in sisusb2vga driver. Signed-off-by: Felipe Balbi Cc: Thomas Winischhofer Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/sisusbvga/sisusb.c | 26 +++++++++++++------------- drivers/usb/misc/sisusbvga/sisusb.h | 6 +++--- drivers/usb/misc/sisusbvga/sisusb_init.c | 2 +- drivers/usb/misc/sisusbvga/sisusb_init.h | 4 ++-- drivers/usb/misc/sisusbvga/sisusb_struct.h | 2 +- 5 files changed, 20 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index b64ca91d9b0..376f86cab4b 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -32,7 +32,7 @@ * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Author: Thomas Winischhofer + * Author: Thomas Winischhofer * */ @@ -962,12 +962,12 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr, packet.address = 0x00000194; packet.data = addr; ret = sisusb_send_bridge_packet(sisusb, 10, - &packet, 0); + &packet, 0); packet.header = 0x001f; packet.address = 0x00000190; packet.data = (length & ~3); ret |= sisusb_send_bridge_packet(sisusb, 10, - &packet, 0); + &packet, 0); if (sisusb->flagb0 != 0x16) { packet.header = 0x001f; packet.address = 0x00000180; @@ -1019,7 +1019,7 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr, } if (ret) - break; + break; } @@ -1305,7 +1305,7 @@ static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr, } if (ret) - break; + break; } return ret; @@ -1533,9 +1533,9 @@ sisusb_clear_vram(struct sisusb_usb_data *sisusb, u32 address, int length) #define SETIREGAND(r,i,a) sisusb_setidxregand(sisusb, r, i, a) #define SETIREGANDOR(r,i,a,o) sisusb_setidxregandor(sisusb, r, i, a, o) #define READL(a,d) sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM, a, d) -#define WRITEL(a,d) sisusb_write_memio_long(sisusb, SISUSB_TYPE_MEM, a, d) +#define WRITEL(a,d) sisusb_write_memio_long(sisusb, SISUSB_TYPE_MEM, a, d) #define READB(a,d) sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d) -#define WRITEB(a,d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d) +#define WRITEB(a,d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d) static int sisusb_triggersr16(struct sisusb_usb_data *sisusb, u8 ramtype) @@ -2008,7 +2008,7 @@ sisusb_set_default_mode(struct sisusb_usb_data *sisusb, int touchengines) SETIREG(SISSR, 0x26, 0x00); } - SETIREG(SISCR, 0x34, 0x44); /* we just set std mode #44 */ + SETIREG(SISCR, 0x34, 0x44); /* we just set std mode #44 */ return ret; } @@ -2942,7 +2942,7 @@ static int sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y, unsigned long arg) { - int retval, port, length; + int retval, port, length; u32 address; /* All our commands require the device @@ -3065,12 +3065,12 @@ sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y, static int sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg) + unsigned long arg) { struct sisusb_usb_data *sisusb; struct sisusb_info x; struct sisusb_command y; - int retval = 0; + int retval = 0; u32 __user *argp = (u32 __user *)arg; if (!(sisusb = (struct sisusb_usb_data *)file->private_data)) @@ -3095,7 +3095,7 @@ sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, case SISUSB_GET_CONFIG: - x.sisusb_id = SISUSB_ID; + x.sisusb_id = SISUSB_ID; x.sisusb_version = SISUSB_VERSION; x.sisusb_revision = SISUSB_REVISION; x.sisusb_patchlevel = SISUSB_PATCHLEVEL; @@ -3164,7 +3164,7 @@ static const struct file_operations usb_sisusb_fops = { .release = sisusb_release, .read = sisusb_read, .write = sisusb_write, - .llseek = sisusb_lseek, + .llseek = sisusb_lseek, #ifdef SISUSB_NEW_CONFIG_COMPAT .compat_ioctl = sisusb_compat_ioctl, #endif diff --git a/drivers/usb/misc/sisusbvga/sisusb.h b/drivers/usb/misc/sisusbvga/sisusb.h index 8e1120a6480..555fed0ba0e 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.h +++ b/drivers/usb/misc/sisusbvga/sisusb.h @@ -30,7 +30,7 @@ * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Author: Thomas Winischhofer + * Author: Thomas Winischhofer * */ @@ -53,7 +53,7 @@ /* Version Information */ #define SISUSB_VERSION 0 -#define SISUSB_REVISION 0 +#define SISUSB_REVISION 0 #define SISUSB_PATCHLEVEL 8 /* Include console and mode switching code? */ @@ -93,7 +93,7 @@ */ #ifdef __BIG_ENDIAN -#define SISUSB_CORRECT_ENDIANNESS_PACKET(p) \ +#define SISUSB_CORRECT_ENDIANNESS_PACKET(p) \ do { \ p->header = cpu_to_le16(p->header); \ p->address = cpu_to_le32(p->address); \ diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.c b/drivers/usb/misc/sisusbvga/sisusb_init.c index 9b30f896281..d51de0ff9e4 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_init.c +++ b/drivers/usb/misc/sisusbvga/sisusb_init.c @@ -32,7 +32,7 @@ * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Author: Thomas Winischhofer + * Author: Thomas Winischhofer * */ diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.h b/drivers/usb/misc/sisusbvga/sisusb_init.h index 864bc0e9659..d47301eaca7 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_init.h +++ b/drivers/usb/misc/sisusbvga/sisusb_init.h @@ -46,7 +46,7 @@ * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Author: Thomas Winischhofer + * Author: Thomas Winischhofer * */ @@ -82,7 +82,7 @@ /* Infoflag */ #define SupportTV 0x0008 #define SupportTV1024 0x0800 -#define SupportCHTV 0x0800 +#define SupportCHTV 0x0800 #define Support64048060Hz 0x0800 /* Special for 640x480 LCD */ #define SupportHiVision 0x0010 #define SupportYPbPr750p 0x1000 diff --git a/drivers/usb/misc/sisusbvga/sisusb_struct.h b/drivers/usb/misc/sisusbvga/sisusb_struct.h index f325ecb29a6..9def598192c 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_struct.h +++ b/drivers/usb/misc/sisusbvga/sisusb_struct.h @@ -44,7 +44,7 @@ * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Author: Thomas Winischhofer + * Author: Thomas Winischhofer * */ -- cgit v1.2.3-70-g09d2 From 9dedd36778f9d9bd043df27c8fc62088ce93813f Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 10 Aug 2007 09:34:26 -0400 Subject: USB: SisUSB2VGA: Remove if 0'ed code Unused code should be removed. We don't need to increase the size of the file with dead code inside if 0 statements. Signed-off-by: Felipe Balbi Cc: Thomas Winischhofer Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/sisusbvga/sisusb.c | 57 -------------------- drivers/usb/misc/sisusbvga/sisusb.h | 4 +- drivers/usb/misc/sisusbvga/sisusb_con.c | 47 ----------------- drivers/usb/misc/sisusbvga/sisusb_init.c | 90 -------------------------------- 4 files changed, 1 insertion(+), 197 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index 376f86cab4b..558b94fd209 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -1261,47 +1261,6 @@ static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr, addr += 4; length -= 4; } -#if 0 /* That does not work, as EP 2 is an OUT EP! */ - default: - CLEARPACKET(&packet); - packet.header = 0x001f; - packet.address = 0x000001a0; - packet.data = 0x00000006; - ret |= sisusb_send_bridge_packet(sisusb, 10, - &packet, 0); - packet.header = 0x001f; - packet.address = 0x000001b0; - packet.data = (length & ~3) | 0x40000000; - ret |= sisusb_send_bridge_packet(sisusb, 10, - &packet, 0); - packet.header = 0x001f; - packet.address = 0x000001b4; - packet.data = addr; - ret |= sisusb_send_bridge_packet(sisusb, 10, - &packet, 0); - packet.header = 0x001f; - packet.address = 0x000001a4; - packet.data = 0x00000001; - ret |= sisusb_send_bridge_packet(sisusb, 10, - &packet, 0); - if (userbuffer) { - ret |= sisusb_recv_bulk_msg(sisusb, - SISUSB_EP_GFX_BULK_IN, - (length & ~3), - NULL, userbuffer, - bytes_read, 0); - if (!ret) userbuffer += (*bytes_read); - } else { - ret |= sisusb_recv_bulk_msg(sisusb, - SISUSB_EP_GFX_BULK_IN, - (length & ~3), - kernbuffer, NULL, - bytes_read, 0); - if (!ret) kernbuffer += (*bytes_read); - } - addr += (*bytes_read); - length -= (*bytes_read); -#endif } if (ret) @@ -1401,22 +1360,6 @@ sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data) return(sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data)); } -#if 0 - -int -sisusb_writew(struct sisusb_usb_data *sisusb, u32 adr, u16 data) -{ - return(sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data)); -} - -int -sisusb_readw(struct sisusb_usb_data *sisusb, u32 adr, u16 *data) -{ - return(sisusb_read_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data)); -} - -#endif /* 0 */ - int sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src, u32 dest, int length, size_t *bytes_written) diff --git a/drivers/usb/misc/sisusbvga/sisusb.h b/drivers/usb/misc/sisusbvga/sisusb.h index 555fed0ba0e..dc0473921e3 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.h +++ b/drivers/usb/misc/sisusbvga/sisusb.h @@ -46,9 +46,7 @@ /* For older kernels, support for text consoles is by default * off. To ensable text console support, change the following: */ -#if 0 -#define CONFIG_USB_SISUSBVGA_CON -#endif +/* #define CONFIG_USB_SISUSBVGA_CON */ /* Version Information */ diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c index 8d0edc867f3..20938cd09ed 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_con.c +++ b/drivers/usb/misc/sisusbvga/sisusb_con.c @@ -373,14 +373,6 @@ sisusbcon_putc(struct vc_data *c, int ch, int y, int x) return; /* sisusb->lock is down */ - - /* Don't need to put the character into buffer ourselves, - * because the vt does this BEFORE calling us. - */ -#if 0 - sisusbcon_writew(ch, SISUSB_VADDR(x, y)); -#endif - if (sisusb_is_inactive(c, sisusb)) { mutex_unlock(&sisusb->lock); return; @@ -490,10 +482,6 @@ sisusbcon_bmove(struct vc_data *c, int sy, int sx, struct sisusb_usb_data *sisusb; ssize_t written; int cols, length; -#if 0 - u16 *src, *dest; - int i; -#endif if (width <= 0 || height <= 0) return; @@ -505,41 +493,6 @@ sisusbcon_bmove(struct vc_data *c, int sy, int sx, cols = sisusb->sisusb_num_columns; - /* Don't need to move data outselves, because - * vt does this BEFORE calling us. - * This is only used by vt's insert/deletechar. - */ -#if 0 - if (sx == 0 && dx == 0 && width >= c->vc_cols && width <= cols) { - - sisusbcon_memmovew(SISUSB_VADDR(0, dy), SISUSB_VADDR(0, sy), - height * width * 2); - - } else if (dy < sy || (dy == sy && dx < sx)) { - - src = SISUSB_VADDR(sx, sy); - dest = SISUSB_VADDR(dx, dy); - - for (i = height; i > 0; i--) { - sisusbcon_memmovew(dest, src, width * 2); - src += cols; - dest += cols; - } - - } else { - - src = SISUSB_VADDR(sx, sy + height - 1); - dest = SISUSB_VADDR(dx, dy + height - 1); - - for (i = height; i > 0; i--) { - sisusbcon_memmovew(dest, src, width * 2); - src -= cols; - dest -= cols; - } - - } -#endif - if (sisusb_is_inactive(c, sisusb)) { mutex_unlock(&sisusb->lock); return; diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.c b/drivers/usb/misc/sisusbvga/sisusb_init.c index d51de0ff9e4..5d8358295e7 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_init.c +++ b/drivers/usb/misc/sisusbvga/sisusb_init.c @@ -69,96 +69,6 @@ SiSUSB_InitPtr(struct SiS_Private *SiS_Pr) SiS_Pr->SiS_VCLKData = SiSUSB_VCLKData; } -/*********************************************/ -/* HELPER: Get ModeID */ -/*********************************************/ - -#if 0 -unsigned short -SiSUSB_GetModeID(int HDisplay, int VDisplay, int Depth) -{ - unsigned short ModeIndex = 0; - - switch (HDisplay) - { - case 320: - if (VDisplay == 200) - ModeIndex = ModeIndex_320x200[Depth]; - else if (VDisplay == 240) - ModeIndex = ModeIndex_320x240[Depth]; - break; - case 400: - if (VDisplay == 300) - ModeIndex = ModeIndex_400x300[Depth]; - break; - case 512: - if (VDisplay == 384) - ModeIndex = ModeIndex_512x384[Depth]; - break; - case 640: - if (VDisplay == 480) - ModeIndex = ModeIndex_640x480[Depth]; - else if (VDisplay == 400) - ModeIndex = ModeIndex_640x400[Depth]; - break; - case 720: - if (VDisplay == 480) - ModeIndex = ModeIndex_720x480[Depth]; - else if (VDisplay == 576) - ModeIndex = ModeIndex_720x576[Depth]; - break; - case 768: - if (VDisplay == 576) - ModeIndex = ModeIndex_768x576[Depth]; - break; - case 800: - if (VDisplay == 600) - ModeIndex = ModeIndex_800x600[Depth]; - else if (VDisplay == 480) - ModeIndex = ModeIndex_800x480[Depth]; - break; - case 848: - if (VDisplay == 480) - ModeIndex = ModeIndex_848x480[Depth]; - break; - case 856: - if (VDisplay == 480) - ModeIndex = ModeIndex_856x480[Depth]; - break; - case 960: - if (VDisplay == 540) - ModeIndex = ModeIndex_960x540[Depth]; - else if (VDisplay == 600) - ModeIndex = ModeIndex_960x600[Depth]; - break; - case 1024: - if (VDisplay == 576) - ModeIndex = ModeIndex_1024x576[Depth]; - else if (VDisplay == 768) - ModeIndex = ModeIndex_1024x768[Depth]; - break; - case 1152: - if (VDisplay == 864) - ModeIndex = ModeIndex_1152x864[Depth]; - break; - case 1280: - switch (VDisplay) { - case 720: - ModeIndex = ModeIndex_1280x720[Depth]; - break; - case 768: - ModeIndex = ModeIndex_1280x768[Depth]; - break; - case 1024: - ModeIndex = ModeIndex_1280x1024[Depth]; - break; - } - } - - return ModeIndex; -} -#endif /* 0 */ - /*********************************************/ /* HELPER: SetReg, GetReg */ /*********************************************/ -- cgit v1.2.3-70-g09d2 From 2acbd647315017c07537287857ea2db36c70eacf Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 10 Aug 2007 09:34:27 -0400 Subject: USB: SisUSB2VGA: Mis-spelled word Trivial fix Signed-off-by: Felipe Balbi Cc: Thomas Winischhofer Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/sisusbvga/sisusb.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/misc/sisusbvga/sisusb.h b/drivers/usb/misc/sisusbvga/sisusb.h index dc0473921e3..7183e762fea 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.h +++ b/drivers/usb/misc/sisusbvga/sisusb.h @@ -44,7 +44,7 @@ #include /* For older kernels, support for text consoles is by default - * off. To ensable text console support, change the following: + * off. To enable text console support, change the following: */ /* #define CONFIG_USB_SISUSBVGA_CON */ -- cgit v1.2.3-70-g09d2 From 1c1772a2609a16b3b590f8390a337dbe25859118 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 10 Aug 2007 09:34:29 -0400 Subject: USB: SisUSB2VGA: Lindent drivers/usb/misc/sisusbvga/sisusb.h Better indentation Signed-off-by: Felipe Balbi Cc: Thomas Winischhofer Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/sisusbvga/sisusb.h | 118 ++++++++++++++++++------------------ 1 file changed, 58 insertions(+), 60 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/misc/sisusbvga/sisusb.h b/drivers/usb/misc/sisusbvga/sisusb.h index 7183e762fea..d2d7872cd02 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.h +++ b/drivers/usb/misc/sisusbvga/sisusb.h @@ -8,27 +8,27 @@ * * Otherwise, the following license terms apply: * - * * Redistribution and use in source and binary forms, with or without - * * modification, are permitted provided that the following conditions - * * are met: - * * 1) Redistributions of source code must retain the above copyright - * * notice, this list of conditions and the following disclaimer. - * * 2) Redistributions in binary form must reproduce the above copyright - * * notice, this list of conditions and the following disclaimer in the - * * documentation and/or other materials provided with the distribution. - * * 3) The name of the author may not be used to endorse or promote products - * * derived from this software without specific prior written permission. - * * - * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR - * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1) Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2) Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3) The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Author: Thomas Winischhofer * @@ -72,7 +72,7 @@ #define SISUSB_IBUF_SIZE 0x01000 #define SISUSB_OBUF_SIZE 0x10000 /* fixed */ -#define NUMOBUFS 8 /* max number of output buffers/output URBs */ +#define NUMOBUFS 8 /* max number of output buffers/output URBs */ /* About endianness: * @@ -103,7 +103,7 @@ struct sisusb_usb_data; -struct sisusb_urb_context { /* urb->context for outbound bulk URBs */ +struct sisusb_urb_context { /* urb->context for outbound bulk URBs */ struct sisusb_usb_data *sisusb; int urbindex; int *actual_length; @@ -114,16 +114,16 @@ struct sisusb_usb_data { struct usb_interface *interface; struct kref kref; wait_queue_head_t wait_q; /* for syncind and timeouts */ - struct mutex lock; /* general race avoidance */ - unsigned int ifnum; /* interface number of the USB device */ - int minor; /* minor (for logging clarity) */ - int isopen; /* !=0 if open */ - int present; /* !=0 if device is present on the bus */ - int ready; /* !=0 if device is ready for userland */ + struct mutex lock; /* general race avoidance */ + unsigned int ifnum; /* interface number of the USB device */ + int minor; /* minor (for logging clarity) */ + int isopen; /* !=0 if open */ + int present; /* !=0 if device is present on the bus */ + int ready; /* !=0 if device is ready for userland */ #ifdef SISUSB_OLD_CONFIG_COMPAT int ioctl32registered; #endif - int numobufs; /* number of obufs = number of out urbs */ + int numobufs; /* number of obufs = number of out urbs */ char *obuf[NUMOBUFS], *ibuf; /* transfer buffers */ int obufsize, ibufsize; dma_addr_t transfer_dma_out[NUMOBUFS]; @@ -134,13 +134,13 @@ struct sisusb_usb_data { unsigned char completein; struct sisusb_urb_context urbout_context[NUMOBUFS]; unsigned long flagb0; - unsigned long vrambase; /* framebuffer base */ - unsigned int vramsize; /* framebuffer size (bytes) */ + unsigned long vrambase; /* framebuffer base */ + unsigned int vramsize; /* framebuffer size (bytes) */ unsigned long mmiobase; unsigned int mmiosize; unsigned long ioportbase; - unsigned char devinit; /* device initialized? */ - unsigned char gfxinit; /* graphics core initialized? */ + unsigned char devinit; /* device initialized? */ + unsigned char gfxinit; /* graphics core initialized? */ unsigned short chipid, chipvendor; unsigned short chiprevision; #ifdef INCL_SISUSB_CON @@ -150,7 +150,7 @@ struct sisusb_usb_data { int haveconsole, con_first, con_last; int havethisconsole[MAX_NR_CONSOLES]; int textmodedestroyed; - unsigned int sisusb_num_columns; /* real number, not vt's idea */ + unsigned int sisusb_num_columns; /* real number, not vt's idea */ int cur_start_addr, con_rolled_over; int sisusb_cursor_loc, bad_cursor_pos; int sisusb_cursor_size_from; @@ -195,7 +195,7 @@ struct sisusb_packet { unsigned short header; u32 address; u32 data; -} __attribute__((__packed__)); +} __attribute__ ((__packed__)); #define CLEARPACKET(packet) memset(packet, 0, 10) @@ -263,36 +263,36 @@ struct sisusb_packet { /* Structure argument for SISUSB_GET_INFO ioctl */ struct sisusb_info { - __u32 sisusb_id; /* for identifying sisusb */ -#define SISUSB_ID 0x53495355 /* Identify myself with 'SISU' */ - __u8 sisusb_version; - __u8 sisusb_revision; - __u8 sisusb_patchlevel; - __u8 sisusb_gfxinit; /* graphics core initialized? */ + __u32 sisusb_id; /* for identifying sisusb */ +#define SISUSB_ID 0x53495355 /* Identify myself with 'SISU' */ + __u8 sisusb_version; + __u8 sisusb_revision; + __u8 sisusb_patchlevel; + __u8 sisusb_gfxinit; /* graphics core initialized? */ - __u32 sisusb_vrambase; - __u32 sisusb_mmiobase; - __u32 sisusb_iobase; - __u32 sisusb_pcibase; + __u32 sisusb_vrambase; + __u32 sisusb_mmiobase; + __u32 sisusb_iobase; + __u32 sisusb_pcibase; - __u32 sisusb_vramsize; /* framebuffer size in bytes */ + __u32 sisusb_vramsize; /* framebuffer size in bytes */ - __u32 sisusb_minor; + __u32 sisusb_minor; - __u32 sisusb_fbdevactive; /* != 0 if framebuffer device active */ + __u32 sisusb_fbdevactive; /* != 0 if framebuffer device active */ - __u32 sisusb_conactive; /* != 0 if console driver active */ + __u32 sisusb_conactive; /* != 0 if console driver active */ - __u8 sisusb_reserved[28]; /* for future use */ + __u8 sisusb_reserved[28]; /* for future use */ }; struct sisusb_command { - __u8 operation; /* see below */ - __u8 data0; /* operation dependent */ - __u8 data1; /* operation dependent */ - __u8 data2; /* operation dependent */ - __u32 data3; /* operation dependent */ - __u32 data4; /* for future use */ + __u8 operation; /* see below */ + __u8 data0; /* operation dependent */ + __u8 data1; /* operation dependent */ + __u8 data2; /* operation dependent */ + __u32 data3; /* operation dependent */ + __u32 data4; /* for future use */ }; #define SUCMD_GET 0x01 /* for all: data0 = index, data3 = port */ @@ -304,7 +304,7 @@ struct sisusb_command { #define SUCMD_CLRSCR 0x07 /* data0:1:2 = length, data3 = address */ -#define SUCMD_HANDLETEXTMODE 0x08 /* Reset/destroy text mode */ +#define SUCMD_HANDLETEXTMODE 0x08 /* Reset/destroy text mode */ #define SUCMD_SETMODE 0x09 /* Set a display mode (data3 = SiS mode) */ #define SUCMD_SETVESAMODE 0x0a /* Set a display mode (data3 = VESA mode) */ @@ -313,6 +313,4 @@ struct sisusb_command { #define SISUSB_GET_CONFIG_SIZE _IOR(0xF3,0x3E,__u32) #define SISUSB_GET_CONFIG _IOR(0xF3,0x3F,struct sisusb_info) - #endif /* SISUSB_H */ - -- cgit v1.2.3-70-g09d2 From 22b2c526e70741ce8a244cab339fe0f56ace8cb6 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 10 Aug 2007 09:34:31 -0400 Subject: USB: SisUSB2VGA: Lindent drivers/usb/misc/sisusbvga/sisusb_init.c Better indentation Signed-off-by: Felipe Balbi Cc: Thomas Winischhofer Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/sisusbvga/sisusb_init.c | 262 ++++++++++++++++--------------- 1 file changed, 133 insertions(+), 129 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.c b/drivers/usb/misc/sisusbvga/sisusb_init.c index 5d8358295e7..273de5d0934 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_init.c +++ b/drivers/usb/misc/sisusbvga/sisusb_init.c @@ -55,18 +55,17 @@ /* POINTER INITIALIZATION */ /*********************************************/ -static void -SiSUSB_InitPtr(struct SiS_Private *SiS_Pr) +static void SiSUSB_InitPtr(struct SiS_Private *SiS_Pr) { - SiS_Pr->SiS_ModeResInfo = SiSUSB_ModeResInfo; - SiS_Pr->SiS_StandTable = SiSUSB_StandTable; + SiS_Pr->SiS_ModeResInfo = SiSUSB_ModeResInfo; + SiS_Pr->SiS_StandTable = SiSUSB_StandTable; - SiS_Pr->SiS_SModeIDTable = SiSUSB_SModeIDTable; - SiS_Pr->SiS_EModeIDTable = SiSUSB_EModeIDTable; - SiS_Pr->SiS_RefIndex = SiSUSB_RefIndex; - SiS_Pr->SiS_CRT1Table = SiSUSB_CRT1Table; + SiS_Pr->SiS_SModeIDTable = SiSUSB_SModeIDTable; + SiS_Pr->SiS_EModeIDTable = SiSUSB_EModeIDTable; + SiS_Pr->SiS_RefIndex = SiSUSB_RefIndex; + SiS_Pr->SiS_CRT1Table = SiSUSB_CRT1Table; - SiS_Pr->SiS_VCLKData = SiSUSB_VCLKData; + SiS_Pr->SiS_VCLKData = SiSUSB_VCLKData; } /*********************************************/ @@ -75,21 +74,20 @@ SiSUSB_InitPtr(struct SiS_Private *SiS_Pr) static void SiS_SetReg(struct SiS_Private *SiS_Pr, unsigned long port, - unsigned short index, unsigned short data) + unsigned short index, unsigned short data) { sisusb_setidxreg(SiS_Pr->sisusb, port, index, data); } static void SiS_SetRegByte(struct SiS_Private *SiS_Pr, unsigned long port, - unsigned short data) + unsigned short data) { sisusb_setreg(SiS_Pr->sisusb, port, data); } static unsigned char -SiS_GetReg(struct SiS_Private *SiS_Pr, unsigned long port, - unsigned short index) +SiS_GetReg(struct SiS_Private *SiS_Pr, unsigned long port, unsigned short index) { u8 data; @@ -110,22 +108,22 @@ SiS_GetRegByte(struct SiS_Private *SiS_Pr, unsigned long port) static void SiS_SetRegANDOR(struct SiS_Private *SiS_Pr, unsigned long port, - unsigned short index, unsigned short DataAND, - unsigned short DataOR) + unsigned short index, unsigned short DataAND, + unsigned short DataOR) { sisusb_setidxregandor(SiS_Pr->sisusb, port, index, DataAND, DataOR); } static void SiS_SetRegAND(struct SiS_Private *SiS_Pr, unsigned long port, - unsigned short index, unsigned short DataAND) + unsigned short index, unsigned short DataAND) { sisusb_setidxregand(SiS_Pr->sisusb, port, index, DataAND); } static void -SiS_SetRegOR(struct SiS_Private *SiS_Pr,unsigned long port, - unsigned short index, unsigned short DataOR) +SiS_SetRegOR(struct SiS_Private *SiS_Pr, unsigned long port, + unsigned short index, unsigned short DataOR) { sisusb_setidxregor(SiS_Pr->sisusb, port, index, DataOR); } @@ -134,8 +132,7 @@ SiS_SetRegOR(struct SiS_Private *SiS_Pr,unsigned long port, /* HELPER: DisplayOn, DisplayOff */ /*********************************************/ -static void -SiS_DisplayOn(struct SiS_Private *SiS_Pr) +static void SiS_DisplayOn(struct SiS_Private *SiS_Pr) { SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, 0xDF); } @@ -144,8 +141,7 @@ SiS_DisplayOn(struct SiS_Private *SiS_Pr) /* HELPER: Init Port Addresses */ /*********************************************/ -static void -SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr) +static void SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr) { SiS_Pr->SiS_P3c4 = BaseAddr + 0x14; SiS_Pr->SiS_P3d4 = BaseAddr + 0x24; @@ -168,8 +164,7 @@ SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr) /* HELPER: GetSysFlags */ /*********************************************/ -static void -SiS_GetSysFlags(struct SiS_Private *SiS_Pr) +static void SiS_GetSysFlags(struct SiS_Private *SiS_Pr) { SiS_Pr->SiS_MyCR63 = 0x63; } @@ -178,8 +173,7 @@ SiS_GetSysFlags(struct SiS_Private *SiS_Pr) /* HELPER: Init PCI & Engines */ /*********************************************/ -static void -SiSInitPCIetc(struct SiS_Private *SiS_Pr) +static void SiSInitPCIetc(struct SiS_Private *SiS_Pr) { SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x20, 0xa1); /* - Enable 2D (0x40) @@ -195,8 +189,7 @@ SiSInitPCIetc(struct SiS_Private *SiS_Pr) /* HELPER: SET SEGMENT REGISTERS */ /*********************************************/ -static void -SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value) +static void SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value) { unsigned short temp; @@ -209,8 +202,7 @@ SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value) SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd, temp); } -static void -SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value) +static void SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value) { unsigned short temp; @@ -223,15 +215,13 @@ SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value) SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd, temp); } -static void -SiS_SetSegmentReg(struct SiS_Private *SiS_Pr, unsigned short value) +static void SiS_SetSegmentReg(struct SiS_Private *SiS_Pr, unsigned short value) { SiS_SetSegRegLower(SiS_Pr, value); SiS_SetSegRegUpper(SiS_Pr, value); } -static void -SiS_ResetSegmentReg(struct SiS_Private *SiS_Pr) +static void SiS_ResetSegmentReg(struct SiS_Private *SiS_Pr) { SiS_SetSegmentReg(SiS_Pr, 0); } @@ -247,14 +237,12 @@ SiS_SetSegmentRegOver(struct SiS_Private *SiS_Pr, unsigned short value) SiS_SetSegmentReg(SiS_Pr, value); } -static void -SiS_ResetSegmentRegOver(struct SiS_Private *SiS_Pr) +static void SiS_ResetSegmentRegOver(struct SiS_Private *SiS_Pr) { SiS_SetSegmentRegOver(SiS_Pr, 0); } -static void -SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr) +static void SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr) { SiS_ResetSegmentReg(SiS_Pr); SiS_ResetSegmentRegOver(SiS_Pr); @@ -266,7 +254,7 @@ SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr) static int SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo, - unsigned short *ModeIdIndex) + unsigned short *ModeIdIndex) { if ((*ModeNo) <= 0x13) { @@ -277,12 +265,14 @@ SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo, } else { - for(*ModeIdIndex = 0; ;(*ModeIdIndex)++) { + for (*ModeIdIndex = 0;; (*ModeIdIndex)++) { - if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == (*ModeNo)) + if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == + (*ModeNo)) break; - if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == 0xFF) + if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == + 0xFF) return 0; } @@ -295,8 +285,7 @@ SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo, /* HELPER: ENABLE CRT1 */ /*********************************************/ -static void -SiS_HandleCRT1(struct SiS_Private *SiS_Pr) +static void SiS_HandleCRT1(struct SiS_Private *SiS_Pr) { /* Enable CRT1 gating */ SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, SiS_Pr->SiS_MyCR63, 0xbf); @@ -308,9 +297,9 @@ SiS_HandleCRT1(struct SiS_Private *SiS_Pr) static unsigned short SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short ModeIdIndex) + unsigned short ModeIdIndex) { - static const unsigned short ColorDepth[6] = { 1, 2, 4, 4, 6, 8}; + static const unsigned short ColorDepth[6] = { 1, 2, 4, 4, 6, 8 }; unsigned short modeflag; short index; @@ -321,7 +310,8 @@ SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo, } index = (modeflag & ModeTypeMask) - ModeEGA; - if (index < 0) index = 0; + if (index < 0) + index = 0; return ColorDepth[index]; } @@ -331,7 +321,7 @@ SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo, static unsigned short SiS_GetOffset(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short ModeIdIndex, unsigned short rrti) + unsigned short ModeIdIndex, unsigned short rrti) { unsigned short xres, temp, colordepth, infoflag; @@ -368,8 +358,8 @@ SiS_SetSeqRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[0] | 0x20; SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, SRdata); - for(i = 2; i <= 4; i++) { - SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[i-1]; + for (i = 2; i <= 4; i++) { + SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[i - 1]; SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, i, SRdata); } } @@ -398,7 +388,7 @@ SiS_SetCRTCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, 0x11, 0x7f); - for(i = 0; i <= 0x18; i++) { + for (i = 0; i <= 0x18; i++) { CRTCdata = SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[i]; SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, i, CRTCdata); } @@ -414,7 +404,7 @@ SiS_SetATTRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) unsigned char ARdata; unsigned short i; - for(i = 0; i <= 0x13; i++) { + for (i = 0; i <= 0x13; i++) { ARdata = SiS_Pr->SiS_StandTable[StandTableIndex].ATTR[i]; SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3da); SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, i); @@ -439,7 +429,7 @@ SiS_SetGRCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) unsigned char GRdata; unsigned short i; - for(i = 0; i <= 0x08; i++) { + for (i = 0; i <= 0x08; i++) { GRdata = SiS_Pr->SiS_StandTable[StandTableIndex].GRC[i]; SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3ce, i, GRdata); } @@ -454,12 +444,11 @@ SiS_SetGRCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) /* CLEAR EXTENDED REGISTERS */ /*********************************************/ -static void -SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo) +static void SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo) { int i; - for(i = 0x0A; i <= 0x0E; i++) { + for (i = 0x0A; i <= 0x0E; i++) { SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, i, 0x00); } @@ -472,15 +461,16 @@ SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo) static unsigned short SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short ModeIdIndex) + unsigned short ModeIdIndex) { unsigned short rrti, i, index, temp; if (ModeNo <= 0x13) return 0xFFFF; - index = SiS_GetReg(SiS_Pr,SiS_Pr->SiS_P3d4, 0x33) & 0x0F; - if (index > 0) index--; + index = SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x33) & 0x0F; + if (index > 0) + index--; rrti = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex; ModeNo = SiS_Pr->SiS_RefIndex[rrti].ModeID; @@ -490,13 +480,14 @@ SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, if (SiS_Pr->SiS_RefIndex[rrti + i].ModeID != ModeNo) break; - temp = SiS_Pr->SiS_RefIndex[rrti + i].Ext_InfoFlag & ModeTypeMask; + temp = + SiS_Pr->SiS_RefIndex[rrti + i].Ext_InfoFlag & ModeTypeMask; if (temp < SiS_Pr->SiS_ModeType) break; i++; index--; - } while(index != 0xFFFF); + } while (index != 0xFFFF); i--; @@ -507,8 +498,7 @@ SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, /* SYNC */ /*********************************************/ -static void -SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti) +static void SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti) { unsigned short sync = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag >> 8; sync &= 0xC0; @@ -522,39 +512,40 @@ SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti) static void SiS_SetCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short ModeIdIndex, unsigned short rrti) + unsigned short ModeIdIndex, unsigned short rrti) { - unsigned char index; + unsigned char index; unsigned short temp, i, j, modeflag; - SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4,0x11,0x7f); + SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, 0x11, 0x7f); modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRT1CRTC; - for(i = 0,j = 0; i <= 7; i++, j++) { + for (i = 0, j = 0; i <= 7; i++, j++) { SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j, - SiS_Pr->SiS_CRT1Table[index].CR[i]); + SiS_Pr->SiS_CRT1Table[index].CR[i]); } - for(j = 0x10; i <= 10; i++, j++) { + for (j = 0x10; i <= 10; i++, j++) { SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j, - SiS_Pr->SiS_CRT1Table[index].CR[i]); + SiS_Pr->SiS_CRT1Table[index].CR[i]); } - for(j = 0x15; i <= 12; i++, j++) { + for (j = 0x15; i <= 12; i++, j++) { SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j, - SiS_Pr->SiS_CRT1Table[index].CR[i]); + SiS_Pr->SiS_CRT1Table[index].CR[i]); } - for(j = 0x0A; i <= 15; i++, j++) { + for (j = 0x0A; i <= 15; i++, j++) { SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, j, - SiS_Pr->SiS_CRT1Table[index].CR[i]); + SiS_Pr->SiS_CRT1Table[index].CR[i]); } temp = SiS_Pr->SiS_CRT1Table[index].CR[16] & 0xE0; - SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4, 0x0E, temp); + SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0E, temp); temp = ((SiS_Pr->SiS_CRT1Table[index].CR[16]) & 0x01) << 5; - if (modeflag & DoubleScanMode) temp |= 0x80; + if (modeflag & DoubleScanMode) + temp |= 0x80; SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3d4, 0x09, 0x5F, temp); if (SiS_Pr->SiS_ModeType > ModeVGA) @@ -569,10 +560,10 @@ SiS_SetCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, static void SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short ModeIdIndex, unsigned short rrti) + unsigned short ModeIdIndex, unsigned short rrti) { unsigned short du = SiS_GetOffset(SiS_Pr, ModeNo, ModeIdIndex, rrti); - unsigned short infoflag = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag; + unsigned short infoflag = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag; unsigned short temp; temp = (du >> 8) & 0x0f; @@ -580,11 +571,13 @@ SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo, SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x13, (du & 0xFF)); - if (infoflag & InterlaceMode) du >>= 1; + if (infoflag & InterlaceMode) + du >>= 1; du <<= 5; temp = (du >> 8) & 0xff; - if (du & 0xff) temp++; + if (du & 0xff) + temp++; temp++; SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x10, temp); } @@ -595,17 +588,17 @@ SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo, static void SiS_SetCRT1VCLK(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short rrti) + unsigned short rrti) { unsigned short index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRTVCLK; unsigned short clka = SiS_Pr->SiS_VCLKData[index].SR2B; unsigned short clkb = SiS_Pr->SiS_VCLKData[index].SR2C; - SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4,0x31,0xCF); + SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x31, 0xCF); - SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2B,clka); - SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2C,clkb); - SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2D,0x01); + SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2B, clka); + SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2C, clkb); + SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2D, 0x01); } /*********************************************/ @@ -614,7 +607,7 @@ SiS_SetCRT1VCLK(struct SiS_Private *SiS_Pr, unsigned short ModeNo, static void SiS_SetCRT1FIFO_310(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short mi) + unsigned short mi) { unsigned short modeflag = SiS_Pr->SiS_EModeIDTable[mi].Ext_ModeFlag; @@ -639,7 +632,7 @@ SiS_SetCRT1FIFO_310(struct SiS_Private *SiS_Pr, unsigned short ModeNo, static void SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short rrti) + unsigned short rrti) { unsigned short data = 0, VCLK = 0, index = 0; @@ -648,7 +641,8 @@ SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo, VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK; } - if (VCLK >= 166) data |= 0x0c; + if (VCLK >= 166) + data |= 0x0c; SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x32, 0xf3, data); if (VCLK >= 166) @@ -668,7 +662,7 @@ SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo, static void SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short ModeIdIndex, unsigned short rrti) + unsigned short ModeIdIndex, unsigned short rrti) { unsigned short data, infoflag = 0, modeflag; @@ -688,17 +682,22 @@ SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo, data |= 0x02; data |= ((SiS_Pr->SiS_ModeType - ModeVGA) << 2); } - if (infoflag & InterlaceMode) data |= 0x20; + if (infoflag & InterlaceMode) + data |= 0x20; } SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x06, 0xC0, data); data = 0; if (infoflag & InterlaceMode) { /* data = (Hsync / 8) - ((Htotal / 8) / 2) + 3 */ - unsigned short hrs = (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x04) | - ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0xc0) << 2)) - 3; - unsigned short hto = (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x00) | - ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0x03) << 8)) + 5; + unsigned short hrs = + (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x04) | + ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0xc0) << 2)) + - 3; + unsigned short hto = + (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x00) | + ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0x03) << 8)) + + 5; data = hrs - (hto >> 1) + 3; } SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x19, (data & 0xFF)); @@ -739,20 +738,26 @@ SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo, static void SiS_WriteDAC(struct SiS_Private *SiS_Pr, unsigned long DACData, - unsigned short shiftflag, unsigned short dl, unsigned short ah, - unsigned short al, unsigned short dh) + unsigned short shiftflag, unsigned short dl, unsigned short ah, + unsigned short al, unsigned short dh) { unsigned short d1, d2, d3; switch (dl) { - case 0: - d1 = dh; d2 = ah; d3 = al; - break; - case 1: - d1 = ah; d2 = al; d3 = dh; - break; - default: - d1 = al; d2 = dh; d3 = ah; + case 0: + d1 = dh; + d2 = ah; + d3 = al; + break; + case 1: + d1 = ah; + d2 = al; + d3 = dh; + break; + default: + d1 = al; + d2 = dh; + d3 = ah; } SiS_SetRegByte(SiS_Pr, DACData, (d1 << shiftflag)); SiS_SetRegByte(SiS_Pr, DACData, (d2 << shiftflag)); @@ -760,7 +765,8 @@ SiS_WriteDAC(struct SiS_Private *SiS_Pr, unsigned long DACData, } static void -SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short mi) +SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short mi) { unsigned short data, data2, time, i, j, k, m, n, o; unsigned short si, di, bx, sf; @@ -794,41 +800,45 @@ SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short mi SiS_SetRegByte(SiS_Pr, DACAddr, 0x00); - for(i = 0; i < j; i++) { + for (i = 0; i < j; i++) { data = table[i]; - for(k = 0; k < 3; k++) { + for (k = 0; k < 3; k++) { data2 = 0; - if (data & 0x01) data2 += 0x2A; - if (data & 0x02) data2 += 0x15; + if (data & 0x01) + data2 += 0x2A; + if (data & 0x02) + data2 += 0x15; SiS_SetRegByte(SiS_Pr, DACData, (data2 << sf)); data >>= 2; } } if (time == 256) { - for(i = 16; i < 32; i++) { + for (i = 16; i < 32; i++) { data = table[i] << sf; - for(k = 0; k < 3; k++) + for (k = 0; k < 3; k++) SiS_SetRegByte(SiS_Pr, DACData, data); } si = 32; - for(m = 0; m < 9; m++) { + for (m = 0; m < 9; m++) { di = si; bx = si + 4; - for(n = 0; n < 3; n++) { - for(o = 0; o < 5; o++) { + for (n = 0; n < 3; n++) { + for (o = 0; o < 5; o++) { SiS_WriteDAC(SiS_Pr, DACData, sf, n, - table[di], table[bx], table[si]); + table[di], table[bx], + table[si]); si++; } si -= 2; - for(o = 0; o < 3; o++) { + for (o = 0; o < 3; o++) { SiS_WriteDAC(SiS_Pr, DACData, sf, n, - table[di], table[si], table[bx]); + table[di], table[si], + table[bx]); si--; } } - si += 5; + si += 5; } } } @@ -839,7 +849,7 @@ SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short mi static void SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short ModeIdIndex) + unsigned short ModeIdIndex) { unsigned short StandTableIndex, rrti; @@ -880,11 +890,10 @@ SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo, /* SiSSetMode() */ /*********************************************/ -int -SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo) +int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo) { unsigned short ModeIdIndex; - unsigned long BaseAddr = SiS_Pr->IOAddress; + unsigned long BaseAddr = SiS_Pr->IOAddress; SiSUSB_InitPtr(SiS_Pr); SiSUSBRegInit(SiS_Pr, BaseAddr); @@ -900,7 +909,7 @@ SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo) ModeNo &= 0x7f; SiS_Pr->SiS_ModeType = - SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag & ModeTypeMask; + SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag & ModeTypeMask; SiS_Pr->SiS_SetFlag = LowModeTests; @@ -918,8 +927,7 @@ SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo) return 1; } -int -SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo) +int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo) { unsigned short ModeNo = 0; int i; @@ -951,7 +959,3 @@ SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo) } #endif /* INCL_SISUSB_CON */ - - - - -- cgit v1.2.3-70-g09d2 From 7c59901421e22cff3fa9b8ea83e7a2fe37951497 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 10 Aug 2007 09:34:32 -0400 Subject: USB: SisUSB2VGA: Lindent drivers/usb/misc/sisusbvga/sisusb_init.h Better indentation Signed-off-by: Felipe Balbi Cc: Thomas Winischhofer Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/sisusbvga/sisusb_init.h | 1311 +++++++++++++++--------------- 1 file changed, 655 insertions(+), 656 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.h b/drivers/usb/misc/sisusbvga/sisusb_init.h index d47301eaca7..c46ce42d448 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_init.h +++ b/drivers/usb/misc/sisusbvga/sisusb_init.h @@ -76,21 +76,21 @@ #define CRT2Mode 0x0800 #define HalfDCLK 0x1000 #define NoSupportSimuTV 0x2000 -#define NoSupportLCDScale 0x4000 /* SiS bridge: No scaling possible (no matter what panel) */ +#define NoSupportLCDScale 0x4000 /* SiS bridge: No scaling possible (no matter what panel) */ #define DoubleScanMode 0x8000 /* Infoflag */ #define SupportTV 0x0008 #define SupportTV1024 0x0800 #define SupportCHTV 0x0800 -#define Support64048060Hz 0x0800 /* Special for 640x480 LCD */ +#define Support64048060Hz 0x0800 /* Special for 640x480 LCD */ #define SupportHiVision 0x0010 #define SupportYPbPr750p 0x1000 #define SupportLCD 0x0020 #define SupportRAMDAC2 0x0040 /* All (<= 100Mhz) */ -#define SupportRAMDAC2_135 0x0100 /* All except DH (<= 135Mhz) */ -#define SupportRAMDAC2_162 0x0200 /* B, C (<= 162Mhz) */ -#define SupportRAMDAC2_202 0x0400 /* C (<= 202Mhz) */ +#define SupportRAMDAC2_135 0x0100 /* All except DH (<= 135Mhz) */ +#define SupportRAMDAC2_162 0x0200 /* B, C (<= 162Mhz) */ +#define SupportRAMDAC2_202 0x0400 /* C (<= 202Mhz) */ #define InterlaceMode 0x0080 #define SyncPP 0x0000 #define SyncPN 0x4000 @@ -129,7 +129,7 @@ #define SIS_RI_856x480 19 #define SIS_RI_1280x768 20 #define SIS_RI_1400x1050 21 -#define SIS_RI_1152x864 22 /* Up to here SiS conforming */ +#define SIS_RI_1152x864 22 /* Up to here SiS conforming */ #define SIS_RI_848x480 23 #define SIS_RI_1360x768 24 #define SIS_RI_1024x600 25 @@ -147,691 +147,691 @@ #define SIS_CRT2_PORT_04 0x04 - 0x30 /* Mode numbers */ -static const unsigned short ModeIndex_320x200[] = {0x59, 0x41, 0x00, 0x4f}; -static const unsigned short ModeIndex_320x240[] = {0x50, 0x56, 0x00, 0x53}; -static const unsigned short ModeIndex_400x300[] = {0x51, 0x57, 0x00, 0x54}; -static const unsigned short ModeIndex_512x384[] = {0x52, 0x58, 0x00, 0x5c}; -static const unsigned short ModeIndex_640x400[] = {0x2f, 0x5d, 0x00, 0x5e}; -static const unsigned short ModeIndex_640x480[] = {0x2e, 0x44, 0x00, 0x62}; -static const unsigned short ModeIndex_720x480[] = {0x31, 0x33, 0x00, 0x35}; -static const unsigned short ModeIndex_720x576[] = {0x32, 0x34, 0x00, 0x36}; -static const unsigned short ModeIndex_768x576[] = {0x5f, 0x60, 0x00, 0x61}; -static const unsigned short ModeIndex_800x480[] = {0x70, 0x7a, 0x00, 0x76}; -static const unsigned short ModeIndex_800x600[] = {0x30, 0x47, 0x00, 0x63}; -static const unsigned short ModeIndex_848x480[] = {0x39, 0x3b, 0x00, 0x3e}; -static const unsigned short ModeIndex_856x480[] = {0x3f, 0x42, 0x00, 0x45}; -static const unsigned short ModeIndex_960x540[] = {0x1d, 0x1e, 0x00, 0x1f}; -static const unsigned short ModeIndex_960x600[] = {0x20, 0x21, 0x00, 0x22}; -static const unsigned short ModeIndex_1024x768[] = {0x38, 0x4a, 0x00, 0x64}; -static const unsigned short ModeIndex_1024x576[] = {0x71, 0x74, 0x00, 0x77}; -static const unsigned short ModeIndex_1152x864[] = {0x29, 0x2a, 0x00, 0x2b}; -static const unsigned short ModeIndex_1280x720[] = {0x79, 0x75, 0x00, 0x78}; -static const unsigned short ModeIndex_1280x768[] = {0x23, 0x24, 0x00, 0x25}; -static const unsigned short ModeIndex_1280x1024[] = {0x3a, 0x4d, 0x00, 0x65}; +static const unsigned short ModeIndex_320x200[] = { 0x59, 0x41, 0x00, 0x4f }; +static const unsigned short ModeIndex_320x240[] = { 0x50, 0x56, 0x00, 0x53 }; +static const unsigned short ModeIndex_400x300[] = { 0x51, 0x57, 0x00, 0x54 }; +static const unsigned short ModeIndex_512x384[] = { 0x52, 0x58, 0x00, 0x5c }; +static const unsigned short ModeIndex_640x400[] = { 0x2f, 0x5d, 0x00, 0x5e }; +static const unsigned short ModeIndex_640x480[] = { 0x2e, 0x44, 0x00, 0x62 }; +static const unsigned short ModeIndex_720x480[] = { 0x31, 0x33, 0x00, 0x35 }; +static const unsigned short ModeIndex_720x576[] = { 0x32, 0x34, 0x00, 0x36 }; +static const unsigned short ModeIndex_768x576[] = { 0x5f, 0x60, 0x00, 0x61 }; +static const unsigned short ModeIndex_800x480[] = { 0x70, 0x7a, 0x00, 0x76 }; +static const unsigned short ModeIndex_800x600[] = { 0x30, 0x47, 0x00, 0x63 }; +static const unsigned short ModeIndex_848x480[] = { 0x39, 0x3b, 0x00, 0x3e }; +static const unsigned short ModeIndex_856x480[] = { 0x3f, 0x42, 0x00, 0x45 }; +static const unsigned short ModeIndex_960x540[] = { 0x1d, 0x1e, 0x00, 0x1f }; +static const unsigned short ModeIndex_960x600[] = { 0x20, 0x21, 0x00, 0x22 }; +static const unsigned short ModeIndex_1024x768[] = { 0x38, 0x4a, 0x00, 0x64 }; +static const unsigned short ModeIndex_1024x576[] = { 0x71, 0x74, 0x00, 0x77 }; +static const unsigned short ModeIndex_1152x864[] = { 0x29, 0x2a, 0x00, 0x2b }; +static const unsigned short ModeIndex_1280x720[] = { 0x79, 0x75, 0x00, 0x78 }; +static const unsigned short ModeIndex_1280x768[] = { 0x23, 0x24, 0x00, 0x25 }; +static const unsigned short ModeIndex_1280x1024[] = { 0x3a, 0x4d, 0x00, 0x65 }; -static const unsigned char SiS_MDA_DAC[] = -{ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, - 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, - 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, - 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, - 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F +static const unsigned char SiS_MDA_DAC[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F }; -static const unsigned char SiS_CGA_DAC[] = -{ - 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, - 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, - 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, - 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, - 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, - 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, - 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, - 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F +static const unsigned char SiS_CGA_DAC[] = { + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, + 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F, + 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F, + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, + 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F, + 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F }; -static const unsigned char SiS_EGA_DAC[] = -{ - 0x00,0x10,0x04,0x14,0x01,0x11,0x05,0x15, - 0x20,0x30,0x24,0x34,0x21,0x31,0x25,0x35, - 0x08,0x18,0x0C,0x1C,0x09,0x19,0x0D,0x1D, - 0x28,0x38,0x2C,0x3C,0x29,0x39,0x2D,0x3D, - 0x02,0x12,0x06,0x16,0x03,0x13,0x07,0x17, - 0x22,0x32,0x26,0x36,0x23,0x33,0x27,0x37, - 0x0A,0x1A,0x0E,0x1E,0x0B,0x1B,0x0F,0x1F, - 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F +static const unsigned char SiS_EGA_DAC[] = { + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x05, 0x15, + 0x20, 0x30, 0x24, 0x34, 0x21, 0x31, 0x25, 0x35, + 0x08, 0x18, 0x0C, 0x1C, 0x09, 0x19, 0x0D, 0x1D, + 0x28, 0x38, 0x2C, 0x3C, 0x29, 0x39, 0x2D, 0x3D, + 0x02, 0x12, 0x06, 0x16, 0x03, 0x13, 0x07, 0x17, + 0x22, 0x32, 0x26, 0x36, 0x23, 0x33, 0x27, 0x37, + 0x0A, 0x1A, 0x0E, 0x1E, 0x0B, 0x1B, 0x0F, 0x1F, + 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F }; -static const unsigned char SiS_VGA_DAC[] = -{ - 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, - 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, - 0x00,0x05,0x08,0x0B,0x0E,0x11,0x14,0x18, - 0x1C,0x20,0x24,0x28,0x2D,0x32,0x38,0x3F, - 0x00,0x10,0x1F,0x2F,0x3F,0x1F,0x27,0x2F, - 0x37,0x3F,0x2D,0x31,0x36,0x3A,0x3F,0x00, - 0x07,0x0E,0x15,0x1C,0x0E,0x11,0x15,0x18, - 0x1C,0x14,0x16,0x18,0x1A,0x1C,0x00,0x04, - 0x08,0x0C,0x10,0x08,0x0A,0x0C,0x0E,0x10, - 0x0B,0x0C,0x0D,0x0F,0x10 +static const unsigned char SiS_VGA_DAC[] = { + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, + 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F, + 0x00, 0x05, 0x08, 0x0B, 0x0E, 0x11, 0x14, 0x18, + 0x1C, 0x20, 0x24, 0x28, 0x2D, 0x32, 0x38, 0x3F, + 0x00, 0x10, 0x1F, 0x2F, 0x3F, 0x1F, 0x27, 0x2F, + 0x37, 0x3F, 0x2D, 0x31, 0x36, 0x3A, 0x3F, 0x00, + 0x07, 0x0E, 0x15, 0x1C, 0x0E, 0x11, 0x15, 0x18, + 0x1C, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x00, 0x04, + 0x08, 0x0C, 0x10, 0x08, 0x0A, 0x0C, 0x0E, 0x10, + 0x0B, 0x0C, 0x0D, 0x0F, 0x10 }; -static const struct SiS_St SiSUSB_SModeIDTable[] = -{ - {0x03,0x0010,0x18,0x02,0x02,0x00,0x01,0x03,0x40}, - {0xff,0x0000,0x00,0x00,0x00,0x00,0x00,0x00,0x00} +static const struct SiS_St SiSUSB_SModeIDTable[] = { + {0x03, 0x0010, 0x18, 0x02, 0x02, 0x00, 0x01, 0x03, 0x40}, + {0xff, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }; -static const struct SiS_StResInfo_S SiSUSB_StResInfo[] = -{ - { 640,400}, - { 640,350}, - { 720,400}, - { 720,350}, - { 640,480} +static const struct SiS_StResInfo_S SiSUSB_StResInfo[] = { + {640, 400}, + {640, 350}, + {720, 400}, + {720, 350}, + {640, 480} }; -static const struct SiS_ModeResInfo SiSUSB_ModeResInfo[] = -{ - { 320, 200, 8, 8}, /* 0x00 */ - { 320, 240, 8, 8}, /* 0x01 */ - { 320, 400, 8, 8}, /* 0x02 */ - { 400, 300, 8, 8}, /* 0x03 */ - { 512, 384, 8, 8}, /* 0x04 */ - { 640, 400, 8,16}, /* 0x05 */ - { 640, 480, 8,16}, /* 0x06 */ - { 800, 600, 8,16}, /* 0x07 */ - { 1024, 768, 8,16}, /* 0x08 */ - { 1280,1024, 8,16}, /* 0x09 */ - { 1600,1200, 8,16}, /* 0x0a */ - { 1920,1440, 8,16}, /* 0x0b */ - { 2048,1536, 8,16}, /* 0x0c */ - { 720, 480, 8,16}, /* 0x0d */ - { 720, 576, 8,16}, /* 0x0e */ - { 1280, 960, 8,16}, /* 0x0f */ - { 800, 480, 8,16}, /* 0x10 */ - { 1024, 576, 8,16}, /* 0x11 */ - { 1280, 720, 8,16}, /* 0x12 */ - { 856, 480, 8,16}, /* 0x13 */ - { 1280, 768, 8,16}, /* 0x14 */ - { 1400,1050, 8,16}, /* 0x15 */ - { 1152, 864, 8,16}, /* 0x16 */ - { 848, 480, 8,16}, /* 0x17 */ - { 1360, 768, 8,16}, /* 0x18 */ - { 1024, 600, 8,16}, /* 0x19 */ - { 1152, 768, 8,16}, /* 0x1a */ - { 768, 576, 8,16}, /* 0x1b */ - { 1360,1024, 8,16}, /* 0x1c */ - { 1680,1050, 8,16}, /* 0x1d */ - { 1280, 800, 8,16}, /* 0x1e */ - { 1920,1080, 8,16}, /* 0x1f */ - { 960, 540, 8,16}, /* 0x20 */ - { 960, 600, 8,16} /* 0x21 */ +static const struct SiS_ModeResInfo SiSUSB_ModeResInfo[] = { + {320, 200, 8, 8}, /* 0x00 */ + {320, 240, 8, 8}, /* 0x01 */ + {320, 400, 8, 8}, /* 0x02 */ + {400, 300, 8, 8}, /* 0x03 */ + {512, 384, 8, 8}, /* 0x04 */ + {640, 400, 8, 16}, /* 0x05 */ + {640, 480, 8, 16}, /* 0x06 */ + {800, 600, 8, 16}, /* 0x07 */ + {1024, 768, 8, 16}, /* 0x08 */ + {1280, 1024, 8, 16}, /* 0x09 */ + {1600, 1200, 8, 16}, /* 0x0a */ + {1920, 1440, 8, 16}, /* 0x0b */ + {2048, 1536, 8, 16}, /* 0x0c */ + {720, 480, 8, 16}, /* 0x0d */ + {720, 576, 8, 16}, /* 0x0e */ + {1280, 960, 8, 16}, /* 0x0f */ + {800, 480, 8, 16}, /* 0x10 */ + {1024, 576, 8, 16}, /* 0x11 */ + {1280, 720, 8, 16}, /* 0x12 */ + {856, 480, 8, 16}, /* 0x13 */ + {1280, 768, 8, 16}, /* 0x14 */ + {1400, 1050, 8, 16}, /* 0x15 */ + {1152, 864, 8, 16}, /* 0x16 */ + {848, 480, 8, 16}, /* 0x17 */ + {1360, 768, 8, 16}, /* 0x18 */ + {1024, 600, 8, 16}, /* 0x19 */ + {1152, 768, 8, 16}, /* 0x1a */ + {768, 576, 8, 16}, /* 0x1b */ + {1360, 1024, 8, 16}, /* 0x1c */ + {1680, 1050, 8, 16}, /* 0x1d */ + {1280, 800, 8, 16}, /* 0x1e */ + {1920, 1080, 8, 16}, /* 0x1f */ + {960, 540, 8, 16}, /* 0x20 */ + {960, 600, 8, 16} /* 0x21 */ }; -static const struct SiS_StandTable SiSUSB_StandTable[] = -{ +static const struct SiS_StandTable SiSUSB_StandTable[] = { /* MD_3_400 - mode 0x03 - 400 */ { - 0x50,0x18,0x10,0x1000, - { 0x00,0x03,0x00,0x02 }, - 0x67, - { 0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, - 0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00, - 0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3, - 0xff }, - { 0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07, - 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, - 0x0c,0x00,0x0f,0x08 }, - { 0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00, 0xff } - }, + 0x50, 0x18, 0x10, 0x1000, + {0x00, 0x03, 0x00, 0x02}, + 0x67, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x0c, 0x00, 0x0f, 0x08}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, 0xff} + }, /* Generic for VGA and higher */ { - 0x00,0x00,0x00,0x0000, - { 0x01,0x0f,0x00,0x0e }, - 0x23, - { 0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e, - 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00, - 0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3, - 0xff }, - { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, - 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, - 0x01,0x00,0x00,0x00 }, - { 0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f, 0xff } - } + 0x00, 0x00, 0x00, 0x0000, + {0x01, 0x0f, 0x00, 0x0e}, + 0x23, + {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xea, 0x8c, 0xdf, 0x28, 0x40, 0xe7, 0x04, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x01, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, 0xff} + } }; -static const struct SiS_Ext SiSUSB_EModeIDTable[] = -{ - {0x2e,0x0a1b,0x0101,SIS_RI_640x480, 0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x8 */ - {0x2f,0x0a1b,0x0100,SIS_RI_640x400, 0x00,0x00,0x05,0x05,0x10, 0}, /* 640x400x8 */ - {0x30,0x2a1b,0x0103,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x8 */ - {0x31,0x4a1b,0x0000,SIS_RI_720x480, 0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x8 */ - {0x32,0x4a1b,0x0000,SIS_RI_720x576, 0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x8 */ - {0x33,0x4a1d,0x0000,SIS_RI_720x480, 0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x16 */ - {0x34,0x6a1d,0x0000,SIS_RI_720x576, 0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x16 */ - {0x35,0x4a1f,0x0000,SIS_RI_720x480, 0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x32 */ - {0x36,0x6a1f,0x0000,SIS_RI_720x576, 0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x32 */ - {0x38,0x0a1b,0x0105,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x8 */ - {0x3a,0x0e3b,0x0107,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x2f, 8}, /* 1280x1024x8 */ - {0x41,0x9a1d,0x010e,SIS_RI_320x200, 0x00,0x00,0x04,0x04,0x1a, 0}, /* 320x200x16 */ - {0x44,0x0a1d,0x0111,SIS_RI_640x480, 0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x16 */ - {0x47,0x2a1d,0x0114,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x16 */ - {0x4a,0x0a3d,0x0117,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x16 */ - {0x4d,0x0e7d,0x011a,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x2f, 8}, /* 1280x1024x16 */ - {0x50,0x9a1b,0x0132,SIS_RI_320x240, 0x00,0x00,0x04,0x04,0x1b, 2}, /* 320x240x8 */ - {0x51,0xba1b,0x0133,SIS_RI_400x300, 0x00,0x00,0x07,0x07,0x1c, 3}, /* 400x300x8 */ - {0x52,0xba1b,0x0134,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x1d, 4}, /* 512x384x8 */ - {0x56,0x9a1d,0x0135,SIS_RI_320x240, 0x00,0x00,0x04,0x04,0x1b, 2}, /* 320x240x16 */ - {0x57,0xba1d,0x0136,SIS_RI_400x300, 0x00,0x00,0x07,0x07,0x1c, 3}, /* 400x300x16 */ - {0x58,0xba1d,0x0137,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x1d, 4}, /* 512x384x16 */ - {0x59,0x9a1b,0x0138,SIS_RI_320x200, 0x00,0x00,0x04,0x04,0x1a, 0}, /* 320x200x8 */ - {0x5c,0xba1f,0x0000,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x1d, 4}, /* 512x384x32 */ - {0x5d,0x0a1d,0x0139,SIS_RI_640x400, 0x00,0x00,0x05,0x07,0x10, 0}, /* 640x400x16 */ - {0x5e,0x0a1f,0x0000,SIS_RI_640x400, 0x00,0x00,0x05,0x07,0x10, 0}, /* 640x400x32 */ - {0x62,0x0a3f,0x013a,SIS_RI_640x480, 0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x32 */ - {0x63,0x2a3f,0x013b,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x32 */ - {0x64,0x0a7f,0x013c,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x32 */ - {0x65,0x0eff,0x013d,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x2f, 8}, /* 1280x1024x32 */ - {0x70,0x6a1b,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x07,0x1e,-1}, /* 800x480x8 */ - {0x71,0x4a1b,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x21,-1}, /* 1024x576x8 */ - {0x74,0x4a1d,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x21,-1}, /* 1024x576x16 */ - {0x75,0x0a3d,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x24, 5}, /* 1280x720x16 */ - {0x76,0x6a1f,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x07,0x1e,-1}, /* 800x480x32 */ - {0x77,0x4a1f,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x21,-1}, /* 1024x576x32 */ - {0x78,0x0a3f,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x24, 5}, /* 1280x720x32 */ - {0x79,0x0a3b,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x24, 5}, /* 1280x720x8 */ - {0x7a,0x6a1d,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x07,0x1e,-1}, /* 800x480x16 */ - {0x23,0x0e3b,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x27, 6}, /* 1280x768x8 */ - {0x24,0x0e7d,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x27, 6}, /* 1280x768x16 */ - {0x25,0x0eff,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x27, 6}, /* 1280x768x32 */ - {0x39,0x6a1b,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x28,-1}, /* 848x480 */ - {0x3b,0x6a3d,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x28,-1}, - {0x3e,0x6a7f,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x28,-1}, - {0x3f,0x6a1b,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x2a,-1}, /* 856x480 */ - {0x42,0x6a3d,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x2a,-1}, - {0x45,0x6a7f,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x2a,-1}, - {0x4f,0x9a1f,0x0000,SIS_RI_320x200, 0x00,0x00,0x04,0x04,0x1a, 0}, /* 320x200x32 */ - {0x53,0x9a1f,0x0000,SIS_RI_320x240, 0x00,0x00,0x04,0x04,0x1b, 2}, /* 320x240x32 */ - {0x54,0xba1f,0x0000,SIS_RI_400x300, 0x00,0x00,0x07,0x07,0x1c, 3}, /* 400x300x32 */ - {0x5f,0x6a1b,0x0000,SIS_RI_768x576, 0x00,0x00,0x06,0x06,0x2c,-1}, /* 768x576 */ - {0x60,0x6a1d,0x0000,SIS_RI_768x576, 0x00,0x00,0x06,0x06,0x2c,-1}, - {0x61,0x6a3f,0x0000,SIS_RI_768x576, 0x00,0x00,0x06,0x06,0x2c,-1}, - {0x1d,0x6a1b,0x0000,SIS_RI_960x540, 0x00,0x00,0x00,0x00,0x2d,-1}, /* 960x540 */ - {0x1e,0x6a3d,0x0000,SIS_RI_960x540, 0x00,0x00,0x00,0x00,0x2d,-1}, - {0x1f,0x6a7f,0x0000,SIS_RI_960x540, 0x00,0x00,0x00,0x00,0x2d,-1}, - {0x20,0x6a1b,0x0000,SIS_RI_960x600, 0x00,0x00,0x00,0x00,0x2e,-1}, /* 960x600 */ - {0x21,0x6a3d,0x0000,SIS_RI_960x600, 0x00,0x00,0x00,0x00,0x2e,-1}, - {0x22,0x6a7f,0x0000,SIS_RI_960x600, 0x00,0x00,0x00,0x00,0x2e,-1}, - {0x29,0x4e1b,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x33,-1}, /* 1152x864 */ - {0x2a,0x4e3d,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x33,-1}, - {0x2b,0x4e7f,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x33,-1}, - {0xff,0x0000,0x0000,0, 0x00,0x00,0x00,0x00,0x00,-1} +static const struct SiS_Ext SiSUSB_EModeIDTable[] = { + {0x2e, 0x0a1b, 0x0101, SIS_RI_640x480, 0x00, 0x00, 0x05, 0x05, 0x08, 2}, /* 640x480x8 */ + {0x2f, 0x0a1b, 0x0100, SIS_RI_640x400, 0x00, 0x00, 0x05, 0x05, 0x10, 0}, /* 640x400x8 */ + {0x30, 0x2a1b, 0x0103, SIS_RI_800x600, 0x00, 0x00, 0x07, 0x06, 0x00, 3}, /* 800x600x8 */ + {0x31, 0x4a1b, 0x0000, SIS_RI_720x480, 0x00, 0x00, 0x06, 0x06, 0x11, -1}, /* 720x480x8 */ + {0x32, 0x4a1b, 0x0000, SIS_RI_720x576, 0x00, 0x00, 0x06, 0x06, 0x12, -1}, /* 720x576x8 */ + {0x33, 0x4a1d, 0x0000, SIS_RI_720x480, 0x00, 0x00, 0x06, 0x06, 0x11, -1}, /* 720x480x16 */ + {0x34, 0x6a1d, 0x0000, SIS_RI_720x576, 0x00, 0x00, 0x06, 0x06, 0x12, -1}, /* 720x576x16 */ + {0x35, 0x4a1f, 0x0000, SIS_RI_720x480, 0x00, 0x00, 0x06, 0x06, 0x11, -1}, /* 720x480x32 */ + {0x36, 0x6a1f, 0x0000, SIS_RI_720x576, 0x00, 0x00, 0x06, 0x06, 0x12, -1}, /* 720x576x32 */ + {0x38, 0x0a1b, 0x0105, SIS_RI_1024x768, 0x00, 0x00, 0x08, 0x07, 0x13, 4}, /* 1024x768x8 */ + {0x3a, 0x0e3b, 0x0107, SIS_RI_1280x1024, 0x00, 0x00, 0x00, 0x00, 0x2f, 8}, /* 1280x1024x8 */ + {0x41, 0x9a1d, 0x010e, SIS_RI_320x200, 0x00, 0x00, 0x04, 0x04, 0x1a, 0}, /* 320x200x16 */ + {0x44, 0x0a1d, 0x0111, SIS_RI_640x480, 0x00, 0x00, 0x05, 0x05, 0x08, 2}, /* 640x480x16 */ + {0x47, 0x2a1d, 0x0114, SIS_RI_800x600, 0x00, 0x00, 0x07, 0x06, 0x00, 3}, /* 800x600x16 */ + {0x4a, 0x0a3d, 0x0117, SIS_RI_1024x768, 0x00, 0x00, 0x08, 0x07, 0x13, 4}, /* 1024x768x16 */ + {0x4d, 0x0e7d, 0x011a, SIS_RI_1280x1024, 0x00, 0x00, 0x00, 0x00, 0x2f, 8}, /* 1280x1024x16 */ + {0x50, 0x9a1b, 0x0132, SIS_RI_320x240, 0x00, 0x00, 0x04, 0x04, 0x1b, 2}, /* 320x240x8 */ + {0x51, 0xba1b, 0x0133, SIS_RI_400x300, 0x00, 0x00, 0x07, 0x07, 0x1c, 3}, /* 400x300x8 */ + {0x52, 0xba1b, 0x0134, SIS_RI_512x384, 0x00, 0x00, 0x00, 0x00, 0x1d, 4}, /* 512x384x8 */ + {0x56, 0x9a1d, 0x0135, SIS_RI_320x240, 0x00, 0x00, 0x04, 0x04, 0x1b, 2}, /* 320x240x16 */ + {0x57, 0xba1d, 0x0136, SIS_RI_400x300, 0x00, 0x00, 0x07, 0x07, 0x1c, 3}, /* 400x300x16 */ + {0x58, 0xba1d, 0x0137, SIS_RI_512x384, 0x00, 0x00, 0x00, 0x00, 0x1d, 4}, /* 512x384x16 */ + {0x59, 0x9a1b, 0x0138, SIS_RI_320x200, 0x00, 0x00, 0x04, 0x04, 0x1a, 0}, /* 320x200x8 */ + {0x5c, 0xba1f, 0x0000, SIS_RI_512x384, 0x00, 0x00, 0x00, 0x00, 0x1d, 4}, /* 512x384x32 */ + {0x5d, 0x0a1d, 0x0139, SIS_RI_640x400, 0x00, 0x00, 0x05, 0x07, 0x10, 0}, /* 640x400x16 */ + {0x5e, 0x0a1f, 0x0000, SIS_RI_640x400, 0x00, 0x00, 0x05, 0x07, 0x10, 0}, /* 640x400x32 */ + {0x62, 0x0a3f, 0x013a, SIS_RI_640x480, 0x00, 0x00, 0x05, 0x05, 0x08, 2}, /* 640x480x32 */ + {0x63, 0x2a3f, 0x013b, SIS_RI_800x600, 0x00, 0x00, 0x07, 0x06, 0x00, 3}, /* 800x600x32 */ + {0x64, 0x0a7f, 0x013c, SIS_RI_1024x768, 0x00, 0x00, 0x08, 0x07, 0x13, 4}, /* 1024x768x32 */ + {0x65, 0x0eff, 0x013d, SIS_RI_1280x1024, 0x00, 0x00, 0x00, 0x00, 0x2f, 8}, /* 1280x1024x32 */ + {0x70, 0x6a1b, 0x0000, SIS_RI_800x480, 0x00, 0x00, 0x07, 0x07, 0x1e, -1}, /* 800x480x8 */ + {0x71, 0x4a1b, 0x0000, SIS_RI_1024x576, 0x00, 0x00, 0x00, 0x00, 0x21, -1}, /* 1024x576x8 */ + {0x74, 0x4a1d, 0x0000, SIS_RI_1024x576, 0x00, 0x00, 0x00, 0x00, 0x21, -1}, /* 1024x576x16 */ + {0x75, 0x0a3d, 0x0000, SIS_RI_1280x720, 0x00, 0x00, 0x00, 0x00, 0x24, 5}, /* 1280x720x16 */ + {0x76, 0x6a1f, 0x0000, SIS_RI_800x480, 0x00, 0x00, 0x07, 0x07, 0x1e, -1}, /* 800x480x32 */ + {0x77, 0x4a1f, 0x0000, SIS_RI_1024x576, 0x00, 0x00, 0x00, 0x00, 0x21, -1}, /* 1024x576x32 */ + {0x78, 0x0a3f, 0x0000, SIS_RI_1280x720, 0x00, 0x00, 0x00, 0x00, 0x24, 5}, /* 1280x720x32 */ + {0x79, 0x0a3b, 0x0000, SIS_RI_1280x720, 0x00, 0x00, 0x00, 0x00, 0x24, 5}, /* 1280x720x8 */ + {0x7a, 0x6a1d, 0x0000, SIS_RI_800x480, 0x00, 0x00, 0x07, 0x07, 0x1e, -1}, /* 800x480x16 */ + {0x23, 0x0e3b, 0x0000, SIS_RI_1280x768, 0x00, 0x00, 0x00, 0x00, 0x27, 6}, /* 1280x768x8 */ + {0x24, 0x0e7d, 0x0000, SIS_RI_1280x768, 0x00, 0x00, 0x00, 0x00, 0x27, 6}, /* 1280x768x16 */ + {0x25, 0x0eff, 0x0000, SIS_RI_1280x768, 0x00, 0x00, 0x00, 0x00, 0x27, 6}, /* 1280x768x32 */ + {0x39, 0x6a1b, 0x0000, SIS_RI_848x480, 0x00, 0x00, 0x00, 0x00, 0x28, -1}, /* 848x480 */ + {0x3b, 0x6a3d, 0x0000, SIS_RI_848x480, 0x00, 0x00, 0x00, 0x00, 0x28, + -1}, + {0x3e, 0x6a7f, 0x0000, SIS_RI_848x480, 0x00, 0x00, 0x00, 0x00, 0x28, + -1}, + {0x3f, 0x6a1b, 0x0000, SIS_RI_856x480, 0x00, 0x00, 0x00, 0x00, 0x2a, -1}, /* 856x480 */ + {0x42, 0x6a3d, 0x0000, SIS_RI_856x480, 0x00, 0x00, 0x00, 0x00, 0x2a, + -1}, + {0x45, 0x6a7f, 0x0000, SIS_RI_856x480, 0x00, 0x00, 0x00, 0x00, 0x2a, + -1}, + {0x4f, 0x9a1f, 0x0000, SIS_RI_320x200, 0x00, 0x00, 0x04, 0x04, 0x1a, 0}, /* 320x200x32 */ + {0x53, 0x9a1f, 0x0000, SIS_RI_320x240, 0x00, 0x00, 0x04, 0x04, 0x1b, 2}, /* 320x240x32 */ + {0x54, 0xba1f, 0x0000, SIS_RI_400x300, 0x00, 0x00, 0x07, 0x07, 0x1c, 3}, /* 400x300x32 */ + {0x5f, 0x6a1b, 0x0000, SIS_RI_768x576, 0x00, 0x00, 0x06, 0x06, 0x2c, -1}, /* 768x576 */ + {0x60, 0x6a1d, 0x0000, SIS_RI_768x576, 0x00, 0x00, 0x06, 0x06, 0x2c, + -1}, + {0x61, 0x6a3f, 0x0000, SIS_RI_768x576, 0x00, 0x00, 0x06, 0x06, 0x2c, + -1}, + {0x1d, 0x6a1b, 0x0000, SIS_RI_960x540, 0x00, 0x00, 0x00, 0x00, 0x2d, -1}, /* 960x540 */ + {0x1e, 0x6a3d, 0x0000, SIS_RI_960x540, 0x00, 0x00, 0x00, 0x00, 0x2d, + -1}, + {0x1f, 0x6a7f, 0x0000, SIS_RI_960x540, 0x00, 0x00, 0x00, 0x00, 0x2d, + -1}, + {0x20, 0x6a1b, 0x0000, SIS_RI_960x600, 0x00, 0x00, 0x00, 0x00, 0x2e, -1}, /* 960x600 */ + {0x21, 0x6a3d, 0x0000, SIS_RI_960x600, 0x00, 0x00, 0x00, 0x00, 0x2e, + -1}, + {0x22, 0x6a7f, 0x0000, SIS_RI_960x600, 0x00, 0x00, 0x00, 0x00, 0x2e, + -1}, + {0x29, 0x4e1b, 0x0000, SIS_RI_1152x864, 0x00, 0x00, 0x00, 0x00, 0x33, -1}, /* 1152x864 */ + {0x2a, 0x4e3d, 0x0000, SIS_RI_1152x864, 0x00, 0x00, 0x00, 0x00, 0x33, + -1}, + {0x2b, 0x4e7f, 0x0000, SIS_RI_1152x864, 0x00, 0x00, 0x00, 0x00, 0x33, + -1}, + {0xff, 0x0000, 0x0000, 0, 0x00, 0x00, 0x00, 0x00, 0x00, -1} }; -static const struct SiS_Ext2 SiSUSB_RefIndex[] = -{ - {0x085f,0x0d,0x03,0x05,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x0 */ - {0x0067,0x0e,0x04,0x05,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x1 */ - {0x0067,0x0f,0x08,0x48,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x2 */ - {0x0067,0x10,0x07,0x8b,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x3 */ - {0x0047,0x11,0x0a,0x00,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x4 */ - {0x0047,0x12,0x0d,0x00,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x5 */ - {0x0047,0x13,0x13,0x00,0x05,0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x6 */ - {0x0107,0x14,0x1c,0x00,0x05,0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x7 */ - {0xc85f,0x05,0x00,0x04,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x8 */ - {0xc067,0x06,0x02,0x04,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x9 */ - {0xc067,0x07,0x02,0x47,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xa */ - {0xc067,0x08,0x03,0x8a,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xb */ - {0xc047,0x09,0x05,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xc */ - {0xc047,0x0a,0x09,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xd */ - {0xc047,0x0b,0x0e,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xe */ - {0xc047,0x0c,0x15,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xf */ - {0x487f,0x04,0x00,0x00,0x00,0x2f, 640, 400, 0x30, 0x55, 0x6e}, /* 0x10 */ - {0xc06f,0x3c,0x01,0x06,0x13,0x31, 720, 480, 0x30, 0x00, 0x00}, /* 0x11 */ - {0x006f,0x3d,0x6f,0x06,0x14,0x32, 720, 576, 0x30, 0x00, 0x00}, /* 0x12 (6f was 03) */ - {0x0087,0x15,0x06,0x00,0x06,0x38,1024, 768, 0x30, 0x00, 0x00}, /* 0x13 */ - {0xc877,0x16,0x0b,0x06,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x14 */ - {0xc067,0x17,0x0f,0x49,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x15 */ - {0x0067,0x18,0x11,0x00,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x16 */ - {0x0047,0x19,0x16,0x8c,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x17 */ - {0x0107,0x1a,0x1b,0x00,0x06,0x38,1024, 768, 0x10, 0x00, 0x00}, /* 0x18 */ - {0x0107,0x1b,0x1f,0x00,0x06,0x38,1024, 768, 0x10, 0x00, 0x00}, /* 0x19 */ - {0x407f,0x00,0x00,0x00,0x00,0x41, 320, 200, 0x30, 0x56, 0x4e}, /* 0x1a */ - {0xc07f,0x01,0x00,0x04,0x04,0x50, 320, 240, 0x30, 0x00, 0x00}, /* 0x1b */ - {0x007f,0x02,0x04,0x05,0x05,0x51, 400, 300, 0x30, 0x00, 0x00}, /* 0x1c */ - {0xc077,0x03,0x0b,0x06,0x06,0x52, 512, 384, 0x30, 0x00, 0x00}, /* 0x1d */ - {0x0077,0x32,0x40,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1e */ - {0x0047,0x33,0x07,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1f */ - {0x0047,0x34,0x0a,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x20 */ - {0x0077,0x35,0x0b,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00}, /* 0x21 */ - {0x0047,0x36,0x11,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00}, /* 0x22 */ - {0x0047,0x37,0x16,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00}, /* 0x23 */ - {0x1137,0x38,0x19,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00}, /* 0x24 */ - {0x1107,0x39,0x1e,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00}, /* 0x25 */ - {0x1307,0x3a,0x20,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00}, /* 0x26 */ - {0x0077,0x42,0x5b,0x08,0x11,0x23,1280, 768, 0x30, 0x00, 0x00}, /* 0x27 */ - {0x0087,0x45,0x57,0x00,0x16,0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x28 38Hzi */ - {0xc067,0x46,0x55,0x0b,0x16,0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x29 848x480-60Hz */ - {0x0087,0x47,0x57,0x00,0x17,0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2a 856x480-38Hzi */ - {0xc067,0x48,0x57,0x00,0x17,0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2b 856x480-60Hz */ - {0x006f,0x4d,0x71,0x06,0x15,0x5f, 768, 576, 0x30, 0x00, 0x00}, /* 0x2c 768x576-56Hz */ - {0x0067,0x52,0x6a,0x00,0x1c,0x1d, 960, 540, 0x30, 0x00, 0x00}, /* 0x2d 960x540 60Hz */ - {0x0077,0x53,0x6b,0x0b,0x1d,0x20, 960, 600, 0x30, 0x00, 0x00}, /* 0x2e 960x600 60Hz */ - {0x0087,0x1c,0x11,0x00,0x07,0x3a,1280,1024, 0x30, 0x00, 0x00}, /* 0x2f */ - {0x0137,0x1d,0x19,0x07,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00}, /* 0x30 */ - {0x0107,0x1e,0x1e,0x00,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00}, /* 0x31 */ - {0x0207,0x1f,0x20,0x00,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00}, /* 0x32 */ - {0x0127,0x54,0x6d,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00}, /* 0x33 1152x864-60Hz */ - {0x0127,0x44,0x19,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00}, /* 0x34 1152x864-75Hz */ - {0x0127,0x4a,0x1e,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00}, /* 0x35 1152x864-85Hz */ - {0xffff,0x00,0x00,0x00,0x00,0x00, 0, 0, 0, 0x00, 0x00} +static const struct SiS_Ext2 SiSUSB_RefIndex[] = { + {0x085f, 0x0d, 0x03, 0x05, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x0 */ + {0x0067, 0x0e, 0x04, 0x05, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x1 */ + {0x0067, 0x0f, 0x08, 0x48, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x2 */ + {0x0067, 0x10, 0x07, 0x8b, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x3 */ + {0x0047, 0x11, 0x0a, 0x00, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x4 */ + {0x0047, 0x12, 0x0d, 0x00, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x5 */ + {0x0047, 0x13, 0x13, 0x00, 0x05, 0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x6 */ + {0x0107, 0x14, 0x1c, 0x00, 0x05, 0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x7 */ + {0xc85f, 0x05, 0x00, 0x04, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x8 */ + {0xc067, 0x06, 0x02, 0x04, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x9 */ + {0xc067, 0x07, 0x02, 0x47, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xa */ + {0xc067, 0x08, 0x03, 0x8a, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xb */ + {0xc047, 0x09, 0x05, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xc */ + {0xc047, 0x0a, 0x09, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xd */ + {0xc047, 0x0b, 0x0e, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xe */ + {0xc047, 0x0c, 0x15, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xf */ + {0x487f, 0x04, 0x00, 0x00, 0x00, 0x2f, 640, 400, 0x30, 0x55, 0x6e}, /* 0x10 */ + {0xc06f, 0x3c, 0x01, 0x06, 0x13, 0x31, 720, 480, 0x30, 0x00, 0x00}, /* 0x11 */ + {0x006f, 0x3d, 0x6f, 0x06, 0x14, 0x32, 720, 576, 0x30, 0x00, 0x00}, /* 0x12 (6f was 03) */ + {0x0087, 0x15, 0x06, 0x00, 0x06, 0x38, 1024, 768, 0x30, 0x00, 0x00}, /* 0x13 */ + {0xc877, 0x16, 0x0b, 0x06, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00}, /* 0x14 */ + {0xc067, 0x17, 0x0f, 0x49, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00}, /* 0x15 */ + {0x0067, 0x18, 0x11, 0x00, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00}, /* 0x16 */ + {0x0047, 0x19, 0x16, 0x8c, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00}, /* 0x17 */ + {0x0107, 0x1a, 0x1b, 0x00, 0x06, 0x38, 1024, 768, 0x10, 0x00, 0x00}, /* 0x18 */ + {0x0107, 0x1b, 0x1f, 0x00, 0x06, 0x38, 1024, 768, 0x10, 0x00, 0x00}, /* 0x19 */ + {0x407f, 0x00, 0x00, 0x00, 0x00, 0x41, 320, 200, 0x30, 0x56, 0x4e}, /* 0x1a */ + {0xc07f, 0x01, 0x00, 0x04, 0x04, 0x50, 320, 240, 0x30, 0x00, 0x00}, /* 0x1b */ + {0x007f, 0x02, 0x04, 0x05, 0x05, 0x51, 400, 300, 0x30, 0x00, 0x00}, /* 0x1c */ + {0xc077, 0x03, 0x0b, 0x06, 0x06, 0x52, 512, 384, 0x30, 0x00, 0x00}, /* 0x1d */ + {0x0077, 0x32, 0x40, 0x08, 0x18, 0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1e */ + {0x0047, 0x33, 0x07, 0x08, 0x18, 0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1f */ + {0x0047, 0x34, 0x0a, 0x08, 0x18, 0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x20 */ + {0x0077, 0x35, 0x0b, 0x09, 0x19, 0x71, 1024, 576, 0x30, 0x00, 0x00}, /* 0x21 */ + {0x0047, 0x36, 0x11, 0x09, 0x19, 0x71, 1024, 576, 0x30, 0x00, 0x00}, /* 0x22 */ + {0x0047, 0x37, 0x16, 0x09, 0x19, 0x71, 1024, 576, 0x30, 0x00, 0x00}, /* 0x23 */ + {0x1137, 0x38, 0x19, 0x0a, 0x0c, 0x75, 1280, 720, 0x30, 0x00, 0x00}, /* 0x24 */ + {0x1107, 0x39, 0x1e, 0x0a, 0x0c, 0x75, 1280, 720, 0x30, 0x00, 0x00}, /* 0x25 */ + {0x1307, 0x3a, 0x20, 0x0a, 0x0c, 0x75, 1280, 720, 0x30, 0x00, 0x00}, /* 0x26 */ + {0x0077, 0x42, 0x5b, 0x08, 0x11, 0x23, 1280, 768, 0x30, 0x00, 0x00}, /* 0x27 */ + {0x0087, 0x45, 0x57, 0x00, 0x16, 0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x28 38Hzi */ + {0xc067, 0x46, 0x55, 0x0b, 0x16, 0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x29 848x480-60Hz */ + {0x0087, 0x47, 0x57, 0x00, 0x17, 0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2a 856x480-38Hzi */ + {0xc067, 0x48, 0x57, 0x00, 0x17, 0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2b 856x480-60Hz */ + {0x006f, 0x4d, 0x71, 0x06, 0x15, 0x5f, 768, 576, 0x30, 0x00, 0x00}, /* 0x2c 768x576-56Hz */ + {0x0067, 0x52, 0x6a, 0x00, 0x1c, 0x1d, 960, 540, 0x30, 0x00, 0x00}, /* 0x2d 960x540 60Hz */ + {0x0077, 0x53, 0x6b, 0x0b, 0x1d, 0x20, 960, 600, 0x30, 0x00, 0x00}, /* 0x2e 960x600 60Hz */ + {0x0087, 0x1c, 0x11, 0x00, 0x07, 0x3a, 1280, 1024, 0x30, 0x00, 0x00}, /* 0x2f */ + {0x0137, 0x1d, 0x19, 0x07, 0x07, 0x3a, 1280, 1024, 0x00, 0x00, 0x00}, /* 0x30 */ + {0x0107, 0x1e, 0x1e, 0x00, 0x07, 0x3a, 1280, 1024, 0x00, 0x00, 0x00}, /* 0x31 */ + {0x0207, 0x1f, 0x20, 0x00, 0x07, 0x3a, 1280, 1024, 0x00, 0x00, 0x00}, /* 0x32 */ + {0x0127, 0x54, 0x6d, 0x00, 0x1a, 0x29, 1152, 864, 0x30, 0x00, 0x00}, /* 0x33 1152x864-60Hz */ + {0x0127, 0x44, 0x19, 0x00, 0x1a, 0x29, 1152, 864, 0x30, 0x00, 0x00}, /* 0x34 1152x864-75Hz */ + {0x0127, 0x4a, 0x1e, 0x00, 0x1a, 0x29, 1152, 864, 0x30, 0x00, 0x00}, /* 0x35 1152x864-85Hz */ + {0xffff, 0x00, 0x00, 0x00, 0x00, 0x00, 0, 0, 0, 0x00, 0x00} }; -static const struct SiS_CRT1Table SiSUSB_CRT1Table[] = -{ - {{0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f, - 0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x00, - 0x00}}, /* 0x0 */ - {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e, - 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00, - 0x00}}, /* 0x1 */ - {{0x3d,0x31,0x31,0x81,0x37,0x1f,0x72,0xf0, - 0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x05, - 0x01}}, /* 0x2 */ - {{0x4f,0x3f,0x3f,0x93,0x45,0x0d,0x24,0xf5, - 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x01, - 0x01}}, /* 0x3 */ - {{0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, - 0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x05, - 0x00}}, /* 0x4 */ - {{0x5f,0x4f,0x4f,0x83,0x55,0x81,0x0b,0x3e, - 0xe9,0x8b,0xdf,0xe8,0x0c,0x00,0x00,0x05, - 0x00}}, /* 0x5 */ - {{0x63,0x4f,0x4f,0x87,0x56,0x9b,0x06,0x3e, - 0xe8,0x8a,0xdf,0xe7,0x07,0x00,0x00,0x01, - 0x00}}, /* 0x6 */ - {{0x64,0x4f,0x4f,0x88,0x55,0x9d,0xf2,0x1f, - 0xe0,0x83,0xdf,0xdf,0xf3,0x10,0x00,0x01, - 0x00}}, /* 0x7 */ - {{0x63,0x4f,0x4f,0x87,0x5a,0x81,0xfb,0x1f, - 0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05, - 0x00}}, /* 0x8 */ - {{0x65,0x4f,0x4f,0x89,0x58,0x80,0xfb,0x1f, - 0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05, - 0x61}}, /* 0x9 */ - {{0x65,0x4f,0x4f,0x89,0x58,0x80,0x01,0x3e, - 0xe0,0x83,0xdf,0xdf,0x02,0x00,0x00,0x05, - 0x61}}, /* 0xa */ - {{0x67,0x4f,0x4f,0x8b,0x58,0x81,0x0d,0x3e, - 0xe0,0x83,0xdf,0xdf,0x0e,0x00,0x00,0x05, - 0x61}}, /* 0xb */ - {{0x65,0x4f,0x4f,0x89,0x57,0x9f,0xfb,0x1f, - 0xe6,0x8a,0xdf,0xdf,0xfc,0x10,0x00,0x01, - 0x00}}, /* 0xc */ - {{0x7b,0x63,0x63,0x9f,0x6a,0x93,0x6f,0xf0, - 0x58,0x8a,0x57,0x57,0x70,0x20,0x00,0x05, - 0x01}}, /* 0xd */ - {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xf0, - 0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x06, - 0x01}}, /* 0xe */ - {{0x7d,0x63,0x63,0x81,0x6e,0x1d,0x98,0xf0, - 0x7c,0x82,0x57,0x57,0x99,0x00,0x00,0x06, - 0x01}}, /* 0xf */ - {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xf0, - 0x58,0x8b,0x57,0x57,0x70,0x20,0x00,0x06, - 0x01}}, /* 0x10 */ - {{0x7e,0x63,0x63,0x82,0x6b,0x13,0x75,0xf0, - 0x58,0x8b,0x57,0x57,0x76,0x20,0x00,0x06, - 0x01}}, /* 0x11 */ - {{0x81,0x63,0x63,0x85,0x6d,0x18,0x7a,0xf0, - 0x58,0x8b,0x57,0x57,0x7b,0x20,0x00,0x06, - 0x61}}, /* 0x12 */ - {{0x83,0x63,0x63,0x87,0x6e,0x19,0x81,0xf0, - 0x58,0x8b,0x57,0x57,0x82,0x20,0x00,0x06, - 0x61}}, /* 0x13 */ - {{0x85,0x63,0x63,0x89,0x6f,0x1a,0x91,0xf0, - 0x58,0x8b,0x57,0x57,0x92,0x20,0x00,0x06, - 0x61}}, /* 0x14 */ - {{0x99,0x7f,0x7f,0x9d,0x84,0x1a,0x96,0x1f, - 0x7f,0x83,0x7f,0x7f,0x97,0x10,0x00,0x02, - 0x00}}, /* 0x15 */ - {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5, - 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02, - 0x01}}, /* 0x16 */ - {{0xa1,0x7f,0x7f,0x85,0x86,0x97,0x24,0xf5, - 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02, - 0x01}}, /* 0x17 */ - {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf5, - 0x00,0x83,0xff,0xff,0x1f,0x10,0x00,0x02, - 0x01}}, /* 0x18 */ - {{0xa7,0x7f,0x7f,0x8b,0x89,0x95,0x26,0xf5, - 0x00,0x83,0xff,0xff,0x27,0x10,0x00,0x02, - 0x01}}, /* 0x19 */ - {{0xa9,0x7f,0x7f,0x8d,0x8c,0x9a,0x2c,0xf5, - 0x00,0x83,0xff,0xff,0x2d,0x14,0x00,0x02, - 0x62}}, /* 0x1a */ - {{0xab,0x7f,0x7f,0x8f,0x8d,0x9b,0x35,0xf5, - 0x00,0x83,0xff,0xff,0x36,0x14,0x00,0x02, - 0x62}}, /* 0x1b */ - {{0xcf,0x9f,0x9f,0x93,0xb2,0x01,0x14,0xba, - 0x00,0x83,0xff,0xff,0x15,0x00,0x00,0x03, - 0x00}}, /* 0x1c */ - {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0x5a, - 0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07, - 0x01}}, /* 0x1d */ - {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0x5a, - 0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07, - 0x01}}, /* 0x1e */ - {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0x5a, - 0x00,0x83,0xff,0xff,0x2f,0x09,0x00,0x07, - 0x01}}, /* 0x1f */ - {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, - 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, - 0x00}}, /* 0x20 */ - {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, - 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, - 0x00}}, /* 0x21 */ - {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, - 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, - 0x00}}, /* 0x22 */ - {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, - 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, - 0x00}}, /* 0x23 */ - {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, - 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, - 0x00}}, /* 0x24 */ - {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, - 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, - 0x00}}, /* 0x25 */ - {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, - 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, - 0x00}}, /* 0x26 */ - {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f, - 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01, - 0x00}}, /* 0x27 */ - {{0x43,0xef,0xef,0x87,0x06,0x00,0xd4,0x1f, - 0xa0,0x83,0x9f,0x9f,0xd5,0x1f,0x41,0x05, - 0x63}}, /* 0x28 */ - {{0x45,0xef,0xef,0x89,0x07,0x01,0xd9,0x1f, - 0xa0,0x83,0x9f,0x9f,0xda,0x1f,0x41,0x05, - 0x63}}, /* 0x29 */ - {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f, - 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01, - 0x00}}, /* 0x2a */ - {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f, - 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01, - 0x00}}, /* 0x2b */ - {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f, - 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01, - 0x00}}, /* 0x2c */ - {{0x59,0xff,0xff,0x9d,0x17,0x13,0x33,0xba, - 0x00,0x83,0xff,0xff,0x34,0x0f,0x41,0x05, - 0x44}}, /* 0x2d */ - {{0x5b,0xff,0xff,0x9f,0x18,0x14,0x38,0xba, - 0x00,0x83,0xff,0xff,0x39,0x0f,0x41,0x05, - 0x44}}, /* 0x2e */ - {{0x5b,0xff,0xff,0x9f,0x18,0x14,0x3d,0xba, - 0x00,0x83,0xff,0xff,0x3e,0x0f,0x41,0x05, - 0x44}}, /* 0x2f */ - {{0x5d,0xff,0xff,0x81,0x19,0x95,0x41,0xba, - 0x00,0x84,0xff,0xff,0x42,0x0f,0x41,0x05, - 0x44}}, /* 0x30 */ - {{0x55,0xff,0xff,0x99,0x0d,0x0c,0x3e,0xba, - 0x00,0x84,0xff,0xff,0x3f,0x0f,0x41,0x05, - 0x00}}, /* 0x31 */ - {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xba, - 0x27,0x8b,0xdf,0xdf,0x73,0x00,0x00,0x06, - 0x01}}, /* 0x32 */ - {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xba, - 0x26,0x89,0xdf,0xdf,0x6f,0x00,0x00,0x06, - 0x01}}, /* 0x33 */ - {{0x7f,0x63,0x63,0x82,0x6b,0x13,0x75,0xba, - 0x29,0x8c,0xdf,0xdf,0x75,0x00,0x00,0x06, - 0x01}}, /* 0x34 */ - {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf1, - 0xaf,0x85,0x3f,0x3f,0x25,0x30,0x00,0x02, - 0x01}}, /* 0x35 */ - {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf1, - 0xad,0x81,0x3f,0x3f,0x1f,0x30,0x00,0x02, - 0x01}}, /* 0x36 */ - {{0xa7,0x7f,0x7f,0x88,0x89,0x95,0x26,0xf1, - 0xb1,0x85,0x3f,0x3f,0x27,0x30,0x00,0x02, - 0x01}}, /* 0x37 */ - {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0xc4, - 0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07, - 0x01}}, /* 0x38 */ - {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0xd4, - 0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07, - 0x01}}, /* 0x39 */ - {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0xd4, - 0x7d,0x81,0xcf,0xcf,0x2f,0x21,0x00,0x07, - 0x01}}, /* 0x3a */ - {{0xdc,0x9f,0x9f,0x80,0xaf,0x9d,0xe6,0xff, - 0xc0,0x83,0xbf,0xbf,0xe7,0x10,0x00,0x07, - 0x01}}, /* 0x3b */ - {{0x6b,0x59,0x59,0x8f,0x5e,0x8c,0x0b,0x3e, - 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x05, - 0x00}}, /* 0x3c */ - {{0x6d,0x59,0x59,0x91,0x60,0x89,0x53,0xf0, - 0x41,0x84,0x3f,0x3f,0x54,0x00,0x00,0x05, - 0x41}}, /* 0x3d */ - {{0x86,0x6a,0x6a,0x8a,0x74,0x06,0x8c,0x15, - 0x4f,0x83,0xef,0xef,0x8d,0x30,0x00,0x02, - 0x00}}, /* 0x3e */ - {{0x81,0x6a,0x6a,0x85,0x70,0x00,0x0f,0x3e, - 0xeb,0x8e,0xdf,0xdf,0x10,0x00,0x00,0x02, - 0x00}}, /* 0x3f */ - {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x1e,0xf1, - 0xae,0x85,0x57,0x57,0x1f,0x30,0x00,0x02, - 0x01}}, /* 0x40 */ - {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5, - 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02, - 0x01}}, /* 0x41 */ - {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x20,0xf5, - 0x03,0x88,0xff,0xff,0x21,0x10,0x00,0x07, - 0x01}}, /* 0x42 */ - {{0xe6,0xae,0xae,0x8a,0xbd,0x90,0x3d,0x10, - 0x1a,0x8d,0x19,0x19,0x3e,0x2f,0x00,0x03, - 0x00}}, /* 0x43 */ - {{0xc3,0x8f,0x8f,0x87,0x9b,0x0b,0x82,0xef, - 0x60,0x83,0x5f,0x5f,0x83,0x10,0x00,0x07, - 0x01}}, /* 0x44 */ - {{0x86,0x69,0x69,0x8A,0x74,0x06,0x8C,0x15, - 0x4F,0x83,0xEF,0xEF,0x8D,0x30,0x00,0x02, - 0x00}}, /* 0x45 */ - {{0x83,0x69,0x69,0x87,0x6f,0x1d,0x03,0x3E, - 0xE5,0x8d,0xDF,0xe4,0x04,0x00,0x00,0x06, - 0x00}}, /* 0x46 */ - {{0x86,0x6A,0x6A,0x8A,0x74,0x06,0x8C,0x15, - 0x4F,0x83,0xEF,0xEF,0x8D,0x30,0x00,0x02, - 0x00}}, /* 0x47 */ - {{0x81,0x6A,0x6A,0x85,0x70,0x00,0x0F,0x3E, - 0xEB,0x8E,0xDF,0xDF,0x10,0x00,0x00,0x02, - 0x00}}, /* 0x48 */ - {{0xdd,0xa9,0xa9,0x81,0xb4,0x97,0x26,0xfd, - 0x01,0x8d,0xff,0x00,0x27,0x10,0x00,0x03, - 0x01}}, /* 0x49 */ - {{0xd9,0x8f,0x8f,0x9d,0xba,0x0a,0x8a,0xff, - 0x60,0x8b,0x5f,0x5f,0x8b,0x10,0x00,0x03, - 0x01}}, /* 0x4a */ - {{0xea,0xae,0xae,0x8e,0xba,0x82,0x40,0x10, - 0x1b,0x87,0x19,0x1a,0x41,0x0f,0x00,0x03, - 0x00}}, /* 0x4b */ - {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0xf1,0xff, - 0xc0,0x83,0xbf,0xbf,0xf2,0x10,0x00,0x07, - 0x01}}, /* 0x4c */ - {{0x75,0x5f,0x5f,0x99,0x66,0x90,0x53,0xf0, - 0x41,0x84,0x3f,0x3f,0x54,0x00,0x00,0x05, - 0x41}}, - {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e, - 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00, - 0x00}}, /* 0x4e */ - {{0xcd,0x9f,0x9f,0x91,0xab,0x1c,0x3a,0xff, - 0x20,0x83,0x1f,0x1f,0x3b,0x10,0x00,0x07, - 0x21}}, /* 0x4f */ - {{0x15,0xd1,0xd1,0x99,0xe2,0x19,0x3d,0x10, - 0x1a,0x8d,0x19,0x19,0x3e,0x2f,0x01,0x0c, - 0x20}}, /* 0x50 */ - {{0x0e,0xef,0xef,0x92,0xfe,0x03,0x30,0xf0, - 0x1e,0x83,0x1b,0x1c,0x31,0x00,0x01,0x00, - 0x61}}, /* 0x51 */ - {{0x85,0x77,0x77,0x89,0x7d,0x01,0x31,0xf0, - 0x1e,0x84,0x1b,0x1c,0x32,0x00,0x00,0x02, - 0x41}}, /* 0x52 */ - {{0x87,0x77,0x77,0x8b,0x81,0x0b,0x68,0xf0, - 0x5a,0x80,0x57,0x57,0x69,0x00,0x00,0x02, - 0x01}}, /* 0x53 */ - {{0xcd,0x8f,0x8f,0x91,0x9b,0x1b,0x7a,0xff, - 0x64,0x8c,0x5f,0x62,0x7b,0x10,0x00,0x07, - 0x41}} /* 0x54 */ +static const struct SiS_CRT1Table SiSUSB_CRT1Table[] = { + {{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0xbf, 0x1f, + 0x9c, 0x8e, 0x8f, 0x96, 0xb9, 0x30, 0x00, 0x00, + 0x00}}, /* 0x0 */ + {{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0x0b, 0x3e, + 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x00, + 0x00}}, /* 0x1 */ + {{0x3d, 0x31, 0x31, 0x81, 0x37, 0x1f, 0x72, 0xf0, + 0x58, 0x8c, 0x57, 0x57, 0x73, 0x20, 0x00, 0x05, + 0x01}}, /* 0x2 */ + {{0x4f, 0x3f, 0x3f, 0x93, 0x45, 0x0d, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x01, + 0x01}}, /* 0x3 */ + {{0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x9c, 0x8e, 0x8f, 0x96, 0xb9, 0x30, 0x00, 0x05, + 0x00}}, /* 0x4 */ + {{0x5f, 0x4f, 0x4f, 0x83, 0x55, 0x81, 0x0b, 0x3e, + 0xe9, 0x8b, 0xdf, 0xe8, 0x0c, 0x00, 0x00, 0x05, + 0x00}}, /* 0x5 */ + {{0x63, 0x4f, 0x4f, 0x87, 0x56, 0x9b, 0x06, 0x3e, + 0xe8, 0x8a, 0xdf, 0xe7, 0x07, 0x00, 0x00, 0x01, + 0x00}}, /* 0x6 */ + {{0x64, 0x4f, 0x4f, 0x88, 0x55, 0x9d, 0xf2, 0x1f, + 0xe0, 0x83, 0xdf, 0xdf, 0xf3, 0x10, 0x00, 0x01, + 0x00}}, /* 0x7 */ + {{0x63, 0x4f, 0x4f, 0x87, 0x5a, 0x81, 0xfb, 0x1f, + 0xe0, 0x83, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x05, + 0x00}}, /* 0x8 */ + {{0x65, 0x4f, 0x4f, 0x89, 0x58, 0x80, 0xfb, 0x1f, + 0xe0, 0x83, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x05, + 0x61}}, /* 0x9 */ + {{0x65, 0x4f, 0x4f, 0x89, 0x58, 0x80, 0x01, 0x3e, + 0xe0, 0x83, 0xdf, 0xdf, 0x02, 0x00, 0x00, 0x05, + 0x61}}, /* 0xa */ + {{0x67, 0x4f, 0x4f, 0x8b, 0x58, 0x81, 0x0d, 0x3e, + 0xe0, 0x83, 0xdf, 0xdf, 0x0e, 0x00, 0x00, 0x05, + 0x61}}, /* 0xb */ + {{0x65, 0x4f, 0x4f, 0x89, 0x57, 0x9f, 0xfb, 0x1f, + 0xe6, 0x8a, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x01, + 0x00}}, /* 0xc */ + {{0x7b, 0x63, 0x63, 0x9f, 0x6a, 0x93, 0x6f, 0xf0, + 0x58, 0x8a, 0x57, 0x57, 0x70, 0x20, 0x00, 0x05, + 0x01}}, /* 0xd */ + {{0x7f, 0x63, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xf0, + 0x58, 0x8c, 0x57, 0x57, 0x73, 0x20, 0x00, 0x06, + 0x01}}, /* 0xe */ + {{0x7d, 0x63, 0x63, 0x81, 0x6e, 0x1d, 0x98, 0xf0, + 0x7c, 0x82, 0x57, 0x57, 0x99, 0x00, 0x00, 0x06, + 0x01}}, /* 0xf */ + {{0x7f, 0x63, 0x63, 0x83, 0x69, 0x13, 0x6f, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x70, 0x20, 0x00, 0x06, + 0x01}}, /* 0x10 */ + {{0x7e, 0x63, 0x63, 0x82, 0x6b, 0x13, 0x75, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x76, 0x20, 0x00, 0x06, + 0x01}}, /* 0x11 */ + {{0x81, 0x63, 0x63, 0x85, 0x6d, 0x18, 0x7a, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x7b, 0x20, 0x00, 0x06, + 0x61}}, /* 0x12 */ + {{0x83, 0x63, 0x63, 0x87, 0x6e, 0x19, 0x81, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x82, 0x20, 0x00, 0x06, + 0x61}}, /* 0x13 */ + {{0x85, 0x63, 0x63, 0x89, 0x6f, 0x1a, 0x91, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x92, 0x20, 0x00, 0x06, + 0x61}}, /* 0x14 */ + {{0x99, 0x7f, 0x7f, 0x9d, 0x84, 0x1a, 0x96, 0x1f, + 0x7f, 0x83, 0x7f, 0x7f, 0x97, 0x10, 0x00, 0x02, + 0x00}}, /* 0x15 */ + {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02, + 0x01}}, /* 0x16 */ + {{0xa1, 0x7f, 0x7f, 0x85, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02, + 0x01}}, /* 0x17 */ + {{0x9f, 0x7f, 0x7f, 0x83, 0x85, 0x91, 0x1e, 0xf5, + 0x00, 0x83, 0xff, 0xff, 0x1f, 0x10, 0x00, 0x02, + 0x01}}, /* 0x18 */ + {{0xa7, 0x7f, 0x7f, 0x8b, 0x89, 0x95, 0x26, 0xf5, + 0x00, 0x83, 0xff, 0xff, 0x27, 0x10, 0x00, 0x02, + 0x01}}, /* 0x19 */ + {{0xa9, 0x7f, 0x7f, 0x8d, 0x8c, 0x9a, 0x2c, 0xf5, + 0x00, 0x83, 0xff, 0xff, 0x2d, 0x14, 0x00, 0x02, + 0x62}}, /* 0x1a */ + {{0xab, 0x7f, 0x7f, 0x8f, 0x8d, 0x9b, 0x35, 0xf5, + 0x00, 0x83, 0xff, 0xff, 0x36, 0x14, 0x00, 0x02, + 0x62}}, /* 0x1b */ + {{0xcf, 0x9f, 0x9f, 0x93, 0xb2, 0x01, 0x14, 0xba, + 0x00, 0x83, 0xff, 0xff, 0x15, 0x00, 0x00, 0x03, + 0x00}}, /* 0x1c */ + {{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x28, 0x5a, + 0x00, 0x83, 0xff, 0xff, 0x29, 0x09, 0x00, 0x07, + 0x01}}, /* 0x1d */ + {{0xce, 0x9f, 0x9f, 0x92, 0xa5, 0x17, 0x28, 0x5a, + 0x00, 0x83, 0xff, 0xff, 0x29, 0x09, 0x00, 0x07, + 0x01}}, /* 0x1e */ + {{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0x2e, 0x5a, + 0x00, 0x83, 0xff, 0xff, 0x2f, 0x09, 0x00, 0x07, + 0x01}}, /* 0x1f */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x20 */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x21 */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x22 */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x23 */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x24 */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x25 */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x26 */ + {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01, + 0x00}}, /* 0x27 */ + {{0x43, 0xef, 0xef, 0x87, 0x06, 0x00, 0xd4, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xd5, 0x1f, 0x41, 0x05, + 0x63}}, /* 0x28 */ + {{0x45, 0xef, 0xef, 0x89, 0x07, 0x01, 0xd9, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xda, 0x1f, 0x41, 0x05, + 0x63}}, /* 0x29 */ + {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01, + 0x00}}, /* 0x2a */ + {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01, + 0x00}}, /* 0x2b */ + {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01, + 0x00}}, /* 0x2c */ + {{0x59, 0xff, 0xff, 0x9d, 0x17, 0x13, 0x33, 0xba, + 0x00, 0x83, 0xff, 0xff, 0x34, 0x0f, 0x41, 0x05, + 0x44}}, /* 0x2d */ + {{0x5b, 0xff, 0xff, 0x9f, 0x18, 0x14, 0x38, 0xba, + 0x00, 0x83, 0xff, 0xff, 0x39, 0x0f, 0x41, 0x05, + 0x44}}, /* 0x2e */ + {{0x5b, 0xff, 0xff, 0x9f, 0x18, 0x14, 0x3d, 0xba, + 0x00, 0x83, 0xff, 0xff, 0x3e, 0x0f, 0x41, 0x05, + 0x44}}, /* 0x2f */ + {{0x5d, 0xff, 0xff, 0x81, 0x19, 0x95, 0x41, 0xba, + 0x00, 0x84, 0xff, 0xff, 0x42, 0x0f, 0x41, 0x05, + 0x44}}, /* 0x30 */ + {{0x55, 0xff, 0xff, 0x99, 0x0d, 0x0c, 0x3e, 0xba, + 0x00, 0x84, 0xff, 0xff, 0x3f, 0x0f, 0x41, 0x05, + 0x00}}, /* 0x31 */ + {{0x7f, 0x63, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xba, + 0x27, 0x8b, 0xdf, 0xdf, 0x73, 0x00, 0x00, 0x06, + 0x01}}, /* 0x32 */ + {{0x7f, 0x63, 0x63, 0x83, 0x69, 0x13, 0x6f, 0xba, + 0x26, 0x89, 0xdf, 0xdf, 0x6f, 0x00, 0x00, 0x06, + 0x01}}, /* 0x33 */ + {{0x7f, 0x63, 0x63, 0x82, 0x6b, 0x13, 0x75, 0xba, + 0x29, 0x8c, 0xdf, 0xdf, 0x75, 0x00, 0x00, 0x06, + 0x01}}, /* 0x34 */ + {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf1, + 0xaf, 0x85, 0x3f, 0x3f, 0x25, 0x30, 0x00, 0x02, + 0x01}}, /* 0x35 */ + {{0x9f, 0x7f, 0x7f, 0x83, 0x85, 0x91, 0x1e, 0xf1, + 0xad, 0x81, 0x3f, 0x3f, 0x1f, 0x30, 0x00, 0x02, + 0x01}}, /* 0x36 */ + {{0xa7, 0x7f, 0x7f, 0x88, 0x89, 0x95, 0x26, 0xf1, + 0xb1, 0x85, 0x3f, 0x3f, 0x27, 0x30, 0x00, 0x02, + 0x01}}, /* 0x37 */ + {{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x28, 0xc4, + 0x7a, 0x8e, 0xcf, 0xcf, 0x29, 0x21, 0x00, 0x07, + 0x01}}, /* 0x38 */ + {{0xce, 0x9f, 0x9f, 0x92, 0xa5, 0x17, 0x28, 0xd4, + 0x7a, 0x8e, 0xcf, 0xcf, 0x29, 0x21, 0x00, 0x07, + 0x01}}, /* 0x39 */ + {{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0x2e, 0xd4, + 0x7d, 0x81, 0xcf, 0xcf, 0x2f, 0x21, 0x00, 0x07, + 0x01}}, /* 0x3a */ + {{0xdc, 0x9f, 0x9f, 0x80, 0xaf, 0x9d, 0xe6, 0xff, + 0xc0, 0x83, 0xbf, 0xbf, 0xe7, 0x10, 0x00, 0x07, + 0x01}}, /* 0x3b */ + {{0x6b, 0x59, 0x59, 0x8f, 0x5e, 0x8c, 0x0b, 0x3e, + 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x05, + 0x00}}, /* 0x3c */ + {{0x6d, 0x59, 0x59, 0x91, 0x60, 0x89, 0x53, 0xf0, + 0x41, 0x84, 0x3f, 0x3f, 0x54, 0x00, 0x00, 0x05, + 0x41}}, /* 0x3d */ + {{0x86, 0x6a, 0x6a, 0x8a, 0x74, 0x06, 0x8c, 0x15, + 0x4f, 0x83, 0xef, 0xef, 0x8d, 0x30, 0x00, 0x02, + 0x00}}, /* 0x3e */ + {{0x81, 0x6a, 0x6a, 0x85, 0x70, 0x00, 0x0f, 0x3e, + 0xeb, 0x8e, 0xdf, 0xdf, 0x10, 0x00, 0x00, 0x02, + 0x00}}, /* 0x3f */ + {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x1e, 0xf1, + 0xae, 0x85, 0x57, 0x57, 0x1f, 0x30, 0x00, 0x02, + 0x01}}, /* 0x40 */ + {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02, + 0x01}}, /* 0x41 */ + {{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x20, 0xf5, + 0x03, 0x88, 0xff, 0xff, 0x21, 0x10, 0x00, 0x07, + 0x01}}, /* 0x42 */ + {{0xe6, 0xae, 0xae, 0x8a, 0xbd, 0x90, 0x3d, 0x10, + 0x1a, 0x8d, 0x19, 0x19, 0x3e, 0x2f, 0x00, 0x03, + 0x00}}, /* 0x43 */ + {{0xc3, 0x8f, 0x8f, 0x87, 0x9b, 0x0b, 0x82, 0xef, + 0x60, 0x83, 0x5f, 0x5f, 0x83, 0x10, 0x00, 0x07, + 0x01}}, /* 0x44 */ + {{0x86, 0x69, 0x69, 0x8A, 0x74, 0x06, 0x8C, 0x15, + 0x4F, 0x83, 0xEF, 0xEF, 0x8D, 0x30, 0x00, 0x02, + 0x00}}, /* 0x45 */ + {{0x83, 0x69, 0x69, 0x87, 0x6f, 0x1d, 0x03, 0x3E, + 0xE5, 0x8d, 0xDF, 0xe4, 0x04, 0x00, 0x00, 0x06, + 0x00}}, /* 0x46 */ + {{0x86, 0x6A, 0x6A, 0x8A, 0x74, 0x06, 0x8C, 0x15, + 0x4F, 0x83, 0xEF, 0xEF, 0x8D, 0x30, 0x00, 0x02, + 0x00}}, /* 0x47 */ + {{0x81, 0x6A, 0x6A, 0x85, 0x70, 0x00, 0x0F, 0x3E, + 0xEB, 0x8E, 0xDF, 0xDF, 0x10, 0x00, 0x00, 0x02, + 0x00}}, /* 0x48 */ + {{0xdd, 0xa9, 0xa9, 0x81, 0xb4, 0x97, 0x26, 0xfd, + 0x01, 0x8d, 0xff, 0x00, 0x27, 0x10, 0x00, 0x03, + 0x01}}, /* 0x49 */ + {{0xd9, 0x8f, 0x8f, 0x9d, 0xba, 0x0a, 0x8a, 0xff, + 0x60, 0x8b, 0x5f, 0x5f, 0x8b, 0x10, 0x00, 0x03, + 0x01}}, /* 0x4a */ + {{0xea, 0xae, 0xae, 0x8e, 0xba, 0x82, 0x40, 0x10, + 0x1b, 0x87, 0x19, 0x1a, 0x41, 0x0f, 0x00, 0x03, + 0x00}}, /* 0x4b */ + {{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0xf1, 0xff, + 0xc0, 0x83, 0xbf, 0xbf, 0xf2, 0x10, 0x00, 0x07, + 0x01}}, /* 0x4c */ + {{0x75, 0x5f, 0x5f, 0x99, 0x66, 0x90, 0x53, 0xf0, + 0x41, 0x84, 0x3f, 0x3f, 0x54, 0x00, 0x00, 0x05, + 0x41}}, + {{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0x0b, 0x3e, + 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x00, + 0x00}}, /* 0x4e */ + {{0xcd, 0x9f, 0x9f, 0x91, 0xab, 0x1c, 0x3a, 0xff, + 0x20, 0x83, 0x1f, 0x1f, 0x3b, 0x10, 0x00, 0x07, + 0x21}}, /* 0x4f */ + {{0x15, 0xd1, 0xd1, 0x99, 0xe2, 0x19, 0x3d, 0x10, + 0x1a, 0x8d, 0x19, 0x19, 0x3e, 0x2f, 0x01, 0x0c, + 0x20}}, /* 0x50 */ + {{0x0e, 0xef, 0xef, 0x92, 0xfe, 0x03, 0x30, 0xf0, + 0x1e, 0x83, 0x1b, 0x1c, 0x31, 0x00, 0x01, 0x00, + 0x61}}, /* 0x51 */ + {{0x85, 0x77, 0x77, 0x89, 0x7d, 0x01, 0x31, 0xf0, + 0x1e, 0x84, 0x1b, 0x1c, 0x32, 0x00, 0x00, 0x02, + 0x41}}, /* 0x52 */ + {{0x87, 0x77, 0x77, 0x8b, 0x81, 0x0b, 0x68, 0xf0, + 0x5a, 0x80, 0x57, 0x57, 0x69, 0x00, 0x00, 0x02, + 0x01}}, /* 0x53 */ + {{0xcd, 0x8f, 0x8f, 0x91, 0x9b, 0x1b, 0x7a, 0xff, + 0x64, 0x8c, 0x5f, 0x62, 0x7b, 0x10, 0x00, 0x07, + 0x41}} /* 0x54 */ }; -static const struct SiS_VCLKData SiSUSB_VCLKData[] = -{ - { 0x1b,0xe1, 25}, /* 0x00 */ - { 0x4e,0xe4, 28}, /* 0x01 */ - { 0x57,0xe4, 31}, /* 0x02 */ - { 0xc3,0xc8, 36}, /* 0x03 */ - { 0x42,0xe2, 40}, /* 0x04 */ - { 0xfe,0xcd, 43}, /* 0x05 */ - { 0x5d,0xc4, 44}, /* 0x06 */ - { 0x52,0xe2, 49}, /* 0x07 */ - { 0x53,0xe2, 50}, /* 0x08 */ - { 0x74,0x67, 52}, /* 0x09 */ - { 0x6d,0x66, 56}, /* 0x0a */ - { 0x5a,0x64, 65}, /* 0x0b */ - { 0x46,0x44, 67}, /* 0x0c */ - { 0xb1,0x46, 68}, /* 0x0d */ - { 0xd3,0x4a, 72}, /* 0x0e */ - { 0x29,0x61, 75}, /* 0x0f */ - { 0x6e,0x46, 76}, /* 0x10 */ - { 0x2b,0x61, 78}, /* 0x11 */ - { 0x31,0x42, 79}, /* 0x12 */ - { 0xab,0x44, 83}, /* 0x13 */ - { 0x46,0x25, 84}, /* 0x14 */ - { 0x78,0x29, 86}, /* 0x15 */ - { 0x62,0x44, 94}, /* 0x16 */ - { 0x2b,0x41,104}, /* 0x17 */ - { 0x3a,0x23,105}, /* 0x18 */ - { 0x70,0x44,108}, /* 0x19 */ - { 0x3c,0x23,109}, /* 0x1a */ - { 0x5e,0x43,113}, /* 0x1b */ - { 0xbc,0x44,116}, /* 0x1c */ - { 0xe0,0x46,132}, /* 0x1d */ - { 0x54,0x42,135}, /* 0x1e */ - { 0xea,0x2a,139}, /* 0x1f */ - { 0x41,0x22,157}, /* 0x20 */ - { 0x70,0x24,162}, /* 0x21 */ - { 0x30,0x21,175}, /* 0x22 */ - { 0x4e,0x22,189}, /* 0x23 */ - { 0xde,0x26,194}, /* 0x24 */ - { 0x62,0x06,202}, /* 0x25 */ - { 0x3f,0x03,229}, /* 0x26 */ - { 0xb8,0x06,234}, /* 0x27 */ - { 0x34,0x02,253}, /* 0x28 */ - { 0x58,0x04,255}, /* 0x29 */ - { 0x24,0x01,265}, /* 0x2a */ - { 0x9b,0x02,267}, /* 0x2b */ - { 0x70,0x05,270}, /* 0x2c */ - { 0x25,0x01,272}, /* 0x2d */ - { 0x9c,0x02,277}, /* 0x2e */ - { 0x27,0x01,286}, /* 0x2f */ - { 0x3c,0x02,291}, /* 0x30 */ - { 0xef,0x0a,292}, /* 0x31 */ - { 0xf6,0x0a,310}, /* 0x32 */ - { 0x95,0x01,315}, /* 0x33 */ - { 0xf0,0x09,324}, /* 0x34 */ - { 0xfe,0x0a,331}, /* 0x35 */ - { 0xf3,0x09,332}, /* 0x36 */ - { 0xea,0x08,340}, /* 0x37 */ - { 0xe8,0x07,376}, /* 0x38 */ - { 0xde,0x06,389}, /* 0x39 */ - { 0x52,0x2a, 54}, /* 0x3a 301 TV */ - { 0x52,0x6a, 27}, /* 0x3b 301 TV */ - { 0x62,0x24, 70}, /* 0x3c 301 TV */ - { 0x62,0x64, 70}, /* 0x3d 301 TV */ - { 0xa8,0x4c, 30}, /* 0x3e 301 TV */ - { 0x20,0x26, 33}, /* 0x3f 301 TV */ - { 0x31,0xc2, 39}, /* 0x40 */ - { 0x60,0x36, 30}, /* 0x41 Chrontel */ - { 0x40,0x4a, 28}, /* 0x42 Chrontel */ - { 0x9f,0x46, 44}, /* 0x43 Chrontel */ - { 0x97,0x2c, 26}, /* 0x44 */ - { 0x44,0xe4, 25}, /* 0x45 Chrontel */ - { 0x7e,0x32, 47}, /* 0x46 Chrontel */ - { 0x8a,0x24, 31}, /* 0x47 Chrontel */ - { 0x97,0x2c, 26}, /* 0x48 Chrontel */ - { 0xce,0x3c, 39}, /* 0x49 */ - { 0x52,0x4a, 36}, /* 0x4a Chrontel */ - { 0x34,0x61, 95}, /* 0x4b */ - { 0x78,0x27,108}, /* 0x4c - was 102 */ - { 0x66,0x43,123}, /* 0x4d Modes 0x26-0x28 (1400x1050) */ - { 0x41,0x4e, 21}, /* 0x4e */ - { 0xa1,0x4a, 29}, /* 0x4f Chrontel */ - { 0x19,0x42, 42}, /* 0x50 */ - { 0x54,0x46, 58}, /* 0x51 Chrontel */ - { 0x25,0x42, 61}, /* 0x52 */ - { 0x44,0x44, 66}, /* 0x53 Chrontel */ - { 0x3a,0x62, 70}, /* 0x54 Chrontel */ - { 0x62,0xc6, 34}, /* 0x55 848x480-60 */ - { 0x6a,0xc6, 37}, /* 0x56 848x480-75 - TEMP */ - { 0xbf,0xc8, 35}, /* 0x57 856x480-38i,60 */ - { 0x30,0x23, 88}, /* 0x58 1360x768-62 (is 60Hz!) */ - { 0x52,0x07,149}, /* 0x59 1280x960-85 */ - { 0x56,0x07,156}, /* 0x5a 1400x1050-75 */ - { 0x70,0x29, 81}, /* 0x5b 1280x768 LCD */ - { 0x45,0x25, 83}, /* 0x5c 1280x800 */ - { 0x70,0x0a,147}, /* 0x5d 1680x1050 */ - { 0x70,0x24,162}, /* 0x5e 1600x1200 */ - { 0x5a,0x64, 65}, /* 0x5f 1280x720 - temp */ - { 0x63,0x46, 68}, /* 0x60 1280x768_2 */ - { 0x31,0x42, 79}, /* 0x61 1280x768_3 - temp */ - { 0, 0, 0}, /* 0x62 - custom (will be filled out at run-time) */ - { 0x5a,0x64, 65}, /* 0x63 1280x720 (LCD LVDS) */ - { 0x70,0x28, 90}, /* 0x64 1152x864@60 */ - { 0x41,0xc4, 32}, /* 0x65 848x480@60 */ - { 0x5c,0xc6, 32}, /* 0x66 856x480@60 */ - { 0x76,0xe7, 27}, /* 0x67 720x480@60 */ - { 0x5f,0xc6, 33}, /* 0x68 720/768x576@60 */ - { 0x52,0x27, 75}, /* 0x69 1920x1080i 60Hz interlaced */ - { 0x7c,0x6b, 38}, /* 0x6a 960x540@60 */ - { 0xe3,0x56, 41}, /* 0x6b 960x600@60 */ - { 0x45,0x25, 83}, /* 0x6c 1280x800 */ - { 0x70,0x28, 90}, /* 0x6d 1152x864@60 */ - { 0x15,0xe1, 20}, /* 0x6e 640x400@60 (fake, not actually used) */ - { 0x5f,0xc6, 33}, /* 0x6f 720x576@60 */ - { 0x37,0x5a, 10}, /* 0x70 320x200@60 (fake, not actually used) */ - { 0x2b,0xc2, 35} /* 0x71 768@576@60 */ +static const struct SiS_VCLKData SiSUSB_VCLKData[] = { + {0x1b, 0xe1, 25}, /* 0x00 */ + {0x4e, 0xe4, 28}, /* 0x01 */ + {0x57, 0xe4, 31}, /* 0x02 */ + {0xc3, 0xc8, 36}, /* 0x03 */ + {0x42, 0xe2, 40}, /* 0x04 */ + {0xfe, 0xcd, 43}, /* 0x05 */ + {0x5d, 0xc4, 44}, /* 0x06 */ + {0x52, 0xe2, 49}, /* 0x07 */ + {0x53, 0xe2, 50}, /* 0x08 */ + {0x74, 0x67, 52}, /* 0x09 */ + {0x6d, 0x66, 56}, /* 0x0a */ + {0x5a, 0x64, 65}, /* 0x0b */ + {0x46, 0x44, 67}, /* 0x0c */ + {0xb1, 0x46, 68}, /* 0x0d */ + {0xd3, 0x4a, 72}, /* 0x0e */ + {0x29, 0x61, 75}, /* 0x0f */ + {0x6e, 0x46, 76}, /* 0x10 */ + {0x2b, 0x61, 78}, /* 0x11 */ + {0x31, 0x42, 79}, /* 0x12 */ + {0xab, 0x44, 83}, /* 0x13 */ + {0x46, 0x25, 84}, /* 0x14 */ + {0x78, 0x29, 86}, /* 0x15 */ + {0x62, 0x44, 94}, /* 0x16 */ + {0x2b, 0x41, 104}, /* 0x17 */ + {0x3a, 0x23, 105}, /* 0x18 */ + {0x70, 0x44, 108}, /* 0x19 */ + {0x3c, 0x23, 109}, /* 0x1a */ + {0x5e, 0x43, 113}, /* 0x1b */ + {0xbc, 0x44, 116}, /* 0x1c */ + {0xe0, 0x46, 132}, /* 0x1d */ + {0x54, 0x42, 135}, /* 0x1e */ + {0xea, 0x2a, 139}, /* 0x1f */ + {0x41, 0x22, 157}, /* 0x20 */ + {0x70, 0x24, 162}, /* 0x21 */ + {0x30, 0x21, 175}, /* 0x22 */ + {0x4e, 0x22, 189}, /* 0x23 */ + {0xde, 0x26, 194}, /* 0x24 */ + {0x62, 0x06, 202}, /* 0x25 */ + {0x3f, 0x03, 229}, /* 0x26 */ + {0xb8, 0x06, 234}, /* 0x27 */ + {0x34, 0x02, 253}, /* 0x28 */ + {0x58, 0x04, 255}, /* 0x29 */ + {0x24, 0x01, 265}, /* 0x2a */ + {0x9b, 0x02, 267}, /* 0x2b */ + {0x70, 0x05, 270}, /* 0x2c */ + {0x25, 0x01, 272}, /* 0x2d */ + {0x9c, 0x02, 277}, /* 0x2e */ + {0x27, 0x01, 286}, /* 0x2f */ + {0x3c, 0x02, 291}, /* 0x30 */ + {0xef, 0x0a, 292}, /* 0x31 */ + {0xf6, 0x0a, 310}, /* 0x32 */ + {0x95, 0x01, 315}, /* 0x33 */ + {0xf0, 0x09, 324}, /* 0x34 */ + {0xfe, 0x0a, 331}, /* 0x35 */ + {0xf3, 0x09, 332}, /* 0x36 */ + {0xea, 0x08, 340}, /* 0x37 */ + {0xe8, 0x07, 376}, /* 0x38 */ + {0xde, 0x06, 389}, /* 0x39 */ + {0x52, 0x2a, 54}, /* 0x3a 301 TV */ + {0x52, 0x6a, 27}, /* 0x3b 301 TV */ + {0x62, 0x24, 70}, /* 0x3c 301 TV */ + {0x62, 0x64, 70}, /* 0x3d 301 TV */ + {0xa8, 0x4c, 30}, /* 0x3e 301 TV */ + {0x20, 0x26, 33}, /* 0x3f 301 TV */ + {0x31, 0xc2, 39}, /* 0x40 */ + {0x60, 0x36, 30}, /* 0x41 Chrontel */ + {0x40, 0x4a, 28}, /* 0x42 Chrontel */ + {0x9f, 0x46, 44}, /* 0x43 Chrontel */ + {0x97, 0x2c, 26}, /* 0x44 */ + {0x44, 0xe4, 25}, /* 0x45 Chrontel */ + {0x7e, 0x32, 47}, /* 0x46 Chrontel */ + {0x8a, 0x24, 31}, /* 0x47 Chrontel */ + {0x97, 0x2c, 26}, /* 0x48 Chrontel */ + {0xce, 0x3c, 39}, /* 0x49 */ + {0x52, 0x4a, 36}, /* 0x4a Chrontel */ + {0x34, 0x61, 95}, /* 0x4b */ + {0x78, 0x27, 108}, /* 0x4c - was 102 */ + {0x66, 0x43, 123}, /* 0x4d Modes 0x26-0x28 (1400x1050) */ + {0x41, 0x4e, 21}, /* 0x4e */ + {0xa1, 0x4a, 29}, /* 0x4f Chrontel */ + {0x19, 0x42, 42}, /* 0x50 */ + {0x54, 0x46, 58}, /* 0x51 Chrontel */ + {0x25, 0x42, 61}, /* 0x52 */ + {0x44, 0x44, 66}, /* 0x53 Chrontel */ + {0x3a, 0x62, 70}, /* 0x54 Chrontel */ + {0x62, 0xc6, 34}, /* 0x55 848x480-60 */ + {0x6a, 0xc6, 37}, /* 0x56 848x480-75 - TEMP */ + {0xbf, 0xc8, 35}, /* 0x57 856x480-38i,60 */ + {0x30, 0x23, 88}, /* 0x58 1360x768-62 (is 60Hz!) */ + {0x52, 0x07, 149}, /* 0x59 1280x960-85 */ + {0x56, 0x07, 156}, /* 0x5a 1400x1050-75 */ + {0x70, 0x29, 81}, /* 0x5b 1280x768 LCD */ + {0x45, 0x25, 83}, /* 0x5c 1280x800 */ + {0x70, 0x0a, 147}, /* 0x5d 1680x1050 */ + {0x70, 0x24, 162}, /* 0x5e 1600x1200 */ + {0x5a, 0x64, 65}, /* 0x5f 1280x720 - temp */ + {0x63, 0x46, 68}, /* 0x60 1280x768_2 */ + {0x31, 0x42, 79}, /* 0x61 1280x768_3 - temp */ + {0, 0, 0}, /* 0x62 - custom (will be filled out at run-time) */ + {0x5a, 0x64, 65}, /* 0x63 1280x720 (LCD LVDS) */ + {0x70, 0x28, 90}, /* 0x64 1152x864@60 */ + {0x41, 0xc4, 32}, /* 0x65 848x480@60 */ + {0x5c, 0xc6, 32}, /* 0x66 856x480@60 */ + {0x76, 0xe7, 27}, /* 0x67 720x480@60 */ + {0x5f, 0xc6, 33}, /* 0x68 720/768x576@60 */ + {0x52, 0x27, 75}, /* 0x69 1920x1080i 60Hz interlaced */ + {0x7c, 0x6b, 38}, /* 0x6a 960x540@60 */ + {0xe3, 0x56, 41}, /* 0x6b 960x600@60 */ + {0x45, 0x25, 83}, /* 0x6c 1280x800 */ + {0x70, 0x28, 90}, /* 0x6d 1152x864@60 */ + {0x15, 0xe1, 20}, /* 0x6e 640x400@60 (fake, not actually used) */ + {0x5f, 0xc6, 33}, /* 0x6f 720x576@60 */ + {0x37, 0x5a, 10}, /* 0x70 320x200@60 (fake, not actually used) */ + {0x2b, 0xc2, 35} /* 0x71 768@576@60 */ }; -int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo); -int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo); +int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo); +int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo); -extern int sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data); -extern int sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 *data); -extern int sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, - u8 index, u8 data); -extern int sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, - u8 index, u8 *data); -extern int sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, - u8 idx, u8 myand, u8 myor); -extern int sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, - u8 index, u8 myor); -extern int sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, - u8 idx, u8 myand); +extern int sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data); +extern int sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 * data); +extern int sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, + u8 index, u8 data); +extern int sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, + u8 index, u8 * data); +extern int sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, + u8 idx, u8 myand, u8 myor); +extern int sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, + u8 index, u8 myor); +extern int sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, + u8 idx, u8 myand); void sisusb_delete(struct kref *kref); int sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data); -int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data); +int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 * data); int sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src, - u32 dest, int length, size_t *bytes_written); + u32 dest, int length, size_t * bytes_written); int sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init); int sisusbcon_do_font_op(struct sisusb_usb_data *sisusb, int set, int slot, - u8 *arg, int cmapsz, int ch512, int dorecalc, + u8 * arg, int cmapsz, int ch512, int dorecalc, struct vc_data *c, int fh, int uplock); void sisusb_set_cursor(struct sisusb_usb_data *sisusb, unsigned int location); int sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last); @@ -839,4 +839,3 @@ void sisusb_console_exit(struct sisusb_usb_data *sisusb); void sisusb_init_concode(void); #endif - -- cgit v1.2.3-70-g09d2 From ecb8b190bcf49e67a6bd955340ecc07d243b6efa Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 10 Aug 2007 16:04:56 -0400 Subject: USB: SisUSB2VGA: Lindent drivers/usb/misc/sisusbvga/sisusb_struct.h Better indentation Signed-off-by: Felipe Balbi Cc: Thomas Winischhofer Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/sisusbvga/sisusb_struct.h | 142 ++++++++++++++--------------- 1 file changed, 67 insertions(+), 75 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/misc/sisusbvga/sisusb_struct.h b/drivers/usb/misc/sisusbvga/sisusb_struct.h index 9def598192c..1c4240e802c 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_struct.h +++ b/drivers/usb/misc/sisusbvga/sisusb_struct.h @@ -52,85 +52,78 @@ #define _SISUSB_STRUCT_H_ struct SiS_St { - unsigned char St_ModeID; - unsigned short St_ModeFlag; - unsigned char St_StTableIndex; - unsigned char St_CRT2CRTC; - unsigned char St_ResInfo; - unsigned char VB_StTVFlickerIndex; - unsigned char VB_StTVEdgeIndex; - unsigned char VB_StTVYFilterIndex; - unsigned char St_PDC; + unsigned char St_ModeID; + unsigned short St_ModeFlag; + unsigned char St_StTableIndex; + unsigned char St_CRT2CRTC; + unsigned char St_ResInfo; + unsigned char VB_StTVFlickerIndex; + unsigned char VB_StTVEdgeIndex; + unsigned char VB_StTVYFilterIndex; + unsigned char St_PDC; }; -struct SiS_StandTable -{ - unsigned char CRT_COLS; - unsigned char ROWS; - unsigned char CHAR_HEIGHT; - unsigned short CRT_LEN; - unsigned char SR[4]; - unsigned char MISC; - unsigned char CRTC[0x19]; - unsigned char ATTR[0x14]; - unsigned char GRC[9]; +struct SiS_StandTable { + unsigned char CRT_COLS; + unsigned char ROWS; + unsigned char CHAR_HEIGHT; + unsigned short CRT_LEN; + unsigned char SR[4]; + unsigned char MISC; + unsigned char CRTC[0x19]; + unsigned char ATTR[0x14]; + unsigned char GRC[9]; }; struct SiS_StResInfo_S { - unsigned short HTotal; - unsigned short VTotal; + unsigned short HTotal; + unsigned short VTotal; }; -struct SiS_Ext -{ - unsigned char Ext_ModeID; - unsigned short Ext_ModeFlag; - unsigned short Ext_VESAID; - unsigned char Ext_RESINFO; - unsigned char VB_ExtTVFlickerIndex; - unsigned char VB_ExtTVEdgeIndex; - unsigned char VB_ExtTVYFilterIndex; - unsigned char VB_ExtTVYFilterIndexROM661; - unsigned char REFindex; - char ROMMODEIDX661; +struct SiS_Ext { + unsigned char Ext_ModeID; + unsigned short Ext_ModeFlag; + unsigned short Ext_VESAID; + unsigned char Ext_RESINFO; + unsigned char VB_ExtTVFlickerIndex; + unsigned char VB_ExtTVEdgeIndex; + unsigned char VB_ExtTVYFilterIndex; + unsigned char VB_ExtTVYFilterIndexROM661; + unsigned char REFindex; + char ROMMODEIDX661; }; -struct SiS_Ext2 -{ - unsigned short Ext_InfoFlag; - unsigned char Ext_CRT1CRTC; - unsigned char Ext_CRTVCLK; - unsigned char Ext_CRT2CRTC; - unsigned char Ext_CRT2CRTC_NS; - unsigned char ModeID; - unsigned short XRes; - unsigned short YRes; - unsigned char Ext_PDC; - unsigned char Ext_FakeCRT2CRTC; - unsigned char Ext_FakeCRT2Clk; +struct SiS_Ext2 { + unsigned short Ext_InfoFlag; + unsigned char Ext_CRT1CRTC; + unsigned char Ext_CRTVCLK; + unsigned char Ext_CRT2CRTC; + unsigned char Ext_CRT2CRTC_NS; + unsigned char ModeID; + unsigned short XRes; + unsigned short YRes; + unsigned char Ext_PDC; + unsigned char Ext_FakeCRT2CRTC; + unsigned char Ext_FakeCRT2Clk; }; -struct SiS_CRT1Table -{ - unsigned char CR[17]; +struct SiS_CRT1Table { + unsigned char CR[17]; }; -struct SiS_VCLKData -{ - unsigned char SR2B,SR2C; - unsigned short CLOCK; +struct SiS_VCLKData { + unsigned char SR2B, SR2C; + unsigned short CLOCK; }; -struct SiS_ModeResInfo -{ - unsigned short HTotal; - unsigned short VTotal; - unsigned char XChar; - unsigned char YChar; +struct SiS_ModeResInfo { + unsigned short HTotal; + unsigned short VTotal; + unsigned char XChar; + unsigned char YChar; }; -struct SiS_Private -{ +struct SiS_Private { void *sisusb; unsigned long IOAddress; @@ -151,19 +144,18 @@ struct SiS_Private unsigned long SiS_P3da; unsigned long SiS_Part1Port; - unsigned char SiS_MyCR63; - unsigned short SiS_CRT1Mode; - unsigned short SiS_ModeType; - unsigned short SiS_SetFlag; - - const struct SiS_StandTable *SiS_StandTable; - const struct SiS_St *SiS_SModeIDTable; - const struct SiS_Ext *SiS_EModeIDTable; - const struct SiS_Ext2 *SiS_RefIndex; - const struct SiS_CRT1Table *SiS_CRT1Table; - const struct SiS_VCLKData *SiS_VCLKData; - const struct SiS_ModeResInfo *SiS_ModeResInfo; + unsigned char SiS_MyCR63; + unsigned short SiS_CRT1Mode; + unsigned short SiS_ModeType; + unsigned short SiS_SetFlag; + + const struct SiS_StandTable *SiS_StandTable; + const struct SiS_St *SiS_SModeIDTable; + const struct SiS_Ext *SiS_EModeIDTable; + const struct SiS_Ext2 *SiS_RefIndex; + const struct SiS_CRT1Table *SiS_CRT1Table; + const struct SiS_VCLKData *SiS_VCLKData; + const struct SiS_ModeResInfo *SiS_ModeResInfo; }; #endif - -- cgit v1.2.3-70-g09d2 From 7b5cd5fefbe023625a7ff7604e8beb9a15a9efab Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 15 Aug 2007 10:38:12 -0400 Subject: USB: SisUSB2VGA: Convert printk to dev_* macros This patch convert printk entries to dev_* macros, this provide better debugging and better readability to the code. Signed-off-by: Felipe Balbi Cc: Thomas Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/sisusbvga/sisusb.c | 111 +++++++++----------------------- drivers/usb/misc/sisusbvga/sisusb_con.c | 13 ++-- 2 files changed, 36 insertions(+), 88 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index 558b94fd209..4d6b89336e6 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -1003,16 +1003,10 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr, if (ret) { msgcount++; if (msgcount < 500) - printk(KERN_ERR - "sisusbvga[%d]: Wrote %zd of " - "%d bytes, error %d\n", - sisusb->minor, *bytes_written, - length, ret); + dev_err(&sisusb->sisusb_dev->dev, "Wrote %zd of %d bytes, error %d\n", + *bytes_written, length, ret); else if (msgcount == 500) - printk(KERN_ERR - "sisusbvga[%d]: Too many errors" - ", logging stopped\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Too many errors, logging stopped\n"); } addr += (*bytes_written); length -= (*bytes_written); @@ -1389,10 +1383,10 @@ sisusb_testreadwrite(struct sisusb_usb_data *sisusb) sisusb_copy_memory(sisusb, srcbuffer, sisusb->vrambase, 7, &dummy); for(i = 1; i <= 7; i++) { - printk(KERN_DEBUG "sisusb: rwtest %d bytes\n", i); + dev_dbg(&sisusb->sisusb_dev->dev, "sisusb: rwtest %d bytes\n", i); sisusb_read_memory(sisusb, destbuffer, sisusb->vrambase, i, &dummy); for(j = 0; j < i; j++) { - printk(KERN_DEBUG "sisusb: rwtest read[%d] = %x\n", j, destbuffer[j]); + dev_dbg(&sisusb->sisusb_dev->dev, "rwtest read[%d] = %x\n", j, destbuffer[j]); } } } @@ -2111,17 +2105,12 @@ sisusb_init_gfxcore(struct sisusb_usb_data *sisusb) if (ramtype <= 1) { ret |= sisusb_get_sdram_size(sisusb, &iret, bw, chab); if (iret) { - printk(KERN_ERR "sisusbvga[%d]: RAM size " - "detection failed, " - "assuming 8MB video RAM\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev,"RAM size detection failed, assuming 8MB video RAM\n"); ret |= SETIREG(SISSR,0x14,0x31); /* TODO */ } } else { - printk(KERN_ERR "sisusbvga[%d]: DDR RAM device found, " - "assuming 8MB video RAM\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "DDR RAM device found, assuming 8MB video RAM\n"); ret |= SETIREG(SISSR,0x14,0x31); /* *** TODO *** */ } @@ -2192,8 +2181,7 @@ sisusb_get_ramconfig(struct sisusb_usb_data *sisusb) break; } - printk(KERN_INFO "sisusbvga[%d]: %dMB %s %s, bus width %d\n", - sisusb->minor, (sisusb->vramsize >> 20), ramtypetext1, + dev_info(&sisusb->sisusb_dev->dev, "%dMB %s %s, bus width %d\n", (sisusb->vramsize >> 20), ramtypetext1, ramtypetext2[ramtype], bw); } @@ -2453,8 +2441,7 @@ sisusb_open(struct inode *inode, struct file *file) int subminor = iminor(inode); if (!(interface = usb_find_interface(&sisusb_driver, subminor))) { - printk(KERN_ERR "sisusb[%d]: Failed to find interface\n", - subminor); + dev_err(&sisusb->sisusb_dev->dev, "Failed to find interface\n"); return -ENODEV; } @@ -2477,18 +2464,12 @@ sisusb_open(struct inode *inode, struct file *file) if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH) { if (sisusb_init_gfxdevice(sisusb, 0)) { mutex_unlock(&sisusb->lock); - printk(KERN_ERR - "sisusbvga[%d]: Failed to initialize " - "device\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Failed to initialize device\n"); return -EIO; } } else { mutex_unlock(&sisusb->lock); - printk(KERN_ERR - "sisusbvga[%d]: Device not attached to " - "USB 2.0 hub\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Device not attached to USB 2.0 hub\n"); return -EIO; } } @@ -2529,7 +2510,6 @@ static int sisusb_release(struct inode *inode, struct file *file) { struct sisusb_usb_data *sisusb; - int myminor; if (!(sisusb = (struct sisusb_usb_data *)file->private_data)) return -ENODEV; @@ -2542,8 +2522,6 @@ sisusb_release(struct inode *inode, struct file *file) sisusb_kill_all_busy(sisusb); } - myminor = sisusb->minor; - sisusb->isopen = 0; file->private_data = NULL; @@ -3126,17 +3104,13 @@ static int sisusb_probe(struct usb_interface *intf, struct usb_device *dev = interface_to_usbdev(intf); struct sisusb_usb_data *sisusb; int retval = 0, i; - const char *memfail = - KERN_ERR - "sisusbvga[%d]: Failed to allocate memory for %s buffer\n"; - printk(KERN_INFO "sisusb: USB2VGA dongle found at address %d\n", + dev_info(&dev->dev, "USB2VGA dongle found at address %d\n", dev->devnum); /* Allocate memory for our private */ if (!(sisusb = kzalloc(sizeof(*sisusb), GFP_KERNEL))) { - printk(KERN_ERR - "sisusb: Failed to allocate memory for private data\n"); + dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for private data\n"); return -ENOMEM; } kref_init(&sisusb->kref); @@ -3145,8 +3119,7 @@ static int sisusb_probe(struct usb_interface *intf, /* Register device */ if ((retval = usb_register_dev(intf, &usb_sisusb_class))) { - printk(KERN_ERR - "sisusb: Failed to get a minor for device %d\n", + dev_err(&sisusb->sisusb_dev->dev, "Failed to get a minor for device %d\n", dev->devnum); retval = -ENODEV; goto error_1; @@ -3164,7 +3137,7 @@ static int sisusb_probe(struct usb_interface *intf, sisusb->ibufsize = SISUSB_IBUF_SIZE; if (!(sisusb->ibuf = usb_buffer_alloc(dev, SISUSB_IBUF_SIZE, GFP_KERNEL, &sisusb->transfer_dma_in))) { - printk(memfail, "input", sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for input buffer"); retval = -ENOMEM; goto error_2; } @@ -3176,7 +3149,7 @@ static int sisusb_probe(struct usb_interface *intf, GFP_KERNEL, &sisusb->transfer_dma_out[i]))) { if (i == 0) { - printk(memfail, "output", sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for output buffer\n"); retval = -ENOMEM; goto error_3; } @@ -3188,9 +3161,7 @@ static int sisusb_probe(struct usb_interface *intf, /* Allocate URBs */ if (!(sisusb->sisurbin = usb_alloc_urb(0, GFP_KERNEL))) { - printk(KERN_ERR - "sisusbvga[%d]: Failed to allocate URBs\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate URBs\n"); retval = -ENOMEM; goto error_3; } @@ -3198,9 +3169,7 @@ static int sisusb_probe(struct usb_interface *intf, for (i = 0; i < sisusb->numobufs; i++) { if (!(sisusb->sisurbout[i] = usb_alloc_urb(0, GFP_KERNEL))) { - printk(KERN_ERR - "sisusbvga[%d]: Failed to allocate URBs\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate URBs\n"); retval = -ENOMEM; goto error_4; } @@ -3209,15 +3178,12 @@ static int sisusb_probe(struct usb_interface *intf, sisusb->urbstatus[i] = 0; } - printk(KERN_INFO "sisusbvga[%d]: Allocated %d output buffers\n", - sisusb->minor, sisusb->numobufs); + dev_info(&sisusb->sisusb_dev->dev, "Allocated %d output buffers\n", sisusb->numobufs); #ifdef INCL_SISUSB_CON /* Allocate our SiS_Pr */ if (!(sisusb->SiS_Pr = kmalloc(sizeof(struct SiS_Private), GFP_KERNEL))) { - printk(KERN_ERR - "sisusbvga[%d]: Failed to allocate SiS_Pr\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate SiS_Pr\n"); } #endif @@ -3239,10 +3205,7 @@ static int sisusb_probe(struct usb_interface *intf, ret |= register_ioctl32_conversion(SISUSB_GET_CONFIG, NULL); ret |= register_ioctl32_conversion(SISUSB_COMMAND, NULL); if (ret) - printk(KERN_ERR - "sisusbvga[%d]: Error registering ioctl32 " - "translations\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Error registering ioctl32 translations\n"); else sisusb->ioctl32registered = 1; } @@ -3258,23 +3221,17 @@ static int sisusb_probe(struct usb_interface *intf, initscreen = 0; #endif if (sisusb_init_gfxdevice(sisusb, initscreen)) - printk(KERN_ERR - "sisusbvga[%d]: Failed to early " - "initialize device\n", - sisusb->minor); + dev_err(&sisusb->sisusb_dev->dev, "Failed to early initialize device\n"); } else - printk(KERN_INFO - "sisusbvga[%d]: Not attached to USB 2.0 hub, " - "deferring init\n", - sisusb->minor); + dev_info(&sisusb->sisusb_dev->dev, "Not attached to USB 2.0 hub, deferring init\n"); sisusb->ready = 1; #ifdef SISUSBENDIANTEST - printk(KERN_DEBUG "sisusb: *** RWTEST ***\n"); + dev_dbg(&sisusb->sisusb_dev->dev, "*** RWTEST ***\n"); sisusb_testreadwrite(sisusb); - printk(KERN_DEBUG "sisusb: *** RWTEST END ***\n"); + dev_dbg(&sisusb->sisusb_dev->dev, "*** RWTEST END ***\n"); #endif #ifdef INCL_SISUSB_CON @@ -3297,7 +3254,6 @@ error_1: static void sisusb_disconnect(struct usb_interface *intf) { struct sisusb_usb_data *sisusb; - int minor; /* This should *not* happen */ if (!(sisusb = usb_get_intfdata(intf))) @@ -3307,8 +3263,6 @@ static void sisusb_disconnect(struct usb_interface *intf) sisusb_console_exit(sisusb); #endif - minor = sisusb->minor; - usb_deregister_dev(intf, &usb_sisusb_class); mutex_lock(&sisusb->lock); @@ -3327,10 +3281,7 @@ static void sisusb_disconnect(struct usb_interface *intf) ret |= unregister_ioctl32_conversion(SISUSB_GET_CONFIG); ret |= unregister_ioctl32_conversion(SISUSB_COMMAND); if (ret) { - printk(KERN_ERR - "sisusbvga[%d]: Error unregistering " - "ioctl32 translations\n", - minor); + dev_err(&sisusb->sisusb_dev->dev, "Error unregistering ioctl32 translations\n"); } } #endif @@ -3343,7 +3294,7 @@ static void sisusb_disconnect(struct usb_interface *intf) /* decrement our usage count */ kref_put(&sisusb->kref, sisusb_delete); - printk(KERN_INFO "sisusbvga[%d]: Disconnected\n", minor); + dev_info(&sisusb->sisusb_dev->dev, "Disconnected\n"); } static struct usb_device_id sisusb_table [] = { @@ -3368,6 +3319,7 @@ static struct usb_driver sisusb_driver = { static int __init usb_sisusb_init(void) { int retval; + struct sisusb_usb_data *sisusb; #ifdef INCL_SISUSB_CON sisusb_init_concode(); @@ -3375,10 +3327,9 @@ static int __init usb_sisusb_init(void) if (!(retval = usb_register(&sisusb_driver))) { - printk(KERN_INFO "sisusb: Driver version %d.%d.%d\n", - SISUSB_VERSION, SISUSB_REVISION, SISUSB_PATCHLEVEL); - printk(KERN_INFO - "sisusb: Copyright (C) 2005 Thomas Winischhofer\n"); + dev_info(&sisusb->sisusb_dev->dev, "Driver version %d.%d.%d\n", SISUSB_VERSION, + SISUSB_REVISION, SISUSB_PATCHLEVEL); + dev_info(&sisusb->sisusb_dev->dev, "sisusb: Copyright (C) 2005 Thomas Winischhofer\n"); } diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c index 20938cd09ed..43722e5a49d 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_con.c +++ b/drivers/usb/misc/sisusbvga/sisusb_con.c @@ -52,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -537,7 +538,7 @@ sisusbcon_switch(struct vc_data *c) */ if (c->vc_origin == (unsigned long)c->vc_screenbuf) { mutex_unlock(&sisusb->lock); - printk(KERN_DEBUG "sisusb: ASSERT ORIGIN != SCREENBUF!\n"); + dev_dbg(&sisusb->sisusb_dev->dev, "ASSERT ORIGIN != SCREENBUF!\n"); return 0; } @@ -1428,7 +1429,7 @@ static const struct consw sisusb_dummy_con = { int sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last) { - int i, ret, minor = sisusb->minor; + int i, ret; mutex_lock(&sisusb->lock); @@ -1461,9 +1462,7 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last) /* Set up text mode (and upload default font) */ if (sisusb_reset_text_mode(sisusb, 1)) { mutex_unlock(&sisusb->lock); - printk(KERN_ERR - "sisusbvga[%d]: Failed to set up text mode\n", - minor); + dev_err(&sisusb->sisusb_dev->dev, "Failed to set up text mode\n"); return 1; } @@ -1484,9 +1483,7 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last) /* Allocate screen buffer */ if (!(sisusb->scrbuf = (unsigned long)vmalloc(sisusb->scrbuf_size))) { mutex_unlock(&sisusb->lock); - printk(KERN_ERR - "sisusbvga[%d]: Failed to allocate screen buffer\n", - minor); + dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate screen buffer\n"); return 1; } -- cgit v1.2.3-70-g09d2 From fc401e697f8c00ad1178a6758e86e3881dfa3181 Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Mon, 13 Aug 2007 22:50:13 -0700 Subject: usblp: mutex in usblp_check_status Add a mutex to protect the ->statusbuf. Not really an issue, because CUPS is single-threaded when it talks to the printer, but I feel safer this way. This should be deadlock-free, but I kept this as a separate patch in case someone ends running a git bisect. Signed-off-by: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usblp.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index 9696668e575..2c4a359355b 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -345,16 +345,17 @@ static int usblp_check_status(struct usblp *usblp, int err) unsigned char status, newerr = 0; int error; - error = usblp_read_status (usblp, usblp->statusbuf); - if (error < 0) { + mutex_lock(&usblp->mut); + if ((error = usblp_read_status(usblp, usblp->statusbuf)) < 0) { + mutex_unlock(&usblp->mut); if (printk_ratelimit()) printk(KERN_ERR "usblp%d: error %d reading printer status\n", usblp->minor, error); return 0; } - status = *usblp->statusbuf; + mutex_unlock(&usblp->mut); if (~status & LP_PERRORP) newerr = 3; -- cgit v1.2.3-70-g09d2 From 283face86b002e670053e9189604852ccb81d357 Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Mon, 13 Aug 2007 22:54:29 -0700 Subject: usblp: Cosmetics This is a small bunch of cosmetic fixes: - Timeout is not a write timeout anymore, rename - Condition in poll was confusingly backwards, invert and simplify - The comment log gave a wrong impression of version 0.13, terminate it. Signed-off-by: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usblp.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index 2c4a359355b..3a0f8186d4b 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -28,6 +28,7 @@ * v0.12 - add hpoj.sourceforge.net ioctls (David Paschal) * v0.13 - alloc space for statusbuf ( not on stack); * use usb_buffer_alloc() for read buf & write buf; + * none - Maintained in Linux kernel after v0.13 */ /* @@ -114,7 +115,7 @@ MFG:HEWLETT-PACKARD;MDL:DESKJET 970C;CMD:MLC,PCL,PML;CLASS:PRINTER;DESCRIPTION:H #define USBLP_MINORS 16 #define USBLP_MINOR_BASE 0 -#define USBLP_WRITE_TIMEOUT (5000) /* 5 seconds */ +#define USBLP_CTL_TIMEOUT 5000 /* 5 seconds */ #define USBLP_FIRST_PROTOCOL 1 #define USBLP_LAST_PROTOCOL 3 @@ -260,7 +261,7 @@ static int usblp_ctrl_msg(struct usblp *usblp, int request, int type, int dir, i retval = usb_control_msg(usblp->dev, dir ? usb_rcvctrlpipe(usblp->dev, 0) : usb_sndctrlpipe(usblp->dev, 0), - request, type | dir | recip, value, index, buf, len, USBLP_WRITE_TIMEOUT); + request, type | dir | recip, value, index, buf, len, USBLP_CTL_TIMEOUT); dbg("usblp_control_msg: rq: 0x%02x dir: %d recip: %d value: %d idx: %d len: %#x result: %d", request, !!dir, recip, value, index, len, retval); return retval < 0 ? retval : 0; @@ -479,8 +480,8 @@ static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait poll_wait(file, &usblp->rwait, wait); poll_wait(file, &usblp->wwait, wait); spin_lock_irqsave(&usblp->lock, flags); - ret = ((!usblp->bidir || !usblp->rcomplete) ? 0 : POLLIN | POLLRDNORM) - | ((usblp->no_paper || usblp->wcomplete) ? POLLOUT | POLLWRNORM : 0); + ret = ((usblp->bidir && usblp->rcomplete) ? POLLIN | POLLRDNORM : 0) | + ((usblp->no_paper || usblp->wcomplete) ? POLLOUT | POLLWRNORM : 0); spin_unlock_irqrestore(&usblp->lock, flags); return ret; } -- cgit v1.2.3-70-g09d2 From 30c7431de3631d6a5482a87b7c2453b937e8aa51 Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Tue, 14 Aug 2007 00:33:40 -0700 Subject: usbmon: Update pipe removal to suit my taste This is a set of small updates to Alan's work to make the code more to my liking. Mostly premature optimizations, but also direction of control transfers in the binary interface was always out. Signed-off-by: Pete Zaitcev Cc: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/mon/mon_bin.c | 44 ++++++++++++++------------------------------ drivers/usb/mon/mon_text.c | 8 ++++---- 2 files changed, 18 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c index 0b0d77c669d..5185e93dede 100644 --- a/drivers/usb/mon/mon_bin.c +++ b/drivers/usb/mon/mon_bin.c @@ -172,6 +172,10 @@ static inline struct mon_bin_hdr *MON_OFF2HDR(const struct mon_reader_bin *rp, #define MON_RING_EMPTY(rp) ((rp)->b_cnt == 0) +static unsigned char xfer_to_pipe[4] = { + PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT +}; + static struct class *mon_bin_class; static dev_t mon_bin_dev0; static struct cdev mon_bin_cdev; @@ -388,11 +392,13 @@ static char mon_bin_get_data(const struct mon_reader_bin *rp, static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, char ev_type) { + const struct usb_endpoint_descriptor *epd = &urb->ep->desc; unsigned long flags; struct timeval ts; unsigned int urb_length; unsigned int offset; unsigned int length; + unsigned char dir; struct mon_bin_hdr *ep; char data_tag = 0; @@ -415,11 +421,14 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, length = 0; data_tag = '<'; } + /* Cannot rely on endpoint number in case of control ep.0 */ + dir = USB_DIR_IN; } else { if (ev_type == 'C') { length = 0; data_tag = '>'; } + dir = 0; } if (rp->mmap_active) @@ -440,21 +449,8 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, */ memset(ep, 0, PKT_SIZE); ep->type = ev_type; - switch (usb_endpoint_type(&urb->ep->desc)) { - case USB_ENDPOINT_XFER_CONTROL: - ep->xfer_type = PIPE_CONTROL; - break; - case USB_ENDPOINT_XFER_BULK: - ep->xfer_type = PIPE_BULK; - break; - case USB_ENDPOINT_XFER_INT: - ep->xfer_type = PIPE_INTERRUPT; - break; - default: - ep->xfer_type = PIPE_ISOCHRONOUS; - break; - } - ep->epnum = urb->ep->desc.bEndpointAddress; + ep->xfer_type = xfer_to_pipe[usb_endpoint_type(epd)]; + ep->epnum = dir | usb_endpoint_num(epd); ep->devnum = urb->dev->devnum; ep->busnum = urb->dev->bus->busnum; ep->id = (unsigned long) urb; @@ -512,21 +508,9 @@ static void mon_bin_error(void *data, struct urb *urb, int error) memset(ep, 0, PKT_SIZE); ep->type = 'E'; - switch (usb_endpoint_type(&urb->ep->desc)) { - case USB_ENDPOINT_XFER_CONTROL: - ep->xfer_type = PIPE_CONTROL; - break; - case USB_ENDPOINT_XFER_BULK: - ep->xfer_type = PIPE_BULK; - break; - case USB_ENDPOINT_XFER_INT: - ep->xfer_type = PIPE_INTERRUPT; - break; - default: - ep->xfer_type = PIPE_ISOCHRONOUS; - break; - } - ep->epnum = urb->ep->desc.bEndpointAddress; + ep->xfer_type = xfer_to_pipe[usb_endpoint_type(&urb->ep->desc)]; + ep->epnum = usb_urb_dir_in(urb) ? USB_DIR_IN : 0; + ep->epnum |= usb_endpoint_num(&urb->ep->desc); ep->devnum = urb->dev->devnum; ep->busnum = urb->dev->bus->busnum; ep->id = (unsigned long) urb; diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c index 9d0070ceef5..a74069c2e82 100644 --- a/drivers/usb/mon/mon_text.c +++ b/drivers/usb/mon/mon_text.c @@ -52,10 +52,11 @@ struct mon_event_text { int type; /* submit, complete, etc. */ unsigned long id; /* From pointer, most of the time */ unsigned int tstamp; - int xfertype; int busnum; - int devnum; - int epnum; + char devnum; + char epnum; + char is_in; + char xfertype; int length; /* Depends on type: xfer length or act length */ int status; int interval; @@ -63,7 +64,6 @@ struct mon_event_text { int error_count; char setup_flag; char data_flag; - char is_in; int numdesc; /* Full number */ struct mon_iso_desc isodesc[ISODESC_MAX]; unsigned char setup[SETUP_MAX]; -- cgit v1.2.3-70-g09d2 From cdd5a8fd24f5be43417a25c6feb8e7ebdce63098 Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Tue, 14 Aug 2007 00:37:51 -0700 Subject: usbmon: Drop DMA mapping for setup packet Setup packet must be visible in virtual space. There's absolutely no good reason to implement any kind of zero-copy transfer of 8 bytes, and the documentation in usb.h is explicit about it. So, drop DMA remapping. Signed-off-by: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman --- drivers/usb/mon/mon_bin.c | 4 ---- drivers/usb/mon/mon_text.c | 4 ---- 2 files changed, 8 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c index 5185e93dede..3d6f03819ff 100644 --- a/drivers/usb/mon/mon_bin.c +++ b/drivers/usb/mon/mon_bin.c @@ -361,10 +361,6 @@ static inline char mon_bin_get_setup(unsigned char *setupb, if (!usb_endpoint_xfer_control(&urb->ep->desc) || ev_type != 'S') return '-'; - if (urb->dev->bus->uses_dma && - (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) { - return mon_dmapeek(setupb, urb->setup_dma, SETUP_LEN); - } if (urb->setup_packet == NULL) return 'Z'; diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c index a74069c2e82..663a702a17d 100644 --- a/drivers/usb/mon/mon_text.c +++ b/drivers/usb/mon/mon_text.c @@ -127,10 +127,6 @@ static inline char mon_text_get_setup(struct mon_event_text *ep, if (ep->xfertype != USB_ENDPOINT_XFER_CONTROL || ev_type != 'S') return '-'; - if (urb->dev->bus->uses_dma && - (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) { - return mon_dmapeek(ep->setup, urb->setup_dma, SETUP_MAX); - } if (urb->setup_packet == NULL) return 'Z'; /* '0' would be not as pretty. */ -- cgit v1.2.3-70-g09d2 From c36d54ab380fb8edeaa22776af869c64bfda43bd Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Tue, 14 Aug 2007 00:42:53 -0700 Subject: usbmon: Smooth the core code Two things: - mbus can be NULL (in case of bus removal while reader is reading) - Remove a useless assignment Signed-off-by: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman --- drivers/usb/mon/mon_main.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c index e58f761d060..2e317bd79e9 100644 --- a/drivers/usb/mon/mon_main.c +++ b/drivers/usb/mon/mon_main.c @@ -148,18 +148,8 @@ static void mon_complete(struct usb_bus *ubus, struct urb *urb) { struct mon_bus *mbus; - mbus = ubus->mon_bus; - if (mbus == NULL) { - /* - * This should not happen. - * At this point we do not even know the bus number... - */ - printk(KERN_ERR TAG ": Null mon bus in URB, address %p\n", - urb); - return; - } - - mon_bus_complete(mbus, urb); + if ((mbus = ubus->mon_bus) != NULL) + mon_bus_complete(mbus, urb); mon_bus_complete(&mon_bus0, urb); } @@ -170,7 +160,7 @@ static void mon_complete(struct usb_bus *ubus, struct urb *urb) */ static void mon_stop(struct mon_bus *mbus) { - struct usb_bus *ubus = mbus->u_bus; + struct usb_bus *ubus; struct list_head *p; if (mbus == &mon_bus0) { -- cgit v1.2.3-70-g09d2 From 42cb967fd01b1f50374fdfa811f86db103eea532 Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Tue, 14 Aug 2007 13:19:16 -0700 Subject: usblp: Fix a double kfree If submit fails, slab hits a BUG() because of a double kfree. The today's lesson is, you cannot just slap USB_FREE_BUFFER on code without adjusting the error paths. The patch is made bigger by opportunistic refactoring. Signed-Off-By: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usblp.c | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index 3a0f8186d4b..ad632f2d6f9 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -686,10 +686,30 @@ done: return retval; } +static struct urb *usblp_new_writeurb(struct usblp *usblp, int transfer_length) +{ + struct urb *urb; + char *writebuf; + + if ((writebuf = kmalloc(transfer_length, GFP_KERNEL)) == NULL) + return NULL; + if ((urb = usb_alloc_urb(0, GFP_KERNEL)) == NULL) { + kfree(writebuf); + return NULL; + } + + usb_fill_bulk_urb(urb, usblp->dev, + usb_sndbulkpipe(usblp->dev, + usblp->protocol[usblp->current_protocol].epwrite->bEndpointAddress), + writebuf, transfer_length, usblp_bulk_write, usblp); + urb->transfer_flags |= URB_FREE_BUFFER; + + return urb; +} + static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { struct usblp *usblp = file->private_data; - char *writebuf; struct urb *writeurb; int rv; int transfer_length; @@ -710,18 +730,11 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t transfer_length = USBLP_BUF_SIZE; rv = -ENOMEM; - if ((writebuf = kmalloc(USBLP_BUF_SIZE, GFP_KERNEL)) == NULL) - goto raise_buf; - if ((writeurb = usb_alloc_urb(0, GFP_KERNEL)) == NULL) + if ((writeurb = usblp_new_writeurb(usblp, transfer_length)) == NULL) goto raise_urb; - usb_fill_bulk_urb(writeurb, usblp->dev, - usb_sndbulkpipe(usblp->dev, - usblp->protocol[usblp->current_protocol].epwrite->bEndpointAddress), - writebuf, transfer_length, usblp_bulk_write, usblp); - writeurb->transfer_flags |= URB_FREE_BUFFER; usb_anchor_urb(writeurb, &usblp->urbs); - if (copy_from_user(writebuf, + if (copy_from_user(writeurb->transfer_buffer, buffer + writecount, transfer_length)) { rv = -EFAULT; goto raise_badaddr; @@ -780,8 +793,6 @@ raise_badaddr: usb_unanchor_urb(writeurb); usb_free_urb(writeurb); raise_urb: - kfree(writebuf); -raise_buf: raise_wait: collect_error: /* Out of raise sequence */ mutex_unlock(&usblp->wmut); -- cgit v1.2.3-70-g09d2 From 3f6ff6ef044bc7078daa01412c911015d6cbaa39 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 10 Aug 2007 14:53:34 -0700 Subject: USB: kl5kusb105: witch to new speed API Signed-off-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/kl5kusb105.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index 5a4127e62c4..90e3216abd1 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -728,24 +728,32 @@ static void klsi_105_set_termios (struct usb_serial_port *port, #endif } - switch(cflag & CBAUD) { - case B0: /* handled below */ + switch(tty_get_baud_rate(port->tty)) { + case 0: /* handled below */ break; - case B1200: priv->cfg.baudrate = kl5kusb105a_sio_b1200; + case 1200: + priv->cfg.baudrate = kl5kusb105a_sio_b1200; break; - case B2400: priv->cfg.baudrate = kl5kusb105a_sio_b2400; + case 2400: + priv->cfg.baudrate = kl5kusb105a_sio_b2400; break; - case B4800: priv->cfg.baudrate = kl5kusb105a_sio_b4800; + case 4800: + priv->cfg.baudrate = kl5kusb105a_sio_b4800; break; - case B9600: priv->cfg.baudrate = kl5kusb105a_sio_b9600; + case 9600: + priv->cfg.baudrate = kl5kusb105a_sio_b9600; break; - case B19200: priv->cfg.baudrate = kl5kusb105a_sio_b19200; + case 19200: + priv->cfg.baudrate = kl5kusb105a_sio_b19200; break; - case B38400: priv->cfg.baudrate = kl5kusb105a_sio_b38400; + case 38400: + priv->cfg.baudrate = kl5kusb105a_sio_b38400; break; - case B57600: priv->cfg.baudrate = kl5kusb105a_sio_b57600; + case 57600: + priv->cfg.baudrate = kl5kusb105a_sio_b57600; break; - case B115200: priv->cfg.baudrate = kl5kusb105a_sio_b115200; + case 115200: + priv->cfg.baudrate = kl5kusb105a_sio_b115200; break; default: err("KLSI USB->Serial converter:" -- cgit v1.2.3-70-g09d2 From b3aceb2bab988e514e65dd37f385221a095ad477 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Fri, 10 Aug 2007 14:53:35 -0700 Subject: USB: mct_u232-convert-to-proper-speed-handling-api-fix Make Pete happy Cc: Alan Cox Cc: Pete Zaitcev Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/mct_u232.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index e08c9bb403d..0dc99f75bb0 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -206,20 +206,20 @@ static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value } } else { switch (value) { - case 300: break; - case 600: break; - case 1200: break; - case 2400: break; - case 4800: break; - case 9600: break; - case 19200: break; - case 38400: break; - case 57600: break; - case 115200: break; - default: - err("MCT USB-RS232: unsupported baudrate request 0x%x," - " using default of B9600", value); - value = 9600; + case 300: break; + case 600: break; + case 1200: break; + case 2400: break; + case 4800: break; + case 9600: break; + case 19200: break; + case 38400: break; + case 57600: break; + case 115200: break; + default: + err("MCT USB-RS232: unsupported baudrate request 0x%x," + " using default of B9600", value); + value = 9600; } return 115200/value; } -- cgit v1.2.3-70-g09d2 From 5280d6083a77cc06a8c8360a2c461fd12d780fb8 Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Fri, 10 Aug 2007 14:53:35 -0700 Subject: USB: ftdi-elan.c: kmalloc + memset conversion to kzalloc drivers/usb/misc/ftdi-elan.c | 121253 -> 121196 (-57 bytes) drivers/usb/misc/ftdi-elan.o | 209425 -> 209265 (-160 bytes) Signed-off-by: Mariusz Kozlowski Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/ftdi-elan.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c index 538b535e955..d3d8cd6ff10 100644 --- a/drivers/usb/misc/ftdi-elan.c +++ b/drivers/usb/misc/ftdi-elan.c @@ -2777,12 +2777,14 @@ static int ftdi_elan_probe(struct usb_interface *interface, size_t buffer_size; int i; int retval = -ENOMEM; - struct usb_ftdi *ftdi = kmalloc(sizeof(struct usb_ftdi), GFP_KERNEL); - if (ftdi == NULL) { + struct usb_ftdi *ftdi; + + ftdi = kzalloc(sizeof(struct usb_ftdi), GFP_KERNEL); + if (!ftdi) { printk(KERN_ERR "Out of memory\n"); return -ENOMEM; } - memset(ftdi, 0x00, sizeof(struct usb_ftdi)); + mutex_lock(&ftdi_module_lock); list_add_tail(&ftdi->ftdi_list, &ftdi_static_list); ftdi->sequence_num = ++ftdi_instances; -- cgit v1.2.3-70-g09d2 From 60b69a966fddeb3bdd79712d52b34b8696a27f88 Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Fri, 10 Aug 2007 14:53:37 -0700 Subject: usb: remove redundant memset from amd5536udc Remove redundant memset() call from udc_pci_probe(). No functional change. Signed-off-by: Mariusz Kozlowski Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/amd5536udc.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index 714156ca8fe..e95ffc9eee3 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c @@ -3244,7 +3244,6 @@ static int udc_pci_probe( retval = -ENOMEM; goto finished; } - memset(dev, 0, sizeof(struct udc)); /* pci setup */ if (pci_enable_device(pdev) < 0) { -- cgit v1.2.3-70-g09d2 From f6c1ceaa3844b7a7787816cc97d15b9fea8b0909 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Thu, 16 Aug 2007 16:02:08 +0200 Subject: USB: missing test for ESHUTDOWN in adutux driver this driver lacks a test for unlink due to ESHUTDOWN Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/adutux.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c index e9fdbc8997b..5131cbfb2f5 100644 --- a/drivers/usb/misc/adutux.c +++ b/drivers/usb/misc/adutux.c @@ -188,7 +188,8 @@ static void adu_interrupt_in_callback(struct urb *urb) spin_lock(&dev->buflock); if (status != 0) { - if ((status != -ENOENT) && (status != -ECONNRESET)) { + if ((status != -ENOENT) && (status != -ECONNRESET) && + (status != -ESHUTDOWN)) { dbg(1," %s : nonzero status received: %d", __FUNCTION__, status); } -- cgit v1.2.3-70-g09d2 From f311cf58bd04adc683067f8d66daa5925b80f082 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 14 Aug 2007 23:22:50 +0200 Subject: USB: ark3116.c: fix check-after-use The Coverity checker spotted that we'd have already oops'ed if one of these was NULL. Signed-off-by: Adrian Bunk Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ark3116.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index c9fd486c1c7..2a8e537cb04 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c @@ -172,11 +172,6 @@ static void ark3116_set_termios(struct usb_serial_port *port, dbg("%s - port %d", __FUNCTION__, port->number); - if (!port->tty || !port->tty->termios) { - dbg("%s - no tty structures", __FUNCTION__); - return; - } - spin_lock_irqsave(&priv->lock, flags); if (!priv->termios_initialized) { *(port->tty->termios) = tty_std_termios; -- cgit v1.2.3-70-g09d2 From e39ab592f182cd0be48acc4ad49f93ef4100017c Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 16 Aug 2007 16:17:49 -0400 Subject: USB: remove unnecessary tests in isp116x and sl811 This patch (as962) cleans up some code I forgot to remove earlier in the isp116x and sl811 HCDs. There is no longer any need to check for unlink-during-submit; it can't happen since the endpoint queues are now under the protection of the HCD-private spinlock. Signed-off-by: Alan Stern CC: David Brownell CC: Olav Kongas Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/isp116x-hcd.c | 6 ------ drivers/usb/host/sl811-hcd.c | 10 ---------- 2 files changed, 16 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index d5027dc75a5..f2b5d6281c5 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -815,12 +815,6 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd, } } - /* in case of unlink-during-submit */ - if (urb->status != -EINPROGRESS) { - finish_request(isp116x, ep, urb); - ret = 0; - goto fail; - } urb->hcpriv = hep; start_atl_transfers(isp116x); diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index 3d3a63d002c..15a93f946af 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -957,17 +957,7 @@ static int sl811h_urb_enqueue( sofirq_on(sl811); } - /* in case of unlink-during-submit */ - spin_lock(&urb->lock); - if (urb->status != -EINPROGRESS) { - spin_unlock(&urb->lock); - finish_request(sl811, ep, urb, 0); - retval = 0; - goto fail; - } urb->hcpriv = hep; - spin_unlock(&urb->lock); - start_transfer(sl811); sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable); fail: -- cgit v1.2.3-70-g09d2 From c8e463796c7ae6d8dda39b0c7eb3d627600ffe2e Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 20 Aug 2007 23:23:12 +0200 Subject: UEAGLE: Eagle IV chipset support Add support to newest chipset of eagle family. It is compatible with older chipsets at USB level. However DSP firmware and CMVs (Configuration and Management Variables) have different format of data and are sent/received by different way. Signed-off-by: Stanislaw Gruszka Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/ueagle-atm.c | 1191 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 978 insertions(+), 213 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index 29807d048b0..b5e8cbad223 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -107,12 +107,42 @@ #define uea_info(usb_dev, format,args...) \ dev_info(&(usb_dev)->dev ,"[ueagle-atm] " format, ##args) -struct uea_cmvs { +struct intr_pkt; + +/* cmv's from firmware */ +struct uea_cmvs_v1 { u32 address; u16 offset; u32 data; } __attribute__ ((packed)); +struct uea_cmvs_v2 { + u32 group; + u32 address; + u32 offset; + u32 data; +} __attribute__ ((packed)); + +/* information about currently processed cmv */ +struct cmv_dsc_e1 { + u8 function; + u16 idx; + u32 address; + u16 offset; +}; + +struct cmv_dsc_e4 { + u16 function; + u16 offset; + u16 address; + u16 group; +}; + +union cmv_dsc { + struct cmv_dsc_e1 e1; + struct cmv_dsc_e4 e4; +}; + struct uea_softc { struct usb_device *usb_dev; struct usbatm_data *usbatm; @@ -127,8 +157,11 @@ struct uea_softc { struct task_struct *kthread; u32 data; + u32 data1; wait_queue_head_t cmv_ack_wait; + int cmv_ack; + union cmv_dsc cmv_dsc; struct work_struct task; u16 pageno; @@ -137,10 +170,10 @@ struct uea_softc { const struct firmware *dsp_firm; struct urb *urb_int; - u8 cmv_function; - u16 cmv_idx; - u32 cmv_address; - u16 cmv_offset; + void (*dispatch_cmv) (struct uea_softc *, struct intr_pkt *); + void (*schedule_load_page) (struct uea_softc *, struct intr_pkt *); + int (*stat) (struct uea_softc *); + int (*send_cmvs) (struct uea_softc *); /* keep in sync with eaglectl */ struct uea_stats { @@ -187,12 +220,12 @@ struct uea_softc { #define EAGLE_II_PID_PREFIRM 0x9022 /* Eagle II */ #define EAGLE_II_PID_PSTFIRM 0x9021 /* Eagle II */ -/* - * Eagle III Pid - */ #define EAGLE_III_PID_PREFIRM 0x9032 /* Eagle III */ #define EAGLE_III_PID_PSTFIRM 0x9031 /* Eagle III */ +#define EAGLE_IV_PID_PREFIRM 0x9042 /* Eagle IV */ +#define EAGLE_IV_PID_PSTFIRM 0x9041 /* Eagle IV */ + /* * USR USB IDs */ @@ -212,7 +245,8 @@ enum { ADI930 = 0, EAGLE_I, EAGLE_II, - EAGLE_III + EAGLE_III, + EAGLE_IV }; /* macros for both struct usb_device_id and struct uea_softc */ @@ -228,8 +262,11 @@ enum { #define GET_STATUS(data) \ ((data >> 8) & 0xf) + #define IS_OPERATIONAL(sc) \ - (GET_STATUS(sc->stats.phy.state) == 2) + ((UEA_CHIP_VERSION(sc) != EAGLE_IV) ? \ + (GET_STATUS(sc->stats.phy.state) == 2) : \ + (sc->stats.phy.state == 7)) /* * Set of macros to handle unaligned data in the firmware blob. @@ -259,7 +296,8 @@ enum { #define UEA_INTR_PIPE 0x04 #define UEA_ISO_DATA_PIPE 0x08 -#define UEA_SET_BLOCK 0x0001 +#define UEA_E1_SET_BLOCK 0x0001 +#define UEA_E4_SET_BLOCK 0x002c #define UEA_SET_MODE 0x0003 #define UEA_SET_2183_DATA 0x0004 #define UEA_SET_TIMEOUT 0x0011 @@ -275,71 +313,179 @@ enum { #define UEA_MPTX_MAILBOX (0x3fd6 | 0x4000) #define UEA_MPRX_MAILBOX (0x3fdf | 0x4000) -/* structure describing a block within a DSP page */ -struct block_info { +/* block information in eagle4 dsp firmware */ +struct block_index { + __le32 PageOffset; + __le32 NotLastBlock; + __le32 dummy; + __le32 PageSize; + __le32 PageAddress; + __le16 dummy1; + __le16 PageNumber; +} __attribute__ ((packed)); + +#define E4_IS_BOOT_PAGE(PageSize) ((le32_to_cpu(PageSize)) & 0x80000000) +#define E4_PAGE_BYTES(PageSize) ((le32_to_cpu(PageSize) & 0x7fffffff) * 4) + +#define E4_L1_STRING_HEADER 0x10 +#define E4_MAX_PAGE_NUMBER 0x58 +#define E4_NO_SWAPPAGE_HEADERS 0x31 + +/* l1_code is eagle4 dsp firmware format */ +struct l1_code { + u8 string_header[E4_L1_STRING_HEADER]; + u8 page_number_to_block_index[E4_MAX_PAGE_NUMBER]; + struct block_index page_header[E4_NO_SWAPPAGE_HEADERS]; + u8 code [0]; +} __attribute__ ((packed)); + +/* structures describing a block within a DSP page */ +struct block_info_e1 { __le16 wHdr; -#define UEA_BIHDR 0xabcd __le16 wAddress; __le16 wSize; __le16 wOvlOffset; __le16 wOvl; /* overlay */ __le16 wLast; } __attribute__ ((packed)); -#define BLOCK_INFO_SIZE 12 +#define E1_BLOCK_INFO_SIZE 12 + +struct block_info_e4 { + __be16 wHdr; + __u8 bBootPage; + __u8 bPageNumber; + __be32 dwSize; + __be32 dwAddress; + __be16 wReserved; +} __attribute__ ((packed)); +#define E4_BLOCK_INFO_SIZE 14 -/* structure representing a CMV (Configuration and Management Variable) */ -struct cmv { - __le16 wPreamble; -#define PREAMBLE 0x535c - __u8 bDirection; -#define MODEMTOHOST 0x01 -#define HOSTTOMODEM 0x10 - __u8 bFunction; -#define FUNCTION_TYPE(f) ((f) >> 4) -#define MEMACCESS 0x1 -#define ADSLDIRECTIVE 0x7 +#define UEA_BIHDR 0xabcd +#define UEA_RESERVED 0xffff + +/* constants describing cmv type */ +#define E1_PREAMBLE 0x535c +#define E1_MODEMTOHOST 0x01 +#define E1_HOSTTOMODEM 0x10 + +#define E1_MEMACCESS 0x1 +#define E1_ADSLDIRECTIVE 0x7 +#define E1_FUNCTION_TYPE(f) ((f) >> 4) +#define E1_FUNCTION_SUBTYPE(f) ((f) & 0x0f) + +#define E4_MEMACCESS 0 +#define E4_ADSLDIRECTIVE 0xf +#define E4_FUNCTION_TYPE(f) ((f) >> 8) +#define E4_FUNCTION_SIZE(f) ((f) & 0x0f) +#define E4_FUNCTION_SUBTYPE(f) (((f) >> 4) & 0x0f) -#define FUNCTION_SUBTYPE(f) ((f) & 0x0f) /* for MEMACCESS */ -#define REQUESTREAD 0x0 -#define REQUESTWRITE 0x1 -#define REPLYREAD 0x2 -#define REPLYWRITE 0x3 +#define E1_REQUESTREAD 0x0 +#define E1_REQUESTWRITE 0x1 +#define E1_REPLYREAD 0x2 +#define E1_REPLYWRITE 0x3 + +#define E4_REQUESTREAD 0x0 +#define E4_REQUESTWRITE 0x4 +#define E4_REPLYREAD (E4_REQUESTREAD | 1) +#define E4_REPLYWRITE (E4_REQUESTWRITE | 1) + /* for ADSLDIRECTIVE */ -#define KERNELREADY 0x0 -#define MODEMREADY 0x1 +#define E1_KERNELREADY 0x0 +#define E1_MODEMREADY 0x1 -#define MAKEFUNCTION(t, s) (((t) & 0xf) << 4 | ((s) & 0xf)) - __le16 wIndex; - __le32 dwSymbolicAddress; -#define MAKESA(a, b, c, d) \ +#define E4_KERNELREADY 0x0 +#define E4_MODEMREADY 0x1 + +#define E1_MAKEFUNCTION(t, s) (((t) & 0xf) << 4 | ((s) & 0xf)) +#define E4_MAKEFUNCTION(t, st, s) (((t) & 0xf) << 8 | ((st) & 0xf) << 4 | ((s) & 0xf)) + +#define E1_MAKESA(a, b, c, d) \ (((c) & 0xff) << 24 | \ ((d) & 0xff) << 16 | \ ((a) & 0xff) << 8 | \ ((b) & 0xff)) -#define GETSA1(a) ((a >> 8) & 0xff) -#define GETSA2(a) (a & 0xff) -#define GETSA3(a) ((a >> 24) & 0xff) -#define GETSA4(a) ((a >> 16) & 0xff) - -#define SA_CNTL MAKESA('C', 'N', 'T', 'L') -#define SA_DIAG MAKESA('D', 'I', 'A', 'G') -#define SA_INFO MAKESA('I', 'N', 'F', 'O') -#define SA_OPTN MAKESA('O', 'P', 'T', 'N') -#define SA_RATE MAKESA('R', 'A', 'T', 'E') -#define SA_STAT MAKESA('S', 'T', 'A', 'T') + +#define E1_GETSA1(a) ((a >> 8) & 0xff) +#define E1_GETSA2(a) (a & 0xff) +#define E1_GETSA3(a) ((a >> 24) & 0xff) +#define E1_GETSA4(a) ((a >> 16) & 0xff) + +#define E1_SA_CNTL E1_MAKESA('C', 'N', 'T', 'L') +#define E1_SA_DIAG E1_MAKESA('D', 'I', 'A', 'G') +#define E1_SA_INFO E1_MAKESA('I', 'N', 'F', 'O') +#define E1_SA_OPTN E1_MAKESA('O', 'P', 'T', 'N') +#define E1_SA_RATE E1_MAKESA('R', 'A', 'T', 'E') +#define E1_SA_STAT E1_MAKESA('S', 'T', 'A', 'T') + +#define E4_SA_CNTL 1 +#define E4_SA_STAT 2 +#define E4_SA_INFO 3 +#define E4_SA_TEST 4 +#define E4_SA_OPTN 5 +#define E4_SA_RATE 6 +#define E4_SA_DIAG 7 +#define E4_SA_CNFG 8 + +/* structures representing a CMV (Configuration and Management Variable) */ +struct cmv_e1 { + __le16 wPreamble; + __u8 bDirection; + __u8 bFunction; + __le16 wIndex; + __le32 dwSymbolicAddress; __le16 wOffsetAddress; __le32 dwData; } __attribute__ ((packed)); -#define CMV_SIZE 16 -/* structure representing swap information */ -struct swap_info { +struct cmv_e4 { + __be16 wGroup; + __be16 wFunction; + __be16 wOffset; + __be16 wAddress; + __be32 dwData [6]; +} __attribute__ ((packed)); + +/* structures representing swap information */ +struct swap_info_e1 { __u8 bSwapPageNo; __u8 bOvl; /* overlay */ } __attribute__ ((packed)); -/* structure representing interrupt data */ +struct swap_info_e4 { + __u8 bSwapPageNo; +} __attribute__ ((packed)); + +/* structures representing interrupt data */ +#define e1_bSwapPageNo u.e1.s1.swapinfo.bSwapPageNo +#define e1_bOvl u.e1.s1.swapinfo.bOvl +#define e4_bSwapPageNo u.e4.s1.swapinfo.bSwapPageNo + +#define INT_LOADSWAPPAGE 0x0001 +#define INT_INCOMINGCMV 0x0002 + +union intr_data_e1 { + struct { + struct swap_info_e1 swapinfo; + __le16 wDataSize; + } __attribute__ ((packed)) s1; + struct { + struct cmv_e1 cmv; + __le16 wDataSize; + } __attribute__ ((packed)) s2; +} __attribute__ ((packed)); + +union intr_data_e4 { + struct { + struct swap_info_e4 swapinfo; + __le16 wDataSize; + } __attribute__ ((packed)) s1; + struct { + struct cmv_e4 cmv; + __le16 wDataSize; + } __attribute__ ((packed)) s2; +} __attribute__ ((packed)); + struct intr_pkt { __u8 bType; __u8 bNotification; @@ -347,27 +493,18 @@ struct intr_pkt { __le16 wIndex; __le16 wLength; __le16 wInterrupt; -#define INT_LOADSWAPPAGE 0x0001 -#define INT_INCOMINGCMV 0x0002 union { - struct { - struct swap_info swapinfo; - __le16 wDataSize; - } __attribute__ ((packed)) s1; - - struct { - struct cmv cmv; - __le16 wDataSize; - } __attribute__ ((packed)) s2; - } __attribute__ ((packed)) u; -#define bSwapPageNo u.s1.swapinfo.bSwapPageNo -#define bOvl u.s1.swapinfo.bOvl + union intr_data_e1 e1; + union intr_data_e4 e4; + } u; } __attribute__ ((packed)); -#define INTR_PKT_SIZE 28 + +#define E1_INTR_PKT_SIZE 28 +#define E4_INTR_PKT_SIZE 64 static struct usb_driver uea_driver; static DEFINE_MUTEX(uea_mutex); -static const char *chip_name[] = {"ADI930", "Eagle I", "Eagle II", "Eagle III"}; +static const char *chip_name[] = {"ADI930", "Eagle I", "Eagle II", "Eagle III", "Eagle IV"}; static int modem_index; static unsigned int debug; @@ -519,6 +656,9 @@ static int uea_load_firmware(struct usb_device *usb, unsigned int ver) case EAGLE_III: fw_name = FW_DIR "eagleIII.fw"; break; + case EAGLE_IV: + fw_name = FW_DIR "eagleIV.fw"; + break; } ret = request_firmware_nowait(THIS_MODULE, 1, fw_name, &usb->dev, usb, uea_upload_pre_firmware); @@ -537,7 +677,7 @@ static int uea_load_firmware(struct usb_device *usb, unsigned int ver) /* * Make sure that the DSP code provided is safe to use. */ -static int check_dsp(u8 *dsp, unsigned int len) +static int check_dsp_e1(u8 *dsp, unsigned int len) { u8 pagecount, blockcount; u16 blocksize; @@ -588,6 +728,51 @@ static int check_dsp(u8 *dsp, unsigned int len) return 0; } +static int check_dsp_e4(u8 *dsp, int len) +{ + int i; + struct l1_code *p = (struct l1_code *) dsp; + unsigned int sum = p->code - dsp; + + if (len < sum) + return 1; + + if (strcmp("STRATIPHY ANEXA", p->string_header) != 0 && + strcmp("STRATIPHY ANEXB", p->string_header) != 0) + return 1; + + for (i = 0; i < E4_MAX_PAGE_NUMBER; i++) { + struct block_index *blockidx; + u8 blockno = p->page_number_to_block_index[i]; + if (blockno >= E4_NO_SWAPPAGE_HEADERS) + continue; + + do { + u64 l; + + if (blockno >= E4_NO_SWAPPAGE_HEADERS) + return 1; + + blockidx = &p->page_header[blockno++]; + if ((u8 *)(blockidx + 1) - dsp >= len) + return 1; + + if (le16_to_cpu(blockidx->PageNumber) != i) + return 1; + + l = E4_PAGE_BYTES(blockidx->PageSize); + sum += l; + l += le32_to_cpu(blockidx->PageOffset); + if (l > len) + return 1; + + /* zero is zero regardless endianes */ + } while (blockidx->NotLastBlock); + } + + return (sum == len) ? 0 : 1; +} + /* * send data to the idma pipe * */ @@ -624,7 +809,12 @@ static int request_dsp(struct uea_softc *sc) int ret; char *dsp_name; - if (UEA_CHIP_VERSION(sc) == ADI930) { + if (UEA_CHIP_VERSION(sc) == EAGLE_IV) { + if (IS_ISDN(sc->usb_dev)) + dsp_name = FW_DIR "DSP4i.bin"; + else + dsp_name = FW_DIR "DSP4p.bin"; + } else if (UEA_CHIP_VERSION(sc) == ADI930) { if (IS_ISDN(sc->usb_dev)) dsp_name = FW_DIR "DSP9i.bin"; else @@ -640,11 +830,16 @@ static int request_dsp(struct uea_softc *sc) if (ret < 0) { uea_err(INS_TO_USBDEV(sc), "requesting firmware %s failed with error %d\n", - dsp_name, ret); + dsp_name, ret); return ret; } - if (check_dsp(sc->dsp_firm->data, sc->dsp_firm->size)) { + if (UEA_CHIP_VERSION(sc) == EAGLE_IV) + ret = check_dsp_e4(sc->dsp_firm->data, sc->dsp_firm->size); + else + ret = check_dsp_e1(sc->dsp_firm->data, sc->dsp_firm->size); + + if (ret) { uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n", dsp_name); release_firmware(sc->dsp_firm); @@ -658,12 +853,12 @@ static int request_dsp(struct uea_softc *sc) /* * The uea_load_page() function must be called within a process context */ -static void uea_load_page(struct work_struct *work) +static void uea_load_page_e1(struct work_struct *work) { struct uea_softc *sc = container_of(work, struct uea_softc, task); u16 pageno = sc->pageno; u16 ovl = sc->ovl; - struct block_info bi; + struct block_info_e1 bi; u8 *p; u8 pagecount, blockcount; @@ -716,7 +911,7 @@ static void uea_load_page(struct work_struct *work) bi.wLast = cpu_to_le16((i == blockcount - 1) ? 1 : 0); /* send block info through the IDMA pipe */ - if (uea_idma_write(sc, &bi, BLOCK_INFO_SIZE)) + if (uea_idma_write(sc, &bi, E1_BLOCK_INFO_SIZE)) goto bad2; /* send block data through the IDMA pipe */ @@ -735,6 +930,103 @@ bad1: uea_err(INS_TO_USBDEV(sc), "invalid DSP page %u requested\n", pageno); } +static void __uea_load_page_e4(struct uea_softc *sc, u8 pageno, int boot) +{ + struct block_info_e4 bi; + struct block_index *blockidx; + struct l1_code *p = (struct l1_code *) sc->dsp_firm->data; + u8 blockno = p->page_number_to_block_index[pageno]; + + bi.wHdr = cpu_to_be16(UEA_BIHDR); + bi.bBootPage = boot; + bi.bPageNumber = pageno; + bi.wReserved = cpu_to_be16(UEA_RESERVED); + + do { + u8 *blockoffset; + unsigned int blocksize; + + blockidx = &p->page_header[blockno]; + blocksize = E4_PAGE_BYTES(blockidx->PageSize); + blockoffset = sc->dsp_firm->data + le32_to_cpu(blockidx->PageOffset); + + bi.dwSize = cpu_to_be32(blocksize); + bi.dwAddress = swab32(blockidx->PageAddress); + + uea_dbg(INS_TO_USBDEV(sc), + "sending block %u for DSP page %u size %u adress %x\n", + blockno, pageno, blocksize, le32_to_cpu(blockidx->PageAddress)); + + /* send block info through the IDMA pipe */ + if (uea_idma_write(sc, &bi, E4_BLOCK_INFO_SIZE)) + goto bad; + + /* send block data through the IDMA pipe */ + if (uea_idma_write(sc, blockoffset, blocksize)) + goto bad; + + blockno++; + } while (blockidx->NotLastBlock); + + return; + +bad: + uea_err(INS_TO_USBDEV(sc), "sending DSP block %u failed\n", blockno); + return; +} + +static void uea_load_page_e4(struct work_struct *work) +{ + struct uea_softc *sc = container_of(work, struct uea_softc, task); + u8 pageno = sc->pageno; + int i; + struct block_info_e4 bi; + struct l1_code *p; + + uea_dbg(INS_TO_USBDEV(sc), "sending DSP page %u\n", pageno); + + /* reload firmware when reboot start and it's loaded already */ + if (pageno == 0 && sc->dsp_firm) { + release_firmware(sc->dsp_firm); + sc->dsp_firm = NULL; + } + + if (sc->dsp_firm == NULL && request_dsp(sc) < 0) + return; + + p = (struct l1_code *) sc->dsp_firm->data; + if (pageno >= p->page_header[0].PageNumber) { + uea_err(INS_TO_USBDEV(sc), "invalid DSP page %u requested\n", pageno); + return; + } + + if (pageno != 0) { + __uea_load_page_e4(sc, pageno, 0); + return; + } + + uea_dbg(INS_TO_USBDEV(sc), + "sending Main DSP page %u\n", p->page_header[0].PageNumber); + + for (i = 0; i < le16_to_cpu(p->page_header[0].PageNumber); i++) { + if (E4_IS_BOOT_PAGE(p->page_header[i].PageSize)) + __uea_load_page_e4(sc, i, 1); + } + + uea_dbg(INS_TO_USBDEV(sc),"sending start bi\n"); + + bi.wHdr = cpu_to_be16(UEA_BIHDR); + bi.bBootPage = 0; + bi.bPageNumber = 0xff; + bi.wReserved = cpu_to_be16(UEA_RESERVED); + bi.dwSize = cpu_to_be32(E4_PAGE_BYTES(p->page_header[0].PageSize)); + bi.dwAddress = swab32(p->page_header[0].PageAddress); + + /* send block info through the IDMA pipe */ + if (uea_idma_write(sc, &bi, E4_BLOCK_INFO_SIZE)) + uea_err(INS_TO_USBDEV(sc), "sending DSP start bi failed\n"); +} + static inline void wake_up_cmv_ack(struct uea_softc *sc) { BUG_ON(sc->cmv_ack); @@ -792,33 +1084,68 @@ static int uea_request(struct uea_softc *sc, return 0; } -static int uea_cmv(struct uea_softc *sc, +static int uea_cmv_e1(struct uea_softc *sc, u8 function, u32 address, u16 offset, u32 data) { - struct cmv cmv; + struct cmv_e1 cmv; int ret; uea_enters(INS_TO_USBDEV(sc)); uea_vdbg(INS_TO_USBDEV(sc), "Function : %d-%d, Address : %c%c%c%c, " "offset : 0x%04x, data : 0x%08x\n", - FUNCTION_TYPE(function), FUNCTION_SUBTYPE(function), - GETSA1(address), GETSA2(address), GETSA3(address), - GETSA4(address), offset, data); + E1_FUNCTION_TYPE(function), E1_FUNCTION_SUBTYPE(function), + E1_GETSA1(address), E1_GETSA2(address), E1_GETSA3(address), + E1_GETSA4(address), offset, data); + /* we send a request, but we expect a reply */ - sc->cmv_function = function | 0x2; - sc->cmv_idx++; - sc->cmv_address = address; - sc->cmv_offset = offset; + sc->cmv_dsc.e1.function = function | 0x2; + sc->cmv_dsc.e1.idx++; + sc->cmv_dsc.e1.address = address; + sc->cmv_dsc.e1.offset = offset; - cmv.wPreamble = cpu_to_le16(PREAMBLE); - cmv.bDirection = HOSTTOMODEM; + cmv.wPreamble = cpu_to_le16(E1_PREAMBLE); + cmv.bDirection = E1_HOSTTOMODEM; cmv.bFunction = function; - cmv.wIndex = cpu_to_le16(sc->cmv_idx); + cmv.wIndex = cpu_to_le16(sc->cmv_dsc.e1.idx); put_unaligned(cpu_to_le32(address), &cmv.dwSymbolicAddress); cmv.wOffsetAddress = cpu_to_le16(offset); put_unaligned(cpu_to_le32(data >> 16 | data << 16), &cmv.dwData); - ret = uea_request(sc, UEA_SET_BLOCK, UEA_MPTX_START, CMV_SIZE, &cmv); + ret = uea_request(sc, UEA_E1_SET_BLOCK, UEA_MPTX_START, sizeof(cmv), &cmv); + if (ret < 0) + return ret; + ret = wait_cmv_ack(sc); + uea_leaves(INS_TO_USBDEV(sc)); + return ret; +} + +static int uea_cmv_e4(struct uea_softc *sc, + u16 function, u16 group, u16 address, u16 offset, u32 data) +{ + struct cmv_e4 cmv; + int ret; + + uea_enters(INS_TO_USBDEV(sc)); + memset(&cmv, 0, sizeof(cmv)); + + uea_vdbg(INS_TO_USBDEV(sc), "Function : %d-%d, Group : 0x%04x, " + "Address : 0x%04x, offset : 0x%04x, data : 0x%08x\n", + E4_FUNCTION_TYPE(function), E4_FUNCTION_SUBTYPE(function), + group, address, offset, data); + + /* we send a request, but we expect a reply */ + sc->cmv_dsc.e4.function = function | (0x1 << 4); + sc->cmv_dsc.e4.offset = offset; + sc->cmv_dsc.e4.address = address; + sc->cmv_dsc.e4.group = group; + + cmv.wFunction = cpu_to_be16(function); + cmv.wGroup = cpu_to_be16(group); + cmv.wAddress = cpu_to_be16(address); + cmv.wOffset = cpu_to_be16(offset); + cmv.dwData[0] = cpu_to_be32(data); + + ret = uea_request(sc, UEA_E4_SET_BLOCK, UEA_MPTX_START, sizeof(cmv), &cmv); if (ret < 0) return ret; ret = wait_cmv_ack(sc); @@ -826,10 +1153,10 @@ static int uea_cmv(struct uea_softc *sc, return ret; } -static inline int uea_read_cmv(struct uea_softc *sc, +static inline int uea_read_cmv_e1(struct uea_softc *sc, u32 address, u16 offset, u32 *data) { - int ret = uea_cmv(sc, MAKEFUNCTION(MEMACCESS, REQUESTREAD), + int ret = uea_cmv_e1(sc, E1_MAKEFUNCTION(E1_MEMACCESS, E1_REQUESTREAD), address, offset, 0); if (ret < 0) uea_err(INS_TO_USBDEV(sc), @@ -840,10 +1167,27 @@ static inline int uea_read_cmv(struct uea_softc *sc, return ret; } -static inline int uea_write_cmv(struct uea_softc *sc, +static inline int uea_read_cmv_e4(struct uea_softc *sc, + u8 size, u16 group, u16 address, u16 offset, u32 *data) +{ + int ret = uea_cmv_e4(sc, E4_MAKEFUNCTION(E4_MEMACCESS, E4_REQUESTREAD, size), + group, address, offset, 0); + if (ret < 0) + uea_err(INS_TO_USBDEV(sc), + "reading cmv failed with error %d\n", ret); + else { + *data = sc->data; + /* size is in 16-bit word quantities */ + if (size > 2) + *(data + 1) = sc->data1; + } + return ret; +} + +static inline int uea_write_cmv_e1(struct uea_softc *sc, u32 address, u16 offset, u32 data) { - int ret = uea_cmv(sc, MAKEFUNCTION(MEMACCESS, REQUESTWRITE), + int ret = uea_cmv_e1(sc, E1_MAKEFUNCTION(E1_MEMACCESS, E1_REQUESTWRITE), address, offset, data); if (ret < 0) uea_err(INS_TO_USBDEV(sc), @@ -852,12 +1196,48 @@ static inline int uea_write_cmv(struct uea_softc *sc, return ret; } +static inline int uea_write_cmv_e4(struct uea_softc *sc, + u8 size, u16 group, u16 address, u16 offset, u32 data) +{ + int ret = uea_cmv_e4(sc, E4_MAKEFUNCTION(E4_MEMACCESS, E4_REQUESTWRITE, size), + group, address, offset, data); + if (ret < 0) + uea_err(INS_TO_USBDEV(sc), + "writing cmv failed with error %d\n", ret); + + return ret; +} + +static void uea_set_bulk_timeout(struct uea_softc *sc, u32 dsrate) +{ + int ret; + u16 timeout; + + /* in bulk mode the modem have problem with high rate + * changing internal timing could improve things, but the + * value is misterious. + * ADI930 don't support it (-EPIPE error). + */ + + if (UEA_CHIP_VERSION(sc) == ADI930 || + use_iso[sc->modem_index] > 0 || + sc->stats.phy.dsrate == dsrate) + return; + + /* Original timming (1Mbit/s) from ADI (used in windows driver) */ + timeout = (dsrate <= 1024*1024) ? 0 : 1; + ret = uea_request(sc, UEA_SET_TIMEOUT, timeout, 0, NULL); + uea_info(INS_TO_USBDEV(sc), "setting new timeout %d%s\n", + timeout, ret < 0 ? " failed" : ""); + +} + /* * Monitor the modem and update the stat * return 0 if everything is ok * return < 0 if an error occurs (-EAGAIN reboot needed) */ -static int uea_stat(struct uea_softc *sc) +static int uea_stat_e1(struct uea_softc *sc) { u32 data; int ret; @@ -865,7 +1245,7 @@ static int uea_stat(struct uea_softc *sc) uea_enters(INS_TO_USBDEV(sc)); data = sc->stats.phy.state; - ret = uea_read_cmv(sc, SA_STAT, 0, &sc->stats.phy.state); + ret = uea_read_cmv_e1(sc, E1_SA_STAT, 0, &sc->stats.phy.state); if (ret < 0) return ret; @@ -885,7 +1265,7 @@ static int uea_stat(struct uea_softc *sc) case 3: /* fail ... */ uea_info(INS_TO_USBDEV(sc), "modem synchronization failed" - " (may be try other cmv/dsp)\n"); + " (may be try other cmv/dsp)\n"); return -EAGAIN; case 4 ... 6: /* test state */ @@ -923,7 +1303,7 @@ static int uea_stat(struct uea_softc *sc) /* wake up processes waiting for synchronization */ wake_up(&sc->sync_q); - ret = uea_read_cmv(sc, SA_DIAG, 2, &sc->stats.phy.flags); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 2, &sc->stats.phy.flags); if (ret < 0) return ret; sc->stats.phy.mflags |= sc->stats.phy.flags; @@ -937,105 +1317,223 @@ static int uea_stat(struct uea_softc *sc) return 0; } - ret = uea_read_cmv(sc, SA_RATE, 0, &data); + ret = uea_read_cmv_e1(sc, E1_SA_RATE, 0, &data); if (ret < 0) return ret; - /* in bulk mode the modem have problem with high rate - * changing internal timing could improve things, but the - * value is misterious. - * ADI930 don't support it (-EPIPE error). - */ - if (UEA_CHIP_VERSION(sc) != ADI930 - && !use_iso[sc->modem_index] - && sc->stats.phy.dsrate != (data >> 16) * 32) { - /* Original timming from ADI(used in windows driver) - * 0x20ffff>>16 * 32 = 32 * 32 = 1Mbits - */ - u16 timeout = (data <= 0x20ffff) ? 0 : 1; - ret = uea_request(sc, UEA_SET_TIMEOUT, timeout, 0, NULL); - uea_info(INS_TO_USBDEV(sc), - "setting new timeout %d%s\n", timeout, - ret < 0?" failed":""); - } + uea_set_bulk_timeout(sc, (data >> 16) * 32); sc->stats.phy.dsrate = (data >> 16) * 32; sc->stats.phy.usrate = (data & 0xffff) * 32; UPDATE_ATM_STAT(link_rate, sc->stats.phy.dsrate * 1000 / 424); - ret = uea_read_cmv(sc, SA_DIAG, 23, &data); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 23, &data); if (ret < 0) return ret; sc->stats.phy.dsattenuation = (data & 0xff) / 2; - ret = uea_read_cmv(sc, SA_DIAG, 47, &data); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 47, &data); if (ret < 0) return ret; sc->stats.phy.usattenuation = (data & 0xff) / 2; - ret = uea_read_cmv(sc, SA_DIAG, 25, &sc->stats.phy.dsmargin); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 25, &sc->stats.phy.dsmargin); if (ret < 0) return ret; - ret = uea_read_cmv(sc, SA_DIAG, 49, &sc->stats.phy.usmargin); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 49, &sc->stats.phy.usmargin); if (ret < 0) return ret; - ret = uea_read_cmv(sc, SA_DIAG, 51, &sc->stats.phy.rxflow); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 51, &sc->stats.phy.rxflow); if (ret < 0) return ret; - ret = uea_read_cmv(sc, SA_DIAG, 52, &sc->stats.phy.txflow); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 52, &sc->stats.phy.txflow); if (ret < 0) return ret; - ret = uea_read_cmv(sc, SA_DIAG, 54, &sc->stats.phy.dsunc); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 54, &sc->stats.phy.dsunc); if (ret < 0) return ret; /* only for atu-c */ - ret = uea_read_cmv(sc, SA_DIAG, 58, &sc->stats.phy.usunc); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 58, &sc->stats.phy.usunc); if (ret < 0) return ret; - ret = uea_read_cmv(sc, SA_DIAG, 53, &sc->stats.phy.dscorr); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 53, &sc->stats.phy.dscorr); if (ret < 0) return ret; /* only for atu-c */ - ret = uea_read_cmv(sc, SA_DIAG, 57, &sc->stats.phy.uscorr); + ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 57, &sc->stats.phy.uscorr); if (ret < 0) return ret; - ret = uea_read_cmv(sc, SA_INFO, 8, &sc->stats.phy.vidco); + ret = uea_read_cmv_e1(sc, E1_SA_INFO, 8, &sc->stats.phy.vidco); if (ret < 0) return ret; - ret = uea_read_cmv(sc, SA_INFO, 13, &sc->stats.phy.vidcpe); + ret = uea_read_cmv_e1(sc, E1_SA_INFO, 13, &sc->stats.phy.vidcpe); if (ret < 0) return ret; return 0; } -static int request_cmvs(struct uea_softc *sc, - struct uea_cmvs **cmvs, const struct firmware **fw) +static int uea_stat_e4(struct uea_softc *sc) { - int ret, size; - u8 *data; + u32 data; + u32 tmp_arr[2]; + int ret; + + uea_enters(INS_TO_USBDEV(sc)); + data = sc->stats.phy.state; + + /* XXX only need to be done before operationnal... */ + ret = uea_read_cmv_e4(sc, 1, E4_SA_STAT, 0, 0, &sc->stats.phy.state); + if (ret < 0) + return ret; + + switch (sc->stats.phy.state) { + case 0x0: /* not yet synchronized */ + case 0x1: + case 0x3: + case 0x4: + uea_dbg(INS_TO_USBDEV(sc), "modem not yet synchronized\n"); + return 0; + case 0x5: /* initialization */ + case 0x6: + case 0x9: + case 0xa: + uea_dbg(INS_TO_USBDEV(sc), "modem initializing\n"); + return 0; + case 0x2: /* fail ... */ + uea_info(INS_TO_USBDEV(sc), "modem synchronization failed" + " (may be try other cmv/dsp)\n"); + return -EAGAIN; + case 0x7: /* operational */ + break; + default: + uea_warn(INS_TO_USBDEV(sc), "unknown state: %x\n", sc->stats.phy.state); + return 0; + } + + if (data != 7) { + uea_request(sc, UEA_SET_MODE, UEA_LOOPBACK_OFF, 0, NULL); + uea_info(INS_TO_USBDEV(sc), "modem operational\n"); + + /* release the dsp firmware as it is not needed until + * the next failure + */ + if (sc->dsp_firm) { + release_firmware(sc->dsp_firm); + sc->dsp_firm = NULL; + } + } + + /* always update it as atm layer could not be init when we switch to + * operational state + */ + UPDATE_ATM_STAT(signal, ATM_PHY_SIG_FOUND); + + /* wake up processes waiting for synchronization */ + wake_up(&sc->sync_q); + + /* TODO improve this state machine : + * we need some CMV info : what they do and their unit + * we should find the equivalent of eagle3- CMV + */ + /* check flags */ + ret = uea_read_cmv_e4(sc, 1, E4_SA_DIAG, 0, 0, &sc->stats.phy.flags); + if (ret < 0) + return ret; + sc->stats.phy.mflags |= sc->stats.phy.flags; + + /* in case of a flags ( for example delineation LOSS (& 0x10)), + * we check the status again in order to detect the failure earlier + */ + if (sc->stats.phy.flags) { + uea_dbg(INS_TO_USBDEV(sc), "Stat flag = 0x%x\n", + sc->stats.phy.flags); + if (sc->stats.phy.flags & 1) //delineation LOSS + return -EAGAIN; + if (sc->stats.phy.flags & 0x4000) //Reset Flag + return -EAGAIN; + return 0; + } + + /* rate data may be in upper or lower half of 64 bit word, strange */ + ret = uea_read_cmv_e4(sc, 4, E4_SA_RATE, 0, 0, tmp_arr); + if (ret < 0) + return ret; + data = (tmp_arr[0]) ? tmp_arr[0] : tmp_arr[1]; + sc->stats.phy.usrate = data / 1000; + + ret = uea_read_cmv_e4(sc, 4, E4_SA_RATE, 1, 0, tmp_arr); + if (ret < 0) + return ret; + data = (tmp_arr[0]) ? tmp_arr[0] : tmp_arr[1]; + uea_set_bulk_timeout(sc, data / 1000); + sc->stats.phy.dsrate = data / 1000; + UPDATE_ATM_STAT(link_rate, sc->stats.phy.dsrate * 1000 / 424); + + ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 68, 1, &data); + if (ret < 0) + return ret; + sc->stats.phy.dsattenuation = data / 10; + + ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 69, 1, &data); + if (ret < 0) + return ret; + sc->stats.phy.usattenuation = data / 10; + + ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 68, 3, &data); + if (ret < 0) + return ret; + sc->stats.phy.dsmargin = data / 2; + + ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 69, 3, &data); + if (ret < 0) + return ret; + sc->stats.phy.usmargin = data / 10; + + return 0; +} + +static void cmvs_file_name(struct uea_softc *sc, char *const cmv_name, int ver) +{ + char file_arr[] = "CMVxy.bin"; char *file; - char cmv_name[FIRMWARE_NAME_MAX]; /* 30 bytes stack variable */ + /* set proper name corresponding modem version and line type */ if (cmv_file[sc->modem_index] == NULL) { if (UEA_CHIP_VERSION(sc) == ADI930) - file = (IS_ISDN(sc->usb_dev)) ? "CMV9i.bin" : "CMV9p.bin"; + file_arr[3] = '9'; + else if (UEA_CHIP_VERSION(sc) == EAGLE_IV) + file_arr[3] = '4'; else - file = (IS_ISDN(sc->usb_dev)) ? "CMVei.bin" : "CMVep.bin"; + file_arr[3] = 'e'; + + file_arr[4] = IS_ISDN(sc->usb_dev) ? 'i' : 'p'; + file = file_arr; } else file = cmv_file[sc->modem_index]; strcpy(cmv_name, FW_DIR); - strlcat(cmv_name, file, sizeof(cmv_name)); + strlcat(cmv_name, file, FIRMWARE_NAME_MAX); + if (ver == 2) + strlcat(cmv_name, ".v2", FIRMWARE_NAME_MAX); +} + +static int request_cmvs_old(struct uea_softc *sc, + void **cmvs, const struct firmware **fw) +{ + int ret, size; + u8 *data; + char cmv_name[FIRMWARE_NAME_MAX]; /* 30 bytes stack variable */ + cmvs_file_name(sc, cmv_name, 1); ret = request_firmware(fw, cmv_name, &sc->usb_dev->dev); if (ret < 0) { uea_err(INS_TO_USBDEV(sc), @@ -1045,16 +1543,197 @@ static int request_cmvs(struct uea_softc *sc, } data = (u8 *) (*fw)->data; - size = *data * sizeof(struct uea_cmvs) + 1; - if (size != (*fw)->size) { - uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n", - cmv_name); - release_firmware(*fw); - return -EILSEQ; + size = (*fw)->size; + if (size < 1) + goto err_fw_corrupted; + + if (size != *data * sizeof(struct uea_cmvs_v1) + 1) + goto err_fw_corrupted; + + *cmvs = (void *)(data + 1); + return *data; + +err_fw_corrupted: + uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n", cmv_name); + release_firmware(*fw); + return -EILSEQ; +} + +static int request_cmvs(struct uea_softc *sc, + void **cmvs, const struct firmware **fw, int *ver) +{ + int ret, size; + u32 crc; + u8 *data; + char cmv_name[FIRMWARE_NAME_MAX]; /* 30 bytes stack variable */ + + cmvs_file_name(sc, cmv_name, 2); + ret = request_firmware(fw, cmv_name, &sc->usb_dev->dev); + if (ret < 0) { + /* if caller can handle old version, try to provide it */ + if (*ver == 1) { + uea_warn(INS_TO_USBDEV(sc), "requesting firmware %s failed, " + "try to get older cmvs\n", cmv_name); + return request_cmvs_old(sc, cmvs, fw); + } + uea_err(INS_TO_USBDEV(sc), + "requesting firmware %s failed with error %d\n", + cmv_name, ret); + return ret; + } + + size = (*fw)->size; + data = (u8 *) (*fw)->data; + if (size < 4 || strncmp(data, "cmv2", 4) != 0) { + if (*ver == 1) { + uea_warn(INS_TO_USBDEV(sc), "firmware %s is corrupted, " + "try to get older cmvs\n", cmv_name); + release_firmware(*fw); + return request_cmvs_old(sc, cmvs, fw); + } + goto err_fw_corrupted; } - *cmvs = (struct uea_cmvs *)(data + 1); + *ver = 2; + + data += 4; + size -= 4; + if (size < 5) + goto err_fw_corrupted; + + crc = FW_GET_LONG(data); + data += 4; + size -= 4; + if (crc32_be(0, data, size) != crc) + goto err_fw_corrupted; + + if (size != *data * sizeof(struct uea_cmvs_v2) + 1) + goto err_fw_corrupted; + + *cmvs = (void *) (data + 1); return *data; + +err_fw_corrupted: + uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n", cmv_name); + release_firmware(*fw); + return -EILSEQ; +} + +static int uea_send_cmvs_e1(struct uea_softc *sc) +{ + int i, ret, len; + void *cmvs_ptr; + const struct firmware *cmvs_fw; + int ver = 1; // we can handle v1 cmv firmware version; + + /* Enter in R-IDLE (cmv) until instructed otherwise */ + ret = uea_write_cmv_e1(sc, E1_SA_CNTL, 0, 1); + if (ret < 0) + return ret; + + /* Dump firmware version */ + ret = uea_read_cmv_e1(sc, E1_SA_INFO, 10, &sc->stats.phy.firmid); + if (ret < 0) + return ret; + uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n", + sc->stats.phy.firmid); + + /* get options */ + ret = len = request_cmvs(sc, &cmvs_ptr, &cmvs_fw, &ver); + if (ret < 0) + return ret; + + /* send options */ + if (ver == 1) { + struct uea_cmvs_v1 *cmvs_v1 = cmvs_ptr; + + uea_warn(INS_TO_USBDEV(sc), "use deprecated cmvs version, " + "please update your firmware\n"); + + for (i = 0; i < len; i++) { + ret = uea_write_cmv_e1(sc, FW_GET_LONG(&cmvs_v1[i].address), + FW_GET_WORD(&cmvs_v1[i].offset), + FW_GET_LONG(&cmvs_v1[i].data)); + if (ret < 0) + goto out; + } + } else if (ver == 2) { + struct uea_cmvs_v2 *cmvs_v2 = cmvs_ptr; + + for (i = 0; i < len; i++) { + ret = uea_write_cmv_e1(sc, FW_GET_LONG(&cmvs_v2[i].address), + (u16) FW_GET_LONG(&cmvs_v2[i].offset), + FW_GET_LONG(&cmvs_v2[i].data)); + if (ret < 0) + goto out; + } + } else { + /* This realy should not happen */ + uea_err(INS_TO_USBDEV(sc), "bad cmvs version %d\n", ver); + goto out; + } + + /* Enter in R-ACT-REQ */ + ret = uea_write_cmv_e1(sc, E1_SA_CNTL, 0, 2); + uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n"); + uea_info(INS_TO_USBDEV(sc), "modem started, waiting synchronization...\n"); +out: + release_firmware(cmvs_fw); + return ret; +} + +static int uea_send_cmvs_e4(struct uea_softc *sc) +{ + int i, ret, len; + void *cmvs_ptr; + const struct firmware *cmvs_fw; + int ver = 2; // we can only handle v2 cmv firmware version; + + /* Enter in R-IDLE (cmv) until instructed otherwise */ + ret = uea_write_cmv_e4(sc, 1, E4_SA_CNTL, 0, 0, 1); + if (ret < 0) + return ret; + + /* Dump firmware version */ + /* XXX don't read the 3th byte as it is always 6 */ + ret = uea_read_cmv_e4(sc, 2, E4_SA_INFO, 55, 0, &sc->stats.phy.firmid); + if (ret < 0) + return ret; + uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n", + sc->stats.phy.firmid); + + + /* get options */ + ret = len = request_cmvs(sc, &cmvs_ptr, &cmvs_fw, &ver); + if (ret < 0) + return ret; + + /* send options */ + if (ver == 2) { + struct uea_cmvs_v2 *cmvs_v2 = cmvs_ptr; + + for (i = 0; i < len; i++) { + ret = uea_write_cmv_e4(sc, 1, + FW_GET_LONG(&cmvs_v2[i].group), + FW_GET_LONG(&cmvs_v2[i].address), + FW_GET_LONG(&cmvs_v2[i].offset), + FW_GET_LONG(&cmvs_v2[i].data)); + if (ret < 0) + goto out; + } + } else { + /* This realy should not happen */ + uea_err(INS_TO_USBDEV(sc), "bad cmvs version %d\n", ver); + goto out; + } + + /* Enter in R-ACT-REQ */ + ret = uea_write_cmv_e4(sc, 1, E4_SA_CNTL, 0, 0, 2); + uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n"); + uea_info(INS_TO_USBDEV(sc), "modem started, waiting synchronization...\n"); +out: + release_firmware(cmvs_fw); + return ret; } /* Start boot post firmware modem: @@ -1066,9 +1745,7 @@ static int request_cmvs(struct uea_softc *sc, static int uea_start_reset(struct uea_softc *sc) { u16 zero = 0; /* ;-) */ - int i, len, ret; - struct uea_cmvs *cmvs; - const struct firmware *cmvs_fw; + int ret; uea_enters(INS_TO_USBDEV(sc)); uea_info(INS_TO_USBDEV(sc), "(re)booting started\n"); @@ -1098,13 +1775,20 @@ static int uea_start_reset(struct uea_softc *sc) /* leave reset mode */ uea_request(sc, UEA_SET_MODE, UEA_END_RESET, 0, NULL); - /* clear tx and rx mailboxes */ - uea_request(sc, UEA_SET_2183_DATA, UEA_MPTX_MAILBOX, 2, &zero); - uea_request(sc, UEA_SET_2183_DATA, UEA_MPRX_MAILBOX, 2, &zero); - uea_request(sc, UEA_SET_2183_DATA, UEA_SWAP_MAILBOX, 2, &zero); + if (UEA_CHIP_VERSION(sc) != EAGLE_IV) { + /* clear tx and rx mailboxes */ + uea_request(sc, UEA_SET_2183_DATA, UEA_MPTX_MAILBOX, 2, &zero); + uea_request(sc, UEA_SET_2183_DATA, UEA_MPRX_MAILBOX, 2, &zero); + uea_request(sc, UEA_SET_2183_DATA, UEA_SWAP_MAILBOX, 2, &zero); + } msleep(1000); - sc->cmv_function = MAKEFUNCTION(ADSLDIRECTIVE, MODEMREADY); + + if (UEA_CHIP_VERSION(sc) == EAGLE_IV) + sc->cmv_dsc.e4.function = E4_MAKEFUNCTION(E4_ADSLDIRECTIVE, E4_MODEMREADY, 1); + else + sc->cmv_dsc.e1.function = E1_MAKEFUNCTION(E1_ADSLDIRECTIVE, E1_MODEMREADY); + /* demask interrupt */ sc->booting = 0; @@ -1120,38 +1804,10 @@ static int uea_start_reset(struct uea_softc *sc) uea_vdbg(INS_TO_USBDEV(sc), "Ready CMV received\n"); - /* Enter in R-IDLE (cmv) until instructed otherwise */ - ret = uea_write_cmv(sc, SA_CNTL, 0, 1); - if (ret < 0) - return ret; - - /* Dump firmware version */ - ret = uea_read_cmv(sc, SA_INFO, 10, &sc->stats.phy.firmid); - if (ret < 0) - return ret; - uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n", - sc->stats.phy.firmid); - - /* get options */ - ret = len = request_cmvs(sc, &cmvs, &cmvs_fw); + ret = sc->send_cmvs(sc); if (ret < 0) return ret; - /* send options */ - for (i = 0; i < len; i++) { - ret = uea_write_cmv(sc, FW_GET_LONG(&cmvs[i].address), - FW_GET_WORD(&cmvs[i].offset), - FW_GET_LONG(&cmvs[i].data)); - if (ret < 0) - goto out; - } - /* Enter in R-ACT-REQ */ - ret = uea_write_cmv(sc, SA_CNTL, 0, 2); - uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n"); - uea_info(INS_TO_USBDEV(sc), "Modem started, " - "waiting synchronization\n"); -out: - release_firmware(cmvs_fw); sc->reset = 0; uea_leaves(INS_TO_USBDEV(sc)); return ret; @@ -1174,7 +1830,7 @@ static int uea_kthread(void *data) if (ret < 0 || sc->reset) ret = uea_start_reset(sc); if (!ret) - ret = uea_stat(sc); + ret = sc->stat(sc); if (ret != -EAGAIN) msleep_interruptible(1000); if (try_to_freeze()) @@ -1234,7 +1890,6 @@ static int load_XILINX_firmware(struct uea_softc *sc) if (ret < 0) uea_err(sc->usb_dev, "elsa de-assert failed with error %d\n", ret); - err1: release_firmware(fw_entry); err0: @@ -1243,40 +1898,41 @@ err0: } /* The modem send us an ack. First with check if it right */ -static void uea_dispatch_cmv(struct uea_softc *sc, struct cmv* cmv) +static void uea_dispatch_cmv_e1(struct uea_softc *sc, struct intr_pkt *intr) { + struct cmv_dsc_e1 *dsc = &sc->cmv_dsc.e1; + struct cmv_e1 *cmv = &intr->u.e1.s2.cmv; + uea_enters(INS_TO_USBDEV(sc)); - if (le16_to_cpu(cmv->wPreamble) != PREAMBLE) + if (le16_to_cpu(cmv->wPreamble) != E1_PREAMBLE) goto bad1; - if (cmv->bDirection != MODEMTOHOST) + if (cmv->bDirection != E1_MODEMTOHOST) goto bad1; /* FIXME : ADI930 reply wrong preambule (func = 2, sub = 2) to * the first MEMACESS cmv. Ignore it... */ - if (cmv->bFunction != sc->cmv_function) { + if (cmv->bFunction != dsc->function) { if (UEA_CHIP_VERSION(sc) == ADI930 - && cmv->bFunction == MAKEFUNCTION(2, 2)) { - cmv->wIndex = cpu_to_le16(sc->cmv_idx); - put_unaligned(cpu_to_le32(sc->cmv_address), &cmv->dwSymbolicAddress); - cmv->wOffsetAddress = cpu_to_le16(sc->cmv_offset); - } - else + && cmv->bFunction == E1_MAKEFUNCTION(2, 2)) { + cmv->wIndex = cpu_to_le16(dsc->idx); + put_unaligned(cpu_to_le32(dsc->address), &cmv->dwSymbolicAddress); + cmv->wOffsetAddress = cpu_to_le16(dsc->offset); + } else goto bad2; } - if (cmv->bFunction == MAKEFUNCTION(ADSLDIRECTIVE, MODEMREADY)) { + if (cmv->bFunction == E1_MAKEFUNCTION(E1_ADSLDIRECTIVE, E1_MODEMREADY)) { wake_up_cmv_ack(sc); uea_leaves(INS_TO_USBDEV(sc)); return; } /* in case of MEMACCESS */ - if (le16_to_cpu(cmv->wIndex) != sc->cmv_idx || - le32_to_cpu(get_unaligned(&cmv->dwSymbolicAddress)) != - sc->cmv_address - || le16_to_cpu(cmv->wOffsetAddress) != sc->cmv_offset) + if (le16_to_cpu(cmv->wIndex) != dsc->idx || + le32_to_cpu(get_unaligned(&cmv->dwSymbolicAddress)) != dsc->address || + le16_to_cpu(cmv->wOffsetAddress) != dsc->offset) goto bad2; sc->data = le32_to_cpu(get_unaligned(&cmv->dwData)); @@ -1289,8 +1945,8 @@ static void uea_dispatch_cmv(struct uea_softc *sc, struct cmv* cmv) bad2: uea_err(INS_TO_USBDEV(sc), "unexpected cmv received," "Function : %d, Subfunction : %d\n", - FUNCTION_TYPE(cmv->bFunction), - FUNCTION_SUBTYPE(cmv->bFunction)); + E1_FUNCTION_TYPE(cmv->bFunction), + E1_FUNCTION_SUBTYPE(cmv->bFunction)); uea_leaves(INS_TO_USBDEV(sc)); return; @@ -1301,6 +1957,61 @@ bad1: uea_leaves(INS_TO_USBDEV(sc)); } +/* The modem send us an ack. First with check if it right */ +static void uea_dispatch_cmv_e4(struct uea_softc *sc, struct intr_pkt *intr) +{ + struct cmv_dsc_e4 *dsc = &sc->cmv_dsc.e4; + struct cmv_e4 *cmv = &intr->u.e4.s2.cmv; + + uea_enters(INS_TO_USBDEV(sc)); + uea_dbg(INS_TO_USBDEV(sc), "cmv %x %x %x %x %x %x\n", + be16_to_cpu(cmv->wGroup), be16_to_cpu(cmv->wFunction), + be16_to_cpu(cmv->wOffset), be16_to_cpu(cmv->wAddress), + be32_to_cpu(cmv->dwData[0]), be32_to_cpu(cmv->dwData[1])); + + if (be16_to_cpu(cmv->wFunction) != dsc->function) + goto bad2; + + if (be16_to_cpu(cmv->wFunction) == E4_MAKEFUNCTION(E4_ADSLDIRECTIVE, E4_MODEMREADY, 1)) { + wake_up_cmv_ack(sc); + uea_leaves(INS_TO_USBDEV(sc)); + return; + } + + /* in case of MEMACCESS */ + if (be16_to_cpu(cmv->wOffset) != dsc->offset || + be16_to_cpu(cmv->wGroup) != dsc->group || + be16_to_cpu(cmv->wAddress) != dsc->address) + goto bad2; + + sc->data = be32_to_cpu(cmv->dwData[0]); + sc->data1 = be32_to_cpu(cmv->dwData[1]); + wake_up_cmv_ack(sc); + uea_leaves(INS_TO_USBDEV(sc)); + return; + +bad2: + uea_err(INS_TO_USBDEV(sc), "unexpected cmv received," + "Function : %d, Subfunction : %d\n", + E4_FUNCTION_TYPE(cmv->wFunction), + E4_FUNCTION_SUBTYPE(cmv->wFunction)); + uea_leaves(INS_TO_USBDEV(sc)); + return; +} + +static void uea_schedule_load_page_e1(struct uea_softc *sc, struct intr_pkt *intr) +{ + sc->pageno = intr->e1_bSwapPageNo; + sc->ovl = intr->e1_bOvl >> 4 | intr->e1_bOvl << 4; + schedule_work(&sc->task); +} + +static void uea_schedule_load_page_e4(struct uea_softc *sc, struct intr_pkt *intr) +{ + sc->pageno = intr->e4_bSwapPageNo; + schedule_work(&sc->task); +} + /* * interrupt handler */ @@ -1326,13 +2037,11 @@ static void uea_intr(struct urb *urb) switch (le16_to_cpu(intr->wInterrupt)) { case INT_LOADSWAPPAGE: - sc->pageno = intr->bSwapPageNo; - sc->ovl = intr->bOvl >> 4 | intr->bOvl << 4; - schedule_work(&sc->task); + sc->schedule_load_page(sc, intr); break; case INT_INCOMINGCMV: - uea_dispatch_cmv(sc, &intr->u.s2.cmv); + sc->dispatch_cmv(sc, intr); break; default: @@ -1349,19 +2058,34 @@ resubmit: */ static int uea_boot(struct uea_softc *sc) { - int ret; + int ret, size; struct intr_pkt *intr; uea_enters(INS_TO_USBDEV(sc)); - INIT_WORK(&sc->task, uea_load_page); + if (UEA_CHIP_VERSION(sc) == EAGLE_IV) { + size = E4_INTR_PKT_SIZE; + sc->dispatch_cmv = uea_dispatch_cmv_e4; + sc->schedule_load_page = uea_schedule_load_page_e4; + sc->stat = uea_stat_e4; + sc->send_cmvs = uea_send_cmvs_e4; + INIT_WORK(&sc->task, uea_load_page_e4); + } else { + size = E1_INTR_PKT_SIZE; + sc->dispatch_cmv = uea_dispatch_cmv_e1; + sc->schedule_load_page = uea_schedule_load_page_e1; + sc->stat = uea_stat_e1; + sc->send_cmvs = uea_send_cmvs_e1; + INIT_WORK(&sc->task, uea_load_page_e1); + } + init_waitqueue_head(&sc->sync_q); init_waitqueue_head(&sc->cmv_ack_wait); if (UEA_CHIP_VERSION(sc) == ADI930) load_XILINX_firmware(sc); - intr = kmalloc(INTR_PKT_SIZE, GFP_KERNEL); + intr = kmalloc(size, GFP_KERNEL); if (!intr) { uea_err(INS_TO_USBDEV(sc), "cannot allocate interrupt package\n"); @@ -1377,7 +2101,7 @@ static int uea_boot(struct uea_softc *sc) usb_fill_int_urb(sc->urb_int, sc->usb_dev, usb_rcvintpipe(sc->usb_dev, UEA_INTR_PIPE), - intr, INTR_PKT_SIZE, uea_intr, sc, + intr, size, uea_intr, sc, sc->usb_dev->actconfig->interface[0]->altsetting[0]. endpoint[0].desc.bInterval); @@ -1487,6 +2211,7 @@ static ssize_t read_human_status(struct device *dev, struct device_attribute *at char *buf) { int ret = -ENODEV; + int modem_state; struct uea_softc *sc; mutex_lock(&uea_mutex); @@ -1494,7 +2219,34 @@ static ssize_t read_human_status(struct device *dev, struct device_attribute *at if (!sc) goto out; - switch (GET_STATUS(sc->stats.phy.state)) { + if (UEA_CHIP_VERSION(sc) == EAGLE_IV) { + switch (sc->stats.phy.state) { + case 0x0: /* not yet synchronized */ + case 0x1: + case 0x3: + case 0x4: + modem_state = 0; + break; + case 0x5: /* initialization */ + case 0x6: + case 0x9: + case 0xa: + modem_state = 1; + break; + case 0x7: /* operational */ + modem_state = 2; + break; + case 0x2: /* fail ... */ + modem_state = 3; + break; + default: /* unknown */ + modem_state = 4; + break; + } + } else + modem_state = GET_STATUS(sc->stats.phy.state); + + switch (modem_state) { case 0: ret = sprintf(buf, "Modem is booting\n"); break; @@ -1504,9 +2256,12 @@ static ssize_t read_human_status(struct device *dev, struct device_attribute *at case 2: ret = sprintf(buf, "Modem is operational\n"); break; - default: + case 3: ret = sprintf(buf, "Modem synchronization failed\n"); break; + default: + ret = sprintf(buf, "Modem state is unknown\n"); + break; } out: mutex_unlock(&uea_mutex); @@ -1520,18 +2275,26 @@ static ssize_t read_delin(struct device *dev, struct device_attribute *attr, { int ret = -ENODEV; struct uea_softc *sc; + char *delin = "GOOD"; mutex_lock(&uea_mutex); sc = dev_to_uea(dev); if (!sc) goto out; - if (sc->stats.phy.flags & 0x0C00) - ret = sprintf(buf, "ERROR\n"); - else if (sc->stats.phy.flags & 0x0030) - ret = sprintf(buf, "LOSS\n"); - else - ret = sprintf(buf, "GOOD\n"); + if (UEA_CHIP_VERSION(sc) == EAGLE_IV) { + if (sc->stats.phy.flags & 0x4000) + delin = "RESET"; + else if (sc->stats.phy.flags & 0x0001) + delin = "LOSS"; + } else { + if (sc->stats.phy.flags & 0x0C00) + delin = "ERROR"; + else if (sc->stats.phy.flags & 0x0030) + delin = "LOSS"; + } + + ret = sprintf(buf, "%s\n", delin); out: mutex_unlock(&uea_mutex); return ret; @@ -1803,6 +2566,8 @@ static const struct usb_device_id uea_ids[] = { {USB_DEVICE(EAGLE_VID, EAGLE_IIC_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM}, {USB_DEVICE(EAGLE_VID, EAGLE_III_PID_PREFIRM), .driver_info = EAGLE_III | PREFIRM}, {USB_DEVICE(EAGLE_VID, EAGLE_III_PID_PSTFIRM), .driver_info = EAGLE_III | PSTFIRM}, + {USB_DEVICE(EAGLE_VID, EAGLE_IV_PID_PREFIRM), .driver_info = EAGLE_IV | PREFIRM}, + {USB_DEVICE(EAGLE_VID, EAGLE_IV_PID_PSTFIRM), .driver_info = EAGLE_IV | PSTFIRM}, {USB_DEVICE(USR_VID, MILLER_A_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM}, {USB_DEVICE(USR_VID, MILLER_A_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM}, {USB_DEVICE(USR_VID, MILLER_B_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM}, -- cgit v1.2.3-70-g09d2 From 603cf6087c5f3ee054bb257195b023848d26d76f Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 20 Aug 2007 23:21:01 +0200 Subject: UEAGLE: Devolo and Elsa chipsets support Support for Devolo and Elsa chipsets. These chipsets have no information about ADSL annex (line type) encoded in USB descriptors. Driver try to get this information from USB VID and PID or it can be explicitly set by the user through module parameter. Thanks to Johann Hanne, whose make most of this patch. Signed-off-by: Stanislaw Gruszka Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/ueagle-atm.c | 114 +++++++++++++++++++++++++++++++++---------- 1 file changed, 88 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index b5e8cbad223..2cdabd3421e 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -149,6 +149,9 @@ struct uea_softc { int modem_index; unsigned int driver_info; + int annex; +#define ANNEXA 0 +#define ANNEXB 1 int booting; int reset; @@ -207,10 +210,34 @@ struct uea_softc { #define ELSA_PID_PSTFIRM 0x3350 #define ELSA_PID_PREFIRM 0x3351 +#define ELSA_PID_A_PREFIRM 0x3352 +#define ELSA_PID_A_PSTFIRM 0x3353 +#define ELSA_PID_B_PREFIRM 0x3362 +#define ELSA_PID_B_PSTFIRM 0x3363 + /* - * Sagem USB IDs + * Devolo IDs : pots if (pid & 0x10) */ -#define EAGLE_VID 0x1110 +#define DEVOLO_VID 0x1039 +#define DEVOLO_EAGLE_I_A_PID_PSTFIRM 0x2110 +#define DEVOLO_EAGLE_I_A_PID_PREFIRM 0x2111 + +#define DEVOLO_EAGLE_I_B_PID_PSTFIRM 0x2100 +#define DEVOLO_EAGLE_I_B_PID_PREFIRM 0x2101 + +#define DEVOLO_EAGLE_II_A_PID_PSTFIRM 0x2130 +#define DEVOLO_EAGLE_II_A_PID_PREFIRM 0x2131 + +#define DEVOLO_EAGLE_II_B_PID_PSTFIRM 0x2120 +#define DEVOLO_EAGLE_II_B_PID_PREFIRM 0x2121 + +/* + * Reference design USB IDs + */ +#define ANALOG_VID 0x1110 +#define ADI930_PID_PREFIRM 0x9001 +#define ADI930_PID_PSTFIRM 0x9000 + #define EAGLE_I_PID_PREFIRM 0x9010 /* Eagle I */ #define EAGLE_I_PID_PSTFIRM 0x900F /* Eagle I */ @@ -241,6 +268,9 @@ struct uea_softc { #define PREFIRM 0 #define PSTFIRM (1<<7) +#define AUTO_ANNEX_A (1<<8) +#define AUTO_ANNEX_B (1<<9) + enum { ADI930 = 0, EAGLE_I, @@ -255,8 +285,8 @@ enum { #define UEA_CHIP_VERSION(x) \ ((x)->driver_info & 0xf) -#define IS_ISDN(usb_dev) \ - (le16_to_cpu((usb_dev)->descriptor.bcdDevice) & 0x80) +#define IS_ISDN(x) \ + ((x)->annex & ANNEXB) #define INS_TO_USBDEV(ins) ins->usb_dev @@ -511,6 +541,7 @@ static unsigned int debug; static int use_iso[NB_MODEM] = {[0 ... (NB_MODEM - 1)] = 1}; static int sync_wait[NB_MODEM]; static char *cmv_file[NB_MODEM]; +static int annex[NB_MODEM]; module_param(debug, uint, 0644); MODULE_PARM_DESC(debug, "module debug level (0=off,1=on,2=verbose)"); @@ -521,6 +552,9 @@ MODULE_PARM_DESC(sync_wait, "wait the synchronisation before starting ATM"); module_param_array(cmv_file, charp, NULL, 0644); MODULE_PARM_DESC(cmv_file, "file name with configuration and management variables"); +module_param_array(annex, uint, NULL, 0644); +MODULE_PARM_DESC(annex, + "manually set annex a/b (0=auto, 1=annex a, 2=annex b)"); #define UPDATE_ATM_STAT(type, val) \ do { \ @@ -810,17 +844,17 @@ static int request_dsp(struct uea_softc *sc) char *dsp_name; if (UEA_CHIP_VERSION(sc) == EAGLE_IV) { - if (IS_ISDN(sc->usb_dev)) + if (IS_ISDN(sc)) dsp_name = FW_DIR "DSP4i.bin"; else dsp_name = FW_DIR "DSP4p.bin"; } else if (UEA_CHIP_VERSION(sc) == ADI930) { - if (IS_ISDN(sc->usb_dev)) + if (IS_ISDN(sc)) dsp_name = FW_DIR "DSP9i.bin"; else dsp_name = FW_DIR "DSP9p.bin"; } else { - if (IS_ISDN(sc->usb_dev)) + if (IS_ISDN(sc)) dsp_name = FW_DIR "DSPei.bin"; else dsp_name = FW_DIR "DSPep.bin"; @@ -1515,7 +1549,7 @@ static void cmvs_file_name(struct uea_softc *sc, char *const cmv_name, int ver) else file_arr[3] = 'e'; - file_arr[4] = IS_ISDN(sc->usb_dev) ? 'i' : 'p'; + file_arr[4] = IS_ISDN(sc) ? 'i' : 'p'; file = file_arr; } else file = cmv_file[sc->modem_index]; @@ -2459,6 +2493,19 @@ static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf, sc->modem_index = (modem_index < NB_MODEM) ? modem_index++ : 0; sc->driver_info = id->driver_info; + /* first try to use module parameter */ + if (annex[sc->modem_index] == 1) + sc->annex = ANNEXA; + else if (annex[sc->modem_index] == 2) + sc->annex = ANNEXB; + /* try to autodetect annex */ + else if (sc->driver_info & AUTO_ANNEX_A) + sc->annex = ANNEXA; + else if (sc->driver_info & AUTO_ANNEX_B) + sc->annex = ANNEXB; + else + sc->annex = (le16_to_cpu(sc->usb_dev->descriptor.bcdDevice) & 0x80)?ANNEXB:ANNEXA; + /* ADI930 don't support iso */ if (UEA_CHIP_VERSION(id) != ADI930 && use_iso[sc->modem_index]) { int i; @@ -2520,10 +2567,11 @@ static int uea_probe(struct usb_interface *intf, const struct usb_device_id *id) struct usb_device *usb = interface_to_usbdev(intf); uea_enters(usb); - uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) : %s %s\n", - le16_to_cpu(usb->descriptor.idVendor), - le16_to_cpu(usb->descriptor.idProduct), - chip_name[UEA_CHIP_VERSION(id)], IS_ISDN(usb)?"isdn":"pots"); + uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) Rev (%#X): %s\n", + le16_to_cpu(usb->descriptor.idVendor), + le16_to_cpu(usb->descriptor.idProduct), + le16_to_cpu(usb->descriptor.bcdDevice), + chip_name[UEA_CHIP_VERSION(id)]); usb_reset_device(usb); @@ -2556,26 +2604,40 @@ static void uea_disconnect(struct usb_interface *intf) * List of supported VID/PID */ static const struct usb_device_id uea_ids[] = { + {USB_DEVICE(ANALOG_VID, ADI930_PID_PREFIRM), .driver_info = ADI930 | PREFIRM}, + {USB_DEVICE(ANALOG_VID, ADI930_PID_PSTFIRM), .driver_info = ADI930 | PSTFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_I_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_I_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_II_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_II_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_IIC_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_IIC_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_III_PID_PREFIRM), .driver_info = EAGLE_III | PREFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_III_PID_PSTFIRM), .driver_info = EAGLE_III | PSTFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_IV_PID_PREFIRM), .driver_info = EAGLE_IV | PREFIRM}, + {USB_DEVICE(ANALOG_VID, EAGLE_IV_PID_PSTFIRM), .driver_info = EAGLE_IV | PSTFIRM}, + {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_A_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM}, + {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_A_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_A}, + {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_B_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM}, + {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_B_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_B}, + {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_A_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM}, + {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_A_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM | AUTO_ANNEX_A}, + {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_B_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM}, + {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_B_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM | AUTO_ANNEX_B}, {USB_DEVICE(ELSA_VID, ELSA_PID_PREFIRM), .driver_info = ADI930 | PREFIRM}, {USB_DEVICE(ELSA_VID, ELSA_PID_PSTFIRM), .driver_info = ADI930 | PSTFIRM}, - {USB_DEVICE(EAGLE_VID, EAGLE_I_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM}, - {USB_DEVICE(EAGLE_VID, EAGLE_I_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM}, - {USB_DEVICE(EAGLE_VID, EAGLE_II_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM}, - {USB_DEVICE(EAGLE_VID, EAGLE_II_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM}, - {USB_DEVICE(EAGLE_VID, EAGLE_IIC_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM}, - {USB_DEVICE(EAGLE_VID, EAGLE_IIC_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM}, - {USB_DEVICE(EAGLE_VID, EAGLE_III_PID_PREFIRM), .driver_info = EAGLE_III | PREFIRM}, - {USB_DEVICE(EAGLE_VID, EAGLE_III_PID_PSTFIRM), .driver_info = EAGLE_III | PSTFIRM}, - {USB_DEVICE(EAGLE_VID, EAGLE_IV_PID_PREFIRM), .driver_info = EAGLE_IV | PREFIRM}, - {USB_DEVICE(EAGLE_VID, EAGLE_IV_PID_PSTFIRM), .driver_info = EAGLE_IV | PSTFIRM}, + {USB_DEVICE(ELSA_VID, ELSA_PID_A_PREFIRM), .driver_info = ADI930 | PREFIRM}, + {USB_DEVICE(ELSA_VID, ELSA_PID_A_PSTFIRM), .driver_info = ADI930 | PSTFIRM | AUTO_ANNEX_A}, + {USB_DEVICE(ELSA_VID, ELSA_PID_B_PREFIRM), .driver_info = ADI930 | PREFIRM}, + {USB_DEVICE(ELSA_VID, ELSA_PID_B_PSTFIRM), .driver_info = ADI930 | PSTFIRM | AUTO_ANNEX_B}, {USB_DEVICE(USR_VID, MILLER_A_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM}, - {USB_DEVICE(USR_VID, MILLER_A_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM}, + {USB_DEVICE(USR_VID, MILLER_A_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_A}, {USB_DEVICE(USR_VID, MILLER_B_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM}, - {USB_DEVICE(USR_VID, MILLER_B_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM}, + {USB_DEVICE(USR_VID, MILLER_B_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_B}, {USB_DEVICE(USR_VID, HEINEKEN_A_PID_PREFIRM),.driver_info = EAGLE_I | PREFIRM}, - {USB_DEVICE(USR_VID, HEINEKEN_A_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM}, + {USB_DEVICE(USR_VID, HEINEKEN_A_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_A}, {USB_DEVICE(USR_VID, HEINEKEN_B_PID_PREFIRM),.driver_info = EAGLE_I | PREFIRM}, - {USB_DEVICE(USR_VID, HEINEKEN_B_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM}, + {USB_DEVICE(USR_VID, HEINEKEN_B_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_B}, {} }; -- cgit v1.2.3-70-g09d2 From 503add467d4dd2355fe16ebffa7f6d5e9fcd10a8 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 20 Aug 2007 23:21:06 +0200 Subject: UEAGLE: Allow user to choose input interface alternate setting Let's user control how much USB bus bandwidth will be reserved by ueagle-atm device. This make possible to share bus with other devices when ueagle-atm driver works in isochronous mode. Signed-off-by: Stanislaw Gruszka Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/ueagle-atm.c | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index 2cdabd3421e..dee5f798946 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -538,15 +538,16 @@ static const char *chip_name[] = {"ADI930", "Eagle I", "Eagle II", "Eagle III", static int modem_index; static unsigned int debug; -static int use_iso[NB_MODEM] = {[0 ... (NB_MODEM - 1)] = 1}; +static unsigned int altsetting[NB_MODEM] = {[0 ... (NB_MODEM - 1)] = FASTEST_ISO_INTF}; static int sync_wait[NB_MODEM]; static char *cmv_file[NB_MODEM]; static int annex[NB_MODEM]; module_param(debug, uint, 0644); MODULE_PARM_DESC(debug, "module debug level (0=off,1=on,2=verbose)"); -module_param_array(use_iso, bool, NULL, 0644); -MODULE_PARM_DESC(use_iso, "use isochronous usb pipe for incoming traffic"); +module_param_array(altsetting, uint, NULL, 0644); +MODULE_PARM_DESC(altsetting, "alternate setting for incoming traffic: 0=bulk, " + "1=isoc slowest, ... , 8=isoc fastest (default)"); module_param_array(sync_wait, bool, NULL, 0644); MODULE_PARM_DESC(sync_wait, "wait the synchronisation before starting ATM"); module_param_array(cmv_file, charp, NULL, 0644); @@ -1254,7 +1255,7 @@ static void uea_set_bulk_timeout(struct uea_softc *sc, u32 dsrate) */ if (UEA_CHIP_VERSION(sc) == ADI930 || - use_iso[sc->modem_index] > 0 || + altsetting[sc->modem_index] > 0 || sc->stats.phy.dsrate == dsrate) return; @@ -2459,6 +2460,7 @@ static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf, struct usb_device *usb = interface_to_usbdev(intf); struct uea_softc *sc; int ret, ifnum = intf->altsetting->desc.bInterfaceNumber; + unsigned int alt; uea_enters(usb); @@ -2506,22 +2508,16 @@ static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf, else sc->annex = (le16_to_cpu(sc->usb_dev->descriptor.bcdDevice) & 0x80)?ANNEXB:ANNEXA; + alt = altsetting[sc->modem_index]; /* ADI930 don't support iso */ - if (UEA_CHIP_VERSION(id) != ADI930 && use_iso[sc->modem_index]) { - int i; - - /* try set fastest alternate for inbound traffic interface */ - for (i = FASTEST_ISO_INTF; i > 0; i--) - if (usb_set_interface(usb, UEA_DS_IFACE_NO, i) == 0) - break; - - if (i > 0) { - uea_dbg(usb, "set alternate %d for 2 interface\n", i); + if (UEA_CHIP_VERSION(id) != ADI930 && alt > 0) { + if (alt <= 8 && usb_set_interface(usb, UEA_DS_IFACE_NO, alt) == 0) { + uea_dbg(usb, "set alternate %u for 2 interface\n", alt); uea_info(usb, "using iso mode\n"); usbatm->flags |= UDSL_USE_ISOC | UDSL_IGNORE_EILSEQ; } else { - uea_err(usb, "setting any alternate failed for " - "2 interface, using bulk mode\n"); + uea_err(usb, "setting alternate %u failed for " + "2 interface, using bulk mode\n", alt); } } -- cgit v1.2.3-70-g09d2 From 04ea02f5746a2e01a38edae2de3eafc40eac17aa Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 20 Aug 2007 23:21:10 +0200 Subject: UEAGLE: Avoid keyboard driver blocking Ueagle-atm driver load DSP firmware in function, which is running from common workqueue. In some (error) circumstances loading firmware may sleep for long periods (even 60 seconds, depending on timeout). This block keyboard driver, which also use common workqueue. To fix problem use custom workqueue in ueagle-atm. Signed-off-by: Stanislaw Gruszka Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/ueagle-atm.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index dee5f798946..648c6b79ff4 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -167,6 +167,7 @@ struct uea_softc { union cmv_dsc cmv_dsc; struct work_struct task; + struct workqueue_struct *work_q; u16 pageno; u16 ovl; @@ -1830,7 +1831,7 @@ static int uea_start_reset(struct uea_softc *sc) /* start loading DSP */ sc->pageno = 0; sc->ovl = 0; - schedule_work(&sc->task); + queue_work(sc->work_q, &sc->task); /* wait for modem ready CMV */ ret = wait_cmv_ack(sc); @@ -2038,13 +2039,13 @@ static void uea_schedule_load_page_e1(struct uea_softc *sc, struct intr_pkt *int { sc->pageno = intr->e1_bSwapPageNo; sc->ovl = intr->e1_bOvl >> 4 | intr->e1_bOvl << 4; - schedule_work(&sc->task); + queue_work(sc->work_q, &sc->task); } static void uea_schedule_load_page_e4(struct uea_softc *sc, struct intr_pkt *intr) { sc->pageno = intr->e4_bSwapPageNo; - schedule_work(&sc->task); + queue_work(sc->work_q, &sc->task); } /* @@ -2117,6 +2118,13 @@ static int uea_boot(struct uea_softc *sc) init_waitqueue_head(&sc->sync_q); init_waitqueue_head(&sc->cmv_ack_wait); + sc->work_q = create_workqueue("ueagle-dsp"); + if (!sc->work_q) { + uea_err(INS_TO_USBDEV(sc), "cannot allocate workqueue\n"); + uea_leaves(INS_TO_USBDEV(sc)); + return -ENOMEM; + } + if (UEA_CHIP_VERSION(sc) == ADI930) load_XILINX_firmware(sc); @@ -2124,14 +2132,13 @@ static int uea_boot(struct uea_softc *sc) if (!intr) { uea_err(INS_TO_USBDEV(sc), "cannot allocate interrupt package\n"); - uea_leaves(INS_TO_USBDEV(sc)); - return -ENOMEM; + goto err0; } sc->urb_int = usb_alloc_urb(0, GFP_KERNEL); if (!sc->urb_int) { uea_err(INS_TO_USBDEV(sc), "cannot allocate interrupt URB\n"); - goto err; + goto err1; } usb_fill_int_urb(sc->urb_int, sc->usb_dev, @@ -2144,7 +2151,7 @@ static int uea_boot(struct uea_softc *sc) if (ret < 0) { uea_err(INS_TO_USBDEV(sc), "urb submition failed with error %d\n", ret); - goto err; + goto err1; } sc->kthread = kthread_run(uea_kthread, sc, "ueagle-atm"); @@ -2158,10 +2165,12 @@ static int uea_boot(struct uea_softc *sc) err2: usb_kill_urb(sc->urb_int); -err: +err1: usb_free_urb(sc->urb_int); sc->urb_int = NULL; kfree(intr); +err0: + destroy_workqueue(sc->work_q); uea_leaves(INS_TO_USBDEV(sc)); return -ENOMEM; } @@ -2176,15 +2185,15 @@ static void uea_stop(struct uea_softc *sc) ret = kthread_stop(sc->kthread); uea_dbg(INS_TO_USBDEV(sc), "kthread finish with status %d\n", ret); - /* stop any pending boot process */ - flush_scheduled_work(); - uea_request(sc, UEA_SET_MODE, UEA_LOOPBACK_ON, 0, NULL); usb_kill_urb(sc->urb_int); kfree(sc->urb_int->transfer_buffer); usb_free_urb(sc->urb_int); + /* stop any pending boot process, when no one can schedule work */ + destroy_workqueue(sc->work_q); + if (sc->dsp_firm) release_firmware(sc->dsp_firm); uea_leaves(INS_TO_USBDEV(sc)); -- cgit v1.2.3-70-g09d2 From 337427f91f844ebe84442dc0b5e24577a8139600 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 20 Aug 2007 23:21:14 +0200 Subject: UEAGLE: Do not sleep when device is disconnected Do not sleep in kernel thread when device is disconnected, this make faster suspending and module unloading. Use one wait queue for sleeping. Signed-off-by: Stanislaw Gruszka Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/ueagle-atm.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index 648c6b79ff4..4aa41a97bf6 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -161,7 +161,6 @@ struct uea_softc { struct task_struct *kthread; u32 data; u32 data1; - wait_queue_head_t cmv_ack_wait; int cmv_ack; union cmv_dsc cmv_dsc; @@ -558,6 +557,15 @@ module_param_array(annex, uint, NULL, 0644); MODULE_PARM_DESC(annex, "manually set annex a/b (0=auto, 1=annex a, 2=annex b)"); +#define uea_wait(sc, cond, timeo) \ +({ \ + int _r = wait_event_interruptible_timeout(sc->sync_q, \ + (cond) || kthread_should_stop(), timeo); \ + if (kthread_should_stop()) \ + _r = -ENODEV; \ + _r; \ +}) + #define UPDATE_ATM_STAT(type, val) \ do { \ if (sc->usbatm->atm_dev) \ @@ -1067,13 +1075,13 @@ static inline void wake_up_cmv_ack(struct uea_softc *sc) { BUG_ON(sc->cmv_ack); sc->cmv_ack = 1; - wake_up(&sc->cmv_ack_wait); + wake_up(&sc->sync_q); } static inline int wait_cmv_ack(struct uea_softc *sc) { - int ret = wait_event_interruptible_timeout(sc->cmv_ack_wait, - sc->cmv_ack, ACK_TIMEOUT); + int ret = uea_wait(sc, sc->cmv_ack , ACK_TIMEOUT); + sc->cmv_ack = 0; uea_dbg(INS_TO_USBDEV(sc), "wait_event_timeout : %d ms\n", @@ -1806,7 +1814,9 @@ static int uea_start_reset(struct uea_softc *sc) uea_request(sc, UEA_SET_MODE, UEA_START_RESET, 0, NULL); /* original driver use 200ms, but windows driver use 100ms */ - msleep(100); + ret = uea_wait(sc, 0, msecs_to_jiffies(100)); + if (ret < 0) + return ret; /* leave reset mode */ uea_request(sc, UEA_SET_MODE, UEA_END_RESET, 0, NULL); @@ -1818,7 +1828,9 @@ static int uea_start_reset(struct uea_softc *sc) uea_request(sc, UEA_SET_2183_DATA, UEA_SWAP_MAILBOX, 2, &zero); } - msleep(1000); + ret = uea_wait(sc, 0, msecs_to_jiffies(1000)); + if (ret < 0) + return ret; if (UEA_CHIP_VERSION(sc) == EAGLE_IV) sc->cmv_dsc.e4.function = E4_MAKEFUNCTION(E4_ADSLDIRECTIVE, E4_MODEMREADY, 1); @@ -1868,7 +1880,7 @@ static int uea_kthread(void *data) if (!ret) ret = sc->stat(sc); if (ret != -EAGAIN) - msleep_interruptible(1000); + uea_wait(sc, 0, msecs_to_jiffies(1000)); if (try_to_freeze()) uea_err(INS_TO_USBDEV(sc), "suspend/resume not supported, " "please unplug/replug your modem\n"); @@ -2116,7 +2128,6 @@ static int uea_boot(struct uea_softc *sc) } init_waitqueue_head(&sc->sync_q); - init_waitqueue_head(&sc->cmv_ack_wait); sc->work_q = create_workqueue("ueagle-dsp"); if (!sc->work_q) { -- cgit v1.2.3-70-g09d2 From 0eb0226c9d819fd2af31ae4fc52bbca81c215369 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 20 Aug 2007 23:21:19 +0200 Subject: UEAGLE: Cosmetic Update copyrights and remove not necessary warning (ueagle-atm works well on suspend/resume). Signed-off-by: Stanislaw Gruszka Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/ueagle-atm.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index 4aa41a97bf6..389c5b164eb 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -2,7 +2,8 @@ * Copyright (c) 2003, 2004 * Damien Bergamini . All rights reserved. * - * Copyright (c) 2005 Matthieu Castet + * Copyright (c) 2005-2007 Matthieu Castet + * Copyright (c) 2005-2007 Stanislaw Gruszka * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -1881,9 +1882,7 @@ static int uea_kthread(void *data) ret = sc->stat(sc); if (ret != -EAGAIN) uea_wait(sc, 0, msecs_to_jiffies(1000)); - if (try_to_freeze()) - uea_err(INS_TO_USBDEV(sc), "suspend/resume not supported, " - "please unplug/replug your modem\n"); + try_to_freeze(); } uea_leaves(INS_TO_USBDEV(sc)); return ret; -- cgit v1.2.3-70-g09d2 From af1c51fcb2aea23ec2dfe73b7d66515d1622e689 Mon Sep 17 00:00:00 2001 From: Marcelo Tosatti Date: Mon, 20 Aug 2007 18:13:27 -0700 Subject: USB: EHCI restart speedup It is not necessary to powerdown the ports on ehci_pci_reinit() when the chip reset already did that. Removing this saves 20ms during restart after poweroff paths (which OLPC uses a lot). To ensure driver startup then behaves consistently, force a reset during driver startup. (Not doing this was an accident of some previous changes to the init sequence.) Make the corresponding change in the PS3 support. It's not clear what ehci-fsl should do here; it has similar code to the PS3. Signed-off-by: Marcelo Tosatti Signed-off-by: David Brownell Cc: Acked-by: Geoff Levand Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-pci.c | 5 +---- drivers/usb/host/ehci-ps3.c | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index a7816e392a8..ad0d4965f2f 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -58,8 +58,6 @@ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev) if (!retval) ehci_dbg(ehci, "MWI active\n"); - ehci_port_power(ehci, 0); - return 0; } @@ -156,8 +154,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd) break; } - if (ehci_is_TDI(ehci)) - ehci_reset(ehci); + ehci_reset(ehci); /* at least the Genesys GL880S needs fixup here */ temp = HCS_N_CC(ehci->hcs_params) * HCS_N_PCC(ehci->hcs_params); diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c index 829fe649a98..03a6b2f4e6e 100644 --- a/drivers/usb/host/ehci-ps3.c +++ b/drivers/usb/host/ehci-ps3.c @@ -47,7 +47,7 @@ static int ps3_ehci_hc_reset(struct usb_hcd *hcd) if (result) return result; - ehci_port_power(ehci, 0); + ehci_reset(ehci); return result; } -- cgit v1.2.3-70-g09d2 From dfd1e53777afe1050e3a0a3f0dd063a64242b818 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 21 Aug 2007 15:36:52 -0400 Subject: USB: minor fixes for r8a66597 driver This patch (as967) makes a few relatively minor changes to the r8a66597 driver: finish_request() does nothing but call done(), so merge the two routines. Detect and report -EOVERFLOW errors. Fix the calculation that checks for short packets. Signed-off-by: Alan Stern CC: Yoshihiro Shimoda Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/r8a66597-hcd.c | 40 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 94bb229df3b..49cf998c172 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -1109,8 +1109,9 @@ static void set_td_timer(struct r8a66597 *r8a66597, struct r8a66597_td *td) } /* this function must be called with interrupt disabled */ -static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td, - u16 pipenum, struct urb *urb) +static void finish_request(struct r8a66597 *r8a66597, struct r8a66597_td *td, + u16 pipenum, struct urb *urb) +__releases(r8a66597->lock) __acquires(r8a66597->lock) { int restart = 0; struct usb_hcd *hcd = r8a66597_to_hcd(r8a66597); @@ -1151,14 +1152,6 @@ static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td, } } -/* this function must be called with interrupt disabled */ -static void finish_request(struct r8a66597 *r8a66597, struct r8a66597_td *td, - u16 pipenum, struct urb *urb) -__releases(r8a66597->lock) __acquires(r8a66597->lock) -{ - done(r8a66597, td, pipenum, urb); -} - static void packet_read(struct r8a66597 *r8a66597, u16 pipenum) { u16 tmp; @@ -1167,6 +1160,7 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum) struct r8a66597_td *td = r8a66597_get_td(r8a66597, pipenum); struct urb *urb; int finish = 0; + int status = 0; if (unlikely(!td)) return; @@ -1185,7 +1179,6 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum) /* prepare parameters */ rcv_len = tmp & DTLN; - bufsize = td->maxpacket; if (usb_pipeisoc(urb->pipe)) { buf = (u16 *)(urb->transfer_buffer + urb->iso_frame_desc[td->iso_cnt].offset); @@ -1194,25 +1187,30 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum) buf = (void *)urb->transfer_buffer + urb->actual_length; urb_len = urb->transfer_buffer_length - urb->actual_length; } - if (rcv_len < bufsize) - size = min(rcv_len, urb_len); - else - size = min(bufsize, urb_len); + bufsize = min(urb_len, (int) td->maxpacket); + if (rcv_len <= bufsize) { + size = rcv_len; + } else { + size = bufsize; + status = -EOVERFLOW; + finish = 1; + } /* update parameters */ urb->actual_length += size; if (rcv_len == 0) td->zero_packet = 1; - if ((size % td->maxpacket) > 0) { + if (rcv_len < bufsize) { td->short_packet = 1; if (urb->transfer_buffer_length != urb->actual_length && urb->transfer_flags & URB_SHORT_NOT_OK) - td->urb->status = -EREMOTEIO; + status = -EREMOTEIO; } if (usb_pipeisoc(urb->pipe)) { urb->iso_frame_desc[td->iso_cnt].actual_length = size; - urb->iso_frame_desc[td->iso_cnt].status = 0; + urb->iso_frame_desc[td->iso_cnt].status = status; td->iso_cnt++; + finish = 0; } /* check transfer finish */ @@ -1233,7 +1231,7 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum) if (finish && pipenum != 0) { if (td->urb->status == -EINPROGRESS) - td->urb->status = 0; + td->urb->status = status; finish_request(r8a66597, td, pipenum, urb); } } @@ -1807,7 +1805,7 @@ static int r8a66597_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, pipe_stop(r8a66597, td->pipe); pipe_irq_disable(r8a66597, td->pipenum); disable_irq_empty(r8a66597, td->pipenum); - done(r8a66597, td, td->pipenum, urb); + finish_request(r8a66597, td, td->pipenum, urb); } done: spin_unlock_irqrestore(&r8a66597->lock, flags); @@ -1841,7 +1839,7 @@ static void r8a66597_endpoint_disable(struct usb_hcd *hcd, td = r8a66597_get_td(r8a66597, pipenum); if (td) urb = td->urb; - done(r8a66597, td, pipenum, urb); + finish_request(r8a66597, td, pipenum, urb); kfree(hep->hcpriv); hep->hcpriv = NULL; spin_unlock_irqrestore(&r8a66597->lock, flags); -- cgit v1.2.3-70-g09d2 From ee7d1f3f0c32d8abe9627aa73dc62ee5bf2daf7f Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 21 Aug 2007 15:37:50 -0400 Subject: USB: remove Iso status value in uhci-hcd This patch (968) changes the way uhci-hcd reports status for Isochronous URBs. Until now urb->status has been set to the last detected error code. But other HCDs don't do this; they leave the status set to 0 and report errors only in the individual iso packet descriptors. So this patch removes the extra computation and makes uhci-hcd behave like the others. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/uhci-hcd.h | 1 - drivers/usb/host/uhci-q.c | 11 +++-------- 2 files changed, 3 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index 1b3d23406ac..e46d2b0203c 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h @@ -146,7 +146,6 @@ struct uhci_qh { short phase; /* Between 0 and period-1 */ short load; /* Periodic time requirement, in us */ unsigned int iso_frame; /* Frame # for iso_packet_desc */ - int iso_status; /* Status for Isochronous URBs */ int state; /* QH_STATE_xxx; see above */ int type; /* Queue type (control, bulk, etc) */ diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index bff200cb3d2..793a04685ef 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -1324,7 +1324,6 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb, if (list_empty(&qh->queue)) { qh->iso_packet_desc = &urb->iso_frame_desc[0]; qh->iso_frame = urb->start_frame; - qh->iso_status = 0; } qh->skel = SKEL_ISO; @@ -1361,18 +1360,15 @@ static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb) qh->iso_packet_desc->actual_length = actlength; qh->iso_packet_desc->status = status; } - - if (status) { + if (status) urb->error_count++; - qh->iso_status = status; - } uhci_remove_td_from_urbp(td); uhci_free_td(uhci, td); qh->iso_frame += qh->period; ++qh->iso_packet_desc; } - return qh->iso_status; + return 0; } static int uhci_urb_enqueue(struct usb_hcd *hcd, @@ -1517,7 +1513,6 @@ __acquires(uhci->lock) qh->iso_packet_desc = &nurb->iso_frame_desc[0]; qh->iso_frame = nurb->start_frame; - qh->iso_status = 0; } /* Take the URB off the QH's queue. If the queue is now empty, @@ -1586,7 +1581,7 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) } uhci_giveback_urb(uhci, qh, urb); - if (status < 0 && qh->type != USB_ENDPOINT_XFER_ISOC) + if (status < 0) break; } -- cgit v1.2.3-70-g09d2 From b0d9efba3ec53468984aecef8eeaf079089f2e5a Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 21 Aug 2007 15:39:21 -0400 Subject: USB: centralize -EREMOTEIO handling This patch (as969) continues the ongoing changes to the way HCDs report URB statuses. The programming interface has been simplified by making usbcore responsible for clearing urb->hcpriv and for setting -EREMOTEIO status when an URB with the URB_SHORT_NOT_OK flag ends up as a short transfer. By moving the work out of the HCDs, this removes a fair amount of repeated code. Signed-off-by: Alan Stern CC: David Brownell CC: Olav Kongas CC: Yoshihiro Shimoda CC: Tony Olech Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 9 +++++++-- drivers/usb/gadget/dummy_hcd.c | 9 ++------- drivers/usb/host/ehci-q.c | 7 ++++--- drivers/usb/host/isp116x-hcd.c | 8 +------- drivers/usb/host/ohci-q.c | 11 ----------- drivers/usb/host/r8a66597-hcd.c | 7 +------ drivers/usb/host/sl811-hcd.c | 14 +++----------- drivers/usb/host/u132-hcd.c | 5 ----- drivers/usb/host/uhci-q.c | 8 -------- 9 files changed, 18 insertions(+), 60 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index a853f63b925..22a098b318c 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -366,6 +366,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) spin_unlock_irq(&hcd_root_hub_lock); if (status) return status; + urb->hcpriv = hcd; /* Indicate it's queued */ cmd = (struct usb_ctrlrequest *) urb->setup_packet; typeReq = (cmd->bRequestType << 8) | cmd->bRequest; @@ -579,7 +580,6 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd) hcd->poll_pending = 0; hcd->status_urb = NULL; urb->status = 0; - urb->hcpriv = NULL; urb->actual_length = length; memcpy(urb->transfer_buffer, buffer, length); @@ -675,7 +675,6 @@ static int usb_rh_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) del_timer (&hcd->rh_timer); if (urb == hcd->status_urb) { hcd->status_urb = NULL; - urb->hcpriv = NULL; usb_hcd_unlink_urb_from_ep(hcd, urb); spin_unlock(&hcd_root_hub_lock); @@ -1192,6 +1191,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) if (unlikely(status)) { usbmon_urb_submit_error(&hcd->self, urb, status); unmap_urb_for_dma(hcd, urb); + urb->hcpriv = NULL; INIT_LIST_HEAD(&urb->urb_list); atomic_dec(&urb->use_count); if (urb->reject) @@ -1265,6 +1265,11 @@ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb) unmap_urb_for_dma(hcd, urb); usbmon_urb_complete (&hcd->self, urb); usb_unanchor_urb(urb); + urb->hcpriv = NULL; + if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) && + urb->actual_length < urb->transfer_buffer_length && + !urb->status)) + urb->status = -EREMOTEIO; /* pass ownership to the completion handler */ urb->complete (urb); diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index c441d10c087..0cb032526ca 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -1099,8 +1099,7 @@ top: * * partially filling a buffer optionally blocks queue advances * (so completion handlers can clean up the queue) but we don't - * need to emulate such data-in-flight. so we only show part - * of the URB_SHORT_NOT_OK effect: completion status. + * need to emulate such data-in-flight. */ if (is_short) { if (host_len == dev_len) { @@ -1111,10 +1110,7 @@ top: if (dev_len > host_len) maybe_set_status (urb, -EOVERFLOW); else - maybe_set_status (urb, - (urb->transfer_flags - & URB_SHORT_NOT_OK) - ? -EREMOTEIO : 0); + maybe_set_status (urb, 0); } else if (!to_host) { maybe_set_status (urb, 0); if (host_len > dev_len) @@ -1516,7 +1512,6 @@ restart: continue; return_urb: - urb->hcpriv = NULL; list_del (&urbp->urbp_list); kfree (urbp); if (ep) diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 1da2de4d34e..e80b5c417d7 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -232,7 +232,6 @@ __acquires(ehci->lock) } spin_lock (&urb->lock); - urb->hcpriv = NULL; switch (urb->status) { case -EINPROGRESS: /* success */ urb->status = 0; @@ -395,8 +394,10 @@ halt: /* remove it from the queue */ spin_lock (&urb->lock); qtd_copy_status (ehci, urb, qtd->length, token); - do_status = (urb->status == -EREMOTEIO) - && usb_pipecontrol (urb->pipe); + if (unlikely(urb->status == -EREMOTEIO)) { + do_status = usb_pipecontrol(urb->pipe); + urb->status = 0; + } spin_unlock (&urb->lock); if (stopped && qtd->qtd_list.prev != &qh->qtd_list) { diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index f2b5d6281c5..c2919dbc3f5 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -282,7 +282,6 @@ __releases(isp116x->lock) __acquires(isp116x->lock) { unsigned i; - urb->hcpriv = NULL; ep->error_count = 0; if (usb_pipecontrol(urb->pipe)) @@ -446,12 +445,7 @@ static void postproc_atl_queue(struct isp116x *isp116x) if (PTD_GET_ACTIVE(ptd) || (cc != TD_CC_NOERROR && cc < 0x0E)) break; - if ((urb->transfer_flags & URB_SHORT_NOT_OK) && - urb->actual_length < - urb->transfer_buffer_length) - status = -EREMOTEIO; - else - status = 0; + status = 0; ep->nextpid = 0; break; default: diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index 889c0720743..8aad6199cdc 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -43,21 +43,10 @@ __acquires(ohci->lock) // ASSERT (urb->hcpriv != 0); urb_free_priv (ohci, urb->hcpriv); - urb->hcpriv = NULL; spin_lock (&urb->lock); if (likely (urb->status == -EINPROGRESS)) urb->status = 0; - /* report short control reads right even though the data TD always - * has TD_R set. (much simpler, but creates the 1-td limit.) - */ - if (unlikely (urb->transfer_flags & URB_SHORT_NOT_OK) - && unlikely (usb_pipecontrol (urb->pipe)) - && urb->actual_length < urb->transfer_buffer_length - && usb_pipein (urb->pipe) - && urb->status == 0) { - urb->status = -EREMOTEIO; - } spin_unlock (&urb->lock); switch (usb_pipetype (urb->pipe)) { diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 49cf998c172..60248b01ce1 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -783,7 +783,6 @@ static void force_dequeue(struct r8a66597 *r8a66597, u16 pipenum, u16 address) if (urb) { urb->status = -ENODEV; - urb->hcpriv = NULL; usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597), urb); @@ -1134,7 +1133,6 @@ __releases(r8a66597->lock) __acquires(r8a66597->lock) if (usb_pipeisoc(urb->pipe)) urb->start_frame = r8a66597_get_frame(hcd); - urb->hcpriv = NULL; usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597), urb); spin_unlock(&r8a66597->lock); @@ -1202,9 +1200,6 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum) td->zero_packet = 1; if (rcv_len < bufsize) { td->short_packet = 1; - if (urb->transfer_buffer_length != urb->actual_length && - urb->transfer_flags & URB_SHORT_NOT_OK) - status = -EREMOTEIO; } if (usb_pipeisoc(urb->pipe)) { urb->iso_frame_desc[td->iso_cnt].actual_length = size; @@ -1214,7 +1209,7 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum) } /* check transfer finish */ - if (check_transfer_finish(td, urb)) { + if (finish || check_transfer_finish(td, urb)) { pipe_stop(r8a66597, td->pipe); pipe_irq_disable(r8a66597, pipenum); finish = 1; diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index 15a93f946af..e90953a9c9f 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -438,7 +438,6 @@ static void finish_request( spin_lock(&urb->lock); if (urb->status == -EINPROGRESS) urb->status = status; - urb->hcpriv = NULL; spin_unlock(&urb->lock); usb_hcd_unlink_urb_from_ep(sl811_to_hcd(sl811), urb); @@ -545,17 +544,10 @@ done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank) sl811_read_buf(sl811, SL811HS_PACKET_BUF(bank == 0), buf, len); usb_dotoggle(udev, ep->epnum, 0); - if (urb->actual_length == urb->transfer_buffer_length) + if (urb->actual_length == urb->transfer_buffer_length + || len < ep->maxpacket) urbstat = 0; - else if (len < ep->maxpacket) { - if (urb->transfer_flags & URB_SHORT_NOT_OK) - urbstat = -EREMOTEIO; - else - urbstat = 0; - } - if (usb_pipecontrol(urb->pipe) - && (urbstat == -EREMOTEIO - || urbstat == 0)) { + if (usb_pipecontrol(urb->pipe) && urbstat == 0) { /* NOTE if the status stage STALLs (why?), * this reports the wrong urb status. diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index c87660b5edc..1381275d448 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -519,7 +519,6 @@ static void u132_hcd_giveback_urb(struct u132 *u132, struct u132_endp *endp, struct usb_hcd *hcd = u132_to_hcd(u132); urb->error_count = 0; urb->status = status; - urb->hcpriv = NULL; spin_lock_irqsave(&endp->queue_lock.slock, irqs); usb_hcd_unlink_urb_from_ep(hcd, urb); endp->queue_next += 1; @@ -560,7 +559,6 @@ static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp, struct usb_hcd *hcd = u132_to_hcd(u132); urb->error_count = 0; urb->status = status; - urb->hcpriv = NULL; spin_lock_irqsave(&endp->queue_lock.slock, irqs); usb_hcd_unlink_urb_from_ep(hcd, urb); endp->queue_next += 1; @@ -2430,7 +2428,6 @@ static int dequeue_from_overflow_chain(struct u132 *u132, list_del(scan); endp->queue_size -= 1; urb->error_count = 0; - urb->hcpriv = NULL; usb_hcd_giveback_urb(hcd, urb); return 0; } else @@ -2472,7 +2469,6 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, endp->edset_flush = 1; u132_endp_queue_work(u132, endp, 0); spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - urb->hcpriv = NULL; return 0; } else { spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); @@ -2517,7 +2513,6 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, irqs); kfree(urbq); } urb->error_count = 0; - urb->hcpriv = NULL; usb_hcd_giveback_urb(hcd, urb); return 0; } else if (list_empty(&endp->urb_more)) { diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index 793a04685ef..fbc3af392c2 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -757,7 +757,6 @@ static void uhci_free_urb_priv(struct uhci_hcd *uhci, uhci_free_td(uhci, td); } - urbp->urb->hcpriv = NULL; kmem_cache_free(uhci_up_cachep, urbp); } @@ -1494,13 +1493,6 @@ __acquires(uhci->lock) * unlinked first. Regardless, don't confuse people with a * negative length. */ urb->actual_length = max(urb->actual_length, 0); - - /* Report erroneous short transfers */ - if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) && - urb->actual_length < - urb->transfer_buffer_length && - urb->status == 0)) - urb->status = -EREMOTEIO; } /* When giving back the first URB in an Isochronous queue, -- cgit v1.2.3-70-g09d2 From eb23105462304fd35571fd0cab1de7aec79a9ec5 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 21 Aug 2007 15:40:36 -0400 Subject: USB: add urb->unlinked field This patch (as970) adds a new urb->unlinked field, which is used to store the status of unlinked URBs since we can't use urb->status for that purpose any more. To help simplify the HCDs, usbcore will check urb->unlinked before calling the completion handler; if the value is set it will automatically override the status reported by the HCD. Signed-off-by: Alan Stern CC: David Brownell CC: Olav Kongas CC: Yoshihiro Shimoda CC: Tony Olech Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 19 +++--- drivers/usb/gadget/dummy_hcd.c | 8 +-- drivers/usb/host/ehci-q.c | 29 ++++------ drivers/usb/host/isp116x-hcd.c | 5 +- drivers/usb/host/ohci-q.c | 5 +- drivers/usb/host/r8a66597-hcd.c | 24 +++----- drivers/usb/host/sl811-hcd.c | 5 +- drivers/usb/host/u132-hcd.c | 124 ++++++++++++++++++++-------------------- drivers/usb/host/uhci-debug.c | 4 +- drivers/usb/host/uhci-q.c | 9 +-- include/linux/usb.h | 1 + 11 files changed, 108 insertions(+), 125 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 22a098b318c..ec17fc4d286 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -532,8 +532,7 @@ error: /* any errors get returned through the urb completion */ spin_lock_irq(&hcd_root_hub_lock); - if (urb->status == -EINPROGRESS) - urb->status = status; + urb->status = status; usb_hcd_unlink_urb_from_ep(hcd, urb); /* This peculiar use of spinlocks echoes what real HC drivers do. @@ -1024,6 +1023,7 @@ int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb) switch (hcd->state) { case HC_STATE_RUNNING: case HC_STATE_RESUMING: + urb->unlinked = 0; list_add_tail(&urb->urb_list, &urb->ep->urb_list); break; default: @@ -1071,9 +1071,9 @@ int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb, /* Any status except -EINPROGRESS means something already started to * unlink this URB from the hardware. So there's no more work to do. */ - if (urb->status != -EINPROGRESS) + if (urb->unlinked) return -EBUSY; - urb->status = status; + urb->unlinked = status; /* IRQ setup can easily be broken so that USB controllers * never get completion IRQs ... maybe even the ones we need to @@ -1259,6 +1259,10 @@ int usb_hcd_unlink_urb (struct urb *urb, int status) * (and is done using urb->hcpriv). It also released all HCD locks; * the device driver won't cause problems if it frees, modifies, * or resubmits this URB. + * + * If @urb was unlinked, the value of @urb->status will be overridden by + * @urb->unlinked. Erroneous short transfers are detected in case + * the HCD hasn't checked for them. */ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb) { @@ -1266,7 +1270,9 @@ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb) usbmon_urb_complete (&hcd->self, urb); usb_unanchor_urb(urb); urb->hcpriv = NULL; - if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) && + if (unlikely(urb->unlinked)) + urb->status = urb->unlinked; + else if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) && urb->actual_length < urb->transfer_buffer_length && !urb->status)) urb->status = -EREMOTEIO; @@ -1305,8 +1311,7 @@ rescan: list_for_each_entry (urb, &ep->urb_list, urb_list) { int is_in; - /* the urb may already have been unlinked */ - if (urb->status != -EINPROGRESS) + if (urb->unlinked) continue; usb_get_urb (urb); is_in = usb_urb_dir_in(urb); diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 0cb032526ca..f2b124cf320 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -1029,8 +1029,7 @@ static int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) static void maybe_set_status (struct urb *urb, int status) { spin_lock (&urb->lock); - if (urb->status == -EINPROGRESS) - urb->status = status; + urb->status = status; spin_unlock (&urb->lock); } @@ -1257,10 +1256,9 @@ restart: int type; urb = urbp->urb; - if (urb->status != -EINPROGRESS) { - /* likely it was just unlinked */ + if (urb->unlinked) goto return_urb; - } else if (dum->rh_state != DUMMY_RH_RUNNING) + else if (dum->rh_state != DUMMY_RH_RUNNING) continue; type = usb_pipetype (urb->pipe); diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index e80b5c417d7..a8f5408c161 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -151,7 +151,7 @@ static void qtd_copy_status ( urb->actual_length += length - QTD_LENGTH (token); /* don't modify error codes */ - if (unlikely (urb->status != -EINPROGRESS)) + if (unlikely(urb->unlinked)) return; /* force cleanup after short read; not always an error */ @@ -232,21 +232,14 @@ __acquires(ehci->lock) } spin_lock (&urb->lock); - switch (urb->status) { - case -EINPROGRESS: /* success */ - urb->status = 0; - default: /* fault */ - COUNT (ehci->stats.complete); - break; - case -EREMOTEIO: /* fault or normal */ - if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) + if (unlikely(urb->unlinked)) { + COUNT(ehci->stats.unlink); + } else { + if (likely(urb->status == -EINPROGRESS || + (urb->status == -EREMOTEIO && + !(urb->transfer_flags & URB_SHORT_NOT_OK)))) urb->status = 0; - COUNT (ehci->stats.complete); - break; - case -ECONNRESET: /* canceled */ - case -ENOENT: - COUNT (ehci->stats.unlink); - break; + COUNT(ehci->stats.complete); } spin_unlock (&urb->lock); @@ -364,7 +357,8 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) * for the urb faulted (including short read) or * its urb was canceled. we may patch qh or qtds. */ - if (likely (urb->status == -EINPROGRESS)) + if (likely(urb->status == -EINPROGRESS && + !urb->unlinked)) continue; /* issue status after short control reads */ @@ -395,7 +389,8 @@ halt: spin_lock (&urb->lock); qtd_copy_status (ehci, urb, qtd->length, token); if (unlikely(urb->status == -EREMOTEIO)) { - do_status = usb_pipecontrol(urb->pipe); + do_status = (!urb->unlinked && + usb_pipecontrol(urb->pipe)); urb->status = 0; } spin_unlock (&urb->lock); diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index c2919dbc3f5..35b3507ff40 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -455,11 +455,10 @@ static void postproc_atl_queue(struct isp116x *isp116x) done: if (status != -EINPROGRESS) { spin_lock(&urb->lock); - if (urb->status == -EINPROGRESS) - urb->status = status; + urb->status = status; spin_unlock(&urb->lock); } - if (urb->status != -EINPROGRESS) + if (urb->status != -EINPROGRESS || urb->unlinked) finish_request(isp116x, ep, urb); } } diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index 8aad6199cdc..3c793fad178 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -758,8 +758,7 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td) cc = TD_CC_NOERROR; if (cc != TD_CC_NOERROR && cc < 0x0E) { spin_lock (&urb->lock); - if (urb->status == -EINPROGRESS) - urb->status = cc_to_error [cc]; + urb->status = cc_to_error[cc]; spin_unlock (&urb->lock); } @@ -972,7 +971,7 @@ rescan_this: urb = td->urb; urb_priv = td->urb->hcpriv; - if (urb->status == -EINPROGRESS) { + if (!urb->unlinked) { prev = &td->hwNextTD; continue; } diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 60248b01ce1..98b9e054754 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -1118,7 +1118,7 @@ __releases(r8a66597->lock) __acquires(r8a66597->lock) r8a66597->timeout_map &= ~(1 << pipenum); if (likely(td)) { - if (td->set_address && urb->status != 0) + if (td->set_address && (urb->status != 0 || urb->unlinked)) r8a66597->address_map &= ~(1 << urb->setup_packet[2]); pipe_toggle_save(r8a66597, td->pipe, urb); @@ -1225,8 +1225,7 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum) } if (finish && pipenum != 0) { - if (td->urb->status == -EINPROGRESS) - td->urb->status = status; + td->urb->status = status; finish_request(r8a66597, td, pipenum, urb); } } @@ -1308,32 +1307,24 @@ static void check_next_phase(struct r8a66597 *r8a66597) switch (td->type) { case USB_PID_IN: case USB_PID_OUT: - if (urb->status != -EINPROGRESS) { - finish = 1; - break; - } if (check_transfer_finish(td, urb)) td->type = USB_PID_ACK; break; case USB_PID_SETUP: - if (urb->status != -EINPROGRESS) - finish = 1; - else if (urb->transfer_buffer_length == urb->actual_length) { + if (urb->transfer_buffer_length == urb->actual_length) td->type = USB_PID_ACK; - urb->status = 0; - } else if (usb_pipeout(urb->pipe)) + else if (usb_pipeout(urb->pipe)) td->type = USB_PID_OUT; else td->type = USB_PID_IN; break; case USB_PID_ACK: finish = 1; - if (urb->status == -EINPROGRESS) - urb->status = 0; + urb->status = 0; break; } - if (finish) + if (finish || urb->unlinked) finish_request(r8a66597, td, 0, urb); else start_transfer(r8a66597, td); @@ -1418,8 +1409,7 @@ static void irq_pipe_empty(struct r8a66597 *r8a66597) if ((tmp & INBUFM) == 0) { disable_irq_empty(r8a66597, pipenum); pipe_irq_disable(r8a66597, pipenum); - if (td->urb->status == -EINPROGRESS) - td->urb->status = 0; + td->urb->status = 0; finish_request(r8a66597, td, pipenum, td->urb); } } diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index e90953a9c9f..f0fa94148d9 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -436,8 +436,7 @@ static void finish_request( ep->nextpid = USB_PID_SETUP; spin_lock(&urb->lock); - if (urb->status == -EINPROGRESS) - urb->status = status; + urb->status = status; spin_unlock(&urb->lock); usb_hcd_unlink_urb_from_ep(sl811_to_hcd(sl811), urb); @@ -598,7 +597,7 @@ done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank) bank, status, ep, urbstat); } - if (urb && (urbstat != -EINPROGRESS || urb->status != -EINPROGRESS)) + if (urb && (urbstat != -EINPROGRESS || urb->unlinked)) finish_request(sl811, ep, urb, urbstat); } diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index 1381275d448..db800a434b8 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -645,12 +645,12 @@ static void u132_hcd_interrupt_recv(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { struct u132_ring *ring = endp->ring; u8 *u = urb->transfer_buffer + urb->actual_length; u8 *b = buf; @@ -716,8 +716,8 @@ static void u132_hcd_interrupt_recv(void *data, struct urb *urb, u8 *buf, return; } } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, urb->status); return; @@ -744,12 +744,12 @@ static void u132_hcd_bulk_output_sent(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { struct u132_ring *ring = endp->ring; urb->actual_length += len; endp->toggle_bits = toggle_bits; @@ -768,8 +768,8 @@ static void u132_hcd_bulk_output_sent(void *data, struct urb *urb, u8 *buf, return; } } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, urb->status); return; @@ -797,12 +797,12 @@ static void u132_hcd_bulk_input_recv(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { struct u132_ring *ring = endp->ring; u8 *u = urb->transfer_buffer + urb->actual_length; u8 *b = buf; @@ -871,8 +871,8 @@ static void u132_hcd_bulk_input_recv(void *data, struct urb *urb, u8 *buf, return; } } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, urb->status); return; @@ -898,18 +898,18 @@ static void u132_hcd_configure_empty_sent(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, 0); return; } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, urb->status); return; @@ -936,12 +936,12 @@ static void u132_hcd_configure_input_recv(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { struct u132_ring *ring = endp->ring; u8 *u = urb->transfer_buffer; u8 *b = buf; @@ -980,8 +980,8 @@ static void u132_hcd_configure_input_recv(void *data, struct urb *urb, u8 *buf, return; } } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, urb->status); return; @@ -1007,18 +1007,18 @@ static void u132_hcd_configure_empty_recv(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, 0); return; } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, urb->status); return; @@ -1045,12 +1045,12 @@ static void u132_hcd_configure_setup_sent(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { if (usb_pipein(urb->pipe)) { int retval; struct u132_ring *ring = endp->ring; @@ -1077,8 +1077,8 @@ static void u132_hcd_configure_setup_sent(void *data, struct urb *urb, u8 *buf, return; } } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, urb->status); return; @@ -1106,20 +1106,20 @@ static void u132_hcd_enumeration_empty_recv(void *data, struct urb *urb, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { u132->addr[0].address = 0; endp->usb_addr = udev->usb_addr; up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, 0); return; } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, urb->status); return; @@ -1145,12 +1145,12 @@ static void u132_hcd_enumeration_address_sent(void *data, struct urb *urb, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { int retval; struct u132_ring *ring = endp->ring; up(&u132->scheduler_lock); @@ -1162,8 +1162,8 @@ static void u132_hcd_enumeration_address_sent(void *data, struct urb *urb, u132_hcd_giveback_urb(u132, endp, urb, retval); return; } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, urb->status); return; @@ -1189,18 +1189,18 @@ static void u132_hcd_initial_empty_sent(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, 0); return; } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, urb->status); return; @@ -1227,12 +1227,12 @@ static void u132_hcd_initial_input_recv(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { int retval; struct u132_ring *ring = endp->ring; u8 *u = urb->transfer_buffer; @@ -1251,8 +1251,8 @@ static void u132_hcd_initial_input_recv(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, retval); return; } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, urb->status); return; @@ -1279,12 +1279,12 @@ static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, -EINTR); return; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); return; - } else if (urb->status == -EINPROGRESS) { + } else if (!urb->unlinked) { int retval; struct u132_ring *ring = endp->ring; up(&u132->scheduler_lock); @@ -1296,8 +1296,8 @@ static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf, u132_hcd_giveback_urb(u132, endp, urb, retval); return; } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" - "s=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " + "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, urb->status); return; @@ -2279,8 +2279,8 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, , u132->going); return -ENODEV; } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed urb=" - "%p status=%d\n", urb, urb->status); + dev_err(&u132->platform_dev->dev, "device is being removed " + "urb=%p\n", urb); return -ESHUTDOWN; } else { u8 usb_addr = usb_pipedevice(urb->pipe); diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c index 1497371583b..20cc58b9780 100644 --- a/drivers/usb/host/uhci-debug.c +++ b/drivers/usb/host/uhci-debug.c @@ -120,8 +120,8 @@ static int uhci_show_urbp(struct urb_priv *urbp, char *buf, int len, int space) out += sprintf(out, "%s%s", ptype, (urbp->fsbr ? " FSBR" : "")); out += sprintf(out, " Actlen=%d", urbp->urb->actual_length); - if (urbp->urb->status != -EINPROGRESS) - out += sprintf(out, " Status=%d", urbp->urb->status); + if (urbp->urb->unlinked) + out += sprintf(out, " Unlinked=%d", urbp->urb->unlinked); out += sprintf(out, "\n"); i = nactive = ninactive = 0; diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index fbc3af392c2..bab56726655 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -1557,15 +1557,12 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) break; spin_lock(&urb->lock); - if (urb->status == -EINPROGRESS) /* Not dequeued */ - urb->status = status; - else - status = ECONNRESET; /* Not -ECONNRESET */ + urb->status = status; spin_unlock(&urb->lock); /* Dequeued but completed URBs can't be given back unless * the QH is stopped or has finished unlinking. */ - if (status == ECONNRESET) { + if (urb->unlinked) { if (QH_FINISHED_UNLINKING(qh)) qh->is_stopped = 1; else if (!qh->is_stopped) @@ -1588,7 +1585,7 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) restart: list_for_each_entry(urbp, &qh->queue, node) { urb = urbp->urb; - if (urb->status != -EINPROGRESS) { + if (urb->unlinked) { /* Fix up the TD links and save the toggles for * non-Isochronous queues. For Isochronous queues, diff --git a/include/linux/usb.h b/include/linux/usb.h index 92d63c6b6fc..5c7b79088ad 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -1245,6 +1245,7 @@ struct urb void *hcpriv; /* private data for host controller */ atomic_t use_count; /* concurrent submissions counter */ u8 reject; /* submissions will fail */ + int unlinked; /* unlink error code */ /* public: documented fields in the urb that can be used by drivers */ struct list_head urb_list; /* list head for use by the urb's -- cgit v1.2.3-70-g09d2 From ed6e52829c113ca18f042ac55cc77b1b90745eab Mon Sep 17 00:00:00 2001 From: "Andrew M. Bishop" Date: Tue, 21 Aug 2007 19:08:56 +0100 Subject: USB: ftdi_sio: Handle FT232RL devices like FT232BM devices Handle the FT232RL device type in exactly the same way as FT232BM devices (FT232RL detection was added around kernel 2.6.20 but not code for handling it). Signed-off-by: Andrew M. Bishop Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 2d045857b18..e4c248c98e8 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1169,7 +1169,9 @@ static void remove_sysfs_attrs(struct usb_serial_port *port) /* XXX see create_sysfs_attrs */ if (priv->chip_type != SIO) { device_remove_file(&port->dev, &dev_attr_event_char); - if (priv->chip_type == FT232BM || priv->chip_type == FT2232C) { + if (priv->chip_type == FT232BM || + priv->chip_type == FT2232C || + priv->chip_type == FT232RL) { device_remove_file(&port->dev, &dev_attr_latency_timer); } } @@ -2102,6 +2104,7 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file) case FT8U232AM: case FT232BM: case FT2232C: + case FT232RL: /* the 8U232AM returns a two byte value (the sio is a 1 byte value) - in the same format as the data returned from the in point */ if ((ret = usb_control_msg(port->serial->dev, -- cgit v1.2.3-70-g09d2 From 1f5a3d0f34fd5719081c6b8f3dbbcbe328d4da31 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 22 Aug 2007 13:06:53 -0400 Subject: USB: fix mistake in usb_hcd_giveback_urb This patch (as971) fixes a small mistake: The URB's completion status needs to be adjusted before the URB is passed to usmon_urb_complete(), not afterward. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index ec17fc4d286..8b17babf5c5 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1266,9 +1266,6 @@ int usb_hcd_unlink_urb (struct urb *urb, int status) */ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb) { - unmap_urb_for_dma(hcd, urb); - usbmon_urb_complete (&hcd->self, urb); - usb_unanchor_urb(urb); urb->hcpriv = NULL; if (unlikely(urb->unlinked)) urb->status = urb->unlinked; @@ -1277,6 +1274,10 @@ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb) !urb->status)) urb->status = -EREMOTEIO; + unmap_urb_for_dma(hcd, urb); + usbmon_urb_complete(&hcd->self, urb); + usb_unanchor_urb(urb); + /* pass ownership to the completion handler */ urb->complete (urb); atomic_dec (&urb->use_count); -- cgit v1.2.3-70-g09d2 From 6e8fe43b26085a64327d1cbb751ab895f3ad3f5d Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 22 Aug 2007 13:08:40 -0400 Subject: USB: avoid the donelist after an error in ohci-hcd This patch (as972) changes ohci-hcd so that after an error occurs, the remaining TDs for the URB will be skipped over entirely instead of going through the donelist. This enables the driver to give back the URB as soon as the error is detected, avoiding the need to store the error status in urb->status. Signed-off-by: Alan Stern CC: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-q.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index 3c793fad178..860e55ff67a 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -783,10 +783,10 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td) /*-------------------------------------------------------------------------*/ -static inline struct td * -ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev) +static void ed_halted(struct ohci_hcd *ohci, struct td *td, int cc) { struct urb *urb = td->urb; + urb_priv_t *urb_priv = urb->hcpriv; struct ed *ed = td->ed; struct list_head *tmp = td->td_list.next; __hc32 toggle = ed->hwHeadP & cpu_to_hc32 (ohci, ED_C); @@ -798,13 +798,12 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev) wmb (); ed->hwHeadP &= ~cpu_to_hc32 (ohci, ED_H); - /* put any later tds from this urb onto the donelist, after 'td', - * order won't matter here: no errors, and nothing was transferred. - * also patch the ed so it looks as if those tds completed normally. + /* Get rid of all later tds from this urb. We don't have + * to be careful: no errors and nothing was transferred. + * Also patch the ed so it looks as if those tds completed normally. */ while (tmp != &ed->td_list) { struct td *next; - __hc32 info; next = list_entry (tmp, struct td, td_list); tmp = next->td_list.next; @@ -819,14 +818,9 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev) * then we need to leave the control STATUS packet queued * and clear ED_SKIP. */ - info = next->hwINFO; - info |= cpu_to_hc32 (ohci, TD_DONE); - info &= ~cpu_to_hc32 (ohci, TD_CC); - next->hwINFO = info; - - next->next_dl_td = rev; - rev = next; + list_del(&next->td_list); + urb_priv->td_cnt++; ed->hwHeadP = next->hwNextTD | toggle; } @@ -852,8 +846,6 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev) hc32_to_cpu (ohci, td->hwINFO), cc, cc_to_error [cc]); } - - return rev; } /* replies to the request have to be on a FIFO basis so @@ -890,7 +882,7 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci) */ if (cc != TD_CC_NOERROR && (td->ed->hwHeadP & cpu_to_hc32 (ohci, ED_H))) - td_rev = ed_halted (ohci, td, cc, td_rev); + ed_halted(ohci, td, cc); td->next_dl_td = td_rev; td_rev = td; -- cgit v1.2.3-70-g09d2 From c4e41562e09961df6ba72b49269793d21c0034dc Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 22 Aug 2007 23:06:48 +0100 Subject: USB: cp2101: Coding style police Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/cp2101.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c index 33f6ee50b8d..883625126d6 100644 --- a/drivers/usb/serial/cp2101.c +++ b/drivers/usb/serial/cp2101.c @@ -521,7 +521,7 @@ static void cp2101_set_termios (struct usb_serial_port *port, dbg("%s - port %d", __FUNCTION__, port->number); - if ((!port->tty) || (!port->tty->termios)) { + if (!port->tty || !port->tty->termios) { dbg("%s - no tty structures", __FUNCTION__); return; } -- cgit v1.2.3-70-g09d2 From 94d0f7eac77a84da2cee41b8038796891f75f09e Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 22 Aug 2007 23:09:16 +0100 Subject: USB: kobil_sct: Rework driver No hardware but this driver is currently totally broken so we can't make it much worse. Remove all tbe broken invalid termios handling and replace it with a proper set_termios method. Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/kobil_sct.c | 144 ++++++++++++++++------------------------- 1 file changed, 55 insertions(+), 89 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index 02a86dbc0e9..6f224195bd2 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c @@ -82,6 +82,7 @@ static int kobil_tiocmset(struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear); static void kobil_read_int_callback( struct urb *urb ); static void kobil_write_callback( struct urb *purb ); +static void kobil_set_termios(struct usb_serial_port *port, struct ktermios *old); static struct usb_device_id id_table [] = { @@ -119,6 +120,7 @@ static struct usb_serial_driver kobil_device = { .attach = kobil_startup, .shutdown = kobil_shutdown, .ioctl = kobil_ioctl, + .set_termios = kobil_set_termios, .tiocmget = kobil_tiocmget, .tiocmset = kobil_tiocmset, .open = kobil_open, @@ -137,7 +139,6 @@ struct kobil_private { int cur_pos; // index of the next char to send in buf __u16 device_type; int line_state; - struct ktermios internal_termios; }; @@ -216,7 +217,7 @@ static void kobil_shutdown (struct usb_serial *serial) static int kobil_open (struct usb_serial_port *port, struct file *filp) { - int i, result = 0; + int result = 0; struct kobil_private *priv; unsigned char *transfer_buffer; int transfer_buffer_length = 8; @@ -242,16 +243,6 @@ static int kobil_open (struct usb_serial_port *port, struct file *filp) port->tty->termios->c_iflag = IGNBRK | IGNPAR | IXOFF; port->tty->termios->c_oflag &= ~ONLCR; // do NOT translate CR to CR-NL (0x0A -> 0x0A 0x0D) - // set up internal termios structure - priv->internal_termios.c_iflag = port->tty->termios->c_iflag; - priv->internal_termios.c_oflag = port->tty->termios->c_oflag; - priv->internal_termios.c_cflag = port->tty->termios->c_cflag; - priv->internal_termios.c_lflag = port->tty->termios->c_lflag; - - for (i=0; iinternal_termios.c_cc[i] = port->tty->termios->c_cc[i]; - } - // allocate memory for transfer buffer transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL); if (! transfer_buffer) { @@ -607,102 +598,79 @@ static int kobil_tiocmset(struct usb_serial_port *port, struct file *file, return (result < 0) ? result : 0; } - -static int kobil_ioctl(struct usb_serial_port *port, struct file *file, - unsigned int cmd, unsigned long arg) +static void kobil_set_termios(struct usb_serial_port *port, struct ktermios *old) { struct kobil_private * priv; int result; unsigned short urb_val = 0; - unsigned char *transfer_buffer; - int transfer_buffer_length = 8; - char *settings; - void __user *user_arg = (void __user *)arg; + int c_cflag = port->tty->termios->c_cflag; + speed_t speed; + void * settings; priv = usb_get_serial_port_data(port); - if ((priv->device_type == KOBIL_USBTWIN_PRODUCT_ID) || (priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID)) { + if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID) // This device doesn't support ioctl calls - return 0; - } - - switch (cmd) { - case TCGETS: // 0x5401 - if (!access_ok(VERIFY_WRITE, user_arg, sizeof(struct ktermios))) { - dbg("%s - port %d Error in access_ok", __FUNCTION__, port->number); - return -EFAULT; - } - if (kernel_termios_to_user_termios((struct ktermios __user *)arg, - &priv->internal_termios)) - return -EFAULT; - return 0; - - case TCSETS: // 0x5402 - if (!(port->tty->termios)) { - dbg("%s - port %d Error: port->tty->termios is NULL", __FUNCTION__, port->number); - return -ENOTTY; - } - if (!access_ok(VERIFY_READ, user_arg, sizeof(struct ktermios))) { - dbg("%s - port %d Error in access_ok", __FUNCTION__, port->number); - return -EFAULT; - } - if (user_termios_to_kernel_termios(&priv->internal_termios, - (struct ktermios __user *)arg)) - return -EFAULT; - - settings = kzalloc(50, GFP_KERNEL); - if (! settings) { - return -ENOBUFS; - } + return; - switch (priv->internal_termios.c_cflag & CBAUD) { - case B1200: + switch (speed = tty_get_baud_rate(port->tty)) { + case 1200: urb_val = SUSBCR_SBR_1200; - strcat(settings, "1200 "); break; - case B9600: + case 9600: default: urb_val = SUSBCR_SBR_9600; - strcat(settings, "9600 "); break; - } + } + urb_val |= (c_cflag & CSTOPB) ? SUSBCR_SPASB_2StopBits : SUSBCR_SPASB_1StopBit; + + settings = kzalloc(50, GFP_KERNEL); + if (! settings) + return; - urb_val |= (priv->internal_termios.c_cflag & CSTOPB) ? SUSBCR_SPASB_2StopBits : SUSBCR_SPASB_1StopBit; - strcat(settings, (priv->internal_termios.c_cflag & CSTOPB) ? "2 StopBits " : "1 StopBit "); + sprintf(settings, "%d ", speed); - if (priv->internal_termios.c_cflag & PARENB) { - if (priv->internal_termios.c_cflag & PARODD) { - urb_val |= SUSBCR_SPASB_OddParity; - strcat(settings, "Odd Parity"); - } else { - urb_val |= SUSBCR_SPASB_EvenParity; - strcat(settings, "Even Parity"); - } + if (c_cflag & PARENB) { + if (c_cflag & PARODD) { + urb_val |= SUSBCR_SPASB_OddParity; + strcat(settings, "Odd Parity"); } else { - urb_val |= SUSBCR_SPASB_NoParity; - strcat(settings, "No Parity"); + urb_val |= SUSBCR_SPASB_EvenParity; + strcat(settings, "Even Parity"); } - dbg("%s - port %d setting port to: %s", __FUNCTION__, port->number, settings ); + } else { + urb_val |= SUSBCR_SPASB_NoParity; + strcat(settings, "No Parity"); + } - result = usb_control_msg( port->serial->dev, - usb_rcvctrlpipe(port->serial->dev, 0 ), - SUSBCRequest_SetBaudRateParityAndStopBits, - USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT, - urb_val, - 0, - settings, - 0, - KOBIL_TIMEOUT - ); + result = usb_control_msg( port->serial->dev, + usb_rcvctrlpipe(port->serial->dev, 0 ), + SUSBCRequest_SetBaudRateParityAndStopBits, + USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT, + urb_val, + 0, + settings, + 0, + KOBIL_TIMEOUT + ); + kfree(settings); +} - dbg("%s - port %d Send set_baudrate URB returns: %i", __FUNCTION__, port->number, result); - kfree(settings); +static int kobil_ioctl(struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg) +{ + struct kobil_private * priv = usb_get_serial_port_data(port); + unsigned char *transfer_buffer; + int transfer_buffer_length = 8; + int result; + + if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID) + // This device doesn't support ioctl calls return 0; + switch (cmd) { case TCFLSH: // 0x540B transfer_buffer = kmalloc(transfer_buffer_length, GFP_KERNEL); - if (! transfer_buffer) { + if (! transfer_buffer) return -ENOBUFS; - } result = usb_control_msg( port->serial->dev, usb_rcvctrlpipe(port->serial->dev, 0 ), @@ -716,15 +684,13 @@ static int kobil_ioctl(struct usb_serial_port *port, struct file *file, ); dbg("%s - port %d Send reset_all_queues (FLUSH) URB returns: %i", __FUNCTION__, port->number, result); - kfree(transfer_buffer); - return ((result < 0) ? -EFAULT : 0); - + return (result < 0) ? -EFAULT : 0; + default: + return -ENOIOCTLCMD; } - return -ENOIOCTLCMD; } - static int __init kobil_init (void) { int retval; -- cgit v1.2.3-70-g09d2 From 12943f097e5a4a0550f52f98ab8f476435e2ce15 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 24 Aug 2007 16:27:50 -0400 Subject: USB: less-restrictive command checking in g-file-storage This patch (as983) makes a test for minimum-length command sizes in g_file_storage less restrictive. It doesn't matter because commands with bad lengths will be detected later on anyway, and doing it like this makes the driver interoperable with certain buggy hosts such as the JVC HiFi (reported by Samuel Hangouet). Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/file_storage.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 9998cd7af41..0551140010e 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -2964,7 +2964,7 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh) /* Is the CBW meaningful? */ if (cbw->Lun >= MAX_LUNS || cbw->Flags & ~USB_BULK_IN_FLAG || - cbw->Length < 6 || cbw->Length > MAX_COMMAND_SIZE) { + cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) { DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, " "cmdlen %u\n", cbw->Lun, cbw->Flags, cbw->Length); -- cgit v1.2.3-70-g09d2 From fdf99c9ec10cb9cd44be3ac0bd007a49ac6dc751 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 23 Aug 2007 15:55:34 -0700 Subject: USB: fix memory leak in berry_charge driver This fixes a small memory leak that happens every time the device is plugged in. Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/berry_charge.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/misc/berry_charge.c b/drivers/usb/misc/berry_charge.c index 92c1d2768df..24e2dc3148a 100644 --- a/drivers/usb/misc/berry_charge.c +++ b/drivers/usb/misc/berry_charge.c @@ -71,7 +71,7 @@ static int magic_charge(struct usb_device *udev) if (retval != 2) { dev_err(&udev->dev, "First magic command failed: %d.\n", retval); - return retval; + goto exit; } dbg(&udev->dev, "Sending second magic command\n"); @@ -80,7 +80,7 @@ static int magic_charge(struct usb_device *udev) if (retval != 0) { dev_err(&udev->dev, "Second magic command failed: %d.\n", retval); - return retval; + goto exit; } dbg(&udev->dev, "Calling set_configuration\n"); @@ -88,6 +88,8 @@ static int magic_charge(struct usb_device *udev) if (retval) dev_err(&udev->dev, "Set Configuration failed :%d.\n", retval); +exit: + kfree(dummy_buffer); return retval; } @@ -112,6 +114,7 @@ static int magic_dual_mode(struct usb_device *udev) if (retval) dev_err(&udev->dev, "Set Configuration failed :%d.\n", retval); + kfree(dummy_buffer); return retval; } -- cgit v1.2.3-70-g09d2 From ce0d9325b19555f05b08cbb1ea4c2393eec188ec Mon Sep 17 00:00:00 2001 From: Roman Kagan Date: Fri, 24 Aug 2007 20:22:52 +0400 Subject: usb-serial: show port number in sysfs Some usb-serial devices (e.g. certain Edgeport models) have more than one serial port on the same USB device/interface. Currently the only way to distinguish these ports in userspace is by their minor device number: the driver makes them consecutive and in stable order. However, for the purpose of stable naming with udev this is insufficient: when udev handles the ADD event for one of the ports it doesn't know what minor number the other one has. To make stable naming easier, export the port number via sysfs. Signed-off-by: Roman Kagan Signed-off-by: Dmitry Guryanov Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/bus.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c index a47a24f8820..0b14aea8ebd 100644 --- a/drivers/usb/serial/bus.c +++ b/drivers/usb/serial/bus.c @@ -36,6 +36,16 @@ static int usb_serial_device_match (struct device *dev, struct device_driver *dr return 0; } +static ssize_t show_port_number(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct usb_serial_port *port = to_usb_serial_port(dev); + + return sprintf(buf, "%d\n", port->number - port->serial->minor); +} + +static DEVICE_ATTR(port_number, S_IRUGO, show_port_number, NULL); + static int usb_serial_device_probe (struct device *dev) { struct usb_serial_driver *driver; @@ -62,6 +72,10 @@ static int usb_serial_device_probe (struct device *dev) goto exit; } + retval = device_create_file(dev, &dev_attr_port_number); + if (retval) + goto exit; + minor = port->number; tty_register_device (usb_serial_tty_driver, minor, dev); dev_info(&port->serial->dev->dev, @@ -84,6 +98,8 @@ static int usb_serial_device_remove (struct device *dev) return -ENODEV; } + device_remove_file(&port->dev, &dev_attr_port_number); + driver = port->serial->type; if (driver->port_remove) { if (!try_module_get(driver->driver.owner)) { -- cgit v1.2.3-70-g09d2 From b84d2bf07ffb962733ba56307c61539a301a742e Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Fri, 24 Aug 2007 02:35:14 +0200 Subject: usb: avoid redundant cast of kmalloc() return value in OTi-6858 driver In drivers/usb/serial/oti6858.c::pl2303_buf_alloc() the return value of kmalloc() is being cast to "struct pl2303_buf *", but that need not be done here since kmalloc() returns "void *". Signed-off-by: Jesper Juhl Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/oti6858.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c index 64f3f66a7a3..d19861166b5 100644 --- a/drivers/usb/serial/oti6858.c +++ b/drivers/usb/serial/oti6858.c @@ -1144,7 +1144,7 @@ static struct pl2303_buf *pl2303_buf_alloc(unsigned int size) if (size == 0) return NULL; - pb = (struct pl2303_buf *)kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL); + pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL); if (pb == NULL) return NULL; -- cgit v1.2.3-70-g09d2 From e7beb667842ad0f6ec95a22e7c88e71dfbd60649 Mon Sep 17 00:00:00 2001 From: Andreas Loibl Date: Fri, 24 Aug 2007 01:51:11 +0200 Subject: usb: serial/pl2303: support for BenQ Siemens Mobile Phone EF81 This patch adds support for the BenQ Mobile Phone EF81 to pl2303 Signed-off-by: Andreas Loibl Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/pl2303.c | 1 + drivers/usb/serial/pl2303.h | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index f9f85f56f0d..1da57fd9ea2 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -73,6 +73,7 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) }, { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) }, { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) }, + { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) }, { USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) }, { USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) }, { USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) }, diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index f9a71d0c102..c39bace5cbc 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -59,6 +59,7 @@ #define SIEMENS_PRODUCT_ID_SX1 0x0001 #define SIEMENS_PRODUCT_ID_X65 0x0003 #define SIEMENS_PRODUCT_ID_X75 0x0004 +#define SIEMENS_PRODUCT_ID_EF81 0x0005 #define SYNTECH_VENDOR_ID 0x0745 #define SYNTECH_PRODUCT_ID 0x0001 -- cgit v1.2.3-70-g09d2 From 4d2f110c51eec853c50f68cf068888a77551c8d3 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 24 Aug 2007 15:40:10 -0400 Subject: USB: reorganize urb->status use in dummy-hcd This patch (as973) reorganizes the way dummy-hcd sets urb->status. It now keeps the information in a local variable until the last moment. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/dummy_hcd.c | 53 +++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index f2b124cf320..c1af7bab26f 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -1026,16 +1026,10 @@ static int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) return rc; } -static void maybe_set_status (struct urb *urb, int status) -{ - spin_lock (&urb->lock); - urb->status = status; - spin_unlock (&urb->lock); -} - /* transfer up to a frame's worth; caller must own lock */ static int -transfer (struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit) +transfer(struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit, + int *status) { struct dummy_request *req; @@ -1103,15 +1097,15 @@ top: if (is_short) { if (host_len == dev_len) { req->req.status = 0; - maybe_set_status (urb, 0); + *status = 0; } else if (to_host) { req->req.status = 0; if (dev_len > host_len) - maybe_set_status (urb, -EOVERFLOW); + *status = -EOVERFLOW; else - maybe_set_status (urb, 0); + *status = 0; } else if (!to_host) { - maybe_set_status (urb, 0); + *status = 0; if (host_len > dev_len) req->req.status = -EOVERFLOW; else @@ -1125,9 +1119,8 @@ top: req->req.status = 0; if (urb->transfer_buffer_length == urb->actual_length && !(urb->transfer_flags - & URB_ZERO_PACKET)) { - maybe_set_status (urb, 0); - } + & URB_ZERO_PACKET)) + *status = 0; } /* device side completion --> continuable */ @@ -1143,7 +1136,7 @@ top: } /* host side completion --> terminate */ - if (urb->status != -EINPROGRESS) + if (*status != -EINPROGRESS) break; /* rescan to continue with any other queued i/o */ @@ -1254,6 +1247,7 @@ restart: u8 address; struct dummy_ep *ep = NULL; int type; + int status = -EINPROGRESS; urb = urbp->urb; if (urb->unlinked) @@ -1279,7 +1273,7 @@ restart: dev_dbg (dummy_dev(dum), "no ep configured for urb %p\n", urb); - maybe_set_status (urb, -EPROTO); + status = -EPROTO; goto return_urb; } @@ -1294,7 +1288,7 @@ restart: /* NOTE: must not be iso! */ dev_dbg (dummy_dev(dum), "ep %s halted, urb %p\n", ep->ep.name, urb); - maybe_set_status (urb, -EPIPE); + status = -EPIPE; goto return_urb; } /* FIXME make sure both ends agree on maxpacket */ @@ -1312,7 +1306,7 @@ restart: w_value = le16_to_cpu(setup.wValue); if (le16_to_cpu(setup.wLength) != urb->transfer_buffer_length) { - maybe_set_status (urb, -EOVERFLOW); + status = -EOVERFLOW; goto return_urb; } @@ -1342,7 +1336,7 @@ restart: if (setup.bRequestType != Dev_Request) break; dum->address = w_value; - maybe_set_status (urb, 0); + status = 0; dev_dbg (udc_dev(dum), "set_address = %d\n", w_value); value = 0; @@ -1369,7 +1363,7 @@ restart: if (value == 0) { dum->devstatus |= (1 << w_value); - maybe_set_status (urb, 0); + status = 0; } } else if (setup.bRequestType == Ep_Request) { @@ -1381,7 +1375,7 @@ restart: } ep2->halted = 1; value = 0; - maybe_set_status (urb, 0); + status = 0; } break; case USB_REQ_CLEAR_FEATURE: @@ -1391,7 +1385,7 @@ restart: dum->devstatus &= ~(1 << USB_DEVICE_REMOTE_WAKEUP); value = 0; - maybe_set_status (urb, 0); + status = 0; break; default: value = -EOPNOTSUPP; @@ -1406,7 +1400,7 @@ restart: } ep2->halted = 0; value = 0; - maybe_set_status (urb, 0); + status = 0; } break; case USB_REQ_GET_STATUS: @@ -1443,7 +1437,7 @@ restart: urb->actual_length = min (2, urb->transfer_buffer_length); value = 0; - maybe_set_status (urb, 0); + status = 0; } break; } @@ -1470,7 +1464,7 @@ restart: dev_dbg (udc_dev(dum), "setup --> %d\n", value); - maybe_set_status (urb, -EPIPE); + status = -EPIPE; urb->actual_length = 0; } @@ -1487,7 +1481,7 @@ restart: * report random errors, to debug drivers. */ limit = max (limit, periodic_bytes (dum, ep)); - maybe_set_status (urb, -ENOSYS); + status = -ENOSYS; break; case PIPE_INTERRUPT: @@ -1501,12 +1495,12 @@ restart: default: treat_control_like_bulk: ep->last_io = jiffies; - total = transfer (dum, urb, ep, limit); + total = transfer(dum, urb, ep, limit, &status); break; } /* incomplete transfer? */ - if (urb->status == -EINPROGRESS) + if (status == -EINPROGRESS) continue; return_urb: @@ -1517,6 +1511,7 @@ return_urb: usb_hcd_unlink_urb_from_ep(dummy_to_hcd(dum), urb); spin_unlock (&dum->lock); + urb->status = status; usb_hcd_giveback_urb (dummy_to_hcd(dum), urb); spin_lock (&dum->lock); -- cgit v1.2.3-70-g09d2 From 14c04c0f88f228fee1f412be91d6edcb935c78aa Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 24 Aug 2007 15:40:19 -0400 Subject: USB: reorganize urb->status use in ehci-hcd This patch (as974) reorganizes the way ehci-hcd sets urb->status. It now keeps the information in a local variable until the last moment. The patch also simplifies the handling of -EREMOTEIO, since the only use of that code is to set the do_status flag. Signed-off-by: Alan Stern CC: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-q.c | 62 +++++++++++++++++++++++-------------------- drivers/usb/host/ehci-sched.c | 4 +-- 2 files changed, 35 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index a8f5408c161..794d27e0780 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -139,63 +139,65 @@ qh_refresh (struct ehci_hcd *ehci, struct ehci_qh *qh) /*-------------------------------------------------------------------------*/ -static void qtd_copy_status ( +static int qtd_copy_status ( struct ehci_hcd *ehci, struct urb *urb, size_t length, u32 token ) { + int status = -EINPROGRESS; + /* count IN/OUT bytes, not SETUP (even short packets) */ if (likely (QTD_PID (token) != 2)) urb->actual_length += length - QTD_LENGTH (token); /* don't modify error codes */ if (unlikely(urb->unlinked)) - return; + return status; /* force cleanup after short read; not always an error */ if (unlikely (IS_SHORT_READ (token))) - urb->status = -EREMOTEIO; + status = -EREMOTEIO; /* serious "can't proceed" faults reported by the hardware */ if (token & QTD_STS_HALT) { if (token & QTD_STS_BABBLE) { /* FIXME "must" disable babbling device's port too */ - urb->status = -EOVERFLOW; + status = -EOVERFLOW; } else if (token & QTD_STS_MMF) { /* fs/ls interrupt xfer missed the complete-split */ - urb->status = -EPROTO; + status = -EPROTO; } else if (token & QTD_STS_DBE) { - urb->status = (QTD_PID (token) == 1) /* IN ? */ + status = (QTD_PID (token) == 1) /* IN ? */ ? -ENOSR /* hc couldn't read data */ : -ECOMM; /* hc couldn't write data */ } else if (token & QTD_STS_XACT) { /* timeout, bad crc, wrong PID, etc; retried */ if (QTD_CERR (token)) - urb->status = -EPIPE; + status = -EPIPE; else { ehci_dbg (ehci, "devpath %s ep%d%s 3strikes\n", urb->dev->devpath, usb_pipeendpoint (urb->pipe), usb_pipein (urb->pipe) ? "in" : "out"); - urb->status = -EPROTO; + status = -EPROTO; } /* CERR nonzero + no errors + halt --> stall */ } else if (QTD_CERR (token)) - urb->status = -EPIPE; + status = -EPIPE; else /* unknown */ - urb->status = -EPROTO; + status = -EPROTO; ehci_vdbg (ehci, "dev%d ep%d%s qtd token %08x --> status %d\n", usb_pipedevice (urb->pipe), usb_pipeendpoint (urb->pipe), usb_pipein (urb->pipe) ? "in" : "out", - token, urb->status); + token, status); /* if async CSPLIT failed, try cleaning out the TT buffer */ - if (urb->status != -EPIPE + if (status != -EPIPE && urb->dev->tt && !usb_pipeint (urb->pipe) && ((token & QTD_STS_MMF) != 0 || QTD_CERR(token) == 0) @@ -212,10 +214,12 @@ static void qtd_copy_status ( usb_hub_tt_clear_buffer (urb->dev, urb->pipe); } } + + return status; } static void -ehci_urb_done (struct ehci_hcd *ehci, struct urb *urb) +ehci_urb_done(struct ehci_hcd *ehci, struct urb *urb, int status) __releases(ehci->lock) __acquires(ehci->lock) { @@ -231,17 +235,13 @@ __acquires(ehci->lock) qh_put (qh); } - spin_lock (&urb->lock); if (unlikely(urb->unlinked)) { COUNT(ehci->stats.unlink); } else { - if (likely(urb->status == -EINPROGRESS || - (urb->status == -EREMOTEIO && - !(urb->transfer_flags & URB_SHORT_NOT_OK)))) - urb->status = 0; + if (likely(status == -EINPROGRESS)) + status = 0; COUNT(ehci->stats.complete); } - spin_unlock (&urb->lock); #ifdef EHCI_URB_TRACE ehci_dbg (ehci, @@ -249,13 +249,14 @@ __acquires(ehci->lock) __FUNCTION__, urb->dev->devpath, urb, usb_pipeendpoint (urb->pipe), usb_pipein (urb->pipe) ? "in" : "out", - urb->status, + status, urb->actual_length, urb->transfer_buffer_length); #endif /* complete() can reenter this HCD */ usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); spin_unlock (&ehci->lock); + urb->status = status; usb_hcd_giveback_urb (ehci_to_hcd(ehci), urb); spin_lock (&ehci->lock); } @@ -276,6 +277,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) { struct ehci_qtd *last = NULL, *end = qh->dummy; struct list_head *entry, *tmp; + int last_status = -EINPROGRESS; int stopped; unsigned count = 0; int do_status = 0; @@ -304,6 +306,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) struct ehci_qtd *qtd; struct urb *urb; u32 token = 0; + int qtd_status; qtd = list_entry (entry, struct ehci_qtd, qtd_list); urb = qtd->urb; @@ -311,11 +314,12 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) /* clean up any state from previous QTD ...*/ if (last) { if (likely (last->urb != urb)) { - ehci_urb_done (ehci, last->urb); + ehci_urb_done(ehci, last->urb, last_status); count++; } ehci_qtd_free (ehci, last); last = NULL; + last_status = -EINPROGRESS; } /* ignore urbs submitted during completions we reported */ @@ -351,13 +355,13 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) stopped = 1; if (unlikely (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state))) - urb->status = -ESHUTDOWN; + last_status = -ESHUTDOWN; /* ignore active urbs unless some previous qtd * for the urb faulted (including short read) or * its urb was canceled. we may patch qh or qtds. */ - if (likely(urb->status == -EINPROGRESS && + if (likely(last_status == -EINPROGRESS && !urb->unlinked)) continue; @@ -386,14 +390,14 @@ halt: } /* remove it from the queue */ - spin_lock (&urb->lock); - qtd_copy_status (ehci, urb, qtd->length, token); - if (unlikely(urb->status == -EREMOTEIO)) { + qtd_status = qtd_copy_status(ehci, urb, qtd->length, token); + if (unlikely(qtd_status == -EREMOTEIO)) { do_status = (!urb->unlinked && usb_pipecontrol(urb->pipe)); - urb->status = 0; + qtd_status = 0; } - spin_unlock (&urb->lock); + if (likely(last_status == -EINPROGRESS)) + last_status = qtd_status; if (stopped && qtd->qtd_list.prev != &qh->qtd_list) { last = list_entry (qtd->qtd_list.prev, @@ -406,7 +410,7 @@ halt: /* last urb's completion might still need calling */ if (likely (last != NULL)) { - ehci_urb_done (ehci, last->urb); + ehci_urb_done(ehci, last->urb, last_status); count++; ehci_qtd_free (ehci, last); } diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 8b267b3fd2b..80d99bce2b3 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -1627,7 +1627,7 @@ itd_complete ( /* give urb back to the driver ... can be out-of-order */ dev = urb->dev; - ehci_urb_done (ehci, urb); + ehci_urb_done(ehci, urb, 0); urb = NULL; /* defer stopping schedule; completion can submit */ @@ -2000,7 +2000,7 @@ sitd_complete ( /* give urb back to the driver */ dev = urb->dev; - ehci_urb_done (ehci, urb); + ehci_urb_done(ehci, urb, 0); urb = NULL; /* defer stopping schedule; completion can submit */ -- cgit v1.2.3-70-g09d2 From 55d8496837cf124f68656e4242a5e20eb592fd54 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 24 Aug 2007 15:40:34 -0400 Subject: USB: reorganize urb->status use in ohci-hcd This patch (as975) reorganizes the way ohci-hcd sets urb->status. It now keeps the information in a local variable until the last moment. Signed-off-by: Alan Stern CC: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-dbg.c | 8 ++++---- drivers/usb/host/ohci-hcd.c | 15 +++++++-------- drivers/usb/host/ohci-q.c | 38 +++++++++++++++++--------------------- 3 files changed, 28 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c index f61c6cdd06f..ebab5ce8f5c 100644 --- a/drivers/usb/host/ohci-dbg.c +++ b/drivers/usb/host/ohci-dbg.c @@ -24,7 +24,7 @@ * small: 0) header + data packets 1) just header */ static void __maybe_unused -urb_print (struct urb * urb, char * str, int small) +urb_print(struct urb * urb, char * str, int small, int status) { unsigned int pipe= urb->pipe; @@ -34,7 +34,7 @@ urb_print (struct urb * urb, char * str, int small) } #ifndef OHCI_VERBOSE_DEBUG - if (urb->status != 0) + if (status != 0) #endif dbg("%s %p dev=%d ep=%d%s-%s flags=%x len=%d/%d stat=%d", str, @@ -46,7 +46,7 @@ urb_print (struct urb * urb, char * str, int small) urb->transfer_flags, urb->actual_length, urb->transfer_buffer_length, - urb->status); + status); #ifdef OHCI_VERBOSE_DEBUG if (!small) { @@ -66,7 +66,7 @@ urb_print (struct urb * urb, char * str, int small) urb->transfer_buffer_length: urb->actual_length; for (i = 0; i < 16 && i < len; i++) printk (" %02x", ((__u8 *) urb->transfer_buffer) [i]); - printk ("%s stat:%d\n", i < len? "...": "", urb->status); + printk ("%s stat:%d\n", i < len? "...": "", status); } } #endif diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 6b06ab69938..f7c6ced2bc0 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -129,7 +129,7 @@ static int ohci_urb_enqueue ( int retval = 0; #ifdef OHCI_VERBOSE_DEBUG - urb_print (urb, "SUB", usb_pipein (pipe)); + urb_print(urb, "SUB", usb_pipein(pipe), -EINPROGRESS); #endif /* every endpoint has a ed, locate and maybe (re)initialize it */ @@ -240,8 +240,8 @@ fail: } /* - * decouple the URB from the HC queues (TDs, urb_priv); it's - * already marked using urb->status. reporting is always done + * decouple the URB from the HC queues (TDs, urb_priv). + * reporting is always done * asynchronously, and we might be dealing with an urb that's * partially transferred, or an ED with other urbs being unlinked. */ @@ -252,7 +252,7 @@ static int ohci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) int rc; #ifdef OHCI_VERBOSE_DEBUG - urb_print (urb, "UNLINK", 1); + urb_print(urb, "UNLINK", 1, status); #endif spin_lock_irqsave (&ohci->lock, flags); @@ -277,7 +277,7 @@ static int ohci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) * any more ... just clean up every urb's memory. */ if (urb->hcpriv) - finish_urb (ohci, urb); + finish_urb(ohci, urb, status); } spin_unlock_irqrestore (&ohci->lock, flags); return rc; @@ -927,9 +927,8 @@ static int ohci_restart (struct ohci_hcd *ohci) ed, ed->state); } - spin_lock (&urb->lock); - urb->status = -ESHUTDOWN; - spin_unlock (&urb->lock); + if (!urb->unlinked) + urb->unlinked = -ESHUTDOWN; } finish_unlinks (ohci, 0); spin_unlock_irq(&ohci->lock); diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index 860e55ff67a..13d31edd1a8 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -36,18 +36,15 @@ static void urb_free_priv (struct ohci_hcd *hc, urb_priv_t *urb_priv) * PRECONDITION: ohci lock held, irqs blocked. */ static void -finish_urb (struct ohci_hcd *ohci, struct urb *urb) +finish_urb(struct ohci_hcd *ohci, struct urb *urb, int status) __releases(ohci->lock) __acquires(ohci->lock) { // ASSERT (urb->hcpriv != 0); urb_free_priv (ohci, urb->hcpriv); - - spin_lock (&urb->lock); - if (likely (urb->status == -EINPROGRESS)) - urb->status = 0; - spin_unlock (&urb->lock); + if (likely(status == -EINPROGRESS)) + status = 0; switch (usb_pipetype (urb->pipe)) { case PIPE_ISOCHRONOUS: @@ -59,12 +56,13 @@ __acquires(ohci->lock) } #ifdef OHCI_VERBOSE_DEBUG - urb_print (urb, "RET", usb_pipeout (urb->pipe)); + urb_print(urb, "RET", usb_pipeout (urb->pipe), status); #endif /* urb->complete() can reenter this HCD */ usb_hcd_unlink_urb_from_ep(ohci_to_hcd(ohci), urb); spin_unlock (&ohci->lock); + urb->status = status; usb_hcd_giveback_urb (ohci_to_hcd(ohci), urb); spin_lock (&ohci->lock); @@ -702,19 +700,18 @@ static void td_submit_urb ( * Done List handling functions *-------------------------------------------------------------------------*/ -/* calculate transfer length/status and update the urb - * PRECONDITION: irqsafe (only for urb->status locking) - */ -static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td) +/* calculate transfer length/status and update the urb */ +static int td_done(struct ohci_hcd *ohci, struct urb *urb, struct td *td) { u32 tdINFO = hc32_to_cpup (ohci, &td->hwINFO); int cc = 0; + int status = -EINPROGRESS; list_del (&td->td_list); /* ISO ... drivers see per-TD length/status */ if (tdINFO & TD_ISO) { - u16 tdPSW = ohci_hwPSW (ohci, td, 0); + u16 tdPSW = ohci_hwPSW(ohci, td, 0); int dlen = 0; /* NOTE: assumes FC in tdINFO == 0, and that @@ -723,7 +720,7 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td) cc = (tdPSW >> 12) & 0xF; if (tdINFO & TD_CC) /* hc didn't touch? */ - return; + return status; if (usb_pipeout (urb->pipe)) dlen = urb->iso_frame_desc [td->index].length; @@ -756,11 +753,8 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td) if (cc == TD_DATAUNDERRUN && !(urb->transfer_flags & URB_SHORT_NOT_OK)) cc = TD_CC_NOERROR; - if (cc != TD_CC_NOERROR && cc < 0x0E) { - spin_lock (&urb->lock); - urb->status = cc_to_error[cc]; - spin_unlock (&urb->lock); - } + if (cc != TD_CC_NOERROR && cc < 0x0E) + status = cc_to_error[cc]; /* count all non-empty packets except control SETUP packet */ if ((type != PIPE_CONTROL || td->index != 0) && tdBE != 0) { @@ -779,6 +773,7 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td) urb->actual_length, urb->transfer_buffer_length); } + return status; } /*-------------------------------------------------------------------------*/ @@ -979,7 +974,7 @@ rescan_this: /* if URB is done, clean up */ if (urb_priv->td_cnt == urb_priv->length) { modified = completed = 1; - finish_urb (ohci, urb); + finish_urb(ohci, urb, 0); } } if (completed && !list_empty (&ed->td_list)) @@ -1062,14 +1057,15 @@ static void takeback_td(struct ohci_hcd *ohci, struct td *td) struct urb *urb = td->urb; urb_priv_t *urb_priv = urb->hcpriv; struct ed *ed = td->ed; + int status; /* update URB's length and status from TD */ - td_done(ohci, urb, td); + status = td_done(ohci, urb, td); urb_priv->td_cnt++; /* If all this urb's TDs are done, call complete() */ if (urb_priv->td_cnt == urb_priv->length) - finish_urb(ohci, urb); + finish_urb(ohci, urb, status); /* clean schedule: unlink EDs that are no longer busy */ if (list_empty(&ed->td_list)) { -- cgit v1.2.3-70-g09d2 From 65e51098d9094c7e840b6d6291867b95538d9442 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 24 Aug 2007 15:40:47 -0400 Subject: USB: reorganize urb->status use in sl811-hcd This patch (as976) reorganizes the way sl811-hcd sets urb->status. It now keeps the information in a local variable until the last moment. The patch also improves the handling of faults during the status stage of a control transfer, since it no longer needs to retain the error information from the earlier stages. Signed-off-by: Alan Stern CC: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/sl811-hcd.c | 32 +++++++++++--------------------- 1 file changed, 11 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index f0fa94148d9..515152809d3 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -435,11 +435,8 @@ static void finish_request( if (usb_pipecontrol(urb->pipe)) ep->nextpid = USB_PID_SETUP; - spin_lock(&urb->lock); - urb->status = status; - spin_unlock(&urb->lock); - usb_hcd_unlink_urb_from_ep(sl811_to_hcd(sl811), urb); + urb->status = status; spin_unlock(&sl811->lock); usb_hcd_giveback_urb(sl811_to_hcd(sl811), urb); spin_lock(&sl811->lock); @@ -537,27 +534,20 @@ done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank) bank + SL11H_XFERCNTREG); if (len > ep->length) { len = ep->length; - urb->status = -EOVERFLOW; + urbstat = -EOVERFLOW; } urb->actual_length += len; sl811_read_buf(sl811, SL811HS_PACKET_BUF(bank == 0), buf, len); usb_dotoggle(udev, ep->epnum, 0); - if (urb->actual_length == urb->transfer_buffer_length - || len < ep->maxpacket) - urbstat = 0; - if (usb_pipecontrol(urb->pipe) && urbstat == 0) { - - /* NOTE if the status stage STALLs (why?), - * this reports the wrong urb status. - */ - spin_lock(&urb->lock); - if (urb->status == -EINPROGRESS) - urb->status = urbstat; - spin_unlock(&urb->lock); - - urb = NULL; - ep->nextpid = USB_PID_ACK; + if (urbstat == -EINPROGRESS && + (len < ep->maxpacket || + urb->actual_length == + urb->transfer_buffer_length)) { + if (usb_pipecontrol(urb->pipe)) + ep->nextpid = USB_PID_ACK; + else + urbstat = 0; } break; case USB_PID_SETUP: @@ -597,7 +587,7 @@ done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank) bank, status, ep, urbstat); } - if (urb && (urbstat != -EINPROGRESS || urb->unlinked)) + if (urbstat != -EINPROGRESS || urb->unlinked) finish_request(sl811, ep, urb, urbstat); } -- cgit v1.2.3-70-g09d2 From 888fda47051716765175d0008450126c837adb32 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 24 Aug 2007 15:41:18 -0400 Subject: USB: reorganize urb->status use in r8a66597-hcd This patch (as977) reorganizes the way r8a66597-hcd sets urb->status. It now keeps the information in a local variable until the last moment. Parts of this patch were written by Yoshihiro Shimoda. Signed-off-by: Alan Stern CC: Yoshihiro Shimoda Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/r8a66597-hcd.c | 61 ++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 98b9e054754..fea6036771f 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -1109,7 +1109,7 @@ static void set_td_timer(struct r8a66597 *r8a66597, struct r8a66597_td *td) /* this function must be called with interrupt disabled */ static void finish_request(struct r8a66597 *r8a66597, struct r8a66597_td *td, - u16 pipenum, struct urb *urb) + u16 pipenum, struct urb *urb, int status) __releases(r8a66597->lock) __acquires(r8a66597->lock) { int restart = 0; @@ -1118,7 +1118,7 @@ __releases(r8a66597->lock) __acquires(r8a66597->lock) r8a66597->timeout_map &= ~(1 << pipenum); if (likely(td)) { - if (td->set_address && (urb->status != 0 || urb->unlinked)) + if (td->set_address && (status != 0 || urb->unlinked)) r8a66597->address_map &= ~(1 << urb->setup_packet[2]); pipe_toggle_save(r8a66597, td->pipe, urb); @@ -1135,6 +1135,7 @@ __releases(r8a66597->lock) __acquires(r8a66597->lock) usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597), urb); + urb->status = status; spin_unlock(&r8a66597->lock); usb_hcd_giveback_urb(hcd, urb); spin_lock(&r8a66597->lock); @@ -1167,11 +1168,10 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum) fifo_change_from_pipe(r8a66597, td->pipe); tmp = r8a66597_read(r8a66597, td->pipe->fifoctr); if (unlikely((tmp & FRDY) == 0)) { - urb->status = -EPIPE; pipe_stop(r8a66597, td->pipe); pipe_irq_disable(r8a66597, pipenum); err("in fifo not ready (%d)", pipenum); - finish_request(r8a66597, td, pipenum, td->urb); + finish_request(r8a66597, td, pipenum, td->urb, -EPIPE); return; } @@ -1224,10 +1224,8 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum) buf, size); } - if (finish && pipenum != 0) { - td->urb->status = status; - finish_request(r8a66597, td, pipenum, urb); - } + if (finish && pipenum != 0) + finish_request(r8a66597, td, pipenum, urb, status); } static void packet_write(struct r8a66597 *r8a66597, u16 pipenum) @@ -1245,11 +1243,10 @@ static void packet_write(struct r8a66597 *r8a66597, u16 pipenum) fifo_change_from_pipe(r8a66597, td->pipe); tmp = r8a66597_read(r8a66597, td->pipe->fifoctr); if (unlikely((tmp & FRDY) == 0)) { - urb->status = -EPIPE; pipe_stop(r8a66597, td->pipe); pipe_irq_disable(r8a66597, pipenum); err("out write fifo not ready. (%d)", pipenum); - finish_request(r8a66597, td, pipenum, td->urb); + finish_request(r8a66597, td, pipenum, urb, -EPIPE); return; } @@ -1294,7 +1291,7 @@ static void packet_write(struct r8a66597 *r8a66597, u16 pipenum) } -static void check_next_phase(struct r8a66597 *r8a66597) +static void check_next_phase(struct r8a66597 *r8a66597, int status) { struct r8a66597_td *td = r8a66597_get_td(r8a66597, 0); struct urb *urb; @@ -1320,28 +1317,28 @@ static void check_next_phase(struct r8a66597 *r8a66597) break; case USB_PID_ACK: finish = 1; - urb->status = 0; break; } - if (finish || urb->unlinked) - finish_request(r8a66597, td, 0, urb); + if (finish || status != 0 || urb->unlinked) + finish_request(r8a66597, td, 0, urb, status); else start_transfer(r8a66597, td); } -static void set_urb_error(struct r8a66597 *r8a66597, u16 pipenum) +static int get_urb_error(struct r8a66597 *r8a66597, u16 pipenum) { struct r8a66597_td *td = r8a66597_get_td(r8a66597, pipenum); - if (td && td->urb) { + if (td) { u16 pid = r8a66597_read(r8a66597, td->pipe->pipectr) & PID; if (pid == PID_NAK) - td->urb->status = -ECONNRESET; + return -ECONNRESET; else - td->urb->status = -EPIPE; + return -EPIPE; } + return 0; } static void irq_pipe_ready(struct r8a66597 *r8a66597) @@ -1360,7 +1357,7 @@ static void irq_pipe_ready(struct r8a66597 *r8a66597) packet_read(r8a66597, 0); else pipe_irq_disable(r8a66597, 0); - check_next_phase(r8a66597); + check_next_phase(r8a66597, 0); } for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) { @@ -1394,7 +1391,7 @@ static void irq_pipe_empty(struct r8a66597 *r8a66597) td = r8a66597_get_td(r8a66597, 0); if (td && td->type != USB_PID_OUT) disable_irq_empty(r8a66597, 0); - check_next_phase(r8a66597); + check_next_phase(r8a66597, 0); } for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) { @@ -1409,8 +1406,8 @@ static void irq_pipe_empty(struct r8a66597 *r8a66597) if ((tmp & INBUFM) == 0) { disable_irq_empty(r8a66597, pipenum); pipe_irq_disable(r8a66597, pipenum); - td->urb->status = 0; - finish_request(r8a66597, td, pipenum, td->urb); + finish_request(r8a66597, td, pipenum, td->urb, + 0); } } } @@ -1421,15 +1418,16 @@ static void irq_pipe_nrdy(struct r8a66597 *r8a66597) u16 check; u16 pipenum; u16 mask; + int status; mask = r8a66597_read(r8a66597, NRDYSTS) & r8a66597_read(r8a66597, NRDYENB); r8a66597_write(r8a66597, ~mask, NRDYSTS); if (mask & NRDY0) { cfifo_change(r8a66597, 0); - set_urb_error(r8a66597, 0); + status = get_urb_error(r8a66597, 0); pipe_irq_disable(r8a66597, 0); - check_next_phase(r8a66597); + check_next_phase(r8a66597, status); } for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) { @@ -1440,10 +1438,10 @@ static void irq_pipe_nrdy(struct r8a66597 *r8a66597) if (unlikely(!td)) continue; - set_urb_error(r8a66597, pipenum); + status = get_urb_error(r8a66597, pipenum); pipe_irq_disable(r8a66597, pipenum); pipe_stop(r8a66597, td->pipe); - finish_request(r8a66597, td, pipenum, td->urb); + finish_request(r8a66597, td, pipenum, td->urb, status); } } } @@ -1463,6 +1461,7 @@ static irqreturn_t r8a66597_irq(struct usb_hcd *hcd) u16 intsts0, intsts1, intsts2; u16 intenb0, intenb1, intenb2; u16 mask0, mask1, mask2; + int status; spin_lock(&r8a66597->lock); @@ -1506,12 +1505,12 @@ static irqreturn_t r8a66597_irq(struct usb_hcd *hcd) } if (mask1 & SIGN) { r8a66597_write(r8a66597, ~SIGN, INTSTS1); - set_urb_error(r8a66597, 0); - check_next_phase(r8a66597); + status = get_urb_error(r8a66597, 0); + check_next_phase(r8a66597, status); } if (mask1 & SACK) { r8a66597_write(r8a66597, ~SACK, INTSTS1); - check_next_phase(r8a66597); + check_next_phase(r8a66597, 0); } } if (mask0) { @@ -1790,7 +1789,7 @@ static int r8a66597_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, pipe_stop(r8a66597, td->pipe); pipe_irq_disable(r8a66597, td->pipenum); disable_irq_empty(r8a66597, td->pipenum); - finish_request(r8a66597, td, td->pipenum, urb); + finish_request(r8a66597, td, td->pipenum, urb, status); } done: spin_unlock_irqrestore(&r8a66597->lock, flags); @@ -1824,7 +1823,7 @@ static void r8a66597_endpoint_disable(struct usb_hcd *hcd, td = r8a66597_get_td(r8a66597, pipenum); if (td) urb = td->urb; - finish_request(r8a66597, td, pipenum, urb); + finish_request(r8a66597, td, pipenum, urb, -ESHUTDOWN); kfree(hep->hcpriv); hep->hcpriv = NULL; spin_unlock_irqrestore(&r8a66597->lock, flags); -- cgit v1.2.3-70-g09d2 From 9347d51c52afcf1a77d2104f162cf8a085624c83 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 24 Aug 2007 15:41:41 -0400 Subject: USB: reorganize urb->status use in usbmon This patch (as978) reorganizes the way usbmon uses urb->status. It now accepts the status value as an argument. Signed-off-by: Alan Stern Acked-by: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 2 +- drivers/usb/core/hcd.h | 10 ++++++---- drivers/usb/mon/mon_bin.c | 10 +++++----- drivers/usb/mon/mon_main.c | 11 ++++++----- drivers/usb/mon/mon_text.c | 10 +++++----- drivers/usb/mon/usb_mon.h | 2 +- 6 files changed, 24 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 8b17babf5c5..4ac021e42cd 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1275,7 +1275,7 @@ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb) urb->status = -EREMOTEIO; unmap_urb_for_dma(hcd, urb); - usbmon_urb_complete(&hcd->self, urb); + usbmon_urb_complete(&hcd->self, urb, urb->status); usb_unanchor_urb(urb); /* pass ownership to the completion handler */ diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 745be2566f6..729b7a03acd 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -413,7 +413,7 @@ static inline void usbfs_cleanup(void) { } struct usb_mon_operations { void (*urb_submit)(struct usb_bus *bus, struct urb *urb); void (*urb_submit_error)(struct usb_bus *bus, struct urb *urb, int err); - void (*urb_complete)(struct usb_bus *bus, struct urb *urb); + void (*urb_complete)(struct usb_bus *bus, struct urb *urb, int status); /* void (*urb_unlink)(struct usb_bus *bus, struct urb *urb); */ }; @@ -432,10 +432,11 @@ static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb, (*mon_ops->urb_submit_error)(bus, urb, error); } -static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb) +static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb, + int status) { if (bus->monitored) - (*mon_ops->urb_complete)(bus, urb); + (*mon_ops->urb_complete)(bus, urb, status); } int usb_mon_register(struct usb_mon_operations *ops); @@ -446,7 +447,8 @@ void usb_mon_deregister(void); static inline void usbmon_urb_submit(struct usb_bus *bus, struct urb *urb) {} static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb, int error) {} -static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb) {} +static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb, + int status) {} #endif /* CONFIG_USB_MON */ diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c index 3d6f03819ff..f06e4e2b49d 100644 --- a/drivers/usb/mon/mon_bin.c +++ b/drivers/usb/mon/mon_bin.c @@ -386,7 +386,7 @@ static char mon_bin_get_data(const struct mon_reader_bin *rp, } static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, - char ev_type) + char ev_type, int status) { const struct usb_endpoint_descriptor *epd = &urb->ep->desc; unsigned long flags; @@ -452,7 +452,7 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, ep->id = (unsigned long) urb; ep->ts_sec = ts.tv_sec; ep->ts_usec = ts.tv_usec; - ep->status = urb->status; + ep->status = status; ep->len_urb = urb_length; ep->len_cap = length; @@ -475,13 +475,13 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, static void mon_bin_submit(void *data, struct urb *urb) { struct mon_reader_bin *rp = data; - mon_bin_event(rp, urb, 'S'); + mon_bin_event(rp, urb, 'S', -EINPROGRESS); } -static void mon_bin_complete(void *data, struct urb *urb) +static void mon_bin_complete(void *data, struct urb *urb, int status) { struct mon_reader_bin *rp = data; - mon_bin_event(rp, urb, 'C'); + mon_bin_event(rp, urb, 'C', status); } static void mon_bin_error(void *data, struct urb *urb, int error) diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c index 2e317bd79e9..b371ffd39d3 100644 --- a/drivers/usb/mon/mon_main.c +++ b/drivers/usb/mon/mon_main.c @@ -129,7 +129,8 @@ static void mon_submit_error(struct usb_bus *ubus, struct urb *urb, int error) /* */ -static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb) +static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb, + int status) { unsigned long flags; struct list_head *pos; @@ -139,18 +140,18 @@ static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb) mbus->cnt_events++; list_for_each (pos, &mbus->r_list) { r = list_entry(pos, struct mon_reader, r_link); - r->rnf_complete(r->r_data, urb); + r->rnf_complete(r->r_data, urb, status); } spin_unlock_irqrestore(&mbus->lock, flags); } -static void mon_complete(struct usb_bus *ubus, struct urb *urb) +static void mon_complete(struct usb_bus *ubus, struct urb *urb, int status) { struct mon_bus *mbus; if ((mbus = ubus->mon_bus) != NULL) - mon_bus_complete(mbus, urb); - mon_bus_complete(&mon_bus0, urb); + mon_bus_complete(mbus, urb, status); + mon_bus_complete(&mon_bus0, urb, status); } /* int (*unlink_urb) (struct urb *urb, int status); */ diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c index 663a702a17d..ebb04ac4857 100644 --- a/drivers/usb/mon/mon_text.c +++ b/drivers/usb/mon/mon_text.c @@ -183,7 +183,7 @@ static inline unsigned int mon_get_timestamp(void) } static void mon_text_event(struct mon_reader_text *rp, struct urb *urb, - char ev_type) + char ev_type, int status) { struct mon_event_text *ep; unsigned int stamp; @@ -210,7 +210,7 @@ static void mon_text_event(struct mon_reader_text *rp, struct urb *urb, ep->length = (ev_type == 'S') ? urb->transfer_buffer_length : urb->actual_length; /* Collecting status makes debugging sense for submits, too */ - ep->status = urb->status; + ep->status = status; if (ep->xfertype == USB_ENDPOINT_XFER_INT) { ep->interval = urb->interval; @@ -248,13 +248,13 @@ static void mon_text_event(struct mon_reader_text *rp, struct urb *urb, static void mon_text_submit(void *data, struct urb *urb) { struct mon_reader_text *rp = data; - mon_text_event(rp, urb, 'S'); + mon_text_event(rp, urb, 'S', -EINPROGRESS); } -static void mon_text_complete(void *data, struct urb *urb) +static void mon_text_complete(void *data, struct urb *urb, int status) { struct mon_reader_text *rp = data; - mon_text_event(rp, urb, 'C'); + mon_text_event(rp, urb, 'C', status); } static void mon_text_error(void *data, struct urb *urb, int error) diff --git a/drivers/usb/mon/usb_mon.h b/drivers/usb/mon/usb_mon.h index f68ad6d99ad..f5d84ff8c10 100644 --- a/drivers/usb/mon/usb_mon.h +++ b/drivers/usb/mon/usb_mon.h @@ -46,7 +46,7 @@ struct mon_reader { void (*rnf_submit)(void *data, struct urb *urb); void (*rnf_error)(void *data, struct urb *urb, int error); - void (*rnf_complete)(void *data, struct urb *urb); + void (*rnf_complete)(void *data, struct urb *urb, int status); }; void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r); -- cgit v1.2.3-70-g09d2 From 4a00027dcb088bf90fa8fb14a7e8ba3506d78f22 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 24 Aug 2007 15:42:24 -0400 Subject: USB: Eliminate urb->status usage! This patch (as979) removes the last vestiges of urb->status from the host controller drivers and the root-hub emulator. Now the field doesn't get set until just before the URB's completion routine is called. Signed-off-by: Alan Stern CC: David Brownell CC: Olav Kongas CC: Yoshihiro Shimoda CC: Tony Olech Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 22 +++++++++++----------- drivers/usb/core/hcd.h | 3 ++- drivers/usb/gadget/dummy_hcd.c | 3 +-- drivers/usb/host/ehci-q.c | 3 +-- drivers/usb/host/isp116x-hcd.c | 15 +++++---------- drivers/usb/host/ohci-q.c | 3 +-- drivers/usb/host/r8a66597-hcd.c | 8 +++----- drivers/usb/host/sl811-hcd.c | 3 +-- drivers/usb/host/u132-hcd.c | 36 +++++++++++++++++------------------- drivers/usb/host/uhci-hcd.h | 15 --------------- drivers/usb/host/uhci-q.c | 12 ++++-------- 11 files changed, 46 insertions(+), 77 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 4ac021e42cd..1c5e5d35e08 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -532,7 +532,6 @@ error: /* any errors get returned through the urb completion */ spin_lock_irq(&hcd_root_hub_lock); - urb->status = status; usb_hcd_unlink_urb_from_ep(hcd, urb); /* This peculiar use of spinlocks echoes what real HC drivers do. @@ -540,7 +539,7 @@ error: * RT-friendly. */ spin_unlock(&hcd_root_hub_lock); - usb_hcd_giveback_urb(hcd, urb); + usb_hcd_giveback_urb(hcd, urb, status); spin_lock(&hcd_root_hub_lock); spin_unlock_irq(&hcd_root_hub_lock); @@ -578,13 +577,12 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd) if (urb) { hcd->poll_pending = 0; hcd->status_urb = NULL; - urb->status = 0; urb->actual_length = length; memcpy(urb->transfer_buffer, buffer, length); usb_hcd_unlink_urb_from_ep(hcd, urb); spin_unlock(&hcd_root_hub_lock); - usb_hcd_giveback_urb(hcd, urb); + usb_hcd_giveback_urb(hcd, urb, 0); spin_lock(&hcd_root_hub_lock); } else { length = 0; @@ -677,7 +675,7 @@ static int usb_rh_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) usb_hcd_unlink_urb_from_ep(hcd, urb); spin_unlock(&hcd_root_hub_lock); - usb_hcd_giveback_urb(hcd, urb); + usb_hcd_giveback_urb(hcd, urb, status); spin_lock(&hcd_root_hub_lock); } } @@ -1252,6 +1250,7 @@ int usb_hcd_unlink_urb (struct urb *urb, int status) * usb_hcd_giveback_urb - return URB from HCD to device driver * @hcd: host controller returning the URB * @urb: urb being returned to the USB device driver. + * @status: completion status code for the URB. * Context: in_interrupt() * * This hands the URB from HCD to its USB device driver, using its @@ -1260,25 +1259,26 @@ int usb_hcd_unlink_urb (struct urb *urb, int status) * the device driver won't cause problems if it frees, modifies, * or resubmits this URB. * - * If @urb was unlinked, the value of @urb->status will be overridden by + * If @urb was unlinked, the value of @status will be overridden by * @urb->unlinked. Erroneous short transfers are detected in case * the HCD hasn't checked for them. */ -void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb) +void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status) { urb->hcpriv = NULL; if (unlikely(urb->unlinked)) - urb->status = urb->unlinked; + status = urb->unlinked; else if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) && urb->actual_length < urb->transfer_buffer_length && - !urb->status)) - urb->status = -EREMOTEIO; + !status)) + status = -EREMOTEIO; unmap_urb_for_dma(hcd, urb); - usbmon_urb_complete(&hcd->self, urb, urb->status); + usbmon_urb_complete(&hcd->self, urb, status); usb_unanchor_urb(urb); /* pass ownership to the completion handler */ + urb->status = status; urb->complete (urb); atomic_dec (&urb->use_count); if (unlikely (urb->reject)) diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 729b7a03acd..0fc7b95259f 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -217,7 +217,8 @@ extern void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb); extern int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags); extern int usb_hcd_unlink_urb (struct urb *urb, int status); -extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb); +extern void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, + int status); extern void usb_hcd_endpoint_disable (struct usb_device *udev, struct usb_host_endpoint *ep); extern int usb_hcd_get_frame_number (struct usb_device *udev); diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index c1af7bab26f..58e4d720880 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -1511,8 +1511,7 @@ return_urb: usb_hcd_unlink_urb_from_ep(dummy_to_hcd(dum), urb); spin_unlock (&dum->lock); - urb->status = status; - usb_hcd_giveback_urb (dummy_to_hcd(dum), urb); + usb_hcd_giveback_urb(dummy_to_hcd(dum), urb, status); spin_lock (&dum->lock); goto restart; diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 794d27e0780..b10f39c047e 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -256,8 +256,7 @@ __acquires(ehci->lock) /* complete() can reenter this HCD */ usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); spin_unlock (&ehci->lock); - urb->status = status; - usb_hcd_giveback_urb (ehci_to_hcd(ehci), urb); + usb_hcd_giveback_urb(ehci_to_hcd(ehci), urb, status); spin_lock (&ehci->lock); } diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index 35b3507ff40..c27417f5b9d 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -277,7 +277,7 @@ static void preproc_atl_queue(struct isp116x *isp116x) processed urbs. */ static void finish_request(struct isp116x *isp116x, struct isp116x_ep *ep, - struct urb *urb) + struct urb *urb, int status) __releases(isp116x->lock) __acquires(isp116x->lock) { unsigned i; @@ -291,7 +291,7 @@ __releases(isp116x->lock) __acquires(isp116x->lock) usb_hcd_unlink_urb_from_ep(isp116x_to_hcd(isp116x), urb); spin_unlock(&isp116x->lock); - usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb); + usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb, status); spin_lock(&isp116x->lock); /* take idle endpoints out of the schedule */ @@ -453,13 +453,8 @@ static void postproc_atl_queue(struct isp116x *isp116x) } done: - if (status != -EINPROGRESS) { - spin_lock(&urb->lock); - urb->status = status; - spin_unlock(&urb->lock); - } - if (urb->status != -EINPROGRESS || urb->unlinked) - finish_request(isp116x, ep, urb); + if (status != -EINPROGRESS || urb->unlinked) + finish_request(isp116x, ep, urb, status); } } @@ -853,7 +848,7 @@ static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, } if (urb) - finish_request(isp116x, ep, urb); + finish_request(isp116x, ep, urb, status); done: spin_unlock_irqrestore(&isp116x->lock, flags); return rc; diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index 13d31edd1a8..51817322232 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -62,8 +62,7 @@ __acquires(ohci->lock) /* urb->complete() can reenter this HCD */ usb_hcd_unlink_urb_from_ep(ohci_to_hcd(ohci), urb); spin_unlock (&ohci->lock); - urb->status = status; - usb_hcd_giveback_urb (ohci_to_hcd(ohci), urb); + usb_hcd_giveback_urb(ohci_to_hcd(ohci), urb, status); spin_lock (&ohci->lock); /* stop periodic dma if it's not needed */ diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index fea6036771f..fd00f1e33fb 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -782,12 +782,12 @@ static void force_dequeue(struct r8a66597 *r8a66597, u16 pipenum, u16 address) kfree(td); if (urb) { - urb->status = -ENODEV; usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597), urb); spin_unlock(&r8a66597->lock); - usb_hcd_giveback_urb(r8a66597_to_hcd(r8a66597), urb); + usb_hcd_giveback_urb(r8a66597_to_hcd(r8a66597), urb, + -ENODEV); spin_lock(&r8a66597->lock); } break; @@ -1134,10 +1134,8 @@ __releases(r8a66597->lock) __acquires(r8a66597->lock) urb->start_frame = r8a66597_get_frame(hcd); usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597), urb); - - urb->status = status; spin_unlock(&r8a66597->lock); - usb_hcd_giveback_urb(hcd, urb); + usb_hcd_giveback_urb(hcd, urb, status); spin_lock(&r8a66597->lock); } diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index 515152809d3..94d859aa73f 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -436,9 +436,8 @@ static void finish_request( ep->nextpid = USB_PID_SETUP; usb_hcd_unlink_urb_from_ep(sl811_to_hcd(sl811), urb); - urb->status = status; spin_unlock(&sl811->lock); - usb_hcd_giveback_urb(sl811_to_hcd(sl811), urb); + usb_hcd_giveback_urb(sl811_to_hcd(sl811), urb, status); spin_lock(&sl811->lock); /* leave active endpoints in the schedule */ diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index db800a434b8..2b379a78d0d 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -518,7 +518,6 @@ static void u132_hcd_giveback_urb(struct u132 *u132, struct u132_endp *endp, unsigned long irqs; struct usb_hcd *hcd = u132_to_hcd(u132); urb->error_count = 0; - urb->status = status; spin_lock_irqsave(&endp->queue_lock.slock, irqs); usb_hcd_unlink_urb_from_ep(hcd, urb); endp->queue_next += 1; @@ -542,7 +541,7 @@ static void u132_hcd_giveback_urb(struct u132 *u132, struct u132_endp *endp, u132_ring_queue_work(u132, ring, 0); up(&u132->scheduler_lock); u132_endp_put_kref(u132, endp); - usb_hcd_giveback_urb(hcd, urb); + usb_hcd_giveback_urb(hcd, urb, status); return; } @@ -558,7 +557,6 @@ static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp, unsigned long irqs; struct usb_hcd *hcd = u132_to_hcd(u132); urb->error_count = 0; - urb->status = status; spin_lock_irqsave(&endp->queue_lock.slock, irqs); usb_hcd_unlink_urb_from_ep(hcd, urb); endp->queue_next += 1; @@ -575,7 +573,7 @@ static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp, endp->active = 0; spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); kfree(urbq); - } usb_hcd_giveback_urb(hcd, urb); + } usb_hcd_giveback_urb(hcd, urb, status); return; } @@ -719,7 +717,7 @@ static void u132_hcd_interrupt_recv(void *data, struct urb *urb, u8 *buf, dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -771,7 +769,7 @@ static void u132_hcd_bulk_output_sent(void *data, struct urb *urb, u8 *buf, dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -874,7 +872,7 @@ static void u132_hcd_bulk_input_recv(void *data, struct urb *urb, u8 *buf, dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -911,7 +909,7 @@ static void u132_hcd_configure_empty_sent(void *data, struct urb *urb, u8 *buf, dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -983,7 +981,7 @@ static void u132_hcd_configure_input_recv(void *data, struct urb *urb, u8 *buf, dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -1020,7 +1018,7 @@ static void u132_hcd_configure_empty_recv(void *data, struct urb *urb, u8 *buf, dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -1080,7 +1078,7 @@ static void u132_hcd_configure_setup_sent(void *data, struct urb *urb, u8 *buf, dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -1121,7 +1119,7 @@ static void u132_hcd_enumeration_empty_recv(void *data, struct urb *urb, dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -1165,7 +1163,7 @@ static void u132_hcd_enumeration_address_sent(void *data, struct urb *urb, dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -1202,7 +1200,7 @@ static void u132_hcd_initial_empty_sent(void *data, struct urb *urb, u8 *buf, dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -1254,7 +1252,7 @@ static void u132_hcd_initial_input_recv(void *data, struct urb *urb, u8 *buf, dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -1299,7 +1297,7 @@ static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf, dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " "unlinked=%d\n", urb, urb->unlinked); up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, urb->status); + u132_hcd_giveback_urb(u132, endp, urb, 0); return; } } @@ -2428,7 +2426,7 @@ static int dequeue_from_overflow_chain(struct u132 *u132, list_del(scan); endp->queue_size -= 1; urb->error_count = 0; - usb_hcd_giveback_urb(hcd, urb); + usb_hcd_giveback_urb(hcd, urb, 0); return 0; } else continue; @@ -2472,7 +2470,7 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, return 0; } else { spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - u132_hcd_abandon_urb(u132, endp, urb, urb->status); + u132_hcd_abandon_urb(u132, endp, urb, status); return 0; } } else { @@ -2513,7 +2511,7 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, irqs); kfree(urbq); } urb->error_count = 0; - usb_hcd_giveback_urb(hcd, urb); + usb_hcd_giveback_urb(hcd, urb, status); return 0; } else if (list_empty(&endp->urb_more)) { dev_err(&u132->platform_dev->dev, "urb=%p not found in " diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index e46d2b0203c..340d6ed3e6e 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h @@ -456,21 +456,6 @@ struct urb_priv { }; -/* - * Locking in uhci.c - * - * Almost everything relating to the hardware schedule and processing - * of URBs is protected by uhci->lock. urb->status is protected by - * urb->lock; that's the one exception. - * - * To prevent deadlocks, never lock uhci->lock while holding urb->lock. - * The safe order of locking is: - * - * #1 uhci->lock - * #2 urb->lock - */ - - /* Some special IDs */ #define PCI_VENDOR_ID_GENESYS 0x17a0 diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index bab56726655..e5d60d5b105 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -1480,7 +1480,7 @@ done: * Finish unlinking an URB and give it back */ static void uhci_giveback_urb(struct uhci_hcd *uhci, struct uhci_qh *qh, - struct urb *urb) + struct urb *urb, int status) __releases(uhci->lock) __acquires(uhci->lock) { @@ -1520,7 +1520,7 @@ __acquires(uhci->lock) usb_hcd_unlink_urb_from_ep(uhci_to_hcd(uhci), urb); spin_unlock(&uhci->lock); - usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb); + usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb, status); spin_lock(&uhci->lock); /* If the queue is now empty, we can unlink the QH and give up its @@ -1556,10 +1556,6 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) if (status == -EINPROGRESS) break; - spin_lock(&urb->lock); - urb->status = status; - spin_unlock(&urb->lock); - /* Dequeued but completed URBs can't be given back unless * the QH is stopped or has finished unlinking. */ if (urb->unlinked) { @@ -1569,7 +1565,7 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) return; } - uhci_giveback_urb(uhci, qh, urb); + uhci_giveback_urb(uhci, qh, urb, status); if (status < 0) break; } @@ -1594,7 +1590,7 @@ restart: qh->is_stopped = 0; return; } - uhci_giveback_urb(uhci, qh, urb); + uhci_giveback_urb(uhci, qh, urb, 0); goto restart; } } -- cgit v1.2.3-70-g09d2 From 1431d2a44ccf68a547094976f363f94177ab00c6 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 24 Aug 2007 15:42:39 -0400 Subject: USB: get rid of urb->lock Now that urb->status isn't used, urb->lock doesn't protect anything. This patch (as980) removes it and replaces it with a private mutex in the one remaining place it was still used: usb_kill_urb. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/urb.c | 11 ++++++----- include/linux/usb.h | 4 ---- 2 files changed, 6 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 19f5f66c273..76db76fdb4e 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -39,7 +39,6 @@ void usb_init_urb(struct urb *urb) if (urb) { memset(urb, 0, sizeof(*urb)); kref_init(&urb->kref); - spin_lock_init(&urb->lock); INIT_LIST_HEAD(&urb->anchor_list); } } @@ -541,19 +540,21 @@ int usb_unlink_urb(struct urb *urb) */ void usb_kill_urb(struct urb *urb) { + static DEFINE_MUTEX(reject_mutex); + might_sleep(); if (!(urb && urb->dev && urb->ep)) return; - spin_lock_irq(&urb->lock); + mutex_lock(&reject_mutex); ++urb->reject; - spin_unlock_irq(&urb->lock); + mutex_unlock(&reject_mutex); usb_hcd_unlink_urb(urb, -ENOENT); wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0); - spin_lock_irq(&urb->lock); + mutex_lock(&reject_mutex); --urb->reject; - spin_unlock_irq(&urb->lock); + mutex_unlock(&reject_mutex); } /** diff --git a/include/linux/usb.h b/include/linux/usb.h index 5c7b79088ad..5b14b4c81fd 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -1241,7 +1241,6 @@ struct urb { /* private: usb core and host controller only fields in the urb */ struct kref kref; /* reference count of the URB */ - spinlock_t lock; /* lock for the URB */ void *hcpriv; /* private data for host controller */ atomic_t use_count; /* concurrent submissions counter */ u8 reject; /* submissions will fail */ @@ -1299,7 +1298,6 @@ static inline void usb_fill_control_urb (struct urb *urb, usb_complete_t complete_fn, void *context) { - spin_lock_init(&urb->lock); urb->dev = dev; urb->pipe = pipe; urb->setup_packet = setup_packet; @@ -1330,7 +1328,6 @@ static inline void usb_fill_bulk_urb (struct urb *urb, usb_complete_t complete_fn, void *context) { - spin_lock_init(&urb->lock); urb->dev = dev; urb->pipe = pipe; urb->transfer_buffer = transfer_buffer; @@ -1366,7 +1363,6 @@ static inline void usb_fill_int_urb (struct urb *urb, void *context, int interval) { - spin_lock_init(&urb->lock); urb->dev = dev; urb->pipe = pipe; urb->transfer_buffer = transfer_buffer; -- cgit v1.2.3-70-g09d2 From e015268d2fcfcaef70a1ec535e6381f75aafbf81 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 24 Aug 2007 15:42:52 -0400 Subject: USB: remove traces of urb->status from usbcore This patch (as981) removes the remaining nontrivial usages of urb->status from usbcore. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 8 +++++--- drivers/usb/core/hub.c | 8 ++++---- 2 files changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index b9f1edd6af5..e5ad76b4a73 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -71,6 +71,7 @@ struct async { void __user *userbuffer; void __user *userurb; struct urb *urb; + int status; u32 secid; }; @@ -310,9 +311,10 @@ static void async_completed(struct urb *urb) spin_lock(&ps->lock); list_move_tail(&as->asynclist, &ps->async_completed); spin_unlock(&ps->lock); + as->status = urb->status; if (as->signr) { sinfo.si_signo = as->signr; - sinfo.si_errno = as->urb->status; + sinfo.si_errno = as->status; sinfo.si_code = SI_ASYNCIO; sinfo.si_addr = as->userurb; kill_pid_info_as_uid(as->signr, &sinfo, as->pid, as->uid, @@ -1132,7 +1134,7 @@ static int processcompl(struct async *as, void __user * __user *arg) if (as->userbuffer) if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length)) return -EFAULT; - if (put_user(urb->status, &userurb->status)) + if (put_user(as->status, &userurb->status)) return -EFAULT; if (put_user(urb->actual_length, &userurb->actual_length)) return -EFAULT; @@ -1246,7 +1248,7 @@ static int processcompl_compat(struct async *as, void __user * __user *arg) if (as->userbuffer) if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length)) return -EFAULT; - if (put_user(urb->status, &userurb->status)) + if (put_user(as->status, &userurb->status)) return -EFAULT; if (put_user(urb->actual_length, &userurb->actual_length)) return -EFAULT; diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 4c495c4d505..bd08d51d7f4 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -347,11 +347,11 @@ void usb_kick_khubd(struct usb_device *hdev) static void hub_irq(struct urb *urb) { struct usb_hub *hub = urb->context; - int status; + int status = urb->status; int i; unsigned long bits; - switch (urb->status) { + switch (status) { case -ENOENT: /* synchronous unlink */ case -ECONNRESET: /* async unlink */ case -ESHUTDOWN: /* hardware going away */ @@ -359,10 +359,10 @@ static void hub_irq(struct urb *urb) default: /* presumably an error */ /* Cause a hub reset after 10 consecutive errors */ - dev_dbg (hub->intfdev, "transfer --> %d\n", urb->status); + dev_dbg (hub->intfdev, "transfer --> %d\n", status); if ((++hub->nerrors < 10) || hub->error) goto resubmit; - hub->error = urb->status; + hub->error = status; /* FALL THROUGH */ /* let khubd handle things */ -- cgit v1.2.3-70-g09d2 From 63f991b2871bdb1431e8ff62cae2b7b94b4e5b0c Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 4 Sep 2007 09:53:24 -0400 Subject: USB: fix location of statement label in dummy-hcd This patch (as984) fixes a rather elementary mistake in dummy_hcd. The new statement label should come before the spin_unlock_irqrestore, not after it. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/dummy_hcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 58e4d720880..6479a36d6f0 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -1001,8 +1001,8 @@ static int dummy_urb_enqueue ( if (!timer_pending (&dum->timer)) mod_timer (&dum->timer, jiffies + 1); - spin_unlock_irqrestore (&dum->lock, flags); done: + spin_unlock_irqrestore(&dum->lock, flags); return rc; } -- cgit v1.2.3-70-g09d2 From d853d872c14b9adc4adad29e56cd378b291f86e0 Mon Sep 17 00:00:00 2001 From: Johann Wilhelm Date: Wed, 5 Sep 2007 13:49:29 +0200 Subject: USB: usb-storage: Initialize Huawei E220 properly This is a reworked version of this patch: http://www.mail-archive.com/linux-usb-devel%40lists.sourceforge.net/msg55094/activate_huawei_dev.patch That properly initializes the HUAWEI E220 devices into multi-port mode. Signed-off-by: Johann Wilhelm Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/initializers.c | 14 ++++++++++++++ drivers/usb/storage/initializers.h | 3 +++ drivers/usb/storage/unusual_devs.h | 11 +++++++++++ 3 files changed, 28 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/storage/initializers.c b/drivers/usb/storage/initializers.c index 3a41740cad9..ee5b42aa536 100644 --- a/drivers/usb/storage/initializers.c +++ b/drivers/usb/storage/initializers.c @@ -90,3 +90,17 @@ int usb_stor_ucr61s2b_init(struct us_data *us) return (res ? -1 : 0); } + +/* This places the HUAWEI E220 devices in multi-port mode */ +int usb_stor_huawei_e220_init(struct us_data *us) +{ + int result; + + us->iobuf[0] = 0x1; + result = usb_stor_control_msg(us, us->send_ctrl_pipe, + USB_REQ_SET_FEATURE, + USB_TYPE_STANDARD | USB_RECIP_DEVICE, + 0x01, 0x0, us->iobuf, 0x1, 1000); + US_DEBUGP("usb_control_msg performing result is %d\n", result); + return (result ? 0 : -1); +} diff --git a/drivers/usb/storage/initializers.h b/drivers/usb/storage/initializers.h index e2967a4d48a..ad3ffd4236c 100644 --- a/drivers/usb/storage/initializers.h +++ b/drivers/usb/storage/initializers.h @@ -47,3 +47,6 @@ int usb_stor_euscsi_init(struct us_data *us); /* This function is required to activate all four slots on the UCR-61S2B * flash reader */ int usb_stor_ucr61s2b_init(struct us_data *us); + +/* This places the HUAWEI E220 devices in multi-port mode */ +int usb_stor_huawei_e220_init(struct us_data *us); diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index c6b78ba815e..94b1dd2aeb3 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -1463,6 +1463,17 @@ UNUSUAL_DEV( 0x1210, 0x0003, 0x0100, 0x0100, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE ), +/* Reported by fangxiaozhi + * and by linlei + * Patch reworked by Johann Wilhelm + * This brings the HUAWEI E220 devices into multi-port mode + */ +UNUSUAL_DEV( 0x12d1, 0x1003, 0x0000, 0x0000, + "HUAWEI MOBILE", + "Mass Storage", + US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init, + 0), + /* Reported by Vilius Bilinkevicius Date: Thu, 6 Sep 2007 23:18:15 +0200 Subject: USB: ELAN U132 Host Controller Driver: convert sw_lock to mutex The ELAN U132 Host Controller Driver uses the semaphore sw_lock as mutex. Use the mutex API instead of the (binary) semaphore. Signed-off-by: Matthias Kaehlcke Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/u132-hcd.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index 2b379a78d0d..ac283b09a63 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -183,7 +183,7 @@ struct u132_ring { struct u132 { struct kref kref; struct list_head u132_list; - struct semaphore sw_lock; + struct mutex sw_lock; struct semaphore scheduler_lock; struct u132_platform_data *board; struct platform_device *platform_dev; @@ -492,20 +492,20 @@ static void u132_hcd_monitor_work(struct work_struct *work) return; } else { int retval; - down(&u132->sw_lock); + mutex_lock(&u132->sw_lock); retval = read_roothub_info(u132); if (retval) { struct usb_hcd *hcd = u132_to_hcd(u132); u132_disable(u132); u132->going = 1; - up(&u132->sw_lock); + mutex_unlock(&u132->sw_lock); usb_hc_died(hcd); ftdi_elan_gone_away(u132->platform_dev); u132_monitor_put_kref(u132); return; } else { u132_monitor_requeue_work(u132, 500); - up(&u132->sw_lock); + mutex_unlock(&u132->sw_lock); return; } } @@ -1802,10 +1802,10 @@ static void u132_hcd_stop(struct usb_hcd *hcd) dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov" "ed\n", hcd); } else { - down(&u132->sw_lock); + mutex_lock(&u132->sw_lock); msleep(100); u132_power(u132, 0); - up(&u132->sw_lock); + mutex_unlock(&u132->sw_lock); } } @@ -1827,7 +1827,7 @@ static int u132_hcd_start(struct usb_hcd *hcd) (pdev->dev.platform_data))->vendor; u16 device = ((struct u132_platform_data *) (pdev->dev.platform_data))->device; - down(&u132->sw_lock); + mutex_lock(&u132->sw_lock); msleep(10); if (vendor == PCI_VENDOR_ID_AMD && device == 0x740c) { u132->flags = OHCI_QUIRK_AMD756; @@ -1842,7 +1842,7 @@ static int u132_hcd_start(struct usb_hcd *hcd) u132->going = 1; } msleep(100); - up(&u132->sw_lock); + mutex_unlock(&u132->sw_lock); return retval; } else { dev_err(&u132->platform_dev->dev, "platform_device missing\n"); @@ -1862,13 +1862,13 @@ static int u132_hcd_reset(struct usb_hcd *hcd) return -ESHUTDOWN; } else { int retval; - down(&u132->sw_lock); + mutex_lock(&u132->sw_lock); retval = u132_init(u132); if (retval) { u132_disable(u132); u132->going = 1; } - up(&u132->sw_lock); + mutex_unlock(&u132->sw_lock); return retval; } } @@ -2865,7 +2865,7 @@ static int u132_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, return -ESHUTDOWN; } else { int retval = 0; - down(&u132->sw_lock); + mutex_lock(&u132->sw_lock); switch (typeReq) { case ClearHubFeature: switch (wValue) { @@ -2928,7 +2928,7 @@ static int u132_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, stall:retval = -EPIPE; break; } - up(&u132->sw_lock); + mutex_unlock(&u132->sw_lock); return retval; } } @@ -3064,7 +3064,7 @@ static int __devexit u132_remove(struct platform_device *pdev) dev_err(&u132->platform_dev->dev, "removing device u132" ".%d\n", u132->sequence_num); msleep(100); - down(&u132->sw_lock); + mutex_lock(&u132->sw_lock); u132_monitor_cancel_work(u132); while (rings-- > 0) { struct u132_ring *ring = &u132->ring[rings]; @@ -3077,7 +3077,7 @@ static int __devexit u132_remove(struct platform_device *pdev) u132->going += 1; printk(KERN_INFO "removing device u132.%d\n", u132->sequence_num); - up(&u132->sw_lock); + mutex_unlock(&u132->sw_lock); usb_remove_hcd(hcd); u132_u132_put_kref(u132); return 0; @@ -3097,7 +3097,7 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev) u132->platform_dev = pdev; u132->power = 0; u132->reset = 0; - init_MUTEX(&u132->sw_lock); + mutex_init(&u132->sw_lock); init_MUTEX(&u132->scheduler_lock); while (rings-- > 0) { struct u132_ring *ring = &u132->ring[rings]; @@ -3107,7 +3107,7 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev) ring->curr_endp = NULL; INIT_DELAYED_WORK(&ring->scheduler, u132_hcd_ring_work_scheduler); - } down(&u132->sw_lock); + } mutex_lock(&u132->sw_lock); INIT_DELAYED_WORK(&u132->monitor, u132_hcd_monitor_work); while (ports-- > 0) { struct u132_port *port = &u132->port[ports]; @@ -3137,7 +3137,7 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev) while (endps-- > 0) { u132->endp[endps] = NULL; } - up(&u132->sw_lock); + mutex_unlock(&u132->sw_lock); return; } -- cgit v1.2.3-70-g09d2 From 5adceac5da3d353dd1318d0482cab94a79472adf Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Fri, 17 Aug 2007 14:01:38 +0200 Subject: USB: fix errornous assumption in the usb serial framework revealed by iuu_phoenix the iuu_phoenix driver submits another URB from a completion handler. This dictates a certain order of calls to usb_kill_urb() in kill_traffic(). As other drivers may do it the other way round, we need to use both orders in kill_traffic(). This patch does so and should be merged before iuu_phoenix is merged. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/usb-serial.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 9bf01a5efc8..26e015c39a3 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -578,6 +578,17 @@ static void kill_traffic(struct usb_serial_port *port) { usb_kill_urb(port->read_urb); usb_kill_urb(port->write_urb); + /* + * This is tricky. + * Some drivers submit the read_urb in the + * handler for the write_urb or vice versa + * this order determines the order in which + * usb_kill_urb() must be used to reliably + * kill the URBs. As it is unknown here, + * both orders must be used in turn. + * The call below is not redundant. + */ + usb_kill_urb(port->read_urb); usb_kill_urb(port->interrupt_in_urb); usb_kill_urb(port->interrupt_out_urb); } -- cgit v1.2.3-70-g09d2 From e6d42f0e962390e956545aa282efb05a9d6a41d1 Mon Sep 17 00:00:00 2001 From: Satyam Sharma Date: Mon, 3 Sep 2007 01:37:31 +0530 Subject: USB: sisusbvga: Fix bug drivers/usb/misc/sisusbvga/sisusb.c: In function sisusb_open drivers/usb/misc/sisusbvga/sisusb.c:2444: warning: sisusb is used uninitialized in this function is a genuine bug (which will cause oops). We cannot use "sisusb" in error path for (!interface), because sisusb will itself be derived from "interface" later. Signed-off-by: Satyam Sharma Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/sisusbvga/sisusb.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index 4d6b89336e6..033bdfe9b21 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -2440,10 +2440,8 @@ sisusb_open(struct inode *inode, struct file *file) struct usb_interface *interface; int subminor = iminor(inode); - if (!(interface = usb_find_interface(&sisusb_driver, subminor))) { - dev_err(&sisusb->sisusb_dev->dev, "Failed to find interface\n"); + if (!(interface = usb_find_interface(&sisusb_driver, subminor))) return -ENODEV; - } if (!(sisusb = usb_get_intfdata(interface))) return -ENODEV; -- cgit v1.2.3-70-g09d2 From 1d3ee41e9549609a6151216a0bcb06b758a64b6b Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Mon, 27 Aug 2007 16:16:13 -0700 Subject: USB: AMD5536: use pdev->revision Signed-off-by: Auke Kok Cc: Thomas Dahlmann Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/amd5536udc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index e95ffc9eee3..bdd5f2284b3 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c @@ -3285,14 +3285,12 @@ static int udc_pci_probe( pci_set_drvdata(pdev, dev); - /* chip revision */ - dev->chiprev = 0; + /* chip revision for Hs AMD5536 */ + dev->chiprev = pdev->revision; pci_set_master(pdev); pci_set_mwi(pdev); - /* chip rev for Hs AMD5536 */ - pci_read_config_byte(pdev, PCI_REVISION_ID, (u8 *) &dev->chiprev); /* init dma pools */ if (use_dma) { retval = init_dma_pools(dev); -- cgit v1.2.3-70-g09d2 From 7477120e34eef65a530cfb3fea5fe612c89669e5 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 10 Sep 2007 11:35:14 -0400 Subject: USB: Get rid of annoying endpoint-release message This patch (as990) removes an annoying debugging message. Nobody really cares when endpoint pseudo-devices are released. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/endpoint.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c index e0ec7045e86..7dc123d6b2d 100644 --- a/drivers/usb/core/endpoint.c +++ b/drivers/usb/core/endpoint.c @@ -267,7 +267,6 @@ static void ep_device_release(struct device *dev) { struct ep_device *ep_dev = to_ep_device(dev); - dev_dbg(dev, "%s called for %s\n", __FUNCTION__, dev->bus_id); endpoint_free_minor(ep_dev); kfree(ep_dev); } -- cgit v1.2.3-70-g09d2 From 5ad4f71e2f19a06f738463da1f09ea7fda3a3db2 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 10 Sep 2007 11:31:43 -0400 Subject: USB: move decision to ignore FREEZE events This patch (as987) changes the way FREEZE and PRETHAW suspend events are handled in usbcore. The decision about whether or not to ignore them for non-root devices is pushed down into the USB-device driver, instead of being made in the core code. This is appropriate, since devices exported to a virtualized guest or over a network may indeed need to handle these types of suspend, even though normal devices don't. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/driver.c | 9 +-------- drivers/usb/core/generic.c | 5 +++++ 2 files changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 8da4801bb92..ca43a6f824a 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1088,15 +1088,8 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) break; } } - if (status == 0) { - - /* Non-root devices don't need to do anything for FREEZE - * or PRETHAW. */ - if (udev->parent && (msg.event == PM_EVENT_FREEZE || - msg.event == PM_EVENT_PRETHAW)) - goto done; + if (status == 0) status = usb_suspend_device(udev, msg); - } /* If the suspend failed, resume interfaces that did get suspended */ if (status != 0) { diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index 9148b69785c..c1cb94e9f24 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -206,8 +206,13 @@ static int generic_suspend(struct usb_device *udev, pm_message_t msg) */ if (!udev->parent) rc = hcd_bus_suspend(udev); + + /* Non-root devices don't need to do anything for FREEZE or PRETHAW */ + else if (msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW) + rc = 0; else rc = usb_port_suspend(udev); + return rc; } -- cgit v1.2.3-70-g09d2 From 95cf82f99cfbd697c15572c444bd4f54f19745b0 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 10 Sep 2007 11:33:05 -0400 Subject: USB: break apart flush_endpoint and disable_endpoint This patch (as988) breaks usb_hcd_endpoint_disable() apart into two routines. The first, usb_hcd_flush_endpoint() does the -ESHUTDOWN unlinking of all URBs in the endpoint's queue and waits for them to complete. The second, usb_hcd_disable_endpoint() -- renamed for better grammatical style -- merely calls the HCD's endpoint_disable method. The changeover is easy because the routine currently has only one caller. This separation of function will be exploited in the following patch: When a device is suspended, the core will be able to cancel all outstanding URBs for that device while leaving the HCD's endpoint-related data structures intact for later. As an added benefit, HCDs no longer need to check for existing URBs in their endpoint_disable methods. It is now guaranteed that there will be none. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 48 ++++++++++++++++++++++++++-------------------- drivers/usb/core/hcd.h | 4 +++- drivers/usb/core/message.c | 3 ++- 3 files changed, 32 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 1c5e5d35e08..e5874e8b8cb 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1289,24 +1289,22 @@ EXPORT_SYMBOL (usb_hcd_giveback_urb); /*-------------------------------------------------------------------------*/ -/* disables the endpoint: cancels any pending urbs, then synchronizes with - * the hcd to make sure all endpoint state is gone from hardware, and then - * waits until the endpoint's queue is completely drained. use for - * set_configuration, set_interface, driver removal, physical disconnect. - * - * example: a qh stored in ep->hcpriv, holding state related to endpoint - * type, maxpacket size, toggle, halt status, and scheduling. +/* Cancel all URBs pending on this endpoint and wait for the endpoint's + * queue to drain completely. The caller must first insure that no more + * URBs can be submitted for this endpoint. */ -void usb_hcd_endpoint_disable (struct usb_device *udev, +void usb_hcd_flush_endpoint(struct usb_device *udev, struct usb_host_endpoint *ep) { struct usb_hcd *hcd; struct urb *urb; + if (!ep) + return; might_sleep(); hcd = bus_to_hcd(udev->bus); - /* ep is already gone from udev->ep_{in,out}[]; no more submits */ + /* No more submits can occur */ rescan: spin_lock_irq(&hcd_urb_list_lock); list_for_each_entry (urb, &ep->urb_list, urb_list) { @@ -1345,18 +1343,7 @@ rescan: } spin_unlock_irq(&hcd_urb_list_lock); - /* synchronize with the hardware, so old configuration state - * clears out immediately (and will be freed). - */ - if (hcd->driver->endpoint_disable) - hcd->driver->endpoint_disable (hcd, ep); - - /* Wait until the endpoint queue is completely empty. Most HCDs - * will have done this already in their endpoint_disable method, - * but some might not. And there could be root-hub control URBs - * still pending since they aren't affected by the HCDs' - * endpoint_disable methods. - */ + /* Wait until the endpoint queue is completely empty */ while (!list_empty (&ep->urb_list)) { spin_lock_irq(&hcd_urb_list_lock); @@ -1376,6 +1363,25 @@ rescan: } } +/* Disables the endpoint: synchronizes with the hcd to make sure all + * endpoint state is gone from hardware. usb_hcd_flush_endpoint() must + * have been called previously. Use for set_configuration, set_interface, + * driver removal, physical disconnect. + * + * example: a qh stored in ep->hcpriv, holding state related to endpoint + * type, maxpacket size, toggle, halt status, and scheduling. + */ +void usb_hcd_disable_endpoint(struct usb_device *udev, + struct usb_host_endpoint *ep) +{ + struct usb_hcd *hcd; + + might_sleep(); + hcd = bus_to_hcd(udev->bus); + if (hcd->driver->endpoint_disable) + hcd->driver->endpoint_disable(hcd, ep); +} + /*-------------------------------------------------------------------------*/ /* called in any context */ diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 0fc7b95259f..1396141274f 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -219,7 +219,9 @@ extern int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags); extern int usb_hcd_unlink_urb (struct urb *urb, int status); extern void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status); -extern void usb_hcd_endpoint_disable (struct usb_device *udev, +extern void usb_hcd_flush_endpoint(struct usb_device *udev, + struct usb_host_endpoint *ep); +extern void usb_hcd_disable_endpoint(struct usb_device *udev, struct usb_host_endpoint *ep); extern int usb_hcd_get_frame_number (struct usb_device *udev); diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index d638375e22e..98fcddba690 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1017,7 +1017,8 @@ void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr) } if (ep) { ep->enabled = 0; - usb_hcd_endpoint_disable(dev, ep); + usb_hcd_flush_endpoint(dev, ep); + usb_hcd_disable_endpoint(dev, ep); } } -- cgit v1.2.3-70-g09d2 From 6840d2555afd66290be7a39b400b5e66a840b82d Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 10 Sep 2007 11:34:26 -0400 Subject: USB: flush outstanding URBs when suspending This patch (as989) makes usbcore flush all outstanding URBs for each device as the device is suspended. This will be true even when CONFIG_USB_SUSPEND is not enabled. In addition, an extra can_submit flag is added to the usb_device structure. That flag will be turned off whenever a suspend request has been received for the device, even if the device isn't actually suspended because CONFIG_USB_SUSPEND isn't set. It's no longer necessary to check for the device state being equal to USB_STATE_SUSPENDED during URB submission; that check can be replaced by a check of the can_submit flag. This also permits us to remove some questionable references to the deprecated power.power_state field. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/driver.c | 10 +++++++++- drivers/usb/core/hcd.c | 5 +++++ drivers/usb/core/hub.c | 9 +-------- drivers/usb/core/urb.c | 3 --- drivers/usb/core/usb.c | 1 + include/linux/usb.h | 1 + 6 files changed, 17 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index ca43a6f824a..ba5bbc7eedc 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1102,9 +1102,16 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) if (udev->auto_pm) autosuspend_check(udev); - /* If the suspend succeeded, propagate it up the tree */ + /* If the suspend succeeded then prevent any more URB submissions, + * flush any outstanding URBs, and propagate the suspend up the tree. + */ } else { cancel_delayed_work(&udev->autosuspend); + udev->can_submit = 0; + for (i = 0; i < 16; ++i) { + usb_hcd_flush_endpoint(udev, udev->ep_out[i]); + usb_hcd_flush_endpoint(udev, udev->ep_in[i]); + } if (parent) usb_autosuspend_device(parent); } @@ -1154,6 +1161,7 @@ static int usb_resume_both(struct usb_device *udev) status = -ENODEV; goto done; } + udev->can_submit = 1; /* Propagate the resume up the tree, if necessary */ if (udev->state == USB_STATE_SUSPENDED) { diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index e5874e8b8cb..2c79aa6ca2b 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1014,6 +1014,11 @@ int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb) goto done; } + if (unlikely(!urb->dev->can_submit)) { + rc = -EHOSTUNREACH; + goto done; + } + /* * Check the host controller's state and add the URB to the * endpoint's queue. diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index bd08d51d7f4..691acf2223c 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1955,14 +1955,7 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg) struct usb_device *udev; udev = hdev->children [port1-1]; - if (udev && msg.event == PM_EVENT_SUSPEND && -#ifdef CONFIG_USB_SUSPEND - udev->state != USB_STATE_SUSPENDED -#else - udev->dev.power.power_state.event - == PM_EVENT_ON -#endif - ) { + if (udev && udev->can_submit) { if (!hdev->auto_pm) dev_dbg(&intf->dev, "port %d nyet suspended\n", port1); diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 76db76fdb4e..c20c03aaf01 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -286,9 +286,6 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) return -EINVAL; if (!(dev = urb->dev) || dev->state < USB_STATE_DEFAULT) return -ENODEV; - if (dev->bus->controller->power.power_state.event != PM_EVENT_ON - || dev->state == USB_STATE_SUSPENDED) - return -EHOSTUNREACH; /* For now, get the endpoint from the pipe. Eventually drivers * will be required to set urb->ep directly and we will eliminate diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index e5ff161776f..8121edbd149 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -272,6 +272,7 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT; /* ep0 maxpacket comes later, from device descriptor */ usb_enable_endpoint(dev, &dev->ep0); + dev->can_submit = 1; /* Save readable and stable topology id, distinguishing devices * by location for diagnostics, tools, driver model, etc. The diff --git a/include/linux/usb.h b/include/linux/usb.h index 5b14b4c81fd..e5b35e0dca2 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -383,6 +383,7 @@ struct usb_device { u8 portnum; /* Parent port number (origin 1) */ u8 level; /* Number of USB hub ancestors */ + unsigned can_submit:1; /* URBs may be submitted */ unsigned discon_suspended:1; /* Disconnected while suspended */ unsigned have_langid:1; /* whether string_langid is valid */ unsigned authorized:1; /* Policy has determined we can use it */ -- cgit v1.2.3-70-g09d2 From f7294055a7a5bf1ea7da16dffb0cb0f7a282c04b Mon Sep 17 00:00:00 2001 From: Mark Gross Date: Mon, 24 Sep 2007 09:28:14 -0700 Subject: USB: usb-skeleton leaking locks on open This weekend I was hacking around with a trivial USB driver for talking to the boot load firmware of a USB Bit Whacker. It's running the MicroChip Pic18 boot loader firmware and I'm putting together a flash program for writing new FW to the thing. Anyway in my use of the usb-skeleton.c as my starting point I discovered my test program was getting hung up after attempting to write a buffer. The application and driver where hung in a way that required me to reboot to get it to clean up so I could try again. It turned out the code path through skel_open can grap the driver's io_mutex lock and forget to release it. The following patch fixes the problem for me. Signed-off-by: Mark Gross Cc: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/usb-skeleton.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c index 8de11deb5d1..c815a40e167 100644 --- a/drivers/usb/usb-skeleton.c +++ b/drivers/usb/usb-skeleton.c @@ -125,6 +125,7 @@ static int skel_open(struct inode *inode, struct file *file) /* save our object in the file's private structure */ file->private_data = dev; + mutex_unlock(&dev->io_mutex); exit: return retval; -- cgit v1.2.3-70-g09d2 From 0e66fb3492442faa17fc7f27a3eba35b3c811e38 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 11 Sep 2007 19:10:21 +0200 Subject: USB: always visit drivers/usb/misc/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, every driver under drivers/usb/misc/ also has to be listed in drivers/usb/Makefile. This has been forgotten more than once, and this patch changes drivers/usb/Makefile to simply always visit drivers/usb/misc/ when building the USB code. Signed-off-by: Adrian Bunk Cc: Toralf Förster Acked-by: Satyam Sharma Signed-off-by: Greg Kroah-Hartman --- drivers/usb/Makefile | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index cce216517ca..516a6400db4 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -28,28 +28,7 @@ obj-$(CONFIG_USB_MICROTEK) += image/ obj-$(CONFIG_USB_SERIAL) += serial/ -obj-$(CONFIG_USB_ADUTUX) += misc/ -obj-$(CONFIG_USB_APPLEDISPLAY) += misc/ -obj-$(CONFIG_USB_AUERSWALD) += misc/ -obj-$(CONFIG_USB_BERRY_CHARGE) += misc/ -obj-$(CONFIG_USB_CYPRESS_CY7C63)+= misc/ -obj-$(CONFIG_USB_CYTHERM) += misc/ -obj-$(CONFIG_USB_EMI26) += misc/ -obj-$(CONFIG_USB_EMI62) += misc/ -obj-$(CONFIG_USB_FTDI_ELAN) += misc/ -obj-$(CONFIG_USB_IDMOUSE) += misc/ -obj-$(CONFIG_USB_IOWARRIOR) += misc/ -obj-$(CONFIG_USB_LCD) += misc/ -obj-$(CONFIG_USB_LD) += misc/ -obj-$(CONFIG_USB_LED) += misc/ -obj-$(CONFIG_USB_LEGOTOWER) += misc/ -obj-$(CONFIG_USB_PHIDGETSERVO) += misc/ -obj-$(CONFIG_USB_RIO500) += misc/ -obj-$(CONFIG_USB_SISUSBVGA) += misc/ -obj-$(CONFIG_USB_TEST) += misc/ -obj-$(CONFIG_USB_TRANCEVIBRATOR)+= misc/ -obj-$(CONFIG_USB_USS720) += misc/ -obj-$(CONFIG_USB_IOWARRIOR) += misc/ +obj-$(CONFIG_USB) += misc/ obj-$(CONFIG_USB_ATM) += atm/ obj-$(CONFIG_USB_SPEEDTOUCH) += atm/ -- cgit v1.2.3-70-g09d2 From ed6590a861a16276db34ee626375fa79f3369ac3 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Mon, 17 Sep 2007 20:15:53 +0200 Subject: USB: fix double frees in error code paths of ipaq driver the error code paths can be enter with buffers to freed buffers. Serial core would do a kfree() on memory already freed. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ipaq.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index 6a3a704b584..c1a6484f652 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -646,11 +646,13 @@ static int ipaq_open(struct usb_serial_port *port, struct file *filp) kfree(port->bulk_out_buffer); port->bulk_in_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL); if (port->bulk_in_buffer == NULL) { + port->bulk_out_buffer = NULL; /* prevent double free */ goto enomem; } port->bulk_out_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL); if (port->bulk_out_buffer == NULL) { kfree(port->bulk_in_buffer); + port->bulk_in_buffer = NULL; goto enomem; } port->read_urb->transfer_buffer = port->bulk_in_buffer; -- cgit v1.2.3-70-g09d2 From 403fae78d7388876b96fbe30ccf2cb551c49ae5a Mon Sep 17 00:00:00 2001 From: jidong xiao Date: Fri, 14 Sep 2007 00:08:51 +0800 Subject: USB: fix limited_power setting mistake in hub.c This patch (jx001) fixes a variable assignment mistake in hub driver. limited_power should be set to 0 if the hub is self-powered,and 1 if the hub is bus-powered. However, the effect of the code was exactly opposite to the spec's statement for the Local Power Source field. The spec says, this field is 1 meaning Local power supply lost while this field is 0 indicating Local power supply good.(This statement is very confusing.) So this patch switchs the 0 and 1. Signed-off-by: Jason Xiao Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 691acf2223c..481dca641ea 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2818,9 +2818,9 @@ static void hub_events(void) clear_hub_feature(hdev, C_HUB_LOCAL_POWER); if (hubstatus & HUB_STATUS_LOCAL_POWER) /* FIXME: Is this always true? */ - hub->limited_power = 0; - else hub->limited_power = 1; + else + hub->limited_power = 0; } if (hubchange & HUB_CHANGE_OVERCURRENT) { dev_dbg (hub_dev, "overcurrent change\n"); -- cgit v1.2.3-70-g09d2 From 393e5511a5f58e82b88589f1dd2464f6b661df06 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 18 Sep 2007 10:09:32 -0400 Subject: USB: unusual_devs update for Nokia 6131 This patch (as991) updates the unusual_devs entry for the Nokia 6131 phone. As reported by Juan Ignacio Cherrutti, there's new firmware available but it still has the same old transfer-size limit. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 94b1dd2aeb3..b0ff0295580 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -198,7 +198,7 @@ UNUSUAL_DEV( 0x0421, 0x044e, 0x0100, 0x0100, US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ), /* Reported by Bardur Arantsson */ -UNUSUAL_DEV( 0x0421, 0x047c, 0x0370, 0x0370, +UNUSUAL_DEV( 0x0421, 0x047c, 0x0370, 0x0610, "Nokia", "6131", US_SC_DEVICE, US_PR_DEVICE, NULL, -- cgit v1.2.3-70-g09d2 From 7108f28465a0a37d5afc05c5ad788938423b74a7 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 20 Sep 2007 12:37:50 -0400 Subject: USB: don't propagate FREEZE or PRETHAW suspends This patch (as992) fixes a recently-added bug. During a FREEZE or PRETHAW suspend notification, non-root devices don't actually get suspended. So we shouldn't tell their parent hubs that they did. (This code path used to be skipped over, until the FREEZE/PRETHAW test got moved out of usb_suspend_both() into generic_suspend().) Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/driver.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index ba5bbc7eedc..3f734240e0e 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1112,7 +1112,12 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) usb_hcd_flush_endpoint(udev, udev->ep_out[i]); usb_hcd_flush_endpoint(udev, udev->ep_in[i]); } - if (parent) + + /* If this is just a FREEZE or a PRETHAW, udev might + * not really be suspended. Only true suspends get + * propagated up the device tree. + */ + if (parent && udev->state == USB_STATE_SUSPENDED) usb_autosuspend_device(parent); } -- cgit v1.2.3-70-g09d2 From a691efa9888e71232dfb4088fb8a8304ffc7b0f9 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 21 Sep 2007 16:57:54 -0400 Subject: USB: remove USB_QUIRK_NO_AUTOSUSPEND This patch (as995) cleans up the remains of the former NO_AUTOSUSPEND quirk. Since autosuspend is disabled by default, we will let userspace worry about which devices can safely be suspended. Thus the lengthy series of quirk entries is no longer needed, and neither is the quirk ID. I suppose someone might eventually run across a hub that can't be suspended; let's ignore the possibility for now. The patch also cleans up the hasty way in which autosuspend gets disabled. Setting udev->autosuspend_delay to -1 wasn't quite right, because the value is always supposed to be a multiple of HZ. It's better to leave the delay value alone and set autosuspend_disabled, which is what the quirk routine used to do. Signed-off-by: Alan Stern Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/quirks.c | 81 +--------------------------------------------- include/linux/usb/quirks.h | 7 ++-- 2 files changed, 3 insertions(+), 85 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index ebf3dc20110..d42c561c75f 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -32,52 +32,6 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x0204, 0x6025), .driver_info = USB_QUIRK_RESET_RESUME }, /* HP 5300/5370C scanner */ { USB_DEVICE(0x03f0, 0x0701), .driver_info = USB_QUIRK_STRING_FETCH_255 }, - /* Hewlett-Packard PhotoSmart 720 / PhotoSmart 935 (storage) */ - { USB_DEVICE(0x03f0, 0x4002), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - - /* SGS Thomson Microelectronics 4in1 card reader */ - { USB_DEVICE(0x0483, 0x0321), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - - /* Acer Peripherals Inc. (now BenQ Corp.) Prisa 640BU */ - { USB_DEVICE(0x04a5, 0x207e), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Benq S2W 3300U */ - { USB_DEVICE(0x04a5, 0x20b0), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Canon, Inc. CanoScan N1240U/LiDE30 */ - { USB_DEVICE(0x04a9, 0x220e), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Canon, Inc. CanoScan N650U/N656U */ - { USB_DEVICE(0x04a9, 0x2206), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Canon, Inc. CanoScan 1220U */ - { USB_DEVICE(0x04a9, 0x2207), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Canon, Inc. CanoScan N670U/N676U/LiDE 20 */ - { USB_DEVICE(0x04a9, 0x220d), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* old Cannon scanner */ - { USB_DEVICE(0x04a9, 0x2220), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Seiko Epson Corp. Perfection 1200 */ - { USB_DEVICE(0x04b8, 0x0104), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Seiko Epson Corp. Perfection 660 */ - { USB_DEVICE(0x04b8, 0x0114), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Epson Perfection 1260 Photo */ - { USB_DEVICE(0x04b8, 0x011d), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Seiko Epson Corp - Perfection 1670 */ - { USB_DEVICE(0x04b8, 0x011f), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* EPSON Perfection 2480 */ - { USB_DEVICE(0x04b8, 0x0121), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Seiko Epson Corp.*/ - { USB_DEVICE(0x04b8, 0x0122), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Samsung ML-2010 printer */ - { USB_DEVICE(0x04e8, 0x326c), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Samsung ML-2510 Series printer */ - { USB_DEVICE(0x04e8, 0x327e), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Elsa MicroLink 56k (V.250) */ - { USB_DEVICE(0x05cc, 0x2267), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Ultima Electronics Corp.*/ - { USB_DEVICE(0x05d8, 0x4005), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - - /* Genesys USB-to-IDE */ - { USB_DEVICE(0x0503, 0x0702), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - - /* USB Graphical LCD - EEH Datalink GmbH */ - { USB_DEVICE(0x060c, 0x04eb), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, /* INTEL VALUE SSD */ { USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME }, @@ -85,44 +39,15 @@ static const struct usb_device_id usb_quirk_list[] = { /* M-Systems Flash Disk Pioneers */ { USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME }, - /* Agfa Snapscan1212u */ - { USB_DEVICE(0x06bd, 0x2061), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Seagate RSS LLC */ - { USB_DEVICE(0x0bc2, 0x3000), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Umax [hex] Astra 3400U */ - { USB_DEVICE(0x1606, 0x0060), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* Philips PSC805 audio device */ { USB_DEVICE(0x0471, 0x0155), .driver_info = USB_QUIRK_RESET_RESUME }, - /* Alcor multi-card reader */ - { USB_DEVICE(0x058f, 0x6366), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - - /* Canon EOS 5D in PC Connection mode */ - { USB_DEVICE(0x04a9, 0x3101), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - - /* RIM Blackberry */ - { USB_DEVICE(0x0fca, 0x0001), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - { USB_DEVICE(0x0fca, 0x0004), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - { USB_DEVICE(0x0fca, 0x0006), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - - /* Apple iPhone */ - { USB_DEVICE(0x05ac, 0x1290), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, - /* SKYMEDI USB_DRIVE */ { USB_DEVICE(0x1516, 0x8628), .driver_info = USB_QUIRK_RESET_RESUME }, { } /* terminating entry must be last */ }; -static void usb_autosuspend_quirk(struct usb_device *udev) -{ -#ifdef CONFIG_USB_SUSPEND - /* disable autosuspend, but allow the user to re-enable it via sysfs */ - udev->autosuspend_disabled = 1; -#endif -} - static const struct usb_device_id *find_id(struct usb_device *udev) { const struct usb_device_id *id = usb_quirk_list; @@ -149,13 +74,9 @@ void usb_detect_quirks(struct usb_device *udev) dev_dbg(&udev->dev, "USB quirks for this device: %x\n", udev->quirks); - /* do any special quirk handling here if needed */ - if (udev->quirks & USB_QUIRK_NO_AUTOSUSPEND) - usb_autosuspend_quirk(udev); - /* By default, disable autosuspend for all non-hubs */ #ifdef CONFIG_USB_SUSPEND if (udev->descriptor.bDeviceClass != USB_CLASS_HUB) - udev->autosuspend_delay = -1; + udev->autosuspend_disabled = 1; #endif } diff --git a/include/linux/usb/quirks.h b/include/linux/usb/quirks.h index 8da374caf58..2692ec9389c 100644 --- a/include/linux/usb/quirks.h +++ b/include/linux/usb/quirks.h @@ -4,11 +4,8 @@ * belong here. */ -/* device must not be autosuspended */ -#define USB_QUIRK_NO_AUTOSUSPEND 0x00000001 - /* string descriptors must not be fetched using a 255-byte read */ -#define USB_QUIRK_STRING_FETCH_255 0x00000002 +#define USB_QUIRK_STRING_FETCH_255 0x00000001 /* device can't resume correctly so reset it instead */ -#define USB_QUIRK_RESET_RESUME 0x00000004 +#define USB_QUIRK_RESET_RESUME 0x00000002 -- cgit v1.2.3-70-g09d2 From 16eb345f4d9189b59bae576ae63cba7ca77817b2 Mon Sep 17 00:00:00 2001 From: Phil Dibowitz Date: Sat, 22 Sep 2007 20:58:12 -0700 Subject: USB: unusual_devs modification for Nikon D200 Upgrade the unusual_devs.h file to support the Nikon D200 Signed-off-by: Mike Pagano Signed-off-by: Phil Dibowitz Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index b0ff0295580..5129b538be9 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -341,6 +341,13 @@ UNUSUAL_DEV( 0x04b0, 0x040d, 0x0100, 0x0100, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_CAPACITY), +/* Reported by Graber and Mike Pagano */ +UNUSUAL_DEV( 0x04b0, 0x040f, 0x0200, 0x0200, + "NIKON", + "NIKON DSC D200", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY), + /* Reported by Emil Larsson */ UNUSUAL_DEV( 0x04b0, 0x0411, 0x0100, 0x0101, "NIKON", -- cgit v1.2.3-70-g09d2 From 1f4f714f88955cfb61fba0cd43fe3b07e4212257 Mon Sep 17 00:00:00 2001 From: Edouard Lafargue Date: Tue, 25 Sep 2007 10:15:36 +0200 Subject: USB: cp2101.c: add additional device ID This patch adds an additional device ID to the cp2101 USB serial driver. This device is a Gemalto Prox-PU or CU contactless card reader (ISO14443-A/B and Mifare). The reader is a standard Gemalto serial proximity reader using the Gemalto Block Protocol (see reader's documentation) bundled with a built-in CP2102 for serial/USB conversion. Signed-off-by: Edouard Lafargue (edouard@lafargue.name) Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/cp2101.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c index 883625126d6..eb7df1835c1 100644 --- a/drivers/usb/serial/cp2101.c +++ b/drivers/usb/serial/cp2101.c @@ -53,6 +53,7 @@ static void cp2101_shutdown(struct usb_serial*); static int debug; static struct usb_device_id id_table [] = { + { USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */ { USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */ { USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */ { USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */ -- cgit v1.2.3-70-g09d2 From 4ac0718e83821db53451614e098399004694aa81 Mon Sep 17 00:00:00 2001 From: Simon Arlott Date: Tue, 25 Sep 2007 20:20:10 +0100 Subject: USB: cxacru: Use appropriate logging for errors When an error occurs, existing logging uses dbg() so the cause of a problem is hard to determine. Error conditions shouldn't only be properly reported with debugging enabled. A side effect of this change is that when an uninitialised device is started, a log message similar to the following is sent: cxacru 5-2:1.0: receive of cm 0x90 failed (-104) This is normal - the device did not respond so firmware will be loaded. Signed-off-by: Simon Arlott Acked-by: Duncan Sands Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/cxacru.c | 43 ++++++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index a73e714288e..a51eeedc18d 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c @@ -482,7 +482,9 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm, int rbuflen = ((rsize - 1) / stride + 1) * CMD_PACKET_SIZE; if (wbuflen > PAGE_SIZE || rbuflen > PAGE_SIZE) { - dbg("too big transfer requested"); + if (printk_ratelimit()) + usb_err(instance->usbatm, "requested transfer size too large (%d, %d)\n", + wbuflen, rbuflen); ret = -ENOMEM; goto fail; } @@ -493,8 +495,9 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm, init_completion(&instance->rcv_done); ret = usb_submit_urb(instance->rcv_urb, GFP_KERNEL); if (ret < 0) { - dbg("submitting read urb for cm %#x failed", cm); - ret = ret; + if (printk_ratelimit()) + usb_err(instance->usbatm, "submit of read urb for cm %#x failed (%d)\n", + cm, ret); goto fail; } @@ -510,27 +513,29 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm, init_completion(&instance->snd_done); ret = usb_submit_urb(instance->snd_urb, GFP_KERNEL); if (ret < 0) { - dbg("submitting write urb for cm %#x failed", cm); - ret = ret; + if (printk_ratelimit()) + usb_err(instance->usbatm, "submit of write urb for cm %#x failed (%d)\n", + cm, ret); goto fail; } ret = cxacru_start_wait_urb(instance->snd_urb, &instance->snd_done, NULL); if (ret < 0) { - dbg("sending cm %#x failed", cm); - ret = ret; + if (printk_ratelimit()) + usb_err(instance->usbatm, "send of cm %#x failed (%d)\n", cm, ret); goto fail; } ret = cxacru_start_wait_urb(instance->rcv_urb, &instance->rcv_done, &actlen); if (ret < 0) { - dbg("receiving cm %#x failed", cm); - ret = ret; + if (printk_ratelimit()) + usb_err(instance->usbatm, "receive of cm %#x failed (%d)\n", cm, ret); goto fail; } if (actlen % CMD_PACKET_SIZE || !actlen) { - dbg("response is not a positive multiple of %d: %#x", - CMD_PACKET_SIZE, actlen); + if (printk_ratelimit()) + usb_err(instance->usbatm, "invalid response length to cm %#x: %d\n", + cm, actlen); ret = -EIO; goto fail; } @@ -538,12 +543,16 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm, /* check the return status and copy the data to the output buffer, if needed */ for (offb = offd = 0; offd < rsize && offb < actlen; offb += CMD_PACKET_SIZE) { if (rbuf[offb] != cm) { - dbg("wrong cm %#x in response", rbuf[offb]); + if (printk_ratelimit()) + usb_err(instance->usbatm, "wrong cm %#x in response to cm %#x\n", + rbuf[offb], cm); ret = -EIO; goto fail; } if (rbuf[offb + 1] != CM_STATUS_SUCCESS) { - dbg("response failed: %#x", rbuf[offb + 1]); + if (printk_ratelimit()) + usb_err(instance->usbatm, "response to cm %#x failed: %#x\n", + cm, rbuf[offb + 1]); ret = -EIO; goto fail; } @@ -582,14 +591,18 @@ static int cxacru_cm_get_array(struct cxacru_data *instance, enum cxacru_cm_requ for (offb = 0; offb < len; ) { int l = le32_to_cpu(buf[offb++]); if (l > stride || l > (len - offb) / 2) { - dbg("wrong data length %#x in response", l); + if (printk_ratelimit()) + usb_err(instance->usbatm, "invalid data length from cm %#x: %d\n", + cm, l); ret = -EIO; goto cleanup; } while (l--) { offd = le32_to_cpu(buf[offb++]); if (offd >= size) { - dbg("wrong index %#x in response", offd); + if (printk_ratelimit()) + usb_err(instance->usbatm, "wrong index #%x in response to cm #%x\n", + offd, cm); ret = -EIO; goto cleanup; } -- cgit v1.2.3-70-g09d2 From 6ce76104781a10554129791dc62c3104424f6d48 Mon Sep 17 00:00:00 2001 From: Frank A Kingswood Date: Wed, 22 Aug 2007 20:48:58 +0100 Subject: USB: Driver for CH341 USB-serial adaptor This patch implements a USB serial port driver for the Winchiphead CH341 USB-RS232 Converter. This chip also implements an IEEE 1284 parallel port, I2C and SPI, but that is not supported by the driver. Signed-off-by: Frank A Kingswood Signed-off-by: Greg Kroah-Hartman --- Documentation/usb/usb-serial.txt | 11 ++ drivers/usb/serial/Kconfig | 10 ++ drivers/usb/serial/Makefile | 1 + drivers/usb/serial/ch341.c | 352 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 374 insertions(+) create mode 100644 drivers/usb/serial/ch341.c (limited to 'drivers') diff --git a/Documentation/usb/usb-serial.txt b/Documentation/usb/usb-serial.txt index 5b635ae8494..4e0b62b8566 100644 --- a/Documentation/usb/usb-serial.txt +++ b/Documentation/usb/usb-serial.txt @@ -428,6 +428,17 @@ Options supported: See http://www.uuhaus.de/linux/palmconnect.html for up-to-date information on this driver. +Winchiphead CH341 Driver + + This driver is for the Winchiphead CH341 USB-RS232 Converter. This chip + also implements an IEEE 1284 parallel port, I2C and SPI, but that is not + supported by the driver. The protocol was analyzed from the behaviour + of the Windows driver, no datasheet is available at present. + The manufacturer's website: http://www.winchiphead.com/. + For any questions or problems with this driver, please contact + frank@kingswood-consulting.co.uk. + + Generic Serial driver If your device is not one of the above listed devices, compatible with diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index 43d6db696f9..99fefed7791 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -92,6 +92,16 @@ config USB_SERIAL_BELKIN To compile this driver as a module, choose M here: the module will be called belkin_sa. +config USB_SERIAL_CH341 + tristate "USB Winchiphead CH341 Single Port Serial Driver" + depends on USB_SERIAL + help + Say Y here if you want to use a Winchiphead CH341 single port + USB to serial adapter. + + To compile this driver as a module, choose M here: the + module will be called ch341. + config USB_SERIAL_WHITEHEAT tristate "USB ConnectTech WhiteHEAT Serial Driver" depends on USB_SERIAL diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile index 07a976eca6b..d6fb384e52b 100644 --- a/drivers/usb/serial/Makefile +++ b/drivers/usb/serial/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_USB_SERIAL_AIRCABLE) += aircable.o obj-$(CONFIG_USB_SERIAL_AIRPRIME) += airprime.o obj-$(CONFIG_USB_SERIAL_ARK3116) += ark3116.o obj-$(CONFIG_USB_SERIAL_BELKIN) += belkin_sa.o +obj-$(CONFIG_USB_SERIAL_CH341) += ch341.o obj-$(CONFIG_USB_SERIAL_CP2101) += cp2101.o obj-$(CONFIG_USB_SERIAL_CYBERJACK) += cyberjack.o obj-$(CONFIG_USB_SERIAL_CYPRESS_M8) += cypress_m8.o diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c new file mode 100644 index 00000000000..eb681069e24 --- /dev/null +++ b/drivers/usb/serial/ch341.c @@ -0,0 +1,352 @@ +/* + * Copyright 2007, Frank A Kingswood + * + * ch341.c implements a serial port driver for the Winchiphead CH341. + * + * The CH341 device can be used to implement an RS232 asynchronous + * serial port, an IEEE-1284 parallel printer port or a memory-like + * interface. In all cases the CH341 supports an I2C interface as well. + * This driver only supports the asynchronous serial interface. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define DEFAULT_BAUD_RATE 2400 +#define DEFAULT_TIMEOUT 1000 + +static int debug; + +static struct usb_device_id id_table [] = { + { USB_DEVICE(0x4348, 0x5523) }, + { }, +}; +MODULE_DEVICE_TABLE(usb, id_table); + +struct ch341_private { + unsigned baud_rate; + u8 dtr; + u8 rts; +}; + +static int ch341_control_out(struct usb_device *dev, u8 request, + u16 value, u16 index) +{ + int r; + dbg("ch341_control_out(%02x,%02x,%04x,%04x)", USB_DIR_OUT|0x40, + (int)request, (int)value, (int)index); + + r = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, + value, index, NULL, 0, DEFAULT_TIMEOUT); + + return r; +} + +static int ch341_control_in(struct usb_device *dev, + u8 request, u16 value, u16 index, + char *buf, unsigned bufsize) +{ + int r; + dbg("ch341_control_in(%02x,%02x,%04x,%04x,%p,%u)", USB_DIR_IN|0x40, + (int)request, (int)value, (int)index, buf, (int)bufsize); + + r = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), request, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, + value, index, buf, bufsize, DEFAULT_TIMEOUT); + return r; +} + +int ch341_set_baudrate(struct usb_device *dev, struct ch341_private *priv) +{ + short a, b; + int r; + + dbg("ch341_set_baudrate(%d)", priv->baud_rate); + switch (priv->baud_rate) { + case 2400: + a = 0xd901; + b = 0x0038; + break; + case 4800: + a = 0x6402; + b = 0x001f; + break; + case 9600: + a = 0xb202; + b = 0x0013; + break; + case 19200: + a = 0xd902; + b = 0x000d; + break; + case 38400: + a = 0x6403; + b = 0x000a; + break; + case 115200: + a = 0xcc03; + b = 0x0008; + break; + default: + return -EINVAL; + } + + r = ch341_control_out(dev, 0x9a, 0x1312, a); + if (!r) + r = ch341_control_out(dev, 0x9a, 0x0f2c, b); + + return r; +} + +int ch341_set_handshake(struct usb_device *dev, struct ch341_private *priv) +{ + dbg("ch341_set_handshake(%d,%d)", priv->dtr, priv->rts); + return ch341_control_out(dev, 0xa4, + ~((priv->dtr?1<<5:0)|(priv->rts?1<<6:0)), 0); +} + +int ch341_get_status(struct usb_device *dev) +{ + char *buffer; + int r; + const unsigned size = 8; + + dbg("ch341_get_status()"); + + buffer = kmalloc(size, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + r = ch341_control_in(dev, 0x95, 0x0706, 0, buffer, size); + if ( r < 0) + goto out; + + /* Not having the datasheet for the CH341, we ignore the bytes returned + * from the device. Return error if the device did not respond in time. + */ + r = 0; + +out: kfree(buffer); + return r; +} + +/* -------------------------------------------------------------------------- */ + +int ch341_configure(struct usb_device *dev, struct ch341_private *priv) +{ + char *buffer; + int r; + const unsigned size = 8; + + dbg("ch341_configure()"); + + buffer = kmalloc(size, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + /* expect two bytes 0x27 0x00 */ + r = ch341_control_in(dev, 0x5f, 0, 0, buffer, size); + if (r < 0) + goto out; + + r = ch341_control_out(dev, 0xa1, 0, 0); + if (r < 0) + goto out; + + r = ch341_set_baudrate(dev, priv); + if (r < 0) + goto out; + + /* expect two bytes 0x56 0x00 */ + r = ch341_control_in(dev, 0x95, 0x2518, 0, buffer, size); + if (r < 0) + goto out; + + r = ch341_control_out(dev, 0x9a, 0x2518, 0x0050); + if (r < 0) + goto out; + + /* expect 0xff 0xee */ + r = ch341_get_status(dev); + if (r < 0) + goto out; + + r = ch341_control_out(dev, 0xa1, 0x501f, 0xd90a); + if (r < 0) + goto out; + + r = ch341_set_baudrate(dev, priv); + if (r < 0) + goto out; + + r = ch341_set_handshake(dev, priv); + if (r < 0) + goto out; + + /* expect 0x9f 0xee */ + r = ch341_get_status(dev); + +out: kfree(buffer); + return r; +} + +/* allocate private data */ +static int ch341_attach(struct usb_serial *serial) +{ + struct ch341_private *priv; + int r; + + dbg("ch341_attach()"); + + /* private data */ + priv = kzalloc(sizeof(struct ch341_private), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->baud_rate = DEFAULT_BAUD_RATE; + priv->dtr = 1; + priv->rts = 1; + + r = ch341_configure(serial->dev, priv); + if (r < 0) + goto error; + + usb_set_serial_port_data(serial->port[0], priv); + return 0; + +error: kfree(priv); + return r; +} + +/* open this device, set default parameters */ +static int ch341_open(struct usb_serial_port *port, struct file *filp) +{ + struct usb_serial *serial = port->serial; + struct ch341_private *priv = usb_get_serial_port_data(serial->port[0]); + int r; + + dbg("ch341_open()"); + + priv->baud_rate = DEFAULT_BAUD_RATE; + priv->dtr = 1; + priv->rts = 1; + + r = ch341_configure(serial->dev, priv); + if (r) + goto out; + + r = ch341_set_handshake(serial->dev, priv); + if (r) + goto out; + + r = ch341_set_baudrate(serial->dev, priv); + if (r) + goto out; + + r = usb_serial_generic_open(port, filp); + +out: return r; +} + +/* Old_termios contains the original termios settings and + * tty->termios contains the new setting to be used. + */ +static void ch341_set_termios(struct usb_serial_port *port, + struct ktermios *old_termios) +{ + struct ch341_private *priv = usb_get_serial_port_data(port); + struct tty_struct *tty = port->tty; + unsigned baud_rate; + + dbg("ch341_set_termios()"); + + if (!tty || !tty->termios) + return; + + baud_rate = tty_get_baud_rate(tty); + + switch (baud_rate) { + case 2400: + case 4800: + case 9600: + case 19200: + case 38400: + case 115200: + priv->baud_rate = baud_rate; + break; + default: + dbg("Rate %d not supported, using %d", + baud_rate, DEFAULT_BAUD_RATE); + priv->baud_rate = DEFAULT_BAUD_RATE; + } + + ch341_set_baudrate(port->serial->dev, priv); + + /* Unimplemented: + * (cflag & CSIZE) : data bits [5, 8] + * (cflag & PARENB) : parity {NONE, EVEN, ODD} + * (cflag & CSTOPB) : stop bits [1, 2] + */ +} + +static struct usb_driver ch341_driver = { + .name = "ch341", + .probe = usb_serial_probe, + .disconnect = usb_serial_disconnect, + .id_table = id_table, + .no_dynamic_id = 1, +}; + +static struct usb_serial_driver ch341_device = { + .driver = { + .owner = THIS_MODULE, + .name = "ch341-uart", + }, + .id_table = id_table, + .usb_driver = &ch341_driver, + .num_interrupt_in = NUM_DONT_CARE, + .num_bulk_in = 1, + .num_bulk_out = 1, + .num_ports = 1, + .open = ch341_open, + .set_termios = ch341_set_termios, + .attach = ch341_attach, +}; + +static int __init ch341_init(void) +{ + int retval; + + retval = usb_serial_register(&ch341_device); + if (retval) + return retval; + retval = usb_register(&ch341_driver); + if (retval) + usb_serial_deregister(&ch341_device); + return retval; +} + +static void __exit ch341_exit(void) +{ + usb_deregister(&ch341_driver); + usb_serial_deregister(&ch341_device); +} + +module_init(ch341_init); +module_exit(ch341_exit); +MODULE_LICENSE("GPL"); + +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Debug enabled or not"); + +/* EOF ch341.c */ -- cgit v1.2.3-70-g09d2 From 93b6497da99978742ffa9d9db6177397436278f5 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sun, 9 Sep 2007 22:25:04 +0200 Subject: USB: usb/serial/ch341.c: make 4 functions static This patch makes four needlessly global functions static. Signed-off-by: Adrian Bunk Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ch341.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c index eb681069e24..6b252ceb39a 100644 --- a/drivers/usb/serial/ch341.c +++ b/drivers/usb/serial/ch341.c @@ -66,7 +66,8 @@ static int ch341_control_in(struct usb_device *dev, return r; } -int ch341_set_baudrate(struct usb_device *dev, struct ch341_private *priv) +static int ch341_set_baudrate(struct usb_device *dev, + struct ch341_private *priv) { short a, b; int r; @@ -108,14 +109,15 @@ int ch341_set_baudrate(struct usb_device *dev, struct ch341_private *priv) return r; } -int ch341_set_handshake(struct usb_device *dev, struct ch341_private *priv) +static int ch341_set_handshake(struct usb_device *dev, + struct ch341_private *priv) { dbg("ch341_set_handshake(%d,%d)", priv->dtr, priv->rts); return ch341_control_out(dev, 0xa4, ~((priv->dtr?1<<5:0)|(priv->rts?1<<6:0)), 0); } -int ch341_get_status(struct usb_device *dev) +static int ch341_get_status(struct usb_device *dev) { char *buffer; int r; @@ -142,7 +144,7 @@ out: kfree(buffer); /* -------------------------------------------------------------------------- */ -int ch341_configure(struct usb_device *dev, struct ch341_private *priv) +static int ch341_configure(struct usb_device *dev, struct ch341_private *priv) { char *buffer; int r; -- cgit v1.2.3-70-g09d2 From e3a09051a16fcdb190ad0b7dc6064904c8118409 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Wed, 3 Oct 2007 18:53:13 +0900 Subject: USB: r8a66597-hcd: fix Class or Vendor Request Fixed the problem that does not work in the case of bRequest = 0x05 in Class or Vendor Request. Signed-off-by: Yoshihiro Shimoda Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/r8a66597-hcd.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index fd00f1e33fb..0a699efe6c9 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -1034,6 +1034,15 @@ static void prepare_status_packet(struct r8a66597 *r8a66597, pipe_start(r8a66597, td->pipe); } +static int is_set_address(unsigned char *setup_packet) +{ + if (((setup_packet[0] & USB_TYPE_MASK) == USB_TYPE_STANDARD) && + setup_packet[1] == USB_REQ_SET_ADDRESS) + return 1; + else + return 0; +} + /* this function must be called with interrupt disabled */ static int start_transfer(struct r8a66597 *r8a66597, struct r8a66597_td *td) { @@ -1041,7 +1050,7 @@ static int start_transfer(struct r8a66597 *r8a66597, struct r8a66597_td *td) switch (td->type) { case USB_PID_SETUP: - if (td->urb->setup_packet[1] == USB_REQ_SET_ADDRESS) { + if (is_set_address(td->urb->setup_packet)) { td->set_address = 1; td->urb->setup_packet[2] = alloc_usb_address(r8a66597, td->urb); -- cgit v1.2.3-70-g09d2 From 05eac910b69209164b1d9357bf8877a7c81b2e4e Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Wed, 3 Oct 2007 18:53:28 +0900 Subject: USB: r8a66597-hcd: fix endian problem Fixed the problem that does not work in the big endian machine. Signed-off-by: Yoshihiro Shimoda Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/r8a66597-hcd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 0a699efe6c9..64fba53c263 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -834,7 +834,7 @@ static void init_pipe_info(struct r8a66597 *r8a66597, struct urb *urb, info.pipenum = get_empty_pipenum(r8a66597, ep); info.address = get_urb_to_r8a66597_addr(r8a66597, urb); info.epnum = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; - info.maxpacket = ep->wMaxPacketSize; + info.maxpacket = le16_to_cpu(ep->wMaxPacketSize); info.type = get_r8a66597_type(ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK); info.bufnum = get_bufnum(info.pipenum); @@ -925,7 +925,7 @@ static void prepare_setup_packet(struct r8a66597 *r8a66597, r8a66597_write(r8a66597, ~(SIGN | SACK), INTSTS1); for (i = 0; i < 4; i++) { - r8a66597_write(r8a66597, p[i], setup_addr); + r8a66597_write(r8a66597, cpu_to_le16(p[i]), setup_addr); setup_addr += 2; } r8a66597_write(r8a66597, SUREQ, DCPCTR); @@ -2027,7 +2027,7 @@ static int r8a66597_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, case GetPortStatus: if (wIndex > R8A66597_MAX_ROOT_HUB) goto error; - *(u32 *)buf = rh->port; + *(u32 *)buf = cpu_to_le32(rh->port); break; case SetPortFeature: if (wIndex > R8A66597_MAX_ROOT_HUB) -- cgit v1.2.3-70-g09d2 From ca0677a29bddee35918bf3c0c55cc3badd69079e Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 5 Oct 2007 15:53:12 +0900 Subject: USB: r8a66597-hcd: fix driver removing Fixed the problem that accessed register of this controller after having called iounmap(). Signed-off-by: Yoshihiro Shimoda Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/r8a66597-hcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 64fba53c263..ae8ec4474eb 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -2126,8 +2126,8 @@ static int __init_or_module r8a66597_remove(struct platform_device *pdev) struct usb_hcd *hcd = r8a66597_to_hcd(r8a66597); del_timer_sync(&r8a66597->rh_timer); - iounmap((void *)r8a66597->reg); usb_remove_hcd(hcd); + iounmap((void *)r8a66597->reg); usb_put_hcd(hcd); return 0; } -- cgit v1.2.3-70-g09d2 From 9dcfbd97a695a3c28a867501127fa35ac49bc805 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 2 Oct 2007 14:40:46 -0700 Subject: USB: fix gregkh-usb-usb-sisusb2vga-convert-printk-to-dev_-macros drivers/usb/misc/sisusbvga/sisusb.c: In function 'sisusb_open': drivers/usb/misc/sisusbvga/sisusb.c:2444: warning: 'sisusb' is used uninitialized in this function I can tell that'll oops just by looking at it. How come this code assume a 7,000 column xterm? :( Cc: Felipe Balbi Cc: Thomas Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/sisusbvga/sisusb.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index 033bdfe9b21..0790829a570 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -3323,15 +3323,7 @@ static int __init usb_sisusb_init(void) sisusb_init_concode(); #endif - if (!(retval = usb_register(&sisusb_driver))) { - - dev_info(&sisusb->sisusb_dev->dev, "Driver version %d.%d.%d\n", SISUSB_VERSION, - SISUSB_REVISION, SISUSB_PATCHLEVEL); - dev_info(&sisusb->sisusb_dev->dev, "sisusb: Copyright (C) 2005 Thomas Winischhofer\n"); - - } - - return retval; + return usb_register(&sisusb_driver); } static void __exit usb_sisusb_exit(void) -- cgit v1.2.3-70-g09d2 From 5395353e0c8272fe73ac914acd7e4add0da2bef0 Mon Sep 17 00:00:00 2001 From: Benedikt Spranger Date: Tue, 2 Oct 2007 14:40:48 -0700 Subject: usb-gadget-ether: prevent oops caused by error interrupt race Fix a longstanding race in the Ethernet gadget driver, which can cause an oops on device disconnect. The fix is just to make the TX path check whether its freelist is empty. That check is otherwise not necessary, since the queue is always stopped when that list empties (and restarted when request completion puts an entry back on that freelist). The race window starts when the network code decides to transmit a packet, and ends when hard_start_xmit() grabs the freelist lock. When disconnect() is called inside that window, it shuts down the TX queue and breaks the otherwise-solid assumption that packets are never sent through a TX queue that's stopped. Signed-off-by: Benedikt Spranger Signed-off-by: Thomas Gleixner Signed-off-by: David Brownell Signed-off-by: Andrew Morton Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/ether.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index ff244f42723..9f4fd7e849a 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -1957,8 +1957,20 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net) } spin_lock_irqsave(&dev->req_lock, flags); + /* + * this freelist can be empty if an interrupt triggered disconnect() + * and reconfigured the gadget (shutting down this queue) after the + * network stack decided to xmit but before we got the spinlock. + */ + if (list_empty(&dev->tx_reqs)) { + spin_unlock_irqrestore(&dev->req_lock, flags); + return 1; + } + req = container_of (dev->tx_reqs.next, struct usb_request, list); list_del (&req->list); + + /* temporarily stop TX queue when the freelist empties */ if (list_empty (&dev->tx_reqs)) netif_stop_queue (net); spin_unlock_irqrestore(&dev->req_lock, flags); -- cgit v1.2.3-70-g09d2 From a59048d46303c4146993c37f51ed97a760fc4c0a Mon Sep 17 00:00:00 2001 From: WANG Cong Date: Tue, 2 Oct 2007 14:40:49 -0700 Subject: USB: drivers/usb/misc/sisusbvga/sisusb.c: kill two unused variables Kill two unused variables in drivers/usb/misc/sisusbvga/sisusb.c. Signed-off-by: WANG Cong Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/sisusbvga/sisusb.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index 0790829a570..9244d067cec 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -3316,8 +3316,6 @@ static struct usb_driver sisusb_driver = { static int __init usb_sisusb_init(void) { - int retval; - struct sisusb_usb_data *sisusb; #ifdef INCL_SISUSB_CON sisusb_init_concode(); -- cgit v1.2.3-70-g09d2 From 437f375f262417b484f28007c3e8d21bd01d0e01 Mon Sep 17 00:00:00 2001 From: Vitaly Bordug Date: Thu, 27 Sep 2007 00:36:22 +0400 Subject: USB: serial gadget: Disable endpoints on unload After Serial gadget is being unloaded, neither serial itself, nor other gadget stuff can be loaded subsequently. Signed-off-by: Vitaly Bordug Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/serial.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index afdf71f76f7..a2a1ebc947d 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -1470,6 +1470,12 @@ static void /* __init_or_exit */ gs_unbind(struct usb_gadget *gadget) dev->dev_ctrl_req = NULL; } gs_free_ports(dev); + if (dev->dev_notify_ep) + usb_ep_disable(dev->dev_notify_ep); + if (dev->dev_in_ep) + usb_ep_disable(dev->dev_in_ep); + if (dev->dev_out_ep) + usb_ep_disable(dev->dev_out_ep); kfree(dev); set_gadget_data(gadget, NULL); } -- cgit v1.2.3-70-g09d2 From 4d59d8a11383ebf0e0260ee481a4e766959fd7d9 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Wed, 3 Oct 2007 14:56:03 -0700 Subject: USB: Export URB statistics for powertop powertop currently tracks interrupts generated by uhci, ehci, and ohci, but it has no way of telling which USB device to blame USB bus activity on. This patch exports the number of URBs that are submitted for a given device. Cat the file 'urbnum' in /sys/bus/usb/devices/.../ Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 2 ++ drivers/usb/core/sysfs.c | 11 +++++++++++ drivers/usb/core/usb.c | 1 + include/linux/usb.h | 1 + 4 files changed, 15 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 2c79aa6ca2b..3dd997df850 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1176,6 +1176,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) */ usb_get_urb(urb); atomic_inc(&urb->use_count); + atomic_inc(&urb->dev->urbnum); usbmon_urb_submit(&hcd->self, urb); /* NOTE requirements on root-hub callers (usbfs and the hub @@ -1197,6 +1198,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) urb->hcpriv = NULL; INIT_LIST_HEAD(&urb->urb_list); atomic_dec(&urb->use_count); + atomic_dec(&urb->dev->urbnum); if (urb->reject) wake_up(&usb_kill_urb_queue); usb_put_urb(urb); diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index e02590297d3..b04afd06e50 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -169,6 +169,16 @@ show_quirks(struct device *dev, struct device_attribute *attr, char *buf) } static DEVICE_ATTR(quirks, S_IRUGO, show_quirks, NULL); +static ssize_t +show_urbnum(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct usb_device *udev; + + udev = to_usb_device(dev); + return sprintf(buf, "%d\n", atomic_read(&udev->urbnum)); +} +static DEVICE_ATTR(urbnum, S_IRUGO, show_urbnum, NULL); + #if defined(CONFIG_USB_PERSIST) || defined(CONFIG_USB_SUSPEND) static const char power_group[] = "power"; @@ -458,6 +468,7 @@ static struct attribute *dev_attrs[] = { &dev_attr_bConfigurationValue.attr, &dev_attr_bmAttributes.attr, &dev_attr_bMaxPower.attr, + &dev_attr_urbnum.attr, /* device attributes */ &dev_attr_idVendor.attr, &dev_attr_idProduct.attr, diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 8121edbd149..c99938d5f78 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -266,6 +266,7 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) dev->dev.dma_mask = bus->controller->dma_mask; set_dev_node(&dev->dev, dev_to_node(bus->controller)); dev->state = USB_STATE_ATTACHED; + atomic_set(&dev->urbnum, 0); INIT_LIST_HEAD(&dev->ep0.urb_list); dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE; diff --git a/include/linux/usb.h b/include/linux/usb.h index e5b35e0dca2..c10935fdc03 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -415,6 +415,7 @@ struct usb_device { int pm_usage_cnt; /* usage counter for autosuspend */ u32 quirks; /* quirks of the whole device */ + atomic_t urbnum; /* number of URBs submitted for the whole device */ #ifdef CONFIG_PM struct delayed_work autosuspend; /* for delayed autosuspends */ -- cgit v1.2.3-70-g09d2 From 9454a57ab5922e5cd25321cae9d1a8cbeb3e2e85 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 4 Oct 2007 18:05:17 -0700 Subject: USB: move to Move to , reducing some of the clutter in the main include directory. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/amd5536udc.c | 2 +- drivers/usb/gadget/at91_udc.c | 2 +- drivers/usb/gadget/config.c | 2 +- drivers/usb/gadget/dummy_hcd.c | 2 +- drivers/usb/gadget/epautoconf.c | 2 +- drivers/usb/gadget/ether.c | 2 +- drivers/usb/gadget/file_storage.c | 2 +- drivers/usb/gadget/fsl_usb2_udc.c | 4 +- drivers/usb/gadget/gmidi.c | 2 +- drivers/usb/gadget/goku_udc.c | 2 +- drivers/usb/gadget/inode.c | 2 +- drivers/usb/gadget/lh7a40x_udc.h | 2 +- drivers/usb/gadget/m66592-udc.c | 2 +- drivers/usb/gadget/net2280.c | 2 +- drivers/usb/gadget/omap_udc.c | 2 +- drivers/usb/gadget/pxa2xx_udc.c | 2 +- drivers/usb/gadget/s3c2410_udc.c | 2 +- drivers/usb/gadget/serial.c | 2 +- drivers/usb/gadget/usbstring.c | 2 +- drivers/usb/gadget/zero.c | 2 +- include/linux/usb/gadget.h | 866 ++++++++++++++++++++++++++++++++++++++ include/linux/usb_gadget.h | 866 -------------------------------------- 22 files changed, 887 insertions(+), 887 deletions(-) create mode 100644 include/linux/usb/gadget.h delete mode 100644 include/linux/usb_gadget.h (limited to 'drivers') diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index bdd5f2284b3..1c804060252 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c @@ -69,7 +69,7 @@ /* gadget stack */ #include -#include +#include /* udc specific */ #include "amd5536udc.h" diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 63d7d656869..a6adf7e0f6f 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c index c6760aee1e5..a4e54b2743f 100644 --- a/drivers/usb/gadget/config.c +++ b/drivers/usb/gadget/config.c @@ -25,7 +25,7 @@ #include #include -#include +#include /** diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 6479a36d6f0..9db2482bdfa 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -46,7 +46,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index 3aa46cfa66b..f9d07108bc3 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -28,7 +28,7 @@ #include #include -#include +#include #include "gadget_chips.h" diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 9f4fd7e849a..9e732bff9df 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -30,7 +30,7 @@ #include #include -#include +#include #include "gadget_chips.h" diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 0551140010e..73726c570a6 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -240,7 +240,7 @@ #include #include -#include +#include #include "gadget_chips.h" diff --git a/drivers/usb/gadget/fsl_usb2_udc.c b/drivers/usb/gadget/fsl_usb2_udc.c index 89c768e2aed..9bb7f64a85c 100644 --- a/drivers/usb/gadget/fsl_usb2_udc.c +++ b/drivers/usb/gadget/fsl_usb2_udc.c @@ -35,7 +35,7 @@ #include #include #include -#include +#include #include #include #include @@ -1117,7 +1117,7 @@ static int fsl_pullup(struct usb_gadget *gadget, int is_on) return 0; } -/* defined in usb_gadget.h */ +/* defined in gadget.h */ static struct usb_gadget_ops fsl_gadget_ops = { .get_frame = fsl_get_frame, .wakeup = fsl_wakeup, diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c index d2475755a20..0689189550b 100644 --- a/drivers/usb/gadget/gmidi.c +++ b/drivers/usb/gadget/gmidi.c @@ -30,7 +30,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index 349b8166f34..2ec9d196a8c 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -37,7 +37,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 129eda5358f..47ef8bd58a0 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -37,7 +37,7 @@ #include #include -#include +#include /* diff --git a/drivers/usb/gadget/lh7a40x_udc.h b/drivers/usb/gadget/lh7a40x_udc.h index b3fe197e1ee..1ecfd6366b9 100644 --- a/drivers/usb/gadget/lh7a40x_udc.h +++ b/drivers/usb/gadget/lh7a40x_udc.h @@ -50,7 +50,7 @@ #include #include -#include +#include /* * Memory map diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c index 4b27d12f049..ebc5536aa27 100644 --- a/drivers/usb/gadget/m66592-udc.c +++ b/drivers/usb/gadget/m66592-udc.c @@ -27,7 +27,7 @@ #include #include -#include +#include #include "m66592-udc.h" diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index c3d364ecd4f..d5d473f8144 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -62,7 +62,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index bf2788dfb32..87c4f50dfb6 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c index 1407ad1c812..3e715082de3 100644 --- a/drivers/usb/gadget/pxa2xx_udc.c +++ b/drivers/usb/gadget/pxa2xx_udc.c @@ -54,7 +54,7 @@ #include #include -#include +#include #include diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c index 0be80c635c4..e3e90f8a75e 100644 --- a/drivers/usb/gadget/s3c2410_udc.c +++ b/drivers/usb/gadget/s3c2410_udc.c @@ -42,7 +42,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index a2a1ebc947d..f5738eb8e76 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -25,7 +25,7 @@ #include #include -#include +#include #include "gadget_chips.h" diff --git a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c index 3459ea6c6c0..878e428a0ec 100644 --- a/drivers/usb/gadget/usbstring.c +++ b/drivers/usb/gadget/usbstring.c @@ -15,7 +15,7 @@ #include #include -#include +#include #include diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index ff540879ce3..fcde5d9c87d 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -55,7 +55,7 @@ #include #include -#include +#include #include "gadget_chips.h" diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h new file mode 100644 index 00000000000..46705e91573 --- /dev/null +++ b/include/linux/usb/gadget.h @@ -0,0 +1,866 @@ +/* + * + * + * We call the USB code inside a Linux-based peripheral device a "gadget" + * driver, except for the hardware-specific bus glue. One USB host can + * master many USB gadgets, but the gadgets are only slaved to one host. + * + * + * (C) Copyright 2002-2004 by David Brownell + * All Rights Reserved. + * + * This software is licensed under the GNU GPL version 2. + */ + +#ifndef __LINUX_USB_GADGET_H +#define __LINUX_USB_GADGET_H + +#ifdef __KERNEL__ + +struct usb_ep; + +/** + * struct usb_request - describes one i/o request + * @buf: Buffer used for data. Always provide this; some controllers + * only use PIO, or don't use DMA for some endpoints. + * @dma: DMA address corresponding to 'buf'. If you don't set this + * field, and the usb controller needs one, it is responsible + * for mapping and unmapping the buffer. + * @length: Length of that data + * @no_interrupt: If true, hints that no completion irq is needed. + * Helpful sometimes with deep request queues that are handled + * directly by DMA controllers. + * @zero: If true, when writing data, makes the last packet be "short" + * by adding a zero length packet as needed; + * @short_not_ok: When reading data, makes short packets be + * treated as errors (queue stops advancing till cleanup). + * @complete: Function called when request completes, so this request and + * its buffer may be re-used. + * Reads terminate with a short packet, or when the buffer fills, + * whichever comes first. When writes terminate, some data bytes + * will usually still be in flight (often in a hardware fifo). + * Errors (for reads or writes) stop the queue from advancing + * until the completion function returns, so that any transfers + * invalidated by the error may first be dequeued. + * @context: For use by the completion callback + * @list: For use by the gadget driver. + * @status: Reports completion code, zero or a negative errno. + * Normally, faults block the transfer queue from advancing until + * the completion callback returns. + * Code "-ESHUTDOWN" indicates completion caused by device disconnect, + * or when the driver disabled the endpoint. + * @actual: Reports bytes transferred to/from the buffer. For reads (OUT + * transfers) this may be less than the requested length. If the + * short_not_ok flag is set, short reads are treated as errors + * even when status otherwise indicates successful completion. + * Note that for writes (IN transfers) some data bytes may still + * reside in a device-side FIFO when the request is reported as + * complete. + * + * These are allocated/freed through the endpoint they're used with. The + * hardware's driver can add extra per-request data to the memory it returns, + * which often avoids separate memory allocations (potential failures), + * later when the request is queued. + * + * Request flags affect request handling, such as whether a zero length + * packet is written (the "zero" flag), whether a short read should be + * treated as an error (blocking request queue advance, the "short_not_ok" + * flag), or hinting that an interrupt is not required (the "no_interrupt" + * flag, for use with deep request queues). + * + * Bulk endpoints can use any size buffers, and can also be used for interrupt + * transfers. interrupt-only endpoints can be much less functional. + */ + // NOTE this is analagous to 'struct urb' on the host side, + // except that it's thinner and promotes more pre-allocation. + +struct usb_request { + void *buf; + unsigned length; + dma_addr_t dma; + + unsigned no_interrupt:1; + unsigned zero:1; + unsigned short_not_ok:1; + + void (*complete)(struct usb_ep *ep, + struct usb_request *req); + void *context; + struct list_head list; + + int status; + unsigned actual; +}; + +/*-------------------------------------------------------------------------*/ + +/* endpoint-specific parts of the api to the usb controller hardware. + * unlike the urb model, (de)multiplexing layers are not required. + * (so this api could slash overhead if used on the host side...) + * + * note that device side usb controllers commonly differ in how many + * endpoints they support, as well as their capabilities. + */ +struct usb_ep_ops { + int (*enable) (struct usb_ep *ep, + const struct usb_endpoint_descriptor *desc); + int (*disable) (struct usb_ep *ep); + + struct usb_request *(*alloc_request) (struct usb_ep *ep, + gfp_t gfp_flags); + void (*free_request) (struct usb_ep *ep, struct usb_request *req); + + int (*queue) (struct usb_ep *ep, struct usb_request *req, + gfp_t gfp_flags); + int (*dequeue) (struct usb_ep *ep, struct usb_request *req); + + int (*set_halt) (struct usb_ep *ep, int value); + int (*fifo_status) (struct usb_ep *ep); + void (*fifo_flush) (struct usb_ep *ep); +}; + +/** + * struct usb_ep - device side representation of USB endpoint + * @name:identifier for the endpoint, such as "ep-a" or "ep9in-bulk" + * @ops: Function pointers used to access hardware-specific operations. + * @ep_list:the gadget's ep_list holds all of its endpoints + * @maxpacket:The maximum packet size used on this endpoint. The initial + * value can sometimes be reduced (hardware allowing), according to + * the endpoint descriptor used to configure the endpoint. + * @driver_data:for use by the gadget driver. all other fields are + * read-only to gadget drivers. + * + * the bus controller driver lists all the general purpose endpoints in + * gadget->ep_list. the control endpoint (gadget->ep0) is not in that list, + * and is accessed only in response to a driver setup() callback. + */ +struct usb_ep { + void *driver_data; + + const char *name; + const struct usb_ep_ops *ops; + struct list_head ep_list; + unsigned maxpacket:16; +}; + +/*-------------------------------------------------------------------------*/ + +/** + * usb_ep_enable - configure endpoint, making it usable + * @ep:the endpoint being configured. may not be the endpoint named "ep0". + * drivers discover endpoints through the ep_list of a usb_gadget. + * @desc:descriptor for desired behavior. caller guarantees this pointer + * remains valid until the endpoint is disabled; the data byte order + * is little-endian (usb-standard). + * + * when configurations are set, or when interface settings change, the driver + * will enable or disable the relevant endpoints. while it is enabled, an + * endpoint may be used for i/o until the driver receives a disconnect() from + * the host or until the endpoint is disabled. + * + * the ep0 implementation (which calls this routine) must ensure that the + * hardware capabilities of each endpoint match the descriptor provided + * for it. for example, an endpoint named "ep2in-bulk" would be usable + * for interrupt transfers as well as bulk, but it likely couldn't be used + * for iso transfers or for endpoint 14. some endpoints are fully + * configurable, with more generic names like "ep-a". (remember that for + * USB, "in" means "towards the USB master".) + * + * returns zero, or a negative error code. + */ +static inline int +usb_ep_enable (struct usb_ep *ep, const struct usb_endpoint_descriptor *desc) +{ + return ep->ops->enable (ep, desc); +} + +/** + * usb_ep_disable - endpoint is no longer usable + * @ep:the endpoint being unconfigured. may not be the endpoint named "ep0". + * + * no other task may be using this endpoint when this is called. + * any pending and uncompleted requests will complete with status + * indicating disconnect (-ESHUTDOWN) before this call returns. + * gadget drivers must call usb_ep_enable() again before queueing + * requests to the endpoint. + * + * returns zero, or a negative error code. + */ +static inline int +usb_ep_disable (struct usb_ep *ep) +{ + return ep->ops->disable (ep); +} + +/** + * usb_ep_alloc_request - allocate a request object to use with this endpoint + * @ep:the endpoint to be used with with the request + * @gfp_flags:GFP_* flags to use + * + * Request objects must be allocated with this call, since they normally + * need controller-specific setup and may even need endpoint-specific + * resources such as allocation of DMA descriptors. + * Requests may be submitted with usb_ep_queue(), and receive a single + * completion callback. Free requests with usb_ep_free_request(), when + * they are no longer needed. + * + * Returns the request, or null if one could not be allocated. + */ +static inline struct usb_request * +usb_ep_alloc_request (struct usb_ep *ep, gfp_t gfp_flags) +{ + return ep->ops->alloc_request (ep, gfp_flags); +} + +/** + * usb_ep_free_request - frees a request object + * @ep:the endpoint associated with the request + * @req:the request being freed + * + * Reverses the effect of usb_ep_alloc_request(). + * Caller guarantees the request is not queued, and that it will + * no longer be requeued (or otherwise used). + */ +static inline void +usb_ep_free_request (struct usb_ep *ep, struct usb_request *req) +{ + ep->ops->free_request (ep, req); +} + +/** + * usb_ep_queue - queues (submits) an I/O request to an endpoint. + * @ep:the endpoint associated with the request + * @req:the request being submitted + * @gfp_flags: GFP_* flags to use in case the lower level driver couldn't + * pre-allocate all necessary memory with the request. + * + * This tells the device controller to perform the specified request through + * that endpoint (reading or writing a buffer). When the request completes, + * including being canceled by usb_ep_dequeue(), the request's completion + * routine is called to return the request to the driver. Any endpoint + * (except control endpoints like ep0) may have more than one transfer + * request queued; they complete in FIFO order. Once a gadget driver + * submits a request, that request may not be examined or modified until it + * is given back to that driver through the completion callback. + * + * Each request is turned into one or more packets. The controller driver + * never merges adjacent requests into the same packet. OUT transfers + * will sometimes use data that's already buffered in the hardware. + * Drivers can rely on the fact that the first byte of the request's buffer + * always corresponds to the first byte of some USB packet, for both + * IN and OUT transfers. + * + * Bulk endpoints can queue any amount of data; the transfer is packetized + * automatically. The last packet will be short if the request doesn't fill it + * out completely. Zero length packets (ZLPs) should be avoided in portable + * protocols since not all usb hardware can successfully handle zero length + * packets. (ZLPs may be explicitly written, and may be implicitly written if + * the request 'zero' flag is set.) Bulk endpoints may also be used + * for interrupt transfers; but the reverse is not true, and some endpoints + * won't support every interrupt transfer. (Such as 768 byte packets.) + * + * Interrupt-only endpoints are less functional than bulk endpoints, for + * example by not supporting queueing or not handling buffers that are + * larger than the endpoint's maxpacket size. They may also treat data + * toggle differently. + * + * Control endpoints ... after getting a setup() callback, the driver queues + * one response (even if it would be zero length). That enables the + * status ack, after transfering data as specified in the response. Setup + * functions may return negative error codes to generate protocol stalls. + * (Note that some USB device controllers disallow protocol stall responses + * in some cases.) When control responses are deferred (the response is + * written after the setup callback returns), then usb_ep_set_halt() may be + * used on ep0 to trigger protocol stalls. + * + * For periodic endpoints, like interrupt or isochronous ones, the usb host + * arranges to poll once per interval, and the gadget driver usually will + * have queued some data to transfer at that time. + * + * Returns zero, or a negative error code. Endpoints that are not enabled + * report errors; errors will also be + * reported when the usb peripheral is disconnected. + */ +static inline int +usb_ep_queue (struct usb_ep *ep, struct usb_request *req, gfp_t gfp_flags) +{ + return ep->ops->queue (ep, req, gfp_flags); +} + +/** + * usb_ep_dequeue - dequeues (cancels, unlinks) an I/O request from an endpoint + * @ep:the endpoint associated with the request + * @req:the request being canceled + * + * if the request is still active on the endpoint, it is dequeued and its + * completion routine is called (with status -ECONNRESET); else a negative + * error code is returned. + * + * note that some hardware can't clear out write fifos (to unlink the request + * at the head of the queue) except as part of disconnecting from usb. such + * restrictions prevent drivers from supporting configuration changes, + * even to configuration zero (a "chapter 9" requirement). + */ +static inline int usb_ep_dequeue (struct usb_ep *ep, struct usb_request *req) +{ + return ep->ops->dequeue (ep, req); +} + +/** + * usb_ep_set_halt - sets the endpoint halt feature. + * @ep: the non-isochronous endpoint being stalled + * + * Use this to stall an endpoint, perhaps as an error report. + * Except for control endpoints, + * the endpoint stays halted (will not stream any data) until the host + * clears this feature; drivers may need to empty the endpoint's request + * queue first, to make sure no inappropriate transfers happen. + * + * Note that while an endpoint CLEAR_FEATURE will be invisible to the + * gadget driver, a SET_INTERFACE will not be. To reset endpoints for the + * current altsetting, see usb_ep_clear_halt(). When switching altsettings, + * it's simplest to use usb_ep_enable() or usb_ep_disable() for the endpoints. + * + * Returns zero, or a negative error code. On success, this call sets + * underlying hardware state that blocks data transfers. + * Attempts to halt IN endpoints will fail (returning -EAGAIN) if any + * transfer requests are still queued, or if the controller hardware + * (usually a FIFO) still holds bytes that the host hasn't collected. + */ +static inline int +usb_ep_set_halt (struct usb_ep *ep) +{ + return ep->ops->set_halt (ep, 1); +} + +/** + * usb_ep_clear_halt - clears endpoint halt, and resets toggle + * @ep:the bulk or interrupt endpoint being reset + * + * Use this when responding to the standard usb "set interface" request, + * for endpoints that aren't reconfigured, after clearing any other state + * in the endpoint's i/o queue. + * + * Returns zero, or a negative error code. On success, this call clears + * the underlying hardware state reflecting endpoint halt and data toggle. + * Note that some hardware can't support this request (like pxa2xx_udc), + * and accordingly can't correctly implement interface altsettings. + */ +static inline int +usb_ep_clear_halt (struct usb_ep *ep) +{ + return ep->ops->set_halt (ep, 0); +} + +/** + * usb_ep_fifo_status - returns number of bytes in fifo, or error + * @ep: the endpoint whose fifo status is being checked. + * + * FIFO endpoints may have "unclaimed data" in them in certain cases, + * such as after aborted transfers. Hosts may not have collected all + * the IN data written by the gadget driver (and reported by a request + * completion). The gadget driver may not have collected all the data + * written OUT to it by the host. Drivers that need precise handling for + * fault reporting or recovery may need to use this call. + * + * This returns the number of such bytes in the fifo, or a negative + * errno if the endpoint doesn't use a FIFO or doesn't support such + * precise handling. + */ +static inline int +usb_ep_fifo_status (struct usb_ep *ep) +{ + if (ep->ops->fifo_status) + return ep->ops->fifo_status (ep); + else + return -EOPNOTSUPP; +} + +/** + * usb_ep_fifo_flush - flushes contents of a fifo + * @ep: the endpoint whose fifo is being flushed. + * + * This call may be used to flush the "unclaimed data" that may exist in + * an endpoint fifo after abnormal transaction terminations. The call + * must never be used except when endpoint is not being used for any + * protocol translation. + */ +static inline void +usb_ep_fifo_flush (struct usb_ep *ep) +{ + if (ep->ops->fifo_flush) + ep->ops->fifo_flush (ep); +} + + +/*-------------------------------------------------------------------------*/ + +struct usb_gadget; + +/* the rest of the api to the controller hardware: device operations, + * which don't involve endpoints (or i/o). + */ +struct usb_gadget_ops { + int (*get_frame)(struct usb_gadget *); + int (*wakeup)(struct usb_gadget *); + int (*set_selfpowered) (struct usb_gadget *, int is_selfpowered); + int (*vbus_session) (struct usb_gadget *, int is_active); + int (*vbus_draw) (struct usb_gadget *, unsigned mA); + int (*pullup) (struct usb_gadget *, int is_on); + int (*ioctl)(struct usb_gadget *, + unsigned code, unsigned long param); +}; + +/** + * struct usb_gadget - represents a usb slave device + * @ops: Function pointers used to access hardware-specific operations. + * @ep0: Endpoint zero, used when reading or writing responses to + * driver setup() requests + * @ep_list: List of other endpoints supported by the device. + * @speed: Speed of current connection to USB host. + * @is_dualspeed: True if the controller supports both high and full speed + * operation. If it does, the gadget driver must also support both. + * @is_otg: True if the USB device port uses a Mini-AB jack, so that the + * gadget driver must provide a USB OTG descriptor. + * @is_a_peripheral: False unless is_otg, the "A" end of a USB cable + * is in the Mini-AB jack, and HNP has been used to switch roles + * so that the "A" device currently acts as A-Peripheral, not A-Host. + * @a_hnp_support: OTG device feature flag, indicating that the A-Host + * supports HNP at this port. + * @a_alt_hnp_support: OTG device feature flag, indicating that the A-Host + * only supports HNP on a different root port. + * @b_hnp_enable: OTG device feature flag, indicating that the A-Host + * enabled HNP support. + * @name: Identifies the controller hardware type. Used in diagnostics + * and sometimes configuration. + * @dev: Driver model state for this abstract device. + * + * Gadgets have a mostly-portable "gadget driver" implementing device + * functions, handling all usb configurations and interfaces. Gadget + * drivers talk to hardware-specific code indirectly, through ops vectors. + * That insulates the gadget driver from hardware details, and packages + * the hardware endpoints through generic i/o queues. The "usb_gadget" + * and "usb_ep" interfaces provide that insulation from the hardware. + * + * Except for the driver data, all fields in this structure are + * read-only to the gadget driver. That driver data is part of the + * "driver model" infrastructure in 2.6 (and later) kernels, and for + * earlier systems is grouped in a similar structure that's not known + * to the rest of the kernel. + * + * Values of the three OTG device feature flags are updated before the + * setup() call corresponding to USB_REQ_SET_CONFIGURATION, and before + * driver suspend() calls. They are valid only when is_otg, and when the + * device is acting as a B-Peripheral (so is_a_peripheral is false). + */ +struct usb_gadget { + /* readonly to gadget driver */ + const struct usb_gadget_ops *ops; + struct usb_ep *ep0; + struct list_head ep_list; /* of usb_ep */ + enum usb_device_speed speed; + unsigned is_dualspeed:1; + unsigned is_otg:1; + unsigned is_a_peripheral:1; + unsigned b_hnp_enable:1; + unsigned a_hnp_support:1; + unsigned a_alt_hnp_support:1; + const char *name; + struct device dev; +}; + +static inline void set_gadget_data (struct usb_gadget *gadget, void *data) + { dev_set_drvdata (&gadget->dev, data); } +static inline void *get_gadget_data (struct usb_gadget *gadget) + { return dev_get_drvdata (&gadget->dev); } + +/* iterates the non-control endpoints; 'tmp' is a struct usb_ep pointer */ +#define gadget_for_each_ep(tmp,gadget) \ + list_for_each_entry(tmp, &(gadget)->ep_list, ep_list) + + +/** + * gadget_is_dualspeed - return true iff the hardware handles high speed + * @gadget: controller that might support both high and full speeds + */ +static inline int gadget_is_dualspeed(struct usb_gadget *g) +{ +#ifdef CONFIG_USB_GADGET_DUALSPEED + /* runtime test would check "g->is_dualspeed" ... that might be + * useful to work around hardware bugs, but is mostly pointless + */ + return 1; +#else + return 0; +#endif +} + +/** + * gadget_is_otg - return true iff the hardware is OTG-ready + * @gadget: controller that might have a Mini-AB connector + * + * This is a runtime test, since kernels with a USB-OTG stack sometimes + * run on boards which only have a Mini-B (or Mini-A) connector. + */ +static inline int gadget_is_otg(struct usb_gadget *g) +{ +#ifdef CONFIG_USB_OTG + return g->is_otg; +#else + return 0; +#endif +} + + +/** + * usb_gadget_frame_number - returns the current frame number + * @gadget: controller that reports the frame number + * + * Returns the usb frame number, normally eleven bits from a SOF packet, + * or negative errno if this device doesn't support this capability. + */ +static inline int usb_gadget_frame_number (struct usb_gadget *gadget) +{ + return gadget->ops->get_frame (gadget); +} + +/** + * usb_gadget_wakeup - tries to wake up the host connected to this gadget + * @gadget: controller used to wake up the host + * + * Returns zero on success, else negative error code if the hardware + * doesn't support such attempts, or its support has not been enabled + * by the usb host. Drivers must return device descriptors that report + * their ability to support this, or hosts won't enable it. + * + * This may also try to use SRP to wake the host and start enumeration, + * even if OTG isn't otherwise in use. OTG devices may also start + * remote wakeup even when hosts don't explicitly enable it. + */ +static inline int usb_gadget_wakeup (struct usb_gadget *gadget) +{ + if (!gadget->ops->wakeup) + return -EOPNOTSUPP; + return gadget->ops->wakeup (gadget); +} + +/** + * usb_gadget_set_selfpowered - sets the device selfpowered feature. + * @gadget:the device being declared as self-powered + * + * this affects the device status reported by the hardware driver + * to reflect that it now has a local power supply. + * + * returns zero on success, else negative errno. + */ +static inline int +usb_gadget_set_selfpowered (struct usb_gadget *gadget) +{ + if (!gadget->ops->set_selfpowered) + return -EOPNOTSUPP; + return gadget->ops->set_selfpowered (gadget, 1); +} + +/** + * usb_gadget_clear_selfpowered - clear the device selfpowered feature. + * @gadget:the device being declared as bus-powered + * + * this affects the device status reported by the hardware driver. + * some hardware may not support bus-powered operation, in which + * case this feature's value can never change. + * + * returns zero on success, else negative errno. + */ +static inline int +usb_gadget_clear_selfpowered (struct usb_gadget *gadget) +{ + if (!gadget->ops->set_selfpowered) + return -EOPNOTSUPP; + return gadget->ops->set_selfpowered (gadget, 0); +} + +/** + * usb_gadget_vbus_connect - Notify controller that VBUS is powered + * @gadget:The device which now has VBUS power. + * + * This call is used by a driver for an external transceiver (or GPIO) + * that detects a VBUS power session starting. Common responses include + * resuming the controller, activating the D+ (or D-) pullup to let the + * host detect that a USB device is attached, and starting to draw power + * (8mA or possibly more, especially after SET_CONFIGURATION). + * + * Returns zero on success, else negative errno. + */ +static inline int +usb_gadget_vbus_connect(struct usb_gadget *gadget) +{ + if (!gadget->ops->vbus_session) + return -EOPNOTSUPP; + return gadget->ops->vbus_session (gadget, 1); +} + +/** + * usb_gadget_vbus_draw - constrain controller's VBUS power usage + * @gadget:The device whose VBUS usage is being described + * @mA:How much current to draw, in milliAmperes. This should be twice + * the value listed in the configuration descriptor bMaxPower field. + * + * This call is used by gadget drivers during SET_CONFIGURATION calls, + * reporting how much power the device may consume. For example, this + * could affect how quickly batteries are recharged. + * + * Returns zero on success, else negative errno. + */ +static inline int +usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA) +{ + if (!gadget->ops->vbus_draw) + return -EOPNOTSUPP; + return gadget->ops->vbus_draw (gadget, mA); +} + +/** + * usb_gadget_vbus_disconnect - notify controller about VBUS session end + * @gadget:the device whose VBUS supply is being described + * + * This call is used by a driver for an external transceiver (or GPIO) + * that detects a VBUS power session ending. Common responses include + * reversing everything done in usb_gadget_vbus_connect(). + * + * Returns zero on success, else negative errno. + */ +static inline int +usb_gadget_vbus_disconnect(struct usb_gadget *gadget) +{ + if (!gadget->ops->vbus_session) + return -EOPNOTSUPP; + return gadget->ops->vbus_session (gadget, 0); +} + +/** + * usb_gadget_connect - software-controlled connect to USB host + * @gadget:the peripheral being connected + * + * Enables the D+ (or potentially D-) pullup. The host will start + * enumerating this gadget when the pullup is active and a VBUS session + * is active (the link is powered). This pullup is always enabled unless + * usb_gadget_disconnect() has been used to disable it. + * + * Returns zero on success, else negative errno. + */ +static inline int +usb_gadget_connect (struct usb_gadget *gadget) +{ + if (!gadget->ops->pullup) + return -EOPNOTSUPP; + return gadget->ops->pullup (gadget, 1); +} + +/** + * usb_gadget_disconnect - software-controlled disconnect from USB host + * @gadget:the peripheral being disconnected + * + * Disables the D+ (or potentially D-) pullup, which the host may see + * as a disconnect (when a VBUS session is active). Not all systems + * support software pullup controls. + * + * This routine may be used during the gadget driver bind() call to prevent + * the peripheral from ever being visible to the USB host, unless later + * usb_gadget_connect() is called. For example, user mode components may + * need to be activated before the system can talk to hosts. + * + * Returns zero on success, else negative errno. + */ +static inline int +usb_gadget_disconnect (struct usb_gadget *gadget) +{ + if (!gadget->ops->pullup) + return -EOPNOTSUPP; + return gadget->ops->pullup (gadget, 0); +} + + + +/*-------------------------------------------------------------------------*/ + +/** + * struct usb_gadget_driver - driver for usb 'slave' devices + * @function: String describing the gadget's function + * @speed: Highest speed the driver handles. + * @bind: Invoked when the driver is bound to a gadget, usually + * after registering the driver. + * At that point, ep0 is fully initialized, and ep_list holds + * the currently-available endpoints. + * Called in a context that permits sleeping. + * @setup: Invoked for ep0 control requests that aren't handled by + * the hardware level driver. Most calls must be handled by + * the gadget driver, including descriptor and configuration + * management. The 16 bit members of the setup data are in + * USB byte order. Called in_interrupt; this may not sleep. Driver + * queues a response to ep0, or returns negative to stall. + * @disconnect: Invoked after all transfers have been stopped, + * when the host is disconnected. May be called in_interrupt; this + * may not sleep. Some devices can't detect disconnect, so this might + * not be called except as part of controller shutdown. + * @unbind: Invoked when the driver is unbound from a gadget, + * usually from rmmod (after a disconnect is reported). + * Called in a context that permits sleeping. + * @suspend: Invoked on USB suspend. May be called in_interrupt. + * @resume: Invoked on USB resume. May be called in_interrupt. + * @driver: Driver model state for this driver. + * + * Devices are disabled till a gadget driver successfully bind()s, which + * means the driver will handle setup() requests needed to enumerate (and + * meet "chapter 9" requirements) then do some useful work. + * + * If gadget->is_otg is true, the gadget driver must provide an OTG + * descriptor during enumeration, or else fail the bind() call. In such + * cases, no USB traffic may flow until both bind() returns without + * having called usb_gadget_disconnect(), and the USB host stack has + * initialized. + * + * Drivers use hardware-specific knowledge to configure the usb hardware. + * endpoint addressing is only one of several hardware characteristics that + * are in descriptors the ep0 implementation returns from setup() calls. + * + * Except for ep0 implementation, most driver code shouldn't need change to + * run on top of different usb controllers. It'll use endpoints set up by + * that ep0 implementation. + * + * The usb controller driver handles a few standard usb requests. Those + * include set_address, and feature flags for devices, interfaces, and + * endpoints (the get_status, set_feature, and clear_feature requests). + * + * Accordingly, the driver's setup() callback must always implement all + * get_descriptor requests, returning at least a device descriptor and + * a configuration descriptor. Drivers must make sure the endpoint + * descriptors match any hardware constraints. Some hardware also constrains + * other descriptors. (The pxa250 allows only configurations 1, 2, or 3). + * + * The driver's setup() callback must also implement set_configuration, + * and should also implement set_interface, get_configuration, and + * get_interface. Setting a configuration (or interface) is where + * endpoints should be activated or (config 0) shut down. + * + * (Note that only the default control endpoint is supported. Neither + * hosts nor devices generally support control traffic except to ep0.) + * + * Most devices will ignore USB suspend/resume operations, and so will + * not provide those callbacks. However, some may need to change modes + * when the host is not longer directing those activities. For example, + * local controls (buttons, dials, etc) may need to be re-enabled since + * the (remote) host can't do that any longer; or an error state might + * be cleared, to make the device behave identically whether or not + * power is maintained. + */ +struct usb_gadget_driver { + char *function; + enum usb_device_speed speed; + int (*bind)(struct usb_gadget *); + void (*unbind)(struct usb_gadget *); + int (*setup)(struct usb_gadget *, + const struct usb_ctrlrequest *); + void (*disconnect)(struct usb_gadget *); + void (*suspend)(struct usb_gadget *); + void (*resume)(struct usb_gadget *); + + // FIXME support safe rmmod + struct device_driver driver; +}; + + + +/*-------------------------------------------------------------------------*/ + +/* driver modules register and unregister, as usual. + * these calls must be made in a context that can sleep. + * + * these will usually be implemented directly by the hardware-dependent + * usb bus interface driver, which will only support a single driver. + */ + +/** + * usb_gadget_register_driver - register a gadget driver + * @driver:the driver being registered + * + * Call this in your gadget driver's module initialization function, + * to tell the underlying usb controller driver about your driver. + * The driver's bind() function will be called to bind it to a + * gadget before this registration call returns. It's expected that + * the bind() functions will be in init sections. + * This function must be called in a context that can sleep. + */ +int usb_gadget_register_driver (struct usb_gadget_driver *driver); + +/** + * usb_gadget_unregister_driver - unregister a gadget driver + * @driver:the driver being unregistered + * + * Call this in your gadget driver's module cleanup function, + * to tell the underlying usb controller that your driver is + * going away. If the controller is connected to a USB host, + * it will first disconnect(). The driver is also requested + * to unbind() and clean up any device state, before this procedure + * finally returns. It's expected that the unbind() functions + * will in in exit sections, so may not be linked in some kernels. + * This function must be called in a context that can sleep. + */ +int usb_gadget_unregister_driver (struct usb_gadget_driver *driver); + +/*-------------------------------------------------------------------------*/ + +/* utility to simplify dealing with string descriptors */ + +/** + * struct usb_string - wraps a C string and its USB id + * @id:the (nonzero) ID for this string + * @s:the string, in UTF-8 encoding + * + * If you're using usb_gadget_get_string(), use this to wrap a string + * together with its ID. + */ +struct usb_string { + u8 id; + const char *s; +}; + +/** + * struct usb_gadget_strings - a set of USB strings in a given language + * @language:identifies the strings' language (0x0409 for en-us) + * @strings:array of strings with their ids + * + * If you're using usb_gadget_get_string(), use this to wrap all the + * strings for a given language. + */ +struct usb_gadget_strings { + u16 language; /* 0x0409 for en-us */ + struct usb_string *strings; +}; + +/* put descriptor for string with that id into buf (buflen >= 256) */ +int usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf); + +/*-------------------------------------------------------------------------*/ + +/* utility to simplify managing config descriptors */ + +/* write vector of descriptors into buffer */ +int usb_descriptor_fillbuf(void *, unsigned, + const struct usb_descriptor_header **); + +/* build config descriptor from single descriptor vector */ +int usb_gadget_config_buf(const struct usb_config_descriptor *config, + void *buf, unsigned buflen, const struct usb_descriptor_header **desc); + +/*-------------------------------------------------------------------------*/ + +/* utility wrapping a simple endpoint selection policy */ + +extern struct usb_ep *usb_ep_autoconfig (struct usb_gadget *, + struct usb_endpoint_descriptor *) __devinit; + +extern void usb_ep_autoconfig_reset (struct usb_gadget *) __devinit; + +#endif /* __KERNEL__ */ + +#endif /* __LINUX_USB_GADGET_H */ diff --git a/include/linux/usb_gadget.h b/include/linux/usb_gadget.h deleted file mode 100644 index 5ea611e48ec..00000000000 --- a/include/linux/usb_gadget.h +++ /dev/null @@ -1,866 +0,0 @@ -/* - * - * - * We call the USB code inside a Linux-based peripheral device a "gadget" - * driver, except for the hardware-specific bus glue. One USB host can - * master many USB gadgets, but the gadgets are only slaved to one host. - * - * - * (C) Copyright 2002-2004 by David Brownell - * All Rights Reserved. - * - * This software is licensed under the GNU GPL version 2. - */ - -#ifndef __LINUX_USB_GADGET_H -#define __LINUX_USB_GADGET_H - -#ifdef __KERNEL__ - -struct usb_ep; - -/** - * struct usb_request - describes one i/o request - * @buf: Buffer used for data. Always provide this; some controllers - * only use PIO, or don't use DMA for some endpoints. - * @dma: DMA address corresponding to 'buf'. If you don't set this - * field, and the usb controller needs one, it is responsible - * for mapping and unmapping the buffer. - * @length: Length of that data - * @no_interrupt: If true, hints that no completion irq is needed. - * Helpful sometimes with deep request queues that are handled - * directly by DMA controllers. - * @zero: If true, when writing data, makes the last packet be "short" - * by adding a zero length packet as needed; - * @short_not_ok: When reading data, makes short packets be - * treated as errors (queue stops advancing till cleanup). - * @complete: Function called when request completes, so this request and - * its buffer may be re-used. - * Reads terminate with a short packet, or when the buffer fills, - * whichever comes first. When writes terminate, some data bytes - * will usually still be in flight (often in a hardware fifo). - * Errors (for reads or writes) stop the queue from advancing - * until the completion function returns, so that any transfers - * invalidated by the error may first be dequeued. - * @context: For use by the completion callback - * @list: For use by the gadget driver. - * @status: Reports completion code, zero or a negative errno. - * Normally, faults block the transfer queue from advancing until - * the completion callback returns. - * Code "-ESHUTDOWN" indicates completion caused by device disconnect, - * or when the driver disabled the endpoint. - * @actual: Reports bytes transferred to/from the buffer. For reads (OUT - * transfers) this may be less than the requested length. If the - * short_not_ok flag is set, short reads are treated as errors - * even when status otherwise indicates successful completion. - * Note that for writes (IN transfers) some data bytes may still - * reside in a device-side FIFO when the request is reported as - * complete. - * - * These are allocated/freed through the endpoint they're used with. The - * hardware's driver can add extra per-request data to the memory it returns, - * which often avoids separate memory allocations (potential failures), - * later when the request is queued. - * - * Request flags affect request handling, such as whether a zero length - * packet is written (the "zero" flag), whether a short read should be - * treated as an error (blocking request queue advance, the "short_not_ok" - * flag), or hinting that an interrupt is not required (the "no_interrupt" - * flag, for use with deep request queues). - * - * Bulk endpoints can use any size buffers, and can also be used for interrupt - * transfers. interrupt-only endpoints can be much less functional. - */ - // NOTE this is analagous to 'struct urb' on the host side, - // except that it's thinner and promotes more pre-allocation. - -struct usb_request { - void *buf; - unsigned length; - dma_addr_t dma; - - unsigned no_interrupt:1; - unsigned zero:1; - unsigned short_not_ok:1; - - void (*complete)(struct usb_ep *ep, - struct usb_request *req); - void *context; - struct list_head list; - - int status; - unsigned actual; -}; - -/*-------------------------------------------------------------------------*/ - -/* endpoint-specific parts of the api to the usb controller hardware. - * unlike the urb model, (de)multiplexing layers are not required. - * (so this api could slash overhead if used on the host side...) - * - * note that device side usb controllers commonly differ in how many - * endpoints they support, as well as their capabilities. - */ -struct usb_ep_ops { - int (*enable) (struct usb_ep *ep, - const struct usb_endpoint_descriptor *desc); - int (*disable) (struct usb_ep *ep); - - struct usb_request *(*alloc_request) (struct usb_ep *ep, - gfp_t gfp_flags); - void (*free_request) (struct usb_ep *ep, struct usb_request *req); - - int (*queue) (struct usb_ep *ep, struct usb_request *req, - gfp_t gfp_flags); - int (*dequeue) (struct usb_ep *ep, struct usb_request *req); - - int (*set_halt) (struct usb_ep *ep, int value); - int (*fifo_status) (struct usb_ep *ep); - void (*fifo_flush) (struct usb_ep *ep); -}; - -/** - * struct usb_ep - device side representation of USB endpoint - * @name:identifier for the endpoint, such as "ep-a" or "ep9in-bulk" - * @ops: Function pointers used to access hardware-specific operations. - * @ep_list:the gadget's ep_list holds all of its endpoints - * @maxpacket:The maximum packet size used on this endpoint. The initial - * value can sometimes be reduced (hardware allowing), according to - * the endpoint descriptor used to configure the endpoint. - * @driver_data:for use by the gadget driver. all other fields are - * read-only to gadget drivers. - * - * the bus controller driver lists all the general purpose endpoints in - * gadget->ep_list. the control endpoint (gadget->ep0) is not in that list, - * and is accessed only in response to a driver setup() callback. - */ -struct usb_ep { - void *driver_data; - - const char *name; - const struct usb_ep_ops *ops; - struct list_head ep_list; - unsigned maxpacket:16; -}; - -/*-------------------------------------------------------------------------*/ - -/** - * usb_ep_enable - configure endpoint, making it usable - * @ep:the endpoint being configured. may not be the endpoint named "ep0". - * drivers discover endpoints through the ep_list of a usb_gadget. - * @desc:descriptor for desired behavior. caller guarantees this pointer - * remains valid until the endpoint is disabled; the data byte order - * is little-endian (usb-standard). - * - * when configurations are set, or when interface settings change, the driver - * will enable or disable the relevant endpoints. while it is enabled, an - * endpoint may be used for i/o until the driver receives a disconnect() from - * the host or until the endpoint is disabled. - * - * the ep0 implementation (which calls this routine) must ensure that the - * hardware capabilities of each endpoint match the descriptor provided - * for it. for example, an endpoint named "ep2in-bulk" would be usable - * for interrupt transfers as well as bulk, but it likely couldn't be used - * for iso transfers or for endpoint 14. some endpoints are fully - * configurable, with more generic names like "ep-a". (remember that for - * USB, "in" means "towards the USB master".) - * - * returns zero, or a negative error code. - */ -static inline int -usb_ep_enable (struct usb_ep *ep, const struct usb_endpoint_descriptor *desc) -{ - return ep->ops->enable (ep, desc); -} - -/** - * usb_ep_disable - endpoint is no longer usable - * @ep:the endpoint being unconfigured. may not be the endpoint named "ep0". - * - * no other task may be using this endpoint when this is called. - * any pending and uncompleted requests will complete with status - * indicating disconnect (-ESHUTDOWN) before this call returns. - * gadget drivers must call usb_ep_enable() again before queueing - * requests to the endpoint. - * - * returns zero, or a negative error code. - */ -static inline int -usb_ep_disable (struct usb_ep *ep) -{ - return ep->ops->disable (ep); -} - -/** - * usb_ep_alloc_request - allocate a request object to use with this endpoint - * @ep:the endpoint to be used with with the request - * @gfp_flags:GFP_* flags to use - * - * Request objects must be allocated with this call, since they normally - * need controller-specific setup and may even need endpoint-specific - * resources such as allocation of DMA descriptors. - * Requests may be submitted with usb_ep_queue(), and receive a single - * completion callback. Free requests with usb_ep_free_request(), when - * they are no longer needed. - * - * Returns the request, or null if one could not be allocated. - */ -static inline struct usb_request * -usb_ep_alloc_request (struct usb_ep *ep, gfp_t gfp_flags) -{ - return ep->ops->alloc_request (ep, gfp_flags); -} - -/** - * usb_ep_free_request - frees a request object - * @ep:the endpoint associated with the request - * @req:the request being freed - * - * Reverses the effect of usb_ep_alloc_request(). - * Caller guarantees the request is not queued, and that it will - * no longer be requeued (or otherwise used). - */ -static inline void -usb_ep_free_request (struct usb_ep *ep, struct usb_request *req) -{ - ep->ops->free_request (ep, req); -} - -/** - * usb_ep_queue - queues (submits) an I/O request to an endpoint. - * @ep:the endpoint associated with the request - * @req:the request being submitted - * @gfp_flags: GFP_* flags to use in case the lower level driver couldn't - * pre-allocate all necessary memory with the request. - * - * This tells the device controller to perform the specified request through - * that endpoint (reading or writing a buffer). When the request completes, - * including being canceled by usb_ep_dequeue(), the request's completion - * routine is called to return the request to the driver. Any endpoint - * (except control endpoints like ep0) may have more than one transfer - * request queued; they complete in FIFO order. Once a gadget driver - * submits a request, that request may not be examined or modified until it - * is given back to that driver through the completion callback. - * - * Each request is turned into one or more packets. The controller driver - * never merges adjacent requests into the same packet. OUT transfers - * will sometimes use data that's already buffered in the hardware. - * Drivers can rely on the fact that the first byte of the request's buffer - * always corresponds to the first byte of some USB packet, for both - * IN and OUT transfers. - * - * Bulk endpoints can queue any amount of data; the transfer is packetized - * automatically. The last packet will be short if the request doesn't fill it - * out completely. Zero length packets (ZLPs) should be avoided in portable - * protocols since not all usb hardware can successfully handle zero length - * packets. (ZLPs may be explicitly written, and may be implicitly written if - * the request 'zero' flag is set.) Bulk endpoints may also be used - * for interrupt transfers; but the reverse is not true, and some endpoints - * won't support every interrupt transfer. (Such as 768 byte packets.) - * - * Interrupt-only endpoints are less functional than bulk endpoints, for - * example by not supporting queueing or not handling buffers that are - * larger than the endpoint's maxpacket size. They may also treat data - * toggle differently. - * - * Control endpoints ... after getting a setup() callback, the driver queues - * one response (even if it would be zero length). That enables the - * status ack, after transfering data as specified in the response. Setup - * functions may return negative error codes to generate protocol stalls. - * (Note that some USB device controllers disallow protocol stall responses - * in some cases.) When control responses are deferred (the response is - * written after the setup callback returns), then usb_ep_set_halt() may be - * used on ep0 to trigger protocol stalls. - * - * For periodic endpoints, like interrupt or isochronous ones, the usb host - * arranges to poll once per interval, and the gadget driver usually will - * have queued some data to transfer at that time. - * - * Returns zero, or a negative error code. Endpoints that are not enabled - * report errors; errors will also be - * reported when the usb peripheral is disconnected. - */ -static inline int -usb_ep_queue (struct usb_ep *ep, struct usb_request *req, gfp_t gfp_flags) -{ - return ep->ops->queue (ep, req, gfp_flags); -} - -/** - * usb_ep_dequeue - dequeues (cancels, unlinks) an I/O request from an endpoint - * @ep:the endpoint associated with the request - * @req:the request being canceled - * - * if the request is still active on the endpoint, it is dequeued and its - * completion routine is called (with status -ECONNRESET); else a negative - * error code is returned. - * - * note that some hardware can't clear out write fifos (to unlink the request - * at the head of the queue) except as part of disconnecting from usb. such - * restrictions prevent drivers from supporting configuration changes, - * even to configuration zero (a "chapter 9" requirement). - */ -static inline int usb_ep_dequeue (struct usb_ep *ep, struct usb_request *req) -{ - return ep->ops->dequeue (ep, req); -} - -/** - * usb_ep_set_halt - sets the endpoint halt feature. - * @ep: the non-isochronous endpoint being stalled - * - * Use this to stall an endpoint, perhaps as an error report. - * Except for control endpoints, - * the endpoint stays halted (will not stream any data) until the host - * clears this feature; drivers may need to empty the endpoint's request - * queue first, to make sure no inappropriate transfers happen. - * - * Note that while an endpoint CLEAR_FEATURE will be invisible to the - * gadget driver, a SET_INTERFACE will not be. To reset endpoints for the - * current altsetting, see usb_ep_clear_halt(). When switching altsettings, - * it's simplest to use usb_ep_enable() or usb_ep_disable() for the endpoints. - * - * Returns zero, or a negative error code. On success, this call sets - * underlying hardware state that blocks data transfers. - * Attempts to halt IN endpoints will fail (returning -EAGAIN) if any - * transfer requests are still queued, or if the controller hardware - * (usually a FIFO) still holds bytes that the host hasn't collected. - */ -static inline int -usb_ep_set_halt (struct usb_ep *ep) -{ - return ep->ops->set_halt (ep, 1); -} - -/** - * usb_ep_clear_halt - clears endpoint halt, and resets toggle - * @ep:the bulk or interrupt endpoint being reset - * - * Use this when responding to the standard usb "set interface" request, - * for endpoints that aren't reconfigured, after clearing any other state - * in the endpoint's i/o queue. - * - * Returns zero, or a negative error code. On success, this call clears - * the underlying hardware state reflecting endpoint halt and data toggle. - * Note that some hardware can't support this request (like pxa2xx_udc), - * and accordingly can't correctly implement interface altsettings. - */ -static inline int -usb_ep_clear_halt (struct usb_ep *ep) -{ - return ep->ops->set_halt (ep, 0); -} - -/** - * usb_ep_fifo_status - returns number of bytes in fifo, or error - * @ep: the endpoint whose fifo status is being checked. - * - * FIFO endpoints may have "unclaimed data" in them in certain cases, - * such as after aborted transfers. Hosts may not have collected all - * the IN data written by the gadget driver (and reported by a request - * completion). The gadget driver may not have collected all the data - * written OUT to it by the host. Drivers that need precise handling for - * fault reporting or recovery may need to use this call. - * - * This returns the number of such bytes in the fifo, or a negative - * errno if the endpoint doesn't use a FIFO or doesn't support such - * precise handling. - */ -static inline int -usb_ep_fifo_status (struct usb_ep *ep) -{ - if (ep->ops->fifo_status) - return ep->ops->fifo_status (ep); - else - return -EOPNOTSUPP; -} - -/** - * usb_ep_fifo_flush - flushes contents of a fifo - * @ep: the endpoint whose fifo is being flushed. - * - * This call may be used to flush the "unclaimed data" that may exist in - * an endpoint fifo after abnormal transaction terminations. The call - * must never be used except when endpoint is not being used for any - * protocol translation. - */ -static inline void -usb_ep_fifo_flush (struct usb_ep *ep) -{ - if (ep->ops->fifo_flush) - ep->ops->fifo_flush (ep); -} - - -/*-------------------------------------------------------------------------*/ - -struct usb_gadget; - -/* the rest of the api to the controller hardware: device operations, - * which don't involve endpoints (or i/o). - */ -struct usb_gadget_ops { - int (*get_frame)(struct usb_gadget *); - int (*wakeup)(struct usb_gadget *); - int (*set_selfpowered) (struct usb_gadget *, int is_selfpowered); - int (*vbus_session) (struct usb_gadget *, int is_active); - int (*vbus_draw) (struct usb_gadget *, unsigned mA); - int (*pullup) (struct usb_gadget *, int is_on); - int (*ioctl)(struct usb_gadget *, - unsigned code, unsigned long param); -}; - -/** - * struct usb_gadget - represents a usb slave device - * @ops: Function pointers used to access hardware-specific operations. - * @ep0: Endpoint zero, used when reading or writing responses to - * driver setup() requests - * @ep_list: List of other endpoints supported by the device. - * @speed: Speed of current connection to USB host. - * @is_dualspeed: True if the controller supports both high and full speed - * operation. If it does, the gadget driver must also support both. - * @is_otg: True if the USB device port uses a Mini-AB jack, so that the - * gadget driver must provide a USB OTG descriptor. - * @is_a_peripheral: False unless is_otg, the "A" end of a USB cable - * is in the Mini-AB jack, and HNP has been used to switch roles - * so that the "A" device currently acts as A-Peripheral, not A-Host. - * @a_hnp_support: OTG device feature flag, indicating that the A-Host - * supports HNP at this port. - * @a_alt_hnp_support: OTG device feature flag, indicating that the A-Host - * only supports HNP on a different root port. - * @b_hnp_enable: OTG device feature flag, indicating that the A-Host - * enabled HNP support. - * @name: Identifies the controller hardware type. Used in diagnostics - * and sometimes configuration. - * @dev: Driver model state for this abstract device. - * - * Gadgets have a mostly-portable "gadget driver" implementing device - * functions, handling all usb configurations and interfaces. Gadget - * drivers talk to hardware-specific code indirectly, through ops vectors. - * That insulates the gadget driver from hardware details, and packages - * the hardware endpoints through generic i/o queues. The "usb_gadget" - * and "usb_ep" interfaces provide that insulation from the hardware. - * - * Except for the driver data, all fields in this structure are - * read-only to the gadget driver. That driver data is part of the - * "driver model" infrastructure in 2.6 (and later) kernels, and for - * earlier systems is grouped in a similar structure that's not known - * to the rest of the kernel. - * - * Values of the three OTG device feature flags are updated before the - * setup() call corresponding to USB_REQ_SET_CONFIGURATION, and before - * driver suspend() calls. They are valid only when is_otg, and when the - * device is acting as a B-Peripheral (so is_a_peripheral is false). - */ -struct usb_gadget { - /* readonly to gadget driver */ - const struct usb_gadget_ops *ops; - struct usb_ep *ep0; - struct list_head ep_list; /* of usb_ep */ - enum usb_device_speed speed; - unsigned is_dualspeed:1; - unsigned is_otg:1; - unsigned is_a_peripheral:1; - unsigned b_hnp_enable:1; - unsigned a_hnp_support:1; - unsigned a_alt_hnp_support:1; - const char *name; - struct device dev; -}; - -static inline void set_gadget_data (struct usb_gadget *gadget, void *data) - { dev_set_drvdata (&gadget->dev, data); } -static inline void *get_gadget_data (struct usb_gadget *gadget) - { return dev_get_drvdata (&gadget->dev); } - -/* iterates the non-control endpoints; 'tmp' is a struct usb_ep pointer */ -#define gadget_for_each_ep(tmp,gadget) \ - list_for_each_entry(tmp, &(gadget)->ep_list, ep_list) - - -/** - * gadget_is_dualspeed - return true iff the hardware handles high speed - * @gadget: controller that might support both high and full speeds - */ -static inline int gadget_is_dualspeed(struct usb_gadget *g) -{ -#ifdef CONFIG_USB_GADGET_DUALSPEED - /* runtime test would check "g->is_dualspeed" ... that might be - * useful to work around hardware bugs, but is mostly pointless - */ - return 1; -#else - return 0; -#endif -} - -/** - * gadget_is_otg - return true iff the hardware is OTG-ready - * @gadget: controller that might have a Mini-AB connector - * - * This is a runtime test, since kernels with a USB-OTG stack sometimes - * run on boards which only have a Mini-B (or Mini-A) connector. - */ -static inline int gadget_is_otg(struct usb_gadget *g) -{ -#ifdef CONFIG_USB_OTG - return g->is_otg; -#else - return 0; -#endif -} - - -/** - * usb_gadget_frame_number - returns the current frame number - * @gadget: controller that reports the frame number - * - * Returns the usb frame number, normally eleven bits from a SOF packet, - * or negative errno if this device doesn't support this capability. - */ -static inline int usb_gadget_frame_number (struct usb_gadget *gadget) -{ - return gadget->ops->get_frame (gadget); -} - -/** - * usb_gadget_wakeup - tries to wake up the host connected to this gadget - * @gadget: controller used to wake up the host - * - * Returns zero on success, else negative error code if the hardware - * doesn't support such attempts, or its support has not been enabled - * by the usb host. Drivers must return device descriptors that report - * their ability to support this, or hosts won't enable it. - * - * This may also try to use SRP to wake the host and start enumeration, - * even if OTG isn't otherwise in use. OTG devices may also start - * remote wakeup even when hosts don't explicitly enable it. - */ -static inline int usb_gadget_wakeup (struct usb_gadget *gadget) -{ - if (!gadget->ops->wakeup) - return -EOPNOTSUPP; - return gadget->ops->wakeup (gadget); -} - -/** - * usb_gadget_set_selfpowered - sets the device selfpowered feature. - * @gadget:the device being declared as self-powered - * - * this affects the device status reported by the hardware driver - * to reflect that it now has a local power supply. - * - * returns zero on success, else negative errno. - */ -static inline int -usb_gadget_set_selfpowered (struct usb_gadget *gadget) -{ - if (!gadget->ops->set_selfpowered) - return -EOPNOTSUPP; - return gadget->ops->set_selfpowered (gadget, 1); -} - -/** - * usb_gadget_clear_selfpowered - clear the device selfpowered feature. - * @gadget:the device being declared as bus-powered - * - * this affects the device status reported by the hardware driver. - * some hardware may not support bus-powered operation, in which - * case this feature's value can never change. - * - * returns zero on success, else negative errno. - */ -static inline int -usb_gadget_clear_selfpowered (struct usb_gadget *gadget) -{ - if (!gadget->ops->set_selfpowered) - return -EOPNOTSUPP; - return gadget->ops->set_selfpowered (gadget, 0); -} - -/** - * usb_gadget_vbus_connect - Notify controller that VBUS is powered - * @gadget:The device which now has VBUS power. - * - * This call is used by a driver for an external transceiver (or GPIO) - * that detects a VBUS power session starting. Common responses include - * resuming the controller, activating the D+ (or D-) pullup to let the - * host detect that a USB device is attached, and starting to draw power - * (8mA or possibly more, especially after SET_CONFIGURATION). - * - * Returns zero on success, else negative errno. - */ -static inline int -usb_gadget_vbus_connect(struct usb_gadget *gadget) -{ - if (!gadget->ops->vbus_session) - return -EOPNOTSUPP; - return gadget->ops->vbus_session (gadget, 1); -} - -/** - * usb_gadget_vbus_draw - constrain controller's VBUS power usage - * @gadget:The device whose VBUS usage is being described - * @mA:How much current to draw, in milliAmperes. This should be twice - * the value listed in the configuration descriptor bMaxPower field. - * - * This call is used by gadget drivers during SET_CONFIGURATION calls, - * reporting how much power the device may consume. For example, this - * could affect how quickly batteries are recharged. - * - * Returns zero on success, else negative errno. - */ -static inline int -usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA) -{ - if (!gadget->ops->vbus_draw) - return -EOPNOTSUPP; - return gadget->ops->vbus_draw (gadget, mA); -} - -/** - * usb_gadget_vbus_disconnect - notify controller about VBUS session end - * @gadget:the device whose VBUS supply is being described - * - * This call is used by a driver for an external transceiver (or GPIO) - * that detects a VBUS power session ending. Common responses include - * reversing everything done in usb_gadget_vbus_connect(). - * - * Returns zero on success, else negative errno. - */ -static inline int -usb_gadget_vbus_disconnect(struct usb_gadget *gadget) -{ - if (!gadget->ops->vbus_session) - return -EOPNOTSUPP; - return gadget->ops->vbus_session (gadget, 0); -} - -/** - * usb_gadget_connect - software-controlled connect to USB host - * @gadget:the peripheral being connected - * - * Enables the D+ (or potentially D-) pullup. The host will start - * enumerating this gadget when the pullup is active and a VBUS session - * is active (the link is powered). This pullup is always enabled unless - * usb_gadget_disconnect() has been used to disable it. - * - * Returns zero on success, else negative errno. - */ -static inline int -usb_gadget_connect (struct usb_gadget *gadget) -{ - if (!gadget->ops->pullup) - return -EOPNOTSUPP; - return gadget->ops->pullup (gadget, 1); -} - -/** - * usb_gadget_disconnect - software-controlled disconnect from USB host - * @gadget:the peripheral being disconnected - * - * Disables the D+ (or potentially D-) pullup, which the host may see - * as a disconnect (when a VBUS session is active). Not all systems - * support software pullup controls. - * - * This routine may be used during the gadget driver bind() call to prevent - * the peripheral from ever being visible to the USB host, unless later - * usb_gadget_connect() is called. For example, user mode components may - * need to be activated before the system can talk to hosts. - * - * Returns zero on success, else negative errno. - */ -static inline int -usb_gadget_disconnect (struct usb_gadget *gadget) -{ - if (!gadget->ops->pullup) - return -EOPNOTSUPP; - return gadget->ops->pullup (gadget, 0); -} - - - -/*-------------------------------------------------------------------------*/ - -/** - * struct usb_gadget_driver - driver for usb 'slave' devices - * @function: String describing the gadget's function - * @speed: Highest speed the driver handles. - * @bind: Invoked when the driver is bound to a gadget, usually - * after registering the driver. - * At that point, ep0 is fully initialized, and ep_list holds - * the currently-available endpoints. - * Called in a context that permits sleeping. - * @setup: Invoked for ep0 control requests that aren't handled by - * the hardware level driver. Most calls must be handled by - * the gadget driver, including descriptor and configuration - * management. The 16 bit members of the setup data are in - * USB byte order. Called in_interrupt; this may not sleep. Driver - * queues a response to ep0, or returns negative to stall. - * @disconnect: Invoked after all transfers have been stopped, - * when the host is disconnected. May be called in_interrupt; this - * may not sleep. Some devices can't detect disconnect, so this might - * not be called except as part of controller shutdown. - * @unbind: Invoked when the driver is unbound from a gadget, - * usually from rmmod (after a disconnect is reported). - * Called in a context that permits sleeping. - * @suspend: Invoked on USB suspend. May be called in_interrupt. - * @resume: Invoked on USB resume. May be called in_interrupt. - * @driver: Driver model state for this driver. - * - * Devices are disabled till a gadget driver successfully bind()s, which - * means the driver will handle setup() requests needed to enumerate (and - * meet "chapter 9" requirements) then do some useful work. - * - * If gadget->is_otg is true, the gadget driver must provide an OTG - * descriptor during enumeration, or else fail the bind() call. In such - * cases, no USB traffic may flow until both bind() returns without - * having called usb_gadget_disconnect(), and the USB host stack has - * initialized. - * - * Drivers use hardware-specific knowledge to configure the usb hardware. - * endpoint addressing is only one of several hardware characteristics that - * are in descriptors the ep0 implementation returns from setup() calls. - * - * Except for ep0 implementation, most driver code shouldn't need change to - * run on top of different usb controllers. It'll use endpoints set up by - * that ep0 implementation. - * - * The usb controller driver handles a few standard usb requests. Those - * include set_address, and feature flags for devices, interfaces, and - * endpoints (the get_status, set_feature, and clear_feature requests). - * - * Accordingly, the driver's setup() callback must always implement all - * get_descriptor requests, returning at least a device descriptor and - * a configuration descriptor. Drivers must make sure the endpoint - * descriptors match any hardware constraints. Some hardware also constrains - * other descriptors. (The pxa250 allows only configurations 1, 2, or 3). - * - * The driver's setup() callback must also implement set_configuration, - * and should also implement set_interface, get_configuration, and - * get_interface. Setting a configuration (or interface) is where - * endpoints should be activated or (config 0) shut down. - * - * (Note that only the default control endpoint is supported. Neither - * hosts nor devices generally support control traffic except to ep0.) - * - * Most devices will ignore USB suspend/resume operations, and so will - * not provide those callbacks. However, some may need to change modes - * when the host is not longer directing those activities. For example, - * local controls (buttons, dials, etc) may need to be re-enabled since - * the (remote) host can't do that any longer; or an error state might - * be cleared, to make the device behave identically whether or not - * power is maintained. - */ -struct usb_gadget_driver { - char *function; - enum usb_device_speed speed; - int (*bind)(struct usb_gadget *); - void (*unbind)(struct usb_gadget *); - int (*setup)(struct usb_gadget *, - const struct usb_ctrlrequest *); - void (*disconnect)(struct usb_gadget *); - void (*suspend)(struct usb_gadget *); - void (*resume)(struct usb_gadget *); - - // FIXME support safe rmmod - struct device_driver driver; -}; - - - -/*-------------------------------------------------------------------------*/ - -/* driver modules register and unregister, as usual. - * these calls must be made in a context that can sleep. - * - * these will usually be implemented directly by the hardware-dependent - * usb bus interface driver, which will only support a single driver. - */ - -/** - * usb_gadget_register_driver - register a gadget driver - * @driver:the driver being registered - * - * Call this in your gadget driver's module initialization function, - * to tell the underlying usb controller driver about your driver. - * The driver's bind() function will be called to bind it to a - * gadget before this registration call returns. It's expected that - * the bind() functions will be in init sections. - * This function must be called in a context that can sleep. - */ -int usb_gadget_register_driver (struct usb_gadget_driver *driver); - -/** - * usb_gadget_unregister_driver - unregister a gadget driver - * @driver:the driver being unregistered - * - * Call this in your gadget driver's module cleanup function, - * to tell the underlying usb controller that your driver is - * going away. If the controller is connected to a USB host, - * it will first disconnect(). The driver is also requested - * to unbind() and clean up any device state, before this procedure - * finally returns. It's expected that the unbind() functions - * will in in exit sections, so may not be linked in some kernels. - * This function must be called in a context that can sleep. - */ -int usb_gadget_unregister_driver (struct usb_gadget_driver *driver); - -/*-------------------------------------------------------------------------*/ - -/* utility to simplify dealing with string descriptors */ - -/** - * struct usb_string - wraps a C string and its USB id - * @id:the (nonzero) ID for this string - * @s:the string, in UTF-8 encoding - * - * If you're using usb_gadget_get_string(), use this to wrap a string - * together with its ID. - */ -struct usb_string { - u8 id; - const char *s; -}; - -/** - * struct usb_gadget_strings - a set of USB strings in a given language - * @language:identifies the strings' language (0x0409 for en-us) - * @strings:array of strings with their ids - * - * If you're using usb_gadget_get_string(), use this to wrap all the - * strings for a given language. - */ -struct usb_gadget_strings { - u16 language; /* 0x0409 for en-us */ - struct usb_string *strings; -}; - -/* put descriptor for string with that id into buf (buflen >= 256) */ -int usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf); - -/*-------------------------------------------------------------------------*/ - -/* utility to simplify managing config descriptors */ - -/* write vector of descriptors into buffer */ -int usb_descriptor_fillbuf(void *, unsigned, - const struct usb_descriptor_header **); - -/* build config descriptor from single descriptor vector */ -int usb_gadget_config_buf(const struct usb_config_descriptor *config, - void *buf, unsigned buflen, const struct usb_descriptor_header **desc); - -/*-------------------------------------------------------------------------*/ - -/* utility wrapping a simple endpoint selection policy */ - -extern struct usb_ep *usb_ep_autoconfig (struct usb_gadget *, - struct usb_endpoint_descriptor *) __devinit; - -extern void usb_ep_autoconfig_reset (struct usb_gadget *) __devinit; - -#endif /* __KERNEL__ */ - -#endif /* __LINUX_USB_GADGET_H */ -- cgit v1.2.3-70-g09d2 From 3046c6db575019ba4ce6b9deac352d438ddf733d Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 5 Oct 2007 14:43:00 -0400 Subject: USB: unusual_devs entry for Nikon DSC D2Xs This patch (as996) adds an unusual_devs entry for the Nikon DSC D2Xs camera. Signed-off-by: Alan Stern Cc: Phil Dibowitz Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 5129b538be9..edf92914674 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -362,6 +362,13 @@ UNUSUAL_DEV( 0x04b0, 0x0413, 0x0110, 0x0110, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_CAPACITY), +/* Reported by Paul Check */ +UNUSUAL_DEV( 0x04b0, 0x0415, 0x0100, 0x0100, + "NIKON", + "NIKON DSC D2Xs", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY), + /* BENQ DC5330 * Reported by Manuel Fombuena and * Frank Copeland */ -- cgit v1.2.3-70-g09d2 From d9c563626d9a136636385209d59d0c4f16c4a7ab Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 26 Sep 2007 23:34:18 +0100 Subject: USB: visor: termios bits Visor has a huge complex routine which displays termios bits for debug but doesn't do anything. Get the correct behaviour by removing it all Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/visor.c | 64 ---------------------------------------------- 1 file changed, 64 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index 30e08c0bcdc..7ee087fed91 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -46,7 +46,6 @@ static int visor_probe (struct usb_serial *serial, const struct usb_device_id static int visor_calc_num_ports(struct usb_serial *serial); static void visor_shutdown (struct usb_serial *serial); static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg); -static void visor_set_termios (struct usb_serial_port *port, struct ktermios *old_termios); static void visor_write_bulk_callback (struct urb *urb); static void visor_read_bulk_callback (struct urb *urb); static void visor_read_int_callback (struct urb *urb); @@ -203,7 +202,6 @@ static struct usb_serial_driver handspring_device = { .calc_num_ports = visor_calc_num_ports, .shutdown = visor_shutdown, .ioctl = visor_ioctl, - .set_termios = visor_set_termios, .write = visor_write, .write_room = visor_write_room, .chars_in_buffer = visor_chars_in_buffer, @@ -234,7 +232,6 @@ static struct usb_serial_driver clie_5_device = { .calc_num_ports = visor_calc_num_ports, .shutdown = visor_shutdown, .ioctl = visor_ioctl, - .set_termios = visor_set_termios, .write = visor_write, .write_room = visor_write_room, .chars_in_buffer = visor_chars_in_buffer, @@ -262,7 +259,6 @@ static struct usb_serial_driver clie_3_5_device = { .unthrottle = visor_unthrottle, .attach = clie_3_5_startup, .ioctl = visor_ioctl, - .set_termios = visor_set_termios, .write = visor_write, .write_room = visor_write_room, .chars_in_buffer = visor_chars_in_buffer, @@ -936,66 +932,6 @@ static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsign return -ENOIOCTLCMD; } - -/* This function is all nice and good, but we don't change anything based on it :) */ -static void visor_set_termios (struct usb_serial_port *port, struct ktermios *old_termios) -{ - unsigned int cflag; - - dbg("%s - port %d", __FUNCTION__, port->number); - - if ((!port->tty) || (!port->tty->termios)) { - dbg("%s - no tty structures", __FUNCTION__); - return; - } - - cflag = port->tty->termios->c_cflag; - - /* get the byte size */ - switch (cflag & CSIZE) { - case CS5: dbg("%s - data bits = 5", __FUNCTION__); break; - case CS6: dbg("%s - data bits = 6", __FUNCTION__); break; - case CS7: dbg("%s - data bits = 7", __FUNCTION__); break; - default: - case CS8: dbg("%s - data bits = 8", __FUNCTION__); break; - } - - /* determine the parity */ - if (cflag & PARENB) - if (cflag & PARODD) - dbg("%s - parity = odd", __FUNCTION__); - else - dbg("%s - parity = even", __FUNCTION__); - else - dbg("%s - parity = none", __FUNCTION__); - - /* figure out the stop bits requested */ - if (cflag & CSTOPB) - dbg("%s - stop bits = 2", __FUNCTION__); - else - dbg("%s - stop bits = 1", __FUNCTION__); - - - /* figure out the flow control settings */ - if (cflag & CRTSCTS) - dbg("%s - RTS/CTS is enabled", __FUNCTION__); - else - dbg("%s - RTS/CTS is disabled", __FUNCTION__); - - /* determine software flow control */ - if (I_IXOFF(port->tty)) - dbg("%s - XON/XOFF is enabled, XON = %2x, XOFF = %2x", - __FUNCTION__, START_CHAR(port->tty), STOP_CHAR(port->tty)); - else - dbg("%s - XON/XOFF is disabled", __FUNCTION__); - - /* get the baud rate wanted */ - dbg("%s - baud rate = %d", __FUNCTION__, tty_get_baud_rate(port->tty)); - - return; -} - - static int __init visor_init (void) { int i, retval; -- cgit v1.2.3-70-g09d2 From f621b8437d6ae502dde45797f56407e48c7a68b4 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 26 Sep 2007 23:22:36 +0100 Subject: USB: funsoft: Fix termios Funsoft has a bogus ioctl handler doing bogus termios handling in a bogus manner. Fortunately we can simply delete all the bogus bits and get the right default behaviour ! Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/funsoft.c | 21 --------------------- 1 file changed, 21 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/serial/funsoft.c b/drivers/usb/serial/funsoft.c index 4092f6dc9ef..b5194dc7d3b 100644 --- a/drivers/usb/serial/funsoft.c +++ b/drivers/usb/serial/funsoft.c @@ -24,26 +24,6 @@ static struct usb_device_id id_table [] = { }; MODULE_DEVICE_TABLE(usb, id_table); -static int funsoft_ioctl(struct usb_serial_port *port, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct ktermios t; - - dbg("%s - port %d, cmd 0x%04x", __FUNCTION__, port->number, cmd); - - if (cmd == TCSETSF) { - if (user_termios_to_kernel_termios(&t, (struct termios __user *)arg)) - return -EFAULT; - - dbg("%s - iflag:%x oflag:%x cflag:%x lflag:%x", __FUNCTION__, - t.c_iflag, t.c_oflag, t.c_cflag, t.c_lflag); - - if (!(t.c_lflag & ICANON)) - return -EINVAL; - } - return -ENOIOCTLCMD; -} - static struct usb_driver funsoft_driver = { .name = "funsoft", .probe = usb_serial_probe, @@ -63,7 +43,6 @@ static struct usb_serial_driver funsoft_device = { .num_bulk_in = NUM_DONT_CARE, .num_bulk_out = NUM_DONT_CARE, .num_ports = 1, - .ioctl = funsoft_ioctl, }; static int __init funsoft_init(void) -- cgit v1.2.3-70-g09d2 From 4f45426cfd6170311e116442ccd8ce0e31979237 Mon Sep 17 00:00:00 2001 From: Valentine Barshak Date: Tue, 9 Oct 2007 15:00:05 -0700 Subject: USB: add runtime frame_no quirk for big-endian OHCI Add OHCI big endian frame_no quirk. The frame_no value stored in the HCCA is a 16 bit field at a specific offset, but since not all CPUs can do 16-bit memory accesses it's used as a 32 bit field. And that's why big-endian OHCI must shift 16 bits ... unless the spec is not followed. Currently there's one MPC52xx platform that doesn't need the shift. This patch adds a new "big endian frame_no" quirk to control that at runtime. Signed-off-by: Valentine Barshak Acked-by: Dale Farnsworth Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-ppc-of.c | 5 ++++- drivers/usb/host/ohci-ppc-soc.c | 5 +++++ drivers/usb/host/ohci.h | 13 ++++++------- 3 files changed, 15 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c index c43b66acd4d..0a742692015 100644 --- a/drivers/usb/host/ohci-ppc-of.c +++ b/drivers/usb/host/ohci-ppc-of.c @@ -134,8 +134,11 @@ ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match) } ohci = hcd_to_ohci(hcd); - if (is_bigendian) + if (is_bigendian) { ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC; + if (of_device_is_compatible(dn, "mpc5200-ohci")) + ohci->flags |= OHCI_QUIRK_FRAME_NO; + } ohci_hcd_init(ohci); diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c index 1a2e1777ca6..f95be1896b0 100644 --- a/drivers/usb/host/ohci-ppc-soc.c +++ b/drivers/usb/host/ohci-ppc-soc.c @@ -73,6 +73,11 @@ static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver, ohci = hcd_to_ohci(hcd); ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC; + +#ifdef CONFIG_PPC_MPC52xx + /* MPC52xx doesn't need frame_no shift */ + ohci->flags |= OHCI_QUIRK_FRAME_NO; +#endif ohci_hcd_init(ohci); retval = usb_add_hcd(hcd, irq, IRQF_DISABLED); diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index dd4d5b4dcb6..47c5c66a282 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -398,6 +398,7 @@ struct ohci_hcd { #define OHCI_QUIRK_BE_MMIO 0x10 /* BE registers */ #define OHCI_QUIRK_ZFMICRO 0x20 /* Compaq ZFMicro chipset*/ #define OHCI_QUIRK_NEC 0x40 /* lost interrupts */ +#define OHCI_QUIRK_FRAME_NO 0x80 /* no big endian frame_no shift */ // there are also chip quirks/bugs in init logic struct work_struct nec_work; /* Worker for NEC quirk */ @@ -633,15 +634,12 @@ static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x) /* HCCA frame number is 16 bits, but is accessed as 32 bits since not all * hardware handles 16 bit reads. That creates a different confusion on * some big-endian SOC implementations. Same thing happens with PSW access. - * - * FIXME: Deal with that as a runtime quirk when STB03xxx is ported over - * to arch/powerpc */ -#ifdef CONFIG_STB03xxx -#define OHCI_BE_FRAME_NO_SHIFT 16 +#ifdef CONFIG_PPC_MPC52xx +#define big_endian_frame_no_quirk(ohci) (ohci->flags & OHCI_QUIRK_FRAME_NO) #else -#define OHCI_BE_FRAME_NO_SHIFT 0 +#define big_endian_frame_no_quirk(ohci) 0 #endif static inline u16 ohci_frame_no(const struct ohci_hcd *ohci) @@ -649,7 +647,8 @@ static inline u16 ohci_frame_no(const struct ohci_hcd *ohci) u32 tmp; if (big_endian_desc(ohci)) { tmp = be32_to_cpup((__force __be32 *)&ohci->hcca->frame_no); - tmp >>= OHCI_BE_FRAME_NO_SHIFT; + if (!big_endian_frame_no_quirk(ohci)) + tmp >>= 16; } else tmp = le32_to_cpup((__force __le32 *)&ohci->hcca->frame_no); -- cgit v1.2.3-70-g09d2 From b24896c6b7ddb37ab20ba0bbfd0ed36a38923f67 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 9 Oct 2007 22:04:16 -0700 Subject: USB: ehci build fixes on au1xxx, ppc-soc Cleanup: references to two PM routines (and HCD entry points) that no longer exist are swapped with their replacements. Evidently au1xxx and ppc-soc EHCI support doesn't get compiled with power management very much, or these build bugs would have been patched long ago. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-au1xxx.c | 6 ++---- drivers/usb/host/ehci-ppc-soc.c | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c index b1d19268cb2..766ef68a0b4 100644 --- a/drivers/usb/host/ehci-au1xxx.c +++ b/drivers/usb/host/ehci-au1xxx.c @@ -220,10 +220,8 @@ static const struct hc_driver ehci_au1xxx_hc_driver = { */ .hub_status_data = ehci_hub_status_data, .hub_control = ehci_hub_control, -#ifdef CONFIG_PM - .hub_suspend = ehci_hub_suspend, - .hub_resume = ehci_hub_resume, -#endif + .bus_suspend = ehci_bus_suspend, + .bus_resume = ehci_bus_resume, }; /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ehci-ppc-soc.c b/drivers/usb/host/ehci-ppc-soc.c index 4f99b0eb27b..452d4b1bc85 100644 --- a/drivers/usb/host/ehci-ppc-soc.c +++ b/drivers/usb/host/ehci-ppc-soc.c @@ -160,10 +160,8 @@ static const struct hc_driver ehci_ppc_soc_hc_driver = { */ .hub_status_data = ehci_hub_status_data, .hub_control = ehci_hub_control, -#ifdef CONFIG_PM - .hub_suspend = ehci_hub_suspend, - .hub_resume = ehci_hub_resume, -#endif + .bus_suspend = ehci_bus_suspend, + .bus_resume = ehci_bus_resume, }; static int ehci_hcd_ppc_soc_drv_probe(struct platform_device *pdev) -- cgit v1.2.3-70-g09d2 From c604e851486eabcbeb73e984279d436ce121fd5d Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Tue, 9 Oct 2007 23:47:17 -0700 Subject: USB: ohci SSB bus glue This adds SSB bus glue for the USB OHCI HCD. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/Kconfig | 13 +++ drivers/usb/host/ohci-hcd.c | 21 +++- drivers/usb/host/ohci-ssb.c | 247 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 280 insertions(+), 1 deletion(-) create mode 100644 drivers/usb/host/ohci-ssb.c (limited to 'drivers') diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 565d6ef4c4c..c978d622fa8 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -154,6 +154,19 @@ config USB_OHCI_HCD_PCI Enables support for PCI-bus plug-in USB controller cards. If unsure, say Y. +config USB_OHCI_HCD_SSB + bool "OHCI support for Broadcom SSB OHCI core" + depends on USB_OHCI_HCD && SSB && EXPERIMENTAL + default n + ---help--- + Support for the Sonics Silicon Backplane (SSB) attached + Broadcom USB OHCI core. + + This device is present in some embedded devices with + Broadcom based SSB bus. + + If unsure, say N. + config USB_OHCI_BIG_ENDIAN_DESC bool depends on USB_OHCI_HCD diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index f7c6ced2bc0..240c7f50754 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -1033,11 +1033,17 @@ MODULE_LICENSE ("GPL"); #define PS3_SYSTEM_BUS_DRIVER ps3_ohci_driver #endif +#ifdef CONFIG_USB_OHCI_HCD_SSB +#include "ohci-ssb.c" +#define SSB_OHCI_DRIVER ssb_ohci_driver +#endif + #if !defined(PCI_DRIVER) && \ !defined(PLATFORM_DRIVER) && \ !defined(OF_PLATFORM_DRIVER) && \ !defined(SA1111_DRIVER) && \ - !defined(PS3_SYSTEM_BUS_DRIVER) + !defined(PS3_SYSTEM_BUS_DRIVER) && \ + !defined(SSB_OHCI_DRIVER) #error "missing bus glue for ohci-hcd" #endif @@ -1082,10 +1088,20 @@ static int __init ohci_hcd_mod_init(void) goto error_pci; #endif +#ifdef SSB_OHCI_DRIVER + retval = ssb_driver_register(&SSB_OHCI_DRIVER); + if (retval) + goto error_ssb; +#endif + return retval; /* Error path */ +#ifdef SSB_OHCI_DRIVER + error_ssb: +#endif #ifdef PCI_DRIVER + pci_unregister_driver(&PCI_DRIVER); error_pci: #endif #ifdef SA1111_DRIVER @@ -1110,6 +1126,9 @@ module_init(ohci_hcd_mod_init); static void __exit ohci_hcd_mod_exit(void) { +#ifdef SSB_OHCI_DRIVER + ssb_driver_unregister(&SSB_OHCI_DRIVER); +#endif #ifdef PCI_DRIVER pci_unregister_driver(&PCI_DRIVER); #endif diff --git a/drivers/usb/host/ohci-ssb.c b/drivers/usb/host/ohci-ssb.c new file mode 100644 index 00000000000..bc3e785d8c0 --- /dev/null +++ b/drivers/usb/host/ohci-ssb.c @@ -0,0 +1,247 @@ +/* + * Sonics Silicon Backplane + * Broadcom USB-core OHCI driver + * + * Copyright 2007 Michael Buesch + * + * Derived from the OHCI-PCI driver + * Copyright 1999 Roman Weissgaerber + * Copyright 2000-2002 David Brownell + * Copyright 1999 Linus Torvalds + * Copyright 1999 Gregory P. Smith + * + * Derived from the USBcore related parts of Broadcom-SB + * Copyright 2005 Broadcom Corporation + * + * Licensed under the GNU/GPL. See COPYING for details. + */ +#include + + +#define SSB_OHCI_TMSLOW_HOSTMODE (1 << 29) + +struct ssb_ohci_device { + struct ohci_hcd ohci; /* _must_ be at the beginning. */ + + u32 enable_flags; +}; + +static inline +struct ssb_ohci_device *hcd_to_ssb_ohci(struct usb_hcd *hcd) +{ + return (struct ssb_ohci_device *)(hcd->hcd_priv); +} + + +static int ssb_ohci_reset(struct usb_hcd *hcd) +{ + struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd); + struct ohci_hcd *ohci = &ohcidev->ohci; + int err; + + ohci_hcd_init(ohci); + err = ohci_init(ohci); + + return err; +} + +static int ssb_ohci_start(struct usb_hcd *hcd) +{ + struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd); + struct ohci_hcd *ohci = &ohcidev->ohci; + int err; + + err = ohci_run(ohci); + if (err < 0) { + ohci_err(ohci, "can't start\n"); + ohci_stop(hcd); + } + + return err; +} + +#ifdef CONFIG_PM +static int ssb_ohci_hcd_suspend(struct usb_hcd *hcd, pm_message_t message) +{ + struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd); + struct ohci_hcd *ohci = &ohcidev->ohci; + unsigned long flags; + + spin_lock_irqsave(&ohci->lock, flags); + + ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); + ohci_readl(ohci, &ohci->regs->intrdisable); /* commit write */ + + /* make sure snapshot being resumed re-enumerates everything */ + if (message.event == PM_EVENT_PRETHAW) + ohci_usb_reset(ohci); + + clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + + spin_unlock_irqrestore(&ohci->lock, flags); + return 0; +} + +static int ssb_ohci_hcd_resume(struct usb_hcd *hcd) +{ + set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + usb_hcd_resume_root_hub(hcd); + return 0; +} +#endif /* CONFIG_PM */ + +static const struct hc_driver ssb_ohci_hc_driver = { + .description = "ssb-usb-ohci", + .product_desc = "SSB OHCI Controller", + .hcd_priv_size = sizeof(struct ssb_ohci_device), + + .irq = ohci_irq, + .flags = HCD_MEMORY | HCD_USB11, + + .reset = ssb_ohci_reset, + .start = ssb_ohci_start, + .stop = ohci_stop, + .shutdown = ohci_shutdown, + +#ifdef CONFIG_PM + .suspend = ssb_ohci_hcd_suspend, + .resume = ssb_ohci_hcd_resume, +#endif + + .urb_enqueue = ohci_urb_enqueue, + .urb_dequeue = ohci_urb_dequeue, + .endpoint_disable = ohci_endpoint_disable, + + .get_frame_number = ohci_get_frame, + + .hub_status_data = ohci_hub_status_data, + .hub_control = ohci_hub_control, + .hub_irq_enable = ohci_rhsc_enable, + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, + + .start_port_reset = ohci_start_port_reset, +}; + +static void ssb_ohci_detach(struct ssb_device *dev) +{ + struct usb_hcd *hcd = ssb_get_drvdata(dev); + + usb_remove_hcd(hcd); + iounmap(hcd->regs); + usb_put_hcd(hcd); + ssb_device_disable(dev, 0); +} + +static int ssb_ohci_attach(struct ssb_device *dev) +{ + struct ssb_ohci_device *ohcidev; + struct usb_hcd *hcd; + int err = -ENOMEM; + u32 tmp, flags = 0; + + if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV) + flags |= SSB_OHCI_TMSLOW_HOSTMODE; + + ssb_device_enable(dev, flags); + + hcd = usb_create_hcd(&ssb_ohci_hc_driver, dev->dev, + dev->dev->bus_id); + if (!hcd) + goto err_dev_disable; + ohcidev = hcd_to_ssb_ohci(hcd); + ohcidev->enable_flags = flags; + + tmp = ssb_read32(dev, SSB_ADMATCH0); + hcd->rsrc_start = ssb_admatch_base(tmp); + hcd->rsrc_len = ssb_admatch_size(tmp); + hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); + if (!hcd->regs) + goto err_put_hcd; + err = usb_add_hcd(hcd, dev->irq, IRQF_SHARED); + if (err) + goto err_iounmap; + + ssb_set_drvdata(dev, hcd); + + return err; + +err_iounmap: + iounmap(hcd->regs); +err_put_hcd: + usb_put_hcd(hcd); +err_dev_disable: + ssb_device_disable(dev, flags); + return err; +} + +static int ssb_ohci_probe(struct ssb_device *dev, + const struct ssb_device_id *id) +{ + int err; + u16 chipid_top; + + /* USBcores are only connected on embedded devices. */ + chipid_top = (dev->bus->chip_id & 0xFF00); + if (chipid_top != 0x4700 && chipid_top != 0x5300) + return -ENODEV; + + /* TODO: Probably need checks here; is the core connected? */ + + if (usb_disabled()) + return -ENODEV; + + /* We currently always attach SSB_DEV_USB11_HOSTDEV + * as HOST OHCI. If we want to attach it as Client device, + * we must branch here and call into the (yet to + * be written) Client mode driver. Same for remove(). */ + + err = ssb_ohci_attach(dev); + + return err; +} + +static void ssb_ohci_remove(struct ssb_device *dev) +{ + ssb_ohci_detach(dev); +} + +#ifdef CONFIG_PM + +static int ssb_ohci_suspend(struct ssb_device *dev, pm_message_t state) +{ + ssb_device_disable(dev, 0); + + return 0; +} + +static int ssb_ohci_resume(struct ssb_device *dev) +{ + struct usb_hcd *hcd = ssb_get_drvdata(dev); + struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd); + + ssb_device_enable(dev, ohcidev->enable_flags); + + return 0; +} + +#else /* !CONFIG_PM */ +#define ssb_ohci_suspend NULL +#define ssb_ohci_resume NULL +#endif /* CONFIG_PM */ + +static const struct ssb_device_id ssb_ohci_table[] = { + SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV), + SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV), + SSB_DEVTABLE_END +}; +MODULE_DEVICE_TABLE(ssb, ssb_ohci_table); + +static struct ssb_driver ssb_ohci_driver = { + .name = KBUILD_MODNAME, + .id_table = ssb_ohci_table, + .probe = ssb_ohci_probe, + .remove = ssb_ohci_remove, + .suspend = ssb_ohci_suspend, + .resume = ssb_ohci_resume, +}; -- cgit v1.2.3-70-g09d2 From 914a3f3b375493eb44ad652a431939258cf34f71 Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Wed, 10 Oct 2007 02:29:43 -0700 Subject: USB: add atmel_usba_udc driver This is a driver for the Atmel USBA UDC which can be found integrated on AT32AP700x AVR32 processors. For hardware documentation, please see the AT32AP7000 data sheet: http://www.atmel.com/dyn/resources/prod_documents/doc32003.pdf This is a dual speed controller (connects at high or full speed). The driver supports up to 7 control, bulk, interrupt and isochronous endpoints with some constraints. Bulk, interrupt and isochronous transfers are driven by DMA. Signed-off-by: Haavard Skinnemoen Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 7 + drivers/usb/gadget/Kconfig | 26 +- drivers/usb/gadget/Makefile | 1 + drivers/usb/gadget/atmel_usba_udc.c | 2038 +++++++++++++++++++++++++++++++++++ drivers/usb/gadget/atmel_usba_udc.h | 350 ++++++ 5 files changed, 2421 insertions(+), 1 deletion(-) create mode 100644 drivers/usb/gadget/atmel_usba_udc.c create mode 100644 drivers/usb/gadget/atmel_usba_udc.h (limited to 'drivers') diff --git a/MAINTAINERS b/MAINTAINERS index c4eca56ed5b..60e649ff6fd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -677,6 +677,13 @@ P: Haavard Skinnemoen M: hskinnemoen@atmel.com S: Supported +ATMEL USBA UDC DRIVER +P: Haavard Skinnemoen +M: hskinnemoen@atmel.com +L: kernel@avr32linux.org +W: http://avr32linux.org/twiki/bin/view/Main/AtmelUsbDeviceDriver +S: Supported + ATMEL WIRELESS DRIVER P: Simon Kelley M: simon@thekelleys.org.uk diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 767aed5b4be..f81d08d6538 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -67,6 +67,17 @@ config USB_GADGET_DEBUG_FILES driver on a new board. Enable these files by choosing "Y" here. If in doubt, or to conserve kernel memory, say "N". +config USB_GADGET_DEBUG_FS + boolean "Debugging information files in debugfs" + depends on USB_GADGET && DEBUG_FS + help + Some of the drivers in the "gadget" framework can expose + debugging information in files under /sys/kernel/debug/. + The information in these files may help when you're + troubleshooting or bringing up a driver on a new board. + Enable these files by choosing "Y" here. If in doubt, or + to conserve kernel memory, say "N". + config USB_GADGET_SELECTED boolean @@ -103,6 +114,20 @@ config USB_AMD5536UDC default USB_GADGET select USB_GADGET_SELECTED +config USB_GADGET_ATMEL_USBA + boolean "Atmel USBA" + select USB_GADGET_DUALSPEED + depends on AVR32 + help + USBA is the integrated high-speed USB Device controller on + the AT32AP700x processors from Atmel. + +config USB_ATMEL_USBA + tristate + depends on USB_GADGET_ATMEL_USBA + default USB_GADGET + select USB_GADGET_SELECTED + config USB_GADGET_FSL_USB2 boolean "Freescale Highspeed USB DR Peripheral Controller" depends on MPC834x || PPC_MPC831x @@ -228,7 +253,6 @@ config USB_LH7A40X default USB_GADGET select USB_GADGET_SELECTED - config USB_GADGET_OMAP boolean "OMAP USB Device Controller" depends on ARCH_OMAP diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 1bc0f03550c..904e57bf611 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_USB_OMAP) += omap_udc.o obj-$(CONFIG_USB_LH7A40X) += lh7a40x_udc.o obj-$(CONFIG_USB_S3C2410) += s3c2410_udc.o obj-$(CONFIG_USB_AT91) += at91_udc.o +obj-$(CONFIG_USB_ATMEL_USBA) += atmel_usba_udc.o obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o obj-$(CONFIG_USB_M66592) += m66592-udc.o diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c new file mode 100644 index 00000000000..2bb28a58393 --- /dev/null +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -0,0 +1,2038 @@ +/* + * Driver for the Atmel USBA high speed USB device controller + * + * Copyright (C) 2005-2007 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "atmel_usba_udc.h" + + +static struct usba_udc the_udc; + +#ifdef CONFIG_USB_GADGET_DEBUG_FS +#include +#include + +static int queue_dbg_open(struct inode *inode, struct file *file) +{ + struct usba_ep *ep = inode->i_private; + struct usba_request *req, *req_copy; + struct list_head *queue_data; + + queue_data = kmalloc(sizeof(*queue_data), GFP_KERNEL); + if (!queue_data) + return -ENOMEM; + INIT_LIST_HEAD(queue_data); + + spin_lock_irq(&ep->udc->lock); + list_for_each_entry(req, &ep->queue, queue) { + req_copy = kmalloc(sizeof(*req_copy), GFP_ATOMIC); + if (!req_copy) + goto fail; + memcpy(req_copy, req, sizeof(*req_copy)); + list_add_tail(&req_copy->queue, queue_data); + } + spin_unlock_irq(&ep->udc->lock); + + file->private_data = queue_data; + return 0; + +fail: + spin_unlock_irq(&ep->udc->lock); + list_for_each_entry_safe(req, req_copy, queue_data, queue) { + list_del(&req->queue); + kfree(req); + } + kfree(queue_data); + return -ENOMEM; +} + +/* + * bbbbbbbb llllllll IZS sssss nnnn FDL\n\0 + * + * b: buffer address + * l: buffer length + * I/i: interrupt/no interrupt + * Z/z: zero/no zero + * S/s: short ok/short not ok + * s: status + * n: nr_packets + * F/f: submitted/not submitted to FIFO + * D/d: using/not using DMA + * L/l: last transaction/not last transaction + */ +static ssize_t queue_dbg_read(struct file *file, char __user *buf, + size_t nbytes, loff_t *ppos) +{ + struct list_head *queue = file->private_data; + struct usba_request *req, *tmp_req; + size_t len, remaining, actual = 0; + char tmpbuf[38]; + + if (!access_ok(VERIFY_WRITE, buf, nbytes)) + return -EFAULT; + + mutex_lock(&file->f_dentry->d_inode->i_mutex); + list_for_each_entry_safe(req, tmp_req, queue, queue) { + len = snprintf(tmpbuf, sizeof(tmpbuf), + "%8p %08x %c%c%c %5d %c%c%c\n", + req->req.buf, req->req.length, + req->req.no_interrupt ? 'i' : 'I', + req->req.zero ? 'Z' : 'z', + req->req.short_not_ok ? 's' : 'S', + req->req.status, + req->submitted ? 'F' : 'f', + req->using_dma ? 'D' : 'd', + req->last_transaction ? 'L' : 'l'); + len = min(len, sizeof(tmpbuf)); + if (len > nbytes) + break; + + list_del(&req->queue); + kfree(req); + + remaining = __copy_to_user(buf, tmpbuf, len); + actual += len - remaining; + if (remaining) + break; + + nbytes -= len; + buf += len; + } + mutex_unlock(&file->f_dentry->d_inode->i_mutex); + + return actual; +} + +static int queue_dbg_release(struct inode *inode, struct file *file) +{ + struct list_head *queue_data = file->private_data; + struct usba_request *req, *tmp_req; + + list_for_each_entry_safe(req, tmp_req, queue_data, queue) { + list_del(&req->queue); + kfree(req); + } + kfree(queue_data); + return 0; +} + +static int regs_dbg_open(struct inode *inode, struct file *file) +{ + struct usba_udc *udc; + unsigned int i; + u32 *data; + int ret = -ENOMEM; + + mutex_lock(&inode->i_mutex); + udc = inode->i_private; + data = kmalloc(inode->i_size, GFP_KERNEL); + if (!data) + goto out; + + spin_lock_irq(&udc->lock); + for (i = 0; i < inode->i_size / 4; i++) + data[i] = __raw_readl(udc->regs + i * 4); + spin_unlock_irq(&udc->lock); + + file->private_data = data; + ret = 0; + +out: + mutex_unlock(&inode->i_mutex); + + return ret; +} + +static ssize_t regs_dbg_read(struct file *file, char __user *buf, + size_t nbytes, loff_t *ppos) +{ + struct inode *inode = file->f_dentry->d_inode; + int ret; + + mutex_lock(&inode->i_mutex); + ret = simple_read_from_buffer(buf, nbytes, ppos, + file->private_data, + file->f_dentry->d_inode->i_size); + mutex_unlock(&inode->i_mutex); + + return ret; +} + +static int regs_dbg_release(struct inode *inode, struct file *file) +{ + kfree(file->private_data); + return 0; +} + +const struct file_operations queue_dbg_fops = { + .owner = THIS_MODULE, + .open = queue_dbg_open, + .llseek = no_llseek, + .read = queue_dbg_read, + .release = queue_dbg_release, +}; + +const struct file_operations regs_dbg_fops = { + .owner = THIS_MODULE, + .open = regs_dbg_open, + .llseek = generic_file_llseek, + .read = regs_dbg_read, + .release = regs_dbg_release, +}; + +static void usba_ep_init_debugfs(struct usba_udc *udc, + struct usba_ep *ep) +{ + struct dentry *ep_root; + + ep_root = debugfs_create_dir(ep->ep.name, udc->debugfs_root); + if (!ep_root) + goto err_root; + ep->debugfs_dir = ep_root; + + ep->debugfs_queue = debugfs_create_file("queue", 0400, ep_root, + ep, &queue_dbg_fops); + if (!ep->debugfs_queue) + goto err_queue; + + if (ep->can_dma) { + ep->debugfs_dma_status + = debugfs_create_u32("dma_status", 0400, ep_root, + &ep->last_dma_status); + if (!ep->debugfs_dma_status) + goto err_dma_status; + } + if (ep_is_control(ep)) { + ep->debugfs_state + = debugfs_create_u32("state", 0400, ep_root, + &ep->state); + if (!ep->debugfs_state) + goto err_state; + } + + return; + +err_state: + if (ep->can_dma) + debugfs_remove(ep->debugfs_dma_status); +err_dma_status: + debugfs_remove(ep->debugfs_queue); +err_queue: + debugfs_remove(ep_root); +err_root: + dev_err(&ep->udc->pdev->dev, + "failed to create debugfs directory for %s\n", ep->ep.name); +} + +static void usba_ep_cleanup_debugfs(struct usba_ep *ep) +{ + debugfs_remove(ep->debugfs_queue); + debugfs_remove(ep->debugfs_dma_status); + debugfs_remove(ep->debugfs_state); + debugfs_remove(ep->debugfs_dir); + ep->debugfs_dma_status = NULL; + ep->debugfs_dir = NULL; +} + +static void usba_init_debugfs(struct usba_udc *udc) +{ + struct dentry *root, *regs; + struct resource *regs_resource; + + root = debugfs_create_dir(udc->gadget.name, NULL); + if (IS_ERR(root) || !root) + goto err_root; + udc->debugfs_root = root; + + regs = debugfs_create_file("regs", 0400, root, udc, ®s_dbg_fops); + if (!regs) + goto err_regs; + + regs_resource = platform_get_resource(udc->pdev, IORESOURCE_MEM, + CTRL_IOMEM_ID); + regs->d_inode->i_size = regs_resource->end - regs_resource->start + 1; + udc->debugfs_regs = regs; + + usba_ep_init_debugfs(udc, to_usba_ep(udc->gadget.ep0)); + + return; + +err_regs: + debugfs_remove(root); +err_root: + udc->debugfs_root = NULL; + dev_err(&udc->pdev->dev, "debugfs is not available\n"); +} + +static void usba_cleanup_debugfs(struct usba_udc *udc) +{ + usba_ep_cleanup_debugfs(to_usba_ep(udc->gadget.ep0)); + debugfs_remove(udc->debugfs_regs); + debugfs_remove(udc->debugfs_root); + udc->debugfs_regs = NULL; + udc->debugfs_root = NULL; +} +#else +static inline void usba_ep_init_debugfs(struct usba_udc *udc, + struct usba_ep *ep) +{ + +} + +static inline void usba_ep_cleanup_debugfs(struct usba_ep *ep) +{ + +} + +static inline void usba_init_debugfs(struct usba_udc *udc) +{ + +} + +static inline void usba_cleanup_debugfs(struct usba_udc *udc) +{ + +} +#endif + +static int vbus_is_present(struct usba_udc *udc) +{ + if (udc->vbus_pin != -1) + return gpio_get_value(udc->vbus_pin); + + /* No Vbus detection: Assume always present */ + return 1; +} + +static void copy_to_fifo(void __iomem *fifo, const void *buf, int len) +{ + unsigned long tmp; + + DBG(DBG_FIFO, "copy to FIFO (len %d):\n", len); + for (; len > 0; len -= 4, buf += 4, fifo += 4) { + tmp = *(unsigned long *)buf; + if (len >= 4) { + DBG(DBG_FIFO, " -> %08lx\n", tmp); + __raw_writel(tmp, fifo); + } else { + do { + DBG(DBG_FIFO, " -> %02lx\n", tmp >> 24); + __raw_writeb(tmp >> 24, fifo); + fifo++; + tmp <<= 8; + } while (--len); + break; + } + } +} + +static void copy_from_fifo(void *buf, void __iomem *fifo, int len) +{ + union { + unsigned long *w; + unsigned char *b; + } p; + unsigned long tmp; + + DBG(DBG_FIFO, "copy from FIFO (len %d):\n", len); + for (p.w = buf; len > 0; len -= 4, p.w++, fifo += 4) { + if (len >= 4) { + tmp = __raw_readl(fifo); + *p.w = tmp; + DBG(DBG_FIFO, " -> %08lx\n", tmp); + } else { + do { + tmp = __raw_readb(fifo); + *p.b = tmp; + DBG(DBG_FIFO, " -> %02lx\n", tmp); + fifo++, p.b++; + } while (--len); + } + } +} + +static void next_fifo_transaction(struct usba_ep *ep, struct usba_request *req) +{ + unsigned int transaction_len; + + transaction_len = req->req.length - req->req.actual; + req->last_transaction = 1; + if (transaction_len > ep->ep.maxpacket) { + transaction_len = ep->ep.maxpacket; + req->last_transaction = 0; + } else if (transaction_len == ep->ep.maxpacket && req->req.zero) + req->last_transaction = 0; + + DBG(DBG_QUEUE, "%s: submit_transaction, req %p (length %d)%s\n", + ep->ep.name, req, transaction_len, + req->last_transaction ? ", done" : ""); + + copy_to_fifo(ep->fifo, req->req.buf + req->req.actual, transaction_len); + usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY); + req->req.actual += transaction_len; +} + +static void submit_request(struct usba_ep *ep, struct usba_request *req) +{ + DBG(DBG_QUEUE, "%s: submit_request: req %p (length %d)\n", + ep->ep.name, req, req->req.length); + + req->req.actual = 0; + req->submitted = 1; + + if (req->using_dma) { + if (req->req.length == 0) { + usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY); + return; + } + + if (req->req.zero) + usba_ep_writel(ep, CTL_ENB, USBA_SHORT_PACKET); + else + usba_ep_writel(ep, CTL_DIS, USBA_SHORT_PACKET); + + usba_dma_writel(ep, ADDRESS, req->req.dma); + usba_dma_writel(ep, CONTROL, req->ctrl); + } else { + next_fifo_transaction(ep, req); + if (req->last_transaction) { + usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY); + usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE); + } else { + usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE); + usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY); + } + } +} + +static void submit_next_request(struct usba_ep *ep) +{ + struct usba_request *req; + + if (list_empty(&ep->queue)) { + usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY | USBA_RX_BK_RDY); + return; + } + + req = list_entry(ep->queue.next, struct usba_request, queue); + if (!req->submitted) + submit_request(ep, req); +} + +static void send_status(struct usba_udc *udc, struct usba_ep *ep) +{ + ep->state = STATUS_STAGE_IN; + usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY); + usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE); +} + +static void receive_data(struct usba_ep *ep) +{ + struct usba_udc *udc = ep->udc; + struct usba_request *req; + unsigned long status; + unsigned int bytecount, nr_busy; + int is_complete = 0; + + status = usba_ep_readl(ep, STA); + nr_busy = USBA_BFEXT(BUSY_BANKS, status); + + DBG(DBG_QUEUE, "receive data: nr_busy=%u\n", nr_busy); + + while (nr_busy > 0) { + if (list_empty(&ep->queue)) { + usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY); + break; + } + req = list_entry(ep->queue.next, + struct usba_request, queue); + + bytecount = USBA_BFEXT(BYTE_COUNT, status); + + if (status & (1 << 31)) + is_complete = 1; + if (req->req.actual + bytecount >= req->req.length) { + is_complete = 1; + bytecount = req->req.length - req->req.actual; + } + + copy_from_fifo(req->req.buf + req->req.actual, + ep->fifo, bytecount); + req->req.actual += bytecount; + + usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY); + + if (is_complete) { + DBG(DBG_QUEUE, "%s: request done\n", ep->ep.name); + req->req.status = 0; + list_del_init(&req->queue); + usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY); + spin_unlock(&udc->lock); + req->req.complete(&ep->ep, &req->req); + spin_lock(&udc->lock); + } + + status = usba_ep_readl(ep, STA); + nr_busy = USBA_BFEXT(BUSY_BANKS, status); + + if (is_complete && ep_is_control(ep)) { + send_status(udc, ep); + break; + } + } +} + +static void +request_complete(struct usba_ep *ep, struct usba_request *req, int status) +{ + struct usba_udc *udc = ep->udc; + + WARN_ON(!list_empty(&req->queue)); + + if (req->req.status == -EINPROGRESS) + req->req.status = status; + + if (req->mapped) { + dma_unmap_single( + &udc->pdev->dev, req->req.dma, req->req.length, + ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + req->req.dma = DMA_ADDR_INVALID; + req->mapped = 0; + } + + DBG(DBG_GADGET | DBG_REQ, + "%s: req %p complete: status %d, actual %u\n", + ep->ep.name, req, req->req.status, req->req.actual); + + spin_unlock(&udc->lock); + req->req.complete(&ep->ep, &req->req); + spin_lock(&udc->lock); +} + +static void +request_complete_list(struct usba_ep *ep, struct list_head *list, int status) +{ + struct usba_request *req, *tmp_req; + + list_for_each_entry_safe(req, tmp_req, list, queue) { + list_del_init(&req->queue); + request_complete(ep, req, status); + } +} + +static int +usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) +{ + struct usba_ep *ep = to_usba_ep(_ep); + struct usba_udc *udc = ep->udc; + unsigned long flags, ept_cfg, maxpacket; + unsigned int nr_trans; + + DBG(DBG_GADGET, "%s: ep_enable: desc=%p\n", ep->ep.name, desc); + + maxpacket = le16_to_cpu(desc->wMaxPacketSize) & 0x7ff; + + if (((desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) != ep->index) + || ep->index == 0 + || desc->bDescriptorType != USB_DT_ENDPOINT + || maxpacket == 0 + || maxpacket > ep->fifo_size) { + DBG(DBG_ERR, "ep_enable: Invalid argument"); + return -EINVAL; + } + + ep->is_isoc = 0; + ep->is_in = 0; + + if (maxpacket <= 8) + ept_cfg = USBA_BF(EPT_SIZE, USBA_EPT_SIZE_8); + else + /* LSB is bit 1, not 0 */ + ept_cfg = USBA_BF(EPT_SIZE, fls(maxpacket - 1) - 3); + + DBG(DBG_HW, "%s: EPT_SIZE = %lu (maxpacket = %lu)\n", + ep->ep.name, ept_cfg, maxpacket); + + if ((desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) { + ep->is_in = 1; + ept_cfg |= USBA_EPT_DIR_IN; + } + + switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { + case USB_ENDPOINT_XFER_CONTROL: + ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_CONTROL); + ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE); + break; + case USB_ENDPOINT_XFER_ISOC: + if (!ep->can_isoc) { + DBG(DBG_ERR, "ep_enable: %s is not isoc capable\n", + ep->ep.name); + return -EINVAL; + } + + /* + * Bits 11:12 specify number of _additional_ + * transactions per microframe. + */ + nr_trans = ((le16_to_cpu(desc->wMaxPacketSize) >> 11) & 3) + 1; + if (nr_trans > 3) + return -EINVAL; + + ep->is_isoc = 1; + ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_ISO); + + /* + * Do triple-buffering on high-bandwidth iso endpoints. + */ + if (nr_trans > 1 && ep->nr_banks == 3) + ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_TRIPLE); + else + ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE); + ept_cfg |= USBA_BF(NB_TRANS, nr_trans); + break; + case USB_ENDPOINT_XFER_BULK: + ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK); + ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE); + break; + case USB_ENDPOINT_XFER_INT: + ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_INT); + ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE); + break; + } + + spin_lock_irqsave(&ep->udc->lock, flags); + + if (ep->desc) { + spin_unlock_irqrestore(&ep->udc->lock, flags); + DBG(DBG_ERR, "ep%d already enabled\n", ep->index); + return -EBUSY; + } + + ep->desc = desc; + ep->ep.maxpacket = maxpacket; + + usba_ep_writel(ep, CFG, ept_cfg); + usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE); + + if (ep->can_dma) { + u32 ctrl; + + usba_writel(udc, INT_ENB, + (usba_readl(udc, INT_ENB) + | USBA_BF(EPT_INT, 1 << ep->index) + | USBA_BF(DMA_INT, 1 << ep->index))); + ctrl = USBA_AUTO_VALID | USBA_INTDIS_DMA; + usba_ep_writel(ep, CTL_ENB, ctrl); + } else { + usba_writel(udc, INT_ENB, + (usba_readl(udc, INT_ENB) + | USBA_BF(EPT_INT, 1 << ep->index))); + } + + spin_unlock_irqrestore(&udc->lock, flags); + + DBG(DBG_HW, "EPT_CFG%d after init: %#08lx\n", ep->index, + (unsigned long)usba_ep_readl(ep, CFG)); + DBG(DBG_HW, "INT_ENB after init: %#08lx\n", + (unsigned long)usba_readl(udc, INT_ENB)); + + return 0; +} + +static int usba_ep_disable(struct usb_ep *_ep) +{ + struct usba_ep *ep = to_usba_ep(_ep); + struct usba_udc *udc = ep->udc; + LIST_HEAD(req_list); + unsigned long flags; + + DBG(DBG_GADGET, "ep_disable: %s\n", ep->ep.name); + + spin_lock_irqsave(&udc->lock, flags); + + if (!ep->desc) { + spin_unlock_irqrestore(&udc->lock, flags); + DBG(DBG_ERR, "ep_disable: %s not enabled\n", ep->ep.name); + return -EINVAL; + } + ep->desc = NULL; + + list_splice_init(&ep->queue, &req_list); + if (ep->can_dma) { + usba_dma_writel(ep, CONTROL, 0); + usba_dma_writel(ep, ADDRESS, 0); + usba_dma_readl(ep, STATUS); + } + usba_ep_writel(ep, CTL_DIS, USBA_EPT_ENABLE); + usba_writel(udc, INT_ENB, + usba_readl(udc, INT_ENB) + & ~USBA_BF(EPT_INT, 1 << ep->index)); + + request_complete_list(ep, &req_list, -ESHUTDOWN); + + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + +static struct usb_request * +usba_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) +{ + struct usba_request *req; + + DBG(DBG_GADGET, "ep_alloc_request: %p, 0x%x\n", _ep, gfp_flags); + + req = kzalloc(sizeof(*req), gfp_flags); + if (!req) + return NULL; + + INIT_LIST_HEAD(&req->queue); + req->req.dma = DMA_ADDR_INVALID; + + return &req->req; +} + +static void +usba_ep_free_request(struct usb_ep *_ep, struct usb_request *_req) +{ + struct usba_request *req = to_usba_req(_req); + + DBG(DBG_GADGET, "ep_free_request: %p, %p\n", _ep, _req); + + kfree(req); +} + +static int queue_dma(struct usba_udc *udc, struct usba_ep *ep, + struct usba_request *req, gfp_t gfp_flags) +{ + unsigned long flags; + int ret; + + DBG(DBG_DMA, "%s: req l/%u d/%08x %c%c%c\n", + ep->ep.name, req->req.length, req->req.dma, + req->req.zero ? 'Z' : 'z', + req->req.short_not_ok ? 'S' : 's', + req->req.no_interrupt ? 'I' : 'i'); + + if (req->req.length > 0x10000) { + /* Lengths from 0 to 65536 (inclusive) are supported */ + DBG(DBG_ERR, "invalid request length %u\n", req->req.length); + return -EINVAL; + } + + req->using_dma = 1; + + if (req->req.dma == DMA_ADDR_INVALID) { + req->req.dma = dma_map_single( + &udc->pdev->dev, req->req.buf, req->req.length, + ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + req->mapped = 1; + } else { + dma_sync_single_for_device( + &udc->pdev->dev, req->req.dma, req->req.length, + ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + req->mapped = 0; + } + + req->ctrl = USBA_BF(DMA_BUF_LEN, req->req.length) + | USBA_DMA_CH_EN | USBA_DMA_END_BUF_IE + | USBA_DMA_END_TR_EN | USBA_DMA_END_TR_IE; + + if (ep->is_in) + req->ctrl |= USBA_DMA_END_BUF_EN; + + /* + * Add this request to the queue and submit for DMA if + * possible. Check if we're still alive first -- we may have + * received a reset since last time we checked. + */ + ret = -ESHUTDOWN; + spin_lock_irqsave(&udc->lock, flags); + if (ep->desc) { + if (list_empty(&ep->queue)) + submit_request(ep, req); + + list_add_tail(&req->queue, &ep->queue); + ret = 0; + } + spin_unlock_irqrestore(&udc->lock, flags); + + return ret; +} + +static int +usba_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) +{ + struct usba_request *req = to_usba_req(_req); + struct usba_ep *ep = to_usba_ep(_ep); + struct usba_udc *udc = ep->udc; + unsigned long flags; + int ret; + + DBG(DBG_GADGET | DBG_QUEUE | DBG_REQ, "%s: queue req %p, len %u\n", + ep->ep.name, req, _req->length); + + if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN || !ep->desc) + return -ESHUTDOWN; + + req->submitted = 0; + req->using_dma = 0; + req->last_transaction = 0; + + _req->status = -EINPROGRESS; + _req->actual = 0; + + if (ep->can_dma) + return queue_dma(udc, ep, req, gfp_flags); + + /* May have received a reset since last time we checked */ + ret = -ESHUTDOWN; + spin_lock_irqsave(&udc->lock, flags); + if (ep->desc) { + list_add_tail(&req->queue, &ep->queue); + + if (ep->is_in || (ep_is_control(ep) + && (ep->state == DATA_STAGE_IN + || ep->state == STATUS_STAGE_IN))) + usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY); + else + usba_ep_writel(ep, CTL_ENB, USBA_RX_BK_RDY); + ret = 0; + } + spin_unlock_irqrestore(&udc->lock, flags); + + return ret; +} + +static void +usba_update_req(struct usba_ep *ep, struct usba_request *req, u32 status) +{ + req->req.actual = req->req.length - USBA_BFEXT(DMA_BUF_LEN, status); +} + +static int stop_dma(struct usba_ep *ep, u32 *pstatus) +{ + unsigned int timeout; + u32 status; + + /* + * Stop the DMA controller. When writing both CH_EN + * and LINK to 0, the other bits are not affected. + */ + usba_dma_writel(ep, CONTROL, 0); + + /* Wait for the FIFO to empty */ + for (timeout = 40; timeout; --timeout) { + status = usba_dma_readl(ep, STATUS); + if (!(status & USBA_DMA_CH_EN)) + break; + udelay(1); + } + + if (pstatus) + *pstatus = status; + + if (timeout == 0) { + dev_err(&ep->udc->pdev->dev, + "%s: timed out waiting for DMA FIFO to empty\n", + ep->ep.name); + return -ETIMEDOUT; + } + + return 0; +} + +static int usba_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) +{ + struct usba_ep *ep = to_usba_ep(_ep); + struct usba_udc *udc = ep->udc; + struct usba_request *req = to_usba_req(_req); + unsigned long flags; + u32 status; + + DBG(DBG_GADGET | DBG_QUEUE, "ep_dequeue: %s, req %p\n", + ep->ep.name, req); + + spin_lock_irqsave(&udc->lock, flags); + + if (req->using_dma) { + /* + * If this request is currently being transferred, + * stop the DMA controller and reset the FIFO. + */ + if (ep->queue.next == &req->queue) { + status = usba_dma_readl(ep, STATUS); + if (status & USBA_DMA_CH_EN) + stop_dma(ep, &status); + +#ifdef CONFIG_USB_GADGET_DEBUG_FS + ep->last_dma_status = status; +#endif + + usba_writel(udc, EPT_RST, 1 << ep->index); + + usba_update_req(ep, req, status); + } + } + + /* + * Errors should stop the queue from advancing until the + * completion function returns. + */ + list_del_init(&req->queue); + + request_complete(ep, req, -ECONNRESET); + + /* Process the next request if any */ + submit_next_request(ep); + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + +static int usba_ep_set_halt(struct usb_ep *_ep, int value) +{ + struct usba_ep *ep = to_usba_ep(_ep); + struct usba_udc *udc = ep->udc; + unsigned long flags; + int ret = 0; + + DBG(DBG_GADGET, "endpoint %s: %s HALT\n", ep->ep.name, + value ? "set" : "clear"); + + if (!ep->desc) { + DBG(DBG_ERR, "Attempted to halt uninitialized ep %s\n", + ep->ep.name); + return -ENODEV; + } + if (ep->is_isoc) { + DBG(DBG_ERR, "Attempted to halt isochronous ep %s\n", + ep->ep.name); + return -ENOTTY; + } + + spin_lock_irqsave(&udc->lock, flags); + + /* + * We can't halt IN endpoints while there are still data to be + * transferred + */ + if (!list_empty(&ep->queue) + || ((value && ep->is_in && (usba_ep_readl(ep, STA) + & USBA_BF(BUSY_BANKS, -1L))))) { + ret = -EAGAIN; + } else { + if (value) + usba_ep_writel(ep, SET_STA, USBA_FORCE_STALL); + else + usba_ep_writel(ep, CLR_STA, + USBA_FORCE_STALL | USBA_TOGGLE_CLR); + usba_ep_readl(ep, STA); + } + + spin_unlock_irqrestore(&udc->lock, flags); + + return ret; +} + +static int usba_ep_fifo_status(struct usb_ep *_ep) +{ + struct usba_ep *ep = to_usba_ep(_ep); + + return USBA_BFEXT(BYTE_COUNT, usba_ep_readl(ep, STA)); +} + +static void usba_ep_fifo_flush(struct usb_ep *_ep) +{ + struct usba_ep *ep = to_usba_ep(_ep); + struct usba_udc *udc = ep->udc; + + usba_writel(udc, EPT_RST, 1 << ep->index); +} + +static const struct usb_ep_ops usba_ep_ops = { + .enable = usba_ep_enable, + .disable = usba_ep_disable, + .alloc_request = usba_ep_alloc_request, + .free_request = usba_ep_free_request, + .queue = usba_ep_queue, + .dequeue = usba_ep_dequeue, + .set_halt = usba_ep_set_halt, + .fifo_status = usba_ep_fifo_status, + .fifo_flush = usba_ep_fifo_flush, +}; + +static int usba_udc_get_frame(struct usb_gadget *gadget) +{ + struct usba_udc *udc = to_usba_udc(gadget); + + return USBA_BFEXT(FRAME_NUMBER, usba_readl(udc, FNUM)); +} + +static const struct usb_gadget_ops usba_udc_ops = { + .get_frame = usba_udc_get_frame, +}; + +#define EP(nam, idx, maxpkt, maxbk, dma, isoc) \ +{ \ + .ep = { \ + .ops = &usba_ep_ops, \ + .name = nam, \ + .maxpacket = maxpkt, \ + }, \ + .udc = &the_udc, \ + .queue = LIST_HEAD_INIT(usba_ep[idx].queue), \ + .fifo_size = maxpkt, \ + .nr_banks = maxbk, \ + .index = idx, \ + .can_dma = dma, \ + .can_isoc = isoc, \ +} + +static struct usba_ep usba_ep[] = { + EP("ep0", 0, 64, 1, 0, 0), + EP("ep1in-bulk", 1, 512, 2, 1, 1), + EP("ep2out-bulk", 2, 512, 2, 1, 1), + EP("ep3in-int", 3, 64, 3, 1, 0), + EP("ep4out-int", 4, 64, 3, 1, 0), + EP("ep5in-iso", 5, 1024, 3, 1, 1), + EP("ep6out-iso", 6, 1024, 3, 1, 1), +}; +#undef EP + +static struct usb_endpoint_descriptor usba_ep0_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0, + .bmAttributes = USB_ENDPOINT_XFER_CONTROL, + .wMaxPacketSize = __constant_cpu_to_le16(64), + /* FIXME: I have no idea what to put here */ + .bInterval = 1, +}; + +static void nop_release(struct device *dev) +{ + +} + +static struct usba_udc the_udc = { + .gadget = { + .ops = &usba_udc_ops, + .ep0 = &usba_ep[0].ep, + .ep_list = LIST_HEAD_INIT(the_udc.gadget.ep_list), + .is_dualspeed = 1, + .name = "atmel_usba_udc", + .dev = { + .bus_id = "gadget", + .release = nop_release, + }, + }, + + .lock = SPIN_LOCK_UNLOCKED, +}; + +/* + * Called with interrupts disabled and udc->lock held. + */ +static void reset_all_endpoints(struct usba_udc *udc) +{ + struct usba_ep *ep; + struct usba_request *req, *tmp_req; + + usba_writel(udc, EPT_RST, ~0UL); + + ep = to_usba_ep(udc->gadget.ep0); + list_for_each_entry_safe(req, tmp_req, &ep->queue, queue) { + list_del_init(&req->queue); + request_complete(ep, req, -ECONNRESET); + } + + list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) { + if (ep->desc) + usba_ep_disable(&ep->ep); + } +} + +static struct usba_ep *get_ep_by_addr(struct usba_udc *udc, u16 wIndex) +{ + struct usba_ep *ep; + + if ((wIndex & USB_ENDPOINT_NUMBER_MASK) == 0) + return to_usba_ep(udc->gadget.ep0); + + list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list) { + u8 bEndpointAddress; + + if (!ep->desc) + continue; + bEndpointAddress = ep->desc->bEndpointAddress; + if ((wIndex ^ bEndpointAddress) & USB_DIR_IN) + continue; + if ((bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) + == (wIndex & USB_ENDPOINT_NUMBER_MASK)) + return ep; + } + + return NULL; +} + +/* Called with interrupts disabled and udc->lock held */ +static inline void set_protocol_stall(struct usba_udc *udc, struct usba_ep *ep) +{ + usba_ep_writel(ep, SET_STA, USBA_FORCE_STALL); + ep->state = WAIT_FOR_SETUP; +} + +static inline int is_stalled(struct usba_udc *udc, struct usba_ep *ep) +{ + if (usba_ep_readl(ep, STA) & USBA_FORCE_STALL) + return 1; + return 0; +} + +static inline void set_address(struct usba_udc *udc, unsigned int addr) +{ + u32 regval; + + DBG(DBG_BUS, "setting address %u...\n", addr); + regval = usba_readl(udc, CTRL); + regval = USBA_BFINS(DEV_ADDR, addr, regval); + usba_writel(udc, CTRL, regval); +} + +static int do_test_mode(struct usba_udc *udc) +{ + static const char test_packet_buffer[] = { + /* JKJKJKJK * 9 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* JJKKJJKK * 8 */ + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + /* JJKKJJKK * 8 */ + 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, + /* JJJJJJJKKKKKKK * 8 */ + 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + /* JJJJJJJK * 8 */ + 0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, + /* {JKKKKKKK * 10}, JK */ + 0xFC, 0x7E, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0x7E + }; + struct usba_ep *ep; + struct device *dev = &udc->pdev->dev; + int test_mode; + + test_mode = udc->test_mode; + + /* Start from a clean slate */ + reset_all_endpoints(udc); + + switch (test_mode) { + case 0x0100: + /* Test_J */ + usba_writel(udc, TST, USBA_TST_J_MODE); + dev_info(dev, "Entering Test_J mode...\n"); + break; + case 0x0200: + /* Test_K */ + usba_writel(udc, TST, USBA_TST_K_MODE); + dev_info(dev, "Entering Test_K mode...\n"); + break; + case 0x0300: + /* + * Test_SE0_NAK: Force high-speed mode and set up ep0 + * for Bulk IN transfers + */ + ep = &usba_ep[0]; + usba_writel(udc, TST, + USBA_BF(SPEED_CFG, USBA_SPEED_CFG_FORCE_HIGH)); + usba_ep_writel(ep, CFG, + USBA_BF(EPT_SIZE, USBA_EPT_SIZE_64) + | USBA_EPT_DIR_IN + | USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK) + | USBA_BF(BK_NUMBER, 1)); + if (!(usba_ep_readl(ep, CFG) & USBA_EPT_MAPPED)) { + set_protocol_stall(udc, ep); + dev_err(dev, "Test_SE0_NAK: ep0 not mapped\n"); + } else { + usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE); + dev_info(dev, "Entering Test_SE0_NAK mode...\n"); + } + break; + case 0x0400: + /* Test_Packet */ + ep = &usba_ep[0]; + usba_ep_writel(ep, CFG, + USBA_BF(EPT_SIZE, USBA_EPT_SIZE_64) + | USBA_EPT_DIR_IN + | USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK) + | USBA_BF(BK_NUMBER, 1)); + if (!(usba_ep_readl(ep, CFG) & USBA_EPT_MAPPED)) { + set_protocol_stall(udc, ep); + dev_err(dev, "Test_Packet: ep0 not mapped\n"); + } else { + usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE); + usba_writel(udc, TST, USBA_TST_PKT_MODE); + copy_to_fifo(ep->fifo, test_packet_buffer, + sizeof(test_packet_buffer)); + usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY); + dev_info(dev, "Entering Test_Packet mode...\n"); + } + break; + default: + dev_err(dev, "Invalid test mode: 0x%04x\n", test_mode); + return -EINVAL; + } + + return 0; +} + +/* Avoid overly long expressions */ +static inline bool feature_is_dev_remote_wakeup(struct usb_ctrlrequest *crq) +{ + if (crq->wValue == __constant_cpu_to_le16(USB_DEVICE_REMOTE_WAKEUP)) + return true; + return false; +} + +static inline bool feature_is_dev_test_mode(struct usb_ctrlrequest *crq) +{ + if (crq->wValue == __constant_cpu_to_le16(USB_DEVICE_TEST_MODE)) + return true; + return false; +} + +static inline bool feature_is_ep_halt(struct usb_ctrlrequest *crq) +{ + if (crq->wValue == __constant_cpu_to_le16(USB_ENDPOINT_HALT)) + return true; + return false; +} + +static int handle_ep0_setup(struct usba_udc *udc, struct usba_ep *ep, + struct usb_ctrlrequest *crq) +{ + int retval = 0;; + + switch (crq->bRequest) { + case USB_REQ_GET_STATUS: { + u16 status; + + if (crq->bRequestType == (USB_DIR_IN | USB_RECIP_DEVICE)) { + /* Self-powered, no remote wakeup */ + status = __constant_cpu_to_le16(1 << 0); + } else if (crq->bRequestType + == (USB_DIR_IN | USB_RECIP_INTERFACE)) { + status = __constant_cpu_to_le16(0); + } else if (crq->bRequestType + == (USB_DIR_IN | USB_RECIP_ENDPOINT)) { + struct usba_ep *target; + + target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex)); + if (!target) + goto stall; + + status = 0; + if (is_stalled(udc, target)) + status |= __constant_cpu_to_le16(1); + } else + goto delegate; + + /* Write directly to the FIFO. No queueing is done. */ + if (crq->wLength != __constant_cpu_to_le16(sizeof(status))) + goto stall; + ep->state = DATA_STAGE_IN; + __raw_writew(status, ep->fifo); + usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY); + break; + } + + case USB_REQ_CLEAR_FEATURE: { + if (crq->bRequestType == USB_RECIP_DEVICE) { + if (feature_is_dev_remote_wakeup(crq)) { + /* TODO: Handle REMOTE_WAKEUP */ + } else { + /* Can't CLEAR_FEATURE TEST_MODE */ + goto stall; + } + } else if (crq->bRequestType == USB_RECIP_ENDPOINT) { + struct usba_ep *target; + + if (crq->wLength != __constant_cpu_to_le16(0) + || !feature_is_ep_halt(crq)) + goto stall; + target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex)); + if (!target) + goto stall; + + usba_ep_writel(target, CLR_STA, USBA_FORCE_STALL); + if (target->index != 0) + usba_ep_writel(target, CLR_STA, + USBA_TOGGLE_CLR); + } else { + goto delegate; + } + + send_status(udc, ep); + break; + } + + case USB_REQ_SET_FEATURE: { + if (crq->bRequestType == USB_RECIP_DEVICE) { + if (feature_is_dev_test_mode(crq)) { + send_status(udc, ep); + ep->state = STATUS_STAGE_TEST; + udc->test_mode = le16_to_cpu(crq->wIndex); + return 0; + } else if (feature_is_dev_remote_wakeup(crq)) { + /* TODO: Handle REMOTE_WAKEUP */ + } else { + goto stall; + } + } else if (crq->bRequestType == USB_RECIP_ENDPOINT) { + struct usba_ep *target; + + if (crq->wLength != __constant_cpu_to_le16(0) + || !feature_is_ep_halt(crq)) + goto stall; + + target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex)); + if (!target) + goto stall; + + usba_ep_writel(target, SET_STA, USBA_FORCE_STALL); + } else + goto delegate; + + send_status(udc, ep); + break; + } + + case USB_REQ_SET_ADDRESS: + if (crq->bRequestType != (USB_DIR_OUT | USB_RECIP_DEVICE)) + goto delegate; + + set_address(udc, le16_to_cpu(crq->wValue)); + send_status(udc, ep); + ep->state = STATUS_STAGE_ADDR; + break; + + default: +delegate: + spin_unlock(&udc->lock); + retval = udc->driver->setup(&udc->gadget, crq); + spin_lock(&udc->lock); + } + + return retval; + +stall: + printk(KERN_ERR + "udc: %s: Invalid setup request: %02x.%02x v%04x i%04x l%d, " + "halting endpoint...\n", + ep->ep.name, crq->bRequestType, crq->bRequest, + le16_to_cpu(crq->wValue), le16_to_cpu(crq->wIndex), + le16_to_cpu(crq->wLength)); + set_protocol_stall(udc, ep); + return -1; +} + +static void usba_control_irq(struct usba_udc *udc, struct usba_ep *ep) +{ + struct usba_request *req; + u32 epstatus; + u32 epctrl; + +restart: + epstatus = usba_ep_readl(ep, STA); + epctrl = usba_ep_readl(ep, CTL); + + DBG(DBG_INT, "%s [%d]: s/%08x c/%08x\n", + ep->ep.name, ep->state, epstatus, epctrl); + + req = NULL; + if (!list_empty(&ep->queue)) + req = list_entry(ep->queue.next, + struct usba_request, queue); + + if ((epctrl & USBA_TX_PK_RDY) && !(epstatus & USBA_TX_PK_RDY)) { + if (req->submitted) + next_fifo_transaction(ep, req); + else + submit_request(ep, req); + + if (req->last_transaction) { + usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY); + usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE); + } + goto restart; + } + if ((epstatus & epctrl) & USBA_TX_COMPLETE) { + usba_ep_writel(ep, CLR_STA, USBA_TX_COMPLETE); + + switch (ep->state) { + case DATA_STAGE_IN: + usba_ep_writel(ep, CTL_ENB, USBA_RX_BK_RDY); + usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE); + ep->state = STATUS_STAGE_OUT; + break; + case STATUS_STAGE_ADDR: + /* Activate our new address */ + usba_writel(udc, CTRL, (usba_readl(udc, CTRL) + | USBA_FADDR_EN)); + usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE); + ep->state = WAIT_FOR_SETUP; + break; + case STATUS_STAGE_IN: + if (req) { + list_del_init(&req->queue); + request_complete(ep, req, 0); + submit_next_request(ep); + } + usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE); + ep->state = WAIT_FOR_SETUP; + break; + case STATUS_STAGE_TEST: + usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE); + ep->state = WAIT_FOR_SETUP; + if (do_test_mode(udc)) + set_protocol_stall(udc, ep); + break; + default: + printk(KERN_ERR + "udc: %s: TXCOMP: Invalid endpoint state %d, " + "halting endpoint...\n", + ep->ep.name, ep->state); + set_protocol_stall(udc, ep); + break; + } + + goto restart; + } + if ((epstatus & epctrl) & USBA_RX_BK_RDY) { + switch (ep->state) { + case STATUS_STAGE_OUT: + usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY); + usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY); + + if (req) { + list_del_init(&req->queue); + request_complete(ep, req, 0); + } + ep->state = WAIT_FOR_SETUP; + break; + + case DATA_STAGE_OUT: + receive_data(ep); + break; + + default: + usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY); + usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY); + printk(KERN_ERR + "udc: %s: RXRDY: Invalid endpoint state %d, " + "halting endpoint...\n", + ep->ep.name, ep->state); + set_protocol_stall(udc, ep); + break; + } + + goto restart; + } + if (epstatus & USBA_RX_SETUP) { + union { + struct usb_ctrlrequest crq; + unsigned long data[2]; + } crq; + unsigned int pkt_len; + int ret; + + if (ep->state != WAIT_FOR_SETUP) { + /* + * Didn't expect a SETUP packet at this + * point. Clean up any pending requests (which + * may be successful). + */ + int status = -EPROTO; + + /* + * RXRDY and TXCOMP are dropped when SETUP + * packets arrive. Just pretend we received + * the status packet. + */ + if (ep->state == STATUS_STAGE_OUT + || ep->state == STATUS_STAGE_IN) { + usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY); + status = 0; + } + + if (req) { + list_del_init(&req->queue); + request_complete(ep, req, status); + } + } + + pkt_len = USBA_BFEXT(BYTE_COUNT, usba_ep_readl(ep, STA)); + DBG(DBG_HW, "Packet length: %u\n", pkt_len); + if (pkt_len != sizeof(crq)) { + printk(KERN_WARNING "udc: Invalid packet length %u " + "(expected %lu)\n", pkt_len, sizeof(crq)); + set_protocol_stall(udc, ep); + return; + } + + DBG(DBG_FIFO, "Copying ctrl request from 0x%p:\n", ep->fifo); + copy_from_fifo(crq.data, ep->fifo, sizeof(crq)); + + /* Free up one bank in the FIFO so that we can + * generate or receive a reply right away. */ + usba_ep_writel(ep, CLR_STA, USBA_RX_SETUP); + + /* printk(KERN_DEBUG "setup: %d: %02x.%02x\n", + ep->state, crq.crq.bRequestType, + crq.crq.bRequest); */ + + if (crq.crq.bRequestType & USB_DIR_IN) { + /* + * The USB 2.0 spec states that "if wLength is + * zero, there is no data transfer phase." + * However, testusb #14 seems to actually + * expect a data phase even if wLength = 0... + */ + ep->state = DATA_STAGE_IN; + } else { + if (crq.crq.wLength != __constant_cpu_to_le16(0)) + ep->state = DATA_STAGE_OUT; + else + ep->state = STATUS_STAGE_IN; + } + + ret = -1; + if (ep->index == 0) + ret = handle_ep0_setup(udc, ep, &crq.crq); + else { + spin_unlock(&udc->lock); + ret = udc->driver->setup(&udc->gadget, &crq.crq); + spin_lock(&udc->lock); + } + + DBG(DBG_BUS, "req %02x.%02x, length %d, state %d, ret %d\n", + crq.crq.bRequestType, crq.crq.bRequest, + le16_to_cpu(crq.crq.wLength), ep->state, ret); + + if (ret < 0) { + /* Let the host know that we failed */ + set_protocol_stall(udc, ep); + } + } +} + +static void usba_ep_irq(struct usba_udc *udc, struct usba_ep *ep) +{ + struct usba_request *req; + u32 epstatus; + u32 epctrl; + + epstatus = usba_ep_readl(ep, STA); + epctrl = usba_ep_readl(ep, CTL); + + DBG(DBG_INT, "%s: interrupt, status: 0x%08x\n", ep->ep.name, epstatus); + + while ((epctrl & USBA_TX_PK_RDY) && !(epstatus & USBA_TX_PK_RDY)) { + DBG(DBG_BUS, "%s: TX PK ready\n", ep->ep.name); + + if (list_empty(&ep->queue)) { + dev_warn(&udc->pdev->dev, "ep_irq: queue empty\n"); + usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY); + return; + } + + req = list_entry(ep->queue.next, struct usba_request, queue); + + if (req->using_dma) { + /* Send a zero-length packet */ + usba_ep_writel(ep, SET_STA, + USBA_TX_PK_RDY); + usba_ep_writel(ep, CTL_DIS, + USBA_TX_PK_RDY); + list_del_init(&req->queue); + submit_next_request(ep); + request_complete(ep, req, 0); + } else { + if (req->submitted) + next_fifo_transaction(ep, req); + else + submit_request(ep, req); + + if (req->last_transaction) { + list_del_init(&req->queue); + submit_next_request(ep); + request_complete(ep, req, 0); + } + } + + epstatus = usba_ep_readl(ep, STA); + epctrl = usba_ep_readl(ep, CTL); + } + if ((epstatus & epctrl) & USBA_RX_BK_RDY) { + DBG(DBG_BUS, "%s: RX data ready\n", ep->ep.name); + receive_data(ep); + usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY); + } +} + +static void usba_dma_irq(struct usba_udc *udc, struct usba_ep *ep) +{ + struct usba_request *req; + u32 status, control, pending; + + status = usba_dma_readl(ep, STATUS); + control = usba_dma_readl(ep, CONTROL); +#ifdef CONFIG_USB_GADGET_DEBUG_FS + ep->last_dma_status = status; +#endif + pending = status & control; + DBG(DBG_INT | DBG_DMA, "dma irq, s/%#08x, c/%#08x\n", status, control); + + if (status & USBA_DMA_CH_EN) { + dev_err(&udc->pdev->dev, + "DMA_CH_EN is set after transfer is finished!\n"); + dev_err(&udc->pdev->dev, + "status=%#08x, pending=%#08x, control=%#08x\n", + status, pending, control); + + /* + * try to pretend nothing happened. We might have to + * do something here... + */ + } + + if (list_empty(&ep->queue)) + /* Might happen if a reset comes along at the right moment */ + return; + + if (pending & (USBA_DMA_END_TR_ST | USBA_DMA_END_BUF_ST)) { + req = list_entry(ep->queue.next, struct usba_request, queue); + usba_update_req(ep, req, status); + + list_del_init(&req->queue); + submit_next_request(ep); + request_complete(ep, req, 0); + } +} + +static irqreturn_t usba_udc_irq(int irq, void *devid) +{ + struct usba_udc *udc = devid; + u32 status; + u32 dma_status; + u32 ep_status; + + spin_lock(&udc->lock); + + status = usba_readl(udc, INT_STA); + DBG(DBG_INT, "irq, status=%#08x\n", status); + + if (status & USBA_DET_SUSPEND) { + usba_writel(udc, INT_CLR, USBA_DET_SUSPEND); + DBG(DBG_BUS, "Suspend detected\n"); + if (udc->gadget.speed != USB_SPEED_UNKNOWN + && udc->driver && udc->driver->suspend) { + spin_unlock(&udc->lock); + udc->driver->suspend(&udc->gadget); + spin_lock(&udc->lock); + } + } + + if (status & USBA_WAKE_UP) { + usba_writel(udc, INT_CLR, USBA_WAKE_UP); + DBG(DBG_BUS, "Wake Up CPU detected\n"); + } + + if (status & USBA_END_OF_RESUME) { + usba_writel(udc, INT_CLR, USBA_END_OF_RESUME); + DBG(DBG_BUS, "Resume detected\n"); + if (udc->gadget.speed != USB_SPEED_UNKNOWN + && udc->driver && udc->driver->resume) { + spin_unlock(&udc->lock); + udc->driver->resume(&udc->gadget); + spin_lock(&udc->lock); + } + } + + dma_status = USBA_BFEXT(DMA_INT, status); + if (dma_status) { + int i; + + for (i = 1; i < USBA_NR_ENDPOINTS; i++) + if (dma_status & (1 << i)) + usba_dma_irq(udc, &usba_ep[i]); + } + + ep_status = USBA_BFEXT(EPT_INT, status); + if (ep_status) { + int i; + + for (i = 0; i < USBA_NR_ENDPOINTS; i++) + if (ep_status & (1 << i)) { + if (ep_is_control(&usba_ep[i])) + usba_control_irq(udc, &usba_ep[i]); + else + usba_ep_irq(udc, &usba_ep[i]); + } + } + + if (status & USBA_END_OF_RESET) { + struct usba_ep *ep0; + + usba_writel(udc, INT_CLR, USBA_END_OF_RESET); + reset_all_endpoints(udc); + + if (status & USBA_HIGH_SPEED) { + DBG(DBG_BUS, "High-speed bus reset detected\n"); + udc->gadget.speed = USB_SPEED_HIGH; + } else { + DBG(DBG_BUS, "Full-speed bus reset detected\n"); + udc->gadget.speed = USB_SPEED_FULL; + } + + ep0 = &usba_ep[0]; + ep0->desc = &usba_ep0_desc; + ep0->state = WAIT_FOR_SETUP; + usba_ep_writel(ep0, CFG, + (USBA_BF(EPT_SIZE, EP0_EPT_SIZE) + | USBA_BF(EPT_TYPE, USBA_EPT_TYPE_CONTROL) + | USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE))); + usba_ep_writel(ep0, CTL_ENB, + USBA_EPT_ENABLE | USBA_RX_SETUP); + usba_writel(udc, INT_ENB, + (usba_readl(udc, INT_ENB) + | USBA_BF(EPT_INT, 1) + | USBA_DET_SUSPEND + | USBA_END_OF_RESUME)); + + if (!(usba_ep_readl(ep0, CFG) & USBA_EPT_MAPPED)) + dev_warn(&udc->pdev->dev, + "WARNING: EP0 configuration is invalid!\n"); + } + + spin_unlock(&udc->lock); + + return IRQ_HANDLED; +} + +static irqreturn_t usba_vbus_irq(int irq, void *devid) +{ + struct usba_udc *udc = devid; + int vbus; + + /* debounce */ + udelay(10); + + spin_lock(&udc->lock); + + /* May happen if Vbus pin toggles during probe() */ + if (!udc->driver) + goto out; + + vbus = gpio_get_value(udc->vbus_pin); + if (vbus != udc->vbus_prev) { + if (vbus) { + usba_writel(udc, CTRL, USBA_EN_USBA); + usba_writel(udc, INT_ENB, USBA_END_OF_RESET); + } else { + udc->gadget.speed = USB_SPEED_UNKNOWN; + reset_all_endpoints(udc); + usba_writel(udc, CTRL, 0); + spin_unlock(&udc->lock); + udc->driver->disconnect(&udc->gadget); + spin_lock(&udc->lock); + } + udc->vbus_prev = vbus; + } + +out: + spin_unlock(&udc->lock); + + return IRQ_HANDLED; +} + +int usb_gadget_register_driver(struct usb_gadget_driver *driver) +{ + struct usba_udc *udc = &the_udc; + unsigned long flags; + int ret; + + if (!udc->pdev) + return -ENODEV; + + spin_lock_irqsave(&udc->lock, flags); + if (udc->driver) { + spin_unlock_irqrestore(&udc->lock, flags); + return -EBUSY; + } + + udc->driver = driver; + udc->gadget.dev.driver = &driver->driver; + spin_unlock_irqrestore(&udc->lock, flags); + + clk_enable(udc->pclk); + clk_enable(udc->hclk); + + ret = driver->bind(&udc->gadget); + if (ret) { + DBG(DBG_ERR, "Could not bind to driver %s: error %d\n", + driver->driver.name, ret); + goto err_driver_bind; + } + + DBG(DBG_GADGET, "registered driver `%s'\n", driver->driver.name); + + udc->vbus_prev = 0; + if (udc->vbus_pin != -1) + enable_irq(gpio_to_irq(udc->vbus_pin)); + + /* If Vbus is present, enable the controller and wait for reset */ + spin_lock_irqsave(&udc->lock, flags); + if (vbus_is_present(udc) && udc->vbus_prev == 0) { + usba_writel(udc, CTRL, USBA_EN_USBA); + usba_writel(udc, INT_ENB, USBA_END_OF_RESET); + } + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; + +err_driver_bind: + udc->driver = NULL; + udc->gadget.dev.driver = NULL; + return ret; +} +EXPORT_SYMBOL(usb_gadget_register_driver); + +int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +{ + struct usba_udc *udc = &the_udc; + unsigned long flags; + + if (!udc->pdev) + return -ENODEV; + if (driver != udc->driver) + return -EINVAL; + + if (udc->vbus_pin != -1) + disable_irq(gpio_to_irq(udc->vbus_pin)); + + spin_lock_irqsave(&udc->lock, flags); + udc->gadget.speed = USB_SPEED_UNKNOWN; + reset_all_endpoints(udc); + spin_unlock_irqrestore(&udc->lock, flags); + + /* This will also disable the DP pullup */ + usba_writel(udc, CTRL, 0); + + driver->unbind(&udc->gadget); + udc->gadget.dev.driver = NULL; + udc->driver = NULL; + + clk_disable(udc->hclk); + clk_disable(udc->pclk); + + DBG(DBG_GADGET, "unregistered driver `%s'\n", driver->driver.name); + + return 0; +} +EXPORT_SYMBOL(usb_gadget_unregister_driver); + +static int __init usba_udc_probe(struct platform_device *pdev) +{ + struct usba_platform_data *pdata = pdev->dev.platform_data; + struct resource *regs, *fifo; + struct clk *pclk, *hclk; + struct usba_udc *udc = &the_udc; + int irq, ret, i; + + regs = platform_get_resource(pdev, IORESOURCE_MEM, CTRL_IOMEM_ID); + fifo = platform_get_resource(pdev, IORESOURCE_MEM, FIFO_IOMEM_ID); + if (!regs || !fifo) + return -ENXIO; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + pclk = clk_get(&pdev->dev, "pclk"); + if (IS_ERR(pclk)) + return PTR_ERR(pclk); + hclk = clk_get(&pdev->dev, "hclk"); + if (IS_ERR(hclk)) { + ret = PTR_ERR(hclk); + goto err_get_hclk; + } + + udc->pdev = pdev; + udc->pclk = pclk; + udc->hclk = hclk; + udc->vbus_pin = -1; + + ret = -ENOMEM; + udc->regs = ioremap(regs->start, regs->end - regs->start + 1); + if (!udc->regs) { + dev_err(&pdev->dev, "Unable to map I/O memory, aborting.\n"); + goto err_map_regs; + } + dev_info(&pdev->dev, "MMIO registers at 0x%08lx mapped at %p\n", + (unsigned long)regs->start, udc->regs); + udc->fifo = ioremap(fifo->start, fifo->end - fifo->start + 1); + if (!udc->fifo) { + dev_err(&pdev->dev, "Unable to map FIFO, aborting.\n"); + goto err_map_fifo; + } + dev_info(&pdev->dev, "FIFO at 0x%08lx mapped at %p\n", + (unsigned long)fifo->start, udc->fifo); + + device_initialize(&udc->gadget.dev); + udc->gadget.dev.parent = &pdev->dev; + udc->gadget.dev.dma_mask = pdev->dev.dma_mask; + + platform_set_drvdata(pdev, udc); + + /* Make sure we start from a clean slate */ + clk_enable(pclk); + usba_writel(udc, CTRL, 0); + clk_disable(pclk); + + INIT_LIST_HEAD(&usba_ep[0].ep.ep_list); + usba_ep[0].ep_regs = udc->regs + USBA_EPT_BASE(0); + usba_ep[0].dma_regs = udc->regs + USBA_DMA_BASE(0); + usba_ep[0].fifo = udc->fifo + USBA_FIFO_BASE(0); + for (i = 1; i < ARRAY_SIZE(usba_ep); i++) { + struct usba_ep *ep = &usba_ep[i]; + + ep->ep_regs = udc->regs + USBA_EPT_BASE(i); + ep->dma_regs = udc->regs + USBA_DMA_BASE(i); + ep->fifo = udc->fifo + USBA_FIFO_BASE(i); + + list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); + } + + ret = request_irq(irq, usba_udc_irq, 0, "atmel_usba_udc", udc); + if (ret) { + dev_err(&pdev->dev, "Cannot request irq %d (error %d)\n", + irq, ret); + goto err_request_irq; + } + udc->irq = irq; + + ret = device_add(&udc->gadget.dev); + if (ret) { + dev_dbg(&pdev->dev, "Could not add gadget: %d\n", ret); + goto err_device_add; + } + + if (pdata && pdata->vbus_pin != GPIO_PIN_NONE) { + if (!gpio_request(pdata->vbus_pin, "atmel_usba_udc")) { + udc->vbus_pin = pdata->vbus_pin; + + ret = request_irq(gpio_to_irq(udc->vbus_pin), + usba_vbus_irq, 0, + "atmel_usba_udc", udc); + if (ret) { + gpio_free(udc->vbus_pin); + udc->vbus_pin = -1; + dev_warn(&udc->pdev->dev, + "failed to request vbus irq; " + "assuming always on\n"); + } else { + disable_irq(gpio_to_irq(udc->vbus_pin)); + } + } + } + + usba_init_debugfs(udc); + for (i = 1; i < ARRAY_SIZE(usba_ep); i++) + usba_ep_init_debugfs(udc, &usba_ep[i]); + + return 0; + +err_device_add: + free_irq(irq, udc); +err_request_irq: + iounmap(udc->fifo); +err_map_fifo: + iounmap(udc->regs); +err_map_regs: + clk_put(hclk); +err_get_hclk: + clk_put(pclk); + + platform_set_drvdata(pdev, NULL); + + return ret; +} + +static int __exit usba_udc_remove(struct platform_device *pdev) +{ + struct usba_udc *udc; + int i; + + udc = platform_get_drvdata(pdev); + + for (i = 1; i < ARRAY_SIZE(usba_ep); i++) + usba_ep_cleanup_debugfs(&usba_ep[i]); + usba_cleanup_debugfs(udc); + + if (udc->vbus_pin != -1) + gpio_free(udc->vbus_pin); + + free_irq(udc->irq, udc); + iounmap(udc->fifo); + iounmap(udc->regs); + clk_put(udc->hclk); + clk_put(udc->pclk); + + device_unregister(&udc->gadget.dev); + + return 0; +} + +static struct platform_driver udc_driver = { + .remove = __exit_p(usba_udc_remove), + .driver = { + .name = "atmel_usba_udc", + }, +}; + +static int __init udc_init(void) +{ + return platform_driver_probe(&udc_driver, usba_udc_probe); +} +module_init(udc_init); + +static void __exit udc_exit(void) +{ + platform_driver_unregister(&udc_driver); +} +module_exit(udc_exit); + +MODULE_DESCRIPTION("Atmel USBA UDC driver"); +MODULE_AUTHOR("Haavard Skinnemoen "); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/atmel_usba_udc.h b/drivers/usb/gadget/atmel_usba_udc.h new file mode 100644 index 00000000000..f4f0f8bf812 --- /dev/null +++ b/drivers/usb/gadget/atmel_usba_udc.h @@ -0,0 +1,350 @@ +/* + * Driver for the Atmel USBA high speed USB device controller + * + * Copyright (C) 2005-2007 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __LINUX_USB_GADGET_USBA_UDC_H__ +#define __LINUX_USB_GADGET_USBA_UDC_H__ + +/* USB register offsets */ +#define USBA_CTRL 0x0000 +#define USBA_FNUM 0x0004 +#define USBA_INT_ENB 0x0010 +#define USBA_INT_STA 0x0014 +#define USBA_INT_CLR 0x0018 +#define USBA_EPT_RST 0x001c +#define USBA_TST 0x00e0 + +/* USB endpoint register offsets */ +#define USBA_EPT_CFG 0x0000 +#define USBA_EPT_CTL_ENB 0x0004 +#define USBA_EPT_CTL_DIS 0x0008 +#define USBA_EPT_CTL 0x000c +#define USBA_EPT_SET_STA 0x0014 +#define USBA_EPT_CLR_STA 0x0018 +#define USBA_EPT_STA 0x001c + +/* USB DMA register offsets */ +#define USBA_DMA_NXT_DSC 0x0000 +#define USBA_DMA_ADDRESS 0x0004 +#define USBA_DMA_CONTROL 0x0008 +#define USBA_DMA_STATUS 0x000c + +/* Bitfields in CTRL */ +#define USBA_DEV_ADDR_OFFSET 0 +#define USBA_DEV_ADDR_SIZE 7 +#define USBA_FADDR_EN (1 << 7) +#define USBA_EN_USBA (1 << 8) +#define USBA_DETACH (1 << 9) +#define USBA_REMOTE_WAKE_UP (1 << 10) + +/* Bitfields in FNUM */ +#define USBA_MICRO_FRAME_NUM_OFFSET 0 +#define USBA_MICRO_FRAME_NUM_SIZE 3 +#define USBA_FRAME_NUMBER_OFFSET 3 +#define USBA_FRAME_NUMBER_SIZE 11 +#define USBA_FRAME_NUM_ERROR (1 << 31) + +/* Bitfields in INT_ENB/INT_STA/INT_CLR */ +#define USBA_HIGH_SPEED (1 << 0) +#define USBA_DET_SUSPEND (1 << 1) +#define USBA_MICRO_SOF (1 << 2) +#define USBA_SOF (1 << 3) +#define USBA_END_OF_RESET (1 << 4) +#define USBA_WAKE_UP (1 << 5) +#define USBA_END_OF_RESUME (1 << 6) +#define USBA_UPSTREAM_RESUME (1 << 7) +#define USBA_EPT_INT_OFFSET 8 +#define USBA_EPT_INT_SIZE 16 +#define USBA_DMA_INT_OFFSET 24 +#define USBA_DMA_INT_SIZE 8 + +/* Bitfields in EPT_RST */ +#define USBA_RST_OFFSET 0 +#define USBA_RST_SIZE 16 + +/* Bitfields in USBA_TST */ +#define USBA_SPEED_CFG_OFFSET 0 +#define USBA_SPEED_CFG_SIZE 2 +#define USBA_TST_J_MODE (1 << 2) +#define USBA_TST_K_MODE (1 << 3) +#define USBA_TST_PKT_MODE (1 << 4) +#define USBA_OPMODE2 (1 << 5) + +/* Bitfields in EPT_CFG */ +#define USBA_EPT_SIZE_OFFSET 0 +#define USBA_EPT_SIZE_SIZE 3 +#define USBA_EPT_DIR_IN (1 << 3) +#define USBA_EPT_TYPE_OFFSET 4 +#define USBA_EPT_TYPE_SIZE 2 +#define USBA_BK_NUMBER_OFFSET 6 +#define USBA_BK_NUMBER_SIZE 2 +#define USBA_NB_TRANS_OFFSET 8 +#define USBA_NB_TRANS_SIZE 2 +#define USBA_EPT_MAPPED (1 << 31) + +/* Bitfields in EPT_CTL/EPT_CTL_ENB/EPT_CTL_DIS */ +#define USBA_EPT_ENABLE (1 << 0) +#define USBA_AUTO_VALID (1 << 1) +#define USBA_INTDIS_DMA (1 << 3) +#define USBA_NYET_DIS (1 << 4) +#define USBA_DATAX_RX (1 << 6) +#define USBA_MDATA_RX (1 << 7) +/* Bits 8-15 and 31 enable interrupts for respective bits in EPT_STA */ +#define USBA_BUSY_BANK_IE (1 << 18) + +/* Bitfields in EPT_SET_STA/EPT_CLR_STA/EPT_STA */ +#define USBA_FORCE_STALL (1 << 5) +#define USBA_TOGGLE_CLR (1 << 6) +#define USBA_TOGGLE_SEQ_OFFSET 6 +#define USBA_TOGGLE_SEQ_SIZE 2 +#define USBA_ERR_OVFLW (1 << 8) +#define USBA_RX_BK_RDY (1 << 9) +#define USBA_KILL_BANK (1 << 9) +#define USBA_TX_COMPLETE (1 << 10) +#define USBA_TX_PK_RDY (1 << 11) +#define USBA_ISO_ERR_TRANS (1 << 11) +#define USBA_RX_SETUP (1 << 12) +#define USBA_ISO_ERR_FLOW (1 << 12) +#define USBA_STALL_SENT (1 << 13) +#define USBA_ISO_ERR_CRC (1 << 13) +#define USBA_ISO_ERR_NBTRANS (1 << 13) +#define USBA_NAK_IN (1 << 14) +#define USBA_ISO_ERR_FLUSH (1 << 14) +#define USBA_NAK_OUT (1 << 15) +#define USBA_CURRENT_BANK_OFFSET 16 +#define USBA_CURRENT_BANK_SIZE 2 +#define USBA_BUSY_BANKS_OFFSET 18 +#define USBA_BUSY_BANKS_SIZE 2 +#define USBA_BYTE_COUNT_OFFSET 20 +#define USBA_BYTE_COUNT_SIZE 11 +#define USBA_SHORT_PACKET (1 << 31) + +/* Bitfields in DMA_CONTROL */ +#define USBA_DMA_CH_EN (1 << 0) +#define USBA_DMA_LINK (1 << 1) +#define USBA_DMA_END_TR_EN (1 << 2) +#define USBA_DMA_END_BUF_EN (1 << 3) +#define USBA_DMA_END_TR_IE (1 << 4) +#define USBA_DMA_END_BUF_IE (1 << 5) +#define USBA_DMA_DESC_LOAD_IE (1 << 6) +#define USBA_DMA_BURST_LOCK (1 << 7) +#define USBA_DMA_BUF_LEN_OFFSET 16 +#define USBA_DMA_BUF_LEN_SIZE 16 + +/* Bitfields in DMA_STATUS */ +#define USBA_DMA_CH_ACTIVE (1 << 1) +#define USBA_DMA_END_TR_ST (1 << 4) +#define USBA_DMA_END_BUF_ST (1 << 5) +#define USBA_DMA_DESC_LOAD_ST (1 << 6) + +/* Constants for SPEED_CFG */ +#define USBA_SPEED_CFG_NORMAL 0 +#define USBA_SPEED_CFG_FORCE_HIGH 2 +#define USBA_SPEED_CFG_FORCE_FULL 3 + +/* Constants for EPT_SIZE */ +#define USBA_EPT_SIZE_8 0 +#define USBA_EPT_SIZE_16 1 +#define USBA_EPT_SIZE_32 2 +#define USBA_EPT_SIZE_64 3 +#define USBA_EPT_SIZE_128 4 +#define USBA_EPT_SIZE_256 5 +#define USBA_EPT_SIZE_512 6 +#define USBA_EPT_SIZE_1024 7 + +/* Constants for EPT_TYPE */ +#define USBA_EPT_TYPE_CONTROL 0 +#define USBA_EPT_TYPE_ISO 1 +#define USBA_EPT_TYPE_BULK 2 +#define USBA_EPT_TYPE_INT 3 + +/* Constants for BK_NUMBER */ +#define USBA_BK_NUMBER_ZERO 0 +#define USBA_BK_NUMBER_ONE 1 +#define USBA_BK_NUMBER_DOUBLE 2 +#define USBA_BK_NUMBER_TRIPLE 3 + +/* Bit manipulation macros */ +#define USBA_BF(name, value) \ + (((value) & ((1 << USBA_##name##_SIZE) - 1)) \ + << USBA_##name##_OFFSET) +#define USBA_BFEXT(name, value) \ + (((value) >> USBA_##name##_OFFSET) \ + & ((1 << USBA_##name##_SIZE) - 1)) +#define USBA_BFINS(name, value, old) \ + (((old) & ~(((1 << USBA_##name##_SIZE) - 1) \ + << USBA_##name##_OFFSET)) \ + | USBA_BF(name, value)) + +/* Register access macros */ +#define usba_readl(udc, reg) \ + __raw_readl((udc)->regs + USBA_##reg) +#define usba_writel(udc, reg, value) \ + __raw_writel((value), (udc)->regs + USBA_##reg) +#define usba_ep_readl(ep, reg) \ + __raw_readl((ep)->ep_regs + USBA_EPT_##reg) +#define usba_ep_writel(ep, reg, value) \ + __raw_writel((value), (ep)->ep_regs + USBA_EPT_##reg) +#define usba_dma_readl(ep, reg) \ + __raw_readl((ep)->dma_regs + USBA_DMA_##reg) +#define usba_dma_writel(ep, reg, value) \ + __raw_writel((value), (ep)->dma_regs + USBA_DMA_##reg) + +/* Calculate base address for a given endpoint or DMA controller */ +#define USBA_EPT_BASE(x) (0x100 + (x) * 0x20) +#define USBA_DMA_BASE(x) (0x300 + (x) * 0x10) +#define USBA_FIFO_BASE(x) ((x) << 16) + +/* Synth parameters */ +#define USBA_NR_ENDPOINTS 7 + +#define EP0_FIFO_SIZE 64 +#define EP0_EPT_SIZE USBA_EPT_SIZE_64 +#define EP0_NR_BANKS 1 + +/* + * REVISIT: Try to eliminate this value. Can we rely on req->mapped to + * provide this information? + */ +#define DMA_ADDR_INVALID (~(dma_addr_t)0) + +#define FIFO_IOMEM_ID 0 +#define CTRL_IOMEM_ID 1 + +#ifdef DEBUG +#define DBG_ERR 0x0001 /* report all error returns */ +#define DBG_HW 0x0002 /* debug hardware initialization */ +#define DBG_GADGET 0x0004 /* calls to/from gadget driver */ +#define DBG_INT 0x0008 /* interrupts */ +#define DBG_BUS 0x0010 /* report changes in bus state */ +#define DBG_QUEUE 0x0020 /* debug request queue processing */ +#define DBG_FIFO 0x0040 /* debug FIFO contents */ +#define DBG_DMA 0x0080 /* debug DMA handling */ +#define DBG_REQ 0x0100 /* print out queued request length */ +#define DBG_ALL 0xffff +#define DBG_NONE 0x0000 + +#define DEBUG_LEVEL (DBG_ERR) +#define DBG(level, fmt, ...) \ + do { \ + if ((level) & DEBUG_LEVEL) \ + printk(KERN_DEBUG "udc: " fmt, ## __VA_ARGS__); \ + } while (0) +#else +#define DBG(level, fmt...) +#endif + +enum usba_ctrl_state { + WAIT_FOR_SETUP, + DATA_STAGE_IN, + DATA_STAGE_OUT, + STATUS_STAGE_IN, + STATUS_STAGE_OUT, + STATUS_STAGE_ADDR, + STATUS_STAGE_TEST, +}; +/* + EP_STATE_IDLE, + EP_STATE_SETUP, + EP_STATE_IN_DATA, + EP_STATE_OUT_DATA, + EP_STATE_SET_ADDR_STATUS, + EP_STATE_RX_STATUS, + EP_STATE_TX_STATUS, + EP_STATE_HALT, +*/ + +struct usba_dma_desc { + dma_addr_t next; + dma_addr_t addr; + u32 ctrl; +}; + +struct usba_ep { + int state; + void __iomem *ep_regs; + void __iomem *dma_regs; + void __iomem *fifo; + struct usb_ep ep; + struct usba_udc *udc; + + struct list_head queue; + const struct usb_endpoint_descriptor *desc; + + u16 fifo_size; + u8 nr_banks; + u8 index; + unsigned int can_dma:1; + unsigned int can_isoc:1; + unsigned int is_isoc:1; + unsigned int is_in:1; + +#ifdef CONFIG_USB_GADGET_DEBUG_FS + u32 last_dma_status; + struct dentry *debugfs_dir; + struct dentry *debugfs_queue; + struct dentry *debugfs_dma_status; + struct dentry *debugfs_state; +#endif +}; + +struct usba_request { + struct usb_request req; + struct list_head queue; + + u32 ctrl; + + unsigned int submitted:1; + unsigned int last_transaction:1; + unsigned int using_dma:1; + unsigned int mapped:1; +}; + +struct usba_udc { + /* Protect hw registers from concurrent modifications */ + spinlock_t lock; + + void __iomem *regs; + void __iomem *fifo; + + struct usb_gadget gadget; + struct usb_gadget_driver *driver; + struct platform_device *pdev; + int irq; + int vbus_pin; + struct clk *pclk; + struct clk *hclk; + + int test_mode; + int vbus_prev; + +#ifdef CONFIG_USB_GADGET_DEBUG_FS + struct dentry *debugfs_root; + struct dentry *debugfs_regs; +#endif +}; + +static inline struct usba_ep *to_usba_ep(struct usb_ep *ep) +{ + return container_of(ep, struct usba_ep, ep); +} + +static inline struct usba_request *to_usba_req(struct usb_request *req) +{ + return container_of(req, struct usba_request, req); +} + +static inline struct usba_udc *to_usba_udc(struct usb_gadget *gadget) +{ + return container_of(gadget, struct usba_udc, gadget); +} + +#define ep_is_control(ep) ((ep)->index == 0) +#define ep_is_idle(ep) ((ep)->state == EP_STATE_IDLE) + +#endif /* __LINUX_USB_GADGET_USBA_UDC_H */ -- cgit v1.2.3-70-g09d2 From eecfb911a03a48ef5f7114246343128bd01c1b5f Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Thu, 11 Oct 2007 00:37:50 +0900 Subject: USB: Adding support for SHARP WS011SH to ipaq.c This patch supports for SHARP WS011SH[0] to ipaq.c [0]: http://www.willcom-inc.com/ja/lineup/ws/011sh/index.html (Sorry , Japanese only.) Signed-off-by: Nobuhiro Iwamatsu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ipaq.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index c1a6484f652..e836ad07fdb 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -256,6 +256,7 @@ static struct usb_device_id ipaq_id_table [] = { { USB_DEVICE(0x04DD, 0x9121) }, /* SHARP WS004SH USB Modem */ { USB_DEVICE(0x04DD, 0x9123) }, /* SHARP WS007SH USB Modem */ { USB_DEVICE(0x04DD, 0x9151) }, /* SHARP S01SH USB Modem */ + { USB_DEVICE(0x04DD, 0x91AC) }, /* SHARP WS011SH USB Modem */ { USB_DEVICE(0x04E8, 0x5F00) }, /* Samsung NEXiO USB Sync */ { USB_DEVICE(0x04E8, 0x5F01) }, /* Samsung NEXiO USB Sync */ { USB_DEVICE(0x04E8, 0x5F02) }, /* Samsung NEXiO USB Sync */ -- cgit v1.2.3-70-g09d2 From 17f060224fb9f435c6f9306b7b61419d038def13 Mon Sep 17 00:00:00 2001 From: Richard Sharpe Date: Wed, 10 Oct 2007 10:56:28 -0700 Subject: USB: allow usbstorage to have LUNS greater than 2Tb Attached is a very small patch (several comment lines) and a one-line coded change) that allows for USB storage devices that are larger than 2TB. At the company where I work we need such support, and one of my co-workers, Jane Liu, pointed out that SCSI low-layer drivers need to specify what size CDBs they accept. After looking through the code it became obvious that the current USB Storage code accepted the default of 12-byte CDBs, so I changed it to accept 16-byte CDBs. This allows our device to work. Signed-off-by: Richard Sharpe Signed-off-by: Matthew Dharm Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/usb.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 59181667066..3451e8d03ab 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -960,6 +960,10 @@ static int storage_probe(struct usb_interface *intf, return -ENOMEM; } + /* + * Allow 16-byte CDBs and thus > 2TB + */ + host->max_cmd_len = 16; us = host_to_us(host); memset(us, 0, sizeof(struct us_data)); mutex_init(&(us->dev_mutex)); -- cgit v1.2.3-70-g09d2 From 32fe01985aa2cb2562f6fc171e526e279abe10db Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 10 Oct 2007 16:27:07 -0400 Subject: USB: mutual exclusion for EHCI init and port resets This patch (as999) fixes a problem that sometimes shows up when host controller driver modules are loaded in the wrong order. If ehci-hcd happens to initialize an EHCI controller while the companion OHCI or UHCI controller is in the middle of a port reset, the reset can fail and the companion may get very confused. The patch adds an rw-semaphore and uses it to keep EHCI initialization and port resets mutually exclusive. Signed-off-by: Alan Stern Acked-by: David Brownell Cc: David Miller Cc: Dely L Sy Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.h | 8 +++++++- drivers/usb/core/hub.c | 15 ++++++++++++++- drivers/usb/host/ehci-hcd.c | 8 ++++++++ 3 files changed, 29 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 1396141274f..98e24194a4a 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -19,6 +19,8 @@ #ifdef __KERNEL__ +#include + /* This file contains declarations of usbcore internals that are mostly * used or exposed by Host Controller Drivers. */ @@ -470,5 +472,9 @@ static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb, : (in_interrupt () ? "in_interrupt" : "can sleep")) -#endif /* __KERNEL__ */ +/* This rwsem is for use only by the hub driver and ehci-hcd. + * Nobody else should touch it. + */ +extern struct rw_semaphore ehci_cf_port_reset_rwsem; +#endif /* __KERNEL__ */ diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 481dca641ea..d20cb545a6e 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -125,6 +125,12 @@ MODULE_PARM_DESC(use_both_schemes, "try the other device initialization scheme if the " "first one fails"); +/* Mutual exclusion for EHCI CF initialization. This interferes with + * port reset on some companion controllers. + */ +DECLARE_RWSEM(ehci_cf_port_reset_rwsem); +EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem); + static inline char *portspeed(int portstatus) { @@ -1581,6 +1587,11 @@ static int hub_port_reset(struct usb_hub *hub, int port1, { int i, status; + /* Block EHCI CF initialization during the port reset. + * Some companion controllers don't like it when they mix. + */ + down_read(&ehci_cf_port_reset_rwsem); + /* Reset the port */ for (i = 0; i < PORT_RESET_TRIES; i++) { status = set_port_feature(hub->hdev, @@ -1612,7 +1623,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1, usb_set_device_state(udev, status ? USB_STATE_NOTATTACHED : USB_STATE_DEFAULT); - return status; + goto done; } dev_dbg (hub->intfdev, @@ -1625,6 +1636,8 @@ static int hub_port_reset(struct usb_hub *hub, int port1, "Cannot enable port %i. Maybe the USB cable is bad?\n", port1); + done: + up_read(&ehci_cf_port_reset_rwsem); return status; } diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index db00492588b..c1514442883 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -570,10 +570,18 @@ static int ehci_run (struct usb_hcd *hcd) * are explicitly handed to companion controller(s), so no TT is * involved with the root hub. (Except where one is integrated, * and there's no companion controller unless maybe for USB OTG.) + * + * Turning on the CF flag will transfer ownership of all ports + * from the companions to the EHCI controller. If any of the + * companions are in the middle of a port reset at the time, it + * could cause trouble. Write-locking ehci_cf_port_reset_rwsem + * guarantees that no resets are in progress. */ + down_write(&ehci_cf_port_reset_rwsem); hcd->state = HC_STATE_RUNNING; ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag); ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */ + up_write(&ehci_cf_port_reset_rwsem); temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase)); ehci_info (ehci, -- cgit v1.2.3-70-g09d2 From 271f9e68f3450ac8d1ff3bda36581f1ec0d0cc1f Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 10 Oct 2007 16:30:12 -0400 Subject: USB: skip autosuspended devices during system resume System suspends and hibernation are supposed to be as transparent as possible. By this reasoning, if a USB device is already autosuspended before the system sleep begins then it should remain autosuspended after the system wakes up. This patch (as1001) adds a skip_sys_resume flag to the usb_device structure and uses it to avoid waking up devices which were suspended when a system sleep began. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/driver.c | 27 ++++++++++++++++++++------- include/linux/usb.h | 1 + 2 files changed, 21 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 3f734240e0e..8c1eac27f2d 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1540,9 +1540,21 @@ int usb_external_resume_device(struct usb_device *udev) static int usb_suspend(struct device *dev, pm_message_t message) { + struct usb_device *udev; + if (!is_usb_device(dev)) /* Ignore PM for interfaces */ return 0; - return usb_external_suspend_device(to_usb_device(dev), message); + udev = to_usb_device(dev); + + /* If udev is already suspended, we can skip this suspend and + * we should also skip the upcoming system resume. */ + if (udev->state == USB_STATE_SUSPENDED) { + udev->skip_sys_resume = 1; + return 0; + } + + udev->skip_sys_resume = 0; + return usb_external_suspend_device(udev, message); } static int usb_resume(struct device *dev) @@ -1553,13 +1565,14 @@ static int usb_resume(struct device *dev) return 0; udev = to_usb_device(dev); - /* If autoresume is disabled then we also want to prevent resume - * during system wakeup. However, a "persistent-device" reset-resume - * after power loss counts as a wakeup event. So allow a - * reset-resume to occur if remote wakeup is enabled. */ - if (udev->autoresume_disabled) { + /* If udev->skip_sys_resume is set then udev was already suspended + * when the system suspend started, so we don't want to resume + * udev during this system wakeup. However a reset-resume counts + * as a wakeup event, so allow a reset-resume to occur if remote + * wakeup is enabled. */ + if (udev->skip_sys_resume) { if (!(udev->reset_resume && udev->do_remote_wakeup)) - return -EPERM; + return -EHOSTUNREACH; } return usb_external_resume_device(udev); } diff --git a/include/linux/usb.h b/include/linux/usb.h index c10935fdc03..c5c8f169d3c 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -430,6 +430,7 @@ struct usb_device { unsigned persist_enabled:1; /* USB_PERSIST enabled for this dev */ unsigned autosuspend_disabled:1; /* autosuspend and autoresume */ unsigned autoresume_disabled:1; /* disabled by the user */ + unsigned skip_sys_resume:1; /* skip the next system resume */ #endif }; #define to_usb_device(d) container_of(d, struct usb_device, dev) -- cgit v1.2.3-70-g09d2 From 063a2da8f01806906f7d7b1a1424b9afddebc443 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 10 Oct 2007 16:24:06 -0400 Subject: USB: serial core should respect driver requirements This patch (as997) fixes a bug in the USB serial core. The core needs to pay attention to drivers' requirements regarding the number and type of endpoints a device has. At the same time, the patch changes the NUM_DONT_CARE constant (which is stored in a single-byte field) from -1 to a safer, unsigned value. It also improves the kerneldoc for several fields in the usb_serial_driver structure. Finally, the patch replaces a list_for_each() with list_for_each_entry(). Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/usb-serial.c | 31 ++++++++++++++++++++++--------- include/linux/usb/serial.h | 20 +++++++++++++------- 2 files changed, 35 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 26e015c39a3..4b1bd7def4a 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -662,16 +662,14 @@ exit: static struct usb_serial_driver *search_serial_device(struct usb_interface *iface) { - struct list_head *p; const struct usb_device_id *id; - struct usb_serial_driver *t; + struct usb_serial_driver *drv; /* Check if the usb id matches a known device */ - list_for_each(p, &usb_serial_driver_list) { - t = list_entry(p, struct usb_serial_driver, driver_list); - id = get_iface_id(t, iface); + list_for_each_entry(drv, &usb_serial_driver_list, driver_list) { + id = get_iface_id(drv, iface); if (id) - return t; + return drv; } return NULL; @@ -811,9 +809,6 @@ int usb_serial_probe(struct usb_interface *interface, /* END HORRIBLE HACK FOR PL2303 */ #endif - /* found all that we need */ - dev_info(&interface->dev, "%s converter detected\n", type->description); - #ifdef CONFIG_USB_SERIAL_GENERIC if (type == &usb_serial_generic_device) { num_ports = num_bulk_out; @@ -847,6 +842,24 @@ int usb_serial_probe(struct usb_interface *interface, serial->num_interrupt_in = num_interrupt_in; serial->num_interrupt_out = num_interrupt_out; + /* check that the device meets the driver's requirements */ + if ((type->num_interrupt_in != NUM_DONT_CARE && + type->num_interrupt_in != num_interrupt_in) + || (type->num_interrupt_out != NUM_DONT_CARE && + type->num_interrupt_out != num_interrupt_out) + || (type->num_bulk_in != NUM_DONT_CARE && + type->num_bulk_in != num_bulk_in) + || (type->num_bulk_out != NUM_DONT_CARE && + type->num_bulk_out != num_bulk_out)) { + dbg("wrong number of endpoints"); + kfree(serial); + return -EIO; + } + + /* found all that we need */ + dev_info(&interface->dev, "%s converter detected\n", + type->description); + /* create our ports, we need as many as the max endpoints */ /* we don't use num_ports here cauz some devices have more endpoint pairs than ports */ max_endpoints = max(num_bulk_in, num_bulk_out); diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h index e8b8928232c..488ce128885 100644 --- a/include/linux/usb/serial.h +++ b/include/linux/usb/serial.h @@ -141,7 +141,7 @@ struct usb_serial { }; #define to_usb_serial(d) container_of(d, struct usb_serial, kref) -#define NUM_DONT_CARE (-1) +#define NUM_DONT_CARE 99 /* get and set the serial private data pointer helper functions */ static inline void *usb_get_serial_data (struct usb_serial *serial) @@ -160,12 +160,18 @@ static inline void usb_set_serial_data (struct usb_serial *serial, void *data) * in the syslog messages when a device is inserted or removed. * @id_table: pointer to a list of usb_device_id structures that define all * of the devices this structure can support. - * @num_interrupt_in: the number of interrupt in endpoints this device will - * have. - * @num_interrupt_out: the number of interrupt out endpoints this device will - * have. - * @num_bulk_in: the number of bulk in endpoints this device will have. - * @num_bulk_out: the number of bulk out endpoints this device will have. + * @num_interrupt_in: If a device doesn't have this many interrupt-in + * endpoints, it won't be sent to the driver's attach() method. + * (But it might still be sent to the probe() method.) + * @num_interrupt_out: If a device doesn't have this many interrupt-out + * endpoints, it won't be sent to the driver's attach() method. + * (But it might still be sent to the probe() method.) + * @num_bulk_in: If a device doesn't have this many bulk-in + * endpoints, it won't be sent to the driver's attach() method. + * (But it might still be sent to the probe() method.) + * @num_bulk_out: If a device doesn't have this many bulk-out + * endpoints, it won't be sent to the driver's attach() method. + * (But it might still be sent to the probe() method.) * @num_ports: the number of different ports this device will have. * @calc_num_ports: pointer to a function to determine how many ports this * device has dynamically. It will be called after the probe() -- cgit v1.2.3-70-g09d2 From d466a9190ff1ceddfee50686e61d63590fc820d9 Mon Sep 17 00:00:00 2001 From: Ortwin Glück Date: Thu, 11 Oct 2007 17:29:43 +0200 Subject: USB: Nikon D40X unusual_devs entry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not surprisingly the Nikon D40X DSC needs the same quirks as the D40, but it has a separate ID. See http://bugs.gentoo.org/show_bug.cgi?id=191431 From: Ortwin Glück Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index edf92914674..9b656ec427d 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -369,6 +369,13 @@ UNUSUAL_DEV( 0x04b0, 0x0415, 0x0100, 0x0100, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_CAPACITY), +/* Reported by Shan Destromp (shansan@gmail.com) */ +UNUSUAL_DEV( 0x04b0, 0x0417, 0x0100, 0x0100, + "NIKON", + "NIKON DSC D40X", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY), + /* BENQ DC5330 * Reported by Manuel Fombuena and * Frank Copeland */ -- cgit v1.2.3-70-g09d2 From 58ed7b94d98245fbad54a0af7ea3317ab1dd6876 Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Thu, 11 Oct 2007 13:40:30 -0700 Subject: atmel_usba_udc: Keep track of the device status Keep track of the device status (as returned by the GET_STATUS request) and allow it to be manipulated by set_selfpowered() as well as SET_FEATURE/CLEAR_FEATURE (for remote wakeup) Implement the wakeup() op, which refuses to do anything if the DEVICE_REMOTE_WAKEUP feature wasn't set by the host. Now this driver passes USBCV (at least, with gadget zero). Fix one more locking bug; lockdep is every developer's friend. Signed-off-by: Haavard Skinnemoen Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/atmel_usba_udc.c | 57 +++++++++++++++++++++++++++++++------ drivers/usb/gadget/atmel_usba_udc.h | 4 ++- 2 files changed, 51 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index 2bb28a58393..4fb5ff46957 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -989,8 +989,44 @@ static int usba_udc_get_frame(struct usb_gadget *gadget) return USBA_BFEXT(FRAME_NUMBER, usba_readl(udc, FNUM)); } +static int usba_udc_wakeup(struct usb_gadget *gadget) +{ + struct usba_udc *udc = to_usba_udc(gadget); + unsigned long flags; + u32 ctrl; + int ret = -EINVAL; + + spin_lock_irqsave(&udc->lock, flags); + if (udc->devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) { + ctrl = usba_readl(udc, CTRL); + usba_writel(udc, CTRL, ctrl | USBA_REMOTE_WAKE_UP); + ret = 0; + } + spin_unlock_irqrestore(&udc->lock, flags); + + return ret; +} + +static int +usba_udc_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered) +{ + struct usba_udc *udc = to_usba_udc(gadget); + unsigned long flags; + + spin_lock_irqsave(&udc->lock, flags); + if (is_selfpowered) + udc->devstatus |= 1 << USB_DEVICE_SELF_POWERED; + else + udc->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED); + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + static const struct usb_gadget_ops usba_udc_ops = { - .get_frame = usba_udc_get_frame, + .get_frame = usba_udc_get_frame, + .wakeup = usba_udc_wakeup, + .set_selfpowered = usba_udc_set_selfpowered, }; #define EP(nam, idx, maxpkt, maxbk, dma, isoc) \ @@ -1068,8 +1104,11 @@ static void reset_all_endpoints(struct usba_udc *udc) } list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) { - if (ep->desc) + if (ep->desc) { + spin_unlock(&udc->lock); usba_ep_disable(&ep->ep); + spin_lock(&udc->lock); + } } } @@ -1238,8 +1277,7 @@ static int handle_ep0_setup(struct usba_udc *udc, struct usba_ep *ep, u16 status; if (crq->bRequestType == (USB_DIR_IN | USB_RECIP_DEVICE)) { - /* Self-powered, no remote wakeup */ - status = __constant_cpu_to_le16(1 << 0); + status = cpu_to_le16(udc->devstatus); } else if (crq->bRequestType == (USB_DIR_IN | USB_RECIP_INTERFACE)) { status = __constant_cpu_to_le16(0); @@ -1268,12 +1306,12 @@ static int handle_ep0_setup(struct usba_udc *udc, struct usba_ep *ep, case USB_REQ_CLEAR_FEATURE: { if (crq->bRequestType == USB_RECIP_DEVICE) { - if (feature_is_dev_remote_wakeup(crq)) { - /* TODO: Handle REMOTE_WAKEUP */ - } else { + if (feature_is_dev_remote_wakeup(crq)) + udc->devstatus + &= ~(1 << USB_DEVICE_REMOTE_WAKEUP); + else /* Can't CLEAR_FEATURE TEST_MODE */ goto stall; - } } else if (crq->bRequestType == USB_RECIP_ENDPOINT) { struct usba_ep *target; @@ -1304,7 +1342,7 @@ static int handle_ep0_setup(struct usba_udc *udc, struct usba_ep *ep, udc->test_mode = le16_to_cpu(crq->wIndex); return 0; } else if (feature_is_dev_remote_wakeup(crq)) { - /* TODO: Handle REMOTE_WAKEUP */ + udc->devstatus |= 1 << USB_DEVICE_REMOTE_WAKEUP; } else { goto stall; } @@ -1791,6 +1829,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) return -EBUSY; } + udc->devstatus = 1 << USB_DEVICE_SELF_POWERED; udc->driver = driver; udc->gadget.dev.driver = &driver->driver; spin_unlock_irqrestore(&udc->lock, flags); diff --git a/drivers/usb/gadget/atmel_usba_udc.h b/drivers/usb/gadget/atmel_usba_udc.h index f4f0f8bf812..a68304e31a6 100644 --- a/drivers/usb/gadget/atmel_usba_udc.h +++ b/drivers/usb/gadget/atmel_usba_udc.h @@ -320,7 +320,9 @@ struct usba_udc { struct clk *pclk; struct clk *hclk; - int test_mode; + u16 devstatus; + + u16 test_mode; int vbus_prev; #ifdef CONFIG_USB_GADGET_DEBUG_FS -- cgit v1.2.3-70-g09d2 From d1aa3e6aa8edfeb864af7c930523d9e588b28bea Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 11 Oct 2007 16:47:36 -0400 Subject: USB: fix race in autosuspend reschedule This patch (as1002) fixes a small race which can occur when a driver expects usbcore to reschedule an autosuspend request. If the request arrives too late, it won't be rescheduled. The patch adds an extra argument to autosuspend_check(), indicating that a reschedule is needed no matter how much time has elapsed. It also tries to avoid letting asynchronous changes to the value of jiffies cause a delay to become negative, by caching a local copy of the current time. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/driver.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 8c1eac27f2d..c27bc080d84 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -950,11 +950,11 @@ done: #ifdef CONFIG_USB_SUSPEND /* Internal routine to check whether we may autosuspend a device. */ -static int autosuspend_check(struct usb_device *udev) +static int autosuspend_check(struct usb_device *udev, int reschedule) { int i; struct usb_interface *intf; - unsigned long suspend_time; + unsigned long suspend_time, j; /* For autosuspend, fail fast if anything is in use or autosuspend * is disabled. Also fail if any interfaces require remote wakeup @@ -996,20 +996,20 @@ static int autosuspend_check(struct usb_device *udev) } /* If everything is okay but the device hasn't been idle for long - * enough, queue a delayed autosuspend request. + * enough, queue a delayed autosuspend request. If the device + * _has_ been idle for long enough and the reschedule flag is set, + * likewise queue a delayed (1 second) autosuspend request. */ - if (time_after(suspend_time, jiffies)) { + j = jiffies; + if (time_before(j, suspend_time)) + reschedule = 1; + else + suspend_time = j + HZ; + if (reschedule) { if (!timer_pending(&udev->autosuspend.timer)) { - - /* The value of jiffies may change between the - * time_after() comparison above and the subtraction - * below. That's okay; the system behaves sanely - * when a timer is registered for the present moment - * or for the past. - */ queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend, - round_jiffies_relative(suspend_time - jiffies)); - } + round_jiffies_relative(suspend_time - j)); + } return -EAGAIN; } return 0; @@ -1017,7 +1017,7 @@ static int autosuspend_check(struct usb_device *udev) #else -static inline int autosuspend_check(struct usb_device *udev) +static inline int autosuspend_check(struct usb_device *udev, int reschedule) { return 0; } @@ -1074,7 +1074,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) udev->do_remote_wakeup = device_may_wakeup(&udev->dev); if (udev->auto_pm) { - status = autosuspend_check(udev); + status = autosuspend_check(udev, 0); if (status < 0) goto done; } @@ -1100,7 +1100,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) /* Try another autosuspend when the interfaces aren't busy */ if (udev->auto_pm) - autosuspend_check(udev); + autosuspend_check(udev, status == -EBUSY); /* If the suspend succeeded then prevent any more URB submissions, * flush any outstanding URBs, and propagate the suspend up the tree. -- cgit v1.2.3-70-g09d2 From 73a985a140cd0f1b17fa1438af0359d6b9b32b16 Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Tue, 31 Jul 2007 19:14:28 +0200 Subject: PCI Hotplug: cpqphp_ctrl.c: kmalloc + memset conversion to kzalloc drivers/pci/hotplug/cpqphp_ctrl.c | 79698 -> 79638 (-60 bytes) drivers/pci/hotplug/cpqphp_ctrl.o | 192896 -> 192736 (-160 bytes) Signed-off-by: Mariusz Kozlowski Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/cpqphp_ctrl.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/hotplug/cpqphp_ctrl.c b/drivers/pci/hotplug/cpqphp_ctrl.c index 37d72f123a8..dcafa2aaef8 100644 --- a/drivers/pci/hotplug/cpqphp_ctrl.c +++ b/drivers/pci/hotplug/cpqphp_ctrl.c @@ -973,16 +973,13 @@ struct pci_func *cpqhp_slot_create(u8 busnumber) struct pci_func *new_slot; struct pci_func *next; - new_slot = kmalloc(sizeof(*new_slot), GFP_KERNEL); - + new_slot = kzalloc(sizeof(*new_slot), GFP_KERNEL); if (new_slot == NULL) { /* I'm not dead yet! * You will be. */ return new_slot; } - memset(new_slot, 0, sizeof(struct pci_func)); - new_slot->next = NULL; new_slot->configured = 1; -- cgit v1.2.3-70-g09d2 From 89913bf77a60fdb6ff204a670d3e191848a7b2c8 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Thu, 9 Aug 2007 16:09:30 -0700 Subject: pciehp: remove CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE Remove unnecessary CONFIG_HOTPLUG_PCI_PCIE_EVENT_MODE. The CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE option is not needed because polling mechanism can be enabled through 'pciehp_poll_mode' module option. Signed-off-by: Kenji Kaneshige Signed-off-by: Kristen Carlson Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/pciehp_core.c | 4 ---- drivers/pci/pcie/Kconfig | 9 --------- 2 files changed, 13 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index e5d3f0b4f45..3d692a97121 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -540,10 +540,6 @@ static int __init pcied_init(void) { int retval = 0; -#ifdef CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE - pciehp_poll_mode = 1; -#endif - retval = pcie_port_service_register(&hpdriver_portdrv); dbg("pcie_port_service_register = %d\n", retval); info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig index 0ad92a8ad8b..287a9311716 100644 --- a/drivers/pci/pcie/Kconfig +++ b/drivers/pci/pcie/Kconfig @@ -25,13 +25,4 @@ config HOTPLUG_PCI_PCIE When in doubt, say N. -config HOTPLUG_PCI_PCIE_POLL_EVENT_MODE - bool "Use polling mechanism for hot-plug events (for testing purpose)" - depends on HOTPLUG_PCI_PCIE - help - Say Y here if you want to use the polling mechanism for hot-plug - events for early platform testing. - - When in doubt, say N. - source "drivers/pci/pcie/aer/Kconfig" -- cgit v1.2.3-70-g09d2 From 1cf53d5ddb93b77ce1e277da85fe695e4c2a667d Mon Sep 17 00:00:00 2001 From: Kristen Carlson Accardi Date: Thu, 9 Aug 2007 16:09:31 -0700 Subject: PCI Hotplug: pciehp: Dont check bridge control on remove When removing a device with a bridge on it, only read the bridge control register if the adapter is actually present. Signed-off-by: Kristen Carlson Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/pciehp_pci.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c index 854aaea09e4..8f2b25c49f8 100644 --- a/drivers/pci/hotplug/pciehp_pci.c +++ b/drivers/pci/hotplug/pciehp_pci.c @@ -243,9 +243,10 @@ int pciehp_configure_device(struct slot *p_slot) int pciehp_unconfigure_device(struct slot *p_slot) { - int rc = 0; + int ret, rc = 0; int j; u8 bctl = 0; + u8 presence = 0; struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate; dbg("%s: bus/dev = %x/%x\n", __FUNCTION__, p_slot->bus, @@ -263,12 +264,17 @@ int pciehp_unconfigure_device(struct slot *p_slot) continue; } if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE) { - pci_read_config_byte(temp, PCI_BRIDGE_CONTROL, &bctl); - if (bctl & PCI_BRIDGE_CTL_VGA) { - err("Cannot remove display device %s\n", + ret = p_slot->hpc_ops->get_adapter_status(p_slot, + &presence); + if (!ret && presence) { + pci_read_config_byte(temp, PCI_BRIDGE_CONTROL, + &bctl); + if (bctl & PCI_BRIDGE_CTL_VGA) { + err("Cannot remove display device %s\n", pci_name(temp)); - pci_dev_put(temp); - continue; + pci_dev_put(temp); + continue; + } } } pci_remove_bus_device(temp); -- cgit v1.2.3-70-g09d2 From 57d90c027641169b0724f94d355704e28895bcd6 Mon Sep 17 00:00:00 2001 From: Kristen Carlson Accardi Date: Thu, 9 Aug 2007 16:09:32 -0700 Subject: PCI Hotplug: pciehp: Request control over PCI Express Capability as well as Native hotplug According to the PCI firmware spec (3.0), the OS must claim control over the PCI Express Capability bits in addition to the PCI Express Native Hot Plug feature when executing _OSC. Signed-off-by: Kristen Carlson Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/pciehp_hpc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 016eea94a8a..dbd04660bab 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -1138,6 +1138,7 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev) dbg("Trying to get hotplug control for %s \n", (char *)string.pointer); status = pci_osc_control_set(handle, + OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL | OSC_PCI_EXPRESS_NATIVE_HP_CONTROL); if (status == AE_NOT_FOUND) status = acpi_run_oshp(handle); -- cgit v1.2.3-70-g09d2 From c8426483776d913c5bdc3d698a7633496a885b78 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Thu, 9 Aug 2007 16:09:33 -0700 Subject: pciehp: remove DBG_XXX_ROUTINE This patch removes DBG_ENTER_ROUTIN, DBG_LEAVE_ROUTINE and related code, which seem no longer needed. Signed-off-by: Kenji Kaneshige Signed-off-by: Kristen Carlson Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/pciehp_hpc.c | 111 ++------------------------------------- 1 file changed, 5 insertions(+), 106 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index dbd04660bab..f6143175de7 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -39,37 +39,6 @@ #include "../pci.h" #include "pciehp.h" -#ifdef DEBUG -#define DBG_K_TRACE_ENTRY ((unsigned int)0x00000001) /* On function entry */ -#define DBG_K_TRACE_EXIT ((unsigned int)0x00000002) /* On function exit */ -#define DBG_K_INFO ((unsigned int)0x00000004) /* Info messages */ -#define DBG_K_ERROR ((unsigned int)0x00000008) /* Error messages */ -#define DBG_K_TRACE (DBG_K_TRACE_ENTRY|DBG_K_TRACE_EXIT) -#define DBG_K_STANDARD (DBG_K_INFO|DBG_K_ERROR|DBG_K_TRACE) -/* Redefine this flagword to set debug level */ -#define DEBUG_LEVEL DBG_K_STANDARD - -#define DEFINE_DBG_BUFFER char __dbg_str_buf[256]; - -#define DBG_PRINT( dbg_flags, args... ) \ - do { \ - if ( DEBUG_LEVEL & ( dbg_flags ) ) \ - { \ - int len; \ - len = sprintf( __dbg_str_buf, "%s:%d: %s: ", \ - __FILE__, __LINE__, __FUNCTION__ ); \ - sprintf( __dbg_str_buf + len, args ); \ - printk( KERN_NOTICE "%s\n", __dbg_str_buf ); \ - } \ - } while (0) - -#define DBG_ENTER_ROUTINE DBG_PRINT (DBG_K_TRACE_ENTRY, "%s", "[Entry]"); -#define DBG_LEAVE_ROUTINE DBG_PRINT (DBG_K_TRACE_EXIT, "%s", "[Exit]"); -#else -#define DEFINE_DBG_BUFFER -#define DBG_ENTER_ROUTINE -#define DBG_LEAVE_ROUTINE -#endif /* DEBUG */ static atomic_t pciehp_num_controllers = ATOMIC_INIT(0); @@ -221,8 +190,6 @@ static inline int pciehp_writel(struct controller *ctrl, int reg, u32 value) #define EMI_STATE 0x0080 #define EMI_STATUS_BIT 7 -DEFINE_DBG_BUFFER /* Debug string buffer for entire HPC defined here */ - static irqreturn_t pcie_isr(int irq, void *dev_id); static void start_int_poll_timer(struct controller *ctrl, int sec); @@ -231,8 +198,6 @@ static void int_poll_timeout(unsigned long data) { struct controller *ctrl = (struct controller *)data; - DBG_ENTER_ROUTINE - /* Poll for interrupt events. regs == NULL => polling */ pcie_isr(0, ctrl); @@ -289,8 +254,6 @@ static int pcie_write_cmd(struct slot *slot, u16 cmd, u16 mask) u16 slot_ctrl; unsigned long flags; - DBG_ENTER_ROUTINE - mutex_lock(&ctrl->ctrl_lock); retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); @@ -332,7 +295,6 @@ static int pcie_write_cmd(struct slot *slot, u16 cmd, u16 mask) retval = pcie_wait_cmd(ctrl); out: mutex_unlock(&ctrl->ctrl_lock); - DBG_LEAVE_ROUTINE return retval; } @@ -341,8 +303,6 @@ static int hpc_check_lnk_status(struct controller *ctrl) u16 lnk_status; int retval = 0; - DBG_ENTER_ROUTINE - retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status); if (retval) { err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__); @@ -357,7 +317,6 @@ static int hpc_check_lnk_status(struct controller *ctrl) return retval; } - DBG_LEAVE_ROUTINE return retval; } @@ -368,8 +327,6 @@ static int hpc_get_attention_status(struct slot *slot, u8 *status) u16 slot_ctrl; u8 atten_led_state; int retval = 0; - - DBG_ENTER_ROUTINE retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); if (retval) { @@ -400,7 +357,6 @@ static int hpc_get_attention_status(struct slot *slot, u8 *status) break; } - DBG_LEAVE_ROUTINE return 0; } @@ -410,8 +366,6 @@ static int hpc_get_power_status(struct slot *slot, u8 *status) u16 slot_ctrl; u8 pwr_state; int retval = 0; - - DBG_ENTER_ROUTINE retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); if (retval) { @@ -435,7 +389,6 @@ static int hpc_get_power_status(struct slot *slot, u8 *status) break; } - DBG_LEAVE_ROUTINE return retval; } @@ -446,8 +399,6 @@ static int hpc_get_latch_status(struct slot *slot, u8 *status) u16 slot_status; int retval = 0; - DBG_ENTER_ROUTINE - retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); if (retval) { err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); @@ -456,7 +407,6 @@ static int hpc_get_latch_status(struct slot *slot, u8 *status) *status = (((slot_status & MRL_STATE) >> 5) == 0) ? 0 : 1; - DBG_LEAVE_ROUTINE return 0; } @@ -467,8 +417,6 @@ static int hpc_get_adapter_status(struct slot *slot, u8 *status) u8 card_state; int retval = 0; - DBG_ENTER_ROUTINE - retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); if (retval) { err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); @@ -477,7 +425,6 @@ static int hpc_get_adapter_status(struct slot *slot, u8 *status) card_state = (u8)((slot_status & PRSN_STATE) >> 6); *status = (card_state == 1) ? 1 : 0; - DBG_LEAVE_ROUTINE return 0; } @@ -488,8 +435,6 @@ static int hpc_query_power_fault(struct slot *slot) u8 pwr_fault; int retval = 0; - DBG_ENTER_ROUTINE - retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); if (retval) { err("%s: Cannot check for power fault\n", __FUNCTION__); @@ -497,7 +442,6 @@ static int hpc_query_power_fault(struct slot *slot) } pwr_fault = (u8)((slot_status & PWR_FAULT_DETECTED) >> 1); - DBG_LEAVE_ROUTINE return pwr_fault; } @@ -507,8 +451,6 @@ static int hpc_get_emi_status(struct slot *slot, u8 *status) u16 slot_status; int retval = 0; - DBG_ENTER_ROUTINE - retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); if (retval) { err("%s : Cannot check EMI status\n", __FUNCTION__); @@ -516,7 +458,6 @@ static int hpc_get_emi_status(struct slot *slot, u8 *status) } *status = (slot_status & EMI_STATE) >> EMI_STATUS_BIT; - DBG_LEAVE_ROUTINE return retval; } @@ -526,8 +467,6 @@ static int hpc_toggle_emi(struct slot *slot) u16 cmd_mask; int rc; - DBG_ENTER_ROUTINE - slot_cmd = EMI_CTRL; cmd_mask = EMI_CTRL; if (!pciehp_poll_mode) { @@ -537,7 +476,7 @@ static int hpc_toggle_emi(struct slot *slot) rc = pcie_write_cmd(slot, slot_cmd, cmd_mask); slot->last_emi_toggle = get_seconds(); - DBG_LEAVE_ROUTINE + return rc; } @@ -548,8 +487,6 @@ static int hpc_set_attention_status(struct slot *slot, u8 value) u16 cmd_mask; int rc; - DBG_ENTER_ROUTINE - cmd_mask = ATTN_LED_CTRL; switch (value) { case 0 : /* turn off */ @@ -573,7 +510,6 @@ static int hpc_set_attention_status(struct slot *slot, u8 value) dbg("%s: SLOTCTRL %x write cmd %x\n", __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); - DBG_LEAVE_ROUTINE return rc; } @@ -584,8 +520,6 @@ static void hpc_set_green_led_on(struct slot *slot) u16 slot_cmd; u16 cmd_mask; - DBG_ENTER_ROUTINE - slot_cmd = 0x0100; cmd_mask = PWR_LED_CTRL; if (!pciehp_poll_mode) { @@ -597,8 +531,6 @@ static void hpc_set_green_led_on(struct slot *slot) dbg("%s: SLOTCTRL %x write cmd %x\n", __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); - DBG_LEAVE_ROUTINE - return; } static void hpc_set_green_led_off(struct slot *slot) @@ -607,8 +539,6 @@ static void hpc_set_green_led_off(struct slot *slot) u16 slot_cmd; u16 cmd_mask; - DBG_ENTER_ROUTINE - slot_cmd = 0x0300; cmd_mask = PWR_LED_CTRL; if (!pciehp_poll_mode) { @@ -619,9 +549,6 @@ static void hpc_set_green_led_off(struct slot *slot) pcie_write_cmd(slot, slot_cmd, cmd_mask); dbg("%s: SLOTCTRL %x write cmd %x\n", __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); - - DBG_LEAVE_ROUTINE - return; } static void hpc_set_green_led_blink(struct slot *slot) @@ -630,8 +557,6 @@ static void hpc_set_green_led_blink(struct slot *slot) u16 slot_cmd; u16 cmd_mask; - DBG_ENTER_ROUTINE - slot_cmd = 0x0200; cmd_mask = PWR_LED_CTRL; if (!pciehp_poll_mode) { @@ -643,14 +568,10 @@ static void hpc_set_green_led_blink(struct slot *slot) dbg("%s: SLOTCTRL %x write cmd %x\n", __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); - DBG_LEAVE_ROUTINE - return; } static void hpc_release_ctlr(struct controller *ctrl) { - DBG_ENTER_ROUTINE - if (pciehp_poll_mode) del_timer(&ctrl->poll_timer); else @@ -662,8 +583,6 @@ static void hpc_release_ctlr(struct controller *ctrl) */ if (atomic_dec_and_test(&pciehp_num_controllers)) destroy_workqueue(pciehp_wq); - - DBG_LEAVE_ROUTINE } static int hpc_power_on_slot(struct slot * slot) @@ -674,8 +593,6 @@ static int hpc_power_on_slot(struct slot * slot) u16 slot_status; int retval = 0; - DBG_ENTER_ROUTINE - dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot); /* Clear sticky power-fault bit from previous power failures */ @@ -719,8 +636,6 @@ static int hpc_power_on_slot(struct slot * slot) dbg("%s: SLOTCTRL %x write cmd %x\n", __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); - DBG_LEAVE_ROUTINE - return retval; } @@ -731,8 +646,6 @@ static int hpc_power_off_slot(struct slot * slot) u16 cmd_mask; int retval = 0; - DBG_ENTER_ROUTINE - dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot); slot_cmd = POWER_OFF; @@ -764,8 +677,6 @@ static int hpc_power_off_slot(struct slot * slot) dbg("%s: SLOTCTRL %x write cmd %x\n", __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); - DBG_LEAVE_ROUTINE - return retval; } @@ -915,8 +826,6 @@ static int hpc_get_max_lnk_speed (struct slot *slot, enum pci_bus_speed *value) u32 lnk_cap; int retval = 0; - DBG_ENTER_ROUTINE - retval = pciehp_readl(ctrl, LNKCAP, &lnk_cap); if (retval) { err("%s: Cannot read LNKCAP register\n", __FUNCTION__); @@ -934,7 +843,7 @@ static int hpc_get_max_lnk_speed (struct slot *slot, enum pci_bus_speed *value) *value = lnk_speed; dbg("Max link speed = %d\n", lnk_speed); - DBG_LEAVE_ROUTINE + return retval; } @@ -945,8 +854,6 @@ static int hpc_get_max_lnk_width (struct slot *slot, enum pcie_link_width *value u32 lnk_cap; int retval = 0; - DBG_ENTER_ROUTINE - retval = pciehp_readl(ctrl, LNKCAP, &lnk_cap); if (retval) { err("%s: Cannot read LNKCAP register\n", __FUNCTION__); @@ -985,7 +892,7 @@ static int hpc_get_max_lnk_width (struct slot *slot, enum pcie_link_width *value *value = lnk_wdth; dbg("Max link width = %d\n", lnk_wdth); - DBG_LEAVE_ROUTINE + return retval; } @@ -996,8 +903,6 @@ static int hpc_get_cur_lnk_speed (struct slot *slot, enum pci_bus_speed *value) int retval = 0; u16 lnk_status; - DBG_ENTER_ROUTINE - retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status); if (retval) { err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__); @@ -1015,7 +920,7 @@ static int hpc_get_cur_lnk_speed (struct slot *slot, enum pci_bus_speed *value) *value = lnk_speed; dbg("Current link speed = %d\n", lnk_speed); - DBG_LEAVE_ROUTINE + return retval; } @@ -1026,8 +931,6 @@ static int hpc_get_cur_lnk_width (struct slot *slot, enum pcie_link_width *value int retval = 0; u16 lnk_status; - DBG_ENTER_ROUTINE - retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status); if (retval) { err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__); @@ -1066,7 +969,7 @@ static int hpc_get_cur_lnk_width (struct slot *slot, enum pcie_link_width *value *value = lnk_wdth; dbg("Current link width = %d\n", lnk_wdth); - DBG_LEAVE_ROUTINE + return retval; } @@ -1177,8 +1080,6 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) u16 slot_status, slot_ctrl; struct pci_dev *pdev; - DBG_ENTER_ROUTINE - pdev = dev->port; ctrl->pci_dev = pdev; /* save pci_dev in context */ @@ -1376,7 +1277,6 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) ctrl->hpc_ops = &pciehp_hpc_ops; - DBG_LEAVE_ROUTINE return 0; /* We end up here for the many possible ways to fail this API. */ @@ -1396,6 +1296,5 @@ abort_free_irq: free_irq(ctrl->pci_dev->irq, ctrl); abort_free_ctlr: - DBG_LEAVE_ROUTINE return -1; } -- cgit v1.2.3-70-g09d2 From 71ad556dadcd303b4d32e9b890dcf1ccfbe9aeb3 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Thu, 9 Aug 2007 16:09:34 -0700 Subject: pciehp: remove trailing whitespace from pciehp_hpc.c Remove trailing whitespaces from pciehp_hpc.c. Signed-off-by: Kenji Kaneshige Signed-off-by: Kristen Carlson Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/pciehp_hpc.c | 50 ++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index f6143175de7..2e501f73c3b 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -129,10 +129,10 @@ static inline int pciehp_writel(struct controller *ctrl, int reg, u32 value) /* Link Width Encoding */ #define LNK_X1 0x01 #define LNK_X2 0x02 -#define LNK_X4 0x04 +#define LNK_X4 0x04 #define LNK_X8 0x08 #define LNK_X12 0x0C -#define LNK_X16 0x10 +#define LNK_X16 0x10 #define LNK_X32 0x20 /*Field definitions of Link Status Register */ @@ -262,7 +262,7 @@ static int pcie_write_cmd(struct slot *slot, u16 cmd, u16 mask) goto out; } - if ((slot_status & CMD_COMPLETED) == CMD_COMPLETED ) { + if ((slot_status & CMD_COMPLETED) == CMD_COMPLETED ) { /* After 1 sec and CMD_COMPLETED still not set, just proceed forward to issue the next command according to spec. Just print out the error message */ @@ -310,7 +310,7 @@ static int hpc_check_lnk_status(struct controller *ctrl) } dbg("%s: lnk_status = %x\n", __FUNCTION__, lnk_status); - if ( (lnk_status & LNK_TRN) || (lnk_status & LNK_TRN_ERR) || + if ( (lnk_status & LNK_TRN) || (lnk_status & LNK_TRN_ERR) || !(lnk_status & NEG_LINK_WD)) { err("%s : Link Training Error occurs \n", __FUNCTION__); retval = -1; @@ -382,7 +382,7 @@ static int hpc_get_power_status(struct slot *slot, u8 *status) *status = 1; break; case 1: - *status = 0; + *status = 0; break; default: *status = 0xFF; @@ -405,7 +405,7 @@ static int hpc_get_latch_status(struct slot *slot, u8 *status) return retval; } - *status = (((slot_status & MRL_STATE) >> 5) == 0) ? 0 : 1; + *status = (((slot_status & MRL_STATE) >> 5) == 0) ? 0 : 1; return 0; } @@ -441,7 +441,7 @@ static int hpc_query_power_fault(struct slot *slot) return retval; } pwr_fault = (u8)((slot_status & PWR_FAULT_DETECTED) >> 1); - + return pwr_fault; } @@ -509,7 +509,7 @@ static int hpc_set_attention_status(struct slot *slot, u8 value) rc = pcie_write_cmd(slot, slot_cmd, cmd_mask); dbg("%s: SLOTCTRL %x write cmd %x\n", __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); - + return rc; } @@ -519,7 +519,7 @@ static void hpc_set_green_led_on(struct slot *slot) struct controller *ctrl = slot->ctrl; u16 slot_cmd; u16 cmd_mask; - + slot_cmd = 0x0100; cmd_mask = PWR_LED_CTRL; if (!pciehp_poll_mode) { @@ -556,7 +556,7 @@ static void hpc_set_green_led_blink(struct slot *slot) struct controller *ctrl = slot->ctrl; u16 slot_cmd; u16 cmd_mask; - + slot_cmd = 0x0200; cmd_mask = PWR_LED_CTRL; if (!pciehp_poll_mode) { @@ -736,7 +736,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) } dbg("%s: pciehp_readw(SLOTSTATUS) with value %x\n", __FUNCTION__, slot_status); - + /* Clear command complete interrupt caused by this write */ temp_word = 0x1f; rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); @@ -746,10 +746,10 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) return IRQ_NONE; } } - + if (intr_loc & CMD_COMPLETED) { - /* - * Command Complete Interrupt Pending + /* + * Command Complete Interrupt Pending */ ctrl->cmd_busy = 0; wake_up_interruptible(&ctrl->queue); @@ -803,7 +803,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) __FUNCTION__); return IRQ_NONE; } - + /* Clear command complete interrupt caused by this write */ temp_word = 0x1F; rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); @@ -815,7 +815,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) dbg("%s: pciehp_writew(SLOTSTATUS) with value %x\n", __FUNCTION__, temp_word); } - + return IRQ_HANDLED; } @@ -936,7 +936,7 @@ static int hpc_get_cur_lnk_width (struct slot *slot, enum pcie_link_width *value err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__); return retval; } - + switch ((lnk_status & 0x03F0) >> 4){ case 0: lnk_wdth = PCIE_LNK_WIDTH_RESRV; @@ -988,12 +988,12 @@ static struct hpc_ops pciehp_hpc_ops = { .get_cur_bus_speed = hpc_get_cur_lnk_speed, .get_max_lnk_width = hpc_get_max_lnk_width, .get_cur_lnk_width = hpc_get_cur_lnk_width, - + .query_power_fault = hpc_query_power_fault, .green_led_on = hpc_set_green_led_on, .green_led_off = hpc_set_green_led_off, .green_led_blink = hpc_set_green_led_blink, - + .release_ctlr = hpc_release_ctlr, .check_lnk_status = hpc_check_lnk_status, }; @@ -1144,7 +1144,7 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) (unsigned long long)pci_resource_start(pdev, rc), (unsigned long long)pci_resource_len(pdev, rc)); - info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, + info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, pdev->subsystem_vendor, pdev->subsystem_device); mutex_init(&ctrl->crit_sect); @@ -1232,14 +1232,14 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) if (ATTN_BUTTN(slot_cap)) intr_enable = intr_enable | ATTN_BUTTN_ENABLE; - + if (POWER_CTRL(slot_cap)) intr_enable = intr_enable | PWR_FAULT_DETECT_ENABLE; - + if (MRL_SENS(slot_cap)) intr_enable = intr_enable | MRL_DETECT_ENABLE; - temp_word = (temp_word & ~intr_enable) | intr_enable; + temp_word = (temp_word & ~intr_enable) | intr_enable; if (pciehp_poll_mode) { temp_word = (temp_word & ~HP_INTR_ENABLE) | 0x0; @@ -1258,14 +1258,14 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); goto abort_disable_intr; } - + temp_word = 0x1F; /* Clear all events */ rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); if (rc) { err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__); goto abort_disable_intr; } - + if (pciehp_force) { dbg("Bypassing BIOS check for pciehp use on %s\n", pci_name(ctrl->pci_dev)); -- cgit v1.2.3-70-g09d2 From a073a8267400be2bd8acf808a45bc3ab01cf1b20 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Thu, 9 Aug 2007 16:09:35 -0700 Subject: pciehp: remove trailing whitespace from pciehp_core.c Remove trailing whitespaces from pciehp_core.c. Signed-off-by: Kenji Kaneshige Signed-off-by: Kristen Carlson Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/pciehp_core.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index 3d692a97121..6462ac3b405 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -304,8 +304,8 @@ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status) dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); hotplug_slot->info->attention_status = status; - - if (ATTN_LED(slot->ctrl->ctrlcap)) + + if (ATTN_LED(slot->ctrl->ctrlcap)) slot->hpc_ops->set_attention_status(slot, status); return 0; @@ -405,7 +405,7 @@ static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_spe int retval; dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - + retval = slot->hpc_ops->get_max_bus_speed(slot, value); if (retval < 0) *value = PCI_SPEED_UNKNOWN; @@ -419,7 +419,7 @@ static int get_cur_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_spe int retval; dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - + retval = slot->hpc_ops->get_cur_bus_speed(slot, value); if (retval < 0) *value = PCI_SPEED_UNKNOWN; @@ -434,7 +434,7 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_ struct slot *t_slot; u8 value; struct pci_dev *pdev; - + ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); if (!ctrl) { err("%s : out of memory\n", __FUNCTION__); @@ -502,23 +502,23 @@ static void pciehp_remove (struct pcie_device *dev) #ifdef CONFIG_PM static int pciehp_suspend (struct pcie_device *dev, pm_message_t state) { - printk("%s ENTRY\n", __FUNCTION__); + printk("%s ENTRY\n", __FUNCTION__); return 0; } static int pciehp_resume (struct pcie_device *dev) { - printk("%s ENTRY\n", __FUNCTION__); + printk("%s ENTRY\n", __FUNCTION__); return 0; } #endif -static struct pcie_port_service_id port_pci_ids[] = { { - .vendor = PCI_ANY_ID, +static struct pcie_port_service_id port_pci_ids[] = { { + .vendor = PCI_ANY_ID, .device = PCI_ANY_ID, .port_type = PCIE_ANY_PORT, .service_type = PCIE_PORT_SERVICE_HP, - .driver_data = 0, + .driver_data = 0, }, { /* end: all zeroes */ } }; static const char device_name[] = "hpdriver"; -- cgit v1.2.3-70-g09d2 From 36ed27b07b873db06c10d2f8f41aa17be6803fdd Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Thu, 9 Aug 2007 16:09:36 -0700 Subject: pciehp: remove trailing whitespace from pciehp_ctrl.c Remove trailing whitespaces from pciehp_ctrl.c. Signed-off-by: Kenji Kaneshige Signed-off-by: Kristen Carlson Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/pciehp_ctrl.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index 98e541ffef3..c8cb49c5a75 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -173,7 +173,7 @@ u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl) return 1; } -/* The following routines constitute the bulk of the +/* The following routines constitute the bulk of the hotplug controller logic */ @@ -181,7 +181,7 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot) { /* turn off slot, turn on Amber LED, turn off Green LED if supported*/ if (POWER_CTRL(ctrl->ctrlcap)) { - if (pslot->hpc_ops->power_off_slot(pslot)) { + if (pslot->hpc_ops->power_off_slot(pslot)) { err("%s: Issue of Slot Power Off command failed\n", __FUNCTION__); return; @@ -189,7 +189,7 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot) } if (PWR_LED(ctrl->ctrlcap)) - pslot->hpc_ops->green_led_off(pslot); + pslot->hpc_ops->green_led_off(pslot); if (ATTN_LED(ctrl->ctrlcap)) { if (pslot->hpc_ops->set_attention_status(pslot, 1)) { @@ -231,7 +231,7 @@ static int board_added(struct slot *p_slot) if (retval) return retval; } - + if (PWR_LED(ctrl->ctrlcap)) p_slot->hpc_ops->green_led_blink(p_slot); @@ -548,7 +548,7 @@ int pciehp_enable_slot(struct slot *p_slot) mutex_unlock(&p_slot->ctrl->crit_sect); return -ENODEV; } - if (MRL_SENS(p_slot->ctrl->ctrlcap)) { + if (MRL_SENS(p_slot->ctrl->ctrlcap)) { rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); if (rc || getstatus) { info("%s: latch open on slot(%s)\n", __FUNCTION__, @@ -557,8 +557,8 @@ int pciehp_enable_slot(struct slot *p_slot) return -ENODEV; } } - - if (POWER_CTRL(p_slot->ctrl->ctrlcap)) { + + if (POWER_CTRL(p_slot->ctrl->ctrlcap)) { rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); if (rc || getstatus) { info("%s: already enabled on slot(%s)\n", __FUNCTION__, @@ -593,7 +593,7 @@ int pciehp_disable_slot(struct slot *p_slot) /* Check to see if (latch closed, card present, power on) */ mutex_lock(&p_slot->ctrl->crit_sect); - if (!HP_SUPR_RM(p_slot->ctrl->ctrlcap)) { + if (!HP_SUPR_RM(p_slot->ctrl->ctrlcap)) { ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); if (ret || !getstatus) { info("%s: no adapter on slot(%s)\n", __FUNCTION__, @@ -603,7 +603,7 @@ int pciehp_disable_slot(struct slot *p_slot) } } - if (MRL_SENS(p_slot->ctrl->ctrlcap)) { + if (MRL_SENS(p_slot->ctrl->ctrlcap)) { ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); if (ret || getstatus) { info("%s: latch open on slot(%s)\n", __FUNCTION__, @@ -613,7 +613,7 @@ int pciehp_disable_slot(struct slot *p_slot) } } - if (POWER_CTRL(p_slot->ctrl->ctrlcap)) { + if (POWER_CTRL(p_slot->ctrl->ctrlcap)) { ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); if (ret || !getstatus) { info("%s: already disabled slot(%s)\n", __FUNCTION__, -- cgit v1.2.3-70-g09d2 From 9fe8164536c4fa6e630c706c667a2c6e8456d143 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Thu, 9 Aug 2007 16:09:37 -0700 Subject: pciehp: remove trailing whitespace form pciehp_pci.c Remove trailing whitespaces from pciehp_pci.c. Signed-off-by: Kenji Kaneshige Signed-off-by: Kristen Carlson Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/pciehp_pci.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c index 8f2b25c49f8..c424aded13f 100644 --- a/drivers/pci/hotplug/pciehp_pci.c +++ b/drivers/pci/hotplug/pciehp_pci.c @@ -280,12 +280,12 @@ int pciehp_unconfigure_device(struct slot *p_slot) pci_remove_bus_device(temp); pci_dev_put(temp); } - /* + /* * Some PCI Express root ports require fixup after hot-plug operation. */ - if (pcie_mch_quirk) + if (pcie_mch_quirk) pci_fixup_device(pci_fixup_final, p_slot->ctrl->pci_dev); - + return rc; } -- cgit v1.2.3-70-g09d2 From 40730d1042c595b1e84b28e40021f2c1377b4f8b Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Thu, 9 Aug 2007 16:09:38 -0700 Subject: pciehp: minor cleanups for pciehp_hpc.c Minor cleanups for pciehp_hpc.c. The 80 column rules, removing unnecessary lines, and so on. Signed-off-by: Kenji Kaneshige Signed-off-by: Kristen Carlson Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/pciehp_hpc.c | 47 ++++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 2e501f73c3b..06d025b8b13 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -203,7 +203,7 @@ static void int_poll_timeout(unsigned long data) init_timer(&ctrl->poll_timer); if (!pciehp_poll_time) - pciehp_poll_time = 2; /* reset timer to poll in 2 secs if user doesn't specify at module installation*/ + pciehp_poll_time = 2; /* default polling interval is 2 sec */ start_int_poll_timer(ctrl, pciehp_poll_time); } @@ -320,7 +320,6 @@ static int hpc_check_lnk_status(struct controller *ctrl) return retval; } - static int hpc_get_attention_status(struct slot *slot, u8 *status) { struct controller *ctrl = slot->ctrl; @@ -392,7 +391,6 @@ static int hpc_get_power_status(struct slot *slot, u8 *status) return retval; } - static int hpc_get_latch_status(struct slot *slot, u8 *status) { struct controller *ctrl = slot->ctrl; @@ -513,7 +511,6 @@ static int hpc_set_attention_status(struct slot *slot, u8 value) return rc; } - static void hpc_set_green_led_on(struct slot *slot) { struct controller *ctrl = slot->ctrl; @@ -695,8 +692,8 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) return IRQ_NONE; } - intr_detect = ( ATTN_BUTTN_PRESSED | PWR_FAULT_DETECTED | MRL_SENS_CHANGED | - PRSN_DETECT_CHANGED | CMD_COMPLETED ); + intr_detect = (ATTN_BUTTN_PRESSED | PWR_FAULT_DETECTED | + MRL_SENS_CHANGED | PRSN_DETECT_CHANGED | CMD_COMPLETED); intr_loc = slot_status & intr_detect; @@ -718,7 +715,8 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) dbg("%s: pciehp_readw(SLOTCTRL) with value %x\n", __FUNCTION__, temp_word); - temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00; + temp_word = (temp_word & ~HP_INTR_ENABLE & + ~CMD_CMPL_INTR_ENABLE) | 0x00; rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); if (rc) { err("%s: Cannot write to SLOTCTRL register\n", @@ -819,7 +817,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) return IRQ_HANDLED; } -static int hpc_get_max_lnk_speed (struct slot *slot, enum pci_bus_speed *value) +static int hpc_get_max_lnk_speed(struct slot *slot, enum pci_bus_speed *value) { struct controller *ctrl = slot->ctrl; enum pcie_link_speed lnk_speed; @@ -847,7 +845,8 @@ static int hpc_get_max_lnk_speed (struct slot *slot, enum pci_bus_speed *value) return retval; } -static int hpc_get_max_lnk_width (struct slot *slot, enum pcie_link_width *value) +static int hpc_get_max_lnk_width(struct slot *slot, + enum pcie_link_width *value) { struct controller *ctrl = slot->ctrl; enum pcie_link_width lnk_wdth; @@ -896,7 +895,7 @@ static int hpc_get_max_lnk_width (struct slot *slot, enum pcie_link_width *value return retval; } -static int hpc_get_cur_lnk_speed (struct slot *slot, enum pci_bus_speed *value) +static int hpc_get_cur_lnk_speed(struct slot *slot, enum pci_bus_speed *value) { struct controller *ctrl = slot->ctrl; enum pcie_link_speed lnk_speed = PCI_SPEED_UNKNOWN; @@ -924,7 +923,8 @@ static int hpc_get_cur_lnk_speed (struct slot *slot, enum pci_bus_speed *value) return retval; } -static int hpc_get_cur_lnk_width (struct slot *slot, enum pcie_link_width *value) +static int hpc_get_cur_lnk_width(struct slot *slot, + enum pcie_link_width *value) { struct controller *ctrl = slot->ctrl; enum pcie_link_width lnk_wdth = PCIE_LNK_WIDTH_UNKNOWN; @@ -1067,8 +1067,6 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev) } #endif - - int pcie_init(struct controller * ctrl, struct pcie_device *dev) { int rc; @@ -1103,9 +1101,11 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) dbg("%s: CAPREG offset %x cap_reg %x\n", __FUNCTION__, ctrl->cap_base + CAPREG, cap_reg); - if (((cap_reg & SLOT_IMPL) == 0) || (((cap_reg & DEV_PORT_TYPE) != 0x0040) + if (((cap_reg & SLOT_IMPL) == 0) || + (((cap_reg & DEV_PORT_TYPE) != 0x0040) && ((cap_reg & DEV_PORT_TYPE) != 0x0060))) { - dbg("%s : This is not a root port or the port is not connected to a slot\n", __FUNCTION__); + dbg("%s : This is not a root port or the port is not " + "connected to a slot\n", __FUNCTION__); goto abort_free_ctlr; } @@ -1138,14 +1138,15 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) dbg("%s: SLOTCTRL offset %x slot_ctrl %x\n", __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl); - for ( rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++) + for (rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++) if (pci_resource_len(pdev, rc) > 0) dbg("pci resource[%d] start=0x%llx(len=0x%llx)\n", rc, (unsigned long long)pci_resource_start(pdev, rc), (unsigned long long)pci_resource_len(pdev, rc)); - info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, - pdev->subsystem_vendor, pdev->subsystem_device); + info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", + pdev->vendor, pdev->device, + pdev->subsystem_vendor, pdev->subsystem_device); mutex_init(&ctrl->crit_sect); mutex_init(&ctrl->ctrl_lock); @@ -1169,7 +1170,8 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) dbg("%s: SLOTCTRL %x value read %x\n", __FUNCTION__, ctrl->cap_base + SLOTCTRL, temp_word); - temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00; + temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | + 0x00; rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); if (rc) { @@ -1247,7 +1249,10 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE; } - /* Unmask Hot-plug Interrupt Enable for the interrupt notification mechanism case */ + /* + * Unmask Hot-plug Interrupt Enable for the interrupt + * notification mechanism case. + */ rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); if (rc) { err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__); @@ -1279,7 +1284,7 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) return 0; - /* We end up here for the many possible ways to fail this API. */ + /* We end up here for the many possible ways to fail this API. */ abort_disable_intr: rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); if (!rc) { -- cgit v1.2.3-70-g09d2 From 229f5afded86bf3819b7b67e57c62813ca0648a7 Mon Sep 17 00:00:00 2001 From: vignesh babu Date: Mon, 13 Aug 2007 18:23:14 +0530 Subject: PCI: is_power_of_2 in drivers/pci/pci.c Replacing n & (n - 1) for power of 2 check by is_power_of_2(n) Signed-off-by: vignesh babu Signed-off-by: Greg Kroah-Hartman --- drivers/pci/pci.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 37c00f6fd80..19a64a36eca 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -17,6 +17,7 @@ #include #include #include +#include #include /* isa_dma_bridge_buggy */ #include "pci.h" @@ -1454,7 +1455,7 @@ int pcix_set_mmrbc(struct pci_dev *dev, int mmrbc) int cap, err = -EINVAL; u32 stat, cmd, v, o; - if (mmrbc < 512 || mmrbc > 4096 || (mmrbc & (mmrbc-1))) + if (mmrbc < 512 || mmrbc > 4096 || !is_power_of_2(mmrbc)) goto out; v = ffs(mmrbc) - 10; @@ -1526,7 +1527,7 @@ int pcie_set_readrq(struct pci_dev *dev, int rq) int cap, err = -EINVAL; u16 ctl, v; - if (rq < 128 || rq > 4096 || (rq & (rq-1))) + if (rq < 128 || rq > 4096 || !is_power_of_2(rq)) goto out; v = (ffs(rq) - 8) << 12; -- cgit v1.2.3-70-g09d2 From 2d100fe8f6ebe5e4335b26f3749bb0b7f706d1f9 Mon Sep 17 00:00:00 2001 From: Kristen Carlson Accardi Date: Tue, 14 Aug 2007 16:07:00 -0700 Subject: pci: hotplug: ibmphp: convert to kthread Convert ibmphp to new kthread api Signed-off-by: Kristen Carlson Accardi Cc: Christoph Hellwig Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/ibmphp_hpc.c | 57 +++++++++------------------------------- 1 file changed, 12 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/hotplug/ibmphp_hpc.c b/drivers/pci/hotplug/ibmphp_hpc.c index d06ccb69e41..c31e7bf3450 100644 --- a/drivers/pci/hotplug/ibmphp_hpc.c +++ b/drivers/pci/hotplug/ibmphp_hpc.c @@ -35,7 +35,7 @@ #include #include #include - +#include #include "ibmphp.h" static int to_debug = 0; @@ -101,12 +101,11 @@ static int to_debug = 0; //---------------------------------------------------------------------------- // global variables //---------------------------------------------------------------------------- -static int ibmphp_shutdown; -static int tid_poll; static struct mutex sem_hpcaccess; // lock access to HPC static struct semaphore semOperations; // lock all operations and // access to data structures static struct semaphore sem_exit; // make sure polling thread goes away +static struct task_struct *ibmphp_poll_thread; //---------------------------------------------------------------------------- // local function prototypes //---------------------------------------------------------------------------- @@ -116,10 +115,9 @@ static u8 hpc_writecmdtoindex (u8, u8); static u8 hpc_readcmdtoindex (u8, u8); static void get_hpc_access (void); static void free_hpc_access (void); -static void poll_hpc (void); +static int poll_hpc(void *data); static int process_changeinstatus (struct slot *, struct slot *); static int process_changeinlatch (u8, u8, struct controller *); -static int hpc_poll_thread (void *); static int hpc_wait_ctlr_notworking (int, struct controller *, void __iomem *, u8 *); //---------------------------------------------------------------------------- @@ -137,8 +135,6 @@ void __init ibmphp_hpc_initvars (void) init_MUTEX (&semOperations); init_MUTEX_LOCKED (&sem_exit); to_debug = 0; - ibmphp_shutdown = 0; - tid_poll = 0; debug ("%s - Exit\n", __FUNCTION__); } @@ -819,7 +815,7 @@ void ibmphp_unlock_operations (void) #define POLL_LATCH_REGISTER 0 #define POLL_SLOTS 1 #define POLL_SLEEP 2 -static void poll_hpc (void) +static int poll_hpc(void *data) { struct slot myslot; struct slot *pslot = NULL; @@ -833,10 +829,7 @@ static void poll_hpc (void) debug ("%s - Entry\n", __FUNCTION__); - while (!ibmphp_shutdown) { - if (ibmphp_shutdown) - break; - + while (!kthread_should_stop()) { /* try to get the lock to do some kind of hardware access */ down (&semOperations); @@ -896,7 +889,7 @@ static void poll_hpc (void) up (&semOperations); msleep(POLL_INTERVAL_SEC * 1000); - if (ibmphp_shutdown) + if (kthread_should_stop()) break; down (&semOperations); @@ -915,6 +908,7 @@ static void poll_hpc (void) } up (&sem_exit); debug ("%s - Exit\n", __FUNCTION__); + return 0; } @@ -1049,29 +1043,6 @@ static int process_changeinlatch (u8 old, u8 new, struct controller *ctrl) return rc; } -/*---------------------------------------------------------------------- -* Name: hpc_poll_thread -* -* Action: polling -* -* Return 0 -* Value: -*---------------------------------------------------------------------*/ -static int hpc_poll_thread (void *data) -{ - debug ("%s - Entry\n", __FUNCTION__); - - daemonize("hpc_poll"); - allow_signal(SIGKILL); - - poll_hpc (); - - tid_poll = 0; - debug ("%s - Exit\n", __FUNCTION__); - return 0; -} - - /*---------------------------------------------------------------------- * Name: ibmphp_hpc_start_poll_thread * @@ -1079,18 +1050,14 @@ static int hpc_poll_thread (void *data) *---------------------------------------------------------------------*/ int __init ibmphp_hpc_start_poll_thread (void) { - int rc = 0; - debug ("%s - Entry\n", __FUNCTION__); - tid_poll = kernel_thread (hpc_poll_thread, NULL, 0); - if (tid_poll < 0) { + ibmphp_poll_thread = kthread_run(poll_hpc, NULL, "hpc_poll"); + if (IS_ERR(ibmphp_poll_thread)) { err ("%s - Error, thread not started\n", __FUNCTION__); - rc = -1; + return PTR_ERR(ibmphp_poll_thread); } - - debug ("%s - Exit tid_poll[%d] rc[%d]\n", __FUNCTION__, tid_poll, rc); - return rc; + return 0; } /*---------------------------------------------------------------------- @@ -1102,7 +1069,7 @@ void __exit ibmphp_hpc_stop_poll_thread (void) { debug ("%s - Entry\n", __FUNCTION__); - ibmphp_shutdown = 1; + kthread_stop(ibmphp_poll_thread); debug ("before locking operations \n"); ibmphp_lock_operations (); debug ("after locking operations \n"); -- cgit v1.2.3-70-g09d2 From fa007d8bebc5d812a445c48664b5bcad81f1351c Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 14 Aug 2007 16:17:15 -0700 Subject: pci: hotplug: cpqphp: convert to kthread infrastructure Signed-off-by: Christoph Hellwig Signed-off-by: Kristen Carlson Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/cpqphp_ctrl.c | 69 ++++++++++++--------------------------- 1 file changed, 21 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/hotplug/cpqphp_ctrl.c b/drivers/pci/hotplug/cpqphp_ctrl.c index dcafa2aaef8..3ef0a4875a6 100644 --- a/drivers/pci/hotplug/cpqphp_ctrl.c +++ b/drivers/pci/hotplug/cpqphp_ctrl.c @@ -37,6 +37,7 @@ #include #include #include +#include #include "cpqphp.h" static u32 configure_new_device(struct controller* ctrl, struct pci_func *func, @@ -45,34 +46,20 @@ static int configure_new_function(struct controller* ctrl, struct pci_func *func u8 behind_bridge, struct resource_lists *resources); static void interrupt_event_handler(struct controller *ctrl); -static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */ -static struct semaphore event_exit; /* guard ensure thread has exited before calling it quits */ -static int event_finished; -static unsigned long pushbutton_pending; /* = 0 */ -/* things needed for the long_delay function */ -static struct semaphore delay_sem; -static wait_queue_head_t delay_wait; +static struct task_struct *cpqhp_event_thread; +static unsigned long pushbutton_pending; /* = 0 */ /* delay is in jiffies to wait for */ static void long_delay(int delay) { - DECLARE_WAITQUEUE(wait, current); - - /* only allow 1 customer into the delay queue at once - * yes this makes some people wait even longer, but who really cares? - * this is for _huge_ delays to make the hardware happy as the - * signals bounce around + /* + * XXX(hch): if someone is bored please convert all callers + * to call msleep_interruptible directly. They really want + * to specify timeouts in natural units and spend a lot of + * effort converting them to jiffies.. */ - down (&delay_sem); - - init_waitqueue_head(&delay_wait); - - add_wait_queue(&delay_wait, &wait); msleep_interruptible(jiffies_to_msecs(delay)); - remove_wait_queue(&delay_wait, &wait); - - up(&delay_sem); } @@ -955,8 +942,8 @@ irqreturn_t cpqhp_ctrl_intr(int IRQ, void *data) } if (schedule_flag) { - up(&event_semaphore); - dbg("Signal event_semaphore\n"); + wake_up_process(cpqhp_event_thread); + dbg("Waking even thread"); } return IRQ_HANDLED; } @@ -1735,7 +1722,7 @@ static u32 remove_board(struct pci_func * func, u32 replace_flag, struct control static void pushbutton_helper_thread(unsigned long data) { pushbutton_pending = data; - up(&event_semaphore); + wake_up_process(cpqhp_event_thread); } @@ -1744,13 +1731,13 @@ static int event_thread(void* data) { struct controller *ctrl; - daemonize("phpd_event"); - while (1) { dbg("!!!!event_thread sleeping\n"); - down_interruptible (&event_semaphore); - dbg("event_thread woken finished = %d\n", event_finished); - if (event_finished) break; + set_current_state(TASK_INTERRUPTIBLE); + schedule(); + + if (kthread_should_stop()) + break; /* Do stuff here */ if (pushbutton_pending) cpqhp_pushbutton_thread(pushbutton_pending); @@ -1759,38 +1746,24 @@ static int event_thread(void* data) interrupt_event_handler(ctrl); } dbg("event_thread signals exit\n"); - up(&event_exit); return 0; } - int cpqhp_event_start_thread(void) { - int pid; - - /* initialize our semaphores */ - init_MUTEX(&delay_sem); - init_MUTEX_LOCKED(&event_semaphore); - init_MUTEX_LOCKED(&event_exit); - event_finished=0; - - pid = kernel_thread(event_thread, NULL, 0); - if (pid < 0) { + cpqhp_event_thread = kthread_run(event_thread, NULL, "phpd_event"); + if (IS_ERR(cpqhp_event_thread)) { err ("Can't start up our event thread\n"); - return -1; + return PTR_ERR(cpqhp_event_thread); } - dbg("Our event thread pid = %d\n", pid); + return 0; } void cpqhp_event_stop_thread(void) { - event_finished = 1; - dbg("event_thread finish command given\n"); - up(&event_semaphore); - dbg("wait for event_thread to exit\n"); - down(&event_exit); + kthread_stop(cpqhp_event_thread); } -- cgit v1.2.3-70-g09d2 From 3799a4e7d8867cfbb137d417beb126d5a2302607 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Mon, 27 Aug 2007 16:17:38 -0700 Subject: cpqphp: Use PCI_CLASS_REVISION instead of PCI_REVISION_ID for read While PCI_CLASS_REVISION and PCI_REVISION_ID are identical, the code here discards the revision content and is only interested in the class number. Signed-off-by: Auke Kok Cc: Krosten Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/cpqphp_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c index 2305cc450a4..a96b739b2d3 100644 --- a/drivers/pci/hotplug/cpqphp_core.c +++ b/drivers/pci/hotplug/cpqphp_core.c @@ -549,7 +549,7 @@ get_slot_mapping(struct pci_bus *bus, u8 bus_num, u8 dev_num, u8 *slot) * slot. */ bus->number = tbus; pci_bus_read_config_dword(bus, PCI_DEVFN(tdevice, 0), - PCI_REVISION_ID, &work); + PCI_CLASS_REVISION, &work); if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) { pci_bus_read_config_dword(bus, -- cgit v1.2.3-70-g09d2 From aa288d4d6bc7d150bab3a5be954979a09633ccdd Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Mon, 27 Aug 2007 16:17:47 -0700 Subject: PCI: quirk amd_8131_mmrbc: Omit reading pci revision ID Signed-off-by: Auke Kok Cc: Peter Oruba Signed-off-by: Greg Kroah-Hartman --- drivers/pci/quirks.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 50f2dd9e1bb..70f196f77c1 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -629,12 +629,9 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk */ static void __init quirk_amd_8131_mmrbc(struct pci_dev *dev) { - unsigned char revid; - - pci_read_config_byte(dev, PCI_REVISION_ID, &revid); - if (dev->subordinate && revid <= 0x12) { + if (dev->subordinate && dev->revision <= 0x12) { printk(KERN_INFO "AMD8131 rev %x detected, disabling PCI-X " - "MMRBC\n", revid); + "MMRBC\n", dev->revision); dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MMRBC; } } -- cgit v1.2.3-70-g09d2 From 651472fbff71df39d3d734de31bca6e5412a688b Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Mon, 27 Aug 2007 16:18:10 -0700 Subject: PCI: quirk_vt82c586_acpi: Omit reading PCI revision ID Signed-off-by: Auke Kok Signed-off-by: Greg Kroah-Hartman --- drivers/pci/quirks.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 70f196f77c1..3b0bb3268bb 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -472,11 +472,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_3, quirk_ */ static void __devinit quirk_vt82c586_acpi(struct pci_dev *dev) { - u8 rev; u32 region; - pci_read_config_byte(dev, PCI_CLASS_REVISION, &rev); - if (rev & 0x10) { + if (dev->revision & 0x10) { pci_read_config_dword(dev, 0x48, ®ion); region &= PCI_BASE_ADDRESS_IO_MASK; quirk_io_region(dev, region, 256, PCI_BRIDGE_RESOURCES, "vt82c586 ACPI"); -- cgit v1.2.3-70-g09d2 From 346ca04d050ac48ceb8e4a6b1c76c2d7fd5d1a6a Mon Sep 17 00:00:00 2001 From: Johannes Goecke Date: Mon, 10 Sep 2007 10:46:52 +0200 Subject: PCI: re-enable onboard sound on "MSI K8T Neo2-FIR" On the "MSI K8T Neo2-FIR" board the BIOS disables the onboard soundcard, if a second PCI soundcard is present. This patch sets the korrect register bit to enable the onboard sound. Removed old code in /drivers/pci/quirks.c that only checks for the PCI-ID and fires on any Board with VIA 8237. New code in /arch/i386/pci/fixup.c checks the DMI-tables and only runs on the specific board. Signed-off-by: Johannes Goecke Acked-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- arch/x86/pci/fixup.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/pci/quirks.c | 32 -------------------------------- 2 files changed, 47 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/arch/x86/pci/fixup.c b/arch/x86/pci/fixup.c index c82cbf4c722..6cff66dd0c9 100644 --- a/arch/x86/pci/fixup.c +++ b/arch/x86/pci/fixup.c @@ -353,6 +353,53 @@ static void __devinit pci_fixup_video(struct pci_dev *pdev) } DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_video); + +static struct dmi_system_id __devinitdata msi_k8t_dmi_table[] = { + { + .ident = "MSI-K8T-Neo2Fir", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "MSI"), + DMI_MATCH(DMI_PRODUCT_NAME, "MS-6702E"), + }, + }, + {} +}; + +/* + * The AMD-Athlon64 board MSI "K8T Neo2-FIR" disables the onboard sound + * card if a PCI-soundcard is added. + * + * The BIOS only gives options "DISABLED" and "AUTO". This code sets + * the corresponding register-value to enable the soundcard. + * + * The soundcard is only enabled, if the mainborad is identified + * via DMI-tables and the soundcard is detected to be off. + */ +static void __devinit pci_fixup_msi_k8t_onboard_sound(struct pci_dev *dev) +{ + unsigned char val; + if (!dmi_check_system(msi_k8t_dmi_table)) + return; /* only applies to MSI K8T Neo2-FIR */ + + pci_read_config_byte(dev, 0x50, &val); + if (val & 0x40) { + pci_write_config_byte(dev, 0x50, val & (~0x40)); + + /* verify the change for status output */ + pci_read_config_byte(dev, 0x50, &val); + if (val & 0x40) + printk(KERN_INFO "PCI: Detected MSI K8T Neo2-FIR, " + "can't enable onboard soundcard!\n"); + else + printk(KERN_INFO "PCI: Detected MSI K8T Neo2-FIR, " + "enabled onboard soundcard.\n"); + } +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, + pci_fixup_msi_k8t_onboard_sound); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, + pci_fixup_msi_k8t_onboard_sound); + /* * Some Toshiba laptops need extra code to enable their TI TSB43AB22/A. * diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 3b0bb3268bb..59d4da2734c 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -925,38 +925,6 @@ static void __init quirk_eisa_bridge(struct pci_dev *dev) } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82375, quirk_eisa_bridge ); -/* - * On the MSI-K8T-Neo2Fir Board, the internal Soundcard is disabled - * when a PCI-Soundcard is added. The BIOS only gives Options - * "Disabled" and "AUTO". This Quirk Sets the corresponding - * Register-Value to enable the Soundcard. - * - * FIXME: Presently this quirk will run on anything that has an 8237 - * which isn't correct, we need to check DMI tables or something in - * order to make sure it only runs on the MSI-K8T-Neo2Fir. Because it - * runs everywhere at present we suppress the printk output in most - * irrelevant cases. - */ -static void k8t_sound_hostbridge(struct pci_dev *dev) -{ - unsigned char val; - - pci_read_config_byte(dev, 0x50, &val); - if (val == 0xc8) { - /* Assume it's probably a MSI-K8T-Neo2Fir */ - printk(KERN_INFO "PCI: MSI-K8T-Neo2Fir, attempting to turn soundcard ON\n"); - pci_write_config_byte(dev, 0x50, val & (~0x40)); - - /* Verify the Change for Status output */ - pci_read_config_byte(dev, 0x50, &val); - if (val & 0x40) - printk(KERN_INFO "PCI: MSI-K8T-Neo2Fir, soundcard still off\n"); - else - printk(KERN_INFO "PCI: MSI-K8T-Neo2Fir, soundcard on\n"); - } -} -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, k8t_sound_hostbridge); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, k8t_sound_hostbridge); /* * On ASUS P4B boards, the SMBus PCI Device within the ICH2/4 southbridge -- cgit v1.2.3-70-g09d2 From a56bc69a182f501582557af7fad5bc882b1c856c Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Fri, 14 Sep 2007 15:33:13 +1000 Subject: PCI: Fix incorrect argument order to list_add_tail() in PCI dynamic ID code The code for dynamically assigning new ids to PCI drivers, store_new_id(), calls list_add_tail() with the list head and new node arguments in reversed order. The result is that every new id written essentially overwrites the previous list of ids. Caught with the help of Rusty's "horribly bad" list_node patch: http://lkml.org/lkml/2007/6/10/10 Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- drivers/pci/pci-driver.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 004bc248727..c43ecedce67 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -54,7 +54,6 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count) if (!dynid) return -ENOMEM; - INIT_LIST_HEAD(&dynid->node); dynid->id.vendor = vendor; dynid->id.device = device; dynid->id.subvendor = subvendor; @@ -65,7 +64,7 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count) driver_data : 0UL; spin_lock(&pdrv->dynids.lock); - list_add_tail(&pdrv->dynids.list, &dynid->node); + list_add_tail(&dynid->node, &pdrv->dynids.list); spin_unlock(&pdrv->dynids.lock); if (get_driver(&pdrv->driver)) { -- cgit v1.2.3-70-g09d2 From cbf5d9e6b9bcf03291cbb51db144b3e2773a8a2d Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Wed, 3 Oct 2007 11:15:11 -0700 Subject: MSI: Use correct data offset for 32-bit MSI in read_msi_msg() While reading the MSI code trying to find a reason why MSI wouldn't work for devices that have a 32-bit MSI address capability, I noticed that read_msi_msg() seems to read the message data from the wrong offset in this case. Signed-off-by: Roland Dreier Acked-by: Eric W. Biederman Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/pci/msi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index be1df85e5e2..87e01615053 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -132,7 +132,7 @@ void read_msi_msg(unsigned int irq, struct msi_msg *msg) pci_read_config_word(dev, msi_data_reg(pos, 1), &data); } else { msg->address_hi = 0; - pci_read_config_word(dev, msi_data_reg(pos, 1), &data); + pci_read_config_word(dev, msi_data_reg(pos, 0), &data); } msg->data = data; break; -- cgit v1.2.3-70-g09d2 From fd6e732186ab522c812ab19c2c5e5befb8ec8115 Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Tue, 2 Oct 2007 14:19:23 -0700 Subject: PCI: fix IDE legacy mode resources I got the following error on MIPS Cobalt. PCI: Unable to reserve I/O region #1:8@f00001f0 for device 0000:00:09.1 pata_via 0000:00:09.1: failed to request/iomap BARs for port 0 (errno=-16) PCI: Unable to reserve I/O region #3:8@f0000170 for device 0000:00:09.1 pata_via 0000:00:09.1: failed to request/iomap BARs for port 1 (errno=-16) pata_via 0000:00:09.1: no available native port The legacy mode IDE resources set the following order. pci_setup_device() Legacy mode ATA controllers have fixed addresses. IDE resources: 0x1F0-0x1F7, 0x3F6, 0x170-0x177, 0x376 | V pcibios_fixup_bus() MIPS Cobalt PCI bus regions have the -0x10000000 offset from PCI resources. pcibios_fixup_bus() fix PCI bus regions. 0x1F0 - 0x10000000 = 0xF00001F0 | V ata_pci_init_one() PCI: Unable to reserve I/O region #1:8@f00001f0 for device 0000:00:09.1 In some architectures, PCI bus regions have the offset from PCI resources. For this reason, pci_setup_device() should set PCI bus regions to dev->resource[]. [akpm@linux-foundation.org: use struct initialiser] Signed-off-by: Yoichi Yuasa Cc: Alan Cox Cc: Greg KH Cc: Bartlomiej Zolnierkiewicz Cc: Ralf Baechle Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/pci/probe.c | 48 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 171ca712e52..40e571d3c39 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -744,22 +744,46 @@ static int pci_setup_device(struct pci_dev * dev) */ if (class == PCI_CLASS_STORAGE_IDE) { u8 progif; + struct pci_bus_region region; + pci_read_config_byte(dev, PCI_CLASS_PROG, &progif); if ((progif & 1) == 0) { - dev->resource[0].start = 0x1F0; - dev->resource[0].end = 0x1F7; - dev->resource[0].flags = LEGACY_IO_RESOURCE; - dev->resource[1].start = 0x3F6; - dev->resource[1].end = 0x3F6; - dev->resource[1].flags = LEGACY_IO_RESOURCE; + struct resource resource = { + .start = 0x1F0, + .end = 0x1F7, + .flags = LEGACY_IO_RESOURCE, + }; + + pcibios_resource_to_bus(dev, ®ion, &resource); + dev->resource[0].start = region.start; + dev->resource[0].end = region.end; + dev->resource[0].flags = resource.flags; + resource.start = 0x3F6; + resource.end = 0x3F6; + resource.flags = LEGACY_IO_RESOURCE; + pcibios_resource_to_bus(dev, ®ion, &resource); + dev->resource[1].start = region.start; + dev->resource[1].end = region.end; + dev->resource[1].flags = resource.flags; } if ((progif & 4) == 0) { - dev->resource[2].start = 0x170; - dev->resource[2].end = 0x177; - dev->resource[2].flags = LEGACY_IO_RESOURCE; - dev->resource[3].start = 0x376; - dev->resource[3].end = 0x376; - dev->resource[3].flags = LEGACY_IO_RESOURCE; + struct resource resource = { + .start = 0x170, + .end = 0x177, + .flags = LEGACY_IO_RESOURCE, + }; + + pcibios_resource_to_bus(dev, ®ion, &resource); + dev->resource[2].start = region.start; + dev->resource[2].end = region.end; + dev->resource[2].flags = resource.flags; + resource.start = 0x376; + resource.end = 0x376; + resource.flags = LEGACY_IO_RESOURCE; + pcibios_resource_to_bus(dev, ®ion, &resource); + dev->resource[3].start = region.start; + dev->resource[3].end = region.end; + dev->resource[3].flags = resource.flags; } } break; -- cgit v1.2.3-70-g09d2 From 7f785763660e75c9eddaddea3d618696af4ae3a2 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 5 Oct 2007 13:17:58 -0700 Subject: pci: implement "pci=noaer" For cases in which CONFIG_PCIEAER=y (such as distro kernels), allow users to disable PCIE Advanced Error Reporting by using "pci=noaer" on the kernel command line. This can be used to work around hardware or (kernel) software problems. Signed-off-by: Randy Dunlap Signed-off-by: Greg Kroah-Hartman --- Documentation/kernel-parameters.txt | 4 ++++ drivers/pci/pci.c | 2 ++ drivers/pci/pci.h | 6 ++++++ drivers/pci/pcie/aer/aerdrv.c | 9 +++++++++ 4 files changed, 21 insertions(+) (limited to 'drivers') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index a57c1f216b2..3f0173f4501 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -68,6 +68,7 @@ parameter is applicable: PARIDE The ParIDE (parallel port IDE) subsystem is enabled. PARISC The PA-RISC architecture is enabled. PCI PCI bus support is enabled. + PCIE PCI Express support is enabled. PCMCIA The PCMCIA subsystem is enabled. PNP Plug & Play support is enabled. PPC PowerPC architecture is enabled. @@ -1270,6 +1271,9 @@ and is between 256 and 4096 characters. It is defined in the file Mechanism 1. conf2 [X86-32] Force use of PCI Configuration Mechanism 2. + noaer [PCIE] If the PCIEAER kernel config parameter is + enabled, this kernel boot option can be used to + disable the use of PCIE advanced error reporting. nommconf [X86-32,X86_64] Disable use of MMCONFIG for PCI Configuration nomsi [MSI] If the PCI_MSI kernel config parameter is diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 19a64a36eca..2dd5c282fab 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1586,6 +1586,8 @@ static int __devinit pci_setup(char *str) if (*str && (str = pcibios_setup(str)) && *str) { if (!strcmp(str, "nomsi")) { pci_no_msi(); + } else if (!strcmp(str, "noaer")) { + pci_no_aer(); } else if (!strncmp(str, "cbiosize=", 9)) { pci_cardbus_io_size = memparse(str + 9, &str); } else if (!strncmp(str, "cbmemsize=", 10)) { diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 4c36e80f6d2..5360d73d494 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -52,6 +52,12 @@ void pci_restore_msi_state(struct pci_dev *dev); static inline void pci_restore_msi_state(struct pci_dev *dev) {} #endif +#ifdef CONFIG_PCIEAER +void pci_no_aer(void); +#else +static inline void pci_no_aer(void) { } +#endif + static inline int pci_no_d1d2(struct pci_dev *dev) { unsigned int parent_dstates = 0; diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c index ad90a01b0df..7a62f7dd900 100644 --- a/drivers/pci/pcie/aer/aerdrv.c +++ b/drivers/pci/pcie/aer/aerdrv.c @@ -81,6 +81,13 @@ static struct pcie_port_service_driver aerdriver = { .reset_link = aer_root_reset, }; +static int pcie_aer_disable; + +void pci_no_aer(void) +{ + pcie_aer_disable = 1; /* has priority over 'forceload' */ +} + /** * aer_irq - Root Port's ISR * @irq: IRQ assigned to Root Port @@ -327,6 +334,8 @@ static void aer_error_resume(struct pci_dev *dev) **/ static int __init aer_service_init(void) { + if (pcie_aer_disable) + return -ENXIO; return pcie_port_service_register(&aerdriver); } -- cgit v1.2.3-70-g09d2 From cd68602f36ceb65b24a9abcae10ca04a933c07fd Mon Sep 17 00:00:00 2001 From: David Rientjes Date: Thu, 27 Sep 2007 13:41:16 -0700 Subject: pci: use size stored in proc_dir_entry for proc bus files On pci_proc_attach_device(), the size of the PCI configuration space is stored in the proc_dir_entry as the size of the file. Thus, the procfs interface to PCI devices should use it instead of the device directly. Signed-off-by: David Rientjes Signed-off-by: Greg Kroah-Hartman --- drivers/pci/proc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c index 90adc62d07f..73714db6995 100644 --- a/drivers/pci/proc.c +++ b/drivers/pci/proc.c @@ -60,7 +60,7 @@ proc_bus_pci_read(struct file *file, char __user *buf, size_t nbytes, loff_t *pp */ if (capable(CAP_SYS_ADMIN)) - size = dev->cfg_size; + size = dp->size; else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) size = 128; else @@ -133,7 +133,7 @@ proc_bus_pci_write(struct file *file, const char __user *buf, size_t nbytes, lof const struct proc_dir_entry *dp = PDE(ino); struct pci_dev *dev = dp->data; int pos = *ppos; - int size = dev->cfg_size; + int size = dp->size; int cnt; if (pos >= size) -- cgit v1.2.3-70-g09d2 From ecb3908046ce9ce7feb44e2c2cf77ccdbe231f70 Mon Sep 17 00:00:00 2001 From: David Rientjes Date: Thu, 27 Sep 2007 13:41:17 -0700 Subject: pci: write file size to inode on proc bus file write When a /proc/bus/pci file is written to, the size of that PCI device's configuration space must be written to the inode. Otherwise, it is possible for the file to specify a size of 0 on stat if a task is holding the same file open. Signed-off-by: David Rientjes Signed-off-by: Greg Kroah-Hartman --- drivers/pci/proc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c index 73714db6995..716439e25dd 100644 --- a/drivers/pci/proc.c +++ b/drivers/pci/proc.c @@ -129,7 +129,7 @@ proc_bus_pci_read(struct file *file, char __user *buf, size_t nbytes, loff_t *pp static ssize_t proc_bus_pci_write(struct file *file, const char __user *buf, size_t nbytes, loff_t *ppos) { - const struct inode *ino = file->f_path.dentry->d_inode; + struct inode *ino = file->f_path.dentry->d_inode; const struct proc_dir_entry *dp = PDE(ino); struct pci_dev *dev = dp->data; int pos = *ppos; @@ -193,6 +193,7 @@ proc_bus_pci_write(struct file *file, const char __user *buf, size_t nbytes, lof } *ppos = pos; + i_size_write(ino, dp->size); return nbytes; } -- cgit v1.2.3-70-g09d2 From 8fa5913d54f3b1e09948e6a0db34da887e05ff1f Mon Sep 17 00:00:00 2001 From: Gary Hade Date: Wed, 3 Oct 2007 15:55:51 -0700 Subject: PCI: remove transparent bridge sizing Remove transparent bridge sizing. Due to code in pci_read_bridge_bases() [drivers/pci/probe.c] the child bus of a transparent bridge already has access to the parent bus resources so transparent bridge sizing appears unnecessary. The bridge sizing includes alignment and granularity adjustments that can cause significantly more memory to be reserved from the parant bus than required by devices on the child bus and allotted by _CRS. Signed-off-by: Gary Hade Signed-off-by: Greg Kroah-Hartman --- drivers/pci/setup-bus.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 5e5191ec8de..401e03c920b 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -472,7 +472,12 @@ void pci_bus_size_bridges(struct pci_bus *bus) break; case PCI_CLASS_BRIDGE_PCI: + /* don't size subtractive decoding (transparent) + * PCI-to-PCI bridges */ + if (bus->self->transparent) + break; pci_bridge_check_ranges(bus); + /* fall through */ default: pbus_size_io(bus); /* If the bridge supports prefetchable range, size it -- cgit v1.2.3-70-g09d2 From 036fff4cf732c4d69f99a2915924935705744b00 Mon Sep 17 00:00:00 2001 From: Gary Hade Date: Wed, 3 Oct 2007 15:56:14 -0700 Subject: PCI: skip ISA ioresource alignment on some systems Skip ISA ioresource alignment on some systems To conserve limited PCI i/o resource on some IBM multi-node systems, the BIOS allocates (via _CRS) and expects the kernel to use addresses in ranges currently excluded by pcibios_align_resource() [i386/pci/i386.c]. This change allows the kernel to use the currently excluded address ranges on the IBM x3800, x3850, and x3950. Signed-off-by: Gary Hade Signed-off-by: Greg Kroah-Hartman --- arch/x86/pci/acpi.c | 42 ++++++++++++++++++++++++++++++++++++++++++ arch/x86/pci/i386.c | 13 +++++++++++++ arch/x86/pci/pci.h | 1 + drivers/pci/probe.c | 4 ++-- 4 files changed, 58 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c index bc8a44bddaa..1dd6f3fc077 100644 --- a/arch/x86/pci/acpi.c +++ b/arch/x86/pci/acpi.c @@ -2,15 +2,57 @@ #include #include #include +#include #include #include "pci.h" +static int __devinit can_skip_ioresource_align(struct dmi_system_id *d) +{ + pci_probe |= PCI_CAN_SKIP_ISA_ALIGN; + printk(KERN_INFO "PCI: %s detected, can skip ISA alignment\n", d->ident); + return 0; +} + +static struct dmi_system_id acpi_pciprobe_dmi_table[] = { +/* + * Systems where PCI IO resource ISA alignment can be skipped + * when the ISA enable bit in the bridge control is not set + */ + { + .callback = can_skip_ioresource_align, + .ident = "IBM System x3800", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "IBM"), + DMI_MATCH(DMI_PRODUCT_NAME, "x3800"), + }, + }, + { + .callback = can_skip_ioresource_align, + .ident = "IBM System x3850", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "IBM"), + DMI_MATCH(DMI_PRODUCT_NAME, "x3850"), + }, + }, + { + .callback = can_skip_ioresource_align, + .ident = "IBM System x3950", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "IBM"), + DMI_MATCH(DMI_PRODUCT_NAME, "x3950"), + }, + }, + {} +}; + struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int domain, int busnum) { struct pci_bus *bus; struct pci_sysdata *sd; int pxm; + dmi_check_system(acpi_pciprobe_dmi_table); + /* Allocate per-root-bus (not per bus) arch-specific data. * TODO: leak; this memory is never freed. * It's arguable whether it's worth the trouble to care. diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c index bcd2f94b732..055187bc255 100644 --- a/arch/x86/pci/i386.c +++ b/arch/x86/pci/i386.c @@ -33,6 +33,15 @@ #include "pci.h" +static int +skip_isa_ioresource_align(struct pci_dev *dev) { + + if ((pci_probe & PCI_CAN_SKIP_ISA_ALIGN) && + (dev->bus->bridge_ctl & PCI_BRIDGE_CTL_NO_ISA)) + return 1; + return 0; +} + /* * We need to avoid collisions with `mirrored' VGA ports * and other strange ISA hardware, so we always want the @@ -50,9 +59,13 @@ void pcibios_align_resource(void *data, struct resource *res, resource_size_t size, resource_size_t align) { + struct pci_dev *dev = data; + if (res->flags & IORESOURCE_IO) { resource_size_t start = res->start; + if (skip_isa_ioresource_align(dev)) + return; if (start & 0x300) { start = (start + 0x3ff) & ~0x3ff; res->start = start; diff --git a/arch/x86/pci/pci.h b/arch/x86/pci/pci.h index 8c66f275756..057f335fa3f 100644 --- a/arch/x86/pci/pci.h +++ b/arch/x86/pci/pci.h @@ -26,6 +26,7 @@ #define PCI_ASSIGN_ROMS 0x1000 #define PCI_BIOS_IRQ_SCAN 0x2000 #define PCI_ASSIGN_ALL_BUSSES 0x4000 +#define PCI_CAN_SKIP_ISA_ALIGN 0x8000 extern unsigned int pci_probe; extern unsigned long pirq_table_addr; diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 40e571d3c39..59d6c309281 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -544,7 +544,7 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass goto out; child->primary = buses & 0xFF; child->subordinate = (buses >> 16) & 0xFF; - child->bridge_ctl = bctl; + child->bridge_ctl = bctl ^ PCI_BRIDGE_CTL_NO_ISA; cmax = pci_scan_child_bus(child); if (cmax > max) @@ -597,7 +597,7 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses); if (!is_cardbus) { - child->bridge_ctl = bctl | PCI_BRIDGE_CTL_NO_ISA; + child->bridge_ctl = bctl ^ PCI_BRIDGE_CTL_NO_ISA; /* * Adjust subordinate busnr in parent buses. * We do this before scanning for children because -- cgit v1.2.3-70-g09d2 From fd64cb4606cbdd592b7119e82341d4ae5b56f2cc Mon Sep 17 00:00:00 2001 From: Gary Hade Date: Wed, 3 Oct 2007 15:56:30 -0700 Subject: PCI: avoid P2P prefetch window for expansion ROMs Avoid creating P2P prefetch window for expansion ROMs Because of the future possibility that P2P prefetch windows will contain address ranges above 4GB some BIOSes are providing space in the P2P non-prefetch windows for expansion ROMs. This is due to expansion ROM BAR 32-bit limitation. When expansion ROM BARs without BIOS assigned address(es) are currently found behind a P2P bridge, the kernel attempts to create a P2P prefetch window for them even though space for them has already been provided in the non-prefetch window. _CRS on some systems with certain resource conservation conscious BIOSes may not provide the extra 1MB or more memory resource needed for the expansion ROM motivated prefetch window causing resource allocation errors. This change corrects the problem by removing IORESOURCE_PREFETCH from the expansion ROM flags initialization. It also removes IORESOURCE_CACHEABLE which seems inappropriate if only non-cacheable memory is available. Signed-off-by: Gary Hade Signed-off-by: Greg Kroah-Hartman --- drivers/pci/probe.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 59d6c309281..3112024bdc2 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -276,8 +276,7 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) sz = pci_size(l, sz, (u32)PCI_ROM_ADDRESS_MASK); if (sz) { res->flags = (l & IORESOURCE_ROM_ENABLE) | - IORESOURCE_MEM | IORESOURCE_PREFETCH | - IORESOURCE_READONLY | IORESOURCE_CACHEABLE; + IORESOURCE_MEM | IORESOURCE_READONLY; res->start = l & PCI_ROM_ADDRESS_MASK; res->end = res->start + (unsigned long) sz; } -- cgit v1.2.3-70-g09d2 From 11949255d9433ea6c0908b7390ec4faecd1d4cf0 Mon Sep 17 00:00:00 2001 From: Gary Hade Date: Mon, 8 Oct 2007 16:24:16 -0700 Subject: PCI: modify PCI bridge control ISA flag for clarity Modify PCI Bridge Control ISA flag for clarity This patch changes PCI_BRIDGE_CTL_NO_ISA to PCI_BRIDGE_CTL_ISA and modifies it's clarifying comment and locations where used. The change reduces the chance of future confusion since it makes the set/unset meaning of the bit the same in both the bridge control register and bridge_ctl field of the pci_bus struct. Signed-off-by: Gary Hade Acked-by: Linas Vepstas Cc: Ivan Kokshaysky Signed-off-by: Greg Kroah-Hartman --- arch/x86/pci/i386.c | 2 +- drivers/pci/probe.c | 4 ++-- include/linux/pci_regs.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c index 055187bc255..42ba0e2da1a 100644 --- a/arch/x86/pci/i386.c +++ b/arch/x86/pci/i386.c @@ -37,7 +37,7 @@ static int skip_isa_ioresource_align(struct pci_dev *dev) { if ((pci_probe & PCI_CAN_SKIP_ISA_ALIGN) && - (dev->bus->bridge_ctl & PCI_BRIDGE_CTL_NO_ISA)) + !(dev->bus->bridge_ctl & PCI_BRIDGE_CTL_ISA)) return 1; return 0; } diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 3112024bdc2..5db6b6690b5 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -543,7 +543,7 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass goto out; child->primary = buses & 0xFF; child->subordinate = (buses >> 16) & 0xFF; - child->bridge_ctl = bctl ^ PCI_BRIDGE_CTL_NO_ISA; + child->bridge_ctl = bctl; cmax = pci_scan_child_bus(child); if (cmax > max) @@ -596,7 +596,7 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses); if (!is_cardbus) { - child->bridge_ctl = bctl ^ PCI_BRIDGE_CTL_NO_ISA; + child->bridge_ctl = bctl; /* * Adjust subordinate busnr in parent buses. * We do this before scanning for children because diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h index 4a24ee368a1..c1914a8b94a 100644 --- a/include/linux/pci_regs.h +++ b/include/linux/pci_regs.h @@ -147,7 +147,7 @@ #define PCI_BRIDGE_CONTROL 0x3e #define PCI_BRIDGE_CTL_PARITY 0x01 /* Enable parity detection on secondary interface */ #define PCI_BRIDGE_CTL_SERR 0x02 /* The same for SERR forwarding */ -#define PCI_BRIDGE_CTL_NO_ISA 0x04 /* Disable bridging of ISA ports */ +#define PCI_BRIDGE_CTL_ISA 0x04 /* Enable ISA mode */ #define PCI_BRIDGE_CTL_VGA 0x08 /* Forward VGA addresses */ #define PCI_BRIDGE_CTL_MASTER_ABORT 0x20 /* Report master aborts */ #define PCI_BRIDGE_CTL_BUS_RESET 0x40 /* Secondary bus reset */ -- cgit v1.2.3-70-g09d2 From 32a2eea795643929a43cbbba00d8c4a176b309bf Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 11 Oct 2007 16:57:27 -0400 Subject: PCI: Add 'nodomains' boot option, and pci_domains_supported global * Introduce pci_domains_supported global, hardcoded to zero if !CONFIG_PCI_DOMAINS. * Introduce 'nodomains' boot option, which clears pci_domains_supported on platforms that enable it by default (x86, x86-64, and others when they are converted to use this). Signed-off-by: Jeff Garzik Cc: Andi Kleen Signed-off-by: Greg Kroah-Hartman --- Documentation/kernel-parameters.txt | 2 ++ drivers/pci/pci.c | 13 +++++++++++++ include/linux/pci.h | 7 +++++-- 3 files changed, 20 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index e9acd5540d2..d006e8b66ff 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1274,6 +1274,8 @@ and is between 256 and 4096 characters. It is defined in the file noaer [PCIE] If the PCIEAER kernel config parameter is enabled, this kernel boot option can be used to disable the use of PCIE advanced error reporting. + nodomains [PCI] Disable support for multiple PCI + root domains (aka PCI segments, in ACPI-speak). nommconf [X86-32,X86_64] Disable use of MMCONFIG for PCI Configuration nomsi [MSI] If the PCI_MSI kernel config parameter is diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 2dd5c282fab..728b3c863d8 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -23,6 +23,10 @@ unsigned int pci_pm_d3_delay = 10; +#ifdef CONFIG_PCI_DOMAINS +int pci_domains_supported = 1; +#endif + #define DEFAULT_CARDBUS_IO_SIZE (256) #define DEFAULT_CARDBUS_MEM_SIZE (64*1024*1024) /* pci=cbmemsize=nnM,cbiosize=nn can override this */ @@ -1567,6 +1571,13 @@ int pci_select_bars(struct pci_dev *dev, unsigned long flags) return bars; } +static void __devinit pci_no_domains(void) +{ +#ifdef CONFIG_PCI_DOMAINS + pci_domains_supported = 0; +#endif +} + static int __devinit pci_init(void) { struct pci_dev *dev = NULL; @@ -1588,6 +1599,8 @@ static int __devinit pci_setup(char *str) pci_no_msi(); } else if (!strcmp(str, "noaer")) { pci_no_aer(); + } else if (!strcmp(str, "nodomains")) { + pci_no_domains(); } else if (!strncmp(str, "cbiosize=", 9)) { pci_cardbus_io_size = memparse(str + 9, &str); } else if (!strncmp(str, "cbmemsize=", 10)) { diff --git a/include/linux/pci.h b/include/linux/pci.h index 038a0dc7273..768b93359f9 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -685,13 +685,16 @@ extern void pci_unblock_user_cfg_access(struct pci_dev *dev); * a PCI domain is defined to be a set of PCI busses which share * configuration space. */ -#ifndef CONFIG_PCI_DOMAINS +#ifdef CONFIG_PCI_DOMAINS +extern int pci_domains_supported; +#else +enum { pci_domains_supported = 0 }; static inline int pci_domain_nr(struct pci_bus *bus) { return 0; } static inline int pci_proc_domain(struct pci_bus *bus) { return 0; } -#endif +#endif /* CONFIG_PCI_DOMAINS */ #else /* CONFIG_PCI is not enabled */ -- cgit v1.2.3-70-g09d2